summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/ABI/stable/sysfs-bus-usb14
-rw-r--r--Documentation/ABI/stable/sysfs-driver-ib_srp25
-rw-r--r--Documentation/ABI/testing/sysfs-bus-pci13
-rw-r--r--Documentation/ABI/testing/sysfs-bus-usb19
-rw-r--r--Documentation/DocBook/alsa-driver-api.tmpl31
-rw-r--r--Documentation/DocBook/media/dvb/dvbproperty.xml4
-rw-r--r--Documentation/DocBook/media/v4l/biblio.xml85
-rw-r--r--Documentation/DocBook/media/v4l/dev-subdev.xml109
-rw-r--r--Documentation/DocBook/media/v4l/io.xml5
-rw-r--r--Documentation/DocBook/media/v4l/pixfmt.xml1274
-rw-r--r--Documentation/DocBook/media/v4l/selections-common.xml16
-rw-r--r--Documentation/DocBook/media/v4l/subdev-formats.xml308
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enuminput.xml8
-rw-r--r--Documentation/DocBook/media/v4l/vidioc-enumoutput.xml8
-rw-r--r--Documentation/DocBook/writing-an-alsa-driver.tmpl23
-rw-r--r--Documentation/IRQ-domain.txt71
-rw-r--r--Documentation/RCU/rcu.txt4
-rw-r--r--Documentation/RCU/stallwarn.txt14
-rw-r--r--Documentation/RCU/trace.txt4
-rw-r--r--Documentation/RCU/whatisRCU.txt2
-rw-r--r--Documentation/acpi/gpio-properties.txt96
-rw-r--r--Documentation/arm/firmware.txt28
-rw-r--r--Documentation/arm/sunxi/README16
-rw-r--r--Documentation/arm64/legacy_instructions.txt45
-rw-r--r--Documentation/atomic_ops.txt12
-rw-r--r--Documentation/block/biodoc.txt4
-rw-r--r--Documentation/cgroups/hugetlb.txt2
-rw-r--r--Documentation/cgroups/memory.txt26
-rw-r--r--Documentation/cgroups/resource_counter.txt197
-rw-r--r--Documentation/cpu-freq/intel-pstate.txt37
-rw-r--r--Documentation/device-mapper/cache-policies.txt24
-rw-r--r--Documentation/devicetree/bindings/arm/amlogic.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/arch_timer.txt8
-rw-r--r--Documentation/devicetree/bindings/arm/arm-boards65
-rw-r--r--Documentation/devicetree/bindings/arm/bcm/cygnus.txt31
-rw-r--r--Documentation/devicetree/bindings/arm/cpus.txt9
-rw-r--r--Documentation/devicetree/bindings/arm/fsl.txt38
-rw-r--r--Documentation/devicetree/bindings/arm/gic.txt1
-rw-r--r--Documentation/devicetree/bindings/arm/idle-states.txt20
-rw-r--r--Documentation/devicetree/bindings/arm/marvell,berlin.txt10
-rw-r--r--Documentation/devicetree/bindings/arm/mediatek.txt19
-rw-r--r--Documentation/devicetree/bindings/arm/omap/omap.txt3
-rw-r--r--Documentation/devicetree/bindings/arm/rockchip.txt4
-rw-r--r--Documentation/devicetree/bindings/arm/samsung-boards.txt19
-rw-r--r--Documentation/devicetree/bindings/arm/ste-nomadik.txt6
-rw-r--r--Documentation/devicetree/bindings/arm/sunxi.txt12
-rw-r--r--Documentation/devicetree/bindings/arm/ux500/power_domain.txt35
-rw-r--r--Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt6
-rw-r--r--Documentation/devicetree/bindings/bus/mvebu-mbus.txt17
-rw-r--r--Documentation/devicetree/bindings/chosen.txt46
-rw-r--r--Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt34
-rw-r--r--Documentation/devicetree/bindings/clock/vf610-clock.txt15
-rw-r--r--Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt2
-rw-r--r--Documentation/devicetree/bindings/hwmon/ltc2978.txt39
-rw-r--r--Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt1
-rw-r--r--Documentation/devicetree/bindings/i2c/trivial-devices.txt2
-rw-r--r--Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt26
-rw-r--r--Documentation/devicetree/bindings/mailbox/omap-mailbox.txt23
-rw-r--r--Documentation/devicetree/bindings/media/meson-ir.txt14
-rw-r--r--Documentation/devicetree/bindings/media/si4713.txt30
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt21
-rw-r--r--Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt36
-rw-r--r--Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt51
-rw-r--r--Documentation/devicetree/bindings/mfd/max77686.txt6
-rw-r--r--Documentation/devicetree/bindings/mfd/max77693.txt21
-rw-r--r--Documentation/devicetree/bindings/mfd/s2mps11.txt22
-rw-r--r--Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt4
-rw-r--r--Documentation/devicetree/bindings/mmc/img-dw-mshc.txt29
-rw-r--r--Documentation/devicetree/bindings/mmc/sdhci-pxa.txt7
-rw-r--r--Documentation/devicetree/bindings/nios2/nios2.txt62
-rw-r--r--Documentation/devicetree/bindings/nios2/timer.txt19
-rw-r--r--Documentation/devicetree/bindings/pci/layerscape-pci.txt42
-rw-r--r--Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt96
-rw-r--r--Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt2
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt215
-rw-r--r--Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt162
-rw-r--r--Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt3
-rw-r--r--Documentation/devicetree/bindings/pinctrl/ste,abx500.txt184
-rw-r--r--Documentation/devicetree/bindings/power/power-controller.txt18
-rw-r--r--Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt23
-rw-r--r--Documentation/devicetree/bindings/regulator/act8865-regulator.txt4
-rw-r--r--Documentation/devicetree/bindings/regulator/max77802.txt35
-rw-r--r--Documentation/devicetree/bindings/regulator/regulator.txt22
-rw-r--r--Documentation/devicetree/bindings/regulator/sky81452-regulator.txt10
-rw-r--r--Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt42
-rw-r--r--Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt23
-rw-r--r--Documentation/devicetree/bindings/rtc/rtc-omap.txt9
-rw-r--r--Documentation/devicetree/bindings/serial/pl011.txt28
-rw-r--r--Documentation/devicetree/bindings/sound/arndale.txt24
-rw-r--r--Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/eukrea-tlv320.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,esai.txt44
-rw-r--r--Documentation/devicetree/bindings/sound/fsl,spdif.txt37
-rw-r--r--Documentation/devicetree/bindings/sound/fsl-sai.txt66
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt61
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-spdif.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt45
-rw-r--r--Documentation/devicetree/bindings/sound/imx-audmux.txt22
-rw-r--r--Documentation/devicetree/bindings/sound/max98090.txt2
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,fsi.txt9
-rw-r--r--Documentation/devicetree/bindings/sound/renesas,rsnd.txt10
-rw-r--r--Documentation/devicetree/bindings/sound/rt5631.txt48
-rw-r--r--Documentation/devicetree/bindings/sound/rt5677.txt17
-rw-r--r--Documentation/devicetree/bindings/sound/samsung-i2s.txt15
-rw-r--r--Documentation/devicetree/bindings/sound/sgtl5000.txt13
-rw-r--r--Documentation/devicetree/bindings/sound/ts3a227e.txt26
-rw-r--r--Documentation/devicetree/bindings/sound/wm8960.txt31
-rw-r--r--Documentation/devicetree/bindings/spi/spi-gpio.txt6
-rw-r--r--Documentation/devicetree/bindings/spi/spi-img-spfi.txt37
-rw-r--r--Documentation/devicetree/bindings/spi/spi-meson.txt22
-rw-r--r--Documentation/devicetree/bindings/spi/spi-samsung.txt2
-rw-r--r--Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt9
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,mtu2.txt2
-rw-r--r--Documentation/devicetree/bindings/timer/renesas,tmu.txt4
-rw-r--r--Documentation/devicetree/bindings/unittest.txt14
-rw-r--r--Documentation/devicetree/bindings/vendor-prefixes.txt5
-rw-r--r--Documentation/devicetree/bindings/video/backlight/lp855x.txt2
-rw-r--r--Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt33
-rw-r--r--Documentation/devicetree/bindings/video/simple-framebuffer.txt68
-rw-r--r--Documentation/devicetree/bindings/w1/omap-hdq.txt17
-rw-r--r--Documentation/devicetree/bindings/watchdog/marvel.txt13
-rw-r--r--Documentation/devicetree/of_selftest.txt20
-rw-r--r--Documentation/devicetree/overlay-notes.txt133
-rw-r--r--Documentation/devicetree/todo.txt1
-rw-r--r--Documentation/filesystems/debugfs.txt2
-rw-r--r--Documentation/filesystems/f2fs.txt7
-rw-r--r--Documentation/filesystems/nfs/Exporting23
-rw-r--r--Documentation/filesystems/porting8
-rw-r--r--Documentation/filesystems/seq_file.txt22
-rw-r--r--Documentation/filesystems/vfs.txt2
-rw-r--r--Documentation/gpio/consumer.txt18
-rw-r--r--Documentation/hwmon/lm755
-rw-r--r--Documentation/hwmon/lm9523415
-rw-r--r--Documentation/hwmon/lm9524514
-rw-r--r--Documentation/hwmon/nct677514
-rw-r--r--Documentation/hwmon/nct780232
-rw-r--r--Documentation/hwmon/tmp4018
-rw-r--r--Documentation/kdump/kdump.txt7
-rw-r--r--Documentation/kernel-parameters.txt24
-rw-r--r--Documentation/locking/lglock.txt166
-rw-r--r--Documentation/memory-barriers.txt51
-rw-r--r--Documentation/nios2/README23
-rw-r--r--Documentation/scsi/libsas.txt82
-rw-r--r--Documentation/scsi/scsi_mid_low_api.txt66
-rw-r--r--Documentation/scsi/st.txt8
-rw-r--r--Documentation/scsi/wd719x.txt21
-rw-r--r--Documentation/sound/alsa/ControlNames.txt32
-rw-r--r--Documentation/sound/alsa/HD-Audio-Models.txt8
-rw-r--r--Documentation/sound/alsa/Procfile.txt17
-rw-r--r--Documentation/sysctl/kernel.txt40
-rw-r--r--Documentation/trace/ftrace.txt15
-rw-r--r--Documentation/usb/power-management.txt17
-rw-r--r--Documentation/video4linux/CARDLIST.cx238852
-rw-r--r--Documentation/video4linux/CARDLIST.em28xx1
-rw-r--r--Documentation/video4linux/CARDLIST.saa71341
-rw-r--r--Documentation/video4linux/soc-camera.txt2
-rw-r--r--Documentation/x86/intel_mpx.txt234
-rw-r--r--MAINTAINERS213
-rw-r--r--Makefile2
-rw-r--r--arch/alpha/kernel/osf_sys.c7
-rw-r--r--arch/arc/include/asm/io.h2
-rw-r--r--arch/arm/Kconfig30
-rw-r--r--arch/arm/Kconfig.debug167
-rw-r--r--arch/arm/Makefile8
-rw-r--r--arch/arm/boot/dts/Makefile80
-rw-r--r--arch/arm/boot/dts/am335x-boneblack.dts4
-rw-r--r--arch/arm/boot/dts/am335x-evm.dts17
-rw-r--r--arch/arm/boot/dts/am335x-igep0033.dtsi4
-rw-r--r--arch/arm/boot/dts/am335x-lxm.dts362
-rw-r--r--arch/arm/boot/dts/am33xx.dtsi34
-rw-r--r--arch/arm/boot/dts/am4372.dtsi48
-rw-r--r--arch/arm/boot/dts/am437x-gp-evm.dts34
-rw-r--r--arch/arm/boot/dts/am43x-epos-evm.dts12
-rw-r--r--arch/arm/boot/dts/am57xx-beagle-x15.dts405
-rw-r--r--arch/arm/boot/dts/arm-realview-pb1176.dts412
-rw-r--r--arch/arm/boot/dts/armada-370-db.dts106
-rw-r--r--arch/arm/boot/dts/armada-370-mirabox.dts25
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn102.dts101
-rw-r--r--arch/arm/boot/dts/armada-370-netgear-rn104.dts64
-rw-r--r--arch/arm/boot/dts/armada-370-rd.dts73
-rw-r--r--arch/arm/boot/dts/armada-370-synology-ds213j.dts316
-rw-r--r--arch/arm/boot/dts/armada-370-xp.dtsi14
-rw-r--r--arch/arm/boot/dts/armada-370.dtsi190
-rw-r--r--arch/arm/boot/dts/armada-375.dtsi12
-rw-r--r--arch/arm/boot/dts/armada-385-db.dts2
-rw-r--r--arch/arm/boot/dts/armada-38x.dtsi6
-rw-r--r--arch/arm/boot/dts/armada-xp-axpwifiap.dts57
-rw-r--r--arch/arm/boot/dts/armada-xp-gp.dts19
-rw-r--r--arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts75
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78230.dtsi15
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78260.dtsi15
-rw-r--r--arch/arm/boot/dts/armada-xp-mv78460.dtsi15
-rw-r--r--arch/arm/boot/dts/armada-xp-netgear-rn2120.dts166
-rw-r--r--arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts14
-rw-r--r--arch/arm/boot/dts/armada-xp-synology-ds414.dts330
-rw-r--r--arch/arm/boot/dts/armada-xp.dtsi71
-rw-r--r--arch/arm/boot/dts/at91sam9263.dtsi19
-rw-r--r--arch/arm/boot/dts/at91sam9x25.dtsi1
-rw-r--r--arch/arm/boot/dts/at91sam9x35.dtsi1
-rw-r--r--arch/arm/boot/dts/at91sam9x5.dtsi12
-rw-r--r--arch/arm/boot/dts/at91sam9x5_can.dtsi50
-rw-r--r--arch/arm/boot/dts/at91sam9x5_usart3.dtsi3
-rw-r--r--arch/arm/boot/dts/atlas6.dtsi15
-rw-r--r--arch/arm/boot/dts/bcm-cygnus-clock.dtsi91
-rw-r--r--arch/arm/boot/dts/bcm-cygnus.dtsi140
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b-plus.dts30
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi-b.dts46
-rw-r--r--arch/arm/boot/dts/bcm2835-rpi.dtsi51
-rw-r--r--arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts64
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6250.dts59
-rw-r--r--arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts84
-rw-r--r--arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts78
-rw-r--r--arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts57
-rw-r--r--arch/arm/boot/dts/bcm47081.dtsi26
-rw-r--r--arch/arm/boot/dts/bcm5301x.dtsi51
-rw-r--r--arch/arm/boot/dts/bcm911360_entphn.dts53
-rw-r--r--arch/arm/boot/dts/bcm911360k.dts53
-rw-r--r--arch/arm/boot/dts/bcm958300k.dts53
-rw-r--r--arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts16
-rw-r--r--arch/arm/boot/dts/berlin2.dtsi110
-rw-r--r--arch/arm/boot/dts/berlin2cd-google-chromecast.dts30
-rw-r--r--arch/arm/boot/dts/berlin2cd.dtsi82
-rw-r--r--arch/arm/boot/dts/berlin2q-marvell-dmp.dts61
-rw-r--r--arch/arm/boot/dts/berlin2q.dtsi96
-rw-r--r--arch/arm/boot/dts/dra7-evm.dts133
-rw-r--r--arch/arm/boot/dts/dra7.dtsi202
-rw-r--r--arch/arm/boot/dts/dra72-evm.dts319
-rw-r--r--arch/arm/boot/dts/dra74x.dtsi22
-rw-r--r--arch/arm/boot/dts/emev2-kzm9d.dts63
-rw-r--r--arch/arm/boot/dts/emev2.dtsi12
-rw-r--r--arch/arm/boot/dts/exynos3250-monk.dts579
-rw-r--r--arch/arm/boot/dts/exynos3250-pinctrl.dtsi16
-rw-r--r--arch/arm/boot/dts/exynos3250-rinato.dts682
-rw-r--r--arch/arm/boot/dts/exynos3250.dtsi10
-rw-r--r--arch/arm/boot/dts/exynos4.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos4210-trats.dts16
-rw-r--r--arch/arm/boot/dts/exynos4210-universal_c210.dts16
-rw-r--r--arch/arm/boot/dts/exynos4210.dtsi17
-rw-r--r--arch/arm/boot/dts/exynos4212.dtsi17
-rw-r--r--arch/arm/boot/dts/exynos4412-odroid-common.dtsi26
-rw-r--r--arch/arm/boot/dts/exynos4412-trats2.dts412
-rw-r--r--arch/arm/boot/dts/exynos4412.dtsi29
-rw-r--r--arch/arm/boot/dts/exynos4415-pinctrl.dtsi573
-rw-r--r--arch/arm/boot/dts/exynos4415.dtsi604
-rw-r--r--arch/arm/boot/dts/exynos4x12-pinctrl.dtsi16
-rw-r--r--arch/arm/boot/dts/exynos4x12.dtsi10
-rw-r--r--arch/arm/boot/dts/exynos5250-arndale.dts907
-rw-r--r--arch/arm/boot/dts/exynos5250-smdk5250.dts618
-rw-r--r--arch/arm/boot/dts/exynos5250-snow.dts266
-rw-r--r--arch/arm/boot/dts/exynos5250-spring.dts566
-rw-r--r--arch/arm/boot/dts/exynos5250.dtsi20
-rw-r--r--arch/arm/boot/dts/exynos5420-peach-pit.dts7
-rw-r--r--arch/arm/boot/dts/exynos5420.dtsi4
-rw-r--r--arch/arm/boot/dts/exynos5800-peach-pi.dts7
-rw-r--r--arch/arm/boot/dts/hisi-x5hd2-dkb.dts33
-rw-r--r--arch/arm/boot/dts/hisi-x5hd2.dtsi390
-rw-r--r--arch/arm/boot/dts/imx51.dtsi12
-rw-r--r--arch/arm/boot/dts/imx53.dtsi25
-rw-r--r--arch/arm/boot/dts/imx6dl.dtsi8
-rw-r--r--arch/arm/boot/dts/imx6q-tbs2910.dts432
-rw-r--r--arch/arm/boot/dts/imx6q.dtsi4
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw52xx.dtsi1
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw53xx.dtsi1
-rw-r--r--arch/arm/boot/dts/imx6qdl-gw54xx.dtsi2
-rw-r--r--arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi131
-rw-r--r--arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi97
-rw-r--r--arch/arm/boot/dts/imx6qdl-rex.dtsi1
-rw-r--r--arch/arm/boot/dts/imx6qdl-sabresd.dtsi12
-rw-r--r--arch/arm/boot/dts/imx6qdl.dtsi14
-rw-r--r--arch/arm/boot/dts/imx6sl-evk.dts4
-rw-r--r--arch/arm/boot/dts/imx6sl.dtsi6
-rw-r--r--arch/arm/boot/dts/imx6sx-sdb.dts66
-rw-r--r--arch/arm/boot/dts/imx6sx.dtsi8
-rw-r--r--arch/arm/boot/dts/integrator.dtsi48
-rw-r--r--arch/arm/boot/dts/k2e-evm.dts12
-rw-r--r--arch/arm/boot/dts/k2e.dtsi45
-rw-r--r--arch/arm/boot/dts/k2l-evm.dts12
-rw-r--r--arch/arm/boot/dts/keystone.dtsi45
-rw-r--r--arch/arm/boot/dts/kirkwood-dir665.dts278
-rw-r--r--arch/arm/boot/dts/kirkwood-synology.dtsi2
-rw-r--r--arch/arm/boot/dts/ls1021a-qds.dts240
-rw-r--r--arch/arm/boot/dts/ls1021a-twr.dts127
-rw-r--r--arch/arm/boot/dts/ls1021a.dtsi408
-rw-r--r--arch/arm/boot/dts/meson.dtsi44
-rw-r--r--arch/arm/boot/dts/meson6-atv1200.dts2
-rw-r--r--arch/arm/boot/dts/meson6.dtsi2
-rw-r--r--arch/arm/boot/dts/meson8.dtsi92
-rw-r--r--arch/arm/boot/dts/mt6592-evb.dts26
-rw-r--r--arch/arm/boot/dts/mt6592.dtsi98
-rw-r--r--arch/arm/boot/dts/mt8127-moose.dts25
-rw-r--r--arch/arm/boot/dts/mt8127.dtsi94
-rw-r--r--arch/arm/boot/dts/mt8135-evbp1.dts25
-rw-r--r--arch/arm/boot/dts/mt8135.dtsi116
-rw-r--r--arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi41
-rw-r--r--arch/arm/boot/dts/omap-zoom-common.dtsi62
-rw-r--r--arch/arm/boot/dts/omap2420-n8x0-common.dtsi4
-rw-r--r--arch/arm/boot/dts/omap2420.dtsi1
-rw-r--r--arch/arm/boot/dts/omap2430-sdp.dts28
-rw-r--r--arch/arm/boot/dts/omap2430.dtsi1
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3517.dts11
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3530.dts11
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3730.dts24
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3x.dtsi151
-rw-r--r--arch/arm/boot/dts/omap3-cm-t3x30.dtsi35
-rw-r--r--arch/arm/boot/dts/omap3-devkit8000.dts4
-rw-r--r--arch/arm/boot/dts/omap3-evm-37xx.dts5
-rw-r--r--arch/arm/boot/dts/omap3-evm-common.dtsi21
-rw-r--r--arch/arm/boot/dts/omap3-gta04.dtsi86
-rw-r--r--arch/arm/boot/dts/omap3-igep.dtsi103
-rw-r--r--arch/arm/boot/dts/omap3-igep0020-common.dtsi246
-rw-r--r--arch/arm/boot/dts/omap3-igep0020-rev-f.dts45
-rw-r--r--arch/arm/boot/dts/omap3-igep0020.dts285
-rw-r--r--arch/arm/boot/dts/omap3-igep0030-common.dtsi60
-rw-r--r--arch/arm/boot/dts/omap3-igep0030-rev-g.dts67
-rw-r--r--arch/arm/boot/dts/omap3-igep0030.dts123
-rw-r--r--arch/arm/boot/dts/omap3-ldp.dts26
-rw-r--r--arch/arm/boot/dts/omap3-lilly-a83x.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3-n900.dts51
-rw-r--r--arch/arm/boot/dts/omap3-n950-n9.dtsi4
-rw-r--r--arch/arm/boot/dts/omap3-sb-t35.dtsi126
-rw-r--r--arch/arm/boot/dts/omap3-sbc-t3517.dts15
-rw-r--r--arch/arm/boot/dts/omap3-sbc-t3530.dts15
-rw-r--r--arch/arm/boot/dts/omap3-sbc-t3730.dts15
-rw-r--r--arch/arm/boot/dts/omap3-tao3530.dtsi2
-rw-r--r--arch/arm/boot/dts/omap3.dtsi3
-rw-r--r--arch/arm/boot/dts/omap3430-sdp.dts8
-rw-r--r--arch/arm/boot/dts/omap4-duovero-parlor.dts1
-rw-r--r--arch/arm/boot/dts/omap4.dtsi3
-rw-r--r--arch/arm/boot/dts/omap44xx-clocks.dtsi8
-rw-r--r--arch/arm/boot/dts/omap5.dtsi1
-rw-r--r--arch/arm/boot/dts/prima2.dtsi33
-rw-r--r--arch/arm/boot/dts/r7s72100-genmai.dts3
-rw-r--r--arch/arm/boot/dts/r7s72100.dtsi202
-rw-r--r--arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts7
-rw-r--r--arch/arm/boot/dts/r8a73a4.dtsi263
-rw-r--r--arch/arm/boot/dts/r8a7740-armadillo800eva.dts7
-rw-r--r--arch/arm/boot/dts/r8a7740.dtsi44
-rw-r--r--arch/arm/boot/dts/r8a7778-bockw-reference.dts7
-rw-r--r--arch/arm/boot/dts/r8a7778.dtsi42
-rw-r--r--arch/arm/boot/dts/r8a7779-marzen.dts84
-rw-r--r--arch/arm/boot/dts/r8a7779.dtsi34
-rw-r--r--arch/arm/boot/dts/r8a7790-lager.dts185
-rw-r--r--arch/arm/boot/dts/r8a7790.dtsi279
-rw-r--r--arch/arm/boot/dts/r8a7791-henninger.dts12
-rw-r--r--arch/arm/boot/dts/r8a7791-koelsch.dts118
-rw-r--r--arch/arm/boot/dts/r8a7791.dtsi255
-rw-r--r--arch/arm/boot/dts/r8a7794-alt.dts3
-rw-r--r--arch/arm/boot/dts/r8a7794.dtsi29
-rw-r--r--arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi41
-rw-r--r--arch/arm/boot/dts/rk3066a-bqcurie2.dts4
-rw-r--r--arch/arm/boot/dts/rk3066a-marsboard.dts206
-rw-r--r--arch/arm/boot/dts/rk3066a.dtsi115
-rw-r--r--arch/arm/boot/dts/rk3188-radxarock.dts23
-rw-r--r--arch/arm/boot/dts/rk3188.dtsi45
-rw-r--r--arch/arm/boot/dts/rk3288-evb-rk808.dts6
-rw-r--r--arch/arm/boot/dts/rk3288-evb.dtsi6
-rw-r--r--arch/arm/boot/dts/rk3288-thermal.dtsi74
-rw-r--r--arch/arm/boot/dts/rk3288.dtsi99
-rw-r--r--arch/arm/boot/dts/rk3xxx.dtsi17
-rw-r--r--arch/arm/boot/dts/s3c6410-mini6410.dts4
-rw-r--r--arch/arm/boot/dts/s3c64xx.dtsi1
-rw-r--r--arch/arm/boot/dts/sh73a0-kzm9g-reference.dts9
-rw-r--r--arch/arm/boot/dts/sh73a0.dtsi10
-rw-r--r--arch/arm/boot/dts/socfpga.dtsi27
-rw-r--r--arch/arm/boot/dts/socfpga_arria10.dtsi374
-rwxr-xr-xarch/arm/boot/dts/socfpga_arria10_socdk.dts48
-rw-r--r--arch/arm/boot/dts/socfpga_cyclone5.dtsi4
-rw-r--r--arch/arm/boot/dts/ste-ccu8540-pinctrl.dtsi64
-rw-r--r--arch/arm/boot/dts/ste-dbx5x0.dtsi22
-rw-r--r--arch/arm/boot/dts/ste-href-ab8500.dtsi162
-rw-r--r--arch/arm/boot/dts/ste-href-ab8505.dtsi90
-rw-r--r--arch/arm/boot/dts/ste-href-family-pinctrl.dtsi230
-rw-r--r--arch/arm/boot/dts/ste-href-stuib.dtsi4
-rw-r--r--arch/arm/boot/dts/ste-href-tvk1281618.dtsi12
-rw-r--r--arch/arm/boot/dts/ste-hrefprev60.dtsi20
-rw-r--r--arch/arm/boot/dts/ste-hrefv60plus.dtsi42
-rw-r--r--arch/arm/boot/dts/ste-nomadik-nhk15.dts151
-rw-r--r--arch/arm/boot/dts/ste-nomadik-s8815.dts64
-rw-r--r--arch/arm/boot/dts/ste-nomadik-stn8815.dtsi73
-rw-r--r--arch/arm/boot/dts/ste-snowball.dts36
-rw-r--r--arch/arm/boot/dts/stih407-b2120.dts55
-rw-r--r--arch/arm/boot/dts/stih407-clock.dtsi293
-rw-r--r--arch/arm/boot/dts/stih407-family.dtsi (renamed from arch/arm/boot/dts/stih407.dtsi)35
-rw-r--r--arch/arm/boot/dts/stih410-b2120.dts29
-rw-r--r--arch/arm/boot/dts/stih410-clock.dtsi338
-rw-r--r--arch/arm/boot/dts/stih410-pinctrl.dtsi34
-rw-r--r--arch/arm/boot/dts/stih410.dtsi14
-rw-r--r--arch/arm/boot/dts/stih415-pinctrl.dtsi361
-rw-r--r--arch/arm/boot/dts/stih415.dtsi12
-rw-r--r--arch/arm/boot/dts/stih416-b2020.dts22
-rw-r--r--arch/arm/boot/dts/stih416-b2020e.dts26
-rw-r--r--arch/arm/boot/dts/stih416-pinctrl.dtsi415
-rw-r--r--arch/arm/boot/dts/stih416.dtsi209
-rw-r--r--arch/arm/boot/dts/stih41x-b2000.dtsi6
-rw-r--r--arch/arm/boot/dts/stih41x-b2020.dtsi10
-rw-r--r--arch/arm/boot/dts/stih41x-b2020x.dtsi4
-rw-r--r--arch/arm/boot/dts/stihxxx-b2120.dtsi59
-rw-r--r--arch/arm/boot/dts/sun4i-a10-a1000.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-cubieboard.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-hackberry.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-inet97fv2.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-mini-xplus.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10-pcduino.dts46
-rw-r--r--arch/arm/boot/dts/sun4i-a10.dtsi14
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts46
-rw-r--r--arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts46
-rw-r--r--arch/arm/boot/dts/sun5i-a10s.dtsi14
-rw-r--r--arch/arm/boot/dts/sun5i-a13-hsg-h702.dts6
-rw-r--r--arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts48
-rw-r--r--arch/arm/boot/dts/sun5i-a13-olinuxino.dts46
-rw-r--r--arch/arm/boot/dts/sun6i-a31-app4-evb1.dts46
-rw-r--r--arch/arm/boot/dts/sun6i-a31-colombus.dts46
-rw-r--r--arch/arm/boot/dts/sun6i-a31-hummingbird.dts46
-rw-r--r--arch/arm/boot/dts/sun6i-a31-m9.dts103
-rw-r--r--arch/arm/boot/dts/sun6i-a31.dtsi46
-rw-r--r--arch/arm/boot/dts/sun7i-a20-bananapi.dts214
-rw-r--r--arch/arm/boot/dts/sun7i-a20-cubietruck.dts14
-rw-r--r--arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts46
-rw-r--r--arch/arm/boot/dts/sun7i-a20-m3.dts168
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts46
-rw-r--r--arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts228
-rw-r--r--arch/arm/boot/dts/sun7i-a20-pcduino3.dts46
-rw-r--r--arch/arm/boot/dts/sun7i-a20.dtsi45
-rw-r--r--arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts46
-rw-r--r--arch/arm/boot/dts/sun8i-a23.dtsi6
-rw-r--r--arch/arm/boot/dts/sun9i-a80-optimus.dts119
-rw-r--r--arch/arm/boot/dts/sun9i-a80.dtsi514
-rw-r--r--arch/arm/boot/dts/sunxi-common-regulators.dtsi66
-rw-r--r--arch/arm/boot/dts/tegra30-cardhu.dtsi2
-rw-r--r--arch/arm/boot/dts/vf-colibri-eval-v3.dtsi96
-rw-r--r--arch/arm/boot/dts/vf-colibri.dtsi186
-rw-r--r--arch/arm/boot/dts/vf500-colibri-eval-v3.dts17
-rw-r--r--arch/arm/boot/dts/vf500-colibri.dtsi20
-rw-r--r--arch/arm/boot/dts/vf500.dtsi171
-rw-r--r--arch/arm/boot/dts/vf610-colibri-eval-v3.dts33
-rw-r--r--arch/arm/boot/dts/vf610-colibri.dtsi100
-rw-r--r--arch/arm/boot/dts/vf610-cosmic.dts14
-rw-r--r--arch/arm/boot/dts/vf610-twr.dts46
-rw-r--r--arch/arm/boot/dts/vf610.dtsi486
-rw-r--r--arch/arm/boot/dts/vfxxx.dtsi437
-rw-r--r--arch/arm/boot/dts/zynq-7000.dtsi1
-rw-r--r--arch/arm/boot/dts/zynq-parallella.dts1
-rw-r--r--arch/arm/boot/dts/zynq-zc702.dts4
-rw-r--r--arch/arm/boot/dts/zynq-zc706.dts4
-rw-r--r--arch/arm/boot/dts/zynq-zed.dts4
-rw-r--r--arch/arm/boot/dts/zynq-zybo.dts52
-rw-r--r--arch/arm/common/edma.c54
-rw-r--r--arch/arm/configs/ape6evm_defconfig1
-rw-r--r--arch/arm/configs/at91_dt_defconfig3
-rw-r--r--arch/arm/configs/at91rm9200_defconfig161
-rw-r--r--arch/arm/configs/at91sam9260_9g20_defconfig145
-rw-r--r--arch/arm/configs/at91sam9261_9g10_defconfig147
-rw-r--r--arch/arm/configs/at91sam9263_defconfig151
-rw-r--r--arch/arm/configs/at91sam9g45_defconfig175
-rw-r--r--arch/arm/configs/at91sam9rl_defconfig92
-rw-r--r--arch/arm/configs/at91x40_defconfig48
-rw-r--r--arch/arm/configs/bcm_defconfig3
-rw-r--r--arch/arm/configs/exynos_defconfig1
-rw-r--r--arch/arm/configs/hisi_defconfig19
-rw-r--r--arch/arm/configs/imx_v6_v7_defconfig10
-rw-r--r--arch/arm/configs/integrator_defconfig3
-rw-r--r--arch/arm/configs/keystone_defconfig7
-rw-r--r--arch/arm/configs/koelsch_defconfig113
-rw-r--r--arch/arm/configs/multi_v5_defconfig2
-rw-r--r--arch/arm/configs/multi_v7_defconfig36
-rw-r--r--arch/arm/configs/mvebu_v5_defconfig2
-rw-r--r--arch/arm/configs/mvebu_v7_defconfig9
-rw-r--r--arch/arm/configs/nhk8815_defconfig11
-rw-r--r--arch/arm/configs/omap2plus_defconfig22
-rw-r--r--arch/arm/configs/sama5_defconfig7
-rw-r--r--arch/arm/configs/shmobile_defconfig4
-rw-r--r--arch/arm/configs/tegra_defconfig2
-rw-r--r--arch/arm/include/asm/arch_timer.h9
-rw-r--r--arch/arm/include/asm/cpuidle.h1
-rw-r--r--arch/arm/include/asm/firmware.h10
-rw-r--r--arch/arm/include/asm/io.h89
-rw-r--r--arch/arm/include/asm/mach/pci.h10
-rw-r--r--arch/arm/include/asm/memory.h4
-rw-r--r--arch/arm/include/asm/perf_event.h2
-rw-r--r--arch/arm/include/asm/pmu.h36
-rw-r--r--arch/arm/include/debug/asm9260.S29
-rw-r--r--arch/arm/include/debug/renesas-scif.S52
-rw-r--r--arch/arm/include/debug/sa1100.S (renamed from arch/arm/mach-sa1100/include/mach/debug-macro.S)10
-rw-r--r--arch/arm/kernel/Makefile2
-rw-r--r--arch/arm/kernel/bios32.c28
-rw-r--r--arch/arm/kernel/perf_callchain.c136
-rw-r--r--arch/arm/kernel/perf_event.c162
-rw-r--r--arch/arm/kernel/perf_event_cpu.c181
-rw-r--r--arch/arm/kernel/perf_event_v6.c12
-rw-r--r--arch/arm/kernel/perf_event_v7.c72
-rw-r--r--arch/arm/kernel/perf_event_xscale.c20
-rw-r--r--arch/arm/mach-asm9260/Kconfig6
-rw-r--r--arch/arm/mach-at91/Kconfig72
-rw-r--r--arch/arm/mach-at91/Kconfig.non_dt344
-rw-r--r--arch/arm/mach-at91/Makefile67
-rw-r--r--arch/arm/mach-at91/Makefile.boot6
-rw-r--r--arch/arm/mach-at91/at91_aic.h99
-rw-r--r--arch/arm/mach-at91/at91_tc.h146
-rw-r--r--arch/arm/mach-at91/at91rm9200.c341
-rw-r--r--arch/arm/mach-at91/at91rm9200_devices.c1212
-rw-r--r--arch/arm/mach-at91/at91rm9200_time.c23
-rw-r--r--arch/arm/mach-at91/at91sam9260.c397
-rw-r--r--arch/arm/mach-at91/at91sam9260_devices.c1364
-rw-r--r--arch/arm/mach-at91/at91sam9261.c375
-rw-r--r--arch/arm/mach-at91/at91sam9261_devices.c1098
-rw-r--r--arch/arm/mach-at91/at91sam9263.c399
-rw-r--r--arch/arm/mach-at91/at91sam9263_devices.c1538
-rw-r--r--arch/arm/mach-at91/at91sam9g45.c456
-rw-r--r--arch/arm/mach-at91/at91sam9g45_devices.c1915
-rw-r--r--arch/arm/mach-at91/at91sam9n12.c213
-rw-r--r--arch/arm/mach-at91/at91sam9rl.c378
-rw-r--r--arch/arm/mach-at91/at91sam9rl_devices.c1260
-rw-r--r--arch/arm/mach-at91/at91sam9x5.c311
-rw-r--r--arch/arm/mach-at91/at91x40.c93
-rw-r--r--arch/arm/mach-at91/at91x40_time.c85
-rw-r--r--arch/arm/mach-at91/board-1arm.c99
-rw-r--r--arch/arm/mach-at91/board-afeb-9260v1.c223
-rw-r--r--arch/arm/mach-at91/board-cam60.c199
-rw-r--r--arch/arm/mach-at91/board-carmeva.c167
-rw-r--r--arch/arm/mach-at91/board-cpu9krea.c386
-rw-r--r--arch/arm/mach-at91/board-cpuat91.c189
-rw-r--r--arch/arm/mach-at91/board-csb337.c260
-rw-r--r--arch/arm/mach-at91/board-csb637.c142
-rw-r--r--arch/arm/mach-at91/board-dt-rm9200.c3
-rw-r--r--arch/arm/mach-at91/board-dt-sam9.c2
-rw-r--r--arch/arm/mach-at91/board-dt-sama5.c1
-rw-r--r--arch/arm/mach-at91/board-eb01.c52
-rw-r--r--arch/arm/mach-at91/board-eb9200.c126
-rw-r--r--arch/arm/mach-at91/board-ecbat91.c191
-rw-r--r--arch/arm/mach-at91/board-eco920.c160
-rw-r--r--arch/arm/mach-at91/board-flexibity.c171
-rw-r--r--arch/arm/mach-at91/board-gsia18s.c585
-rw-r--r--arch/arm/mach-at91/board-kafa.c113
-rw-r--r--arch/arm/mach-at91/board-kb9202.c159
-rw-r--r--arch/arm/mach-at91/board-pcontrol-g20.c228
-rw-r--r--arch/arm/mach-at91/board-picotux200.c129
-rw-r--r--arch/arm/mach-at91/board-rm9200ek.c196
-rw-r--r--arch/arm/mach-at91/board-sam9-l9260.c230
-rw-r--r--arch/arm/mach-at91/board-sam9260ek.c354
-rw-r--r--arch/arm/mach-at91/board-sam9261ek.c623
-rw-r--r--arch/arm/mach-at91/board-sam9263ek.c493
-rw-r--r--arch/arm/mach-at91/board-sam9g20ek.c429
-rw-r--r--arch/arm/mach-at91/board-sam9m10g45ek.c527
-rw-r--r--arch/arm/mach-at91/board-sam9rlek.c333
-rw-r--r--arch/arm/mach-at91/board-snapper9260.c191
-rw-r--r--arch/arm/mach-at91/board-stamp9g20.c294
-rw-r--r--arch/arm/mach-at91/board-yl-9200.c597
-rw-r--r--arch/arm/mach-at91/board.h127
-rw-r--r--arch/arm/mach-at91/clock.c977
-rw-r--r--arch/arm/mach-at91/clock.h49
-rw-r--r--arch/arm/mach-at91/generic.h53
-rw-r--r--arch/arm/mach-at91/gpio.c982
-rw-r--r--arch/arm/mach-at91/gpio.h214
-rw-r--r--arch/arm/mach-at91/gsia18s.h33
-rw-r--r--arch/arm/mach-at91/include/mach/at91_dbgu.h3
-rw-r--r--arch/arm/mach-at91/include/mach/at91_ramc.h6
-rw-r--r--arch/arm/mach-at91/include/mach/at91x40.h60
-rw-r--r--arch/arm/mach-at91/include/mach/cpu.h1
-rw-r--r--arch/arm/mach-at91/include/mach/hardware.h10
-rw-r--r--arch/arm/mach-at91/include/mach/uncompress.h7
-rw-r--r--arch/arm/mach-at91/irq.c296
-rw-r--r--arch/arm/mach-at91/leds.c56
-rw-r--r--arch/arm/mach-at91/pm.c33
-rw-r--r--arch/arm/mach-at91/pm.h1
-rw-r--r--arch/arm/mach-at91/setup.c67
-rw-r--r--arch/arm/mach-at91/soc.h6
-rw-r--r--arch/arm/mach-at91/stamp9g20.h7
-rw-r--r--arch/arm/mach-bcm/Kconfig97
-rw-r--r--arch/arm/mach-bcm/Makefile5
-rw-r--r--arch/arm/mach-bcm/bcm_cygnus.c25
-rw-r--r--arch/arm/mach-bcm/brcmstb.h19
-rw-r--r--arch/arm/mach-bcm/headsmp-brcmstb.S33
-rw-r--r--arch/arm/mach-bcm/platsmp-brcmstb.c329
-rw-r--r--arch/arm/mach-berlin/Kconfig3
-rw-r--r--arch/arm/mach-davinci/board-da830-evm.c89
-rw-r--r--arch/arm/mach-davinci/board-da850-evm.c9
-rw-r--r--arch/arm/mach-davinci/board-dm355-evm.c2
-rw-r--r--arch/arm/mach-davinci/board-dm365-evm.c4
-rw-r--r--arch/arm/mach-davinci/board-dm644x-evm.c10
-rw-r--r--arch/arm/mach-davinci/board-mityomapl138.c45
-rw-r--r--arch/arm/mach-davinci/board-neuros-osd2.c5
-rw-r--r--arch/arm/mach-davinci/clock.c2
-rw-r--r--arch/arm/mach-davinci/cpuidle.c1
-rw-r--r--arch/arm/mach-davinci/dm355.c7
-rw-r--r--arch/arm/mach-davinci/dm365.c7
-rw-r--r--arch/arm/mach-davinci/mux.c15
-rw-r--r--arch/arm/mach-davinci/time.c13
-rw-r--r--arch/arm/mach-ebsa110/include/mach/io.h25
-rw-r--r--arch/arm/mach-ebsa110/io.c14
-rw-r--r--arch/arm/mach-ep93xx/dma.c12
-rw-r--r--arch/arm/mach-exynos/Kconfig11
-rw-r--r--arch/arm/mach-exynos/Makefile7
-rw-r--r--arch/arm/mach-exynos/common.h33
-rw-r--r--arch/arm/mach-exynos/exynos-pmu.h24
-rw-r--r--arch/arm/mach-exynos/exynos.c80
-rw-r--r--arch/arm/mach-exynos/firmware.c67
-rw-r--r--arch/arm/mach-exynos/hotplug.c91
-rw-r--r--arch/arm/mach-exynos/include/mach/map.h23
-rw-r--r--arch/arm/mach-exynos/mcpm-exynos.c32
-rw-r--r--arch/arm/mach-exynos/platsmp.c148
-rw-r--r--arch/arm/mach-exynos/pm.c311
-rw-r--r--arch/arm/mach-exynos/pmu.c675
-rw-r--r--arch/arm/mach-exynos/regs-pmu.h361
-rw-r--r--arch/arm/mach-exynos/sleep.S28
-rw-r--r--arch/arm/mach-exynos/smc.h4
-rw-r--r--arch/arm/mach-exynos/suspend.c566
-rw-r--r--arch/arm/mach-imx/Kconfig31
-rw-r--r--arch/arm/mach-imx/Makefile6
-rw-r--r--arch/arm/mach-imx/anatop.c34
-rw-r--r--arch/arm/mach-imx/clk-cpu.c107
-rw-r--r--arch/arm/mach-imx/clk-imx51-imx53.c14
-rw-r--r--arch/arm/mach-imx/clk-imx6q.c2
-rw-r--r--arch/arm/mach-imx/clk-pllv3.c7
-rw-r--r--arch/arm/mach-imx/clk-vf610.c21
-rw-r--r--arch/arm/mach-imx/clk.h4
-rw-r--r--arch/arm/mach-imx/common.h7
-rw-r--r--arch/arm/mach-imx/cpuidle-imx5.c1
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6q.c3
-rw-r--r--arch/arm/mach-imx/cpuidle-imx6sl.c3
-rw-r--r--arch/arm/mach-imx/gpc.c42
-rw-r--r--arch/arm/mach-imx/imx25-dt.c9
-rw-r--r--arch/arm/mach-imx/imx27-dt.c3
-rw-r--r--arch/arm/mach-imx/imx31-dt.c9
-rw-r--r--arch/arm/mach-imx/imx35-dt.c10
-rw-r--r--arch/arm/mach-imx/iomux-imx31.c8
-rw-r--r--arch/arm/mach-imx/iomux-mx3.h2
-rw-r--r--arch/arm/mach-imx/mach-imx50.c9
-rw-r--r--arch/arm/mach-imx/mach-imx51.c2
-rw-r--r--arch/arm/mach-imx/mach-imx53.c4
-rw-r--r--arch/arm/mach-imx/mach-imx6q.c3
-rw-r--r--arch/arm/mach-imx/mach-imx6sl.c4
-rw-r--r--arch/arm/mach-imx/mach-imx6sx.c55
-rw-r--r--arch/arm/mach-imx/mach-ls1021a.c22
-rw-r--r--arch/arm/mach-imx/mach-vf610.c10
-rw-r--r--arch/arm/mach-imx/mmdc.c17
-rw-r--r--arch/arm/mach-imx/mxc.h2
-rw-r--r--arch/arm/mach-imx/platsmp.c33
-rw-r--r--arch/arm/mach-imx/pm-imx6.c15
-rw-r--r--arch/arm/mach-imx/suspend-imx6.S14
-rw-r--r--arch/arm/mach-imx/system.c15
-rw-r--r--arch/arm/mach-integrator/Kconfig23
-rw-r--r--arch/arm/mach-integrator/Makefile2
-rw-r--r--arch/arm/mach-integrator/cm.h1
-rw-r--r--arch/arm/mach-integrator/common.h2
-rw-r--r--arch/arm/mach-integrator/core.c103
-rw-r--r--arch/arm/mach-integrator/include/mach/uncompress.h48
-rw-r--r--arch/arm/mach-integrator/integrator_ap.c218
-rw-r--r--arch/arm/mach-integrator/integrator_cp.c28
-rw-r--r--arch/arm/mach-integrator/leds.c124
-rw-r--r--arch/arm/mach-iop13xx/msi.c10
-rw-r--r--arch/arm/mach-ixp4xx/common.c2
-rw-r--r--arch/arm/mach-ixp4xx/include/mach/io.h24
-rw-r--r--arch/arm/mach-keystone/Kconfig2
-rw-r--r--arch/arm/mach-mediatek/Kconfig4
-rw-r--r--arch/arm/mach-mediatek/mediatek.c3
-rw-r--r--arch/arm/mach-meson/Kconfig6
-rw-r--r--arch/arm/mach-meson/meson.c10
-rw-r--r--arch/arm/mach-mvebu/Makefile2
-rw-r--r--arch/arm/mach-mvebu/armada-370-xp.h6
-rw-r--r--arch/arm/mach-mvebu/board-v7.c122
-rw-r--r--arch/arm/mach-mvebu/coherency.c221
-rw-r--r--arch/arm/mach-mvebu/coherency_ll.S21
-rw-r--r--arch/arm/mach-mvebu/common.h2
-rw-r--r--arch/arm/mach-mvebu/cpu-reset.c1
-rw-r--r--arch/arm/mach-mvebu/headsmp-a9.S1
-rw-r--r--arch/arm/mach-mvebu/platsmp-a9.c53
-rw-r--r--arch/arm/mach-mvebu/platsmp.c33
-rw-r--r--arch/arm/mach-mvebu/pm-board.c141
-rw-r--r--arch/arm/mach-mvebu/pm.c218
-rw-r--r--arch/arm/mach-mvebu/pmsu.c11
-rw-r--r--arch/arm/mach-mvebu/pmsu.h3
-rw-r--r--arch/arm/mach-mvebu/pmsu_ll.S28
-rw-r--r--arch/arm/mach-nomadik/cpu-8815.c1
-rw-r--r--arch/arm/mach-omap2/Kconfig18
-rw-r--r--arch/arm/mach-omap2/Makefile10
-rw-r--r--arch/arm/mach-omap2/am33xx-restart.c12
-rw-r--r--arch/arm/mach-omap2/board-3430sdp.c632
-rw-r--r--arch/arm/mach-omap2/board-am3517crane.c1
-rw-r--r--arch/arm/mach-omap2/board-cm-t35.c3
-rw-r--r--arch/arm/mach-omap2/board-cm-t3517.c3
-rw-r--r--arch/arm/mach-omap2/board-flash.c3
-rw-r--r--arch/arm/mach-omap2/board-flash.h1
-rw-r--r--arch/arm/mach-omap2/board-n8x0.c4
-rw-r--r--arch/arm/mach-omap2/board-omap3pandora.c2
-rw-r--r--arch/arm/mach-omap2/board-rx51-peripherals.c107
-rw-r--r--arch/arm/mach-omap2/board-ti8168evm.c62
-rw-r--r--arch/arm/mach-omap2/cclock3xxx_data.c6
-rw-r--r--arch/arm/mach-omap2/clock.c7
-rw-r--r--arch/arm/mach-omap2/clock.h1
-rw-r--r--arch/arm/mach-omap2/clock3xxx.c38
-rw-r--r--arch/arm/mach-omap2/cm.h18
-rw-r--r--arch/arm/mach-omap2/cm1_44xx.h2
-rw-r--r--arch/arm/mach-omap2/cm1_54xx.h2
-rw-r--r--arch/arm/mach-omap2/cm1_7xx.h2
-rw-r--r--arch/arm/mach-omap2/cm2_44xx.h2
-rw-r--r--arch/arm/mach-omap2/cm2_54xx.h2
-rw-r--r--arch/arm/mach-omap2/cm2_7xx.h2
-rw-r--r--arch/arm/mach-omap2/cm2xxx.c17
-rw-r--r--arch/arm/mach-omap2/cm2xxx.h10
-rw-r--r--arch/arm/mach-omap2/cm33xx.c61
-rw-r--r--arch/arm/mach-omap2/cm33xx.h37
-rw-r--r--arch/arm/mach-omap2/cm3xxx.c19
-rw-r--r--arch/arm/mach-omap2/cm3xxx.h12
-rw-r--r--arch/arm/mach-omap2/cm44xx.c49
-rw-r--r--arch/arm/mach-omap2/cm44xx.h3
-rw-r--r--arch/arm/mach-omap2/cm_44xx_54xx.h36
-rw-r--r--arch/arm/mach-omap2/cm_common.c82
-rw-r--r--arch/arm/mach-omap2/cminst44xx.c80
-rw-r--r--arch/arm/mach-omap2/cminst44xx.h43
-rw-r--r--arch/arm/mach-omap2/cpuidle34xx.c7
-rw-r--r--arch/arm/mach-omap2/cpuidle44xx.c5
-rw-r--r--arch/arm/mach-omap2/devices.c93
-rw-r--r--arch/arm/mach-omap2/dpll3xxx.c179
-rw-r--r--arch/arm/mach-omap2/dpll44xx.c41
-rw-r--r--arch/arm/mach-omap2/gpmc-nand.c3
-rw-r--r--arch/arm/mach-omap2/gpmc-nand.h27
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.c3
-rw-r--r--arch/arm/mach-omap2/gpmc-onenand.h24
-rw-r--r--arch/arm/mach-omap2/gpmc-smc91x.c186
-rw-r--r--arch/arm/mach-omap2/gpmc-smc91x.h42
-rw-r--r--arch/arm/mach-omap2/gpmc.h227
-rw-r--r--arch/arm/mach-omap2/hsmmc.c158
-rw-r--r--arch/arm/mach-omap2/hsmmc.h9
-rw-r--r--arch/arm/mach-omap2/io.c11
-rw-r--r--arch/arm/mach-omap2/mmc.h10
-rw-r--r--arch/arm/mach-omap2/omap-mpuss-lowpower.c4
-rw-r--r--arch/arm/mach-omap2/omap2-restart.c5
-rw-r--r--arch/arm/mach-omap2/omap3-restart.c7
-rw-r--r--arch/arm/mach-omap2/omap4-common.c1
-rw-r--r--arch/arm/mach-omap2/omap4-restart.c6
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.c272
-rw-r--r--arch/arm/mach-omap2/omap_hwmod.h8
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_2430_data.c4
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c8
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_33xx_data.c1
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_3xxx_data.c8
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_43xx_data.c39
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_44xx_data.c29
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_54xx_data.c9
-rw-r--r--arch/arm/mach-omap2/omap_hwmod_7xx_data.c104
-rw-r--r--arch/arm/mach-omap2/omap_phy_internal.c8
-rw-r--r--arch/arm/mach-omap2/pdata-quirks.c39
-rw-r--r--arch/arm/mach-omap2/pm34xx.c2
-rw-r--r--arch/arm/mach-omap2/pm44xx.c146
-rw-r--r--arch/arm/mach-omap2/prm.h16
-rw-r--r--arch/arm/mach-omap2/prm2xxx.c6
-rw-r--r--arch/arm/mach-omap2/prm2xxx.h1
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.c19
-rw-r--r--arch/arm/mach-omap2/prm2xxx_3xxx.h9
-rw-r--r--arch/arm/mach-omap2/prm33xx.c64
-rw-r--r--arch/arm/mach-omap2/prm33xx.h11
-rw-r--r--arch/arm/mach-omap2/prm3xxx.c32
-rw-r--r--arch/arm/mach-omap2/prm3xxx.h16
-rw-r--r--arch/arm/mach-omap2/prm44xx.c36
-rw-r--r--arch/arm/mach-omap2/prm44xx_54xx.h19
-rw-r--r--arch/arm/mach-omap2/prm_common.c99
-rw-r--r--arch/arm/mach-omap2/prminst44xx.c10
-rw-r--r--arch/arm/mach-omap2/prminst44xx.h5
-rw-r--r--arch/arm/mach-omap2/serial.c3
-rw-r--r--arch/arm/mach-pxa/Kconfig11
-rw-r--r--arch/arm/mach-pxa/Makefile1
-rw-r--r--arch/arm/mach-pxa/em-x270.c4
-rw-r--r--arch/arm/mach-pxa/generic.h65
-rw-r--r--arch/arm/mach-pxa/gumstix.c3
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa25x.h8
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa27x.h4
-rw-r--r--arch/arm/mach-pxa/include/mach/pxa3xx.h5
-rw-r--r--arch/arm/mach-pxa/mfp-pxa2xx.c12
-rw-r--r--arch/arm/mach-pxa/poodle.c2
-rw-r--r--arch/arm/mach-pxa/pxa-dt.c18
-rw-r--r--arch/arm/mach-pxa/pxa27x.c6
-rw-r--r--arch/arm/mach-pxa/pxa3xx-ulpi.c6
-rw-r--r--arch/arm/mach-pxa/raumfeld.c26
-rw-r--r--arch/arm/mach-pxa/spitz.c9
-rw-r--r--arch/arm/mach-pxa/tosa.c41
-rw-r--r--arch/arm/mach-realview/Kconfig13
-rw-r--r--arch/arm/mach-realview/Makefile1
-rw-r--r--arch/arm/mach-realview/realview-dt.c32
-rw-r--r--arch/arm/mach-rockchip/headsmp.S5
-rw-r--r--arch/arm/mach-rockchip/platsmp.c223
-rw-r--r--arch/arm/mach-rockchip/rockchip.c7
-rw-r--r--arch/arm/mach-s3c24xx/h1940-bluetooth.c4
-rw-r--r--arch/arm/mach-s3c24xx/h1940.h4
-rw-r--r--arch/arm/mach-s3c24xx/mach-h1940.c3
-rw-r--r--arch/arm/mach-s3c24xx/mach-rx1950.c3
-rw-r--r--arch/arm/mach-s3c64xx/cpuidle.c1
-rw-r--r--arch/arm/mach-sa1100/pci-nanoengine.c8
-rw-r--r--arch/arm/mach-shmobile/Kconfig22
-rw-r--r--arch/arm/mach-shmobile/Makefile6
-rw-r--r--arch/arm/mach-shmobile/Makefile.boot1
-rw-r--r--arch/arm/mach-shmobile/board-ape6evm-reference.c5
-rw-r--r--arch/arm/mach-shmobile/board-ape6evm.c4
-rw-r--r--arch/arm/mach-shmobile/board-armadillo800eva.c57
-rw-r--r--arch/arm/mach-shmobile/board-bockw-reference.c4
-rw-r--r--arch/arm/mach-shmobile/board-bockw.c4
-rw-r--r--arch/arm/mach-shmobile/board-koelsch-reference.c117
-rw-r--r--arch/arm/mach-shmobile/board-koelsch.c527
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g-reference.c12
-rw-r--r--arch/arm/mach-shmobile/board-kzm9g.c4
-rw-r--r--arch/arm/mach-shmobile/board-lager-reference.c84
-rw-r--r--arch/arm/mach-shmobile/board-lager.c4
-rw-r--r--arch/arm/mach-shmobile/board-mackerel.c6
-rw-r--r--arch/arm/mach-shmobile/board-marzen-reference.c5
-rw-r--r--arch/arm/mach-shmobile/board-marzen.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a73a4.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7740.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7778.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7779.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7790.c4
-rw-r--r--arch/arm/mach-shmobile/clock-r8a7791.c342
-rw-r--r--arch/arm/mach-shmobile/clock-sh7372.c4
-rw-r--r--arch/arm/mach-shmobile/clock-sh73a0.c4
-rw-r--r--arch/arm/mach-shmobile/clock.c36
-rw-r--r--arch/arm/mach-shmobile/clock.h14
-rw-r--r--arch/arm/mach-shmobile/common.h5
-rw-r--r--arch/arm/mach-shmobile/console.c4
-rw-r--r--arch/arm/mach-shmobile/headsmp-scu.S5
-rw-r--r--arch/arm/mach-shmobile/intc-sh7372.c4
-rw-r--r--arch/arm/mach-shmobile/intc-sh73a0.c4
-rw-r--r--arch/arm/mach-shmobile/platsmp-apmu.c27
-rw-r--r--arch/arm/mach-shmobile/platsmp-apmu.h32
-rw-r--r--arch/arm/mach-shmobile/pm-r8a7740.c44
-rw-r--r--arch/arm/mach-shmobile/pm-r8a7779.c3
-rw-r--r--arch/arm/mach-shmobile/pm-rmobile.c3
-rw-r--r--arch/arm/mach-shmobile/pm-sh7372.c4
-rw-r--r--arch/arm/mach-shmobile/r8a73a4.h1
-rw-r--r--arch/arm/mach-shmobile/r8a7740.h4
-rw-r--r--arch/arm/mach-shmobile/r8a7778.h5
-rw-r--r--arch/arm/mach-shmobile/r8a7791.h3
-rw-r--r--arch/arm/mach-shmobile/setup-emev2.c4
-rw-r--r--arch/arm/mach-shmobile/setup-r7s72100.c4
-rw-r--r--arch/arm/mach-shmobile/setup-r8a73a4.c13
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7740.c16
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7778.c14
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7779.c11
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7790.c4
-rw-r--r--arch/arm/mach-shmobile/setup-r8a7791.c185
-rw-r--r--arch/arm/mach-shmobile/setup-rcar-gen2.c76
-rw-r--r--arch/arm/mach-shmobile/setup-sh7372.c8
-rw-r--r--arch/arm/mach-shmobile/setup-sh73a0.c24
-rw-r--r--arch/arm/mach-shmobile/sh73a0.h1
-rw-r--r--arch/arm/mach-shmobile/sleep-sh7372.S5
-rw-r--r--arch/arm/mach-shmobile/smp-emev2.c4
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7779.c4
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7790.c16
-rw-r--r--arch/arm/mach-shmobile/smp-r8a7791.c12
-rw-r--r--arch/arm/mach-shmobile/smp-sh73a0.c4
-rw-r--r--arch/arm/mach-shmobile/timer.c28
-rw-r--r--arch/arm/mach-socfpga/core.h3
-rw-r--r--arch/arm/mach-socfpga/platsmp.c19
-rw-r--r--arch/arm/mach-sti/Kconfig10
-rw-r--r--arch/arm/mach-sunxi/Kconfig7
-rw-r--r--arch/arm/mach-sunxi/platsmp.c2
-rw-r--r--arch/arm/mach-sunxi/sunxi.c9
-rw-r--r--arch/arm/mach-tegra/Kconfig9
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra114.c3
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra20.c3
-rw-r--r--arch/arm/mach-tegra/cpuidle-tegra30.c1
-rw-r--r--arch/arm/mach-tegra/reset-handler.S1
-rw-r--r--arch/arm/mach-u300/dummyspichip.c65
-rw-r--r--arch/arm/mach-ux500/Kconfig1
-rw-r--r--arch/arm/mach-ux500/Makefile1
-rw-r--r--arch/arm/mach-ux500/pm.c4
-rw-r--r--arch/arm/mach-ux500/pm_domains.c79
-rw-r--r--arch/arm/mach-ux500/pm_domains.h17
-rw-r--r--arch/arm/mach-vexpress/Kconfig4
-rw-r--r--arch/arm/mach-vexpress/Makefile3
-rw-r--r--arch/arm/mach-vexpress/core.h7
-rw-r--r--arch/arm/mach-vexpress/ct-ca9x4.c212
-rw-r--r--arch/arm/mach-vexpress/include/mach/ct-ca9x4.h47
-rw-r--r--arch/arm/mach-vexpress/include/mach/hardware.h1
-rw-r--r--arch/arm/mach-vexpress/include/mach/irqs.h6
-rw-r--r--arch/arm/mach-vexpress/include/mach/motherboard.h88
-rw-r--r--arch/arm/mach-vexpress/platsmp.c42
-rw-r--r--arch/arm/mach-vexpress/v2m.c374
-rw-r--r--arch/arm/mach-zynq/Makefile2
-rw-r--r--arch/arm/mach-zynq/common.h1
-rw-r--r--arch/arm/mach-zynq/hotplug.c14
-rw-r--r--arch/arm/mm/Kconfig28
-rw-r--r--arch/arm/plat-orion/gpio.c11
-rw-r--r--arch/arm/plat-orion/include/plat/orion-gpio.h5
-rw-r--r--arch/arm/plat-samsung/Makefile1
-rw-r--r--arch/arm/plat-samsung/include/plat/map-s5p.h21
-rw-r--r--arch/arm/plat-versatile/Kconfig2
-rw-r--r--arch/arm64/Kconfig197
-rw-r--r--arch/arm64/Kconfig.debug12
-rw-r--r--arch/arm64/Makefile10
-rw-r--r--arch/arm64/boot/dts/Makefile16
-rw-r--r--arch/arm64/boot/dts/amd/Makefile5
-rw-r--r--arch/arm64/boot/dts/amd/amd-overdrive.dts66
-rw-r--r--arch/arm64/boot/dts/amd/amd-seattle-clks.dtsi54
-rw-r--r--arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi172
-rw-r--r--arch/arm64/boot/dts/apm/Makefile5
-rw-r--r--arch/arm64/boot/dts/apm/apm-mustang.dts (renamed from arch/arm64/boot/dts/apm-mustang.dts)0
-rw-r--r--arch/arm64/boot/dts/apm/apm-storm.dtsi (renamed from arch/arm64/boot/dts/apm-storm.dtsi)0
-rw-r--r--arch/arm64/boot/dts/arm/Makefile7
-rw-r--r--arch/arm64/boot/dts/arm/foundation-v8.dts (renamed from arch/arm64/boot/dts/foundation-v8.dts)8
-rw-r--r--arch/arm64/boot/dts/arm/juno-clocks.dtsi44
-rw-r--r--arch/arm64/boot/dts/arm/juno-motherboard.dtsi129
-rw-r--r--arch/arm64/boot/dts/arm/juno.dts218
-rw-r--r--arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts (renamed from arch/arm64/boot/dts/rtsm_ve-aemv8a.dts)8
-rw-r--r--arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi (renamed from arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi)0
-rw-r--r--arch/arm64/boot/dts/cavium/Makefile5
-rw-r--r--arch/arm64/boot/dts/cavium/thunder-88xx.dts (renamed from arch/arm64/boot/dts/thunder-88xx.dts)0
-rw-r--r--arch/arm64/boot/dts/cavium/thunder-88xx.dtsi (renamed from arch/arm64/boot/dts/thunder-88xx.dtsi)0
l---------arch/arm64/boot/dts/include/dt-bindings1
-rw-r--r--arch/arm64/crypto/Kconfig5
-rw-r--r--arch/arm64/crypto/aes-ce-ccm-glue.c4
-rw-r--r--arch/arm64/crypto/aes-ce-cipher.c112
-rw-r--r--arch/arm64/crypto/aes-ce-setkey.h5
-rw-r--r--arch/arm64/crypto/aes-glue.c18
-rw-r--r--arch/arm64/include/asm/alternative-asm.h29
-rw-r--r--arch/arm64/include/asm/alternative.h44
-rw-r--r--arch/arm64/include/asm/arch_timer.h9
-rw-r--r--arch/arm64/include/asm/cache.h2
-rw-r--r--arch/arm64/include/asm/cacheflush.h2
-rw-r--r--arch/arm64/include/asm/cmpxchg.h73
-rw-r--r--arch/arm64/include/asm/compat.h7
-rw-r--r--arch/arm64/include/asm/cpu.h2
-rw-r--r--arch/arm64/include/asm/cpufeature.h29
-rw-r--r--arch/arm64/include/asm/cputype.h5
-rw-r--r--arch/arm64/include/asm/dmi.h31
-rw-r--r--arch/arm64/include/asm/fixmap.h8
-rw-r--r--arch/arm64/include/asm/hwcap.h1
-rw-r--r--arch/arm64/include/asm/insn.h10
-rw-r--r--arch/arm64/include/asm/io.h145
-rw-r--r--arch/arm64/include/asm/irq.h3
-rw-r--r--arch/arm64/include/asm/kvm_arm.h21
-rw-r--r--arch/arm64/include/asm/memory.h2
-rw-r--r--arch/arm64/include/asm/opcodes.h1
-rw-r--r--arch/arm64/include/asm/percpu.h215
-rw-r--r--arch/arm64/include/asm/pgalloc.h8
-rw-r--r--arch/arm64/include/asm/pgtable.h1
-rw-r--r--arch/arm64/include/asm/seccomp.h25
-rw-r--r--arch/arm64/include/asm/tlb.h67
-rw-r--r--arch/arm64/include/asm/traps.h16
-rw-r--r--arch/arm64/include/asm/unistd.h3
-rw-r--r--arch/arm64/include/asm/unistd32.h3
-rw-r--r--arch/arm64/kernel/Makefile7
-rw-r--r--arch/arm64/kernel/alternative.c85
-rw-r--r--arch/arm64/kernel/armv8_deprecated.c553
-rw-r--r--arch/arm64/kernel/cpu_errata.c111
-rw-r--r--arch/arm64/kernel/cpuinfo.c23
-rw-r--r--arch/arm64/kernel/efi-entry.S3
-rw-r--r--arch/arm64/kernel/efi.c37
-rw-r--r--arch/arm64/kernel/entry-ftrace.S21
-rw-r--r--arch/arm64/kernel/entry.S138
-rw-r--r--arch/arm64/kernel/head.S434
-rw-r--r--arch/arm64/kernel/insn.c26
-rw-r--r--arch/arm64/kernel/io.c66
-rw-r--r--arch/arm64/kernel/irq.c2
-rw-r--r--arch/arm64/kernel/jump_label.c23
-rw-r--r--arch/arm64/kernel/module.c18
-rw-r--r--arch/arm64/kernel/perf_event.c10
-rw-r--r--arch/arm64/kernel/ptrace.c40
-rw-r--r--arch/arm64/kernel/setup.c108
-rw-r--r--arch/arm64/kernel/signal32.c6
-rw-r--r--arch/arm64/kernel/sleep.S36
-rw-r--r--arch/arm64/kernel/smp.c2
-rw-r--r--arch/arm64/kernel/suspend.c4
-rw-r--r--arch/arm64/kernel/sys_compat.c49
-rw-r--r--arch/arm64/kernel/topology.c7
-rw-r--r--arch/arm64/kernel/trace-events-emulation.h35
-rw-r--r--arch/arm64/kernel/traps.c66
-rw-r--r--arch/arm64/kernel/vmlinux.lds.S33
-rw-r--r--arch/arm64/kvm/hyp.S4
-rw-r--r--arch/arm64/mm/Makefile1
-rw-r--r--arch/arm64/mm/cache.S10
-rw-r--r--arch/arm64/mm/dump.c332
-rw-r--r--arch/arm64/mm/fault.c2
-rw-r--r--arch/arm64/mm/init.c2
-rw-r--r--arch/arm64/mm/ioremap.c93
-rw-r--r--arch/arm64/mm/mm.h1
-rw-r--r--arch/arm64/mm/mmap.c12
-rw-r--r--arch/arm64/mm/mmu.c94
-rw-r--r--arch/arm64/mm/pgd.c4
-rw-r--r--arch/arm64/net/bpf_jit_comp.c13
-rw-r--r--arch/avr32/mach-at32ap/at32ap700x.c2
-rw-r--r--arch/avr32/mach-at32ap/include/mach/atmel-mci.h17
-rw-r--r--arch/cris/include/asm/io.h3
-rw-r--r--arch/frv/include/asm/io.h3
-rw-r--r--arch/ia64/Kconfig2
-rw-r--r--arch/ia64/include/asm/io.h4
-rw-r--r--arch/ia64/include/asm/uaccess.h16
-rw-r--r--arch/ia64/include/uapi/asm/siginfo.h8
-rw-r--r--arch/ia64/kernel/msi_ia64.c8
-rw-r--r--arch/ia64/kernel/perfmon.c2
-rw-r--r--arch/ia64/sn/kernel/msi_sn.c8
-rw-r--r--arch/m32r/include/asm/io.h3
-rw-r--r--arch/m68k/atari/config.c27
-rw-r--r--arch/m68k/atari/stdma.c61
-rw-r--r--arch/m68k/include/asm/atari_stdma.h4
-rw-r--r--arch/m68k/include/asm/io.h8
-rw-r--r--arch/m68k/include/asm/io_no.h4
-rw-r--r--arch/m68k/include/asm/macintosh.h4
-rw-r--r--arch/m68k/mac/config.c146
-rw-r--r--arch/m68k/mm/init.c1
-rw-r--r--arch/m68k/sun3/config.c60
-rw-r--r--arch/microblaze/include/asm/io.h8
-rw-r--r--arch/microblaze/include/asm/tlb.h3
-rw-r--r--arch/mips/include/asm/idle.h1
-rw-r--r--arch/mips/include/uapi/asm/siginfo.h4
-rw-r--r--arch/mips/pci/msi-octeon.c2
-rw-r--r--arch/mips/pci/msi-xlp.c12
-rw-r--r--arch/mips/pci/pci-xlr.c2
-rw-r--r--arch/mn10300/include/asm/io.h4
-rw-r--r--arch/nios2/Kconfig206
-rw-r--r--arch/nios2/Kconfig.debug17
-rw-r--r--arch/nios2/Makefile73
-rw-r--r--arch/nios2/boot/Makefile52
-rw-r--r--arch/nios2/boot/dts/3c120_devboard.dts164
-rw-r--r--arch/nios2/boot/install.sh52
-rw-r--r--arch/nios2/boot/linked_dtb.S19
-rw-r--r--arch/nios2/configs/3c120_defconfig77
-rw-r--r--arch/nios2/include/asm/Kbuild65
-rw-r--r--arch/nios2/include/asm/asm-macros.h309
-rw-r--r--arch/nios2/include/asm/asm-offsets.h20
-rw-r--r--arch/nios2/include/asm/cache.h36
-rw-r--r--arch/nios2/include/asm/cacheflush.h52
-rw-r--r--arch/nios2/include/asm/checksum.h78
-rw-r--r--arch/nios2/include/asm/cmpxchg.h61
-rw-r--r--arch/nios2/include/asm/cpuinfo.h57
-rw-r--r--arch/nios2/include/asm/delay.h21
-rw-r--r--arch/nios2/include/asm/dma-mapping.h140
-rw-r--r--arch/nios2/include/asm/elf.h101
-rw-r--r--arch/nios2/include/asm/entry.h120
-rw-r--r--arch/nios2/include/asm/io.h61
-rw-r--r--arch/nios2/include/asm/irq.h28
-rw-r--r--arch/nios2/include/asm/irqflags.h72
-rw-r--r--arch/nios2/include/asm/linkage.h25
-rw-r--r--arch/nios2/include/asm/mmu.h16
-rw-r--r--arch/nios2/include/asm/mmu_context.h66
-rw-r--r--arch/nios2/include/asm/mutex.h1
-rw-r--r--arch/nios2/include/asm/page.h109
-rw-r--r--arch/nios2/include/asm/pgalloc.h86
-rw-r--r--arch/nios2/include/asm/pgtable-bits.h35
-rw-r--r--arch/nios2/include/asm/pgtable.h310
-rw-r--r--arch/nios2/include/asm/processor.h103
-rw-r--r--arch/nios2/include/asm/ptrace.h33
-rw-r--r--arch/nios2/include/asm/registers.h71
-rw-r--r--arch/nios2/include/asm/setup.h38
-rw-r--r--arch/nios2/include/asm/signal.h22
-rw-r--r--arch/nios2/include/asm/string.h24
-rw-r--r--arch/nios2/include/asm/switch_to.h31
-rw-r--r--arch/nios2/include/asm/syscall.h138
-rw-r--r--arch/nios2/include/asm/syscalls.h25
-rw-r--r--arch/nios2/include/asm/thread_info.h120
-rw-r--r--arch/nios2/include/asm/timex.h24
-rw-r--r--arch/nios2/include/asm/tlb.h34
-rw-r--r--arch/nios2/include/asm/tlbflush.h46
-rw-r--r--arch/nios2/include/asm/traps.h19
-rw-r--r--arch/nios2/include/asm/uaccess.h231
-rw-r--r--arch/nios2/include/asm/ucontext.h32
-rw-r--r--arch/nios2/include/uapi/asm/Kbuild4
-rw-r--r--arch/nios2/include/uapi/asm/byteorder.h22
-rw-r--r--arch/nios2/include/uapi/asm/elf.h67
-rw-r--r--arch/nios2/include/uapi/asm/ptrace.h120
-rw-r--r--arch/nios2/include/uapi/asm/sigcontext.h28
-rw-r--r--arch/nios2/include/uapi/asm/signal.h23
-rw-r--r--arch/nios2/include/uapi/asm/swab.h37
-rw-r--r--arch/nios2/include/uapi/asm/unistd.h25
-rw-r--r--arch/nios2/kernel/Makefile24
-rw-r--r--arch/nios2/kernel/asm-offsets.c87
-rw-r--r--arch/nios2/kernel/cpuinfo.c197
-rw-r--r--arch/nios2/kernel/entry.S555
-rw-r--r--arch/nios2/kernel/head.S175
-rw-r--r--arch/nios2/kernel/insnemu.S592
-rw-r--r--arch/nios2/kernel/irq.c93
-rw-r--r--arch/nios2/kernel/misaligned.c256
-rw-r--r--arch/nios2/kernel/module.c138
-rw-r--r--arch/nios2/kernel/nios2_ksyms.c33
-rw-r--r--arch/nios2/kernel/process.c258
-rw-r--r--arch/nios2/kernel/prom.c65
-rw-r--r--arch/nios2/kernel/ptrace.c166
-rw-r--r--arch/nios2/kernel/setup.c218
-rw-r--r--arch/nios2/kernel/signal.c323
-rw-r--r--arch/nios2/kernel/sys_nios2.c53
-rw-r--r--arch/nios2/kernel/syscall_table.c29
-rw-r--r--arch/nios2/kernel/time.c308
-rw-r--r--arch/nios2/kernel/traps.c185
-rw-r--r--arch/nios2/kernel/vmlinux.lds.S75
-rw-r--r--arch/nios2/lib/Makefile8
-rw-r--r--arch/nios2/lib/delay.c52
-rw-r--r--arch/nios2/lib/memcpy.c202
-rw-r--r--arch/nios2/lib/memmove.c82
-rw-r--r--arch/nios2/lib/memset.c81
-rw-r--r--arch/nios2/mm/Makefile14
-rw-r--r--arch/nios2/mm/cacheflush.c271
-rw-r--r--arch/nios2/mm/dma-mapping.c186
-rw-r--r--arch/nios2/mm/extable.c25
-rw-r--r--arch/nios2/mm/fault.c251
-rw-r--r--arch/nios2/mm/init.c142
-rw-r--r--arch/nios2/mm/ioremap.c187
-rw-r--r--arch/nios2/mm/mmu_context.c116
-rw-r--r--arch/nios2/mm/pgtable.c74
-rw-r--r--arch/nios2/mm/tlb.c275
-rw-r--r--arch/nios2/mm/uaccess.c163
-rw-r--r--arch/nios2/platform/Kconfig.platform129
-rw-r--r--arch/nios2/platform/Makefile1
-rw-r--r--arch/nios2/platform/platform.c46
-rw-r--r--arch/parisc/hpux/fs.c7
-rw-r--r--arch/parisc/include/asm/io.h12
-rw-r--r--arch/powerpc/include/asm/io.h12
-rw-r--r--arch/powerpc/include/asm/iommu.h17
-rw-r--r--arch/powerpc/include/asm/pgalloc.h3
-rw-r--r--arch/powerpc/include/asm/pgtable-ppc64.h1
-rw-r--r--arch/powerpc/include/asm/tlb.h1
-rw-r--r--arch/powerpc/kernel/dma-iommu.c8
-rw-r--r--arch/powerpc/kernel/ftrace.c2
-rw-r--r--arch/powerpc/kernel/iommu.c16
-rw-r--r--arch/powerpc/mm/hugetlbpage.c2
-rw-r--r--arch/powerpc/mm/numa.c3
-rw-r--r--arch/powerpc/oprofile/cell/spu_task_sync.c10
-rw-r--r--arch/powerpc/platforms/cell/axon_msi.c8
-rw-r--r--arch/powerpc/platforms/cell/iommu.c9
-rw-r--r--arch/powerpc/platforms/cell/spufs/inode.c6
-rw-r--r--arch/powerpc/platforms/powernv/opal-sensor.c20
-rw-r--r--arch/powerpc/platforms/powernv/pci.c2
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-cpu.c7
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c15
-rw-r--r--arch/powerpc/platforms/pseries/iommu.c5
-rw-r--r--arch/powerpc/platforms/pseries/msi.c2
-rw-r--r--arch/powerpc/platforms/pseries/setup.c5
-rw-r--r--arch/powerpc/sysdev/fsl_msi.c6
-rw-r--r--arch/powerpc/sysdev/mpic_pasemi_msi.c6
-rw-r--r--arch/powerpc/sysdev/mpic_u3msi.c6
-rw-r--r--arch/powerpc/sysdev/ppc4xx_hsta_msi.c2
-rw-r--r--arch/powerpc/sysdev/ppc4xx_msi.c2
-rw-r--r--arch/powerpc/sysdev/xics/ics-opal.c2
-rw-r--r--arch/powerpc/sysdev/xics/ics-rtas.c2
-rw-r--r--arch/s390/hypfs/hypfs_dbfs.c3
-rw-r--r--arch/s390/include/asm/io.h10
-rw-r--r--arch/s390/include/asm/mmu_context.h11
-rw-r--r--arch/s390/mm/maccess.c4
-rw-r--r--arch/s390/pci/pci.c10
-rw-r--r--arch/sh/Kconfig1
-rw-r--r--arch/sh/boards/mach-ap325rxa/setup.c2
-rw-r--r--arch/sh/kernel/cpu/shmobile/cpuidle.c3
-rw-r--r--arch/sh/mm/numa.c2
-rw-r--r--arch/sparc/include/asm/io_32.h4
-rw-r--r--arch/sparc/include/asm/io_64.h14
-rw-r--r--arch/sparc/include/asm/pgtable_64.h7
-rw-r--r--arch/sparc/kernel/pci_msi.c10
-rw-r--r--arch/tile/include/asm/io.h4
-rw-r--r--arch/tile/kernel/early_printk.c19
-rw-r--r--arch/tile/kernel/pci_gx.c8
-rw-r--r--arch/tile/kernel/setup.c45
-rw-r--r--arch/um/include/asm/mmu_context.h24
-rw-r--r--arch/unicore32/include/asm/mmu_context.h11
-rw-r--r--arch/x86/Kconfig22
-rw-r--r--arch/x86/boot/compressed/Makefile17
-rw-r--r--arch/x86/boot/compressed/eboot.c8
-rw-r--r--arch/x86/boot/compressed/eboot.h16
-rw-r--r--arch/x86/boot/compressed/misc.c14
-rw-r--r--arch/x86/configs/i386_defconfig1
-rw-r--r--arch/x86/configs/x86_64_defconfig1
-rw-r--r--arch/x86/ia32/ia32_aout.c8
-rw-r--r--arch/x86/include/asm/cacheflush.h59
-rw-r--r--arch/x86/include/asm/cpufeature.h5
-rw-r--r--arch/x86/include/asm/disabled-features.h8
-rw-r--r--arch/x86/include/asm/efi.h24
-rw-r--r--arch/x86/include/asm/fb.h6
-rw-r--r--arch/x86/include/asm/fixmap.h4
-rw-r--r--arch/x86/include/asm/ftrace.h33
-rw-r--r--arch/x86/include/asm/highmem.h25
-rw-r--r--arch/x86/include/asm/insn.h10
-rw-r--r--arch/x86/include/asm/io.h10
-rw-r--r--arch/x86/include/asm/mce.h5
-rw-r--r--arch/x86/include/asm/microcode.h2
-rw-r--r--arch/x86/include/asm/microcode_amd.h4
-rw-r--r--arch/x86/include/asm/microcode_intel.h2
-rw-r--r--arch/x86/include/asm/mmu_context.h37
-rw-r--r--arch/x86/include/asm/mpx.h103
-rw-r--r--arch/x86/include/asm/page_64.h4
-rw-r--r--arch/x86/include/asm/paravirt.h16
-rw-r--r--arch/x86/include/asm/pat.h7
-rw-r--r--arch/x86/include/asm/percpu.h61
-rw-r--r--arch/x86/include/asm/perf_event.h3
-rw-r--r--arch/x86/include/asm/pgtable.h24
-rw-r--r--arch/x86/include/asm/pgtable_32_types.h2
-rw-r--r--arch/x86/include/asm/pgtable_64_types.h2
-rw-r--r--arch/x86/include/asm/pgtable_types.h96
-rw-r--r--arch/x86/include/asm/platform_sst_audio.h62
-rw-r--r--arch/x86/include/asm/preempt.h3
-rw-r--r--arch/x86/include/asm/processor.h45
-rw-r--r--arch/x86/include/asm/spinlock.h14
-rw-r--r--arch/x86/include/asm/switch_to.h12
-rw-r--r--arch/x86/include/asm/uv/uv_bau.h4
-rw-r--r--arch/x86/include/asm/vgtod.h19
-rw-r--r--arch/x86/include/asm/vsyscall.h33
-rw-r--r--arch/x86/include/asm/vvar.h2
-rw-r--r--arch/x86/include/asm/x86_init.h3
-rw-r--r--arch/x86/include/uapi/asm/msr-index.h42
-rw-r--r--arch/x86/kernel/Makefile3
-rw-r--r--arch/x86/kernel/amd_nb.c2
-rw-r--r--arch/x86/kernel/apic/apic_numachip.c26
-rw-r--r--arch/x86/kernel/apic/hw_nmi.c91
-rw-r--r--arch/x86/kernel/apic/io_apic.c8
-rw-r--r--arch/x86/kernel/apm_32.c1
-rw-r--r--arch/x86/kernel/asm-offsets_64.c1
-rw-r--r--arch/x86/kernel/cpu/amd.c23
-rw-r--r--arch/x86/kernel/cpu/common.c10
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce-internal.h4
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce-severity.c23
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c72
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce_amd.c54
-rw-r--r--arch/x86/kernel/cpu/microcode/amd.c8
-rw-r--r--arch/x86/kernel/cpu/microcode/amd_early.c20
-rw-r--r--arch/x86/kernel/cpu/microcode/core.c10
-rw-r--r--arch/x86/kernel/cpu/microcode/core_early.c21
-rw-r--r--arch/x86/kernel/cpu/microcode/intel_early.c42
-rw-r--r--arch/x86/kernel/cpu/perf_event.h4
-rw-r--r--arch/x86/kernel/cpu/perf_event_amd_ibs.c15
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_ds.c98
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_lbr.c25
-rw-r--r--arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c8
-rw-r--r--arch/x86/kernel/cpu/proc.c10
-rw-r--r--arch/x86/kernel/cpu/scattered.c5
-rw-r--r--arch/x86/kernel/cpuid.c2
-rw-r--r--arch/x86/kernel/espfix_64.c3
-rw-r--r--arch/x86/kernel/ftrace.c288
-rw-r--r--arch/x86/kernel/irq.c30
-rw-r--r--arch/x86/kernel/kprobes/core.c8
-rw-r--r--arch/x86/kernel/kprobes/ftrace.c9
-rw-r--r--arch/x86/kernel/kprobes/opt.c4
-rw-r--r--arch/x86/kernel/mcount_64.S224
-rw-r--r--arch/x86/kernel/msr.c11
-rw-r--r--arch/x86/kernel/setup.c4
-rw-r--r--arch/x86/kernel/setup_percpu.c2
-rw-r--r--arch/x86/kernel/smpboot.c2
-rw-r--r--arch/x86/kernel/sysfb.c2
-rw-r--r--arch/x86/kernel/sysfb_simplefb.c5
-rw-r--r--arch/x86/kernel/time.c2
-rw-r--r--arch/x86/kernel/traps.c90
-rw-r--r--arch/x86/kernel/uprobes.c2
-rw-r--r--arch/x86/kernel/vmlinux.lds.S2
-rw-r--r--arch/x86/kernel/vsyscall_64.c147
-rw-r--r--arch/x86/kernel/x86_init.c10
-rw-r--r--arch/x86/kvm/mmutrace.h4
-rw-r--r--arch/x86/lib/insn.c5
-rw-r--r--arch/x86/mm/Makefile2
-rw-r--r--arch/x86/mm/dump_pagetables.c27
-rw-r--r--arch/x86/mm/init.c37
-rw-r--r--arch/x86/mm/init_64.c65
-rw-r--r--arch/x86/mm/iomap_32.c12
-rw-r--r--arch/x86/mm/ioremap.c67
-rw-r--r--arch/x86/mm/mm_internal.h2
-rw-r--r--arch/x86/mm/mpx.c928
-rw-r--r--arch/x86/mm/pageattr.c84
-rw-r--r--arch/x86/mm/pat.c247
-rw-r--r--arch/x86/mm/pat_internal.h22
-rw-r--r--arch/x86/mm/pat_rbtree.c8
-rw-r--r--arch/x86/pci/i386.c4
-rw-r--r--arch/x86/pci/numachip.c2
-rw-r--r--arch/x86/pci/xen.c19
-rw-r--r--arch/x86/platform/efi/efi_64.c3
-rw-r--r--arch/x86/platform/uv/tlb_uv.c30
-rw-r--r--arch/x86/purgatory/Makefile1
-rw-r--r--arch/x86/tools/insn_sanity.c2
-rw-r--r--arch/x86/tools/relocs.c36
-rw-r--r--arch/x86/tools/test_get_len.c2
-rw-r--r--arch/x86/vdso/vgetcpu.c2
-rw-r--r--arch/x86/vdso/vma.c83
-rw-r--r--arch/x86/xen/enlighten.c25
-rw-r--r--arch/x86/xen/mmu.c53
-rw-r--r--arch/x86/xen/xen-ops.h1
-rw-r--r--arch/xtensa/include/asm/io.h7
-rw-r--r--block/blk-core.c10
-rw-r--r--block/blk-mq-tag.c28
-rw-r--r--block/blk-mq.c2
-rw-r--r--block/elevator.c2
-rw-r--r--block/scsi_ioctl.c2
-rw-r--r--drivers/Kconfig2
-rw-r--r--drivers/acpi/Kconfig36
-rw-r--r--drivers/acpi/Makefile5
-rw-r--r--drivers/acpi/acpi_lpss.c98
-rw-r--r--drivers/acpi/acpica/acglobal.h1
-rw-r--r--drivers/acpi/acpica/aclocal.h4
-rw-r--r--drivers/acpi/acpica/evgpe.c9
-rw-r--r--drivers/acpi/acpica/hwgpe.c53
-rw-r--r--drivers/acpi/acpica/utresrc.c2
-rw-r--r--drivers/acpi/acpica/utxface.c4
-rw-r--r--drivers/acpi/acpica/utxfinit.c11
-rw-r--r--drivers/acpi/apei/ghes.c20
-rw-r--r--drivers/acpi/battery.c4
-rw-r--r--drivers/acpi/device_pm.c10
-rw-r--r--drivers/acpi/internal.h6
-rw-r--r--drivers/acpi/osl.c8
-rw-r--r--drivers/acpi/pci_irq.c2
-rw-r--r--drivers/acpi/pmic/intel_pmic.c354
-rw-r--r--drivers/acpi/pmic/intel_pmic.h25
-rw-r--r--drivers/acpi/pmic/intel_pmic_crc.c211
-rw-r--r--drivers/acpi/pmic/intel_pmic_xpower.c268
-rw-r--r--drivers/acpi/processor_idle.c20
-rw-r--r--drivers/acpi/property.c551
-rw-r--r--drivers/acpi/scan.c214
-rw-r--r--drivers/acpi/sleep.c2
-rw-r--r--drivers/acpi/tables.c68
-rw-r--r--drivers/acpi/utils.c5
-rw-r--r--drivers/acpi/video.c18
-rw-r--r--drivers/amba/Kconfig14
-rw-r--r--drivers/amba/bus.c2
-rw-r--r--drivers/ata/ahci.c4
-rw-r--r--drivers/ata/libata-scsi.c19
-rw-r--r--drivers/ata/sata_fsl.c2
-rw-r--r--drivers/ata/sata_nv.c2
-rw-r--r--drivers/base/Kconfig8
-rw-r--r--drivers/base/Makefile2
-rw-r--r--drivers/base/platform.c1
-rw-r--r--drivers/base/power/clock_ops.c150
-rw-r--r--drivers/base/power/domain.c147
-rw-r--r--drivers/base/power/domain_governor.c11
-rw-r--r--drivers/base/power/opp.c196
-rw-r--r--drivers/base/power/power.h56
-rw-r--r--drivers/base/power/qos.c5
-rw-r--r--drivers/base/power/runtime.c76
-rw-r--r--drivers/base/power/sysfs.c19
-rw-r--r--drivers/base/property.c431
-rw-r--r--drivers/base/regmap/Kconfig5
-rw-r--r--drivers/base/regmap/Makefile1
-rw-r--r--drivers/base/regmap/regcache-flat.c2
-rw-r--r--drivers/base/regmap/regcache-lzo.c2
-rw-r--r--drivers/base/regmap/regcache-rbtree.c4
-rw-r--r--drivers/base/regmap/regcache.c63
-rw-r--r--drivers/base/regmap/regmap-ac97.c114
-rw-r--r--drivers/block/drbd/drbd_debugfs.c6
-rw-r--r--drivers/block/nvme-scsi.c4
-rw-r--r--drivers/block/virtio_blk.c74
-rw-r--r--drivers/bus/Kconfig2
-rw-r--r--drivers/bus/arm-cci.c552
-rw-r--r--drivers/bus/brcmstb_gisb.c167
-rw-r--r--drivers/bus/mvebu-mbus.c180
-rw-r--r--drivers/bus/omap_l3_noc.c63
-rw-r--r--drivers/bus/omap_l3_smx.c26
-rw-r--r--drivers/char/hw_random/exynos-rng.c2
-rw-r--r--drivers/char/mem.c13
-rw-r--r--drivers/char/virtio_console.c39
-rw-r--r--drivers/clk/clk-s2mps11.c24
-rw-r--r--drivers/clk/mvebu/common.c32
-rw-r--r--drivers/clk/samsung/clk-exynos5440.c29
-rw-r--r--drivers/clk/tegra/clk-divider.c13
-rw-r--r--drivers/clk/tegra/clk-tegra114.c7
-rw-r--r--drivers/clk/tegra/clk-tegra124.c7
-rw-r--r--drivers/clk/tegra/clk-tegra20.c8
-rw-r--r--drivers/clk/tegra/clk-tegra30.c7
-rw-r--r--drivers/clk/tegra/clk.h2
-rw-r--r--drivers/clk/ti/dpll.c15
-rw-r--r--drivers/clk/versatile/Makefile1
-rw-r--r--drivers/clk/versatile/clk-vexpress-osc.c7
-rw-r--r--drivers/clk/versatile/clk-vexpress.c86
-rw-r--r--drivers/clocksource/Kconfig1
-rw-r--r--drivers/clocksource/Makefile1
-rw-r--r--drivers/clocksource/arm_arch_timer.c13
-rw-r--r--drivers/clocksource/time-armada-370-xp.c55
-rw-r--r--drivers/clocksource/timer-atmel-pit.c32
-rw-r--r--drivers/clocksource/timer-integrator-ap.c210
-rw-r--r--drivers/clocksource/timer-marco.c23
-rw-r--r--drivers/cpufreq/Kconfig57
-rw-r--r--drivers/cpufreq/Kconfig.arm8
-rw-r--r--drivers/cpufreq/Makefile4
-rw-r--r--drivers/cpufreq/arm_big_little.c7
-rw-r--r--drivers/cpufreq/arm_big_little.h5
-rw-r--r--drivers/cpufreq/arm_big_little_dt.c1
-rw-r--r--drivers/cpufreq/cpufreq-dt.c66
-rw-r--r--drivers/cpufreq/cpufreq.c53
-rw-r--r--drivers/cpufreq/exynos5440-cpufreq.c5
-rw-r--r--drivers/cpufreq/imx6q-cpufreq.c11
-rw-r--r--drivers/cpufreq/intel_pstate.c146
-rw-r--r--drivers/cpufreq/ls1x-cpufreq.c223
-rw-r--r--drivers/cpufreq/pcc-cpufreq.c7
-rw-r--r--drivers/cpuidle/cpuidle-arm64.c14
-rw-r--r--drivers/cpuidle/cpuidle-at91.c1
-rw-r--r--drivers/cpuidle/cpuidle-big_little.c6
-rw-r--r--drivers/cpuidle/cpuidle-calxeda.c1
-rw-r--r--drivers/cpuidle/cpuidle-cps.c7
-rw-r--r--drivers/cpuidle/cpuidle-exynos.c1
-rw-r--r--drivers/cpuidle/cpuidle-kirkwood.c1
-rw-r--r--drivers/cpuidle/cpuidle-mvebu-v7.c8
-rw-r--r--drivers/cpuidle/cpuidle-powernv.c6
-rw-r--r--drivers/cpuidle/cpuidle-pseries.c3
-rw-r--r--drivers/cpuidle/cpuidle-ux500.c3
-rw-r--r--drivers/cpuidle/cpuidle-zynq.c1
-rw-r--r--drivers/cpuidle/driver.c1
-rw-r--r--drivers/cpuidle/dt_idle_states.c12
-rw-r--r--drivers/cpuidle/governors/ladder.c2
-rw-r--r--drivers/cpuidle/governors/menu.c2
-rw-r--r--drivers/crypto/nx/nx-842.c4
-rw-r--r--drivers/dma/dw/core.c11
-rw-r--r--drivers/dma/nbpfaxi.c2
-rw-r--r--drivers/dma/ste_dma40.c2
-rw-r--r--drivers/dma/tegra20-apb-dma.c2
-rw-r--r--drivers/edac/Kconfig16
-rw-r--r--drivers/edac/Makefile2
-rw-r--r--drivers/edac/amd64_edac.c260
-rw-r--r--drivers/edac/amd64_edac.h15
-rw-r--r--drivers/edac/edac_mc.c40
-rw-r--r--drivers/edac/edac_mc_sysfs.c2
-rw-r--r--drivers/edac/edac_pci_sysfs.c5
-rw-r--r--drivers/edac/ghes_edac.c4
-rw-r--r--drivers/edac/i3000_edac.c3
-rw-r--r--drivers/edac/i3200_edac.c3
-rw-r--r--drivers/edac/i82443bxgx_edac.c3
-rw-r--r--drivers/edac/mce_amd.c47
-rw-r--r--drivers/edac/mce_amd.h3
-rw-r--r--drivers/edac/mce_amd_inj.c293
-rw-r--r--drivers/edac/mv64x60_edac.c8
-rw-r--r--drivers/edac/ppc4xx_edac.c4
-rw-r--r--drivers/edac/sb_edac.c208
-rw-r--r--drivers/edac/x38_edac.c3
-rw-r--r--drivers/firmware/dmi_scan.c79
-rw-r--r--drivers/firmware/efi/Makefile2
-rw-r--r--drivers/firmware/efi/cper.c2
-rw-r--r--drivers/firmware/efi/efi.c4
-rw-r--r--drivers/firmware/efi/libstub/arm-stub.c11
-rw-r--r--drivers/gpio/Kconfig12
-rw-r--r--drivers/gpio/Makefile1
-rw-r--r--drivers/gpio/devres.c32
-rw-r--r--drivers/gpio/gpio-dln2.c553
-rw-r--r--drivers/gpio/gpio-omap.c8
-rw-r--r--drivers/gpio/gpio-sch.c293
-rw-r--r--drivers/gpio/gpio-tc3589x.c2
-rw-r--r--drivers/gpio/gpio-tz1090.c2
-rw-r--r--drivers/gpio/gpio-zynq.c2
-rw-r--r--drivers/gpio/gpiolib-acpi.c179
-rw-r--r--drivers/gpio/gpiolib.c85
-rw-r--r--drivers/gpio/gpiolib.h7
-rw-r--r--drivers/gpu/drm/armada/armada_gem.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_fimc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_g2d.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_gsc.c2
-rw-r--r--drivers/gpu/drm/exynos/exynos_drm_rotator.c2
-rw-r--r--drivers/gpu/drm/i915/intel_display.c2
-rw-r--r--drivers/gpu/drm/i915/intel_lvds.c22
-rw-r--r--drivers/gpu/ipu-v3/ipu-csi.c66
-rw-r--r--drivers/hid/hid-sensor-hub.c8
-rw-r--r--drivers/hid/i2c-hid/i2c-hid.c2
-rw-r--r--drivers/hsi/controllers/omap_ssi.c2
-rw-r--r--drivers/hsi/controllers/omap_ssi_port.c2
-rw-r--r--drivers/hwmon/Kconfig28
-rw-r--r--drivers/hwmon/Makefile1
-rw-r--r--drivers/hwmon/gpio-fan.c18
-rw-r--r--drivers/hwmon/ibmpowernv.c78
-rw-r--r--drivers/hwmon/iio_hwmon.c7
-rw-r--r--drivers/hwmon/ina2xx.c26
-rw-r--r--drivers/hwmon/lm75.c12
-rw-r--r--drivers/hwmon/lm95234.c91
-rw-r--r--drivers/hwmon/lm95245.c41
-rw-r--r--drivers/hwmon/nct6775.c77
-rw-r--r--drivers/hwmon/nct7802.c860
-rw-r--r--drivers/hwmon/pmbus/Kconfig11
-rw-r--r--drivers/hwmon/pmbus/ltc2978.c39
-rw-r--r--drivers/hwmon/pmbus/pmbus.h30
-rw-r--r--drivers/hwmon/pmbus/pmbus_core.c118
-rw-r--r--drivers/hwmon/tmp401.c42
-rw-r--r--drivers/i2c/busses/Kconfig10
-rw-r--r--drivers/i2c/busses/Makefile1
-rw-r--r--drivers/i2c/busses/i2c-cadence.c11
-rw-r--r--drivers/i2c/busses/i2c-davinci.c8
-rw-r--r--drivers/i2c/busses/i2c-dln2.c262
-rw-r--r--drivers/i2c/busses/i2c-hix5hd2.c2
-rw-r--r--drivers/i2c/busses/i2c-nomadik.c2
-rw-r--r--drivers/i2c/busses/i2c-omap.c2
-rw-r--r--drivers/i2c/i2c-core.c150
-rw-r--r--drivers/idle/intel_idle.c108
-rw-r--r--drivers/iio/accel/bmc150-accel.c4
-rw-r--r--drivers/iio/accel/kxcjk-1013.c4
-rw-r--r--drivers/iio/adc/Kconfig8
-rw-r--r--drivers/iio/adc/Makefile1
-rw-r--r--drivers/iio/adc/axp288_adc.c261
-rw-r--r--drivers/iio/gyro/bmg160.c4
-rw-r--r--drivers/infiniband/ulp/iser/iscsi_iser.c3
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.c1100
-rw-r--r--drivers/infiniband/ulp/srp/ib_srp.h75
-rw-r--r--drivers/input/keyboard/gpio_keys_polled.c112
-rw-r--r--drivers/input/keyboard/samsung-keypad.c2
-rw-r--r--drivers/input/touchscreen/cyttsp4_core.c2
-rw-r--r--drivers/iommu/Kconfig12
-rw-r--r--drivers/iommu/amd_iommu.c1
-rw-r--r--drivers/iommu/arm-smmu.c1
-rw-r--r--drivers/iommu/exynos-iommu.c1
-rw-r--r--drivers/iommu/intel-iommu.c1
-rw-r--r--drivers/iommu/iommu.c50
-rw-r--r--drivers/iommu/ipmmu-vmsa.c1
-rw-r--r--drivers/iommu/irq_remapping.c8
-rw-r--r--drivers/iommu/msm_iommu.c1
-rw-r--r--drivers/iommu/omap-iommu.c1
-rw-r--r--drivers/iommu/shmobile-iommu.c1
-rw-r--r--drivers/iommu/tegra-smmu.c1609
-rw-r--r--drivers/irqchip/Kconfig7
-rw-r--r--drivers/irqchip/Makefile4
-rw-r--r--drivers/irqchip/irq-armada-370-xp.c70
-rw-r--r--drivers/irqchip/irq-atmel-aic-common.c26
-rw-r--r--drivers/irqchip/irq-atmel-aic-common.h2
-rw-r--r--drivers/irqchip/irq-atmel-aic.c66
-rw-r--r--drivers/irqchip/irq-atmel-aic5.c65
-rw-r--r--drivers/irqchip/irq-bcm7120-l2.c174
-rw-r--r--drivers/irqchip/irq-brcmstb-l2.c41
-rw-r--r--drivers/irqchip/irq-dw-apb-ictl.c32
-rw-r--r--drivers/irqchip/irq-gic.c2
-rw-r--r--drivers/irqchip/irq-hip04.c3
-rw-r--r--drivers/irqchip/irq-sunxi-nmi.c4
-rw-r--r--drivers/irqchip/irq-tb10x.c4
-rw-r--r--drivers/leds/leds-gpio.c150
-rw-r--r--drivers/lguest/lguest_device.c17
-rw-r--r--drivers/mailbox/Kconfig12
-rw-r--r--drivers/mailbox/Makefile2
-rw-r--r--drivers/mailbox/mailbox.c19
-rw-r--r--drivers/mailbox/mailbox.h14
-rw-r--r--drivers/mailbox/omap-mailbox.c346
-rw-r--r--drivers/mailbox/pcc.c403
-rw-r--r--drivers/md/dm-bio-prison.c186
-rw-r--r--drivers/md/dm-bio-prison.h28
-rw-r--r--drivers/md/dm-bufio.c226
-rw-r--r--drivers/md/dm-cache-block-types.h11
-rw-r--r--drivers/md/dm-cache-metadata.c34
-rw-r--r--drivers/md/dm-cache-metadata.h6
-rw-r--r--drivers/md/dm-cache-policy-mq.c82
-rw-r--r--drivers/md/dm-cache-target.c378
-rw-r--r--drivers/md/dm-crypt.c2
-rw-r--r--drivers/md/dm-ioctl.c5
-rw-r--r--drivers/md/dm-stats.c2
-rw-r--r--drivers/md/dm-table.c36
-rw-r--r--drivers/md/dm-thin-metadata.c35
-rw-r--r--drivers/md/dm-thin-metadata.h9
-rw-r--r--drivers/md/dm-thin.c760
-rw-r--r--drivers/md/dm.c273
-rw-r--r--drivers/md/dm.h10
-rw-r--r--drivers/md/persistent-data/dm-array.c4
-rw-r--r--drivers/md/persistent-data/dm-space-map-metadata.c8
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.c77
-rw-r--r--drivers/md/persistent-data/dm-transaction-manager.h7
-rw-r--r--drivers/media/common/cx2341x.c29
-rw-r--r--drivers/media/common/saa7146/saa7146_core.c2
-rw-r--r--drivers/media/common/siano/smsir.c3
-rw-r--r--drivers/media/common/tveeprom.c36
-rw-r--r--drivers/media/dvb-core/dvb-usb-ids.h1
-rw-r--r--drivers/media/dvb-core/dvb_net.c4
-rw-r--r--drivers/media/dvb-frontends/Kconfig5
-rw-r--r--drivers/media/dvb-frontends/af9033.c140
-rw-r--r--drivers/media/dvb-frontends/af9033_priv.h11
-rw-r--r--drivers/media/dvb-frontends/au8522_dig.c117
-rw-r--r--drivers/media/dvb-frontends/cx22700.c3
-rw-r--r--drivers/media/dvb-frontends/cx24110.c50
-rw-r--r--drivers/media/dvb-frontends/cx24117.c2
-rw-r--r--drivers/media/dvb-frontends/dib7000p.c9
-rw-r--r--drivers/media/dvb-frontends/drx39xyj/drxj.c3
-rw-r--r--drivers/media/dvb-frontends/drxk_hard.c9
-rw-r--r--drivers/media/dvb-frontends/m88ds3103.c267
-rw-r--r--drivers/media/dvb-frontends/m88ds3103_priv.h181
-rw-r--r--drivers/media/dvb-frontends/mn88472.h38
-rw-r--r--drivers/media/dvb-frontends/mn88473.h38
-rw-r--r--drivers/media/dvb-frontends/rtl2832.c60
-rw-r--r--drivers/media/dvb-frontends/rtl2832.h11
-rw-r--r--drivers/media/dvb-frontends/rtl2832_sdr.c8
-rw-r--r--drivers/media/dvb-frontends/si2168.c75
-rw-r--r--drivers/media/dvb-frontends/si2168.h4
-rw-r--r--drivers/media/dvb-frontends/si2168_priv.h1
-rw-r--r--drivers/media/dvb-frontends/sp2.c21
-rw-r--r--drivers/media/dvb-frontends/stb0899_drv.c2
-rw-r--r--drivers/media/dvb-frontends/stv090x.c196
-rw-r--r--drivers/media/dvb-frontends/stv090x.h44
-rw-r--r--drivers/media/firewire/firedtv-ci.c3
-rw-r--r--drivers/media/firewire/firedtv.h2
-rw-r--r--drivers/media/i2c/adv7170.c16
-rw-r--r--drivers/media/i2c/adv7175.c16
-rw-r--r--drivers/media/i2c/adv7180.c6
-rw-r--r--drivers/media/i2c/adv7183.c6
-rw-r--r--drivers/media/i2c/adv7511.c229
-rw-r--r--drivers/media/i2c/adv7604.c109
-rw-r--r--drivers/media/i2c/adv7842.c40
-rw-r--r--drivers/media/i2c/ak881x.c8
-rw-r--r--drivers/media/i2c/cx25840/cx25840-core.c14
-rw-r--r--drivers/media/i2c/cx25840/cx25840-firmware.c11
-rw-r--r--drivers/media/i2c/ir-kbd-i2c.c3
-rw-r--r--drivers/media/i2c/m5mols/m5mols_core.c6
-rw-r--r--drivers/media/i2c/ml86v7667.c6
-rw-r--r--drivers/media/i2c/mt9m032.c6
-rw-r--r--drivers/media/i2c/mt9p031.c8
-rw-r--r--drivers/media/i2c/mt9t001.c8
-rw-r--r--drivers/media/i2c/mt9v011.c6
-rw-r--r--drivers/media/i2c/mt9v032.c12
-rw-r--r--drivers/media/i2c/noon010pc30.c12
-rw-r--r--drivers/media/i2c/ov7670.c16
-rw-r--r--drivers/media/i2c/ov9650.c10
-rw-r--r--drivers/media/i2c/s5c73m3/s5c73m3.h6
-rw-r--r--drivers/media/i2c/s5k4ecgx.c4
-rw-r--r--drivers/media/i2c/s5k5baf.c14
-rw-r--r--drivers/media/i2c/s5k6a3.c2
-rw-r--r--drivers/media/i2c/s5k6aa.c8
-rw-r--r--drivers/media/i2c/saa6752hs.c6
-rw-r--r--drivers/media/i2c/saa7115.c2
-rw-r--r--drivers/media/i2c/saa717x.c2
-rw-r--r--drivers/media/i2c/smiapp-pll.c280
-rw-r--r--drivers/media/i2c/smiapp-pll.h21
-rw-r--r--drivers/media/i2c/smiapp/smiapp-core.c261
-rw-r--r--drivers/media/i2c/smiapp/smiapp.h8
-rw-r--r--drivers/media/i2c/soc_camera/imx074.c8
-rw-r--r--drivers/media/i2c/soc_camera/mt9m001.c14
-rw-r--r--drivers/media/i2c/soc_camera/mt9m111.c70
-rw-r--r--drivers/media/i2c/soc_camera/mt9t031.c10
-rw-r--r--drivers/media/i2c/soc_camera/mt9t112.c22
-rw-r--r--drivers/media/i2c/soc_camera/mt9v022.c26
-rw-r--r--drivers/media/i2c/soc_camera/ov2640.c54
-rw-r--r--drivers/media/i2c/soc_camera/ov5642.c8
-rw-r--r--drivers/media/i2c/soc_camera/ov6650.c58
-rw-r--r--drivers/media/i2c/soc_camera/ov772x.c20
-rw-r--r--drivers/media/i2c/soc_camera/ov9640.c40
-rw-r--r--drivers/media/i2c/soc_camera/ov9740.c12
-rw-r--r--drivers/media/i2c/soc_camera/rj54n1cb0c.c54
-rw-r--r--drivers/media/i2c/soc_camera/tw9910.c10
-rw-r--r--drivers/media/i2c/sr030pc30.c14
-rw-r--r--drivers/media/i2c/tvp514x.c12
-rw-r--r--drivers/media/i2c/tvp5150.c6
-rw-r--r--drivers/media/i2c/tvp7002.c10
-rw-r--r--drivers/media/i2c/vs6624.c18
-rw-r--r--drivers/media/media-entity.c13
-rw-r--r--drivers/media/pci/Kconfig1
-rw-r--r--drivers/media/pci/Makefile3
-rw-r--r--drivers/media/pci/bt8xx/bttv-cards.c6
-rw-r--r--drivers/media/pci/bt8xx/bttv-risc.c12
-rw-r--r--drivers/media/pci/cx18/cx18-av-core.c18
-rw-r--r--drivers/media/pci/cx18/cx18-cards.h3
-rw-r--r--drivers/media/pci/cx18/cx18-controls.c2
-rw-r--r--drivers/media/pci/cx18/cx18-driver.h1
-rw-r--r--drivers/media/pci/cx18/cx18-ioctl.c9
-rw-r--r--drivers/media/pci/cx18/cx18-streams.c9
-rw-r--r--drivers/media/pci/cx23885/cx23885-417.c4
-rw-r--r--drivers/media/pci/cx23885/cx23885-cards.c131
-rw-r--r--drivers/media/pci/cx23885/cx23885-core.c21
-rw-r--r--drivers/media/pci/cx23885/cx23885-dvb.c691
-rw-r--r--drivers/media/pci/cx23885/cx23885-input.c31
-rw-r--r--drivers/media/pci/cx23885/cx23885-vbi.c10
-rw-r--r--drivers/media/pci/cx23885/cx23885-video.c12
-rw-r--r--drivers/media/pci/cx23885/cx23885.h8
-rw-r--r--drivers/media/pci/cx25821/cx25821-core.c12
-rw-r--r--drivers/media/pci/cx88/Kconfig5
-rw-r--r--drivers/media/pci/cx88/Makefile1
-rw-r--r--drivers/media/pci/cx88/cx88-alsa.c112
-rw-r--r--drivers/media/pci/cx88/cx88-blackbird.c565
-rw-r--r--drivers/media/pci/cx88/cx88-cards.c71
-rw-r--r--drivers/media/pci/cx88/cx88-core.c119
-rw-r--r--drivers/media/pci/cx88/cx88-dvb.c158
-rw-r--r--drivers/media/pci/cx88/cx88-mpeg.c159
-rw-r--r--drivers/media/pci/cx88/cx88-vbi.c216
-rw-r--r--drivers/media/pci/cx88/cx88-video.c871
-rw-r--r--drivers/media/pci/cx88/cx88.h104
-rw-r--r--drivers/media/pci/ddbridge/ddbridge-core.c3
-rw-r--r--drivers/media/pci/ivtv/ivtv-controls.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-ioctl.c2
-rw-r--r--drivers/media/pci/ivtv/ivtv-udma.c2
-rw-r--r--drivers/media/pci/meye/meye.c3
-rw-r--r--drivers/media/pci/pt1/pt1.c13
-rw-r--r--drivers/media/pci/pt3/pt3.c75
-rw-r--r--drivers/media/pci/saa7134/saa7134-alsa.c4
-rw-r--r--drivers/media/pci/saa7134/saa7134-core.c18
-rw-r--r--drivers/media/pci/saa7134/saa7134-empress.c5
-rw-r--r--drivers/media/pci/saa7134/saa7134-ts.c17
-rw-r--r--drivers/media/pci/saa7134/saa7134-vbi.c16
-rw-r--r--drivers/media/pci/saa7134/saa7134-video.c16
-rw-r--r--drivers/media/pci/saa7134/saa7134.h2
-rw-r--r--drivers/media/pci/saa7164/saa7164-buffer.c4
-rw-r--r--drivers/media/pci/saa7164/saa7164-bus.c101
-rw-r--r--drivers/media/pci/saa7164/saa7164-core.c13
-rw-r--r--drivers/media/pci/saa7164/saa7164-fw.c6
-rw-r--r--drivers/media/pci/saa7164/saa7164-types.h4
-rw-r--r--drivers/media/pci/saa7164/saa7164.h4
-rw-r--r--drivers/media/pci/smipcie/Kconfig17
-rw-r--r--drivers/media/pci/smipcie/Makefile6
-rw-r--r--drivers/media/pci/smipcie/smipcie.c1099
-rw-r--r--drivers/media/pci/smipcie/smipcie.h299
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-core.c10
-rw-r--r--drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c88
-rw-r--r--drivers/media/pci/solo6x10/solo6x10.h1
-rw-r--r--drivers/media/pci/tw68/tw68-core.c15
-rw-r--r--drivers/media/pci/tw68/tw68-video.c9
-rw-r--r--drivers/media/pci/tw68/tw68.h1
-rw-r--r--drivers/media/pci/zoran/zoran_driver.c5
-rw-r--r--drivers/media/pci/zoran/zoran_procfs.c4
-rw-r--r--drivers/media/platform/Kconfig4
-rw-r--r--drivers/media/platform/Makefile2
-rw-r--r--drivers/media/platform/blackfin/bfin_capture.c34
-rw-r--r--drivers/media/platform/coda/Makefile2
-rw-r--r--drivers/media/platform/coda/coda-bit.c322
-rw-r--r--drivers/media/platform/coda/coda-common.c611
-rw-r--r--drivers/media/platform/coda/coda-jpeg.c238
-rw-r--r--drivers/media/platform/coda/coda.h24
-rw-r--r--drivers/media/platform/coda/coda_regs.h7
-rw-r--r--drivers/media/platform/davinci/vpbe.c21
-rw-r--r--drivers/media/platform/davinci/vpbe_display.c617
-rw-r--r--drivers/media/platform/davinci/vpfe_capture.c8
-rw-r--r--drivers/media/platform/davinci/vpif_capture.c2
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.c23
-rw-r--r--drivers/media/platform/exynos-gsc/gsc-core.h2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-capture.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.c20
-rw-r--r--drivers/media/platform/exynos4-is/fimc-core.h4
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is-i2c.c2
-rw-r--r--drivers/media/platform/exynos4-is/fimc-is.c10
-rw-r--r--drivers/media/platform/exynos4-is/fimc-isp.c16
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite-reg.c26
-rw-r--r--drivers/media/platform/exynos4-is/fimc-lite.c16
-rw-r--r--drivers/media/platform/exynos4-is/fimc-reg.c14
-rw-r--r--drivers/media/platform/exynos4-is/mipi-csis.c16
-rw-r--r--drivers/media/platform/fsl-viu.c3
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.c85
-rw-r--r--drivers/media/platform/marvell-ccic/mcam-core.h3
-rw-r--r--drivers/media/platform/mx2_emmaprp.c9
-rw-r--r--drivers/media/platform/omap/Kconfig3
-rw-r--r--drivers/media/platform/omap/omap_vout.c11
-rw-r--r--drivers/media/platform/omap3isp/ispccdc.c112
-rw-r--r--drivers/media/platform/omap3isp/ispccp2.c18
-rw-r--r--drivers/media/platform/omap3isp/ispcsi2.c42
-rw-r--r--drivers/media/platform/omap3isp/isppreview.c60
-rw-r--r--drivers/media/platform/omap3isp/ispresizer.c19
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.c95
-rw-r--r--drivers/media/platform/omap3isp/ispvideo.h10
-rw-r--r--drivers/media/platform/s3c-camif/camif-capture.c10
-rw-r--r--drivers/media/platform/s3c-camif/camif-core.c3
-rw-r--r--drivers/media/platform/s3c-camif/camif-regs.c8
-rw-r--r--drivers/media/platform/s5p-g2d/g2d.c10
-rw-r--r--drivers/media/platform/s5p-jpeg/jpeg-core.c13
-rw-r--r--drivers/media/platform/s5p-mfc/regs-mfc-v6.h1
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc.c51
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_common.h4
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c122
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_dec.c12
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_enc.c65
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c13
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c32
-rw-r--r--drivers/media/platform/s5p-mfc/s5p_mfc_pm.c10
-rw-r--r--drivers/media/platform/s5p-tv/hdmi_drv.c2
-rw-r--r--drivers/media/platform/s5p-tv/sdo_drv.c2
-rw-r--r--drivers/media/platform/sh_vou.c11
-rw-r--r--drivers/media/platform/soc_camera/atmel-isi.c22
-rw-r--r--drivers/media/platform/soc_camera/mx2_camera.c26
-rw-r--r--drivers/media/platform/soc_camera/mx3_camera.c6
-rw-r--r--drivers/media/platform/soc_camera/omap1_camera.c36
-rw-r--r--drivers/media/platform/soc_camera/pxa_camera.c16
-rw-r--r--drivers/media/platform/soc_camera/rcar_vin.c14
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c20
-rw-r--r--drivers/media/platform/soc_camera/sh_mobile_csi2.c38
-rw-r--r--drivers/media/platform/soc_camera/soc_camera.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_camera_platform.c2
-rw-r--r--drivers/media/platform/soc_camera/soc_mediabus.c78
-rw-r--r--drivers/media/platform/ti-vpe/csc.c10
-rw-r--r--drivers/media/platform/ti-vpe/sc.c10
-rw-r--r--drivers/media/platform/via-camera.c12
-rw-r--r--drivers/media/platform/vim2m.c (renamed from drivers/media/platform/mem2mem_testdev.c)222
-rw-r--r--drivers/media/platform/vino.c6
-rw-r--r--drivers/media/platform/vivid/vivid-core.c21
-rw-r--r--drivers/media/platform/vivid/vivid-core.h16
-rw-r--r--drivers/media/platform/vivid/vivid-ctrls.c165
-rw-r--r--drivers/media/platform/vivid/vivid-sdr-cap.c4
-rw-r--r--drivers/media/platform/vivid/vivid-tpg-colors.c704
-rw-r--r--drivers/media/platform/vivid/vivid-tpg-colors.h4
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.c327
-rw-r--r--drivers/media/platform/vivid/vivid-tpg.h38
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-cap.c4
-rw-r--r--drivers/media/platform/vivid/vivid-vbi-out.c4
-rw-r--r--drivers/media/platform/vivid/vivid-vid-cap.c38
-rw-r--r--drivers/media/platform/vivid/vivid-vid-common.c4
-rw-r--r--drivers/media/platform/vivid/vivid-vid-out.c29
-rw-r--r--drivers/media/platform/vsp1/vsp1_bru.c14
-rw-r--r--drivers/media/platform/vsp1/vsp1_hsit.c12
-rw-r--r--drivers/media/platform/vsp1/vsp1_lif.c10
-rw-r--r--drivers/media/platform/vsp1/vsp1_lut.c14
-rw-r--r--drivers/media/platform/vsp1/vsp1_rwpf.c10
-rw-r--r--drivers/media/platform/vsp1/vsp1_sru.c12
-rw-r--r--drivers/media/platform/vsp1/vsp1_uds.c10
-rw-r--r--drivers/media/platform/vsp1/vsp1_video.c42
-rw-r--r--drivers/media/radio/radio-wl1273.c4
-rw-r--r--drivers/media/radio/si4713/radio-platform-si4713.c28
-rw-r--r--drivers/media/radio/si4713/si4713.c164
-rw-r--r--drivers/media/radio/si4713/si4713.h15
-rw-r--r--drivers/media/radio/wl128x/fmdrv_v4l2.c4
-rw-r--r--drivers/media/rc/Kconfig26
-rw-r--r--drivers/media/rc/Makefile2
-rw-r--r--drivers/media/rc/igorplugusb.c261
-rw-r--r--drivers/media/rc/img-ir/Kconfig1
-rw-r--r--drivers/media/rc/img-ir/img-ir-core.c1
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.c28
-rw-r--r--drivers/media/rc/img-ir/img-ir-hw.h6
-rw-r--r--drivers/media/rc/ir-lirc-codec.c12
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c2
-rw-r--r--drivers/media/rc/lirc_dev.c3
-rw-r--r--drivers/media/rc/meson-ir.c216
-rw-r--r--drivers/media/rc/rc-main.c8
-rw-r--r--drivers/media/rc/redrat3.c4
-rw-r--r--drivers/media/tuners/Kconfig8
-rw-r--r--drivers/media/tuners/Makefile1
-rw-r--r--drivers/media/tuners/m88rs6000t.c744
-rw-r--r--drivers/media/tuners/m88rs6000t.h29
-rw-r--r--drivers/media/tuners/m88ts2022.c2
-rw-r--r--drivers/media/tuners/mxl5007t.c30
-rw-r--r--drivers/media/tuners/r820t.c12
-rw-r--r--drivers/media/tuners/si2157.c44
-rw-r--r--drivers/media/tuners/si2157.h2
-rw-r--r--drivers/media/tuners/si2157_priv.h8
-rw-r--r--drivers/media/tuners/tda18271-common.c2
-rw-r--r--drivers/media/tuners/xc5000.c17
-rw-r--r--drivers/media/tuners/xc5000.h1
-rw-r--r--drivers/media/usb/au0828/au0828-cards.c5
-rw-r--r--drivers/media/usb/au0828/au0828-core.c8
-rw-r--r--drivers/media/usb/au0828/au0828-dvb.c2
-rw-r--r--drivers/media/usb/au0828/au0828-input.c14
-rw-r--r--drivers/media/usb/cx231xx/Kconfig1
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-417.c59
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-audio.c97
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-avcore.c331
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-cards.c257
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-core.c165
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-dvb.c159
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-i2c.c132
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-input.c8
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c47
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-vbi.c48
-rw-r--r--drivers/media/usb/cx231xx/cx231xx-video.c89
-rw-r--r--drivers/media/usb/cx231xx/cx231xx.h41
-rw-r--r--drivers/media/usb/dvb-usb-v2/Kconfig3
-rw-r--r--drivers/media/usb/dvb-usb-v2/af9035.c1
-rw-r--r--drivers/media/usb/dvb-usb-v2/dvbsky.c438
-rw-r--r--drivers/media/usb/dvb-usb-v2/lmedm04.c22
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.c231
-rw-r--r--drivers/media/usb/dvb-usb-v2/rtl28xxu.h7
-rw-r--r--drivers/media/usb/dvb-usb/Kconfig1
-rw-r--r--drivers/media/usb/dvb-usb/af9005.c3
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.c230
-rw-r--r--drivers/media/usb/dvb-usb/cxusb.h4
-rw-r--r--drivers/media/usb/dvb-usb/technisat-usb2.c5
-rw-r--r--drivers/media/usb/em28xx/em28xx-audio.c19
-rw-r--r--drivers/media/usb/em28xx/em28xx-camera.c7
-rw-r--r--drivers/media/usb/em28xx/em28xx-cards.c71
-rw-r--r--drivers/media/usb/em28xx/em28xx-core.c41
-rw-r--r--drivers/media/usb/em28xx/em28xx-dvb.c95
-rw-r--r--drivers/media/usb/em28xx/em28xx-i2c.c6
-rw-r--r--drivers/media/usb/em28xx/em28xx-input.c17
-rw-r--r--drivers/media/usb/em28xx/em28xx-reg.h3
-rw-r--r--drivers/media/usb/em28xx/em28xx-v4l.h1
-rw-r--r--drivers/media/usb/em28xx/em28xx-vbi.c1
-rw-r--r--drivers/media/usb/em28xx/em28xx-video.c98
-rw-r--r--drivers/media/usb/em28xx/em28xx.h27
-rw-r--r--drivers/media/usb/go7007/go7007-v4l2.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-context.c2
-rw-r--r--drivers/media/usb/pvrusb2/pvrusb2-hdw.c2
-rw-r--r--drivers/media/usb/s2255/s2255drv.c27
-rw-r--r--drivers/media/usb/stk1160/stk1160-v4l.c2
-rw-r--r--drivers/media/usb/usbvision/usbvision-video.c3
-rw-r--r--drivers/media/usb/uvc/uvc_driver.c51
-rw-r--r--drivers/media/usb/uvc/uvc_queue.c161
-rw-r--r--drivers/media/usb/uvc/uvc_v4l2.c1009
-rw-r--r--drivers/media/usb/uvc/uvc_video.c23
-rw-r--r--drivers/media/usb/uvc/uvcvideo.h12
-rw-r--r--drivers/media/v4l2-core/v4l2-common.c125
-rw-r--r--drivers/media/v4l2-core/v4l2-compat-ioctl32.c10
-rw-r--r--drivers/media/v4l2-core/v4l2-ctrls.c87
-rw-r--r--drivers/media/v4l2-core/v4l2-dev.c34
-rw-r--r--drivers/media/v4l2-core/v4l2-ioctl.c15
-rw-r--r--drivers/media/v4l2-core/videobuf-core.c6
-rw-r--r--drivers/media/v4l2-core/videobuf2-core.c49
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-contig.c71
-rw-r--r--drivers/media/v4l2-core/videobuf2-dma-sg.c425
-rw-r--r--drivers/media/v4l2-core/videobuf2-vmalloc.c194
-rw-r--r--drivers/memory/Kconfig20
-rw-r--r--drivers/memory/Makefile4
-rw-r--r--drivers/memory/omap-gpmc.c (renamed from arch/arm/mach-omap2/gpmc.c)387
-rw-r--r--drivers/memory/tegra/Kconfig7
-rw-r--r--drivers/memory/tegra/Makefile7
-rw-r--r--drivers/memory/tegra/mc.c301
-rw-r--r--drivers/memory/tegra/mc.h40
-rw-r--r--drivers/memory/tegra/tegra114.c948
-rw-r--r--drivers/memory/tegra/tegra124.c995
-rw-r--r--drivers/memory/tegra/tegra30.c970
-rw-r--r--drivers/memory/tegra30-mc.c378
-rw-r--r--drivers/message/fusion/mptsas.c1
-rw-r--r--drivers/message/fusion/mptscsih.c22
-rw-r--r--drivers/message/fusion/mptscsih.h3
-rw-r--r--drivers/mfd/Kconfig25
-rw-r--r--drivers/mfd/Makefile4
-rw-r--r--drivers/mfd/ab8500-gpadc.c2
-rw-r--r--drivers/mfd/ab8500-sysctrl.c57
-rw-r--r--drivers/mfd/arizona-core.c4
-rw-r--r--drivers/mfd/arizona-spi.c2
-rw-r--r--drivers/mfd/atmel-hlcdc.c122
-rw-r--r--drivers/mfd/axp20x.c364
-rw-r--r--drivers/mfd/da9063-core.c4
-rw-r--r--drivers/mfd/db8500-prcmu.c22
-rw-r--r--drivers/mfd/dln2.c781
-rw-r--r--drivers/mfd/intel_soc_pmic_crc.c3
-rw-r--r--drivers/mfd/lpc_sch.c6
-rw-r--r--drivers/mfd/max14577.c2
-rw-r--r--drivers/mfd/max77693.c31
-rw-r--r--drivers/mfd/mfd-core.c8
-rw-r--r--drivers/mfd/rts5227.c6
-rw-r--r--drivers/mfd/rts5249.c4
-rw-r--r--drivers/mfd/rtsx_gops.c37
-rw-r--r--drivers/mfd/rtsx_pcr.h3
-rw-r--r--drivers/mfd/rtsx_usb.c4
-rw-r--r--drivers/mfd/sec-core.c39
-rw-r--r--drivers/mfd/sec-irq.c23
-rw-r--r--drivers/mfd/syscon.c96
-rw-r--r--drivers/mfd/t7l66xb.c14
-rw-r--r--drivers/mfd/tc3589x.c9
-rw-r--r--drivers/mfd/tc6387xb.c10
-rw-r--r--drivers/mfd/tc6393xb.c23
-rw-r--r--drivers/mfd/tps65090.c62
-rw-r--r--drivers/mfd/tps65217.c2
-rw-r--r--drivers/mfd/twl4030-power.c3
-rw-r--r--drivers/mfd/vexpress-sysreg.c2
-rw-r--r--drivers/mfd/viperboard.c5
-rw-r--r--drivers/mfd/wm5102-tables.c6
-rw-r--r--drivers/mfd/wm5110-tables.c20
-rw-r--r--drivers/mfd/wm8350-core.c2
-rw-r--r--drivers/mfd/wm8994-core.c2
-rw-r--r--drivers/mfd/wm8997-tables.c6
-rw-r--r--drivers/misc/Kconfig2
-rw-r--r--drivers/misc/apds990x.c4
-rw-r--r--drivers/misc/bh1770glc.c2
-rw-r--r--drivers/misc/eeprom/at25.c34
-rw-r--r--drivers/misc/eeprom/eeprom_93cx6.c62
-rw-r--r--drivers/misc/enclosure.c44
-rw-r--r--drivers/misc/genwqe/card_dev.c2
-rw-r--r--drivers/misc/lis3lv02d/lis3lv02d_i2c.c4
-rw-r--r--drivers/misc/mei/mei_dev.h4
-rw-r--r--drivers/misc/mei/pci-me.c8
-rw-r--r--drivers/misc/mei/pci-txe.c8
-rw-r--r--drivers/misc/mic/card/mic_virtio.c14
-rw-r--r--drivers/misc/vexpress-syscfg.c60
-rw-r--r--drivers/mmc/card/block.c83
-rw-r--r--drivers/mmc/card/mmc_test.c28
-rw-r--r--drivers/mmc/card/queue.c16
-rw-r--r--drivers/mmc/core/bus.c59
-rw-r--r--drivers/mmc/core/core.c111
-rw-r--r--drivers/mmc/core/core.h1
-rw-r--r--drivers/mmc/core/debugfs.c9
-rw-r--r--drivers/mmc/core/mmc.c184
-rw-r--r--drivers/mmc/core/mmc_ops.c130
-rw-r--r--drivers/mmc/core/mmc_ops.h2
-rw-r--r--drivers/mmc/core/sdio.c10
-rw-r--r--drivers/mmc/core/sdio_bus.c16
-rw-r--r--drivers/mmc/host/Kconfig7
-rw-r--r--drivers/mmc/host/Makefile1
-rw-r--r--drivers/mmc/host/atmel-mci.c207
-rw-r--r--drivers/mmc/host/dw_mmc-exynos.c91
-rw-r--r--drivers/mmc/host/dw_mmc-pltfm.c6
-rw-r--r--drivers/mmc/host/dw_mmc-rockchip.c13
-rw-r--r--drivers/mmc/host/dw_mmc.c346
-rw-r--r--drivers/mmc/host/dw_mmc.h15
-rw-r--r--drivers/mmc/host/mmci.c9
-rw-r--r--drivers/mmc/host/msm_sdcc.c6
-rw-r--r--drivers/mmc/host/mvsdio.c7
-rw-r--r--drivers/mmc/host/mxcmmc.c25
-rw-r--r--drivers/mmc/host/mxs-mmc.c26
-rw-r--r--drivers/mmc/host/omap_hsmmc.c286
-rw-r--r--drivers/mmc/host/sdhci-acpi.c54
-rw-r--r--drivers/mmc/host/sdhci-esdhc-imx.c82
-rw-r--r--drivers/mmc/host/sdhci-msm.c50
-rw-r--r--drivers/mmc/host/sdhci-of-arasan.c5
-rw-r--r--drivers/mmc/host/sdhci-pci-o2micro.c2
-rw-r--r--drivers/mmc/host/sdhci-pci.c74
-rw-r--r--drivers/mmc/host/sdhci-pxav2.c15
-rw-r--r--drivers/mmc/host/sdhci-pxav3.c62
-rw-r--r--drivers/mmc/host/sdhci-s3c.c14
-rw-r--r--drivers/mmc/host/sdhci.c280
-rw-r--r--drivers/mmc/host/sdhci.h48
-rw-r--r--drivers/mmc/host/sh_mobile_sdhi.c2
-rw-r--r--drivers/mmc/host/sunxi-mmc.c1
-rw-r--r--drivers/mmc/host/tmio_mmc.c2
-rw-r--r--drivers/mmc/host/toshsd.c717
-rw-r--r--drivers/mmc/host/toshsd.h176
-rw-r--r--drivers/net/ethernet/cadence/Kconfig2
-rw-r--r--drivers/net/ethernet/intel/e1000e/netdev.c2
-rw-r--r--drivers/net/ethernet/intel/igb/igb_main.c6
-rw-r--r--drivers/net/macvtap.c68
-rw-r--r--drivers/net/tun.c172
-rw-r--r--drivers/net/virtio_net.c161
-rw-r--r--drivers/nubus/nubus.c4
-rw-r--r--drivers/of/Kconfig11
-rw-r--r--drivers/of/Makefile5
-rw-r--r--drivers/of/address.c4
-rw-r--r--drivers/of/base.c168
-rw-r--r--drivers/of/dynamic.c218
-rw-r--r--drivers/of/fdt.c111
-rw-r--r--drivers/of/of_pci.c8
-rw-r--r--drivers/of/of_private.h2
-rw-r--r--drivers/of/overlay.c562
-rw-r--r--drivers/of/pdt.c27
-rw-r--r--drivers/of/platform.c65
-rw-r--r--drivers/of/resolver.c128
-rw-r--r--drivers/of/testcase-data/testcases.dts50
-rw-r--r--drivers/of/unittest-data/testcases.dts79
-rw-r--r--drivers/of/unittest-data/tests-interrupts.dtsi (renamed from drivers/of/testcase-data/tests-interrupts.dtsi)0
-rw-r--r--drivers/of/unittest-data/tests-match.dtsi (renamed from drivers/of/testcase-data/tests-match.dtsi)0
-rw-r--r--drivers/of/unittest-data/tests-overlay.dtsi180
-rw-r--r--drivers/of/unittest-data/tests-phandle.dtsi (renamed from drivers/of/testcase-data/tests-phandle.dtsi)0
-rw-r--r--drivers/of/unittest-data/tests-platform.dtsi (renamed from drivers/of/testcase-data/tests-platform.dtsi)0
-rw-r--r--drivers/of/unittest.c (renamed from drivers/of/selftest.c)633
-rw-r--r--drivers/pci/Kconfig6
-rw-r--r--drivers/pci/host/Kconfig13
-rw-r--r--drivers/pci/host/Makefile1
-rw-r--r--drivers/pci/host/pci-dra7xx.c6
-rw-r--r--drivers/pci/host/pci-exynos.c18
-rw-r--r--drivers/pci/host/pci-host-generic.c126
-rw-r--r--drivers/pci/host/pci-imx6.c4
-rw-r--r--drivers/pci/host/pci-keystone-dw.c8
-rw-r--r--drivers/pci/host/pci-keystone.c5
-rw-r--r--drivers/pci/host/pci-keystone.h2
-rw-r--r--drivers/pci/host/pci-layerscape.c179
-rw-r--r--drivers/pci/host/pci-mvebu.c15
-rw-r--r--drivers/pci/host/pci-tegra.c35
-rw-r--r--drivers/pci/host/pcie-designware.c33
-rw-r--r--drivers/pci/host/pcie-designware.h2
-rw-r--r--drivers/pci/host/pcie-rcar.c33
-rw-r--r--drivers/pci/host/pcie-spear13xx.c13
-rw-r--r--drivers/pci/host/pcie-xilinx.c37
-rw-r--r--drivers/pci/hotplug/ibmphp_res.c5
-rw-r--r--drivers/pci/iov.c11
-rw-r--r--drivers/pci/msi.c394
-rw-r--r--drivers/pci/pci-acpi.c3
-rw-r--r--drivers/pci/pci-driver.c20
-rw-r--r--drivers/pci/pci-sysfs.c31
-rw-r--r--drivers/pci/pci.c21
-rw-r--r--drivers/pci/pci.h6
-rw-r--r--drivers/pci/pcie/Kconfig2
-rw-r--r--drivers/pci/probe.c80
-rw-r--r--drivers/pci/search.c3
-rw-r--r--drivers/pci/xen-pcifront.c13
-rw-r--r--drivers/pinctrl/Kconfig13
-rw-r--r--drivers/pinctrl/Makefile2
-rw-r--r--drivers/pinctrl/freescale/pinctrl-imx.c72
-rw-r--r--drivers/pinctrl/freescale/pinctrl-mxs.c25
-rw-r--r--drivers/pinctrl/intel/Kconfig27
-rw-r--r--drivers/pinctrl/intel/Makefile4
-rw-r--r--drivers/pinctrl/intel/pinctrl-baytrail.c (renamed from drivers/pinctrl/pinctrl-baytrail.c)7
-rw-r--r--drivers/pinctrl/intel/pinctrl-cherryview.c1519
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-abx500.c33
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c4
-rw-r--r--drivers/pinctrl/nomadik/pinctrl-nomadik.c18
-rw-r--r--drivers/pinctrl/pinconf-generic.c71
-rw-r--r--drivers/pinctrl/pinctrl-at91.c17
-rw-r--r--drivers/pinctrl/pinctrl-at91.h72
-rw-r--r--drivers/pinctrl/pinctrl-bcm281xx.c5
-rw-r--r--drivers/pinctrl/pinctrl-rockchip.c116
-rw-r--r--drivers/pinctrl/pinctrl-st.c2
-rw-r--r--drivers/pinctrl/pinctrl-tb10x.c8
-rw-r--r--drivers/pinctrl/pinctrl-tegra-xusb.c19
-rw-r--r--drivers/pinctrl/qcom/Kconfig13
-rw-r--r--drivers/pinctrl/qcom/Makefile2
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-gpio.c933
-rw-r--r--drivers/pinctrl/qcom/pinctrl-spmi-mpp.c949
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.c376
-rw-r--r--drivers/pinctrl/samsung/pinctrl-exynos.h3
-rw-r--r--drivers/pinctrl/samsung/pinctrl-s3c24xx.c30
-rw-r--r--drivers/pinctrl/samsung/pinctrl-s3c64xx.c31
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.c131
-rw-r--r--drivers/pinctrl/samsung/pinctrl-samsung.h82
-rw-r--r--drivers/pinctrl/sunxi/Kconfig4
-rw-r--r--drivers/pinctrl/sunxi/Makefile1
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c749
-rw-r--r--drivers/pinctrl/sunxi/pinctrl-sunxi.h1
-rw-r--r--drivers/power/reset/Kconfig9
-rw-r--r--drivers/power/reset/Makefile1
-rw-r--r--drivers/power/reset/at91-reset.c4
-rw-r--r--drivers/power/reset/imx-snvs-poweroff.c66
-rw-r--r--drivers/powercap/Kconfig2
-rw-r--r--drivers/powercap/intel_rapl.c264
-rw-r--r--drivers/regulator/88pm8607.c3
-rw-r--r--drivers/regulator/Kconfig20
-rw-r--r--drivers/regulator/Makefile1
-rw-r--r--drivers/regulator/act8865-regulator.c31
-rw-r--r--drivers/regulator/anatop-regulator.c18
-rw-r--r--drivers/regulator/arizona-ldo1.c10
-rw-r--r--drivers/regulator/arizona-micsupp.c8
-rw-r--r--drivers/regulator/core.c23
-rw-r--r--drivers/regulator/da9052-regulator.c3
-rw-r--r--drivers/regulator/da9063-regulator.c19
-rw-r--r--drivers/regulator/da9210-regulator.c2
-rw-r--r--drivers/regulator/dummy.c2
-rw-r--r--drivers/regulator/fan53555.c17
-rw-r--r--drivers/regulator/fixed.c24
-rw-r--r--drivers/regulator/gpio-regulator.c115
-rw-r--r--drivers/regulator/max77686.c172
-rw-r--r--drivers/regulator/max77693.c2
-rw-r--r--drivers/regulator/max77802.c254
-rw-r--r--drivers/regulator/max8952.c4
-rw-r--r--drivers/regulator/max8973-regulator.c3
-rw-r--r--drivers/regulator/max8997.c3
-rw-r--r--drivers/regulator/max8998.c5
-rw-r--r--drivers/regulator/mc13xxx-regulator-core.c3
-rw-r--r--drivers/regulator/of_regulator.c87
-rw-r--r--drivers/regulator/pwm-regulator.c3
-rw-r--r--drivers/regulator/qcom_rpm-regulator.c28
-rw-r--r--drivers/regulator/rk808-regulator.c57
-rw-r--r--drivers/regulator/rn5t618-regulator.c51
-rw-r--r--drivers/regulator/rt5033-regulator.c123
-rw-r--r--drivers/regulator/s2mpa01.c2
-rw-r--r--drivers/regulator/s2mps11.c105
-rw-r--r--drivers/regulator/s5m8767.c4
-rw-r--r--drivers/regulator/sky81452-regulator.c46
-rw-r--r--drivers/regulator/stw481x-vmmc.c3
-rw-r--r--drivers/regulator/ti-abb-regulator.c3
-rw-r--r--drivers/regulator/tps51632-regulator.c43
-rw-r--r--drivers/regulator/tps62360-regulator.c31
-rw-r--r--drivers/regulator/tps65090-regulator.c4
-rw-r--r--drivers/regulator/tps65218-regulator.c3
-rw-r--r--drivers/regulator/twl-regulator.c3
-rw-r--r--drivers/regulator/vexpress.c3
-rw-r--r--drivers/regulator/wm8994-regulator.c6
-rw-r--r--drivers/remoteproc/omap_remoteproc.c51
-rw-r--r--drivers/remoteproc/remoteproc_virtio.c11
-rw-r--r--drivers/reset/Makefile1
-rw-r--r--drivers/reset/core.c15
-rw-r--r--drivers/reset/reset-berlin.c131
-rw-r--r--drivers/reset/reset-socfpga.c15
-rw-r--r--drivers/reset/sti/Kconfig4
-rw-r--r--drivers/reset/sti/Makefile1
-rw-r--r--drivers/reset/sti/reset-stih407.c158
-rw-r--r--drivers/rtc/Kconfig38
-rw-r--r--drivers/rtc/class.c30
-rw-r--r--drivers/rtc/interface.c21
-rw-r--r--drivers/rtc/rtc-ab8500.c2
-rw-r--r--drivers/rtc/rtc-at91sam9.c138
-rw-r--r--drivers/rtc/rtc-ds1307.c127
-rw-r--r--drivers/rtc/rtc-ds1374.c285
-rw-r--r--drivers/rtc/rtc-isl12057.c83
-rw-r--r--drivers/rtc/rtc-lib.c38
-rw-r--r--drivers/rtc/rtc-omap.c547
-rw-r--r--drivers/rtc/rtc-pcf8563.c55
-rw-r--r--drivers/rtc/rtc-sirfsoc.c66
-rw-r--r--drivers/rtc/rtc-snvs.c39
-rw-r--r--drivers/s390/char/hmcdrv_dev.c16
-rw-r--r--drivers/s390/kvm/kvm_virtio.c11
-rw-r--r--drivers/s390/kvm/virtio_ccw.c203
-rw-r--r--drivers/s390/scsi/zfcp_aux.c6
-rw-r--r--drivers/s390/scsi/zfcp_ccw.c32
-rw-r--r--drivers/s390/scsi/zfcp_def.h3
-rw-r--r--drivers/s390/scsi/zfcp_erp.c7
-rw-r--r--drivers/s390/scsi/zfcp_ext.h1
-rw-r--r--drivers/s390/scsi/zfcp_fc.c52
-rw-r--r--drivers/s390/scsi/zfcp_fc.h14
-rw-r--r--drivers/s390/scsi/zfcp_fsf.c3
-rw-r--r--drivers/s390/scsi/zfcp_scsi.c26
-rw-r--r--drivers/s390/scsi/zfcp_sysfs.c66
-rw-r--r--drivers/scsi/3w-9xxx.c15
-rw-r--r--drivers/scsi/3w-sas.c15
-rw-r--r--drivers/scsi/3w-xxxx.c15
-rw-r--r--drivers/scsi/53c700.c51
-rw-r--r--drivers/scsi/BusLogic.c4
-rw-r--r--drivers/scsi/Kconfig18
-rw-r--r--drivers/scsi/Makefile3
-rw-r--r--drivers/scsi/NCR5380.c310
-rw-r--r--drivers/scsi/NCR5380.h78
-rw-r--r--drivers/scsi/aacraid/aachba.c4
-rw-r--r--drivers/scsi/aacraid/linit.c20
-rw-r--r--drivers/scsi/advansys.c11
-rw-r--r--drivers/scsi/aha152x.c994
-rw-r--r--drivers/scsi/aha1740.c2
-rw-r--r--drivers/scsi/aic7xxx/aic79xx_osm.c19
-rw-r--r--drivers/scsi/aic7xxx/aic7xxx_osm.c23
-rw-r--r--drivers/scsi/aic94xx/aic94xx.h2
-rw-r--r--drivers/scsi/aic94xx/aic94xx_hwi.c3
-rw-r--r--drivers/scsi/aic94xx/aic94xx_init.c13
-rw-r--r--drivers/scsi/aic94xx/aic94xx_task.c13
-rw-r--r--drivers/scsi/am53c974.c586
-rw-r--r--drivers/scsi/arcmsr/arcmsr_hba.c9
-rw-r--r--drivers/scsi/arm/acornscsi.c12
-rw-r--r--drivers/scsi/arm/cumana_1.c18
-rw-r--r--drivers/scsi/arm/fas216.c39
-rw-r--r--drivers/scsi/arm/oak.c23
-rw-r--r--drivers/scsi/atari_NCR5380.c986
-rw-r--r--drivers/scsi/atari_scsi.c673
-rw-r--r--drivers/scsi/atari_scsi.h60
-rw-r--r--drivers/scsi/be2iscsi/be_main.c4
-rw-r--r--drivers/scsi/bfa/bfad_debugfs.c30
-rw-r--r--drivers/scsi/bfa/bfad_im.c18
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_fcoe.c9
-rw-r--r--drivers/scsi/bnx2fc/bnx2fc_io.c18
-rw-r--r--drivers/scsi/bnx2i/bnx2i_iscsi.c3
-rw-r--r--drivers/scsi/ch.c36
-rw-r--r--drivers/scsi/constants.c599
-rw-r--r--drivers/scsi/csiostor/csio_scsi.c37
-rw-r--r--drivers/scsi/cxgbi/cxgb3i/cxgb3i.c3
-rw-r--r--drivers/scsi/cxgbi/cxgb4i/cxgb4i.c3
-rw-r--r--drivers/scsi/device_handler/scsi_dh.c55
-rw-r--r--drivers/scsi/device_handler/scsi_dh_alua.c82
-rw-r--r--drivers/scsi/device_handler/scsi_dh_emc.c86
-rw-r--r--drivers/scsi/device_handler/scsi_dh_hp_sw.c81
-rw-r--r--drivers/scsi/device_handler/scsi_dh_rdac.c82
-rw-r--r--drivers/scsi/dmx3191d.c31
-rw-r--r--drivers/scsi/dpt_i2o.c4
-rw-r--r--drivers/scsi/dtc.c85
-rw-r--r--drivers/scsi/dtc.h26
-rw-r--r--drivers/scsi/eata.c8
-rw-r--r--drivers/scsi/esas2r/esas2r.h5
-rw-r--r--drivers/scsi/esas2r/esas2r_ioctl.c22
-rw-r--r--drivers/scsi/esas2r/esas2r_main.c64
-rw-r--r--drivers/scsi/esp_scsi.c428
-rw-r--r--drivers/scsi/esp_scsi.h22
-rw-r--r--drivers/scsi/fcoe/fcoe.c6
-rw-r--r--drivers/scsi/fnic/fnic.h2
-rw-r--r--drivers/scsi/fnic/fnic_fcs.c5
-rw-r--r--drivers/scsi/fnic/fnic_main.c23
-rw-r--r--drivers/scsi/fnic/fnic_scsi.c43
-rw-r--r--drivers/scsi/fnic/fnic_trace.c4
-rw-r--r--drivers/scsi/g_NCR5380.c224
-rw-r--r--drivers/scsi/g_NCR5380.h26
-rw-r--r--drivers/scsi/gdth.c5
-rw-r--r--drivers/scsi/hosts.c5
-rw-r--r--drivers/scsi/hpsa.c509
-rw-r--r--drivers/scsi/hpsa.h33
-rw-r--r--drivers/scsi/hpsa_cmd.h34
-rw-r--r--drivers/scsi/hptiop.c8
-rw-r--r--drivers/scsi/ibmvscsi/ibmvfc.c58
-rw-r--r--drivers/scsi/ibmvscsi/ibmvscsi.c11
-rw-r--r--drivers/scsi/ipr.c175
-rw-r--r--drivers/scsi/ipr.h2
-rw-r--r--drivers/scsi/ips.c2
-rw-r--r--drivers/scsi/isci/init.c4
-rw-r--r--drivers/scsi/isci/task.c147
-rw-r--r--drivers/scsi/isci/task.h1
-rw-r--r--drivers/scsi/iscsi_tcp.c3
-rw-r--r--drivers/scsi/libfc/fc_fcp.c52
-rw-r--r--drivers/scsi/libiscsi.c19
-rw-r--r--drivers/scsi/libsas/sas_ata.c9
-rw-r--r--drivers/scsi/libsas/sas_expander.c2
-rw-r--r--drivers/scsi/libsas/sas_init.c21
-rw-r--r--drivers/scsi/libsas/sas_internal.h2
-rw-r--r--drivers/scsi/libsas/sas_scsi_host.c223
-rw-r--r--drivers/scsi/lpfc/lpfc_debugfs.c8
-rw-r--r--drivers/scsi/lpfc/lpfc_scsi.c158
-rw-r--r--drivers/scsi/mac_scsi.c552
-rw-r--r--drivers/scsi/mac_scsi.h74
-rw-r--r--drivers/scsi/megaraid.c8
-rw-r--r--drivers/scsi/megaraid/megaraid_mbox.c23
-rw-r--r--drivers/scsi/megaraid/megaraid_sas.h23
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_base.c164
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fp.c33
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.c112
-rw-r--r--drivers/scsi/megaraid/megaraid_sas_fusion.h18
-rw-r--r--drivers/scsi/mpt2sas/mpt2sas_scsih.c82
-rw-r--r--drivers/scsi/mpt3sas/mpt3sas_scsih.c84
-rw-r--r--drivers/scsi/mvsas/mv_init.c24
-rw-r--r--drivers/scsi/mvsas/mv_sas.c109
-rw-r--r--drivers/scsi/mvsas/mv_sas.h10
-rw-r--r--drivers/scsi/ncr53c8xx.c5
-rw-r--r--drivers/scsi/osd/osd_uld.c2
-rw-r--r--drivers/scsi/osst.c29
-rw-r--r--drivers/scsi/pas16.c106
-rw-r--r--drivers/scsi/pas16.h21
-rw-r--r--drivers/scsi/pm8001/pm8001_init.c4
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.c22
-rw-r--r--drivers/scsi/pm8001/pm8001_sas.h3
-rw-r--r--drivers/scsi/pmcraid.c94
-rw-r--r--drivers/scsi/ps3rom.c4
-rw-r--r--drivers/scsi/qla1280.c5
-rw-r--r--drivers/scsi/qla2xxx/qla_gbl.h2
-rw-r--r--drivers/scsi/qla2xxx/qla_iocb.c92
-rw-r--r--drivers/scsi/qla2xxx/qla_mr.c13
-rw-r--r--drivers/scsi/qla2xxx/qla_nx2.c2
-rw-r--r--drivers/scsi/qla2xxx/qla_os.c83
-rw-r--r--drivers/scsi/qla4xxx/ql4_iocb.c10
-rw-r--r--drivers/scsi/qla4xxx/ql4_os.c35
-rw-r--r--drivers/scsi/scsi.c211
-rw-r--r--drivers/scsi/scsi_debug.c1995
-rw-r--r--drivers/scsi/scsi_error.c211
-rw-r--r--drivers/scsi/scsi_ioctl.c74
-rw-r--r--drivers/scsi/scsi_lib.c165
-rw-r--r--drivers/scsi/scsi_logging.h1
-rw-r--r--drivers/scsi/scsi_priv.h2
-rw-r--r--drivers/scsi/scsi_scan.c27
-rw-r--r--drivers/scsi/scsi_sysfs.c18
-rw-r--r--drivers/scsi/scsi_trace.c2
-rw-r--r--drivers/scsi/scsi_transport_spi.c23
-rw-r--r--drivers/scsi/scsicam.c4
-rw-r--r--drivers/scsi/sd.c114
-rw-r--r--drivers/scsi/sd.h6
-rw-r--r--drivers/scsi/ses.c2
-rw-r--r--drivers/scsi/sg.c62
-rw-r--r--drivers/scsi/sr.c19
-rw-r--r--drivers/scsi/sr.h3
-rw-r--r--drivers/scsi/sr_ioctl.c10
-rw-r--r--drivers/scsi/st.c47
-rw-r--r--drivers/scsi/stex.c30
-rw-r--r--drivers/scsi/storvsc_drv.c6
-rw-r--r--drivers/scsi/sun3_NCR5380.c2933
-rw-r--r--drivers/scsi/sun3_scsi.c512
-rw-r--r--drivers/scsi/sun3_scsi.h84
-rw-r--r--drivers/scsi/sym53c8xx_2/sym_glue.c4
-rw-r--r--drivers/scsi/t128.c83
-rw-r--r--drivers/scsi/t128.h23
-rw-r--r--drivers/scsi/tmscsim.c2620
-rw-r--r--drivers/scsi/tmscsim.h551
-rw-r--r--drivers/scsi/u14-34f.c10
-rw-r--r--drivers/scsi/ufs/ufshcd.c39
-rw-r--r--drivers/scsi/virtio_scsi.c90
-rw-r--r--drivers/scsi/vmw_pvscsi.c32
-rw-r--r--drivers/scsi/wd7000.c1
-rw-r--r--drivers/scsi/wd719x.c996
-rw-r--r--drivers/scsi/wd719x.h249
-rw-r--r--drivers/sh/pm_runtime.c4
-rw-r--r--drivers/soc/ti/knav_qmss.h8
-rw-r--r--drivers/soc/ti/knav_qmss_queue.c13
-rw-r--r--drivers/soc/versatile/Kconfig9
-rw-r--r--drivers/soc/versatile/Makefile1
-rw-r--r--drivers/soc/versatile/soc-integrator.c155
-rw-r--r--drivers/spi/Kconfig17
-rw-r--r--drivers/spi/Makefile2
-rw-r--r--drivers/spi/spi-atmel.c115
-rw-r--r--drivers/spi/spi-cadence.c33
-rw-r--r--drivers/spi/spi-dw-mid.c114
-rw-r--r--drivers/spi/spi-dw.h2
-rw-r--r--drivers/spi/spi-fsl-cpm.c5
-rw-r--r--drivers/spi/spi-fsl-dspi.c3
-rw-r--r--drivers/spi/spi-fsl-espi.c59
-rw-r--r--drivers/spi/spi-fsl-lib.c59
-rw-r--r--drivers/spi/spi-fsl-lib.h10
-rw-r--r--drivers/spi/spi-fsl-spi.c17
-rw-r--r--drivers/spi/spi-gpio.c37
-rw-r--r--drivers/spi/spi-img-spfi.c746
-rw-r--r--drivers/spi/spi-meson-spifc.c462
-rw-r--r--drivers/spi/spi-mxs.c12
-rw-r--r--drivers/spi/spi-pl022.c2
-rw-r--r--drivers/spi/spi-pxa2xx-pci.c8
-rw-r--r--drivers/spi/spi-pxa2xx.c304
-rw-r--r--drivers/spi/spi-pxa2xx.h16
-rw-r--r--drivers/spi/spi-rockchip.c2
-rw-r--r--drivers/spi/spi-s3c64xx.c41
-rw-r--r--drivers/spi/spi-sirf.c12
-rw-r--r--drivers/spi/spi-txx9.c3
-rw-r--r--drivers/spi/spi.c308
-rw-r--r--drivers/spi/spidev.c16
-rw-r--r--drivers/staging/iio/light/isl29028.c3
-rw-r--r--drivers/staging/lustre/lustre/libcfs/tracefile.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/dcache.c21
-rw-r--r--drivers/staging/lustre/lustre/llite/dir.c9
-rw-r--r--drivers/staging/lustre/lustre/llite/file.c158
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_internal.h10
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_lib.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_mmap.c12
-rw-r--r--drivers/staging/lustre/lustre/llite/llite_nfs.c8
-rw-r--r--drivers/staging/lustre/lustre/llite/lloop.c7
-rw-r--r--drivers/staging/lustre/lustre/llite/namei.c388
-rw-r--r--drivers/staging/lustre/lustre/llite/statahead.c33
-rw-r--r--drivers/staging/lustre/lustre/llite/vvp_io.c4
-rw-r--r--drivers/staging/lustre/lustre/llite/xattr.c9
-rw-r--r--drivers/staging/media/Kconfig4
-rw-r--r--drivers/staging/media/Makefile4
-rw-r--r--drivers/staging/media/bcm2048/radio-bcm2048.c7
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe.c18
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c26
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_ipipeif.c100
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_isif.c90
-rw-r--r--drivers/staging/media/davinci_vpfe/dm365_resizer.c98
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c18
-rw-r--r--drivers/staging/media/davinci_vpfe/vpfe_video.c8
-rw-r--r--drivers/staging/media/dt3155v4l/dt3155v4l.c5
-rw-r--r--drivers/staging/media/lirc/Kconfig6
-rw-r--r--drivers/staging/media/lirc/Makefile1
-rw-r--r--drivers/staging/media/lirc/lirc_igorplugusb.c508
-rw-r--r--drivers/staging/media/lirc/lirc_imon.c10
-rw-r--r--drivers/staging/media/lirc/lirc_sasem.c10
-rw-r--r--drivers/staging/media/lirc/lirc_zilog.c8
-rw-r--r--drivers/staging/media/mn88472/Kconfig7
-rw-r--r--drivers/staging/media/mn88472/Makefile5
-rw-r--r--drivers/staging/media/mn88472/TODO21
-rw-r--r--drivers/staging/media/mn88472/mn88472.c523
-rw-r--r--drivers/staging/media/mn88472/mn88472_priv.h36
-rw-r--r--drivers/staging/media/mn88473/Kconfig7
-rw-r--r--drivers/staging/media/mn88473/Makefile5
-rw-r--r--drivers/staging/media/mn88473/TODO21
-rw-r--r--drivers/staging/media/mn88473/mn88473.c464
-rw-r--r--drivers/staging/media/mn88473/mn88473_priv.h36
-rw-r--r--drivers/staging/media/omap24xx/Kconfig35
-rw-r--r--drivers/staging/media/omap24xx/Makefile5
-rw-r--r--drivers/staging/media/omap24xx/omap24xxcam-dma.c598
-rw-r--r--drivers/staging/media/omap24xx/omap24xxcam.c1882
-rw-r--r--drivers/staging/media/omap24xx/omap24xxcam.h596
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.c938
-rw-r--r--drivers/staging/media/omap24xx/tcm825x.h200
-rw-r--r--drivers/staging/media/omap24xx/v4l2-int-device.c164
-rw-r--r--drivers/staging/media/omap24xx/v4l2-int-device.h305
-rw-r--r--drivers/staging/media/omap4iss/iss_csi2.c62
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipe.c16
-rw-r--r--drivers/staging/media/omap4iss/iss_ipipeif.c28
-rw-r--r--drivers/staging/media/omap4iss/iss_resizer.c26
-rw-r--r--drivers/staging/media/omap4iss/iss_video.c78
-rw-r--r--drivers/staging/media/omap4iss/iss_video.h10
-rw-r--r--drivers/target/loopback/tcm_loop.c75
-rw-r--r--drivers/target/target_core_alua.c2
-rw-r--r--drivers/target/target_core_pr.c2
-rw-r--r--drivers/target/target_core_sbc.c2
-rw-r--r--drivers/tty/n_tty.c17
-rw-r--r--drivers/tty/serial/Kconfig4
-rw-r--r--drivers/usb/core/driver.c6
-rw-r--r--drivers/usb/core/hcd-pci.c11
-rw-r--r--drivers/usb/core/hcd.c12
-rw-r--r--drivers/usb/core/hub.c6
-rw-r--r--drivers/usb/core/port.c4
-rw-r--r--drivers/usb/core/sysfs.c13
-rw-r--r--drivers/usb/core/usb.c4
-rw-r--r--drivers/usb/core/usb.h23
-rw-r--r--drivers/usb/gadget/legacy/tcm_usb_gadget.c2
-rw-r--r--drivers/usb/host/ehci-pci.c2
-rw-r--r--drivers/usb/host/sl811-hcd.c5
-rw-r--r--drivers/usb/host/u132-hcd.c3
-rw-r--r--drivers/usb/host/xhci-hub.c2
-rw-r--r--drivers/usb/host/xhci.c29
-rw-r--r--drivers/usb/phy/phy-msm-usb.c2
-rw-r--r--drivers/usb/storage/debug.c12
-rw-r--r--drivers/usb/storage/uas.c7
-rw-r--r--drivers/vfio/pci/vfio_pci_intrs.c2
-rw-r--r--drivers/vhost/net.c31
-rw-r--r--drivers/vhost/scsi.c22
-rw-r--r--drivers/vhost/vhost.c93
-rw-r--r--drivers/vhost/vhost.h41
-rw-r--r--drivers/video/backlight/Kconfig1
-rw-r--r--drivers/video/backlight/lp855x_bl.c55
-rw-r--r--drivers/video/backlight/pwm_bl.c5
-rw-r--r--drivers/video/console/fbcon.c2
-rw-r--r--drivers/video/fbdev/Kconfig19
-rw-r--r--drivers/video/fbdev/amba-clcd.c1
-rw-r--r--drivers/video/fbdev/arkfb.c2
-rw-r--r--drivers/video/fbdev/gbefb.c3
-rw-r--r--drivers/video/fbdev/mmp/core.c6
-rw-r--r--drivers/video/fbdev/mmp/hw/mmp_ctrl.c3
-rw-r--r--drivers/video/fbdev/mx3fb.c3
-rw-r--r--drivers/video/fbdev/mxsfb.c19
-rw-r--r--drivers/video/fbdev/omap2/displays-new/connector-dvi.c9
-rw-r--r--drivers/video/fbdev/omap2/displays-new/connector-hdmi.c99
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c1
-rw-r--r--drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c57
-rw-r--r--drivers/video/fbdev/omap2/dss/Kconfig7
-rw-r--r--drivers/video/fbdev/omap2/dss/Makefile2
-rw-r--r--drivers/video/fbdev/omap2/dss/dispc.c20
-rw-r--r--drivers/video/fbdev/omap2/dss/dpi.c327
-rw-r--r--drivers/video/fbdev/omap2/dss/dsi.c659
-rw-r--r--drivers/video/fbdev/omap2/dss/dss-of.c58
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.c123
-rw-r--r--drivers/video/fbdev/omap2/dss/dss.h225
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.c42
-rw-r--r--drivers/video/fbdev/omap2/dss/dss_features.h12
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi.h71
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4.c338
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.c14
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi4_core.h4
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5.c338
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.c11
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi5_core.h2
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_common.c2
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_phy.c31
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_pll.c313
-rw-r--r--drivers/video/fbdev/omap2/dss/hdmi_wp.c16
-rw-r--r--drivers/video/fbdev/omap2/dss/output.c19
-rw-r--r--drivers/video/fbdev/omap2/dss/pll.c378
-rw-r--r--drivers/video/fbdev/omap2/dss/sdi.c2
-rw-r--r--drivers/video/fbdev/s3fb.c2
-rw-r--r--drivers/video/fbdev/sh_mobile_lcdcfb.c3
-rw-r--r--drivers/video/fbdev/simplefb.c162
-rw-r--r--drivers/video/fbdev/sis/sis_main.c14
-rw-r--r--drivers/video/fbdev/sm501fb.c1
-rw-r--r--drivers/video/fbdev/smscufx.c6
-rw-r--r--drivers/video/fbdev/udlfb.c9
-rw-r--r--drivers/video/fbdev/uvesafb.c6
-rw-r--r--drivers/video/fbdev/vermilion/vermilion.c6
-rw-r--r--drivers/video/fbdev/via/viafbdev.c3
-rw-r--r--drivers/video/fbdev/vt8623fb.c2
-rw-r--r--drivers/virtio/Makefile1
-rw-r--r--drivers/virtio/virtio.c102
-rw-r--r--drivers/virtio/virtio_mmio.c17
-rw-r--r--drivers/virtio/virtio_pci.c802
-rw-r--r--drivers/virtio/virtio_pci_common.c464
-rw-r--r--drivers/virtio/virtio_pci_common.h136
-rw-r--r--drivers/virtio/virtio_pci_legacy.c326
-rw-r--r--drivers/virtio/virtio_ring.c109
-rw-r--r--drivers/w1/masters/omap_hdq.c7
-rw-r--r--drivers/watchdog/Kconfig4
-rw-r--r--drivers/watchdog/orion_wdt.c42
-rw-r--r--drivers/watchdog/s3c2410_wdt.c2
-rw-r--r--drivers/xen/efi.c1
-rw-r--r--drivers/xen/xen-scsiback.c4
-rw-r--r--fs/9p/vfs_inode.c2
-rw-r--r--fs/9p/vfs_inode_dotl.c4
-rw-r--r--fs/affs/amigaffs.c2
-rw-r--r--fs/affs/inode.c4
-rw-r--r--fs/affs/namei.c40
-rw-r--r--fs/afs/dir.c80
-rw-r--r--fs/afs/inode.c4
-rw-r--r--fs/afs/mntpt.c22
-rw-r--r--fs/afs/write.c9
-rw-r--r--fs/autofs4/expire.c42
-rw-r--r--fs/autofs4/root.c25
-rw-r--r--fs/befs/linuxvfs.c16
-rw-r--r--fs/binfmt_aout.c8
-rw-r--r--fs/binfmt_elf.c40
-rw-r--r--fs/binfmt_misc.c393
-rw-r--r--fs/block_dev.c10
-rw-r--r--fs/btrfs/inode.c2
-rw-r--r--fs/btrfs/ioctl.c2
-rw-r--r--fs/cachefiles/namei.c21
-rw-r--r--fs/cachefiles/xattr.c15
-rw-r--r--fs/ceph/debugfs.c14
-rw-r--r--fs/ceph/dir.c56
-rw-r--r--fs/ceph/file.c6
-rw-r--r--fs/ceph/inode.c18
-rw-r--r--fs/char_dev.c1
-rw-r--r--fs/cifs/cifs_debug.c77
-rw-r--r--fs/cifs/cifs_debug.h7
-rw-r--r--fs/cifs/cifsacl.c2
-rw-r--r--fs/cifs/cifsfs.c3
-rw-r--r--fs/cifs/cifsfs.h2
-rw-r--r--fs/cifs/cifsglob.h6
-rw-r--r--fs/cifs/cifssmb.c20
-rw-r--r--fs/cifs/connect.c51
-rw-r--r--fs/cifs/file.c16
-rw-r--r--fs/cifs/inode.c2
-rw-r--r--fs/cifs/misc.c32
-rw-r--r--fs/cifs/readdir.c14
-rw-r--r--fs/cifs/sess.c7
-rw-r--r--fs/cifs/smb2file.c4
-rw-r--r--fs/cifs/smb2misc.c38
-rw-r--r--fs/cifs/smb2ops.c65
-rw-r--r--fs/cifs/smb2pdu.c5
-rw-r--r--fs/cifs/smb2pdu.h47
-rw-r--r--fs/cifs/transport.c4
-rw-r--r--fs/coda/cache.c2
-rw-r--r--fs/coda/coda_linux.c6
-rw-r--r--fs/coda/coda_linux.h1
-rw-r--r--fs/coda/dir.c12
-rw-r--r--fs/compat.c21
-rw-r--r--fs/configfs/dir.c2
-rw-r--r--fs/dcache.c271
-rw-r--r--fs/debugfs/file.c15
-rw-r--r--fs/debugfs/inode.c2
-rw-r--r--fs/dlm/debug_fs.c263
-rw-r--r--fs/dlm/lock.c76
-rw-r--r--fs/dlm/lock.h3
-rw-r--r--fs/dlm/user.c13
-rw-r--r--fs/ecryptfs/crypto.c2
-rw-r--r--fs/ecryptfs/file.c6
-rw-r--r--fs/ecryptfs/mmap.c2
-rw-r--r--fs/efivarfs/file.c4
-rw-r--r--fs/efivarfs/super.c11
-rw-r--r--fs/eventfd.c9
-rw-r--r--fs/eventpoll.c13
-rw-r--r--fs/exec.c1
-rw-r--r--fs/exportfs/expfs.c7
-rw-r--r--fs/ext2/ext2.h3
-rw-r--r--fs/ext2/super.c10
-rw-r--r--fs/ext3/ext3.h4
-rw-r--r--fs/ext3/super.c10
-rw-r--r--fs/ext4/ext4.h4
-rw-r--r--fs/ext4/super.c8
-rw-r--r--fs/f2fs/acl.c148
-rw-r--r--fs/f2fs/acl.h5
-rw-r--r--fs/f2fs/checkpoint.c186
-rw-r--r--fs/f2fs/data.c166
-rw-r--r--fs/f2fs/debug.c15
-rw-r--r--fs/f2fs/dir.c308
-rw-r--r--fs/f2fs/f2fs.h176
-rw-r--r--fs/f2fs/file.c212
-rw-r--r--fs/f2fs/gc.c89
-rw-r--r--fs/f2fs/gc.h5
-rw-r--r--fs/f2fs/inline.c482
-rw-r--r--fs/f2fs/inode.c44
-rw-r--r--fs/f2fs/namei.c58
-rw-r--r--fs/f2fs/node.c163
-rw-r--r--fs/f2fs/node.h8
-rw-r--r--fs/f2fs/recovery.c14
-rw-r--r--fs/f2fs/segment.c122
-rw-r--r--fs/f2fs/segment.h8
-rw-r--r--fs/f2fs/super.c29
-rw-r--r--fs/f2fs/xattr.c6
-rw-r--r--fs/f2fs/xattr.h6
-rw-r--r--fs/fat/dir.c5
-rw-r--r--fs/file.c2
-rw-r--r--fs/fuse/dir.c4
-rw-r--r--fs/fuse/file.c2
-rw-r--r--fs/gfs2/dir.c39
-rw-r--r--fs/gfs2/export.c8
-rw-r--r--fs/gfs2/file.c83
-rw-r--r--fs/gfs2/glock.c3
-rw-r--r--fs/gfs2/glops.c26
-rw-r--r--fs/gfs2/glops.h2
-rw-r--r--fs/gfs2/incore.h19
-rw-r--r--fs/gfs2/inode.c72
-rw-r--r--fs/gfs2/log.c42
-rw-r--r--fs/gfs2/main.c11
-rw-r--r--fs/gfs2/ops_fstype.c19
-rw-r--r--fs/gfs2/quota.c9
-rw-r--r--fs/gfs2/rgrp.c69
-rw-r--r--fs/gfs2/rgrp.h1
-rw-r--r--fs/gfs2/super.c112
-rw-r--r--fs/gfs2/super.h1
-rw-r--r--fs/gfs2/trans.c17
-rw-r--r--fs/hfs/catalog.c14
-rw-r--r--fs/hppfs/hppfs.c5
-rw-r--r--fs/inode.c3
-rw-r--r--fs/ioctl.c6
-rw-r--r--fs/jbd/journal.c3
-rw-r--r--fs/jfs/jfs_incore.h3
-rw-r--r--fs/jfs/namei.c18
-rw-r--r--fs/jfs/super.c9
-rw-r--r--fs/kernfs/dir.c2
-rw-r--r--fs/libfs.c12
-rw-r--r--fs/lockd/svclock.c2
-rw-r--r--fs/lockd/svcsubs.c2
-rw-r--r--fs/ncpfs/dir.c12
-rw-r--r--fs/ncpfs/file.c14
-rw-r--r--fs/ncpfs/ioctl.c1
-rw-r--r--fs/ncpfs/mmap.c4
-rw-r--r--fs/ncpfs/ncplib_kernel.h4
-rw-r--r--fs/nfs/blocklayout/blocklayout.c2
-rw-r--r--fs/nfs/blocklayout/rpc_pipefs.c2
-rw-r--r--fs/nfs/callback_proc.c2
-rw-r--r--fs/nfs/dir.c6
-rw-r--r--fs/nfs/filelayout/filelayoutdev.c3
-rw-r--r--fs/nfs/fscache.c24
-rw-r--r--fs/nfs/getroot.c4
-rw-r--r--fs/nfs/inode.c9
-rw-r--r--fs/nfs/iostat.h5
-rw-r--r--fs/nfs/nfs42.h2
-rw-r--r--fs/nfs/nfs42proc.c77
-rw-r--r--fs/nfs/nfs42xdr.c139
-rw-r--r--fs/nfs/nfs4_fs.h1
-rw-r--r--fs/nfs/nfs4client.c46
-rw-r--r--fs/nfs/nfs4file.c31
-rw-r--r--fs/nfs/nfs4proc.c12
-rw-r--r--fs/nfs/nfs4xdr.c12
-rw-r--r--fs/nfs/pagelist.c11
-rw-r--r--fs/nfs/read.c2
-rw-r--r--fs/nfs/write.c19
-rw-r--r--fs/nfsd/nfs4recover.c7
-rw-r--r--fs/nfsd/nfs4xdr.c2
-rw-r--r--fs/nfsd/nfsctl.c37
-rw-r--r--fs/nfsd/vfs.c16
-rw-r--r--fs/nfsd/vfs.h4
-rw-r--r--fs/nilfs2/file.c10
-rw-r--r--fs/nilfs2/inode.c32
-rw-r--r--fs/nilfs2/namei.c15
-rw-r--r--fs/nilfs2/the_nilfs.c3
-rw-r--r--fs/notify/fdinfo.c78
-rw-r--r--fs/notify/fdinfo.h4
-rw-r--r--fs/notify/fsnotify.c4
-rw-r--r--fs/notify/inotify/inotify_user.c9
-rw-r--r--fs/ntfs/namei.c4
-rw-r--r--fs/ocfs2/aops.c2
-rw-r--r--fs/ocfs2/cluster/heartbeat.c4
-rw-r--r--fs/ocfs2/cluster/tcp.c2
-rw-r--r--fs/ocfs2/dcache.c20
-rw-r--r--fs/ocfs2/dir.c10
-rw-r--r--fs/ocfs2/dlm/dlmdomain.c2
-rw-r--r--fs/ocfs2/dlm/dlmmaster.c12
-rw-r--r--fs/ocfs2/dlm/dlmrecovery.c18
-rw-r--r--fs/ocfs2/dlmfs/dlmfs.c4
-rw-r--r--fs/ocfs2/dlmglue.c40
-rw-r--r--fs/ocfs2/file.c4
-rw-r--r--fs/ocfs2/inode.c3
-rw-r--r--fs/ocfs2/inode.h2
-rw-r--r--fs/ocfs2/journal.c8
-rw-r--r--fs/ocfs2/move_extents.c3
-rw-r--r--fs/ocfs2/ocfs2.h6
-rw-r--r--fs/ocfs2/slot_map.c2
-rw-r--r--fs/ocfs2/super.c11
-rw-r--r--fs/ocfs2/xattr.c2
-rw-r--r--fs/open.c4
-rw-r--r--fs/overlayfs/readdir.c8
-rw-r--r--fs/proc/array.c47
-rw-r--r--fs/proc/base.c7
-rw-r--r--fs/proc/fd.c3
-rw-r--r--fs/proc/generic.c163
-rw-r--r--fs/proc/internal.h11
-rw-r--r--fs/proc/proc_net.c1
-rw-r--r--fs/proc/root.c1
-rw-r--r--fs/proc/task_mmu.c107
-rw-r--r--fs/pstore/inode.c22
-rw-r--r--fs/pstore/ram.c22
-rw-r--r--fs/quota/dquot.c59
-rw-r--r--fs/quota/quota.c13
-rw-r--r--fs/readdir.c21
-rw-r--r--fs/reiserfs/reiserfs.h4
-rw-r--r--fs/reiserfs/super.c11
-rw-r--r--fs/reiserfs/xattr.c21
-rw-r--r--fs/seq_file.c15
-rw-r--r--fs/signalfd.c4
-rw-r--r--fs/sync.c2
-rw-r--r--fs/timerfd.c27
-rw-r--r--fs/udf/super.c11
-rw-r--r--fs/xattr.c16
-rw-r--r--fs/xfs/xfs_super.c1
-rw-r--r--include/acpi/acbuffer.h14
-rw-r--r--include/acpi/acpi_bus.h35
-rw-r--r--include/acpi/acpixf.h2
-rw-r--r--include/acpi/actypes.h4
-rw-r--r--include/acpi/processor.h7
-rw-r--r--include/asm-generic/futex.h114
-rw-r--r--include/asm-generic/io.h751
-rw-r--r--include/asm-generic/mm_hooks.h17
-rw-r--r--include/asm-generic/msi.h32
-rw-r--r--include/asm-generic/preempt.h3
-rw-r--r--include/asm-generic/seccomp.h30
-rw-r--r--include/asm-generic/tlb.h57
-rw-r--r--include/dt-bindings/arm/ux500_pm_domains.h15
-rw-r--r--include/dt-bindings/clock/imx5-clock.h5
-rw-r--r--include/dt-bindings/clock/r8a7740-clock.h1
-rw-r--r--include/dt-bindings/clock/r8a7790-clock.h14
-rw-r--r--include/dt-bindings/clock/r8a7791-clock.h11
-rw-r--r--include/dt-bindings/clock/r8a7794-clock.h9
-rw-r--r--include/dt-bindings/clock/stih407-clks.h86
-rw-r--r--include/dt-bindings/clock/stih410-clks.h25
-rw-r--r--include/dt-bindings/clock/tegra114-car.h2
-rw-r--r--include/dt-bindings/clock/tegra124-car.h2
-rw-r--r--include/dt-bindings/clock/tegra20-car.h2
-rw-r--r--include/dt-bindings/memory/tegra114-mc.h25
-rw-r--r--include/dt-bindings/memory/tegra124-mc.h31
-rw-r--r--include/dt-bindings/memory/tegra30-mc.h24
-rw-r--r--include/dt-bindings/pinctrl/qcom,pmic-gpio.h142
-rw-r--r--include/dt-bindings/pinctrl/qcom,pmic-mpp.h44
-rw-r--r--include/dt-bindings/regulator/maxim,max77802.h18
-rw-r--r--include/dt-bindings/reset-controller/stih407-resets.h61
-rw-r--r--include/linux/acpi.h167
-rw-r--r--include/linux/atmel-mci.h2
-rw-r--r--include/linux/audit.h9
-rw-r--r--include/linux/blk-mq.h17
-rw-r--r--include/linux/blkdev.h5
-rw-r--r--include/linux/cgroup.h30
-rw-r--r--include/linux/clk/ti.h15
-rw-r--r--include/linux/compaction.h10
-rw-r--r--include/linux/cpufreq.h54
-rw-r--r--include/linux/cpuidle.h4
-rw-r--r--include/linux/dcache.h9
-rw-r--r--include/linux/debugfs.h7
-rw-r--r--include/linux/device-mapper.h2
-rw-r--r--include/linux/edac.h4
-rw-r--r--include/linux/eeprom_93cx6.h4
-rw-r--r--include/linux/efi.h6
-rw-r--r--include/linux/f2fs_fs.h27
-rw-r--r--include/linux/file.h1
-rw-r--r--include/linux/freezer.h50
-rw-r--r--include/linux/fs.h20
-rw-r--r--include/linux/ftrace.h36
-rw-r--r--include/linux/ftrace_event.h11
-rw-r--r--include/linux/gfp.h4
-rw-r--r--include/linux/gpio/consumer.h7
-rw-r--r--include/linux/gpio_keys.h3
-rw-r--r--include/linux/hugetlb.h3
-rw-r--r--include/linux/hugetlb_cgroup.h1
-rw-r--r--include/linux/i2c/pmbus.h4
-rw-r--r--include/linux/init_task.h12
-rw-r--r--include/linux/iommu.h22
-rw-r--r--include/linux/irq.h65
-rw-r--r--include/linux/irqdomain.h101
-rw-r--r--include/linux/irqhandler.h14
-rw-r--r--include/linux/kern_levels.h13
-rw-r--r--include/linux/kernel.h6
-rw-r--r--include/linux/leds.h3
-rw-r--r--include/linux/libata.h4
-rw-r--r--include/linux/lockd/debug.h6
-rw-r--r--include/linux/mailbox_client.h3
-rw-r--r--include/linux/mbus.h1
-rw-r--r--include/linux/memcontrol.h50
-rw-r--r--include/linux/mfd/abx500/ab8500-sysctrl.h1
-rw-r--r--include/linux/mfd/arizona/core.h1
-rw-r--r--include/linux/mfd/arizona/registers.h50
-rw-r--r--include/linux/mfd/atmel-hlcdc.h85
-rw-r--r--include/linux/mfd/axp20x.h59
-rw-r--r--include/linux/mfd/core.h7
-rw-r--r--include/linux/mfd/davinci_voicecodec.h7
-rw-r--r--include/linux/mfd/dln2.h103
-rw-r--r--include/linux/mfd/max77686.h7
-rw-r--r--include/linux/mfd/max77693-private.h1
-rw-r--r--include/linux/mfd/rtsx_pci.h37
-rw-r--r--include/linux/mfd/samsung/core.h2
-rw-r--r--include/linux/mfd/samsung/s2mps13.h186
-rw-r--r--include/linux/mfd/syscon/imx6q-iomuxc-gpr.h39
-rw-r--r--include/linux/mfd/tc3589x.h8
-rw-r--r--include/linux/mm.h6
-rw-r--r--include/linux/mm_types.h9
-rw-r--r--include/linux/mmc/card.h23
-rw-r--r--include/linux/mmc/core.h3
-rw-r--r--include/linux/mmc/dw_mmc.h7
-rw-r--r--include/linux/mmc/host.h1
-rw-r--r--include/linux/mmc/mmc.h3
-rw-r--r--include/linux/mmc/sdhci.h18
-rw-r--r--include/linux/mmc/sdio_func.h2
-rw-r--r--include/linux/mmzone.h12
-rw-r--r--include/linux/msi.h187
-rw-r--r--include/linux/nfs4.h2
-rw-r--r--include/linux/nfs_fs.h4
-rw-r--r--include/linux/nfs_fs_sb.h2
-rw-r--r--include/linux/nfs_xdr.h14
-rw-r--r--include/linux/of.h169
-rw-r--r--include/linux/of_address.h4
-rw-r--r--include/linux/of_pci.h12
-rw-r--r--include/linux/of_pdt.h3
-rw-r--r--include/linux/of_platform.h6
-rw-r--r--include/linux/omap-gpmc.h199
-rw-r--r--include/linux/omap-mailbox.h16
-rw-r--r--include/linux/page_cgroup.h105
-rw-r--r--include/linux/page_counter.h51
-rw-r--r--include/linux/pci.h2
-rw-r--r--include/linux/pci_hotplug.h1
-rw-r--r--include/linux/pci_ids.h2
-rw-r--r--include/linux/percpu-refcount.h47
-rw-r--r--include/linux/percpu.h4
-rw-r--r--include/linux/perf_event.h37
-rw-r--r--include/linux/platform_data/asoc-s3c.h1
-rw-r--r--include/linux/platform_data/hsmmc-omap.h90
-rw-r--r--include/linux/platform_data/lp855x.h2
-rw-r--r--include/linux/platform_data/mmc-atmel-mci.h (renamed from arch/arm/mach-at91/include/mach/atmel-mci.h)13
-rw-r--r--include/linux/platform_data/mmc-omap.h27
-rw-r--r--include/linux/platform_data/pxa_sdhci.h5
-rw-r--r--include/linux/platform_data/serial-omap.h3
-rw-r--r--include/linux/pm.h19
-rw-r--r--include/linux/pm_clock.h8
-rw-r--r--include/linux/pm_domain.h17
-rw-r--r--include/linux/pm_opp.h12
-rw-r--r--include/linux/pm_qos.h38
-rw-r--r--include/linux/pm_runtime.h21
-rw-r--r--include/linux/printk.h3
-rw-r--r--include/linux/property.h143
-rw-r--r--include/linux/ptrace.h2
-rw-r--r--include/linux/pxa2xx_ssp.h20
-rw-r--r--include/linux/quota.h5
-rw-r--r--include/linux/quotaops.h8
-rw-r--r--include/linux/rcupdate.h19
-rw-r--r--include/linux/rcutiny.h2
-rw-r--r--include/linux/rcutree.h6
-rw-r--r--include/linux/regmap.h7
-rw-r--r--include/linux/regulator/consumer.h6
-rw-r--r--include/linux/regulator/driver.h8
-rw-r--r--include/linux/regulator/of_regulator.h9
-rw-r--r--include/linux/res_counter.h223
-rw-r--r--include/linux/reset-controller.h2
-rw-r--r--include/linux/reset.h7
-rw-r--r--include/linux/rtc.h21
-rw-r--r--include/linux/sched.h91
-rw-r--r--include/linux/seq_buf.h136
-rw-r--r--include/linux/seq_file.h15
-rw-r--r--include/linux/slab.h4
-rw-r--r--include/linux/spi/spi.h6
-rw-r--r--include/linux/sunrpc/auth.h2
-rw-r--r--include/linux/sunrpc/clnt.h4
-rw-r--r--include/linux/sunrpc/debug.h64
-rw-r--r--include/linux/sunrpc/metrics.h3
-rw-r--r--include/linux/sunrpc/sched.h8
-rw-r--r--include/linux/sunrpc/xprt.h3
-rw-r--r--include/linux/sunrpc/xprtsock.h59
-rw-r--r--include/linux/swap_cgroup.h42
-rw-r--r--include/linux/syslog.h9
-rw-r--r--include/linux/time.h17
-rw-r--r--include/linux/timekeeper_internal.h2
-rw-r--r--include/linux/timekeeping.h51
-rw-r--r--include/linux/trace_seq.h77
-rw-r--r--include/linux/usb.h2
-rw-r--r--include/linux/usb/hcd.h7
-rw-r--r--include/linux/vexpress.h19
-rw-r--r--include/linux/virtio.h12
-rw-r--r--include/linux/virtio_byteorder.h59
-rw-r--r--include/linux/virtio_config.h103
-rw-r--r--include/linux/wait.h80
-rw-r--r--include/media/davinci/vpbe.h2
-rw-r--r--include/media/davinci/vpbe_display.h21
-rw-r--r--include/media/davinci/vpbe_venc.h5
-rw-r--r--include/media/exynos-fimc.h2
-rw-r--r--include/media/lirc_dev.h8
-rw-r--r--include/media/radio-si4713.h30
-rw-r--r--include/media/si4713.h4
-rw-r--r--include/media/soc_camera.h2
-rw-r--r--include/media/soc_mediabus.h6
-rw-r--r--include/media/v4l2-common.h17
-rw-r--r--include/media/v4l2-ctrls.h25
-rw-r--r--include/media/v4l2-image-sizes.h9
-rw-r--r--include/media/v4l2-mediabus.h6
-rw-r--r--include/media/v4l2-subdev.h2
-rw-r--r--include/media/videobuf2-core.h42
-rw-r--r--include/media/videobuf2-dma-sg.h3
-rw-r--r--include/net/netfilter/nf_conntrack_core.h2
-rw-r--r--include/net/netfilter/nf_conntrack_l3proto.h4
-rw-r--r--include/net/netfilter/nf_conntrack_l4proto.h6
-rw-r--r--include/net/sock.h27
-rw-r--r--include/scsi/libfc.h2
-rw-r--r--include/scsi/libiscsi.h2
-rw-r--r--include/scsi/libsas.h17
-rw-r--r--include/scsi/scsi.h12
-rw-r--r--include/scsi/scsi_cmnd.h6
-rw-r--r--include/scsi/scsi_dbg.h28
-rw-r--r--include/scsi/scsi_device.h21
-rw-r--r--include/scsi/scsi_driver.h1
-rw-r--r--include/scsi/scsi_eh.h24
-rw-r--r--include/scsi/scsi_host.h39
-rw-r--r--include/scsi/scsi_ioctl.h4
-rw-r--r--include/scsi/scsi_tcq.h87
-rw-r--r--include/scsi/scsi_transport_spi.h1
-rw-r--r--include/scsi/sg.h5
-rw-r--r--include/soc/at91/at91rm9200_sdramc.h (renamed from arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h)0
-rw-r--r--include/soc/at91/at91sam9_ddrsdr.h (renamed from arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h)0
-rw-r--r--include/soc/at91/at91sam9_sdramc.h (renamed from arch/arm/mach-at91/include/mach/at91sam9_sdramc.h)0
-rw-r--r--include/soc/tegra/mc.h107
-rw-r--r--include/sound/compress_driver.h5
-rw-r--r--include/sound/jack.h26
-rw-r--r--include/sound/omap-hdmi-audio.h43
-rw-r--r--include/sound/pcm.h254
-rw-r--r--include/sound/rcar_snd.h8
-rw-r--r--include/sound/rt5645.h4
-rw-r--r--include/sound/rt5677.h10
-rw-r--r--include/sound/seq_kernel.h4
-rw-r--r--include/sound/soc-dai.h7
-rw-r--r--include/sound/soc-dapm.h9
-rw-r--r--include/sound/soc.h116
-rw-r--r--include/sound/uda134x.h12
-rw-r--r--include/trace/events/asoc.h25
-rw-r--r--include/trace/events/rcu.h4
-rw-r--r--include/trace/events/sched.h9
-rw-r--r--include/trace/events/scsi.h2
-rw-r--r--include/trace/events/sunrpc.h160
-rw-r--r--include/trace/events/target.h2
-rw-r--r--include/trace/ftrace.h8
-rw-r--r--include/uapi/asm-generic/siginfo.h9
-rw-r--r--include/uapi/linux/Kbuild3
-rw-r--r--include/uapi/linux/dlmconstants.h2
-rw-r--r--include/uapi/linux/dm-ioctl.h9
-rw-r--r--include/uapi/linux/elf-em.h1
-rw-r--r--include/uapi/linux/elf.h1
-rw-r--r--include/uapi/linux/if_tun.h17
-rw-r--r--include/uapi/linux/media-bus-format.h125
-rw-r--r--include/uapi/linux/nfsd/debug.h2
-rw-r--r--include/uapi/linux/perf_event.h15
-rw-r--r--include/uapi/linux/prctl.h6
-rw-r--r--include/uapi/linux/sched.h4
-rw-r--r--include/uapi/linux/sysctl.h1
-rw-r--r--include/uapi/linux/v4l2-common.h2
-rw-r--r--include/uapi/linux/v4l2-mediabus.h219
-rw-r--r--include/uapi/linux/v4l2-subdev.h6
-rw-r--r--include/uapi/linux/videodev2.h101
-rw-r--r--include/uapi/linux/virtio_blk.h15
-rw-r--r--include/uapi/linux/virtio_config.h9
-rw-r--r--include/uapi/linux/virtio_console.h7
-rw-r--r--include/uapi/linux/virtio_net.h15
-rw-r--r--include/uapi/linux/virtio_ring.h45
-rw-r--r--include/uapi/linux/virtio_scsi.h (renamed from include/linux/virtio_scsi.h)106
-rw-r--r--include/uapi/linux/virtio_types.h46
-rw-r--r--include/uapi/sound/asound.h3
-rw-r--r--include/uapi/sound/compress_offload.h17
-rw-r--r--include/uapi/sound/firewire.h3
-rw-r--r--include/uapi/sound/hdspm.h12
-rw-r--r--include/video/omapdss.h45
-rw-r--r--init/Kconfig105
-rw-r--r--init/main.c14
-rw-r--r--ipc/mqueue.c4
-rw-r--r--kernel/Makefile1
-rw-r--r--kernel/audit.c11
-rw-r--r--kernel/auditsc.c7
-rw-r--r--kernel/cpu.c19
-rw-r--r--kernel/cpuset.c23
-rw-r--r--kernel/events/core.c62
-rw-r--r--kernel/exit.c248
-rw-r--r--kernel/extable.c7
-rw-r--r--kernel/fork.c5
-rw-r--r--kernel/irq/Kconfig15
-rw-r--r--kernel/irq/Makefile1
-rw-r--r--kernel/irq/chip.c130
-rw-r--r--kernel/irq/generic-chip.c36
-rw-r--r--kernel/irq/irqdomain.c567
-rw-r--r--kernel/irq/manage.c2
-rw-r--r--kernel/irq/msi.c330
-rw-r--r--kernel/kmod.c43
-rw-r--r--kernel/kprobes.c2
-rw-r--r--kernel/locking/mutex.c8
-rw-r--r--kernel/module.c30
-rw-r--r--kernel/panic.c13
-rw-r--r--kernel/pid.c2
-rw-r--r--kernel/pid_namespace.c28
-rw-r--r--kernel/power/Kconfig7
-rw-r--r--kernel/power/hibernate.c14
-rw-r--r--kernel/power/power.h3
-rw-r--r--kernel/power/snapshot.c9
-rw-r--r--kernel/power/swap.c43
-rw-r--r--kernel/printk/printk.c90
-rw-r--r--kernel/ptrace.c23
-rw-r--r--kernel/rcu/Makefile2
-rw-r--r--kernel/rcu/rcu.h2
-rw-r--r--kernel/rcu/rcutorture.c1
-rw-r--r--kernel/rcu/tiny.c6
-rw-r--r--kernel/rcu/tree.c97
-rw-r--r--kernel/rcu/tree.h22
-rw-r--r--kernel/rcu/tree_plugin.h111
-rw-r--r--kernel/rcu/update.c89
-rw-r--r--kernel/res_counter.c211
-rw-r--r--kernel/sched/completion.c5
-rw-r--r--kernel/sched/core.c247
-rw-r--r--kernel/sched/cpudeadline.h3
-rw-r--r--kernel/sched/cpupri.h3
-rw-r--r--kernel/sched/deadline.c99
-rw-r--r--kernel/sched/debug.c11
-rw-r--r--kernel/sched/fair.c354
-rw-r--r--kernel/sched/rt.c17
-rw-r--r--kernel/sched/sched.h43
-rw-r--r--kernel/sched/wait.c66
-rw-r--r--kernel/signal.c46
-rw-r--r--kernel/smpboot.c15
-rw-r--r--kernel/softirq.c2
-rw-r--r--kernel/sys.c12
-rw-r--r--kernel/sysctl.c9
-rw-r--r--kernel/sysctl_binary.c1
-rw-r--r--kernel/taskstats.c2
-rw-r--r--kernel/time/Makefile2
-rw-r--r--kernel/time/test_udelay.c (renamed from kernel/time/udelay_test.c)0
-rw-r--r--kernel/time/tick-sched.c2
-rw-r--r--kernel/time/time.c20
-rw-r--r--kernel/time/timekeeping.c127
-rw-r--r--kernel/time/timer.c3
-rw-r--r--kernel/trace/blktrace.c148
-rw-r--r--kernel/trace/ftrace.c330
-rw-r--r--kernel/trace/ring_buffer.c75
-rw-r--r--kernel/trace/trace.c228
-rw-r--r--kernel/trace/trace.h17
-rw-r--r--kernel/trace/trace_branch.c47
-rw-r--r--kernel/trace/trace_events.c15
-rw-r--r--kernel/trace/trace_events_filter.c29
-rw-r--r--kernel/trace/trace_events_trigger.c6
-rw-r--r--kernel/trace/trace_functions.c119
-rw-r--r--kernel/trace/trace_functions_graph.c423
-rw-r--r--kernel/trace/trace_kdb.c21
-rw-r--r--kernel/trace/trace_kprobe.c46
-rw-r--r--kernel/trace/trace_mmiotrace.c52
-rw-r--r--kernel/trace/trace_output.c446
-rw-r--r--kernel/trace/trace_output.h16
-rw-r--r--kernel/trace/trace_printk.c2
-rw-r--r--kernel/trace/trace_probe.c10
-rw-r--r--kernel/trace/trace_sched_switch.c144
-rw-r--r--kernel/trace/trace_sched_wakeup.c56
-rw-r--r--kernel/trace/trace_seq.c253
-rw-r--r--kernel/trace/trace_syscalls.c47
-rw-r--r--kernel/trace/trace_uprobe.c28
-rw-r--r--lib/Kconfig.debug14
-rw-r--r--lib/Makefile2
-rw-r--r--lib/dma-debug.c43
-rw-r--r--lib/dynamic_debug.c4
-rw-r--r--lib/lcm.c8
-rw-r--r--lib/seq_buf.c359
-rw-r--r--mm/Makefile4
-rw-r--r--mm/cma.c14
-rw-r--r--mm/compaction.c139
-rw-r--r--mm/debug.c5
-rw-r--r--mm/frontswap.c2
-rw-r--r--mm/huge_memory.c1
-rw-r--r--mm/hugetlb.c4
-rw-r--r--mm/hugetlb_cgroup.c103
-rw-r--r--mm/internal.h7
-rw-r--r--mm/memcontrol.c1710
-rw-r--r--mm/memory-failure.c6
-rw-r--r--mm/memory.c30
-rw-r--r--mm/memory_hotplug.c4
-rw-r--r--mm/mmap.c2
-rw-r--r--mm/oom_kill.c4
-rw-r--r--mm/page-writeback.c4
-rw-r--r--mm/page_alloc.c137
-rw-r--r--mm/page_cgroup.c530
-rw-r--r--mm/page_counter.c192
-rw-r--r--mm/page_isolation.c2
-rw-r--r--mm/rmap.c4
-rw-r--r--mm/slab.c23
-rw-r--r--mm/slab.h8
-rw-r--r--mm/slab_common.c40
-rw-r--r--mm/slub.c21
-rw-r--r--mm/swap_cgroup.c208
-rw-r--r--mm/swap_state.c1
-rw-r--r--mm/swapfile.c2
-rw-r--r--mm/vmalloc.c3
-rw-r--r--mm/vmscan.c18
-rw-r--r--net/bluetooth/rfcomm/core.c18
-rw-r--r--net/core/dev.c10
-rw-r--r--net/core/rtnetlink.c10
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c6
-rw-r--r--net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c53
-rw-r--r--net/ipv4/netfilter/nf_conntrack_proto_icmp.c10
-rw-r--r--net/ipv4/tcp_memcontrol.c87
-rw-r--r--net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c6
-rw-r--r--net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c10
-rw-r--r--net/netfilter/nf_conntrack_l3proto_generic.c5
-rw-r--r--net/netfilter/nf_conntrack_proto_dccp.c14
-rw-r--r--net/netfilter/nf_conntrack_proto_generic.c5
-rw-r--r--net/netfilter/nf_conntrack_proto_gre.c18
-rw-r--r--net/netfilter/nf_conntrack_proto_sctp.c14
-rw-r--r--net/netfilter/nf_conntrack_proto_tcp.c14
-rw-r--r--net/netfilter/nf_conntrack_proto_udp.c10
-rw-r--r--net/netfilter/nf_conntrack_proto_udplite.c10
-rw-r--r--net/netfilter/nf_conntrack_standalone.c77
-rw-r--r--net/netfilter/nf_log.c30
-rw-r--r--net/netfilter/nfnetlink_queue_core.c13
-rw-r--r--net/netfilter/x_tables.c19
-rw-r--r--net/netfilter/xt_hashlimit.c36
-rw-r--r--net/packet/af_packet.c35
-rw-r--r--net/rfkill/rfkill-gpio.c18
-rw-r--r--net/sunrpc/Kconfig1
-rw-r--r--net/sunrpc/Makefile1
-rw-r--r--net/sunrpc/auth.c4
-rw-r--r--net/sunrpc/auth_generic.c2
-rw-r--r--net/sunrpc/auth_gss/auth_gss.c2
-rw-r--r--net/sunrpc/auth_gss/gss_generic_token.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_crypto.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_keys.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_mech.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seal.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_seqnum.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_unseal.c2
-rw-r--r--net/sunrpc/auth_gss/gss_krb5_wrap.c2
-rw-r--r--net/sunrpc/auth_gss/gss_mech_switch.c2
-rw-r--r--net/sunrpc/auth_gss/gss_rpc_xdr.h2
-rw-r--r--net/sunrpc/auth_gss/svcauth_gss.c2
-rw-r--r--net/sunrpc/auth_null.c4
-rw-r--r--net/sunrpc/auth_unix.c2
-rw-r--r--net/sunrpc/backchannel_rqst.c2
-rw-r--r--net/sunrpc/clnt.c16
-rw-r--r--net/sunrpc/debugfs.c292
-rw-r--r--net/sunrpc/rpcb_clnt.c2
-rw-r--r--net/sunrpc/sched.c4
-rw-r--r--net/sunrpc/stats.c21
-rw-r--r--net/sunrpc/sunrpc_syms.c12
-rw-r--r--net/sunrpc/svc.c23
-rw-r--r--net/sunrpc/svc_xprt.c31
-rw-r--r--net/sunrpc/sysctl.c2
-rw-r--r--net/sunrpc/xprt.c19
-rw-r--r--net/sunrpc/xprtrdma/rpc_rdma.c4
-rw-r--r--net/sunrpc/xprtrdma/transport.c12
-rw-r--r--net/sunrpc/xprtrdma/verbs.c122
-rw-r--r--net/sunrpc/xprtrdma/xprt_rdma.h6
-rw-r--r--net/sunrpc/xprtsock.c77
-rw-r--r--scripts/Kbuild.include6
-rw-r--r--scripts/Makefile.dtbinst51
-rw-r--r--scripts/Makefile.lib12
-rwxr-xr-xscripts/checkpatch.pl263
-rwxr-xr-xscripts/kernel-doc2
-rw-r--r--security/commoncap.c2
-rw-r--r--security/integrity/ima/ima_api.c4
-rw-r--r--security/integrity/ima/ima_appraise.c4
-rw-r--r--security/integrity/ima/ima_template_lib.c2
-rw-r--r--security/selinux/selinuxfs.c6
-rw-r--r--security/smack/smack_lsm.c8
-rw-r--r--sound/aoa/codecs/onyx.c8
-rw-r--r--sound/aoa/codecs/tas.c10
-rw-r--r--sound/aoa/soundbus/i2sbus/core.c6
-rw-r--r--sound/arm/pxa2xx-pcm-lib.c4
-rw-r--r--sound/atmel/abdac.c18
-rw-r--r--sound/atmel/ac97c.c12
-rw-r--r--sound/core/Makefile3
-rw-r--r--sound/core/control.c71
-rw-r--r--sound/core/init.c33
-rw-r--r--sound/core/pcm.c48
-rw-r--r--sound/core/pcm_lib.c148
-rw-r--r--sound/core/pcm_native.c214
-rw-r--r--sound/core/pcm_trace.h110
-rw-r--r--sound/core/seq/oss/seq_oss_init.c9
-rw-r--r--sound/core/seq/seq.c5
-rw-r--r--sound/core/seq/seq_device.c103
-rw-r--r--sound/core/sgbuf.c3
-rw-r--r--sound/core/sound.c9
-rw-r--r--sound/drivers/mts64.c18
-rw-r--r--sound/drivers/virmidi.c21
-rw-r--r--sound/drivers/vx/vx_core.c10
-rw-r--r--sound/drivers/vx/vx_mixer.c35
-rw-r--r--sound/firewire/Kconfig26
-rw-r--r--sound/firewire/Makefile7
-rw-r--r--sound/firewire/amdtp.c8
-rw-r--r--sound/firewire/amdtp.h24
-rw-r--r--sound/firewire/bebob/bebob.h4
-rw-r--r--sound/firewire/bebob/bebob_focusrite.c10
-rw-r--r--sound/firewire/bebob/bebob_maudio.c59
-rw-r--r--sound/firewire/bebob/bebob_terratec.c4
-rw-r--r--sound/firewire/bebob/bebob_yamaha.c2
-rw-r--r--sound/firewire/cmp.c2
-rw-r--r--sound/firewire/dice.c1511
-rw-r--r--sound/firewire/dice/Makefile3
-rw-r--r--sound/firewire/dice/dice-hwdep.c190
-rw-r--r--sound/firewire/dice/dice-interface.h (renamed from sound/firewire/dice-interface.h)0
-rw-r--r--sound/firewire/dice/dice-midi.c157
-rw-r--r--sound/firewire/dice/dice-pcm.c422
-rw-r--r--sound/firewire/dice/dice-proc.c252
-rw-r--r--sound/firewire/dice/dice-stream.c407
-rw-r--r--sound/firewire/dice/dice-transaction.c382
-rw-r--r--sound/firewire/dice/dice.c361
-rw-r--r--sound/firewire/dice/dice.h189
-rw-r--r--sound/firewire/isight.c10
-rw-r--r--sound/firewire/oxfw/Makefile3
-rw-r--r--sound/firewire/oxfw/oxfw-command.c153
-rw-r--r--sound/firewire/oxfw/oxfw-control.c283
-rw-r--r--sound/firewire/oxfw/oxfw-hwdep.c190
-rw-r--r--sound/firewire/oxfw/oxfw-midi.c207
-rw-r--r--sound/firewire/oxfw/oxfw-pcm.c424
-rw-r--r--sound/firewire/oxfw/oxfw-proc.c113
-rw-r--r--sound/firewire/oxfw/oxfw-stream.c685
-rw-r--r--sound/firewire/oxfw/oxfw.c317
-rw-r--r--sound/firewire/oxfw/oxfw.h146
-rw-r--r--sound/firewire/speakers.c792
-rw-r--r--sound/i2c/other/ak4xxx-adda.c26
-rw-r--r--sound/isa/ad1816a/ad1816a_lib.c10
-rw-r--r--sound/isa/es1688/es1688_lib.c13
-rw-r--r--sound/isa/es18xx.c78
-rw-r--r--sound/isa/msnd/msnd_pinnacle_mixer.c11
-rw-r--r--sound/isa/sb/emu8000_synth.c3
-rw-r--r--sound/isa/sb/sb16_main.c10
-rw-r--r--sound/isa/sb/sb_common.c3
-rw-r--r--sound/isa/sb/sb_mixer.c31
-rw-r--r--sound/isa/wss/wss_lib.c16
-rw-r--r--sound/mips/sgio2audio.c11
-rw-r--r--sound/oss/uart401.c11
-rw-r--r--sound/parisc/harmony.c12
-rw-r--r--sound/pci/ac97/ac97_codec.c10
-rw-r--r--sound/pci/ac97/ac97_patch.c198
-rw-r--r--sound/pci/ac97/ac97_patch.h2
-rw-r--r--sound/pci/asihpi/asihpi.c377
-rw-r--r--sound/pci/asihpi/hpi.h16
-rw-r--r--sound/pci/asihpi/hpi6205.c43
-rw-r--r--sound/pci/asihpi/hpi_internal.h20
-rw-r--r--sound/pci/asihpi/hpicmn.c107
-rw-r--r--sound/pci/asihpi/hpicmn.h19
-rw-r--r--sound/pci/asihpi/hpimsginit.c30
-rw-r--r--sound/pci/asihpi/hpimsgx.c15
-rw-r--r--sound/pci/asihpi/hpioctl.c126
-rw-r--r--sound/pci/asihpi/hpios.h8
-rw-r--r--sound/pci/atiixp.c4
-rw-r--r--sound/pci/atiixp_modem.c4
-rw-r--r--sound/pci/au88x0/au88x0.c35
-rw-r--r--sound/pci/au88x0/au88x0.h4
-rw-r--r--sound/pci/au88x0/au88x0_a3d.c21
-rw-r--r--sound/pci/au88x0/au88x0_core.c102
-rw-r--r--sound/pci/au88x0/au88x0_eq.c3
-rw-r--r--sound/pci/au88x0/au88x0_game.c3
-rw-r--r--sound/pci/au88x0/au88x0_mpu401.c2
-rw-r--r--sound/pci/au88x0/au88x0_pcm.c8
-rw-r--r--sound/pci/au88x0/au88x0_synth.c17
-rw-r--r--sound/pci/aw2/aw2-alsa.c13
-rw-r--r--sound/pci/azt3328.c13
-rw-r--r--sound/pci/ca0106/ca0106_mixer.c40
-rw-r--r--sound/pci/ctxfi/ctatc.c10
-rw-r--r--sound/pci/ctxfi/ctdaio.c30
-rw-r--r--sound/pci/ctxfi/cttimer.c4
-rw-r--r--sound/pci/echoaudio/darla20_dsp.c5
-rw-r--r--sound/pci/echoaudio/darla24_dsp.c13
-rw-r--r--sound/pci/echoaudio/echo3g_dsp.c5
-rw-r--r--sound/pci/echoaudio/echoaudio.c145
-rw-r--r--sound/pci/echoaudio/echoaudio.h31
-rw-r--r--sound/pci/echoaudio/echoaudio_3g.c27
-rw-r--r--sound/pci/echoaudio/echoaudio_dsp.c109
-rw-r--r--sound/pci/echoaudio/echoaudio_gml.c11
-rw-r--r--sound/pci/echoaudio/gina20_dsp.c9
-rw-r--r--sound/pci/echoaudio/gina24_dsp.c30
-rw-r--r--sound/pci/echoaudio/indigo_dsp.c11
-rw-r--r--sound/pci/echoaudio/indigo_express_dsp.c6
-rw-r--r--sound/pci/echoaudio/indigodj_dsp.c11
-rw-r--r--sound/pci/echoaudio/indigodjx_dsp.c5
-rw-r--r--sound/pci/echoaudio/indigoio_dsp.c8
-rw-r--r--sound/pci/echoaudio/indigoiox_dsp.c5
-rw-r--r--sound/pci/echoaudio/layla20_dsp.c28
-rw-r--r--sound/pci/echoaudio/layla24_dsp.c26
-rw-r--r--sound/pci/echoaudio/mia_dsp.c15
-rw-r--r--sound/pci/echoaudio/midi.c23
-rw-r--r--sound/pci/echoaudio/mona_dsp.c29
-rw-r--r--sound/pci/emu10k1/emu10k1_main.c9
-rw-r--r--sound/pci/emu10k1/emu10k1x.c2
-rw-r--r--sound/pci/emu10k1/emufx.c3
-rw-r--r--sound/pci/emu10k1/emumixer.c58
-rw-r--r--sound/pci/emu10k1/p16v.c20
-rw-r--r--sound/pci/es1938.c10
-rw-r--r--sound/pci/es1968.c15
-rw-r--r--sound/pci/fm801.c10
-rw-r--r--sound/pci/hda/hda_auto_parser.c66
-rw-r--r--sound/pci/hda/hda_beep.c38
-rw-r--r--sound/pci/hda/hda_codec.c298
-rw-r--r--sound/pci/hda/hda_eld.c2
-rw-r--r--sound/pci/hda/hda_generic.c181
-rw-r--r--sound/pci/hda/hda_intel.c150
-rw-r--r--sound/pci/hda/hda_jack.c60
-rw-r--r--sound/pci/hda/hda_jack.h5
-rw-r--r--sound/pci/hda/hda_priv.h16
-rw-r--r--sound/pci/hda/hda_sysfs.c35
-rw-r--r--sound/pci/hda/patch_analog.c2
-rw-r--r--sound/pci/hda/patch_ca0132.c11
-rw-r--r--sound/pci/hda/patch_realtek.c111
-rw-r--r--sound/pci/ice1712/aureon.c46
-rw-r--r--sound/pci/ice1712/ews.c16
-rw-r--r--sound/pci/ice1712/hoontech.c6
-rw-r--r--sound/pci/ice1712/ice1712.c52
-rw-r--r--sound/pci/ice1712/ice1724.c18
-rw-r--r--sound/pci/ice1712/juli.c5
-rw-r--r--sound/pci/ice1712/maya44.c20
-rw-r--r--sound/pci/ice1712/phase.c12
-rw-r--r--sound/pci/ice1712/pontis.c8
-rw-r--r--sound/pci/ice1712/prodigy192.c22
-rw-r--r--sound/pci/ice1712/prodigy_hifi.c11
-rw-r--r--sound/pci/ice1712/quartet.c32
-rw-r--r--sound/pci/ice1712/revo.c4
-rw-r--r--sound/pci/ice1712/se.c9
-rw-r--r--sound/pci/korg1212/korg1212.c26
-rw-r--r--sound/pci/lola/lola.c2
-rw-r--r--sound/pci/lola/lola_mixer.c3
-rw-r--r--sound/pci/lx6464es/lx_defs.h2
-rw-r--r--sound/pci/mixart/mixart_hwdep.c9
-rw-r--r--sound/pci/pcxhr/pcxhr.c54
-rw-r--r--sound/pci/pcxhr/pcxhr_core.c10
-rw-r--r--sound/pci/pcxhr/pcxhr_mixer.c18
-rw-r--r--sound/pci/rme32.c34
-rw-r--r--sound/pci/rme96.c62
-rw-r--r--sound/pci/rme9652/hdsp.c178
-rw-r--r--sound/pci/rme9652/hdspm.c84
-rw-r--r--sound/pci/rme9652/rme9652.c58
-rw-r--r--sound/pci/sonicvibes.c10
-rw-r--r--sound/pci/trident/trident_main.c3
-rw-r--r--sound/pci/via82xx.c10
-rw-r--r--sound/pci/vx222/vx222_ops.c5
-rw-r--r--sound/pcmcia/vx/vxpocket.c1
-rw-r--r--sound/ppc/pmac.c3
-rw-r--r--sound/ppc/tumbler.c11
-rw-r--r--sound/soc/Makefile6
-rw-r--r--sound/soc/atmel/Kconfig9
-rw-r--r--sound/soc/atmel/Makefile1
-rw-r--r--sound/soc/atmel/atmel-pcm-dma.c4
-rw-r--r--sound/soc/atmel/atmel_ssc_dai.c5
-rw-r--r--sound/soc/atmel/snd-soc-afeb9260.c151
-rw-r--r--sound/soc/au1x/ac97c.c2
-rw-r--r--sound/soc/au1x/psc-ac97.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ac97.c2
-rw-r--r--sound/soc/blackfin/bf5xx-ad1980.c2
-rw-r--r--sound/soc/cirrus/Kconfig3
-rw-r--r--sound/soc/cirrus/ep93xx-ac97.c2
-rw-r--r--sound/soc/codecs/Kconfig47
-rw-r--r--sound/soc/codecs/Makefile10
-rw-r--r--sound/soc/codecs/ab8500-codec.c32
-rw-r--r--sound/soc/codecs/ac97.c18
-rw-r--r--sound/soc/codecs/ad193x.c14
-rw-r--r--sound/soc/codecs/ad1980.c212
-rw-r--r--sound/soc/codecs/ad1980.h26
-rw-r--r--sound/soc/codecs/adau1373.c6
-rw-r--r--sound/soc/codecs/adau1701.c86
-rw-r--r--sound/soc/codecs/adau1761.c25
-rw-r--r--sound/soc/codecs/adau1781.c33
-rw-r--r--sound/soc/codecs/adau17x1.c71
-rw-r--r--sound/soc/codecs/adau17x1.h10
-rw-r--r--sound/soc/codecs/adav80x.c4
-rw-r--r--sound/soc/codecs/ak4535.c31
-rw-r--r--sound/soc/codecs/ak4641.c33
-rw-r--r--sound/soc/codecs/ak4642.c16
-rw-r--r--sound/soc/codecs/ak4671.c13
-rw-r--r--sound/soc/codecs/alc5623.c22
-rw-r--r--sound/soc/codecs/alc5632.c22
-rw-r--r--sound/soc/codecs/arizona.c34
-rw-r--r--sound/soc/codecs/cq93vc.c33
-rw-r--r--sound/soc/codecs/cs4265.c2
-rw-r--r--sound/soc/codecs/cs4271-i2c.c62
-rw-r--r--sound/soc/codecs/cs4271-spi.c55
-rw-r--r--sound/soc/codecs/cs4271.c155
-rw-r--r--sound/soc/codecs/cs4271.h11
-rw-r--r--sound/soc/codecs/cs42l51.c6
-rw-r--r--sound/soc/codecs/cs42l73.c6
-rw-r--r--sound/soc/codecs/hdmi.c2
-rw-r--r--sound/soc/codecs/lm49453.c8
-rw-r--r--sound/soc/codecs/max98088.c31
-rw-r--r--sound/soc/codecs/max98090.c201
-rw-r--r--sound/soc/codecs/max98090.h8
-rw-r--r--sound/soc/codecs/max98095.c23
-rw-r--r--sound/soc/codecs/max9850.c22
-rw-r--r--sound/soc/codecs/rt286.c231
-rw-r--r--sound/soc/codecs/rt5631.c38
-rw-r--r--sound/soc/codecs/rt5645.c200
-rw-r--r--sound/soc/codecs/rt5645.h19
-rw-r--r--sound/soc/codecs/rt5670.c136
-rw-r--r--sound/soc/codecs/rt5670.h6
-rw-r--r--sound/soc/codecs/rt5677-spi.c130
-rw-r--r--sound/soc/codecs/rt5677-spi.h21
-rw-r--r--sound/soc/codecs/rt5677.c1198
-rw-r--r--sound/soc/codecs/rt5677.h162
-rw-r--r--sound/soc/codecs/sgtl5000.c111
-rw-r--r--sound/soc/codecs/sigmadsp-i2c.c81
-rw-r--r--sound/soc/codecs/sigmadsp-regmap.c46
-rw-r--r--sound/soc/codecs/sigmadsp.c711
-rw-r--r--sound/soc/codecs/sigmadsp.h59
-rw-r--r--sound/soc/codecs/sirf-audio-codec.c6
-rw-r--r--sound/soc/codecs/sn95031.c15
-rw-r--r--sound/soc/codecs/ssm4567.c128
-rw-r--r--sound/soc/codecs/sta32x.c21
-rw-r--r--sound/soc/codecs/sta350.c21
-rw-r--r--sound/soc/codecs/sta529.c35
-rw-r--r--sound/soc/codecs/stac9766.c60
-rw-r--r--sound/soc/codecs/tas2552.c10
-rw-r--r--sound/soc/codecs/tfa9879.c328
-rw-r--r--sound/soc/codecs/tfa9879.h202
-rw-r--r--sound/soc/codecs/tlv320aic23.c21
-rw-r--r--sound/soc/codecs/tlv320aic31xx.c31
-rw-r--r--sound/soc/codecs/tlv320aic32x4.c24
-rw-r--r--sound/soc/codecs/tlv320aic3x.c228
-rw-r--r--sound/soc/codecs/tlv320aic3x.h1
-rw-r--r--sound/soc/codecs/tlv320dac33.c2
-rw-r--r--sound/soc/codecs/ts3a227e.c314
-rw-r--r--sound/soc/codecs/ts3a227e.h17
-rw-r--r--sound/soc/codecs/twl4030.c2
-rw-r--r--sound/soc/codecs/twl6040.c23
-rw-r--r--sound/soc/codecs/uda134x.c32
-rw-r--r--sound/soc/codecs/uda1380.c20
-rw-r--r--sound/soc/codecs/wl1273.c10
-rw-r--r--sound/soc/codecs/wm5102.c18
-rw-r--r--sound/soc/codecs/wm8350.c21
-rw-r--r--sound/soc/codecs/wm8400.c34
-rw-r--r--sound/soc/codecs/wm8510.c26
-rw-r--r--sound/soc/codecs/wm8523.c29
-rw-r--r--sound/soc/codecs/wm8580.c4
-rw-r--r--sound/soc/codecs/wm8711.c27
-rw-r--r--sound/soc/codecs/wm8728.c34
-rw-r--r--sound/soc/codecs/wm8731.c37
-rw-r--r--sound/soc/codecs/wm8737.c49
-rw-r--r--sound/soc/codecs/wm8750.c25
-rw-r--r--sound/soc/codecs/wm8776.c31
-rw-r--r--sound/soc/codecs/wm8804.c3
-rw-r--r--sound/soc/codecs/wm8900.c8
-rw-r--r--sound/soc/codecs/wm8903.c43
-rw-r--r--sound/soc/codecs/wm8940.c22
-rw-r--r--sound/soc/codecs/wm8955.c33
-rw-r--r--sound/soc/codecs/wm8958-dsp2.c12
-rw-r--r--sound/soc/codecs/wm8960.c113
-rw-r--r--sound/soc/codecs/wm8961.c34
-rw-r--r--sound/soc/codecs/wm8962.c11
-rw-r--r--sound/soc/codecs/wm8974.c25
-rw-r--r--sound/soc/codecs/wm8978.c10
-rw-r--r--sound/soc/codecs/wm8983.c27
-rw-r--r--sound/soc/codecs/wm8985.c28
-rw-r--r--sound/soc/codecs/wm8988.c27
-rw-r--r--sound/soc/codecs/wm8990.c24
-rw-r--r--sound/soc/codecs/wm8991.c32
-rw-r--r--sound/soc/codecs/wm8993.c12
-rw-r--r--sound/soc/codecs/wm8994.c4
-rw-r--r--sound/soc/codecs/wm8994.h2
-rw-r--r--sound/soc/codecs/wm8995.c17
-rw-r--r--sound/soc/codecs/wm9081.c7
-rw-r--r--sound/soc/codecs/wm9090.c32
-rw-r--r--sound/soc/codecs/wm9705.c46
-rw-r--r--sound/soc/codecs/wm9712.c219
-rw-r--r--sound/soc/codecs/wm9713.c230
-rw-r--r--sound/soc/codecs/wm_adsp.c97
-rw-r--r--sound/soc/davinci/davinci-mcasp.c339
-rw-r--r--sound/soc/davinci/davinci-mcasp.h17
-rw-r--r--sound/soc/dwc/designware_i2s.c46
-rw-r--r--sound/soc/fsl/eukrea-tlv320.c5
-rw-r--r--sound/soc/fsl/fsl-asoc-card.c19
-rw-r--r--sound/soc/fsl/fsl_dma.c9
-rw-r--r--sound/soc/fsl/fsl_esai.c12
-rw-r--r--sound/soc/fsl/fsl_ssi.c17
-rw-r--r--sound/soc/fsl/imx-sgtl5000.c6
-rw-r--r--sound/soc/fsl/imx-spdif.c3
-rw-r--r--sound/soc/fsl/imx-ssi.c2
-rw-r--r--sound/soc/fsl/imx-wm8962.c6
-rw-r--r--sound/soc/fsl/mpc5200_dma.c3
-rw-r--r--sound/soc/fsl/mpc5200_psc_ac97.c6
-rw-r--r--sound/soc/generic/simple-card.c160
-rw-r--r--sound/soc/intel/Kconfig44
-rw-r--r--sound/soc/intel/Makefile7
-rw-r--r--sound/soc/intel/broadwell.c64
-rw-r--r--sound/soc/intel/bytcr_dpcm_rt5640.c230
-rw-r--r--sound/soc/intel/cht_bsw_rt5672.c285
-rw-r--r--sound/soc/intel/haswell.c14
-rw-r--r--sound/soc/intel/sst-atom-controls.c1208
-rw-r--r--sound/soc/intel/sst-atom-controls.h428
-rw-r--r--sound/soc/intel/sst-baytrail-dsp.c24
-rw-r--r--sound/soc/intel/sst-dsp-priv.h136
-rw-r--r--sound/soc/intel/sst-dsp.c31
-rw-r--r--sound/soc/intel/sst-dsp.h28
-rw-r--r--sound/soc/intel/sst-firmware.c937
-rw-r--r--sound/soc/intel/sst-haswell-dsp.c295
-rw-r--r--sound/soc/intel/sst-haswell-ipc.c413
-rw-r--r--sound/soc/intel/sst-haswell-ipc.h25
-rw-r--r--sound/soc/intel/sst-haswell-pcm.c419
-rw-r--r--sound/soc/intel/sst-mfld-platform-compress.c8
-rw-r--r--sound/soc/intel/sst-mfld-platform-pcm.c154
-rw-r--r--sound/soc/intel/sst-mfld-platform.h5
-rw-r--r--sound/soc/intel/sst/Makefile7
-rw-r--r--sound/soc/intel/sst/sst.c437
-rw-r--r--sound/soc/intel/sst/sst.h546
-rw-r--r--sound/soc/intel/sst/sst_acpi.c383
-rw-r--r--sound/soc/intel/sst/sst_drv_interface.c686
-rw-r--r--sound/soc/intel/sst/sst_ipc.c373
-rw-r--r--sound/soc/intel/sst/sst_loader.c456
-rw-r--r--sound/soc/intel/sst/sst_pci.c209
-rw-r--r--sound/soc/intel/sst/sst_pvt.c449
-rw-r--r--sound/soc/intel/sst/sst_stream.c437
-rw-r--r--sound/soc/jz4740/qi_lb60.c11
-rw-r--r--sound/soc/mxs/mxs-saif.c2
-rw-r--r--sound/soc/mxs/mxs-sgtl5000.c7
-rw-r--r--sound/soc/nuc900/nuc900-ac97.c2
-rw-r--r--sound/soc/omap/Kconfig34
-rw-r--r--sound/soc/omap/Makefile6
-rw-r--r--sound/soc/omap/mcbsp.c3
-rw-r--r--sound/soc/omap/omap-hdmi-audio.c407
-rw-r--r--sound/soc/omap/omap-hdmi-card.c87
-rw-r--r--sound/soc/omap/omap-hdmi.c364
-rw-r--r--sound/soc/omap/omap-hdmi.h38
-rw-r--r--sound/soc/pxa/mioa701_wm9713.c7
-rw-r--r--sound/soc/pxa/pxa-ssp.c16
-rw-r--r--sound/soc/pxa/pxa2xx-ac97.c6
-rw-r--r--sound/soc/pxa/spitz.c52
-rw-r--r--sound/soc/rockchip/Kconfig9
-rw-r--r--sound/soc/samsung/Kconfig8
-rw-r--r--sound/soc/samsung/Makefile2
-rw-r--r--sound/soc/samsung/ac97.c4
-rw-r--r--sound/soc/samsung/arndale_rt5631.c150
-rw-r--r--sound/soc/samsung/i2s-regs.h10
-rw-r--r--sound/soc/samsung/i2s.c244
-rw-r--r--sound/soc/samsung/odroidx2_max98090.c4
-rw-r--r--sound/soc/sh/fsi.c9
-rw-r--r--sound/soc/sh/hac.c2
-rw-r--r--sound/soc/sh/rcar/adg.c2
-rw-r--r--sound/soc/sh/rcar/core.c236
-rw-r--r--sound/soc/sh/rcar/dvc.c215
-rw-r--r--sound/soc/sh/rcar/gen.c30
-rw-r--r--sound/soc/sh/rcar/rsnd.h92
-rw-r--r--sound/soc/sh/rcar/src.c101
-rw-r--r--sound/soc/sh/rcar/ssi.c233
-rw-r--r--sound/soc/soc-ac97.c256
-rw-r--r--sound/soc/soc-cache.c149
-rw-r--r--sound/soc/soc-compress.c11
-rw-r--r--sound/soc/soc-core.c1642
-rw-r--r--sound/soc/soc-dapm.c755
-rw-r--r--sound/soc/soc-jack.c11
-rw-r--r--sound/soc/soc-ops.c952
-rw-r--r--sound/soc/soc-pcm.c23
-rw-r--r--sound/soc/tegra/tegra20_ac97.c2
-rw-r--r--sound/soc/tegra/tegra_rt5640.c6
-rw-r--r--sound/soc/txx9/txx9aclc-ac97.c2
-rw-r--r--sound/soc/txx9/txx9aclc.c2
-rw-r--r--sound/soc/ux500/mop500.c8
-rw-r--r--sound/sparc/cs4231.c12
-rw-r--r--sound/usb/6fire/control.c22
-rw-r--r--sound/usb/6fire/firmware.c2
-rw-r--r--sound/usb/6fire/pcm.c17
-rw-r--r--sound/usb/Makefile1
-rw-r--r--sound/usb/card.c109
-rw-r--r--sound/usb/endpoint.c16
-rw-r--r--sound/usb/endpoint.h2
-rw-r--r--sound/usb/midi.c2
-rw-r--r--sound/usb/misc/ua101.c18
-rw-r--r--sound/usb/mixer.c241
-rw-r--r--sound/usb/mixer.h40
-rw-r--r--sound/usb/mixer_maps.c9
-rw-r--r--sound/usb/mixer_quirks.c920
-rw-r--r--sound/usb/mixer_scarlett.c1004
-rw-r--r--sound/usb/mixer_scarlett.h6
-rw-r--r--sound/usb/pcm.c5
-rw-r--r--sound/usb/quirks-table.h298
-rw-r--r--sound/usb/quirks.c72
-rw-r--r--sound/usb/quirks.h3
-rw-r--r--sound/usb/usx2y/usbusx2yaudio.c9
-rw-r--r--tools/lib/traceevent/plugin_scsi.c9
-rw-r--r--tools/perf/.gitignore2
-rw-r--r--tools/perf/Documentation/perf-record.txt6
-rw-r--r--tools/perf/Documentation/perf-report.txt12
-rw-r--r--tools/perf/Makefile.perf51
-rw-r--r--tools/perf/arch/powerpc/util/skip-callchain-idx.c38
-rw-r--r--tools/perf/builtin-diff.c1
-rw-r--r--tools/perf/builtin-inject.c4
-rw-r--r--tools/perf/builtin-kvm.c25
-rw-r--r--tools/perf/builtin-probe.c65
-rw-r--r--tools/perf/builtin-record.c20
-rw-r--r--tools/perf/builtin-report.c31
-rw-r--r--tools/perf/builtin-script.c8
-rw-r--r--tools/perf/builtin-stat.c105
-rw-r--r--tools/perf/builtin-timechart.c9
-rw-r--r--tools/perf/builtin-trace.c6
-rw-r--r--tools/perf/config/Makefile49
-rw-r--r--tools/perf/config/Makefile.arch8
-rw-r--r--tools/perf/config/feature-checks/Makefile16
-rw-r--r--tools/perf/config/feature-checks/test-all.c5
-rw-r--r--tools/perf/config/feature-checks/test-compile.c4
-rw-r--r--tools/perf/config/feature-checks/test-zlib.c9
-rw-r--r--tools/perf/perf-read-vdso.c34
-rw-r--r--tools/perf/perf.h4
-rw-r--r--tools/perf/scripts/python/bin/export-to-postgresql-record8
-rw-r--r--tools/perf/scripts/python/bin/export-to-postgresql-report29
-rw-r--r--tools/perf/scripts/python/export-to-postgresql.py444
-rw-r--r--tools/perf/tests/builtin-test.c2
-rw-r--r--tools/perf/tests/code-reading.c13
-rw-r--r--tools/perf/tests/dwarf-unwind.c18
-rw-r--r--tools/perf/tests/hists_filter.c2
-rw-r--r--tools/perf/tests/mmap-thread-lookup.c2
-rw-r--r--tools/perf/tests/sample-parsing.c55
-rw-r--r--tools/perf/ui/browsers/annotate.c13
-rw-r--r--tools/perf/ui/browsers/hists.c42
-rw-r--r--tools/perf/ui/gtk/hists.c11
-rw-r--r--tools/perf/ui/stdio/hist.c23
-rw-r--r--tools/perf/util/annotate.c34
-rw-r--r--tools/perf/util/annotate.h1
-rw-r--r--tools/perf/util/build-id.c348
-rw-r--r--tools/perf/util/build-id.h12
-rw-r--r--tools/perf/util/callchain.c37
-rw-r--r--tools/perf/util/callchain.h11
-rw-r--r--tools/perf/util/comm.h4
-rw-r--r--tools/perf/util/db-export.c428
-rw-r--r--tools/perf/util/db-export.h107
-rw-r--r--tools/perf/util/debug.c4
-rw-r--r--tools/perf/util/dso.c71
-rw-r--r--tools/perf/util/dso.h13
-rw-r--r--tools/perf/util/event.c20
-rw-r--r--tools/perf/util/event.h44
-rw-r--r--tools/perf/util/evlist.c38
-rw-r--r--tools/perf/util/evsel.c156
-rw-r--r--tools/perf/util/evsel.h50
-rw-r--r--tools/perf/util/find-vdso-map.c30
-rw-r--r--tools/perf/util/header.c361
-rw-r--r--tools/perf/util/header.h8
-rw-r--r--tools/perf/util/include/linux/bitmap.h17
-rw-r--r--tools/perf/util/include/linux/bitops.h2
-rw-r--r--tools/perf/util/machine.c264
-rw-r--r--tools/perf/util/machine.h17
-rw-r--r--tools/perf/util/map.c10
-rw-r--r--tools/perf/util/map.h4
-rw-r--r--tools/perf/util/parse-events.c2
-rw-r--r--tools/perf/util/parse-options.c78
-rw-r--r--tools/perf/util/parse-options.h4
-rw-r--r--tools/perf/util/pmu.c115
-rw-r--r--tools/perf/util/pmu.h5
-rw-r--r--tools/perf/util/probe-event.c18
-rw-r--r--tools/perf/util/scripting-engines/trace-event-perl.c29
-rw-r--r--tools/perf/util/scripting-engines/trace-event-python.c440
-rw-r--r--tools/perf/util/session.c196
-rw-r--r--tools/perf/util/session.h15
-rw-r--r--tools/perf/util/sort.c8
-rw-r--r--tools/perf/util/srcline.c17
-rw-r--r--tools/perf/util/symbol-elf.c56
-rw-r--r--tools/perf/util/symbol-minimal.c1
-rw-r--r--tools/perf/util/symbol.c19
-rw-r--r--tools/perf/util/symbol.h25
-rw-r--r--tools/perf/util/thread-stack.c747
-rw-r--r--tools/perf/util/thread-stack.h111
-rw-r--r--tools/perf/util/thread.c14
-rw-r--r--tools/perf/util/thread.h9
-rw-r--r--tools/perf/util/tool.h3
-rw-r--r--tools/perf/util/unwind-libdw.c8
-rw-r--r--tools/perf/util/unwind-libunwind.c17
-rw-r--r--tools/perf/util/unwind.h2
-rw-r--r--tools/perf/util/util.h10
-rw-r--r--tools/perf/util/vdso.c217
-rw-r--r--tools/perf/util/vdso.h4
-rw-r--r--tools/perf/util/zlib.c78
-rw-r--r--tools/power/cpupower/utils/cpuidle-info.c8
-rwxr-xr-xtools/testing/ktest/ktest.pl37
-rwxr-xr-xtools/testing/selftests/ftrace/ftracetest43
-rw-r--r--tools/testing/selftests/ftrace/test.d/00basic/basic4.tc5
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/event-enable.tc53
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc53
-rw-r--r--tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc47
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc89
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc52
-rw-r--r--tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc80
-rw-r--r--tools/testing/selftests/ftrace/test.d/functions16
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc1
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc55
-rw-r--r--tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc1
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh6
-rwxr-xr-xtools/testing/selftests/rcutorture/bin/kvm.sh19
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY022
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TINY02.boot2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE013
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE023
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE02-T3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE035
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE041
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE051
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot1
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE061
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE071
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE085
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08-T3
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot2
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/TREE093
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST14
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP18
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP18
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP19
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp27
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh33
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST17
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP19
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP18
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp19
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP26
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp27
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp18
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP30
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all30
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none30
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp30
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST14
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP19
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP18
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp27
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh44
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST14
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP19
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP18
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp20
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp27
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh23
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH22
-rw-r--r--tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh57
-rw-r--r--tools/testing/selftests/rcutorture/doc/TINY_RCU.txt2
-rw-r--r--tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt15
-rw-r--r--tools/virtio/linux/virtio.h22
-rw-r--r--tools/virtio/linux/virtio_config.h2
-rw-r--r--tools/virtio/virtio_test.c5
-rw-r--r--tools/virtio/vringh_test.c16
3752 files changed, 156244 insertions, 100024 deletions
diff --git a/Documentation/ABI/stable/sysfs-bus-usb b/Documentation/ABI/stable/sysfs-bus-usb
index e2bc700..831f15d 100644
--- a/Documentation/ABI/stable/sysfs-bus-usb
+++ b/Documentation/ABI/stable/sysfs-bus-usb
@@ -32,10 +32,9 @@ Date: January 2008
KernelVersion: 2.6.25
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
Description:
- If CONFIG_PM_RUNTIME is enabled then this file
- is present. When read, it returns the total time (in msec)
- that the USB device has been connected to the machine. This
- file is read-only.
+ If CONFIG_PM is enabled, then this file is present. When read,
+ it returns the total time (in msec) that the USB device has been
+ connected to the machine. This file is read-only.
Users:
PowerTOP <powertop@lists.01.org>
https://01.org/powertop/
@@ -45,10 +44,9 @@ Date: January 2008
KernelVersion: 2.6.25
Contact: Sarah Sharp <sarah.a.sharp@intel.com>
Description:
- If CONFIG_PM_RUNTIME is enabled then this file
- is present. When read, it returns the total time (in msec)
- that the USB device has been active, i.e. not in a suspended
- state. This file is read-only.
+ If CONFIG_PM is enabled, then this file is present. When read,
+ it returns the total time (in msec) that the USB device has been
+ active, i.e. not in a suspended state. This file is read-only.
Tools can use this file and the connected_duration file to
compute the percentage of time that a device has been active.
diff --git a/Documentation/ABI/stable/sysfs-driver-ib_srp b/Documentation/ABI/stable/sysfs-driver-ib_srp
index b9688de..7049a2b 100644
--- a/Documentation/ABI/stable/sysfs-driver-ib_srp
+++ b/Documentation/ABI/stable/sysfs-driver-ib_srp
@@ -55,12 +55,12 @@ Description: Interface for making ib_srp connect to a new target.
only safe with partial memory descriptor list support enabled
(allow_ext_sg=1).
* comp_vector, a number in the range 0..n-1 specifying the
- MSI-X completion vector. Some HCA's allocate multiple (n)
- MSI-X vectors per HCA port. If the IRQ affinity masks of
- these interrupts have been configured such that each MSI-X
- interrupt is handled by a different CPU then the comp_vector
- parameter can be used to spread the SRP completion workload
- over multiple CPU's.
+ MSI-X completion vector of the first RDMA channel. Some
+ HCA's allocate multiple (n) MSI-X vectors per HCA port. If
+ the IRQ affinity masks of these interrupts have been
+ configured such that each MSI-X interrupt is handled by a
+ different CPU then the comp_vector parameter can be used to
+ spread the SRP completion workload over multiple CPU's.
* tl_retry_count, a number in the range 2..7 specifying the
IB RC retry count.
* queue_size, the maximum number of commands that the
@@ -88,6 +88,13 @@ Description: Whether ib_srp is allowed to include a partial memory
descriptor list in an SRP_CMD when communicating with an SRP
target.
+What: /sys/class/scsi_host/host<n>/ch_count
+Date: April 1, 2015
+KernelVersion: 3.19
+Contact: linux-rdma@vger.kernel.org
+Description: Number of RDMA channels used for communication with the SRP
+ target.
+
What: /sys/class/scsi_host/host<n>/cmd_sg_entries
Date: May 19, 2011
KernelVersion: 2.6.39
@@ -95,6 +102,12 @@ Contact: linux-rdma@vger.kernel.org
Description: Maximum number of data buffer descriptors that may be sent to
the target in a single SRP_CMD request.
+What: /sys/class/scsi_host/host<n>/comp_vector
+Date: September 2, 2013
+KernelVersion: 3.11
+Contact: linux-rdma@vger.kernel.org
+Description: Completion vector used for the first RDMA channel.
+
What: /sys/class/scsi_host/host<n>/dgid
Date: June 17, 2006
KernelVersion: 2.6.17
diff --git a/Documentation/ABI/testing/sysfs-bus-pci b/Documentation/ABI/testing/sysfs-bus-pci
index ee6c040..b3bc50f 100644
--- a/Documentation/ABI/testing/sysfs-bus-pci
+++ b/Documentation/ABI/testing/sysfs-bus-pci
@@ -281,3 +281,16 @@ Description:
opt-out of driver binding using a driver_override name such as
"none". Only a single driver may be specified in the override,
there is no support for parsing delimiters.
+
+What: /sys/bus/pci/devices/.../numa_node
+Date: Oct 2014
+Contact: Prarit Bhargava <prarit@redhat.com>
+Description:
+ This file contains the NUMA node to which the PCI device is
+ attached, or -1 if the node is unknown. The initial value
+ comes from an ACPI _PXM method or a similar firmware
+ source. If that is missing or incorrect, this file can be
+ written to override the node. In that case, please report
+ a firmware bug to the system vendor. Writing to this file
+ taints the kernel with TAINT_FIRMWARE_WORKAROUND, which
+ reduces the supportability of your system.
diff --git a/Documentation/ABI/testing/sysfs-bus-usb b/Documentation/ABI/testing/sysfs-bus-usb
index 614d451..e5cc763 100644
--- a/Documentation/ABI/testing/sysfs-bus-usb
+++ b/Documentation/ABI/testing/sysfs-bus-usb
@@ -104,16 +104,15 @@ What: /sys/bus/usb/devices/.../power/usb2_hardware_lpm
Date: September 2011
Contact: Andiry Xu <andiry.xu@amd.com>
Description:
- If CONFIG_PM_RUNTIME is set and a USB 2.0 lpm-capable device
- is plugged in to a xHCI host which support link PM, it will
- perform a LPM test; if the test is passed and host supports
- USB2 hardware LPM (xHCI 1.0 feature), USB2 hardware LPM will
- be enabled for the device and the USB device directory will
- contain a file named power/usb2_hardware_lpm. The file holds
- a string value (enable or disable) indicating whether or not
- USB2 hardware LPM is enabled for the device. Developer can
- write y/Y/1 or n/N/0 to the file to enable/disable the
- feature.
+ If CONFIG_PM is set and a USB 2.0 lpm-capable device is plugged
+ in to a xHCI host which support link PM, it will perform a LPM
+ test; if the test is passed and host supports USB2 hardware LPM
+ (xHCI 1.0 feature), USB2 hardware LPM will be enabled for the
+ device and the USB device directory will contain a file named
+ power/usb2_hardware_lpm. The file holds a string value (enable
+ or disable) indicating whether or not USB2 hardware LPM is
+ enabled for the device. Developer can write y/Y/1 or n/N/0 to
+ the file to enable/disable the feature.
What: /sys/bus/usb/devices/.../removable
Date: February 2012
diff --git a/Documentation/DocBook/alsa-driver-api.tmpl b/Documentation/DocBook/alsa-driver-api.tmpl
index 0230a96..71f9246 100644
--- a/Documentation/DocBook/alsa-driver-api.tmpl
+++ b/Documentation/DocBook/alsa-driver-api.tmpl
@@ -57,6 +57,7 @@
!Esound/core/pcm.c
!Esound/core/pcm_lib.c
!Esound/core/pcm_native.c
+!Iinclude/sound/pcm.h
</sect1>
<sect1><title>PCM Format Helpers</title>
!Esound/core/pcm_misc.c
@@ -64,6 +65,10 @@
<sect1><title>PCM Memory Management</title>
!Esound/core/pcm_memory.c
</sect1>
+ <sect1><title>PCM DMA Engine API</title>
+!Esound/core/pcm_dmaengine.c
+!Iinclude/sound/dmaengine_pcm.h
+ </sect1>
</chapter>
<chapter><title>Control/Mixer API</title>
<sect1><title>General Control Interface</title>
@@ -91,12 +96,38 @@
!Esound/core/info.c
</sect1>
</chapter>
+ <chapter><title>Compress Offload</title>
+ <sect1><title>Compress Offload API</title>
+!Esound/core/compress_offload.c
+!Iinclude/uapi/sound/compress_offload.h
+!Iinclude/uapi/sound/compress_params.h
+!Iinclude/sound/compress_driver.h
+ </sect1>
+ </chapter>
+ <chapter><title>ASoC</title>
+ <sect1><title>ASoC Core API</title>
+!Iinclude/sound/soc.h
+!Esound/soc/soc-core.c
+!Esound/soc/soc-cache.c
+!Esound/soc/soc-devres.c
+!Esound/soc/soc-io.c
+!Esound/soc/soc-pcm.c
+ </sect1>
+ <sect1><title>ASoC DAPM API</title>
+!Esound/soc/soc-dapm.c
+ </sect1>
+ <sect1><title>ASoC DMA Engine API</title>
+!Esound/soc/soc-generic-dmaengine-pcm.c
+ </sect1>
+ </chapter>
<chapter><title>Miscellaneous Functions</title>
<sect1><title>Hardware-Dependent Devices API</title>
!Esound/core/hwdep.c
</sect1>
<sect1><title>Jack Abstraction Layer API</title>
+!Iinclude/sound/jack.h
!Esound/core/jack.c
+!Esound/soc/soc-jack.c
</sect1>
<sect1><title>ISA DMA Helpers</title>
!Esound/core/isadma.c
diff --git a/Documentation/DocBook/media/dvb/dvbproperty.xml b/Documentation/DocBook/media/dvb/dvbproperty.xml
index 948ddaa..3018564 100644
--- a/Documentation/DocBook/media/dvb/dvbproperty.xml
+++ b/Documentation/DocBook/media/dvb/dvbproperty.xml
@@ -120,8 +120,8 @@ struct dtv_properties {
</para>
<informaltable><tgroup cols="1"><tbody><row><entry
align="char">
-<para>This ioctl call sets one or more frontend properties. This call only
- requires read-only access to the device.</para>
+<para>This ioctl call sets one or more frontend properties. This call
+ requires read/write access to the device.</para>
</entry>
</row></tbody></tgroup></informaltable>
<para>SYNOPSIS
diff --git a/Documentation/DocBook/media/v4l/biblio.xml b/Documentation/DocBook/media/v4l/biblio.xml
index d2eb79e..7ff01a2 100644
--- a/Documentation/DocBook/media/v4l/biblio.xml
+++ b/Documentation/DocBook/media/v4l/biblio.xml
@@ -178,6 +178,75 @@ Signal - NTSC for Studio Applications"</title>
1125-Line High-Definition Production"</title>
</biblioentry>
+ <biblioentry id="srgb">
+ <abbrev>sRGB</abbrev>
+ <authorgroup>
+ <corpauthor>International Electrotechnical Commission
+(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
+ </authorgroup>
+ <title>IEC 61966-2-1 ed1.0 "Multimedia systems and equipment - Colour measurement
+and management - Part 2-1: Colour management - Default RGB colour space - sRGB"</title>
+ </biblioentry>
+
+ <biblioentry id="sycc">
+ <abbrev>sYCC</abbrev>
+ <authorgroup>
+ <corpauthor>International Electrotechnical Commission
+(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
+ </authorgroup>
+ <title>IEC 61966-2-1-am1 ed1.0 "Amendment 1 - Multimedia systems and equipment - Colour measurement
+and management - Part 2-1: Colour management - Default RGB colour space - sRGB"</title>
+ </biblioentry>
+
+ <biblioentry id="xvycc">
+ <abbrev>xvYCC</abbrev>
+ <authorgroup>
+ <corpauthor>International Electrotechnical Commission
+(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
+ </authorgroup>
+ <title>IEC 61966-2-4 ed1.0 "Multimedia systems and equipment - Colour measurement
+and management - Part 2-4: Colour management - Extended-gamut YCC colour space for video
+applications - xvYCC"</title>
+ </biblioentry>
+
+ <biblioentry id="adobergb">
+ <abbrev>AdobeRGB</abbrev>
+ <authorgroup>
+ <corpauthor>Adobe Systems Incorporated (<ulink url="http://www.adobe.com">http://www.adobe.com</ulink>)</corpauthor>
+ </authorgroup>
+ <title>Adobe&copy; RGB (1998) Color Image Encoding Version 2005-05</title>
+ </biblioentry>
+
+ <biblioentry id="oprgb">
+ <abbrev>opRGB</abbrev>
+ <authorgroup>
+ <corpauthor>International Electrotechnical Commission
+(<ulink url="http://www.iec.ch">http://www.iec.ch</ulink>)</corpauthor>
+ </authorgroup>
+ <title>IEC 61966-2-5 "Multimedia systems and equipment - Colour measurement
+and management - Part 2-5: Colour management - Optional RGB colour space - opRGB"</title>
+ </biblioentry>
+
+ <biblioentry id="itu2020">
+ <abbrev>ITU&nbsp;BT.2020</abbrev>
+ <authorgroup>
+ <corpauthor>International Telecommunication Union (<ulink
+url="http://www.itu.ch">http://www.itu.ch</ulink>)</corpauthor>
+ </authorgroup>
+ <title>ITU-R Recommendation BT.2020 (08/2012) "Parameter values for ultra-high
+definition television systems for production and international programme exchange"
+</title>
+ </biblioentry>
+
+ <biblioentry id="tech3213">
+ <abbrev>EBU&nbsp;Tech&nbsp;3213</abbrev>
+ <authorgroup>
+ <corpauthor>European Broadcast Union (<ulink
+url="http://www.ebu.ch">http://www.ebu.ch</ulink>)</corpauthor>
+ </authorgroup>
+ <title>E.B.U. Standard for Chromaticity Tolerances for Studio Monitors"</title>
+ </biblioentry>
+
<biblioentry id="iec62106">
<abbrev>IEC&nbsp;62106</abbrev>
<authorgroup>
@@ -266,4 +335,20 @@ in the frequency range from 87,5 to 108,0 MHz</title>
<subtitle>Version 1, Revision 2</subtitle>
</biblioentry>
+ <biblioentry id="poynton">
+ <abbrev>poynton</abbrev>
+ <authorgroup>
+ <corpauthor>Charles Poynton</corpauthor>
+ </authorgroup>
+ <title>Digital Video and HDTV, Algorithms and Interfaces</title>
+ </biblioentry>
+
+ <biblioentry id="colimg">
+ <abbrev>colimg</abbrev>
+ <authorgroup>
+ <corpauthor>Erik Reinhard et al.</corpauthor>
+ </authorgroup>
+ <title>Color Imaging: Fundamentals and Applications</title>
+ </biblioentry>
+
</bibliography>
diff --git a/Documentation/DocBook/media/v4l/dev-subdev.xml b/Documentation/DocBook/media/v4l/dev-subdev.xml
index d15aaf8..4f0ba58 100644
--- a/Documentation/DocBook/media/v4l/dev-subdev.xml
+++ b/Documentation/DocBook/media/v4l/dev-subdev.xml
@@ -195,53 +195,59 @@
<title>Sample Pipeline Configuration</title>
<tgroup cols="3">
<colspec colname="what"/>
- <colspec colname="sensor-0" />
- <colspec colname="frontend-0" />
- <colspec colname="frontend-1" />
- <colspec colname="scaler-0" />
- <colspec colname="scaler-1" />
+ <colspec colname="sensor-0 format" />
+ <colspec colname="frontend-0 format" />
+ <colspec colname="frontend-1 format" />
+ <colspec colname="scaler-0 format" />
+ <colspec colname="scaler-0 compose" />
+ <colspec colname="scaler-1 format" />
<thead>
<row>
<entry></entry>
- <entry>Sensor/0</entry>
- <entry>Frontend/0</entry>
- <entry>Frontend/1</entry>
- <entry>Scaler/0</entry>
- <entry>Scaler/1</entry>
+ <entry>Sensor/0 format</entry>
+ <entry>Frontend/0 format</entry>
+ <entry>Frontend/1 format</entry>
+ <entry>Scaler/0 format</entry>
+ <entry>Scaler/0 compose selection rectangle</entry>
+ <entry>Scaler/1 format</entry>
</row>
</thead>
<tbody valign="top">
<row>
<entry>Initial state</entry>
- <entry>2048x1536</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
- <entry>-</entry>
+ <entry>2048x1536/SGRBG8_1X8</entry>
+ <entry>(default)</entry>
+ <entry>(default)</entry>
+ <entry>(default)</entry>
+ <entry>(default)</entry>
+ <entry>(default)</entry>
</row>
<row>
- <entry>Configure frontend input</entry>
- <entry>2048x1536</entry>
- <entry><emphasis>2048x1536</emphasis></entry>
- <entry><emphasis>2046x1534</emphasis></entry>
- <entry>-</entry>
- <entry>-</entry>
+ <entry>Configure frontend sink format</entry>
+ <entry>2048x1536/SGRBG8_1X8</entry>
+ <entry><emphasis>2048x1536/SGRBG8_1X8</emphasis></entry>
+ <entry><emphasis>2046x1534/SGRBG8_1X8</emphasis></entry>
+ <entry>(default)</entry>
+ <entry>(default)</entry>
+ <entry>(default)</entry>
</row>
<row>
- <entry>Configure scaler input</entry>
- <entry>2048x1536</entry>
- <entry>2048x1536</entry>
- <entry>2046x1534</entry>
- <entry><emphasis>2046x1534</emphasis></entry>
- <entry><emphasis>2046x1534</emphasis></entry>
+ <entry>Configure scaler sink format</entry>
+ <entry>2048x1536/SGRBG8_1X8</entry>
+ <entry>2048x1536/SGRBG8_1X8</entry>
+ <entry>2046x1534/SGRBG8_1X8</entry>
+ <entry><emphasis>2046x1534/SGRBG8_1X8</emphasis></entry>
+ <entry><emphasis>0,0/2046x1534</emphasis></entry>
+ <entry><emphasis>2046x1534/SGRBG8_1X8</emphasis></entry>
</row>
<row>
- <entry>Configure scaler output</entry>
- <entry>2048x1536</entry>
- <entry>2048x1536</entry>
- <entry>2046x1534</entry>
- <entry>2046x1534</entry>
- <entry><emphasis>1280x960</emphasis></entry>
+ <entry>Configure scaler sink compose selection</entry>
+ <entry>2048x1536/SGRBG8_1X8</entry>
+ <entry>2048x1536/SGRBG8_1X8</entry>
+ <entry>2046x1534/SGRBG8_1X8</entry>
+ <entry>2046x1534/SGRBG8_1X8</entry>
+ <entry><emphasis>0,0/1280x960</emphasis></entry>
+ <entry><emphasis>1280x960/SGRBG8_1X8</emphasis></entry>
</row>
</tbody>
</tgroup>
@@ -249,19 +255,30 @@
<para>
<orderedlist>
- <listitem><para>Initial state. The sensor output is set to its native 3MP
- resolution. Resolutions on the host frontend and scaler input and output
- pads are undefined.</para></listitem>
- <listitem><para>The application configures the frontend input pad resolution to
- 2048x1536. The driver propagates the format to the frontend output pad.
- Note that the propagated output format can be different, as in this case,
- than the input format, as the hardware might need to crop pixels (for
- instance when converting a Bayer filter pattern to RGB or YUV).</para></listitem>
- <listitem><para>The application configures the scaler input pad resolution to
- 2046x1534 to match the frontend output resolution. The driver propagates
- the format to the scaler output pad.</para></listitem>
- <listitem><para>The application configures the scaler output pad resolution to
- 1280x960.</para></listitem>
+ <listitem><para>Initial state. The sensor source pad format is
+ set to its native 3MP size and V4L2_MBUS_FMT_SGRBG8_1X8
+ media bus code. Formats on the host frontend and scaler sink
+ and source pads have the default values, as well as the
+ compose rectangle on the scaler's sink pad.</para></listitem>
+
+ <listitem><para>The application configures the frontend sink
+ pad format's size to 2048x1536 and its media bus code to
+ V4L2_MBUS_FMT_SGRBG_1X8. The driver propagates the format to
+ the frontend source pad.</para></listitem>
+
+ <listitem><para>The application configures the scaler sink pad
+ format's size to 2046x1534 and the media bus code to
+ V4L2_MBUS_FMT_SGRBG_1X8 to match the frontend source size and
+ media bus code. The media bus code on the sink pad is set to
+ V4L2_MBUS_FMT_SGRBG_1X8. The driver propagates the size to the
+ compose selection rectangle on the scaler's sink pad, and the
+ format to the scaler source pad.</para></listitem>
+
+ <listitem><para>The application configures the size of the compose
+ selection rectangle of the scaler's sink pad 1280x960. The driver
+ propagates the size to the scaler's source pad
+ format.</para></listitem>
+
</orderedlist>
</para>
diff --git a/Documentation/DocBook/media/v4l/io.xml b/Documentation/DocBook/media/v4l/io.xml
index e5e8325..1c17f80 100644
--- a/Documentation/DocBook/media/v4l/io.xml
+++ b/Documentation/DocBook/media/v4l/io.xml
@@ -1422,7 +1422,10 @@ one of the <constant>V4L2_FIELD_NONE</constant>,
<constant>V4L2_FIELD_BOTTOM</constant>, or
<constant>V4L2_FIELD_INTERLACED</constant> formats is acceptable.
Drivers choose depending on hardware capabilities or e.&nbsp;g. the
-requested image size, and return the actual field order. &v4l2-buffer;
+requested image size, and return the actual field order. Drivers must
+never return <constant>V4L2_FIELD_ANY</constant>. If multiple
+field orders are possible the driver must choose one of the possible
+field orders during &VIDIOC-S-FMT; or &VIDIOC-TRY-FMT;. &v4l2-buffer;
<structfield>field</structfield> can never be
<constant>V4L2_FIELD_ANY</constant>.</entry>
</row>
diff --git a/Documentation/DocBook/media/v4l/pixfmt.xml b/Documentation/DocBook/media/v4l/pixfmt.xml
index df5b23d..ccf6053 100644
--- a/Documentation/DocBook/media/v4l/pixfmt.xml
+++ b/Documentation/DocBook/media/v4l/pixfmt.xml
@@ -296,343 +296,1003 @@ in the 2-planar version or with each component in its own buffer in the
<section id="colorspaces">
<title>Colorspaces</title>
- <para>[intro]</para>
+ <para>'Color' is a very complex concept and depends on physics, chemistry and
+biology. Just because you have three numbers that describe the 'red', 'green'
+and 'blue' components of the color of a pixel does not mean that you can accurately
+display that color. A colorspace defines what it actually <emphasis>means</emphasis>
+to have an RGB value of e.g. (255,&nbsp;0,&nbsp;0). That is, which color should be
+reproduced on the screen in a perfectly calibrated environment.</para>
- <!-- See proposal by Billy Biggs, video4linux-list@redhat.com
-on 11 Oct 2002, subject: "Re: [V4L] Re: v4l2 api", and
-http://vektor.theorem.ca/graphics/ycbcr/ and
-http://www.poynton.com/notes/colour_and_gamma/ColorFAQ.html -->
+ <para>In order to do that we first need to have a good definition of
+color, i.e. some way to uniquely and unambiguously define a color so that someone
+else can reproduce it. Human color vision is trichromatic since the human eye has
+color receptors that are sensitive to three different wavelengths of light. Hence
+the need to use three numbers to describe color. Be glad you are not a mantis shrimp
+as those are sensitive to 12 different wavelengths, so instead of RGB we would be
+using the ABCDEFGHIJKL colorspace...</para>
- <para>
- <variablelist>
- <varlistentry>
- <term>Gamma Correction</term>
- <listitem>
- <para>[to do]</para>
- <para>E'<subscript>R</subscript> = f(R)</para>
- <para>E'<subscript>G</subscript> = f(G)</para>
- <para>E'<subscript>B</subscript> = f(B)</para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Construction of luminance and color-difference
-signals</term>
- <listitem>
- <para>[to do]</para>
- <para>E'<subscript>Y</subscript> =
-Coeff<subscript>R</subscript> E'<subscript>R</subscript>
-+ Coeff<subscript>G</subscript> E'<subscript>G</subscript>
-+ Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
- <para>(E'<subscript>R</subscript> - E'<subscript>Y</subscript>) = E'<subscript>R</subscript>
-- Coeff<subscript>R</subscript> E'<subscript>R</subscript>
-- Coeff<subscript>G</subscript> E'<subscript>G</subscript>
-- Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
- <para>(E'<subscript>B</subscript> - E'<subscript>Y</subscript>) = E'<subscript>B</subscript>
-- Coeff<subscript>R</subscript> E'<subscript>R</subscript>
-- Coeff<subscript>G</subscript> E'<subscript>G</subscript>
-- Coeff<subscript>B</subscript> E'<subscript>B</subscript></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Re-normalized color-difference signals</term>
- <listitem>
- <para>The color-difference signals are scaled back to unity
-range [-0.5;+0.5]:</para>
- <para>K<subscript>B</subscript> = 0.5 / (1 - Coeff<subscript>B</subscript>)</para>
- <para>K<subscript>R</subscript> = 0.5 / (1 - Coeff<subscript>R</subscript>)</para>
- <para>P<subscript>B</subscript> =
-K<subscript>B</subscript> (E'<subscript>B</subscript> - E'<subscript>Y</subscript>) =
- 0.5 (Coeff<subscript>R</subscript> / Coeff<subscript>B</subscript>) E'<subscript>R</subscript>
-+ 0.5 (Coeff<subscript>G</subscript> / Coeff<subscript>B</subscript>) E'<subscript>G</subscript>
-+ 0.5 E'<subscript>B</subscript></para>
- <para>P<subscript>R</subscript> =
-K<subscript>R</subscript> (E'<subscript>R</subscript> - E'<subscript>Y</subscript>) =
- 0.5 E'<subscript>R</subscript>
-+ 0.5 (Coeff<subscript>G</subscript> / Coeff<subscript>R</subscript>) E'<subscript>G</subscript>
-+ 0.5 (Coeff<subscript>B</subscript> / Coeff<subscript>R</subscript>) E'<subscript>B</subscript></para>
- </listitem>
- </varlistentry>
- <varlistentry>
- <term>Quantization</term>
- <listitem>
- <para>[to do]</para>
- <para>Y' = (Lum. Levels - 1) &middot; E'<subscript>Y</subscript> + Lum. Offset</para>
- <para>C<subscript>B</subscript> = (Chrom. Levels - 1)
-&middot; P<subscript>B</subscript> + Chrom. Offset</para>
- <para>C<subscript>R</subscript> = (Chrom. Levels - 1)
-&middot; P<subscript>R</subscript> + Chrom. Offset</para>
- <para>Rounding to the nearest integer and clamping to the range
-[0;255] finally yields the digital color components Y'CbCr
-stored in YUV images.</para>
- </listitem>
- </varlistentry>
- </variablelist>
- </para>
-
- <example>
- <title>ITU-R Rec. BT.601 color conversion</title>
-
- <para>Forward Transformation</para>
-
- <programlisting>
-int ER, EG, EB; /* gamma corrected RGB input [0;255] */
-int Y1, Cb, Cr; /* output [0;255] */
-
-double r, g, b; /* temporaries */
-double y1, pb, pr;
-
-int
-clamp (double x)
-{
- int r = x; /* round to nearest */
-
- if (r &lt; 0) return 0;
- else if (r &gt; 255) return 255;
- else return r;
-}
-
-r = ER / 255.0;
-g = EG / 255.0;
-b = EB / 255.0;
-
-y1 = 0.299 * r + 0.587 * g + 0.114 * b;
-pb = -0.169 * r - 0.331 * g + 0.5 * b;
-pr = 0.5 * r - 0.419 * g - 0.081 * b;
-
-Y1 = clamp (219 * y1 + 16);
-Cb = clamp (224 * pb + 128);
-Cr = clamp (224 * pr + 128);
-
-/* or shorter */
-
-y1 = 0.299 * ER + 0.587 * EG + 0.114 * EB;
-
-Y1 = clamp ( (219 / 255.0) * y1 + 16);
-Cb = clamp (((224 / 255.0) / (2 - 2 * 0.114)) * (EB - y1) + 128);
-Cr = clamp (((224 / 255.0) / (2 - 2 * 0.299)) * (ER - y1) + 128);
- </programlisting>
-
- <para>Inverse Transformation</para>
-
- <programlisting>
-int Y1, Cb, Cr; /* gamma pre-corrected input [0;255] */
-int ER, EG, EB; /* output [0;255] */
-
-double r, g, b; /* temporaries */
-double y1, pb, pr;
-
-int
-clamp (double x)
-{
- int r = x; /* round to nearest */
-
- if (r &lt; 0) return 0;
- else if (r &gt; 255) return 255;
- else return r;
-}
-
-y1 = (Y1 - 16) / 219.0;
-pb = (Cb - 128) / 224.0;
-pr = (Cr - 128) / 224.0;
-
-r = 1.0 * y1 + 0 * pb + 1.402 * pr;
-g = 1.0 * y1 - 0.344 * pb - 0.714 * pr;
-b = 1.0 * y1 + 1.772 * pb + 0 * pr;
-
-ER = clamp (r * 255); /* [ok? one should prob. limit y1,pb,pr] */
-EG = clamp (g * 255);
-EB = clamp (b * 255);
- </programlisting>
- </example>
-
- <table pgwide="1" id="v4l2-colorspace" orient="land">
- <title>enum v4l2_colorspace</title>
- <tgroup cols="11" align="center">
- <colspec align="left" />
- <colspec align="center" />
- <colspec align="left" />
- <colspec colname="cr" />
- <colspec colname="cg" />
- <colspec colname="cb" />
- <colspec colname="wp" />
- <colspec colname="gc" />
- <colspec colname="lum" />
- <colspec colname="qy" />
- <colspec colname="qc" />
- <spanspec namest="cr" nameend="cb" spanname="chrom" />
- <spanspec namest="qy" nameend="qc" spanname="quant" />
- <spanspec namest="lum" nameend="qc" spanname="spam" />
+ <para>Color exists only in the eye and brain and is the result of how strongly
+color receptors are stimulated. This is based on the Spectral
+Power Distribution (SPD) which is a graph showing the intensity (radiant power)
+of the light at wavelengths covering the visible spectrum as it enters the eye.
+The science of colorimetry is about the relationship between the SPD and color as
+perceived by the human brain.</para>
+
+ <para>Since the human eye has only three color receptors it is perfectly
+possible that different SPDs will result in the same stimulation of those receptors
+and are perceived as the same color, even though the SPD of the light is
+different.</para>
+
+ <para>In the 1920s experiments were devised to determine the relationship
+between SPDs and the perceived color and that resulted in the CIE 1931 standard
+that defines spectral weighting functions that model the perception of color.
+Specifically that standard defines functions that can take an SPD and calculate
+the stimulus for each color receptor. After some further mathematical transforms
+these stimuli are known as the <emphasis>CIE XYZ tristimulus</emphasis> values
+and these X, Y and Z values describe a color as perceived by a human unambiguously.
+These X, Y and Z values are all in the range [0&hellip;1].</para>
+
+ <para>The Y value in the CIE XYZ colorspace corresponds to luminance. Often
+the CIE XYZ colorspace is transformed to the normalized CIE xyY colorspace:</para>
+
+ <para>x = X / (X + Y + Z)</para>
+ <para>y = Y / (X + Y + Z)</para>
+
+ <para>The x and y values are the chromaticity coordinates and can be used to
+define a color without the luminance component Y. It is very confusing to
+have such similar names for these colorspaces. Just be aware that if colors
+are specified with lower case 'x' and 'y', then the CIE xyY colorspace is
+used. Upper case 'X' and 'Y' refer to the CIE XYZ colorspace. Also, y has nothing
+to do with luminance. Together x and y specify a color, and Y the luminance.
+That is really all you need to remember from a practical point of view. At
+the end of this section you will find reading resources that go into much more
+detail if you are interested.
+</para>
+
+ <para>A monitor or TV will reproduce colors by emitting light at three
+different wavelengths, the combination of which will stimulate the color receptors
+in the eye and thus cause the perception of color. Historically these wavelengths
+were defined by the red, green and blue phosphors used in the displays. These
+<emphasis>color primaries</emphasis> are part of what defines a colorspace.</para>
+
+ <para>Different display devices will have different primaries and some
+primaries are more suitable for some display technologies than others. This has
+resulted in a variety of colorspaces that are used for different display
+technologies or uses. To define a colorspace you need to define the three
+color primaries (these are typically defined as x,&nbsp;y chromaticity coordinates
+from the CIE xyY colorspace) but also the white reference: that is the color obtained
+when all three primaries are at maximum power. This determines the relative power
+or energy of the primaries. This is usually chosen to be close to daylight which has
+been defined as the CIE D65 Illuminant.</para>
+
+ <para>To recapitulate: the CIE XYZ colorspace uniquely identifies colors.
+Other colorspaces are defined by three chromaticity coordinates defined in the
+CIE xyY colorspace. Based on those a 3x3 matrix can be constructed that
+transforms CIE XYZ colors to colors in the new colorspace.
+</para>
+
+ <para>Both the CIE XYZ and the RGB colorspace that are derived from the
+specific chromaticity primaries are linear colorspaces. But neither the eye,
+nor display technology is linear. Doubling the values of all components in
+the linear colorspace will not be perceived as twice the intensity of the color.
+So each colorspace also defines a transfer function that takes a linear color
+component value and transforms it to the non-linear component value, which is a
+closer match to the non-linear performance of both the eye and displays. Linear
+component values are denoted RGB, non-linear are denoted as R'G'B'. In general
+colors used in graphics are all R'G'B', except in openGL which uses linear RGB.
+Special care should be taken when dealing with openGL to provide linear RGB colors
+or to use the built-in openGL support to apply the inverse transfer function.</para>
+
+ <para>The final piece that defines a colorspace is a function that
+transforms non-linear R'G'B' to non-linear Y'CbCr. This function is determined
+by the so-called luma coefficients. There may be multiple possible Y'CbCr
+encodings allowed for the same colorspace. Many encodings of color
+prefer to use luma (Y') and chroma (CbCr) instead of R'G'B'. Since the human
+eye is more sensitive to differences in luminance than in color this encoding
+allows one to reduce the amount of color information compared to the luma
+data. Note that the luma (Y') is unrelated to the Y in the CIE XYZ colorspace.
+Also note that Y'CbCr is often called YCbCr or YUV even though these are
+strictly speaking wrong.</para>
+
+ <para>Sometimes people confuse Y'CbCr as being a colorspace. This is not
+correct, it is just an encoding of an R'G'B' color into luma and chroma
+values. The underlying colorspace that is associated with the R'G'B' color
+is also associated with the Y'CbCr color.</para>
+
+ <para>The final step is how the RGB, R'G'B' or Y'CbCr values are
+quantized. The CIE XYZ colorspace where X, Y and Z are in the range
+[0&hellip;1] describes all colors that humans can perceive, but the transform to
+another colorspace will produce colors that are outside the [0&hellip;1] range.
+Once clamped to the [0&hellip;1] range those colors can no longer be reproduced
+in that colorspace. This clamping is what reduces the extent or gamut of the
+colorspace. How the range of [0&hellip;1] is translated to integer values in the
+range of [0&hellip;255] (or higher, depending on the color depth) is called the
+quantization. This is <emphasis>not</emphasis> part of the colorspace
+definition. In practice RGB or R'G'B' values are full range, i.e. they
+use the full [0&hellip;255] range. Y'CbCr values on the other hand are limited
+range with Y' using [16&hellip;235] and Cb and Cr using [16&hellip;240].</para>
+
+ <para>Unfortunately, in some cases limited range RGB is also used
+where the components use the range [16&hellip;235]. And full range Y'CbCr also exists
+using the [0&hellip;255] range.</para>
+
+ <para>In order to correctly interpret a color you need to know the
+quantization range, whether it is R'G'B' or Y'CbCr, the used Y'CbCr encoding
+and the colorspace.
+From that information you can calculate the corresponding CIE XYZ color
+and map that again to whatever colorspace your display device uses.</para>
+
+ <para>The colorspace definition itself consists of the three
+chromaticity primaries, the white reference chromaticity, a transfer
+function and the luma coefficients needed to transform R'G'B' to Y'CbCr. While
+some colorspace standards correctly define all four, quite often the colorspace
+standard only defines some, and you have to rely on other standards for
+the missing pieces. The fact that colorspaces are often a mix of different
+standards also led to very confusing naming conventions where the name of
+a standard was used to name a colorspace when in fact that standard was
+part of various other colorspaces as well.</para>
+
+ <para>If you want to read more about colors and colorspaces, then the
+following resources are useful: <xref linkend="poynton" /> is a good practical
+book for video engineers, <xref linkend="colimg" /> has a much broader scope and
+describes many more aspects of color (physics, chemistry, biology, etc.).
+The <ulink url="http://www.brucelindbloom.com">http://www.brucelindbloom.com</ulink>
+website is an excellent resource, especially with respect to the mathematics behind
+colorspace conversions. The wikipedia <ulink url="http://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space">CIE 1931 colorspace</ulink> article
+is also very useful.</para>
+ </section>
+
+ <section>
+ <title>Defining Colorspaces in V4L2</title>
+ <para>In V4L2 colorspaces are defined by three values. The first is the colorspace
+identifier (&v4l2-colorspace;) which defines the chromaticities, the transfer
+function, the default Y'CbCr encoding and the default quantization method. The second
+is the Y'CbCr encoding identifier (&v4l2-ycbcr-encoding;) to specify non-standard
+Y'CbCr encodings and the third is the quantization identifier (&v4l2-quantization;)
+to specify non-standard quantization methods. Most of the time only the colorspace
+field of &v4l2-pix-format; or &v4l2-pix-format-mplane; needs to be filled in. Note
+that the default R'G'B' quantization is always full range for all colorspaces,
+so this won't be mentioned explicitly for each colorspace description.</para>
+
+ <table pgwide="1" frame="none" id="v4l2-colorspace">
+ <title>V4L2 Colorspaces</title>
+ <tgroup cols="2" align="left">
+ &cs-def;
<thead>
<row>
- <entry morerows="1">Identifier</entry>
- <entry morerows="1">Value</entry>
- <entry morerows="1">Description</entry>
- <entry spanname="chrom">Chromaticities<footnote>
- <para>The coordinates of the color primaries are
-given in the CIE system (1931)</para>
- </footnote></entry>
- <entry morerows="1">White Point</entry>
- <entry morerows="1">Gamma Correction</entry>
- <entry morerows="1">Luminance E'<subscript>Y</subscript></entry>
- <entry spanname="quant">Quantization</entry>
- </row>
- <row>
- <entry>Red</entry>
- <entry>Green</entry>
- <entry>Blue</entry>
- <entry>Y'</entry>
- <entry>Cb, Cr</entry>
+ <entry>Identifier</entry>
+ <entry>Details</entry>
</row>
</thead>
<tbody valign="top">
<row>
<entry><constant>V4L2_COLORSPACE_SMPTE170M</constant></entry>
- <entry>1</entry>
- <entry>NTSC/PAL according to <xref linkend="smpte170m" />,
-<xref linkend="itu601" /></entry>
- <entry>x&nbsp;=&nbsp;0.630, y&nbsp;=&nbsp;0.340</entry>
- <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.595</entry>
- <entry>x&nbsp;=&nbsp;0.155, y&nbsp;=&nbsp;0.070</entry>
- <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
- Illuminant D<subscript>65</subscript></entry>
- <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
-1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
- <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
- <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
- <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+ <entry>See <xref linkend="col-smpte-170m" />.</entry>
</row>
<row>
- <entry><constant>V4L2_COLORSPACE_SMPTE240M</constant></entry>
- <entry>2</entry>
- <entry>1125-Line (US) HDTV, see <xref
-linkend="smpte240m" /></entry>
- <entry>x&nbsp;=&nbsp;0.630, y&nbsp;=&nbsp;0.340</entry>
- <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.595</entry>
- <entry>x&nbsp;=&nbsp;0.155, y&nbsp;=&nbsp;0.070</entry>
- <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
- Illuminant D<subscript>65</subscript></entry>
- <entry>E' = 4&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.0228,
-1.1115&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.1115&nbsp;for&nbsp;0.0228&nbsp;&lt;&nbsp;I</entry>
- <entry>0.212&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.701&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.087&nbsp;E'<subscript>B</subscript></entry>
- <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
- <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+ <entry><constant>V4L2_COLORSPACE_REC709</constant></entry>
+ <entry>See <xref linkend="col-rec709" />.</entry>
</row>
<row>
- <entry><constant>V4L2_COLORSPACE_REC709</constant></entry>
- <entry>3</entry>
- <entry>HDTV and modern devices, see <xref
-linkend="itu709" /></entry>
- <entry>x&nbsp;=&nbsp;0.640, y&nbsp;=&nbsp;0.330</entry>
- <entry>x&nbsp;=&nbsp;0.300, y&nbsp;=&nbsp;0.600</entry>
- <entry>x&nbsp;=&nbsp;0.150, y&nbsp;=&nbsp;0.060</entry>
- <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
- Illuminant D<subscript>65</subscript></entry>
- <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
-1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
- <entry>0.2125&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.7154&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.0721&nbsp;E'<subscript>B</subscript></entry>
- <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
- <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+ <entry><constant>V4L2_COLORSPACE_SRGB</constant></entry>
+ <entry>See <xref linkend="col-srgb" />.</entry>
</row>
<row>
- <entry><constant>V4L2_COLORSPACE_BT878</constant></entry>
- <entry>4</entry>
- <entry>Broken Bt878 extents<footnote>
- <para>The ubiquitous Bt878 video capture chip
-quantizes E'<subscript>Y</subscript> to 238 levels, yielding a range
-of Y' = 16 &hellip; 253, unlike Rec. 601 Y' = 16 &hellip;
-235. This is not a typo in the Bt878 documentation, it has been
-implemented in silicon. The chroma extents are unclear.</para>
- </footnote>, <xref linkend="itu601" /></entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
- <entry><emphasis>237</emphasis>&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
- <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128 (probably)</entry>
+ <entry><constant>V4L2_COLORSPACE_ADOBERGB</constant></entry>
+ <entry>See <xref linkend="col-adobergb" />.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORSPACE_BT2020</constant></entry>
+ <entry>See <xref linkend="col-bt2020" />.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_COLORSPACE_SMPTE240M</constant></entry>
+ <entry>See <xref linkend="col-smpte-240m" />.</entry>
</row>
<row>
<entry><constant>V4L2_COLORSPACE_470_SYSTEM_M</constant></entry>
- <entry>5</entry>
- <entry>M/NTSC<footnote>
- <para>No identifier exists for M/PAL which uses
-the chromaticities of M/NTSC, the remaining parameters are equal to B and
-G/PAL.</para>
- </footnote> according to <xref linkend="itu470" />, <xref
- linkend="itu601" /></entry>
- <entry>x&nbsp;=&nbsp;0.67, y&nbsp;=&nbsp;0.33</entry>
- <entry>x&nbsp;=&nbsp;0.21, y&nbsp;=&nbsp;0.71</entry>
- <entry>x&nbsp;=&nbsp;0.14, y&nbsp;=&nbsp;0.08</entry>
- <entry>x&nbsp;=&nbsp;0.310, y&nbsp;=&nbsp;0.316, Illuminant C</entry>
- <entry>?</entry>
- <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
- <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
- <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+ <entry>See <xref linkend="col-sysm" />.</entry>
</row>
<row>
<entry><constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant></entry>
- <entry>6</entry>
- <entry>625-line PAL and SECAM systems according to <xref
-linkend="itu470" />, <xref linkend="itu601" /></entry>
- <entry>x&nbsp;=&nbsp;0.64, y&nbsp;=&nbsp;0.33</entry>
- <entry>x&nbsp;=&nbsp;0.29, y&nbsp;=&nbsp;0.60</entry>
- <entry>x&nbsp;=&nbsp;0.15, y&nbsp;=&nbsp;0.06</entry>
- <entry>x&nbsp;=&nbsp;0.313, y&nbsp;=&nbsp;0.329,
-Illuminant D<subscript>65</subscript></entry>
- <entry>?</entry>
- <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
- <entry>219&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16</entry>
- <entry>224&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+ <entry>See <xref linkend="col-sysbg" />.</entry>
</row>
<row>
<entry><constant>V4L2_COLORSPACE_JPEG</constant></entry>
- <entry>7</entry>
- <entry>JPEG Y'CbCr, see <xref linkend="jfif" />, <xref linkend="itu601" /></entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>?</entry>
- <entry>0.299&nbsp;E'<subscript>R</subscript>
-+&nbsp;0.587&nbsp;E'<subscript>G</subscript>
-+&nbsp;0.114&nbsp;E'<subscript>B</subscript></entry>
- <entry>256&nbsp;E'<subscript>Y</subscript>&nbsp;+&nbsp;16<footnote>
- <para>Note JFIF quantizes
-Y'P<subscript>B</subscript>P<subscript>R</subscript> in range [0;+1] and
-[-0.5;+0.5] to <emphasis>257</emphasis> levels, however Y'CbCr signals
-are still clamped to [0;255].</para>
- </footnote></entry>
- <entry>256&nbsp;P<subscript>B,R</subscript>&nbsp;+&nbsp;128</entry>
+ <entry>See <xref linkend="col-jpeg" />.</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+
+ <table pgwide="1" frame="none" id="v4l2-ycbcr-encoding">
+ <title>V4L2 Y'CbCr Encodings</title>
+ <tgroup cols="2" align="left">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Details</entry>
</row>
+ </thead>
+ <tbody valign="top">
<row>
- <entry><constant>V4L2_COLORSPACE_SRGB</constant></entry>
- <entry>8</entry>
- <entry>[?]</entry>
- <entry>x&nbsp;=&nbsp;0.640, y&nbsp;=&nbsp;0.330</entry>
- <entry>x&nbsp;=&nbsp;0.300, y&nbsp;=&nbsp;0.600</entry>
- <entry>x&nbsp;=&nbsp;0.150, y&nbsp;=&nbsp;0.060</entry>
- <entry>x&nbsp;=&nbsp;0.3127, y&nbsp;=&nbsp;0.3290,
- Illuminant D<subscript>65</subscript></entry>
- <entry>E' = 4.5&nbsp;I&nbsp;for&nbsp;I&nbsp;&le;0.018,
-1.099&nbsp;I<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&lt;&nbsp;I</entry>
- <entry spanname="spam">n/a</entry>
+ <entry><constant>V4L2_YCBCR_ENC_DEFAULT</constant></entry>
+ <entry>Use the default Y'CbCr encoding as defined by the colorspace.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_601</constant></entry>
+ <entry>Use the BT.601 Y'CbCr encoding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_709</constant></entry>
+ <entry>Use the Rec. 709 Y'CbCr encoding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_XV601</constant></entry>
+ <entry>Use the extended gamut xvYCC BT.601 encoding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_XV709</constant></entry>
+ <entry>Use the extended gamut xvYCC Rec. 709 encoding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_SYCC</constant></entry>
+ <entry>Use the extended gamut sYCC encoding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_BT2020</constant></entry>
+ <entry>Use the default non-constant luminance BT.2020 Y'CbCr encoding.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_YCBCR_ENC_BT2020_CONST_LUM</constant></entry>
+ <entry>Use the constant luminance BT.2020 Yc'CbcCrc encoding.</entry>
</row>
</tbody>
</tgroup>
</table>
+
+ <table pgwide="1" frame="none" id="v4l2-quantization">
+ <title>V4L2 Quantization Methods</title>
+ <tgroup cols="2" align="left">
+ &cs-def;
+ <thead>
+ <row>
+ <entry>Identifier</entry>
+ <entry>Details</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry><constant>V4L2_QUANTIZATION_DEFAULT</constant></entry>
+ <entry>Use the default quantization encoding as defined by the colorspace.
+This is always full range for R'G'B' and usually limited range for Y'CbCr.</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_QUANTIZATION_FULL_RANGE</constant></entry>
+ <entry>Use the full range quantization encoding. I.e. the range [0&hellip;1]
+is mapped to [0&hellip;255] (with possible clipping to [1&hellip;254] to avoid the
+0x00 and 0xff values). Cb and Cr are mapped from [-0.5&hellip;0.5] to [0&hellip;255]
+(with possible clipping to [1&hellip;254] to avoid the 0x00 and 0xff values).</entry>
+ </row>
+ <row>
+ <entry><constant>V4L2_QUANTIZATION_LIM_RANGE</constant></entry>
+ <entry>Use the limited range quantization encoding. I.e. the range [0&hellip;1]
+is mapped to [16&hellip;235]. Cb and Cr are mapped from [-0.5&hellip;0.5] to [16&hellip;240].
+</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ </section>
+
+ <section>
+ <title>Detailed Colorspace Descriptions</title>
+ <section>
+ <title id="col-smpte-170m">Colorspace SMPTE 170M (<constant>V4L2_COLORSPACE_SMPTE170M</constant>)</title>
+ <para>The <xref linkend="smpte170m" /> standard defines the colorspace used by NTSC and PAL and by SDTV
+in general. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>.
+The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and
+the white reference are:</para>
+ <table frame="none">
+ <title>SMPTE 170M Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.630</entry>
+ <entry>0.340</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.310</entry>
+ <entry>0.595</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.155</entry>
+ <entry>0.070</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>The red, green and blue chromaticities are also often referred to
+as the SMPTE C set, so this colorspace is sometimes called SMPTE C as well.</para>
+ <variablelist>
+ <varlistentry>
+ <term>The transfer function defined for SMPTE 170M is the same as the
+one defined in Rec. 709. Normally L is in the range [0&hellip;1], but for the extended
+gamut xvYCC encoding values outside that range are allowed.</term>
+ <listitem>
+ <para>L' = -1.099(-L)<superscript>0.45</superscript>&nbsp;+&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&le;&nbsp;-0.018</para>
+ <para>L' = 4.5L&nbsp;for&nbsp;-0.018&nbsp;&lt;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
+ <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&ge;&nbsp;0.018</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = -((L'&nbsp;-&nbsp;0.099)&nbsp;/&nbsp;-1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&le;&nbsp;-0.081</para>
+ <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;-0.081&nbsp;&lt;&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with
+the following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
+clamped to the range [-0.5&hellip;0.5]. This conversion to Y'CbCr is identical to the one
+defined in the <xref linkend="itu601" /> standard and this colorspace is sometimes called BT.601 as well, even
+though BT.601 does not mention any color primaries.</para>
+ <para>The default quantization is limited range, but full range is possible although
+rarely seen.</para>
+ <para>The <constant>V4L2_YCBCR_ENC_601</constant> encoding as described above is the
+default for this colorspace, but it can be overridden with <constant>V4L2_YCBCR_ENC_709</constant>,
+in which case the Rec. 709 Y'CbCr encoding is used.</para>
+ <variablelist>
+ <varlistentry>
+ <term>The xvYCC 601 encoding (<constant>V4L2_YCBCR_ENC_XV601</constant>, <xref linkend="xvycc" />) is similar
+to the BT.601 encoding, but it allows for R', G' and B' values that are outside the range
+[0&hellip;1]. The resulting Y', Cb and Cr values are scaled and offset:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;(219&nbsp;/&nbsp;255)&nbsp;*&nbsp;(0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B')&nbsp;+&nbsp;(16&nbsp;/&nbsp;255)</para>
+ <para>Cb&nbsp;=&nbsp;(224&nbsp;/&nbsp;255)&nbsp;*&nbsp;(-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B')</para>
+ <para>Cr&nbsp;=&nbsp;(224&nbsp;/&nbsp;255)&nbsp;*&nbsp;(0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B')</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are clamped
+to the range [-0.5&hellip;0.5]. The non-standard xvYCC 709 encoding can also be used by selecting
+<constant>V4L2_YCBCR_ENC_XV709</constant>. The xvYCC encodings always use full range
+quantization.</para>
+ </section>
+
+ <section>
+ <title id="col-rec709">Colorspace Rec. 709 (<constant>V4L2_COLORSPACE_REC709</constant>)</title>
+ <para>The <xref linkend="itu709" /> standard defines the colorspace used by HDTV in general. The default
+Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_709</constant>. The default Y'CbCr quantization is
+limited range. The chromaticities of the primary colors and the white reference are:</para>
+ <table frame="none">
+ <title>Rec. 709 Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.640</entry>
+ <entry>0.330</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.300</entry>
+ <entry>0.600</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.150</entry>
+ <entry>0.060</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>The full name of this standard is Rec. ITU-R BT.709-5.</para>
+ <variablelist>
+ <varlistentry>
+ <term>Transfer function. Normally L is in the range [0&hellip;1], but for the extended
+gamut xvYCC encoding values outside that range are allowed.</term>
+ <listitem>
+ <para>L' = -1.099(-L)<superscript>0.45</superscript>&nbsp;+&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&le;&nbsp;-0.018</para>
+ <para>L' = 4.5L&nbsp;for&nbsp;-0.018&nbsp;&lt;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
+ <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;L&nbsp;&ge;&nbsp;0.018</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = -((L'&nbsp;-&nbsp;0.099)&nbsp;/&nbsp;-1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&le;&nbsp;-0.081</para>
+ <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;-0.081&nbsp;&lt;&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the following
+<constant>V4L2_YCBCR_ENC_709</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.2126R'&nbsp;+&nbsp;0.7152G'&nbsp;+&nbsp;0.0722B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.1146R'&nbsp;-&nbsp;0.3854G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4542G'&nbsp;-&nbsp;0.0458B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
+clamped to the range [-0.5&hellip;0.5].</para>
+ <para>The default quantization is limited range, but full range is possible although
+rarely seen.</para>
+ <para>The <constant>V4L2_YCBCR_ENC_709</constant> encoding described above is the default
+for this colorspace, but it can be overridden with <constant>V4L2_YCBCR_ENC_601</constant>, in which
+case the BT.601 Y'CbCr encoding is used.</para>
+ <variablelist>
+ <varlistentry>
+ <term>The xvYCC 709 encoding (<constant>V4L2_YCBCR_ENC_XV709</constant>, <xref linkend="xvycc" />)
+is similar to the Rec. 709 encoding, but it allows for R', G' and B' values that are outside the range
+[0&hellip;1]. The resulting Y', Cb and Cr values are scaled and offset:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;(219&nbsp;/&nbsp;255)&nbsp;*&nbsp;(0.2126R'&nbsp;+&nbsp;0.7152G'&nbsp;+&nbsp;0.0722B')&nbsp;+&nbsp;(16&nbsp;/&nbsp;255)</para>
+ <para>Cb&nbsp;=&nbsp;(224&nbsp;/&nbsp;255)&nbsp;*&nbsp;(-0.1146R'&nbsp;-&nbsp;0.3854G'&nbsp;+&nbsp;0.5B')</para>
+ <para>Cr&nbsp;=&nbsp;(224&nbsp;/&nbsp;255)&nbsp;*&nbsp;(0.5R'&nbsp;-&nbsp;0.4542G'&nbsp;-&nbsp;0.0458B')</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are clamped
+to the range [-0.5&hellip;0.5]. The non-standard xvYCC 601 encoding can also be used by
+selecting <constant>V4L2_YCBCR_ENC_XV601</constant>. The xvYCC encodings always use full
+range quantization.</para>
+ </section>
+
+ <section>
+ <title id="col-srgb">Colorspace sRGB (<constant>V4L2_COLORSPACE_SRGB</constant>)</title>
+ <para>The <xref linkend="srgb" /> standard defines the colorspace used by most webcams and computer graphics. The
+default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SYCC</constant>. The default Y'CbCr quantization
+is full range. The chromaticities of the primary colors and the white reference are:</para>
+ <table frame="none">
+ <title>sRGB Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.640</entry>
+ <entry>0.330</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.300</entry>
+ <entry>0.600</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.150</entry>
+ <entry>0.060</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>These chromaticities are identical to the Rec. 709 colorspace.</para>
+ <variablelist>
+ <varlistentry>
+ <term>Transfer function. Note that negative values for L are only used by the Y'CbCr conversion.</term>
+ <listitem>
+ <para>L' = -1.055(-L)<superscript>1/2.4</superscript>&nbsp;+&nbsp;0.055&nbsp;for&nbsp;L&nbsp;&lt;&nbsp;-0.0031308</para>
+ <para>L' = 12.92L&nbsp;for&nbsp;-0.0031308&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;0.0031308</para>
+ <para>L' = 1.055L<superscript>1/2.4</superscript>&nbsp;-&nbsp;0.055&nbsp;for&nbsp;0.0031308&nbsp;&lt;&nbsp;L&nbsp;&le;&nbsp;1</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = -((-L'&nbsp;+&nbsp;0.055)&nbsp;/&nbsp;1.055)<superscript>2.4</superscript>&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;-0.04045</para>
+ <para>L = L'&nbsp;/&nbsp;12.92&nbsp;for&nbsp;-0.04045&nbsp;&le;&nbsp;L'&nbsp;&le;&nbsp;0.04045</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.055)&nbsp;/&nbsp;1.055)<superscript>2.4</superscript>&nbsp;for&nbsp;L'&nbsp;&gt;&nbsp;0.04045</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the following
+<constant>V4L2_YCBCR_ENC_SYCC</constant> encoding as defined by <xref linkend="sycc" />:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.2990R'&nbsp;+&nbsp;0.5870G'&nbsp;+&nbsp;0.1140B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.1687R'&nbsp;-&nbsp;0.3313G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4187G'&nbsp;-&nbsp;0.0813B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are clamped
+to the range [-0.5&hellip;0.5]. The <constant>V4L2_YCBCR_ENC_SYCC</constant> quantization is always
+full range. Although this Y'CbCr encoding looks very similar to the <constant>V4L2_YCBCR_ENC_XV601</constant>
+encoding, it is not. The <constant>V4L2_YCBCR_ENC_XV601</constant> scales and offsets the Y'CbCr
+values before quantization, but this encoding does not do that.</para>
+ </section>
+
+ <section>
+ <title id="col-adobergb">Colorspace Adobe RGB (<constant>V4L2_COLORSPACE_ADOBERGB</constant>)</title>
+ <para>The <xref linkend="adobergb" /> standard defines the colorspace used by computer graphics
+that use the AdobeRGB colorspace. This is also known as the <xref linkend="oprgb" /> standard.
+The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr
+quantization is limited range. The chromaticities of the primary colors and the white reference
+are:</para>
+ <table frame="none">
+ <title>Adobe RGB Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.6400</entry>
+ <entry>0.3300</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.2100</entry>
+ <entry>0.7100</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.1500</entry>
+ <entry>0.0600</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <variablelist>
+ <varlistentry>
+ <term>Transfer function:</term>
+ <listitem>
+ <para>L' = L<superscript>1/2.19921875</superscript></para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = L'<superscript>2.19921875</superscript></para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
+following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
+clamped to the range [-0.5&hellip;0.5]. This transform is identical to one defined in
+SMPTE 170M/BT.601. The Y'CbCr quantization is limited range.</para>
+ </section>
+
+ <section>
+ <title id="col-bt2020">Colorspace BT.2020 (<constant>V4L2_COLORSPACE_BT2020</constant>)</title>
+ <para>The <xref linkend="itu2020" /> standard defines the colorspace used by Ultra-high definition
+television (UHDTV). The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_BT2020</constant>.
+The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and
+the white reference are:</para>
+ <table frame="none">
+ <title>BT.2020 Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.708</entry>
+ <entry>0.292</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.170</entry>
+ <entry>0.797</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.131</entry>
+ <entry>0.046</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <variablelist>
+ <varlistentry>
+ <term>Transfer function (same as Rec. 709):</term>
+ <listitem>
+ <para>L' = 4.5L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
+ <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
+following <constant>V4L2_YCBCR_ENC_BT2020</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.2627R'&nbsp;+&nbsp;0.6789G'&nbsp;+&nbsp;0.0593B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.1396R'&nbsp;-&nbsp;0.3604G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4598G'&nbsp;-&nbsp;0.0402B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
+clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.</para>
+ <para>There is also an alternate constant luminance R'G'B' to Yc'CbcCrc
+(<constant>V4L2_YCBCR_ENC_BT2020_CONST_LUM</constant>) encoding:</para>
+ <variablelist>
+ <varlistentry>
+ <term>Luma:</term>
+ <listitem>
+ <para>Yc'&nbsp;=&nbsp;(0.2627R&nbsp;+&nbsp;0.6789G&nbsp;+&nbsp;0.0593B)'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>B'&nbsp;-&nbsp;Yc'&nbsp;&le;&nbsp;0:</term>
+ <listitem>
+ <para>Cbc&nbsp;=&nbsp;(B'&nbsp;-&nbsp;Y')&nbsp;/&nbsp;1.9404</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>B'&nbsp;-&nbsp;Yc'&nbsp;&gt;&nbsp;0:</term>
+ <listitem>
+ <para>Cbc&nbsp;=&nbsp;(B'&nbsp;-&nbsp;Y')&nbsp;/&nbsp;1.5816</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>R'&nbsp;-&nbsp;Yc'&nbsp;&le;&nbsp;0:</term>
+ <listitem>
+ <para>Crc&nbsp;=&nbsp;(R'&nbsp;-&nbsp;Y')&nbsp;/&nbsp;1.7184</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>R'&nbsp;-&nbsp;Yc'&nbsp;&gt;&nbsp;0:</term>
+ <listitem>
+ <para>Crc&nbsp;=&nbsp;(R'&nbsp;-&nbsp;Y')&nbsp;/&nbsp;0.9936</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Yc' is clamped to the range [0&hellip;1] and Cbc and Crc are
+clamped to the range [-0.5&hellip;0.5]. The Yc'CbcCrc quantization is limited range.</para>
+ </section>
+
+ <section>
+ <title id="col-smpte-240m">Colorspace SMPTE 240M (<constant>V4L2_COLORSPACE_SMPTE240M</constant>)</title>
+ <para>The <xref linkend="smpte240m" /> standard was an interim standard used during the early days of HDTV (1988-1998).
+It has been superseded by Rec. 709. The default Y'CbCr encoding is <constant>V4L2_YCBCR_ENC_SMPTE240M</constant>.
+The default Y'CbCr quantization is limited range. The chromaticities of the primary colors and the
+white reference are:</para>
+ <table frame="none">
+ <title>SMPTE 240M Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.630</entry>
+ <entry>0.340</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.310</entry>
+ <entry>0.595</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.155</entry>
+ <entry>0.070</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>These chromaticities are identical to the SMPTE 170M colorspace.</para>
+ <variablelist>
+ <varlistentry>
+ <term>Transfer function:</term>
+ <listitem>
+ <para>L' = 4L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.0228</para>
+ <para>L' = 1.1115L<superscript>0.45</superscript>&nbsp;-&nbsp;0.1115&nbsp;for&nbsp;0.0228&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = L'&nbsp;/&nbsp;4&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L'&nbsp;&lt;&nbsp;0.0913</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.1115)&nbsp;/&nbsp;1.1115)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.0913</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
+following <constant>V4L2_YCBCR_ENC_SMPTE240M</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.2122R'&nbsp;+&nbsp;0.7013G'&nbsp;+&nbsp;0.0865B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.1161R'&nbsp;-&nbsp;0.3839G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.4451G'&nbsp;-&nbsp;0.0549B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Yc' is clamped to the range [0&hellip;1] and Cbc and Crc are
+clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.</para>
+ </section>
+
+ <section>
+ <title id="col-sysm">Colorspace NTSC 1953 (<constant>V4L2_COLORSPACE_470_SYSTEM_M</constant>)</title>
+ <para>This standard defines the colorspace used by NTSC in 1953. In practice this
+colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding
+is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range.
+The chromaticities of the primary colors and the white reference are:</para>
+ <table frame="none">
+ <title>NTSC 1953 Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.67</entry>
+ <entry>0.33</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.21</entry>
+ <entry>0.71</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.14</entry>
+ <entry>0.08</entry>
+ </row>
+ <row>
+ <entry>White Reference (C)</entry>
+ <entry>0.310</entry>
+ <entry>0.316</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <para>Note that this colorspace uses Illuminant C instead of D65 as the
+white reference. To correctly convert an image in this colorspace to another
+that uses D65 you need to apply a chromatic adaptation algorithm such as the
+Bradford method.</para>
+ <variablelist>
+ <varlistentry>
+ <term>The transfer function was never properly defined for NTSC 1953. The
+Rec. 709 transfer function is recommended in the literature:</term>
+ <listitem>
+ <para>L' = 4.5L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
+ <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
+following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
+clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.
+This transform is identical to one defined in SMPTE 170M/BT.601.</para>
+ </section>
+
+ <section>
+ <title id="col-sysbg">Colorspace EBU Tech. 3213 (<constant>V4L2_COLORSPACE_470_SYSTEM_BG</constant>)</title>
+ <para>The <xref linkend="tech3213" /> standard defines the colorspace used by PAL/SECAM in 1975. In practice this
+colorspace is obsolete and SMPTE 170M should be used instead. The default Y'CbCr encoding
+is <constant>V4L2_YCBCR_ENC_601</constant>. The default Y'CbCr quantization is limited range.
+The chromaticities of the primary colors and the white reference are:</para>
+ <table frame="none">
+ <title>EBU Tech. 3213 Chromaticities</title>
+ <tgroup cols="3" align="left">
+ &cs-str;
+ <thead>
+ <row>
+ <entry>Color</entry>
+ <entry>x</entry>
+ <entry>y</entry>
+ </row>
+ </thead>
+ <tbody valign="top">
+ <row>
+ <entry>Red</entry>
+ <entry>0.64</entry>
+ <entry>0.33</entry>
+ </row>
+ <row>
+ <entry>Green</entry>
+ <entry>0.29</entry>
+ <entry>0.60</entry>
+ </row>
+ <row>
+ <entry>Blue</entry>
+ <entry>0.15</entry>
+ <entry>0.06</entry>
+ </row>
+ <row>
+ <entry>White Reference (D65)</entry>
+ <entry>0.3127</entry>
+ <entry>0.3290</entry>
+ </row>
+ </tbody>
+ </tgroup>
+ </table>
+ <variablelist>
+ <varlistentry>
+ <term>The transfer function was never properly defined for this colorspace.
+The Rec. 709 transfer function is recommended in the literature:</term>
+ <listitem>
+ <para>L' = 4.5L&nbsp;for&nbsp;0&nbsp;&le;&nbsp;L&nbsp;&lt;&nbsp;0.018</para>
+ <para>L' = 1.099L<superscript>0.45</superscript>&nbsp;-&nbsp;0.099&nbsp;for&nbsp;0.018&nbsp;&le;&nbsp;L&nbsp;&le;&nbsp;1</para>
+ </listitem>
+ </varlistentry>
+ <varlistentry>
+ <term>Inverse Transfer function:</term>
+ <listitem>
+ <para>L = L'&nbsp;/&nbsp;4.5&nbsp;for&nbsp;L'&nbsp;&lt;&nbsp;0.081</para>
+ <para>L = ((L'&nbsp;+&nbsp;0.099)&nbsp;/&nbsp;1.099)<superscript>1/0.45</superscript>&nbsp;for&nbsp;L'&nbsp;&ge;&nbsp;0.081</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <variablelist>
+ <varlistentry>
+ <term>The luminance (Y') and color difference (Cb and Cr) are obtained with the
+following <constant>V4L2_YCBCR_ENC_601</constant> encoding:</term>
+ <listitem>
+ <para>Y'&nbsp;=&nbsp;0.299R'&nbsp;+&nbsp;0.587G'&nbsp;+&nbsp;0.114B'</para>
+ <para>Cb&nbsp;=&nbsp;-0.169R'&nbsp;-&nbsp;0.331G'&nbsp;+&nbsp;0.5B'</para>
+ <para>Cr&nbsp;=&nbsp;0.5R'&nbsp;-&nbsp;0.419G'&nbsp;-&nbsp;0.081B'</para>
+ </listitem>
+ </varlistentry>
+ </variablelist>
+ <para>Y' is clamped to the range [0&hellip;1] and Cb and Cr are
+clamped to the range [-0.5&hellip;0.5]. The Y'CbCr quantization is limited range.
+This transform is identical to one defined in SMPTE 170M/BT.601.</para>
+ </section>
+
+ <section>
+ <title id="col-jpeg">Colorspace JPEG (<constant>V4L2_COLORSPACE_JPEG</constant>)</title>
+ <para>This colorspace defines the colorspace used by most (Motion-)JPEG formats. The chromaticities
+of the primary colors and the white reference are identical to sRGB. The Y'CbCr encoding is
+<constant>V4L2_YCBCR_ENC_601</constant> with full range quantization where
+Y' is scaled to [0&hellip;255] and Cb/Cr are scaled to [-128&hellip;128] and
+then clipped to [-128&hellip;127].</para>
+ <para>Note that the JPEG standard does not actually store colorspace information.
+So if something other than sRGB is used, then the driver will have to set that information
+explicitly. Effectively <constant>V4L2_COLORSPACE_JPEG</constant> can be considered to be
+an abbreviation for <constant>V4L2_COLORSPACE_SRGB</constant>, <constant>V4L2_YCBCR_ENC_601</constant>
+and <constant>V4L2_QUANTIZATION_FULL_RANGE</constant>.</para>
+ </section>
+
</section>
<section id="pixfmt-indexed">
diff --git a/Documentation/DocBook/media/v4l/selections-common.xml b/Documentation/DocBook/media/v4l/selections-common.xml
index 7502f78..d6d56fb 100644
--- a/Documentation/DocBook/media/v4l/selections-common.xml
+++ b/Documentation/DocBook/media/v4l/selections-common.xml
@@ -63,6 +63,22 @@
<entry>Yes</entry>
</row>
<row>
+ <entry><constant>V4L2_SEL_TGT_NATIVE_SIZE</constant></entry>
+ <entry>0x0003</entry>
+ <entry>The native size of the device, e.g. a sensor's
+ pixel array. <structfield>left</structfield> and
+ <structfield>top</structfield> fields are zero for this
+ target. Setting the native size will generally only make
+ sense for memory to memory devices where the software can
+ create a canvas of a given size in which for example a
+ video frame can be composed. In that case
+ V4L2_SEL_TGT_NATIVE_SIZE can be used to configure the size
+ of that canvas.
+ </entry>
+ <entry>Yes</entry>
+ <entry>Yes</entry>
+ </row>
+ <row>
<entry><constant>V4L2_SEL_TGT_COMPOSE</constant></entry>
<entry>0x0100</entry>
<entry>Compose rectangle. Used to configure scaling
diff --git a/Documentation/DocBook/media/v4l/subdev-formats.xml b/Documentation/DocBook/media/v4l/subdev-formats.xml
index b2d5a03..18730b9 100644
--- a/Documentation/DocBook/media/v4l/subdev-formats.xml
+++ b/Documentation/DocBook/media/v4l/subdev-formats.xml
@@ -86,7 +86,7 @@
green and 5-bit blue values padded on the high bit, transferred as 2 8-bit
samples per pixel with the most significant bits (padding, red and half of
the green value) transferred first will be named
- <constant>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</constant>.
+ <constant>MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE</constant>.
</para>
<para>The following tables list existing packed RGB formats.</para>
@@ -176,8 +176,8 @@
</row>
</thead>
<tbody valign="top">
- <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-BE">
- <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE</entry>
+ <row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-BE">
+ <entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE</entry>
<entry>0x1001</entry>
<entry></entry>
&dash-ent-24;
@@ -204,8 +204,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB444-2X8-PADHI-LE">
- <entry>V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE</entry>
+ <row id="MEDIA-BUS-FMT-RGB444-2X8-PADHI-LE">
+ <entry>MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE</entry>
<entry>0x1002</entry>
<entry></entry>
&dash-ent-24;
@@ -232,8 +232,8 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-BE">
- <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE</entry>
+ <row id="MEDIA-BUS-FMT-RGB555-2X8-PADHI-BE">
+ <entry>MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE</entry>
<entry>0x1003</entry>
<entry></entry>
&dash-ent-24;
@@ -260,8 +260,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB555-2X8-PADHI-LE">
- <entry>V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE</entry>
+ <row id="MEDIA-BUS-FMT-RGB555-2X8-PADHI-LE">
+ <entry>MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE</entry>
<entry>0x1004</entry>
<entry></entry>
&dash-ent-24;
@@ -288,8 +288,8 @@
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-BGR565-2X8-BE">
- <entry>V4L2_MBUS_FMT_BGR565_2X8_BE</entry>
+ <row id="MEDIA-BUS-FMT-BGR565-2X8-BE">
+ <entry>MEDIA_BUS_FMT_BGR565_2X8_BE</entry>
<entry>0x1005</entry>
<entry></entry>
&dash-ent-24;
@@ -316,8 +316,8 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-BGR565-2X8-LE">
- <entry>V4L2_MBUS_FMT_BGR565_2X8_LE</entry>
+ <row id="MEDIA-BUS-FMT-BGR565-2X8-LE">
+ <entry>MEDIA_BUS_FMT_BGR565_2X8_LE</entry>
<entry>0x1006</entry>
<entry></entry>
&dash-ent-24;
@@ -344,8 +344,8 @@
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB565-2X8-BE">
- <entry>V4L2_MBUS_FMT_RGB565_2X8_BE</entry>
+ <row id="MEDIA-BUS-FMT-RGB565-2X8-BE">
+ <entry>MEDIA_BUS_FMT_RGB565_2X8_BE</entry>
<entry>0x1007</entry>
<entry></entry>
&dash-ent-24;
@@ -372,8 +372,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB565-2X8-LE">
- <entry>V4L2_MBUS_FMT_RGB565_2X8_LE</entry>
+ <row id="MEDIA-BUS-FMT-RGB565-2X8-LE">
+ <entry>MEDIA_BUS_FMT_RGB565_2X8_LE</entry>
<entry>0x1008</entry>
<entry></entry>
&dash-ent-24;
@@ -400,8 +400,8 @@
<entry>g<subscript>4</subscript></entry>
<entry>g<subscript>3</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB666-1X18">
- <entry>V4L2_MBUS_FMT_RGB666_1X18</entry>
+ <row id="MEDIA-BUS-FMT-RGB666-1X18">
+ <entry>MEDIA_BUS_FMT_RGB666_1X18</entry>
<entry>0x1009</entry>
<entry></entry>
&dash-ent-14;
@@ -424,8 +424,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB888-1X24">
- <entry>V4L2_MBUS_FMT_RGB888_1X24</entry>
+ <row id="MEDIA-BUS-FMT-RGB888-1X24">
+ <entry>MEDIA_BUS_FMT_RGB888_1X24</entry>
<entry>0x100a</entry>
<entry></entry>
&dash-ent-8;
@@ -454,8 +454,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB888-2X12-BE">
- <entry>V4L2_MBUS_FMT_RGB888_2X12_BE</entry>
+ <row id="MEDIA-BUS-FMT-RGB888-2X12-BE">
+ <entry>MEDIA_BUS_FMT_RGB888_2X12_BE</entry>
<entry>0x100b</entry>
<entry></entry>
&dash-ent-20;
@@ -490,8 +490,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-RGB888-2X12-LE">
- <entry>V4L2_MBUS_FMT_RGB888_2X12_LE</entry>
+ <row id="MEDIA-BUS-FMT-RGB888-2X12-LE">
+ <entry>MEDIA_BUS_FMT_RGB888_2X12_LE</entry>
<entry>0x100c</entry>
<entry></entry>
&dash-ent-20;
@@ -526,8 +526,8 @@
<entry>g<subscript>5</subscript></entry>
<entry>g<subscript>4</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-ARGB888-1X32">
- <entry>V4L2_MBUS_FMT_ARGB888_1X32</entry>
+ <row id="MEDIA-BUS-FMT-ARGB888-1X32">
+ <entry>MEDIA_BUS_FMT_ARGB888_1X32</entry>
<entry>0x100d</entry>
<entry></entry>
<entry>a<subscript>7</subscript></entry>
@@ -600,7 +600,7 @@
<para>For instance, a format with uncompressed 10-bit Bayer components
arranged in a red, green, green, blue pattern transferred as 2 8-bit
samples per pixel with the least significant bits transferred first will
- be named <constant>V4L2_MBUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
+ be named <constant>MEDIA_BUS_FMT_SRGGB10_2X8_PADHI_LE</constant>.
</para>
<figure id="bayer-patterns">
@@ -663,8 +663,8 @@
</row>
</thead>
<tbody valign="top">
- <row id="V4L2-MBUS-FMT-SBGGR8-1X8">
- <entry>V4L2_MBUS_FMT_SBGGR8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR8-1X8">
+ <entry>MEDIA_BUS_FMT_SBGGR8_1X8</entry>
<entry>0x3001</entry>
<entry></entry>
<entry>-</entry>
@@ -680,8 +680,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGBRG8-1X8">
- <entry>V4L2_MBUS_FMT_SGBRG8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SGBRG8-1X8">
+ <entry>MEDIA_BUS_FMT_SGBRG8_1X8</entry>
<entry>0x3013</entry>
<entry></entry>
<entry>-</entry>
@@ -697,8 +697,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGRBG8-1X8">
- <entry>V4L2_MBUS_FMT_SGRBG8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SGRBG8-1X8">
+ <entry>MEDIA_BUS_FMT_SGRBG8_1X8</entry>
<entry>0x3002</entry>
<entry></entry>
<entry>-</entry>
@@ -714,8 +714,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SRGGB8-1X8">
- <entry>V4L2_MBUS_FMT_SRGGB8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SRGGB8-1X8">
+ <entry>MEDIA_BUS_FMT_SRGGB8_1X8</entry>
<entry>0x3014</entry>
<entry></entry>
<entry>-</entry>
@@ -731,8 +731,8 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-ALAW8-1X8">
- <entry>V4L2_MBUS_FMT_SBGGR10_ALAW8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-ALAW8-1X8">
+ <entry>MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8</entry>
<entry>0x3015</entry>
<entry></entry>
<entry>-</entry>
@@ -748,8 +748,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGBRG10-ALAW8-1X8">
- <entry>V4L2_MBUS_FMT_SGBRG10_ALAW8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SGBRG10-ALAW8-1X8">
+ <entry>MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8</entry>
<entry>0x3016</entry>
<entry></entry>
<entry>-</entry>
@@ -765,8 +765,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGRBG10-ALAW8-1X8">
- <entry>V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SGRBG10-ALAW8-1X8">
+ <entry>MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8</entry>
<entry>0x3017</entry>
<entry></entry>
<entry>-</entry>
@@ -782,8 +782,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SRGGB10-ALAW8-1X8">
- <entry>V4L2_MBUS_FMT_SRGGB10_ALAW8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SRGGB10-ALAW8-1X8">
+ <entry>MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8</entry>
<entry>0x3018</entry>
<entry></entry>
<entry>-</entry>
@@ -799,8 +799,8 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-DPCM8-1X8">
- <entry>V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-DPCM8-1X8">
+ <entry>MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8</entry>
<entry>0x300b</entry>
<entry></entry>
<entry>-</entry>
@@ -816,8 +816,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGBRG10-DPCM8-1X8">
- <entry>V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SGBRG10-DPCM8-1X8">
+ <entry>MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8</entry>
<entry>0x300c</entry>
<entry></entry>
<entry>-</entry>
@@ -833,8 +833,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGRBG10-DPCM8-1X8">
- <entry>V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SGRBG10-DPCM8-1X8">
+ <entry>MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8</entry>
<entry>0x3009</entry>
<entry></entry>
<entry>-</entry>
@@ -850,8 +850,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SRGGB10-DPCM8-1X8">
- <entry>V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-SRGGB10-DPCM8-1X8">
+ <entry>MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8</entry>
<entry>0x300d</entry>
<entry></entry>
<entry>-</entry>
@@ -867,8 +867,8 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-BE">
- <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADHI-BE">
+ <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE</entry>
<entry>0x3003</entry>
<entry></entry>
<entry>-</entry>
@@ -901,8 +901,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADHI-LE">
- <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADHI-LE">
+ <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE</entry>
<entry>0x3004</entry>
<entry></entry>
<entry>-</entry>
@@ -935,8 +935,8 @@
<entry>b<subscript>9</subscript></entry>
<entry>b<subscript>8</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-BE">
- <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADLO-BE">
+ <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE</entry>
<entry>0x3005</entry>
<entry></entry>
<entry>-</entry>
@@ -969,8 +969,8 @@
<entry>0</entry>
<entry>0</entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-2X8-PADLO-LE">
- <entry>V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-2X8-PADLO-LE">
+ <entry>MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE</entry>
<entry>0x3006</entry>
<entry></entry>
<entry>-</entry>
@@ -1003,8 +1003,8 @@
<entry>b<subscript>3</subscript></entry>
<entry>b<subscript>2</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR10-1X10">
- <entry>V4L2_MBUS_FMT_SBGGR10_1X10</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR10-1X10">
+ <entry>MEDIA_BUS_FMT_SBGGR10_1X10</entry>
<entry>0x3007</entry>
<entry></entry>
<entry>-</entry>
@@ -1020,8 +1020,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGBRG10-1X10">
- <entry>V4L2_MBUS_FMT_SGBRG10_1X10</entry>
+ <row id="MEDIA-BUS-FMT-SGBRG10-1X10">
+ <entry>MEDIA_BUS_FMT_SGBRG10_1X10</entry>
<entry>0x300e</entry>
<entry></entry>
<entry>-</entry>
@@ -1037,8 +1037,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGRBG10-1X10">
- <entry>V4L2_MBUS_FMT_SGRBG10_1X10</entry>
+ <row id="MEDIA-BUS-FMT-SGRBG10-1X10">
+ <entry>MEDIA_BUS_FMT_SGRBG10_1X10</entry>
<entry>0x300a</entry>
<entry></entry>
<entry>-</entry>
@@ -1054,8 +1054,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SRGGB10-1X10">
- <entry>V4L2_MBUS_FMT_SRGGB10_1X10</entry>
+ <row id="MEDIA-BUS-FMT-SRGGB10-1X10">
+ <entry>MEDIA_BUS_FMT_SRGGB10_1X10</entry>
<entry>0x300f</entry>
<entry></entry>
<entry>-</entry>
@@ -1071,8 +1071,8 @@
<entry>r<subscript>1</subscript></entry>
<entry>r<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SBGGR12-1X12">
- <entry>V4L2_MBUS_FMT_SBGGR12_1X12</entry>
+ <row id="MEDIA-BUS-FMT-SBGGR12-1X12">
+ <entry>MEDIA_BUS_FMT_SBGGR12_1X12</entry>
<entry>0x3008</entry>
<entry></entry>
<entry>b<subscript>11</subscript></entry>
@@ -1088,8 +1088,8 @@
<entry>b<subscript>1</subscript></entry>
<entry>b<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGBRG12-1X12">
- <entry>V4L2_MBUS_FMT_SGBRG12_1X12</entry>
+ <row id="MEDIA-BUS-FMT-SGBRG12-1X12">
+ <entry>MEDIA_BUS_FMT_SGBRG12_1X12</entry>
<entry>0x3010</entry>
<entry></entry>
<entry>g<subscript>11</subscript></entry>
@@ -1105,8 +1105,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SGRBG12-1X12">
- <entry>V4L2_MBUS_FMT_SGRBG12_1X12</entry>
+ <row id="MEDIA-BUS-FMT-SGRBG12-1X12">
+ <entry>MEDIA_BUS_FMT_SGRBG12_1X12</entry>
<entry>0x3011</entry>
<entry></entry>
<entry>g<subscript>11</subscript></entry>
@@ -1122,8 +1122,8 @@
<entry>g<subscript>1</subscript></entry>
<entry>g<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-SRGGB12-1X12">
- <entry>V4L2_MBUS_FMT_SRGGB12_1X12</entry>
+ <row id="MEDIA-BUS-FMT-SRGGB12-1X12">
+ <entry>MEDIA_BUS_FMT_SRGGB12_1X12</entry>
<entry>0x3012</entry>
<entry></entry>
<entry>r<subscript>11</subscript></entry>
@@ -1175,7 +1175,7 @@
<para>For instance, a format where pixels are encoded as 8-bit YUV values
downsampled to 4:2:2 and transferred as 2 8-bit bus samples per pixel in the
- U, Y, V, Y order will be named <constant>V4L2_MBUS_FMT_UYVY8_2X8</constant>.
+ U, Y, V, Y order will be named <constant>MEDIA_BUS_FMT_UYVY8_2X8</constant>.
</para>
<para><xref linkend="v4l2-mbus-pixelcode-yuv8"/> lists existing packed YUV
@@ -1280,8 +1280,8 @@
</row>
</thead>
<tbody valign="top">
- <row id="V4L2-MBUS-FMT-Y8-1X8">
- <entry>V4L2_MBUS_FMT_Y8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-Y8-1X8">
+ <entry>MEDIA_BUS_FMT_Y8_1X8</entry>
<entry>0x2001</entry>
<entry></entry>
&dash-ent-24;
@@ -1294,8 +1294,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UV8-1X8">
- <entry>V4L2_MBUS_FMT_UV8_1X8</entry>
+ <row id="MEDIA-BUS-FMT-UV8-1X8">
+ <entry>MEDIA_BUS_FMT_UV8_1X8</entry>
<entry>0x2015</entry>
<entry></entry>
&dash-ent-24;
@@ -1322,8 +1322,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY8-1_5X8">
- <entry>V4L2_MBUS_FMT_UYVY8_1_5X8</entry>
+ <row id="MEDIA-BUS-FMT-UYVY8-1_5X8">
+ <entry>MEDIA_BUS_FMT_UYVY8_1_5X8</entry>
<entry>0x2002</entry>
<entry></entry>
&dash-ent-24;
@@ -1406,8 +1406,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY8-1_5X8">
- <entry>V4L2_MBUS_FMT_VYUY8_1_5X8</entry>
+ <row id="MEDIA-BUS-FMT-VYUY8-1_5X8">
+ <entry>MEDIA_BUS_FMT_VYUY8_1_5X8</entry>
<entry>0x2003</entry>
<entry></entry>
&dash-ent-24;
@@ -1490,8 +1490,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV8-1_5X8">
- <entry>V4L2_MBUS_FMT_YUYV8_1_5X8</entry>
+ <row id="MEDIA-BUS-FMT-YUYV8-1_5X8">
+ <entry>MEDIA_BUS_FMT_YUYV8_1_5X8</entry>
<entry>0x2004</entry>
<entry></entry>
&dash-ent-24;
@@ -1574,8 +1574,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU8-1_5X8">
- <entry>V4L2_MBUS_FMT_YVYU8_1_5X8</entry>
+ <row id="MEDIA-BUS-FMT-YVYU8-1_5X8">
+ <entry>MEDIA_BUS_FMT_YVYU8_1_5X8</entry>
<entry>0x2005</entry>
<entry></entry>
&dash-ent-24;
@@ -1658,8 +1658,8 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY8-2X8">
- <entry>V4L2_MBUS_FMT_UYVY8_2X8</entry>
+ <row id="MEDIA-BUS-FMT-UYVY8-2X8">
+ <entry>MEDIA_BUS_FMT_UYVY8_2X8</entry>
<entry>0x2006</entry>
<entry></entry>
&dash-ent-24;
@@ -1714,8 +1714,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY8-2X8">
- <entry>V4L2_MBUS_FMT_VYUY8_2X8</entry>
+ <row id="MEDIA-BUS-FMT-VYUY8-2X8">
+ <entry>MEDIA_BUS_FMT_VYUY8_2X8</entry>
<entry>0x2007</entry>
<entry></entry>
&dash-ent-24;
@@ -1770,8 +1770,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV8-2X8">
- <entry>V4L2_MBUS_FMT_YUYV8_2X8</entry>
+ <row id="MEDIA-BUS-FMT-YUYV8-2X8">
+ <entry>MEDIA_BUS_FMT_YUYV8_2X8</entry>
<entry>0x2008</entry>
<entry></entry>
&dash-ent-24;
@@ -1826,8 +1826,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU8-2X8">
- <entry>V4L2_MBUS_FMT_YVYU8_2X8</entry>
+ <row id="MEDIA-BUS-FMT-YVYU8-2X8">
+ <entry>MEDIA_BUS_FMT_YVYU8_2X8</entry>
<entry>0x2009</entry>
<entry></entry>
&dash-ent-24;
@@ -1882,8 +1882,8 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-Y10-1X10">
- <entry>V4L2_MBUS_FMT_Y10_1X10</entry>
+ <row id="MEDIA-BUS-FMT-Y10-1X10">
+ <entry>MEDIA_BUS_FMT_Y10_1X10</entry>
<entry>0x200a</entry>
<entry></entry>
&dash-ent-22;
@@ -1898,8 +1898,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY10-2X10">
- <entry>V4L2_MBUS_FMT_UYVY10_2X10</entry>
+ <row id="MEDIA-BUS-FMT-UYVY10-2X10">
+ <entry>MEDIA_BUS_FMT_UYVY10_2X10</entry>
<entry>0x2018</entry>
<entry></entry>
&dash-ent-22;
@@ -1962,8 +1962,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY10-2X10">
- <entry>V4L2_MBUS_FMT_VYUY10_2X10</entry>
+ <row id="MEDIA-BUS-FMT-VYUY10-2X10">
+ <entry>MEDIA_BUS_FMT_VYUY10_2X10</entry>
<entry>0x2019</entry>
<entry></entry>
&dash-ent-22;
@@ -2026,8 +2026,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV10-2X10">
- <entry>V4L2_MBUS_FMT_YUYV10_2X10</entry>
+ <row id="MEDIA-BUS-FMT-YUYV10-2X10">
+ <entry>MEDIA_BUS_FMT_YUYV10_2X10</entry>
<entry>0x200b</entry>
<entry></entry>
&dash-ent-22;
@@ -2090,8 +2090,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU10-2X10">
- <entry>V4L2_MBUS_FMT_YVYU10_2X10</entry>
+ <row id="MEDIA-BUS-FMT-YVYU10-2X10">
+ <entry>MEDIA_BUS_FMT_YVYU10_2X10</entry>
<entry>0x200c</entry>
<entry></entry>
&dash-ent-22;
@@ -2154,8 +2154,8 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-Y12-1X12">
- <entry>V4L2_MBUS_FMT_Y12_1X12</entry>
+ <row id="MEDIA-BUS-FMT-Y12-1X12">
+ <entry>MEDIA_BUS_FMT_Y12_1X12</entry>
<entry>0x2013</entry>
<entry></entry>
&dash-ent-20;
@@ -2172,8 +2172,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY8-1X16">
- <entry>V4L2_MBUS_FMT_UYVY8_1X16</entry>
+ <row id="MEDIA-BUS-FMT-UYVY8-1X16">
+ <entry>MEDIA_BUS_FMT_UYVY8_1X16</entry>
<entry>0x200f</entry>
<entry></entry>
&dash-ent-16;
@@ -2216,8 +2216,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY8-1X16">
- <entry>V4L2_MBUS_FMT_VYUY8_1X16</entry>
+ <row id="MEDIA-BUS-FMT-VYUY8-1X16">
+ <entry>MEDIA_BUS_FMT_VYUY8_1X16</entry>
<entry>0x2010</entry>
<entry></entry>
&dash-ent-16;
@@ -2260,8 +2260,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV8-1X16">
- <entry>V4L2_MBUS_FMT_YUYV8_1X16</entry>
+ <row id="MEDIA-BUS-FMT-YUYV8-1X16">
+ <entry>MEDIA_BUS_FMT_YUYV8_1X16</entry>
<entry>0x2011</entry>
<entry></entry>
&dash-ent-16;
@@ -2304,8 +2304,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU8-1X16">
- <entry>V4L2_MBUS_FMT_YVYU8_1X16</entry>
+ <row id="MEDIA-BUS-FMT-YVYU8-1X16">
+ <entry>MEDIA_BUS_FMT_YVYU8_1X16</entry>
<entry>0x2012</entry>
<entry></entry>
&dash-ent-16;
@@ -2348,8 +2348,8 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YDYUYDYV8-1X16">
- <entry>V4L2_MBUS_FMT_YDYUYDYV8_1X16</entry>
+ <row id="MEDIA-BUS-FMT-YDYUYDYV8-1X16">
+ <entry>MEDIA_BUS_FMT_YDYUYDYV8_1X16</entry>
<entry>0x2014</entry>
<entry></entry>
&dash-ent-16;
@@ -2436,8 +2436,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY10-1X20">
- <entry>V4L2_MBUS_FMT_UYVY10_1X20</entry>
+ <row id="MEDIA-BUS-FMT-UYVY10-1X20">
+ <entry>MEDIA_BUS_FMT_UYVY10_1X20</entry>
<entry>0x201a</entry>
<entry></entry>
&dash-ent-12;
@@ -2488,8 +2488,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY10-1X20">
- <entry>V4L2_MBUS_FMT_VYUY10_1X20</entry>
+ <row id="MEDIA-BUS-FMT-VYUY10-1X20">
+ <entry>MEDIA_BUS_FMT_VYUY10_1X20</entry>
<entry>0x201b</entry>
<entry></entry>
&dash-ent-12;
@@ -2540,8 +2540,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV10-1X20">
- <entry>V4L2_MBUS_FMT_YUYV10_1X20</entry>
+ <row id="MEDIA-BUS-FMT-YUYV10-1X20">
+ <entry>MEDIA_BUS_FMT_YUYV10_1X20</entry>
<entry>0x200d</entry>
<entry></entry>
&dash-ent-12;
@@ -2592,8 +2592,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU10-1X20">
- <entry>V4L2_MBUS_FMT_YVYU10_1X20</entry>
+ <row id="MEDIA-BUS-FMT-YVYU10-1X20">
+ <entry>MEDIA_BUS_FMT_YVYU10_1X20</entry>
<entry>0x200e</entry>
<entry></entry>
&dash-ent-12;
@@ -2644,8 +2644,8 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUV10-1X30">
- <entry>V4L2_MBUS_FMT_YUV10_1X30</entry>
+ <row id="MEDIA-BUS-FMT-YUV10-1X30">
+ <entry>MEDIA_BUS_FMT_YUV10_1X30</entry>
<entry>0x2016</entry>
<entry></entry>
<entry>-</entry>
@@ -2681,8 +2681,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-AYUV8-1X32">
- <entry>V4L2_MBUS_FMT_AYUV8_1X32</entry>
+ <row id="MEDIA-BUS-FMT-AYUV8-1X32">
+ <entry>MEDIA_BUS_FMT_AYUV8_1X32</entry>
<entry>0x2017</entry>
<entry></entry>
<entry>a<subscript>7</subscript></entry>
@@ -2718,8 +2718,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY12-2X12">
- <entry>V4L2_MBUS_FMT_UYVY12_2X12</entry>
+ <row id="MEDIA-BUS-FMT-UYVY12-2X12">
+ <entry>MEDIA_BUS_FMT_UYVY12_2X12</entry>
<entry>0x201c</entry>
<entry></entry>
&dash-ent-20;
@@ -2790,8 +2790,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY12-2X12">
- <entry>V4L2_MBUS_FMT_VYUY12_2X12</entry>
+ <row id="MEDIA-BUS-FMT-VYUY12-2X12">
+ <entry>MEDIA_BUS_FMT_VYUY12_2X12</entry>
<entry>0x201d</entry>
<entry></entry>
&dash-ent-20;
@@ -2862,8 +2862,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV12-2X12">
- <entry>V4L2_MBUS_FMT_YUYV12_2X12</entry>
+ <row id="MEDIA-BUS-FMT-YUYV12-2X12">
+ <entry>MEDIA_BUS_FMT_YUYV12_2X12</entry>
<entry>0x201e</entry>
<entry></entry>
&dash-ent-20;
@@ -2934,8 +2934,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU12-2X12">
- <entry>V4L2_MBUS_FMT_YVYU12_2X12</entry>
+ <row id="MEDIA-BUS-FMT-YVYU12-2X12">
+ <entry>MEDIA_BUS_FMT_YVYU12_2X12</entry>
<entry>0x201f</entry>
<entry></entry>
&dash-ent-20;
@@ -3006,8 +3006,8 @@
<entry>u<subscript>1</subscript></entry>
<entry>u<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-UYVY12-1X24">
- <entry>V4L2_MBUS_FMT_UYVY12_1X24</entry>
+ <row id="MEDIA-BUS-FMT-UYVY12-1X24">
+ <entry>MEDIA_BUS_FMT_UYVY12_1X24</entry>
<entry>0x2020</entry>
<entry></entry>
&dash-ent-8;
@@ -3066,8 +3066,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-VYUY12-1X24">
- <entry>V4L2_MBUS_FMT_VYUY12_1X24</entry>
+ <row id="MEDIA-BUS-FMT-VYUY12-1X24">
+ <entry>MEDIA_BUS_FMT_VYUY12_1X24</entry>
<entry>0x2021</entry>
<entry></entry>
&dash-ent-8;
@@ -3126,8 +3126,8 @@
<entry>y<subscript>1</subscript></entry>
<entry>y<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YUYV12-1X24">
- <entry>V4L2_MBUS_FMT_YUYV12_1X24</entry>
+ <row id="MEDIA-BUS-FMT-YUYV12-1X24">
+ <entry>MEDIA_BUS_FMT_YUYV12_1X24</entry>
<entry>0x2022</entry>
<entry></entry>
&dash-ent-8;
@@ -3186,8 +3186,8 @@
<entry>v<subscript>1</subscript></entry>
<entry>v<subscript>0</subscript></entry>
</row>
- <row id="V4L2-MBUS-FMT-YVYU12-1X24">
- <entry>V4L2_MBUS_FMT_YVYU12_1X24</entry>
+ <row id="MEDIA-BUS-FMT-YVYU12-1X24">
+ <entry>MEDIA_BUS_FMT_YVYU12_1X24</entry>
<entry>0x2023</entry>
<entry></entry>
&dash-ent-8;
@@ -3366,8 +3366,8 @@
</row>
</thead>
<tbody valign="top">
- <row id="V4L2-MBUS-FMT-AHSV8888-1X32">
- <entry>V4L2_MBUS_FMT_AHSV8888_1X32</entry>
+ <row id="MEDIA-BUS-FMT-AHSV8888-1X32">
+ <entry>MEDIA_BUS_FMT_AHSV8888_1X32</entry>
<entry>0x6001</entry>
<entry></entry>
<entry>a<subscript>7</subscript></entry>
@@ -3422,7 +3422,7 @@
</para>
<para>For instance, for a JPEG baseline process and an 8-bit bus width
- the format will be named <constant>V4L2_MBUS_FMT_JPEG_1X8</constant>.
+ the format will be named <constant>MEDIA_BUS_FMT_JPEG_1X8</constant>.
</para>
<para>The following table lists existing JPEG compressed formats.</para>
@@ -3441,8 +3441,8 @@
</row>
</thead>
<tbody valign="top">
- <row id="V4L2-MBUS-FMT-JPEG-1X8">
- <entry>V4L2_MBUS_FMT_JPEG_1X8</entry>
+ <row id="MEDIA-BUS-FMT-JPEG-1X8">
+ <entry>MEDIA_BUS_FMT_JPEG_1X8</entry>
<entry>0x4001</entry>
<entry>Besides of its usage for the parallel bus this format is
recommended for transmission of JPEG data over MIPI CSI bus
@@ -3484,8 +3484,8 @@ interface and may change in the future.</para>
</row>
</thead>
<tbody valign="top">
- <row id="V4L2-MBUS-FMT-S5C-UYVY-JPEG-1X8">
- <entry>V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8</entry>
+ <row id="MEDIA-BUS-FMT-S5C-UYVY-JPEG-1X8">
+ <entry>MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8</entry>
<entry>0x5001</entry>
<entry>
Interleaved raw UYVY and JPEG image format with embedded
diff --git a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
index 493a39a..603fece 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enuminput.xml
@@ -287,6 +287,14 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
<entry>0x00000004</entry>
<entry>This input supports setting the TV standard by using VIDIOC_S_STD.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_IN_CAP_NATIVE_SIZE</constant></entry>
+ <entry>0x00000008</entry>
+ <entry>This input supports setting the native size using
+ the <constant>V4L2_SEL_TGT_NATIVE_SIZE</constant>
+ selection target, see <xref
+ linkend="v4l2-selections-common"/>.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
index 2654e09..773fb12 100644
--- a/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
+++ b/Documentation/DocBook/media/v4l/vidioc-enumoutput.xml
@@ -172,6 +172,14 @@ input/output interface to linux-media@vger.kernel.org on 19 Oct 2009.
<entry>0x00000004</entry>
<entry>This output supports setting the TV standard by using VIDIOC_S_STD.</entry>
</row>
+ <row>
+ <entry><constant>V4L2_OUT_CAP_NATIVE_SIZE</constant></entry>
+ <entry>0x00000008</entry>
+ <entry>This output supports setting the native size using
+ the <constant>V4L2_SEL_TGT_NATIVE_SIZE</constant>
+ selection target, see <xref
+ linkend="v4l2-selections-common"/>.</entry>
+ </row>
</tbody>
</tgroup>
</table>
diff --git a/Documentation/DocBook/writing-an-alsa-driver.tmpl b/Documentation/DocBook/writing-an-alsa-driver.tmpl
index 784793d..84ef6a9 100644
--- a/Documentation/DocBook/writing-an-alsa-driver.tmpl
+++ b/Documentation/DocBook/writing-an-alsa-driver.tmpl
@@ -3658,6 +3658,29 @@ struct _snd_pcm_runtime {
</para>
<para>
+ The above callback can be simplified with a helper function,
+ <function>snd_ctl_enum_info</function>. The final code
+ looks like below.
+ (You can pass ARRAY_SIZE(texts) instead of 4 in the third
+ argument; it's a matter of taste.)
+
+ <informalexample>
+ <programlisting>
+<![CDATA[
+ static int snd_myctl_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+ {
+ static char *texts[4] = {
+ "First", "Second", "Third", "Fourth"
+ };
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
+ }
+]]>
+ </programlisting>
+ </informalexample>
+ </para>
+
+ <para>
Some common info callbacks are available for your convenience:
<function>snd_ctl_boolean_mono_info()</function> and
<function>snd_ctl_boolean_stereo_info()</function>.
diff --git a/Documentation/IRQ-domain.txt b/Documentation/IRQ-domain.txt
index 8a8b82c..39cfa72 100644
--- a/Documentation/IRQ-domain.txt
+++ b/Documentation/IRQ-domain.txt
@@ -151,3 +151,74 @@ used and no descriptor gets allocated it is very important to make sure
that the driver using the simple domain call irq_create_mapping()
before any irq_find_mapping() since the latter will actually work
for the static IRQ assignment case.
+
+==== Hierarchy IRQ domain ====
+On some architectures, there may be multiple interrupt controllers
+involved in delivering an interrupt from the device to the target CPU.
+Let's look at a typical interrupt delivering path on x86 platforms:
+
+Device --> IOAPIC -> Interrupt remapping Controller -> Local APIC -> CPU
+
+There are three interrupt controllers involved:
+1) IOAPIC controller
+2) Interrupt remapping controller
+3) Local APIC controller
+
+To support such a hardware topology and make software architecture match
+hardware architecture, an irq_domain data structure is built for each
+interrupt controller and those irq_domains are organized into hierarchy.
+When building irq_domain hierarchy, the irq_domain near to the device is
+child and the irq_domain near to CPU is parent. So a hierarchy structure
+as below will be built for the example above.
+ CPU Vector irq_domain (root irq_domain to manage CPU vectors)
+ ^
+ |
+ Interrupt Remapping irq_domain (manage irq_remapping entries)
+ ^
+ |
+ IOAPIC irq_domain (manage IOAPIC delivery entries/pins)
+
+There are four major interfaces to use hierarchy irq_domain:
+1) irq_domain_alloc_irqs(): allocate IRQ descriptors and interrupt
+ controller related resources to deliver these interrupts.
+2) irq_domain_free_irqs(): free IRQ descriptors and interrupt controller
+ related resources associated with these interrupts.
+3) irq_domain_activate_irq(): activate interrupt controller hardware to
+ deliver the interrupt.
+3) irq_domain_deactivate_irq(): deactivate interrupt controller hardware
+ to stop delivering the interrupt.
+
+Following changes are needed to support hierarchy irq_domain.
+1) a new field 'parent' is added to struct irq_domain; it's used to
+ maintain irq_domain hierarchy information.
+2) a new field 'parent_data' is added to struct irq_data; it's used to
+ build hierarchy irq_data to match hierarchy irq_domains. The irq_data
+ is used to store irq_domain pointer and hardware irq number.
+3) new callbacks are added to struct irq_domain_ops to support hierarchy
+ irq_domain operations.
+
+With support of hierarchy irq_domain and hierarchy irq_data ready, an
+irq_domain structure is built for each interrupt controller, and an
+irq_data structure is allocated for each irq_domain associated with an
+IRQ. Now we could go one step further to support stacked(hierarchy)
+irq_chip. That is, an irq_chip is associated with each irq_data along
+the hierarchy. A child irq_chip may implement a required action by
+itself or by cooperating with its parent irq_chip.
+
+With stacked irq_chip, interrupt controller driver only needs to deal
+with the hardware managed by itself and may ask for services from its
+parent irq_chip when needed. So we could achieve a much cleaner
+software architecture.
+
+For an interrupt controller driver to support hierarchy irq_domain, it
+needs to:
+1) Implement irq_domain_ops.alloc and irq_domain_ops.free
+2) Optionally implement irq_domain_ops.activate and
+ irq_domain_ops.deactivate.
+3) Optionally implement an irq_chip to manage the interrupt controller
+ hardware.
+4) No need to implement irq_domain_ops.map and irq_domain_ops.unmap,
+ they are unused with hierarchy irq_domain.
+
+Hierarchy irq_domain may also be used to support other architectures,
+such as ARM, ARM64 etc.
diff --git a/Documentation/RCU/rcu.txt b/Documentation/RCU/rcu.txt
index bf77833..745f429 100644
--- a/Documentation/RCU/rcu.txt
+++ b/Documentation/RCU/rcu.txt
@@ -36,7 +36,7 @@ o How can the updater tell when a grace period has completed
executed in user mode, or executed in the idle loop, we can
safely free up that item.
- Preemptible variants of RCU (CONFIG_TREE_PREEMPT_RCU) get the
+ Preemptible variants of RCU (CONFIG_PREEMPT_RCU) get the
same effect, but require that the readers manipulate CPU-local
counters. These counters allow limited types of blocking within
RCU read-side critical sections. SRCU also uses CPU-local
@@ -81,7 +81,7 @@ o I hear that RCU is patented? What is with that?
o I hear that RCU needs work in order to support realtime kernels?
This work is largely completed. Realtime-friendly RCU can be
- enabled via the CONFIG_TREE_PREEMPT_RCU kernel configuration
+ enabled via the CONFIG_PREEMPT_RCU kernel configuration
parameter. However, work is in progress for enabling priority
boosting of preempted RCU read-side critical sections. This is
needed if you have CPU-bound realtime threads.
diff --git a/Documentation/RCU/stallwarn.txt b/Documentation/RCU/stallwarn.txt
index ef5a2fd..ed186a9 100644
--- a/Documentation/RCU/stallwarn.txt
+++ b/Documentation/RCU/stallwarn.txt
@@ -26,12 +26,6 @@ CONFIG_RCU_CPU_STALL_TIMEOUT
Stall-warning messages may be enabled and disabled completely via
/sys/module/rcupdate/parameters/rcu_cpu_stall_suppress.
-CONFIG_RCU_CPU_STALL_VERBOSE
-
- This kernel configuration parameter causes the stall warning to
- also dump the stacks of any tasks that are blocking the current
- RCU-preempt grace period.
-
CONFIG_RCU_CPU_STALL_INFO
This kernel configuration parameter causes the stall warning to
@@ -77,7 +71,7 @@ This message indicates that CPU 5 detected that it was causing a stall,
and that the stall was affecting RCU-sched. This message will normally be
followed by a stack dump of the offending CPU. On TREE_RCU kernel builds,
RCU and RCU-sched are implemented by the same underlying mechanism,
-while on TREE_PREEMPT_RCU kernel builds, RCU is instead implemented
+while on PREEMPT_RCU kernel builds, RCU is instead implemented
by rcu_preempt_state.
On the other hand, if the offending CPU fails to print out a stall-warning
@@ -89,7 +83,7 @@ INFO: rcu_bh_state detected stalls on CPUs/tasks: { 3 5 } (detected by 2, 2502 j
This message indicates that CPU 2 detected that CPUs 3 and 5 were both
causing stalls, and that the stall was affecting RCU-bh. This message
will normally be followed by stack dumps for each CPU. Please note that
-TREE_PREEMPT_RCU builds can be stalled by tasks as well as by CPUs,
+PREEMPT_RCU builds can be stalled by tasks as well as by CPUs,
and that the tasks will be indicated by PID, for example, "P3421".
It is even possible for a rcu_preempt_state stall to be caused by both
CPUs -and- tasks, in which case the offending CPUs and tasks will all
@@ -205,10 +199,10 @@ o A CPU-bound real-time task in a CONFIG_PREEMPT kernel, which might
o A CPU-bound real-time task in a CONFIG_PREEMPT_RT kernel that
is running at a higher priority than the RCU softirq threads.
This will prevent RCU callbacks from ever being invoked,
- and in a CONFIG_TREE_PREEMPT_RCU kernel will further prevent
+ and in a CONFIG_PREEMPT_RCU kernel will further prevent
RCU grace periods from ever completing. Either way, the
system will eventually run out of memory and hang. In the
- CONFIG_TREE_PREEMPT_RCU case, you might see stall-warning
+ CONFIG_PREEMPT_RCU case, you might see stall-warning
messages.
o A hardware or software issue shuts off the scheduler-clock
diff --git a/Documentation/RCU/trace.txt b/Documentation/RCU/trace.txt
index 910870b..b63b9bb 100644
--- a/Documentation/RCU/trace.txt
+++ b/Documentation/RCU/trace.txt
@@ -8,7 +8,7 @@ The following sections describe the debugfs files and formats, first
for rcutree and next for rcutiny.
-CONFIG_TREE_RCU and CONFIG_TREE_PREEMPT_RCU debugfs Files and Formats
+CONFIG_TREE_RCU and CONFIG_PREEMPT_RCU debugfs Files and Formats
These implementations of RCU provide several debugfs directories under the
top-level directory "rcu":
@@ -18,7 +18,7 @@ rcu/rcu_preempt
rcu/rcu_sched
Each directory contains files for the corresponding flavor of RCU.
-Note that rcu/rcu_preempt is only present for CONFIG_TREE_PREEMPT_RCU.
+Note that rcu/rcu_preempt is only present for CONFIG_PREEMPT_RCU.
For CONFIG_TREE_RCU, the RCU flavor maps onto the RCU-sched flavor,
so that activity for both appears in rcu/rcu_sched.
diff --git a/Documentation/RCU/whatisRCU.txt b/Documentation/RCU/whatisRCU.txt
index e48c57f..88dfce1 100644
--- a/Documentation/RCU/whatisRCU.txt
+++ b/Documentation/RCU/whatisRCU.txt
@@ -137,7 +137,7 @@ rcu_read_lock()
Used by a reader to inform the reclaimer that the reader is
entering an RCU read-side critical section. It is illegal
to block while in an RCU read-side critical section, though
- kernels built with CONFIG_TREE_PREEMPT_RCU can preempt RCU
+ kernels built with CONFIG_PREEMPT_RCU can preempt RCU
read-side critical sections. Any RCU-protected data structure
accessed during an RCU read-side critical section is guaranteed to
remain unreclaimed for the full duration of that critical section.
diff --git a/Documentation/acpi/gpio-properties.txt b/Documentation/acpi/gpio-properties.txt
new file mode 100644
index 0000000..ae36fcf
--- /dev/null
+++ b/Documentation/acpi/gpio-properties.txt
@@ -0,0 +1,96 @@
+_DSD Device Properties Related to GPIO
+--------------------------------------
+
+With the release of ACPI 5.1 and the _DSD configuration objecte names
+can finally be given to GPIOs (and other things as well) returned by
+_CRS. Previously, we were only able to use an integer index to find
+the corresponding GPIO, which is pretty error prone (it depends on
+the _CRS output ordering, for example).
+
+With _DSD we can now query GPIOs using a name instead of an integer
+index, like the ASL example below shows:
+
+ // Bluetooth device with reset and shutdown GPIOs
+ Device (BTH)
+ {
+ Name (_HID, ...)
+
+ Name (_CRS, ResourceTemplate ()
+ {
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {15}
+ GpioIo (Exclusive, PullUp, 0, 0, IoRestrictionInputOnly,
+ "\\_SB.GPO0", 0, ResourceConsumer) {27, 31}
+ })
+
+ Name (_DSD, Package ()
+ {
+ ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ Package ()
+ {
+ Package () {"reset-gpio", Package() {^BTH, 1, 1, 0 }},
+ Package () {"shutdown-gpio", Package() {^BTH, 0, 0, 0 }},
+ }
+ })
+ }
+
+The format of the supported GPIO property is:
+
+ Package () { "name", Package () { ref, index, pin, active_low }}
+
+ ref - The device that has _CRS containing GpioIo()/GpioInt() resources,
+ typically this is the device itself (BTH in our case).
+ index - Index of the GpioIo()/GpioInt() resource in _CRS starting from zero.
+ pin - Pin in the GpioIo()/GpioInt() resource. Typically this is zero.
+ active_low - If 1 the GPIO is marked as active_low.
+
+Since ACPI GpioIo() resource does not have a field saying whether it is
+active low or high, the "active_low" argument can be used here. Setting
+it to 1 marks the GPIO as active low.
+
+In our Bluetooth example the "reset-gpio" refers to the second GpioIo()
+resource, second pin in that resource with the GPIO number of 31.
+
+ACPI GPIO Mappings Provided by Drivers
+--------------------------------------
+
+There are systems in which the ACPI tables do not contain _DSD but provide _CRS
+with GpioIo()/GpioInt() resources and device drivers still need to work with
+them.
+
+In those cases ACPI device identification objects, _HID, _CID, _CLS, _SUB, _HRV,
+available to the driver can be used to identify the device and that is supposed
+to be sufficient to determine the meaning and purpose of all of the GPIO lines
+listed by the GpioIo()/GpioInt() resources returned by _CRS. In other words,
+the driver is supposed to know what to use the GpioIo()/GpioInt() resources for
+once it has identified the device. Having done that, it can simply assign names
+to the GPIO lines it is going to use and provide the GPIO subsystem with a
+mapping between those names and the ACPI GPIO resources corresponding to them.
+
+To do that, the driver needs to define a mapping table as a NULL-terminated
+array of struct acpi_gpio_mapping objects that each contain a name, a pointer
+to an array of line data (struct acpi_gpio_params) objects and the size of that
+array. Each struct acpi_gpio_params object consists of three fields,
+crs_entry_index, line_index, active_low, representing the index of the target
+GpioIo()/GpioInt() resource in _CRS starting from zero, the index of the target
+line in that resource starting from zero, and the active-low flag for that line,
+respectively, in analogy with the _DSD GPIO property format specified above.
+
+For the example Bluetooth device discussed previously the data structures in
+question would look like this:
+
+static const struct acpi_gpio_params reset_gpio = { 1, 1, false };
+static const struct acpi_gpio_params shutdown_gpio = { 0, 0, false };
+
+static const struct acpi_gpio_mapping bluetooth_acpi_gpios[] = {
+ { "reset-gpio", &reset_gpio, 1 },
+ { "shutdown-gpio", &shutdown_gpio, 1 },
+ { },
+};
+
+Next, the mapping table needs to be passed as the second argument to
+acpi_dev_add_driver_gpios() that will register it with the ACPI device object
+pointed to by its first argument. That should be done in the driver's .probe()
+routine. On removal, the driver should unregister its GPIO mapping table by
+calling acpi_dev_remove_driver_gpios() on the ACPI device object where that
+table was previously registered.
diff --git a/Documentation/arm/firmware.txt b/Documentation/arm/firmware.txt
index c2e468f..da6713a 100644
--- a/Documentation/arm/firmware.txt
+++ b/Documentation/arm/firmware.txt
@@ -7,32 +7,14 @@ world, which changes the way some things have to be initialized. This makes
a need to provide an interface for such platforms to specify available firmware
operations and call them when needed.
-Firmware operations can be specified using struct firmware_ops
-
- struct firmware_ops {
- /*
- * Enters CPU idle mode
- */
- int (*do_idle)(void);
- /*
- * Sets boot address of specified physical CPU
- */
- int (*set_cpu_boot_addr)(int cpu, unsigned long boot_addr);
- /*
- * Boots specified physical CPU
- */
- int (*cpu_boot)(int cpu);
- /*
- * Initializes L2 cache
- */
- int (*l2x0_init)(void);
- };
-
-and then registered with register_firmware_ops function
+Firmware operations can be specified by filling in a struct firmware_ops
+with appropriate callbacks and then registering it with register_firmware_ops()
+function.
void register_firmware_ops(const struct firmware_ops *ops)
-the ops pointer must be non-NULL.
+The ops pointer must be non-NULL. More information about struct firmware_ops
+and its members can be found in arch/arm/include/asm/firmware.h header.
There is a default, empty set of operations provided, so there is no need to
set anything if platform does not require firmware operations.
diff --git a/Documentation/arm/sunxi/README b/Documentation/arm/sunxi/README
index 79452384..e68d163 100644
--- a/Documentation/arm/sunxi/README
+++ b/Documentation/arm/sunxi/README
@@ -37,16 +37,26 @@ SunXi family
http://dl.linux-sunxi.org/A20/A20%20User%20Manual%202013-03-22.pdf
- Allwinner A23
- + Not Supported
+ + Datasheet
+ http://dl.linux-sunxi.org/A23/A23%20Datasheet%20V1.0%2020130830.pdf
+ + User Manual
+ http://dl.linux-sunxi.org/A23/A23%20User%20Manual%20V1.0%2020130830.pdf
* Quad ARM Cortex-A7 based SoCs
- Allwinner A31 (sun6i)
+ Datasheet
- http://dl.linux-sunxi.org/A31/A31%20Datasheet%20-%20v1.00%20(2012-12-24).pdf
+ http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20datasheet%20V1.3%2020131106.pdf
+ + User Manual
+ http://dl.linux-sunxi.org/A31/A3x_release_document/A31/IC/A31%20user%20manual%20V1.1%2020130630.pdf
- Allwinner A31s (sun6i)
+ Not Supported
+ + Datasheet
+ http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20datasheet%20V1.3%2020131106.pdf
+ + User Manual
+ http://dl.linux-sunxi.org/A31/A3x_release_document/A31s/IC/A31s%20User%20Manual%20%20V1.0%2020130322.pdf
* Quad ARM Cortex-A15, Quad ARM Cortex-A7 based SoCs
- Allwinner A80
- + Not Supported \ No newline at end of file
+ + Datasheet
+ http://dl.linux-sunxi.org/A80/A80_Datasheet_Revision_1.0_0404.pdf
diff --git a/Documentation/arm64/legacy_instructions.txt b/Documentation/arm64/legacy_instructions.txt
new file mode 100644
index 0000000..a3b3da2
--- /dev/null
+++ b/Documentation/arm64/legacy_instructions.txt
@@ -0,0 +1,45 @@
+The arm64 port of the Linux kernel provides infrastructure to support
+emulation of instructions which have been deprecated, or obsoleted in
+the architecture. The infrastructure code uses undefined instruction
+hooks to support emulation. Where available it also allows turning on
+the instruction execution in hardware.
+
+The emulation mode can be controlled by writing to sysctl nodes
+(/proc/sys/abi). The following explains the different execution
+behaviours and the corresponding values of the sysctl nodes -
+
+* Undef
+ Value: 0
+ Generates undefined instruction abort. Default for instructions that
+ have been obsoleted in the architecture, e.g., SWP
+
+* Emulate
+ Value: 1
+ Uses software emulation. To aid migration of software, in this mode
+ usage of emulated instruction is traced as well as rate limited
+ warnings are issued. This is the default for deprecated
+ instructions, .e.g., CP15 barriers
+
+* Hardware Execution
+ Value: 2
+ Although marked as deprecated, some implementations may support the
+ enabling/disabling of hardware support for the execution of these
+ instructions. Using hardware execution generally provides better
+ performance, but at the loss of ability to gather runtime statistics
+ about the use of the deprecated instructions.
+
+The default mode depends on the status of the instruction in the
+architecture. Deprecated instructions should default to emulation
+while obsolete instructions must be undefined by default.
+
+Supported legacy instructions
+-----------------------------
+* SWP{B}
+Node: /proc/sys/abi/swp
+Status: Obsolete
+Default: Undef (0)
+
+* CP15 Barriers
+Node: /proc/sys/abi/cp15_barrier
+Status: Deprecated
+Default: Emulate (1)
diff --git a/Documentation/atomic_ops.txt b/Documentation/atomic_ops.txt
index 68542fe..183e41b 100644
--- a/Documentation/atomic_ops.txt
+++ b/Documentation/atomic_ops.txt
@@ -7,12 +7,13 @@
maintainers on how to implement atomic counter, bitops, and spinlock
interfaces properly.
- The atomic_t type should be defined as a signed integer.
-Also, it should be made opaque such that any kind of cast to a normal
-C integer type will fail. Something like the following should
-suffice:
+ The atomic_t type should be defined as a signed integer and
+the atomic_long_t type as a signed long integer. Also, they should
+be made opaque such that any kind of cast to a normal C integer type
+will fail. Something like the following should suffice:
typedef struct { int counter; } atomic_t;
+ typedef struct { long counter; } atomic_long_t;
Historically, counter has been declared volatile. This is now discouraged.
See Documentation/volatile-considered-harmful.txt for the complete rationale.
@@ -37,6 +38,9 @@ initializer is used before runtime. If the initializer is used at runtime, a
proper implicit or explicit read memory barrier is needed before reading the
value with atomic_read from another thread.
+As with all of the atomic_ interfaces, replace the leading "atomic_"
+with "atomic_long_" to operate on atomic_long_t.
+
The second interface can be used at runtime, as in:
struct foo { atomic_t counter; };
diff --git a/Documentation/block/biodoc.txt b/Documentation/block/biodoc.txt
index 2101e71..6b972b2 100644
--- a/Documentation/block/biodoc.txt
+++ b/Documentation/block/biodoc.txt
@@ -827,10 +827,6 @@ but in the event of any barrier requests in the tag queue we need to ensure
that requests are restarted in the order they were queue. This may happen
if the driver needs to use blk_queue_invalidate_tags().
-Tagging also defines a new request flag, REQ_QUEUED. This is set whenever
-a request is currently tagged. You should not use this flag directly,
-blk_rq_tagged(rq) is the portable way to do so.
-
3.3 I/O Submission
The routine submit_bio() is used to submit a single io. Higher level i/o
diff --git a/Documentation/cgroups/hugetlb.txt b/Documentation/cgroups/hugetlb.txt
index a9faaca..106245c 100644
--- a/Documentation/cgroups/hugetlb.txt
+++ b/Documentation/cgroups/hugetlb.txt
@@ -29,7 +29,7 @@ Brief summary of control files
hugetlb.<hugepagesize>.limit_in_bytes # set/show limit of "hugepagesize" hugetlb usage
hugetlb.<hugepagesize>.max_usage_in_bytes # show max "hugepagesize" hugetlb usage recorded
- hugetlb.<hugepagesize>.usage_in_bytes # show current res_counter usage for "hugepagesize" hugetlb
+ hugetlb.<hugepagesize>.usage_in_bytes # show current usage for "hugepagesize" hugetlb
hugetlb.<hugepagesize>.failcnt # show the number of allocation failure due to HugeTLB limit
For a system supporting two hugepage size (16M and 16G) the control
diff --git a/Documentation/cgroups/memory.txt b/Documentation/cgroups/memory.txt
index 02ab997..46b2b50 100644
--- a/Documentation/cgroups/memory.txt
+++ b/Documentation/cgroups/memory.txt
@@ -1,5 +1,10 @@
Memory Resource Controller
+NOTE: This document is hopelessly outdated and it asks for a complete
+ rewrite. It still contains a useful information so we are keeping it
+ here but make sure to check the current code if you need a deeper
+ understanding.
+
NOTE: The Memory Resource Controller has generically been referred to as the
memory controller in this document. Do not confuse memory controller
used here with the memory controller that is used in hardware.
@@ -52,9 +57,9 @@ Brief summary of control files.
tasks # attach a task(thread) and show list of threads
cgroup.procs # show list of processes
cgroup.event_control # an interface for event_fd()
- memory.usage_in_bytes # show current res_counter usage for memory
+ memory.usage_in_bytes # show current usage for memory
(See 5.5 for details)
- memory.memsw.usage_in_bytes # show current res_counter usage for memory+Swap
+ memory.memsw.usage_in_bytes # show current usage for memory+Swap
(See 5.5 for details)
memory.limit_in_bytes # set/show limit of memory usage
memory.memsw.limit_in_bytes # set/show limit of memory+Swap usage
@@ -116,16 +121,16 @@ The memory controller is the first controller developed.
2.1. Design
-The core of the design is a counter called the res_counter. The res_counter
-tracks the current memory usage and limit of the group of processes associated
-with the controller. Each cgroup has a memory controller specific data
-structure (mem_cgroup) associated with it.
+The core of the design is a counter called the page_counter. The
+page_counter tracks the current memory usage and limit of the group of
+processes associated with the controller. Each cgroup has a memory controller
+specific data structure (mem_cgroup) associated with it.
2.2. Accounting
+--------------------+
- | mem_cgroup |
- | (res_counter) |
+ | mem_cgroup |
+ | (page_counter) |
+--------------------+
/ ^ \
/ | \
@@ -352,9 +357,8 @@ set:
0. Configuration
a. Enable CONFIG_CGROUPS
-b. Enable CONFIG_RESOURCE_COUNTERS
-c. Enable CONFIG_MEMCG
-d. Enable CONFIG_MEMCG_SWAP (to use swap extension)
+b. Enable CONFIG_MEMCG
+c. Enable CONFIG_MEMCG_SWAP (to use swap extension)
d. Enable CONFIG_MEMCG_KMEM (to use kmem extension)
1. Prepare the cgroups (see cgroups.txt, Why are cgroups needed?)
diff --git a/Documentation/cgroups/resource_counter.txt b/Documentation/cgroups/resource_counter.txt
deleted file mode 100644
index 762ca54..0000000
--- a/Documentation/cgroups/resource_counter.txt
+++ /dev/null
@@ -1,197 +0,0 @@
-
- The Resource Counter
-
-The resource counter, declared at include/linux/res_counter.h,
-is supposed to facilitate the resource management by controllers
-by providing common stuff for accounting.
-
-This "stuff" includes the res_counter structure and routines
-to work with it.
-
-
-
-1. Crucial parts of the res_counter structure
-
- a. unsigned long long usage
-
- The usage value shows the amount of a resource that is consumed
- by a group at a given time. The units of measurement should be
- determined by the controller that uses this counter. E.g. it can
- be bytes, items or any other unit the controller operates on.
-
- b. unsigned long long max_usage
-
- The maximal value of the usage over time.
-
- This value is useful when gathering statistical information about
- the particular group, as it shows the actual resource requirements
- for a particular group, not just some usage snapshot.
-
- c. unsigned long long limit
-
- The maximal allowed amount of resource to consume by the group. In
- case the group requests for more resources, so that the usage value
- would exceed the limit, the resource allocation is rejected (see
- the next section).
-
- d. unsigned long long failcnt
-
- The failcnt stands for "failures counter". This is the number of
- resource allocation attempts that failed.
-
- c. spinlock_t lock
-
- Protects changes of the above values.
-
-
-
-2. Basic accounting routines
-
- a. void res_counter_init(struct res_counter *rc,
- struct res_counter *rc_parent)
-
- Initializes the resource counter. As usual, should be the first
- routine called for a new counter.
-
- The struct res_counter *parent can be used to define a hierarchical
- child -> parent relationship directly in the res_counter structure,
- NULL can be used to define no relationship.
-
- c. int res_counter_charge(struct res_counter *rc, unsigned long val,
- struct res_counter **limit_fail_at)
-
- When a resource is about to be allocated it has to be accounted
- with the appropriate resource counter (controller should determine
- which one to use on its own). This operation is called "charging".
-
- This is not very important which operation - resource allocation
- or charging - is performed first, but
- * if the allocation is performed first, this may create a
- temporary resource over-usage by the time resource counter is
- charged;
- * if the charging is performed first, then it should be uncharged
- on error path (if the one is called).
-
- If the charging fails and a hierarchical dependency exists, the
- limit_fail_at parameter is set to the particular res_counter element
- where the charging failed.
-
- d. u64 res_counter_uncharge(struct res_counter *rc, unsigned long val)
-
- When a resource is released (freed) it should be de-accounted
- from the resource counter it was accounted to. This is called
- "uncharging". The return value of this function indicate the amount
- of charges still present in the counter.
-
- The _locked routines imply that the res_counter->lock is taken.
-
- e. u64 res_counter_uncharge_until
- (struct res_counter *rc, struct res_counter *top,
- unsigned long val)
-
- Almost same as res_counter_uncharge() but propagation of uncharge
- stops when rc == top. This is useful when kill a res_counter in
- child cgroup.
-
- 2.1 Other accounting routines
-
- There are more routines that may help you with common needs, like
- checking whether the limit is reached or resetting the max_usage
- value. They are all declared in include/linux/res_counter.h.
-
-
-
-3. Analyzing the resource counter registrations
-
- a. If the failcnt value constantly grows, this means that the counter's
- limit is too tight. Either the group is misbehaving and consumes too
- many resources, or the configuration is not suitable for the group
- and the limit should be increased.
-
- b. The max_usage value can be used to quickly tune the group. One may
- set the limits to maximal values and either load the container with
- a common pattern or leave one for a while. After this the max_usage
- value shows the amount of memory the container would require during
- its common activity.
-
- Setting the limit a bit above this value gives a pretty good
- configuration that works in most of the cases.
-
- c. If the max_usage is much less than the limit, but the failcnt value
- is growing, then the group tries to allocate a big chunk of resource
- at once.
-
- d. If the max_usage is much less than the limit, but the failcnt value
- is 0, then this group is given too high limit, that it does not
- require. It is better to lower the limit a bit leaving more resource
- for other groups.
-
-
-
-4. Communication with the control groups subsystem (cgroups)
-
-All the resource controllers that are using cgroups and resource counters
-should provide files (in the cgroup filesystem) to work with the resource
-counter fields. They are recommended to adhere to the following rules:
-
- a. File names
-
- Field name File name
- ---------------------------------------------------
- usage usage_in_<unit_of_measurement>
- max_usage max_usage_in_<unit_of_measurement>
- limit limit_in_<unit_of_measurement>
- failcnt failcnt
- lock no file :)
-
- b. Reading from file should show the corresponding field value in the
- appropriate format.
-
- c. Writing to file
-
- Field Expected behavior
- ----------------------------------
- usage prohibited
- max_usage reset to usage
- limit set the limit
- failcnt reset to zero
-
-
-
-5. Usage example
-
- a. Declare a task group (take a look at cgroups subsystem for this) and
- fold a res_counter into it
-
- struct my_group {
- struct res_counter res;
-
- <other fields>
- }
-
- b. Put hooks in resource allocation/release paths
-
- int alloc_something(...)
- {
- if (res_counter_charge(res_counter_ptr, amount) < 0)
- return -ENOMEM;
-
- <allocate the resource and return to the caller>
- }
-
- void release_something(...)
- {
- res_counter_uncharge(res_counter_ptr, amount);
-
- <release the resource>
- }
-
- In order to keep the usage value self-consistent, both the
- "res_counter_ptr" and the "amount" in release_something() should be
- the same as they were in the alloc_something() when the releasing
- resource was allocated.
-
- c. Provide the way to read res_counter values and set them (the cgroups
- still can help with it).
-
- c. Compile and run :)
diff --git a/Documentation/cpu-freq/intel-pstate.txt b/Documentation/cpu-freq/intel-pstate.txt
index a69ffe1..765d7fc 100644
--- a/Documentation/cpu-freq/intel-pstate.txt
+++ b/Documentation/cpu-freq/intel-pstate.txt
@@ -1,17 +1,28 @@
Intel P-state driver
--------------------
-This driver implements a scaling driver with an internal governor for
-Intel Core processors. The driver follows the same model as the
-Transmeta scaling driver (longrun.c) and implements the setpolicy()
-instead of target(). Scaling drivers that implement setpolicy() are
-assumed to implement internal governors by the cpufreq core. All the
-logic for selecting the current P state is contained within the
-driver; no external governor is used by the cpufreq core.
-
-Intel SandyBridge+ processors are supported.
-
-New sysfs files for controlling P state selection have been added to
+This driver provides an interface to control the P state selection for
+SandyBridge+ Intel processors. The driver can operate two different
+modes based on the processor model legacy and Hardware P state (HWP)
+mode.
+
+In legacy mode the driver implements a scaling driver with an internal
+governor for Intel Core processors. The driver follows the same model
+as the Transmeta scaling driver (longrun.c) and implements the
+setpolicy() instead of target(). Scaling drivers that implement
+setpolicy() are assumed to implement internal governors by the cpufreq
+core. All the logic for selecting the current P state is contained
+within the driver; no external governor is used by the cpufreq core.
+
+In HWP mode P state selection is implemented in the processor
+itself. The driver provides the interfaces between the cpufreq core and
+the processor to control P state selection based on user preferences
+and reporting frequency to the cpufreq core. In this mode the
+internal governor code is disabled.
+
+In addtion to the interfaces provided by the cpufreq core for
+controlling frequency the driver provides sysfs files for
+controlling P state selection. These files have been added to
/sys/devices/system/cpu/intel_pstate/
max_perf_pct: limits the maximum P state that will be requested by
@@ -33,7 +44,9 @@ frequency is fiction for Intel Core processors. Even if the scaling
driver selects a single P state the actual frequency the processor
will run at is selected by the processor itself.
-New debugfs files have also been added to /sys/kernel/debug/pstate_snb/
+For legacy mode debugfs files have also been added to allow tuning of
+the internal governor algorythm. These files are located at
+/sys/kernel/debug/pstate_snb/ These files are NOT present in HWP mode.
deadband
d_gain_pct
diff --git a/Documentation/device-mapper/cache-policies.txt b/Documentation/device-mapper/cache-policies.txt
index 66c2774..0d124a9 100644
--- a/Documentation/device-mapper/cache-policies.txt
+++ b/Documentation/device-mapper/cache-policies.txt
@@ -47,20 +47,26 @@ Message and constructor argument pairs are:
'discard_promote_adjustment <value>'
The sequential threshold indicates the number of contiguous I/Os
-required before a stream is treated as sequential. The random threshold
+required before a stream is treated as sequential. Once a stream is
+considered sequential it will bypass the cache. The random threshold
is the number of intervening non-contiguous I/Os that must be seen
before the stream is treated as random again.
The sequential and random thresholds default to 512 and 4 respectively.
-Large, sequential ios are probably better left on the origin device
-since spindles tend to have good bandwidth. The io_tracker counts
-contiguous I/Os to try to spot when the io is in one of these sequential
-modes.
-
-Internally the mq policy maintains a promotion threshold variable. If
-the hit count of a block not in the cache goes above this threshold it
-gets promoted to the cache. The read, write and discard promote adjustment
+Large, sequential I/Os are probably better left on the origin device
+since spindles tend to have good sequential I/O bandwidth. The
+io_tracker counts contiguous I/Os to try to spot when the I/O is in one
+of these sequential modes. But there are use-cases for wanting to
+promote sequential blocks to the cache (e.g. fast application startup).
+If sequential threshold is set to 0 the sequential I/O detection is
+disabled and sequential I/O will no longer implicitly bypass the cache.
+Setting the random threshold to 0 does _not_ disable the random I/O
+stream detection.
+
+Internally the mq policy determines a promotion threshold. If the hit
+count of a block not in the cache goes above this threshold it gets
+promoted to the cache. The read, write and discard promote adjustment
tunables allow you to tweak the promotion threshold by adding a small
value based on the io type. They default to 4, 8 and 1 respectively.
If you're trying to quickly warm a new cache device you may wish to
diff --git a/Documentation/devicetree/bindings/arm/amlogic.txt b/Documentation/devicetree/bindings/arm/amlogic.txt
index 7eece72..8fe8150 100644
--- a/Documentation/devicetree/bindings/arm/amlogic.txt
+++ b/Documentation/devicetree/bindings/arm/amlogic.txt
@@ -2,7 +2,9 @@ Amlogic MesonX device tree bindings
-------------------------------------------
Boards with the Amlogic Meson6 SoC shall have the following properties:
+ Required root node property:
+ compatible: "amlogic,meson6"
-Required root node property:
-
-compatible = "amlogic,meson6";
+Boards with the Amlogic Meson8 SoC shall have the following properties:
+ Required root node property:
+ compatible: "amlogic,meson8";
diff --git a/Documentation/devicetree/bindings/arm/arch_timer.txt b/Documentation/devicetree/bindings/arm/arch_timer.txt
index 37b2caf..256b4d8 100644
--- a/Documentation/devicetree/bindings/arm/arch_timer.txt
+++ b/Documentation/devicetree/bindings/arm/arch_timer.txt
@@ -22,6 +22,14 @@ to deliver its interrupts via SPIs.
- always-on : a boolean property. If present, the timer is powered through an
always-on power domain, therefore it never loses context.
+** Optional properties:
+
+- arm,cpu-registers-not-fw-configured : Firmware does not initialize
+ any of the generic timer CPU registers, which contain their
+ architecturally-defined reset values. Only supported for 32-bit
+ systems which follow the ARMv7 architected reset values.
+
+
Example:
timer {
diff --git a/Documentation/devicetree/bindings/arm/arm-boards b/Documentation/devicetree/bindings/arm/arm-boards
index c554ed3..556c866 100644
--- a/Documentation/devicetree/bindings/arm/arm-boards
+++ b/Documentation/devicetree/bindings/arm/arm-boards
@@ -92,3 +92,68 @@ Required nodes:
- core-module: the root node to the Versatile platforms must have
a core-module with regs and the compatible strings
"arm,core-module-versatile", "syscon"
+
+ARM RealView Boards
+-------------------
+The RealView boards cover tailored evaluation boards that are used to explore
+the ARM11 and Cortex A-8 and Cortex A-9 processors.
+
+Required properties (in root node):
+ /* RealView Emulation Baseboard */
+ compatible = "arm,realview-eb";
+ /* RealView Platform Baseboard for ARM1176JZF-S */
+ compatible = "arm,realview-pb1176";
+ /* RealView Platform Baseboard for ARM11 MPCore */
+ compatible = "arm,realview-pb11mp";
+ /* RealView Platform Baseboard for Cortex A-8 */
+ compatible = "arm,realview-pba8";
+ /* RealView Platform Baseboard Explore for Cortex A-9 */
+ compatible = "arm,realview-pbx";
+
+Required nodes:
+
+- soc: some node of the RealView platforms must be the SoC
+ node that contain the SoC-specific devices, withe the compatible
+ string set to one of these tuples:
+ "arm,realview-eb-soc", "simple-bus"
+ "arm,realview-pb1176-soc", "simple-bus"
+ "arm,realview-pb11mp-soc", "simple-bus"
+ "arm,realview-pba8-soc", "simple-bus"
+ "arm,realview-pbx-soc", "simple-bus"
+
+- syscon: some subnode of the RealView SoC node must be a
+ system controller node pointing to the control registers,
+ with the compatible string set to one of these tuples:
+ "arm,realview-eb-syscon", "syscon"
+ "arm,realview-pb1176-syscon", "syscon"
+ "arm,realview-pb11mp-syscon", "syscon"
+ "arm,realview-pba8-syscon", "syscon"
+ "arm,realview-pbx-syscon", "syscon"
+
+ Required properties for the system controller:
+ - regs: the location and size of the system controller registers,
+ one range of 0x1000 bytes.
+
+Example:
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
+#include "skeleton.dtsi"
+
+/ {
+ model = "ARM RealView PB1176 with device tree";
+ compatible = "arm,realview-pb1176";
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,realview-pb1176-soc", "simple-bus";
+ ranges;
+
+ syscon: syscon@10000000 {
+ compatible = "arm,realview-syscon", "syscon";
+ reg = <0x10000000 0x1000>;
+ };
+
+ };
+};
diff --git a/Documentation/devicetree/bindings/arm/bcm/cygnus.txt b/Documentation/devicetree/bindings/arm/bcm/cygnus.txt
new file mode 100644
index 0000000..4c77169
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/bcm/cygnus.txt
@@ -0,0 +1,31 @@
+Broadcom Cygnus device tree bindings
+------------------------------------
+
+
+Boards with Cygnus SoCs shall have the following properties:
+
+Required root node property:
+
+BCM11300
+compatible = "brcm,bcm11300", "brcm,cygnus";
+
+BCM11320
+compatible = "brcm,bcm11320", "brcm,cygnus";
+
+BCM11350
+compatible = "brcm,bcm11350", "brcm,cygnus";
+
+BCM11360
+compatible = "brcm,bcm11360", "brcm,cygnus";
+
+BCM58300
+compatible = "brcm,bcm58300", "brcm,cygnus";
+
+BCM58302
+compatible = "brcm,bcm58302", "brcm,cygnus";
+
+BCM58303
+compatible = "brcm,bcm58303", "brcm,cygnus";
+
+BCM58305
+compatible = "brcm,bcm58305", "brcm,cygnus";
diff --git a/Documentation/devicetree/bindings/arm/cpus.txt b/Documentation/devicetree/bindings/arm/cpus.txt
index fc446347..b2aacbe 100644
--- a/Documentation/devicetree/bindings/arm/cpus.txt
+++ b/Documentation/devicetree/bindings/arm/cpus.txt
@@ -227,6 +227,15 @@ nodes to be present and contain the properties described below.
# List of phandles to idle state nodes supported
by this cpu [3].
+ - rockchip,pmu
+ Usage: optional for systems that have an "enable-method"
+ property value of "rockchip,rk3066-smp"
+ While optional, it is the preferred way to get access to
+ the cpu-core power-domains.
+ Value type: <phandle>
+ Definition: Specifies the syscon node controlling the cpu core
+ power domains.
+
Example 1 (dual-cluster big.LITTLE system 32-bit):
cpus {
diff --git a/Documentation/devicetree/bindings/arm/fsl.txt b/Documentation/devicetree/bindings/arm/fsl.txt
index e935d7d..4e8b7df 100644
--- a/Documentation/devicetree/bindings/arm/fsl.txt
+++ b/Documentation/devicetree/bindings/arm/fsl.txt
@@ -74,3 +74,41 @@ Required root node properties:
i.MX6q generic board
Required root node properties:
- compatible = "fsl,imx6q";
+
+
+Freescale LS1021A Platform Device Tree Bindings
+------------------------------------------------
+
+Required root node compatible properties:
+ - compatible = "fsl,ls1021a";
+
+Freescale LS1021A SoC-specific Device Tree Bindings
+-------------------------------------------
+
+Freescale SCFG
+ SCFG is the supplemental configuration unit, that provides SoC specific
+configuration and status registers for the chip. Such as getting PEX port
+status.
+ Required properties:
+ - compatible: should be "fsl,ls1021a-scfg"
+ - reg: should contain base address and length of SCFG memory-mapped registers
+
+Example:
+ scfg: scfg@1570000 {
+ compatible = "fsl,ls1021a-scfg";
+ reg = <0x0 0x1570000 0x0 0x10000>;
+ };
+
+Freescale DCFG
+ DCFG is the device configuration unit, that provides general purpose
+configuration and status for the device. Such as setting the secondary
+core start address and release the secondary core from holdoff and startup.
+ Required properties:
+ - compatible: should be "fsl,ls1021a-dcfg"
+ - reg : should contain base address and length of DCFG memory-mapped registers
+
+Example:
+ dcfg: dcfg@1ee0000 {
+ compatible = "fsl,ls1021a-dcfg";
+ reg = <0x0 0x1ee0000 0x0 0x10000>;
+ };
diff --git a/Documentation/devicetree/bindings/arm/gic.txt b/Documentation/devicetree/bindings/arm/gic.txt
index c7d2fa1..b38608a 100644
--- a/Documentation/devicetree/bindings/arm/gic.txt
+++ b/Documentation/devicetree/bindings/arm/gic.txt
@@ -17,6 +17,7 @@ Main node required properties:
"arm,cortex-a7-gic"
"arm,arm11mp-gic"
"brcm,brahma-b15-gic"
+ "arm,arm1176jzf-devchip-gic"
- interrupt-controller : Identifies the node as an interrupt controller
- #interrupt-cells : Specifies the number of cells needed to encode an
interrupt source. The type shall be a <u32> and the value shall be 3.
diff --git a/Documentation/devicetree/bindings/arm/idle-states.txt b/Documentation/devicetree/bindings/arm/idle-states.txt
index 37375c7..a8274ea 100644
--- a/Documentation/devicetree/bindings/arm/idle-states.txt
+++ b/Documentation/devicetree/bindings/arm/idle-states.txt
@@ -317,6 +317,26 @@ follows:
In such systems entry-latency-us + exit-latency-us
will exceed wakeup-latency-us by this duration.
+ - status:
+ Usage: Optional
+ Value type: <string>
+ Definition: A standard device tree property [5] that indicates
+ the operational status of an idle-state.
+ If present, it shall be:
+ "okay": to indicate that the idle state is
+ operational.
+ "disabled": to indicate that the idle state has
+ been disabled in firmware so it is not
+ operational.
+ If the property is not present the idle-state must
+ be considered operational.
+
+ - idle-state-name:
+ Usage: Optional
+ Value type: <string>
+ Definition: A string used as a descriptive name for the idle
+ state.
+
In addition to the properties listed above, a state node may require
additional properties specifics to the entry-method defined in the
idle-states node, please refer to the entry-method bindings
diff --git a/Documentation/devicetree/bindings/arm/marvell,berlin.txt b/Documentation/devicetree/bindings/arm/marvell,berlin.txt
index 904de57..a99eb9e 100644
--- a/Documentation/devicetree/bindings/arm/marvell,berlin.txt
+++ b/Documentation/devicetree/bindings/arm/marvell,berlin.txt
@@ -106,11 +106,21 @@ Required subnode-properties:
- groups: a list of strings describing the group names.
- function: a string describing the function used to mux the groups.
+* Reset controller binding
+
+A reset controller is part of the chip control registers set. The chip control
+node also provides the reset. The register set is not at the same offset between
+Berlin SoCs.
+
+Required property:
+- #reset-cells: must be set to 2
+
Example:
chip: chip-control@ea0000 {
compatible = "marvell,berlin2-chip-ctrl";
#clock-cells = <1>;
+ #reset-cells = <2>;
reg = <0xea0000 0x400>;
clocks = <&refclk>, <&externaldev 0>;
clock-names = "refclk", "video_ext0";
diff --git a/Documentation/devicetree/bindings/arm/mediatek.txt b/Documentation/devicetree/bindings/arm/mediatek.txt
index fa25226..3be4013 100644
--- a/Documentation/devicetree/bindings/arm/mediatek.txt
+++ b/Documentation/devicetree/bindings/arm/mediatek.txt
@@ -1,10 +1,14 @@
-Mediatek MT6589 Platforms Device Tree Bindings
+MediaTek mt65xx & mt81xx Platforms Device Tree Bindings
-Boards with a SoC of the Mediatek MT6589 shall have the following property:
+Boards with a MediaTek mt65xx/mt81xx SoC shall have the following property:
Required root node property:
-compatible: must contain "mediatek,mt6589"
+compatible: Must contain one of
+ "mediatek,mt6589"
+ "mediatek,mt6592"
+ "mediatek,mt8127"
+ "mediatek,mt8135"
Supported boards:
@@ -12,3 +16,12 @@ Supported boards:
- bq Aquaris5 smart phone:
Required root node properties:
- compatible = "mundoreader,bq-aquaris5", "mediatek,mt6589";
+- Evaluation board for MT6592:
+ Required root node properties:
+ - compatible = "mediatek,mt6592-evb", "mediatek,mt6592";
+- MTK mt8127 tablet moose EVB:
+ Required root node properties:
+ - compatible = "mediatek,mt8127-moose", "mediatek,mt8127";
+- MTK mt8135 tablet EVB:
+ Required root node properties:
+ - compatible = "mediatek,mt8135-evbp1", "mediatek,mt8135";
diff --git a/Documentation/devicetree/bindings/arm/omap/omap.txt b/Documentation/devicetree/bindings/arm/omap/omap.txt
index ddd9bcd..4f6a82c 100644
--- a/Documentation/devicetree/bindings/arm/omap/omap.txt
+++ b/Documentation/devicetree/bindings/arm/omap/omap.txt
@@ -132,6 +132,9 @@ Boards:
- AM335X Bone : Low cost community board
compatible = "ti,am335x-bone", "ti,am33xx", "ti,omap3"
+- AM335X OrionLXm : Substation Automation Platform
+ compatible = "novatech,am335x-lxm", "ti,am33xx"
+
- OMAP5 EVM : Evaluation Module
compatible = "ti,omap5-evm", "ti,omap5"
diff --git a/Documentation/devicetree/bindings/arm/rockchip.txt b/Documentation/devicetree/bindings/arm/rockchip.txt
index 857f126..eaa3d1a 100644
--- a/Documentation/devicetree/bindings/arm/rockchip.txt
+++ b/Documentation/devicetree/bindings/arm/rockchip.txt
@@ -1,6 +1,10 @@
Rockchip platforms device tree bindings
---------------------------------------
+- MarsBoard RK3066 board:
+ Required root node properties:
+ - compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a";
+
- bq Curie 2 tablet:
Required root node properties:
- compatible = "mundoreader,bq-curie2", "rockchip,rk3066a";
diff --git a/Documentation/devicetree/bindings/arm/samsung-boards.txt b/Documentation/devicetree/bindings/arm/samsung-boards.txt
index 2168ed3..43589d2 100644
--- a/Documentation/devicetree/bindings/arm/samsung-boards.txt
+++ b/Documentation/devicetree/bindings/arm/samsung-boards.txt
@@ -1,11 +1,20 @@
-* Samsung's Exynos4210 based SMDKV310 evaluation board
-
-SMDKV310 evaluation board is based on Samsung's Exynos4210 SoC.
+* Samsung's Exynos SoC based boards
Required root node properties:
- compatible = should be one or more of the following.
- (a) "samsung,smdkv310" - for Samsung's SMDKV310 eval board.
- (b) "samsung,exynos4210" - for boards based on Exynos4210 SoC.
+ - "samsung,monk" - for Exynos3250-based Samsung Simband board.
+ - "samsung,rinato" - for Exynos3250-based Samsung Gear2 board.
+ - "samsung,smdkv310" - for Exynos4210-based Samsung SMDKV310 eval board.
+ - "samsung,trats" - for Exynos4210-based Tizen Reference board.
+ - "samsung,universal_c210" - for Exynos4210-based Samsung board.
+ - "samsung,smdk4412", - for Exynos4412-based Samsung SMDK4412 eval board.
+ - "samsung,trats2" - for Exynos4412-based Tizen Reference board.
+ - "samsung,smdk5250" - for Exynos5250-based Samsung SMDK5250 eval board.
+ - "samsung,xyref5260" - for Exynos5260-based Samsung board.
+ - "samsung,smdk5410" - for Exynos5410-based Samsung SMDK5410 eval board.
+ - "samsung,smdk5420" - for Exynos5420-based Samsung SMDK5420 eval board.
+ - "samsung,sd5v1" - for Exynos5440-based Samsung board.
+ - "samsung,ssdk5440" - for Exynos5440-based Samsung board.
Optional:
- firmware node, specifying presence and type of secure firmware:
diff --git a/Documentation/devicetree/bindings/arm/ste-nomadik.txt b/Documentation/devicetree/bindings/arm/ste-nomadik.txt
index 6256ec3..2fdff5a 100644
--- a/Documentation/devicetree/bindings/arm/ste-nomadik.txt
+++ b/Documentation/devicetree/bindings/arm/ste-nomadik.txt
@@ -10,6 +10,12 @@ Required root node property: src
Boards with the Nomadik SoC include:
+Nomadik NHK-15 board manufactured by ST Microelectronics:
+
+Required root node property:
+
+compatible="st,nomadik-nhk-15";
+
S8815 "MiniKit" manufactured by Calao Systems:
Required root node property:
diff --git a/Documentation/devicetree/bindings/arm/sunxi.txt b/Documentation/devicetree/bindings/arm/sunxi.txt
new file mode 100644
index 0000000..42941fd
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/sunxi.txt
@@ -0,0 +1,12 @@
+Allwinner sunXi Platforms Device Tree Bindings
+
+Each device tree must specify which Allwinner SoC it uses,
+using one of the following compatible strings:
+
+ allwinner,sun4i-a10
+ allwinner,sun5i-a10s
+ allwinner,sun5i-a13
+ allwinner,sun6i-a31
+ allwinner,sun7i-a20
+ allwinner,sun8i-a23
+ allwinner,sun9i-a80
diff --git a/Documentation/devicetree/bindings/arm/ux500/power_domain.txt b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt
new file mode 100644
index 0000000..5679d17
--- /dev/null
+++ b/Documentation/devicetree/bindings/arm/ux500/power_domain.txt
@@ -0,0 +1,35 @@
+* ST-Ericsson UX500 PM Domains
+
+UX500 supports multiple PM domains which are used to gate power to one or
+more peripherals on the SOC.
+
+The implementation of PM domains for UX500 are based upon the generic PM domain
+and use the corresponding DT bindings.
+
+==PM domain providers==
+
+Required properties:
+ - compatible: Must be "stericsson,ux500-pm-domains".
+ - #power-domain-cells : Number of cells in a power domain specifier, must be 1.
+
+Example:
+ pm_domains: pm_domains0 {
+ compatible = "stericsson,ux500-pm-domains";
+ #power-domain-cells = <1>;
+ };
+
+==PM domain consumers==
+
+Required properties:
+ - power-domains: A phandle and PM domain specifier. Below are the list of
+ valid specifiers:
+
+ Index Specifier
+ ----- ---------
+ 0 DOMAIN_VAPE
+
+Example:
+ sdi0_per1@80126000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ power-domains = <&pm_domains DOMAIN_VAPE>
+ };
diff --git a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
index e2d501d..1eceefb 100644
--- a/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
+++ b/Documentation/devicetree/bindings/bus/brcm,gisb-arb.txt
@@ -2,7 +2,11 @@ Broadcom GISB bus Arbiter controller
Required properties:
-- compatible: should be "brcm,gisb-arb"
+- compatible:
+ "brcm,gisb-arb" or "brcm,bcm7445-gisb-arb" for 28nm chips
+ "brcm,bcm7435-gisb-arb" for newer 40nm chips
+ "brcm,bcm7400-gisb-arb" for older 40nm chips and all 65nm chips
+ "brcm,bcm7038-gisb-arb" for 130nm chips
- reg: specifies the base physical address and size of the registers
- interrupt-parent: specifies the phandle to the parent interrupt controller
this arbiter gets interrupt line from
diff --git a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
index 5fa44f5..5e16c3c 100644
--- a/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
+++ b/Documentation/devicetree/bindings/bus/mvebu-mbus.txt
@@ -48,9 +48,12 @@ Required properties:
- compatible: Should be set to "marvell,mbus-controller".
- reg: Device's register space.
- Two entries are expected (see the examples below):
- the first one controls the devices decoding window and
- the second one controls the SDRAM decoding window.
+ Two or three entries are expected (see the examples below):
+ the first one controls the devices decoding window,
+ the second one controls the SDRAM decoding window and
+ the third controls the MBus bridge (only with the
+ marvell,armada370-mbus and marvell,armadaxp-mbus
+ compatible strings)
Example:
@@ -67,7 +70,7 @@ Example:
mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller";
- reg = <0x20000 0x100>, <0x20180 0x20>;
+ reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
};
/* more children ...*/
@@ -126,7 +129,7 @@ are skipped.
mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller";
- reg = <0x20000 0x100>, <0x20180 0x20>;
+ reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
};
/* more children ...*/
@@ -170,7 +173,7 @@ Using this macro, the above example would be:
mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller";
- reg = <0x20000 0x100>, <0x20180 0x20>;
+ reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
};
/* other children */
@@ -266,7 +269,7 @@ See the example below, where a more complete device tree is shown:
ranges = <0 MBUS_ID(0xf0, 0x01) 0 0x100000>;
mbusc: mbus-controller@20000 {
- reg = <0x20000 0x100>, <0x20180 0x20>;
+ reg = <0x20000 0x100>, <0x20180 0x20>, <0x20250 0x8>;
};
interrupt-controller@20000 {
diff --git a/Documentation/devicetree/bindings/chosen.txt b/Documentation/devicetree/bindings/chosen.txt
new file mode 100644
index 0000000..ed838f4
--- /dev/null
+++ b/Documentation/devicetree/bindings/chosen.txt
@@ -0,0 +1,46 @@
+The chosen node
+---------------
+
+The chosen node does not represent a real device, but serves as a place
+for passing data between firmware and the operating system, like boot
+arguments. Data in the chosen node does not represent the hardware.
+
+
+stdout-path property
+--------------------
+
+Device trees may specify the device to be used for boot console output
+with a stdout-path property under /chosen, as described in ePAPR, e.g.
+
+/ {
+ chosen {
+ stdout-path = "/serial@f00:115200";
+ };
+
+ serial@f00 {
+ compatible = "vendor,some-uart";
+ reg = <0xf00 0x10>;
+ };
+};
+
+If the character ":" is present in the value, this terminates the path.
+The meaning of any characters following the ":" is device-specific, and
+must be specified in the relevant binding documentation.
+
+For UART devices, the preferred binding is a string in the form:
+
+ <baud>{<parity>{<bits>{<flow>}}}
+
+where
+
+ baud - baud rate in decimal
+ parity - 'n' (none), 'o', (odd) or 'e' (even)
+ bits - number of data bits
+ flow - 'r' (rts)
+
+For example: 115200n8r
+
+Implementation note: Linux will look for the property "linux,stdout-path" or
+on PowerPC "stdout" if "stdout-path" is not found. However, the
+"linux,stdout-path" and "stdout" properties are deprecated. New platforms
+should only use the "stdout-path" property.
diff --git a/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt b/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt
new file mode 100644
index 0000000..00d26ed
--- /dev/null
+++ b/Documentation/devicetree/bindings/clock/bcm-cygnus-clock.txt
@@ -0,0 +1,34 @@
+Broadcom Cygnus Clocks
+
+This binding uses the common clock binding:
+Documentation/devicetree/bindings/clock/clock-bindings.txt
+
+Currently various "fixed" clocks are declared for peripheral drivers that use
+the common clock framework to reference their core clocks. Proper support of
+these clocks will be added later
+
+Device tree example:
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ osc: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <1>;
+ clock-frequency = <25000000>;
+ };
+
+ apb_clk: apb_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000000>;
+ };
+
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <500000000>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/clock/vf610-clock.txt b/Documentation/devicetree/bindings/clock/vf610-clock.txt
index c80863d..63f9f1a 100644
--- a/Documentation/devicetree/bindings/clock/vf610-clock.txt
+++ b/Documentation/devicetree/bindings/clock/vf610-clock.txt
@@ -5,6 +5,19 @@ Required properties:
- reg: Address and length of the register set
- #clock-cells: Should be <1>
+Optional properties:
+- clocks: list of clock identifiers which are external input clocks to the
+ given clock controller. Please refer the next section to find
+ the input clocks for a given controller.
+- clock-names: list of names of clocks which are exteral input clocks to the
+ given clock controller.
+
+Input clocks for top clock controller:
+ - sxosc (external crystal oscillator 32KHz, recommended)
+ - fxosc (external crystal oscillator 24MHz, recommended)
+ - audio_ext
+ - enet_ext
+
The clock consumer should specify the desired clock by having the clock
ID in its "clocks" phandle cell. See include/dt-bindings/clock/vf610-clock.h
for the full list of VF610 clock IDs.
@@ -15,6 +28,8 @@ clks: ccm@4006b000 {
compatible = "fsl,vf610-ccm";
reg = <0x4006b000 0x1000>;
#clock-cells = <1>;
+ clocks = <&sxosc>, <&fxosc>;
+ clock-names = "sxosc", "fxosc";
};
uart1: serial@40028000 {
diff --git a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
index 1405ed0..e4c4d47 100644
--- a/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
+++ b/Documentation/devicetree/bindings/dma/xilinx/xilinx_vdma.txt
@@ -25,7 +25,7 @@ Required child node properties:
- compatible: It should be either "xlnx,axi-vdma-mm2s-channel" or
"xlnx,axi-vdma-s2mm-channel".
- interrupts: Should contain per channel VDMA interrupts.
-- xlnx,data-width: Should contain the stream data width, take values
+- xlnx,datawidth: Should contain the stream data width, take values
{32,64...1024}.
Optional child node properties:
diff --git a/Documentation/devicetree/bindings/hwmon/ltc2978.txt b/Documentation/devicetree/bindings/hwmon/ltc2978.txt
new file mode 100644
index 0000000..ed2f09d
--- /dev/null
+++ b/Documentation/devicetree/bindings/hwmon/ltc2978.txt
@@ -0,0 +1,39 @@
+ltc2978
+
+Required properties:
+- compatible: should contain one of:
+ * "lltc,ltc2974"
+ * "lltc,ltc2977"
+ * "lltc,ltc2978"
+ * "lltc,ltc3880"
+ * "lltc,ltc3883"
+ * "lltc,ltm4676"
+- reg: I2C slave address
+
+Optional properties:
+- regulators: A node that houses a sub-node for each regulator controlled by
+ the device. Each sub-node is identified using the node's name, with valid
+ values listed below. The content of each sub-node is defined by the
+ standard binding for regulators; see regulator.txt.
+
+Valid names of regulators depend on number of supplies supported per device:
+ * ltc2974 : vout0 - vout3
+ * ltc2977 : vout0 - vout7
+ * ltc2978 : vout0 - vout7
+ * ltc3880 : vout0 - vout1
+ * ltc3883 : vout0
+ * ltm4676 : vout0 - vout1
+
+Example:
+ltc2978@5e {
+ compatible = "lltc,ltc2978";
+ reg = <0x5e>;
+ regulators {
+ vout0 {
+ regulator-name = "FPGA-2.5V";
+ };
+ vout2 {
+ regulator-name = "FPGA-1.5V";
+ };
+ };
+};
diff --git a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
index 278de8e..89b3250 100644
--- a/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
+++ b/Documentation/devicetree/bindings/i2c/i2c-s3c2410.txt
@@ -32,6 +32,7 @@ Optional properties:
specified, default value is 0.
- samsung,i2c-max-bus-freq: Desired frequency in Hz of the bus. If not
specified, the default value in Hz is 100000.
+ - samsung,sysreg-phandle - handle to syscon used to control the system registers
Example:
diff --git a/Documentation/devicetree/bindings/i2c/trivial-devices.txt b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
index fbde415..605dcca 100644
--- a/Documentation/devicetree/bindings/i2c/trivial-devices.txt
+++ b/Documentation/devicetree/bindings/i2c/trivial-devices.txt
@@ -56,6 +56,8 @@ gmt,g751 G751: Digital Temperature Sensor and Thermal Watchdog with Two-Wire In
infineon,slb9635tt Infineon SLB9635 (Soft-) I2C TPM (old protocol, max 100khz)
infineon,slb9645tt Infineon SLB9645 I2C TPM (new protocol, max 400khz)
isl,isl12057 Intersil ISL12057 I2C RTC Chip
+isil,isl29028 (deprecated, use isl)
+isl,isl29028 Intersil ISL29028 Ambient Light and Proximity Sensor
maxim,ds1050 5 Bit Programmable, Pulse-Width Modulator
maxim,max1237 Low-Power, 4-/12-Channel, 2-Wire Serial, 12-Bit ADCs
maxim,max6625 9-Bit/12-Bit Temperature Sensors with I²C-Compatible Serial Interface
diff --git a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
index ff812a8..bae1f21 100644
--- a/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
+++ b/Documentation/devicetree/bindings/interrupt-controller/brcm,bcm7120-l2-intc.txt
@@ -13,7 +13,12 @@ Such an interrupt controller has the following hardware design:
or if they will output an interrupt signal at this 2nd level interrupt
controller, in particular for UARTs
-- not all 32-bits within the interrupt controller actually map to an interrupt
+- typically has one 32-bit enable word and one 32-bit status word, but on
+ some hardware may have more than one enable/status pair
+
+- no atomic set/clear operations
+
+- not all bits within the interrupt controller actually map to an interrupt
The typical hardware layout for this controller is represented below:
@@ -48,7 +53,9 @@ The typical hardware layout for this controller is represented below:
Required properties:
- compatible: should be "brcm,bcm7120-l2-intc"
-- reg: specifies the base physical address and size of the registers
+- reg: specifies the base physical address and size of the registers;
+ multiple pairs may be specified, with the first pair handling IRQ offsets
+ 0..31 and the second pair handling 32..63
- interrupt-controller: identifies the node as an interrupt controller
- #interrupt-cells: specifies the number of cells needed to encode an interrupt
source, should be 1.
@@ -59,18 +66,21 @@ Required properties:
- brcm,int-map-mask: 32-bits bit mask describing how many and which interrupts
are wired to this 2nd level interrupt controller, and how they match their
respective interrupt parents. Should match exactly the number of interrupts
- specified in the 'interrupts' property.
+ specified in the 'interrupts' property, multiplied by the number of
+ enable/status register pairs implemented by this controller. For
+ multiple parent IRQs with multiple enable/status words, this looks like:
+ <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
Optional properties:
- brcm,irq-can-wake: if present, this means the L2 controller can be used as a
wakeup source for system suspend/resume.
-- brcm,int-fwd-mask: if present, a 32-bits bit mask to configure for the
- interrupts which have a mux gate, typically UARTs. Setting these bits will
- make their respective interrupts outputs bypass this 2nd level interrupt
- controller completely, it completely transparent for the interrupt controller
- parent
+- brcm,int-fwd-mask: if present, a bit mask to configure the interrupts which
+ have a mux gate, typically UARTs. Setting these bits will make their
+ respective interrupt outputs bypass this 2nd level interrupt controller
+ completely; it is completely transparent for the interrupt controller
+ parent. This should have one 32-bit word per enable/status pair.
Example:
diff --git a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
index 48edc4b..d1a0433 100644
--- a/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
+++ b/Documentation/devicetree/bindings/mailbox/omap-mailbox.txt
@@ -43,6 +43,9 @@ Required properties:
device. The format is dependent on which interrupt
controller the OMAP device uses
- ti,hwmods: Name of the hwmod associated with the mailbox
+- #mbox-cells: Common mailbox binding property to identify the number
+ of cells required for the mailbox specifier. Should be
+ 1
- ti,mbox-num-users: Number of targets (processor devices) that the mailbox
device can interrupt
- ti,mbox-num-fifos: Number of h/w fifo queues within the mailbox IP block
@@ -72,6 +75,18 @@ data that represent the following:
Cell #3 (usr_id) - mailbox user id for identifying the interrupt line
associated with generating a tx/rx fifo interrupt.
+Mailbox Users:
+==============
+A device needing to communicate with a target processor device should specify
+them using the common mailbox binding properties, "mboxes" and the optional
+"mbox-names" (please see Documentation/devicetree/bindings/mailbox/mailbox.txt
+for details). Each value of the mboxes property should contain a phandle to the
+mailbox controller device node and an args specifier that will be the phandle to
+the intended sub-mailbox child node to be used for communication. The equivalent
+"mbox-names" property value can be used to give a name to the communication channel
+to be used by the client user.
+
+
Example:
--------
@@ -81,6 +96,7 @@ mailbox: mailbox@4a0f4000 {
reg = <0x4a0f4000 0x200>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <3>;
ti,mbox-num-fifos = <8>;
mbox_ipu: mbox_ipu {
@@ -93,12 +109,19 @@ mailbox: mailbox@4a0f4000 {
};
};
+dsp {
+ ...
+ mboxes = <&mailbox &mbox_dsp>;
+ ...
+};
+
/* AM33xx */
mailbox: mailbox@480C8000 {
compatible = "ti,omap4-mailbox";
reg = <0x480C8000 0x200>;
interrupts = <77>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <8>;
mbox_wkupm3: wkup_m3 {
diff --git a/Documentation/devicetree/bindings/media/meson-ir.txt b/Documentation/devicetree/bindings/media/meson-ir.txt
new file mode 100644
index 0000000..407848e
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/meson-ir.txt
@@ -0,0 +1,14 @@
+* Amlogic Meson IR remote control receiver
+
+Required properties:
+ - compatible : should be "amlogic,meson6-ir"
+ - reg : physical base address and length of the device registers
+ - interrupts : a single specifier for the interrupt from the device
+
+Example:
+
+ ir-receiver@c8100480 {
+ compatible= "amlogic,meson6-ir";
+ reg = <0xc8100480 0x20>;
+ interrupts = <0 15 1>;
+ };
diff --git a/Documentation/devicetree/bindings/media/si4713.txt b/Documentation/devicetree/bindings/media/si4713.txt
new file mode 100644
index 0000000..5ee5552
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/si4713.txt
@@ -0,0 +1,30 @@
+* Silicon Labs FM Radio transmitter
+
+The Silicon Labs Si4713 is an FM radio transmitter with receive power scan
+supporting 76-108 MHz. It includes an RDS encoder and has both, a stereo-analog
+and a digital interface, which supports I2S, left-justified and a custom
+DSP-mode format. It is programmable through an I2C interface.
+
+Required Properties:
+- compatible: Should contain "silabs,si4713"
+- reg: the I2C address of the device
+
+Optional Properties:
+- interrupts-extended: Interrupt specifier for the chips interrupt
+- reset-gpios: GPIO specifier for the chips reset line
+- vdd-supply: phandle for Vdd regulator
+- vio-supply: phandle for Vio regulator
+
+Example:
+
+&i2c2 {
+ fmtx: si4713@63 {
+ compatible = "silabs,si4713";
+ reg = <0x63>;
+
+ interrupts-extended = <&gpio2 21 IRQ_TYPE_EDGE_FALLING>; /* 53 */
+ reset-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 */
+ vio-supply = <&vio>;
+ vdd-supply = <&vaux1>;
+ };
+};
diff --git a/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt
new file mode 100644
index 0000000..89657d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/mvebu-sdram-controller.txt
@@ -0,0 +1,21 @@
+Device Tree bindings for MVEBU SDRAM controllers
+
+The Marvell EBU SoCs all have a SDRAM controller. The SDRAM controller
+differs from one SoC variant to another, but they also share a number
+of commonalities.
+
+For now, this Device Tree binding documentation only documents the
+Armada XP SDRAM controller.
+
+Required properties:
+
+ - compatible: for Armada XP, "marvell,armada-xp-sdram-controller"
+ - reg: a resource specifier for the register space, which should
+ include all SDRAM controller registers as per the datasheet.
+
+Example:
+
+sdramc@1400 {
+ compatible = "marvell,armada-xp-sdram-controller";
+ reg = <0x1400 0x500>;
+};
diff --git a/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
new file mode 100644
index 0000000..f3db93c
--- /dev/null
+++ b/Documentation/devicetree/bindings/memory-controllers/nvidia,tegra-mc.txt
@@ -0,0 +1,36 @@
+NVIDIA Tegra Memory Controller device tree bindings
+===================================================
+
+Required properties:
+- compatible: Should be "nvidia,tegra<chip>-mc"
+- reg: Physical base address and length of the controller's registers.
+- clocks: Must contain an entry for each entry in clock-names.
+ See ../clocks/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+ - mc: the module's clock input
+- interrupts: The interrupt outputs from the controller.
+- #iommu-cells: Should be 1. The single cell of the IOMMU specifier defines
+ the SWGROUP of the master.
+
+This device implements an IOMMU that complies with the generic IOMMU binding.
+See ../iommu/iommu.txt for details.
+
+Example:
+--------
+
+ mc: memory-controller@0,70019000 {
+ compatible = "nvidia,tegra124-mc";
+ reg = <0x0 0x70019000 0x0 0x1000>;
+ clocks = <&tegra_car TEGRA124_CLK_MC>;
+ clock-names = "mc";
+
+ interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
+
+ #iommu-cells = <1>;
+ };
+
+ sdhci@0,700b0000 {
+ compatible = "nvidia,tegra124-sdhci";
+ ...
+ iommus = <&mc TEGRA_SWGROUP_SDMMC1A>;
+ };
diff --git a/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
new file mode 100644
index 0000000..f64de95a
--- /dev/null
+++ b/Documentation/devicetree/bindings/mfd/atmel-hlcdc.txt
@@ -0,0 +1,51 @@
+Device-Tree bindings for Atmel's HLCDC (High LCD Controller) MFD driver
+
+Required properties:
+ - compatible: value should be one of the following:
+ "atmel,sama5d3-hlcdc"
+ - reg: base address and size of the HLCDC device registers.
+ - clock-names: the name of the 3 clocks requested by the HLCDC device.
+ Should contain "periph_clk", "sys_clk" and "slow_clk".
+ - clocks: should contain the 3 clocks requested by the HLCDC device.
+ - interrupts: should contain the description of the HLCDC interrupt line
+
+The HLCDC IP exposes two subdevices:
+ - a PWM chip: see ../pwm/atmel-hlcdc-pwm.txt
+ - a Display Controller: see ../drm/atmel-hlcdc-dc.txt
+
+Example:
+
+ hlcdc: hlcdc@f0030000 {
+ compatible = "atmel,sama5d3-hlcdc";
+ reg = <0xf0030000 0x2000>;
+ clocks = <&lcdc_clk>, <&lcdck>, <&clk32k>;
+ clock-names = "periph_clk","sys_clk", "slow_clk";
+ interrupts = <36 IRQ_TYPE_LEVEL_HIGH 0>;
+ status = "disabled";
+
+ hlcdc-display-controller {
+ compatible = "atmel,hlcdc-display-controller";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcd_base &pinctrl_lcd_rgb888>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ hlcdc_panel_output: endpoint@0 {
+ reg = <0>;
+ remote-endpoint = <&panel_input>;
+ };
+ };
+ };
+
+ hlcdc_pwm: hlcdc-pwm {
+ compatible = "atmel,hlcdc-pwm";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_lcd_pwm>;
+ #pwm-cells = <3>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/mfd/max77686.txt b/Documentation/devicetree/bindings/mfd/max77686.txt
index 678f3cf..75fdfaf 100644
--- a/Documentation/devicetree/bindings/mfd/max77686.txt
+++ b/Documentation/devicetree/bindings/mfd/max77686.txt
@@ -34,6 +34,12 @@ to get matched with their hardware counterparts as follow:
-BUCKn : for BUCKs, where n can lie in range 1 to 9.
example: BUCK1, BUCK5, BUCK9.
+ Regulators which can be turned off during system suspend:
+ -LDOn : 2, 6-8, 10-12, 14-16,
+ -BUCKn : 1-4.
+ Use standard regulator bindings for it ('regulator-off-in-suspend').
+
+
Example:
max77686@09 {
diff --git a/Documentation/devicetree/bindings/mfd/max77693.txt b/Documentation/devicetree/bindings/mfd/max77693.txt
index 11921cc..01e9f30 100644
--- a/Documentation/devicetree/bindings/mfd/max77693.txt
+++ b/Documentation/devicetree/bindings/mfd/max77693.txt
@@ -27,6 +27,20 @@ Optional properties:
[*] refer Documentation/devicetree/bindings/regulator/regulator.txt
+- haptic : The MAX77693 haptic device utilises a PWM controlled motor to provide
+ users with tactile feedback. PWM period and duty-cycle are varied in
+ order to provide the approprite level of feedback.
+
+ Required properties:
+ - compatible : Must be "maxim,max77693-hpatic"
+ - haptic-supply : power supply for the haptic motor
+ [*] refer Documentation/devicetree/bindings/regulator/regulator.txt
+ - pwms : phandle to the physical PWM(Pulse Width Modulation) device.
+ PWM properties should be named "pwms". And number of cell is different
+ for each pwm device.
+ To get more informations, please refer to documentaion.
+ [*] refer Documentation/devicetree/bindings/pwm/pwm.txt
+
Example:
max77693@66 {
compatible = "maxim,max77693";
@@ -52,4 +66,11 @@ Example:
regulator-boot-on;
};
};
+
+ haptic {
+ compatible = "maxim,max77693-haptic";
+ haptic-supply = <&haptic_supply>;
+ pwms = <&pwm 0 40000 0>;
+ pwm-names = "haptic";
+ };
};
diff --git a/Documentation/devicetree/bindings/mfd/s2mps11.txt b/Documentation/devicetree/bindings/mfd/s2mps11.txt
index 0e4026a..57a0450 100644
--- a/Documentation/devicetree/bindings/mfd/s2mps11.txt
+++ b/Documentation/devicetree/bindings/mfd/s2mps11.txt
@@ -1,5 +1,5 @@
-* Samsung S2MPS11, S2MPS14 and S2MPU02 Voltage and Current Regulator
+* Samsung S2MPS11, S2MPS13, S2MPS14 and S2MPU02 Voltage and Current Regulator
The Samsung S2MPS11 is a multi-function device which includes voltage and
current regulators, RTC, charger controller and other sub-blocks. It is
@@ -7,8 +7,8 @@ interfaced to the host controller using an I2C interface. Each sub-block is
addressed by the host system using different I2C slave addresses.
Required properties:
-- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps14-pmic"
- or "samsung,s2mpu02-pmic".
+- compatible: Should be "samsung,s2mps11-pmic" or "samsung,s2mps13-pmic"
+ or "samsung,s2mps14-pmic" or "samsung,s2mpu02-pmic".
- reg: Specifies the I2C slave address of the pmic block. It should be 0x66.
Optional properties:
@@ -17,8 +17,8 @@ Optional properties:
- interrupts: Interrupt specifiers for interrupt sources.
Optional nodes:
-- clocks: s2mps11 and s5m8767 provide three(AP/CP/BT) buffered 32.768 KHz
- outputs, so to register these as clocks with common clock framework
+- clocks: s2mps11, s2mps13 and s5m8767 provide three(AP/CP/BT) buffered 32.768
+ KHz outputs, so to register these as clocks with common clock framework
instantiate a sub-node named "clocks". It uses the common clock binding
documented in :
[Documentation/devicetree/bindings/clock/clock-bindings.txt]
@@ -30,12 +30,12 @@ Optional nodes:
the clock which they consume.
Clock ID Devices
----------------------------------------------------------
- 32KhzAP 0 S2MPS11, S2MPS14, S5M8767
- 32KhzCP 1 S2MPS11, S5M8767
- 32KhzBT 2 S2MPS11, S2MPS14, S5M8767
+ 32KhzAP 0 S2MPS11, S2MPS13, S2MPS14, S5M8767
+ 32KhzCP 1 S2MPS11, S2MPS13, S5M8767
+ 32KhzBT 2 S2MPS11, S2MPS13, S2MPS14, S5M8767
- - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps14-clk",
- "samsung,s5m8767-clk"
+ - compatible: Should be one of: "samsung,s2mps11-clk", "samsung,s2mps13-clk",
+ "samsung,s2mps14-clk", "samsung,s5m8767-clk"
- regulators: The regulators of s2mps11 that have to be instantiated should be
included in a sub-node named 'regulators'. Regulator nodes included in this
@@ -81,12 +81,14 @@ as per the datasheet of s2mps11.
- LDOn
- valid values for n are:
- S2MPS11: 1 to 38
+ - S2MPS13: 1 to 40
- S2MPS14: 1 to 25
- S2MPU02: 1 to 28
- Example: LDO1, LDO2, LDO28
- BUCKn
- valid values for n are:
- S2MPS11: 1 to 10
+ - S2MPS13: 1 to 10
- S2MPS14: 1 to 5
- S2MPU02: 1 to 7
- Example: BUCK1, BUCK2, BUCK9
diff --git a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
index 6cd3525..ee4fc05 100644
--- a/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
+++ b/Documentation/devicetree/bindings/mmc/exynos-dw-mshc.txt
@@ -18,6 +18,10 @@ Required Properties:
specific extensions.
- "samsung,exynos5420-dw-mshc": for controllers with Samsung Exynos5420
specific extensions.
+ - "samsung,exynos7-dw-mshc": for controllers with Samsung Exynos7
+ specific extensions.
+ - "samsung,exynos7-dw-mshc-smu": for controllers with Samsung Exynos7
+ specific extensions having an SMU.
* samsung,dw-mshc-ciu-div: Specifies the divider value for the card interface
unit (ciu) clock. This property is applicable only for Exynos5 SoC's and
diff --git a/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt b/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt
new file mode 100644
index 0000000..85de99f
--- /dev/null
+++ b/Documentation/devicetree/bindings/mmc/img-dw-mshc.txt
@@ -0,0 +1,29 @@
+* Imagination specific extensions to the Synopsys Designware Mobile Storage
+ Host Controller
+
+The Synopsys 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 Synopsys dw mshc controller properties described
+by synopsys-dw-mshc.txt and the properties used by the Imagination specific
+extensions to the Synopsys Designware Mobile Storage Host Controller.
+
+Required Properties:
+
+* compatible: should be
+ - "img,pistachio-dw-mshc": for Pistachio SoCs
+
+Example:
+
+ mmc@18142000 {
+ compatible = "img,pistachio-dw-mshc";
+ reg = <0x18142000 0x400>;
+ interrupts = <GIC_SHARED 39 IRQ_TYPE_LEVEL_HIGH>;
+
+ clocks = <&system_clk>, <&sdhost_clk>;
+ clock-names = "biu", "ciu";
+
+ fifo-depth = <0x20>;
+ bus-width = <4>;
+ num-slots = <1>;
+ disable-wp;
+ };
diff --git a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
index 86223c3..4dd6deb 100644
--- a/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
+++ b/Documentation/devicetree/bindings/mmc/sdhci-pxa.txt
@@ -12,6 +12,10 @@ Required properties:
* for "marvell,armada-380-sdhci", two register areas. The first one
for the SDHCI registers themselves, and the second one for the
AXI/Mbus bridge registers of the SDHCI unit.
+- clocks: Array of clocks required for SDHCI; requires at least one for
+ I/O clock.
+- clock-names: Array of names corresponding to clocks property; shall be
+ "io" for I/O clock and "core" for optional core clock.
Optional properties:
- mrvl,clk-delay-cycles: Specify a number of cycles to delay for tuning.
@@ -23,6 +27,8 @@ sdhci@d4280800 {
reg = <0xd4280800 0x800>;
bus-width = <8>;
interrupts = <27>;
+ clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>;
+ clock-names = "io", "core";
non-removable;
mrvl,clk-delay-cycles = <31>;
};
@@ -32,5 +38,6 @@ sdhci@d8000 {
reg = <0xd8000 0x1000>, <0xdc000 0x100>;
interrupts = <0 25 0x4>;
clocks = <&gateclk 17>;
+ clock-names = "io";
mrvl,clk-delay-cycles = <0x1F>;
};
diff --git a/Documentation/devicetree/bindings/nios2/nios2.txt b/Documentation/devicetree/bindings/nios2/nios2.txt
new file mode 100644
index 0000000..d6d0a94
--- /dev/null
+++ b/Documentation/devicetree/bindings/nios2/nios2.txt
@@ -0,0 +1,62 @@
+* Nios II Processor Binding
+
+This binding specifies what properties available in the device tree
+representation of a Nios II Processor Core.
+
+Users can use sopc2dts tool for generating device tree sources (dts) from a
+Qsys system. See more detail in: http://www.alterawiki.com/wiki/Sopc2dts
+
+Required properties:
+
+- compatible: Compatible property value should be "altr,nios2-1.0".
+- reg: Contains CPU index.
+- interrupt-controller: Specifies that the node is an interrupt controller
+- #interrupt-cells: Specifies the number of cells needed to encode an
+ interrupt source, should be 1.
+- clock-frequency: Contains the clock frequency for CPU, in Hz.
+- dcache-line-size: Contains data cache line size.
+- icache-line-size: Contains instruction line size.
+- dcache-size: Contains data cache size.
+- icache-size: Contains instruction cache size.
+- altr,pid-num-bits: Specifies the number of bits to use to represent the process
+ identifier (PID).
+- altr,tlb-num-ways: Specifies the number of set-associativity ways in the TLB.
+- altr,tlb-num-entries: Specifies the number of entries in the TLB.
+- altr,tlb-ptr-sz: Specifies size of TLB pointer.
+- altr,has-mul: Specifies CPU hardware multipy support, should be 1.
+- altr,has-mmu: Specifies CPU support MMU support, should be 1.
+- altr,has-initda: Specifies CPU support initda instruction, should be 1.
+- altr,reset-addr: Specifies CPU reset address
+- altr,fast-tlb-miss-addr: Specifies CPU fast TLB miss exception address
+- altr,exception-addr: Specifies CPU exception address
+
+Optional properties:
+- altr,has-div: Specifies CPU hardware divide support
+- altr,implementation: Nios II core implementation, this should be "fast";
+
+Example:
+
+cpu@0x0 {
+ device_type = "cpu";
+ compatible = "altr,nios2-1.0";
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ clock-frequency = <125000000>;
+ dcache-line-size = <32>;
+ icache-line-size = <32>;
+ dcache-size = <32768>;
+ icache-size = <32768>;
+ altr,implementation = "fast";
+ altr,pid-num-bits = <8>;
+ altr,tlb-num-ways = <16>;
+ altr,tlb-num-entries = <128>;
+ altr,tlb-ptr-sz = <7>;
+ altr,has-div = <1>;
+ altr,has-mul = <1>;
+ altr,reset-addr = <0xc2800000>;
+ altr,fast-tlb-miss-addr = <0xc7fff400>;
+ altr,exception-addr = <0xd0000020>;
+ altr,has-initda = <1>;
+ altr,has-mmu = <1>;
+};
diff --git a/Documentation/devicetree/bindings/nios2/timer.txt b/Documentation/devicetree/bindings/nios2/timer.txt
new file mode 100644
index 0000000..904a584
--- /dev/null
+++ b/Documentation/devicetree/bindings/nios2/timer.txt
@@ -0,0 +1,19 @@
+Altera Timer
+
+Required properties:
+
+- compatible : should be "altr,timer-1.0"
+- reg : Specifies base physical address and size of the registers.
+- interrupt-parent: phandle of the interrupt controller
+- interrupts : Should contain the timer interrupt number
+- clock-frequency : The frequency of the clock that drives the counter, in Hz.
+
+Example:
+
+timer {
+ compatible = "altr,timer-1.0";
+ reg = <0x00400000 0x00000020>;
+ interrupt-parent = <&cpu>;
+ interrupts = <11>;
+ clock-frequency = <125000000>;
+};
diff --git a/Documentation/devicetree/bindings/pci/layerscape-pci.txt b/Documentation/devicetree/bindings/pci/layerscape-pci.txt
new file mode 100644
index 0000000..6286f04
--- /dev/null
+++ b/Documentation/devicetree/bindings/pci/layerscape-pci.txt
@@ -0,0 +1,42 @@
+Freescale Layerscape PCIe controller
+
+This PCIe host controller is based on the Synopsis Designware PCIe IP
+and thus inherits all the common properties defined in designware-pcie.txt.
+
+Required properties:
+- compatible: should contain the platform identifier such as "fsl,ls1021a-pcie"
+- reg: base addresses and lengths of the PCIe controller
+- interrupts: A list of interrupt outputs of the controller. Must contain an
+ entry for each entry in the interrupt-names property.
+- interrupt-names: Must include the following entries:
+ "intr": The interrupt that is asserted for controller interrupts
+- fsl,pcie-scfg: Must include two entries.
+ The first entry must be a link to the SCFG device node
+ The second entry must be '0' or '1' based on physical PCIe controller index.
+ This is used to get SCFG PEXN registers
+
+Example:
+
+ pcie@3400000 {
+ compatible = "fsl,ls1021a-pcie", "snps,dw-pcie";
+ reg = <0x00 0x03400000 0x0 0x00010000 /* controller registers */
+ 0x40 0x00000000 0x0 0x00002000>; /* configuration space */
+ reg-names = "regs", "config";
+ interrupts = <GIC_SPI 177 IRQ_TYPE_LEVEL_HIGH>; /* controller interrupt */
+ interrupt-names = "intr";
+ fsl,pcie-scfg = <&scfg 0>;
+ #address-cells = <3>;
+ #size-cells = <2>;
+ device_type = "pci";
+ num-lanes = <4>;
+ bus-range = <0x0 0xff>;
+ ranges = <0x81000000 0x0 0x00000000 0x40 0x00010000 0x0 0x00010000 /* downstream I/O */
+ 0xc2000000 0x0 0x20000000 0x40 0x20000000 0x0 0x20000000 /* prefetchable memory */
+ 0x82000000 0x0 0x40000000 0x40 0x40000000 0x0 0x40000000>; /* non-prefetchable memory */
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0000 0 0 1 &gic GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <0000 0 0 2 &gic GIC_SPI 188 IRQ_TYPE_LEVEL_HIGH>,
+ <0000 0 0 3 &gic GIC_SPI 190 IRQ_TYPE_LEVEL_HIGH>,
+ <0000 0 0 4 &gic GIC_SPI 192 IRQ_TYPE_LEVEL_HIGH>;
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
index 49d0e60..509faa8 100644
--- a/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/img,tz1090-pinctrl.txt
@@ -67,7 +67,7 @@ Valid values for pin and group names are:
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.
+ function 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
diff --git a/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
new file mode 100644
index 0000000..17e7240
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/meson,pinctrl.txt
@@ -0,0 +1,96 @@
+== Amlogic Meson pinmux controller ==
+
+Required properties for the root node:
+ - compatible: "amlogic,meson8-pinctrl"
+ - reg: address and size of registers controlling irq functionality
+
+=== GPIO sub-nodes ===
+
+The 2 power domains of the controller (regular and always-on) are
+represented as sub-nodes and each of them acts as a GPIO controller.
+
+Required properties for sub-nodes are:
+ - reg: should contain address and size for mux, pull-enable, pull and
+ gpio register sets
+ - reg-names: an array of strings describing the "reg" entries. Must
+ contain "mux", "pull" and "gpio". "pull-enable" is optional and
+ when it is missing the "pull" registers are used instead
+ - gpio-controller: identifies the node as a gpio controller
+ - #gpio-cells: must be 2
+
+Valid sub-node names are:
+ - "banks" for the regular domain
+ - "ao-bank" for the always-on domain
+
+=== Other sub-nodes ===
+
+Child nodes without the "gpio-controller" represent some desired
+configuration for a pin or a group. Those nodes can be pinmux nodes or
+configuration nodes.
+
+Required properties for pinmux nodes are:
+ - groups: a list of pinmux groups. The list of all available groups
+ depends on the SoC and can be found in driver sources.
+ - function: the name of a function to activate for the specified set
+ of groups. The list of all available functions depends on the SoC
+ and can be found in driver sources.
+
+Required properties for configuration nodes:
+ - pins: a list of pin names
+
+Configuration nodes support the generic properties "bias-disable",
+"bias-pull-up" and "bias-pull-down", described in file
+pinctrl-bindings.txt
+
+=== Example ===
+
+ pinctrl: pinctrl@c1109880 {
+ compatible = "amlogic,meson8-pinctrl";
+ reg = <0xc1109880 0x10>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ gpio: banks@c11080b0 {
+ reg = <0xc11080b0 0x28>,
+ <0xc11080e8 0x18>,
+ <0xc1108120 0x18>,
+ <0xc1108030 0x30>;
+ reg-names = "mux", "pull", "pull-enable", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ gpio_ao: ao-bank@c1108030 {
+ reg = <0xc8100014 0x4>,
+ <0xc810002c 0x4>,
+ <0xc8100024 0x8>;
+ reg-names = "mux", "pull", "gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+
+ nand {
+ mux {
+ groups = "nand_io", "nand_io_ce0", "nand_io_ce1",
+ "nand_io_rb0", "nand_ale", "nand_cle",
+ "nand_wen_clk", "nand_ren_clk", "nand_dqs",
+ "nand_ce2", "nand_ce3";
+ function = "nand";
+ };
+ };
+
+ uart_ao_a {
+ mux {
+ groups = "uart_tx_ao_a", "uart_rx_ao_a",
+ "uart_cts_ao_a", "uart_rts_ao_a";
+ function = "uart_ao";
+ };
+
+ conf {
+ pins = "GPIOAO_0", "GPIOAO_1",
+ "GPIOAO_2", "GPIOAO_3";
+ bias-disable;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
index 98eb94d..47d84b6 100644
--- a/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
+++ b/Documentation/devicetree/bindings/pinctrl/pinctrl-bindings.txt
@@ -216,4 +216,4 @@ arguments are described below.
or 0 to disable debouncing
More in-depth documentation on these parameters can be found in
-<include/linux/pinctrl/pinconfig-generic.h>
+<include/linux/pinctrl/pinconf-generic.h>
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
new file mode 100644
index 0000000..7ed0804
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-gpio.txt
@@ -0,0 +1,215 @@
+Qualcomm PMIC GPIO block
+
+This binding describes the GPIO block(s) found in the 8xxx series of
+PMIC's from Qualcomm.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: must be one of:
+ "qcom,pm8018-gpio"
+ "qcom,pm8038-gpio"
+ "qcom,pm8058-gpio"
+ "qcom,pm8917-gpio"
+ "qcom,pm8921-gpio"
+ "qcom,pm8941-gpio"
+ "qcom,pma8084-gpio"
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Register base of the GPIO block and length.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Must contain an array of encoded interrupt specifiers for
+ each available GPIO
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: Mark the device node as a GPIO controller
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: Must be 2;
+ the first cell will be used to define gpio number and the
+ second denotes the flags for this gpio
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin or a list of pins. This configuration can include the
+mux function to select on those pin(s), and various pin configuration
+parameters, as listed below.
+
+
+SUBNODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of gpio pins affected by the properties specified in
+ this subnode. Valid pins are:
+ gpio1-gpio6 for pm8018
+ gpio1-gpio12 for pm8038
+ gpio1-gpio40 for pm8058
+ gpio1-gpio38 for pm8917
+ gpio1-gpio44 for pm8921
+ gpio1-gpio36 for pm8941
+ gpio1-gpio22 for pma8084
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins. Valid values are:
+ "normal",
+ "paired",
+ "func1",
+ "func2",
+ "dtest1",
+ "dtest2",
+ "dtest3",
+ "dtest4"
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configured as no pull.
+
+- bias-pull-down:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configured as pull down.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <empty>
+ Definition: The specified pins should be configured as pull up.
+
+- qcom,pull-up-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Specifies the strength to use for pull up, if selected.
+ Valid values are; as defined in
+ <dt-bindings/pinctrl/qcom,pmic-gpio.h>:
+ 1: 30uA (PMIC_GPIO_PULL_UP_30)
+ 2: 1.5uA (PMIC_GPIO_PULL_UP_1P5)
+ 3: 31.5uA (PMIC_GPIO_PULL_UP_31P5)
+ 4: 1.5uA + 30uA boost (PMIC_GPIO_PULL_UP_1P5_30)
+ If this property is ommited 30uA strength will be used if
+ pull up is selected
+
+- bias-high-impedance:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins will put in high-Z mode and disabled.
+
+- input-enable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are put in input mode.
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+
+- power-source:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the power source for the specified pins. Valid
+ power sources are defined per chip in
+ <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+- qcom,drive-strength:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the drive strength for the specified pins. Value
+ drive strengths are:
+ 0: no (PMIC_GPIO_STRENGTH_NO)
+ 1: high (PMIC_GPIO_STRENGTH_HIGH) 0.9mA @ 1.8V - 1.9mA @ 2.6V
+ 2: medium (PMIC_GPIO_STRENGTH_MED) 0.6mA @ 1.8V - 1.25mA @ 2.6V
+ 3: low (PMIC_GPIO_STRENGTH_LOW) 0.15mA @ 1.8V - 0.3mA @ 2.6V
+ as defined in <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+- drive-push-pull:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in push-pull mode.
+
+- drive-open-drain:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in open-drain mode.
+
+- drive-open-source:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in open-source mode.
+
+Example:
+
+ pm8921_gpio: gpio@150 {
+ compatible = "qcom,pm8921-gpio";
+ reg = <0x150 0x160>;
+ interrupts = <192 1>, <193 1>, <194 1>,
+ <195 1>, <196 1>, <197 1>,
+ <198 1>, <199 1>, <200 1>,
+ <201 1>, <202 1>, <203 1>,
+ <204 1>, <205 1>, <206 1>,
+ <207 1>, <208 1>, <209 1>,
+ <210 1>, <211 1>, <212 1>,
+ <213 1>, <214 1>, <215 1>,
+ <216 1>, <217 1>, <218 1>,
+ <219 1>, <220 1>, <221 1>,
+ <222 1>, <223 1>, <224 1>,
+ <225 1>, <226 1>, <227 1>,
+ <228 1>, <229 1>, <230 1>,
+ <231 1>, <232 1>, <233 1>,
+ <234 1>, <235 1>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ pm8921_gpio_keys: gpio-keys {
+ volume-keys {
+ pins = "gpio20", "gpio21";
+ function = "normal";
+
+ input-enable;
+ bias-pull-up;
+ drive-push-pull;
+ qcom,drive-strength = <PMIC_GPIO_STRENGTH_NO>;
+ power-source = <PM8921_GPIO_S4>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
new file mode 100644
index 0000000..854774b1
--- /dev/null
+++ b/Documentation/devicetree/bindings/pinctrl/qcom,pmic-mpp.txt
@@ -0,0 +1,162 @@
+Qualcomm PMIC Multi-Purpose Pin (MPP) block
+
+This binding describes the MPP block(s) found in the 8xxx series
+of PMIC's from Qualcomm.
+
+- compatible:
+ Usage: required
+ Value type: <string>
+ Definition: Should contain one of:
+ "qcom,pm8841-mpp",
+ "qcom,pm8941-mpp",
+ "qcom,pma8084-mpp",
+
+- reg:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Register base of the MPP block and length.
+
+- interrupts:
+ Usage: required
+ Value type: <prop-encoded-array>
+ Definition: Must contain an array of encoded interrupt specifiers for
+ each available MPP
+
+- gpio-controller:
+ Usage: required
+ Value type: <none>
+ Definition: Mark the device node as a GPIO controller
+
+- #gpio-cells:
+ Usage: required
+ Value type: <u32>
+ Definition: Must be 2;
+ the first cell will be used to define MPP number and the
+ second denotes the flags for this MPP
+
+Please refer to ../gpio/gpio.txt and ../interrupt-controller/interrupts.txt for
+a general description of GPIO and interrupt bindings.
+
+Please refer to pinctrl-bindings.txt in this directory for details of the
+common pinctrl bindings used by client devices, including the meaning of the
+phrase "pin configuration node".
+
+The pin configuration nodes act as a container for an arbitrary number of
+subnodes. Each of these subnodes represents some desired configuration for a
+pin or a list of pins. This configuration can include the
+mux function to select on those pin(s), and various pin configuration
+parameters, as listed below.
+
+SUBNODES:
+
+The name of each subnode is not important; all subnodes should be enumerated
+and processed purely based on their content.
+
+Each subnode only affects those parameters that are explicitly listed. In
+other words, a subnode that lists a mux function but no pin configuration
+parameters implies no information about any pin configuration parameters.
+Similarly, a pin subnode that describes a pullup parameter implies no
+information about e.g. the mux function.
+
+The following generic properties as defined in pinctrl-bindings.txt are valid
+to specify in a pin configuration subnode:
+
+- pins:
+ Usage: required
+ Value type: <string-array>
+ Definition: List of MPP pins affected by the properties specified in
+ this subnode. Valid pins are:
+ mpp1-mpp4 for pm8841
+ mpp1-mpp8 for pm8941
+ mpp1-mpp4 for pma8084
+
+- function:
+ Usage: required
+ Value type: <string>
+ Definition: Specify the alternative function to be configured for the
+ specified pins. Valid values are:
+ "normal",
+ "paired",
+ "dtest1",
+ "dtest2",
+ "dtest3",
+ "dtest4"
+
+- bias-disable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins should be configured as no pull.
+
+- bias-pull-up:
+ Usage: optional
+ Value type: <u32>
+ Definition: The specified pins should be configured as pull up.
+ Valid values are 600, 10000 and 30000 in bidirectional mode
+ only, i.e. when operating in qcom,analog-mode and input and
+ outputs are enabled. The hardware ignores the configuration
+ when operating in other modes.
+
+- bias-high-impedance:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins will put in high-Z mode and disabled.
+
+- input-enable:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are put in input mode, i.e. their input
+ buffer is enabled
+
+- output-high:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ high.
+
+- output-low:
+ Usage: optional
+ Value type: <none>
+ Definition: The specified pins are configured in output mode, driven
+ low.
+
+- power-source:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the power source for the specified pins. Valid power
+ sources are defined in <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+
+- qcom,analog-mode:
+ Usage: optional
+ Value type: <none>
+ Definition: Selects Analog mode of operation: combined with input-enable
+ and/or output-high, output-low MPP could operate as
+ Bidirectional Logic, Analog Input, Analog Output.
+
+- qcom,amux-route:
+ Usage: optional
+ Value type: <u32>
+ Definition: Selects the source for analog input. Valid values are
+ defined in <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+ PMIC_MPP_AMUX_ROUTE_CH5, PMIC_MPP_AMUX_ROUTE_CH6...
+
+Example:
+
+ mpps@a000 {
+ compatible = "qcom,pm8841-mpp";
+ reg = <0xa000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts = <4 0xa0 0 0>, <4 0xa1 0 0>, <4 0xa2 0 0>, <4 0xa3 0 0>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&pm8841_default>;
+
+ pm8841_default: default {
+ gpio {
+ pins = "mpp1", "mpp2", "mpp3", "mpp4";
+ function = "normal";
+ input-enable;
+ power-source = <PM8841_MPP_S3>;
+ };
+ };
+ };
diff --git a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
index e82aaf4..8425838 100644
--- a/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
+++ b/Documentation/devicetree/bindings/pinctrl/samsung-pinctrl.txt
@@ -18,6 +18,7 @@ Required Properties:
- "samsung,exynos5250-pinctrl": for Exynos5250 compatible pin-controller.
- "samsung,exynos5260-pinctrl": for Exynos5260 compatible pin-controller.
- "samsung,exynos5420-pinctrl": for Exynos5420 compatible pin-controller.
+ - "samsung,exynos7-pinctrl": for Exynos7 compatible pin-controller.
- reg: Base address of the pin controller hardware module and length of
the address space it occupies.
@@ -136,6 +137,8 @@ B. External Wakeup Interrupts: For supporting external wakeup interrupts, a
found on Samsung S3C64xx SoCs,
- samsung,exynos4210-wakeup-eint: represents wakeup interrupt controller
found on Samsung Exynos4210 and S5PC110/S5PV210 SoCs.
+ - samsung,exynos7-wakeup-eint: represents wakeup interrupt controller
+ found on Samsung Exynos7 SoC.
- interrupt-parent: phandle of the interrupt parent to which the external
wakeup interrupts are forwarded to.
- interrupts: interrupt used by multiplexed wakeup interrupts.
diff --git a/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt
index e3865e1..8769742 100644
--- a/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt
+++ b/Documentation/devicetree/bindings/pinctrl/ste,abx500.txt
@@ -8,42 +8,8 @@ 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>;
- };
+ST Ericsson's pin configuration nodes use the generic pin multiplexing
+and pin configuration bindings, see pinctrl-bindings.txt
Example board file extract:
@@ -54,11 +20,11 @@ Example board file extract:
sysclkreq2 {
sysclkreq2_default_mode: sysclkreq2_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq2_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq2_d_1";
};
default_cfg {
- ste,pins = "GPIO1";
+ pins = "GPIO1";
bias-disable;
};
};
@@ -66,11 +32,11 @@ Example board file extract:
sysclkreq3 {
sysclkreq3_default_mode: sysclkreq3_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq3_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq3_d_1";
};
default_cfg {
- ste,pins = "GPIO2";
+ pins = "GPIO2";
output-low;
};
};
@@ -78,11 +44,11 @@ Example board file extract:
gpio3 {
gpio3_default_mode: gpio3_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio3_a_1";
+ function = "gpio";
+ groups = "gpio3_a_1";
};
default_cfg {
- ste,pins = "GPIO3";
+ pins = "GPIO3";
output-low;
};
};
@@ -90,11 +56,11 @@ Example board file extract:
sysclkreq6 {
sysclkreq6_default_mode: sysclkreq6_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq6_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq6_d_1";
};
default_cfg {
- ste,pins = "GPIO4";
+ pins = "GPIO4";
bias-disable;
};
};
@@ -102,11 +68,11 @@ Example board file extract:
pwmout1 {
pwmout1_default_mode: pwmout1_default {
default_mux {
- ste,function = "pwmout";
- ste,pins = "pwmout1_d_1";
+ function = "pwmout";
+ groups = "pwmout1_d_1";
};
default_cfg {
- ste,pins = "GPIO14";
+ pins = "GPIO14";
output-low;
};
};
@@ -114,11 +80,11 @@ Example board file extract:
pwmout2 {
pwmout2_default_mode: pwmout2_default {
pwmout2_default_mux {
- ste,function = "pwmout";
- ste,pins = "pwmout2_d_1";
+ function = "pwmout";
+ groups = "pwmout2_d_1";
};
pwmout2_default_cfg {
- ste,pins = "GPIO15";
+ pins = "GPIO15";
output-low;
};
};
@@ -126,11 +92,11 @@ Example board file extract:
pwmout3 {
pwmout3_default_mode: pwmout3_default {
pwmout3_default_mux {
- ste,function = "pwmout";
- ste,pins = "pwmout3_d_1";
+ function = "pwmout";
+ groups = "pwmout3_d_1";
};
pwmout3_default_cfg {
- ste,pins = "GPIO16";
+ pins = "GPIO16";
output-low;
};
};
@@ -139,15 +105,15 @@ Example board file extract:
adi1_default_mode: adi1_default {
adi1_default_mux {
- ste,function = "adi1";
- ste,pins = "adi1_d_1";
+ function = "adi1";
+ groups = "adi1_d_1";
};
adi1_default_cfg1 {
- ste,pins = "GPIO17","GPIO19","GPIO20";
+ pins = "GPIO17","GPIO19","GPIO20";
bias-disable;
};
adi1_default_cfg2 {
- ste,pins = "GPIO18";
+ pins = "GPIO18";
output-low;
};
};
@@ -155,15 +121,15 @@ Example board file extract:
dmic12 {
dmic12_default_mode: dmic12_default {
dmic12_default_mux {
- ste,function = "dmic";
- ste,pins = "dmic12_d_1";
+ function = "dmic";
+ groups = "dmic12_d_1";
};
dmic12_default_cfg1 {
- ste,pins = "GPIO27";
+ pins = "GPIO27";
output-low;
};
dmic12_default_cfg2 {
- ste,pins = "GPIO28";
+ pins = "GPIO28";
bias-disable;
};
};
@@ -171,15 +137,15 @@ Example board file extract:
dmic34 {
dmic34_default_mode: dmic34_default {
dmic34_default_mux {
- ste,function = "dmic";
- ste,pins = "dmic34_d_1";
+ function = "dmic";
+ groups = "dmic34_d_1";
};
dmic34_default_cfg1 {
- ste,pins = "GPIO29";
+ pins = "GPIO29";
output-low;
};
dmic34_default_cfg2 {
- ste,pins = "GPIO30";
+ pins = "GPIO30";
bias-disable;{
};
@@ -188,15 +154,15 @@ Example board file extract:
dmic56 {
dmic56_default_mode: dmic56_default {
dmic56_default_mux {
- ste,function = "dmic";
- ste,pins = "dmic56_d_1";
+ function = "dmic";
+ groups = "dmic56_d_1";
};
dmic56_default_cfg1 {
- ste,pins = "GPIO31";
+ pins = "GPIO31";
output-low;
};
dmic56_default_cfg2 {
- ste,pins = "GPIO32";
+ pins = "GPIO32";
bias-disable;
};
};
@@ -204,11 +170,11 @@ Example board file extract:
sysclkreq5 {
sysclkreq5_default_mode: sysclkreq5_default {
sysclkreq5_default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq5_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq5_d_1";
};
sysclkreq5_default_cfg {
- ste,pins = "GPIO42";
+ pins = "GPIO42";
output-low;
};
};
@@ -216,11 +182,11 @@ Example board file extract:
batremn {
batremn_default_mode: batremn_default {
batremn_default_mux {
- ste,function = "batremn";
- ste,pins = "batremn_d_1";
+ function = "batremn";
+ groups = "batremn_d_1";
};
batremn_default_cfg {
- ste,pins = "GPIO43";
+ pins = "GPIO43";
bias-disable;
};
};
@@ -228,11 +194,11 @@ Example board file extract:
service {
service_default_mode: service_default {
service_default_mux {
- ste,function = "service";
- ste,pins = "service_d_1";
+ function = "service";
+ groups = "service_d_1";
};
service_default_cfg {
- ste,pins = "GPIO44";
+ pins = "GPIO44";
bias-disable;
};
};
@@ -240,13 +206,13 @@ Example board file extract:
pwrctrl0 {
pwrctrl0_default_mux: pwrctrl0_mux {
pwrctrl0_default_mux {
- ste,function = "pwrctrl";
- ste,pins = "pwrctrl0_d_1";
+ function = "pwrctrl";
+ groups = "pwrctrl0_d_1";
};
};
pwrctrl0_default_mode: pwrctrl0_default {
pwrctrl0_default_cfg {
- ste,pins = "GPIO45";
+ pins = "GPIO45";
bias-disable;
};
};
@@ -254,13 +220,13 @@ Example board file extract:
pwrctrl1 {
pwrctrl1_default_mux: pwrctrl1_mux {
pwrctrl1_default_mux {
- ste,function = "pwrctrl";
- ste,pins = "pwrctrl1_d_1";
+ function = "pwrctrl";
+ groups = "pwrctrl1_d_1";
};
};
pwrctrl1_default_mode: pwrctrl1_default {
pwrctrl1_default_cfg {
- ste,pins = "GPIO46";
+ pins = "GPIO46";
bias-disable;
};
};
@@ -268,11 +234,11 @@ Example board file extract:
pwmextvibra1 {
pwmextvibra1_default_mode: pwmextvibra1_default {
pwmextvibra1_default_mux {
- ste,function = "pwmextvibra";
- ste,pins = "pwmextvibra1_d_1";
+ function = "pwmextvibra";
+ groups = "pwmextvibra1_d_1";
};
pwmextvibra1_default_cfg {
- ste,pins = "GPIO47";
+ pins = "GPIO47";
bias-disable;
};
};
@@ -280,11 +246,11 @@ Example board file extract:
pwmextvibra2 {
pwmextvibra2_default_mode: pwmextvibra2_default {
pwmextvibra2_default_mux {
- ste,function = "pwmextvibra";
- ste,pins = "pwmextvibra2_d_1";
+ function = "pwmextvibra";
+ groups = "pwmextvibra2_d_1";
};
pwmextvibra1_default_cfg {
- ste,pins = "GPIO48";
+ pins = "GPIO48";
bias-disable;
};
};
@@ -292,11 +258,11 @@ Example board file extract:
gpio51 {
gpio51_default_mode: gpio51_default {
gpio51_default_mux {
- ste,function = "gpio";
- ste,pins = "gpio51_a_1";
+ function = "gpio";
+ groups = "gpio51_a_1";
};
gpio51_default_cfg {
- ste,pins = "GPIO51";
+ pins = "GPIO51";
output-low;
};
};
@@ -304,11 +270,11 @@ Example board file extract:
gpio52 {
gpio52_default_mode: gpio52_default {
gpio52_default_mux {
- ste,function = "gpio";
- ste,pins = "gpio52_a_1";
+ function = "gpio";
+ groups = "gpio52_a_1";
};
gpio52_default_cfg {
- ste,pins = "GPIO52";
+ pins = "GPIO52";
bias-pull-down;
};
};
@@ -316,11 +282,11 @@ Example board file extract:
gpio53 {
gpio53_default_mode: gpio53_default {
gpio53_default_mux {
- ste,function = "gpio";
- ste,pins = "gpio53_a_1";
+ function = "gpio";
+ groups = "gpio53_a_1";
};
gpio53_default_cfg {
- ste,pins = "GPIO53";
+ pins = "GPIO53";
bias-pull-down;
};
};
@@ -328,11 +294,11 @@ Example board file extract:
gpio54 {
gpio54_default_mode: gpio54_default {
gpio54_default_mux {
- ste,function = "gpio";
- ste,pins = "gpio54_a_1";
+ function = "gpio";
+ groups = "gpio54_a_1";
};
gpio54_default_cfg {
- ste,pins = "GPIO54";
+ pins = "GPIO54";
output-low;
};
};
@@ -340,11 +306,11 @@ Example board file extract:
pdmclkdat {
pdmclkdat_default_mode: pdmclkdat_default {
pdmclkdat_default_mux {
- ste,function = "pdm";
- ste,pins = "pdmclkdat_d_1";
+ function = "pdm";
+ groups = "pdmclkdat_d_1";
};
pdmclkdat_default_cfg {
- ste,pins = "GPIO55", "GPIO56";
+ pins = "GPIO55", "GPIO56";
bias-disable;
};
};
diff --git a/Documentation/devicetree/bindings/power/power-controller.txt b/Documentation/devicetree/bindings/power/power-controller.txt
new file mode 100644
index 0000000..4f7a3bc
--- /dev/null
+++ b/Documentation/devicetree/bindings/power/power-controller.txt
@@ -0,0 +1,18 @@
+* Generic system power control capability
+
+Power-management integrated circuits or miscellaneous hardware components are
+sometimes able to control the system power. The device driver associated with these
+components might need to define this capability, which tells the kernel that
+it can be used to switch off the system. The corresponding device must have the
+standard property "system-power-controller" in its device node. This property
+marks the device as able to control the system power. In order to test if this
+property is found programmatically, use the helper function
+"of_device_is_system_power_controller" from of.h .
+
+Example:
+
+act8846: act8846@5 {
+ compatible = "active-semi,act8846";
+ status = "okay";
+ system-power-controller;
+}
diff --git a/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt
new file mode 100644
index 0000000..dc7c9ba
--- /dev/null
+++ b/Documentation/devicetree/bindings/power_supply/imx-snvs-poweroff.txt
@@ -0,0 +1,23 @@
+i.mx6 Poweroff Driver
+
+SNVS_LPCR in SNVS module can power off the whole system by pull
+PMIC_ON_REQ low if PMIC_ON_REQ is connected with external PMIC.
+If you don't want to use PMIC_ON_REQ as power on/off control,
+please set status='disabled' to disable this driver.
+
+Required Properties:
+-compatible: "fsl,sec-v4.0-poweroff"
+-reg: Specifies the physical address of the SNVS_LPCR register
+
+Example:
+ snvs@020cc000 {
+ compatible = "fsl,sec-v4.0-mon", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x020cc000 0x4000>;
+ .....
+ snvs_poweroff: snvs-poweroff@38 {
+ compatible = "fsl,sec-v4.0-poweroff";
+ reg = <0x38 0x4>;
+ };
+ }
diff --git a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt
index 865614b..dad6358 100644
--- a/Documentation/devicetree/bindings/regulator/act8865-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/act8865-regulator.txt
@@ -5,6 +5,10 @@ Required properties:
- compatible: "active-semi,act8846" or "active-semi,act8865"
- reg: I2C slave address
+Optional properties:
+- system-power-controller: Telling whether or not this pmic is controlling
+ the system power. See Documentation/devicetree/bindings/power/power-controller.txt .
+
Any standard regulator properties can be used to configure the single regulator.
The valid names for regulators are:
diff --git a/Documentation/devicetree/bindings/regulator/max77802.txt b/Documentation/devicetree/bindings/regulator/max77802.txt
index 5aeaffc..79e5476 100644
--- a/Documentation/devicetree/bindings/regulator/max77802.txt
+++ b/Documentation/devicetree/bindings/regulator/max77802.txt
@@ -25,6 +25,29 @@ with their hardware counterparts as follow. The valid names are:
example: LDO1, LDO2, LDO35.
-BUCKn : for BUCKs, where n can lie in range 1 to 10.
example: BUCK1, BUCK5, BUCK10.
+
+The max77802 regulator supports two different operating modes: Normal and Low
+Power Mode. Some regulators support the modes to be changed at startup or by
+the consumers during normal operation while others only support to change the
+mode during system suspend. The standard regulator suspend states binding can
+be used to configure the regulator operating mode.
+
+The regulators that support the standard "regulator-initial-mode" property,
+changing their mode during normal operation are: LDOs 1, 3, 20 and 21.
+
+The possible values for "regulator-initial-mode" and "regulator-mode" are:
+ 1: Normal regulator voltage output mode.
+ 3: Low Power which reduces the quiescent current down to only 1uA
+
+The list of valid modes are defined in the dt-bindings/clock/maxim,max77802.h
+header and can be included by device tree source files.
+
+The standard "regulator-mode" property can only be used for regulators that
+support changing their mode to Low Power Mode during suspend. These regulators
+are: BUCKs 2-4 and LDOs 1-35. Also, it only takes effect if the regulator has
+been enabled for the given suspend state using "regulator-on-in-suspend" and
+has not been disabled for that state using "regulator-off-in-suspend".
+
Example:
max77802@09 {
@@ -36,11 +59,23 @@ Example:
#size-cells = <0>;
regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "vdd_1v0";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-initial-mode = <MAX77802_OPMODE_LP>;
+ };
+
ldo11_reg: LDO11 {
regulator-name = "vdd_ldo11";
regulator-min-microvolt = <1900000>;
regulator-max-microvolt = <1900000>;
regulator-always-on;
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ regulator-mode = <MAX77802_OPMODE_LP>;
+ };
};
buck1_reg: BUCK1 {
diff --git a/Documentation/devicetree/bindings/regulator/regulator.txt b/Documentation/devicetree/bindings/regulator/regulator.txt
index 8607433..abb26b5 100644
--- a/Documentation/devicetree/bindings/regulator/regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/regulator.txt
@@ -19,6 +19,24 @@ Optional properties:
design requires. This property describes the total system ramp time
required due to the combination of internal ramping of the regulator itself,
and board design issues such as trace capacitance and load on the supply.
+- regulator-state-mem sub-root node for Suspend-to-RAM mode
+ : suspend to memory, the device goes to sleep, but all data stored in memory,
+ only some external interrupt can wake the device.
+- regulator-state-disk sub-root node for Suspend-to-DISK mode
+ : suspend to disk, this state operates similarly to Suspend-to-RAM,
+ but includes a final step of writing memory contents to disk.
+- regulator-state-[mem/disk] node has following common properties:
+ - regulator-on-in-suspend: regulator should be on in suspend state.
+ - regulator-off-in-suspend: regulator should be off in suspend state.
+ - regulator-suspend-microvolt: regulator should be set to this voltage
+ in suspend.
+ - regulator-mode: operating mode in the given suspend state.
+ The set of possible operating modes depends on the capabilities of
+ every hardware so the valid modes are documented on each regulator
+ device tree binding document.
+- regulator-initial-mode: initial operating mode. The set of possible operating
+ modes depends on the capabilities of every hardware so each device binding
+ documentation explains which values the regulator supports.
Deprecated properties:
- regulator-compatible: If a regulator chip contains multiple
@@ -34,6 +52,10 @@ Example:
regulator-max-microvolt = <2500000>;
regulator-always-on;
vin-supply = <&vin>;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
};
Regulator Consumers:
diff --git a/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt b/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt
index 882455e..f9acbc1 100644
--- a/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt
+++ b/Documentation/devicetree/bindings/regulator/sky81452-regulator.txt
@@ -1,6 +1,7 @@
SKY81452 voltage regulator
Required properties:
+- regulator node named lout.
- any required generic properties defined in regulator.txt
Optional properties:
@@ -9,8 +10,9 @@ Optional properties:
Example:
regulator {
- /* generic regulator properties */
- regulator-name = "touch_en";
- regulator-min-microvolt = <4500000>;
- regulator-max-microvolt = <8000000>;
+ lout {
+ regulator-name = "sky81452-lout";
+ regulator-min-microvolt = <4500000>;
+ regulator-max-microvolt = <8000000>;
+ };
};
diff --git a/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt
new file mode 100644
index 0000000..54ae9f7
--- /dev/null
+++ b/Documentation/devicetree/bindings/reset/st,sti-picophyreset.txt
@@ -0,0 +1,42 @@
+STMicroelectronics STi family Sysconfig Picophy SoftReset Controller
+=============================================================================
+
+This binding describes a reset controller device that is used to enable and
+disable on-chip PicoPHY USB2 phy(s) using "softreset" control bits found in
+the STi family SoC system configuration registers.
+
+The actual action taken when softreset is asserted is hardware dependent.
+However, when asserted it may not be possible to access the hardware's
+registers and after an assert/deassert sequence the hardware's previous state
+may no longer be valid.
+
+Please refer to Documentation/devicetree/bindings/reset/reset.txt
+for common reset controller binding usage.
+
+Required properties:
+- compatible: Should be "st,stih407-picophyreset"
+- #reset-cells: 1, see below
+
+Example:
+
+ picophyreset: picophyreset-controller {
+ compatible = "st,stih407-picophyreset";
+ #reset-cells = <1>;
+ };
+
+Specifying picophyreset control of devices
+=======================================
+
+Device nodes should specify the reset channel required in their "resets"
+property, containing a phandle to the picophyreset device node and an
+index specifying which channel to use, as described in
+Documentation/devicetree/bindings/reset/reset.txt.
+
+Example:
+
+ usb2_picophy0: usbpicophy@0 {
+ resets = <&picophyreset STIH407_PICOPHY0_RESET>;
+ };
+
+Macro definitions for the supported reset channels can be found in:
+include/dt-bindings/reset-controller/stih407-resets.h
diff --git a/Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt b/Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt
new file mode 100644
index 0000000..6ae79d1
--- /dev/null
+++ b/Documentation/devicetree/bindings/rtc/atmel,at91sam9-rtc.txt
@@ -0,0 +1,23 @@
+Atmel AT91SAM9260 Real Time Timer
+
+Required properties:
+- compatible: should be: "atmel,at91sam9260-rtt"
+- reg: should encode the memory region of the RTT controller
+- interrupts: rtt alarm/event interrupt
+- clocks: should contain the 32 KHz slow clk that will drive the RTT block.
+- atmel,rtt-rtc-time-reg: should encode the GPBR register used to store
+ the time base when the RTT is used as an RTC.
+ The first cell should point to the GPBR node and the second one
+ encode the offset within the GPBR block (or in other words, the
+ GPBR register used to store the time base).
+
+
+Example:
+
+rtt@fffffd20 {
+ compatible = "atmel,at91sam9260-rtt";
+ reg = <0xfffffd20 0x10>;
+ interrupts = <1 4 7>;
+ clocks = <&clk32k>;
+ atmel,rtt-rtc-time-reg = <&gpbr 0x0>;
+};
diff --git a/Documentation/devicetree/bindings/rtc/rtc-omap.txt b/Documentation/devicetree/bindings/rtc/rtc-omap.txt
index 5a0f02d..4ba4dbd 100644
--- a/Documentation/devicetree/bindings/rtc/rtc-omap.txt
+++ b/Documentation/devicetree/bindings/rtc/rtc-omap.txt
@@ -5,11 +5,17 @@ Required properties:
- "ti,da830-rtc" - for RTC IP used similar to that on DA8xx SoC family.
- "ti,am3352-rtc" - for RTC IP used similar to that on AM335x SoC family.
This RTC IP has special WAKE-EN Register to enable
- Wakeup generation for event Alarm.
+ Wakeup generation for event Alarm. It can also be
+ used to control an external PMIC via the
+ pmic_power_en pin.
- reg: Address range of rtc register set
- interrupts: rtc timer, alarm interrupts in order
- interrupt-parent: phandle for the interrupt controller
+Optional properties:
+- system-power-controller: whether the rtc is controlling the system power
+ through pmic_power_en
+
Example:
rtc@1c23000 {
@@ -18,4 +24,5 @@ rtc@1c23000 {
interrupts = <19
19>;
interrupt-parent = <&intc>;
+ system-power-controller;
};
diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt
index 5d2e840..52464918 100644
--- a/Documentation/devicetree/bindings/serial/pl011.txt
+++ b/Documentation/devicetree/bindings/serial/pl011.txt
@@ -6,12 +6,34 @@ Required properties:
- interrupts: exactly one interrupt specifier
Optional properties:
-- pinctrl: When present, must have one state named "sleep"
- and one state named "default"
-- clocks: When present, must refer to exactly one clock named
+- pinctrl: When present, must have one state named "default",
+ and may contain a second name named "sleep". The former
+ state sets up pins for ordinary operation whereas
+ the latter state will put the associated pins to sleep
+ when the UART is unused
+- clocks: When present, the first clock listed must correspond to
+ the clock named UARTCLK on the IP block, i.e. the clock
+ to the external serial line, whereas the second clock
+ must correspond to the PCLK clocking the internal logic
+ of the block. Just listing one clock (the first one) is
+ deprecated.
+- clocks-names: When present, the first clock listed must be named
+ "uartclk" and the second clock listed must be named
"apb_pclk"
- dmas: When present, may have one or two dma channels.
The first one must be named "rx", the second one
must be named "tx".
See also bindings/arm/primecell.txt
+
+Example:
+
+uart@80120000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x80120000 0x1000>;
+ interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
+ dmas = <&dma 13 0 0x2>, <&dma 13 0 0x0>;
+ dma-names = "rx", "tx";
+ clocks = <&foo_clk>, <&bar_clk>;
+ clock-names = "uartclk", "apb_pclk";
+};
diff --git a/Documentation/devicetree/bindings/sound/arndale.txt b/Documentation/devicetree/bindings/sound/arndale.txt
new file mode 100644
index 0000000..0e76946
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/arndale.txt
@@ -0,0 +1,24 @@
+Audio Binding for Arndale boards
+
+Required properties:
+- compatible : Can be the following,
+ "samsung,arndale-rt5631"
+
+- samsung,audio-cpu: The phandle of the Samsung I2S controller
+- samsung,audio-codec: The phandle of the audio codec
+
+Optional:
+- samsung,model: The name of the sound-card
+
+Arndale Boards has many audio daughter cards, one of them is
+rt5631/alc5631. Below example shows audio bindings for rt5631/
+alc5631 based codec.
+
+Example:
+
+sound {
+ compatible = "samsung,arndale-rt5631";
+
+ samsung,audio-cpu = <&i2s0>
+ samsung,audio-codec = <&rt5631>;
+};
diff --git a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
index 60ca079..46bc982 100644
--- a/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
+++ b/Documentation/devicetree/bindings/sound/davinci-mcasp-audio.txt
@@ -32,7 +32,7 @@ Optional properties:
- rx-num-evt : FIFO levels.
- sram-size-playback : size of sram to be allocated during playback
- sram-size-capture : size of sram to be allocated during capture
-- interrupts : Interrupt numbers for McASP, currently not used by the driver
+- interrupts : Interrupt numbers for McASP
- interrupt-names : Known interrupt names are "tx" and "rx"
- pinctrl-0: Should specify pin control group used for this controller.
- pinctrl-names: Should contain only one value - "default", for more details
diff --git a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
index 0d7985c..6dfa88c 100644
--- a/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
+++ b/Documentation/devicetree/bindings/sound/eukrea-tlv320.txt
@@ -1,11 +1,16 @@
Audio complex for Eukrea boards with tlv320aic23 codec.
Required properties:
-- compatible : "eukrea,asoc-tlv320"
-- eukrea,model : The user-visible name of this sound complex.
-- ssi-controller : The phandle of the SSI controller.
-- fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
-- fsl,mux-ext-port : The external port of the i.MX audio muxer.
+
+ - compatible : "eukrea,asoc-tlv320"
+
+ - eukrea,model : The user-visible name of this sound complex.
+
+ - ssi-controller : The phandle of the SSI controller.
+
+ - fsl,mux-int-port : The internal port of the i.MX audio muxer (AUDMUX).
+
+ - fsl,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.
diff --git a/Documentation/devicetree/bindings/sound/fsl,esai.txt b/Documentation/devicetree/bindings/sound/fsl,esai.txt
index 52f5b6b..d3b6b5f 100644
--- a/Documentation/devicetree/bindings/sound/fsl,esai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,esai.txt
@@ -7,37 +7,39 @@ other DSPs. It has up to six transmitters and four receivers.
Required properties:
- - compatible : Compatible list, must contain "fsl,imx35-esai" or
- "fsl,vf610-esai"
+ - compatible : Compatible list, must contain "fsl,imx35-esai" or
+ "fsl,vf610-esai"
- - reg : Offset and length of the register set for the device.
+ - reg : Offset and length of the register set for the device.
- - interrupts : Contains the spdif interrupt.
+ - interrupts : Contains the spdif interrupt.
- - dmas : Generic dma devicetree binding as described in
- Documentation/devicetree/bindings/dma/dma.txt.
+ - dmas : Generic dma devicetree binding as described in
+ Documentation/devicetree/bindings/dma/dma.txt.
- - dma-names : Two dmas have to be defined, "tx" and "rx".
+ - dma-names : Two dmas have to be defined, "tx" and "rx".
- - clocks: Contains an entry for each entry in clock-names.
+ - clocks : Contains an entry for each entry in clock-names.
- - clock-names : Includes the following entries:
- "core" The core clock used to access registers
- "extal" The esai baud clock for esai controller used to derive
- HCK, SCK and FS.
- "fsys" The system clock derived from ahb clock used to derive
- HCK, SCK and FS.
+ - clock-names : Includes the following entries:
+ "core" The core clock used to access registers
+ "extal" The esai baud clock for esai controller used to
+ derive HCK, SCK and FS.
+ "fsys" The system clock derived from ahb clock used to
+ derive HCK, SCK and FS.
- - fsl,fifo-depth: The number of elements in the transmit and receive FIFOs.
- This number is the maximum allowed value for TFCR[TFWM] or RFCR[RFWM].
+ - fsl,fifo-depth : The number of elements in the transmit and receive
+ FIFOs. This number is the maximum allowed value for
+ TFCR[TFWM] or RFCR[RFWM].
- fsl,esai-synchronous: This is a boolean property. If present, indicating
- that ESAI would work in the synchronous mode, which means all the settings
- for Receiving would be duplicated from Transmition related registers.
+ that ESAI would work in the synchronous mode, which
+ means all the settings for Receiving would be
+ duplicated from Transmition related registers.
- - big-endian : If this property is absent, the native endian mode will
- be in use as default, or the big endian mode will be in use for all the
- device registers.
+ - big-endian : If this property is absent, the native endian mode
+ will be in use as default, or the big endian mode
+ will be in use for all the device registers.
Example:
diff --git a/Documentation/devicetree/bindings/sound/fsl,spdif.txt b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
index 3e9e82c8..b5ee32e 100644
--- a/Documentation/devicetree/bindings/sound/fsl,spdif.txt
+++ b/Documentation/devicetree/bindings/sound/fsl,spdif.txt
@@ -6,32 +6,31 @@ a fibre cable.
Required properties:
- - compatible : Compatible list, must contain "fsl,imx35-spdif".
+ - compatible : Compatible list, must contain "fsl,imx35-spdif".
- - reg : Offset and length of the register set for the device.
+ - reg : Offset and length of the register set for the device.
- - interrupts : Contains the spdif interrupt.
+ - interrupts : Contains the spdif interrupt.
- - dmas : Generic dma devicetree binding as described in
- Documentation/devicetree/bindings/dma/dma.txt.
+ - dmas : Generic dma devicetree binding as described in
+ Documentation/devicetree/bindings/dma/dma.txt.
- - dma-names : Two dmas have to be defined, "tx" and "rx".
+ - dma-names : Two dmas have to be defined, "tx" and "rx".
- - clocks : Contains an entry for each entry in clock-names.
+ - clocks : Contains an entry for each entry in clock-names.
- - clock-names : Includes the following entries:
- "core" The core clock of spdif controller
- "rxtx<0-7>" Clock source list for tx and rx clock.
- This clock list should be identical to
- the source list connecting to the spdif
- clock mux in "SPDIF Transceiver Clock
- Diagram" of SoC reference manual. It
- can also be referred to TxClk_Source
- bit of register SPDIF_STC.
+ - clock-names : Includes the following entries:
+ "core" The core clock of spdif controller.
+ "rxtx<0-7>" Clock source list for tx and rx clock.
+ This clock list should be identical to the source
+ list connecting to the spdif clock mux in "SPDIF
+ Transceiver Clock Diagram" of SoC reference manual.
+ It can also be referred to TxClk_Source bit of
+ register SPDIF_STC.
- - big-endian : If this property is absent, the native endian mode will
- be in use as default, or the big endian mode will be in use for all the
- device registers.
+ - big-endian : If this property is absent, the native endian mode
+ will be in use as default, or the big endian mode
+ will be in use for all the device registers.
Example:
diff --git a/Documentation/devicetree/bindings/sound/fsl-sai.txt b/Documentation/devicetree/bindings/sound/fsl-sai.txt
index 4956b14..044e5d7 100644
--- a/Documentation/devicetree/bindings/sound/fsl-sai.txt
+++ b/Documentation/devicetree/bindings/sound/fsl-sai.txt
@@ -5,32 +5,48 @@ which provides a synchronous audio interface that supports fullduplex
serial interfaces with frame synchronization such as I2S, AC97, TDM, and
codec/DSP interfaces.
-
Required properties:
-- compatible: Compatible list, contains "fsl,vf610-sai" or "fsl,imx6sx-sai".
-- reg: Offset and length of the register set for the device.
-- clocks: Must contain an entry for each entry in clock-names.
-- clock-names : Must include the "bus" for register access and "mclk1" "mclk2"
- "mclk3" for bit clock and frame clock providing.
-- dmas : Generic dma devicetree binding as described in
- Documentation/devicetree/bindings/dma/dma.txt.
-- dma-names : Two dmas have to be defined, "tx" and "rx".
-- pinctrl-names: Must contain a "default" entry.
-- pinctrl-NNN: One property must exist for each entry in pinctrl-names.
- See ../pinctrl/pinctrl-bindings.txt for details of the property values.
-- big-endian: Boolean property, required if all the FTM_PWM registers
- are big-endian rather than little-endian.
-- lsb-first: Configures whether the LSB or the MSB is transmitted first for
- the fifo data. If this property is absent, the MSB is transmitted first as
- default, or the LSB is transmitted first.
-- fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
- that SAI will work in the synchronous mode (sync Tx with Rx) which means
- both the transimitter and receiver will send and receive data by following
- receiver's bit clocks and frame sync clocks.
-- fsl,sai-asynchronous: This is a boolean property. If present, indicating
- that SAI will work in the asynchronous mode, which means both transimitter
- and receiver will send and receive data by following their own bit clocks
- and frame sync clocks separately.
+
+ - compatible : Compatible list, contains "fsl,vf610-sai" or
+ "fsl,imx6sx-sai".
+
+ - reg : Offset and length of the register set for the device.
+
+ - clocks : Must contain an entry for each entry in clock-names.
+
+ - clock-names : Must include the "bus" for register access and
+ "mclk1", "mclk2", "mclk3" for bit clock and frame
+ clock providing.
+ - dmas : Generic dma devicetree binding as described in
+ Documentation/devicetree/bindings/dma/dma.txt.
+
+ - dma-names : Two dmas have to be defined, "tx" and "rx".
+
+ - pinctrl-names : Must contain a "default" entry.
+
+ - pinctrl-NNN : One property must exist for each entry in
+ pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
+ for details of the property values.
+
+ - big-endian : Boolean property, required if all the FTM_PWM
+ registers are big-endian rather than little-endian.
+
+ - lsb-first : Configures whether the LSB or the MSB is transmitted
+ first for the fifo data. If this property is absent,
+ the MSB is transmitted first as default, or the LSB
+ is transmitted first.
+
+ - fsl,sai-synchronous-rx: This is a boolean property. If present, indicating
+ that SAI will work in the synchronous mode (sync Tx
+ with Rx) which means both the transimitter and the
+ receiver will send and receive data by following
+ receiver's bit clocks and frame sync clocks.
+
+ - fsl,sai-asynchronous: This is a boolean property. If present, indicating
+ that SAI will work in the asynchronous mode, which
+ means both transimitter and receiver will send and
+ receive data by following their own bit clocks and
+ frame sync clocks separately.
Note:
- If both fsl,sai-asynchronous and fsl,sai-synchronous-rx are absent, the
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
index e4acdd8..2f89db8 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
+++ b/Documentation/devicetree/bindings/sound/imx-audio-sgtl5000.txt
@@ -1,33 +1,40 @@
Freescale i.MX audio complex with SGTL5000 codec
Required properties:
-- compatible : "fsl,imx-audio-sgtl5000"
-- 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 SGTL5000 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, SGTL5000 pins, and the jacks on the board:
-
- Power supplies:
- * Mic Bias
-
- SGTL5000 pins:
- * MIC_IN
- * LINE_IN
- * HP_OUT
- * LINE_OUT
-
- Board connectors:
- * Mic Jack
- * Line In Jack
- * Headphone Jack
- * Line Out 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
+
+ - compatible : "fsl,imx-audio-sgtl5000"
+
+ - 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 SGTL5000 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, SGTL5000
+ pins, and the jacks on the board:
+
+ Power supplies:
+ * Mic Bias
+
+ SGTL5000 pins:
+ * MIC_IN
+ * LINE_IN
+ * HP_OUT
+ * LINE_OUT
+
+ Board connectors:
+ * Mic Jack
+ * Line In Jack
+ * Headphone Jack
+ * Line Out 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.
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
index 7d13479..da84a44 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
+++ b/Documentation/devicetree/bindings/sound/imx-audio-spdif.txt
@@ -2,23 +2,25 @@ Freescale i.MX audio complex with S/PDIF transceiver
Required properties:
- - compatible : "fsl,imx-audio-spdif"
+ - compatible : "fsl,imx-audio-spdif"
- - model : The user-visible name of this sound complex
+ - model : The user-visible name of this sound complex
- - spdif-controller : The phandle of the i.MX S/PDIF controller
+ - spdif-controller : The phandle of the i.MX S/PDIF controller
Optional properties:
- - spdif-out : This is a boolean property. If present, the transmitting
- function of S/PDIF will be enabled, indicating there's a physical
- S/PDIF out connector/jack on the board or it's connecting to some
- other IP block, such as an HDMI encoder/display-controller.
+ - spdif-out : This is a boolean property. If present, the
+ transmitting function of S/PDIF will be enabled,
+ indicating there's a physical S/PDIF out connector
+ or jack on the board or it's connecting to some
+ other IP block, such as an HDMI encoder or
+ display-controller.
- - spdif-in : This is a boolean property. If present, the receiving
- function of S/PDIF will be enabled, indicating there's a physical
- S/PDIF in connector/jack on the board.
+ - spdif-in : This is a boolean property. If present, the receiving
+ function of S/PDIF will be enabled, indicating there
+ is a physical S/PDIF in connector/jack on the board.
* Note: At least one of these two properties should be set in the DT binding.
diff --git a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
index f49450a..acea71b 100644
--- a/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
+++ b/Documentation/devicetree/bindings/sound/imx-audio-wm8962.txt
@@ -1,25 +1,32 @@
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
+
+ - 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.
diff --git a/Documentation/devicetree/bindings/sound/imx-audmux.txt b/Documentation/devicetree/bindings/sound/imx-audmux.txt
index f88a00e..b30a737 100644
--- a/Documentation/devicetree/bindings/sound/imx-audmux.txt
+++ b/Documentation/devicetree/bindings/sound/imx-audmux.txt
@@ -1,18 +1,24 @@
Freescale Digital Audio Mux (AUDMUX) device
Required properties:
-- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used on i.MX21,
- or "fsl,imx31-audmux" for the version firstly used on i.MX31.
-- reg : Should contain AUDMUX registers location and length
+
+ - compatible : "fsl,imx21-audmux" for AUDMUX version firstly used
+ on i.MX21, or "fsl,imx31-audmux" for the version
+ firstly used on i.MX31.
+
+ - reg : Should contain AUDMUX registers location and length.
An initial configuration can be setup using child nodes.
Required properties of optional child nodes:
-- fsl,audmux-port : Integer of the audmux port that is configured by this
- child node.
-- fsl,port-config : List of configuration options for the specific port. For
- imx31-audmux and above, it is a list of tuples <ptcr pdcr>. For
- imx21-audmux it is a list of pcr values.
+
+ - fsl,audmux-port : Integer of the audmux port that is configured by this
+ child node.
+
+ - fsl,port-config : List of configuration options for the specific port.
+ For imx31-audmux and above, it is a list of tuples
+ <ptcr pdcr>. For imx21-audmux it is a list of pcr
+ values.
Example:
diff --git a/Documentation/devicetree/bindings/sound/max98090.txt b/Documentation/devicetree/bindings/sound/max98090.txt
index c454e67..aa802a2 100644
--- a/Documentation/devicetree/bindings/sound/max98090.txt
+++ b/Documentation/devicetree/bindings/sound/max98090.txt
@@ -16,6 +16,8 @@ Optional properties:
- clock-names: Should be "mclk"
+- maxim,dmic-freq: Frequency at which to clock DMIC
+
Pins on the device (for linking into audio routes):
* MIC1
diff --git a/Documentation/devicetree/bindings/sound/renesas,fsi.txt b/Documentation/devicetree/bindings/sound/renesas,fsi.txt
index c5be003..0d0ab51 100644
--- a/Documentation/devicetree/bindings/sound/renesas,fsi.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,fsi.txt
@@ -1,11 +1,16 @@
Renesas FSI
Required properties:
-- compatible : "renesas,sh_fsi2" or "renesas,sh_fsi"
+- compatible : "renesas,fsi2-<soctype>",
+ "renesas,sh_fsi2" or "renesas,sh_fsi" as
+ fallback.
+ Examples with soctypes are:
+ - "renesas,fsi2-r8a7740" (R-Mobile A1)
+ - "renesas,fsi2-sh73a0" (SH-Mobile AG5)
- reg : Should contain the register physical address and length
- interrupts : Should contain FSI interrupt
-- fsia,spdif-connection : FSI is connected by S/PDFI
+- fsia,spdif-connection : FSI is connected by S/PDIF
- fsia,stream-mode-support : FSI supports 16bit stream mode.
- fsia,use-internal-clock : FSI uses internal clock when master mode.
diff --git a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
index aa697ab..2dd690b 100644
--- a/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
+++ b/Documentation/devicetree/bindings/sound/renesas,rsnd.txt
@@ -1,8 +1,12 @@
Renesas R-Car sound
Required properties:
-- compatible : "renesas,rcar_sound-gen1" if generation1
+- compatible : "renesas,rcar_sound-<soctype>", fallbacks
+ "renesas,rcar_sound-gen1" if generation1, and
"renesas,rcar_sound-gen2" if generation2
+ Examples with soctypes are:
+ - "renesas,rcar_sound-r8a7790" (R-Car H2)
+ - "renesas,rcar_sound-r8a7791" (R-Car M2-W)
- reg : Should contain the register physical address.
required register is
SRU/ADG/SSI if generation1
@@ -35,9 +39,9 @@ DAI subnode properties:
Example:
-rcar_sound: rcar_sound@0xffd90000 {
+rcar_sound: rcar_sound@ec500000 {
#sound-dai-cells = <1>;
- compatible = "renesas,rcar_sound-gen2";
+ compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
reg = <0 0xec500000 0 0x1000>, /* SCU */
<0 0xec5a0000 0 0x100>, /* ADG */
<0 0xec540000 0 0x1000>, /* SSIU */
diff --git a/Documentation/devicetree/bindings/sound/rt5631.txt b/Documentation/devicetree/bindings/sound/rt5631.txt
new file mode 100644
index 0000000..92b986c
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/rt5631.txt
@@ -0,0 +1,48 @@
+ALC5631/RT5631 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+ - compatible : "realtek,alc5631" or "realtek,rt5631"
+
+ - reg : the I2C address of the device.
+
+Pins on the device (for linking into audio routes):
+
+ * SPK_OUT_R_P
+ * SPK_OUT_R_N
+ * SPK_OUT_L_P
+ * SPK_OUT_L_N
+ * HP_OUT_L
+ * HP_OUT_R
+ * AUX_OUT2_LP
+ * AUX_OUT2_RN
+ * AUX_OUT1_LP
+ * AUX_OUT1_RN
+ * AUX_IN_L_JD
+ * AUX_IN_R_JD
+ * MONO_IN_P
+ * MONO_IN_N
+ * MIC1_P
+ * MIC1_N
+ * MIC2_P
+ * MIC2_N
+ * MONO_OUT_P
+ * MONO_OUT_N
+ * MICBIAS1
+ * MICBIAS2
+
+Example:
+
+alc5631: alc5631@1a {
+ compatible = "realtek,alc5631";
+ reg = <0x1a>;
+};
+
+or
+
+rt5631: rt5631@1a {
+ compatible = "realtek,rt5631";
+ reg = <0x1a>;
+};
diff --git a/Documentation/devicetree/bindings/sound/rt5677.txt b/Documentation/devicetree/bindings/sound/rt5677.txt
index 0701b83..740ff77 100644
--- a/Documentation/devicetree/bindings/sound/rt5677.txt
+++ b/Documentation/devicetree/bindings/sound/rt5677.txt
@@ -27,6 +27,21 @@ Optional properties:
Boolean. Indicate MIC1/2 input and LOUT1/2/3 outputs are differential,
rather than single-ended.
+- realtek,gpio-config
+ Array of six 8bit elements that configures GPIO.
+ 0 - floating (reset value)
+ 1 - pull down
+ 2 - pull up
+
+- realtek,jd1-gpio
+ Configures GPIO Mic Jack detection 1.
+ Select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively.
+
+- realtek,jd2-gpio
+- realtek,jd3-gpio
+ Configures GPIO Mic Jack detection 2 and 3.
+ Select 0 ~ 3 as OFF, GPIO4, GPIO5 and GPIO6 respectively.
+
Pins on the device (for linking into audio routes):
* IN1P
@@ -56,4 +71,6 @@ rt5677 {
realtek,pow-ldo2-gpio =
<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
realtek,in1-differential = "true";
+ realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */
+ realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */
};
diff --git a/Documentation/devicetree/bindings/sound/samsung-i2s.txt b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
index 7386d44..d188296 100644
--- a/Documentation/devicetree/bindings/sound/samsung-i2s.txt
+++ b/Documentation/devicetree/bindings/sound/samsung-i2s.txt
@@ -6,10 +6,17 @@ Required SoC Specific Properties:
- samsung,s3c6410-i2s: for 8/16/24bit stereo I2S.
- samsung,s5pv210-i2s: for 8/16/24bit multichannel(5.1) I2S with
secondary fifo, s/w reset control and internal mux for root clk src.
- - samsung,exynos5420-i2s: for 8/16/24bit multichannel(7.1) I2S with
- secondary fifo, s/w reset control, internal mux for root clk src and
- TDM support. TDM (Time division multiplexing) is to allow transfer of
- multiple channel audio data on single data line.
+ - samsung,exynos5420-i2s: for 8/16/24bit multichannel(5.1) I2S for
+ playback, sterio channel capture, secondary fifo using internal
+ or external dma, s/w reset control, internal mux for root clk src
+ and 7.1 channel TDM support for playback. TDM (Time division multiplexing)
+ is to allow transfer of multiple channel audio data on single data line.
+ - samsung,exynos7-i2s: with all the available features of exynos5 i2s,
+ exynos7 I2S has 7.1 channel TDM support for capture, secondary fifo
+ with only external dma and more no.of root clk sampling frequencies.
+ - samsung,exynos7-i2s1: I2S1 on previous samsung platforms supports
+ stereo channels. exynos7 i2s1 upgraded to 5.1 multichannel with
+ slightly modified bit offsets.
- reg: physical base address of the controller and length of memory mapped
region.
diff --git a/Documentation/devicetree/bindings/sound/sgtl5000.txt b/Documentation/devicetree/bindings/sound/sgtl5000.txt
index d556dcb..0e5e4eb 100644
--- a/Documentation/devicetree/bindings/sound/sgtl5000.txt
+++ b/Documentation/devicetree/bindings/sound/sgtl5000.txt
@@ -7,6 +7,17 @@ Required properties:
- clocks : the clock provider of SYS_MCLK
+- micbias-resistor-k-ohms : the bias resistor to be used in kOmhs
+ The resistor can take values of 2k, 4k or 8k.
+ If set to 0 it will be off.
+ If this node is not mentioned or if the value is unknown, then
+ micbias resistor is set to 4K.
+
+- micbias-voltage-m-volts : the bias voltage to be used in mVolts
+ The voltage can take values from 1.25V to 3V by 250mV steps
+ If this node is not mentionned or the value is unknown, then
+ the value is set to 1.25V.
+
- VDDA-supply : the regulator provider of VDDA
- VDDIO-supply: the regulator provider of VDDIO
@@ -21,6 +32,8 @@ codec: sgtl5000@0a {
compatible = "fsl,sgtl5000";
reg = <0x0a>;
clocks = <&clks 150>;
+ micbias-resistor-k-ohms = <2>;
+ micbias-voltage-m-volts = <2250>;
VDDA-supply = <&reg_3p3v>;
VDDIO-supply = <&reg_3p3v>;
};
diff --git a/Documentation/devicetree/bindings/sound/ts3a227e.txt b/Documentation/devicetree/bindings/sound/ts3a227e.txt
new file mode 100644
index 0000000..e8bf23e
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/ts3a227e.txt
@@ -0,0 +1,26 @@
+Texas Instruments TS3A227E
+Autonomous Audio Accessory Detection and Configuration Switch
+
+The TS3A227E detect headsets of 3-ring and 4-ring standards and
+switches automatically to route the microphone correctly. It also
+handles key press detection in accordance with the Android audio
+headset specification v1.0.
+
+Required properties:
+
+ - compatible: Should contain "ti,ts3a227e".
+ - reg: The i2c address. Should contain <0x3b>.
+ - interrupt-parent: The parent interrupt controller
+ - interrupts: Interrupt number for /INT pin from the 227e
+
+
+Examples:
+
+ i2c {
+ ts3a227e@3b {
+ compatible = "ti,ts3a227e";
+ reg = <0x3b>;
+ interrupt-parent = <&gpio>;
+ interrupts = <3 IRQ_TYPE_LEVEL_LOW>;
+ };
+ };
diff --git a/Documentation/devicetree/bindings/sound/wm8960.txt b/Documentation/devicetree/bindings/sound/wm8960.txt
new file mode 100644
index 0000000..2deb8a3
--- /dev/null
+++ b/Documentation/devicetree/bindings/sound/wm8960.txt
@@ -0,0 +1,31 @@
+WM8960 audio CODEC
+
+This device supports I2C only.
+
+Required properties:
+
+ - compatible : "wlf,wm8960"
+
+ - reg : the I2C address of the device.
+
+Optional properties:
+ - wlf,shared-lrclk: This is a boolean property. If present, the LRCM bit of
+ R24 (Additional control 2) gets set, indicating that ADCLRC and DACLRC pins
+ will be disabled only when ADC (Left and Right) and DAC (Left and Right)
+ are disabled.
+ When wm8960 works on synchronize mode and DACLRC pin is used to supply
+ frame clock, it will no frame clock for captrue unless enable DAC to enable
+ DACLRC pin. If shared-lrclk is present, no need to enable DAC for captrue.
+
+ - wlf,capless: This is a boolean property. If present, OUT3 pin will be
+ enabled and disabled together with HP_L and HP_R pins in response to jack
+ detect events.
+
+Example:
+
+codec: wm8960@1a {
+ compatible = "wlf,wm8960";
+ reg = <0x1a>;
+
+ wlf,shared-lrclk;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-gpio.txt b/Documentation/devicetree/bindings/spi/spi-gpio.txt
index 8a824be..a95603b 100644
--- a/Documentation/devicetree/bindings/spi/spi-gpio.txt
+++ b/Documentation/devicetree/bindings/spi/spi-gpio.txt
@@ -8,8 +8,10 @@ Required properties:
- gpio-sck: GPIO spec for the SCK line to use
- gpio-miso: GPIO spec for the MISO line to use
- gpio-mosi: GPIO spec for the MOSI line to use
- - cs-gpios: GPIOs to use for chipselect lines
- - num-chipselects: number of chipselect lines
+ - cs-gpios: GPIOs to use for chipselect lines.
+ Not needed if num-chipselects = <0>.
+ - num-chipselects: Number of chipselect lines. Should be <0> if a single device
+ with no chip select is connected.
Example:
diff --git a/Documentation/devicetree/bindings/spi/spi-img-spfi.txt b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt
new file mode 100644
index 0000000..c7dd50f
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-img-spfi.txt
@@ -0,0 +1,37 @@
+IMG Synchronous Peripheral Flash Interface (SPFI) controller
+
+Required properties:
+- compatible: Must be "img,spfi".
+- reg: Must contain the base address and length of the SPFI registers.
+- interrupts: Must contain the SPFI interrupt.
+- clocks: Must contain an entry for each entry in clock-names.
+ See ../clock/clock-bindings.txt for details.
+- clock-names: Must include the following entries:
+ - spfi: SPI operating clock
+ - sys: SPI system interface clock
+- dmas: Must contain an entry for each entry in dma-names.
+ See ../dma/dma.txt for details.
+- dma-names: Must include the following entries:
+ - rx
+ - tx
+- #address-cells: Must be 1.
+- #size-cells: Must be 0.
+
+Optional properties:
+- img,supports-quad-mode: Should be set if the interface supports quad mode
+ SPI transfers.
+
+Example:
+
+spi@18100f00 {
+ compatible = "img,spfi";
+ reg = <0x18100f00 0x100>;
+ interrupts = <GIC_SHARED 22 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&spi_clk>, <&system_clk>;
+ clock-names = "spfi", "sys";
+ dmas = <&mdc 9 0xffffffff 0>, <&mdc 10 0xffffffff 0>;
+ dma-names = "rx", "tx";
+
+ #address-cells = <1>;
+ #size-cells = <0>;
+};
diff --git a/Documentation/devicetree/bindings/spi/spi-meson.txt b/Documentation/devicetree/bindings/spi/spi-meson.txt
new file mode 100644
index 0000000..bb52a86
--- /dev/null
+++ b/Documentation/devicetree/bindings/spi/spi-meson.txt
@@ -0,0 +1,22 @@
+Amlogic Meson SPI controllers
+
+* SPIFC (SPI Flash Controller)
+
+The Meson SPIFC is a controller optimized for communication with SPI
+NOR memories, without DMA support and a 64-byte unified transmit /
+receive buffer.
+
+Required properties:
+ - compatible: should be "amlogic,meson6-spifc"
+ - reg: physical base address and length of the controller registers
+ - clocks: phandle of the input clock for the baud rate generator
+ - #address-cells: should be 1
+ - #size-cells: should be 0
+
+ spi@c1108c80 {
+ compatible = "amlogic,meson6-spifc";
+ reg = <0xc1108c80 0x80>;
+ clocks = <&clk81>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
diff --git a/Documentation/devicetree/bindings/spi/spi-samsung.txt b/Documentation/devicetree/bindings/spi/spi-samsung.txt
index 1e8a857..6dbdeb3 100644
--- a/Documentation/devicetree/bindings/spi/spi-samsung.txt
+++ b/Documentation/devicetree/bindings/spi/spi-samsung.txt
@@ -9,7 +9,7 @@ Required SoC Specific Properties:
- samsung,s3c2443-spi: for s3c2443, s3c2416 and s3c2450 platforms
- samsung,s3c6410-spi: for s3c6410 platforms
- samsung,s5pv210-spi: for s5pv210 and s5pc110 platforms
- - samsung,exynos4210-spi: for exynos4 and exynos5 platforms
+ - samsung,exynos7-spi: for exynos7 platforms
- reg: physical base address of the controller and length of memory mapped
region.
diff --git a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
index f455182..e9c78ce 100644
--- a/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
+++ b/Documentation/devicetree/bindings/timer/marvell,armada-370-xp-timer.txt
@@ -2,8 +2,10 @@ Marvell Armada 370 and Armada XP Timers
---------------------------------------
Required properties:
-- compatible: Should be either "marvell,armada-370-timer" or
- "marvell,armada-xp-timer" as appropriate.
+- compatible: Should be one of the following
+ "marvell,armada-370-timer",
+ "marvell,armada-375-timer",
+ "marvell,armada-xp-timer".
- interrupts: Should contain the list of Global Timer interrupts and
then local timer interrupts
- reg: Should contain location and length for timers register. First
@@ -13,7 +15,8 @@ Required properties:
Clocks required for compatible = "marvell,armada-370-timer":
- clocks : Must contain a single entry describing the clock input
-Clocks required for compatible = "marvell,armada-xp-timer":
+Clocks required for compatibles = "marvell,armada-xp-timer",
+ "marvell,armada-375-timer":
- clocks : Must contain an entry for each entry in clock-names.
- clock-names : Must include the following entries:
"nbclk" (L2/coherency fabric clock),
diff --git a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt
index d9a8d5a..ba0a34d 100644
--- a/Documentation/devicetree/bindings/timer/renesas,mtu2.txt
+++ b/Documentation/devicetree/bindings/timer/renesas,mtu2.txt
@@ -1,4 +1,4 @@
-* Renesas R-Car Multi-Function Timer Pulse Unit 2 (MTU2)
+* Renesas Multi-Function Timer Pulse Unit 2 (MTU2)
The MTU2 is a multi-purpose, multi-channel timer/counter with configurable
clock inputs and programmable compare match.
diff --git a/Documentation/devicetree/bindings/timer/renesas,tmu.txt b/Documentation/devicetree/bindings/timer/renesas,tmu.txt
index 7db89fb..cd5f20b 100644
--- a/Documentation/devicetree/bindings/timer/renesas,tmu.txt
+++ b/Documentation/devicetree/bindings/timer/renesas,tmu.txt
@@ -1,4 +1,4 @@
-* Renesas R-Car Timer Unit (TMU)
+* Renesas R-Mobile/R-Car Timer Unit (TMU)
The TMU is a 32-bit timer/counter with configurable clock inputs and
programmable compare match.
@@ -9,6 +9,8 @@ are independent. The TMU hardware supports up to three channels.
Required Properties:
- compatible: must contain one or more of the following:
+ - "renesas,tmu-r8a7740" for the r8a7740 TMU
+ - "renesas,tmu-r8a7778" for the r8a7778 TMU
- "renesas,tmu-r8a7779" for the r8a7779 TMU
- "renesas,tmu" for any TMU.
This is a fallback for the above renesas,tmu-* entries
diff --git a/Documentation/devicetree/bindings/unittest.txt b/Documentation/devicetree/bindings/unittest.txt
new file mode 100644
index 0000000..0f92a22
--- /dev/null
+++ b/Documentation/devicetree/bindings/unittest.txt
@@ -0,0 +1,14 @@
+* OF selftest platform device
+
+** selftest
+
+Required properties:
+- compatible: must be "selftest"
+
+All other properties are optional.
+
+Example:
+ selftest {
+ compatible = "selftest";
+ status = "okay";
+ };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.txt b/Documentation/devicetree/bindings/vendor-prefixes.txt
index a344ec2..2417cb0 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.txt
+++ b/Documentation/devicetree/bindings/vendor-prefixes.txt
@@ -41,6 +41,7 @@ dallas Maxim Integrated Products (formerly Dallas Semiconductor)
davicom DAVICOM Semiconductor, Inc.
denx Denx Software Engineering
digi Digi International Inc.
+digilent Diglent, Inc.
dlg Dialog Semiconductor
dlink D-Link Corporation
dmo Data Modul AG
@@ -78,6 +79,7 @@ innolux Innolux Corporation
intel Intel Corporation
intercontrol Inter Control Group
isee ISEE 2007 S.L.
+isil Intersil (deprecated, use isl)
isl Intersil
karo Ka-Ro electronics GmbH
keymile Keymile GmbH
@@ -91,6 +93,7 @@ lltc Linear Technology Corporation
marvell Marvell Technology Group Ltd.
maxim Maxim Integrated Products
mediatek MediaTek Inc.
+merrii Merrii Technology Co., Ltd.
micrel Micrel Inc.
microchip Microchip Technology Inc.
micron Micron Technology Inc.
@@ -112,6 +115,7 @@ nxp NXP Semiconductors
onnn ON Semiconductor Corp.
opencores OpenCores.org
panasonic Panasonic Corporation
+pericom Pericom Technology Inc.
phytec PHYTEC Messtechnik GmbH
picochip Picochip Ltd
plathome Plat'Home Co., Ltd.
@@ -149,6 +153,7 @@ st STMicroelectronics
ste ST-Ericsson
stericsson ST-Ericsson
synology Synology, Inc.
+tbs TBS Technologies
thine THine Electronics, Inc.
ti Texas Instruments
tlm Trusted Logic Mobility
diff --git a/Documentation/devicetree/bindings/video/backlight/lp855x.txt b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
index 96e83a56..0a3ecbc 100644
--- a/Documentation/devicetree/bindings/video/backlight/lp855x.txt
+++ b/Documentation/devicetree/bindings/video/backlight/lp855x.txt
@@ -12,6 +12,7 @@ Optional properties:
- pwm-period: PWM period value. Set only PWM input mode used (u32)
- rom-addr: Register address of ROM area to be updated (u8)
- rom-val: Register value to be updated (u8)
+ - power-supply: Regulator which controls the 3V rail
Example:
@@ -56,6 +57,7 @@ Example:
backlight@2c {
compatible = "ti,lp8557";
reg = <0x2c>;
+ power-supply = <&backlight_vdd>;
dev-ctrl = /bits/ 8 <0x41>;
init-brt = /bits/ 8 <0x0a>;
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt
new file mode 100644
index 0000000..c46ba64
--- /dev/null
+++ b/Documentation/devicetree/bindings/video/simple-framebuffer-sunxi.txt
@@ -0,0 +1,33 @@
+Sunxi specific Simple Framebuffer bindings
+
+This binding documents sunxi specific extensions to the simple-framebuffer
+bindings. The sunxi simplefb u-boot code relies on the devicetree containing
+pre-populated simplefb nodes.
+
+These extensions are intended so that u-boot can select the right node based
+on which pipeline is being used. As such they are solely intended for
+firmware / bootloader use, and the OS should ignore them.
+
+Required properties:
+- compatible: "allwinner,simple-framebuffer"
+- allwinner,pipeline, one of:
+ "de_be0-lcd0"
+ "de_be1-lcd1"
+ "de_be0-lcd0-hdmi"
+ "de_be1-lcd1-hdmi"
+
+Example:
+
+chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@0 {
+ compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-hdmi";
+ clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+ <&ahb_gates 44>;
+ status = "disabled";
+ };
+};
diff --git a/Documentation/devicetree/bindings/video/simple-framebuffer.txt b/Documentation/devicetree/bindings/video/simple-framebuffer.txt
index 70c26f3..4474ef6 100644
--- a/Documentation/devicetree/bindings/video/simple-framebuffer.txt
+++ b/Documentation/devicetree/bindings/video/simple-framebuffer.txt
@@ -1,8 +1,40 @@
Simple Framebuffer
-A simple frame-buffer describes a raw memory region that may be rendered to,
-with the assumption that the display hardware has already been set up to scan
-out from that buffer.
+A simple frame-buffer describes a frame-buffer setup by firmware or
+the bootloader, with the assumption that the display hardware has already
+been set up to scan out from the memory pointed to by the reg property.
+
+Since simplefb nodes represent runtime information they must be sub-nodes of
+the chosen node (*). Simplefb nodes must be named "framebuffer@<address>".
+
+If the devicetree contains nodes for the display hardware used by a simplefb,
+then the simplefb node must contain a property called "display", which
+contains a phandle pointing to the primary display hw node, so that the OS
+knows which simplefb to disable when handing over control to a driver for the
+real hardware. The bindings for the hw nodes must specify which node is
+considered the primary node.
+
+It is advised to add display# aliases to help the OS determine how to number
+things. If display# aliases are used, then if the simplefb node contains a
+"display" property then the /aliases/display# path must point to the display
+hw node the "display" property points to, otherwise it must point directly
+to the simplefb node.
+
+If a simplefb node represents the preferred console for user interaction,
+then the chosen node's stdout-path property should point to it, or to the
+primary display hw node, as with display# aliases. If display aliases are
+used then it should be set to the alias instead.
+
+It is advised that devicetree files contain pre-filled, disabled framebuffer
+nodes, so that the firmware only needs to update the mode information and
+enable them. This way if e.g. later on support for more display clocks get
+added, the simplefb nodes will already contain this info and the firmware
+does not need to be updated.
+
+If pre-filled framebuffer nodes are used, the firmware may need extra
+information to find the right node. In that case an extra platform specific
+compatible and platform specific properties should be used and documented,
+see e.g. simple-framebuffer-sunxi.txt .
Required properties:
- compatible: "simple-framebuffer"
@@ -14,13 +46,41 @@ Required properties:
- r5g6b5 (16-bit pixels, d[15:11]=r, d[10:5]=g, d[4:0]=b).
- a8b8g8r8 (32-bit pixels, d[31:24]=a, d[23:16]=b, d[15:8]=g, d[7:0]=r).
+Optional properties:
+- clocks : List of clocks used by the framebuffer. Clocks listed here
+ are expected to already be configured correctly. The OS must
+ ensure these clocks are not modified or disabled while the
+ simple framebuffer remains active.
+- display : phandle pointing to the primary display hardware node
+
Example:
- framebuffer {
+aliases {
+ display0 = &lcdc0;
+}
+
+chosen {
+ framebuffer0: framebuffer@1d385000 {
compatible = "simple-framebuffer";
reg = <0x1d385000 (1600 * 1200 * 2)>;
width = <1600>;
height = <1200>;
stride = <(1600 * 2)>;
format = "r5g6b5";
+ clocks = <&ahb_gates 36>, <&ahb_gates 43>, <&ahb_gates 44>;
+ display = <&lcdc0>;
+ };
+ stdout-path = "display0";
+};
+
+soc@01c00000 {
+ lcdc0: lcdc@1c0c000 {
+ compatible = "allwinner,sun4i-a10-lcdc";
+ ...
};
+};
+
+
+*) Older devicetree files may have a compatible = "simple-framebuffer" node
+in a different place, operating systems must first enumerate any compatible
+nodes found under chosen and then check for other compatible nodes.
diff --git a/Documentation/devicetree/bindings/w1/omap-hdq.txt b/Documentation/devicetree/bindings/w1/omap-hdq.txt
new file mode 100644
index 0000000..fef7947
--- /dev/null
+++ b/Documentation/devicetree/bindings/w1/omap-hdq.txt
@@ -0,0 +1,17 @@
+* OMAP HDQ One wire bus master controller
+
+Required properties:
+- compatible : should be "ti,omap3-1w"
+- reg : Address and length of the register set for the device
+- interrupts : interrupt line.
+- ti,hwmods : "hdq1w"
+
+Example:
+
+- From omap3.dtsi
+ hdqw1w: 1w@480b2000 {
+ compatible = "ti,omap3-1w";
+ reg = <0x480b2000 0x1000>;
+ interrupts = <58>;
+ ti,hwmods = "hdq1w";
+ };
diff --git a/Documentation/devicetree/bindings/watchdog/marvel.txt b/Documentation/devicetree/bindings/watchdog/marvel.txt
index 97223fd..858ed92 100644
--- a/Documentation/devicetree/bindings/watchdog/marvel.txt
+++ b/Documentation/devicetree/bindings/watchdog/marvel.txt
@@ -17,6 +17,18 @@ For "marvell,armada-375-wdt" and "marvell,armada-380-wdt":
- reg : A third entry is mandatory and should contain the
shared mask/unmask RSTOUT address.
+Clocks required for compatibles = "marvell,orion-wdt",
+ "marvell,armada-370-wdt":
+- clocks : Must contain a single entry describing the clock input
+
+Clocks required for compatibles = "marvell,armada-xp-wdt"
+ "marvell,armada-375-wdt"
+ "marvell,armada-380-wdt":
+- clocks : Must contain an entry for each entry in clock-names.
+- clock-names : Must include the following entries:
+ "nbclk" (L2/coherency fabric clock),
+ "fixed" (Reference 25 MHz fixed-clock).
+
Optional properties:
- interrupts : Contains the IRQ for watchdog expiration
@@ -30,4 +42,5 @@ Example:
interrupts = <3>;
timeout-sec = <10>;
status = "okay";
+ clocks = <&gate_clk 7>;
};
diff --git a/Documentation/devicetree/of_selftest.txt b/Documentation/devicetree/of_selftest.txt
index 1e3d5c9..57a808b 100644
--- a/Documentation/devicetree/of_selftest.txt
+++ b/Documentation/devicetree/of_selftest.txt
@@ -63,7 +63,6 @@ struct device_node {
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
- struct device_node *allnext; /* next in list of all nodes */
...
};
@@ -99,12 +98,6 @@ child11 -> sibling12 -> sibling13 -> sibling14 -> null
Figure 1: Generic structure of un-flattened device tree
-*allnext: it is used to link all the nodes of DT into a list. So, for the
- above tree the list would be as follows:
-
-root->child1->child11->sibling12->sibling13->child131->sibling14->sibling2->
-child21->sibling22->sibling23->sibling3->child31->sibling32->sibling4->null
-
Before executing OF selftest, it is required to attach the test data to
machine's device tree (if present). So, when selftest_data_add() is called,
at first it reads the flattened device tree data linked into the kernel image
@@ -131,11 +124,6 @@ root ('/')
test-child01 null null null
-allnext list:
-
-root->testcase-data->test-child0->test-child01->test-sibling1->test-sibling2
-->test-sibling3->null
-
Figure 2: Example test data tree to be attached to live tree.
According to the scenario above, the live tree is already present so it isn't
@@ -204,8 +192,6 @@ detached and then moving up the parent nodes are removed, and eventually the
whole tree). selftest_data_remove() calls detach_node_and_children() that uses
of_detach_node() to detach the nodes from the live device tree.
-To detach a node, of_detach_node() first updates all_next linked list, by
-attaching the previous node's allnext to current node's allnext pointer. And
-then, it either updates the child pointer of given node's parent to its
-sibling or attaches the previous sibling to the given node's sibling, as
-appropriate. That is it :)
+To detach a node, of_detach_node() either updates the child pointer of given
+node's parent to its sibling or attaches the previous sibling to the given
+node's sibling, as appropriate. That is it :)
diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
new file mode 100644
index 0000000..30ae758
--- /dev/null
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -0,0 +1,133 @@
+Device Tree Overlay Notes
+-------------------------
+
+This document describes the implementation of the in-kernel
+device tree overlay functionality residing in drivers/of/overlay.c and is a
+companion document to Documentation/devicetree/dt-object-internal.txt[1] &
+Documentation/devicetree/dynamic-resolution-notes.txt[2]
+
+How overlays work
+-----------------
+
+A Device Tree's overlay purpose is to modify the kernel's live tree, and
+have the modification affecting the state of the the kernel in a way that
+is reflecting the changes.
+Since the kernel mainly deals with devices, any new device node that result
+in an active device should have it created while if the device node is either
+disabled or removed all together, the affected device should be deregistered.
+
+Lets take an example where we have a foo board with the following base tree
+which is taken from [1].
+
+---- foo.dts -----------------------------------------------------------------
+ /* FOO platform */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+ }
+ };
+---- foo.dts -----------------------------------------------------------------
+
+The overlay bar.dts, when loaded (and resolved as described in [2]) should
+
+---- bar.dts -----------------------------------------------------------------
+/plugin/; /* allow undefined label references and record them */
+/ {
+ .... /* various properties for loader use; i.e. part id etc. */
+ fragment@0 {
+ target = <&ocp>;
+ __overlay__ {
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+ };
+ };
+};
+---- bar.dts -----------------------------------------------------------------
+
+result in foo+bar.dts
+
+---- foo+bar.dts -------------------------------------------------------------
+ /* FOO platform + bar peripheral */
+ / {
+ compatible = "corp,foo";
+
+ /* shared resources */
+ res: res {
+ };
+
+ /* On chip peripherals */
+ ocp: ocp {
+ /* peripherals that are always instantiated */
+ peripheral1 { ... };
+
+ /* bar peripheral */
+ bar {
+ compatible = "corp,bar";
+ ... /* various properties and child nodes */
+ }
+ }
+ };
+---- foo+bar.dts -------------------------------------------------------------
+
+As a result of the the overlay, a new device node (bar) has been created
+so a bar platform device will be registered and if a matching device driver
+is loaded the device will be created as expected.
+
+Overlay in-kernel API
+--------------------------------
+
+The API is quite easy to use.
+
+1. Call of_overlay_create() to create and apply an overlay. The return value
+is a cookie identifying this overlay.
+
+2. Call of_overlay_destroy() to remove and cleanup the overlay previously
+created via the call to of_overlay_create(). Removal of an overlay that
+is stacked by another will not be permitted.
+
+Finally, if you need to remove all overlays in one-go, just call
+of_overlay_destroy_all() which will remove every single one in the correct
+order.
+
+Overlay DTS Format
+------------------
+
+The DTS of an overlay should have the following format:
+
+{
+ /* ignored properties by the overlay */
+
+ fragment@0 { /* first child node */
+
+ target=<phandle>; /* phandle target of the overlay */
+ or
+ target-path="/path"; /* target path of the overlay */
+
+ __overlay__ {
+ property-a; /* add property-a to the target */
+ node-a { /* add to an existing, or create a node-a */
+ ...
+ };
+ };
+ }
+ fragment@1 { /* second child node */
+ ...
+ };
+ /* more fragments follow */
+}
+
+Using the non-phandle based target method allows one to use a base DT which does
+not contain a __symbols__ node, i.e. it was not compiled with the -@ option.
+The __symbols__ node is only required for the target=<phandle> method, since it
+contains the information required to map from a phandle to a tree location.
diff --git a/Documentation/devicetree/todo.txt b/Documentation/devicetree/todo.txt
index c3cf065..b5139d1 100644
--- a/Documentation/devicetree/todo.txt
+++ b/Documentation/devicetree/todo.txt
@@ -2,7 +2,6 @@ Todo list for devicetree:
=== General structure ===
- Switch from custom lists to (h)list_head for nodes and properties structure
-- Remove of_allnodes list and iterate using list of child nodes alone
=== CONFIG_OF_DYNAMIC ===
- Switch to RCU for tree updates and get rid of global spinlock
diff --git a/Documentation/filesystems/debugfs.txt b/Documentation/filesystems/debugfs.txt
index 3a863f6..88ab81c 100644
--- a/Documentation/filesystems/debugfs.txt
+++ b/Documentation/filesystems/debugfs.txt
@@ -140,7 +140,7 @@ file.
struct dentry *parent,
struct debugfs_regset32 *regset);
- int debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
+ void debugfs_print_regs32(struct seq_file *s, struct debugfs_reg32 *regs,
int nregs, void __iomem *base, char *prefix);
The "base" argument may be 0, but you may want to build the reg32 array
diff --git a/Documentation/filesystems/f2fs.txt b/Documentation/filesystems/f2fs.txt
index 2cca5a2..e0950c4 100644
--- a/Documentation/filesystems/f2fs.txt
+++ b/Documentation/filesystems/f2fs.txt
@@ -122,6 +122,10 @@ disable_ext_identify Disable the extension list configured by mkfs, so f2fs
inline_xattr Enable the inline xattrs feature.
inline_data Enable the inline data feature: New created small(<~3.4k)
files can be written into inode block.
+inline_dentry Enable the inline dir feature: data in new created
+ directory entries can be written into inode block. The
+ space of inode block which is used to store inline
+ dentries is limited to ~3.4k.
flush_merge Merge concurrent cache_flush commands as much as possible
to eliminate redundant command issues. If the underlying
device handles the cache_flush command relatively slowly,
@@ -131,6 +135,9 @@ nobarrier This option can be used if underlying storage guarantees
If this option is set, no cache_flush commands are issued
but f2fs still guarantees the write ordering of all the
data writes.
+fastboot This option is used when a system wants to reduce mount
+ time as much as possible, even though normal performance
+ can be sacrificed.
================================================================================
DEBUGFS ENTRIES
diff --git a/Documentation/filesystems/nfs/Exporting b/Documentation/filesystems/nfs/Exporting
index c8f036a..520a4be 100644
--- a/Documentation/filesystems/nfs/Exporting
+++ b/Documentation/filesystems/nfs/Exporting
@@ -72,24 +72,11 @@ c/ Helper routines to allocate anonymous dentries, and to help attach
DCACHE_DISCONNECTED) dentry is allocated and attached.
In the case of a directory, care is taken that only one dentry
can ever be attached.
- d_splice_alias(inode, dentry) or d_materialise_unique(dentry, inode)
- will introduce a new dentry into the tree; either the passed-in
- dentry or a preexisting alias for the given inode (such as an
- anonymous one created by d_obtain_alias), if appropriate. The two
- functions differ in their handling of directories with preexisting
- aliases:
- d_splice_alias will use any existing IS_ROOT dentry, but it will
- return -EIO rather than try to move a dentry with a different
- parent. This is appropriate for local filesystems, which
- should never see such an alias unless the filesystem is
- corrupted somehow (for example, if two on-disk directory
- entries refer to the same directory.)
- d_materialise_unique will attempt to move any dentry. This is
- appropriate for distributed filesystems, where finding a
- directory other than where we last cached it may be a normal
- consequence of concurrent operations on other hosts.
- Both functions return NULL when the passed-in dentry is used,
- following the calling convention of ->lookup.
+ d_splice_alias(inode, dentry) will introduce a new dentry into the tree;
+ either the passed-in dentry or a preexisting alias for the given inode
+ (such as an anonymous one created by d_obtain_alias), if appropriate.
+ It returns NULL when the passed-in dentry is used, following the calling
+ convention of ->lookup.
Filesystem Issues
diff --git a/Documentation/filesystems/porting b/Documentation/filesystems/porting
index 0f3a139..fa2db08 100644
--- a/Documentation/filesystems/porting
+++ b/Documentation/filesystems/porting
@@ -463,3 +463,11 @@ in your dentry operations instead.
of the in-tree instances did). inode_hash_lock is still held,
of course, so they are still serialized wrt removal from inode hash,
as well as wrt set() callback of iget5_locked().
+--
+[mandatory]
+ d_materialise_unique() is gone; d_splice_alias() does everything you
+ need now. Remember that they have opposite orders of arguments ;-/
+--
+[mandatory]
+ f_dentry is gone; use f_path.dentry, or, better yet, see if you can avoid
+ it entirely.
diff --git a/Documentation/filesystems/seq_file.txt b/Documentation/filesystems/seq_file.txt
index 8ea3e90..b797ed3 100644
--- a/Documentation/filesystems/seq_file.txt
+++ b/Documentation/filesystems/seq_file.txt
@@ -180,23 +180,19 @@ output must be passed to the seq_file code. Some utility functions have
been defined which make this task easy.
Most code will simply use seq_printf(), which works pretty much like
-printk(), but which requires the seq_file pointer as an argument. It is
-common to ignore the return value from seq_printf(), but a function
-producing complicated output may want to check that value and quit if
-something non-zero is returned; an error return means that the seq_file
-buffer has been filled and further output will be discarded.
+printk(), but which requires the seq_file pointer as an argument.
For straight character output, the following functions may be used:
- int seq_putc(struct seq_file *m, char c);
- int seq_puts(struct seq_file *m, const char *s);
- int seq_escape(struct seq_file *m, const char *s, const char *esc);
+ seq_putc(struct seq_file *m, char c);
+ seq_puts(struct seq_file *m, const char *s);
+ seq_escape(struct seq_file *m, const char *s, const char *esc);
The first two output a single character and a string, just like one would
expect. seq_escape() is like seq_puts(), except that any character in s
which is in the string esc will be represented in octal form in the output.
-There is also a pair of functions for printing filenames:
+There are also a pair of functions for printing filenames:
int seq_path(struct seq_file *m, struct path *path, char *esc);
int seq_path_root(struct seq_file *m, struct path *path,
@@ -209,6 +205,14 @@ root is desired, it can be used with seq_path_root(). Note that, if it
turns out that path cannot be reached from root, the value of root will be
changed in seq_file_root() to a root which *does* work.
+A function producing complicated output may want to check
+ bool seq_has_overflowed(struct seq_file *m);
+and avoid further seq_<output> calls if true is returned.
+
+A true return from seq_has_overflowed means that the seq_file buffer will
+be discarded and the seq_show function will attempt to allocate a larger
+buffer and retry printing.
+
Making it all work
diff --git a/Documentation/filesystems/vfs.txt b/Documentation/filesystems/vfs.txt
index 20bf204..43ce050 100644
--- a/Documentation/filesystems/vfs.txt
+++ b/Documentation/filesystems/vfs.txt
@@ -835,7 +835,7 @@ struct file_operations {
ssize_t (*splice_read)(struct file *, struct pipe_inode_info *, size_t, unsigned int);
int (*setlease)(struct file *, long arg, struct file_lock **, void **);
long (*fallocate)(struct file *, int mode, loff_t offset, loff_t len);
- int (*show_fdinfo)(struct seq_file *m, struct file *f);
+ void (*show_fdinfo)(struct seq_file *m, struct file *f);
};
Again, all methods are called without any locks being held, unless
diff --git a/Documentation/gpio/consumer.txt b/Documentation/gpio/consumer.txt
index 6ce5441..859918d 100644
--- a/Documentation/gpio/consumer.txt
+++ b/Documentation/gpio/consumer.txt
@@ -219,6 +219,24 @@ part of the IRQ interface, e.g. IRQF_TRIGGER_FALLING, as are system wakeup
capabilities.
+GPIOs and ACPI
+==============
+
+On ACPI systems, GPIOs are described by GpioIo()/GpioInt() resources listed by
+the _CRS configuration objects of devices. Those resources do not provide
+connection IDs (names) for GPIOs, so it is necessary to use an additional
+mechanism for this purpose.
+
+Systems compliant with ACPI 5.1 or newer may provide a _DSD configuration object
+which, among other things, may be used to provide connection IDs for specific
+GPIOs described by the GpioIo()/GpioInt() resources in _CRS. If that is the
+case, it will be handled by the GPIO subsystem automatically. However, if the
+_DSD is not present, the mappings between GpioIo()/GpioInt() resources and GPIO
+connection IDs need to be provided by device drivers.
+
+For details refer to Documentation/acpi/gpio-properties.txt
+
+
Interacting With the Legacy GPIO Subsystem
==========================================
Many kernel subsystems still handle GPIOs using the legacy integer-based
diff --git a/Documentation/hwmon/lm75 b/Documentation/hwmon/lm75
index c6a5ff1..67691a0a 100644
--- a/Documentation/hwmon/lm75
+++ b/Documentation/hwmon/lm75
@@ -53,6 +53,11 @@ Supported chips:
http://www.ti.com/product/tmp75
http://www.ti.com/product/tmp175
http://www.ti.com/product/tmp275
+ * NXP LM75B
+ Prefix: 'lm75b'
+ Addresses scanned: none
+ Datasheet: Publicly available at the NXP website
+ http://www.nxp.com/documents/data_sheet/LM75B.pdf
Author: Frodo Looijaard <frodol@dds.nl>
diff --git a/Documentation/hwmon/lm95234 b/Documentation/hwmon/lm95234
index a0e95dd..32b777e 100644
--- a/Documentation/hwmon/lm95234
+++ b/Documentation/hwmon/lm95234
@@ -2,6 +2,10 @@ Kernel driver lm95234
=====================
Supported chips:
+ * National Semiconductor / Texas Instruments LM95233
+ Addresses scanned: I2C 0x18, 0x2a, 0x2b
+ Datasheet: Publicly available at the Texas Instruments website
+ http://www.ti.com/product/lm95233
* National Semiconductor / Texas Instruments LM95234
Addresses scanned: I2C 0x18, 0x4d, 0x4e
Datasheet: Publicly available at the Texas Instruments website
@@ -13,11 +17,12 @@ Author: Guenter Roeck <linux@roeck-us.net>
Description
-----------
-LM95234 is an 11-bit digital temperature sensor with a 2-wire System Management
-Bus (SMBus) interface and TrueTherm technology that can very accurately monitor
-the temperature of four remote diodes as well as its own temperature.
-The four remote diodes can be external devices such as microprocessors,
-graphics processors or diode-connected 2N3904s. The LM95234's TruTherm
+LM95233 and LM95234 are 11-bit digital temperature sensors with a 2-wire
+System Management Bus (SMBus) interface and TrueTherm technology
+that can very accurately monitor the temperature of two (LM95233)
+or four (LM95234) remote diodes as well as its own temperature.
+The remote diodes can be external devices such as microprocessors,
+graphics processors or diode-connected 2N3904s. The chip's TruTherm
beta compensation technology allows sensing of 90 nm or 65 nm process
thermal diodes accurately.
diff --git a/Documentation/hwmon/lm95245 b/Documentation/hwmon/lm95245
index 77eaf28..d755901 100644
--- a/Documentation/hwmon/lm95245
+++ b/Documentation/hwmon/lm95245
@@ -2,10 +2,14 @@ Kernel driver lm95245
==================
Supported chips:
- * National Semiconductor LM95245
+ * TI LM95235
+ Addresses scanned: I2C 0x18, 0x29, 0x4c
+ Datasheet: Publicly available at the TI website
+ http://www.ti.com/lit/ds/symlink/lm95235.pdf
+ * TI / National Semiconductor LM95245
Addresses scanned: I2C 0x18, 0x19, 0x29, 0x4c, 0x4d
- Datasheet: Publicly available at the National Semiconductor website
- http://www.national.com/mpf/LM/LM95245.html
+ Datasheet: Publicly available at the TI website
+ http://www.ti.com/lit/ds/symlink/lm95245.pdf
Author: Alexander Stein <alexander.stein@systec-electronic.com>
@@ -13,10 +17,10 @@ Author: Alexander Stein <alexander.stein@systec-electronic.com>
Description
-----------
-The LM95245 is an 11-bit digital temperature sensor with a 2-wire System
+LM95235 and LM95245 are 11-bit digital temperature sensors with a 2-wire System
Management Bus (SMBus) interface and TruTherm technology that can monitor
the temperature of a remote diode as well as its own temperature.
-The LM95245 can be used to very accurately monitor the temperature of
+The chips can be used to very accurately monitor the temperature of
external devices such as microprocessors.
All temperature values are given in millidegrees Celsius. Local temperature
diff --git a/Documentation/hwmon/nct6775 b/Documentation/hwmon/nct6775
index 4e9ef60..f0dd3d2 100644
--- a/Documentation/hwmon/nct6775
+++ b/Documentation/hwmon/nct6775
@@ -8,11 +8,15 @@ Kernel driver NCT6775
=====================
Supported chips:
+ * Nuvoton NCT6102D/NCT6104D/NCT6106D
+ Prefix: 'nct6106'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from the Nuvoton web site
* Nuvoton NCT5572D/NCT6771F/NCT6772F/NCT6775F/W83677HG-I
Prefix: 'nct6775'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
- * Nuvoton NCT5577D/NCT6776D/NCT6776F
+ * Nuvoton NCT5573D/NCT5577D/NCT6776D/NCT6776F
Prefix: 'nct6776'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
@@ -20,6 +24,14 @@ Supported chips:
Prefix: 'nct6779'
Addresses scanned: ISA address retrieved from Super I/O registers
Datasheet: Available from Nuvoton upon request
+ * Nuvoton NCT6791D
+ Prefix: 'nct6791'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
+ * Nuvoton NCT6792D
+ Prefix: 'nct6792'
+ Addresses scanned: ISA address retrieved from Super I/O registers
+ Datasheet: Available from Nuvoton upon request
Authors:
Guenter Roeck <linux@roeck-us.net>
diff --git a/Documentation/hwmon/nct7802 b/Documentation/hwmon/nct7802
new file mode 100644
index 0000000..2e00f5e
--- /dev/null
+++ b/Documentation/hwmon/nct7802
@@ -0,0 +1,32 @@
+Kernel driver nct7802
+=====================
+
+Supported chips:
+ * Nuvoton NCT7802Y
+ Prefix: 'nct7802'
+ Addresses scanned: I2C 0x28..0x2f
+ Datasheet: Available from Nuvoton web site
+
+Authors:
+ Guenter Roeck <linux@roeck-us.net>
+
+Description
+-----------
+
+This driver implements support for the Nuvoton NCT7802Y hardware monitoring
+chip. NCT7802Y supports 6 temperature sensors, 5 voltage sensors, and 3 fan
+speed sensors.
+
+The chip also supports intelligent fan speed control. This functionality is
+not currently supported by the driver.
+
+Tested Boards and BIOS Versions
+-------------------------------
+
+The driver has been reported to work with the following boards and
+BIOS versions.
+
+Board BIOS version
+---------------------------------------------------------------
+Kontron COMe-bSC2 CHR2E934.001.GGO
+Kontron COMe-bIP2 CCR2E212
diff --git a/Documentation/hwmon/tmp401 b/Documentation/hwmon/tmp401
index f91e3fa..8eb88e9 100644
--- a/Documentation/hwmon/tmp401
+++ b/Documentation/hwmon/tmp401
@@ -18,6 +18,10 @@ Supported chips:
Prefix: 'tmp432'
Addresses scanned: I2C 0x4c, 0x4d
Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp432.html
+ * Texas Instruments TMP435
+ Prefix: 'tmp435'
+ Addresses scanned: I2C 0x37, 0x48 - 0x4f
+ Datasheet: http://focus.ti.com/docs/prod/folders/print/tmp435.html
Authors:
Hans de Goede <hdegoede@redhat.com>
@@ -27,8 +31,8 @@ Description
-----------
This driver implements support for Texas Instruments TMP401, TMP411,
-TMP431, and TMP432 chips. These chips implement one or two remote and
-one local temperature sensors. Temperature is measured in degrees
+TMP431, TMP432 and TMP435 chips. These chips implement one or two remote
+and one local temperature sensors. Temperature is measured in degrees
Celsius. Resolution of the remote sensor is 0.0625 degree. Local
sensor resolution can be set to 0.5, 0.25, 0.125 or 0.0625 degree (not
supported by the driver so far, so using the default resolution of 0.5
diff --git a/Documentation/kdump/kdump.txt b/Documentation/kdump/kdump.txt
index 6c0b9f2..bc4bd5a 100644
--- a/Documentation/kdump/kdump.txt
+++ b/Documentation/kdump/kdump.txt
@@ -471,6 +471,13 @@ format. Crash is available on Dave Anderson's site at the following URL:
http://people.redhat.com/~anderson/
+Trigger Kdump on WARN()
+=======================
+
+The kernel parameter, panic_on_warn, calls panic() in all WARN() paths. This
+will cause a kdump to occur at the panic() call. In cases where a user wants
+to specify this during runtime, /proc/sys/kernel/panic_on_warn can be set to 1
+to achieve the same behaviour.
Contact
=======
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt
index 479f332..eacb2e0 100644
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -1446,6 +1446,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
disable
Do not enable intel_pstate as the default
scaling driver for the supported processors
+ no_hwp
+ Do not enable hardware P state control (HWP)
+ if available.
intremap= [X86-64, Intel-IOMMU]
on enable Interrupt Remapping (default)
@@ -2509,6 +2512,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
timeout < 0: reboot immediately
Format: <timeout>
+ panic_on_warn panic() instead of WARN(). Useful to cause kdump
+ on a WARN().
+
crash_kexec_post_notifiers
Run kdump after running panic-notifiers and dumping
kmsg. This only for the users who doubt kdump always
@@ -2940,6 +2946,13 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
quiescent states. Units are jiffies, minimum
value is one, and maximum value is HZ.
+ rcutree.kthread_prio= [KNL,BOOT]
+ Set the SCHED_FIFO priority of the RCU
+ per-CPU kthreads (rcuc/N). This value is also
+ used for the priority of the RCU boost threads
+ (rcub/N). Valid values are 1-99 and the default
+ is 1 (the least-favored priority).
+
rcutree.rcu_nocb_leader_stride= [KNL]
Set the number of NOCB kthread groups, which
defaults to the square root of the number of
@@ -3089,6 +3102,15 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
messages. Disable with a value less than or equal
to zero.
+ rcupdate.rcu_self_test= [KNL]
+ Run the RCU early boot self tests
+
+ rcupdate.rcu_self_test_bh= [KNL]
+ Run the RCU bh early boot self tests
+
+ rcupdate.rcu_self_test_sched= [KNL]
+ Run the RCU sched early boot self tests
+
rdinit= [KNL]
Format: <full_path>
Run specified binary instead of /init from the ramdisk,
@@ -3501,7 +3523,7 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
are saved.
trace_buf_size=nn[KMG]
- [FTRACE] will set tracing buffer size.
+ [FTRACE] will set tracing buffer size on each cpu.
trace_event=[event-list]
[FTRACE] Set and start specified trace events in order
diff --git a/Documentation/locking/lglock.txt b/Documentation/locking/lglock.txt
new file mode 100644
index 0000000..a6971e3
--- /dev/null
+++ b/Documentation/locking/lglock.txt
@@ -0,0 +1,166 @@
+lglock - local/global locks for mostly local access patterns
+------------------------------------------------------------
+
+Origin: Nick Piggin's VFS scalability series introduced during
+ 2.6.35++ [1] [2]
+Location: kernel/locking/lglock.c
+ include/linux/lglock.h
+Users: currently only the VFS and stop_machine related code
+
+Design Goal:
+------------
+
+Improve scalability of globally used large data sets that are
+distributed over all CPUs as per_cpu elements.
+
+To manage global data structures that are partitioned over all CPUs
+as per_cpu elements but can be mostly handled by CPU local actions
+lglock will be used where the majority of accesses are cpu local
+reading and occasional cpu local writing with very infrequent
+global write access.
+
+
+* deal with things locally whenever possible
+ - very fast access to the local per_cpu data
+ - reasonably fast access to specific per_cpu data on a different
+ CPU
+* while making global action possible when needed
+ - by expensive access to all CPUs locks - effectively
+ resulting in a globally visible critical section.
+
+Design:
+-------
+
+Basically it is an array of per_cpu spinlocks with the
+lg_local_lock/unlock accessing the local CPUs lock object and the
+lg_local_lock_cpu/unlock_cpu accessing a remote CPUs lock object
+the lg_local_lock has to disable preemption as migration protection so
+that the reference to the local CPUs lock does not go out of scope.
+Due to the lg_local_lock/unlock only touching cpu-local resources it
+is fast. Taking the local lock on a different CPU will be more
+expensive but still relatively cheap.
+
+One can relax the migration constraints by acquiring the current
+CPUs lock with lg_local_lock_cpu, remember the cpu, and release that
+lock at the end of the critical section even if migrated. This should
+give most of the performance benefits without inhibiting migration
+though needs careful considerations for nesting of lglocks and
+consideration of deadlocks with lg_global_lock.
+
+The lg_global_lock/unlock locks all underlying spinlocks of all
+possible CPUs (including those off-line). The preemption disable/enable
+are needed in the non-RT kernels to prevent deadlocks like:
+
+ on cpu 1
+
+ task A task B
+ lg_global_lock
+ got cpu 0 lock
+ <<<< preempt <<<<
+ lg_local_lock_cpu for cpu 0
+ spin on cpu 0 lock
+
+On -RT this deadlock scenario is resolved by the arch_spin_locks in the
+lglocks being replaced by rt_mutexes which resolve the above deadlock
+by boosting the lock-holder.
+
+
+Implementation:
+---------------
+
+The initial lglock implementation from Nick Piggin used some complex
+macros to generate the lglock/brlock in lglock.h - they were later
+turned into a set of functions by Andi Kleen [7]. The change to functions
+was motivated by the presence of multiple lock users and also by them
+being easier to maintain than the generating macros. This change to
+functions is also the basis to eliminated the restriction of not
+being initializeable in kernel modules (the remaining problem is that
+locks are not explicitly initialized - see lockdep-design.txt)
+
+Declaration and initialization:
+-------------------------------
+
+ #include <linux/lglock.h>
+
+ DEFINE_LGLOCK(name)
+ or:
+ DEFINE_STATIC_LGLOCK(name);
+
+ lg_lock_init(&name, "lockdep_name_string");
+
+ on UP this is mapped to DEFINE_SPINLOCK(name) in both cases, note
+ also that as of 3.18-rc6 all declaration in use are of the _STATIC_
+ variant (and it seems that the non-static was never in use).
+ lg_lock_init is initializing the lockdep map only.
+
+Usage:
+------
+
+From the locking semantics it is a spinlock. It could be called a
+locality aware spinlock. lg_local_* behaves like a per_cpu
+spinlock and lg_global_* like a global spinlock.
+No surprises in the API.
+
+ lg_local_lock(*lglock);
+ access to protected per_cpu object on this CPU
+ lg_local_unlock(*lglock);
+
+ lg_local_lock_cpu(*lglock, cpu);
+ access to protected per_cpu object on other CPU cpu
+ lg_local_unlock_cpu(*lglock, cpu);
+
+ lg_global_lock(*lglock);
+ access all protected per_cpu objects on all CPUs
+ lg_global_unlock(*lglock);
+
+ There are no _trylock variants of the lglocks.
+
+Note that the lg_global_lock/unlock has to iterate over all possible
+CPUs rather than the actually present CPUs or a CPU could go off-line
+with a held lock [4] and that makes it very expensive. A discussion on
+these issues can be found at [5]
+
+Constraints:
+------------
+
+ * currently the declaration of lglocks in kernel modules is not
+ possible, though this should be doable with little change.
+ * lglocks are not recursive.
+ * suitable for code that can do most operations on the CPU local
+ data and will very rarely need the global lock
+ * lg_global_lock/unlock is *very* expensive and does not scale
+ * on UP systems all lg_* primitives are simply spinlocks
+ * in PREEMPT_RT the spinlock becomes an rt-mutex and can sleep but
+ does not change the tasks state while sleeping [6].
+ * in PREEMPT_RT the preempt_disable/enable in lg_local_lock/unlock
+ is downgraded to a migrate_disable/enable, the other
+ preempt_disable/enable are downgraded to barriers [6].
+ The deadlock noted for non-RT above is resolved due to rt_mutexes
+ boosting the lock-holder in this case which arch_spin_locks do
+ not do.
+
+lglocks were designed for very specific problems in the VFS and probably
+only are the right answer in these corner cases. Any new user that looks
+at lglocks probably wants to look at the seqlock and RCU alternatives as
+her first choice. There are also efforts to resolve the RCU issues that
+currently prevent using RCU in place of view remaining lglocks.
+
+Note on brlock history:
+-----------------------
+
+The 'Big Reader' read-write spinlocks were originally introduced by
+Ingo Molnar in 2000 (2.4/2.5 kernel series) and removed in 2003. They
+later were introduced by the VFS scalability patch set in 2.6 series
+again as the "big reader lock" brlock [2] variant of lglock which has
+been replaced by seqlock primitives or by RCU based primitives in the
+3.13 kernel series as was suggested in [3] in 2003. The brlock was
+entirely removed in the 3.13 kernel series.
+
+Link: 1 http://lkml.org/lkml/2010/8/2/81
+Link: 2 http://lwn.net/Articles/401738/
+Link: 3 http://lkml.org/lkml/2003/3/9/205
+Link: 4 https://lkml.org/lkml/2011/8/24/185
+Link: 5 http://lkml.org/lkml/2011/12/18/189
+Link: 6 https://www.kernel.org/pub/linux/kernel/projects/rt/
+ patch series - lglocks-rt.patch.patch
+Link: 7 http://lkml.org/lkml/2012/3/5/26
diff --git a/Documentation/memory-barriers.txt b/Documentation/memory-barriers.txt
index 22a969c..7ee2ae6 100644
--- a/Documentation/memory-barriers.txt
+++ b/Documentation/memory-barriers.txt
@@ -121,22 +121,22 @@ For example, consider the following sequence of events:
The set of accesses as seen by the memory system in the middle can be arranged
in 24 different combinations:
- STORE A=3, STORE B=4, x=LOAD A->3, y=LOAD B->4
- STORE A=3, STORE B=4, y=LOAD B->4, x=LOAD A->3
- STORE A=3, x=LOAD A->3, STORE B=4, y=LOAD B->4
- STORE A=3, x=LOAD A->3, y=LOAD B->2, STORE B=4
- STORE A=3, y=LOAD B->2, STORE B=4, x=LOAD A->3
- STORE A=3, y=LOAD B->2, x=LOAD A->3, STORE B=4
- STORE B=4, STORE A=3, x=LOAD A->3, y=LOAD B->4
+ STORE A=3, STORE B=4, y=LOAD A->3, x=LOAD B->4
+ STORE A=3, STORE B=4, x=LOAD B->4, y=LOAD A->3
+ STORE A=3, y=LOAD A->3, STORE B=4, x=LOAD B->4
+ STORE A=3, y=LOAD A->3, x=LOAD B->2, STORE B=4
+ STORE A=3, x=LOAD B->2, STORE B=4, y=LOAD A->3
+ STORE A=3, x=LOAD B->2, y=LOAD A->3, STORE B=4
+ STORE B=4, STORE A=3, y=LOAD A->3, x=LOAD B->4
STORE B=4, ...
...
and can thus result in four different combinations of values:
- x == 1, y == 2
- x == 1, y == 4
- x == 3, y == 2
- x == 3, y == 4
+ x == 2, y == 1
+ x == 2, y == 3
+ x == 4, y == 1
+ x == 4, y == 3
Furthermore, the stores committed by a CPU to the memory system may not be
@@ -694,6 +694,24 @@ Please note once again that the stores to 'b' differ. If they were
identical, as noted earlier, the compiler could pull this store outside
of the 'if' statement.
+You must also be careful not to rely too much on boolean short-circuit
+evaluation. Consider this example:
+
+ q = ACCESS_ONCE(a);
+ if (a || 1 > 0)
+ ACCESS_ONCE(b) = 1;
+
+Because the second condition is always true, the compiler can transform
+this example as following, defeating control dependency:
+
+ q = ACCESS_ONCE(a);
+ ACCESS_ONCE(b) = 1;
+
+This example underscores the need to ensure that the compiler cannot
+out-guess your code. More generally, although ACCESS_ONCE() does force
+the compiler to actually emit code for a given load, it does not force
+the compiler to use the results.
+
Finally, control dependencies do -not- provide transitivity. This is
demonstrated by two related examples, with the initial values of
x and y both being zero:
@@ -2465,10 +2483,15 @@ functions:
Please refer to the PCI specification for more information on interactions
between PCI transactions.
- (*) readX_relaxed()
+ (*) readX_relaxed(), writeX_relaxed()
- These are similar to readX(), but are not guaranteed to be ordered in any
- way. Be aware that there is no I/O read barrier available.
+ These are similar to readX() and writeX(), but provide weaker memory
+ ordering guarantees. Specifically, they do not guarantee ordering with
+ respect to normal memory accesses (e.g. DMA buffers) nor do they guarantee
+ ordering with respect to LOCK or UNLOCK operations. If the latter is
+ required, an mmiowb() barrier can be used. Note that relaxed accesses to
+ the same peripheral are guaranteed to be ordered with respect to each
+ other.
(*) ioreadX(), iowriteX()
diff --git a/Documentation/nios2/README b/Documentation/nios2/README
new file mode 100644
index 0000000..054a67d
--- /dev/null
+++ b/Documentation/nios2/README
@@ -0,0 +1,23 @@
+Linux on the Nios II architecture
+=================================
+
+This is a port of Linux to Nios II (nios2) processor.
+
+In order to compile for Nios II, you need a version of GCC with support for the generic
+system call ABI. Please see this link for more information on how compiling and booting
+software for the Nios II platform:
+http://www.rocketboards.org/foswiki/Documentation/NiosIILinuxUserManual
+
+For reference, please see the following link:
+http://www.altera.com/literature/lit-nio2.jsp
+
+What is Nios II?
+================
+Nios II is a 32-bit embedded-processor architecture designed specifically for the
+Altera family of FPGAs. In order to support Linux, Nios II needs to be configured
+with MMU and hardware multiplier enabled.
+
+Nios II ABI
+===========
+Please refer to chapter "Application Binary Interface" in Nios II Processor Reference
+Handbook.
diff --git a/Documentation/scsi/libsas.txt b/Documentation/scsi/libsas.txt
index 3cc9c78..8cac649 100644
--- a/Documentation/scsi/libsas.txt
+++ b/Documentation/scsi/libsas.txt
@@ -226,9 +226,6 @@ static int register_sas_ha(struct my_sas_ha *my_ha)
my_ha->sas_ha.lldd_dev_found = my_dev_found;
my_ha->sas_ha.lldd_dev_gone = my_dev_gone;
- my_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num; (1)
-
- my_ha->sas_ha.lldd_queue_size = ha_can_queue;
my_ha->sas_ha.lldd_execute_task = my_execute_task;
my_ha->sas_ha.lldd_abort_task = my_abort_task;
@@ -247,28 +244,6 @@ static int register_sas_ha(struct my_sas_ha *my_ha)
return sas_register_ha(&my_ha->sas_ha);
}
-(1) This is normally a LLDD parameter, something of the
-lines of a task collector. What it tells the SAS Layer is
-whether the SAS layer should run in Direct Mode (default:
-value 0 or 1) or Task Collector Mode (value greater than 1).
-
-In Direct Mode, the SAS Layer calls Execute Task as soon as
-it has a command to send to the SDS, _and_ this is a single
-command, i.e. not linked.
-
-Some hardware (e.g. aic94xx) has the capability to DMA more
-than one task at a time (interrupt) from host memory. Task
-Collector Mode is an optional feature for HAs which support
-this in their hardware. (Again, it is completely optional
-even if your hardware supports it.)
-
-In Task Collector Mode, the SAS Layer would do _natural_
-coalescing of tasks and at the appropriate moment it would
-call your driver to DMA more than one task in a single HA
-interrupt. DMBS may want to use this by insmod/modprobe
-setting the lldd_max_execute_num to something greater than
-1.
-
(2) SAS 1.1 does not define I_T Nexus Reset TMF.
Events
@@ -325,71 +300,22 @@ PHYE_SPINUP_HOLD -- SATA is present, COMWAKE not sent.
The Execute Command SCSI RPC:
- int (*lldd_execute_task)(struct sas_task *, int num,
- unsigned long gfp_flags);
+ int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags);
-Used to queue a task to the SAS LLDD. @task is the tasks to
-be executed. @num should be the number of tasks being
-queued at this function call (they are linked listed via
-task::list), @gfp_mask should be the gfp_mask defining the
-context of the caller.
+Used to queue a task to the SAS LLDD. @task is the task to be executed.
+@gfp_mask is the gfp_mask defining the context of the caller.
This function should implement the Execute Command SCSI RPC,
-or if you're sending a SCSI Task as linked commands, you
-should also use this function.
-That is, when lldd_execute_task() is called, the command(s)
+That is, when lldd_execute_task() is called, the command
go out on the transport *immediately*. There is *no*
queuing of any sort and at any level in a SAS LLDD.
-The use of task::list is two-fold, one for linked commands,
-the other discussed below.
-
-It is possible to queue up more than one task at a time, by
-initializing the list element of struct sas_task, and
-passing the number of tasks enlisted in this manner in num.
-
Returns: -SAS_QUEUE_FULL, -ENOMEM, nothing was queued;
0, the task(s) were queued.
-If you want to pass num > 1, then either
-A) you're the only caller of this function and keep track
- of what you've queued to the LLDD, or
-B) you know what you're doing and have a strategy of
- retrying.
-
-As opposed to queuing one task at a time (function call),
-batch queuing of tasks, by having num > 1, greatly
-simplifies LLDD code, sequencer code, and _hardware design_,
-and has some performance advantages in certain situations
-(DBMS).
-
-The LLDD advertises if it can take more than one command at
-a time at lldd_execute_task(), by setting the
-lldd_max_execute_num parameter (controlled by "collector"
-module parameter in aic94xx SAS LLDD).
-
-You should leave this to the default 1, unless you know what
-you're doing.
-
-This is a function of the LLDD, to which the SAS layer can
-cater to.
-
-int lldd_queue_size
- The host adapter's queue size. This is the maximum
-number of commands the lldd can have pending to domain
-devices on behalf of all upper layers submitting through
-lldd_execute_task().
-
-You really want to set this to something (much) larger than
-1.
-
-This _really_ has absolutely nothing to do with queuing.
-There is no queuing in SAS LLDDs.
-
struct sas_task {
dev -- the device this task is destined to
- list -- must be initialized (INIT_LIST_HEAD)
task_proto -- _one_ of enum sas_proto
scatter -- pointer to scatter gather list array
num_scatter -- number of elements in scatter
diff --git a/Documentation/scsi/scsi_mid_low_api.txt b/Documentation/scsi/scsi_mid_low_api.txt
index d6a9bde..731bc4f 100644
--- a/Documentation/scsi/scsi_mid_low_api.txt
+++ b/Documentation/scsi/scsi_mid_low_api.txt
@@ -149,7 +149,7 @@ scsi_add_host() ---->
scsi_scan_host() -------+
|
slave_alloc()
- slave_configure() --> scsi_adjust_queue_depth()
+ slave_configure() --> scsi_change_queue_depth()
|
slave_alloc()
slave_configure()
@@ -159,7 +159,7 @@ scsi_scan_host() -------+
------------------------------------------------------------
If the LLD wants to adjust the default queue settings, it can invoke
-scsi_adjust_queue_depth() in its slave_configure() routine.
+scsi_change_queue_depth() in its slave_configure() routine.
*** For scsi devices that the mid level tries to scan but do not
respond, a slave_alloc(), slave_destroy() pair is called.
@@ -203,7 +203,7 @@ LLD mid level LLD
scsi_add_device() ------+
|
slave_alloc()
- slave_configure() [--> scsi_adjust_queue_depth()]
+ slave_configure() [--> scsi_change_queue_depth()]
------------------------------------------------------------
In a similar fashion, an LLD may become aware that a SCSI device has been
@@ -261,7 +261,7 @@ init_this_scsi_driver() ----+
| scsi_register()
|
slave_alloc()
- slave_configure() --> scsi_adjust_queue_depth()
+ slave_configure() --> scsi_change_queue_depth()
slave_alloc() ***
slave_destroy() ***
|
@@ -271,9 +271,9 @@ init_this_scsi_driver() ----+
slave_destroy() ***
------------------------------------------------------------
-The mid level invokes scsi_adjust_queue_depth() with tagged queuing off and
-"cmd_per_lun" for that host as the queue length. These settings can be
-overridden by a slave_configure() supplied by the LLD.
+The mid level invokes scsi_change_queue_depth() with "cmd_per_lun" for that
+host as the queue length. These settings can be overridden by a
+slave_configure() supplied by the LLD.
*** For scsi devices that the mid level tries to scan but do not
respond, a slave_alloc(), slave_destroy() pair is called.
@@ -366,13 +366,11 @@ is initialized. The functions below are listed alphabetically and their
names all start with "scsi_".
Summary:
- scsi_activate_tcq - turn on tag command queueing
scsi_add_device - creates new scsi device (lu) instance
scsi_add_host - perform sysfs registration and set up transport class
- scsi_adjust_queue_depth - change the queue depth on a SCSI device
+ scsi_change_queue_depth - change the queue depth on a SCSI device
scsi_bios_ptable - return copy of block device's partition table
scsi_block_requests - prevent further commands being queued to given host
- scsi_deactivate_tcq - turn off tag command queueing
scsi_host_alloc - return a new scsi_host instance whose refcount==1
scsi_host_get - increments Scsi_Host instance's refcount
scsi_host_put - decrements Scsi_Host instance's refcount (free if 0)
@@ -390,24 +388,6 @@ Summary:
Details:
/**
- * scsi_activate_tcq - turn on tag command queueing ("ordered" task attribute)
- * @sdev: device to turn on TCQ for
- * @depth: queue depth
- *
- * Returns nothing
- *
- * Might block: no
- *
- * Notes: Eventually, it is hoped depth would be the maximum depth
- * the device could cope with and the real queue depth
- * would be adjustable from 0 to depth.
- *
- * Defined (inline) in: include/scsi/scsi_tcq.h
- **/
-void scsi_activate_tcq(struct scsi_device *sdev, int depth)
-
-
-/**
* scsi_add_device - creates new scsi device (lu) instance
* @shost: pointer to scsi host instance
* @channel: channel number (rarely other than 0)
@@ -456,11 +436,8 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev)
/**
- * scsi_adjust_queue_depth - allow LLD to change queue depth on a SCSI device
+ * scsi_change_queue_depth - allow LLD to change queue depth on a SCSI device
* @sdev: pointer to SCSI device to change queue depth on
- * @tagged: 0 - no tagged queuing
- * MSG_SIMPLE_TAG - simple tagged queuing
- * MSG_ORDERED_TAG - ordered tagged queuing
* @tags Number of tags allowed if tagged queuing enabled,
* or number of commands the LLD can queue up
* in non-tagged mode (as per cmd_per_lun).
@@ -471,15 +448,12 @@ int scsi_add_host(struct Scsi_Host *shost, struct device * dev)
*
* Notes: Can be invoked any time on a SCSI device controlled by this
* LLD. [Specifically during and after slave_configure() and prior to
- * slave_destroy().] Can safely be invoked from interrupt code. Actual
- * queue depth change may be delayed until the next command is being
- * processed. See also scsi_activate_tcq() and scsi_deactivate_tcq().
+ * slave_destroy().] Can safely be invoked from interrupt code.
*
* Defined in: drivers/scsi/scsi.c [see source code for more notes]
*
**/
-void scsi_adjust_queue_depth(struct scsi_device * sdev, int tagged,
- int tags)
+int scsi_change_queue_depth(struct scsi_device *sdev, int tags)
/**
@@ -515,20 +489,6 @@ void scsi_block_requests(struct Scsi_Host * shost)
/**
- * scsi_deactivate_tcq - turn off tag command queueing
- * @sdev: device to turn off TCQ for
- * @depth: queue depth (stored in sdev)
- *
- * Returns nothing
- *
- * Might block: no
- *
- * Defined (inline) in: include/scsi/scsi_tcq.h
- **/
-void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
-
-
-/**
* scsi_host_alloc - create a scsi host adapter instance and perform basic
* initialization.
* @sht: pointer to scsi host template
@@ -1254,7 +1214,7 @@ of interest:
for disk firmware uploads.
cmd_per_lun - maximum number of commands that can be queued on devices
controlled by the host. Overridden by LLD calls to
- scsi_adjust_queue_depth().
+ scsi_change_queue_depth().
unchecked_isa_dma - 1=>only use bottom 16 MB of ram (ISA DMA addressing
restriction), 0=>can use full 32 bit (or better) DMA
address space
@@ -1294,7 +1254,7 @@ struct scsi_cmnd
Instances of this structure convey SCSI commands to the LLD and responses
back to the mid level. The SCSI mid level will ensure that no more SCSI
commands become queued against the LLD than are indicated by
-scsi_adjust_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will
+scsi_change_queue_depth() (or struct Scsi_Host::cmd_per_lun). There will
be at least one instance of struct scsi_cmnd available for each SCSI device.
Members of interest:
cmnd - array containing SCSI command
diff --git a/Documentation/scsi/st.txt b/Documentation/scsi/st.txt
index f346abb..0d5bdb1 100644
--- a/Documentation/scsi/st.txt
+++ b/Documentation/scsi/st.txt
@@ -506,9 +506,11 @@ user does not request data that far.)
DEBUGGING HINTS
-To enable debugging messages, edit st.c and #define DEBUG 1. As seen
-above, debugging can be switched off with an ioctl if debugging is
-compiled into the driver. The debugging output is not voluminous.
+Debugging code is now compiled in by default but debugging is turned off
+with the kernel module parameter debug_flag defaulting to 0. Debugging
+can still be switched on and off with an ioctl. To enable debug at
+module load time add debug_flag=1 to the module load options, the
+debugging output is not voluminous.
If the tape seems to hang, I would be very interested to hear where
the driver is waiting. With the command 'ps -l' you can see the state
diff --git a/Documentation/scsi/wd719x.txt b/Documentation/scsi/wd719x.txt
new file mode 100644
index 0000000..0816b02
--- /dev/null
+++ b/Documentation/scsi/wd719x.txt
@@ -0,0 +1,21 @@
+Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards
+---------------------------------------------------------------
+
+The card requires firmware that can be cut out of the Windows NT driver that
+can be downloaded from WD at:
+http://support.wdc.com/product/download.asp?groupid=801&sid=27&lang=en
+
+There is no license anywhere in the file or on the page - so the firmware
+probably cannot be added to linux-firmware.
+
+This script downloads and extracts the firmware, creating wd719x-risc.bin and
+d719x-wcs.bin files. Put them in /lib/firmware/.
+
+#!/bin/sh
+wget http://support.wdc.com/download/archive/pciscsi.exe
+lha xi pciscsi.exe pci-scsi.exe
+lha xi pci-scsi.exe nt/wd7296a.sys
+rm pci-scsi.exe
+dd if=wd7296a.sys of=wd719x-risc.bin bs=1 skip=5760 count=14336
+dd if=wd7296a.sys of=wd719x-wcs.bin bs=1 skip=20096 count=514
+rm wd7296a.sys
diff --git a/Documentation/sound/alsa/ControlNames.txt b/Documentation/sound/alsa/ControlNames.txt
index fea65bb..79a6127 100644
--- a/Documentation/sound/alsa/ControlNames.txt
+++ b/Documentation/sound/alsa/ControlNames.txt
@@ -1,6 +1,6 @@
This document describes standard names of mixer controls.
-Syntax: SOURCE [DIRECTION] FUNCTION
+Syntax: [LOCATION] SOURCE [CHANNEL] [DIRECTION] FUNCTION
DIRECTION:
<nothing> (both directions)
@@ -14,12 +14,29 @@ FUNCTION:
Volume
Route (route control, hardware specific)
+CHANNEL:
+ <nothing> (channel independent, or applies to all channels)
+ Front
+ Surround (rear left/right in 4.0/5.1 surround)
+ CLFE
+ Center
+ LFE
+ Side (side left/right for 7.1 surround)
+
+LOCATION: (physical location of source)
+ Front
+ Rear
+ Dock (docking station)
+ Internal
+
SOURCE:
Master
Master Mono
Hardware Master
Speaker (internal speaker)
+ Bass Speaker (internal LFE speaker)
Headphone
+ Line Out
Beep (beep generator)
Phone
Phone Input
@@ -27,14 +44,14 @@ SOURCE:
Synth
FM
Mic
- Line
+ Headset Mic (mic part of combined headset jack - 4-pin headphone + mic)
+ Headphone Mic (mic part of either/or - 3-pin headphone or mic)
+ Line (input only, use "Line Out" for output)
CD
Video
Zoom Video
Aux
PCM
- PCM Front
- PCM Rear
PCM Pan
Loopback
Analog Loopback (D/A -> A/D loopback)
@@ -47,8 +64,13 @@ SOURCE:
Music
I2S
IEC958
+ HDMI
+ SPDIF (output only)
+ SPDIF In
+ Digital In
+ HDMI/DP (either HDMI or DisplayPort)
-Exceptions:
+Exceptions (deprecated):
[Digital] Capture Source
[Digital] Capture Switch (aka input gain switch)
[Digital] Capture Volume (aka input gain volume)
diff --git a/Documentation/sound/alsa/HD-Audio-Models.txt b/Documentation/sound/alsa/HD-Audio-Models.txt
index a5e7547..5a3163c 100644
--- a/Documentation/sound/alsa/HD-Audio-Models.txt
+++ b/Documentation/sound/alsa/HD-Audio-Models.txt
@@ -113,14 +113,10 @@ AD1984
AD1986A
=======
- 6stack 6-jack, separate surrounds (default)
3stack 3-stack, shared surrounds
laptop 2-channel only (FSC V2060, Samsung M50)
- laptop-eapd 2-channel with EAPD (ASUS A6J)
- laptop-automute 2-channel with EAPD and HP-automute (Lenovo N100)
- ultra 2-channel with EAPD (Samsung Ultra tablet PC)
- samsung 2-channel with EAPD (Samsung R65)
- samsung-p50 2-channel with HP-automute (Samsung P50)
+ laptop-imic 2-channel with built-in mic
+ eapd Turn on EAPD constantly
AD1988/AD1988B/AD1989A/AD1989B
==============================
diff --git a/Documentation/sound/alsa/Procfile.txt b/Documentation/sound/alsa/Procfile.txt
index 7fcd1ad..7f8a0d3 100644
--- a/Documentation/sound/alsa/Procfile.txt
+++ b/Documentation/sound/alsa/Procfile.txt
@@ -101,10 +101,6 @@ card*/pcm*/xrun_debug
bit 0 = Enable XRUN/jiffies debug messages
bit 1 = Show stack trace at XRUN / jiffies check
bit 2 = Enable additional jiffies check
- bit 3 = Log hwptr update at each period interrupt
- bit 4 = Log hwptr update at each snd_pcm_update_hw_ptr()
- bit 5 = Show last 10 positions on error
- bit 6 = Do above only once
When the bit 0 is set, the driver will show the messages to
kernel log when an xrun is detected. The debug message is
@@ -121,15 +117,6 @@ card*/pcm*/xrun_debug
buggy) hardware that doesn't give smooth pointer updates.
This feature is enabled via the bit 2.
- Bits 3 and 4 are for logging the hwptr records. Note that
- these will give flood of kernel messages.
-
- When bit 5 is set, the driver logs the last 10 xrun errors and
- the proc file shows each jiffies, position, period_size,
- buffer_size, old_hw_ptr, and hw_ptr_base values.
-
- When bit 6 is set, the full xrun log is shown only once.
-
card*/pcm*/sub*/info
The general information of this PCM sub-stream.
@@ -146,6 +133,10 @@ card*/pcm*/sub*/sw_params
card*/pcm*/sub*/prealloc
The buffer pre-allocation information.
+card*/pcm*/sub*/xrun_injection
+ Triggers an XRUN to the running stream when any value is
+ written to this proc file. Used for fault injection.
+ This entry is write-only.
AC97 Codec Information
----------------------
diff --git a/Documentation/sysctl/kernel.txt b/Documentation/sysctl/kernel.txt
index 57baff5..b5d0c85 100644
--- a/Documentation/sysctl/kernel.txt
+++ b/Documentation/sysctl/kernel.txt
@@ -54,8 +54,9 @@ show up in /proc/sys/kernel:
- overflowuid
- panic
- panic_on_oops
-- panic_on_unrecovered_nmi
- panic_on_stackoverflow
+- panic_on_unrecovered_nmi
+- panic_on_warn
- pid_max
- powersave-nap [ PPC only ]
- printk
@@ -527,19 +528,6 @@ the recommended setting is 60.
==============================================================
-panic_on_unrecovered_nmi:
-
-The default Linux behaviour on an NMI of either memory or unknown is
-to continue operation. For many environments such as scientific
-computing it is preferable that the box is taken out and the error
-dealt with than an uncorrected parity/ECC error get propagated.
-
-A small number of systems do generate NMI's for bizarre random reasons
-such as power management so the default is off. That sysctl works like
-the existing panic controls already in that directory.
-
-==============================================================
-
panic_on_oops:
Controls the kernel's behaviour when an oops or BUG is encountered.
@@ -563,6 +551,30 @@ This file shows up if CONFIG_DEBUG_STACKOVERFLOW is enabled.
==============================================================
+panic_on_unrecovered_nmi:
+
+The default Linux behaviour on an NMI of either memory or unknown is
+to continue operation. For many environments such as scientific
+computing it is preferable that the box is taken out and the error
+dealt with than an uncorrected parity/ECC error get propagated.
+
+A small number of systems do generate NMI's for bizarre random reasons
+such as power management so the default is off. That sysctl works like
+the existing panic controls already in that directory.
+
+==============================================================
+
+panic_on_warn:
+
+Calls panic() in the WARN() path when set to 1. This is useful to avoid
+a kernel rebuild when attempting to kdump at the location of a WARN().
+
+0: only WARN(), default behaviour.
+
+1: call panic() after printing out WARN() location.
+
+==============================================================
+
perf_cpu_time_max_percent:
Hints to the kernel how much CPU time it should be allowed to
diff --git a/Documentation/trace/ftrace.txt b/Documentation/trace/ftrace.txt
index 4da4261..8408e04 100644
--- a/Documentation/trace/ftrace.txt
+++ b/Documentation/trace/ftrace.txt
@@ -234,6 +234,11 @@ of ftrace. Here is a list of some of the key files:
will be displayed on the same line as the function that
is returning registers.
+ If the callback registered to be traced by a function with
+ the "ip modify" attribute (thus the regs->ip can be changed),
+ an 'I' will be displayed on the same line as the function that
+ can be overridden.
+
function_profile_enabled:
When set it will enable all functions with either the function
@@ -680,9 +685,11 @@ The above is mostly meaningful for kernel developers.
needs to be fixed to be only relative to the same CPU.
The marks are determined by the difference between this
current trace and the next trace.
- '!' - greater than preempt_mark_thresh (default 100)
- '+' - greater than 1 microsecond
- ' ' - less than or equal to 1 microsecond.
+ '$' - greater than 1 second
+ '#' - greater than 1000 microsecond
+ '!' - greater than 100 microsecond
+ '+' - greater than 10 microsecond
+ ' ' - less than or equal to 10 microsecond.
The rest is the same as the 'trace' file.
@@ -1951,6 +1958,8 @@ want, depending on your needs.
+ means that the function exceeded 10 usecs.
! means that the function exceeded 100 usecs.
+ # means that the function exceeded 1000 usecs.
+ $ means that the function exceeded 1 sec.
- The task/pid field displays the thread cmdline and pid which
diff --git a/Documentation/usb/power-management.txt b/Documentation/usb/power-management.txt
index 7b90fe0..b5f8391 100644
--- a/Documentation/usb/power-management.txt
+++ b/Documentation/usb/power-management.txt
@@ -47,14 +47,15 @@ dynamic PM is implemented in the USB subsystem, although system PM is
covered to some extent (see Documentation/power/*.txt for more
information about system PM).
-Note: Dynamic PM support for USB is present only if the kernel was
-built with CONFIG_USB_SUSPEND enabled (which depends on
-CONFIG_PM_RUNTIME). System PM support is present only if the kernel
-was built with CONFIG_SUSPEND or CONFIG_HIBERNATION enabled.
-
-(Starting with the 3.10 kernel release, dynamic PM support for USB is
-present whenever the kernel was built with CONFIG_PM_RUNTIME enabled.
-The CONFIG_USB_SUSPEND option has been eliminated.)
+System PM support is present only if the kernel was built with CONFIG_SUSPEND
+or CONFIG_HIBERNATION enabled. Dynamic PM support for USB is present whenever
+the kernel was built with CONFIG_PM enabled.
+
+[Historically, dynamic PM support for USB was present only if the
+kernel had been built with CONFIG_USB_SUSPEND enabled (which depended on
+CONFIG_PM_RUNTIME). Starting with the 3.10 kernel release, dynamic PM support
+for USB was present whenever the kernel was built with CONFIG_PM_RUNTIME
+enabled. The CONFIG_USB_SUSPEND option had been eliminated.]
What is Remote Wakeup?
diff --git a/Documentation/video4linux/CARDLIST.cx23885 b/Documentation/video4linux/CARDLIST.cx23885
index a74eecc..4c84ec8 100644
--- a/Documentation/video4linux/CARDLIST.cx23885
+++ b/Documentation/video4linux/CARDLIST.cx23885
@@ -43,3 +43,5 @@
42 -> Leadtek Winfast PxPVR2200 [107d:6f21]
43 -> Hauppauge ImpactVCB-e [0070:7133]
44 -> DViCO FusionHDTV DVB-T Dual Express2 [18ac:db98]
+ 45 -> DVBSky T9580 [4254:9580]
+ 46 -> DVBSky T980C [4254:980c]
diff --git a/Documentation/video4linux/CARDLIST.em28xx b/Documentation/video4linux/CARDLIST.em28xx
index bc3351b..3700edb 100644
--- a/Documentation/video4linux/CARDLIST.em28xx
+++ b/Documentation/video4linux/CARDLIST.em28xx
@@ -93,3 +93,4 @@
92 -> PCTV DVB-S2 Stick (461e) (em28178)
93 -> KWorld USB ATSC TV Stick UB435-Q V3 (em2874) [1b80:e34c]
94 -> PCTV tripleStick (292e) (em28178)
+ 95 -> Leadtek VC100 (em2861) [0413:6f07]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 8df17d0..a93d864 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -191,3 +191,4 @@
190 -> Asus My Cinema PS3-100 [1043:48cd]
191 -> Hawell HW-9004V1
192 -> AverMedia AverTV Satellite Hybrid+FM A706 [1461:2055]
+193 -> WIS Voyager or compatible [1905:7007]
diff --git a/Documentation/video4linux/soc-camera.txt b/Documentation/video4linux/soc-camera.txt
index daa9e2a..84f41cf 100644
--- a/Documentation/video4linux/soc-camera.txt
+++ b/Documentation/video4linux/soc-camera.txt
@@ -151,7 +151,7 @@ they are transferred over a media bus. Soc-camera provides support to
conveniently manage these formats. A table of standard transformations is
maintained by soc-camera core, which describes, what FOURCC pixel format will
be obtained, if a media-bus pixel format is stored in memory according to
-certain rules. E.g. if V4L2_MBUS_FMT_YUYV8_2X8 data is sampled with 8 bits per
+certain rules. E.g. if MEDIA_BUS_FMT_YUYV8_2X8 data is sampled with 8 bits per
sample and stored in memory in the little-endian order with no gaps between
bytes, data in memory will represent the V4L2_PIX_FMT_YUYV FOURCC format. These
standard transformations will be used by soc-camera or by camera host drivers to
diff --git a/Documentation/x86/intel_mpx.txt b/Documentation/x86/intel_mpx.txt
new file mode 100644
index 0000000..4472ed2
--- /dev/null
+++ b/Documentation/x86/intel_mpx.txt
@@ -0,0 +1,234 @@
+1. Intel(R) MPX Overview
+========================
+
+Intel(R) Memory Protection Extensions (Intel(R) MPX) is a new capability
+introduced into Intel Architecture. Intel MPX provides hardware features
+that can be used in conjunction with compiler changes to check memory
+references, for those references whose compile-time normal intentions are
+usurped at runtime due to buffer overflow or underflow.
+
+For more information, please refer to Intel(R) Architecture Instruction
+Set Extensions Programming Reference, Chapter 9: Intel(R) Memory Protection
+Extensions.
+
+Note: Currently no hardware with MPX ISA is available but it is always
+possible to use SDE (Intel(R) Software Development Emulator) instead, which
+can be downloaded from
+http://software.intel.com/en-us/articles/intel-software-development-emulator
+
+
+2. How to get the advantage of MPX
+==================================
+
+For MPX to work, changes are required in the kernel, binutils and compiler.
+No source changes are required for applications, just a recompile.
+
+There are a lot of moving parts of this to all work right. The following
+is how we expect the compiler, application and kernel to work together.
+
+1) Application developer compiles with -fmpx. The compiler will add the
+ instrumentation as well as some setup code called early after the app
+ starts. New instruction prefixes are noops for old CPUs.
+2) That setup code allocates (virtual) space for the "bounds directory",
+ points the "bndcfgu" register to the directory and notifies the kernel
+ (via the new prctl(PR_MPX_ENABLE_MANAGEMENT)) that the app will be using
+ MPX.
+3) The kernel detects that the CPU has MPX, allows the new prctl() to
+ succeed, and notes the location of the bounds directory. Userspace is
+ expected to keep the bounds directory at that locationWe note it
+ instead of reading it each time because the 'xsave' operation needed
+ to access the bounds directory register is an expensive operation.
+4) If the application needs to spill bounds out of the 4 registers, it
+ issues a bndstx instruction. Since the bounds directory is empty at
+ this point, a bounds fault (#BR) is raised, the kernel allocates a
+ bounds table (in the user address space) and makes the relevant entry
+ in the bounds directory point to the new table.
+5) If the application violates the bounds specified in the bounds registers,
+ a separate kind of #BR is raised which will deliver a signal with
+ information about the violation in the 'struct siginfo'.
+6) Whenever memory is freed, we know that it can no longer contain valid
+ pointers, and we attempt to free the associated space in the bounds
+ tables. If an entire table becomes unused, we will attempt to free
+ the table and remove the entry in the directory.
+
+To summarize, there are essentially three things interacting here:
+
+GCC with -fmpx:
+ * enables annotation of code with MPX instructions and prefixes
+ * inserts code early in the application to call in to the "gcc runtime"
+GCC MPX Runtime:
+ * Checks for hardware MPX support in cpuid leaf
+ * allocates virtual space for the bounds directory (malloc() essentially)
+ * points the hardware BNDCFGU register at the directory
+ * calls a new prctl(PR_MPX_ENABLE_MANAGEMENT) to notify the kernel to
+ start managing the bounds directories
+Kernel MPX Code:
+ * Checks for hardware MPX support in cpuid leaf
+ * Handles #BR exceptions and sends SIGSEGV to the app when it violates
+ bounds, like during a buffer overflow.
+ * When bounds are spilled in to an unallocated bounds table, the kernel
+ notices in the #BR exception, allocates the virtual space, then
+ updates the bounds directory to point to the new table. It keeps
+ special track of the memory with a VM_MPX flag.
+ * Frees unused bounds tables at the time that the memory they described
+ is unmapped.
+
+
+3. How does MPX kernel code work
+================================
+
+Handling #BR faults caused by MPX
+---------------------------------
+
+When MPX is enabled, there are 2 new situations that can generate
+#BR faults.
+ * new bounds tables (BT) need to be allocated to save bounds.
+ * bounds violation caused by MPX instructions.
+
+We hook #BR handler to handle these two new situations.
+
+On-demand kernel allocation of bounds tables
+--------------------------------------------
+
+MPX only has 4 hardware registers for storing bounds information. If
+MPX-enabled code needs more than these 4 registers, it needs to spill
+them somewhere. It has two special instructions for this which allow
+the bounds to be moved between the bounds registers and some new "bounds
+tables".
+
+#BR exceptions are a new class of exceptions just for MPX. They are
+similar conceptually to a page fault and will be raised by the MPX
+hardware during both bounds violations or when the tables are not
+present. The kernel handles those #BR exceptions for not-present tables
+by carving the space out of the normal processes address space and then
+pointing the bounds-directory over to it.
+
+The tables need to be accessed and controlled by userspace because
+the instructions for moving bounds in and out of them are extremely
+frequent. They potentially happen every time a register points to
+memory. Any direct kernel involvement (like a syscall) to access the
+tables would obviously destroy performance.
+
+Why not do this in userspace? MPX does not strictly require anything in
+the kernel. It can theoretically be done completely from userspace. Here
+are a few ways this could be done. We don't think any of them are practical
+in the real-world, but here they are.
+
+Q: Can virtual space simply be reserved for the bounds tables so that we
+ never have to allocate them?
+A: MPX-enabled application will possibly create a lot of bounds tables in
+ process address space to save bounds information. These tables can take
+ up huge swaths of memory (as much as 80% of the memory on the system)
+ even if we clean them up aggressively. In the worst-case scenario, the
+ tables can be 4x the size of the data structure being tracked. IOW, a
+ 1-page structure can require 4 bounds-table pages. An X-GB virtual
+ area needs 4*X GB of virtual space, plus 2GB for the bounds directory.
+ If we were to preallocate them for the 128TB of user virtual address
+ space, we would need to reserve 512TB+2GB, which is larger than the
+ entire virtual address space today. This means they can not be reserved
+ ahead of time. Also, a single process's pre-popualated bounds directory
+ consumes 2GB of virtual *AND* physical memory. IOW, it's completely
+ infeasible to prepopulate bounds directories.
+
+Q: Can we preallocate bounds table space at the same time memory is
+ allocated which might contain pointers that might eventually need
+ bounds tables?
+A: This would work if we could hook the site of each and every memory
+ allocation syscall. This can be done for small, constrained applications.
+ But, it isn't practical at a larger scale since a given app has no
+ way of controlling how all the parts of the app might allocate memory
+ (think libraries). The kernel is really the only place to intercept
+ these calls.
+
+Q: Could a bounds fault be handed to userspace and the tables allocated
+ there in a signal handler intead of in the kernel?
+A: mmap() is not on the list of safe async handler functions and even
+ if mmap() would work it still requires locking or nasty tricks to
+ keep track of the allocation state there.
+
+Having ruled out all of the userspace-only approaches for managing
+bounds tables that we could think of, we create them on demand in
+the kernel.
+
+Decoding MPX instructions
+-------------------------
+
+If a #BR is generated due to a bounds violation caused by MPX.
+We need to decode MPX instructions to get violation address and
+set this address into extended struct siginfo.
+
+The _sigfault feild of struct siginfo is extended as follow:
+
+87 /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */
+88 struct {
+89 void __user *_addr; /* faulting insn/memory ref. */
+90 #ifdef __ARCH_SI_TRAPNO
+91 int _trapno; /* TRAP # which caused the signal */
+92 #endif
+93 short _addr_lsb; /* LSB of the reported address */
+94 struct {
+95 void __user *_lower;
+96 void __user *_upper;
+97 } _addr_bnd;
+98 } _sigfault;
+
+The '_addr' field refers to violation address, and new '_addr_and'
+field refers to the upper/lower bounds when a #BR is caused.
+
+Glibc will be also updated to support this new siginfo. So user
+can get violation address and bounds when bounds violations occur.
+
+Cleanup unused bounds tables
+----------------------------
+
+When a BNDSTX instruction attempts to save bounds to a bounds directory
+entry marked as invalid, a #BR is generated. This is an indication that
+no bounds table exists for this entry. In this case the fault handler
+will allocate a new bounds table on demand.
+
+Since the kernel allocated those tables on-demand without userspace
+knowledge, it is also responsible for freeing them when the associated
+mappings go away.
+
+Here, the solution for this issue is to hook do_munmap() to check
+whether one process is MPX enabled. If yes, those bounds tables covered
+in the virtual address region which is being unmapped will be freed also.
+
+Adding new prctl commands
+-------------------------
+
+Two new prctl commands are added to enable and disable MPX bounds tables
+management in kernel.
+
+155 #define PR_MPX_ENABLE_MANAGEMENT 43
+156 #define PR_MPX_DISABLE_MANAGEMENT 44
+
+Runtime library in userspace is responsible for allocation of bounds
+directory. So kernel have to use XSAVE instruction to get the base
+of bounds directory from BNDCFG register.
+
+But XSAVE is expected to be very expensive. In order to do performance
+optimization, we have to get the base of bounds directory and save it
+into struct mm_struct to be used in future during PR_MPX_ENABLE_MANAGEMENT
+command execution.
+
+
+4. Special rules
+================
+
+1) If userspace is requesting help from the kernel to do the management
+of bounds tables, it may not create or modify entries in the bounds directory.
+
+Certainly users can allocate bounds tables and forcibly point the bounds
+directory at them through XSAVE instruction, and then set valid bit
+of bounds entry to have this entry valid. But, the kernel will decline
+to assist in managing these tables.
+
+2) Userspace may not take multiple bounds directory entries and point
+them at the same bounds table.
+
+This is allowed architecturally. See more information "Intel(R) Architecture
+Instruction Set Extensions Programming Reference" (9.3.4).
+
+However, if users did this, the kernel might be fooled in to unmaping an
+in-use bounds table since it does not recognize sharing.
diff --git a/MAINTAINERS b/MAINTAINERS
index cb3221d..34b4b84 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -850,6 +850,7 @@ ARM/Amlogic MesonX SoC support
M: Carlo Caione <carlo@caione.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
+F: drivers/media/rc/meson-ir.c
N: meson[x68]
ARM/ATMEL AT91RM9200 AND AT91SAM ARM ARCHITECTURES
@@ -861,6 +862,7 @@ W: http://maxim.org.za/at91_26.html
W: http://www.linux4sam.org
S: Supported
F: arch/arm/mach-at91/
+F: include/soc/at91/
F: arch/arm/boot/dts/at91*.dts
F: arch/arm/boot/dts/at91*.dtsi
F: arch/arm/boot/dts/sama*.dts
@@ -1308,30 +1310,22 @@ F: drivers/*/*rockchip*
F: drivers/*/*/*rockchip*
F: sound/soc/rockchip/
-ARM/SAMSUNG ARM ARCHITECTURES
-M: Ben Dooks <ben-linux@fluff.org>
-M: Kukjin Kim <kgene.kim@samsung.com>
+ARM/SAMSUNG EXYNOS ARM ARCHITECTURES
+M: Kukjin Kim <kgene@kernel.org>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
L: linux-samsung-soc@vger.kernel.org (moderated for non-subscribers)
-W: http://www.fluff.org/ben/linux/
S: Maintained
F: arch/arm/boot/dts/s3c*
F: arch/arm/boot/dts/exynos*
F: arch/arm/plat-samsung/
F: arch/arm/mach-s3c24*/
F: arch/arm/mach-s3c64xx/
+F: arch/arm/mach-s5p*/
+F: arch/arm/mach-exynos*/
F: drivers/*/*s3c2410*
F: drivers/*/*/*s3c2410*
F: drivers/spi/spi-s3c*
F: sound/soc/samsung/*
-
-ARM/S5P EXYNOS ARM ARCHITECTURES
-M: Kukjin Kim <kgene.kim@samsung.com>
-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: arch/arm/mach-s5p*/
-F: arch/arm/mach-exynos*/
N: exynos
ARM/SAMSUNG MOBILE MACHINE SUPPORT
@@ -1381,12 +1375,12 @@ F: arch/arm/boot/dts/sh*
F: arch/arm/configs/ape6evm_defconfig
F: arch/arm/configs/armadillo800eva_defconfig
F: arch/arm/configs/bockw_defconfig
-F: arch/arm/configs/koelsch_defconfig
F: arch/arm/configs/kzm9g_defconfig
F: arch/arm/configs/lager_defconfig
F: arch/arm/configs/mackerel_defconfig
F: arch/arm/configs/marzen_defconfig
F: arch/arm/configs/shmobile_defconfig
+F: arch/arm/include/debug/renesas-scif.S
F: arch/arm/mach-shmobile/
F: drivers/sh/
@@ -1430,6 +1424,7 @@ F: drivers/tty/serial/st-asc.c
F: drivers/usb/dwc3/dwc3-st.c
F: drivers/usb/host/ehci-st.c
F: drivers/usb/host/ohci-st.c
+F: drivers/ata/ahci_st.c
ARM/TECHNOLOGIC SYSTEMS TS7250 MACHINE SUPPORT
M: Lennert Buytenhek <kernel@wantstofly.org>
@@ -1503,6 +1498,19 @@ S: Maintained
F: drivers/clk/ux500/
F: include/linux/platform_data/clk-ux500.h
+ARM/VERSATILE EXPRESS PLATFORM
+M: Liviu Dudau <liviu.dudau@arm.com>
+M: Sudeep Holla <sudeep.holla@arm.com>
+M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+S: Maintained
+F: arch/arm/boot/dts/vexpress*
+F: arch/arm/mach-vexpress/
+F: */*/vexpress*
+F: */*/*/vexpress*
+F: drivers/clk/versatile/clk-vexpress-osc.c
+F: drivers/clocksource/versatile.c
+
ARM/VFP SUPPORT
M: Russell King <linux@arm.linux.org.uk>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
@@ -1828,7 +1836,7 @@ F: include/net/ax25.h
F: net/ax25/
AZ6007 DVB DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -1862,7 +1870,6 @@ F: drivers/net/wireless/b43legacy/
BACKLIGHT CLASS/SUBSYSTEM
M: Jingoo Han <jg1.han@samsung.com>
-M: Bryan Wu <cooloney@gmail.com>
M: Lee Jones <lee.jones@linaro.org>
S: Maintained
F: drivers/video/backlight/
@@ -2097,10 +2104,13 @@ F: arch/arm/include/debug/bcm63xx.S
BROADCOM BCM7XXX ARM ARCHITECTURE
M: Marc Carino <marc.ceeeee@gmail.com>
M: Brian Norris <computersforpeace@gmail.com>
+M: Gregory Fong <gregory.0xf0@gmail.com>
+M: Florian Fainelli <f.fainelli@gmail.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
F: arch/arm/mach-bcm/*brcmstb*
F: arch/arm/boot/dts/bcm7*.dts*
+F: drivers/bus/brcmstb_gisb.c
BROADCOM TG3 GIGABIT ETHERNET DRIVER
M: Prashant Sreedharan <prashant@broadcom.com>
@@ -2131,6 +2141,20 @@ L: linux-scsi@vger.kernel.org
S: Supported
F: drivers/scsi/bnx2i/
+BROADCOM CYGNUS/IPROC ARM ARCHITECTURE
+M: Ray Jui <rjui@broadcom.com>
+M: Scott Branden <sbranden@broadcom.com>
+L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
+L: bcm-kernel-feedback-list@broadcom.com
+T: git git://git.github.com/brcm/linux.git
+S: Maintained
+N: iproc
+N: cygnus
+N: bcm9113*
+N: bcm9583*
+N: bcm583*
+N: bcm113*
+
BROADCOM KONA GPIO DRIVER
M: Ray Jui <rjui@broadcom.com>
L: bcm-kernel-feedback-list@broadcom.com
@@ -2198,7 +2222,7 @@ F: Documentation/filesystems/btrfs.txt
F: fs/btrfs/
BTTV VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -2497,6 +2521,13 @@ F: fs/coda/
F: include/linux/coda*.h
F: include/uapi/linux/coda*.h
+CODA V4L2 MEM2MEM DRIVER
+M: Philipp Zabel <p.zabel@pengutronix.de>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/media/coda.txt
+F: drivers/media/platform/coda/
+
COMMON CLK FRAMEWORK
M: Mike Turquette <mturquette@linaro.org>
L: linux-kernel@vger.kernel.org
@@ -2512,8 +2543,7 @@ M: Steve French <sfrench@samba.org>
L: linux-cifs@vger.kernel.org
L: samba-technical@lists.samba.org (moderated for non-subscribers)
W: http://linux-cifs.samba.org/
-Q: http://patchwork.ozlabs.org/project/linux-cifs-client/list/
-T: git git://git.kernel.org/pub/scm/linux/kernel/git/sfrench/cifs-2.6.git
+T: git git://git.samba.org/sfrench/cifs-2.6.git
S: Supported
F: Documentation/filesystems/cifs/
F: fs/cifs/
@@ -2590,7 +2620,7 @@ L: cgroups@vger.kernel.org
L: linux-mm@kvack.org
S: Maintained
F: mm/memcontrol.c
-F: mm/page_cgroup.c
+F: mm/swap_cgroup.c
CORETEMP HARDWARE MONITORING DRIVER
M: Fenghua Yu <fenghua.yu@intel.com>
@@ -2640,6 +2670,16 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm.git
S: Maintained
F: drivers/cpuidle/cpuidle-big_little.c
+CPUIDLE DRIVER - ARM EXYNOS
+M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>
+M: Daniel Lezcano <daniel.lezcano@linaro.org>
+M: Kukjin Kim <kgene@kernel.org>
+L: linux-pm@vger.kernel.org
+L: linux-samsung-soc@vger.kernel.org
+S: Supported
+F: drivers/cpuidle/cpuidle-exynos.c
+F: arch/arm/mach-exynos/pm.c
+
CPUIDLE DRIVERS
M: Rafael J. Wysocki <rjw@rjwysocki.net>
M: Daniel Lezcano <daniel.lezcano@linaro.org>
@@ -2707,7 +2747,7 @@ F: drivers/net/wireless/cw1200/
CX18 VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
-L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
+L: ivtv-devel@ivtvdriver.org (subscribers-only)
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://linuxtv.org
@@ -2727,7 +2767,7 @@ F: drivers/media/common/cx2341x*
F: include/media/cx2341x*
CX88 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -2870,11 +2910,10 @@ F: Documentation/networking/dmfe.txt
F: drivers/net/ethernet/dec/tulip/dmfe.c
DC390/AM53C974 SCSI driver
-M: Kurt Garloff <garloff@suse.de>
-W: http://www.garloff.de/kurt/linux/dc390/
-M: Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+M: Hannes Reinecke <hare@suse.de>
+L: linux-scsi@vger.kernel.org
S: Maintained
-F: drivers/scsi/tmscsim.*
+F: drivers/scsi/am53c974.c
DC395x SCSI driver
M: Oliver Neukum <oliver@neukum.org>
@@ -3410,7 +3449,7 @@ F: fs/ecryptfs/
EDAC-CORE
M: Doug Thompson <dougthompson@xmission.com>
M: Borislav Petkov <bp@alien8.de>
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Supported
@@ -3459,7 +3498,7 @@ S: Maintained
F: drivers/edac/e7xxx_edac.c
EDAC-GHES
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
@@ -3487,21 +3526,21 @@ S: Maintained
F: drivers/edac/i5000_edac.c
EDAC-I5400
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i5400_edac.c
EDAC-I7300
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
F: drivers/edac/i7300_edac.c
EDAC-I7CORE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
@@ -3544,7 +3583,7 @@ S: Maintained
F: drivers/edac/r82600_edac.c
EDAC-SBRIDGE
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-edac@vger.kernel.org
W: bluesmoke.sourceforge.net
S: Maintained
@@ -3604,7 +3643,7 @@ S: Maintained
F: drivers/net/ethernet/ibm/ehea/
EM28XX VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -4730,6 +4769,12 @@ F: include/net/cfg802154.h
F: include/net/ieee802154_netdev.h
F: Documentation/networking/ieee802154.txt
+IGORPLUG-USB IR RECEIVER
+M: Sean Young <sean@mess.org>
+L: linux-media@vger.kernel.org
+S: Maintained
+F: drivers/media/rc/igorplugusb.c
+
IGUANAWORKS USB IR TRANSCEIVER
M: Sean Young <sean@mess.org>
L: linux-media@vger.kernel.org
@@ -4787,6 +4832,11 @@ L: linux-security-module@vger.kernel.org
S: Supported
F: security/integrity/ima/
+IMGTEC IR DECODER DRIVER
+M: James Hogan <james.hogan@imgtec.com>
+S: Maintained
+F: drivers/media/rc/img-ir/
+
IMS TWINTURBO FRAMEBUFFER DRIVER
L: linux-fbdev@vger.kernel.org
S: Orphan
@@ -5201,7 +5251,7 @@ F: drivers/media/tuners/it913x*
IVTV VIDEO4LINUX DRIVER
M: Andy Walls <awalls@md.metrocast.net>
-L: ivtv-devel@ivtvdriver.org (moderated for non-subscribers)
+L: ivtv-devel@ivtvdriver.org (subscribers-only)
L: linux-media@vger.kernel.org
T: git git://linuxtv.org/media_tree.git
W: http://www.ivtvdriver.org
@@ -5982,7 +6032,7 @@ S: Maintained
F: drivers/media/radio/radio-maxiradio*
MEDIA INPUT INFRASTRUCTURE (V4L/DVB)
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
P: LinuxTV.org Project
L: linux-media@vger.kernel.org
W: http://linuxtv.org
@@ -6011,10 +6061,13 @@ W: http://linuxtv.org
S: Odd Fixes
F: drivers/media/parport/pms*
-MEGARAID SCSI DRIVERS
-M: Neela Syam Kolli <megaraidlinux@lsi.com>
+MEGARAID SCSI/SAS DRIVERS
+M: Kashyap Desai <kashyap.desai@avagotech.com>
+M: Sumit Saxena <sumit.saxena@avagotech.com>
+M: Uday Lingala <uday.lingala@avagotech.com>
+L: megaraidlinux.pdl@avagotech.com
L: linux-scsi@vger.kernel.org
-W: http://megaraid.lsilogic.com
+W: http://www.lsi.com
S: Maintained
F: Documentation/scsi/megaraid.txt
F: drivers/scsi/megaraid.*
@@ -6137,6 +6190,28 @@ S: Supported
F: include/linux/mlx5/
F: drivers/infiniband/hw/mlx5/
+MN88472 MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/staging/media/mn88472/
+F: drivers/media/dvb-frontends/mn88472.h
+
+MN88473 MEDIA DRIVER
+M: Antti Palosaari <crope@iki.fi>
+L: linux-media@vger.kernel.org
+W: http://linuxtv.org/
+W: http://palosaari.fi/linux/
+Q: http://patchwork.linuxtv.org/project/linux-media/list/
+T: git git://linuxtv.org/anttip/media_tree.git
+S: Maintained
+F: drivers/staging/media/mn88473/
+F: drivers/media/dvb-frontends/mn88473.h
+
MODULE SUPPORT
M: Rusty Russell <rusty@rustcorp.com.au>
S: Maintained
@@ -6325,7 +6400,6 @@ F: drivers/scsi/g_NCR5380.*
F: drivers/scsi/g_NCR5380_mmio.c
F: drivers/scsi/mac_scsi.*
F: drivers/scsi/pas16.*
-F: drivers/scsi/sun3_NCR5380.c
F: drivers/scsi/sun3_scsi.*
F: drivers/scsi/sun3_scsi_vme.c
F: drivers/scsi/t128.*
@@ -6581,6 +6655,13 @@ S: Maintained
F: Documentation/scsi/NinjaSCSI.txt
F: drivers/scsi/nsp32*
+NIOS2 ARCHITECTURE
+M: Ley Foon Tan <lftan@altera.com>
+L: nios2-dev@lists.rocketboards.org (moderated for non-subscribers)
+T: git git://git.rocketboards.org/linux-socfpga.git
+S: Maintained
+F: arch/nios2/
+
NTB DRIVER
M: Jon Mason <jdmason@kudzu.us>
M: Dave Jiang <dave.jiang@intel.com>
@@ -6621,6 +6702,12 @@ S: Supported
F: drivers/gpu/drm/i2c/tda998x_drv.c
F: include/drm/i2c/tda998x.h
+NXP TFA9879 DRIVER
+M: Peter Rosin <peda@axentia.se>
+L: alsa-devel@alsa-project.org (moderated for non-subscribers)
+S: Maintained
+F: sound/soc/codecs/tfa9879*
+
OMAP SUPPORT
M: Tony Lindgren <tony@atomide.com>
L: linux-omap@vger.kernel.org
@@ -6690,6 +6777,14 @@ L: linux-omap@vger.kernel.org
S: Maintained
F: sound/soc/omap/
+OMAP GENERAL PURPOSE MEMORY CONTROLLER SUPPORT
+M: Roger Quadros <rogerq@ti.com>
+M: Tony Lindgren <tony@atomide.com>
+L: linux-omap@vger.kernel.org
+S: Maintained
+F: drivers/memory/omap-gpmc.c
+F: arch/arm/mach-omap2/*gpmc*
+
OMAP FRAMEBUFFER SUPPORT
M: Tomi Valkeinen <tomi.valkeinen@ti.com>
L: linux-fbdev@vger.kernel.org
@@ -7067,6 +7162,16 @@ S: Maintained
F: Documentation/devicetree/bindings/pci/xgene-pci.txt
F: drivers/pci/host/pci-xgene.c
+PCI DRIVER FOR FREESCALE LAYERSCAPE
+M: Minghuan Lian <minghuan.Lian@freescale.com>
+M: Mingkai Hu <mingkai.hu@freescale.com>
+M: Roy Zang <tie-fei.zang@freescale.com>
+L: linuxppc-dev@lists.ozlabs.org
+L: linux-pci@vger.kernel.org
+L: linux-arm-kernel@lists.infradead.org
+S: Maintained
+F: drivers/pci/host/*layerscape*
+
PCI DRIVER FOR IMX6
M: Richard Zhu <r65037@freescale.com>
M: Lucas Stach <l.stach@pengutronix.de>
@@ -7246,7 +7351,13 @@ PIN CONTROLLER - ATMEL AT91
M: Jean-Christophe Plagniol-Villard <plagnioj@jcrosoft.com>
L: linux-arm-kernel@lists.infradead.org (moderated for non-subscribers)
S: Maintained
-F: drivers/pinctrl/pinctrl-at91.c
+F: drivers/pinctrl/pinctrl-at91.*
+
+PIN CONTROLLER - INTEL
+M: Mika Westerberg <mika.westerberg@linux.intel.com>
+M: Heikki Krogerus <heikki.krogerus@linux.intel.com>
+S: Maintained
+F: drivers/pinctrl/intel/
PIN CONTROLLER - RENESAS
M: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
@@ -8039,7 +8150,7 @@ S: Odd Fixes
F: drivers/media/i2c/saa6588*
SAA7134 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -8497,7 +8608,7 @@ S: Maintained
F: drivers/media/radio/si4713/radio-usb-si4713.c
SIANO DVB DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -8507,6 +8618,14 @@ F: drivers/media/usb/siano/
F: drivers/media/usb/siano/
F: drivers/media/mmc/siano/
+SIMPLEFB FB DRIVER
+M: Hans de Goede <hdegoede@redhat.com>
+L: linux-fbdev@vger.kernel.org
+S: Maintained
+F: Documentation/devicetree/bindings/video/simple-framebuffer.txt
+F: drivers/video/fbdev/simplefb.c
+F: include/linux/platform_data/simplefb.h
+
SH_VEU V4L2 MEM2MEM DRIVER
L: linux-media@vger.kernel.org
S: Orphan
@@ -8708,7 +8827,9 @@ S: Maintained
F: drivers/leds/leds-net48xx.c
SOFTLOGIC 6x10 MPEG CODEC
-M: Ismael Luceno <ismael.luceno@corp.bluecherry.net>
+M: Bluecherry Maintainers <maintainers@bluecherrydvr.com>
+M: Andrey Utkin <andrey.utkin@corp.bluecherry.net>
+M: Andrey Utkin <andrey.krieger.utkin@gmail.com>
L: linux-media@vger.kernel.org
S: Supported
F: drivers/media/pci/solo6x10/
@@ -9189,7 +9310,7 @@ S: Maintained
F: drivers/media/i2c/tda9840*
TEA5761 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -9197,7 +9318,7 @@ S: Odd fixes
F: drivers/media/tuners/tea5761.*
TEA5767 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -9509,7 +9630,7 @@ F: include/linux/shmem_fs.h
F: mm/shmem.c
TM6000 VIDEO4LINUX DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
@@ -10330,7 +10451,7 @@ S: Maintained
F: arch/x86/kernel/cpu/mcheck/*
XC2028/3028 TUNER DRIVER
-M: Mauro Carvalho Chehab <m.chehab@samsung.com>
+M: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
L: linux-media@vger.kernel.org
W: http://linuxtv.org
T: git git://linuxtv.org/media_tree.git
diff --git a/Makefile b/Makefile
index ce70361..fd80c6e 100644
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
VERSION = 3
PATCHLEVEL = 18
SUBLEVEL = 0
-EXTRAVERSION = -rc7
+EXTRAVERSION =
NAME = Diseased Newt
# *DOCUMENTATION*
diff --git a/arch/alpha/kernel/osf_sys.c b/arch/alpha/kernel/osf_sys.c
index f9c732e..e51f578 100644
--- a/arch/alpha/kernel/osf_sys.c
+++ b/arch/alpha/kernel/osf_sys.c
@@ -104,11 +104,12 @@ struct osf_dirent_callback {
};
static int
-osf_filldir(void *__buf, const char *name, int namlen, loff_t offset,
- u64 ino, unsigned int d_type)
+osf_filldir(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct osf_dirent __user *dirent;
- struct osf_dirent_callback *buf = (struct osf_dirent_callback *) __buf;
+ struct osf_dirent_callback *buf =
+ container_of(ctx, struct osf_dirent_callback, ctx);
unsigned int reclen = ALIGN(NAME_OFFSET + namlen + 1, sizeof(u32));
unsigned int d_ino;
diff --git a/arch/arc/include/asm/io.h b/arch/arc/include/asm/io.h
index 334ce70..cabd518 100644
--- a/arch/arc/include/asm/io.h
+++ b/arch/arc/include/asm/io.h
@@ -13,8 +13,6 @@
#include <asm/byteorder.h>
#include <asm/page.h>
-#define PCI_IOBASE ((void __iomem *)0)
-
extern void __iomem *ioremap(unsigned long physaddr, unsigned long size);
extern void __iomem *ioremap_prot(phys_addr_t offset, unsigned long size,
unsigned long flags);
diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 89c4b5c..c8424a8 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -320,24 +320,6 @@ config ARCH_MULTIPLATFORM
select SPARSE_IRQ
select USE_OF
-config ARCH_INTEGRATOR
- bool "ARM Ltd. Integrator family"
- select ARM_AMBA
- select ARM_PATCH_PHYS_VIRT if MMU
- select AUTO_ZRELADDR
- select COMMON_CLK
- select COMMON_CLK_VERSATILE
- select GENERIC_CLOCKEVENTS
- select HAVE_TCM
- select ICST
- select MULTI_IRQ_HANDLER
- select PLAT_VERSATILE
- select SPARSE_IRQ
- select USE_OF
- select VERSATILE_FPGA_IRQ
- help
- Support for ARM's Integrator platform.
-
config ARCH_REALVIEW
bool "ARM Ltd. RealView family"
select ARCH_WANT_OPTIONAL_GPIOLIB
@@ -350,6 +332,7 @@ config ARCH_REALVIEW
select ICST
select NEED_MACH_MEMORY_H
select PLAT_VERSATILE
+ select PLAT_VERSATILE_SCHED_CLOCK
help
This enables support for ARM Ltd RealView boards.
@@ -365,6 +348,7 @@ config ARCH_VERSATILE
select ICST
select PLAT_VERSATILE
select PLAT_VERSATILE_CLOCK
+ select PLAT_VERSATILE_SCHED_CLOCK
select VERSATILE_FPGA_IRQ
help
This enables support for ARM Ltd Versatile board.
@@ -376,10 +360,11 @@ config ARCH_AT91
select IRQ_DOMAIN
select NEED_MACH_IO_H if PCCARD
select PINCTRL
- select PINCTRL_AT91 if USE_OF
+ select PINCTRL_AT91
+ select USE_OF
help
This enables support for systems based on Atmel
- AT91RM9200 and AT91SAM9* processors.
+ AT91RM9200, AT91SAM9 and SAMA5 processors.
config ARCH_CLPS711X
bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
@@ -854,6 +839,8 @@ config ARCH_VIRT
#
source "arch/arm/mach-mvebu/Kconfig"
+source "arch/arm/mach-asm9260/Kconfig"
+
source "arch/arm/mach-at91/Kconfig"
source "arch/arm/mach-axxia/Kconfig"
@@ -1259,9 +1246,6 @@ source "arch/arm/common/Kconfig"
menu "Bus support"
-config ARM_AMBA
- bool
-
config ISA
bool
help
diff --git a/arch/arm/Kconfig.debug b/arch/arm/Kconfig.debug
index d8f6a2e..f9295a4 100644
--- a/arch/arm/Kconfig.debug
+++ b/arch/arm/Kconfig.debug
@@ -93,6 +93,27 @@ choice
prompt "Kernel low-level debugging port"
depends on DEBUG_LL
+ config DEBUG_ASM9260_UART
+ bool "Kernel low-level debugging via asm9260 UART"
+ depends on MACH_ASM9260
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to an UART or USART port on asm9260 based
+ machines.
+
+ DEBUG_UART_PHYS | DEBUG_UART_VIRT
+
+ 0x80000000 | 0xf0000000 | UART0
+ 0x80004000 | 0xf0004000 | UART1
+ 0x80008000 | 0xf0008000 | UART2
+ 0x8000c000 | 0xf000c000 | UART3
+ 0x80010000 | 0xf0010000 | UART4
+ 0x80014000 | 0xf0014000 | UART5
+ 0x80018000 | 0xf0018000 | UART6
+ 0x8001c000 | 0xf001c000 | UART7
+ 0x80020000 | 0xf0020000 | UART8
+ 0x80024000 | 0xf0024000 | UART9
+
config AT91_DEBUG_LL_DBGU0
bool "Kernel low-level debugging on rm9200, 9260/9g20, 9261/9g10 and 9rl"
depends on HAVE_AT91_DBGU0
@@ -113,7 +134,7 @@ choice
config DEBUG_BCM_5301X
bool "Kernel low-level debugging on BCM5301X UART1"
depends on ARCH_BCM_5301X
- select DEBUG_UART_PL01X
+ select DEBUG_UART_8250
config DEBUG_BCM_KONA_UART
bool "Kernel low-level debugging messages via BCM KONA UART"
@@ -139,6 +160,17 @@ choice
Say Y here if you want kernel low-level debugging support
on Marvell Berlin SoC based platforms.
+ config DEBUG_BRCMSTB_UART
+ bool "Use BRCMSTB UART for low-level debug"
+ depends on ARCH_BRCMSTB
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want the debug print routines to direct
+ their output to the first serial port on these devices.
+
+ If you have a Broadcom STB chip and would like early print
+ messages to appear over the UART, select this option.
+
config DEBUG_CLPS711X_UART1
bool "Kernel low-level debugging messages via UART1"
depends on ARCH_CLPS711X
@@ -653,6 +685,64 @@ choice
Say Y here if you want kernel low-level debugging support
on Rockchip RK32xx based platforms.
+ config DEBUG_R7S72100_SCIF2
+ bool "Kernel low-level debugging messages via SCIF2 on R7S72100"
+ depends on ARCH_R7S72100
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIF2 on Renesas RZ/A1H (R7S72100).
+
+ config DEBUG_RCAR_GEN1_SCIF0
+ bool "Kernel low-level debugging messages via SCIF0 on R8A7778"
+ depends on ARCH_R8A7778
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIF0 on Renesas R-Car M1A (R8A7778).
+
+ config DEBUG_RCAR_GEN1_SCIF2
+ bool "Kernel low-level debugging messages via SCIF2 on R8A7779"
+ depends on ARCH_R8A7779
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIF2 on Renesas R-Car H1 (R8A7779).
+
+ config DEBUG_RCAR_GEN2_SCIF0
+ bool "Kernel low-level debugging messages via SCIF0 on R8A7790/R8A7791/R8A7793)"
+ depends on ARCH_R8A7790 || ARCH_R8A7791 || ARCH_R8A7793
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIF0 on Renesas R-Car H2 (R8A7790), M2-W (R8A7791), or
+ M2-N (R8A7793).
+
+ config DEBUG_RCAR_GEN2_SCIF2
+ bool "Kernel low-level debugging messages via SCIF2 on R8A7794"
+ depends on ARCH_R8A7794
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIF2 on Renesas R-Car E2 (R8A7794).
+
+ config DEBUG_RMOBILE_SCIFA0
+ bool "Kernel low-level debugging messages via SCIFA0 on R8A73A4/SH7372"
+ depends on ARCH_R8A73A4 || ARCH_SH7372
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIFA0 on Renesas R-Mobile APE6 (R8A73A4) or SH-Mobile
+ AP4 (SH7372).
+
+ config DEBUG_RMOBILE_SCIFA1
+ bool "Kernel low-level debugging messages via SCIFA1 on R8A7740"
+ depends on ARCH_R8A7740
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIFA1 on Renesas R-Mobile A1 (R8A7740).
+
+ config DEBUG_RMOBILE_SCIFA4
+ bool "Kernel low-level debugging messages via SCIFA4 on SH73A0"
+ depends on ARCH_SH73A0
+ help
+ Say Y here if you want kernel low-level debugging support
+ via SCIFA4 on Renesas SH-Mobile AG5 (SH73A0).
+
config DEBUG_S3C_UART0
depends on PLAT_SAMSUNG
select DEBUG_EXYNOS_UART if ARCH_EXYNOS
@@ -723,6 +813,14 @@ choice
their output to UART 2. The port must have been initialised
by the boot-loader before use.
+ config DEBUG_SA1100
+ depends on ARCH_SA1100
+ bool "Use SA1100 UARTs for low-level debug"
+ help
+ Say Y here if you want kernel low-level debugging support
+ on SA-11x0 UART ports. The kernel will check for the first
+ enabled UART in a sequence 3-1-2.
+
config DEBUG_SOCFPGA_UART
depends on ARCH_SOCFPGA
bool "Use SOCFPGA UART for low-level debug"
@@ -731,6 +829,14 @@ choice
Say Y here if you want kernel low-level debugging support
on SOCFPGA based platforms.
+ config DEBUG_SUN9I_UART0
+ bool "Kernel low-level debugging messages via sun9i UART0"
+ depends on MACH_SUN9I
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ on Allwinner A80 based platforms on the UART0.
+
config DEBUG_SUNXI_UART0
bool "Kernel low-level debugging messages via sunXi UART0"
depends on ARCH_SUNXI
@@ -866,6 +972,22 @@ choice
Say Y here if you want kernel low-level debugging support
for Mediatek mt6589 based platforms on UART0.
+ config DEBUG_MT8127_UART0
+ bool "Mediatek mt8127 UART0"
+ depends on ARCH_MEDIATEK
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ for Mediatek mt8127 based platforms on UART0.
+
+ config DEBUG_MT8135_UART3
+ bool "Mediatek mt8135 UART3"
+ depends on ARCH_MEDIATEK
+ select DEBUG_UART_8250
+ help
+ Say Y here if you want kernel low-level debugging support
+ for Mediatek mt8135 based platforms on UART3.
+
config DEBUG_VEXPRESS_UART0_DETECT
bool "Autodetect UART0 on Versatile Express Cortex-A core tiles"
depends on ARCH_VEXPRESS && CPU_CP15_MMU
@@ -1041,7 +1163,9 @@ config DEBUG_STI_UART
config DEBUG_LL_INCLUDE
string
+ default "debug/sa1100.S" if DEBUG_SA1100
default "debug/8250.S" if DEBUG_LL_UART_8250 || DEBUG_UART_8250
+ default "debug/asm9260.S" if DEBUG_ASM9260_UART
default "debug/clps711x.S" if DEBUG_CLPS711X_UART1 || DEBUG_CLPS711X_UART2
default "debug/meson.S" if DEBUG_MESON_UARTAO
default "debug/pl01x.S" if DEBUG_LL_UART_PL01X || DEBUG_UART_PL01X
@@ -1061,6 +1185,14 @@ config DEBUG_LL_INCLUDE
DEBUG_IMX6SX_UART
default "debug/msm.S" if DEBUG_MSM_UART || DEBUG_QCOM_UARTDM
default "debug/omap2plus.S" if DEBUG_OMAP2PLUS_UART
+ default "debug/renesas-scif.S" if DEBUG_R7S72100_SCIF2
+ default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF0
+ default "debug/renesas-scif.S" if DEBUG_RCAR_GEN1_SCIF2
+ default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF0
+ default "debug/renesas-scif.S" if DEBUG_RCAR_GEN2_SCIF2
+ default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA0
+ default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA1
+ default "debug/renesas-scif.S" if DEBUG_RMOBILE_SCIFA4
default "debug/s3c24xx.S" if DEBUG_S3C24XX_UART
default "debug/s5pv210.S" if DEBUG_S5PV210_UART
default "debug/sirf.S" if DEBUG_SIRFPRIMA2_UART1 || DEBUG_SIRFMARCO_UART1
@@ -1106,6 +1238,7 @@ config DEBUG_UART_PHYS
default 0x02530c00 if DEBUG_KEYSTONE_UART0
default 0x02531000 if DEBUG_KEYSTONE_UART1
default 0x03010fe0 if ARCH_RPC
+ default 0x07000000 if DEBUG_SUN9I_UART0
default 0x10009000 if DEBUG_REALVIEW_STD_PORT || \
DEBUG_VEXPRESS_UART0_CA9
default 0x1010c000 if DEBUG_REALVIEW_PB1176_PORT
@@ -1113,7 +1246,9 @@ config DEBUG_UART_PHYS
default 0x10126000 if DEBUG_RK3X_UART1
default 0x101f1000 if ARCH_VERSATILE
default 0x101fb000 if DEBUG_NOMADIK_UART
+ default 0x11002000 if DEBUG_MT8127_UART0
default 0x11006000 if DEBUG_MT6589_UART0
+ default 0x11009000 if DEBUG_MT8135_UART3
default 0x16000000 if ARCH_INTEGRATOR
default 0x18000300 if DEBUG_BCM_5301X
default 0x1c090000 if DEBUG_VEXPRESS_UART0_RS1
@@ -1135,6 +1270,7 @@ config DEBUG_UART_PHYS
default 0x78000000 if DEBUG_CNS3XXX
default 0x7c0003f8 if FOOTBRIDGE
default 0x78000000 if DEBUG_CNS3XXX
+ default 0x80010000 if DEBUG_ASM9260_UART
default 0x80070000 if DEBUG_IMX23_UART
default 0x80074000 if DEBUG_IMX28_UART
default 0x80230000 if DEBUG_PICOXCELL_UART
@@ -1152,7 +1288,14 @@ config DEBUG_UART_PHYS
default 0xd4018000 if DEBUG_MMP_UART3
default 0xe0000000 if ARCH_SPEAR13XX
default 0xe4007000 if DEBUG_HIP04_UART
+ default 0xe6c40000 if DEBUG_RMOBILE_SCIFA0
+ default 0xe6c50000 if DEBUG_RMOBILE_SCIFA1
+ default 0xe6c80000 if DEBUG_RMOBILE_SCIFA4
+ default 0xe6e58000 if DEBUG_RCAR_GEN2_SCIF2
+ default 0xe6e60000 if DEBUG_RCAR_GEN2_SCIF0
+ default 0xe8008000 if DEBUG_R7S72100_SCIF2
default 0xf0000be0 if ARCH_EBSA110
+ default 0xf040ab00 if DEBUG_BRCMSTB_UART
default 0xf1012000 if DEBUG_MVEBU_UART_ALTERNATE
default 0xf1012000 if ARCH_DOVE || ARCH_MV78XX0 || \
ARCH_ORION5X
@@ -1164,24 +1307,33 @@ config DEBUG_UART_PHYS
default 0xff690000 if DEBUG_RK32_UART2
default 0xffc02000 if DEBUG_SOCFPGA_UART
default 0xffd82340 if ARCH_IOP13XX
+ default 0xffe40000 if DEBUG_RCAR_GEN1_SCIF0
+ default 0xffe42000 if DEBUG_RCAR_GEN1_SCIF2
default 0xfff36000 if DEBUG_HIGHBANK_UART
default 0xfffe8600 if DEBUG_UART_BCM63XX
default 0xfffff700 if ARCH_IOP33X
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_LL_UART_EFM32 || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
- DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
- DEBUG_UART_BCM63XX
+ DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_R7S72100_SCIF2 || \
+ DEBUG_RCAR_GEN1_SCIF0 || DEBUG_RCAR_GEN1_SCIF2 || \
+ DEBUG_RCAR_GEN2_SCIF0 || DEBUG_RCAR_GEN2_SCIF2 || \
+ DEBUG_RMOBILE_SCIFA0 || DEBUG_RMOBILE_SCIFA1 || \
+ DEBUG_RMOBILE_SCIFA4 || DEBUG_S3C24XX_UART || \
+ DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
config DEBUG_UART_VIRT
hex "Virtual base address of debug UART"
default 0xe0010fe0 if ARCH_RPC
default 0xe1000000 if DEBUG_MSM_UART
default 0xf0000be0 if ARCH_EBSA110
+ default 0xf0010000 if DEBUG_ASM9260_UART
default 0xf01fb000 if DEBUG_NOMADIK_UART
default 0xf0201000 if DEBUG_BCM2835
default 0xf1000300 if DEBUG_BCM_5301X
+ default 0xf1002000 if DEBUG_MT8127_UART0
default 0xf1006000 if DEBUG_MT6589_UART0
+ default 0xf1009000 if DEBUG_MT8135_UART3
default 0xf11f1000 if ARCH_VERSATILE
default 0xf1600000 if ARCH_INTEGRATOR
default 0xf1c28000 if DEBUG_SUNXI_UART0
@@ -1190,6 +1342,7 @@ config DEBUG_UART_VIRT
default 0xf6200000 if DEBUG_PXA_UART1
default 0xf4090000 if ARCH_LPC32XX
default 0xf4200000 if ARCH_GEMINI
+ default 0xf7000000 if DEBUG_SUN9I_UART0
default 0xf7000000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART0 || \
DEBUG_S3C2410_UART0)
default 0xf7004000 if DEBUG_S3C24XX_UART && (DEBUG_S3C_UART1 || \
@@ -1204,6 +1357,7 @@ config DEBUG_UART_VIRT
default 0xfb002000 if DEBUG_CNS3XXX
default 0xfb009000 if DEBUG_REALVIEW_STD_PORT
default 0xfb10c000 if DEBUG_REALVIEW_PB1176_PORT
+ default 0xfc40ab00 if DEBUG_BRCMSTB_UART
default 0xfcfe8600 if DEBUG_UART_BCM63XX
default 0xfd000000 if ARCH_SPEAR3XX || ARCH_SPEAR6XX
default 0xfd000000 if ARCH_SPEAR13XX
@@ -1244,12 +1398,12 @@ config DEBUG_UART_VIRT
depends on DEBUG_LL_UART_8250 || DEBUG_LL_UART_PL01X || \
DEBUG_UART_8250 || DEBUG_UART_PL01X || DEBUG_MESON_UARTAO || \
DEBUG_MSM_UART || DEBUG_QCOM_UARTDM || DEBUG_S3C24XX_UART || \
- DEBUG_UART_BCM63XX
+ DEBUG_UART_BCM63XX || DEBUG_ASM9260_UART
config DEBUG_UART_8250_SHIFT
int "Register offset shift for the 8250 debug UART"
depends on DEBUG_LL_UART_8250 || DEBUG_UART_8250
- default 0 if FOOTBRIDGE || ARCH_IOP32X
+ default 0 if FOOTBRIDGE || ARCH_IOP32X || DEBUG_BCM_5301X
default 2
config DEBUG_UART_8250_WORD
@@ -1260,7 +1414,8 @@ config DEBUG_UART_8250_WORD
ARCH_KEYSTONE || \
DEBUG_DAVINCI_DMx_UART0 || DEBUG_DAVINCI_DA8XX_UART1 || \
DEBUG_DAVINCI_DA8XX_UART2 || \
- DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2
+ DEBUG_BCM_KONA_UART || DEBUG_RK32_UART2 || \
+ DEBUG_BRCMSTB_UART
config DEBUG_UART_8250_FLOW_CONTROL
bool "Enable flow control for 8250 UART"
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 034a949..c1785ee 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -312,8 +312,12 @@ $(INSTALL_TARGETS):
$(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $(boot)/dts/$@
PHONY += dtbs dtbs_install
-dtbs dtbs_install: prepare scripts
- $(Q)$(MAKE) $(build)=$(boot)/dts MACHINE=$(MACHINE) $@
+
+dtbs: prepare scripts
+ $(Q)$(MAKE) $(build)=$(boot)/dts
+
+dtbs_install:
+ $(Q)$(MAKE) $(dtbinst)=$(boot)/dts
# We use MRPROPER_FILES and CLEAN_FILES now
archclean:
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 38c89ca..6a3d9a6 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -54,8 +54,17 @@ dtb-$(CONFIG_ARCH_AT91) += at91-sama5d4ek.dtb
dtb-$(CONFIG_ARCH_ATLAS6) += atlas6-evb.dtb
dtb-$(CONFIG_ARCH_AXXIA) += axm5516-amarillo.dtb
dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b.dtb
-dtb-$(CONFIG_ARCH_BCM_5301X) += bcm4708-netgear-r6250.dtb
+dtb-$(CONFIG_ARCH_BCM2835) += bcm2835-rpi-b-plus.dtb
+dtb-$(CONFIG_ARCH_BCM_5301X) += \
+ bcm4708-buffalo-wzr-1750dhp.dtb \
+ bcm4708-netgear-r6250.dtb \
+ bcm4708-netgear-r6300-v2.dtb \
+ bcm47081-asus-rt-n18u.dtb \
+ bcm47081-buffalo-wzr-600dhp2.dtb
dtb-$(CONFIG_ARCH_BCM_63XX) += bcm963138dvt.dtb
+dtb-$(CONFIG_ARCH_BCM_CYGNUS) += bcm911360_entphn.dtb \
+ bcm911360k.dtb \
+ bcm958300k.dtb
dtb-$(CONFIG_ARCH_BCM_MOBILE) += bcm28155-ap.dtb \
bcm21664-garnet.dtb
dtb-$(CONFIG_ARCH_BERLIN) += \
@@ -67,7 +76,9 @@ dtb-$(CONFIG_ARCH_BRCMSTB) += \
dtb-$(CONFIG_ARCH_DAVINCI) += da850-enbw-cmc.dtb \
da850-evm.dtb
dtb-$(CONFIG_ARCH_EFM32) += efm32gg-dk3750.dtb
-dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
+dtb-$(CONFIG_ARCH_EXYNOS) += exynos3250-monk.dtb \
+ exynos3250-rinato.dtb \
+ exynos4210-origen.dtb \
exynos4210-smdkv310.dtb \
exynos4210-trats.dtb \
exynos4210-universal_c210.dtb \
@@ -81,6 +92,7 @@ dtb-$(CONFIG_ARCH_EXYNOS) += exynos4210-origen.dtb \
exynos5250-arndale.dtb \
exynos5250-smdk5250.dtb \
exynos5250-snow.dtb \
+ exynos5250-spring.dtb \
exynos5260-xyref5260.dtb \
exynos5410-smdk5410.dtb \
exynos5420-arndale-octa.dtb \
@@ -104,6 +116,7 @@ dtb-$(CONFIG_MACH_KIRKWOOD) += kirkwood-b3.dtb \
kirkwood-d2net.dtb \
kirkwood-db-88f6281.dtb \
kirkwood-db-88f6282.dtb \
+ kirkwood-dir665.dtb \
kirkwood-dns320.dtb \
kirkwood-dns325.dtb \
kirkwood-dockstar.dtb \
@@ -240,6 +253,7 @@ dtb-$(CONFIG_ARCH_MXC) += \
imx6q-sabrelite.dtb \
imx6q-sabresd.dtb \
imx6q-sbc6x.dtb \
+ imx6q-tbs2910.dtb \
imx6q-udoo.dtb \
imx6q-wandboard.dtb \
imx6q-wandboard-revb1.dtb \
@@ -250,6 +264,9 @@ dtb-$(CONFIG_ARCH_MXC) += \
imx6q-tx6q-1110.dtb \
imx6sl-evk.dtb \
imx6sx-sdb.dtb \
+ ls1021a-qds.dtb \
+ ls1021a-twr.dtb \
+ vf500-colibri-eval-v3.dtb \
vf610-colibri-eval-v3.dtb \
vf610-cosmic.dtb \
vf610-twr.dtb
@@ -274,7 +291,8 @@ dtb-$(CONFIG_ARCH_MXS) += imx23-evk.dtb \
imx28-m28evk.dtb \
imx28-sps1.dtb \
imx28-tx28.dtb
-dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb
+dtb-$(CONFIG_ARCH_NOMADIK) += ste-nomadik-s8815.dtb \
+ ste-nomadik-nhk15.dtb
dtb-$(CONFIG_ARCH_NSPIRE) += nspire-cx.dtb \
nspire-tp.dtb \
nspire-clp.dtb
@@ -302,7 +320,9 @@ dtb-$(CONFIG_ARCH_OMAP3) += am3517-craneboard.dtb \
omap3-ha.dtb \
omap3-ha-lcd.dtb \
omap3-igep0020.dtb \
+ omap3-igep0020-rev-f.dtb \
omap3-igep0030.dtb \
+ omap3-igep0030-rev-g.dtb \
omap3-ldp.dtb \
omap3-lilly-dbb056.dtb \
omap3-n900.dtb \
@@ -331,7 +351,8 @@ dtb-$(CONFIG_SOC_AM33XX) += am335x-base0033.dtb \
am335x-evm.dtb \
am335x-evmsk.dtb \
am335x-nano.dtb \
- am335x-pepper.dtb
+ am335x-pepper.dtb \
+ am335x-lxm.dtb
dtb-$(CONFIG_ARCH_OMAP4) += omap4-duovero-parlor.dtb \
omap4-panda.dtb \
omap4-panda-a4.dtb \
@@ -347,6 +368,7 @@ dtb-$(CONFIG_SOC_OMAP5) += omap5-cm-t54.dtb \
omap5-sbc-t54.dtb \
omap5-uevm.dtb
dtb-$(CONFIG_SOC_DRA7XX) += dra7-evm.dtb \
+ am57xx-beagle-x15.dtb \
dra72-evm.dtb
dtb-$(CONFIG_ARCH_ORION5X) += orion5x-lacie-d2-network.dtb \
orion5x-lacie-ethernet-disk-mini-v2.dtb \
@@ -363,8 +385,10 @@ dtb-$(CONFIG_ARCH_QCOM) += \
qcom-msm8660-surf.dtb \
qcom-msm8960-cdp.dtb \
qcom-msm8974-sony-xperia-honami.dtb
+dtb-$(CONFIG_ARCH_REALVIEW) += arm-realview-pb1176.dtb
dtb-$(CONFIG_ARCH_ROCKCHIP) += \
rk3066a-bqcurie2.dtb \
+ rk3066a-marsboard.dtb \
rk3188-radxarock.dtb \
rk3288-evb-act8846.dtb \
rk3288-evb-rk808.dtb
@@ -376,27 +400,27 @@ dtb-$(CONFIG_ARCH_S5PV210) += s5pv210-aquila.dtb \
s5pv210-smdkc110.dtb \
s5pv210-smdkv210.dtb \
s5pv210-torbreck.dtb
-dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += r7s72100-genmai.dtb \
+dtb-$(CONFIG_ARCH_SHMOBILE_LEGACY) += \
+ r8a73a4-ape6evm.dtb \
+ r8a73a4-ape6evm-reference.dtb \
r8a7740-armadillo800eva.dtb \
r8a7778-bockw.dtb \
r8a7778-bockw-reference.dtb \
r8a7779-marzen.dtb \
- r8a7791-koelsch.dtb \
r8a7790-lager.dtb \
+ sh7372-mackerel.dtb \
sh73a0-kzm9g.dtb \
- sh73a0-kzm9g-reference.dtb \
- r8a73a4-ape6evm.dtb \
- r8a73a4-ape6evm-reference.dtb \
- sh7372-mackerel.dtb
+ sh73a0-kzm9g-reference.dtb
dtb-$(CONFIG_ARCH_SHMOBILE_MULTI) += emev2-kzm9d.dtb \
r7s72100-genmai.dtb \
r8a7740-armadillo800eva.dtb \
+ r8a7779-marzen.dtb \
+ r8a7790-lager.dtb \
r8a7791-henninger.dtb \
r8a7791-koelsch.dtb \
- r8a7790-lager.dtb \
- r8a7779-marzen.dtb \
r8a7794-alt.dtb
dtb-$(CONFIG_ARCH_SOCFPGA) += socfpga_arria5_socdk.dtb \
+ socfpga_arria10_socdk.dtb \
socfpga_cyclone5_socdk.dtb \
socfpga_cyclone5_sockit.dtb \
socfpga_cyclone5_socrates.dtb \
@@ -409,6 +433,7 @@ dtb-$(CONFIG_ARCH_SPEAR3XX)+= spear300-evb.dtb \
spear320-hmi.dtb
dtb-$(CONFIG_ARCH_SPEAR6XX)+= spear600-evb.dtb
dtb-$(CONFIG_ARCH_STI)+= stih407-b2120.dtb \
+ stih410-b2120.dtb \
stih415-b2000.dtb \
stih415-b2020.dtb \
stih416-b2000.dtb \
@@ -435,15 +460,20 @@ dtb-$(CONFIG_MACH_SUN6I) += \
sun6i-a31-hummingbird.dtb \
sun6i-a31-m9.dtb
dtb-$(CONFIG_MACH_SUN7I) += \
+ sun7i-a20-bananapi.dtb \
sun7i-a20-cubieboard2.dtb \
sun7i-a20-cubietruck.dtb \
sun7i-a20-hummingbird.dtb \
sun7i-a20-i12-tvbox.dtb \
+ sun7i-a20-m3.dtb \
sun7i-a20-olinuxino-lime.dtb \
+ sun7i-a20-olinuxino-lime2.dtb \
sun7i-a20-olinuxino-micro.dtb \
sun7i-a20-pcduino3.dtb
dtb-$(CONFIG_MACH_SUN8I) += \
sun8i-a23-ippo-q8h-v5.dtb
+dtb-$(CONFIG_MACH_SUN9I) += \
+ sun9i-a80-optimus.dtb
dtb-$(CONFIG_ARCH_TEGRA) += tegra20-harmony.dtb \
tegra20-iris-512.dtb \
tegra20-medcom-wide.dtb \
@@ -489,13 +519,15 @@ dtb-$(CONFIG_ARCH_ZYNQ) += \
zynq-parallella.dtb \
zynq-zc702.dtb \
zynq-zc706.dtb \
- zynq-zed.dtb
+ zynq-zed.dtb \
+ zynq-zybo.dtb
dtb-$(CONFIG_MACH_ARMADA_370) += \
armada-370-db.dtb \
armada-370-mirabox.dtb \
armada-370-netgear-rn102.dtb \
armada-370-netgear-rn104.dtb \
- armada-370-rd.dtb
+ armada-370-rd.dtb \
+ armada-370-synology-ds213j.dtb
dtb-$(CONFIG_MACH_ARMADA_375) += \
armada-375-db.dtb
dtb-$(CONFIG_MACH_ARMADA_38X) += \
@@ -508,24 +540,20 @@ dtb-$(CONFIG_MACH_ARMADA_XP) += \
armada-xp-lenovo-ix4-300d.dtb \
armada-xp-matrix.dtb \
armada-xp-netgear-rn2120.dtb \
- armada-xp-openblocks-ax3-4.dtb
+ armada-xp-openblocks-ax3-4.dtb \
+ armada-xp-synology-ds414.dtb
dtb-$(CONFIG_MACH_DOVE) += dove-cm-a510.dtb \
dove-cubox.dtb \
dove-cubox-es.dtb \
dove-d2plug.dtb \
dove-d3plug.dtb \
dove-dove-db.dtb
-dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aquaris5.dtb
+dtb-$(CONFIG_ARCH_MEDIATEK) += mt6589-aquaris5.dtb \
+ mt6592-evb.dtb \
+ mt8127-moose.dtb \
+ mt8135-evbp1.dtb
-targets += dtbs dtbs_install
-targets += $(dtb-y)
endif
-# *.dtb used to be generated in the directory above. Clean out the
-# old build results so people don't accidentally use them.
-dtbs: $(addprefix $(obj)/, $(dtb-y))
- $(Q)rm -f $(obj)/../*.dtb
-
-clean-files := *.dtb
-
-dtbs_install: $(addsuffix _dtbinst_, $(dtb-y))
+always := $(dtb-y)
+clean-files := *.dtb
diff --git a/arch/arm/boot/dts/am335x-boneblack.dts b/arch/arm/boot/dts/am335x-boneblack.dts
index 901739f..5c42d25 100644
--- a/arch/arm/boot/dts/am335x-boneblack.dts
+++ b/arch/arm/boot/dts/am335x-boneblack.dts
@@ -80,3 +80,7 @@
status = "okay";
};
};
+
+&rtc {
+ system-power-controller;
+};
diff --git a/arch/arm/boot/dts/am335x-evm.dts b/arch/arm/boot/dts/am335x-evm.dts
index c4b968f..54f118c 100644
--- a/arch/arm/boot/dts/am335x-evm.dts
+++ b/arch/arm/boot/dts/am335x-evm.dts
@@ -307,6 +307,13 @@
0x144 (PIN_INPUT_PULLDOWN | MUX_MODE4) /* rmii1_ref_clk.mcasp1_axr3 */
>;
};
+
+ dcan1_pins_default: dcan1_pins_default {
+ pinctrl-single,pins = <
+ 0x168 (PIN_OUTPUT | MUX_MODE2) /* uart0_ctsn.d_can1_tx */
+ 0x16c (PIN_INPUT_PULLDOWN | MUX_MODE2) /* uart0_rtsn.d_can1_rx */
+ >;
+ };
};
&uart0 {
@@ -437,9 +444,9 @@
status = "okay";
pinctrl-names = "default";
pinctrl-0 = <&nandflash_pins_s0>;
- ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
+ ranges = <0 0 0x08000000 0x1000000>; /* CS0: 16MB for NAND */
nand@0,0 {
- reg = <0 0 0>; /* CS0, offset 0 */
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
ti,nand-ecc-opt = "bch8";
ti,elm-id = <&elm>;
nand-bus-width = <8>;
@@ -664,3 +671,9 @@
&aes {
status = "okay";
};
+
+&dcan1 {
+ status = "disabled"; /* Enable only if Profile 1 is selected */
+ pinctrl-names = "default";
+ pinctrl-0 = <&dcan1_pins_default>;
+};
diff --git a/arch/arm/boot/dts/am335x-igep0033.dtsi b/arch/arm/boot/dts/am335x-igep0033.dtsi
index a1a0cc5..c0e1135 100644
--- a/arch/arm/boot/dts/am335x-igep0033.dtsi
+++ b/arch/arm/boot/dts/am335x-igep0033.dtsi
@@ -126,10 +126,10 @@
pinctrl-names = "default";
pinctrl-0 = <&nandflash_pins>;
- ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
+ ranges = <0 0 0x08000000 0x1000000>; /* CS0: 16MB for NAND */
nand@0,0 {
- reg = <0 0 0>; /* CS0, offset 0 */
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <8>;
ti,nand-ecc-opt = "bch8";
gpmc,device-width = <1>;
diff --git a/arch/arm/boot/dts/am335x-lxm.dts b/arch/arm/boot/dts/am335x-lxm.dts
new file mode 100644
index 0000000..7266a00
--- /dev/null
+++ b/arch/arm/boot/dts/am335x-lxm.dts
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2014 NovaTech LLC - http://www.novatechweb.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+#include "am33xx.dtsi"
+
+/ {
+ model = "NovaTech OrionLXm";
+ compatible = "novatech,am335x-lxm", "ti,am33xx";
+
+ cpus {
+ cpu@0 {
+ cpu0-supply = <&vdd1_reg>;
+ };
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x20000000>; /* 512 MB */
+ };
+
+ /* Power supply provides a fixed 5V @2A */
+ vbat: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vbat";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+
+ /* Power supply provides a fixed 3.3V @3A */
+ vmmcsd_fixed: fixedregulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmcsd_fixed";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+};
+
+&am33xx_pinmux {
+ mmc1_pins: pinmux_mmc1_pins {
+ pinctrl-single,pins = <
+ 0xf0 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat3 */
+ 0xf4 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat2 */
+ 0xf8 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat1 */
+ 0xfc (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_dat0 */
+ 0x100 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_clk */
+ 0x104 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc0_cmd */
+ >;
+ };
+
+ i2c0_pins: pinmux_i2c0_pins {
+ pinctrl-single,pins = <
+ 0x188 (PIN_INPUT | MUX_MODE0) /* i2c0_sda.i2c0_sda */
+ 0x18c (PIN_INPUT | MUX_MODE0) /* i2c0_scl.i2c0_scl */
+ >;
+ };
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */
+ 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_crs_dv */
+ 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rxer */
+ 0x114 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_txen */
+ 0x124 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td1 */
+ 0x128 (PIN_OUTPUT_PULLDOWN | MUX_MODE1) /* rmii1_td0 */
+ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd1 */
+ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii1_rd0 */
+ 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE0) /* rmii1_refclk */
+
+ /* Slave 2 */
+ 0x40 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_txen */
+ 0x50 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td1 */
+ 0x54 (PIN_OUTPUT_PULLDOWN | MUX_MODE3) /* rmii2_td0 */
+ 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd1 */
+ 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rd0 */
+ 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_crs_dv */
+ 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE3) /* rmii2_rxer */
+ 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */
+ 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE1) /* rmii2_refclk */
+ >;
+ };
+
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 reset value */
+ 0x64 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_int */
+ 0x10c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_crs_dv */
+ 0x110 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rxer */
+ 0x114 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_txen */
+ 0x124 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td1 */
+ 0x128 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_td0 */
+ 0x13c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd1 */
+ 0x140 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_rd0 */
+ 0x144 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii1_refclk */
+
+ /* Slave 2 reset value*/
+ 0x40 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_txen */
+ 0x50 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td1 */
+ 0x54 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_td0 */
+ 0x68 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd1 */
+ 0x6c (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rd0 */
+ 0x70 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_crs_dv */
+ 0x74 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_rxer */
+ 0x78 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_int */
+ 0x108 (PIN_INPUT_PULLDOWN | MUX_MODE7) /* rmii2_refclk */
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ /* MDIO */
+ 0x148 (PIN_INPUT_PULLUP | SLEWCTRL_FAST | MUX_MODE0) /* mdio_data.mdio_data */
+ 0x14c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ /* MDIO reset value */
+ 0x148 (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ 0x14c (PIN_INPUT_PULLDOWN | MUX_MODE7)
+ >;
+ };
+
+ emmc_pins: pinmux_emmc_pins {
+ pinctrl-single,pins = <
+ 0x80 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn1.mmc1_clk */
+ 0x84 (PIN_INPUT_PULLUP | MUX_MODE2) /* gpmc_csn2.mmc1_cmd */
+ 0x00 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad0.mmc1_dat0 */
+ 0x04 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad1.mmc1_dat1 */
+ 0x08 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad2.mmc1_dat2 */
+ 0x0c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad3.mmc1_dat3 */
+ 0x10 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad4.mmc1_dat4 */
+ 0x14 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad5.mmc1_dat5 */
+ 0x18 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad6.mmc1_dat6 */
+ 0x1c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_ad7.mmc1_dat7 */
+ >;
+ };
+
+ uart0_pins: pinmux_uart0_pins {
+ pinctrl-single,pins = <
+ 0x170 (PIN_INPUT_PULLUP | MUX_MODE0) /* uart0_rxd.uart0_rxd */
+ 0x174 (PIN_OUTPUT_PULLDOWN | MUX_MODE0) /* uart0_txd.uart0_txd */
+ >;
+ };
+};
+
+&i2c0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins>;
+
+ status = "okay";
+ clock-frequency = <400000>;
+
+ serial_config1: serial_config1@20 {
+ compatible = "nxp,pca9539";
+ reg = <0x20>;
+ };
+
+ serial_config2: serial_config2@21 {
+ compatible = "nxp,pca9539";
+ reg = <0x21>;
+ };
+
+ tps: tps@2d {
+ compatible = "ti,tps65910";
+ reg = <0x2d>;
+ };
+};
+
+/include/ "tps65910.dtsi"
+
+&tps {
+ vcc1-supply = <&vbat>;
+ vcc2-supply = <&vbat>;
+ vcc3-supply = <&vbat>;
+ vcc4-supply = <&vbat>;
+ vcc5-supply = <&vbat>;
+ vcc6-supply = <&vbat>;
+ vcc7-supply = <&vbat>;
+ vccio-supply = <&vbat>;
+
+ regulators {
+ /* vrtc - unused */
+
+ vio_reg: regulator@1 {
+ regulator-name = "vio_1v5,ddr";
+ regulator-min-microvolt = <1500000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd1_reg: regulator@2 {
+ regulator-name = "vdd1,mpu";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vdd2_reg: regulator@3 {
+ regulator-name = "vdd2_1v1,core";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ /* vdd3 - unused */
+
+ /* vdig1 - unused */
+
+ vdig2_reg: regulator@6 {
+ regulator-name = "vdig2_1v8,vdds_pll";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ /* vpll - unused */
+
+ vdac_reg: regulator@8 {
+ regulator-name = "vdac_1v8,vdds";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vaux1_reg: regulator@9 {
+ regulator-name = "vaux1_1v8,usb";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vaux2_reg: regulator@10 {
+ regulator-name = "vaux2_3v3,io";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vaux33_reg: regulator@11 {
+ regulator-name = "vaux33_3v3,usb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vmmc_reg: regulator@12 {
+ regulator-name = "vmmc_3v3,io";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+};
+
+&sham {
+ status = "okay";
+};
+
+&aes {
+ status = "okay";
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins>;
+
+ status = "okay";
+};
+
+&usb {
+ status = "okay";
+};
+
+&usb_ctrl_mod {
+ status = "okay";
+};
+
+&usb0_phy {
+ status = "okay";
+};
+
+&usb1_phy {
+ status = "okay";
+};
+
+&usb0 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&usb1 {
+ status = "okay";
+ dr_mode = "host";
+};
+
+&cppi41dma {
+ status = "okay";
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <5>;
+ phy-mode = "rmii";
+ dual_emac_res_vlan = <2>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <4>;
+ phy-mode = "rmii";
+ dual_emac_res_vlan = <3>;
+};
+
+&mac {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+ dual_emac = <1>;
+ status = "okay";
+};
+
+&davinci_mdio {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_default>;
+ pinctrl-1 = <&davinci_mdio_sleep>;
+ status = "okay";
+};
+
+&mmc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&emmc_pins>;
+ vmmc-supply = <&vmmcsd_fixed>;
+ bus-width = <8>;
+ ti,non-removable;
+ status = "okay";
+};
+
diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi
index 8318105..acd3705 100644
--- a/arch/arm/boot/dts/am33xx.dtsi
+++ b/arch/arm/boot/dts/am33xx.dtsi
@@ -83,6 +83,11 @@
};
};
+ am33xx_control_module: control_module@4a002000 {
+ compatible = "syscon";
+ reg = <0x44e10000 0x7fc>;
+ };
+
am33xx_pinmux: pinmux@44e10800 {
compatible = "pinctrl-single";
reg = <0x44e10800 0x0238>;
@@ -204,6 +209,8 @@
reg = <0x44e09000 0x2000>;
interrupts = <72>;
status = "disabled";
+ dmas = <&edma 26>, <&edma 27>;
+ dma-names = "tx", "rx";
};
uart1: serial@48022000 {
@@ -213,6 +220,8 @@
reg = <0x48022000 0x2000>;
interrupts = <73>;
status = "disabled";
+ dmas = <&edma 28>, <&edma 29>;
+ dma-names = "tx", "rx";
};
uart2: serial@48024000 {
@@ -222,6 +231,8 @@
reg = <0x48024000 0x2000>;
interrupts = <74>;
status = "disabled";
+ dmas = <&edma 30>, <&edma 31>;
+ dma-names = "tx", "rx";
};
uart3: serial@481a6000 {
@@ -333,20 +344,24 @@
interrupts = <91>;
};
- dcan0: d_can@481cc000 {
- compatible = "bosch,d_can";
+ dcan0: can@481cc000 {
+ compatible = "ti,am3352-d_can";
ti,hwmods = "d_can0";
- reg = <0x481cc000 0x2000
- 0x44e10644 0x4>;
+ reg = <0x481cc000 0x2000>;
+ clocks = <&dcan0_fck>;
+ clock-names = "fck";
+ syscon-raminit = <&am33xx_control_module 0x644 0>;
interrupts = <52>;
status = "disabled";
};
- dcan1: d_can@481d0000 {
- compatible = "bosch,d_can";
+ dcan1: can@481d0000 {
+ compatible = "ti,am3352-d_can";
ti,hwmods = "d_can1";
- reg = <0x481d0000 0x2000
- 0x44e10644 0x4>;
+ reg = <0x481d0000 0x2000>;
+ clocks = <&dcan1_fck>;
+ clock-names = "fck";
+ syscon-raminit = <&am33xx_control_module 0x644 1>;
interrupts = <55>;
status = "disabled";
};
@@ -356,6 +371,7 @@
reg = <0x480C8000 0x200>;
interrupts = <77>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <8>;
mbox_wkupm3: wkup_m3 {
@@ -419,7 +435,7 @@
};
rtc: rtc@44e3e000 {
- compatible = "ti,da830-rtc";
+ compatible = "ti,am3352-rtc", "ti,da830-rtc";
reg = <0x44e3e000 0x1000>;
interrupts = <75
76>;
diff --git a/arch/arm/boot/dts/am4372.dtsi b/arch/arm/boot/dts/am4372.dtsi
index 46660ff..d42d786 100644
--- a/arch/arm/boot/dts/am4372.dtsi
+++ b/arch/arm/boot/dts/am4372.dtsi
@@ -57,6 +57,11 @@
cache-level = <2>;
};
+ am43xx_control_module: control_module@4a002000 {
+ compatible = "syscon";
+ reg = <0x44e10000 0x7f4>;
+ };
+
am43xx_pinmux: pinmux@44e10800 {
compatible = "ti,am437-padconf", "pinctrl-single";
reg = <0x44e10800 0x31c>;
@@ -168,6 +173,7 @@
reg = <0x480C8000 0x200>;
interrupts = <GIC_SPI 77 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <8>;
mbox_wkupm3: wkup_m3 {
@@ -667,6 +673,26 @@
};
};
+ tscadc: tscadc@44e0d000 {
+ compatible = "ti,am3359-tscadc";
+ reg = <0x44e0d000 0x1000>;
+ ti,hwmods = "adc_tsc";
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&adc_tsc_fck>;
+ clock-names = "fck";
+ status = "disabled";
+
+ tsc {
+ compatible = "ti,am3359-tsc";
+ };
+
+ adc {
+ #io-channel-cells = <1>;
+ compatible = "ti,am3359-adc";
+ };
+
+ };
+
sham: sham@53100000 {
compatible = "ti,omap5-sham";
ti,hwmods = "sham";
@@ -896,6 +922,28 @@
compatible = "mmio-sram";
reg = <0x40300000 0x40000>; /* 256k */
};
+
+ dcan0: can@481cc000 {
+ compatible = "ti,am4372-d_can", "ti,am3352-d_can";
+ ti,hwmods = "d_can0";
+ clocks = <&dcan0_fck>;
+ clock-names = "fck";
+ reg = <0x481cc000 0x2000>;
+ syscon-raminit = <&am43xx_control_module 0x644 0>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ dcan1: can@481d0000 {
+ compatible = "ti,am4372-d_can", "ti,am3352-d_can";
+ ti,hwmods = "d_can1";
+ clocks = <&dcan1_fck>;
+ clock-names = "fck";
+ reg = <0x481d0000 0x2000>;
+ syscon-raminit = <&am43xx_control_module 0x644 1>;
+ interrupts = <GIC_SPI 49 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/am437x-gp-evm.dts b/arch/arm/boot/dts/am437x-gp-evm.dts
index a521ac0..7eaae4c 100644
--- a/arch/arm/boot/dts/am437x-gp-evm.dts
+++ b/arch/arm/boot/dts/am437x-gp-evm.dts
@@ -254,6 +254,20 @@
0x238 (PIN_OUTPUT_PULLUP | MUX_MODE7)
>;
};
+
+ dcan0_default: dcan0_default_pins {
+ pinctrl-single,pins = <
+ 0x178 (PIN_OUTPUT | MUX_MODE2) /* uart1_ctsn.d_can0_tx */
+ 0x17c (PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_rtsn.d_can0_rx */
+ >;
+ };
+
+ dcan1_default: dcan1_default_pins {
+ pinctrl-single,pins = <
+ 0x180 (PIN_OUTPUT | MUX_MODE2) /* uart1_rxd.d_can1_tx */
+ 0x184 (PIN_INPUT_PULLUP | MUX_MODE2) /* uart1_txd.d_can1_rx */
+ >;
+ };
};
&i2c0 {
@@ -343,6 +357,14 @@
status = "okay";
};
+&tscadc {
+ status = "okay";
+
+ adc {
+ ti,adc-channels = <0 1 2 3 4 5 6 7>;
+ };
+};
+
&ecap0 {
status = "okay";
pinctrl-names = "default";
@@ -511,3 +533,15 @@
};
};
};
+
+&dcan0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dcan0_default>;
+ status = "okay";
+};
+
+&dcan1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&dcan1_default>;
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/am43x-epos-evm.dts b/arch/arm/boot/dts/am43x-epos-evm.dts
index f7e9bba..662261d 100644
--- a/arch/arm/boot/dts/am43x-epos-evm.dts
+++ b/arch/arm/boot/dts/am43x-epos-evm.dts
@@ -438,9 +438,9 @@
status = "okay"; /* Disable QSPI when enabling GPMC (NAND) */
pinctrl-names = "default";
pinctrl-0 = <&nand_flash_x8>;
- ranges = <0 0 0x08000000 0x10000000>; /* CS0: NAND */
+ ranges = <0 0 0x08000000 0x1000000>; /* CS0: 16MB for NAND */
nand@0,0 {
- reg = <0 0 0>; /* CS0, offset 0 */
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
ti,nand-ecc-opt = "bch16";
ti,elm-id = <&elm>;
nand-bus-width = <8>;
@@ -519,6 +519,14 @@
status = "okay";
};
+&tscadc {
+ status = "okay";
+
+ adc {
+ ti,adc-channels = <0 1 2 3 4 5 6 7>;
+ };
+};
+
&ecap0 {
status = "okay";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/am57xx-beagle-x15.dts b/arch/arm/boot/dts/am57xx-beagle-x15.dts
new file mode 100644
index 0000000..49edbda
--- /dev/null
+++ b/arch/arm/boot/dts/am57xx-beagle-x15.dts
@@ -0,0 +1,405 @@
+/*
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+
+#include "dra74x.dtsi"
+#include <dt-bindings/clk/ti-dra7-atl.h>
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+/ {
+ model = "TI AM5728 BeagleBoard-X15";
+ compatible = "ti,am572x-beagle-x15", "ti,am5728", "ti,dra742", "ti,dra74", "ti,dra7";
+
+ aliases {
+ rtc0 = &mcp_rtc;
+ rtc1 = &tps659038_rtc;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x80000000 0x80000000>;
+ };
+
+ vdd_3v3: fixedregulator-vdd_3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "vdd_3v3";
+ vin-supply = <&regen1>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ vtt_fixed: fixedregulator-vtt {
+ /* TPS51200 */
+ compatible = "regulator-fixed";
+ regulator-name = "vtt_fixed";
+ vin-supply = <&smps3_reg>;
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ enable-active-high;
+ gpio = <&gpio7 11 GPIO_ACTIVE_HIGH>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_pins_default>;
+
+ led@0 {
+ label = "beagle-x15:usr0";
+ gpios = <&gpio7 9 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "heartbeat";
+ default-state = "off";
+ };
+
+ led@1 {
+ label = "beagle-x15:usr1";
+ gpios = <&gpio7 8 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "cpu0";
+ default-state = "off";
+ };
+
+ led@2 {
+ label = "beagle-x15:usr2";
+ gpios = <&gpio7 14 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+
+ led@3 {
+ label = "beagle-x15:usr3";
+ gpios = <&gpio7 15 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "ide-disk";
+ default-state = "off";
+ };
+ };
+};
+
+&dra7_pmx_core {
+ leds_pins_default: leds_pins_default {
+ pinctrl-single,pins = <
+ 0x3a8 (PIN_OUTPUT | MUX_MODE14) /* spi1_d1.gpio7_8 */
+ 0x3ac (PIN_OUTPUT | MUX_MODE14) /* spi1_d0.gpio7_9 */
+ 0x3c0 (PIN_OUTPUT | MUX_MODE14) /* spi2_sclk.gpio7_14 */
+ 0x3c4 (PIN_OUTPUT | MUX_MODE14) /* spi2_d1.gpio7_15 */
+ >;
+ };
+
+ i2c1_pins_default: i2c1_pins_default {
+ pinctrl-single,pins = <
+ 0x400 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda.sda */
+ 0x404 (PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl.scl */
+ >;
+ };
+
+ i2c3_pins_default: i2c3_pins_default {
+ pinctrl-single,pins = <
+ 0x2a4 (PIN_INPUT| MUX_MODE10) /* mcasp1_aclkx.i2c3_sda */
+ 0x2a8 (PIN_INPUT| MUX_MODE10) /* mcasp1_fsx.i2c3_scl */
+ >;
+ };
+
+ uart3_pins_default: uart3_pins_default {
+ pinctrl-single,pins = <
+ 0x248 (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_rxd.rxd */
+ 0x24c (PIN_INPUT_SLEW | MUX_MODE0) /* uart3_txd.txd */
+ >;
+ };
+
+ mmc1_pins_default: mmc1_pins_default {
+ pinctrl-single,pins = <
+ 0x36c (PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
+ 0x354 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
+ 0x358 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
+ 0x35c (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
+ 0x360 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
+ 0x364 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
+ 0x368 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
+ >;
+ };
+
+ mmc2_pins_default: mmc2_pins_default {
+ pinctrl-single,pins = <
+ 0x9c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+ 0xb0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+ 0xa0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+ 0xa4 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+ 0xa8 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+ 0xac (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+ 0x8c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+ 0x90 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+ 0x94 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+ 0x98 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+ >;
+ };
+
+ tps659038_pins_default: tps659038_pins_default {
+ pinctrl-single,pins = <
+ 0x418 (PIN_INPUT_PULLUP | MUX_MODE14) /* wakeup0.gpio1_0 */
+ >;
+ };
+
+ tmp102_pins_default: tmp102_pins_default {
+ pinctrl-single,pins = <
+ 0x3C8 (PIN_INPUT_PULLUP | MUX_MODE14) /* spi2_d0.gpio7_16 */
+ >;
+ };
+
+ mcp79410_pins_default: mcp79410_pins_default {
+ pinctrl-single,pins = <
+ 0x424 (PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
+ >;
+ };
+
+ usb1_pins: pinmux_usb1_pins {
+ pinctrl-single,pins = <
+ 0x280 (PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
+ >;
+ };
+
+};
+
+&i2c1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_default>;
+ clock-frequency = <400000>;
+
+ tps659038: tps659038@58 {
+ compatible = "ti,tps659038";
+ reg = <0x58>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <0 IRQ_TYPE_LEVEL_LOW>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tps659038_pins_default>;
+
+ #interrupt-cells = <2>;
+ interrupt-controller;
+
+ ti,system-power-controller;
+
+ tps659038_pmic {
+ compatible = "ti,tps659038-pmic";
+
+ regulators {
+ smps12_reg: smps12 {
+ /* VDD_MPU */
+ regulator-name = "smps12";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1250000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps3_reg: smps3 {
+ /* VDD_DDR */
+ regulator-name = "smps3";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps45_reg: smps45 {
+ /* VDD_DSPEVE, VDD_IVA, VDD_GPU */
+ regulator-name = "smps45";
+ regulator-min-microvolt = < 850000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ smps6_reg: smps6 {
+ /* VDD_CORE */
+ regulator-name = "smps6";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1030000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* SMPS7 unused */
+
+ smps8_reg: smps8 {
+ /* VDD_1V8 */
+ regulator-name = "smps8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ /* SMPS9 unused */
+
+ ldo1_reg: ldo1 {
+ /* VDD_SD */
+ regulator-name = "ldo1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ ldo2_reg: ldo2 {
+ /* VDD_SHV5 */
+ regulator-name = "ldo2";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo3_reg: ldo3 {
+ /* VDDA_1V8_PHY */
+ regulator-name = "ldo3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldo9_reg: ldo9 {
+ /* VDD_RTC */
+ regulator-name = "ldo9";
+ regulator-min-microvolt = <1050000>;
+ regulator-max-microvolt = <1050000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldoln_reg: ldoln {
+ /* VDDA_1V8_PLL */
+ regulator-name = "ldoln";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ ldousb_reg: ldousb {
+ /* VDDA_3V_USB: VDDA_USBHS33 */
+ regulator-name = "ldousb";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ regen1: regen1 {
+ /* VDD_3V3_ON */
+ regulator-name = "regen1";
+ regulator-boot-on;
+ regulator-always-on;
+ };
+ };
+ };
+
+ tps659038_rtc: tps659038_rtc {
+ compatible = "ti,palmas-rtc";
+ interrupt-parent = <&tps659038>;
+ interrupts = <8 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
+ };
+
+ tps659038_pwr_button: tps659038_pwr_button {
+ compatible = "ti,palmas-pwrbutton";
+ interrupt-parent = <&tps659038>;
+ interrupts = <1 IRQ_TYPE_EDGE_FALLING>;
+ wakeup-source;
+ ti,palmas-long-press-seconds = <12>;
+ };
+ };
+
+ tmp102: tmp102@48 {
+ compatible = "ti,tmp102";
+ reg = <0x48>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tmp102_pins_default>;
+ interrupt-parent = <&gpio7>;
+ interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&i2c3 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins_default>;
+ clock-frequency = <400000>;
+
+ mcp_rtc: rtc@6f {
+ compatible = "microchip,mcp7941x";
+ reg = <0x6f>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 2 IRQ_TYPE_LEVEL_LOW>; /* IRQ_SYS_1N */
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcp79410_pins_default>;
+
+ vcc-supply = <&vdd_3v3>;
+ wakeup-source;
+ };
+};
+
+&gpio7 {
+ ti,no-reset-on-init;
+ ti,no-idle-on-init;
+};
+
+&cpu0 {
+ cpu0-supply = <&smps12_reg>;
+ voltage-tolerance = <1>;
+};
+
+&uart3 {
+ status = "okay";
+ interrupts-extended = <&gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+ <&dra7_pmx_core 0x248>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_default>;
+};
+
+&mmc1 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_default>;
+
+ vmmc-supply = <&ldo1_reg>;
+ vmmc_aux-supply = <&vdd_3v3>;
+ pbias-supply = <&pbias_mmc_reg>;
+ bus-width = <4>;
+ cd-gpios = <&gpio6 27 0>; /* gpio 219 */
+};
+
+&mmc2 {
+ status = "okay";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_default>;
+
+ vmmc-supply = <&vdd_3v3>;
+ bus-width = <8>;
+ ti,non-removable;
+ cap-mmc-dual-data-rate;
+};
+
+&sata {
+ status = "okay";
+};
+
+&usb2_phy1 {
+ phy-supply = <&ldousb_reg>;
+};
+
+&usb1 {
+ dr_mode = "host";
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_pins>;
+};
diff --git a/arch/arm/boot/dts/arm-realview-pb1176.dts b/arch/arm/boot/dts/arm-realview-pb1176.dts
new file mode 100644
index 0000000..ff26c7e
--- /dev/null
+++ b/arch/arm/boot/dts/arm-realview-pb1176.dts
@@ -0,0 +1,412 @@
+/*
+ * Copyright 2014 Linaro Ltd
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "skeleton.dtsi"
+
+/ {
+ model = "ARM RealView PB1176";
+ compatible = "arm,realview-pb1176";
+
+ chosen { };
+
+ aliases {
+ serial0 = &pb1176_serial0;
+ serial1 = &pb1176_serial1;
+ serial2 = &pb1176_serial2;
+ serial3 = &pb1176_serial3;
+ serial4 = &fpga_serial;
+ };
+
+ memory {
+ /* 128 MiB memory @ 0x0 */
+ reg = <0x00000000 0x08000000>;
+ };
+
+ /* The voltage to the MMC card is hardwired at 3.3V */
+ vmmc: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "vmmc";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-boot-on;
+ };
+
+ xtal24mhz: xtal24mhz@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ };
+
+ timclk: timclk@1M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <24>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ mclk: mclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ kmiclk: kmiclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ sspclk: sspclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ uartclk: uartclk@24M {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clock-div = <1>;
+ clock-mult = <1>;
+ clocks = <&xtal24mhz>;
+ };
+
+ /* FIXME: this actually hangs off the PLL clocks */
+ pclk: pclk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,realview-pb1176-soc", "simple-bus";
+ regmap = <&syscon>;
+ ranges;
+
+ syscon: syscon@10000000 {
+ compatible = "arm,realview-pb1176-syscon", "syscon";
+ reg = <0x10000000 0x1000>;
+
+ led@08.0 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x01>;
+ label = "versatile:0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ led@08.1 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x02>;
+ label = "versatile:1";
+ linux,default-trigger = "mmc0";
+ default-state = "off";
+ };
+ led@08.2 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x04>;
+ label = "versatile:2";
+ linux,default-trigger = "cpu0";
+ default-state = "off";
+ };
+ led@08.3 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x08>;
+ label = "versatile:3";
+ default-state = "off";
+ };
+ led@08.4 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x10>;
+ label = "versatile:4";
+ default-state = "off";
+ };
+ led@08.5 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x20>;
+ label = "versatile:5";
+ default-state = "off";
+ };
+ led@08.6 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x40>;
+ label = "versatile:6";
+ default-state = "off";
+ };
+ led@08.7 {
+ compatible = "register-bit-led";
+ offset = <0x08>;
+ mask = <0x80>;
+ label = "versatile:7";
+ default-state = "off";
+ };
+ };
+
+ /* Primary DevChip GIC synthesized with the CPU */
+ intc_dc1176: interrupt-controller@10120000 {
+ compatible = "arm,arm1176jzf-devchip-gic", "arm,arm11mp-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x10121000 0x1000>,
+ <0x10120000 0x100>;
+ };
+
+ L2: l2-cache {
+ compatible = "arm,l220-cache";
+ reg = <0x10110000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 13 IRQ_TYPE_LEVEL_HIGH>;
+ cache-unified;
+ cache-level = <2>;
+ /*
+ * Override default cache size, sets and
+ * associativity as these may be erroneously set
+ * up by boot loader(s).
+ */
+ arm,override-auxreg;
+ cache-size = <131072>; // 128kB
+ cache-sets = <512>;
+ cache-line-size = <32>;
+ };
+
+ pmu {
+ compatible = "arm,arm1176-pmu";
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ timer01: timer@10104000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x10104000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>, <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&timclk>, <&timclk>, <&pclk>;
+ clock-names = "timer1", "timer2", "apb_pclk";
+ };
+
+ timer23: timer@10105000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x10105000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
+ arm,sp804-has-irq = <1>;
+ clocks = <&timclk>, <&timclk>, <&pclk>;
+ clock-names = "timer1", "timer2", "apb_pclk";
+ };
+
+ pb1176_rtc: rtc@10108000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x10108000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 14 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ pb1176_gpio0: gpio@1010a000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x1010a000 0x1000>;
+ gpio-controller;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 16 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ pb1176_ssp: ssp@1010b000 {
+ compatible = "arm,pl022", "arm,primecell";
+ reg = <0x1010b000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 17 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sspclk>, <&pclk>;
+ clock-names = "SSPCLK", "apb_pclk";
+ };
+
+ pb1176_serial0: serial@1010c000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1010c000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ pb1176_serial1: serial@1010d000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1010d000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ pb1176_serial2: serial@1010e000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1010e000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 20 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ pb1176_serial3: serial@1010f000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x1010f000 0x1000>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 21 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+ };
+
+ /* These peripherals are inside the FPGA rather than the DevChip */
+ fpga {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+
+ fpga_mci: mmcsd@10005000 {
+ compatible = "arm,pl18x", "arm,primecell";
+ reg = <0x10005000 0x1000>;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 1 IRQ_TYPE_LEVEL_HIGH>,
+ <0 2 IRQ_TYPE_LEVEL_HIGH>;
+ /* Due to frequent FIFO overruns, use just 500 kHz */
+ max-frequency = <500000>;
+ bus-width = <4>;
+ cap-sd-highspeed;
+ cap-mmc-highspeed;
+ clocks = <&mclk>, <&pclk>;
+ clock-names = "mclk", "apb_pclk";
+ vmmc-supply = <&vmmc>;
+ cd-gpios = <&fpga_gpio1 0 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&fpga_gpio1 1 GPIO_ACTIVE_HIGH>;
+ };
+
+ fpga_kmi0: kmi@10006000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x10006000 0x1000>;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&kmiclk>, <&pclk>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ fpga_kmi1: kmi@10007000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x10007000 0x1000>;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 4 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&kmiclk>, <&pclk>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ fpga_charlcd: charlcd@10008000 {
+ compatible = "arm,versatile-lcd";
+ reg = <0x10008000 0x1000>;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ fpga_serial: serial@10009000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x10009000 0x1000>;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 6 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&uartclk>, <&pclk>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ /* This GIC on the board is cascaded off the DevChip GIC */
+ intc_fpga1176: interrupt-controller@10040000 {
+ compatible = "arm,arm1176jzf-devchip-gic", "arm,arm11mp-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <1>;
+ interrupt-controller;
+ reg = <0x10041000 0x1000>,
+ <0x10040000 0x100>;
+ interrupt-parent = <&intc_dc1176>;
+ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ fpga_gpio0: gpio@10014000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x10014000 0x1000>;
+ gpio-controller;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ fpga_gpio1: gpio@10015000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x10015000 0x1000>;
+ gpio-controller;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+ fpga_rtc: rtc@10017000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x10017000 0x1000>;
+ interrupt-parent = <&intc_fpga1176>;
+ interrupts = <0 25 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&pclk>;
+ clock-names = "apb_pclk";
+ };
+
+
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-db.dts b/arch/arm/boot/dts/armada-370-db.dts
index a495e58..1466580 100644
--- a/arch/arm/boot/dts/armada-370-db.dts
+++ b/arch/arm/boot/dts/armada-370-db.dts
@@ -75,6 +75,7 @@
clock-frequency = <100000>;
status = "okay";
audio_codec: audio-codec@4a {
+ #sound-dai-cells = <0>;
compatible = "cirrus,cs42l51";
reg = <0x4a>;
};
@@ -102,30 +103,6 @@
broken-cd;
};
- pinctrl {
- /*
- * These pins might be muxed as I2S by
- * the bootloader, but it conflicts
- * with the real I2S pins that are
- * muxed using i2s_pins. We must mux
- * those pins to a function other than
- * I2S.
- */
- pinctrl-0 = <&hog_pins1 &hog_pins2>;
- pinctrl-names = "default";
-
- hog_pins1: hog-pins1 {
- marvell,pins = "mpp6", "mpp8", "mpp10",
- "mpp12", "mpp13";
- marvell,function = "gpio";
- };
-
- hog_pins2: hog-pins2 {
- marvell,pins = "mpp5", "mpp7", "mpp9";
- marvell,function = "gpo";
- };
- };
-
usb@50000 {
status = "okay";
};
@@ -135,6 +112,8 @@
};
spi0: spi@10600 {
+ pinctrl-0 = <&spi0_pins2>;
+ pinctrl-names = "default";
status = "okay";
spi-flash@0 {
@@ -167,17 +146,84 @@
};
sound {
- compatible = "marvell,a370db-audio";
- marvell,audio-controller = <&audio_controller>;
- marvell,audio-codec = <&audio_codec &spdif_out &spdif_in>;
- status = "okay";
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "Armada 370 DB Audio";
+ simple-audio-card,mclk-fs = <256>;
+ simple-audio-card,widgets =
+ "Headphone", "Out Jack",
+ "Line", "In Jack";
+ simple-audio-card,routing =
+ "Out Jack", "HPL",
+ "Out Jack", "HPR",
+ "AIN1L", "In Jack",
+ "AIN1L", "In Jack";
+ status = "okay";
+
+ simple-audio-card,dai-link@0 {
+ format = "i2s";
+ cpu {
+ sound-dai = <&audio_controller 0>;
+ };
+
+ codec {
+ sound-dai = <&audio_codec>;
+ };
+ };
+
+ simple-audio-card,dai-link@1 {
+ format = "i2s";
+ cpu {
+ sound-dai = <&audio_controller 1>;
+ };
+
+ codec {
+ sound-dai = <&spdif_out>;
+ };
+ };
+
+ simple-audio-card,dai-link@2 {
+ format = "i2s";
+ cpu {
+ sound-dai = <&audio_controller 1>;
+ };
+
+ codec {
+ sound-dai = <&spdif_in>;
+ };
+ };
};
spdif_out: spdif-out {
- compatible = "linux,spdif-dit";
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dit";
};
spdif_in: spdif-in {
- compatible = "linux,spdif-dir";
+ #sound-dai-cells = <0>;
+ compatible = "linux,spdif-dir";
+ };
+};
+
+&pinctrl {
+ /*
+ * These pins might be muxed as I2S by
+ * the bootloader, but it conflicts
+ * with the real I2S pins that are
+ * muxed using i2s_pins. We must mux
+ * those pins to a function other than
+ * I2S.
+ */
+ pinctrl-0 = <&hog_pins1 &hog_pins2>;
+ pinctrl-names = "default";
+
+ hog_pins1: hog-pins1 {
+ marvell,pins = "mpp6", "mpp8", "mpp10",
+ "mpp12", "mpp13";
+ marvell,function = "gpio";
+ };
+
+ hog_pins2: hog-pins2 {
+ marvell,pins = "mpp5", "mpp7", "mpp9";
+ marvell,function = "gpo";
};
};
diff --git a/arch/arm/boot/dts/armada-370-mirabox.dts b/arch/arm/boot/dts/armada-370-mirabox.dts
index 2b6d24e..e1b0eb6 100644
--- a/arch/arm/boot/dts/armada-370-mirabox.dts
+++ b/arch/arm/boot/dts/armada-370-mirabox.dts
@@ -54,18 +54,6 @@
status = "okay";
};
- pinctrl {
- pwr_led_pin: pwr-led-pin {
- marvell,pins = "mpp63";
- marvell,function = "gpo";
- };
-
- stat_led_pins: stat-led-pins {
- marvell,pins = "mpp64", "mpp65";
- marvell,function = "gpio";
- };
- };
-
gpio_leds {
compatible = "gpio-leds";
pinctrl-names = "default";
@@ -169,3 +157,16 @@
};
};
};
+
+&pinctrl {
+ pwr_led_pin: pwr-led-pin {
+ marvell,pins = "mpp63";
+ marvell,function = "gpo";
+ };
+
+ stat_led_pins: stat-led-pins {
+ marvell,pins = "mpp64", "mpp65";
+ marvell,function = "gpio";
+ };
+};
+
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn102.dts b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
index 3aebd93..4e24932 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn102.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn102.dts
@@ -35,7 +35,7 @@
pcie-controller {
status = "okay";
- /* Connected to Marvell SATA controller */
+ /* Connected to Marvell 88SE9170 SATA controller */
pcie@1,0 {
/* Port 0, Lane 0 */
status = "okay";
@@ -53,53 +53,12 @@
status = "okay";
};
+ /* eSATA interface */
sata@a0000 {
- nr-ports = <2>;
+ nr-ports = <1>;
status = "okay";
};
- pinctrl {
- power_led_pin: power-led-pin {
- marvell,pins = "mpp57";
- marvell,function = "gpio";
- };
-
- sata1_led_pin: sata1-led-pin {
- marvell,pins = "mpp15";
- marvell,function = "gpio";
- };
-
- sata2_led_pin: sata2-led-pin {
- marvell,pins = "mpp14";
- marvell,function = "gpio";
- };
-
- backup_led_pin: backup-led-pin {
- marvell,pins = "mpp56";
- marvell,function = "gpio";
- };
-
- backup_button_pin: backup-button-pin {
- marvell,pins = "mpp58";
- marvell,function = "gpio";
- };
-
- power_button_pin: power-button-pin {
- marvell,pins = "mpp62";
- marvell,function = "gpio";
- };
-
- reset_button_pin: reset-button-pin {
- marvell,pins = "mpp6";
- marvell,function = "gpio";
- };
-
- poweroff: poweroff {
- marvell,pins = "mpp8";
- marvell,function = "gpio";
- };
- };
-
mdio {
pinctrl-0 = <&mdio_pins>;
pinctrl-names = "default";
@@ -204,20 +163,20 @@
default-state = "keep";
};
- green-sata1-led {
- label = "rn102:green:sata1";
+ blue-sata1-led {
+ label = "rn102:blue:sata1";
gpios = <&gpio0 15 GPIO_ACTIVE_LOW>;
default-state = "on";
};
- green-sata2-led {
- label = "rn102:green:sata2";
+ blue-sata2-led {
+ label = "rn102:blue:sata2";
gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
default-state = "on";
};
- green-backup-led {
- label = "rn102:green:backup";
+ blue-backup-led {
+ label = "rn102:blue:backup";
gpios = <&gpio1 24 GPIO_ACTIVE_LOW>;
default-state = "on";
};
@@ -256,3 +215,45 @@
gpios = <&gpio0 8 GPIO_ACTIVE_LOW>;
};
};
+
+&pinctrl {
+ power_led_pin: power-led-pin {
+ marvell,pins = "mpp57";
+ marvell,function = "gpio";
+ };
+
+ sata1_led_pin: sata1-led-pin {
+ marvell,pins = "mpp15";
+ marvell,function = "gpio";
+ };
+
+ sata2_led_pin: sata2-led-pin {
+ marvell,pins = "mpp14";
+ marvell,function = "gpio";
+ };
+
+ backup_led_pin: backup-led-pin {
+ marvell,pins = "mpp56";
+ marvell,function = "gpio";
+ };
+
+ backup_button_pin: backup-button-pin {
+ marvell,pins = "mpp58";
+ marvell,function = "gpio";
+ };
+
+ power_button_pin: power-button-pin {
+ marvell,pins = "mpp62";
+ marvell,function = "gpio";
+ };
+
+ reset_button_pin: reset-button-pin {
+ marvell,pins = "mpp6";
+ marvell,function = "gpio";
+ };
+
+ poweroff: poweroff {
+ marvell,pins = "mpp8";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-netgear-rn104.dts b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
index c2f414b..30586e47 100644
--- a/arch/arm/boot/dts/armada-370-netgear-rn104.dts
+++ b/arch/arm/boot/dts/armada-370-netgear-rn104.dts
@@ -53,38 +53,6 @@
status = "okay";
};
- pinctrl {
- poweroff: poweroff {
- marvell,pins = "mpp60";
- marvell,function = "gpio";
- };
-
- backup_button_pin: backup-button-pin {
- marvell,pins = "mpp52";
- marvell,function = "gpio";
- };
-
- power_button_pin: power-button-pin {
- marvell,pins = "mpp62";
- marvell,function = "gpio";
- };
-
- backup_led_pin: backup-led-pin {
- marvell,pins = "mpp63";
- marvell,function = "gpo";
- };
-
- power_led_pin: power-led-pin {
- marvell,pins = "mpp64";
- marvell,function = "gpio";
- };
-
- reset_button_pin: reset-button-pin {
- marvell,pins = "mpp65";
- marvell,function = "gpio";
- };
- };
-
mdio {
pinctrl-0 = <&mdio_pins>;
pinctrl-names = "default";
@@ -269,3 +237,35 @@
gpios = <&gpio1 28 GPIO_ACTIVE_LOW>;
};
};
+
+&pinctrl {
+ poweroff: poweroff {
+ marvell,pins = "mpp60";
+ marvell,function = "gpio";
+ };
+
+ backup_button_pin: backup-button-pin {
+ marvell,pins = "mpp52";
+ marvell,function = "gpio";
+ };
+
+ power_button_pin: power-button-pin {
+ marvell,pins = "mpp62";
+ marvell,function = "gpio";
+ };
+
+ backup_led_pin: backup-led-pin {
+ marvell,pins = "mpp63";
+ marvell,function = "gpo";
+ };
+
+ power_led_pin: power-led-pin {
+ marvell,pins = "mpp64";
+ marvell,function = "gpio";
+ };
+
+ reset_button_pin: reset-button-pin {
+ marvell,pins = "mpp65";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-rd.dts b/arch/arm/boot/dts/armada-370-rd.dts
index f57a8f84..3943089 100644
--- a/arch/arm/boot/dts/armada-370-rd.dts
+++ b/arch/arm/boot/dts/armada-370-rd.dts
@@ -59,18 +59,6 @@
};
internal-regs {
- pinctrl {
- fan_pins: fan-pins {
- marvell,pins = "mpp8";
- marvell,function = "gpio";
- };
-
- led_pins: led-pins {
- marvell,pins = "mpp32";
- marvell,function = "gpio";
- };
- };
-
serial@12000 {
status = "okay";
};
@@ -85,10 +73,6 @@
phy0: ethernet-phy@0 {
reg = <0>;
};
-
- phy1: ethernet-phy@1 {
- reg = <1>;
- };
};
ethernet@70000 {
@@ -100,8 +84,11 @@
pinctrl-0 = <&ge1_rgmii_pins>;
pinctrl-names = "default";
status = "okay";
- phy = <&phy1>;
phy-mode = "rgmii-id";
+ fixed-link {
+ speed = <1000>;
+ full-duplex;
+ };
};
mvsdio@d4000 {
@@ -173,4 +160,56 @@
};
};
};
+
+ dsa@0 {
+ compatible = "marvell,dsa";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ dsa,ethernet = <&eth1>;
+ dsa,mii-bus = <&mdio>;
+
+ switch@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x10 0>; /* MDIO address 16, switch 0 in tree */
+
+ port@0 {
+ reg = <0>;
+ label = "lan0";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan1";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan2";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan3";
+ };
+
+ port@5 {
+ reg = <5>;
+ label = "cpu";
+ };
+ };
+ };
};
+
+&pinctrl {
+ fan_pins: fan-pins {
+ marvell,pins = "mpp8";
+ marvell,function = "gpio";
+ };
+
+ led_pins: led-pins {
+ marvell,pins = "mpp32";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-synology-ds213j.dts b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
new file mode 100644
index 0000000..70fecde
--- /dev/null
+++ b/arch/arm/boot/dts/armada-370-synology-ds213j.dts
@@ -0,0 +1,316 @@
+/*
+ * Device Tree file for Synology DS213j
+ *
+ * Copyright (C) 2014, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Note: this Device Tree assumes that the bootloader has remapped the
+ * internal registers to 0xf1000000 (instead of the old 0xd0000000).
+ * The 0xf1000000 is the default used by the recent, DT-capable, U-Boot
+ * bootloaders provided by Marvell. It is used in recent versions of
+ * DSM software provided by Synology. Nonetheless, some earlier boards
+ * were delivered with an older version of u-boot that left internal
+ * registers mapped at 0xd0000000. If you have such a device you will
+ * not be able to directly boot a kernel based on this Device Tree. In
+ * that case, the preferred solution is to update your bootloader (e.g.
+ * by upgrading to latest version of DSM, or building a new one and
+ * installing it from u-boot prompt) or adjust the Devive Tree
+ * (s/0xf1000000/0xd0000000/ in 'ranges' below).
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "armada-370.dtsi"
+
+/ {
+ model = "Synology DS213j";
+ compatible = "synology,ds213j", "marvell,armada370",
+ "marvell,armada-370-xp";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlyprintk";
+ stdout-path = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x20000000>; /* 512 MB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0xe0) 0 0xfff00000 0x100000>;
+
+ internal-regs {
+
+ /* RTC provided by Seiko S-35390A I2C RTC chip below */
+ rtc@10300 {
+ status = "disabled";
+ };
+
+ spi0: spi@10600 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q064";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <20000000>;
+
+ /*
+ * Warning!
+ *
+ * Synology u-boot uses its compiled-in environment
+ * and it seems Synology did not care to change u-boot
+ * default configuration in order to allow saving a
+ * modified environment at a sensible location. So,
+ * if you do a 'saveenv' under u-boot, your modified
+ * environment will be saved at 1MB after the start
+ * of the flash, i.e. in the middle of the uImage.
+ * For that reason, it is strongly advised not to
+ * change the default environment, unless you know
+ * what you are doing.
+ */
+ partition@00000000 { /* u-boot */
+ label = "RedBoot";
+ reg = <0x00000000 0x000c0000>; /* 768KB */
+ };
+
+ partition@000c0000 { /* uImage */
+ label = "zImage";
+ reg = <0x000c0000 0x002d0000>; /* 2880KB */
+ };
+
+ partition@00390000 { /* uInitramfs */
+ label = "rd.gz";
+ reg = <0x00390000 0x00440000>; /* 4250KB */
+ };
+
+ partition@007d0000 { /* MAC address and serial number */
+ label = "vendor";
+ reg = <0x007d0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007e0000 {
+ label = "RedBoot config";
+ reg = <0x007e0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007f0000 {
+ label = "FIS directory";
+ reg = <0x007f0000 0x00010000>; /* 64KB */
+ };
+ };
+ };
+
+ i2c@11000 {
+ compatible = "marvell,mv64xxx-i2c";
+ pinctrl-0 = <&i2c0_pins>;
+ pinctrl-names = "default";
+ clock-frequency = <400000>;
+ status = "okay";
+
+ /* Main device RTC chip */
+ s35390a: s35390a@30 {
+ compatible = "sii,s35390a";
+ reg = <0x30>;
+ };
+ };
+
+ /* Connected to a header on device's PCB */
+ serial@12000 {
+ status = "okay";
+ };
+
+ /* Connected to a TI MSP430F2111 for power control */
+ serial@12100 {
+ status = "okay";
+ };
+
+ poweroff@12100 {
+ compatible = "synology,power-off";
+ reg = <0x12100 0x100>;
+ clocks = <&coreclk 0>;
+ };
+
+ /* rear USB port, near reset button */
+ usb@50000 {
+ status = "okay";
+ };
+
+ /* rear USB port, near RJ45 port */
+ usb@51000 {
+ status = "okay";
+ };
+
+ mdio {
+ phy1: ethernet-phy@1 { /* Marvell 88E1512 */
+ reg = <1>;
+ };
+ };
+
+ ethernet@70000 {
+ status = "okay";
+ phy = <&phy1>;
+ phy-mode = "sgmii";
+ };
+
+ sata@a0000 {
+ nr-ports = <2>;
+ status = "okay";
+ };
+ };
+ };
+
+ gpio-fan-32-38 {
+ status = "okay";
+ compatible = "gpio-fan";
+ pinctrl-0 = <&fan_ctrl_low_pin &fan_ctrl_mid_pin
+ &fan_ctrl_high_pin &fan_alarm_pin>;
+ pinctrl-names = "default";
+ gpios = <&gpio1 31 GPIO_ACTIVE_HIGH
+ &gpio2 0 GPIO_ACTIVE_HIGH
+ &gpio2 1 GPIO_ACTIVE_HIGH>;
+ alarm-gpios = <&gpio1 6 GPIO_ACTIVE_HIGH>;
+ gpio-fan,speed-map = < 0 0
+ 1000 1
+ 1150 2
+ 1350 4
+ 1500 3
+ 1650 5
+ 1750 6
+ 1900 7 >;
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+ pinctrl-0 = <&disk1_led_pin
+ &disk2_led_pin>;
+ pinctrl-names = "default";
+
+ disk1-led-amber {
+ label = "synology:amber:disk1";
+ gpios = <&gpio0 31 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ };
+
+ disk2-led-amber {
+ label = "synology:amber:disk2";
+ gpios = <&gpio1 0 GPIO_ACTIVE_LOW>;
+ default-state = "keep";
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&sata1_pwr_pin &sata2_pwr_pin>;
+ pinctrl-names = "default";
+
+ sata1_regulator: sata1-regulator {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "SATA1 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <2000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 5 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata2_regulator: sata2-regulator {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "SATA2 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <4000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 30 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&pinctrl {
+ disk1_led_pin: disk1-led-pin {
+ marvell,pins = "mpp31";
+ marvell,function = "gpio";
+ };
+
+ disk2_led_pin: disk2-led-pin {
+ marvell,pins = "mpp32";
+ marvell,function = "gpio";
+ };
+
+ sata1_pwr_pin: sata1-pwr-pin {
+ marvell,pins = "mpp37";
+ marvell,function = "gpio";
+ };
+
+ sata2_pwr_pin: sata2-pwr-pin {
+ marvell,pins = "mpp62";
+ marvell,function = "gpio";
+ };
+
+ sata1_pres_pin: sata1-pres-pin {
+ marvell,pins = "mpp60";
+ marvell,function = "gpio";
+ };
+
+ sata2_pres_pin: sata2-pres-pin {
+ marvell,pins = "mpp48";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit0_pin: syno-id-bit0-pin {
+ marvell,pins = "mpp55";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit1_pin: syno-id-bit1-pin {
+ marvell,pins = "mpp56";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit2_pin: syno-id-bit2-pin {
+ marvell,pins = "mpp57";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit3_pin: syno-id-bit3-pin {
+ marvell,pins = "mpp58";
+ marvell,function = "gpio";
+ };
+
+ fan_ctrl_low_pin: fan-ctrl-low-pin {
+ marvell,pins = "mpp65";
+ marvell,function = "gpio";
+ };
+
+ fan_ctrl_mid_pin: fan-ctrl-mid-pin {
+ marvell,pins = "mpp64";
+ marvell,function = "gpio";
+ };
+
+ fan_ctrl_high_pin: fan-ctrl-high-pin {
+ marvell,pins = "mpp63";
+ marvell,function = "gpo";
+ };
+
+ fan_alarm_pin: fan-alarm-pin {
+ marvell,pins = "mpp38";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-370-xp.dtsi b/arch/arm/boot/dts/armada-370-xp.dtsi
index 83286ec..1af4286 100644
--- a/arch/arm/boot/dts/armada-370-xp.dtsi
+++ b/arch/arm/boot/dts/armada-370-xp.dtsi
@@ -151,7 +151,7 @@
status = "disabled";
};
- serial@12000 {
+ uart0: serial@12000 {
compatible = "snps,dw-apb-uart";
reg = <0x12000 0x100>;
reg-shift = <2>;
@@ -160,7 +160,8 @@
clocks = <&coreclk 0>;
status = "disabled";
};
- serial@12100 {
+
+ uart1: serial@12100 {
compatible = "snps,dw-apb-uart";
reg = <0x12100 0x100>;
reg-shift = <2>;
@@ -170,6 +171,10 @@
status = "disabled";
};
+ pinctrl: pin-ctrl@18000 {
+ reg = <0x18000 0x38>;
+ };
+
coredivclk: corediv-clock@18740 {
compatible = "marvell,armada-370-corediv-clock";
reg = <0x18740 0xc>;
@@ -180,7 +185,8 @@
mbusc: mbus-controller@20000 {
compatible = "marvell,mbus-controller";
- reg = <0x20000 0x100>, <0x20180 0x20>;
+ reg = <0x20000 0x100>, <0x20180 0x20>,
+ <0x20250 0x8>;
};
mpic: interrupt-controller@20000 {
@@ -232,7 +238,7 @@
status = "disabled";
};
- mdio {
+ mdio: mdio {
#address-cells = <1>;
#size-cells = <0>;
compatible = "marvell,orion-mdio";
diff --git a/arch/arm/boot/dts/armada-370.dtsi b/arch/arm/boot/dts/armada-370.dtsi
index 6b3c23b..fdb3c12 100644
--- a/arch/arm/boot/dts/armada-370.dtsi
+++ b/arch/arm/boot/dts/armada-370.dtsi
@@ -95,81 +95,30 @@
compatible = "marvell,aurora-outer-cache";
reg = <0x08000 0x1000>;
cache-id-part = <0x100>;
+ cache-unified;
wt-override;
};
- i2c0: i2c@11000 {
- reg = <0x11000 0x20>;
+ /*
+ * Default SPI pinctrl setting, can be overwritten on
+ * board level if a different configuration is used.
+ */
+ spi0: spi@10600 {
+ pinctrl-0 = <&spi0_pins1>;
+ pinctrl-names = "default";
};
- i2c1: i2c@11100 {
- reg = <0x11100 0x20>;
+ spi1: spi@10680 {
+ pinctrl-0 = <&spi1_pins>;
+ pinctrl-names = "default";
};
- system-controller@18200 {
- compatible = "marvell,armada-370-xp-system-controller";
- reg = <0x18200 0x100>;
+ i2c0: i2c@11000 {
+ reg = <0x11000 0x20>;
};
- pinctrl {
- compatible = "marvell,mv88f6710-pinctrl";
- reg = <0x18000 0x38>;
-
- sdio_pins1: sdio-pins1 {
- marvell,pins = "mpp9", "mpp11", "mpp12",
- "mpp13", "mpp14", "mpp15";
- marvell,function = "sd0";
- };
-
- sdio_pins2: sdio-pins2 {
- marvell,pins = "mpp47", "mpp48", "mpp49",
- "mpp50", "mpp51", "mpp52";
- marvell,function = "sd0";
- };
-
- sdio_pins3: sdio-pins3 {
- marvell,pins = "mpp48", "mpp49", "mpp50",
- "mpp51", "mpp52", "mpp53";
- marvell,function = "sd0";
- };
-
- i2c0_pins: i2c0-pins {
- marvell,pins = "mpp2", "mpp3";
- marvell,function = "i2c0";
- };
-
- i2s_pins1: i2s-pins1 {
- marvell,pins = "mpp5", "mpp6", "mpp7",
- "mpp8", "mpp9", "mpp10",
- "mpp12", "mpp13";
- marvell,function = "audio";
- };
-
- i2s_pins2: i2s-pins2 {
- marvell,pins = "mpp49", "mpp47", "mpp50",
- "mpp59", "mpp57", "mpp61",
- "mpp62", "mpp60", "mpp58";
- marvell,function = "audio";
- };
-
- mdio_pins: mdio-pins {
- marvell,pins = "mpp17", "mpp18";
- marvell,function = "ge";
- };
-
- ge0_rgmii_pins: ge0-rgmii-pins {
- marvell,pins = "mpp5", "mpp6", "mpp7", "mpp8",
- "mpp9", "mpp10", "mpp11", "mpp12",
- "mpp13", "mpp14", "mpp15", "mpp16";
- marvell,function = "ge0";
- };
-
- ge1_rgmii_pins: ge1-rgmii-pins {
- marvell,pins = "mpp19", "mpp20", "mpp21", "mpp22",
- "mpp23", "mpp24", "mpp25", "mpp26",
- "mpp27", "mpp28", "mpp29", "mpp30";
- marvell,function = "ge1";
- };
+ i2c1: i2c@11100 {
+ reg = <0x11100 0x20>;
};
gpio0: gpio@18100 {
@@ -205,6 +154,26 @@
interrupts = <91>;
};
+ /*
+ * Default UART pinctrl setting without RTS/CTS, can
+ * be overwritten on board level if a different
+ * configuration is used.
+ */
+ uart0: serial@12000 {
+ pinctrl-0 = <&uart0_pins>;
+ pinctrl-names = "default";
+ };
+
+ uart1: serial@12100 {
+ pinctrl-0 = <&uart1_pins>;
+ pinctrl-names = "default";
+ };
+
+ system-controller@18200 {
+ compatible = "marvell,armada-370-xp-system-controller";
+ reg = <0x18200 0x100>;
+ };
+
gateclk: clock-gating-control@18220 {
compatible = "marvell,armada-370-gating-clock";
reg = <0x18220 0x4>;
@@ -249,6 +218,7 @@
};
audio_controller: audio-controller@30000 {
+ #sound-dai-cells = <1>;
compatible = "marvell,armada370-audio";
reg = <0x30000 0x4000>;
interrupts = <93>;
@@ -305,3 +275,91 @@
};
};
};
+
+&pinctrl {
+ compatible = "marvell,mv88f6710-pinctrl";
+
+ spi0_pins1: spi0-pins1 {
+ marvell,pins = "mpp33", "mpp34",
+ "mpp35", "mpp36";
+ marvell,function = "spi0";
+ };
+
+ spi0_pins2: spi0_pins2 {
+ marvell,pins = "mpp32", "mpp63",
+ "mpp64", "mpp65";
+ marvell,function = "spi0";
+ };
+
+ spi1_pins: spi1-pins {
+ marvell,pins = "mpp49", "mpp50",
+ "mpp51", "mpp52";
+ marvell,function = "spi1";
+ };
+
+ uart0_pins: uart0-pins {
+ marvell,pins = "mpp0", "mpp1";
+ marvell,function = "uart0";
+ };
+
+ uart1_pins: uart1-pins {
+ marvell,pins = "mpp41", "mpp42";
+ marvell,function = "uart1";
+ };
+
+ sdio_pins1: sdio-pins1 {
+ marvell,pins = "mpp9", "mpp11", "mpp12",
+ "mpp13", "mpp14", "mpp15";
+ marvell,function = "sd0";
+ };
+
+ sdio_pins2: sdio-pins2 {
+ marvell,pins = "mpp47", "mpp48", "mpp49",
+ "mpp50", "mpp51", "mpp52";
+ marvell,function = "sd0";
+ };
+
+ sdio_pins3: sdio-pins3 {
+ marvell,pins = "mpp48", "mpp49", "mpp50",
+ "mpp51", "mpp52", "mpp53";
+ marvell,function = "sd0";
+ };
+
+ i2c0_pins: i2c0-pins {
+ marvell,pins = "mpp2", "mpp3";
+ marvell,function = "i2c0";
+ };
+
+ i2s_pins1: i2s-pins1 {
+ marvell,pins = "mpp5", "mpp6", "mpp7",
+ "mpp8", "mpp9", "mpp10",
+ "mpp12", "mpp13";
+ marvell,function = "audio";
+ };
+
+ i2s_pins2: i2s-pins2 {
+ marvell,pins = "mpp49", "mpp47", "mpp50",
+ "mpp59", "mpp57", "mpp61",
+ "mpp62", "mpp60", "mpp58";
+ marvell,function = "audio";
+ };
+
+ mdio_pins: mdio-pins {
+ marvell,pins = "mpp17", "mpp18";
+ marvell,function = "ge";
+ };
+
+ ge0_rgmii_pins: ge0-rgmii-pins {
+ marvell,pins = "mpp5", "mpp6", "mpp7", "mpp8",
+ "mpp9", "mpp10", "mpp11", "mpp12",
+ "mpp13", "mpp14", "mpp15", "mpp16";
+ marvell,function = "ge0";
+ };
+
+ ge1_rgmii_pins: ge1-rgmii-pins {
+ marvell,pins = "mpp19", "mpp20", "mpp21", "mpp22",
+ "mpp23", "mpp24", "mpp25", "mpp26",
+ "mpp27", "mpp28", "mpp29", "mpp30";
+ marvell,function = "ge1";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-375.dtsi b/arch/arm/boot/dts/armada-375.dtsi
index de65714..9721e55 100644
--- a/arch/arm/boot/dts/armada-375.dtsi
+++ b/arch/arm/boot/dts/armada-375.dtsi
@@ -36,6 +36,12 @@
#clock-cells = <0>;
clock-frequency = <2000000000>;
};
+ /* 25 MHz reference crystal */
+ refclk: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ };
};
cpus {
@@ -366,13 +372,15 @@
<&gic GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>,
<&mpic 5>,
<&mpic 6>;
- clocks = <&coreclk 0>;
+ clocks = <&coreclk 0>, <&refclk>;
+ clock-names = "nbclk", "fixed";
};
watchdog@20300 {
compatible = "marvell,armada-375-wdt";
reg = <0x20300 0x34>, <0x20704 0x4>, <0x18254 0x4>;
- clocks = <&coreclk 0>;
+ clocks = <&coreclk 0>, <&refclk>;
+ clock-names = "nbclk", "fixed";
};
cpurst@20800 {
diff --git a/arch/arm/boot/dts/armada-385-db.dts b/arch/arm/boot/dts/armada-385-db.dts
index 1af886f..2aaa9d2 100644
--- a/arch/arm/boot/dts/armada-385-db.dts
+++ b/arch/arm/boot/dts/armada-385-db.dts
@@ -116,11 +116,11 @@
};
sdhci@d8000 {
- clock-frequency = <200000000>;
broken-cd;
wp-inverted;
bus-width = <8>;
status = "okay";
+ no-1-8-v;
};
usb3@f0000 {
diff --git a/arch/arm/boot/dts/armada-38x.dtsi b/arch/arm/boot/dts/armada-38x.dtsi
index 242d0ec..74391da 100644
--- a/arch/arm/boot/dts/armada-38x.dtsi
+++ b/arch/arm/boot/dts/armada-38x.dtsi
@@ -25,9 +25,9 @@
aliases {
gpio0 = &gpio0;
gpio1 = &gpio1;
- eth0 = &eth0;
- eth1 = &eth1;
- eth2 = &eth2;
+ ethernet0 = &eth0;
+ ethernet1 = &eth1;
+ ethernet2 = &eth2;
};
soc {
diff --git a/arch/arm/boot/dts/armada-xp-axpwifiap.dts b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
index a55a97a..ca0200e 100644
--- a/arch/arm/boot/dts/armada-xp-axpwifiap.dts
+++ b/arch/arm/boot/dts/armada-xp-axpwifiap.dts
@@ -60,40 +60,6 @@
};
internal-regs {
- pinctrl {
- pinctrl-0 = <&pmx_phy_int>;
- pinctrl-names = "default";
-
- pmx_ge0: pmx-ge0 {
- marvell,pins = "mpp0", "mpp1", "mpp2", "mpp3",
- "mpp4", "mpp5", "mpp6", "mpp7",
- "mpp8", "mpp9", "mpp10", "mpp11";
- marvell,function = "ge0";
- };
-
- pmx_ge1: pmx-ge1 {
- marvell,pins = "mpp12", "mpp13", "mpp14", "mpp15",
- "mpp16", "mpp17", "mpp18", "mpp19",
- "mpp20", "mpp21", "mpp22", "mpp23";
- marvell,function = "ge1";
- };
-
- pmx_keys: pmx-keys {
- marvell,pins = "mpp33";
- marvell,function = "gpio";
- };
-
- pmx_spi: pmx-spi {
- marvell,pins = "mpp36", "mpp37", "mpp38", "mpp39";
- marvell,function = "spi";
- };
-
- pmx_phy_int: pmx-phy-int {
- marvell,pins = "mpp32";
- marvell,function = "gpio";
- };
- };
-
serial@12000 {
status = "okay";
};
@@ -118,14 +84,14 @@
};
ethernet@70000 {
- pinctrl-0 = <&pmx_ge0>;
+ pinctrl-0 = <&ge0_rgmii_pins>;
pinctrl-names = "default";
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
ethernet@74000 {
- pinctrl-0 = <&pmx_ge1>;
+ pinctrl-0 = <&ge1_rgmii_pins>;
pinctrl-names = "default";
status = "okay";
phy = <&phy1>;
@@ -134,8 +100,6 @@
spi0: spi@10600 {
status = "okay";
- pinctrl-0 = <&pmx_spi>;
- pinctrl-names = "default";
spi-flash@0 {
#address-cells = <1>;
@@ -152,7 +116,7 @@
compatible = "gpio-keys";
#address-cells = <1>;
#size-cells = <0>;
- pinctrl-0 = <&pmx_keys>;
+ pinctrl-0 = <&keys_pin>;
pinctrl-names = "default";
button@1 {
@@ -162,3 +126,18 @@
};
};
};
+
+&pinctrl {
+ pinctrl-0 = <&phy_int_pin>;
+ pinctrl-names = "default";
+
+ keys_pin: keys-pin {
+ marvell,pins = "mpp33";
+ marvell,function = "gpio";
+ };
+
+ phy_int_pin: phy-int-pin {
+ marvell,pins = "mpp32";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-gp.dts b/arch/arm/boot/dts/armada-xp-gp.dts
index 0478c55..ea86736 100644
--- a/arch/arm/boot/dts/armada-xp-gp.dts
+++ b/arch/arm/boot/dts/armada-xp-gp.dts
@@ -23,6 +23,7 @@
*/
/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
#include "armada-xp-mv78460.dtsi"
/ {
@@ -48,6 +49,14 @@
<0x00000001 0x00000000 0x00000001 0x00000000>;
};
+ cpus {
+ pm_pic {
+ ctrl-gpios = <&gpio0 16 GPIO_ACTIVE_LOW>,
+ <&gpio0 17 GPIO_ACTIVE_LOW>,
+ <&gpio0 18 GPIO_ACTIVE_LOW>;
+ };
+ };
+
soc {
ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000
@@ -115,7 +124,15 @@
serial@12300 {
status = "okay";
};
-
+ pinctrl {
+ pinctrl-0 = <&pic_pins>;
+ pinctrl-names = "default";
+ pic_pins: pic-pins-0 {
+ marvell,pins = "mpp16", "mpp17",
+ "mpp18";
+ marvell,function = "gpio";
+ };
+ };
sata@a0000 {
nr-ports = <2>;
status = "okay";
diff --git a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
index 469cf71..a2ef93c 100644
--- a/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
+++ b/arch/arm/boot/dts/armada-xp-lenovo-ix4-300d.dts
@@ -22,7 +22,7 @@
chosen {
bootargs = "console=ttyS0,115200 earlyprintk";
- stdout-path = "/soc/internal-regs/serial@12000";
+ stdout-path = &uart0;
};
memory {
@@ -51,37 +51,6 @@
};
internal-regs {
- pinctrl {
- poweroff_pin: poweroff-pin {
- marvell,pins = "mpp24";
- marvell,function = "gpio";
- };
-
- power_button_pin: power-button-pin {
- marvell,pins = "mpp44";
- marvell,function = "gpio";
- };
-
- reset_button_pin: reset-button-pin {
- marvell,pins = "mpp45";
- marvell,function = "gpio";
- };
- select_button_pin: select-button-pin {
- marvell,pins = "mpp41";
- marvell,function = "gpio";
- };
-
- scroll_button_pin: scroll-button-pin {
- marvell,pins = "mpp42";
- marvell,function = "gpio";
- };
-
- hdd_led_pin: hdd-led-pin {
- marvell,pins = "mpp26";
- marvell,function = "gpio";
- };
- };
-
serial@12000 {
status = "okay";
};
@@ -97,12 +66,16 @@
};
ethernet@70000 {
+ pinctrl-0 = <&ge0_rgmii_pins>;
+ pinctrl-names = "default";
status = "okay";
phy = <&phy0>;
phy-mode = "rgmii-id";
};
ethernet@74000 {
+ pinctrl-0 = <&ge1_rgmii_pins>;
+ pinctrl-names = "default";
status = "okay";
phy = <&phy1>;
phy-mode = "rgmii-id";
@@ -125,6 +98,11 @@
reg = <0x2e>;
};
+ eeprom@50 {
+ compatible = "atmel,24c64";
+ reg = <0x50>;
+ };
+
pcf8563@51 {
compatible = "nxp,pcf8563";
reg = <0x51>;
@@ -226,7 +204,7 @@
gpio-controller;
#gpio-cells = <2>;
reg = <0>;
- registers-number = <2>;
+ registers-number = <1>;
spi-max-frequency = <100000>;
};
};
@@ -282,3 +260,34 @@
gpios = <&gpio0 24 GPIO_ACTIVE_HIGH>;
};
};
+
+&pinctrl {
+ poweroff_pin: poweroff-pin {
+ marvell,pins = "mpp24";
+ marvell,function = "gpio";
+ };
+
+ power_button_pin: power-button-pin {
+ marvell,pins = "mpp44";
+ marvell,function = "gpio";
+ };
+
+ reset_button_pin: reset-button-pin {
+ marvell,pins = "mpp45";
+ marvell,function = "gpio";
+ };
+ select_button_pin: select-button-pin {
+ marvell,pins = "mpp41";
+ marvell,function = "gpio";
+ };
+
+ scroll_button_pin: scroll-button-pin {
+ marvell,pins = "mpp42";
+ marvell,function = "gpio";
+ };
+
+ hdd_led_pin: hdd-led-pin {
+ marvell,pins = "mpp26";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-mv78230.dtsi b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
index 2592e1c..281ccd2 100644
--- a/arch/arm/boot/dts/armada-xp-mv78230.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78230.dtsi
@@ -167,17 +167,6 @@
};
internal-regs {
- pinctrl {
- compatible = "marvell,mv78230-pinctrl";
- reg = <0x18000 0x38>;
-
- sdio_pins: sdio-pins {
- marvell,pins = "mpp30", "mpp31", "mpp32",
- "mpp33", "mpp34", "mpp35";
- marvell,function = "sd0";
- };
- };
-
gpio0: gpio@18100 {
compatible = "marvell,orion-gpio";
reg = <0x18100 0x40>;
@@ -202,3 +191,7 @@
};
};
};
+
+&pinctrl {
+ compatible = "marvell,mv78230-pinctrl";
+};
diff --git a/arch/arm/boot/dts/armada-xp-mv78260.dtsi b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
index 480e237..d7a8d0b 100644
--- a/arch/arm/boot/dts/armada-xp-mv78260.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78260.dtsi
@@ -251,17 +251,6 @@
};
internal-regs {
- pinctrl {
- compatible = "marvell,mv78260-pinctrl";
- reg = <0x18000 0x38>;
-
- sdio_pins: sdio-pins {
- marvell,pins = "mpp30", "mpp31", "mpp32",
- "mpp33", "mpp34", "mpp35";
- marvell,function = "sd0";
- };
- };
-
gpio0: gpio@18100 {
compatible = "marvell,orion-gpio";
reg = <0x18100 0x40>;
@@ -305,3 +294,7 @@
};
};
};
+
+&pinctrl {
+ compatible = "marvell,mv78260-pinctrl";
+};
diff --git a/arch/arm/boot/dts/armada-xp-mv78460.dtsi b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
index 2c7b1fe..9c40c13 100644
--- a/arch/arm/boot/dts/armada-xp-mv78460.dtsi
+++ b/arch/arm/boot/dts/armada-xp-mv78460.dtsi
@@ -289,17 +289,6 @@
};
internal-regs {
- pinctrl {
- compatible = "marvell,mv78460-pinctrl";
- reg = <0x18000 0x38>;
-
- sdio_pins: sdio-pins {
- marvell,pins = "mpp30", "mpp31", "mpp32",
- "mpp33", "mpp34", "mpp35";
- marvell,function = "sd0";
- };
- };
-
gpio0: gpio@18100 {
compatible = "marvell,orion-gpio";
reg = <0x18100 0x40>;
@@ -343,3 +332,7 @@
};
};
};
+
+&pinctrl {
+ compatible = "marvell,mv78460-pinctrl";
+};
diff --git a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
index 7d8f328..d81430a 100644
--- a/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
+++ b/arch/arm/boot/dts/armada-xp-netgear-rn2120.dts
@@ -55,86 +55,10 @@
};
internal-regs {
- pinctrl {
- poweroff: poweroff {
- marvell,pins = "mpp42";
- marvell,function = "gpio";
- };
-
- power_button_pin: power-button-pin {
- marvell,pins = "mpp27";
- marvell,function = "gpio";
- };
-
- reset_button_pin: reset-button-pin {
- marvell,pins = "mpp41";
- marvell,function = "gpio";
- };
-
- sata1_led_pin: sata1-led-pin {
- marvell,pins = "mpp31";
- marvell,function = "gpio";
- };
-
- sata2_led_pin: sata2-led-pin {
- marvell,pins = "mpp40";
- marvell,function = "gpio";
- };
-
- sata3_led_pin: sata3-led-pin {
- marvell,pins = "mpp44";
- marvell,function = "gpio";
- };
-
- sata4_led_pin: sata4-led-pin {
- marvell,pins = "mpp47";
- marvell,function = "gpio";
- };
-
- sata1_power_pin: sata1-power-pin {
- marvell,pins = "mpp24";
- marvell,function = "gpio";
- };
-
- sata2_power_pin: sata2-power-pin {
- marvell,pins = "mpp25";
- marvell,function = "gpio";
- };
-
- sata3_power_pin: sata3-power-pin {
- marvell,pins = "mpp26";
- marvell,function = "gpio";
- };
-
- sata4_power_pin: sata4-power-pin {
- marvell,pins = "mpp28";
- marvell,function = "gpio";
- };
-
- sata1_pres_pin: sata1-pres-pin {
- marvell,pins = "mpp32";
- marvell,function = "gpio";
- };
-
- sata2_pres_pin: sata2-pres-pin {
- marvell,pins = "mpp33";
- marvell,function = "gpio";
- };
-
- sata3_pres_pin: sata3-pres-pin {
- marvell,pins = "mpp34";
- marvell,function = "gpio";
- };
-
- sata4_pres_pin: sata4-pres-pin {
- marvell,pins = "mpp35";
- marvell,function = "gpio";
- };
-
- err_led_pin: err-led-pin {
- marvell,pins = "mpp45";
- marvell,function = "gpio";
- };
+ /* Two rear eSATA ports */
+ sata@a0000 {
+ nr-ports = <2>;
+ status = "okay";
};
serial@12000 {
@@ -328,3 +252,85 @@
gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
};
};
+
+&pinctrl {
+ poweroff: poweroff {
+ marvell,pins = "mpp42";
+ marvell,function = "gpio";
+ };
+
+ power_button_pin: power-button-pin {
+ marvell,pins = "mpp27";
+ marvell,function = "gpio";
+ };
+
+ reset_button_pin: reset-button-pin {
+ marvell,pins = "mpp41";
+ marvell,function = "gpio";
+ };
+
+ sata1_led_pin: sata1-led-pin {
+ marvell,pins = "mpp31";
+ marvell,function = "gpio";
+ };
+
+ sata2_led_pin: sata2-led-pin {
+ marvell,pins = "mpp40";
+ marvell,function = "gpio";
+ };
+
+ sata3_led_pin: sata3-led-pin {
+ marvell,pins = "mpp44";
+ marvell,function = "gpio";
+ };
+
+ sata4_led_pin: sata4-led-pin {
+ marvell,pins = "mpp47";
+ marvell,function = "gpio";
+ };
+
+ sata1_power_pin: sata1-power-pin {
+ marvell,pins = "mpp24";
+ marvell,function = "gpio";
+ };
+
+ sata2_power_pin: sata2-power-pin {
+ marvell,pins = "mpp25";
+ marvell,function = "gpio";
+ };
+
+ sata3_power_pin: sata3-power-pin {
+ marvell,pins = "mpp26";
+ marvell,function = "gpio";
+ };
+
+ sata4_power_pin: sata4-power-pin {
+ marvell,pins = "mpp28";
+ marvell,function = "gpio";
+ };
+
+ sata1_pres_pin: sata1-pres-pin {
+ marvell,pins = "mpp32";
+ marvell,function = "gpio";
+ };
+
+ sata2_pres_pin: sata2-pres-pin {
+ marvell,pins = "mpp33";
+ marvell,function = "gpio";
+ };
+
+ sata3_pres_pin: sata3-pres-pin {
+ marvell,pins = "mpp34";
+ marvell,function = "gpio";
+ };
+
+ sata4_pres_pin: sata4-pres-pin {
+ marvell,pins = "mpp35";
+ marvell,function = "gpio";
+ };
+
+ err_led_pin: err-led-pin {
+ marvell,pins = "mpp45";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
index 4e5a59e..6f6b091 100644
--- a/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
+++ b/arch/arm/boot/dts/armada-xp-openblocks-ax3-4.dts
@@ -77,12 +77,7 @@
serial@12100 {
status = "okay";
};
- pinctrl {
- led_pins: led-pins-0 {
- marvell,pins = "mpp49", "mpp51", "mpp53";
- marvell,function = "gpio";
- };
- };
+
leds {
compatible = "gpio-leds";
pinctrl-names = "default";
@@ -187,3 +182,10 @@
};
};
};
+
+&pinctrl {
+ led_pins: led-pins-0 {
+ marvell,pins = "mpp49", "mpp51", "mpp53";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp-synology-ds414.dts b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
new file mode 100644
index 0000000..749fdba
--- /dev/null
+++ b/arch/arm/boot/dts/armada-xp-synology-ds414.dts
@@ -0,0 +1,330 @@
+/*
+ * Device Tree file for Synology DS414
+ *
+ * Copyright (C) 2014, Arnaud EBALARD <arno@natisbad.org>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ *
+ * Note: this Device Tree assumes that the bootloader has remapped the
+ * internal registers to 0xf1000000 (instead of the old 0xd0000000).
+ * The 0xf1000000 is the default used by the recent, DT-capable, U-Boot
+ * bootloaders provided by Marvell. It is used in recent versions of
+ * DSM software provided by Synology. Nonetheless, some earlier boards
+ * were delivered with an older version of u-boot that left internal
+ * registers mapped at 0xd0000000. If you have such a device you will
+ * not be able to directly boot a kernel based on this Device Tree. In
+ * that case, the preferred solution is to update your bootloader (e.g.
+ * by upgrading to latest version of DSM, or building a new one and
+ * installing it from u-boot prompt) or adjust the Devive Tree
+ * (s/0xf1000000/0xd0000000/ in 'ranges' below).
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/input/input.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "armada-xp-mv78230.dtsi"
+
+/ {
+ model = "Synology DS414";
+ compatible = "synology,ds414", "marvell,armadaxp-mv78230",
+ "marvell,armadaxp", "marvell,armada-370-xp";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlyprintk";
+ stdout-path = &uart0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0 0x00000000 0 0x40000000>; /* 1GB */
+ };
+
+ soc {
+ ranges = <MBUS_ID(0xf0, 0x01) 0 0 0xf1000000 0x100000
+ MBUS_ID(0x01, 0x1d) 0 0 0xfff00000 0x100000>;
+
+ pcie-controller {
+ status = "okay";
+
+ /*
+ * Connected to Marvell 88SX7042 SATA-II controller
+ * handling the four disks.
+ */
+ pcie@1,0 {
+ /* Port 0, Lane 0 */
+ status = "okay";
+ };
+
+ /*
+ * Connected to EtronTech EJ168A XHCI controller
+ * providing the two rear USB 3.0 ports.
+ */
+ pcie@5,0 {
+ /* Port 1, Lane 0 */
+ status = "okay";
+ };
+ };
+
+ internal-regs {
+
+ /* RTC is provided by Seiko S-35390A below */
+ rtc@10300 {
+ status = "disabled";
+ };
+
+ spi0: spi@10600 {
+ status = "okay";
+
+ spi-flash@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "micron,n25q064";
+ reg = <0>; /* Chip select 0 */
+ spi-max-frequency = <20000000>;
+
+ /*
+ * Warning!
+ *
+ * Synology u-boot uses its compiled-in environment
+ * and it seems Synology did not care to change u-boot
+ * default configuration in order to allow saving a
+ * modified environment at a sensible location. So,
+ * if you do a 'saveenv' under u-boot, your modified
+ * environment will be saved at 1MB after the start
+ * of the flash, i.e. in the middle of the uImage.
+ * For that reason, it is strongly advised not to
+ * change the default environment, unless you know
+ * what you are doing.
+ */
+ partition@00000000 { /* u-boot */
+ label = "RedBoot";
+ reg = <0x00000000 0x000d0000>; /* 832KB */
+ };
+
+ partition@000c0000 { /* uImage */
+ label = "zImage";
+ reg = <0x000d0000 0x002d0000>; /* 2880KB */
+ };
+
+ partition@003a0000 { /* uInitramfs */
+ label = "rd.gz";
+ reg = <0x003a0000 0x00430000>; /* 4250KB */
+ };
+
+ partition@007d0000 { /* MAC address and serial number */
+ label = "vendor";
+ reg = <0x007d0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007e0000 {
+ label = "RedBoot config";
+ reg = <0x007e0000 0x00010000>; /* 64KB */
+ };
+
+ partition@007f0000 {
+ label = "FIS directory";
+ reg = <0x007f0000 0x00010000>; /* 64KB */
+ };
+ };
+ };
+
+ i2c@11000 {
+ clock-frequency = <400000>;
+ status = "okay";
+
+ s35390a: s35390a@30 {
+ compatible = "sii,s35390a";
+ reg = <0x30>;
+ };
+ };
+
+ /* Connected to a header on device's PCB. This
+ * provides the main console for the device.
+ *
+ * Warning: the device may not boot with a 3.3V
+ * USB-serial converter connected when the power
+ * button is pressed. The converter needs to be
+ * connected a few seconds after pressing the
+ * power button. This is possibly due to UART0_TXD
+ * pin being sampled at reset (bit 0 of SAR).
+ */
+ serial@12000 {
+ status = "okay";
+ };
+
+ /* Connected to a Microchip PIC16F883 for power control */
+ serial@12100 {
+ status = "okay";
+ };
+
+ poweroff@12100 {
+ compatible = "synology,power-off";
+ reg = <0x12100 0x100>;
+ clocks = <&coreclk 0>;
+ };
+
+ /* Front USB 2.0 port */
+ usb@50000 {
+ status = "okay";
+ };
+
+ mdio {
+ phy0: ethernet-phy@0 { /* Marvell 88E1512 */
+ reg = <0>;
+ };
+
+ phy1: ethernet-phy@1 { /* Marvell 88E1512 */
+ reg = <1>;
+ };
+ };
+
+ ethernet@70000 {
+ status = "okay";
+ pinctrl-0 = <&ge0_rgmii_pins>;
+ pinctrl-names = "default";
+ phy = <&phy1>;
+ phy-mode = "rgmii-id";
+ };
+
+ ethernet@74000 {
+ pinctrl-0 = <&ge1_rgmii_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+ phy = <&phy0>;
+ phy-mode = "rgmii-id";
+ };
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-0 = <&sata1_pwr_pin &sata2_pwr_pin
+ &sata3_pwr_pin &sata4_pwr_pin>;
+ pinctrl-names = "default";
+
+ sata1_regulator: sata1-regulator {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "SATA1 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <2000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 10 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata2_regulator: sata2-regulator {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "SATA2 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <4000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 12 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata3_regulator: sata3-regulator {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "SATA3 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <6000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+ };
+
+ sata4_regulator: sata4-regulator {
+ compatible = "regulator-fixed";
+ reg = <4>;
+ regulator-name = "SATA4 Power";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ startup-delay-us = <8000000>;
+ enable-active-high;
+ regulator-always-on;
+ regulator-boot-on;
+ gpio = <&gpio1 14 GPIO_ACTIVE_HIGH>;
+ };
+ };
+};
+
+&pinctrl {
+ sata1_pwr_pin: sata1-pwr-pin {
+ marvell,pins = "mpp42";
+ marvell,function = "gpio";
+ };
+
+ sata2_pwr_pin: sata2-pwr-pin {
+ marvell,pins = "mpp44";
+ marvell,function = "gpio";
+ };
+
+ sata3_pwr_pin: sata3-pwr-pin {
+ marvell,pins = "mpp45";
+ marvell,function = "gpio";
+ };
+
+ sata4_pwr_pin: sata4-pwr-pin {
+ marvell,pins = "mpp46";
+ marvell,function = "gpio";
+ };
+
+ sata1_pres_pin: sata1-pres-pin {
+ marvell,pins = "mpp34";
+ marvell,function = "gpio";
+ };
+
+ sata2_pres_pin: sata2-pres-pin {
+ marvell,pins = "mpp35";
+ marvell,function = "gpio";
+ };
+
+ sata3_pres_pin: sata3-pres-pin {
+ marvell,pins = "mpp40";
+ marvell,function = "gpio";
+ };
+
+ sata4_pres_pin: sata4-pres-pin {
+ marvell,pins = "mpp41";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit0_pin: syno-id-bit0-pin {
+ marvell,pins = "mpp26";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit1_pin: syno-id-bit1-pin {
+ marvell,pins = "mpp28";
+ marvell,function = "gpio";
+ };
+
+ syno_id_bit2_pin: syno-id-bit2-pin {
+ marvell,pins = "mpp29";
+ marvell,function = "gpio";
+ };
+
+ fan1_alarm_pin: fan1-alarm-pin {
+ marvell,pins = "mpp33";
+ marvell,function = "gpio";
+ };
+
+ fan2_alarm_pin: fan2-alarm-pin {
+ marvell,pins = "mpp32";
+ marvell,function = "gpio";
+ };
+};
diff --git a/arch/arm/boot/dts/armada-xp.dtsi b/arch/arm/boot/dts/armada-xp.dtsi
index bff9f6c..62c3ba9 100644
--- a/arch/arm/boot/dts/armada-xp.dtsi
+++ b/arch/arm/boot/dts/armada-xp.dtsi
@@ -35,13 +35,24 @@
};
internal-regs {
+ sdramc@1400 {
+ compatible = "marvell,armada-xp-sdram-controller";
+ reg = <0x1400 0x500>;
+ };
+
L2: l2-cache {
compatible = "marvell,aurora-system-cache";
reg = <0x08000 0x1000>;
cache-id-part = <0x100>;
+ cache-unified;
wt-override;
};
+ spi0: spi@10600 {
+ pinctrl-0 = <&spi0_pins>;
+ pinctrl-names = "default";
+ };
+
i2c0: i2c@11000 {
compatible = "marvell,mv78230-i2c", "marvell,mv64xxx-i2c";
reg = <0x11000 0x100>;
@@ -52,8 +63,10 @@
reg = <0x11100 0x100>;
};
- serial@12200 {
+ uart2: serial@12200 {
compatible = "snps,dw-apb-uart";
+ pinctrl-0 = <&uart2_pins>;
+ pinctrl-names = "default";
reg = <0x12200 0x100>;
reg-shift = <2>;
interrupts = <43>;
@@ -61,8 +74,11 @@
clocks = <&coreclk 0>;
status = "disabled";
};
- serial@12300 {
+
+ uart3: serial@12300 {
compatible = "snps,dw-apb-uart";
+ pinctrl-0 = <&uart3_pins>;
+ pinctrl-names = "default";
reg = <0x12300 0x100>;
reg-shift = <2>;
interrupts = <44>;
@@ -199,3 +215,54 @@
};
};
};
+
+&pinctrl {
+ ge0_gmii_pins: ge0-gmii-pins {
+ marvell,pins =
+ "mpp0", "mpp1", "mpp2", "mpp3",
+ "mpp4", "mpp5", "mpp6", "mpp7",
+ "mpp8", "mpp9", "mpp10", "mpp11",
+ "mpp12", "mpp13", "mpp14", "mpp15",
+ "mpp16", "mpp17", "mpp18", "mpp19",
+ "mpp20", "mpp21", "mpp22", "mpp23";
+ marvell,function = "ge0";
+ };
+
+ ge0_rgmii_pins: ge0-rgmii-pins {
+ marvell,pins =
+ "mpp0", "mpp1", "mpp2", "mpp3",
+ "mpp4", "mpp5", "mpp6", "mpp7",
+ "mpp8", "mpp9", "mpp10", "mpp11";
+ marvell,function = "ge0";
+ };
+
+ ge1_rgmii_pins: ge1-rgmii-pins {
+ marvell,pins =
+ "mpp12", "mpp13", "mpp14", "mpp15",
+ "mpp16", "mpp17", "mpp18", "mpp19",
+ "mpp20", "mpp21", "mpp22", "mpp23";
+ marvell,function = "ge1";
+ };
+
+ sdio_pins: sdio-pins {
+ marvell,pins = "mpp30", "mpp31", "mpp32",
+ "mpp33", "mpp34", "mpp35";
+ marvell,function = "sd0";
+ };
+
+ spi0_pins: spi0-pins {
+ marvell,pins = "mpp36", "mpp37",
+ "mpp38", "mpp39";
+ marvell,function = "spi";
+ };
+
+ uart2_pins: uart2-pins {
+ marvell,pins = "mpp42", "mpp43";
+ marvell,function = "uart2";
+ };
+
+ uart3_pins: uart3-pins {
+ marvell,pins = "mpp44", "mpp45";
+ marvell,function = "uart3";
+ };
+};
diff --git a/arch/arm/boot/dts/at91sam9263.dtsi b/arch/arm/boot/dts/at91sam9263.dtsi
index 51416c7d..653e439 100644
--- a/arch/arm/boot/dts/at91sam9263.dtsi
+++ b/arch/arm/boot/dts/at91sam9263.dtsi
@@ -677,6 +677,14 @@
};
};
+ can {
+ pinctrl_can_rx_tx: can_rx_tx {
+ atmel,pins =
+ <AT91_PIOA 14 AT91_PERIPH_A AT91_PINCTRL_NONE /* CANRX, conflicts with IRQ0 */
+ AT91_PIOA 13 AT91_PERIPH_A AT91_PINCTRL_NONE>; /* CANTX, conflicts with PCK0 */
+ };
+ };
+
pioA: gpio@fffff200 {
compatible = "atmel,at91rm9200-gpio";
reg = <0xfffff200 0x200>;
@@ -905,6 +913,17 @@
clock-names = "pwm_clk";
status = "disabled";
};
+
+ can: can@fffac000 {
+ compatible = "atmel,at91sam9263-can";
+ reg = <0xfffac000 0x300>;
+ interrupts = <12 IRQ_TYPE_LEVEL_HIGH 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can_rx_tx>;
+ clocks = <&can_clk>;
+ clock-names = "can_clk";
+ status = "disabled";
+ };
};
fb0: fb@0x00700000 {
diff --git a/arch/arm/boot/dts/at91sam9x25.dtsi b/arch/arm/boot/dts/at91sam9x25.dtsi
index c255421..3c5fa33 100644
--- a/arch/arm/boot/dts/at91sam9x25.dtsi
+++ b/arch/arm/boot/dts/at91sam9x25.dtsi
@@ -10,6 +10,7 @@
#include "at91sam9x5_usart3.dtsi"
#include "at91sam9x5_macb0.dtsi"
#include "at91sam9x5_macb1.dtsi"
+#include "at91sam9x5_can.dtsi"
/ {
model = "Atmel AT91SAM9X25 SoC";
diff --git a/arch/arm/boot/dts/at91sam9x35.dtsi b/arch/arm/boot/dts/at91sam9x35.dtsi
index 8eac66c..499cdc8 100644
--- a/arch/arm/boot/dts/at91sam9x35.dtsi
+++ b/arch/arm/boot/dts/at91sam9x35.dtsi
@@ -8,6 +8,7 @@
#include "at91sam9x5.dtsi"
#include "at91sam9x5_macb0.dtsi"
+#include "at91sam9x5_can.dtsi"
/ {
model = "Atmel AT91SAM9X35 SoC";
diff --git a/arch/arm/boot/dts/at91sam9x5.dtsi b/arch/arm/boot/dts/at91sam9x5.dtsi
index 726274f..bbb3ba6 100644
--- a/arch/arm/boot/dts/at91sam9x5.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5.dtsi
@@ -860,6 +860,9 @@
interrupts = <1 IRQ_TYPE_LEVEL_HIGH 7>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_dbgu>;
+ dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(8)>,
+ <&dma1 1 (AT91_DMA_CFG_PER_ID(9) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
+ dma-names = "tx", "rx";
clocks = <&mck>;
clock-names = "usart";
status = "disabled";
@@ -871,6 +874,9 @@
interrupts = <5 IRQ_TYPE_LEVEL_HIGH 5>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart0>;
+ dmas = <&dma0 1 AT91_DMA_CFG_PER_ID(3)>,
+ <&dma0 1 (AT91_DMA_CFG_PER_ID(4) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
+ dma-names = "tx", "rx";
clocks = <&usart0_clk>;
clock-names = "usart";
status = "disabled";
@@ -882,6 +888,9 @@
interrupts = <6 IRQ_TYPE_LEVEL_HIGH 5>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart1>;
+ dmas = <&dma0 1 AT91_DMA_CFG_PER_ID(5)>,
+ <&dma0 1 (AT91_DMA_CFG_PER_ID(6) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
+ dma-names = "tx", "rx";
clocks = <&usart1_clk>;
clock-names = "usart";
status = "disabled";
@@ -893,6 +902,9 @@
interrupts = <7 IRQ_TYPE_LEVEL_HIGH 5>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart2>;
+ dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(12)>,
+ <&dma1 1 (AT91_DMA_CFG_PER_ID(13) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
+ dma-names = "tx", "rx";
clocks = <&usart2_clk>;
clock-names = "usart";
status = "disabled";
diff --git a/arch/arm/boot/dts/at91sam9x5_can.dtsi b/arch/arm/boot/dts/at91sam9x5_can.dtsi
index f44ab77..8eb2f9c 100644
--- a/arch/arm/boot/dts/at91sam9x5_can.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5_can.dtsi
@@ -1,5 +1,5 @@
/*
- * at91sam9x5_macb0.dtsi - Device Tree Include file for AT91SAM9x5 SoC with 1
+ * at91sam9x5_can.dtsi - Device Tree Include file for AT91SAM9x5 SoC with 1
* Ethernet interface.
*
* Copyright (C) 2013 Boris BREZILLON <b.brezillon@overkiz.com>
@@ -20,10 +20,50 @@
reg = <29>;
};
- can1_clk: can1_clk {
- #clock-cells = <0>;
- reg = <30>;
- };
+ can1_clk: can1_clk {
+ #clock-cells = <0>;
+ reg = <30>;
+ };
+ };
+ };
+
+ can0: can@f8000000 {
+ compatible = "atmel,at91sam9x5-can";
+ reg = <0xf8000000 0x300>;
+ interrupts = <29 IRQ_TYPE_LEVEL_HIGH 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can0_rx_tx>;
+ clocks = <&can0_clk>;
+ clock-names = "can_clk";
+ status = "disabled";
+ };
+
+ can1: can@f8004000 {
+ compatible = "atmel,at91sam9x5-can";
+ reg = <0xf8004000 0x300>;
+ interrupts = <30 IRQ_TYPE_LEVEL_HIGH 3>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_can1_rx_tx>;
+ clocks = <&can1_clk>;
+ clock-names = "can_clk";
+ status = "disabled";
+ };
+
+ pinctrl@fffff400 {
+ can0 {
+ pinctrl_can0_rx_tx: can0_rx_tx {
+ atmel,pins =
+ <AT91_PIOA 9 AT91_PERIPH_B AT91_PINCTRL_NONE /* CANRX0, conflicts with DRXD */
+ AT91_PIOA 10 AT91_PERIPH_B AT91_PINCTRL_NONE>; /* CANTX0, conflicts with DTXD */
+ };
+ };
+
+ can1 {
+ pinctrl_can1_rx_tx: can1_rx_tx {
+ atmel,pins =
+ <AT91_PIOA 6 AT91_PERIPH_B AT91_PINCTRL_NONE /* CANRX1, conflicts with RXD1 */
+ AT91_PIOA 5 AT91_PERIPH_B AT91_PINCTRL_NONE>; /* CANTX1, conflicts with TXD1 */
+ };
};
};
};
diff --git a/arch/arm/boot/dts/at91sam9x5_usart3.dtsi b/arch/arm/boot/dts/at91sam9x5_usart3.dtsi
index 140217a5..43bb5b5 100644
--- a/arch/arm/boot/dts/at91sam9x5_usart3.dtsi
+++ b/arch/arm/boot/dts/at91sam9x5_usart3.dtsi
@@ -57,6 +57,9 @@
interrupts = <8 IRQ_TYPE_LEVEL_HIGH 5>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_usart3>;
+ dmas = <&dma1 1 AT91_DMA_CFG_PER_ID(14)>,
+ <&dma1 1 (AT91_DMA_CFG_PER_ID(15) | AT91_DMA_CFG_FIFOCFG_ASAP)>;
+ dma-names = "tx", "rx";
clocks = <&usart3_clk>;
clock-names = "usart";
status = "disabled";
diff --git a/arch/arm/boot/dts/atlas6.dtsi b/arch/arm/boot/dts/atlas6.dtsi
index bb22842..2959866 100644
--- a/arch/arm/boot/dts/atlas6.dtsi
+++ b/arch/arm/boot/dts/atlas6.dtsi
@@ -131,6 +131,7 @@
reg = <0x90020000 0x10000>;
interrupts = <31>;
clocks = <&clks 35>;
+ resets = <&rstc 6>;
};
};
@@ -312,6 +313,7 @@
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clks 19>;
+ resets = <&rstc 26>;
status = "disabled";
};
@@ -327,6 +329,7 @@
#address-cells = <1>;
#size-cells = <0>;
clocks = <&clks 20>;
+ resets = <&rstc 27>;
status = "disabled";
};
@@ -522,6 +525,18 @@
sirf,function = "sdmmc5";
};
};
+ i2s_mclk_pins_a: i2s_mclk@0 {
+ i2s_mclk {
+ sirf,pins = "i2smclkgrp";
+ sirf,function = "i2s_mclk";
+ };
+ };
+ i2s_ext_clk_input_pins_a: i2s_ext_clk_input@0 {
+ i2s_ext_clk_input {
+ sirf,pins = "i2s_ext_clk_inputgrp";
+ sirf,function = "i2s_ext_clk_input";
+ };
+ };
i2s_pins_a: i2s@0 {
i2s {
sirf,pins = "i2sgrp";
diff --git a/arch/arm/boot/dts/bcm-cygnus-clock.dtsi b/arch/arm/boot/dts/bcm-cygnus-clock.dtsi
new file mode 100644
index 0000000..60d8389
--- /dev/null
+++ b/arch/arm/boot/dts/bcm-cygnus-clock.dtsi
@@ -0,0 +1,91 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ osc: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <1>;
+ clock-frequency = <25000000>;
+ };
+
+ apb_clk: apb_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000000>;
+ };
+
+ periph_clk: periph_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <500000000>;
+ };
+
+ sdio_clk: lcpll_ch2 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <200000000>;
+ };
+
+ axi81_clk: axi81_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ };
+
+ keypad_clk: keypad_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <31806>;
+ };
+
+ adc_clk: adc_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1562500>;
+ };
+
+ pwm_clk: pwm_clk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <1000000>;
+ };
+
+ lcd_clk: mipipll_ch1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/bcm-cygnus.dtsi b/arch/arm/boot/dts/bcm-cygnus.dtsi
new file mode 100644
index 0000000..5126f9e
--- /dev/null
+++ b/arch/arm/boot/dts/bcm-cygnus.dtsi
@@ -0,0 +1,140 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+
+#include "skeleton.dtsi"
+
+/ {
+ compatible = "brcm,cygnus";
+ model = "Broadcom Cygnus SoC";
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x0>;
+ };
+ };
+
+ /include/ "bcm-cygnus-clock.dtsi"
+
+ amba {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "arm,amba-bus", "simple-bus";
+ interrupt-parent = <&gic>;
+ ranges;
+
+ wdt@18009000 {
+ compatible = "arm,sp805" , "arm,primecell";
+ reg = <0x18009000 0x1000>;
+ interrupts = <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-names = "apb_pclk";
+ };
+ };
+
+ uart0: serial@18020000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18020000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 73 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
+
+ uart1: serial@18021000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18021000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 74 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
+
+ uart2: serial@18022000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18020000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
+
+ uart3: serial@18023000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x18023000 0x100>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&axi81_clk>;
+ clock-frequency = <100000000>;
+ status = "disabled";
+ };
+
+ gic: interrupt-controller@19021000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0x19021000 0x1000>,
+ <0x19020100 0x100>;
+ };
+
+ L2: l2-cache {
+ compatible = "arm,pl310-cache";
+ reg = <0x19022000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ timer@19020200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x19020200 0x100>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&periph_clk>;
+ };
+
+};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
new file mode 100644
index 0000000..e479515
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835-rpi-b-plus.dts
@@ -0,0 +1,30 @@
+/dts-v1/;
+/include/ "bcm2835-rpi.dtsi"
+
+/ {
+ compatible = "raspberrypi,model-b-plus", "brcm,bcm2835";
+ model = "Raspberry Pi Model B+";
+
+ leds {
+ act {
+ gpios = <&gpio 47 0>;
+ };
+
+ pwr {
+ label = "PWR";
+ gpios = <&gpio 35 0>;
+ default-state = "keep";
+ linux,default-trigger = "default-on";
+ };
+ };
+};
+
+&gpio {
+ pinctrl-0 = <&gpioout &alt0 &i2s_alt0 &alt3>;
+
+ /* I2S interface */
+ i2s_alt0: i2s_alt0 {
+ brcm,pins = <18 19 20 21>;
+ brcm,function = <4>; /* alt0 */
+ };
+};
diff --git a/arch/arm/boot/dts/bcm2835-rpi-b.dts b/arch/arm/boot/dts/bcm2835-rpi-b.dts
index 58a0d60..bafa46f 100644
--- a/arch/arm/boot/dts/bcm2835-rpi-b.dts
+++ b/arch/arm/boot/dts/bcm2835-rpi-b.dts
@@ -1,63 +1,23 @@
/dts-v1/;
-/include/ "bcm2835.dtsi"
+/include/ "bcm2835-rpi.dtsi"
/ {
compatible = "raspberrypi,model-b", "brcm,bcm2835";
model = "Raspberry Pi Model B";
- memory {
- reg = <0 0x10000000>;
- };
-
leds {
- compatible = "gpio-leds";
-
act {
- label = "ACT";
gpios = <&gpio 16 1>;
- default-state = "keep";
- linux,default-trigger = "heartbeat";
};
};
};
&gpio {
- pinctrl-names = "default";
- pinctrl-0 = <&gpioout &alt0 &alt2 &alt3>;
-
- gpioout: gpioout {
- brcm,pins = <6>;
- brcm,function = <1>; /* GPIO out */
- };
-
- alt0: alt0 {
- brcm,pins = <0 1 2 3 4 5 7 8 9 10 11 14 15 40 45>;
- brcm,function = <4>; /* alt0 */
- };
-
- alt3: alt3 {
- brcm,pins = <48 49 50 51 52 53>;
- brcm,function = <7>; /* alt3 */
- };
+ pinctrl-0 = <&gpioout &alt0 &i2s_alt2 &alt3>;
/* I2S interface */
- alt2: alt2 {
+ i2s_alt2: i2s_alt2 {
brcm,pins = <28 29 30 31>;
brcm,function = <6>; /* alt2 */
};
};
-
-&i2c0 {
- status = "okay";
- clock-frequency = <100000>;
-};
-
-&i2c1 {
- status = "okay";
- clock-frequency = <100000>;
-};
-
-&sdhci {
- status = "okay";
- bus-width = <4>;
-};
diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi b/arch/arm/boot/dts/bcm2835-rpi.dtsi
new file mode 100644
index 0000000..c706448
--- /dev/null
+++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
@@ -0,0 +1,51 @@
+/include/ "bcm2835.dtsi"
+
+/ {
+ memory {
+ reg = <0 0x10000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ act {
+ label = "ACT";
+ default-state = "keep";
+ linux,default-trigger = "heartbeat";
+ };
+ };
+};
+
+&gpio {
+ pinctrl-names = "default";
+
+ gpioout: gpioout {
+ brcm,pins = <6>;
+ brcm,function = <1>; /* GPIO out */
+ };
+
+ alt0: alt0 {
+ brcm,pins = <0 1 2 3 4 5 7 8 9 10 11 14 15 40 45>;
+ brcm,function = <4>; /* alt0 */
+ };
+
+ alt3: alt3 {
+ brcm,pins = <48 49 50 51 52 53>;
+ brcm,function = <7>; /* alt3 */
+ };
+};
+
+&i2c0 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+&i2c1 {
+ status = "okay";
+ clock-frequency = <100000>;
+};
+
+&sdhci {
+ status = "okay";
+ bus-width = <4>;
+};
diff --git a/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
new file mode 100644
index 0000000..5fc0fae
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-buffalo-wzr-1750dhp.dts
@@ -0,0 +1,64 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Buffalo WZR-1750DHP
+ *
+ * Copyright (C) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ compatible = "buffalo,wzr-1750dhp", "brcm,bcm4708";
+ model = "Buffalo WZR-1750DHP (BCM4708)";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <200>;
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+
+ aoss {
+ label = "AOSS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 12 GPIO_ACTIVE_LOW>;
+ };
+
+ /* Commit mode set by switch? */
+ mode {
+ label = "Mode";
+ linux,code = <KEY_SETUP>;
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ };
+
+ /* Switch: AP mode */
+ sw_ap {
+ label = "AP";
+ linux,code = <BTN_0>;
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ };
+
+ eject {
+ label = "USB eject";
+ linux,code = <KEY_EJECTCD>;
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
index 3b5259d..4ed7de1 100644
--- a/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6250.dts
@@ -32,4 +32,63 @@
status = "okay";
};
};
+
+ leds {
+ compatible = "gpio-leds";
+
+ logo {
+ label = "bcm53xx:white:logo";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+
+ power0 {
+ label = "bcm53xx:green:power";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ power1 {
+ label = "bcm53xx:amber:power";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ usb {
+ label = "bcm53xx:blue:usb";
+ gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ wireless {
+ label = "bcm53xx:blue:wireless";
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <200>;
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ };
+
+ rfkill {
+ label = "WiFi";
+ linux,code = <KEY_RFKILL>;
+ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
new file mode 100644
index 0000000..12fc2a01
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-netgear-r6300-v2.dts
@@ -0,0 +1,84 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Netgear R6300 V2
+ *
+ * Copyright (C) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ compatible = "netgear,r6300v2", "brcm,bcm4708";
+ model = "Netgear R6300 V2 (BCM4708)";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ logo {
+ label = "bcm53xx:white:logo";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_HIGH>;
+ linux,default-trigger = "default-on";
+ };
+
+ power0 {
+ label = "bcm53xx:green:power";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ power1 {
+ label = "bcm53xx:amber:power";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ usb {
+ label = "bcm53xx:blue:usb";
+ gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ wireless {
+ label = "bcm53xx:blue:wireless";
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <200>;
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ };
+
+ rfkill {
+ label = "WiFi";
+ linux,code = <KEY_RFKILL>;
+ gpios = <&chipcommon 5 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
new file mode 100644
index 0000000..fb76378
--- /dev/null
+++ b/arch/arm/boot/dts/bcm47081-asus-rt-n18u.dts
@@ -0,0 +1,78 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Asus RT-N18U
+ *
+ * Copyright (C) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm47081.dtsi"
+
+/ {
+ compatible = "asus,rt-n18u", "brcm,bcm47081", "brcm,bcm4708";
+ model = "Asus RT-N18U (BCM47081)";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power {
+ label = "bcm53xx:blue:power";
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ usb2 {
+ label = "bcm53xx:blue:usb2";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan {
+ label = "bcm53xx:blue:wan";
+ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ lan {
+ label = "bcm53xx:blue:lan";
+ gpios = <&chipcommon 9 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ usb3 {
+ label = "bcm53xx:blue:usb3";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <200>;
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 7 GPIO_ACTIVE_LOW>;
+ };
+
+ wps {
+ label = "WPS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
new file mode 100644
index 0000000..bbb414f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm47081-buffalo-wzr-600dhp2.dts
@@ -0,0 +1,57 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for Buffalo WZR-600DHP2
+ *
+ * Copyright (C) 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+/dts-v1/;
+
+#include "bcm47081.dtsi"
+
+/ {
+ compatible = "buffalo,wzr-600dhp2", "brcm,bcm47081", "brcm,bcm4708";
+ model = "Buffalo WZR-600DHP2 (BCM47081)";
+
+ chosen {
+ bootargs = "console=ttyS0,115200";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ poll-interval = <200>;
+
+ aoss {
+ label = "AOSS";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&chipcommon 9 GPIO_ACTIVE_LOW>;
+ };
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+
+ /* Switch device mode? */
+ mode {
+ label = "Mode";
+ linux,code = <KEY_SETUP>;
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ };
+
+ eject {
+ label = "USB eject";
+ linux,code = <KEY_EJECTCD>;
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm47081.dtsi b/arch/arm/boot/dts/bcm47081.dtsi
new file mode 100644
index 0000000..f720012
--- /dev/null
+++ b/arch/arm/boot/dts/bcm47081.dtsi
@@ -0,0 +1,26 @@
+/*
+ * Broadcom BCM470X / BCM5301X ARM platform code.
+ * DTS for BCM47081 SoC.
+ *
+ * Copyright © 2014 Rafał Miłecki <zajec5@gmail.com>
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcm5301x.dtsi"
+
+/ {
+ compatible = "brcm,bcm47081";
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x0>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/bcm5301x.dtsi b/arch/arm/boot/dts/bcm5301x.dtsi
index 53c624f..78aec62 100644
--- a/arch/arm/boot/dts/bcm5301x.dtsi
+++ b/arch/arm/boot/dts/bcm5301x.dtsi
@@ -8,6 +8,8 @@
* Licensed under the GNU/GPL. See COPYING for details.
*/
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include "skeleton.dtsi"
@@ -92,4 +94,53 @@
clock-frequency = <400000000>;
};
};
+
+ axi@18000000 {
+ compatible = "brcm,bus-axi";
+ reg = <0x18000000 0x1000>;
+ ranges = <0x00000000 0x18000000 0x00100000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0x000fffff 0xffff>;
+ interrupt-map =
+ /* ChipCommon */
+ <0x00000000 0 &gic GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* USB 2.0 Controller */
+ <0x00021000 0 &gic GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* USB 3.0 Controller */
+ <0x00023000 0 &gic GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* Ethernet Controller 0 */
+ <0x00024000 0 &gic GIC_SPI 147 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* Ethernet Controller 1 */
+ <0x00025000 0 &gic GIC_SPI 148 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* Ethernet Controller 2 */
+ <0x00026000 0 &gic GIC_SPI 149 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* Ethernet Controller 3 */
+ <0x00027000 0 &gic GIC_SPI 150 IRQ_TYPE_LEVEL_HIGH>,
+
+ /* NAND Controller */
+ <0x00028000 0 &gic GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 1 &gic GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 2 &gic GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 3 &gic GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 4 &gic GIC_SPI 68 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 5 &gic GIC_SPI 69 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 6 &gic GIC_SPI 70 IRQ_TYPE_LEVEL_HIGH>,
+ <0x00028000 7 &gic GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+
+ chipcommon: chipcommon@0 {
+ reg = <0x00000000 0x1000>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+ };
+ };
};
diff --git a/arch/arm/boot/dts/bcm911360_entphn.dts b/arch/arm/boot/dts/bcm911360_entphn.dts
new file mode 100644
index 0000000..d2ee952
--- /dev/null
+++ b/arch/arm/boot/dts/bcm911360_entphn.dts
@@ -0,0 +1,53 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+ model = "Cygnus Enterprise Phone (BCM911360_ENTPHN)";
+ compatible = "brcm,bcm11360", "brcm,cygnus";
+
+ aliases {
+ serial0 = &uart3;
+ };
+
+ chosen {
+ stdout-path = &uart3;
+ bootargs = "console=ttyS0,115200";
+ };
+
+ uart3: serial@18023000 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/bcm911360k.dts b/arch/arm/boot/dts/bcm911360k.dts
new file mode 100644
index 0000000..9658d4f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm911360k.dts
@@ -0,0 +1,53 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+ model = "Cygnus SVK (BCM911360K)";
+ compatible = "brcm,bcm11360", "brcm,cygnus";
+
+ aliases {
+ serial0 = &uart3;
+ };
+
+ chosen {
+ stdout-path = &uart3;
+ bootargs = "console=ttyS0,115200";
+ };
+
+ uart3: serial@18023000 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/bcm958300k.dts b/arch/arm/boot/dts/bcm958300k.dts
new file mode 100644
index 0000000..f1bb36f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm958300k.dts
@@ -0,0 +1,53 @@
+/*
+ * BSD LICENSE
+ *
+ * Copyright(c) 2014 Broadcom Corporation. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ * * Neither the name of Broadcom Corporation nor the names of its
+ * contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/dts-v1/;
+
+#include "bcm-cygnus.dtsi"
+
+/ {
+ model = "Cygnus SVK (BCM958300K)";
+ compatible = "brcm,bcm58300", "brcm,cygnus";
+
+ aliases {
+ serial0 = &uart3;
+ };
+
+ chosen {
+ stdout-path = &uart3;
+ bootargs = "console=ttyS0,115200";
+ };
+
+ uart3: serial@18023000 {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
index c72bfd4..86d85d8 100644
--- a/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
+++ b/arch/arm/boot/dts/berlin2-sony-nsz-gs7.dts
@@ -26,4 +26,20 @@
};
};
+&ahci { status = "okay"; };
+
+&eth1 { status = "okay"; };
+
+/* Unpopulated SATA plug on solder side */
+&sata0 { status = "okay"; };
+
+&sata_phy { status = "okay"; };
+
+/* Samsung M8G2FA 8GB eMMC */
+&sdhci2 {
+ non-removable;
+ bus-width = <8>;
+ status = "okay";
+};
+
&uart0 { status = "okay"; };
diff --git a/arch/arm/boot/dts/berlin2.dtsi b/arch/arm/boot/dts/berlin2.dtsi
index 9d7c810..015a06c 100644
--- a/arch/arm/boot/dts/berlin2.dtsi
+++ b/arch/arm/boot/dts/berlin2.dtsi
@@ -53,6 +53,35 @@
ranges = <0 0xf7000000 0x1000000>;
+ sdhci0: sdhci@ab0000 {
+ compatible = "mrvl,pxav3-mmc";
+ reg = <0xab0000 0x200>;
+ clocks = <&chip CLKID_SDIO0XIN>, <&chip CLKID_SDIO0>;
+ clock-names = "io", "core";
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ sdhci1: sdhci@ab0800 {
+ compatible = "mrvl,pxav3-mmc";
+ reg = <0xab0800 0x200>;
+ clocks = <&chip CLKID_SDIO1XIN>, <&chip CLKID_SDIO1>;
+ clock-names = "io", "core";
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ sdhci2: sdhci@ab1000 {
+ compatible = "mrvl,pxav3-mmc";
+ reg = <0xab1000 0x200>;
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_NFC_ECC>, <&chip CLKID_NFC>;
+ clock-names = "io", "core";
+ pinctrl-0 = <&emmc_pmux>;
+ pinctrl-names = "default";
+ status = "disabled";
+ };
+
l2: l2-cache-controller@ac0000 {
compatible = "marvell,tauros3-cache", "arm,pl310-cache";
reg = <0xac0000 0x1000>;
@@ -79,11 +108,47 @@
clocks = <&chip CLKID_TWD>;
};
+ eth1: ethernet@b90000 {
+ compatible = "marvell,pxa168-eth";
+ reg = <0xb90000 0x10000>;
+ clocks = <&chip CLKID_GETH1>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ /* set by bootloader */
+ local-mac-address = [00 00 00 00 00 00];
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy-connection-type = "mii";
+ phy-handle = <&ethphy1>;
+ status = "disabled";
+
+ ethphy1: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
cpu-ctrl@dd0000 {
compatible = "marvell,berlin-cpu-ctrl";
reg = <0xdd0000 0x10000>;
};
+ eth0: ethernet@e50000 {
+ compatible = "marvell,pxa168-eth";
+ reg = <0xe50000 0x10000>;
+ clocks = <&chip CLKID_GETH0>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ /* set by bootloader */
+ local-mac-address = [00 00 00 00 00 00];
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy-connection-type = "mii";
+ phy-handle = <&ethphy0>;
+ status = "disabled";
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
apb@e80000 {
compatible = "simple-bus";
#address-cells = <1>;
@@ -246,12 +311,57 @@
};
};
+ ahci: sata@e90000 {
+ compatible = "marvell,berlin2-ahci", "generic-ahci";
+ reg = <0xe90000 0x1000>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_SATA>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy 0>;
+ status = "disabled";
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy 1>;
+ status = "disabled";
+ };
+ };
+
+ sata_phy: phy@e900a0 {
+ compatible = "marvell,berlin2-sata-phy";
+ reg = <0xe900a0 0x200>;
+ clocks = <&chip CLKID_SATA>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #phy-cells = <1>;
+ status = "disabled";
+
+ sata-phy@0 {
+ reg = <0>;
+ };
+
+ sata-phy@1 {
+ reg = <1>;
+ };
+ };
+
chip: chip-control@ea0000 {
compatible = "marvell,berlin2-chip-ctrl";
#clock-cells = <1>;
+ #reset-cells = <2>;
reg = <0xea0000 0x400>;
clocks = <&refclk>;
clock-names = "refclk";
+
+ emmc_pmux: emmc-pmux {
+ groups = "G26";
+ function = "emmc";
+ };
};
apb@fc0000 {
diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index bcd81ff..30270be 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -11,6 +11,7 @@
/dts-v1/;
#include "berlin2cd.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Google Chromecast";
@@ -24,6 +25,35 @@
device_type = "memory";
reg = <0x00000000 0x20000000>; /* 512 MB */
};
+
+ leds {
+ compatible = "gpio-leds";
+
+ white {
+ label = "white";
+ gpios = <&portc 1 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+
+ red {
+ label = "red";
+ gpios = <&portc 2 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+ };
+};
+
+/*
+ * AzureWave AW-NH387 (Marvell 88W8787)
+ * 802.11b/g/n + Bluetooth 2.1
+ */
+&sdhci0 {
+ non-removable;
+ status = "okay";
};
&uart0 { status = "okay"; };
+
+&usb_phy1 { status = "okay"; };
+
+&usb1 { status = "okay"; };
diff --git a/arch/arm/boot/dts/berlin2cd.dtsi b/arch/arm/boot/dts/berlin2cd.dtsi
index cc1df65..230df3b 100644
--- a/arch/arm/boot/dts/berlin2cd.dtsi
+++ b/arch/arm/boot/dts/berlin2cd.dtsi
@@ -45,6 +45,15 @@
ranges = <0 0xf7000000 0x1000000>;
+ sdhci0: sdhci@ab0000 {
+ compatible = "mrvl,pxav3-mmc";
+ reg = <0xab0000 0x200>;
+ clocks = <&chip CLKID_SDIO0XIN>, <&chip CLKID_SDIO0>;
+ clock-names = "io", "core";
+ interrupts = <GIC_SPI 17 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
l2: l2-cache-controller@ac0000 {
compatible = "arm,pl310-cache";
reg = <0xac0000 0x1000>;
@@ -66,6 +75,58 @@
clocks = <&chip CLKID_TWD>;
};
+ usb_phy0: usb-phy@b74000 {
+ compatible = "marvell,berlin2cd-usb-phy";
+ reg = <0xb74000 0x128>;
+ #phy-cells = <0>;
+ resets = <&chip 0x178 23>;
+ status = "disabled";
+ };
+
+ usb_phy1: usb-phy@b78000 {
+ compatible = "marvell,berlin2cd-usb-phy";
+ reg = <0xb78000 0x128>;
+ #phy-cells = <0>;
+ resets = <&chip 0x178 24>;
+ status = "disabled";
+ };
+
+ eth1: ethernet@b90000 {
+ compatible = "marvell,pxa168-eth";
+ reg = <0xb90000 0x10000>;
+ clocks = <&chip CLKID_GETH1>;
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+ /* set by bootloader */
+ local-mac-address = [00 00 00 00 00 00];
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy-connection-type = "mii";
+ phy-handle = <&ethphy1>;
+ status = "disabled";
+
+ ethphy1: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
+ eth0: ethernet@e50000 {
+ compatible = "marvell,pxa168-eth";
+ reg = <0xe50000 0x10000>;
+ clocks = <&chip CLKID_GETH0>;
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>;
+ /* set by bootloader */
+ local-mac-address = [00 00 00 00 00 00];
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy-connection-type = "mii";
+ phy-handle = <&ethphy0>;
+ status = "disabled";
+
+ ethphy0: ethernet-phy@0 {
+ reg = <0>;
+ };
+ };
+
apb@e80000 {
compatible = "simple-bus";
#address-cells = <1>;
@@ -231,6 +292,7 @@
chip: chip-control@ea0000 {
compatible = "marvell,berlin2cd-chip-ctrl";
#clock-cells = <1>;
+ #reset-cells = <2>;
reg = <0xea0000 0x400>;
clocks = <&refclk>;
clock-names = "refclk";
@@ -241,6 +303,26 @@
};
};
+ usb0: usb@ed0000 {
+ compatible = "chipidea,usb2";
+ reg = <0xed0000 0x200>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_USB0>;
+ phys = <&usb_phy0>;
+ phy-names = "usb-phy";
+ status = "disabled";
+ };
+
+ usb1: usb@ee0000 {
+ compatible = "chipidea,usb2";
+ reg = <0xee0000 0x200>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_USB1>;
+ phys = <&usb_phy1>;
+ phy-names = "usb-phy";
+ status = "disabled";
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
index ea1f99b..28e7e20 100644
--- a/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
+++ b/arch/arm/boot/dts/berlin2q-marvell-dmp.dts
@@ -7,6 +7,8 @@
*/
/dts-v1/;
+
+#include <dt-bindings/gpio/gpio.h>
#include "berlin2q.dtsi"
/ {
@@ -21,6 +23,39 @@
choosen {
bootargs = "console=ttyS0,115200 earlyprintk";
};
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_usb0_vbus: regulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb0_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&portb 8 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usb1_vbus: regulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb1_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&portb 10 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+
+ reg_usb2_vbus: regulator@2 {
+ compatible = "regulator-fixed";
+ regulator-name = "usb2_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&portb 12 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ };
+ };
};
&sdhci1 {
@@ -46,6 +81,32 @@
status = "okay";
};
+&usb_phy0 {
+ status = "okay";
+};
+
+&usb_phy2 {
+ status = "okay";
+};
+
+&usb0 {
+ vbus-supply = <&reg_usb0_vbus>;
+ status = "okay";
+};
+
+&usb2 {
+ vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+};
+
&eth0 {
status = "okay";
};
+
+&sata0 {
+ status = "okay";
+};
+
+&sata_phy {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/berlin2q.dtsi b/arch/arm/boot/dts/berlin2q.dtsi
index 891d56b..35253c9 100644
--- a/arch/arm/boot/dts/berlin2q.dtsi
+++ b/arch/arm/boot/dts/berlin2q.dtsi
@@ -114,6 +114,40 @@
#interrupt-cells = <3>;
};
+ usb_phy2: phy@a2f400 {
+ compatible = "marvell,berlin2-usb-phy";
+ reg = <0xa2f400 0x128>;
+ #phy-cells = <0>;
+ resets = <&chip 0x104 14>;
+ status = "disabled";
+ };
+
+ usb2: usb@a30000 {
+ compatible = "chipidea,usb2";
+ reg = <0xa30000 0x10000>;
+ interrupts = <GIC_SPI 52 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_USB2>;
+ phys = <&usb_phy2>;
+ phy-names = "usb-phy";
+ status = "disabled";
+ };
+
+ usb_phy0: phy@b74000 {
+ compatible = "marvell,berlin2-usb-phy";
+ reg = <0xb74000 0x128>;
+ #phy-cells = <0>;
+ resets = <&chip 0x104 12>;
+ status = "disabled";
+ };
+
+ usb_phy1: phy@b78000 {
+ compatible = "marvell,berlin2-usb-phy";
+ reg = <0xb78000 0x128>;
+ #phy-cells = <0>;
+ resets = <&chip 0x104 13>;
+ status = "disabled";
+ };
+
eth0: ethernet@b90000 {
compatible = "marvell,pxa168-eth";
reg = <0xb90000 0x10000>;
@@ -123,6 +157,7 @@
local-mac-address = [00 00 00 00 00 00];
#address-cells = <1>;
#size-cells = <0>;
+ phy-connection-type = "mii";
phy-handle = <&ethphy0>;
status = "disabled";
@@ -255,7 +290,6 @@
reg = <0x2c14 0x14>;
clocks = <&chip CLKID_CFG>;
clock-names = "timer";
- status = "disabled";
};
timer2: timer@2c28 {
@@ -349,6 +383,7 @@
chip: chip-control@ea0000 {
compatible = "marvell,berlin2q-chip-ctrl";
#clock-cells = <1>;
+ #reset-cells = <2>;
reg = <0xea0000 0x400>, <0xdd0170 0x10>;
clocks = <&refclk>;
clock-names = "refclk";
@@ -364,6 +399,65 @@
};
};
+ ahci: sata@e90000 {
+ compatible = "marvell,berlin2q-ahci", "generic-ahci";
+ reg = <0xe90000 0x1000>;
+ interrupts = <GIC_SPI 7 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_SATA>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata0: sata-port@0 {
+ reg = <0>;
+ phys = <&sata_phy 0>;
+ status = "disabled";
+ };
+
+ sata1: sata-port@1 {
+ reg = <1>;
+ phys = <&sata_phy 1>;
+ status = "disabled";
+ };
+ };
+
+ sata_phy: phy@e900a0 {
+ compatible = "marvell,berlin2q-sata-phy";
+ reg = <0xe900a0 0x200>;
+ clocks = <&chip CLKID_SATA>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #phy-cells = <1>;
+ status = "disabled";
+
+ sata-phy@0 {
+ reg = <0>;
+ };
+
+ sata-phy@1 {
+ reg = <1>;
+ };
+ };
+
+ usb0: usb@ed0000 {
+ compatible = "chipidea,usb2";
+ reg = <0xed0000 0x10000>;
+ interrupts = <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_USB0>;
+ phys = <&usb_phy0>;
+ phy-names = "usb-phy";
+ status = "disabled";
+ };
+
+ usb1: usb@ee0000 {
+ compatible = "chipidea,usb2";
+ reg = <0xee0000 0x10000>;
+ interrupts = <GIC_SPI 12 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&chip CLKID_USB1>;
+ phys = <&usb_phy1>;
+ phy-names = "usb-phy";
+ status = "disabled";
+ };
+
apb@fc0000 {
compatible = "simple-bus";
#address-cells = <1>;
diff --git a/arch/arm/boot/dts/dra7-evm.dts b/arch/arm/boot/dts/dra7-evm.dts
index c6ce625..736092b 100644
--- a/arch/arm/boot/dts/dra7-evm.dts
+++ b/arch/arm/boot/dts/dra7-evm.dts
@@ -171,6 +171,101 @@
0xd0 (PIN_OUTPUT | MUX_MODE0) /* gpmc_be0n_cle */
>;
};
+
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ 0x250 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txc.rgmii0_txc */
+ 0x254 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txctl.rgmii0_txctl */
+ 0x258 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_td3.rgmii0_txd3 */
+ 0x25c (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd2.rgmii0_txd2 */
+ 0x260 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd1.rgmii0_txd1 */
+ 0x264 (PIN_OUTPUT | MUX_MODE0) /* rgmii0_txd0.rgmii0_txd0 */
+ 0x268 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxc.rgmii0_rxc */
+ 0x26c (PIN_INPUT | MUX_MODE0) /* rgmii0_rxctl.rgmii0_rxctl */
+ 0x270 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd3.rgmii0_rxd3 */
+ 0x274 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd2.rgmii0_rxd2 */
+ 0x278 (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd1.rgmii0_rxd1 */
+ 0x27c (PIN_INPUT | MUX_MODE0) /* rgmii0_rxd0.rgmii0_rxd0 */
+
+ /* Slave 2 */
+ 0x198 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_txc */
+ 0x19c (PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
+ 0x1a0 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
+ 0x1a4 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
+ 0x1a8 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
+ 0x1ac (PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
+ 0x1b0 (PIN_INPUT | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
+ 0x1b4 (PIN_INPUT | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
+ 0x1b8 (PIN_INPUT | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
+ 0x1bc (PIN_INPUT | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
+ 0x1c0 (PIN_INPUT | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
+ 0x1c4 (PIN_INPUT | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
+ >;
+
+ };
+
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 1 */
+ 0x250 (MUX_MODE15)
+ 0x254 (MUX_MODE15)
+ 0x258 (MUX_MODE15)
+ 0x25c (MUX_MODE15)
+ 0x260 (MUX_MODE15)
+ 0x264 (MUX_MODE15)
+ 0x268 (MUX_MODE15)
+ 0x26c (MUX_MODE15)
+ 0x270 (MUX_MODE15)
+ 0x274 (MUX_MODE15)
+ 0x278 (MUX_MODE15)
+ 0x27c (MUX_MODE15)
+
+ /* Slave 2 */
+ 0x198 (MUX_MODE15)
+ 0x19c (MUX_MODE15)
+ 0x1a0 (MUX_MODE15)
+ 0x1a4 (MUX_MODE15)
+ 0x1a8 (MUX_MODE15)
+ 0x1ac (MUX_MODE15)
+ 0x1b0 (MUX_MODE15)
+ 0x1b4 (MUX_MODE15)
+ 0x1b8 (MUX_MODE15)
+ 0x1bc (MUX_MODE15)
+ 0x1c0 (MUX_MODE15)
+ 0x1c4 (MUX_MODE15)
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ 0x23c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_d.mdio_d */
+ 0x240 (PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ 0x23c (MUX_MODE15)
+ 0x240 (MUX_MODE15)
+ >;
+ };
+
+ dcan1_pins_default: dcan1_pins_default {
+ pinctrl-single,pins = <
+ 0x3d0 (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
+ 0x3d4 (MUX_MODE15) /* dcan1_rx.off */
+ 0x418 (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+ >;
+ };
+
+ dcan1_pins_sleep: dcan1_pins_sleep {
+ pinctrl-single,pins = <
+ 0x3d0 (MUX_MODE15) /* dcan1_tx.off */
+ 0x3d4 (MUX_MODE15) /* dcan1_rx.off */
+ 0x418 (MUX_MODE15) /* wakeup0.off */
+ >;
+ };
};
&i2c1 {
@@ -201,6 +296,7 @@
regulator-name = "smps45";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1150000>;
+ regulator-always-on;
regulator-boot-on;
};
@@ -209,6 +305,7 @@
regulator-name = "smps6";
regulator-min-microvolt = <850000>;
regulator-max-microvolt = <12500000>;
+ regulator-always-on;
regulator-boot-on;
};
@@ -226,6 +323,7 @@
regulator-name = "smps8";
regulator-min-microvolt = < 850000>;
regulator-max-microvolt = <1250000>;
+ regulator-always-on;
regulator-boot-on;
};
@@ -252,6 +350,7 @@
regulator-name = "ldo2";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
+ regulator-always-on;
regulator-boot-on;
};
@@ -269,6 +368,7 @@
regulator-name = "ldo9";
regulator-min-microvolt = <1050000>;
regulator-max-microvolt = <1050000>;
+ regulator-always-on;
regulator-boot-on;
};
@@ -528,3 +628,36 @@
ti,no-reset-on-init;
ti,no-idle-on-init;
};
+
+&mac {
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+ dual_emac;
+};
+
+&cpsw_emac0 {
+ phy_id = <&davinci_mdio>, <2>;
+ phy-mode = "rgmii";
+ dual_emac_res_vlan = <1>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <3>;
+ phy-mode = "rgmii";
+ dual_emac_res_vlan = <2>;
+};
+
+&davinci_mdio {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_default>;
+ pinctrl-1 = <&davinci_mdio_sleep>;
+};
+
+&dcan1 {
+ status = "ok";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&dcan1_pins_default>;
+ pinctrl-1 = <&dcan1_pins_sleep>;
+};
diff --git a/arch/arm/boot/dts/dra7.dtsi b/arch/arm/boot/dts/dra7.dtsi
index 9cc9843..63bf99b 100644
--- a/arch/arm/boot/dts/dra7.dtsi
+++ b/arch/arm/boot/dts/dra7.dtsi
@@ -34,6 +34,14 @@
serial3 = &uart4;
serial4 = &uart5;
serial5 = &uart6;
+ serial6 = &uart7;
+ serial7 = &uart8;
+ serial8 = &uart9;
+ serial9 = &uart10;
+ ethernet0 = &cpsw_emac0;
+ ethernet1 = &cpsw_emac1;
+ d_can0 = &dcan1;
+ d_can1 = &dcan2;
};
timer {
@@ -201,6 +209,11 @@
ti,hwmods = "counter_32k";
};
+ dra7_ctrl_core: ctrl_core@4a002000 {
+ compatible = "syscon";
+ reg = <0x4a002000 0x6d0>;
+ };
+
dra7_ctrl_general: tisyscon@4a002e00 {
compatible = "syscon";
reg = <0x4a002e00 0x7c>;
@@ -335,6 +348,8 @@
ti,hwmods = "uart1";
clock-frequency = <48000000>;
status = "disabled";
+ dmas = <&sdma 49>, <&sdma 50>;
+ dma-names = "tx", "rx";
};
uart2: serial@4806c000 {
@@ -344,6 +359,8 @@
ti,hwmods = "uart2";
clock-frequency = <48000000>;
status = "disabled";
+ dmas = <&sdma 51>, <&sdma 52>;
+ dma-names = "tx", "rx";
};
uart3: serial@48020000 {
@@ -353,6 +370,8 @@
ti,hwmods = "uart3";
clock-frequency = <48000000>;
status = "disabled";
+ dmas = <&sdma 53>, <&sdma 54>;
+ dma-names = "tx", "rx";
};
uart4: serial@4806e000 {
@@ -362,6 +381,8 @@
ti,hwmods = "uart4";
clock-frequency = <48000000>;
status = "disabled";
+ dmas = <&sdma 55>, <&sdma 56>;
+ dma-names = "tx", "rx";
};
uart5: serial@48066000 {
@@ -371,6 +392,8 @@
ti,hwmods = "uart5";
clock-frequency = <48000000>;
status = "disabled";
+ dmas = <&sdma 63>, <&sdma 64>;
+ dma-names = "tx", "rx";
};
uart6: serial@48068000 {
@@ -380,6 +403,8 @@
ti,hwmods = "uart6";
clock-frequency = <48000000>;
status = "disabled";
+ dmas = <&sdma 79>, <&sdma 80>;
+ dma-names = "tx", "rx";
};
uart7: serial@48420000 {
@@ -421,7 +446,11 @@
mailbox1: mailbox@4a0f4000 {
compatible = "ti,omap4-mailbox";
reg = <0x4a0f4000 0x200>;
+ interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 134 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox1";
+ #mbox-cells = <1>;
ti,mbox-num-users = <3>;
ti,mbox-num-fifos = <8>;
status = "disabled";
@@ -430,7 +459,12 @@
mailbox2: mailbox@4883a000 {
compatible = "ti,omap4-mailbox";
reg = <0x4883a000 0x200>;
+ interrupts = <GIC_SPI 237 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 238 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 239 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 240 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox2";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -439,7 +473,12 @@
mailbox3: mailbox@4883c000 {
compatible = "ti,omap4-mailbox";
reg = <0x4883c000 0x200>;
+ interrupts = <GIC_SPI 241 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 242 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 243 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 244 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox3";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -448,7 +487,12 @@
mailbox4: mailbox@4883e000 {
compatible = "ti,omap4-mailbox";
reg = <0x4883e000 0x200>;
+ interrupts = <GIC_SPI 245 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 246 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 247 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 248 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox4";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -457,7 +501,12 @@
mailbox5: mailbox@48840000 {
compatible = "ti,omap4-mailbox";
reg = <0x48840000 0x200>;
+ interrupts = <GIC_SPI 249 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 250 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 251 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 252 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox5";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -466,7 +515,12 @@
mailbox6: mailbox@48842000 {
compatible = "ti,omap4-mailbox";
reg = <0x48842000 0x200>;
+ interrupts = <GIC_SPI 253 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 254 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 255 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 256 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox6";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -475,7 +529,12 @@
mailbox7: mailbox@48844000 {
compatible = "ti,omap4-mailbox";
reg = <0x48844000 0x200>;
+ interrupts = <GIC_SPI 257 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 258 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 259 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 260 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox7";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -484,7 +543,12 @@
mailbox8: mailbox@48846000 {
compatible = "ti,omap4-mailbox";
reg = <0x48846000 0x200>;
+ interrupts = <GIC_SPI 261 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 262 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 263 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 264 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox8";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -493,7 +557,12 @@
mailbox9: mailbox@4885e000 {
compatible = "ti,omap4-mailbox";
reg = <0x4885e000 0x200>;
+ interrupts = <GIC_SPI 265 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 266 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 267 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 268 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox9";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -502,7 +571,12 @@
mailbox10: mailbox@48860000 {
compatible = "ti,omap4-mailbox";
reg = <0x48860000 0x200>;
+ interrupts = <GIC_SPI 269 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 270 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 271 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 272 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox10";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -511,7 +585,12 @@
mailbox11: mailbox@48862000 {
compatible = "ti,omap4-mailbox";
reg = <0x48862000 0x200>;
+ interrupts = <GIC_SPI 273 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 274 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 275 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 276 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox11";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -520,7 +599,12 @@
mailbox12: mailbox@48864000 {
compatible = "ti,omap4-mailbox";
reg = <0x48864000 0x200>;
+ interrupts = <GIC_SPI 277 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 278 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 279 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 280 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox12";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -529,7 +613,12 @@
mailbox13: mailbox@48802000 {
compatible = "ti,omap4-mailbox";
reg = <0x48802000 0x200>;
+ interrupts = <GIC_SPI 379 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 380 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 381 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 382 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox13";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <12>;
status = "disabled";
@@ -1075,6 +1164,15 @@
status = "disabled";
};
+ rtc@48838000 {
+ compatible = "ti,am3352-rtc";
+ reg = <0x48838000 0x100>;
+ interrupts = <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 217 IRQ_TYPE_LEVEL_HIGH>;
+ ti,hwmods = "rtcss";
+ clocks = <&sys_32k_ck>;
+ };
+
omap_control_usb2phy1: control-phy@4a002300 {
compatible = "ti,control-phy-usb2";
reg = <0x4a002300 0x4>;
@@ -1141,7 +1239,7 @@
};
};
- omap_dwc3_1@48880000 {
+ omap_dwc3_1: omap_dwc3_1@48880000 {
compatible = "ti,dwc3";
ti,hwmods = "usb_otg_ss1";
reg = <0x48880000 0x10000>;
@@ -1162,7 +1260,7 @@
};
};
- omap_dwc3_2@488c0000 {
+ omap_dwc3_2: omap_dwc3_2@488c0000 {
compatible = "ti,dwc3";
ti,hwmods = "usb_otg_ss2";
reg = <0x488c0000 0x10000>;
@@ -1184,7 +1282,7 @@
};
/* IRQ for DWC3_3 and DWC3_4 need IRQ crossbar */
- omap_dwc3_3@48900000 {
+ omap_dwc3_3: omap_dwc3_3@48900000 {
compatible = "ti,dwc3";
ti,hwmods = "usb_otg_ss3";
reg = <0x48900000 0x10000>;
@@ -1204,26 +1302,6 @@
};
};
- omap_dwc3_4@48940000 {
- compatible = "ti,dwc3";
- ti,hwmods = "usb_otg_ss4";
- reg = <0x48940000 0x10000>;
- interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
- #address-cells = <1>;
- #size-cells = <1>;
- utmi-mode = <2>;
- ranges;
- status = "disabled";
- usb4: usb@48950000 {
- compatible = "snps,dwc3";
- reg = <0x48950000 0x17000>;
- interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
- tx-fifo-resize;
- maximum-speed = "high-speed";
- dr_mode = "otg";
- };
- };
-
elm: elm@48078000 {
compatible = "ti,am3352-elm";
reg = <0x48078000 0xfc0>; /* device IO registers */
@@ -1265,6 +1343,84 @@
ti,irqs-skip = <10 133 139 140>;
ti,irqs-safe-map = <0>;
};
+
+ mac: ethernet@4a100000 {
+ compatible = "ti,cpsw";
+ ti,hwmods = "gmac";
+ clocks = <&dpll_gmac_ck>, <&gmac_gmii_ref_clk_div>;
+ clock-names = "fck", "cpts";
+ cpdma_channels = <8>;
+ ale_entries = <1024>;
+ bd_ram_size = <0x2000>;
+ no_bd_ram = <0>;
+ rx_descs = <64>;
+ mac_control = <0x20>;
+ slaves = <2>;
+ active_slave = <0>;
+ cpts_clock_mult = <0x80000000>;
+ cpts_clock_shift = <29>;
+ reg = <0x48484000 0x1000
+ 0x48485200 0x2E00>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /*
+ * rx_thresh_pend
+ * rx_pend
+ * tx_pend
+ * misc_pend
+ */
+ interrupts = <GIC_SPI 334 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 335 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 336 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 337 IRQ_TYPE_LEVEL_HIGH>;
+ ranges;
+ status = "disabled";
+
+ davinci_mdio: mdio@48485000 {
+ compatible = "ti,davinci_mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ ti,hwmods = "davinci_mdio";
+ bus_freq = <1000000>;
+ reg = <0x48485000 0x100>;
+ };
+
+ cpsw_emac0: slave@48480200 {
+ /* Filled in by U-Boot */
+ mac-address = [ 00 00 00 00 00 00 ];
+ };
+
+ cpsw_emac1: slave@48480300 {
+ /* Filled in by U-Boot */
+ mac-address = [ 00 00 00 00 00 00 ];
+ };
+
+ phy_sel: cpsw-phy-sel@4a002554 {
+ compatible = "ti,dra7xx-cpsw-phy-sel";
+ reg= <0x4a002554 0x4>;
+ reg-names = "gmii-sel";
+ };
+ };
+
+ dcan1: can@481cc000 {
+ compatible = "ti,dra7-d_can";
+ ti,hwmods = "dcan1";
+ reg = <0x4ae3c000 0x2000>;
+ syscon-raminit = <&dra7_ctrl_core 0x558 0>;
+ interrupts = <GIC_SPI 222 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&dcan1_sys_clk_mux>;
+ status = "disabled";
+ };
+
+ dcan2: can@481d0000 {
+ compatible = "ti,dra7-d_can";
+ ti,hwmods = "dcan2";
+ reg = <0x48480000 0x2000>;
+ syscon-raminit = <&dra7_ctrl_core 0x558 1>;
+ interrupts = <GIC_SPI 225 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sys_clkin1>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/dra72-evm.dts b/arch/arm/boot/dts/dra72-evm.dts
index 4107428..afc74fd 100644
--- a/arch/arm/boot/dts/dra72-evm.dts
+++ b/arch/arm/boot/dts/dra72-evm.dts
@@ -17,6 +17,13 @@
device_type = "memory";
reg = <0x80000000 0x40000000>; /* 1024 MB */
};
+
+ evm_3v3: fixedregulator-evm_3v3 {
+ compatible = "regulator-fixed";
+ regulator-name = "evm_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
};
&dra7_pmx_core {
@@ -26,6 +33,94 @@
0x404 (PIN_INPUT | MUX_MODE0) /* i2c1_scl.i2c1_scl */
>;
};
+
+ nand_default: nand_default {
+ pinctrl-single,pins = <
+ 0x0 (PIN_INPUT | MUX_MODE0) /* gpmc_ad0 */
+ 0x4 (PIN_INPUT | MUX_MODE0) /* gpmc_ad1 */
+ 0x8 (PIN_INPUT | MUX_MODE0) /* gpmc_ad2 */
+ 0xc (PIN_INPUT | MUX_MODE0) /* gpmc_ad3 */
+ 0x10 (PIN_INPUT | MUX_MODE0) /* gpmc_ad4 */
+ 0x14 (PIN_INPUT | MUX_MODE0) /* gpmc_ad5 */
+ 0x18 (PIN_INPUT | MUX_MODE0) /* gpmc_ad6 */
+ 0x1c (PIN_INPUT | MUX_MODE0) /* gpmc_ad7 */
+ 0x20 (PIN_INPUT | MUX_MODE0) /* gpmc_ad8 */
+ 0x24 (PIN_INPUT | MUX_MODE0) /* gpmc_ad9 */
+ 0x28 (PIN_INPUT | MUX_MODE0) /* gpmc_ad10 */
+ 0x2c (PIN_INPUT | MUX_MODE0) /* gpmc_ad11 */
+ 0x30 (PIN_INPUT | MUX_MODE0) /* gpmc_ad12 */
+ 0x34 (PIN_INPUT | MUX_MODE0) /* gpmc_ad13 */
+ 0x38 (PIN_INPUT | MUX_MODE0) /* gpmc_ad14 */
+ 0x3c (PIN_INPUT | MUX_MODE0) /* gpmc_ad15 */
+ 0xb4 (PIN_OUTPUT | MUX_MODE0) /* gpmc_cs0 */
+ 0xc4 (PIN_OUTPUT | MUX_MODE0) /* gpmc_advn_ale */
+ 0xcc (PIN_OUTPUT | MUX_MODE0) /* gpmc_wen */
+ 0xc8 (PIN_OUTPUT | MUX_MODE0) /* gpmc_oen_ren */
+ 0xd0 (PIN_OUTPUT | MUX_MODE0) /* gpmc_ben0 */
+ 0xd8 (PIN_INPUT | MUX_MODE0) /* gpmc_wait0 */
+ >;
+ };
+
+ usb1_pins: pinmux_usb1_pins {
+ pinctrl-single,pins = <
+ 0x280 (PIN_INPUT_SLEW | MUX_MODE0) /* usb1_drvvbus */
+ >;
+ };
+
+ usb2_pins: pinmux_usb2_pins {
+ pinctrl-single,pins = <
+ 0x284 (PIN_INPUT_SLEW | MUX_MODE0) /* usb2_drvvbus */
+ >;
+ };
+
+ tps65917_pins_default: tps65917_pins_default {
+ pinctrl-single,pins = <
+ 0x424 (PIN_INPUT_PULLUP | MUX_MODE1) /* wakeup3.sys_nirq1 */
+ >;
+ };
+
+ mmc1_pins_default: mmc1_pins_default {
+ pinctrl-single,pins = <
+ 0x36c (PIN_INPUT | MUX_MODE14) /* mmc1sdcd.gpio219 */
+ 0x354 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_clk.clk */
+ 0x358 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_cmd.cmd */
+ 0x35c (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat0.dat0 */
+ 0x360 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat1.dat1 */
+ 0x364 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat2.dat2 */
+ 0x368 (PIN_INPUT_PULLUP | MUX_MODE0) /* mmc1_dat3.dat3 */
+ >;
+ };
+
+ mmc2_pins_default: mmc2_pins_default {
+ pinctrl-single,pins = <
+ 0x9c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a23.mmc2_clk */
+ 0xb0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_cs1.mmc2_cmd */
+ 0xa0 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a24.mmc2_dat0 */
+ 0xa4 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a25.mmc2_dat1 */
+ 0xa8 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a26.mmc2_dat2 */
+ 0xac (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a27.mmc2_dat3 */
+ 0x8c (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a19.mmc2_dat4 */
+ 0x90 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a20.mmc2_dat5 */
+ 0x94 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a21.mmc2_dat6 */
+ 0x98 (PIN_INPUT_PULLUP | MUX_MODE1) /* gpmc_a22.mmc2_dat7 */
+ >;
+ };
+
+ dcan1_pins_default: dcan1_pins_default {
+ pinctrl-single,pins = <
+ 0x3d0 (PIN_OUTPUT | MUX_MODE0) /* dcan1_tx */
+ 0x3d4 (MUX_MODE15) /* dcan1_rx.off */
+ 0x418 (PULL_DIS | MUX_MODE1) /* wakeup0.dcan1_rx */
+ >;
+ };
+
+ dcan1_pins_sleep: dcan1_pins_sleep {
+ pinctrl-single,pins = <
+ 0x3d0 (MUX_MODE15) /* dcan1_tx.off */
+ 0x3d4 (MUX_MODE15) /* dcan1_rx.off */
+ 0x418 (MUX_MODE15) /* wakeup0.off */
+ >;
+ };
};
&i2c1 {
@@ -38,6 +133,9 @@
compatible = "ti,tps65917";
reg = <0x58>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&tps65917_pins_default>;
+
interrupts = <GIC_SPI 2 IRQ_TYPE_NONE>; /* IRQ_SYS_1N */
interrupt-parent = <&gic>;
interrupt-controller;
@@ -136,9 +234,230 @@
};
};
};
+
+ tps65917_power_button {
+ compatible = "ti,palmas-pwrbutton";
+ interrupt-parent = <&tps65917>;
+ interrupts = <1 IRQ_TYPE_NONE>;
+ wakeup-source;
+ ti,palmas-long-press-seconds = <6>;
+ };
};
};
&uart1 {
status = "okay";
};
+
+&elm {
+ status = "okay";
+};
+
+&gpmc {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&nand_default>;
+ ranges = <0 0 0 0x01000000>; /* minimum GPMC partition = 16MB */
+ nand@0,0 {
+ /* To use NAND, DIP switch SW5 must be set like so:
+ * SW5.1 (NAND_SELn) = ON (LOW)
+ * SW5.9 (GPMC_WPN) = OFF (HIGH)
+ */
+ reg = <0 0 4>; /* device IO registers */
+ ti,nand-ecc-opt = "bch8";
+ ti,elm-id = <&elm>;
+ nand-bus-width = <16>;
+ gpmc,device-width = <2>;
+ gpmc,sync-clk-ps = <0>;
+ gpmc,cs-on-ns = <0>;
+ gpmc,cs-rd-off-ns = <80>;
+ gpmc,cs-wr-off-ns = <80>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <60>;
+ gpmc,adv-wr-off-ns = <60>;
+ gpmc,we-on-ns = <10>;
+ gpmc,we-off-ns = <50>;
+ gpmc,oe-on-ns = <4>;
+ gpmc,oe-off-ns = <40>;
+ gpmc,access-ns = <40>;
+ gpmc,wr-access-ns = <80>;
+ gpmc,rd-cycle-ns = <80>;
+ gpmc,wr-cycle-ns = <80>;
+ gpmc,bus-turnaround-ns = <0>;
+ gpmc,cycle2cycle-delay-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ /* MTD partition table */
+ /* All SPL-* partitions are sized to minimal length
+ * which can be independently programmable. For
+ * NAND flash this is equal to size of erase-block */
+ #address-cells = <1>;
+ #size-cells = <1>;
+ partition@0 {
+ label = "NAND.SPL";
+ reg = <0x00000000 0x000020000>;
+ };
+ partition@1 {
+ label = "NAND.SPL.backup1";
+ reg = <0x00020000 0x00020000>;
+ };
+ partition@2 {
+ label = "NAND.SPL.backup2";
+ reg = <0x00040000 0x00020000>;
+ };
+ partition@3 {
+ label = "NAND.SPL.backup3";
+ reg = <0x00060000 0x00020000>;
+ };
+ partition@4 {
+ label = "NAND.u-boot-spl-os";
+ reg = <0x00080000 0x00040000>;
+ };
+ partition@5 {
+ label = "NAND.u-boot";
+ reg = <0x000c0000 0x00100000>;
+ };
+ partition@6 {
+ label = "NAND.u-boot-env";
+ reg = <0x001c0000 0x00020000>;
+ };
+ partition@7 {
+ label = "NAND.u-boot-env.backup1";
+ reg = <0x001e0000 0x00020000>;
+ };
+ partition@8 {
+ label = "NAND.kernel";
+ reg = <0x00200000 0x00800000>;
+ };
+ partition@9 {
+ label = "NAND.file-system";
+ reg = <0x00a00000 0x0f600000>;
+ };
+ };
+};
+
+&usb2_phy1 {
+ phy-supply = <&ldo4_reg>;
+};
+
+&usb2_phy2 {
+ phy-supply = <&ldo4_reg>;
+};
+
+&usb1 {
+ dr_mode = "peripheral";
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_pins>;
+};
+
+&usb2 {
+ dr_mode = "host";
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb2_pins>;
+};
+
+&mmc1 {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc1_pins_default>;
+
+ vmmc-supply = <&ldo1_reg>;
+ bus-width = <4>;
+ /*
+ * SDCD signal is not being used here - using the fact that GPIO mode
+ * is a viable alternative
+ */
+ cd-gpios = <&gpio6 27 0>;
+};
+
+&mmc2 {
+ /* SW5-3 in ON position */
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_default>;
+
+ vmmc-supply = <&evm_3v3>;
+ bus-width = <8>;
+ ti,non-removable;
+};
+
+&dra7_pmx_core {
+ cpsw_default: cpsw_default {
+ pinctrl-single,pins = <
+ /* Slave 2 */
+ 0x198 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d12.rgmii1_txc */
+ 0x19c (PIN_OUTPUT | MUX_MODE3) /* vin2a_d13.rgmii1_tctl */
+ 0x1a0 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d14.rgmii1_td3 */
+ 0x1a4 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d15.rgmii1_td2 */
+ 0x1a8 (PIN_OUTPUT | MUX_MODE3) /* vin2a_d16.rgmii1_td1 */
+ 0x1ac (PIN_OUTPUT | MUX_MODE3) /* vin2a_d17.rgmii1_td0 */
+ 0x1b0 (PIN_INPUT | MUX_MODE3) /* vin2a_d18.rgmii1_rclk */
+ 0x1b4 (PIN_INPUT | MUX_MODE3) /* vin2a_d19.rgmii1_rctl */
+ 0x1b8 (PIN_INPUT | MUX_MODE3) /* vin2a_d20.rgmii1_rd3 */
+ 0x1bc (PIN_INPUT | MUX_MODE3) /* vin2a_d21.rgmii1_rd2 */
+ 0x1c0 (PIN_INPUT | MUX_MODE3) /* vin2a_d22.rgmii1_rd1 */
+ 0x1c4 (PIN_INPUT | MUX_MODE3) /* vin2a_d23.rgmii1_rd0 */
+ >;
+
+ };
+
+ cpsw_sleep: cpsw_sleep {
+ pinctrl-single,pins = <
+ /* Slave 2 */
+ 0x198 (MUX_MODE15)
+ 0x19c (MUX_MODE15)
+ 0x1a0 (MUX_MODE15)
+ 0x1a4 (MUX_MODE15)
+ 0x1a8 (MUX_MODE15)
+ 0x1ac (MUX_MODE15)
+ 0x1b0 (MUX_MODE15)
+ 0x1b4 (MUX_MODE15)
+ 0x1b8 (MUX_MODE15)
+ 0x1bc (MUX_MODE15)
+ 0x1c0 (MUX_MODE15)
+ 0x1c4 (MUX_MODE15)
+ >;
+ };
+
+ davinci_mdio_default: davinci_mdio_default {
+ pinctrl-single,pins = <
+ /* MDIO */
+ 0x23c (PIN_OUTPUT_PULLUP | MUX_MODE0) /* mdio_d.mdio_d */
+ 0x240 (PIN_INPUT_PULLUP | MUX_MODE0) /* mdio_clk.mdio_clk */
+ >;
+ };
+
+ davinci_mdio_sleep: davinci_mdio_sleep {
+ pinctrl-single,pins = <
+ 0x23c (MUX_MODE15)
+ 0x240 (MUX_MODE15)
+ >;
+ };
+};
+
+&mac {
+ status = "okay";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&cpsw_default>;
+ pinctrl-1 = <&cpsw_sleep>;
+};
+
+&cpsw_emac1 {
+ phy_id = <&davinci_mdio>, <3>;
+ phy-mode = "rgmii";
+};
+
+&davinci_mdio {
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&davinci_mdio_default>;
+ pinctrl-1 = <&davinci_mdio_sleep>;
+ active_slave = <1>;
+};
+
+&dcan1 {
+ status = "ok";
+ pinctrl-names = "default", "sleep";
+ pinctrl-0 = <&dcan1_pins_default>;
+ pinctrl-1 = <&dcan1_pins_sleep>;
+};
diff --git a/arch/arm/boot/dts/dra74x.dtsi b/arch/arm/boot/dts/dra74x.dtsi
index 3be544c..10173fa 100644
--- a/arch/arm/boot/dts/dra74x.dtsi
+++ b/arch/arm/boot/dts/dra74x.dtsi
@@ -44,4 +44,26 @@
interrupts = <GIC_SPI DIRECT_IRQ(131) IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI DIRECT_IRQ(132) IRQ_TYPE_LEVEL_HIGH>;
};
+
+ ocp {
+ omap_dwc3_4: omap_dwc3_4@48940000 {
+ compatible = "ti,dwc3";
+ ti,hwmods = "usb_otg_ss4";
+ reg = <0x48940000 0x10000>;
+ interrupts = <GIC_SPI 346 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ utmi-mode = <2>;
+ ranges;
+ status = "disabled";
+ usb4: usb@48950000 {
+ compatible = "snps,dwc3";
+ reg = <0x48950000 0x17000>;
+ interrupts = <GIC_SPI 345 IRQ_TYPE_LEVEL_HIGH>;
+ tx-fifo-resize;
+ maximum-speed = "high-speed";
+ dr_mode = "otg";
+ };
+ };
+ };
};
diff --git a/arch/arm/boot/dts/emev2-kzm9d.dts b/arch/arm/boot/dts/emev2-kzm9d.dts
index 50ccd15..667d323 100644
--- a/arch/arm/boot/dts/emev2-kzm9d.dts
+++ b/arch/arm/boot/dts/emev2-kzm9d.dts
@@ -25,37 +25,7 @@
chosen {
bootargs = "console=ttyS1,115200n81 ignore_loglevel root=/dev/nfs ip=dhcp";
- };
-
- reg_1p8v: regulator@0 {
- compatible = "regulator-fixed";
- regulator-name = "fixed-1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- reg_3p3v: regulator@1 {
- compatible = "regulator-fixed";
- regulator-name = "fixed-3.3V";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- lan9220@20000000 {
- compatible = "smsc,lan9220", "smsc,lan9115";
- reg = <0x20000000 0x10000>;
- phy-mode = "mii";
- interrupt-parent = <&gpio0>;
- interrupts = <1 IRQ_TYPE_EDGE_RISING>;
- reg-io-width = <4>;
- smsc,irq-active-high;
- smsc,irq-push-pull;
- vddvario-supply = <&reg_1p8v>;
- vdd33a-supply = <&reg_3p3v>;
+ stdout-path = &uart1;
};
gpio_keys {
@@ -92,4 +62,35 @@
gpios = <&gpio0 17 GPIO_ACTIVE_HIGH>;
};
};
+
+ reg_1p8v: regulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ reg_3p3v: regulator@1 {
+ compatible = "regulator-fixed";
+ regulator-name = "fixed-3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ lan9220@20000000 {
+ compatible = "smsc,lan9220", "smsc,lan9115";
+ reg = <0x20000000 0x10000>;
+ phy-mode = "mii";
+ interrupt-parent = <&gpio0>;
+ interrupts = <1 IRQ_TYPE_EDGE_RISING>;
+ reg-io-width = <4>;
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
+ vddvario-supply = <&reg_1p8v>;
+ vdd33a-supply = <&reg_3p3v>;
+ };
};
diff --git a/arch/arm/boot/dts/emev2.dtsi b/arch/arm/boot/dts/emev2.dtsi
index 00eeed3..cc7bfe0 100644
--- a/arch/arm/boot/dts/emev2.dtsi
+++ b/arch/arm/boot/dts/emev2.dtsi
@@ -55,7 +55,7 @@
<0 121 IRQ_TYPE_LEVEL_HIGH>;
};
- smu@e0110000 {
+ clocks@e0110000 {
compatible = "renesas,emev2-smu";
reg = <0xe0110000 0x10000>;
#address-cells = <2>;
@@ -129,7 +129,7 @@
};
};
- sti@e0180000 {
+ timer@e0180000 {
compatible = "renesas,em-sti";
reg = <0xe0180000 0x54>;
interrupts = <0 125 IRQ_TYPE_LEVEL_HIGH>;
@@ -137,7 +137,7 @@
clock-names = "sclk";
};
- uart@e1020000 {
+ uart0: serial@e1020000 {
compatible = "renesas,em-uart";
reg = <0xe1020000 0x38>;
interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>;
@@ -145,7 +145,7 @@
clock-names = "sclk";
};
- uart@e1030000 {
+ uart1: serial@e1030000 {
compatible = "renesas,em-uart";
reg = <0xe1030000 0x38>;
interrupts = <0 9 IRQ_TYPE_LEVEL_HIGH>;
@@ -153,7 +153,7 @@
clock-names = "sclk";
};
- uart@e1040000 {
+ uart2: serial@e1040000 {
compatible = "renesas,em-uart";
reg = <0xe1040000 0x38>;
interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>;
@@ -161,7 +161,7 @@
clock-names = "sclk";
};
- uart@e1050000 {
+ uart3: serial@e1050000 {
compatible = "renesas,em-uart";
reg = <0xe1050000 0x38>;
interrupts = <0 11 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/exynos3250-monk.dts b/arch/arm/boot/dts/exynos3250-monk.dts
new file mode 100644
index 0000000..24822aa
--- /dev/null
+++ b/arch/arm/boot/dts/exynos3250-monk.dts
@@ -0,0 +1,579 @@
+/*
+ * Samsung's Exynos3250 based Monk board device tree source
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Device tree source file for Samsung's Monk board which is based on
+ * Samsung Exynos3250 SoC.
+ *
+ * This program is free software; you can 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 "exynos3250.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Samsung Monk board";
+ compatible = "samsung,monk", "samsung,exynos3250", "samsung,exynos3";
+
+ aliases {
+ i2c7 = &i2c_max77836;
+ };
+
+ memory {
+ reg = <0x40000000 0x1ff00000>;
+ };
+
+ firmware@0205F000 {
+ compatible = "samsung,secure-firmware";
+ reg = <0x0205F000 0x1000>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ power_key {
+ interrupt-parent = <&gpx2>;
+ interrupts = <7 0>;
+ gpios = <&gpx2 7 1>;
+ linux,code = <KEY_POWER>;
+ label = "power key";
+ debounce-interval = <10>;
+ gpio-key,wakeup;
+ };
+ };
+
+ vemmc_reg: voltage-regulator-0 {
+ compatible = "regulator-fixed";
+ regulator-name = "V_EMMC_2.8V-fixed";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ gpio = <&gpk0 2 0>;
+ enable-active-high;
+ };
+
+ i2c_max77836: i2c-gpio-0 {
+ compatible = "i2c-gpio";
+ gpios = <&gpd0 2 0>, <&gpd0 3 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ max77836: subpmic@25 {
+ compatible = "maxim,max77836";
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 0>;
+ reg = <0x25>;
+ wakeup;
+
+ muic: max77836-muic {
+ compatible = "maxim,max77836-muic";
+ };
+
+ regulators {
+ compatible = "maxim,max77836-regulator";
+ safeout_reg: SAFEOUT {
+ regulator-name = "SAFEOUT";
+ };
+
+ charger_reg: CHARGER {
+ regulator-name = "CHARGER";
+ regulator-min-microamp = <45000>;
+ regulator-max-microamp = <475000>;
+ regulator-boot-on;
+ };
+
+ motor_reg: LDO1 {
+ regulator-name = "MOT_2.7V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ LDO2 {
+ regulator-name = "UNUSED_LDO2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3950000>;
+ };
+ };
+
+ charger {
+ compatible = "maxim,max77836-charger";
+
+ maxim,constant-uvolt = <4350000>;
+ maxim,fast-charge-uamp = <225000>;
+ maxim,eoc-uamp = <7500>;
+ maxim,ovp-uvolt = <6500000>;
+ };
+ };
+ };
+};
+
+&adc {
+ vdd-supply = <&ldo3_reg>;
+ status = "okay";
+ assigned-clocks = <&cmu CLK_SCLK_TSADC>;
+ assigned-clock-rates = <6000000>;
+
+ thermistor-ap {
+ compatible = "ntc,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <100000>;
+ pulldown-ohm = <100000>;
+ io-channels = <&adc 0>;
+ };
+
+ thermistor-battery {
+ compatible = "ntc,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <100000>;
+ pulldown-ohm = <100000>;
+ io-channels = <&adc 1>;
+ };
+};
+
+&i2c_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <100000>;
+ status = "okay";
+
+ s2mps14_pmic@66 {
+ compatible = "samsung,s2mps14-pmic";
+ interrupt-parent = <&gpx0>;
+ interrupts = <7 0>;
+ reg = <0x66>;
+ wakeup;
+
+ s2mps14_osc: clocks {
+ compatible = "samsung,s2mps14-clk";
+ #clock-cells = <1>;
+ clock-output-names = "s2mps14_ap", "unused",
+ "s2mps14_bt";
+ };
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VAP_ALIVE_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VAP_M1_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "VCC_AP_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "VAP_AVDD_PLL1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "VAP_PLL_ISO_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "VAP_MIPI_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "VAP_AVDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "VAP_USB_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "V_LPDDR_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "UNUSED_LDO10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "V_EMMC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "V_EMMC_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "VSENSOR_2.85V";
+ regulator-min-microvolt = <2850000>;
+ regulator-max-microvolt = <2850000>;
+ regulator-always-on;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "UNUSED_LDO14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "TSP_AVDD_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "LCD_VDD_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "UNUSED_LDO17";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "UNUSED_LDO18";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "TSP_VDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo20_reg: LDO20 {
+ regulator-name = "LCD_VDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo21_reg: LDO21 {
+ regulator-name = "UNUSED_LDO21";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo22_reg: LDO22 {
+ regulator-name = "UNUSED_LDO22";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo23_reg: LDO23 {
+ regulator-name = "UNUSED_LDO23";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ ldo24_reg: LDO24 {
+ regulator-name = "UNUSED_LDO24";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "UNUSED_LDO25";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "VAP_MIF_1.0V";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <900000>;
+ regulator-always-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "VAP_ARM_1.0V";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-always-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "VAP_INT3D_1.0V";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "VCC_SUB_1.95V";
+ regulator-min-microvolt = <1950000>;
+ regulator-max-microvolt = <1950000>;
+ regulator-always-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "VCC_SUB_1.35V";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+&i2c_1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <400000>;
+ status = "okay";
+
+ fuelgauge@36 {
+ compatible = "maxim,max77836-battery";
+ interrupt-parent = <&gpx1>;
+ interrupts = <2 8>;
+ reg = <0x36>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&mshc_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ num-slots = <1>;
+ broken-cd;
+ non-removable;
+ cap-mmc-highspeed;
+ desc-num = <4>;
+ mmc-hs200-1_8v;
+ card-detect-delay = <200>;
+ vmmc-supply = <&vemmc_reg>;
+ clock-frequency = <100000000>;
+ clock-freq-min-max = <400000 100000000>;
+ samsung,dw-mshc-ciu-div = <1>;
+ samsung,dw-mshc-sdr-timing = <0 1>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
+ bus-width = <8>;
+ status = "okay";
+};
+
+&serial_0 {
+ assigned-clocks = <&cmu CLK_SCLK_UART0>;
+ assigned-clock-rates = <100000000>;
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&tmu {
+ vtmu-supply = <&ldo7_reg>;
+ status = "okay";
+};
+
+&rtc {
+ clocks = <&cmu CLK_RTC>, <&s2mps14_osc 0>;
+ clock-names = "rtc", "rtc_src";
+ status = "okay";
+};
+
+&xusbxti {
+ clock-frequency = <24000000>;
+};
+
+&pinctrl_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep0>;
+
+ sleep0: sleep-state {
+ PIN_SLP(gpa0-0, INPUT, DOWN);
+ PIN_SLP(gpa0-1, INPUT, DOWN);
+ PIN_SLP(gpa0-2, INPUT, DOWN);
+ PIN_SLP(gpa0-3, INPUT, DOWN);
+ PIN_SLP(gpa0-4, INPUT, DOWN);
+ PIN_SLP(gpa0-5, INPUT, DOWN);
+ PIN_SLP(gpa0-6, INPUT, DOWN);
+ PIN_SLP(gpa0-7, INPUT, DOWN);
+
+ PIN_SLP(gpa1-0, INPUT, DOWN);
+ PIN_SLP(gpa1-1, INPUT, DOWN);
+ PIN_SLP(gpa1-2, INPUT, DOWN);
+ PIN_SLP(gpa1-3, INPUT, DOWN);
+ PIN_SLP(gpa1-4, INPUT, DOWN);
+ PIN_SLP(gpa1-5, INPUT, DOWN);
+
+ PIN_SLP(gpb-0, PREV, NONE);
+ PIN_SLP(gpb-1, PREV, NONE);
+ PIN_SLP(gpb-2, PREV, NONE);
+ PIN_SLP(gpb-3, PREV, NONE);
+ PIN_SLP(gpb-4, INPUT, DOWN);
+ PIN_SLP(gpb-5, INPUT, DOWN);
+ PIN_SLP(gpb-6, INPUT, DOWN);
+ PIN_SLP(gpb-7, INPUT, DOWN);
+
+ PIN_SLP(gpc0-0, INPUT, DOWN);
+ PIN_SLP(gpc0-1, INPUT, DOWN);
+ PIN_SLP(gpc0-2, INPUT, DOWN);
+ PIN_SLP(gpc0-3, INPUT, DOWN);
+ PIN_SLP(gpc0-4, INPUT, DOWN);
+
+ PIN_SLP(gpc1-0, INPUT, DOWN);
+ PIN_SLP(gpc1-1, INPUT, DOWN);
+ PIN_SLP(gpc1-2, INPUT, DOWN);
+ PIN_SLP(gpc1-3, INPUT, DOWN);
+ PIN_SLP(gpc1-4, INPUT, DOWN);
+
+ PIN_SLP(gpd0-0, INPUT, DOWN);
+ PIN_SLP(gpd0-1, INPUT, DOWN);
+ PIN_SLP(gpd0-2, INPUT, NONE);
+ PIN_SLP(gpd0-3, INPUT, NONE);
+
+ PIN_SLP(gpd1-0, INPUT, NONE);
+ PIN_SLP(gpd1-1, INPUT, NONE);
+ PIN_SLP(gpd1-2, INPUT, NONE);
+ PIN_SLP(gpd1-3, INPUT, NONE);
+ };
+};
+
+&pinctrl_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep1>;
+
+ sleep1: sleep-state {
+ PIN_SLP(gpe0-0, PREV, NONE);
+ PIN_SLP(gpe0-1, PREV, NONE);
+ PIN_SLP(gpe0-2, INPUT, DOWN);
+ PIN_SLP(gpe0-3, INPUT, DOWN);
+ PIN_SLP(gpe0-4, PREV, NONE);
+ PIN_SLP(gpe0-5, INPUT, DOWN);
+ PIN_SLP(gpe0-6, INPUT, DOWN);
+ PIN_SLP(gpe0-7, INPUT, DOWN);
+
+ PIN_SLP(gpe1-0, INPUT, DOWN);
+ PIN_SLP(gpe1-1, PREV, NONE);
+ PIN_SLP(gpe1-2, INPUT, DOWN);
+ PIN_SLP(gpe1-3, INPUT, DOWN);
+ PIN_SLP(gpe1-4, INPUT, DOWN);
+ PIN_SLP(gpe1-5, INPUT, DOWN);
+ PIN_SLP(gpe1-6, INPUT, DOWN);
+ PIN_SLP(gpe1-7, INPUT, NONE);
+
+ PIN_SLP(gpe2-0, INPUT, NONE);
+ PIN_SLP(gpe2-1, INPUT, NONE);
+ PIN_SLP(gpe2-2, INPUT, NONE);
+
+ PIN_SLP(gpk0-0, INPUT, DOWN);
+ PIN_SLP(gpk0-1, INPUT, DOWN);
+ PIN_SLP(gpk0-2, OUT0, NONE);
+ PIN_SLP(gpk0-3, INPUT, DOWN);
+ PIN_SLP(gpk0-4, INPUT, DOWN);
+ PIN_SLP(gpk0-5, INPUT, DOWN);
+ PIN_SLP(gpk0-6, INPUT, DOWN);
+ PIN_SLP(gpk0-7, INPUT, DOWN);
+
+ PIN_SLP(gpk1-0, PREV, NONE);
+ PIN_SLP(gpk1-1, PREV, NONE);
+ PIN_SLP(gpk1-2, INPUT, DOWN);
+ PIN_SLP(gpk1-3, PREV, NONE);
+ PIN_SLP(gpk1-4, PREV, NONE);
+ PIN_SLP(gpk1-5, PREV, NONE);
+ PIN_SLP(gpk1-6, PREV, NONE);
+
+ PIN_SLP(gpk2-0, INPUT, DOWN);
+ PIN_SLP(gpk2-1, INPUT, DOWN);
+ PIN_SLP(gpk2-2, INPUT, DOWN);
+ PIN_SLP(gpk2-3, INPUT, DOWN);
+ PIN_SLP(gpk2-4, INPUT, DOWN);
+ PIN_SLP(gpk2-5, INPUT, DOWN);
+ PIN_SLP(gpk2-6, INPUT, DOWN);
+
+ PIN_SLP(gpl0-0, INPUT, DOWN);
+ PIN_SLP(gpl0-1, INPUT, DOWN);
+ PIN_SLP(gpl0-2, INPUT, DOWN);
+ PIN_SLP(gpl0-3, INPUT, DOWN);
+
+ PIN_SLP(gpm0-0, INPUT, DOWN);
+ PIN_SLP(gpm0-1, INPUT, DOWN);
+ PIN_SLP(gpm0-2, INPUT, DOWN);
+ PIN_SLP(gpm0-3, INPUT, DOWN);
+ PIN_SLP(gpm0-4, INPUT, DOWN);
+ PIN_SLP(gpm0-5, INPUT, DOWN);
+ PIN_SLP(gpm0-6, INPUT, DOWN);
+ PIN_SLP(gpm0-7, INPUT, DOWN);
+
+ PIN_SLP(gpm1-0, INPUT, DOWN);
+ PIN_SLP(gpm1-1, INPUT, DOWN);
+ PIN_SLP(gpm1-2, INPUT, DOWN);
+ PIN_SLP(gpm1-3, INPUT, DOWN);
+ PIN_SLP(gpm1-4, INPUT, DOWN);
+ PIN_SLP(gpm1-5, INPUT, DOWN);
+ PIN_SLP(gpm1-6, INPUT, DOWN);
+
+ PIN_SLP(gpm2-0, INPUT, DOWN);
+ PIN_SLP(gpm2-1, INPUT, DOWN);
+ PIN_SLP(gpm2-2, INPUT, DOWN);
+ PIN_SLP(gpm2-3, INPUT, DOWN);
+ PIN_SLP(gpm2-4, INPUT, DOWN);
+
+ PIN_SLP(gpm3-0, INPUT, DOWN);
+ PIN_SLP(gpm3-1, INPUT, DOWN);
+ PIN_SLP(gpm3-2, INPUT, DOWN);
+ PIN_SLP(gpm3-3, INPUT, DOWN);
+ PIN_SLP(gpm3-4, INPUT, DOWN);
+ PIN_SLP(gpm3-5, INPUT, DOWN);
+ PIN_SLP(gpm3-6, INPUT, DOWN);
+ PIN_SLP(gpm3-7, INPUT, DOWN);
+
+ PIN_SLP(gpm4-0, INPUT, DOWN);
+ PIN_SLP(gpm4-1, INPUT, DOWN);
+ PIN_SLP(gpm4-2, INPUT, DOWN);
+ PIN_SLP(gpm4-3, INPUT, DOWN);
+ PIN_SLP(gpm4-4, INPUT, DOWN);
+ PIN_SLP(gpm4-5, INPUT, DOWN);
+ PIN_SLP(gpm4-6, INPUT, DOWN);
+ PIN_SLP(gpm4-7, INPUT, DOWN);
+ };
+};
diff --git a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
index 47b92c1..5ab81c3 100644
--- a/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos3250-pinctrl.dtsi
@@ -12,6 +12,22 @@
* published by the Free Software Foundation.
*/
+#define PIN_PULL_NONE 0
+#define PIN_PULL_DOWN 1
+#define PIN_PULL_UP 3
+
+#define PIN_PDN_OUT0 0
+#define PIN_PDN_OUT1 1
+#define PIN_PDN_INPUT 2
+#define PIN_PDN_PREV 3
+
+#define PIN_SLP(_pin, _mode, _pull) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-con-pdn = <PIN_PDN_ ##_mode>; \
+ samsung,pin-pud-pdn = <PIN_PULL_ ##_pull>; \
+ }
+
&pinctrl_0 {
gpa0: gpa0 {
gpio-controller;
diff --git a/arch/arm/boot/dts/exynos3250-rinato.dts b/arch/arm/boot/dts/exynos3250-rinato.dts
new file mode 100644
index 0000000..80aa8b4
--- /dev/null
+++ b/arch/arm/boot/dts/exynos3250-rinato.dts
@@ -0,0 +1,682 @@
+/*
+ * Samsung's Exynos3250 based Rinato board device tree source
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Device tree source file for Samsung's Rinato board which is based on
+ * Samsung Exynos3250 SoC.
+ *
+ * This program is free software; you can 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 "exynos3250.dtsi"
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "Samsung Rinato board";
+ compatible = "samsung,rinato", "samsung,exynos3250", "samsung,exynos3";
+
+ aliases {
+ i2c7 = &i2c_max77836;
+ };
+
+ memory {
+ reg = <0x40000000 0x1ff00000>;
+ };
+
+ firmware@0205F000 {
+ compatible = "samsung,secure-firmware";
+ reg = <0x0205F000 0x1000>;
+ };
+
+ gpio_keys {
+ compatible = "gpio-keys";
+
+ power_key {
+ interrupt-parent = <&gpx2>;
+ interrupts = <7 0>;
+ gpios = <&gpx2 7 1>;
+ linux,code = <KEY_POWER>;
+ label = "power key";
+ debounce-interval = <10>;
+ gpio-key,wakeup;
+ };
+ };
+
+ i2c_max77836: i2c-gpio-0 {
+ compatible = "i2c-gpio";
+ gpios = <&gpd0 2 0>, <&gpd0 3 0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ max77836: subpmic@25 {
+ compatible = "maxim,max77836";
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 0>;
+ reg = <0x25>;
+ wakeup;
+
+ muic: max77836-muic {
+ compatible = "maxim,max77836-muic";
+ };
+
+ regulators {
+ compatible = "maxim,max77836-regulator";
+ safeout_reg: SAFEOUT {
+ regulator-name = "SAFEOUT";
+ };
+
+ charger_reg: CHARGER {
+ regulator-name = "CHARGER";
+ regulator-min-microamp = <45000>;
+ regulator-max-microamp = <475000>;
+ regulator-boot-on;
+ };
+
+ motor_reg: LDO1 {
+ regulator-name = "MOT_2.7V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <2700000>;
+ };
+
+ LDO2 {
+ regulator-name = "UNUSED_LDO2";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <3950000>;
+ };
+ };
+
+ charger {
+ compatible = "maxim,max77836-charger";
+
+ maxim,constant-uvolt = <4350000>;
+ maxim,fast-charge-uamp = <225000>;
+ maxim,eoc-uamp = <7500>;
+ maxim,ovp-uvolt = <6500000>;
+ };
+ };
+ };
+};
+
+&adc {
+ vdd-supply = <&ldo3_reg>;
+ status = "okay";
+ assigned-clocks = <&cmu CLK_SCLK_TSADC>;
+ assigned-clock-rates = <6000000>;
+
+ thermistor-ap {
+ compatible = "ntc,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <100000>;
+ pulldown-ohm = <100000>;
+ io-channels = <&adc 0>;
+ };
+
+ thermistor-battery {
+ compatible = "ntc,ncp15wb473";
+ pullup-uv = <1800000>;
+ pullup-ohm = <100000>;
+ pulldown-ohm = <100000>;
+ io-channels = <&adc 1>;
+ };
+};
+
+&i2c_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <100000>;
+ status = "okay";
+
+ s2mps14_pmic@66 {
+ compatible = "samsung,s2mps14-pmic";
+ interrupt-parent = <&gpx0>;
+ interrupts = <7 0>;
+ reg = <0x66>;
+ wakeup;
+
+ s2mps14_osc: clocks {
+ compatible = "samsung,s2mps14-clk";
+ #clock-cells = <1>;
+ clock-output-names = "s2mps14_ap", "unused",
+ "s2mps14_bt";
+ };
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VAP_ALIVE_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo2_reg: LDO2 {
+ regulator-name = "VAP_M1_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "VCC_AP_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "VAP_AVDD_PLL1";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "VAP_PLL_ISO_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "VAP_VMIPI_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "VAP_AVDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "VAP_USB_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "V_LPDDR_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "UNUSED_LDO10";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "V_EMMC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "V_EMMC_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ samsung,ext-control-gpios = <&gpk0 2 0>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "CAM_AVDD_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "UNUSED_LDO14";
+ regulator-min-microvolt = <2700000>;
+ regulator-max-microvolt = <2700000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "TSP_AVDD_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "LCD_VDD_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "V_IRLED_3.3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "CAM_AF_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo19_reg: LDO19 {
+ regulator-name = "TSP_VDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo20_reg: LDO20 {
+ regulator-name = "LCD_VDD_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo21_reg: LDO21 {
+ regulator-name = "CAM_IO_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo22_reg: LDO22 {
+ regulator-name = "CAM_DVDD_1.2V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo23_reg: LDO23 {
+ regulator-name = "HRM_VCC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
+
+ ldo24_reg: LDO24 {
+ regulator-name = "HRM_VCC_3.3V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "UNUSED_LDO25";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "VAP_MIF_1.0V";
+ regulator-min-microvolt = <800000>;
+ regulator-max-microvolt = <900000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "VAP_ARM_1.0V";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1150000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "VAP_INT3D_1.0V";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-off-in-suspend;
+ };
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "VCC_SUB_1.95V";
+ regulator-min-microvolt = <1950000>;
+ regulator-max-microvolt = <1950000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "VCC_SUB_1.35V";
+ regulator-min-microvolt = <1350000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+
+ regulator-state-mem {
+ regulator-on-in-suspend;
+ };
+ };
+ };
+ };
+};
+
+&i2c_1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-slave-addr = <0x10>;
+ samsung,i2c-max-bus-freq = <400000>;
+ status = "okay";
+
+ fuelgauge@36 {
+ compatible = "maxim,max77836-battery";
+ interrupt-parent = <&gpx1>;
+ interrupts = <2 8>;
+ reg = <0x36>;
+ };
+};
+
+&i2s2 {
+ status = "okay";
+};
+
+&mfc {
+ status = "okay";
+};
+
+&mshc_0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ num-slots = <1>;
+ broken-cd;
+ non-removable;
+ cap-mmc-highspeed;
+ desc-num = <4>;
+ mmc-hs200-1_8v;
+ card-detect-delay = <200>;
+ vmmc-supply = <&ldo12_reg>;
+ clock-frequency = <100000000>;
+ clock-freq-min-max = <400000 100000000>;
+ samsung,dw-mshc-ciu-div = <1>;
+ samsung,dw-mshc-sdr-timing = <0 1>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_cmd &sd0_bus1 &sd0_bus4 &sd0_bus8>;
+ bus-width = <8>;
+ status = "okay";
+};
+
+&serial_0 {
+ assigned-clocks = <&cmu CLK_SCLK_UART0>;
+ assigned-clock-rates = <100000000>;
+ status = "okay";
+};
+
+&serial_1 {
+ status = "okay";
+};
+
+&tmu {
+ vtmu-supply = <&ldo7_reg>;
+ status = "okay";
+};
+
+&rtc {
+ clocks = <&cmu CLK_RTC>, <&s2mps14_osc 0>;
+ clock-names = "rtc", "rtc_src";
+ status = "okay";
+};
+
+&xusbxti {
+ clock-frequency = <24000000>;
+};
+
+&pinctrl_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep0>;
+
+ sleep0: sleep-state {
+ PIN_SLP(gpa0-0, INPUT, DOWN);
+ PIN_SLP(gpa0-1, INPUT, DOWN);
+ PIN_SLP(gpa0-2, INPUT, DOWN);
+ PIN_SLP(gpa0-3, INPUT, DOWN);
+ PIN_SLP(gpa0-4, INPUT, DOWN);
+ PIN_SLP(gpa0-5, INPUT, DOWN);
+ PIN_SLP(gpa0-6, INPUT, DOWN);
+ PIN_SLP(gpa0-7, INPUT, DOWN);
+
+ PIN_SLP(gpa1-0, INPUT, DOWN);
+ PIN_SLP(gpa1-1, INPUT, DOWN);
+ PIN_SLP(gpa1-2, INPUT, DOWN);
+ PIN_SLP(gpa1-3, INPUT, DOWN);
+ PIN_SLP(gpa1-4, INPUT, DOWN);
+ PIN_SLP(gpa1-5, INPUT, DOWN);
+
+ PIN_SLP(gpb-0, PREV, NONE);
+ PIN_SLP(gpb-1, PREV, NONE);
+ PIN_SLP(gpb-2, PREV, NONE);
+ PIN_SLP(gpb-3, PREV, NONE);
+ PIN_SLP(gpb-4, INPUT, DOWN);
+ PIN_SLP(gpb-5, INPUT, DOWN);
+ PIN_SLP(gpb-6, INPUT, DOWN);
+ PIN_SLP(gpb-7, INPUT, DOWN);
+
+ PIN_SLP(gpc0-0, INPUT, DOWN);
+ PIN_SLP(gpc0-1, INPUT, DOWN);
+ PIN_SLP(gpc0-2, INPUT, DOWN);
+ PIN_SLP(gpc0-3, INPUT, DOWN);
+ PIN_SLP(gpc0-4, INPUT, DOWN);
+
+ PIN_SLP(gpc1-0, INPUT, DOWN);
+ PIN_SLP(gpc1-1, INPUT, DOWN);
+ PIN_SLP(gpc1-2, INPUT, DOWN);
+ PIN_SLP(gpc1-3, INPUT, DOWN);
+ PIN_SLP(gpc1-4, INPUT, DOWN);
+
+ PIN_SLP(gpd0-0, INPUT, DOWN);
+ PIN_SLP(gpd0-1, INPUT, DOWN);
+ PIN_SLP(gpd0-2, INPUT, NONE);
+ PIN_SLP(gpd0-3, INPUT, NONE);
+
+ PIN_SLP(gpd1-0, INPUT, NONE);
+ PIN_SLP(gpd1-1, INPUT, NONE);
+ PIN_SLP(gpd1-2, INPUT, NONE);
+ PIN_SLP(gpd1-3, INPUT, NONE);
+ };
+};
+
+&pinctrl_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep1>;
+
+ sleep1: sleep-state {
+ PIN_SLP(gpe0-0, PREV, NONE);
+ PIN_SLP(gpe0-1, PREV, NONE);
+ PIN_SLP(gpe0-2, INPUT, DOWN);
+ PIN_SLP(gpe0-3, INPUT, UP);
+ PIN_SLP(gpe0-4, INPUT, DOWN);
+ PIN_SLP(gpe0-5, INPUT, DOWN);
+ PIN_SLP(gpe0-6, INPUT, DOWN);
+ PIN_SLP(gpe0-7, INPUT, DOWN);
+
+ PIN_SLP(gpe1-0, INPUT, DOWN);
+ PIN_SLP(gpe1-1, PREV, NONE);
+ PIN_SLP(gpe1-2, INPUT, DOWN);
+ PIN_SLP(gpe1-3, INPUT, DOWN);
+ PIN_SLP(gpe1-4, INPUT, DOWN);
+ PIN_SLP(gpe1-5, INPUT, DOWN);
+ PIN_SLP(gpe1-6, INPUT, DOWN);
+ PIN_SLP(gpe1-7, INPUT, NONE);
+
+ PIN_SLP(gpe2-0, INPUT, NONE);
+ PIN_SLP(gpe2-1, INPUT, NONE);
+ PIN_SLP(gpe2-2, INPUT, NONE);
+
+ PIN_SLP(gpk0-0, INPUT, DOWN);
+ PIN_SLP(gpk0-1, INPUT, DOWN);
+ PIN_SLP(gpk0-2, OUT0, NONE);
+ PIN_SLP(gpk0-3, INPUT, DOWN);
+ PIN_SLP(gpk0-4, INPUT, DOWN);
+ PIN_SLP(gpk0-5, INPUT, DOWN);
+ PIN_SLP(gpk0-6, INPUT, DOWN);
+ PIN_SLP(gpk0-7, INPUT, DOWN);
+
+ PIN_SLP(gpk1-0, INPUT, DOWN);
+ PIN_SLP(gpk1-1, INPUT, DOWN);
+ PIN_SLP(gpk1-2, INPUT, DOWN);
+ PIN_SLP(gpk1-3, INPUT, DOWN);
+ PIN_SLP(gpk1-4, INPUT, DOWN);
+ PIN_SLP(gpk1-5, INPUT, DOWN);
+ PIN_SLP(gpk1-6, INPUT, DOWN);
+
+ PIN_SLP(gpk2-0, INPUT, DOWN);
+ PIN_SLP(gpk2-1, INPUT, DOWN);
+ PIN_SLP(gpk2-2, INPUT, DOWN);
+ PIN_SLP(gpk2-3, INPUT, DOWN);
+ PIN_SLP(gpk2-4, INPUT, DOWN);
+ PIN_SLP(gpk2-5, INPUT, DOWN);
+ PIN_SLP(gpk2-6, INPUT, DOWN);
+
+ PIN_SLP(gpl0-0, INPUT, DOWN);
+ PIN_SLP(gpl0-1, INPUT, DOWN);
+ PIN_SLP(gpl0-2, INPUT, DOWN);
+ PIN_SLP(gpl0-3, INPUT, DOWN);
+
+ PIN_SLP(gpm0-0, INPUT, DOWN);
+ PIN_SLP(gpm0-1, INPUT, DOWN);
+ PIN_SLP(gpm0-2, INPUT, DOWN);
+ PIN_SLP(gpm0-3, INPUT, DOWN);
+ PIN_SLP(gpm0-4, INPUT, DOWN);
+ PIN_SLP(gpm0-5, INPUT, DOWN);
+ PIN_SLP(gpm0-6, INPUT, DOWN);
+ PIN_SLP(gpm0-7, INPUT, DOWN);
+
+ PIN_SLP(gpm1-0, INPUT, DOWN);
+ PIN_SLP(gpm1-1, INPUT, DOWN);
+ PIN_SLP(gpm1-2, INPUT, DOWN);
+ PIN_SLP(gpm1-3, INPUT, DOWN);
+ PIN_SLP(gpm1-4, INPUT, DOWN);
+ PIN_SLP(gpm1-5, INPUT, DOWN);
+ PIN_SLP(gpm1-6, INPUT, DOWN);
+
+ PIN_SLP(gpm2-0, INPUT, DOWN);
+ PIN_SLP(gpm2-1, INPUT, DOWN);
+ PIN_SLP(gpm2-2, INPUT, DOWN);
+ PIN_SLP(gpm2-3, INPUT, DOWN);
+ PIN_SLP(gpm2-4, INPUT, DOWN);
+
+ PIN_SLP(gpm3-0, INPUT, DOWN);
+ PIN_SLP(gpm3-1, INPUT, DOWN);
+ PIN_SLP(gpm3-2, INPUT, DOWN);
+ PIN_SLP(gpm3-3, INPUT, DOWN);
+ PIN_SLP(gpm3-4, INPUT, DOWN);
+ PIN_SLP(gpm3-5, INPUT, DOWN);
+ PIN_SLP(gpm3-6, INPUT, DOWN);
+ PIN_SLP(gpm3-7, INPUT, DOWN);
+
+ PIN_SLP(gpm4-0, INPUT, DOWN);
+ PIN_SLP(gpm4-1, INPUT, DOWN);
+ PIN_SLP(gpm4-2, INPUT, DOWN);
+ PIN_SLP(gpm4-3, INPUT, DOWN);
+ PIN_SLP(gpm4-4, INPUT, DOWN);
+ PIN_SLP(gpm4-5, INPUT, DOWN);
+ PIN_SLP(gpm4-6, INPUT, DOWN);
+ PIN_SLP(gpm4-7, INPUT, DOWN);
+ };
+};
diff --git a/arch/arm/boot/dts/exynos3250.dtsi b/arch/arm/boot/dts/exynos3250.dtsi
index 693a327..242ddda 100644
--- a/arch/arm/boot/dts/exynos3250.dtsi
+++ b/arch/arm/boot/dts/exynos3250.dtsi
@@ -320,6 +320,16 @@
status = "disabled";
};
+ mfc: codec@13400000 {
+ compatible = "samsung,mfc-v7";
+ reg = <0x13400000 0x10000>;
+ interrupts = <0 102 0>;
+ clock-names = "mfc", "sclk_mfc";
+ clocks = <&cmu CLK_MFC>, <&cmu CLK_SCLK_MFC>;
+ samsung,power-domain = <&pd_mfc>;
+ status = "disabled";
+ };
+
serial_0: serial@13800000 {
compatible = "samsung,exynos4210-uart";
reg = <0x13800000 0x100>;
diff --git a/arch/arm/boot/dts/exynos4.dtsi b/arch/arm/boot/dts/exynos4.dtsi
index e0278ec..b8168f1 100644
--- a/arch/arm/boot/dts/exynos4.dtsi
+++ b/arch/arm/boot/dts/exynos4.dtsi
@@ -392,8 +392,8 @@
reg = <0x13400000 0x10000>;
interrupts = <0 94 0>;
samsung,power-domain = <&pd_mfc>;
- clocks = <&clock CLK_MFC>;
- clock-names = "mfc";
+ clocks = <&clock CLK_MFC>, <&clock CLK_SCLK_MFC>;
+ clock-names = "mfc", "sclk_mfc";
status = "disabled";
};
diff --git a/arch/arm/boot/dts/exynos4210-trats.dts b/arch/arm/boot/dts/exynos4210-trats.dts
index f516da9..7208362 100644
--- a/arch/arm/boot/dts/exynos4210-trats.dts
+++ b/arch/arm/boot/dts/exynos4210-trats.dts
@@ -431,18 +431,34 @@
fimc_0: fimc@11800000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+ <&clock CLK_SCLK_FIMC0>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
fimc_1: fimc@11810000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+ <&clock CLK_SCLK_FIMC1>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
fimc_2: fimc@11820000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+ <&clock CLK_SCLK_FIMC2>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
fimc_3: fimc@11830000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+ <&clock CLK_SCLK_FIMC3>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
};
};
diff --git a/arch/arm/boot/dts/exynos4210-universal_c210.dts b/arch/arm/boot/dts/exynos4210-universal_c210.dts
index d50eb3a..aaf0cae 100644
--- a/arch/arm/boot/dts/exynos4210-universal_c210.dts
+++ b/arch/arm/boot/dts/exynos4210-universal_c210.dts
@@ -473,18 +473,34 @@
fimc_0: fimc@11800000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+ <&clock CLK_SCLK_FIMC0>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
fimc_1: fimc@11810000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+ <&clock CLK_SCLK_FIMC1>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
fimc_2: fimc@11820000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+ <&clock CLK_SCLK_FIMC2>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
fimc_3: fimc@11830000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+ <&clock CLK_SCLK_FIMC3>;
+ assigned-clock-parents = <&clock CLK_SCLK_MPLL>;
+ assigned-clock-rates = <0>, <160000000>;
};
};
};
diff --git a/arch/arm/boot/dts/exynos4210.dtsi b/arch/arm/boot/dts/exynos4210.dtsi
index 807bb5b..bcc9e63 100644
--- a/arch/arm/boot/dts/exynos4210.dtsi
+++ b/arch/arm/boot/dts/exynos4210.dtsi
@@ -31,6 +31,23 @@
pinctrl2 = &pinctrl_2;
};
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@900 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0x900>;
+ };
+
+ cpu@901 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0x901>;
+ };
+ };
+
pmu_system_controller: system-controller@10020000 {
clock-names = "clkout0", "clkout1", "clkout2", "clkout3",
"clkout4", "clkout8", "clkout9";
diff --git a/arch/arm/boot/dts/exynos4212.dtsi b/arch/arm/boot/dts/exynos4212.dtsi
index 3c00e6e..dd0a43e 100644
--- a/arch/arm/boot/dts/exynos4212.dtsi
+++ b/arch/arm/boot/dts/exynos4212.dtsi
@@ -22,6 +22,23 @@
/ {
compatible = "samsung,exynos4212", "samsung,exynos4";
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@A00 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xA00>;
+ };
+
+ cpu@A01 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xA01>;
+ };
+ };
+
combiner: interrupt-controller@10440000 {
samsung,combiner-nr = <18>;
};
diff --git a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
index c697ff0..3fbf588 100644
--- a/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
+++ b/arch/arm/boot/dts/exynos4412-odroid-common.dtsi
@@ -45,6 +45,16 @@
compatible = "samsung,odroidx2-audio";
samsung,i2s-controller = <&i2s0>;
samsung,audio-codec = <&max98090>;
+ assigned-clocks = <&clock_audss EXYNOS_MOUT_AUDSS>,
+ <&clock_audss EXYNOS_MOUT_I2S>,
+ <&clock_audss EXYNOS_DOUT_SRP>,
+ <&clock_audss EXYNOS_DOUT_AUD_BUS>;
+ assigned-clock-parents = <&clock CLK_FOUT_EPLL>,
+ <&clock_audss EXYNOS_MOUT_AUDSS>;
+ assigned-clock-rates = <0>,
+ <0>,
+ <192000000>,
+ <19200000>;
};
mmc@12550000 {
@@ -82,18 +92,34 @@
fimc_0: fimc@11800000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+ <&clock CLK_SCLK_FIMC0>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
fimc_1: fimc@11810000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+ <&clock CLK_SCLK_FIMC1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
fimc_2: fimc@11820000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+ <&clock CLK_SCLK_FIMC2>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
fimc_3: fimc@11830000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+ <&clock CLK_SCLK_FIMC3>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
};
diff --git a/arch/arm/boot/dts/exynos4412-trats2.dts b/arch/arm/boot/dts/exynos4412-trats2.dts
index 5e066cd..29231b4 100644
--- a/arch/arm/boot/dts/exynos4412-trats2.dts
+++ b/arch/arm/boot/dts/exynos4412-trats2.dts
@@ -14,6 +14,7 @@
/dts-v1/;
#include "exynos4412.dtsi"
+#include <dt-bindings/gpio/gpio.h>
/ {
model = "Samsung Trats 2 based on Exynos4412";
@@ -22,6 +23,7 @@
aliases {
i2c9 = &i2c_ak8975;
i2c10 = &i2c_cm36651;
+ i2c11 = &i2c_max77693;
};
memory {
@@ -399,8 +401,6 @@
regulator-name = "VMEM_VDD_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- regulator-always-on;
- regulator-mem-off;
};
ldo23_reg: ldo23 {
@@ -503,8 +503,6 @@
regulator-name = "VMEM_VDDF_3.0V";
regulator-min-microvolt = <2850000>;
regulator-max-microvolt = <2850000>;
- regulator-always-on;
- regulator-mem-off;
};
buck9_reg: buck9 {
@@ -518,6 +516,42 @@
};
};
+ i2c_max77693: i2c-gpio-1 {
+ compatible = "i2c-gpio";
+ gpios = <&gpm2 0 GPIO_ACTIVE_HIGH>, <&gpm2 1 GPIO_ACTIVE_HIGH>;
+ i2c-gpio,delay-us = <2>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "okay";
+
+ max77693@66 {
+ compatible = "maxim,max77693";
+ interrupt-parent = <&gpx1>;
+ interrupts = <5 2>;
+ reg = <0x66>;
+
+ regulators {
+ esafeout1_reg: ESAFEOUT1@1 {
+ regulator-name = "ESAFEOUT1";
+ };
+ esafeout2_reg: ESAFEOUT2@2 {
+ regulator-name = "ESAFEOUT2";
+ };
+ charger_reg: CHARGER@0 {
+ regulator-name = "CHARGER";
+ regulator-min-microamp = <60000>;
+ regulator-max-microamp = <2580000>;
+ };
+ };
+
+ max77693_haptic {
+ compatible = "maxim,max77693-haptic";
+ haptic-supply = <&ldo26_reg>;
+ pwms = <&pwm 0 38022 0>;
+ };
+ };
+ };
+
mmc@12550000 {
num-slots = <1>;
broken-cd;
@@ -535,6 +569,16 @@
cap-mmc-highspeed;
};
+ sdhci@12530000 {
+ bus-width = <4>;
+ cd-gpios = <&gpx3 4 0>;
+ cd-inverted;
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_bus4>;
+ pinctrl-names = "default";
+ vmmc-supply = <&ldo21_reg>;
+ status = "okay";
+ };
+
serial@13800000 {
status = "okay";
};
@@ -551,6 +595,11 @@
status = "okay";
};
+ tmu@100C0000 {
+ vtmu-supply = <&ldo10_reg>;
+ status = "okay";
+ };
+
i2c_ak8975: i2c-gpio-0 {
compatible = "i2c-gpio";
gpios = <&gpy2 4 0>, <&gpy2 5 0>;
@@ -598,6 +647,13 @@
};
};
+ pwm: pwm@139D0000 {
+ pinctrl-0 = <&pwm0_out>;
+ pinctrl-names = "default";
+ samsung,pwm-outputs = <0>;
+ status = "okay";
+ };
+
dsi_0: dsi@11C80000 {
vddcore-supply = <&ldo8_reg>;
vddio-supply = <&ldo10_reg>;
@@ -663,28 +719,51 @@
pinctrl-0 = <&cam_port_a_clk_active &cam_port_b_clk_active>;
pinctrl-names = "default";
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_CAM0>,
+ <&clock CLK_MOUT_CAM1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>,
+ <&clock CLK_MOUT_MPLL_USER_T>;
fimc_0: fimc@11800000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC0>,
+ <&clock CLK_SCLK_FIMC0>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
fimc_1: fimc@11810000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC1>,
+ <&clock CLK_SCLK_FIMC1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
fimc_2: fimc@11820000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC2>,
+ <&clock CLK_SCLK_FIMC2>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
fimc_3: fimc@11830000 {
status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_FIMC3>,
+ <&clock CLK_SCLK_FIMC3>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
};
csis_0: csis@11880000 {
status = "okay";
vddcore-supply = <&ldo8_reg>;
vddio-supply = <&ldo10_reg>;
- clock-frequency = <176000000>;
+ assigned-clocks = <&clock CLK_MOUT_CSIS0>,
+ <&clock CLK_SCLK_CSIS0>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
/* Camera C (3) MIPI CSI-2 (CSIS0) */
port@3 {
@@ -698,10 +777,13 @@
};
csis_1: csis@11890000 {
+ status = "okay";
vddcore-supply = <&ldo8_reg>;
vddio-supply = <&ldo10_reg>;
- clock-frequency = <160000000>;
- status = "okay";
+ assigned-clocks = <&clock CLK_MOUT_CSIS1>,
+ <&clock CLK_SCLK_CSIS1>;
+ assigned-clock-parents = <&clock CLK_MOUT_MPLL_USER_T>;
+ assigned-clock-rates = <0>, <176000000>;
/* Camera D (4) MIPI CSI-2 (CSIS1) */
port@4 {
@@ -782,3 +864,319 @@
io-channels = <&adc 2>; /* Battery temperature */
};
};
+
+&pinctrl_0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep0>;
+
+ sleep0: sleep-states {
+ PIN_SLP(gpa0-0, INPUT, NONE);
+ PIN_SLP(gpa0-1, OUT0, NONE);
+ PIN_SLP(gpa0-2, INPUT, NONE);
+ PIN_SLP(gpa0-3, INPUT, UP);
+ PIN_SLP(gpa0-4, INPUT, NONE);
+ PIN_SLP(gpa0-5, INPUT, DOWN);
+ PIN_SLP(gpa0-6, INPUT, DOWN);
+ PIN_SLP(gpa0-7, INPUT, UP);
+
+ PIN_SLP(gpa1-0, INPUT, DOWN);
+ PIN_SLP(gpa1-1, INPUT, DOWN);
+ PIN_SLP(gpa1-2, INPUT, DOWN);
+ PIN_SLP(gpa1-3, INPUT, DOWN);
+ PIN_SLP(gpa1-4, INPUT, DOWN);
+ PIN_SLP(gpa1-5, INPUT, DOWN);
+
+ PIN_SLP(gpb-0, INPUT, NONE);
+ PIN_SLP(gpb-1, INPUT, NONE);
+ PIN_SLP(gpb-2, INPUT, NONE);
+ PIN_SLP(gpb-3, INPUT, NONE);
+ PIN_SLP(gpb-4, INPUT, DOWN);
+ PIN_SLP(gpb-5, INPUT, UP);
+ PIN_SLP(gpb-6, INPUT, DOWN);
+ PIN_SLP(gpb-7, INPUT, DOWN);
+
+ PIN_SLP(gpc0-0, INPUT, DOWN);
+ PIN_SLP(gpc0-1, INPUT, DOWN);
+ PIN_SLP(gpc0-2, INPUT, DOWN);
+ PIN_SLP(gpc0-3, INPUT, DOWN);
+ PIN_SLP(gpc0-4, INPUT, DOWN);
+
+ PIN_SLP(gpc1-0, INPUT, NONE);
+ PIN_SLP(gpc1-1, PREV, NONE);
+ PIN_SLP(gpc1-2, INPUT, NONE);
+ PIN_SLP(gpc1-3, INPUT, NONE);
+ PIN_SLP(gpc1-4, INPUT, NONE);
+
+ PIN_SLP(gpd0-0, INPUT, DOWN);
+ PIN_SLP(gpd0-1, INPUT, DOWN);
+ PIN_SLP(gpd0-2, INPUT, NONE);
+ PIN_SLP(gpd0-3, INPUT, NONE);
+
+ PIN_SLP(gpd1-0, INPUT, DOWN);
+ PIN_SLP(gpd1-1, INPUT, DOWN);
+ PIN_SLP(gpd1-2, INPUT, NONE);
+ PIN_SLP(gpd1-3, INPUT, NONE);
+
+ PIN_SLP(gpf0-0, INPUT, NONE);
+ PIN_SLP(gpf0-1, INPUT, NONE);
+ PIN_SLP(gpf0-2, INPUT, DOWN);
+ PIN_SLP(gpf0-3, INPUT, DOWN);
+ PIN_SLP(gpf0-4, INPUT, NONE);
+ PIN_SLP(gpf0-5, INPUT, DOWN);
+ PIN_SLP(gpf0-6, INPUT, NONE);
+ PIN_SLP(gpf0-7, INPUT, DOWN);
+
+ PIN_SLP(gpf1-0, INPUT, DOWN);
+ PIN_SLP(gpf1-1, INPUT, DOWN);
+ PIN_SLP(gpf1-2, INPUT, DOWN);
+ PIN_SLP(gpf1-3, INPUT, DOWN);
+ PIN_SLP(gpf1-4, INPUT, NONE);
+ PIN_SLP(gpf1-5, INPUT, NONE);
+ PIN_SLP(gpf1-6, INPUT, DOWN);
+ PIN_SLP(gpf1-7, PREV, NONE);
+
+ PIN_SLP(gpf2-0, PREV, NONE);
+ PIN_SLP(gpf2-1, INPUT, DOWN);
+ PIN_SLP(gpf2-2, INPUT, DOWN);
+ PIN_SLP(gpf2-3, INPUT, DOWN);
+ PIN_SLP(gpf2-4, INPUT, DOWN);
+ PIN_SLP(gpf2-5, INPUT, DOWN);
+ PIN_SLP(gpf2-6, INPUT, NONE);
+ PIN_SLP(gpf2-7, INPUT, NONE);
+
+ PIN_SLP(gpf3-0, INPUT, NONE);
+ PIN_SLP(gpf3-1, PREV, NONE);
+ PIN_SLP(gpf3-2, PREV, NONE);
+ PIN_SLP(gpf3-3, PREV, NONE);
+ PIN_SLP(gpf3-4, OUT1, NONE);
+ PIN_SLP(gpf3-5, INPUT, DOWN);
+
+ PIN_SLP(gpj0-0, PREV, NONE);
+ PIN_SLP(gpj0-1, PREV, NONE);
+ PIN_SLP(gpj0-2, PREV, NONE);
+ PIN_SLP(gpj0-3, INPUT, DOWN);
+ PIN_SLP(gpj0-4, PREV, NONE);
+ PIN_SLP(gpj0-5, PREV, NONE);
+ PIN_SLP(gpj0-6, INPUT, DOWN);
+ PIN_SLP(gpj0-7, INPUT, DOWN);
+
+ PIN_SLP(gpj1-0, INPUT, DOWN);
+ PIN_SLP(gpj1-1, PREV, NONE);
+ PIN_SLP(gpj1-2, PREV, NONE);
+ PIN_SLP(gpj1-3, INPUT, DOWN);
+ PIN_SLP(gpj1-4, INPUT, DOWN);
+ };
+};
+
+&pinctrl_1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep1>;
+
+ sleep1: sleep-states {
+ PIN_SLP(gpk0-0, PREV, NONE);
+ PIN_SLP(gpk0-1, PREV, NONE);
+ PIN_SLP(gpk0-2, OUT0, NONE);
+ PIN_SLP(gpk0-3, PREV, NONE);
+ PIN_SLP(gpk0-4, PREV, NONE);
+ PIN_SLP(gpk0-5, PREV, NONE);
+ PIN_SLP(gpk0-6, PREV, NONE);
+
+ PIN_SLP(gpk1-0, INPUT, DOWN);
+ PIN_SLP(gpk1-1, INPUT, DOWN);
+ PIN_SLP(gpk1-2, INPUT, DOWN);
+ PIN_SLP(gpk1-3, PREV, NONE);
+ PIN_SLP(gpk1-4, PREV, NONE);
+ PIN_SLP(gpk1-5, PREV, NONE);
+ PIN_SLP(gpk1-6, PREV, NONE);
+
+ PIN_SLP(gpk2-0, INPUT, DOWN);
+ PIN_SLP(gpk2-1, INPUT, DOWN);
+ PIN_SLP(gpk2-2, INPUT, DOWN);
+ PIN_SLP(gpk2-3, INPUT, DOWN);
+ PIN_SLP(gpk2-4, INPUT, DOWN);
+ PIN_SLP(gpk2-5, INPUT, DOWN);
+ PIN_SLP(gpk2-6, INPUT, DOWN);
+
+ PIN_SLP(gpk3-0, OUT0, NONE);
+ PIN_SLP(gpk3-1, INPUT, NONE);
+ PIN_SLP(gpk3-2, INPUT, DOWN);
+ PIN_SLP(gpk3-3, INPUT, NONE);
+ PIN_SLP(gpk3-4, INPUT, NONE);
+ PIN_SLP(gpk3-5, INPUT, NONE);
+ PIN_SLP(gpk3-6, INPUT, NONE);
+
+ PIN_SLP(gpl0-0, INPUT, DOWN);
+ PIN_SLP(gpl0-1, INPUT, DOWN);
+ PIN_SLP(gpl0-2, INPUT, DOWN);
+ PIN_SLP(gpl0-3, INPUT, DOWN);
+ PIN_SLP(gpl0-4, PREV, NONE);
+ PIN_SLP(gpl0-6, PREV, NONE);
+
+ PIN_SLP(gpl1-0, INPUT, DOWN);
+ PIN_SLP(gpl1-1, INPUT, DOWN);
+ PIN_SLP(gpl2-0, INPUT, DOWN);
+ PIN_SLP(gpl2-1, INPUT, DOWN);
+ PIN_SLP(gpl2-2, INPUT, DOWN);
+ PIN_SLP(gpl2-3, INPUT, DOWN);
+ PIN_SLP(gpl2-4, INPUT, DOWN);
+ PIN_SLP(gpl2-5, INPUT, DOWN);
+ PIN_SLP(gpl2-6, PREV, NONE);
+ PIN_SLP(gpl2-7, INPUT, DOWN);
+
+ PIN_SLP(gpm0-0, INPUT, DOWN);
+ PIN_SLP(gpm0-1, INPUT, DOWN);
+ PIN_SLP(gpm0-2, INPUT, DOWN);
+ PIN_SLP(gpm0-3, INPUT, DOWN);
+ PIN_SLP(gpm0-4, INPUT, DOWN);
+ PIN_SLP(gpm0-5, INPUT, DOWN);
+ PIN_SLP(gpm0-6, INPUT, DOWN);
+ PIN_SLP(gpm0-7, INPUT, DOWN);
+
+ PIN_SLP(gpm1-0, INPUT, DOWN);
+ PIN_SLP(gpm1-1, INPUT, DOWN);
+ PIN_SLP(gpm1-2, INPUT, NONE);
+ PIN_SLP(gpm1-3, INPUT, NONE);
+ PIN_SLP(gpm1-4, INPUT, NONE);
+ PIN_SLP(gpm1-5, INPUT, NONE);
+ PIN_SLP(gpm1-6, INPUT, DOWN);
+
+ PIN_SLP(gpm2-0, INPUT, NONE);
+ PIN_SLP(gpm2-1, INPUT, NONE);
+ PIN_SLP(gpm2-2, INPUT, DOWN);
+ PIN_SLP(gpm2-3, INPUT, DOWN);
+ PIN_SLP(gpm2-4, INPUT, DOWN);
+
+ PIN_SLP(gpm3-0, PREV, NONE);
+ PIN_SLP(gpm3-1, PREV, NONE);
+ PIN_SLP(gpm3-2, PREV, NONE);
+ PIN_SLP(gpm3-3, OUT1, NONE);
+ PIN_SLP(gpm3-4, INPUT, DOWN);
+ PIN_SLP(gpm3-5, INPUT, DOWN);
+ PIN_SLP(gpm3-6, INPUT, DOWN);
+ PIN_SLP(gpm3-7, INPUT, DOWN);
+
+ PIN_SLP(gpm4-0, INPUT, DOWN);
+ PIN_SLP(gpm4-1, INPUT, DOWN);
+ PIN_SLP(gpm4-2, INPUT, DOWN);
+ PIN_SLP(gpm4-3, INPUT, DOWN);
+ PIN_SLP(gpm4-4, INPUT, DOWN);
+ PIN_SLP(gpm4-5, INPUT, DOWN);
+ PIN_SLP(gpm4-6, INPUT, DOWN);
+ PIN_SLP(gpm4-7, INPUT, DOWN);
+
+ PIN_SLP(gpy0-0, INPUT, DOWN);
+ PIN_SLP(gpy0-1, INPUT, DOWN);
+ PIN_SLP(gpy0-2, INPUT, DOWN);
+ PIN_SLP(gpy0-3, INPUT, DOWN);
+ PIN_SLP(gpy0-4, INPUT, DOWN);
+ PIN_SLP(gpy0-5, INPUT, DOWN);
+
+ PIN_SLP(gpy1-0, INPUT, DOWN);
+ PIN_SLP(gpy1-1, INPUT, DOWN);
+ PIN_SLP(gpy1-2, INPUT, DOWN);
+ PIN_SLP(gpy1-3, INPUT, DOWN);
+
+ PIN_SLP(gpy2-0, PREV, NONE);
+ PIN_SLP(gpy2-1, INPUT, DOWN);
+ PIN_SLP(gpy2-2, INPUT, NONE);
+ PIN_SLP(gpy2-3, INPUT, NONE);
+ PIN_SLP(gpy2-4, INPUT, NONE);
+ PIN_SLP(gpy2-5, INPUT, NONE);
+
+ PIN_SLP(gpy3-0, INPUT, DOWN);
+ PIN_SLP(gpy3-1, INPUT, DOWN);
+ PIN_SLP(gpy3-2, INPUT, DOWN);
+ PIN_SLP(gpy3-3, INPUT, DOWN);
+ PIN_SLP(gpy3-4, INPUT, DOWN);
+ PIN_SLP(gpy3-5, INPUT, DOWN);
+ PIN_SLP(gpy3-6, INPUT, DOWN);
+ PIN_SLP(gpy3-7, INPUT, DOWN);
+
+ PIN_SLP(gpy4-0, INPUT, DOWN);
+ PIN_SLP(gpy4-1, INPUT, DOWN);
+ PIN_SLP(gpy4-2, INPUT, DOWN);
+ PIN_SLP(gpy4-3, INPUT, DOWN);
+ PIN_SLP(gpy4-4, INPUT, DOWN);
+ PIN_SLP(gpy4-5, INPUT, DOWN);
+ PIN_SLP(gpy4-6, INPUT, DOWN);
+ PIN_SLP(gpy4-7, INPUT, DOWN);
+
+ PIN_SLP(gpy5-0, INPUT, DOWN);
+ PIN_SLP(gpy5-1, INPUT, DOWN);
+ PIN_SLP(gpy5-2, INPUT, DOWN);
+ PIN_SLP(gpy5-3, INPUT, DOWN);
+ PIN_SLP(gpy5-4, INPUT, DOWN);
+ PIN_SLP(gpy5-5, INPUT, DOWN);
+ PIN_SLP(gpy5-6, INPUT, DOWN);
+ PIN_SLP(gpy5-7, INPUT, DOWN);
+
+ PIN_SLP(gpy6-0, INPUT, DOWN);
+ PIN_SLP(gpy6-1, INPUT, DOWN);
+ PIN_SLP(gpy6-2, INPUT, DOWN);
+ PIN_SLP(gpy6-3, INPUT, DOWN);
+ PIN_SLP(gpy6-4, INPUT, DOWN);
+ PIN_SLP(gpy6-5, INPUT, DOWN);
+ PIN_SLP(gpy6-6, INPUT, DOWN);
+ PIN_SLP(gpy6-7, INPUT, DOWN);
+ };
+};
+
+&pinctrl_2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep2>;
+
+ sleep2: sleep-states {
+ PIN_SLP(gpz-0, INPUT, DOWN);
+ PIN_SLP(gpz-1, INPUT, DOWN);
+ PIN_SLP(gpz-2, INPUT, DOWN);
+ PIN_SLP(gpz-3, INPUT, DOWN);
+ PIN_SLP(gpz-4, INPUT, DOWN);
+ PIN_SLP(gpz-5, INPUT, DOWN);
+ PIN_SLP(gpz-6, INPUT, DOWN);
+ };
+};
+
+&pinctrl_3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&sleep3>;
+
+ sleep3: sleep-states {
+ PIN_SLP(gpv0-0, INPUT, DOWN);
+ PIN_SLP(gpv0-1, INPUT, DOWN);
+ PIN_SLP(gpv0-2, INPUT, DOWN);
+ PIN_SLP(gpv0-3, INPUT, DOWN);
+ PIN_SLP(gpv0-4, INPUT, DOWN);
+ PIN_SLP(gpv0-5, INPUT, DOWN);
+ PIN_SLP(gpv0-6, INPUT, DOWN);
+ PIN_SLP(gpv0-7, INPUT, DOWN);
+
+ PIN_SLP(gpv1-0, INPUT, DOWN);
+ PIN_SLP(gpv1-1, INPUT, DOWN);
+ PIN_SLP(gpv1-2, INPUT, DOWN);
+ PIN_SLP(gpv1-3, INPUT, DOWN);
+ PIN_SLP(gpv1-4, INPUT, DOWN);
+ PIN_SLP(gpv1-5, INPUT, DOWN);
+ PIN_SLP(gpv1-6, INPUT, DOWN);
+ PIN_SLP(gpv1-7, INPUT, DOWN);
+
+ PIN_SLP(gpv2-0, INPUT, DOWN);
+ PIN_SLP(gpv2-1, INPUT, DOWN);
+ PIN_SLP(gpv2-2, INPUT, DOWN);
+ PIN_SLP(gpv2-3, INPUT, DOWN);
+ PIN_SLP(gpv2-4, INPUT, DOWN);
+ PIN_SLP(gpv2-5, INPUT, DOWN);
+ PIN_SLP(gpv2-6, INPUT, DOWN);
+ PIN_SLP(gpv2-7, INPUT, DOWN);
+
+ PIN_SLP(gpv3-0, INPUT, DOWN);
+ PIN_SLP(gpv3-1, INPUT, DOWN);
+ PIN_SLP(gpv3-2, INPUT, DOWN);
+ PIN_SLP(gpv3-3, INPUT, DOWN);
+ PIN_SLP(gpv3-4, INPUT, DOWN);
+ PIN_SLP(gpv3-5, INPUT, DOWN);
+ PIN_SLP(gpv3-6, INPUT, DOWN);
+ PIN_SLP(gpv3-7, INPUT, DOWN);
+
+ PIN_SLP(gpv4-0, INPUT, DOWN);
+ };
+};
diff --git a/arch/arm/boot/dts/exynos4412.dtsi b/arch/arm/boot/dts/exynos4412.dtsi
index d8bc059e..0f6ec93 100644
--- a/arch/arm/boot/dts/exynos4412.dtsi
+++ b/arch/arm/boot/dts/exynos4412.dtsi
@@ -22,6 +22,35 @@
/ {
compatible = "samsung,exynos4412", "samsung,exynos4";
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@A00 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xA00>;
+ };
+
+ cpu@A01 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xA01>;
+ };
+
+ cpu@A02 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xA02>;
+ };
+
+ cpu@A03 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xA03>;
+ };
+ };
+
combiner: interrupt-controller@10440000 {
samsung,combiner-nr = <20>;
};
diff --git a/arch/arm/boot/dts/exynos4415-pinctrl.dtsi b/arch/arm/boot/dts/exynos4415-pinctrl.dtsi
new file mode 100644
index 0000000..75af9c5
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4415-pinctrl.dtsi
@@ -0,0 +1,573 @@
+/*
+ * Samsung's Exynos4415 SoCs pin-mux and pin-config device tree source
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Samsung's Exynos4415 SoCs pin-mux and pin-config optiosn are listed as device
+ * tree nodes are listed in this file.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+&pinctrl_0 {
+ gpa0: gpa0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpa1: gpa1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpb: gpb {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpc0: gpc0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpc1: gpc1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpd0: gpd0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpd1: gpd1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf0: gpf0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf1: gpf1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpf2: gpf2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ uart0_data: uart0-data {
+ samsung,pins = "gpa0-0", "gpa0-1";
+ samsung,pin-function = <0x2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ uart0_fctl: uart0-fctl {
+ samsung,pins = "gpa0-2", "gpa0-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ uart1_data: uart1-data {
+ samsung,pins = "gpa0-4", "gpa0-5";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ uart1_fctl: uart1-fctl {
+ samsung,pins = "gpa0-6", "gpa0-7";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ uart2_data: uart2-data {
+ samsung,pins = "gpa1-0", "gpa1-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ uart2_fctl: uart2-fctl {
+ samsung,pins = "gpa1-2", "gpa1-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ uart3_data: uart3-data {
+ samsung,pins = "gpa1-4", "gpa1-5";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c2_bus: i2c2-bus {
+ samsung,pins = "gpa0-6", "gpa0-7";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c3_bus: i2c3-bus {
+ samsung,pins = "gpa1-2", "gpa1-3";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ spi0_bus: spi0-bus {
+ samsung,pins = "gpb-0", "gpb-2", "gpb-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c4_bus: i2c4-bus {
+ samsung,pins = "gpb-0", "gpb-1";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ spi1_bus: spi1-bus {
+ samsung,pins = "gpb-4", "gpb-6", "gpb-7";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c5_bus: i2c5-bus {
+ samsung,pins = "gpb-2", "gpb-3";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2s1_bus: i2s1-bus {
+ samsung,pins = "gpc0-0", "gpc0-1", "gpc0-2", "gpc0-3",
+ "gpc0-4";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2s2_bus: i2s2-bus {
+ samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
+ "gpc1-4";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ pcm2_bus: pcm2-bus {
+ samsung,pins = "gpc1-0", "gpc1-1", "gpc1-2", "gpc1-3",
+ "gpc1-4";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c6_bus: i2c6-bus {
+ samsung,pins = "gpc1-3", "gpc1-4";
+ samsung,pin-function = <4>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ spi2_bus: spi2-bus {
+ samsung,pins = "gpc1-1", "gpc1-3", "gpc1-4";
+ samsung,pin-function = <5>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ pwm0_out: pwm0-out {
+ samsung,pins = "gpd0-0";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ pwm1_out: pwm1-out {
+ samsung,pins = "gpd0-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ pwm2_out: pwm2-out {
+ samsung,pins = "gpd0-2";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ pwm3_out: pwm3-out {
+ samsung,pins = "gpd0-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c7_bus: i2c7-bus {
+ samsung,pins = "gpd0-2", "gpd0-3";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c0_bus: i2c0-bus {
+ samsung,pins = "gpd1-0", "gpd1-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ i2c1_bus: i2c1-bus {
+ samsung,pins = "gpd1-2", "gpd1-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_1 {
+ gpk0: gpk0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpk1: gpk1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpk2: gpk2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpk3: gpk3 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpl0: gpl0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpm0: gpm0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpm1: gpm1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpm2: gpm2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpm3: gpm3 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpm4: gpm4 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpx0: gpx0 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ interrupt-parent = <&gic>;
+ interrupts = <0 32 0>, <0 33 0>, <0 34 0>, <0 35 0>,
+ <0 36 0>, <0 37 0>, <0 38 0>, <0 39 0>;
+ #interrupt-cells = <2>;
+ };
+
+ gpx1: gpx1 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ interrupt-parent = <&gic>;
+ interrupts = <0 40 0>, <0 41 0>, <0 42 0>, <0 43 0>,
+ <0 44 0>, <0 45 0>, <0 46 0>, <0 47 0>;
+ #interrupt-cells = <2>;
+ };
+
+ gpx2: gpx2 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ gpx3: gpx3 {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ sd0_clk: sd0-clk {
+ samsung,pins = "gpk0-0";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd0_cmd: sd0-cmd {
+ samsung,pins = "gpk0-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd0_cd: sd0-cd {
+ samsung,pins = "gpk0-2";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd0_rdqs: sd0-rdqs {
+ samsung,pins = "gpk0-7";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd0_bus1: sd0-bus-width1 {
+ samsung,pins = "gpk0-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd0_bus4: sd0-bus-width4 {
+ samsung,pins = "gpk0-4", "gpk0-5", "gpk0-6";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd0_bus8: sd0-bus-width8 {
+ samsung,pins = "gpl0-0", "gpl0-1", "gpl0-2", "gpl0-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd1_clk: sd1-clk {
+ samsung,pins = "gpk1-0";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd1_cmd: sd1-cmd {
+ samsung,pins = "gpk1-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd1_cd: sd1-cd {
+ samsung,pins = "gpk1-2";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd1_bus1: sd1-bus-width1 {
+ samsung,pins = "gpk1-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd1_bus4: sd1-bus-width4 {
+ samsung,pins = "gpk1-4", "gpk1-5", "gpk1-6";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd2_clk: sd2-clk {
+ samsung,pins = "gpk2-0";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <4>;
+ };
+
+ sd2_cmd: sd2-cmd {
+ samsung,pins = "gpk2-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <4>;
+ };
+
+ sd2_cd: sd2-cd {
+ samsung,pins = "gpk2-2";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <3>;
+ };
+
+ sd2_bus1: sd2-bus-width1 {
+ samsung,pins = "gpk2-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <4>;
+ };
+
+ sd2_bus4: sd2-bus-width4 {
+ samsung,pins = "gpk2-4", "gpk2-5", "gpk2-6";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <4>;
+ };
+
+ cam_port_b_io: cam-port-b-io {
+ samsung,pins = "gpm0-0", "gpm0-1", "gpm0-2", "gpm0-3",
+ "gpm0-4", "gpm0-5", "gpm0-6", "gpm0-7",
+ "gpm1-0", "gpm1-1", "gpm2-0", "gpm2-1";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ cam_port_b_clk_active: cam-port-b-clk-active {
+ samsung,pins = "gpm2-2";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <3>;
+ };
+
+ cam_port_b_clk_idle: cam-port-b-clk-idle {
+ samsung,pins = "gpm2-2";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ fimc_is_i2c0: fimc-is-i2c0 {
+ samsung,pins = "gpm4-0", "gpm4-1";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ fimc_is_i2c1: fimc-is-i2c1 {
+ samsung,pins = "gpm4-2", "gpm4-3";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ fimc_is_uart: fimc-is-uart {
+ samsung,pins = "gpm3-5", "gpm3-7";
+ samsung,pin-function = <3>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_2 {
+ gpz: gpz {
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+
+ i2s0_bus: i2s0-bus {
+ samsung,pins = "gpz-0", "gpz-1", "gpz-2", "gpz-3",
+ "gpz-4", "gpz-5", "gpz-6";
+ samsung,pin-function = <2>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
diff --git a/arch/arm/boot/dts/exynos4415.dtsi b/arch/arm/boot/dts/exynos4415.dtsi
new file mode 100644
index 0000000..c1c9b37
--- /dev/null
+++ b/arch/arm/boot/dts/exynos4415.dtsi
@@ -0,0 +1,604 @@
+/*
+ * Samsung's Exynos4415 SoC device tree source
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ *
+ * Samsung's Exynos4415 SoC device nodes are listed in this file. Exynos4415
+ * based board files can include this file and provide values for board
+ * specific bindings.
+ *
+ * Note: This file does not include device nodes for all the controllers in
+ * Exynos4415 SoC. As device tree coverage for Exynos4415 increases, additional
+ * nodes can be added to this file.
+ *
+ * This program is free software; you can 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"
+#include <dt-bindings/clock/exynos4415.h>
+#include <dt-bindings/clock/exynos-audss-clk.h>
+
+/ {
+ compatible = "samsung,exynos4415";
+ interrupt-parent = <&gic>;
+
+ aliases {
+ pinctrl0 = &pinctrl_0;
+ pinctrl1 = &pinctrl_1;
+ pinctrl2 = &pinctrl_2;
+ mshc0 = &mshc_0;
+ mshc1 = &mshc_1;
+ mshc2 = &mshc_2;
+ spi0 = &spi_0;
+ spi1 = &spi_1;
+ spi2 = &spi_2;
+ i2c0 = &i2c_0;
+ i2c1 = &i2c_1;
+ i2c2 = &i2c_2;
+ i2c3 = &i2c_3;
+ i2c4 = &i2c_4;
+ i2c5 = &i2c_5;
+ i2c6 = &i2c_6;
+ i2c7 = &i2c_7;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@a00 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xa00>;
+ clock-frequency = <1600000000>;
+ };
+
+ cpu1: cpu@a01 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xa01>;
+ clock-frequency = <1600000000>;
+ };
+
+ cpu2: cpu@a02 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xa02>;
+ clock-frequency = <1600000000>;
+ };
+
+ cpu3: cpu@a03 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ reg = <0xa03>;
+ clock-frequency = <1600000000>;
+ };
+ };
+
+ soc: soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ sysram@02020000 {
+ compatible = "mmio-sram";
+ reg = <0x02020000 0x50000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x02020000 0x50000>;
+
+ smp-sysram@0 {
+ compatible = "samsung,exynos4210-sysram";
+ reg = <0x0 0x1000>;
+ };
+
+ smp-sysram@4f000 {
+ compatible = "samsung,exynos4210-sysram-ns";
+ reg = <0x4f000 0x1000>;
+ };
+ };
+
+ pinctrl_2: pinctrl@03860000 {
+ compatible = "samsung,exynos4415-pinctrl";
+ reg = <0x03860000 0x1000>;
+ interrupts = <0 242 0>;
+ };
+
+ chipid@10000000 {
+ compatible = "samsung,exynos4210-chipid";
+ reg = <0x10000000 0x100>;
+ };
+
+ sysreg_system_controller: syscon@10010000 {
+ compatible = "samsung,exynos4-sysreg", "syscon";
+ reg = <0x10010000 0x400>;
+ };
+
+ pmu_system_controller: system-controller@10020000 {
+ compatible = "samsung,exynos4415-pmu", "syscon";
+ reg = <0x10020000 0x4000>;
+ };
+
+ mipi_phy: video-phy@10020710 {
+ compatible = "samsung,s5pv210-mipi-video-phy";
+ reg = <0x10020710 8>;
+ #phy-cells = <1>;
+ };
+
+ pd_cam: cam-power-domain@10024000 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x10024000 0x20>;
+ };
+
+ pd_tv: tv-power-domain@10024020 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x10024020 0x20>;
+ };
+
+ pd_mfc: mfc-power-domain@10024040 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x10024040 0x20>;
+ };
+
+ pd_g3d: g3d-power-domain@10024060 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x10024060 0x20>;
+ };
+
+ pd_lcd0: lcd0-power-domain@10024080 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x10024080 0x20>;
+ };
+
+ pd_isp0: isp0-power-domain@100240A0 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x100240A0 0x20>;
+ };
+
+ pd_isp1: isp1-power-domain@100240E0 {
+ compatible = "samsung,exynos4210-pd";
+ reg = <0x100240E0 0x20>;
+ };
+
+ cmu: clock-controller@10030000 {
+ compatible = "samsung,exynos4415-cmu";
+ reg = <0x10030000 0x18000>;
+ #clock-cells = <1>;
+ };
+
+ rtc: rtc@10070000 {
+ compatible = "samsung,exynos3250-rtc";
+ reg = <0x10070000 0x100>;
+ interrupts = <0 73 0>, <0 74 0>;
+ status = "disabled";
+ };
+
+ mct@10050000 {
+ compatible = "samsung,exynos4210-mct";
+ reg = <0x10050000 0x800>;
+ interrupts = <0 218 0>, <0 219 0>, <0 220 0>, <0 221 0>,
+ <0 223 0>, <0 226 0>, <0 227 0>, <0 228 0>;
+ clocks = <&cmu CLK_FIN_PLL>, <&cmu CLK_MCT>;
+ clock-names = "fin_pll", "mct";
+ };
+
+ gic: interrupt-controller@10481000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x10481000 0x1000>,
+ <0x10482000 0x1000>,
+ <0x10484000 0x2000>,
+ <0x10486000 0x2000>;
+ interrupts = <1 9 0xf04>;
+ };
+
+ l2c: l2-cache-controller@10502000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x10502000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ arm,tag-latency = <2 2 1>;
+ arm,data-latency = <3 2 1>;
+ arm,double-linefill = <1>;
+ arm,double-linefill-incr = <0>;
+ arm,double-linefill-wrap = <1>;
+ arm,prefetch-drop = <1>;
+ arm,prefetch-offset = <7>;
+ };
+
+ cmu_dmc: clock-controller@105C0000 {
+ compatible = "samsung,exynos4415-cmu-dmc";
+ reg = <0x105C0000 0x3000>;
+ #clock-cells = <1>;
+ };
+
+ pinctrl_1: pinctrl@11000000 {
+ compatible = "samsung,exynos4415-pinctrl";
+ reg = <0x11000000 0x1000>;
+ interrupts = <0 225 0>;
+
+ wakeup-interrupt-controller {
+ compatible = "samsung,exynos4210-wakeup-eint";
+ interrupt-parent = <&gic>;
+ interrupts = <0 48 0>;
+ };
+ };
+
+ pinctrl_0: pinctrl@11400000 {
+ compatible = "samsung,exynos4415-pinctrl";
+ reg = <0x11400000 0x1000>;
+ interrupts = <0 240 0>;
+ };
+
+ hsotg: hsotg@12480000 {
+ compatible = "samsung,s3c6400-hsotg";
+ reg = <0x12480000 0x20000>;
+ interrupts = <0 141 0>;
+ clocks = <&cmu CLK_USBDEVICE>;
+ clock-names = "otg";
+ phys = <&exynos_usbphy 0>;
+ phy-names = "usb2-phy";
+ status = "disabled";
+ };
+
+ mshc_0: mshc@12510000 {
+ compatible = "samsung,exynos5250-dw-mshc";
+ reg = <0x12510000 0x1000>;
+ interrupts = <0 142 0>;
+ clocks = <&cmu CLK_SDMMC0>, <&cmu CLK_SCLK_MMC0>;
+ clock-names = "biu", "ciu";
+ fifo-depth = <0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ mshc_1: mshc@12520000 {
+ compatible = "samsung,exynos5250-dw-mshc";
+ reg = <0x12520000 0x1000>;
+ interrupts = <0 143 0>;
+ clocks = <&cmu CLK_SDMMC1>, <&cmu CLK_SCLK_MMC1>;
+ clock-names = "biu", "ciu";
+ fifo-depth = <0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ mshc_2: mshc@12530000 {
+ compatible = "samsung,exynos5250-dw-mshc";
+ reg = <0x12530000 0x1000>;
+ interrupts = <0 144 0>;
+ clocks = <&cmu CLK_SDMMC2>, <&cmu CLK_SCLK_MMC2>;
+ clock-names = "biu", "ciu";
+ fifo-depth = <0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ ehci: ehci@12580000 {
+ compatible = "samsung,exynos4210-ehci";
+ reg = <0x12580000 0x100>;
+ interrupts = <0 140 0>;
+ clocks = <&cmu CLK_USBHOST>;
+ clock-names = "usbhost";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ phys = <&exynos_usbphy 1>;
+ status = "disabled";
+ };
+ port@1 {
+ reg = <1>;
+ phys = <&exynos_usbphy 2>;
+ status = "disabled";
+ };
+ port@2 {
+ reg = <2>;
+ phys = <&exynos_usbphy 3>;
+ status = "disabled";
+ };
+ };
+
+ ohci: ohci@12590000 {
+ compatible = "samsung,exynos4210-ohci";
+ reg = <0x12590000 0x100>;
+ interrupts = <0 140 0>;
+ clocks = <&cmu CLK_USBHOST>;
+ clock-names = "usbhost";
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ port@0 {
+ reg = <0>;
+ phys = <&exynos_usbphy 1>;
+ status = "disabled";
+ };
+ };
+
+ exynos_usbphy: exynos-usbphy@125B0000 {
+ compatible = "samsung,exynos4x12-usb2-phy";
+ reg = <0x125B0000 0x100>;
+ samsung,pmureg-phandle = <&pmu_system_controller>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
+ clocks = <&cmu CLK_USBDEVICE>, <&xusbxti>;
+ clock-names = "phy", "ref";
+ #phy-cells = <1>;
+ status = "disabled";
+ };
+
+ amba {
+ compatible = "arm,amba-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ interrupt-parent = <&gic>;
+ ranges;
+
+ pdma0: pdma@12680000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x12680000 0x1000>;
+ interrupts = <0 138 0>;
+ clocks = <&cmu CLK_PDMA0>;
+ clock-names = "apb_pclk";
+ #dma-cells = <1>;
+ #dma-channels = <8>;
+ #dma-requests = <32>;
+ };
+
+ pdma1: pdma@12690000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x12690000 0x1000>;
+ interrupts = <0 139 0>;
+ clocks = <&cmu CLK_PDMA1>;
+ clock-names = "apb_pclk";
+ #dma-cells = <1>;
+ #dma-channels = <8>;
+ #dma-requests = <32>;
+ };
+ };
+
+ adc: adc@126C0000 {
+ compatible = "samsung,exynos3250-adc",
+ "samsung,exynos-adc-v2";
+ reg = <0x126C0000 0x100>, <0x10020718 0x4>;
+ interrupts = <0 137 0>;
+ clock-names = "adc", "sclk";
+ clocks = <&cmu CLK_TSADC>, <&cmu CLK_SCLK_TSADC>;
+ #io-channel-cells = <1>;
+ io-channel-ranges;
+ status = "disabled";
+ };
+
+ serial_0: serial@13800000 {
+ compatible = "samsung,exynos4210-uart";
+ reg = <0x13800000 0x100>;
+ interrupts = <0 109 0>;
+ clocks = <&cmu CLK_UART0>, <&cmu CLK_SCLK_UART0>;
+ clock-names = "uart", "clk_uart_baud0";
+ status = "disabled";
+ };
+
+ serial_1: serial@13810000 {
+ compatible = "samsung,exynos4210-uart";
+ reg = <0x13810000 0x100>;
+ interrupts = <0 110 0>;
+ clocks = <&cmu CLK_UART1>, <&cmu CLK_SCLK_UART1>;
+ clock-names = "uart", "clk_uart_baud0";
+ status = "disabled";
+ };
+
+ serial_2: serial@13820000 {
+ compatible = "samsung,exynos4210-uart";
+ reg = <0x13820000 0x100>;
+ interrupts = <0 111 0>;
+ clocks = <&cmu CLK_UART2>, <&cmu CLK_SCLK_UART2>;
+ clock-names = "uart", "clk_uart_baud0";
+ status = "disabled";
+ };
+
+ serial_3: serial@13830000 {
+ compatible = "samsung,exynos4210-uart";
+ reg = <0x13830000 0x100>;
+ interrupts = <0 112 0>;
+ clocks = <&cmu CLK_UART3>, <&cmu CLK_SCLK_UART3>;
+ clock-names = "uart", "clk_uart_baud0";
+ status = "disabled";
+ };
+
+ i2c_0: i2c@13860000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x13860000 0x100>;
+ interrupts = <0 113 0>;
+ clocks = <&cmu CLK_I2C0>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_bus>;
+ status = "disabled";
+ };
+
+ i2c_1: i2c@13870000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x13870000 0x100>;
+ interrupts = <0 114 0>;
+ clocks = <&cmu CLK_I2C1>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_bus>;
+ status = "disabled";
+ };
+
+ i2c_2: i2c@13880000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x13880000 0x100>;
+ interrupts = <0 115 0>;
+ clocks = <&cmu CLK_I2C2>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_bus>;
+ status = "disabled";
+ };
+
+ i2c_3: i2c@13890000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x13890000 0x100>;
+ interrupts = <0 116 0>;
+ clocks = <&cmu CLK_I2C3>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_bus>;
+ status = "disabled";
+ };
+
+ i2c_4: i2c@138A0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x138A0000 0x100>;
+ interrupts = <0 117 0>;
+ clocks = <&cmu CLK_I2C4>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c4_bus>;
+ status = "disabled";
+ };
+
+ i2c_5: i2c@138B0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x138B0000 0x100>;
+ interrupts = <0 118 0>;
+ clocks = <&cmu CLK_I2C5>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c5_bus>;
+ status = "disabled";
+ };
+
+ i2c_6: i2c@138C0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x138C0000 0x100>;
+ interrupts = <0 119 0>;
+ clocks = <&cmu CLK_I2C6>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c6_bus>;
+ status = "disabled";
+ };
+
+ i2c_7: i2c@138D0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "samsung,s3c2440-i2c";
+ reg = <0x138D0000 0x100>;
+ interrupts = <0 120 0>;
+ clocks = <&cmu CLK_I2C7>;
+ clock-names = "i2c";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c7_bus>;
+ status = "disabled";
+ };
+
+ spi_0: spi@13920000 {
+ compatible = "samsung,exynos4210-spi";
+ reg = <0x13920000 0x100>;
+ interrupts = <0 121 0>;
+ dmas = <&pdma0 7>, <&pdma0 6>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&cmu CLK_SPI0>, <&cmu CLK_SCLK_SPI0>;
+ clock-names = "spi", "spi_busclk0";
+ samsung,spi-src-clk = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_bus>;
+ status = "disabled";
+ };
+
+ spi_1: spi@13930000 {
+ compatible = "samsung,exynos4210-spi";
+ reg = <0x13930000 0x100>;
+ interrupts = <0 122 0>;
+ dmas = <&pdma1 7>, <&pdma1 6>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&cmu CLK_SPI1>, <&cmu CLK_SCLK_SPI1>;
+ clock-names = "spi", "spi_busclk0";
+ samsung,spi-src-clk = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi1_bus>;
+ status = "disabled";
+ };
+
+ spi_2: spi@13940000 {
+ compatible = "samsung,exynos4210-spi";
+ reg = <0x13940000 0x100>;
+ interrupts = <0 123 0>;
+ dmas = <&pdma0 9>, <&pdma0 8>;
+ dma-names = "tx", "rx";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&cmu CLK_SPI2>, <&cmu CLK_SCLK_SPI2>;
+ clock-names = "spi", "spi_busclk0";
+ samsung,spi-src-clk = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi2_bus>;
+ status = "disabled";
+ };
+
+ clock_audss: clock-controller@03810000 {
+ compatible = "samsung,exynos4210-audss-clock";
+ reg = <0x03810000 0x0C>;
+ #clock-cells = <1>;
+ };
+
+ i2s0: i2s@3830000 {
+ compatible = "samsung,s5pv210-i2s";
+ reg = <0x03830000 0x100>;
+ interrupts = <0 124 0>;
+ clocks = <&clock_audss EXYNOS_I2S_BUS>,
+ <&clock_audss EXYNOS_SCLK_I2S>;
+ clock-names = "iis", "i2s_opclk0";
+ dmas = <&pdma1 10>, <&pdma1 9>, <&pdma1 8>;
+ dma-names = "tx", "rx", "tx-sec";
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_bus>;
+ samsung,idma-addr = <0x03000000>;
+ status = "disabled";
+ };
+
+ pwm: pwm@139D0000 {
+ compatible = "samsung,exynos4210-pwm";
+ reg = <0x139D0000 0x1000>;
+ interrupts = <0 104 0>, <0 105 0>, <0 106 0>,
+ <0 107 0>, <0 108 0>;
+ #pwm-cells = <3>;
+ status = "disabled";
+ };
+
+ pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupts = <0 18 0>, <0 19 0>, <0 20 0>, <0 21 0>;
+ };
+ };
+};
+
+#include "exynos4415-pinctrl.dtsi"
diff --git a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
index 0865a2e..c141931 100644
--- a/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
+++ b/arch/arm/boot/dts/exynos4x12-pinctrl.dtsi
@@ -12,6 +12,22 @@
* published by the Free Software Foundation.
*/
+#define PIN_PULL_NONE 0
+#define PIN_PULL_DOWN 1
+#define PIN_PULL_UP 3
+
+#define PIN_PDN_OUT0 0
+#define PIN_PDN_OUT1 1
+#define PIN_PDN_INPUT 2
+#define PIN_PDN_PREV 3
+
+#define PIN_SLP(_pin, _mode, _pull) \
+ _pin { \
+ samsung,pins = #_pin; \
+ samsung,pin-con-pdn = <PIN_PDN_ ##_mode>; \
+ samsung,pin-pud-pdn = <PIN_PULL_ ##_pull>; \
+ }
+
/ {
pinctrl@11400000 {
gpa0: gpa0 {
diff --git a/arch/arm/boot/dts/exynos4x12.dtsi b/arch/arm/boot/dts/exynos4x12.dtsi
index 861bb91..2e9f1f7 100644
--- a/arch/arm/boot/dts/exynos4x12.dtsi
+++ b/arch/arm/boot/dts/exynos4x12.dtsi
@@ -271,4 +271,14 @@
compatible = "samsung,exynos4x12-usb2-phy";
samsung,sysreg-phandle = <&sys_reg>;
};
+
+ tmu@100C0000 {
+ compatible = "samsung,exynos4412-tmu";
+ interrupt-parent = <&combiner>;
+ interrupts = <2 4>;
+ reg = <0x100C0000 0x100>;
+ clocks = <&clock 383>;
+ clock-names = "tmu_apbif";
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/exynos5250-arndale.dts b/arch/arm/boot/dts/exynos5250-arndale.dts
index 3acd97e..7e728a1 100644
--- a/arch/arm/boot/dts/exynos5250-arndale.dts
+++ b/arch/arm/boot/dts/exynos5250-arndale.dts
@@ -7,12 +7,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.
-*/
+ */
/dts-v1/;
-#include "exynos5250.dtsi"
+#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/input/input.h>
+#include "exynos5250.dtsi"
/ {
model = "Insignal Arndale evaluation board based on EXYNOS5250";
@@ -26,465 +27,52 @@
bootargs = "console=ttySAC2,115200";
};
- rtc@101E0000 {
- status = "okay";
- };
-
- codec@11000000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
- };
-
- i2c@12C60000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <20000>;
- samsung,i2c-slave-addr = <0x66>;
- status = "okay";
-
- s5m8767_pmic@66 {
- compatible = "samsung,s5m8767-pmic";
- reg = <0x66>;
- interrupt-parent = <&gpx3>;
- interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
-
- vinb1-supply = <&main_dc_reg>;
- vinb2-supply = <&main_dc_reg>;
- vinb3-supply = <&main_dc_reg>;
- vinb4-supply = <&main_dc_reg>;
- vinb5-supply = <&main_dc_reg>;
- vinb6-supply = <&main_dc_reg>;
- vinb7-supply = <&main_dc_reg>;
- vinb8-supply = <&main_dc_reg>;
- vinb9-supply = <&main_dc_reg>;
-
- vinl1-supply = <&buck7_reg>;
- vinl2-supply = <&buck7_reg>;
- vinl3-supply = <&buck7_reg>;
- vinl4-supply = <&main_dc_reg>;
- vinl5-supply = <&main_dc_reg>;
- vinl6-supply = <&main_dc_reg>;
- vinl7-supply = <&main_dc_reg>;
- vinl8-supply = <&buck8_reg>;
- vinl9-supply = <&buck8_reg>;
-
- s5m8767,pmic-buck2-dvs-voltage = <1300000>;
- s5m8767,pmic-buck3-dvs-voltage = <1100000>;
- s5m8767,pmic-buck4-dvs-voltage = <1200000>;
- s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 0>,
- <&gpd1 1 0>,
- <&gpd1 2 0>;
- s5m8767,pmic-buck-ds-gpios = <&gpx2 3 0>,
- <&gpx2 4 0>,
- <&gpx2 5 0>;
- regulators {
- ldo1_reg: LDO1 {
- regulator-name = "VDD_ALIVE_1.0V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "VDD_28IO_DP_1.35V";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "VDD_COMMON1_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo4_reg: LDO4 {
- regulator-name = "VDD_IOPERI_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- op_mode = <1>;
- };
-
- ldo5_reg: LDO5 {
- regulator-name = "VDD_EXT_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "VDD_MPLL_1.1V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "VDD_XPLL_1.1V";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "VDD_COMMON2_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo9_reg: LDO9 {
- regulator-name = "VDD_33ON_3.0V";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- op_mode = <1>;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "VDD_COMMON3_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "VDD_ABB2_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "VDD_USB_3.0V";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo13_reg: LDO13 {
- regulator-name = "VDDQ_C2C_W_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo14_reg: LDO14 {
- regulator-name = "VDD18_ABB0_3_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "VDD10_COMMON4_1.0V";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "VDD18_HSIC_1.8V";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo17_reg: LDO17 {
- regulator-name = "VDDQ_MMC2_3_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- ldo18_reg: LDO18 {
- regulator-name = "VDD_33ON_2.8V";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- op_mode = <1>;
- };
-
- ldo22_reg: LDO22 {
- regulator-name = "EXT_33_OFF";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- op_mode = <1>;
- };
-
- ldo23_reg: LDO23 {
- regulator-name = "EXT_28_OFF";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- op_mode = <1>;
- };
-
- ldo25_reg: LDO25 {
- regulator-name = "PVDD_LDO25";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- op_mode = <1>;
- };
-
- ldo26_reg: LDO26 {
- regulator-name = "EXT_18_OFF";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- op_mode = <1>;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <912500>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "VDD_MEM_1.35V";
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1355000>;
- regulator-always-on;
- regulator-boot-on;
- op_mode = <1>;
- };
-
- buck7_reg: BUCK7 {
- regulator-name = "PVDD_BUCK7";
- regulator-always-on;
- op_mode = <1>;
- };
-
- buck8_reg: BUCK8 {
- regulator-name = "PVDD_BUCK8";
- regulator-always-on;
- op_mode = <1>;
- };
-
- buck9_reg: BUCK9 {
- regulator-name = "VDD_33_OFF_EXT1";
- regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <3000000>;
- op_mode = <1>;
- };
- };
- };
- };
-
- i2c@12C80000 {
- status = "okay";
-
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
- samsung,i2c-slave-addr = <0x50>;
-
- hdmiddc@50 {
- compatible = "samsung,exynos4210-hdmiddc";
- reg = <0x50>;
- };
- };
-
- i2c@12C90000 {
- status = "okay";
-
- wm1811a@1a {
-
- compatible = "wlf,wm1811";
- reg = <0x1a>;
-
- AVDD2-supply = <&main_dc_reg>;
- CPVDD-supply = <&main_dc_reg>;
- DBVDD1-supply = <&main_dc_reg>;
- DBVDD2-supply = <&main_dc_reg>;
- DBVDD3-supply = <&main_dc_reg>;
- LDO1VDD-supply = <&main_dc_reg>;
- SPKVDD1-supply = <&main_dc_reg>;
- SPKVDD2-supply = <&main_dc_reg>;
-
- wlf,ldo1ena = <&gpb0 0 0>;
- wlf,ldo2ena = <&gpb0 1 0>;
- };
- };
-
- i2c@12CE0000 {
- status = "okay";
-
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
- samsung,i2c-slave-addr = <0x38>;
-
- hdmiphy@38 {
- compatible = "samsung,exynos4212-hdmiphy";
- reg = <0x38>;
- };
- };
-
- i2c@121D0000 {
- status = "okay";
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <40000>;
- samsung,i2c-slave-addr = <0x38>;
-
- sata_phy_i2c:sata-phy@38 {
- compatible = "samsung,exynos-sataphy-i2c";
- reg = <0x38>;
- };
- };
-
- sata@122F0000 {
- status = "okay";
- };
-
- sata-phy@12170000 {
- status = "okay";
- samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>;
- };
-
- mmc_0: mmc@12200000 {
- status = "okay";
- num-slots = <1>;
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- vmmc-supply = <&mmc_reg>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
- bus-width = <8>;
- cap-mmc-highspeed;
- };
-
- mmc_2: mmc@12220000 {
- status = "okay";
- num-slots = <1>;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- vmmc-supply = <&mmc_reg>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
- bus-width = <4>;
- disable-wp;
- cap-sd-highspeed;
- };
-
- i2s0: i2s@03830000 {
- status = "okay";
- };
-
gpio_keys {
compatible = "gpio-keys";
menu {
label = "SW-TACT2";
- gpios = <&gpx1 4 1>;
+ gpios = <&gpx1 4 GPIO_ACTIVE_LOW>;
linux,code = <KEY_MENU>;
gpio-key,wakeup;
};
home {
label = "SW-TACT3";
- gpios = <&gpx1 5 1>;
+ gpios = <&gpx1 5 GPIO_ACTIVE_LOW>;
linux,code = <KEY_HOME>;
gpio-key,wakeup;
};
up {
label = "SW-TACT4";
- gpios = <&gpx1 6 1>;
+ gpios = <&gpx1 6 GPIO_ACTIVE_LOW>;
linux,code = <KEY_UP>;
gpio-key,wakeup;
};
down {
label = "SW-TACT5";
- gpios = <&gpx1 7 1>;
+ gpios = <&gpx1 7 GPIO_ACTIVE_LOW>;
linux,code = <KEY_DOWN>;
gpio-key,wakeup;
};
back {
label = "SW-TACT6";
- gpios = <&gpx2 0 1>;
+ gpios = <&gpx2 0 GPIO_ACTIVE_LOW>;
linux,code = <KEY_BACK>;
gpio-key,wakeup;
};
wakeup {
label = "SW-TACT7";
- gpios = <&gpx2 1 1>;
+ gpios = <&gpx2 1 GPIO_ACTIVE_LOW>;
linux,code = <KEY_WAKEUP>;
gpio-key,wakeup;
};
};
- hdmi {
- hpd-gpio = <&gpx3 7 2>;
- vdd_osc-supply = <&ldo10_reg>;
- vdd_pll-supply = <&ldo8_reg>;
- vdd-supply = <&ldo8_reg>;
- };
-
regulators {
compatible = "simple-bus";
#address-cells = <1>;
@@ -502,7 +90,7 @@
regulator-name = "VDD_33ON_2.8V";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
- gpio = <&gpx1 1 1>;
+ gpio = <&gpx1 1 GPIO_ACTIVE_LOW>;
enable-active-high;
};
@@ -520,46 +108,455 @@
};
};
- dp-controller@145B0000 {
- samsung,color-space = <0>;
- samsung,dynamic-range = <0>;
- samsung,ycbcr-coeff = <0>;
- samsung,color-depth = <1>;
- samsung,link-rate = <0x0a>;
- samsung,lane-count = <4>;
- status = "okay";
+ // SMSC USB3503 connected in hardware only mode as a PHY
+ usb_hub: usb-hub {
+ compatible = "smsc,usb3503a";
+
+ reset-gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
+ connect-gpios = <&gpd1 7 GPIO_ACTIVE_LOW>;
};
+};
- fimd: fimd@14400000 {
- status = "okay";
- display-timings {
- native-mode = <&timing0>;
- timing0: timing@0 {
- /* 2560x1600 DP panel */
- clock-frequency = <50000>;
- hactive = <2560>;
- vactive = <1600>;
- hfront-porch = <48>;
- hback-porch = <80>;
- hsync-len = <32>;
- vback-porch = <16>;
- vfront-porch = <8>;
- vsync-len = <6>;
- };
+&dp {
+ status = "okay";
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ samsung,link-rate = <0x0a>;
+ samsung,lane-count = <4>;
+};
+
+&fimd {
+ status = "okay";
+
+ display-timings {
+ native-mode = <&timing0>;
+
+ timing0: timing@0 {
+ /* 2560x1600 DP panel */
+ clock-frequency = <50000>;
+ hactive = <2560>;
+ vactive = <1600>;
+ hfront-porch = <48>;
+ hback-porch = <80>;
+ hsync-len = <32>;
+ vback-porch = <16>;
+ vfront-porch = <8>;
+ vsync-len = <6>;
};
};
+};
- usb_hub_bus {
- compatible = "simple-bus";
- #address-cells = <1>;
- #size-cells = <0>;
+&hdmi {
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_LOW>;
+ vdd_osc-supply = <&ldo10_reg>;
+ vdd_pll-supply = <&ldo8_reg>;
+ vdd-supply = <&ldo8_reg>;
+};
+
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
+ samsung,i2c-slave-addr = <0x66>;
+
+ s5m8767_pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_LEVEL_LOW>;
+
+ vinb1-supply = <&main_dc_reg>;
+ vinb2-supply = <&main_dc_reg>;
+ vinb3-supply = <&main_dc_reg>;
+ vinb4-supply = <&main_dc_reg>;
+ vinb5-supply = <&main_dc_reg>;
+ vinb6-supply = <&main_dc_reg>;
+ vinb7-supply = <&main_dc_reg>;
+ vinb8-supply = <&main_dc_reg>;
+ vinb9-supply = <&main_dc_reg>;
+
+ vinl1-supply = <&buck7_reg>;
+ vinl2-supply = <&buck7_reg>;
+ vinl3-supply = <&buck7_reg>;
+ vinl4-supply = <&main_dc_reg>;
+ vinl5-supply = <&main_dc_reg>;
+ vinl6-supply = <&main_dc_reg>;
+ vinl7-supply = <&main_dc_reg>;
+ vinl8-supply = <&buck8_reg>;
+ vinl9-supply = <&buck8_reg>;
+
+ s5m8767,pmic-buck2-dvs-voltage = <1300000>;
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>;
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>;
+ s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 GPIO_ACTIVE_HIGH>,
+ <&gpd1 1 GPIO_ACTIVE_HIGH>,
+ <&gpd1 2 GPIO_ACTIVE_HIGH>;
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 GPIO_ACTIVE_HIGH>,
+ <&gpx2 4 GPIO_ACTIVE_HIGH>,
+ <&gpx2 5 GPIO_ACTIVE_HIGH>;
+
+ regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "VDD_ALIVE_1.0V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
- // SMSC USB3503 connected in hardware only mode as a PHY
- usb_hub: usb_hub {
- compatible = "smsc,usb3503a";
+ ldo2_reg: LDO2 {
+ regulator-name = "VDD_28IO_DP_1.35V";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo3_reg: LDO3 {
+ regulator-name = "VDD_COMMON1_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo4_reg: LDO4 {
+ regulator-name = "VDD_IOPERI_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <1>;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "VDD_EXT_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "VDD_MPLL_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
- reset-gpios = <&gpx3 5 1>;
- connect-gpios = <&gpd1 7 1>;
+ ldo7_reg: LDO7 {
+ regulator-name = "VDD_XPLL_1.1V";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "VDD_COMMON2_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo9_reg: LDO9 {
+ regulator-name = "VDD_33ON_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ op_mode = <1>;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "VDD_COMMON3_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "VDD_ABB2_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "VDD_USB_3.0V";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "VDDQ_C2C_W_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "VDD18_ABB0_3_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "VDD10_COMMON4_1.0V";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "VDD18_HSIC_1.8V";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "VDDQ_MMC2_3_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ ldo18_reg: LDO18 {
+ regulator-name = "VDD_33ON_2.8V";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ op_mode = <1>;
+ };
+
+ ldo22_reg: LDO22 {
+ regulator-name = "EXT_33_OFF";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ op_mode = <1>;
+ };
+
+ ldo23_reg: LDO23 {
+ regulator-name = "EXT_28_OFF";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ op_mode = <1>;
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "PVDD_LDO25";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ op_mode = <1>;
+ };
+
+ ldo26_reg: LDO26 {
+ regulator-name = "EXT_18_OFF";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ op_mode = <1>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <912500>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "VDD_MEM_1.35V";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <1355000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck7_reg: BUCK7 {
+ regulator-name = "PVDD_BUCK7";
+ regulator-always-on;
+ op_mode = <1>;
+ };
+
+ buck8_reg: BUCK8 {
+ regulator-name = "PVDD_BUCK8";
+ regulator-always-on;
+ op_mode = <1>;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "VDD_33_OFF_EXT1";
+ regulator-min-microvolt = <750000>;
+ regulator-max-microvolt = <3000000>;
+ op_mode = <1>;
+ };
};
};
};
+
+&i2c_2 {
+ status = "okay";
+
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+ samsung,i2c-slave-addr = <0x50>;
+
+ hdmiddc@50 {
+ compatible = "samsung,exynos4210-hdmiddc";
+ reg = <0x50>;
+ };
+};
+
+&i2c_3 {
+ status = "okay";
+
+ wm1811a@1a {
+ compatible = "wlf,wm1811";
+ reg = <0x1a>;
+
+ AVDD2-supply = <&main_dc_reg>;
+ CPVDD-supply = <&main_dc_reg>;
+ DBVDD1-supply = <&main_dc_reg>;
+ DBVDD2-supply = <&main_dc_reg>;
+ DBVDD3-supply = <&main_dc_reg>;
+ LDO1VDD-supply = <&main_dc_reg>;
+ SPKVDD1-supply = <&main_dc_reg>;
+ SPKVDD2-supply = <&main_dc_reg>;
+
+ wlf,ldo1ena = <&gpb0 0 GPIO_ACTIVE_HIGH>;
+ wlf,ldo2ena = <&gpb0 1 GPIO_ACTIVE_HIGH>;
+ };
+};
+
+&i2c_8 {
+ status = "okay";
+
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+ samsung,i2c-slave-addr = <0x38>;
+
+ hdmiphy@38 {
+ compatible = "samsung,exynos4212-hdmiphy";
+ reg = <0x38>;
+ };
+};
+
+&i2c_9 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <40000>;
+ samsung,i2c-slave-addr = <0x38>;
+
+ sata_phy_i2c:sata-phy@38 {
+ compatible = "samsung,exynos-sataphy-i2c";
+ reg = <0x38>;
+ };
+};
+
+&i2s0 {
+ status = "okay";
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+ status = "okay";
+ num-slots = <1>;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ vmmc-supply = <&mmc_reg>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
+
+&mmc_2 {
+ status = "okay";
+ num-slots = <1>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ vmmc-supply = <&mmc_reg>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+ bus-width = <4>;
+ disable-wp;
+ cap-sd-highspeed;
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&sata_phy {
+ status = "okay";
+ samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>;
+};
diff --git a/arch/arm/boot/dts/exynos5250-smdk5250.dts b/arch/arm/boot/dts/exynos5250-smdk5250.dts
index 6a0f4c0..bc27cc2 100644
--- a/arch/arm/boot/dts/exynos5250-smdk5250.dts
+++ b/arch/arm/boot/dts/exynos5250-smdk5250.dts
@@ -7,9 +7,11 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
-*/
+ */
/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
#include "exynos5250.dtsi"
/ {
@@ -27,165 +29,6 @@
bootargs = "root=/dev/ram0 rw ramdisk=8192 initrd=0x41000000,8M console=ttySAC2,115200 init=/linuxrc";
};
- rtc@101E0000 {
- status = "okay";
- };
-
- i2c@12C60000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <20000>;
- status = "okay";
-
- eeprom@50 {
- compatible = "samsung,s524ad0xd1";
- reg = <0x50>;
- };
-
- max77686@09 {
- compatible = "maxim,max77686";
- reg = <0x09>;
- interrupt-parent = <&gpx3>;
- interrupts = <2 0>;
-
- voltage-regulators {
- ldo1_reg: LDO1 {
- regulator-name = "P1.0V_LDO_OUT1";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- regulator-always-on;
- };
-
- ldo2_reg: LDO2 {
- regulator-name = "P1.2V_LDO_OUT2";
- regulator-min-microvolt = <1200000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- };
-
- ldo3_reg: LDO3 {
- regulator-name = "P1.8V_LDO_OUT3";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- };
-
- ldo4_reg: LDO4 {
- regulator-name = "P2.8V_LDO_OUT4";
- regulator-min-microvolt = <2800000>;
- regulator-max-microvolt = <2800000>;
- };
-
- ldo5_reg: LDO5 {
- regulator-name = "P1.8V_LDO_OUT5";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo6_reg: LDO6 {
- regulator-name = "P1.1V_LDO_OUT6";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- ldo7_reg: LDO7 {
- regulator-name = "P1.1V_LDO_OUT7";
- regulator-min-microvolt = <1100000>;
- regulator-max-microvolt = <1100000>;
- regulator-always-on;
- };
-
- ldo8_reg: LDO8 {
- regulator-name = "P1.0V_LDO_OUT8";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- ldo10_reg: LDO10 {
- regulator-name = "P1.8V_LDO_OUT10";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo11_reg: LDO11 {
- regulator-name = "P1.8V_LDO_OUT11";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo12_reg: LDO12 {
- regulator-name = "P3.0V_LDO_OUT12";
- regulator-min-microvolt = <3000000>;
- regulator-max-microvolt = <3000000>;
- };
-
- ldo13_reg: LDO13 {
- regulator-name = "P1.8V_LDO_OUT13";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo14_reg: LDO14 {
- regulator-name = "P1.8V_LDO_OUT14";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- ldo15_reg: LDO15 {
- regulator-name = "P1.0V_LDO_OUT15";
- regulator-min-microvolt = <1000000>;
- regulator-max-microvolt = <1000000>;
- };
-
- ldo16_reg: LDO16 {
- regulator-name = "P1.8V_LDO_OUT16";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- };
-
- buck1_reg: BUCK1 {
- regulator-name = "vdd_mif";
- regulator-min-microvolt = <950000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck2_reg: BUCK2 {
- regulator-name = "vdd_arm";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1350000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck3_reg: BUCK3 {
- regulator-name = "vdd_int";
- regulator-min-microvolt = <900000>;
- regulator-max-microvolt = <1200000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck4_reg: BUCK4 {
- regulator-name = "vdd_g3d";
- regulator-min-microvolt = <850000>;
- regulator-max-microvolt = <1300000>;
- regulator-always-on;
- regulator-boot-on;
- };
-
- buck5_reg: BUCK5 {
- regulator-name = "P1.8V_BUCK_OUT5";
- regulator-min-microvolt = <1800000>;
- regulator-max-microvolt = <1800000>;
- regulator-always-on;
- regulator-boot-on;
- };
- };
- };
- };
-
vdd: fixed-regulator@0 {
compatible = "regulator-fixed";
regulator-name = "vdd-supply";
@@ -210,199 +53,360 @@
regulator-always-on;
};
- i2c@12C70000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <20000>;
- status = "okay";
+ sound {
+ compatible = "samsung,smdk-wm8994";
- eeprom@51 {
- compatible = "samsung,s524ad0xd1";
- reg = <0x51>;
+ samsung,i2s-controller = <&i2s0>;
+ samsung,audio-codec = <&wm8994>;
+ };
+
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <24000000>;
};
- wm8994: wm8994@1a {
- compatible = "wlf,wm8994";
- reg = <0x1a>;
+ codec_mclk: codec-mclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <16934000>;
+ };
+ };
+};
- gpio-controller;
- #gpio-cells = <2>;
+&dp {
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ samsung,link-rate = <0x0a>;
+ samsung,lane-count = <4>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_hpd>;
+ status = "okay";
+};
- clocks = <&codec_mclk>;
- clock-names = "MCLK1";
+&ehci {
+ samsung,vbus-gpio = <&gpx2 6 GPIO_ACTIVE_HIGH>;
+};
- AVDD2-supply = <&vdd>;
- CPVDD-supply = <&vdd>;
- DBVDD-supply = <&dbvdd>;
- SPKVDD1-supply = <&spkvdd>;
- SPKVDD2-supply = <&spkvdd>;
+&fimd {
+ status = "okay";
+
+ display-timings {
+ native-mode = <&timing0>;
+
+ timing0: timing@0 {
+ /* 1280x800 */
+ clock-frequency = <50000>;
+ hactive = <1280>;
+ vactive = <800>;
+ hfront-porch = <4>;
+ hback-porch = <4>;
+ hsync-len = <4>;
+ vback-porch = <4>;
+ vfront-porch = <4>;
+ vsync-len = <4>;
};
};
+};
- i2c@121D0000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <40000>;
- samsung,i2c-slave-addr = <0x38>;
- status = "okay";
+&hdmi {
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+};
- sata_phy_i2c:sata-phy@38 {
- compatible = "samsung,exynos-sataphy-i2c";
- reg = <0x38>;
- };
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
+
+ eeprom@50 {
+ compatible = "samsung,s524ad0xd1";
+ reg = <0x50>;
};
- i2c@12C80000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
- status = "okay";
+ max77686@09 {
+ compatible = "maxim,max77686";
+ reg = <0x09>;
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_NONE>;
+
+ voltage-regulators {
+ ldo1_reg: LDO1 {
+ regulator-name = "P1.0V_LDO_OUT1";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ };
- hdmiddc@50 {
- compatible = "samsung,exynos4210-hdmiddc";
- reg = <0x50>;
- };
- };
+ ldo2_reg: LDO2 {
+ regulator-name = "P1.2V_LDO_OUT2";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ };
- i2c@12CE0000 {
- samsung,i2c-sda-delay = <100>;
- samsung,i2c-max-bus-freq = <66000>;
- status = "okay";
+ ldo3_reg: LDO3 {
+ regulator-name = "P1.8V_LDO_OUT3";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ };
- hdmiphy@38 {
- compatible = "samsung,exynos4212-hdmiphy";
- reg = <0x38>;
- };
- };
+ ldo4_reg: LDO4 {
+ regulator-name = "P2.8V_LDO_OUT4";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ };
- sata@122F0000 {
- status = "okay";
- };
+ ldo5_reg: LDO5 {
+ regulator-name = "P1.8V_LDO_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- sata-phy@12170000 {
- status = "okay";
- samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>;
- };
+ ldo6_reg: LDO6 {
+ regulator-name = "P1.1V_LDO_OUT6";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
- mmc@12200000 {
- status = "okay";
- num-slots = <1>;
- broken-cd;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
- bus-width = <8>;
- cap-mmc-highspeed;
- };
+ ldo7_reg: LDO7 {
+ regulator-name = "P1.1V_LDO_OUT7";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ };
- mmc@12220000 {
- status = "okay";
- num-slots = <1>;
- card-detect-delay = <200>;
- samsung,dw-mshc-ciu-div = <3>;
- samsung,dw-mshc-sdr-timing = <2 3>;
- samsung,dw-mshc-ddr-timing = <1 2>;
- pinctrl-names = "default";
- pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
- bus-width = <4>;
- disable-wp;
- cap-sd-highspeed;
- };
+ ldo8_reg: LDO8 {
+ regulator-name = "P1.0V_LDO_OUT8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "P1.8V_LDO_OUT10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- spi_1: spi@12d30000 {
- cs-gpios = <&gpa2 5 0>;
- status = "okay";
+ ldo11_reg: LDO11 {
+ regulator-name = "P1.8V_LDO_OUT11";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
- w25q80bw@0 {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "w25x80";
- reg = <0>;
- spi-max-frequency = <1000000>;
+ ldo12_reg: LDO12 {
+ regulator-name = "P3.0V_LDO_OUT12";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ };
- controller-data {
- samsung,spi-feedback-delay = <0>;
+ ldo13_reg: LDO13 {
+ regulator-name = "P1.8V_LDO_OUT13";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
};
- partition@0 {
- label = "U-Boot";
- reg = <0x0 0x40000>;
- read-only;
+ ldo14_reg: LDO14 {
+ regulator-name = "P1.8V_LDO_OUT14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
};
- partition@40000 {
- label = "Kernel";
- reg = <0x40000 0xc0000>;
+ ldo15_reg: LDO15 {
+ regulator-name = "P1.0V_LDO_OUT15";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "P1.8V_LDO_OUT16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "P1.8V_BUCK_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
};
};
};
+};
- hdmi {
- hpd-gpio = <&gpx3 7 0>;
- };
+&i2c_1 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <20000>;
- codec@11000000 {
- samsung,mfc-r = <0x43000000 0x800000>;
- samsung,mfc-l = <0x51000000 0x800000>;
+ eeprom@51 {
+ compatible = "samsung,s524ad0xd1";
+ reg = <0x51>;
};
- i2s0: i2s@03830000 {
- status = "okay";
+ wm8994: wm8994@1a {
+ compatible = "wlf,wm8994";
+ reg = <0x1a>;
+
+ gpio-controller;
+ #gpio-cells = <2>;
+
+ clocks = <&codec_mclk>;
+ clock-names = "MCLK1";
+
+ AVDD2-supply = <&vdd>;
+ CPVDD-supply = <&vdd>;
+ DBVDD-supply = <&dbvdd>;
+ SPKVDD1-supply = <&spkvdd>;
+ SPKVDD2-supply = <&spkvdd>;
};
+};
- sound {
- compatible = "samsung,smdk-wm8994";
+&i2c_2 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
- samsung,i2s-controller = <&i2s0>;
- samsung,audio-codec = <&wm8994>;
+ hdmiddc@50 {
+ compatible = "samsung,exynos4210-hdmiddc";
+ reg = <0x50>;
};
+};
+
+&i2c_8 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
- usb@12110000 {
- samsung,vbus-gpio = <&gpx2 6 0>;
+ hdmiphy@38 {
+ compatible = "samsung,exynos4212-hdmiphy";
+ reg = <0x38>;
};
+};
+
+&i2c_9 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <40000>;
+ samsung,i2c-slave-addr = <0x38>;
- dp-controller@145B0000 {
- samsung,color-space = <0>;
- samsung,dynamic-range = <0>;
- samsung,ycbcr-coeff = <0>;
- samsung,color-depth = <1>;
- samsung,link-rate = <0x0a>;
- samsung,lane-count = <4>;
-
- pinctrl-names = "default";
- pinctrl-0 = <&dp_hpd>;
- status = "okay";
+ sata_phy_i2c: sata-phy@38 {
+ compatible = "samsung,exynos-sataphy-i2c";
+ reg = <0x38>;
};
+};
- fimd@14400000 {
- status = "okay";
- display-timings {
- native-mode = <&timing0>;
- timing0: timing@0 {
- /* 1280x800 */
- clock-frequency = <50000>;
- hactive = <1280>;
- vactive = <800>;
- hfront-porch = <4>;
- hback-porch = <4>;
- hsync-len = <4>;
- vback-porch = <4>;
- vfront-porch = <4>;
- vsync-len = <4>;
- };
+&i2s0 {
+ status = "okay";
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+ status = "okay";
+ num-slots = <1>;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_bus4 &sd0_bus8>;
+ bus-width = <8>;
+ cap-mmc-highspeed;
+};
+
+&mmc_2 {
+ status = "okay";
+ num-slots = <1>;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
+ bus-width = <4>;
+ disable-wp;
+ cap-sd-highspeed;
+};
+
+&rtc {
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&sata_phy {
+ status = "okay";
+ samsung,exynos-sataphy-i2c-phandle = <&sata_phy_i2c>;
+};
+
+&spi_1 {
+ status = "okay";
+ cs-gpios = <&gpa2 5 GPIO_ACTIVE_HIGH>;
+
+ w25q80bw@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "w25x80";
+ reg = <0>;
+ spi-max-frequency = <1000000>;
+
+ controller-data {
+ samsung,spi-feedback-delay = <0>;
};
- };
- fixed-rate-clocks {
- xxti {
- compatible = "samsung,clock-xxti";
- clock-frequency = <24000000>;
+ partition@0 {
+ label = "U-Boot";
+ reg = <0x0 0x40000>;
+ read-only;
};
- codec_mclk: codec-mclk {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <16934000>;
+ partition@40000 {
+ label = "Kernel";
+ reg = <0x40000 0xc0000>;
};
};
};
diff --git a/arch/arm/boot/dts/exynos5250-snow.dts b/arch/arm/boot/dts/exynos5250-snow.dts
index 60429ad..effaf2a 100644
--- a/arch/arm/boot/dts/exynos5250-snow.dts
+++ b/arch/arm/boot/dts/exynos5250-snow.dts
@@ -6,10 +6,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.
-*/
+ */
/dts-v1/;
#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/clock/maxim,max77686.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
#include "exynos5250.dtsi"
/ {
@@ -25,76 +28,7 @@
};
chosen {
- };
-
- rtc@101E0000 {
- status = "okay";
- };
-
- pinctrl@11400000 {
- ec_irq: ec-irq {
- samsung,pins = "gpx1-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- sd3_clk: sd3-clk {
- samsung,pin-drv = <0>;
- };
-
- sd3_cmd: sd3-cmd {
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
- };
-
- sd3_bus4: sd3-bus-width4 {
- samsung,pin-drv = <0>;
- };
-
- max98095_en: max98095-en {
- samsung,pins = "gpx1-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
- };
-
- tps65090_irq: tps65090-irq {
- samsung,pins = "gpx2-6";
- samsung,pin-function = <0>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- usb3_vbus_en: usb3-vbus-en {
- samsung,pins = "gpx2-7";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
-
- hdmi_hpd_irq: hdmi-hpd-irq {
- samsung,pins = "gpx3-7";
- samsung,pin-function = <0>;
- samsung,pin-pud = <1>;
- samsung,pin-drv = <0>;
- };
- };
-
- pinctrl@13400000 {
- arb_their_claim: arb-their-claim {
- samsung,pins = "gpe0-4";
- samsung,pin-function = <0>;
- samsung,pin-pud = <3>;
- samsung,pin-drv = <0>;
- };
-
- arb_our_claim: arb-our-claim {
- samsung,pins = "gpf0-3";
- samsung,pin-function = <1>;
- samsung,pin-pud = <0>;
- samsung,pin-drv = <0>;
- };
+ bootargs = "console=tty1";
};
gpio-keys {
@@ -102,14 +36,14 @@
power {
label = "Power";
- gpios = <&gpx1 3 1>;
- linux,code = <116>; /* KEY_POWER */
+ gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
gpio-key,wakeup;
};
lid-switch {
label = "Lid";
- gpios = <&gpx3 5 1>;
+ gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
linux,input-type = <5>; /* EV_SW */
linux,code = <0>; /* SW_LID */
debounce-interval = <1>;
@@ -130,8 +64,8 @@
i2c-parent = <&{/i2c@12CA0000}>;
- our-claim-gpio = <&gpf0 3 1>;
- their-claim-gpios = <&gpe0 4 1>;
+ our-claim-gpio = <&gpf0 3 GPIO_ACTIVE_LOW>;
+ their-claim-gpios = <&gpe0 4 GPIO_ACTIVE_LOW>;
slew-delay-us = <10>;
wait-retry-us = <3000>;
wait-free-us = <50000>;
@@ -154,7 +88,7 @@
cros_ec: embedded-controller {
compatible = "google,cros-ec-i2c";
reg = <0x1e>;
- interrupts = <6 0>;
+ interrupts = <6 IRQ_TYPE_NONE>;
interrupt-parent = <&gpx1>;
pinctrl-names = "default";
pinctrl-0 = <&ec_irq>;
@@ -241,13 +175,6 @@
};
i2c@12CD0000 {
- max98095: codec@11 {
- compatible = "maxim,max98095";
- reg = <0x11>;
- pinctrl-0 = <&max98095_en>;
- pinctrl-names = "default";
- };
-
ptn3460: lvds-bridge@20 {
compatible = "nxp,ptn3460";
reg = <0x20>;
@@ -258,10 +185,6 @@
};
};
- i2s0: i2s@03830000 {
- status = "okay";
- };
-
sound {
compatible = "google,snow-audio-max98095";
@@ -275,20 +198,12 @@
regulator-name = "P5.0V_USB3CON";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
- gpio = <&gpx2 7 0>;
+ gpio = <&gpx2 7 GPIO_ACTIVE_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&usb3_vbus_en>;
enable-active-high;
};
- phy@12100000 {
- vbus-supply = <&usb3_vbus_reg>;
- };
-
- usb@12110000 {
- samsung,vbus-gpio = <&gpx1 1 0>;
- };
-
fixed-rate-clocks {
xxti {
compatible = "samsung,clock-xxti";
@@ -296,18 +211,6 @@
};
};
- hdmi {
- hpd-gpio = <&gpx3 7 0>;
- pinctrl-names = "default";
- pinctrl-0 = <&hdmi_hpd_irq>;
- phy = <&hdmiphy>;
- ddc = <&i2c_2>;
- hdmi-en-supply = <&tps65090_fet7>;
- vdd-supply = <&ldo8_reg>;
- vdd_osc-supply = <&ldo10_reg>;
- vdd_pll-supply = <&ldo8_reg>;
- };
-
backlight: backlight {
compatible = "pwm-backlight";
pwms = <&pwm 0 1000000 0>;
@@ -319,30 +222,46 @@
pinctrl-names = "default";
};
- fimd@14400000 {
- status = "okay";
- samsung,invert-vclk;
- };
-
panel: panel {
compatible = "auo,b116xw03";
power-supply = <&fet6>;
backlight = <&backlight>;
};
+};
- dp-controller@145B0000 {
- status = "okay";
- pinctrl-names = "default";
- pinctrl-0 = <&dp_hpd>;
- samsung,color-space = <0>;
- samsung,dynamic-range = <0>;
- samsung,ycbcr-coeff = <0>;
- samsung,color-depth = <1>;
- samsung,link-rate = <0x0a>;
- samsung,lane-count = <2>;
- samsung,hpd-gpio = <&gpx0 7 0>;
- bridge = <&ptn3460>;
- };
+&dp {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_hpd>;
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ samsung,link-rate = <0x0a>;
+ samsung,lane-count = <2>;
+ samsung,hpd-gpio = <&gpx0 7 GPIO_ACTIVE_HIGH>;
+ bridge = <&ptn3460>;
+};
+
+&ehci {
+ samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
+};
+
+&fimd {
+ status = "okay";
+ samsung,invert-vclk;
+};
+
+&hdmi {
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_hpd_irq>;
+ phy = <&hdmiphy>;
+ ddc = <&i2c_2>;
+ hdmi-en-supply = <&tps65090_fet7>;
+ vdd-supply = <&ldo8_reg>;
+ vdd_osc-supply = <&ldo10_reg>;
+ vdd_pll-supply = <&ldo8_reg>;
};
&i2c_0 {
@@ -350,10 +269,10 @@
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <378000>;
- max77686@09 {
+ max77686: max77686@09 {
compatible = "maxim,max77686";
interrupt-parent = <&gpx3>;
- interrupts = <2 0>;
+ interrupts = <2 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&max77686_irq>;
wakeup-source;
@@ -503,7 +422,7 @@
trackpad {
reg = <0x67>;
compatible = "cypress,cyapa";
- interrupts = <2 0>;
+ interrupts = <2 IRQ_TYPE_NONE>;
interrupt-parent = <&gpx1>;
wakeup-source;
};
@@ -550,6 +469,13 @@
status = "okay";
samsung,i2c-sda-delay = <100>;
samsung,i2c-max-bus-freq = <66000>;
+
+ max98095: codec@11 {
+ compatible = "maxim,max98095";
+ reg = <0x11>;
+ pinctrl-0 = <&max98095_en>;
+ pinctrl-names = "default";
+ };
};
&i2c_8 {
@@ -563,6 +489,10 @@
};
};
+&i2s0 {
+ status = "okay";
+};
+
&mmc_0 {
status = "okay";
num-slots = <1>;
@@ -587,7 +517,7 @@
pinctrl-names = "default";
pinctrl-0 = <&sd2_clk &sd2_cmd &sd2_cd &sd2_bus4>;
bus-width = <4>;
- wp-gpios = <&gpc2 1 0>;
+ wp-gpios = <&gpc2 1 GPIO_ACTIVE_HIGH>;
cap-sd-highspeed;
};
@@ -610,12 +540,82 @@
};
&pinctrl_0 {
+ ec_irq: ec-irq {
+ samsung,pins = "gpx1-6";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ max98095_en: max98095-en {
+ samsung,pins = "gpx1-7";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ tps65090_irq: tps65090-irq {
+ samsung,pins = "gpx2-6";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ usb3_vbus_en: usb3-vbus-en {
+ samsung,pins = "gpx2-7";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
max77686_irq: max77686-irq {
samsung,pins = "gpx3-2";
samsung,pin-function = <0>;
samsung,pin-pud = <0>;
samsung,pin-drv = <0>;
};
+
+ hdmi_hpd_irq: hdmi-hpd-irq {
+ samsung,pins = "gpx3-7";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_1 {
+ arb_their_claim: arb-their-claim {
+ samsung,pins = "gpe0-4";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ arb_our_claim: arb-our-claim {
+ samsung,pins = "gpf0-3";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&rtc {
+ status = "okay";
+ clocks = <&clock CLK_RTC>, <&max77686 MAX77686_CLK_AP>;
+ clock-names = "rtc", "rtc_src";
+};
+
+&sd3_bus4 {
+ samsung,pin-drv = <0>;
+};
+
+&sd3_clk {
+ samsung,pin-drv = <0>;
+};
+
+&sd3_cmd {
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
};
&spi_1 {
@@ -628,4 +628,8 @@
dr_mode = "host";
};
+&usbdrd_phy {
+ vbus-supply = <&usb3_vbus_reg>;
+};
+
#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/boot/dts/exynos5250-spring.dts b/arch/arm/boot/dts/exynos5250-spring.dts
new file mode 100644
index 0000000..f027754
--- /dev/null
+++ b/arch/arm/boot/dts/exynos5250-spring.dts
@@ -0,0 +1,566 @@
+/*
+ * Google Spring board device tree source
+ *
+ * Copyright (c) 2013 Google, Inc
+ * Copyright (c) 2014 SUSE LINUX Products GmbH
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+/dts-v1/;
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/input/input.h>
+#include "exynos5250.dtsi"
+
+/ {
+ model = "Google Spring";
+ compatible = "google,spring", "samsung,exynos5250", "samsung,exynos5";
+
+ memory {
+ reg = <0x40000000 0x80000000>;
+ };
+
+ chosen {
+ bootargs = "console=tty1";
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ pinctrl-names = "default";
+ pinctrl-0 = <&power_key_irq>, <&lid_irq>;
+
+ power {
+ label = "Power";
+ gpios = <&gpx1 3 GPIO_ACTIVE_LOW>;
+ linux,code = <KEY_POWER>;
+ gpio-key,wakeup;
+ };
+
+ lid-switch {
+ label = "Lid";
+ gpios = <&gpx3 5 GPIO_ACTIVE_LOW>;
+ linux,input-type = <5>; /* EV_SW */
+ linux,code = <0>; /* SW_LID */
+ debounce-interval = <1>;
+ gpio-key,wakeup;
+ };
+ };
+
+ usb-hub {
+ compatible = "smsc,usb3503a";
+ reset-gpios = <&gpe1 0 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hsic_reset>;
+ };
+
+ fixed-rate-clocks {
+ xxti {
+ compatible = "samsung,clock-xxti";
+ clock-frequency = <24000000>;
+ };
+ };
+};
+
+&dp {
+ status = "okay";
+ pinctrl-names = "default";
+ pinctrl-0 = <&dp_hpd_gpio>;
+ samsung,color-space = <0>;
+ samsung,dynamic-range = <0>;
+ samsung,ycbcr-coeff = <0>;
+ samsung,color-depth = <1>;
+ samsung,link-rate = <0x0a>;
+ samsung,lane-count = <1>;
+ samsung,hpd-gpio = <&gpc3 0 GPIO_ACTIVE_HIGH>;
+};
+
+&ehci {
+ samsung,vbus-gpio = <&gpx1 1 GPIO_ACTIVE_HIGH>;
+};
+
+&fimd {
+ status = "okay";
+ samsung,invert-vclk;
+};
+
+&hdmi {
+ hpd-gpio = <&gpx3 7 GPIO_ACTIVE_HIGH>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_hpd_irq>;
+ phy = <&hdmiphy>;
+ ddc = <&i2c_2>;
+ hdmi-en-supply = <&ldo8_reg>;
+ vdd-supply = <&ldo8_reg>;
+ vdd_osc-supply = <&ldo10_reg>;
+ vdd_pll-supply = <&ldo8_reg>;
+};
+
+&i2c_0 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ s5m8767-pmic@66 {
+ compatible = "samsung,s5m8767-pmic";
+ reg = <0x66>;
+ interrupt-parent = <&gpx3>;
+ interrupts = <2 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&s5m8767_irq &s5m8767_dvs &s5m8767_ds>;
+ wakeup-source;
+
+ s5m8767,pmic-buck-dvs-gpios = <&gpd1 0 GPIO_ACTIVE_LOW>, /* DVS1 */
+ <&gpd1 1 GPIO_ACTIVE_LOW>, /* DVS2 */
+ <&gpd1 2 GPIO_ACTIVE_LOW>; /* DVS3 */
+
+ s5m8767,pmic-buck-ds-gpios = <&gpx2 3 GPIO_ACTIVE_LOW>, /* SET1 */
+ <&gpx2 4 GPIO_ACTIVE_LOW>, /* SET2 */
+ <&gpx2 5 GPIO_ACTIVE_LOW>; /* SET3 */
+
+ /*
+ * The following arrays of DVS voltages are not used, since we are
+ * not using GPIOs to control PMIC bucks, but they must be defined
+ * to please the driver.
+ */
+ s5m8767,pmic-buck2-dvs-voltage = <1350000>, <1300000>,
+ <1250000>, <1200000>,
+ <1150000>, <1100000>,
+ <1000000>, <950000>;
+
+ s5m8767,pmic-buck3-dvs-voltage = <1100000>, <1100000>,
+ <1100000>, <1100000>,
+ <1000000>, <1000000>,
+ <1000000>, <1000000>;
+
+ s5m8767,pmic-buck4-dvs-voltage = <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>,
+ <1200000>, <1200000>;
+
+ clocks {
+ compatible = "samsung,s5m8767-clk";
+ #clock-cells = <1>;
+ clock-output-names = "en32khz_ap",
+ "en32khz_cp",
+ "en32khz_bt";
+ };
+
+ regulators {
+ ldo4_reg: LDO4 {
+ regulator-name = "P1.0V_LDO_OUT4";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo5_reg: LDO5 {
+ regulator-name = "P1.0V_LDO_OUT5";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo6_reg: LDO6 {
+ regulator-name = "vdd_mydp";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo7_reg: LDO7 {
+ regulator-name = "P1.1V_LDO_OUT7";
+ regulator-min-microvolt = <1100000>;
+ regulator-max-microvolt = <1100000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo8_reg: LDO8 {
+ regulator-name = "P1.0V_LDO_OUT8";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo10_reg: LDO10 {
+ regulator-name = "P1.8V_LDO_OUT10";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo11_reg: LDO11 {
+ regulator-name = "P1.8V_LDO_OUT11";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo12_reg: LDO12 {
+ regulator-name = "P3.0V_LDO_OUT12";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo13_reg: LDO13 {
+ regulator-name = "P1.8V_LDO_OUT13";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo14_reg: LDO14 {
+ regulator-name = "P1.8V_LDO_OUT14";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo15_reg: LDO15 {
+ regulator-name = "P1.0V_LDO_OUT15";
+ regulator-min-microvolt = <1000000>;
+ regulator-max-microvolt = <1000000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo16_reg: LDO16 {
+ regulator-name = "P1.8V_LDO_OUT16";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ op_mode = <3>;
+ };
+
+ ldo17_reg: LDO17 {
+ regulator-name = "P2.8V_LDO_OUT17";
+ regulator-min-microvolt = <2800000>;
+ regulator-max-microvolt = <2800000>;
+ regulator-always-on;
+ op_mode = <0>;
+ };
+
+ ldo25_reg: LDO25 {
+ regulator-name = "vdd_bridge";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ op_mode = <1>;
+ };
+
+ buck1_reg: BUCK1 {
+ regulator-name = "vdd_mif";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck2_reg: BUCK2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1350000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck3_reg: BUCK3 {
+ regulator-name = "vdd_int";
+ regulator-min-microvolt = <900000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck4_reg: BUCK4 {
+ regulator-name = "vdd_g3d";
+ regulator-min-microvolt = <850000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+
+ buck5_reg: BUCK5 {
+ regulator-name = "P1.8V_BUCK_OUT5";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <1>;
+ };
+
+ buck6_reg: BUCK6 {
+ regulator-name = "P1.2V_BUCK_OUT6";
+ regulator-min-microvolt = <1200000>;
+ regulator-max-microvolt = <1200000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <0>;
+ };
+
+ buck9_reg: BUCK9 {
+ regulator-name = "vdd_ummc";
+ regulator-min-microvolt = <950000>;
+ regulator-max-microvolt = <3000000>;
+ regulator-always-on;
+ regulator-boot-on;
+ op_mode = <3>;
+ };
+ };
+ };
+};
+
+&i2c_1 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ trackpad@4b {
+ compatible = "atmel,maxtouch";
+ reg = <0x4b>;
+ interrupt-parent = <&gpx1>;
+ interrupts = <2 IRQ_TYPE_EDGE_FALLING>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&trackpad_irq>;
+ linux,gpio-keymap = <KEY_RESERVED
+ KEY_RESERVED
+ KEY_RESERVED
+ KEY_RESERVED
+ KEY_RESERVED
+ BTN_LEFT>;
+ wakeup-source;
+ };
+};
+
+/*
+ * Disabled pullups since external part has its own pullups and
+ * double-pulling gets us out of spec in some cases.
+ */
+&i2c2_bus {
+ samsung,pin-pud = <0>;
+};
+
+&i2c_2 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ hdmiddc@50 {
+ compatible = "samsung,exynos4210-hdmiddc";
+ reg = <0x50>;
+ };
+};
+
+&i2c_3 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_4 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ cros_ec: embedded-controller {
+ compatible = "google,cros-ec-i2c";
+ reg = <0x1e>;
+ interrupts = <6 IRQ_TYPE_NONE>;
+ interrupt-parent = <&gpx1>;
+ wakeup-source;
+ pinctrl-names = "default";
+ pinctrl-0 = <&ec_irq>;
+ };
+};
+
+&i2c_5 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+};
+
+&i2c_7 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <66000>;
+
+ temperature-sensor@4c {
+ compatible = "gmt,g781";
+ reg = <0x4c>;
+ };
+};
+
+&i2c_8 {
+ status = "okay";
+ samsung,i2c-sda-delay = <100>;
+ samsung,i2c-max-bus-freq = <378000>;
+
+ hdmiphy: hdmiphy@38 {
+ compatible = "samsung,exynos4212-hdmiphy";
+ reg = <0x38>;
+ };
+};
+
+&i2s0 {
+ status = "okay";
+};
+
+&mfc {
+ samsung,mfc-r = <0x43000000 0x800000>;
+ samsung,mfc-l = <0x51000000 0x800000>;
+};
+
+&mmc_0 {
+ status = "okay";
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd0_clk &sd0_cmd &sd0_cd &sd0_bus4 &sd0_bus8>;
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <8>;
+ };
+};
+
+/*
+ * On Spring we've got SIP WiFi and so can keep drive strengths low to
+ * reduce EMI.
+ */
+&mmc_1 {
+ status = "okay";
+ num-slots = <1>;
+ supports-highspeed;
+ broken-cd;
+ card-detect-delay = <200>;
+ samsung,dw-mshc-ciu-div = <3>;
+ samsung,dw-mshc-sdr-timing = <2 3>;
+ samsung,dw-mshc-ddr-timing = <1 2>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&sd1_clk &sd1_cmd &sd1_cd &sd1_bus4>;
+
+ slot@0 {
+ reg = <0>;
+ bus-width = <4>;
+ };
+};
+
+&pinctrl_0 {
+ s5m8767_dvs: s5m8767-dvs {
+ samsung,pins = "gpd1-0", "gpd1-1", "gpd1-2";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+
+ dp_hpd_gpio: dp-hpd-gpio {
+ samsung,pins = "gpc3-0";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+ };
+
+ trackpad_irq: trackpad-irq {
+ samsung,pins = "gpx1-2";
+ samsung,pin-function = <0xf>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ power_key_irq: power-key-irq {
+ samsung,pins = "gpx1-3";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ ec_irq: ec-irq {
+ samsung,pins = "gpx1-6";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ s5m8767_ds: s5m8767-ds {
+ samsung,pins = "gpx2-3", "gpx2-4", "gpx2-5";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+
+ s5m8767_irq: s5m8767-irq {
+ samsung,pins = "gpx3-2";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ lid_irq: lid-irq {
+ samsung,pins = "gpx3-5";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+
+ hdmi_hpd_irq: hdmi-hpd-irq {
+ samsung,pins = "gpx3-7";
+ samsung,pin-function = <0>;
+ samsung,pin-pud = <1>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&pinctrl_1 {
+ hsic_reset: hsic-reset {
+ samsung,pins = "gpe1-0";
+ samsung,pin-function = <1>;
+ samsung,pin-pud = <0>;
+ samsung,pin-drv = <0>;
+ };
+};
+
+&sd1_bus4 {
+ samsung,pin-drv = <0>;
+};
+
+&sd1_cd {
+ samsung,pin-drv = <0>;
+};
+
+&sd1_clk {
+ samsung,pin-drv = <0>;
+};
+
+&sd1_cmd {
+ samsung,pin-pud = <3>;
+ samsung,pin-drv = <0>;
+};
+
+&spi_1 {
+ status = "okay";
+ samsung,spi-src-clk = <0>;
+ num-cs = <1>;
+};
+
+#include "cros-ec-keyboard.dtsi"
diff --git a/arch/arm/boot/dts/exynos5250.dtsi b/arch/arm/boot/dts/exynos5250.dtsi
index d55c1a2..d45a07e 100644
--- a/arch/arm/boot/dts/exynos5250.dtsi
+++ b/arch/arm/boot/dts/exynos5250.dtsi
@@ -218,7 +218,7 @@
clock-names = "fimg2d";
};
- codec@11000000 {
+ mfc: codec@11000000 {
compatible = "samsung,mfc-v6";
reg = <0x11000000 0x10000>;
interrupts = <0 96 0>;
@@ -227,7 +227,7 @@
clock-names = "mfc";
};
- rtc@101E0000 {
+ rtc: rtc@101E0000 {
clocks = <&clock CLK_RTC>;
clock-names = "rtc";
status = "disabled";
@@ -261,7 +261,7 @@
clock-names = "uart", "clk_uart_baud0";
};
- sata@122F0000 {
+ sata: sata@122F0000 {
compatible = "snps,dwc-ahci";
samsung,sata-freq = <66>;
reg = <0x122F0000 0x1ff>;
@@ -293,6 +293,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c0_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -306,6 +307,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c1_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -319,6 +321,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c2_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -332,6 +335,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c3_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -573,7 +577,7 @@
#phy-cells = <1>;
};
- usb@12110000 {
+ ehci: usb@12110000 {
compatible = "samsung,exynos4210-ehci";
reg = <0x12110000 0x100>;
interrupts = <0 71 0>;
@@ -588,7 +592,7 @@
};
};
- usb@12120000 {
+ ohci: usb@12120000 {
compatible = "samsung,exynos4210-ohci";
reg = <0x12120000 0x100>;
interrupts = <0 71 0>;
@@ -710,7 +714,7 @@
clock-names = "gscl";
};
- hdmi {
+ hdmi: hdmi {
compatible = "samsung,exynos4212-hdmi";
reg = <0x14530000 0x70000>;
interrupts = <0 95 0>;
@@ -736,14 +740,14 @@
#phy-cells = <0>;
};
- dp-controller@145B0000 {
+ dp: dp-controller@145B0000 {
clocks = <&clock CLK_DP>;
clock-names = "dp";
phys = <&dp_phy>;
phy-names = "dp";
};
- fimd@14400000 {
+ fimd: fimd@14400000 {
clocks = <&clock CLK_SCLK_FIMD1>, <&clock CLK_FIMD1>;
clock-names = "sclk_fimd", "fimd";
};
diff --git a/arch/arm/boot/dts/exynos5420-peach-pit.dts b/arch/arm/boot/dts/exynos5420-peach-pit.dts
index 82cdb74..9a050e1 100644
--- a/arch/arm/boot/dts/exynos5420-peach-pit.dts
+++ b/arch/arm/boot/dts/exynos5420-peach-pit.dts
@@ -12,6 +12,7 @@
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/maxim,max77802.h>
#include "exynos5420.dtsi"
/ {
@@ -151,7 +152,7 @@
status = "okay";
clock-frequency = <400000>;
- max77802-pmic@9 {
+ max77802: max77802-pmic@9 {
compatible = "maxim,max77802";
interrupt-parent = <&gpx3>;
interrupts = <1 IRQ_TYPE_NONE>;
@@ -560,7 +561,7 @@
status = "okay";
num-slots = <1>;
broken-cd;
- caps2-mmc-hs200-1_8v;
+ mmc-hs200-1_8v;
cap-mmc-highspeed;
non-removable;
card-detect-delay = <200>;
@@ -727,6 +728,8 @@
&rtc {
status = "okay";
+ clocks = <&clock CLK_RTC>, <&max77802 MAX77802_CLK_32K_AP>;
+ clock-names = "rtc", "rtc_src";
};
&spi_2 {
diff --git a/arch/arm/boot/dts/exynos5420.dtsi b/arch/arm/boot/dts/exynos5420.dtsi
index 8617a03..90bf401 100644
--- a/arch/arm/boot/dts/exynos5420.dtsi
+++ b/arch/arm/boot/dts/exynos5420.dtsi
@@ -560,6 +560,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c0_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -573,6 +574,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c1_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -586,6 +588,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c2_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
@@ -599,6 +602,7 @@
clock-names = "i2c";
pinctrl-names = "default";
pinctrl-0 = <&i2c3_bus>;
+ samsung,sysreg-phandle = <&sysreg_system_controller>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/exynos5800-peach-pi.dts b/arch/arm/boot/dts/exynos5800-peach-pi.dts
index 7bb1c8d..e8fdda8 100644
--- a/arch/arm/boot/dts/exynos5800-peach-pi.dts
+++ b/arch/arm/boot/dts/exynos5800-peach-pi.dts
@@ -12,6 +12,7 @@
#include <dt-bindings/input/input.h>
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/clock/maxim,max77802.h>
#include "exynos5800.dtsi"
/ {
@@ -150,7 +151,7 @@
status = "okay";
clock-frequency = <400000>;
- max77802-pmic@9 {
+ max77802: max77802-pmic@9 {
compatible = "maxim,max77802";
interrupt-parent = <&gpx3>;
interrupts = <1 IRQ_TYPE_NONE>;
@@ -548,7 +549,7 @@
status = "okay";
num-slots = <1>;
broken-cd;
- caps2-mmc-hs200-1_8v;
+ mmc-hs200-1_8v;
cap-mmc-highspeed;
non-removable;
card-detect-delay = <200>;
@@ -715,6 +716,8 @@
&rtc {
status = "okay";
+ clocks = <&clock CLK_RTC>, <&max77802 MAX77802_CLK_32K_AP>;
+ clock-names = "rtc", "rtc_src";
};
&spi_2 {
diff --git a/arch/arm/boot/dts/hisi-x5hd2-dkb.dts b/arch/arm/boot/dts/hisi-x5hd2-dkb.dts
index 05b44c2..721b092 100644
--- a/arch/arm/boot/dts/hisi-x5hd2-dkb.dts
+++ b/arch/arm/boot/dts/hisi-x5hd2-dkb.dts
@@ -51,3 +51,36 @@
&uart0 {
status = "okay";
};
+
+&gmac0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy-handle = <&phy2>;
+ phy-mode = "mii";
+ /* Placeholder, overwritten by bootloader */
+ mac-address = [00 00 00 00 00 00];
+ status = "okay";
+
+ phy2: ethernet-phy@2 {
+ reg = <2>;
+ };
+};
+
+&gmac1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy-handle = <&phy1>;
+ phy-mode = "rgmii";
+ /* Placeholder, overwritten by bootloader */
+ mac-address = [00 00 00 00 00 00];
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+};
+
+&ahci {
+ phys = <&sata_phy>;
+ phy-names = "sata-phy";
+};
diff --git a/arch/arm/boot/dts/hisi-x5hd2.dtsi b/arch/arm/boot/dts/hisi-x5hd2.dtsi
index f85ba29..c52722b 100644
--- a/arch/arm/boot/dts/hisi-x5hd2.dtsi
+++ b/arch/arm/boot/dts/hisi-x5hd2.dtsi
@@ -131,6 +131,249 @@
clock-names = "apb_pclk";
status = "disabled";
};
+
+ gpio0: gpio@b20000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb20000 0x1000>;
+ interrupts = <0 108 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio1: gpio@b21000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb21000 0x1000>;
+ interrupts = <0 109 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio2: gpio@b22000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb22000 0x1000>;
+ interrupts = <0 110 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio3: gpio@b23000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb23000 0x1000>;
+ interrupts = <0 111 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio4: gpio@b24000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb24000 0x1000>;
+ interrupts = <0 112 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio5: gpio@004000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0x004000 0x1000>;
+ interrupts = <0 113 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio6: gpio@b26000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb26000 0x1000>;
+ interrupts = <0 114 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio7: gpio@b27000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb27000 0x1000>;
+ interrupts = <0 115 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio8: gpio@b28000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb28000 0x1000>;
+ interrupts = <0 116 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio9: gpio@b29000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb29000 0x1000>;
+ interrupts = <0 117 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio10: gpio@b2a000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb2a000 0x1000>;
+ interrupts = <0 118 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio11: gpio@b2b000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb2b000 0x1000>;
+ interrupts = <0 119 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio12: gpio@b2c000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb2c000 0x1000>;
+ interrupts = <0 120 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio13: gpio@b2d000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb2d000 0x1000>;
+ interrupts = <0 121 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio14: gpio@b2e000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb2e000 0x1000>;
+ interrupts = <0 122 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio15: gpio@b2f000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb2f000 0x1000>;
+ interrupts = <0 123 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio16: gpio@b30000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb30000 0x1000>;
+ interrupts = <0 124 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ gpio17: gpio@b31000 {
+ compatible = "arm,pl061", "arm,primecell";
+ reg = <0xb31000 0x1000>;
+ interrupts = <0 125 0x4>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ clocks = <&clock HIX5HD2_FIXED_100M>;
+ clock-names = "apb_pclk";
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ status = "disabled";
+ };
+
+ wdt0: watchdog@a2c000 {
+ compatible = "arm,sp805", "arm,primecell";
+ arm,primecell-periphid = <0x00141805>;
+ reg = <0xa2c000 0x1000>;
+ interrupts = <0 29 4>;
+ clocks = <&clock HIX5HD2_WDG0_RST>;
+ clock-names = "apb_pclk";
+ };
};
local_timer@00a00600 {
@@ -148,9 +391,15 @@
};
sysctrl: system-controller@00000000 {
- compatible = "hisilicon,sysctrl";
+ compatible = "hisilicon,sysctrl", "syscon";
reg = <0x00000000 0x1000>;
- reboot-offset = <0x4>;
+ };
+
+ reboot {
+ compatible = "syscon-reboot";
+ regmap = <&sysctrl>;
+ offset = <0x4>;
+ mask = <0xdeadbeef>;
};
cpuctrl@00a22000 {
@@ -166,5 +415,142 @@
#clock-cells = <1>;
};
};
+
+ /* unremovable emmc as mmcblk0 */
+ mmc: mmc@1830000 {
+ compatible = "snps,dw-mshc";
+ reg = <0x1830000 0x1000>;
+ interrupts = <0 35 4>;
+ clocks = <&clock HIX5HD2_MMC_CIU_RST>,
+ <&clock HIX5HD2_MMC_BIU_CLK>;
+ clock-names = "ciu", "biu";
+ };
+
+ sd: mmc@1820000 {
+ compatible = "snps,dw-mshc";
+ reg = <0x1820000 0x1000>;
+ interrupts = <0 34 4>;
+ clocks = <&clock HIX5HD2_SD_CIU_RST>,
+ <&clock HIX5HD2_SD_BIU_CLK>;
+ clock-names = "ciu","biu";
+ };
+
+ gmac0: ethernet@1840000 {
+ compatible = "hisilicon,hix5hd2-gmac";
+ reg = <0x1840000 0x1000>,<0x184300c 0x4>;
+ interrupts = <0 71 4>;
+ clocks = <&clock HIX5HD2_MAC0_CLK>;
+ status = "disabled";
+ };
+
+ gmac1: ethernet@1841000 {
+ compatible = "hisilicon,hix5hd2-gmac";
+ reg = <0x1841000 0x1000>,<0x1843010 0x4>;
+ interrupts = <0 72 4>;
+ clocks = <&clock HIX5HD2_MAC1_CLK>;
+ status = "disabled";
+ };
+
+ usb0: ehci@1890000 {
+ compatible = "generic-ehci";
+ reg = <0x1890000 0x1000>;
+ interrupts = <0 66 4>;
+ clocks = <&clock HIX5HD2_USB_CLK>;
+ };
+
+ usb1: ohci@1880000 {
+ compatible = "generic-ohci";
+ reg = <0x1880000 0x1000>;
+ interrupts = <0 67 4>;
+ clocks = <&clock HIX5HD2_USB_CLK>;
+ };
+
+ peripheral_ctrl: syscon@a20000 {
+ compatible = "syscon";
+ reg = <0xa20000 0x1000>;
+ };
+
+ sata_phy: phy@1900000 {
+ compatible = "hisilicon,hix5hd2-sata-phy";
+ reg = <0x1900000 0x10000>;
+ #phy-cells = <0>;
+ hisilicon,peripheral-syscon = <&peripheral_ctrl>;
+ hisilicon,power-reg = <0x8 10>;
+ };
+
+ ahci: sata@1900000 {
+ compatible = "hisilicon,hisi-ahci";
+ reg = <0x1900000 0x10000>;
+ interrupts = <0 70 4>;
+ clocks = <&clock HIX5HD2_SATA_CLK>;
+ };
+
+ ir: ir@001000 {
+ compatible = "hisilicon,hix5hd2-ir";
+ reg = <0x001000 0x1000>;
+ interrupts = <0 47 4>;
+ clocks = <&clock HIX5HD2_FIXED_24M>;
+ hisilicon,power-syscon = <&sysctrl>;
+ };
+
+ i2c0: i2c@b10000 {
+ compatible = "hisilicon,hix5hd2-i2c";
+ reg = <0xb10000 0x1000>;
+ interrupts = <0 38 4>;
+ clocks = <&clock HIX5HD2_I2C0_RST>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@b11000 {
+ compatible = "hisilicon,hix5hd2-i2c";
+ reg = <0xb11000 0x1000>;
+ interrupts = <0 39 4>;
+ clocks = <&clock HIX5HD2_I2C1_RST>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@b12000 {
+ compatible = "hisilicon,hix5hd2-i2c";
+ reg = <0xb12000 0x1000>;
+ interrupts = <0 40 4>;
+ clocks = <&clock HIX5HD2_I2C2_RST>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@b13000 {
+ compatible = "hisilicon,hix5hd2-i2c";
+ reg = <0xb13000 0x1000>;
+ interrupts = <0 41 4>;
+ clocks = <&clock HIX5HD2_I2C3_RST>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@b16000 {
+ compatible = "hisilicon,hix5hd2-i2c";
+ reg = <0xb16000 0x1000>;
+ interrupts = <0 43 4>;
+ clocks = <&clock HIX5HD2_I2C4_RST>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c5: i2c@b17000 {
+ compatible = "hisilicon,hix5hd2-i2c";
+ reg = <0xb17000 0x1000>;
+ interrupts = <0 44 4>;
+ clocks = <&clock HIX5HD2_I2C5_RST>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
};
};
diff --git a/arch/arm/boot/dts/imx51.dtsi b/arch/arm/boot/dts/imx51.dtsi
index 92660e1..c0116cf 100644
--- a/arch/arm/boot/dts/imx51.dtsi
+++ b/arch/arm/boot/dts/imx51.dtsi
@@ -214,7 +214,9 @@
compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
reg = <0x70014000 0x4000>;
interrupts = <30>;
- clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>;
+ clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>,
+ <&clks IMX5_CLK_SSI2_ROOT_GATE>;
+ clock-names = "ipg", "baud";
dmas = <&sdma 24 1 0>,
<&sdma 25 1 0>;
dma-names = "rx", "tx";
@@ -504,7 +506,9 @@
compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
reg = <0x83fcc000 0x4000>;
interrupts = <29>;
- clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>;
+ clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>,
+ <&clks IMX5_CLK_SSI1_ROOT_GATE>;
+ clock-names = "ipg", "baud";
dmas = <&sdma 28 0 0>,
<&sdma 29 0 0>;
dma-names = "rx", "tx";
@@ -560,7 +564,9 @@
compatible = "fsl,imx51-ssi", "fsl,imx21-ssi";
reg = <0x83fe8000 0x4000>;
interrupts = <96>;
- clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>;
+ clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>,
+ <&clks IMX5_CLK_SSI3_ROOT_GATE>;
+ clock-names = "ipg", "baud";
dmas = <&sdma 46 0 0>,
<&sdma 47 0 0>;
dma-names = "rx", "tx";
diff --git a/arch/arm/boot/dts/imx53.dtsi b/arch/arm/boot/dts/imx53.dtsi
index f91725b..a30bddf 100644
--- a/arch/arm/boot/dts/imx53.dtsi
+++ b/arch/arm/boot/dts/imx53.dtsi
@@ -46,10 +46,21 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
- cpu@0 {
+ cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a8";
reg = <0x0>;
+ clocks = <&clks IMX5_CLK_ARM>;
+ clock-latency = <61036>;
+ voltage-tolerance = <5>;
+ operating-points = <
+ /* kHz */
+ 166666 850000
+ 400000 900000
+ 800000 1050000
+ 1000000 1200000
+ 1200000 1300000
+ >;
};
};
@@ -227,7 +238,9 @@
"fsl,imx21-ssi";
reg = <0x50014000 0x4000>;
interrupts = <30>;
- clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>;
+ clocks = <&clks IMX5_CLK_SSI2_IPG_GATE>,
+ <&clks IMX5_CLK_SSI2_ROOT_GATE>;
+ clock-names = "ipg", "baud";
dmas = <&sdma 24 1 0>,
<&sdma 25 1 0>;
dma-names = "rx", "tx";
@@ -675,7 +688,9 @@
"fsl,imx21-ssi";
reg = <0x63fcc000 0x4000>;
interrupts = <29>;
- clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>;
+ clocks = <&clks IMX5_CLK_SSI1_IPG_GATE>,
+ <&clks IMX5_CLK_SSI1_ROOT_GATE>;
+ clock-names = "ipg", "baud";
dmas = <&sdma 28 0 0>,
<&sdma 29 0 0>;
dma-names = "rx", "tx";
@@ -703,7 +718,9 @@
"fsl,imx21-ssi";
reg = <0x63fe8000 0x4000>;
interrupts = <96>;
- clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>;
+ clocks = <&clks IMX5_CLK_SSI3_IPG_GATE>,
+ <&clks IMX5_CLK_SSI3_ROOT_GATE>;
+ clock-names = "ipg", "baud";
dmas = <&sdma 46 0 0>,
<&sdma 47 0 0>;
dma-names = "rx", "tx";
diff --git a/arch/arm/boot/dts/imx6dl.dtsi b/arch/arm/boot/dts/imx6dl.dtsi
index b453e0e..1ac2fe7 100644
--- a/arch/arm/boot/dts/imx6dl.dtsi
+++ b/arch/arm/boot/dts/imx6dl.dtsi
@@ -13,6 +13,10 @@
#include "imx6qdl.dtsi"
/ {
+ aliases {
+ i2c3 = &i2c4;
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -114,3 +118,7 @@
"di0_sel", "di1_sel",
"di0", "di1";
};
+
+&vpu {
+ compatible = "fsl,imx6dl-vpu", "cnm,coda960";
+};
diff --git a/arch/arm/boot/dts/imx6q-tbs2910.dts b/arch/arm/boot/dts/imx6q-tbs2910.dts
new file mode 100644
index 0000000..a43abfa
--- /dev/null
+++ b/arch/arm/boot/dts/imx6q-tbs2910.dts
@@ -0,0 +1,432 @@
+/*
+ * Copyright 2014 Soeren Moch <smoch@web.de>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+
+#include "imx6q.dtsi"
+#include <dt-bindings/gpio/gpio.h>
+#include <dt-bindings/input/input.h>
+
+/ {
+ model = "TBS2910 Matrix ARM mini PC";
+ compatible = "tbs,imx6q-tbs2910", "fsl,imx6q";
+
+ chosen {
+ stdout-path = &uart1;
+ };
+
+ memory {
+ reg = <0x10000000 0x80000000>;
+ };
+
+ fan {
+ compatible = "gpio-fan";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_fan>;
+ gpios = <&gpio3 28 GPIO_ACTIVE_HIGH>;
+ gpio-fan,speed-map = <0 0
+ 3000 1>;
+ };
+
+ ir_recv {
+ compatible = "gpio-ir-receiver";
+ gpios = <&gpio3 18 GPIO_ACTIVE_LOW>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_ir>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpio_leds>;
+
+ blue {
+ label = "blue_status_led";
+ gpios = <&gpio1 2 GPIO_ACTIVE_HIGH>;
+ default-state = "keep";
+ };
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reg_2p5v: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "2P5V";
+ regulator-min-microvolt = <2500000>;
+ regulator-max-microvolt = <2500000>;
+ };
+
+ reg_3p3v: regulator@1 {
+ compatible = "regulator-fixed";
+ reg = <1>;
+ regulator-name = "3P3V";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ reg_5p0v: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "5P0V";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ };
+ };
+
+ sound-sgtl5000 {
+ audio-codec = <&sgtl5000>;
+ audio-routing =
+ "MIC_IN", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "Headphone Jack", "HP_OUT";
+ compatible = "fsl,imx-audio-sgtl5000";
+ model = "On-board Codec";
+ mux-ext-port = <3>;
+ mux-int-port = <1>;
+ ssi-controller = <&ssi1>;
+ };
+
+ sound-spdif {
+ compatible = "fsl,imx-audio-spdif";
+ model = "On-board SPDIF";
+ spdif-controller = <&spdif>;
+ spdif-out;
+ };
+};
+
+&audmux {
+ status = "okay";
+};
+
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio1 25 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&hdmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_hdmi>;
+ ddc-i2c-bus = <&i2c2>;
+ status = "okay";
+};
+
+&i2c1 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c1>;
+ status = "okay";
+
+ sgtl5000: sgtl5000@0a {
+ clocks = <&clks 201>;
+ compatible = "fsl,sgtl5000";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_sgtl5000>;
+ reg = <0x0a>;
+ VDDA-supply = <&reg_2p5v>;
+ VDDIO-supply = <&reg_3p3v>;
+ };
+};
+
+&i2c2 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ status = "okay";
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ status = "okay";
+
+ rtc: ds1307@68 {
+ compatible = "dallas,ds1307";
+ reg = <0x68>;
+ };
+};
+
+&pcie {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio7 12 GPIO_ACTIVE_HIGH>;
+ status = "okay";
+};
+
+&sata {
+ status = "okay";
+};
+
+&snvs_poweroff {
+ status = "okay";
+};
+
+&spdif {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_spdif>;
+ status = "okay";
+};
+
+&ssi1 {
+ status = "okay";
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+ status = "okay";
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&reg_5p0v>;
+ status = "okay";
+};
+
+&usbotg {
+ vbus-supply = <&reg_5p0v>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbotg>;
+ disable-over-current;
+ status = "okay";
+};
+
+&usdhc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc2>;
+ bus-width = <4>;
+ cd-gpios = <&gpio2 2 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&reg_3p3v>;
+ status = "okay";
+};
+
+&usdhc3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc3>;
+ bus-width = <4>;
+ cd-gpios = <&gpio2 0 GPIO_ACTIVE_HIGH>;
+ wp-gpios = <&gpio2 1 GPIO_ACTIVE_HIGH>;
+ vmmc-supply = <&reg_3p3v>;
+ status = "okay";
+};
+
+&usdhc4 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usdhc4>;
+ bus-width = <8>;
+ non-removable;
+ no-1-8-v;
+ status = "okay";
+};
+
+&iomuxc {
+ imx6q-tbs2910 {
+ pinctrl_enet: enetgrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_MDIO__ENET_MDIO 0x1b0b0
+ MX6QDL_PAD_ENET_MDC__ENET_MDC 0x1b0b0
+ MX6QDL_PAD_RGMII_TXC__RGMII_TXC 0x1b0b0
+ MX6QDL_PAD_RGMII_TD0__RGMII_TD0 0x1b0b0
+ MX6QDL_PAD_RGMII_TD1__RGMII_TD1 0x1b0b0
+ MX6QDL_PAD_RGMII_TD2__RGMII_TD2 0x1b0b0
+ MX6QDL_PAD_RGMII_TD3__RGMII_TD3 0x1b0b0
+ MX6QDL_PAD_RGMII_TX_CTL__RGMII_TX_CTL 0x1b0b0
+ MX6QDL_PAD_ENET_REF_CLK__ENET_TX_CLK 0x1b0b0
+ MX6QDL_PAD_RGMII_RXC__RGMII_RXC 0x1b0b0
+ MX6QDL_PAD_RGMII_RD0__RGMII_RD0 0x1b0b0
+ MX6QDL_PAD_RGMII_RD1__RGMII_RD1 0x1b0b0
+ MX6QDL_PAD_RGMII_RD2__RGMII_RD2 0x1b0b0
+ MX6QDL_PAD_RGMII_RD3__RGMII_RD3 0x1b0b0
+ MX6QDL_PAD_RGMII_RX_CTL__RGMII_RX_CTL 0x1b0b0
+ MX6QDL_PAD_GPIO_16__ENET_REF_CLK 0x4001b0a8
+ MX6QDL_PAD_ENET_CRS_DV__GPIO1_IO25 0x1b059
+ >;
+ };
+
+ pinctrl_hdmi: hdmigrp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__HDMI_TX_CEC_LINE 0x1f8b0
+ >;
+ };
+
+ pinctrl_i2c1: i2c1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT9__I2C1_SCL 0x4001b8b1
+ MX6QDL_PAD_CSI0_DAT8__I2C1_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_COL3__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_KEY_ROW3__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_3__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_GPIO_6__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_ir: irgrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D18__GPIO3_IO18 0x17059
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_17__GPIO7_IO12 0x17059
+ >;
+ };
+
+ pinctrl_sgtl5000: sgtl5000grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT7__AUD3_RXD 0x130b0
+ MX6QDL_PAD_CSI0_DAT4__AUD3_TXC 0x130b0
+ MX6QDL_PAD_CSI0_DAT5__AUD3_TXD 0x110b0
+ MX6QDL_PAD_CSI0_DAT6__AUD3_TXFS 0x130b0
+ MX6QDL_PAD_GPIO_0__CCM_CLKO1 0x130b0
+ >;
+ };
+
+ pinctrl_spdif: spdifgrp {
+ fsl,pins = <MX6QDL_PAD_GPIO_19__SPDIF_OUT 0x13091
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ MX6QDL_PAD_CSI0_DAT10__UART1_TX_DATA 0x1b0b1
+ MX6QDL_PAD_CSI0_DAT11__UART1_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D26__UART2_TX_DATA 0x1b0b1
+ MX6QDL_PAD_EIM_D27__UART2_RX_DATA 0x1b0b1
+ >;
+ };
+
+ pinctrl_usbotg: usbotggrp {
+ fsl,pins = <
+ MX6QDL_PAD_ENET_RX_ER__USB_OTG_ID 0x17059
+ >;
+ };
+
+ pinctrl_usdhc2: usdhc2grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD2_CMD__SD2_CMD 0x17059
+ MX6QDL_PAD_SD2_CLK__SD2_CLK 0x10059
+ MX6QDL_PAD_SD2_DAT0__SD2_DATA0 0x17059
+ MX6QDL_PAD_SD2_DAT1__SD2_DATA1 0x17059
+ MX6QDL_PAD_SD2_DAT2__SD2_DATA2 0x17059
+ MX6QDL_PAD_SD2_DAT3__SD2_DATA3 0x17059
+ MX6QDL_PAD_NANDF_D2__GPIO2_IO02 0x17059
+ >;
+ };
+
+ pinctrl_usdhc3: usdhc3grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD3_CMD__SD3_CMD 0x17059
+ MX6QDL_PAD_SD3_CLK__SD3_CLK 0x10059
+ MX6QDL_PAD_SD3_DAT0__SD3_DATA0 0x17059
+ MX6QDL_PAD_SD3_DAT1__SD3_DATA1 0x17059
+ MX6QDL_PAD_SD3_DAT2__SD3_DATA2 0x17059
+ MX6QDL_PAD_SD3_DAT3__SD3_DATA3 0x17059
+ MX6QDL_PAD_NANDF_D0__GPIO2_IO00 0x17059
+ MX6QDL_PAD_NANDF_D1__GPIO2_IO01 0x17059
+ >;
+ };
+
+ pinctrl_usdhc4: usdhc4grp {
+ fsl,pins = <
+ MX6QDL_PAD_SD4_CMD__SD4_CMD 0x17059
+ MX6QDL_PAD_SD4_CLK__SD4_CLK 0x10059
+ MX6QDL_PAD_SD4_DAT0__SD4_DATA0 0x17059
+ MX6QDL_PAD_SD4_DAT1__SD4_DATA1 0x17059
+ MX6QDL_PAD_SD4_DAT2__SD4_DATA2 0x17059
+ MX6QDL_PAD_SD4_DAT3__SD4_DATA3 0x17059
+ MX6QDL_PAD_SD4_DAT4__SD4_DATA4 0x17059
+ MX6QDL_PAD_SD4_DAT5__SD4_DATA5 0x17059
+ MX6QDL_PAD_SD4_DAT6__SD4_DATA6 0x17059
+ MX6QDL_PAD_SD4_DAT7__SD4_DATA7 0x17059
+ >;
+ };
+ };
+
+ gpio_fan {
+ pinctrl_gpio_fan: gpiofangrp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D28__GPIO3_IO28 0x130b1
+ >;
+ };
+ };
+
+ gpio_leds {
+ pinctrl_gpio_leds: gpioledsgrp {
+ fsl,pins = <
+ MX6QDL_PAD_GPIO_2__GPIO1_IO02 0x130b1
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/imx6q.dtsi b/arch/arm/boot/dts/imx6q.dtsi
index e9f3646..85f72e6 100644
--- a/arch/arm/boot/dts/imx6q.dtsi
+++ b/arch/arm/boot/dts/imx6q.dtsi
@@ -308,3 +308,7 @@
};
};
};
+
+&vpu {
+ compatible = "fsl,imx6q-vpu", "cnm,coda960";
+};
diff --git a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
index d3c0bf5..b5756c2 100644
--- a/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw52xx.dtsi
@@ -282,7 +282,6 @@
};
&ssi1 {
- fsl,mode = "i2s-slave";
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
index cade1bd..86f03c1 100644
--- a/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw53xx.dtsi
@@ -287,7 +287,6 @@
};
&ssi1 {
- fsl,mode = "i2s-slave";
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
index cf13239..4a8d97f 100644
--- a/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-gw54xx.dtsi
@@ -376,12 +376,10 @@
};
&ssi1 {
- fsl,mode = "i2s-slave";
status = "okay";
};
&ssi2 {
- fsl,mode = "i2s-slave";
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi
index 5847212..585b4f6 100644
--- a/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-phytec-pbab01.dtsi
@@ -9,17 +9,103 @@
* http://www.gnu.org/copyleft/gpl.html
*/
+#include <dt-bindings/sound/fsl-imx-audmux.h>
+
/ {
chosen {
linux,stdout-path = &uart4;
};
+
+ regulators {
+ sound_1v8: regulator@2 {
+ compatible = "regulator-fixed";
+ reg = <2>;
+ regulator-name = "i2s-audio-1v8";
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <1800000>;
+ };
+
+ sound_3v3: regulator@3 {
+ compatible = "regulator-fixed";
+ reg = <3>;
+ regulator-name = "i2s-audio-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+ };
+
+ tlv320_mclk: oscillator {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <19200000>;
+ clock-output-names = "tlv320-mclk";
+ };
+
+ sound {
+ compatible = "simple-audio-card";
+ simple-audio-card,name = "OnboardTLV320AIC3007";
+ simple-audio-card,format = "i2s";
+ simple-audio-card,bitclock-master = <&dailink_master>;
+ simple-audio-card,frame-master = <&dailink_master>;
+ simple-audio-card,widgets =
+ "Microphone", "Mic Jack",
+ "Line", "Line In",
+ "Line", "Line Out",
+ "Speaker", "Speaker",
+ "Headphone", "Headphone Jack";
+ simple-audio-card,routing =
+ "Line Out", "LLOUT",
+ "Line Out", "RLOUT",
+ "Speaker", "SPOP",
+ "Speaker", "SPOM",
+ "Headphone Jack", "HPLOUT",
+ "Headphone Jack", "HPROUT",
+ "MIC3L", "Mic Jack",
+ "MIC3R", "Mic Jack",
+ "Mic Jack", "Mic Bias",
+ "LINE1L", "Line In",
+ "LINE1R", "Line In";
+
+ simple-audio-card,cpu {
+ sound-dai = <&ssi2>;
+ };
+
+ dailink_master: simple-audio-card,codec {
+ sound-dai = <&codec>;
+ clocks = <&tlv320_mclk>;
+ };
+ };
+
};
-&fec {
+&audmux {
status = "okay";
+
+ ssi2 {
+ fsl,audmux-port = <1>;
+ fsl,port-config = <
+ (IMX_AUDMUX_V2_PTCR_TFSDIR |
+ IMX_AUDMUX_V2_PTCR_TFSEL(4) |
+ IMX_AUDMUX_V2_PTCR_TCLKDIR |
+ IMX_AUDMUX_V2_PTCR_TCSEL(4))
+ IMX_AUDMUX_V2_PDCR_RXDSEL(4)
+ >;
+ };
+
+ pins5 {
+ fsl,audmux-port = <4>;
+ fsl,port-config = <
+ 0x00000000
+ IMX_AUDMUX_V2_PDCR_RXDSEL(1)
+ >;
+ };
};
-&gpmi {
+&can1 {
+ status = "okay";
+};
+
+&fec {
status = "okay";
};
@@ -28,14 +114,18 @@
};
&i2c2 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c2>;
- clock-frequency = <100000>;
status = "okay";
- tlv320@18 {
- compatible = "ti,tlv320aic3x";
+ codec: tlv320@18 {
+ compatible = "ti,tlv320aic3007";
+ #sound-dai-cells = <0>;
reg = <0x18>;
+ ai3x-micbias-vg = <2>;
+
+ AVDD-supply = <&sound_3v3>;
+ IOVDD-supply = <&sound_3v3>;
+ DRVDD-supply = <&sound_3v3>;
+ DVDD-supply = <&sound_1v8>;
};
stmpe@41 {
@@ -55,9 +145,14 @@
};
&i2c3 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_i2c3>;
- clock-frequency = <100000>;
+ status = "okay";
+};
+
+&pcie {
+ status = "okay";
+};
+
+&ssi2 {
status = "okay";
};
@@ -84,19 +179,3 @@
&usdhc3 {
status = "okay";
};
-
-&iomuxc {
- pinctrl_i2c2: i2c2grp {
- fsl,pins = <
- MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1
- MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1
- >;
- };
-
- pinctrl_i2c3: i2c3grp {
- fsl,pins = <
- MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
- MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
- >;
- };
-};
diff --git a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
index 0e50bb0..19cc269 100644
--- a/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-phytec-pfla02.dtsi
@@ -58,6 +58,18 @@
};
};
+&audmux {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_audmux>;
+ status = "disabled";
+};
+
+&can1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_flexcan1>;
+ status = "disabled";
+};
+
&ecspi3 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_ecspi3>;
@@ -72,6 +84,22 @@
};
};
+&fec {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet>;
+ phy-mode = "rgmii";
+ phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
+ phy-supply = <&vdd_eth_io_reg>;
+ status = "disabled";
+};
+
+&gpmi {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_gpmi_nand>;
+ nand-on-flash-bbt;
+ status = "okay";
+};
+
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_i2c1>;
@@ -85,8 +113,8 @@
pmic@58 {
compatible = "dlg,da9063";
reg = <0x58>;
- interrupt-parent = <&gpio4>;
- interrupts = <17 0x8>; /* active-low GPIO4_17 */
+ interrupt-parent = <&gpio2>;
+ interrupts = <9 0x8>; /* active-low GPIO2_9 */
regulators {
vddcore_reg: bcore1 {
@@ -162,6 +190,18 @@
};
};
+&i2c2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c2>;
+ clock-frequency = <100000>;
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c3>;
+ clock-frequency = <100000>;
+};
+
&iomuxc {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_hog>;
@@ -171,7 +211,7 @@
fsl,pins = <
MX6QDL_PAD_EIM_D23__GPIO3_IO23 0x80000000
MX6QDL_PAD_DISP0_DAT3__GPIO4_IO24 0x80000000 /* SPI NOR chipselect */
- MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000 /* PMIC interrupt */
+ MX6QDL_PAD_SD4_DAT1__GPIO2_IO09 0x80000000 /* PMIC interrupt */
MX6QDL_PAD_ENET_TXD0__GPIO1_IO30 0x80000000 /* Green LED */
MX6QDL_PAD_EIM_EB3__GPIO2_IO31 0x80000000 /* Red LED */
>;
@@ -206,6 +246,13 @@
>;
};
+ pinctrl_flexcan1: flexcan1grp {
+ fsl,pins = <
+ MX6QDL_PAD_KEY_ROW2__FLEXCAN1_RX 0x1b0b0
+ MX6QDL_PAD_KEY_COL2__FLEXCAN1_TX 0x1b0b0
+ >;
+ };
+
pinctrl_gpmi_nand: gpminandgrp {
fsl,pins = <
MX6QDL_PAD_NANDF_CLE__NAND_CLE 0xb0b1
@@ -235,6 +282,24 @@
>;
};
+ pinctrl_i2c2: i2c2grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_EB2__I2C2_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D16__I2C2_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_i2c3: i2c3grp {
+ fsl,pins = <
+ MX6QDL_PAD_EIM_D17__I2C3_SCL 0x4001b8b1
+ MX6QDL_PAD_EIM_D18__I2C3_SDA 0x4001b8b1
+ >;
+ };
+
+ pinctrl_pcie: pciegrp {
+ fsl,pins = <MX6QDL_PAD_DI0_PIN15__GPIO4_IO17 0x80000000>;
+ };
+
pinctrl_uart3: uart3grp {
fsl,pins = <
MX6QDL_PAD_EIM_D24__UART3_TX_DATA 0x1b0b1
@@ -293,22 +358,22 @@
MX6QDL_PAD_ENET_TXD1__GPIO1_IO29 0x80000000
>;
};
- };
-};
-&fec {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_enet>;
- phy-mode = "rgmii";
- phy-reset-gpios = <&gpio3 23 GPIO_ACTIVE_LOW>;
- phy-supply = <&vdd_eth_io_reg>;
- status = "disabled";
+ pinctrl_audmux: audmuxgrp {
+ fsl,pins = <
+ MX6QDL_PAD_DISP0_DAT16__AUD5_TXC 0x130b0
+ MX6QDL_PAD_DISP0_DAT17__AUD5_TXD 0x110b0
+ MX6QDL_PAD_DISP0_DAT18__AUD5_TXFS 0x130b0
+ MX6QDL_PAD_DISP0_DAT19__AUD5_RXD 0x130b0
+ >;
+ };
+ };
};
-&gpmi {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_gpmi_nand>;
- nand-on-flash-bbt;
+&pcie {
+ pinctrl-name = "default";
+ pinctrl-0 = <&pinctrl_pcie>;
+ reset-gpio = <&gpio4 17 0>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/imx6qdl-rex.dtsi b/arch/arm/boot/dts/imx6qdl-rex.dtsi
index df7bcf8..488a640 100644
--- a/arch/arm/boot/dts/imx6qdl-rex.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-rex.dtsi
@@ -308,7 +308,6 @@
};
&ssi1 {
- fsl,mode = "i2s-slave";
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
index baf2f00..f1cd214 100644
--- a/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
+++ b/arch/arm/boot/dts/imx6qdl-sabresd.dtsi
@@ -107,10 +107,8 @@
"Headphone Jack", "HPOUTR",
"Ext Spk", "SPKOUTL",
"Ext Spk", "SPKOUTR",
- "MICBIAS", "AMIC",
- "IN3R", "MICBIAS",
- "DMIC", "MICBIAS",
- "DMICDAT", "DMIC";
+ "AMIC", "MICBIAS",
+ "IN3R", "AMIC";
mux-int-port = <2>;
mux-ext-port = <3>;
};
@@ -179,7 +177,7 @@
codec: wm8962@1a {
compatible = "wlf,wm8962";
reg = <0x1a>;
- clocks = <&clks 201>;
+ clocks = <&clks IMX6QDL_CLK_CKO>;
DCVDD-supply = <&reg_audio>;
DBVDD-supply = <&reg_audio>;
AVDD-supply = <&reg_audio>;
@@ -531,6 +529,10 @@
status = "okay";
};
+&snvs_poweroff {
+ status = "okay";
+};
+
&ssi2 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6qdl.dtsi b/arch/arm/boot/dts/imx6qdl.dtsi
index 9596ed5..4fc03b7 100644
--- a/arch/arm/boot/dts/imx6qdl.dtsi
+++ b/arch/arm/boot/dts/imx6qdl.dtsi
@@ -333,9 +333,17 @@
};
vpu: vpu@02040000 {
+ compatible = "cnm,coda960";
reg = <0x02040000 0x3c000>;
interrupts = <0 3 IRQ_TYPE_LEVEL_HIGH>,
<0 12 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "bit", "jpeg";
+ clocks = <&clks IMX6QDL_CLK_VPU_AXI>,
+ <&clks IMX6QDL_CLK_MMDC_CH0_AXI>,
+ <&clks IMX6QDL_CLK_OCRAM>;
+ clock-names = "per", "ahb", "ocram";
+ resets = <&src 1>;
+ iram = <&ocram>;
};
aipstz@0207c000 { /* AIPSTZ1 */
@@ -657,6 +665,12 @@
interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>,
<0 20 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ snvs_poweroff: snvs-poweroff@38 {
+ compatible = "fsl,sec-v4.0-poweroff";
+ reg = <0x38 0x4>;
+ status = "disabled";
+ };
};
epit1: epit@020d0000 { /* EPIT1 */
diff --git a/arch/arm/boot/dts/imx6sl-evk.dts b/arch/arm/boot/dts/imx6sl-evk.dts
index 898d14f..fda4932 100644
--- a/arch/arm/boot/dts/imx6sl-evk.dts
+++ b/arch/arm/boot/dts/imx6sl-evk.dts
@@ -580,6 +580,10 @@
status = "okay";
};
+&snvs_poweroff {
+ status = "okay";
+};
+
&ssi2 {
status = "okay";
};
diff --git a/arch/arm/boot/dts/imx6sl.dtsi b/arch/arm/boot/dts/imx6sl.dtsi
index dfd83e6..36ab8e0 100644
--- a/arch/arm/boot/dts/imx6sl.dtsi
+++ b/arch/arm/boot/dts/imx6sl.dtsi
@@ -574,6 +574,12 @@
interrupts = <0 19 IRQ_TYPE_LEVEL_HIGH>,
<0 20 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ snvs_poweroff: snvs-poweroff@38 {
+ compatible = "fsl,sec-v4.0-poweroff";
+ reg = <0x38 0x4>;
+ status = "disabled";
+ };
};
epit1: epit@020d0000 {
diff --git a/arch/arm/boot/dts/imx6sx-sdb.dts b/arch/arm/boot/dts/imx6sx-sdb.dts
index 82d6b34..1e6e5cc 100644
--- a/arch/arm/boot/dts/imx6sx-sdb.dts
+++ b/arch/arm/boot/dts/imx6sx-sdb.dts
@@ -105,6 +105,30 @@
gpio = <&gpio3 27 0>;
enable-active-high;
};
+
+ reg_peri_3v3: regulator@5 {
+ compatible = "regulator-fixed";
+ reg = <5>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_peri_3v3>;
+ regulator-name = "peri_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpios = <&gpio4 16 GPIO_ACTIVE_HIGH>;
+ enable-active-high;
+ regulator-always-on;
+ };
+
+ reg_enet_3v3: regulator@6 {
+ compatible = "regulator-fixed";
+ reg = <6>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet_3v3>;
+ regulator-name = "enet_3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpios = <&gpio2 6 GPIO_ACTIVE_LOW>;
+ };
};
sound {
@@ -133,6 +157,14 @@
&fec1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_enet1>;
+ phy-supply = <&reg_enet_3v3>;
+ phy-mode = "rgmii";
+ status = "okay";
+};
+
+&fec2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_enet2>;
phy-mode = "rgmii";
status = "okay";
};
@@ -304,6 +336,10 @@
status = "okay";
};
+&snvs_poweroff {
+ status = "okay";
+};
+
&ssi2 {
status = "okay";
};
@@ -394,6 +430,30 @@
MX6SX_PAD_RGMII1_RD2__ENET1_RX_DATA_2 0x3081
MX6SX_PAD_RGMII1_RD3__ENET1_RX_DATA_3 0x3081
MX6SX_PAD_RGMII1_RX_CTL__ENET1_RX_EN 0x3081
+ MX6SX_PAD_ENET2_RX_CLK__ENET2_REF_CLK_25M 0x91
+ >;
+ };
+
+ pinctrl_enet_3v3: enet3v3grp {
+ fsl,pins = <
+ MX6SX_PAD_ENET2_COL__GPIO2_IO_6 0x80000000
+ >;
+ };
+
+ pinctrl_enet2: enet2grp {
+ fsl,pins = <
+ MX6SX_PAD_RGMII2_TXC__ENET2_RGMII_TXC 0xa0b9
+ MX6SX_PAD_RGMII2_TD0__ENET2_TX_DATA_0 0xa0b1
+ MX6SX_PAD_RGMII2_TD1__ENET2_TX_DATA_1 0xa0b1
+ MX6SX_PAD_RGMII2_TD2__ENET2_TX_DATA_2 0xa0b1
+ MX6SX_PAD_RGMII2_TD3__ENET2_TX_DATA_3 0xa0b1
+ MX6SX_PAD_RGMII2_TX_CTL__ENET2_TX_EN 0xa0b1
+ MX6SX_PAD_RGMII2_RXC__ENET2_RX_CLK 0x3081
+ MX6SX_PAD_RGMII2_RD0__ENET2_RX_DATA_0 0x3081
+ MX6SX_PAD_RGMII2_RD1__ENET2_RX_DATA_1 0x3081
+ MX6SX_PAD_RGMII2_RD2__ENET2_RX_DATA_2 0x3081
+ MX6SX_PAD_RGMII2_RD3__ENET2_RX_DATA_3 0x3081
+ MX6SX_PAD_RGMII2_RX_CTL__ENET2_RX_EN 0x3081
>;
};
@@ -452,6 +512,12 @@
>;
};
+ pinctrl_peri_3v3: peri3v3grp {
+ fsl,pins = <
+ MX6SX_PAD_QSPI1A_DATA0__GPIO4_IO_16 0x80000000
+ >;
+ };
+
pinctrl_pwm3: pwm3grp-1 {
fsl,pins = <
MX6SX_PAD_SD1_DATA2__PWM3_OUT 0x110b0
diff --git a/arch/arm/boot/dts/imx6sx.dtsi b/arch/arm/boot/dts/imx6sx.dtsi
index f3e88c0..7a24fee 100644
--- a/arch/arm/boot/dts/imx6sx.dtsi
+++ b/arch/arm/boot/dts/imx6sx.dtsi
@@ -671,6 +671,12 @@
reg = <0x34 0x58>;
interrupts = <GIC_SPI 19 IRQ_TYPE_LEVEL_HIGH>, <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
};
+
+ snvs_poweroff: snvs-poweroff@38 {
+ compatible = "fsl,sec-v4.0-poweroff";
+ reg = <0x38 0x4>;
+ status = "disabled";
+ };
};
epit1: epit@020d0000 {
@@ -877,7 +883,7 @@
};
fec2: ethernet@021b4000 {
- compatible = "fsl,imx6sx-fec";
+ compatible = "fsl,imx6sx-fec", "fsl,imx6q-fec";
reg = <0x021b4000 0x4000>;
interrupts = <GIC_SPI 102 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 103 IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/integrator.dtsi b/arch/arm/boot/dts/integrator.dtsi
index 88e3d477..28e38f8 100644
--- a/arch/arm/boot/dts/integrator.dtsi
+++ b/arch/arm/boot/dts/integrator.dtsi
@@ -6,8 +6,18 @@
/ {
core-module@10000000 {
- compatible = "arm,core-module-integrator";
+ compatible = "arm,core-module-integrator", "syscon";
reg = <0x10000000 0x200>;
+
+ /* Use core module LED to indicate CPU load */
+ led@0c.0 {
+ compatible = "register-bit-led";
+ offset = <0x0c>;
+ mask = <0x01>;
+ label = "integrator:core_module";
+ linux,default-trigger = "cpu0";
+ default-state = "on";
+ };
};
ebi@12000000 {
@@ -82,5 +92,41 @@
reg = <0x19000000 0x1000>;
interrupts = <4>;
};
+
+ syscon {
+ /* Debug registers mapped as syscon */
+ compatible = "syscon";
+ reg = <0x1a000000 0x10>;
+
+ led@04.0 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x01>;
+ label = "integrator:green0";
+ linux,default-trigger = "heartbeat";
+ default-state = "on";
+ };
+ led@04.1 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x02>;
+ label = "integrator:yellow";
+ default-state = "off";
+ };
+ led@04.2 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x04>;
+ label = "integrator:red";
+ default-state = "off";
+ };
+ led@04.3 {
+ compatible = "register-bit-led";
+ offset = <0x04>;
+ mask = <0x08>;
+ label = "integrator:green1";
+ default-state = "off";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/k2e-evm.dts b/arch/arm/boot/dts/k2e-evm.dts
index c568f06..560d621 100644
--- a/arch/arm/boot/dts/k2e-evm.dts
+++ b/arch/arm/boot/dts/k2e-evm.dts
@@ -139,3 +139,15 @@
};
};
};
+
+&mdio {
+ ethphy0: ethernet-phy@0 {
+ compatible = "marvell,88E1514", "marvell,88E1510", "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ compatible = "marvell,88E1514", "marvell,88E1510", "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/k2e.dtsi b/arch/arm/boot/dts/k2e.dtsi
index c358b4b..5fc14683 100644
--- a/arch/arm/boot/dts/k2e.dtsi
+++ b/arch/arm/boot/dts/k2e.dtsi
@@ -85,6 +85,51 @@
#gpio-cells = <2>;
gpio,syscon-dev = <&devctrl 0x240>;
};
+
+ pcie@21020000 {
+ compatible = "ti,keystone-pcie","snps,dw-pcie";
+ clocks = <&clkpcie1>;
+ clock-names = "pcie";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ reg = <0x21021000 0x2000>, <0x21020000 0x1000>, <0x02620128 4>;
+ ranges = <0x81000000 0 0 0x23260000 0x4000 0x4000
+ 0x82000000 0 0x60000000 0x60000000 0 0x10000000>;
+
+ device_type = "pci";
+ num-lanes = <2>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc1 0>, /* INT A */
+ <0 0 0 2 &pcie_intc1 1>, /* INT B */
+ <0 0 0 3 &pcie_intc1 2>, /* INT C */
+ <0 0 0 4 &pcie_intc1 3>; /* INT D */
+
+ pcie_msi_intc1: msi-interrupt-controller {
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 377 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 378 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 379 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 380 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 381 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 382 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 383 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 384 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ pcie_intc1: legacy-interrupt-controller {
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 373 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 374 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 375 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 376 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/k2l-evm.dts b/arch/arm/boot/dts/k2l-evm.dts
index fec4312..85cc7f2 100644
--- a/arch/arm/boot/dts/k2l-evm.dts
+++ b/arch/arm/boot/dts/k2l-evm.dts
@@ -116,3 +116,15 @@
};
};
};
+
+&mdio {
+ ethphy0: ethernet-phy@0 {
+ compatible = "marvell,88E1514", "marvell,88E1510", "ethernet-phy-ieee802.3-c22";
+ reg = <0>;
+ };
+
+ ethphy1: ethernet-phy@1 {
+ compatible = "marvell,88E1514", "marvell,88E1510", "ethernet-phy-ieee802.3-c22";
+ reg = <1>;
+ };
+};
diff --git a/arch/arm/boot/dts/keystone.dtsi b/arch/arm/boot/dts/keystone.dtsi
index 5d3e83f..c06542b 100644
--- a/arch/arm/boot/dts/keystone.dtsi
+++ b/arch/arm/boot/dts/keystone.dtsi
@@ -285,5 +285,50 @@
#interrupt-cells = <1>;
ti,syscon-dev = <&devctrl 0x2a0>;
};
+
+ pcie@21800000 {
+ compatible = "ti,keystone-pcie", "snps,dw-pcie";
+ clocks = <&clkpcie>;
+ clock-names = "pcie";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ reg = <0x21801000 0x2000>, <0x21800000 0x1000>, <0x02620128 4>;
+ ranges = <0x81000000 0 0 0x23250000 0 0x4000
+ 0x82000000 0 0x50000000 0x50000000 0 0x10000000>;
+
+ device_type = "pci";
+ num-lanes = <2>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 0 7>;
+ interrupt-map = <0 0 0 1 &pcie_intc0 0>, /* INT A */
+ <0 0 0 2 &pcie_intc0 1>, /* INT B */
+ <0 0 0 3 &pcie_intc0 2>, /* INT C */
+ <0 0 0 4 &pcie_intc0 3>; /* INT D */
+
+ pcie_msi_intc0: msi-interrupt-controller {
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 30 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 31 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 32 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 33 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 34 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 35 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 36 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 37 IRQ_TYPE_EDGE_RISING>;
+ };
+
+ pcie_intc0: legacy-interrupt-controller {
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ interrupt-parent = <&gic>;
+ interrupts = <GIC_SPI 26 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 27 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 28 IRQ_TYPE_EDGE_RISING>,
+ <GIC_SPI 29 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/kirkwood-dir665.dts b/arch/arm/boot/dts/kirkwood-dir665.dts
new file mode 100644
index 0000000..786959e
--- /dev/null
+++ b/arch/arm/boot/dts/kirkwood-dir665.dts
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2014 Claudio Leite <leitec@staticky.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+/dts-v1/;
+
+#include "kirkwood.dtsi"
+#include "kirkwood-6281.dtsi"
+
+/ {
+ model = "D-Link DIR-665";
+ compatible = "dlink,dir-665", "marvell,kirkwood-88f6281", "marvell,kirkwood";
+
+ memory {
+ device_type = "memory";
+ reg = <0x00000000 0x8000000>; /* 128 MB */
+ };
+
+ chosen {
+ bootargs = "console=ttyS0,115200n8 earlyprintk";
+ stdout-path = &uart0;
+ };
+
+ mbus {
+ pcie-controller {
+ status = "okay";
+
+ pcie@1,0 {
+ status = "okay";
+ };
+ };
+ };
+
+ ocp@f1000000 {
+ pinctrl: pin-controller@10000 {
+ pinctrl-0 =< &pmx_led_usb
+ &pmx_led_internet_blue
+ &pmx_led_internet_amber
+ &pmx_led_5g &pmx_led_status_blue
+ &pmx_led_wps &pmx_led_status_amber
+ &pmx_led_24g
+ &pmx_btn_restart &pmx_btn_wps>;
+ pinctrl-names = "default";
+
+ pmx_led_usb: pmx-led-usb {
+ marvell,pins = "mpp12";
+ marvell,function = "gpio";
+ };
+ pmx_led_internet_blue: pmx-led-internet-blue {
+ marvell,pins = "mpp42";
+ marvell,function = "gpio";
+ };
+ pmx_led_internet_amber: pmx-led-internet-amber {
+ marvell,pins = "mpp43";
+ marvell,function = "gpio";
+ };
+ pmx_led_5g: pmx-led-5g {
+ marvell,pins = "mpp44";
+ marvell,function = "gpio";
+ };
+ pmx_led_status_blue: pmx-led-status-blue {
+ marvell,pins = "mpp45";
+ marvell,function = "gpio";
+ };
+ pmx_led_wps: pmx-led-wps {
+ marvell,pins = "mpp47";
+ marvell,function = "gpio";
+ };
+ pmx_led_status_amber: pmx-led-status-amber {
+ marvell,pins = "mpp48";
+ marvell,function = "gpio";
+ };
+ pmx_led_24g: pmx-led-24g {
+ marvell,pins = "mpp49";
+ marvell,function = "gpio";
+ };
+ pmx_btn_restart: pmx-btn-restart {
+ marvell,pins = "mpp28";
+ marvell,function = "gpio";
+ };
+ pmx_btn_wps: pmx-btn-wps {
+ marvell,pins = "mpp46";
+ marvell,function = "gpio";
+ };
+ };
+
+ spi@10600 {
+ status = "okay";
+ m25p80@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "mxicy,mx25l12805d";
+ spi-max-frequency = <50000000>;
+ reg = <0>;
+
+ partition@0 {
+ label = "uboot";
+ reg = <0x0 0x30000>;
+ read-only;
+ };
+
+ partition@30000 {
+ label = "nvram";
+ reg = <0x30000 0x10000>;
+ read-only;
+ };
+
+ partition@40000 {
+ label = "kernel";
+ reg = <0x40000 0x180000>;
+ };
+
+ partition@1c0000 {
+ label = "rootfs";
+ reg = <0x1c0000 0xe00000>;
+ };
+
+ cal_data: partition@fc0000 {
+ label = "cal_data";
+ reg = <0xfc0000 0x10000>;
+ read-only;
+ };
+
+ partition@fd0000 {
+ label = "lang_pack";
+ reg = <0xfd0000 0x30000>;
+ read-only;
+ };
+ };
+ };
+
+ serial@12000 {
+ status = "okay";
+ };
+
+ i2c@11000 {
+ status = "okay";
+ };
+
+ ehci@50000 {
+ status = "okay";
+ };
+ };
+
+ gpio-leds {
+ compatible = "gpio-leds";
+
+ blue-usb {
+ label = "dir665:blue:usb";
+ gpios = <&gpio0 12 GPIO_ACTIVE_HIGH>;
+ };
+ blue-internet {
+ /* Can only be turned on if the Internet
+ * Ethernet port has Link
+ */
+ label = "dir665:blue:internet";
+ gpios = <&gpio1 10 GPIO_ACTIVE_LOW>;
+ };
+ amber-internet {
+ label = "dir665:amber:internet";
+ gpios = <&gpio1 11 GPIO_ACTIVE_HIGH>;
+ };
+ blue-wifi5g {
+ label = "dir665:blue:5g";
+ gpios = <&gpio1 12 GPIO_ACTIVE_LOW>;
+ };
+ blue-status {
+ label = "dir665:blue:status";
+ gpios = <&gpio1 13 GPIO_ACTIVE_HIGH>;
+ };
+ blue-wps {
+ label = "dir665:blue:wps";
+ gpios = <&gpio1 15 GPIO_ACTIVE_HIGH>;
+ };
+ amber-status {
+ label = "dir665:amber:status";
+ gpios = <&gpio1 16 GPIO_ACTIVE_HIGH>;
+ };
+ blue-24g {
+ label = "dir665:blue:24g";
+ gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ reset {
+ label = "reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&gpio0 28 GPIO_ACTIVE_LOW>;
+ };
+ wps {
+ label = "wps";
+ linux,code = <KEY_WPS_BUTTON>;
+ gpios = <&gpio1 14 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ dsa@0 {
+ compatible = "marvell,dsa";
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ dsa,ethernet = <&eth0port>;
+ dsa,mii-bus = <&mdio>;
+
+ switch@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0 0>; /* MDIO address 0, switch 0 in tree */
+
+ port@0 {
+ reg = <0>;
+ label = "lan4";
+ };
+
+ port@1 {
+ reg = <1>;
+ label = "lan3";
+ };
+
+ port@2 {
+ reg = <2>;
+ label = "lan2";
+ };
+
+ port@3 {
+ reg = <3>;
+ label = "lan1";
+ };
+
+ port@4 {
+ reg = <4>;
+ label = "wan";
+ };
+
+ port@6 {
+ reg = <6>;
+ label = "cpu";
+ };
+ };
+ };
+};
+
+&mdio {
+ status = "okay";
+};
+
+/* eth0 is connected to a Marvell 88E6171 switch, without a PHY. So set
+ * fixed speed and duplex. */
+&eth0 {
+ status = "okay";
+
+ ethernet0-port@0 {
+ speed = <1000>;
+ duplex = <1>;
+ };
+};
+
+/* eth1 is connected to the switch as well. However DSA only supports a
+ * single CPU port. So leave this port disabled to avoid confusion. */
+
+&eth1 {
+ status = "disabled";
+};
+
+/* There is no battery on the boards, so the RTC does not keep time
+ * when there is no power, making it useless. */
+&rtc {
+ status = "disabled";
+};
diff --git a/arch/arm/boot/dts/kirkwood-synology.dtsi b/arch/arm/boot/dts/kirkwood-synology.dtsi
index 811e097..8be5b2e 100644
--- a/arch/arm/boot/dts/kirkwood-synology.dtsi
+++ b/arch/arm/boot/dts/kirkwood-synology.dtsi
@@ -266,7 +266,7 @@
s35390a: s35390a@30 {
status = "disabled";
- compatible = "ssi,s35390a";
+ compatible = "sii,s35390a";
reg = <0x30>;
};
};
diff --git a/arch/arm/boot/dts/ls1021a-qds.dts b/arch/arm/boot/dts/ls1021a-qds.dts
new file mode 100644
index 0000000..9c5e16b
--- /dev/null
+++ b/arch/arm/boot/dts/ls1021a-qds.dts
@@ -0,0 +1,240 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "ls1021a.dtsi"
+
+/ {
+ model = "LS1021A QDS Board";
+
+ aliases {
+ enet0_rgmii_phy = &rgmii_phy1;
+ enet1_rgmii_phy = &rgmii_phy2;
+ enet2_rgmii_phy = &rgmii_phy3;
+ enet0_sgmii_phy = &sgmii_phy1c;
+ enet1_sgmii_phy = &sgmii_phy1d;
+ };
+};
+
+&dspi0 {
+ bus-num = <0>;
+ status = "okay";
+
+ dspiflash: at45db021d@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "atmel,at45db021d", "atmel,at45", "atmel,dataflash";
+ spi-max-frequency = <16000000>;
+ spi-cpol;
+ spi-cpha;
+ reg = <0>;
+ };
+};
+
+&i2c0 {
+ status = "okay";
+
+ pca9547: mux@77 {
+ reg = <0x77>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ i2c@0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0>;
+
+ ds3232: rtc@68 {
+ compatible = "dallas,ds3232";
+ reg = <0x68>;
+ interrupts = <GIC_SPI 169 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ i2c@2 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x2>;
+
+ ina220@40 {
+ compatible = "ti,ina220";
+ reg = <0x40>;
+ shunt-resistor = <1000>;
+ };
+
+ ina220@41 {
+ compatible = "ti,ina220";
+ reg = <0x41>;
+ shunt-resistor = <1000>;
+ };
+ };
+
+ i2c@3 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x3>;
+
+ eeprom@56 {
+ compatible = "atmel,24c512";
+ reg = <0x56>;
+ };
+
+ eeprom@57 {
+ compatible = "atmel,24c512";
+ reg = <0x57>;
+ };
+
+ adt7461a@4c {
+ compatible = "adi,adt7461a";
+ reg = <0x4c>;
+ };
+ };
+ };
+};
+
+&ifc {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ /* NOR, NAND Flashes and FPGA on board */
+ ranges = <0x0 0x0 0x0 0x60000000 0x08000000
+ 0x2 0x0 0x0 0x7e800000 0x00010000
+ 0x3 0x0 0x0 0x7fb00000 0x00000100>;
+ status = "okay";
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+
+ fpga: board-control@3,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ reg = <0x3 0x0 0x0000100>;
+ bank-width = <1>;
+ device-width = <1>;
+ ranges = <0 3 0 0x100>;
+
+ mdio-mux-emi1 {
+ compatible = "mdio-mux-mmioreg";
+ mdio-parent-bus = <&mdio0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x54 1>; /* BRDCFG4 */
+ mux-mask = <0xe0>; /* EMI1[2:0] */
+
+ /* Onboard PHYs */
+ ls1021amdio0: mdio@0 {
+ reg = <0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rgmii_phy1: ethernet-phy@1 {
+ reg = <0x1>;
+ };
+ };
+
+ ls1021amdio1: mdio@20 {
+ reg = <0x20>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rgmii_phy2: ethernet-phy@2 {
+ reg = <0x2>;
+ };
+ };
+
+ ls1021amdio2: mdio@40 {
+ reg = <0x40>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ rgmii_phy3: ethernet-phy@3 {
+ reg = <0x3>;
+ };
+ };
+
+ ls1021amdio3: mdio@60 {
+ reg = <0x60>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ sgmii_phy1c: ethernet-phy@1c {
+ reg = <0x1c>;
+ };
+ };
+
+ ls1021amdio4: mdio@80 {
+ reg = <0x80>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ sgmii_phy1d: ethernet-phy@1d {
+ reg = <0x1d>;
+ };
+ };
+ };
+ };
+};
+
+&lpuart0 {
+ status = "okay";
+};
+
+&mdio0 {
+ tbi0: tbi-phy@8 {
+ reg = <0x8>;
+ device_type = "tbi-phy";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/ls1021a-twr.dts b/arch/arm/boot/dts/ls1021a-twr.dts
new file mode 100644
index 0000000..a2c591e
--- /dev/null
+++ b/arch/arm/boot/dts/ls1021a-twr.dts
@@ -0,0 +1,127 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "ls1021a.dtsi"
+
+/ {
+ model = "LS1021A TWR Board";
+
+ aliases {
+ enet2_rgmii_phy = &rgmii_phy1;
+ enet0_sgmii_phy = &sgmii_phy2;
+ enet1_sgmii_phy = &sgmii_phy0;
+ };
+};
+
+&dspi1 {
+ bus-num = <0>;
+ status = "okay";
+
+ dspiflash: s25fl064k@0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "spansion,s25fl064k";
+ spi-max-frequency = <16000000>;
+ spi-cpol;
+ spi-cpha;
+ reg = <0>;
+ };
+};
+
+&i2c0 {
+ status = "okay";
+};
+
+&i2c1 {
+ status = "okay";
+};
+
+&ifc {
+ #address-cells = <2>;
+ #size-cells = <1>;
+ /* NOR Flash on board */
+ ranges = <0x0 0x0 0x0 0x60000000 0x08000000>;
+ status = "okay";
+
+ nor@0,0 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "cfi-flash";
+ reg = <0x0 0x0 0x8000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ };
+};
+
+&lpuart0 {
+ status = "okay";
+};
+
+&mdio0 {
+ sgmii_phy0: ethernet-phy@0 {
+ reg = <0x0>;
+ };
+ rgmii_phy1: ethernet-phy@1 {
+ reg = <0x1>;
+ };
+ sgmii_phy2: ethernet-phy@2 {
+ reg = <0x2>;
+ };
+ tbi1: tbi-phy@1f {
+ reg = <0x1f>;
+ device_type = "tbi-phy";
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/ls1021a.dtsi b/arch/arm/boot/dts/ls1021a.dtsi
new file mode 100644
index 0000000..657da14
--- /dev/null
+++ b/arch/arm/boot/dts/ls1021a.dtsi
@@ -0,0 +1,408 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "skeleton64.dtsi"
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ compatible = "fsl,ls1021a";
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &lpuart0;
+ serial1 = &lpuart1;
+ serial2 = &lpuart2;
+ serial3 = &lpuart3;
+ serial4 = &lpuart4;
+ serial5 = &lpuart5;
+ sysclk = &sysclk;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@f00 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0xf00>;
+ clocks = <&cluster1_clk>;
+ };
+
+ cpu@f01 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0xf01>;
+ clocks = <&cluster1_clk>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ pmu {
+ compatible = "arm,cortex-a7-pmu";
+ interrupts = <GIC_SPI 138 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 139 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ device_type = "soc";
+ interrupt-parent = <&gic>;
+ ranges;
+
+ gic: interrupt-controller@1400000 {
+ compatible = "arm,cortex-a7-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x0 0x1401000 0x0 0x1000>,
+ <0x0 0x1402000 0x0 0x1000>,
+ <0x0 0x1404000 0x0 0x2000>,
+ <0x0 0x1406000 0x0 0x2000>;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(2) | IRQ_TYPE_LEVEL_HIGH)>;
+
+ };
+
+ ifc: ifc@1530000 {
+ compatible = "fsl,ifc", "simple-bus";
+ reg = <0x0 0x1530000 0x0 0x10000>;
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ dcfg: dcfg@1ee0000 {
+ compatible = "fsl,ls1021a-dcfg", "syscon";
+ reg = <0x0 0x1ee0000 0x0 0x10000>;
+ big-endian;
+ };
+
+ esdhc: esdhc@1560000 {
+ compatible = "fsl,esdhc";
+ reg = <0x0 0x1560000 0x0 0x10000>;
+ interrupts = <GIC_SPI 94 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <0>;
+ voltage-ranges = <1800 1800 3300 3300>;
+ sdhci,auto-cmd12;
+ big-endian;
+ bus-width = <4>;
+ status = "disabled";
+ };
+
+ scfg: scfg@1570000 {
+ compatible = "fsl,ls1021a-scfg", "syscon";
+ reg = <0x0 0x1570000 0x0 0x10000>;
+ };
+
+ clockgen: clocking@1ee1000 {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x0 0x0 0x1ee1000 0x10000>;
+
+ sysclk: sysclk {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-output-names = "sysclk";
+ };
+
+ cga_pll1: pll@800 {
+ compatible = "fsl,qoriq-core-pll-2.0";
+ #clock-cells = <1>;
+ reg = <0x800 0x10>;
+ clocks = <&sysclk>;
+ clock-output-names = "cga-pll1", "cga-pll1-div2",
+ "cga-pll1-div4";
+ };
+
+ platform_clk: pll@c00 {
+ compatible = "fsl,qoriq-core-pll-2.0";
+ #clock-cells = <1>;
+ reg = <0xc00 0x10>;
+ clocks = <&sysclk>;
+ clock-output-names = "platform-clk", "platform-clk-div2";
+ };
+
+ cluster1_clk: clk0c0@0 {
+ compatible = "fsl,qoriq-core-mux-2.0";
+ #clock-cells = <0>;
+ reg = <0x0 0x10>;
+ clock-names = "pll1cga", "pll1cga-div2", "pll1cga-div4";
+ clocks = <&cga_pll1 0>, <&cga_pll1 1>, <&cga_pll1 2>;
+ clock-output-names = "cluster1-clk";
+ };
+ };
+
+ dspi0: dspi@2100000 {
+ compatible = "fsl,vf610-dspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2100000 0x0 0x10000>;
+ interrupts = <GIC_SPI 96 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "dspi";
+ clocks = <&platform_clk 1>;
+ spi-num-chipselects = <5>;
+ big-endian;
+ status = "disabled";
+ };
+
+ dspi1: dspi@2110000 {
+ compatible = "fsl,vf610-dspi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2110000 0x0 0x10000>;
+ interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "dspi";
+ clocks = <&platform_clk 1>;
+ spi-num-chipselects = <5>;
+ big-endian;
+ status = "disabled";
+ };
+
+ i2c0: i2c@2180000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2180000 0x0 0x10000>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "i2c";
+ clocks = <&platform_clk 1>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@2190000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2190000 0x0 0x10000>;
+ interrupts = <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "i2c";
+ clocks = <&platform_clk 1>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@21a0000 {
+ compatible = "fsl,vf610-i2c";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x21a0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>;
+ clock-names = "i2c";
+ clocks = <&platform_clk 1>;
+ status = "disabled";
+ };
+
+ uart0: serial@21c0500 {
+ compatible = "fsl,16550-FIFO64", "ns16550a";
+ reg = <0x0 0x21c0500 0x0 0x100>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <0>;
+ fifo-size = <15>;
+ status = "disabled";
+ };
+
+ uart1: serial@21c0600 {
+ compatible = "fsl,16550-FIFO64", "ns16550a";
+ reg = <0x0 0x21c0600 0x0 0x100>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <0>;
+ fifo-size = <15>;
+ status = "disabled";
+ };
+
+ uart2: serial@21d0500 {
+ compatible = "fsl,16550-FIFO64", "ns16550a";
+ reg = <0x0 0x21d0500 0x0 0x100>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <0>;
+ fifo-size = <15>;
+ status = "disabled";
+ };
+
+ uart3: serial@21d0600 {
+ compatible = "fsl,16550-FIFO64", "ns16550a";
+ reg = <0x0 0x21d0600 0x0 0x100>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <0>;
+ fifo-size = <15>;
+ status = "disabled";
+ };
+
+ lpuart0: serial@2950000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2950000 0x0 0x1000>;
+ interrupts = <GIC_SPI 80 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&sysclk>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart1: serial@2960000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2960000 0x0 0x1000>;
+ interrupts = <GIC_SPI 81 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart2: serial@2970000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2970000 0x0 0x1000>;
+ interrupts = <GIC_SPI 82 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart3: serial@2980000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2980000 0x0 0x1000>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart4: serial@2990000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x2990000 0x0 0x1000>;
+ interrupts = <GIC_SPI 84 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ lpuart5: serial@29a0000 {
+ compatible = "fsl,ls1021a-lpuart";
+ reg = <0x0 0x29a0000 0x0 0x1000>;
+ interrupts = <GIC_SPI 85 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ wdog0: watchdog@2ad0000 {
+ compatible = "fsl,imx21-wdt";
+ reg = <0x0 0x2ad0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "wdog-en";
+ big-endian;
+ };
+
+ sai1: sai@2b50000 {
+ compatible = "fsl,vf610-sai";
+ reg = <0x0 0x2b50000 0x0 0x10000>;
+ interrupts = <GIC_SPI 132 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "sai";
+ dma-names = "tx", "rx";
+ dmas = <&edma0 1 47>,
+ <&edma0 1 46>;
+ big-endian;
+ status = "disabled";
+ };
+
+ sai2: sai@2b60000 {
+ compatible = "fsl,vf610-sai";
+ reg = <0x0 0x2b60000 0x0 0x10000>;
+ interrupts = <GIC_SPI 133 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&platform_clk 1>;
+ clock-names = "sai";
+ dma-names = "tx", "rx";
+ dmas = <&edma0 1 45>,
+ <&edma0 1 44>;
+ big-endian;
+ status = "disabled";
+ };
+
+ edma0: edma@2c00000 {
+ #dma-cells = <2>;
+ compatible = "fsl,vf610-edma";
+ reg = <0x0 0x2c00000 0x0 0x10000>,
+ <0x0 0x2c10000 0x0 0x10000>,
+ <0x0 0x2c20000 0x0 0x10000>;
+ interrupts = <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 135 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma-tx", "edma-err";
+ dma-channels = <32>;
+ big-endian;
+ clock-names = "dmamux0", "dmamux1";
+ clocks = <&platform_clk 1>,
+ <&platform_clk 1>;
+ };
+
+ mdio0: mdio@2d24000 {
+ compatible = "gianfar";
+ device_type = "mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0x0 0x2d24000 0x0 0x4000>;
+ };
+
+ usb@8600000 {
+ compatible = "fsl-usb2-dr-v2.5", "fsl-usb2-dr";
+ reg = <0x0 0x8600000 0x0 0x1000>;
+ interrupts = <GIC_SPI 171 IRQ_TYPE_LEVEL_HIGH>;
+ dr_mode = "host";
+ phy_type = "ulpi";
+ };
+
+ usb3@3100000 {
+ compatible = "snps,dwc3";
+ reg = <0x0 0x3100000 0x0 0x10000>;
+ interrupts = <GIC_SPI 93 IRQ_TYPE_LEVEL_HIGH>;
+ dr_mode = "host";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/meson.dtsi b/arch/arm/boot/dts/meson.dtsi
index e6539ea..b67ede5 100644
--- a/arch/arm/boot/dts/meson.dtsi
+++ b/arch/arm/boot/dts/meson.dtsi
@@ -50,6 +50,13 @@
/ {
interrupt-parent = <&gic>;
+ L2: l2-cache-controller@c4200000 {
+ compatible = "arm,pl310-cache";
+ reg = <0xc4200000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
gic: interrupt-controller@c4301000 {
compatible = "arm,cortex-a9-gic";
reg = <0xc4301000 0x1000>,
@@ -106,5 +113,42 @@
clocks = <&clk81>;
status = "disabled";
};
+
+ i2c_AO: i2c@c8100500 {
+ compatible = "amlogic,meson6-i2c";
+ reg = <0xc8100500 0x20>;
+ interrupts = <0 92 1>;
+ clocks = <&clk81>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c_A: i2c@c1108500 {
+ compatible = "amlogic,meson6-i2c";
+ reg = <0xc1108500 0x20>;
+ interrupts = <0 21 1>;
+ clocks = <&clk81>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ i2c_B: i2c@c11087c0 {
+ compatible = "amlogic,meson6-i2c";
+ reg = <0xc11087c0 0x20>;
+ interrupts = <0 128 1>;
+ clocks = <&clk81>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "disabled";
+ };
+
+ ir_receiver: ir-receiver@c8100480 {
+ compatible= "amlogic,meson6-ir";
+ reg = <0xc8100480 0x20>;
+ interrupts = <0 15 1>;
+ status = "disabled";
+ };
};
}; /* end of / */
diff --git a/arch/arm/boot/dts/meson6-atv1200.dts b/arch/arm/boot/dts/meson6-atv1200.dts
index dc2541fa..d7d351a 100644
--- a/arch/arm/boot/dts/meson6-atv1200.dts
+++ b/arch/arm/boot/dts/meson6-atv1200.dts
@@ -50,7 +50,7 @@
/ {
model = "Geniatech ATV1200";
- compatible = "geniatech,atv1200";
+ compatible = "geniatech,atv1200", "amlogic,meson6";
aliases {
serial0 = &uart_AO;
diff --git a/arch/arm/boot/dts/meson6.dtsi b/arch/arm/boot/dts/meson6.dtsi
index 4ba4912..8b33be1 100644
--- a/arch/arm/boot/dts/meson6.dtsi
+++ b/arch/arm/boot/dts/meson6.dtsi
@@ -60,12 +60,14 @@
cpu@200 {
device_type = "cpu";
compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
reg = <0x200>;
};
cpu@201 {
device_type = "cpu";
compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
reg = <0x201>;
};
};
diff --git a/arch/arm/boot/dts/meson8.dtsi b/arch/arm/boot/dts/meson8.dtsi
new file mode 100644
index 0000000..1f442a7
--- /dev/null
+++ b/arch/arm/boot/dts/meson8.dtsi
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2014 Carlo Caione <carlo@caione.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/include/ "meson.dtsi"
+
+/ {
+ model = "Amlogic Meson8 SoC";
+ compatible = "amlogic,meson8";
+
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@200 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x200>;
+ };
+
+ cpu@201 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x201>;
+ };
+
+ cpu@202 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x202>;
+ };
+
+ cpu@203 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a9";
+ next-level-cache = <&L2>;
+ reg = <0x203>;
+ };
+ };
+
+ clk81: clk@0 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <141666666>;
+ };
+}; /* end of / */
diff --git a/arch/arm/boot/dts/mt6592-evb.dts b/arch/arm/boot/dts/mt6592-evb.dts
new file mode 100644
index 0000000..b57237e
--- /dev/null
+++ b/arch/arm/boot/dts/mt6592-evb.dts
@@ -0,0 +1,26 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Howard Chen <ibanezchen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+#include "mt6592.dtsi"
+
+/ {
+ model = "mt6592 evb";
+ compatible = "mediatek,mt6592-evb", "mediatek,mt6592";
+
+ memory {
+ reg = <0x80000000 0x40000000>;
+ };
+};
+
diff --git a/arch/arm/boot/dts/mt6592.dtsi b/arch/arm/boot/dts/mt6592.dtsi
new file mode 100644
index 0000000..31e5a09
--- /dev/null
+++ b/arch/arm/boot/dts/mt6592.dtsi
@@ -0,0 +1,98 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Howard Chen <ibanezchen@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "skeleton.dtsi"
+
+/ {
+ compatible = "mediatek,mt6592";
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x1>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x3>;
+ };
+ cpu@4 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x4>;
+ };
+ cpu@5 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x5>;
+ };
+ cpu@6 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x6>;
+ };
+ cpu@7 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x7>;
+ };
+ };
+
+ system_clk: dummy13m {
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ #clock-cells = <0>;
+ };
+
+ rtc_clk: dummy32k {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+
+ timer: timer@10008000 {
+ compatible = "mediatek,mt6577-timer";
+ reg = <0x10008000 0x80>;
+ interrupts = <GIC_SPI 144 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>, <&rtc_clk>;
+ clock-names = "system-clk", "rtc-clk";
+ };
+
+ gic: interrupt-controller@10211000 {
+ compatible = "arm,cortex-a7-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0x10211000 0x1000>,
+ <0x10212000 0x1000>;
+ };
+
+};
+
diff --git a/arch/arm/boot/dts/mt8127-moose.dts b/arch/arm/boot/dts/mt8127-moose.dts
new file mode 100644
index 0000000..13cba0e
--- /dev/null
+++ b/arch/arm/boot/dts/mt8127-moose.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Joe.C <yingjoe.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+#include "mt8127.dtsi"
+
+/ {
+ model = "MediaTek MT8127 Moose Board";
+ compatible = "mediatek,mt8127-moose", "mediatek,mt8127";
+
+ memory {
+ reg = <0 0x80000000 0 0x40000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/mt8127.dtsi b/arch/arm/boot/dts/mt8127.dtsi
new file mode 100644
index 0000000..b24c0a2
--- /dev/null
+++ b/arch/arm/boot/dts/mt8127.dtsi
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Joe.C <yingjoe.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "skeleton64.dtsi"
+
+/ {
+ compatible = "mediatek,mt8127";
+ interrupt-parent = <&gic>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x0>;
+ };
+ cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x1>;
+ };
+ cpu@2 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x2>;
+ };
+ cpu@3 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x3>;
+ };
+
+ };
+
+ clocks {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "simple-bus";
+ ranges;
+
+ system_clk: dummy13m {
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ #clock-cells = <0>;
+ };
+
+ rtc_clk: dummy32k {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+ };
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "simple-bus";
+ ranges;
+
+ timer: timer@10008000 {
+ compatible = "mediatek,mt8127-timer",
+ "mediatek,mt6577-timer";
+ reg = <0 0x10008000 0 0x80>;
+ interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>, <&rtc_clk>;
+ clock-names = "system-clk", "rtc-clk";
+ };
+
+ gic: interrupt-controller@10211000 {
+ compatible = "arm,cortex-a7-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0 0x10211000 0 0x1000>,
+ <0 0x10212000 0 0x1000>,
+ <0 0x10214000 0 0x2000>,
+ <0 0x10216000 0 0x2000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/mt8135-evbp1.dts b/arch/arm/boot/dts/mt8135-evbp1.dts
new file mode 100644
index 0000000..a5adf97
--- /dev/null
+++ b/arch/arm/boot/dts/mt8135-evbp1.dts
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Joe.C <yingjoe.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+/dts-v1/;
+#include "mt8135.dtsi"
+
+/ {
+ model = "MediaTek MT8135 evaluation board";
+ compatible = "mediatek,mt8135-evbp1", "mediatek,mt8135";
+
+ memory {
+ reg = <0 0x80000000 0 0x40000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/mt8135.dtsi b/arch/arm/boot/dts/mt8135.dtsi
new file mode 100644
index 0000000..7d56a98
--- /dev/null
+++ b/arch/arm/boot/dts/mt8135.dtsi
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2014 MediaTek Inc.
+ * Author: Joe.C <yingjoe.chen@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+#include "skeleton64.dtsi"
+
+/ {
+ compatible = "mediatek,mt8135";
+ interrupt-parent = <&gic>;
+
+ cpu-map {
+ cluster0 {
+ core0 {
+ cpu = <&cpu0>;
+ };
+ core1 {
+ cpu = <&cpu1>;
+ };
+ };
+
+ cluster1 {
+ core0 {
+ cpu = <&cpu2>;
+ };
+ core1 {
+ cpu = <&cpu3>;
+ };
+ };
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x000>;
+ };
+
+ cpu1: cpu@1 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a7";
+ reg = <0x001>;
+ };
+
+ cpu2: cpu@100 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x100>;
+ };
+
+ cpu3: cpu@101 {
+ device_type = "cpu";
+ compatible = "arm,cortex-a15";
+ reg = <0x101>;
+ };
+ };
+
+ clocks {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "simple-bus";
+ ranges;
+
+ system_clk: dummy13m {
+ compatible = "fixed-clock";
+ clock-frequency = <13000000>;
+ #clock-cells = <0>;
+ };
+
+ rtc_clk: dummy32k {
+ compatible = "fixed-clock";
+ clock-frequency = <32000>;
+ #clock-cells = <0>;
+ };
+ };
+
+ soc {
+ #address-cells = <2>;
+ #size-cells = <2>;
+ compatible = "simple-bus";
+ ranges;
+
+ timer: timer@10008000 {
+ compatible = "mediatek,mt8135-timer",
+ "mediatek,mt6577-timer";
+ reg = <0 0x10008000 0 0x80>;
+ interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&system_clk>, <&rtc_clk>;
+ clock-names = "system-clk", "rtc-clk";
+ };
+
+ gic: interrupt-controller@10211000 {
+ compatible = "arm,cortex-a15-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ reg = <0 0x10211000 0 0x1000>,
+ <0 0x10212000 0 0x1000>,
+ <0 0x10214000 0 0x2000>,
+ <0 0x10216000 0 0x2000>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
index 521c587..445fafc 100644
--- a/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
+++ b/arch/arm/boot/dts/omap-gpmc-smsc911x.dtsi
@@ -23,24 +23,29 @@
ethernet@gpmc {
compatible = "smsc,lan9221", "smsc,lan9115";
bank-width = <2>;
- gpmc,mux-add-data;
- gpmc,cs-on-ns = <1>;
- gpmc,cs-rd-off-ns = <180>;
- gpmc,cs-wr-off-ns = <180>;
- gpmc,adv-rd-off-ns = <18>;
- gpmc,adv-wr-off-ns = <48>;
- gpmc,oe-on-ns = <54>;
- gpmc,oe-off-ns = <168>;
- gpmc,we-on-ns = <54>;
- gpmc,we-off-ns = <168>;
- gpmc,rd-cycle-ns = <186>;
- gpmc,wr-cycle-ns = <186>;
- gpmc,access-ns = <144>;
- gpmc,page-burst-access-ns = <24>;
- gpmc,bus-turnaround-ns = <90>;
- gpmc,cycle2cycle-delay-ns = <90>;
- gpmc,cycle2cycle-samecsen;
- gpmc,cycle2cycle-diffcsen;
+ gpmc,device-width = <1>;
+ gpmc,cycle2cycle-samecsen = <1>;
+ gpmc,cycle2cycle-diffcsen = <1>;
+ gpmc,cs-on-ns = <5>;
+ gpmc,cs-rd-off-ns = <150>;
+ gpmc,cs-wr-off-ns = <150>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <15>;
+ gpmc,adv-wr-off-ns = <40>;
+ gpmc,oe-on-ns = <45>;
+ gpmc,oe-off-ns = <140>;
+ gpmc,we-on-ns = <45>;
+ gpmc,we-off-ns = <140>;
+ gpmc,rd-cycle-ns = <155>;
+ gpmc,wr-cycle-ns = <155>;
+ gpmc,access-ns = <120>;
+ gpmc,page-burst-access-ns = <20>;
+ gpmc,bus-turnaround-ns = <75>;
+ gpmc,cycle2cycle-delay-ns = <75>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ gpmc,wr-access-ns = <0>;
vddvario-supply = <&vddvario>;
vdd33a-supply = <&vdd33a>;
reg-io-width = <4>;
diff --git a/arch/arm/boot/dts/omap-zoom-common.dtsi b/arch/arm/boot/dts/omap-zoom-common.dtsi
index 68221fa..46ef3e4 100644
--- a/arch/arm/boot/dts/omap-zoom-common.dtsi
+++ b/arch/arm/boot/dts/omap-zoom-common.dtsi
@@ -5,7 +5,7 @@
#include "omap-gpmc-smsc911x.dtsi"
&gpmc {
- ranges = <3 0 0x10000000 0x00000400>,
+ ranges = <3 0 0x10000000 0x1000000>, /* CS3: 16MB for UART */
<7 0 0x2c000000 0x01000000>;
/*
@@ -15,7 +15,65 @@
*/
uart@3,0 {
compatible = "ns16550a";
- reg = <3 0 0x100>;
+ reg = <3 0 8>; /* CS3, offset 0, IO size 8 */
+ bank-width = <2>;
+ reg-shift = <1>;
+ reg-io-width = <1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <6 IRQ_TYPE_EDGE_RISING>; /* gpio102 */
+ clock-frequency = <1843200>;
+ current-speed = <115200>;
+ gpmc,mux-add-data = <0>;
+ gpmc,device-width = <1>;
+ gpmc,wait-pin = <1>;
+ gpmc,cycle2cycle-samecsen = <1>;
+ gpmc,cycle2cycle-diffcsen = <1>;
+ gpmc,cs-on-ns = <5>;
+ gpmc,cs-rd-off-ns = <155>;
+ gpmc,cs-wr-off-ns = <155>;
+ gpmc,adv-on-ns = <15>;
+ gpmc,adv-rd-off-ns = <40>;
+ gpmc,adv-wr-off-ns = <40>;
+ gpmc,oe-on-ns = <45>;
+ gpmc,oe-off-ns = <145>;
+ gpmc,we-on-ns = <45>;
+ gpmc,we-off-ns = <145>;
+ gpmc,rd-cycle-ns = <155>;
+ gpmc,wr-cycle-ns = <155>;
+ gpmc,access-ns = <145>;
+ gpmc,page-burst-access-ns = <20>;
+ gpmc,bus-turnaround-ns = <20>;
+ gpmc,cycle2cycle-delay-ns = <20>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wr-data-mux-bus-ns = <45>;
+ gpmc,wr-access-ns = <145>;
+ };
+ uart@3,1 {
+ compatible = "ns16550a";
+ reg = <3 0x100 8>; /* CS3, offset 0x100, IO size 8 */
+ bank-width = <2>;
+ reg-shift = <1>;
+ reg-io-width = <1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <6 IRQ_TYPE_EDGE_RISING>; /* gpio102 */
+ clock-frequency = <1843200>;
+ current-speed = <115200>;
+ };
+ uart@3,2 {
+ compatible = "ns16550a";
+ reg = <3 0x200 8>; /* CS3, offset 0x200, IO size 8 */
+ bank-width = <2>;
+ reg-shift = <1>;
+ reg-io-width = <1>;
+ interrupt-parent = <&gpio4>;
+ interrupts = <6 IRQ_TYPE_EDGE_RISING>; /* gpio102 */
+ clock-frequency = <1843200>;
+ current-speed = <115200>;
+ };
+ uart@3,3 {
+ compatible = "ns16550a";
+ reg = <3 0x300 8>; /* CS3, offset 0x300, IO size 8 */
bank-width = <2>;
reg-shift = <1>;
reg-io-width = <1>;
diff --git a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
index 24c50db..c9f1e93 100644
--- a/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
+++ b/arch/arm/boot/dts/omap2420-n8x0-common.dtsi
@@ -40,14 +40,14 @@
};
&gpmc {
- ranges = <0 0 0x04000000 0x10000000>;
+ ranges = <0 0 0x04000000 0x1000000>; /* CS0: 16MB for OneNAND */
/* gpio-irq for dma: 26 */
onenand@0,0 {
#address-cells = <1>;
#size-cells = <1>;
- reg = <0 0 0x10000000>;
+ reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */
gpmc,sync-read;
gpmc,burst-length = <16>;
diff --git a/arch/arm/boot/dts/omap2420.dtsi b/arch/arm/boot/dts/omap2420.dtsi
index ae89aad..e2b2e93 100644
--- a/arch/arm/boot/dts/omap2420.dtsi
+++ b/arch/arm/boot/dts/omap2420.dtsi
@@ -157,6 +157,7 @@
interrupts = <26>, <34>;
interrupt-names = "dsp", "iva";
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <6>;
mbox_dsp: dsp {
diff --git a/arch/arm/boot/dts/omap2430-sdp.dts b/arch/arm/boot/dts/omap2430-sdp.dts
index 2c90d29..05eca2e 100644
--- a/arch/arm/boot/dts/omap2430-sdp.dts
+++ b/arch/arm/boot/dts/omap2430-sdp.dts
@@ -43,7 +43,31 @@
interrupts = <21 IRQ_TYPE_LEVEL_LOW>; /* gpio149 */
reg = <5 0x300 0xf>;
bank-width = <2>;
- gpmc,mux-add-data;
- };
+ gpmc,sync-clk-ps = <0>;
+ gpmc,mux-add-data = <2>;
+ gpmc,device-width = <1>;
+ gpmc,cycle2cycle-samecsen = <1>;
+ gpmc,cycle2cycle-diffcsen = <1>;
+ gpmc,cs-on-ns = <7>;
+ gpmc,cs-rd-off-ns = <233>;
+ gpmc,cs-wr-off-ns = <233>;
+ gpmc,adv-on-ns = <22>;
+ gpmc,adv-rd-off-ns = <60>;
+ gpmc,adv-wr-off-ns = <60>;
+ gpmc,oe-on-ns = <67>;
+ gpmc,oe-off-ns = <210>;
+ gpmc,we-on-ns = <67>;
+ gpmc,we-off-ns = <210>;
+ gpmc,rd-cycle-ns = <233>;
+ gpmc,wr-cycle-ns = <233>;
+ gpmc,access-ns = <233>;
+ gpmc,page-burst-access-ns = <30>;
+ gpmc,bus-turnaround-ns = <30>;
+ gpmc,cycle2cycle-delay-ns = <30>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ gpmc,wr-access-ns = <0>;
+ };
};
diff --git a/arch/arm/boot/dts/omap2430.dtsi b/arch/arm/boot/dts/omap2430.dtsi
index b56d7161..0dc8de2 100644
--- a/arch/arm/boot/dts/omap2430.dtsi
+++ b/arch/arm/boot/dts/omap2430.dtsi
@@ -247,6 +247,7 @@
reg = <0x48094000 0x200>;
interrupts = <26>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <4>;
ti,mbox-num-fifos = <6>;
mbox_dsp: dsp {
diff --git a/arch/arm/boot/dts/omap3-cm-t3517.dts b/arch/arm/boot/dts/omap3-cm-t3517.dts
index d00502f..0ab748c 100644
--- a/arch/arm/boot/dts/omap3-cm-t3517.dts
+++ b/arch/arm/boot/dts/omap3-cm-t3517.dts
@@ -134,3 +134,14 @@
bus-width = <4>;
cap-power-off-card;
};
+
+&dss {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &dss_dpi_pins_common
+ &dss_dpi_pins_cm_t35x
+ >;
+};
+
diff --git a/arch/arm/boot/dts/omap3-cm-t3530.dts b/arch/arm/boot/dts/omap3-cm-t3530.dts
index d145849..8dd14fc 100644
--- a/arch/arm/boot/dts/omap3-cm-t3530.dts
+++ b/arch/arm/boot/dts/omap3-cm-t3530.dts
@@ -46,3 +46,14 @@
bus-width = <4>;
cap-power-off-card;
};
+
+&dss {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &dss_dpi_pins_common
+ &dss_dpi_pins_cm_t35x
+ >;
+};
+
diff --git a/arch/arm/boot/dts/omap3-cm-t3730.dts b/arch/arm/boot/dts/omap3-cm-t3730.dts
index b3f9a50..46eadb2 100644
--- a/arch/arm/boot/dts/omap3-cm-t3730.dts
+++ b/arch/arm/boot/dts/omap3-cm-t3730.dts
@@ -31,6 +31,19 @@
};
};
+&omap3_pmx_wkup {
+ dss_dpi_pins_cm_t3730: pinmux_dss_dpi_pins_cm_t3730 {
+ pinctrl-single,pins = <
+ OMAP3_WKUP_IOPAD(0x2a08, PIN_OUTPUT | MUX_MODE3) /* sys_boot0.dss_data18 */
+ OMAP3_WKUP_IOPAD(0x2a0c, PIN_OUTPUT | MUX_MODE3) /* sys_boot1.dss_data19 */
+ OMAP3_WKUP_IOPAD(0x2a10, PIN_OUTPUT | MUX_MODE3) /* sys_boot3.dss_data20 */
+ OMAP3_WKUP_IOPAD(0x2a12, PIN_OUTPUT | MUX_MODE3) /* sys_boot4.dss_data21 */
+ OMAP3_WKUP_IOPAD(0x2a14, PIN_OUTPUT | MUX_MODE3) /* sys_boot5.dss_data22 */
+ OMAP3_WKUP_IOPAD(0x2a16, PIN_OUTPUT | MUX_MODE3) /* sys_boot6.dss_data23 */
+ >;
+ };
+};
+
&omap3_pmx_core {
mmc2_pins: pinmux_mmc2_pins {
@@ -61,3 +74,14 @@
bus-width = <4>;
cap-power-off-card;
};
+
+&dss {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &dss_dpi_pins_common
+ &dss_dpi_pins_cm_t3730
+ >;
+};
+
diff --git a/arch/arm/boot/dts/omap3-cm-t3x.dtsi b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
index c671a22..6ea6d46 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x.dtsi
@@ -49,6 +49,24 @@
compatible = "usb-nop-xceiv";
vcc-supply = <&hsusb2_power>;
};
+
+ ads7846reg: ads7846-reg {
+ compatible = "regulator-fixed";
+ regulator-name = "ads7846-reg";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ };
+
+ tv0: connector@1 {
+ compatible = "svideo-connector";
+ label = "tv";
+
+ port {
+ tv_connector_in: endpoint {
+ remote-endpoint = <&venc_out>;
+ };
+ };
+ };
};
&omap3_pmx_core {
@@ -76,6 +94,76 @@
OMAP3_CORE1_IOPAD(0x21e2, PIN_OUTPUT | MUX_MODE4) /* sys_clkout2.gpio_186 */
>;
};
+
+ dss_dpi_pins_common: pinmux_dss_dpi_pins_common {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+
+ OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+ OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
+ OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
+ OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
+ OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
+ OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
+ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
+ >;
+ };
+
+ dss_dpi_pins_cm_t35x: pinmux_dss_dpi_pins_cm_t35x {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
+ OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
+ OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
+ OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
+ OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
+ OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
+ >;
+ };
+
+ ads7846_pins: pinmux_ads7846_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20ba, PIN_INPUT_PULLUP | MUX_MODE4) /* gpmc_ncs6.gpio_57 */
+ >;
+ };
+
+ mcspi1_pins: pinmux_mcspi1_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21c8, PIN_INPUT | MUX_MODE0) /* mcspi1_clk */
+ OMAP3_CORE1_IOPAD(0x21ca, PIN_INPUT | MUX_MODE0) /* mcspi1_simo */
+ OMAP3_CORE1_IOPAD(0x21cc, PIN_INPUT | MUX_MODE0) /* mcspi1_somi */
+ OMAP3_CORE1_IOPAD(0x21ce, PIN_INPUT_PULLDOWN | MUX_MODE0) /* mcspi1_cs0 */
+ >;
+ };
+
+ i2c1_pins: pinmux_i2c1_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21ba, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_scl */
+ OMAP3_CORE1_IOPAD(0x21bc, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c1_sda */
+ >;
+ };
+
+ mcbsp2_pins: pinmux_mcbsp2_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x213c, PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx */
+ OMAP3_CORE1_IOPAD(0x213e, PIN_INPUT | MUX_MODE0) /* mcbsp2_clkx */
+ OMAP3_CORE1_IOPAD(0x2140, PIN_INPUT | MUX_MODE0) /* mcbsp2_dr */
+ OMAP3_CORE1_IOPAD(0x2142, PIN_OUTPUT | MUX_MODE0) /* mcbsp2_dx */
+ >;
+ };
};
&uart3 {
@@ -94,12 +182,22 @@
};
&i2c1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins>;
+
clock-frequency = <400000>;
+
+ at24@50 {
+ compatible = "at24,24c02";
+ pagesize = <16>;
+ reg = <0x50>;
+ };
};
&i2c3 {
clock-frequency = <400000>;
};
+
&usbhshost {
port1-mode = "ehci-phy";
port2-mode = "ehci-phy";
@@ -108,3 +206,56 @@
&usbhsehci {
phys = <&hsusb1_phy &hsusb2_phy>;
};
+
+&mcspi1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcspi1_pins>;
+
+ /* touch controller */
+ ads7846@0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ads7846_pins>;
+
+ compatible = "ti,ads7846";
+ vcc-supply = <&ads7846reg>;
+
+ reg = <0>; /* CS0 */
+ spi-max-frequency = <1500000>;
+
+ interrupt-parent = <&gpio2>;
+ interrupts = <25 0>; /* gpio_57 */
+ pendown-gpio = <&gpio2 25 0>;
+
+ ti,x-min = /bits/ 16 <0x0>;
+ ti,x-max = /bits/ 16 <0x0fff>;
+ ti,y-min = /bits/ 16 <0x0>;
+ ti,y-max = /bits/ 16 <0x0fff>;
+
+ ti,x-plate-ohms = /bits/ 16 <180>;
+ ti,pressure-max = /bits/ 16 <255>;
+
+ ti,debounce-max = /bits/ 16 <30>;
+ ti,debounce-tol = /bits/ 16 <10>;
+ ti,debounce-rep = /bits/ 16 <1>;
+
+ linux,wakeup;
+ };
+};
+
+&venc {
+ status = "ok";
+
+ port {
+ venc_out: endpoint {
+ remote-endpoint = <&tv_connector_in>;
+ ti,channels = <2>;
+ };
+ };
+};
+
+&mcbsp2 {
+ status = "ok";
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&mcbsp2_pins>;
+};
diff --git a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi
index 25ba083..9a4a3ab 100644
--- a/arch/arm/boot/dts/omap3-cm-t3x30.dtsi
+++ b/arch/arm/boot/dts/omap3-cm-t3x30.dtsi
@@ -10,6 +10,14 @@
cpu0-supply = <&vcc>;
};
};
+
+ sound {
+ compatible = "ti,omap-twl4030";
+ ti,model = "cm-t35";
+
+ ti,mcbsp = <&mcbsp2>;
+ ti,codec = <&twl_audio>;
+ };
};
&omap3_pmx_core {
@@ -59,11 +67,22 @@
reg = <0x48>;
interrupts = <7>; /* SYS_NIRQ cascaded to intc */
interrupt-parent = <&intc>;
+
+ twl_audio: audio {
+ compatible = "ti,twl4030-audio";
+ codec {
+ };
+ };
};
};
#include "twl4030.dtsi"
#include "twl4030_omap3.dtsi"
+#include <dt-bindings/input/input.h>
+
+&venc {
+ vdda-supply = <&vdac>;
+};
&mmc1 {
vmmc-supply = <&vmmc1>;
@@ -75,6 +94,22 @@
ti,pullups = <0x000001>;
};
+&twl_keypad {
+ linux,keymap = <
+ MATRIX_KEY(0x00, 0x01, KEY_A)
+ MATRIX_KEY(0x00, 0x02, KEY_B)
+ MATRIX_KEY(0x00, 0x03, KEY_LEFT)
+
+ MATRIX_KEY(0x01, 0x01, KEY_UP)
+ MATRIX_KEY(0x01, 0x02, KEY_ENTER)
+ MATRIX_KEY(0x01, 0x03, KEY_DOWN)
+
+ MATRIX_KEY(0x02, 0x01, KEY_RIGHT)
+ MATRIX_KEY(0x02, 0x02, KEY_C)
+ MATRIX_KEY(0x02, 0x03, KEY_D)
+ >;
+};
+
&hsusb1_phy {
reset-gpios = <&twl_gpio 6 GPIO_ACTIVE_LOW>;
};
diff --git a/arch/arm/boot/dts/omap3-devkit8000.dts b/arch/arm/boot/dts/omap3-devkit8000.dts
index da402f0..169037e 100644
--- a/arch/arm/boot/dts/omap3-devkit8000.dts
+++ b/arch/arm/boot/dts/omap3-devkit8000.dts
@@ -106,10 +106,10 @@
};
&gpmc {
- ranges = <0 0 0x30000000 0x04>; /* CS0: NAND */
+ ranges = <0 0 0x30000000 0x1000000>; /* CS0: 16MB for NAND */
nand@0,0 {
- reg = <0 0 0>; /* CS0, offset 0 */
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <16>;
gpmc,sync-clk-ps = <0>;
diff --git a/arch/arm/boot/dts/omap3-evm-37xx.dts b/arch/arm/boot/dts/omap3-evm-37xx.dts
index a8bd434..16e8ce3 100644
--- a/arch/arm/boot/dts/omap3-evm-37xx.dts
+++ b/arch/arm/boot/dts/omap3-evm-37xx.dts
@@ -154,13 +154,14 @@
};
&gpmc {
- ranges = <0 0 0x00000000 0x20000000>,
+ ranges = <0 0 0x00000000 0x1000000>, /* CS0: 16MB for NAND */
<5 0 0x2c000000 0x01000000>;
nand@0,0 {
linux,mtd-name= "hynix,h8kds0un0mer-4em";
- reg = <0 0 0>;
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <16>;
+ gpmc,device-width = <2>;
ti,nand-ecc-opt = "bch8";
gpmc,sync-clk-ps = <0>;
diff --git a/arch/arm/boot/dts/omap3-evm-common.dtsi b/arch/arm/boot/dts/omap3-evm-common.dtsi
index c8747c7..127f3e7 100644
--- a/arch/arm/boot/dts/omap3-evm-common.dtsi
+++ b/arch/arm/boot/dts/omap3-evm-common.dtsi
@@ -2,6 +2,7 @@
* Common support for omap3 EVM boards
*/
+#include <dt-bindings/input/input.h>
#include "omap-gpmc-smsc911x.dtsi"
/ {
@@ -111,6 +112,26 @@
ti,use-leds;
};
+&twl_keypad {
+ linux,keymap = <
+ MATRIX_KEY(2, 2, KEY_1)
+ MATRIX_KEY(1, 1, KEY_2)
+ MATRIX_KEY(0, 0, KEY_3)
+ MATRIX_KEY(3, 2, KEY_4)
+ MATRIX_KEY(2, 1, KEY_5)
+ MATRIX_KEY(1, 0, KEY_6)
+ MATRIX_KEY(1, 3, KEY_7)
+ MATRIX_KEY(3, 1, KEY_8)
+ MATRIX_KEY(2, 0, KEY_9)
+ MATRIX_KEY(2, 3, KEY_KPASTERISK)
+ MATRIX_KEY(0, 2, KEY_0)
+ MATRIX_KEY(3, 0, KEY_KPDOT)
+ /* s4 not wired */
+ MATRIX_KEY(1, 2, KEY_BACKSPACE)
+ MATRIX_KEY(0, 1, KEY_ENTER)
+ >;
+};
+
&usb_otg_hs {
interface-type = <0>;
usb-phy = <&usb2_phy>;
diff --git a/arch/arm/boot/dts/omap3-gta04.dtsi b/arch/arm/boot/dts/omap3-gta04.dtsi
index fd34f91..655d6e9 100644
--- a/arch/arm/boot/dts/omap3-gta04.dtsi
+++ b/arch/arm/boot/dts/omap3-gta04.dtsi
@@ -104,67 +104,67 @@
uart1_pins: pinmux_uart1_pins {
pinctrl-single,pins = <
- 0x152 (PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
- 0x14c (PIN_OUTPUT |MUX_MODE0) /* uart1_tx.uart1_tx */
+ OMAP3_CORE1_IOPAD(0x2182, PIN_INPUT | MUX_MODE0) /* uart1_rx.uart1_rx */
+ OMAP3_CORE1_IOPAD(0x217c, PIN_OUTPUT | MUX_MODE0) /* uart1_tx.uart1_tx */
>;
};
uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0x14a (PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
- 0x148 (PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
>;
};
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
- 0x16e (PIN_INPUT | MUX_MODE0) /* uart3_rx.uart3_rx */
- 0x170 (PIN_OUTPUT | MUX_MODE0) /* uart3_tx.uart3_tx */
+ OMAP3_CORE1_IOPAD(0x219e, PIN_INPUT | MUX_MODE0) /* uart3_rx.uart3_rx */
+ OMAP3_CORE1_IOPAD(0x21a0, PIN_OUTPUT | MUX_MODE0) /* uart3_tx.uart3_tx */
>;
};
mmc1_pins: pinmux_mmc1_pins {
pinctrl-single,pins = <
- 0x114 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
- 0x116 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
- 0x118 (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
- 0x11a (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
- 0x11c (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
- 0x11e (PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
+ OMAP3_CORE1_IOPAD(0x2144, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_clk.sdmmc1_clk */
+ OMAP3_CORE1_IOPAD(0x2146, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_cmd.sdmmc1_cmd */
+ OMAP3_CORE1_IOPAD(0x2148, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat0.sdmmc1_dat0 */
+ OMAP3_CORE1_IOPAD(0x214a, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat1.sdmmc1_dat1 */
+ OMAP3_CORE1_IOPAD(0x214c, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat2.sdmmc1_dat2 */
+ OMAP3_CORE1_IOPAD(0x214e, PIN_INPUT_PULLUP | MUX_MODE0) /* sdmmc1_dat3.sdmmc1_dat3 */
>;
};
dss_dpi_pins: pinmux_dss_dpi_pins {
pinctrl-single,pins = <
- 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
- 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
- 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
- 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
- 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
- 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
- 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
- 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
- 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
- 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
- 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
- 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
- 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
- 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
- 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
- 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
- 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
- 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
- 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
- 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
- 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
- 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
- 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
- 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
- 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
- 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
- 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
- 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
- >;
+ OMAP3_CORE1_IOPAD(0x20d4, PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ OMAP3_CORE1_IOPAD(0x20d6, PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ OMAP3_CORE1_IOPAD(0x20d8, PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ OMAP3_CORE1_IOPAD(0x20da, PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+ OMAP3_CORE1_IOPAD(0x20dc, PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
+ OMAP3_CORE1_IOPAD(0x20de, PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
+ OMAP3_CORE1_IOPAD(0x20e0, PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
+ OMAP3_CORE1_IOPAD(0x20e2, PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
+ OMAP3_CORE1_IOPAD(0x20e4, PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
+ OMAP3_CORE1_IOPAD(0x20e6, PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
+ OMAP3_CORE1_IOPAD(0x20e8, PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ OMAP3_CORE1_IOPAD(0x20ea, PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ OMAP3_CORE1_IOPAD(0x20ec, PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ OMAP3_CORE1_IOPAD(0x20ee, PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ OMAP3_CORE1_IOPAD(0x20f0, PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ OMAP3_CORE1_IOPAD(0x20f2, PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ OMAP3_CORE1_IOPAD(0x20f4, PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ OMAP3_CORE1_IOPAD(0x20f6, PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ OMAP3_CORE1_IOPAD(0x20f8, PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ OMAP3_CORE1_IOPAD(0x20fa, PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ OMAP3_CORE1_IOPAD(0x20fc, PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ OMAP3_CORE1_IOPAD(0x20fe, PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+ OMAP3_CORE1_IOPAD(0x2100, PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
+ OMAP3_CORE1_IOPAD(0x2102, PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
+ OMAP3_CORE1_IOPAD(0x2104, PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
+ OMAP3_CORE1_IOPAD(0x2106, PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
+ OMAP3_CORE1_IOPAD(0x2108, PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
+ OMAP3_CORE1_IOPAD(0x210a, PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
+ >;
};
};
@@ -397,10 +397,10 @@
};
&gpmc {
- ranges = <0 0 0x30000000 0x04>; /* CS0: NAND */
+ ranges = <0 0 0x30000000 0x1000000>; /* CS0: 16MB for NAND */
nand@0,0 {
- reg = <0 0 0>; /* CS0, offset 0 */
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <16>;
ti,nand-ecc-opt = "bch8";
diff --git a/arch/arm/boot/dts/omap3-igep.dtsi b/arch/arm/boot/dts/omap3-igep.dtsi
index e2d163b..8a63ad2 100644
--- a/arch/arm/boot/dts/omap3-igep.dtsi
+++ b/arch/arm/boot/dts/omap3-igep.dtsi
@@ -31,18 +31,6 @@
regulator-always-on;
};
- lbee1usjyc_vmmc: lbee1usjyc_vmmc {
- pinctrl-names = "default";
- pinctrl-0 = <&lbee1usjyc_pins>;
- compatible = "regulator-fixed";
- regulator-name = "regulator-lbee1usjyc";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>; /* gpio_138 WIFI_PDN */
- startup-delay-us = <10000>;
- enable-active-high;
- vin-supply = <&vdd33>;
- };
};
&omap3_pmx_core {
@@ -53,13 +41,6 @@
>;
};
- uart2_pins: pinmux_uart2_pins {
- pinctrl-single,pins = <
- 0x14a (PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
- 0x148 (PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
- >;
- };
-
uart3_pins: pinmux_uart3_pins {
pinctrl-single,pins = <
0x16e (PIN_INPUT | MUX_MODE0) /* uart3_rx.uart3_rx */
@@ -67,15 +48,6 @@
>;
};
- /* WiFi/BT combo */
- lbee1usjyc_pins: pinmux_lbee1usjyc_pins {
- pinctrl-single,pins = <
- 0x136 (PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat5.gpio_137 */
- 0x138 (PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat6.gpio_138 */
- 0x13a (PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 */
- >;
- };
-
mcbsp2_pins: pinmux_mcbsp2_pins {
pinctrl-single,pins = <
0x10c (PIN_INPUT | MUX_MODE0) /* mcbsp2_fsx.mcbsp2_fsx */
@@ -120,13 +92,6 @@
>;
};
- i2c2_pins: pinmux_i2c2_pins {
- pinctrl-single,pins = <
- 0x18e (PIN_INPUT | MUX_MODE0) /* i2c2_scl.i2c2_scl */
- 0x190 (PIN_INPUT | MUX_MODE0) /* i2c2_sda.i2c2_sda */
- >;
- };
-
i2c3_pins: pinmux_i2c3_pins {
pinctrl-single,pins = <
0x192 (PIN_INPUT | MUX_MODE0) /* i2c3_scl.i2c3_scl */
@@ -135,6 +100,55 @@
};
};
+&gpmc {
+ nand@0,0 {
+ linux,mtd-name= "micron,mt29c4g96maz";
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
+ nand-bus-width = <16>;
+ gpmc,device-width = <2>;
+ ti,nand-ecc-opt = "bch8";
+
+ gpmc,sync-clk-ps = <0>;
+ gpmc,cs-on-ns = <0>;
+ gpmc,cs-rd-off-ns = <44>;
+ gpmc,cs-wr-off-ns = <44>;
+ gpmc,adv-on-ns = <6>;
+ gpmc,adv-rd-off-ns = <34>;
+ gpmc,adv-wr-off-ns = <44>;
+ gpmc,we-off-ns = <40>;
+ gpmc,oe-off-ns = <54>;
+ gpmc,access-ns = <64>;
+ gpmc,rd-cycle-ns = <82>;
+ gpmc,wr-cycle-ns = <82>;
+ gpmc,wr-access-ns = <40>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@0 {
+ label = "SPL";
+ reg = <0 0x100000>;
+ };
+ partition@80000 {
+ label = "U-Boot";
+ reg = <0x100000 0x180000>;
+ };
+ partition@1c0000 {
+ label = "Environment";
+ reg = <0x280000 0x100000>;
+ };
+ partition@280000 {
+ label = "Kernel";
+ reg = <0x380000 0x300000>;
+ };
+ partition@780000 {
+ label = "Filesystem";
+ reg = <0x680000 0x1f980000>;
+ };
+ };
+};
+
&i2c1 {
pinctrl-names = "default";
pinctrl-0 = <&i2c1_pins>;
@@ -156,12 +170,6 @@
#include "twl4030.dtsi"
#include "twl4030_omap3.dtsi"
-&i2c2 {
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_pins>;
- clock-frequency = <400000>;
-};
-
&i2c3 {
pinctrl-names = "default";
pinctrl-0 = <&i2c3_pins>;
@@ -181,14 +189,6 @@
bus-width = <4>;
};
-&mmc2 {
- pinctrl-names = "default";
- pinctrl-0 = <&mmc2_pins>;
- vmmc-supply = <&lbee1usjyc_vmmc>;
- bus-width = <4>;
- non-removable;
-};
-
&mmc3 {
status = "disabled";
};
@@ -198,11 +198,6 @@
pinctrl-0 = <&uart1_pins>;
};
-&uart2 {
- pinctrl-names = "default";
- pinctrl-0 = <&uart2_pins>;
-};
-
&uart3 {
pinctrl-names = "default";
pinctrl-0 = <&uart3_pins>;
diff --git a/arch/arm/boot/dts/omap3-igep0020-common.dtsi b/arch/arm/boot/dts/omap3-igep0020-common.dtsi
new file mode 100644
index 0000000..e458c21
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-igep0020-common.dtsi
@@ -0,0 +1,246 @@
+/*
+ * Common Device Tree Source for IGEPv2
+ *
+ * Copyright (C) 2014 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2014 Enric Balletbo i Serra <eballetbo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "omap3-igep.dtsi"
+#include "omap-gpmc-smsc9221.dtsi"
+
+/ {
+
+ leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_pins>;
+ compatible = "gpio-leds";
+
+ boot {
+ label = "omap3:green:boot";
+ gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+
+ user0 {
+ label = "omap3:red:user0";
+ gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ user1 {
+ label = "omap3:red:user1";
+ gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
+ default-state = "off";
+ };
+
+ user2 {
+ label = "omap3:green:user1";
+ gpios = <&twl_gpio 19 GPIO_ACTIVE_LOW>;
+ };
+ };
+
+ /* HS USB Port 1 Power */
+ hsusb1_power: hsusb1_power_reg {
+ compatible = "regulator-fixed";
+ regulator-name = "hsusb1_vbus";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&twl_gpio 18 GPIO_ACTIVE_LOW>; /* GPIO LEDA */
+ startup-delay-us = <70000>;
+ };
+
+ /* HS USB Host PHY on PORT 1 */
+ hsusb1_phy: hsusb1_phy {
+ compatible = "usb-nop-xceiv";
+ reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; /* gpio_24 */
+ vcc-supply = <&hsusb1_power>;
+ };
+
+ tfp410: encoder@0 {
+ compatible = "ti,tfp410";
+ powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_LOW>; /* gpio_170 */
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ tfp410_in: endpoint@0 {
+ remote-endpoint = <&dpi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tfp410_out: endpoint@0 {
+ remote-endpoint = <&dvi_connector_in>;
+ };
+ };
+ };
+ };
+
+ dvi0: connector@0 {
+ compatible = "dvi-connector";
+ label = "dvi";
+
+ digital;
+
+ ddc-i2c-bus = <&i2c3>;
+
+ port {
+ dvi_connector_in: endpoint {
+ remote-endpoint = <&tfp410_out>;
+ };
+ };
+ };
+};
+
+&omap3_pmx_core {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &tfp410_pins
+ &dss_dpi_pins
+ >;
+
+ tfp410_pins: pinmux_tfp410_pins {
+ pinctrl-single,pins = <
+ 0x196 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */
+ >;
+ };
+
+ dss_dpi_pins: pinmux_dss_dpi_pins {
+ pinctrl-single,pins = <
+ 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
+ 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
+ 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
+ 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
+ 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
+ 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
+ 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
+ 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
+ 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
+ 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
+ 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
+ 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
+ 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
+ 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
+ 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
+ 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
+ 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
+ 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
+ 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
+ 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
+ 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
+ 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
+ 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
+ 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
+ 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
+ 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
+ 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
+ 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
+ >;
+ };
+
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT | MUX_MODE0) /* uart2_cts.uart2_cts */
+ OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts .uart2_rts*/
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
+ >;
+ };
+};
+
+&omap3_pmx_core2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <
+ &hsusbb1_pins
+ >;
+
+ hsusbb1_pins: pinmux_hsusbb1_pins {
+ pinctrl-single,pins = <
+ OMAP3630_CORE2_IOPAD(0x25da, PIN_OUTPUT | MUX_MODE3) /* etk_ctl.hsusb1_clk */
+ OMAP3630_CORE2_IOPAD(0x25d8, PIN_OUTPUT | MUX_MODE3) /* etk_clk.hsusb1_stp */
+ OMAP3630_CORE2_IOPAD(0x25ec, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d8.hsusb1_dir */
+ OMAP3630_CORE2_IOPAD(0x25ee, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d9.hsusb1_nxt */
+ OMAP3630_CORE2_IOPAD(0x25dc, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d0.hsusb1_data0 */
+ OMAP3630_CORE2_IOPAD(0x25de, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d1.hsusb1_data1 */
+ OMAP3630_CORE2_IOPAD(0x25e0, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d2.hsusb1_data2 */
+ OMAP3630_CORE2_IOPAD(0x25e2, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d3.hsusb1_data7 */
+ OMAP3630_CORE2_IOPAD(0x25e4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d4.hsusb1_data4 */
+ OMAP3630_CORE2_IOPAD(0x25e6, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d5.hsusb1_data5 */
+ OMAP3630_CORE2_IOPAD(0x25e8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d6.hsusb1_data6 */
+ OMAP3630_CORE2_IOPAD(0x25ea, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d7.hsusb1_data3 */
+ >;
+ };
+
+ leds_pins: pinmux_leds_pins {
+ pinctrl-single,pins = <
+ OMAP3630_CORE2_IOPAD(0x25f4, PIN_OUTPUT | MUX_MODE4) /* etk_d12.gpio_26 */
+ OMAP3630_CORE2_IOPAD(0x25f6, PIN_OUTPUT | MUX_MODE4) /* etk_d13.gpio_27 */
+ OMAP3630_CORE2_IOPAD(0x25f8, PIN_OUTPUT | MUX_MODE4) /* etk_d14.gpio_28 */
+ >;
+ };
+};
+
+&i2c3 {
+ clock-frequency = <100000>;
+
+ /*
+ * Display monitor features are burnt in the EEPROM
+ * as EDID data.
+ */
+ eeprom@50 {
+ compatible = "ti,eeprom";
+ reg = <0x50>;
+ };
+};
+
+&gpmc {
+ ranges = <0 0 0x00000000 0x20000000>,
+ <5 0 0x2c000000 0x01000000>;
+
+ ethernet@gpmc {
+ pinctrl-names = "default";
+ pinctrl-0 = <&smsc9221_pins>;
+ reg = <5 0 0xff>;
+ interrupt-parent = <&gpio6>;
+ interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+};
+
+&usbhshost {
+ port1-mode = "ehci-phy";
+};
+
+&usbhsehci {
+ phys = <&hsusb1_phy>;
+};
+
+&vpll2 {
+ /* Needed for DSS */
+ regulator-name = "vdds_dsi";
+};
+
+&dss {
+ status = "ok";
+
+ port {
+ dpi_out: endpoint {
+ remote-endpoint = <&tfp410_in>;
+ data-lines = <24>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/omap3-igep0020-rev-f.dts b/arch/arm/boot/dts/omap3-igep0020-rev-f.dts
new file mode 100644
index 0000000..cc8bd0c
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-igep0020-rev-f.dts
@@ -0,0 +1,45 @@
+/*
+ * Device Tree Source for IGEPv2 Rev. F (TI OMAP AM/DM37x)
+ *
+ * Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "omap3-igep0020-common.dtsi"
+
+/ {
+ model = "IGEPv2 Rev. F (TI OMAP AM/DM37x)";
+ compatible = "isee,omap3-igep0020-rev-f", "ti,omap36xx", "ti,omap3";
+
+ /* Regulator to trigger the WL_EN signal of the Wifi module */
+ lbep5clwmc_wlen: regulator-lbep5clwmc-wlen {
+ compatible = "regulator-fixed";
+ regulator-name = "regulator-lbep5clwmc-wlen";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; /* gpio_139 - WL_EN */
+ enable-active-high;
+ };
+};
+
+&omap3_pmx_core {
+ lbep5clwmc_pins: pinmux_lbep5clwmc_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21d4, PIN_INPUT | MUX_MODE4) /* mcspi1_cs3.gpio_177 - W_IRQ */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat5.gpio_137 - BT_EN */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 - WL_EN */
+ >;
+ };
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins &lbep5clwmc_pins>;
+ vmmc-supply = <&lbep5clwmc_wlen>;
+ bus-width = <4>;
+ non-removable;
+};
diff --git a/arch/arm/boot/dts/omap3-igep0020.dts b/arch/arm/boot/dts/omap3-igep0020.dts
index b22caaa..fea7f7e 100644
--- a/arch/arm/boot/dts/omap3-igep0020.dts
+++ b/arch/arm/boot/dts/omap3-igep0020.dts
@@ -1,5 +1,5 @@
/*
- * Device Tree Source for IGEPv2 Rev. (TI OMAP AM/DM37x)
+ * Device Tree Source for IGEPv2 Rev. C (TI OMAP AM/DM37x)
*
* Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
* Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
@@ -9,272 +9,59 @@
* published by the Free Software Foundation.
*/
-#include "omap3-igep.dtsi"
-#include "omap-gpmc-smsc9221.dtsi"
+#include "omap3-igep0020-common.dtsi"
/ {
- model = "IGEPv2 (TI OMAP AM/DM37x)";
+ model = "IGEPv2 Rev. C (TI OMAP AM/DM37x)";
compatible = "isee,omap3-igep0020", "ti,omap36xx", "ti,omap3";
- leds {
- pinctrl-names = "default";
- pinctrl-0 = <&leds_pins>;
- compatible = "gpio-leds";
-
- boot {
- label = "omap3:green:boot";
- gpios = <&gpio1 26 GPIO_ACTIVE_HIGH>;
- default-state = "on";
- };
-
- user0 {
- label = "omap3:red:user0";
- gpios = <&gpio1 27 GPIO_ACTIVE_HIGH>;
- default-state = "off";
- };
-
- user1 {
- label = "omap3:red:user1";
- gpios = <&gpio1 28 GPIO_ACTIVE_HIGH>;
- default-state = "off";
- };
-
- user2 {
- label = "omap3:green:user1";
- gpios = <&twl_gpio 19 GPIO_ACTIVE_LOW>;
- };
+ /* Regulator to trigger the WIFI_PDN signal of the Wifi module */
+ lbee1usjyc_pdn: lbee1usjyc_pdn {
+ compatible = "regulator-fixed";
+ regulator-name = "regulator-lbee1usjyc-pdn";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>; /* gpio_138 - WIFI_PDN */
+ startup-delay-us = <10000>;
+ enable-active-high;
};
- /* HS USB Port 1 Power */
- hsusb1_power: hsusb1_power_reg {
- compatible = "regulator-fixed";
- regulator-name = "hsusb1_vbus";
- regulator-min-microvolt = <3300000>;
- regulator-max-microvolt = <3300000>;
- gpio = <&twl_gpio 18 GPIO_ACTIVE_LOW>; /* GPIO LEDA */
- startup-delay-us = <70000>;
- };
-
- /* HS USB Host PHY on PORT 1 */
- hsusb1_phy: hsusb1_phy {
- compatible = "usb-nop-xceiv";
- reset-gpios = <&gpio1 24 GPIO_ACTIVE_LOW>; /* gpio_24 */
- vcc-supply = <&hsusb1_power>;
- };
-
- tfp410: encoder@0 {
- compatible = "ti,tfp410";
- powerdown-gpios = <&gpio6 10 GPIO_ACTIVE_LOW>; /* gpio_170 */
-
- ports {
- #address-cells = <1>;
- #size-cells = <0>;
-
- port@0 {
- reg = <0>;
-
- tfp410_in: endpoint@0 {
- remote-endpoint = <&dpi_out>;
- };
- };
-
- port@1 {
- reg = <1>;
-
- tfp410_out: endpoint@0 {
- remote-endpoint = <&dvi_connector_in>;
- };
- };
- };
- };
-
- dvi0: connector@0 {
- compatible = "dvi-connector";
- label = "dvi";
-
- digital;
-
- ddc-i2c-bus = <&i2c3>;
-
- port {
- dvi_connector_in: endpoint {
- remote-endpoint = <&tfp410_out>;
- };
- };
+ /* Regulator to trigger the RESET_N_W signal of the Wifi module */
+ lbee1usjyc_reset_n_w: lbee1usjyc_reset_n_w {
+ compatible = "regulator-fixed";
+ regulator-name = "regulator-lbee1usjyc-reset-n-w";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; /* gpio_139 - RESET_N_W */
+ enable-active-high;
};
};
&omap3_pmx_core {
- pinctrl-names = "default";
- pinctrl-0 = <
- &tfp410_pins
- &dss_dpi_pins
- >;
-
- tfp410_pins: pinmux_tfp410_pins {
+ lbee1usjyc_pins: pinmux_lbee1usjyc_pins {
pinctrl-single,pins = <
- 0x196 (PIN_OUTPUT | MUX_MODE4) /* hdq_sio.gpio_170 */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat5.gpio_137 - RESET_N_W */
+ OMAP3_CORE1_IOPAD(0x2168, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat6.gpio_138 - WIFI_PDN */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 - RST_N_B */
>;
};
- dss_dpi_pins: pinmux_dss_dpi_pins {
+ uart2_pins: pinmux_uart2_pins {
pinctrl-single,pins = <
- 0x0a4 (PIN_OUTPUT | MUX_MODE0) /* dss_pclk.dss_pclk */
- 0x0a6 (PIN_OUTPUT | MUX_MODE0) /* dss_hsync.dss_hsync */
- 0x0a8 (PIN_OUTPUT | MUX_MODE0) /* dss_vsync.dss_vsync */
- 0x0aa (PIN_OUTPUT | MUX_MODE0) /* dss_acbias.dss_acbias */
- 0x0ac (PIN_OUTPUT | MUX_MODE0) /* dss_data0.dss_data0 */
- 0x0ae (PIN_OUTPUT | MUX_MODE0) /* dss_data1.dss_data1 */
- 0x0b0 (PIN_OUTPUT | MUX_MODE0) /* dss_data2.dss_data2 */
- 0x0b2 (PIN_OUTPUT | MUX_MODE0) /* dss_data3.dss_data3 */
- 0x0b4 (PIN_OUTPUT | MUX_MODE0) /* dss_data4.dss_data4 */
- 0x0b6 (PIN_OUTPUT | MUX_MODE0) /* dss_data5.dss_data5 */
- 0x0b8 (PIN_OUTPUT | MUX_MODE0) /* dss_data6.dss_data6 */
- 0x0ba (PIN_OUTPUT | MUX_MODE0) /* dss_data7.dss_data7 */
- 0x0bc (PIN_OUTPUT | MUX_MODE0) /* dss_data8.dss_data8 */
- 0x0be (PIN_OUTPUT | MUX_MODE0) /* dss_data9.dss_data9 */
- 0x0c0 (PIN_OUTPUT | MUX_MODE0) /* dss_data10.dss_data10 */
- 0x0c2 (PIN_OUTPUT | MUX_MODE0) /* dss_data11.dss_data11 */
- 0x0c4 (PIN_OUTPUT | MUX_MODE0) /* dss_data12.dss_data12 */
- 0x0c6 (PIN_OUTPUT | MUX_MODE0) /* dss_data13.dss_data13 */
- 0x0c8 (PIN_OUTPUT | MUX_MODE0) /* dss_data14.dss_data14 */
- 0x0ca (PIN_OUTPUT | MUX_MODE0) /* dss_data15.dss_data15 */
- 0x0cc (PIN_OUTPUT | MUX_MODE0) /* dss_data16.dss_data16 */
- 0x0ce (PIN_OUTPUT | MUX_MODE0) /* dss_data17.dss_data17 */
- 0x0d0 (PIN_OUTPUT | MUX_MODE0) /* dss_data18.dss_data18 */
- 0x0d2 (PIN_OUTPUT | MUX_MODE0) /* dss_data19.dss_data19 */
- 0x0d4 (PIN_OUTPUT | MUX_MODE0) /* dss_data20.dss_data20 */
- 0x0d6 (PIN_OUTPUT | MUX_MODE0) /* dss_data21.dss_data21 */
- 0x0d8 (PIN_OUTPUT | MUX_MODE0) /* dss_data22.dss_data22 */
- 0x0da (PIN_OUTPUT | MUX_MODE0) /* dss_data23.dss_data23 */
+ OMAP3_CORE1_IOPAD(0x2174, PIN_INPUT | MUX_MODE0) /* uart2_cts.uart2_cts */
+ OMAP3_CORE1_IOPAD(0x2176, PIN_OUTPUT | MUX_MODE0) /* uart2_rts .uart2_rts*/
+ OMAP3_CORE1_IOPAD(0x2178, PIN_OUTPUT | MUX_MODE0) /* uart2_tx.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x217a, PIN_INPUT | MUX_MODE0) /* uart2_rx.uart2_rx */
>;
};
};
-&omap3_pmx_core2 {
+/* On board Wifi module */
+&mmc2 {
pinctrl-names = "default";
- pinctrl-0 = <
- &hsusbb1_pins
- >;
-
- hsusbb1_pins: pinmux_hsusbb1_pins {
- pinctrl-single,pins = <
- OMAP3630_CORE2_IOPAD(0x25da, PIN_OUTPUT | MUX_MODE3) /* etk_ctl.hsusb1_clk */
- OMAP3630_CORE2_IOPAD(0x25d8, PIN_OUTPUT | MUX_MODE3) /* etk_clk.hsusb1_stp */
- OMAP3630_CORE2_IOPAD(0x25ec, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d8.hsusb1_dir */
- OMAP3630_CORE2_IOPAD(0x25ee, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d9.hsusb1_nxt */
- OMAP3630_CORE2_IOPAD(0x25dc, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d0.hsusb1_data0 */
- OMAP3630_CORE2_IOPAD(0x25de, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d1.hsusb1_data1 */
- OMAP3630_CORE2_IOPAD(0x25e0, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d2.hsusb1_data2 */
- OMAP3630_CORE2_IOPAD(0x25e2, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d3.hsusb1_data7 */
- OMAP3630_CORE2_IOPAD(0x25e4, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d4.hsusb1_data4 */
- OMAP3630_CORE2_IOPAD(0x25e6, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d5.hsusb1_data5 */
- OMAP3630_CORE2_IOPAD(0x25e8, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d6.hsusb1_data6 */
- OMAP3630_CORE2_IOPAD(0x25ea, PIN_INPUT_PULLDOWN | MUX_MODE3) /* etk_d7.hsusb1_data3 */
- >;
- };
-
- leds_pins: pinmux_leds_pins {
- pinctrl-single,pins = <
- OMAP3630_CORE2_IOPAD(0x25f4, PIN_OUTPUT | MUX_MODE4) /* etk_d12.gpio_26 */
- OMAP3630_CORE2_IOPAD(0x25f6, PIN_OUTPUT | MUX_MODE4) /* etk_d13.gpio_27 */
- OMAP3630_CORE2_IOPAD(0x25f8, PIN_OUTPUT | MUX_MODE4) /* etk_d14.gpio_28 */
- >;
- };
-};
-
-&i2c3 {
- clock-frequency = <100000>;
-
- /*
- * Display monitor features are burnt in the EEPROM
- * as EDID data.
- */
- eeprom@50 {
- compatible = "ti,eeprom";
- reg = <0x50>;
- };
-};
-
-&gpmc {
- ranges = <0 0 0x00000000 0x20000000>,
- <5 0 0x2c000000 0x01000000>;
-
- nand@0,0 {
- linux,mtd-name= "micron,mt29c4g96maz";
- reg = <0 0 0>;
- nand-bus-width = <16>;
- ti,nand-ecc-opt = "bch8";
-
- gpmc,sync-clk-ps = <0>;
- gpmc,cs-on-ns = <0>;
- gpmc,cs-rd-off-ns = <44>;
- gpmc,cs-wr-off-ns = <44>;
- gpmc,adv-on-ns = <6>;
- gpmc,adv-rd-off-ns = <34>;
- gpmc,adv-wr-off-ns = <44>;
- gpmc,we-off-ns = <40>;
- gpmc,oe-off-ns = <54>;
- gpmc,access-ns = <64>;
- gpmc,rd-cycle-ns = <82>;
- gpmc,wr-cycle-ns = <82>;
- gpmc,wr-access-ns = <40>;
- gpmc,wr-data-mux-bus-ns = <0>;
-
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "SPL";
- reg = <0 0x100000>;
- };
- partition@80000 {
- label = "U-Boot";
- reg = <0x100000 0x180000>;
- };
- partition@1c0000 {
- label = "Environment";
- reg = <0x280000 0x100000>;
- };
- partition@280000 {
- label = "Kernel";
- reg = <0x380000 0x300000>;
- };
- partition@780000 {
- label = "Filesystem";
- reg = <0x680000 0x1f980000>;
- };
- };
-
- ethernet@gpmc {
- pinctrl-names = "default";
- pinctrl-0 = <&smsc9221_pins>;
- reg = <5 0 0xff>;
- interrupt-parent = <&gpio6>;
- interrupts = <16 IRQ_TYPE_LEVEL_LOW>;
- };
-};
-
-&usbhshost {
- port1-mode = "ehci-phy";
-};
-
-&usbhsehci {
- phys = <&hsusb1_phy>;
-};
-
-&vpll2 {
- /* Needed for DSS */
- regulator-name = "vdds_dsi";
-};
-
-&dss {
- status = "ok";
-
- port {
- dpi_out: endpoint {
- remote-endpoint = <&tfp410_in>;
- data-lines = <24>;
- };
- };
+ pinctrl-0 = <&mmc2_pins &lbee1usjyc_pins>;
+ vmmc-supply = <&lbee1usjyc_pdn>;
+ vmmc_aux-supply = <&lbee1usjyc_reset_n_w>;
+ bus-width = <4>;
+ non-removable;
};
diff --git a/arch/arm/boot/dts/omap3-igep0030-common.dtsi b/arch/arm/boot/dts/omap3-igep0030-common.dtsi
new file mode 100644
index 0000000..0cb1527
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-igep0030-common.dtsi
@@ -0,0 +1,60 @@
+/*
+ * Common Device Tree Source for IGEP COM MODULE
+ *
+ * Copyright (C) 2014 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2014 Enric Balletbo i Serra <eballetbo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "omap3-igep.dtsi"
+
+/ {
+ leds: gpio_leds {
+ compatible = "gpio-leds";
+
+ user0 {
+ label = "omap3:red:user0";
+ gpios = <&twl_gpio 18 GPIO_ACTIVE_LOW>; /* LEDA */
+ default-state = "off";
+ };
+
+ user1 {
+ label = "omap3:green:user1";
+ gpios = <&twl_gpio 19 GPIO_ACTIVE_LOW>; /* LEDB */
+ default-state = "off";
+ };
+
+ user2 {
+ label = "omap3:red:user1";
+ gpios = <&gpio1 16 GPIO_ACTIVE_LOW>; /* gpio_16 */
+ default-state = "off";
+ };
+ };
+};
+
+&omap3_pmx_core {
+ uart2_pins: pinmux_uart2_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x216c, PIN_INPUT | MUX_MODE1) /* mcbsp3_dx.uart2_cts */
+ OMAP3_CORE1_IOPAD(0x216e, PIN_OUTPUT | MUX_MODE1) /* mcbsp3_dr.uart2_rts */
+ OMAP3_CORE1_IOPAD(0x2170, PIN_OUTPUT | MUX_MODE1) /* mcbsp3_clk.uart2_tx */
+ OMAP3_CORE1_IOPAD(0x2172, PIN_INPUT | MUX_MODE1) /* mcbsp3_fsx.uart2_rx */
+ >;
+ };
+};
+
+&omap3_pmx_core2 {
+ leds_core2_pins: pinmux_leds_core2_pins {
+ pinctrl-single,pins = <
+ OMAP3630_CORE2_IOPAD(0x25e0, PIN_OUTPUT | MUX_MODE4) /* etk_d2.gpio_16 */
+ >;
+ };
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart2_pins>;
+};
diff --git a/arch/arm/boot/dts/omap3-igep0030-rev-g.dts b/arch/arm/boot/dts/omap3-igep0030-rev-g.dts
new file mode 100644
index 0000000..9326b28
--- /dev/null
+++ b/arch/arm/boot/dts/omap3-igep0030-rev-g.dts
@@ -0,0 +1,67 @@
+/*
+ * Device Tree Source for IGEP COM MODULE Rev. G (TI OMAP AM/DM37x)
+ *
+ * Copyright (C) 2014 Javier Martinez Canillas <javier@collabora.co.uk>
+ * Copyright (C) 2014 Enric Balletbo i Serra <eballetbo@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include "omap3-igep0030-common.dtsi"
+
+/ {
+ model = "IGEP COM MODULE Rev. G (TI OMAP AM/DM37x)";
+ compatible = "isee,omap3-igep0030-rev-g", "ti,omap36xx", "ti,omap3";
+
+ /* Regulator to trigger the WL_EN signal of the Wifi module */
+ lbep5clwmc_wlen: regulator-lbep5clwmc-wlen {
+ compatible = "regulator-fixed";
+ regulator-name = "regulator-lbep5clwmc-wlen";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; /* gpio_139 - WL_EN */
+ enable-active-high;
+ };
+};
+
+&omap3_pmx_core {
+ lbep5clwmc_pins: pinmux_lbep5clwmc_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x2164, PIN_INPUT | MUX_MODE4) /* sdmmc2_dat4.gpio_136 - W_IRQ */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat5.gpio_137 - BT_EN */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 - WL_EN */
+ >;
+ };
+
+ leds_pins: pinmux_leds_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21be, PIN_OUTPUT | MUX_MODE4) /* i2c2_scl.gpio_168 */
+ >;
+ };
+
+};
+
+&i2c2 {
+ status = "disabled";
+};
+
+&leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_pins &leds_core2_pins>;
+
+ boot {
+ label = "omap3:green:boot";
+ gpios = <&gpio6 8 GPIO_ACTIVE_HIGH>;
+ default-state = "on";
+ };
+};
+
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins &lbep5clwmc_pins>;
+ vmmc-supply = <&lbep5clwmc_wlen>;
+ bus-width = <4>;
+ non-removable;
+};
diff --git a/arch/arm/boot/dts/omap3-igep0030.dts b/arch/arm/boot/dts/omap3-igep0030.dts
index 2793749..8150f47 100644
--- a/arch/arm/boot/dts/omap3-igep0030.dts
+++ b/arch/arm/boot/dts/omap3-igep0030.dts
@@ -1,5 +1,5 @@
/*
- * Device Tree Source for IGEP COM MODULE (TI OMAP AM/DM37x)
+ * Device Tree Source for IGEP COM MODULE Rev. E (TI OMAP AM/DM37x)
*
* Copyright (C) 2012 Javier Martinez Canillas <javier@collabora.co.uk>
* Copyright (C) 2012 Enric Balletbo i Serra <eballetbo@gmail.com>
@@ -9,97 +9,62 @@
* published by the Free Software Foundation.
*/
-#include "omap3-igep.dtsi"
+#include "omap3-igep0030-common.dtsi"
/ {
- model = "IGEP COM MODULE (TI OMAP AM/DM37x)";
+ model = "IGEP COM MODULE Rev. E (TI OMAP AM/DM37x)";
compatible = "isee,omap3-igep0030", "ti,omap36xx", "ti,omap3";
- leds {
- pinctrl-names = "default";
- pinctrl-0 = <&leds_pins>;
- compatible = "gpio-leds";
-
- boot {
- label = "omap3:green:boot";
- gpios = <&twl_gpio 13 GPIO_ACTIVE_LOW>;
- default-state = "on";
- };
-
- user0 {
- label = "omap3:red:user0";
- gpios = <&twl_gpio 18 GPIO_ACTIVE_LOW>; /* LEDA */
- default-state = "off";
- };
-
- user1 {
- label = "omap3:green:user1";
- gpios = <&twl_gpio 19 GPIO_ACTIVE_LOW>; /* LEDB */
- default-state = "off";
- };
+ /* Regulator to trigger the WIFI_PDN signal of the Wifi module */
+ lbee1usjyc_pdn: lbee1usjyc_pdn {
+ compatible = "regulator-fixed";
+ regulator-name = "regulator-lbee1usjyc-pdn";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio5 10 GPIO_ACTIVE_HIGH>; /* gpio_138 - WIFI_PDN */
+ startup-delay-us = <10000>;
+ enable-active-high;
+ };
- user2 {
- label = "omap3:red:user1";
- gpios = <&gpio1 16 GPIO_ACTIVE_LOW>;
- default-state = "off";
- };
+ /* Regulator to trigger the RESET_N_W signal of the Wifi module */
+ lbee1usjyc_reset_n_w: lbee1usjyc_reset_n_w {
+ compatible = "regulator-fixed";
+ regulator-name = "regulator-lbee1usjyc-reset-n-w";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ gpio = <&gpio5 11 GPIO_ACTIVE_HIGH>; /* gpio_139 - RESET_N_W */
+ enable-active-high;
};
};
-&omap3_pmx_core2 {
- leds_pins: pinmux_leds_pins {
+&omap3_pmx_core {
+ lbee1usjyc_pins: pinmux_lbee1usjyc_pins {
pinctrl-single,pins = <
- OMAP3630_CORE2_IOPAD(0x25e0, PIN_OUTPUT | MUX_MODE4) /* etk_d2.gpio_16 */
+ OMAP3_CORE1_IOPAD(0x2166, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat5.gpio_137 - RESET_N_W */
+ OMAP3_CORE1_IOPAD(0x2168, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat6.gpio_138 - WIFI_PDN */
+ OMAP3_CORE1_IOPAD(0x216a, PIN_OUTPUT | MUX_MODE4) /* sdmmc2_dat7.gpio_139 - RST_N_B */
>;
};
};
-&gpmc {
- ranges = <0 0 0x00000000 0x20000000>;
-
- nand@0,0 {
- linux,mtd-name= "micron,mt29c4g96maz";
- reg = <0 0 0>;
- nand-bus-width = <16>;
- ti,nand-ecc-opt = "bch8";
+&leds {
+ pinctrl-names = "default";
+ pinctrl-0 = <&leds_core2_pins>;
- gpmc,sync-clk-ps = <0>;
- gpmc,cs-on-ns = <0>;
- gpmc,cs-rd-off-ns = <44>;
- gpmc,cs-wr-off-ns = <44>;
- gpmc,adv-on-ns = <6>;
- gpmc,adv-rd-off-ns = <34>;
- gpmc,adv-wr-off-ns = <44>;
- gpmc,we-off-ns = <40>;
- gpmc,oe-off-ns = <54>;
- gpmc,access-ns = <64>;
- gpmc,rd-cycle-ns = <82>;
- gpmc,wr-cycle-ns = <82>;
- gpmc,wr-access-ns = <40>;
- gpmc,wr-data-mux-bus-ns = <0>;
-
- #address-cells = <1>;
- #size-cells = <1>;
-
- partition@0 {
- label = "SPL";
- reg = <0 0x100000>;
- };
- partition@80000 {
- label = "U-Boot";
- reg = <0x100000 0x180000>;
- };
- partition@1c0000 {
- label = "Environment";
- reg = <0x280000 0x100000>;
- };
- partition@280000 {
- label = "Kernel";
- reg = <0x380000 0x300000>;
- };
- partition@780000 {
- label = "Filesystem";
- reg = <0x680000 0x1f980000>;
- };
+ boot {
+ label = "omap3:green:boot";
+ gpios = <&twl_gpio 13 GPIO_ACTIVE_LOW>; /* LEDSYNC */
+ default-state = "on";
};
};
+
+/* On board Wifi module */
+&mmc2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins &lbee1usjyc_pins>;
+ vmmc-supply = <&lbee1usjyc_pdn>;
+ vmmc_aux-supply = <&lbee1usjyc_reset_n_w>;
+ bus-width = <4>;
+ non-removable;
+};
+
diff --git a/arch/arm/boot/dts/omap3-ldp.dts b/arch/arm/boot/dts/omap3-ldp.dts
index 72dca0b..b699bc4 100644
--- a/arch/arm/boot/dts/omap3-ldp.dts
+++ b/arch/arm/boot/dts/omap3-ldp.dts
@@ -7,6 +7,7 @@
*/
/dts-v1/;
+#include <dt-bindings/input/input.h>
#include "omap34xx.dtsi"
#include "omap-gpmc-smsc911x.dtsi"
@@ -101,8 +102,9 @@
nand@0,0 {
linux,mtd-name= "micron,nand";
- reg = <0 0 0>;
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <16>;
+ gpmc,device-width = <2>;
ti,nand-ecc-opt = "bch8";
gpmc,sync-clk-ps = <0>;
@@ -141,7 +143,7 @@
};
partition@2000000 {
label = "Filesystem";
- reg = <0x2000000 0xe000000>;
+ reg = <0x2000000 0x6000000>;
};
};
@@ -263,6 +265,26 @@
};
};
+&twl_keypad {
+ linux,keymap = <MATRIX_KEY(0, 0, KEY_1)
+ MATRIX_KEY(0, 1, KEY_2)
+ MATRIX_KEY(0, 2, KEY_3)
+ MATRIX_KEY(1, 0, KEY_4)
+ MATRIX_KEY(1, 1, KEY_5)
+ MATRIX_KEY(1, 2, KEY_6)
+ MATRIX_KEY(1, 3, KEY_F5)
+ MATRIX_KEY(2, 0, KEY_7)
+ MATRIX_KEY(2, 1, KEY_8)
+ MATRIX_KEY(2, 2, KEY_9)
+ MATRIX_KEY(2, 3, KEY_F6)
+ MATRIX_KEY(3, 0, KEY_F7)
+ MATRIX_KEY(3, 1, KEY_0)
+ MATRIX_KEY(3, 2, KEY_F8)
+ MATRIX_KEY(5, 4, KEY_RESERVED)
+ MATRIX_KEY(4, 4, KEY_VOLUMEUP)
+ MATRIX_KEY(5, 5, KEY_VOLUMEDOWN)>;
+};
+
&uart3 {
interrupts-extended = <&intc 74 &omap3_pmx_core OMAP3_UART3_RX>;
};
diff --git a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
index d973088..e81fb65 100644
--- a/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
+++ b/arch/arm/boot/dts/omap3-lilly-a83x.dtsi
@@ -363,7 +363,7 @@
<7 0 0x15000000 0x01000000>;
nand@0,0 {
- reg = <0 0 0x1000000>;
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <16>;
ti,nand-ecc-opt = "bch8";
/* no elm on omap3 */
diff --git a/arch/arm/boot/dts/omap3-n900.dts b/arch/arm/boot/dts/omap3-n900.dts
index bc82a12..53f3ca0 100644
--- a/arch/arm/boot/dts/omap3-n900.dts
+++ b/arch/arm/boot/dts/omap3-n900.dts
@@ -115,6 +115,12 @@
eci-switch-gpios = <&gpio6 22 GPIO_ACTIVE_HIGH>; /* 182 */
speaker-amplifier-gpios = <&twl_gpio 7 GPIO_ACTIVE_HIGH>;
};
+
+ battery: n900-battery {
+ compatible = "nokia,n900-battery";
+ io-channels = <&twl_madc 0>, <&twl_madc 4>, <&twl_madc 12>;
+ io-channel-names = "temp", "bsi", "vbat";
+ };
};
&omap3_pmx_core {
@@ -142,6 +148,33 @@
>;
};
+ gpmc_pins: pinmux_gpmc_pins {
+ pinctrl-single,pins = <
+
+ /* address lines */
+ OMAP3_CORE1_IOPAD(0x207a, PIN_OUTPUT | MUX_MODE0) /* gpmc_a1.gpmc_a1 */
+ OMAP3_CORE1_IOPAD(0x207c, PIN_OUTPUT | MUX_MODE0) /* gpmc_a2.gpmc_a2 */
+ OMAP3_CORE1_IOPAD(0x207e, PIN_OUTPUT | MUX_MODE0) /* gpmc_a3.gpmc_a3 */
+
+ /* data lines, gpmc_d0..d7 not muxable according to TRM */
+ OMAP3_CORE1_IOPAD(0x209e, PIN_INPUT | MUX_MODE0) /* gpmc_d8.gpmc_d8 */
+ OMAP3_CORE1_IOPAD(0x20a0, PIN_INPUT | MUX_MODE0) /* gpmc_d9.gpmc_d9 */
+ OMAP3_CORE1_IOPAD(0x20a2, PIN_INPUT | MUX_MODE0) /* gpmc_d10.gpmc_d10 */
+ OMAP3_CORE1_IOPAD(0x20a4, PIN_INPUT | MUX_MODE0) /* gpmc_d11.gpmc_d11 */
+ OMAP3_CORE1_IOPAD(0x20a6, PIN_INPUT | MUX_MODE0) /* gpmc_d12.gpmc_d12 */
+ OMAP3_CORE1_IOPAD(0x20a8, PIN_INPUT | MUX_MODE0) /* gpmc_d13.gpmc_d13 */
+ OMAP3_CORE1_IOPAD(0x20aa, PIN_INPUT | MUX_MODE0) /* gpmc_d14.gpmc_d14 */
+ OMAP3_CORE1_IOPAD(0x20ac, PIN_INPUT | MUX_MODE0) /* gpmc_d15.gpmc_d15 */
+
+ /*
+ * gpmc_ncs0, gpmc_nadv_ale, gpmc_noe, gpmc_nwe, gpmc_wait0 not muxable
+ * according to TRM. OneNAND seems to require PIN_INPUT on clock.
+ */
+ OMAP3_CORE1_IOPAD(0x20b0, PIN_OUTPUT | MUX_MODE0) /* gpmc_ncs1.gpmc_ncs1 */
+ OMAP3_CORE1_IOPAD(0x20be, PIN_INPUT | MUX_MODE0) /* gpmc_clk.gpmc_clk */
+ >;
+ };
+
i2c1_pins: pinmux_i2c1_pins {
pinctrl-single,pins = <
0x18a (PIN_INPUT | MUX_MODE0) /* i2c1_scl */
@@ -540,6 +573,16 @@
power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>; /* 98 */
};
+ si4713: si4713@63 {
+ compatible = "silabs,si4713";
+ reg = <0x63>;
+
+ interrupts-extended = <&gpio2 21 IRQ_TYPE_EDGE_FALLING>; /* 53 */
+ reset-gpios = <&gpio6 3 GPIO_ACTIVE_HIGH>; /* 163 */
+ vio-supply = <&vio>;
+ vdd-supply = <&vaux1>;
+ };
+
bq24150a: bq24150a@6b {
compatible = "ti,bq24150a";
reg = <0x6b>;
@@ -585,16 +628,16 @@
};
&gpmc {
- ranges = <0 0 0x04000000 0x10000000>; /* 256MB */
ranges = <0 0 0x01000000 0x01000000>, /* 16 MB for OneNAND */
<1 0 0x02000000 0x01000000>; /* 16 MB for smc91c96 */
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpmc_pins>;
- /* gpio-irq for dma: 65 */
-
+ /* sys_ndmareq1 could be used by the driver, not as gpio65 though */
onenand@0,0 {
#address-cells = <1>;
#size-cells = <1>;
- reg = <0 0 0x10000000>;
+ reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */
gpmc,sync-read;
gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 70addcb..1e49dfe 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -115,12 +115,12 @@
};
&gpmc {
- ranges = <0 0 0x04000000 0x20000000>;
+ ranges = <0 0 0x04000000 0x1000000>; /* CS0: 16MB for OneNAND */
onenand@0,0 {
#address-cells = <1>;
#size-cells = <1>;
- reg = <0 0 0x20000000>;
+ reg = <0 0 0x20000>; /* CS0, offset 0, IO size 128K */
gpmc,sync-read;
gpmc,sync-write;
diff --git a/arch/arm/boot/dts/omap3-sb-t35.dtsi b/arch/arm/boot/dts/omap3-sb-t35.dtsi
index d59e3de..827f614 100644
--- a/arch/arm/boot/dts/omap3-sb-t35.dtsi
+++ b/arch/arm/boot/dts/omap3-sb-t35.dtsi
@@ -2,6 +2,59 @@
* Common support for CompuLab SB-T35 used on SBC-T3530, SBC-T3517 and SBC-T3730
*/
+/ {
+ tfp410: encoder@0 {
+ compatible = "ti,tfp410";
+
+ powerdown-gpios = <&gpio2 22 GPIO_ACTIVE_LOW>; /* gpio_54 */
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&tfp410_pins>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+
+ tfp410_in: endpoint@0 {
+ remote-endpoint = <&dpi_out>;
+ };
+ };
+
+ port@1 {
+ reg = <1>;
+
+ tfp410_out: endpoint@0 {
+ remote-endpoint = <&dvi_connector_in>;
+ };
+ };
+ };
+ };
+
+ dvi0: connector@0 {
+ compatible = "dvi-connector";
+ label = "dvi";
+
+ port {
+ dvi_connector_in: endpoint {
+ remote-endpoint = <&tfp410_out>;
+ };
+ };
+ };
+
+ audio_amp: audio_amp {
+ compatible = "regulator-fixed";
+ regulator-name = "audio_amp";
+ pinctrl-names = "default";
+ pinctrl-0 = <&sb_t35_audio_amp>;
+ gpio = <&gpio2 29 GPIO_ACTIVE_LOW>; /* gpio_61 */
+ enable-active-low;
+ regulator-always-on;
+ };
+};
+
&omap3_pmx_core {
smsc2_pins: pinmux_smsc2_pins {
pinctrl-single,pins = <
@@ -9,6 +62,38 @@
OMAP3_CORE1_IOPAD(0x20d2, PIN_INPUT_PULLUP | MUX_MODE4) /* gpmc_wait3.gpio_65 */
>;
};
+
+ tfp410_pins: pinmux_tfp410_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20b4, PIN_OUTPUT | MUX_MODE4) /* gpmc_ncs3.gpio_54 */
+ >;
+ };
+
+ i2c3_pins: pinmux_i2c3_pins {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x21c2, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_scl */
+ OMAP3_CORE1_IOPAD(0x21c4, PIN_INPUT_PULLUP | MUX_MODE0) /* i2c3_sda */
+ >;
+ };
+
+ sb_t35_audio_amp: pinmux_sb_t35_audio_amp {
+ pinctrl-single,pins = <
+ OMAP3_CORE1_IOPAD(0x20c8, PIN_OUTPUT | MUX_MODE4) /* gpmc_nbe1.gpio_61 */
+ >;
+ };
+};
+
+&i2c3 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins>;
+
+ clock-frequency = <400000>;
+
+ at24@50 {
+ compatible = "at24,24c02";
+ pagesize = <16>;
+ reg = <0x50>;
+ };
};
&gpmc {
@@ -22,24 +107,29 @@
interrupts = <1 IRQ_TYPE_LEVEL_LOW>;
reg = <4 0 0xff>;
bank-width = <2>;
- gpmc,mux-add-data;
- gpmc,cs-on-ns = <1>;
- gpmc,cs-rd-off-ns = <180>;
- gpmc,cs-wr-off-ns = <180>;
- gpmc,adv-rd-off-ns = <18>;
- gpmc,adv-wr-off-ns = <48>;
- gpmc,oe-on-ns = <54>;
- gpmc,oe-off-ns = <168>;
- gpmc,we-on-ns = <54>;
- gpmc,we-off-ns = <168>;
- gpmc,rd-cycle-ns = <186>;
- gpmc,wr-cycle-ns = <186>;
- gpmc,access-ns = <144>;
- gpmc,page-burst-access-ns = <24>;
- gpmc,bus-turnaround-ns = <90>;
- gpmc,cycle2cycle-delay-ns = <90>;
- gpmc,cycle2cycle-samecsen;
- gpmc,cycle2cycle-diffcsen;
+ gpmc,device-width = <1>;
+ gpmc,cycle2cycle-samecsen = <1>;
+ gpmc,cycle2cycle-diffcsen = <1>;
+ gpmc,cs-on-ns = <5>;
+ gpmc,cs-rd-off-ns = <150>;
+ gpmc,cs-wr-off-ns = <150>;
+ gpmc,adv-on-ns = <0>;
+ gpmc,adv-rd-off-ns = <15>;
+ gpmc,adv-wr-off-ns = <40>;
+ gpmc,oe-on-ns = <45>;
+ gpmc,oe-off-ns = <140>;
+ gpmc,we-on-ns = <45>;
+ gpmc,we-off-ns = <140>;
+ gpmc,rd-cycle-ns = <155>;
+ gpmc,wr-cycle-ns = <155>;
+ gpmc,access-ns = <120>;
+ gpmc,page-burst-access-ns = <20>;
+ gpmc,bus-turnaround-ns = <75>;
+ gpmc,cycle2cycle-delay-ns = <75>;
+ gpmc,wait-monitoring-ns = <0>;
+ gpmc,clk-activation-ns = <0>;
+ gpmc,wr-data-mux-bus-ns = <0>;
+ gpmc,wr-access-ns = <0>;
vddvario-supply = <&vddvario>;
vdd33a-supply = <&vdd33a>;
reg-io-width = <4>;
diff --git a/arch/arm/boot/dts/omap3-sbc-t3517.dts b/arch/arm/boot/dts/omap3-sbc-t3517.dts
index 42189b6..1798653 100644
--- a/arch/arm/boot/dts/omap3-sbc-t3517.dts
+++ b/arch/arm/boot/dts/omap3-sbc-t3517.dts
@@ -9,6 +9,11 @@
model = "CompuLab SBC-T3517 with CM-T3517";
compatible = "compulab,omap3-sbc-t3517", "compulab,omap3-cm-t3517", "ti,am3517", "ti,omap3";
+ aliases {
+ display0 = &dvi0;
+ display1 = &tv0;
+ };
+
/* Only one GPMC smsc9220 on SBC-T3517, CM-T3517 uses am35x Ethernet */
vddvario: regulator-vddvario-sb-t35 {
compatible = "regulator-fixed";
@@ -54,3 +59,13 @@
wp-gpios = <&gpio2 27 GPIO_ACTIVE_HIGH>; /* gpio_59 */
cd-gpios = <&gpio5 16 GPIO_ACTIVE_HIGH>; /* gpio_144 */
};
+
+&dss {
+ port {
+ dpi_out: endpoint {
+ remote-endpoint = <&tfp410_in>;
+ data-lines = <24>;
+ };
+ };
+};
+
diff --git a/arch/arm/boot/dts/omap3-sbc-t3530.dts b/arch/arm/boot/dts/omap3-sbc-t3530.dts
index bbbeea6..c994f0f 100644
--- a/arch/arm/boot/dts/omap3-sbc-t3530.dts
+++ b/arch/arm/boot/dts/omap3-sbc-t3530.dts
@@ -8,6 +8,11 @@
/ {
model = "CompuLab SBC-T3530 with CM-T3530";
compatible = "compulab,omap3-sbc-t3530", "compulab,omap3-cm-t3530", "ti,omap34xx", "ti,omap3";
+
+ aliases {
+ display0 = &dvi0;
+ display1 = &tv0;
+ };
};
&omap3_pmx_core {
@@ -34,3 +39,13 @@
&mmc1 {
cd-gpios = <&twl_gpio 0 GPIO_ACTIVE_HIGH>;
};
+
+&dss {
+ port {
+ dpi_out: endpoint {
+ remote-endpoint = <&tfp410_in>;
+ data-lines = <24>;
+ };
+ };
+};
+
diff --git a/arch/arm/boot/dts/omap3-sbc-t3730.dts b/arch/arm/boot/dts/omap3-sbc-t3730.dts
index 08e4a70..5bdddf2 100644
--- a/arch/arm/boot/dts/omap3-sbc-t3730.dts
+++ b/arch/arm/boot/dts/omap3-sbc-t3730.dts
@@ -8,6 +8,11 @@
/ {
model = "CompuLab SBC-T3730 with CM-T3730";
compatible = "compulab,omap3-sbc-t3730", "compulab,omap3-cm-t3730", "ti,omap36xx", "ti,omap3";
+
+ aliases {
+ display0 = &dvi0;
+ display1 = &tv0;
+ };
};
&omap3_pmx_core {
@@ -25,3 +30,13 @@
ranges = <5 0 0x2c000000 0x01000000>,
<4 0 0x2d000000 0x01000000>;
};
+
+&dss {
+ port {
+ dpi_out: endpoint {
+ remote-endpoint = <&tfp410_in>;
+ data-lines = <24>;
+ };
+ };
+};
+
diff --git a/arch/arm/boot/dts/omap3-tao3530.dtsi b/arch/arm/boot/dts/omap3-tao3530.dtsi
index b30f387..e89820a 100644
--- a/arch/arm/boot/dts/omap3-tao3530.dtsi
+++ b/arch/arm/boot/dts/omap3-tao3530.dtsi
@@ -270,7 +270,7 @@
ranges = <0 0 0x00000000 0x01000000>;
nand@0,0 {
- reg = <0 0 0>; /* CS0, offset 0 */
+ reg = <0 0 4>; /* CS0, offset 0, IO size 4 */
nand-bus-width = <16>;
gpmc,device-width = <2>; /* GPMC_DEVWIDTH_16BIT */
ti,nand-ecc-opt = "sw";
diff --git a/arch/arm/boot/dts/omap3.dtsi b/arch/arm/boot/dts/omap3.dtsi
index d0e884d..01b7111 100644
--- a/arch/arm/boot/dts/omap3.dtsi
+++ b/arch/arm/boot/dts/omap3.dtsi
@@ -79,7 +79,7 @@
* hierarchy.
*/
ocp {
- compatible = "simple-bus";
+ compatible = "ti,omap3-l3-smx", "simple-bus";
reg = <0x68000000 0x10000>;
interrupts = <9 10>;
#address-cells = <1>;
@@ -332,6 +332,7 @@
ti,hwmods = "mailbox";
reg = <0x48094000 0x200>;
interrupts = <26>;
+ #mbox-cells = <1>;
ti,mbox-num-users = <2>;
ti,mbox-num-fifos = <2>;
mbox_dsp: dsp {
diff --git a/arch/arm/boot/dts/omap3430-sdp.dts b/arch/arm/boot/dts/omap3430-sdp.dts
index 9bad94e..16b0cdf 100644
--- a/arch/arm/boot/dts/omap3430-sdp.dts
+++ b/arch/arm/boot/dts/omap3430-sdp.dts
@@ -51,8 +51,8 @@
&gpmc {
ranges = <0 0 0x10000000 0x08000000>,
- <1 0 0x28000000 0x08000000>,
- <2 0 0x20000000 0x10000000>;
+ <1 0 0x28000000 0x1000000>, /* CS1: 16MB for NAND */
+ <2 0 0x20000000 0x1000000>; /* CS2: 16MB for OneNAND */
nor@0,0 {
compatible = "cfi-flash";
@@ -106,7 +106,7 @@
linux,mtd-name= "micron,mt29f1g08abb";
#address-cells = <1>;
#size-cells = <1>;
- reg = <1 0 0x08000000>;
+ reg = <1 0 4>; /* CS1, offset 0, IO size 4 */
ti,nand-ecc-opt = "sw";
nand-bus-width = <8>;
gpmc,cs-on-ns = <0>;
@@ -150,7 +150,7 @@
linux,mtd-name= "samsung,kfm2g16q2m-deb8";
#address-cells = <1>;
#size-cells = <1>;
- reg = <2 0 0x10000000>;
+ reg = <2 0 0x20000>; /* CS2, offset 0, IO size 4 */
gpmc,device-width = <2>;
gpmc,mux-add-data = <2>;
diff --git a/arch/arm/boot/dts/omap4-duovero-parlor.dts b/arch/arm/boot/dts/omap4-duovero-parlor.dts
index 6dc84d9..1a78f01 100644
--- a/arch/arm/boot/dts/omap4-duovero-parlor.dts
+++ b/arch/arm/boot/dts/omap4-duovero-parlor.dts
@@ -177,6 +177,7 @@
&hdmi {
status = "ok";
+ vdda-supply = <&vdac>;
pinctrl-names = "default";
pinctrl-0 = <&dss_hdmi_pins>;
diff --git a/arch/arm/boot/dts/omap4.dtsi b/arch/arm/boot/dts/omap4.dtsi
index 878c979..074147c 100644
--- a/arch/arm/boot/dts/omap4.dtsi
+++ b/arch/arm/boot/dts/omap4.dtsi
@@ -661,6 +661,7 @@
reg = <0x4a0f4000 0x200>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <3>;
ti,mbox-num-fifos = <8>;
mbox_ipu: mbox_ipu {
@@ -895,7 +896,7 @@
reg = <0x58002000 0x1000>;
status = "disabled";
ti,hwmods = "dss_rfbi";
- clocks = <&dss_dss_clk>, <&dss_fck>;
+ clocks = <&dss_dss_clk>, <&l3_div_ck>;
clock-names = "fck", "ick";
};
diff --git a/arch/arm/boot/dts/omap44xx-clocks.dtsi b/arch/arm/boot/dts/omap44xx-clocks.dtsi
index c821ff5..f2c48f0 100644
--- a/arch/arm/boot/dts/omap44xx-clocks.dtsi
+++ b/arch/arm/boot/dts/omap44xx-clocks.dtsi
@@ -1018,14 +1018,6 @@
reg = <0x1120>;
};
- dss_fck: dss_fck {
- #clock-cells = <0>;
- compatible = "ti,gate-clock";
- clocks = <&l3_div_ck>;
- ti,bit-shift = <1>;
- reg = <0x1120>;
- };
-
fdif_fck: fdif_fck {
#clock-cells = <0>;
compatible = "ti,divider-clock";
diff --git a/arch/arm/boot/dts/omap5.dtsi b/arch/arm/boot/dts/omap5.dtsi
index 256b7f6..b321fdf 100644
--- a/arch/arm/boot/dts/omap5.dtsi
+++ b/arch/arm/boot/dts/omap5.dtsi
@@ -651,6 +651,7 @@
reg = <0x4a0f4000 0x200>;
interrupts = <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>;
ti,hwmods = "mailbox";
+ #mbox-cells = <1>;
ti,mbox-num-users = <3>;
ti,mbox-num-fifos = <8>;
mbox_ipu: mbox_ipu {
diff --git a/arch/arm/boot/dts/prima2.dtsi b/arch/arm/boot/dts/prima2.dtsi
index 963b7e5..1ca1a9a 100644
--- a/arch/arm/boot/dts/prima2.dtsi
+++ b/arch/arm/boot/dts/prima2.dtsi
@@ -41,6 +41,11 @@
};
};
+ arm-pmu {
+ compatible = "arm,cortex-a9-pmu";
+ interrupts = <29>;
+ };
+
axi {
compatible = "simple-bus";
#address-cells = <1>;
@@ -132,6 +137,7 @@
reg = <0x90020000 0x10000>;
interrupts = <31>;
clocks = <&clks 35>;
+ resets = <&rstc 6>;
};
};
@@ -173,6 +179,7 @@
compatible = "sirf,prima2-dspif";
reg = <0xa8000000 0x10000>;
interrupts = <9>;
+ resets = <&rstc 1>;
};
gps@a8010000 {
@@ -180,6 +187,7 @@
reg = <0xa8010000 0x10000>;
interrupts = <7>;
clocks = <&clks 9>;
+ resets = <&rstc 2>;
};
dsp@a9000000 {
@@ -187,6 +195,7 @@
reg = <0xa9000000 0x1000000>;
interrupts = <8>;
clocks = <&clks 8>;
+ resets = <&rstc 0>;
};
};
@@ -524,12 +533,36 @@
sirf,function = "sdmmc5";
};
};
+ i2s_mclk_pins_a: i2s_mclk@0 {
+ i2s_mclk {
+ sirf,pins = "i2smclkgrp";
+ sirf,function = "i2s_mclk";
+ };
+ };
+ i2s_ext_clk_input_pins_a: i2s_ext_clk_input@0 {
+ i2s_ext_clk_input {
+ sirf,pins = "i2s_ext_clk_inputgrp";
+ sirf,function = "i2s_ext_clk_input";
+ };
+ };
i2s_pins_a: i2s@0 {
i2s {
sirf,pins = "i2sgrp";
sirf,function = "i2s";
};
};
+ i2s_no_din_pins_a: i2s_no_din@0 {
+ i2s_no_din {
+ sirf,pins = "i2s_no_dingrp";
+ sirf,function = "i2s_no_din";
+ };
+ };
+ i2s_6chn_pins_a: i2s_6chn@0 {
+ i2s_6chn {
+ sirf,pins = "i2s_6chngrp";
+ sirf,function = "i2s_6chn";
+ };
+ };
ac97_pins_a: ac97@0 {
ac97 {
sirf,pins = "ac97grp";
diff --git a/arch/arm/boot/dts/r7s72100-genmai.dts b/arch/arm/boot/dts/r7s72100-genmai.dts
index a3ed23c..1518c5b 100644
--- a/arch/arm/boot/dts/r7s72100-genmai.dts
+++ b/arch/arm/boot/dts/r7s72100-genmai.dts
@@ -21,7 +21,8 @@
};
chosen {
- bootargs = "console=ttySC2,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = &scif2;
};
memory {
diff --git a/arch/arm/boot/dts/r7s72100.dtsi b/arch/arm/boot/dts/r7s72100.dtsi
index 801a556..277e73c 100644
--- a/arch/arm/boot/dts/r7s72100.dtsi
+++ b/arch/arm/boot/dts/r7s72100.dtsi
@@ -52,16 +52,6 @@
clock-output-names = "usb_x1";
};
- /* Special CPG clocks */
- cpg_clocks: cpg_clocks@fcfe0000 {
- #clock-cells = <1>;
- compatible = "renesas,r7s72100-cpg-clocks",
- "renesas,rz-cpg-clocks";
- reg = <0xfcfe0000 0x18>;
- clocks = <&extal_clk>, <&usb_x1_clk>;
- clock-output-names = "pll", "i", "g";
- };
-
/* Fixed factor clocks */
b_clk: b_clk {
#clock-cells = <0>;
@@ -88,6 +78,16 @@
clock-output-names = "p0";
};
+ /* Special CPG clocks */
+ cpg_clocks: cpg_clocks@fcfe0000 {
+ #clock-cells = <1>;
+ compatible = "renesas,r7s72100-cpg-clocks",
+ "renesas,rz-cpg-clocks";
+ reg = <0xfcfe0000 0x18>;
+ clocks = <&extal_clk>, <&usb_x1_clk>;
+ clock-output-names = "pll", "i", "g";
+ };
+
/* MSTP clocks */
mstp3_clks: mstp3_clks@fcfe0420 {
#clock-cells = <1>;
@@ -148,97 +148,6 @@
};
};
- gic: interrupt-controller@e8201000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- #address-cells = <0>;
- interrupt-controller;
- reg = <0xe8201000 0x1000>,
- <0xe8202000 0x1000>;
- };
-
- i2c0: i2c@fcfee000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
- reg = <0xfcfee000 0x44>;
- interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>,
- <0 158 IRQ_TYPE_EDGE_RISING>,
- <0 159 IRQ_TYPE_EDGE_RISING>,
- <0 160 IRQ_TYPE_LEVEL_HIGH>,
- <0 161 IRQ_TYPE_LEVEL_HIGH>,
- <0 162 IRQ_TYPE_LEVEL_HIGH>,
- <0 163 IRQ_TYPE_LEVEL_HIGH>,
- <0 164 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&mstp9_clks R7S72100_CLK_I2C0>;
- clock-frequency = <100000>;
- status = "disabled";
- };
-
- i2c1: i2c@fcfee400 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
- reg = <0xfcfee400 0x44>;
- interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>,
- <0 166 IRQ_TYPE_EDGE_RISING>,
- <0 167 IRQ_TYPE_EDGE_RISING>,
- <0 168 IRQ_TYPE_LEVEL_HIGH>,
- <0 169 IRQ_TYPE_LEVEL_HIGH>,
- <0 170 IRQ_TYPE_LEVEL_HIGH>,
- <0 171 IRQ_TYPE_LEVEL_HIGH>,
- <0 172 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&mstp9_clks R7S72100_CLK_I2C1>;
- clock-frequency = <100000>;
- status = "disabled";
- };
-
- i2c2: i2c@fcfee800 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
- reg = <0xfcfee800 0x44>;
- interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>,
- <0 174 IRQ_TYPE_EDGE_RISING>,
- <0 175 IRQ_TYPE_EDGE_RISING>,
- <0 176 IRQ_TYPE_LEVEL_HIGH>,
- <0 177 IRQ_TYPE_LEVEL_HIGH>,
- <0 178 IRQ_TYPE_LEVEL_HIGH>,
- <0 179 IRQ_TYPE_LEVEL_HIGH>,
- <0 180 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&mstp9_clks R7S72100_CLK_I2C2>;
- clock-frequency = <100000>;
- status = "disabled";
- };
-
- i2c3: i2c@fcfeec00 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
- reg = <0xfcfeec00 0x44>;
- interrupts = <0 181 IRQ_TYPE_LEVEL_HIGH>,
- <0 182 IRQ_TYPE_EDGE_RISING>,
- <0 183 IRQ_TYPE_EDGE_RISING>,
- <0 184 IRQ_TYPE_LEVEL_HIGH>,
- <0 185 IRQ_TYPE_LEVEL_HIGH>,
- <0 186 IRQ_TYPE_LEVEL_HIGH>,
- <0 187 IRQ_TYPE_LEVEL_HIGH>,
- <0 188 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&mstp9_clks R7S72100_CLK_I2C3>;
- clock-frequency = <100000>;
- status = "disabled";
- };
-
- mtu2: timer@fcff0000 {
- compatible = "renesas,mtu2-r7s72100", "renesas,mtu2";
- reg = <0xfcff0000 0x400>;
- interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "tgi0a";
- clocks = <&mstp3_clks R7S72100_CLK_MTU2>;
- clock-names = "fck";
- status = "disabled";
- };
-
scif0: serial@e8007000 {
compatible = "renesas,scif-r7s72100", "renesas,scif";
reg = <0xe8007000 64>;
@@ -404,4 +313,95 @@
#size-cells = <0>;
status = "disabled";
};
+
+ gic: interrupt-controller@e8201000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0xe8201000 0x1000>,
+ <0xe8202000 0x1000>;
+ };
+
+ i2c0: i2c@fcfee000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+ reg = <0xfcfee000 0x44>;
+ interrupts = <0 157 IRQ_TYPE_LEVEL_HIGH>,
+ <0 158 IRQ_TYPE_EDGE_RISING>,
+ <0 159 IRQ_TYPE_EDGE_RISING>,
+ <0 160 IRQ_TYPE_LEVEL_HIGH>,
+ <0 161 IRQ_TYPE_LEVEL_HIGH>,
+ <0 162 IRQ_TYPE_LEVEL_HIGH>,
+ <0 163 IRQ_TYPE_LEVEL_HIGH>,
+ <0 164 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R7S72100_CLK_I2C0>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@fcfee400 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+ reg = <0xfcfee400 0x44>;
+ interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>,
+ <0 166 IRQ_TYPE_EDGE_RISING>,
+ <0 167 IRQ_TYPE_EDGE_RISING>,
+ <0 168 IRQ_TYPE_LEVEL_HIGH>,
+ <0 169 IRQ_TYPE_LEVEL_HIGH>,
+ <0 170 IRQ_TYPE_LEVEL_HIGH>,
+ <0 171 IRQ_TYPE_LEVEL_HIGH>,
+ <0 172 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R7S72100_CLK_I2C1>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@fcfee800 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+ reg = <0xfcfee800 0x44>;
+ interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>,
+ <0 174 IRQ_TYPE_EDGE_RISING>,
+ <0 175 IRQ_TYPE_EDGE_RISING>,
+ <0 176 IRQ_TYPE_LEVEL_HIGH>,
+ <0 177 IRQ_TYPE_LEVEL_HIGH>,
+ <0 178 IRQ_TYPE_LEVEL_HIGH>,
+ <0 179 IRQ_TYPE_LEVEL_HIGH>,
+ <0 180 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R7S72100_CLK_I2C2>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@fcfeec00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,riic-r7s72100", "renesas,riic-rz";
+ reg = <0xfcfeec00 0x44>;
+ interrupts = <0 181 IRQ_TYPE_LEVEL_HIGH>,
+ <0 182 IRQ_TYPE_EDGE_RISING>,
+ <0 183 IRQ_TYPE_EDGE_RISING>,
+ <0 184 IRQ_TYPE_LEVEL_HIGH>,
+ <0 185 IRQ_TYPE_LEVEL_HIGH>,
+ <0 186 IRQ_TYPE_LEVEL_HIGH>,
+ <0 187 IRQ_TYPE_LEVEL_HIGH>,
+ <0 188 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp9_clks R7S72100_CLK_I2C3>;
+ clock-frequency = <100000>;
+ status = "disabled";
+ };
+
+ mtu2: timer@fcff0000 {
+ compatible = "renesas,mtu2-r7s72100", "renesas,mtu2";
+ reg = <0xfcff0000 0x400>;
+ interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "tgi0a";
+ clocks = <&mstp3_clks R7S72100_CLK_MTU2>;
+ clock-names = "fck";
+ status = "disabled";
+ };
};
diff --git a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
index a860f32..84e05f7 100644
--- a/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
+++ b/arch/arm/boot/dts/r8a73a4-ape6evm-reference.dts
@@ -21,7 +21,8 @@
};
chosen {
- bootargs = "console=ttySC0,115200 ignore_loglevel rw";
+ bootargs = "ignore_loglevel rw";
+ stdout-path = &scifa0;
};
memory@40000000 {
@@ -93,6 +94,10 @@
voltage-tolerance = <1>; /* 1% */
};
+&cmt1 {
+ status = "okay";
+};
+
&pfc {
scifa0_pins: serial0 {
renesas,groups = "scifa0_data";
diff --git a/arch/arm/boot/dts/r8a73a4.dtsi b/arch/arm/boot/dts/r8a73a4.dtsi
index ef152e3..5ac57ba 100644
--- a/arch/arm/boot/dts/r8a73a4.dtsi
+++ b/arch/arm/boot/dts/r8a73a4.dtsi
@@ -30,18 +30,6 @@
};
};
- gic: interrupt-controller@f1001000 {
- compatible = "arm,cortex-a15-gic";
- #interrupt-cells = <3>;
- #address-cells = <0>;
- interrupt-controller;
- reg = <0 0xf1001000 0 0x1000>,
- <0 0xf1002000 0 0x1000>,
- <0 0xf1004000 0 0x2000>,
- <0 0xf1006000 0 0x2000>;
- interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
- };
-
timer {
compatible = "arm,armv7-timer";
interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
@@ -50,6 +38,91 @@
<1 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
};
+ dmac: dma-multiplexer {
+ compatible = "renesas,shdma-mux";
+ #dma-cells = <1>;
+ dma-channels = <20>;
+ dma-requests = <256>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ dma0: dma-controller@e6700020 {
+ compatible = "renesas,shdma-r8a73a4";
+ reg = <0 0xe6700020 0 0x89e0>;
+ interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
+ 0 200 IRQ_TYPE_LEVEL_HIGH
+ 0 201 IRQ_TYPE_LEVEL_HIGH
+ 0 202 IRQ_TYPE_LEVEL_HIGH
+ 0 203 IRQ_TYPE_LEVEL_HIGH
+ 0 204 IRQ_TYPE_LEVEL_HIGH
+ 0 205 IRQ_TYPE_LEVEL_HIGH
+ 0 206 IRQ_TYPE_LEVEL_HIGH
+ 0 207 IRQ_TYPE_LEVEL_HIGH
+ 0 208 IRQ_TYPE_LEVEL_HIGH
+ 0 209 IRQ_TYPE_LEVEL_HIGH
+ 0 210 IRQ_TYPE_LEVEL_HIGH
+ 0 211 IRQ_TYPE_LEVEL_HIGH
+ 0 212 IRQ_TYPE_LEVEL_HIGH
+ 0 213 IRQ_TYPE_LEVEL_HIGH
+ 0 214 IRQ_TYPE_LEVEL_HIGH
+ 0 215 IRQ_TYPE_LEVEL_HIGH
+ 0 216 IRQ_TYPE_LEVEL_HIGH
+ 0 217 IRQ_TYPE_LEVEL_HIGH
+ 0 218 IRQ_TYPE_LEVEL_HIGH
+ 0 219 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12", "ch13", "ch14", "ch15",
+ "ch16", "ch17", "ch18", "ch19";
+ };
+ };
+
+ pfc: pfc@e6050000 {
+ compatible = "renesas,pfc-r8a73a4";
+ reg = <0 0xe6050000 0 0x9000>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupts-extended =
+ <&irqc0 0 0>, <&irqc0 1 0>, <&irqc0 2 0>, <&irqc0 3 0>,
+ <&irqc0 4 0>, <&irqc0 5 0>, <&irqc0 6 0>, <&irqc0 7 0>,
+ <&irqc0 8 0>, <&irqc0 9 0>, <&irqc0 10 0>, <&irqc0 11 0>,
+ <&irqc0 12 0>, <&irqc0 13 0>, <&irqc0 14 0>, <&irqc0 15 0>,
+ <&irqc0 16 0>, <&irqc0 17 0>, <&irqc0 18 0>, <&irqc0 19 0>,
+ <&irqc0 20 0>, <&irqc0 21 0>, <&irqc0 22 0>, <&irqc0 23 0>,
+ <&irqc0 24 0>, <&irqc0 25 0>, <&irqc0 26 0>, <&irqc0 27 0>,
+ <&irqc0 28 0>, <&irqc0 29 0>, <&irqc0 30 0>, <&irqc0 31 0>,
+ <&irqc1 0 0>, <&irqc1 1 0>, <&irqc1 2 0>, <&irqc1 3 0>,
+ <&irqc1 4 0>, <&irqc1 5 0>, <&irqc1 6 0>, <&irqc1 7 0>,
+ <&irqc1 8 0>, <&irqc1 9 0>, <&irqc1 10 0>, <&irqc1 11 0>,
+ <&irqc1 12 0>, <&irqc1 13 0>, <&irqc1 14 0>, <&irqc1 15 0>,
+ <&irqc1 16 0>, <&irqc1 17 0>, <&irqc1 18 0>, <&irqc1 19 0>,
+ <&irqc1 20 0>, <&irqc1 21 0>, <&irqc1 22 0>, <&irqc1 23 0>,
+ <&irqc1 24 0>, <&irqc1 25 0>;
+ };
+
+ i2c5: i2c@e60b0000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
+ reg = <0 0xe60b0000 0 0x428>;
+ interrupts = <0 179 IRQ_TYPE_LEVEL_HIGH>;
+
+ status = "disabled";
+ };
+
+ cmt1: timer@e6130000 {
+ compatible = "renesas,cmt-48-r8a73a4", "renesas,cmt-48-gen2";
+ reg = <0 0xe6130000 0 0x1004>;
+ interrupts = <0 120 IRQ_TYPE_LEVEL_HIGH>;
+
+ renesas,channels-mask = <0xff>;
+
+ status = "disabled";
+ };
+
irqc0: interrupt-controller@e61c0000 {
compatible = "renesas,irqc-r8a73a4", "renesas,irqc";
#interrupt-cells = <2>;
@@ -122,48 +195,6 @@
<0 57 IRQ_TYPE_LEVEL_HIGH>;
};
- dmac: dma-multiplexer@0 {
- compatible = "renesas,shdma-mux";
- #dma-cells = <1>;
- dma-channels = <20>;
- dma-requests = <256>;
- #address-cells = <2>;
- #size-cells = <2>;
- ranges;
-
- dma0: dma-controller@e6700020 {
- compatible = "renesas,shdma-r8a73a4";
- reg = <0 0xe6700020 0 0x89e0>;
- interrupts = <0 220 IRQ_TYPE_LEVEL_HIGH
- 0 200 IRQ_TYPE_LEVEL_HIGH
- 0 201 IRQ_TYPE_LEVEL_HIGH
- 0 202 IRQ_TYPE_LEVEL_HIGH
- 0 203 IRQ_TYPE_LEVEL_HIGH
- 0 204 IRQ_TYPE_LEVEL_HIGH
- 0 205 IRQ_TYPE_LEVEL_HIGH
- 0 206 IRQ_TYPE_LEVEL_HIGH
- 0 207 IRQ_TYPE_LEVEL_HIGH
- 0 208 IRQ_TYPE_LEVEL_HIGH
- 0 209 IRQ_TYPE_LEVEL_HIGH
- 0 210 IRQ_TYPE_LEVEL_HIGH
- 0 211 IRQ_TYPE_LEVEL_HIGH
- 0 212 IRQ_TYPE_LEVEL_HIGH
- 0 213 IRQ_TYPE_LEVEL_HIGH
- 0 214 IRQ_TYPE_LEVEL_HIGH
- 0 215 IRQ_TYPE_LEVEL_HIGH
- 0 216 IRQ_TYPE_LEVEL_HIGH
- 0 217 IRQ_TYPE_LEVEL_HIGH
- 0 218 IRQ_TYPE_LEVEL_HIGH
- 0 219 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "error",
- "ch0", "ch1", "ch2", "ch3",
- "ch4", "ch5", "ch6", "ch7",
- "ch8", "ch9", "ch10", "ch11",
- "ch12", "ch13", "ch14", "ch15",
- "ch16", "ch17", "ch18", "ch19";
- };
- };
-
thermal@e61f0000 {
compatible = "renesas,thermal-r8a73a4", "renesas,rcar-thermal";
reg = <0 0xe61f0000 0 0x14>, <0 0xe61f0100 0 0x38>,
@@ -174,7 +205,7 @@
i2c0: i2c@e6500000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6500000 0 0x428>;
interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -183,7 +214,7 @@
i2c1: i2c@e6510000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6510000 0 0x428>;
interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -192,7 +223,7 @@
i2c2: i2c@e6520000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6520000 0 0x428>;
interrupts = <0 176 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -201,7 +232,7 @@
i2c3: i2c@e6530000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6530000 0 0x428>;
interrupts = <0 177 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -210,25 +241,16 @@
i2c4: i2c@e6540000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6540000 0 0x428>;
interrupts = <0 178 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
- i2c5: i2c@e60b0000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "renesas,rmobile-iic";
- reg = <0 0xe60b0000 0 0x428>;
- interrupts = <0 179 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
i2c6: i2c@e6550000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6550000 0 0x428>;
interrupts = <0 184 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -237,7 +259,7 @@
i2c7: i2c@e6560000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6560000 0 0x428>;
interrupts = <0 185 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
@@ -246,12 +268,26 @@
i2c8: i2c@e6570000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-r8a73a4", "renesas,rmobile-iic";
reg = <0 0xe6570000 0 0x428>;
interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
+ scifb0: serial@e6c20000 {
+ compatible = "renesas,scifb-r8a73a4", "renesas,scifb";
+ reg = <0 0xe6c20000 0 0x100>;
+ interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ scifb1: serial@e6c30000 {
+ compatible = "renesas,scifb-r8a73a4", "renesas,scifb";
+ reg = <0 0xe6c30000 0 0x100>;
+ interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
scifa0: serial@e6c40000 {
compatible = "renesas,scifa-r8a73a4", "renesas,scifa";
reg = <0 0xe6c40000 0 0x100>;
@@ -266,73 +302,20 @@
status = "disabled";
};
- scifb2: serial@e6c20000 {
- compatible = "renesas,scifb-r8a73a4", "renesas,scifb";
- reg = <0 0xe6c20000 0 0x100>;
- interrupts = <0 148 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
- scifb3: serial@e6c30000 {
- compatible = "renesas,scifb-r8a73a4", "renesas,scifb";
- reg = <0 0xe6c30000 0 0x100>;
- interrupts = <0 149 IRQ_TYPE_LEVEL_HIGH>;
- status = "disabled";
- };
-
- scifb4: serial@e6ce0000 {
+ scifb2: serial@e6ce0000 {
compatible = "renesas,scifb-r8a73a4", "renesas,scifb";
reg = <0 0xe6ce0000 0 0x100>;
interrupts = <0 150 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
- scifb5: serial@e6cf0000 {
+ scifb3: serial@e6cf0000 {
compatible = "renesas,scifb-r8a73a4", "renesas,scifb";
reg = <0 0xe6cf0000 0 0x100>;
interrupts = <0 151 IRQ_TYPE_LEVEL_HIGH>;
status = "disabled";
};
- mmcif0: mmc@ee200000 {
- compatible = "renesas,sh-mmcif";
- reg = <0 0xee200000 0 0x80>;
- interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>;
- reg-io-width = <4>;
- status = "disabled";
- };
-
- mmcif1: mmc@ee220000 {
- compatible = "renesas,sh-mmcif";
- reg = <0 0xee220000 0 0x80>;
- interrupts = <0 170 IRQ_TYPE_LEVEL_HIGH>;
- reg-io-width = <4>;
- status = "disabled";
- };
-
- pfc: pfc@e6050000 {
- compatible = "renesas,pfc-r8a73a4";
- reg = <0 0xe6050000 0 0x9000>;
- gpio-controller;
- #gpio-cells = <2>;
- interrupts-extended =
- <&irqc0 0 0>, <&irqc0 1 0>, <&irqc0 2 0>, <&irqc0 3 0>,
- <&irqc0 4 0>, <&irqc0 5 0>, <&irqc0 6 0>, <&irqc0 7 0>,
- <&irqc0 8 0>, <&irqc0 9 0>, <&irqc0 10 0>, <&irqc0 11 0>,
- <&irqc0 12 0>, <&irqc0 13 0>, <&irqc0 14 0>, <&irqc0 15 0>,
- <&irqc0 16 0>, <&irqc0 17 0>, <&irqc0 18 0>, <&irqc0 19 0>,
- <&irqc0 20 0>, <&irqc0 21 0>, <&irqc0 22 0>, <&irqc0 23 0>,
- <&irqc0 24 0>, <&irqc0 25 0>, <&irqc0 26 0>, <&irqc0 27 0>,
- <&irqc0 28 0>, <&irqc0 29 0>, <&irqc0 30 0>, <&irqc0 31 0>,
- <&irqc1 0 0>, <&irqc1 1 0>, <&irqc1 2 0>, <&irqc1 3 0>,
- <&irqc1 4 0>, <&irqc1 5 0>, <&irqc1 6 0>, <&irqc1 7 0>,
- <&irqc1 8 0>, <&irqc1 9 0>, <&irqc1 10 0>, <&irqc1 11 0>,
- <&irqc1 12 0>, <&irqc1 13 0>, <&irqc1 14 0>, <&irqc1 15 0>,
- <&irqc1 16 0>, <&irqc1 17 0>, <&irqc1 18 0>, <&irqc1 19 0>,
- <&irqc1 20 0>, <&irqc1 21 0>, <&irqc1 22 0>, <&irqc1 23 0>,
- <&irqc1 24 0>, <&irqc1 25 0>;
- };
-
sdhi0: sd@ee100000 {
compatible = "renesas,sdhi-r8a73a4";
reg = <0 0xee100000 0 0x100>;
@@ -356,4 +339,32 @@
cap-sd-highspeed;
status = "disabled";
};
+
+ mmcif0: mmc@ee200000 {
+ compatible = "renesas,sh-mmcif";
+ reg = <0 0xee200000 0 0x80>;
+ interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ mmcif1: mmc@ee220000 {
+ compatible = "renesas,sh-mmcif";
+ reg = <0 0xee220000 0 0x80>;
+ interrupts = <0 170 IRQ_TYPE_LEVEL_HIGH>;
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
+ gic: interrupt-controller@f1001000 {
+ compatible = "arm,cortex-a15-gic";
+ #interrupt-cells = <3>;
+ #address-cells = <0>;
+ interrupt-controller;
+ reg = <0 0xf1001000 0 0x1000>,
+ <0 0xf1002000 0 0x1000>,
+ <0 0xf1004000 0 0x2000>,
+ <0 0xf1006000 0 0x2000>;
+ interrupts = <1 9 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
};
diff --git a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
index effb7b4..d4af4d8 100644
--- a/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
+++ b/arch/arm/boot/dts/r8a7740-armadillo800eva.dts
@@ -25,6 +25,7 @@
chosen {
bootargs = "console=tty0 console=ttySC1,115200 earlyprintk=sh-sci.1,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw";
+ stdout-path = &scifa1;
};
memory {
@@ -77,7 +78,7 @@
regulator-boot-on;
};
- gpio-keys {
+ keyboard {
compatible = "gpio-keys";
power-key {
@@ -298,3 +299,7 @@
status = "okay";
};
+
+&tmu0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/r8a7740.dtsi b/arch/arm/boot/dts/r8a7740.dtsi
index eed697a..a8a674b 100644
--- a/arch/arm/boot/dts/r8a7740.dtsi
+++ b/arch/arm/boot/dts/r8a7740.dtsi
@@ -71,6 +71,7 @@
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
};
/* irqpin1: IRQ8 - IRQ15 */
@@ -91,6 +92,7 @@
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
};
/* irqpin2: IRQ16 - IRQ23 */
@@ -111,6 +113,7 @@
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
};
/* irqpin3: IRQ24 - IRQ31 */
@@ -131,6 +134,7 @@
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH
0 149 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp2_clks R8A7740_CLK_INTCA>;
};
ether: ethernet@e9a00000 {
@@ -193,7 +197,7 @@
compatible = "renesas,scifa-r8a7740", "renesas,scifa";
reg = <0xe6c60000 0x100>;
interrupts = <0 102 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&mstp2_clks R8A7740_CLK_SCIFA0>;
+ clocks = <&mstp2_clks R8A7740_CLK_SCIFA2>;
clock-names = "sci_ick";
status = "disabled";
};
@@ -331,6 +335,34 @@
status = "disabled";
};
+ tmu0: timer@fff80000 {
+ compatible = "renesas,tmu-r8a7740", "renesas,tmu";
+ reg = <0xfff80000 0x2c>;
+ interrupts = <0 198 IRQ_TYPE_LEVEL_HIGH>,
+ <0 199 IRQ_TYPE_LEVEL_HIGH>,
+ <0 200 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7740_CLK_TMU0>;
+ clock-names = "fck";
+
+ #renesas,channels = <3>;
+
+ status = "disabled";
+ };
+
+ tmu1: timer@fff90000 {
+ compatible = "renesas,tmu-r8a7740", "renesas,tmu";
+ reg = <0xfff90000 0x2c>;
+ interrupts = <0 170 IRQ_TYPE_LEVEL_HIGH>,
+ <0 171 IRQ_TYPE_LEVEL_HIGH>,
+ <0 172 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7740_CLK_TMU1>;
+ clock-names = "fck";
+
+ #renesas,channels = <3>;
+
+ status = "disabled";
+ };
+
clocks {
#address-cells = <1>;
#size-cells = <1>;
@@ -448,8 +480,8 @@
mstp2_clks: mstp2_clks@e6150138 {
compatible = "renesas,r8a7740-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0xe6150138 4>, <0xe6150040 4>;
- clocks = <&sub_clk>, <&sub_clk>,
- <&cpg_clocks R8A7740_CLK_HP>,
+ clocks = <&sub_clk>, <&cpg_clocks R8A7740_CLK_HP>,
+ <&sub_clk>, <&cpg_clocks R8A7740_CLK_HP>,
<&cpg_clocks R8A7740_CLK_HP>,
<&cpg_clocks R8A7740_CLK_HP>,
<&cpg_clocks R8A7740_CLK_HP>,
@@ -458,7 +490,8 @@
<&sub_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
- R8A7740_CLK_SCIFA6 R8A7740_CLK_SCIFA7
+ R8A7740_CLK_SCIFA6 R8A7740_CLK_INTCA
+ R8A7740_CLK_SCIFA7
R8A7740_CLK_DMAC1 R8A7740_CLK_DMAC2
R8A7740_CLK_DMAC3 R8A7740_CLK_USBDMAC
R8A7740_CLK_SCIFA5 R8A7740_CLK_SCIFB
@@ -467,7 +500,8 @@
R8A7740_CLK_SCIFA4
>;
clock-output-names =
- "scifa6", "scifa7", "dmac1", "dmac2", "dmac3",
+ "scifa6", "intca",
+ "scifa7", "dmac1", "dmac2", "dmac3",
"usbdmac", "scifa5", "scifb", "scifa0", "scifa1",
"scifa2", "scifa3", "scifa4";
};
diff --git a/arch/arm/boot/dts/r8a7778-bockw-reference.dts b/arch/arm/boot/dts/r8a7778-bockw-reference.dts
index 3342c74..04c0c37 100644
--- a/arch/arm/boot/dts/r8a7778-bockw-reference.dts
+++ b/arch/arm/boot/dts/r8a7778-bockw-reference.dts
@@ -28,7 +28,8 @@
};
chosen {
- bootargs = "console=ttySC0,115200 ignore_loglevel root=/dev/nfs ip=dhcp rw";
+ bootargs = "ignore_loglevel root=/dev/nfs ip=dhcp rw";
+ stdout-path = &scif0;
};
memory {
@@ -73,6 +74,10 @@
status = "okay";
};
+&tmu0 {
+ status = "okay";
+};
+
&pfc {
scif0_pins: serial0 {
renesas,groups = "scif0_data_a", "scif0_ctrl";
diff --git a/arch/arm/boot/dts/r8a7778.dtsi b/arch/arm/boot/dts/r8a7778.dtsi
index 315ec62..ef85339 100644
--- a/arch/arm/boot/dts/r8a7778.dtsi
+++ b/arch/arm/boot/dts/r8a7778.dtsi
@@ -162,6 +162,42 @@
status = "disabled";
};
+ tmu0: timer@ffd80000 {
+ compatible = "renesas,tmu-r8a7778", "renesas,tmu";
+ reg = <0xffd80000 0x30>;
+ interrupts = <0 32 IRQ_TYPE_LEVEL_HIGH>,
+ <0 33 IRQ_TYPE_LEVEL_HIGH>,
+ <0 34 IRQ_TYPE_LEVEL_HIGH>;
+
+ #renesas,channels = <3>;
+
+ status = "disabled";
+ };
+
+ tmu1: timer@ffd81000 {
+ compatible = "renesas,tmu-r8a7778", "renesas,tmu";
+ reg = <0xffd81000 0x30>;
+ interrupts = <0 36 IRQ_TYPE_LEVEL_HIGH>,
+ <0 37 IRQ_TYPE_LEVEL_HIGH>,
+ <0 38 IRQ_TYPE_LEVEL_HIGH>;
+
+ #renesas,channels = <3>;
+
+ status = "disabled";
+ };
+
+ tmu2: timer@ffd82000 {
+ compatible = "renesas,tmu-r8a7778", "renesas,tmu";
+ reg = <0xffd82000 0x30>;
+ interrupts = <0 40 IRQ_TYPE_LEVEL_HIGH>,
+ <0 41 IRQ_TYPE_LEVEL_HIGH>,
+ <0 42 IRQ_TYPE_LEVEL_HIGH>;
+
+ #renesas,channels = <3>;
+
+ status = "disabled";
+ };
+
scif0: serial@ffe40000 {
compatible = "renesas,scif-r8a7778", "renesas,scif";
reg = <0xffe40000 0x100>;
@@ -215,8 +251,6 @@
compatible = "renesas,sdhi-r8a7778";
reg = <0xffe4c000 0x100>;
interrupts = <0 87 IRQ_TYPE_LEVEL_HIGH>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
@@ -224,8 +258,6 @@
compatible = "renesas,sdhi-r8a7778";
reg = <0xffe4d000 0x100>;
interrupts = <0 88 IRQ_TYPE_LEVEL_HIGH>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
@@ -233,8 +265,6 @@
compatible = "renesas,sdhi-r8a7778";
reg = <0xffe4f000 0x100>;
interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/r8a7779-marzen.dts b/arch/arm/boot/dts/r8a7779-marzen.dts
index c160404..e83d40e 100644
--- a/arch/arm/boot/dts/r8a7779-marzen.dts
+++ b/arch/arm/boot/dts/r8a7779-marzen.dts
@@ -25,6 +25,7 @@
chosen {
bootargs = "console=ttySC2,115200 ignore_loglevel root=/dev/nfs ip=on";
+ stdout-path = &scif2;
};
memory {
@@ -68,6 +69,78 @@
gpios = <&gpio4 31 GPIO_ACTIVE_HIGH>;
};
};
+
+ vga-encoder {
+ compatible = "adi,adv7123";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ vga_enc_in: endpoint {
+ remote-endpoint = <&du_out_rgb0>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ vga_enc_out: endpoint {
+ remote-endpoint = <&vga_in>;
+ };
+ };
+ };
+ };
+
+ vga {
+ compatible = "vga-connector";
+
+ port {
+ vga_in: endpoint {
+ remote-endpoint = <&vga_enc_out>;
+ };
+ };
+ };
+
+ lvds-encoder {
+ compatible = "thine,thc63lvdm83d";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ lvds_enc_in: endpoint {
+ remote-endpoint = <&du_out_rgb1>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ lvds_connector: endpoint {
+ };
+ };
+ };
+ };
+};
+
+&du {
+ pinctrl-0 = <&du_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ ports {
+ port@0 {
+ endpoint {
+ remote-endpoint = <&vga_enc_in>;
+ };
+ };
+ port@1 {
+ endpoint {
+ remote-endpoint = <&lvds_enc_in>;
+ };
+ };
+ };
};
&irqpin0 {
@@ -83,6 +156,17 @@
};
&pfc {
+ du_pins: du {
+ du0 {
+ renesas,groups = "du0_rgb888", "du0_sync_1", "du0_clk_out_0";
+ renesas,function = "du0";
+ };
+ du1 {
+ renesas,groups = "du1_rgb666", "du1_sync_1", "du1_clk_out";
+ renesas,function = "du1";
+ };
+ };
+
lan0_pins: lan0 {
intc {
renesas,groups = "intc_irq1_b";
diff --git a/arch/arm/boot/dts/r8a7779.dtsi b/arch/arm/boot/dts/r8a7779.dtsi
index 7cfba9a..ede9a29 100644
--- a/arch/arm/boot/dts/r8a7779.dtsi
+++ b/arch/arm/boot/dts/r8a7779.dtsi
@@ -303,7 +303,7 @@
};
sata: sata@fc600000 {
- compatible = "renesas,rcar-sata";
+ compatible = "renesas,sata-r8a7779", "renesas,rcar-sata";
reg = <0xfc600000 0x2000>;
interrupts = <0 100 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp1_clks R8A7779_CLK_SATA>;
@@ -314,8 +314,6 @@
reg = <0xffe4c000 0x100>;
interrupts = <0 104 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7779_CLK_SDHI0>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
@@ -324,8 +322,6 @@
reg = <0xffe4d000 0x100>;
interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7779_CLK_SDHI1>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
@@ -334,8 +330,6 @@
reg = <0xffe4e000 0x100>;
interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7779_CLK_SDHI2>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
@@ -344,8 +338,6 @@
reg = <0xffe4f000 0x100>;
interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7779_CLK_SDHI3>;
- cap-sd-highspeed;
- cap-sdio-irq;
status = "disabled";
};
@@ -379,6 +371,30 @@
status = "disabled";
};
+ du: display@fff80000 {
+ compatible = "renesas,du-r8a7779";
+ reg = <0 0xfff80000 0 0x40000>;
+ interrupts = <0 31 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7779_CLK_DU>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb0: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_rgb1: endpoint {
+ };
+ };
+ };
+ };
+
clocks {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/r8a7790-lager.dts b/arch/arm/boot/dts/r8a7790-lager.dts
index 69098b9..636d53b 100644
--- a/arch/arm/boot/dts/r8a7790-lager.dts
+++ b/arch/arm/boot/dts/r8a7790-lager.dts
@@ -9,6 +9,34 @@
* kind, whether express or implied.
*/
+/*
+ * SSI-AK4643
+ *
+ * SW1: 1: AK4643
+ * 2: CN22
+ * 3: ADV7511
+ *
+ * This command is required when Playback/Capture
+ *
+ * amixer set "LINEOUT Mixer DACL" on
+ * amixer set "DVC Out" 100%
+ * amixer set "DVC In" 100%
+ *
+ * You can use Mute
+ *
+ * amixer set "DVC Out Mute" on
+ * amixer set "DVC In Mute" on
+ *
+ * You can use Volume Ramp
+ *
+ * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps"
+ * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
+ * amixer set "DVC Out Ramp" on
+ * aplay xxx.wav &
+ * amixer set "DVC Out" 80% // Volume Down
+ * amixer set "DVC Out" 100% // Volume Up
+ */
+
/dts-v1/;
#include "r8a7790.dtsi"
#include <dt-bindings/gpio/gpio.h>
@@ -19,12 +47,13 @@
compatible = "renesas,lager", "renesas,r8a7790";
aliases {
- serial6 = &scif0;
- serial7 = &scif1;
+ serial6 = &scifa0;
+ serial7 = &scifa1;
};
chosen {
bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = &scifa0;
};
memory@40000000 {
@@ -42,7 +71,7 @@
#size-cells = <1>;
};
- gpio_keys {
+ keyboard {
compatible = "gpio-keys";
button@1 {
@@ -144,6 +173,73 @@
states = <3300000 1
1800000 0>;
};
+
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcodec>;
+ simple-audio-card,frame-master = <&sndcodec>;
+
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4643>;
+ system-clock-frequency = <11289600>;
+ };
+ };
+
+ vga-encoder {
+ compatible = "adi,adv7123";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ adv7123_in: endpoint {
+ remote-endpoint = <&du_out_rgb>;
+ };
+ };
+ port@1 {
+ reg = <1>;
+ adv7123_out: endpoint {
+ remote-endpoint = <&vga_in>;
+ };
+ };
+ };
+ };
+
+ vga {
+ compatible = "vga-connector";
+
+ port {
+ vga_in: endpoint {
+ remote-endpoint = <&adv7123_out>;
+ };
+ };
+ };
+};
+
+&du {
+ pinctrl-0 = <&du_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ ports {
+ port@0 {
+ endpoint {
+ remote-endpoint = <&adv7123_in>;
+ };
+ };
+ port@2 {
+ lvds_connector: endpoint {
+ };
+ };
+ };
};
&extal_clk {
@@ -151,17 +247,14 @@
};
&pfc {
- pinctrl-0 = <&du_pins>;
- pinctrl-names = "default";
-
du_pins: du {
renesas,groups = "du_rgb666", "du_sync_1", "du_clk_out_0";
renesas,function = "du";
};
- scif0_pins: serial0 {
- renesas,groups = "scif0_data";
- renesas,function = "scif0";
+ scifa0_pins: serial0 {
+ renesas,groups = "scifa0_data";
+ renesas,function = "scifa0";
};
ether_pins: ether {
@@ -174,9 +267,9 @@
renesas,function = "intc";
};
- scif1_pins: serial1 {
- renesas,groups = "scif1_data";
- renesas,function = "scif1";
+ scifa1_pins: serial1 {
+ renesas,groups = "scifa1_data";
+ renesas,function = "scifa1";
};
sdhi0_pins: sd0 {
@@ -220,6 +313,11 @@
renesas,function = "iic3";
};
+ hsusb_pins: hsusb {
+ renesas,groups = "usb0_ovc_vbus";
+ renesas,function = "usb0";
+ };
+
usb0_pins: usb0 {
renesas,groups = "usb0";
renesas,function = "usb0";
@@ -239,6 +337,16 @@
renesas,groups = "vin1_data8", "vin1_clk";
renesas,function = "vin1";
};
+
+ sound_pins: sound {
+ renesas,groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data";
+ renesas,function = "ssi";
+ };
+
+ sound_clk_pins: sound_clk {
+ renesas,groups = "audio_clk_a";
+ renesas,function = "audio_clk";
+ };
};
&ether {
@@ -308,15 +416,15 @@
};
};
-&scif0 {
- pinctrl-0 = <&scif0_pins>;
+&scifa0 {
+ pinctrl-0 = <&scifa0_pins>;
pinctrl-names = "default";
status = "okay";
};
-&scif1 {
- pinctrl-0 = <&scif1_pins>;
+&scifa1 {
+ pinctrl-0 = <&scifa1_pins>;
pinctrl-names = "default";
status = "okay";
@@ -376,6 +484,14 @@
pinctrl-0 = <&iic2_pins>;
pinctrl-names = "default";
+ clock-frequency = <100000>;
+
+ ak4643: sound-codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
+
composite-in@20 {
compatible = "adi,adv7180";
reg = <0x20>;
@@ -418,12 +534,29 @@
pinctrl-names = "default";
};
+&xhci {
+ status = "okay";
+ pinctrl-0 = <&usb2_pins>;
+ pinctrl-names = "default";
+};
+
&pci2 {
status = "okay";
pinctrl-0 = <&usb2_pins>;
pinctrl-names = "default";
};
+&hsusb {
+ status = "okay";
+ pinctrl-0 = <&hsusb_pins>;
+ pinctrl-names = "default";
+ renesas,enable-gpio = <&gpio5 18 GPIO_ACTIVE_HIGH>;
+};
+
+&usbphy {
+ status = "okay";
+};
+
/* composite video input */
&vin1 {
pinctrl-0 = <&vin1_pins>;
@@ -441,3 +574,23 @@
};
};
};
+
+&rcar_sound {
+ pinctrl-0 = <&sound_pins &sound_clk_pins>;
+ pinctrl-names = "default";
+
+ #sound-dai-cells = <0>;
+
+ status = "okay";
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0 &src2 &dvc0>;
+ capture = <&ssi1 &src3 &dvc1>;
+ };
+ };
+};
+
+&ssi1 {
+ shared-pin;
+};
diff --git a/arch/arm/boot/dts/r8a7790.dtsi b/arch/arm/boot/dts/r8a7790.dtsi
index e20affe..af7e255 100644
--- a/arch/arm/boot/dts/r8a7790.dtsi
+++ b/arch/arm/boot/dts/r8a7790.dtsi
@@ -312,6 +312,70 @@
#dma-cells = <1>;
dma-channels = <15>;
};
+
+ audma0: dma-controller@ec700000 {
+ compatible = "renesas,rcar-dmac";
+ reg = <0 0xec700000 0 0x10000>;
+ interrupts = <0 346 IRQ_TYPE_LEVEL_HIGH
+ 0 320 IRQ_TYPE_LEVEL_HIGH
+ 0 321 IRQ_TYPE_LEVEL_HIGH
+ 0 322 IRQ_TYPE_LEVEL_HIGH
+ 0 323 IRQ_TYPE_LEVEL_HIGH
+ 0 324 IRQ_TYPE_LEVEL_HIGH
+ 0 325 IRQ_TYPE_LEVEL_HIGH
+ 0 326 IRQ_TYPE_LEVEL_HIGH
+ 0 327 IRQ_TYPE_LEVEL_HIGH
+ 0 328 IRQ_TYPE_LEVEL_HIGH
+ 0 329 IRQ_TYPE_LEVEL_HIGH
+ 0 330 IRQ_TYPE_LEVEL_HIGH
+ 0 331 IRQ_TYPE_LEVEL_HIGH
+ 0 332 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12";
+ clocks = <&mstp5_clks R8A7790_CLK_AUDIO_DMAC0>;
+ clock-names = "fck";
+ #dma-cells = <1>;
+ dma-channels = <13>;
+ };
+
+ audma1: dma-controller@ec720000 {
+ compatible = "renesas,rcar-dmac";
+ reg = <0 0xec720000 0 0x10000>;
+ interrupts = <0 347 IRQ_TYPE_LEVEL_HIGH
+ 0 333 IRQ_TYPE_LEVEL_HIGH
+ 0 334 IRQ_TYPE_LEVEL_HIGH
+ 0 335 IRQ_TYPE_LEVEL_HIGH
+ 0 336 IRQ_TYPE_LEVEL_HIGH
+ 0 337 IRQ_TYPE_LEVEL_HIGH
+ 0 338 IRQ_TYPE_LEVEL_HIGH
+ 0 339 IRQ_TYPE_LEVEL_HIGH
+ 0 340 IRQ_TYPE_LEVEL_HIGH
+ 0 341 IRQ_TYPE_LEVEL_HIGH
+ 0 342 IRQ_TYPE_LEVEL_HIGH
+ 0 343 IRQ_TYPE_LEVEL_HIGH
+ 0 344 IRQ_TYPE_LEVEL_HIGH
+ 0 345 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12";
+ clocks = <&mstp5_clks R8A7790_CLK_AUDIO_DMAC1>;
+ clock-names = "fck";
+ #dma-cells = <1>;
+ dma-channels = <13>;
+ };
+
+ audmapp: dma-controller@ec740000 {
+ compatible = "renesas,rcar-audmapp";
+ #dma-cells = <1>;
+
+ reg = <0 0xec740000 0 0x200>;
+ };
+
i2c0: i2c@e6508000 {
#address-cells = <1>;
#size-cells = <0>;
@@ -359,6 +423,8 @@
reg = <0 0xe6500000 0 0x425>;
interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_IIC0>;
+ dmas = <&dmac0 0x61>, <&dmac0 0x62>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -369,6 +435,8 @@
reg = <0 0xe6510000 0 0x425>;
interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_IIC1>;
+ dmas = <&dmac0 0x65>, <&dmac0 0x66>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -379,6 +447,8 @@
reg = <0 0xe6520000 0 0x425>;
interrupts = <0 176 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_IIC2>;
+ dmas = <&dmac0 0x69>, <&dmac0 0x6a>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -389,14 +459,18 @@
reg = <0 0xe60b0000 0 0x425>;
interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7790_CLK_IICDVFS>;
+ dmas = <&dmac0 0x77>, <&dmac0 0x78>;
+ dma-names = "tx", "rx";
status = "disabled";
};
- mmcif0: mmcif@ee200000 {
+ mmcif0: mmc@ee200000 {
compatible = "renesas,mmcif-r8a7790", "renesas,sh-mmcif";
reg = <0 0xee200000 0 0x80>;
interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_MMCIF0>;
+ dmas = <&dmac0 0xd1>, <&dmac0 0xd2>;
+ dma-names = "tx", "rx";
reg-io-width = <4>;
status = "disabled";
};
@@ -406,6 +480,8 @@
reg = <0 0xee220000 0 0x80>;
interrupts = <0 170 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_MMCIF1>;
+ dmas = <&dmac0 0xe1>, <&dmac0 0xe2>;
+ dma-names = "tx", "rx";
reg-io-width = <4>;
status = "disabled";
};
@@ -420,7 +496,6 @@
reg = <0 0xee100000 0 0x200>;
interrupts = <0 165 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_SDHI0>;
- cap-sd-highspeed;
status = "disabled";
};
@@ -429,7 +504,6 @@
reg = <0 0xee120000 0 0x200>;
interrupts = <0 166 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_SDHI1>;
- cap-sd-highspeed;
status = "disabled";
};
@@ -438,7 +512,6 @@
reg = <0 0xee140000 0 0x100>;
interrupts = <0 167 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_SDHI2>;
- cap-sd-highspeed;
status = "disabled";
};
@@ -447,7 +520,6 @@
reg = <0 0xee160000 0 0x100>;
interrupts = <0 168 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7790_CLK_SDHI3>;
- cap-sd-highspeed;
status = "disabled";
};
@@ -568,6 +640,36 @@
status = "disabled";
};
+ hsusb: usb@e6590000 {
+ compatible = "renesas,usbhs-r8a7790";
+ reg = <0 0xe6590000 0 0x100>;
+ interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7790_CLK_HSUSB>;
+ renesas,buswait = <4>;
+ phys = <&usb0 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ usbphy: usb-phy@e6590100 {
+ compatible = "renesas,usb-phy-r8a7790";
+ reg = <0 0xe6590100 0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mstp7_clks R8A7790_CLK_HSUSB>;
+ clock-names = "usbhs";
+ status = "disabled";
+
+ usb0: usb-channel@0 {
+ reg = <0>;
+ #phy-cells = <1>;
+ };
+ usb2: usb-channel@2 {
+ reg = <2>;
+ #phy-cells = <1>;
+ };
+ };
+
vin0: video@e6ef0000 {
compatible = "renesas,vin-r8a7790";
clocks = <&mstp8_clks R8A7790_CLK_VIN0>;
@@ -600,6 +702,96 @@
status = "disabled";
};
+ vsp1@fe920000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe920000 0 0x8000>;
+ interrupts = <0 266 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7790_CLK_VSP1_R>;
+
+ renesas,has-sru;
+ renesas,#rpf = <5>;
+ renesas,#uds = <1>;
+ renesas,#wpf = <4>;
+ };
+
+ vsp1@fe928000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe928000 0 0x8000>;
+ interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7790_CLK_VSP1_S>;
+
+ renesas,has-lut;
+ renesas,has-sru;
+ renesas,#rpf = <5>;
+ renesas,#uds = <3>;
+ renesas,#wpf = <4>;
+ };
+
+ vsp1@fe930000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe930000 0 0x8000>;
+ interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU0>;
+
+ renesas,has-lif;
+ renesas,has-lut;
+ renesas,#rpf = <4>;
+ renesas,#uds = <1>;
+ renesas,#wpf = <4>;
+ };
+
+ vsp1@fe938000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe938000 0 0x8000>;
+ interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7790_CLK_VSP1_DU1>;
+
+ renesas,has-lif;
+ renesas,has-lut;
+ renesas,#rpf = <4>;
+ renesas,#uds = <1>;
+ renesas,#wpf = <4>;
+ };
+
+ du: display@feb00000 {
+ compatible = "renesas,du-r8a7790";
+ reg = <0 0xfeb00000 0 0x70000>,
+ <0 0xfeb90000 0 0x1c>,
+ <0 0xfeb94000 0 0x1c>;
+ reg-names = "du", "lvds.0", "lvds.1";
+ interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+ <0 268 IRQ_TYPE_LEVEL_HIGH>,
+ <0 269 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7790_CLK_DU0>,
+ <&mstp7_clks R8A7790_CLK_DU1>,
+ <&mstp7_clks R8A7790_CLK_DU2>,
+ <&mstp7_clks R8A7790_CLK_LVDS0>,
+ <&mstp7_clks R8A7790_CLK_LVDS1>;
+ clock-names = "du.0", "du.1", "du.2", "lvds.0", "lvds.1";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_lvds0: endpoint {
+ };
+ };
+ port@2 {
+ reg = <2>;
+ du_out_lvds1: endpoint {
+ };
+ };
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -868,18 +1060,25 @@
mstp1_clks: mstp1_clks@e6150134 {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150134 0 4>, <0 0xe6150038 0 4>;
- clocks = <&m2_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>,
- <&cp_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>,
- <&zs_clk>;
+ clocks = <&zs_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>, <&m2_clk>,
+ <&zs_clk>, <&p_clk>, <&zg_clk>, <&zs_clk>, <&zs_clk>,
+ <&zs_clk>, <&zs_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>,
+ <&cp_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
- R8A7790_CLK_JPU R8A7790_CLK_TMU1 R8A7790_CLK_TMU3 R8A7790_CLK_TMU2
- R8A7790_CLK_CMT0 R8A7790_CLK_TMU0 R8A7790_CLK_VSP1_DU1
- R8A7790_CLK_VSP1_DU0 R8A7790_CLK_VSP1_R R8A7790_CLK_VSP1_S
+ R8A7790_CLK_VCP1 R8A7790_CLK_VCP0 R8A7790_CLK_VPC1
+ R8A7790_CLK_VPC0 R8A7790_CLK_JPU R8A7790_CLK_SSP1
+ R8A7790_CLK_TMU1 R8A7790_CLK_3DG R8A7790_CLK_2DDMAC
+ R8A7790_CLK_FDP1_2 R8A7790_CLK_FDP1_1 R8A7790_CLK_FDP1_0
+ R8A7790_CLK_TMU3 R8A7790_CLK_TMU2 R8A7790_CLK_CMT0
+ R8A7790_CLK_TMU0 R8A7790_CLK_VSP1_DU1 R8A7790_CLK_VSP1_DU0
+ R8A7790_CLK_VSP1_R R8A7790_CLK_VSP1_S
>;
clock-output-names =
- "jpu", "tmu1", "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1",
- "vsp1-du0", "vsp1-rt", "vsp1-sy";
+ "vcp1", "vcp0", "vpc1", "vpc0", "jpu", "ssp1",
+ "tmu1", "3dg", "2ddmac", "fdp1-2", "fdp1-1",
+ "fdp1-0", "tmu3", "tmu2", "cmt0", "tmu0",
+ "vsp1-du1", "vsp1-du0", "vsp1-rt", "vsp1-sy";
};
mstp2_clks: mstp2_clks@e6150138 {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -904,25 +1103,29 @@
reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
clocks = <&hp_clk>, <&cp_clk>, <&mmc1_clk>, <&sd3_clk>,
<&sd2_clk>, <&cpg_clocks R8A7790_CLK_SD1>, <&cpg_clocks R8A7790_CLK_SD0>, <&mmc0_clk>,
- <&hp_clk>, <&mp_clk>, <&hp_clk>, <&mp_clk>, <&rclk_clk>;
+ <&hp_clk>, <&mp_clk>, <&hp_clk>, <&mp_clk>, <&rclk_clk>,
+ <&hp_clk>, <&hp_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
R8A7790_CLK_IIC2 R8A7790_CLK_TPU0 R8A7790_CLK_MMCIF1 R8A7790_CLK_SDHI3
R8A7790_CLK_SDHI2 R8A7790_CLK_SDHI1 R8A7790_CLK_SDHI0 R8A7790_CLK_MMCIF0
R8A7790_CLK_IIC0 R8A7790_CLK_PCIEC R8A7790_CLK_IIC1 R8A7790_CLK_SSUSB R8A7790_CLK_CMT1
+ R8A7790_CLK_USBDMAC0 R8A7790_CLK_USBDMAC1
>;
clock-output-names =
"iic2", "tpu0", "mmcif1", "sdhi3",
"sdhi2", "sdhi1", "sdhi0", "mmcif0",
- "iic0", "pciec", "iic1", "ssusb", "cmt1";
+ "iic0", "pciec", "iic1", "ssusb", "cmt1",
+ "usbdmac0", "usbdmac1";
};
mstp5_clks: mstp5_clks@e6150144 {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
- clocks = <&extal_clk>, <&p_clk>;
+ clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>;
#clock-cells = <1>;
- renesas,clock-indices = <R8A7790_CLK_THERMAL R8A7790_CLK_PWM>;
- clock-output-names = "thermal", "pwm";
+ renesas,clock-indices = <R8A7790_CLK_AUDIO_DMAC0 R8A7790_CLK_AUDIO_DMAC1
+ R8A7790_CLK_THERMAL R8A7790_CLK_PWM>;
+ clock-output-names = "audmac0", "audmac1", "thermal", "pwm";
};
mstp7_clks: mstp7_clks@e615014c {
compatible = "renesas,r8a7790-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -1070,6 +1273,16 @@
status = "disabled";
};
+ xhci: usb@ee000000 {
+ compatible = "renesas,xhci-r8a7790";
+ reg = <0 0xee000000 0 0xc00>;
+ interrupts = <0 101 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp3_clks R8A7790_CLK_SSUSB>;
+ phys = <&usb2 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
pci0: pci@ee090000 {
compatible = "renesas,pci-r8a7790";
device_type = "pci";
@@ -1088,6 +1301,20 @@
interrupt-map = <0x0000 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x1000 0 0 2 &gic 0 108 IRQ_TYPE_LEVEL_HIGH>;
+
+ usb@0,1 {
+ reg = <0x800 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb0 0>;
+ phy-names = "usb";
+ };
+
+ usb@0,2 {
+ reg = <0x1000 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb0 0>;
+ phy-names = "usb";
+ };
};
pci1: pci@ee0b0000 {
@@ -1128,6 +1355,20 @@
interrupt-map = <0x0000 0 0 1 &gic 0 113 IRQ_TYPE_LEVEL_HIGH
0x0800 0 0 1 &gic 0 113 IRQ_TYPE_LEVEL_HIGH
0x1000 0 0 2 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+
+ usb@0,1 {
+ reg = <0x800 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb2 0>;
+ phy-names = "usb";
+ };
+
+ usb@0,2 {
+ reg = <0x1000 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb2 0>;
+ phy-names = "usb";
+ };
};
pciec: pcie@fe000000 {
@@ -1155,7 +1396,7 @@
status = "disabled";
};
- rcar_sound: rcar_sound@0xec500000 {
+ rcar_sound: rcar_sound@ec500000 {
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-r8a7790", "renesas,rcar_sound-gen2", "renesas,rcar_sound";
reg = <0 0xec500000 0 0x1000>, /* SCU */
diff --git a/arch/arm/boot/dts/r8a7791-henninger.dts b/arch/arm/boot/dts/r8a7791-henninger.dts
index f1b56de1..740e386 100644
--- a/arch/arm/boot/dts/r8a7791-henninger.dts
+++ b/arch/arm/boot/dts/r8a7791-henninger.dts
@@ -23,6 +23,7 @@
chosen {
bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = &scif0;
};
memory@40000000 {
@@ -271,6 +272,17 @@
pinctrl-names = "default";
};
+&hsusb {
+ status = "okay";
+ pinctrl-0 = <&usb0_pins>;
+ pinctrl-names = "default";
+ renesas,enable-gpio = <&gpio5 31 GPIO_ACTIVE_HIGH>;
+};
+
+&usbphy {
+ status = "okay";
+};
+
&pcie_bus_clk {
status = "okay";
};
diff --git a/arch/arm/boot/dts/r8a7791-koelsch.dts b/arch/arm/boot/dts/r8a7791-koelsch.dts
index 07550e7..990af16 100644
--- a/arch/arm/boot/dts/r8a7791-koelsch.dts
+++ b/arch/arm/boot/dts/r8a7791-koelsch.dts
@@ -10,6 +10,34 @@
* kind, whether express or implied.
*/
+/*
+ * SSI-AK4643
+ *
+ * SW1: 1: AK4643
+ * 2: CN22
+ * 3: ADV7511
+ *
+ * This command is required when Playback/Capture
+ *
+ * amixer set "LINEOUT Mixer DACL" on
+ * amixer set "DVC Out" 100%
+ * amixer set "DVC In" 100%
+ *
+ * You can use Mute
+ *
+ * amixer set "DVC Out Mute" on
+ * amixer set "DVC In Mute" on
+ *
+ * You can use Volume Ramp
+ *
+ * amixer set "DVC Out Ramp Up Rate" "0.125 dB/64 steps"
+ * amixer set "DVC Out Ramp Down Rate" "0.125 dB/512 steps"
+ * amixer set "DVC Out Ramp" on
+ * aplay xxx.wav &
+ * amixer set "DVC Out" 80% // Volume Down
+ * amixer set "DVC Out" 100% // Volume Up
+ */
+
/dts-v1/;
#include "r8a7791.dtsi"
#include <dt-bindings/gpio/gpio.h>
@@ -25,7 +53,8 @@
};
chosen {
- bootargs = "console=ttySC6,115200 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = &scif0;
};
memory@40000000 {
@@ -43,7 +72,7 @@
#size-cells = <1>;
};
- gpio-keys {
+ keyboard {
compatible = "gpio-keys";
key-1 {
@@ -129,12 +158,15 @@
compatible = "gpio-leds";
led6 {
gpios = <&gpio2 19 GPIO_ACTIVE_HIGH>;
+ label = "LED6";
};
led7 {
gpios = <&gpio2 20 GPIO_ACTIVE_HIGH>;
+ label = "LED7";
};
led8 {
gpios = <&gpio2 21 GPIO_ACTIVE_HIGH>;
+ label = "LED8";
};
};
@@ -209,6 +241,36 @@
states = <3300000 1
1800000 0>;
};
+
+ sound {
+ compatible = "simple-audio-card";
+
+ simple-audio-card,format = "left_j";
+ simple-audio-card,bitclock-master = <&sndcodec>;
+ simple-audio-card,frame-master = <&sndcodec>;
+
+ sndcpu: simple-audio-card,cpu {
+ sound-dai = <&rcar_sound>;
+ };
+
+ sndcodec: simple-audio-card,codec {
+ sound-dai = <&ak4643>;
+ system-clock-frequency = <11289600>;
+ };
+ };
+};
+
+&du {
+ pinctrl-0 = <&du_pins>;
+ pinctrl-names = "default";
+ status = "okay";
+
+ ports {
+ port@1 {
+ lvds_connector: endpoint {
+ };
+ };
+ };
};
&extal_clk {
@@ -216,9 +278,6 @@
};
&pfc {
- pinctrl-0 = <&du_pins>;
- pinctrl-names = "default";
-
i2c2_pins: i2c2 {
renesas,groups = "i2c2";
renesas,function = "i2c2";
@@ -289,6 +348,16 @@
renesas,groups = "vin1_data8", "vin1_clk";
renesas,function = "vin1";
};
+
+ sound_pins: sound {
+ renesas,groups = "ssi0129_ctrl", "ssi0_data", "ssi1_data";
+ renesas,function = "ssi";
+ };
+
+ sound_clk_pins: sound_clk {
+ renesas,groups = "audio_clk_a";
+ renesas,function = "audio_clk";
+ };
};
&ether {
@@ -414,7 +483,13 @@
pinctrl-names = "default";
status = "okay";
- clock-frequency = <400000>;
+ clock-frequency = <100000>;
+
+ ak4643: sound-codec@12 {
+ compatible = "asahi-kasei,ak4643";
+ #sound-dai-cells = <0>;
+ reg = <0x12>;
+ };
composite-in@20 {
compatible = "adi,adv7180";
@@ -463,6 +538,17 @@
pinctrl-names = "default";
};
+&hsusb {
+ status = "okay";
+ pinctrl-0 = <&usb0_pins>;
+ pinctrl-names = "default";
+ renesas,enable-gpio = <&gpio5 31 GPIO_ACTIVE_HIGH>;
+};
+
+&usbphy {
+ status = "okay";
+};
+
&pcie_bus_clk {
status = "okay";
};
@@ -491,3 +577,23 @@
};
};
};
+
+&rcar_sound {
+ pinctrl-0 = <&sound_pins &sound_clk_pins>;
+ pinctrl-names = "default";
+
+ #sound-dai-cells = <0>;
+
+ status = "okay";
+
+ rcar_sound,dai {
+ dai0 {
+ playback = <&ssi0 &src2 &dvc0>;
+ capture = <&ssi1 &src3 &dvc1>;
+ };
+ };
+};
+
+&ssi1 {
+ shared-pin;
+};
diff --git a/arch/arm/boot/dts/r8a7791.dtsi b/arch/arm/boot/dts/r8a7791.dtsi
index e06c11f..77c0bee 100644
--- a/arch/arm/boot/dts/r8a7791.dtsi
+++ b/arch/arm/boot/dts/r8a7791.dtsi
@@ -1,7 +1,7 @@
/*
* Device Tree Source for the r8a7791 SoC
*
- * Copyright (C) 2013 Renesas Electronics Corporation
+ * Copyright (C) 2013-2014 Renesas Electronics Corporation
* Copyright (C) 2013-2014 Renesas Solutions Corp.
* Copyright (C) 2014 Cogent Embedded Inc.
*
@@ -301,6 +301,69 @@
dma-channels = <15>;
};
+ audma0: dma-controller@ec700000 {
+ compatible = "renesas,rcar-dmac";
+ reg = <0 0xec700000 0 0x10000>;
+ interrupts = <0 346 IRQ_TYPE_LEVEL_HIGH
+ 0 320 IRQ_TYPE_LEVEL_HIGH
+ 0 321 IRQ_TYPE_LEVEL_HIGH
+ 0 322 IRQ_TYPE_LEVEL_HIGH
+ 0 323 IRQ_TYPE_LEVEL_HIGH
+ 0 324 IRQ_TYPE_LEVEL_HIGH
+ 0 325 IRQ_TYPE_LEVEL_HIGH
+ 0 326 IRQ_TYPE_LEVEL_HIGH
+ 0 327 IRQ_TYPE_LEVEL_HIGH
+ 0 328 IRQ_TYPE_LEVEL_HIGH
+ 0 329 IRQ_TYPE_LEVEL_HIGH
+ 0 330 IRQ_TYPE_LEVEL_HIGH
+ 0 331 IRQ_TYPE_LEVEL_HIGH
+ 0 332 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12";
+ clocks = <&mstp5_clks R8A7791_CLK_AUDIO_DMAC0>;
+ clock-names = "fck";
+ #dma-cells = <1>;
+ dma-channels = <13>;
+ };
+
+ audma1: dma-controller@ec720000 {
+ compatible = "renesas,rcar-dmac";
+ reg = <0 0xec720000 0 0x10000>;
+ interrupts = <0 347 IRQ_TYPE_LEVEL_HIGH
+ 0 333 IRQ_TYPE_LEVEL_HIGH
+ 0 334 IRQ_TYPE_LEVEL_HIGH
+ 0 335 IRQ_TYPE_LEVEL_HIGH
+ 0 336 IRQ_TYPE_LEVEL_HIGH
+ 0 337 IRQ_TYPE_LEVEL_HIGH
+ 0 338 IRQ_TYPE_LEVEL_HIGH
+ 0 339 IRQ_TYPE_LEVEL_HIGH
+ 0 340 IRQ_TYPE_LEVEL_HIGH
+ 0 341 IRQ_TYPE_LEVEL_HIGH
+ 0 342 IRQ_TYPE_LEVEL_HIGH
+ 0 343 IRQ_TYPE_LEVEL_HIGH
+ 0 344 IRQ_TYPE_LEVEL_HIGH
+ 0 345 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "error",
+ "ch0", "ch1", "ch2", "ch3",
+ "ch4", "ch5", "ch6", "ch7",
+ "ch8", "ch9", "ch10", "ch11",
+ "ch12";
+ clocks = <&mstp5_clks R8A7791_CLK_AUDIO_DMAC1>;
+ clock-names = "fck";
+ #dma-cells = <1>;
+ dma-channels = <13>;
+ };
+
+ audmapp: dma-controller@ec740000 {
+ compatible = "renesas,rcar-audmapp";
+ #dma-cells = <1>;
+
+ reg = <0 0xec740000 0 0x200>;
+ };
+
/* The memory map in the User's Manual maps the cores to bus numbers */
i2c0: i2c@e6508000 {
#address-cells = <1>;
@@ -371,6 +434,8 @@
reg = <0 0xe60b0000 0 0x425>;
interrupts = <0 173 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp9_clks R8A7791_CLK_IICDVFS>;
+ dmas = <&dmac0 0x77>, <&dmac0 0x78>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -381,6 +446,8 @@
reg = <0 0xe6500000 0 0x425>;
interrupts = <0 174 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7791_CLK_IIC0>;
+ dmas = <&dmac0 0x61>, <&dmac0 0x62>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -391,6 +458,8 @@
reg = <0 0xe6510000 0 0x425>;
interrupts = <0 175 IRQ_TYPE_LEVEL_HIGH>;
clocks = <&mstp3_clks R8A7791_CLK_IIC1>;
+ dmas = <&dmac0 0x65>, <&dmac0 0x66>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -400,6 +469,17 @@
#gpio-range-cells = <3>;
};
+ mmcif0: mmc@ee200000 {
+ compatible = "renesas,mmcif-r8a7791", "renesas,sh-mmcif";
+ reg = <0 0xee200000 0 0x80>;
+ interrupts = <0 169 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp3_clks R8A7791_CLK_MMCIF0>;
+ dmas = <&dmac0 0xd1>, <&dmac0 0xd2>;
+ dma-names = "tx", "rx";
+ reg-io-width = <4>;
+ status = "disabled";
+ };
+
sdhi0: sd@ee100000 {
compatible = "renesas,sdhi-r8a7791";
reg = <0 0xee100000 0 0x200>;
@@ -613,6 +693,36 @@
status = "disabled";
};
+ hsusb: usb@e6590000 {
+ compatible = "renesas,usbhs-r8a7791";
+ reg = <0 0xe6590000 0 0x100>;
+ interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7791_CLK_HSUSB>;
+ renesas,buswait = <4>;
+ phys = <&usb0 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
+ usbphy: usb-phy@e6590100 {
+ compatible = "renesas,usb-phy-r8a7791";
+ reg = <0 0xe6590100 0 0x100>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ clocks = <&mstp7_clks R8A7791_CLK_HSUSB>;
+ clock-names = "usbhs";
+ status = "disabled";
+
+ usb0: usb-channel@0 {
+ reg = <0>;
+ #phy-cells = <1>;
+ };
+ usb2: usb-channel@2 {
+ reg = <2>;
+ #phy-cells = <1>;
+ };
+ };
+
vin0: video@e6ef0000 {
compatible = "renesas,vin-r8a7791";
clocks = <&mstp8_clks R8A7791_CLK_VIN0>;
@@ -637,6 +747,75 @@
status = "disabled";
};
+ vsp1@fe928000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe928000 0 0x8000>;
+ interrupts = <0 267 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7791_CLK_VSP1_S>;
+
+ renesas,has-lut;
+ renesas,has-sru;
+ renesas,#rpf = <5>;
+ renesas,#uds = <3>;
+ renesas,#wpf = <4>;
+ };
+
+ vsp1@fe930000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe930000 0 0x8000>;
+ interrupts = <0 246 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU0>;
+
+ renesas,has-lif;
+ renesas,has-lut;
+ renesas,#rpf = <4>;
+ renesas,#uds = <1>;
+ renesas,#wpf = <4>;
+ };
+
+ vsp1@fe938000 {
+ compatible = "renesas,vsp1";
+ reg = <0 0xfe938000 0 0x8000>;
+ interrupts = <0 247 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp1_clks R8A7791_CLK_VSP1_DU1>;
+
+ renesas,has-lif;
+ renesas,has-lut;
+ renesas,#rpf = <4>;
+ renesas,#uds = <1>;
+ renesas,#wpf = <4>;
+ };
+
+ du: display@feb00000 {
+ compatible = "renesas,du-r8a7791";
+ reg = <0 0xfeb00000 0 0x40000>,
+ <0 0xfeb90000 0 0x1c>;
+ reg-names = "du", "lvds.0";
+ interrupts = <0 256 IRQ_TYPE_LEVEL_HIGH>,
+ <0 268 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp7_clks R8A7791_CLK_DU0>,
+ <&mstp7_clks R8A7791_CLK_DU1>,
+ <&mstp7_clks R8A7791_CLK_LVDS0>;
+ clock-names = "du.0", "du.1", "lvds.0";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ port@0 {
+ reg = <0>;
+ du_out_rgb: endpoint {
+ };
+ };
+ port@1 {
+ reg = <1>;
+ du_out_lvds0: endpoint {
+ };
+ };
+ };
+ };
+
clocks {
#address-cells = <2>;
#size-cells = <2>;
@@ -889,17 +1068,23 @@
mstp1_clks: mstp1_clks@e6150134 {
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150134 0 4>, <0 0xe6150038 0 4>;
- clocks = <&m2_clk>, <&p_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>,
- <&cp_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>;
+ clocks = <&zs_clk>, <&zs_clk>, <&m2_clk>, <&zs_clk>, <&p_clk>,
+ <&zg_clk>, <&zs_clk>, <&zs_clk>, <&zs_clk>, <&p_clk>,
+ <&p_clk>, <&rclk_clk>, <&cp_clk>, <&zs_clk>, <&zs_clk>,
+ <&zs_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
- R8A7791_CLK_JPU R8A7791_CLK_TMU1 R8A7791_CLK_TMU3 R8A7791_CLK_TMU2
- R8A7791_CLK_CMT0 R8A7791_CLK_TMU0 R8A7791_CLK_VSP1_DU1
- R8A7791_CLK_VSP1_DU0 R8A7791_CLK_VSP1_S
+ R8A7791_CLK_VCP0 R8A7791_CLK_VPC0 R8A7791_CLK_JPU
+ R8A7791_CLK_SSP1 R8A7791_CLK_TMU1 R8A7791_CLK_3DG
+ R8A7791_CLK_2DDMAC R8A7791_CLK_FDP1_1 R8A7791_CLK_FDP1_0
+ R8A7791_CLK_TMU3 R8A7791_CLK_TMU2 R8A7791_CLK_CMT0
+ R8A7791_CLK_TMU0 R8A7791_CLK_VSP1_DU1 R8A7791_CLK_VSP1_DU0
+ R8A7791_CLK_VSP1_S
>;
clock-output-names =
- "jpu", "tmu1", "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du1",
- "vsp1-du0", "vsp1-sy";
+ "vcp0", "vpc0", "jpu", "ssp1", "tmu1", "3dg",
+ "2ddmac", "fdp1-1", "fdp1-0", "tmu3", "tmu2", "cmt0",
+ "tmu0", "vsp1-du1", "vsp1-du0", "vsp1-sy";
};
mstp2_clks: mstp2_clks@e6150138 {
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -923,24 +1108,28 @@
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe615013c 0 4>, <0 0xe6150048 0 4>;
clocks = <&cp_clk>, <&sd2_clk>, <&sd1_clk>, <&cpg_clocks R8A7791_CLK_SD0>,
- <&mmc0_clk>, <&hp_clk>, <&mp_clk>, <&hp_clk>, <&mp_clk>, <&rclk_clk>;
+ <&mmc0_clk>, <&hp_clk>, <&mp_clk>, <&hp_clk>, <&mp_clk>, <&rclk_clk>,
+ <&hp_clk>, <&hp_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
R8A7791_CLK_TPU0 R8A7791_CLK_SDHI2 R8A7791_CLK_SDHI1 R8A7791_CLK_SDHI0
R8A7791_CLK_MMCIF0 R8A7791_CLK_IIC0 R8A7791_CLK_PCIEC R8A7791_CLK_IIC1
R8A7791_CLK_SSUSB R8A7791_CLK_CMT1
+ R8A7791_CLK_USBDMAC0 R8A7791_CLK_USBDMAC1
>;
clock-output-names =
"tpu0", "sdhi2", "sdhi1", "sdhi0",
- "mmcif0", "i2c7", "pciec", "i2c8", "ssusb", "cmt1";
+ "mmcif0", "i2c7", "pciec", "i2c8", "ssusb", "cmt1",
+ "usbdmac0", "usbdmac1";
};
mstp5_clks: mstp5_clks@e6150144 {
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150144 0 4>, <0 0xe615003c 0 4>;
- clocks = <&extal_clk>, <&p_clk>;
+ clocks = <&hp_clk>, <&hp_clk>, <&extal_clk>, <&p_clk>;
#clock-cells = <1>;
- renesas,clock-indices = <R8A7791_CLK_THERMAL R8A7791_CLK_PWM>;
- clock-output-names = "thermal", "pwm";
+ renesas,clock-indices = <R8A7791_CLK_AUDIO_DMAC0 R8A7791_CLK_AUDIO_DMAC1
+ R8A7791_CLK_THERMAL R8A7791_CLK_PWM>;
+ clock-output-names = "audmac0", "audmac1", "thermal", "pwm";
};
mstp7_clks: mstp7_clks@e615014c {
compatible = "renesas,r8a7791-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -1088,6 +1277,16 @@
status = "disabled";
};
+ xhci: usb@ee000000 {
+ compatible = "renesas,xhci-r8a7791";
+ reg = <0 0xee000000 0 0xc00>;
+ interrupts = <0 101 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&mstp3_clks R8A7791_CLK_SSUSB>;
+ phys = <&usb2 1>;
+ phy-names = "usb";
+ status = "disabled";
+ };
+
pci0: pci@ee090000 {
compatible = "renesas,pci-r8a7791";
device_type = "pci";
@@ -1106,6 +1305,20 @@
interrupt-map = <0x0000 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x0800 0 0 1 &gic 0 108 IRQ_TYPE_LEVEL_HIGH
0x1000 0 0 2 &gic 0 108 IRQ_TYPE_LEVEL_HIGH>;
+
+ usb@0,1 {
+ reg = <0x800 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb0 0>;
+ phy-names = "usb";
+ };
+
+ usb@0,2 {
+ reg = <0x1000 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb0 0>;
+ phy-names = "usb";
+ };
};
pci1: pci@ee0d0000 {
@@ -1126,6 +1339,20 @@
interrupt-map = <0x0000 0 0 1 &gic 0 113 IRQ_TYPE_LEVEL_HIGH
0x0800 0 0 1 &gic 0 113 IRQ_TYPE_LEVEL_HIGH
0x1000 0 0 2 &gic 0 113 IRQ_TYPE_LEVEL_HIGH>;
+
+ usb@0,1 {
+ reg = <0x800 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb2 0>;
+ phy-names = "usb";
+ };
+
+ usb@0,2 {
+ reg = <0x1000 0 0 0 0>;
+ device_type = "pci";
+ phys = <&usb2 0>;
+ phy-names = "usb";
+ };
};
pciec: pcie@fe000000 {
@@ -1153,7 +1380,7 @@
status = "disabled";
};
- rcar_sound: rcar_sound@0xec500000 {
+ rcar_sound: rcar_sound@ec500000 {
#sound-dai-cells = <1>;
compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2", "renesas,rcar_sound";
reg = <0 0xec500000 0 0x1000>, /* SCU */
diff --git a/arch/arm/boot/dts/r8a7794-alt.dts b/arch/arm/boot/dts/r8a7794-alt.dts
index 79d06ef0..f2cf757 100644
--- a/arch/arm/boot/dts/r8a7794-alt.dts
+++ b/arch/arm/boot/dts/r8a7794-alt.dts
@@ -20,7 +20,8 @@
};
chosen {
- bootargs = "console=ttySC0,38400 ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ bootargs = "ignore_loglevel rw root=/dev/nfs ip=dhcp";
+ stdout-path = &scif2;
};
memory@40000000 {
diff --git a/arch/arm/boot/dts/r8a7794.dtsi b/arch/arm/boot/dts/r8a7794.dtsi
index d4e8bce..19c9de3 100644
--- a/arch/arm/boot/dts/r8a7794.dtsi
+++ b/arch/arm/boot/dts/r8a7794.dtsi
@@ -82,6 +82,14 @@
status = "disabled";
};
+ timer {
+ compatible = "arm,armv7-timer";
+ interrupts = <1 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <1 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <1 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>,
+ <1 10 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
irqc0: interrupt-controller@e61c0000 {
compatible = "renesas,irqc-r8a7794", "renesas,irqc";
#interrupt-cells = <2>;
@@ -453,16 +461,19 @@
mstp1_clks: mstp1_clks@e6150134 {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150134 0 4>, <0 0xe6150038 0 4>;
- clocks = <&p_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>,
- <&cp_clk>,
- <&zs_clk>, <&zs_clk>, <&zs_clk>;
+ clocks = <&zs_clk>, <&zs_clk>, <&p_clk>, <&zg_clk>, <&zs_clk>,
+ <&zs_clk>, <&p_clk>, <&p_clk>, <&rclk_clk>, <&cp_clk>,
+ <&zs_clk>, <&zs_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
- R8A7794_CLK_TMU1 R8A7794_CLK_TMU3 R8A7794_CLK_TMU2
- R8A7794_CLK_CMT0 R8A7794_CLK_TMU0
+ R8A7794_CLK_VCP0 R8A7794_CLK_VPC0 R8A7794_CLK_TMU1
+ R8A7794_CLK_3DG R8A7794_CLK_2DDMAC R8A7794_CLK_FDP1_0
+ R8A7794_CLK_TMU3 R8A7794_CLK_TMU2 R8A7794_CLK_CMT0
+ R8A7794_CLK_TMU0 R8A7794_CLK_VSP1_DU0 R8A7794_CLK_VSP1_S
>;
clock-output-names =
- "tmu1", "tmu3", "tmu2", "cmt0", "tmu0";
+ "vcp0", "vpc0", "tmu1", "3dg", "2ddmac", "fdp1-0",
+ "tmu3", "tmu2", "cmt0", "tmu0", "vsp1-du0", "vsps";
};
mstp2_clks: mstp2_clks@e6150138 {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
@@ -509,13 +520,13 @@
mstp8_clks: mstp8_clks@e6150990 {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
reg = <0 0xe6150990 0 4>, <0 0xe61509a0 0 4>;
- clocks = <&p_clk>;
+ clocks = <&zg_clk>, <&zg_clk>, <&p_clk>;
#clock-cells = <1>;
renesas,clock-indices = <
- R8A7794_CLK_ETHER
+ R8A7794_CLK_VIN1 R8A7794_CLK_VIN0 R8A7794_CLK_ETHER
>;
clock-output-names =
- "ether";
+ "vin1", "vin0", "ether";
};
mstp11_clks: mstp11_clks@e615099c {
compatible = "renesas,r8a7794-mstp-clocks", "renesas,cpg-mstp-clocks";
diff --git a/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi
new file mode 100644
index 0000000..65cb50f
--- /dev/null
+++ b/arch/arm/boot/dts/r8a77xx-aa104xd12-panel.dtsi
@@ -0,0 +1,41 @@
+/*
+ * Common file for the AA104XD12 panel connected to Renesas R-Car boards
+ *
+ * Copyright (C) 2014 Renesas Electronics Corp.
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+/ {
+ panel {
+ compatible = "mitsubishi,aa104xd12", "panel-dpi";
+
+ width-mm = <210>;
+ height-mm = <158>;
+
+ panel-timing {
+ /* 1024x768 @65Hz */
+ clock-frequency = <65000000>;
+ hactive = <1024>;
+ vactive = <768>;
+ hsync-len = <136>;
+ hfront-porch = <20>;
+ hback-porch = <160>;
+ vfront-porch = <3>;
+ vback-porch = <29>;
+ vsync-len = <6>;
+ };
+
+ port {
+ panel_in: endpoint {
+ remote-endpoint = <&lvds_connector>;
+ };
+ };
+ };
+};
+
+&lvds_connector {
+ remote-endpoint = <&panel_in>;
+};
diff --git a/arch/arm/boot/dts/rk3066a-bqcurie2.dts b/arch/arm/boot/dts/rk3066a-bqcurie2.dts
index d534451..baf21ac 100644
--- a/arch/arm/boot/dts/rk3066a-bqcurie2.dts
+++ b/arch/arm/boot/dts/rk3066a-bqcurie2.dts
@@ -60,6 +60,10 @@
};
};
+&cpu0 {
+ cpu0-supply = <&vdd_arm>;
+};
+
&i2c1 {
status = "okay";
clock-frequency = <400000>;
diff --git a/arch/arm/boot/dts/rk3066a-marsboard.dts b/arch/arm/boot/dts/rk3066a-marsboard.dts
new file mode 100644
index 0000000..0a7304b
--- /dev/null
+++ b/arch/arm/boot/dts/rk3066a-marsboard.dts
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2014 Romain Perier <romain.perier@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+#include "rk3066a.dtsi"
+
+/ {
+ model = "MarsBoard RK3066";
+ compatible = "haoyu,marsboard-rk3066", "rockchip,rk3066a";
+
+ memory {
+ reg = <0x60000000 0x40000000>;
+ };
+
+ vcc_sd0: sdmmc-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "sdmmc-supply";
+ regulator-min-microvolt = <3000000>;
+ regulator-max-microvolt = <3000000>;
+ gpio = <&gpio3 7 GPIO_ACTIVE_LOW>;
+ startup-delay-us = <100000>;
+ vin-supply = <&vcc_io>;
+ };
+
+ vsys: vsys-regulator {
+ compatible = "regulator-fixed";
+ regulator-name = "vsys";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
+ };
+};
+
+&i2c1 {
+ status = "okay";
+ clock-frequency = <400000>;
+
+ tps: tps@2d {
+ reg = <0x2d>;
+
+ interrupt-parent = <&gpio6>;
+ interrupts = <4 IRQ_TYPE_LEVEL_LOW>;
+
+ vcc1-supply = <&vsys>;
+ vcc2-supply = <&vsys>;
+ vcc3-supply = <&vsys>;
+ vcc4-supply = <&vsys>;
+ vcc5-supply = <&vcc_io>;
+ vcc6-supply = <&vcc_io>;
+ vcc7-supply = <&vsys>;
+ vccio-supply = <&vsys>;
+
+ regulators {
+ vcc_rtc: regulator@0 {
+ regulator-name = "vcc_rtc";
+ regulator-always-on;
+ };
+
+ vcc_io: regulator@1 {
+ regulator-name = "vcc_io";
+ regulator-always-on;
+ };
+
+ vdd_arm: regulator@2 {
+ regulator-name = "vdd_arm";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vcc_ddr: regulator@3 {
+ regulator-name = "vcc_ddr";
+ regulator-min-microvolt = <600000>;
+ regulator-max-microvolt = <1500000>;
+ regulator-boot-on;
+ regulator-always-on;
+ };
+
+ vcc18_cif: regulator@5 {
+ regulator-name = "vcc18_cif";
+ regulator-always-on;
+ };
+
+ vdd_11: regulator@6 {
+ regulator-name = "vdd_11";
+ regulator-always-on;
+ };
+
+ vcc_25: regulator@7 {
+ regulator-name = "vcc_25";
+ regulator-always-on;
+ };
+
+ vcc_18: regulator@8 {
+ regulator-name = "vcc_18";
+ regulator-always-on;
+ };
+
+ vcc25_hdmi: regulator@9 {
+ regulator-name = "vcc25_hdmi";
+ regulator-always-on;
+ };
+
+ vcca_33: regulator@10 {
+ regulator-name = "vcca_33";
+ regulator-always-on;
+ };
+
+ vcc_rmii: regulator@11 {
+ regulator-name = "vcc_rmii";
+ };
+
+ vcc28_cif: regulator@12 {
+ regulator-name = "vcc28_cif";
+ regulator-always-on;
+ };
+ };
+ };
+};
+
+/* must be included after &tps gets defined */
+#include "tps65910.dtsi"
+
+&emac {
+ status = "okay";
+
+ phy = <&phy0>;
+ phy-supply = <&vcc_rmii>;
+
+ pinctrl-names = "default";
+ pinctrl-0 = <&emac_xfer>, <&emac_mdio>, <&phy_int>;
+
+ phy0: ethernet-phy@0 {
+ reg = <0>;
+ interrupt-parent = <&gpio1>;
+ interrupts = <26 IRQ_TYPE_LEVEL_LOW>;
+ };
+};
+
+&pinctrl {
+ lan8720a {
+ phy_int: phy-int {
+ rockchip,pins = <RK_GPIO1 26 RK_FUNC_GPIO &pcfg_pull_none>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&uart3 {
+ status = "okay";
+};
+
+&wdt {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/rk3066a.dtsi b/arch/arm/boot/dts/rk3066a.dtsi
index ad9c2db..41ffd49 100644
--- a/arch/arm/boot/dts/rk3066a.dtsi
+++ b/arch/arm/boot/dts/rk3066a.dtsi
@@ -26,11 +26,21 @@
#size-cells = <0>;
enable-method = "rockchip,rk3066-smp";
- cpu@0 {
+ cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
next-level-cache = <&L2>;
reg = <0x0>;
+ operating-points = <
+ /* kHz uV */
+ 1008000 1075000
+ 816000 1025000
+ 600000 1025000
+ 504000 1000000
+ 312000 975000
+ >;
+ clock-latency = <40000>;
+ clocks = <&cru ARMCLK>;
};
cpu@1 {
device_type = "cpu";
@@ -53,6 +63,51 @@
};
};
+ i2s0: i2s@10118000 {
+ compatible = "rockchip,rk3066-i2s";
+ reg = <0x10118000 0x2000>;
+ interrupts = <GIC_SPI 31 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_bus>;
+ dmas = <&dmac1_s 4>, <&dmac1_s 5>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_hclk", "i2s_clk";
+ clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+ status = "disabled";
+ };
+
+ i2s1: i2s@1011a000 {
+ compatible = "rockchip,rk3066-i2s";
+ reg = <0x1011a000 0x2000>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s1_bus>;
+ dmas = <&dmac1_s 6>, <&dmac1_s 7>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_hclk", "i2s_clk";
+ clocks = <&cru HCLK_I2S1>, <&cru SCLK_I2S1>;
+ status = "disabled";
+ };
+
+ i2s2: i2s@1011c000 {
+ compatible = "rockchip,rk3066-i2s";
+ reg = <0x1011c000 0x2000>;
+ interrupts = <GIC_SPI 20 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s2_bus>;
+ dmas = <&dmac1_s 9>, <&dmac1_s 10>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_hclk", "i2s_clk";
+ clocks = <&cru HCLK_I2S2>, <&cru SCLK_I2S2>;
+ status = "disabled";
+ };
+
cru: clock-controller@20000000 {
compatible = "rockchip,rk3066a-cru";
reg = <0x20000000 0x1000>;
@@ -179,6 +234,24 @@
bias-disable;
};
+ emac {
+ emac_xfer: emac-xfer {
+ rockchip,pins = <RK_GPIO1 16 RK_FUNC_2 &pcfg_pull_none>, /* mac_clk */
+ <RK_GPIO1 17 RK_FUNC_2 &pcfg_pull_none>, /* tx_en */
+ <RK_GPIO1 18 RK_FUNC_2 &pcfg_pull_none>, /* txd1 */
+ <RK_GPIO1 19 RK_FUNC_2 &pcfg_pull_none>, /* txd0 */
+ <RK_GPIO1 20 RK_FUNC_2 &pcfg_pull_none>, /* rx_err */
+ <RK_GPIO1 21 RK_FUNC_2 &pcfg_pull_none>, /* crs_dvalid */
+ <RK_GPIO1 22 RK_FUNC_2 &pcfg_pull_none>, /* rxd1 */
+ <RK_GPIO1 23 RK_FUNC_2 &pcfg_pull_none>; /* rxd0 */
+ };
+
+ emac_mdio: emac-mdio {
+ rockchip,pins = <RK_GPIO1 24 RK_FUNC_2 &pcfg_pull_none>, /* mac_md */
+ <RK_GPIO1 25 RK_FUNC_2 &pcfg_pull_none>; /* mac_mdclk */
+ };
+ };
+
emmc {
emmc_clk: emmc-clk {
rockchip,pins = <RK_GPIO3 31 RK_FUNC_2 &pcfg_pull_default>;
@@ -405,6 +478,42 @@
<RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_default>;
};
};
+
+ i2s0 {
+ i2s0_bus: i2s0-bus {
+ rockchip,pins = <RK_GPIO0 7 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 8 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 9 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 10 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 11 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 12 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 13 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 14 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 15 RK_FUNC_1 &pcfg_pull_default>;
+ };
+ };
+
+ i2s1 {
+ i2s1_bus: i2s1-bus {
+ rockchip,pins = <RK_GPIO0 16 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 17 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 18 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 19 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 20 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 21 RK_FUNC_1 &pcfg_pull_default>;
+ };
+ };
+
+ i2s2 {
+ i2s2_bus: i2s2-bus {
+ rockchip,pins = <RK_GPIO0 24 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 25 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 26 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 27 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 28 RK_FUNC_1 &pcfg_pull_default>,
+ <RK_GPIO0 29 RK_FUNC_1 &pcfg_pull_default>;
+ };
+ };
};
};
@@ -496,3 +605,7 @@
&wdt {
compatible = "rockchip,rk3066-wdt", "snps,dw-wdt";
};
+
+&emac {
+ compatible = "rockchip,rk3066-emac";
+};
diff --git a/arch/arm/boot/dts/rk3188-radxarock.dts b/arch/arm/boot/dts/rk3188-radxarock.dts
index 15910c9..9a09579 100644
--- a/arch/arm/boot/dts/rk3188-radxarock.dts
+++ b/arch/arm/boot/dts/rk3188-radxarock.dts
@@ -43,16 +43,19 @@
compatible = "gpio-leds";
green {
+ label = "rock:green:user1";
gpios = <&gpio0 12 GPIO_ACTIVE_LOW>;
default-state = "off";
};
- yellow {
+ blue {
+ label = "rock:blue:user2";
gpios = <&gpio0 14 GPIO_ACTIVE_LOW>;
default-state = "off";
};
sleep {
+ label = "rock:red:power";
gpios = <&gpio0 15 0>;
default-state = "off";
};
@@ -118,6 +121,10 @@
};
};
+&cpu0 {
+ cpu0-supply = <&vdd_arm>;
+};
+
&i2c1 {
status = "okay";
clock-frequency = <400000>;
@@ -159,7 +166,7 @@
vdd_arm: REG3 {
regulator-name = "VDD_ARM";
regulator-min-microvolt = <875000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
regulator-always-on;
};
@@ -239,6 +246,18 @@
disable-wp;
};
+&pwm1 {
+ status = "okay";
+};
+
+&pwm2 {
+ status = "okay";
+};
+
+&pwm3 {
+ status = "okay";
+};
+
&pinctrl {
pcfg_output_low: pcfg-output-low {
output-low;
diff --git a/arch/arm/boot/dts/rk3188.dtsi b/arch/arm/boot/dts/rk3188.dtsi
index ddaada7..1d4d79c 100644
--- a/arch/arm/boot/dts/rk3188.dtsi
+++ b/arch/arm/boot/dts/rk3188.dtsi
@@ -26,11 +26,24 @@
#size-cells = <0>;
enable-method = "rockchip,rk3066-smp";
- cpu@0 {
+ cpu0: cpu@0 {
device_type = "cpu";
compatible = "arm,cortex-a9";
next-level-cache = <&L2>;
reg = <0x0>;
+ operating-points = <
+ /* kHz uV */
+ 1608000 1350000
+ 1416000 1250000
+ 1200000 1150000
+ 1008000 1075000
+ 816000 975000
+ 600000 950000
+ 504000 925000
+ 312000 875000
+ >;
+ clock-latency = <40000>;
+ clocks = <&cru ARMCLK>;
};
cpu@1 {
device_type = "cpu";
@@ -65,6 +78,21 @@
};
};
+ i2s0: i2s@1011a000 {
+ compatible = "rockchip,rk3188-i2s", "rockchip,rk3066-i2s";
+ reg = <0x1011a000 0x2000>;
+ interrupts = <GIC_SPI 32 IRQ_TYPE_LEVEL_HIGH>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2s0_bus>;
+ dmas = <&dmac1_s 6>, <&dmac1_s 7>;
+ dma-names = "tx", "rx";
+ clock-names = "i2s_hclk", "i2s_clk";
+ clocks = <&cru HCLK_I2S0>, <&cru SCLK_I2S0>;
+ status = "disabled";
+ };
+
cru: clock-controller@20000000 {
compatible = "rockchip,rk3188-cru";
reg = <0x20000000 0x1000>;
@@ -83,7 +111,7 @@
#size-cells = <1>;
ranges;
- gpio0: gpio0@0x2000a000 {
+ gpio0: gpio0@2000a000 {
compatible = "rockchip,rk3188-gpio-bank0";
reg = <0x2000a000 0x100>;
interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
@@ -96,7 +124,7 @@
#interrupt-cells = <2>;
};
- gpio1: gpio1@0x2003c000 {
+ gpio1: gpio1@2003c000 {
compatible = "rockchip,gpio-bank";
reg = <0x2003c000 0x100>;
interrupts = <GIC_SPI 55 IRQ_TYPE_LEVEL_HIGH>;
@@ -395,6 +423,17 @@
<RK_GPIO3 20 RK_FUNC_1 &pcfg_pull_none>;
};
};
+
+ i2s0 {
+ i2s0_bus: i2s0-bus {
+ rockchip,pins = <RK_GPIO1 16 RK_FUNC_1 &pcfg_pull_none>,
+ <RK_GPIO1 17 RK_FUNC_1 &pcfg_pull_none>,
+ <RK_GPIO1 18 RK_FUNC_1 &pcfg_pull_none>,
+ <RK_GPIO1 19 RK_FUNC_1 &pcfg_pull_none>,
+ <RK_GPIO1 20 RK_FUNC_1 &pcfg_pull_none>,
+ <RK_GPIO1 21 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/rk3288-evb-rk808.dts b/arch/arm/boot/dts/rk3288-evb-rk808.dts
index ff522f8..d8c775e6 100644
--- a/arch/arm/boot/dts/rk3288-evb-rk808.dts
+++ b/arch/arm/boot/dts/rk3288-evb-rk808.dts
@@ -17,6 +17,10 @@
compatible = "rockchip,rk3288-evb-rk808", "rockchip,rk3288";
};
+&cpu0 {
+ cpu0-supply = <&vdd_cpu>;
+};
+
&i2c0 {
clock-frequency = <400000>;
status = "okay";
@@ -44,7 +48,7 @@
regulator-always-on;
regulator-boot-on;
regulator-min-microvolt = <750000>;
- regulator-max-microvolt = <1300000>;
+ regulator-max-microvolt = <1350000>;
regulator-name = "vdd_arm";
};
diff --git a/arch/arm/boot/dts/rk3288-evb.dtsi b/arch/arm/boot/dts/rk3288-evb.dtsi
index cb83cea..3e067dd 100644
--- a/arch/arm/boot/dts/rk3288-evb.dtsi
+++ b/arch/arm/boot/dts/rk3288-evb.dtsi
@@ -148,6 +148,12 @@
status = "okay";
};
+&tsadc {
+ rockchip,hw-tshut-mode = <0>; /* tshut mode 0:CRU 1:GPIO */
+ rockchip,hw-tshut-polarity = <0>; /* tshut polarity 0:LOW 1:HIGH */
+ status = "okay";
+};
+
&pinctrl {
backlight {
bl_en: bl-en {
diff --git a/arch/arm/boot/dts/rk3288-thermal.dtsi b/arch/arm/boot/dts/rk3288-thermal.dtsi
new file mode 100644
index 0000000..2695200
--- /dev/null
+++ b/arch/arm/boot/dts/rk3288-thermal.dtsi
@@ -0,0 +1,74 @@
+/*
+ * Device Tree Source for RK3288 SoC thermal
+ *
+ * Copyright (c) 2014, Fuzhou Rockchip Electronics Co., Ltd
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#include <dt-bindings/thermal/thermal.h>
+
+reserve_thermal: reserve_thermal {
+ polling-delay-passive = <1000>; /* milliseconds */
+ polling-delay = <5000>; /* milliseconds */
+
+ thermal-sensors = <&tsadc 0>;
+};
+
+cpu_thermal: cpu_thermal {
+ polling-delay-passive = <1000>; /* milliseconds */
+ polling-delay = <5000>; /* milliseconds */
+
+ thermal-sensors = <&tsadc 1>;
+
+ trips {
+ cpu_alert0: cpu_alert0 {
+ temperature = <70000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ cpu_crit: cpu_crit {
+ temperature = <90000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&cpu_alert0>;
+ cooling-device =
+ <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+};
+
+gpu_thermal: gpu_thermal {
+ polling-delay-passive = <1000>; /* milliseconds */
+ polling-delay = <5000>; /* milliseconds */
+
+ thermal-sensors = <&tsadc 2>;
+
+ trips {
+ gpu_alert0: gpu_alert0 {
+ temperature = <70000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "passive";
+ };
+ gpu_crit: gpu_crit {
+ temperature = <90000>; /* millicelsius */
+ hysteresis = <2000>; /* millicelsius */
+ type = "critical";
+ };
+ };
+
+ cooling-maps {
+ map0 {
+ trip = <&gpu_alert0>;
+ cooling-device =
+ <&cpu0 THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/rk3288.dtsi b/arch/arm/boot/dts/rk3288.dtsi
index 874e66d..fd19f007 100644
--- a/arch/arm/boot/dts/rk3288.dtsi
+++ b/arch/arm/boot/dts/rk3288.dtsi
@@ -15,6 +15,7 @@
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/pinctrl/rockchip.h>
#include <dt-bindings/clock/rk3288-cru.h>
+#include <dt-bindings/thermal/thermal.h>
#include "skeleton.dtsi"
/ {
@@ -46,26 +47,50 @@
cpus {
#address-cells = <1>;
#size-cells = <0>;
+ enable-method = "rockchip,rk3066-smp";
+ rockchip,pmu = <&pmu>;
- cpu@500 {
+ cpu0: cpu@500 {
device_type = "cpu";
compatible = "arm,cortex-a12";
reg = <0x500>;
+ resets = <&cru SRST_CORE0>;
+ operating-points = <
+ /* KHz uV */
+ 1608000 1350000
+ 1512000 1300000
+ 1416000 1200000
+ 1200000 1100000
+ 1008000 1050000
+ 816000 1000000
+ 696000 950000
+ 600000 900000
+ 408000 900000
+ 312000 900000
+ 216000 900000
+ 126000 900000
+ >;
+ #cooling-cells = <2>; /* min followed by max */
+ clock-latency = <40000>;
+ clocks = <&cru ARMCLK>;
};
cpu@501 {
device_type = "cpu";
compatible = "arm,cortex-a12";
reg = <0x501>;
+ resets = <&cru SRST_CORE1>;
};
cpu@502 {
device_type = "cpu";
compatible = "arm,cortex-a12";
reg = <0x502>;
+ resets = <&cru SRST_CORE2>;
};
cpu@503 {
device_type = "cpu";
compatible = "arm,cortex-a12";
reg = <0x503>;
+ resets = <&cru SRST_CORE3>;
};
};
@@ -116,6 +141,7 @@
timer {
compatible = "arm,armv7-timer";
+ arm,cpu-registers-not-fw-configured;
interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
<GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(4) | IRQ_TYPE_LEVEL_HIGH)>,
@@ -177,6 +203,8 @@
compatible = "rockchip,rk3288-spi", "rockchip,rk3066-spi";
clocks = <&cru SCLK_SPI0>, <&cru PCLK_SPI0>;
clock-names = "spiclk", "apb_pclk";
+ dmas = <&dmac_peri 11>, <&dmac_peri 12>;
+ dma-names = "tx", "rx";
interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&spi0_clk &spi0_tx &spi0_rx &spi0_cs0>;
@@ -190,6 +218,8 @@
compatible = "rockchip,rk3288-spi", "rockchip,rk3066-spi";
clocks = <&cru SCLK_SPI1>, <&cru PCLK_SPI1>;
clock-names = "spiclk", "apb_pclk";
+ dmas = <&dmac_peri 13>, <&dmac_peri 14>;
+ dma-names = "tx", "rx";
interrupts = <GIC_SPI 45 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&spi1_clk &spi1_tx &spi1_rx &spi1_cs0>;
@@ -203,6 +233,8 @@
compatible = "rockchip,rk3288-spi", "rockchip,rk3066-spi";
clocks = <&cru SCLK_SPI2>, <&cru PCLK_SPI2>;
clock-names = "spiclk", "apb_pclk";
+ dmas = <&dmac_peri 15>, <&dmac_peri 16>;
+ dma-names = "tx", "rx";
interrupts = <GIC_SPI 46 IRQ_TYPE_LEVEL_HIGH>;
pinctrl-names = "default";
pinctrl-0 = <&spi2_clk &spi2_tx &spi2_rx &spi2_cs0>;
@@ -329,6 +361,25 @@
status = "disabled";
};
+ thermal-zones {
+ #include "rk3288-thermal.dtsi"
+ };
+
+ tsadc: tsadc@ff280000 {
+ compatible = "rockchip,rk3288-tsadc";
+ reg = <0xff280000 0x100>;
+ interrupts = <GIC_SPI 37 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&cru SCLK_TSADC>, <&cru PCLK_TSADC>;
+ clock-names = "tsadc", "apb_pclk";
+ resets = <&cru SRST_TSADC>;
+ reset-names = "tsadc-apb";
+ pinctrl-names = "default";
+ pinctrl-0 = <&otp_out>;
+ #thermal-sensor-cells = <1>;
+ rockchip,hw-tshut-temp = <95000>;
+ status = "disabled";
+ };
+
usb_host0_ehci: usb@ff500000 {
compatible = "generic-ehci";
reg = <0xff500000 0x100>;
@@ -439,6 +490,18 @@
status = "disabled";
};
+ bus_intmem@ff700000 {
+ compatible = "mmio-sram";
+ reg = <0xff700000 0x18000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0xff700000 0x18000>;
+ smp-sram@0 {
+ compatible = "rockchip,rk3066-smp-sram";
+ reg = <0x00 0x10>;
+ };
+ };
+
pmu: power-management@ff730000 {
compatible = "rockchip,rk3288-pmu", "syscon";
reg = <0xff730000 0x100>;
@@ -455,6 +518,16 @@
rockchip,grf = <&grf>;
#clock-cells = <1>;
#reset-cells = <1>;
+ assigned-clocks = <&cru PLL_GPLL>, <&cru PLL_CPLL>,
+ <&cru PLL_NPLL>, <&cru ACLK_CPU>,
+ <&cru HCLK_CPU>, <&cru PCLK_CPU>,
+ <&cru ACLK_PERI>, <&cru HCLK_PERI>,
+ <&cru PCLK_PERI>;
+ assigned-clock-rates = <594000000>, <400000000>,
+ <500000000>, <300000000>,
+ <150000000>, <75000000>,
+ <300000000>, <150000000>,
+ <75000000>;
};
grf: syscon@ff770000 {
@@ -484,6 +557,24 @@
status = "disabled";
};
+ vopb_mmu: iommu@ff930300 {
+ compatible = "rockchip,iommu";
+ reg = <0xff930300 0x100>;
+ interrupts = <GIC_SPI 15 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "vopb_mmu";
+ #iommu-cells = <0>;
+ status = "disabled";
+ };
+
+ vopl_mmu: iommu@ff940300 {
+ compatible = "rockchip,iommu";
+ reg = <0xff940300 0x100>;
+ interrupts = <GIC_SPI 16 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "vopl_mmu";
+ #iommu-cells = <0>;
+ status = "disabled";
+ };
+
gic: interrupt-controller@ffc01000 {
compatible = "arm,gic-400";
interrupt-controller;
@@ -948,6 +1039,12 @@
};
};
+ tsadc {
+ otp_out: otp-out {
+ rockchip,pins = <0 10 RK_FUNC_1 &pcfg_pull_none>;
+ };
+ };
+
pwm0 {
pwm0_pin: pwm0-pin {
rockchip,pins = <7 0 RK_FUNC_1 &pcfg_pull_none>;
diff --git a/arch/arm/boot/dts/rk3xxx.dtsi b/arch/arm/boot/dts/rk3xxx.dtsi
index 499468d..c54a971 100644
--- a/arch/arm/boot/dts/rk3xxx.dtsi
+++ b/arch/arm/boot/dts/rk3xxx.dtsi
@@ -29,6 +29,10 @@
mshc0 = &emmc;
mshc1 = &mmc0;
mshc2 = &mmc1;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
spi0 = &spi0;
spi1 = &spi1;
};
@@ -173,10 +177,9 @@
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x10214000 0x1000>;
interrupts = <GIC_SPI 23 IRQ_TYPE_LEVEL_HIGH>;
-
clocks = <&cru HCLK_SDMMC>, <&cru SCLK_SDMMC>;
clock-names = "biu", "ciu";
-
+ fifo-depth = <256>;
status = "disabled";
};
@@ -184,10 +187,9 @@
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x10218000 0x1000>;
interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
-
clocks = <&cru HCLK_SDIO>, <&cru SCLK_SDIO>;
clock-names = "biu", "ciu";
-
+ fifo-depth = <256>;
status = "disabled";
};
@@ -195,10 +197,9 @@
compatible = "rockchip,rk2928-dw-mshc";
reg = <0x1021c000 0x1000>;
interrupts = <GIC_SPI 25 IRQ_TYPE_LEVEL_HIGH>;
-
clocks = <&cru HCLK_EMMC>, <&cru SCLK_EMMC>;
clock-names = "biu", "ciu";
-
+ fifo-depth = <256>;
status = "disabled";
};
@@ -367,6 +368,8 @@
reg = <0x20070000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
+ dmas = <&dmac2 10>, <&dmac2 11>;
+ dma-names = "tx", "rx";
status = "disabled";
};
@@ -378,6 +381,8 @@
reg = <0x20074000 0x1000>;
#address-cells = <1>;
#size-cells = <0>;
+ dmas = <&dmac2 12>, <&dmac2 13>;
+ dma-names = "tx", "rx";
status = "disabled";
};
};
diff --git a/arch/arm/boot/dts/s3c6410-mini6410.dts b/arch/arm/boot/dts/s3c6410-mini6410.dts
index 57e00f9..a25debb 100644
--- a/arch/arm/boot/dts/s3c6410-mini6410.dts
+++ b/arch/arm/boot/dts/s3c6410-mini6410.dts
@@ -198,10 +198,6 @@
status = "okay";
};
-&pwm {
- status = "okay";
-};
-
&pinctrl0 {
gpio_leds: gpio-leds {
samsung,pins = "gpk-4", "gpk-5", "gpk-6", "gpk-7";
diff --git a/arch/arm/boot/dts/s3c64xx.dtsi b/arch/arm/boot/dts/s3c64xx.dtsi
index ff5bdaa..0ccb414 100644
--- a/arch/arm/boot/dts/s3c64xx.dtsi
+++ b/arch/arm/boot/dts/s3c64xx.dtsi
@@ -172,7 +172,6 @@
clocks = <&clocks PCLK_PWM>;
samsung,pwm-outputs = <0>, <1>;
#pwm-cells = <3>;
- status = "disabled";
};
pinctrl0: pinctrl@7f008000 {
diff --git a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
index 30ef97e..939be12 100644
--- a/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
+++ b/arch/arm/boot/dts/sh73a0-kzm9g-reference.dts
@@ -40,6 +40,7 @@
chosen {
bootargs = "console=tty0 console=ttySC4,115200 root=/dev/nfs ip=dhcp ignore_loglevel rw";
+ stdout-path = &scifa4;
};
memory {
@@ -100,19 +101,23 @@
compatible = "gpio-leds";
led1 {
gpios = <&pfc 20 GPIO_ACTIVE_LOW>;
+ label = "LED1";
};
led2 {
gpios = <&pfc 21 GPIO_ACTIVE_LOW>;
+ label = "LED2";
};
led3 {
gpios = <&pfc 22 GPIO_ACTIVE_LOW>;
+ label = "LED3";
};
led4 {
gpios = <&pfc 23 GPIO_ACTIVE_LOW>;
+ label = "LED4";
};
};
- gpio-keys {
+ keyboard {
compatible = "gpio-keys";
back-key {
@@ -250,7 +255,7 @@
};
};
- ak4648: ak4648@0x12 {
+ ak4648: ak4648@12 {
#sound-dai-cells = <0>;
compatible = "asahi-kasei,ak4648";
reg = <0x12>;
diff --git a/arch/arm/boot/dts/sh73a0.dtsi b/arch/arm/boot/dts/sh73a0.dtsi
index 030a592..d8def5a 100644
--- a/arch/arm/boot/dts/sh73a0.dtsi
+++ b/arch/arm/boot/dts/sh73a0.dtsi
@@ -138,7 +138,7 @@
i2c0: i2c@e6820000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-sh73a0", "renesas,rmobile-iic";
reg = <0xe6820000 0x425>;
interrupts = <0 167 IRQ_TYPE_LEVEL_HIGH
0 168 IRQ_TYPE_LEVEL_HIGH
@@ -150,7 +150,7 @@
i2c1: i2c@e6822000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-sh73a0", "renesas,rmobile-iic";
reg = <0xe6822000 0x425>;
interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH
0 52 IRQ_TYPE_LEVEL_HIGH
@@ -162,7 +162,7 @@
i2c2: i2c@e6824000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-sh73a0", "renesas,rmobile-iic";
reg = <0xe6824000 0x425>;
interrupts = <0 171 IRQ_TYPE_LEVEL_HIGH
0 172 IRQ_TYPE_LEVEL_HIGH
@@ -174,7 +174,7 @@
i2c3: i2c@e6826000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-sh73a0", "renesas,rmobile-iic";
reg = <0xe6826000 0x425>;
interrupts = <0 183 IRQ_TYPE_LEVEL_HIGH
0 184 IRQ_TYPE_LEVEL_HIGH
@@ -186,7 +186,7 @@
i2c4: i2c@e6828000 {
#address-cells = <1>;
#size-cells = <0>;
- compatible = "renesas,rmobile-iic";
+ compatible = "renesas,iic-sh73a0", "renesas,rmobile-iic";
reg = <0xe6828000 0x425>;
interrupts = <0 187 IRQ_TYPE_LEVEL_HIGH
0 188 IRQ_TYPE_LEVEL_HIGH
diff --git a/arch/arm/boot/dts/socfpga.dtsi b/arch/arm/boot/dts/socfpga.dtsi
index 4472fd9..252c3d1 100644
--- a/arch/arm/boot/dts/socfpga.dtsi
+++ b/arch/arm/boot/dts/socfpga.dtsi
@@ -639,6 +639,33 @@
clock-names = "biu", "ciu";
};
+ ocram: sram@ffff0000 {
+ compatible = "mmio-sram";
+ reg = <0xffff0000 0x10000>;
+ };
+
+ spi0: spi@fff00000 {
+ compatible = "snps,dw-apb-ssi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfff00000 0x1000>;
+ interrupts = <0 154 4>;
+ num-cs = <4>;
+ clocks = <&spi_m_clk>;
+ status = "disabled";
+ };
+
+ spi1: spi@fff01000 {
+ compatible = "snps,dw-apb-ssi";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0xfff01000 0x1000>;
+ interrupts = <0 156 4>;
+ num-cs = <4>;
+ clocks = <&spi_m_clk>;
+ status = "disabled";
+ };
+
/* Local timer */
timer@fffec600 {
compatible = "arm,cortex-a9-twd-timer";
diff --git a/arch/arm/boot/dts/socfpga_arria10.dtsi b/arch/arm/boot/dts/socfpga_arria10.dtsi
new file mode 100644
index 0000000..8a05c47
--- /dev/null
+++ b/arch/arm/boot/dts/socfpga_arria10.dtsi
@@ -0,0 +1,374 @@
+/*
+ * Copyright Altera Corporation (C) 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "skeleton.dtsi"
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ aliases {
+ ethernet0 = &gmac0;
+ ethernet1 = &gmac1;
+ ethernet2 = &gmac2;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ timer0 = &timer0;
+ timer1 = &timer1;
+ timer2 = &timer2;
+ timer3 = &timer3;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu@0 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <0>;
+ next-level-cache = <&L2>;
+ };
+ cpu@1 {
+ compatible = "arm,cortex-a9";
+ device_type = "cpu";
+ reg = <1>;
+ next-level-cache = <&L2>;
+ };
+ };
+
+ intc: intc@ffffd000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0xffffd000 0x1000>,
+ <0xffffc100 0x100>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ device_type = "soc";
+ interrupt-parent = <&intc>;
+ ranges;
+
+ amba {
+ compatible = "arm,amba-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ pdma: pdma@ffda1000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0xffda1000 0x1000>;
+ interrupts = <0 83 IRQ_TYPE_LEVEL_HIGH>,
+ <0 84 IRQ_TYPE_LEVEL_HIGH>,
+ <0 85 IRQ_TYPE_LEVEL_HIGH>,
+ <0 86 IRQ_TYPE_LEVEL_HIGH>,
+ <0 87 IRQ_TYPE_LEVEL_HIGH>,
+ <0 88 IRQ_TYPE_LEVEL_HIGH>,
+ <0 89 IRQ_TYPE_LEVEL_HIGH>,
+ <0 90 IRQ_TYPE_LEVEL_HIGH>;
+ #dma-cells = <1>;
+ #dma-channels = <8>;
+ #dma-requests = <32>;
+ };
+ };
+
+ clkmgr@ffd04000 {
+ compatible = "altr,clk-mgr";
+ reg = <0xffd04000 0x1000>;
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ osc1: osc1 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ };
+
+ main_pll: main_pll {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-pll-clock";
+ clocks = <&osc1>;
+ };
+
+ periph_pll: periph_pll {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ #clock-cells = <0>;
+ compatible = "altr,socfpga-pll-clock";
+ clocks = <&osc1>;
+ };
+ };
+ };
+
+ gmac0: ethernet@ff800000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+ reg = <0xff800000 0x2000>;
+ interrupts = <0 92 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ /* Filled in by bootloader */
+ mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ };
+
+ gmac1: ethernet@ff802000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+ reg = <0xff802000 0x2000>;
+ interrupts = <0 93 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ /* Filled in by bootloader */
+ mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ };
+
+ gmac2: ethernet@ff804000 {
+ compatible = "altr,socfpga-stmmac", "snps,dwmac-3.72a", "snps,dwmac";
+ reg = <0xff804000 0x2000>;
+ interrupts = <0 94 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "macirq";
+ /* Filled in by bootloader */
+ mac-address = [00 00 00 00 00 00];
+ status = "disabled";
+ };
+
+ gpio0: gpio@ffc02900 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dw-apb-gpio";
+ reg = <0xffc02900 0x100>;
+ status = "disabled";
+
+ porta: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <29>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0 112 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ gpio1: gpio@ffc02a00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dw-apb-gpio";
+ reg = <0xffc02a00 0x100>;
+ status = "disabled";
+
+ portb: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <29>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0 113 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ gpio2: gpio@ffc02b00 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,dw-apb-gpio";
+ reg = <0xffc02b00 0x100>;
+ status = "disabled";
+
+ portc: gpio-controller@0 {
+ compatible = "snps,dw-apb-gpio-port";
+ gpio-controller;
+ #gpio-cells = <2>;
+ snps,nr-gpios = <27>;
+ reg = <0>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ interrupts = <0 114 IRQ_TYPE_LEVEL_HIGH>;
+ };
+ };
+
+ i2c0: i2c@ffc02200 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02200 0x100>;
+ interrupts = <0 105 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ i2c1: i2c@ffc02300 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02300 0x100>;
+ interrupts = <0 106 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ i2c2: i2c@ffc02400 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02400 0x100>;
+ interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ i2c3: i2c@ffc02500 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02500 0x100>;
+ interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ i2c4: i2c@ffc02600 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "snps,designware-i2c";
+ reg = <0xffc02600 0x100>;
+ interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ L2: l2-cache@fffff000 {
+ compatible = "arm,pl310-cache";
+ reg = <0xfffff000 0x1000>;
+ interrupts = <0 18 IRQ_TYPE_LEVEL_HIGH>;
+ cache-unified;
+ cache-level = <2>;
+ };
+
+ mmc: dwmmc0@ff808000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "altr,socfpga-dw-mshc";
+ reg = <0xff808000 0x1000>;
+ interrupts = <0 98 IRQ_TYPE_LEVEL_HIGH>;
+ fifo-depth = <0x400>;
+ };
+
+ ocram: sram@ffe00000 {
+ compatible = "mmio-sram";
+ reg = <0xffe00000 0x40000>;
+ };
+
+ rst: rstmgr@ffd05000 {
+ #reset-cells = <1>;
+ compatible = "altr,rst-mgr";
+ reg = <0xffd05000 0x100>;
+ };
+
+ sysmgr: sysmgr@ffd06000 {
+ compatible = "altr,sys-mgr", "syscon";
+ reg = <0xffd06000 0x300>;
+ };
+
+ /* Local timer */
+ timer@ffffc600 {
+ compatible = "arm,cortex-a9-twd-timer";
+ reg = <0xffffc600 0x100>;
+ interrupts = <1 13 0xf04>;
+ };
+
+ timer0: timer0@ffc02700 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 115 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0xffc02700 0x100>;
+ };
+
+ timer1: timer1@ffc02800 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 116 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0xffc02800 0x100>;
+ };
+
+ timer2: timer2@ffd00000 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 117 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0xffd00000 0x100>;
+ };
+
+ timer3: timer3@ffd00100 {
+ compatible = "snps,dw-apb-timer";
+ interrupts = <0 118 IRQ_TYPE_LEVEL_HIGH>;
+ reg = <0xffd01000 0x100>;
+ };
+
+ uart0: serial0@ffc02000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0xffc02000 0x100>;
+ interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ };
+
+ uart1: serial1@ffc02100 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0xffc02100 0x100>;
+ interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ };
+
+ usbphy0: usbphy@0 {
+ #phy-cells = <0>;
+ compatible = "usb-nop-xceiv";
+ status = "okay";
+ };
+
+ usb0: usb@ffb00000 {
+ compatible = "snps,dwc2";
+ reg = <0xffb00000 0xffff>;
+ interrupts = <0 95 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usbphy0>;
+ phy-names = "usb2-phy";
+ status = "disabled";
+ };
+
+ usb1: usb@ffb40000 {
+ compatible = "snps,dwc2";
+ reg = <0xffb40000 0xffff>;
+ interrupts = <0 96 IRQ_TYPE_LEVEL_HIGH>;
+ phys = <&usbphy0>;
+ phy-names = "usb2-phy";
+ status = "disabled";
+ };
+
+ watchdog0: watchdog@ffd00200 {
+ compatible = "snps,dw-wdt";
+ reg = <0xffd00200 0x100>;
+ interrupts = <0 119 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+
+ watchdog1: watchdog@ffd00300 {
+ compatible = "snps,dw-wdt";
+ reg = <0xffd00300 0x100>;
+ interrupts = <0 120 IRQ_TYPE_LEVEL_HIGH>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/socfpga_arria10_socdk.dts b/arch/arm/boot/dts/socfpga_arria10_socdk.dts
new file mode 100755
index 0000000..3015ce8
--- /dev/null
+++ b/arch/arm/boot/dts/socfpga_arria10_socdk.dts
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2014 Altera Corporation <www.altera.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/dts-v1/;
+#include "socfpga_arria10.dtsi"
+
+/ {
+ model = "Altera SOCFPGA Arria 10";
+ compatible = "altr,socfpga-arria10", "altr,socfpga";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 rootwait";
+ };
+
+ memory {
+ name = "memory";
+ device_type = "memory";
+ reg = <0x0 0x40000000>; /* 1GB */
+ };
+
+ soc {
+ clkmgr@ffd04000 {
+ clocks {
+ osc1 {
+ clock-frequency = <25000000>;
+ };
+ };
+ };
+
+ serial0@ffc02000 {
+ status = "okay";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/socfpga_cyclone5.dtsi b/arch/arm/boot/dts/socfpga_cyclone5.dtsi
index 28c05e7..06db951 100644
--- a/arch/arm/boot/dts/socfpga_cyclone5.dtsi
+++ b/arch/arm/boot/dts/socfpga_cyclone5.dtsi
@@ -49,3 +49,7 @@
};
};
};
+
+&watchdog0 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/ste-ccu8540-pinctrl.dtsi b/arch/arm/boot/dts/ste-ccu8540-pinctrl.dtsi
index e079996..52dba2e 100644
--- a/arch/arm/boot/dts/ste-ccu8540-pinctrl.dtsi
+++ b/arch/arm/boot/dts/ste-ccu8540-pinctrl.dtsi
@@ -16,31 +16,31 @@
uart0 {
uart0_default_mux: uart0_mux {
default_mux {
- ste,function = "u0";
- ste,pins = "u0_a_1";
+ function = "u0";
+ groups = "u0_a_1";
};
};
uart0_default_mode: uart0_default {
default_cfg1 {
- ste,pins = "GPIO0", "GPIO2";
+ pins = "GPIO0", "GPIO2";
ste,config = <&in_pu>;
};
default_cfg2 {
- ste,pins = "GPIO1", "GPIO3";
+ pins = "GPIO1", "GPIO3";
ste,config = <&out_hi>;
};
};
uart0_sleep_mode: uart0_sleep {
sleep_cfg1 {
- ste,pins = "GPIO0", "GPIO2";
+ pins = "GPIO0", "GPIO2";
ste,config = <&slpm_in_pu>;
};
sleep_cfg2 {
- ste,pins = "GPIO1", "GPIO3";
+ pins = "GPIO1", "GPIO3";
ste,config = <&slpm_out_hi>;
};
};
@@ -49,29 +49,29 @@
uart2 {
uart2_default_mode: uart2_default {
default_mux {
- ste,function = "u2";
- ste,pins = "u2txrx_a_1";
+ function = "u2";
+ groups = "u2txrx_a_1";
};
default_cfg1 {
- ste,pins = "GPIO120";
+ pins = "GPIO120";
ste,config = <&in_pu>;
};
default_cfg2 {
- ste,pins = "GPIO121";
+ pins = "GPIO121";
ste,config = <&out_hi>;
};
};
uart2_sleep_mode: uart2_sleep {
sleep_cfg1 {
- ste,pins = "GPIO120";
+ pins = "GPIO120";
ste,config = <&slpm_in_pu>;
};
sleep_cfg2 {
- ste,pins = "GPIO121";
+ pins = "GPIO121";
ste,config = <&slpm_out_hi>;
};
};
@@ -80,21 +80,21 @@
i2c0 {
i2c0_default_mux: i2c_mux {
default_mux {
- ste,function = "i2c0";
- ste,pins = "i2c0_a_1";
+ function = "i2c0";
+ groups = "i2c0_a_1";
};
};
i2c0_default_mode: i2c_default {
default_cfg1 {
- ste,pins = "GPIO147", "GPIO148";
+ pins = "GPIO147", "GPIO148";
ste,config = <&in_pu>;
};
};
i2c0_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO147", "GPIO148";
+ pins = "GPIO147", "GPIO148";
ste,config = <&slpm_in_pu>;
};
};
@@ -103,21 +103,21 @@
i2c1 {
i2c1_default_mux: i2c_mux {
default_mux {
- ste,function = "i2c1";
- ste,pins = "i2c1_b_2";
+ function = "i2c1";
+ groups = "i2c1_b_2";
};
};
i2c1_default_mode: i2c_default {
default_cfg1 {
- ste,pins = "GPIO16", "GPIO17";
+ pins = "GPIO16", "GPIO17";
ste,config = <&in_pu>;
};
};
i2c1_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO16", "GPIO17";
+ pins = "GPIO16", "GPIO17";
ste,config = <&slpm_in_pu>;
};
};
@@ -126,21 +126,21 @@
i2c2 {
i2c2_default_mux: i2c_mux {
default_mux {
- ste,function = "i2c2";
- ste,pins = "i2c2_b_2";
+ function = "i2c2";
+ groups = "i2c2_b_2";
};
};
i2c2_default_mode: i2c_default {
default_cfg1 {
- ste,pins = "GPIO10", "GPIO11";
+ pins = "GPIO10", "GPIO11";
ste,config = <&in_pu>;
};
};
i2c2_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO11", "GPIO11";
+ pins = "GPIO11", "GPIO11";
ste,config = <&slpm_in_pu>;
};
};
@@ -149,21 +149,21 @@
i2c4 {
i2c4_default_mux: i2c_mux {
default_mux {
- ste,function = "i2c4";
- ste,pins = "i2c4_b_2";
+ function = "i2c4";
+ groups = "i2c4_b_2";
};
};
i2c4_default_mode: i2c_default {
default_cfg1 {
- ste,pins = "GPIO122", "GPIO123";
+ pins = "GPIO122", "GPIO123";
ste,config = <&in_pu>;
};
};
i2c4_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO122", "GPIO123";
+ pins = "GPIO122", "GPIO123";
ste,config = <&slpm_in_pu>;
};
};
@@ -172,21 +172,21 @@
i2c5 {
i2c5_default_mux: i2c_mux {
default_mux {
- ste,function = "i2c5";
- ste,pins = "i2c5_c_2";
+ function = "i2c5";
+ groups = "i2c5_c_2";
};
};
i2c5_default_mode: i2c_default {
default_cfg1 {
- ste,pins = "GPIO118", "GPIO119";
+ pins = "GPIO118", "GPIO119";
ste,config = <&in_pu>;
};
};
i2c5_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO118", "GPIO119";
+ pins = "GPIO118", "GPIO119";
ste,config = <&slpm_in_pu>;
};
};
diff --git a/arch/arm/boot/dts/ste-dbx5x0.dtsi b/arch/arm/boot/dts/ste-dbx5x0.dtsi
index 9d23230..bfd3f1c 100644
--- a/arch/arm/boot/dts/ste-dbx5x0.dtsi
+++ b/arch/arm/boot/dts/ste-dbx5x0.dtsi
@@ -11,6 +11,7 @@
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/mfd/dbx500-prcmu.h>
+#include <dt-bindings/arm/ux500_pm_domains.h>
#include "skeleton.dtsi"
/ {
@@ -43,6 +44,10 @@
interrupts = <0 7 IRQ_TYPE_LEVEL_HIGH>;
};
+ pm_domains: pm_domains0 {
+ compatible = "stericsson,ux500-pm-domains";
+ #power-domain-cells = <1>;
+ };
clocks {
compatible = "stericsson,u8500-clks";
@@ -636,6 +641,7 @@
clock-frequency = <400000>;
clocks = <&prcc_kclk 3 3>, <&prcc_pclk 3 3>;
clock-names = "i2cclk", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
i2c@80122000 {
@@ -651,6 +657,7 @@
clocks = <&prcc_kclk 1 2>, <&prcc_pclk 1 2>;
clock-names = "i2cclk", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
i2c@80128000 {
@@ -666,6 +673,7 @@
clocks = <&prcc_kclk 1 6>, <&prcc_pclk 1 6>;
clock-names = "i2cclk", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
i2c@80110000 {
@@ -681,6 +689,7 @@
clocks = <&prcc_kclk 2 0>, <&prcc_pclk 2 0>;
clock-names = "i2cclk", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
i2c@8012a000 {
@@ -696,6 +705,7 @@
clocks = <&prcc_kclk 1 9>, <&prcc_pclk 1 10>;
clock-names = "i2cclk", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
ssp@80002000 {
@@ -709,6 +719,7 @@
dmas = <&dma 8 0 0x2>, /* Logical - DevToMem */
<&dma 8 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
ssp@80003000 {
@@ -722,6 +733,7 @@
dmas = <&dma 9 0 0x2>, /* Logical - DevToMem */
<&dma 9 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
spi@8011a000 {
@@ -736,6 +748,7 @@
dmas = <&dma 0 0 0x2>, /* Logical - DevToMem */
<&dma 0 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
spi@80112000 {
@@ -750,6 +763,7 @@
dmas = <&dma 35 0 0x2>, /* Logical - DevToMem */
<&dma 35 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
spi@80111000 {
@@ -764,6 +778,7 @@
dmas = <&dma 33 0 0x2>, /* Logical - DevToMem */
<&dma 33 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
spi@80129000 {
@@ -778,6 +793,7 @@
dmas = <&dma 40 0 0x2>, /* Logical - DevToMem */
<&dma 40 0 0x0>; /* Logical - MemToDev */
dma-names = "rx", "tx";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
};
uart@80120000 {
@@ -836,6 +852,7 @@
clocks = <&prcc_kclk 1 5>, <&prcc_pclk 1 5>;
clock-names = "sdi", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled";
};
@@ -851,6 +868,7 @@
clocks = <&prcc_kclk 2 4>, <&prcc_pclk 2 6>;
clock-names = "sdi", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled";
};
@@ -866,6 +884,7 @@
clocks = <&prcc_kclk 3 4>, <&prcc_pclk 3 4>;
clock-names = "sdi", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled";
};
@@ -881,6 +900,7 @@
clocks = <&prcc_kclk 2 5>, <&prcc_pclk 2 7>;
clock-names = "sdi", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled";
};
@@ -896,6 +916,7 @@
clocks = <&prcc_kclk 2 2>, <&prcc_pclk 2 4>;
clock-names = "sdi", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled";
};
@@ -911,6 +932,7 @@
clocks = <&prcc_kclk 3 7>, <&prcc_pclk 3 7>;
clock-names = "sdi", "apb_pclk";
+ power-domains = <&pm_domains DOMAIN_VAPE>;
status = "disabled";
};
diff --git a/arch/arm/boot/dts/ste-href-ab8500.dtsi b/arch/arm/boot/dts/ste-href-ab8500.dtsi
index 30f8601..9b69bce 100644
--- a/arch/arm/boot/dts/ste-href-ab8500.dtsi
+++ b/arch/arm/boot/dts/ste-href-ab8500.dtsi
@@ -47,11 +47,11 @@
gpio2 {
gpio2_default_mode: gpio2_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio2_a_1";
+ function = "gpio";
+ groups = "gpio2_a_1";
};
default_cfg {
- ste,pins = "GPIO2_T9";
+ pins = "GPIO2_T9";
input-enable;
bias-pull-down;
};
@@ -60,11 +60,11 @@
gpio4 {
gpio4_default_mode: gpio4_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio4_a_1";
+ function = "gpio";
+ groups = "gpio4_a_1";
};
default_cfg {
- ste,pins = "GPIO4_W2";
+ pins = "GPIO4_W2";
input-enable;
bias-pull-down;
};
@@ -73,11 +73,11 @@
gpio10 {
gpio10_default_mode: gpio10_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio10_d_1";
+ function = "gpio";
+ groups = "gpio10_d_1";
};
default_cfg {
- ste,pins = "GPIO10_U17";
+ pins = "GPIO10_U17";
input-enable;
bias-pull-down;
};
@@ -86,11 +86,11 @@
gpio11 {
gpio11_default_mode: gpio11_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio11_d_1";
+ function = "gpio";
+ groups = "gpio11_d_1";
};
default_cfg {
- ste,pins = "GPIO11_AA18";
+ pins = "GPIO11_AA18";
input-enable;
bias-pull-down;
};
@@ -99,11 +99,11 @@
gpio12 {
gpio12_default_mode: gpio12_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio12_d_1";
+ function = "gpio";
+ groups = "gpio12_d_1";
};
default_cfg {
- ste,pins = "GPIO12_U16";
+ pins = "GPIO12_U16";
input-enable;
bias-pull-down;
};
@@ -112,11 +112,11 @@
gpio13 {
gpio13_default_mode: gpio13_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio13_d_1";
+ function = "gpio";
+ groups = "gpio13_d_1";
};
default_cfg {
- ste,pins = "GPIO13_W17";
+ pins = "GPIO13_W17";
input-enable;
bias-pull-down;
};
@@ -125,11 +125,11 @@
gpio16 {
gpio16_default_mode: gpio16_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio16_a_1";
+ function = "gpio";
+ groups = "gpio16_a_1";
};
default_cfg {
- ste,pins = "GPIO16_F15";
+ pins = "GPIO16_F15";
input-enable;
bias-pull-down;
};
@@ -138,11 +138,11 @@
gpio24 {
gpio24_default_mode: gpio24_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio24_a_1";
+ function = "gpio";
+ groups = "gpio24_a_1";
};
default_cfg {
- ste,pins = "GPIO24_T14";
+ pins = "GPIO24_T14";
input-enable;
bias-pull-down;
};
@@ -151,11 +151,11 @@
gpio25 {
gpio25_default_mode: gpio25_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio25_a_1";
+ function = "gpio";
+ groups = "gpio25_a_1";
};
default_cfg {
- ste,pins = "GPIO25_R16";
+ pins = "GPIO25_R16";
input-enable;
bias-pull-down;
};
@@ -164,11 +164,11 @@
gpio36 {
gpio36_default_mode: gpio36_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio36_a_1";
+ function = "gpio";
+ groups = "gpio36_a_1";
};
default_cfg {
- ste,pins = "GPIO36_A17";
+ pins = "GPIO36_A17";
input-enable;
bias-pull-down;
};
@@ -177,11 +177,11 @@
gpio37 {
gpio37_default_mode: gpio37_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio37_a_1";
+ function = "gpio";
+ groups = "gpio37_a_1";
};
default_cfg {
- ste,pins = "GPIO37_E15";
+ pins = "GPIO37_E15";
input-enable;
bias-pull-down;
};
@@ -190,11 +190,11 @@
gpio38 {
gpio38_default_mode: gpio38_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio38_a_1";
+ function = "gpio";
+ groups = "gpio38_a_1";
};
default_cfg {
- ste,pins = "GPIO38_C17";
+ pins = "GPIO38_C17";
input-enable;
bias-pull-down;
};
@@ -203,11 +203,11 @@
gpio39 {
gpio39_default_mode: gpio39_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio39_a_1";
+ function = "gpio";
+ groups = "gpio39_a_1";
};
default_cfg {
- ste,pins = "GPIO39_E16";
+ pins = "GPIO39_E16";
input-enable;
bias-pull-down;
};
@@ -216,11 +216,11 @@
gpio42 {
gpio42_default_mode: gpio42_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio42_a_1";
+ function = "gpio";
+ groups = "gpio42_a_1";
};
default_cfg {
- ste,pins = "GPIO42_U2";
+ pins = "GPIO42_U2";
input-enable;
bias-pull-down;
};
@@ -232,11 +232,11 @@
gpio26 {
gpio26_default_mode: gpio26_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio26_d_1";
+ function = "gpio";
+ groups = "gpio26_d_1";
};
default_cfg {
- ste,pins = "GPIO26_M16";
+ pins = "GPIO26_M16";
output-low;
};
};
@@ -244,11 +244,11 @@
gpio35 {
gpio35_default_mode: gpio35_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio35_d_1";
+ function = "gpio";
+ groups = "gpio35_d_1";
};
default_cfg {
- ste,pins = "GPIO35_W15";
+ pins = "GPIO35_W15";
output-low;
};
};
@@ -260,11 +260,11 @@
ycbcr {
ycbcr_default_mode: ycbcr_default {
default_mux {
- ste,function = "ycbcr";
- ste,pins = "ycbcr0123_d_1";
+ function = "ycbcr";
+ groups = "ycbcr0123_d_1";
};
default_cfg {
- ste,pins = "GPIO6_Y18",
+ pins = "GPIO6_Y18",
"GPIO7_AA20",
"GPIO8_W18",
"GPIO9_AA19";
@@ -277,11 +277,11 @@
pwm {
pwm_default_mode: pwm_default {
default_mux {
- ste,function = "pwmout";
- ste,pins = "pwmout1_d_1", "pwmout2_d_1";
+ function = "pwmout";
+ groups = "pwmout1_d_1", "pwmout2_d_1";
};
default_cfg {
- ste,pins = "GPIO14_F14",
+ pins = "GPIO14_F14",
"GPIO15_B17";
input-enable;
bias-pull-down;
@@ -292,11 +292,11 @@
adi1 {
adi1_default_mode: adi1_default {
default_mux {
- ste,function = "adi1";
- ste,pins = "adi1_d_1";
+ function = "adi1";
+ groups = "adi1_d_1";
};
default_cfg {
- ste,pins = "GPIO17_P5",
+ pins = "GPIO17_P5",
"GPIO18_R5",
"GPIO19_U5",
"GPIO20_T5";
@@ -309,11 +309,11 @@
usbuicc {
usbuicc_default_mode: usbuicc_default {
default_mux {
- ste,function = "usbuicc";
- ste,pins = "usbuicc_d_1";
+ function = "usbuicc";
+ groups = "usbuicc_d_1";
};
default_cfg {
- ste,pins = "GPIO21_H19",
+ pins = "GPIO21_H19",
"GPIO22_G20",
"GPIO23_G19";
input-enable;
@@ -325,13 +325,13 @@
dmic {
dmic_default_mode: dmic_default {
default_mux {
- ste,function = "dmic";
- ste,pins = "dmic12_d_1",
+ function = "dmic";
+ groups = "dmic12_d_1",
"dmic34_d_1",
"dmic56_d_1";
};
default_cfg {
- ste,pins = "GPIO27_J6",
+ pins = "GPIO27_J6",
"GPIO28_K6",
"GPIO29_G6",
"GPIO30_H6",
@@ -345,11 +345,11 @@
extcpena {
extcpena_default_mode: extcpena_default {
default_mux {
- ste,function = "extcpena";
- ste,pins = "extcpena_d_1";
+ function = "extcpena";
+ groups = "extcpena_d_1";
};
default_cfg {
- ste,pins = "GPIO34_R17";
+ pins = "GPIO34_R17";
input-enable;
bias-pull-down;
};
@@ -359,11 +359,11 @@
modsclsda {
modsclsda_default_mode: modsclsda_default {
default_mux {
- ste,function = "modsclsda";
- ste,pins = "modsclsda_d_1";
+ function = "modsclsda";
+ groups = "modsclsda_d_1";
};
default_cfg {
- ste,pins = "GPIO40_T19",
+ pins = "GPIO40_T19",
"GPIO41_U19";
input-enable;
bias-pull-down;
@@ -376,22 +376,22 @@
sysclkreq2 {
sysclkreq2_default_mode: sysclkreq2_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq2_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq2_d_1";
};
default_cfg {
- ste,pins = "GPIO1_T10";
+ pins = "GPIO1_T10";
input-enable;
bias-disable;
};
};
sysclkreq2_sleep_mode: sysclkreq2_sleep {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio1_a_1";
+ function = "gpio";
+ groups = "gpio1_a_1";
};
default_cfg {
- ste,pins = "GPIO1_T10";
+ pins = "GPIO1_T10";
input-enable;
bias-pull-down;
};
@@ -400,22 +400,22 @@
sysclkreq4 {
sysclkreq4_default_mode: sysclkreq4_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq4_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq4_d_1";
};
default_cfg {
- ste,pins = "GPIO3_U9";
+ pins = "GPIO3_U9";
input-enable;
bias-disable;
};
};
sysclkreq4_sleep_mode: sysclkreq4_sleep {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio3_a_1";
+ function = "gpio";
+ groups = "gpio3_a_1";
};
default_cfg {
- ste,pins = "GPIO3_U9";
+ pins = "GPIO3_U9";
input-enable;
bias-pull-down;
};
diff --git a/arch/arm/boot/dts/ste-href-ab8505.dtsi b/arch/arm/boot/dts/ste-href-ab8505.dtsi
index 6006d62..ccf37a9 100644
--- a/arch/arm/boot/dts/ste-href-ab8505.dtsi
+++ b/arch/arm/boot/dts/ste-href-ab8505.dtsi
@@ -35,11 +35,11 @@
gpio2 {
gpio2_default_mode: gpio2_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio2_a_1";
+ function = "gpio";
+ groups = "gpio2_a_1";
};
default_cfg {
- ste,pins = "GPIO2_R5";
+ pins = "GPIO2_R5";
input-enable;
bias-pull-down;
};
@@ -48,11 +48,11 @@
gpio10 {
gpio10_default_mode: gpio10_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio10_d_1";
+ function = "gpio";
+ groups = "gpio10_d_1";
};
default_cfg {
- ste,pins = "GPIO10_B16";
+ pins = "GPIO10_B16";
input-enable;
bias-pull-down;
};
@@ -61,11 +61,11 @@
gpio11 {
gpio11_default_mode: gpio11_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio11_d_1";
+ function = "gpio";
+ groups = "gpio11_d_1";
};
default_cfg {
- ste,pins = "GPIO11_B17";
+ pins = "GPIO11_B17";
input-enable;
bias-pull-down;
};
@@ -74,11 +74,11 @@
gpio13 {
gpio13_default_mode: gpio13_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio13_d_1";
+ function = "gpio";
+ groups = "gpio13_d_1";
};
default_cfg {
- ste,pins = "GPIO13_D17";
+ pins = "GPIO13_D17";
input-enable;
bias-disable;
};
@@ -87,11 +87,11 @@
gpio34 {
gpio34_default_mode: gpio34_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio34_a_1";
+ function = "gpio";
+ groups = "gpio34_a_1";
};
default_cfg {
- ste,pins = "GPIO34_H14";
+ pins = "GPIO34_H14";
input-enable;
bias-pull-down;
};
@@ -100,11 +100,11 @@
gpio50 {
gpio50_default_mode: gpio50_default {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio50_d_1";
+ function = "gpio";
+ groups = "gpio50_d_1";
};
default_cfg {
- ste,pins = "GPIO50_L4";
+ pins = "GPIO50_L4";
input-enable;
bias-disable;
};
@@ -114,11 +114,11 @@
pwm {
pwm_default_mode: pwm_default {
default_mux {
- ste,function = "pwmout";
- ste,pins = "pwmout1_d_1";
+ function = "pwmout";
+ groups = "pwmout1_d_1";
};
default_cfg {
- ste,pins = "GPIO14_C16";
+ pins = "GPIO14_C16";
input-enable;
bias-pull-down;
};
@@ -128,11 +128,11 @@
adi2 {
adi2_default_mode: adi2_default {
default_mux {
- ste,function = "adi2";
- ste,pins = "adi2_d_1";
+ function = "adi2";
+ groups = "adi2_d_1";
};
default_cfg {
- ste,pins = "GPIO17_P2",
+ pins = "GPIO17_P2",
"GPIO18_N3",
"GPIO19_T1",
"GPIO20_P3";
@@ -145,11 +145,11 @@
modsclsda {
modsclsda_default_mode: modsclsda_default {
default_mux {
- ste,function = "modsclsda";
- ste,pins = "modsclsda_d_1";
+ function = "modsclsda";
+ groups = "modsclsda_d_1";
};
default_cfg {
- ste,pins = "GPIO40_J15",
+ pins = "GPIO40_J15",
"GPIO41_J14";
input-enable;
bias-pull-down;
@@ -159,11 +159,11 @@
resethw {
resethw_default_mode: resethw_default {
default_mux {
- ste,function = "resethw";
- ste,pins = "resethw_d_1";
+ function = "resethw";
+ groups = "resethw_d_1";
};
default_cfg {
- ste,pins = "GPIO52_D16";
+ pins = "GPIO52_D16";
input-enable;
bias-pull-down;
};
@@ -172,11 +172,11 @@
service {
service_default_mode: service_default {
default_mux {
- ste,function = "service";
- ste,pins = "service_d_1";
+ function = "service";
+ groups = "service_d_1";
};
default_cfg {
- ste,pins = "GPIO53_D15";
+ pins = "GPIO53_D15";
input-enable;
bias-pull-down;
};
@@ -188,22 +188,22 @@
sysclkreq2 {
sysclkreq2_default_mode: sysclkreq2_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq2_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq2_d_1";
};
default_cfg {
- ste,pins = "GPIO1_N4";
+ pins = "GPIO1_N4";
input-enable;
bias-disable;
};
};
sysclkreq2_sleep_mode: sysclkreq2_sleep {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio1_a_1";
+ function = "gpio";
+ groups = "gpio1_a_1";
};
default_cfg {
- ste,pins = "GPIO1_N4";
+ pins = "GPIO1_N4";
input-enable;
bias-pull-down;
};
@@ -212,22 +212,22 @@
sysclkreq4 {
sysclkreq4_default_mode: sysclkreq4_default {
default_mux {
- ste,function = "sysclkreq";
- ste,pins = "sysclkreq4_d_1";
+ function = "sysclkreq";
+ groups = "sysclkreq4_d_1";
};
default_cfg {
- ste,pins = "GPIO3_P5";
+ pins = "GPIO3_P5";
input-enable;
bias-disable;
};
};
sysclkreq4_sleep_mode: sysclkreq4_sleep {
default_mux {
- ste,function = "gpio";
- ste,pins = "gpio3_a_1";
+ function = "gpio";
+ groups = "gpio3_a_1";
};
default_cfg {
- ste,pins = "GPIO3_P5";
+ pins = "GPIO3_P5";
input-enable;
bias-pull-down;
};
diff --git a/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi b/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi
index addfcc7..5c5cea2 100644
--- a/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi
+++ b/arch/arm/boot/dts/ste-href-family-pinctrl.dtsi
@@ -18,33 +18,33 @@
uart0 {
uart0_default_mode: uart0_default {
default_mux {
- ste,function = "u0";
- ste,pins = "u0_a_1";
+ function = "u0";
+ groups = "u0_a_1";
};
default_cfg1 {
- ste,pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */
+ pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */
ste,config = <&in_pu>;
};
default_cfg2 {
- ste,pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */
+ pins = "GPIO1_AJ3", "GPIO3_AH3"; /* RTS+TXD */
ste,config = <&out_hi>;
};
};
uart0_sleep_mode: uart0_sleep {
sleep_cfg1 {
- ste,pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */
+ pins = "GPIO0_AJ5", "GPIO2_AH4"; /* CTS+RXD */
ste,config = <&slpm_in_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins = "GPIO1_AJ3"; /* RTS */
+ pins = "GPIO1_AJ3"; /* RTS */
ste,config = <&slpm_out_hi_wkup_pdis>;
};
sleep_cfg3 {
- ste,pins = "GPIO3_AH3"; /* TXD */
+ pins = "GPIO3_AH3"; /* TXD */
ste,config = <&slpm_out_wkup_pdis>;
};
};
@@ -53,28 +53,28 @@
uart1 {
uart1_default_mode: uart1_default {
default_mux {
- ste,function = "u1";
- ste,pins = "u1rxtx_a_1";
+ function = "u1";
+ groups = "u1rxtx_a_1";
};
default_cfg1 {
- ste,pins = "GPIO4_AH6"; /* RXD */
+ pins = "GPIO4_AH6"; /* RXD */
ste,config = <&in_pu>;
};
default_cfg2 {
- ste,pins = "GPIO5_AG6"; /* TXD */
+ pins = "GPIO5_AG6"; /* TXD */
ste,config = <&out_hi>;
};
};
uart1_sleep_mode: uart1_sleep {
sleep_cfg1 {
- ste,pins = "GPIO4_AH6"; /* RXD */
+ pins = "GPIO4_AH6"; /* RXD */
ste,config = <&slpm_in_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins = "GPIO5_AG6"; /* TXD */
+ pins = "GPIO5_AG6"; /* TXD */
ste,config = <&slpm_out_wkup_pdis>;
};
};
@@ -83,28 +83,28 @@
uart2 {
uart2_default_mode: uart2_default {
default_mux {
- ste,function = "u2";
- ste,pins = "u2rxtx_c_1";
+ function = "u2";
+ groups = "u2rxtx_c_1";
};
default_cfg1 {
- ste,pins = "GPIO29_W2"; /* RXD */
+ pins = "GPIO29_W2"; /* RXD */
ste,config = <&in_pu>;
};
default_cfg2 {
- ste,pins = "GPIO30_W3"; /* TXD */
+ pins = "GPIO30_W3"; /* TXD */
ste,config = <&out_hi>;
};
};
uart2_sleep_mode: uart2_sleep {
sleep_cfg1 {
- ste,pins = "GPIO29_W2"; /* RXD */
+ pins = "GPIO29_W2"; /* RXD */
ste,config = <&in_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins = "GPIO30_W3"; /* TXD */
+ pins = "GPIO30_W3"; /* TXD */
ste,config = <&out_wkup_pdis>;
};
};
@@ -114,18 +114,18 @@
i2c0 {
i2c0_default_mode: i2c_default {
default_mux {
- ste,function = "i2c0";
- ste,pins = "i2c0_a_1";
+ function = "i2c0";
+ groups = "i2c0_a_1";
};
default_cfg1 {
- ste,pins = "GPIO147_C15", "GPIO148_B16"; /* SDA/SCL */
+ pins = "GPIO147_C15", "GPIO148_B16"; /* SDA/SCL */
ste,config = <&in_pu>;
};
};
i2c0_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO147_C15", "GPIO148_B16"; /* SDA/SCL */
+ pins = "GPIO147_C15", "GPIO148_B16"; /* SDA/SCL */
ste,config = <&slpm_in_wkup_pdis>;
};
};
@@ -134,18 +134,18 @@
i2c1 {
i2c1_default_mode: i2c_default {
default_mux {
- ste,function = "i2c1";
- ste,pins = "i2c1_b_2";
+ function = "i2c1";
+ groups = "i2c1_b_2";
};
default_cfg1 {
- ste,pins = "GPIO16_AD3", "GPIO17_AD4"; /* SDA/SCL */
+ pins = "GPIO16_AD3", "GPIO17_AD4"; /* SDA/SCL */
ste,config = <&in_pu>;
};
};
i2c1_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO16_AD3", "GPIO17_AD4"; /* SDA/SCL */
+ pins = "GPIO16_AD3", "GPIO17_AD4"; /* SDA/SCL */
ste,config = <&slpm_in_wkup_pdis>;
};
};
@@ -154,18 +154,18 @@
i2c2 {
i2c2_default_mode: i2c_default {
default_mux {
- ste,function = "i2c2";
- ste,pins = "i2c2_b_2";
+ function = "i2c2";
+ groups = "i2c2_b_2";
};
default_cfg1 {
- ste,pins = "GPIO10_AF5", "GPIO11_AG4"; /* SDA/SCL */
+ pins = "GPIO10_AF5", "GPIO11_AG4"; /* SDA/SCL */
ste,config = <&in_pu>;
};
};
i2c2_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO10_AF5", "GPIO11_AG4"; /* SDA/SCL */
+ pins = "GPIO10_AF5", "GPIO11_AG4"; /* SDA/SCL */
ste,config = <&slpm_in_wkup_pdis>;
};
};
@@ -174,18 +174,18 @@
i2c3 {
i2c3_default_mode: i2c_default {
default_mux {
- ste,function = "i2c3";
- ste,pins = "i2c3_c_2";
+ function = "i2c3";
+ groups = "i2c3_c_2";
};
default_cfg1 {
- ste,pins = "GPIO229_AG7", "GPIO230_AF7"; /* SDA/SCL */
+ pins = "GPIO229_AG7", "GPIO230_AF7"; /* SDA/SCL */
ste,config = <&in_pu>;
};
};
i2c3_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO229_AG7", "GPIO230_AF7"; /* SDA/SCL */
+ pins = "GPIO229_AG7", "GPIO230_AF7"; /* SDA/SCL */
ste,config = <&slpm_in_wkup_pdis>;
};
};
@@ -198,18 +198,18 @@
i2c4 {
i2c4_default_mode: i2c_default {
default_mux {
- ste,function = "i2c4";
- ste,pins = "i2c4_b_1";
+ function = "i2c4";
+ groups = "i2c4_b_1";
};
default_cfg1 {
- ste,pins = "GPIO4_AH6", "GPIO5_AG6"; /* SDA/SCL */
+ pins = "GPIO4_AH6", "GPIO5_AG6"; /* SDA/SCL */
ste,config = <&in_pu>;
};
};
i2c4_sleep_mode: i2c_sleep {
sleep_cfg1 {
- ste,pins = "GPIO4_AH6", "GPIO5_AG6"; /* SDA/SCL */
+ pins = "GPIO4_AH6", "GPIO5_AG6"; /* SDA/SCL */
ste,config = <&slpm_in_wkup_pdis>;
};
};
@@ -219,19 +219,19 @@
spi2 {
spi2_default_mode: spi_default {
default_mux {
- ste,function = "spi2";
- ste,pins = "spi2_oc1_2";
+ function = "spi2";
+ groups = "spi2_oc1_2";
};
default_cfg1 {
- ste,pins = "GPIO216_AG12"; /* FRM */
+ pins = "GPIO216_AG12"; /* FRM */
ste,config = <&gpio_out_hi>;
};
default_cfg2 {
- ste,pins = "GPIO218_AH11"; /* RXD */
+ pins = "GPIO218_AH11"; /* RXD */
ste,config = <&in_pd>;
};
default_cfg3 {
- ste,pins =
+ pins =
"GPIO215_AH13", /* TXD */
"GPIO217_AH12"; /* CLK */
ste,config = <&out_lo>;
@@ -245,32 +245,32 @@
* as we do not state any muxing.
*/
idle_cfg1 {
- ste,pins = "GPIO218_AH11"; /* RXD */
+ pins = "GPIO218_AH11"; /* RXD */
ste,config = <&slpm_in_pdis>;
};
idle_cfg2 {
- ste,pins = "GPIO215_AH13"; /* TXD */
+ pins = "GPIO215_AH13"; /* TXD */
ste,config = <&slpm_out_lo_pdis>;
};
idle_cfg3 {
- ste,pins = "GPIO217_AH12"; /* CLK */
+ pins = "GPIO217_AH12"; /* CLK */
ste,config = <&slpm_pdis>;
};
};
spi2_sleep_mode: spi_sleep {
sleep_cfg1 {
- ste,pins =
+ pins =
"GPIO216_AG12", /* FRM */
"GPIO218_AH11"; /* RXD */
ste,config = <&slpm_in_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins = "GPIO215_AH13"; /* TXD */
+ pins = "GPIO215_AH13"; /* TXD */
ste,config = <&slpm_out_lo_wkup_pdis>;
};
sleep_cfg3 {
- ste,pins = "GPIO217_AH12"; /* CLK */
+ pins = "GPIO217_AH12"; /* CLK */
ste,config = <&slpm_wkup_pdis>;
};
};
@@ -281,26 +281,26 @@
/* This is the external SD card slot, 4 bits wide */
sdi0_default_mode: sdi0_default {
default_mux {
- ste,function = "mc0";
- ste,pins = "mc0_a_1";
+ function = "mc0";
+ groups = "mc0_a_1";
};
default_cfg1 {
- ste,pins =
+ pins =
"GPIO18_AC2", /* CMDDIR */
"GPIO19_AC1", /* DAT0DIR */
"GPIO20_AB4"; /* DAT2DIR */
ste,config = <&out_hi>;
};
default_cfg2 {
- ste,pins = "GPIO22_AA3"; /* FBCLK */
+ pins = "GPIO22_AA3"; /* FBCLK */
ste,config = <&in_nopull>;
};
default_cfg3 {
- ste,pins = "GPIO23_AA4"; /* CLK */
+ pins = "GPIO23_AA4"; /* CLK */
ste,config = <&out_lo>;
};
default_cfg4 {
- ste,pins =
+ pins =
"GPIO24_AB2", /* CMD */
"GPIO25_Y4", /* DAT0 */
"GPIO26_Y2", /* DAT1 */
@@ -312,14 +312,14 @@
sdi0_sleep_mode: sdi0_sleep {
sleep_cfg1 {
- ste,pins =
+ pins =
"GPIO18_AC2", /* CMDDIR */
"GPIO19_AC1", /* DAT0DIR */
"GPIO20_AB4"; /* DAT2DIR */
ste,config = <&slpm_out_hi_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins =
+ pins =
"GPIO22_AA3", /* FBCLK */
"GPIO24_AB2", /* CMD */
"GPIO25_Y4", /* DAT0 */
@@ -329,7 +329,7 @@
ste,config = <&slpm_in_wkup_pdis>;
};
sleep_cfg3 {
- ste,pins = "GPIO23_AA4"; /* CLK */
+ pins = "GPIO23_AA4"; /* CLK */
ste,config = <&slpm_out_lo_wkup_pdis>;
};
};
@@ -339,19 +339,19 @@
/* This is the WLAN SDIO 4 bits wide */
sdi1_default_mode: sdi1_default {
default_mux {
- ste,function = "mc1";
- ste,pins = "mc1_a_1";
+ function = "mc1";
+ groups = "mc1_a_1";
};
default_cfg1 {
- ste,pins = "GPIO208_AH16"; /* CLK */
+ pins = "GPIO208_AH16"; /* CLK */
ste,config = <&out_lo>;
};
default_cfg2 {
- ste,pins = "GPIO209_AG15"; /* FBCLK */
+ pins = "GPIO209_AG15"; /* FBCLK */
ste,config = <&in_nopull>;
};
default_cfg3 {
- ste,pins =
+ pins =
"GPIO210_AJ15", /* CMD */
"GPIO211_AG14", /* DAT0 */
"GPIO212_AF13", /* DAT1 */
@@ -363,11 +363,11 @@
sdi1_sleep_mode: sdi1_sleep {
sleep_cfg1 {
- ste,pins = "GPIO208_AH16"; /* CLK */
+ pins = "GPIO208_AH16"; /* CLK */
ste,config = <&slpm_out_lo_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins =
+ pins =
"GPIO209_AG15", /* FBCLK */
"GPIO210_AJ15", /* CMD */
"GPIO211_AG14", /* DAT0 */
@@ -383,19 +383,19 @@
/* This is the eMMC 8 bits wide, usually PoP eMMC */
sdi2_default_mode: sdi2_default {
default_mux {
- ste,function = "mc2";
- ste,pins = "mc2_a_1";
+ function = "mc2";
+ groups = "mc2_a_1";
};
default_cfg1 {
- ste,pins = "GPIO128_A5"; /* CLK */
+ pins = "GPIO128_A5"; /* CLK */
ste,config = <&out_lo>;
};
default_cfg2 {
- ste,pins = "GPIO130_C8"; /* FBCLK */
+ pins = "GPIO130_C8"; /* FBCLK */
ste,config = <&in_nopull>;
};
default_cfg3 {
- ste,pins =
+ pins =
"GPIO129_B4", /* CMD */
"GPIO131_A12", /* DAT0 */
"GPIO132_C10", /* DAT1 */
@@ -411,17 +411,17 @@
sdi2_sleep_mode: sdi2_sleep {
sleep_cfg1 {
- ste,pins = "GPIO128_A5"; /* CLK */
+ pins = "GPIO128_A5"; /* CLK */
ste,config = <&out_lo_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins =
+ pins =
"GPIO130_C8", /* FBCLK */
"GPIO129_B4"; /* CMD */
ste,config = <&in_wkup_pdis_en>;
};
sleep_cfg3 {
- ste,pins =
+ pins =
"GPIO131_A12", /* DAT0 */
"GPIO132_C10", /* DAT1 */
"GPIO133_B10", /* DAT2 */
@@ -439,19 +439,19 @@
/* This is the eMMC 8 bits wide, usually PCB-mounted eMMC */
sdi4_default_mode: sdi4_default {
default_mux {
- ste,function = "mc4";
- ste,pins = "mc4_a_1";
+ function = "mc4";
+ groups = "mc4_a_1";
};
default_cfg1 {
- ste,pins = "GPIO203_AE23"; /* CLK */
+ pins = "GPIO203_AE23"; /* CLK */
ste,config = <&out_lo>;
};
default_cfg2 {
- ste,pins = "GPIO202_AF25"; /* FBCLK */
+ pins = "GPIO202_AF25"; /* FBCLK */
ste,config = <&in_nopull>;
};
default_cfg3 {
- ste,pins =
+ pins =
"GPIO201_AF24", /* CMD */
"GPIO200_AH26", /* DAT0 */
"GPIO199_AH23", /* DAT1 */
@@ -467,11 +467,11 @@
sdi4_sleep_mode: sdi4_sleep {
sleep_cfg1 {
- ste,pins = "GPIO203_AE23"; /* CLK */
+ pins = "GPIO203_AE23"; /* CLK */
ste,config = <&out_lo_wkup_pdis>;
};
sleep_cfg2 {
- ste,pins =
+ pins =
"GPIO202_AF25", /* FBCLK */
"GPIO201_AF24", /* CMD */
"GPIO200_AH26", /* DAT0 */
@@ -494,11 +494,11 @@
msp0 {
msp0_default_mode: msp0_default {
default_msp0_mux {
- ste,function = "msp0";
- ste,pins = "msp0txrx_a_1", "msp0tfstck_a_1";
+ function = "msp0";
+ groups = "msp0txrx_a_1", "msp0tfstck_a_1";
};
default_msp0_cfg {
- ste,pins =
+ pins =
"GPIO12_AC4", /* TXD */
"GPIO15_AC3", /* RXD */
"GPIO13_AF3", /* TFS */
@@ -511,15 +511,15 @@
msp1 {
msp1_default_mode: msp1_default {
default_mux {
- ste,function = "msp1";
- ste,pins = "msp1txrx_a_1", "msp1_a_1";
+ function = "msp1";
+ groups = "msp1txrx_a_1", "msp1_a_1";
};
default_cfg1 {
- ste,pins = "GPIO33_AF2";
+ pins = "GPIO33_AF2";
ste,config = <&out_lo>;
};
default_cfg2 {
- ste,pins =
+ pins =
"GPIO34_AE1",
"GPIO35_AE2",
"GPIO36_AG2";
@@ -533,18 +533,18 @@
msp2_default_mode: msp2_default {
/* MSP2 usually used for HDMI audio */
default_mux {
- ste,function = "msp2";
- ste,pins = "msp2_a_1";
+ function = "msp2";
+ groups = "msp2_a_1";
};
default_cfg1 {
- ste,pins =
+ pins =
"GPIO193_AH27", /* TXD */
"GPIO194_AF27", /* TCK */
"GPIO195_AG28"; /* TFS */
ste,config = <&in_pd>;
};
default_cfg2 {
- ste,pins = "GPIO196_AG26"; /* RXD */
+ pins = "GPIO196_AG26"; /* RXD */
ste,config = <&out_lo>;
};
};
@@ -554,11 +554,11 @@
musb {
musb_default_mode: musb_default {
default_mux {
- ste,function = "usb";
- ste,pins = "usb_a_1";
+ function = "usb";
+ groups = "usb_a_1";
};
default_cfg1 {
- ste,pins =
+ pins =
"GPIO256_AF28", /* NXT */
"GPIO258_AD29", /* XCLK */
"GPIO259_AC29", /* DIR */
@@ -573,25 +573,25 @@
ste,config = <&in_nopull>;
};
default_cfg2 {
- ste,pins = "GPIO257_AE29"; /* STP */
+ pins = "GPIO257_AE29"; /* STP */
ste,config = <&out_hi>;
};
};
musb_sleep_mode: musb_sleep {
sleep_cfg1 {
- ste,pins =
+ pins =
"GPIO256_AF28", /* NXT */
"GPIO258_AD29", /* XCLK */
"GPIO259_AC29"; /* DIR */
ste,config = <&slpm_wkup_pdis_en>;
};
sleep_cfg2 {
- ste,pins = "GPIO257_AE29"; /* STP */
+ pins = "GPIO257_AE29"; /* STP */
ste,config = <&slpm_out_hi_wkup_pdis>;
};
sleep_cfg3 {
- ste,pins =
+ pins =
"GPIO260_AD28", /* DAT7 */
"GPIO261_AD26", /* DAT6 */
"GPIO262_AE26", /* DAT5 */
@@ -609,8 +609,8 @@
lcd_default_mode: lcd_default {
default_mux {
/* Mux in VSI0 and all the data lines */
- ste,function = "lcd";
- ste,pins =
+ function = "lcd";
+ groups =
"lcdvsi0_a_1", /* VSI0 for LCD */
"lcd_d0_d7_a_1", /* Data lines */
"lcd_d8_d11_a_1", /* TV-out */
@@ -618,7 +618,7 @@
"lcdvsi1_a_1"; /* VSI1 for HDMI */
};
default_cfg1 {
- ste,pins =
+ pins =
"GPIO68_E1", /* VSI0 */
"GPIO69_E2"; /* VSI1 */
ste,config = <&in_pu>;
@@ -626,7 +626,7 @@
};
lcd_sleep_mode: lcd_sleep {
sleep_cfg1 {
- ste,pins = "GPIO69_E2"; /* VSI1 */
+ pins = "GPIO69_E2"; /* VSI1 */
ste,config = <&slpm_in_wkup_pdis>;
};
};
@@ -636,11 +636,11 @@
/* SKE keys on position 2 in an 8x8 matrix */
ske_kpa2_default_mode: ske_kpa2_default {
default_mux {
- ste,function = "kp";
- ste,pins = "kp_a_2";
+ function = "kp";
+ groups = "kp_a_2";
};
default_cfg1 {
- ste,pins =
+ pins =
"GPIO153_B17", /* I7 */
"GPIO154_C16", /* I6 */
"GPIO155_C19", /* I5 */
@@ -652,7 +652,7 @@
ste,config = <&in_pd>;
};
default_cfg2 {
- ste,pins =
+ pins =
"GPIO157_A18", /* O7 */
"GPIO158_C18", /* O6 */
"GPIO159_B19", /* O5 */
@@ -666,7 +666,7 @@
};
ske_kpa2_sleep_mode: ske_kpa2_sleep {
sleep_cfg1 {
- ste,pins =
+ pins =
"GPIO153_B17", /* I7 */
"GPIO154_C16", /* I6 */
"GPIO155_C19", /* I5 */
@@ -678,7 +678,7 @@
ste,config = <&slpm_in_pu_wkup_pdis_en>;
};
sleep_cfg2 {
- ste,pins =
+ pins =
"GPIO157_A18", /* O7 */
"GPIO158_C18", /* O6 */
"GPIO159_B19", /* O5 */
@@ -696,11 +696,11 @@
*/
ske_kpaoc1_default_mode: ske_kpaoc1_default {
default_mux {
- ste,function = "kp";
- ste,pins = "kp_a_1", "kp_oc1_1";
+ function = "kp";
+ groups = "kp_a_1", "kp_oc1_1";
};
default_cfg1 {
- ste,pins =
+ pins =
"GPIO91_B6", /* KP_O0 */
"GPIO90_A3", /* KP_O1 */
"GPIO87_B3", /* KP_O2 */
@@ -710,7 +710,7 @@
ste,config = <&out_lo>;
};
default_cfg2 {
- ste,pins =
+ pins =
"GPIO93_B7", /* KP_I0 */
"GPIO92_D6", /* KP_I1 */
"GPIO89_E6", /* KP_I2 */
@@ -729,13 +729,13 @@
* These are plain GPIO pins used by WLAN
*/
default_cfg1 {
- ste,pins =
+ pins =
"GPIO226_AF8", /* WLAN_PMU_EN */
"GPIO85_D5"; /* WLAN_ENA */
ste,config = <&gpio_out_lo>;
};
default_cfg2 {
- ste,pins = "GPIO4_AH6"; /* WLAN_IRQ on UART1 */
+ pins = "GPIO4_AH6"; /* WLAN_IRQ on UART1 */
ste,config = <&gpio_in_pu>;
};
};
diff --git a/arch/arm/boot/dts/ste-href-stuib.dtsi b/arch/arm/boot/dts/ste-href-stuib.dtsi
index 84d7c5d..7d4f818 100644
--- a/arch/arm/boot/dts/ste-href-stuib.dtsi
+++ b/arch/arm/boot/dts/ste-href-stuib.dtsi
@@ -103,7 +103,7 @@
prox {
prox_stuib_mode: prox_stuib {
stuib_cfg {
- ste,pins = "GPIO217_AH12";
+ pins = "GPIO217_AH12";
ste,config = <&gpio_in_pu>;
};
};
@@ -111,7 +111,7 @@
hall {
hall_stuib_mode: stuib_tvk {
stuib_cfg {
- ste,pins = "GPIO145_C13";
+ pins = "GPIO145_C13";
ste,config = <&gpio_in_pu>;
};
};
diff --git a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
index 18b65d1..062c6aa 100644
--- a/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
+++ b/arch/arm/boot/dts/ste-href-tvk1281618.dtsi
@@ -130,7 +130,7 @@
tc35893 {
tc35893_tvk_mode: tc35893_tvk {
tvk_cfg {
- ste,pins = "GPIO218_AH11";
+ pins = "GPIO218_AH11";
ste,config = <&gpio_in_pu>;
};
};
@@ -138,7 +138,7 @@
prox {
prox_tvk_mode: prox_tvk {
tvk_cfg {
- ste,pins = "GPIO217_AH12";
+ pins = "GPIO217_AH12";
ste,config = <&gpio_in_pu>;
};
};
@@ -146,7 +146,7 @@
hall {
hall_tvk_mode: hall_tvk {
tvk_cfg {
- ste,pins = "GPIO145_C13";
+ pins = "GPIO145_C13";
ste,config = <&gpio_in_pu>;
};
};
@@ -155,7 +155,7 @@
accel_tvk_mode: accel_tvk {
/* Accelerometer interrupt lines 1 & 2 */
tvk_cfg {
- ste,pins = "GPIO82_C1", "GPIO83_D3";
+ pins = "GPIO82_C1", "GPIO83_D3";
ste,config = <&gpio_in_pu>;
};
};
@@ -164,11 +164,11 @@
magneto_tvk_mode: magneto_tvk {
/* Magnetometer uses GPIO 31 and 32, pull these up/down respectively */
tvk_cfg1 {
- ste,pins = "GPIO31_V3";
+ pins = "GPIO31_V3";
ste,config = <&gpio_in_pu>;
};
tvk_cfg2 {
- ste,pins = "GPIO32_V2";
+ pins = "GPIO32_V2";
ste,config = <&gpio_in_pd>;
};
};
diff --git a/arch/arm/boot/dts/ste-hrefprev60.dtsi b/arch/arm/boot/dts/ste-hrefprev60.dtsi
index abc762e..7f3975b 100644
--- a/arch/arm/boot/dts/ste-hrefprev60.dtsi
+++ b/arch/arm/boot/dts/ste-hrefprev60.dtsi
@@ -79,11 +79,11 @@
ssp0 {
ssp0_hrefprev60_mode: ssp0_hrefprev60_default {
hrefprev60_mux {
- ste,function = "ssp0";
- ste,pins = "ssp0_a_1";
+ function = "ssp0";
+ groups = "ssp0_a_1";
};
hrefprev60_cfg1 {
- ste,pins = "GPIO145_C13"; /* RXD */
+ pins = "GPIO145_C13"; /* RXD */
ste,config = <&in_pd>;
};
@@ -93,11 +93,11 @@
/* This additional pin needed on early MOP500 and HREFs previous to v60 */
sdi0_default_mode: sdi0_default {
hrefprev60_mux {
- ste,function = "mc0";
- ste,pins = "mc0dat31dir_a_1";
+ function = "mc0";
+ groups = "mc0dat31dir_a_1";
};
hrefprev60_cfg1 {
- ste,pins = "GPIO21_AB3"; /* DAT31DIR */
+ pins = "GPIO21_AB3"; /* DAT31DIR */
ste,config = <&out_hi>;
};
@@ -106,7 +106,7 @@
tc35892 {
tc35892_hrefprev60_mode: tc35892_hrefprev60 {
hrefprev60_cfg {
- ste,pins = "GPIO217_AH12";
+ pins = "GPIO217_AH12";
ste,config = <&gpio_in_pu>;
};
};
@@ -114,11 +114,11 @@
ipgpio {
ipgpio_hrefprev60_mode: ipgpio_hrefprev60 {
hrefprev60_mux {
- ste,function = "ipgpio";
- ste,pins = "ipgpio0_c_1", "ipgpio1_c_1";
+ function = "ipgpio";
+ groups = "ipgpio0_c_1", "ipgpio1_c_1";
};
hrefprev60_cfg1 {
- ste,pins = "GPIO6_AF6", "GPIO7_AG5";
+ pins = "GPIO6_AF6", "GPIO7_AG5";
ste,config = <&in_pu>;
};
};
diff --git a/arch/arm/boot/dts/ste-hrefv60plus.dtsi b/arch/arm/boot/dts/ste-hrefv60plus.dtsi
index bcc1f0c..a4bc9e7 100644
--- a/arch/arm/boot/dts/ste-hrefv60plus.dtsi
+++ b/arch/arm/boot/dts/ste-hrefv60plus.dtsi
@@ -49,7 +49,7 @@
/* SD card detect GPIO pin, extend default state */
sdi0_default_mode: sdi0_default {
default_hrefv60_cfg1 {
- ste,pins = "GPIO95_E8";
+ pins = "GPIO95_E8";
ste,config = <&gpio_in_pu>;
};
};
@@ -64,19 +64,19 @@
*/
ipgpio_hrefv60_mode: ipgpio_hrefv60 {
hrefv60_mux {
- ste,function = "ipgpio";
- ste,pins = "ipgpio0_c_1", "ipgpio1_c_1", "ipgpio4_c_1";
+ function = "ipgpio";
+ groups = "ipgpio0_c_1", "ipgpio1_c_1", "ipgpio4_c_1";
};
hrefv60_cfg1 {
- ste,pins = "GPIO6_AF6", "GPIO7_AG5";
+ pins = "GPIO6_AF6", "GPIO7_AG5";
ste,config = <&in_pu>;
};
hrefv60_cfg2 {
- ste,pins = "GPIO21_AB3";
+ pins = "GPIO21_AB3";
ste,config = <&gpio_out_lo>;
};
hrefv60_cfg3 {
- ste,pins = "GPIO64_F3";
+ pins = "GPIO64_F3";
ste,config = <&out_lo>;
};
};
@@ -89,7 +89,7 @@
*/
etm_hrefv60_mode: etm_hrefv60 {
hrefv60_cfg1 {
- ste,pins =
+ pins =
"GPIO70_G5",
"GPIO71_G4",
"GPIO72_H4",
@@ -103,11 +103,11 @@
nahj_hrefv60_mode: nahj_hrefv60 {
/* NAHJ CTRL on GPIO76 to low, CTRL_INV on GPIO216 to high */
hrefv60_cfg1 {
- ste,pins = "GPIO76_J2";
+ pins = "GPIO76_J2";
ste,config = <&gpio_out_lo>;
};
hrefv60_cfg2 {
- ste,pins = "GPIO216_AG12";
+ pins = "GPIO216_AG12";
ste,config = <&gpio_out_hi>;
};
};
@@ -116,13 +116,13 @@
nfc_hrefv60_mode: nfc_hrefv60 {
/* NFC ENA and RESET to low, pulldown IRQ line */
hrefv60_cfg1 {
- ste,pins =
+ pins =
"GPIO77_H1", /* NFC_ENA */
"GPIO142_C11"; /* NFC_RESET */
ste,config = <&gpio_out_lo>;
};
hrefv60_cfg2 {
- ste,pins = "GPIO144_B13"; /* NFC_IRQ */
+ pins = "GPIO144_B13"; /* NFC_IRQ */
ste,config = <&gpio_in_pd>;
};
};
@@ -130,11 +130,11 @@
force {
force_hrefv60_mode: force_hrefv60 {
hrefv60_cfg1 {
- ste,pins = "GPIO91_B6"; /* FORCE_SENSING_INT */
+ pins = "GPIO91_B6"; /* FORCE_SENSING_INT */
ste,config = <&gpio_in_pu>;
};
hrefv60_cfg2 {
- ste,pins =
+ pins =
"GPIO92_D6", /* FORCE_SENSING_RST */
"GPIO97_D9"; /* FORCE_SENSING_WU */
ste,config = <&gpio_out_lo>;
@@ -144,7 +144,7 @@
dipro {
dipro_hrefv60_mode: dipro_hrefv60 {
hrefv60_cfg1 {
- ste,pins = "GPIO139_C9"; /* DIPRO_INT */
+ pins = "GPIO139_C9"; /* DIPRO_INT */
ste,config = <&gpio_in_pu>;
};
};
@@ -153,7 +153,7 @@
vaudio_hf_hrefv60_mode: vaudio_hf_hrefv60 {
/* Audio Amplifier HF enable GPIO */
hrefv60_cfg1 {
- ste,pins = "GPIO149_B14"; /* VAUDIO_HF_EN, enable MAX8968 */
+ pins = "GPIO149_B14"; /* VAUDIO_HF_EN, enable MAX8968 */
ste,config = <&gpio_out_hi>;
};
};
@@ -165,7 +165,7 @@
* pull low to reset state
*/
hrefv60_cfg1 {
- ste,pins = "GPIO171_D23"; /* GBF_ENA_RESET */
+ pins = "GPIO171_D23"; /* GBF_ENA_RESET */
ste,config = <&gpio_out_lo>;
};
};
@@ -174,7 +174,7 @@
hdtv_hrefv60_mode: hdtv_hrefv60 {
/* MSP : HDTV INTERFACE GPIO line */
hrefv60_cfg1 {
- ste,pins = "GPIO192_AJ27";
+ pins = "GPIO192_AJ27";
ste,config = <&gpio_in_pd>;
};
};
@@ -187,11 +187,11 @@
* reset signals low.
*/
hrefv60_cfg1 {
- ste,pins = "GPIO143_D12", "GPIO146_D13";
+ pins = "GPIO143_D12", "GPIO146_D13";
ste,config = <&gpio_out_lo>;
};
hrefv60_cfg2 {
- ste,pins = "GPIO67_G2";
+ pins = "GPIO67_G2";
ste,config = <&gpio_in_pu>;
};
};
@@ -204,11 +204,11 @@
* Drive DISP1 reset high (not reset), driver DISP2 reset low (reset)
*/
hrefv60_cfg1 {
- ste,pins ="GPIO65_F1";
+ pins ="GPIO65_F1";
ste,config = <&gpio_out_hi>;
};
hrefv60_cfg2 {
- ste,pins ="GPIO66_G3";
+ pins ="GPIO66_G3";
ste,config = <&gpio_out_lo>;
};
};
diff --git a/arch/arm/boot/dts/ste-nomadik-nhk15.dts b/arch/arm/boot/dts/ste-nomadik-nhk15.dts
new file mode 100644
index 0000000..a8c00ee
--- /dev/null
+++ b/arch/arm/boot/dts/ste-nomadik-nhk15.dts
@@ -0,0 +1,151 @@
+/*
+ * Device Tree for the ST-Ericsson Nomadik S8815 board
+ * Produced by Calao Systems
+ */
+
+/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+#include "ste-nomadik-stn8815.dtsi"
+
+/ {
+ model = "Nomadik STN8815NHK";
+ compatible = "st,nomadik-nhk-15";
+
+ chosen {
+ bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk";
+ };
+
+ aliases {
+ stmpe-i2c0 = &stmpe0;
+ stmpe-i2c1 = &stmpe1;
+ };
+
+ pinctrl {
+ stmpe2401_1 {
+ stmpe2401_1_nhk_mode: stmpe2401_1_nhk {
+ nhk_cfg1 {
+ ste,pins = "GPIO76_B20"; // IRQ line
+ ste,input = <0>;
+ };
+ nhk_cfg2 {
+ ste,pins = "GPIO77_B8"; // reset line
+ ste,output = <1>;
+ };
+ };
+ };
+ stmpe2401_2 {
+ stmpe2401_2_nhk_mode: stmpe2401_2_nhk {
+ nhk_cfg1 {
+ ste,pins = "GPIO78_A8"; // IRQ line
+ ste,input = <0>;
+ };
+ nhk_cfg2 {
+ ste,pins = "GPIO79_C9"; // reset line
+ ste,output = <1>;
+ };
+ };
+ };
+ };
+
+ src@101e0000 {
+ /* These chrystal outputs are not used on this board */
+ disable-sxtalo;
+ disable-mxtalo;
+ };
+
+ /* This is where the interrupt is routed on the NHK-15 debug board */
+ external-bus@34000000 {
+ compatible = "simple-bus";
+ reg = <0x34000000 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x34000000 0x1000000>;
+ ethernet@300 {
+ compatible = "smsc,lan91c111";
+ reg = <0x300 0x0fd00>;
+ reg-io-width = <2>;
+ reset-gpios = <&stmpe_gpio44 10 GPIO_ACTIVE_HIGH>;
+ interrupt-parent = <&stmpe_gpio44>;
+ interrupts = <11 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
+
+ i2c0 {
+ stmpe0: stmpe2401@43 {
+ compatible = "st,stmpe2401";
+ reg = <0x43>;
+ reset-gpios = <&gpio2 13 GPIO_ACTIVE_LOW>; // GPIO77
+ interrupts = <12 IRQ_TYPE_EDGE_FALLING>; // GPIO76
+ interrupt-parent = <&gpio2>;
+ interrupt-controller;
+ wakeup-source;
+ pinctrl-names = "default";
+ pinctrl-0 = <&stmpe2401_1_nhk_mode>;
+ stmpe_gpio43: stmpe_gpio {
+ compatible = "st,stmpe-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ /* Some pins in alternate functions */
+ st,norequest-mask = <0xf0f002>;
+ };
+ stmpe_keypad {
+ compatible = "st,stmpe-keypad";
+ debounce-interval = <64>;
+ st,scan-count = <8>;
+ st,no-autorepeat;
+ keypad,num-rows = <8>;
+ keypad,num-columns = <8>;
+ linux,keymap = <0x00020072 // Vol down
+ 0x00030073 // Vol up
+ 0x0100009e // Back
+ 0x010100e3 // TV out
+ 0x01020098 // Lock
+ 0x0103013b // Start
+ 0x020000a3 // Next
+ 0x020100a4 // Play
+ 0x020200a5 // Prev
+ 0x02030160 // OK
+ 0x03000069 // Left
+ 0x0301006a // Right
+ 0x03020067 // Up
+ 0x0303006c>; // Down
+ };
+ };
+ stmpe1: stmpe2401@44 {
+ compatible = "st,stmpe2401";
+ reg = <0x44>;
+ reset-gpios = <&gpio2 15 GPIO_ACTIVE_LOW>; // GPIO79
+ interrupts = <14 IRQ_TYPE_EDGE_FALLING>; // GPIO78
+ interrupt-parent = <&gpio2>;
+ interrupt-controller;
+ wakeup-source;
+ pinctrl-names = "default";
+ pinctrl-0 = <&stmpe2401_2_nhk_mode>;
+ stmpe_gpio44: stmpe_gpio {
+ compatible = "st,stmpe-gpio";
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ };
+ };
+ };
+
+ amba {
+ mmcsd: sdi@101f6000 {
+ cd-gpios = <&stmpe_gpio44 7 GPIO_ACTIVE_LOW>;
+ wp-gpios = <&stmpe_gpio44 18 GPIO_ACTIVE_HIGH>;
+ };
+ };
+
+ /* Custom board node with GPIO pins to active etc */
+ usb-s8815 {
+ /* This will turn off SATA so that MMC/SD can thrive */
+ mmcsd-gpio {
+ gpios = <&stmpe_gpio44 2 0x1>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/ste-nomadik-s8815.dts b/arch/arm/boot/dts/ste-nomadik-s8815.dts
index 90d8b6c..85d3b95 100644
--- a/arch/arm/boot/dts/ste-nomadik-s8815.dts
+++ b/arch/arm/boot/dts/ste-nomadik-s8815.dts
@@ -4,6 +4,7 @@
*/
/dts-v1/;
+#include <dt-bindings/interrupt-controller/irq.h>
#include "ste-nomadik-stn8815.dtsi"
/ {
@@ -14,14 +15,6 @@
bootargs = "root=/dev/ram0 console=ttyAMA1,115200n8 earlyprintk";
};
- /* This is where the interrupt is routed on the S8815 board */
- external-bus@34000000 {
- ethernet@300 {
- interrupt-parent = <&gpio3>;
- interrupts = <8 0x1>;
- };
- };
-
src@101e0000 {
/* These chrystal drivers are not used on this board */
disable-sxtalo;
@@ -37,20 +30,28 @@
cd_default_mode: cd_default {
cd_default_cfg1 {
/* CD input GPIO */
- ste,pins = "GPIO111_H21";
+ pins = "GPIO111_H21";
ste,input = <0>;
};
cd_default_cfg2 {
/* CD GPIO biasing */
- ste,pins = "GPIO112_J21";
+ pins = "GPIO112_J21";
ste,output = <0>;
};
};
};
+ gpioi2c {
+ gpioi2c_default_mode: gpioi2c_default {
+ gpioi2c_default_cfg {
+ pins = "GPIO73_C21", "GPIO74_C20";
+ ste,input = <0>;
+ };
+ };
+ };
user-led {
user_led_default_mode: user_led_default {
user_led_default_cfg {
- ste,pins = "GPIO2_C5";
+ pins = "GPIO2_C5";
ste,output = <1>;
};
};
@@ -58,13 +59,52 @@
user-button {
user_button_default_mode: user_button_default {
user_button_default_cfg {
- ste,pins = "GPIO3_A4";
+ pins = "GPIO3_A4";
ste,input = <0>;
};
};
};
};
+ /* Ethernet */
+ external-bus@34000000 {
+ compatible = "simple-bus";
+ reg = <0x34000000 0x1000000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 0x34000000 0x1000000>;
+ ethernet@300 {
+ compatible = "smsc,lan91c111";
+ reg = <0x300 0x0fd00>;
+ interrupt-parent = <&gpio3>;
+ interrupts = <8 IRQ_TYPE_EDGE_RISING>;
+ };
+ };
+
+ /* GPIO I2C connected to the USB portions of the STw4811 only */
+ gpio-i2c {
+ compatible = "i2c-gpio";
+ gpios = <&gpio2 10 0>, /* sda */
+ <&gpio2 9 0>; /* scl */
+ #address-cells = <1>;
+ #size-cells = <0>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&gpioi2c_default_mode>;
+
+ stw4811@2d {
+ compatible = "st,stw4811-usb";
+ reg = <0x2d>;
+ };
+ };
+
+
+ /* Configure card detect for the uSD slot */
+ amba {
+ mmcsd: sdi@101f6000 {
+ cd-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
+ };
+ };
+
/* Custom board node with GPIO pins to active etc */
usb-s8815 {
/* This will bias the MMC/SD card detect line */
diff --git a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
index dbcf521..f182f65 100644
--- a/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
+++ b/arch/arm/boot/dts/ste-nomadik-stn8815.dtsi
@@ -100,41 +100,41 @@
uart0 {
uart0_default_mux: uart0_mux {
u0_default_mux {
- ste,function = "u0";
- ste,pins = "u0_a_1";
+ function = "u0";
+ groups = "u0_a_1";
};
};
};
uart1 {
uart1_default_mux: uart1_mux {
u1_default_mux {
- ste,function = "u1";
- ste,pins = "u1_a_1";
+ function = "u1";
+ groups = "u1_a_1";
};
};
};
mmcsd {
mmcsd_default_mux: mmcsd_mux {
mmcsd_default_mux {
- ste,function = "mmcsd";
- ste,pins = "mmcsd_a_1";
+ function = "mmcsd";
+ groups = "mmcsd_a_1", "mmcsd_b_1";
};
};
mmcsd_default_mode: mmcsd_default {
mmcsd_default_cfg1 {
/* MCCLK */
- ste,pins = "GPIO8_B10";
+ pins = "GPIO8_B10";
ste,output = <0>;
};
mmcsd_default_cfg2 {
- /* MCCMDDIR, MCDAT0DIR, MCDAT31DIR */
- ste,pins = "GPIO10_C11", "GPIO15_A12",
- "GPIO16_C13";
+ /* MCCMDDIR, MCDAT0DIR, MCDAT31DIR, MCDATDIR2 */
+ pins = "GPIO10_C11", "GPIO15_A12",
+ "GPIO16_C13", "GPIO23_D15";
ste,output = <1>;
};
mmcsd_default_cfg3 {
/* MCCMD, MCDAT3-0, MCMSFBCLK */
- ste,pins = "GPIO9_A10", "GPIO11_B11",
+ pins = "GPIO9_A10", "GPIO11_B11",
"GPIO12_A11", "GPIO13_C12",
"GPIO14_B12", "GPIO24_C15";
ste,input = <1>;
@@ -144,13 +144,13 @@
i2c0 {
i2c0_default_mux: i2c0_mux {
i2c0_default_mux {
- ste,function = "i2c0";
- ste,pins = "i2c0_a_1";
+ function = "i2c0";
+ groups = "i2c0_a_1";
};
};
i2c0_default_mode: i2c0_default {
i2c0_default_cfg {
- ste,pins = "GPIO62_D3", "GPIO63_D2";
+ pins = "GPIO62_D3", "GPIO63_D2";
ste,input = <0>;
};
};
@@ -158,21 +158,13 @@
i2c1 {
i2c1_default_mux: i2c1_mux {
i2c1_default_mux {
- ste,function = "i2c1";
- ste,pins = "i2c1_a_1";
+ function = "i2c1";
+ groups = "i2c1_a_1";
};
};
i2c1_default_mode: i2c1_default {
i2c1_default_cfg {
- ste,pins = "GPIO53_L4", "GPIO54_L3";
- ste,input = <0>;
- };
- };
- };
- i2c2 {
- i2c2_default_mode: i2c2_default {
- i2c2_default_cfg {
- ste,pins = "GPIO73_C21", "GPIO74_C20";
+ pins = "GPIO53_L4", "GPIO54_L3";
ste,input = <0>;
};
};
@@ -182,8 +174,6 @@
src: src@101e0000 {
compatible = "stericsson,nomadik-src";
reg = <0x101e0000 0x1000>;
- disable-sxtalo;
- disable-mxtalo;
/*
* MXTAL "Main Chrystal" is a chrystal oscillator @19.2 MHz
@@ -683,18 +673,6 @@
};
};
- external-bus@34000000 {
- compatible = "simple-bus";
- reg = <0x34000000 0x1000000>;
- #address-cells = <1>;
- #size-cells = <1>;
- ranges = <0 0x34000000 0x1000000>;
- ethernet@300 {
- compatible = "smsc,lan91c111";
- reg = <0x300 0x0fd00>;
- };
- };
-
/* I2C0 connected to the STw4811 power management chip */
i2c0 {
compatible = "st,nomadik-i2c", "arm,primecell";
@@ -749,22 +727,6 @@
};
};
- /* I2C2 connected to the USB portions of the STw4811 only */
- i2c2 {
- compatible = "i2c-gpio";
- gpios = <&gpio2 10 0>, /* sda */
- <&gpio2 9 0>; /* scl */
- #address-cells = <1>;
- #size-cells = <0>;
- pinctrl-names = "default";
- pinctrl-0 = <&i2c2_default_mode>;
-
- stw4811@2d {
- compatible = "st,stw4811-usb";
- reg = <0x2d>;
- };
- };
-
amba {
compatible = "arm,amba-bus";
#address-cells = <1>;
@@ -844,7 +806,6 @@
bus-width = <4>;
cap-mmc-highspeed;
cap-sd-highspeed;
- cd-gpios = <&gpio3 15 GPIO_ACTIVE_LOW>;
pinctrl-names = "default";
pinctrl-0 = <&mmcsd_default_mux>, <&mmcsd_default_mode>;
vmmc-supply = <&vmmc_regulator>;
diff --git a/arch/arm/boot/dts/ste-snowball.dts b/arch/arm/boot/dts/ste-snowball.dts
index 3e97a66..206826a 100644
--- a/arch/arm/boot/dts/ste-snowball.dts
+++ b/arch/arm/boot/dts/ste-snowball.dts
@@ -404,17 +404,17 @@
*/
eth_snowball_mode: eth_snowball {
snowball_mux {
- ste,function = "sm";
- ste,pins = "sm_b_1";
+ function = "sm";
+ groups = "sm_b_1";
};
/* LAN IRQ pin */
snowball_cfg1 {
- ste,pins = "GPIO140_B11";
+ pins = "GPIO140_B11";
ste,config = <&in_nopull>;
};
/* LAN reset pin */
snowball_cfg2 {
- ste,pins = "GPIO141_C12";
+ pins = "GPIO141_C12";
ste,config = <&gpio_out_hi>;
};
@@ -423,11 +423,11 @@
sdi0 {
sdi0_default_mode: sdi0_default {
snowball_mux {
- ste,function = "mc0";
- ste,pins = "mc0dat31dir_a_1";
+ function = "mc0";
+ groups = "mc0dat31dir_a_1";
};
snowball_cfg1 {
- ste,pins = "GPIO21_AB3"; /* DAT31DIR */
+ pins = "GPIO21_AB3"; /* DAT31DIR */
ste,config = <&out_hi>;
};
@@ -436,19 +436,19 @@
ssp0 {
ssp0_snowball_mode: ssp0_snowball_default {
snowball_mux {
- ste,function = "ssp0";
- ste,pins = "ssp0_a_1";
+ function = "ssp0";
+ groups = "ssp0_a_1";
};
snowball_cfg1 {
- ste,pins = "GPIO144_B13"; /* FRM */
+ pins = "GPIO144_B13"; /* FRM */
ste,config = <&gpio_out_hi>;
};
snowball_cfg2 {
- ste,pins = "GPIO145_C13"; /* RXD */
+ pins = "GPIO145_C13"; /* RXD */
ste,config = <&in_pd>;
};
snowball_cfg3 {
- ste,pins =
+ pins =
"GPIO146_D13", /* TXD */
"GPIO143_D12"; /* CLK */
ste,config = <&out_lo>;
@@ -459,7 +459,7 @@
gpio_led {
gpioled_snowball_mode: gpioled_default {
snowball_cfg1 {
- ste,pins = "GPIO142_C11";
+ pins = "GPIO142_C11";
ste,config = <&gpio_out_hi>;
};
@@ -469,7 +469,7 @@
accel_snowball_mode: accel_snowball {
/* Accelerometer lines */
snowball_cfg1 {
- ste,pins =
+ pins =
"GPIO163_C20", /* ACCEL_IRQ1 */
"GPIO164_B21"; /* ACCEL_IRQ2 */
ste,config = <&gpio_in_pu>;
@@ -479,7 +479,7 @@
magnetometer {
magneto_snowball_mode: magneto_snowball {
snowball_cfg1 {
- ste,pins = "GPIO165_C21"; /* MAG_DRDY */
+ pins = "GPIO165_C21"; /* MAG_DRDY */
ste,config = <&gpio_in_pu>;
};
};
@@ -491,7 +491,7 @@
* pull low to reset state
*/
snowball_cfg1 {
- ste,pins = "GPIO171_D23"; /* GBF_ENA_RESET */
+ pins = "GPIO171_D23"; /* GBF_ENA_RESET */
ste,config = <&gpio_out_lo>;
};
};
@@ -503,13 +503,13 @@
* These are plain GPIO pins used by WLAN
*/
snowball_cfg1 {
- ste,pins =
+ pins =
"GPIO161_D21", /* WLAN_PMU_EN */
"GPIO215_AH13"; /* WLAN_ENA */
ste,config = <&gpio_out_lo>;
};
snowball_cfg2 {
- ste,pins = "GPIO216_AG12"; /* WLAN_IRQ */
+ pins = "GPIO216_AG12"; /* WLAN_IRQ */
ste,config = <&gpio_in_pu>;
};
};
diff --git a/arch/arm/boot/dts/stih407-b2120.dts b/arch/arm/boot/dts/stih407-b2120.dts
index fe69f92..261d5e2 100644
--- a/arch/arm/boot/dts/stih407-b2120.dts
+++ b/arch/arm/boot/dts/stih407-b2120.dts
@@ -7,13 +7,15 @@
* published by the Free Software Foundation.
*/
/dts-v1/;
-#include "stih407.dtsi"
+#include "stih407-clock.dtsi"
+#include "stih407-family.dtsi"
+#include "stihxxx-b2120.dtsi"
/ {
model = "STiH407 B2120";
compatible = "st,stih407-b2120", "st,stih407";
chosen {
- bootargs = "console=ttyAS0,115200";
+ bootargs = "console=ttyAS0,115200 clk_ignore_unused";
linux,stdout-path = &sbc_serial0;
};
@@ -26,53 +28,4 @@
ttyAS0 = &sbc_serial0;
};
- soc {
- sbc_serial0: serial@9530000 {
- status = "okay";
- };
-
- leds {
- compatible = "gpio-leds";
- red {
- #gpio-cells = <2>;
- label = "Front Panel LED";
- gpios = <&pio4 1 0>;
- linux,default-trigger = "heartbeat";
- };
- green {
- #gpio-cells = <2>;
- gpios = <&pio1 3 0>;
- default-state = "off";
- };
- };
-
- i2c@9842000 {
- status = "okay";
- };
-
- i2c@9843000 {
- status = "okay";
- };
-
- i2c@9844000 {
- status = "okay";
- };
-
- i2c@9845000 {
- status = "okay";
- };
-
- i2c@9540000 {
- status = "okay";
- };
-
- /* SSC11 to HDMI */
- i2c@9541000 {
- status = "okay";
- /* HDMI V1.3a supports Standard mode only */
- clock-frequency = <100000>;
- st,i2c-min-scl-pulse-width-us = <0>;
- st,i2c-min-sda-pulse-width-us = <5>;
- };
- };
};
diff --git a/arch/arm/boot/dts/stih407-clock.dtsi b/arch/arm/boot/dts/stih407-clock.dtsi
index 800f46f..e65744f 100644
--- a/arch/arm/boot/dts/stih407-clock.dtsi
+++ b/arch/arm/boot/dts/stih407-clock.dtsi
@@ -5,8 +5,13 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+#include <dt-bindings/clock/stih407-clks.h>
/ {
clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
/*
* Fixed 30MHz oscillator inputs to SoC
*/
@@ -19,10 +24,59 @@
/*
* ARM Peripheral clock for timers
*/
- arm_periph_clk: arm-periph-clk {
+ arm_periph_clk: clk-m-a9-periphs {
#clock-cells = <0>;
- compatible = "fixed-clock";
- clock-frequency = <600000000>;
+ compatible = "fixed-factor-clock";
+
+ clocks = <&clk_m_a9>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ /*
+ * A9 PLL.
+ */
+ clockgen-a9@92b0000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x92b0000 0xffff>;
+
+ clockgen_a9_pll: clockgen-a9-pll {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clockgen-a9-pll-odf";
+ };
+ };
+
+ /*
+ * ARM CPU related clocks.
+ */
+ clk_m_a9: clk-m-a9@92b0000 {
+ #clock-cells = <0>;
+ compatible = "st,stih407-clkgen-a9-mux", "st,clkgen-mux";
+ reg = <0x92b0000 0x10000>;
+
+ clocks = <&clockgen_a9_pll 0>,
+ <&clockgen_a9_pll 0>,
+ <&clk_s_c0_flexgen 13>,
+ <&clk_m_a9_ext2f_div2>;
+ };
+
+ /*
+ * ARM Peripheral clock for timers
+ */
+ clk_m_a9_ext2f_div2: clk-m-a9-ext2f-div2s {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+
+ clocks = <&clk_s_c0_flexgen 13>;
+
+ clock-output-names = "clk-m-a9-ext2f-div2";
+
+ clock-div = <2>;
+ clock-mult = <1>;
};
/*
@@ -35,5 +89,238 @@
clock-frequency = <200000000>;
clock-output-names = "clk-s-icn-reg-0";
};
+
+ clockgen-a@090ff000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x90ff000 0x1000>;
+
+ clk_s_a0_pll: clk-s-a0-pll {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-a0-pll-ofd-0";
+ };
+
+ clk_s_a0_flexgen: clk-s-a0-flexgen {
+ compatible = "st,flexgen";
+
+ #clock-cells = <1>;
+
+ clocks = <&clk_s_a0_pll 0>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-ic-lmi0";
+ };
+ };
+
+ clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-C", "st,quadfs";
+ reg = <0x9103000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-c0-fs0-ch0",
+ "clk-s-c0-fs0-ch1",
+ "clk-s-c0-fs0-ch2",
+ "clk-s-c0-fs0-ch3";
+ };
+
+ clk_s_c0: clockgen-c@09103000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9103000 0x1000>;
+
+ clk_s_c0_pll0: clk-s-c0-pll0 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-c0-pll0-odf-0";
+ };
+
+ clk_s_c0_pll1: clk-s-c0-pll1 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-c0-pll1-odf-0";
+ };
+
+ clk_s_c0_flexgen: clk-s-c0-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_c0_pll0 0>,
+ <&clk_s_c0_pll1 0>,
+ <&clk_s_c0_quadfs 0>,
+ <&clk_s_c0_quadfs 1>,
+ <&clk_s_c0_quadfs 2>,
+ <&clk_s_c0_quadfs 3>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-icn-gpu",
+ "clk-fdma",
+ "clk-nand",
+ "clk-hva",
+ "clk-proc-stfe",
+ "clk-proc-tp",
+ "clk-rx-icn-dmu",
+ "clk-rx-icn-hva",
+ "clk-icn-cpu",
+ "clk-tx-icn-dmu",
+ "clk-mmc-0",
+ "clk-mmc-1",
+ "clk-jpegdec",
+ "clk-ext2fa9",
+ "clk-ic-bdisp-0",
+ "clk-ic-bdisp-1",
+ "clk-pp-dmu",
+ "clk-vid-dmu",
+ "clk-dss-lpc",
+ "clk-st231-aud-0",
+ "clk-st231-gp-1",
+ "clk-st231-dmu",
+ "clk-icn-lmi",
+ "clk-tx-icn-disp-1",
+ "clk-icn-sbc",
+ "clk-stfe-frc2",
+ "clk-eth-phy",
+ "clk-eth-ref-phyclk",
+ "clk-flash-promip",
+ "clk-main-disp",
+ "clk-aux-disp",
+ "clk-compo-dvp";
+ };
+ };
+
+ clk_s_d0_quadfs: clk-s-d0-quadfs@9104000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ reg = <0x9104000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-d0-fs0-ch0",
+ "clk-s-d0-fs0-ch1",
+ "clk-s-d0-fs0-ch2",
+ "clk-s-d0-fs0-ch3";
+ };
+
+ clockgen-d0@09104000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9104000 0x1000>;
+
+ clk_s_d0_flexgen: clk-s-d0-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_d0_quadfs 0>,
+ <&clk_s_d0_quadfs 1>,
+ <&clk_s_d0_quadfs 2>,
+ <&clk_s_d0_quadfs 3>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-pcm-0",
+ "clk-pcm-1",
+ "clk-pcm-2",
+ "clk-spdiff";
+ };
+ };
+
+ clk_s_d2_quadfs: clk-s-d2-quadfs@9106000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ reg = <0x9106000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-d2-fs0-ch0",
+ "clk-s-d2-fs0-ch1",
+ "clk-s-d2-fs0-ch2",
+ "clk-s-d2-fs0-ch3";
+ };
+
+ clk_tmdsout_hdmi: clk-tmdsout-hdmi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ clockgen-d2@x9106000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9106000 0x1000>;
+
+ clk_s_d2_flexgen: clk-s-d2-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_d2_quadfs 0>,
+ <&clk_s_d2_quadfs 1>,
+ <&clk_s_d2_quadfs 2>,
+ <&clk_s_d2_quadfs 3>,
+ <&clk_sysin>,
+ <&clk_sysin>,
+ <&clk_tmdsout_hdmi>;
+
+ clock-output-names = "clk-pix-main-disp",
+ "clk-pix-pip",
+ "clk-pix-gdp1",
+ "clk-pix-gdp2",
+ "clk-pix-gdp3",
+ "clk-pix-gdp4",
+ "clk-pix-aux-disp",
+ "clk-denc",
+ "clk-pix-hddac",
+ "clk-hddac",
+ "clk-sddac",
+ "clk-pix-dvo",
+ "clk-dvo",
+ "clk-pix-hdmi",
+ "clk-tmds-hdmi",
+ "clk-ref-hdmiphy";
+ };
+ };
+
+ clk_s_d3_quadfs: clk-s-d3-quadfs@9107000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ reg = <0x9107000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-d3-fs0-ch0",
+ "clk-s-d3-fs0-ch1",
+ "clk-s-d3-fs0-ch2",
+ "clk-s-d3-fs0-ch3";
+ };
+
+ clockgen-d3@9107000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9107000 0x1000>;
+
+ clk_s_d3_flexgen: clk-s-d3-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_d3_quadfs 0>,
+ <&clk_s_d3_quadfs 1>,
+ <&clk_s_d3_quadfs 2>,
+ <&clk_s_d3_quadfs 3>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-stfe-frc1",
+ "clk-tsout-0",
+ "clk-tsout-1",
+ "clk-mchi",
+ "clk-vsens-compo",
+ "clk-frc1-remote",
+ "clk-lpc-0",
+ "clk-lpc-1";
+ };
+ };
};
};
diff --git a/arch/arm/boot/dts/stih407.dtsi b/arch/arm/boot/dts/stih407-family.dtsi
index 4f9024f..3e31d32 100644
--- a/arch/arm/boot/dts/stih407.dtsi
+++ b/arch/arm/boot/dts/stih407-family.dtsi
@@ -6,8 +6,8 @@
* it under the terms of the GNU General Public License version 2 as
* publishhed by the Free Software Foundation.
*/
-#include "stih407-clock.dtsi"
#include "stih407-pinctrl.dtsi"
+#include <dt-bindings/reset-controller/stih407-resets.h>
/ {
#address-cells = <1>;
#size-cells = <1>;
@@ -63,6 +63,21 @@
ranges;
compatible = "simple-bus";
+ powerdown: powerdown-controller {
+ compatible = "st,stih407-powerdown";
+ #reset-cells = <1>;
+ };
+
+ softreset: softreset-controller {
+ compatible = "st,stih407-softreset";
+ #reset-cells = <1>;
+ };
+
+ picophyreset: picophyreset-controller {
+ compatible = "st,stih407-picophyreset";
+ #reset-cells = <1>;
+ };
+
syscfg_sbc: sbc-syscfg@9620000 {
compatible = "st,stih407-sbc-syscfg", "syscon";
reg = <0x9620000 0x1000>;
@@ -104,7 +119,7 @@
interrupts = <GIC_SPI 122 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_serial0>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
status = "disabled";
};
@@ -115,7 +130,7 @@
interrupts = <GIC_SPI 123 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_serial1>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
status = "disabled";
};
@@ -126,7 +141,7 @@
interrupts = <GIC_SPI 124 IRQ_TYPE_NONE>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_serial2>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
status = "disabled";
};
@@ -158,7 +173,7 @@
compatible = "st,comms-ssc4-i2c";
interrupts = <GIC_SPI 112 IRQ_TYPE_LEVEL_HIGH>;
reg = <0x9840000 0x110>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
@@ -171,7 +186,7 @@
compatible = "st,comms-ssc4-i2c";
reg = <0x9841000 0x110>;
interrupts = <GIC_SPI 113 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
@@ -184,7 +199,7 @@
compatible = "st,comms-ssc4-i2c";
reg = <0x9842000 0x110>;
interrupts = <GIC_SPI 114 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
@@ -197,7 +212,7 @@
compatible = "st,comms-ssc4-i2c";
reg = <0x9843000 0x110>;
interrupts = <GIC_SPI 115 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
@@ -210,7 +225,7 @@
compatible = "st,comms-ssc4-i2c";
reg = <0x9844000 0x110>;
interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
@@ -223,7 +238,7 @@
compatible = "st,comms-ssc4-i2c";
reg = <0x9845000 0x110>;
interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clk_ext2f_a9>;
+ clocks = <&clk_s_c0_flexgen CLK_EXT2F_A9>;
clock-names = "ssc";
clock-frequency = <400000>;
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/stih410-b2120.dts b/arch/arm/boot/dts/stih410-b2120.dts
new file mode 100644
index 0000000..2f61a99
--- /dev/null
+++ b/arch/arm/boot/dts/stih410-b2120.dts
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics (R&D) Limited.
+ * Author: Peter Griffin <peter.griffin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+/dts-v1/;
+#include "stih410.dtsi"
+#include "stihxxx-b2120.dtsi"
+/ {
+ model = "STiH410 B2120";
+ compatible = "st,stih410-b2120", "st,stih410";
+
+ chosen {
+ bootargs = "console=ttyAS0,115200 clk_ignore_unused";
+ linux,stdout-path = &sbc_serial0;
+ };
+
+ memory {
+ device_type = "memory";
+ reg = <0x40000000 0x80000000>;
+ };
+
+ aliases {
+ ttyAS0 = &sbc_serial0;
+ };
+};
diff --git a/arch/arm/boot/dts/stih410-clock.dtsi b/arch/arm/boot/dts/stih410-clock.dtsi
new file mode 100644
index 0000000..6b5803a
--- /dev/null
+++ b/arch/arm/boot/dts/stih410-clock.dtsi
@@ -0,0 +1,338 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics R&D Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <dt-bindings/clock/stih410-clks.h>
+/ {
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ compatible = "st,stih410-clk", "simple-bus";
+
+ /*
+ * Fixed 30MHz oscillator inputs to SoC
+ */
+ clk_sysin: clk-sysin {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <30000000>;
+ clock-output-names = "CLK_SYSIN";
+ };
+
+ /*
+ * ARM Peripheral clock for timers
+ */
+ arm_periph_clk: clk-m-a9-periphs {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+ clocks = <&clk_m_a9>;
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ /*
+ * A9 PLL.
+ */
+ clockgen-a9@92b0000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x92b0000 0xffff>;
+
+ clockgen_a9_pll: clockgen-a9-pll {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-a9", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clockgen-a9-pll-odf";
+ };
+ };
+
+ /*
+ * ARM CPU related clocks.
+ */
+ clk_m_a9: clk-m-a9@92b0000 {
+ #clock-cells = <0>;
+ compatible = "st,stih407-clkgen-a9-mux", "st,clkgen-mux";
+ reg = <0x92b0000 0x10000>;
+
+ clocks = <&clockgen_a9_pll 0>,
+ <&clockgen_a9_pll 0>,
+ <&clk_s_c0_flexgen 13>,
+ <&clk_m_a9_ext2f_div2>;
+ };
+
+ /*
+ * ARM Peripheral clock for timers
+ */
+ clk_m_a9_ext2f_div2: clk-m-a9-ext2f-div2s {
+ #clock-cells = <0>;
+ compatible = "fixed-factor-clock";
+
+ clocks = <&clk_s_c0_flexgen 13>;
+
+ clock-output-names = "clk-m-a9-ext2f-div2";
+
+ clock-div = <2>;
+ clock-mult = <1>;
+ };
+
+ /*
+ * Bootloader initialized system infrastructure clock for
+ * serial devices.
+ */
+ clk_ext2f_a9: clockgen-c0@13 {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <200000000>;
+ clock-output-names = "clk-s-icn-reg-0";
+ };
+
+ clockgen-a@090ff000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x90ff000 0x1000>;
+
+ clk_s_a0_pll: clk-s-a0-pll {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-a0", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-a0-pll-ofd-0";
+ };
+
+ clk_s_a0_flexgen: clk-s-a0-flexgen {
+ compatible = "st,flexgen";
+
+ #clock-cells = <1>;
+
+ clocks = <&clk_s_a0_pll 0>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-ic-lmi0",
+ "clk-ic-lmi1";
+ };
+ };
+
+ clk_s_c0_quadfs: clk-s-c0-quadfs@9103000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-C", "st,quadfs";
+ reg = <0x9103000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-c0-fs0-ch0",
+ "clk-s-c0-fs0-ch1",
+ "clk-s-c0-fs0-ch2",
+ "clk-s-c0-fs0-ch3";
+ };
+
+ clk_s_c0: clockgen-c@09103000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9103000 0x1000>;
+
+ clk_s_c0_pll0: clk-s-c0-pll0 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-c0_0", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-c0-pll0-odf-0";
+ };
+
+ clk_s_c0_pll1: clk-s-c0-pll1 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-plls-c32-c0_1", "st,clkgen-plls-c32";
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-c0-pll1-odf-0";
+ };
+
+ clk_s_c0_flexgen: clk-s-c0-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_c0_pll0 0>,
+ <&clk_s_c0_pll1 0>,
+ <&clk_s_c0_quadfs 0>,
+ <&clk_s_c0_quadfs 1>,
+ <&clk_s_c0_quadfs 2>,
+ <&clk_s_c0_quadfs 3>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-icn-gpu",
+ "clk-fdma",
+ "clk-nand",
+ "clk-hva",
+ "clk-proc-stfe",
+ "clk-proc-tp",
+ "clk-rx-icn-dmu",
+ "clk-rx-icn-hva",
+ "clk-icn-cpu",
+ "clk-tx-icn-dmu",
+ "clk-mmc-0",
+ "clk-mmc-1",
+ "clk-jpegdec",
+ "clk-ext2fa9",
+ "clk-ic-bdisp-0",
+ "clk-ic-bdisp-1",
+ "clk-pp-dmu",
+ "clk-vid-dmu",
+ "clk-dss-lpc",
+ "clk-st231-aud-0",
+ "clk-st231-gp-1",
+ "clk-st231-dmu",
+ "clk-icn-lmi",
+ "clk-tx-icn-disp-1",
+ "clk-icn-sbc",
+ "clk-stfe-frc2",
+ "clk-eth-phy",
+ "clk-eth-ref-phyclk",
+ "clk-flash-promip",
+ "clk-main-disp",
+ "clk-aux-disp",
+ "clk-compo-dvp",
+ "clk-tx-icn-hades",
+ "clk-rx-icn-hades",
+ "clk-icn-reg-16",
+ "clk-pp-hades",
+ "clk-clust-hades",
+ "clk-hwpe-hades",
+ "clk-fc-hades";
+ };
+ };
+
+ clk_s_d0_quadfs: clk-s-d0-quadfs@9104000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ reg = <0x9104000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-d0-fs0-ch0",
+ "clk-s-d0-fs0-ch1",
+ "clk-s-d0-fs0-ch2",
+ "clk-s-d0-fs0-ch3";
+ };
+
+ clockgen-d0@09104000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9104000 0x1000>;
+
+ clk_s_d0_flexgen: clk-s-d0-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_d0_quadfs 0>,
+ <&clk_s_d0_quadfs 1>,
+ <&clk_s_d0_quadfs 2>,
+ <&clk_s_d0_quadfs 3>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-pcm-0",
+ "clk-pcm-1",
+ "clk-pcm-2",
+ "clk-spdiff",
+ "clk-pcmr10-master",
+ "clk-usb2-phy";
+ };
+ };
+
+ clk_s_d2_quadfs: clk-s-d2-quadfs@9106000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ reg = <0x9106000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-d2-fs0-ch0",
+ "clk-s-d2-fs0-ch1",
+ "clk-s-d2-fs0-ch2",
+ "clk-s-d2-fs0-ch3";
+ };
+
+ clk_tmdsout_hdmi: clk-tmdsout-hdmi {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <0>;
+ };
+
+ clockgen-d2@x9106000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9106000 0x1000>;
+
+ clk_s_d2_flexgen: clk-s-d2-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_d2_quadfs 0>,
+ <&clk_s_d2_quadfs 1>,
+ <&clk_s_d2_quadfs 2>,
+ <&clk_s_d2_quadfs 3>,
+ <&clk_sysin>,
+ <&clk_sysin>,
+ <&clk_tmdsout_hdmi>;
+
+ clock-output-names = "clk-pix-main-disp",
+ "clk-pix-pip",
+ "clk-pix-gdp1",
+ "clk-pix-gdp2",
+ "clk-pix-gdp3",
+ "clk-pix-gdp4",
+ "clk-pix-aux-disp",
+ "clk-denc",
+ "clk-pix-hddac",
+ "clk-hddac",
+ "clk-sddac",
+ "clk-pix-dvo",
+ "clk-dvo",
+ "clk-pix-hdmi",
+ "clk-tmds-hdmi",
+ "clk-ref-hdmiphy";
+ };
+ };
+
+ clk_s_d3_quadfs: clk-s-d3-quadfs@9107000 {
+ #clock-cells = <1>;
+ compatible = "st,stih407-quadfs660-D", "st,quadfs";
+ reg = <0x9107000 0x1000>;
+
+ clocks = <&clk_sysin>;
+
+ clock-output-names = "clk-s-d3-fs0-ch0",
+ "clk-s-d3-fs0-ch1",
+ "clk-s-d3-fs0-ch2",
+ "clk-s-d3-fs0-ch3";
+ };
+
+ clockgen-d3@9107000 {
+ compatible = "st,clkgen-c32";
+ reg = <0x9107000 0x1000>;
+
+ clk_s_d3_flexgen: clk-s-d3-flexgen {
+ #clock-cells = <1>;
+ compatible = "st,flexgen";
+
+ clocks = <&clk_s_d3_quadfs 0>,
+ <&clk_s_d3_quadfs 1>,
+ <&clk_s_d3_quadfs 2>,
+ <&clk_s_d3_quadfs 3>,
+ <&clk_sysin>;
+
+ clock-output-names = "clk-stfe-frc1",
+ "clk-tsout-0",
+ "clk-tsout-1",
+ "clk-mchi",
+ "clk-vsens-compo",
+ "clk-frc1-remote",
+ "clk-lpc-0",
+ "clk-lpc-1";
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih410-pinctrl.dtsi b/arch/arm/boot/dts/stih410-pinctrl.dtsi
new file mode 100644
index 0000000..b3e9dfc
--- /dev/null
+++ b/arch/arm/boot/dts/stih410-pinctrl.dtsi
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics Limited.
+ * Author: Peter Griffin <peter.griffin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ */
+#include "st-pincfg.h"
+/ {
+
+ soc {
+ pin-controller-rear {
+
+ usb0 {
+ pinctrl_usb0: usb2-0 {
+ st,pins {
+ usb-oc-detect = <&pio35 0 ALT1 IN>;
+ usb-pwr-enable = <&pio35 1 ALT1 OUT>;
+ };
+ };
+ };
+
+ usb1 {
+ pinctrl_usb1: usb2-1 {
+ st,pins {
+ usb-oc-detect = <&pio35 2 ALT1 IN>;
+ usb-pwr-enable = <&pio35 3 ALT1 OUT>;
+ };
+ };
+ };
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/stih410.dtsi b/arch/arm/boot/dts/stih410.dtsi
new file mode 100644
index 0000000..c05627e
--- /dev/null
+++ b/arch/arm/boot/dts/stih410.dtsi
@@ -0,0 +1,14 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics Limited.
+ * Author: Peter Griffin <peter.griffin@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * publishhed by the Free Software Foundation.
+ */
+#include "stih410-clock.dtsi"
+#include "stih407-family.dtsi"
+#include "stih410-pinctrl.dtsi"
+/ {
+
+};
diff --git a/arch/arm/boot/dts/stih415-pinctrl.dtsi b/arch/arm/boot/dts/stih415-pinctrl.dtsi
index 8509a03..3791ad9 100644
--- a/arch/arm/boot/dts/stih415-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih415-pinctrl.dtsi
@@ -11,33 +11,33 @@
/ {
aliases {
- gpio0 = &PIO0;
- gpio1 = &PIO1;
- gpio2 = &PIO2;
- gpio3 = &PIO3;
- gpio4 = &PIO4;
- gpio5 = &PIO5;
- gpio6 = &PIO6;
- gpio7 = &PIO7;
- gpio8 = &PIO8;
- gpio9 = &PIO9;
- gpio10 = &PIO10;
- gpio11 = &PIO11;
- gpio12 = &PIO12;
- gpio13 = &PIO13;
- gpio14 = &PIO14;
- gpio15 = &PIO15;
- gpio16 = &PIO16;
- gpio17 = &PIO17;
- gpio18 = &PIO18;
- gpio19 = &PIO100;
- gpio20 = &PIO101;
- gpio21 = &PIO102;
- gpio22 = &PIO103;
- gpio23 = &PIO104;
- gpio24 = &PIO105;
- gpio25 = &PIO106;
- gpio26 = &PIO107;
+ gpio0 = &pio0;
+ gpio1 = &pio1;
+ gpio2 = &pio2;
+ gpio3 = &pio3;
+ gpio4 = &pio4;
+ gpio5 = &pio5;
+ gpio6 = &pio6;
+ gpio7 = &pio7;
+ gpio8 = &pio8;
+ gpio9 = &pio9;
+ gpio10 = &pio10;
+ gpio11 = &pio11;
+ gpio12 = &pio12;
+ gpio13 = &pio13;
+ gpio14 = &pio14;
+ gpio15 = &pio15;
+ gpio16 = &pio16;
+ gpio17 = &pio17;
+ gpio18 = &pio18;
+ gpio19 = &pio100;
+ gpio20 = &pio101;
+ gpio21 = &pio102;
+ gpio22 = &pio103;
+ gpio23 = &pio104;
+ gpio24 = &pio105;
+ gpio25 = &pio106;
+ gpio26 = &pio107;
};
soc {
@@ -52,7 +52,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfe610000 0x5000>;
- PIO0: gpio@fe610000 {
+ pio0: gpio@fe610000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -60,7 +60,7 @@
reg = <0 0x100>;
st,bank-name = "PIO0";
};
- PIO1: gpio@fe611000 {
+ pio1: gpio@fe611000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -68,7 +68,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO1";
};
- PIO2: gpio@fe612000 {
+ pio2: gpio@fe612000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -76,7 +76,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO2";
};
- PIO3: gpio@fe613000 {
+ pio3: gpio@fe613000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -84,7 +84,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO3";
};
- PIO4: gpio@fe614000 {
+ pio4: gpio@fe614000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -96,8 +96,8 @@
sbc_serial1 {
pinctrl_sbc_serial1:sbc_serial1 {
st,pins {
- tx = <&PIO2 6 ALT3 OUT>;
- rx = <&PIO2 7 ALT3 IN>;
+ tx = <&pio2 6 ALT3 OUT>;
+ rx = <&pio2 7 ALT3 IN>;
};
};
};
@@ -105,15 +105,15 @@
keyscan {
pinctrl_keyscan: keyscan {
st,pins {
- keyin0 = <&PIO0 2 ALT2 IN>;
- keyin1 = <&PIO0 3 ALT2 IN>;
- keyin2 = <&PIO0 4 ALT2 IN>;
- keyin3 = <&PIO2 6 ALT2 IN>;
-
- keyout0 = <&PIO1 6 ALT2 OUT>;
- keyout1 = <&PIO1 7 ALT2 OUT>;
- keyout2 = <&PIO0 6 ALT2 OUT>;
- keyout3 = <&PIO2 7 ALT2 OUT>;
+ keyin0 = <&pio0 2 ALT2 IN>;
+ keyin1 = <&pio0 3 ALT2 IN>;
+ keyin2 = <&pio0 4 ALT2 IN>;
+ keyin3 = <&pio2 6 ALT2 IN>;
+
+ keyout0 = <&pio1 6 ALT2 OUT>;
+ keyout1 = <&pio1 7 ALT2 OUT>;
+ keyout2 = <&pio0 6 ALT2 OUT>;
+ keyout3 = <&pio2 7 ALT2 OUT>;
};
};
};
@@ -121,8 +121,8 @@
sbc_i2c0 {
pinctrl_sbc_i2c0_default: sbc_i2c0-default {
st,pins {
- sda = <&PIO4 6 ALT1 BIDIR>;
- scl = <&PIO4 5 ALT1 BIDIR>;
+ sda = <&pio4 6 ALT1 BIDIR>;
+ scl = <&pio4 5 ALT1 BIDIR>;
};
};
};
@@ -130,8 +130,8 @@
sbc_i2c1 {
pinctrl_sbc_i2c1_default: sbc_i2c1-default {
st,pins {
- sda = <&PIO3 2 ALT2 BIDIR>;
- scl = <&PIO3 1 ALT2 BIDIR>;
+ sda = <&pio3 2 ALT2 BIDIR>;
+ scl = <&pio3 1 ALT2 BIDIR>;
};
};
};
@@ -139,7 +139,7 @@
rc{
pinctrl_ir: ir0 {
st,pins {
- ir = <&PIO4 0 ALT2 IN>;
+ ir = <&pio4 0 ALT2 IN>;
};
};
};
@@ -147,49 +147,49 @@
gmac1 {
pinctrl_mii1: mii1 {
st,pins {
- txd0 = <&PIO0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txd1 = <&PIO0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txd2 = <&PIO0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txd3 = <&PIO0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txer = <&PIO0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txen = <&PIO0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>;
- col = <&PIO0 7 ALT1 IN BYPASS 1000>;
- mdio = <&PIO1 0 ALT1 OUT BYPASS 0>;
- mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>;
- crs = <&PIO1 2 ALT1 IN BYPASS 1000>;
- mdint = <&PIO1 3 ALT1 IN BYPASS 0>;
- rxd0 = <&PIO1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxd1 = <&PIO1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxd2 = <&PIO1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxd3 = <&PIO1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxdv = <&PIO2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rx_er = <&PIO2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>;
- phyclk = <&PIO2 3 ALT1 IN NICLK 1000 CLK_A>;
+ txd0 = <&pio0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd1 = <&pio0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd2 = <&pio0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd3 = <&pio0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txer = <&pio0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txen = <&pio0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txclk = <&pio0 6 ALT1 IN NICLK 0 CLK_A>;
+ col = <&pio0 7 ALT1 IN BYPASS 1000>;
+ mdio = <&pio1 0 ALT1 OUT BYPASS 0>;
+ mdc = <&pio1 1 ALT1 OUT NICLK 0 CLK_A>;
+ crs = <&pio1 2 ALT1 IN BYPASS 1000>;
+ mdint = <&pio1 3 ALT1 IN BYPASS 0>;
+ rxd0 = <&pio1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxd1 = <&pio1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxd2 = <&pio1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxd3 = <&pio1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxdv = <&pio2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rx_er = <&pio2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxclk = <&pio2 2 ALT1 IN NICLK 0 CLK_A>;
+ phyclk = <&pio2 3 ALT1 IN NICLK 1000 CLK_A>;
};
};
pinctrl_rgmii1: rgmii1-0 {
st,pins {
- txd0 = <&PIO0 0 ALT1 OUT DE_IO 1000 CLK_A>;
- txd1 = <&PIO0 1 ALT1 OUT DE_IO 1000 CLK_A>;
- txd2 = <&PIO0 2 ALT1 OUT DE_IO 1000 CLK_A>;
- txd3 = <&PIO0 3 ALT1 OUT DE_IO 1000 CLK_A>;
- txen = <&PIO0 5 ALT1 OUT DE_IO 0 CLK_A>;
- txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>;
- mdio = <&PIO1 0 ALT1 OUT BYPASS 0>;
- mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>;
- rxd0 = <&PIO1 4 ALT1 IN DE_IO 0 CLK_A>;
- rxd1 = <&PIO1 5 ALT1 IN DE_IO 0 CLK_A>;
- rxd2 = <&PIO1 6 ALT1 IN DE_IO 0 CLK_A>;
- rxd3 = <&PIO1 7 ALT1 IN DE_IO 0 CLK_A>;
-
- rxdv = <&PIO2 0 ALT1 IN DE_IO 500 CLK_A>;
- rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>;
- phyclk = <&PIO2 3 ALT4 OUT NICLK 0 CLK_B>;
-
- clk125= <&PIO3 7 ALT4 IN NICLK 0 CLK_A>;
+ txd0 = <&pio0 0 ALT1 OUT DE_IO 1000 CLK_A>;
+ txd1 = <&pio0 1 ALT1 OUT DE_IO 1000 CLK_A>;
+ txd2 = <&pio0 2 ALT1 OUT DE_IO 1000 CLK_A>;
+ txd3 = <&pio0 3 ALT1 OUT DE_IO 1000 CLK_A>;
+ txen = <&pio0 5 ALT1 OUT DE_IO 0 CLK_A>;
+ txclk = <&pio0 6 ALT1 IN NICLK 0 CLK_A>;
+ mdio = <&pio1 0 ALT1 OUT BYPASS 0>;
+ mdc = <&pio1 1 ALT1 OUT NICLK 0 CLK_A>;
+ rxd0 = <&pio1 4 ALT1 IN DE_IO 0 CLK_A>;
+ rxd1 = <&pio1 5 ALT1 IN DE_IO 0 CLK_A>;
+ rxd2 = <&pio1 6 ALT1 IN DE_IO 0 CLK_A>;
+ rxd3 = <&pio1 7 ALT1 IN DE_IO 0 CLK_A>;
+
+ rxdv = <&pio2 0 ALT1 IN DE_IO 500 CLK_A>;
+ rxclk = <&pio2 2 ALT1 IN NICLK 0 CLK_A>;
+ phyclk = <&pio2 3 ALT4 OUT NICLK 0 CLK_B>;
+
+ clk125= <&pio3 7 ALT4 IN NICLK 0 CLK_A>;
};
};
};
@@ -206,7 +206,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfee00000 0x8000>;
- PIO5: gpio@fee00000 {
+ pio5: gpio@fee00000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -214,7 +214,7 @@
reg = <0 0x100>;
st,bank-name = "PIO5";
};
- PIO6: gpio@fee01000 {
+ pio6: gpio@fee01000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -222,7 +222,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO6";
};
- PIO7: gpio@fee02000 {
+ pio7: gpio@fee02000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -230,7 +230,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO7";
};
- PIO8: gpio@fee03000 {
+ pio8: gpio@fee03000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -238,7 +238,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO8";
};
- PIO9: gpio@fee04000 {
+ pio9: gpio@fee04000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -246,7 +246,7 @@
reg = <0x4000 0x100>;
st,bank-name = "PIO9";
};
- PIO10: gpio@fee05000 {
+ pio10: gpio@fee05000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -254,7 +254,7 @@
reg = <0x5000 0x100>;
st,bank-name = "PIO10";
};
- PIO11: gpio@fee06000 {
+ pio11: gpio@fee06000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -262,7 +262,7 @@
reg = <0x6000 0x100>;
st,bank-name = "PIO11";
};
- PIO12: gpio@fee07000 {
+ pio12: gpio@fee07000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -274,8 +274,8 @@
i2c0 {
pinctrl_i2c0_default: i2c0-default {
st,pins {
- sda = <&PIO9 3 ALT1 BIDIR>;
- scl = <&PIO9 2 ALT1 BIDIR>;
+ sda = <&pio9 3 ALT1 BIDIR>;
+ scl = <&pio9 2 ALT1 BIDIR>;
};
};
};
@@ -283,8 +283,8 @@
i2c1 {
pinctrl_i2c1_default: i2c1-default {
st,pins {
- sda = <&PIO12 1 ALT1 BIDIR>;
- scl = <&PIO12 0 ALT1 BIDIR>;
+ sda = <&pio12 1 ALT1 BIDIR>;
+ scl = <&pio12 0 ALT1 BIDIR>;
};
};
};
@@ -301,7 +301,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfe820000 0x8000>;
- PIO13: gpio@fe820000 {
+ pio13: gpio@fe820000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -309,7 +309,7 @@
reg = <0 0x100>;
st,bank-name = "PIO13";
};
- PIO14: gpio@fe821000 {
+ pio14: gpio@fe821000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -317,7 +317,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO14";
};
- PIO15: gpio@fe822000 {
+ pio15: gpio@fe822000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -325,7 +325,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO15";
};
- PIO16: gpio@fe823000 {
+ pio16: gpio@fe823000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -333,7 +333,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO16";
};
- PIO17: gpio@fe824000 {
+ pio17: gpio@fe824000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -341,7 +341,7 @@
reg = <0x4000 0x100>;
st,bank-name = "PIO17";
};
- PIO18: gpio@fe825000 {
+ pio18: gpio@fe825000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -353,8 +353,8 @@
serial2 {
pinctrl_serial2: serial2-0 {
st,pins {
- tx = <&PIO17 4 ALT2 OUT>;
- rx = <&PIO17 5 ALT2 IN>;
+ tx = <&pio17 4 ALT2 OUT>;
+ rx = <&pio17 5 ALT2 IN>;
};
};
};
@@ -362,73 +362,94 @@
gmac0{
pinctrl_mii0: mii0 {
st,pins {
- mdint = <&PIO13 6 ALT2 IN BYPASS 0>;
- txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
-
- txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
- txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
-
- txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>;
- txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- crs = <&PIO15 2 ALT2 IN BYPASS 1000>;
- col = <&PIO15 3 ALT2 IN BYPASS 1000>;
- mdio = <&PIO15 4 ALT2 OUT BYPASS 3000>;
- mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>;
-
- rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>;
- phyclk = <&PIO13 5 ALT2 OUT NICLK 1000 CLK_A>;
+ mdint = <&pio13 6 ALT2 IN BYPASS 0>;
+ txen = <&pio13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+
+ txd0 = <&pio14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ txd1 = <&pio14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ txd2 = <&pio14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
+ txd3 = <&pio14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
+
+ txclk = <&pio15 0 ALT2 IN NICLK 0 CLK_A>;
+ txer = <&pio15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ crs = <&pio15 2 ALT2 IN BYPASS 1000>;
+ col = <&pio15 3 ALT2 IN BYPASS 1000>;
+ mdio = <&pio15 4 ALT2 OUT BYPASS 3000>;
+ mdc = <&pio15 5 ALT2 OUT NICLK 0 CLK_B>;
+
+ rxd0 = <&pio16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxd1 = <&pio16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxd2 = <&pio16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxd3 = <&pio16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxdv = <&pio15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rx_er = <&pio15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxclk = <&pio17 0 ALT2 IN NICLK 0 CLK_A>;
+ phyclk = <&pio13 5 ALT2 OUT NICLK 1000 CLK_A>;
};
};
pinctrl_gmii0: gmii0 {
st,pins {
- mdint = <&PIO13 6 ALT2 IN BYPASS 0>;
- mdio = <&PIO15 4 ALT2 OUT BYPASS 3000>;
- mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>;
- txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
-
- txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
- txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
- txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
- txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
- txd4 = <&PIO14 4 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
- txd5 = <&PIO14 5 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
- txd6 = <&PIO14 6 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
- txd7 = <&PIO14 7 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
-
- txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>;
- txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
- crs = <&PIO15 2 ALT2 IN BYPASS 1000>;
- col = <&PIO15 3 ALT2 IN BYPASS 1000>;
- rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
-
- rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd4 = <&PIO16 4 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd5 = <&PIO16 5 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd6 = <&PIO16 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
- rxd7 = <&PIO16 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
-
- rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>;
- clk125 = <&PIO17 6 ALT1 IN NICLK 0 CLK_A>;
- phyclk = <&PIO13 5 ALT4 OUT NICLK 0 CLK_B>;
+ mdint = <&pio13 6 ALT2 IN BYPASS 0>;
+ mdio = <&pio15 4 ALT2 OUT BYPASS 3000>;
+ mdc = <&pio15 5 ALT2 OUT NICLK 0 CLK_B>;
+ txen = <&pio13 7 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
+
+ txd0 = <&pio14 0 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
+ txd1 = <&pio14 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
+ txd2 = <&pio14 2 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
+ txd3 = <&pio14 3 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
+ txd4 = <&pio14 4 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
+ txd5 = <&pio14 5 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
+ txd6 = <&pio14 6 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
+ txd7 = <&pio14 7 ALT2 OUT SE_NICLK_IO 3000 CLK_B>;
+
+ txclk = <&pio15 0 ALT2 IN NICLK 0 CLK_A>;
+ txer = <&pio15 1 ALT2 OUT SE_NICLK_IO 3000 CLK_A>;
+ crs = <&pio15 2 ALT2 IN BYPASS 1000>;
+ col = <&pio15 3 ALT2 IN BYPASS 1000>;
+ rxdv = <&pio15 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rx_er = <&pio15 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+
+ rxd0 = <&pio16 0 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd1 = <&pio16 1 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd2 = <&pio16 2 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd3 = <&pio16 3 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd4 = <&pio16 4 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd5 = <&pio16 5 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd6 = <&pio16 6 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+ rxd7 = <&pio16 7 ALT2 IN SE_NICLK_IO 1500 CLK_A>;
+
+ rxclk = <&pio17 0 ALT2 IN NICLK 0 CLK_A>;
+ clk125 = <&pio17 6 ALT1 IN NICLK 0 CLK_A>;
+ phyclk = <&pio13 5 ALT4 OUT NICLK 0 CLK_B>;
};
};
};
+
+ mmc0 {
+ pinctrl_mmc0: mmc0 {
+ st,pins {
+ mmcclk = <&pio13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>;
+ data0 = <&pio14 4 ALT4 BIDIR_PU BYPASS 0>;
+ data1 = <&pio14 5 ALT4 BIDIR_PU BYPASS 0>;
+ data2 = <&pio14 6 ALT4 BIDIR_PU BYPASS 0>;
+ data3 = <&pio14 7 ALT4 BIDIR_PU BYPASS 0>;
+ cmd = <&pio15 1 ALT4 BIDIR_PU BYPASS 0>;
+ wp = <&pio15 3 ALT4 IN>;
+ data4 = <&pio16 4 ALT4 BIDIR_PU BYPASS 0>;
+ data5 = <&pio16 5 ALT4 BIDIR_PU BYPASS 0>;
+ data6 = <&pio16 6 ALT4 BIDIR_PU BYPASS 0>;
+ data7 = <&pio16 7 ALT4 BIDIR_PU BYPASS 0>;
+ pwr = <&pio17 1 ALT4 OUT>;
+ cd = <&pio17 2 ALT4 IN>;
+ led = <&pio17 3 ALT4 OUT>;
+ };
+ };
+ };
};
pin-controller-left {
@@ -442,7 +463,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfd6b0000 0x3000>;
- PIO100: gpio@fd6b0000 {
+ pio100: gpio@fd6b0000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -450,7 +471,7 @@
reg = <0 0x100>;
st,bank-name = "PIO100";
};
- PIO101: gpio@fd6b1000 {
+ pio101: gpio@fd6b1000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -458,7 +479,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO101";
};
- PIO102: gpio@fd6b2000 {
+ pio102: gpio@fd6b2000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -479,7 +500,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfd330000 0x5000>;
- PIO103: gpio@fd330000 {
+ pio103: gpio@fd330000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -487,7 +508,7 @@
reg = <0 0x100>;
st,bank-name = "PIO103";
};
- PIO104: gpio@fd331000 {
+ pio104: gpio@fd331000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -495,7 +516,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO104";
};
- PIO105: gpio@fd332000 {
+ pio105: gpio@fd332000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -503,7 +524,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO105";
};
- PIO106: gpio@fd333000 {
+ pio106: gpio@fd333000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -511,7 +532,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO106";
};
- PIO107: gpio@fd334000 {
+ pio107: gpio@fd334000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/stih415.dtsi b/arch/arm/boot/dts/stih415.dtsi
index a0f6f75..9198c12 100644
--- a/arch/arm/boot/dts/stih415.dtsi
+++ b/arch/arm/boot/dts/stih415.dtsi
@@ -218,5 +218,17 @@
resets = <&powerdown STIH415_KEYSCAN_POWERDOWN>,
<&softreset STIH415_KEYSCAN_SOFTRESET>;
};
+
+ mmc0: sdhci@fe81e000 {
+ compatible = "st,sdhci";
+ status = "disabled";
+ reg = <0xfe81e000 0x1000>;
+ interrupts = <GIC_SPI 145 IRQ_TYPE_NONE>;
+ interrupt-names = "mmcirq";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc0>;
+ clock-names = "mmc";
+ clocks = <&clk_s_a1_ls 1>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stih416-b2020.dts b/arch/arm/boot/dts/stih416-b2020.dts
index 4e2df66..200a818 100644
--- a/arch/arm/boot/dts/stih416-b2020.dts
+++ b/arch/arm/boot/dts/stih416-b2020.dts
@@ -12,4 +12,26 @@
/ {
model = "STiH416 B2020";
compatible = "st,stih416-b2020", "st,stih416";
+
+ soc {
+ mmc1: sdhci@fe81f000 {
+ status = "okay";
+ bus-width = <8>;
+ non-removable;
+ };
+
+ miphy365x_phy: phy@fe382000 {
+ phy_port0: port@fe382000 {
+ st,sata-gen = <3>;
+ };
+
+ phy_port1: port@fe38a000 {
+ st,pcie-tx-pol-inv;
+ };
+ };
+
+ sata0: sata@fe380000{
+ status = "okay";
+ };
+ };
};
diff --git a/arch/arm/boot/dts/stih416-b2020e.dts b/arch/arm/boot/dts/stih416-b2020e.dts
index ba0fa2c..961799e 100644
--- a/arch/arm/boot/dts/stih416-b2020e.dts
+++ b/arch/arm/boot/dts/stih416-b2020e.dts
@@ -19,17 +19,37 @@
red {
#gpio-cells = <1>;
label = "Front Panel LED";
- gpios = <&PIO4 1>;
+ gpios = <&pio4 1>;
linux,default-trigger = "heartbeat";
};
green {
- gpios = <&PIO1 3>;
+ gpios = <&pio1 3>;
default-state = "off";
};
};
ethernet1: dwmac@fef08000 {
- snps,reset-gpio = <&PIO0 7>;
+ snps,reset-gpio = <&pio0 7>;
+ };
+
+ mmc1: sdhci@fe81f000 {
+ status = "okay";
+ bus-width = <8>;
+ non-removable;
+ };
+
+ miphy365x_phy: phy@fe382000 {
+ phy_port0: port@fe382000 {
+ st,sata-gen = <3>;
+ };
+
+ phy_port1: port@fe38a000 {
+ st,pcie-tx-pol-inv;
+ };
+ };
+
+ sata0: sata@fe380000{
+ status = "okay";
};
};
};
diff --git a/arch/arm/boot/dts/stih416-pinctrl.dtsi b/arch/arm/boot/dts/stih416-pinctrl.dtsi
index ee6c119..9cccf2d 100644
--- a/arch/arm/boot/dts/stih416-pinctrl.dtsi
+++ b/arch/arm/boot/dts/stih416-pinctrl.dtsi
@@ -12,36 +12,36 @@
/ {
aliases {
- gpio0 = &PIO0;
- gpio1 = &PIO1;
- gpio2 = &PIO2;
- gpio3 = &PIO3;
- gpio4 = &PIO4;
- gpio5 = &PIO40;
- gpio6 = &PIO5;
- gpio7 = &PIO6;
- gpio8 = &PIO7;
- gpio9 = &PIO8;
- gpio10 = &PIO9;
- gpio11 = &PIO10;
- gpio12 = &PIO11;
- gpio13 = &PIO12;
- gpio14 = &PIO30;
- gpio15 = &PIO31;
- gpio16 = &PIO13;
- gpio17 = &PIO14;
- gpio18 = &PIO15;
- gpio19 = &PIO16;
- gpio20 = &PIO17;
- gpio21 = &PIO18;
- gpio22 = &PIO100;
- gpio23 = &PIO101;
- gpio24 = &PIO102;
- gpio25 = &PIO103;
- gpio26 = &PIO104;
- gpio27 = &PIO105;
- gpio28 = &PIO106;
- gpio29 = &PIO107;
+ gpio0 = &pio0;
+ gpio1 = &pio1;
+ gpio2 = &pio2;
+ gpio3 = &pio3;
+ gpio4 = &pio4;
+ gpio5 = &pio40;
+ gpio6 = &pio5;
+ gpio7 = &pio6;
+ gpio8 = &pio7;
+ gpio9 = &pio8;
+ gpio10 = &pio9;
+ gpio11 = &pio10;
+ gpio12 = &pio11;
+ gpio13 = &pio12;
+ gpio14 = &pio30;
+ gpio15 = &pio31;
+ gpio16 = &pio13;
+ gpio17 = &pio14;
+ gpio18 = &pio15;
+ gpio19 = &pio16;
+ gpio20 = &pio17;
+ gpio21 = &pio18;
+ gpio22 = &pio100;
+ gpio23 = &pio101;
+ gpio24 = &pio102;
+ gpio25 = &pio103;
+ gpio26 = &pio104;
+ gpio27 = &pio105;
+ gpio28 = &pio106;
+ gpio29 = &pio107;
};
soc {
@@ -56,7 +56,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfe610000 0x6000>;
- PIO0: gpio@fe610000 {
+ pio0: gpio@fe610000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -64,7 +64,7 @@
reg = <0 0x100>;
st,bank-name = "PIO0";
};
- PIO1: gpio@fe611000 {
+ pio1: gpio@fe611000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -72,7 +72,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO1";
};
- PIO2: gpio@fe612000 {
+ pio2: gpio@fe612000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -80,7 +80,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO2";
};
- PIO3: gpio@fe613000 {
+ pio3: gpio@fe613000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -88,7 +88,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO3";
};
- PIO4: gpio@fe614000 {
+ pio4: gpio@fe614000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -96,7 +96,7 @@
reg = <0x4000 0x100>;
st,bank-name = "PIO4";
};
- PIO40: gpio@fe615000 {
+ pio40: gpio@fe615000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -109,15 +109,15 @@
rc{
pinctrl_ir: ir0 {
st,pins {
- ir = <&PIO4 0 ALT2 IN>;
+ ir = <&pio4 0 ALT2 IN>;
};
};
};
sbc_serial1 {
pinctrl_sbc_serial1: sbc_serial1 {
st,pins {
- tx = <&PIO2 6 ALT3 OUT>;
- rx = <&PIO2 7 ALT3 IN>;
+ tx = <&pio2 6 ALT3 OUT>;
+ rx = <&pio2 7 ALT3 IN>;
};
};
};
@@ -125,15 +125,15 @@
keyscan {
pinctrl_keyscan: keyscan {
st,pins {
- keyin0 = <&PIO0 2 ALT2 IN>;
- keyin1 = <&PIO0 3 ALT2 IN>;
- keyin2 = <&PIO0 4 ALT2 IN>;
- keyin3 = <&PIO2 6 ALT2 IN>;
-
- keyout0 = <&PIO1 6 ALT2 OUT>;
- keyout1 = <&PIO1 7 ALT2 OUT>;
- keyout2 = <&PIO0 6 ALT2 OUT>;
- keyout3 = <&PIO2 7 ALT2 OUT>;
+ keyin0 = <&pio0 2 ALT2 IN>;
+ keyin1 = <&pio0 3 ALT2 IN>;
+ keyin2 = <&pio0 4 ALT2 IN>;
+ keyin3 = <&pio2 6 ALT2 IN>;
+
+ keyout0 = <&pio1 6 ALT2 OUT>;
+ keyout1 = <&pio1 7 ALT2 OUT>;
+ keyout2 = <&pio0 6 ALT2 OUT>;
+ keyout3 = <&pio2 7 ALT2 OUT>;
};
};
};
@@ -141,8 +141,17 @@
sbc_i2c0 {
pinctrl_sbc_i2c0_default: sbc_i2c0-default {
st,pins {
- sda = <&PIO4 6 ALT1 BIDIR>;
- scl = <&PIO4 5 ALT1 BIDIR>;
+ sda = <&pio4 6 ALT1 BIDIR>;
+ scl = <&pio4 5 ALT1 BIDIR>;
+ };
+ };
+ };
+
+ usb {
+ pinctrl_usb3: usb3 {
+ st,pins {
+ oc-detect = <&pio40 0 ALT1 IN>;
+ pwr-enable = <&pio40 1 ALT1 OUT>;
};
};
};
@@ -150,8 +159,8 @@
sbc_i2c1 {
pinctrl_sbc_i2c1_default: sbc_i2c1-default {
st,pins {
- sda = <&PIO3 2 ALT2 BIDIR>;
- scl = <&PIO3 1 ALT2 BIDIR>;
+ sda = <&pio3 2 ALT2 BIDIR>;
+ scl = <&pio3 1 ALT2 BIDIR>;
};
};
};
@@ -159,51 +168,51 @@
gmac1 {
pinctrl_mii1: mii1 {
st,pins {
- txd0 = <&PIO0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txd1 = <&PIO0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txd2 = <&PIO0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txd3 = <&PIO0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txer = <&PIO0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txen = <&PIO0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
- txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>;
- col = <&PIO0 7 ALT1 IN BYPASS 1000>;
-
- mdio = <&PIO1 0 ALT1 OUT BYPASS 1500>;
- mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>;
- crs = <&PIO1 2 ALT1 IN BYPASS 1000>;
- mdint = <&PIO1 3 ALT1 IN BYPASS 0>;
- rxd0 = <&PIO1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxd1 = <&PIO1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxd2 = <&PIO1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxd3 = <&PIO1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>;
-
- rxdv = <&PIO2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rx_er = <&PIO2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>;
- rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>;
- phyclk = <&PIO2 3 ALT1 OUT NICLK 0 CLK_A>;
+ txd0 = <&pio0 0 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd1 = <&pio0 1 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd2 = <&pio0 2 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txd3 = <&pio0 3 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txer = <&pio0 4 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txen = <&pio0 5 ALT1 OUT SE_NICLK_IO 0 CLK_A>;
+ txclk = <&pio0 6 ALT1 IN NICLK 0 CLK_A>;
+ col = <&pio0 7 ALT1 IN BYPASS 1000>;
+
+ mdio = <&pio1 0 ALT1 OUT BYPASS 1500>;
+ mdc = <&pio1 1 ALT1 OUT NICLK 0 CLK_A>;
+ crs = <&pio1 2 ALT1 IN BYPASS 1000>;
+ mdint = <&pio1 3 ALT1 IN BYPASS 0>;
+ rxd0 = <&pio1 4 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxd1 = <&pio1 5 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxd2 = <&pio1 6 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxd3 = <&pio1 7 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+
+ rxdv = <&pio2 0 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rx_er = <&pio2 1 ALT1 IN SE_NICLK_IO 0 CLK_A>;
+ rxclk = <&pio2 2 ALT1 IN NICLK 0 CLK_A>;
+ phyclk = <&pio2 3 ALT1 OUT NICLK 0 CLK_A>;
};
};
pinctrl_rgmii1: rgmii1-0 {
st,pins {
- txd0 = <&PIO0 0 ALT1 OUT DE_IO 500 CLK_A>;
- txd1 = <&PIO0 1 ALT1 OUT DE_IO 500 CLK_A>;
- txd2 = <&PIO0 2 ALT1 OUT DE_IO 500 CLK_A>;
- txd3 = <&PIO0 3 ALT1 OUT DE_IO 500 CLK_A>;
- txen = <&PIO0 5 ALT1 OUT DE_IO 0 CLK_A>;
- txclk = <&PIO0 6 ALT1 IN NICLK 0 CLK_A>;
-
- mdio = <&PIO1 0 ALT1 OUT BYPASS 0>;
- mdc = <&PIO1 1 ALT1 OUT NICLK 0 CLK_A>;
- rxd0 = <&PIO1 4 ALT1 IN DE_IO 500 CLK_A>;
- rxd1 = <&PIO1 5 ALT1 IN DE_IO 500 CLK_A>;
- rxd2 = <&PIO1 6 ALT1 IN DE_IO 500 CLK_A>;
- rxd3 = <&PIO1 7 ALT1 IN DE_IO 500 CLK_A>;
-
- rxdv = <&PIO2 0 ALT1 IN DE_IO 500 CLK_A>;
- rxclk = <&PIO2 2 ALT1 IN NICLK 0 CLK_A>;
- phyclk = <&PIO2 3 ALT4 OUT NICLK 0 CLK_B>;
-
- clk125= <&PIO3 7 ALT4 IN NICLK 0 CLK_A>;
+ txd0 = <&pio0 0 ALT1 OUT DE_IO 500 CLK_A>;
+ txd1 = <&pio0 1 ALT1 OUT DE_IO 500 CLK_A>;
+ txd2 = <&pio0 2 ALT1 OUT DE_IO 500 CLK_A>;
+ txd3 = <&pio0 3 ALT1 OUT DE_IO 500 CLK_A>;
+ txen = <&pio0 5 ALT1 OUT DE_IO 0 CLK_A>;
+ txclk = <&pio0 6 ALT1 IN NICLK 0 CLK_A>;
+
+ mdio = <&pio1 0 ALT1 OUT BYPASS 0>;
+ mdc = <&pio1 1 ALT1 OUT NICLK 0 CLK_A>;
+ rxd0 = <&pio1 4 ALT1 IN DE_IO 500 CLK_A>;
+ rxd1 = <&pio1 5 ALT1 IN DE_IO 500 CLK_A>;
+ rxd2 = <&pio1 6 ALT1 IN DE_IO 500 CLK_A>;
+ rxd3 = <&pio1 7 ALT1 IN DE_IO 500 CLK_A>;
+
+ rxdv = <&pio2 0 ALT1 IN DE_IO 500 CLK_A>;
+ rxclk = <&pio2 2 ALT1 IN NICLK 0 CLK_A>;
+ phyclk = <&pio2 3 ALT4 OUT NICLK 0 CLK_B>;
+
+ clk125= <&pio3 7 ALT4 IN NICLK 0 CLK_A>;
};
};
};
@@ -220,7 +229,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfee00000 0x10000>;
- PIO5: gpio@fee00000 {
+ pio5: gpio@fee00000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -228,7 +237,7 @@
reg = <0 0x100>;
st,bank-name = "PIO5";
};
- PIO6: gpio@fee01000 {
+ pio6: gpio@fee01000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -236,7 +245,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO6";
};
- PIO7: gpio@fee02000 {
+ pio7: gpio@fee02000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -244,7 +253,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO7";
};
- PIO8: gpio@fee03000 {
+ pio8: gpio@fee03000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -252,7 +261,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO8";
};
- PIO9: gpio@fee04000 {
+ pio9: gpio@fee04000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -260,7 +269,7 @@
reg = <0x4000 0x100>;
st,bank-name = "PIO9";
};
- PIO10: gpio@fee05000 {
+ pio10: gpio@fee05000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -268,7 +277,7 @@
reg = <0x5000 0x100>;
st,bank-name = "PIO10";
};
- PIO11: gpio@fee06000 {
+ pio11: gpio@fee06000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -276,7 +285,7 @@
reg = <0x6000 0x100>;
st,bank-name = "PIO11";
};
- PIO12: gpio@fee07000 {
+ pio12: gpio@fee07000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -284,7 +293,7 @@
reg = <0x7000 0x100>;
st,bank-name = "PIO12";
};
- PIO30: gpio@fee08000 {
+ pio30: gpio@fee08000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -292,7 +301,7 @@
reg = <0x8000 0x100>;
st,bank-name = "PIO30";
};
- PIO31: gpio@fee09000 {
+ pio31: gpio@fee09000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -304,7 +313,7 @@
serial2-oe {
pinctrl_serial2_oe: serial2-1 {
st,pins {
- output-enable = <&PIO11 3 ALT2 OUT>;
+ output-enable = <&pio11 3 ALT2 OUT>;
};
};
};
@@ -312,17 +321,27 @@
i2c0 {
pinctrl_i2c0_default: i2c0-default {
st,pins {
- sda = <&PIO9 3 ALT1 BIDIR>;
- scl = <&PIO9 2 ALT1 BIDIR>;
+ sda = <&pio9 3 ALT1 BIDIR>;
+ scl = <&pio9 2 ALT1 BIDIR>;
+ };
+ };
+ };
+
+ usb {
+ pinctrl_usb0: usb0 {
+ st,pins {
+ oc-detect = <&pio9 4 ALT1 IN>;
+ pwr-enable = <&pio9 5 ALT1 OUT>;
};
};
};
+
i2c1 {
pinctrl_i2c1_default: i2c1-default {
st,pins {
- sda = <&PIO12 1 ALT1 BIDIR>;
- scl = <&PIO12 0 ALT1 BIDIR>;
+ sda = <&pio12 1 ALT1 BIDIR>;
+ scl = <&pio12 0 ALT1 BIDIR>;
};
};
};
@@ -330,12 +349,12 @@
fsm {
pinctrl_fsm: fsm {
st,pins {
- spi-fsm-clk = <&PIO12 2 ALT1 OUT>;
- spi-fsm-cs = <&PIO12 3 ALT1 OUT>;
- spi-fsm-mosi = <&PIO12 4 ALT1 OUT>;
- spi-fsm-miso = <&PIO12 5 ALT1 IN>;
- spi-fsm-hol = <&PIO12 6 ALT1 OUT>;
- spi-fsm-wp = <&PIO12 7 ALT1 OUT>;
+ spi-fsm-clk = <&pio12 2 ALT1 OUT>;
+ spi-fsm-cs = <&pio12 3 ALT1 OUT>;
+ spi-fsm-mosi = <&pio12 4 ALT1 OUT>;
+ spi-fsm-miso = <&pio12 5 ALT1 IN>;
+ spi-fsm-hol = <&pio12 6 ALT1 OUT>;
+ spi-fsm-wp = <&pio12 7 ALT1 OUT>;
};
};
};
@@ -352,7 +371,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfe820000 0x6000>;
- PIO13: gpio@fe820000 {
+ pio13: gpio@fe820000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -360,7 +379,7 @@
reg = <0 0x100>;
st,bank-name = "PIO13";
};
- PIO14: gpio@fe821000 {
+ pio14: gpio@fe821000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -368,7 +387,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO14";
};
- PIO15: gpio@fe822000 {
+ pio15: gpio@fe822000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -376,7 +395,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO15";
};
- PIO16: gpio@fe823000 {
+ pio16: gpio@fe823000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -384,7 +403,7 @@
reg = <0x3000 0x100>;
st,bank-name = "PIO16";
};
- PIO17: gpio@fe824000 {
+ pio17: gpio@fe824000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -392,7 +411,7 @@
reg = <0x4000 0x100>;
st,bank-name = "PIO17";
};
- PIO18: gpio@fe825000 {
+ pio18: gpio@fe825000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -405,8 +424,8 @@
serial2 {
pinctrl_serial2: serial2-0 {
st,pins {
- tx = <&PIO17 4 ALT2 OUT>;
- rx = <&PIO17 5 ALT2 IN>;
+ tx = <&pio17 4 ALT2 OUT>;
+ rx = <&pio17 5 ALT2 IN>;
};
};
};
@@ -414,28 +433,28 @@
gmac0 {
pinctrl_mii0: mii0 {
st,pins {
- mdint = <&PIO13 6 ALT2 IN BYPASS 0>;
- txen = <&PIO13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- txd0 = <&PIO14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- txd1 = <&PIO14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- txd2 = <&PIO14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
- txd3 = <&PIO14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
-
- txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>;
- txer = <&PIO15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
- crs = <&PIO15 2 ALT2 IN BYPASS 1000>;
- col = <&PIO15 3 ALT2 IN BYPASS 1000>;
- mdio= <&PIO15 4 ALT2 OUT BYPASS 1500>;
- mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>;
-
- rxd0 = <&PIO16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxd1 = <&PIO16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxd2 = <&PIO16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxd3 = <&PIO16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxdv = <&PIO15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rx_er = <&PIO15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>;
- rxclk = <&PIO17 0 ALT2 IN NICLK 0 CLK_A>;
- phyclk = <&PIO13 5 ALT2 OUT NICLK 0 CLK_B>;
+ mdint = <&pio13 6 ALT2 IN BYPASS 0>;
+ txen = <&pio13 7 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ txd0 = <&pio14 0 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ txd1 = <&pio14 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ txd2 = <&pio14 2 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
+ txd3 = <&pio14 3 ALT2 OUT SE_NICLK_IO 0 CLK_B>;
+
+ txclk = <&pio15 0 ALT2 IN NICLK 0 CLK_A>;
+ txer = <&pio15 1 ALT2 OUT SE_NICLK_IO 0 CLK_A>;
+ crs = <&pio15 2 ALT2 IN BYPASS 1000>;
+ col = <&pio15 3 ALT2 IN BYPASS 1000>;
+ mdio= <&pio15 4 ALT2 OUT BYPASS 1500>;
+ mdc = <&pio15 5 ALT2 OUT NICLK 0 CLK_B>;
+
+ rxd0 = <&pio16 0 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxd1 = <&pio16 1 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxd2 = <&pio16 2 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxd3 = <&pio16 3 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxdv = <&pio15 6 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rx_er = <&pio15 7 ALT2 IN SE_NICLK_IO 0 CLK_A>;
+ rxclk = <&pio17 0 ALT2 IN NICLK 0 CLK_A>;
+ phyclk = <&pio13 5 ALT2 OUT NICLK 0 CLK_B>;
};
};
@@ -445,25 +464,79 @@
};
pinctrl_rgmii0: rgmii0 {
st,pins {
- phyclk = <&PIO13 5 ALT4 OUT NICLK 0 CLK_B>;
- txen = <&PIO13 7 ALT2 OUT DE_IO 0 CLK_A>;
- txd0 = <&PIO14 0 ALT2 OUT DE_IO 500 CLK_A>;
- txd1 = <&PIO14 1 ALT2 OUT DE_IO 500 CLK_A>;
- txd2 = <&PIO14 2 ALT2 OUT DE_IO 500 CLK_B>;
- txd3 = <&PIO14 3 ALT2 OUT DE_IO 500 CLK_B>;
- txclk = <&PIO15 0 ALT2 IN NICLK 0 CLK_A>;
-
- mdio = <&PIO15 4 ALT2 OUT BYPASS 0>;
- mdc = <&PIO15 5 ALT2 OUT NICLK 0 CLK_B>;
-
- rxdv = <&PIO15 6 ALT2 IN DE_IO 500 CLK_A>;
- rxd0 =<&PIO16 0 ALT2 IN DE_IO 500 CLK_A>;
- rxd1 =<&PIO16 1 ALT2 IN DE_IO 500 CLK_A>;
- rxd2 =<&PIO16 2 ALT2 IN DE_IO 500 CLK_A>;
- rxd3 =<&PIO16 3 ALT2 IN DE_IO 500 CLK_A>;
- rxclk =<&PIO17 0 ALT2 IN NICLK 0 CLK_A>;
-
- clk125=<&PIO17 6 ALT1 IN NICLK 0 CLK_A>;
+ phyclk = <&pio13 5 ALT4 OUT NICLK 0 CLK_B>;
+ txen = <&pio13 7 ALT2 OUT DE_IO 0 CLK_A>;
+ txd0 = <&pio14 0 ALT2 OUT DE_IO 500 CLK_A>;
+ txd1 = <&pio14 1 ALT2 OUT DE_IO 500 CLK_A>;
+ txd2 = <&pio14 2 ALT2 OUT DE_IO 500 CLK_B>;
+ txd3 = <&pio14 3 ALT2 OUT DE_IO 500 CLK_B>;
+ txclk = <&pio15 0 ALT2 IN NICLK 0 CLK_A>;
+
+ mdio = <&pio15 4 ALT2 OUT BYPASS 0>;
+ mdc = <&pio15 5 ALT2 OUT NICLK 0 CLK_B>;
+
+ rxdv = <&pio15 6 ALT2 IN DE_IO 500 CLK_A>;
+ rxd0 =<&pio16 0 ALT2 IN DE_IO 500 CLK_A>;
+ rxd1 =<&pio16 1 ALT2 IN DE_IO 500 CLK_A>;
+ rxd2 =<&pio16 2 ALT2 IN DE_IO 500 CLK_A>;
+ rxd3 =<&pio16 3 ALT2 IN DE_IO 500 CLK_A>;
+ rxclk =<&pio17 0 ALT2 IN NICLK 0 CLK_A>;
+
+ clk125=<&pio17 6 ALT1 IN NICLK 0 CLK_A>;
+ };
+ };
+ };
+
+ mmc0 {
+ pinctrl_mmc0: mmc0 {
+ st,pins {
+ mmcclk = <&pio13 4 ALT4 BIDIR_PU NICLK 0 CLK_B>;
+ data0 = <&pio14 4 ALT4 BIDIR_PU BYPASS 0>;
+ data1 = <&pio14 5 ALT4 BIDIR_PU BYPASS 0>;
+ data2 = <&pio14 6 ALT4 BIDIR_PU BYPASS 0>;
+ data3 = <&pio14 7 ALT4 BIDIR_PU BYPASS 0>;
+ cmd = <&pio15 1 ALT4 BIDIR_PU BYPASS 0>;
+ wp = <&pio15 3 ALT4 IN>;
+ data4 = <&pio16 4 ALT4 BIDIR_PU BYPASS 0>;
+ data5 = <&pio16 5 ALT4 BIDIR_PU BYPASS 0>;
+ data6 = <&pio16 6 ALT4 BIDIR_PU BYPASS 0>;
+ data7 = <&pio16 7 ALT4 BIDIR_PU BYPASS 0>;
+ pwr = <&pio17 1 ALT4 OUT>;
+ cd = <&pio17 2 ALT4 IN>;
+ led = <&pio17 3 ALT4 OUT>;
+ };
+ };
+ };
+ mmc1 {
+ pinctrl_mmc1: mmc1 {
+ st,pins {
+ mmcclk = <&pio15 0 ALT3 BIDIR_PU NICLK 0 CLK_B>;
+ data0 = <&pio13 7 ALT3 BIDIR_PU BYPASS 0>;
+ data1 = <&pio14 1 ALT3 BIDIR_PU BYPASS 0>;
+ data2 = <&pio14 2 ALT3 BIDIR_PU BYPASS 0>;
+ data3 = <&pio14 3 ALT3 BIDIR_PU BYPASS 0>;
+ cmd = <&pio15 4 ALT3 BIDIR_PU BYPASS 0>;
+ data4 = <&pio15 6 ALT3 BIDIR_PU BYPASS 0>;
+ data5 = <&pio15 7 ALT3 BIDIR_PU BYPASS 0>;
+ data6 = <&pio16 0 ALT3 BIDIR_PU BYPASS 0>;
+ data7 = <&pio16 1 ALT3 BIDIR_PU BYPASS 0>;
+ pwr = <&pio16 2 ALT3 OUT>;
+ nreset = <&pio13 6 ALT3 OUT>;
+ };
+ };
+ };
+
+ usb {
+ pinctrl_usb1: usb1 {
+ st,pins {
+ oc-detect = <&pio18 0 ALT1 IN>;
+ pwr-enable = <&pio18 1 ALT1 OUT>;
+ };
+ };
+ pinctrl_usb2: usb2 {
+ st,pins {
+ oc-detect = <&pio18 2 ALT1 IN>;
+ pwr-enable = <&pio18 3 ALT1 OUT>;
};
};
};
@@ -480,7 +553,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfd6b0000 0x3000>;
- PIO100: gpio@fd6b0000 {
+ pio100: gpio@fd6b0000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -488,7 +561,7 @@
reg = <0 0x100>;
st,bank-name = "PIO100";
};
- PIO101: gpio@fd6b1000 {
+ pio101: gpio@fd6b1000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -496,7 +569,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO101";
};
- PIO102: gpio@fd6b2000 {
+ pio102: gpio@fd6b2000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -517,7 +590,7 @@
interrupt-names = "irqmux";
ranges = <0 0xfd330000 0x5000>;
- PIO103: gpio@fd330000 {
+ pio103: gpio@fd330000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -525,7 +598,7 @@
reg = <0 0x100>;
st,bank-name = "PIO103";
};
- PIO104: gpio@fd331000 {
+ pio104: gpio@fd331000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -533,7 +606,7 @@
reg = <0x1000 0x100>;
st,bank-name = "PIO104";
};
- PIO105: gpio@fd332000 {
+ pio105: gpio@fd332000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -541,7 +614,7 @@
reg = <0x2000 0x100>;
st,bank-name = "PIO105";
};
- PIO106: gpio@fd333000 {
+ pio106: gpio@fd333000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
@@ -550,7 +623,7 @@
st,bank-name = "PIO106";
};
- PIO107: gpio@fd334000 {
+ pio107: gpio@fd334000 {
gpio-controller;
#gpio-cells = <1>;
interrupt-controller;
diff --git a/arch/arm/boot/dts/stih416.dtsi b/arch/arm/boot/dts/stih416.dtsi
index 84758d7..fad9073 100644
--- a/arch/arm/boot/dts/stih416.dtsi
+++ b/arch/arm/boot/dts/stih416.dtsi
@@ -9,6 +9,8 @@
#include "stih41x.dtsi"
#include "stih416-clock.dtsi"
#include "stih416-pinctrl.dtsi"
+
+#include <dt-bindings/phy/phy-miphy365x.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/reset-controller/stih416-resets.h>
/ {
@@ -236,5 +238,212 @@
resets = <&powerdown STIH416_KEYSCAN_POWERDOWN>,
<&softreset STIH416_KEYSCAN_SOFTRESET>;
};
+
+ temp0 {
+ compatible = "st,stih416-sas-thermal";
+ clock-names = "thermal";
+ clocks = <&clockgen_c_vcc 14>;
+
+ status = "okay";
+ };
+
+ temp1@fdfe8000 {
+ compatible = "st,stih416-mpe-thermal";
+ reg = <0xfdfe8000 0x10>;
+ clocks = <&clockgen_e 3>;
+ clock-names = "thermal";
+ interrupts = <GIC_SPI 23 IRQ_TYPE_EDGE_RISING>;
+
+ status = "okay";
+ };
+
+ mmc0: sdhci@fe81e000 {
+ compatible = "st,sdhci";
+ status = "disabled";
+ reg = <0xfe81e000 0x1000>;
+ interrupts = <GIC_SPI 127 IRQ_TYPE_NONE>;
+ interrupt-names = "mmcirq";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc0>;
+ clock-names = "mmc";
+ clocks = <&clk_s_a1_ls 1>;
+ };
+
+ mmc1: sdhci@fe81f000 {
+ compatible = "st,sdhci";
+ status = "disabled";
+ reg = <0xfe81f000 0x1000>;
+ interrupts = <GIC_SPI 128 IRQ_TYPE_NONE>;
+ interrupt-names = "mmcirq";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_mmc1>;
+ clock-names = "mmc";
+ clocks = <&clk_s_a1_ls 8>;
+ };
+
+ miphy365x_phy: phy@fe382000 {
+ compatible = "st,miphy365x-phy";
+ st,syscfg = <&syscfg_rear>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ phy_port0: port@fe382000 {
+ #phy-cells = <1>;
+ reg = <0xfe382000 0x100>, <0xfe394000 0x100>, <0x824 0x4>;
+ reg-names = "sata", "pcie", "syscfg";
+ };
+
+ phy_port1: port@fe38a000 {
+ #phy-cells = <1>;
+ reg = <0xfe38a000 0x100>, <0xfe804000 0x100>, <0x828 0x4>;
+ reg-names = "sata", "pcie", "syscfg";
+ };
+ };
+
+ sata0: sata@fe380000 {
+ compatible = "st,sti-ahci";
+ reg = <0xfe380000 0x1000>;
+ interrupts = <GIC_SPI 157 IRQ_TYPE_NONE>;
+ interrupt-names = "hostc";
+ phys = <&phy_port0 MIPHY_TYPE_SATA>;
+ phy-names = "sata-phy";
+ resets = <&powerdown STIH416_SATA0_POWERDOWN>,
+ <&softreset STIH416_SATA0_SOFTRESET>;
+ reset-names = "pwr-dwn", "sw-rst";
+ clock-names = "ahci_clk";
+ clocks = <&clk_s_a0_ls CLK_ICN_REG>;
+
+ status = "disabled";
+ };
+
+ usb2_phy: phy@0 {
+ compatible = "st,stih416-usb-phy";
+ #phy-cells = <0>;
+ st,syscfg = <&syscfg_rear>;
+ clocks = <&clk_sysin>;
+ clock-names = "osc_phy";
+ };
+
+ ehci0: usb@fe1ffe00 {
+ compatible = "st,st-ehci-300x";
+ reg = <0xfe1ffe00 0x100>;
+ interrupts = <GIC_SPI 148 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb0>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB0_POWERDOWN>,
+ <&softreset STIH416_USB0_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ohci0: usb@fe1ffc00 {
+ compatible = "st,st-ohci-300x";
+ reg = <0xfe1ffc00 0x100>;
+ interrupts = <GIC_SPI 149 IRQ_TYPE_NONE>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ status = "okay";
+ resets = <&powerdown STIH416_USB0_POWERDOWN>,
+ <&softreset STIH416_USB0_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ehci1: usb@fe203e00 {
+ compatible = "st,st-ehci-300x";
+ reg = <0xfe203e00 0x100>;
+ interrupts = <GIC_SPI 150 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb1>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB1_POWERDOWN>,
+ <&softreset STIH416_USB1_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ohci1: usb@fe203c00 {
+ compatible = "st,st-ohci-300x";
+ reg = <0xfe203c00 0x100>;
+ interrupts = <GIC_SPI 151 IRQ_TYPE_NONE>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB1_POWERDOWN>,
+ <&softreset STIH416_USB1_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ehci2: usb@fe303e00 {
+ compatible = "st,st-ehci-300x";
+ reg = <0xfe303e00 0x100>;
+ interrupts = <GIC_SPI 152 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb2>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB2_POWERDOWN>,
+ <&softreset STIH416_USB2_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ohci2: usb@fe303c00 {
+ compatible = "st,st-ohci-300x";
+ reg = <0xfe303c00 0x100>;
+ interrupts = <GIC_SPI 153 IRQ_TYPE_NONE>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB2_POWERDOWN>,
+ <&softreset STIH416_USB2_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ehci3: usb@fe343e00 {
+ compatible = "st,st-ehci-300x";
+ reg = <0xfe343e00 0x100>;
+ interrupts = <GIC_SPI 154 IRQ_TYPE_NONE>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usb3>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB3_POWERDOWN>,
+ <&softreset STIH416_USB3_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
+
+ ohci3: usb@fe343c00 {
+ compatible = "st,st-ohci-300x";
+ reg = <0xfe343c00 0x100>;
+ interrupts = <GIC_SPI 155 IRQ_TYPE_NONE>;
+ clocks = <&clk_s_a1_ls 0>,
+ <&clockgen_b0 0>;
+ clock-names = "ic", "clk48";
+ phys = <&usb2_phy>;
+ phy-names = "usb";
+ resets = <&powerdown STIH416_USB3_POWERDOWN>,
+ <&softreset STIH416_USB3_SOFTRESET>;
+ reset-names = "power", "softreset";
+ };
};
};
diff --git a/arch/arm/boot/dts/stih41x-b2000.dtsi b/arch/arm/boot/dts/stih41x-b2000.dtsi
index b3dd6ca..5f91f45 100644
--- a/arch/arm/boot/dts/stih41x-b2000.dtsi
+++ b/arch/arm/boot/dts/stih41x-b2000.dtsi
@@ -35,7 +35,7 @@
fp_led {
#gpio-cells = <1>;
label = "Front Panel LED";
- gpios = <&PIO105 7>;
+ gpios = <&pio105 7>;
linux,default-trigger = "heartbeat";
};
};
@@ -55,7 +55,7 @@
phy-mode = "mii";
pinctrl-0 = <&pinctrl_mii0>;
- snps,reset-gpio = <&PIO106 2>;
+ snps,reset-gpio = <&pio106 2>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 10000>;
};
@@ -65,7 +65,7 @@
phy-mode = "mii";
st,tx-retime-src = "txclk";
- snps,reset-gpio = <&PIO4 7>;
+ snps,reset-gpio = <&pio4 7>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 10000>;
};
diff --git a/arch/arm/boot/dts/stih41x-b2020.dtsi b/arch/arm/boot/dts/stih41x-b2020.dtsi
index d8a8429..487d7d8 100644
--- a/arch/arm/boot/dts/stih41x-b2020.dtsi
+++ b/arch/arm/boot/dts/stih41x-b2020.dtsi
@@ -32,11 +32,11 @@
red {
#gpio-cells = <1>;
label = "Front Panel LED";
- gpios = <&PIO4 1>;
+ gpios = <&pio4 1>;
linux,default-trigger = "heartbeat";
};
green {
- gpios = <&PIO4 7>;
+ gpios = <&pio4 7>;
default-state = "off";
};
};
@@ -68,11 +68,15 @@
phy-mode = "rgmii-id";
max-speed = <1000>;
st,tx-retime-src = "clk_125";
- snps,reset-gpio = <&PIO3 0>;
+ snps,reset-gpio = <&pio3 0>;
snps,reset-active-low;
snps,reset-delays-us = <0 10000 10000>;
pinctrl-0 = <&pinctrl_rgmii1>;
};
+
+ mmc0: sdhci@fe81e000 {
+ bus-width = <8>;
+ };
};
};
diff --git a/arch/arm/boot/dts/stih41x-b2020x.dtsi b/arch/arm/boot/dts/stih41x-b2020x.dtsi
index df01c12..f797a06 100644
--- a/arch/arm/boot/dts/stih41x-b2020x.dtsi
+++ b/arch/arm/boot/dts/stih41x-b2020x.dtsi
@@ -8,6 +8,10 @@
*/
/ {
soc {
+ mmc0: sdhci@fe81e000 {
+ status = "okay";
+ };
+
spifsm: spifsm@fe902000 {
#address-cells = <1>;
#size-cells = <1>;
diff --git a/arch/arm/boot/dts/stihxxx-b2120.dtsi b/arch/arm/boot/dts/stihxxx-b2120.dtsi
new file mode 100644
index 0000000..0074bd4
--- /dev/null
+++ b/arch/arm/boot/dts/stihxxx-b2120.dtsi
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics (R&D) Limited.
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.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.
+ */
+/ {
+ soc {
+ sbc_serial0: serial@9530000 {
+ status = "okay";
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ red {
+ #gpio-cells = <2>;
+ label = "Front Panel LED";
+ gpios = <&pio4 1 0>;
+ linux,default-trigger = "heartbeat";
+ };
+ green {
+ #gpio-cells = <2>;
+ gpios = <&pio1 3 0>;
+ default-state = "off";
+ };
+ };
+
+ i2c@9842000 {
+ status = "okay";
+ };
+
+ i2c@9843000 {
+ status = "okay";
+ };
+
+ i2c@9844000 {
+ status = "okay";
+ };
+
+ i2c@9845000 {
+ status = "okay";
+ };
+
+ i2c@9540000 {
+ status = "okay";
+ };
+
+ /* SSC11 to HDMI */
+ i2c@9541000 {
+ status = "okay";
+ /* HDMI V1.3a supports Standard mode only */
+ clock-frequency = <100000>;
+ st,i2c-min-scl-pulse-width-us = <0>;
+ st,i2c-min-sda-pulse-width-us = <5>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun4i-a10-a1000.dts b/arch/arm/boot/dts/sun4i-a10-a1000.dts
index 9e99ade..3bcfd818 100644
--- a/arch/arm/boot/dts/sun4i-a10-a1000.dts
+++ b/arch/arm/boot/dts/sun4i-a10-a1000.dts
@@ -3,12 +3,48 @@
*
* Emilio López <emilio@elopez.com.ar>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
index 1763cc7..f3f2974 100644
--- a/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
+++ b/arch/arm/boot/dts/sun4i-a10-ba10-tvbox.dts
@@ -1,12 +1,48 @@
/*
* Copyright 2014 Hans de Goede <hdegoede@redhat.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
index 3ce56bfb..6a310da 100644
--- a/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
+++ b/arch/arm/boot/dts/sun4i-a10-cubieboard.dts
@@ -2,12 +2,48 @@
* Copyright 2012 Stefan Roese
* Stefan Roese <sr@denx.de>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-hackberry.dts b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
index 891ea44..efc1162 100644
--- a/arch/arm/boot/dts/sun4i-a10-hackberry.dts
+++ b/arch/arm/boot/dts/sun4i-a10-hackberry.dts
@@ -3,12 +3,48 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
index 6b0c378..3e25ee4 100644
--- a/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
+++ b/arch/arm/boot/dts/sun4i-a10-inet97fv2.dts
@@ -3,12 +3,48 @@
*
* David Lanzendörfer <david.lanzendoerfer@o2s.ch>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
index b9ecce6..8b3f974 100644
--- a/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
+++ b/arch/arm/boot/dts/sun4i-a10-mini-xplus.dts
@@ -3,12 +3,48 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
index d046d56..88cf1a5 100644
--- a/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun4i-a10-olinuxino-lime.dts
@@ -1,12 +1,48 @@
/*
* Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10-pcduino.dts b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
index 6675bcd..ce59945 100644
--- a/arch/arm/boot/dts/sun4i-a10-pcduino.dts
+++ b/arch/arm/boot/dts/sun4i-a10-pcduino.dts
@@ -2,12 +2,48 @@
* Copyright 2014 Zoltan HERPAI
* Zoltan HERPAI <wigyori@uid0.hu>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun4i-a10.dtsi b/arch/arm/boot/dts/sun4i-a10.dtsi
index 380f914..e3ab942 100644
--- a/arch/arm/boot/dts/sun4i-a10.dtsi
+++ b/arch/arm/boot/dts/sun4i-a10.dtsi
@@ -27,6 +27,20 @@
serial7 = &uart7;
};
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@0 {
+ compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-hdmi";
+ clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+ <&ahb_gates 44>;
+ status = "disabled";
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
diff --git a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
index ea9519d..fe3c559 100644
--- a/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-olinuxino-micro.dts
@@ -3,12 +3,48 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
index 43a9376..1fa2916 100644
--- a/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
+++ b/arch/arm/boot/dts/sun5i-a10s-r7-tv-dongle.dts
@@ -1,12 +1,48 @@
/*
* Copyright 2014 Hans de Goede <hdegoede@redhat.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun5i-a10s.dtsi b/arch/arm/boot/dts/sun5i-a10s.dtsi
index 531272c..81ad4b9 100644
--- a/arch/arm/boot/dts/sun5i-a10s.dtsi
+++ b/arch/arm/boot/dts/sun5i-a10s.dtsi
@@ -24,6 +24,20 @@
serial3 = &uart3;
};
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@0 {
+ compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-hdmi";
+ clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+ <&ahb_gates 44>;
+ status = "disabled";
+ };
+ };
+
cpus {
cpu@0 {
compatible = "arm,cortex-a8";
diff --git a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
index 8b3cd090..eeed1f2 100644
--- a/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
+++ b/arch/arm/boot/dts/sun5i-a13-hsg-h702.dts
@@ -6,18 +6,18 @@
* licensing only applies to this file, and not this project as a
* whole.
*
- * a) This library is free software; you can redistribute it and/or
+ * a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free
+ * License along with this file; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
index fa44b02..916ee8b 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino-micro.dts
@@ -1,15 +1,49 @@
/*
- * Copyright 2012 Maxime Ripard
+ * Copyright 2012 Maxime Ripard <maxime.ripard@free-electrons.com>
* Copyright 2013 Hans de Goede <hdegoede@redhat.com>
*
- * Maxime Ripard <maxime.ripard@free-electrons.com>
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
index 429994e..e31d291 100644
--- a/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
+++ b/arch/arm/boot/dts/sun5i-a13-olinuxino.dts
@@ -3,12 +3,48 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
index 2bbf886..c74a63a 100644
--- a/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
+++ b/arch/arm/boot/dts/sun6i-a31-app4-evb1.dts
@@ -3,12 +3,48 @@
*
* Boris Brezillon <boris.brezillon@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun6i-a31-colombus.dts b/arch/arm/boot/dts/sun6i-a31-colombus.dts
index 546cf6e..c36b4dc 100644
--- a/arch/arm/boot/dts/sun6i-a31-colombus.dts
+++ b/arch/arm/boot/dts/sun6i-a31-colombus.dts
@@ -3,12 +3,48 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
index f142065..6e924d9 100644
--- a/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
+++ b/arch/arm/boot/dts/sun6i-a31-hummingbird.dts
@@ -3,12 +3,48 @@
*
* Maxime Ripard <maxime.ripard@free-electrons.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun6i-a31-m9.dts b/arch/arm/boot/dts/sun6i-a31-m9.dts
index bc6115d..3ab544f 100644
--- a/arch/arm/boot/dts/sun6i-a31-m9.dts
+++ b/arch/arm/boot/dts/sun6i-a31-m9.dts
@@ -1,12 +1,48 @@
/*
* Copyright 2014 Hans de Goede <hdegoede@redhat.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
@@ -32,13 +68,40 @@
status = "okay";
};
+ usbphy: phy@01c19400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ status = "okay";
+ };
+
+ ehci0: usb@01c1a000 {
+ status = "okay";
+ };
+
+ ehci1: usb@01c1b000 {
+ status = "okay";
+ };
+
pio: pinctrl@01c20800 {
+ led_pins_m9: led_pins@0 {
+ allwinner,pins = "PH13";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
mmc0_cd_pin_m9: mmc0_cd_pin@0 {
allwinner,pins = "PH22";
allwinner,function = "gpio_in";
allwinner,drive = <0>;
allwinner,pull = <1>;
};
+
+ usb1_vbus_pin_m9: usb1_vbus_pin@0 {
+ allwinner,pins = "PC27";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
uart0: serial@01c28000 {
@@ -46,5 +109,35 @@
pinctrl-0 = <&uart0_pins_a>;
status = "okay";
};
+
+ gmac: ethernet@01c30000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_m9>;
+
+ blue {
+ label = "m9:blue:usr";
+ gpios = <&pio 7 13 0>;
+ };
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb1_vbus_pin_m9>;
+ gpio = <&pio 2 27 0>;
+ status = "okay";
};
};
diff --git a/arch/arm/boot/dts/sun6i-a31.dtsi b/arch/arm/boot/dts/sun6i-a31.dtsi
index 2e652e2..a400172 100644
--- a/arch/arm/boot/dts/sun6i-a31.dtsi
+++ b/arch/arm/boot/dts/sun6i-a31.dtsi
@@ -8,18 +8,18 @@
* licensing only applies to this file, and not this project as a
* whole.
*
- * a) This library is free software; you can redistribute it and/or
+ * a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free
+ * License along with this file; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
@@ -62,6 +62,18 @@
ethernet0 = &gmac;
};
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@0 {
+ compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-hdmi";
+ clocks = <&pll6 0>;
+ status = "disabled";
+ };
+ };
cpus {
enable-method = "allwinner,sun6i-a31";
@@ -132,11 +144,11 @@
};
pll6: clk@01c20028 {
- #clock-cells = <0>;
+ #clock-cells = <1>;
compatible = "allwinner,sun6i-a31-pll6-clk";
reg = <0x01c20028 0x4>;
clocks = <&osc24M>;
- clock-output-names = "pll6";
+ clock-output-names = "pll6", "pll6x2";
};
cpu: cpu@01c20050 {
@@ -166,7 +178,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun6i-a31-ahb1-mux-clk";
reg = <0x01c20054 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6>;
+ clocks = <&osc32k>, <&osc24M>, <&axi>, <&pll6 0>;
clock-output-names = "ahb1_mux";
};
@@ -221,7 +233,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-apb1-mux-clk";
reg = <0x01c20058 0x4>;
- clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
clock-output-names = "apb2_mux";
};
@@ -248,7 +260,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c20088 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "mmc0";
};
@@ -256,7 +268,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c2008c 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "mmc1";
};
@@ -264,7 +276,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c20090 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "mmc2";
};
@@ -272,7 +284,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c20094 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "mmc3";
};
@@ -280,7 +292,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c200a0 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "spi0";
};
@@ -288,7 +300,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c200a4 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "spi1";
};
@@ -296,7 +308,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c200a8 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "spi2";
};
@@ -304,7 +316,7 @@
#clock-cells = <0>;
compatible = "allwinner,sun4i-a10-mod0-clk";
reg = <0x01c200ac 0x4>;
- clocks = <&osc24M>, <&pll6>;
+ clocks = <&osc24M>, <&pll6 0>;
clock-output-names = "spi3";
};
@@ -364,7 +376,7 @@
/* DMA controller requires AHB1 clocked from PLL6 */
assigned-clocks = <&ahb1_mux>;
- assigned-clock-parents = <&pll6>;
+ assigned-clock-parents = <&pll6 0>;
};
mmc0: mmc@01c0f000 {
@@ -844,7 +856,7 @@
ar100: ar100_clk {
compatible = "allwinner,sun6i-a31-ar100-clk";
#clock-cells = <0>;
- clocks = <&osc32k>, <&osc24M>, <&pll6>, <&pll6>;
+ clocks = <&osc32k>, <&osc24M>, <&pll6 0>, <&pll6 0>;
clock-output-names = "ar100";
};
diff --git a/arch/arm/boot/dts/sun7i-a20-bananapi.dts b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
new file mode 100644
index 0000000..1cf1214
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-bananapi.dts
@@ -0,0 +1,214 @@
+/*
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
+
+/ {
+ model = "LeMaker Banana Pi";
+ compatible = "lemaker,bananapi", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ spi0: spi@01c05000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&spi0_pins_a>;
+ status = "okay";
+ };
+
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_bananapi>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 10 0>; /* PH10 */
+ cd-inverted;
+ status = "okay";
+ };
+
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+ };
+
+ ehci0: usb@01c14000 {
+ status = "okay";
+ };
+
+ ohci0: usb@01c14400 {
+ status = "okay";
+ };
+
+ ahci: sata@01c18000 {
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ mmc0_cd_pin_bananapi: mmc0_cd_pin@0 {
+ allwinner,pins = "PH10";
+ allwinner,function = "gpio_in";
+ allwinner,drive = <0>;
+ allwinner,pull = <1>;
+ };
+
+ gmac_power_pin_bananapi: gmac_power_pin@0 {
+ allwinner,pins = "PH23";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ led_pins_bananapi: led_pins@0 {
+ allwinner,pins = "PH24";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ ir0: ir@01c21800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_pins_a>;
+ status = "okay";
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ uart3: serial@01c28c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart3_pins_b>;
+ status = "okay";
+ };
+
+ uart7: serial@01c29c00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart7_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ i2c2: i2c@01c2b400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c2_pins_a>;
+ status = "okay";
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ phy-supply = <&reg_gmac_3v3>;
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_bananapi>;
+
+ green {
+ label = "bananapi:green:usr";
+ gpios = <&pio 7 24 0>;
+ };
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
+
+ reg_gmac_3v3: gmac-3v3 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_power_pin_bananapi>;
+ regulator-name = "gmac-3v3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ startup-delay-us = <100000>;
+ enable-active-high;
+ gpio = <&pio 7 23 0>;
+ };
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
index a6c1a3c..a281d25 100644
--- a/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
+++ b/arch/arm/boot/dts/sun7i-a20-cubietruck.dts
@@ -40,6 +40,7 @@
};
usbphy: phy@01c13400 {
+ usb0_vbus-supply = <&reg_usb0_vbus>;
usb1_vbus-supply = <&reg_usb1_vbus>;
usb2_vbus-supply = <&reg_usb2_vbus>;
status = "okay";
@@ -92,6 +93,13 @@
allwinner,drive = <0>;
allwinner,pull = <0>;
};
+
+ usb0_vbus_pin_a: usb0_vbus_pin@0 {
+ allwinner,pins = "PH17";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
};
pwm: pwm@01c20e00 {
@@ -185,6 +193,12 @@
status = "okay";
};
+ reg_usb0_vbus: usb0-vbus {
+ pinctrl-0 = <&usb0_vbus_pin_a>;
+ gpio = <&pio 7 17 0>;
+ status = "okay";
+ };
+
reg_usb1_vbus: usb1-vbus {
status = "okay";
};
diff --git a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
index 6a67712..f38bb1a 100644
--- a/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
+++ b/arch/arm/boot/dts/sun7i-a20-i12-tvbox.dts
@@ -1,12 +1,48 @@
/*
* Copyright 2014 Hans de Goede <hdegoede@redhat.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun7i-a20-m3.dts b/arch/arm/boot/dts/sun7i-a20-m3.dts
new file mode 100644
index 0000000..b8e568c
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-m3.dts
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2014 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Hans de Goede <hdegoede@redhat.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
+
+/ {
+ model = "Mele M3";
+ compatible = "mele,m3", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 0>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+ };
+
+ mmc2: mmc@01c11000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc2_pins_a>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ non-removable;
+ status = "okay";
+ };
+
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+ };
+
+ ehci0: usb@01c14000 {
+ status = "okay";
+ };
+
+ ohci0: usb@01c14400 {
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ led_pins_m3: led_pins@0 {
+ allwinner,pins = "PH20";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ ir0: ir@01c21800 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&ir0_pins_a>;
+ status = "okay";
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ };
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_mii_a>;
+ phy = <&phy1>;
+ phy-mode = "mii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_m3>;
+
+ blue {
+ label = "m3:blue:usr";
+ gpios = <&pio 7 20 0>;
+ };
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
index 1eb8175..3f3ff96 100644
--- a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime.dts
@@ -4,12 +4,48 @@
* Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
* Copyright (c) 2014 FUKAUMI Naoki <naobsd@gmail.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
new file mode 100644
index 0000000..ed364d5
--- /dev/null
+++ b/arch/arm/boot/dts/sun7i-a20-olinuxino-lime2.dts
@@ -0,0 +1,228 @@
+/*
+ * Copyright 2014 - Iain Paton <ipaton0@gmail.com>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun7i-a20.dtsi"
+/include/ "sunxi-common-regulators.dtsi"
+
+/ {
+ model = "Olimex A20-OLinuXino-LIME2";
+ compatible = "olimex,a20-olinuxino-lime2", "allwinner,sun7i-a20";
+
+ soc@01c00000 {
+ mmc0: mmc@01c0f000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&mmc0_pins_a>, <&mmc0_cd_pin_reference_design>;
+ vmmc-supply = <&reg_vcc3v3>;
+ bus-width = <4>;
+ cd-gpios = <&pio 7 1 0>; /* PH1 */
+ cd-inverted;
+ status = "okay";
+ };
+
+ usbphy: phy@01c13400 {
+ usb1_vbus-supply = <&reg_usb1_vbus>;
+ usb2_vbus-supply = <&reg_usb2_vbus>;
+ status = "okay";
+ };
+
+ ehci0: usb@01c14000 {
+ status = "okay";
+ };
+
+ ohci0: usb@01c14400 {
+ status = "okay";
+ };
+
+ ahci: sata@01c18000 {
+ target-supply = <&reg_ahci_5v>;
+ status = "okay";
+ };
+
+ ehci1: usb@01c1c000 {
+ status = "okay";
+ };
+
+ ohci1: usb@01c1c400 {
+ status = "okay";
+ };
+
+ pinctrl@01c20800 {
+ ahci_pwr_pin_olinuxinolime: ahci_pwr_pin@1 {
+ allwinner,pins = "PC3";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ led_pins_olinuxinolime: led_pins@0 {
+ allwinner,pins = "PH2";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <1>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ uart0: serial@01c28000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ i2c0: i2c@01c2ac00 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c0_pins_a>;
+ status = "okay";
+
+ axp209: pmic@34 {
+ compatible = "x-powers,axp209";
+ reg = <0x34>;
+ interrupt-parent = <&nmi_intc>;
+ interrupts = <0 8>;
+
+ interrupt-controller;
+ #interrupt-cells = <1>;
+
+ acin-supply = <&reg_axp_ipsout>;
+ vin2-supply = <&reg_axp_ipsout>;
+ vin3-supply = <&reg_axp_ipsout>;
+ ldo24in-supply = <&reg_axp_ipsout>;
+ ldo3in-supply = <&reg_axp_ipsout>;
+
+ regulators {
+ vdd_rtc: ldo1 {
+ regulator-min-microvolt = <1300000>;
+ regulator-max-microvolt = <1300000>;
+ regulator-always-on;
+ };
+
+ avcc: ldo2 {
+ regulator-min-microvolt = <1800000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vcc_csi0: ldo3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
+ };
+
+ vcc_csi1: ldo4 {
+ regulator-min-microvolt = <1250000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ vdd_cpu: dcdc2 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <2275000>;
+ regulator-always-on;
+ };
+
+ vdd_int: dcdc3 {
+ regulator-min-microvolt = <700000>;
+ regulator-max-microvolt = <3500000>;
+ regulator-always-on;
+ };
+ };
+ };
+ };
+
+ i2c1: i2c@01c2b000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c1_pins_a>;
+ status = "okay";
+ };
+
+ gmac: ethernet@01c50000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&gmac_pins_rgmii_a>;
+ phy = <&phy1>;
+ phy-mode = "rgmii";
+ status = "okay";
+
+ phy1: ethernet-phy@1 {
+ reg = <1>;
+ };
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_olinuxinolime>;
+
+ green {
+ label = "a20-olinuxino-lime2:green:usr";
+ gpios = <&pio 7 2 0>;
+ default-state = "on";
+ };
+ };
+
+ reg_ahci_5v: ahci-5v {
+ pinctrl-0 = <&ahci_pwr_pin_olinuxinolime>;
+ gpio = <&pio 2 3 0>;
+ status = "okay";
+ };
+
+ reg_usb1_vbus: usb1-vbus {
+ status = "okay";
+ };
+
+ reg_usb2_vbus: usb2-vbus {
+ status = "okay";
+ };
+
+ reg_axp_ipsout: axp_ipsout {
+ compatible = "regulator-fixed";
+ regulator-name = "axp-ipsout";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+};
diff --git a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
index 046dfc0..8dca49b 100644
--- a/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
+++ b/arch/arm/boot/dts/sun7i-a20-pcduino3.dts
@@ -2,12 +2,48 @@
* Copyright 2014 Zoltan HERPAI
* Zoltan HERPAI <wigyori@uid0.hu>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun7i-a20.dtsi b/arch/arm/boot/dts/sun7i-a20.dtsi
index 82097c9..82a524c 100644
--- a/arch/arm/boot/dts/sun7i-a20.dtsi
+++ b/arch/arm/boot/dts/sun7i-a20.dtsi
@@ -8,18 +8,18 @@
* licensing only applies to this file, and not this project as a
* whole.
*
- * a) This library is free software; you can redistribute it and/or
+ * a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free
+ * License along with this file; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
@@ -64,6 +64,20 @@
serial7 = &uart7;
};
+ chosen {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ framebuffer@0 {
+ compatible = "allwinner,simple-framebuffer", "simple-framebuffer";
+ allwinner,pipeline = "de_be0-lcd0-hdmi";
+ clocks = <&pll5 1>, <&ahb_gates 36>, <&ahb_gates 43>,
+ <&ahb_gates 44>;
+ status = "disabled";
+ };
+ };
+
cpus {
#address-cells = <1>;
#size-cells = <0>;
@@ -552,8 +566,8 @@
reg-names = "phy_ctrl", "pmu1", "pmu2";
clocks = <&usb_clk 8>;
clock-names = "usb_phy";
- resets = <&usb_clk 1>, <&usb_clk 2>;
- reset-names = "usb1_reset", "usb2_reset";
+ resets = <&usb_clk 0>, <&usb_clk 1>, <&usb_clk 2>;
+ reset-names = "usb0_reset", "usb1_reset", "usb2_reset";
status = "disabled";
};
@@ -677,6 +691,13 @@
allwinner,pull = <0>;
};
+ uart3_pins_b: uart3@1 {
+ allwinner,pins = "PH0", "PH1";
+ allwinner,function = "uart3";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
uart4_pins_a: uart4@0 {
allwinner,pins = "PG10", "PG11";
allwinner,function = "uart4";
@@ -784,6 +805,13 @@
allwinner,pull = <0>;
};
+ spi0_pins_a: spi0@0 {
+ allwinner,pins = "PI10", "PI11", "PI12", "PI13", "PI14";
+ allwinner,function = "spi0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
spi1_pins_a: spi1@0 {
allwinner,pins = "PI16", "PI17", "PI18", "PI19";
allwinner,function = "spi1";
@@ -819,6 +847,13 @@
allwinner,pull = <1>;
};
+ mmc2_pins_a: mmc2@0 {
+ allwinner,pins = "PC6","PC7","PC8","PC9","PC10","PC11";
+ allwinner,function = "mmc2";
+ allwinner,drive = <2>;
+ allwinner,pull = <1>;
+ };
+
mmc3_pins_a: mmc3@0 {
allwinner,pins = "PI4","PI5","PI6","PI7","PI8","PI9";
allwinner,function = "mmc3";
diff --git a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
index e9b8cca..7f2117c 100644
--- a/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
+++ b/arch/arm/boot/dts/sun8i-a23-ippo-q8h-v5.dts
@@ -3,12 +3,48 @@
*
* Chen-Yu Tsai <wens@csie.org>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/dts-v1/;
diff --git a/arch/arm/boot/dts/sun8i-a23.dtsi b/arch/arm/boot/dts/sun8i-a23.dtsi
index 6146ef1..6086adb 100644
--- a/arch/arm/boot/dts/sun8i-a23.dtsi
+++ b/arch/arm/boot/dts/sun8i-a23.dtsi
@@ -8,18 +8,18 @@
* licensing only applies to this file, and not this project as a
* whole.
*
- * a) This library is free software; you can redistribute it and/or
+ * a) This file is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
- * This library is distributed in the hope that it will be useful,
+ * This file is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
- * License along with this library; if not, write to the Free
+ * License along with this file; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
* MA 02110-1301 USA
*
diff --git a/arch/arm/boot/dts/sun9i-a80-optimus.dts b/arch/arm/boot/dts/sun9i-a80-optimus.dts
new file mode 100644
index 0000000..506948f
--- /dev/null
+++ b/arch/arm/boot/dts/sun9i-a80-optimus.dts
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/dts-v1/;
+/include/ "sun9i-a80.dtsi"
+
+/ {
+ model = "Merrii A80 Optimus Board";
+ compatible = "merrii,a80-optimus", "allwinner,sun9i-a80";
+
+ chosen {
+ bootargs = "earlyprintk console=ttyS0,115200";
+ };
+
+ soc {
+ pio: pinctrl@06000800 {
+ i2c3_pins_a: i2c3@0 {
+ /* Enable internal pull-up */
+ allwinner,pull = <1>;
+ };
+
+ led_pins_optimus: led-pins@0 {
+ allwinner,pins = "PH0", "PH1";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart4_pins_a: uart4@0 {
+ /* Enable internal pull-up */
+ allwinner,pull = <1>;
+ };
+ };
+
+ uart0: serial@07000000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart0_pins_a>;
+ status = "okay";
+ };
+
+ uart4: serial@07001000 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&uart4_pins_a>;
+ status = "okay";
+ };
+
+ i2c3: i2c@07003400 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&i2c3_pins_a>;
+ status = "okay";
+ };
+ };
+
+ leds {
+ compatible = "gpio-leds";
+ pinctrl-names = "default";
+ pinctrl-0 = <&led_pins_optimus>;
+
+ /* The LED names match those found on the board */
+
+ led2 {
+ label = "optimus:led2:usr";
+ gpios = <&pio 7 1 0>;
+ };
+
+ /* led3 is on PM15, in R_PIO */
+
+ led4 {
+ label = "optimus:led4:usr";
+ gpios = <&pio 7 0 0>;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sun9i-a80.dtsi b/arch/arm/boot/dts/sun9i-a80.dtsi
new file mode 100644
index 0000000..494714f
--- /dev/null
+++ b/arch/arm/boot/dts/sun9i-a80.dtsi
@@ -0,0 +1,514 @@
+/*
+ * Copyright 2014 Chen-Yu Tsai
+ *
+ * Chen-Yu Tsai <wens@csie.org>
+ *
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
+ *
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/include/ "skeleton64.dtsi"
+
+/ {
+ interrupt-parent = <&gic>;
+
+ aliases {
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ serial4 = &uart4;
+ serial5 = &uart5;
+ serial6 = &r_uart;
+ };
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu0: cpu@0 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0x0>;
+ };
+
+ cpu1: cpu@1 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0x1>;
+ };
+
+ cpu2: cpu@2 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0x2>;
+ };
+
+ cpu3: cpu@3 {
+ compatible = "arm,cortex-a7";
+ device_type = "cpu";
+ reg = <0x3>;
+ };
+
+ cpu4: cpu@100 {
+ compatible = "arm,cortex-a15";
+ device_type = "cpu";
+ reg = <0x100>;
+ };
+
+ cpu5: cpu@101 {
+ compatible = "arm,cortex-a15";
+ device_type = "cpu";
+ reg = <0x101>;
+ };
+
+ cpu6: cpu@102 {
+ compatible = "arm,cortex-a15";
+ device_type = "cpu";
+ reg = <0x102>;
+ };
+
+ cpu7: cpu@103 {
+ compatible = "arm,cortex-a15";
+ device_type = "cpu";
+ reg = <0x103>;
+ };
+ };
+
+ memory {
+ /* 8GB max. with LPAE */
+ reg = <0 0x20000000 0x02 0>;
+ };
+
+ clocks {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /*
+ * map 64 bit address range down to 32 bits,
+ * as the peripherals are all under 512MB.
+ */
+ ranges = <0 0 0 0x20000000>;
+
+ osc24M: osc24M_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <24000000>;
+ clock-output-names = "osc24M";
+ };
+
+ osc32k: osc32k_clk {
+ #clock-cells = <0>;
+ compatible = "fixed-clock";
+ clock-frequency = <32768>;
+ clock-output-names = "osc32k";
+ };
+
+ pll4: clk@0600000c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-pll4-clk";
+ reg = <0x0600000c 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll4";
+ };
+
+ pll12: clk@0600002c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-pll4-clk";
+ reg = <0x0600002c 0x4>;
+ clocks = <&osc24M>;
+ clock-output-names = "pll12";
+ };
+
+ gt_clk: clk@0600005c {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-gt-clk";
+ reg = <0x0600005c 0x4>;
+ clocks = <&osc24M>, <&pll4>, <&pll12>, <&pll12>;
+ clock-output-names = "gt";
+ };
+
+ ahb0: clk@06000060 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-ahb-clk";
+ reg = <0x06000060 0x4>;
+ clocks = <&gt_clk>, <&pll4>, <&pll12>, <&pll12>;
+ clock-output-names = "ahb0";
+ };
+
+ ahb1: clk@06000064 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-ahb-clk";
+ reg = <0x06000064 0x4>;
+ clocks = <&gt_clk>, <&pll4>, <&pll12>, <&pll12>;
+ clock-output-names = "ahb1";
+ };
+
+ ahb2: clk@06000068 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-ahb-clk";
+ reg = <0x06000068 0x4>;
+ clocks = <&gt_clk>, <&pll4>, <&pll12>, <&pll12>;
+ clock-output-names = "ahb2";
+ };
+
+ apb0: clk@06000070 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-apb0-clk";
+ reg = <0x06000070 0x4>;
+ clocks = <&osc24M>, <&pll4>;
+ clock-output-names = "apb0";
+ };
+
+ apb1: clk@06000074 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-apb1-clk";
+ reg = <0x06000074 0x4>;
+ clocks = <&osc24M>, <&pll4>;
+ clock-output-names = "apb1";
+ };
+
+ cci400_clk: clk@06000078 {
+ #clock-cells = <0>;
+ compatible = "allwinner,sun9i-a80-gt-clk";
+ reg = <0x06000078 0x4>;
+ clocks = <&osc24M>, <&pll4>, <&pll12>, <&pll12>;
+ clock-output-names = "cci400";
+ };
+
+ ahb0_gates: clk@06000580 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun9i-a80-ahb0-gates-clk";
+ reg = <0x06000580 0x4>;
+ clocks = <&ahb0>;
+ clock-output-names = "ahb0_fd", "ahb0_ve", "ahb0_gpu",
+ "ahb0_ss", "ahb0_sd", "ahb0_nand1",
+ "ahb0_nand0", "ahb0_sdram",
+ "ahb0_mipi_hsi", "ahb0_sata", "ahb0_ts",
+ "ahb0_spi0","ahb0_spi1", "ahb0_spi2",
+ "ahb0_spi3";
+ };
+
+ ahb1_gates: clk@06000584 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun9i-a80-ahb1-gates-clk";
+ reg = <0x06000584 0x4>;
+ clocks = <&ahb1>;
+ clock-output-names = "ahb1_usbotg", "ahb1_usbhci",
+ "ahb1_gmac", "ahb1_msgbox",
+ "ahb1_spinlock", "ahb1_hstimer",
+ "ahb1_dma";
+ };
+
+ ahb2_gates: clk@06000588 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun9i-a80-ahb2-gates-clk";
+ reg = <0x06000588 0x4>;
+ clocks = <&ahb2>;
+ clock-output-names = "ahb2_lcd0", "ahb2_lcd1",
+ "ahb2_edp", "ahb2_csi", "ahb2_hdmi",
+ "ahb2_de", "ahb2_mp", "ahb2_mipi_dsi";
+ };
+
+ apb0_gates: clk@06000590 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun9i-a80-apb0-gates-clk";
+ reg = <0x06000590 0x4>;
+ clocks = <&apb0>;
+ clock-output-names = "apb0_spdif", "apb0_pio",
+ "apb0_ac97", "apb0_i2s0", "apb0_i2s1",
+ "apb0_lradc", "apb0_gpadc", "apb0_twd",
+ "apb0_cirtx";
+ };
+
+ apb1_gates: clk@06000594 {
+ #clock-cells = <1>;
+ compatible = "allwinner,sun9i-a80-apb1-gates-clk";
+ reg = <0x06000594 0x4>;
+ clocks = <&apb1>;
+ clock-output-names = "apb1_i2c0", "apb1_i2c1",
+ "apb1_i2c2", "apb1_i2c3", "apb1_i2c4",
+ "apb1_uart0", "apb1_uart1",
+ "apb1_uart2", "apb1_uart3",
+ "apb1_uart4", "apb1_uart5";
+ };
+ };
+
+ soc {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ /*
+ * map 64 bit address range down to 32 bits,
+ * as the peripherals are all under 512MB.
+ */
+ ranges = <0 0 0 0x20000000>;
+
+ gic: interrupt-controller@01c41000 {
+ compatible = "arm,cortex-a7-gic", "arm,cortex-a15-gic";
+ reg = <0x01c41000 0x1000>,
+ <0x01c42000 0x1000>,
+ <0x01c44000 0x2000>,
+ <0x01c46000 0x2000>;
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ interrupts = <1 9 0xf04>;
+ };
+
+ ahb0_resets: reset@060005a0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x060005a0 0x4>;
+ };
+
+ ahb1_resets: reset@060005a4 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x060005a4 0x4>;
+ };
+
+ ahb2_resets: reset@060005a8 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x060005a8 0x4>;
+ };
+
+ apb0_resets: reset@060005b0 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x060005b0 0x4>;
+ };
+
+ apb1_resets: reset@060005b4 {
+ #reset-cells = <1>;
+ compatible = "allwinner,sun6i-a31-clock-reset";
+ reg = <0x060005b4 0x4>;
+ };
+
+ timer@06000c00 {
+ compatible = "allwinner,sun4i-a10-timer";
+ reg = <0x06000c00 0xa0>;
+ interrupts = <0 18 4>,
+ <0 19 4>,
+ <0 20 4>,
+ <0 21 4>,
+ <0 22 4>,
+ <0 23 4>;
+
+ clocks = <&osc24M>;
+ };
+
+ pio: pinctrl@06000800 {
+ compatible = "allwinner,sun9i-a80-pinctrl";
+ reg = <0x06000800 0x400>;
+ interrupts = <0 11 4>,
+ <0 15 4>,
+ <0 16 4>,
+ <0 17 4>,
+ <0 120 4>;
+ clocks = <&apb0_gates 5>;
+ gpio-controller;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ #size-cells = <0>;
+ #gpio-cells = <3>;
+
+ i2c3_pins_a: i2c3@0 {
+ allwinner,pins = "PG10", "PG11";
+ allwinner,function = "i2c3";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart0_pins_a: uart0@0 {
+ allwinner,pins = "PH12", "PH13";
+ allwinner,function = "uart0";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
+ uart4_pins_a: uart4@0 {
+ allwinner,pins = "PG12", "PG13", "PG14", "PG15";
+ allwinner,function = "uart4";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+ };
+
+ uart0: serial@07000000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x07000000 0x400>;
+ interrupts = <0 0 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 16>;
+ resets = <&apb1_resets 16>;
+ status = "disabled";
+ };
+
+ uart1: serial@07000400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x07000400 0x400>;
+ interrupts = <0 1 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 17>;
+ resets = <&apb1_resets 17>;
+ status = "disabled";
+ };
+
+ uart2: serial@07000800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x07000800 0x400>;
+ interrupts = <0 2 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 18>;
+ resets = <&apb1_resets 18>;
+ status = "disabled";
+ };
+
+ uart3: serial@07000c00 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x07000c00 0x400>;
+ interrupts = <0 3 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 19>;
+ resets = <&apb1_resets 19>;
+ status = "disabled";
+ };
+
+ uart4: serial@07001000 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x07001000 0x400>;
+ interrupts = <0 4 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 20>;
+ resets = <&apb1_resets 20>;
+ status = "disabled";
+ };
+
+ uart5: serial@07001400 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x07001400 0x400>;
+ interrupts = <0 5 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&apb1_gates 21>;
+ resets = <&apb1_resets 21>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@07002800 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x07002800 0x400>;
+ interrupts = <0 6 4>;
+ clocks = <&apb1_gates 0>;
+ resets = <&apb1_resets 0>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c1: i2c@07002c00 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x07002c00 0x400>;
+ interrupts = <0 7 4>;
+ clocks = <&apb1_gates 1>;
+ resets = <&apb1_resets 1>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c2: i2c@07003000 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x07003000 0x400>;
+ interrupts = <0 8 4>;
+ clocks = <&apb1_gates 2>;
+ resets = <&apb1_resets 2>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c3: i2c@07003400 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x07003400 0x400>;
+ interrupts = <0 9 4>;
+ clocks = <&apb1_gates 3>;
+ resets = <&apb1_resets 3>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ i2c4: i2c@07003800 {
+ compatible = "allwinner,sun6i-a31-i2c";
+ reg = <0x07003800 0x400>;
+ interrupts = <0 10 4>;
+ clocks = <&apb1_gates 4>;
+ resets = <&apb1_resets 4>;
+ status = "disabled";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ r_wdt: watchdog@08001000 {
+ compatible = "allwinner,sun6i-a31-wdt";
+ reg = <0x08001000 0x20>;
+ interrupts = <0 36 4>;
+ };
+
+ r_uart: serial@08002800 {
+ compatible = "snps,dw-apb-uart";
+ reg = <0x08002800 0x400>;
+ interrupts = <0 38 4>;
+ reg-shift = <2>;
+ reg-io-width = <4>;
+ clocks = <&osc24M>;
+ status = "disabled";
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/sunxi-common-regulators.dtsi b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
index c9c5b10..d887663 100644
--- a/arch/arm/boot/dts/sunxi-common-regulators.dtsi
+++ b/arch/arm/boot/dts/sunxi-common-regulators.dtsi
@@ -3,12 +3,48 @@
*
* Copyright 2014 - Hans de Goede <hdegoede@redhat.com>
*
- * The code contained herein is licensed under the GNU General Public
- * License. You may obtain a copy of the GNU General Public License
- * Version 2 or later at the following locations:
+ * This file is dual-licensed: you can use it either under the terms
+ * of the GPL or the X11 license, at your option. Note that this dual
+ * licensing only applies to this file, and not this project as a
+ * whole.
*
- * http://www.opensource.org/licenses/gpl-license.html
- * http://www.gnu.org/copyleft/gpl.html
+ * a) This file is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation; either version 2 of the
+ * License, or (at your option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public
+ * License along with this file; if not, write to the Free
+ * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+ * MA 02110-1301 USA
+ *
+ * Or, alternatively,
+ *
+ * b) Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
*/
/ {
@@ -21,6 +57,13 @@
allwinner,pull = <0>;
};
+ usb0_vbus_pin_a: usb0_vbus_pin@0 {
+ allwinner,pins = "PB9";
+ allwinner,function = "gpio_out";
+ allwinner,drive = <0>;
+ allwinner,pull = <0>;
+ };
+
usb1_vbus_pin_a: usb1_vbus_pin@0 {
allwinner,pins = "PH6";
allwinner,function = "gpio_out";
@@ -44,11 +87,24 @@
regulator-name = "ahci-5v";
regulator-min-microvolt = <5000000>;
regulator-max-microvolt = <5000000>;
+ regulator-boot-on;
enable-active-high;
gpio = <&pio 1 8 0>;
status = "disabled";
};
+ reg_usb0_vbus: usb0-vbus {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&usb0_vbus_pin_a>;
+ regulator-name = "usb0-vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ enable-active-high;
+ gpio = <&pio 1 9 0>;
+ status = "disabled";
+ };
+
reg_usb1_vbus: usb1-vbus {
compatible = "regulator-fixed";
pinctrl-names = "default";
diff --git a/arch/arm/boot/dts/tegra30-cardhu.dtsi b/arch/arm/boot/dts/tegra30-cardhu.dtsi
index a1b682e..cbf5a1a 100644
--- a/arch/arm/boot/dts/tegra30-cardhu.dtsi
+++ b/arch/arm/boot/dts/tegra30-cardhu.dtsi
@@ -189,7 +189,7 @@
/* ALS and Proximity sensor */
isl29028@44 {
- compatible = "isil,isl29028";
+ compatible = "isl,isl29028";
reg = <0x44>;
interrupt-parent = <&gpio>;
interrupts = <TEGRA_GPIO(L, 0) IRQ_TYPE_LEVEL_HIGH>;
diff --git a/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
new file mode 100644
index 0000000..56a452b
--- /dev/null
+++ b/arch/arm/boot/dts/vf-colibri-eval-v3.dtsi
@@ -0,0 +1,96 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * 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.
+ */
+
+/ {
+ chosen {
+ bootargs = "console=ttyLP0,115200";
+ };
+
+ regulators {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sys_5v0_reg: regulator@0 {
+ compatible = "regulator-fixed";
+ reg = <0>;
+ regulator-name = "5v0";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ regulator-always-on;
+ };
+
+ /* USBH_PEN */
+ usbh_vbus_reg: regulator@1 {
+ compatible = "regulator-fixed";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_usbh1_reg>;
+ reg = <1>;
+ regulator-name = "usbh_vbus";
+ regulator-min-microvolt = <5000000>;
+ regulator-max-microvolt = <5000000>;
+ gpio = <&gpio3 19 GPIO_ACTIVE_LOW>;
+ vin-supply = <&sys_5v0_reg>;
+ };
+ };
+};
+
+&bl {
+ brightness-levels = <0 4 8 16 32 64 128 255>;
+ default-brightness-level = <6>;
+ status = "okay";
+};
+
+&esdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_esdhc1>;
+ bus-width = <4>;
+ status = "okay";
+};
+
+&fec1 {
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec1>;
+ status = "okay";
+};
+
+&i2c0 {
+ status = "okay";
+
+ /* M41T0M6 real time clock on carrier board */
+ rtc: m41t0m6@68 {
+ compatible = "st,m41t00";
+ reg = <0x68>;
+ };
+};
+
+&pwm0 {
+ status = "okay";
+};
+
+&pwm1 {
+ status = "okay";
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
+
+&uart2 {
+ status = "okay";
+};
+
+&usbh1 {
+ vbus-supply = <&usbh_vbus_reg>;
+};
diff --git a/arch/arm/boot/dts/vf-colibri.dtsi b/arch/arm/boot/dts/vf-colibri.dtsi
new file mode 100644
index 0000000..82f5728
--- /dev/null
+++ b/arch/arm/boot/dts/vf-colibri.dtsi
@@ -0,0 +1,186 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * 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.
+ */
+
+/ {
+ bl: backlight {
+ compatible = "pwm-backlight";
+ pwms = <&pwm0 0 5000000 0>;
+ status = "disabled";
+ };
+};
+
+&adc0 {
+ status = "okay";
+};
+
+&adc1 {
+ status = "okay";
+};
+
+&edma0 {
+ status = "okay";
+};
+
+&esdhc1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_esdhc1>;
+ bus-width = <4>;
+ cd-gpios = <&gpio2 10 GPIO_ACTIVE_LOW>;
+};
+
+&fec1 {
+ phy-mode = "rmii";
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_fec1>;
+};
+
+&i2c0 {
+ clock-frequency = <400000>;
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_i2c0>;
+};
+
+&pwm0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm0>;
+};
+
+&pwm1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_pwm1>;
+};
+
+&uart0 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart0>;
+};
+
+&uart1 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart1>;
+};
+
+&uart2 {
+ pinctrl-names = "default";
+ pinctrl-0 = <&pinctrl_uart2>;
+};
+
+&usbdev0 {
+ disable-over-current;
+ status = "okay";
+};
+
+&usbh1 {
+ disable-over-current;
+ status = "okay";
+};
+
+&usbmisc0 {
+ status = "okay";
+};
+
+&usbmisc1 {
+ status = "okay";
+};
+
+&usbphy0 {
+ status = "okay";
+};
+
+&usbphy1 {
+ status = "okay";
+};
+
+&iomuxc {
+ vf610-colibri {
+ pinctrl_gpio_ext: gpio_ext {
+ fsl,pins = <
+ VF610_PAD_PTD10__GPIO_89 0x22ed /* EXT_IO_0 */
+ VF610_PAD_PTD9__GPIO_88 0x22ed /* EXT_IO_1 */
+ VF610_PAD_PTD26__GPIO_68 0x22ed /* EXT_IO_2 */
+ >;
+ };
+
+ pinctrl_esdhc1: esdhc1grp {
+ fsl,pins = <
+ VF610_PAD_PTA24__ESDHC1_CLK 0x31ef
+ VF610_PAD_PTA25__ESDHC1_CMD 0x31ef
+ VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef
+ VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef
+ VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef
+ VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef
+ VF610_PAD_PTB20__GPIO_42 0x219d
+ >;
+ };
+
+ pinctrl_fec1: fec1grp {
+ fsl,pins = <
+ VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
+ VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
+ VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
+ VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
+ VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
+ VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
+ VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
+ VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2
+ VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2
+ >;
+ };
+
+ pinctrl_i2c0: i2c0grp {
+ fsl,pins = <
+ VF610_PAD_PTB14__I2C0_SCL 0x37ff
+ VF610_PAD_PTB15__I2C0_SDA 0x37ff
+ >;
+ };
+
+ pinctrl_pwm0: pwm0grp {
+ fsl,pins = <
+ VF610_PAD_PTB0__FTM0_CH0 0x1182
+ VF610_PAD_PTB1__FTM0_CH1 0x1182
+ >;
+ };
+
+ pinctrl_pwm1: pwm1grp {
+ fsl,pins = <
+ VF610_PAD_PTB8__FTM1_CH0 0x1182
+ VF610_PAD_PTB9__FTM1_CH1 0x1182
+ >;
+ };
+
+ pinctrl_uart0: uart0grp {
+ fsl,pins = <
+ VF610_PAD_PTB10__UART0_TX 0x21a2
+ VF610_PAD_PTB11__UART0_RX 0x21a1
+ >;
+ };
+
+ pinctrl_uart1: uart1grp {
+ fsl,pins = <
+ VF610_PAD_PTB4__UART1_TX 0x21a2
+ VF610_PAD_PTB5__UART1_RX 0x21a1
+ >;
+ };
+
+ pinctrl_uart2: uart2grp {
+ fsl,pins = <
+ VF610_PAD_PTD0__UART2_TX 0x21a2
+ VF610_PAD_PTD1__UART2_RX 0x21a1
+ VF610_PAD_PTD2__UART2_RTS 0x21a2
+ VF610_PAD_PTD3__UART2_CTS 0x21a1
+ >;
+ };
+
+ pinctrl_usbh1_reg: gpio_usb_vbus {
+ fsl,pins = <
+ VF610_PAD_PTD4__GPIO_83 0x22ed
+ >;
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/vf500-colibri-eval-v3.dts b/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
new file mode 100644
index 0000000..7fc782c
--- /dev/null
+++ b/arch/arm/boot/dts/vf500-colibri-eval-v3.dts
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * 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 "vf500-colibri.dtsi"
+#include "vf-colibri-eval-v3.dtsi"
+
+/ {
+ model = "Toradex Colibri VF50 on Colibri Evaluation Board";
+ compatible = "toradex,vf500-colibri_vf50-on-eval", "toradex,vf500-colibri_vf50", "fsl,vf500";
+};
diff --git a/arch/arm/boot/dts/vf500-colibri.dtsi b/arch/arm/boot/dts/vf500-colibri.dtsi
new file mode 100644
index 0000000..cee34a3
--- /dev/null
+++ b/arch/arm/boot/dts/vf500-colibri.dtsi
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2014 Toradex AG
+ *
+ * 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 "vf500.dtsi"
+#include "vf-colibri.dtsi"
+
+/ {
+ model = "Toradex Colibri VF50 COM";
+ compatible = "toradex,vf610-colibri_vf50", "fsl,vf500";
+
+ memory {
+ reg = <0x80000000 0x8000000>;
+ };
+};
diff --git a/arch/arm/boot/dts/vf500.dtsi b/arch/arm/boot/dts/vf500.dtsi
new file mode 100644
index 0000000..de67005
--- /dev/null
+++ b/arch/arm/boot/dts/vf500.dtsi
@@ -0,0 +1,171 @@
+/*
+ * 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 "skeleton.dtsi"
+#include "vfxxx.dtsi"
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ a5_cpu: cpu@0 {
+ compatible = "arm,cortex-a5";
+ device_type = "cpu";
+ reg = <0x0>;
+ };
+ };
+
+ soc {
+ interrupt-parent = <&intc>;
+
+ aips-bus@40000000 {
+
+ intc: interrupt-controller@40002000 {
+ compatible = "arm,cortex-a9-gic";
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ reg = <0x40003000 0x1000>,
+ <0x40002100 0x100>;
+ };
+
+ global_timer: timer@40002200 {
+ compatible = "arm,cortex-a9-global-timer";
+ reg = <0x40002200 0x20>;
+ interrupts = <GIC_PPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&clks VF610_CLK_PLATFORM_BUS>;
+ };
+ };
+ };
+};
+
+&adc0 {
+ interrupts = <GIC_SPI 53 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&adc1 {
+ interrupts = <GIC_SPI 54 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&can0 {
+ interrupts = <GIC_SPI 58 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&can1 {
+ interrupts = <GIC_SPI 59 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&dspi0 {
+ interrupts = <GIC_SPI 67 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&edma0 {
+ interrupts = <GIC_SPI 8 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 9 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma-tx", "edma-err";
+};
+
+&edma1 {
+ interrupts = <GIC_SPI 10 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 11 IRQ_TYPE_LEVEL_HIGH>;
+ interrupt-names = "edma-tx", "edma-err";
+};
+
+&esdhc1 {
+ interrupts = <GIC_SPI 28 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&fec0 {
+ interrupts = <GIC_SPI 78 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&fec1 {
+ interrupts = <GIC_SPI 79 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&ftm {
+ interrupts = <GIC_SPI 44 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&gpio1 {
+ interrupts = <GIC_SPI 107 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&gpio2 {
+ interrupts = <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&gpio3 {
+ interrupts = <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&gpio4 {
+ interrupts = <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&gpio5 {
+ interrupts = <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&i2c0 {
+ interrupts = <GIC_SPI 71 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&pit {
+ interrupts = <GIC_SPI 39 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&qspi0 {
+ interrupts = <GIC_SPI 24 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&sai2 {
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart0 {
+ interrupts = <GIC_SPI 61 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart1 {
+ interrupts = <GIC_SPI 62 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart2 {
+ interrupts = <GIC_SPI 63 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart3 {
+ interrupts = <GIC_SPI 64 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart4 {
+ interrupts = <GIC_SPI 65 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&uart5 {
+ interrupts = <GIC_SPI 66 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&usbdev0 {
+ interrupts = <GIC_SPI 75 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&usbh1 {
+ interrupts = <GIC_SPI 76 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&usbphy0 {
+ interrupts = <GIC_SPI 50 IRQ_TYPE_LEVEL_HIGH>;
+};
+
+&usbphy1 {
+ interrupts = <GIC_SPI 51 IRQ_TYPE_LEVEL_HIGH>;
+};
diff --git a/arch/arm/boot/dts/vf610-colibri-eval-v3.dts b/arch/arm/boot/dts/vf610-colibri-eval-v3.dts
index 7fb3066..10ebe99 100644
--- a/arch/arm/boot/dts/vf610-colibri-eval-v3.dts
+++ b/arch/arm/boot/dts/vf610-colibri-eval-v3.dts
@@ -9,38 +9,9 @@
/dts-v1/;
#include "vf610-colibri.dtsi"
+#include "vf-colibri-eval-v3.dtsi"
/ {
model = "Toradex Colibri VF61 on Colibri Evaluation Board";
compatible = "toradex,vf610-colibri_vf61-on-eval", "toradex,vf610-colibri_vf61", "fsl,vf610";
-
- chosen {
- bootargs = "console=ttyLP0,115200";
- };
-};
-
-&esdhc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_esdhc1>;
- bus-width = <4>;
- status = "okay";
-};
-
-&fec1 {
- phy-mode = "rmii";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_fec1>;
- status = "okay";
-};
-
-&uart0 {
- status = "okay";
-};
-
-&uart1 {
- status = "okay";
-};
-
-&uart2 {
- status = "okay";
-};
+}; \ No newline at end of file
diff --git a/arch/arm/boot/dts/vf610-colibri.dtsi b/arch/arm/boot/dts/vf610-colibri.dtsi
index 0cd8343..19fe045 100644
--- a/arch/arm/boot/dts/vf610-colibri.dtsi
+++ b/arch/arm/boot/dts/vf610-colibri.dtsi
@@ -8,6 +8,7 @@
*/
#include "vf610.dtsi"
+#include "vf-colibri.dtsi"
/ {
model = "Toradex Colibri VF61 COM";
@@ -16,108 +17,9 @@
memory {
reg = <0x80000000 0x10000000>;
};
-
- clocks {
- enet_ext {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <50000000>;
- };
- };
-
-};
-
-&esdhc1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_esdhc1>;
- bus-width = <4>;
-};
-
-&fec1 {
- phy-mode = "rmii";
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_fec1>;
};
&L2 {
arm,data-latency = <2 1 2>;
arm,tag-latency = <3 2 3>;
};
-
-&uart0 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart0>;
-};
-
-&uart1 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart1>;
-};
-
-&uart2 {
- pinctrl-names = "default";
- pinctrl-0 = <&pinctrl_uart2>;
-};
-
-&usbdev0 {
- disable-over-current;
- status = "okay";
-};
-
-&usbh1 {
- disable-over-current;
- status = "okay";
-};
-
-&iomuxc {
- vf610-colibri {
- pinctrl_esdhc1: esdhc1grp {
- fsl,pins = <
- VF610_PAD_PTA24__ESDHC1_CLK 0x31ef
- VF610_PAD_PTA25__ESDHC1_CMD 0x31ef
- VF610_PAD_PTA26__ESDHC1_DAT0 0x31ef
- VF610_PAD_PTA27__ESDHC1_DAT1 0x31ef
- VF610_PAD_PTA28__ESDHC1_DATA2 0x31ef
- VF610_PAD_PTA29__ESDHC1_DAT3 0x31ef
- VF610_PAD_PTB20__GPIO_42 0x219d
- >;
- };
-
- pinctrl_fec1: fec1grp {
- fsl,pins = <
- VF610_PAD_PTC9__ENET_RMII1_MDC 0x30d2
- VF610_PAD_PTC10__ENET_RMII1_MDIO 0x30d3
- VF610_PAD_PTC11__ENET_RMII1_CRS 0x30d1
- VF610_PAD_PTC12__ENET_RMII_RXD1 0x30d1
- VF610_PAD_PTC13__ENET_RMII1_RXD0 0x30d1
- VF610_PAD_PTC14__ENET_RMII1_RXER 0x30d1
- VF610_PAD_PTC15__ENET_RMII1_TXD1 0x30d2
- VF610_PAD_PTC16__ENET_RMII1_TXD0 0x30d2
- VF610_PAD_PTC17__ENET_RMII1_TXEN 0x30d2
- >;
- };
-
- pinctrl_uart0: uart0grp {
- fsl,pins = <
- VF610_PAD_PTB10__UART0_TX 0x21a2
- VF610_PAD_PTB11__UART0_RX 0x21a1
- >;
- };
-
- pinctrl_uart1: uart1grp {
- fsl,pins = <
- VF610_PAD_PTB4__UART1_TX 0x21a2
- VF610_PAD_PTB5__UART1_RX 0x21a1
- >;
- };
-
- pinctrl_uart2: uart2grp {
- fsl,pins = <
- VF610_PAD_PTD0__UART2_TX 0x21a2
- VF610_PAD_PTD1__UART2_RX 0x21a1
- VF610_PAD_PTD2__UART2_RTS 0x21a2
- VF610_PAD_PTD3__UART2_CTS 0x21a1
- >;
- };
- };
-};
diff --git a/arch/arm/boot/dts/vf610-cosmic.dts b/arch/arm/boot/dts/vf610-cosmic.dts
index de1b453..fd8758b 100644
--- a/arch/arm/boot/dts/vf610-cosmic.dts
+++ b/arch/arm/boot/dts/vf610-cosmic.dts
@@ -23,14 +23,16 @@
reg = <0x80000000 0x10000000>;
};
- clocks {
- enet_ext {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <50000000>;
- };
+ enet_ext: enet_ext {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
};
+};
+&clks {
+ clocks = <&sxosc>, <&fxosc>, <&enet_ext>;
+ clock-names = "sxosc", "fxosc", "enet_ext";
};
&esdhc1 {
diff --git a/arch/arm/boot/dts/vf610-twr.dts b/arch/arm/boot/dts/vf610-twr.dts
index 189b697..a0f7621 100644
--- a/arch/arm/boot/dts/vf610-twr.dts
+++ b/arch/arm/boot/dts/vf610-twr.dts
@@ -22,18 +22,16 @@
reg = <0x80000000 0x8000000>;
};
- clocks {
- audio_ext {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <24576000>;
- };
+ audio_ext: mclk_osc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24576000>;
+ };
- enet_ext {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <50000000>;
- };
+ enet_ext: eth_osc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
};
regulators {
@@ -95,6 +93,11 @@
status = "okay";
};
+&clks {
+ clocks = <&sxosc>, <&fxosc>, <&enet_ext>, <&audio_ext>;
+ clock-names = "sxosc", "fxosc", "enet_ext", "audio_ext";
+};
+
&dspi0 {
bus-num = <0>;
pinctrl-names = "default";
@@ -112,10 +115,15 @@
};
};
+&edma0 {
+ status = "okay";
+};
+
&esdhc1 {
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_esdhc1>;
bus-width = <4>;
+ cd-gpios = <&gpio5 6 GPIO_ACTIVE_LOW>;
status = "okay";
};
@@ -285,3 +293,19 @@
disable-over-current;
status = "okay";
};
+
+&usbmisc0 {
+ status = "okay";
+};
+
+&usbmisc1 {
+ status = "okay";
+};
+
+&usbphy0 {
+ status = "okay";
+};
+
+&usbphy1 {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/vf610.dtsi b/arch/arm/boot/dts/vf610.dtsi
index 4d2ec32..5f8eb1b 100644
--- a/arch/arm/boot/dts/vf610.dtsi
+++ b/arch/arm/boot/dts/vf610.dtsi
@@ -7,481 +7,19 @@
* (at your option) any later version.
*/
-#include "skeleton.dtsi"
-#include "vf610-pinfunc.h"
-#include <dt-bindings/clock/vf610-clock.h>
-#include <dt-bindings/interrupt-controller/irq.h>
+#include "vf500.dtsi"
-/ {
- aliases {
- can0 = &can0;
- can1 = &can1;
- serial0 = &uart0;
- serial1 = &uart1;
- serial2 = &uart2;
- serial3 = &uart3;
- serial4 = &uart4;
- serial5 = &uart5;
- gpio0 = &gpio1;
- gpio1 = &gpio2;
- gpio2 = &gpio3;
- gpio3 = &gpio4;
- gpio4 = &gpio5;
- usbphy0 = &usbphy0;
- usbphy1 = &usbphy1;
- };
-
- cpus {
- #address-cells = <1>;
- #size-cells = <0>;
-
- cpu@0 {
- compatible = "arm,cortex-a5";
- device_type = "cpu";
- reg = <0x0>;
- next-level-cache = <&L2>;
- };
- };
-
- clocks {
- #address-cells = <1>;
- #size-cells = <0>;
-
- sxosc {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <32768>;
- };
-
- fxosc {
- compatible = "fixed-clock";
- #clock-cells = <0>;
- clock-frequency = <24000000>;
- };
- };
-
- soc {
- #address-cells = <1>;
- #size-cells = <1>;
- compatible = "simple-bus";
- interrupt-parent = <&intc>;
- ranges;
-
- aips0: aips-bus@40000000 {
- compatible = "fsl,aips-bus", "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- interrupt-parent = <&intc>;
- reg = <0x40000000 0x70000>;
- ranges;
-
- intc: interrupt-controller@40002000 {
- compatible = "arm,cortex-a9-gic";
- #interrupt-cells = <3>;
- interrupt-controller;
- reg = <0x40003000 0x1000>,
- <0x40002100 0x100>;
- };
-
- L2: l2-cache@40006000 {
- compatible = "arm,pl310-cache";
- reg = <0x40006000 0x1000>;
- cache-unified;
- cache-level = <2>;
- arm,data-latency = <1 1 1>;
- arm,tag-latency = <2 2 2>;
- };
-
- edma0: dma-controller@40018000 {
- #dma-cells = <2>;
- compatible = "fsl,vf610-edma";
- reg = <0x40018000 0x2000>,
- <0x40024000 0x1000>,
- <0x40025000 0x1000>;
- interrupts = <0 8 IRQ_TYPE_LEVEL_HIGH>,
- <0 9 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "edma-tx", "edma-err";
- dma-channels = <32>;
- clock-names = "dmamux0", "dmamux1";
- clocks = <&clks VF610_CLK_DMAMUX0>,
- <&clks VF610_CLK_DMAMUX1>;
- };
-
- can0: flexcan@40020000 {
- compatible = "fsl,vf610-flexcan";
- reg = <0x40020000 0x4000>;
- interrupts = <0 58 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_FLEXCAN0>,
- <&clks VF610_CLK_FLEXCAN0>;
- clock-names = "ipg", "per";
- status = "disabled";
- };
-
- uart0: serial@40027000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40027000 0x1000>;
- interrupts = <0 61 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_UART0>;
- clock-names = "ipg";
- dmas = <&edma0 0 2>,
- <&edma0 0 3>;
- dma-names = "rx","tx";
- status = "disabled";
- };
-
- uart1: serial@40028000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40028000 0x1000>;
- interrupts = <0 62 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_UART1>;
- clock-names = "ipg";
- dmas = <&edma0 0 4>,
- <&edma0 0 5>;
- dma-names = "rx","tx";
- status = "disabled";
- };
-
- uart2: serial@40029000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x40029000 0x1000>;
- interrupts = <0 63 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_UART2>;
- clock-names = "ipg";
- dmas = <&edma0 0 6>,
- <&edma0 0 7>;
- dma-names = "rx","tx";
- status = "disabled";
- };
-
- uart3: serial@4002a000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x4002a000 0x1000>;
- interrupts = <0 64 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_UART3>;
- clock-names = "ipg";
- dmas = <&edma0 0 8>,
- <&edma0 0 9>;
- dma-names = "rx","tx";
- status = "disabled";
- };
-
- dspi0: dspi0@4002c000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,vf610-dspi";
- reg = <0x4002c000 0x1000>;
- interrupts = <0 67 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_DSPI0>;
- clock-names = "dspi";
- spi-num-chipselects = <5>;
- status = "disabled";
- };
-
- sai2: sai@40031000 {
- compatible = "fsl,vf610-sai";
- reg = <0x40031000 0x1000>;
- interrupts = <0 86 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_SAI2>;
- clock-names = "sai";
- dma-names = "tx", "rx";
- dmas = <&edma0 0 21>,
- <&edma0 0 20>;
- status = "disabled";
- };
-
- pit: pit@40037000 {
- compatible = "fsl,vf610-pit";
- reg = <0x40037000 0x1000>;
- interrupts = <0 39 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_PIT>;
- clock-names = "pit";
- };
-
- pwm0: pwm@40038000 {
- compatible = "fsl,vf610-ftm-pwm";
- #pwm-cells = <3>;
- reg = <0x40038000 0x1000>;
- clock-names = "ftm_sys", "ftm_ext",
- "ftm_fix", "ftm_cnt_clk_en";
- clocks = <&clks VF610_CLK_FTM0>,
- <&clks VF610_CLK_FTM0_EXT_SEL>,
- <&clks VF610_CLK_FTM0_FIX_SEL>,
- <&clks VF610_CLK_FTM0_EXT_FIX_EN>;
- status = "disabled";
- };
-
- adc0: adc@4003b000 {
- compatible = "fsl,vf610-adc";
- reg = <0x4003b000 0x1000>;
- interrupts = <0 53 0x04>;
- clocks = <&clks VF610_CLK_ADC0>;
- clock-names = "adc";
- status = "disabled";
- };
-
- wdog@4003e000 {
- compatible = "fsl,vf610-wdt", "fsl,imx21-wdt";
- reg = <0x4003e000 0x1000>;
- clocks = <&clks VF610_CLK_WDT>;
- clock-names = "wdog";
- };
-
- qspi0: quadspi@40044000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,vf610-qspi";
- reg = <0x40044000 0x1000>;
- interrupts = <0 24 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_QSPI0_EN>,
- <&clks VF610_CLK_QSPI0>;
- clock-names = "qspi_en", "qspi";
- status = "disabled";
- };
-
- iomuxc: iomuxc@40048000 {
- compatible = "fsl,vf610-iomuxc";
- reg = <0x40048000 0x1000>;
- #gpio-range-cells = <3>;
- };
-
- gpio1: gpio@40049000 {
- compatible = "fsl,vf610-gpio";
- reg = <0x40049000 0x1000 0x400ff000 0x40>;
- interrupts = <0 107 IRQ_TYPE_LEVEL_HIGH>;
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- gpio-ranges = <&iomuxc 0 0 32>;
- };
-
- gpio2: gpio@4004a000 {
- compatible = "fsl,vf610-gpio";
- reg = <0x4004a000 0x1000 0x400ff040 0x40>;
- interrupts = <0 108 IRQ_TYPE_LEVEL_HIGH>;
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- gpio-ranges = <&iomuxc 0 32 32>;
- };
-
- gpio3: gpio@4004b000 {
- compatible = "fsl,vf610-gpio";
- reg = <0x4004b000 0x1000 0x400ff080 0x40>;
- interrupts = <0 109 IRQ_TYPE_LEVEL_HIGH>;
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- gpio-ranges = <&iomuxc 0 64 32>;
- };
-
- gpio4: gpio@4004c000 {
- compatible = "fsl,vf610-gpio";
- reg = <0x4004c000 0x1000 0x400ff0c0 0x40>;
- interrupts = <0 110 IRQ_TYPE_LEVEL_HIGH>;
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- gpio-ranges = <&iomuxc 0 96 32>;
- };
-
- gpio5: gpio@4004d000 {
- compatible = "fsl,vf610-gpio";
- reg = <0x4004d000 0x1000 0x400ff100 0x40>;
- interrupts = <0 111 IRQ_TYPE_LEVEL_HIGH>;
- gpio-controller;
- #gpio-cells = <2>;
- interrupt-controller;
- #interrupt-cells = <2>;
- gpio-ranges = <&iomuxc 0 128 7>;
- };
-
- anatop: anatop@40050000 {
- compatible = "fsl,vf610-anatop", "syscon";
- reg = <0x40050000 0x400>;
- };
-
- usbphy0: usbphy@40050800 {
- compatible = "fsl,vf610-usbphy";
- reg = <0x40050800 0x400>;
- interrupts = <0 50 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_USBPHY0>;
- fsl,anatop = <&anatop>;
- };
-
- usbphy1: usbphy@40050c00 {
- compatible = "fsl,vf610-usbphy";
- reg = <0x40050c00 0x400>;
- interrupts = <0 51 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_USBPHY1>;
- fsl,anatop = <&anatop>;
- };
-
- i2c0: i2c@40066000 {
- #address-cells = <1>;
- #size-cells = <0>;
- compatible = "fsl,vf610-i2c";
- reg = <0x40066000 0x1000>;
- interrupts =<0 71 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_I2C0>;
- clock-names = "ipg";
- dmas = <&edma0 0 50>,
- <&edma0 0 51>;
- dma-names = "rx","tx";
- status = "disabled";
- };
-
- clks: ccm@4006b000 {
- compatible = "fsl,vf610-ccm";
- reg = <0x4006b000 0x1000>;
- #clock-cells = <1>;
- };
-
- usbdev0: usb@40034000 {
- compatible = "fsl,vf610-usb", "fsl,imx27-usb";
- reg = <0x40034000 0x800>;
- interrupts = <0 75 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_USBC0>;
- fsl,usbphy = <&usbphy0>;
- fsl,usbmisc = <&usbmisc0 0>;
- dr_mode = "peripheral";
- status = "disabled";
- };
-
- usbmisc0: usb@40034800 {
- #index-cells = <1>;
- compatible = "fsl,vf610-usbmisc";
- reg = <0x40034800 0x200>;
- clocks = <&clks VF610_CLK_USBC0>;
- };
- };
-
- aips1: aips-bus@40080000 {
- compatible = "fsl,aips-bus", "simple-bus";
- #address-cells = <1>;
- #size-cells = <1>;
- reg = <0x40080000 0x80000>;
- ranges;
-
- edma1: dma-controller@40098000 {
- #dma-cells = <2>;
- compatible = "fsl,vf610-edma";
- reg = <0x40098000 0x2000>,
- <0x400a1000 0x1000>,
- <0x400a2000 0x1000>;
- interrupts = <0 10 IRQ_TYPE_LEVEL_HIGH>,
- <0 11 IRQ_TYPE_LEVEL_HIGH>;
- interrupt-names = "edma-tx", "edma-err";
- dma-channels = <32>;
- clock-names = "dmamux0", "dmamux1";
- clocks = <&clks VF610_CLK_DMAMUX2>,
- <&clks VF610_CLK_DMAMUX3>;
- };
-
- uart4: serial@400a9000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x400a9000 0x1000>;
- interrupts = <0 65 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_UART4>;
- clock-names = "ipg";
- status = "disabled";
- };
-
- uart5: serial@400aa000 {
- compatible = "fsl,vf610-lpuart";
- reg = <0x400aa000 0x1000>;
- interrupts = <0 66 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_UART5>;
- clock-names = "ipg";
- status = "disabled";
- };
-
- adc1: adc@400bb000 {
- compatible = "fsl,vf610-adc";
- reg = <0x400bb000 0x1000>;
- interrupts = <0 54 0x04>;
- clocks = <&clks VF610_CLK_ADC1>;
- clock-names = "adc";
- status = "disabled";
- };
-
- esdhc1: esdhc@400b2000 {
- compatible = "fsl,imx53-esdhc";
- reg = <0x400b2000 0x1000>;
- interrupts = <0 28 0x04>;
- clocks = <&clks VF610_CLK_IPG_BUS>,
- <&clks VF610_CLK_PLATFORM_BUS>,
- <&clks VF610_CLK_ESDHC1>;
- clock-names = "ipg", "ahb", "per";
- status = "disabled";
- };
-
- usbh1: usb@400b4000 {
- compatible = "fsl,vf610-usb", "fsl,imx27-usb";
- reg = <0x400b4000 0x800>;
- interrupts = <0 76 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_USBC1>;
- fsl,usbphy = <&usbphy1>;
- fsl,usbmisc = <&usbmisc1 0>;
- dr_mode = "host";
- status = "disabled";
- };
-
- usbmisc1: usb@400b4800 {
- #index-cells = <1>;
- compatible = "fsl,vf610-usbmisc";
- reg = <0x400b4800 0x200>;
- clocks = <&clks VF610_CLK_USBC1>;
- };
-
- ftm: ftm@400b8000 {
- compatible = "fsl,ftm-timer";
- reg = <0x400b8000 0x1000 0x400b9000 0x1000>;
- interrupts = <0 44 IRQ_TYPE_LEVEL_HIGH>;
- clock-names = "ftm-evt", "ftm-src",
- "ftm-evt-counter-en", "ftm-src-counter-en";
- clocks = <&clks VF610_CLK_FTM2>,
- <&clks VF610_CLK_FTM3>,
- <&clks VF610_CLK_FTM2_EXT_FIX_EN>,
- <&clks VF610_CLK_FTM3_EXT_FIX_EN>;
- status = "disabled";
- };
-
- fec0: ethernet@400d0000 {
- compatible = "fsl,mvf600-fec";
- reg = <0x400d0000 0x1000>;
- interrupts = <0 78 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_ENET0>,
- <&clks VF610_CLK_ENET0>,
- <&clks VF610_CLK_ENET>;
- clock-names = "ipg", "ahb", "ptp";
- status = "disabled";
- };
-
- fec1: ethernet@400d1000 {
- compatible = "fsl,mvf600-fec";
- reg = <0x400d1000 0x1000>;
- interrupts = <0 79 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_ENET1>,
- <&clks VF610_CLK_ENET1>,
- <&clks VF610_CLK_ENET>;
- clock-names = "ipg", "ahb", "ptp";
- status = "disabled";
- };
-
- can1: flexcan@400d4000 {
- compatible = "fsl,vf610-flexcan";
- reg = <0x400d4000 0x4000>;
- interrupts = <0 59 IRQ_TYPE_LEVEL_HIGH>;
- clocks = <&clks VF610_CLK_FLEXCAN1>,
- <&clks VF610_CLK_FLEXCAN1>;
- clock-names = "ipg", "per";
- status = "disabled";
- };
+&a5_cpu {
+ next-level-cache = <&L2>;
+};
- };
+&aips0 {
+ L2: l2-cache@40006000 {
+ compatible = "arm,pl310-cache";
+ reg = <0x40006000 0x1000>;
+ cache-unified;
+ cache-level = <2>;
+ arm,data-latency = <1 1 1>;
+ arm,tag-latency = <2 2 2>;
};
};
diff --git a/arch/arm/boot/dts/vfxxx.dtsi b/arch/arm/boot/dts/vfxxx.dtsi
new file mode 100644
index 0000000..505969a
--- /dev/null
+++ b/arch/arm/boot/dts/vfxxx.dtsi
@@ -0,0 +1,437 @@
+/*
+ * 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 "vf610-pinfunc.h"
+#include <dt-bindings/clock/vf610-clock.h>
+#include <dt-bindings/interrupt-controller/irq.h>
+#include <dt-bindings/gpio/gpio.h>
+
+/ {
+ aliases {
+ can0 = &can0;
+ can1 = &can1;
+ serial0 = &uart0;
+ serial1 = &uart1;
+ serial2 = &uart2;
+ serial3 = &uart3;
+ serial4 = &uart4;
+ serial5 = &uart5;
+ gpio0 = &gpio1;
+ gpio1 = &gpio2;
+ gpio2 = &gpio3;
+ gpio3 = &gpio4;
+ gpio4 = &gpio5;
+ usbphy0 = &usbphy0;
+ usbphy1 = &usbphy1;
+ };
+
+ fxosc: fxosc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ };
+
+ sxosc: sxosc {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <32768>;
+ };
+
+ soc {
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "simple-bus";
+ ranges;
+
+ aips0: aips-bus@40000000 {
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ edma0: dma-controller@40018000 {
+ #dma-cells = <2>;
+ compatible = "fsl,vf610-edma";
+ reg = <0x40018000 0x2000>,
+ <0x40024000 0x1000>,
+ <0x40025000 0x1000>;
+ dma-channels = <32>;
+ clock-names = "dmamux0", "dmamux1";
+ clocks = <&clks VF610_CLK_DMAMUX0>,
+ <&clks VF610_CLK_DMAMUX1>;
+ status = "disabled";
+ };
+
+ can0: flexcan@40020000 {
+ compatible = "fsl,vf610-flexcan";
+ reg = <0x40020000 0x4000>;
+ clocks = <&clks VF610_CLK_FLEXCAN0>,
+ <&clks VF610_CLK_FLEXCAN0>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ uart0: serial@40027000 {
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40027000 0x1000>;
+ clocks = <&clks VF610_CLK_UART0>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 2>,
+ <&edma0 0 3>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ uart1: serial@40028000 {
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40028000 0x1000>;
+ clocks = <&clks VF610_CLK_UART1>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 4>,
+ <&edma0 0 5>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ uart2: serial@40029000 {
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x40029000 0x1000>;
+ clocks = <&clks VF610_CLK_UART2>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 6>,
+ <&edma0 0 7>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ uart3: serial@4002a000 {
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x4002a000 0x1000>;
+ clocks = <&clks VF610_CLK_UART3>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 8>,
+ <&edma0 0 9>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ dspi0: dspi0@4002c000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-dspi";
+ reg = <0x4002c000 0x1000>;
+ clocks = <&clks VF610_CLK_DSPI0>;
+ clock-names = "dspi";
+ spi-num-chipselects = <5>;
+ status = "disabled";
+ };
+
+ sai2: sai@40031000 {
+ compatible = "fsl,vf610-sai";
+ reg = <0x40031000 0x1000>;
+ clocks = <&clks VF610_CLK_SAI2>;
+ clock-names = "sai";
+ dma-names = "tx", "rx";
+ dmas = <&edma0 0 21>,
+ <&edma0 0 20>;
+ status = "disabled";
+ };
+
+ pit: pit@40037000 {
+ compatible = "fsl,vf610-pit";
+ reg = <0x40037000 0x1000>;
+ clocks = <&clks VF610_CLK_PIT>;
+ clock-names = "pit";
+ };
+
+ pwm0: pwm@40038000 {
+ compatible = "fsl,vf610-ftm-pwm";
+ #pwm-cells = <3>;
+ reg = <0x40038000 0x1000>;
+ clock-names = "ftm_sys", "ftm_ext",
+ "ftm_fix", "ftm_cnt_clk_en";
+ clocks = <&clks VF610_CLK_FTM0>,
+ <&clks VF610_CLK_FTM0_EXT_SEL>,
+ <&clks VF610_CLK_FTM0_FIX_SEL>,
+ <&clks VF610_CLK_FTM0_EXT_FIX_EN>;
+ status = "disabled";
+ };
+
+ pwm1: pwm@40039000 {
+ compatible = "fsl,vf610-ftm-pwm";
+ #pwm-cells = <3>;
+ reg = <0x40039000 0x1000>;
+ clock-names = "ftm_sys", "ftm_ext",
+ "ftm_fix", "ftm_cnt_clk_en";
+ clocks = <&clks VF610_CLK_FTM1>,
+ <&clks VF610_CLK_FTM1_EXT_SEL>,
+ <&clks VF610_CLK_FTM1_FIX_SEL>,
+ <&clks VF610_CLK_FTM1_EXT_FIX_EN>;
+ status = "disabled";
+ };
+
+ adc0: adc@4003b000 {
+ compatible = "fsl,vf610-adc";
+ reg = <0x4003b000 0x1000>;
+ clocks = <&clks VF610_CLK_ADC0>;
+ clock-names = "adc";
+ status = "disabled";
+ };
+
+ wdog@4003e000 {
+ compatible = "fsl,vf610-wdt", "fsl,imx21-wdt";
+ reg = <0x4003e000 0x1000>;
+ clocks = <&clks VF610_CLK_WDT>;
+ clock-names = "wdog";
+ status = "disabled";
+ };
+
+ qspi0: quadspi@40044000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-qspi";
+ reg = <0x40044000 0x1000>;
+ clocks = <&clks VF610_CLK_QSPI0_EN>,
+ <&clks VF610_CLK_QSPI0>;
+ clock-names = "qspi_en", "qspi";
+ status = "disabled";
+ };
+
+ iomuxc: iomuxc@40048000 {
+ compatible = "fsl,vf610-iomuxc";
+ reg = <0x40048000 0x1000>;
+ #gpio-range-cells = <3>;
+ };
+
+ gpio1: gpio@40049000 {
+ compatible = "fsl,vf610-gpio";
+ reg = <0x40049000 0x1000 0x400ff000 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 0 32>;
+ };
+
+ gpio2: gpio@4004a000 {
+ compatible = "fsl,vf610-gpio";
+ reg = <0x4004a000 0x1000 0x400ff040 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 32 32>;
+ };
+
+ gpio3: gpio@4004b000 {
+ compatible = "fsl,vf610-gpio";
+ reg = <0x4004b000 0x1000 0x400ff080 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 64 32>;
+ };
+
+ gpio4: gpio@4004c000 {
+ compatible = "fsl,vf610-gpio";
+ reg = <0x4004c000 0x1000 0x400ff0c0 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 96 32>;
+ };
+
+ gpio5: gpio@4004d000 {
+ compatible = "fsl,vf610-gpio";
+ reg = <0x4004d000 0x1000 0x400ff100 0x40>;
+ gpio-controller;
+ #gpio-cells = <2>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ gpio-ranges = <&iomuxc 0 128 7>;
+ };
+
+ anatop: anatop@40050000 {
+ compatible = "fsl,vf610-anatop", "syscon";
+ reg = <0x40050000 0x400>;
+ };
+
+ usbphy0: usbphy@40050800 {
+ compatible = "fsl,vf610-usbphy";
+ reg = <0x40050800 0x400>;
+ clocks = <&clks VF610_CLK_USBPHY0>;
+ fsl,anatop = <&anatop>;
+ status = "disabled";
+ };
+
+ usbphy1: usbphy@40050c00 {
+ compatible = "fsl,vf610-usbphy";
+ reg = <0x40050c00 0x400>;
+ clocks = <&clks VF610_CLK_USBPHY1>;
+ fsl,anatop = <&anatop>;
+ status = "disabled";
+ };
+
+ i2c0: i2c@40066000 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ compatible = "fsl,vf610-i2c";
+ reg = <0x40066000 0x1000>;
+ clocks = <&clks VF610_CLK_I2C0>;
+ clock-names = "ipg";
+ dmas = <&edma0 0 50>,
+ <&edma0 0 51>;
+ dma-names = "rx","tx";
+ status = "disabled";
+ };
+
+ clks: ccm@4006b000 {
+ compatible = "fsl,vf610-ccm";
+ reg = <0x4006b000 0x1000>;
+ clocks = <&sxosc>, <&fxosc>;
+ clock-names = "sxosc", "fxosc";
+ #clock-cells = <1>;
+ };
+
+ usbdev0: usb@40034000 {
+ compatible = "fsl,vf610-usb", "fsl,imx27-usb";
+ reg = <0x40034000 0x800>;
+ clocks = <&clks VF610_CLK_USBC0>;
+ fsl,usbphy = <&usbphy0>;
+ fsl,usbmisc = <&usbmisc0 0>;
+ dr_mode = "peripheral";
+ status = "disabled";
+ };
+
+ usbmisc0: usb@40034800 {
+ #index-cells = <1>;
+ compatible = "fsl,vf610-usbmisc";
+ reg = <0x40034800 0x200>;
+ clocks = <&clks VF610_CLK_USBC0>;
+ status = "disabled";
+ };
+ };
+
+ aips1: aips-bus@40080000 {
+ compatible = "fsl,aips-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges;
+
+ edma1: dma-controller@40098000 {
+ #dma-cells = <2>;
+ compatible = "fsl,vf610-edma";
+ reg = <0x40098000 0x2000>,
+ <0x400a1000 0x1000>,
+ <0x400a2000 0x1000>;
+ dma-channels = <32>;
+ clock-names = "dmamux0", "dmamux1";
+ clocks = <&clks VF610_CLK_DMAMUX2>,
+ <&clks VF610_CLK_DMAMUX3>;
+ status = "disabled";
+ };
+
+ uart4: serial@400a9000 {
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x400a9000 0x1000>;
+ clocks = <&clks VF610_CLK_UART4>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ uart5: serial@400aa000 {
+ compatible = "fsl,vf610-lpuart";
+ reg = <0x400aa000 0x1000>;
+ clocks = <&clks VF610_CLK_UART5>;
+ clock-names = "ipg";
+ status = "disabled";
+ };
+
+ adc1: adc@400bb000 {
+ compatible = "fsl,vf610-adc";
+ reg = <0x400bb000 0x1000>;
+ clocks = <&clks VF610_CLK_ADC1>;
+ clock-names = "adc";
+ status = "disabled";
+ };
+
+ esdhc1: esdhc@400b2000 {
+ compatible = "fsl,imx53-esdhc";
+ reg = <0x400b2000 0x1000>;
+ clocks = <&clks VF610_CLK_IPG_BUS>,
+ <&clks VF610_CLK_PLATFORM_BUS>,
+ <&clks VF610_CLK_ESDHC1>;
+ clock-names = "ipg", "ahb", "per";
+ status = "disabled";
+ };
+
+ usbh1: usb@400b4000 {
+ compatible = "fsl,vf610-usb", "fsl,imx27-usb";
+ reg = <0x400b4000 0x800>;
+ clocks = <&clks VF610_CLK_USBC1>;
+ fsl,usbphy = <&usbphy1>;
+ fsl,usbmisc = <&usbmisc1 0>;
+ dr_mode = "host";
+ status = "disabled";
+ };
+
+ usbmisc1: usb@400b4800 {
+ #index-cells = <1>;
+ compatible = "fsl,vf610-usbmisc";
+ reg = <0x400b4800 0x200>;
+ clocks = <&clks VF610_CLK_USBC1>;
+ status = "disabled";
+ };
+
+ ftm: ftm@400b8000 {
+ compatible = "fsl,ftm-timer";
+ reg = <0x400b8000 0x1000 0x400b9000 0x1000>;
+ clock-names = "ftm-evt", "ftm-src",
+ "ftm-evt-counter-en", "ftm-src-counter-en";
+ clocks = <&clks VF610_CLK_FTM2>,
+ <&clks VF610_CLK_FTM3>,
+ <&clks VF610_CLK_FTM2_EXT_FIX_EN>,
+ <&clks VF610_CLK_FTM3_EXT_FIX_EN>;
+ status = "disabled";
+ };
+
+ fec0: ethernet@400d0000 {
+ compatible = "fsl,mvf600-fec";
+ reg = <0x400d0000 0x1000>;
+ clocks = <&clks VF610_CLK_ENET0>,
+ <&clks VF610_CLK_ENET0>,
+ <&clks VF610_CLK_ENET>;
+ clock-names = "ipg", "ahb", "ptp";
+ status = "disabled";
+ };
+
+ fec1: ethernet@400d1000 {
+ compatible = "fsl,mvf600-fec";
+ reg = <0x400d1000 0x1000>;
+ clocks = <&clks VF610_CLK_ENET1>,
+ <&clks VF610_CLK_ENET1>,
+ <&clks VF610_CLK_ENET>;
+ clock-names = "ipg", "ahb", "ptp";
+ status = "disabled";
+ };
+
+ can1: flexcan@400d4000 {
+ compatible = "fsl,vf610-flexcan";
+ reg = <0x400d4000 0x4000>;
+ clocks = <&clks VF610_CLK_FLEXCAN1>,
+ <&clks VF610_CLK_FLEXCAN1>;
+ clock-names = "ipg", "per";
+ status = "disabled";
+ };
+
+ };
+ };
+};
diff --git a/arch/arm/boot/dts/zynq-7000.dtsi b/arch/arm/boot/dts/zynq-7000.dtsi
index ce2ef5b..ee3e5d6 100644
--- a/arch/arm/boot/dts/zynq-7000.dtsi
+++ b/arch/arm/boot/dts/zynq-7000.dtsi
@@ -243,7 +243,6 @@
clkc: clkc@100 {
#clock-cells = <1>;
compatible = "xlnx,ps7-clkc";
- ps-clk-frequency = <33333333>;
fclk-enable = <0>;
clock-output-names = "armpll", "ddrpll", "iopll", "cpu_6or4x",
"cpu_3or2x", "cpu_2x", "cpu_1x", "ddr2x", "ddr3x",
diff --git a/arch/arm/boot/dts/zynq-parallella.dts b/arch/arm/boot/dts/zynq-parallella.dts
index 0429bbd..ab1dc0a 100644
--- a/arch/arm/boot/dts/zynq-parallella.dts
+++ b/arch/arm/boot/dts/zynq-parallella.dts
@@ -36,6 +36,7 @@
&clkc {
fclk-enable = <0xf>;
+ ps-clk-frequency = <33333333>;
};
&gem0 {
diff --git a/arch/arm/boot/dts/zynq-zc702.dts b/arch/arm/boot/dts/zynq-zc702.dts
index 94e2cda..280f02d 100644
--- a/arch/arm/boot/dts/zynq-zc702.dts
+++ b/arch/arm/boot/dts/zynq-zc702.dts
@@ -42,6 +42,10 @@
status = "okay";
};
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
&gem0 {
status = "okay";
phy-mode = "rgmii-id";
diff --git a/arch/arm/boot/dts/zynq-zc706.dts b/arch/arm/boot/dts/zynq-zc706.dts
index a8bbdfb..34f7812 100644
--- a/arch/arm/boot/dts/zynq-zc706.dts
+++ b/arch/arm/boot/dts/zynq-zc706.dts
@@ -29,6 +29,10 @@
};
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
&gem0 {
status = "okay";
phy-mode = "rgmii-id";
diff --git a/arch/arm/boot/dts/zynq-zed.dts b/arch/arm/boot/dts/zynq-zed.dts
index 697779a..1c7cc99 100644
--- a/arch/arm/boot/dts/zynq-zed.dts
+++ b/arch/arm/boot/dts/zynq-zed.dts
@@ -29,6 +29,10 @@
};
+&clkc {
+ ps-clk-frequency = <33333333>;
+};
+
&gem0 {
status = "okay";
phy-mode = "rgmii-id";
diff --git a/arch/arm/boot/dts/zynq-zybo.dts b/arch/arm/boot/dts/zynq-zybo.dts
new file mode 100644
index 0000000..a9a12ce
--- /dev/null
+++ b/arch/arm/boot/dts/zynq-zybo.dts
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 - 2014 Xilinx
+ * Copyright (C) 2012 National Instruments Corp.
+ *
+ * This software is licensed under the terms of the GNU General Public
+ * License version 2, as published by the Free Software Foundation, and
+ * may be copied, distributed, and modified under those terms.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+/dts-v1/;
+/include/ "zynq-7000.dtsi"
+
+/ {
+ model = "Zynq ZYBO Development Board";
+ compatible = "digilent,zynq-zybo", "xlnx,zynq-7000";
+
+ memory {
+ device_type = "memory";
+ reg = <0x0 0x20000000>;
+ };
+
+ chosen {
+ bootargs = "console=ttyPS0,115200 earlyprintk";
+ };
+
+};
+
+&clkc {
+ ps-clk-frequency = <50000000>;
+};
+
+&gem0 {
+ status = "okay";
+ phy-mode = "rgmii-id";
+ phy-handle = <&ethernet_phy>;
+
+ ethernet_phy: ethernet-phy@0 {
+ reg = <0>;
+ };
+};
+
+&sdhci0 {
+ status = "okay";
+};
+
+&uart1 {
+ status = "okay";
+};
diff --git a/arch/arm/common/edma.c b/arch/arm/common/edma.c
index 72041f0..5662a87 100644
--- a/arch/arm/common/edma.c
+++ b/arch/arm/common/edma.c
@@ -245,6 +245,8 @@ struct edma {
/* list of channels with no even trigger; terminated by "-1" */
const s8 *noevent;
+ struct edma_soc_info *info;
+
/* The edma_inuse bit for each PaRAM slot is clear unless the
* channel is in use ... by ARM or DSP, for QDMA, or whatever.
*/
@@ -296,7 +298,7 @@ static void map_dmach_queue(unsigned ctlr, unsigned ch_no,
~(0x7 << bit), queue_no << bit);
}
-static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
+static void assign_priority_to_queue(unsigned ctlr, int queue_no,
int priority)
{
int bit = queue_no * 4;
@@ -315,7 +317,7 @@ static void __init assign_priority_to_queue(unsigned ctlr, int queue_no,
* included in that particular EDMA variant (Eg : dm646x)
*
*/
-static void __init map_dmach_param(unsigned ctlr)
+static void map_dmach_param(unsigned ctlr)
{
int i;
for (i = 0; i < EDMA_MAX_DMACH; i++)
@@ -1798,6 +1800,7 @@ static int edma_probe(struct platform_device *pdev)
edma_write_array2(j, EDMA_DRAE, i, 1, 0x0);
edma_write_array(j, EDMA_QRAE, i, 0x0);
}
+ edma_cc[j]->info = info[j];
arch_num_cc++;
edma_dev_info.id = j;
@@ -1807,9 +1810,56 @@ static int edma_probe(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_SLEEP
+static int edma_pm_resume(struct device *dev)
+{
+ int i, j;
+
+ for (j = 0; j < arch_num_cc; j++) {
+ struct edma *cc = edma_cc[j];
+
+ s8 (*queue_priority_mapping)[2];
+
+ queue_priority_mapping = cc->info->queue_priority_mapping;
+
+ /* Event queue priority mapping */
+ for (i = 0; queue_priority_mapping[i][0] != -1; i++)
+ assign_priority_to_queue(j,
+ queue_priority_mapping[i][0],
+ queue_priority_mapping[i][1]);
+
+ /*
+ * Map the channel to param entry if channel mapping logic
+ * exist
+ */
+ if (edma_read(j, EDMA_CCCFG) & CHMAP_EXIST)
+ map_dmach_param(j);
+
+ for (i = 0; i < cc->num_channels; i++) {
+ if (test_bit(i, cc->edma_inuse)) {
+ /* ensure access through shadow region 0 */
+ edma_or_array2(j, EDMA_DRAE, 0, i >> 5,
+ BIT(i & 0x1f));
+
+ setup_dma_interrupt(i,
+ cc->intr_data[i].callback,
+ cc->intr_data[i].data);
+ }
+ }
+ }
+
+ return 0;
+}
+#endif
+
+static const struct dev_pm_ops edma_pm_ops = {
+ SET_LATE_SYSTEM_SLEEP_PM_OPS(NULL, edma_pm_resume)
+};
+
static struct platform_driver edma_driver = {
.driver = {
.name = "edma",
+ .pm = &edma_pm_ops,
.of_match_table = edma_of_ids,
},
.probe = edma_probe,
diff --git a/arch/arm/configs/ape6evm_defconfig b/arch/arm/configs/ape6evm_defconfig
index b54b28f..db81d8c 100644
--- a/arch/arm/configs/ape6evm_defconfig
+++ b/arch/arm/configs/ape6evm_defconfig
@@ -33,6 +33,7 @@ CONFIG_ARM_APPENDED_DTB=y
CONFIG_VFP=y
CONFIG_NEON=y
CONFIG_BINFMT_MISC=y
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
diff --git a/arch/arm/configs/at91_dt_defconfig b/arch/arm/configs/at91_dt_defconfig
index 3b515c1..a67375f 100644
--- a/arch/arm/configs/at91_dt_defconfig
+++ b/arch/arm/configs/at91_dt_defconfig
@@ -80,6 +80,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_NETDEVICES=y
CONFIG_MACB=y
# CONFIG_NET_VENDOR_BROADCOM is not set
+CONFIG_DM9000=y
# CONFIG_NET_VENDOR_FARADAY is not set
# CONFIG_NET_VENDOR_INTEL is not set
# CONFIG_NET_VENDOR_MARVELL is not set
@@ -113,6 +114,7 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_Y=272
CONFIG_INPUT_JOYDEV=y
CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
+CONFIG_KEYBOARD_QT1070=y
CONFIG_KEYBOARD_GPIO=y
# CONFIG_INPUT_MOUSE is not set
CONFIG_INPUT_TOUCHSCREEN=y
@@ -186,6 +188,7 @@ CONFIG_IIO=y
CONFIG_AT91_ADC=y
CONFIG_PWM=y
CONFIG_PWM_ATMEL=y
+CONFIG_PWM_ATMEL_TCB=y
CONFIG_EXT4_FS=y
CONFIG_FANOTIFY=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm/configs/at91rm9200_defconfig b/arch/arm/configs/at91rm9200_defconfig
deleted file mode 100644
index bf05771..0000000
--- a/arch/arm/configs/at91rm9200_defconfig
+++ /dev/null
@@ -1,161 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_NO_HZ=y
-CONFIG_HIGH_RES_TIMERS=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_USER_NS=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_MODULES=y
-CONFIG_MODULE_FORCE_LOAD=y
-CONFIG_MODULE_UNLOAD=y
-CONFIG_MODVERSIONS=y
-CONFIG_MODULE_SRCVERSION_ALL=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91RM9200=y
-CONFIG_MACH_ONEARM=y
-CONFIG_MACH_AT91RM9200EK=y
-CONFIG_MACH_CSB337=y
-CONFIG_MACH_CSB637=y
-CONFIG_MACH_CARMEVA=y
-CONFIG_MACH_ATEB9200=y
-CONFIG_MACH_KB9200=y
-CONFIG_MACH_PICOTUX2XX=y
-CONFIG_MACH_KAFA=y
-CONFIG_MACH_ECBAT91=y
-CONFIG_MACH_YL9200=y
-CONFIG_MACH_CPUAT91=y
-CONFIG_MACH_ECO920=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
-CONFIG_AT91_TIMER_HZ=100
-# CONFIG_ARM_THUMB is not set
-CONFIG_PCCARD=y
-CONFIG_AT91_CF=y
-CONFIG_AEABI=y
-# CONFIG_COMPACTION is not set
-CONFIG_ZBOOT_ROM_TEXT=0x10000000
-CONFIG_ZBOOT_ROM_BSS=0x20040000
-CONFIG_KEXEC=y
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_FPE_NWFPE=y
-CONFIG_BINFMT_MISC=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-CONFIG_IPV6_PRIVACY=y
-CONFIG_IPV6_ROUTER_PREF=y
-CONFIG_IPV6_ROUTE_INFO=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD 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_JEDECPROBE=y
-CONFIG_MTD_CFI_INTELEXT=y
-CONFIG_MTD_CFI_AMDSTD=y
-CONFIG_MTD_COMPLEX_MAPPINGS=y
-CONFIG_MTD_PHYSMAP=y
-CONFIG_MTD_PLATRAM=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_NAND_PLATFORM=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_NETDEVICES=y
-CONFIG_MII=y
-CONFIG_ARM_AT91_ETHER=y
-CONFIG_DAVICOM_PHY=y
-CONFIG_SMSC_PHY=y
-CONFIG_MICREL_PHY=y
-# CONFIG_WLAN is not set
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_GPIO_SYSFS=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91RM9200_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_MODE_HELPERS=y
-CONFIG_FB_TILEBLITTING=y
-CONFIG_FB_S1D13XXX=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FONTS=y
-CONFIG_LOGO=y
-CONFIG_USB=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_AT91=y
-CONFIG_USB_G_SERIAL=y
-CONFIG_MMC=y
-CONFIG_MMC_ATMELMCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_EXT4_FS=y
-CONFIG_AUTOFS4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=y
-CONFIG_MAGIC_SYSRQ=y
-CONFIG_DEBUG_FS=y
-CONFIG_DEBUG_KERNEL=y
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
-CONFIG_CRYPTO_PCBC=y
-CONFIG_CRYPTO_SHA1=y
-CONFIG_XZ_DEC_ARMTHUMB=y
diff --git a/arch/arm/configs/at91sam9260_9g20_defconfig b/arch/arm/configs/at91sam9260_9g20_defconfig
deleted file mode 100644
index 3ada05d..0000000
--- a/arch/arm/configs/at91sam9260_9g20_defconfig
+++ /dev/null
@@ -1,145 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9260=y
-CONFIG_MACH_AT91SAM9260EK=y
-CONFIG_MACH_CAM60=y
-CONFIG_MACH_SAM9_L9260=y
-CONFIG_MACH_AFEB9260=y
-CONFIG_MACH_CPU9260=y
-CONFIG_MACH_FLEXIBITY=y
-CONFIG_MACH_AT91SAM9G20EK=y
-CONFIG_MACH_AT91SAM9G20EK_2MMC=y
-CONFIG_MACH_CPU9G20=y
-CONFIG_MACH_ACMENETUSFOXG20=y
-CONFIG_MACH_PORTUXG20=y
-CONFIG_MACH_STAMP9G20=y
-CONFIG_MACH_PCONTROL_G20=y
-CONFIG_MACH_GSIA18S=y
-CONFIG_MACH_SNAPPER_9260=y
-CONFIG_MACH_AT91SAM9_DT=y
-CONFIG_AT91_SLOW_CLOCK=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_ARM_ATAG_DTB_COMPAT=y
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_EEPROM_AT25=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_NETDEVICES=y
-CONFIG_MACB=y
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_FARADAY is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_MICROCHIP is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-# CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_SMSC is not set
-# CONFIG_NET_VENDOR_STMICRO is not set
-CONFIG_SMSC_PHY=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_SPI_SPIDEV=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-CONFIG_SND_SEQUENCER_OSS=y
-# CONFIG_SND_VERBOSE_PROCFS is not set
-CONFIG_USB=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_AT91=y
-CONFIG_USB_G_SERIAL=y
-CONFIG_MMC=y
-CONFIG_MMC_ATMELMCI=y
-CONFIG_MMC_SPI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_RV3029C2=y
-CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_IIO=y
-CONFIG_AT91_ADC=y
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_DEBUG_INFO=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/configs/at91sam9261_9g10_defconfig b/arch/arm/configs/at91sam9261_9g10_defconfig
deleted file mode 100644
index 0c505d8..0000000
--- a/arch/arm/configs/at91sam9261_9g10_defconfig
+++ /dev/null
@@ -1,147 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-CONFIG_KERNEL_LZMA=y
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_NAMESPACES=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9261=y
-CONFIG_MACH_AT91SAM9261EK=y
-CONFIG_MACH_AT91SAM9G10EK=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_VFP=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_LRO is not set
-# CONFIG_IPV6 is not set
-CONFIG_CFG80211=y
-CONFIG_MAC80211=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_TCLIB=y
-CONFIG_ATMEL_SSC=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_NETDEVICES=y
-CONFIG_DM9000=y
-CONFIG_USB_ZD1201=m
-CONFIG_RTL8187=m
-CONFIG_LIBERTAS=m
-CONFIG_LIBERTAS_USB=m
-CONFIG_LIBERTAS_SDIO=m
-CONFIG_LIBERTAS_SPI=m
-CONFIG_RT2X00=m
-CONFIG_RT2500USB=m
-CONFIG_RT73USB=m
-CONFIG_ZD1211RW=m
-CONFIG_INPUT_POLLDEV=m
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=240
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=320
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-CONFIG_DEVPTS_MULTIPLE_INSTANCES=y
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-# CONFIG_LCD_CLASS_DEVICE is not set
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_ATMEL_LCDC=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_LOGO=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_AT73C213=y
-CONFIG_SND_USB_AUDIO=m
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_AT91=y
-CONFIG_USB_G_SERIAL=y
-CONFIG_MMC=y
-CONFIG_MMC_ATMELMCI=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_MSDOS_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-CONFIG_SQUASHFS=y
-CONFIG_SQUASHFS_LZO=y
-CONFIG_SQUASHFS_XZ=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_CRC_CCITT=m
diff --git a/arch/arm/configs/at91sam9263_defconfig b/arch/arm/configs/at91sam9263_defconfig
deleted file mode 100644
index 8b671c9..0000000
--- a/arch/arm/configs/at91sam9263_defconfig
+++ /dev/null
@@ -1,151 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_NAMESPACES=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9263=y
-CONFIG_MACH_AT91SAM9263EK=y
-CONFIG_MTD_AT91_DATAFLASH_CARD=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,3145728 root=/dev/ram0 rw"
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_NET_KEY=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_ADVANCED_ROUTER=y
-CONFIG_IP_ROUTE_VERBOSE=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-CONFIG_IP_PNP_RARP=y
-CONFIG_NET_IPIP=y
-CONFIG_IP_MROUTE=y
-CONFIG_IP_PIMSM_V1=y
-CONFIG_IP_PIMSM_V2=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_LRO is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-# CONFIG_WIRELESS is not set
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_NFTL=y
-CONFIG_NFTL_RW=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_BLOCK2MTD=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_TCLIB=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-CONFIG_NETDEVICES=y
-CONFIG_MACB=y
-CONFIG_SMSC_PHY=y
-# CONFIG_WLAN is not set
-CONFIG_INPUT_POLLDEV=m
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ADS7846=y
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_GPIO_SYSFS=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_LOGO=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_ATMEL_AC97C=y
-# CONFIG_SND_SPI is not set
-CONFIG_SND_USB_AUDIO=m
-CONFIG_USB=y
-CONFIG_USB_MON=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ATMEL_USBA=y
-CONFIG_USB_G_SERIAL=y
-CONFIG_MMC=y
-CONFIG_SDIO_UART=m
-CONFIG_MMC_ATMELMCI=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_PWM=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_PWM=y
-CONFIG_PWM_ATMEL=y
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-CONFIG_NFS_FS=y
-CONFIG_NFS_V3_ACL=y
-CONFIG_NFS_V4=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_UTF8=y
-CONFIG_DEBUG_USER=y
-CONFIG_XZ_DEC=y
-CONFIG_FONTS=y
diff --git a/arch/arm/configs/at91sam9g45_defconfig b/arch/arm/configs/at91sam9g45_defconfig
deleted file mode 100644
index f66d1a1..0000000
--- a/arch/arm/configs/at91sam9g45_defconfig
+++ /dev/null
@@ -1,175 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_SYSFS_DEPRECATED=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9G45=y
-CONFIG_MACH_AT91SAM9M10G45EK=y
-CONFIG_MACH_AT91SAM9_DT=y
-CONFIG_AT91_SLOW_CLOCK=y
-CONFIG_AEABI=y
-CONFIG_UACCESS_WITH_MEMCPY=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=128M console=ttyS0,115200 initrd=0x71100000,25165824 root=/dev/ram0 rw"
-CONFIG_AUTO_ZRELADDR=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_MULTICAST=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_IP_PNP_BOOTP=y
-# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET_XFRM_MODE_BEET is not set
-# CONFIG_INET_DIAG is not set
-CONFIG_IPV6=y
-# CONFIG_INET6_XFRM_MODE_TRANSPORT is not set
-# CONFIG_INET6_XFRM_MODE_TUNNEL is not set
-# CONFIG_INET6_XFRM_MODE_BEET is not set
-CONFIG_IPV6_SIT_6RD=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-# CONFIG_STANDALONE is not set
-# CONFIG_PREVENT_FIRMWARE_BUILD is not set
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_MTD_UBI_GLUEBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=4
-CONFIG_BLK_DEV_RAM_SIZE=8192
-CONFIG_ATMEL_TCLIB=y
-CONFIG_ATMEL_SSC=y
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-# CONFIG_SCSI_LOWLEVEL is not set
-CONFIG_NETDEVICES=y
-CONFIG_MACB=y
-CONFIG_DAVICOM_PHY=y
-# CONFIG_INPUT_MOUSEDEV is not set
-CONFIG_INPUT_JOYDEV=y
-CONFIG_INPUT_EVDEV=y
-# CONFIG_KEYBOARD_ATKBD is not set
-CONFIG_KEYBOARD_QT1070=y
-CONFIG_KEYBOARD_QT2160=y
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-CONFIG_TOUCHSCREEN_ATMEL_MXT=m
-# CONFIG_SERIO is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-CONFIG_HW_RANDOM=y
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_BACKLIGHT_LCD_SUPPORT=y
-CONFIG_LCD_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_CLASS_DEVICE=y
-CONFIG_BACKLIGHT_ATMEL_LCDC=y
-# CONFIG_BACKLIGHT_GENERIC is not set
-CONFIG_BACKLIGHT_PWM=y
-CONFIG_FRAMEBUFFER_CONSOLE=y
-CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY=y
-CONFIG_LOGO=y
-CONFIG_SOUND=y
-CONFIG_SND=y
-CONFIG_SND_SEQUENCER=y
-CONFIG_SND_MIXER_OSS=y
-CONFIG_SND_PCM_OSS=y
-# CONFIG_SND_SUPPORT_OLD_API is not set
-# CONFIG_SND_VERBOSE_PROCFS is not set
-# CONFIG_SND_DRIVERS is not set
-# CONFIG_SND_ARM is not set
-CONFIG_SND_ATMEL_AC97C=y
-# CONFIG_SND_SPI is not set
-# CONFIG_SND_USB is not set
-# CONFIG_USB_HID is not set
-CONFIG_USB=y
-CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
-CONFIG_USB_EHCI_HCD=y
-CONFIG_USB_OHCI_HCD=y
-CONFIG_USB_ACM=y
-CONFIG_USB_STORAGE=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ATMEL_USBA=y
-CONFIG_USB_G_MULTI=y
-CONFIG_USB_G_MULTI_CDC=y
-CONFIG_MMC=y
-# CONFIG_MMC_BLOCK_BOUNCE is not set
-CONFIG_MMC_ATMELMCI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_PWM=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_TIMER=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_LEDS_TRIGGER_GPIO=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91RM9200=y
-CONFIG_DMADEVICES=y
-CONFIG_AT_HDMAC=y
-CONFIG_DMATEST=m
-# CONFIG_IOMMU_SUPPORT is not set
-CONFIG_IIO=y
-CONFIG_AT91_ADC=y
-CONFIG_PWM=y
-CONFIG_PWM_ATMEL=y
-CONFIG_EXT4_FS=y
-CONFIG_FANOTIFY=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_UBIFS_FS=y
-CONFIG_UBIFS_FS_ADVANCED_COMPR=y
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_STRIP_ASM_SYMS=y
-CONFIG_DEBUG_MEMORY_INIT=y
-# CONFIG_SCHED_DEBUG is not set
-# CONFIG_FTRACE is not set
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
-CONFIG_EARLY_PRINTK=y
-CONFIG_CRYPTO_ECB=y
-# CONFIG_CRYPTO_ANSI_CPRNG is not set
-CONFIG_CRYPTO_USER_API_HASH=m
-CONFIG_CRYPTO_USER_API_SKCIPHER=m
-# CONFIG_CRYPTO_HW is not set
-CONFIG_FONTS=y
diff --git a/arch/arm/configs/at91sam9rl_defconfig b/arch/arm/configs/at91sam9rl_defconfig
deleted file mode 100644
index 4c26d344..0000000
--- a/arch/arm/configs/at91sam9rl_defconfig
+++ /dev/null
@@ -1,92 +0,0 @@
-# CONFIG_LOCALVERSION_AUTO is not set
-# CONFIG_SWAP is not set
-CONFIG_SYSVIPC=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_BLK_DEV_INITRD=y
-CONFIG_EMBEDDED=y
-CONFIG_SLAB=y
-CONFIG_MODULES=y
-CONFIG_MODULE_UNLOAD=y
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91SAM9RL=y
-CONFIG_MACH_AT91SAM9RLEK=y
-# CONFIG_ARM_THUMB is not set
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_CMDLINE="mem=64M console=ttyS0,115200 initrd=0x21100000,17105363 root=/dev/ram0 rw"
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_NET=y
-CONFIG_UNIX=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_MTD=y
-CONFIG_MTD_CMDLINE_PARTS=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_DATAFLASH=y
-CONFIG_MTD_NAND=y
-CONFIG_MTD_NAND_ATMEL=y
-CONFIG_MTD_UBI=y
-CONFIG_BLK_DEV_LOOP=y
-CONFIG_BLK_DEV_RAM=y
-CONFIG_BLK_DEV_RAM_COUNT=4
-CONFIG_BLK_DEV_RAM_SIZE=24576
-CONFIG_SCSI=y
-CONFIG_BLK_DEV_SD=y
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_INPUT_MOUSEDEV_SCREEN_X=320
-CONFIG_INPUT_MOUSEDEV_SCREEN_Y=240
-CONFIG_INPUT_EVDEV=y
-# CONFIG_INPUT_KEYBOARD is not set
-# CONFIG_INPUT_MOUSE is not set
-CONFIG_INPUT_TOUCHSCREEN=y
-# CONFIG_SERIO is not set
-CONFIG_SERIAL_ATMEL=y
-CONFIG_SERIAL_ATMEL_CONSOLE=y
-# CONFIG_HW_RANDOM is not set
-CONFIG_I2C=y
-CONFIG_I2C_CHARDEV=y
-CONFIG_I2C_GPIO=y
-CONFIG_SPI=y
-CONFIG_SPI_ATMEL=y
-CONFIG_POWER_SUPPLY=y
-CONFIG_POWER_RESET=y
-# CONFIG_HWMON is not set
-CONFIG_WATCHDOG=y
-CONFIG_WATCHDOG_NOWAYOUT=y
-CONFIG_AT91SAM9X_WATCHDOG=y
-CONFIG_FB=y
-CONFIG_FB_ATMEL=y
-CONFIG_USB_GADGET=y
-CONFIG_USB_ATMEL_USBA=y
-CONFIG_MMC=y
-CONFIG_MMC_ATMELMCI=m
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-CONFIG_LEDS_PWM=y
-CONFIG_LEDS_TRIGGERS=y
-CONFIG_LEDS_TRIGGER_HEARTBEAT=y
-CONFIG_RTC_CLASS=y
-CONFIG_RTC_DRV_AT91SAM9=y
-CONFIG_IIO=y
-CONFIG_AT91_ADC=y
-CONFIG_PWM=y
-CONFIG_PWM_ATMEL=y
-CONFIG_EXT4_FS=y
-CONFIG_VFAT_FS=y
-CONFIG_TMPFS=y
-CONFIG_UBIFS_FS=y
-CONFIG_CRAMFS=y
-CONFIG_NLS_CODEPAGE_437=y
-CONFIG_NLS_CODEPAGE_850=y
-CONFIG_NLS_ISO8859_1=y
-CONFIG_NLS_ISO8859_15=y
-CONFIG_NLS_UTF8=y
-CONFIG_DEBUG_INFO=y
-CONFIG_DEBUG_USER=y
-CONFIG_DEBUG_LL=y
diff --git a/arch/arm/configs/at91x40_defconfig b/arch/arm/configs/at91x40_defconfig
deleted file mode 100644
index c55e921..0000000
--- a/arch/arm/configs/at91x40_defconfig
+++ /dev/null
@@ -1,48 +0,0 @@
-CONFIG_EXPERIMENTAL=y
-CONFIG_LOG_BUF_SHIFT=14
-CONFIG_EMBEDDED=y
-# CONFIG_HOTPLUG is not set
-# CONFIG_ELF_CORE is not set
-# CONFIG_FUTEX is not set
-# CONFIG_TIMERFD is not set
-# CONFIG_VM_EVENT_COUNTERS is not set
-# CONFIG_COMPAT_BRK is not set
-CONFIG_SLAB=y
-# CONFIG_LBDAF is not set
-# CONFIG_BLK_DEV_BSG is not set
-# CONFIG_IOSCHED_DEADLINE is not set
-# CONFIG_IOSCHED_CFQ is not set
-# CONFIG_MMU is not set
-CONFIG_ARCH_AT91=y
-CONFIG_ARCH_AT91X40=y
-CONFIG_MACH_AT91EB01=y
-CONFIG_AT91_EARLY_USART0=y
-CONFIG_CPU_ARM7TDMI=y
-CONFIG_SET_MEM_PARAM=y
-CONFIG_DRAM_BASE=0x01000000
-CONFIG_DRAM_SIZE=0x00400000
-CONFIG_FLASH_MEM_BASE=0x01400000
-CONFIG_PROCESSOR_ID=0x14000040
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_BINFMT_FLAT=y
-# CONFIG_SUSPEND is not set
-# CONFIG_FW_LOADER is not set
-CONFIG_MTD=y
-CONFIG_MTD_PARTITIONS=y
-CONFIG_MTD_CHAR=y
-CONFIG_MTD_BLOCK=y
-CONFIG_MTD_RAM=y
-CONFIG_MTD_ROM=y
-CONFIG_BLK_DEV_RAM=y
-# CONFIG_INPUT is not set
-# CONFIG_SERIO is not set
-# CONFIG_VT is not set
-# CONFIG_DEVKMEM is not set
-# CONFIG_HW_RANDOM is not set
-# CONFIG_HWMON is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_EXT2_FS=y
-# CONFIG_DNOTIFY is not set
-CONFIG_ROMFS_FS=y
-# CONFIG_ENABLE_MUST_CHECK is not set
diff --git a/arch/arm/configs/bcm_defconfig b/arch/arm/configs/bcm_defconfig
index bc614f4..83a87e4 100644
--- a/arch/arm/configs/bcm_defconfig
+++ b/arch/arm/configs/bcm_defconfig
@@ -25,7 +25,8 @@ CONFIG_MODULE_UNLOAD=y
# CONFIG_BLK_DEV_BSG is not set
CONFIG_PARTITION_ADVANCED=y
CONFIG_ARCH_BCM=y
-CONFIG_ARCH_BCM_MOBILE=y
+CONFIG_ARCH_BCM_21664=y
+CONFIG_ARCH_BCM_281XX=y
CONFIG_ARM_THUMBEE=y
CONFIG_SMP=y
CONFIG_PREEMPT=y
diff --git a/arch/arm/configs/exynos_defconfig b/arch/arm/configs/exynos_defconfig
index e21ef83..c419907 100644
--- a/arch/arm/configs/exynos_defconfig
+++ b/arch/arm/configs/exynos_defconfig
@@ -134,6 +134,7 @@ CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=y
CONFIG_USB_HSIC_USB3503=y
CONFIG_MMC=y
+CONFIG_MMC_BLOCK_MINORS=16
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_S3C=y
CONFIG_MMC_SDHCI_S3C_DMA=y
diff --git a/arch/arm/configs/hisi_defconfig b/arch/arm/configs/hisi_defconfig
index 1772505..1fe3621f 100644
--- a/arch/arm/configs/hisi_defconfig
+++ b/arch/arm/configs/hisi_defconfig
@@ -5,6 +5,8 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_RD_LZMA=y
CONFIG_ARCH_HISI=y
CONFIG_ARCH_HI3xxx=y
+CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
CONFIG_ARCH_HIX5HD2=y
CONFIG_ARCH_HIP04=y
CONFIG_SMP=y
@@ -14,8 +16,11 @@ CONFIG_AEABI=y
CONFIG_HIGHMEM=y
CONFIG_ARM_APPENDED_DTB=y
CONFIG_ARM_ATAG_DTB_COMPAT=y
+CONFIG_NEON=y
CONFIG_ARM_ATAG_DTB_COMPAT_CMDLINE_FROM_BOOTLOADER=y
+CONFIG_PM_RUNTIME=y
CONFIG_NET=y
+CONFIG_PACKET=y
CONFIG_UNIX=y
CONFIG_INET=y
CONFIG_IP_PNP=y
@@ -26,6 +31,7 @@ CONFIG_BLK_DEV_SD=y
CONFIG_ATA=y
CONFIG_SATA_AHCI_PLATFORM=y
CONFIG_NETDEVICES=y
+CONFIG_HIX5HD2_GMAC=y
CONFIG_SERIAL_8250=y
CONFIG_SERIAL_8250_DEPRECATED_OPTIONS=y
CONFIG_SERIAL_8250_CONSOLE=y
@@ -39,8 +45,13 @@ CONFIG_I2C_DESIGNWARE_PLATFORM=y
CONFIG_SPI=y
CONFIG_SPI_PL022=y
CONFIG_PINCTRL_SINGLE=y
+CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_SYSFS=y
+CONFIG_GPIOLIB=y
CONFIG_GPIO_GENERIC_PLATFORM=y
CONFIG_REGULATOR_GPIO=y
+CONFIG_MFD_SYSCON=y
+CONFIG_POWER_RESET_SYSCON=y
CONFIG_DRM=y
CONFIG_FB_SIMPLE=y
CONFIG_USB=y
@@ -48,15 +59,21 @@ CONFIG_USB_XHCI_HCD=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_MXC=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
+CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_STORAGE=y
CONFIG_NOP_USB_XCEIV=y
CONFIG_MMC=y
CONFIG_RTC_CLASS=y
+CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_MMC_DW_PLTFM=y
CONFIG_RTC_DRV_PL031=y
CONFIG_DMADEVICES=y
CONFIG_DW_DMAC=y
CONFIG_PL330_DMA=y
CONFIG_PWM=y
+CONFIG_PHY_HIX5HD2_SATA=y
CONFIG_EXT4_FS=y
CONFIG_TMPFS=y
CONFIG_NFS_FS=y
@@ -65,6 +82,8 @@ CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_FS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
CONFIG_DEBUG_KERNEL=y
CONFIG_LOCKUP_DETECTOR=y
CONFIG_VFP=y
diff --git a/arch/arm/configs/imx_v6_v7_defconfig b/arch/arm/configs/imx_v6_v7_defconfig
index 6790f1b..f707cd2 100644
--- a/arch/arm/configs/imx_v6_v7_defconfig
+++ b/arch/arm/configs/imx_v6_v7_defconfig
@@ -163,7 +163,13 @@ CONFIG_SPI_IMX=y
CONFIG_GPIO_SYSFS=y
CONFIG_GPIO_MC9S08DZ60=y
CONFIG_GPIO_STMPE=y
-# CONFIG_HWMON is not set
+CONFIG_SENSORS_GPIO_FAN=y
+CONFIG_THERMAL=y
+CONFIG_CPU_THERMAL=y
+CONFIG_IMX_THERMAL=y
+CONFIG_POWER_SUPPLY=y
+CONFIG_POWER_RESET=y
+CONFIG_POWER_RESET_IMX=y
CONFIG_WATCHDOG=y
CONFIG_IMX2_WDT=y
CONFIG_MFD_DA9052_I2C=y
@@ -211,6 +217,7 @@ CONFIG_SND_SOC_IMX_WM8962=y
CONFIG_SND_SOC_IMX_SGTL5000=y
CONFIG_SND_SOC_IMX_SPDIF=y
CONFIG_SND_SOC_IMX_MC13783=y
+CONFIG_SND_SOC_TLV320AIC3X=y
CONFIG_SND_SIMPLE_CARD=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
@@ -239,6 +246,7 @@ CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_INTF_DEV_UIE_EMUL=y
+CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_ISL1208=y
CONFIG_RTC_DRV_PCF8563=y
CONFIG_RTC_DRV_MC13XXX=y
diff --git a/arch/arm/configs/integrator_defconfig b/arch/arm/configs/integrator_defconfig
index c1f5adc..71f1467 100644
--- a/arch/arm/configs/integrator_defconfig
+++ b/arch/arm/configs/integrator_defconfig
@@ -8,6 +8,9 @@ CONFIG_BLK_DEV_INITRD=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
+CONFIG_ARCH_MULTI_V4T=y
+CONFIG_ARCH_MULTI_V5=y
+# CONFIG_ARCH_MULTI_V7 is not set
CONFIG_ARCH_INTEGRATOR=y
CONFIG_ARCH_INTEGRATOR_AP=y
CONFIG_ARCH_INTEGRATOR_CP=y
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index 932ae40..20a3ff9 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -20,6 +20,9 @@ CONFIG_MODULE_FORCE_UNLOAD=y
CONFIG_MODVERSIONS=y
CONFIG_ARCH_KEYSTONE=y
CONFIG_ARM_LPAE=y
+CONFIG_PCI=y
+CONFIG_PCI_MSI=y
+CONFIG_PCI_KEYSTONE=y
CONFIG_SMP=y
CONFIG_PREEMPT=y
CONFIG_AEABI=y
@@ -194,3 +197,7 @@ CONFIG_LEDS_TRIGGER_ONESHOT=y
CONFIG_LEDS_TRIGGER_HEARTBEAT=y
CONFIG_LEDS_TRIGGER_BACKLIGHT=y
CONFIG_LEDS_TRIGGER_GPIO=y
+CONFIG_KEYSTONE_IRQ=y
+CONFIG_GPIO_SYSCON=y
+CONFIG_TI_DAVINCI_MDIO=y
+CONFIG_MARVELL_PHY=y
diff --git a/arch/arm/configs/koelsch_defconfig b/arch/arm/configs/koelsch_defconfig
deleted file mode 100644
index b33d19b..0000000
--- a/arch/arm/configs/koelsch_defconfig
+++ /dev/null
@@ -1,113 +0,0 @@
-CONFIG_SYSVIPC=y
-CONFIG_NO_HZ=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_LOG_BUF_SHIFT=16
-CONFIG_CC_OPTIMIZE_FOR_SIZE=y
-CONFIG_SYSCTL_SYSCALL=y
-CONFIG_EMBEDDED=y
-CONFIG_PERF_EVENTS=y
-CONFIG_SLAB=y
-CONFIG_ARCH_SHMOBILE_LEGACY=y
-CONFIG_ARCH_R8A7791=y
-CONFIG_MACH_KOELSCH=y
-# CONFIG_SWP_EMULATE is not set
-CONFIG_CPU_BPREDICT_DISABLE=y
-CONFIG_PL310_ERRATA_588369=y
-CONFIG_ARM_ERRATA_754322=y
-CONFIG_PCI=y
-CONFIG_PCI_RCAR_GEN2=y
-CONFIG_PCI_RCAR_GEN2_PCIE=y
-CONFIG_SMP=y
-CONFIG_SCHED_MC=y
-CONFIG_NR_CPUS=8
-CONFIG_AEABI=y
-CONFIG_ZBOOT_ROM_TEXT=0x0
-CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_ARM_APPENDED_DTB=y
-CONFIG_KEXEC=y
-CONFIG_AUTO_ZRELADDR=y
-CONFIG_VFP=y
-CONFIG_NEON=y
-# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
-CONFIG_PM_RUNTIME=y
-CONFIG_NET=y
-CONFIG_PACKET=y
-CONFIG_UNIX=y
-CONFIG_INET=y
-CONFIG_IP_PNP=y
-CONFIG_IP_PNP_DHCP=y
-CONFIG_DEVTMPFS=y
-CONFIG_DEVTMPFS_MOUNT=y
-CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
-CONFIG_BLK_DEV_SD=y
-CONFIG_ATA=y
-CONFIG_SATA_RCAR=y
-CONFIG_MTD=y
-CONFIG_MTD_M25P80=y
-CONFIG_MTD_SPI_NOR=y
-CONFIG_EEPROM_AT24=y
-CONFIG_NETDEVICES=y
-# CONFIG_NET_VENDOR_ARC is not set
-# CONFIG_NET_CADENCE is not set
-# CONFIG_NET_VENDOR_BROADCOM is not set
-# CONFIG_NET_VENDOR_CIRRUS is not set
-# CONFIG_NET_VENDOR_FARADAY is not set
-# CONFIG_NET_VENDOR_INTEL is not set
-# CONFIG_NET_VENDOR_MARVELL is not set
-# CONFIG_NET_VENDOR_MICREL is not set
-# CONFIG_NET_VENDOR_NATSEMI is not set
-CONFIG_SH_ETH=y
-# CONFIG_NET_VENDOR_SEEQ is not set
-# CONFIG_NET_VENDOR_SMSC is not set
-# CONFIG_NET_VENDOR_STMICRO is not set
-# CONFIG_NET_VENDOR_VIA is not set
-# CONFIG_NET_VENDOR_WIZNET is not set
-# CONFIG_INPUT_MOUSEDEV_PSAUX is not set
-CONFIG_KEYBOARD_GPIO=y
-# CONFIG_INPUT_MOUSE is not set
-# CONFIG_LEGACY_PTYS is not set
-CONFIG_SERIAL_SH_SCI=y
-CONFIG_SERIAL_SH_SCI_NR_UARTS=20
-CONFIG_SERIAL_SH_SCI_CONSOLE=y
-CONFIG_I2C=y
-CONFIG_I2C_MUX=y
-CONFIG_I2C_SH_MOBILE=y
-CONFIG_I2C_RCAR=y
-CONFIG_SPI=y
-CONFIG_SPI_RSPI=y
-CONFIG_SPI_SH_MSIOF=y
-CONFIG_GPIOLIB=y
-CONFIG_GPIO_RCAR=y
-# CONFIG_HWMON is not set
-CONFIG_THERMAL=y
-CONFIG_RCAR_THERMAL=y
-CONFIG_REGULATOR=y
-CONFIG_REGULATOR_FIXED_VOLTAGE=y
-CONFIG_REGULATOR_DA9210=y
-CONFIG_REGULATOR_GPIO=y
-CONFIG_MEDIA_SUPPORT=y
-CONFIG_MEDIA_CAMERA_SUPPORT=y
-CONFIG_V4L_PLATFORM_DRIVERS=y
-CONFIG_SOC_CAMERA=y
-CONFIG_SOC_CAMERA_PLATFORM=y
-CONFIG_VIDEO_RCAR_VIN=y
-# CONFIG_MEDIA_SUBDRV_AUTOSELECT is not set
-CONFIG_VIDEO_ADV7180=y
-# CONFIG_HID is not set
-# CONFIG_USB_SUPPORT is not set
-CONFIG_MMC=y
-CONFIG_MMC_SDHI=y
-CONFIG_NEW_LEDS=y
-CONFIG_LEDS_CLASS=y
-CONFIG_LEDS_GPIO=y
-# CONFIG_IOMMU_SUPPORT is not set
-# CONFIG_DNOTIFY is not set
-CONFIG_TMPFS=y
-CONFIG_CONFIGFS_FS=y
-# CONFIG_MISC_FILESYSTEMS is not set
-CONFIG_NFS_FS=y
-CONFIG_ROOT_NFS=y
-# CONFIG_ENABLE_WARN_DEPRECATED is not set
-# CONFIG_ENABLE_MUST_CHECK is not set
-# CONFIG_ARM_UNWIND is not set
diff --git a/arch/arm/configs/multi_v5_defconfig b/arch/arm/configs/multi_v5_defconfig
index 018bef9..9d56781 100644
--- a/arch/arm/configs/multi_v5_defconfig
+++ b/arch/arm/configs/multi_v5_defconfig
@@ -67,9 +67,11 @@ CONFIG_SATA_AHCI=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
CONFIG_NET_DSA_MV88E6123_61_65=y
+CONFIG_NET_DSA_MV88E6171=y
CONFIG_MV643XX_ETH=y
CONFIG_R8169=y
CONFIG_MARVELL_PHY=y
+CONFIG_MWL8K=m
CONFIG_LIBERTAS=y
CONFIG_LIBERTAS_SDIO=y
CONFIG_INPUT_EVDEV=y
diff --git a/arch/arm/configs/multi_v7_defconfig b/arch/arm/configs/multi_v7_defconfig
index 9d7a32f..d789658 100644
--- a/arch/arm/configs/multi_v7_defconfig
+++ b/arch/arm/configs/multi_v7_defconfig
@@ -3,12 +3,14 @@ CONFIG_FHANDLE=y
CONFIG_IRQ_DOMAIN_DEBUG=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
+CONFIG_CGROUPS=y
CONFIG_BLK_DEV_INITRD=y
CONFIG_EMBEDDED=y
CONFIG_PERF_EVENTS=y
CONFIG_MODULES=y
CONFIG_MODULE_UNLOAD=y
CONFIG_PARTITION_ADVANCED=y
+CONFIG_CMDLINE_PARTITION=y
CONFIG_ARCH_VIRT=y
CONFIG_ARCH_MVEBU=y
CONFIG_MACH_ARMADA_370=y
@@ -17,7 +19,9 @@ CONFIG_MACH_ARMADA_38X=y
CONFIG_MACH_ARMADA_XP=y
CONFIG_MACH_DOVE=y
CONFIG_ARCH_BCM=y
-CONFIG_ARCH_BCM_MOBILE=y
+CONFIG_ARCH_BCM_CYGNUS=y
+CONFIG_ARCH_BCM_21664=y
+CONFIG_ARCH_BCM_281XX=y
CONFIG_ARCH_BCM_5301X=y
CONFIG_ARCH_BRCMSTB=y
CONFIG_ARCH_BERLIN=y
@@ -124,8 +128,12 @@ CONFIG_DMA_CMA=y
CONFIG_CMA_SIZE_MBYTES=64
CONFIG_OMAP_OCP2SCP=y
CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
CONFIG_MTD_M25P80=y
+CONFIG_MTD_NAND=y
CONFIG_MTD_SPI_NOR=y
+CONFIG_MTD_UBI=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_AD525X_DPOT=y
CONFIG_AD525X_DPOT_I2C=y
@@ -146,6 +154,7 @@ CONFIG_AHCI_TEGRA=y
CONFIG_SATA_HIGHBANK=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
+CONFIG_HIX5HD2_GMAC=y
CONFIG_SUN4I_EMAC=y
CONFIG_MACB=y
CONFIG_NET_CALXEDA_XGMAC=y
@@ -160,6 +169,7 @@ CONFIG_TI_CPSW=y
CONFIG_XILINX_EMACLITE=y
CONFIG_AT803X_PHY=y
CONFIG_MARVELL_PHY=y
+CONFIG_BROADCOM_PHY=y
CONFIG_ICPLUS_PHY=y
CONFIG_USB_PEGASUS=y
CONFIG_USB_USBNET=y
@@ -234,6 +244,7 @@ CONFIG_SPI_TEGRA114=y
CONFIG_SPI_TEGRA20_SFLASH=y
CONFIG_SPI_TEGRA20_SLINK=y
CONFIG_SPI_XILINX=y
+CONFIG_SPI_SPIDEV=y
CONFIG_PINCTRL_AS3722=y
CONFIG_PINCTRL_PALMAS=y
CONFIG_PINCTRL_APQ8084=y
@@ -261,6 +272,7 @@ CONFIG_ST_THERMAL_SYSCFG=y
CONFIG_ST_THERMAL_MEMMAP=y
CONFIG_WATCHDOG=y
CONFIG_XILINX_WATCHDOG=y
+CONFIG_ARM_SP805_WATCHDOG=y
CONFIG_ORION_WATCHDOG=y
CONFIG_SUNXI_WATCHDOG=y
CONFIG_MESON_WATCHDOG=y
@@ -268,6 +280,7 @@ CONFIG_MFD_AS3722=y
CONFIG_MFD_BCM590XX=y
CONFIG_MFD_CROS_EC=y
CONFIG_MFD_CROS_EC_SPI=y
+CONFIG_MFD_MAX77686=y
CONFIG_MFD_MAX8907=y
CONFIG_MFD_SEC_CORE=y
CONFIG_MFD_STMPE=y
@@ -279,7 +292,10 @@ CONFIG_REGULATOR_AB8500=y
CONFIG_REGULATOR_AS3722=y
CONFIG_REGULATOR_BCM590XX=y
CONFIG_REGULATOR_GPIO=y
+CONFIG_MFD_SYSCON=y
+CONFIG_POWER_RESET_SYSCON=y
CONFIG_REGULATOR_MAX8907=y
+CONFIG_REGULATOR_MAX77686=y
CONFIG_REGULATOR_PALMAS=y
CONFIG_REGULATOR_S2MPS11=y
CONFIG_REGULATOR_S5M8767=y
@@ -308,6 +324,8 @@ CONFIG_FRAMEBUFFER_CONSOLE=y
CONFIG_FRAMEBUFFER_CONSOLE_ROTATION=y
CONFIG_SOUND=y
CONFIG_SND=y
+CONFIG_SND_DYNAMIC_MINORS=y
+CONFIG_SND_USB_AUDIO=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_TEGRA=y
CONFIG_SND_SOC_TEGRA_RT5640=y
@@ -321,9 +339,11 @@ CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_MVEBU=y
CONFIG_USB_EHCI_HCD=y
CONFIG_USB_EHCI_TEGRA=y
+CONFIG_USB_EHCI_HCD_STI=y
CONFIG_USB_EHCI_HCD_PLATFORM=y
CONFIG_USB_ISP1760_HCD=y
CONFIG_USB_OHCI_HCD=y
+CONFIG_USB_OHCI_HCD_STI=y
CONFIG_USB_OHCI_HCD_PLATFORM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_CHIPIDEA=y
@@ -355,6 +375,8 @@ CONFIG_MMC_OMAP_HS=y
CONFIG_MMC_MVSDIO=y
CONFIG_MMC_SUNXI=y
CONFIG_MMC_DW=y
+CONFIG_MMC_DW_IDMAC=y
+CONFIG_MMC_DW_PLTFM=y
CONFIG_MMC_DW_EXYNOS=y
CONFIG_MMC_DW_ROCKCHIP=y
CONFIG_NEW_LEDS=y
@@ -379,6 +401,7 @@ CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_AS3722=y
CONFIG_RTC_DRV_DS1307=y
CONFIG_RTC_DRV_MAX8907=y
+CONFIG_RTC_DRV_MAX77686=y
CONFIG_RTC_DRV_PALMAS=y
CONFIG_RTC_DRV_TWL4030=y
CONFIG_RTC_DRV_TPS6586X=y
@@ -413,6 +436,7 @@ CONFIG_NVEC_POWER=y
CONFIG_NVEC_PAZ00=y
CONFIG_QCOM_GSBI=y
CONFIG_COMMON_CLK_QCOM=y
+CONFIG_COMMON_CLK_MAX77686=y
CONFIG_APQ_MMCC_8084=y
CONFIG_MSM_GCC_8660=y
CONFIG_MSM_MMCC_8960=y
@@ -426,12 +450,19 @@ CONFIG_AK8975=y
CONFIG_PWM=y
CONFIG_PWM_TEGRA=y
CONFIG_PWM_VT8500=y
+CONFIG_PHY_HIX5HD2_SATA=y
CONFIG_OMAP_USB2=y
CONFIG_TI_PIPE3=y
CONFIG_PHY_MIPHY365X=y
+CONFIG_PHY_STIH41X_USB=y
CONFIG_PHY_SUN4I_USB=y
CONFIG_EXT4_FS=y
+CONFIG_AUTOFS4_FS=y
+CONFIG_MSDOS_FS=y
CONFIG_VFAT_FS=y
+CONFIG_NTFS_FS=y
+CONFIG_TMPFS_POSIX_ACL=y
+CONFIG_UBIFS_FS=y
CONFIG_TMPFS=y
CONFIG_SQUASHFS=y
CONFIG_SQUASHFS_LZO=y
@@ -440,6 +471,9 @@ CONFIG_NFS_FS=y
CONFIG_NFS_V3_ACL=y
CONFIG_NFS_V4=y
CONFIG_ROOT_NFS=y
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_UTF8=y
CONFIG_PRINTK_TIME=y
CONFIG_DEBUG_FS=y
CONFIG_MAGIC_SYSRQ=y
diff --git a/arch/arm/configs/mvebu_v5_defconfig b/arch/arm/configs/mvebu_v5_defconfig
index 22058e1..824de49 100644
--- a/arch/arm/configs/mvebu_v5_defconfig
+++ b/arch/arm/configs/mvebu_v5_defconfig
@@ -67,9 +67,11 @@ CONFIG_SATA_AHCI=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
CONFIG_NET_DSA_MV88E6123_61_65=y
+CONFIG_NET_DSA_MV88E6171=y
CONFIG_MV643XX_ETH=y
CONFIG_R8169=y
CONFIG_MARVELL_PHY=y
+CONFIG_MWL8K=m
CONFIG_LIBERTAS=y
CONFIG_LIBERTAS_SDIO=y
CONFIG_INPUT_EVDEV=y
diff --git a/arch/arm/configs/mvebu_v7_defconfig b/arch/arm/configs/mvebu_v7_defconfig
index ed0a0d1..627acce 100644
--- a/arch/arm/configs/mvebu_v7_defconfig
+++ b/arch/arm/configs/mvebu_v7_defconfig
@@ -45,6 +45,7 @@ CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
CONFIG_DEVTMPFS=y
CONFIG_DEVTMPFS_MOUNT=y
CONFIG_MTD=y
+CONFIG_MTD_BLOCK=y
CONFIG_MTD_CFI=y
CONFIG_MTD_CFI_INTELEXT=y
CONFIG_MTD_CFI_AMDSTD=y
@@ -59,10 +60,12 @@ CONFIG_ATA=y
CONFIG_AHCI_MVEBU=y
CONFIG_SATA_MV=y
CONFIG_NETDEVICES=y
+CONFIG_NET_DSA_MV88E6171=y
CONFIG_MV643XX_ETH=y
CONFIG_MVNETA=y
CONFIG_MVPP2=y
CONFIG_MARVELL_PHY=y
+CONFIG_FIXED_PHY=y
CONFIG_MWIFIEX=y
CONFIG_MWIFIEX_SDIO=y
CONFIG_INPUT_EVDEV=y
@@ -72,6 +75,7 @@ CONFIG_SERIAL_8250_CONSOLE=y
CONFIG_SERIAL_8250_DW=y
CONFIG_SERIAL_OF_PLATFORM=y
CONFIG_I2C=y
+CONFIG_I2C_CHARDEV=y
CONFIG_I2C_MV64XXX=y
CONFIG_SPI=y
CONFIG_SPI_ORION=y
@@ -85,7 +89,9 @@ CONFIG_SOUND=y
CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_KIRKWOOD_SOC=y
-CONFIG_SND_KIRKWOOD_SOC_ARMADA370_DB=y
+CONFIG_SND_SOC_CS42L51_I2C=y
+CONFIG_SND_SOC_SPDIF=y
+CONFIG_SND_SIMPLE_CARD=y
CONFIG_USB=y
CONFIG_USB_XHCI_HCD=y
CONFIG_USB_XHCI_MVEBU=y
@@ -96,6 +102,7 @@ CONFIG_MMC=y
CONFIG_MMC_SDHCI=y
CONFIG_MMC_SDHCI_PLTFM=y
CONFIG_MMC_SDHCI_DOVE=y
+CONFIG_MMC_SDHCI_PXAV3=y
CONFIG_MMC_MVSDIO=y
CONFIG_LEDS_GPIO=y
CONFIG_LEDS_CLASS=y
diff --git a/arch/arm/configs/nhk8815_defconfig b/arch/arm/configs/nhk8815_defconfig
index 263ae38..7d2ad30 100644
--- a/arch/arm/configs/nhk8815_defconfig
+++ b/arch/arm/configs/nhk8815_defconfig
@@ -20,7 +20,6 @@ CONFIG_PREEMPT=y
CONFIG_AEABI=y
CONFIG_ZBOOT_ROM_TEXT=0x0
CONFIG_ZBOOT_ROM_BSS=0x0
-CONFIG_FPE_NWFPE=y
CONFIG_NET=y
CONFIG_PACKET=y
CONFIG_UNIX=y
@@ -57,14 +56,12 @@ CONFIG_MTD_NAND_FSMC=y
CONFIG_MTD_ONENAND=y
CONFIG_MTD_ONENAND_VERIFY_WRITE=y
CONFIG_MTD_ONENAND_GENERIC=y
-CONFIG_PROC_DEVICETREE=y
CONFIG_BLK_DEV_LOOP=y
CONFIG_BLK_DEV_CRYPTOLOOP=y
CONFIG_BLK_DEV_RAM=y
CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_CHR_DEV_SG=y
-CONFIG_SCSI_MULTI_LUN=y
CONFIG_SCSI_CONSTANTS=y
CONFIG_SCSI_LOGGING=y
CONFIG_SCSI_SCAN_ASYNC=y
@@ -83,21 +80,21 @@ CONFIG_PPP_SYNC_TTY=m
CONFIG_INPUT_EVDEV=y
# CONFIG_KEYBOARD_ATKBD is not set
CONFIG_KEYBOARD_GPIO=y
+CONFIG_KEYBOARD_STMPE=y
# CONFIG_MOUSE_PS2 is not set
# CONFIG_SERIO is not set
# CONFIG_LEGACY_PTYS is not set
CONFIG_SERIAL_AMBA_PL011=y
CONFIG_SERIAL_AMBA_PL011_CONSOLE=y
CONFIG_HW_RANDOM=y
-CONFIG_HW_RANDOM_NOMADIK=y
CONFIG_I2C_CHARDEV=y
CONFIG_I2C_GPIO=y
-CONFIG_I2C_NOMADIK=y
CONFIG_DEBUG_GPIO=y
+CONFIG_GPIO_STMPE=y
# CONFIG_HWMON is not set
+CONFIG_MFD_STMPE=y
CONFIG_REGULATOR=y
CONFIG_MMC=y
-CONFIG_MMC_UNSAFE_RESUME=y
# CONFIG_MMC_BLOCK_BOUNCE is not set
CONFIG_MMC_ARMMMCI=y
CONFIG_NEW_LEDS=y
@@ -125,12 +122,12 @@ CONFIG_NLS_CODEPAGE_437=y
CONFIG_NLS_ASCII=y
CONFIG_NLS_ISO8859_1=y
CONFIG_NLS_ISO8859_15=y
+CONFIG_DEBUG_INFO=y
# CONFIG_ENABLE_MUST_CHECK is not set
CONFIG_DEBUG_FS=y
# CONFIG_SCHED_DEBUG is not set
# CONFIG_DEBUG_PREEMPT is not set
# CONFIG_DEBUG_BUGVERBOSE is not set
-CONFIG_DEBUG_INFO=y
CONFIG_CRYPTO_MD5=y
CONFIG_CRYPTO_SHA1=y
CONFIG_CRYPTO_DES=y
diff --git a/arch/arm/configs/omap2plus_defconfig b/arch/arm/configs/omap2plus_defconfig
index b3f8667..3e09286 100644
--- a/arch/arm/configs/omap2plus_defconfig
+++ b/arch/arm/configs/omap2plus_defconfig
@@ -129,11 +129,27 @@ CONFIG_BLK_DEV_SD=y
CONFIG_SCSI_SCAN_ASYNC=y
CONFIG_MD=y
CONFIG_NETDEVICES=y
+# CONFIG_NET_VENDOR_ARC is not set
+# CONFIG_NET_CADENCE is not set
+# CONFIG_NET_VENDOR_BROADCOM is not set
+# CONFIG_NET_VENDOR_CIRRUS is not set
+# CONFIG_NET_VENDOR_FARADAY is not set
+# CONFIG_NET_VENDOR_HISILICON is not set
+# CONFIG_NET_VENDOR_INTEL is not set
+# CONFIG_NET_VENDOR_MARVELL is not set
CONFIG_KS8851=y
CONFIG_KS8851_MLL=y
+# CONFIG_NET_VENDOR_MICROCHIP is not set
+# CONFIG_NET_VENDOR_NATSEMI is not set
+# CONFIG_NET_VENDOR_QUALCOMM is not set
+# CONFIG_NET_VENDOR_SAMSUNG is not set
+# CONFIG_NET_VENDOR_SEEQ is not set
CONFIG_SMC91X=y
CONFIG_SMSC911X=y
+# CONFIG_NET_VENDOR_STMICRO is not set
CONFIG_TI_CPSW=y
+# CONFIG_NET_VENDOR_VIA is not set
+# CONFIG_NET_VENDOR_WIZNET is not set
CONFIG_AT803X_PHY=y
CONFIG_SMSC_PHY=y
CONFIG_USB_USBNET=y
@@ -161,6 +177,7 @@ CONFIG_KEYBOARD_MATRIX=m
CONFIG_KEYBOARD_TWL4030=y
CONFIG_INPUT_TOUCHSCREEN=y
CONFIG_TOUCHSCREEN_ADS7846=m
+CONFIG_TOUCHSCREEN_EDT_FT5X06=m
CONFIG_TOUCHSCREEN_TSC2005=m
CONFIG_TOUCHSCREEN_TSC2007=m
CONFIG_INPUT_MISC=y
@@ -264,6 +281,8 @@ CONFIG_SND_VERBOSE_PRINTK=y
CONFIG_SND_DEBUG=y
CONFIG_SND_USB_AUDIO=m
CONFIG_SND_SOC=m
+CONFIG_SND_EDMA_SOC=m
+CONFIG_SND_AM33XX_SOC_EVM=m
CONFIG_SND_OMAP_SOC=m
CONFIG_SND_OMAP_SOC_OMAP_TWL4030=m
CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040=m
@@ -271,6 +290,7 @@ CONFIG_SND_OMAP_SOC_OMAP3_PANDORA=m
CONFIG_USB=y
CONFIG_USB_ANNOUNCE_NEW_DEVICES=y
CONFIG_USB_MON=y
+CONFIG_USB_XHCI_HCD=m
CONFIG_USB_WDM=y
CONFIG_USB_STORAGE=y
CONFIG_USB_DWC3=m
@@ -306,6 +326,8 @@ CONFIG_DMA_OMAP=y
CONFIG_EXTCON=y
CONFIG_EXTCON_PALMAS=y
CONFIG_PWM=y
+CONFIG_PWM_TIECAP=y
+CONFIG_PWM_TIEHRPWM=y
CONFIG_PWM_TWL=y
CONFIG_PWM_TWL_LED=y
CONFIG_OMAP_USB2=y
diff --git a/arch/arm/configs/sama5_defconfig b/arch/arm/configs/sama5_defconfig
index c9089c9..b58fb32 100644
--- a/arch/arm/configs/sama5_defconfig
+++ b/arch/arm/configs/sama5_defconfig
@@ -12,7 +12,7 @@ CONFIG_MODULES=y
CONFIG_MODULE_FORCE_LOAD=y
CONFIG_MODULE_UNLOAD=y
CONFIG_MODULE_FORCE_UNLOAD=y
-# CONFIG_LBDAF is not set
+CONFIG_LBDAF=y
# CONFIG_BLK_DEV_BSG is not set
# CONFIG_IOSCHED_DEADLINE is not set
# CONFIG_IOSCHED_CFQ is not set
@@ -20,7 +20,6 @@ CONFIG_ARCH_AT91=y
CONFIG_SOC_SAM_V7=y
CONFIG_SOC_SAMA5D3=y
CONFIG_SOC_SAMA5D4=y
-CONFIG_MACH_SAMA5_DT=y
CONFIG_AEABI=y
CONFIG_UACCESS_WITH_MEMCPY=y
CONFIG_ZBOOT_ROM_TEXT=0x0
@@ -30,6 +29,8 @@ CONFIG_CMDLINE="console=ttyS0,115200 initrd=0x21100000,25165824 root=/dev/ram0 r
CONFIG_KEXEC=y
CONFIG_AUTO_ZRELADDR=y
CONFIG_VFP=y
+CONFIG_NEON=y
+CONFIG_KERNEL_MODE_NEON=y
# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
CONFIG_PM_RUNTIME=y
CONFIG_PM_DEBUG=y
@@ -176,11 +177,13 @@ CONFIG_LEDS_TRIGGER_GPIO=y
CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_AT91RM9200=y
CONFIG_DMADEVICES=y
+CONFIG_AT_XDMAC=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_IIO=y
CONFIG_AT91_ADC=y
CONFIG_PWM=y
CONFIG_PWM_ATMEL=y
+CONFIG_PWM_ATMEL_TCB=y
CONFIG_EXT4_FS=y
CONFIG_FANOTIFY=y
CONFIG_VFAT_FS=y
diff --git a/arch/arm/configs/shmobile_defconfig b/arch/arm/configs/shmobile_defconfig
index d7346ad..63fb531 100644
--- a/arch/arm/configs/shmobile_defconfig
+++ b/arch/arm/configs/shmobile_defconfig
@@ -17,7 +17,6 @@ CONFIG_ARCH_R8A7779=y
CONFIG_ARCH_R8A7790=y
CONFIG_ARCH_R8A7791=y
CONFIG_ARCH_R8A7794=y
-CONFIG_MACH_KOELSCH=y
CONFIG_MACH_LAGER=y
CONFIG_MACH_MARZEN=y
# CONFIG_SWP_EMULATE is not set
@@ -126,6 +125,7 @@ CONFIG_SND=y
CONFIG_SND_SOC=y
CONFIG_SND_SOC_SH4_FSI=y
CONFIG_SND_SOC_RCAR=y
+CONFIG_SND_SOC_AK4642=y
CONFIG_SND_SOC_WM8978=y
CONFIG_USB=y
CONFIG_USB_EHCI_HCD=y
@@ -146,6 +146,8 @@ CONFIG_RTC_CLASS=y
CONFIG_RTC_DRV_S35390A=y
CONFIG_DMADEVICES=y
CONFIG_SH_DMAE=y
+CONFIG_RCAR_AUDMAC_PP=y
+CONFIG_RCAR_DMAC=y
# CONFIG_IOMMU_SUPPORT is not set
CONFIG_PWM=y
CONFIG_PWM_RENESAS_TPU=y
diff --git a/arch/arm/configs/tegra_defconfig b/arch/arm/configs/tegra_defconfig
index 888fc15..40750f9 100644
--- a/arch/arm/configs/tegra_defconfig
+++ b/arch/arm/configs/tegra_defconfig
@@ -97,10 +97,8 @@ CONFIG_ICS932S401=y
CONFIG_APDS9802ALS=y
CONFIG_ISL29003=y
CONFIG_EEPROM_AT24=y
-CONFIG_SCSI=y
CONFIG_BLK_DEV_SD=y
CONFIG_BLK_DEV_SR=y
-CONFIG_SCSI_MULTI_LUN=y
# CONFIG_SCSI_LOWLEVEL is not set
CONFIG_ATA=y
CONFIG_SATA_AHCI=y
diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h
index 92793ba..d4ebf56 100644
--- a/arch/arm/include/asm/arch_timer.h
+++ b/arch/arm/include/asm/arch_timer.h
@@ -78,6 +78,15 @@ 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/cpuidle.h b/arch/arm/include/asm/cpuidle.h
index 2fca60a..af319ac 100644
--- a/arch/arm/include/asm/cpuidle.h
+++ b/arch/arm/include/asm/cpuidle.h
@@ -15,7 +15,6 @@ static inline int arm_cpuidle_simple_enter(struct cpuidle_device *dev,
.exit_latency = 1,\
.target_residency = 1,\
.power_usage = p,\
- .flags = CPUIDLE_FLAG_TIME_VALID,\
.name = "WFI",\
.desc = "ARM WFI",\
}
diff --git a/arch/arm/include/asm/firmware.h b/arch/arm/include/asm/firmware.h
index 2c9f10d..89aefe1 100644
--- a/arch/arm/include/asm/firmware.h
+++ b/arch/arm/include/asm/firmware.h
@@ -28,7 +28,7 @@ struct firmware_ops {
/*
* Enters CPU idle mode
*/
- int (*do_idle)(void);
+ int (*do_idle)(unsigned long mode);
/*
* Sets boot address of specified physical CPU
*/
@@ -41,6 +41,14 @@ struct firmware_ops {
* Initializes L2 cache
*/
int (*l2x0_init)(void);
+ /*
+ * Enter system-wide suspend.
+ */
+ int (*suspend)(void);
+ /*
+ * Restore state of privileged hardware after system-wide suspend.
+ */
+ int (*resume)(void);
};
/* Global pointer for current firmware_ops structure, can't be NULL. */
diff --git a/arch/arm/include/asm/io.h b/arch/arm/include/asm/io.h
index 1805674..db58deb 100644
--- a/arch/arm/include/asm/io.h
+++ b/arch/arm/include/asm/io.h
@@ -47,13 +47,13 @@ extern void atomic_io_modify_relaxed(void __iomem *reg, u32 mask, u32 set);
* Generic IO read/write. These perform native-endian accesses. Note
* that some architectures will want to re-define __raw_{read,write}w.
*/
-extern void __raw_writesb(void __iomem *addr, const void *data, int bytelen);
-extern void __raw_writesw(void __iomem *addr, const void *data, int wordlen);
-extern void __raw_writesl(void __iomem *addr, const void *data, int longlen);
+void __raw_writesb(volatile void __iomem *addr, const void *data, int bytelen);
+void __raw_writesw(volatile void __iomem *addr, const void *data, int wordlen);
+void __raw_writesl(volatile void __iomem *addr, const void *data, int longlen);
-extern void __raw_readsb(const void __iomem *addr, void *data, int bytelen);
-extern void __raw_readsw(const void __iomem *addr, void *data, int wordlen);
-extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
+void __raw_readsb(const volatile void __iomem *addr, void *data, int bytelen);
+void __raw_readsw(const volatile void __iomem *addr, void *data, int wordlen);
+void __raw_readsl(const volatile void __iomem *addr, void *data, int longlen);
#if __LINUX_ARM_ARCH__ < 6
/*
@@ -69,6 +69,7 @@ extern void __raw_readsl(const void __iomem *addr, void *data, int longlen);
* writeback addressing modes as these incur a significant performance
* overhead (the address generation must be emulated in software).
*/
+#define __raw_writew __raw_writew
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
asm volatile("strh %1, %0"
@@ -76,6 +77,7 @@ static inline void __raw_writew(u16 val, volatile void __iomem *addr)
: "r" (val));
}
+#define __raw_readw __raw_readw
static inline u16 __raw_readw(const volatile void __iomem *addr)
{
u16 val;
@@ -86,6 +88,7 @@ static inline u16 __raw_readw(const volatile void __iomem *addr)
}
#endif
+#define __raw_writeb __raw_writeb
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
asm volatile("strb %1, %0"
@@ -93,6 +96,7 @@ static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
: "r" (val));
}
+#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
asm volatile("str %1, %0"
@@ -100,6 +104,7 @@ static inline void __raw_writel(u32 val, volatile void __iomem *addr)
: "r" (val));
}
+#define __raw_readb __raw_readb
static inline u8 __raw_readb(const volatile void __iomem *addr)
{
u8 val;
@@ -109,6 +114,7 @@ static inline u8 __raw_readb(const volatile void __iomem *addr)
return val;
}
+#define __raw_readl __raw_readl
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
u32 val;
@@ -267,20 +273,6 @@ extern int pci_ioremap_io(unsigned int offset, phys_addr_t phys_addr);
#define insl(p,d,l) __raw_readsl(__io(p),d,l)
#endif
-#define outb_p(val,port) outb((val),(port))
-#define outw_p(val,port) outw((val),(port))
-#define outl_p(val,port) outl((val),(port))
-#define inb_p(port) inb((port))
-#define inw_p(port) inw((port))
-#define inl_p(port) inl((port))
-
-#define outsb_p(port,from,len) outsb(port,from,len)
-#define outsw_p(port,from,len) outsw(port,from,len)
-#define outsl_p(port,from,len) outsl(port,from,len)
-#define insb_p(port,to,len) insb(port,to,len)
-#define insw_p(port,to,len) insw(port,to,len)
-#define insl_p(port,to,len) insl(port,to,len)
-
/*
* String version of IO memory access ops:
*/
@@ -347,40 +339,42 @@ extern void _memset_io(volatile void __iomem *, int, size_t);
#define iounmap __arm_iounmap
/*
- * io{read,write}{8,16,32} macros
+ * io{read,write}{16,32}be() macros
*/
-#ifndef ioread8
-#define ioread8(p) ({ unsigned int __v = __raw_readb(p); __iormb(); __v; })
-#define ioread16(p) ({ unsigned int __v = le16_to_cpu((__force __le16)__raw_readw(p)); __iormb(); __v; })
-#define ioread32(p) ({ unsigned int __v = le32_to_cpu((__force __le32)__raw_readl(p)); __iormb(); __v; })
-
-#define ioread16be(p) ({ unsigned int __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
-#define ioread32be(p) ({ unsigned int __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
-
-#define iowrite8(v,p) ({ __iowmb(); __raw_writeb(v, p); })
-#define iowrite16(v,p) ({ __iowmb(); __raw_writew((__force __u16)cpu_to_le16(v), p); })
-#define iowrite32(v,p) ({ __iowmb(); __raw_writel((__force __u32)cpu_to_le32(v), p); })
+#define ioread16be(p) ({ __u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32be(p) ({ __u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
-#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force __u16)cpu_to_be16(v), p); })
-#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force __u32)cpu_to_be32(v), p); })
-
-#define ioread8_rep(p,d,c) __raw_readsb(p,d,c)
-#define ioread16_rep(p,d,c) __raw_readsw(p,d,c)
-#define ioread32_rep(p,d,c) __raw_readsl(p,d,c)
-
-#define iowrite8_rep(p,s,c) __raw_writesb(p,s,c)
-#define iowrite16_rep(p,s,c) __raw_writesw(p,s,c)
-#define iowrite32_rep(p,s,c) __raw_writesl(p,s,c)
+#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force __u16)cpu_to_be16(v), p); })
+#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force __u32)cpu_to_be32(v), p); })
+#ifndef ioport_map
+#define ioport_map ioport_map
extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
+#endif
+#ifndef ioport_unmap
+#define ioport_unmap ioport_unmap
extern void ioport_unmap(void __iomem *addr);
#endif
struct pci_dev;
+#define pci_iounmap pci_iounmap
extern void pci_iounmap(struct pci_dev *dev, void __iomem *addr);
/*
+ * Convert a physical pointer to a virtual kernel pointer for /dev/mem
+ * access
+ */
+#define xlate_dev_mem_ptr(p) __va(p)
+
+/*
+ * Convert a virtual cached pointer to an uncached pointer
+ */
+#define xlate_dev_kmem_ptr(p) p
+
+#include <asm-generic/io.h>
+
+/*
* can the hardware map this into one segment or not, given no other
* constraints.
*/
@@ -402,17 +396,6 @@ extern int devmem_is_allowed(unsigned long pfn);
#endif
/*
- * Convert a physical pointer to a virtual kernel pointer for /dev/mem
- * access
- */
-#define xlate_dev_mem_ptr(p) __va(p)
-
-/*
- * Convert a virtual cached pointer to an uncached pointer
- */
-#define xlate_dev_kmem_ptr(p) p
-
-/*
* Register ISA memory and port locations for glibc iopl/inb/outb
* emulation.
*/
diff --git a/arch/arm/include/asm/mach/pci.h b/arch/arm/include/asm/mach/pci.h
index 7fc4278..8292b5f 100644
--- a/arch/arm/include/asm/mach/pci.h
+++ b/arch/arm/include/asm/mach/pci.h
@@ -22,6 +22,9 @@ struct hw_pci {
#ifdef CONFIG_PCI_DOMAINS
int domain;
#endif
+#ifdef CONFIG_PCI_MSI
+ struct msi_controller *msi_ctrl;
+#endif
struct pci_ops *ops;
int nr_controllers;
void **private_data;
@@ -36,8 +39,6 @@ struct hw_pci {
resource_size_t start,
resource_size_t size,
resource_size_t align);
- void (*add_bus)(struct pci_bus *bus);
- void (*remove_bus)(struct pci_bus *bus);
};
/*
@@ -47,6 +48,9 @@ struct pci_sys_data {
#ifdef CONFIG_PCI_DOMAINS
int domain;
#endif
+#ifdef CONFIG_PCI_MSI
+ struct msi_controller *msi_ctrl;
+#endif
struct list_head node;
int busnr; /* primary bus number */
u64 mem_offset; /* bus->cpu memory mapping offset */
@@ -65,8 +69,6 @@ struct pci_sys_data {
resource_size_t start,
resource_size_t size,
resource_size_t align);
- void (*add_bus)(struct pci_bus *bus);
- void (*remove_bus)(struct pci_bus *bus);
void *private_data; /* platform controller private data */
};
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index e731018..184def0 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -274,11 +274,13 @@ static inline unsigned long __phys_to_virt(phys_addr_t x)
* translation for translating DMA addresses. Use the driver
* DMA support - see dma-mapping.h.
*/
+#define virt_to_phys virt_to_phys
static inline phys_addr_t virt_to_phys(const volatile void *x)
{
return __virt_to_phys((unsigned long)(x));
}
+#define phys_to_virt phys_to_virt
static inline void *phys_to_virt(phys_addr_t x)
{
return (void *)__phys_to_virt(x);
@@ -322,11 +324,13 @@ static inline phys_addr_t __virt_to_idmap(unsigned long x)
#endif
#ifdef CONFIG_VIRT_TO_BUS
+#define virt_to_bus virt_to_bus
static inline __deprecated unsigned long virt_to_bus(void *x)
{
return __virt_to_bus((unsigned long)x);
}
+#define bus_to_virt bus_to_virt
static inline __deprecated void *bus_to_virt(unsigned long x)
{
return (void *)__bus_to_virt(x);
diff --git a/arch/arm/include/asm/perf_event.h b/arch/arm/include/asm/perf_event.h
index c3a8369..d9cf138 100644
--- a/arch/arm/include/asm/perf_event.h
+++ b/arch/arm/include/asm/perf_event.h
@@ -12,7 +12,7 @@
#ifndef __ARM_PERF_EVENT_H__
#define __ARM_PERF_EVENT_H__
-#ifdef CONFIG_HW_PERF_EVENTS
+#ifdef CONFIG_PERF_EVENTS
struct pt_regs;
extern unsigned long perf_instruction_pointer(struct pt_regs *regs);
extern unsigned long perf_misc_flags(struct pt_regs *regs);
diff --git a/arch/arm/include/asm/pmu.h b/arch/arm/include/asm/pmu.h
index 0b648c5..b1596bd 100644
--- a/arch/arm/include/asm/pmu.h
+++ b/arch/arm/include/asm/pmu.h
@@ -15,6 +15,8 @@
#include <linux/interrupt.h>
#include <linux/perf_event.h>
+#include <asm/cputype.h>
+
/*
* struct arm_pmu_platdata - ARM PMU platform data
*
@@ -66,19 +68,25 @@ struct pmu_hw_events {
/*
* The events that are active on the PMU for the given index.
*/
- struct perf_event **events;
+ struct perf_event *events[ARMPMU_MAX_HWEVENTS];
/*
* A 1 bit for an index indicates that the counter is being used for
* an event. A 0 means that the counter can be used.
*/
- unsigned long *used_mask;
+ DECLARE_BITMAP(used_mask, ARMPMU_MAX_HWEVENTS);
/*
* Hardware lock to serialize accesses to PMU registers. Needed for the
* read/modify/write sequences.
*/
raw_spinlock_t pmu_lock;
+
+ /*
+ * When using percpu IRQs, we need a percpu dev_id. Place it here as we
+ * already have to allocate this struct per cpu.
+ */
+ struct arm_pmu *percpu_pmu;
};
struct arm_pmu {
@@ -107,7 +115,8 @@ struct arm_pmu {
struct mutex reserve_mutex;
u64 max_period;
struct platform_device *plat_device;
- struct pmu_hw_events *(*get_hw_events)(void);
+ struct pmu_hw_events __percpu *hw_events;
+ struct notifier_block hotplug_nb;
};
#define to_arm_pmu(p) (container_of(p, struct arm_pmu, pmu))
@@ -127,6 +136,27 @@ int armpmu_map_event(struct perf_event *event,
[PERF_COUNT_HW_CACHE_RESULT_MAX],
u32 raw_event_mask);
+struct pmu_probe_info {
+ unsigned int cpuid;
+ unsigned int mask;
+ int (*init)(struct arm_pmu *);
+};
+
+#define PMU_PROBE(_cpuid, _mask, _fn) \
+{ \
+ .cpuid = (_cpuid), \
+ .mask = (_mask), \
+ .init = (_fn), \
+}
+
+#define ARM_PMU_PROBE(_cpuid, _fn) \
+ PMU_PROBE(_cpuid, ARM_CPU_PART_MASK, _fn)
+
+#define ARM_PMU_XSCALE_MASK ((0xff << 24) | ARM_CPU_XSCALE_ARCH_MASK)
+
+#define XSCALE_PMU_PROBE(_version, _fn) \
+ PMU_PROBE(ARM_CPU_IMP_INTEL << 24 | _version, ARM_PMU_XSCALE_MASK, _fn)
+
#endif /* CONFIG_HW_PERF_EVENTS */
#endif /* __ARM_PMU_H__ */
diff --git a/arch/arm/include/debug/asm9260.S b/arch/arm/include/debug/asm9260.S
new file mode 100644
index 0000000..292f85b
--- /dev/null
+++ b/arch/arm/include/debug/asm9260.S
@@ -0,0 +1,29 @@
+/* Debugging macro include header
+ *
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ * Modified for ASM9260 by Oleksij Remepl <linux@rempel-privat.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ */
+
+ .macro addruart, rp, rv, tmp
+ ldr \rp, = CONFIG_DEBUG_UART_PHYS
+ ldr \rv, = CONFIG_DEBUG_UART_VIRT
+ .endm
+
+ .macro waituart,rd,rx
+ .endm
+
+ .macro senduart,rd,rx
+ str \rd, [\rx, #0x50] @ TXDATA
+ .endm
+
+ .macro busyuart,rd,rx
+1002: ldr \rd, [\rx, #0x60] @ STAT
+ tst \rd, #1 << 27 @ TXEMPTY
+ beq 1002b @ wait until transmit done
+ .endm
diff --git a/arch/arm/include/debug/renesas-scif.S b/arch/arm/include/debug/renesas-scif.S
new file mode 100644
index 0000000..97820a8
--- /dev/null
+++ b/arch/arm/include/debug/renesas-scif.S
@@ -0,0 +1,52 @@
+/*
+ * Renesas SCIF(A) debugging macro include header
+ *
+ * Based on r8a7790.S
+ *
+ * Copyright (C) 2012-2013 Renesas Electronics Corporation
+ * Copyright (C) 1994-1999 Russell King
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#define SCIF_PHYS CONFIG_DEBUG_UART_PHYS
+#define SCIF_VIRT ((SCIF_PHYS & 0x00ffffff) | 0xfd000000)
+
+#if CONFIG_DEBUG_UART_PHYS < 0xe6e00000
+/* SCIFA */
+#define FTDR 0x20
+#define FSR 0x14
+#else
+/* SCIF */
+#define FTDR 0x0c
+#define FSR 0x10
+#endif
+
+#define TDFE (1 << 5)
+#define TEND (1 << 6)
+
+ .macro addruart, rp, rv, tmp
+ ldr \rp, =SCIF_PHYS
+ ldr \rv, =SCIF_VIRT
+ .endm
+
+ .macro waituart, rd, rx
+1001: ldrh \rd, [\rx, #FSR]
+ tst \rd, #TDFE
+ beq 1001b
+ .endm
+
+ .macro senduart, rd, rx
+ strb \rd, [\rx, #FTDR]
+ ldrh \rd, [\rx, #FSR]
+ bic \rd, \rd, #TEND
+ strh \rd, [\rx, #FSR]
+ .endm
+
+ .macro busyuart, rd, rx
+1001: ldrh \rd, [\rx, #FSR]
+ tst \rd, #TEND
+ beq 1001b
+ .endm
diff --git a/arch/arm/mach-sa1100/include/mach/debug-macro.S b/arch/arm/include/debug/sa1100.S
index 530772d..a0ae4f4 100644
--- a/arch/arm/mach-sa1100/include/mach/debug-macro.S
+++ b/arch/arm/include/debug/sa1100.S
@@ -1,4 +1,4 @@
-/* arch/arm/mach-sa1100/include/mach/debug-macro.S
+/* arch/arm/include/debug/sa1100.S
*
* Debugging macro include header
*
@@ -10,7 +10,13 @@
* published by the Free Software Foundation.
*
*/
-#include <mach/hardware.h>
+
+#define UTCR3 0x0c
+#define UTDR 0x14
+#define UTSR1 0x20
+#define UTCR3_TXE 0x00000002 /* Transmit Enable */
+#define UTSR1_TBY 0x00000001 /* Transmitter BusY (read) */
+#define UTSR1_TNF 0x00000004 /* Transmit FIFO Not Full (read) */
.macro addruart, rp, rv, tmp
mrc p15, 0, \rp, c1, c0
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 38ddd9f..8dcbed5 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -82,7 +82,7 @@ obj-$(CONFIG_CPU_MOHAWK) += xscale-cp0.o
obj-$(CONFIG_CPU_PJ4) += pj4-cp0.o
obj-$(CONFIG_CPU_PJ4B) += pj4-cp0.o
obj-$(CONFIG_IWMMXT) += iwmmxt.o
-obj-$(CONFIG_PERF_EVENTS) += perf_regs.o
+obj-$(CONFIG_PERF_EVENTS) += perf_regs.o perf_callchain.o
obj-$(CONFIG_HW_PERF_EVENTS) += perf_event.o perf_event_cpu.o
AFLAGS_iwmmxt.o := -Wa,-mcpu=iwmmxt
obj-$(CONFIG_ARM_CPU_TOPOLOGY) += topology.o
diff --git a/arch/arm/kernel/bios32.c b/arch/arm/kernel/bios32.c
index 17a26c1..daaff73 100644
--- a/arch/arm/kernel/bios32.c
+++ b/arch/arm/kernel/bios32.c
@@ -18,6 +18,15 @@
static int debug_pci;
+#ifdef CONFIG_PCI_MSI
+struct msi_controller *pcibios_msi_controller(struct pci_dev *dev)
+{
+ struct pci_sys_data *sysdata = dev->bus->sysdata;
+
+ return sysdata->msi_ctrl;
+}
+#endif
+
/*
* We can't use pci_get_device() here since we are
* called from interrupt context.
@@ -360,20 +369,6 @@ void pcibios_fixup_bus(struct pci_bus *bus)
}
EXPORT_SYMBOL(pcibios_fixup_bus);
-void pcibios_add_bus(struct pci_bus *bus)
-{
- struct pci_sys_data *sys = bus->sysdata;
- if (sys->add_bus)
- sys->add_bus(bus);
-}
-
-void pcibios_remove_bus(struct pci_bus *bus)
-{
- struct pci_sys_data *sys = bus->sysdata;
- if (sys->remove_bus)
- sys->remove_bus(bus);
-}
-
/*
* Swizzle the device pin each time we cross a bridge. If a platform does
* not provide a swizzle function, we perform the standard PCI swizzling.
@@ -471,12 +466,13 @@ static void pcibios_init_hw(struct device *parent, struct hw_pci *hw,
#ifdef CONFIG_PCI_DOMAINS
sys->domain = hw->domain;
#endif
+#ifdef CONFIG_PCI_MSI
+ sys->msi_ctrl = hw->msi_ctrl;
+#endif
sys->busnr = busnr;
sys->swizzle = hw->swizzle;
sys->map_irq = hw->map_irq;
sys->align_resource = hw->align_resource;
- sys->add_bus = hw->add_bus;
- sys->remove_bus = hw->remove_bus;
INIT_LIST_HEAD(&sys->resources);
if (hw->private_data)
diff --git a/arch/arm/kernel/perf_callchain.c b/arch/arm/kernel/perf_callchain.c
new file mode 100644
index 0000000..4e02ae5
--- /dev/null
+++ b/arch/arm/kernel/perf_callchain.c
@@ -0,0 +1,136 @@
+/*
+ * ARM callchain support
+ *
+ * Copyright (C) 2009 picoChip Designs, Ltd., Jamie Iles
+ * Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com>
+ *
+ * This code is based on the ARM OProfile backtrace code.
+ */
+#include <linux/perf_event.h>
+#include <linux/uaccess.h>
+
+#include <asm/stacktrace.h>
+
+/*
+ * The registers we're interested in are at the end of the variable
+ * length saved register structure. The fp points at the end of this
+ * structure so the address of this struct is:
+ * (struct frame_tail *)(xxx->fp)-1
+ *
+ * This code has been adapted from the ARM OProfile support.
+ */
+struct frame_tail {
+ struct frame_tail __user *fp;
+ unsigned long sp;
+ unsigned long lr;
+} __attribute__((packed));
+
+/*
+ * Get the return address for a single stackframe and return a pointer to the
+ * next frame tail.
+ */
+static struct frame_tail __user *
+user_backtrace(struct frame_tail __user *tail,
+ struct perf_callchain_entry *entry)
+{
+ struct frame_tail buftail;
+ unsigned long err;
+
+ if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
+ return NULL;
+
+ pagefault_disable();
+ err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
+ pagefault_enable();
+
+ if (err)
+ return NULL;
+
+ perf_callchain_store(entry, buftail.lr);
+
+ /*
+ * Frame pointers should strictly progress back up the stack
+ * (towards higher addresses).
+ */
+ if (tail + 1 >= buftail.fp)
+ return NULL;
+
+ return buftail.fp - 1;
+}
+
+void
+perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+ struct frame_tail __user *tail;
+
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+ /* We don't support guest os callchain now */
+ return;
+ }
+
+ perf_callchain_store(entry, regs->ARM_pc);
+
+ if (!current->mm)
+ return;
+
+ tail = (struct frame_tail __user *)regs->ARM_fp - 1;
+
+ while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
+ tail && !((unsigned long)tail & 0x3))
+ tail = user_backtrace(tail, entry);
+}
+
+/*
+ * Gets called by walk_stackframe() for every stackframe. This will be called
+ * whist unwinding the stackframe and is like a subroutine return so we use
+ * the PC.
+ */
+static int
+callchain_trace(struct stackframe *fr,
+ void *data)
+{
+ struct perf_callchain_entry *entry = data;
+ perf_callchain_store(entry, fr->pc);
+ return 0;
+}
+
+void
+perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
+{
+ struct stackframe fr;
+
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+ /* We don't support guest os callchain now */
+ return;
+ }
+
+ arm_get_current_stackframe(regs, &fr);
+ walk_stackframe(&fr, callchain_trace, entry);
+}
+
+unsigned long perf_instruction_pointer(struct pt_regs *regs)
+{
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
+ return perf_guest_cbs->get_guest_ip();
+
+ return instruction_pointer(regs);
+}
+
+unsigned long perf_misc_flags(struct pt_regs *regs)
+{
+ int misc = 0;
+
+ if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
+ if (perf_guest_cbs->is_user_mode())
+ misc |= PERF_RECORD_MISC_GUEST_USER;
+ else
+ misc |= PERF_RECORD_MISC_GUEST_KERNEL;
+ } else {
+ if (user_mode(regs))
+ misc |= PERF_RECORD_MISC_USER;
+ else
+ misc |= PERF_RECORD_MISC_KERNEL;
+ }
+
+ return misc;
+}
diff --git a/arch/arm/kernel/perf_event.c b/arch/arm/kernel/perf_event.c
index 266cba4..e34934f 100644
--- a/arch/arm/kernel/perf_event.c
+++ b/arch/arm/kernel/perf_event.c
@@ -7,21 +7,18 @@
* Copyright (C) 2010 ARM Ltd., Will Deacon <will.deacon@arm.com>
*
* This code is based on the sparc64 perf event code, which is in turn based
- * on the x86 code. Callchain code is based on the ARM OProfile backtrace
- * code.
+ * on the x86 code.
*/
#define pr_fmt(fmt) "hw perfevents: " fmt
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
-#include <linux/uaccess.h>
#include <linux/irq.h>
#include <linux/irqdesc.h>
#include <asm/irq_regs.h>
#include <asm/pmu.h>
-#include <asm/stacktrace.h>
static int
armpmu_map_cache_event(const unsigned (*cache_map)
@@ -80,8 +77,12 @@ armpmu_map_event(struct perf_event *event,
u32 raw_event_mask)
{
u64 config = event->attr.config;
+ int type = event->attr.type;
- switch (event->attr.type) {
+ if (type == event->pmu->type)
+ return armpmu_map_raw_event(raw_event_mask, config);
+
+ switch (type) {
case PERF_TYPE_HARDWARE:
return armpmu_map_hw_event(event_map, config);
case PERF_TYPE_HW_CACHE:
@@ -200,7 +201,7 @@ static void
armpmu_del(struct perf_event *event, int flags)
{
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+ struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
@@ -217,7 +218,7 @@ static int
armpmu_add(struct perf_event *event, int flags)
{
struct arm_pmu *armpmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+ struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
struct hw_perf_event *hwc = &event->hw;
int idx;
int err = 0;
@@ -274,14 +275,12 @@ validate_group(struct perf_event *event)
{
struct perf_event *sibling, *leader = event->group_leader;
struct pmu_hw_events fake_pmu;
- DECLARE_BITMAP(fake_used_mask, ARMPMU_MAX_HWEVENTS);
/*
* Initialise the fake PMU. We only need to populate the
* used_mask for the purposes of validation.
*/
- memset(fake_used_mask, 0, sizeof(fake_used_mask));
- fake_pmu.used_mask = fake_used_mask;
+ memset(&fake_pmu.used_mask, 0, sizeof(fake_pmu.used_mask));
if (!validate_event(&fake_pmu, leader))
return -EINVAL;
@@ -305,17 +304,21 @@ static irqreturn_t armpmu_dispatch_irq(int irq, void *dev)
int ret;
u64 start_clock, finish_clock;
- if (irq_is_percpu(irq))
- dev = *(void **)dev;
- armpmu = dev;
+ /*
+ * we request the IRQ with a (possibly percpu) struct arm_pmu**, but
+ * the handlers expect a struct arm_pmu*. The percpu_irq framework will
+ * do any necessary shifting, we just need to perform the first
+ * dereference.
+ */
+ armpmu = *(void **)dev;
plat_device = armpmu->plat_device;
plat = dev_get_platdata(&plat_device->dev);
start_clock = sched_clock();
if (plat && plat->handle_irq)
- ret = plat->handle_irq(irq, dev, armpmu->handle_irq);
+ ret = plat->handle_irq(irq, armpmu, armpmu->handle_irq);
else
- ret = armpmu->handle_irq(irq, dev);
+ ret = armpmu->handle_irq(irq, armpmu);
finish_clock = sched_clock();
perf_sample_event_took(finish_clock - start_clock);
@@ -468,7 +471,7 @@ static int armpmu_event_init(struct perf_event *event)
static void armpmu_enable(struct pmu *pmu)
{
struct arm_pmu *armpmu = to_arm_pmu(pmu);
- struct pmu_hw_events *hw_events = armpmu->get_hw_events();
+ struct pmu_hw_events *hw_events = this_cpu_ptr(armpmu->hw_events);
int enabled = bitmap_weight(hw_events->used_mask, armpmu->num_events);
if (enabled)
@@ -533,130 +536,3 @@ int armpmu_register(struct arm_pmu *armpmu, int type)
return perf_pmu_register(&armpmu->pmu, armpmu->name, type);
}
-/*
- * Callchain handling code.
- */
-
-/*
- * The registers we're interested in are at the end of the variable
- * length saved register structure. The fp points at the end of this
- * structure so the address of this struct is:
- * (struct frame_tail *)(xxx->fp)-1
- *
- * This code has been adapted from the ARM OProfile support.
- */
-struct frame_tail {
- struct frame_tail __user *fp;
- unsigned long sp;
- unsigned long lr;
-} __attribute__((packed));
-
-/*
- * Get the return address for a single stackframe and return a pointer to the
- * next frame tail.
- */
-static struct frame_tail __user *
-user_backtrace(struct frame_tail __user *tail,
- struct perf_callchain_entry *entry)
-{
- struct frame_tail buftail;
- unsigned long err;
-
- if (!access_ok(VERIFY_READ, tail, sizeof(buftail)))
- return NULL;
-
- pagefault_disable();
- err = __copy_from_user_inatomic(&buftail, tail, sizeof(buftail));
- pagefault_enable();
-
- if (err)
- return NULL;
-
- perf_callchain_store(entry, buftail.lr);
-
- /*
- * Frame pointers should strictly progress back up the stack
- * (towards higher addresses).
- */
- if (tail + 1 >= buftail.fp)
- return NULL;
-
- return buftail.fp - 1;
-}
-
-void
-perf_callchain_user(struct perf_callchain_entry *entry, struct pt_regs *regs)
-{
- struct frame_tail __user *tail;
-
- if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
- /* We don't support guest os callchain now */
- return;
- }
-
- perf_callchain_store(entry, regs->ARM_pc);
-
- if (!current->mm)
- return;
-
- tail = (struct frame_tail __user *)regs->ARM_fp - 1;
-
- while ((entry->nr < PERF_MAX_STACK_DEPTH) &&
- tail && !((unsigned long)tail & 0x3))
- tail = user_backtrace(tail, entry);
-}
-
-/*
- * Gets called by walk_stackframe() for every stackframe. This will be called
- * whist unwinding the stackframe and is like a subroutine return so we use
- * the PC.
- */
-static int
-callchain_trace(struct stackframe *fr,
- void *data)
-{
- struct perf_callchain_entry *entry = data;
- perf_callchain_store(entry, fr->pc);
- return 0;
-}
-
-void
-perf_callchain_kernel(struct perf_callchain_entry *entry, struct pt_regs *regs)
-{
- struct stackframe fr;
-
- if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
- /* We don't support guest os callchain now */
- return;
- }
-
- arm_get_current_stackframe(regs, &fr);
- walk_stackframe(&fr, callchain_trace, entry);
-}
-
-unsigned long perf_instruction_pointer(struct pt_regs *regs)
-{
- if (perf_guest_cbs && perf_guest_cbs->is_in_guest())
- return perf_guest_cbs->get_guest_ip();
-
- return instruction_pointer(regs);
-}
-
-unsigned long perf_misc_flags(struct pt_regs *regs)
-{
- int misc = 0;
-
- if (perf_guest_cbs && perf_guest_cbs->is_in_guest()) {
- if (perf_guest_cbs->is_user_mode())
- misc |= PERF_RECORD_MISC_GUEST_USER;
- else
- misc |= PERF_RECORD_MISC_GUEST_KERNEL;
- } else {
- if (user_mode(regs))
- misc |= PERF_RECORD_MISC_USER;
- else
- misc |= PERF_RECORD_MISC_KERNEL;
- }
-
- return misc;
-}
diff --git a/arch/arm/kernel/perf_event_cpu.c b/arch/arm/kernel/perf_event_cpu.c
index eb2c4d55..dd9acc9 100644
--- a/arch/arm/kernel/perf_event_cpu.c
+++ b/arch/arm/kernel/perf_event_cpu.c
@@ -35,11 +35,6 @@
/* Set at runtime when we know what CPU type we are. */
static struct arm_pmu *cpu_pmu;
-static DEFINE_PER_CPU(struct arm_pmu *, percpu_pmu);
-static DEFINE_PER_CPU(struct perf_event * [ARMPMU_MAX_HWEVENTS], hw_events);
-static DEFINE_PER_CPU(unsigned long [BITS_TO_LONGS(ARMPMU_MAX_HWEVENTS)], used_mask);
-static DEFINE_PER_CPU(struct pmu_hw_events, cpu_hw_events);
-
/*
* Despite the names, these two functions are CPU-specific and are used
* by the OProfile/perf code.
@@ -69,11 +64,6 @@ EXPORT_SYMBOL_GPL(perf_num_counters);
#include "perf_event_v6.c"
#include "perf_event_v7.c"
-static struct pmu_hw_events *cpu_pmu_get_cpu_events(void)
-{
- return this_cpu_ptr(&cpu_hw_events);
-}
-
static void cpu_pmu_enable_percpu_irq(void *data)
{
int irq = *(int *)data;
@@ -92,20 +82,21 @@ static void cpu_pmu_free_irq(struct arm_pmu *cpu_pmu)
{
int i, irq, irqs;
struct platform_device *pmu_device = cpu_pmu->plat_device;
+ struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
irqs = min(pmu_device->num_resources, num_possible_cpus());
irq = platform_get_irq(pmu_device, 0);
if (irq >= 0 && irq_is_percpu(irq)) {
on_each_cpu(cpu_pmu_disable_percpu_irq, &irq, 1);
- free_percpu_irq(irq, &percpu_pmu);
+ free_percpu_irq(irq, &hw_events->percpu_pmu);
} else {
for (i = 0; i < irqs; ++i) {
if (!cpumask_test_and_clear_cpu(i, &cpu_pmu->active_irqs))
continue;
irq = platform_get_irq(pmu_device, i);
if (irq >= 0)
- free_irq(irq, cpu_pmu);
+ free_irq(irq, per_cpu_ptr(&hw_events->percpu_pmu, i));
}
}
}
@@ -114,19 +105,21 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
{
int i, err, irq, irqs;
struct platform_device *pmu_device = cpu_pmu->plat_device;
+ struct pmu_hw_events __percpu *hw_events = cpu_pmu->hw_events;
if (!pmu_device)
return -ENODEV;
irqs = min(pmu_device->num_resources, num_possible_cpus());
if (irqs < 1) {
- printk_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n");
+ pr_warn_once("perf/ARM: No irqs for PMU defined, sampling events not supported\n");
return 0;
}
irq = platform_get_irq(pmu_device, 0);
if (irq >= 0 && irq_is_percpu(irq)) {
- err = request_percpu_irq(irq, handler, "arm-pmu", &percpu_pmu);
+ err = request_percpu_irq(irq, handler, "arm-pmu",
+ &hw_events->percpu_pmu);
if (err) {
pr_err("unable to request IRQ%d for ARM PMU counters\n",
irq);
@@ -153,7 +146,7 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
err = request_irq(irq, handler,
IRQF_NOBALANCING | IRQF_NO_THREAD, "arm-pmu",
- cpu_pmu);
+ per_cpu_ptr(&hw_events->percpu_pmu, i));
if (err) {
pr_err("unable to request IRQ%d for ARM PMU counters\n",
irq);
@@ -167,18 +160,50 @@ static int cpu_pmu_request_irq(struct arm_pmu *cpu_pmu, irq_handler_t handler)
return 0;
}
-static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
+/*
+ * PMU hardware loses all context when a CPU goes offline.
+ * When a CPU is hotplugged back in, since some hardware registers are
+ * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
+ * junk values out of them.
+ */
+static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
+ void *hcpu)
+{
+ struct arm_pmu *pmu = container_of(b, struct arm_pmu, hotplug_nb);
+
+ if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
+ return NOTIFY_DONE;
+
+ if (pmu->reset)
+ pmu->reset(pmu);
+ else
+ return NOTIFY_DONE;
+
+ return NOTIFY_OK;
+}
+
+static int cpu_pmu_init(struct arm_pmu *cpu_pmu)
{
+ int err;
int cpu;
+ struct pmu_hw_events __percpu *cpu_hw_events;
+
+ cpu_hw_events = alloc_percpu(struct pmu_hw_events);
+ if (!cpu_hw_events)
+ return -ENOMEM;
+
+ cpu_pmu->hotplug_nb.notifier_call = cpu_pmu_notify;
+ err = register_cpu_notifier(&cpu_pmu->hotplug_nb);
+ if (err)
+ goto out_hw_events;
+
for_each_possible_cpu(cpu) {
- struct pmu_hw_events *events = &per_cpu(cpu_hw_events, cpu);
- events->events = per_cpu(hw_events, cpu);
- events->used_mask = per_cpu(used_mask, cpu);
+ struct pmu_hw_events *events = per_cpu_ptr(cpu_hw_events, cpu);
raw_spin_lock_init(&events->pmu_lock);
- per_cpu(percpu_pmu, cpu) = cpu_pmu;
+ events->percpu_pmu = cpu_pmu;
}
- cpu_pmu->get_hw_events = cpu_pmu_get_cpu_events;
+ cpu_pmu->hw_events = cpu_hw_events;
cpu_pmu->request_irq = cpu_pmu_request_irq;
cpu_pmu->free_irq = cpu_pmu_free_irq;
@@ -189,31 +214,19 @@ static void cpu_pmu_init(struct arm_pmu *cpu_pmu)
/* If no interrupts available, set the corresponding capability flag */
if (!platform_get_irq(cpu_pmu->plat_device, 0))
cpu_pmu->pmu.capabilities |= PERF_PMU_CAP_NO_INTERRUPT;
-}
-
-/*
- * PMU hardware loses all context when a CPU goes offline.
- * When a CPU is hotplugged back in, since some hardware registers are
- * UNKNOWN at reset, the PMU must be explicitly reset to avoid reading
- * junk values out of them.
- */
-static int cpu_pmu_notify(struct notifier_block *b, unsigned long action,
- void *hcpu)
-{
- if ((action & ~CPU_TASKS_FROZEN) != CPU_STARTING)
- return NOTIFY_DONE;
- if (cpu_pmu && cpu_pmu->reset)
- cpu_pmu->reset(cpu_pmu);
- else
- return NOTIFY_DONE;
+ return 0;
- return NOTIFY_OK;
+out_hw_events:
+ free_percpu(cpu_hw_events);
+ return err;
}
-static struct notifier_block cpu_pmu_hotplug_notifier = {
- .notifier_call = cpu_pmu_notify,
-};
+static void cpu_pmu_destroy(struct arm_pmu *cpu_pmu)
+{
+ unregister_cpu_notifier(&cpu_pmu->hotplug_nb);
+ free_percpu(cpu_pmu->hw_events);
+}
/*
* PMU platform driver and devicetree bindings.
@@ -241,48 +254,34 @@ static struct platform_device_id cpu_pmu_plat_device_ids[] = {
{},
};
+static const struct pmu_probe_info pmu_probe_table[] = {
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM1136, armv6_1136_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM1156, armv6_1156_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM1176, armv6_1176_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_ARM11MPCORE, armv6mpcore_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A8, armv7_a8_pmu_init),
+ ARM_PMU_PROBE(ARM_CPU_PART_CORTEX_A9, armv7_a9_pmu_init),
+ XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V1, xscale1pmu_init),
+ XSCALE_PMU_PROBE(ARM_CPU_XSCALE_ARCH_V2, xscale2pmu_init),
+ { /* sentinel value */ }
+};
+
/*
* CPU PMU identification and probing.
*/
static int probe_current_pmu(struct arm_pmu *pmu)
{
int cpu = get_cpu();
+ unsigned int cpuid = read_cpuid_id();
int ret = -ENODEV;
+ const struct pmu_probe_info *info;
pr_info("probing PMU on CPU %d\n", cpu);
- switch (read_cpuid_part()) {
- /* ARM Ltd CPUs. */
- case ARM_CPU_PART_ARM1136:
- ret = armv6_1136_pmu_init(pmu);
- break;
- case ARM_CPU_PART_ARM1156:
- ret = armv6_1156_pmu_init(pmu);
- break;
- case ARM_CPU_PART_ARM1176:
- ret = armv6_1176_pmu_init(pmu);
- break;
- case ARM_CPU_PART_ARM11MPCORE:
- ret = armv6mpcore_pmu_init(pmu);
- break;
- case ARM_CPU_PART_CORTEX_A8:
- ret = armv7_a8_pmu_init(pmu);
- break;
- case ARM_CPU_PART_CORTEX_A9:
- ret = armv7_a9_pmu_init(pmu);
- break;
-
- default:
- if (read_cpuid_implementor() == ARM_CPU_IMP_INTEL) {
- switch (xscale_cpu_arch_version()) {
- case ARM_CPU_XSCALE_ARCH_V1:
- ret = xscale1pmu_init(pmu);
- break;
- case ARM_CPU_XSCALE_ARCH_V2:
- ret = xscale2pmu_init(pmu);
- break;
- }
- }
+ for (info = pmu_probe_table; info->init != NULL; info++) {
+ if ((cpuid & info->mask) != info->cpuid)
+ continue;
+ ret = info->init(pmu);
break;
}
@@ -299,13 +298,13 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
int ret = -ENODEV;
if (cpu_pmu) {
- pr_info("attempt to register multiple PMU devices!");
+ pr_info("attempt to register multiple PMU devices!\n");
return -ENOSPC;
}
pmu = kzalloc(sizeof(struct arm_pmu), GFP_KERNEL);
if (!pmu) {
- pr_info("failed to allocate PMU device!");
+ pr_info("failed to allocate PMU device!\n");
return -ENOMEM;
}
@@ -320,18 +319,24 @@ static int cpu_pmu_device_probe(struct platform_device *pdev)
}
if (ret) {
- pr_info("failed to probe PMU!");
+ pr_info("failed to probe PMU!\n");
goto out_free;
}
- cpu_pmu_init(cpu_pmu);
- ret = armpmu_register(cpu_pmu, PERF_TYPE_RAW);
+ ret = cpu_pmu_init(cpu_pmu);
+ if (ret)
+ goto out_free;
- if (!ret)
- return 0;
+ ret = armpmu_register(cpu_pmu, -1);
+ if (ret)
+ goto out_destroy;
+ return 0;
+
+out_destroy:
+ cpu_pmu_destroy(cpu_pmu);
out_free:
- pr_info("failed to register PMU devices!");
+ pr_info("failed to register PMU devices!\n");
kfree(pmu);
return ret;
}
@@ -348,16 +353,6 @@ static struct platform_driver cpu_pmu_driver = {
static int __init register_pmu_driver(void)
{
- int err;
-
- err = register_cpu_notifier(&cpu_pmu_hotplug_notifier);
- if (err)
- return err;
-
- err = platform_driver_register(&cpu_pmu_driver);
- if (err)
- unregister_cpu_notifier(&cpu_pmu_hotplug_notifier);
-
- return err;
+ return platform_driver_register(&cpu_pmu_driver);
}
device_initcall(register_pmu_driver);
diff --git a/arch/arm/kernel/perf_event_v6.c b/arch/arm/kernel/perf_event_v6.c
index abfeb04..f2ffd5c 100644
--- a/arch/arm/kernel/perf_event_v6.c
+++ b/arch/arm/kernel/perf_event_v6.c
@@ -262,7 +262,7 @@ static void armv6pmu_enable_event(struct perf_event *event)
unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
if (ARMV6_CYCLE_COUNTER == idx) {
@@ -300,7 +300,7 @@ armv6pmu_handle_irq(int irq_num,
unsigned long pmcr = armv6_pmcr_read();
struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
- struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs;
int idx;
@@ -356,7 +356,7 @@ armv6pmu_handle_irq(int irq_num,
static void armv6pmu_start(struct arm_pmu *cpu_pmu)
{
unsigned long flags, val;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
@@ -368,7 +368,7 @@ static void armv6pmu_start(struct arm_pmu *cpu_pmu)
static void armv6pmu_stop(struct arm_pmu *cpu_pmu)
{
unsigned long flags, val;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = armv6_pmcr_read();
@@ -409,7 +409,7 @@ static void armv6pmu_disable_event(struct perf_event *event)
unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
if (ARMV6_CYCLE_COUNTER == idx) {
@@ -444,7 +444,7 @@ static void armv6mpcore_pmu_disable_event(struct perf_event *event)
unsigned long val, mask, flags, evt = 0;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
if (ARMV6_CYCLE_COUNTER == idx) {
diff --git a/arch/arm/kernel/perf_event_v7.c b/arch/arm/kernel/perf_event_v7.c
index 116758b..8993770 100644
--- a/arch/arm/kernel/perf_event_v7.c
+++ b/arch/arm/kernel/perf_event_v7.c
@@ -564,13 +564,11 @@ static inline int armv7_pmnc_counter_has_overflowed(u32 pmnc, int idx)
return pmnc & BIT(ARMV7_IDX_TO_COUNTER(idx));
}
-static inline int armv7_pmnc_select_counter(int idx)
+static inline void armv7_pmnc_select_counter(int idx)
{
u32 counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 5" : : "r" (counter));
isb();
-
- return idx;
}
static inline u32 armv7pmu_read_counter(struct perf_event *event)
@@ -580,13 +578,15 @@ static inline u32 armv7pmu_read_counter(struct perf_event *event)
int idx = hwc->idx;
u32 value = 0;
- if (!armv7_pmnc_counter_valid(cpu_pmu, idx))
+ if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) {
pr_err("CPU%u reading wrong counter %d\n",
smp_processor_id(), idx);
- else if (idx == ARMV7_IDX_CYCLE_COUNTER)
+ } else if (idx == ARMV7_IDX_CYCLE_COUNTER) {
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (value));
- else if (armv7_pmnc_select_counter(idx) == idx)
+ } else {
+ armv7_pmnc_select_counter(idx);
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (value));
+ }
return value;
}
@@ -597,45 +597,43 @@ static inline void armv7pmu_write_counter(struct perf_event *event, u32 value)
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
- if (!armv7_pmnc_counter_valid(cpu_pmu, idx))
+ if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) {
pr_err("CPU%u writing wrong counter %d\n",
smp_processor_id(), idx);
- else if (idx == ARMV7_IDX_CYCLE_COUNTER)
+ } else if (idx == ARMV7_IDX_CYCLE_COUNTER) {
asm volatile("mcr p15, 0, %0, c9, c13, 0" : : "r" (value));
- else if (armv7_pmnc_select_counter(idx) == idx)
+ } else {
+ armv7_pmnc_select_counter(idx);
asm volatile("mcr p15, 0, %0, c9, c13, 2" : : "r" (value));
+ }
}
static inline void armv7_pmnc_write_evtsel(int idx, u32 val)
{
- if (armv7_pmnc_select_counter(idx) == idx) {
- val &= ARMV7_EVTYPE_MASK;
- asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
- }
+ armv7_pmnc_select_counter(idx);
+ val &= ARMV7_EVTYPE_MASK;
+ asm volatile("mcr p15, 0, %0, c9, c13, 1" : : "r" (val));
}
-static inline int armv7_pmnc_enable_counter(int idx)
+static inline void armv7_pmnc_enable_counter(int idx)
{
u32 counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 1" : : "r" (BIT(counter)));
- return idx;
}
-static inline int armv7_pmnc_disable_counter(int idx)
+static inline void armv7_pmnc_disable_counter(int idx)
{
u32 counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c12, 2" : : "r" (BIT(counter)));
- return idx;
}
-static inline int armv7_pmnc_enable_intens(int idx)
+static inline void armv7_pmnc_enable_intens(int idx)
{
u32 counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c14, 1" : : "r" (BIT(counter)));
- return idx;
}
-static inline int armv7_pmnc_disable_intens(int idx)
+static inline void armv7_pmnc_disable_intens(int idx)
{
u32 counter = ARMV7_IDX_TO_COUNTER(idx);
asm volatile("mcr p15, 0, %0, c9, c14, 2" : : "r" (BIT(counter)));
@@ -643,8 +641,6 @@ static inline int armv7_pmnc_disable_intens(int idx)
/* Clear the overflow flag in case an interrupt is pending. */
asm volatile("mcr p15, 0, %0, c9, c12, 3" : : "r" (BIT(counter)));
isb();
-
- return idx;
}
static inline u32 armv7_pmnc_getreset_flags(void)
@@ -667,34 +663,34 @@ static void armv7_pmnc_dump_regs(struct arm_pmu *cpu_pmu)
u32 val;
unsigned int cnt;
- printk(KERN_INFO "PMNC registers dump:\n");
+ pr_info("PMNC registers dump:\n");
asm volatile("mrc p15, 0, %0, c9, c12, 0" : "=r" (val));
- printk(KERN_INFO "PMNC =0x%08x\n", val);
+ pr_info("PMNC =0x%08x\n", val);
asm volatile("mrc p15, 0, %0, c9, c12, 1" : "=r" (val));
- printk(KERN_INFO "CNTENS=0x%08x\n", val);
+ pr_info("CNTENS=0x%08x\n", val);
asm volatile("mrc p15, 0, %0, c9, c14, 1" : "=r" (val));
- printk(KERN_INFO "INTENS=0x%08x\n", val);
+ pr_info("INTENS=0x%08x\n", val);
asm volatile("mrc p15, 0, %0, c9, c12, 3" : "=r" (val));
- printk(KERN_INFO "FLAGS =0x%08x\n", val);
+ pr_info("FLAGS =0x%08x\n", val);
asm volatile("mrc p15, 0, %0, c9, c12, 5" : "=r" (val));
- printk(KERN_INFO "SELECT=0x%08x\n", val);
+ pr_info("SELECT=0x%08x\n", val);
asm volatile("mrc p15, 0, %0, c9, c13, 0" : "=r" (val));
- printk(KERN_INFO "CCNT =0x%08x\n", val);
+ pr_info("CCNT =0x%08x\n", val);
for (cnt = ARMV7_IDX_COUNTER0;
cnt <= ARMV7_IDX_COUNTER_LAST(cpu_pmu); cnt++) {
armv7_pmnc_select_counter(cnt);
asm volatile("mrc p15, 0, %0, c9, c13, 2" : "=r" (val));
- printk(KERN_INFO "CNT[%d] count =0x%08x\n",
+ pr_info("CNT[%d] count =0x%08x\n",
ARMV7_IDX_TO_COUNTER(cnt), val);
asm volatile("mrc p15, 0, %0, c9, c13, 1" : "=r" (val));
- printk(KERN_INFO "CNT[%d] evtsel=0x%08x\n",
+ pr_info("CNT[%d] evtsel=0x%08x\n",
ARMV7_IDX_TO_COUNTER(cnt), val);
}
}
@@ -705,7 +701,7 @@ static void armv7pmu_enable_event(struct perf_event *event)
unsigned long flags;
struct hw_perf_event *hwc = &event->hw;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) {
@@ -751,7 +747,7 @@ static void armv7pmu_disable_event(struct perf_event *event)
unsigned long flags;
struct hw_perf_event *hwc = &event->hw;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
if (!armv7_pmnc_counter_valid(cpu_pmu, idx)) {
@@ -783,7 +779,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
u32 pmnc;
struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
- struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs;
int idx;
@@ -843,7 +839,7 @@ static irqreturn_t armv7pmu_handle_irq(int irq_num, void *dev)
static void armv7pmu_start(struct arm_pmu *cpu_pmu)
{
unsigned long flags;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Enable all counters */
@@ -854,7 +850,7 @@ static void armv7pmu_start(struct arm_pmu *cpu_pmu)
static void armv7pmu_stop(struct arm_pmu *cpu_pmu)
{
unsigned long flags;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
/* Disable all counters */
@@ -1287,7 +1283,7 @@ static void krait_pmu_disable_event(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
/* Disable counter and interrupt */
raw_spin_lock_irqsave(&events->pmu_lock, flags);
@@ -1313,7 +1309,7 @@ static void krait_pmu_enable_event(struct perf_event *event)
struct hw_perf_event *hwc = &event->hw;
int idx = hwc->idx;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
/*
* Enable counter and interrupt, and set the counter to count
diff --git a/arch/arm/kernel/perf_event_xscale.c b/arch/arm/kernel/perf_event_xscale.c
index 08da0af..8af9f1f 100644
--- a/arch/arm/kernel/perf_event_xscale.c
+++ b/arch/arm/kernel/perf_event_xscale.c
@@ -138,7 +138,7 @@ xscale1pmu_handle_irq(int irq_num, void *dev)
unsigned long pmnc;
struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
- struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs;
int idx;
@@ -198,7 +198,7 @@ static void xscale1pmu_enable_event(struct perf_event *event)
unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
switch (idx) {
@@ -234,7 +234,7 @@ static void xscale1pmu_disable_event(struct perf_event *event)
unsigned long val, mask, evt, flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
switch (idx) {
@@ -287,7 +287,7 @@ xscale1pmu_get_event_idx(struct pmu_hw_events *cpuc,
static void xscale1pmu_start(struct arm_pmu *cpu_pmu)
{
unsigned long flags, val;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale1pmu_read_pmnc();
@@ -299,7 +299,7 @@ static void xscale1pmu_start(struct arm_pmu *cpu_pmu)
static void xscale1pmu_stop(struct arm_pmu *cpu_pmu)
{
unsigned long flags, val;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale1pmu_read_pmnc();
@@ -485,7 +485,7 @@ xscale2pmu_handle_irq(int irq_num, void *dev)
unsigned long pmnc, of_flags;
struct perf_sample_data data;
struct arm_pmu *cpu_pmu = (struct arm_pmu *)dev;
- struct pmu_hw_events *cpuc = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *cpuc = this_cpu_ptr(cpu_pmu->hw_events);
struct pt_regs *regs;
int idx;
@@ -539,7 +539,7 @@ static void xscale2pmu_enable_event(struct perf_event *event)
unsigned long flags, ien, evtsel;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
ien = xscale2pmu_read_int_enable();
@@ -585,7 +585,7 @@ static void xscale2pmu_disable_event(struct perf_event *event)
unsigned long flags, ien, evtsel, of_flags;
struct arm_pmu *cpu_pmu = to_arm_pmu(event->pmu);
struct hw_perf_event *hwc = &event->hw;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
int idx = hwc->idx;
ien = xscale2pmu_read_int_enable();
@@ -651,7 +651,7 @@ out:
static void xscale2pmu_start(struct arm_pmu *cpu_pmu)
{
unsigned long flags, val;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale2pmu_read_pmnc() & ~XSCALE_PMU_CNT64;
@@ -663,7 +663,7 @@ static void xscale2pmu_start(struct arm_pmu *cpu_pmu)
static void xscale2pmu_stop(struct arm_pmu *cpu_pmu)
{
unsigned long flags, val;
- struct pmu_hw_events *events = cpu_pmu->get_hw_events();
+ struct pmu_hw_events *events = this_cpu_ptr(cpu_pmu->hw_events);
raw_spin_lock_irqsave(&events->pmu_lock, flags);
val = xscale2pmu_read_pmnc();
diff --git a/arch/arm/mach-asm9260/Kconfig b/arch/arm/mach-asm9260/Kconfig
new file mode 100644
index 0000000..8423be7
--- /dev/null
+++ b/arch/arm/mach-asm9260/Kconfig
@@ -0,0 +1,6 @@
+config MACH_ASM9260
+ bool "Alphascale ASM9260"
+ depends on ARCH_MULTI_V5
+ select CPU_ARM926T
+ help
+ Support for Alphascale ASM9260 based platform.
diff --git a/arch/arm/mach-at91/Kconfig b/arch/arm/mach-at91/Kconfig
index 0e6d548..2395c68 100644
--- a/arch/arm/mach-at91/Kconfig
+++ b/arch/arm/mach-at91/Kconfig
@@ -15,27 +15,10 @@ config HAVE_AT91_DBGU1
config HAVE_AT91_DBGU2
bool
-config AT91_USE_OLD_CLK
- bool
-
-config AT91_PMC_UNIT
- bool
- default !ARCH_AT91X40
-
config COMMON_CLK_AT91
bool
- default AT91_PMC_UNIT && USE_OF && !AT91_USE_OLD_CLK
select COMMON_CLK
-config OLD_CLK_AT91
- bool
- default AT91_PMC_UNIT && AT91_USE_OLD_CLK
-
-config OLD_IRQ_AT91
- bool
- select MULTI_IRQ_HANDLER
- select SPARSE_IRQ
-
config HAVE_AT91_SMD
bool
@@ -44,20 +27,22 @@ config HAVE_AT91_H32MX
config SOC_AT91SAM9
bool
- select ATMEL_AIC_IRQ if !OLD_IRQ_AT91
+ select ATMEL_AIC_IRQ
+ select COMMON_CLK_AT91
select CPU_ARM926T
select GENERIC_CLOCKEVENTS
- select MEMORY if USE_OF
- select ATMEL_SDRAMC if USE_OF
+ select MEMORY
+ select ATMEL_SDRAMC
config SOC_SAMA5
bool
select ATMEL_AIC5_IRQ
+ select COMMON_CLK_AT91
select CPU_V7
select GENERIC_CLOCKEVENTS
- select USE_OF
select MEMORY
select ATMEL_SDRAMC
+ select PHYLIB if NETDEVICES
menu "Atmel AT91 System-on-Chip"
@@ -65,16 +50,6 @@ choice
prompt "Core type"
-config ARCH_AT91X40
- bool "ARM7 AT91X40"
- depends on !MMU
- select CPU_ARM7TDMI
- select ARCH_USES_GETTIMEOFFSET
- select OLD_IRQ_AT91
-
- help
- Select this if you are using one of Atmel's AT91X40 SoC.
-
config SOC_SAM_V4_V5
bool "ARM9 AT91SAM9/AT91RM9200"
help
@@ -122,7 +97,8 @@ endif
if SOC_SAM_V4_V5
config SOC_AT91RM9200
bool "AT91RM9200"
- select ATMEL_AIC_IRQ if !OLD_IRQ_AT91
+ select ATMEL_AIC_IRQ
+ select COMMON_CLK_AT91
select CPU_ARM920T
select GENERIC_CLOCKEVENTS
select HAVE_AT91_DBGU0
@@ -198,37 +174,11 @@ config SOC_AT91SAM9N12
# ----------------------------------------------------------
endif # SOC_SAM_V4_V5
-
-if SOC_SAM_V4_V5 || ARCH_AT91X40
-source arch/arm/mach-at91/Kconfig.non_dt
-endif
-
-comment "Generic Board Type"
-
config MACH_AT91RM9200_DT
- bool "Atmel AT91RM9200 Evaluation Kits with device-tree support"
- depends on SOC_AT91RM9200
- select USE_OF
- help
- Select this if you want to experiment device-tree with
- an Atmel RM9200 Evaluation Kit.
+ def_bool SOC_AT91RM9200
config MACH_AT91SAM9_DT
- bool "Atmel AT91SAM Evaluation Kits with device-tree support"
- depends on SOC_AT91SAM9
- select USE_OF
- help
- Select this if you want to experiment device-tree with
- an Atmel Evaluation Kit.
-
-config MACH_SAMA5_DT
- bool "Atmel SAMA5 Evaluation Kits with device-tree support"
- depends on SOC_SAMA5
- select USE_OF
- select PHYLIB if NETDEVICES
- help
- Select this if you want to experiment device-tree with
- an Atmel Evaluation Kit.
+ def_bool SOC_AT91SAM9
# ----------------------------------------------------------
@@ -251,7 +201,7 @@ config AT91_TIMER_HZ
int "Kernel HZ (jiffies per second)"
range 32 1024
depends on ARCH_AT91
- default "128" if ARCH_AT91RM9200
+ default "128" if SOC_AT91RM9200
default "100"
help
On AT91rm9200 chips where you're using a system clock derived
diff --git a/arch/arm/mach-at91/Kconfig.non_dt b/arch/arm/mach-at91/Kconfig.non_dt
deleted file mode 100644
index d8e8821..0000000
--- a/arch/arm/mach-at91/Kconfig.non_dt
+++ /dev/null
@@ -1,344 +0,0 @@
-menu "Atmel Non-DT world"
-
-config HAVE_AT91_DATAFLASH_CARD
- bool
-
-choice
- prompt "Atmel AT91 Processor Devices for non DT boards"
- depends on !ARCH_AT91X40
-
-config ARCH_AT91_NONE
- bool "None"
-
-config ARCH_AT91RM9200
- bool "AT91RM9200"
- select SOC_AT91RM9200
- select AT91_USE_OLD_CLK
- select OLD_IRQ_AT91
-
-config ARCH_AT91SAM9260
- bool "AT91SAM9260 or AT91SAM9XE or AT91SAM9G20"
- select SOC_AT91SAM9260
- select AT91_USE_OLD_CLK
- select OLD_IRQ_AT91
-
-config ARCH_AT91SAM9261
- bool "AT91SAM9261 or AT91SAM9G10"
- select SOC_AT91SAM9261
- select AT91_USE_OLD_CLK
- select OLD_IRQ_AT91
-
-config ARCH_AT91SAM9263
- bool "AT91SAM9263"
- select SOC_AT91SAM9263
- select AT91_USE_OLD_CLK
- select OLD_IRQ_AT91
-
-config ARCH_AT91SAM9RL
- bool "AT91SAM9RL"
- select SOC_AT91SAM9RL
- select AT91_USE_OLD_CLK
- select OLD_IRQ_AT91
-
-config ARCH_AT91SAM9G45
- bool "AT91SAM9G45"
- select SOC_AT91SAM9G45
- select AT91_USE_OLD_CLK
- select OLD_IRQ_AT91
-
-endchoice
-
-config ARCH_AT91SAM9G20
- bool
- select ARCH_AT91SAM9260
-
-config ARCH_AT91SAM9G10
- bool
- select ARCH_AT91SAM9261
-
-# ----------------------------------------------------------
-
-if ARCH_AT91RM9200
-
-comment "AT91RM9200 Board Type"
-
-config MACH_ONEARM
- bool "Ajeco 1ARM Single Board Computer"
- help
- Select this if you are using Ajeco's 1ARM Single Board Computer.
- <http://www.ajeco.fi/>
-
-config MACH_AT91RM9200EK
- bool "Atmel AT91RM9200-EK Evaluation Kit"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Atmel's AT91RM9200-EK Evaluation Kit.
- <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3507>
-
-config MACH_CSB337
- bool "Cogent CSB337"
- help
- Select this if you are using Cogent's CSB337 board.
- <http://www.cogcomp.com/csb_csb337.htm>
-
-config MACH_CSB637
- bool "Cogent CSB637"
- help
- Select this if you are using Cogent's CSB637 board.
- <http://www.cogcomp.com/csb_csb637.htm>
-
-config MACH_CARMEVA
- bool "Conitec ARM&EVA"
- help
- Select this if you are using Conitec's AT91RM9200-MCU-Module.
- <http://www.conitec.net/english/linuxboard.php>
-
-config MACH_ATEB9200
- bool "Embest ATEB9200"
- help
- Select this if you are using Embest's ATEB9200 board.
- <http://www.embedinfo.com/english/product/ATEB9200.asp>
-
-config MACH_KB9200
- bool "KwikByte KB920x"
- help
- Select this if you are using KwikByte's KB920x board.
- <http://www.kwikbyte.com/KB9202.html>
-
-config MACH_PICOTUX2XX
- bool "picotux 200"
- help
- Select this if you are using a picotux 200.
- <http://www.picotux.com/>
-
-config MACH_KAFA
- bool "Sperry-Sun KAFA board"
- help
- Select this if you are using Sperry-Sun's KAFA board.
-
-config MACH_ECBAT91
- bool "emQbit ECB_AT91 SBC"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using emQbit's ECB_AT91 board.
- <http://wiki.emqbit.com/free-ecb-at91>
-
-config MACH_YL9200
- bool "ucDragon YL-9200"
- help
- Select this if you are using the ucDragon YL-9200 board.
-
-config MACH_CPUAT91
- bool "Eukrea CPUAT91"
- help
- Select this if you are using the Eukrea Electromatique's
- CPUAT91 board <http://www.eukrea.com/>.
-
-config MACH_ECO920
- bool "eco920"
- help
- Select this if you are using the eco920 board
-endif
-
-# ----------------------------------------------------------
-
-if ARCH_AT91SAM9260
-
-comment "AT91SAM9260 Variants"
-
-comment "AT91SAM9260 / AT91SAM9XE Board Type"
-
-config MACH_AT91SAM9260EK
- bool "Atmel AT91SAM9260-EK / AT91SAM9XE Evaluation Kit"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Atmel's AT91SAM9260-EK or AT91SAM9XE Evaluation Kit
- <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3933>
-
-config MACH_CAM60
- bool "KwikByte KB9260 (CAM60) board"
- help
- Select this if you are using KwikByte's KB9260 (CAM60) board based on the Atmel AT91SAM9260.
- <http://www.kwikbyte.com/KB9260.html>
-
-config MACH_SAM9_L9260
- bool "Olimex SAM9-L9260 board"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Olimex's SAM9-L9260 board based on the Atmel AT91SAM9260.
- <http://www.olimex.com/dev/sam9-L9260.html>
-
-config MACH_AFEB9260
- bool "Custom afeb9260 board v1"
- help
- Select this if you are using custom afeb9260 board based on
- open hardware design. Select this for revision 1 of the board.
- <svn://194.85.238.22/home/users/george/svn/arm9eb>
- <http://groups.google.com/group/arm9fpga-evolution-board>
-
-config MACH_CPU9260
- bool "Eukrea CPU9260 board"
- help
- Select this if you are using a Eukrea Electromatique's
- CPU9260 Board <http://www.eukrea.com/>
-
-config MACH_FLEXIBITY
- bool "Flexibity Connect board"
- help
- Select this if you are using Flexibity Connect board
- <http://www.flexibity.com>
-
-comment "AT91SAM9G20 Board Type"
-
-config MACH_AT91SAM9G20EK
- bool "Atmel AT91SAM9G20-EK Evaluation Kit"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Atmel's AT91SAM9G20-EK Evaluation Kit
- that embeds only one SD/MMC slot.
-
-config MACH_AT91SAM9G20EK_2MMC
- depends on MACH_AT91SAM9G20EK
- bool "Atmel AT91SAM9G20-EK Evaluation Kit with 2 SD/MMC Slots"
- help
- Select this if you are using an Atmel AT91SAM9G20-EK Evaluation Kit
- with 2 SD/MMC Slots. This is the case for AT91SAM9G20-EK rev. C and
- onwards.
- <http://www.atmel.com/tools/SAM9G20-EK.aspx>
-
-config MACH_CPU9G20
- bool "Eukrea CPU9G20 board"
- help
- Select this if you are using a Eukrea Electromatique's
- CPU9G20 Board <http://www.eukrea.com/>
-
-config MACH_PORTUXG20
- bool "taskit PortuxG20"
- help
- Select this if you are using taskit's PortuxG20.
- <http://www.taskit.de/en/>
-
-config MACH_STAMP9G20
- bool "taskit Stamp9G20 CPU module"
- help
- Select this if you are using taskit's Stamp9G20 CPU module on its
- evaluation board.
- <http://www.taskit.de/en/>
-
-config MACH_PCONTROL_G20
- bool "PControl G20 CPU module"
- help
- Select this if you are using taskit's Stamp9G20 CPU module on this
- carrier board, being the decentralized unit of a building automation
- system; featuring nvram, eth-switch, iso-rs485, display, io
-
-config MACH_GSIA18S
- bool "GS_IA18_S board"
- help
- This enables support for the GS_IA18_S board
- produced by GeoSIG Ltd company. This is an internet accelerograph.
- <http://www.geosig.com>
-
-config MACH_SNAPPER_9260
- bool "Bluewater Systems Snapper 9260/9G20 module"
- help
- Select this if you are using the Bluewater Systems Snapper 9260 or
- Snapper 9G20 modules.
- <http://www.bluewatersys.com/>
-endif
-
-# ----------------------------------------------------------
-
-if ARCH_AT91SAM9261
-
-comment "AT91SAM9261 Board Type"
-
-config MACH_AT91SAM9261EK
- bool "Atmel AT91SAM9261-EK Evaluation Kit"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Atmel's AT91SAM9261-EK Evaluation Kit.
- <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=3820>
-
-comment "AT91SAM9G10 Board Type"
-
-config MACH_AT91SAM9G10EK
- bool "Atmel AT91SAM9G10-EK Evaluation Kit"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Atmel's AT91SAM9G10-EK Evaluation Kit.
- <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4588>
-
-endif
-
-# ----------------------------------------------------------
-
-if ARCH_AT91SAM9263
-
-comment "AT91SAM9263 Board Type"
-
-config MACH_AT91SAM9263EK
- bool "Atmel AT91SAM9263-EK Evaluation Kit"
- select HAVE_AT91_DATAFLASH_CARD
- help
- Select this if you are using Atmel's AT91SAM9263-EK Evaluation Kit.
- <http://www.atmel.com/dyn/products/tools_card.asp?tool_id=4057>
-
-endif
-
-# ----------------------------------------------------------
-
-if ARCH_AT91SAM9RL
-
-comment "AT91SAM9RL Board Type"
-
-config MACH_AT91SAM9RLEK
- bool "Atmel AT91SAM9RL-EK Evaluation Kit"
- help
- Select this if you are using Atmel's AT91SAM9RL-EK Evaluation Kit.
-
-endif
-
-# ----------------------------------------------------------
-
-if ARCH_AT91SAM9G45
-
-comment "AT91SAM9G45 Board Type"
-
-config MACH_AT91SAM9M10G45EK
- bool "Atmel AT91SAM9M10G45-EK Evaluation Kits"
- help
- Select this if you are using Atmel's AT91SAM9M10G45-EK Evaluation Kit.
- Those boards can be populated with any SoC of AT91SAM9G45 or AT91SAM9M10
- families: AT91SAM9G45, AT91SAM9G46, AT91SAM9M10 and AT91SAM9M11.
- <http://www.atmel.com/tools/SAM9M10-G45-EK.aspx>
-
-endif
-
-# ----------------------------------------------------------
-
-if ARCH_AT91X40
-
-comment "AT91X40 Board Type"
-
-config MACH_AT91EB01
- bool "Atmel AT91EB01 Evaluation Kit"
- help
- Select this if you are using Atmel's AT91EB01 Evaluation Kit.
- It is also a popular target for simulators such as GDB's
- ARM simulator (commonly known as the ARMulator) and the
- Skyeye simulator.
-
-endif
-
-# ----------------------------------------------------------
-
-comment "AT91 Board Options"
-
-config MTD_AT91_DATAFLASH_CARD
- bool "Enable DataFlash Card support"
- depends on HAVE_AT91_DATAFLASH_CARD
- help
- Enable support for the DataFlash card.
-
-endmenu
diff --git a/arch/arm/mach-at91/Makefile b/arch/arm/mach-at91/Makefile
index 1b9ae02..7b6424d 100644
--- a/arch/arm/mach-at91/Makefile
+++ b/arch/arm/mach-at91/Makefile
@@ -2,10 +2,8 @@
# Makefile for the linux kernel.
#
-obj-y := gpio.o setup.o sysirq_mask.o
+obj-y := setup.o sysirq_mask.o
-obj-$(CONFIG_OLD_IRQ_AT91) += irq.o
-obj-$(CONFIG_OLD_CLK_AT91) += clock.o
obj-$(CONFIG_SOC_AT91SAM9) += sam9_smc.o
# CPU-specific support
@@ -20,73 +18,12 @@ obj-$(CONFIG_SOC_AT91SAM9RL) += at91sam9rl.o
obj-$(CONFIG_SOC_SAMA5D3) += sama5d3.o
obj-$(CONFIG_SOC_SAMA5D4) += sama5d4.o
-obj-$(CONFIG_ARCH_AT91RM9200) += at91rm9200_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9260) += at91sam9260_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9261) += at91sam9261_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9263) += at91sam9263_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9RL) += at91sam9rl_devices.o
-obj-$(CONFIG_ARCH_AT91SAM9G45) += at91sam9g45_devices.o
-obj-$(CONFIG_ARCH_AT91X40) += at91x40.o at91x40_time.o
-
-# AT91RM9200 board-specific support
-obj-$(CONFIG_MACH_ONEARM) += board-1arm.o
-obj-$(CONFIG_MACH_AT91RM9200EK) += board-rm9200ek.o
-obj-$(CONFIG_MACH_CSB337) += board-csb337.o
-obj-$(CONFIG_MACH_CSB637) += board-csb637.o
-obj-$(CONFIG_MACH_CARMEVA) += board-carmeva.o
-obj-$(CONFIG_MACH_KB9200) += board-kb9202.o
-obj-$(CONFIG_MACH_ATEB9200) += board-eb9200.o
-obj-$(CONFIG_MACH_KAFA) += board-kafa.o
-obj-$(CONFIG_MACH_PICOTUX2XX) += board-picotux200.o
-obj-$(CONFIG_MACH_ECBAT91) += board-ecbat91.o
-obj-$(CONFIG_MACH_YL9200) += board-yl-9200.o
-obj-$(CONFIG_MACH_CPUAT91) += board-cpuat91.o
-obj-$(CONFIG_MACH_ECO920) += board-eco920.o
-
-# AT91SAM9260 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9260EK) += board-sam9260ek.o
-obj-$(CONFIG_MACH_CAM60) += board-cam60.o
-obj-$(CONFIG_MACH_SAM9_L9260) += board-sam9-l9260.o
-obj-$(CONFIG_MACH_AFEB9260) += board-afeb-9260v1.o
-obj-$(CONFIG_MACH_CPU9260) += board-cpu9krea.o
-obj-$(CONFIG_MACH_FLEXIBITY) += board-flexibity.o
-
-# AT91SAM9261 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9261EK) += board-sam9261ek.o
-obj-$(CONFIG_MACH_AT91SAM9G10EK) += board-sam9261ek.o
-
-# AT91SAM9263 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9263EK) += board-sam9263ek.o
-
-# AT91SAM9RL board-specific support
-obj-$(CONFIG_MACH_AT91SAM9RLEK) += board-sam9rlek.o
-
-# AT91SAM9G20 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9G20EK) += board-sam9g20ek.o
-obj-$(CONFIG_MACH_CPU9G20) += board-cpu9krea.o
-obj-$(CONFIG_MACH_STAMP9G20) += board-stamp9g20.o
-obj-$(CONFIG_MACH_PORTUXG20) += board-stamp9g20.o
-obj-$(CONFIG_MACH_PCONTROL_G20) += board-pcontrol-g20.o board-stamp9g20.o
-obj-$(CONFIG_MACH_GSIA18S) += board-gsia18s.o board-stamp9g20.o
-
-# AT91SAM9260/AT91SAM9G20 board-specific support
-obj-$(CONFIG_MACH_SNAPPER_9260) += board-snapper9260.o
-
-# AT91SAM9G45 board-specific support
-obj-$(CONFIG_MACH_AT91SAM9M10G45EK) += board-sam9m10g45ek.o
-
# AT91SAM board with device-tree
obj-$(CONFIG_MACH_AT91RM9200_DT) += board-dt-rm9200.o
obj-$(CONFIG_MACH_AT91SAM9_DT) += board-dt-sam9.o
# SAMA5 board with device-tree
-obj-$(CONFIG_MACH_SAMA5_DT) += board-dt-sama5.o
-
-# AT91X40 board-specific support
-obj-$(CONFIG_MACH_AT91EB01) += board-eb01.o
-
-# Drivers
-obj-y += leds.o
+obj-$(CONFIG_SOC_SAMA5) += board-dt-sama5.o
# Power Management
obj-$(CONFIG_PM) += pm.o
diff --git a/arch/arm/mach-at91/Makefile.boot b/arch/arm/mach-at91/Makefile.boot
index 5309f9b..29ed0fa 100644
--- a/arch/arm/mach-at91/Makefile.boot
+++ b/arch/arm/mach-at91/Makefile.boot
@@ -3,12 +3,6 @@
# PARAMS_PHYS must be within 4MB of ZRELADDR
# INITRD_PHYS must be in RAM
-ifeq ($(CONFIG_ARCH_AT91SAM9G45),y)
- zreladdr-y += 0x70008000
-params_phys-y := 0x70000100
-initrd_phys-y := 0x70410000
-else
zreladdr-y += 0x20008000
params_phys-y := 0x20000100
initrd_phys-y := 0x20410000
-endif
diff --git a/arch/arm/mach-at91/at91_aic.h b/arch/arm/mach-at91/at91_aic.h
deleted file mode 100644
index eaea661..0000000
--- a/arch/arm/mach-at91/at91_aic.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_aic.h
- *
- * Copyright (C) 2005 Ivan Kokshaysky
- * Copyright (C) SAN People
- *
- * Advanced Interrupt Controller (AIC) - System peripherals registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_AIC_H
-#define AT91_AIC_H
-
-#ifndef __ASSEMBLY__
-extern void __iomem *at91_aic_base;
-
-#define at91_aic_read(field) \
- __raw_readl(at91_aic_base + field)
-
-#define at91_aic_write(field, value) \
- __raw_writel(value, at91_aic_base + field)
-#else
-.extern at91_aic_base
-#endif
-
-/* Number of irq lines managed by AIC */
-#define NR_AIC_IRQS 32
-#define NR_AIC5_IRQS 128
-
-#define AT91_AIC5_SSR 0x0 /* Source Select Register [AIC5] */
-#define AT91_AIC5_INTSEL_MSK (0x7f << 0) /* Interrupt Line Selection Mask */
-
-#define AT91_AIC_IRQ_MIN_PRIORITY 0
-#define AT91_AIC_IRQ_MAX_PRIORITY 7
-
-#define AT91_AIC_SMR(n) ((n) * 4) /* Source Mode Registers 0-31 */
-#define AT91_AIC5_SMR 0x4 /* Source Mode Register [AIC5] */
-#define AT91_AIC_PRIOR (7 << 0) /* Priority Level */
-#define AT91_AIC_SRCTYPE (3 << 5) /* Interrupt Source Type */
-#define AT91_AIC_SRCTYPE_LOW (0 << 5)
-#define AT91_AIC_SRCTYPE_FALLING (1 << 5)
-#define AT91_AIC_SRCTYPE_HIGH (2 << 5)
-#define AT91_AIC_SRCTYPE_RISING (3 << 5)
-
-#define AT91_AIC_SVR(n) (0x80 + ((n) * 4)) /* Source Vector Registers 0-31 */
-#define AT91_AIC5_SVR 0x8 /* Source Vector Register [AIC5] */
-#define AT91_AIC_IVR 0x100 /* Interrupt Vector Register */
-#define AT91_AIC5_IVR 0x10 /* Interrupt Vector Register [AIC5] */
-#define AT91_AIC_FVR 0x104 /* Fast Interrupt Vector Register */
-#define AT91_AIC5_FVR 0x14 /* Fast Interrupt Vector Register [AIC5] */
-#define AT91_AIC_ISR 0x108 /* Interrupt Status Register */
-#define AT91_AIC5_ISR 0x18 /* Interrupt Status Register [AIC5] */
-#define AT91_AIC_IRQID (0x1f << 0) /* Current Interrupt Identifier */
-
-#define AT91_AIC_IPR 0x10c /* Interrupt Pending Register */
-#define AT91_AIC5_IPR0 0x20 /* Interrupt Pending Register 0 [AIC5] */
-#define AT91_AIC5_IPR1 0x24 /* Interrupt Pending Register 1 [AIC5] */
-#define AT91_AIC5_IPR2 0x28 /* Interrupt Pending Register 2 [AIC5] */
-#define AT91_AIC5_IPR3 0x2c /* Interrupt Pending Register 3 [AIC5] */
-#define AT91_AIC_IMR 0x110 /* Interrupt Mask Register */
-#define AT91_AIC5_IMR 0x30 /* Interrupt Mask Register [AIC5] */
-#define AT91_AIC_CISR 0x114 /* Core Interrupt Status Register */
-#define AT91_AIC5_CISR 0x34 /* Core Interrupt Status Register [AIC5] */
-#define AT91_AIC_NFIQ (1 << 0) /* nFIQ Status */
-#define AT91_AIC_NIRQ (1 << 1) /* nIRQ Status */
-
-#define AT91_AIC_IECR 0x120 /* Interrupt Enable Command Register */
-#define AT91_AIC5_IECR 0x40 /* Interrupt Enable Command Register [AIC5] */
-#define AT91_AIC_IDCR 0x124 /* Interrupt Disable Command Register */
-#define AT91_AIC5_IDCR 0x44 /* Interrupt Disable Command Register [AIC5] */
-#define AT91_AIC_ICCR 0x128 /* Interrupt Clear Command Register */
-#define AT91_AIC5_ICCR 0x48 /* Interrupt Clear Command Register [AIC5] */
-#define AT91_AIC_ISCR 0x12c /* Interrupt Set Command Register */
-#define AT91_AIC5_ISCR 0x4c /* Interrupt Set Command Register [AIC5] */
-#define AT91_AIC_EOICR 0x130 /* End of Interrupt Command Register */
-#define AT91_AIC5_EOICR 0x38 /* End of Interrupt Command Register [AIC5] */
-#define AT91_AIC_SPU 0x134 /* Spurious Interrupt Vector Register */
-#define AT91_AIC5_SPU 0x3c /* Spurious Interrupt Vector Register [AIC5] */
-#define AT91_AIC_DCR 0x138 /* Debug Control Register */
-#define AT91_AIC5_DCR 0x6c /* Debug Control Register [AIC5] */
-#define AT91_AIC_DCR_PROT (1 << 0) /* Protection Mode */
-#define AT91_AIC_DCR_GMSK (1 << 1) /* General Mask */
-
-#define AT91_AIC_FFER 0x140 /* Fast Forcing Enable Register [SAM9 only] */
-#define AT91_AIC5_FFER 0x50 /* Fast Forcing Enable Register [AIC5] */
-#define AT91_AIC_FFDR 0x144 /* Fast Forcing Disable Register [SAM9 only] */
-#define AT91_AIC5_FFDR 0x54 /* Fast Forcing Disable Register [AIC5] */
-#define AT91_AIC_FFSR 0x148 /* Fast Forcing Status Register [SAM9 only] */
-#define AT91_AIC5_FFSR 0x58 /* Fast Forcing Status Register [AIC5] */
-
-void at91_aic_handle_irq(struct pt_regs *regs);
-void at91_aic5_handle_irq(struct pt_regs *regs);
-
-#endif
diff --git a/arch/arm/mach-at91/at91_tc.h b/arch/arm/mach-at91/at91_tc.h
deleted file mode 100644
index 46a317f..0000000
--- a/arch/arm/mach-at91/at91_tc.h
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91_tc.h
- *
- * Copyright (C) SAN People
- *
- * Timer/Counter Unit (TC) registers.
- * Based on AT91RM9200 datasheet revision E.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#ifndef AT91_TC_H
-#define AT91_TC_H
-
-#define AT91_TC_BCR 0xc0 /* TC Block Control Register */
-#define AT91_TC_SYNC (1 << 0) /* Synchro Command */
-
-#define AT91_TC_BMR 0xc4 /* TC Block Mode Register */
-#define AT91_TC_TC0XC0S (3 << 0) /* External Clock Signal 0 Selection */
-#define AT91_TC_TC0XC0S_TCLK0 (0 << 0)
-#define AT91_TC_TC0XC0S_NONE (1 << 0)
-#define AT91_TC_TC0XC0S_TIOA1 (2 << 0)
-#define AT91_TC_TC0XC0S_TIOA2 (3 << 0)
-#define AT91_TC_TC1XC1S (3 << 2) /* External Clock Signal 1 Selection */
-#define AT91_TC_TC1XC1S_TCLK1 (0 << 2)
-#define AT91_TC_TC1XC1S_NONE (1 << 2)
-#define AT91_TC_TC1XC1S_TIOA0 (2 << 2)
-#define AT91_TC_TC1XC1S_TIOA2 (3 << 2)
-#define AT91_TC_TC2XC2S (3 << 4) /* External Clock Signal 2 Selection */
-#define AT91_TC_TC2XC2S_TCLK2 (0 << 4)
-#define AT91_TC_TC2XC2S_NONE (1 << 4)
-#define AT91_TC_TC2XC2S_TIOA0 (2 << 4)
-#define AT91_TC_TC2XC2S_TIOA1 (3 << 4)
-
-
-#define AT91_TC_CCR 0x00 /* Channel Control Register */
-#define AT91_TC_CLKEN (1 << 0) /* Counter Clock Enable Command */
-#define AT91_TC_CLKDIS (1 << 1) /* Counter CLock Disable Command */
-#define AT91_TC_SWTRG (1 << 2) /* Software Trigger Command */
-
-#define AT91_TC_CMR 0x04 /* Channel Mode Register */
-#define AT91_TC_TCCLKS (7 << 0) /* Capture/Waveform Mode: Clock Selection */
-#define AT91_TC_TIMER_CLOCK1 (0 << 0)
-#define AT91_TC_TIMER_CLOCK2 (1 << 0)
-#define AT91_TC_TIMER_CLOCK3 (2 << 0)
-#define AT91_TC_TIMER_CLOCK4 (3 << 0)
-#define AT91_TC_TIMER_CLOCK5 (4 << 0)
-#define AT91_TC_XC0 (5 << 0)
-#define AT91_TC_XC1 (6 << 0)
-#define AT91_TC_XC2 (7 << 0)
-#define AT91_TC_CLKI (1 << 3) /* Capture/Waveform Mode: Clock Invert */
-#define AT91_TC_BURST (3 << 4) /* Capture/Waveform Mode: Burst Signal Selection */
-#define AT91_TC_LDBSTOP (1 << 6) /* Capture Mode: Counter Clock Stopped with TB Loading */
-#define AT91_TC_LDBDIS (1 << 7) /* Capture Mode: Counter Clock Disable with RB Loading */
-#define AT91_TC_ETRGEDG (3 << 8) /* Capture Mode: External Trigger Edge Selection */
-#define AT91_TC_ABETRG (1 << 10) /* Capture Mode: TIOA or TIOB External Trigger Selection */
-#define AT91_TC_CPCTRG (1 << 14) /* Capture Mode: RC Compare Trigger Enable */
-#define AT91_TC_WAVE (1 << 15) /* Capture/Waveform mode */
-#define AT91_TC_LDRA (3 << 16) /* Capture Mode: RA Loading Selection */
-#define AT91_TC_LDRB (3 << 18) /* Capture Mode: RB Loading Selection */
-
-#define AT91_TC_CPCSTOP (1 << 6) /* Waveform Mode: Counter Clock Stopped with RC Compare */
-#define AT91_TC_CPCDIS (1 << 7) /* Waveform Mode: Counter Clock Disable with RC Compare */
-#define AT91_TC_EEVTEDG (3 << 8) /* Waveform Mode: External Event Edge Selection */
-#define AT91_TC_EEVTEDG_NONE (0 << 8)
-#define AT91_TC_EEVTEDG_RISING (1 << 8)
-#define AT91_TC_EEVTEDG_FALLING (2 << 8)
-#define AT91_TC_EEVTEDG_BOTH (3 << 8)
-#define AT91_TC_EEVT (3 << 10) /* Waveform Mode: External Event Selection */
-#define AT91_TC_EEVT_TIOB (0 << 10)
-#define AT91_TC_EEVT_XC0 (1 << 10)
-#define AT91_TC_EEVT_XC1 (2 << 10)
-#define AT91_TC_EEVT_XC2 (3 << 10)
-#define AT91_TC_ENETRG (1 << 12) /* Waveform Mode: External Event Trigger Enable */
-#define AT91_TC_WAVESEL (3 << 13) /* Waveform Mode: Waveform Selection */
-#define AT91_TC_WAVESEL_UP (0 << 13)
-#define AT91_TC_WAVESEL_UP_AUTO (2 << 13)
-#define AT91_TC_WAVESEL_UPDOWN (1 << 13)
-#define AT91_TC_WAVESEL_UPDOWN_AUTO (3 << 13)
-#define AT91_TC_ACPA (3 << 16) /* Waveform Mode: RA Compare Effect on TIOA */
-#define AT91_TC_ACPA_NONE (0 << 16)
-#define AT91_TC_ACPA_SET (1 << 16)
-#define AT91_TC_ACPA_CLEAR (2 << 16)
-#define AT91_TC_ACPA_TOGGLE (3 << 16)
-#define AT91_TC_ACPC (3 << 18) /* Waveform Mode: RC Compre Effect on TIOA */
-#define AT91_TC_ACPC_NONE (0 << 18)
-#define AT91_TC_ACPC_SET (1 << 18)
-#define AT91_TC_ACPC_CLEAR (2 << 18)
-#define AT91_TC_ACPC_TOGGLE (3 << 18)
-#define AT91_TC_AEEVT (3 << 20) /* Waveform Mode: External Event Effect on TIOA */
-#define AT91_TC_AEEVT_NONE (0 << 20)
-#define AT91_TC_AEEVT_SET (1 << 20)
-#define AT91_TC_AEEVT_CLEAR (2 << 20)
-#define AT91_TC_AEEVT_TOGGLE (3 << 20)
-#define AT91_TC_ASWTRG (3 << 22) /* Waveform Mode: Software Trigger Effect on TIOA */
-#define AT91_TC_ASWTRG_NONE (0 << 22)
-#define AT91_TC_ASWTRG_SET (1 << 22)
-#define AT91_TC_ASWTRG_CLEAR (2 << 22)
-#define AT91_TC_ASWTRG_TOGGLE (3 << 22)
-#define AT91_TC_BCPB (3 << 24) /* Waveform Mode: RB Compare Effect on TIOB */
-#define AT91_TC_BCPB_NONE (0 << 24)
-#define AT91_TC_BCPB_SET (1 << 24)
-#define AT91_TC_BCPB_CLEAR (2 << 24)
-#define AT91_TC_BCPB_TOGGLE (3 << 24)
-#define AT91_TC_BCPC (3 << 26) /* Waveform Mode: RC Compare Effect on TIOB */
-#define AT91_TC_BCPC_NONE (0 << 26)
-#define AT91_TC_BCPC_SET (1 << 26)
-#define AT91_TC_BCPC_CLEAR (2 << 26)
-#define AT91_TC_BCPC_TOGGLE (3 << 26)
-#define AT91_TC_BEEVT (3 << 28) /* Waveform Mode: External Event Effect on TIOB */
-#define AT91_TC_BEEVT_NONE (0 << 28)
-#define AT91_TC_BEEVT_SET (1 << 28)
-#define AT91_TC_BEEVT_CLEAR (2 << 28)
-#define AT91_TC_BEEVT_TOGGLE (3 << 28)
-#define AT91_TC_BSWTRG (3 << 30) /* Waveform Mode: Software Trigger Effect on TIOB */
-#define AT91_TC_BSWTRG_NONE (0 << 30)
-#define AT91_TC_BSWTRG_SET (1 << 30)
-#define AT91_TC_BSWTRG_CLEAR (2 << 30)
-#define AT91_TC_BSWTRG_TOGGLE (3 << 30)
-
-#define AT91_TC_CV 0x10 /* Counter Value */
-#define AT91_TC_RA 0x14 /* Register A */
-#define AT91_TC_RB 0x18 /* Register B */
-#define AT91_TC_RC 0x1c /* Register C */
-
-#define AT91_TC_SR 0x20 /* Status Register */
-#define AT91_TC_COVFS (1 << 0) /* Counter Overflow Status */
-#define AT91_TC_LOVRS (1 << 1) /* Load Overrun Status */
-#define AT91_TC_CPAS (1 << 2) /* RA Compare Status */
-#define AT91_TC_CPBS (1 << 3) /* RB Compare Status */
-#define AT91_TC_CPCS (1 << 4) /* RC Compare Status */
-#define AT91_TC_LDRAS (1 << 5) /* RA Loading Status */
-#define AT91_TC_LDRBS (1 << 6) /* RB Loading Status */
-#define AT91_TC_ETRGS (1 << 7) /* External Trigger Status */
-#define AT91_TC_CLKSTA (1 << 16) /* Clock Enabling Status */
-#define AT91_TC_MTIOA (1 << 17) /* TIOA Mirror */
-#define AT91_TC_MTIOB (1 << 18) /* TIOB Mirror */
-
-#define AT91_TC_IER 0x24 /* Interrupt Enable Register */
-#define AT91_TC_IDR 0x28 /* Interrupt Disable Register */
-#define AT91_TC_IMR 0x2c /* Interrupt Mask Register */
-
-#endif
diff --git a/arch/arm/mach-at91/at91rm9200.c b/arch/arm/mach-at91/at91rm9200.c
index 038702e..b529169 100644
--- a/arch/arm/mach-at91/at91rm9200.c
+++ b/arch/arm/mach-at91/at91rm9200.c
@@ -11,296 +11,15 @@
*/
#include <linux/module.h>
-#include <linux/reboot.h>
#include <linux/clk/at91_pmc.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/system_misc.h>
-#include <mach/at91rm9200.h>
#include <mach/at91_st.h>
-#include <mach/cpu.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-#include "pm.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk udc_clk = {
- .name = "udc_clk",
- .pmc_mask = 1 << AT91RM9200_ID_UDP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
- .name = "ohci_clk",
- .pmc_mask = 1 << AT91RM9200_ID_UHP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ether_clk = {
- .name = "ether_clk",
- .pmc_mask = 1 << AT91RM9200_ID_EMAC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
- .name = "mci_clk",
- .pmc_mask = 1 << AT91RM9200_ID_MCI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi_clk = {
- .name = "twi_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TWI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91RM9200_ID_US0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91RM9200_ID_US1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91RM9200_ID_US2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .pmc_mask = 1 << AT91RM9200_ID_US3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi_clk = {
- .name = "spi_clk",
- .pmc_mask = 1 << AT91RM9200_ID_SPI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .pmc_mask = 1 << AT91RM9200_ID_PIOA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .pmc_mask = 1 << AT91RM9200_ID_PIOB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
- .name = "pioC_clk",
- .pmc_mask = 1 << AT91RM9200_ID_PIOC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioD_clk = {
- .name = "pioD_clk",
- .pmc_mask = 1 << AT91RM9200_ID_PIOD,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
- .name = "ssc0_clk",
- .pmc_mask = 1 << AT91RM9200_ID_SSC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
- .name = "ssc1_clk",
- .pmc_mask = 1 << AT91RM9200_ID_SSC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc2_clk = {
- .name = "ssc2_clk",
- .pmc_mask = 1 << AT91RM9200_ID_SSC2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc0_clk = {
- .name = "tc0_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc1_clk = {
- .name = "tc1_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc2_clk = {
- .name = "tc2_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TC2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc3_clk = {
- .name = "tc3_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TC3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc4_clk = {
- .name = "tc4_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TC4,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc5_clk = {
- .name = "tc5_clk",
- .pmc_mask = 1 << AT91RM9200_ID_TC5,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
- &pioC_clk,
- &pioD_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &usart3_clk,
- &mmc_clk,
- &udc_clk,
- &twi_clk,
- &spi_clk,
- &ssc0_clk,
- &ssc1_clk,
- &ssc2_clk,
- &tc0_clk,
- &tc1_clk,
- &tc2_clk,
- &tc3_clk,
- &tc4_clk,
- &tc5_clk,
- &ohci_clk,
- &ether_clk,
- // irq0 .. irq6
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffd0000.ssc", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffd4000.ssc", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffd8000.ssc", &ssc2_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91rm9200.0", &twi_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
- CLKDEV_CON_ID("pioD", &pioD_clk),
- /* usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fffc0000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "fffc4000.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "fffc8000.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "fffcc000.serial", &usart3_clk),
- /* tc lookup table for DT entries */
- CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "fffa4000.timer", &tc3_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffa4000.timer", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffa4000.timer", &tc5_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fffb4000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID("emac_clk", "fffbc000.ethernet", &ether_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffb8000.i2c", &twi_clk),
- CLKDEV_CON_DEV_ID("hclk", "300000.ohci", &ohci_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioD_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
-};
-
-/*
- * The four programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-static struct clk pck2 = {
- .name = "pck2",
- .pmc_mask = AT91_PMC_PCK2,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 2,
-};
-static struct clk pck3 = {
- .name = "pck3",
- .pmc_mask = AT91_PMC_PCK3,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 3,
-};
-
-static void __init at91rm9200_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
- clkdev_add_table(usart_clocks_lookups,
- ARRAY_SIZE(usart_clocks_lookups));
-
- clk_register(&pck0);
- clk_register(&pck1);
- clk_register(&pck2);
- clk_register(&pck3);
-}
-#else
-#define at91rm9200_register_clocks NULL
-#endif
-
-/* --------------------------------------------------------------------
- * GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91rm9200_gpio[] __initdata = {
- {
- .id = AT91RM9200_ID_PIOA,
- .regbase = AT91RM9200_BASE_PIOA,
- }, {
- .id = AT91RM9200_ID_PIOB,
- .regbase = AT91RM9200_BASE_PIOB,
- }, {
- .id = AT91RM9200_ID_PIOC,
- .regbase = AT91RM9200_BASE_PIOC,
- }, {
- .id = AT91RM9200_ID_PIOD,
- .regbase = AT91RM9200_BASE_PIOD,
- }
-};
static void at91rm9200_idle(void)
{
@@ -329,74 +48,14 @@ static void __init at91rm9200_map_io(void)
at91_init_sram(0, AT91RM9200_SRAM_BASE, AT91RM9200_SRAM_SIZE);
}
-static void __init at91rm9200_ioremap_registers(void)
-{
- at91rm9200_ioremap_st(AT91RM9200_BASE_ST);
- at91_ioremap_ramc(0, AT91RM9200_BASE_MC, 256);
- at91_pm_set_standby(at91rm9200_standby);
-}
-
static void __init at91rm9200_initialize(void)
{
arm_pm_idle = at91rm9200_idle;
arm_pm_restart = at91rm9200_restart;
-
- /* Initialize GPIO subsystem */
- at91_gpio_init(at91rm9200_gpio,
- cpu_is_at91rm9200_bga() ? AT91RM9200_BGA : AT91RM9200_PQFP);
}
-/* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91rm9200_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller (FIQ) */
- 7, /* System Peripherals */
- 1, /* Parallel IO Controller A */
- 1, /* Parallel IO Controller B */
- 1, /* Parallel IO Controller C */
- 1, /* Parallel IO Controller D */
- 5, /* USART 0 */
- 5, /* USART 1 */
- 5, /* USART 2 */
- 5, /* USART 3 */
- 0, /* Multimedia Card Interface */
- 2, /* USB Device Port */
- 6, /* Two-Wire Interface */
- 5, /* Serial Peripheral Interface */
- 4, /* Serial Synchronous Controller 0 */
- 4, /* Serial Synchronous Controller 1 */
- 4, /* Serial Synchronous Controller 2 */
- 0, /* Timer Counter 0 */
- 0, /* Timer Counter 1 */
- 0, /* Timer Counter 2 */
- 0, /* Timer Counter 3 */
- 0, /* Timer Counter 4 */
- 0, /* Timer Counter 5 */
- 2, /* USB Host port */
- 3, /* Ethernet MAC */
- 0, /* Advanced Interrupt Controller (IRQ0) */
- 0, /* Advanced Interrupt Controller (IRQ1) */
- 0, /* Advanced Interrupt Controller (IRQ2) */
- 0, /* Advanced Interrupt Controller (IRQ3) */
- 0, /* Advanced Interrupt Controller (IRQ4) */
- 0, /* Advanced Interrupt Controller (IRQ5) */
- 0 /* Advanced Interrupt Controller (IRQ6) */
-};
-
AT91_SOC_START(at91rm9200)
.map_io = at91rm9200_map_io,
- .default_irq_priority = at91rm9200_default_irq_priority,
- .extern_irq = (1 << AT91RM9200_ID_IRQ0) | (1 << AT91RM9200_ID_IRQ1)
- | (1 << AT91RM9200_ID_IRQ2) | (1 << AT91RM9200_ID_IRQ3)
- | (1 << AT91RM9200_ID_IRQ4) | (1 << AT91RM9200_ID_IRQ5)
- | (1 << AT91RM9200_ID_IRQ6),
- .ioremap_registers = at91rm9200_ioremap_registers,
- .register_clocks = at91rm9200_register_clocks,
.init = at91rm9200_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91rm9200_devices.c b/arch/arm/mach-at91/at91rm9200_devices.c
deleted file mode 100644
index 74f1eaf..0000000
--- a/arch/arm/mach-at91/at91rm9200_devices.c
+++ /dev/null
@@ -1,1212 +0,0 @@
-/*
- * arch/arm/mach-at91/at91rm9200_devices.c
- *
- * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- * Copyright (C) 2005 David Brownell
- *
- * 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 <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/gpio/machine.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <mach/at91rm9200.h>
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-#include <mach/hardware.h>
-
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-/* --------------------------------------------------------------------
- * USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
- [0] = {
- .start = AT91RM9200_UHP_BASE,
- .end = AT91RM9200_UHP_BASE + SZ_1M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_usbh_device = {
- .name = "at91_ohci",
- .id = -1,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &usbh_data,
- },
- .resource = usbh_resources,
- .num_resources = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
- int i;
-
- if (!data)
- return;
-
- /* Enable overcurrent notification */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->overcurrent_pin[i]))
- at91_set_gpio_input(data->overcurrent_pin[i], 1);
- }
-
- usbh_data = *data;
- platform_device_register(&at91rm9200_usbh_device);
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE)
-static struct at91_udc_data udc_data;
-
-static struct resource udc_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_UDP,
- .end = AT91RM9200_BASE_UDP + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_udc_device = {
- .name = "at91_udc",
- .id = -1,
- .dev = {
- .platform_data = &udc_data,
- },
- .resource = udc_resources,
- .num_resources = ARRAY_SIZE(udc_resources),
-};
-
-void __init at91_add_device_udc(struct at91_udc_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->vbus_pin)) {
- at91_set_gpio_input(data->vbus_pin, 0);
- at91_set_deglitch(data->vbus_pin, 1);
- }
- if (gpio_is_valid(data->pullup_pin))
- at91_set_gpio_output(data->pullup_pin, 0);
-
- udc_data = *data;
- platform_device_register(&at91rm9200_udc_device);
-}
-#else
-void __init at91_add_device_udc(struct at91_udc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ARM_AT91_ETHER) || defined(CONFIG_ARM_AT91_ETHER_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct macb_platform_data eth_data;
-
-static struct resource eth_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_EMAC,
- .end = AT91RM9200_BASE_EMAC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_eth_device = {
- .name = "at91_ether",
- .id = -1,
- .dev = {
- .dma_mask = &eth_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &eth_data,
- },
- .resource = eth_resources,
- .num_resources = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct macb_platform_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->phy_irq_pin)) {
- at91_set_gpio_input(data->phy_irq_pin, 0);
- at91_set_deglitch(data->phy_irq_pin, 1);
- }
-
- /* Pins used for MII and RMII */
- at91_set_A_periph(AT91_PIN_PA16, 0); /* EMDIO */
- at91_set_A_periph(AT91_PIN_PA15, 0); /* EMDC */
- at91_set_A_periph(AT91_PIN_PA14, 0); /* ERXER */
- at91_set_A_periph(AT91_PIN_PA13, 0); /* ERX1 */
- at91_set_A_periph(AT91_PIN_PA12, 0); /* ERX0 */
- at91_set_A_periph(AT91_PIN_PA11, 0); /* ECRS_ECRSDV */
- at91_set_A_periph(AT91_PIN_PA10, 0); /* ETX1 */
- at91_set_A_periph(AT91_PIN_PA9, 0); /* ETX0 */
- at91_set_A_periph(AT91_PIN_PA8, 0); /* ETXEN */
- at91_set_A_periph(AT91_PIN_PA7, 0); /* ETXCK_EREFCK */
-
- if (!data->is_rmii) {
- at91_set_B_periph(AT91_PIN_PB19, 0); /* ERXCK */
- at91_set_B_periph(AT91_PIN_PB18, 0); /* ECOL */
- at91_set_B_periph(AT91_PIN_PB17, 0); /* ERXDV */
- at91_set_B_periph(AT91_PIN_PB16, 0); /* ERX3 */
- at91_set_B_periph(AT91_PIN_PB15, 0); /* ERX2 */
- at91_set_B_periph(AT91_PIN_PB14, 0); /* ETXER */
- at91_set_B_periph(AT91_PIN_PB13, 0); /* ETX3 */
- at91_set_B_periph(AT91_PIN_PB12, 0); /* ETX2 */
- }
-
- eth_data = *data;
- platform_device_register(&at91rm9200_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct macb_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Compact Flash / PCMCIA
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE)
-static struct at91_cf_data cf_data;
-
-#define CF_BASE AT91_CHIPSELECT_4
-
-static struct resource cf_resources[] = {
- [0] = {
- .start = CF_BASE,
- /* ties up CS4, CS5 and CS6 */
- .end = CF_BASE + (0x30000000 - 1),
- .flags = IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT,
- },
-};
-
-static struct platform_device at91rm9200_cf_device = {
- .name = "at91_cf",
- .id = -1,
- .dev = {
- .platform_data = &cf_data,
- },
- .resource = cf_resources,
- .num_resources = ARRAY_SIZE(cf_resources),
-};
-
-void __init at91_add_device_cf(struct at91_cf_data *data)
-{
- unsigned int csa;
-
- if (!data)
- return;
-
- data->chipselect = 4; /* can only use EBI ChipSelect 4 */
-
- /* CF takes over CS4, CS5, CS6 */
- csa = at91_ramc_read(0, AT91_EBI_CSA);
- at91_ramc_write(0, AT91_EBI_CSA, csa | AT91_EBI_CS4A_SMC_COMPACTFLASH);
-
- /*
- * Static memory controller timing adjustments.
- * REVISIT: these timings are in terms of MCK cycles, so
- * when MCK changes (cpufreq etc) so must these values...
- */
- at91_ramc_write(0, AT91_SMC_CSR(4),
- AT91_SMC_ACSS_STD
- | AT91_SMC_DBW_16
- | AT91_SMC_BAT
- | AT91_SMC_WSEN
- | AT91_SMC_NWS_(32) /* wait states */
- | AT91_SMC_RWSETUP_(6) /* setup time */
- | AT91_SMC_RWHOLD_(4) /* hold time */
- );
-
- /* input/irq */
- if (gpio_is_valid(data->irq_pin)) {
- at91_set_gpio_input(data->irq_pin, 1);
- at91_set_deglitch(data->irq_pin, 1);
- }
- at91_set_gpio_input(data->det_pin, 1);
- at91_set_deglitch(data->det_pin, 1);
-
- /* outputs, initially off */
- if (gpio_is_valid(data->vcc_pin))
- at91_set_gpio_output(data->vcc_pin, 0);
- at91_set_gpio_output(data->rst_pin, 0);
-
- /* force poweron defaults for these pins ... */
- at91_set_A_periph(AT91_PIN_PC9, 0); /* A25/CFRNW */
- at91_set_A_periph(AT91_PIN_PC10, 0); /* NCS4/CFCS */
- at91_set_A_periph(AT91_PIN_PC11, 0); /* NCS5/CFCE1 */
- at91_set_A_periph(AT91_PIN_PC12, 0); /* NCS6/CFCE2 */
-
- /* nWAIT is _not_ a default setting */
- at91_set_A_periph(AT91_PIN_PC6, 1); /* nWAIT */
-
- cf_data = *data;
- platform_device_register(&at91rm9200_cf_device);
-}
-#else
-void __init at91_add_device_cf(struct at91_cf_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * MMC / SD
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct mci_platform_data mmc_data;
-
-static struct resource mmc_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_MCI,
- .end = AT91RM9200_BASE_MCI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_mmc_device = {
- .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc_data,
- },
- .resource = mmc_resources,
- .num_resources = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
-{
- unsigned int i;
- unsigned int slot_count = 0;
-
- if (!data)
- return;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
-
- if (!data->slot[i].bus_width)
- continue;
-
- /* input/irq */
- if (gpio_is_valid(data->slot[i].detect_pin)) {
- at91_set_gpio_input(data->slot[i].detect_pin, 1);
- at91_set_deglitch(data->slot[i].detect_pin, 1);
- }
- if (gpio_is_valid(data->slot[i].wp_pin))
- at91_set_gpio_input(data->slot[i].wp_pin, 1);
-
- switch (i) {
- case 0: /* slot A */
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA28, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA29, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_B_periph(AT91_PIN_PB3, 1);
- at91_set_B_periph(AT91_PIN_PB4, 1);
- at91_set_B_periph(AT91_PIN_PB5, 1);
- }
- slot_count++;
- break;
- case 1: /* slot B */
- /* CMD */
- at91_set_B_periph(AT91_PIN_PA8, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_B_periph(AT91_PIN_PA9, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_B_periph(AT91_PIN_PA10, 1);
- at91_set_B_periph(AT91_PIN_PA11, 1);
- at91_set_B_periph(AT91_PIN_PA12, 1);
- }
- slot_count++;
- break;
- default:
- printk(KERN_ERR
- "AT91: SD/MMC slot %d not available\n", i);
- break;
- }
- if (slot_count) {
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA27, 0);
-
- mmc_data = *data;
- platform_device_register(&at91rm9200_mmc_device);
- }
- }
-
-}
-#else
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
- {
- .start = NAND_BASE,
- .end = NAND_BASE + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91rm9200_nand_device = {
- .name = "atmel_nand",
- .id = -1,
- .dev = {
- .platform_data = &nand_data,
- },
- .resource = nand_resources,
- .num_resources = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
- unsigned int csa;
-
- if (!data)
- return;
-
- /* enable the address range of CS3 */
- csa = at91_ramc_read(0, AT91_EBI_CSA);
- at91_ramc_write(0, AT91_EBI_CSA, csa | AT91_EBI_CS3A_SMC_SMARTMEDIA);
-
- /* set the bus interface characteristics */
- at91_ramc_write(0, AT91_SMC_CSR(3), AT91_SMC_ACSS_STD | AT91_SMC_DBW_8 | AT91_SMC_WSEN
- | AT91_SMC_NWS_(5)
- | AT91_SMC_TDF_(1)
- | AT91_SMC_RWSETUP_(0) /* tDS Data Set up Time 30 - ns */
- | AT91_SMC_RWHOLD_(1) /* tDH Data Hold Time 20 - ns */
- );
-
- /* enable pin */
- if (gpio_is_valid(data->enable_pin))
- at91_set_gpio_output(data->enable_pin, 1);
-
- /* ready/busy pin */
- if (gpio_is_valid(data->rdy_pin))
- at91_set_gpio_input(data->rdy_pin, 1);
-
- /* card detect pin */
- if (gpio_is_valid(data->det_pin))
- at91_set_gpio_input(data->det_pin, 1);
-
- at91_set_A_periph(AT91_PIN_PC1, 0); /* SMOE */
- at91_set_A_periph(AT91_PIN_PC3, 0); /* SMWE */
-
- nand_data = *data;
- platform_device_register(&at91rm9200_nand_device);
-}
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
- .sda_pin = AT91_PIN_PA25,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PA26,
- .scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
-};
-
-static struct platform_device at91rm9200_twi_device = {
- .name = "i2c-gpio",
- .id = 0,
- .dev.platform_data = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- at91_set_GPIO_periph(AT91_PIN_PA25, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PA25, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PA26, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PA26, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91rm9200_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_TWI,
- .end = AT91RM9200_BASE_TWI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_twi_device = {
- .name = "i2c-at91rm9200",
- .id = 0,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA25, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA25, 1);
-
- at91_set_A_periph(AT91_PIN_PA26, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PA26, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91rm9200_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_SPI,
- .end = AT91RM9200_BASE_SPI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_SPI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_spi_device = {
- .name = "atmel_spi",
- .id = 0,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi_resources,
- .num_resources = ARRAY_SIZE(spi_resources),
-};
-
-static const unsigned spi_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
- int i;
- unsigned long cs_pin;
-
- at91_set_A_periph(AT91_PIN_PA0, 0); /* MISO */
- at91_set_A_periph(AT91_PIN_PA1, 0); /* MOSI */
- at91_set_A_periph(AT91_PIN_PA2, 0); /* SPCK */
-
- /* Enable SPI chip-selects */
- for (i = 0; i < nr_devices; i++) {
- if (devices[i].controller_data)
- cs_pin = (unsigned long) devices[i].controller_data;
- else
- cs_pin = spi_standard_cs[devices[i].chip_select];
-
- if (devices[i].chip_select == 0) /* for CS0 errata */
- at91_set_A_periph(cs_pin, 0);
- else
- at91_set_gpio_output(cs_pin, 1);
-
-
- /* pass chip-select pin to driver */
- devices[i].controller_data = (void *) cs_pin;
- }
-
- spi_register_board_info(devices, nr_devices);
- platform_device_register(&at91rm9200_spi_device);
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Timer/Counter blocks
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb0_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_TCB0,
- .end = AT91RM9200_BASE_TCB0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_tcb0_device = {
- .name = "atmel_tcb",
- .id = 0,
- .resource = tcb0_resources,
- .num_resources = ARRAY_SIZE(tcb0_resources),
-};
-
-static struct resource tcb1_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_TCB1,
- .end = AT91RM9200_BASE_TCB1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC3,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC4,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_TC5,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_tcb1_device = {
- .name = "atmel_tcb",
- .id = 1,
- .resource = tcb1_resources,
- .num_resources = ARRAY_SIZE(tcb1_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
- platform_device_register(&at91rm9200_tcb0_device);
- platform_device_register(&at91rm9200_tcb1_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- * RTC
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
-static struct resource rtc_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_RTC,
- .end = AT91RM9200_BASE_RTC + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_rtc_device = {
- .name = "at91_rtc",
- .id = -1,
- .resource = rtc_resources,
- .num_resources = ARRAY_SIZE(rtc_resources),
-};
-
-static void __init at91_add_device_rtc(void)
-{
- platform_device_register(&at91rm9200_rtc_device);
-}
-#else
-static void __init at91_add_device_rtc(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91RM9200_WATCHDOG) || defined(CONFIG_AT91RM9200_WATCHDOG_MODULE)
-static struct platform_device at91rm9200_wdt_device = {
- .name = "at91_wdt",
- .id = -1,
- .num_resources = 0,
-};
-
-static void __init at91_add_device_watchdog(void)
-{
- platform_device_register(&at91rm9200_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_SSC0,
- .end = AT91RM9200_BASE_SSC0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_ssc0_device = {
- .name = "at91rm9200_ssc",
- .id = 0,
- .dev = {
- .dma_mask = &ssc0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc0_resources,
- .num_resources = ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PB0, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PB1, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PB2, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PB3, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PB4, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PB5, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_SSC1,
- .end = AT91RM9200_BASE_SSC1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_ssc1_device = {
- .name = "at91rm9200_ssc",
- .id = 1,
- .dev = {
- .dma_mask = &ssc1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc1_resources,
- .num_resources = ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PB6, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PB7, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PB8, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PB9, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PB10, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PB11, 1);
-}
-
-static u64 ssc2_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc2_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_SSC2,
- .end = AT91RM9200_BASE_SSC2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_SSC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91rm9200_ssc2_device = {
- .name = "at91rm9200_ssc",
- .id = 2,
- .dev = {
- .dma_mask = &ssc2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc2_resources,
- .num_resources = ARRAY_SIZE(ssc2_resources),
-};
-
-static inline void configure_ssc2_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PB12, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PB13, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PB14, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PB15, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PB16, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PB17, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver. For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
- struct platform_device *pdev;
-
- /*
- * NOTE: caller is responsible for passing information matching
- * "pins" to whatever will be using each particular controller.
- */
- switch (id) {
- case AT91RM9200_ID_SSC0:
- pdev = &at91rm9200_ssc0_device;
- configure_ssc0_pins(pins);
- break;
- case AT91RM9200_ID_SSC1:
- pdev = &at91rm9200_ssc1_device;
- configure_ssc1_pins(pins);
- break;
- case AT91RM9200_ID_SSC2:
- pdev = &at91rm9200_ssc2_device;
- configure_ssc2_pins(pins);
- break;
- default:
- return;
- }
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_DBGU,
- .end = AT91RM9200_BASE_DBGU + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data dbgu_data = {
- .use_dma_tx = 0,
- .use_dma_rx = 0, /* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91rm9200_dbgu_device = {
- .name = "atmel_usart",
- .id = 0,
- .dev = {
- .dma_mask = &dbgu_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dbgu_data,
- },
- .resource = dbgu_resources,
- .num_resources = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PA30, 0); /* DRXD */
- at91_set_A_periph(AT91_PIN_PA31, 1); /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_US0,
- .end = AT91RM9200_BASE_US0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static struct gpiod_lookup_table uart0_gpios_table = {
- .dev_id = "atmel_usart",
- .table = {
- GPIO_LOOKUP("pioA", 21, "rts", GPIO_ACTIVE_LOW),
- { },
- },
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91rm9200_uart0_device = {
- .name = "atmel_usart",
- .id = 1,
- .dev = {
- .dma_mask = &uart0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart0_data,
- },
- .resource = uart0_resources,
- .num_resources = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PA17, 1); /* TXD0 */
- at91_set_A_periph(AT91_PIN_PA18, 0); /* RXD0 */
-
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PA20, 0); /* CTS0 */
-
- if (pins & ATMEL_UART_RTS) {
- /*
- * AT91RM9200 Errata #39 - RTS0 is not internally connected to PA21.
- * We need to drive the pin manually. The serial driver will driver
- * this to high when initializing.
- */
- gpiod_add_lookup_table(&uart0_gpios_table);
- }
-}
-
-static struct resource uart1_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_US1,
- .end = AT91RM9200_BASE_US1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91rm9200_uart1_device = {
- .name = "atmel_usart",
- .id = 2,
- .dev = {
- .dma_mask = &uart1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart1_data,
- },
- .resource = uart1_resources,
- .num_resources = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB20, 1); /* TXD1 */
- at91_set_A_periph(AT91_PIN_PB21, 0); /* RXD1 */
-
- if (pins & ATMEL_UART_RI)
- at91_set_A_periph(AT91_PIN_PB18, 0); /* RI1 */
- if (pins & ATMEL_UART_DTR)
- at91_set_A_periph(AT91_PIN_PB19, 0); /* DTR1 */
- if (pins & ATMEL_UART_DCD)
- at91_set_A_periph(AT91_PIN_PB23, 0); /* DCD1 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PB24, 0); /* CTS1 */
- if (pins & ATMEL_UART_DSR)
- at91_set_A_periph(AT91_PIN_PB25, 0); /* DSR1 */
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PB26, 0); /* RTS1 */
-}
-
-static struct resource uart2_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_US2,
- .end = AT91RM9200_BASE_US2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91rm9200_uart2_device = {
- .name = "atmel_usart",
- .id = 3,
- .dev = {
- .dma_mask = &uart2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart2_data,
- },
- .resource = uart2_resources,
- .num_resources = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PA22, 0); /* RXD2 */
- at91_set_A_periph(AT91_PIN_PA23, 1); /* TXD2 */
-
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PA30, 0); /* CTS2 */
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PA31, 0); /* RTS2 */
-}
-
-static struct resource uart3_resources[] = {
- [0] = {
- .start = AT91RM9200_BASE_US3,
- .end = AT91RM9200_BASE_US3 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
- .end = NR_IRQS_LEGACY + AT91RM9200_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart3_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart3_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91rm9200_uart3_device = {
- .name = "atmel_usart",
- .id = 4,
- .dev = {
- .dma_mask = &uart3_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart3_data,
- },
- .resource = uart3_resources,
- .num_resources = ARRAY_SIZE(uart3_resources),
-};
-
-static inline void configure_usart3_pins(unsigned pins)
-{
- at91_set_B_periph(AT91_PIN_PA5, 1); /* TXD3 */
- at91_set_B_periph(AT91_PIN_PA6, 0); /* RXD3 */
-
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PB1, 0); /* CTS3 */
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PB0, 0); /* RTS3 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
- struct platform_device *pdev;
- struct atmel_uart_data *pdata;
-
- switch (id) {
- case 0: /* DBGU */
- pdev = &at91rm9200_dbgu_device;
- configure_dbgu_pins();
- break;
- case AT91RM9200_ID_US0:
- pdev = &at91rm9200_uart0_device;
- configure_usart0_pins(pins);
- break;
- case AT91RM9200_ID_US1:
- pdev = &at91rm9200_uart1_device;
- configure_usart1_pins(pins);
- break;
- case AT91RM9200_ID_US2:
- pdev = &at91rm9200_uart2_device;
- configure_usart2_pins(pins);
- break;
- case AT91RM9200_ID_US3:
- pdev = &at91rm9200_uart3_device;
- configure_usart3_pins(pins);
- break;
- default:
- return;
- }
- pdata = pdev->dev.platform_data;
- pdata->num = portnr; /* update to mapped ID */
-
- if (portnr < ATMEL_MAX_UART)
- at91_uarts[portnr] = pdev;
-}
-
-void __init at91_add_device_serial(void)
-{
- int i;
-
- for (i = 0; i < ATMEL_MAX_UART; i++) {
- if (at91_uarts[i])
- platform_device_register(at91_uarts[i]);
- }
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
- at91_add_device_rtc();
- at91_add_device_watchdog();
- at91_add_device_tc();
- return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91rm9200_time.c b/arch/arm/mach-at91/at91rm9200_time.c
index 7fd13ae..51761f8 100644
--- a/arch/arm/mach-at91/at91rm9200_time.c
+++ b/arch/arm/mach-at91/at91rm9200_time.c
@@ -183,7 +183,6 @@ static struct clock_event_device clkevt = {
void __iomem *at91_st_base;
EXPORT_SYMBOL_GPL(at91_st_base);
-#ifdef CONFIG_OF
static struct of_device_id at91rm9200_st_timer_ids[] = {
{ .compatible = "atmel,at91rm9200-st" },
{ /* sentinel */ }
@@ -219,28 +218,6 @@ node_err:
err:
return -EINVAL;
}
-#else
-static int __init of_at91rm9200_st_init(void)
-{
- return -EINVAL;
-}
-#endif
-
-void __init at91rm9200_ioremap_st(u32 addr)
-{
-#ifdef CONFIG_OF
- struct device_node *np;
-
- np = of_find_matching_node(NULL, at91rm9200_st_timer_ids);
- if (np) {
- of_node_put(np);
- return;
- }
-#endif
- at91_st_base = ioremap(addr, 256);
- if (!at91_st_base)
- panic("Impossible to ioremap ST\n");
-}
/*
* ST (system timer) module supports both clockevents and clocksource.
diff --git a/arch/arm/mach-at91/at91sam9260.c b/arch/arm/mach-at91/at91sam9260.c
index aab1f96..78137c2 100644
--- a/arch/arm/mach-at91/at91sam9260.c
+++ b/arch/arm/mach-at91/at91sam9260.c
@@ -10,305 +10,13 @@
*
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/system_misc.h>
#include <mach/cpu.h>
#include <mach/at91_dbgu.h>
-#include <mach/at91sam9260.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-#include "pm.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_PIOA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_PIOB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
- .name = "pioC_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_PIOC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_clk = {
- .name = "adc_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_ADC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk adc_op_clk = {
- .name = "adc_op_clk",
- .type = CLK_TYPE_PERIPHERAL,
- .rate_hz = 5000000,
-};
-
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_US0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_US1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_US2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
- .name = "mci_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_MCI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udc_clk = {
- .name = "udc_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_UDP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi_clk = {
- .name = "twi_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TWI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
- .name = "spi0_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_SPI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
- .name = "spi1_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_SPI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc_clk = {
- .name = "ssc_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_SSC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc0_clk = {
- .name = "tc0_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc1_clk = {
- .name = "tc1_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc2_clk = {
- .name = "tc2_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TC2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
- .name = "ohci_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_UHP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
- .name = "pclk",
- .pmc_mask = 1 << AT91SAM9260_ID_EMAC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk isi_clk = {
- .name = "isi_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_ISI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_US3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart4_clk = {
- .name = "usart4_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_US4,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart5_clk = {
- .name = "usart5_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_US5,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc3_clk = {
- .name = "tc3_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TC3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc4_clk = {
- .name = "tc4_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TC4,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc5_clk = {
- .name = "tc5_clk",
- .pmc_mask = 1 << AT91SAM9260_ID_TC5,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
- &pioC_clk,
- &adc_clk,
- &adc_op_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &mmc_clk,
- &udc_clk,
- &twi_clk,
- &spi0_clk,
- &spi1_clk,
- &ssc_clk,
- &tc0_clk,
- &tc1_clk,
- &tc2_clk,
- &ohci_clk,
- &macb_clk,
- &isi_clk,
- &usart3_clk,
- &usart4_clk,
- &usart5_clk,
- &tc3_clk,
- &tc4_clk,
- &tc5_clk,
- // irq0 .. irq2
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- /* One additional fake clock for macb_hclk */
- CLKDEV_CON_ID("hclk", &macb_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tc3_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.1", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.1", &tc5_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi_clk),
- /* more usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "fffb4000.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "fffb8000.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "fffd0000.serial", &usart3_clk),
- CLKDEV_CON_DEV_ID("usart", "fffd4000.serial", &usart4_clk),
- CLKDEV_CON_DEV_ID("usart", "fffd8000.serial", &usart5_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
- /* more tc lookup table for DT entries */
- CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "fffdc000.timer", &tc3_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffdc000.timer", &tc4_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffdc000.timer", &tc5_clk),
- CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &ohci_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffc8000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffcc000.spi", &spi1_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.5", &usart4_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.6", &usart5_clk),
-};
-
-/*
- * The two programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-
-static void __init at91sam9260_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
- clkdev_add_table(usart_clocks_lookups,
- ARRAY_SIZE(usart_clocks_lookups));
-
- clk_register(&pck0);
- clk_register(&pck1);
-}
-#else
-#define at91sam9260_register_clocks NULL
-#endif
-
-/* --------------------------------------------------------------------
- * GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91sam9260_gpio[] __initdata = {
- {
- .id = AT91SAM9260_ID_PIOA,
- .regbase = AT91SAM9260_BASE_PIOA,
- }, {
- .id = AT91SAM9260_ID_PIOB,
- .regbase = AT91SAM9260_BASE_PIOB,
- }, {
- .id = AT91SAM9260_ID_PIOC,
- .regbase = AT91SAM9260_BASE_PIOC,
- }
-};
/* --------------------------------------------------------------------
* AT91SAM9260 processor initialization
@@ -340,119 +48,14 @@ static void __init at91sam9260_map_io(void)
at91_init_sram(0, AT91SAM9260_SRAM_BASE, AT91SAM9260_SRAM_SIZE);
}
-static void __init at91sam9260_ioremap_registers(void)
-{
- at91_ioremap_ramc(0, AT91SAM9260_BASE_SDRAMC, 512);
- at91sam926x_ioremap_pit(AT91SAM9260_BASE_PIT);
- at91sam9_ioremap_smc(0, AT91SAM9260_BASE_SMC);
- at91_ioremap_matrix(AT91SAM9260_BASE_MATRIX);
- at91_pm_set_standby(at91sam9_sdram_standby);
-}
-
static void __init at91sam9260_initialize(void)
{
arm_pm_idle = at91sam9_idle;
at91_sysirq_mask_rtt(AT91SAM9260_BASE_RTT);
-
- /* Register GPIO subsystem */
- at91_gpio_init(at91sam9260_gpio, 3);
-}
-
-static struct resource rstc_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_RSTC,
- .end = AT91SAM9260_BASE_RSTC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9260_BASE_SDRAMC,
- .end = AT91SAM9260_BASE_SDRAMC + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device rstc_device = {
- .name = "at91-sam9260-reset",
- .resource = rstc_resources,
- .num_resources = ARRAY_SIZE(rstc_resources),
-};
-
-static struct resource shdwc_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_SHDWC,
- .end = AT91SAM9260_BASE_SHDWC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device shdwc_device = {
- .name = "at91-poweroff",
- .resource = shdwc_resources,
- .num_resources = ARRAY_SIZE(shdwc_resources),
-};
-
-static void __init at91sam9260_register_devices(void)
-{
- platform_device_register(&rstc_device);
- platform_device_register(&shdwc_device);
-}
-
-/* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91sam9260_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller */
- 7, /* System Peripherals */
- 1, /* Parallel IO Controller A */
- 1, /* Parallel IO Controller B */
- 1, /* Parallel IO Controller C */
- 0, /* Analog-to-Digital Converter */
- 5, /* USART 0 */
- 5, /* USART 1 */
- 5, /* USART 2 */
- 0, /* Multimedia Card Interface */
- 2, /* USB Device Port */
- 6, /* Two-Wire Interface */
- 5, /* Serial Peripheral Interface 0 */
- 5, /* Serial Peripheral Interface 1 */
- 5, /* Serial Synchronous Controller */
- 0,
- 0,
- 0, /* Timer Counter 0 */
- 0, /* Timer Counter 1 */
- 0, /* Timer Counter 2 */
- 2, /* USB Host port */
- 3, /* Ethernet */
- 0, /* Image Sensor Interface */
- 5, /* USART 3 */
- 5, /* USART 4 */
- 5, /* USART 5 */
- 0, /* Timer Counter 3 */
- 0, /* Timer Counter 4 */
- 0, /* Timer Counter 5 */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
-};
-
-static void __init at91sam9260_init_time(void)
-{
- at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
}
AT91_SOC_START(at91sam9260)
.map_io = at91sam9260_map_io,
- .default_irq_priority = at91sam9260_default_irq_priority,
- .extern_irq = (1 << AT91SAM9260_ID_IRQ0) | (1 << AT91SAM9260_ID_IRQ1)
- | (1 << AT91SAM9260_ID_IRQ2),
- .ioremap_registers = at91sam9260_ioremap_registers,
- .register_clocks = at91sam9260_register_clocks,
- .register_devices = at91sam9260_register_devices,
.init = at91sam9260_initialize,
- .init_time = at91sam9260_init_time,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9260_devices.c b/arch/arm/mach-at91/at91sam9260_devices.c
deleted file mode 100644
index ef88e0f..0000000
--- a/arch/arm/mach-at91/at91sam9260_devices.c
+++ /dev/null
@@ -1,1364 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9260_devices.c
- *
- * Copyright (C) 2006 Atmel
- *
- * 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 <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <linux/platform_data/at91_adc.h>
-
-#include <mach/cpu.h>
-#include <mach/at91sam9260.h>
-#include <mach/at91sam9260_matrix.h>
-#include <mach/at91_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-/* --------------------------------------------------------------------
- * USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
- [0] = {
- .start = AT91SAM9260_UHP_BASE,
- .end = AT91SAM9260_UHP_BASE + SZ_1M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_usbh_device = {
- .name = "at91_ohci",
- .id = -1,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &usbh_data,
- },
- .resource = usbh_resources,
- .num_resources = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
- int i;
-
- if (!data)
- return;
-
- /* Enable overcurrent notification */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->overcurrent_pin[i]))
- at91_set_gpio_input(data->overcurrent_pin[i], 1);
- }
-
- usbh_data = *data;
- platform_device_register(&at91_usbh_device);
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE)
-static struct at91_udc_data udc_data;
-
-static struct resource udc_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_UDP,
- .end = AT91SAM9260_BASE_UDP + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_udc_device = {
- .name = "at91_udc",
- .id = -1,
- .dev = {
- .platform_data = &udc_data,
- },
- .resource = udc_resources,
- .num_resources = ARRAY_SIZE(udc_resources),
-};
-
-void __init at91_add_device_udc(struct at91_udc_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->vbus_pin)) {
- at91_set_gpio_input(data->vbus_pin, 0);
- at91_set_deglitch(data->vbus_pin, 1);
- }
-
- /* Pullup pin is handled internally by USB device peripheral */
-
- udc_data = *data;
- platform_device_register(&at91_udc_device);
-}
-#else
-void __init at91_add_device_udc(struct at91_udc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct macb_platform_data eth_data;
-
-static struct resource eth_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_EMAC,
- .end = AT91SAM9260_BASE_EMAC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_eth_device = {
- .name = "macb",
- .id = -1,
- .dev = {
- .dma_mask = &eth_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &eth_data,
- },
- .resource = eth_resources,
- .num_resources = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct macb_platform_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->phy_irq_pin)) {
- at91_set_gpio_input(data->phy_irq_pin, 0);
- at91_set_deglitch(data->phy_irq_pin, 1);
- }
-
- /* Pins used for MII and RMII */
- at91_set_A_periph(AT91_PIN_PA19, 0); /* ETXCK_EREFCK */
- at91_set_A_periph(AT91_PIN_PA17, 0); /* ERXDV */
- at91_set_A_periph(AT91_PIN_PA14, 0); /* ERX0 */
- at91_set_A_periph(AT91_PIN_PA15, 0); /* ERX1 */
- at91_set_A_periph(AT91_PIN_PA18, 0); /* ERXER */
- at91_set_A_periph(AT91_PIN_PA16, 0); /* ETXEN */
- at91_set_A_periph(AT91_PIN_PA12, 0); /* ETX0 */
- at91_set_A_periph(AT91_PIN_PA13, 0); /* ETX1 */
- at91_set_A_periph(AT91_PIN_PA21, 0); /* EMDIO */
- at91_set_A_periph(AT91_PIN_PA20, 0); /* EMDC */
-
- if (!data->is_rmii) {
- at91_set_B_periph(AT91_PIN_PA28, 0); /* ECRS */
- at91_set_B_periph(AT91_PIN_PA29, 0); /* ECOL */
- at91_set_B_periph(AT91_PIN_PA25, 0); /* ERX2 */
- at91_set_B_periph(AT91_PIN_PA26, 0); /* ERX3 */
- at91_set_B_periph(AT91_PIN_PA27, 0); /* ERXCK */
- at91_set_B_periph(AT91_PIN_PA23, 0); /* ETX2 */
- at91_set_B_periph(AT91_PIN_PA24, 0); /* ETX3 */
- at91_set_B_periph(AT91_PIN_PA22, 0); /* ETXER */
- }
-
- eth_data = *data;
- platform_device_register(&at91sam9260_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct macb_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * MMC / SD Slot for Atmel MCI Driver
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct mci_platform_data mmc_data;
-
-static struct resource mmc_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_MCI,
- .end = AT91SAM9260_BASE_MCI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_mmc_device = {
- .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc_data,
- },
- .resource = mmc_resources,
- .num_resources = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
-{
- unsigned int i;
- unsigned int slot_count = 0;
-
- if (!data)
- return;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
- if (data->slot[i].bus_width) {
- /* input/irq */
- if (gpio_is_valid(data->slot[i].detect_pin)) {
- at91_set_gpio_input(data->slot[i].detect_pin, 1);
- at91_set_deglitch(data->slot[i].detect_pin, 1);
- }
- if (gpio_is_valid(data->slot[i].wp_pin))
- at91_set_gpio_input(data->slot[i].wp_pin, 1);
-
- switch (i) {
- case 0:
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA7, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA6, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA9, 1);
- at91_set_A_periph(AT91_PIN_PA10, 1);
- at91_set_A_periph(AT91_PIN_PA11, 1);
- }
- slot_count++;
- break;
- case 1:
- /* CMD */
- at91_set_B_periph(AT91_PIN_PA1, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_B_periph(AT91_PIN_PA0, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_B_periph(AT91_PIN_PA5, 1);
- at91_set_B_periph(AT91_PIN_PA4, 1);
- at91_set_B_periph(AT91_PIN_PA3, 1);
- }
- slot_count++;
- break;
- default:
- printk(KERN_ERR
- "AT91: SD/MMC slot %d not available\n", i);
- break;
- }
- }
- }
-
- if (slot_count) {
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA8, 0);
-
- mmc_data = *data;
- platform_device_register(&at91sam9260_mmc_device);
- }
-}
-#else
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
- [0] = {
- .start = NAND_BASE,
- .end = NAND_BASE + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9260_BASE_ECC,
- .end = AT91SAM9260_BASE_ECC + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9260_nand_device = {
- .name = "atmel_nand",
- .id = -1,
- .dev = {
- .platform_data = &nand_data,
- },
- .resource = nand_resources,
- .num_resources = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
- unsigned long csa;
-
- if (!data)
- return;
-
- csa = at91_matrix_read(AT91_MATRIX_EBICSA);
- at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
-
- /* enable pin */
- if (gpio_is_valid(data->enable_pin))
- at91_set_gpio_output(data->enable_pin, 1);
-
- /* ready/busy pin */
- if (gpio_is_valid(data->rdy_pin))
- at91_set_gpio_input(data->rdy_pin, 1);
-
- /* card detect pin */
- if (gpio_is_valid(data->det_pin))
- at91_set_gpio_input(data->det_pin, 1);
-
- nand_data = *data;
- platform_device_register(&at91sam9260_nand_device);
-}
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
- .sda_pin = AT91_PIN_PA23,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PA24,
- .scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
-};
-
-static struct platform_device at91sam9260_twi_device = {
- .name = "i2c-gpio",
- .id = 0,
- .dev.platform_data = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- at91_set_GPIO_periph(AT91_PIN_PA23, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PA23, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PA24, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PA24, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9260_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_TWI,
- .end = AT91SAM9260_BASE_TWI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_twi_device = {
- .id = 0,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- /* IP version is not the same on 9260 and g20 */
- if (cpu_is_at91sam9g20()) {
- at91sam9260_twi_device.name = "i2c-at91sam9g20";
- } else {
- at91sam9260_twi_device.name = "i2c-at91sam9260";
- }
-
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA23, 1);
-
- at91_set_A_periph(AT91_PIN_PA24, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PA24, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9260_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_SPI0,
- .end = AT91SAM9260_BASE_SPI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_spi0_device = {
- .name = "atmel_spi",
- .id = 0,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi0_resources,
- .num_resources = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PC11, AT91_PIN_PC16, AT91_PIN_PC17 };
-
-static struct resource spi1_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_SPI1,
- .end = AT91SAM9260_BASE_SPI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_spi1_device = {
- .name = "atmel_spi",
- .id = 1,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi1_resources,
- .num_resources = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PC5, AT91_PIN_PC4, AT91_PIN_PC3 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
- int i;
- unsigned long cs_pin;
- short enable_spi0 = 0;
- short enable_spi1 = 0;
-
- /* Choose SPI chip-selects */
- for (i = 0; i < nr_devices; i++) {
- if (devices[i].controller_data)
- cs_pin = (unsigned long) devices[i].controller_data;
- else if (devices[i].bus_num == 0)
- cs_pin = spi0_standard_cs[devices[i].chip_select];
- else
- cs_pin = spi1_standard_cs[devices[i].chip_select];
-
- if (!gpio_is_valid(cs_pin))
- continue;
-
- if (devices[i].bus_num == 0)
- enable_spi0 = 1;
- else
- enable_spi1 = 1;
-
- /* enable chip-select pin */
- at91_set_gpio_output(cs_pin, 1);
-
- /* pass chip-select pin to driver */
- devices[i].controller_data = (void *) cs_pin;
- }
-
- spi_register_board_info(devices, nr_devices);
-
- /* Configure SPI bus(es) */
- if (enable_spi0) {
- at91_set_A_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */
- at91_set_A_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */
- at91_set_A_periph(AT91_PIN_PA2, 0); /* SPI1_SPCK */
-
- platform_device_register(&at91sam9260_spi0_device);
- }
- if (enable_spi1) {
- at91_set_A_periph(AT91_PIN_PB0, 0); /* SPI1_MISO */
- at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI1_MOSI */
- at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI1_SPCK */
-
- platform_device_register(&at91sam9260_spi1_device);
- }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Timer/Counter blocks
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb0_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_TCB0,
- .end = AT91SAM9260_BASE_TCB0 + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_tcb0_device = {
- .name = "atmel_tcb",
- .id = 0,
- .resource = tcb0_resources,
- .num_resources = ARRAY_SIZE(tcb0_resources),
-};
-
-static struct resource tcb1_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_TCB1,
- .end = AT91SAM9260_BASE_TCB1 + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC3,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC4,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_TC5,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_tcb1_device = {
- .name = "atmel_tcb",
- .id = 1,
- .resource = tcb1_resources,
- .num_resources = ARRAY_SIZE(tcb1_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
- platform_device_register(&at91sam9260_tcb0_device);
- platform_device_register(&at91sam9260_tcb1_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- * RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
- {
- .start = AT91SAM9260_BASE_RTT,
- .end = AT91SAM9260_BASE_RTT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_rtt_device = {
- .name = "at91_rtt",
- .id = 0,
- .resource = rtt_resources,
-};
-
-
-#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
-static void __init at91_add_device_rtt_rtc(void)
-{
- at91sam9260_rtt_device.name = "rtc-at91sam9";
- /*
- * The second resource is needed:
- * GPBR will serve as the storage for RTC time offset
- */
- at91sam9260_rtt_device.num_resources = 3;
- rtt_resources[1].start = AT91SAM9260_BASE_GPBR +
- 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
- rtt_resources[1].end = rtt_resources[1].start + 3;
- rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS;
- rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS;
-}
-#else
-static void __init at91_add_device_rtt_rtc(void)
-{
- /* Only one resource is needed: RTT not used as RTC */
- at91sam9260_rtt_device.num_resources = 1;
-}
-#endif
-
-static void __init at91_add_device_rtt(void)
-{
- at91_add_device_rtt_rtc();
- platform_device_register(&at91sam9260_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- * Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
- {
- .start = AT91SAM9260_BASE_WDT,
- .end = AT91SAM9260_BASE_WDT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9260_wdt_device = {
- .name = "at91_wdt",
- .id = -1,
- .resource = wdt_resources,
- .num_resources = ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
- platform_device_register(&at91sam9260_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_SSC,
- .end = AT91SAM9260_BASE_SSC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_SSC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9260_ssc_device = {
- .name = "at91rm9200_ssc",
- .id = 0,
- .dev = {
- .dma_mask = &ssc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc_resources,
- .num_resources = ARRAY_SIZE(ssc_resources),
-};
-
-static inline void configure_ssc_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PB17, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PB16, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PB18, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PB19, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PB20, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PB21, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver. For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
- struct platform_device *pdev;
-
- /*
- * NOTE: caller is responsible for passing information matching
- * "pins" to whatever will be using each particular controller.
- */
- switch (id) {
- case AT91SAM9260_ID_SSC:
- pdev = &at91sam9260_ssc_device;
- configure_ssc_pins(pins);
- break;
- default:
- return;
- }
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * UART
- * -------------------------------------------------------------------- */
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_DBGU,
- .end = AT91SAM9260_BASE_DBGU + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data dbgu_data = {
- .use_dma_tx = 0,
- .use_dma_rx = 0, /* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_dbgu_device = {
- .name = "atmel_usart",
- .id = 0,
- .dev = {
- .dma_mask = &dbgu_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dbgu_data,
- },
- .resource = dbgu_resources,
- .num_resources = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PB14, 0); /* DRXD */
- at91_set_A_periph(AT91_PIN_PB15, 1); /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_US0,
- .end = AT91SAM9260_BASE_US0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_uart0_device = {
- .name = "atmel_usart",
- .id = 1,
- .dev = {
- .dma_mask = &uart0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart0_data,
- },
- .resource = uart0_resources,
- .num_resources = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB4, 1); /* TXD0 */
- at91_set_A_periph(AT91_PIN_PB5, 0); /* RXD0 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PB26, 0); /* RTS0 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PB27, 0); /* CTS0 */
- if (pins & ATMEL_UART_DTR)
- at91_set_A_periph(AT91_PIN_PB24, 0); /* DTR0 */
- if (pins & ATMEL_UART_DSR)
- at91_set_A_periph(AT91_PIN_PB22, 0); /* DSR0 */
- if (pins & ATMEL_UART_DCD)
- at91_set_A_periph(AT91_PIN_PB23, 0); /* DCD0 */
- if (pins & ATMEL_UART_RI)
- at91_set_A_periph(AT91_PIN_PB25, 0); /* RI0 */
-}
-
-static struct resource uart1_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_US1,
- .end = AT91SAM9260_BASE_US1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_uart1_device = {
- .name = "atmel_usart",
- .id = 2,
- .dev = {
- .dma_mask = &uart1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart1_data,
- },
- .resource = uart1_resources,
- .num_resources = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB6, 1); /* TXD1 */
- at91_set_A_periph(AT91_PIN_PB7, 0); /* RXD1 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PB28, 0); /* RTS1 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PB29, 0); /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_US2,
- .end = AT91SAM9260_BASE_US2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_uart2_device = {
- .name = "atmel_usart",
- .id = 3,
- .dev = {
- .dma_mask = &uart2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart2_data,
- },
- .resource = uart2_resources,
- .num_resources = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB8, 1); /* TXD2 */
- at91_set_A_periph(AT91_PIN_PB9, 0); /* RXD2 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PA4, 0); /* RTS2 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PA5, 0); /* CTS2 */
-}
-
-static struct resource uart3_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_US3,
- .end = AT91SAM9260_BASE_US3 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart3_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart3_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_uart3_device = {
- .name = "atmel_usart",
- .id = 4,
- .dev = {
- .dma_mask = &uart3_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart3_data,
- },
- .resource = uart3_resources,
- .num_resources = ARRAY_SIZE(uart3_resources),
-};
-
-static inline void configure_usart3_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB10, 1); /* TXD3 */
- at91_set_A_periph(AT91_PIN_PB11, 0); /* RXD3 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PC8, 0); /* RTS3 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PC10, 0); /* CTS3 */
-}
-
-static struct resource uart4_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_US4,
- .end = AT91SAM9260_BASE_US4 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US4,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart4_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart4_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_uart4_device = {
- .name = "atmel_usart",
- .id = 5,
- .dev = {
- .dma_mask = &uart4_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart4_data,
- },
- .resource = uart4_resources,
- .num_resources = ARRAY_SIZE(uart4_resources),
-};
-
-static inline void configure_usart4_pins(void)
-{
- at91_set_B_periph(AT91_PIN_PA31, 1); /* TXD4 */
- at91_set_B_periph(AT91_PIN_PA30, 0); /* RXD4 */
-}
-
-static struct resource uart5_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_US5,
- .end = AT91SAM9260_BASE_US5 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_US5,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart5_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart5_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9260_uart5_device = {
- .name = "atmel_usart",
- .id = 6,
- .dev = {
- .dma_mask = &uart5_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart5_data,
- },
- .resource = uart5_resources,
- .num_resources = ARRAY_SIZE(uart5_resources),
-};
-
-static inline void configure_usart5_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PB12, 1); /* TXD5 */
- at91_set_A_periph(AT91_PIN_PB13, 0); /* RXD5 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
- struct platform_device *pdev;
- struct atmel_uart_data *pdata;
-
- switch (id) {
- case 0: /* DBGU */
- pdev = &at91sam9260_dbgu_device;
- configure_dbgu_pins();
- break;
- case AT91SAM9260_ID_US0:
- pdev = &at91sam9260_uart0_device;
- configure_usart0_pins(pins);
- break;
- case AT91SAM9260_ID_US1:
- pdev = &at91sam9260_uart1_device;
- configure_usart1_pins(pins);
- break;
- case AT91SAM9260_ID_US2:
- pdev = &at91sam9260_uart2_device;
- configure_usart2_pins(pins);
- break;
- case AT91SAM9260_ID_US3:
- pdev = &at91sam9260_uart3_device;
- configure_usart3_pins(pins);
- break;
- case AT91SAM9260_ID_US4:
- pdev = &at91sam9260_uart4_device;
- configure_usart4_pins();
- break;
- case AT91SAM9260_ID_US5:
- pdev = &at91sam9260_uart5_device;
- configure_usart5_pins();
- break;
- default:
- return;
- }
- pdata = pdev->dev.platform_data;
- pdata->num = portnr; /* update to mapped ID */
-
- if (portnr < ATMEL_MAX_UART)
- at91_uarts[portnr] = pdev;
-}
-
-void __init at91_add_device_serial(void)
-{
- int i;
-
- for (i = 0; i < ATMEL_MAX_UART; i++) {
- if (at91_uarts[i])
- platform_device_register(at91_uarts[i]);
- }
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-/* --------------------------------------------------------------------
- * CF/IDE
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) || \
- defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE)
-
-static struct at91_cf_data cf0_data;
-
-static struct resource cf0_resources[] = {
- [0] = {
- .start = AT91_CHIPSELECT_4,
- .end = AT91_CHIPSELECT_4 + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device cf0_device = {
- .id = 0,
- .dev = {
- .platform_data = &cf0_data,
- },
- .resource = cf0_resources,
- .num_resources = ARRAY_SIZE(cf0_resources),
-};
-
-static struct at91_cf_data cf1_data;
-
-static struct resource cf1_resources[] = {
- [0] = {
- .start = AT91_CHIPSELECT_5,
- .end = AT91_CHIPSELECT_5 + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device cf1_device = {
- .id = 1,
- .dev = {
- .platform_data = &cf1_data,
- },
- .resource = cf1_resources,
- .num_resources = ARRAY_SIZE(cf1_resources),
-};
-
-void __init at91_add_device_cf(struct at91_cf_data *data)
-{
- struct platform_device *pdev;
- unsigned long csa;
-
- if (!data)
- return;
-
- csa = at91_matrix_read(AT91_MATRIX_EBICSA);
-
- switch (data->chipselect) {
- case 4:
- at91_set_multi_drive(AT91_PIN_PC8, 0);
- at91_set_A_periph(AT91_PIN_PC8, 0);
- csa |= AT91_MATRIX_CS4A_SMC_CF1;
- cf0_data = *data;
- pdev = &cf0_device;
- break;
- case 5:
- at91_set_multi_drive(AT91_PIN_PC9, 0);
- at91_set_A_periph(AT91_PIN_PC9, 0);
- csa |= AT91_MATRIX_CS5A_SMC_CF2;
- cf1_data = *data;
- pdev = &cf1_device;
- break;
- default:
- printk(KERN_ERR "AT91 CF: bad chip-select requested (%u)\n",
- data->chipselect);
- return;
- }
-
- at91_matrix_write(AT91_MATRIX_EBICSA, csa);
-
- if (gpio_is_valid(data->rst_pin)) {
- at91_set_multi_drive(data->rst_pin, 0);
- at91_set_gpio_output(data->rst_pin, 1);
- }
-
- if (gpio_is_valid(data->irq_pin)) {
- at91_set_gpio_input(data->irq_pin, 0);
- at91_set_deglitch(data->irq_pin, 1);
- }
-
- if (gpio_is_valid(data->det_pin)) {
- at91_set_gpio_input(data->det_pin, 0);
- at91_set_deglitch(data->det_pin, 1);
- }
-
- at91_set_B_periph(AT91_PIN_PC6, 0); /* CFCE1 */
- at91_set_B_periph(AT91_PIN_PC7, 0); /* CFCE2 */
- at91_set_A_periph(AT91_PIN_PC10, 0); /* CFRNW */
- at91_set_A_periph(AT91_PIN_PC15, 1); /* NWAIT */
-
- if (IS_ENABLED(CONFIG_PATA_AT91) && (data->flags & AT91_CF_TRUE_IDE))
- pdev->name = "pata_at91";
- else
- pdev->name = "at91_cf";
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_cf(struct at91_cf_data * data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * ADCs
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_AT91_ADC)
-static struct at91_adc_data adc_data;
-
-static struct resource adc_resources[] = {
- [0] = {
- .start = AT91SAM9260_BASE_ADC,
- .end = AT91SAM9260_BASE_ADC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9260_ID_ADC,
- .end = NR_IRQS_LEGACY + AT91SAM9260_ID_ADC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_adc_device = {
- .name = "at91sam9260-adc",
- .id = -1,
- .dev = {
- .platform_data = &adc_data,
- },
- .resource = adc_resources,
- .num_resources = ARRAY_SIZE(adc_resources),
-};
-
-static struct at91_adc_trigger at91_adc_triggers[] = {
- [0] = {
- .name = "timer-counter-0",
- .value = 0x1,
- },
- [1] = {
- .name = "timer-counter-1",
- .value = 0x3,
- },
- [2] = {
- .name = "timer-counter-2",
- .value = 0x5,
- },
- [3] = {
- .name = "external",
- .value = 0xd,
- .is_external = true,
- },
-};
-
-void __init at91_add_device_adc(struct at91_adc_data *data)
-{
- if (!data)
- return;
-
- if (test_bit(0, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PC0, 0);
- if (test_bit(1, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PC1, 0);
- if (test_bit(2, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PC2, 0);
- if (test_bit(3, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PC3, 0);
-
- if (data->use_external_triggers)
- at91_set_A_periph(AT91_PIN_PA22, 0);
-
- data->startup_time = 10;
- data->trigger_number = 4;
- data->trigger_list = at91_adc_triggers;
-
- adc_data = *data;
- platform_device_register(&at91_adc_device);
-}
-#else
-void __init at91_add_device_adc(struct at91_adc_data *data) {}
-#endif
-
-/* -------------------------------------------------------------------- */
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
- if (of_have_populated_dt())
- return 0;
-
- at91_add_device_rtt();
- at91_add_device_watchdog();
- at91_add_device_tc();
- return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91sam9261.c b/arch/arm/mach-at91/at91sam9261.c
index a8bd359..d29953e 100644
--- a/arch/arm/mach-at91/at91sam9261.c
+++ b/arch/arm/mach-at91/at91sam9261.c
@@ -10,282 +10,12 @@
*
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/system_misc.h>
#include <mach/cpu.h>
-#include <mach/at91sam9261.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-#include "pm.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_PIOA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_PIOB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
- .name = "pioC_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_PIOC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_US0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_US1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_US2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
- .name = "mci_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_MCI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udc_clk = {
- .name = "udc_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_UDP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi_clk = {
- .name = "twi_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_TWI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
- .name = "spi0_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_SPI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
- .name = "spi1_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_SPI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
- .name = "ssc0_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_SSC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
- .name = "ssc1_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_SSC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc2_clk = {
- .name = "ssc2_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_SSC2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc0_clk = {
- .name = "tc0_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_TC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc1_clk = {
- .name = "tc1_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_TC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc2_clk = {
- .name = "tc2_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_TC2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
- .name = "ohci_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_UHP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
- .name = "lcdc_clk",
- .pmc_mask = 1 << AT91SAM9261_ID_LCDC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-/* HClocks */
-static struct clk hck0 = {
- .name = "hck0",
- .pmc_mask = AT91_PMC_HCK0,
- .type = CLK_TYPE_SYSTEM,
- .id = 0,
-};
-static struct clk hck1 = {
- .name = "hck1",
- .pmc_mask = AT91_PMC_HCK1,
- .type = CLK_TYPE_SYSTEM,
- .id = 1,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
- &pioC_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &mmc_clk,
- &udc_clk,
- &twi_clk,
- &spi0_clk,
- &spi1_clk,
- &ssc0_clk,
- &ssc1_clk,
- &ssc2_clk,
- &tc0_clk,
- &tc1_clk,
- &tc2_clk,
- &ohci_clk,
- &lcdc_clk,
- // irq0 .. irq2
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("hclk", "at91sam9261-lcdfb.0", &hck1),
- CLKDEV_CON_DEV_ID("hclk", "at91sam9g10-lcdfb.0", &hck1),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.2", &ssc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffbc000.ssc", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc2_clk),
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &hck0),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9261.0", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
- /* more lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "ffffb400.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
- CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &hck0),
- CLKDEV_CON_DEV_ID("hclk", "600000.fb", &hck1),
- CLKDEV_CON_DEV_ID("spi_clk", "fffc8000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffcc000.spi", &spi1_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fffa8000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
-};
-
-/*
- * The four programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-static struct clk pck2 = {
- .name = "pck2",
- .pmc_mask = AT91_PMC_PCK2,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 2,
-};
-static struct clk pck3 = {
- .name = "pck3",
- .pmc_mask = AT91_PMC_PCK3,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 3,
-};
-
-static void __init at91sam9261_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
- clkdev_add_table(usart_clocks_lookups,
- ARRAY_SIZE(usart_clocks_lookups));
-
- clk_register(&pck0);
- clk_register(&pck1);
- clk_register(&pck2);
- clk_register(&pck3);
-
- clk_register(&hck0);
- clk_register(&hck1);
-}
-#else
-#define at91sam9261_register_clocks NULL
-#endif
-/* --------------------------------------------------------------------
- * GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91sam9261_gpio[] __initdata = {
- {
- .id = AT91SAM9261_ID_PIOA,
- .regbase = AT91SAM9261_BASE_PIOA,
- }, {
- .id = AT91SAM9261_ID_PIOB,
- .regbase = AT91SAM9261_BASE_PIOB,
- }, {
- .id = AT91SAM9261_ID_PIOC,
- .regbase = AT91SAM9261_BASE_PIOC,
- }
-};
/* --------------------------------------------------------------------
* AT91SAM9261 processor initialization
@@ -299,119 +29,14 @@ static void __init at91sam9261_map_io(void)
at91_init_sram(0, AT91SAM9261_SRAM_BASE, AT91SAM9261_SRAM_SIZE);
}
-static void __init at91sam9261_ioremap_registers(void)
-{
- at91_ioremap_ramc(0, AT91SAM9261_BASE_SDRAMC, 512);
- at91sam926x_ioremap_pit(AT91SAM9261_BASE_PIT);
- at91sam9_ioremap_smc(0, AT91SAM9261_BASE_SMC);
- at91_ioremap_matrix(AT91SAM9261_BASE_MATRIX);
- at91_pm_set_standby(at91sam9_sdram_standby);
-}
-
static void __init at91sam9261_initialize(void)
{
arm_pm_idle = at91sam9_idle;
at91_sysirq_mask_rtt(AT91SAM9261_BASE_RTT);
-
- /* Register GPIO subsystem */
- at91_gpio_init(at91sam9261_gpio, 3);
-}
-
-static struct resource rstc_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_RSTC,
- .end = AT91SAM9261_BASE_RSTC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9261_BASE_SDRAMC,
- .end = AT91SAM9261_BASE_SDRAMC + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device rstc_device = {
- .name = "at91-sam9260-reset",
- .resource = rstc_resources,
- .num_resources = ARRAY_SIZE(rstc_resources),
-};
-
-static struct resource shdwc_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_SHDWC,
- .end = AT91SAM9261_BASE_SHDWC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device shdwc_device = {
- .name = "at91-poweroff",
- .resource = shdwc_resources,
- .num_resources = ARRAY_SIZE(shdwc_resources),
-};
-
-static void __init at91sam9261_register_devices(void)
-{
- platform_device_register(&rstc_device);
- platform_device_register(&shdwc_device);
-}
-
-/* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91sam9261_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller */
- 7, /* System Peripherals */
- 1, /* Parallel IO Controller A */
- 1, /* Parallel IO Controller B */
- 1, /* Parallel IO Controller C */
- 0,
- 5, /* USART 0 */
- 5, /* USART 1 */
- 5, /* USART 2 */
- 0, /* Multimedia Card Interface */
- 2, /* USB Device Port */
- 6, /* Two-Wire Interface */
- 5, /* Serial Peripheral Interface 0 */
- 5, /* Serial Peripheral Interface 1 */
- 4, /* Serial Synchronous Controller 0 */
- 4, /* Serial Synchronous Controller 1 */
- 4, /* Serial Synchronous Controller 2 */
- 0, /* Timer Counter 0 */
- 0, /* Timer Counter 1 */
- 0, /* Timer Counter 2 */
- 2, /* USB Host port */
- 3, /* LCD Controller */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
- 0, /* Advanced Interrupt Controller */
-};
-
-static void __init at91sam9261_init_time(void)
-{
- at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
}
AT91_SOC_START(at91sam9261)
.map_io = at91sam9261_map_io,
- .default_irq_priority = at91sam9261_default_irq_priority,
- .extern_irq = (1 << AT91SAM9261_ID_IRQ0) | (1 << AT91SAM9261_ID_IRQ1)
- | (1 << AT91SAM9261_ID_IRQ2),
- .ioremap_registers = at91sam9261_ioremap_registers,
- .register_clocks = at91sam9261_register_clocks,
- .register_devices = at91sam9261_register_devices,
.init = at91sam9261_initialize,
- .init_time = at91sam9261_init_time,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9261_devices.c b/arch/arm/mach-at91/at91sam9261_devices.c
deleted file mode 100644
index 29baacb..0000000
--- a/arch/arm/mach-at91/at91sam9261_devices.c
+++ /dev/null
@@ -1,1098 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9261_devices.c
- *
- * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- * Copyright (C) 2005 David Brownell
- *
- * 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 <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <linux/fb.h>
-#include <video/atmel_lcdc.h>
-
-#include <mach/at91sam9261.h>
-#include <mach/at91sam9261_matrix.h>
-#include <mach/at91_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-/* --------------------------------------------------------------------
- * USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
- [0] = {
- .start = AT91SAM9261_UHP_BASE,
- .end = AT91SAM9261_UHP_BASE + SZ_1M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_usbh_device = {
- .name = "at91_ohci",
- .id = -1,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &usbh_data,
- },
- .resource = usbh_resources,
- .num_resources = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
- int i;
-
- if (!data)
- return;
-
- /* Enable overcurrent notification */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->overcurrent_pin[i]))
- at91_set_gpio_input(data->overcurrent_pin[i], 1);
- }
-
- usbh_data = *data;
- platform_device_register(&at91sam9261_usbh_device);
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE)
-static struct at91_udc_data udc_data;
-
-static struct resource udc_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_UDP,
- .end = AT91SAM9261_BASE_UDP + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_udc_device = {
- .name = "at91_udc",
- .id = -1,
- .dev = {
- .platform_data = &udc_data,
- },
- .resource = udc_resources,
- .num_resources = ARRAY_SIZE(udc_resources),
-};
-
-void __init at91_add_device_udc(struct at91_udc_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->vbus_pin)) {
- at91_set_gpio_input(data->vbus_pin, 0);
- at91_set_deglitch(data->vbus_pin, 1);
- }
-
- /* Pullup pin is handled internally by USB device peripheral */
-
- udc_data = *data;
- platform_device_register(&at91sam9261_udc_device);
-}
-#else
-void __init at91_add_device_udc(struct at91_udc_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * MMC / SD
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct mci_platform_data mmc_data;
-
-static struct resource mmc_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_MCI,
- .end = AT91SAM9261_BASE_MCI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_mmc_device = {
- .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc_data,
- },
- .resource = mmc_resources,
- .num_resources = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
-{
- if (!data)
- return;
-
- if (data->slot[0].bus_width) {
- /* input/irq */
- if (gpio_is_valid(data->slot[0].detect_pin)) {
- at91_set_gpio_input(data->slot[0].detect_pin, 1);
- at91_set_deglitch(data->slot[0].detect_pin, 1);
- }
- if (gpio_is_valid(data->slot[0].wp_pin))
- at91_set_gpio_input(data->slot[0].wp_pin, 1);
-
- /* CLK */
- at91_set_B_periph(AT91_PIN_PA2, 0);
-
- /* CMD */
- at91_set_B_periph(AT91_PIN_PA1, 1);
-
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_B_periph(AT91_PIN_PA0, 1);
- if (data->slot[0].bus_width == 4) {
- at91_set_B_periph(AT91_PIN_PA4, 1);
- at91_set_B_periph(AT91_PIN_PA5, 1);
- at91_set_B_periph(AT91_PIN_PA6, 1);
- }
-
- mmc_data = *data;
- platform_device_register(&at91sam9261_mmc_device);
- }
-}
-#else
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
- {
- .start = NAND_BASE,
- .end = NAND_BASE + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device atmel_nand_device = {
- .name = "atmel_nand",
- .id = -1,
- .dev = {
- .platform_data = &nand_data,
- },
- .resource = nand_resources,
- .num_resources = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
- unsigned long csa;
-
- if (!data)
- return;
-
- csa = at91_matrix_read(AT91_MATRIX_EBICSA);
- at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
-
- /* enable pin */
- if (gpio_is_valid(data->enable_pin))
- at91_set_gpio_output(data->enable_pin, 1);
-
- /* ready/busy pin */
- if (gpio_is_valid(data->rdy_pin))
- at91_set_gpio_input(data->rdy_pin, 1);
-
- /* card detect pin */
- if (gpio_is_valid(data->det_pin))
- at91_set_gpio_input(data->det_pin, 1);
-
- at91_set_A_periph(AT91_PIN_PC0, 0); /* NANDOE */
- at91_set_A_periph(AT91_PIN_PC1, 0); /* NANDWE */
-
- nand_data = *data;
- platform_device_register(&atmel_nand_device);
-}
-
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
- .sda_pin = AT91_PIN_PA7,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PA8,
- .scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
-};
-
-static struct platform_device at91sam9261_twi_device = {
- .name = "i2c-gpio",
- .id = 0,
- .dev.platform_data = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- at91_set_GPIO_periph(AT91_PIN_PA7, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PA7, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PA8, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PA8, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9261_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_TWI,
- .end = AT91SAM9261_BASE_TWI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_twi_device = {
- .id = 0,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- /* IP version is not the same on 9261 and g10 */
- if (cpu_is_at91sam9g10()) {
- at91sam9261_twi_device.name = "i2c-at91sam9g10";
- /* I2C PIO must not be configured as open-drain on this chip */
- } else {
- at91sam9261_twi_device.name = "i2c-at91sam9261";
- at91_set_multi_drive(AT91_PIN_PA7, 1);
- at91_set_multi_drive(AT91_PIN_PA8, 1);
- }
-
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA7, 0); /* TWD */
- at91_set_A_periph(AT91_PIN_PA8, 0); /* TWCK */
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9261_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_SPI0,
- .end = AT91SAM9261_BASE_SPI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_spi0_device = {
- .name = "atmel_spi",
- .id = 0,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi0_resources,
- .num_resources = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PA5, AT91_PIN_PA6 };
-
-static struct resource spi1_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_SPI1,
- .end = AT91SAM9261_BASE_SPI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_spi1_device = {
- .name = "atmel_spi",
- .id = 1,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi1_resources,
- .num_resources = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB28, AT91_PIN_PA24, AT91_PIN_PA25, AT91_PIN_PA26 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
- int i;
- unsigned long cs_pin;
- short enable_spi0 = 0;
- short enable_spi1 = 0;
-
- /* Choose SPI chip-selects */
- for (i = 0; i < nr_devices; i++) {
- if (devices[i].controller_data)
- cs_pin = (unsigned long) devices[i].controller_data;
- else if (devices[i].bus_num == 0)
- cs_pin = spi0_standard_cs[devices[i].chip_select];
- else
- cs_pin = spi1_standard_cs[devices[i].chip_select];
-
- if (!gpio_is_valid(cs_pin))
- continue;
-
- if (devices[i].bus_num == 0)
- enable_spi0 = 1;
- else
- enable_spi1 = 1;
-
- /* enable chip-select pin */
- at91_set_gpio_output(cs_pin, 1);
-
- /* pass chip-select pin to driver */
- devices[i].controller_data = (void *) cs_pin;
- }
-
- spi_register_board_info(devices, nr_devices);
-
- /* Configure SPI bus(es) */
- if (enable_spi0) {
- at91_set_A_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */
- at91_set_A_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */
- at91_set_A_periph(AT91_PIN_PA2, 0); /* SPI0_SPCK */
-
- platform_device_register(&at91sam9261_spi0_device);
- }
- if (enable_spi1) {
- at91_set_A_periph(AT91_PIN_PB30, 0); /* SPI1_MISO */
- at91_set_A_periph(AT91_PIN_PB31, 0); /* SPI1_MOSI */
- at91_set_A_periph(AT91_PIN_PB29, 0); /* SPI1_SPCK */
-
- platform_device_register(&at91sam9261_spi1_device);
- }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * LCD Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_pdata lcdc_data;
-
-static struct resource lcdc_resources[] = {
- [0] = {
- .start = AT91SAM9261_LCDC_BASE,
- .end = AT91SAM9261_LCDC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
-#if defined(CONFIG_FB_INTSRAM)
- [2] = {
- .start = AT91SAM9261_SRAM_BASE,
- .end = AT91SAM9261_SRAM_BASE + AT91SAM9261_SRAM_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-#endif
-};
-
-static struct platform_device at91_lcdc_device = {
- .id = 0,
- .dev = {
- .dma_mask = &lcdc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &lcdc_data,
- },
- .resource = lcdc_resources,
- .num_resources = ARRAY_SIZE(lcdc_resources),
-};
-
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
-{
- if (!data) {
- return;
- }
-
- if (cpu_is_at91sam9g10())
- at91_lcdc_device.name = "at91sam9g10-lcdfb";
- else
- at91_lcdc_device.name = "at91sam9261-lcdfb";
-
-#if defined(CONFIG_FB_ATMEL_STN)
- at91_set_A_periph(AT91_PIN_PB0, 0); /* LCDVSYNC */
- at91_set_A_periph(AT91_PIN_PB1, 0); /* LCDHSYNC */
- at91_set_A_periph(AT91_PIN_PB2, 0); /* LCDDOTCK */
- at91_set_A_periph(AT91_PIN_PB3, 0); /* LCDDEN */
- at91_set_A_periph(AT91_PIN_PB4, 0); /* LCDCC */
- at91_set_A_periph(AT91_PIN_PB5, 0); /* LCDD0 */
- at91_set_A_periph(AT91_PIN_PB6, 0); /* LCDD1 */
- at91_set_A_periph(AT91_PIN_PB7, 0); /* LCDD2 */
- at91_set_A_periph(AT91_PIN_PB8, 0); /* LCDD3 */
-#else
- at91_set_A_periph(AT91_PIN_PB1, 0); /* LCDHSYNC */
- at91_set_A_periph(AT91_PIN_PB2, 0); /* LCDDOTCK */
- at91_set_A_periph(AT91_PIN_PB3, 0); /* LCDDEN */
- at91_set_A_periph(AT91_PIN_PB4, 0); /* LCDCC */
- at91_set_A_periph(AT91_PIN_PB7, 0); /* LCDD2 */
- at91_set_A_periph(AT91_PIN_PB8, 0); /* LCDD3 */
- at91_set_A_periph(AT91_PIN_PB9, 0); /* LCDD4 */
- at91_set_A_periph(AT91_PIN_PB10, 0); /* LCDD5 */
- at91_set_A_periph(AT91_PIN_PB11, 0); /* LCDD6 */
- at91_set_A_periph(AT91_PIN_PB12, 0); /* LCDD7 */
- at91_set_A_periph(AT91_PIN_PB15, 0); /* LCDD10 */
- at91_set_A_periph(AT91_PIN_PB16, 0); /* LCDD11 */
- at91_set_A_periph(AT91_PIN_PB17, 0); /* LCDD12 */
- at91_set_A_periph(AT91_PIN_PB18, 0); /* LCDD13 */
- at91_set_A_periph(AT91_PIN_PB19, 0); /* LCDD14 */
- at91_set_A_periph(AT91_PIN_PB20, 0); /* LCDD15 */
- at91_set_B_periph(AT91_PIN_PB23, 0); /* LCDD18 */
- at91_set_B_periph(AT91_PIN_PB24, 0); /* LCDD19 */
- at91_set_B_periph(AT91_PIN_PB25, 0); /* LCDD20 */
- at91_set_B_periph(AT91_PIN_PB26, 0); /* LCDD21 */
- at91_set_B_periph(AT91_PIN_PB27, 0); /* LCDD22 */
- at91_set_B_periph(AT91_PIN_PB28, 0); /* LCDD23 */
-#endif
-
- if (ARRAY_SIZE(lcdc_resources) > 2) {
- void __iomem *fb;
- struct resource *fb_res = &lcdc_resources[2];
- size_t fb_len = resource_size(fb_res);
-
- fb = ioremap(fb_res->start, fb_len);
- if (fb) {
- memset(fb, 0, fb_len);
- iounmap(fb);
- }
- }
- lcdc_data = *data;
- platform_device_register(&at91_lcdc_device);
-}
-#else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Timer/Counter block
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_TCB0,
- .end = AT91SAM9261_BASE_TCB0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_tcb_device = {
- .name = "atmel_tcb",
- .id = 0,
- .resource = tcb_resources,
- .num_resources = ARRAY_SIZE(tcb_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
- platform_device_register(&at91sam9261_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- * RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
- {
- .start = AT91SAM9261_BASE_RTT,
- .end = AT91SAM9261_BASE_RTT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91sam9261_rtt_device = {
- .name = "at91_rtt",
- .id = 0,
- .resource = rtt_resources,
-};
-
-#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
-static void __init at91_add_device_rtt_rtc(void)
-{
- at91sam9261_rtt_device.name = "rtc-at91sam9";
- /*
- * The second resource is needed:
- * GPBR will serve as the storage for RTC time offset
- */
- at91sam9261_rtt_device.num_resources = 3;
- rtt_resources[1].start = AT91SAM9261_BASE_GPBR +
- 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
- rtt_resources[1].end = rtt_resources[1].start + 3;
- rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS;
- rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS;
-}
-#else
-static void __init at91_add_device_rtt_rtc(void)
-{
- /* Only one resource is needed: RTT not used as RTC */
- at91sam9261_rtt_device.num_resources = 1;
-}
-#endif
-
-static void __init at91_add_device_rtt(void)
-{
- at91_add_device_rtt_rtc();
- platform_device_register(&at91sam9261_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- * Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
- {
- .start = AT91SAM9261_BASE_WDT,
- .end = AT91SAM9261_BASE_WDT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9261_wdt_device = {
- .name = "at91_wdt",
- .id = -1,
- .resource = wdt_resources,
- .num_resources = ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
- platform_device_register(&at91sam9261_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_SSC0,
- .end = AT91SAM9261_BASE_SSC0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_ssc0_device = {
- .name = "at91rm9200_ssc",
- .id = 0,
- .dev = {
- .dma_mask = &ssc0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc0_resources,
- .num_resources = ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PB21, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PB22, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PB23, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PB24, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PB25, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PB26, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_SSC1,
- .end = AT91SAM9261_BASE_SSC1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_ssc1_device = {
- .name = "at91rm9200_ssc",
- .id = 1,
- .dev = {
- .dma_mask = &ssc1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc1_resources,
- .num_resources = ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_B_periph(AT91_PIN_PA17, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_B_periph(AT91_PIN_PA18, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_B_periph(AT91_PIN_PA19, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_B_periph(AT91_PIN_PA20, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_B_periph(AT91_PIN_PA21, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_B_periph(AT91_PIN_PA22, 1);
-}
-
-static u64 ssc2_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc2_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_SSC2,
- .end = AT91SAM9261_BASE_SSC2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_SSC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9261_ssc2_device = {
- .name = "at91rm9200_ssc",
- .id = 2,
- .dev = {
- .dma_mask = &ssc2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc2_resources,
- .num_resources = ARRAY_SIZE(ssc2_resources),
-};
-
-static inline void configure_ssc2_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_B_periph(AT91_PIN_PC25, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_B_periph(AT91_PIN_PC26, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_B_periph(AT91_PIN_PC27, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_B_periph(AT91_PIN_PC28, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_B_periph(AT91_PIN_PC29, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_B_periph(AT91_PIN_PC30, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver. For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
- struct platform_device *pdev;
-
- /*
- * NOTE: caller is responsible for passing information matching
- * "pins" to whatever will be using each particular controller.
- */
- switch (id) {
- case AT91SAM9261_ID_SSC0:
- pdev = &at91sam9261_ssc0_device;
- configure_ssc0_pins(pins);
- break;
- case AT91SAM9261_ID_SSC1:
- pdev = &at91sam9261_ssc1_device;
- configure_ssc1_pins(pins);
- break;
- case AT91SAM9261_ID_SSC2:
- pdev = &at91sam9261_ssc2_device;
- configure_ssc2_pins(pins);
- break;
- default:
- return;
- }
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_DBGU,
- .end = AT91SAM9261_BASE_DBGU + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data dbgu_data = {
- .use_dma_tx = 0,
- .use_dma_rx = 0, /* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9261_dbgu_device = {
- .name = "atmel_usart",
- .id = 0,
- .dev = {
- .dma_mask = &dbgu_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dbgu_data,
- },
- .resource = dbgu_resources,
- .num_resources = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PA9, 0); /* DRXD */
- at91_set_A_periph(AT91_PIN_PA10, 1); /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_US0,
- .end = AT91SAM9261_BASE_US0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9261_uart0_device = {
- .name = "atmel_usart",
- .id = 1,
- .dev = {
- .dma_mask = &uart0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart0_data,
- },
- .resource = uart0_resources,
- .num_resources = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PC8, 1); /* TXD0 */
- at91_set_A_periph(AT91_PIN_PC9, 0); /* RXD0 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PC10, 0); /* RTS0 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PC11, 0); /* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_US1,
- .end = AT91SAM9261_BASE_US1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9261_uart1_device = {
- .name = "atmel_usart",
- .id = 2,
- .dev = {
- .dma_mask = &uart1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart1_data,
- },
- .resource = uart1_resources,
- .num_resources = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PC12, 1); /* TXD1 */
- at91_set_A_periph(AT91_PIN_PC13, 0); /* RXD1 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PA12, 0); /* RTS1 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PA13, 0); /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
- [0] = {
- .start = AT91SAM9261_BASE_US2,
- .end = AT91SAM9261_BASE_US2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
- .end = NR_IRQS_LEGACY + AT91SAM9261_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9261_uart2_device = {
- .name = "atmel_usart",
- .id = 3,
- .dev = {
- .dma_mask = &uart2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart2_data,
- },
- .resource = uart2_resources,
- .num_resources = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PC15, 0); /* RXD2 */
- at91_set_A_periph(AT91_PIN_PC14, 1); /* TXD2 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PA15, 0); /* RTS2*/
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PA16, 0); /* CTS2 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
- struct platform_device *pdev;
- struct atmel_uart_data *pdata;
-
- switch (id) {
- case 0: /* DBGU */
- pdev = &at91sam9261_dbgu_device;
- configure_dbgu_pins();
- break;
- case AT91SAM9261_ID_US0:
- pdev = &at91sam9261_uart0_device;
- configure_usart0_pins(pins);
- break;
- case AT91SAM9261_ID_US1:
- pdev = &at91sam9261_uart1_device;
- configure_usart1_pins(pins);
- break;
- case AT91SAM9261_ID_US2:
- pdev = &at91sam9261_uart2_device;
- configure_usart2_pins(pins);
- break;
- default:
- return;
- }
- pdata = pdev->dev.platform_data;
- pdata->num = portnr; /* update to mapped ID */
-
- if (portnr < ATMEL_MAX_UART)
- at91_uarts[portnr] = pdev;
-}
-
-void __init at91_add_device_serial(void)
-{
- int i;
-
- for (i = 0; i < ATMEL_MAX_UART; i++) {
- if (at91_uarts[i])
- platform_device_register(at91_uarts[i]);
- }
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
- at91_add_device_rtt();
- at91_add_device_watchdog();
- at91_add_device_tc();
- return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91sam9263.c b/arch/arm/mach-at91/at91sam9263.c
index fbff228..e7ad148 100644
--- a/arch/arm/mach-at91/at91sam9263.c
+++ b/arch/arm/mach-at91/at91sam9263.c
@@ -10,304 +10,11 @@
*
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/system_misc.h>
-#include <mach/at91sam9263.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-#include "pm.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_PIOA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_PIOB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioCDE_clk = {
- .name = "pioCDE_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_PIOCDE,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_US0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_US1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_US2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc0_clk = {
- .name = "mci0_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_MCI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc1_clk = {
- .name = "mci1_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_MCI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk can_clk = {
- .name = "can_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_CAN,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi_clk = {
- .name = "twi_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_TWI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
- .name = "spi0_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_SPI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
- .name = "spi1_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_SPI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
- .name = "ssc0_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_SSC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
- .name = "ssc1_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_SSC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ac97_clk = {
- .name = "ac97_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_AC97C,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb_clk = {
- .name = "tcb_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_TCB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
- .name = "pwm_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_PWMC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
- .name = "pclk",
- .pmc_mask = 1 << AT91SAM9263_ID_EMAC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma_clk = {
- .name = "dma_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_DMA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twodge_clk = {
- .name = "2dge_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_2DGE,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udc_clk = {
- .name = "udc_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_UDP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk isi_clk = {
- .name = "isi_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_ISI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
- .name = "lcdc_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_LCDC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ohci_clk = {
- .name = "ohci_clk",
- .pmc_mask = 1 << AT91SAM9263_ID_UHP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
- &pioCDE_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &mmc0_clk,
- &mmc1_clk,
- &can_clk,
- &twi_clk,
- &spi0_clk,
- &spi1_clk,
- &ssc0_clk,
- &ssc1_clk,
- &ac97_clk,
- &tcb_clk,
- &pwm_clk,
- &macb_clk,
- &twodge_clk,
- &udc_clk,
- &isi_clk,
- &lcdc_clk,
- &dma_clk,
- &ohci_clk,
- // irq0 .. irq1
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- /* One additional fake clock for macb_hclk */
- CLKDEV_CON_ID("hclk", &macb_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "fff98000.ssc", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc1_clk),
- CLKDEV_CON_DEV_ID("hclk", "at91sam9263-lcdfb.0", &lcdc_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9260.0", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &ohci_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioCDE_clk),
- CLKDEV_CON_ID("pioD", &pioCDE_clk),
- CLKDEV_CON_ID("pioE", &pioCDE_clk),
- /* more usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
- /* more tc lookup table for DT entries */
- CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb_clk),
- CLKDEV_CON_DEV_ID("hclk", "a00000.ohci", &ohci_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff84000.mmc", &mmc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioCDE_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCDE_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCDE_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffb8000.pwm", &pwm_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
-};
-
-/*
- * The four programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-static struct clk pck2 = {
- .name = "pck2",
- .pmc_mask = AT91_PMC_PCK2,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 2,
-};
-static struct clk pck3 = {
- .name = "pck3",
- .pmc_mask = AT91_PMC_PCK3,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 3,
-};
-
-static void __init at91sam9263_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
- clkdev_add_table(usart_clocks_lookups,
- ARRAY_SIZE(usart_clocks_lookups));
-
- clk_register(&pck0);
- clk_register(&pck1);
- clk_register(&pck2);
- clk_register(&pck3);
-}
-#else
-#define at91sam9263_register_clocks NULL
-#endif
-
-/* --------------------------------------------------------------------
- * GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91sam9263_gpio[] __initdata = {
- {
- .id = AT91SAM9263_ID_PIOA,
- .regbase = AT91SAM9263_BASE_PIOA,
- }, {
- .id = AT91SAM9263_ID_PIOB,
- .regbase = AT91SAM9263_BASE_PIOB,
- }, {
- .id = AT91SAM9263_ID_PIOCDE,
- .regbase = AT91SAM9263_BASE_PIOC,
- }, {
- .id = AT91SAM9263_ID_PIOCDE,
- .regbase = AT91SAM9263_BASE_PIOD,
- }, {
- .id = AT91SAM9263_ID_PIOCDE,
- .regbase = AT91SAM9263_BASE_PIOE,
- }
-};
/* --------------------------------------------------------------------
* AT91SAM9263 processor initialization
@@ -319,121 +26,15 @@ static void __init at91sam9263_map_io(void)
at91_init_sram(1, AT91SAM9263_SRAM1_BASE, AT91SAM9263_SRAM1_SIZE);
}
-static void __init at91sam9263_ioremap_registers(void)
-{
- at91_ioremap_ramc(0, AT91SAM9263_BASE_SDRAMC0, 512);
- at91_ioremap_ramc(1, AT91SAM9263_BASE_SDRAMC1, 512);
- at91sam926x_ioremap_pit(AT91SAM9263_BASE_PIT);
- at91sam9_ioremap_smc(0, AT91SAM9263_BASE_SMC0);
- at91sam9_ioremap_smc(1, AT91SAM9263_BASE_SMC1);
- at91_ioremap_matrix(AT91SAM9263_BASE_MATRIX);
- at91_pm_set_standby(at91sam9_sdram_standby);
-}
-
static void __init at91sam9263_initialize(void)
{
arm_pm_idle = at91sam9_idle;
at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT0);
at91_sysirq_mask_rtt(AT91SAM9263_BASE_RTT1);
-
- /* Register GPIO subsystem */
- at91_gpio_init(at91sam9263_gpio, 5);
-}
-
-static struct resource rstc_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_RSTC,
- .end = AT91SAM9263_BASE_RSTC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9263_BASE_SDRAMC0,
- .end = AT91SAM9263_BASE_SDRAMC0 + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device rstc_device = {
- .name = "at91-sam9260-reset",
- .resource = rstc_resources,
- .num_resources = ARRAY_SIZE(rstc_resources),
-};
-
-static struct resource shdwc_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_SHDWC,
- .end = AT91SAM9263_BASE_SHDWC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device shdwc_device = {
- .name = "at91-poweroff",
- .resource = shdwc_resources,
- .num_resources = ARRAY_SIZE(shdwc_resources),
-};
-
-static void __init at91sam9263_register_devices(void)
-{
- platform_device_register(&rstc_device);
- platform_device_register(&shdwc_device);
-}
-
-/* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91sam9263_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller (FIQ) */
- 7, /* System Peripherals */
- 1, /* Parallel IO Controller A */
- 1, /* Parallel IO Controller B */
- 1, /* Parallel IO Controller C, D and E */
- 0,
- 0,
- 5, /* USART 0 */
- 5, /* USART 1 */
- 5, /* USART 2 */
- 0, /* Multimedia Card Interface 0 */
- 0, /* Multimedia Card Interface 1 */
- 3, /* CAN */
- 6, /* Two-Wire Interface */
- 5, /* Serial Peripheral Interface 0 */
- 5, /* Serial Peripheral Interface 1 */
- 4, /* Serial Synchronous Controller 0 */
- 4, /* Serial Synchronous Controller 1 */
- 5, /* AC97 Controller */
- 0, /* Timer Counter 0, 1 and 2 */
- 0, /* Pulse Width Modulation Controller */
- 3, /* Ethernet */
- 0,
- 0, /* 2D Graphic Engine */
- 2, /* USB Device Port */
- 0, /* Image Sensor Interface */
- 3, /* LDC Controller */
- 0, /* DMA Controller */
- 0,
- 2, /* USB Host port */
- 0, /* Advanced Interrupt Controller (IRQ0) */
- 0, /* Advanced Interrupt Controller (IRQ1) */
-};
-
-static void __init at91sam9263_init_time(void)
-{
- at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
}
AT91_SOC_START(at91sam9263)
.map_io = at91sam9263_map_io,
- .default_irq_priority = at91sam9263_default_irq_priority,
- .extern_irq = (1 << AT91SAM9263_ID_IRQ0) | (1 << AT91SAM9263_ID_IRQ1),
- .ioremap_registers = at91sam9263_ioremap_registers,
- .register_clocks = at91sam9263_register_clocks,
- .register_devices = at91sam9263_register_devices,
.init = at91sam9263_initialize,
- .init_time = at91sam9263_init_time,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9263_devices.c b/arch/arm/mach-at91/at91sam9263_devices.c
deleted file mode 100644
index cef0e2f..0000000
--- a/arch/arm/mach-at91/at91sam9263_devices.c
+++ /dev/null
@@ -1,1538 +0,0 @@
-/*
- * arch/arm/mach-at91/at91sam9263_devices.c
- *
- * Copyright (C) 2007 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <linux/fb.h>
-#include <video/atmel_lcdc.h>
-
-#include <mach/at91sam9263.h>
-#include <mach/at91sam9263_matrix.h>
-#include <mach/at91_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-/* --------------------------------------------------------------------
- * USB Host
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_data;
-
-static struct resource usbh_resources[] = {
- [0] = {
- .start = AT91SAM9263_UHP_BASE,
- .end = AT91SAM9263_UHP_BASE + SZ_1M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UHP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_usbh_device = {
- .name = "at91_ohci",
- .id = -1,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &usbh_data,
- },
- .resource = usbh_resources,
- .num_resources = ARRAY_SIZE(usbh_resources),
-};
-
-void __init at91_add_device_usbh(struct at91_usbh_data *data)
-{
- int i;
-
- if (!data)
- return;
-
- /* Enable VBus control for UHP ports */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->vbus_pin[i]))
- at91_set_gpio_output(data->vbus_pin[i],
- data->vbus_pin_active_low[i]);
- }
-
- /* Enable overcurrent notification */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->overcurrent_pin[i]))
- at91_set_gpio_input(data->overcurrent_pin[i], 1);
- }
-
- usbh_data = *data;
- platform_device_register(&at91_usbh_device);
-}
-#else
-void __init at91_add_device_usbh(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_AT91) || defined(CONFIG_USB_AT91_MODULE)
-static struct at91_udc_data udc_data;
-
-static struct resource udc_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_UDP,
- .end = AT91SAM9263_BASE_UDP + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_UDP,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_udc_device = {
- .name = "at91_udc",
- .id = -1,
- .dev = {
- .platform_data = &udc_data,
- },
- .resource = udc_resources,
- .num_resources = ARRAY_SIZE(udc_resources),
-};
-
-void __init at91_add_device_udc(struct at91_udc_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->vbus_pin)) {
- at91_set_gpio_input(data->vbus_pin, 0);
- at91_set_deglitch(data->vbus_pin, 1);
- }
-
- /* Pullup pin is handled internally by USB device peripheral */
-
- udc_data = *data;
- platform_device_register(&at91_udc_device);
-}
-#else
-void __init at91_add_device_udc(struct at91_udc_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct macb_platform_data eth_data;
-
-static struct resource eth_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_EMAC,
- .end = AT91SAM9263_BASE_EMAC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_eth_device = {
- .name = "macb",
- .id = -1,
- .dev = {
- .dma_mask = &eth_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &eth_data,
- },
- .resource = eth_resources,
- .num_resources = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct macb_platform_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->phy_irq_pin)) {
- at91_set_gpio_input(data->phy_irq_pin, 0);
- at91_set_deglitch(data->phy_irq_pin, 1);
- }
-
- /* Pins used for MII and RMII */
- at91_set_A_periph(AT91_PIN_PE21, 0); /* ETXCK_EREFCK */
- at91_set_B_periph(AT91_PIN_PC25, 0); /* ERXDV */
- at91_set_A_periph(AT91_PIN_PE25, 0); /* ERX0 */
- at91_set_A_periph(AT91_PIN_PE26, 0); /* ERX1 */
- at91_set_A_periph(AT91_PIN_PE27, 0); /* ERXER */
- at91_set_A_periph(AT91_PIN_PE28, 0); /* ETXEN */
- at91_set_A_periph(AT91_PIN_PE23, 0); /* ETX0 */
- at91_set_A_periph(AT91_PIN_PE24, 0); /* ETX1 */
- at91_set_A_periph(AT91_PIN_PE30, 0); /* EMDIO */
- at91_set_A_periph(AT91_PIN_PE29, 0); /* EMDC */
-
- if (!data->is_rmii) {
- at91_set_A_periph(AT91_PIN_PE22, 0); /* ECRS */
- at91_set_B_periph(AT91_PIN_PC26, 0); /* ECOL */
- at91_set_B_periph(AT91_PIN_PC22, 0); /* ERX2 */
- at91_set_B_periph(AT91_PIN_PC23, 0); /* ERX3 */
- at91_set_B_periph(AT91_PIN_PC27, 0); /* ERXCK */
- at91_set_B_periph(AT91_PIN_PC20, 0); /* ETX2 */
- at91_set_B_periph(AT91_PIN_PC21, 0); /* ETX3 */
- at91_set_B_periph(AT91_PIN_PC24, 0); /* ETXER */
- }
-
- eth_data = *data;
- platform_device_register(&at91sam9263_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct macb_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * MMC / SD
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct mci_platform_data mmc0_data, mmc1_data;
-
-static struct resource mmc0_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_MCI0,
- .end = AT91SAM9263_BASE_MCI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_mmc0_device = {
- .name = "atmel_mci",
- .id = 0,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc0_data,
- },
- .resource = mmc0_resources,
- .num_resources = ARRAY_SIZE(mmc0_resources),
-};
-
-static struct resource mmc1_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_MCI1,
- .end = AT91SAM9263_BASE_MCI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_MCI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_mmc1_device = {
- .name = "atmel_mci",
- .id = 1,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc1_data,
- },
- .resource = mmc1_resources,
- .num_resources = ARRAY_SIZE(mmc1_resources),
-};
-
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
-{
- unsigned int i;
- unsigned int slot_count = 0;
-
- if (!data)
- return;
-
- for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
-
- if (!data->slot[i].bus_width)
- continue;
-
- /* input/irq */
- if (gpio_is_valid(data->slot[i].detect_pin)) {
- at91_set_gpio_input(data->slot[i].detect_pin,
- 1);
- at91_set_deglitch(data->slot[i].detect_pin,
- 1);
- }
- if (gpio_is_valid(data->slot[i].wp_pin))
- at91_set_gpio_input(data->slot[i].wp_pin, 1);
-
- if (mmc_id == 0) { /* MCI0 */
- switch (i) {
- case 0: /* slot A */
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA1, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA0, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA3, 1);
- at91_set_A_periph(AT91_PIN_PA4, 1);
- at91_set_A_periph(AT91_PIN_PA5, 1);
- }
- slot_count++;
- break;
- case 1: /* slot B */
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA16, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA17, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA18, 1);
- at91_set_A_periph(AT91_PIN_PA19, 1);
- at91_set_A_periph(AT91_PIN_PA20, 1);
- }
- slot_count++;
- break;
- default:
- printk(KERN_ERR
- "AT91: SD/MMC slot %d not available\n", i);
- break;
- }
- if (slot_count) {
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA12, 0);
-
- mmc0_data = *data;
- platform_device_register(&at91sam9263_mmc0_device);
- }
- } else if (mmc_id == 1) { /* MCI1 */
- switch (i) {
- case 0: /* slot A */
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA7, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA8, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA9, 1);
- at91_set_A_periph(AT91_PIN_PA10, 1);
- at91_set_A_periph(AT91_PIN_PA11, 1);
- }
- slot_count++;
- break;
- case 1: /* slot B */
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA21, 1);
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA22, 1);
- if (data->slot[i].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA23, 1);
- at91_set_A_periph(AT91_PIN_PA24, 1);
- at91_set_A_periph(AT91_PIN_PA25, 1);
- }
- slot_count++;
- break;
- default:
- printk(KERN_ERR
- "AT91: SD/MMC slot %d not available\n", i);
- break;
- }
- if (slot_count) {
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA6, 0);
-
- mmc1_data = *data;
- platform_device_register(&at91sam9263_mmc1_device);
- }
- }
- }
-}
-#else
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * Compact Flash (PCMCIA or IDE)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_PATA_AT91) || defined(CONFIG_PATA_AT91_MODULE) || \
- defined(CONFIG_AT91_CF) || defined(CONFIG_AT91_CF_MODULE)
-
-static struct at91_cf_data cf0_data;
-
-static struct resource cf0_resources[] = {
- [0] = {
- .start = AT91_CHIPSELECT_4,
- .end = AT91_CHIPSELECT_4 + SZ_256M - 1,
- .flags = IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT,
- }
-};
-
-static struct platform_device cf0_device = {
- .id = 0,
- .dev = {
- .platform_data = &cf0_data,
- },
- .resource = cf0_resources,
- .num_resources = ARRAY_SIZE(cf0_resources),
-};
-
-static struct at91_cf_data cf1_data;
-
-static struct resource cf1_resources[] = {
- [0] = {
- .start = AT91_CHIPSELECT_5,
- .end = AT91_CHIPSELECT_5 + SZ_256M - 1,
- .flags = IORESOURCE_MEM | IORESOURCE_MEM_8AND16BIT,
- }
-};
-
-static struct platform_device cf1_device = {
- .id = 1,
- .dev = {
- .platform_data = &cf1_data,
- },
- .resource = cf1_resources,
- .num_resources = ARRAY_SIZE(cf1_resources),
-};
-
-void __init at91_add_device_cf(struct at91_cf_data *data)
-{
- unsigned long ebi0_csa;
- struct platform_device *pdev;
-
- if (!data)
- return;
-
- /*
- * assign CS4 or CS5 to SMC with Compact Flash logic support,
- * we assume SMC timings are configured by board code,
- * except True IDE where timings are controlled by driver
- */
- ebi0_csa = at91_matrix_read(AT91_MATRIX_EBI0CSA);
- switch (data->chipselect) {
- case 4:
- at91_set_A_periph(AT91_PIN_PD6, 0); /* EBI0_NCS4/CFCS0 */
- ebi0_csa |= AT91_MATRIX_EBI0_CS4A_SMC_CF1;
- cf0_data = *data;
- pdev = &cf0_device;
- break;
- case 5:
- at91_set_A_periph(AT91_PIN_PD7, 0); /* EBI0_NCS5/CFCS1 */
- ebi0_csa |= AT91_MATRIX_EBI0_CS5A_SMC_CF2;
- cf1_data = *data;
- pdev = &cf1_device;
- break;
- default:
- printk(KERN_ERR "AT91 CF: bad chip-select requested (%u)\n",
- data->chipselect);
- return;
- }
- at91_matrix_write(AT91_MATRIX_EBI0CSA, ebi0_csa);
-
- if (gpio_is_valid(data->det_pin)) {
- at91_set_gpio_input(data->det_pin, 1);
- at91_set_deglitch(data->det_pin, 1);
- }
-
- if (gpio_is_valid(data->irq_pin)) {
- at91_set_gpio_input(data->irq_pin, 1);
- at91_set_deglitch(data->irq_pin, 1);
- }
-
- if (gpio_is_valid(data->vcc_pin))
- /* initially off */
- at91_set_gpio_output(data->vcc_pin, 0);
-
- /* enable EBI controlled pins */
- at91_set_A_periph(AT91_PIN_PD5, 1); /* NWAIT */
- at91_set_A_periph(AT91_PIN_PD8, 0); /* CFCE1 */
- at91_set_A_periph(AT91_PIN_PD9, 0); /* CFCE2 */
- at91_set_A_periph(AT91_PIN_PD14, 0); /* CFNRW */
-
- pdev->name = (data->flags & AT91_CF_TRUE_IDE) ? "pata_at91" : "at91_cf";
- platform_device_register(pdev);
-}
-#else
-void __init at91_add_device_cf(struct at91_cf_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
- [0] = {
- .start = NAND_BASE,
- .end = NAND_BASE + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9263_BASE_ECC0,
- .end = AT91SAM9263_BASE_ECC0 + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9263_nand_device = {
- .name = "atmel_nand",
- .id = -1,
- .dev = {
- .platform_data = &nand_data,
- },
- .resource = nand_resources,
- .num_resources = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
- unsigned long csa;
-
- if (!data)
- return;
-
- csa = at91_matrix_read(AT91_MATRIX_EBI0CSA);
- at91_matrix_write(AT91_MATRIX_EBI0CSA, csa | AT91_MATRIX_EBI0_CS3A_SMC_SMARTMEDIA);
-
- /* enable pin */
- if (gpio_is_valid(data->enable_pin))
- at91_set_gpio_output(data->enable_pin, 1);
-
- /* ready/busy pin */
- if (gpio_is_valid(data->rdy_pin))
- at91_set_gpio_input(data->rdy_pin, 1);
-
- /* card detect pin */
- if (gpio_is_valid(data->det_pin))
- at91_set_gpio_input(data->det_pin, 1);
-
- nand_data = *data;
- platform_device_register(&at91sam9263_nand_device);
-}
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
- .sda_pin = AT91_PIN_PB4,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PB5,
- .scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
-};
-
-static struct platform_device at91sam9263_twi_device = {
- .name = "i2c-gpio",
- .id = 0,
- .dev.platform_data = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- at91_set_GPIO_periph(AT91_PIN_PB4, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PB4, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PB5, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PB5, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9263_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_TWI,
- .end = AT91SAM9263_BASE_TWI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TWI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_twi_device = {
- .name = "i2c-at91sam9260",
- .id = 0,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PB4, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PB4, 1);
-
- at91_set_A_periph(AT91_PIN_PB5, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PB5, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9263_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_SPI0,
- .end = AT91SAM9263_BASE_SPI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_spi0_device = {
- .name = "atmel_spi",
- .id = 0,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi0_resources,
- .num_resources = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PA5, AT91_PIN_PA3, AT91_PIN_PA4, AT91_PIN_PB11 };
-
-static struct resource spi1_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_SPI1,
- .end = AT91SAM9263_BASE_SPI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_spi1_device = {
- .name = "atmel_spi",
- .id = 1,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi1_resources,
- .num_resources = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB15, AT91_PIN_PB16, AT91_PIN_PB17, AT91_PIN_PB18 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
- int i;
- unsigned long cs_pin;
- short enable_spi0 = 0;
- short enable_spi1 = 0;
-
- /* Choose SPI chip-selects */
- for (i = 0; i < nr_devices; i++) {
- if (devices[i].controller_data)
- cs_pin = (unsigned long) devices[i].controller_data;
- else if (devices[i].bus_num == 0)
- cs_pin = spi0_standard_cs[devices[i].chip_select];
- else
- cs_pin = spi1_standard_cs[devices[i].chip_select];
-
- if (!gpio_is_valid(cs_pin))
- continue;
-
- if (devices[i].bus_num == 0)
- enable_spi0 = 1;
- else
- enable_spi1 = 1;
-
- /* enable chip-select pin */
- at91_set_gpio_output(cs_pin, 1);
-
- /* pass chip-select pin to driver */
- devices[i].controller_data = (void *) cs_pin;
- }
-
- spi_register_board_info(devices, nr_devices);
-
- /* Configure SPI bus(es) */
- if (enable_spi0) {
- at91_set_B_periph(AT91_PIN_PA0, 0); /* SPI0_MISO */
- at91_set_B_periph(AT91_PIN_PA1, 0); /* SPI0_MOSI */
- at91_set_B_periph(AT91_PIN_PA2, 0); /* SPI0_SPCK */
-
- platform_device_register(&at91sam9263_spi0_device);
- }
- if (enable_spi1) {
- at91_set_A_periph(AT91_PIN_PB12, 0); /* SPI1_MISO */
- at91_set_A_periph(AT91_PIN_PB13, 0); /* SPI1_MOSI */
- at91_set_A_periph(AT91_PIN_PB14, 0); /* SPI1_SPCK */
-
- platform_device_register(&at91sam9263_spi1_device);
- }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * AC97
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SND_ATMEL_AC97C) || defined(CONFIG_SND_ATMEL_AC97C_MODULE)
-static u64 ac97_dmamask = DMA_BIT_MASK(32);
-static struct ac97c_platform_data ac97_data;
-
-static struct resource ac97_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_AC97C,
- .end = AT91SAM9263_BASE_AC97C + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_AC97C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_ac97_device = {
- .name = "atmel_ac97c",
- .id = 0,
- .dev = {
- .dma_mask = &ac97_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &ac97_data,
- },
- .resource = ac97_resources,
- .num_resources = ARRAY_SIZE(ac97_resources),
-};
-
-void __init at91_add_device_ac97(struct ac97c_platform_data *data)
-{
- if (!data)
- return;
-
- at91_set_A_periph(AT91_PIN_PB0, 0); /* AC97FS */
- at91_set_A_periph(AT91_PIN_PB1, 0); /* AC97CK */
- at91_set_A_periph(AT91_PIN_PB2, 0); /* AC97TX */
- at91_set_A_periph(AT91_PIN_PB3, 0); /* AC97RX */
-
- /* reset */
- if (gpio_is_valid(data->reset_pin))
- at91_set_gpio_output(data->reset_pin, 0);
-
- ac97_data = *data;
- platform_device_register(&at91sam9263_ac97_device);
-}
-#else
-void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * CAN Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_CAN_AT91) || defined(CONFIG_CAN_AT91_MODULE)
-static struct resource can_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_CAN,
- .end = AT91SAM9263_BASE_CAN + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_CAN,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_can_device = {
- .name = "at91_can",
- .id = -1,
- .resource = can_resources,
- .num_resources = ARRAY_SIZE(can_resources),
-};
-
-void __init at91_add_device_can(struct at91_can_data *data)
-{
- at91_set_A_periph(AT91_PIN_PA13, 0); /* CANTX */
- at91_set_A_periph(AT91_PIN_PA14, 0); /* CANRX */
- at91sam9263_can_device.dev.platform_data = data;
-
- platform_device_register(&at91sam9263_can_device);
-}
-#else
-void __init at91_add_device_can(struct at91_can_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * LCD Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_pdata lcdc_data;
-
-static struct resource lcdc_resources[] = {
- [0] = {
- .start = AT91SAM9263_LCDC_BASE,
- .end = AT91SAM9263_LCDC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_lcdc_device = {
- .name = "at91sam9263-lcdfb",
- .id = 0,
- .dev = {
- .dma_mask = &lcdc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &lcdc_data,
- },
- .resource = lcdc_resources,
- .num_resources = ARRAY_SIZE(lcdc_resources),
-};
-
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
-{
- if (!data)
- return;
-
- at91_set_A_periph(AT91_PIN_PC1, 0); /* LCDHSYNC */
- at91_set_A_periph(AT91_PIN_PC2, 0); /* LCDDOTCK */
- at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDDEN */
- at91_set_B_periph(AT91_PIN_PB9, 0); /* LCDCC */
- at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDD2 */
- at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDD3 */
- at91_set_A_periph(AT91_PIN_PC8, 0); /* LCDD4 */
- at91_set_A_periph(AT91_PIN_PC9, 0); /* LCDD5 */
- at91_set_A_periph(AT91_PIN_PC10, 0); /* LCDD6 */
- at91_set_A_periph(AT91_PIN_PC11, 0); /* LCDD7 */
- at91_set_A_periph(AT91_PIN_PC14, 0); /* LCDD10 */
- at91_set_A_periph(AT91_PIN_PC15, 0); /* LCDD11 */
- at91_set_A_periph(AT91_PIN_PC16, 0); /* LCDD12 */
- at91_set_B_periph(AT91_PIN_PC12, 0); /* LCDD13 */
- at91_set_A_periph(AT91_PIN_PC18, 0); /* LCDD14 */
- at91_set_A_periph(AT91_PIN_PC19, 0); /* LCDD15 */
- at91_set_A_periph(AT91_PIN_PC22, 0); /* LCDD18 */
- at91_set_A_periph(AT91_PIN_PC23, 0); /* LCDD19 */
- at91_set_A_periph(AT91_PIN_PC24, 0); /* LCDD20 */
- at91_set_B_periph(AT91_PIN_PC17, 0); /* LCDD21 */
- at91_set_A_periph(AT91_PIN_PC26, 0); /* LCDD22 */
- at91_set_A_periph(AT91_PIN_PC27, 0); /* LCDD23 */
-
- lcdc_data = *data;
- platform_device_register(&at91_lcdc_device);
-}
-#else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Image Sensor Interface
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_VIDEO_AT91_ISI) || defined(CONFIG_VIDEO_AT91_ISI_MODULE)
-
-struct resource isi_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_ISI,
- .end = AT91SAM9263_BASE_ISI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_ISI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_isi_device = {
- .name = "at91_isi",
- .id = -1,
- .resource = isi_resources,
- .num_resources = ARRAY_SIZE(isi_resources),
-};
-
-void __init at91_add_device_isi(struct isi_platform_data *data,
- bool use_pck_as_mck)
-{
- at91_set_A_periph(AT91_PIN_PE0, 0); /* ISI_D0 */
- at91_set_A_periph(AT91_PIN_PE1, 0); /* ISI_D1 */
- at91_set_A_periph(AT91_PIN_PE2, 0); /* ISI_D2 */
- at91_set_A_periph(AT91_PIN_PE3, 0); /* ISI_D3 */
- at91_set_A_periph(AT91_PIN_PE4, 0); /* ISI_D4 */
- at91_set_A_periph(AT91_PIN_PE5, 0); /* ISI_D5 */
- at91_set_A_periph(AT91_PIN_PE6, 0); /* ISI_D6 */
- at91_set_A_periph(AT91_PIN_PE7, 0); /* ISI_D7 */
- at91_set_A_periph(AT91_PIN_PE8, 0); /* ISI_PCK */
- at91_set_A_periph(AT91_PIN_PE9, 0); /* ISI_HSYNC */
- at91_set_A_periph(AT91_PIN_PE10, 0); /* ISI_VSYNC */
- at91_set_B_periph(AT91_PIN_PE12, 0); /* ISI_PD8 */
- at91_set_B_periph(AT91_PIN_PE13, 0); /* ISI_PD9 */
- at91_set_B_periph(AT91_PIN_PE14, 0); /* ISI_PD10 */
- at91_set_B_periph(AT91_PIN_PE15, 0); /* ISI_PD11 */
-
- if (use_pck_as_mck) {
- at91_set_B_periph(AT91_PIN_PE11, 0); /* ISI_MCK (PCK3) */
-
- /* TODO: register the PCK for ISI_MCK and set its parent */
- }
-}
-#else
-void __init at91_add_device_isi(struct isi_platform_data *data,
- bool use_pck_as_mck) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Timer/Counter block
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_TCB0,
- .end = AT91SAM9263_BASE_TCB0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_TCB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_tcb_device = {
- .name = "atmel_tcb",
- .id = 0,
- .resource = tcb_resources,
- .num_resources = ARRAY_SIZE(tcb_resources),
-};
-
-#if defined(CONFIG_OF)
-static struct of_device_id tcb_ids[] = {
- { .compatible = "atmel,at91rm9200-tcb" },
- { /*sentinel*/ }
-};
-#endif
-
-static void __init at91_add_device_tc(void)
-{
-#if defined(CONFIG_OF)
- struct device_node *np;
-
- np = of_find_matching_node(NULL, tcb_ids);
- if (np) {
- of_node_put(np);
- return;
- }
-#endif
-
- platform_device_register(&at91sam9263_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- * RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt0_resources[] = {
- {
- .start = AT91SAM9263_BASE_RTT0,
- .end = AT91SAM9263_BASE_RTT0 + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91sam9263_rtt0_device = {
- .name = "at91_rtt",
- .id = 0,
- .resource = rtt0_resources,
-};
-
-static struct resource rtt1_resources[] = {
- {
- .start = AT91SAM9263_BASE_RTT1,
- .end = AT91SAM9263_BASE_RTT1 + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91sam9263_rtt1_device = {
- .name = "at91_rtt",
- .id = 1,
- .resource = rtt1_resources,
-};
-
-#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
-static void __init at91_add_device_rtt_rtc(void)
-{
- struct platform_device *pdev;
- struct resource *r;
-
- switch (CONFIG_RTC_DRV_AT91SAM9_RTT) {
- case 0:
- /*
- * The second resource is needed only for the chosen RTT:
- * GPBR will serve as the storage for RTC time offset
- */
- at91sam9263_rtt0_device.num_resources = 3;
- at91sam9263_rtt1_device.num_resources = 1;
- pdev = &at91sam9263_rtt0_device;
- r = rtt0_resources;
- break;
- case 1:
- at91sam9263_rtt0_device.num_resources = 1;
- at91sam9263_rtt1_device.num_resources = 3;
- pdev = &at91sam9263_rtt1_device;
- r = rtt1_resources;
- break;
- default:
- pr_err("at91sam9263: only supports 2 RTT (%d)\n",
- CONFIG_RTC_DRV_AT91SAM9_RTT);
- return;
- }
-
- pdev->name = "rtc-at91sam9";
- r[1].start = AT91SAM9263_BASE_GPBR + 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
- r[1].end = r[1].start + 3;
- r[2].start = NR_IRQS_LEGACY + AT91_ID_SYS;
- r[2].end = NR_IRQS_LEGACY + AT91_ID_SYS;
-}
-#else
-static void __init at91_add_device_rtt_rtc(void)
-{
- /* Only one resource is needed: RTT not used as RTC */
- at91sam9263_rtt0_device.num_resources = 1;
- at91sam9263_rtt1_device.num_resources = 1;
-}
-#endif
-
-static void __init at91_add_device_rtt(void)
-{
- at91_add_device_rtt_rtc();
- platform_device_register(&at91sam9263_rtt0_device);
- platform_device_register(&at91sam9263_rtt1_device);
-}
-
-
-/* --------------------------------------------------------------------
- * Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
- {
- .start = AT91SAM9263_BASE_WDT,
- .end = AT91SAM9263_BASE_WDT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9263_wdt_device = {
- .name = "at91_wdt",
- .id = -1,
- .resource = wdt_resources,
- .num_resources = ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
- platform_device_register(&at91sam9263_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * PWM
- * --------------------------------------------------------------------*/
-
-#if IS_ENABLED(CONFIG_PWM_ATMEL)
-static struct resource pwm_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_PWMC,
- .end = AT91SAM9263_BASE_PWMC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_PWMC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_pwm0_device = {
- .name = "at91sam9rl-pwm",
- .id = -1,
- .resource = pwm_resources,
- .num_resources = ARRAY_SIZE(pwm_resources),
-};
-
-void __init at91_add_device_pwm(u32 mask)
-{
- if (mask & (1 << AT91_PWM0))
- at91_set_B_periph(AT91_PIN_PB7, 1); /* enable PWM0 */
-
- if (mask & (1 << AT91_PWM1))
- at91_set_B_periph(AT91_PIN_PB8, 1); /* enable PWM1 */
-
- if (mask & (1 << AT91_PWM2))
- at91_set_B_periph(AT91_PIN_PC29, 1); /* enable PWM2 */
-
- if (mask & (1 << AT91_PWM3))
- at91_set_B_periph(AT91_PIN_PB29, 1); /* enable PWM3 */
-
- platform_device_register(&at91sam9263_pwm0_device);
-}
-#else
-void __init at91_add_device_pwm(u32 mask) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_SSC0,
- .end = AT91SAM9263_BASE_SSC0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_ssc0_device = {
- .name = "at91rm9200_ssc",
- .id = 0,
- .dev = {
- .dma_mask = &ssc0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc0_resources,
- .num_resources = ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_B_periph(AT91_PIN_PB0, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_B_periph(AT91_PIN_PB1, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_B_periph(AT91_PIN_PB2, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_B_periph(AT91_PIN_PB3, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_B_periph(AT91_PIN_PB4, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_B_periph(AT91_PIN_PB5, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_SSC1,
- .end = AT91SAM9263_BASE_SSC1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9263_ssc1_device = {
- .name = "at91rm9200_ssc",
- .id = 1,
- .dev = {
- .dma_mask = &ssc1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc1_resources,
- .num_resources = ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PB6, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PB7, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PB8, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PB9, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PB10, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PB11, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver. For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
- struct platform_device *pdev;
-
- /*
- * NOTE: caller is responsible for passing information matching
- * "pins" to whatever will be using each particular controller.
- */
- switch (id) {
- case AT91SAM9263_ID_SSC0:
- pdev = &at91sam9263_ssc0_device;
- configure_ssc0_pins(pins);
- break;
- case AT91SAM9263_ID_SSC1:
- pdev = &at91sam9263_ssc1_device;
- configure_ssc1_pins(pins);
- break;
- default:
- return;
- }
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-
-static struct resource dbgu_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_DBGU,
- .end = AT91SAM9263_BASE_DBGU + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data dbgu_data = {
- .use_dma_tx = 0,
- .use_dma_rx = 0, /* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9263_dbgu_device = {
- .name = "atmel_usart",
- .id = 0,
- .dev = {
- .dma_mask = &dbgu_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dbgu_data,
- },
- .resource = dbgu_resources,
- .num_resources = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PC30, 0); /* DRXD */
- at91_set_A_periph(AT91_PIN_PC31, 1); /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_US0,
- .end = AT91SAM9263_BASE_US0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9263_uart0_device = {
- .name = "atmel_usart",
- .id = 1,
- .dev = {
- .dma_mask = &uart0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart0_data,
- },
- .resource = uart0_resources,
- .num_resources = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PA26, 1); /* TXD0 */
- at91_set_A_periph(AT91_PIN_PA27, 0); /* RXD0 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PA28, 0); /* RTS0 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PA29, 0); /* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_US1,
- .end = AT91SAM9263_BASE_US1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9263_uart1_device = {
- .name = "atmel_usart",
- .id = 2,
- .dev = {
- .dma_mask = &uart1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart1_data,
- },
- .resource = uart1_resources,
- .num_resources = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PD0, 1); /* TXD1 */
- at91_set_A_periph(AT91_PIN_PD1, 0); /* RXD1 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PD7, 0); /* RTS1 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PD8, 0); /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
- [0] = {
- .start = AT91SAM9263_BASE_US2,
- .end = AT91SAM9263_BASE_US2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
- .end = NR_IRQS_LEGACY + AT91SAM9263_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9263_uart2_device = {
- .name = "atmel_usart",
- .id = 3,
- .dev = {
- .dma_mask = &uart2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart2_data,
- },
- .resource = uart2_resources,
- .num_resources = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PD2, 1); /* TXD2 */
- at91_set_A_periph(AT91_PIN_PD3, 0); /* RXD2 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PD5, 0); /* RTS2 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PD6, 0); /* CTS2 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
- struct platform_device *pdev;
- struct atmel_uart_data *pdata;
-
- switch (id) {
- case 0: /* DBGU */
- pdev = &at91sam9263_dbgu_device;
- configure_dbgu_pins();
- break;
- case AT91SAM9263_ID_US0:
- pdev = &at91sam9263_uart0_device;
- configure_usart0_pins(pins);
- break;
- case AT91SAM9263_ID_US1:
- pdev = &at91sam9263_uart1_device;
- configure_usart1_pins(pins);
- break;
- case AT91SAM9263_ID_US2:
- pdev = &at91sam9263_uart2_device;
- configure_usart2_pins(pins);
- break;
- default:
- return;
- }
- pdata = pdev->dev.platform_data;
- pdata->num = portnr; /* update to mapped ID */
-
- if (portnr < ATMEL_MAX_UART)
- at91_uarts[portnr] = pdev;
-}
-
-void __init at91_add_device_serial(void)
-{
- int i;
-
- for (i = 0; i < ATMEL_MAX_UART; i++) {
- if (at91_uarts[i])
- platform_device_register(at91_uarts[i]);
- }
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
- if (of_have_populated_dt())
- return 0;
-
- at91_add_device_rtt();
- at91_add_device_watchdog();
- at91_add_device_tc();
- return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91sam9g45.c b/arch/arm/mach-at91/at91sam9g45.c
index 405427e..b6117be 100644
--- a/arch/arm/mach-at91/at91sam9g45.c
+++ b/arch/arm/mach-at91/at91sam9g45.c
@@ -10,356 +10,12 @@
*
*/
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk/at91_pmc.h>
-#include <linux/platform_device.h>
-
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/system_misc.h>
-#include <mach/at91sam9g45.h>
-#include <mach/cpu.h>
+#include <asm/irq.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-#include "pm.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_PIOA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_PIOB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
- .name = "pioC_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_PIOC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioDE_clk = {
- .name = "pioDE_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_PIODE,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk trng_clk = {
- .name = "trng_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_TRNG,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_US0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_US1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_US2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_US3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc0_clk = {
- .name = "mci0_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_MCI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
- .name = "twi0_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_TWI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
- .name = "twi1_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_TWI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
- .name = "spi0_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_SPI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
- .name = "spi1_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_SPI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
- .name = "ssc0_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_SSC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
- .name = "ssc1_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_SSC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb0_clk = {
- .name = "tcb0_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_TCB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
- .name = "pwm_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_PWMC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tsc_clk = {
- .name = "tsc_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_TSC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma_clk = {
- .name = "dma_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_DMA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uhphs_clk = {
- .name = "uhphs_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_UHPHS,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
- .name = "lcdc_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_LCDC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ac97_clk = {
- .name = "ac97_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_AC97C,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk macb_clk = {
- .name = "pclk",
- .pmc_mask = 1 << AT91SAM9G45_ID_EMAC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk isi_clk = {
- .name = "isi_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_ISI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udphs_clk = {
- .name = "udphs_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_UDPHS,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc1_clk = {
- .name = "mci1_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_MCI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-/* Video decoder clock - Only for sam9m10/sam9m11 */
-static struct clk vdec_clk = {
- .name = "vdec_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_VDEC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk adc_op_clk = {
- .name = "adc_op_clk",
- .type = CLK_TYPE_PERIPHERAL,
- .rate_hz = 300000,
-};
-
-/* AES/TDES/SHA clock - Only for sam9m11/sam9g56 */
-static struct clk aestdessha_clk = {
- .name = "aestdessha_clk",
- .pmc_mask = 1 << AT91SAM9G45_ID_AESTDESSHA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
- &pioC_clk,
- &pioDE_clk,
- &trng_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &usart3_clk,
- &mmc0_clk,
- &twi0_clk,
- &twi1_clk,
- &spi0_clk,
- &spi1_clk,
- &ssc0_clk,
- &ssc1_clk,
- &tcb0_clk,
- &pwm_clk,
- &tsc_clk,
- &dma_clk,
- &uhphs_clk,
- &lcdc_clk,
- &ac97_clk,
- &macb_clk,
- &isi_clk,
- &udphs_clk,
- &mmc1_clk,
- &adc_op_clk,
- &aestdessha_clk,
- // irq0
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- /* One additional fake clock for macb_hclk */
- CLKDEV_CON_ID("hclk", &macb_clk),
- /* One additional fake clock for ohci */
- CLKDEV_CON_ID("ohci_clk", &uhphs_clk),
- CLKDEV_CON_DEV_ID("hclk", "at91sam9g45-lcdfb.0", &lcdc_clk),
- CLKDEV_CON_DEV_ID("hclk", "at91sam9g45es-lcdfb.0", &lcdc_clk),
- CLKDEV_CON_DEV_ID("ehci_clk", "atmel-ehci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.0", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "atmel_mci.1", &mmc1_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.0", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "atmel_spi.1", &spi1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tcb0_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.1", &tcb0_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.0", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g10.1", &twi1_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91sam9g45_ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "fff9c000.ssc", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffa0000.ssc", &ssc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel-trng", &trng_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel_sha", &aestdessha_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel_tdes", &aestdessha_clk),
- CLKDEV_CON_DEV_ID(NULL, "atmel_aes", &aestdessha_clk),
- CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk),
- /* more usart lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "ffffee00.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fff8c000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "fff90000.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "fff94000.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "fff98000.serial", &usart3_clk),
- /* more tc lookup table for DT entries */
- CLKDEV_CON_DEV_ID("t0_clk", "fff7c000.timer", &tcb0_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "fffd4000.timer", &tcb0_clk),
- CLKDEV_CON_DEV_ID("hclk", "700000.ohci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("ehci_clk", "800000.ehci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fff80000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fffd0000.mmc", &mmc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fff84000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "fff88000.i2c", &twi1_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffa4000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "fffa8000.spi", &spi1_clk),
- CLKDEV_CON_DEV_ID("hclk", "600000.gadget", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "600000.gadget", &udphs_clk),
- /* fake hclk clock */
- CLKDEV_CON_DEV_ID("hclk", "at91_ohci", &uhphs_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff200.gpio", &pioA_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioC_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioDE_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioDE_clk),
-
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
- CLKDEV_CON_ID("pioD", &pioDE_clk),
- CLKDEV_CON_ID("pioE", &pioDE_clk),
- /* Fake adc clock */
- CLKDEV_CON_ID("adc_clk", &tsc_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffb8000.pwm", &pwm_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
-};
-
-/*
- * The two programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-
-static void __init at91sam9g45_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
- clkdev_add_table(usart_clocks_lookups,
- ARRAY_SIZE(usart_clocks_lookups));
-
- if (cpu_is_at91sam9m10() || cpu_is_at91sam9m11())
- clk_register(&vdec_clk);
-
- clk_register(&pck0);
- clk_register(&pck1);
-}
-#else
-#define at91sam9g45_register_clocks NULL
-#endif
-
-/* --------------------------------------------------------------------
- * GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91sam9g45_gpio[] __initdata = {
- {
- .id = AT91SAM9G45_ID_PIOA,
- .regbase = AT91SAM9G45_BASE_PIOA,
- }, {
- .id = AT91SAM9G45_ID_PIOB,
- .regbase = AT91SAM9G45_BASE_PIOB,
- }, {
- .id = AT91SAM9G45_ID_PIOC,
- .regbase = AT91SAM9G45_BASE_PIOC,
- }, {
- .id = AT91SAM9G45_ID_PIODE,
- .regbase = AT91SAM9G45_BASE_PIOD,
- }, {
- .id = AT91SAM9G45_ID_PIODE,
- .regbase = AT91SAM9G45_BASE_PIOE,
- }
-};
/* --------------------------------------------------------------------
* AT91SAM9G45 processor initialization
@@ -370,125 +26,15 @@ static void __init at91sam9g45_map_io(void)
at91_init_sram(0, AT91SAM9G45_SRAM_BASE, AT91SAM9G45_SRAM_SIZE);
}
-static void __init at91sam9g45_ioremap_registers(void)
-{
- at91_ioremap_ramc(0, AT91SAM9G45_BASE_DDRSDRC1, 512);
- at91_ioremap_ramc(1, AT91SAM9G45_BASE_DDRSDRC0, 512);
- at91sam926x_ioremap_pit(AT91SAM9G45_BASE_PIT);
- at91sam9_ioremap_smc(0, AT91SAM9G45_BASE_SMC);
- at91_ioremap_matrix(AT91SAM9G45_BASE_MATRIX);
- at91_pm_set_standby(at91_ddr_standby);
-}
-
static void __init at91sam9g45_initialize(void)
{
arm_pm_idle = at91sam9_idle;
at91_sysirq_mask_rtc(AT91SAM9G45_BASE_RTC);
at91_sysirq_mask_rtt(AT91SAM9G45_BASE_RTT);
-
- /* Register GPIO subsystem */
- at91_gpio_init(at91sam9g45_gpio, 5);
-}
-
-static struct resource rstc_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_RSTC,
- .end = AT91SAM9G45_BASE_RSTC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9G45_BASE_DDRSDRC1,
- .end = AT91SAM9G45_BASE_DDRSDRC1 + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = AT91SAM9G45_BASE_DDRSDRC0,
- .end = AT91SAM9G45_BASE_DDRSDRC0 + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device rstc_device = {
- .name = "at91-sam9g45-reset",
- .resource = rstc_resources,
- .num_resources = ARRAY_SIZE(rstc_resources),
-};
-
-static struct resource shdwc_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_SHDWC,
- .end = AT91SAM9G45_BASE_SHDWC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device shdwc_device = {
- .name = "at91-poweroff",
- .resource = shdwc_resources,
- .num_resources = ARRAY_SIZE(shdwc_resources),
-};
-
-static void __init at91sam9g45_register_devices(void)
-{
- platform_device_register(&rstc_device);
- platform_device_register(&shdwc_device);
-}
-
-/* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91sam9g45_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller (FIQ) */
- 7, /* System Peripherals */
- 1, /* Parallel IO Controller A */
- 1, /* Parallel IO Controller B */
- 1, /* Parallel IO Controller C */
- 1, /* Parallel IO Controller D and E */
- 0,
- 5, /* USART 0 */
- 5, /* USART 1 */
- 5, /* USART 2 */
- 5, /* USART 3 */
- 0, /* Multimedia Card Interface 0 */
- 6, /* Two-Wire Interface 0 */
- 6, /* Two-Wire Interface 1 */
- 5, /* Serial Peripheral Interface 0 */
- 5, /* Serial Peripheral Interface 1 */
- 4, /* Serial Synchronous Controller 0 */
- 4, /* Serial Synchronous Controller 1 */
- 0, /* Timer Counter 0, 1, 2, 3, 4 and 5 */
- 0, /* Pulse Width Modulation Controller */
- 0, /* Touch Screen Controller */
- 0, /* DMA Controller */
- 2, /* USB Host High Speed port */
- 3, /* LDC Controller */
- 5, /* AC97 Controller */
- 3, /* Ethernet */
- 0, /* Image Sensor Interface */
- 2, /* USB Device High speed port */
- 0, /* AESTDESSHA Crypto HW Accelerators */
- 0, /* Multimedia Card Interface 1 */
- 0,
- 0, /* Advanced Interrupt Controller (IRQ0) */
-};
-
-static void __init at91sam9g45_init_time(void)
-{
- at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
}
AT91_SOC_START(at91sam9g45)
.map_io = at91sam9g45_map_io,
- .default_irq_priority = at91sam9g45_default_irq_priority,
- .extern_irq = (1 << AT91SAM9G45_ID_IRQ0),
- .ioremap_registers = at91sam9g45_ioremap_registers,
- .register_clocks = at91sam9g45_register_clocks,
- .register_devices = at91sam9g45_register_devices,
.init = at91sam9g45_initialize,
- .init_time = at91sam9g45_init_time,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9g45_devices.c b/arch/arm/mach-at91/at91sam9g45_devices.c
deleted file mode 100644
index 21ab782..0000000
--- a/arch/arm/mach-at91/at91sam9g45_devices.c
+++ /dev/null
@@ -1,1915 +0,0 @@
-/*
- * On-Chip devices setup code for the AT91SAM9G45 family
- *
- * Copyright (C) 2009 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-#include <linux/atmel-mci.h>
-#include <linux/platform_data/crypto-atmel.h>
-
-#include <linux/platform_data/at91_adc.h>
-
-#include <linux/fb.h>
-#include <video/atmel_lcdc.h>
-
-#include <mach/at91sam9g45.h>
-#include <mach/at91sam9g45_matrix.h>
-#include <mach/at91_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <linux/platform_data/dma-atmel.h>
-#include <mach/atmel-mci.h>
-#include <mach/hardware.h>
-
-#include <media/atmel-isi.h>
-
-#include "board.h"
-#include "generic.h"
-#include "clock.h"
-#include "gpio.h"
-
-
-/* --------------------------------------------------------------------
- * HDMAC - AHB DMA Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
-static u64 hdmac_dmamask = DMA_BIT_MASK(32);
-
-static struct resource hdmac_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_DMA,
- .end = AT91SAM9G45_BASE_DMA + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_DMA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at_hdmac_device = {
- .name = "at91sam9g45_dma",
- .id = -1,
- .dev = {
- .dma_mask = &hdmac_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = hdmac_resources,
- .num_resources = ARRAY_SIZE(hdmac_resources),
-};
-
-void __init at91_add_device_hdmac(void)
-{
- platform_device_register(&at_hdmac_device);
-}
-#else
-void __init at91_add_device_hdmac(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB Host (OHCI)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_OHCI_HCD) || defined(CONFIG_USB_OHCI_HCD_MODULE)
-static u64 ohci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_ohci_data;
-
-static struct resource usbh_ohci_resources[] = {
- [0] = {
- .start = AT91SAM9G45_OHCI_BASE,
- .end = AT91SAM9G45_OHCI_BASE + SZ_1M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_usbh_ohci_device = {
- .name = "at91_ohci",
- .id = -1,
- .dev = {
- .dma_mask = &ohci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &usbh_ohci_data,
- },
- .resource = usbh_ohci_resources,
- .num_resources = ARRAY_SIZE(usbh_ohci_resources),
-};
-
-void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data)
-{
- int i;
-
- if (!data)
- return;
-
- /* Enable VBus control for UHP ports */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->vbus_pin[i]))
- at91_set_gpio_output(data->vbus_pin[i],
- data->vbus_pin_active_low[i]);
- }
-
- /* Enable overcurrent notification */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->overcurrent_pin[i]))
- at91_set_gpio_input(data->overcurrent_pin[i], 1);
- }
-
- usbh_ohci_data = *data;
- platform_device_register(&at91_usbh_ohci_device);
-}
-#else
-void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB Host HS (EHCI)
- * Needs an OHCI host for low and full speed management
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_EHCI_HCD) || defined(CONFIG_USB_EHCI_HCD_MODULE)
-static u64 ehci_dmamask = DMA_BIT_MASK(32);
-static struct at91_usbh_data usbh_ehci_data;
-
-static struct resource usbh_ehci_resources[] = {
- [0] = {
- .start = AT91SAM9G45_EHCI_BASE,
- .end = AT91SAM9G45_EHCI_BASE + SZ_1M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UHPHS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_usbh_ehci_device = {
- .name = "atmel-ehci",
- .id = -1,
- .dev = {
- .dma_mask = &ehci_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &usbh_ehci_data,
- },
- .resource = usbh_ehci_resources,
- .num_resources = ARRAY_SIZE(usbh_ehci_resources),
-};
-
-void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data)
-{
- int i;
-
- if (!data)
- return;
-
- /* Enable VBus control for UHP ports */
- for (i = 0; i < data->ports; i++) {
- if (gpio_is_valid(data->vbus_pin[i]))
- at91_set_gpio_output(data->vbus_pin[i],
- data->vbus_pin_active_low[i]);
- }
-
- usbh_ehci_data = *data;
- platform_device_register(&at91_usbh_ehci_device);
-}
-#else
-void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * USB HS Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
-static struct resource usba_udc_resources[] = {
- [0] = {
- .start = AT91SAM9G45_UDPHS_FIFO,
- .end = AT91SAM9G45_UDPHS_FIFO + SZ_512K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9G45_BASE_UDPHS,
- .end = AT91SAM9G45_BASE_UDPHS + SZ_1K - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_UDPHS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
- [idx] = { \
- .name = nam, \
- .index = idx, \
- .fifo_size = maxpkt, \
- .nr_banks = maxbk, \
- .can_dma = dma, \
- .can_isoc = isoc, \
- }
-
-static struct usba_ep_data usba_udc_ep[] __initdata = {
- EP("ep0", 0, 64, 1, 0, 0),
- EP("ep1", 1, 1024, 2, 1, 1),
- EP("ep2", 2, 1024, 2, 1, 1),
- EP("ep3", 3, 1024, 3, 1, 0),
- EP("ep4", 4, 1024, 3, 1, 0),
- EP("ep5", 5, 1024, 3, 1, 1),
- EP("ep6", 6, 1024, 3, 1, 1),
-};
-
-#undef EP
-
-/*
- * pdata doesn't have room for any endpoints, so we need to
- * append room for the ones we need right after it.
- */
-static struct {
- struct usba_platform_data pdata;
- struct usba_ep_data ep[7];
-} usba_udc_data;
-
-static struct platform_device at91_usba_udc_device = {
- .name = "atmel_usba_udc",
- .id = -1,
- .dev = {
- .platform_data = &usba_udc_data.pdata,
- },
- .resource = usba_udc_resources,
- .num_resources = ARRAY_SIZE(usba_udc_resources),
-};
-
-void __init at91_add_device_usba(struct usba_platform_data *data)
-{
- usba_udc_data.pdata.vbus_pin = -EINVAL;
- usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
- memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
-
- if (data && gpio_is_valid(data->vbus_pin)) {
- at91_set_gpio_input(data->vbus_pin, 0);
- at91_set_deglitch(data->vbus_pin, 1);
- usba_udc_data.pdata.vbus_pin = data->vbus_pin;
- }
-
- /* Pullup pin is handled internally by USB device peripheral */
-
- platform_device_register(&at91_usba_udc_device);
-}
-#else
-void __init at91_add_device_usba(struct usba_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Ethernet
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MACB) || defined(CONFIG_MACB_MODULE)
-static u64 eth_dmamask = DMA_BIT_MASK(32);
-static struct macb_platform_data eth_data;
-
-static struct resource eth_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_EMAC,
- .end = AT91SAM9G45_BASE_EMAC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_EMAC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_eth_device = {
- .name = "macb",
- .id = -1,
- .dev = {
- .dma_mask = &eth_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &eth_data,
- },
- .resource = eth_resources,
- .num_resources = ARRAY_SIZE(eth_resources),
-};
-
-void __init at91_add_device_eth(struct macb_platform_data *data)
-{
- if (!data)
- return;
-
- if (gpio_is_valid(data->phy_irq_pin)) {
- at91_set_gpio_input(data->phy_irq_pin, 0);
- at91_set_deglitch(data->phy_irq_pin, 1);
- }
-
- /* Pins used for MII and RMII */
- at91_set_A_periph(AT91_PIN_PA17, 0); /* ETXCK_EREFCK */
- at91_set_A_periph(AT91_PIN_PA15, 0); /* ERXDV */
- at91_set_A_periph(AT91_PIN_PA12, 0); /* ERX0 */
- at91_set_A_periph(AT91_PIN_PA13, 0); /* ERX1 */
- at91_set_A_periph(AT91_PIN_PA16, 0); /* ERXER */
- at91_set_A_periph(AT91_PIN_PA14, 0); /* ETXEN */
- at91_set_A_periph(AT91_PIN_PA10, 0); /* ETX0 */
- at91_set_A_periph(AT91_PIN_PA11, 0); /* ETX1 */
- at91_set_A_periph(AT91_PIN_PA19, 0); /* EMDIO */
- at91_set_A_periph(AT91_PIN_PA18, 0); /* EMDC */
-
- if (!data->is_rmii) {
- at91_set_B_periph(AT91_PIN_PA29, 0); /* ECRS */
- at91_set_B_periph(AT91_PIN_PA30, 0); /* ECOL */
- at91_set_B_periph(AT91_PIN_PA8, 0); /* ERX2 */
- at91_set_B_periph(AT91_PIN_PA9, 0); /* ERX3 */
- at91_set_B_periph(AT91_PIN_PA28, 0); /* ERXCK */
- at91_set_B_periph(AT91_PIN_PA6, 0); /* ETX2 */
- at91_set_B_periph(AT91_PIN_PA7, 0); /* ETX3 */
- at91_set_B_periph(AT91_PIN_PA27, 0); /* ETXER */
- }
-
- eth_data = *data;
- platform_device_register(&at91sam9g45_eth_device);
-}
-#else
-void __init at91_add_device_eth(struct macb_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * MMC / SD
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MMC_ATMELMCI) || defined(CONFIG_MMC_ATMELMCI_MODULE)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct mci_platform_data mmc0_data, mmc1_data;
-
-static struct resource mmc0_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_MCI0,
- .end = AT91SAM9G45_BASE_MCI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_mmc0_device = {
- .name = "atmel_mci",
- .id = 0,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc0_data,
- },
- .resource = mmc0_resources,
- .num_resources = ARRAY_SIZE(mmc0_resources),
-};
-
-static struct resource mmc1_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_MCI1,
- .end = AT91SAM9G45_BASE_MCI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_MCI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_mmc1_device = {
- .name = "atmel_mci",
- .id = 1,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc1_data,
- },
- .resource = mmc1_resources,
- .num_resources = ARRAY_SIZE(mmc1_resources),
-};
-
-/* Consider only one slot : slot 0 */
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
-{
-
- if (!data)
- return;
-
- /* Must have at least one usable slot */
- if (!data->slot[0].bus_width)
- return;
-
-#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
- {
- struct at_dma_slave *atslave;
- struct mci_dma_data *alt_atslave;
-
- alt_atslave = kzalloc(sizeof(struct mci_dma_data), GFP_KERNEL);
- atslave = &alt_atslave->sdata;
-
- /* DMA slave channel configuration */
- atslave->dma_dev = &at_hdmac_device.dev;
- atslave->cfg = ATC_FIFOCFG_HALFFIFO
- | ATC_SRC_H2SEL_HW | ATC_DST_H2SEL_HW;
- if (mmc_id == 0) /* MCI0 */
- atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI0)
- | ATC_DST_PER(AT_DMA_ID_MCI0);
-
- else /* MCI1 */
- atslave->cfg |= ATC_SRC_PER(AT_DMA_ID_MCI1)
- | ATC_DST_PER(AT_DMA_ID_MCI1);
-
- data->dma_slave = alt_atslave;
- }
-#endif
-
-
- /* input/irq */
- if (gpio_is_valid(data->slot[0].detect_pin)) {
- at91_set_gpio_input(data->slot[0].detect_pin, 1);
- at91_set_deglitch(data->slot[0].detect_pin, 1);
- }
- if (gpio_is_valid(data->slot[0].wp_pin))
- at91_set_gpio_input(data->slot[0].wp_pin, 1);
-
- if (mmc_id == 0) { /* MCI0 */
-
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA0, 0);
-
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA1, 1);
-
- /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
- at91_set_A_periph(AT91_PIN_PA2, 1);
- if (data->slot[0].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA3, 1);
- at91_set_A_periph(AT91_PIN_PA4, 1);
- at91_set_A_periph(AT91_PIN_PA5, 1);
- if (data->slot[0].bus_width == 8) {
- at91_set_A_periph(AT91_PIN_PA6, 1);
- at91_set_A_periph(AT91_PIN_PA7, 1);
- at91_set_A_periph(AT91_PIN_PA8, 1);
- at91_set_A_periph(AT91_PIN_PA9, 1);
- }
- }
-
- mmc0_data = *data;
- platform_device_register(&at91sam9g45_mmc0_device);
-
- } else { /* MCI1 */
-
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA31, 0);
-
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA22, 1);
-
- /* DAT0, maybe DAT1..DAT3 and maybe DAT4..DAT7 */
- at91_set_A_periph(AT91_PIN_PA23, 1);
- if (data->slot[0].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA24, 1);
- at91_set_A_periph(AT91_PIN_PA25, 1);
- at91_set_A_periph(AT91_PIN_PA26, 1);
- if (data->slot[0].bus_width == 8) {
- at91_set_A_periph(AT91_PIN_PA27, 1);
- at91_set_A_periph(AT91_PIN_PA28, 1);
- at91_set_A_periph(AT91_PIN_PA29, 1);
- at91_set_A_periph(AT91_PIN_PA30, 1);
- }
- }
-
- mmc1_data = *data;
- platform_device_register(&at91sam9g45_mmc1_device);
-
- }
-}
-#else
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
- [0] = {
- .start = NAND_BASE,
- .end = NAND_BASE + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9G45_BASE_ECC,
- .end = AT91SAM9G45_BASE_ECC + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9g45_nand_device = {
- .name = "atmel_nand",
- .id = -1,
- .dev = {
- .platform_data = &nand_data,
- },
- .resource = nand_resources,
- .num_resources = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
- unsigned long csa;
-
- if (!data)
- return;
-
- csa = at91_matrix_read(AT91_MATRIX_EBICSA);
- at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_EBI_CS3A_SMC_SMARTMEDIA);
-
- /* enable pin */
- if (gpio_is_valid(data->enable_pin))
- at91_set_gpio_output(data->enable_pin, 1);
-
- /* ready/busy pin */
- if (gpio_is_valid(data->rdy_pin))
- at91_set_gpio_input(data->rdy_pin, 1);
-
- /* card detect pin */
- if (gpio_is_valid(data->det_pin))
- at91_set_gpio_input(data->det_pin, 1);
-
- nand_data = *data;
- platform_device_register(&at91sam9g45_nand_device);
-}
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-static struct i2c_gpio_platform_data pdata_i2c0 = {
- .sda_pin = AT91_PIN_PA20,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PA21,
- .scl_is_open_drain = 1,
- .udelay = 5, /* ~100 kHz */
-};
-
-static struct platform_device at91sam9g45_twi0_device = {
- .name = "i2c-gpio",
- .id = 0,
- .dev.platform_data = &pdata_i2c0,
-};
-
-static struct i2c_gpio_platform_data pdata_i2c1 = {
- .sda_pin = AT91_PIN_PB10,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PB11,
- .scl_is_open_drain = 1,
- .udelay = 5, /* ~100 kHz */
-};
-
-static struct platform_device at91sam9g45_twi1_device = {
- .name = "i2c-gpio",
- .id = 1,
- .dev.platform_data = &pdata_i2c1,
-};
-
-void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
-{
- i2c_register_board_info(i2c_id, devices, nr_devices);
-
- if (i2c_id == 0) {
- at91_set_GPIO_periph(AT91_PIN_PA20, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PA20, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PA21, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PA21, 1);
-
- platform_device_register(&at91sam9g45_twi0_device);
- } else {
- at91_set_GPIO_periph(AT91_PIN_PB10, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PB10, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PB11, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PB11, 1);
-
- platform_device_register(&at91sam9g45_twi1_device);
- }
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-static struct resource twi0_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_TWI0,
- .end = AT91SAM9G45_BASE_TWI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_twi0_device = {
- .name = "i2c-at91sam9g10",
- .id = 0,
- .resource = twi0_resources,
- .num_resources = ARRAY_SIZE(twi0_resources),
-};
-
-static struct resource twi1_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_TWI1,
- .end = AT91SAM9G45_BASE_TWI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TWI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_twi1_device = {
- .name = "i2c-at91sam9g10",
- .id = 1,
- .resource = twi1_resources,
- .num_resources = ARRAY_SIZE(twi1_resources),
-};
-
-void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices)
-{
- i2c_register_board_info(i2c_id, devices, nr_devices);
-
- /* pins used for TWI interface */
- if (i2c_id == 0) {
- at91_set_A_periph(AT91_PIN_PA20, 0); /* TWD */
- at91_set_A_periph(AT91_PIN_PA21, 0); /* TWCK */
-
- platform_device_register(&at91sam9g45_twi0_device);
- } else {
- at91_set_A_periph(AT91_PIN_PB10, 0); /* TWD */
- at91_set_A_periph(AT91_PIN_PB11, 0); /* TWCK */
-
- platform_device_register(&at91sam9g45_twi1_device);
- }
-}
-#else
-void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi0_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_SPI0,
- .end = AT91SAM9G45_BASE_SPI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_spi0_device = {
- .name = "atmel_spi",
- .id = 0,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi0_resources,
- .num_resources = ARRAY_SIZE(spi0_resources),
-};
-
-static const unsigned spi0_standard_cs[4] = { AT91_PIN_PB3, AT91_PIN_PB18, AT91_PIN_PB19, AT91_PIN_PD27 };
-
-static struct resource spi1_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_SPI1,
- .end = AT91SAM9G45_BASE_SPI1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SPI1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_spi1_device = {
- .name = "atmel_spi",
- .id = 1,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi1_resources,
- .num_resources = ARRAY_SIZE(spi1_resources),
-};
-
-static const unsigned spi1_standard_cs[4] = { AT91_PIN_PB17, AT91_PIN_PD28, AT91_PIN_PD18, AT91_PIN_PD19 };
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
- int i;
- unsigned long cs_pin;
- short enable_spi0 = 0;
- short enable_spi1 = 0;
-
- /* Choose SPI chip-selects */
- for (i = 0; i < nr_devices; i++) {
- if (devices[i].controller_data)
- cs_pin = (unsigned long) devices[i].controller_data;
- else if (devices[i].bus_num == 0)
- cs_pin = spi0_standard_cs[devices[i].chip_select];
- else
- cs_pin = spi1_standard_cs[devices[i].chip_select];
-
- if (!gpio_is_valid(cs_pin))
- continue;
-
- if (devices[i].bus_num == 0)
- enable_spi0 = 1;
- else
- enable_spi1 = 1;
-
- /* enable chip-select pin */
- at91_set_gpio_output(cs_pin, 1);
-
- /* pass chip-select pin to driver */
- devices[i].controller_data = (void *) cs_pin;
- }
-
- spi_register_board_info(devices, nr_devices);
-
- /* Configure SPI bus(es) */
- if (enable_spi0) {
- at91_set_A_periph(AT91_PIN_PB0, 0); /* SPI0_MISO */
- at91_set_A_periph(AT91_PIN_PB1, 0); /* SPI0_MOSI */
- at91_set_A_periph(AT91_PIN_PB2, 0); /* SPI0_SPCK */
-
- platform_device_register(&at91sam9g45_spi0_device);
- }
- if (enable_spi1) {
- at91_set_A_periph(AT91_PIN_PB14, 0); /* SPI1_MISO */
- at91_set_A_periph(AT91_PIN_PB15, 0); /* SPI1_MOSI */
- at91_set_A_periph(AT91_PIN_PB16, 0); /* SPI1_SPCK */
-
- platform_device_register(&at91sam9g45_spi1_device);
- }
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * AC97
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SND_ATMEL_AC97C) || defined(CONFIG_SND_ATMEL_AC97C_MODULE)
-static u64 ac97_dmamask = DMA_BIT_MASK(32);
-static struct ac97c_platform_data ac97_data;
-
-static struct resource ac97_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_AC97C,
- .end = AT91SAM9G45_BASE_AC97C + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AC97C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_ac97_device = {
- .name = "atmel_ac97c",
- .id = 0,
- .dev = {
- .dma_mask = &ac97_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &ac97_data,
- },
- .resource = ac97_resources,
- .num_resources = ARRAY_SIZE(ac97_resources),
-};
-
-void __init at91_add_device_ac97(struct ac97c_platform_data *data)
-{
- if (!data)
- return;
-
- at91_set_A_periph(AT91_PIN_PD8, 0); /* AC97FS */
- at91_set_A_periph(AT91_PIN_PD9, 0); /* AC97CK */
- at91_set_A_periph(AT91_PIN_PD7, 0); /* AC97TX */
- at91_set_A_periph(AT91_PIN_PD6, 0); /* AC97RX */
-
- /* reset */
- if (gpio_is_valid(data->reset_pin))
- at91_set_gpio_output(data->reset_pin, 0);
-
- ac97_data = *data;
- platform_device_register(&at91sam9g45_ac97_device);
-}
-#else
-void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * Image Sensor Interface
- * -------------------------------------------------------------------- */
-#if defined(CONFIG_VIDEO_ATMEL_ISI) || defined(CONFIG_VIDEO_ATMEL_ISI_MODULE)
-static u64 isi_dmamask = DMA_BIT_MASK(32);
-static struct isi_platform_data isi_data;
-
-struct resource isi_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_ISI,
- .end = AT91SAM9G45_BASE_ISI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_ISI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_isi_device = {
- .name = "atmel_isi",
- .id = 0,
- .dev = {
- .dma_mask = &isi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &isi_data,
- },
- .resource = isi_resources,
- .num_resources = ARRAY_SIZE(isi_resources),
-};
-
-static struct clk_lookup isi_mck_lookups[] = {
- CLKDEV_CON_DEV_ID("isi_mck", "atmel_isi.0", NULL),
-};
-
-void __init at91_add_device_isi(struct isi_platform_data *data,
- bool use_pck_as_mck)
-{
- struct clk *pck;
- struct clk *parent;
-
- if (!data)
- return;
- isi_data = *data;
-
- at91_set_A_periph(AT91_PIN_PB20, 0); /* ISI_D0 */
- at91_set_A_periph(AT91_PIN_PB21, 0); /* ISI_D1 */
- at91_set_A_periph(AT91_PIN_PB22, 0); /* ISI_D2 */
- at91_set_A_periph(AT91_PIN_PB23, 0); /* ISI_D3 */
- at91_set_A_periph(AT91_PIN_PB24, 0); /* ISI_D4 */
- at91_set_A_periph(AT91_PIN_PB25, 0); /* ISI_D5 */
- at91_set_A_periph(AT91_PIN_PB26, 0); /* ISI_D6 */
- at91_set_A_periph(AT91_PIN_PB27, 0); /* ISI_D7 */
- at91_set_A_periph(AT91_PIN_PB28, 0); /* ISI_PCK */
- at91_set_A_periph(AT91_PIN_PB30, 0); /* ISI_HSYNC */
- at91_set_A_periph(AT91_PIN_PB29, 0); /* ISI_VSYNC */
- at91_set_B_periph(AT91_PIN_PB8, 0); /* ISI_PD8 */
- at91_set_B_periph(AT91_PIN_PB9, 0); /* ISI_PD9 */
- at91_set_B_periph(AT91_PIN_PB10, 0); /* ISI_PD10 */
- at91_set_B_periph(AT91_PIN_PB11, 0); /* ISI_PD11 */
-
- platform_device_register(&at91sam9g45_isi_device);
-
- if (use_pck_as_mck) {
- at91_set_B_periph(AT91_PIN_PB31, 0); /* ISI_MCK (PCK1) */
-
- pck = clk_get(NULL, "pck1");
- parent = clk_get(NULL, "plla");
-
- BUG_ON(IS_ERR(pck) || IS_ERR(parent));
-
- if (clk_set_parent(pck, parent)) {
- pr_err("Failed to set PCK's parent\n");
- } else {
- /* Register PCK as ISI_MCK */
- isi_mck_lookups[0].clk = pck;
- clkdev_add_table(isi_mck_lookups,
- ARRAY_SIZE(isi_mck_lookups));
- }
-
- clk_put(pck);
- clk_put(parent);
- }
-}
-#else
-void __init at91_add_device_isi(struct isi_platform_data *data,
- bool use_pck_as_mck) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * LCD Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_pdata lcdc_data;
-
-static struct resource lcdc_resources[] = {
- [0] = {
- .start = AT91SAM9G45_LCDC_BASE,
- .end = AT91SAM9G45_LCDC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_lcdc_device = {
- .id = 0,
- .dev = {
- .dma_mask = &lcdc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &lcdc_data,
- },
- .resource = lcdc_resources,
- .num_resources = ARRAY_SIZE(lcdc_resources),
-};
-
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
-{
- if (!data)
- return;
-
- if (cpu_is_at91sam9g45es())
- at91_lcdc_device.name = "at91sam9g45es-lcdfb";
- else
- at91_lcdc_device.name = "at91sam9g45-lcdfb";
-
- at91_set_A_periph(AT91_PIN_PE0, 0); /* LCDDPWR */
-
- at91_set_A_periph(AT91_PIN_PE2, 0); /* LCDCC */
- at91_set_A_periph(AT91_PIN_PE3, 0); /* LCDVSYNC */
- at91_set_A_periph(AT91_PIN_PE4, 0); /* LCDHSYNC */
- at91_set_A_periph(AT91_PIN_PE5, 0); /* LCDDOTCK */
- at91_set_A_periph(AT91_PIN_PE6, 0); /* LCDDEN */
- at91_set_A_periph(AT91_PIN_PE7, 0); /* LCDD0 */
- at91_set_A_periph(AT91_PIN_PE8, 0); /* LCDD1 */
- at91_set_A_periph(AT91_PIN_PE9, 0); /* LCDD2 */
- at91_set_A_periph(AT91_PIN_PE10, 0); /* LCDD3 */
- at91_set_A_periph(AT91_PIN_PE11, 0); /* LCDD4 */
- at91_set_A_periph(AT91_PIN_PE12, 0); /* LCDD5 */
- at91_set_A_periph(AT91_PIN_PE13, 0); /* LCDD6 */
- at91_set_A_periph(AT91_PIN_PE14, 0); /* LCDD7 */
- at91_set_A_periph(AT91_PIN_PE15, 0); /* LCDD8 */
- at91_set_A_periph(AT91_PIN_PE16, 0); /* LCDD9 */
- at91_set_A_periph(AT91_PIN_PE17, 0); /* LCDD10 */
- at91_set_A_periph(AT91_PIN_PE18, 0); /* LCDD11 */
- at91_set_A_periph(AT91_PIN_PE19, 0); /* LCDD12 */
- at91_set_A_periph(AT91_PIN_PE20, 0); /* LCDD13 */
- at91_set_A_periph(AT91_PIN_PE21, 0); /* LCDD14 */
- at91_set_A_periph(AT91_PIN_PE22, 0); /* LCDD15 */
- at91_set_A_periph(AT91_PIN_PE23, 0); /* LCDD16 */
- at91_set_A_periph(AT91_PIN_PE24, 0); /* LCDD17 */
- at91_set_A_periph(AT91_PIN_PE25, 0); /* LCDD18 */
- at91_set_A_periph(AT91_PIN_PE26, 0); /* LCDD19 */
- at91_set_A_periph(AT91_PIN_PE27, 0); /* LCDD20 */
- at91_set_A_periph(AT91_PIN_PE28, 0); /* LCDD21 */
- at91_set_A_periph(AT91_PIN_PE29, 0); /* LCDD22 */
- at91_set_A_periph(AT91_PIN_PE30, 0); /* LCDD23 */
-
- lcdc_data = *data;
- platform_device_register(&at91_lcdc_device);
-}
-#else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Timer/Counter block
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-static struct resource tcb0_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_TCB0,
- .end = AT91SAM9G45_BASE_TCB0 + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_tcb0_device = {
- .name = "atmel_tcb",
- .id = 0,
- .resource = tcb0_resources,
- .num_resources = ARRAY_SIZE(tcb0_resources),
-};
-
-/* TCB1 begins with TC3 */
-static struct resource tcb1_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_TCB1,
- .end = AT91SAM9G45_BASE_TCB1 + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TCB,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_tcb1_device = {
- .name = "atmel_tcb",
- .id = 1,
- .resource = tcb1_resources,
- .num_resources = ARRAY_SIZE(tcb1_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
- platform_device_register(&at91sam9g45_tcb0_device);
- platform_device_register(&at91sam9g45_tcb1_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- * RTC
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
-static struct resource rtc_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_RTC,
- .end = AT91SAM9G45_BASE_RTC + SZ_256 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_rtc_device = {
- .name = "at91_rtc",
- .id = -1,
- .resource = rtc_resources,
- .num_resources = ARRAY_SIZE(rtc_resources),
-};
-
-static void __init at91_add_device_rtc(void)
-{
- platform_device_register(&at91sam9g45_rtc_device);
-}
-#else
-static void __init at91_add_device_rtc(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * ADC and touchscreen
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_AT91_ADC)
-static struct at91_adc_data adc_data;
-
-static struct resource adc_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_TSC,
- .end = AT91SAM9G45_BASE_TSC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_TSC,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91_adc_device = {
- .name = "at91sam9g45-adc",
- .id = -1,
- .dev = {
- .platform_data = &adc_data,
- },
- .resource = adc_resources,
- .num_resources = ARRAY_SIZE(adc_resources),
-};
-
-static struct at91_adc_trigger at91_adc_triggers[] = {
- [0] = {
- .name = "external-rising",
- .value = 1,
- .is_external = true,
- },
- [1] = {
- .name = "external-falling",
- .value = 2,
- .is_external = true,
- },
- [2] = {
- .name = "external-any",
- .value = 3,
- .is_external = true,
- },
- [3] = {
- .name = "continuous",
- .value = 6,
- .is_external = false,
- },
-};
-
-void __init at91_add_device_adc(struct at91_adc_data *data)
-{
- if (!data)
- return;
-
- if (test_bit(0, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD20, 0);
- if (test_bit(1, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD21, 0);
- if (test_bit(2, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD22, 0);
- if (test_bit(3, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD23, 0);
- if (test_bit(4, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD24, 0);
- if (test_bit(5, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD25, 0);
- if (test_bit(6, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD26, 0);
- if (test_bit(7, &data->channels_used))
- at91_set_gpio_input(AT91_PIN_PD27, 0);
-
- if (data->use_external_triggers)
- at91_set_A_periph(AT91_PIN_PD28, 0);
-
- data->startup_time = 40;
- data->trigger_number = 4;
- data->trigger_list = at91_adc_triggers;
-
- adc_data = *data;
- platform_device_register(&at91_adc_device);
-}
-#else
-void __init at91_add_device_adc(struct at91_adc_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
- {
- .start = AT91SAM9G45_BASE_RTT,
- .end = AT91SAM9G45_BASE_RTT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91sam9g45_rtt_device = {
- .name = "at91_rtt",
- .id = 0,
- .resource = rtt_resources,
-};
-
-#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
-static void __init at91_add_device_rtt_rtc(void)
-{
- at91sam9g45_rtt_device.name = "rtc-at91sam9";
- /*
- * The second resource is needed:
- * GPBR will serve as the storage for RTC time offset
- */
- at91sam9g45_rtt_device.num_resources = 3;
- rtt_resources[1].start = AT91SAM9G45_BASE_GPBR +
- 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
- rtt_resources[1].end = rtt_resources[1].start + 3;
- rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS;
- rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS;
-}
-#else
-static void __init at91_add_device_rtt_rtc(void)
-{
- /* Only one resource is needed: RTT not used as RTC */
- at91sam9g45_rtt_device.num_resources = 1;
-}
-#endif
-
-static void __init at91_add_device_rtt(void)
-{
- at91_add_device_rtt_rtc();
- platform_device_register(&at91sam9g45_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- * TRNG
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_HW_RANDOM_ATMEL) || defined(CONFIG_HW_RANDOM_ATMEL_MODULE)
-static struct resource trng_resources[] = {
- {
- .start = AT91SAM9G45_BASE_TRNG,
- .end = AT91SAM9G45_BASE_TRNG + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device at91sam9g45_trng_device = {
- .name = "atmel-trng",
- .id = -1,
- .resource = trng_resources,
- .num_resources = ARRAY_SIZE(trng_resources),
-};
-
-static void __init at91_add_device_trng(void)
-{
- platform_device_register(&at91sam9g45_trng_device);
-}
-#else
-static void __init at91_add_device_trng(void) {}
-#endif
-
-/* --------------------------------------------------------------------
- * Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
- {
- .start = AT91SAM9G45_BASE_WDT,
- .end = AT91SAM9G45_BASE_WDT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9g45_wdt_device = {
- .name = "at91_wdt",
- .id = -1,
- .resource = wdt_resources,
- .num_resources = ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
- platform_device_register(&at91sam9g45_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * PWM
- * --------------------------------------------------------------------*/
-
-#if IS_ENABLED(CONFIG_PWM_ATMEL)
-static struct resource pwm_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_PWMC,
- .end = AT91SAM9G45_BASE_PWMC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_PWMC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_pwm0_device = {
- .name = "at91sam9rl-pwm",
- .id = -1,
- .resource = pwm_resources,
- .num_resources = ARRAY_SIZE(pwm_resources),
-};
-
-void __init at91_add_device_pwm(u32 mask)
-{
- if (mask & (1 << AT91_PWM0))
- at91_set_B_periph(AT91_PIN_PD24, 1); /* enable PWM0 */
-
- if (mask & (1 << AT91_PWM1))
- at91_set_B_periph(AT91_PIN_PD31, 1); /* enable PWM1 */
-
- if (mask & (1 << AT91_PWM2))
- at91_set_B_periph(AT91_PIN_PD26, 1); /* enable PWM2 */
-
- if (mask & (1 << AT91_PWM3))
- at91_set_B_periph(AT91_PIN_PD0, 1); /* enable PWM3 */
-
- platform_device_register(&at91sam9g45_pwm0_device);
-}
-#else
-void __init at91_add_device_pwm(u32 mask) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_SSC0,
- .end = AT91SAM9G45_BASE_SSC0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_ssc0_device = {
- .name = "at91sam9g45_ssc",
- .id = 0,
- .dev = {
- .dma_mask = &ssc0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc0_resources,
- .num_resources = ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PD1, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PD0, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PD2, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PD3, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PD4, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PD5, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_SSC1,
- .end = AT91SAM9G45_BASE_SSC1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_ssc1_device = {
- .name = "at91sam9g45_ssc",
- .id = 1,
- .dev = {
- .dma_mask = &ssc1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc1_resources,
- .num_resources = ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PD14, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PD12, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PD10, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PD11, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_A_periph(AT91_PIN_PD13, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_A_periph(AT91_PIN_PD15, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver. For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
- struct platform_device *pdev;
-
- /*
- * NOTE: caller is responsible for passing information matching
- * "pins" to whatever will be using each particular controller.
- */
- switch (id) {
- case AT91SAM9G45_ID_SSC0:
- pdev = &at91sam9g45_ssc0_device;
- configure_ssc0_pins(pins);
- break;
- case AT91SAM9G45_ID_SSC1:
- pdev = &at91sam9g45_ssc1_device;
- configure_ssc1_pins(pins);
- break;
- default:
- return;
- }
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_DBGU,
- .end = AT91SAM9G45_BASE_DBGU + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data dbgu_data = {
- .use_dma_tx = 0,
- .use_dma_rx = 0,
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9g45_dbgu_device = {
- .name = "atmel_usart",
- .id = 0,
- .dev = {
- .dma_mask = &dbgu_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dbgu_data,
- },
- .resource = dbgu_resources,
- .num_resources = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PB12, 0); /* DRXD */
- at91_set_A_periph(AT91_PIN_PB13, 1); /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_US0,
- .end = AT91SAM9G45_BASE_US0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9g45_uart0_device = {
- .name = "atmel_usart",
- .id = 1,
- .dev = {
- .dma_mask = &uart0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart0_data,
- },
- .resource = uart0_resources,
- .num_resources = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB19, 1); /* TXD0 */
- at91_set_A_periph(AT91_PIN_PB18, 0); /* RXD0 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PB17, 0); /* RTS0 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PB15, 0); /* CTS0 */
-}
-
-static struct resource uart1_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_US1,
- .end = AT91SAM9G45_BASE_US1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9g45_uart1_device = {
- .name = "atmel_usart",
- .id = 2,
- .dev = {
- .dma_mask = &uart1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart1_data,
- },
- .resource = uart1_resources,
- .num_resources = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB4, 1); /* TXD1 */
- at91_set_A_periph(AT91_PIN_PB5, 0); /* RXD1 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PD16, 0); /* RTS1 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PD17, 0); /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_US2,
- .end = AT91SAM9G45_BASE_US2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9g45_uart2_device = {
- .name = "atmel_usart",
- .id = 3,
- .dev = {
- .dma_mask = &uart2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart2_data,
- },
- .resource = uart2_resources,
- .num_resources = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB6, 1); /* TXD2 */
- at91_set_A_periph(AT91_PIN_PB7, 0); /* RXD2 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PC9, 0); /* RTS2 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PC11, 0); /* CTS2 */
-}
-
-static struct resource uart3_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_US3,
- .end = AT91SAM9G45_BASE_US3 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart3_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart3_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9g45_uart3_device = {
- .name = "atmel_usart",
- .id = 4,
- .dev = {
- .dma_mask = &uart3_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart3_data,
- },
- .resource = uart3_resources,
- .num_resources = ARRAY_SIZE(uart3_resources),
-};
-
-static inline void configure_usart3_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB8, 1); /* TXD3 */
- at91_set_A_periph(AT91_PIN_PB9, 0); /* RXD3 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PA23, 0); /* RTS3 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PA24, 0); /* CTS3 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
- struct platform_device *pdev;
- struct atmel_uart_data *pdata;
-
- switch (id) {
- case 0: /* DBGU */
- pdev = &at91sam9g45_dbgu_device;
- configure_dbgu_pins();
- break;
- case AT91SAM9G45_ID_US0:
- pdev = &at91sam9g45_uart0_device;
- configure_usart0_pins(pins);
- break;
- case AT91SAM9G45_ID_US1:
- pdev = &at91sam9g45_uart1_device;
- configure_usart1_pins(pins);
- break;
- case AT91SAM9G45_ID_US2:
- pdev = &at91sam9g45_uart2_device;
- configure_usart2_pins(pins);
- break;
- case AT91SAM9G45_ID_US3:
- pdev = &at91sam9g45_uart3_device;
- configure_usart3_pins(pins);
- break;
- default:
- return;
- }
- pdata = pdev->dev.platform_data;
- pdata->num = portnr; /* update to mapped ID */
-
- if (portnr < ATMEL_MAX_UART)
- at91_uarts[portnr] = pdev;
-}
-
-void __init at91_add_device_serial(void)
-{
- int i;
-
- for (i = 0; i < ATMEL_MAX_UART; i++) {
- if (at91_uarts[i])
- platform_device_register(at91_uarts[i]);
- }
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-/* --------------------------------------------------------------------
- * SHA1/SHA256
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_CRYPTO_DEV_ATMEL_SHA) || defined(CONFIG_CRYPTO_DEV_ATMEL_SHA_MODULE)
-static struct resource sha_resources[] = {
- {
- .start = AT91SAM9G45_BASE_SHA,
- .end = AT91SAM9G45_BASE_SHA + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_sha_device = {
- .name = "atmel_sha",
- .id = -1,
- .resource = sha_resources,
- .num_resources = ARRAY_SIZE(sha_resources),
-};
-
-static void __init at91_add_device_sha(void)
-{
- platform_device_register(&at91sam9g45_sha_device);
-}
-#else
-static void __init at91_add_device_sha(void) {}
-#endif
-
-/* --------------------------------------------------------------------
- * DES/TDES
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_CRYPTO_DEV_ATMEL_TDES) || defined(CONFIG_CRYPTO_DEV_ATMEL_TDES_MODULE)
-static struct resource tdes_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_TDES,
- .end = AT91SAM9G45_BASE_TDES + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_tdes_device = {
- .name = "atmel_tdes",
- .id = -1,
- .resource = tdes_resources,
- .num_resources = ARRAY_SIZE(tdes_resources),
-};
-
-static void __init at91_add_device_tdes(void)
-{
- platform_device_register(&at91sam9g45_tdes_device);
-}
-#else
-static void __init at91_add_device_tdes(void) {}
-#endif
-
-/* --------------------------------------------------------------------
- * AES
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_CRYPTO_DEV_ATMEL_AES) || defined(CONFIG_CRYPTO_DEV_ATMEL_AES_MODULE)
-static struct crypto_platform_data aes_data;
-static struct crypto_dma_data alt_atslave;
-static u64 aes_dmamask = DMA_BIT_MASK(32);
-
-static struct resource aes_resources[] = {
- [0] = {
- .start = AT91SAM9G45_BASE_AES,
- .end = AT91SAM9G45_BASE_AES + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
- .end = NR_IRQS_LEGACY + AT91SAM9G45_ID_AESTDESSHA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9g45_aes_device = {
- .name = "atmel_aes",
- .id = -1,
- .dev = {
- .dma_mask = &aes_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &aes_data,
- },
- .resource = aes_resources,
- .num_resources = ARRAY_SIZE(aes_resources),
-};
-
-static void __init at91_add_device_aes(void)
-{
- struct at_dma_slave *atslave;
-
- /* DMA TX slave channel configuration */
- atslave = &alt_atslave.txdata;
- atslave->dma_dev = &at_hdmac_device.dev;
- atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_SRC_H2SEL_HW |
- ATC_SRC_PER(AT_DMA_ID_AES_RX);
-
- /* DMA RX slave channel configuration */
- atslave = &alt_atslave.rxdata;
- atslave->dma_dev = &at_hdmac_device.dev;
- atslave->cfg = ATC_FIFOCFG_ENOUGHSPACE | ATC_DST_H2SEL_HW |
- ATC_DST_PER(AT_DMA_ID_AES_TX);
-
- aes_data.dma_slave = &alt_atslave;
- platform_device_register(&at91sam9g45_aes_device);
-}
-#else
-static void __init at91_add_device_aes(void) {}
-#endif
-
-/* -------------------------------------------------------------------- */
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
- if (of_have_populated_dt())
- return 0;
-
- at91_add_device_hdmac();
- at91_add_device_rtc();
- at91_add_device_rtt();
- at91_add_device_trng();
- at91_add_device_watchdog();
- at91_add_device_tc();
- at91_add_device_sha();
- at91_add_device_tdes();
- at91_add_device_aes();
- return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91sam9n12.c b/arch/arm/mach-at91/at91sam9n12.c
index c8988fe..dee569b 100644
--- a/arch/arm/mach-at91/at91sam9n12.c
+++ b/arch/arm/mach-at91/at91sam9n12.c
@@ -6,219 +6,11 @@
* Licensed under GPLv2 or later.
*/
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk/at91_pmc.h>
+#include <asm/system_misc.h>
+#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <mach/at91sam9n12.h>
-#include <mach/cpu.h>
-
-#include "board.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioAB_clk = {
- .name = "pioAB_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_PIOAB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioCD_clk = {
- .name = "pioCD_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_PIOCD,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_USART0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_USART1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_USART2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_USART3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
- .name = "twi0_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_TWI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
- .name = "twi1_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_TWI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
- .name = "mci_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_MCI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
- .name = "spi0_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_SPI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
- .name = "spi1_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_SPI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uart0_clk = {
- .name = "uart0_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_UART0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uart1_clk = {
- .name = "uart1_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_UART1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb_clk = {
- .name = "tcb_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_TCB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
- .name = "pwm_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_PWM,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_clk = {
- .name = "adc_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_ADC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma_clk = {
- .name = "dma_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_DMA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uhp_clk = {
- .name = "uhp",
- .pmc_mask = 1 << AT91SAM9N12_ID_UHP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udp_clk = {
- .name = "udp_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_UDP,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
- .name = "lcdc_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_LCDC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc_clk = {
- .name = "ssc_clk",
- .pmc_mask = 1 << AT91SAM9N12_ID_SSC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioAB_clk,
- &pioCD_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &usart3_clk,
- &twi0_clk,
- &twi1_clk,
- &mmc_clk,
- &spi0_clk,
- &spi1_clk,
- &lcdc_clk,
- &uart0_clk,
- &uart1_clk,
- &tcb_clk,
- &pwm_clk,
- &adc_clk,
- &dma_clk,
- &uhp_clk,
- &udp_clk,
- &ssc_clk,
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- /* lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID(NULL, "f0010000.ssc", &ssc_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "f0000000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
- /* additional fake clock for macb_hclk */
- CLKDEV_CON_DEV_ID("hclk", "500000.ohci", &uhp_clk),
- CLKDEV_CON_DEV_ID("ohci_clk", "500000.ohci", &uhp_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8034000.pwm", &pwm_clk),
-};
-
-/*
- * The two programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-
-static void __init at91sam9n12_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
- clk_register(&pck0);
- clk_register(&pck1);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
-
-}
-#else
-#define at91sam9n12_register_clocks NULL
-#endif
/* --------------------------------------------------------------------
* AT91SAM9N12 processor initialization
@@ -236,6 +28,5 @@ static void __init at91sam9n12_initialize(void)
AT91_SOC_START(at91sam9n12)
.map_io = at91sam9n12_map_io,
- .register_clocks = at91sam9n12_register_clocks,
.init = at91sam9n12_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl.c b/arch/arm/mach-at91/at91sam9rl.c
index f553e4e..f25b9ae 100644
--- a/arch/arm/mach-at91/at91sam9rl.c
+++ b/arch/arm/mach-at91/at91sam9rl.c
@@ -9,284 +9,14 @@
* more details.
*/
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <asm/proc-fns.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
#include <asm/system_misc.h>
+#include <asm/irq.h>
#include <mach/cpu.h>
#include <mach/at91_dbgu.h>
-#include <mach/at91sam9rl.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-#include "pm.h"
-
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioA_clk = {
- .name = "pioA_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_PIOA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioB_clk = {
- .name = "pioB_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_PIOB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioC_clk = {
- .name = "pioC_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_PIOC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioD_clk = {
- .name = "pioD_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_PIOD,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_US0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_US1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_US2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_US3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc_clk = {
- .name = "mci_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_MCI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
- .name = "twi0_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_TWI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
- .name = "twi1_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_TWI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi_clk = {
- .name = "spi_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_SPI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc0_clk = {
- .name = "ssc0_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_SSC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc1_clk = {
- .name = "ssc1_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_SSC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc0_clk = {
- .name = "tc0_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_TC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc1_clk = {
- .name = "tc1_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_TC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tc2_clk = {
- .name = "tc2_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_TC2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
- .name = "pwm_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_PWMC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tsc_clk = {
- .name = "tsc_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_TSC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma_clk = {
- .name = "dma_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_DMA,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udphs_clk = {
- .name = "udphs_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_UDPHS,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk lcdc_clk = {
- .name = "lcdc_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_LCDC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ac97_clk = {
- .name = "ac97_clk",
- .pmc_mask = 1 << AT91SAM9RL_ID_AC97C,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_op_clk = {
- .name = "adc_op_clk",
- .type = CLK_TYPE_PERIPHERAL,
- .rate_hz = 1000000,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioA_clk,
- &pioB_clk,
- &pioC_clk,
- &pioD_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &usart3_clk,
- &mmc_clk,
- &twi0_clk,
- &twi1_clk,
- &spi_clk,
- &ssc0_clk,
- &ssc1_clk,
- &tc0_clk,
- &tc1_clk,
- &tc2_clk,
- &pwm_clk,
- &tsc_clk,
- &dma_clk,
- &udphs_clk,
- &lcdc_clk,
- &ac97_clk,
- &adc_op_clk,
- // irq0
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("hclk", "at91sam9rl-lcdfb.0", &lcdc_clk),
- CLKDEV_CON_DEV_ID("hclk", "atmel_usba_udc", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "atmel_usba_udc", &udphs_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "atmel_tcb.0", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "atmel_tcb.0", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "atmel_tcb.0", &tc2_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.0", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "at91rm9200_ssc.1", &ssc1_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffc0000.ssc", &ssc0_clk),
- CLKDEV_CON_DEV_ID("pclk", "fffc4000.ssc", &ssc1_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.0", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "i2c-at91sam9g20.1", &twi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "at91sam9rl-pwm", &pwm_clk),
- CLKDEV_CON_ID("pioA", &pioA_clk),
- CLKDEV_CON_ID("pioB", &pioB_clk),
- CLKDEV_CON_ID("pioC", &pioC_clk),
- CLKDEV_CON_ID("pioD", &pioD_clk),
- /* more lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "fffb0000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "ffffb400.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "ffffb800.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "ffffbc00.serial", &usart3_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "fffa0000.timer", &tc0_clk),
- CLKDEV_CON_DEV_ID("t1_clk", "fffa0000.timer", &tc1_clk),
- CLKDEV_CON_DEV_ID("t2_clk", "fffa0000.timer", &tc2_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "fffa4000.mmc", &mmc_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffa8000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffac000.i2c", &twi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffc8000.pwm", &pwm_clk),
- CLKDEV_CON_DEV_ID(NULL, "ffffc800.pwm", &pwm_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioA_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioC_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioD_clk),
- CLKDEV_CON_ID("adc_clk", &tsc_clk),
-};
-
-static struct clk_lookup usart_clocks_lookups[] = {
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.0", &mck),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.1", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.2", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.3", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "atmel_usart.4", &usart3_clk),
-};
-
-/*
- * The two programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-
-static void __init at91sam9rl_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
- clkdev_add_table(usart_clocks_lookups,
- ARRAY_SIZE(usart_clocks_lookups));
-
- clk_register(&pck0);
- clk_register(&pck1);
-}
-#endif
-
-/* --------------------------------------------------------------------
- * GPIO
- * -------------------------------------------------------------------- */
-
-static struct at91_gpio_bank at91sam9rl_gpio[] __initdata = {
- {
- .id = AT91SAM9RL_ID_PIOA,
- .regbase = AT91SAM9RL_BASE_PIOA,
- }, {
- .id = AT91SAM9RL_ID_PIOB,
- .regbase = AT91SAM9RL_BASE_PIOB,
- }, {
- .id = AT91SAM9RL_ID_PIOC,
- .regbase = AT91SAM9RL_BASE_PIOC,
- }, {
- .id = AT91SAM9RL_ID_PIOD,
- .regbase = AT91SAM9RL_BASE_PIOD,
- }
-};
/* --------------------------------------------------------------------
* AT91SAM9RL processor initialization
@@ -309,121 +39,15 @@ static void __init at91sam9rl_map_io(void)
at91_init_sram(0, AT91SAM9RL_SRAM_BASE, sram_size);
}
-static void __init at91sam9rl_ioremap_registers(void)
-{
- at91_ioremap_ramc(0, AT91SAM9RL_BASE_SDRAMC, 512);
- at91sam926x_ioremap_pit(AT91SAM9RL_BASE_PIT);
- at91sam9_ioremap_smc(0, AT91SAM9RL_BASE_SMC);
- at91_ioremap_matrix(AT91SAM9RL_BASE_MATRIX);
- at91_pm_set_standby(at91sam9_sdram_standby);
-}
-
static void __init at91sam9rl_initialize(void)
{
arm_pm_idle = at91sam9_idle;
at91_sysirq_mask_rtc(AT91SAM9RL_BASE_RTC);
at91_sysirq_mask_rtt(AT91SAM9RL_BASE_RTT);
-
- /* Register GPIO subsystem */
- at91_gpio_init(at91sam9rl_gpio, 4);
-}
-
-static struct resource rstc_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_RSTC,
- .end = AT91SAM9RL_BASE_RSTC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9RL_BASE_SDRAMC,
- .end = AT91SAM9RL_BASE_SDRAMC + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device rstc_device = {
- .name = "at91-sam9260-reset",
- .resource = rstc_resources,
- .num_resources = ARRAY_SIZE(rstc_resources),
-};
-
-static struct resource shdwc_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_SHDWC,
- .end = AT91SAM9RL_BASE_SHDWC + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device shdwc_device = {
- .name = "at91-poweroff",
- .resource = shdwc_resources,
- .num_resources = ARRAY_SIZE(shdwc_resources),
-};
-
-static void __init at91sam9rl_register_devices(void)
-{
- platform_device_register(&rstc_device);
- platform_device_register(&shdwc_device);
-}
-
-/* --------------------------------------------------------------------
- * Interrupt initialization
- * -------------------------------------------------------------------- */
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91sam9rl_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller */
- 7, /* System Peripherals */
- 1, /* Parallel IO Controller A */
- 1, /* Parallel IO Controller B */
- 1, /* Parallel IO Controller C */
- 1, /* Parallel IO Controller D */
- 5, /* USART 0 */
- 5, /* USART 1 */
- 5, /* USART 2 */
- 5, /* USART 3 */
- 0, /* Multimedia Card Interface */
- 6, /* Two-Wire Interface 0 */
- 6, /* Two-Wire Interface 1 */
- 5, /* Serial Peripheral Interface */
- 4, /* Serial Synchronous Controller 0 */
- 4, /* Serial Synchronous Controller 1 */
- 0, /* Timer Counter 0 */
- 0, /* Timer Counter 1 */
- 0, /* Timer Counter 2 */
- 0,
- 0, /* Touch Screen Controller */
- 0, /* DMA Controller */
- 2, /* USB Device High speed port */
- 2, /* LCD Controller */
- 6, /* AC97 Controller */
- 0,
- 0,
- 0,
- 0,
- 0,
- 0,
- 0, /* Advanced Interrupt Controller */
-};
-
-static void __init at91sam9rl_init_time(void)
-{
- at91sam926x_pit_init(NR_IRQS_LEGACY + AT91_ID_SYS);
}
AT91_SOC_START(at91sam9rl)
.map_io = at91sam9rl_map_io,
- .default_irq_priority = at91sam9rl_default_irq_priority,
- .extern_irq = (1 << AT91SAM9RL_ID_IRQ0),
- .ioremap_registers = at91sam9rl_ioremap_registers,
-#if defined(CONFIG_OLD_CLK_AT91)
- .register_clocks = at91sam9rl_register_clocks,
-#endif
- .register_devices = at91sam9rl_register_devices,
.init = at91sam9rl_initialize,
- .init_time = at91sam9rl_init_time,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91sam9rl_devices.c b/arch/arm/mach-at91/at91sam9rl_devices.c
deleted file mode 100644
index 37d1c9e..0000000
--- a/arch/arm/mach-at91/at91sam9rl_devices.c
+++ /dev/null
@@ -1,1260 +0,0 @@
-/*
- * Copyright (C) 2007 Atmel Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- */
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/i2c-gpio.h>
-
-#include <linux/fb.h>
-#include <video/atmel_lcdc.h>
-
-#include <mach/at91sam9rl.h>
-#include <mach/at91sam9rl_matrix.h>
-#include <mach/at91_matrix.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-#include <linux/platform_data/dma-atmel.h>
-#include <linux/platform_data/at91_adc.h>
-
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-/* --------------------------------------------------------------------
- * HDMAC - AHB DMA Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT_HDMAC) || defined(CONFIG_AT_HDMAC_MODULE)
-static u64 hdmac_dmamask = DMA_BIT_MASK(32);
-
-static struct resource hdmac_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_DMA,
- .end = AT91SAM9RL_BASE_DMA + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_DMA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at_hdmac_device = {
- .name = "at91sam9rl_dma",
- .id = -1,
- .dev = {
- .dma_mask = &hdmac_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = hdmac_resources,
- .num_resources = ARRAY_SIZE(hdmac_resources),
-};
-
-void __init at91_add_device_hdmac(void)
-{
- platform_device_register(&at_hdmac_device);
-}
-#else
-void __init at91_add_device_hdmac(void) {}
-#endif
-
-/* --------------------------------------------------------------------
- * USB HS Device (Gadget)
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_USB_ATMEL_USBA) || defined(CONFIG_USB_ATMEL_USBA_MODULE)
-
-static struct resource usba_udc_resources[] = {
- [0] = {
- .start = AT91SAM9RL_UDPHS_FIFO,
- .end = AT91SAM9RL_UDPHS_FIFO + SZ_512K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9RL_BASE_UDPHS,
- .end = AT91SAM9RL_BASE_UDPHS + SZ_1K - 1,
- .flags = IORESOURCE_MEM,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_UDPHS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-#define EP(nam, idx, maxpkt, maxbk, dma, isoc) \
- [idx] = { \
- .name = nam, \
- .index = idx, \
- .fifo_size = maxpkt, \
- .nr_banks = maxbk, \
- .can_dma = dma, \
- .can_isoc = isoc, \
- }
-
-static struct usba_ep_data usba_udc_ep[] __initdata = {
- EP("ep0", 0, 64, 1, 0, 0),
- EP("ep1", 1, 1024, 2, 1, 1),
- EP("ep2", 2, 1024, 2, 1, 1),
- EP("ep3", 3, 1024, 3, 1, 0),
- EP("ep4", 4, 1024, 3, 1, 0),
- EP("ep5", 5, 1024, 3, 1, 1),
- EP("ep6", 6, 1024, 3, 1, 1),
-};
-
-#undef EP
-
-/*
- * pdata doesn't have room for any endpoints, so we need to
- * append room for the ones we need right after it.
- */
-static struct {
- struct usba_platform_data pdata;
- struct usba_ep_data ep[7];
-} usba_udc_data;
-
-static struct platform_device at91_usba_udc_device = {
- .name = "atmel_usba_udc",
- .id = -1,
- .dev = {
- .platform_data = &usba_udc_data.pdata,
- },
- .resource = usba_udc_resources,
- .num_resources = ARRAY_SIZE(usba_udc_resources),
-};
-
-void __init at91_add_device_usba(struct usba_platform_data *data)
-{
- /*
- * Invalid pins are 0 on AT91, but the usba driver is shared
- * with AVR32, which use negative values instead. Once/if
- * gpio_is_valid() is ported to AT91, revisit this code.
- */
- usba_udc_data.pdata.vbus_pin = -EINVAL;
- usba_udc_data.pdata.num_ep = ARRAY_SIZE(usba_udc_ep);
- memcpy(usba_udc_data.ep, usba_udc_ep, sizeof(usba_udc_ep));
-
- if (data && gpio_is_valid(data->vbus_pin)) {
- at91_set_gpio_input(data->vbus_pin, 0);
- at91_set_deglitch(data->vbus_pin, 1);
- usba_udc_data.pdata.vbus_pin = data->vbus_pin;
- }
-
- /* Pullup pin is handled internally by USB device peripheral */
-
- platform_device_register(&at91_usba_udc_device);
-}
-#else
-void __init at91_add_device_usba(struct usba_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * MMC / SD
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_MMC_ATMELMCI)
-static u64 mmc_dmamask = DMA_BIT_MASK(32);
-static struct mci_platform_data mmc_data;
-
-static struct resource mmc_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_MCI,
- .end = AT91SAM9RL_BASE_MCI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_MCI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_mmc_device = {
- .name = "atmel_mci",
- .id = -1,
- .dev = {
- .dma_mask = &mmc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &mmc_data,
- },
- .resource = mmc_resources,
- .num_resources = ARRAY_SIZE(mmc_resources),
-};
-
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data)
-{
- if (!data)
- return;
-
- if (data->slot[0].bus_width) {
- /* input/irq */
- if (gpio_is_valid(data->slot[0].detect_pin)) {
- at91_set_gpio_input(data->slot[0].detect_pin, 1);
- at91_set_deglitch(data->slot[0].detect_pin, 1);
- }
- if (gpio_is_valid(data->slot[0].wp_pin))
- at91_set_gpio_input(data->slot[0].wp_pin, 1);
-
- /* CLK */
- at91_set_A_periph(AT91_PIN_PA2, 0);
-
- /* CMD */
- at91_set_A_periph(AT91_PIN_PA1, 1);
-
- /* DAT0, maybe DAT1..DAT3 */
- at91_set_A_periph(AT91_PIN_PA0, 1);
- if (data->slot[0].bus_width == 4) {
- at91_set_A_periph(AT91_PIN_PA3, 1);
- at91_set_A_periph(AT91_PIN_PA4, 1);
- at91_set_A_periph(AT91_PIN_PA5, 1);
- }
-
- mmc_data = *data;
- platform_device_register(&at91sam9rl_mmc_device);
- }
-}
-#else
-void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * NAND / SmartMedia
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_MTD_NAND_ATMEL) || defined(CONFIG_MTD_NAND_ATMEL_MODULE)
-static struct atmel_nand_data nand_data;
-
-#define NAND_BASE AT91_CHIPSELECT_3
-
-static struct resource nand_resources[] = {
- [0] = {
- .start = NAND_BASE,
- .end = NAND_BASE + SZ_256M - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = AT91SAM9RL_BASE_ECC,
- .end = AT91SAM9RL_BASE_ECC + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device atmel_nand_device = {
- .name = "atmel_nand",
- .id = -1,
- .dev = {
- .platform_data = &nand_data,
- },
- .resource = nand_resources,
- .num_resources = ARRAY_SIZE(nand_resources),
-};
-
-void __init at91_add_device_nand(struct atmel_nand_data *data)
-{
- unsigned long csa;
-
- if (!data)
- return;
-
- csa = at91_matrix_read(AT91_MATRIX_EBICSA);
- at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_CS3A_SMC_SMARTMEDIA);
-
- /* enable pin */
- if (gpio_is_valid(data->enable_pin))
- at91_set_gpio_output(data->enable_pin, 1);
-
- /* ready/busy pin */
- if (gpio_is_valid(data->rdy_pin))
- at91_set_gpio_input(data->rdy_pin, 1);
-
- /* card detect pin */
- if (gpio_is_valid(data->det_pin))
- at91_set_gpio_input(data->det_pin, 1);
-
- at91_set_A_periph(AT91_PIN_PB4, 0); /* NANDOE */
- at91_set_A_periph(AT91_PIN_PB5, 0); /* NANDWE */
-
- nand_data = *data;
- platform_device_register(&atmel_nand_device);
-}
-
-#else
-void __init at91_add_device_nand(struct atmel_nand_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * TWI (i2c)
- * -------------------------------------------------------------------- */
-
-/*
- * Prefer the GPIO code since the TWI controller isn't robust
- * (gets overruns and underruns under load) and can only issue
- * repeated STARTs in one scenario (the driver doesn't yet handle them).
- */
-#if defined(CONFIG_I2C_GPIO) || defined(CONFIG_I2C_GPIO_MODULE)
-
-static struct i2c_gpio_platform_data pdata = {
- .sda_pin = AT91_PIN_PA23,
- .sda_is_open_drain = 1,
- .scl_pin = AT91_PIN_PA24,
- .scl_is_open_drain = 1,
- .udelay = 2, /* ~100 kHz */
-};
-
-static struct platform_device at91sam9rl_twi_device = {
- .name = "i2c-gpio",
- .id = 0,
- .dev.platform_data = &pdata,
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- at91_set_GPIO_periph(AT91_PIN_PA23, 1); /* TWD (SDA) */
- at91_set_multi_drive(AT91_PIN_PA23, 1);
-
- at91_set_GPIO_periph(AT91_PIN_PA24, 1); /* TWCK (SCL) */
- at91_set_multi_drive(AT91_PIN_PA24, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9rl_twi_device);
-}
-
-#elif defined(CONFIG_I2C_AT91) || defined(CONFIG_I2C_AT91_MODULE)
-
-static struct resource twi_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_TWI0,
- .end = AT91SAM9RL_BASE_TWI0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TWI0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_twi_device = {
- .name = "i2c-at91sam9g20",
- .id = 0,
- .resource = twi_resources,
- .num_resources = ARRAY_SIZE(twi_resources),
-};
-
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices)
-{
- /* pins used for TWI interface */
- at91_set_A_periph(AT91_PIN_PA23, 0); /* TWD */
- at91_set_multi_drive(AT91_PIN_PA23, 1);
-
- at91_set_A_periph(AT91_PIN_PA24, 0); /* TWCK */
- at91_set_multi_drive(AT91_PIN_PA24, 1);
-
- i2c_register_board_info(0, devices, nr_devices);
- platform_device_register(&at91sam9rl_twi_device);
-}
-#else
-void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SPI
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-static u64 spi_dmamask = DMA_BIT_MASK(32);
-
-static struct resource spi_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_SPI,
- .end = AT91SAM9RL_BASE_SPI + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SPI,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_spi_device = {
- .name = "atmel_spi",
- .id = 0,
- .dev = {
- .dma_mask = &spi_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = spi_resources,
- .num_resources = ARRAY_SIZE(spi_resources),
-};
-
-static const unsigned spi_standard_cs[4] = { AT91_PIN_PA28, AT91_PIN_PB7, AT91_PIN_PD8, AT91_PIN_PD9 };
-
-
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices)
-{
- int i;
- unsigned long cs_pin;
-
- at91_set_A_periph(AT91_PIN_PA25, 0); /* MISO */
- at91_set_A_periph(AT91_PIN_PA26, 0); /* MOSI */
- at91_set_A_periph(AT91_PIN_PA27, 0); /* SPCK */
-
- /* Enable SPI chip-selects */
- for (i = 0; i < nr_devices; i++) {
- if (devices[i].controller_data)
- cs_pin = (unsigned long) devices[i].controller_data;
- else
- cs_pin = spi_standard_cs[devices[i].chip_select];
-
- if (!gpio_is_valid(cs_pin))
- continue;
-
- /* enable chip-select pin */
- at91_set_gpio_output(cs_pin, 1);
-
- /* pass chip-select pin to driver */
- devices[i].controller_data = (void *) cs_pin;
- }
-
- spi_register_board_info(devices, nr_devices);
- platform_device_register(&at91sam9rl_spi_device);
-}
-#else
-void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * AC97
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SND_ATMEL_AC97C) || defined(CONFIG_SND_ATMEL_AC97C_MODULE)
-static u64 ac97_dmamask = DMA_BIT_MASK(32);
-static struct ac97c_platform_data ac97_data;
-
-static struct resource ac97_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_AC97C,
- .end = AT91SAM9RL_BASE_AC97C + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_AC97C,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_ac97_device = {
- .name = "atmel_ac97c",
- .id = 0,
- .dev = {
- .dma_mask = &ac97_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &ac97_data,
- },
- .resource = ac97_resources,
- .num_resources = ARRAY_SIZE(ac97_resources),
-};
-
-void __init at91_add_device_ac97(struct ac97c_platform_data *data)
-{
- if (!data)
- return;
-
- at91_set_A_periph(AT91_PIN_PD1, 0); /* AC97FS */
- at91_set_A_periph(AT91_PIN_PD2, 0); /* AC97CK */
- at91_set_A_periph(AT91_PIN_PD3, 0); /* AC97TX */
- at91_set_A_periph(AT91_PIN_PD4, 0); /* AC97RX */
-
- /* reset */
- if (gpio_is_valid(data->reset_pin))
- at91_set_gpio_output(data->reset_pin, 0);
-
- ac97_data = *data;
- platform_device_register(&at91sam9rl_ac97_device);
-}
-#else
-void __init at91_add_device_ac97(struct ac97c_platform_data *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * LCD Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static u64 lcdc_dmamask = DMA_BIT_MASK(32);
-static struct atmel_lcdfb_pdata lcdc_data;
-
-static struct resource lcdc_resources[] = {
- [0] = {
- .start = AT91SAM9RL_LCDC_BASE,
- .end = AT91SAM9RL_LCDC_BASE + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_LCDC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91_lcdc_device = {
- .name = "at91sam9rl-lcdfb",
- .id = 0,
- .dev = {
- .dma_mask = &lcdc_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &lcdc_data,
- },
- .resource = lcdc_resources,
- .num_resources = ARRAY_SIZE(lcdc_resources),
-};
-
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data)
-{
- if (!data) {
- return;
- }
-
- at91_set_B_periph(AT91_PIN_PC1, 0); /* LCDPWR */
- at91_set_A_periph(AT91_PIN_PC5, 0); /* LCDHSYNC */
- at91_set_A_periph(AT91_PIN_PC6, 0); /* LCDDOTCK */
- at91_set_A_periph(AT91_PIN_PC7, 0); /* LCDDEN */
- at91_set_A_periph(AT91_PIN_PC3, 0); /* LCDCC */
- at91_set_B_periph(AT91_PIN_PC9, 0); /* LCDD3 */
- at91_set_B_periph(AT91_PIN_PC10, 0); /* LCDD4 */
- at91_set_B_periph(AT91_PIN_PC11, 0); /* LCDD5 */
- at91_set_B_periph(AT91_PIN_PC12, 0); /* LCDD6 */
- at91_set_B_periph(AT91_PIN_PC13, 0); /* LCDD7 */
- at91_set_B_periph(AT91_PIN_PC15, 0); /* LCDD11 */
- at91_set_B_periph(AT91_PIN_PC16, 0); /* LCDD12 */
- at91_set_B_periph(AT91_PIN_PC17, 0); /* LCDD13 */
- at91_set_B_periph(AT91_PIN_PC18, 0); /* LCDD14 */
- at91_set_B_periph(AT91_PIN_PC19, 0); /* LCDD15 */
- at91_set_B_periph(AT91_PIN_PC20, 0); /* LCDD18 */
- at91_set_B_periph(AT91_PIN_PC21, 0); /* LCDD19 */
- at91_set_B_periph(AT91_PIN_PC22, 0); /* LCDD20 */
- at91_set_B_periph(AT91_PIN_PC23, 0); /* LCDD21 */
- at91_set_B_periph(AT91_PIN_PC24, 0); /* LCDD22 */
- at91_set_B_periph(AT91_PIN_PC25, 0); /* LCDD23 */
-
- lcdc_data = *data;
- platform_device_register(&at91_lcdc_device);
-}
-#else
-void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * Timer/Counter block
- * -------------------------------------------------------------------- */
-
-#ifdef CONFIG_ATMEL_TCLIB
-
-static struct resource tcb_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_TCB0,
- .end = AT91SAM9RL_BASE_TCB0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC0,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC1,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TC2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_tcb_device = {
- .name = "atmel_tcb",
- .id = 0,
- .resource = tcb_resources,
- .num_resources = ARRAY_SIZE(tcb_resources),
-};
-
-static void __init at91_add_device_tc(void)
-{
- platform_device_register(&at91sam9rl_tcb_device);
-}
-#else
-static void __init at91_add_device_tc(void) { }
-#endif
-
-
-/* --------------------------------------------------------------------
- * ADC and Touchscreen
- * -------------------------------------------------------------------- */
-
-#if IS_ENABLED(CONFIG_AT91_ADC)
-static struct at91_adc_data adc_data;
-
-static struct resource adc_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_TSC,
- .end = AT91SAM9RL_BASE_TSC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_TSC,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91_adc_device = {
- .name = "at91sam9rl-adc",
- .id = -1,
- .dev = {
- .platform_data = &adc_data,
- },
- .resource = adc_resources,
- .num_resources = ARRAY_SIZE(adc_resources),
-};
-
-static struct at91_adc_trigger at91_adc_triggers[] = {
- [0] = {
- .name = "external-rising",
- .value = 1,
- .is_external = true,
- },
- [1] = {
- .name = "external-falling",
- .value = 2,
- .is_external = true,
- },
- [2] = {
- .name = "external-any",
- .value = 3,
- .is_external = true,
- },
- [3] = {
- .name = "continuous",
- .value = 6,
- .is_external = false,
- },
-};
-
-void __init at91_add_device_adc(struct at91_adc_data *data)
-{
- if (!data)
- return;
-
- if (test_bit(0, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PA17, 0);
- if (test_bit(1, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PA18, 0);
- if (test_bit(2, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PA19, 0);
- if (test_bit(3, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PA20, 0);
- if (test_bit(4, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PD6, 0);
- if (test_bit(5, &data->channels_used))
- at91_set_A_periph(AT91_PIN_PD7, 0);
-
- if (data->use_external_triggers)
- at91_set_A_periph(AT91_PIN_PB15, 0);
-
- data->startup_time = 40;
- data->trigger_number = 4;
- data->trigger_list = at91_adc_triggers;
-
- adc_data = *data;
- platform_device_register(&at91_adc_device);
-}
-#else
-void __init at91_add_device_adc(struct at91_adc_data *data) {}
-#endif
-
-/* --------------------------------------------------------------------
- * RTC
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_RTC_DRV_AT91RM9200) || defined(CONFIG_RTC_DRV_AT91RM9200_MODULE)
-static struct platform_device at91sam9rl_rtc_device = {
- .name = "at91_rtc",
- .id = -1,
- .num_resources = 0,
-};
-
-static void __init at91_add_device_rtc(void)
-{
- platform_device_register(&at91sam9rl_rtc_device);
-}
-#else
-static void __init at91_add_device_rtc(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * RTT
- * -------------------------------------------------------------------- */
-
-static struct resource rtt_resources[] = {
- {
- .start = AT91SAM9RL_BASE_RTT,
- .end = AT91SAM9RL_BASE_RTT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_MEM,
- }, {
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device at91sam9rl_rtt_device = {
- .name = "at91_rtt",
- .id = 0,
- .resource = rtt_resources,
-};
-
-#if IS_ENABLED(CONFIG_RTC_DRV_AT91SAM9)
-static void __init at91_add_device_rtt_rtc(void)
-{
- at91sam9rl_rtt_device.name = "rtc-at91sam9";
- /*
- * The second resource is needed:
- * GPBR will serve as the storage for RTC time offset
- */
- at91sam9rl_rtt_device.num_resources = 3;
- rtt_resources[1].start = AT91SAM9RL_BASE_GPBR +
- 4 * CONFIG_RTC_DRV_AT91SAM9_GPBR;
- rtt_resources[1].end = rtt_resources[1].start + 3;
- rtt_resources[2].start = NR_IRQS_LEGACY + AT91_ID_SYS;
- rtt_resources[2].end = NR_IRQS_LEGACY + AT91_ID_SYS;
-}
-#else
-static void __init at91_add_device_rtt_rtc(void)
-{
- /* Only one resource is needed: RTT not used as RTC */
- at91sam9rl_rtt_device.num_resources = 1;
-}
-#endif
-
-static void __init at91_add_device_rtt(void)
-{
- at91_add_device_rtt_rtc();
- platform_device_register(&at91sam9rl_rtt_device);
-}
-
-
-/* --------------------------------------------------------------------
- * Watchdog
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
-static struct resource wdt_resources[] = {
- {
- .start = AT91SAM9RL_BASE_WDT,
- .end = AT91SAM9RL_BASE_WDT + SZ_16 - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device at91sam9rl_wdt_device = {
- .name = "at91_wdt",
- .id = -1,
- .resource = wdt_resources,
- .num_resources = ARRAY_SIZE(wdt_resources),
-};
-
-static void __init at91_add_device_watchdog(void)
-{
- platform_device_register(&at91sam9rl_wdt_device);
-}
-#else
-static void __init at91_add_device_watchdog(void) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * PWM
- * --------------------------------------------------------------------*/
-
-#if IS_ENABLED(CONFIG_PWM_ATMEL)
-static struct resource pwm_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_PWMC,
- .end = AT91SAM9RL_BASE_PWMC + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_PWMC,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_pwm0_device = {
- .name = "at91sam9rl-pwm",
- .id = -1,
- .resource = pwm_resources,
- .num_resources = ARRAY_SIZE(pwm_resources),
-};
-
-void __init at91_add_device_pwm(u32 mask)
-{
- if (mask & (1 << AT91_PWM0))
- at91_set_B_periph(AT91_PIN_PB8, 1); /* enable PWM0 */
-
- if (mask & (1 << AT91_PWM1))
- at91_set_B_periph(AT91_PIN_PB9, 1); /* enable PWM1 */
-
- if (mask & (1 << AT91_PWM2))
- at91_set_B_periph(AT91_PIN_PD5, 1); /* enable PWM2 */
-
- if (mask & (1 << AT91_PWM3))
- at91_set_B_periph(AT91_PIN_PD8, 1); /* enable PWM3 */
-
- platform_device_register(&at91sam9rl_pwm0_device);
-}
-#else
-void __init at91_add_device_pwm(u32 mask) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * SSC -- Synchronous Serial Controller
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_ATMEL_SSC) || defined(CONFIG_ATMEL_SSC_MODULE)
-static u64 ssc0_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc0_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_SSC0,
- .end = AT91SAM9RL_BASE_SSC0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_ssc0_device = {
- .name = "at91rm9200_ssc",
- .id = 0,
- .dev = {
- .dma_mask = &ssc0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc0_resources,
- .num_resources = ARRAY_SIZE(ssc0_resources),
-};
-
-static inline void configure_ssc0_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_A_periph(AT91_PIN_PC0, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_A_periph(AT91_PIN_PC1, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_A_periph(AT91_PIN_PA15, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_A_periph(AT91_PIN_PA16, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_B_periph(AT91_PIN_PA10, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_B_periph(AT91_PIN_PA22, 1);
-}
-
-static u64 ssc1_dmamask = DMA_BIT_MASK(32);
-
-static struct resource ssc1_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_SSC1,
- .end = AT91SAM9RL_BASE_SSC1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_SSC1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device at91sam9rl_ssc1_device = {
- .name = "at91rm9200_ssc",
- .id = 1,
- .dev = {
- .dma_mask = &ssc1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- },
- .resource = ssc1_resources,
- .num_resources = ARRAY_SIZE(ssc1_resources),
-};
-
-static inline void configure_ssc1_pins(unsigned pins)
-{
- if (pins & ATMEL_SSC_TF)
- at91_set_B_periph(AT91_PIN_PA29, 1);
- if (pins & ATMEL_SSC_TK)
- at91_set_B_periph(AT91_PIN_PA30, 1);
- if (pins & ATMEL_SSC_TD)
- at91_set_B_periph(AT91_PIN_PA13, 1);
- if (pins & ATMEL_SSC_RD)
- at91_set_B_periph(AT91_PIN_PA14, 1);
- if (pins & ATMEL_SSC_RK)
- at91_set_B_periph(AT91_PIN_PA9, 1);
- if (pins & ATMEL_SSC_RF)
- at91_set_B_periph(AT91_PIN_PA8, 1);
-}
-
-/*
- * SSC controllers are accessed through library code, instead of any
- * kind of all-singing/all-dancing driver. For example one could be
- * used by a particular I2S audio codec's driver, while another one
- * on the same system might be used by a custom data capture driver.
- */
-void __init at91_add_device_ssc(unsigned id, unsigned pins)
-{
- struct platform_device *pdev;
-
- /*
- * NOTE: caller is responsible for passing information matching
- * "pins" to whatever will be using each particular controller.
- */
- switch (id) {
- case AT91SAM9RL_ID_SSC0:
- pdev = &at91sam9rl_ssc0_device;
- configure_ssc0_pins(pins);
- break;
- case AT91SAM9RL_ID_SSC1:
- pdev = &at91sam9rl_ssc1_device;
- configure_ssc1_pins(pins);
- break;
- default:
- return;
- }
-
- platform_device_register(pdev);
-}
-
-#else
-void __init at91_add_device_ssc(unsigned id, unsigned pins) {}
-#endif
-
-
-/* --------------------------------------------------------------------
- * UART
- * -------------------------------------------------------------------- */
-
-#if defined(CONFIG_SERIAL_ATMEL)
-static struct resource dbgu_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_DBGU,
- .end = AT91SAM9RL_BASE_DBGU + SZ_512 - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91_ID_SYS,
- .end = NR_IRQS_LEGACY + AT91_ID_SYS,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data dbgu_data = {
- .use_dma_tx = 0,
- .use_dma_rx = 0, /* DBGU not capable of receive DMA */
-};
-
-static u64 dbgu_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9rl_dbgu_device = {
- .name = "atmel_usart",
- .id = 0,
- .dev = {
- .dma_mask = &dbgu_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &dbgu_data,
- },
- .resource = dbgu_resources,
- .num_resources = ARRAY_SIZE(dbgu_resources),
-};
-
-static inline void configure_dbgu_pins(void)
-{
- at91_set_A_periph(AT91_PIN_PA21, 0); /* DRXD */
- at91_set_A_periph(AT91_PIN_PA22, 1); /* DTXD */
-}
-
-static struct resource uart0_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_US0,
- .end = AT91SAM9RL_BASE_US0 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US0,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart0_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart0_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9rl_uart0_device = {
- .name = "atmel_usart",
- .id = 1,
- .dev = {
- .dma_mask = &uart0_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart0_data,
- },
- .resource = uart0_resources,
- .num_resources = ARRAY_SIZE(uart0_resources),
-};
-
-static inline void configure_usart0_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PA6, 1); /* TXD0 */
- at91_set_A_periph(AT91_PIN_PA7, 0); /* RXD0 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PA9, 0); /* RTS0 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PA10, 0); /* CTS0 */
- if (pins & ATMEL_UART_DSR)
- at91_set_A_periph(AT91_PIN_PD14, 0); /* DSR0 */
- if (pins & ATMEL_UART_DTR)
- at91_set_A_periph(AT91_PIN_PD15, 0); /* DTR0 */
- if (pins & ATMEL_UART_DCD)
- at91_set_A_periph(AT91_PIN_PD16, 0); /* DCD0 */
- if (pins & ATMEL_UART_RI)
- at91_set_A_periph(AT91_PIN_PD17, 0); /* RI0 */
-}
-
-static struct resource uart1_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_US1,
- .end = AT91SAM9RL_BASE_US1 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US1,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart1_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart1_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9rl_uart1_device = {
- .name = "atmel_usart",
- .id = 2,
- .dev = {
- .dma_mask = &uart1_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart1_data,
- },
- .resource = uart1_resources,
- .num_resources = ARRAY_SIZE(uart1_resources),
-};
-
-static inline void configure_usart1_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PA11, 1); /* TXD1 */
- at91_set_A_periph(AT91_PIN_PA12, 0); /* RXD1 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PA18, 0); /* RTS1 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PA19, 0); /* CTS1 */
-}
-
-static struct resource uart2_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_US2,
- .end = AT91SAM9RL_BASE_US2 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US2,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart2_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart2_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9rl_uart2_device = {
- .name = "atmel_usart",
- .id = 3,
- .dev = {
- .dma_mask = &uart2_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart2_data,
- },
- .resource = uart2_resources,
- .num_resources = ARRAY_SIZE(uart2_resources),
-};
-
-static inline void configure_usart2_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PA13, 1); /* TXD2 */
- at91_set_A_periph(AT91_PIN_PA14, 0); /* RXD2 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_A_periph(AT91_PIN_PA29, 0); /* RTS2 */
- if (pins & ATMEL_UART_CTS)
- at91_set_A_periph(AT91_PIN_PA30, 0); /* CTS2 */
-}
-
-static struct resource uart3_resources[] = {
- [0] = {
- .start = AT91SAM9RL_BASE_US3,
- .end = AT91SAM9RL_BASE_US3 + SZ_16K - 1,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
- .end = NR_IRQS_LEGACY + AT91SAM9RL_ID_US3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct atmel_uart_data uart3_data = {
- .use_dma_tx = 1,
- .use_dma_rx = 1,
-};
-
-static u64 uart3_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device at91sam9rl_uart3_device = {
- .name = "atmel_usart",
- .id = 4,
- .dev = {
- .dma_mask = &uart3_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &uart3_data,
- },
- .resource = uart3_resources,
- .num_resources = ARRAY_SIZE(uart3_resources),
-};
-
-static inline void configure_usart3_pins(unsigned pins)
-{
- at91_set_A_periph(AT91_PIN_PB0, 1); /* TXD3 */
- at91_set_A_periph(AT91_PIN_PB1, 0); /* RXD3 */
-
- if (pins & ATMEL_UART_RTS)
- at91_set_B_periph(AT91_PIN_PD4, 0); /* RTS3 */
- if (pins & ATMEL_UART_CTS)
- at91_set_B_periph(AT91_PIN_PD3, 0); /* CTS3 */
-}
-
-static struct platform_device *__initdata at91_uarts[ATMEL_MAX_UART]; /* the UARTs to use */
-
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins)
-{
- struct platform_device *pdev;
- struct atmel_uart_data *pdata;
-
- switch (id) {
- case 0: /* DBGU */
- pdev = &at91sam9rl_dbgu_device;
- configure_dbgu_pins();
- break;
- case AT91SAM9RL_ID_US0:
- pdev = &at91sam9rl_uart0_device;
- configure_usart0_pins(pins);
- break;
- case AT91SAM9RL_ID_US1:
- pdev = &at91sam9rl_uart1_device;
- configure_usart1_pins(pins);
- break;
- case AT91SAM9RL_ID_US2:
- pdev = &at91sam9rl_uart2_device;
- configure_usart2_pins(pins);
- break;
- case AT91SAM9RL_ID_US3:
- pdev = &at91sam9rl_uart3_device;
- configure_usart3_pins(pins);
- break;
- default:
- return;
- }
- pdata = pdev->dev.platform_data;
- pdata->num = portnr; /* update to mapped ID */
-
- if (portnr < ATMEL_MAX_UART)
- at91_uarts[portnr] = pdev;
-}
-
-void __init at91_add_device_serial(void)
-{
- int i;
-
- for (i = 0; i < ATMEL_MAX_UART; i++) {
- if (at91_uarts[i])
- platform_device_register(at91_uarts[i]);
- }
-}
-#else
-void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins) {}
-void __init at91_add_device_serial(void) {}
-#endif
-
-
-/* -------------------------------------------------------------------- */
-
-/*
- * These devices are always present and don't need any board-specific
- * setup.
- */
-static int __init at91_add_standard_devices(void)
-{
- at91_add_device_hdmac();
- at91_add_device_rtc();
- at91_add_device_rtt();
- at91_add_device_watchdog();
- at91_add_device_tc();
- return 0;
-}
-
-arch_initcall(at91_add_standard_devices);
diff --git a/arch/arm/mach-at91/at91sam9x5.c b/arch/arm/mach-at91/at91sam9x5.c
index 028268ff..f0d5a69 100644
--- a/arch/arm/mach-at91/at91sam9x5.c
+++ b/arch/arm/mach-at91/at91sam9x5.c
@@ -6,317 +6,11 @@
* Licensed under GPLv2 or later.
*/
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/clk/at91_pmc.h>
+#include <asm/system_misc.h>
+#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <mach/at91sam9x5.h>
-#include <mach/cpu.h>
-
-#include "board.h"
#include "soc.h"
#include "generic.h"
-#include "sam9_smc.h"
-
-#if defined(CONFIG_OLD_CLK_AT91)
-#include "clock.h"
-/* --------------------------------------------------------------------
- * Clocks
- * -------------------------------------------------------------------- */
-
-/*
- * The peripheral clocks.
- */
-static struct clk pioAB_clk = {
- .name = "pioAB_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_PIOAB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pioCD_clk = {
- .name = "pioCD_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_PIOCD,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk smd_clk = {
- .name = "smd_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_SMD,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart0_clk = {
- .name = "usart0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_USART0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart1_clk = {
- .name = "usart1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_USART1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk usart2_clk = {
- .name = "usart2_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_USART2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* USART3 clock - Only for sam9g25/sam9x25 */
-static struct clk usart3_clk = {
- .name = "usart3_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_USART3,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi0_clk = {
- .name = "twi0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_TWI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi1_clk = {
- .name = "twi1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_TWI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk twi2_clk = {
- .name = "twi2_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_TWI2,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc0_clk = {
- .name = "mci0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_MCI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi0_clk = {
- .name = "spi0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_SPI0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk spi1_clk = {
- .name = "spi1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_SPI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uart0_clk = {
- .name = "uart0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_UART0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uart1_clk = {
- .name = "uart1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_UART1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk tcb0_clk = {
- .name = "tcb0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_TCB,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk pwm_clk = {
- .name = "pwm_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_PWM,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_clk = {
- .name = "adc_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_ADC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk adc_op_clk = {
- .name = "adc_op_clk",
- .type = CLK_TYPE_PERIPHERAL,
- .rate_hz = 5000000,
-};
-static struct clk dma0_clk = {
- .name = "dma0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_DMA0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk dma1_clk = {
- .name = "dma1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_DMA1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk uhphs_clk = {
- .name = "uhphs",
- .pmc_mask = 1 << AT91SAM9X5_ID_UHPHS,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk udphs_clk = {
- .name = "udphs_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_UDPHS,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* emac0 clock - Only for sam9g25/sam9x25/sam9g35/sam9x35 */
-static struct clk macb0_clk = {
- .name = "pclk",
- .pmc_mask = 1 << AT91SAM9X5_ID_EMAC0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* lcd clock - Only for sam9g15/sam9g35/sam9x35 */
-static struct clk lcdc_clk = {
- .name = "lcdc_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_LCDC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* isi clock - Only for sam9g25 */
-static struct clk isi_clk = {
- .name = "isi_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_ISI,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk mmc1_clk = {
- .name = "mci1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_MCI1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* emac1 clock - Only for sam9x25 */
-static struct clk macb1_clk = {
- .name = "pclk",
- .pmc_mask = 1 << AT91SAM9X5_ID_EMAC1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-static struct clk ssc_clk = {
- .name = "ssc_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_SSC,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* can0 clock - Only for sam9x35 */
-static struct clk can0_clk = {
- .name = "can0_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_CAN0,
- .type = CLK_TYPE_PERIPHERAL,
-};
-/* can1 clock - Only for sam9x35 */
-static struct clk can1_clk = {
- .name = "can1_clk",
- .pmc_mask = 1 << AT91SAM9X5_ID_CAN1,
- .type = CLK_TYPE_PERIPHERAL,
-};
-
-static struct clk *periph_clocks[] __initdata = {
- &pioAB_clk,
- &pioCD_clk,
- &smd_clk,
- &usart0_clk,
- &usart1_clk,
- &usart2_clk,
- &twi0_clk,
- &twi1_clk,
- &twi2_clk,
- &mmc0_clk,
- &spi0_clk,
- &spi1_clk,
- &uart0_clk,
- &uart1_clk,
- &tcb0_clk,
- &pwm_clk,
- &adc_clk,
- &adc_op_clk,
- &dma0_clk,
- &dma1_clk,
- &uhphs_clk,
- &udphs_clk,
- &mmc1_clk,
- &ssc_clk,
- // irq0
-};
-
-static struct clk_lookup periph_clocks_lookups[] = {
- /* lookup table for DT entries */
- CLKDEV_CON_DEV_ID("usart", "fffff200.serial", &mck),
- CLKDEV_CON_DEV_ID("usart", "f801c000.serial", &usart0_clk),
- CLKDEV_CON_DEV_ID("usart", "f8020000.serial", &usart1_clk),
- CLKDEV_CON_DEV_ID("usart", "f8024000.serial", &usart2_clk),
- CLKDEV_CON_DEV_ID("usart", "f8028000.serial", &usart3_clk),
- CLKDEV_CON_DEV_ID("usart", "f8040000.serial", &uart0_clk),
- CLKDEV_CON_DEV_ID("usart", "f8044000.serial", &uart1_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "f8008000.timer", &tcb0_clk),
- CLKDEV_CON_DEV_ID("t0_clk", "f800c000.timer", &tcb0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f0008000.mmc", &mmc0_clk),
- CLKDEV_CON_DEV_ID("mci_clk", "f000c000.mmc", &mmc1_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffec00.dma-controller", &dma0_clk),
- CLKDEV_CON_DEV_ID("dma_clk", "ffffee00.dma-controller", &dma1_clk),
- CLKDEV_CON_DEV_ID("pclk", "f0010000.ssc", &ssc_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8010000.i2c", &twi0_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8014000.i2c", &twi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8018000.i2c", &twi2_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "f0000000.spi", &spi0_clk),
- CLKDEV_CON_DEV_ID("spi_clk", "f0004000.spi", &spi1_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff400.gpio", &pioAB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff600.gpio", &pioAB_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffff800.gpio", &pioCD_clk),
- CLKDEV_CON_DEV_ID(NULL, "fffffa00.gpio", &pioCD_clk),
- /* additional fake clock for macb_hclk */
- CLKDEV_CON_DEV_ID("hclk", "f802c000.ethernet", &macb0_clk),
- CLKDEV_CON_DEV_ID("hclk", "f8030000.ethernet", &macb1_clk),
- CLKDEV_CON_DEV_ID("hclk", "600000.ohci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("ohci_clk", "600000.ohci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("ehci_clk", "700000.ehci", &uhphs_clk),
- CLKDEV_CON_DEV_ID("hclk", "500000.gadget", &utmi_clk),
- CLKDEV_CON_DEV_ID("pclk", "500000.gadget", &udphs_clk),
- CLKDEV_CON_DEV_ID(NULL, "f8034000.pwm", &pwm_clk),
-};
-
-/*
- * The two programmable clocks.
- * You must configure pin multiplexing to bring these signals out.
- */
-static struct clk pck0 = {
- .name = "pck0",
- .pmc_mask = AT91_PMC_PCK0,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 0,
-};
-static struct clk pck1 = {
- .name = "pck1",
- .pmc_mask = AT91_PMC_PCK1,
- .type = CLK_TYPE_PROGRAMMABLE,
- .id = 1,
-};
-
-static void __init at91sam9x5_register_clocks(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(periph_clocks); i++)
- clk_register(periph_clocks[i]);
-
- clkdev_add_table(periph_clocks_lookups,
- ARRAY_SIZE(periph_clocks_lookups));
-
- if (cpu_is_at91sam9g25()
- || cpu_is_at91sam9x25())
- clk_register(&usart3_clk);
-
- if (cpu_is_at91sam9g25()
- || cpu_is_at91sam9x25()
- || cpu_is_at91sam9g35()
- || cpu_is_at91sam9x35())
- clk_register(&macb0_clk);
-
- if (cpu_is_at91sam9g15()
- || cpu_is_at91sam9g35()
- || cpu_is_at91sam9x35())
- clk_register(&lcdc_clk);
-
- if (cpu_is_at91sam9g25())
- clk_register(&isi_clk);
-
- if (cpu_is_at91sam9x25())
- clk_register(&macb1_clk);
-
- if (cpu_is_at91sam9x25()
- || cpu_is_at91sam9x35()) {
- clk_register(&can0_clk);
- clk_register(&can1_clk);
- }
-
- clk_register(&pck0);
- clk_register(&pck1);
-}
-#else
-#define at91sam9x5_register_clocks NULL
-#endif
/* --------------------------------------------------------------------
* AT91SAM9x5 processor initialization
@@ -338,6 +32,5 @@ static void __init at91sam9x5_initialize(void)
AT91_SOC_START(at91sam9x5)
.map_io = at91sam9x5_map_io,
- .register_clocks = at91sam9x5_register_clocks,
.init = at91sam9x5_initialize,
AT91_SOC_END
diff --git a/arch/arm/mach-at91/at91x40.c b/arch/arm/mach-at91/at91x40.c
deleted file mode 100644
index 7523f1c..0000000
--- a/arch/arm/mach-at91/at91x40.c
+++ /dev/null
@@ -1,93 +0,0 @@
-/*
- * arch/arm/mach-at91/at91x40.c
- *
- * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
- * Copyright (C) 2005 SAN People
- *
- * 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/irq.h>
-#include <linux/io.h>
-#include <asm/proc-fns.h>
-#include <asm/system_misc.h>
-#include <asm/mach/arch.h>
-#include <mach/at91x40.h>
-#include <mach/at91_st.h>
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "generic.h"
-
-/*
- * Export the clock functions for the AT91X40. Some external code common
- * to all AT91 family parts relys on this, like the gpio and serial support.
- */
-int clk_enable(struct clk *clk)
-{
- return 0;
-}
-
-void clk_disable(struct clk *clk)
-{
-}
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- return AT91X40_MASTER_CLOCK;
-}
-
-static void at91x40_idle(void)
-{
- /*
- * Disable the processor clock. The processor will be automatically
- * re-enabled by an interrupt or by a reset.
- */
- __raw_writel(AT91_PS_CR_CPU, AT91_IO_P2V(AT91_PS_CR));
- cpu_do_idle();
-}
-
-void __init at91x40_initialize(unsigned long main_clock)
-{
- arm_pm_idle = at91x40_idle;
-}
-
-/*
- * The default interrupt priority levels (0 = lowest, 7 = highest).
- */
-static unsigned int at91x40_default_irq_priority[NR_AIC_IRQS] __initdata = {
- 7, /* Advanced Interrupt Controller (FIQ) */
- 0, /* System Peripherals */
- 0, /* USART 0 */
- 0, /* USART 1 */
- 2, /* Timer Counter 0 */
- 2, /* Timer Counter 1 */
- 2, /* Timer Counter 2 */
- 0, /* Watchdog timer */
- 0, /* Parallel IO Controller A */
- 0, /* Reserved */
- 0, /* Reserved */
- 0, /* Reserved */
- 0, /* Reserved */
- 0, /* Reserved */
- 0, /* Reserved */
- 0, /* Reserved */
- 0, /* External IRQ0 */
- 0, /* External IRQ1 */
- 0, /* External IRQ2 */
-};
-
-void __init at91x40_init_interrupts(unsigned int priority[NR_AIC_IRQS])
-{
- u32 extern_irq = (1 << AT91X40_ID_IRQ0) | (1 << AT91X40_ID_IRQ1)
- | (1 << AT91X40_ID_IRQ2);
- if (!priority)
- priority = at91x40_default_irq_priority;
-
- at91_aic_init(priority, extern_irq);
-}
diff --git a/arch/arm/mach-at91/at91x40_time.c b/arch/arm/mach-at91/at91x40_time.c
deleted file mode 100644
index 07d0bf2..0000000
--- a/arch/arm/mach-at91/at91x40_time.c
+++ /dev/null
@@ -1,85 +0,0 @@
-/*
- * arch/arm/mach-at91/at91x40_time.c
- *
- * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/time.h>
-#include <linux/io.h>
-#include <mach/hardware.h>
-#include <mach/at91x40.h>
-#include <asm/mach/time.h>
-
-#include "at91_tc.h"
-
-#define at91_tc_read(field) \
- __raw_readl(AT91_IO_P2V(AT91_TC) + field)
-
-#define at91_tc_write(field, value) \
- __raw_writel(value, AT91_IO_P2V(AT91_TC) + field)
-
-/*
- * 3 counter/timer units present.
- */
-#define AT91_TC_CLK0BASE 0
-#define AT91_TC_CLK1BASE 0x40
-#define AT91_TC_CLK2BASE 0x80
-
-static u32 at91x40_gettimeoffset(void)
-{
- return (at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_CV) * 1000000 /
- (AT91X40_MASTER_CLOCK / 128)) * 1000;
-}
-
-static irqreturn_t at91x40_timer_interrupt(int irq, void *dev_id)
-{
- at91_tc_read(AT91_TC_CLK1BASE + AT91_TC_SR);
- timer_tick();
- return IRQ_HANDLED;
-}
-
-static struct irqaction at91x40_timer_irq = {
- .name = "at91_tick",
- .flags = IRQF_TIMER,
- .handler = at91x40_timer_interrupt
-};
-
-void __init at91x40_timer_init(void)
-{
- unsigned int v;
-
- arch_gettimeoffset = at91x40_gettimeoffset;
-
- at91_tc_write(AT91_TC_BCR, 0);
- v = at91_tc_read(AT91_TC_BMR);
- v = (v & ~AT91_TC_TC1XC1S) | AT91_TC_TC1XC1S_NONE;
- at91_tc_write(AT91_TC_BMR, v);
-
- at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, AT91_TC_CLKDIS);
- at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CMR, (AT91_TC_TIMER_CLOCK4 | AT91_TC_CPCTRG));
- at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_IDR, 0xffffffff);
- at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_RC, (AT91X40_MASTER_CLOCK / 128) / HZ - 1);
- at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_IER, (1<<4));
-
- setup_irq(AT91X40_ID_TC1, &at91x40_timer_irq);
-
- at91_tc_write(AT91_TC_CLK1BASE + AT91_TC_CCR, (AT91_TC_SWTRG | AT91_TC_CLKEN));
-}
diff --git a/arch/arm/mach-at91/board-1arm.c b/arch/arm/mach-at91/board-1arm.c
deleted file mode 100644
index 3f6dbcc..0000000
--- a/arch/arm/mach-at91/board-1arm.c
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-1arm.c
- *
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/cpu.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-static void __init onearm_init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata onearm_eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata onearm_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata onearm_udc_data = {
- .vbus_pin = AT91_PIN_PC2,
- .pullup_pin = AT91_PIN_PC3,
-};
-
-static void __init onearm_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART1 on ttyS2 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&onearm_eth_data);
- /* USB Host */
- at91_add_device_usbh(&onearm_usbh_data);
- /* USB Device */
- at91_add_device_udc(&onearm_udc_data);
-}
-
-MACHINE_START(ONEARM, "Ajeco 1ARM single board computer")
- /* Maintainer: Lennert Buytenhek <buytenh@wantstofly.org> */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = onearm_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = onearm_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-afeb-9260v1.c b/arch/arm/mach-at91/board-afeb-9260v1.c
deleted file mode 100644
index e76e35c..0000000
--- a/arch/arm/mach-at91/board-afeb-9260v1.c
+++ /dev/null
@@ -1,223 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-afeb-9260v1.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- * Copyright (C) 2008 Sergey Lapin
- *
- * A custom board designed as open hardware; PCBs and various information
- * is available at http://groups.google.com/group/arm9fpga-evolution-board/
- * Subversion repository: svn://194.85.238.22/home/users/george/svn/arm9eb
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/clk.h>
-#include <linux/dma-mapping.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init afeb9260_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata afeb9260_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata afeb9260_udc_data = {
- .vbus_pin = AT91_PIN_PC5,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info afeb9260_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata afeb9260_macb_data = {
- .phy_irq_pin = AT91_PIN_PA9,
- .is_rmii = 0,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata afeb9260_nand_partition[] = {
- {
- .name = "bootloader",
- .offset = 0,
- .size = (640 * SZ_1K),
- },
- {
- .name = "kernel",
- .offset = MTDPART_OFS_NXTBLK,
- .size = SZ_2M,
- },
- {
- .name = "rootfs",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata afeb9260_nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
- .bus_width_16 = 0,
- .ecc_mode = NAND_ECC_SOFT,
- .parts = afeb9260_nand_partition,
- .num_parts = ARRAY_SIZE(afeb9260_nand_partition),
- .det_pin = -EINVAL,
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata afeb9260_mci0_data = {
- .slot[1] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PC9,
- .wp_pin = AT91_PIN_PC4,
- },
-};
-
-
-
-static struct i2c_board_info __initdata afeb9260_i2c_devices[] = {
- {
- I2C_BOARD_INFO("tlv320aic23", 0x1a),
- }, {
- I2C_BOARD_INFO("fm3130", 0x68),
- }, {
- I2C_BOARD_INFO("24c64", 0x50),
- },
-};
-
-/*
- * IDE (CF True IDE mode)
- */
-static struct at91_cf_data afeb9260_cf_data = {
- .chipselect = 4,
- .irq_pin = AT91_PIN_PA6,
- .det_pin = -EINVAL,
- .vcc_pin = -EINVAL,
- .rst_pin = AT91_PIN_PA7,
- .flags = AT91_CF_TRUE_IDE,
-};
-
-static void __init afeb9260_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&afeb9260_usbh_data);
- /* USB Device */
- at91_add_device_udc(&afeb9260_udc_data);
- /* SPI */
- at91_add_device_spi(afeb9260_spi_devices,
- ARRAY_SIZE(afeb9260_spi_devices));
- /* NAND */
- at91_add_device_nand(&afeb9260_nand_data);
- /* Ethernet */
- at91_add_device_eth(&afeb9260_macb_data);
-
- /* Standard function's pin assignments are not
- * appropriate for us and generic code provide
- * no API to configure these pins any other way */
- at91_set_B_periph(AT91_PIN_PA10, 0); /* ETX2 */
- at91_set_B_periph(AT91_PIN_PA11, 0); /* ETX3 */
- /* MMC */
- at91_add_device_mci(0, &afeb9260_mci0_data);
- /* I2C */
- at91_add_device_i2c(afeb9260_i2c_devices,
- ARRAY_SIZE(afeb9260_i2c_devices));
- /* Audio */
- at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
- /* IDE */
- at91_add_device_cf(&afeb9260_cf_data);
-}
-
-MACHINE_START(AFEB9260, "Custom afeb9260 board")
- /* Maintainer: Sergey Lapin <slapin@ossfans.org> */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = afeb9260_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = afeb9260_board_init,
-MACHINE_END
-
diff --git a/arch/arm/mach-at91/board-cam60.c b/arch/arm/mach-at91/board-cam60.c
deleted file mode 100644
index ae827dd..0000000
--- a/arch/arm/mach-at91/board-cam60.c
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * KwikByte CAM60 (KB9260)
- *
- * based on board-sam9260ek.c
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/at91sam9_smc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init cam60_init_early(void)
-{
- /* Initialize processor: 10 MHz crystal */
- at91_initialize(10000000);
-}
-
-/*
- * USB Host
- */
-static struct at91_usbh_data __initdata cam60_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-
-/*
- * SPI devices.
- */
-#if defined(CONFIG_MTD_DATAFLASH)
-static struct mtd_partition cam60_spi_partitions[] = {
- {
- .name = "BOOT1",
- .offset = 0,
- .size = 4 * 1056,
- },
- {
- .name = "BOOT2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 256 * 1056,
- },
- {
- .name = "kernel",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 2222 * 1056,
- },
- {
- .name = "file system",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct flash_platform_data cam60_spi_flash_platform_data = {
- .name = "spi_flash",
- .parts = cam60_spi_partitions,
- .nr_parts = ARRAY_SIZE(cam60_spi_partitions)
-};
-#endif
-
-static struct spi_board_info cam60_spi_devices[] __initdata = {
-#if defined(CONFIG_MTD_DATAFLASH)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- .platform_data = &cam60_spi_flash_platform_data
- },
-#endif
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data cam60_macb_data __initdata = {
- .phy_irq_pin = AT91_PIN_PB5,
- .is_rmii = 0,
-};
-
-
-/*
- * NAND Flash
- */
-static struct mtd_partition __initdata cam60_nand_partition[] = {
- {
- .name = "nand_fs",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata cam60_nand_data = {
- .ale = 21,
- .cle = 22,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PA9,
- .enable_pin = AT91_PIN_PA7,
- .ecc_mode = NAND_ECC_SOFT,
- .parts = cam60_nand_partition,
- .num_parts = ARRAY_SIZE(cam60_nand_partition),
-};
-
-static struct sam9_smc_config __initdata cam60_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 2,
-};
-
-static void __init cam60_add_device_nand(void)
-{
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &cam60_nand_smc_config);
-
- at91_add_device_nand(&cam60_nand_data);
-}
-
-
-static void __init cam60_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
- /* SPI */
- at91_add_device_spi(cam60_spi_devices, ARRAY_SIZE(cam60_spi_devices));
- /* Ethernet */
- at91_add_device_eth(&cam60_macb_data);
- /* USB Host */
- /* enable USB power supply circuit */
- at91_set_gpio_output(AT91_PIN_PB18, 1);
- at91_add_device_usbh(&cam60_usbh_data);
- /* NAND */
- cam60_add_device_nand();
-}
-
-MACHINE_START(CAM60, "KwikByte CAM60")
- /* Maintainer: KwikByte */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = cam60_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = cam60_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-carmeva.c b/arch/arm/mach-at91/board-carmeva.c
deleted file mode 100644
index 47313d3..0000000
--- a/arch/arm/mach-at91/board-carmeva.c
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-carmeva.c
- *
- * Copyright (c) 2005 Peer Georgi
- * Conitec Datasystems
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init carmeva_init_early(void)
-{
- /* Initialize processor: 20.000 MHz crystal */
- at91_initialize(20000000);
-}
-
-static struct macb_platform_data __initdata carmeva_eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata carmeva_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata carmeva_udc_data = {
- .vbus_pin = AT91_PIN_PD12,
- .pullup_pin = AT91_PIN_PD9,
-};
-
-/* FIXME: user dependent */
-// static struct at91_cf_data __initdata carmeva_cf_data = {
-// .det_pin = AT91_PIN_PB0,
-// .rst_pin = AT91_PIN_PC5,
- // .irq_pin = -EINVAL,
- // .vcc_pin = -EINVAL,
-// };
-
-static struct mci_platform_data __initdata carmeva_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PB10,
- .wp_pin = AT91_PIN_PC14,
- },
-};
-
-static struct spi_board_info carmeva_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 10 * 1000 * 1000,
- },
- { /* User accessible spi - cs1 (250KHz) */
- .modalias = "spi-cs1",
- .chip_select = 1,
- .max_speed_hz = 250 * 1000,
- },
- { /* User accessible spi - cs2 (1MHz) */
- .modalias = "spi-cs2",
- .chip_select = 2,
- .max_speed_hz = 1 * 1000 * 1000,
- },
- { /* User accessible spi - cs3 (10MHz) */
- .modalias = "spi-cs3",
- .chip_select = 3,
- .max_speed_hz = 10 * 1000 * 1000,
- },
-};
-
-static struct gpio_led carmeva_leds[] = {
- { /* "user led 1", LED9 */
- .name = "led9",
- .gpio = AT91_PIN_PA21,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* "user led 2", LED10 */
- .name = "led10",
- .gpio = AT91_PIN_PA25,
- .active_low = 1,
- },
- { /* "user led 3", LED11 */
- .name = "led11",
- .gpio = AT91_PIN_PA26,
- .active_low = 1,
- },
- { /* "user led 4", LED12 */
- .name = "led12",
- .gpio = AT91_PIN_PA18,
- .active_low = 1,
- }
-};
-
-static void __init carmeva_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&carmeva_eth_data);
- /* USB Host */
- at91_add_device_usbh(&carmeva_usbh_data);
- /* USB Device */
- at91_add_device_udc(&carmeva_udc_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* SPI */
- at91_add_device_spi(carmeva_spi_devices, ARRAY_SIZE(carmeva_spi_devices));
- /* Compact Flash */
-// at91_add_device_cf(&carmeva_cf_data);
- /* MMC */
- at91_add_device_mci(0, &carmeva_mci0_data);
- /* LEDs */
- at91_gpio_leds(carmeva_leds, ARRAY_SIZE(carmeva_leds));
-}
-
-MACHINE_START(CARMEVA, "Carmeva")
- /* Maintainer: Conitec Datasystems */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = carmeva_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = carmeva_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-cpu9krea.c b/arch/arm/mach-at91/board-cpu9krea.c
deleted file mode 100644
index 731c831..0000000
--- a/arch/arm/mach-at91/board-cpu9krea.c
+++ /dev/null
@@ -1,386 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-cpu9krea.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- * Copyright (C) 2009 Eric Benard - eric@eukrea.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/at91sam9260_matrix.h>
-#include <mach/at91_matrix.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-static void __init cpu9krea_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata cpu9krea_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata cpu9krea_udc_data = {
- .vbus_pin = AT91_PIN_PC8,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata cpu9krea_macb_data = {
- .phy_irq_pin = -EINVAL,
- .is_rmii = 1,
-};
-
-/*
- * NAND flash
- */
-static struct atmel_nand_data __initdata cpu9krea_nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
- .bus_width_16 = 0,
- .det_pin = -EINVAL,
- .ecc_mode = NAND_ECC_SOFT,
-};
-
-#ifdef CONFIG_MACH_CPU9260
-static struct sam9_smc_config __initdata cpu9krea_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 2,
-};
-#else
-static struct sam9_smc_config __initdata cpu9krea_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 2,
- .ncs_write_setup = 0,
- .nwe_setup = 2,
-
- .ncs_read_pulse = 4,
- .nrd_pulse = 4,
- .ncs_write_pulse = 4,
- .nwe_pulse = 4,
-
- .read_cycle = 7,
- .write_cycle = 7,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 3,
-};
-#endif
-
-static void __init cpu9krea_add_device_nand(void)
-{
- sam9_smc_configure(0, 3, &cpu9krea_nand_smc_config);
- at91_add_device_nand(&cpu9krea_nand_data);
-}
-
-/*
- * NOR flash
- */
-static struct physmap_flash_data cpuat9260_nor_data = {
- .width = 2,
-};
-
-#define NOR_BASE AT91_CHIPSELECT_0
-#define NOR_SIZE SZ_64M
-
-static struct resource nor_flash_resources[] = {
- {
- .start = NOR_BASE,
- .end = NOR_BASE + NOR_SIZE - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device cpu9krea_nor_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &cpuat9260_nor_data,
- },
- .resource = nor_flash_resources,
- .num_resources = ARRAY_SIZE(nor_flash_resources),
-};
-
-#ifdef CONFIG_MACH_CPU9260
-static struct sam9_smc_config __initdata cpu9krea_nor_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 10,
- .nrd_pulse = 10,
- .ncs_write_pulse = 6,
- .nwe_pulse = 6,
-
- .read_cycle = 12,
- .write_cycle = 8,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
- | AT91_SMC_DBW_16,
- .tdf_cycles = 2,
-};
-#else
-static struct sam9_smc_config __initdata cpu9krea_nor_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 13,
- .nrd_pulse = 13,
- .ncs_write_pulse = 8,
- .nwe_pulse = 8,
-
- .read_cycle = 15,
- .write_cycle = 10,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE
- | AT91_SMC_DBW_16,
- .tdf_cycles = 2,
-};
-#endif
-
-static __init void cpu9krea_add_device_nor(void)
-{
- unsigned long csa;
-
- csa = at91_matrix_read(AT91_MATRIX_EBICSA);
- at91_matrix_write(AT91_MATRIX_EBICSA, csa | AT91_MATRIX_VDDIOMSEL_3_3V);
-
- /* configure chip-select 0 (NOR) */
- sam9_smc_configure(0, 0, &cpu9krea_nor_smc_config);
-
- platform_device_register(&cpu9krea_nor_flash);
-}
-
-/*
- * LEDs
- */
-static struct gpio_led cpu9krea_leds[] = {
- { /* LED1 */
- .name = "LED1",
- .gpio = AT91_PIN_PC11,
- .active_low = 1,
- .default_trigger = "timer",
- },
- { /* LED2 */
- .name = "LED2",
- .gpio = AT91_PIN_PC12,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* LED3 */
- .name = "LED3",
- .gpio = AT91_PIN_PC7,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* LED4 */
- .name = "LED4",
- .gpio = AT91_PIN_PC9,
- .active_low = 1,
- .default_trigger = "none",
- }
-};
-
-static struct i2c_board_info __initdata cpu9krea_i2c_devices[] = {
- {
- I2C_BOARD_INFO("ds1339", 0x68),
- },
-};
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button cpu9krea_buttons[] = {
- {
- .gpio = AT91_PIN_PC3,
- .code = BTN_0,
- .desc = "BP1",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PB20,
- .code = BTN_1,
- .desc = "BP2",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data cpu9krea_button_data = {
- .buttons = cpu9krea_buttons,
- .nbuttons = ARRAY_SIZE(cpu9krea_buttons),
-};
-
-static struct platform_device cpu9krea_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &cpu9krea_button_data,
- }
-};
-
-static void __init cpu9krea_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PC3, 1); /* BP1 */
- at91_set_deglitch(AT91_PIN_PC3, 1);
- at91_set_gpio_input(AT91_PIN_PB20, 1); /* BP2 */
- at91_set_deglitch(AT91_PIN_PB20, 1);
-
- platform_device_register(&cpu9krea_button_device);
-}
-#else
-static void __init cpu9krea_add_device_buttons(void)
-{
-}
-#endif
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata cpu9krea_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PA29,
- .wp_pin = -EINVAL,
- },
-};
-
-static void __init cpu9krea_board_init(void)
-{
- at91_register_devices();
-
- /* NOR */
- cpu9krea_add_device_nor();
- /* Serial */
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS |
- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
- ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* USART3 on ttyS4. (Rx, Tx) */
- at91_register_uart(AT91SAM9260_ID_US3, 4, 0);
-
- /* USART4 on ttyS5. (Rx, Tx) */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
- /* USART5 on ttyS6. (Rx, Tx) */
- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&cpu9krea_usbh_data);
- /* USB Device */
- at91_add_device_udc(&cpu9krea_udc_data);
- /* NAND */
- cpu9krea_add_device_nand();
- /* Ethernet */
- at91_add_device_eth(&cpu9krea_macb_data);
- /* MMC */
- at91_add_device_mci(0, &cpu9krea_mci0_data);
- /* I2C */
- at91_add_device_i2c(cpu9krea_i2c_devices,
- ARRAY_SIZE(cpu9krea_i2c_devices));
- /* LEDs */
- at91_gpio_leds(cpu9krea_leds, ARRAY_SIZE(cpu9krea_leds));
- /* Push Buttons */
- cpu9krea_add_device_buttons();
-}
-
-#ifdef CONFIG_MACH_CPU9260
-MACHINE_START(CPUAT9260, "Eukrea CPU9260")
-#else
-MACHINE_START(CPUAT9G20, "Eukrea CPU9G20")
-#endif
- /* Maintainer: Eric Benard - EUKREA Electromatique */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = cpu9krea_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = cpu9krea_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-cpuat91.c b/arch/arm/mach-at91/board-cpuat91.c
deleted file mode 100644
index c094350..0000000
--- a/arch/arm/mach-at91/board-cpuat91.c
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-cpuat91.c
- *
- * Copyright (C) 2009 Eric Benard - eric@eukrea.com
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/mtd/plat-ram.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-#include <mach/cpu.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static struct gpio_led cpuat91_leds[] = {
- {
- .name = "led1",
- .default_trigger = "heartbeat",
- .active_low = 1,
- .gpio = AT91_PIN_PC0,
- },
-};
-
-static void __init cpuat91_init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata cpuat91_eth_data = {
- .phy_irq_pin = -EINVAL,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata cpuat91_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata cpuat91_udc_data = {
- .vbus_pin = AT91_PIN_PC15,
- .pullup_pin = AT91_PIN_PC14,
-};
-
-static struct mci_platform_data __initdata cpuat91_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PC2,
- .wp_pin = -EINVAL,
- },
-};
-
-static struct physmap_flash_data cpuat91_flash_data = {
- .width = 2,
-};
-
-static struct resource cpuat91_flash_resource = {
- .start = AT91_CHIPSELECT_0,
- .end = AT91_CHIPSELECT_0 + SZ_16M - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device cpuat91_norflash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &cpuat91_flash_data,
- },
- .resource = &cpuat91_flash_resource,
- .num_resources = 1,
-};
-
-#ifdef CONFIG_MTD_PLATRAM
-struct platdata_mtd_ram at91_sram_pdata = {
- .mapname = "SRAM",
- .bankwidth = 2,
-};
-
-static struct resource at91_sram_resource[] = {
- [0] = {
- .start = AT91RM9200_SRAM_BASE,
- .end = AT91RM9200_SRAM_BASE + AT91RM9200_SRAM_SIZE - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device at91_sram = {
- .name = "mtd-ram",
- .id = 0,
- .resource = at91_sram_resource,
- .num_resources = ARRAY_SIZE(at91_sram_resource),
- .dev = {
- .platform_data = &at91_sram_pdata,
- },
-};
-#endif /* MTD_PLATRAM */
-
-static struct platform_device *platform_devices[] __initdata = {
- &cpuat91_norflash,
-#ifdef CONFIG_MTD_PLATRAM
- &at91_sram,
-#endif /* CONFIG_MTD_PLATRAM */
-};
-
-static void __init cpuat91_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 2, ATMEL_UART_CTS |
- ATMEL_UART_RTS | ATMEL_UART_DTR | ATMEL_UART_DSR |
- ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART2 on ttyS3 (Rx, Tx) */
- at91_register_uart(AT91RM9200_ID_US2, 3, 0);
-
- /* USART3 on ttyS4 (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US3, 4, ATMEL_UART_CTS |
- ATMEL_UART_RTS);
- at91_add_device_serial();
- /* LEDs. */
- at91_gpio_leds(cpuat91_leds, ARRAY_SIZE(cpuat91_leds));
- /* Ethernet */
- at91_add_device_eth(&cpuat91_eth_data);
- /* USB Host */
- at91_add_device_usbh(&cpuat91_usbh_data);
- /* USB Device */
- at91_add_device_udc(&cpuat91_udc_data);
- /* MMC */
- at91_add_device_mci(0, &cpuat91_mci0_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* Platform devices */
- platform_add_devices(platform_devices, ARRAY_SIZE(platform_devices));
-}
-
-MACHINE_START(CPUAT91, "Eukrea")
- /* Maintainer: Eric Benard - EUKREA Electromatique */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = cpuat91_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = cpuat91_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-csb337.c b/arch/arm/mach-at91/board-csb337.c
deleted file mode 100644
index 0e35a45..0000000
--- a/arch/arm/mach-at91/board-csb337.c
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-csb337.c
- *
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mtd/physmap.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-static void __init csb337_init_early(void)
-{
- /* Initialize processor: 3.6864 MHz crystal */
- at91_initialize(3686400);
-}
-
-static struct macb_platform_data __initdata csb337_eth_data = {
- .phy_irq_pin = AT91_PIN_PC2,
- .is_rmii = 0,
- /* The CSB337 bootloader stores the MAC the wrong-way around */
- .rev_eth_addr = 1,
-};
-
-static struct at91_usbh_data __initdata csb337_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata csb337_udc_data = {
- .pullup_pin = AT91_PIN_PA24,
- .vbus_pin = -EINVAL,
-};
-
-static struct i2c_board_info __initdata csb337_i2c_devices[] = {
- {
- I2C_BOARD_INFO("ds1307", 0x68),
- },
-};
-
-static struct at91_cf_data __initdata csb337_cf_data = {
- /*
- * connector P4 on the CSB 337 mates to
- * connector P8 on the CSB 300CF
- */
-
- /* CSB337 specific */
- .det_pin = AT91_PIN_PC3,
-
- /* CSB300CF specific */
- .irq_pin = AT91_PIN_PA19,
- .vcc_pin = AT91_PIN_PD0,
- .rst_pin = AT91_PIN_PD2,
-};
-
-static struct mci_platform_data __initdata csb337_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PD5,
- .wp_pin = AT91_PIN_PD6,
- },
-};
-
-static struct spi_board_info csb337_spi_devices[] = {
- { /* CAN controller */
- .modalias = "sak82c900",
- .chip_select = 0,
- .max_speed_hz = 6 * 1000 * 1000,
- },
-};
-
-#define CSB_FLASH_BASE AT91_CHIPSELECT_0
-#define CSB_FLASH_SIZE SZ_8M
-
-static struct mtd_partition csb_flash_partitions[] = {
- {
- .name = "uMON flash",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- .mask_flags = MTD_WRITEABLE, /* read only */
- }
-};
-
-static struct physmap_flash_data csb_flash_data = {
- .width = 2,
- .parts = csb_flash_partitions,
- .nr_parts = ARRAY_SIZE(csb_flash_partitions),
-};
-
-static struct resource csb_flash_resources[] = {
- {
- .start = CSB_FLASH_BASE,
- .end = CSB_FLASH_BASE + CSB_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device csb_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &csb_flash_data,
- },
- .resource = csb_flash_resources,
- .num_resources = ARRAY_SIZE(csb_flash_resources),
-};
-
-/*
- * GPIO Buttons (on CSB300)
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button csb300_buttons[] = {
- {
- .gpio = AT91_PIN_PB29,
- .code = BTN_0,
- .desc = "sw0",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PB28,
- .code = BTN_1,
- .desc = "sw1",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PA21,
- .code = BTN_2,
- .desc = "sw2",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data csb300_button_data = {
- .buttons = csb300_buttons,
- .nbuttons = ARRAY_SIZE(csb300_buttons),
-};
-
-static struct platform_device csb300_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &csb300_button_data,
- }
-};
-
-static void __init csb300_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PB29, 1); /* sw0 */
- at91_set_deglitch(AT91_PIN_PB29, 1);
- at91_set_gpio_input(AT91_PIN_PB28, 1); /* sw1 */
- at91_set_deglitch(AT91_PIN_PB28, 1);
- at91_set_gpio_input(AT91_PIN_PA21, 1); /* sw2 */
- at91_set_deglitch(AT91_PIN_PA21, 1);
-
- platform_device_register(&csb300_button_device);
-}
-#else
-static void __init csb300_add_device_buttons(void) {}
-#endif
-
-static struct gpio_led csb_leds[] = {
- { /* "led0", yellow */
- .name = "led0",
- .gpio = AT91_PIN_PB2,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* "led1", green */
- .name = "led1",
- .gpio = AT91_PIN_PB1,
- .active_low = 1,
- .default_trigger = "mmc0",
- },
- { /* "led2", yellow */
- .name = "led2",
- .gpio = AT91_PIN_PB0,
- .active_low = 1,
- .default_trigger = "ide-disk",
- }
-};
-
-
-static void __init csb337_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0 */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&csb337_eth_data);
- /* USB Host */
- at91_add_device_usbh(&csb337_usbh_data);
- /* USB Device */
- at91_add_device_udc(&csb337_udc_data);
- /* I2C */
- at91_add_device_i2c(csb337_i2c_devices, ARRAY_SIZE(csb337_i2c_devices));
- /* Compact Flash */
- at91_set_gpio_input(AT91_PIN_PB22, 1); /* IOIS16 */
- at91_add_device_cf(&csb337_cf_data);
- /* SPI */
- at91_add_device_spi(csb337_spi_devices, ARRAY_SIZE(csb337_spi_devices));
- /* MMC */
- at91_add_device_mci(0, &csb337_mci0_data);
- /* NOR flash */
- platform_device_register(&csb_flash);
- /* LEDs */
- at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
- /* Switches on CSB300 */
- csb300_add_device_buttons();
-}
-
-MACHINE_START(CSB337, "Cogent CSB337")
- /* Maintainer: Bill Gatliff */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = csb337_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = csb337_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-csb637.c b/arch/arm/mach-at91/board-csb637.c
deleted file mode 100644
index 18d027f..0000000
--- a/arch/arm/mach-at91/board-csb637.c
+++ /dev/null
@@ -1,142 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-csb637.c
- *
- * Copyright (C) 2005 SAN People
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init csb637_init_early(void)
-{
- /* Initialize processor: 3.6864 MHz crystal */
- at91_initialize(3686400);
-}
-
-static struct macb_platform_data __initdata csb637_eth_data = {
- .phy_irq_pin = AT91_PIN_PC0,
- .is_rmii = 0,
-};
-
-static struct at91_usbh_data __initdata csb637_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata csb637_udc_data = {
- .vbus_pin = AT91_PIN_PB28,
- .pullup_pin = AT91_PIN_PB1,
-};
-
-#define CSB_FLASH_BASE AT91_CHIPSELECT_0
-#define CSB_FLASH_SIZE SZ_16M
-
-static struct mtd_partition csb_flash_partitions[] = {
- {
- .name = "uMON flash",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- .mask_flags = MTD_WRITEABLE, /* read only */
- }
-};
-
-static struct physmap_flash_data csb_flash_data = {
- .width = 2,
- .parts = csb_flash_partitions,
- .nr_parts = ARRAY_SIZE(csb_flash_partitions),
-};
-
-static struct resource csb_flash_resources[] = {
- {
- .start = CSB_FLASH_BASE,
- .end = CSB_FLASH_BASE + CSB_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device csb_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &csb_flash_data,
- },
- .resource = csb_flash_resources,
- .num_resources = ARRAY_SIZE(csb_flash_resources),
-};
-
-static struct gpio_led csb_leds[] = {
- { /* "d1", red */
- .name = "d1",
- .gpio = AT91_PIN_PB2,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
-};
-
-static void __init csb637_board_init(void)
-{
- /* LED(s) */
- at91_gpio_leds(csb_leds, ARRAY_SIZE(csb_leds));
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&csb637_eth_data);
- /* USB Host */
- at91_add_device_usbh(&csb637_usbh_data);
- /* USB Device */
- at91_add_device_udc(&csb637_udc_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* SPI */
- at91_add_device_spi(NULL, 0);
- /* NOR flash */
- platform_device_register(&csb_flash);
-}
-
-MACHINE_START(CSB637, "Cogent CSB637")
- /* Maintainer: Bill Gatliff */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = csb637_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = csb637_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-dt-rm9200.c b/arch/arm/mach-at91/board-dt-rm9200.c
index 226563f..76dfe8f 100644
--- a/arch/arm/mach-at91/board-dt-rm9200.c
+++ b/arch/arm/mach-at91/board-dt-rm9200.c
@@ -22,14 +22,11 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include "at91_aic.h"
#include "generic.h"
static void __init at91rm9200_dt_timer_init(void)
{
-#if defined(CONFIG_COMMON_CLK)
of_clk_init(NULL);
-#endif
at91rm9200_timer_init();
}
diff --git a/arch/arm/mach-at91/board-dt-sam9.c b/arch/arm/mach-at91/board-dt-sam9.c
index d3048cc..f99246a 100644
--- a/arch/arm/mach-at91/board-dt-sam9.c
+++ b/arch/arm/mach-at91/board-dt-sam9.c
@@ -21,8 +21,6 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include "at91_aic.h"
-#include "board.h"
#include "generic.h"
static const char *at91_dt_board_compat[] __initdata = {
diff --git a/arch/arm/mach-at91/board-dt-sama5.c b/arch/arm/mach-at91/board-dt-sama5.c
index 129e291..8fb9ef5 100644
--- a/arch/arm/mach-at91/board-dt-sama5.c
+++ b/arch/arm/mach-at91/board-dt-sama5.c
@@ -24,7 +24,6 @@
#include <asm/mach/map.h>
#include <asm/mach/irq.h>
-#include "at91_aic.h"
#include "generic.h"
static void __init sama5_dt_device_init(void)
diff --git a/arch/arm/mach-at91/board-eb01.c b/arch/arm/mach-at91/board-eb01.c
deleted file mode 100644
index becf0a6..0000000
--- a/arch/arm/mach-at91/board-eb01.c
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- * arch/arm/mach-at91/board-eb01.c
- *
- * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/irq.h>
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-
-static void __init at91eb01_init_irq(void)
-{
- at91x40_init_interrupts(NULL);
-}
-
-static void __init at91eb01_init_early(void)
-{
- at91x40_initialize(40000000);
-}
-
-MACHINE_START(AT91EB01, "Atmel AT91 EB01")
- /* Maintainer: Greg Ungerer <gerg@snapgear.com> */
- .init_time = at91x40_timer_init,
- .handle_irq = at91_aic_handle_irq,
- .init_early = at91eb01_init_early,
- .init_irq = at91eb01_init_irq,
-MACHINE_END
-
diff --git a/arch/arm/mach-at91/board-eb9200.c b/arch/arm/mach-at91/board-eb9200.c
deleted file mode 100644
index aa457a8..0000000
--- a/arch/arm/mach-at91/board-eb9200.c
+++ /dev/null
@@ -1,126 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-eb9200.c
- *
- * Copyright (C) 2005 SAN People, adapted for ATEB9200 from Embest
- * by Andrew Patrikalakis
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/device.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init eb9200_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata eb9200_eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata eb9200_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata eb9200_udc_data = {
- .vbus_pin = AT91_PIN_PD4,
- .pullup_pin = AT91_PIN_PD5,
-};
-
-static struct at91_cf_data __initdata eb9200_cf_data = {
- .irq_pin = -EINVAL,
- .det_pin = AT91_PIN_PB0,
- .vcc_pin = -EINVAL,
- .rst_pin = AT91_PIN_PC5,
-};
-
-static struct mci_platform_data __initdata eb9200_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = -EINVAL,
- .wp_pin = -EINVAL,
- },
-};
-
-static struct i2c_board_info __initdata eb9200_i2c_devices[] = {
- {
- I2C_BOARD_INFO("24c512", 0x50),
- },
-};
-
-
-static void __init eb9200_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART2 on ttyS2. (Rx, Tx) - IRDA */
- at91_register_uart(AT91RM9200_ID_US2, 2, 0);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&eb9200_eth_data);
- /* USB Host */
- at91_add_device_usbh(&eb9200_usbh_data);
- /* USB Device */
- at91_add_device_udc(&eb9200_udc_data);
- /* I2C */
- at91_add_device_i2c(eb9200_i2c_devices, ARRAY_SIZE(eb9200_i2c_devices));
- /* Compact Flash */
- at91_add_device_cf(&eb9200_cf_data);
- /* SPI */
- at91_add_device_spi(NULL, 0);
- /* MMC */
- /* only supports 1 or 4 bit interface, not wired through to SPI */
- at91_add_device_mci(0, &eb9200_mci0_data);
-}
-
-MACHINE_START(ATEB9200, "Embest ATEB9200")
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = eb9200_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = eb9200_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-ecbat91.c b/arch/arm/mach-at91/board-ecbat91.c
deleted file mode 100644
index ede1373c..0000000
--- a/arch/arm/mach-at91/board-ecbat91.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * linux/arch/arm/mach-at91rm9200/board-ecbat91.c
- * Copyright (C) 2007 emQbit.com.
- *
- * We started from board-dk.c, which is Copyright (C) 2005 SAN People.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/flash.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/cpu.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ecb_at91init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata ecb_at91eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 0,
-};
-
-static struct at91_usbh_data __initdata ecb_at91usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct mci_platform_data __initdata ecbat91_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = -EINVAL,
- .wp_pin = -EINVAL,
- },
-};
-
-
-#if defined(CONFIG_MTD_DATAFLASH)
-static struct mtd_partition __initdata my_flash0_partitions[] =
-{
- { /* 0x8400 */
- .name = "Darrell-loader",
- .offset = 0,
- .size = 12 * 1056,
- },
- {
- .name = "U-boot",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 110 * 1056,
- },
- { /* 1336 (167 blocks) pages * 1056 bytes = 0x158700 bytes */
- .name = "UBoot-env",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 8 * 1056,
- },
- { /* 1336 (167 blocks) pages * 1056 bytes = 0x158700 bytes */
- .name = "Kernel",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 1534 * 1056,
- },
- { /* 190200 - jffs2 root filesystem */
- .name = "Filesystem",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL, /* 26 sectors */
- }
-};
-
-static struct flash_platform_data __initdata my_flash0_platform = {
- .name = "Removable flash card",
- .parts = my_flash0_partitions,
- .nr_parts = ARRAY_SIZE(my_flash0_partitions)
-};
-
-#endif
-
-static struct spi_board_info __initdata ecb_at91spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 10 * 1000 * 1000,
- .bus_num = 0,
-#if defined(CONFIG_MTD_DATAFLASH)
- .platform_data = &my_flash0_platform,
-#endif
- },
- { /* User accessible spi - cs1 (250KHz) */
- .modalias = "spi-cs1",
- .chip_select = 1,
- .max_speed_hz = 250 * 1000,
- },
- { /* User accessible spi - cs2 (1MHz) */
- .modalias = "spi-cs2",
- .chip_select = 2,
- .max_speed_hz = 1 * 1000 * 1000,
- },
- { /* User accessible spi - cs3 (10MHz) */
- .modalias = "spi-cs3",
- .chip_select = 3,
- .max_speed_hz = 10 * 1000 * 1000,
- },
-};
-
-/*
- * LEDs
- */
-static struct gpio_led ecb_leds[] = {
- { /* D1 */
- .name = "led1",
- .gpio = AT91_PIN_PC7,
- .active_low = 1,
- .default_trigger = "heartbeat",
- }
-};
-
-static void __init ecb_at91board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx & Tx only) */
- at91_register_uart(AT91RM9200_ID_US0, 1, 0);
- at91_add_device_serial();
-
- /* Ethernet */
- at91_add_device_eth(&ecb_at91eth_data);
-
- /* USB Host */
- at91_add_device_usbh(&ecb_at91usbh_data);
-
- /* I2C */
- at91_add_device_i2c(NULL, 0);
-
- /* MMC */
- at91_add_device_mci(0, &ecbat91_mci0_data);
-
- /* SPI */
- at91_add_device_spi(ecb_at91spi_devices, ARRAY_SIZE(ecb_at91spi_devices));
-
- /* LEDs */
- at91_gpio_leds(ecb_leds, ARRAY_SIZE(ecb_leds));
-}
-
-MACHINE_START(ECBAT91, "emQbit's ECB_AT91")
- /* Maintainer: emQbit.com */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ecb_at91init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ecb_at91board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-eco920.c b/arch/arm/mach-at91/board-eco920.c
deleted file mode 100644
index 4e75321..0000000
--- a/arch/arm/mach-at91/board-eco920.c
+++ /dev/null
@@ -1,160 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/mtd/physmap.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-#include <mach/cpu.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init eco920_init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata eco920_eth_data = {
- .phy_irq_pin = AT91_PIN_PC2,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata eco920_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata eco920_udc_data = {
- .vbus_pin = AT91_PIN_PB12,
- .pullup_pin = AT91_PIN_PB13,
-};
-
-static struct mci_platform_data __initdata eco920_mci0_data = {
- .slot[0] = {
- .bus_width = 1,
- .detect_pin = -EINVAL,
- .wp_pin = -EINVAL,
- },
-};
-
-static struct physmap_flash_data eco920_flash_data = {
- .width = 2,
-};
-
-static struct resource eco920_flash_resource = {
- .start = 0x11000000,
- .end = 0x11ffffff,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device eco920_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &eco920_flash_data,
- },
- .resource = &eco920_flash_resource,
- .num_resources = 1,
-};
-
-static struct spi_board_info eco920_spi_devices[] = {
- { /* CAN controller */
- .modalias = "tlv5638",
- .chip_select = 3,
- .max_speed_hz = 20 * 1000 * 1000,
- .mode = SPI_CPHA,
- },
-};
-
-/*
- * LEDs
- */
-static struct gpio_led eco920_leds[] = {
- { /* D1 */
- .name = "led1",
- .gpio = AT91_PIN_PB0,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* D2 */
- .name = "led2",
- .gpio = AT91_PIN_PB1,
- .active_low = 1,
- .default_trigger = "timer",
- }
-};
-
-static void __init eco920_board_init(void)
-{
- /* DBGU on ttyS0. (Rx & Tx only */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
- at91_add_device_eth(&eco920_eth_data);
- at91_add_device_usbh(&eco920_usbh_data);
- at91_add_device_udc(&eco920_udc_data);
-
- at91_add_device_mci(0, &eco920_mci0_data);
- platform_device_register(&eco920_flash);
-
- at91_ramc_write(0, AT91_SMC_CSR(7), AT91_SMC_RWHOLD_(1)
- | AT91_SMC_RWSETUP_(1)
- | AT91_SMC_DBW_8
- | AT91_SMC_WSEN
- | AT91_SMC_NWS_(15));
-
- at91_set_A_periph(AT91_PIN_PC6, 1);
-
- at91_set_gpio_input(AT91_PIN_PA23, 0);
- at91_set_deglitch(AT91_PIN_PA23, 1);
-
-/* Initialization of the Static Memory Controller for Chip Select 3 */
- at91_ramc_write(0, AT91_SMC_CSR(3),
- AT91_SMC_DBW_16 | /* 16 bit */
- AT91_SMC_WSEN |
- AT91_SMC_NWS_(5) | /* wait states */
- AT91_SMC_TDF_(1) /* float time */
- );
-
- at91_add_device_spi(eco920_spi_devices, ARRAY_SIZE(eco920_spi_devices));
- /* LEDs */
- at91_gpio_leds(eco920_leds, ARRAY_SIZE(eco920_leds));
-}
-
-MACHINE_START(ECO920, "eco920")
- /* Maintainer: Sascha Hauer */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = eco920_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = eco920_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-flexibity.c b/arch/arm/mach-at91/board-flexibity.c
deleted file mode 100644
index a6aa4a2..0000000
--- a/arch/arm/mach-at91/board-flexibity.c
+++ /dev/null
@@ -1,171 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-flexibity.c
- *
- * Copyright (C) 2010-2011 Flexibity
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/input.h>
-#include <linux/gpio.h>
-
-#include <asm/mach-types.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-static void __init flexibity_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/* USB Host port */
-static struct at91_usbh_data __initdata flexibity_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/* USB Device port */
-static struct at91_udc_data __initdata flexibity_udc_data = {
- .vbus_pin = AT91_PIN_PC5,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-/* I2C devices */
-static struct i2c_board_info __initdata flexibity_i2c_devices[] = {
- {
- I2C_BOARD_INFO("ds1307", 0x68),
- },
-};
-
-/* SPI devices */
-static struct spi_board_info flexibity_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-};
-
-/* MCI (SD/MMC) */
-static struct mci_platform_data __initdata flexibity_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PC9,
- .wp_pin = AT91_PIN_PC4,
- },
-};
-
-/* LEDs */
-static struct gpio_led flexibity_leds[] = {
- {
- .name = "usb1:green",
- .gpio = AT91_PIN_PA12,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb1:red",
- .gpio = AT91_PIN_PA13,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb2:green",
- .gpio = AT91_PIN_PB26,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb2:red",
- .gpio = AT91_PIN_PB27,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb3:green",
- .gpio = AT91_PIN_PC8,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb3:red",
- .gpio = AT91_PIN_PC6,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb4:green",
- .gpio = AT91_PIN_PB4,
- .active_low = 1,
- .default_trigger = "default-on",
- },
- {
- .name = "usb4:red",
- .gpio = AT91_PIN_PB5,
- .active_low = 1,
- .default_trigger = "default-on",
- }
-};
-
-static void __init flexibity_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&flexibity_usbh_data);
- /* USB Device */
- at91_add_device_udc(&flexibity_udc_data);
- /* I2C */
- at91_add_device_i2c(flexibity_i2c_devices,
- ARRAY_SIZE(flexibity_i2c_devices));
- /* SPI */
- at91_add_device_spi(flexibity_spi_devices,
- ARRAY_SIZE(flexibity_spi_devices));
- /* MMC */
- at91_add_device_mci(0, &flexibity_mci0_data);
- /* LEDs */
- at91_gpio_leds(flexibity_leds, ARRAY_SIZE(flexibity_leds));
-}
-
-MACHINE_START(FLEXIBITY, "Flexibity Connect")
- /* Maintainer: Maxim Osipov */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = flexibity_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = flexibity_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-gsia18s.c b/arch/arm/mach-at91/board-gsia18s.c
deleted file mode 100644
index bf5cc55c..0000000
--- a/arch/arm/mach-at91/board-gsia18s.c
+++ /dev/null
@@ -1,585 +0,0 @@
-/*
- * Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
- * taskit GmbH
- * 2010 Igor Plyatov <plyatov@gmail.com>
- * GeoSIG Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/w1-gpio.h>
-#include <linux/i2c.h>
-#include <linux/i2c/pcf857x.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gsia18s.h"
-#include "stamp9g20.h"
-#include "gpio.h"
-
-static void __init gsia18s_init_early(void)
-{
- stamp9g20_init_early();
-}
-
-/*
- * Two USB Host ports
- */
-static struct at91_usbh_data __initdata usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata udc_data = {
- .vbus_pin = AT91_PIN_PA22,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata macb_data = {
- .phy_irq_pin = AT91_PIN_PA28,
- .is_rmii = 1,
-};
-
-/*
- * LEDs and GPOs
- */
-static struct gpio_led gpio_leds[] = {
- {
- .name = "gpo:spi1reset",
- .gpio = AT91_PIN_PC1,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- {
- .name = "gpo:trig_net_out",
- .gpio = AT91_PIN_PB20,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- {
- .name = "gpo:trig_net_dir",
- .gpio = AT91_PIN_PB19,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- {
- .name = "gpo:charge_dis",
- .gpio = AT91_PIN_PC2,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- {
- .name = "led:event",
- .gpio = AT91_PIN_PB17,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- {
- .name = "led:lan",
- .gpio = AT91_PIN_PB18,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- {
- .name = "led:error",
- .gpio = AT91_PIN_PB16,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- }
-};
-
-static struct gpio_led_platform_data gpio_led_info = {
- .leds = gpio_leds,
- .num_leds = ARRAY_SIZE(gpio_leds),
-};
-
-static struct platform_device leds = {
- .name = "leds-gpio",
- .id = 0,
- .dev = {
- .platform_data = &gpio_led_info,
- }
-};
-
-static void __init gsia18s_leds_init(void)
-{
- platform_device_register(&leds);
-}
-
-/* PCF8574 0x20 GPIO - U1 on the GS_IA18-CB_V3 board */
-static struct gpio_led pcf_gpio_leds1[] = {
- { /* bit 0 */
- .name = "gpo:hdc_power",
- .gpio = PCF_GPIO_HDC_POWER,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 1 */
- .name = "gpo:wifi_setup",
- .gpio = PCF_GPIO_WIFI_SETUP,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 2 */
- .name = "gpo:wifi_enable",
- .gpio = PCF_GPIO_WIFI_ENABLE,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 3 */
- .name = "gpo:wifi_reset",
- .gpio = PCF_GPIO_WIFI_RESET,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- },
- /* bit 4 used as GPI */
- { /* bit 5 */
- .name = "gpo:gps_setup",
- .gpio = PCF_GPIO_GPS_SETUP,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 6 */
- .name = "gpo:gps_standby",
- .gpio = PCF_GPIO_GPS_STANDBY,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- },
- { /* bit 7 */
- .name = "gpo:gps_power",
- .gpio = PCF_GPIO_GPS_POWER,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- }
-};
-
-static struct gpio_led_platform_data pcf_gpio_led_info1 = {
- .leds = pcf_gpio_leds1,
- .num_leds = ARRAY_SIZE(pcf_gpio_leds1),
-};
-
-static struct platform_device pcf_leds1 = {
- .name = "leds-gpio", /* GS_IA18-CB_board */
- .id = 1,
- .dev = {
- .platform_data = &pcf_gpio_led_info1,
- }
-};
-
-/* PCF8574 0x22 GPIO - U1 on the GS_2G_OPT1-A_V0 board (Alarm) */
-static struct gpio_led pcf_gpio_leds2[] = {
- { /* bit 0 */
- .name = "gpo:alarm_1",
- .gpio = PCF_GPIO_ALARM1,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 1 */
- .name = "gpo:alarm_2",
- .gpio = PCF_GPIO_ALARM2,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 2 */
- .name = "gpo:alarm_3",
- .gpio = PCF_GPIO_ALARM3,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- { /* bit 3 */
- .name = "gpo:alarm_4",
- .gpio = PCF_GPIO_ALARM4,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- /* bits 4, 5, 6 not used */
- { /* bit 7 */
- .name = "gpo:alarm_v_relay_on",
- .gpio = PCF_GPIO_ALARM_V_RELAY_ON,
- .active_low = 0,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
-};
-
-static struct gpio_led_platform_data pcf_gpio_led_info2 = {
- .leds = pcf_gpio_leds2,
- .num_leds = ARRAY_SIZE(pcf_gpio_leds2),
-};
-
-static struct platform_device pcf_leds2 = {
- .name = "leds-gpio",
- .id = 2,
- .dev = {
- .platform_data = &pcf_gpio_led_info2,
- }
-};
-
-/* PCF8574 0x24 GPIO U1 on the GS_2G-OPT23-A_V0 board (Modem) */
-static struct gpio_led pcf_gpio_leds3[] = {
- { /* bit 0 */
- .name = "gpo:modem_power",
- .gpio = PCF_GPIO_MODEM_POWER,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_OFF,
- },
- /* bits 1 and 2 not used */
- { /* bit 3 */
- .name = "gpo:modem_reset",
- .gpio = PCF_GPIO_MODEM_RESET,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- },
- /* bits 4, 5 and 6 not used */
- { /* bit 7 */
- .name = "gpo:trx_reset",
- .gpio = PCF_GPIO_TRX_RESET,
- .active_low = 1,
- .default_trigger = "none",
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- }
-};
-
-static struct gpio_led_platform_data pcf_gpio_led_info3 = {
- .leds = pcf_gpio_leds3,
- .num_leds = ARRAY_SIZE(pcf_gpio_leds3),
-};
-
-static struct platform_device pcf_leds3 = {
- .name = "leds-gpio",
- .id = 3,
- .dev = {
- .platform_data = &pcf_gpio_led_info3,
- }
-};
-
-static void __init gsia18s_pcf_leds_init(void)
-{
- platform_device_register(&pcf_leds1);
- platform_device_register(&pcf_leds2);
- platform_device_register(&pcf_leds3);
-}
-
-/*
- * SPI busses.
- */
-static struct spi_board_info gsia18s_spi_devices[] = {
- { /* User accessible spi0, cs0 used for communication with MSP RTC */
- .modalias = "spidev",
- .bus_num = 0,
- .chip_select = 0,
- .max_speed_hz = 580000,
- .mode = SPI_MODE_1,
- },
- { /* User accessible spi1, cs0 used for communication with int. DSP */
- .modalias = "spidev",
- .bus_num = 1,
- .chip_select = 0,
- .max_speed_hz = 5600000,
- .mode = SPI_MODE_0,
- },
- { /* User accessible spi1, cs1 used for communication with ext. DSP */
- .modalias = "spidev",
- .bus_num = 1,
- .chip_select = 1,
- .max_speed_hz = 5600000,
- .mode = SPI_MODE_0,
- },
- { /* User accessible spi1, cs2 used for communication with ext. DSP */
- .modalias = "spidev",
- .bus_num = 1,
- .chip_select = 2,
- .max_speed_hz = 5600000,
- .mode = SPI_MODE_0,
- },
- { /* User accessible spi1, cs3 used for communication with ext. DSP */
- .modalias = "spidev",
- .bus_num = 1,
- .chip_select = 3,
- .max_speed_hz = 5600000,
- .mode = SPI_MODE_0,
- }
-};
-
-/*
- * GPI Buttons
- */
-static struct gpio_keys_button buttons[] = {
- {
- .gpio = GPIO_TRIG_NET_IN,
- .code = BTN_1,
- .desc = "TRIG_NET_IN",
- .type = EV_KEY,
- .active_low = 0,
- .wakeup = 1,
- },
- { /* SW80 on the GS_IA18_S-MN board*/
- .gpio = GPIO_CARD_UNMOUNT_0,
- .code = BTN_2,
- .desc = "Card umount 0",
- .type = EV_KEY,
- .active_low = 1,
- .wakeup = 1,
- },
- { /* SW79 on the GS_IA18_S-MN board*/
- .gpio = GPIO_CARD_UNMOUNT_1,
- .code = BTN_3,
- .desc = "Card umount 1",
- .type = EV_KEY,
- .active_low = 1,
- .wakeup = 1,
- },
- { /* SW280 on the GS_IA18-CB board*/
- .gpio = GPIO_KEY_POWER,
- .code = KEY_POWER,
- .desc = "Power Off Button",
- .type = EV_KEY,
- .active_low = 0,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data button_data = {
- .buttons = buttons,
- .nbuttons = ARRAY_SIZE(buttons),
-};
-
-static struct platform_device button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &button_data,
- }
-};
-
-static void __init gsia18s_add_device_buttons(void)
-{
- at91_set_gpio_input(GPIO_TRIG_NET_IN, 1);
- at91_set_deglitch(GPIO_TRIG_NET_IN, 1);
- at91_set_gpio_input(GPIO_CARD_UNMOUNT_0, 1);
- at91_set_deglitch(GPIO_CARD_UNMOUNT_0, 1);
- at91_set_gpio_input(GPIO_CARD_UNMOUNT_1, 1);
- at91_set_deglitch(GPIO_CARD_UNMOUNT_1, 1);
- at91_set_gpio_input(GPIO_KEY_POWER, 0);
- at91_set_deglitch(GPIO_KEY_POWER, 1);
-
- platform_device_register(&button_device);
-}
-
-/*
- * I2C
- */
-static int pcf8574x_0x20_setup(struct i2c_client *client, int gpio,
- unsigned int ngpio, void *context)
-{
- int status;
-
- status = gpio_request(gpio + PCF_GPIO_ETH_DETECT, "eth_det");
- if (status < 0) {
- pr_err("error: can't request GPIO%d\n",
- gpio + PCF_GPIO_ETH_DETECT);
- return status;
- }
- status = gpio_direction_input(gpio + PCF_GPIO_ETH_DETECT);
- if (status < 0) {
- pr_err("error: can't setup GPIO%d as input\n",
- gpio + PCF_GPIO_ETH_DETECT);
- return status;
- }
- status = gpio_export(gpio + PCF_GPIO_ETH_DETECT, false);
- if (status < 0) {
- pr_err("error: can't export GPIO%d\n",
- gpio + PCF_GPIO_ETH_DETECT);
- return status;
- }
- status = gpio_sysfs_set_active_low(gpio + PCF_GPIO_ETH_DETECT, 1);
- if (status < 0) {
- pr_err("error: gpio_sysfs_set active_low(GPIO%d, 1)\n",
- gpio + PCF_GPIO_ETH_DETECT);
- return status;
- }
-
- return 0;
-}
-
-static int pcf8574x_0x20_teardown(struct i2c_client *client, int gpio,
- unsigned ngpio, void *context)
-{
- gpio_free(gpio + PCF_GPIO_ETH_DETECT);
- return 0;
-}
-
-static struct pcf857x_platform_data pcf20_pdata = {
- .gpio_base = GS_IA18_S_PCF_GPIO_BASE0,
- .n_latch = (1 << 4),
- .setup = pcf8574x_0x20_setup,
- .teardown = pcf8574x_0x20_teardown,
-};
-
-static struct pcf857x_platform_data pcf22_pdata = {
- .gpio_base = GS_IA18_S_PCF_GPIO_BASE1,
-};
-
-static struct pcf857x_platform_data pcf24_pdata = {
- .gpio_base = GS_IA18_S_PCF_GPIO_BASE2,
-};
-
-static struct i2c_board_info __initdata gsia18s_i2c_devices[] = {
- { /* U1 on the GS_IA18-CB_V3 board */
- I2C_BOARD_INFO("pcf8574", 0x20),
- .platform_data = &pcf20_pdata,
- },
- { /* U1 on the GS_2G_OPT1-A_V0 board (Alarm) */
- I2C_BOARD_INFO("pcf8574", 0x22),
- .platform_data = &pcf22_pdata,
- },
- { /* U1 on the GS_2G-OPT23-A_V0 board (Modem) */
- I2C_BOARD_INFO("pcf8574", 0x24),
- .platform_data = &pcf24_pdata,
- },
- { /* U161 on the GS_IA18_S-MN board */
- I2C_BOARD_INFO("24c1024", 0x50),
- },
- { /* U162 on the GS_IA18_S-MN board */
- I2C_BOARD_INFO("24c01", 0x53),
- },
-};
-
-/*
- * Compact Flash
- */
-static struct at91_cf_data __initdata gsia18s_cf1_data = {
- .irq_pin = AT91_PIN_PA27,
- .det_pin = AT91_PIN_PB30,
- .vcc_pin = -EINVAL,
- .rst_pin = AT91_PIN_PB31,
- .chipselect = 5,
- .flags = AT91_CF_TRUE_IDE,
-};
-
-/* Power Off by RTC */
-static void gsia18s_power_off(void)
-{
- pr_notice("Power supply will be switched off automatically now or after 60 seconds without ArmDAS.\n");
- at91_set_gpio_output(AT91_PIN_PA25, 1);
- /* Spin to death... */
- while (1)
- ;
-}
-
-static int __init gsia18s_power_off_init(void)
-{
- pm_power_off = gsia18s_power_off;
- return 0;
-}
-
-/* ---------------------------------------------------------------------------*/
-
-static void __init gsia18s_board_init(void)
-{
- /*
- * USART0 on ttyS1 (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI).
- * Used for Internal Analog Modem.
- */
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS | ATMEL_UART_RTS |
- ATMEL_UART_DTR | ATMEL_UART_DSR |
- ATMEL_UART_DCD | ATMEL_UART_RI);
- /*
- * USART1 on ttyS2 (Rx, Tx, CTS, RTS).
- * Used for GPS or WiFi or Data stream.
- */
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- /*
- * USART2 on ttyS3 (Rx, Tx, CTS, RTS).
- * Used for External Modem.
- */
- at91_register_uart(AT91SAM9260_ID_US2, 3,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- /*
- * USART3 on ttyS4 (Rx, Tx, RTS).
- * Used for RS-485.
- */
- at91_register_uart(AT91SAM9260_ID_US3, 4, ATMEL_UART_RTS);
-
- /*
- * USART4 on ttyS5 (Rx, Tx).
- * Used for TRX433 Radio Module.
- */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
- stamp9g20_board_init();
- at91_add_device_usbh(&usbh_data);
- at91_add_device_udc(&udc_data);
- at91_add_device_eth(&macb_data);
- gsia18s_leds_init();
- gsia18s_pcf_leds_init();
- gsia18s_add_device_buttons();
- at91_add_device_i2c(gsia18s_i2c_devices,
- ARRAY_SIZE(gsia18s_i2c_devices));
- at91_add_device_cf(&gsia18s_cf1_data);
- at91_add_device_spi(gsia18s_spi_devices,
- ARRAY_SIZE(gsia18s_spi_devices));
- gsia18s_power_off_init();
-}
-
-MACHINE_START(GSIA18S, "GS_IA18_S")
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = gsia18s_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = gsia18s_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-kafa.c b/arch/arm/mach-at91/board-kafa.c
deleted file mode 100644
index 93b1df4..0000000
--- a/arch/arm/mach-at91/board-kafa.c
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-kafa.c
- *
- * Copyright (C) 2006 Sperry-Sun
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/cpu.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init kafa_init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata kafa_eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 0,
-};
-
-static struct at91_usbh_data __initdata kafa_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata kafa_udc_data = {
- .vbus_pin = AT91_PIN_PB6,
- .pullup_pin = AT91_PIN_PB7,
-};
-
-/*
- * LEDs
- */
-static struct gpio_led kafa_leds[] = {
- { /* D1 */
- .name = "led1",
- .gpio = AT91_PIN_PB4,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
-};
-
-static void __init kafa_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1 (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91RM9200_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&kafa_eth_data);
- /* USB Host */
- at91_add_device_usbh(&kafa_usbh_data);
- /* USB Device */
- at91_add_device_udc(&kafa_udc_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* SPI */
- at91_add_device_spi(NULL, 0);
- /* LEDs */
- at91_gpio_leds(kafa_leds, ARRAY_SIZE(kafa_leds));
-}
-
-MACHINE_START(KAFA, "Sperry-Sun KAFA")
- /* Maintainer: Sergei Sharonov */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = kafa_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = kafa_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-kb9202.c b/arch/arm/mach-at91/board-kb9202.c
deleted file mode 100644
index d58d362..0000000
--- a/arch/arm/mach-at91/board-kb9202.c
+++ /dev/null
@@ -1,159 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-kb9202.c
- *
- * Copyright (c) 2005 kb_admin
- * KwikByte, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/cpu.h>
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init kb9202_init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- /* Initialize processor: 10 MHz crystal */
- at91_initialize(10000000);
-}
-
-static struct macb_platform_data __initdata kb9202_eth_data = {
- .phy_irq_pin = AT91_PIN_PB29,
- .is_rmii = 0,
-};
-
-static struct at91_usbh_data __initdata kb9202_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata kb9202_udc_data = {
- .vbus_pin = AT91_PIN_PB24,
- .pullup_pin = AT91_PIN_PB22,
-};
-
-static struct mci_platform_data __initdata kb9202_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PB2,
- .wp_pin = -EINVAL,
- },
-};
-
-static struct mtd_partition __initdata kb9202_nand_partition[] = {
- {
- .name = "nand_fs",
- .offset = 0,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata kb9202_nand_data = {
- .ale = 22,
- .cle = 21,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PC29,
- .enable_pin = AT91_PIN_PC28,
- .ecc_mode = NAND_ECC_SOFT,
- .parts = kb9202_nand_partition,
- .num_parts = ARRAY_SIZE(kb9202_nand_partition),
-};
-
-/*
- * LEDs
- */
-static struct gpio_led kb9202_leds[] = {
- { /* D1 */
- .name = "led1",
- .gpio = AT91_PIN_PC19,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* D2 */
- .name = "led2",
- .gpio = AT91_PIN_PC18,
- .active_low = 1,
- .default_trigger = "timer",
- }
-};
-
-static void __init kb9202_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1 (Rx & Tx only) */
- at91_register_uart(AT91RM9200_ID_US0, 1, 0);
-
- /* USART1 on ttyS2 (Rx & Tx only) - IRDA (optional) */
- at91_register_uart(AT91RM9200_ID_US1, 2, 0);
-
- /* USART3 on ttyS3 (Rx, Tx, CTS, RTS) - RS485 (optional) */
- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&kb9202_eth_data);
- /* USB Host */
- at91_add_device_usbh(&kb9202_usbh_data);
- /* USB Device */
- at91_add_device_udc(&kb9202_udc_data);
- /* MMC */
- at91_add_device_mci(0, &kb9202_mci0_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* SPI */
- at91_add_device_spi(NULL, 0);
- /* NAND */
- at91_add_device_nand(&kb9202_nand_data);
- /* LEDs */
- at91_gpio_leds(kb9202_leds, ARRAY_SIZE(kb9202_leds));
-}
-
-MACHINE_START(KB9200, "KB920x")
- /* Maintainer: KwikByte, Inc. */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = kb9202_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = kb9202_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-pcontrol-g20.c b/arch/arm/mach-at91/board-pcontrol-g20.c
deleted file mode 100644
index 9c26b94..0000000
--- a/arch/arm/mach-at91/board-pcontrol-g20.c
+++ /dev/null
@@ -1,228 +0,0 @@
-/*
- * Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
- * taskit GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-/*
- * copied and adjusted from board-stamp9g20.c
- * by Peter Gsellmann <pgsellmann@portner-elektronik.at>
- */
-
-#include <linux/mm.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/w1-gpio.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "stamp9g20.h"
-#include "gpio.h"
-
-
-static void __init pcontrol_g20_init_early(void)
-{
- stamp9g20_init_early();
-}
-
-static struct sam9_smc_config __initdata pcontrol_smc_config[2] = { {
- .ncs_read_setup = 16,
- .nrd_setup = 18,
- .ncs_write_setup = 16,
- .nwe_setup = 18,
-
- .ncs_read_pulse = 63,
- .nrd_pulse = 55,
- .ncs_write_pulse = 63,
- .nwe_pulse = 55,
-
- .read_cycle = 127,
- .write_cycle = 127,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
- | AT91_SMC_DBW_8 | AT91_SMC_PS_4
- | AT91_SMC_TDFMODE,
- .tdf_cycles = 3,
-}, {
- .ncs_read_setup = 0,
- .nrd_setup = 0,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 8,
- .nrd_pulse = 8,
- .ncs_write_pulse = 5,
- .nwe_pulse = 4,
-
- .read_cycle = 8,
- .write_cycle = 7,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE
- | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_SELECT
- | AT91_SMC_DBW_16 | AT91_SMC_PS_8
- | AT91_SMC_TDFMODE,
- .tdf_cycles = 1,
-} };
-
-static void __init add_device_pcontrol(void)
-{
- /* configure chip-select 4 (IO compatible to 8051 X4 ) */
- sam9_smc_configure(0, 4, &pcontrol_smc_config[0]);
- /* configure chip-select 7 (FerroRAM 256KiBx16bit MR2A16A D4 ) */
- sam9_smc_configure(0, 7, &pcontrol_smc_config[1]);
-}
-
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata pcontrol_g20_udc_data = {
- .vbus_pin = AT91_PIN_PA22, /* Detect +5V bus voltage */
- .pullup_pin = AT91_PIN_PA4, /* K-state, active low */
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata macb_data = {
- .phy_irq_pin = AT91_PIN_PA28,
- .is_rmii = 1,
-};
-
-
-/*
- * I2C devices: eeprom and phy/switch
- */
-static struct i2c_board_info __initdata pcontrol_g20_i2c_devices[] = {
-{ /* D7 address width=2, 8KiB */
- I2C_BOARD_INFO("24c64", 0x50)
-}, { /* D8 address width=1, 1 byte has 32 bits! */
- I2C_BOARD_INFO("lan9303", 0x0a)
-}, };
-
-
-/*
- * LEDs
- */
-static struct gpio_led pcontrol_g20_leds[] = {
- {
- .name = "LED1", /* red H5 */
- .gpio = AT91_PIN_PB18,
- .active_low = 1,
- .default_trigger = "none", /* supervisor */
- }, {
- .name = "LED2", /* yellow H7 */
- .gpio = AT91_PIN_PB19,
- .active_low = 1,
- .default_trigger = "mmc0", /* SD-card activity */
- }, {
- .name = "LED3", /* green H2 */
- .gpio = AT91_PIN_PB20,
- .active_low = 1,
- .default_trigger = "heartbeat", /* blinky */
- }, {
- .name = "LED4", /* red H3 */
- .gpio = AT91_PIN_PC6,
- .active_low = 1,
- .default_trigger = "none", /* connection lost */
- }, {
- .name = "LED5", /* yellow H6 */
- .gpio = AT91_PIN_PC7,
- .active_low = 1,
- .default_trigger = "none", /* unsent data */
- }, {
- .name = "LED6", /* green H1 */
- .gpio = AT91_PIN_PC9,
- .active_low = 1,
- .default_trigger = "none", /* snafu */
- }
-};
-
-
-/*
- * SPI devices
- */
-static struct spi_board_info pcontrol_g20_spi_devices[] = {
- {
- .modalias = "spidev", /* HMI port X4 */
- .chip_select = 1,
- .max_speed_hz = 50 * 1000 * 1000,
- .bus_num = 0,
- }, {
- .modalias = "spidev", /* piggyback A2 */
- .chip_select = 0,
- .max_speed_hz = 50 * 1000 * 1000,
- .bus_num = 1,
- },
-};
-
-
-static void __init pcontrol_g20_board_init(void)
-{
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) piggyback A2 */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS
- | ATMEL_UART_RTS);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) isolated RS485 X5 */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS
- | ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx) 9bit-Bus Multidrop-mode X4 */
- at91_register_uart(AT91SAM9260_ID_US4, 3, 0);
- stamp9g20_board_init();
- at91_add_device_usbh(&usbh_data);
- at91_add_device_eth(&macb_data);
- at91_add_device_i2c(pcontrol_g20_i2c_devices,
- ARRAY_SIZE(pcontrol_g20_i2c_devices));
- add_device_pcontrol();
- at91_add_device_spi(pcontrol_g20_spi_devices,
- ARRAY_SIZE(pcontrol_g20_spi_devices));
- at91_add_device_udc(&pcontrol_g20_udc_data);
- at91_gpio_leds(pcontrol_g20_leds,
- ARRAY_SIZE(pcontrol_g20_leds));
- /* piggyback A2 */
- at91_set_gpio_output(AT91_PIN_PB31, 1);
-}
-
-
-MACHINE_START(PCONTROL_G20, "PControl G20")
- /* Maintainer: pgsellmann@portner-elektronik.at */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = pcontrol_g20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = pcontrol_g20_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-picotux200.c b/arch/arm/mach-at91/board-picotux200.c
deleted file mode 100644
index 2c0f2d5..0000000
--- a/arch/arm/mach-at91/board-picotux200.c
+++ /dev/null
@@ -1,129 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-picotux200.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2007 Kleinhenz Elektronik GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mtd/physmap.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init picotux200_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata picotux200_eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata picotux200_usbh_data = {
- .ports = 1,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct mci_platform_data __initdata picotux200_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PB27,
- .wp_pin = AT91_PIN_PA17,
- },
-};
-
-#define PICOTUX200_FLASH_BASE AT91_CHIPSELECT_0
-#define PICOTUX200_FLASH_SIZE SZ_4M
-
-static struct physmap_flash_data picotux200_flash_data = {
- .width = 2,
-};
-
-static struct resource picotux200_flash_resource = {
- .start = PICOTUX200_FLASH_BASE,
- .end = PICOTUX200_FLASH_BASE + PICOTUX200_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device picotux200_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &picotux200_flash_data,
- },
- .resource = &picotux200_flash_resource,
- .num_resources = 1,
-};
-
-static void __init picotux200_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&picotux200_eth_data);
- /* USB Host */
- at91_add_device_usbh(&picotux200_usbh_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* MMC */
- at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
- at91_add_device_mci(0, &picotux200_mci0_data);
- /* NOR Flash */
- platform_device_register(&picotux200_flash);
-}
-
-MACHINE_START(PICOTUX2XX, "picotux 200")
- /* Maintainer: Kleinhenz Elektronik GmbH */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = picotux200_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = picotux200_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-rm9200ek.c b/arch/arm/mach-at91/board-rm9200ek.c
deleted file mode 100644
index 953cea4..0000000
--- a/arch/arm/mach-at91/board-rm9200ek.c
+++ /dev/null
@@ -1,196 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-rm9200ek.c
- *
- * Copyright (C) 2005 SAN People
- *
- * Epson S1D framebuffer glue code is:
- * Copyright (C) 2005 Thibaut VARENE <varenet@parisc-linux.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/mtd/physmap.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-static struct macb_platform_data __initdata ek_eth_data = {
- .phy_irq_pin = AT91_PIN_PC4,
- .is_rmii = 1,
-};
-
-static struct at91_usbh_data __initdata ek_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata ek_udc_data = {
- .vbus_pin = AT91_PIN_PD4,
- .pullup_pin = AT91_PIN_PD5,
-};
-
-#ifndef CONFIG_MTD_AT91_DATAFLASH_CARD
-static struct mci_platform_data __initdata ek_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PB27,
- .wp_pin = AT91_PIN_PA17,
- }
-};
-#endif
-
-static struct spi_board_info ek_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- },
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
- { /* DataFlash card */
- .modalias = "mtd_dataflash",
- .chip_select = 3,
- .max_speed_hz = 15 * 1000 * 1000,
- },
-#endif
-};
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
- {
- I2C_BOARD_INFO("ics1523", 0x26),
- },
- {
- I2C_BOARD_INFO("dac3550", 0x4d),
- }
-};
-
-#define EK_FLASH_BASE AT91_CHIPSELECT_0
-#define EK_FLASH_SIZE SZ_8M
-
-static struct physmap_flash_data ek_flash_data = {
- .width = 2,
-};
-
-static struct resource ek_flash_resource = {
- .start = EK_FLASH_BASE,
- .end = EK_FLASH_BASE + EK_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device ek_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &ek_flash_data,
- },
- .resource = &ek_flash_resource,
- .num_resources = 1,
-};
-
-static struct gpio_led ek_leds[] = {
- { /* "user led 1", DS2 */
- .name = "green",
- .gpio = AT91_PIN_PB0,
- .active_low = 1,
- .default_trigger = "mmc0",
- },
- { /* "user led 2", DS4 */
- .name = "yellow",
- .gpio = AT91_PIN_PB1,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* "user led 3", DS6 */
- .name = "red",
- .gpio = AT91_PIN_PB2,
- .active_low = 1,
- }
-};
-
-static void __init ek_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&ek_eth_data);
- /* USB Host */
- at91_add_device_usbh(&ek_usbh_data);
- /* USB Device */
- at91_add_device_udc(&ek_udc_data);
- at91_set_multi_drive(ek_udc_data.pullup_pin, 1); /* pullup_pin is connected to reset */
- /* I2C */
- at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
-#ifdef CONFIG_MTD_AT91_DATAFLASH_CARD
- /* DataFlash card */
- at91_set_gpio_output(AT91_PIN_PB22, 0);
-#else
- /* MMC */
- at91_set_gpio_output(AT91_PIN_PB22, 1); /* this MMC card slot can optionally use SPI signaling (CS3). */
- at91_add_device_mci(0, &ek_mci0_data);
-#endif
- /* NOR Flash */
- platform_device_register(&ek_flash);
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
- /* VGA */
-// ek_add_device_video();
-}
-
-MACHINE_START(AT91RM9200EK, "Atmel AT91RM9200-EK")
- /* Maintainer: SAN People/Atmel */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9-l9260.c b/arch/arm/mach-at91/board-sam9-l9260.c
deleted file mode 100644
index c2166e3..0000000
--- a/arch/arm/mach-at91/board-sam9-l9260.c
+++ /dev/null
@@ -1,230 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-sam9-l9260.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- * Copyright (C) 2007 Olimex Ltd
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/at91sam9_smc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
- .vbus_pin = AT91_PIN_PC5,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
-#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
- { /* DataFlash card */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#endif
-#endif
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata ek_macb_data = {
- .phy_irq_pin = AT91_PIN_PA7,
- .is_rmii = 0,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Bootloader Area",
- .offset = 0,
- .size = 10 * SZ_1M,
- },
- {
- .name = "User Area",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 21,
- .cle = 22,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
- .ecc_mode = NAND_ECC_SOFT,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 2,
-};
-
-static void __init ek_add_device_nand(void)
-{
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata ek_mci0_data = {
- .slot[1] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PC8,
- .wp_pin = AT91_PIN_PC4,
- },
-};
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
- { /* D1 */
- .name = "led1",
- .gpio = AT91_PIN_PA9,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* D2 */
- .name = "led2",
- .gpio = AT91_PIN_PA6,
- .active_low = 1,
- .default_trigger = "timer",
- }
-};
-
-static void __init ek_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&ek_usbh_data);
- /* USB Device */
- at91_add_device_udc(&ek_udc_data);
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* NAND */
- ek_add_device_nand();
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* MMC */
- at91_add_device_mci(0, &ek_mci0_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
-}
-
-MACHINE_START(SAM9_L9260, "Olimex SAM9-L9260")
- /* Maintainer: Olimex */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9260ek.c b/arch/arm/mach-at91/board-sam9260ek.c
deleted file mode 100644
index bf8a946..0000000
--- a/arch/arm/mach-at91/board-sam9260ek.c
+++ /dev/null
@@ -1,354 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-sam9260ek.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/at73c213.h>
-#include <linux/clk.h>
-#include <linux/platform_data/at24.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
- .vbus_pin = AT91_PIN_PC5,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * Audio
- */
-static struct at73c213_board_info at73c213_data = {
- .ssc_id = 0,
- .shortname = "AT91SAM9260-EK external DAC",
-};
-
-#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
-static void __init at73c213_set_clk(struct at73c213_board_info *info)
-{
- struct clk *pck0;
- struct clk *plla;
-
- pck0 = clk_get(NULL, "pck0");
- plla = clk_get(NULL, "plla");
-
- /* AT73C213 MCK Clock */
- at91_set_B_periph(AT91_PIN_PC1, 0); /* PCK0 */
-
- clk_set_parent(pck0, plla);
- clk_put(plla);
-
- info->dac_clk = pck0;
-}
-#else
-static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
-#endif
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
-#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
- { /* DataFlash card */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#endif
-#endif
-#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
- { /* AT73C213 DAC */
- .modalias = "at73c213",
- .chip_select = 0,
- .max_speed_hz = 10 * 1000 * 1000,
- .bus_num = 1,
- .mode = SPI_MODE_1,
- .platform_data = &at73c213_data,
- },
-#endif
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata ek_macb_data = {
- .phy_irq_pin = AT91_PIN_PA7,
- .is_rmii = 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Partition 1",
- .offset = 0,
- .size = SZ_256K,
- },
- {
- .name = "Partition 2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 21,
- .cle = 22,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
- .ecc_mode = NAND_ECC_SOFT,
- .on_flash_bbt = 1,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
- .tdf_cycles = 2,
-};
-
-static void __init ek_add_device_nand(void)
-{
- ek_nand_data.bus_width_16 = board_have_nand_16bit();
- /* setup bus-width (8 or 16) */
- if (ek_nand_data.bus_width_16)
- ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
- else
- ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata ek_mci0_data = {
- .slot[1] = {
- .bus_width = 4,
- .detect_pin = -EINVAL,
- .wp_pin = -EINVAL,
- },
-};
-
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
- { /* "bottom" led, green, userled1 to be defined */
- .name = "ds5",
- .gpio = AT91_PIN_PA6,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* "power" led, yellow */
- .name = "ds1",
- .gpio = AT91_PIN_PA9,
- .default_trigger = "heartbeat",
- }
-};
-
-/*
- * I2C devices
- */
-static struct at24_platform_data at24c512 = {
- .byte_len = SZ_512K / 8,
- .page_size = 128,
- .flags = AT24_FLAG_ADDR16,
-};
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
- {
- I2C_BOARD_INFO("24c512", 0x50),
- .platform_data = &at24c512,
- },
- /* more devices can be added using expansion connectors */
-};
-
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ek_buttons[] = {
- {
- .gpio = AT91_PIN_PA30,
- .code = BTN_3,
- .desc = "Button 3",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PA31,
- .code = BTN_4,
- .desc = "Button 4",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data ek_button_data = {
- .buttons = ek_buttons,
- .nbuttons = ARRAY_SIZE(ek_buttons),
-};
-
-static struct platform_device ek_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_button_data,
- }
-};
-
-static void __init ek_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PA30, 1); /* btn3 */
- at91_set_deglitch(AT91_PIN_PA30, 1);
- at91_set_gpio_input(AT91_PIN_PA31, 1); /* btn4 */
- at91_set_deglitch(AT91_PIN_PA31, 1);
-
- platform_device_register(&ek_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-
-static void __init ek_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&ek_usbh_data);
- /* USB Device */
- at91_add_device_udc(&ek_udc_data);
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* NAND */
- ek_add_device_nand();
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* MMC */
- at91_add_device_mci(0, &ek_mci0_data);
- /* I2C */
- at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
- /* SSC (to AT73C213) */
- at73c213_set_clk(&at73c213_data);
- at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
- /* Push Buttons */
- ek_add_device_buttons();
-}
-
-MACHINE_START(AT91SAM9260EK, "Atmel AT91SAM9260-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9261ek.c b/arch/arm/mach-at91/board-sam9261ek.c
deleted file mode 100644
index e85ada8..0000000
--- a/arch/arm/mach-at91/board-sam9261ek.c
+++ /dev/null
@@ -1,623 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-sam9261ek.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2006 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
-#include <linux/spi/at73c213.h>
-#include <linux/clk.h>
-#include <linux/dm9000.h>
-#include <linux/fb.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * DM9000 ethernet device
- */
-#if defined(CONFIG_DM9000)
-static struct resource dm9000_resource[] = {
- [0] = {
- .start = AT91_CHIPSELECT_2,
- .end = AT91_CHIPSELECT_2 + 3,
- .flags = IORESOURCE_MEM
- },
- [1] = {
- .start = AT91_CHIPSELECT_2 + 0x44,
- .end = AT91_CHIPSELECT_2 + 0xFF,
- .flags = IORESOURCE_MEM
- },
- [2] = {
- .flags = IORESOURCE_IRQ
- | IORESOURCE_IRQ_LOWEDGE | IORESOURCE_IRQ_HIGHEDGE,
- }
-};
-
-static struct dm9000_plat_data dm9000_platdata = {
- .flags = DM9000_PLATF_16BITONLY | DM9000_PLATF_NO_EEPROM,
-};
-
-static struct platform_device dm9000_device = {
- .name = "dm9000",
- .id = 0,
- .num_resources = ARRAY_SIZE(dm9000_resource),
- .resource = dm9000_resource,
- .dev = {
- .platform_data = &dm9000_platdata,
- }
-};
-
-/*
- * SMC timings for the DM9000.
- * Note: These timings were calculated for MASTER_CLOCK = 100000000 according to the DM9000 timings.
- */
-static struct sam9_smc_config __initdata dm9000_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 2,
- .ncs_write_setup = 0,
- .nwe_setup = 2,
-
- .ncs_read_pulse = 8,
- .nrd_pulse = 4,
- .ncs_write_pulse = 8,
- .nwe_pulse = 4,
-
- .read_cycle = 16,
- .write_cycle = 16,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_BAT_WRITE | AT91_SMC_DBW_16,
- .tdf_cycles = 1,
-};
-
-static void __init ek_add_device_dm9000(void)
-{
- struct resource *r = &dm9000_resource[2];
-
- /* Configure chip-select 2 (DM9000) */
- sam9_smc_configure(0, 2, &dm9000_smc_config);
-
- /* Configure Reset signal as output */
- at91_set_gpio_output(AT91_PIN_PC10, 0);
-
- /* Configure Interrupt pin as input, no pull-up */
- at91_set_gpio_input(AT91_PIN_PC11, 0);
-
- r->start = r->end = gpio_to_irq(AT91_PIN_PC11);
- platform_device_register(&dm9000_device);
-}
-#else
-static void __init ek_add_device_dm9000(void) {}
-#endif /* CONFIG_DM9000 */
-
-
-/*
- * USB Host Port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-
-/*
- * USB Device Port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
- .vbus_pin = AT91_PIN_PB29,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Partition 1",
- .offset = 0,
- .size = SZ_256K,
- },
- {
- .name = "Partition 2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 22,
- .cle = 21,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PC15,
- .enable_pin = AT91_PIN_PC14,
- .ecc_mode = NAND_ECC_SOFT,
- .on_flash_bbt = 1,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
- .tdf_cycles = 2,
-};
-
-static void __init ek_add_device_nand(void)
-{
- ek_nand_data.bus_width_16 = board_have_nand_16bit();
- /* setup bus-width (8 or 16) */
- if (ek_nand_data.bus_width_16)
- ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
- else
- ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-/*
- * SPI related devices
- */
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
-
-/*
- * ADS7846 Touchscreen
- */
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-
-static int ads7843_pendown_state(void)
-{
- return !at91_get_gpio_value(AT91_PIN_PC2); /* Touchscreen PENIRQ */
-}
-
-static struct ads7846_platform_data ads_info = {
- .model = 7843,
- .x_min = 150,
- .x_max = 3830,
- .y_min = 190,
- .y_max = 3830,
- .vref_delay_usecs = 100,
- .x_plate_ohms = 450,
- .y_plate_ohms = 250,
- .pressure_max = 15000,
- .debounce_max = 1,
- .debounce_rep = 0,
- .debounce_tol = (~0),
- .get_pendown_state = ads7843_pendown_state,
-};
-
-static void __init ek_add_device_ts(void)
-{
- at91_set_B_periph(AT91_PIN_PC2, 1); /* External IRQ0, with pullup */
- at91_set_gpio_input(AT91_PIN_PA11, 1); /* Touchscreen BUSY signal */
-}
-#else
-static void __init ek_add_device_ts(void) {}
-#endif
-
-/*
- * Audio
- */
-static struct at73c213_board_info at73c213_data = {
- .ssc_id = 1,
- .shortname = "AT91SAM9261/9G10-EK external DAC",
-};
-
-#if defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
-static void __init at73c213_set_clk(struct at73c213_board_info *info)
-{
- struct clk *pck2;
- struct clk *plla;
-
- pck2 = clk_get(NULL, "pck2");
- plla = clk_get(NULL, "plla");
-
- /* AT73C213 MCK Clock */
- at91_set_B_periph(AT91_PIN_PB31, 0); /* PCK2 */
-
- clk_set_parent(pck2, plla);
- clk_put(plla);
-
- info->dac_clk = pck2;
-}
-#else
-static void __init at73c213_set_clk(struct at73c213_board_info *info) {}
-#endif
-
-/*
- * SPI devices
- */
-static struct spi_board_info ek_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
- {
- .modalias = "ads7846",
- .chip_select = 2,
- .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
- .bus_num = 0,
- .platform_data = &ads_info,
- .irq = NR_IRQS_LEGACY + AT91SAM9261_ID_IRQ0,
- .controller_data = (void *) AT91_PIN_PA28, /* CS pin */
- },
-#endif
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
- { /* DataFlash card - jumper (J12) configurable to CS3 or CS0 */
- .modalias = "mtd_dataflash",
- .chip_select = 3,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#elif defined(CONFIG_SND_AT73C213) || defined(CONFIG_SND_AT73C213_MODULE)
- { /* AT73C213 DAC */
- .modalias = "at73c213",
- .chip_select = 3,
- .max_speed_hz = 10 * 1000 * 1000,
- .bus_num = 0,
- .mode = SPI_MODE_1,
- .platform_data = &at73c213_data,
- .controller_data = (void*) AT91_PIN_PA29, /* default for CS3 is PA6, but it must be PA29 */
- },
-#endif
-};
-
-#else /* CONFIG_SPI_ATMEL_* */
-/* spi0 and mmc/sd share the same PIO pins: cannot be used at the same time */
-
-/*
- * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
- */
-static struct mci_platform_data __initdata mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = -EINVAL,
- .wp_pin = -EINVAL,
- },
-};
-
-#endif /* CONFIG_SPI_ATMEL_* */
-
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-
-#if defined(CONFIG_FB_ATMEL_STN)
-
-/* STN */
-static struct fb_videomode at91_stn_modes[] = {
- {
- .name = "SP06Q002 @ 75",
- .refresh = 75,
- .xres = 320, .yres = 240,
- .pixclock = KHZ2PICOS(1440),
-
- .left_margin = 1, .right_margin = 1,
- .upper_margin = 0, .lower_margin = 0,
- .hsync_len = 1, .vsync_len = 1,
-
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED,
- },
-};
-
-static struct fb_monspecs at91fb_default_stn_monspecs = {
- .manufacturer = "HIT",
- .monitor = "SP06Q002",
-
- .modedb = at91_stn_modes,
- .modedb_len = ARRAY_SIZE(at91_stn_modes),
- .hfmin = 15000,
- .hfmax = 64000,
- .vfmin = 50,
- .vfmax = 150,
-};
-
-#define AT91SAM9261_DEFAULT_STN_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
- | ATMEL_LCDC_DISTYPE_STNMONO \
- | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE \
- | ATMEL_LCDC_IFWIDTH_4 \
- | ATMEL_LCDC_SCANMOD_SINGLE)
-
-static void at91_lcdc_stn_power_control(struct atmel_lcdfb_pdata *pdata, int on)
-{
- /* backlight */
- if (on) { /* power up */
- at91_set_gpio_value(AT91_PIN_PC14, 0);
- at91_set_gpio_value(AT91_PIN_PC15, 0);
- } else { /* power down */
- at91_set_gpio_value(AT91_PIN_PC14, 1);
- at91_set_gpio_value(AT91_PIN_PC15, 1);
- }
-}
-
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
- .default_bpp = 1,
- .default_dmacon = ATMEL_LCDC_DMAEN,
- .default_lcdcon2 = AT91SAM9261_DEFAULT_STN_LCDCON2,
- .default_monspecs = &at91fb_default_stn_monspecs,
- .atmel_lcdfb_power_control = at91_lcdc_stn_power_control,
- .guard_time = 1,
-};
-
-#else
-
-/* TFT */
-static struct fb_videomode at91_tft_vga_modes[] = {
- {
- .name = "TX09D50VM1CCA @ 60",
- .refresh = 60,
- .xres = 240, .yres = 320,
- .pixclock = KHZ2PICOS(4965),
-
- .left_margin = 1, .right_margin = 33,
- .upper_margin = 1, .lower_margin = 0,
- .hsync_len = 5, .vsync_len = 1,
-
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED,
- },
-};
-
-static struct fb_monspecs at91fb_default_tft_monspecs = {
- .manufacturer = "HIT",
- .monitor = "TX09D50VM1CCA",
-
- .modedb = at91_tft_vga_modes,
- .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
- .hfmin = 15000,
- .hfmax = 64000,
- .vfmin = 50,
- .vfmax = 150,
-};
-
-#define AT91SAM9261_DEFAULT_TFT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
- | ATMEL_LCDC_DISTYPE_TFT \
- | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-static void at91_lcdc_tft_power_control(struct atmel_lcdfb_pdata *pdata, int on)
-{
- if (on)
- at91_set_gpio_value(AT91_PIN_PA12, 0); /* power up */
- else
- at91_set_gpio_value(AT91_PIN_PA12, 1); /* power down */
-}
-
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
- .lcdcon_is_backlight = true,
- .default_bpp = 16,
- .default_dmacon = ATMEL_LCDC_DMAEN,
- .default_lcdcon2 = AT91SAM9261_DEFAULT_TFT_LCDCON2,
- .default_monspecs = &at91fb_default_tft_monspecs,
- .atmel_lcdfb_power_control = at91_lcdc_tft_power_control,
- .guard_time = 1,
-};
-#endif
-
-#else
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
-#endif
-
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ek_buttons[] = {
- {
- .gpio = AT91_PIN_PA27,
- .code = BTN_0,
- .desc = "Button 0",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PA26,
- .code = BTN_1,
- .desc = "Button 1",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PA25,
- .code = BTN_2,
- .desc = "Button 2",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PA24,
- .code = BTN_3,
- .desc = "Button 3",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data ek_button_data = {
- .buttons = ek_buttons,
- .nbuttons = ARRAY_SIZE(ek_buttons),
-};
-
-static struct platform_device ek_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_button_data,
- }
-};
-
-static void __init ek_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PA27, 1); /* btn0 */
- at91_set_deglitch(AT91_PIN_PA27, 1);
- at91_set_gpio_input(AT91_PIN_PA26, 1); /* btn1 */
- at91_set_deglitch(AT91_PIN_PA26, 1);
- at91_set_gpio_input(AT91_PIN_PA25, 1); /* btn2 */
- at91_set_deglitch(AT91_PIN_PA25, 1);
- at91_set_gpio_input(AT91_PIN_PA24, 1); /* btn3 */
- at91_set_deglitch(AT91_PIN_PA24, 1);
-
- platform_device_register(&ek_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
- { /* "bottom" led, green, userled1 to be defined */
- .name = "ds7",
- .gpio = AT91_PIN_PA14,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* "top" led, green, userled2 to be defined */
- .name = "ds8",
- .gpio = AT91_PIN_PA13,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* "power" led, yellow */
- .name = "ds1",
- .gpio = AT91_PIN_PA23,
- .default_trigger = "heartbeat",
- }
-};
-
-static void __init ek_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
-
- if (cpu_is_at91sam9g10())
- ek_lcdc_data.lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB;
-
- /* USB Host */
- at91_add_device_usbh(&ek_usbh_data);
- /* USB Device */
- at91_add_device_udc(&ek_udc_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* NAND */
- ek_add_device_nand();
- /* DM9000 ethernet */
- ek_add_device_dm9000();
-
- /* spi0 and mmc/sd share the same PIO pins */
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* Touchscreen */
- ek_add_device_ts();
- /* SSC (to AT73C213) */
- at73c213_set_clk(&at73c213_data);
- at91_add_device_ssc(AT91SAM9261_ID_SSC1, ATMEL_SSC_TX);
-#else
- /* MMC */
- at91_add_device_mci(0, &mci0_data);
-#endif
- /* LCD Controller */
- at91_add_device_lcdc(&ek_lcdc_data);
- /* Push Buttons */
- ek_add_device_buttons();
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
-}
-
-MACHINE_START(AT91SAM9261EK, "Atmel AT91SAM9261-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
-
-MACHINE_START(AT91SAM9G10EK, "Atmel AT91SAM9G10-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9263ek.c b/arch/arm/mach-at91/board-sam9263ek.c
deleted file mode 100644
index d76680f..0000000
--- a/arch/arm/mach-at91/board-sam9263ek.c
+++ /dev/null
@@ -1,493 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-sam9263ek.c
- *
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2007 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
-#include <linux/platform_data/at24.h>
-#include <linux/fb.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/leds.h>
-#include <linux/pwm.h>
-#include <linux/leds_pwm.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 16.367 MHz crystal */
- at91_initialize(16367660);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
- .ports = 2,
- .vbus_pin = { AT91_PIN_PA24, AT91_PIN_PA21 },
- .vbus_pin_active_low = {1, 1},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
- .vbus_pin = AT91_PIN_PA25,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * ADS7846 Touchscreen
- */
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-static int ads7843_pendown_state(void)
-{
- return !at91_get_gpio_value(AT91_PIN_PA15); /* Touchscreen PENIRQ */
-}
-
-static struct ads7846_platform_data ads_info = {
- .model = 7843,
- .x_min = 150,
- .x_max = 3830,
- .y_min = 190,
- .y_max = 3830,
- .vref_delay_usecs = 100,
- .x_plate_ohms = 450,
- .y_plate_ohms = 250,
- .pressure_max = 15000,
- .debounce_max = 1,
- .debounce_rep = 0,
- .debounce_tol = (~0),
- .get_pendown_state = ads7843_pendown_state,
-};
-
-static void __init ek_add_device_ts(void)
-{
- at91_set_B_periph(AT91_PIN_PA15, 1); /* External IRQ1, with pullup */
- at91_set_gpio_input(AT91_PIN_PA31, 1); /* Touchscreen BUSY signal */
-}
-#else
-static void __init ek_add_device_ts(void) {}
-#endif
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
- { /* DataFlash card */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#endif
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
- {
- .modalias = "ads7846",
- .chip_select = 3,
- .max_speed_hz = 125000 * 26, /* (max sample rate @ 3V) * (cmd + data + overhead) */
- .bus_num = 0,
- .platform_data = &ads_info,
- .irq = NR_IRQS_LEGACY + AT91SAM9263_ID_IRQ1,
- },
-#endif
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata mci1_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PE18,
- .wp_pin = AT91_PIN_PE19,
- },
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata ek_macb_data = {
- .phy_irq_pin = AT91_PIN_PE31,
- .is_rmii = 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Partition 1",
- .offset = 0,
- .size = SZ_64M,
- },
- {
- .name = "Partition 2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 21,
- .cle = 22,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PA22,
- .enable_pin = AT91_PIN_PD15,
- .ecc_mode = NAND_ECC_SOFT,
- .on_flash_bbt = 1,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
- .tdf_cycles = 2,
-};
-
-static void __init ek_add_device_nand(void)
-{
- ek_nand_data.bus_width_16 = board_have_nand_16bit();
- /* setup bus-width (8 or 16) */
- if (ek_nand_data.bus_width_16)
- ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
- else
- ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * I2C devices
- */
-static struct at24_platform_data at24c512 = {
- .byte_len = SZ_512K / 8,
- .page_size = 128,
- .flags = AT24_FLAG_ADDR16,
-};
-
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
- {
- I2C_BOARD_INFO("24c512", 0x50),
- .platform_data = &at24c512,
- },
- /* more devices can be added using expansion connectors */
-};
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static struct fb_videomode at91_tft_vga_modes[] = {
- {
- .name = "TX09D50VM1CCA @ 60",
- .refresh = 60,
- .xres = 240, .yres = 320,
- .pixclock = KHZ2PICOS(4965),
-
- .left_margin = 1, .right_margin = 33,
- .upper_margin = 1, .lower_margin = 0,
- .hsync_len = 5, .vsync_len = 1,
-
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED,
- },
-};
-
-static struct fb_monspecs at91fb_default_monspecs = {
- .manufacturer = "HIT",
- .monitor = "TX09D70VM1CCA",
-
- .modedb = at91_tft_vga_modes,
- .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
- .hfmin = 15000,
- .hfmax = 64000,
- .vfmin = 50,
- .vfmax = 150,
-};
-
-#define AT91SAM9263_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
- | ATMEL_LCDC_DISTYPE_TFT \
- | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-static void at91_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
-{
- at91_set_gpio_value(AT91_PIN_PA30, on);
-}
-
-/* Driver datas */
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
- .lcdcon_is_backlight = true,
- .default_bpp = 16,
- .default_dmacon = ATMEL_LCDC_DMAEN,
- .default_lcdcon2 = AT91SAM9263_DEFAULT_LCDCON2,
- .default_monspecs = &at91fb_default_monspecs,
- .atmel_lcdfb_power_control = at91_lcdc_power_control,
- .guard_time = 1,
-};
-
-#else
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
-#endif
-
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ek_buttons[] = {
- { /* BP1, "leftclic" */
- .code = BTN_LEFT,
- .gpio = AT91_PIN_PC5,
- .active_low = 1,
- .desc = "left_click",
- .wakeup = 1,
- },
- { /* BP2, "rightclic" */
- .code = BTN_RIGHT,
- .gpio = AT91_PIN_PC4,
- .active_low = 1,
- .desc = "right_click",
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data ek_button_data = {
- .buttons = ek_buttons,
- .nbuttons = ARRAY_SIZE(ek_buttons),
-};
-
-static struct platform_device ek_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_button_data,
- }
-};
-
-static void __init ek_add_device_buttons(void)
-{
- at91_set_GPIO_periph(AT91_PIN_PC5, 1); /* left button */
- at91_set_deglitch(AT91_PIN_PC5, 1);
- at91_set_GPIO_periph(AT91_PIN_PC4, 1); /* right button */
- at91_set_deglitch(AT91_PIN_PC4, 1);
-
- platform_device_register(&ek_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-
-/*
- * AC97
- * reset_pin is not connected: NRST
- */
-static struct ac97c_platform_data ek_ac97_data = {
- .reset_pin = -EINVAL,
-};
-
-
-/*
- * LEDs ... these could all be PWM-driven, for variable brightness
- */
-static struct gpio_led ek_leds[] = {
- { /* "right" led, green, userled2 (could be driven by pwm2) */
- .name = "ds2",
- .gpio = AT91_PIN_PC29,
- .active_low = 1,
- .default_trigger = "nand-disk",
- },
- { /* "power" led, yellow (could be driven by pwm0) */
- .name = "ds3",
- .gpio = AT91_PIN_PB7,
- .default_trigger = "heartbeat",
- },
-#if !IS_ENABLED(CONFIG_LEDS_PWM)
- {
- .name = "ds1",
- .gpio = AT91_PIN_PB8,
- .active_low = 1,
- .default_trigger = "none",
- }
-#endif
-};
-
-/*
- * PWM Leds
- */
-static struct pwm_lookup pwm_lookup[] = {
- PWM_LOOKUP("at91sam9rl-pwm", 1, "leds_pwm", "ds1",
- 5000, PWM_POLARITY_INVERSED),
-};
-
-#if IS_ENABLED(CONFIG_LEDS_PWM)
-static struct led_pwm pwm_leds[] = {
- {
- .name = "ds1",
- .max_brightness = 255,
- },
-};
-
-static struct led_pwm_platform_data pwm_data = {
- .num_leds = ARRAY_SIZE(pwm_leds),
- .leds = pwm_leds,
-};
-
-static struct platform_device leds_pwm = {
- .name = "leds_pwm",
- .id = -1,
- .dev = {
- .platform_data = &pwm_data,
- },
-};
-#endif
-
-
-/*
- * CAN
- */
-static void sam9263ek_transceiver_switch(int on)
-{
- if (on) {
- at91_set_gpio_output(AT91_PIN_PA18, 1); /* CANRXEN */
- at91_set_gpio_output(AT91_PIN_PA19, 0); /* CANRS */
- } else {
- at91_set_gpio_output(AT91_PIN_PA18, 0); /* CANRXEN */
- at91_set_gpio_output(AT91_PIN_PA19, 1); /* CANRS */
- }
-}
-
-static struct at91_can_data ek_can_data = {
- .transceiver_switch = sam9263ek_transceiver_switch,
-};
-
-static struct platform_device *devices[] __initdata = {
-#if IS_ENABLED(CONFIG_LEDS_PWM)
- &leds_pwm,
-#endif
-};
-
-static void __init ek_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9263_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&ek_usbh_data);
- /* USB Device */
- at91_add_device_udc(&ek_udc_data);
- /* SPI */
- at91_set_gpio_output(AT91_PIN_PE20, 1); /* select spi0 clock */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* Touchscreen */
- ek_add_device_ts();
- /* MMC */
- at91_add_device_mci(1, &mci1_data);
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* NAND */
- ek_add_device_nand();
- /* I2C */
- at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
- /* LCD Controller */
- at91_add_device_lcdc(&ek_lcdc_data);
- /* Push Buttons */
- ek_add_device_buttons();
- /* AC97 */
- at91_add_device_ac97(&ek_ac97_data);
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
- pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
-#if IS_ENABLED(CONFIG_LEDS_PWM)
- at91_add_device_pwm(1 << AT91_PWM1);
-#endif
- /* CAN */
- at91_add_device_can(&ek_can_data);
- /* Other platform devices */
- platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-MACHINE_START(AT91SAM9263EK, "Atmel AT91SAM9263-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9g20ek.c b/arch/arm/mach-at91/board-sam9g20ek.c
deleted file mode 100644
index 49f0752..0000000
--- a/arch/arm/mach-at91/board-sam9g20ek.c
+++ /dev/null
@@ -1,429 +0,0 @@
-/*
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2008 Atmel
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/at73c213.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/clk.h>
-#include <linux/regulator/machine.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/consumer.h>
-
-#include <linux/platform_data/at91_adc.h>
-
-#include <mach/hardware.h>
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-/*
- * board revision encoding
- * bit 0:
- * 0 => 1 sd/mmc slot
- * 1 => 2 sd/mmc slots connectors (board from revision C)
- */
-#define HAVE_2MMC (1 << 0)
-static int inline ek_have_2mmc(void)
-{
- return machine_is_at91sam9g20ek_2mmc() || (system_rev & HAVE_2MMC);
-}
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata ek_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata ek_udc_data = {
- .vbus_pin = AT91_PIN_PC5,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
-#if !IS_ENABLED(CONFIG_MMC_ATMELMCI)
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 1,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#if defined(CONFIG_MTD_AT91_DATAFLASH_CARD)
- { /* DataFlash card */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-#endif
-#endif
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata ek_macb_data = {
- .phy_irq_pin = AT91_PIN_PA7,
- .is_rmii = 1,
-};
-
-static void __init ek_add_device_macb(void)
-{
- if (ek_have_2mmc())
- ek_macb_data.phy_irq_pin = AT91_PIN_PB0;
-
- at91_add_device_eth(&ek_macb_data);
-}
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Bootstrap",
- .offset = 0,
- .size = 4 * SZ_1M,
- },
- {
- .name = "Partition 1",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 60 * SZ_1M,
- },
- {
- .name = "Partition 2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-/* det_pin is not connected */
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
- .det_pin = -EINVAL,
- .ecc_mode = NAND_ECC_SOFT,
- .on_flash_bbt = 1,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 2,
- .ncs_write_setup = 0,
- .nwe_setup = 2,
-
- .ncs_read_pulse = 4,
- .nrd_pulse = 4,
- .ncs_write_pulse = 4,
- .nwe_pulse = 4,
-
- .read_cycle = 7,
- .write_cycle = 7,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
- .tdf_cycles = 3,
-};
-
-static void __init ek_add_device_nand(void)
-{
- ek_nand_data.bus_width_16 = board_have_nand_16bit();
- /* setup bus-width (8 or 16) */
- if (ek_nand_data.bus_width_16)
- ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
- else
- ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * MCI (SD/MMC)
- * wp_pin and vcc_pin are not connected
- */
-static struct mci_platform_data __initdata ek_mmc_data = {
- .slot[1] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PC9,
- .wp_pin = -EINVAL,
- },
-
-};
-
-static void __init ek_add_device_mmc(void)
-{
- if (ek_have_2mmc()) {
- ek_mmc_data.slot[0].bus_width = 4;
- ek_mmc_data.slot[0].detect_pin = AT91_PIN_PC2;
- ek_mmc_data.slot[0].wp_pin = -1;
- }
- at91_add_device_mci(0, &ek_mmc_data);
-}
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
- { /* "bottom" led, green, userled1 to be defined */
- .name = "ds5",
- .gpio = AT91_PIN_PA6,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* "power" led, yellow */
- .name = "ds1",
- .gpio = AT91_PIN_PA9,
- .default_trigger = "heartbeat",
- }
-};
-
-static void __init ek_add_device_gpio_leds(void)
-{
- if (ek_have_2mmc()) {
- ek_leds[0].gpio = AT91_PIN_PB8;
- ek_leds[1].gpio = AT91_PIN_PB9;
- }
-
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
-}
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ek_buttons[] = {
- {
- .gpio = AT91_PIN_PA30,
- .code = BTN_3,
- .desc = "Button 3",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PA31,
- .code = BTN_4,
- .desc = "Button 4",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data ek_button_data = {
- .buttons = ek_buttons,
- .nbuttons = ARRAY_SIZE(ek_buttons),
-};
-
-static struct platform_device ek_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_button_data,
- }
-};
-
-static void __init ek_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PA30, 1); /* btn3 */
- at91_set_deglitch(AT91_PIN_PA30, 1);
- at91_set_gpio_input(AT91_PIN_PA31, 1); /* btn4 */
- at91_set_deglitch(AT91_PIN_PA31, 1);
-
- platform_device_register(&ek_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-/*
- * ADCs
- */
-
-static struct at91_adc_data ek_adc_data = {
- .channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3),
- .use_external_triggers = true,
- .vref = 3300,
-};
-
-#if defined(CONFIG_REGULATOR_FIXED_VOLTAGE) || defined(CONFIG_REGULATOR_FIXED_VOLTAGE_MODULE)
-static struct regulator_consumer_supply ek_audio_consumer_supplies[] = {
- REGULATOR_SUPPLY("AVDD", "0-001b"),
- REGULATOR_SUPPLY("HPVDD", "0-001b"),
- REGULATOR_SUPPLY("DBVDD", "0-001b"),
- REGULATOR_SUPPLY("DCVDD", "0-001b"),
-};
-
-static struct regulator_init_data ek_avdd_reg_init_data = {
- .constraints = {
- .name = "3V3",
- .valid_ops_mask = REGULATOR_CHANGE_STATUS,
- },
- .consumer_supplies = ek_audio_consumer_supplies,
- .num_consumer_supplies = ARRAY_SIZE(ek_audio_consumer_supplies),
-};
-
-static struct fixed_voltage_config ek_vdd_pdata = {
- .supply_name = "board-3V3",
- .microvolts = 3300000,
- .gpio = -EINVAL,
- .enabled_at_boot = 0,
- .init_data = &ek_avdd_reg_init_data,
-};
-static struct platform_device ek_voltage_regulator = {
- .name = "reg-fixed-voltage",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_vdd_pdata,
- },
-};
-static void __init ek_add_regulators(void)
-{
- platform_device_register(&ek_voltage_regulator);
-}
-#else
-static void __init ek_add_regulators(void) {}
-#endif
-
-
-static struct i2c_board_info __initdata ek_i2c_devices[] = {
- {
- I2C_BOARD_INFO("24c512", 0x50)
- },
- {
- I2C_BOARD_INFO("wm8731", 0x1b)
- },
-};
-
-static struct platform_device sam9g20ek_audio_device = {
- .name = "at91sam9g20ek-audio",
- .id = -1,
-};
-
-static void __init ek_add_device_audio(void)
-{
- platform_device_register(&sam9g20ek_audio_device);
-}
-
-
-static void __init ek_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB Host */
- at91_add_device_usbh(&ek_usbh_data);
- /* USB Device */
- at91_add_device_udc(&ek_udc_data);
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* NAND */
- ek_add_device_nand();
- /* Ethernet */
- ek_add_device_macb();
- /* Regulators */
- ek_add_regulators();
- /* MMC */
- ek_add_device_mmc();
- /* I2C */
- at91_add_device_i2c(ek_i2c_devices, ARRAY_SIZE(ek_i2c_devices));
- /* LEDs */
- ek_add_device_gpio_leds();
- /* Push Buttons */
- ek_add_device_buttons();
- /* ADCs */
- at91_add_device_adc(&ek_adc_data);
- /* PCK0 provides MCLK to the WM8731 */
- at91_set_B_periph(AT91_PIN_PC1, 0);
- /* SSC (for WM8731) */
- at91_add_device_ssc(AT91SAM9260_ID_SSC, ATMEL_SSC_TX);
- ek_add_device_audio();
-}
-
-MACHINE_START(AT91SAM9G20EK, "Atmel AT91SAM9G20-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
-
-MACHINE_START(AT91SAM9G20EK_2MMC, "Atmel AT91SAM9G20-EK 2 MMC Slot Mod")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9m10g45ek.c b/arch/arm/mach-at91/board-sam9m10g45ek.c
deleted file mode 100644
index a517c7f..0000000
--- a/arch/arm/mach-at91/board-sam9m10g45ek.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Board-specific setup code for the AT91SAM9M10G45 Evaluation Kit family
- *
- * Covers: * AT91SAM9G45-EKES board
- * * AT91SAM9M10G45-EK board
- *
- * Copyright (C) 2009 Atmel Corporation.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/fb.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/leds.h>
-#include <linux/atmel-mci.h>
-#include <linux/delay.h>
-#include <linux/pwm.h>
-#include <linux/leds_pwm.h>
-
-#include <linux/platform_data/at91_adc.h>
-
-#include <mach/hardware.h>
-#include <video/atmel_lcdc.h>
-#include <media/soc_camera.h>
-#include <media/atmel-isi.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/at91sam9_smc.h>
-#include <mach/system_rev.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 12.000 MHz crystal */
- at91_initialize(12000000);
-}
-
-/*
- * USB HS Host port (common to OHCI & EHCI)
- */
-static struct at91_usbh_data __initdata ek_usbh_hs_data = {
- .ports = 2,
- .vbus_pin = {AT91_PIN_PD1, AT91_PIN_PD3},
- .vbus_pin_active_low = {1, 1},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-
-/*
- * USB HS Device port
- */
-static struct usba_platform_data __initdata ek_usba_udc_data = {
- .vbus_pin = AT91_PIN_PB19,
-};
-
-
-/*
- * SPI devices.
- */
-static struct spi_board_info ek_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PD10,
- .wp_pin = -EINVAL,
- },
-};
-
-static struct mci_platform_data __initdata mci1_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PD11,
- .wp_pin = AT91_PIN_PD29,
- },
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata ek_macb_data = {
- .phy_irq_pin = AT91_PIN_PD5,
- .is_rmii = 1,
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Partition 1",
- .offset = 0,
- .size = SZ_64M,
- },
- {
- .name = "Partition 2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-/* det_pin is not connected */
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC8,
- .enable_pin = AT91_PIN_PC14,
- .det_pin = -EINVAL,
- .ecc_mode = NAND_ECC_SOFT,
- .on_flash_bbt = 1,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 2,
- .ncs_write_setup = 0,
- .nwe_setup = 2,
-
- .ncs_read_pulse = 4,
- .nrd_pulse = 4,
- .ncs_write_pulse = 4,
- .nwe_pulse = 4,
-
- .read_cycle = 7,
- .write_cycle = 7,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE,
- .tdf_cycles = 3,
-};
-
-static void __init ek_add_device_nand(void)
-{
- ek_nand_data.bus_width_16 = board_have_nand_16bit();
- /* setup bus-width (8 or 16) */
- if (ek_nand_data.bus_width_16)
- ek_nand_smc_config.mode |= AT91_SMC_DBW_16;
- else
- ek_nand_smc_config.mode |= AT91_SMC_DBW_8;
-
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * ISI
- */
-static struct isi_platform_data __initdata isi_data = {
- .frate = ISI_CFG1_FRATE_CAPTURE_ALL,
- /* to use codec and preview path simultaneously */
- .full_mode = 1,
- .data_width_flags = ISI_DATAWIDTH_8 | ISI_DATAWIDTH_10,
- /* ISI_MCK is provided by programmable clock or external clock */
- .mck_hz = 25000000,
-};
-
-
-/*
- * soc-camera OV2640
- */
-#if defined(CONFIG_SOC_CAMERA_OV2640) || \
- defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
-static unsigned long isi_camera_query_bus_param(struct soc_camera_link *link)
-{
- /* ISI board for ek using default 8-bits connection */
- return SOCAM_DATAWIDTH_8;
-}
-
-static int i2c_camera_power(struct device *dev, int on)
-{
- /* enable or disable the camera */
- pr_debug("%s: %s the camera\n", __func__, on ? "ENABLE" : "DISABLE");
- at91_set_gpio_output(AT91_PIN_PD13, !on);
-
- if (!on)
- goto out;
-
- /* If enabled, give a reset impulse */
- at91_set_gpio_output(AT91_PIN_PD12, 0);
- msleep(20);
- at91_set_gpio_output(AT91_PIN_PD12, 1);
- msleep(100);
-
-out:
- return 0;
-}
-
-static struct i2c_board_info i2c_camera = {
- I2C_BOARD_INFO("ov2640", 0x30),
-};
-
-static struct soc_camera_link iclink_ov2640 = {
- .bus_id = 0,
- .board_info = &i2c_camera,
- .i2c_adapter_id = 0,
- .power = i2c_camera_power,
- .query_bus_param = isi_camera_query_bus_param,
-};
-
-static struct platform_device isi_ov2640 = {
- .name = "soc-camera-pdrv",
- .id = 0,
- .dev = {
- .platform_data = &iclink_ov2640,
- },
-};
-#endif
-
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static struct fb_videomode at91_tft_vga_modes[] = {
- {
- .name = "LG",
- .refresh = 60,
- .xres = 480, .yres = 272,
- .pixclock = KHZ2PICOS(9000),
-
- .left_margin = 1, .right_margin = 1,
- .upper_margin = 40, .lower_margin = 1,
- .hsync_len = 45, .vsync_len = 1,
-
- .sync = 0,
- .vmode = FB_VMODE_NONINTERLACED,
- },
-};
-
-static struct fb_monspecs at91fb_default_monspecs = {
- .manufacturer = "LG",
- .monitor = "LB043WQ1",
-
- .modedb = at91_tft_vga_modes,
- .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
- .hfmin = 15000,
- .hfmax = 17640,
- .vfmin = 57,
- .vfmax = 67,
-};
-
-#define AT91SAM9G45_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
- | ATMEL_LCDC_DISTYPE_TFT \
- | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-/* Driver datas */
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
- .lcdcon_is_backlight = true,
- .default_bpp = 32,
- .default_dmacon = ATMEL_LCDC_DMAEN,
- .default_lcdcon2 = AT91SAM9G45_DEFAULT_LCDCON2,
- .default_monspecs = &at91fb_default_monspecs,
- .guard_time = 9,
- .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
-};
-
-#else
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
-#endif
-
-
-/*
- * ADCs and touchscreen
- */
-static struct at91_adc_data ek_adc_data = {
- .channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) | BIT(6) | BIT(7),
- .use_external_triggers = true,
- .vref = 3300,
- .touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE,
-};
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ek_buttons[] = {
- { /* BP1, "leftclic" */
- .code = BTN_LEFT,
- .gpio = AT91_PIN_PB6,
- .active_low = 1,
- .desc = "left_click",
- .wakeup = 1,
- },
- { /* BP2, "rightclic" */
- .code = BTN_RIGHT,
- .gpio = AT91_PIN_PB7,
- .active_low = 1,
- .desc = "right_click",
- .wakeup = 1,
- },
- /* BP3, "joystick" */
- {
- .code = KEY_LEFT,
- .gpio = AT91_PIN_PB14,
- .active_low = 1,
- .desc = "Joystick Left",
- },
- {
- .code = KEY_RIGHT,
- .gpio = AT91_PIN_PB15,
- .active_low = 1,
- .desc = "Joystick Right",
- },
- {
- .code = KEY_UP,
- .gpio = AT91_PIN_PB16,
- .active_low = 1,
- .desc = "Joystick Up",
- },
- {
- .code = KEY_DOWN,
- .gpio = AT91_PIN_PB17,
- .active_low = 1,
- .desc = "Joystick Down",
- },
- {
- .code = KEY_ENTER,
- .gpio = AT91_PIN_PB18,
- .active_low = 1,
- .desc = "Joystick Press",
- },
-};
-
-static struct gpio_keys_platform_data ek_button_data = {
- .buttons = ek_buttons,
- .nbuttons = ARRAY_SIZE(ek_buttons),
-};
-
-static struct platform_device ek_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_button_data,
- }
-};
-
-static void __init ek_add_device_buttons(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ek_buttons); i++) {
- at91_set_GPIO_periph(ek_buttons[i].gpio, 1);
- at91_set_deglitch(ek_buttons[i].gpio, 1);
- }
-
- platform_device_register(&ek_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-
-/*
- * AC97
- * reset_pin is not connected: NRST
- */
-static struct ac97c_platform_data ek_ac97_data = {
- .reset_pin = -EINVAL,
-};
-
-
-/*
- * LEDs ... these could all be PWM-driven, for variable brightness
- */
-static struct gpio_led ek_leds[] = {
- { /* "top" led, red, powerled */
- .name = "d8",
- .gpio = AT91_PIN_PD30,
- .default_trigger = "heartbeat",
- },
- { /* "left" led, green, userled2, pwm3 */
- .name = "d6",
- .gpio = AT91_PIN_PD0,
- .active_low = 1,
- .default_trigger = "nand-disk",
- },
-#if !IS_ENABLED(CONFIG_LEDS_PWM)
- { /* "right" led, green, userled1, pwm1 */
- .name = "d7",
- .gpio = AT91_PIN_PD31,
- .active_low = 1,
- .default_trigger = "mmc0",
- },
-#endif
-};
-
-
-/*
- * PWM Leds
- */
-static struct pwm_lookup pwm_lookup[] = {
- PWM_LOOKUP("at91sam9rl-pwm", 1, "leds_pwm", "d7",
- 5000, PWM_POLARITY_INVERSED),
-};
-
-#if IS_ENABLED(CONFIG_LEDS_PWM)
-static struct led_pwm pwm_leds[] = {
- { /* "right" led, green, userled1, pwm1 */
- .name = "d7",
- .max_brightness = 255,
- },
-};
-
-static struct led_pwm_platform_data pwm_data = {
- .num_leds = ARRAY_SIZE(pwm_leds),
- .leds = pwm_leds,
-};
-
-static struct platform_device leds_pwm = {
- .name = "leds_pwm",
- .id = -1,
- .dev = {
- .platform_data = &pwm_data,
- },
-};
-#endif
-
-static struct platform_device *devices[] __initdata = {
-#if defined(CONFIG_SOC_CAMERA_OV2640) || \
- defined(CONFIG_SOC_CAMERA_OV2640_MODULE)
- &isi_ov2640,
-#endif
-#if IS_ENABLED(CONFIG_LEDS_PWM)
- &leds_pwm,
-#endif
-};
-
-static void __init ek_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 not connected on the -EK board */
- /* USART1 on ttyS2. (Rx, Tx, RTS, CTS) */
- at91_register_uart(AT91SAM9G45_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB HS Host */
- at91_add_device_usbh_ohci(&ek_usbh_hs_data);
- at91_add_device_usbh_ehci(&ek_usbh_hs_data);
- /* USB HS Device */
- at91_add_device_usba(&ek_usba_udc_data);
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* MMC */
- at91_add_device_mci(0, &mci0_data);
- at91_add_device_mci(1, &mci1_data);
- /* Ethernet */
- at91_add_device_eth(&ek_macb_data);
- /* NAND */
- ek_add_device_nand();
- /* I2C */
- at91_add_device_i2c(0, NULL, 0);
- /* ISI, using programmable clock as ISI_MCK */
- at91_add_device_isi(&isi_data, true);
- /* LCD Controller */
- at91_add_device_lcdc(&ek_lcdc_data);
- /* ADC and touchscreen */
- at91_add_device_adc(&ek_adc_data);
- /* Push Buttons */
- ek_add_device_buttons();
- /* AC97 */
- at91_add_device_ac97(&ek_ac97_data);
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
- pwm_add_table(pwm_lookup, ARRAY_SIZE(pwm_lookup));
-#if IS_ENABLED(CONFIG_LEDS_PWM)
- at91_add_device_pwm(1 << AT91_PWM1);
-#endif
- /* Other platform devices */
- platform_add_devices(devices, ARRAY_SIZE(devices));
-}
-
-MACHINE_START(AT91SAM9M10G45EK, "Atmel AT91SAM9M10G45-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-sam9rlek.c b/arch/arm/mach-at91/board-sam9rlek.c
deleted file mode 100644
index 8bca329..0000000
--- a/arch/arm/mach-at91/board-sam9rlek.c
+++ /dev/null
@@ -1,333 +0,0 @@
-/*
- * Copyright (C) 2005 SAN People
- * Copyright (C) 2007 Atmel Corporation
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive for
- * more details.
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/fb.h>
-#include <linux/clk.h>
-#include <linux/input.h>
-#include <linux/gpio_keys.h>
-#include <linux/platform_data/at91_adc.h>
-
-#include <video/atmel_lcdc.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init ek_init_early(void)
-{
- /* Initialize processor: 12.000 MHz crystal */
- at91_initialize(12000000);
-}
-
-/*
- * USB HS Device port
- */
-static struct usba_platform_data __initdata ek_usba_udc_data = {
- .vbus_pin = AT91_PIN_PA8,
-};
-
-
-/*
- * MCI (SD/MMC)
- */
-static struct mci_platform_data __initdata mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PA15,
- .wp_pin = -EINVAL,
- },
-};
-
-
-/*
- * NAND flash
- */
-static struct mtd_partition __initdata ek_nand_partition[] = {
- {
- .name = "Partition 1",
- .offset = 0,
- .size = SZ_256K,
- },
- {
- .name = "Partition 2",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata ek_nand_data = {
- .ale = 21,
- .cle = 22,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PD17,
- .enable_pin = AT91_PIN_PB6,
- .ecc_mode = NAND_ECC_SOFT,
- .on_flash_bbt = 1,
- .parts = ek_nand_partition,
- .num_parts = ARRAY_SIZE(ek_nand_partition),
-};
-
-static struct sam9_smc_config __initdata ek_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 1,
- .ncs_write_setup = 0,
- .nwe_setup = 1,
-
- .ncs_read_pulse = 3,
- .nrd_pulse = 3,
- .ncs_write_pulse = 3,
- .nwe_pulse = 3,
-
- .read_cycle = 5,
- .write_cycle = 5,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 2,
-};
-
-static void __init ek_add_device_nand(void)
-{
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &ek_nand_smc_config);
-
- at91_add_device_nand(&ek_nand_data);
-}
-
-
-/*
- * SPI devices
- */
-static struct spi_board_info ek_spi_devices[] = {
- { /* DataFlash chip */
- .modalias = "mtd_dataflash",
- .chip_select = 0,
- .max_speed_hz = 15 * 1000 * 1000,
- .bus_num = 0,
- },
-};
-
-
-/*
- * LCD Controller
- */
-#if defined(CONFIG_FB_ATMEL) || defined(CONFIG_FB_ATMEL_MODULE)
-static struct fb_videomode at91_tft_vga_modes[] = {
- {
- .name = "TX09D50VM1CCA @ 60",
- .refresh = 60,
- .xres = 240, .yres = 320,
- .pixclock = KHZ2PICOS(4965),
-
- .left_margin = 1, .right_margin = 33,
- .upper_margin = 1, .lower_margin = 0,
- .hsync_len = 5, .vsync_len = 1,
-
- .sync = FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT,
- .vmode = FB_VMODE_NONINTERLACED,
- },
-};
-
-static struct fb_monspecs at91fb_default_monspecs = {
- .manufacturer = "HIT",
- .monitor = "TX09D50VM1CCA",
-
- .modedb = at91_tft_vga_modes,
- .modedb_len = ARRAY_SIZE(at91_tft_vga_modes),
- .hfmin = 15000,
- .hfmax = 64000,
- .vfmin = 50,
- .vfmax = 150,
-};
-
-#define AT91SAM9RL_DEFAULT_LCDCON2 (ATMEL_LCDC_MEMOR_LITTLE \
- | ATMEL_LCDC_DISTYPE_TFT \
- | ATMEL_LCDC_CLKMOD_ALWAYSACTIVE)
-
-static void at91_lcdc_power_control(struct atmel_lcdfb_pdata *pdata, int on)
-{
- if (on)
- at91_set_gpio_value(AT91_PIN_PC1, 0); /* power up */
- else
- at91_set_gpio_value(AT91_PIN_PC1, 1); /* power down */
-}
-
-/* Driver datas */
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data = {
- .lcdcon_is_backlight = true,
- .default_bpp = 16,
- .default_dmacon = ATMEL_LCDC_DMAEN,
- .default_lcdcon2 = AT91SAM9RL_DEFAULT_LCDCON2,
- .default_monspecs = &at91fb_default_monspecs,
- .atmel_lcdfb_power_control = at91_lcdc_power_control,
- .guard_time = 1,
- .lcd_wiring_mode = ATMEL_LCDC_WIRING_RGB,
-};
-
-#else
-static struct atmel_lcdfb_pdata __initdata ek_lcdc_data;
-#endif
-
-
-/*
- * AC97
- * reset_pin is not connected: NRST
- */
-static struct ac97c_platform_data ek_ac97_data = {
- .reset_pin = -EINVAL,
-};
-
-
-/*
- * LEDs
- */
-static struct gpio_led ek_leds[] = {
- { /* "bottom" led, green, userled1 to be defined */
- .name = "ds1",
- .gpio = AT91_PIN_PD15,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* "bottom" led, green, userled2 to be defined */
- .name = "ds2",
- .gpio = AT91_PIN_PD16,
- .active_low = 1,
- .default_trigger = "none",
- },
- { /* "power" led, yellow */
- .name = "ds3",
- .gpio = AT91_PIN_PD14,
- .default_trigger = "heartbeat",
- }
-};
-
-
-/*
- * ADC + Touchscreen
- */
-static struct at91_adc_data ek_adc_data = {
- .channels_used = BIT(0) | BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5),
- .use_external_triggers = true,
- .vref = 3300,
- .touchscreen_type = ATMEL_ADC_TOUCHSCREEN_4WIRE,
-};
-
-
-/*
- * GPIO Buttons
- */
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button ek_buttons[] = {
- {
- .gpio = AT91_PIN_PB0,
- .code = BTN_2,
- .desc = "Right Click",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PB1,
- .code = BTN_1,
- .desc = "Left Click",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data ek_button_data = {
- .buttons = ek_buttons,
- .nbuttons = ARRAY_SIZE(ek_buttons),
-};
-
-static struct platform_device ek_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &ek_button_data,
- }
-};
-
-static void __init ek_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PB1, 1); /* btn1 */
- at91_set_deglitch(AT91_PIN_PB1, 1);
- at91_set_gpio_input(AT91_PIN_PB0, 1); /* btn2 */
- at91_set_deglitch(AT91_PIN_PB0, 1);
-
- platform_device_register(&ek_button_device);
-}
-#else
-static void __init ek_add_device_buttons(void) {}
-#endif
-
-
-static void __init ek_board_init(void)
-{
- at91_register_devices();
-
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9RL_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_add_device_serial();
- /* USB HS */
- at91_add_device_usba(&ek_usba_udc_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* NAND */
- ek_add_device_nand();
- /* SPI */
- at91_add_device_spi(ek_spi_devices, ARRAY_SIZE(ek_spi_devices));
- /* MMC */
- at91_add_device_mci(0, &mci0_data);
- /* LCD Controller */
- at91_add_device_lcdc(&ek_lcdc_data);
- /* AC97 */
- at91_add_device_ac97(&ek_ac97_data);
- /* Touch Screen Controller + ADC */
- at91_add_device_adc(&ek_adc_data);
- /* LEDs */
- at91_gpio_leds(ek_leds, ARRAY_SIZE(ek_leds));
- /* Push Buttons */
- ek_add_device_buttons();
-}
-
-MACHINE_START(AT91SAM9RLEK, "Atmel AT91SAM9RL-EK")
- /* Maintainer: Atmel */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = ek_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = ek_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-snapper9260.c b/arch/arm/mach-at91/board-snapper9260.c
deleted file mode 100644
index b4aff84..0000000
--- a/arch/arm/mach-at91/board-snapper9260.c
+++ /dev/null
@@ -1,191 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-snapper9260.c
- *
- * Copyright (C) 2010 Bluewater System Ltd
- *
- * Author: Andre Renaud <andre@bluewatersys.com>
- * Author: Ryan Mallon
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/gpio.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/platform_data/pca953x.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <mach/hardware.h>
-#include <mach/at91sam9_smc.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-#define SNAPPER9260_IO_EXP_GPIO(x) (NR_BUILTIN_GPIO + (x))
-
-static void __init snapper9260_init_early(void)
-{
- at91_initialize(18432000);
-}
-
-static struct at91_usbh_data __initdata snapper9260_usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-static struct at91_udc_data __initdata snapper9260_udc_data = {
- .vbus_pin = SNAPPER9260_IO_EXP_GPIO(5),
- .vbus_active_low = 1,
- .vbus_polled = 1,
- .pullup_pin = -EINVAL,
-};
-
-static struct macb_platform_data snapper9260_macb_data = {
- .phy_irq_pin = -EINVAL,
- .is_rmii = 1,
-};
-
-static struct mtd_partition __initdata snapper9260_nand_partitions[] = {
- {
- .name = "Preboot",
- .offset = 0,
- .size = SZ_128K,
- },
- {
- .name = "Bootloader",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_256K,
- },
- {
- .name = "Environment",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_128K,
- },
- {
- .name = "Kernel",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_4M,
- },
- {
- .name = "Filesystem",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct atmel_nand_data __initdata snapper9260_nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC13,
- .parts = snapper9260_nand_partitions,
- .num_parts = ARRAY_SIZE(snapper9260_nand_partitions),
- .bus_width_16 = 0,
- .enable_pin = -EINVAL,
- .det_pin = -EINVAL,
- .ecc_mode = NAND_ECC_SOFT,
-};
-
-static struct sam9_smc_config __initdata snapper9260_nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 0,
- .ncs_write_setup = 0,
- .nwe_setup = 0,
-
- .ncs_read_pulse = 5,
- .nrd_pulse = 2,
- .ncs_write_pulse = 5,
- .nwe_pulse = 2,
-
- .read_cycle = 7,
- .write_cycle = 7,
-
- .mode = (AT91_SMC_READMODE | AT91_SMC_WRITEMODE |
- AT91_SMC_EXNWMODE_DISABLE),
- .tdf_cycles = 1,
-};
-
-static struct pca953x_platform_data snapper9260_io_expander_data = {
- .gpio_base = SNAPPER9260_IO_EXP_GPIO(0),
-};
-
-static struct i2c_board_info __initdata snapper9260_i2c_devices[] = {
- {
- /* IO expander */
- I2C_BOARD_INFO("max7312", 0x28),
- .platform_data = &snapper9260_io_expander_data,
- },
- {
- /* Audio codec */
- I2C_BOARD_INFO("tlv320aic23", 0x1a),
- },
-};
-
-static struct i2c_board_info __initdata snapper9260_i2c_isl1208 = {
- /* RTC */
- I2C_BOARD_INFO("isl1208", 0x6f),
-};
-
-static void __init snapper9260_add_device_nand(void)
-{
- at91_set_A_periph(AT91_PIN_PC14, 0);
- sam9_smc_configure(0, 3, &snapper9260_nand_smc_config);
- at91_add_device_nand(&snapper9260_nand_data);
-}
-
-static void __init snapper9260_board_init(void)
-{
- at91_register_devices();
-
- at91_add_device_i2c(snapper9260_i2c_devices,
- ARRAY_SIZE(snapper9260_i2c_devices));
-
- snapper9260_i2c_isl1208.irq = gpio_to_irq(AT91_PIN_PA31);
- i2c_register_board_info(0, &snapper9260_i2c_isl1208, 1);
-
- /* Debug on ttyS0 */
- at91_register_uart(0, 0, 0);
-
- at91_register_uart(AT91SAM9260_ID_US0, 1,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_register_uart(AT91SAM9260_ID_US1, 2,
- ATMEL_UART_CTS | ATMEL_UART_RTS);
- at91_register_uart(AT91SAM9260_ID_US2, 3, 0);
- at91_add_device_serial();
- at91_add_device_usbh(&snapper9260_usbh_data);
- at91_add_device_udc(&snapper9260_udc_data);
- at91_add_device_eth(&snapper9260_macb_data);
- at91_add_device_ssc(AT91SAM9260_ID_SSC, (ATMEL_SSC_TF | ATMEL_SSC_TK |
- ATMEL_SSC_TD | ATMEL_SSC_RD));
- snapper9260_add_device_nand();
-}
-
-MACHINE_START(SNAPPER_9260, "Bluewater Systems Snapper 9260/9G20 module")
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = snapper9260_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = snapper9260_board_init,
-MACHINE_END
-
-
diff --git a/arch/arm/mach-at91/board-stamp9g20.c b/arch/arm/mach-at91/board-stamp9g20.c
deleted file mode 100644
index e825641..0000000
--- a/arch/arm/mach-at91/board-stamp9g20.c
+++ /dev/null
@@ -1,294 +0,0 @@
-/*
- * Copyright (C) 2010 Christian Glindkamp <christian.glindkamp@taskit.de>
- * taskit GmbH
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/mm.h>
-#include <linux/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/w1-gpio.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include <mach/at91sam9_smc.h>
-#include <mach/hardware.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "sam9_smc.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-void __init stamp9g20_init_early(void)
-{
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * NAND flash
- */
-static struct atmel_nand_data __initdata nand_data = {
- .ale = 21,
- .cle = 22,
- .rdy_pin = AT91_PIN_PC13,
- .enable_pin = AT91_PIN_PC14,
- .bus_width_16 = 0,
- .det_pin = -EINVAL,
- .ecc_mode = NAND_ECC_SOFT,
-};
-
-static struct sam9_smc_config __initdata nand_smc_config = {
- .ncs_read_setup = 0,
- .nrd_setup = 2,
- .ncs_write_setup = 0,
- .nwe_setup = 2,
-
- .ncs_read_pulse = 4,
- .nrd_pulse = 4,
- .ncs_write_pulse = 4,
- .nwe_pulse = 4,
-
- .read_cycle = 7,
- .write_cycle = 7,
-
- .mode = AT91_SMC_READMODE | AT91_SMC_WRITEMODE | AT91_SMC_EXNWMODE_DISABLE | AT91_SMC_DBW_8,
- .tdf_cycles = 3,
-};
-
-static void __init add_device_nand(void)
-{
- /* configure chip-select 3 (NAND) */
- sam9_smc_configure(0, 3, &nand_smc_config);
-
- at91_add_device_nand(&nand_data);
-}
-
-
-/*
- * MCI (SD/MMC)
- * det_pin, wp_pin and vcc_pin are not connected
- */
-static struct mci_platform_data __initdata mmc_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = -1,
- .wp_pin = -1,
- },
-};
-
-
-/*
- * USB Host port
- */
-static struct at91_usbh_data __initdata usbh_data = {
- .ports = 2,
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-
-/*
- * USB Device port
- */
-static struct at91_udc_data __initdata portuxg20_udc_data = {
- .vbus_pin = AT91_PIN_PC7,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-static struct at91_udc_data __initdata stamp9g20evb_udc_data = {
- .vbus_pin = AT91_PIN_PA22,
- .pullup_pin = -EINVAL, /* pull-up driven by UDC */
-};
-
-
-/*
- * MACB Ethernet device
- */
-static struct macb_platform_data __initdata macb_data = {
- .phy_irq_pin = AT91_PIN_PA28,
- .is_rmii = 1,
-};
-
-
-/*
- * LEDs
- */
-static struct gpio_led portuxg20_leds[] = {
- {
- .name = "LED2",
- .gpio = AT91_PIN_PC5,
- .default_trigger = "none",
- }, {
- .name = "LED3",
- .gpio = AT91_PIN_PC4,
- .default_trigger = "none",
- }, {
- .name = "LED4",
- .gpio = AT91_PIN_PC10,
- .default_trigger = "heartbeat",
- }
-};
-
-static struct gpio_led stamp9g20evb_leds[] = {
- {
- .name = "D8",
- .gpio = AT91_PIN_PB18,
- .active_low = 1,
- .default_trigger = "none",
- }, {
- .name = "D9",
- .gpio = AT91_PIN_PB19,
- .active_low = 1,
- .default_trigger = "none",
- }, {
- .name = "D10",
- .gpio = AT91_PIN_PB20,
- .active_low = 1,
- .default_trigger = "heartbeat",
- }
-};
-
-
-/*
- * SPI devices
- */
-static struct spi_board_info portuxg20_spi_devices[] = {
- {
- .modalias = "spidev",
- .chip_select = 0,
- .max_speed_hz = 1 * 1000 * 1000,
- .bus_num = 0,
- }, {
- .modalias = "spidev",
- .chip_select = 0,
- .max_speed_hz = 1 * 1000 * 1000,
- .bus_num = 1,
- },
-};
-
-
-/*
- * Dallas 1-Wire
- */
-static struct w1_gpio_platform_data w1_gpio_pdata = {
- .pin = AT91_PIN_PA29,
- .is_open_drain = 1,
- .ext_pullup_enable_pin = -EINVAL,
-};
-
-static struct platform_device w1_device = {
- .name = "w1-gpio",
- .id = -1,
- .dev.platform_data = &w1_gpio_pdata,
-};
-
-void add_w1(void)
-{
- at91_set_GPIO_periph(w1_gpio_pdata.pin, 1);
- at91_set_multi_drive(w1_gpio_pdata.pin, 1);
- platform_device_register(&w1_device);
-}
-
-
-void __init stamp9g20_board_init(void)
-{
- /* Serial */
- /* DGBU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
- at91_add_device_serial();
- /* NAND */
- add_device_nand();
- /* MMC */
- at91_add_device_mci(0, &mmc_data);
- /* W1 */
- add_w1();
-}
-
-static void __init portuxg20_board_init(void)
-{
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
-
- /* USART1 on ttyS2. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US1, 2, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART2 on ttyS3. (Rx, Tx, CTS, RTS) */
- at91_register_uart(AT91SAM9260_ID_US2, 3, ATMEL_UART_CTS | ATMEL_UART_RTS);
-
- /* USART4 on ttyS5. (Rx, Tx only) */
- at91_register_uart(AT91SAM9260_ID_US4, 5, 0);
-
- /* USART5 on ttyS6. (Rx, Tx only) */
- at91_register_uart(AT91SAM9260_ID_US5, 6, 0);
- stamp9g20_board_init();
- /* USB Host */
- at91_add_device_usbh(&usbh_data);
- /* USB Device */
- at91_add_device_udc(&portuxg20_udc_data);
- /* Ethernet */
- at91_add_device_eth(&macb_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* SPI */
- at91_add_device_spi(portuxg20_spi_devices, ARRAY_SIZE(portuxg20_spi_devices));
- /* LEDs */
- at91_gpio_leds(portuxg20_leds, ARRAY_SIZE(portuxg20_leds));
-}
-
-static void __init stamp9g20evb_board_init(void)
-{
- /* USART0 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91SAM9260_ID_US0, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR
- | ATMEL_UART_DCD | ATMEL_UART_RI);
- stamp9g20_board_init();
- /* USB Host */
- at91_add_device_usbh(&usbh_data);
- /* USB Device */
- at91_add_device_udc(&stamp9g20evb_udc_data);
- /* Ethernet */
- at91_add_device_eth(&macb_data);
- /* I2C */
- at91_add_device_i2c(NULL, 0);
- /* LEDs */
- at91_gpio_leds(stamp9g20evb_leds, ARRAY_SIZE(stamp9g20evb_leds));
-}
-
-MACHINE_START(PORTUXG20, "taskit PortuxG20")
- /* Maintainer: taskit GmbH */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = stamp9g20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = portuxg20_board_init,
-MACHINE_END
-
-MACHINE_START(STAMP9G20, "taskit Stamp9G20")
- /* Maintainer: taskit GmbH */
- .init_time = at91_init_time,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = stamp9g20_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = stamp9g20evb_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board-yl-9200.c b/arch/arm/mach-at91/board-yl-9200.c
deleted file mode 100644
index 46fdb0c..0000000
--- a/arch/arm/mach-at91/board-yl-9200.c
+++ /dev/null
@@ -1,597 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/board-yl-9200.c
- *
- * Adapted from various board files in arch/arm/mach-at91
- *
- * Modifications for YL-9200 platform:
- * Copyright (C) 2007 S. Birtles
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/types.h>
-#include <linux/gpio.h>
-#include <linux/init.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/spi/spi.h>
-#include <linux/spi/ads7846.h>
-#include <linux/mtd/physmap.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-
-#include <asm/setup.h>
-#include <asm/mach-types.h>
-#include <asm/irq.h>
-
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/irq.h>
-
-#include <mach/hardware.h>
-#include <mach/at91rm9200_mc.h>
-#include <mach/at91_ramc.h>
-#include <mach/cpu.h>
-
-#include "at91_aic.h"
-#include "board.h"
-#include "generic.h"
-#include "gpio.h"
-
-
-static void __init yl9200_init_early(void)
-{
- /* Set cpu type: PQFP */
- at91rm9200_set_type(ARCH_REVISON_9200_PQFP);
-
- /* Initialize processor: 18.432 MHz crystal */
- at91_initialize(18432000);
-}
-
-/*
- * LEDs
- */
-static struct gpio_led yl9200_leds[] = {
- { /* D2 */
- .name = "led2",
- .gpio = AT91_PIN_PB17,
- .active_low = 1,
- .default_trigger = "timer",
- },
- { /* D3 */
- .name = "led3",
- .gpio = AT91_PIN_PB16,
- .active_low = 1,
- .default_trigger = "heartbeat",
- },
- { /* D4 */
- .name = "led4",
- .gpio = AT91_PIN_PB15,
- .active_low = 1,
- },
- { /* D5 */
- .name = "led5",
- .gpio = AT91_PIN_PB8,
- .active_low = 1,
- }
-};
-
-/*
- * Ethernet
- */
-static struct macb_platform_data __initdata yl9200_eth_data = {
- .phy_irq_pin = AT91_PIN_PB28,
- .is_rmii = 1,
-};
-
-/*
- * USB Host
- */
-static struct at91_usbh_data __initdata yl9200_usbh_data = {
- .ports = 1, /* PQFP version of AT91RM9200 */
- .vbus_pin = {-EINVAL, -EINVAL},
- .overcurrent_pin= {-EINVAL, -EINVAL},
-};
-
-/*
- * USB Device
- */
-static struct at91_udc_data __initdata yl9200_udc_data = {
- .pullup_pin = AT91_PIN_PC4,
- .vbus_pin = AT91_PIN_PC5,
- .pullup_active_low = 1, /* Active Low due to PNP transistor (pg 7) */
-
-};
-
-/*
- * MMC
- */
-static struct mci_platform_data __initdata yl9200_mci0_data = {
- .slot[0] = {
- .bus_width = 4,
- .detect_pin = AT91_PIN_PB9,
- .wp_pin = -EINVAL,
- },
-};
-
-/*
- * NAND Flash
- */
-static struct mtd_partition __initdata yl9200_nand_partition[] = {
- {
- .name = "AT91 NAND partition 1, boot",
- .offset = 0,
- .size = SZ_256K
- },
- {
- .name = "AT91 NAND partition 2, kernel",
- .offset = MTDPART_OFS_NXTBLK,
- .size = (2 * SZ_1M) - SZ_256K
- },
- {
- .name = "AT91 NAND partition 3, filesystem",
- .offset = MTDPART_OFS_NXTBLK,
- .size = 14 * SZ_1M
- },
- {
- .name = "AT91 NAND partition 4, storage",
- .offset = MTDPART_OFS_NXTBLK,
- .size = SZ_16M
- },
- {
- .name = "AT91 NAND partition 5, ext-fs",
- .offset = MTDPART_OFS_NXTBLK,
- .size = SZ_32M
- }
-};
-
-static struct atmel_nand_data __initdata yl9200_nand_data = {
- .ale = 6,
- .cle = 7,
- .det_pin = -EINVAL,
- .rdy_pin = AT91_PIN_PC14, /* R/!B (Sheet10) */
- .enable_pin = AT91_PIN_PC15, /* !CE (Sheet10) */
- .ecc_mode = NAND_ECC_SOFT,
- .parts = yl9200_nand_partition,
- .num_parts = ARRAY_SIZE(yl9200_nand_partition),
-};
-
-/*
- * NOR Flash
- */
-#define YL9200_FLASH_BASE AT91_CHIPSELECT_0
-#define YL9200_FLASH_SIZE SZ_16M
-
-static struct mtd_partition yl9200_flash_partitions[] = {
- {
- .name = "Bootloader",
- .offset = 0,
- .size = SZ_256K,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "Kernel",
- .offset = MTDPART_OFS_NXTBLK,
- .size = (2 * SZ_1M) - SZ_256K
- },
- {
- .name = "Filesystem",
- .offset = MTDPART_OFS_NXTBLK,
- .size = MTDPART_SIZ_FULL
- }
-};
-
-static struct physmap_flash_data yl9200_flash_data = {
- .width = 2,
- .parts = yl9200_flash_partitions,
- .nr_parts = ARRAY_SIZE(yl9200_flash_partitions),
-};
-
-static struct resource yl9200_flash_resources[] = {
- {
- .start = YL9200_FLASH_BASE,
- .end = YL9200_FLASH_BASE + YL9200_FLASH_SIZE - 1,
- .flags = IORESOURCE_MEM,
- }
-};
-
-static struct platform_device yl9200_flash = {
- .name = "physmap-flash",
- .id = 0,
- .dev = {
- .platform_data = &yl9200_flash_data,
- },
- .resource = yl9200_flash_resources,
- .num_resources = ARRAY_SIZE(yl9200_flash_resources),
-};
-
-/*
- * I2C (TWI)
- */
-static struct i2c_board_info __initdata yl9200_i2c_devices[] = {
- { /* EEPROM */
- I2C_BOARD_INFO("24c128", 0x50),
- }
-};
-
-/*
- * GPIO Buttons
-*/
-#if defined(CONFIG_KEYBOARD_GPIO) || defined(CONFIG_KEYBOARD_GPIO_MODULE)
-static struct gpio_keys_button yl9200_buttons[] = {
- {
- .gpio = AT91_PIN_PA24,
- .code = BTN_2,
- .desc = "SW2",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PB1,
- .code = BTN_3,
- .desc = "SW3",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PB2,
- .code = BTN_4,
- .desc = "SW4",
- .active_low = 1,
- .wakeup = 1,
- },
- {
- .gpio = AT91_PIN_PB6,
- .code = BTN_5,
- .desc = "SW5",
- .active_low = 1,
- .wakeup = 1,
- }
-};
-
-static struct gpio_keys_platform_data yl9200_button_data = {
- .buttons = yl9200_buttons,
- .nbuttons = ARRAY_SIZE(yl9200_buttons),
-};
-
-static struct platform_device yl9200_button_device = {
- .name = "gpio-keys",
- .id = -1,
- .num_resources = 0,
- .dev = {
- .platform_data = &yl9200_button_data,
- }
-};
-
-static void __init yl9200_add_device_buttons(void)
-{
- at91_set_gpio_input(AT91_PIN_PA24, 1); /* SW2 */
- at91_set_deglitch(AT91_PIN_PA24, 1);
- at91_set_gpio_input(AT91_PIN_PB1, 1); /* SW3 */
- at91_set_deglitch(AT91_PIN_PB1, 1);
- at91_set_gpio_input(AT91_PIN_PB2, 1); /* SW4 */
- at91_set_deglitch(AT91_PIN_PB2, 1);
- at91_set_gpio_input(AT91_PIN_PB6, 1); /* SW5 */
- at91_set_deglitch(AT91_PIN_PB6, 1);
-
- /* Enable buttons (Sheet 5) */
- at91_set_gpio_output(AT91_PIN_PB7, 1);
-
- platform_device_register(&yl9200_button_device);
-}
-#else
-static void __init yl9200_add_device_buttons(void) {}
-#endif
-
-/*
- * Touchscreen
- */
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
-static int ads7843_pendown_state(void)
-{
- return !at91_get_gpio_value(AT91_PIN_PB11); /* Touchscreen PENIRQ */
-}
-
-static struct ads7846_platform_data ads_info = {
- .model = 7843,
- .x_min = 150,
- .x_max = 3830,
- .y_min = 190,
- .y_max = 3830,
- .vref_delay_usecs = 100,
-
- /* For a 8" touch-screen */
- // .x_plate_ohms = 603,
- // .y_plate_ohms = 332,
-
- /* For a 10.4" touch-screen */
- // .x_plate_ohms = 611,
- // .y_plate_ohms = 325,
-
- .x_plate_ohms = 576,
- .y_plate_ohms = 366,
-
- .pressure_max = 15000, /* generally nonsense on the 7843 */
- .debounce_max = 1,
- .debounce_rep = 0,
- .debounce_tol = (~0),
- .get_pendown_state = ads7843_pendown_state,
-};
-
-static void __init yl9200_add_device_ts(void)
-{
- at91_set_gpio_input(AT91_PIN_PB11, 1); /* Touchscreen interrupt pin */
- at91_set_gpio_input(AT91_PIN_PB10, 1); /* Touchscreen BUSY signal - not used! */
-}
-#else
-static void __init yl9200_add_device_ts(void) {}
-#endif
-
-/*
- * SPI devices
- */
-static struct spi_board_info yl9200_spi_devices[] = {
-#if defined(CONFIG_TOUCHSCREEN_ADS7846) || defined(CONFIG_TOUCHSCREEN_ADS7846_MODULE)
- { /* Touchscreen */
- .modalias = "ads7846",
- .chip_select = 0,
- .max_speed_hz = 5000 * 26,
- .platform_data = &ads_info,
- .irq = AT91_PIN_PB11,
- },
-#endif
- { /* CAN */
- .modalias = "mcp2510",
- .chip_select = 1,
- .max_speed_hz = 25000 * 26,
- .irq = AT91_PIN_PC0,
- }
-};
-
-/*
- * LCD / VGA
- *
- * EPSON S1D13806 FB (discontinued chip)
- * EPSON S1D13506 FB
- */
-#if defined(CONFIG_FB_S1D13XXX) || defined(CONFIG_FB_S1D13XXX_MODULE)
-#include <video/s1d13xxxfb.h>
-
-
-static void yl9200_init_video(void)
-{
- /* NWAIT Signal */
- at91_set_A_periph(AT91_PIN_PC6, 0);
-
- /* Initialization of the Static Memory Controller for Chip Select 2 */
- at91_ramc_write(0, AT91_SMC_CSR(2), AT91_SMC_DBW_16 /* 16 bit */
- | AT91_SMC_WSEN | AT91_SMC_NWS_(0x4) /* wait states */
- | AT91_SMC_TDF_(0x100) /* float time */
- );
-}
-
-static struct s1d13xxxfb_regval yl9200_s1dfb_initregs[] =
-{
- {S1DREG_MISC, 0x00}, /* Miscellaneous Register*/
- {S1DREG_COM_DISP_MODE, 0x01}, /* Display Mode Register, LCD only*/
- {S1DREG_GPIO_CNF0, 0x00}, /* General IO Pins Configuration Register*/
- {S1DREG_GPIO_CTL0, 0x00}, /* General IO Pins Control Register*/
- {S1DREG_CLK_CNF, 0x11}, /* Memory Clock Configuration Register*/
- {S1DREG_LCD_CLK_CNF, 0x10}, /* LCD Pixel Clock Configuration Register*/
- {S1DREG_CRT_CLK_CNF, 0x12}, /* CRT/TV Pixel Clock Configuration Register*/
- {S1DREG_MPLUG_CLK_CNF, 0x01}, /* MediaPlug Clock Configuration Register*/
- {S1DREG_CPU2MEM_WST_SEL, 0x02}, /* CPU To Memory Wait State Select Register*/
- {S1DREG_MEM_CNF, 0x00}, /* Memory Configuration Register*/
- {S1DREG_SDRAM_REF_RATE, 0x04}, /* DRAM Refresh Rate Register, MCLK source*/
- {S1DREG_SDRAM_TC0, 0x12}, /* DRAM Timings Control Register 0*/
- {S1DREG_SDRAM_TC1, 0x02}, /* DRAM Timings Control Register 1*/
- {S1DREG_PANEL_TYPE, 0x25}, /* Panel Type Register*/
- {S1DREG_MOD_RATE, 0x00}, /* MOD Rate Register*/
- {S1DREG_LCD_DISP_HWIDTH, 0x4F}, /* LCD Horizontal Display Width Register*/
- {S1DREG_LCD_NDISP_HPER, 0x13}, /* LCD Horizontal Non-Display Period Register*/
- {S1DREG_TFT_FPLINE_START, 0x01}, /* TFT FPLINE Start Position Register*/
- {S1DREG_TFT_FPLINE_PWIDTH, 0x0c}, /* TFT FPLINE Pulse Width Register*/
- {S1DREG_LCD_DISP_VHEIGHT0, 0xDF}, /* LCD Vertical Display Height Register 0*/
- {S1DREG_LCD_DISP_VHEIGHT1, 0x01}, /* LCD Vertical Display Height Register 1*/
- {S1DREG_LCD_NDISP_VPER, 0x2c}, /* LCD Vertical Non-Display Period Register*/
- {S1DREG_TFT_FPFRAME_START, 0x0a}, /* TFT FPFRAME Start Position Register*/
- {S1DREG_TFT_FPFRAME_PWIDTH, 0x02}, /* TFT FPFRAME Pulse Width Register*/
- {S1DREG_LCD_DISP_MODE, 0x05}, /* LCD Display Mode Register*/
- {S1DREG_LCD_MISC, 0x01}, /* LCD Miscellaneous Register*/
- {S1DREG_LCD_DISP_START0, 0x00}, /* LCD Display Start Address Register 0*/
- {S1DREG_LCD_DISP_START1, 0x00}, /* LCD Display Start Address Register 1*/
- {S1DREG_LCD_DISP_START2, 0x00}, /* LCD Display Start Address Register 2*/
- {S1DREG_LCD_MEM_OFF0, 0x80}, /* LCD Memory Address Offset Register 0*/
- {S1DREG_LCD_MEM_OFF1, 0x02}, /* LCD Memory Address Offset Register 1*/
- {S1DREG_LCD_PIX_PAN, 0x03}, /* LCD Pixel Panning Register*/
- {S1DREG_LCD_DISP_FIFO_HTC, 0x00}, /* LCD Display FIFO High Threshold Control Register*/
- {S1DREG_LCD_DISP_FIFO_LTC, 0x00}, /* LCD Display FIFO Low Threshold Control Register*/
- {S1DREG_CRT_DISP_HWIDTH, 0x4F}, /* CRT/TV Horizontal Display Width Register*/
- {S1DREG_CRT_NDISP_HPER, 0x13}, /* CRT/TV Horizontal Non-Display Period Register*/
- {S1DREG_CRT_HRTC_START, 0x01}, /* CRT/TV HRTC Start Position Register*/
- {S1DREG_CRT_HRTC_PWIDTH, 0x0B}, /* CRT/TV HRTC Pulse Width Register*/
- {S1DREG_CRT_DISP_VHEIGHT0, 0xDF}, /* CRT/TV Vertical Display Height Register 0*/
- {S1DREG_CRT_DISP_VHEIGHT1, 0x01}, /* CRT/TV Vertical Display Height Register 1*/
- {S1DREG_CRT_NDISP_VPER, 0x2B}, /* CRT/TV Vertical Non-Display Period Register*/
- {S1DREG_CRT_VRTC_START, 0x09}, /* CRT/TV VRTC Start Position Register*/
- {S1DREG_CRT_VRTC_PWIDTH, 0x01}, /* CRT/TV VRTC Pulse Width Register*/
- {S1DREG_TV_OUT_CTL, 0x18}, /* TV Output Control Register */
- {S1DREG_CRT_DISP_MODE, 0x05}, /* CRT/TV Display Mode Register, 16BPP*/
- {S1DREG_CRT_DISP_START0, 0x00}, /* CRT/TV Display Start Address Register 0*/
- {S1DREG_CRT_DISP_START1, 0x00}, /* CRT/TV Display Start Address Register 1*/
- {S1DREG_CRT_DISP_START2, 0x00}, /* CRT/TV Display Start Address Register 2*/
- {S1DREG_CRT_MEM_OFF0, 0x80}, /* CRT/TV Memory Address Offset Register 0*/
- {S1DREG_CRT_MEM_OFF1, 0x02}, /* CRT/TV Memory Address Offset Register 1*/
- {S1DREG_CRT_PIX_PAN, 0x00}, /* CRT/TV Pixel Panning Register*/
- {S1DREG_CRT_DISP_FIFO_HTC, 0x00}, /* CRT/TV Display FIFO High Threshold Control Register*/
- {S1DREG_CRT_DISP_FIFO_LTC, 0x00}, /* CRT/TV Display FIFO Low Threshold Control Register*/
- {S1DREG_LCD_CUR_CTL, 0x00}, /* LCD Ink/Cursor Control Register*/
- {S1DREG_LCD_CUR_START, 0x01}, /* LCD Ink/Cursor Start Address Register*/
- {S1DREG_LCD_CUR_XPOS0, 0x00}, /* LCD Cursor X Position Register 0*/
- {S1DREG_LCD_CUR_XPOS1, 0x00}, /* LCD Cursor X Position Register 1*/
- {S1DREG_LCD_CUR_YPOS0, 0x00}, /* LCD Cursor Y Position Register 0*/
- {S1DREG_LCD_CUR_YPOS1, 0x00}, /* LCD Cursor Y Position Register 1*/
- {S1DREG_LCD_CUR_BCTL0, 0x00}, /* LCD Ink/Cursor Blue Color 0 Register*/
- {S1DREG_LCD_CUR_GCTL0, 0x00}, /* LCD Ink/Cursor Green Color 0 Register*/
- {S1DREG_LCD_CUR_RCTL0, 0x00}, /* LCD Ink/Cursor Red Color 0 Register*/
- {S1DREG_LCD_CUR_BCTL1, 0x1F}, /* LCD Ink/Cursor Blue Color 1 Register*/
- {S1DREG_LCD_CUR_GCTL1, 0x3F}, /* LCD Ink/Cursor Green Color 1 Register*/
- {S1DREG_LCD_CUR_RCTL1, 0x1F}, /* LCD Ink/Cursor Red Color 1 Register*/
- {S1DREG_LCD_CUR_FIFO_HTC, 0x00}, /* LCD Ink/Cursor FIFO Threshold Register*/
- {S1DREG_CRT_CUR_CTL, 0x00}, /* CRT/TV Ink/Cursor Control Register*/
- {S1DREG_CRT_CUR_START, 0x01}, /* CRT/TV Ink/Cursor Start Address Register*/
- {S1DREG_CRT_CUR_XPOS0, 0x00}, /* CRT/TV Cursor X Position Register 0*/
- {S1DREG_CRT_CUR_XPOS1, 0x00}, /* CRT/TV Cursor X Position Register 1*/
- {S1DREG_CRT_CUR_YPOS0, 0x00}, /* CRT/TV Cursor Y Position Register 0*/
- {S1DREG_CRT_CUR_YPOS1, 0x00}, /* CRT/TV Cursor Y Position Register 1*/
- {S1DREG_CRT_CUR_BCTL0, 0x00}, /* CRT/TV Ink/Cursor Blue Color 0 Register*/
- {S1DREG_CRT_CUR_GCTL0, 0x00}, /* CRT/TV Ink/Cursor Green Color 0 Register*/
- {S1DREG_CRT_CUR_RCTL0, 0x00}, /* CRT/TV Ink/Cursor Red Color 0 Register*/
- {S1DREG_CRT_CUR_BCTL1, 0x1F}, /* CRT/TV Ink/Cursor Blue Color 1 Register*/
- {S1DREG_CRT_CUR_GCTL1, 0x3F}, /* CRT/TV Ink/Cursor Green Color 1 Register*/
- {S1DREG_CRT_CUR_RCTL1, 0x1F}, /* CRT/TV Ink/Cursor Red Color 1 Register*/
- {S1DREG_CRT_CUR_FIFO_HTC, 0x00}, /* CRT/TV Ink/Cursor FIFO Threshold Register*/
- {S1DREG_BBLT_CTL0, 0x00}, /* BitBlt Control Register 0*/
- {S1DREG_BBLT_CTL1, 0x01}, /* BitBlt Control Register 1*/
- {S1DREG_BBLT_CC_EXP, 0x00}, /* BitBlt ROP Code/Color Expansion Register*/
- {S1DREG_BBLT_OP, 0x00}, /* BitBlt Operation Register*/
- {S1DREG_BBLT_SRC_START0, 0x00}, /* BitBlt Source Start Address Register 0*/
- {S1DREG_BBLT_SRC_START1, 0x00}, /* BitBlt Source Start Address Register 1*/
- {S1DREG_BBLT_SRC_START2, 0x00}, /* BitBlt Source Start Address Register 2*/
- {S1DREG_BBLT_DST_START0, 0x00}, /* BitBlt Destination Start Address Register 0*/
- {S1DREG_BBLT_DST_START1, 0x00}, /* BitBlt Destination Start Address Register 1*/
- {S1DREG_BBLT_DST_START2, 0x00}, /* BitBlt Destination Start Address Register 2*/
- {S1DREG_BBLT_MEM_OFF0, 0x00}, /* BitBlt Memory Address Offset Register 0*/
- {S1DREG_BBLT_MEM_OFF1, 0x00}, /* BitBlt Memory Address Offset Register 1*/
- {S1DREG_BBLT_WIDTH0, 0x00}, /* BitBlt Width Register 0*/
- {S1DREG_BBLT_WIDTH1, 0x00}, /* BitBlt Width Register 1*/
- {S1DREG_BBLT_HEIGHT0, 0x00}, /* BitBlt Height Register 0*/
- {S1DREG_BBLT_HEIGHT1, 0x00}, /* BitBlt Height Register 1*/
- {S1DREG_BBLT_BGC0, 0x00}, /* BitBlt Background Color Register 0*/
- {S1DREG_BBLT_BGC1, 0x00}, /* BitBlt Background Color Register 1*/
- {S1DREG_BBLT_FGC0, 0x00}, /* BitBlt Foreground Color Register 0*/
- {S1DREG_BBLT_FGC1, 0x00}, /* BitBlt Foreground Color Register 1*/
- {S1DREG_LKUP_MODE, 0x00}, /* Look-Up Table Mode Register*/
- {S1DREG_LKUP_ADDR, 0x00}, /* Look-Up Table Address Register*/
- {S1DREG_PS_CNF, 0x00}, /* Power Save Configuration Register*/
- {S1DREG_PS_STATUS, 0x00}, /* Power Save Status Register*/
- {S1DREG_CPU2MEM_WDOGT, 0x00}, /* CPU-to-Memory Access Watchdog Timer Register*/
- {S1DREG_COM_DISP_MODE, 0x01}, /* Display Mode Register, LCD only*/
-};
-
-static struct s1d13xxxfb_pdata yl9200_s1dfb_pdata = {
- .initregs = yl9200_s1dfb_initregs,
- .initregssize = ARRAY_SIZE(yl9200_s1dfb_initregs),
- .platform_init_video = yl9200_init_video,
-};
-
-#define YL9200_FB_REG_BASE AT91_CHIPSELECT_7
-#define YL9200_FB_VMEM_BASE YL9200_FB_REG_BASE + SZ_2M
-#define YL9200_FB_VMEM_SIZE SZ_2M
-
-static struct resource yl9200_s1dfb_resource[] = {
- [0] = { /* video mem */
- .name = "s1d13xxxfb memory",
- .start = YL9200_FB_VMEM_BASE,
- .end = YL9200_FB_VMEM_BASE + YL9200_FB_VMEM_SIZE -1,
- .flags = IORESOURCE_MEM,
- },
- [1] = { /* video registers */
- .name = "s1d13xxxfb registers",
- .start = YL9200_FB_REG_BASE,
- .end = YL9200_FB_REG_BASE + SZ_512 -1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static u64 s1dfb_dmamask = DMA_BIT_MASK(32);
-
-static struct platform_device yl9200_s1dfb_device = {
- .name = "s1d13806fb",
- .id = -1,
- .dev = {
- .dma_mask = &s1dfb_dmamask,
- .coherent_dma_mask = DMA_BIT_MASK(32),
- .platform_data = &yl9200_s1dfb_pdata,
- },
- .resource = yl9200_s1dfb_resource,
- .num_resources = ARRAY_SIZE(yl9200_s1dfb_resource),
-};
-
-void __init yl9200_add_device_video(void)
-{
- platform_device_register(&yl9200_s1dfb_device);
-}
-#else
-void __init yl9200_add_device_video(void) {}
-#endif
-
-
-static void __init yl9200_board_init(void)
-{
- /* Serial */
- /* DBGU on ttyS0. (Rx & Tx only) */
- at91_register_uart(0, 0, 0);
-
- /* USART1 on ttyS1. (Rx, Tx, CTS, RTS, DTR, DSR, DCD, RI) */
- at91_register_uart(AT91RM9200_ID_US1, 1, ATMEL_UART_CTS | ATMEL_UART_RTS
- | ATMEL_UART_DTR | ATMEL_UART_DSR | ATMEL_UART_DCD
- | ATMEL_UART_RI);
-
- /* USART0 on ttyS2. (Rx & Tx only to JP3) */
- at91_register_uart(AT91RM9200_ID_US0, 2, 0);
-
- /* USART3 on ttyS3. (Rx, Tx, RTS - RS485 interface) */
- at91_register_uart(AT91RM9200_ID_US3, 3, ATMEL_UART_RTS);
- at91_add_device_serial();
- /* Ethernet */
- at91_add_device_eth(&yl9200_eth_data);
- /* USB Host */
- at91_add_device_usbh(&yl9200_usbh_data);
- /* USB Device */
- at91_add_device_udc(&yl9200_udc_data);
- /* I2C */
- at91_add_device_i2c(yl9200_i2c_devices, ARRAY_SIZE(yl9200_i2c_devices));
- /* MMC */
- at91_add_device_mci(0, &yl9200_mci0_data);
- /* NAND */
- at91_add_device_nand(&yl9200_nand_data);
- /* NOR Flash */
- platform_device_register(&yl9200_flash);
-#if defined(CONFIG_SPI_ATMEL) || defined(CONFIG_SPI_ATMEL_MODULE)
- /* SPI */
- at91_add_device_spi(yl9200_spi_devices, ARRAY_SIZE(yl9200_spi_devices));
- /* Touchscreen */
- yl9200_add_device_ts();
-#endif
- /* LEDs. */
- at91_gpio_leds(yl9200_leds, ARRAY_SIZE(yl9200_leds));
- /* Push Buttons */
- yl9200_add_device_buttons();
- /* VGA */
- yl9200_add_device_video();
-}
-
-MACHINE_START(YL9200, "uCdragon YL-9200")
- /* Maintainer: S.Birtles */
- .init_time = at91rm9200_timer_init,
- .map_io = at91_map_io,
- .handle_irq = at91_aic_handle_irq,
- .init_early = yl9200_init_early,
- .init_irq = at91_init_irq_default,
- .init_machine = yl9200_board_init,
-MACHINE_END
diff --git a/arch/arm/mach-at91/board.h b/arch/arm/mach-at91/board.h
deleted file mode 100644
index 836e9a5..0000000
--- a/arch/arm/mach-at91/board.h
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/board.h
- *
- * Copyright (C) 2005 HP Labs
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-/*
- * These are data structures found in platform_device.dev.platform_data,
- * and describing board-specific data needed by drivers. For example,
- * which pin is used for a given GPIO role.
- *
- * In 2.6, drivers should strongly avoid board-specific knowledge so
- * that supporting new boards normally won't require driver patches.
- * Most board-specific knowledge should be in arch/.../board-*.c files.
- */
-
-#ifndef __ASM_ARCH_BOARD_H
-#define __ASM_ARCH_BOARD_H
-
-#include <linux/platform_data/atmel.h>
-
- /* USB Device */
-extern void __init at91_add_device_udc(struct at91_udc_data *data);
-
- /* USB High Speed Device */
-extern void __init at91_add_device_usba(struct usba_platform_data *data);
-
- /* Compact Flash */
-extern void __init at91_add_device_cf(struct at91_cf_data *data);
-
- /* MMC / SD */
- /* atmel-mci platform config */
-extern void __init at91_add_device_mci(short mmc_id, struct mci_platform_data *data);
-
-extern void __init at91_add_device_eth(struct macb_platform_data *data);
-
- /* USB Host */
-extern void __init at91_add_device_usbh(struct at91_usbh_data *data);
-extern void __init at91_add_device_usbh_ohci(struct at91_usbh_data *data);
-extern void __init at91_add_device_usbh_ehci(struct at91_usbh_data *data);
-
-extern void __init at91_add_device_nand(struct atmel_nand_data *data);
-
- /* I2C*/
-#if defined(CONFIG_ARCH_AT91SAM9G45)
-extern void __init at91_add_device_i2c(short i2c_id, struct i2c_board_info *devices, int nr_devices);
-#else
-extern void __init at91_add_device_i2c(struct i2c_board_info *devices, int nr_devices);
-#endif
-
- /* SPI */
-extern void __init at91_add_device_spi(struct spi_board_info *devices, int nr_devices);
-
- /* Serial */
-#define ATMEL_UART_CTS 0x01
-#define ATMEL_UART_RTS 0x02
-#define ATMEL_UART_DSR 0x04
-#define ATMEL_UART_DTR 0x08
-#define ATMEL_UART_DCD 0x10
-#define ATMEL_UART_RI 0x20
-
-extern void __init at91_register_uart(unsigned id, unsigned portnr, unsigned pins);
-
-extern struct platform_device *atmel_default_console_device;
-
-extern void __init at91_add_device_serial(void);
-
-/*
- * PWM
- */
-#define AT91_PWM0 0
-#define AT91_PWM1 1
-#define AT91_PWM2 2
-#define AT91_PWM3 3
-
-extern void __init at91_add_device_pwm(u32 mask);
-
-/*
- * SSC -- accessed through ssc_request(id). Drivers don't bind to SSC
- * platform devices. Their SSC ID is part of their configuration data,
- * along with information about which SSC signals they should use.
- */
-#define ATMEL_SSC_TK 0x01
-#define ATMEL_SSC_TF 0x02
-#define ATMEL_SSC_TD 0x04
-#define ATMEL_SSC_TX (ATMEL_SSC_TK | ATMEL_SSC_TF | ATMEL_SSC_TD)
-
-#define ATMEL_SSC_RK 0x10
-#define ATMEL_SSC_RF 0x20
-#define ATMEL_SSC_RD 0x40
-#define ATMEL_SSC_RX (ATMEL_SSC_RK | ATMEL_SSC_RF | ATMEL_SSC_RD)
-
-extern void __init at91_add_device_ssc(unsigned id, unsigned pins);
-
- /* LCD Controller */
-struct atmel_lcdfb_pdata;
-extern void __init at91_add_device_lcdc(struct atmel_lcdfb_pdata *data);
-
- /* AC97 */
-extern void __init at91_add_device_ac97(struct ac97c_platform_data *data);
-
- /* ISI */
-struct isi_platform_data;
-extern void __init at91_add_device_isi(struct isi_platform_data *data,
- bool use_pck_as_mck);
-
-/* CAN */
-extern void __init at91_add_device_can(struct at91_can_data *data);
-
- /* LEDs */
-extern void __init at91_gpio_leds(struct gpio_led *leds, int nr);
-
-#endif
diff --git a/arch/arm/mach-at91/clock.c b/arch/arm/mach-at91/clock.c
deleted file mode 100644
index d66f102..0000000
--- a/arch/arm/mach-at91/clock.c
+++ /dev/null
@@ -1,977 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/clock.c
- *
- * Copyright (C) 2005 David Brownell
- * Copyright (C) 2005 Ivan Kokshaysky
- *
- * 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/kernel.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/list.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/of_address.h>
-#include <linux/clk/at91_pmc.h>
-
-#include <mach/hardware.h>
-#include <mach/cpu.h>
-
-#include <asm/proc-fns.h>
-
-#include "clock.h"
-#include "generic.h"
-
-void __iomem *at91_pmc_base;
-EXPORT_SYMBOL_GPL(at91_pmc_base);
-
-/*
- * There's a lot more which can be done with clocks, including cpufreq
- * integration, slow clock mode support (for system suspend), letting
- * PLLB be used at other rates (on boards that don't need USB), etc.
- */
-
-#define clk_is_primary(x) ((x)->type & CLK_TYPE_PRIMARY)
-#define clk_is_programmable(x) ((x)->type & CLK_TYPE_PROGRAMMABLE)
-#define clk_is_peripheral(x) ((x)->type & CLK_TYPE_PERIPHERAL)
-#define clk_is_sys(x) ((x)->type & CLK_TYPE_SYSTEM)
-
-
-/*
- * Chips have some kind of clocks : group them by functionality
- */
-#define cpu_has_utmi() ( cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_sama5d3())
-
-#define cpu_has_1056M_plla() (cpu_is_sama5d3())
-
-#define cpu_has_800M_plla() ( cpu_is_at91sam9g20() \
- || cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_at91sam9n12())
-
-#define cpu_has_300M_plla() (cpu_is_at91sam9g10())
-
-#define cpu_has_240M_plla() (cpu_is_at91sam9261() \
- || cpu_is_at91sam9263() \
- || cpu_is_at91sam9rl())
-
-#define cpu_has_210M_plla() (cpu_is_at91sam9260())
-
-#define cpu_has_pllb() (!(cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_sama5d3()))
-
-#define cpu_has_upll() (cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_sama5d3())
-
-/* USB host HS & FS */
-#define cpu_has_uhp() (!cpu_is_at91sam9rl())
-
-/* USB device FS only */
-#define cpu_has_udpfs() (!(cpu_is_at91sam9rl() \
- || cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_sama5d3()))
-
-#define cpu_has_plladiv2() (cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_at91sam9n12() \
- || cpu_is_sama5d3())
-
-#define cpu_has_mdiv3() (cpu_is_at91sam9g45() \
- || cpu_is_at91sam9x5() \
- || cpu_is_at91sam9n12() \
- || cpu_is_sama5d3())
-
-#define cpu_has_alt_prescaler() (cpu_is_at91sam9x5() \
- || cpu_is_at91sam9n12() \
- || cpu_is_sama5d3())
-
-static LIST_HEAD(clocks);
-static DEFINE_SPINLOCK(clk_lock);
-
-static u32 at91_pllb_usb_init;
-
-/*
- * Four primary clock sources: two crystal oscillators (32K, main), and
- * two PLLs. PLLA usually runs the master clock; and PLLB must run at
- * 48 MHz (unless no USB function clocks are needed). The main clock and
- * both PLLs are turned off to run in "slow clock mode" (system suspend).
- */
-static struct clk clk32k = {
- .name = "clk32k",
- .rate_hz = AT91_SLOW_CLOCK,
- .users = 1, /* always on */
- .id = 0,
- .type = CLK_TYPE_PRIMARY,
-};
-static struct clk main_clk = {
- .name = "main",
- .pmc_mask = AT91_PMC_MOSCS, /* in PMC_SR */
- .id = 1,
- .type = CLK_TYPE_PRIMARY,
-};
-static struct clk plla = {
- .name = "plla",
- .parent = &main_clk,
- .pmc_mask = AT91_PMC_LOCKA, /* in PMC_SR */
- .id = 2,
- .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
-};
-
-static void pllb_mode(struct clk *clk, int is_on)
-{
- u32 value;
-
- if (is_on) {
- is_on = AT91_PMC_LOCKB;
- value = at91_pllb_usb_init;
- } else
- value = 0;
-
- // REVISIT: Add work-around for AT91RM9200 Errata #26 ?
- at91_pmc_write(AT91_CKGR_PLLBR, value);
-
- do {
- cpu_relax();
- } while ((at91_pmc_read(AT91_PMC_SR) & AT91_PMC_LOCKB) != is_on);
-}
-
-static struct clk pllb = {
- .name = "pllb",
- .parent = &main_clk,
- .pmc_mask = AT91_PMC_LOCKB, /* in PMC_SR */
- .mode = pllb_mode,
- .id = 3,
- .type = CLK_TYPE_PRIMARY | CLK_TYPE_PLL,
-};
-
-static void pmc_sys_mode(struct clk *clk, int is_on)
-{
- if (is_on)
- at91_pmc_write(AT91_PMC_SCER, clk->pmc_mask);
- else
- at91_pmc_write(AT91_PMC_SCDR, clk->pmc_mask);
-}
-
-static void pmc_uckr_mode(struct clk *clk, int is_on)
-{
- unsigned int uckr = at91_pmc_read(AT91_CKGR_UCKR);
-
- if (is_on) {
- is_on = AT91_PMC_LOCKU;
- at91_pmc_write(AT91_CKGR_UCKR, uckr | clk->pmc_mask);
- } else
- at91_pmc_write(AT91_CKGR_UCKR, uckr & ~(clk->pmc_mask));
-
- do {
- cpu_relax();
- } while ((at91_pmc_read(AT91_PMC_SR) & AT91_PMC_LOCKU) != is_on);
-}
-
-/* USB function clocks (PLLB must be 48 MHz) */
-static struct clk udpck = {
- .name = "udpck",
- .parent = &pllb,
- .mode = pmc_sys_mode,
-};
-struct clk utmi_clk = {
- .name = "utmi_clk",
- .parent = &main_clk,
- .pmc_mask = AT91_PMC_UPLLEN, /* in CKGR_UCKR */
- .mode = pmc_uckr_mode,
- .type = CLK_TYPE_PLL,
-};
-static struct clk uhpck = {
- .name = "uhpck",
- /*.parent = ... we choose parent at runtime */
- .mode = pmc_sys_mode,
-};
-
-
-/*
- * The master clock is divided from the CPU clock (by 1-4). It's used for
- * memory, interfaces to on-chip peripherals, the AIC, and sometimes more
- * (e.g baud rate generation). It's sourced from one of the primary clocks.
- */
-struct clk mck = {
- .name = "mck",
- .pmc_mask = AT91_PMC_MCKRDY, /* in PMC_SR */
-};
-
-static void pmc_periph_mode(struct clk *clk, int is_on)
-{
- u32 regval = 0;
-
- /*
- * With sama5d3 devices, we are managing clock division so we have to
- * use the Peripheral Control Register introduced from at91sam9x5
- * devices.
- */
- if (cpu_is_sama5d3()) {
- regval |= AT91_PMC_PCR_CMD; /* write command */
- regval |= clk->pid & AT91_PMC_PCR_PID; /* peripheral selection */
- regval |= AT91_PMC_PCR_DIV(clk->div);
- if (is_on)
- regval |= AT91_PMC_PCR_EN; /* enable clock */
- at91_pmc_write(AT91_PMC_PCR, regval);
- } else {
- if (is_on)
- at91_pmc_write(AT91_PMC_PCER, clk->pmc_mask);
- else
- at91_pmc_write(AT91_PMC_PCDR, clk->pmc_mask);
- }
-}
-
-static struct clk __init *at91_css_to_clk(unsigned long css)
-{
- switch (css) {
- case AT91_PMC_CSS_SLOW:
- return &clk32k;
- case AT91_PMC_CSS_MAIN:
- return &main_clk;
- case AT91_PMC_CSS_PLLA:
- return &plla;
- case AT91_PMC_CSS_PLLB:
- if (cpu_has_upll())
- /* CSS_PLLB == CSS_UPLL */
- return &utmi_clk;
- else if (cpu_has_pllb())
- return &pllb;
- break;
- /* alternate PMC: can use master clock */
- case AT91_PMC_CSS_MASTER:
- return &mck;
- }
-
- return NULL;
-}
-
-static int pmc_prescaler_divider(u32 reg)
-{
- if (cpu_has_alt_prescaler()) {
- return 1 << ((reg & AT91_PMC_ALT_PRES) >> PMC_ALT_PRES_OFFSET);
- } else {
- return 1 << ((reg & AT91_PMC_PRES) >> PMC_PRES_OFFSET);
- }
-}
-
-static void __clk_enable(struct clk *clk)
-{
- if (clk->parent)
- __clk_enable(clk->parent);
- if (clk->users++ == 0 && clk->mode)
- clk->mode(clk, 1);
-}
-
-int clk_enable(struct clk *clk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clk_lock, flags);
- __clk_enable(clk);
- spin_unlock_irqrestore(&clk_lock, flags);
- return 0;
-}
-EXPORT_SYMBOL(clk_enable);
-
-static void __clk_disable(struct clk *clk)
-{
- BUG_ON(clk->users == 0);
- if (--clk->users == 0 && clk->mode)
- clk->mode(clk, 0);
- if (clk->parent)
- __clk_disable(clk->parent);
-}
-
-void clk_disable(struct clk *clk)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&clk_lock, flags);
- __clk_disable(clk);
- spin_unlock_irqrestore(&clk_lock, flags);
-}
-EXPORT_SYMBOL(clk_disable);
-
-unsigned long clk_get_rate(struct clk *clk)
-{
- unsigned long flags;
- unsigned long rate;
-
- spin_lock_irqsave(&clk_lock, flags);
- for (;;) {
- rate = clk->rate_hz;
- if (rate || !clk->parent)
- break;
- clk = clk->parent;
- }
- spin_unlock_irqrestore(&clk_lock, flags);
- return rate;
-}
-EXPORT_SYMBOL(clk_get_rate);
-
-/*------------------------------------------------------------------------*/
-
-/*
- * For now, only the programmable clocks support reparenting (MCK could
- * do this too, with care) or rate changing (the PLLs could do this too,
- * ditto MCK but that's more for cpufreq). Drivers may reparent to get
- * a better rate match; we don't.
- */
-
-long clk_round_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long flags;
- unsigned prescale;
- unsigned long actual;
- unsigned long prev = ULONG_MAX;
-
- if (!clk_is_programmable(clk))
- return -EINVAL;
- spin_lock_irqsave(&clk_lock, flags);
-
- actual = clk->parent->rate_hz;
- for (prescale = 0; prescale < 7; prescale++) {
- if (actual > rate)
- prev = actual;
-
- if (actual && actual <= rate) {
- if ((prev - rate) < (rate - actual)) {
- actual = prev;
- prescale--;
- }
- break;
- }
- actual >>= 1;
- }
-
- spin_unlock_irqrestore(&clk_lock, flags);
- return (prescale < 7) ? actual : -ENOENT;
-}
-EXPORT_SYMBOL(clk_round_rate);
-
-int clk_set_rate(struct clk *clk, unsigned long rate)
-{
- unsigned long flags;
- unsigned prescale;
- unsigned long prescale_offset, css_mask;
- unsigned long actual;
-
- if (!clk_is_programmable(clk))
- return -EINVAL;
- if (clk->users)
- return -EBUSY;
-
- if (cpu_has_alt_prescaler()) {
- prescale_offset = PMC_ALT_PRES_OFFSET;
- css_mask = AT91_PMC_ALT_PCKR_CSS;
- } else {
- prescale_offset = PMC_PRES_OFFSET;
- css_mask = AT91_PMC_CSS;
- }
-
- spin_lock_irqsave(&clk_lock, flags);
-
- actual = clk->parent->rate_hz;
- for (prescale = 0; prescale < 7; prescale++) {
- if (actual && actual <= rate) {
- u32 pckr;
-
- pckr = at91_pmc_read(AT91_PMC_PCKR(clk->id));
- pckr &= css_mask; /* keep clock selection */
- pckr |= prescale << prescale_offset;
- at91_pmc_write(AT91_PMC_PCKR(clk->id), pckr);
- clk->rate_hz = actual;
- break;
- }
- actual >>= 1;
- }
-
- spin_unlock_irqrestore(&clk_lock, flags);
- return (prescale < 7) ? actual : -ENOENT;
-}
-EXPORT_SYMBOL(clk_set_rate);
-
-struct clk *clk_get_parent(struct clk *clk)
-{
- return clk->parent;
-}
-EXPORT_SYMBOL(clk_get_parent);
-
-int clk_set_parent(struct clk *clk, struct clk *parent)
-{
- unsigned long flags;
-
- if (clk->users)
- return -EBUSY;
- if (!clk_is_primary(parent) || !clk_is_programmable(clk))
- return -EINVAL;
-
- if (cpu_is_at91sam9rl() && parent->id == AT91_PMC_CSS_PLLB)
- return -EINVAL;
-
- spin_lock_irqsave(&clk_lock, flags);
-
- clk->rate_hz = parent->rate_hz;
- clk->parent = parent;
- at91_pmc_write(AT91_PMC_PCKR(clk->id), parent->id);
-
- spin_unlock_irqrestore(&clk_lock, flags);
- return 0;
-}
-EXPORT_SYMBOL(clk_set_parent);
-
-/* establish PCK0..PCKN parentage and rate */
-static void __init init_programmable_clock(struct clk *clk)
-{
- struct clk *parent;
- u32 pckr;
- unsigned int css_mask;
-
- if (cpu_has_alt_prescaler())
- css_mask = AT91_PMC_ALT_PCKR_CSS;
- else
- css_mask = AT91_PMC_CSS;
-
- pckr = at91_pmc_read(AT91_PMC_PCKR(clk->id));
- parent = at91_css_to_clk(pckr & css_mask);
- clk->parent = parent;
- clk->rate_hz = parent->rate_hz / pmc_prescaler_divider(pckr);
-}
-
-/*------------------------------------------------------------------------*/
-
-#ifdef CONFIG_DEBUG_FS
-
-static int at91_clk_show(struct seq_file *s, void *unused)
-{
- u32 scsr, pcsr, pcsr1 = 0, uckr = 0, sr;
- struct clk *clk;
-
- scsr = at91_pmc_read(AT91_PMC_SCSR);
- pcsr = at91_pmc_read(AT91_PMC_PCSR);
- if (cpu_is_sama5d3())
- pcsr1 = at91_pmc_read(AT91_PMC_PCSR1);
- sr = at91_pmc_read(AT91_PMC_SR);
- seq_printf(s, "SCSR = %8x\n", scsr);
- seq_printf(s, "PCSR = %8x\n", pcsr);
- if (cpu_is_sama5d3())
- seq_printf(s, "PCSR1 = %8x\n", pcsr1);
- seq_printf(s, "MOR = %8x\n", at91_pmc_read(AT91_CKGR_MOR));
- seq_printf(s, "MCFR = %8x\n", at91_pmc_read(AT91_CKGR_MCFR));
- seq_printf(s, "PLLA = %8x\n", at91_pmc_read(AT91_CKGR_PLLAR));
- if (cpu_has_pllb())
- seq_printf(s, "PLLB = %8x\n", at91_pmc_read(AT91_CKGR_PLLBR));
- if (cpu_has_utmi()) {
- uckr = at91_pmc_read(AT91_CKGR_UCKR);
- seq_printf(s, "UCKR = %8x\n", uckr);
- }
- seq_printf(s, "MCKR = %8x\n", at91_pmc_read(AT91_PMC_MCKR));
- if (cpu_has_upll() || cpu_is_at91sam9n12())
- seq_printf(s, "USB = %8x\n", at91_pmc_read(AT91_PMC_USB));
- seq_printf(s, "SR = %8x\n", sr);
-
- seq_printf(s, "\n");
-
- list_for_each_entry(clk, &clocks, node) {
- char *state;
-
- if (clk->mode == pmc_sys_mode) {
- state = (scsr & clk->pmc_mask) ? "on" : "off";
- } else if (clk->mode == pmc_periph_mode) {
- if (cpu_is_sama5d3()) {
- u32 pmc_mask = 1 << (clk->pid % 32);
-
- if (clk->pid > 31)
- state = (pcsr1 & pmc_mask) ? "on" : "off";
- else
- state = (pcsr & pmc_mask) ? "on" : "off";
- } else {
- state = (pcsr & clk->pmc_mask) ? "on" : "off";
- }
- } else if (clk->mode == pmc_uckr_mode) {
- state = (uckr & clk->pmc_mask) ? "on" : "off";
- } else if (clk->pmc_mask) {
- state = (sr & clk->pmc_mask) ? "on" : "off";
- } else if (clk == &clk32k || clk == &main_clk) {
- state = "on";
- } else {
- state = "";
- }
-
- seq_printf(s, "%-10s users=%2d %-3s %9lu Hz %s\n",
- clk->name, clk->users, state, clk_get_rate(clk),
- clk->parent ? clk->parent->name : "");
- }
- return 0;
-}
-
-static int at91_clk_open(struct inode *inode, struct file *file)
-{
- return single_open(file, at91_clk_show, NULL);
-}
-
-static const struct file_operations at91_clk_operations = {
- .open = at91_clk_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init at91_clk_debugfs_init(void)
-{
- /* /sys/kernel/debug/at91_clk */
- (void) debugfs_create_file("at91_clk", S_IFREG | S_IRUGO, NULL, NULL, &at91_clk_operations);
-
- return 0;
-}
-postcore_initcall(at91_clk_debugfs_init);
-
-#endif
-
-/*------------------------------------------------------------------------*/
-
-/* Register a new clock */
-static void __init at91_clk_add(struct clk *clk)
-{
- list_add_tail(&clk->node, &clocks);
-
- clk->cl.con_id = clk->name;
- clk->cl.clk = clk;
- clkdev_add(&clk->cl);
-}
-
-int __init clk_register(struct clk *clk)
-{
- if (clk_is_peripheral(clk)) {
- if (!clk->parent)
- clk->parent = &mck;
- if (cpu_is_sama5d3())
- clk->rate_hz = DIV_ROUND_UP(clk->parent->rate_hz,
- 1 << clk->div);
- clk->mode = pmc_periph_mode;
- }
- else if (clk_is_sys(clk)) {
- clk->parent = &mck;
- clk->mode = pmc_sys_mode;
- }
- else if (clk_is_programmable(clk)) {
- clk->mode = pmc_sys_mode;
- init_programmable_clock(clk);
- }
-
- at91_clk_add(clk);
-
- return 0;
-}
-
-/*------------------------------------------------------------------------*/
-
-static u32 __init at91_pll_rate(struct clk *pll, u32 freq, u32 reg)
-{
- unsigned mul, div;
-
- div = reg & 0xff;
- if (cpu_is_sama5d3())
- mul = AT91_PMC3_MUL_GET(reg);
- else
- mul = AT91_PMC_MUL_GET(reg);
-
- if (div && mul) {
- freq /= div;
- freq *= mul + 1;
- } else
- freq = 0;
-
- return freq;
-}
-
-static u32 __init at91_usb_rate(struct clk *pll, u32 freq, u32 reg)
-{
- if (pll == &pllb && (reg & AT91_PMC_USB96M))
- return freq / 2;
- else if (pll == &utmi_clk || cpu_is_at91sam9n12())
- return freq / (1 + ((reg & AT91_PMC_OHCIUSBDIV) >> 8));
- else
- return freq;
-}
-
-static unsigned __init at91_pll_calc(unsigned main_freq, unsigned out_freq)
-{
- unsigned i, div = 0, mul = 0, diff = 1 << 30;
- unsigned ret = (out_freq > 155000000) ? 0xbe00 : 0x3e00;
-
- /* PLL output max 240 MHz (or 180 MHz per errata) */
- if (out_freq > 240000000)
- goto fail;
-
- for (i = 1; i < 256; i++) {
- int diff1;
- unsigned input, mul1;
-
- /*
- * PLL input between 1MHz and 32MHz per spec, but lower
- * frequences seem necessary in some cases so allow 100K.
- * Warning: some newer products need 2MHz min.
- */
- input = main_freq / i;
- if (cpu_is_at91sam9g20() && input < 2000000)
- continue;
- if (input < 100000)
- continue;
- if (input > 32000000)
- continue;
-
- mul1 = out_freq / input;
- if (cpu_is_at91sam9g20() && mul > 63)
- continue;
- if (mul1 > 2048)
- continue;
- if (mul1 < 2)
- goto fail;
-
- diff1 = out_freq - input * mul1;
- if (diff1 < 0)
- diff1 = -diff1;
- if (diff > diff1) {
- diff = diff1;
- div = i;
- mul = mul1;
- if (diff == 0)
- break;
- }
- }
- if (i == 256 && diff > (out_freq >> 5))
- goto fail;
- return ret | ((mul - 1) << 16) | div;
-fail:
- return 0;
-}
-
-static struct clk *const standard_pmc_clocks[] __initconst = {
- /* four primary clocks */
- &clk32k,
- &main_clk,
- &plla,
-
- /* MCK */
- &mck
-};
-
-/* PLLB generated USB full speed clock init */
-static void __init at91_pllb_usbfs_clock_init(unsigned long main_clock)
-{
- unsigned int reg;
-
- /*
- * USB clock init: choose 48 MHz PLLB value,
- * disable 48MHz clock during usb peripheral suspend.
- *
- * REVISIT: assumes MCK doesn't derive from PLLB!
- */
- uhpck.parent = &pllb;
-
- reg = at91_pllb_usb_init = at91_pll_calc(main_clock, 48000000 * 2);
- pllb.rate_hz = at91_pll_rate(&pllb, main_clock, at91_pllb_usb_init);
- if (cpu_is_at91rm9200()) {
- reg = at91_pllb_usb_init |= AT91_PMC_USB96M;
- uhpck.pmc_mask = AT91RM9200_PMC_UHP;
- udpck.pmc_mask = AT91RM9200_PMC_UDP;
- at91_pmc_write(AT91_PMC_SCER, AT91RM9200_PMC_MCKUDP);
- } else if (cpu_is_at91sam9260() || cpu_is_at91sam9261() ||
- cpu_is_at91sam9263() || cpu_is_at91sam9g20() ||
- cpu_is_at91sam9g10()) {
- reg = at91_pllb_usb_init |= AT91_PMC_USB96M;
- uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
- udpck.pmc_mask = AT91SAM926x_PMC_UDP;
- } else if (cpu_is_at91sam9n12()) {
- /* Divider for USB clock is in USB clock register for 9n12 */
- reg = AT91_PMC_USBS_PLLB;
-
- /* For PLLB output 96M, set usb divider 2 (USBDIV + 1) */
- reg |= AT91_PMC_OHCIUSBDIV_2;
- at91_pmc_write(AT91_PMC_USB, reg);
-
- /* Still setup masks */
- uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
- udpck.pmc_mask = AT91SAM926x_PMC_UDP;
- }
- at91_pmc_write(AT91_CKGR_PLLBR, 0);
-
- udpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, reg);
- uhpck.rate_hz = at91_usb_rate(&pllb, pllb.rate_hz, reg);
-}
-
-/* UPLL generated USB full speed clock init */
-static void __init at91_upll_usbfs_clock_init(unsigned long main_clock)
-{
- /*
- * USB clock init: choose 480 MHz from UPLL,
- */
- unsigned int usbr = AT91_PMC_USBS_UPLL;
-
- /* Setup divider by 10 to reach 48 MHz */
- usbr |= ((10 - 1) << 8) & AT91_PMC_OHCIUSBDIV;
-
- at91_pmc_write(AT91_PMC_USB, usbr);
-
- /* Now set uhpck values */
- uhpck.parent = &utmi_clk;
- uhpck.pmc_mask = AT91SAM926x_PMC_UHP;
- uhpck.rate_hz = at91_usb_rate(&utmi_clk, utmi_clk.rate_hz, usbr);
-}
-
-static int __init at91_pmc_init(unsigned long main_clock)
-{
- unsigned tmp, freq, mckr;
- int i;
- int pll_overclock = false;
-
- /*
- * When the bootloader initialized the main oscillator correctly,
- * there's no problem using the cycle counter. But if it didn't,
- * or when using oscillator bypass mode, we must be told the speed
- * of the main clock.
- */
- if (!main_clock) {
- do {
- tmp = at91_pmc_read(AT91_CKGR_MCFR);
- } while (!(tmp & AT91_PMC_MAINRDY));
- main_clock = (tmp & AT91_PMC_MAINF) * (AT91_SLOW_CLOCK / 16);
- }
- main_clk.rate_hz = main_clock;
-
- /* report if PLLA is more than mildly overclocked */
- plla.rate_hz = at91_pll_rate(&plla, main_clock, at91_pmc_read(AT91_CKGR_PLLAR));
- if (cpu_has_1056M_plla()) {
- if (plla.rate_hz > 1056000000)
- pll_overclock = true;
- } else if (cpu_has_800M_plla()) {
- if (plla.rate_hz > 800000000)
- pll_overclock = true;
- } else if (cpu_has_300M_plla()) {
- if (plla.rate_hz > 300000000)
- pll_overclock = true;
- } else if (cpu_has_240M_plla()) {
- if (plla.rate_hz > 240000000)
- pll_overclock = true;
- } else if (cpu_has_210M_plla()) {
- if (plla.rate_hz > 210000000)
- pll_overclock = true;
- } else {
- if (plla.rate_hz > 209000000)
- pll_overclock = true;
- }
- if (pll_overclock)
- pr_info("Clocks: PLLA overclocked, %ld MHz\n", plla.rate_hz / 1000000);
-
- if (cpu_has_plladiv2()) {
- mckr = at91_pmc_read(AT91_PMC_MCKR);
- plla.rate_hz /= (1 << ((mckr & AT91_PMC_PLLADIV2) >> 12)); /* plla divisor by 2 */
- }
-
- if (!cpu_has_pllb() && cpu_has_upll()) {
- /* setup UTMI clock as the fourth primary clock
- * (instead of pllb) */
- utmi_clk.type |= CLK_TYPE_PRIMARY;
- utmi_clk.id = 3;
- }
-
-
- /*
- * USB HS clock init
- */
- if (cpu_has_utmi()) {
- /*
- * multiplier is hard-wired to 40
- * (obtain the USB High Speed 480 MHz when input is 12 MHz)
- */
- utmi_clk.rate_hz = 40 * utmi_clk.parent->rate_hz;
-
- /* UTMI bias and PLL are managed at the same time */
- if (cpu_has_upll())
- utmi_clk.pmc_mask |= AT91_PMC_BIASEN;
- }
-
- /*
- * USB FS clock init
- */
- if (cpu_has_pllb())
- at91_pllb_usbfs_clock_init(main_clock);
- if (cpu_has_upll())
- /* assumes that we choose UPLL for USB and not PLLA */
- at91_upll_usbfs_clock_init(main_clock);
-
- /*
- * MCK and CPU derive from one of those primary clocks.
- * For now, assume this parentage won't change.
- */
- mckr = at91_pmc_read(AT91_PMC_MCKR);
- mck.parent = at91_css_to_clk(mckr & AT91_PMC_CSS);
- freq = mck.parent->rate_hz;
- freq /= pmc_prescaler_divider(mckr); /* prescale */
- if (cpu_is_at91rm9200()) {
- mck.rate_hz = freq / (1 + ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
- } else if (cpu_is_at91sam9g20()) {
- mck.rate_hz = (mckr & AT91_PMC_MDIV) ?
- freq / ((mckr & AT91_PMC_MDIV) >> 7) : freq; /* mdiv ; (x >> 7) = ((x >> 8) * 2) */
- if (mckr & AT91_PMC_PDIV)
- freq /= 2; /* processor clock division */
- } else if (cpu_has_mdiv3()) {
- mck.rate_hz = (mckr & AT91_PMC_MDIV) == AT91SAM9_PMC_MDIV_3 ?
- freq / 3 : freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
- } else {
- mck.rate_hz = freq / (1 << ((mckr & AT91_PMC_MDIV) >> 8)); /* mdiv */
- }
-
- if (cpu_has_alt_prescaler()) {
- /* Programmable clocks can use MCK */
- mck.type |= CLK_TYPE_PRIMARY;
- mck.id = 4;
- }
-
- /* Register the PMC's standard clocks */
- for (i = 0; i < ARRAY_SIZE(standard_pmc_clocks); i++)
- at91_clk_add(standard_pmc_clocks[i]);
-
- if (cpu_has_pllb())
- at91_clk_add(&pllb);
-
- if (cpu_has_uhp())
- at91_clk_add(&uhpck);
-
- if (cpu_has_udpfs())
- at91_clk_add(&udpck);
-
- if (cpu_has_utmi())
- at91_clk_add(&utmi_clk);
-
- /* MCK and CPU clock are "always on" */
- clk_enable(&mck);
-
- printk("Clocks: CPU %u MHz, master %u MHz, main %u.%03u MHz\n",
- freq / 1000000, (unsigned) mck.rate_hz / 1000000,
- (unsigned) main_clock / 1000000,
- ((unsigned) main_clock % 1000000) / 1000);
-
- return 0;
-}
-
-#if defined(CONFIG_OF)
-static struct of_device_id pmc_ids[] = {
- { .compatible = "atmel,at91rm9200-pmc" },
- { .compatible = "atmel,at91sam9260-pmc" },
- { .compatible = "atmel,at91sam9g45-pmc" },
- { .compatible = "atmel,at91sam9n12-pmc" },
- { .compatible = "atmel,at91sam9x5-pmc" },
- { .compatible = "atmel,sama5d3-pmc" },
- { /*sentinel*/ }
-};
-
-static struct of_device_id osc_ids[] = {
- { .compatible = "atmel,osc" },
- { /*sentinel*/ }
-};
-
-int __init at91_dt_clock_init(void)
-{
- struct device_node *np;
- u32 main_clock = 0;
-
- np = of_find_matching_node(NULL, pmc_ids);
- if (!np)
- panic("unable to find compatible pmc node in dtb\n");
-
- at91_pmc_base = of_iomap(np, 0);
- if (!at91_pmc_base)
- panic("unable to map pmc cpu registers\n");
-
- of_node_put(np);
-
- /* retrieve the freqency of fixed clocks from device tree */
- np = of_find_matching_node(NULL, osc_ids);
- if (np) {
- u32 rate;
- if (!of_property_read_u32(np, "clock-frequency", &rate))
- main_clock = rate;
- }
-
- of_node_put(np);
-
- return at91_pmc_init(main_clock);
-}
-#endif
-
-int __init at91_clock_init(unsigned long main_clock)
-{
- at91_pmc_base = ioremap(AT91_PMC, 256);
- if (!at91_pmc_base)
- panic("Impossible to ioremap AT91_PMC 0x%x\n", AT91_PMC);
-
- return at91_pmc_init(main_clock);
-}
-
-/*
- * Several unused clocks may be active. Turn them off.
- */
-static int __init at91_clock_reset(void)
-{
- unsigned long pcdr = 0;
- unsigned long pcdr1 = 0;
- unsigned long scdr = 0;
- struct clk *clk;
-
- list_for_each_entry(clk, &clocks, node) {
- if (clk->users > 0)
- continue;
-
- if (clk->mode == pmc_periph_mode) {
- if (cpu_is_sama5d3()) {
- u32 pmc_mask = 1 << (clk->pid % 32);
-
- if (clk->pid > 31)
- pcdr1 |= pmc_mask;
- else
- pcdr |= pmc_mask;
- } else
- pcdr |= clk->pmc_mask;
- }
-
- if (clk->mode == pmc_sys_mode)
- scdr |= clk->pmc_mask;
-
- pr_debug("Clocks: disable unused %s\n", clk->name);
- }
-
- at91_pmc_write(AT91_PMC_SCDR, scdr);
- at91_pmc_write(AT91_PMC_PCDR, pcdr);
- if (cpu_is_sama5d3())
- at91_pmc_write(AT91_PMC_PCDR1, pcdr1);
-
- return 0;
-}
-late_initcall(at91_clock_reset);
-
-void at91sam9_idle(void)
-{
- at91_pmc_write(AT91_PMC_SCDR, AT91_PMC_PCK);
- cpu_do_idle();
-}
diff --git a/arch/arm/mach-at91/clock.h b/arch/arm/mach-at91/clock.h
deleted file mode 100644
index a98a39b..0000000
--- a/arch/arm/mach-at91/clock.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/clock.h
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/clkdev.h>
-
-#define CLK_TYPE_PRIMARY 0x1
-#define CLK_TYPE_PLL 0x2
-#define CLK_TYPE_PROGRAMMABLE 0x4
-#define CLK_TYPE_PERIPHERAL 0x8
-#define CLK_TYPE_SYSTEM 0x10
-
-
-struct clk {
- struct list_head node;
- const char *name; /* unique clock name */
- struct clk_lookup cl;
- unsigned long rate_hz;
- unsigned div; /* parent clock divider */
- struct clk *parent;
- unsigned pid; /* peripheral ID */
- u32 pmc_mask;
- void (*mode)(struct clk *, int);
- unsigned id:3; /* PCK0..4, or 32k/main/a/b */
- unsigned type; /* clock type */
- u16 users;
-};
-
-
-extern int __init clk_register(struct clk *clk);
-extern struct clk mck;
-extern struct clk utmi_clk;
-
-#define CLKDEV_CON_ID(_id, _clk) \
- { \
- .con_id = _id, \
- .clk = _clk, \
- }
-
-#define CLKDEV_CON_DEV_ID(_con_id, _dev_id, _clk) \
- { \
- .con_id = _con_id, \
- .dev_id = _dev_id, \
- .clk = _clk, \
- }
diff --git a/arch/arm/mach-at91/generic.h b/arch/arm/mach-at91/generic.h
index 81959cf..d533242 100644
--- a/arch/arm/mach-at91/generic.h
+++ b/arch/arm/mach-at91/generic.h
@@ -11,7 +11,6 @@
#ifndef _AT91_GENERIC_H
#define _AT91_GENERIC_H
-#include <linux/clkdev.h>
#include <linux/of.h>
#include <linux/reboot.h>
@@ -23,71 +22,19 @@ extern void __init at91_init_sram(int bank, unsigned long base,
/* Processors */
extern void __init at91rm9200_set_type(int type);
-extern void __init at91_initialize(unsigned long main_clock);
-extern void __init at91x40_initialize(unsigned long main_clock);
extern void __init at91rm9200_dt_initialize(void);
extern void __init at91_dt_initialize(void);
/* Interrupts */
-extern void __init at91_init_irq_default(void);
-extern void __init at91_init_interrupts(unsigned int priority[]);
-extern void __init at91x40_init_interrupts(unsigned int priority[]);
-extern void __init at91_aic_init(unsigned int priority[],
- unsigned int ext_irq_mask);
-extern int __init at91_aic_of_init(struct device_node *node,
- struct device_node *parent);
-extern int __init at91_aic5_of_init(struct device_node *node,
- struct device_node *parent);
extern void __init at91_sysirq_mask_rtc(u32 rtc_base);
extern void __init at91_sysirq_mask_rtt(u32 rtt_base);
- /* Devices */
-extern void __init at91_register_devices(void);
-
/* Timer */
-extern void __init at91_init_time(void);
-extern void at91rm9200_ioremap_st(u32 addr);
extern void at91rm9200_timer_init(void);
-extern void at91sam926x_ioremap_pit(u32 addr);
-extern void at91sam926x_pit_init(int irq);
-extern void at91x40_timer_init(void);
-
- /* Clocks */
-#ifdef CONFIG_OLD_CLK_AT91
-extern int __init at91_clock_init(unsigned long main_clock);
-extern int __init at91_dt_clock_init(void);
-#else
-static int inline at91_clock_init(unsigned long main_clock) { return 0; }
-static int inline at91_dt_clock_init(void) { return 0; }
-#endif
-struct device;
-
- /* Power Management */
-extern void at91_irq_suspend(void);
-extern void at91_irq_resume(void);
/* idle */
extern void at91sam9_idle(void);
/* Matrix */
extern void at91_ioremap_matrix(u32 base_addr);
-
-/* Ram Controler */
-extern void at91_ioremap_ramc(int id, u32 addr, u32 size);
-
- /* GPIO */
-#define AT91RM9200_PQFP 3 /* AT91RM9200 PQFP package has 3 banks */
-#define AT91RM9200_BGA 4 /* AT91RM9200 BGA package has 4 banks */
-
-struct at91_gpio_bank {
- unsigned short id; /* peripheral ID */
- unsigned long regbase; /* offset from system peripheral base */
-};
-extern void __init at91_gpio_init(struct at91_gpio_bank *, int nr_banks);
-extern void __init at91_gpio_irq_setup(void);
-extern int __init at91_gpio_of_irq_setup(struct device_node *node,
- struct device_node *parent);
-
-extern u32 at91_get_extern_irq(void);
-
#endif /* _AT91_GENERIC_H */
diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c
deleted file mode 100644
index d3f05aa..0000000
--- a/arch/arm/mach-at91/gpio.c
+++ /dev/null
@@ -1,982 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/gpio.c
- *
- * Copyright (C) 2005 HP Labs
- *
- * 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/errno.h>
-#include <linux/device.h>
-#include <linux/gpio.h>
-#include <linux/interrupt.h>
-#include <linux/irq.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/io.h>
-#include <linux/irqdomain.h>
-#include <linux/irqchip/chained_irq.h>
-#include <linux/of_address.h>
-
-#include <mach/hardware.h>
-#include <mach/at91_pio.h>
-
-#include "generic.h"
-#include "gpio.h"
-
-#define MAX_NB_GPIO_PER_BANK 32
-
-struct at91_gpio_chip {
- struct gpio_chip chip;
- struct at91_gpio_chip *next; /* Bank sharing same clock */
- int pioc_hwirq; /* PIO bank interrupt identifier on AIC */
- int pioc_virq; /* PIO bank Linux virtual interrupt */
- int pioc_idx; /* PIO bank index */
- void __iomem *regbase; /* PIO bank virtual address */
- struct clk *clock; /* associated clock */
- struct irq_domain *domain; /* associated irq domain */
-};
-
-#define to_at91_gpio_chip(c) container_of(c, struct at91_gpio_chip, chip)
-
-static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset);
-static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip);
-static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val);
-static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset);
-static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset);
-static int at91_gpiolib_direction_output(struct gpio_chip *chip,
- unsigned offset, int val);
-static int at91_gpiolib_direction_input(struct gpio_chip *chip,
- unsigned offset);
-static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset);
-
-#define AT91_GPIO_CHIP(name) \
- { \
- .chip = { \
- .label = name, \
- .request = at91_gpiolib_request, \
- .get_direction = at91_gpiolib_get_direction, \
- .direction_input = at91_gpiolib_direction_input, \
- .direction_output = at91_gpiolib_direction_output, \
- .get = at91_gpiolib_get, \
- .set = at91_gpiolib_set, \
- .dbg_show = at91_gpiolib_dbg_show, \
- .to_irq = at91_gpiolib_to_irq, \
- .ngpio = MAX_NB_GPIO_PER_BANK, \
- }, \
- }
-
-static struct at91_gpio_chip gpio_chip[] = {
- AT91_GPIO_CHIP("pioA"),
- AT91_GPIO_CHIP("pioB"),
- AT91_GPIO_CHIP("pioC"),
- AT91_GPIO_CHIP("pioD"),
- AT91_GPIO_CHIP("pioE"),
-};
-
-static int gpio_banks;
-static unsigned long at91_gpio_caps;
-
-/* All PIO controllers support PIO3 features */
-#define AT91_GPIO_CAP_PIO3 (1 << 0)
-
-#define has_pio3() (at91_gpio_caps & AT91_GPIO_CAP_PIO3)
-
-/*--------------------------------------------------------------------------*/
-
-static inline void __iomem *pin_to_controller(unsigned pin)
-{
- pin /= MAX_NB_GPIO_PER_BANK;
- if (likely(pin < gpio_banks))
- return gpio_chip[pin].regbase;
-
- return NULL;
-}
-
-static inline unsigned pin_to_mask(unsigned pin)
-{
- return 1 << (pin % MAX_NB_GPIO_PER_BANK);
-}
-
-
-static char peripheral_function(void __iomem *pio, unsigned mask)
-{
- char ret = 'X';
- u8 select;
-
- if (pio) {
- if (has_pio3()) {
- select = !!(__raw_readl(pio + PIO_ABCDSR1) & mask);
- select |= (!!(__raw_readl(pio + PIO_ABCDSR2) & mask) << 1);
- ret = 'A' + select;
- } else {
- ret = __raw_readl(pio + PIO_ABSR) & mask ?
- 'B' : 'A';
- }
- }
-
- return ret;
-}
-
-/*--------------------------------------------------------------------------*/
-
-/* Not all hardware capabilities are exposed through these calls; they
- * only encapsulate the most common features and modes. (So if you
- * want to change signals in groups, do it directly.)
- *
- * Bootloaders will usually handle some of the pin multiplexing setup.
- * The intent is certainly that by the time Linux is fully booted, all
- * pins should have been fully initialized. These setup calls should
- * only be used by board setup routines, or possibly in driver probe().
- *
- * For bootloaders doing all that setup, these calls could be inlined
- * as NOPs so Linux won't duplicate any setup code
- */
-
-
-/*
- * mux the pin to the "GPIO" peripheral role.
- */
-int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
- __raw_writel(mask, pio + PIO_PER);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_GPIO_periph);
-
-
-/*
- * mux the pin to the "A" internal peripheral role.
- */
-int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
-
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
- if (has_pio3()) {
- __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask,
- pio + PIO_ABCDSR1);
- __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
- pio + PIO_ABCDSR2);
- } else {
- __raw_writel(mask, pio + PIO_ASR);
- }
- __raw_writel(mask, pio + PIO_PDR);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_A_periph);
-
-
-/*
- * mux the pin to the "B" internal peripheral role.
- */
-int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
-
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
- if (has_pio3()) {
- __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask,
- pio + PIO_ABCDSR1);
- __raw_writel(__raw_readl(pio + PIO_ABCDSR2) & ~mask,
- pio + PIO_ABCDSR2);
- } else {
- __raw_writel(mask, pio + PIO_BSR);
- }
- __raw_writel(mask, pio + PIO_PDR);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_B_periph);
-
-
-/*
- * mux the pin to the "C" internal peripheral role.
- */
-int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio || !has_pio3())
- return -EINVAL;
-
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
- __raw_writel(__raw_readl(pio + PIO_ABCDSR1) & ~mask, pio + PIO_ABCDSR1);
- __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
- __raw_writel(mask, pio + PIO_PDR);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_C_periph);
-
-
-/*
- * mux the pin to the "D" internal peripheral role.
- */
-int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio || !has_pio3())
- return -EINVAL;
-
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
- __raw_writel(__raw_readl(pio + PIO_ABCDSR1) | mask, pio + PIO_ABCDSR1);
- __raw_writel(__raw_readl(pio + PIO_ABCDSR2) | mask, pio + PIO_ABCDSR2);
- __raw_writel(mask, pio + PIO_PDR);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_D_periph);
-
-
-/*
- * mux the pin to the gpio controller (instead of "A", "B", "C"
- * or "D" peripheral), and configure it for an input.
- */
-int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
-
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + (use_pullup ? PIO_PUER : PIO_PUDR));
- __raw_writel(mask, pio + PIO_ODR);
- __raw_writel(mask, pio + PIO_PER);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_gpio_input);
-
-
-/*
- * mux the pin to the gpio controller (instead of "A", "B", "C"
- * or "D" peripheral), and configure it for an output.
- */
-int __init_or_module at91_set_gpio_output(unsigned pin, int value)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
-
- __raw_writel(mask, pio + PIO_IDR);
- __raw_writel(mask, pio + PIO_PUDR);
- __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR));
- __raw_writel(mask, pio + PIO_OER);
- __raw_writel(mask, pio + PIO_PER);
- return 0;
-}
-EXPORT_SYMBOL(at91_set_gpio_output);
-
-
-/*
- * enable/disable the glitch filter; mostly used with IRQ handling.
- */
-int __init_or_module at91_set_deglitch(unsigned pin, int is_on)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
-
- if (has_pio3() && is_on)
- __raw_writel(mask, pio + PIO_IFSCDR);
- __raw_writel(mask, pio + (is_on ? PIO_IFER : PIO_IFDR));
- return 0;
-}
-EXPORT_SYMBOL(at91_set_deglitch);
-
-/*
- * enable/disable the debounce filter;
- */
-int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio || !has_pio3())
- return -EINVAL;
-
- if (is_on) {
- __raw_writel(mask, pio + PIO_IFSCER);
- __raw_writel(div & PIO_SCDR_DIV, pio + PIO_SCDR);
- __raw_writel(mask, pio + PIO_IFER);
- } else {
- __raw_writel(mask, pio + PIO_IFDR);
- }
- return 0;
-}
-EXPORT_SYMBOL(at91_set_debounce);
-
-/*
- * enable/disable the multi-driver; This is only valid for output and
- * allows the output pin to run as an open collector output.
- */
-int __init_or_module at91_set_multi_drive(unsigned pin, int is_on)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
-
- __raw_writel(mask, pio + (is_on ? PIO_MDER : PIO_MDDR));
- return 0;
-}
-EXPORT_SYMBOL(at91_set_multi_drive);
-
-/*
- * enable/disable the pull-down.
- * If pull-up already enabled while calling the function, we disable it.
- */
-int __init_or_module at91_set_pulldown(unsigned pin, int is_on)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio || !has_pio3())
- return -EINVAL;
-
- /* Disable pull-up anyway */
- __raw_writel(mask, pio + PIO_PUDR);
- __raw_writel(mask, pio + (is_on ? PIO_PPDER : PIO_PPDDR));
- return 0;
-}
-EXPORT_SYMBOL(at91_set_pulldown);
-
-/*
- * disable Schmitt trigger
- */
-int __init_or_module at91_disable_schmitt_trig(unsigned pin)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio || !has_pio3())
- return -EINVAL;
-
- __raw_writel(__raw_readl(pio + PIO_SCHMITT) | mask, pio + PIO_SCHMITT);
- return 0;
-}
-EXPORT_SYMBOL(at91_disable_schmitt_trig);
-
-/*
- * assuming the pin is muxed as a gpio output, set its value.
- */
-int at91_set_gpio_value(unsigned pin, int value)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (!pio)
- return -EINVAL;
- __raw_writel(mask, pio + (value ? PIO_SODR : PIO_CODR));
- return 0;
-}
-EXPORT_SYMBOL(at91_set_gpio_value);
-
-
-/*
- * read the pin's value (works even if it's not muxed as a gpio).
- */
-int at91_get_gpio_value(unsigned pin)
-{
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
- u32 pdsr;
-
- if (!pio)
- return -EINVAL;
- pdsr = __raw_readl(pio + PIO_PDSR);
- return (pdsr & mask) != 0;
-}
-EXPORT_SYMBOL(at91_get_gpio_value);
-
-/*--------------------------------------------------------------------------*/
-
-#ifdef CONFIG_PM
-
-static u32 wakeups[MAX_GPIO_BANKS];
-static u32 backups[MAX_GPIO_BANKS];
-
-static int gpio_irq_set_wake(struct irq_data *d, unsigned state)
-{
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
- unsigned mask = 1 << d->hwirq;
- unsigned bank = at91_gpio->pioc_idx;
-
- if (unlikely(bank >= MAX_GPIO_BANKS))
- return -EINVAL;
-
- if (state)
- wakeups[bank] |= mask;
- else
- wakeups[bank] &= ~mask;
-
- irq_set_irq_wake(at91_gpio->pioc_virq, state);
-
- return 0;
-}
-
-void at91_gpio_suspend(void)
-{
- int i;
-
- for (i = 0; i < gpio_banks; i++) {
- void __iomem *pio = gpio_chip[i].regbase;
-
- backups[i] = __raw_readl(pio + PIO_IMR);
- __raw_writel(backups[i], pio + PIO_IDR);
- __raw_writel(wakeups[i], pio + PIO_IER);
-
- if (!wakeups[i]) {
- clk_unprepare(gpio_chip[i].clock);
- clk_disable(gpio_chip[i].clock);
- } else {
-#ifdef CONFIG_PM_DEBUG
- printk(KERN_DEBUG "GPIO-%c may wake for %08x\n", 'A'+i, wakeups[i]);
-#endif
- }
- }
-}
-
-void at91_gpio_resume(void)
-{
- int i;
-
- for (i = 0; i < gpio_banks; i++) {
- void __iomem *pio = gpio_chip[i].regbase;
-
- if (!wakeups[i]) {
- if (clk_prepare(gpio_chip[i].clock) == 0)
- clk_enable(gpio_chip[i].clock);
- }
-
- __raw_writel(wakeups[i], pio + PIO_IDR);
- __raw_writel(backups[i], pio + PIO_IER);
- }
-}
-
-#else
-#define gpio_irq_set_wake NULL
-#endif
-
-
-/* Several AIC controller irqs are dispatched through this GPIO handler.
- * To use any AT91_PIN_* as an externally triggered IRQ, first call
- * at91_set_gpio_input() then maybe enable its glitch filter.
- * Then just request_irq() with the pin ID; it works like any ARM IRQ
- * handler.
- * First implementation always triggers on rising and falling edges
- * whereas the newer PIO3 can be additionally configured to trigger on
- * level, edge with any polarity.
- *
- * Alternatively, certain pins may be used directly as IRQ0..IRQ6 after
- * configuring them with at91_set_a_periph() or at91_set_b_periph().
- * IRQ0..IRQ6 should be configurable, e.g. level vs edge triggering.
- */
-
-static void gpio_irq_mask(struct irq_data *d)
-{
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << d->hwirq;
-
- if (pio)
- __raw_writel(mask, pio + PIO_IDR);
-}
-
-static void gpio_irq_unmask(struct irq_data *d)
-{
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << d->hwirq;
-
- if (pio)
- __raw_writel(mask, pio + PIO_IER);
-}
-
-static int gpio_irq_type(struct irq_data *d, unsigned type)
-{
- switch (type) {
- case IRQ_TYPE_NONE:
- case IRQ_TYPE_EDGE_BOTH:
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-/* Alternate irq type for PIO3 support */
-static int alt_gpio_irq_type(struct irq_data *d, unsigned type)
-{
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(d);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << d->hwirq;
-
- switch (type) {
- case IRQ_TYPE_EDGE_RISING:
- __raw_writel(mask, pio + PIO_ESR);
- __raw_writel(mask, pio + PIO_REHLSR);
- break;
- case IRQ_TYPE_EDGE_FALLING:
- __raw_writel(mask, pio + PIO_ESR);
- __raw_writel(mask, pio + PIO_FELLSR);
- break;
- case IRQ_TYPE_LEVEL_LOW:
- __raw_writel(mask, pio + PIO_LSR);
- __raw_writel(mask, pio + PIO_FELLSR);
- break;
- case IRQ_TYPE_LEVEL_HIGH:
- __raw_writel(mask, pio + PIO_LSR);
- __raw_writel(mask, pio + PIO_REHLSR);
- break;
- case IRQ_TYPE_EDGE_BOTH:
- /*
- * disable additional interrupt modes:
- * fall back to default behavior
- */
- __raw_writel(mask, pio + PIO_AIMDR);
- return 0;
- case IRQ_TYPE_NONE:
- default:
- pr_warn("AT91: No type for irq %d\n", gpio_to_irq(d->irq));
- return -EINVAL;
- }
-
- /* enable additional interrupt modes */
- __raw_writel(mask, pio + PIO_AIMER);
-
- return 0;
-}
-
-static struct irq_chip gpio_irqchip = {
- .name = "GPIO",
- .irq_disable = gpio_irq_mask,
- .irq_mask = gpio_irq_mask,
- .irq_unmask = gpio_irq_unmask,
- /* .irq_set_type is set dynamically */
- .irq_set_wake = gpio_irq_set_wake,
-};
-
-static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
-{
- struct irq_chip *chip = irq_desc_get_chip(desc);
- struct irq_data *idata = irq_desc_get_irq_data(desc);
- struct at91_gpio_chip *at91_gpio = irq_data_get_irq_chip_data(idata);
- void __iomem *pio = at91_gpio->regbase;
- unsigned long isr;
- int n;
-
- chained_irq_enter(chip, desc);
- for (;;) {
- /* Reading ISR acks pending (edge triggered) GPIO interrupts.
- * When there none are pending, we're finished unless we need
- * to process multiple banks (like ID_PIOCDE on sam9263).
- */
- isr = __raw_readl(pio + PIO_ISR) & __raw_readl(pio + PIO_IMR);
- if (!isr) {
- if (!at91_gpio->next)
- break;
- at91_gpio = at91_gpio->next;
- pio = at91_gpio->regbase;
- continue;
- }
-
- n = find_first_bit(&isr, BITS_PER_LONG);
- while (n < BITS_PER_LONG) {
- generic_handle_irq(irq_find_mapping(at91_gpio->domain, n));
- n = find_next_bit(&isr, BITS_PER_LONG, n + 1);
- }
- }
- chained_irq_exit(chip, desc);
- /* now it may re-trigger */
-}
-
-/*--------------------------------------------------------------------------*/
-
-#ifdef CONFIG_DEBUG_FS
-
-static void gpio_printf(struct seq_file *s, void __iomem *pio, unsigned mask)
-{
- char *trigger = NULL;
- char *polarity = NULL;
-
- if (__raw_readl(pio + PIO_IMR) & mask) {
- if (!has_pio3() || !(__raw_readl(pio + PIO_AIMMR) & mask )) {
- trigger = "edge";
- polarity = "both";
- } else {
- if (__raw_readl(pio + PIO_ELSR) & mask) {
- trigger = "level";
- polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
- "high" : "low";
- } else {
- trigger = "edge";
- polarity = __raw_readl(pio + PIO_FRLHSR) & mask ?
- "rising" : "falling";
- }
- }
- seq_printf(s, "IRQ:%s-%s\t", trigger, polarity);
- } else {
- seq_printf(s, "GPIO:%s\t\t",
- __raw_readl(pio + PIO_PDSR) & mask ? "1" : "0");
- }
-}
-
-static int at91_gpio_show(struct seq_file *s, void *unused)
-{
- int bank, j;
-
- /* print heading */
- seq_printf(s, "Pin\t");
- for (bank = 0; bank < gpio_banks; bank++) {
- seq_printf(s, "PIO%c\t\t", 'A' + bank);
- };
- seq_printf(s, "\n\n");
-
- /* print pin status */
- for (j = 0; j < 32; j++) {
- seq_printf(s, "%i:\t", j);
-
- for (bank = 0; bank < gpio_banks; bank++) {
- unsigned pin = (32 * bank) + j;
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
-
- if (__raw_readl(pio + PIO_PSR) & mask)
- gpio_printf(s, pio, mask);
- else
- seq_printf(s, "%c\t\t",
- peripheral_function(pio, mask));
- }
-
- seq_printf(s, "\n");
- }
-
- return 0;
-}
-
-static int at91_gpio_open(struct inode *inode, struct file *file)
-{
- return single_open(file, at91_gpio_show, NULL);
-}
-
-static const struct file_operations at91_gpio_operations = {
- .open = at91_gpio_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
-};
-
-static int __init at91_gpio_debugfs_init(void)
-{
- /* /sys/kernel/debug/at91_gpio */
- (void) debugfs_create_file("at91_gpio", S_IFREG | S_IRUGO, NULL, NULL, &at91_gpio_operations);
- return 0;
-}
-postcore_initcall(at91_gpio_debugfs_init);
-
-#endif
-
-/*--------------------------------------------------------------------------*/
-
-/*
- * This lock class tells lockdep that GPIO irqs are in a different
- * category than their parents, so it won't report false recursion.
- */
-static struct lock_class_key gpio_lock_class;
-
-/*
- * irqdomain initialization: pile up irqdomains on top of AIC range
- */
-static void __init at91_gpio_irqdomain(struct at91_gpio_chip *at91_gpio)
-{
- int irq_base;
-
- irq_base = irq_alloc_descs(-1, 0, at91_gpio->chip.ngpio, 0);
- if (irq_base < 0)
- panic("at91_gpio.%d: error %d: couldn't allocate IRQ numbers.\n",
- at91_gpio->pioc_idx, irq_base);
- at91_gpio->domain = irq_domain_add_legacy(NULL, at91_gpio->chip.ngpio,
- irq_base, 0,
- &irq_domain_simple_ops, NULL);
- if (!at91_gpio->domain)
- panic("at91_gpio.%d: couldn't allocate irq domain.\n",
- at91_gpio->pioc_idx);
-}
-
-/*
- * Called from the processor-specific init to enable GPIO interrupt support.
- */
-void __init at91_gpio_irq_setup(void)
-{
- unsigned pioc;
- int gpio_irqnbr = 0;
- struct at91_gpio_chip *this, *prev;
-
- /* Setup proper .irq_set_type function */
- if (has_pio3())
- gpio_irqchip.irq_set_type = alt_gpio_irq_type;
- else
- gpio_irqchip.irq_set_type = gpio_irq_type;
-
- for (pioc = 0, this = gpio_chip, prev = NULL;
- pioc++ < gpio_banks;
- prev = this, this++) {
- int offset;
-
- __raw_writel(~0, this->regbase + PIO_IDR);
-
- /* setup irq domain for this GPIO controller */
- at91_gpio_irqdomain(this);
-
- for (offset = 0; offset < this->chip.ngpio; offset++) {
- unsigned int virq = irq_find_mapping(this->domain, offset);
- irq_set_lockdep_class(virq, &gpio_lock_class);
-
- /*
- * Can use the "simple" and not "edge" handler since it's
- * shorter, and the AIC handles interrupts sanely.
- */
- irq_set_chip_and_handler(virq, &gpio_irqchip,
- handle_simple_irq);
- set_irq_flags(virq, IRQF_VALID);
- irq_set_chip_data(virq, this);
-
- gpio_irqnbr++;
- }
-
- /* The toplevel handler handles one bank of GPIOs, except
- * on some SoC it can handles up to three...
- * We only set up the handler for the first of the list.
- */
- if (prev && prev->next == this)
- continue;
-
- this->pioc_virq = irq_create_mapping(NULL, this->pioc_hwirq);
- irq_set_chip_data(this->pioc_virq, this);
- irq_set_chained_handler(this->pioc_virq, gpio_irq_handler);
- }
- pr_info("AT91: %d gpio irqs in %d banks\n", gpio_irqnbr, gpio_banks);
-}
-
-/* gpiolib support */
-static int at91_gpiolib_request(struct gpio_chip *chip, unsigned offset)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << offset;
-
- __raw_writel(mask, pio + PIO_PER);
- return 0;
-}
-
-static int at91_gpiolib_get_direction(struct gpio_chip *chip, unsigned offset)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << offset;
- u32 osr;
-
- osr = __raw_readl(pio + PIO_OSR);
- return !(osr & mask);
-}
-
-static int at91_gpiolib_direction_input(struct gpio_chip *chip,
- unsigned offset)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << offset;
-
- __raw_writel(mask, pio + PIO_ODR);
- return 0;
-}
-
-static int at91_gpiolib_direction_output(struct gpio_chip *chip,
- unsigned offset, int val)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << offset;
-
- __raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
- __raw_writel(mask, pio + PIO_OER);
- return 0;
-}
-
-static int at91_gpiolib_get(struct gpio_chip *chip, unsigned offset)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << offset;
- u32 pdsr;
-
- pdsr = __raw_readl(pio + PIO_PDSR);
- return (pdsr & mask) != 0;
-}
-
-static void at91_gpiolib_set(struct gpio_chip *chip, unsigned offset, int val)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- void __iomem *pio = at91_gpio->regbase;
- unsigned mask = 1 << offset;
-
- __raw_writel(mask, pio + (val ? PIO_SODR : PIO_CODR));
-}
-
-static void at91_gpiolib_dbg_show(struct seq_file *s, struct gpio_chip *chip)
-{
- int i;
-
- for (i = 0; i < chip->ngpio; i++) {
- unsigned pin = chip->base + i;
- void __iomem *pio = pin_to_controller(pin);
- unsigned mask = pin_to_mask(pin);
- const char *gpio_label;
-
- gpio_label = gpiochip_is_requested(chip, i);
- if (gpio_label) {
- seq_printf(s, "[%s] GPIO%s%d: ",
- gpio_label, chip->label, i);
- if (__raw_readl(pio + PIO_PSR) & mask)
- seq_printf(s, "[gpio] %s\n",
- at91_get_gpio_value(pin) ?
- "set" : "clear");
- else
- seq_printf(s, "[periph %c]\n",
- peripheral_function(pio, mask));
- }
- }
-}
-
-static int at91_gpiolib_to_irq(struct gpio_chip *chip, unsigned offset)
-{
- struct at91_gpio_chip *at91_gpio = to_at91_gpio_chip(chip);
- int virq;
-
- if (offset < chip->ngpio)
- virq = irq_create_mapping(at91_gpio->domain, offset);
- else
- virq = -ENXIO;
-
- dev_dbg(chip->dev, "%s: request IRQ for GPIO %d, return %d\n",
- chip->label, offset + chip->base, virq);
- return virq;
-}
-
-static int __init at91_gpio_setup_clk(int idx)
-{
- struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
-
- /* retreive PIO controller's clock */
- at91_gpio->clock = clk_get_sys(NULL, at91_gpio->chip.label);
- if (IS_ERR(at91_gpio->clock)) {
- pr_err("at91_gpio.%d, failed to get clock, ignoring.\n", idx);
- goto err;
- }
-
- if (clk_prepare(at91_gpio->clock))
- goto clk_prep_err;
-
- /* enable PIO controller's clock */
- if (clk_enable(at91_gpio->clock)) {
- pr_err("at91_gpio.%d, failed to enable clock, ignoring.\n", idx);
- goto clk_err;
- }
-
- return 0;
-
-clk_err:
- clk_unprepare(at91_gpio->clock);
-clk_prep_err:
- clk_put(at91_gpio->clock);
-err:
- return -EINVAL;
-}
-
-static void __init at91_gpio_init_one(int idx, u32 regbase, int pioc_hwirq)
-{
- struct at91_gpio_chip *at91_gpio = &gpio_chip[idx];
-
- at91_gpio->chip.base = idx * MAX_NB_GPIO_PER_BANK;
- at91_gpio->pioc_hwirq = pioc_hwirq;
- at91_gpio->pioc_idx = idx;
-
- at91_gpio->regbase = ioremap(regbase, 512);
- if (!at91_gpio->regbase) {
- pr_err("at91_gpio.%d, failed to map registers, ignoring.\n", idx);
- return;
- }
-
- if (at91_gpio_setup_clk(idx))
- goto ioremap_err;
-
- gpio_banks = max(gpio_banks, idx + 1);
- return;
-
-ioremap_err:
- iounmap(at91_gpio->regbase);
-}
-
-/*
- * Called from the processor-specific init to enable GPIO pin support.
- */
-void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
-{
- unsigned i;
- struct at91_gpio_chip *at91_gpio, *last = NULL;
-
- BUG_ON(nr_banks > MAX_GPIO_BANKS);
-
- if (of_have_populated_dt())
- return;
-
- for (i = 0; i < nr_banks; i++)
- at91_gpio_init_one(i, data[i].regbase, data[i].id);
-
- for (i = 0; i < gpio_banks; i++) {
- at91_gpio = &gpio_chip[i];
-
- /*
- * GPIO controller are grouped on some SoC:
- * PIOC, PIOD and PIOE can share the same IRQ line
- */
- if (last && last->pioc_hwirq == at91_gpio->pioc_hwirq)
- last->next = at91_gpio;
- last = at91_gpio;
-
- gpiochip_add(&at91_gpio->chip);
- }
-}
diff --git a/arch/arm/mach-at91/gpio.h b/arch/arm/mach-at91/gpio.h
deleted file mode 100644
index eed465a..0000000
--- a/arch/arm/mach-at91/gpio.h
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/gpio.h
- *
- * Copyright (C) 2005 HP Labs
- *
- * 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 __ASM_ARCH_AT91RM9200_GPIO_H
-#define __ASM_ARCH_AT91RM9200_GPIO_H
-
-#include <linux/kernel.h>
-#include <asm/irq.h>
-
-#define MAX_GPIO_BANKS 5
-#define NR_BUILTIN_GPIO (MAX_GPIO_BANKS * 32)
-
-/* these pin numbers double as IRQ numbers, like AT91xxx_ID_* values */
-
-#define AT91_PIN_PA0 (0x00 + 0)
-#define AT91_PIN_PA1 (0x00 + 1)
-#define AT91_PIN_PA2 (0x00 + 2)
-#define AT91_PIN_PA3 (0x00 + 3)
-#define AT91_PIN_PA4 (0x00 + 4)
-#define AT91_PIN_PA5 (0x00 + 5)
-#define AT91_PIN_PA6 (0x00 + 6)
-#define AT91_PIN_PA7 (0x00 + 7)
-#define AT91_PIN_PA8 (0x00 + 8)
-#define AT91_PIN_PA9 (0x00 + 9)
-#define AT91_PIN_PA10 (0x00 + 10)
-#define AT91_PIN_PA11 (0x00 + 11)
-#define AT91_PIN_PA12 (0x00 + 12)
-#define AT91_PIN_PA13 (0x00 + 13)
-#define AT91_PIN_PA14 (0x00 + 14)
-#define AT91_PIN_PA15 (0x00 + 15)
-#define AT91_PIN_PA16 (0x00 + 16)
-#define AT91_PIN_PA17 (0x00 + 17)
-#define AT91_PIN_PA18 (0x00 + 18)
-#define AT91_PIN_PA19 (0x00 + 19)
-#define AT91_PIN_PA20 (0x00 + 20)
-#define AT91_PIN_PA21 (0x00 + 21)
-#define AT91_PIN_PA22 (0x00 + 22)
-#define AT91_PIN_PA23 (0x00 + 23)
-#define AT91_PIN_PA24 (0x00 + 24)
-#define AT91_PIN_PA25 (0x00 + 25)
-#define AT91_PIN_PA26 (0x00 + 26)
-#define AT91_PIN_PA27 (0x00 + 27)
-#define AT91_PIN_PA28 (0x00 + 28)
-#define AT91_PIN_PA29 (0x00 + 29)
-#define AT91_PIN_PA30 (0x00 + 30)
-#define AT91_PIN_PA31 (0x00 + 31)
-
-#define AT91_PIN_PB0 (0x20 + 0)
-#define AT91_PIN_PB1 (0x20 + 1)
-#define AT91_PIN_PB2 (0x20 + 2)
-#define AT91_PIN_PB3 (0x20 + 3)
-#define AT91_PIN_PB4 (0x20 + 4)
-#define AT91_PIN_PB5 (0x20 + 5)
-#define AT91_PIN_PB6 (0x20 + 6)
-#define AT91_PIN_PB7 (0x20 + 7)
-#define AT91_PIN_PB8 (0x20 + 8)
-#define AT91_PIN_PB9 (0x20 + 9)
-#define AT91_PIN_PB10 (0x20 + 10)
-#define AT91_PIN_PB11 (0x20 + 11)
-#define AT91_PIN_PB12 (0x20 + 12)
-#define AT91_PIN_PB13 (0x20 + 13)
-#define AT91_PIN_PB14 (0x20 + 14)
-#define AT91_PIN_PB15 (0x20 + 15)
-#define AT91_PIN_PB16 (0x20 + 16)
-#define AT91_PIN_PB17 (0x20 + 17)
-#define AT91_PIN_PB18 (0x20 + 18)
-#define AT91_PIN_PB19 (0x20 + 19)
-#define AT91_PIN_PB20 (0x20 + 20)
-#define AT91_PIN_PB21 (0x20 + 21)
-#define AT91_PIN_PB22 (0x20 + 22)
-#define AT91_PIN_PB23 (0x20 + 23)
-#define AT91_PIN_PB24 (0x20 + 24)
-#define AT91_PIN_PB25 (0x20 + 25)
-#define AT91_PIN_PB26 (0x20 + 26)
-#define AT91_PIN_PB27 (0x20 + 27)
-#define AT91_PIN_PB28 (0x20 + 28)
-#define AT91_PIN_PB29 (0x20 + 29)
-#define AT91_PIN_PB30 (0x20 + 30)
-#define AT91_PIN_PB31 (0x20 + 31)
-
-#define AT91_PIN_PC0 (0x40 + 0)
-#define AT91_PIN_PC1 (0x40 + 1)
-#define AT91_PIN_PC2 (0x40 + 2)
-#define AT91_PIN_PC3 (0x40 + 3)
-#define AT91_PIN_PC4 (0x40 + 4)
-#define AT91_PIN_PC5 (0x40 + 5)
-#define AT91_PIN_PC6 (0x40 + 6)
-#define AT91_PIN_PC7 (0x40 + 7)
-#define AT91_PIN_PC8 (0x40 + 8)
-#define AT91_PIN_PC9 (0x40 + 9)
-#define AT91_PIN_PC10 (0x40 + 10)
-#define AT91_PIN_PC11 (0x40 + 11)
-#define AT91_PIN_PC12 (0x40 + 12)
-#define AT91_PIN_PC13 (0x40 + 13)
-#define AT91_PIN_PC14 (0x40 + 14)
-#define AT91_PIN_PC15 (0x40 + 15)
-#define AT91_PIN_PC16 (0x40 + 16)
-#define AT91_PIN_PC17 (0x40 + 17)
-#define AT91_PIN_PC18 (0x40 + 18)
-#define AT91_PIN_PC19 (0x40 + 19)
-#define AT91_PIN_PC20 (0x40 + 20)
-#define AT91_PIN_PC21 (0x40 + 21)
-#define AT91_PIN_PC22 (0x40 + 22)
-#define AT91_PIN_PC23 (0x40 + 23)
-#define AT91_PIN_PC24 (0x40 + 24)
-#define AT91_PIN_PC25 (0x40 + 25)
-#define AT91_PIN_PC26 (0x40 + 26)
-#define AT91_PIN_PC27 (0x40 + 27)
-#define AT91_PIN_PC28 (0x40 + 28)
-#define AT91_PIN_PC29 (0x40 + 29)
-#define AT91_PIN_PC30 (0x40 + 30)
-#define AT91_PIN_PC31 (0x40 + 31)
-
-#define AT91_PIN_PD0 (0x60 + 0)
-#define AT91_PIN_PD1 (0x60 + 1)
-#define AT91_PIN_PD2 (0x60 + 2)
-#define AT91_PIN_PD3 (0x60 + 3)
-#define AT91_PIN_PD4 (0x60 + 4)
-#define AT91_PIN_PD5 (0x60 + 5)
-#define AT91_PIN_PD6 (0x60 + 6)
-#define AT91_PIN_PD7 (0x60 + 7)
-#define AT91_PIN_PD8 (0x60 + 8)
-#define AT91_PIN_PD9 (0x60 + 9)
-#define AT91_PIN_PD10 (0x60 + 10)
-#define AT91_PIN_PD11 (0x60 + 11)
-#define AT91_PIN_PD12 (0x60 + 12)
-#define AT91_PIN_PD13 (0x60 + 13)
-#define AT91_PIN_PD14 (0x60 + 14)
-#define AT91_PIN_PD15 (0x60 + 15)
-#define AT91_PIN_PD16 (0x60 + 16)
-#define AT91_PIN_PD17 (0x60 + 17)
-#define AT91_PIN_PD18 (0x60 + 18)
-#define AT91_PIN_PD19 (0x60 + 19)
-#define AT91_PIN_PD20 (0x60 + 20)
-#define AT91_PIN_PD21 (0x60 + 21)
-#define AT91_PIN_PD22 (0x60 + 22)
-#define AT91_PIN_PD23 (0x60 + 23)
-#define AT91_PIN_PD24 (0x60 + 24)
-#define AT91_PIN_PD25 (0x60 + 25)
-#define AT91_PIN_PD26 (0x60 + 26)
-#define AT91_PIN_PD27 (0x60 + 27)
-#define AT91_PIN_PD28 (0x60 + 28)
-#define AT91_PIN_PD29 (0x60 + 29)
-#define AT91_PIN_PD30 (0x60 + 30)
-#define AT91_PIN_PD31 (0x60 + 31)
-
-#define AT91_PIN_PE0 (0x80 + 0)
-#define AT91_PIN_PE1 (0x80 + 1)
-#define AT91_PIN_PE2 (0x80 + 2)
-#define AT91_PIN_PE3 (0x80 + 3)
-#define AT91_PIN_PE4 (0x80 + 4)
-#define AT91_PIN_PE5 (0x80 + 5)
-#define AT91_PIN_PE6 (0x80 + 6)
-#define AT91_PIN_PE7 (0x80 + 7)
-#define AT91_PIN_PE8 (0x80 + 8)
-#define AT91_PIN_PE9 (0x80 + 9)
-#define AT91_PIN_PE10 (0x80 + 10)
-#define AT91_PIN_PE11 (0x80 + 11)
-#define AT91_PIN_PE12 (0x80 + 12)
-#define AT91_PIN_PE13 (0x80 + 13)
-#define AT91_PIN_PE14 (0x80 + 14)
-#define AT91_PIN_PE15 (0x80 + 15)
-#define AT91_PIN_PE16 (0x80 + 16)
-#define AT91_PIN_PE17 (0x80 + 17)
-#define AT91_PIN_PE18 (0x80 + 18)
-#define AT91_PIN_PE19 (0x80 + 19)
-#define AT91_PIN_PE20 (0x80 + 20)
-#define AT91_PIN_PE21 (0x80 + 21)
-#define AT91_PIN_PE22 (0x80 + 22)
-#define AT91_PIN_PE23 (0x80 + 23)
-#define AT91_PIN_PE24 (0x80 + 24)
-#define AT91_PIN_PE25 (0x80 + 25)
-#define AT91_PIN_PE26 (0x80 + 26)
-#define AT91_PIN_PE27 (0x80 + 27)
-#define AT91_PIN_PE28 (0x80 + 28)
-#define AT91_PIN_PE29 (0x80 + 29)
-#define AT91_PIN_PE30 (0x80 + 30)
-#define AT91_PIN_PE31 (0x80 + 31)
-
-#ifndef __ASSEMBLY__
-/* setup setup routines, called from board init or driver probe() */
-extern int __init_or_module at91_set_GPIO_periph(unsigned pin, int use_pullup);
-extern int __init_or_module at91_set_A_periph(unsigned pin, int use_pullup);
-extern int __init_or_module at91_set_B_periph(unsigned pin, int use_pullup);
-extern int __init_or_module at91_set_C_periph(unsigned pin, int use_pullup);
-extern int __init_or_module at91_set_D_periph(unsigned pin, int use_pullup);
-extern int __init_or_module at91_set_gpio_input(unsigned pin, int use_pullup);
-extern int __init_or_module at91_set_gpio_output(unsigned pin, int value);
-extern int __init_or_module at91_set_deglitch(unsigned pin, int is_on);
-extern int __init_or_module at91_set_debounce(unsigned pin, int is_on, int div);
-extern int __init_or_module at91_set_multi_drive(unsigned pin, int is_on);
-extern int __init_or_module at91_set_pulldown(unsigned pin, int is_on);
-extern int __init_or_module at91_disable_schmitt_trig(unsigned pin);
-
-/* callable at any time */
-extern int at91_set_gpio_value(unsigned pin, int value);
-extern int at91_get_gpio_value(unsigned pin);
-
-/* callable only from core power-management code */
-extern void at91_gpio_suspend(void);
-extern void at91_gpio_resume(void);
-
-#endif /* __ASSEMBLY__ */
-
-#endif
diff --git a/arch/arm/mach-at91/gsia18s.h b/arch/arm/mach-at91/gsia18s.h
deleted file mode 100644
index 307c194..0000000
--- a/arch/arm/mach-at91/gsia18s.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/* Buttons */
-#define GPIO_TRIG_NET_IN AT91_PIN_PB21
-#define GPIO_CARD_UNMOUNT_0 AT91_PIN_PB13
-#define GPIO_CARD_UNMOUNT_1 AT91_PIN_PB12
-#define GPIO_KEY_POWER AT91_PIN_PA25
-
-/* PCF8574 0x20 GPIO - U1 on the GS_IA18-CB_V3 board */
-#define GS_IA18_S_PCF_GPIO_BASE0 NR_BUILTIN_GPIO
-#define PCF_GPIO_HDC_POWER (GS_IA18_S_PCF_GPIO_BASE0 + 0)
-#define PCF_GPIO_WIFI_SETUP (GS_IA18_S_PCF_GPIO_BASE0 + 1)
-#define PCF_GPIO_WIFI_ENABLE (GS_IA18_S_PCF_GPIO_BASE0 + 2)
-#define PCF_GPIO_WIFI_RESET (GS_IA18_S_PCF_GPIO_BASE0 + 3)
-#define PCF_GPIO_ETH_DETECT 4 /* this is a GPI */
-#define PCF_GPIO_GPS_SETUP (GS_IA18_S_PCF_GPIO_BASE0 + 5)
-#define PCF_GPIO_GPS_STANDBY (GS_IA18_S_PCF_GPIO_BASE0 + 6)
-#define PCF_GPIO_GPS_POWER (GS_IA18_S_PCF_GPIO_BASE0 + 7)
-
-/* PCF8574 0x22 GPIO - U1 on the GS_2G_OPT1-A_V0 board (Alarm) */
-#define GS_IA18_S_PCF_GPIO_BASE1 (GS_IA18_S_PCF_GPIO_BASE0 + 8)
-#define PCF_GPIO_ALARM1 (GS_IA18_S_PCF_GPIO_BASE1 + 0)
-#define PCF_GPIO_ALARM2 (GS_IA18_S_PCF_GPIO_BASE1 + 1)
-#define PCF_GPIO_ALARM3 (GS_IA18_S_PCF_GPIO_BASE1 + 2)
-#define PCF_GPIO_ALARM4 (GS_IA18_S_PCF_GPIO_BASE1 + 3)
-/* bits 4, 5, 6 not used */
-#define PCF_GPIO_ALARM_V_RELAY_ON (GS_IA18_S_PCF_GPIO_BASE1 + 7)
-
-/* PCF8574 0x24 GPIO U1 on the GS_2G-OPT23-A_V0 board (Modem) */
-#define GS_IA18_S_PCF_GPIO_BASE2 (GS_IA18_S_PCF_GPIO_BASE1 + 8)
-#define PCF_GPIO_MODEM_POWER (GS_IA18_S_PCF_GPIO_BASE2 + 0)
-#define PCF_GPIO_MODEM_RESET (GS_IA18_S_PCF_GPIO_BASE2 + 3)
-/* bits 1, 2, 4, 5 not used */
-#define PCF_GPIO_TRX_RESET (GS_IA18_S_PCF_GPIO_BASE2 + 6)
-/* bit 7 not used */
diff --git a/arch/arm/mach-at91/include/mach/at91_dbgu.h b/arch/arm/mach-at91/include/mach/at91_dbgu.h
index 3b59485..42925e8 100644
--- a/arch/arm/mach-at91/include/mach/at91_dbgu.h
+++ b/arch/arm/mach-at91/include/mach/at91_dbgu.h
@@ -16,7 +16,6 @@
#ifndef AT91_DBGU_H
#define AT91_DBGU_H
-#if !defined(CONFIG_ARCH_AT91X40)
#define AT91_DBGU_CR (0x00) /* Control Register */
#define AT91_DBGU_MR (0x04) /* Mode Register */
#define AT91_DBGU_IER (0x08) /* Interrupt Enable Register */
@@ -34,8 +33,6 @@
#define AT91_DBGU_FNR (0x48) /* Force NTRST Register [SAM9 only] */
#define AT91_DBGU_FNTRST (1 << 0) /* Force NTRST */
-#endif /* AT91_DBGU */
-
/*
* Some AT91 parts that don't have full DEBUG units still support the ID
* and extensions register.
diff --git a/arch/arm/mach-at91/include/mach/at91_ramc.h b/arch/arm/mach-at91/include/mach/at91_ramc.h
index d8aeb27..e4492b1 100644
--- a/arch/arm/mach-at91/include/mach/at91_ramc.h
+++ b/arch/arm/mach-at91/include/mach/at91_ramc.h
@@ -25,8 +25,8 @@ extern void __iomem *at91_ramc_base[];
#define AT91_MEMCTRL_SDRAMC 1
#define AT91_MEMCTRL_DDRSDR 2
-#include <mach/at91rm9200_sdramc.h>
-#include <mach/at91sam9_ddrsdr.h>
-#include <mach/at91sam9_sdramc.h>
+#include <soc/at91/at91rm9200_sdramc.h>
+#include <soc/at91/at91sam9_ddrsdr.h>
+#include <soc/at91/at91sam9_sdramc.h>
#endif /* __AT91_RAMC_H__ */
diff --git a/arch/arm/mach-at91/include/mach/at91x40.h b/arch/arm/mach-at91/include/mach/at91x40.h
deleted file mode 100644
index 38dca2b..0000000
--- a/arch/arm/mach-at91/include/mach/at91x40.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * arch/arm/mach-at91/include/mach/at91x40.h
- *
- * (C) Copyright 2007, Greg Ungerer <gerg@snapgear.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 AT91X40_H
-#define AT91X40_H
-
-/*
- * IRQ list.
- */
-#define AT91X40_ID_USART0 2 /* USART port 0 */
-#define AT91X40_ID_USART1 3 /* USART port 1 */
-#define AT91X40_ID_TC0 4 /* Timer/Counter 0 */
-#define AT91X40_ID_TC1 5 /* Timer/Counter 1*/
-#define AT91X40_ID_TC2 6 /* Timer/Counter 2*/
-#define AT91X40_ID_WD 7 /* Watchdog? */
-#define AT91X40_ID_PIOA 8 /* Parallel IO Controller A */
-
-#define AT91X40_ID_IRQ0 16 /* External IRQ 0 */
-#define AT91X40_ID_IRQ1 17 /* External IRQ 1 */
-#define AT91X40_ID_IRQ2 18 /* External IRQ 2 */
-
-/*
- * System Peripherals
- */
-#define AT91_BASE_SYS 0xffc00000
-
-#define AT91_EBI 0xffe00000 /* External Bus Interface */
-#define AT91_SF 0xfff00000 /* Special Function */
-#define AT91_USART1 0xfffcc000 /* USART 1 */
-#define AT91_USART0 0xfffd0000 /* USART 0 */
-#define AT91_TC 0xfffe0000 /* Timer Counter */
-#define AT91_PIOA 0xffff0000 /* PIO Controller A */
-#define AT91_PS 0xffff4000 /* Power Save */
-#define AT91_WD 0xffff8000 /* Watchdog Timer */
-
-/*
- * The AT91x40 series doesn't have a debug unit like the other AT91 parts.
- * But it does have a chip identify register and extension ID, so define at
- * least these here.
- */
-#define AT91_DBGU_CIDR (AT91_SF + 0) /* CIDR in PS segment */
-#define AT91_DBGU_EXID (AT91_SF + 4) /* EXID in PS segment */
-
-/*
- * Support defines for the simple Power Controller module.
- */
-#define AT91_PS_CR (AT91_PS + 0) /* PS Control register */
-#define AT91_PS_CR_CPU (1 << 0) /* CPU clock disable bit */
-
-#define AT91X40_MASTER_CLOCK 40000000
-
-#endif /* AT91X40_H */
diff --git a/arch/arm/mach-at91/include/mach/cpu.h b/arch/arm/mach-at91/include/mach/cpu.h
index b27e9ca..61914fb 100644
--- a/arch/arm/mach-at91/include/mach/cpu.h
+++ b/arch/arm/mach-at91/include/mach/cpu.h
@@ -62,7 +62,6 @@
#define ARCH_EXID_SAMA5D43 0x00000003
#define ARCH_EXID_SAMA5D44 0x00000004
-#define ARCH_FAMILY_AT91X92 0x09200000
#define ARCH_FAMILY_AT91SAM9 0x01900000
#define ARCH_FAMILY_AT91SAM9XE 0x02900000
diff --git a/arch/arm/mach-at91/include/mach/hardware.h b/arch/arm/mach-at91/include/mach/hardware.h
index c137973..cacbaa5 100644
--- a/arch/arm/mach-at91/include/mach/hardware.h
+++ b/arch/arm/mach-at91/include/mach/hardware.h
@@ -24,9 +24,6 @@
/* sama5d4 */
#define AT91_BASE_DBGU2 0xfc069000
-#if defined(CONFIG_ARCH_AT91X40)
-#include <mach/at91x40.h>
-#else
#include <mach/at91rm9200.h>
#include <mach/at91sam9260.h>
#include <mach/at91sam9261.h>
@@ -51,8 +48,6 @@
*/
#define AT91_BASE_SYS 0xffffc000
-#endif
-
/*
* On sama5d4 there is no system controller, we map some needed peripherals
*/
@@ -132,13 +127,8 @@
* called as part of the generic suspend/resume path.
*/
#ifndef __ASSEMBLY__
-#ifdef CONFIG_PINCTRL_AT91
extern void at91_pinctrl_gpio_suspend(void);
extern void at91_pinctrl_gpio_resume(void);
-#else
-static inline void at91_pinctrl_gpio_suspend(void) {}
-static inline void at91_pinctrl_gpio_resume(void) {}
-#endif
#endif
#endif
diff --git a/arch/arm/mach-at91/include/mach/uncompress.h b/arch/arm/mach-at91/include/mach/uncompress.h
index acb2d890..4ebb609 100644
--- a/arch/arm/mach-at91/include/mach/uncompress.h
+++ b/arch/arm/mach-at91/include/mach/uncompress.h
@@ -31,7 +31,6 @@
void __iomem *at91_uart;
-#if !defined(CONFIG_ARCH_AT91X40)
static const u32 uarts_rm9200[] = {
AT91_BASE_DBGU0,
AT91RM9200_BASE_US0,
@@ -188,12 +187,6 @@ static inline void arch_decomp_setup(void)
at91_uart = NULL;
}
-#else
-static inline void arch_decomp_setup(void)
-{
- at91_uart = NULL;
-}
-#endif
/*
* The following code assumes the serial port has already been
diff --git a/arch/arm/mach-at91/irq.c b/arch/arm/mach-at91/irq.c
deleted file mode 100644
index cdb3ec9..0000000
--- a/arch/arm/mach-at91/irq.c
+++ /dev/null
@@ -1,296 +0,0 @@
-/*
- * linux/arch/arm/mach-at91/irq.c
- *
- * Copyright (C) 2004 SAN People
- * Copyright (C) 2004 ATMEL
- * Copyright (C) Rick Bronson
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/bitmap.h>
-#include <linux/types.h>
-#include <linux/irq.h>
-#include <linux/of.h>
-#include <linux/of_address.h>
-#include <linux/of_irq.h>
-#include <linux/irqdomain.h>
-#include <linux/err.h>
-#include <linux/slab.h>
-
-#include <mach/hardware.h>
-#include <asm/irq.h>
-#include <asm/setup.h>
-
-#include <asm/exception.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/irq.h>
-#include <asm/mach/map.h>
-
-#include "at91_aic.h"
-
-void __iomem *at91_aic_base;
-static struct irq_domain *at91_aic_domain;
-static struct device_node *at91_aic_np;
-static unsigned int n_irqs = NR_AIC_IRQS;
-
-#ifdef CONFIG_PM
-
-static unsigned long *wakeups;
-static unsigned long *backups;
-
-#define set_backup(bit) set_bit(bit, backups)
-#define clear_backup(bit) clear_bit(bit, backups)
-
-static int at91_aic_pm_init(void)
-{
- backups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
- if (!backups)
- return -ENOMEM;
-
- wakeups = kzalloc(BITS_TO_LONGS(n_irqs) * sizeof(*backups), GFP_KERNEL);
- if (!wakeups) {
- kfree(backups);
- return -ENOMEM;
- }
-
- return 0;
-}
-
-static int at91_aic_set_wake(struct irq_data *d, unsigned value)
-{
- if (unlikely(d->hwirq >= n_irqs))
- return -EINVAL;
-
- if (value)
- set_bit(d->hwirq, wakeups);
- else
- clear_bit(d->hwirq, wakeups);
-
- return 0;
-}
-
-void at91_irq_suspend(void)
-{
- at91_aic_write(AT91_AIC_IDCR, *backups);
- at91_aic_write(AT91_AIC_IECR, *wakeups);
-}
-
-void at91_irq_resume(void)
-{
- at91_aic_write(AT91_AIC_IDCR, *wakeups);
- at91_aic_write(AT91_AIC_IECR, *backups);
-}
-
-#else
-static inline int at91_aic_pm_init(void)
-{
- return 0;
-}
-
-#define set_backup(bit)
-#define clear_backup(bit)
-#define at91_aic_set_wake NULL
-
-#endif /* CONFIG_PM */
-
-asmlinkage void __exception_irq_entry
-at91_aic_handle_irq(struct pt_regs *regs)
-{
- u32 irqnr;
- u32 irqstat;
-
- irqnr = at91_aic_read(AT91_AIC_IVR);
- irqstat = at91_aic_read(AT91_AIC_ISR);
-
- /*
- * ISR value is 0 when there is no current interrupt or when there is
- * a spurious interrupt
- */
- if (!irqstat)
- at91_aic_write(AT91_AIC_EOICR, 0);
- else
- handle_IRQ(irqnr, regs);
-}
-
-static void at91_aic_mask_irq(struct irq_data *d)
-{
- /* Disable interrupt on AIC */
- at91_aic_write(AT91_AIC_IDCR, 1 << d->hwirq);
- /* Update ISR cache */
- clear_backup(d->hwirq);
-}
-
-static void at91_aic_unmask_irq(struct irq_data *d)
-{
- /* Enable interrupt on AIC */
- at91_aic_write(AT91_AIC_IECR, 1 << d->hwirq);
- /* Update ISR cache */
- set_backup(d->hwirq);
-}
-
-static void at91_aic_eoi(struct irq_data *d)
-{
- /*
- * Mark end-of-interrupt on AIC, the controller doesn't care about
- * the value written. Moreover it's a write-only register.
- */
- at91_aic_write(AT91_AIC_EOICR, 0);
-}
-
-static unsigned long *at91_extern_irq;
-
-u32 at91_get_extern_irq(void)
-{
- if (!at91_extern_irq)
- return 0;
- return *at91_extern_irq;
-}
-
-#define is_extern_irq(hwirq) test_bit(hwirq, at91_extern_irq)
-
-static int at91_aic_compute_srctype(struct irq_data *d, unsigned type)
-{
- int srctype;
-
- switch (type) {
- case IRQ_TYPE_LEVEL_HIGH:
- srctype = AT91_AIC_SRCTYPE_HIGH;
- break;
- case IRQ_TYPE_EDGE_RISING:
- srctype = AT91_AIC_SRCTYPE_RISING;
- break;
- case IRQ_TYPE_LEVEL_LOW:
- if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
- srctype = AT91_AIC_SRCTYPE_LOW;
- else
- srctype = -EINVAL;
- break;
- case IRQ_TYPE_EDGE_FALLING:
- if ((d->hwirq == AT91_ID_FIQ) || is_extern_irq(d->hwirq)) /* only supported on external interrupts */
- srctype = AT91_AIC_SRCTYPE_FALLING;
- else
- srctype = -EINVAL;
- break;
- default:
- srctype = -EINVAL;
- }
-
- return srctype;
-}
-
-static int at91_aic_set_type(struct irq_data *d, unsigned type)
-{
- unsigned int smr;
- int srctype;
-
- srctype = at91_aic_compute_srctype(d, type);
- if (srctype < 0)
- return srctype;
-
- smr = at91_aic_read(AT91_AIC_SMR(d->hwirq)) & ~AT91_AIC_SRCTYPE;
- at91_aic_write(AT91_AIC_SMR(d->hwirq), smr | srctype);
-
- return 0;
-}
-
-static struct irq_chip at91_aic_chip = {
- .name = "AIC",
- .irq_mask = at91_aic_mask_irq,
- .irq_unmask = at91_aic_unmask_irq,
- .irq_set_type = at91_aic_set_type,
- .irq_set_wake = at91_aic_set_wake,
- .irq_eoi = at91_aic_eoi,
-};
-
-static void __init at91_aic_hw_init(unsigned int spu_vector)
-{
- int i;
-
- /*
- * Perform 8 End Of Interrupt Command to make sure AIC
- * will not Lock out nIRQ
- */
- for (i = 0; i < 8; i++)
- at91_aic_write(AT91_AIC_EOICR, 0);
-
- /*
- * Spurious Interrupt ID in Spurious Vector Register.
- * When there is no current interrupt, the IRQ Vector Register
- * reads the value stored in AIC_SPU
- */
- at91_aic_write(AT91_AIC_SPU, spu_vector);
-
- /* No debugging in AIC: Debug (Protect) Control Register */
- at91_aic_write(AT91_AIC_DCR, 0);
-
- /* Disable and clear all interrupts initially */
- at91_aic_write(AT91_AIC_IDCR, 0xFFFFFFFF);
- at91_aic_write(AT91_AIC_ICCR, 0xFFFFFFFF);
-}
-
-/*
- * Initialize the AIC interrupt controller.
- */
-void __init at91_aic_init(unsigned int *priority, unsigned int ext_irq_mask)
-{
- unsigned int i;
- int irq_base;
-
- at91_extern_irq = kzalloc(BITS_TO_LONGS(n_irqs)
- * sizeof(*at91_extern_irq), GFP_KERNEL);
-
- if (at91_aic_pm_init() || at91_extern_irq == NULL)
- panic("Unable to allocate bit maps\n");
-
- *at91_extern_irq = ext_irq_mask;
-
- at91_aic_base = ioremap(AT91_AIC, 512);
- if (!at91_aic_base)
- panic("Unable to ioremap AIC registers\n");
-
- /* Add irq domain for AIC */
- irq_base = irq_alloc_descs(-1, 0, n_irqs, 0);
- if (irq_base < 0) {
- WARN(1, "Cannot allocate irq_descs, assuming pre-allocated\n");
- irq_base = 0;
- }
- at91_aic_domain = irq_domain_add_legacy(at91_aic_np, n_irqs,
- irq_base, 0,
- &irq_domain_simple_ops, NULL);
-
- if (!at91_aic_domain)
- panic("Unable to add AIC irq domain\n");
-
- irq_set_default_host(at91_aic_domain);
-
- /*
- * The IVR is used by macro get_irqnr_and_base to read and verify.
- * The irq number is NR_AIC_IRQS when a spurious interrupt has occurred.
- */
- for (i = 0; i < n_irqs; i++) {
- /* Put hardware irq number in Source Vector Register: */
- at91_aic_write(AT91_AIC_SVR(i), NR_IRQS_LEGACY + i);
- /* Active Low interrupt, with the specified priority */
- at91_aic_write(AT91_AIC_SMR(i), AT91_AIC_SRCTYPE_LOW | priority[i]);
- irq_set_chip_and_handler(NR_IRQS_LEGACY + i, &at91_aic_chip, handle_fasteoi_irq);
- set_irq_flags(i, IRQF_VALID | IRQF_PROBE);
- }
-
- at91_aic_hw_init(n_irqs);
-}
diff --git a/arch/arm/mach-at91/leds.c b/arch/arm/mach-at91/leds.c
deleted file mode 100644
index eb22e33..0000000
--- a/arch/arm/mach-at91/leds.c
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
- * LED driver for Atmel AT91-based boards.
- *
- * Copyright (C) SAN People (Pty) Ltd
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
-*/
-
-#include <linux/gpio.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-
-#include "board.h"
-#include "gpio.h"
-
-
-/* ------------------------------------------------------------------------- */
-
-#if defined(CONFIG_NEW_LEDS)
-
-/*
- * New cross-platform LED support.
- */
-
-static struct gpio_led_platform_data led_data;
-
-static struct platform_device at91_gpio_leds_device = {
- .name = "leds-gpio",
- .id = -1,
- .dev.platform_data = &led_data,
-};
-
-void __init at91_gpio_leds(struct gpio_led *leds, int nr)
-{
- int i;
-
- if (!nr)
- return;
-
- for (i = 0; i < nr; i++)
- at91_set_gpio_output(leds[i].gpio, leds[i].active_low);
-
- led_data.leds = leds;
- led_data.num_leds = nr;
- platform_device_register(&at91_gpio_leds_device);
-}
-
-#else
-void __init at91_gpio_leds(struct gpio_led *leds, int nr) {}
-#endif
-
diff --git a/arch/arm/mach-at91/pm.c b/arch/arm/mach-at91/pm.c
index 4073ab7..9b15169 100644
--- a/arch/arm/mach-at91/pm.c
+++ b/arch/arm/mach-at91/pm.c
@@ -29,10 +29,8 @@
#include <mach/cpu.h>
#include <mach/hardware.h>
-#include "at91_aic.h"
#include "generic.h"
#include "pm.h"
-#include "gpio.h"
static void (*at91_pm_standby)(void);
@@ -131,23 +129,7 @@ extern u32 at91_slow_clock_sz;
static int at91_pm_enter(suspend_state_t state)
{
- if (of_have_populated_dt())
- at91_pinctrl_gpio_suspend();
- else
- at91_gpio_suspend();
-
- if (IS_ENABLED(CONFIG_OLD_IRQ_AT91) && at91_aic_base) {
- at91_irq_suspend();
-
- pr_debug("AT91: PM - wake mask %08x, pm state %d\n",
- /* remember all the always-wake irqs */
- (at91_pmc_read(AT91_PMC_PCSR)
- | (1 << AT91_ID_FIQ)
- | (1 << AT91_ID_SYS)
- | (at91_get_extern_irq()))
- & at91_aic_read(AT91_AIC_IMR),
- state);
- }
+ at91_pinctrl_gpio_suspend();
switch (state) {
/*
@@ -212,21 +194,10 @@ static int at91_pm_enter(suspend_state_t state)
goto error;
}
- if (IS_ENABLED(CONFIG_OLD_IRQ_AT91) && at91_aic_base)
- pr_debug("AT91: PM - wakeup %08x\n",
- at91_aic_read(AT91_AIC_IPR) &
- at91_aic_read(AT91_AIC_IMR));
-
error:
target_state = PM_SUSPEND_ON;
- if (IS_ENABLED(CONFIG_OLD_IRQ_AT91) && at91_aic_base)
- at91_irq_resume();
-
- if (of_have_populated_dt())
- at91_pinctrl_gpio_resume();
- else
- at91_gpio_resume();
+ at91_pinctrl_gpio_resume();
return 0;
}
diff --git a/arch/arm/mach-at91/pm.h b/arch/arm/mach-at91/pm.h
index c5101dc..d2c8996 100644
--- a/arch/arm/mach-at91/pm.h
+++ b/arch/arm/mach-at91/pm.h
@@ -14,7 +14,6 @@
#include <asm/proc-fns.h>
#include <mach/at91_ramc.h>
-#include <mach/at91rm9200_sdramc.h>
#ifdef CONFIG_PM
extern void at91_pm_set_standby(void (*at91_standby)(void));
diff --git a/arch/arm/mach-at91/setup.c b/arch/arm/mach-at91/setup.c
index 9610792..ce25e85 100644
--- a/arch/arm/mach-at91/setup.c
+++ b/arch/arm/mach-at91/setup.c
@@ -42,35 +42,9 @@ void __init at91rm9200_set_type(int type)
at91_get_soc_subtype(&at91_soc_initdata));
}
-void __init at91_init_irq_default(void)
-{
- at91_init_interrupts(at91_boot_soc.default_irq_priority);
-}
-
-void __init at91_init_interrupts(unsigned int *priority)
-{
- /* Initialize the AIC interrupt controller */
- if (IS_ENABLED(CONFIG_OLD_IRQ_AT91))
- at91_aic_init(priority, at91_boot_soc.extern_irq);
-
- /* Enable GPIO interrupts */
- at91_gpio_irq_setup();
-}
-
void __iomem *at91_ramc_base[2];
EXPORT_SYMBOL_GPL(at91_ramc_base);
-void __init at91_ioremap_ramc(int id, u32 addr, u32 size)
-{
- if (id < 0 || id > 1) {
- pr_emerg("Wrong RAM controller id (%d), cannot continue\n", id);
- BUG();
- }
- at91_ramc_base[id] = ioremap(addr, size);
- if (!at91_ramc_base[id])
- panic(pr_fmt("Impossible to ioremap ramc.%d 0x%x\n"), id, addr);
-}
-
static struct map_desc sram_desc[2] __initdata;
void __init at91_init_sram(int bank, unsigned long base, unsigned int length)
@@ -418,7 +392,6 @@ void __init at91_ioremap_matrix(u32 base_addr)
panic(pr_fmt("Impossible to ioremap at91_matrix_base\n"));
}
-#if defined(CONFIG_OF) && !defined(CONFIG_ARCH_AT91X40)
static struct of_device_id ramc_ids[] = {
{ .compatible = "atmel,at91rm9200-sdramc", .data = at91rm9200_standby },
{ .compatible = "atmel,at91sam9260-sdramc", .data = at91sam9_sdram_standby },
@@ -460,13 +433,6 @@ void __init at91rm9200_dt_initialize(void)
{
at91_dt_ramc();
- /* Init clock subsystem */
- at91_dt_clock_init();
-
- /* Register the processor-specific clocks */
- if (at91_boot_soc.register_clocks)
- at91_boot_soc.register_clocks();
-
at91_boot_soc.init();
}
@@ -474,39 +440,6 @@ void __init at91_dt_initialize(void)
{
at91_dt_ramc();
- /* Init clock subsystem */
- at91_dt_clock_init();
-
- /* Register the processor-specific clocks */
- if (at91_boot_soc.register_clocks)
- at91_boot_soc.register_clocks();
-
if (at91_boot_soc.init)
at91_boot_soc.init();
}
-#endif
-
-void __init at91_initialize(unsigned long main_clock)
-{
- at91_boot_soc.ioremap_registers();
-
- /* Init clock subsystem */
- at91_clock_init(main_clock);
-
- /* Register the processor-specific clocks */
- at91_boot_soc.register_clocks();
-
- at91_boot_soc.init();
-
- pinctrl_provide_dummies();
-}
-
-void __init at91_register_devices(void)
-{
- at91_boot_soc.register_devices();
-}
-
-void __init at91_init_time(void)
-{
- at91_boot_soc.init_time();
-}
diff --git a/arch/arm/mach-at91/soc.h b/arch/arm/mach-at91/soc.h
index 9a8fd97..ae6c0b2 100644
--- a/arch/arm/mach-at91/soc.h
+++ b/arch/arm/mach-at91/soc.h
@@ -6,14 +6,8 @@
struct at91_init_soc {
int builtin;
- u32 extern_irq;
- unsigned int *default_irq_priority;
void (*map_io)(void);
- void (*ioremap_registers)(void);
- void (*register_clocks)(void);
- void (*register_devices)(void);
void (*init)(void);
- void (*init_time)(void);
};
extern struct at91_init_soc at91_boot_soc;
diff --git a/arch/arm/mach-at91/stamp9g20.h b/arch/arm/mach-at91/stamp9g20.h
deleted file mode 100644
index f62c0ab..0000000
--- a/arch/arm/mach-at91/stamp9g20.h
+++ /dev/null
@@ -1,7 +0,0 @@
-#ifndef __MACH_STAMP9G20_H
-#define __MACH_STAMP9G20_H
-
-void stamp9g20_init_early(void);
-void stamp9g20_board_init(void);
-
-#endif
diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig
index 2abad74..aaeec78 100644
--- a/arch/arm/mach-bcm/Kconfig
+++ b/arch/arm/mach-bcm/Kconfig
@@ -5,8 +5,56 @@ menuconfig ARCH_BCM
if ARCH_BCM
+comment "IPROC architected SoCs"
+
+config ARCH_BCM_IPROC
+ bool
+ select ARM_GIC
+ select CACHE_L2X0
+ select HAVE_ARM_SCU if SMP
+ select HAVE_ARM_TWD if SMP
+ select ARM_GLOBAL_TIMER
+
+ select CLKSRC_MMIO
+ select ARCH_REQUIRE_GPIOLIB
+ select ARM_AMBA
+ select PINCTRL
+ help
+ This enables support for systems based on Broadcom IPROC architected SoCs.
+ The IPROC complex contains one or more ARM CPUs along with common
+ core periperals. Application specific SoCs are created by adding a
+ uArchitecture containing peripherals outside of the IPROC complex.
+ Currently supported SoCs are Cygnus.
+
+config ARCH_BCM_CYGNUS
+ bool "Broadcom Cygnus Support" if ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
+ help
+ Enable support for the Cygnus family,
+ which includes the following variants:
+ BCM11300, BCM11320, BCM11350, BCM11360,
+ BCM58300, BCM58302, BCM58303, BCM58305.
+
+config ARCH_BCM_5301X
+ bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
+ select ARCH_BCM_IPROC
+ help
+ Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
+
+ This is a network SoC line mostly used in home routers and
+ wifi access points, it's internal name is Northstar.
+ This inclused the following SoC: BCM53010, BCM53011, BCM53012,
+ BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707,
+ BCM4708 and BCM4709.
+
+ Do not confuse this with the BCM4760 which is a totally
+ different SoC or with the older BCM47XX and BCM53XX based
+ network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx
+
+comment "KONA architected SoCs"
+
config ARCH_BCM_MOBILE
- bool "Broadcom Mobile SoC Support" if ARCH_MULTI_V7
+ bool
select ARCH_REQUIRE_GPIOLIB
select ARM_ERRATA_754322
select ARM_ERRATA_775420
@@ -15,16 +63,13 @@ config ARCH_BCM_MOBILE
select TICK_ONESHOT
select HAVE_ARM_ARCH_TIMER
select PINCTRL
+ select ARCH_BCM_MOBILE_SMP if SMP
help
This enables support for systems based on Broadcom mobile SoCs.
-if ARCH_BCM_MOBILE
-
-menu "Broadcom Mobile SoC Selection"
-
config ARCH_BCM_281XX
bool "Broadcom BCM281XX SoC family"
- default y
+ select ARCH_BCM_MOBILE
select HAVE_SMP
help
Enable support for the BCM281XX family, which includes
@@ -33,7 +78,7 @@ config ARCH_BCM_281XX
config ARCH_BCM_21664
bool "Broadcom BCM21664 SoC family"
- default y
+ select ARCH_BCM_MOBILE
select HAVE_SMP
help
Enable support for the BCM21664 family, which includes
@@ -41,19 +86,18 @@ config ARCH_BCM_21664
config ARCH_BCM_MOBILE_L2_CACHE
bool "Broadcom mobile SoC level 2 cache support"
- depends on (ARCH_BCM_281XX || ARCH_BCM_21664)
+ depends on ARCH_BCM_MOBILE
default y
select CACHE_L2X0
select ARCH_BCM_MOBILE_SMC
config ARCH_BCM_MOBILE_SMC
bool
- depends on ARCH_BCM_281XX || ARCH_BCM_21664
+ depends on ARCH_BCM_MOBILE
config ARCH_BCM_MOBILE_SMP
- bool "Broadcom mobile SoC SMP support"
- depends on (ARCH_BCM_281XX || ARCH_BCM_21664) && SMP
- default y
+ bool
+ depends on ARCH_BCM_MOBILE
select HAVE_ARM_SCU
select ARM_ERRATA_764369
help
@@ -61,9 +105,7 @@ config ARCH_BCM_MOBILE_SMP
Provided as an option so SMP support for SoCs of this type
can be disabled for an SMP-enabled kernel.
-endmenu
-
-endif
+comment "Other Architectures"
config ARCH_BCM2835
bool "Broadcom BCM2835 family" if ARCH_MULTI_V6
@@ -78,27 +120,6 @@ config ARCH_BCM2835
This enables support for the Broadcom BCM2835 SoC. This SoC is
used in the Raspberry Pi and Roku 2 devices.
-config ARCH_BCM_5301X
- bool "Broadcom BCM470X / BCM5301X ARM SoC" if ARCH_MULTI_V7
- select ARM_GIC
- select CACHE_L2X0
- select HAVE_ARM_SCU if SMP
- select HAVE_ARM_TWD if SMP
- select ARM_GLOBAL_TIMER
- select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
- help
- Support for Broadcom BCM470X and BCM5301X SoCs with ARM CPU cores.
-
- This is a network SoC line mostly used in home routers and
- wifi access points, it's internal name is Northstar.
- This inclused the following SoC: BCM53010, BCM53011, BCM53012,
- BCM53014, BCM53015, BCM53016, BCM53017, BCM53018, BCM4707,
- BCM4708 and BCM4709.
-
- Do not confuse this with the BCM4760 which is a totally
- different SoC or with the older BCM47XX and BCM53XX based
- network SoC using a MIPS CPU, they are supported by arch/mips/bcm47xx
-
config ARCH_BCM_63XX
bool "Broadcom BCM63xx DSL SoC" if ARCH_MULTI_V7
depends on MMU
@@ -118,13 +139,11 @@ config ARCH_BCM_63XX
config ARCH_BRCMSTB
bool "Broadcom BCM7XXX based boards" if ARCH_MULTI_V7
- depends on MMU
select ARM_GIC
- select MIGHT_HAVE_PCI
- select HAVE_SMP
select HAVE_ARM_ARCH_TIMER
select BRCMSTB_GISB_ARB
select BRCMSTB_L2_IRQ
+ select BCM7120_L2_IRQ
help
Say Y if you intend to run the kernel on a Broadcom ARM-based STB
chipset.
diff --git a/arch/arm/mach-bcm/Makefile b/arch/arm/mach-bcm/Makefile
index 300ae4b..4c38674 100644
--- a/arch/arm/mach-bcm/Makefile
+++ b/arch/arm/mach-bcm/Makefile
@@ -10,6 +10,9 @@
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
+# Cygnus
+obj-$(CONFIG_ARCH_BCM_CYGNUS) += bcm_cygnus.o
+
# BCM281XX
obj-$(CONFIG_ARCH_BCM_281XX) += board_bcm281xx.o
@@ -38,5 +41,7 @@ obj-$(CONFIG_ARCH_BCM_5301X) += bcm_5301x.o
obj-$(CONFIG_ARCH_BCM_63XX) := bcm63xx.o
ifeq ($(CONFIG_ARCH_BRCMSTB),y)
+CFLAGS_platsmp-brcmstb.o += -march=armv7-a
obj-y += brcmstb.o
+obj-$(CONFIG_SMP) += headsmp-brcmstb.o platsmp-brcmstb.o
endif
diff --git a/arch/arm/mach-bcm/bcm_cygnus.c b/arch/arm/mach-bcm/bcm_cygnus.c
new file mode 100644
index 0000000..30dc58b
--- /dev/null
+++ b/arch/arm/mach-bcm/bcm_cygnus.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/mach/arch.h>
+
+static const char const *bcm_cygnus_dt_compat[] = {
+ "brcm,cygnus",
+ NULL,
+};
+
+DT_MACHINE_START(BCM_CYGNUS_DT, "Broadcom Cygnus SoC")
+ .l2c_aux_val = 0,
+ .l2c_aux_mask = ~0,
+ .dt_compat = bcm_cygnus_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-bcm/brcmstb.h b/arch/arm/mach-bcm/brcmstb.h
new file mode 100644
index 0000000..ec0c3d1
--- /dev/null
+++ b/arch/arm/mach-bcm/brcmstb.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2013-2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __BRCMSTB_H__
+#define __BRCMSTB_H__
+
+void brcmstb_secondary_startup(void);
+
+#endif /* __BRCMSTB_H__ */
diff --git a/arch/arm/mach-bcm/headsmp-brcmstb.S b/arch/arm/mach-bcm/headsmp-brcmstb.S
new file mode 100644
index 0000000..199c1ea
--- /dev/null
+++ b/arch/arm/mach-bcm/headsmp-brcmstb.S
@@ -0,0 +1,33 @@
+/*
+ * SMP boot code for secondary CPUs
+ * Based on arch/arm/mach-tegra/headsmp.S
+ *
+ * Copyright (C) 2010 NVIDIA, Inc.
+ * Copyright (C) 2013-2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <asm/assembler.h>
+#include <linux/linkage.h>
+#include <linux/init.h>
+
+ .section ".text.head", "ax"
+
+ENTRY(brcmstb_secondary_startup)
+ /*
+ * Ensure CPU is in a sane state by disabling all IRQs and switching
+ * into SVC mode.
+ */
+ setmode PSR_I_BIT | PSR_F_BIT | SVC_MODE, r0
+
+ bl v7_invalidate_l1
+ b secondary_startup
+ENDPROC(brcmstb_secondary_startup)
diff --git a/arch/arm/mach-bcm/platsmp-brcmstb.c b/arch/arm/mach-bcm/platsmp-brcmstb.c
new file mode 100644
index 0000000..31c87a2
--- /dev/null
+++ b/arch/arm/mach-bcm/platsmp-brcmstb.c
@@ -0,0 +1,329 @@
+/*
+ * Broadcom STB CPU SMP and hotplug support for ARM
+ *
+ * Copyright (C) 2013-2014 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/printk.h>
+#include <linux/regmap.h>
+#include <linux/smp.h>
+#include <linux/mfd/syscon.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cp15.h>
+#include <asm/mach-types.h>
+#include <asm/smp_plat.h>
+
+#include "brcmstb.h"
+
+enum {
+ ZONE_MAN_CLKEN_MASK = BIT(0),
+ ZONE_MAN_RESET_CNTL_MASK = BIT(1),
+ ZONE_MAN_MEM_PWR_MASK = BIT(4),
+ ZONE_RESERVED_1_MASK = BIT(5),
+ ZONE_MAN_ISO_CNTL_MASK = BIT(6),
+ ZONE_MANUAL_CONTROL_MASK = BIT(7),
+ ZONE_PWR_DN_REQ_MASK = BIT(9),
+ ZONE_PWR_UP_REQ_MASK = BIT(10),
+ ZONE_BLK_RST_ASSERT_MASK = BIT(12),
+ ZONE_PWR_OFF_STATE_MASK = BIT(25),
+ ZONE_PWR_ON_STATE_MASK = BIT(26),
+ ZONE_DPG_PWR_STATE_MASK = BIT(28),
+ ZONE_MEM_PWR_STATE_MASK = BIT(29),
+ ZONE_RESET_STATE_MASK = BIT(31),
+ CPU0_PWR_ZONE_CTRL_REG = 1,
+ CPU_RESET_CONFIG_REG = 2,
+};
+
+static void __iomem *cpubiuctrl_block;
+static void __iomem *hif_cont_block;
+static u32 cpu0_pwr_zone_ctrl_reg;
+static u32 cpu_rst_cfg_reg;
+static u32 hif_cont_reg;
+
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * We must quiesce a dying CPU before it can be killed by the boot CPU. Because
+ * one or more cache may be disabled, we must flush to ensure coherency. We
+ * cannot use traditionl completion structures or spinlocks as they rely on
+ * coherency.
+ */
+static DEFINE_PER_CPU_ALIGNED(int, per_cpu_sw_state);
+
+static int per_cpu_sw_state_rd(u32 cpu)
+{
+ sync_cache_r(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
+ return per_cpu(per_cpu_sw_state, cpu);
+}
+
+static void per_cpu_sw_state_wr(u32 cpu, int val)
+{
+ dmb();
+ per_cpu(per_cpu_sw_state, cpu) = val;
+ sync_cache_w(SHIFT_PERCPU_PTR(&per_cpu_sw_state, per_cpu_offset(cpu)));
+}
+#else
+static inline void per_cpu_sw_state_wr(u32 cpu, int val) { }
+#endif
+
+static void __iomem *pwr_ctrl_get_base(u32 cpu)
+{
+ void __iomem *base = cpubiuctrl_block + cpu0_pwr_zone_ctrl_reg;
+ base += (cpu_logical_map(cpu) * 4);
+ return base;
+}
+
+static u32 pwr_ctrl_rd(u32 cpu)
+{
+ void __iomem *base = pwr_ctrl_get_base(cpu);
+ return readl_relaxed(base);
+}
+
+static void pwr_ctrl_wr(u32 cpu, u32 val)
+{
+ void __iomem *base = pwr_ctrl_get_base(cpu);
+ writel(val, base);
+}
+
+static void cpu_rst_cfg_set(u32 cpu, int set)
+{
+ u32 val;
+ val = readl_relaxed(cpubiuctrl_block + cpu_rst_cfg_reg);
+ if (set)
+ val |= BIT(cpu_logical_map(cpu));
+ else
+ val &= ~BIT(cpu_logical_map(cpu));
+ writel_relaxed(val, cpubiuctrl_block + cpu_rst_cfg_reg);
+}
+
+static void cpu_set_boot_addr(u32 cpu, unsigned long boot_addr)
+{
+ const int reg_ofs = cpu_logical_map(cpu) * 8;
+ writel_relaxed(0, hif_cont_block + hif_cont_reg + reg_ofs);
+ writel_relaxed(boot_addr, hif_cont_block + hif_cont_reg + 4 + reg_ofs);
+}
+
+static void brcmstb_cpu_boot(u32 cpu)
+{
+ /* Mark this CPU as "up" */
+ per_cpu_sw_state_wr(cpu, 1);
+
+ /*
+ * Set the reset vector to point to the secondary_startup
+ * routine
+ */
+ cpu_set_boot_addr(cpu, virt_to_phys(brcmstb_secondary_startup));
+
+ /* Unhalt the cpu */
+ cpu_rst_cfg_set(cpu, 0);
+}
+
+static void brcmstb_cpu_power_on(u32 cpu)
+{
+ /*
+ * The secondary cores power was cut, so we must go through
+ * power-on initialization.
+ */
+ u32 tmp;
+
+ /* Request zone power up */
+ pwr_ctrl_wr(cpu, ZONE_PWR_UP_REQ_MASK);
+
+ /* Wait for the power up FSM to complete */
+ do {
+ tmp = pwr_ctrl_rd(cpu);
+ } while (!(tmp & ZONE_PWR_ON_STATE_MASK));
+}
+
+static int brcmstb_cpu_get_power_state(u32 cpu)
+{
+ int tmp = pwr_ctrl_rd(cpu);
+ return (tmp & ZONE_RESET_STATE_MASK) ? 0 : 1;
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+
+static void brcmstb_cpu_die(u32 cpu)
+{
+ v7_exit_coherency_flush(all);
+
+ per_cpu_sw_state_wr(cpu, 0);
+
+ /* Sit and wait to die */
+ wfi();
+
+ /* We should never get here... */
+ while (1)
+ ;
+}
+
+static int brcmstb_cpu_kill(u32 cpu)
+{
+ u32 tmp;
+
+ while (per_cpu_sw_state_rd(cpu))
+ ;
+
+ /* Program zone reset */
+ pwr_ctrl_wr(cpu, ZONE_RESET_STATE_MASK | ZONE_BLK_RST_ASSERT_MASK |
+ ZONE_PWR_DN_REQ_MASK);
+
+ /* Verify zone reset */
+ tmp = pwr_ctrl_rd(cpu);
+ if (!(tmp & ZONE_RESET_STATE_MASK))
+ pr_err("%s: Zone reset bit for CPU %d not asserted!\n",
+ __func__, cpu);
+
+ /* Wait for power down */
+ do {
+ tmp = pwr_ctrl_rd(cpu);
+ } while (!(tmp & ZONE_PWR_OFF_STATE_MASK));
+
+ /* Flush pipeline before resetting CPU */
+ mb();
+
+ /* Assert reset on the CPU */
+ cpu_rst_cfg_set(cpu, 1);
+
+ return 1;
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
+static int __init setup_hifcpubiuctrl_regs(struct device_node *np)
+{
+ int rc = 0;
+ char *name;
+ struct device_node *syscon_np = NULL;
+
+ name = "syscon-cpu";
+
+ syscon_np = of_parse_phandle(np, name, 0);
+ if (!syscon_np) {
+ pr_err("can't find phandle %s\n", name);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ cpubiuctrl_block = of_iomap(syscon_np, 0);
+ if (!cpubiuctrl_block) {
+ pr_err("iomap failed for cpubiuctrl_block\n");
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ rc = of_property_read_u32_index(np, name, CPU0_PWR_ZONE_CTRL_REG,
+ &cpu0_pwr_zone_ctrl_reg);
+ if (rc) {
+ pr_err("failed to read 1st entry from %s property (%d)\n", name,
+ rc);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ rc = of_property_read_u32_index(np, name, CPU_RESET_CONFIG_REG,
+ &cpu_rst_cfg_reg);
+ if (rc) {
+ pr_err("failed to read 2nd entry from %s property (%d)\n", name,
+ rc);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+cleanup:
+ of_node_put(syscon_np);
+ return rc;
+}
+
+static int __init setup_hifcont_regs(struct device_node *np)
+{
+ int rc = 0;
+ char *name;
+ struct device_node *syscon_np = NULL;
+
+ name = "syscon-cont";
+
+ syscon_np = of_parse_phandle(np, name, 0);
+ if (!syscon_np) {
+ pr_err("can't find phandle %s\n", name);
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ hif_cont_block = of_iomap(syscon_np, 0);
+ if (!hif_cont_block) {
+ pr_err("iomap failed for hif_cont_block\n");
+ rc = -EINVAL;
+ goto cleanup;
+ }
+
+ /* Offset is at top of hif_cont_block */
+ hif_cont_reg = 0;
+
+cleanup:
+ of_node_put(syscon_np);
+ return rc;
+}
+
+static void __init brcmstb_cpu_ctrl_setup(unsigned int max_cpus)
+{
+ int rc;
+ struct device_node *np;
+ char *name;
+
+ name = "brcm,brcmstb-smpboot";
+ np = of_find_compatible_node(NULL, NULL, name);
+ if (!np) {
+ pr_err("can't find compatible node %s\n", name);
+ return;
+ }
+
+ rc = setup_hifcpubiuctrl_regs(np);
+ if (rc)
+ return;
+
+ rc = setup_hifcont_regs(np);
+ if (rc)
+ return;
+}
+
+static int brcmstb_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ /* Missing the brcm,brcmstb-smpboot DT node? */
+ if (!cpubiuctrl_block || !hif_cont_block)
+ return -ENODEV;
+
+ /* Bring up power to the core if necessary */
+ if (brcmstb_cpu_get_power_state(cpu) == 0)
+ brcmstb_cpu_power_on(cpu);
+
+ brcmstb_cpu_boot(cpu);
+
+ return 0;
+}
+
+static struct smp_operations brcmstb_smp_ops __initdata = {
+ .smp_prepare_cpus = brcmstb_cpu_ctrl_setup,
+ .smp_boot_secondary = brcmstb_boot_secondary,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_kill = brcmstb_cpu_kill,
+ .cpu_die = brcmstb_cpu_die,
+#endif
+};
+
+CPU_METHOD_OF_DECLARE(brcmstb_smp, "brcm,brahma-b15", &brcmstb_smp_ops);
diff --git a/arch/arm/mach-berlin/Kconfig b/arch/arm/mach-berlin/Kconfig
index 24f85be..3e40a94 100644
--- a/arch/arm/mach-berlin/Kconfig
+++ b/arch/arm/mach-berlin/Kconfig
@@ -1,10 +1,11 @@
menuconfig ARCH_BERLIN
bool "Marvell Berlin SoCs" if ARCH_MULTI_V7
+ select ARCH_HAS_RESET_CONTROLLER
select ARCH_REQUIRE_GPIOLIB
select ARM_GIC
- select GENERIC_IRQ_CHIP
select DW_APB_ICTL
select DW_APB_TIMER_OF
+ select GENERIC_IRQ_CHIP
select PINCTRL
if ARCH_BERLIN
diff --git a/arch/arm/mach-davinci/board-da830-evm.c b/arch/arm/mach-davinci/board-da830-evm.c
index 5623131..f8f62fb 100644
--- a/arch/arm/mach-davinci/board-da830-evm.c
+++ b/arch/arm/mach-davinci/board-da830-evm.c
@@ -80,8 +80,8 @@ static int da830_evm_usb_ocic_notify(da8xx_ocic_handler_t handler)
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING,
"OHCI over-current indicator", NULL);
if (error)
- printk(KERN_ERR "%s: could not request IRQ to watch "
- "over-current indicator changes\n", __func__);
+ pr_err("%s: could not request IRQ to watch over-current indicator changes\n",
+ __func__);
} else
free_irq(irq, NULL);
@@ -145,8 +145,7 @@ static __init void da830_evm_usb_init(void)
/* USB_REFCLKIN is not used. */
ret = davinci_cfg_reg(DA830_USB0_DRVVBUS);
if (ret)
- pr_warning("%s: USB 2.0 PinMux setup failed: %d\n",
- __func__, ret);
+ pr_warn("%s: USB 2.0 PinMux setup failed: %d\n", __func__, ret);
else {
/*
* TPS2065 switch @ 5V supplies 1 A (sustains 1.5 A),
@@ -154,37 +153,35 @@ static __init void da830_evm_usb_init(void)
*/
ret = da8xx_register_usb20(1000, 3);
if (ret)
- pr_warning("%s: USB 2.0 registration failed: %d\n",
- __func__, ret);
+ pr_warn("%s: USB 2.0 registration failed: %d\n",
+ __func__, ret);
}
ret = davinci_cfg_reg_list(da830_evm_usb11_pins);
if (ret) {
- pr_warning("%s: USB 1.1 PinMux setup failed: %d\n",
- __func__, ret);
+ pr_warn("%s: USB 1.1 PinMux setup failed: %d\n", __func__, ret);
return;
}
ret = gpio_request(ON_BD_USB_DRV, "ON_BD_USB_DRV");
if (ret) {
- printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
- "power control: %d\n", __func__, ret);
+ pr_err("%s: failed to request GPIO for USB 1.1 port power control: %d\n",
+ __func__, ret);
return;
}
gpio_direction_output(ON_BD_USB_DRV, 0);
ret = gpio_request(ON_BD_USB_OVC, "ON_BD_USB_OVC");
if (ret) {
- printk(KERN_ERR "%s: failed to request GPIO for USB 1.1 port "
- "over-current indicator: %d\n", __func__, ret);
+ pr_err("%s: failed to request GPIO for USB 1.1 port over-current indicator: %d\n",
+ __func__, ret);
return;
}
gpio_direction_input(ON_BD_USB_OVC);
ret = da8xx_register_usb11(&da830_evm_usb11_pdata);
if (ret)
- pr_warning("%s: USB 1.1 registration failed: %d\n",
- __func__, ret);
+ pr_warn("%s: USB 1.1 registration failed: %d\n", __func__, ret);
}
static const short da830_evm_mcasp1_pins[] = {
@@ -252,31 +249,29 @@ static inline void da830_evm_init_mmc(void)
ret = davinci_cfg_reg_list(da830_evm_mmc_sd_pins);
if (ret) {
- pr_warning("da830_evm_init: mmc/sd mux setup failed: %d\n",
- ret);
+ pr_warn("%s: mmc/sd mux setup failed: %d\n", __func__, ret);
return;
}
ret = gpio_request(DA830_MMCSD_WP_PIN, "MMC WP");
if (ret) {
- pr_warning("da830_evm_init: can not open GPIO %d\n",
- DA830_MMCSD_WP_PIN);
+ pr_warn("%s: can not open GPIO %d\n",
+ __func__, DA830_MMCSD_WP_PIN);
return;
}
gpio_direction_input(DA830_MMCSD_WP_PIN);
ret = gpio_request(DA830_MMCSD_CD_PIN, "MMC CD\n");
if (ret) {
- pr_warning("da830_evm_init: can not open GPIO %d\n",
- DA830_MMCSD_CD_PIN);
+ pr_warn("%s: can not open GPIO %d\n",
+ __func__, DA830_MMCSD_CD_PIN);
return;
}
gpio_direction_input(DA830_MMCSD_CD_PIN);
ret = da8xx_register_mmcsd0(&da830_evm_mmc_config);
if (ret) {
- pr_warning("da830_evm_init: mmc/sd registration failed: %d\n",
- ret);
+ pr_warn("%s: mmc/sd registration failed: %d\n", __func__, ret);
gpio_free(DA830_MMCSD_WP_PIN);
}
}
@@ -404,23 +399,21 @@ static inline void da830_evm_init_nand(int mux_mode)
int ret;
if (HAS_MMC) {
- pr_warning("WARNING: both MMC/SD and NAND are "
- "enabled, but they share AEMIF pins.\n"
- "\tDisable MMC/SD for NAND support.\n");
+ pr_warn("WARNING: both MMC/SD and NAND are enabled, but they share AEMIF pins\n"
+ "\tDisable MMC/SD for NAND support\n");
return;
}
ret = davinci_cfg_reg_list(da830_evm_emif25_pins);
if (ret)
- pr_warning("da830_evm_init: emif25 mux setup failed: %d\n",
- ret);
+ pr_warn("%s: emif25 mux setup failed: %d\n", __func__, ret);
ret = platform_device_register(&da830_evm_nand_device);
if (ret)
- pr_warning("da830_evm_init: NAND device not registered.\n");
+ pr_warn("%s: NAND device not registered\n", __func__);
if (davinci_aemif_setup(&da830_evm_nand_device))
- pr_warn("%s: Cannot configure AEMIF.\n", __func__);
+ pr_warn("%s: Cannot configure AEMIF\n", __func__);
gpio_direction_output(mux_mode, 1);
}
@@ -435,12 +428,11 @@ static inline void da830_evm_init_lcdc(int mux_mode)
ret = davinci_cfg_reg_list(da830_lcdcntl_pins);
if (ret)
- pr_warning("da830_evm_init: lcdcntl mux setup failed: %d\n",
- ret);
+ pr_warn("%s: lcdcntl mux setup failed: %d\n", __func__, ret);
ret = da8xx_register_lcdc(&sharp_lcd035q3dg01_pdata);
if (ret)
- pr_warning("da830_evm_init: lcd setup failed: %d\n", ret);
+ pr_warn("%s: lcd setup failed: %d\n", __func__, ret);
gpio_direction_output(mux_mode, 0);
}
@@ -598,22 +590,19 @@ static __init void da830_evm_init(void)
ret = da830_register_gpio();
if (ret)
- pr_warn("da830_evm_init: GPIO init failed: %d\n", ret);
+ pr_warn("%s: GPIO init failed: %d\n", __func__, ret);
ret = da830_register_edma(da830_edma_rsv);
if (ret)
- pr_warning("da830_evm_init: edma registration failed: %d\n",
- ret);
+ pr_warn("%s: edma registration failed: %d\n", __func__, ret);
ret = davinci_cfg_reg_list(da830_i2c0_pins);
if (ret)
- pr_warning("da830_evm_init: i2c0 mux setup failed: %d\n",
- ret);
+ pr_warn("%s: i2c0 mux setup failed: %d\n", __func__, ret);
ret = da8xx_register_i2c(0, &da830_evm_i2c_0_pdata);
if (ret)
- pr_warning("da830_evm_init: i2c0 registration failed: %d\n",
- ret);
+ pr_warn("%s: i2c0 registration failed: %d\n", __func__, ret);
da830_evm_usb_init();
@@ -622,18 +611,16 @@ static __init void da830_evm_init(void)
ret = davinci_cfg_reg_list(da830_cpgmac_pins);
if (ret)
- pr_warning("da830_evm_init: cpgmac mux setup failed: %d\n",
- ret);
+ pr_warn("%s: cpgmac mux setup failed: %d\n", __func__, ret);
ret = da8xx_register_emac();
if (ret)
- pr_warning("da830_evm_init: emac registration failed: %d\n",
- ret);
+ pr_warn("%s: emac registration failed: %d\n", __func__, ret);
ret = da8xx_register_watchdog();
if (ret)
- pr_warning("da830_evm_init: watchdog registration failed: %d\n",
- ret);
+ pr_warn("%s: watchdog registration failed: %d\n",
+ __func__, ret);
davinci_serial_init(da8xx_serial_device);
i2c_register_board_info(1, da830_evm_i2c_devices,
@@ -641,8 +628,7 @@ static __init void da830_evm_init(void)
ret = davinci_cfg_reg_list(da830_evm_mcasp1_pins);
if (ret)
- pr_warning("da830_evm_init: mcasp1 mux setup failed: %d\n",
- ret);
+ pr_warn("%s: mcasp1 mux setup failed: %d\n", __func__, ret);
da8xx_register_mcasp(1, &da830_evm_snd_data);
@@ -650,18 +636,17 @@ static __init void da830_evm_init(void)
ret = da8xx_register_rtc();
if (ret)
- pr_warning("da830_evm_init: rtc setup failed: %d\n", ret);
+ pr_warn("%s: rtc setup failed: %d\n", __func__, ret);
ret = spi_register_board_info(da830evm_spi_info,
ARRAY_SIZE(da830evm_spi_info));
if (ret)
- pr_warn("%s: spi info registration failed: %d\n", __func__,
- ret);
+ pr_warn("%s: spi info registration failed: %d\n",
+ __func__, ret);
ret = da8xx_register_spi_bus(0, ARRAY_SIZE(da830evm_spi_info));
if (ret)
- pr_warning("da830_evm_init: spi 0 registration failed: %d\n",
- ret);
+ pr_warn("%s: spi 0 registration failed: %d\n", __func__, ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-da850-evm.c b/arch/arm/mach-davinci/board-da850-evm.c
index fa11415..6b5a97d 100644
--- a/arch/arm/mach-davinci/board-da850-evm.c
+++ b/arch/arm/mach-davinci/board-da850-evm.c
@@ -452,8 +452,7 @@ static void da850_evm_ui_keys_init(unsigned gpio)
for (i = 0; i < DA850_N_UI_PB; i++) {
button = &da850_evm_ui_keys[i];
button->code = KEY_F8 - i;
- button->desc = (char *)
- da850_evm_ui_exp[DA850_EVM_UI_EXP_PB8 + i];
+ button->desc = da850_evm_ui_exp[DA850_EVM_UI_EXP_PB8 + i];
button->gpio = gpio + DA850_EVM_UI_EXP_PB8 + i;
}
}
@@ -628,15 +627,13 @@ static void da850_evm_bb_keys_init(unsigned gpio)
struct gpio_keys_button *button;
button = &da850_evm_bb_keys[0];
- button->desc = (char *)
- da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_PB1];
+ button->desc = da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_PB1];
button->gpio = gpio + DA850_EVM_BB_EXP_USER_PB1;
for (i = 0; i < DA850_N_BB_USER_SW; i++) {
button = &da850_evm_bb_keys[i + 1];
button->code = SW_LID + i;
- button->desc = (char *)
- da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_SW1 + i];
+ button->desc = da850_evm_bb_exp[DA850_EVM_BB_EXP_USER_SW1 + i];
button->gpio = gpio + DA850_EVM_BB_EXP_USER_SW1 + i;
}
}
diff --git a/arch/arm/mach-davinci/board-dm355-evm.c b/arch/arm/mach-davinci/board-dm355-evm.c
index 06d63d5..b46b4d2 100644
--- a/arch/arm/mach-davinci/board-dm355-evm.c
+++ b/arch/arm/mach-davinci/board-dm355-evm.c
@@ -294,7 +294,7 @@ static struct vpbe_output dm355evm_vpbe_outputs[] = {
.default_mode = "ntsc",
.num_modes = ARRAY_SIZE(dm355evm_enc_preset_timing),
.modes = dm355evm_enc_preset_timing,
- .if_params = V4L2_MBUS_FMT_FIXED,
+ .if_params = MEDIA_BUS_FMT_FIXED,
},
};
diff --git a/arch/arm/mach-davinci/board-dm365-evm.c b/arch/arm/mach-davinci/board-dm365-evm.c
index e08a868..a756003 100644
--- a/arch/arm/mach-davinci/board-dm365-evm.c
+++ b/arch/arm/mach-davinci/board-dm365-evm.c
@@ -485,7 +485,7 @@ static struct vpbe_output dm365evm_vpbe_outputs[] = {
.default_mode = "ntsc",
.num_modes = ARRAY_SIZE(dm365evm_enc_std_timing),
.modes = dm365evm_enc_std_timing,
- .if_params = V4L2_MBUS_FMT_FIXED,
+ .if_params = MEDIA_BUS_FMT_FIXED,
},
{
.output = {
@@ -498,7 +498,7 @@ static struct vpbe_output dm365evm_vpbe_outputs[] = {
.default_mode = "480p59_94",
.num_modes = ARRAY_SIZE(dm365evm_enc_preset_timing),
.modes = dm365evm_enc_preset_timing,
- .if_params = V4L2_MBUS_FMT_FIXED,
+ .if_params = MEDIA_BUS_FMT_FIXED,
},
};
diff --git a/arch/arm/mach-davinci/board-dm644x-evm.c b/arch/arm/mach-davinci/board-dm644x-evm.c
index e583e58..1a0898c 100644
--- a/arch/arm/mach-davinci/board-dm644x-evm.c
+++ b/arch/arm/mach-davinci/board-dm644x-evm.c
@@ -767,9 +767,8 @@ static __init void davinci_evm_init(void)
if (HAS_ATA) {
if (HAS_NAND || HAS_NOR)
- pr_warning("WARNING: both IDE and Flash are "
- "enabled, but they share AEMIF pins.\n"
- "\tDisable IDE for NAND/NOR support.\n");
+ pr_warn("WARNING: both IDE and Flash are enabled, but they share AEMIF pins\n"
+ "\tDisable IDE for NAND/NOR support\n");
davinci_init_ide();
} else if (HAS_NAND || HAS_NOR) {
davinci_cfg_reg(DM644X_HPIEN_DISABLE);
@@ -780,13 +779,12 @@ static __init void davinci_evm_init(void)
platform_device_register(&davinci_evm_nandflash_device);
if (davinci_aemif_setup(&davinci_evm_nandflash_device))
- pr_warn("%s: Cannot configure AEMIF.\n",
+ pr_warn("%s: Cannot configure AEMIF\n",
__func__);
evm_leds[7].default_trigger = "nand-disk";
if (HAS_NOR)
- pr_warning("WARNING: both NAND and NOR flash "
- "are enabled; disable one of them.\n");
+ pr_warn("WARNING: both NAND and NOR flash are enabled; disable one of them.\n");
} else if (HAS_NOR)
platform_device_register(&davinci_evm_norflash_device);
}
diff --git a/arch/arm/mach-davinci/board-mityomapl138.c b/arch/arm/mach-davinci/board-mityomapl138.c
index 96fc00a..8cfbfe0 100644
--- a/arch/arm/mach-davinci/board-mityomapl138.c
+++ b/arch/arm/mach-davinci/board-mityomapl138.c
@@ -8,6 +8,8 @@
* any kind, whether express or implied.
*/
+#define pr_fmt(fmt) "MityOMAPL138: " fmt
+
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/console.h>
@@ -107,7 +109,7 @@ static void mityomapl138_cpufreq_init(const char *partnum)
ret = da850_register_cpufreq("pll0_sysclk3");
if (ret)
- pr_warning("cpufreq registration failed: %d\n", ret);
+ pr_warn("cpufreq registration failed: %d\n", ret);
}
#else
static void mityomapl138_cpufreq_init(const char *partnum) { }
@@ -121,33 +123,31 @@ static void read_factory_config(struct memory_accessor *a, void *context)
ret = a->read(a, (char *)&factory_config, 0, sizeof(factory_config));
if (ret != sizeof(struct factory_config)) {
- pr_warning("MityOMAPL138: Read Factory Config Failed: %d\n",
- ret);
+ pr_warn("Read Factory Config Failed: %d\n", ret);
goto bad_config;
}
if (factory_config.magic != FACTORY_CONFIG_MAGIC) {
- pr_warning("MityOMAPL138: Factory Config Magic Wrong (%X)\n",
- factory_config.magic);
+ pr_warn("Factory Config Magic Wrong (%X)\n",
+ factory_config.magic);
goto bad_config;
}
if (factory_config.version != FACTORY_CONFIG_VERSION) {
- pr_warning("MityOMAPL138: Factory Config Version Wrong (%X)\n",
- factory_config.version);
+ pr_warn("Factory Config Version Wrong (%X)\n",
+ factory_config.version);
goto bad_config;
}
- pr_info("MityOMAPL138: Found MAC = %pM\n", factory_config.mac);
+ pr_info("Found MAC = %pM\n", factory_config.mac);
if (is_valid_ether_addr(factory_config.mac))
memcpy(soc_info->emac_pdata->mac_addr,
factory_config.mac, ETH_ALEN);
else
- pr_warning("MityOMAPL138: Invalid MAC found "
- "in factory config block\n");
+ pr_warn("Invalid MAC found in factory config block\n");
partnum = factory_config.partnum;
- pr_info("MityOMAPL138: Part Number = %s\n", partnum);
+ pr_info("Part Number = %s\n", partnum);
bad_config:
/* default maximum speed is valid for all platforms */
@@ -435,7 +435,7 @@ static void __init mityomapl138_setup_nand(void)
ARRAY_SIZE(mityomapl138_devices));
if (davinci_aemif_setup(&mityomapl138_nandflash_device))
- pr_warn("%s: Cannot configure AEMIF.\n", __func__);
+ pr_warn("%s: Cannot configure AEMIF\n", __func__);
}
static const short mityomap_mii_pins[] = {
@@ -478,7 +478,7 @@ static void __init mityomapl138_config_emac(void)
}
if (ret) {
- pr_warning("mii/rmii mux setup failed: %d\n", ret);
+ pr_warn("mii/rmii mux setup failed: %d\n", ret);
return;
}
@@ -489,7 +489,7 @@ static void __init mityomapl138_config_emac(void)
ret = da8xx_register_emac();
if (ret)
- pr_warning("emac registration failed: %d\n", ret);
+ pr_warn("emac registration failed: %d\n", ret);
}
static struct davinci_pm_config da850_pm_pdata = {
@@ -511,21 +511,21 @@ static void __init mityomapl138_init(void)
/* for now, no special EDMA channels are reserved */
ret = da850_register_edma(NULL);
if (ret)
- pr_warning("edma registration failed: %d\n", ret);
+ pr_warn("edma registration failed: %d\n", ret);
ret = da8xx_register_watchdog();
if (ret)
- pr_warning("watchdog registration failed: %d\n", ret);
+ pr_warn("watchdog registration failed: %d\n", ret);
davinci_serial_init(da8xx_serial_device);
ret = da8xx_register_i2c(0, &mityomap_i2c_0_pdata);
if (ret)
- pr_warning("i2c0 registration failed: %d\n", ret);
+ pr_warn("i2c0 registration failed: %d\n", ret);
ret = pmic_tps65023_init();
if (ret)
- pr_warning("TPS65023 PMIC init failed: %d\n", ret);
+ pr_warn("TPS65023 PMIC init failed: %d\n", ret);
mityomapl138_setup_nand();
@@ -537,22 +537,21 @@ static void __init mityomapl138_init(void)
ret = da8xx_register_spi_bus(1,
ARRAY_SIZE(mityomapl138_spi_flash_info));
if (ret)
- pr_warning("spi 1 registration failed: %d\n", ret);
+ pr_warn("spi 1 registration failed: %d\n", ret);
mityomapl138_config_emac();
ret = da8xx_register_rtc();
if (ret)
- pr_warning("rtc setup failed: %d\n", ret);
+ pr_warn("rtc setup failed: %d\n", ret);
ret = da8xx_register_cpuidle();
if (ret)
- pr_warning("cpuidle registration failed: %d\n", ret);
+ pr_warn("cpuidle registration failed: %d\n", ret);
ret = da850_register_pm(&da850_pm_device);
if (ret)
- pr_warning("da850_evm_init: suspend registration failed: %d\n",
- ret);
+ pr_warn("suspend registration failed: %d\n", ret);
}
#ifdef CONFIG_SERIAL_8250_CONSOLE
diff --git a/arch/arm/mach-davinci/board-neuros-osd2.c b/arch/arm/mach-davinci/board-neuros-osd2.c
index bb680af..8fcdcf8 100644
--- a/arch/arm/mach-davinci/board-neuros-osd2.c
+++ b/arch/arm/mach-davinci/board-neuros-osd2.c
@@ -183,9 +183,8 @@ static __init void davinci_ntosd2_init(void)
if (HAS_ATA) {
if (HAS_NAND)
- pr_warning("WARNING: both IDE and Flash are "
- "enabled, but they share AEMIF pins.\n"
- "\tDisable IDE for NAND/NOR support.\n");
+ pr_warn("WARNING: both IDE and Flash are enabled, but they share AEMIF pins\n"
+ "\tDisable IDE for NAND/NOR support\n");
davinci_init_ide();
} else if (HAS_NAND) {
davinci_cfg_reg(DM644X_HPIEN_DISABLE);
diff --git a/arch/arm/mach-davinci/clock.c b/arch/arm/mach-davinci/clock.c
index 985e5fd..c70bb0a 100644
--- a/arch/arm/mach-davinci/clock.c
+++ b/arch/arm/mach-davinci/clock.c
@@ -564,7 +564,7 @@ int davinci_set_refclk_rate(unsigned long rate)
refclk = clk_get(NULL, "ref");
if (IS_ERR(refclk)) {
- pr_err("%s: failed to get reference clock.\n", __func__);
+ pr_err("%s: failed to get reference clock\n", __func__);
return PTR_ERR(refclk);
}
diff --git a/arch/arm/mach-davinci/cpuidle.c b/arch/arm/mach-davinci/cpuidle.c
index f1ac1c9..b4675fc 100644
--- a/arch/arm/mach-davinci/cpuidle.c
+++ b/arch/arm/mach-davinci/cpuidle.c
@@ -66,7 +66,6 @@ static struct cpuidle_driver davinci_idle_driver = {
.enter = davinci_enter_idle,
.exit_latency = 10,
.target_residency = 10000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "DDR SR",
.desc = "WFI and DDR Self Refresh",
},
diff --git a/arch/arm/mach-davinci/dm355.c b/arch/arm/mach-davinci/dm355.c
index 2f3ed3a..9cbeda7 100644
--- a/arch/arm/mach-davinci/dm355.c
+++ b/arch/arm/mach-davinci/dm355.c
@@ -785,14 +785,13 @@ static struct resource dm355_v4l2_disp_resources[] = {
},
};
-static int dm355_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type,
- int field)
+static int dm355_vpbe_setup_pinmux(u32 if_type, int field)
{
switch (if_type) {
- case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
davinci_cfg_reg(DM355_VOUT_FIELD_G70);
break;
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
if (field)
davinci_cfg_reg(DM355_VOUT_FIELD);
else
diff --git a/arch/arm/mach-davinci/dm365.c b/arch/arm/mach-davinci/dm365.c
index 0ae8114..e3a3c54 100644
--- a/arch/arm/mach-davinci/dm365.c
+++ b/arch/arm/mach-davinci/dm365.c
@@ -1306,16 +1306,15 @@ static struct resource dm365_v4l2_disp_resources[] = {
},
};
-static int dm365_vpbe_setup_pinmux(enum v4l2_mbus_pixelcode if_type,
- int field)
+static int dm365_vpbe_setup_pinmux(u32 if_type, int field)
{
switch (if_type) {
- case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
davinci_cfg_reg(DM365_VOUT_FIELD_G81);
davinci_cfg_reg(DM365_VOUT_COUTL_EN);
davinci_cfg_reg(DM365_VOUT_COUTH_EN);
break;
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
if (field)
davinci_cfg_reg(DM365_VOUT_FIELD);
else
diff --git a/arch/arm/mach-davinci/mux.c b/arch/arm/mach-davinci/mux.c
index f34a8dc..a8eb909 100644
--- a/arch/arm/mach-davinci/mux.c
+++ b/arch/arm/mach-davinci/mux.c
@@ -15,6 +15,9 @@
*
* Copyright (C) 2008 Texas Instruments.
*/
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/io.h>
#include <linux/module.h>
#include <linux/spinlock.h>
@@ -46,7 +49,7 @@ int __init_or_module davinci_cfg_reg(const unsigned long index)
}
if (index >= soc_info->pinmux_pins_num) {
- printk(KERN_ERR "Invalid pin mux index: %lu (%lu)\n",
+ pr_err("Invalid pin mux index: %lu (%lu)\n",
index, soc_info->pinmux_pins_num);
dump_stack();
return -ENODEV;
@@ -55,7 +58,7 @@ int __init_or_module davinci_cfg_reg(const unsigned long index)
cfg = &soc_info->pinmux_pins[index];
if (cfg->name == NULL) {
- printk(KERN_ERR "No entry for the specified index\n");
+ pr_err("No entry for the specified index\n");
return -ENODEV;
}
@@ -82,15 +85,15 @@ int __init_or_module davinci_cfg_reg(const unsigned long index)
if (warn) {
#ifdef CONFIG_DAVINCI_MUX_WARNINGS
- printk(KERN_WARNING "MUX: initialized %s\n", cfg->name);
+ pr_warn("initialized %s\n", cfg->name);
#endif
}
#ifdef CONFIG_DAVINCI_MUX_DEBUG
if (cfg->debug || warn) {
- printk(KERN_WARNING "MUX: Setting register %s\n", cfg->name);
- printk(KERN_WARNING " %s (0x%08x) = 0x%08x -> 0x%08x\n",
- cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
+ pr_warn("Setting register %s\n", cfg->name);
+ pr_warn(" %s (0x%08x) = 0x%08x -> 0x%08x\n",
+ cfg->mux_reg_name, cfg->mux_reg, reg_orig, reg);
}
#endif
diff --git a/arch/arm/mach-davinci/time.c b/arch/arm/mach-davinci/time.c
index 24ad30f..160c960 100644
--- a/arch/arm/mach-davinci/time.c
+++ b/arch/arm/mach-davinci/time.c
@@ -342,8 +342,6 @@ void __init davinci_timer_init(void)
struct davinci_soc_info *soc_info = &davinci_soc_info;
unsigned int clockevent_id;
unsigned int clocksource_id;
- static char err[] __initdata = KERN_ERR
- "%s: can't register clocksource!\n";
int i;
clockevent_id = soc_info->timer_info->clockevent_id;
@@ -364,12 +362,12 @@ void __init davinci_timer_init(void)
/* Only bottom timers can use compare regs */
if (IS_TIMER_TOP(clockevent_id))
- pr_warning("davinci_timer_init: Invalid use"
- " of system timers. Results unpredictable.\n");
+ pr_warn("%s: Invalid use of system timers. Results unpredictable.\n",
+ __func__);
else if ((dtip[event_timer].cmp_off == 0)
|| (dtip[event_timer].cmp_irq == 0))
- pr_warning("davinci_timer_init: Invalid timer instance"
- " setup. Results unpredictable.\n");
+ pr_warn("%s: Invalid timer instance setup. Results unpredictable.\n",
+ __func__);
else {
timers[TID_CLOCKEVENT].opts |= TIMER_OPTS_USE_COMPARE;
clockevent_davinci.features = CLOCK_EVT_FEAT_ONESHOT;
@@ -389,7 +387,8 @@ void __init davinci_timer_init(void)
clocksource_davinci.name = id_to_name[clocksource_id];
if (clocksource_register_hz(&clocksource_davinci,
davinci_clock_tick_rate))
- printk(err, clocksource_davinci.name);
+ pr_err("%s: can't register clocksource!\n",
+ clocksource_davinci.name);
sched_clock_register(davinci_read_sched_clock, 32,
davinci_clock_tick_rate);
diff --git a/arch/arm/mach-ebsa110/include/mach/io.h b/arch/arm/mach-ebsa110/include/mach/io.h
index 11bb079..6997578 100644
--- a/arch/arm/mach-ebsa110/include/mach/io.h
+++ b/arch/arm/mach-ebsa110/include/mach/io.h
@@ -29,9 +29,9 @@ u8 __readb(const volatile void __iomem *addr);
u16 __readw(const volatile void __iomem *addr);
u32 __readl(const volatile void __iomem *addr);
-void __writeb(u8 val, void __iomem *addr);
-void __writew(u16 val, void __iomem *addr);
-void __writel(u32 val, void __iomem *addr);
+void __writeb(u8 val, volatile void __iomem *addr);
+void __writew(u16 val, volatile void __iomem *addr);
+void __writel(u32 val, volatile void __iomem *addr);
/*
* Argh, someone forgot the IOCS16 line. We therefore have to handle
@@ -62,20 +62,31 @@ void __writel(u32 val, void __iomem *addr);
#define writew(v,b) __writew(v,b)
#define writel(v,b) __writel(v,b)
+#define insb insb
extern void insb(unsigned int port, void *buf, int sz);
+#define insw insw
extern void insw(unsigned int port, void *buf, int sz);
+#define insl insl
extern void insl(unsigned int port, void *buf, int sz);
+#define outsb outsb
extern void outsb(unsigned int port, const void *buf, int sz);
+#define outsw outsw
extern void outsw(unsigned int port, const void *buf, int sz);
+#define outsl outsl
extern void outsl(unsigned int port, const void *buf, int sz);
/* can't support writesb atm */
-extern void writesw(void __iomem *addr, const void *data, int wordlen);
-extern void writesl(void __iomem *addr, const void *data, int longlen);
+#define writesw writesw
+extern void writesw(volatile void __iomem *addr, const void *data, int wordlen);
+#define writesl writesl
+extern void writesl(volatile void __iomem *addr, const void *data, int longlen);
/* can't support readsb atm */
-extern void readsw(const void __iomem *addr, void *data, int wordlen);
-extern void readsl(const void __iomem *addr, void *data, int longlen);
+#define readsw readsw
+extern void readsw(const volatile void __iomem *addr, void *data, int wordlen);
+
+#define readsl readsl
+extern void readsl(const volatile void __iomem *addr, void *data, int longlen);
#endif
diff --git a/arch/arm/mach-ebsa110/io.c b/arch/arm/mach-ebsa110/io.c
index 756cc37..b57980b 100644
--- a/arch/arm/mach-ebsa110/io.c
+++ b/arch/arm/mach-ebsa110/io.c
@@ -102,7 +102,7 @@ EXPORT_SYMBOL(__readb);
EXPORT_SYMBOL(__readw);
EXPORT_SYMBOL(__readl);
-void readsw(const void __iomem *addr, void *data, int len)
+void readsw(const volatile void __iomem *addr, void *data, int len)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -112,7 +112,7 @@ void readsw(const void __iomem *addr, void *data, int len)
}
EXPORT_SYMBOL(readsw);
-void readsl(const void __iomem *addr, void *data, int len)
+void readsl(const volatile void __iomem *addr, void *data, int len)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -122,7 +122,7 @@ void readsl(const void __iomem *addr, void *data, int len)
}
EXPORT_SYMBOL(readsl);
-void __writeb(u8 val, void __iomem *addr)
+void __writeb(u8 val, volatile void __iomem *addr)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -132,7 +132,7 @@ void __writeb(u8 val, void __iomem *addr)
__raw_writeb(val, a);
}
-void __writew(u16 val, void __iomem *addr)
+void __writew(u16 val, volatile void __iomem *addr)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -142,7 +142,7 @@ void __writew(u16 val, void __iomem *addr)
__raw_writew(val, a);
}
-void __writel(u32 val, void __iomem *addr)
+void __writel(u32 val, volatile void __iomem *addr)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -157,7 +157,7 @@ EXPORT_SYMBOL(__writeb);
EXPORT_SYMBOL(__writew);
EXPORT_SYMBOL(__writel);
-void writesw(void __iomem *addr, const void *data, int len)
+void writesw(volatile void __iomem *addr, const void *data, int len)
{
void __iomem *a = __isamem_convert_addr(addr);
@@ -167,7 +167,7 @@ void writesw(void __iomem *addr, const void *data, int len)
}
EXPORT_SYMBOL(writesw);
-void writesl(void __iomem *addr, const void *data, int len)
+void writesl(volatile void __iomem *addr, const void *data, int len)
{
void __iomem *a = __isamem_convert_addr(addr);
diff --git a/arch/arm/mach-ep93xx/dma.c b/arch/arm/mach-ep93xx/dma.c
index d8bfd02..88a4c9b 100644
--- a/arch/arm/mach-ep93xx/dma.c
+++ b/arch/arm/mach-ep93xx/dma.c
@@ -66,11 +66,15 @@ static struct ep93xx_dma_platform_data ep93xx_dma_m2p_data = {
.num_channels = ARRAY_SIZE(ep93xx_dma_m2p_channels),
};
+static u64 ep93xx_dma_m2p_mask = DMA_BIT_MASK(32);
+
static struct platform_device ep93xx_dma_m2p_device = {
.name = "ep93xx-dma-m2p",
.id = -1,
.dev = {
- .platform_data = &ep93xx_dma_m2p_data,
+ .platform_data = &ep93xx_dma_m2p_data,
+ .dma_mask = &ep93xx_dma_m2p_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
},
};
@@ -93,11 +97,15 @@ static struct ep93xx_dma_platform_data ep93xx_dma_m2m_data = {
.num_channels = ARRAY_SIZE(ep93xx_dma_m2m_channels),
};
+static u64 ep93xx_dma_m2m_mask = DMA_BIT_MASK(32);
+
static struct platform_device ep93xx_dma_m2m_device = {
.name = "ep93xx-dma-m2m",
.id = -1,
.dev = {
- .platform_data = &ep93xx_dma_m2m_data,
+ .platform_data = &ep93xx_dma_m2m_data,
+ .dma_mask = &ep93xx_dma_m2m_mask,
+ .coherent_dma_mask = DMA_BIT_MASK(32),
},
};
diff --git a/arch/arm/mach-exynos/Kconfig b/arch/arm/mach-exynos/Kconfig
index 2d0240f..b9e3f1c 100644
--- a/arch/arm/mach-exynos/Kconfig
+++ b/arch/arm/mach-exynos/Kconfig
@@ -24,6 +24,7 @@ menuconfig ARCH_EXYNOS
select PM_GENERIC_DOMAINS if PM_RUNTIME
select S5P_DEV_MFC
select SRAM
+ select MFD_SYSCON
help
Support for SAMSUNG EXYNOS SoCs (EXYNOS4/5)
@@ -75,6 +76,11 @@ config SOC_EXYNOS4412
default y
depends on ARCH_EXYNOS4
+config SOC_EXYNOS4415
+ bool "SAMSUNG EXYNOS4415"
+ default y
+ depends on ARCH_EXYNOS4
+
config SOC_EXYNOS5250
bool "SAMSUNG EXYNOS5250"
default y
@@ -123,4 +129,9 @@ config EXYNOS5420_MCPM
This is needed to provide CPU and cluster power management
on Exynos5420 implementing big.LITTLE.
+config EXYNOS_CPU_SUSPEND
+ bool
+ select ARM_CPU_SUSPEND
+ default PM_SLEEP || ARM_EXYNOS_CPUIDLE
+
endif
diff --git a/arch/arm/mach-exynos/Makefile b/arch/arm/mach-exynos/Makefile
index 27ae614..bcefb54 100644
--- a/arch/arm/mach-exynos/Makefile
+++ b/arch/arm/mach-exynos/Makefile
@@ -11,16 +11,15 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) += -I$(srctree)/$(src)/include -I$(srctree)
obj-$(CONFIG_ARCH_EXYNOS) += exynos.o pmu.o exynos-smc.o firmware.o
-obj-$(CONFIG_PM_SLEEP) += pm.o sleep.o
+obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm.o sleep.o
+obj-$(CONFIG_PM_SLEEP) += suspend.o
obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
-obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
-CFLAGS_hotplug.o += -march=armv7-a
-
plus_sec := $(call as-instr,.arch_extension sec,+sec)
AFLAGS_exynos-smc.o :=-Wa,-march=armv7-a$(plus_sec)
+AFLAGS_sleep.o :=-Wa,-march=armv7-a$(plus_sec)
obj-$(CONFIG_EXYNOS5420_MCPM) += mcpm-exynos.o
CFLAGS_mcpm-exynos.o += -march=armv7-a
diff --git a/arch/arm/mach-exynos/common.h b/arch/arm/mach-exynos/common.h
index 47b904b..865f878 100644
--- a/arch/arm/mach-exynos/common.h
+++ b/arch/arm/mach-exynos/common.h
@@ -12,7 +12,6 @@
#ifndef __ARCH_ARM_MACH_EXYNOS_COMMON_H
#define __ARCH_ARM_MACH_EXYNOS_COMMON_H
-#include <linux/reboot.h>
#include <linux/of.h>
#define EXYNOS3250_SOC_ID 0xE3472000
@@ -111,11 +110,19 @@ IS_SAMSUNG_CPU(exynos5800, EXYNOS5800_SOC_ID, EXYNOS5_SOC_MASK)
#define soc_is_exynos5() (soc_is_exynos5250() || soc_is_exynos5410() || \
soc_is_exynos5420() || soc_is_exynos5800())
+extern u32 cp15_save_diag;
+extern u32 cp15_save_power;
+
extern void __iomem *sysram_ns_base_addr;
extern void __iomem *sysram_base_addr;
extern void __iomem *pmu_base_addr;
void exynos_sysram_init(void);
+enum {
+ FW_DO_IDLE_SLEEP,
+ FW_DO_IDLE_AFTR,
+};
+
void exynos_firmware_init(void);
extern u32 exynos_get_eint_wake_mask(void);
@@ -127,34 +134,20 @@ static inline void exynos_pm_init(void) {}
#endif
extern void exynos_cpu_resume(void);
+extern void exynos_cpu_resume_ns(void);
extern struct smp_operations exynos_smp_ops;
-extern void exynos_cpu_die(unsigned int cpu);
-
-/* PMU(Power Management Unit) support */
-
-#define PMU_TABLE_END (-1U)
-
-enum sys_powerdown {
- SYS_AFTR,
- SYS_LPA,
- SYS_SLEEP,
- NUM_SYS_POWERDOWN,
-};
-
-struct exynos_pmu_conf {
- unsigned int offset;
- unsigned int val[NUM_SYS_POWERDOWN];
-};
-
-extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
extern void exynos_cpu_power_down(int cpu);
extern void exynos_cpu_power_up(int cpu);
extern int exynos_cpu_power_state(int cpu);
extern void exynos_cluster_power_down(int cluster);
extern void exynos_cluster_power_up(int cluster);
extern int exynos_cluster_power_state(int cluster);
+extern void exynos_cpu_save_register(void);
+extern void exynos_cpu_restore_register(void);
+extern void exynos_pm_central_suspend(void);
+extern int exynos_pm_central_resume(void);
extern void exynos_enter_aftr(void);
extern void s5p_init_cpu(void __iomem *cpuid_addr);
diff --git a/arch/arm/mach-exynos/exynos-pmu.h b/arch/arm/mach-exynos/exynos-pmu.h
new file mode 100644
index 0000000..a2ab0d5
--- /dev/null
+++ b/arch/arm/mach-exynos/exynos-pmu.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * Header for EXYNOS PMU Driver 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.
+ */
+
+#ifndef __EXYNOS_PMU_H
+#define __EXYNOS_PMU_H
+
+enum sys_powerdown {
+ SYS_AFTR,
+ SYS_LPA,
+ SYS_SLEEP,
+ NUM_SYS_POWERDOWN,
+};
+
+extern void exynos_sys_powerdown_conf(enum sys_powerdown mode);
+
+#endif /* __EXYNOS_PMU_H */
diff --git a/arch/arm/mach-exynos/exynos.c b/arch/arm/mach-exynos/exynos.c
index 6b283eb..c13d083 100644
--- a/arch/arm/mach-exynos/exynos.c
+++ b/arch/arm/mach-exynos/exynos.c
@@ -41,41 +41,11 @@ static struct map_desc exynos4_iodesc[] __initdata = {
.length = SZ_64K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S3C_VA_TIMER,
- .pfn = __phys_to_pfn(EXYNOS4_PA_TIMER),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S3C_VA_WATCHDOG,
- .pfn = __phys_to_pfn(EXYNOS4_PA_WATCHDOG),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_SROMC,
.pfn = __phys_to_pfn(EXYNOS4_PA_SROMC),
.length = SZ_4K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S5P_VA_SYSTIMER,
- .pfn = __phys_to_pfn(EXYNOS4_PA_SYSTIMER),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S5P_VA_COMBINER_BASE,
- .pfn = __phys_to_pfn(EXYNOS4_PA_COMBINER),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S5P_VA_GIC_CPU,
- .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_CPU),
- .length = SZ_64K,
- .type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S5P_VA_GIC_DIST,
- .pfn = __phys_to_pfn(EXYNOS4_PA_GIC_DIST),
- .length = SZ_64K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_CMU,
.pfn = __phys_to_pfn(EXYNOS4_PA_CMU),
.length = SZ_128K,
@@ -86,11 +56,6 @@ static struct map_desc exynos4_iodesc[] __initdata = {
.length = SZ_8K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S5P_VA_L2CC,
- .pfn = __phys_to_pfn(EXYNOS4_PA_L2CC),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_DMC0,
.pfn = __phys_to_pfn(EXYNOS4_PA_DMC0),
.length = SZ_64K,
@@ -100,11 +65,6 @@ static struct map_desc exynos4_iodesc[] __initdata = {
.pfn = __phys_to_pfn(EXYNOS4_PA_DMC1),
.length = SZ_64K,
.type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S3C_VA_USB_HSPHY,
- .pfn = __phys_to_pfn(EXYNOS4_PA_HSPHY),
- .length = SZ_4K,
- .type = MT_DEVICE,
},
};
@@ -115,16 +75,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
.length = SZ_64K,
.type = MT_DEVICE,
}, {
- .virtual = (unsigned long)S3C_VA_TIMER,
- .pfn = __phys_to_pfn(EXYNOS5_PA_TIMER),
- .length = SZ_16K,
- .type = MT_DEVICE,
- }, {
- .virtual = (unsigned long)S3C_VA_WATCHDOG,
- .pfn = __phys_to_pfn(EXYNOS5_PA_WATCHDOG),
- .length = SZ_4K,
- .type = MT_DEVICE,
- }, {
.virtual = (unsigned long)S5P_VA_SROMC,
.pfn = __phys_to_pfn(EXYNOS5_PA_SROMC),
.length = SZ_4K,
@@ -137,28 +87,6 @@ static struct map_desc exynos5_iodesc[] __initdata = {
},
};
-static void exynos_restart(enum reboot_mode mode, const char *cmd)
-{
- struct device_node *np;
- u32 val = 0x1;
- void __iomem *addr = pmu_base_addr + EXYNOS_SWRESET;
-
- if (of_machine_is_compatible("samsung,exynos5440")) {
- u32 status;
- np = of_find_compatible_node(NULL, NULL, "samsung,exynos5440-clock");
-
- addr = of_iomap(np, 0) + 0xbc;
- status = __raw_readl(addr);
-
- addr = of_iomap(np, 0) + 0xcc;
- val = __raw_readl(addr);
-
- val = (val & 0xffff0000) | (status & 0xffff);
- }
-
- __raw_writel(val, addr);
-}
-
static struct platform_device exynos_cpuidle = {
.name = "exynos_cpuidle",
#ifdef CONFIG_ARM_EXYNOS_CPUIDLE
@@ -252,6 +180,7 @@ static const struct of_device_id exynos_dt_pmu_match[] = {
{ .compatible = "samsung,exynos4210-pmu" },
{ .compatible = "samsung,exynos4212-pmu" },
{ .compatible = "samsung,exynos4412-pmu" },
+ { .compatible = "samsung,exynos4415-pmu" },
{ .compatible = "samsung,exynos5250-pmu" },
{ .compatible = "samsung,exynos5260-pmu" },
{ .compatible = "samsung,exynos5410-pmu" },
@@ -318,7 +247,10 @@ static void __init exynos_dt_machine_init(void)
exynos_sysram_init();
if (of_machine_is_compatible("samsung,exynos4210") ||
- of_machine_is_compatible("samsung,exynos5250"))
+ of_machine_is_compatible("samsung,exynos4212") ||
+ (of_machine_is_compatible("samsung,exynos4412") &&
+ of_machine_is_compatible("samsung,trats2")) ||
+ of_machine_is_compatible("samsung,exynos5250"))
platform_device_register(&exynos_cpuidle);
platform_device_register_simple("exynos-cpufreq", -1, NULL, 0);
@@ -333,6 +265,7 @@ static char const *exynos_dt_compat[] __initconst = {
"samsung,exynos4210",
"samsung,exynos4212",
"samsung,exynos4412",
+ "samsung,exynos4415",
"samsung,exynos5",
"samsung,exynos5250",
"samsung,exynos5260",
@@ -378,7 +311,6 @@ DT_MACHINE_START(EXYNOS_DT, "SAMSUNG EXYNOS (Flattened Device Tree)")
.init_machine = exynos_dt_machine_init,
.init_late = exynos_init_late,
.dt_compat = exynos_dt_compat,
- .restart = exynos_restart,
.reserve = exynos_reserve,
.dt_fixup = exynos_dt_fixup,
MACHINE_END
diff --git a/arch/arm/mach-exynos/firmware.c b/arch/arm/mach-exynos/firmware.c
index e8797bb..766f57d 100644
--- a/arch/arm/mach-exynos/firmware.c
+++ b/arch/arm/mach-exynos/firmware.c
@@ -14,16 +14,44 @@
#include <linux/of.h>
#include <linux/of_address.h>
+#include <asm/cacheflush.h>
+#include <asm/cputype.h>
#include <asm/firmware.h>
+#include <asm/suspend.h>
#include <mach/map.h>
#include "common.h"
#include "smc.h"
-static int exynos_do_idle(void)
+#define EXYNOS_SLEEP_MAGIC 0x00000bad
+#define EXYNOS_AFTR_MAGIC 0xfcba0d10
+#define EXYNOS_BOOT_ADDR 0x8
+#define EXYNOS_BOOT_FLAG 0xc
+
+static void exynos_save_cp15(void)
{
- exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
+ /* Save Power control and Diagnostic registers */
+ asm ("mrc p15, 0, %0, c15, c0, 0\n"
+ "mrc p15, 0, %1, c15, c0, 1\n"
+ : "=r" (cp15_save_power), "=r" (cp15_save_diag)
+ : : "cc");
+}
+
+static int exynos_do_idle(unsigned long mode)
+{
+ switch (mode) {
+ case FW_DO_IDLE_AFTR:
+ if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
+ exynos_save_cp15();
+ __raw_writel(virt_to_phys(exynos_cpu_resume_ns),
+ sysram_ns_base_addr + 0x24);
+ __raw_writel(EXYNOS_AFTR_MAGIC, sysram_ns_base_addr + 0x20);
+ exynos_smc(SMC_CMD_CPU0AFTR, 0, 0, 0);
+ break;
+ case FW_DO_IDLE_SLEEP:
+ exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
+ }
return 0;
}
@@ -69,10 +97,43 @@ static int exynos_set_cpu_boot_addr(int cpu, unsigned long boot_addr)
return 0;
}
+static int exynos_cpu_suspend(unsigned long arg)
+{
+ flush_cache_all();
+ outer_flush_all();
+
+ exynos_smc(SMC_CMD_SLEEP, 0, 0, 0);
+
+ pr_info("Failed to suspend the system\n");
+ writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG);
+ return 1;
+}
+
+static int exynos_suspend(void)
+{
+ if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
+ exynos_save_cp15();
+
+ writel(EXYNOS_SLEEP_MAGIC, sysram_ns_base_addr + EXYNOS_BOOT_FLAG);
+ writel(virt_to_phys(exynos_cpu_resume_ns),
+ sysram_ns_base_addr + EXYNOS_BOOT_ADDR);
+
+ return cpu_suspend(0, exynos_cpu_suspend);
+}
+
+static int exynos_resume(void)
+{
+ writel(0, sysram_ns_base_addr + EXYNOS_BOOT_FLAG);
+
+ return 0;
+}
+
static const struct firmware_ops exynos_firmware_ops = {
- .do_idle = exynos_do_idle,
+ .do_idle = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_do_idle : NULL,
.set_cpu_boot_addr = exynos_set_cpu_boot_addr,
.cpu_boot = exynos_cpu_boot,
+ .suspend = IS_ENABLED(CONFIG_PM_SLEEP) ? exynos_suspend : NULL,
+ .resume = IS_ENABLED(CONFIG_EXYNOS_CPU_SUSPEND) ? exynos_resume : NULL,
};
void __init exynos_firmware_init(void)
diff --git a/arch/arm/mach-exynos/hotplug.c b/arch/arm/mach-exynos/hotplug.c
deleted file mode 100644
index 4d86961..0000000
--- a/arch/arm/mach-exynos/hotplug.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/*
- * Cloned from linux/arch/arm/mach-realview/hotplug.c
- *
- * Copyright (C) 2002 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/kernel.h>
-#include <linux/errno.h>
-#include <linux/smp.h>
-#include <linux/io.h>
-
-#include <asm/cacheflush.h>
-#include <asm/cp15.h>
-#include <asm/smp_plat.h>
-
-#include "common.h"
-#include "regs-pmu.h"
-
-static inline void cpu_leave_lowpower(void)
-{
- unsigned int v;
-
- asm volatile(
- "mrc p15, 0, %0, c1, c0, 0\n"
- " orr %0, %0, %1\n"
- " mcr p15, 0, %0, c1, c0, 0\n"
- " mrc p15, 0, %0, c1, c0, 1\n"
- " orr %0, %0, %2\n"
- " mcr p15, 0, %0, c1, c0, 1\n"
- : "=&r" (v)
- : "Ir" (CR_C), "Ir" (0x40)
- : "cc");
-}
-
-static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
-{
- u32 mpidr = cpu_logical_map(cpu);
- u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
-
- for (;;) {
-
- /* Turn the CPU off on next WFI instruction. */
- exynos_cpu_power_down(core_id);
-
- wfi();
-
- if (pen_release == core_id) {
- /*
- * OK, proper wakeup, we're done
- */
- break;
- }
-
- /*
- * Getting here, means that we have come out of WFI without
- * having been woken up - this shouldn't happen
- *
- * Just note it happening - when we're woken, we can report
- * its occurrence.
- */
- (*spurious)++;
- }
-}
-
-/*
- * platform-specific code to shutdown a CPU
- *
- * Called with IRQs disabled
- */
-void __ref exynos_cpu_die(unsigned int cpu)
-{
- int spurious = 0;
-
- v7_exit_coherency_flush(louis);
-
- platform_do_lowpower(cpu, &spurious);
-
- /*
- * bring this CPU back into the world of cache
- * coherency, and then restore interrupts
- */
- cpu_leave_lowpower();
-
- if (spurious)
- pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
-}
diff --git a/arch/arm/mach-exynos/include/mach/map.h b/arch/arm/mach-exynos/include/mach/map.h
index f0b7e92..1ad3f49 100644
--- a/arch/arm/mach-exynos/include/mach/map.h
+++ b/arch/arm/mach-exynos/include/mach/map.h
@@ -30,40 +30,17 @@
#define EXYNOS4_PA_CMU 0x10030000
#define EXYNOS5_PA_CMU 0x10010000
-#define EXYNOS4_PA_SYSTIMER 0x10050000
-
-#define EXYNOS4_PA_WATCHDOG 0x10060000
-#define EXYNOS5_PA_WATCHDOG 0x101D0000
-
#define EXYNOS4_PA_DMC0 0x10400000
#define EXYNOS4_PA_DMC1 0x10410000
-#define EXYNOS4_PA_COMBINER 0x10440000
-#define EXYNOS5_PA_COMBINER 0x10440000
-
-#define EXYNOS4_PA_GIC_CPU 0x10480000
-#define EXYNOS4_PA_GIC_DIST 0x10490000
-#define EXYNOS5_PA_GIC_CPU 0x10482000
-#define EXYNOS5_PA_GIC_DIST 0x10481000
-
#define EXYNOS4_PA_COREPERI 0x10500000
#define EXYNOS4_PA_L2CC 0x10502000
#define EXYNOS4_PA_SROMC 0x12570000
#define EXYNOS5_PA_SROMC 0x12250000
-#define EXYNOS4_PA_HSPHY 0x125B0000
-
-#define EXYNOS4_PA_UART 0x13800000
-#define EXYNOS5_PA_UART 0x12C00000
-
-#define EXYNOS4_PA_TIMER 0x139D0000
-#define EXYNOS5_PA_TIMER 0x12DD0000
-
/* Compatibility UART */
#define EXYNOS5440_PA_UART0 0x000B0000
-#define S3C_VA_UARTx(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
-
#endif /* __ASM_ARCH_MAP_H */
diff --git a/arch/arm/mach-exynos/mcpm-exynos.c b/arch/arm/mach-exynos/mcpm-exynos.c
index dc9a764..b0d3c2e 100644
--- a/arch/arm/mach-exynos/mcpm-exynos.c
+++ b/arch/arm/mach-exynos/mcpm-exynos.c
@@ -15,6 +15,7 @@
#include <linux/delay.h>
#include <linux/io.h>
#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
#include <asm/cputype.h>
#include <asm/cp15.h>
@@ -30,6 +31,8 @@
#define EXYNOS5420_USE_ARM_CORE_DOWN_STATE BIT(29)
#define EXYNOS5420_USE_L2_COMMON_UP_STATE BIT(30)
+static void __iomem *ns_sram_base_addr;
+
/*
* The common v7_exit_coherency_flush API could not be used because of the
* Erratum 799270 workaround. This macro is the same as the common one (in
@@ -318,10 +321,26 @@ static const struct of_device_id exynos_dt_mcpm_match[] = {
{},
};
+static void exynos_mcpm_setup_entry_point(void)
+{
+ /*
+ * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
+ * as part of secondary_cpu_start(). Let's redirect it to the
+ * mcpm_entry_point(). This is done during both secondary boot-up as
+ * well as system resume.
+ */
+ __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */
+ __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */
+ __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8);
+}
+
+static struct syscore_ops exynos_mcpm_syscore_ops = {
+ .resume = exynos_mcpm_setup_entry_point,
+};
+
static int __init exynos_mcpm_init(void)
{
struct device_node *node;
- void __iomem *ns_sram_base_addr;
unsigned int value, i;
int ret;
@@ -387,16 +406,9 @@ static int __init exynos_mcpm_init(void)
pmu_raw_writel(value, EXYNOS_COMMON_OPTION(i));
}
- /*
- * U-Boot SPL is hardcoded to jump to the start of ns_sram_base_addr
- * as part of secondary_cpu_start(). Let's redirect it to the
- * mcpm_entry_point().
- */
- __raw_writel(0xe59f0000, ns_sram_base_addr); /* ldr r0, [pc, #0] */
- __raw_writel(0xe12fff10, ns_sram_base_addr + 4); /* bx r0 */
- __raw_writel(virt_to_phys(mcpm_entry_point), ns_sram_base_addr + 8);
+ exynos_mcpm_setup_entry_point();
- iounmap(ns_sram_base_addr);
+ register_syscore_ops(&exynos_mcpm_syscore_ops);
return ret;
}
diff --git a/arch/arm/mach-exynos/platsmp.c b/arch/arm/mach-exynos/platsmp.c
index 41ae28d..7a1ebfe 100644
--- a/arch/arm/mach-exynos/platsmp.c
+++ b/arch/arm/mach-exynos/platsmp.c
@@ -22,6 +22,7 @@
#include <linux/of_address.h>
#include <asm/cacheflush.h>
+#include <asm/cp15.h>
#include <asm/smp_plat.h>
#include <asm/smp_scu.h>
#include <asm/firmware.h>
@@ -33,6 +34,88 @@
extern void exynos4_secondary_startup(void);
+/*
+ * Set or clear the USE_DELAYED_RESET_ASSERTION option, set on Exynos4 SoCs
+ * during hot-(un)plugging CPUx.
+ *
+ * The feature can be cleared safely during first boot of secondary CPU.
+ *
+ * Exynos4 SoCs require setting USE_DELAYED_RESET_ASSERTION during powering
+ * down a CPU so the CPU idle clock down feature could properly detect global
+ * idle state when CPUx is off.
+ */
+static void exynos_set_delayed_reset_assertion(u32 core_id, bool enable)
+{
+ if (soc_is_exynos4()) {
+ unsigned int tmp;
+
+ tmp = pmu_raw_readl(EXYNOS_ARM_CORE_OPTION(core_id));
+ if (enable)
+ tmp |= S5P_USE_DELAYED_RESET_ASSERTION;
+ else
+ tmp &= ~(S5P_USE_DELAYED_RESET_ASSERTION);
+ pmu_raw_writel(tmp, EXYNOS_ARM_CORE_OPTION(core_id));
+ }
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static inline void cpu_leave_lowpower(u32 core_id)
+{
+ unsigned int v;
+
+ asm volatile(
+ "mrc p15, 0, %0, c1, c0, 0\n"
+ " orr %0, %0, %1\n"
+ " mcr p15, 0, %0, c1, c0, 0\n"
+ " mrc p15, 0, %0, c1, c0, 1\n"
+ " orr %0, %0, %2\n"
+ " mcr p15, 0, %0, c1, c0, 1\n"
+ : "=&r" (v)
+ : "Ir" (CR_C), "Ir" (0x40)
+ : "cc");
+
+ exynos_set_delayed_reset_assertion(core_id, false);
+}
+
+static inline void platform_do_lowpower(unsigned int cpu, int *spurious)
+{
+ u32 mpidr = cpu_logical_map(cpu);
+ u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+
+ for (;;) {
+
+ /* Turn the CPU off on next WFI instruction. */
+ exynos_cpu_power_down(core_id);
+
+ /*
+ * Exynos4 SoCs require setting
+ * USE_DELAYED_RESET_ASSERTION so the CPU idle
+ * clock down feature could properly detect
+ * global idle state when CPUx is off.
+ */
+ exynos_set_delayed_reset_assertion(core_id, true);
+
+ wfi();
+
+ if (pen_release == core_id) {
+ /*
+ * OK, proper wakeup, we're done
+ */
+ break;
+ }
+
+ /*
+ * Getting here, means that we have come out of WFI without
+ * having been woken up - this shouldn't happen
+ *
+ * Just note it happening - when we're woken, we can report
+ * its occurrence.
+ */
+ (*spurious)++;
+ }
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
/**
* exynos_core_power_down : power down the specified cpu
* @cpu : the cpu to power down
@@ -43,6 +126,18 @@ extern void exynos4_secondary_startup(void);
*/
void exynos_cpu_power_down(int cpu)
{
+ if (cpu == 0 && (of_machine_is_compatible("samsung,exynos5420") ||
+ of_machine_is_compatible("samsung,exynos5800"))) {
+ /*
+ * Bypass power down for CPU0 during suspend. Check for
+ * the SYS_PWR_REG value to decide if we are suspending
+ * the system.
+ */
+ int val = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
+
+ if (!(val & S5P_CORE_LOCAL_PWR_EN))
+ return;
+ }
pmu_raw_writel(0, EXYNOS_ARM_CORE_CONFIGURATION(cpu));
}
@@ -121,6 +216,26 @@ static inline void __iomem *cpu_boot_reg(int cpu)
}
/*
+ * Set wake up by local power mode and execute software reset for given core.
+ *
+ * Currently this is needed only when booting secondary CPU on Exynos3250.
+ */
+static void exynos_core_restart(u32 core_id)
+{
+ u32 val;
+
+ if (!of_machine_is_compatible("samsung,exynos3250"))
+ return;
+
+ val = pmu_raw_readl(EXYNOS_ARM_CORE_STATUS(core_id));
+ val |= S5P_CORE_WAKEUP_FROM_LOCAL_CFG;
+ pmu_raw_writel(val, EXYNOS_ARM_CORE_STATUS(core_id));
+
+ pr_info("CPU%u: Software reset\n", core_id);
+ pmu_raw_writel(EXYNOS_CORE_PO_RESET(core_id), EXYNOS_SWRESET);
+}
+
+/*
* Write pen_release in a way that is guaranteed to be visible to all
* observers, irrespective of whether they're taking part in coherency
* or not. This is necessary for the hotplug code to work reliably.
@@ -196,6 +311,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
return -ETIMEDOUT;
}
}
+
+ exynos_core_restart(core_id);
+
/*
* Send the secondary CPU a soft interrupt, thereby causing
* the boot monitor to read the system wide flags register,
@@ -237,6 +355,9 @@ static int exynos_boot_secondary(unsigned int cpu, struct task_struct *idle)
udelay(10);
}
+ /* No harm if this is called during first boot of secondary CPU */
+ exynos_set_delayed_reset_assertion(core_id, false);
+
/*
* now the secondary core is starting up let it run its
* calibrations, then wait for it to finish
@@ -318,6 +439,33 @@ static void __init exynos_smp_prepare_cpus(unsigned int max_cpus)
}
}
+#ifdef CONFIG_HOTPLUG_CPU
+/*
+ * platform-specific code to shutdown a CPU
+ *
+ * Called with IRQs disabled
+ */
+static void exynos_cpu_die(unsigned int cpu)
+{
+ int spurious = 0;
+ u32 mpidr = cpu_logical_map(cpu);
+ u32 core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+
+ v7_exit_coherency_flush(louis);
+
+ platform_do_lowpower(cpu, &spurious);
+
+ /*
+ * bring this CPU back into the world of cache
+ * coherency, and then restore interrupts
+ */
+ cpu_leave_lowpower(core_id);
+
+ if (spurious)
+ pr_warn("CPU%u: %u spurious wakeup calls\n", cpu, spurious);
+}
+#endif /* CONFIG_HOTPLUG_CPU */
+
struct smp_operations exynos_smp_ops __initdata = {
.smp_init_cpus = exynos_smp_init_cpus,
.smp_prepare_cpus = exynos_smp_prepare_cpus,
diff --git a/arch/arm/mach-exynos/pm.c b/arch/arm/mach-exynos/pm.c
index abefacb..86f3ecd 100644
--- a/arch/arm/mach-exynos/pm.c
+++ b/arch/arm/mach-exynos/pm.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com
*
* EXYNOS - Power Management support
@@ -15,109 +15,45 @@
#include <linux/init.h>
#include <linux/suspend.h>
-#include <linux/syscore_ops.h>
#include <linux/cpu_pm.h>
#include <linux/io.h>
-#include <linux/irqchip/arm-gic.h>
#include <linux/err.h>
-#include <linux/clk.h>
-#include <asm/cacheflush.h>
-#include <asm/hardware/cache-l2x0.h>
+#include <asm/firmware.h>
#include <asm/smp_scu.h>
#include <asm/suspend.h>
#include <plat/pm-common.h>
-#include <plat/regs-srom.h>
-
-#include <mach/map.h>
#include "common.h"
+#include "exynos-pmu.h"
#include "regs-pmu.h"
#include "regs-sys.h"
-/**
- * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
- * @hwirq: Hardware IRQ signal of the GIC
- * @mask: Mask in PMU wake-up mask register
- */
-struct exynos_wkup_irq {
- unsigned int hwirq;
- u32 mask;
-};
-
-static struct sleep_save exynos5_sys_save[] = {
- SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
-};
-
-static struct sleep_save exynos_core_save[] = {
- /* SROM side */
- SAVE_ITEM(S5P_SROM_BW),
- SAVE_ITEM(S5P_SROM_BC0),
- SAVE_ITEM(S5P_SROM_BC1),
- SAVE_ITEM(S5P_SROM_BC2),
- SAVE_ITEM(S5P_SROM_BC3),
-};
-
-/*
- * GIC wake-up support
- */
-
-static u32 exynos_irqwake_intmask = 0xffffffff;
-
-static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
- { 76, BIT(1) }, /* RTC alarm */
- { 77, BIT(2) }, /* RTC tick */
- { /* sentinel */ },
-};
-
-static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
- { 75, BIT(1) }, /* RTC alarm */
- { 76, BIT(2) }, /* RTC tick */
- { /* sentinel */ },
-};
-
-static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
+static inline void __iomem *exynos_boot_vector_addr(void)
{
- const struct exynos_wkup_irq *wkup_irq;
-
- if (soc_is_exynos5250())
- wkup_irq = exynos5250_wkup_irq;
- else
- wkup_irq = exynos4_wkup_irq;
-
- while (wkup_irq->mask) {
- if (wkup_irq->hwirq == data->hwirq) {
- if (!state)
- exynos_irqwake_intmask |= wkup_irq->mask;
- else
- exynos_irqwake_intmask &= ~wkup_irq->mask;
- return 0;
- }
- ++wkup_irq;
- }
-
- return -ENOENT;
+ if (samsung_rev() == EXYNOS4210_REV_1_1)
+ return pmu_base_addr + S5P_INFORM7;
+ else if (samsung_rev() == EXYNOS4210_REV_1_0)
+ return sysram_base_addr + 0x24;
+ return pmu_base_addr + S5P_INFORM0;
}
-#define EXYNOS_BOOT_VECTOR_ADDR (samsung_rev() == EXYNOS4210_REV_1_1 ? \
- pmu_base_addr + S5P_INFORM7 : \
- (samsung_rev() == EXYNOS4210_REV_1_0 ? \
- (sysram_base_addr + 0x24) : \
- pmu_base_addr + S5P_INFORM0))
-#define EXYNOS_BOOT_VECTOR_FLAG (samsung_rev() == EXYNOS4210_REV_1_1 ? \
- pmu_base_addr + S5P_INFORM6 : \
- (samsung_rev() == EXYNOS4210_REV_1_0 ? \
- (sysram_base_addr + 0x20) : \
- pmu_base_addr + S5P_INFORM1))
+static inline void __iomem *exynos_boot_vector_flag(void)
+{
+ if (samsung_rev() == EXYNOS4210_REV_1_1)
+ return pmu_base_addr + S5P_INFORM6;
+ else if (samsung_rev() == EXYNOS4210_REV_1_0)
+ return sysram_base_addr + 0x20;
+ return pmu_base_addr + S5P_INFORM1;
+}
#define S5P_CHECK_AFTR 0xFCBA0D10
-#define S5P_CHECK_SLEEP 0x00000BAD
/* For Cortex-A9 Diagnostic and Power control register */
static unsigned int save_arm_register[2];
-static void exynos_cpu_save_register(void)
+void exynos_cpu_save_register(void)
{
unsigned long tmp;
@@ -134,7 +70,7 @@ static void exynos_cpu_save_register(void)
save_arm_register[1] = tmp;
}
-static void exynos_cpu_restore_register(void)
+void exynos_cpu_restore_register(void)
{
unsigned long tmp;
@@ -153,7 +89,7 @@ static void exynos_cpu_restore_register(void)
: "cc");
}
-static void exynos_pm_central_suspend(void)
+void exynos_pm_central_suspend(void)
{
unsigned long tmp;
@@ -161,9 +97,13 @@ static void exynos_pm_central_suspend(void)
tmp = pmu_raw_readl(S5P_CENTRAL_SEQ_CONFIGURATION);
tmp &= ~S5P_CENTRAL_LOWPWR_CFG;
pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_CONFIGURATION);
+
+ /* Setting SEQ_OPTION register */
+ pmu_raw_writel(S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0,
+ S5P_CENTRAL_SEQ_OPTION);
}
-static int exynos_pm_central_resume(void)
+int exynos_pm_central_resume(void)
{
unsigned long tmp;
@@ -194,17 +134,26 @@ static void exynos_set_wakeupmask(long mask)
static void exynos_cpu_set_boot_vector(long flags)
{
- __raw_writel(virt_to_phys(exynos_cpu_resume), EXYNOS_BOOT_VECTOR_ADDR);
- __raw_writel(flags, EXYNOS_BOOT_VECTOR_FLAG);
+ __raw_writel(virt_to_phys(exynos_cpu_resume),
+ exynos_boot_vector_addr());
+ __raw_writel(flags, exynos_boot_vector_flag());
}
static int exynos_aftr_finisher(unsigned long flags)
{
+ int ret;
+
exynos_set_wakeupmask(0x0000ff3e);
- exynos_cpu_set_boot_vector(S5P_CHECK_AFTR);
/* Set value of power down register for aftr mode */
exynos_sys_powerdown_conf(SYS_AFTR);
- cpu_do_idle();
+
+ ret = call_firmware_op(do_idle, FW_DO_IDLE_AFTR);
+ if (ret == -ENOSYS) {
+ if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
+ exynos_cpu_save_register();
+ exynos_cpu_set_boot_vector(S5P_CHECK_AFTR);
+ cpu_do_idle();
+ }
return 1;
}
@@ -214,196 +163,16 @@ void exynos_enter_aftr(void)
cpu_pm_enter();
exynos_pm_central_suspend();
- if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
- exynos_cpu_save_register();
cpu_suspend(0, exynos_aftr_finisher);
if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
scu_enable(S5P_VA_SCU);
- exynos_cpu_restore_register();
+ if (call_firmware_op(resume) == -ENOSYS)
+ exynos_cpu_restore_register();
}
exynos_pm_central_resume();
cpu_pm_exit();
}
-
-static int exynos_cpu_suspend(unsigned long arg)
-{
-#ifdef CONFIG_CACHE_L2X0
- outer_flush_all();
-#endif
-
- if (soc_is_exynos5250())
- flush_cache_all();
-
- /* issue the standby signal into the pm unit. */
- cpu_do_idle();
-
- pr_info("Failed to suspend the system\n");
- return 1; /* Aborting suspend */
-}
-
-static void exynos_pm_prepare(void)
-{
- unsigned int tmp;
-
- /* Set wake-up mask registers */
- pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK);
- pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
-
- s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
-
- if (soc_is_exynos5250()) {
- s3c_pm_do_save(exynos5_sys_save, ARRAY_SIZE(exynos5_sys_save));
- /* Disable USE_RETENTION of JPEG_MEM_OPTION */
- tmp = pmu_raw_readl(EXYNOS5_JPEG_MEM_OPTION);
- tmp &= ~EXYNOS5_OPTION_USE_RETENTION;
- pmu_raw_writel(tmp, EXYNOS5_JPEG_MEM_OPTION);
- }
-
- /* Set value of power down register for sleep mode */
-
- exynos_sys_powerdown_conf(SYS_SLEEP);
- pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1);
-
- /* ensure at least INFORM0 has the resume address */
-
- pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
-}
-
-static int exynos_pm_suspend(void)
-{
- unsigned long tmp;
-
- exynos_pm_central_suspend();
-
- /* Setting SEQ_OPTION register */
-
- tmp = (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFE0);
- pmu_raw_writel(tmp, S5P_CENTRAL_SEQ_OPTION);
-
- if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
- exynos_cpu_save_register();
-
- return 0;
-}
-
-static void exynos_pm_resume(void)
-{
- if (exynos_pm_central_resume())
- goto early_wakeup;
-
- if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
- exynos_cpu_restore_register();
-
- /* For release retention */
-
- pmu_raw_writel((1 << 28), S5P_PAD_RET_MAUDIO_OPTION);
- pmu_raw_writel((1 << 28), S5P_PAD_RET_GPIO_OPTION);
- pmu_raw_writel((1 << 28), S5P_PAD_RET_UART_OPTION);
- pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCA_OPTION);
- pmu_raw_writel((1 << 28), S5P_PAD_RET_MMCB_OPTION);
- pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIA_OPTION);
- pmu_raw_writel((1 << 28), S5P_PAD_RET_EBIB_OPTION);
-
- if (soc_is_exynos5250())
- s3c_pm_do_restore(exynos5_sys_save,
- ARRAY_SIZE(exynos5_sys_save));
-
- s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
-
- if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
- scu_enable(S5P_VA_SCU);
-
-early_wakeup:
-
- /* Clear SLEEP mode set in INFORM1 */
- pmu_raw_writel(0x0, S5P_INFORM1);
-
- return;
-}
-
-static struct syscore_ops exynos_pm_syscore_ops = {
- .suspend = exynos_pm_suspend,
- .resume = exynos_pm_resume,
-};
-
-/*
- * Suspend Ops
- */
-
-static int exynos_suspend_enter(suspend_state_t state)
-{
- int ret;
-
- s3c_pm_debug_init();
-
- S3C_PMDBG("%s: suspending the system...\n", __func__);
-
- S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__,
- exynos_irqwake_intmask, exynos_get_eint_wake_mask());
-
- if (exynos_irqwake_intmask == -1U
- && exynos_get_eint_wake_mask() == -1U) {
- pr_err("%s: No wake-up sources!\n", __func__);
- pr_err("%s: Aborting sleep\n", __func__);
- return -EINVAL;
- }
-
- s3c_pm_save_uarts();
- exynos_pm_prepare();
- flush_cache_all();
- s3c_pm_check_store();
-
- ret = cpu_suspend(0, exynos_cpu_suspend);
- if (ret)
- return ret;
-
- s3c_pm_restore_uarts();
-
- S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
- pmu_raw_readl(S5P_WAKEUP_STAT));
-
- s3c_pm_check_restore();
-
- S3C_PMDBG("%s: resuming the system...\n", __func__);
-
- return 0;
-}
-
-static int exynos_suspend_prepare(void)
-{
- s3c_pm_check_prepare();
-
- return 0;
-}
-
-static void exynos_suspend_finish(void)
-{
- s3c_pm_check_cleanup();
-}
-
-static const struct platform_suspend_ops exynos_suspend_ops = {
- .enter = exynos_suspend_enter,
- .prepare = exynos_suspend_prepare,
- .finish = exynos_suspend_finish,
- .valid = suspend_valid_only_mem,
-};
-
-void __init exynos_pm_init(void)
-{
- u32 tmp;
-
- /* Platform-specific GIC callback */
- gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
-
- /* All wakeup disable */
- tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
- tmp |= ((0xFF << 8) | (0x1F << 1));
- pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
-
- register_syscore_ops(&exynos_pm_syscore_ops);
- suspend_set_ops(&exynos_suspend_ops);
-}
diff --git a/arch/arm/mach-exynos/pmu.c b/arch/arm/mach-exynos/pmu.c
index ff9d23f..c15761c 100644
--- a/arch/arm/mach-exynos/pmu.c
+++ b/arch/arm/mach-exynos/pmu.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2011-2012 Samsung Electronics Co., Ltd.
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
* http://www.samsung.com/
*
* EXYNOS - CPU PMU(Power Management Unit) support
@@ -10,12 +10,136 @@
*/
#include <linux/io.h>
-#include <linux/kernel.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/delay.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
-#include "common.h"
+
+#include "exynos-pmu.h"
#include "regs-pmu.h"
-static const struct exynos_pmu_conf *exynos_pmu_config;
+#define PMU_TABLE_END (-1U)
+
+struct exynos_pmu_conf {
+ unsigned int offset;
+ u8 val[NUM_SYS_POWERDOWN];
+};
+
+struct exynos_pmu_data {
+ const struct exynos_pmu_conf *pmu_config;
+ const struct exynos_pmu_conf *pmu_config_extra;
+
+ void (*pmu_init)(void);
+ void (*powerdown_conf)(enum sys_powerdown);
+ void (*powerdown_conf_extra)(enum sys_powerdown);
+};
+
+struct exynos_pmu_context {
+ struct device *dev;
+ const struct exynos_pmu_data *pmu_data;
+};
+
+static void __iomem *pmu_base_addr;
+static struct exynos_pmu_context *pmu_context;
+
+static inline void pmu_raw_writel(u32 val, u32 offset)
+{
+ writel_relaxed(val, pmu_base_addr + offset);
+}
+
+static inline u32 pmu_raw_readl(u32 offset)
+{
+ return readl_relaxed(pmu_base_addr + offset);
+}
+
+static struct exynos_pmu_conf exynos3250_pmu_config[] = {
+ /* { .offset = offset, .val = { AFTR, W-AFTR, SLEEP } */
+ { EXYNOS3_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
+ { EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS3_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
+ { EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS3_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS3_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x2} },
+ { EXYNOS3_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x3} },
+ { EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS3_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS3_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x3} },
+ { EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG, { 0x3, 0x3, 0x3} },
+ { EXYNOS3_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS3_CAM_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS3_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS3_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS3_LCD0_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS3_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS3_MAUDIO_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { PMU_TABLE_END,},
+};
static const struct exynos_pmu_conf exynos4210_pmu_config[] = {
/* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
@@ -264,6 +388,7 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = {
{ EXYNOS5_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_JPEG_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_JPEG_MEM_OPTION, { 0x10, 0x10, 0x0} },
{ EXYNOS5_HSI_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_MCUIOP_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
{ EXYNOS5_SATA_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
@@ -315,6 +440,189 @@ static const struct exynos_pmu_conf exynos5250_pmu_config[] = {
{ PMU_TABLE_END,},
};
+static struct exynos_pmu_conf exynos5420_pmu_config[] = {
+ /* { .offset = offset, .val = { AFTR, LPA, SLEEP } */
+ { EXYNOS5_ARM_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_ARM_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_ARM_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_ARM_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_KFC_CORE0_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_KFC_CORE1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_KFC_CORE2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_KFC_CORE3_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_ISP_ARM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_ARM_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_KFC_COMMON_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_ARM_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_KFC_L2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_ACLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CMU_SCLKSTOP_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_CMU_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_CMU_ACLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CMU_SCLKSTOP_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_CMU_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_DRAM_FREQ_DOWN_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_DDRPHY_DLLOFF_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS5_DDRPHY_DLLLOCK_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_APLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_MPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_VPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_EPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_BPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_CPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_MPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_BPLLUSER_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_TOP_BUS_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_TOP_RETENTION_SYS_PWR_REG, { 0x1, 0x1, 0x1} },
+ { EXYNOS5_TOP_PWR_SYS_PWR_REG, { 0x3, 0x3, 0x0} },
+ { EXYNOS5_TOP_BUS_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_TOP_RETENTION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_TOP_PWR_SYSMEM_SYS_PWR_REG, { 0x3, 0x0, 0x0} },
+ { EXYNOS5_LOGIC_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_OSCCLK_GATE_SYS_PWR_REG, { 0x1, 0x0, 0x1} },
+ { EXYNOS5_LOGIC_RESET_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_OSCCLK_GATE_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_INTRAM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} },
+ { EXYNOS5420_INTROM_MEM_SYS_PWR_REG, { 0x3, 0x0, 0x3} },
+ { EXYNOS5_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_RETENTION_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_ISOLATION_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_PAD_ISOLATION_SYSMEM_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_PAD_ALV_SEL_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_XUSBXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_XXTI_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_EXT_REGULATOR_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_GPIO_MODE_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_GPIO_MODE_SYSMEM_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_GPIO_MODE_MAU_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_TOP_ASB_RESET_SYS_PWR_REG, { 0x1, 0x1, 0x0} },
+ { EXYNOS5_TOP_ASB_ISOLATION_SYS_PWR_REG, { 0x1, 0x0, 0x0} },
+ { EXYNOS5_GSCL_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_ISP_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_MFC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_G3D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_DISP1_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_MAU_SYS_PWR_REG, { 0x7, 0x7, 0x0} },
+ { EXYNOS5420_G2D_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_MSC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_FSYS_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_FSYS2_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_PSGEN_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_PERIC_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5420_WCORE_SYS_PWR_REG, { 0x7, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_MFC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG, { 0x0, 0x0, 0x0} },
+ { PMU_TABLE_END,},
+};
+
+static unsigned int const exynos3250_list_feed[] = {
+ EXYNOS3_ARM_CORE_OPTION(0),
+ EXYNOS3_ARM_CORE_OPTION(1),
+ EXYNOS3_ARM_CORE_OPTION(2),
+ EXYNOS3_ARM_CORE_OPTION(3),
+ EXYNOS3_ARM_COMMON_OPTION,
+ EXYNOS3_TOP_PWR_OPTION,
+ EXYNOS3_CORE_TOP_PWR_OPTION,
+ S5P_CAM_OPTION,
+ S5P_MFC_OPTION,
+ S5P_G3D_OPTION,
+ S5P_LCD0_OPTION,
+ S5P_ISP_OPTION,
+};
+
+static void exynos3250_powerdown_conf_extra(enum sys_powerdown mode)
+{
+ unsigned int i;
+ unsigned int tmp;
+
+ /* Enable only SC_FEEDBACK */
+ for (i = 0; i < ARRAY_SIZE(exynos3250_list_feed); i++) {
+ tmp = pmu_raw_readl(exynos3250_list_feed[i]);
+ tmp &= ~(EXYNOS3_OPTION_USE_SC_COUNTER);
+ tmp |= EXYNOS3_OPTION_USE_SC_FEEDBACK;
+ pmu_raw_writel(tmp, exynos3250_list_feed[i]);
+ }
+
+ if (mode != SYS_SLEEP)
+ return;
+
+ pmu_raw_writel(XUSBXTI_DURATION, EXYNOS3_XUSBXTI_DURATION);
+ pmu_raw_writel(XXTI_DURATION, EXYNOS3_XXTI_DURATION);
+ pmu_raw_writel(EXT_REGULATOR_DURATION, EXYNOS3_EXT_REGULATOR_DURATION);
+ pmu_raw_writel(EXT_REGULATOR_COREBLK_DURATION,
+ EXYNOS3_EXT_REGULATOR_COREBLK_DURATION);
+}
+
static unsigned int const exynos5_list_both_cnt_feed[] = {
EXYNOS5_ARM_CORE0_OPTION,
EXYNOS5_ARM_CORE1_OPTION,
@@ -329,13 +637,82 @@ static unsigned int const exynos5_list_both_cnt_feed[] = {
EXYNOS5_TOP_PWR_SYSMEM_OPTION,
};
-static unsigned int const exynos5_list_diable_wfi_wfe[] = {
+static unsigned int const exynos5_list_disable_wfi_wfe[] = {
EXYNOS5_ARM_CORE1_OPTION,
EXYNOS5_FSYS_ARM_OPTION,
EXYNOS5_ISP_ARM_OPTION,
};
-static void exynos5_init_pmu(void)
+static unsigned int const exynos5420_list_disable_pmu_reg[] = {
+ EXYNOS5_CMU_CLKSTOP_GSCL_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_ISP_SYS_PWR_REG,
+ EXYNOS5_CMU_CLKSTOP_G3D_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG,
+ EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_GSCL_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_ISP_SYS_PWR_REG,
+ EXYNOS5_CMU_SYSCLK_G3D_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG,
+ EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_GSCL_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_ISP_SYS_PWR_REG,
+ EXYNOS5_CMU_RESET_G3D_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG,
+ EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG,
+};
+
+static void exynos5_power_off(void)
+{
+ unsigned int tmp;
+
+ pr_info("Power down.\n");
+ tmp = pmu_raw_readl(EXYNOS_PS_HOLD_CONTROL);
+ tmp ^= (1 << 8);
+ pmu_raw_writel(tmp, EXYNOS_PS_HOLD_CONTROL);
+
+ /* Wait a little so we don't give a false warning below */
+ mdelay(100);
+
+ pr_err("Power down failed, please power off system manually.\n");
+ while (1)
+ ;
+}
+
+void exynos5420_powerdown_conf(enum sys_powerdown mode)
+{
+ u32 this_cluster;
+
+ this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+
+ /*
+ * set the cluster id to IROM register to ensure that we wake
+ * up with the current cluster.
+ */
+ pmu_raw_writel(this_cluster, EXYNOS_IROM_DATA2);
+}
+
+
+static void exynos5_powerdown_conf(enum sys_powerdown mode)
{
unsigned int i;
unsigned int tmp;
@@ -343,7 +720,7 @@ static void exynos5_init_pmu(void)
/*
* Enable both SC_FEEDBACK and SC_COUNTER
*/
- for (i = 0 ; i < ARRAY_SIZE(exynos5_list_both_cnt_feed) ; i++) {
+ for (i = 0; i < ARRAY_SIZE(exynos5_list_both_cnt_feed); i++) {
tmp = pmu_raw_readl(exynos5_list_both_cnt_feed[i]);
tmp |= (EXYNOS5_USE_SC_FEEDBACK |
EXYNOS5_USE_SC_COUNTER);
@@ -360,11 +737,11 @@ static void exynos5_init_pmu(void)
/*
* Disable WFI/WFE on XXX_OPTION
*/
- for (i = 0 ; i < ARRAY_SIZE(exynos5_list_diable_wfi_wfe) ; i++) {
- tmp = pmu_raw_readl(exynos5_list_diable_wfi_wfe[i]);
+ for (i = 0; i < ARRAY_SIZE(exynos5_list_disable_wfi_wfe); i++) {
+ tmp = pmu_raw_readl(exynos5_list_disable_wfi_wfe[i]);
tmp &= ~(EXYNOS5_OPTION_USE_STANDBYWFE |
EXYNOS5_OPTION_USE_STANDBYWFI);
- pmu_raw_writel(tmp, exynos5_list_diable_wfi_wfe[i]);
+ pmu_raw_writel(tmp, exynos5_list_disable_wfi_wfe[i]);
}
}
@@ -372,51 +749,257 @@ void exynos_sys_powerdown_conf(enum sys_powerdown mode)
{
unsigned int i;
- if (soc_is_exynos5250())
- exynos5_init_pmu();
+ const struct exynos_pmu_data *pmu_data = pmu_context->pmu_data;
+
+ if (pmu_data->powerdown_conf)
+ pmu_data->powerdown_conf(mode);
+
+ if (pmu_data->pmu_config) {
+ for (i = 0; (pmu_data->pmu_config[i].offset != PMU_TABLE_END); i++)
+ pmu_raw_writel(pmu_data->pmu_config[i].val[mode],
+ pmu_data->pmu_config[i].offset);
+ }
- for (i = 0; (exynos_pmu_config[i].offset != PMU_TABLE_END) ; i++)
- pmu_raw_writel(exynos_pmu_config[i].val[mode],
- exynos_pmu_config[i].offset);
+ if (pmu_data->powerdown_conf_extra)
+ pmu_data->powerdown_conf_extra(mode);
- if (soc_is_exynos4412()) {
- for (i = 0; exynos4412_pmu_config[i].offset != PMU_TABLE_END ; i++)
- pmu_raw_writel(exynos4412_pmu_config[i].val[mode],
- exynos4412_pmu_config[i].offset);
+ if (pmu_data->pmu_config_extra) {
+ for (i = 0; pmu_data->pmu_config_extra[i].offset != PMU_TABLE_END; i++)
+ pmu_raw_writel(pmu_data->pmu_config_extra[i].val[mode],
+ pmu_data->pmu_config_extra[i].offset);
}
}
-static int __init exynos_pmu_init(void)
+static void exynos3250_pmu_init(void)
+{
+ unsigned int value;
+
+ /*
+ * To prevent from issuing new bus request form L2 memory system
+ * If core status is power down, should be set '1' to L2 power down
+ */
+ value = pmu_raw_readl(EXYNOS3_ARM_COMMON_OPTION);
+ value |= EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
+ pmu_raw_writel(value, EXYNOS3_ARM_COMMON_OPTION);
+
+ /* Enable USE_STANDBY_WFI for all CORE */
+ pmu_raw_writel(S5P_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
+
+ /*
+ * Set PSHOLD port for output high
+ */
+ value = pmu_raw_readl(S5P_PS_HOLD_CONTROL);
+ value |= S5P_PS_HOLD_OUTPUT_HIGH;
+ pmu_raw_writel(value, S5P_PS_HOLD_CONTROL);
+
+ /*
+ * Enable signal for PSHOLD port
+ */
+ value = pmu_raw_readl(S5P_PS_HOLD_CONTROL);
+ value |= S5P_PS_HOLD_EN;
+ pmu_raw_writel(value, S5P_PS_HOLD_CONTROL);
+}
+
+static void exynos5250_pmu_init(void)
{
unsigned int value;
+ /*
+ * When SYS_WDTRESET is set, watchdog timer reset request
+ * is ignored by power management unit.
+ */
+ value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE);
+ value &= ~EXYNOS5_SYS_WDTRESET;
+ pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE);
+
+ value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST);
+ value &= ~EXYNOS5_SYS_WDTRESET;
+ pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
+}
+
+static void exynos5420_pmu_init(void)
+{
+ unsigned int value;
+ int i;
+
+ /*
+ * Set the CMU_RESET, CMU_SYSCLK and CMU_CLKSTOP registers
+ * for local power blocks to Low initially as per Table 8-4:
+ * "System-Level Power-Down Configuration Registers".
+ */
+ for (i = 0; i < ARRAY_SIZE(exynos5420_list_disable_pmu_reg); i++)
+ pmu_raw_writel(0, exynos5420_list_disable_pmu_reg[i]);
+
+ /* Enable USE_STANDBY_WFI for all CORE */
+ pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL, S5P_CENTRAL_SEQ_OPTION);
+
+ value = pmu_raw_readl(EXYNOS_L2_OPTION(0));
+ value &= ~EXYNOS5_USE_RETENTION;
+ pmu_raw_writel(value, EXYNOS_L2_OPTION(0));
+
+ value = pmu_raw_readl(EXYNOS_L2_OPTION(1));
+ value &= ~EXYNOS5_USE_RETENTION;
+ pmu_raw_writel(value, EXYNOS_L2_OPTION(1));
+
+ /*
+ * If L2_COMMON is turned off, clocks related to ATB async
+ * bridge are gated. Thus, when ISP power is gated, LPI
+ * may get stuck.
+ */
+ value = pmu_raw_readl(EXYNOS5420_LPI_MASK);
+ value |= EXYNOS5420_ATB_ISP_ARM;
+ pmu_raw_writel(value, EXYNOS5420_LPI_MASK);
+
+ value = pmu_raw_readl(EXYNOS5420_LPI_MASK1);
+ value |= EXYNOS5420_ATB_KFC;
+ pmu_raw_writel(value, EXYNOS5420_LPI_MASK1);
+
+ /* Prevent issue of new bus request from L2 memory */
+ value = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION);
+ value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
+ pmu_raw_writel(value, EXYNOS5420_ARM_COMMON_OPTION);
+
+ value = pmu_raw_readl(EXYNOS5420_KFC_COMMON_OPTION);
+ value |= EXYNOS5_SKIP_DEACTIVATE_ACEACP_IN_PWDN;
+ pmu_raw_writel(value, EXYNOS5420_KFC_COMMON_OPTION);
+
+ /* This setting is to reduce suspend/resume time */
+ pmu_raw_writel(DUR_WAIT_RESET, EXYNOS5420_LOGIC_RESET_DURATION3);
+
+ /* Serialized CPU wakeup of Eagle */
+ pmu_raw_writel(SPREAD_ENABLE, EXYNOS5420_ARM_INTR_SPREAD_ENABLE);
+
+ pmu_raw_writel(SPREAD_USE_STANDWFI,
+ EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI);
+
+ pmu_raw_writel(0x1, EXYNOS5420_UP_SCHEDULER);
+
+ pm_power_off = exynos5_power_off;
+ pr_info("EXYNOS5420 PMU initialized\n");
+}
+
+static int pmu_restart_notify(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ pmu_raw_writel(0x1, EXYNOS_SWRESET);
+
+ return NOTIFY_DONE;
+}
+
+static const struct exynos_pmu_data exynos3250_pmu_data = {
+ .pmu_config = exynos3250_pmu_config,
+ .pmu_init = exynos3250_pmu_init,
+ .powerdown_conf_extra = exynos3250_powerdown_conf_extra,
+};
- exynos_pmu_config = exynos4210_pmu_config;
-
- if (soc_is_exynos4210()) {
- exynos_pmu_config = exynos4210_pmu_config;
- pr_info("EXYNOS4210 PMU Initialize\n");
- } else if (soc_is_exynos4212() || soc_is_exynos4412()) {
- exynos_pmu_config = exynos4x12_pmu_config;
- pr_info("EXYNOS4x12 PMU Initialize\n");
- } else if (soc_is_exynos5250()) {
- /*
- * When SYS_WDTRESET is set, watchdog timer reset request
- * is ignored by power management unit.
- */
- value = pmu_raw_readl(EXYNOS5_AUTO_WDTRESET_DISABLE);
- value &= ~EXYNOS5_SYS_WDTRESET;
- pmu_raw_writel(value, EXYNOS5_AUTO_WDTRESET_DISABLE);
-
- value = pmu_raw_readl(EXYNOS5_MASK_WDTRESET_REQUEST);
- value &= ~EXYNOS5_SYS_WDTRESET;
- pmu_raw_writel(value, EXYNOS5_MASK_WDTRESET_REQUEST);
-
- exynos_pmu_config = exynos5250_pmu_config;
- pr_info("EXYNOS5250 PMU Initialize\n");
- } else {
- pr_info("EXYNOS: PMU not supported\n");
+static const struct exynos_pmu_data exynos4210_pmu_data = {
+ .pmu_config = exynos4210_pmu_config,
+};
+
+static const struct exynos_pmu_data exynos4212_pmu_data = {
+ .pmu_config = exynos4x12_pmu_config,
+};
+
+static const struct exynos_pmu_data exynos4412_pmu_data = {
+ .pmu_config = exynos4x12_pmu_config,
+ .pmu_config_extra = exynos4412_pmu_config,
+};
+
+static const struct exynos_pmu_data exynos5250_pmu_data = {
+ .pmu_config = exynos5250_pmu_config,
+ .pmu_init = exynos5250_pmu_init,
+ .powerdown_conf = exynos5_powerdown_conf,
+};
+
+static struct exynos_pmu_data exynos5420_pmu_data = {
+ .pmu_config = exynos5420_pmu_config,
+ .pmu_init = exynos5420_pmu_init,
+ .powerdown_conf = exynos5420_powerdown_conf,
+};
+
+/*
+ * PMU platform driver and devicetree bindings.
+ */
+static const struct of_device_id exynos_pmu_of_device_ids[] = {
+ {
+ .compatible = "samsung,exynos3250-pmu",
+ .data = &exynos3250_pmu_data,
+ }, {
+ .compatible = "samsung,exynos4210-pmu",
+ .data = &exynos4210_pmu_data,
+ }, {
+ .compatible = "samsung,exynos4212-pmu",
+ .data = &exynos4212_pmu_data,
+ }, {
+ .compatible = "samsung,exynos4412-pmu",
+ .data = &exynos4412_pmu_data,
+ }, {
+ .compatible = "samsung,exynos5250-pmu",
+ .data = &exynos5250_pmu_data,
+ }, {
+ .compatible = "samsung,exynos5420-pmu",
+ .data = &exynos5420_pmu_data,
+ },
+ { /*sentinel*/ },
+};
+
+/*
+ * Exynos PMU restart notifier, handles restart functionality
+ */
+static struct notifier_block pmu_restart_handler = {
+ .notifier_call = pmu_restart_notify,
+ .priority = 128,
+};
+
+static int exynos_pmu_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct device *dev = &pdev->dev;
+ struct resource *res;
+ int ret;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pmu_base_addr = devm_ioremap_resource(dev, res);
+ if (IS_ERR(pmu_base_addr))
+ return PTR_ERR(pmu_base_addr);
+
+ pmu_context = devm_kzalloc(&pdev->dev,
+ sizeof(struct exynos_pmu_context),
+ GFP_KERNEL);
+ if (!pmu_context) {
+ dev_err(dev, "Cannot allocate memory.\n");
+ return -ENOMEM;
}
+ pmu_context->dev = dev;
+
+ match = of_match_node(exynos_pmu_of_device_ids, dev->of_node);
+
+ pmu_context->pmu_data = match->data;
+
+ if (pmu_context->pmu_data->pmu_init)
+ pmu_context->pmu_data->pmu_init();
+
+ platform_set_drvdata(pdev, pmu_context);
+ ret = register_restart_handler(&pmu_restart_handler);
+ if (ret)
+ dev_warn(dev, "can't register restart handler err=%d\n", ret);
+
+ dev_dbg(dev, "Exynos PMU Driver probe done\n");
return 0;
}
-arch_initcall(exynos_pmu_init);
+
+static struct platform_driver exynos_pmu_driver = {
+ .driver = {
+ .name = "exynos-pmu",
+ .owner = THIS_MODULE,
+ .of_match_table = exynos_pmu_of_device_ids,
+ },
+ .probe = exynos_pmu_probe,
+};
+
+static int __init exynos_pmu_init(void)
+{
+ return platform_driver_register(&exynos_pmu_driver);
+
+}
+postcore_initcall(exynos_pmu_init);
diff --git a/arch/arm/mach-exynos/regs-pmu.h b/arch/arm/mach-exynos/regs-pmu.h
index 96a1569..b5f4406 100644
--- a/arch/arm/mach-exynos/regs-pmu.h
+++ b/arch/arm/mach-exynos/regs-pmu.h
@@ -19,8 +19,24 @@
#define S5P_CENTRAL_SEQ_OPTION 0x0208
#define S5P_USE_STANDBY_WFI0 (1 << 16)
+#define S5P_USE_STANDBY_WFI1 (1 << 17)
+#define S5P_USE_STANDBY_WFI2 (1 << 19)
+#define S5P_USE_STANDBY_WFI3 (1 << 20)
#define S5P_USE_STANDBY_WFE0 (1 << 24)
+#define S5P_USE_STANDBY_WFE1 (1 << 25)
+#define S5P_USE_STANDBY_WFE2 (1 << 27)
+#define S5P_USE_STANDBY_WFE3 (1 << 28)
+#define S5P_USE_STANDBY_WFI_ALL \
+ (S5P_USE_STANDBY_WFI0 | S5P_USE_STANDBY_WFI1 | \
+ S5P_USE_STANDBY_WFI2 | S5P_USE_STANDBY_WFI3 | \
+ S5P_USE_STANDBY_WFE0 | S5P_USE_STANDBY_WFE1 | \
+ S5P_USE_STANDBY_WFE2 | S5P_USE_STANDBY_WFE3)
+
+#define S5P_USE_DELAYED_RESET_ASSERTION BIT(12)
+
+#define EXYNOS_CORE_PO_RESET(n) ((1 << 4) << n)
+#define EXYNOS_WAKEUP_FROM_LOWPWR (1 << 28)
#define EXYNOS_SWRESET 0x0400
#define EXYNOS5440_SWRESET 0x00C4
@@ -35,6 +51,7 @@
#define S5P_INFORM7 0x081C
#define S5P_PMU_SPARE3 0x090C
+#define EXYNOS_IROM_DATA2 0x0988
#define S5P_ARM_CORE0_LOWPWR 0x1000
#define S5P_DIS_IRQ_CORE0 0x1004
#define S5P_DIS_IRQ_CENTRAL0 0x1008
@@ -106,6 +123,8 @@
(EXYNOS_ARM_CORE0_CONFIGURATION + (0x80 * (_nr)))
#define EXYNOS_ARM_CORE_STATUS(_nr) \
(EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x4)
+#define EXYNOS_ARM_CORE_OPTION(_nr) \
+ (EXYNOS_ARM_CORE_CONFIGURATION(_nr) + 0x8)
#define EXYNOS_ARM_COMMON_CONFIGURATION 0x2500
#define EXYNOS_COMMON_CONFIGURATION(_nr) \
@@ -115,6 +134,31 @@
#define EXYNOS_COMMON_OPTION(_nr) \
(EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8)
+#define EXYNOS_CORE_LOCAL_PWR_EN 0x3
+
+#define EXYNOS_ARM_COMMON_STATUS 0x2504
+#define EXYNOS_COMMON_OPTION(_nr) \
+ (EXYNOS_COMMON_CONFIGURATION(_nr) + 0x8)
+
+#define EXYNOS_ARM_L2_CONFIGURATION 0x2600
+#define EXYNOS_L2_CONFIGURATION(_nr) \
+ (EXYNOS_ARM_L2_CONFIGURATION + ((_nr) * 0x80))
+#define EXYNOS_L2_STATUS(_nr) \
+ (EXYNOS_L2_CONFIGURATION(_nr) + 0x4)
+#define EXYNOS_L2_OPTION(_nr) \
+ (EXYNOS_L2_CONFIGURATION(_nr) + 0x8)
+#define EXYNOS_L2_COMMON_PWR_EN 0x3
+
+#define EXYNOS_ARM_CORE_X_STATUS_OFFSET 0x4
+
+#define EXYNOS5_APLL_SYSCLK_CONFIGURATION 0x2A00
+#define EXYNOS5_APLL_SYSCLK_STATUS 0x2A04
+
+#define EXYNOS5_ARM_L2_OPTION 0x2608
+#define EXYNOS5_USE_RETENTION BIT(4)
+
+#define EXYNOS5_L2RSTDISABLE_VALUE BIT(3)
+
#define S5P_PAD_RET_MAUDIO_OPTION 0x3028
#define S5P_PAD_RET_GPIO_OPTION 0x3108
#define S5P_PAD_RET_UART_OPTION 0x3128
@@ -123,7 +167,19 @@
#define S5P_PAD_RET_EBIA_OPTION 0x3188
#define S5P_PAD_RET_EBIB_OPTION 0x31A8
+#define S5P_PS_HOLD_CONTROL 0x330C
+#define S5P_PS_HOLD_EN (1 << 31)
+#define S5P_PS_HOLD_OUTPUT_HIGH (3 << 8)
+
+#define S5P_CAM_OPTION 0x3C08
+#define S5P_MFC_OPTION 0x3C48
+#define S5P_G3D_OPTION 0x3C68
+#define S5P_LCD0_OPTION 0x3C88
+#define S5P_LCD1_OPTION 0x3CA8
+#define S5P_ISP_OPTION S5P_LCD1_OPTION
+
#define S5P_CORE_LOCAL_PWR_EN 0x3
+#define S5P_CORE_WAKEUP_FROM_LOCAL_CFG (0x3 << 8)
/* Only for EXYNOS4210 */
#define S5P_CMU_CLKSTOP_LCD1_LOWPWR 0x1154
@@ -182,11 +238,116 @@
#define S5P_DIS_IRQ_CORE3 0x1034
#define S5P_DIS_IRQ_CENTRAL3 0x1038
+/* Only for EXYNOS3XXX */
+#define EXYNOS3_ARM_CORE0_SYS_PWR_REG 0x1000
+#define EXYNOS3_DIS_IRQ_ARM_CORE0_LOCAL_SYS_PWR_REG 0x1004
+#define EXYNOS3_DIS_IRQ_ARM_CORE0_CENTRAL_SYS_PWR_REG 0x1008
+#define EXYNOS3_ARM_CORE1_SYS_PWR_REG 0x1010
+#define EXYNOS3_DIS_IRQ_ARM_CORE1_LOCAL_SYS_PWR_REG 0x1014
+#define EXYNOS3_DIS_IRQ_ARM_CORE1_CENTRAL_SYS_PWR_REG 0x1018
+#define EXYNOS3_ISP_ARM_SYS_PWR_REG 0x1050
+#define EXYNOS3_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1054
+#define EXYNOS3_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1058
+#define EXYNOS3_ARM_COMMON_SYS_PWR_REG 0x1080
+#define EXYNOS3_ARM_L2_SYS_PWR_REG 0x10C0
+#define EXYNOS3_CMU_ACLKSTOP_SYS_PWR_REG 0x1100
+#define EXYNOS3_CMU_SCLKSTOP_SYS_PWR_REG 0x1104
+#define EXYNOS3_CMU_RESET_SYS_PWR_REG 0x110C
+#define EXYNOS3_CMU_ACLKSTOP_COREBLK_SYS_PWR_REG 0x1110
+#define EXYNOS3_CMU_SCLKSTOP_COREBLK_SYS_PWR_REG 0x1114
+#define EXYNOS3_CMU_RESET_COREBLK_SYS_PWR_REG 0x111C
+#define EXYNOS3_APLL_SYSCLK_SYS_PWR_REG 0x1120
+#define EXYNOS3_MPLL_SYSCLK_SYS_PWR_REG 0x1124
+#define EXYNOS3_VPLL_SYSCLK_SYS_PWR_REG 0x1128
+#define EXYNOS3_EPLL_SYSCLK_SYS_PWR_REG 0x112C
+#define EXYNOS3_MPLLUSER_SYSCLK_SYS_PWR_REG 0x1130
+#define EXYNOS3_BPLLUSER_SYSCLK_SYS_PWR_REG 0x1134
+#define EXYNOS3_EPLLUSER_SYSCLK_SYS_PWR_REG 0x1138
+#define EXYNOS3_CMU_CLKSTOP_CAM_SYS_PWR_REG 0x1140
+#define EXYNOS3_CMU_CLKSTOP_MFC_SYS_PWR_REG 0x1148
+#define EXYNOS3_CMU_CLKSTOP_G3D_SYS_PWR_REG 0x114C
+#define EXYNOS3_CMU_CLKSTOP_LCD0_SYS_PWR_REG 0x1150
+#define EXYNOS3_CMU_CLKSTOP_ISP_SYS_PWR_REG 0x1154
+#define EXYNOS3_CMU_CLKSTOP_MAUDIO_SYS_PWR_REG 0x1158
+#define EXYNOS3_CMU_RESET_CAM_SYS_PWR_REG 0x1160
+#define EXYNOS3_CMU_RESET_MFC_SYS_PWR_REG 0x1168
+#define EXYNOS3_CMU_RESET_G3D_SYS_PWR_REG 0x116C
+#define EXYNOS3_CMU_RESET_LCD0_SYS_PWR_REG 0x1170
+#define EXYNOS3_CMU_RESET_ISP_SYS_PWR_REG 0x1174
+#define EXYNOS3_CMU_RESET_MAUDIO_SYS_PWR_REG 0x1178
+#define EXYNOS3_TOP_BUS_SYS_PWR_REG 0x1180
+#define EXYNOS3_TOP_RETENTION_SYS_PWR_REG 0x1184
+#define EXYNOS3_TOP_PWR_SYS_PWR_REG 0x1188
+#define EXYNOS3_TOP_BUS_COREBLK_SYS_PWR_REG 0x1190
+#define EXYNOS3_TOP_RETENTION_COREBLK_SYS_PWR_REG 0x1194
+#define EXYNOS3_TOP_PWR_COREBLK_SYS_PWR_REG 0x1198
+#define EXYNOS3_LOGIC_RESET_SYS_PWR_REG 0x11A0
+#define EXYNOS3_OSCCLK_GATE_SYS_PWR_REG 0x11A4
+#define EXYNOS3_LOGIC_RESET_COREBLK_SYS_PWR_REG 0x11B0
+#define EXYNOS3_OSCCLK_GATE_COREBLK_SYS_PWR_REG 0x11B4
+#define EXYNOS3_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1200
+#define EXYNOS3_PAD_RETENTION_MAUDIO_SYS_PWR_REG 0x1204
+#define EXYNOS3_PAD_RETENTION_SPI_SYS_PWR_REG 0x1208
+#define EXYNOS3_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1218
+#define EXYNOS3_PAD_RETENTION_GPIO_SYS_PWR_REG 0x1220
+#define EXYNOS3_PAD_RETENTION_UART_SYS_PWR_REG 0x1224
+#define EXYNOS3_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1228
+#define EXYNOS3_PAD_RETENTION_MMC1_SYS_PWR_REG 0x122C
+#define EXYNOS3_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1230
+#define EXYNOS3_PAD_RETENTION_EBIB_SYS_PWR_REG 0x1234
+#define EXYNOS3_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1238
+#define EXYNOS3_PAD_ISOLATION_SYS_PWR_REG 0x1240
+#define EXYNOS3_PAD_ALV_SEL_SYS_PWR_REG 0x1260
+#define EXYNOS3_XUSBXTI_SYS_PWR_REG 0x1280
+#define EXYNOS3_XXTI_SYS_PWR_REG 0x1284
+#define EXYNOS3_EXT_REGULATOR_SYS_PWR_REG 0x12C0
+#define EXYNOS3_EXT_REGULATOR_COREBLK_SYS_PWR_REG 0x12C4
+#define EXYNOS3_GPIO_MODE_SYS_PWR_REG 0x1300
+#define EXYNOS3_GPIO_MODE_MAUDIO_SYS_PWR_REG 0x1340
+#define EXYNOS3_TOP_ASB_RESET_SYS_PWR_REG 0x1344
+#define EXYNOS3_TOP_ASB_ISOLATION_SYS_PWR_REG 0x1348
+#define EXYNOS3_TOP_ASB_RESET_COREBLK_SYS_PWR_REG 0x1350
+#define EXYNOS3_TOP_ASB_ISOLATION_COREBLK_SYS_PWR_REG 0x1354
+#define EXYNOS3_CAM_SYS_PWR_REG 0x1380
+#define EXYNOS3_MFC_SYS_PWR_REG 0x1388
+#define EXYNOS3_G3D_SYS_PWR_REG 0x138C
+#define EXYNOS3_LCD0_SYS_PWR_REG 0x1390
+#define EXYNOS3_ISP_SYS_PWR_REG 0x1394
+#define EXYNOS3_MAUDIO_SYS_PWR_REG 0x1398
+#define EXYNOS3_DRAM_FREQ_DOWN_SYS_PWR_REG 0x13B0
+#define EXYNOS3_DDRPHY_DLLOFF_SYS_PWR_REG 0x13B4
+#define EXYNOS3_CMU_SYSCLK_ISP_SYS_PWR_REG 0x13B8
+#define EXYNOS3_LPDDR_PHY_DLL_LOCK_SYS_PWR_REG 0x13C0
+#define EXYNOS3_BPLL_SYSCLK_SYS_PWR_REG 0x13C4
+#define EXYNOS3_UPLL_SYSCLK_SYS_PWR_REG 0x13C8
+
+#define EXYNOS3_ARM_CORE0_OPTION 0x2008
+#define EXYNOS3_ARM_CORE_OPTION(_nr) \
+ (EXYNOS3_ARM_CORE0_OPTION + ((_nr) * 0x80))
+
+#define EXYNOS3_ARM_COMMON_OPTION 0x2408
+#define EXYNOS3_TOP_PWR_OPTION 0x2C48
+#define EXYNOS3_CORE_TOP_PWR_OPTION 0x2CA8
+#define EXYNOS3_XUSBXTI_DURATION 0x341C
+#define EXYNOS3_XXTI_DURATION 0x343C
+#define EXYNOS3_EXT_REGULATOR_DURATION 0x361C
+#define EXYNOS3_EXT_REGULATOR_COREBLK_DURATION 0x363C
+#define XUSBXTI_DURATION 0x00000BB8
+#define XXTI_DURATION XUSBXTI_DURATION
+#define EXT_REGULATOR_DURATION 0x00001D4C
+#define EXT_REGULATOR_COREBLK_DURATION EXT_REGULATOR_DURATION
+
+/* for XXX_OPTION */
+#define EXYNOS3_OPTION_USE_SC_COUNTER (1 << 0)
+#define EXYNOS3_OPTION_USE_SC_FEEDBACK (1 << 1)
+#define EXYNOS3_OPTION_SKIP_DEACTIVATE_ACEACP_IN_PWDN (1 << 7)
+
/* For EXYNOS5 */
#define EXYNOS5_AUTO_WDTRESET_DISABLE 0x0408
#define EXYNOS5_MASK_WDTRESET_REQUEST 0x040C
+#define EXYNOS5_USE_RETENTION BIT(4)
#define EXYNOS5_SYS_WDTRESET (1 << 20)
#define EXYNOS5_ARM_CORE0_SYS_PWR_REG 0x1000
@@ -326,4 +487,204 @@ static inline unsigned int exynos_pmu_cpunr(unsigned int mpidr)
+ MPIDR_AFFINITY_LEVEL(mpidr, 0));
}
+/* Only for EXYNOS5420 */
+#define EXYNOS5420_ISP_ARM_OPTION 0x2488
+#define EXYNOS5420_L2RSTDISABLE_VALUE BIT(3)
+
+#define EXYNOS5420_LPI_MASK 0x0004
+#define EXYNOS5420_LPI_MASK1 0x0008
+#define EXYNOS5420_UFS BIT(8)
+#define EXYNOS5420_ATB_KFC BIT(13)
+#define EXYNOS5420_ATB_ISP_ARM BIT(19)
+#define EXYNOS5420_EMULATION BIT(31)
+#define ATB_ISP_ARM BIT(12)
+#define ATB_KFC BIT(13)
+#define ATB_NOC BIT(14)
+
+#define EXYNOS5420_ARM_INTR_SPREAD_ENABLE 0x0100
+#define EXYNOS5420_ARM_INTR_SPREAD_USE_STANDBYWFI 0x0104
+#define EXYNOS5420_UP_SCHEDULER 0x0120
+#define SPREAD_ENABLE 0xF
+#define SPREAD_USE_STANDWFI 0xF
+
+#define EXYNOS5420_BB_CON1 0x0784
+#define EXYNOS5420_BB_SEL_EN BIT(31)
+#define EXYNOS5420_BB_PMOS_EN BIT(7)
+#define EXYNOS5420_BB_1300X 0XF
+
+#define EXYNOS5420_ARM_CORE2_SYS_PWR_REG 0x1020
+#define EXYNOS5420_DIS_IRQ_ARM_CORE2_LOCAL_SYS_PWR_REG 0x1024
+#define EXYNOS5420_DIS_IRQ_ARM_CORE2_CENTRAL_SYS_PWR_REG 0x1028
+#define EXYNOS5420_ARM_CORE3_SYS_PWR_REG 0x1030
+#define EXYNOS5420_DIS_IRQ_ARM_CORE3_LOCAL_SYS_PWR_REG 0x1034
+#define EXYNOS5420_DIS_IRQ_ARM_CORE3_CENTRAL_SYS_PWR_REG 0x1038
+#define EXYNOS5420_KFC_CORE0_SYS_PWR_REG 0x1040
+#define EXYNOS5420_DIS_IRQ_KFC_CORE0_LOCAL_SYS_PWR_REG 0x1044
+#define EXYNOS5420_DIS_IRQ_KFC_CORE0_CENTRAL_SYS_PWR_REG 0x1048
+#define EXYNOS5420_KFC_CORE1_SYS_PWR_REG 0x1050
+#define EXYNOS5420_DIS_IRQ_KFC_CORE1_LOCAL_SYS_PWR_REG 0x1054
+#define EXYNOS5420_DIS_IRQ_KFC_CORE1_CENTRAL_SYS_PWR_REG 0x1058
+#define EXYNOS5420_KFC_CORE2_SYS_PWR_REG 0x1060
+#define EXYNOS5420_DIS_IRQ_KFC_CORE2_LOCAL_SYS_PWR_REG 0x1064
+#define EXYNOS5420_DIS_IRQ_KFC_CORE2_CENTRAL_SYS_PWR_REG 0x1068
+#define EXYNOS5420_KFC_CORE3_SYS_PWR_REG 0x1070
+#define EXYNOS5420_DIS_IRQ_KFC_CORE3_LOCAL_SYS_PWR_REG 0x1074
+#define EXYNOS5420_DIS_IRQ_KFC_CORE3_CENTRAL_SYS_PWR_REG 0x1078
+#define EXYNOS5420_ISP_ARM_SYS_PWR_REG 0x1090
+#define EXYNOS5420_DIS_IRQ_ISP_ARM_LOCAL_SYS_PWR_REG 0x1094
+#define EXYNOS5420_DIS_IRQ_ISP_ARM_CENTRAL_SYS_PWR_REG 0x1098
+#define EXYNOS5420_ARM_COMMON_SYS_PWR_REG 0x10A0
+#define EXYNOS5420_KFC_COMMON_SYS_PWR_REG 0x10B0
+#define EXYNOS5420_KFC_L2_SYS_PWR_REG 0x10D0
+#define EXYNOS5420_DPLL_SYSCLK_SYS_PWR_REG 0x1158
+#define EXYNOS5420_IPLL_SYSCLK_SYS_PWR_REG 0x115C
+#define EXYNOS5420_KPLL_SYSCLK_SYS_PWR_REG 0x1160
+#define EXYNOS5420_RPLL_SYSCLK_SYS_PWR_REG 0x1174
+#define EXYNOS5420_SPLL_SYSCLK_SYS_PWR_REG 0x1178
+#define EXYNOS5420_INTRAM_MEM_SYS_PWR_REG 0x11B8
+#define EXYNOS5420_INTROM_MEM_SYS_PWR_REG 0x11BC
+#define EXYNOS5420_ONENANDXL_MEM_SYS_PWR 0x11C0
+#define EXYNOS5420_USBDEV_MEM_SYS_PWR 0x11CC
+#define EXYNOS5420_USBDEV1_MEM_SYS_PWR 0x11D0
+#define EXYNOS5420_SDMMC_MEM_SYS_PWR 0x11D4
+#define EXYNOS5420_CSSYS_MEM_SYS_PWR 0x11D8
+#define EXYNOS5420_SECSS_MEM_SYS_PWR 0x11DC
+#define EXYNOS5420_ROTATOR_MEM_SYS_PWR 0x11E0
+#define EXYNOS5420_INTRAM_MEM_SYS_PWR 0x11E4
+#define EXYNOS5420_INTROM_MEM_SYS_PWR 0x11E8
+#define EXYNOS5420_PAD_RETENTION_JTAG_SYS_PWR_REG 0x1208
+#define EXYNOS5420_PAD_RETENTION_DRAM_SYS_PWR_REG 0x1210
+#define EXYNOS5420_PAD_RETENTION_UART_SYS_PWR_REG 0x1214
+#define EXYNOS5420_PAD_RETENTION_MMC0_SYS_PWR_REG 0x1218
+#define EXYNOS5420_PAD_RETENTION_MMC1_SYS_PWR_REG 0x121C
+#define EXYNOS5420_PAD_RETENTION_MMC2_SYS_PWR_REG 0x1220
+#define EXYNOS5420_PAD_RETENTION_HSI_SYS_PWR_REG 0x1224
+#define EXYNOS5420_PAD_RETENTION_EBIA_SYS_PWR_REG 0x1228
+#define EXYNOS5420_PAD_RETENTION_EBIB_SYS_PWR_REG 0x122C
+#define EXYNOS5420_PAD_RETENTION_SPI_SYS_PWR_REG 0x1230
+#define EXYNOS5420_PAD_RETENTION_DRAM_COREBLK_SYS_PWR_REG 0x1234
+#define EXYNOS5420_DISP1_SYS_PWR_REG 0x1410
+#define EXYNOS5420_MAU_SYS_PWR_REG 0x1414
+#define EXYNOS5420_G2D_SYS_PWR_REG 0x1418
+#define EXYNOS5420_MSC_SYS_PWR_REG 0x141C
+#define EXYNOS5420_FSYS_SYS_PWR_REG 0x1420
+#define EXYNOS5420_FSYS2_SYS_PWR_REG 0x1424
+#define EXYNOS5420_PSGEN_SYS_PWR_REG 0x1428
+#define EXYNOS5420_PERIC_SYS_PWR_REG 0x142C
+#define EXYNOS5420_WCORE_SYS_PWR_REG 0x1430
+#define EXYNOS5420_CMU_CLKSTOP_DISP1_SYS_PWR_REG 0x1490
+#define EXYNOS5420_CMU_CLKSTOP_MAU_SYS_PWR_REG 0x1494
+#define EXYNOS5420_CMU_CLKSTOP_G2D_SYS_PWR_REG 0x1498
+#define EXYNOS5420_CMU_CLKSTOP_MSC_SYS_PWR_REG 0x149C
+#define EXYNOS5420_CMU_CLKSTOP_FSYS_SYS_PWR_REG 0x14A0
+#define EXYNOS5420_CMU_CLKSTOP_FSYS2_SYS_PWR_REG 0x14A4
+#define EXYNOS5420_CMU_CLKSTOP_PSGEN_SYS_PWR_REG 0x14A8
+#define EXYNOS5420_CMU_CLKSTOP_PERIC_SYS_PWR_REG 0x14AC
+#define EXYNOS5420_CMU_CLKSTOP_WCORE_SYS_PWR_REG 0x14B0
+#define EXYNOS5420_CMU_SYSCLK_TOPPWR_SYS_PWR_REG 0x14BC
+#define EXYNOS5420_CMU_SYSCLK_DISP1_SYS_PWR_REG 0x14D0
+#define EXYNOS5420_CMU_SYSCLK_MAU_SYS_PWR_REG 0x14D4
+#define EXYNOS5420_CMU_SYSCLK_G2D_SYS_PWR_REG 0x14D8
+#define EXYNOS5420_CMU_SYSCLK_MSC_SYS_PWR_REG 0x14DC
+#define EXYNOS5420_CMU_SYSCLK_FSYS_SYS_PWR_REG 0x14E0
+#define EXYNOS5420_CMU_SYSCLK_FSYS2_SYS_PWR_REG 0x14E4
+#define EXYNOS5420_CMU_SYSCLK_PSGEN_SYS_PWR_REG 0x14E8
+#define EXYNOS5420_CMU_SYSCLK_PERIC_SYS_PWR_REG 0x14EC
+#define EXYNOS5420_CMU_SYSCLK_WCORE_SYS_PWR_REG 0x14F0
+#define EXYNOS5420_CMU_SYSCLK_SYSMEM_TOPPWR_SYS_PWR_REG 0x14F4
+#define EXYNOS5420_CMU_RESET_FSYS2_SYS_PWR_REG 0x1570
+#define EXYNOS5420_CMU_RESET_PSGEN_SYS_PWR_REG 0x1574
+#define EXYNOS5420_CMU_RESET_PERIC_SYS_PWR_REG 0x1578
+#define EXYNOS5420_CMU_RESET_WCORE_SYS_PWR_REG 0x157C
+#define EXYNOS5420_CMU_RESET_DISP1_SYS_PWR_REG 0x1590
+#define EXYNOS5420_CMU_RESET_MAU_SYS_PWR_REG 0x1594
+#define EXYNOS5420_CMU_RESET_G2D_SYS_PWR_REG 0x1598
+#define EXYNOS5420_CMU_RESET_MSC_SYS_PWR_REG 0x159C
+#define EXYNOS5420_CMU_RESET_FSYS_SYS_PWR_REG 0x15A0
+#define EXYNOS5420_SFR_AXI_CGDIS1 0x15E4
+#define EXYNOS_ARM_CORE2_CONFIGURATION 0x2100
+#define EXYNOS5420_ARM_CORE2_OPTION 0x2108
+#define EXYNOS_ARM_CORE3_CONFIGURATION 0x2180
+#define EXYNOS5420_ARM_CORE3_OPTION 0x2188
+#define EXYNOS5420_ARM_COMMON_STATUS 0x2504
+#define EXYNOS5420_ARM_COMMON_OPTION 0x2508
+#define EXYNOS5420_KFC_COMMON_STATUS 0x2584
+#define EXYNOS5420_KFC_COMMON_OPTION 0x2588
+#define EXYNOS5420_LOGIC_RESET_DURATION3 0x2D1C
+
+#define EXYNOS5420_PAD_RET_GPIO_OPTION 0x30C8
+#define EXYNOS5420_PAD_RET_UART_OPTION 0x30E8
+#define EXYNOS5420_PAD_RET_MMCA_OPTION 0x3108
+#define EXYNOS5420_PAD_RET_MMCB_OPTION 0x3128
+#define EXYNOS5420_PAD_RET_MMCC_OPTION 0x3148
+#define EXYNOS5420_PAD_RET_HSI_OPTION 0x3168
+#define EXYNOS5420_PAD_RET_SPI_OPTION 0x31C8
+#define EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION 0x31E8
+#define EXYNOS_PAD_RET_DRAM_OPTION 0x3008
+#define EXYNOS_PAD_RET_MAUDIO_OPTION 0x3028
+#define EXYNOS_PAD_RET_JTAG_OPTION 0x3048
+#define EXYNOS_PAD_RET_GPIO_OPTION 0x3108
+#define EXYNOS_PAD_RET_UART_OPTION 0x3128
+#define EXYNOS_PAD_RET_MMCA_OPTION 0x3148
+#define EXYNOS_PAD_RET_MMCB_OPTION 0x3168
+#define EXYNOS_PAD_RET_EBIA_OPTION 0x3188
+#define EXYNOS_PAD_RET_EBIB_OPTION 0x31A8
+
+#define EXYNOS_PS_HOLD_CONTROL 0x330C
+
+/* For SYS_PWR_REG */
+#define EXYNOS_SYS_PWR_CFG BIT(0)
+
+#define EXYNOS5420_MFC_CONFIGURATION 0x4060
+#define EXYNOS5420_MFC_STATUS 0x4064
+#define EXYNOS5420_MFC_OPTION 0x4068
+#define EXYNOS5420_G3D_CONFIGURATION 0x4080
+#define EXYNOS5420_G3D_STATUS 0x4084
+#define EXYNOS5420_G3D_OPTION 0x4088
+#define EXYNOS5420_DISP0_CONFIGURATION 0x40A0
+#define EXYNOS5420_DISP0_STATUS 0x40A4
+#define EXYNOS5420_DISP0_OPTION 0x40A8
+#define EXYNOS5420_DISP1_CONFIGURATION 0x40C0
+#define EXYNOS5420_DISP1_STATUS 0x40C4
+#define EXYNOS5420_DISP1_OPTION 0x40C8
+#define EXYNOS5420_MAU_CONFIGURATION 0x40E0
+#define EXYNOS5420_MAU_STATUS 0x40E4
+#define EXYNOS5420_MAU_OPTION 0x40E8
+#define EXYNOS5420_FSYS2_OPTION 0x4168
+#define EXYNOS5420_PSGEN_OPTION 0x4188
+
+/* For EXYNOS_CENTRAL_SEQ_OPTION */
+#define EXYNOS5_USE_STANDBYWFI_ARM_CORE0 BIT(16)
+#define EXYNOS5_USE_STANDBYWFI_ARM_CORE1 BUT(17)
+#define EXYNOS5_USE_STANDBYWFE_ARM_CORE0 BIT(24)
+#define EXYNOS5_USE_STANDBYWFE_ARM_CORE1 BIT(25)
+
+#define EXYNOS5420_ARM_USE_STANDBY_WFI0 BIT(4)
+#define EXYNOS5420_ARM_USE_STANDBY_WFI1 BIT(5)
+#define EXYNOS5420_ARM_USE_STANDBY_WFI2 BIT(6)
+#define EXYNOS5420_ARM_USE_STANDBY_WFI3 BIT(7)
+#define EXYNOS5420_KFC_USE_STANDBY_WFI0 BIT(8)
+#define EXYNOS5420_KFC_USE_STANDBY_WFI1 BIT(9)
+#define EXYNOS5420_KFC_USE_STANDBY_WFI2 BIT(10)
+#define EXYNOS5420_KFC_USE_STANDBY_WFI3 BIT(11)
+#define EXYNOS5420_ARM_USE_STANDBY_WFE0 BIT(16)
+#define EXYNOS5420_ARM_USE_STANDBY_WFE1 BIT(17)
+#define EXYNOS5420_ARM_USE_STANDBY_WFE2 BIT(18)
+#define EXYNOS5420_ARM_USE_STANDBY_WFE3 BIT(19)
+#define EXYNOS5420_KFC_USE_STANDBY_WFE0 BIT(20)
+#define EXYNOS5420_KFC_USE_STANDBY_WFE1 BIT(21)
+#define EXYNOS5420_KFC_USE_STANDBY_WFE2 BIT(22)
+#define EXYNOS5420_KFC_USE_STANDBY_WFE3 BIT(23)
+
+#define DUR_WAIT_RESET 0xF
+
+#define EXYNOS5420_USE_STANDBY_WFI_ALL (EXYNOS5420_ARM_USE_STANDBY_WFI0 \
+ | EXYNOS5420_ARM_USE_STANDBY_WFI1 \
+ | EXYNOS5420_ARM_USE_STANDBY_WFI2 \
+ | EXYNOS5420_ARM_USE_STANDBY_WFI3 \
+ | EXYNOS5420_KFC_USE_STANDBY_WFI0 \
+ | EXYNOS5420_KFC_USE_STANDBY_WFI1 \
+ | EXYNOS5420_KFC_USE_STANDBY_WFI2 \
+ | EXYNOS5420_KFC_USE_STANDBY_WFI3)
+
#endif /* __ASM_ARCH_REGS_PMU_H */
diff --git a/arch/arm/mach-exynos/sleep.S b/arch/arm/mach-exynos/sleep.S
index 108a45f..e3c3730 100644
--- a/arch/arm/mach-exynos/sleep.S
+++ b/arch/arm/mach-exynos/sleep.S
@@ -16,6 +16,7 @@
*/
#include <linux/linkage.h>
+#include "smc.h"
#define CPU_MASK 0xff0ffff0
#define CPU_CORTEX_A9 0x410fc090
@@ -55,3 +56,30 @@ ENTRY(exynos_cpu_resume)
#endif
b cpu_resume
ENDPROC(exynos_cpu_resume)
+
+ .align
+
+ENTRY(exynos_cpu_resume_ns)
+ mrc p15, 0, r0, c0, c0, 0
+ ldr r1, =CPU_MASK
+ and r0, r0, r1
+ ldr r1, =CPU_CORTEX_A9
+ cmp r0, r1
+ bne skip_cp15
+
+ adr r0, cp15_save_power
+ ldr r1, [r0]
+ adr r0, cp15_save_diag
+ ldr r2, [r0]
+ mov r0, #SMC_CMD_C15RESUME
+ dsb
+ smc #0
+skip_cp15:
+ b cpu_resume
+ENDPROC(exynos_cpu_resume_ns)
+ .globl cp15_save_diag
+cp15_save_diag:
+ .long 0 @ cp15 diagnostic
+ .globl cp15_save_power
+cp15_save_power:
+ .long 0 @ cp15 power control
diff --git a/arch/arm/mach-exynos/smc.h b/arch/arm/mach-exynos/smc.h
index 13a1dc8..f7b82f9 100644
--- a/arch/arm/mach-exynos/smc.h
+++ b/arch/arm/mach-exynos/smc.h
@@ -26,6 +26,10 @@
#define SMC_CMD_L2X0INVALL (-24)
#define SMC_CMD_L2X0DEBUG (-25)
+#ifndef __ASSEMBLY__
+
extern void exynos_smc(u32 cmd, u32 arg1, u32 arg2, u32 arg3);
+#endif /* __ASSEMBLY__ */
+
#endif
diff --git a/arch/arm/mach-exynos/suspend.c b/arch/arm/mach-exynos/suspend.c
new file mode 100644
index 0000000..f8e7dcd
--- /dev/null
+++ b/arch/arm/mach-exynos/suspend.c
@@ -0,0 +1,566 @@
+/*
+ * Copyright (c) 2011-2014 Samsung Electronics Co., Ltd.
+ * http://www.samsung.com
+ *
+ * EXYNOS - Suspend support
+ *
+ * Based on arch/arm/mach-s3c2410/pm.c
+ * Copyright (c) 2006 Simtec Electronics
+ * Ben Dooks <ben@simtec.co.uk>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/init.h>
+#include <linux/suspend.h>
+#include <linux/syscore_ops.h>
+#include <linux/cpu_pm.h>
+#include <linux/io.h>
+#include <linux/irqchip/arm-gic.h>
+#include <linux/err.h>
+#include <linux/regulator/machine.h>
+
+#include <asm/cacheflush.h>
+#include <asm/hardware/cache-l2x0.h>
+#include <asm/firmware.h>
+#include <asm/mcpm.h>
+#include <asm/smp_scu.h>
+#include <asm/suspend.h>
+
+#include <plat/pm-common.h>
+#include <plat/regs-srom.h>
+
+#include "common.h"
+#include "regs-pmu.h"
+#include "regs-sys.h"
+#include "exynos-pmu.h"
+
+#define S5P_CHECK_SLEEP 0x00000BAD
+
+#define REG_TABLE_END (-1U)
+
+#define EXYNOS5420_CPU_STATE 0x28
+
+/**
+ * struct exynos_wkup_irq - Exynos GIC to PMU IRQ mapping
+ * @hwirq: Hardware IRQ signal of the GIC
+ * @mask: Mask in PMU wake-up mask register
+ */
+struct exynos_wkup_irq {
+ unsigned int hwirq;
+ u32 mask;
+};
+
+static struct sleep_save exynos5_sys_save[] = {
+ SAVE_ITEM(EXYNOS5_SYS_I2C_CFG),
+};
+
+static struct sleep_save exynos_core_save[] = {
+ /* SROM side */
+ SAVE_ITEM(S5P_SROM_BW),
+ SAVE_ITEM(S5P_SROM_BC0),
+ SAVE_ITEM(S5P_SROM_BC1),
+ SAVE_ITEM(S5P_SROM_BC2),
+ SAVE_ITEM(S5P_SROM_BC3),
+};
+
+struct exynos_pm_data {
+ const struct exynos_wkup_irq *wkup_irq;
+ struct sleep_save *extra_save;
+ int num_extra_save;
+ unsigned int wake_disable_mask;
+ unsigned int *release_ret_regs;
+
+ void (*pm_prepare)(void);
+ void (*pm_resume_prepare)(void);
+ void (*pm_resume)(void);
+ int (*pm_suspend)(void);
+ int (*cpu_suspend)(unsigned long);
+};
+
+struct exynos_pm_data *pm_data;
+
+static int exynos5420_cpu_state;
+static unsigned int exynos_pmu_spare3;
+
+/*
+ * GIC wake-up support
+ */
+
+static u32 exynos_irqwake_intmask = 0xffffffff;
+
+static const struct exynos_wkup_irq exynos4_wkup_irq[] = {
+ { 76, BIT(1) }, /* RTC alarm */
+ { 77, BIT(2) }, /* RTC tick */
+ { /* sentinel */ },
+};
+
+static const struct exynos_wkup_irq exynos5250_wkup_irq[] = {
+ { 75, BIT(1) }, /* RTC alarm */
+ { 76, BIT(2) }, /* RTC tick */
+ { /* sentinel */ },
+};
+
+unsigned int exynos_release_ret_regs[] = {
+ S5P_PAD_RET_MAUDIO_OPTION,
+ S5P_PAD_RET_GPIO_OPTION,
+ S5P_PAD_RET_UART_OPTION,
+ S5P_PAD_RET_MMCA_OPTION,
+ S5P_PAD_RET_MMCB_OPTION,
+ S5P_PAD_RET_EBIA_OPTION,
+ S5P_PAD_RET_EBIB_OPTION,
+ REG_TABLE_END,
+};
+
+unsigned int exynos5420_release_ret_regs[] = {
+ EXYNOS_PAD_RET_DRAM_OPTION,
+ EXYNOS_PAD_RET_MAUDIO_OPTION,
+ EXYNOS_PAD_RET_JTAG_OPTION,
+ EXYNOS5420_PAD_RET_GPIO_OPTION,
+ EXYNOS5420_PAD_RET_UART_OPTION,
+ EXYNOS5420_PAD_RET_MMCA_OPTION,
+ EXYNOS5420_PAD_RET_MMCB_OPTION,
+ EXYNOS5420_PAD_RET_MMCC_OPTION,
+ EXYNOS5420_PAD_RET_HSI_OPTION,
+ EXYNOS_PAD_RET_EBIA_OPTION,
+ EXYNOS_PAD_RET_EBIB_OPTION,
+ EXYNOS5420_PAD_RET_SPI_OPTION,
+ EXYNOS5420_PAD_RET_DRAM_COREBLK_OPTION,
+ REG_TABLE_END,
+};
+
+static int exynos_irq_set_wake(struct irq_data *data, unsigned int state)
+{
+ const struct exynos_wkup_irq *wkup_irq;
+
+ if (!pm_data->wkup_irq)
+ return -ENOENT;
+ wkup_irq = pm_data->wkup_irq;
+
+ while (wkup_irq->mask) {
+ if (wkup_irq->hwirq == data->hwirq) {
+ if (!state)
+ exynos_irqwake_intmask |= wkup_irq->mask;
+ else
+ exynos_irqwake_intmask &= ~wkup_irq->mask;
+ return 0;
+ }
+ ++wkup_irq;
+ }
+
+ return -ENOENT;
+}
+
+static int exynos_cpu_do_idle(void)
+{
+ /* issue the standby signal into the pm unit. */
+ cpu_do_idle();
+
+ pr_info("Failed to suspend the system\n");
+ return 1; /* Aborting suspend */
+}
+static void exynos_flush_cache_all(void)
+{
+ flush_cache_all();
+ outer_flush_all();
+}
+
+static int exynos_cpu_suspend(unsigned long arg)
+{
+ exynos_flush_cache_all();
+ return exynos_cpu_do_idle();
+}
+
+static int exynos5420_cpu_suspend(unsigned long arg)
+{
+ /* MCPM works with HW CPU identifiers */
+ unsigned int mpidr = read_cpuid_mpidr();
+ unsigned int cluster = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ unsigned int cpu = MPIDR_AFFINITY_LEVEL(mpidr, 0);
+
+ __raw_writel(0x0, sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+ if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM)) {
+ mcpm_set_entry_vector(cpu, cluster, exynos_cpu_resume);
+
+ /*
+ * Residency value passed to mcpm_cpu_suspend back-end
+ * has to be given clear semantics. Set to 0 as a
+ * temporary value.
+ */
+ mcpm_cpu_suspend(0);
+ }
+
+ pr_info("Failed to suspend the system\n");
+
+ /* return value != 0 means failure */
+ return 1;
+}
+
+static void exynos_pm_set_wakeup_mask(void)
+{
+ /* Set wake-up mask registers */
+ pmu_raw_writel(exynos_get_eint_wake_mask(), S5P_EINT_WAKEUP_MASK);
+ pmu_raw_writel(exynos_irqwake_intmask & ~(1 << 31), S5P_WAKEUP_MASK);
+}
+
+static void exynos_pm_enter_sleep_mode(void)
+{
+ /* Set value of power down register for sleep mode */
+ exynos_sys_powerdown_conf(SYS_SLEEP);
+ pmu_raw_writel(S5P_CHECK_SLEEP, S5P_INFORM1);
+}
+
+static void exynos_pm_prepare(void)
+{
+ /* Set wake-up mask registers */
+ exynos_pm_set_wakeup_mask();
+
+ s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
+
+ if (pm_data->extra_save)
+ s3c_pm_do_save(pm_data->extra_save,
+ pm_data->num_extra_save);
+
+ exynos_pm_enter_sleep_mode();
+
+ /* ensure at least INFORM0 has the resume address */
+ pmu_raw_writel(virt_to_phys(exynos_cpu_resume), S5P_INFORM0);
+}
+
+static void exynos5420_pm_prepare(void)
+{
+ unsigned int tmp;
+
+ /* Set wake-up mask registers */
+ exynos_pm_set_wakeup_mask();
+
+ s3c_pm_do_save(exynos_core_save, ARRAY_SIZE(exynos_core_save));
+
+ exynos_pmu_spare3 = pmu_raw_readl(S5P_PMU_SPARE3);
+ /*
+ * The cpu state needs to be saved and restored so that the
+ * secondary CPUs will enter low power start. Though the U-Boot
+ * is setting the cpu state with low power flag, the kernel
+ * needs to restore it back in case, the primary cpu fails to
+ * suspend for any reason.
+ */
+ exynos5420_cpu_state = __raw_readl(sysram_base_addr +
+ EXYNOS5420_CPU_STATE);
+
+ exynos_pm_enter_sleep_mode();
+
+ /* ensure at least INFORM0 has the resume address */
+ if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
+ pmu_raw_writel(virt_to_phys(mcpm_entry_point), S5P_INFORM0);
+
+ tmp = pmu_raw_readl(EXYNOS5_ARM_L2_OPTION);
+ tmp &= ~EXYNOS5_USE_RETENTION;
+ pmu_raw_writel(tmp, EXYNOS5_ARM_L2_OPTION);
+
+ tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
+ tmp |= EXYNOS5420_UFS;
+ pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
+
+ tmp = pmu_raw_readl(EXYNOS5420_ARM_COMMON_OPTION);
+ tmp &= ~EXYNOS5420_L2RSTDISABLE_VALUE;
+ pmu_raw_writel(tmp, EXYNOS5420_ARM_COMMON_OPTION);
+
+ tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
+ tmp |= EXYNOS5420_EMULATION;
+ pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
+
+ tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
+ tmp |= EXYNOS5420_EMULATION;
+ pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+}
+
+
+static int exynos_pm_suspend(void)
+{
+ exynos_pm_central_suspend();
+
+ if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9)
+ exynos_cpu_save_register();
+
+ return 0;
+}
+
+static int exynos5420_pm_suspend(void)
+{
+ u32 this_cluster;
+
+ exynos_pm_central_suspend();
+
+ /* Setting SEQ_OPTION register */
+
+ this_cluster = MPIDR_AFFINITY_LEVEL(read_cpuid_mpidr(), 1);
+ if (!this_cluster)
+ pmu_raw_writel(EXYNOS5420_ARM_USE_STANDBY_WFI0,
+ S5P_CENTRAL_SEQ_OPTION);
+ else
+ pmu_raw_writel(EXYNOS5420_KFC_USE_STANDBY_WFI0,
+ S5P_CENTRAL_SEQ_OPTION);
+ return 0;
+}
+
+static void exynos_pm_release_retention(void)
+{
+ unsigned int i;
+
+ for (i = 0; (pm_data->release_ret_regs[i] != REG_TABLE_END); i++)
+ pmu_raw_writel(EXYNOS_WAKEUP_FROM_LOWPWR,
+ pm_data->release_ret_regs[i]);
+}
+
+static void exynos_pm_resume(void)
+{
+ u32 cpuid = read_cpuid_part();
+
+ if (exynos_pm_central_resume())
+ goto early_wakeup;
+
+ /* For release retention */
+ exynos_pm_release_retention();
+
+ if (pm_data->extra_save)
+ s3c_pm_do_restore_core(pm_data->extra_save,
+ pm_data->num_extra_save);
+
+ s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
+
+ if (cpuid == ARM_CPU_PART_CORTEX_A9)
+ scu_enable(S5P_VA_SCU);
+
+ if (call_firmware_op(resume) == -ENOSYS
+ && cpuid == ARM_CPU_PART_CORTEX_A9)
+ exynos_cpu_restore_register();
+
+early_wakeup:
+
+ /* Clear SLEEP mode set in INFORM1 */
+ pmu_raw_writel(0x0, S5P_INFORM1);
+}
+
+static void exynos5420_prepare_pm_resume(void)
+{
+ if (IS_ENABLED(CONFIG_EXYNOS5420_MCPM))
+ WARN_ON(mcpm_cpu_powered_up());
+}
+
+static void exynos5420_pm_resume(void)
+{
+ unsigned long tmp;
+
+ /* Restore the CPU0 low power state register */
+ tmp = pmu_raw_readl(EXYNOS5_ARM_CORE0_SYS_PWR_REG);
+ pmu_raw_writel(tmp | S5P_CORE_LOCAL_PWR_EN,
+ EXYNOS5_ARM_CORE0_SYS_PWR_REG);
+
+ /* Restore the sysram cpu state register */
+ __raw_writel(exynos5420_cpu_state,
+ sysram_base_addr + EXYNOS5420_CPU_STATE);
+
+ pmu_raw_writel(EXYNOS5420_USE_STANDBY_WFI_ALL,
+ S5P_CENTRAL_SEQ_OPTION);
+
+ if (exynos_pm_central_resume())
+ goto early_wakeup;
+
+ /* For release retention */
+ exynos_pm_release_retention();
+
+ pmu_raw_writel(exynos_pmu_spare3, S5P_PMU_SPARE3);
+
+ s3c_pm_do_restore_core(exynos_core_save, ARRAY_SIZE(exynos_core_save));
+
+early_wakeup:
+
+ tmp = pmu_raw_readl(EXYNOS5420_SFR_AXI_CGDIS1);
+ tmp &= ~EXYNOS5420_UFS;
+ pmu_raw_writel(tmp, EXYNOS5420_SFR_AXI_CGDIS1);
+
+ tmp = pmu_raw_readl(EXYNOS5420_FSYS2_OPTION);
+ tmp &= ~EXYNOS5420_EMULATION;
+ pmu_raw_writel(tmp, EXYNOS5420_FSYS2_OPTION);
+
+ tmp = pmu_raw_readl(EXYNOS5420_PSGEN_OPTION);
+ tmp &= ~EXYNOS5420_EMULATION;
+ pmu_raw_writel(tmp, EXYNOS5420_PSGEN_OPTION);
+
+ /* Clear SLEEP mode set in INFORM1 */
+ pmu_raw_writel(0x0, S5P_INFORM1);
+}
+
+/*
+ * Suspend Ops
+ */
+
+static int exynos_suspend_enter(suspend_state_t state)
+{
+ int ret;
+
+ s3c_pm_debug_init();
+
+ S3C_PMDBG("%s: suspending the system...\n", __func__);
+
+ S3C_PMDBG("%s: wakeup masks: %08x,%08x\n", __func__,
+ exynos_irqwake_intmask, exynos_get_eint_wake_mask());
+
+ if (exynos_irqwake_intmask == -1U
+ && exynos_get_eint_wake_mask() == -1U) {
+ pr_err("%s: No wake-up sources!\n", __func__);
+ pr_err("%s: Aborting sleep\n", __func__);
+ return -EINVAL;
+ }
+
+ s3c_pm_save_uarts();
+ if (pm_data->pm_prepare)
+ pm_data->pm_prepare();
+ flush_cache_all();
+ s3c_pm_check_store();
+
+ ret = call_firmware_op(suspend);
+ if (ret == -ENOSYS)
+ ret = cpu_suspend(0, pm_data->cpu_suspend);
+ if (ret)
+ return ret;
+
+ if (pm_data->pm_resume_prepare)
+ pm_data->pm_resume_prepare();
+ s3c_pm_restore_uarts();
+
+ S3C_PMDBG("%s: wakeup stat: %08x\n", __func__,
+ pmu_raw_readl(S5P_WAKEUP_STAT));
+
+ s3c_pm_check_restore();
+
+ S3C_PMDBG("%s: resuming the system...\n", __func__);
+
+ return 0;
+}
+
+static int exynos_suspend_prepare(void)
+{
+ int ret;
+
+ /*
+ * REVISIT: It would be better if struct platform_suspend_ops
+ * .prepare handler get the suspend_state_t as a parameter to
+ * avoid hard-coding the suspend to mem state. It's safe to do
+ * it now only because the suspend_valid_only_mem function is
+ * used as the .valid callback used to check if a given state
+ * is supported by the platform anyways.
+ */
+ ret = regulator_suspend_prepare(PM_SUSPEND_MEM);
+ if (ret) {
+ pr_err("Failed to prepare regulators for suspend (%d)\n", ret);
+ return ret;
+ }
+
+ s3c_pm_check_prepare();
+
+ return 0;
+}
+
+static void exynos_suspend_finish(void)
+{
+ int ret;
+
+ s3c_pm_check_cleanup();
+
+ ret = regulator_suspend_finish();
+ if (ret)
+ pr_warn("Failed to resume regulators from suspend (%d)\n", ret);
+}
+
+static const struct platform_suspend_ops exynos_suspend_ops = {
+ .enter = exynos_suspend_enter,
+ .prepare = exynos_suspend_prepare,
+ .finish = exynos_suspend_finish,
+ .valid = suspend_valid_only_mem,
+};
+
+static const struct exynos_pm_data exynos4_pm_data = {
+ .wkup_irq = exynos4_wkup_irq,
+ .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
+ .release_ret_regs = exynos_release_ret_regs,
+ .pm_suspend = exynos_pm_suspend,
+ .pm_resume = exynos_pm_resume,
+ .pm_prepare = exynos_pm_prepare,
+ .cpu_suspend = exynos_cpu_suspend,
+};
+
+static const struct exynos_pm_data exynos5250_pm_data = {
+ .wkup_irq = exynos5250_wkup_irq,
+ .wake_disable_mask = ((0xFF << 8) | (0x1F << 1)),
+ .release_ret_regs = exynos_release_ret_regs,
+ .extra_save = exynos5_sys_save,
+ .num_extra_save = ARRAY_SIZE(exynos5_sys_save),
+ .pm_suspend = exynos_pm_suspend,
+ .pm_resume = exynos_pm_resume,
+ .pm_prepare = exynos_pm_prepare,
+ .cpu_suspend = exynos_cpu_suspend,
+};
+
+static struct exynos_pm_data exynos5420_pm_data = {
+ .wkup_irq = exynos5250_wkup_irq,
+ .wake_disable_mask = (0x7F << 7) | (0x1F << 1),
+ .release_ret_regs = exynos5420_release_ret_regs,
+ .pm_resume_prepare = exynos5420_prepare_pm_resume,
+ .pm_resume = exynos5420_pm_resume,
+ .pm_suspend = exynos5420_pm_suspend,
+ .pm_prepare = exynos5420_pm_prepare,
+ .cpu_suspend = exynos5420_cpu_suspend,
+};
+
+static struct of_device_id exynos_pmu_of_device_ids[] = {
+ {
+ .compatible = "samsung,exynos4210-pmu",
+ .data = &exynos4_pm_data,
+ }, {
+ .compatible = "samsung,exynos4212-pmu",
+ .data = &exynos4_pm_data,
+ }, {
+ .compatible = "samsung,exynos4412-pmu",
+ .data = &exynos4_pm_data,
+ }, {
+ .compatible = "samsung,exynos5250-pmu",
+ .data = &exynos5250_pm_data,
+ }, {
+ .compatible = "samsung,exynos5420-pmu",
+ .data = &exynos5420_pm_data,
+ },
+ { /*sentinel*/ },
+};
+
+static struct syscore_ops exynos_pm_syscore_ops;
+
+void __init exynos_pm_init(void)
+{
+ const struct of_device_id *match;
+ u32 tmp;
+
+ of_find_matching_node_and_match(NULL, exynos_pmu_of_device_ids, &match);
+ if (!match) {
+ pr_err("Failed to find PMU node\n");
+ return;
+ }
+ pm_data = (struct exynos_pm_data *) match->data;
+
+ /* Platform-specific GIC callback */
+ gic_arch_extn.irq_set_wake = exynos_irq_set_wake;
+
+ /* All wakeup disable */
+ tmp = pmu_raw_readl(S5P_WAKEUP_MASK);
+ tmp |= pm_data->wake_disable_mask;
+ pmu_raw_writel(tmp, S5P_WAKEUP_MASK);
+
+ exynos_pm_syscore_ops.suspend = pm_data->pm_suspend;
+ exynos_pm_syscore_ops.resume = pm_data->pm_resume;
+
+ register_syscore_ops(&exynos_pm_syscore_ops);
+ suspend_set_ops(&exynos_suspend_ops);
+}
diff --git a/arch/arm/mach-imx/Kconfig b/arch/arm/mach-imx/Kconfig
index 11b2957..e8627e0 100644
--- a/arch/arm/mach-imx/Kconfig
+++ b/arch/arm/mach-imx/Kconfig
@@ -633,12 +633,41 @@ config SOC_VF610
bool "Vybrid Family VF610 support"
select ARM_GIC
select PINCTRL_VF610
- select VF_PIT_TIMER
select PL310_ERRATA_769419 if CACHE_L2X0
help
This enable support for Freescale Vybrid VF610 processor.
+choice
+ prompt "Clocksource for scheduler clock"
+ depends on SOC_VF610
+ default VF_USE_ARM_GLOBAL_TIMER
+
+ config VF_USE_ARM_GLOBAL_TIMER
+ bool "Use ARM Global Timer"
+ select ARM_GLOBAL_TIMER
+ select CLKSRC_ARM_GLOBAL_TIMER_SCHED_CLOCK
+ help
+ Use the ARM Global Timer as clocksource
+
+ config VF_USE_PIT_TIMER
+ bool "Use PIT timer"
+ select VF_PIT_TIMER
+ help
+ Use SoC Periodic Interrupt Timer (PIT) as clocksource
+
+endchoice
+
+config SOC_LS1021A
+ bool "Freescale LS1021A support"
+ select ARM_GIC
+ select HAVE_ARM_ARCH_TIMER
+ select PCI_DOMAINS if PCI
+ select ZONE_DMA if ARM_LPAE
+
+ help
+ This enable support for Freescale LS1021A processor.
+
endif
source "arch/arm/mach-imx/devices/Kconfig"
diff --git a/arch/arm/mach-imx/Makefile b/arch/arm/mach-imx/Makefile
index 6e4fcd8..f5ac685 100644
--- a/arch/arm/mach-imx/Makefile
+++ b/arch/arm/mach-imx/Makefile
@@ -12,7 +12,7 @@ obj-$(CONFIG_SOC_IMX31) += mm-imx3.o cpu-imx31.o clk-imx31.o iomux-imx31.o ehci-
obj-$(CONFIG_SOC_IMX35) += mm-imx3.o cpu-imx35.o clk-imx35.o ehci-imx35.o pm-imx3.o
imx5-pm-$(CONFIG_PM) += pm-imx5.o
-obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o $(imx5-pm-y)
+obj-$(CONFIG_SOC_IMX5) += cpu-imx5.o clk-imx51-imx53.o clk-cpu.o $(imx5-pm-y)
obj-$(CONFIG_COMMON_CLK) += clk-pllv1.o clk-pllv2.o clk-pllv3.o clk-gate2.o \
clk-pfd.o clk-busy.o clk.o \
@@ -89,7 +89,7 @@ obj-$(CONFIG_HAVE_IMX_ANATOP) += anatop.o
obj-$(CONFIG_HAVE_IMX_GPC) += gpc.o
obj-$(CONFIG_HAVE_IMX_MMDC) += mmdc.o
obj-$(CONFIG_HAVE_IMX_SRC) += src.o
-ifdef CONFIG_SOC_IMX6
+ifneq ($(CONFIG_SOC_IMX6)$(CONFIG_SOC_LS1021A),)
AFLAGS_headsmp.o :=-Wa,-march=armv7-a
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
@@ -110,4 +110,6 @@ obj-$(CONFIG_SOC_IMX53) += mach-imx53.o
obj-$(CONFIG_SOC_VF610) += clk-vf610.o mach-vf610.o
+obj-$(CONFIG_SOC_LS1021A) += mach-ls1021a.o
+
obj-y += devices/
diff --git a/arch/arm/mach-imx/anatop.c b/arch/arm/mach-imx/anatop.c
index 8259a62..7f262fe 100644
--- a/arch/arm/mach-imx/anatop.c
+++ b/arch/arm/mach-imx/anatop.c
@@ -30,8 +30,11 @@
#define ANADIG_DIGPROG_IMX6SL 0x280
#define BM_ANADIG_REG_2P5_ENABLE_WEAK_LINREG 0x40000
+#define BM_ANADIG_REG_2P5_ENABLE_PULLDOWN 0x8
#define BM_ANADIG_REG_CORE_FET_ODRIVE 0x20000000
#define BM_ANADIG_ANA_MISC0_STOP_MODE_CONFIG 0x1000
+/* Below MISC0_DISCON_HIGH_SNVS is only for i.MX6SL */
+#define BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS 0x2000
#define BM_ANADIG_USB_CHRG_DETECT_CHK_CHRG_B 0x80000
#define BM_ANADIG_USB_CHRG_DETECT_EN_B 0x100000
@@ -56,16 +59,43 @@ static void imx_anatop_enable_fet_odrive(bool enable)
BM_ANADIG_REG_CORE_FET_ODRIVE);
}
+static inline void imx_anatop_enable_2p5_pulldown(bool enable)
+{
+ regmap_write(anatop, ANADIG_REG_2P5 + (enable ? REG_SET : REG_CLR),
+ BM_ANADIG_REG_2P5_ENABLE_PULLDOWN);
+}
+
+static inline void imx_anatop_disconnect_high_snvs(bool enable)
+{
+ regmap_write(anatop, ANADIG_ANA_MISC0 + (enable ? REG_SET : REG_CLR),
+ BM_ANADIG_ANA_MISC0_DISCON_HIGH_SNVS);
+}
+
void imx_anatop_pre_suspend(void)
{
- imx_anatop_enable_weak2p5(true);
+ if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
+ imx_anatop_enable_2p5_pulldown(true);
+ else
+ imx_anatop_enable_weak2p5(true);
+
imx_anatop_enable_fet_odrive(true);
+
+ if (cpu_is_imx6sl())
+ imx_anatop_disconnect_high_snvs(true);
}
void imx_anatop_post_resume(void)
{
+ if (imx_mmdc_get_ddr_type() == IMX_DDR_TYPE_LPDDR2)
+ imx_anatop_enable_2p5_pulldown(false);
+ else
+ imx_anatop_enable_weak2p5(false);
+
imx_anatop_enable_fet_odrive(false);
- imx_anatop_enable_weak2p5(false);
+
+ if (cpu_is_imx6sl())
+ imx_anatop_disconnect_high_snvs(false);
+
}
static void imx_anatop_usb_chrg_detect_disable(void)
diff --git a/arch/arm/mach-imx/clk-cpu.c b/arch/arm/mach-imx/clk-cpu.c
new file mode 100644
index 0000000..aa1c345
--- /dev/null
+++ b/arch/arm/mach-imx/clk-cpu.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014 Lucas Stach <l.stach@pengutronix.de>, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * http://www.opensource.org/licenses/gpl-license.html
+ * http://www.gnu.org/copyleft/gpl.html
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/slab.h>
+
+struct clk_cpu {
+ struct clk_hw hw;
+ struct clk *div;
+ struct clk *mux;
+ struct clk *pll;
+ struct clk *step;
+};
+
+static inline struct clk_cpu *to_clk_cpu(struct clk_hw *hw)
+{
+ return container_of(hw, struct clk_cpu, hw);
+}
+
+static unsigned long clk_cpu_recalc_rate(struct clk_hw *hw,
+ unsigned long parent_rate)
+{
+ struct clk_cpu *cpu = to_clk_cpu(hw);
+
+ return clk_get_rate(cpu->div);
+}
+
+static long clk_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *prate)
+{
+ struct clk_cpu *cpu = to_clk_cpu(hw);
+
+ return clk_round_rate(cpu->pll, rate);
+}
+
+static int clk_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_cpu *cpu = to_clk_cpu(hw);
+ int ret;
+
+ /* switch to PLL bypass clock */
+ ret = clk_set_parent(cpu->mux, cpu->step);
+ if (ret)
+ return ret;
+
+ /* reprogram PLL */
+ ret = clk_set_rate(cpu->pll, rate);
+ if (ret) {
+ clk_set_parent(cpu->mux, cpu->pll);
+ return ret;
+ }
+ /* switch back to PLL clock */
+ clk_set_parent(cpu->mux, cpu->pll);
+
+ /* Ensure the divider is what we expect */
+ clk_set_rate(cpu->div, rate);
+
+ return 0;
+}
+
+static const struct clk_ops clk_cpu_ops = {
+ .recalc_rate = clk_cpu_recalc_rate,
+ .round_rate = clk_cpu_round_rate,
+ .set_rate = clk_cpu_set_rate,
+};
+
+struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+ struct clk *div, struct clk *mux, struct clk *pll,
+ struct clk *step)
+{
+ struct clk_cpu *cpu;
+ struct clk *clk;
+ struct clk_init_data init;
+
+ cpu = kzalloc(sizeof(*cpu), GFP_KERNEL);
+ if (!cpu)
+ return ERR_PTR(-ENOMEM);
+
+ cpu->div = div;
+ cpu->mux = mux;
+ cpu->pll = pll;
+ cpu->step = step;
+
+ init.name = name;
+ init.ops = &clk_cpu_ops;
+ init.flags = 0;
+ init.parent_names = &parent_name;
+ init.num_parents = 1;
+
+ cpu->hw.init = &init;
+
+ clk = clk_register(NULL, &cpu->hw);
+ if (IS_ERR(clk))
+ kfree(cpu);
+
+ return clk;
+}
diff --git a/arch/arm/mach-imx/clk-imx51-imx53.c b/arch/arm/mach-imx/clk-imx51-imx53.c
index 72d6521..0f7e536 100644
--- a/arch/arm/mach-imx/clk-imx51-imx53.c
+++ b/arch/arm/mach-imx/clk-imx51-imx53.c
@@ -125,6 +125,8 @@ static const char *mx53_spdif_xtal_sel[] = { "osc", "ckih", "ckih2", "pll4_sw",
static const char *spdif_sel[] = { "pll1_sw", "pll2_sw", "pll3_sw", "spdif_xtal_sel", };
static const char *spdif0_com_sel[] = { "spdif0_podf", "ssi1_root_gate", };
static const char *mx51_spdif1_com_sel[] = { "spdif1_podf", "ssi2_root_gate", };
+static const char *step_sels[] = { "lp_apm", };
+static const char *cpu_podf_sels[] = { "pll1_sw", "step_sel" };
static struct clk *clk[IMX5_CLK_END];
static struct clk_onecell_data clk_data;
@@ -193,7 +195,9 @@ static void __init mx5_clocks_common_init(void __iomem *ccm_base)
clk[IMX5_CLK_USB_PHY_PODF] = imx_clk_divider("usb_phy_podf", "usb_phy_pred", MXC_CCM_CDCDR, 0, 3);
clk[IMX5_CLK_USB_PHY_SEL] = imx_clk_mux("usb_phy_sel", MXC_CCM_CSCMR1, 26, 1,
usb_phy_sel_str, ARRAY_SIZE(usb_phy_sel_str));
- clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "pll1_sw", MXC_CCM_CACRR, 0, 3);
+ clk[IMX5_CLK_STEP_SEL] = imx_clk_mux("step_sel", MXC_CCM_CCSR, 7, 2, step_sels, ARRAY_SIZE(step_sels));
+ clk[IMX5_CLK_CPU_PODF_SEL] = imx_clk_mux("cpu_podf_sel", MXC_CCM_CCSR, 2, 1, cpu_podf_sels, ARRAY_SIZE(cpu_podf_sels));
+ clk[IMX5_CLK_CPU_PODF] = imx_clk_divider("cpu_podf", "cpu_podf_sel", MXC_CCM_CACRR, 0, 3);
clk[IMX5_CLK_DI_PRED] = imx_clk_divider("di_pred", "pll3_sw", MXC_CCM_CDCDR, 6, 3);
clk[IMX5_CLK_IIM_GATE] = imx_clk_gate2("iim_gate", "ipg", MXC_CCM_CCGR0, 30);
clk[IMX5_CLK_UART1_IPG_GATE] = imx_clk_gate2("uart1_ipg_gate", "ipg", MXC_CCM_CCGR1, 6);
@@ -537,6 +541,11 @@ static void __init mx53_clocks_init(struct device_node *np)
clk[IMX5_CLK_CKO2] = imx_clk_gate2("cko2", "cko2_podf", MXC_CCM_CCOSR, 24);
clk[IMX5_CLK_SPDIF_XTAL_SEL] = imx_clk_mux("spdif_xtal_sel", MXC_CCM_CSCMR1, 2, 2,
mx53_spdif_xtal_sel, ARRAY_SIZE(mx53_spdif_xtal_sel));
+ clk[IMX5_CLK_ARM] = imx_clk_cpu("arm", "cpu_podf",
+ clk[IMX5_CLK_CPU_PODF],
+ clk[IMX5_CLK_CPU_PODF_SEL],
+ clk[IMX5_CLK_PLL1_SW],
+ clk[IMX5_CLK_STEP_SEL]);
imx_check_clocks(clk, ARRAY_SIZE(clk));
@@ -551,6 +560,9 @@ static void __init mx53_clocks_init(struct device_node *np)
/* move can bus clk to 24MHz */
clk_set_parent(clk[IMX5_CLK_CAN_SEL], clk[IMX5_CLK_LP_APM]);
+ /* make sure step clock is running from 24MHz */
+ clk_set_parent(clk[IMX5_CLK_STEP_SEL], clk[IMX5_CLK_LP_APM]);
+
clk_prepare_enable(clk[IMX5_CLK_IIM_GATE]);
imx_print_silicon_rev("i.MX53", mx53_revision());
clk_disable_unprepare(clk[IMX5_CLK_IIM_GATE]);
diff --git a/arch/arm/mach-imx/clk-imx6q.c b/arch/arm/mach-imx/clk-imx6q.c
index 4e79da7..5951660 100644
--- a/arch/arm/mach-imx/clk-imx6q.c
+++ b/arch/arm/mach-imx/clk-imx6q.c
@@ -145,7 +145,7 @@ static void __init imx6q_clocks_init(struct device_node *ccm_node)
post_div_table[2].div = 1;
video_div_table[1].div = 1;
video_div_table[2].div = 1;
- };
+ }
clk[IMX6QDL_PLL1_BYPASS_SRC] = imx_clk_mux("pll1_bypass_src", base + 0x00, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
clk[IMX6QDL_PLL2_BYPASS_SRC] = imx_clk_mux("pll2_bypass_src", base + 0x30, 14, 2, pll_bypass_src_sels, ARRAY_SIZE(pll_bypass_src_sels));
diff --git a/arch/arm/mach-imx/clk-pllv3.c b/arch/arm/mach-imx/clk-pllv3.c
index 57de74d..0ad6e54 100644
--- a/arch/arm/mach-imx/clk-pllv3.c
+++ b/arch/arm/mach-imx/clk-pllv3.c
@@ -69,7 +69,6 @@ static int clk_pllv3_prepare(struct clk_hw *hw)
{
struct clk_pllv3 *pll = to_clk_pllv3(hw);
u32 val;
- int ret;
val = readl_relaxed(pll->base);
if (pll->powerup_set)
@@ -78,11 +77,7 @@ static int clk_pllv3_prepare(struct clk_hw *hw)
val &= ~BM_PLL_POWER;
writel_relaxed(val, pll->base);
- ret = clk_pllv3_wait_lock(pll);
- if (ret)
- return ret;
-
- return 0;
+ return clk_pllv3_wait_lock(pll);
}
static void clk_pllv3_unprepare(struct clk_hw *hw)
diff --git a/arch/arm/mach-imx/clk-vf610.c b/arch/arm/mach-imx/clk-vf610.c
index 4096372..5937dde 100644
--- a/arch/arm/mach-imx/clk-vf610.c
+++ b/arch/arm/mach-imx/clk-vf610.c
@@ -120,6 +120,17 @@ static unsigned int const clks_init_on[] __initconst = {
VF610_CLK_DDR_SEL,
};
+static struct clk * __init vf610_get_fixed_clock(
+ struct device_node *ccm_node, const char *name)
+{
+ struct clk *clk = of_clk_get_by_name(ccm_node, name);
+
+ /* Backward compatibility if device tree is missing clks assignments */
+ if (IS_ERR(clk))
+ clk = imx_obtain_fixed_clock(name, 0);
+ return clk;
+};
+
static void __init vf610_clocks_init(struct device_node *ccm_node)
{
struct device_node *np;
@@ -130,13 +141,13 @@ static void __init vf610_clocks_init(struct device_node *ccm_node)
clk[VF610_CLK_SIRC_32K] = imx_clk_fixed("sirc_32k", 32000);
clk[VF610_CLK_FIRC] = imx_clk_fixed("firc", 24000000);
- clk[VF610_CLK_SXOSC] = imx_obtain_fixed_clock("sxosc", 0);
- clk[VF610_CLK_FXOSC] = imx_obtain_fixed_clock("fxosc", 0);
- clk[VF610_CLK_AUDIO_EXT] = imx_obtain_fixed_clock("audio_ext", 0);
- clk[VF610_CLK_ENET_EXT] = imx_obtain_fixed_clock("enet_ext", 0);
+ clk[VF610_CLK_SXOSC] = vf610_get_fixed_clock(ccm_node, "sxosc");
+ clk[VF610_CLK_FXOSC] = vf610_get_fixed_clock(ccm_node, "fxosc");
+ clk[VF610_CLK_AUDIO_EXT] = vf610_get_fixed_clock(ccm_node, "audio_ext");
+ clk[VF610_CLK_ENET_EXT] = vf610_get_fixed_clock(ccm_node, "enet_ext");
/* Clock source from external clock via LVDs PAD */
- clk[VF610_CLK_ANACLK1] = imx_obtain_fixed_clock("anaclk1", 0);
+ clk[VF610_CLK_ANACLK1] = vf610_get_fixed_clock(ccm_node, "anaclk1");
clk[VF610_CLK_FXOSC_HALF] = imx_clk_fixed_factor("fxosc_half", "fxosc", 1, 2);
diff --git a/arch/arm/mach-imx/clk.h b/arch/arm/mach-imx/clk.h
index 4cdf8b6..5ef82e2 100644
--- a/arch/arm/mach-imx/clk.h
+++ b/arch/arm/mach-imx/clk.h
@@ -131,4 +131,8 @@ static inline struct clk *imx_clk_fixed_factor(const char *name,
CLK_SET_RATE_PARENT, mult, div);
}
+struct clk *imx_clk_cpu(const char *name, const char *parent_name,
+ struct clk *div, struct clk *mux, struct clk *pll,
+ struct clk *step);
+
#endif
diff --git a/arch/arm/mach-imx/common.h b/arch/arm/mach-imx/common.h
index 1dabf43..cfcdb62 100644
--- a/arch/arm/mach-imx/common.h
+++ b/arch/arm/mach-imx/common.h
@@ -61,7 +61,6 @@ struct platform_device *mxc_register_gpio(char *name, int id,
void mxc_set_cpu_type(unsigned int type);
void mxc_restart(enum reboot_mode, const char *);
void mxc_arch_reset_init(void __iomem *);
-void mxc_arch_reset_init_dt(void);
int mx51_revision(void);
int mx53_revision(void);
void imx_set_aips(void __iomem *);
@@ -108,14 +107,15 @@ void imx_gpc_pre_suspend(bool arm_power_off);
void imx_gpc_post_resume(void);
void imx_gpc_mask_all(void);
void imx_gpc_restore_all(void);
-void imx_gpc_irq_mask(struct irq_data *d);
-void imx_gpc_irq_unmask(struct irq_data *d);
+void imx_gpc_hwirq_mask(unsigned int hwirq);
+void imx_gpc_hwirq_unmask(unsigned int hwirq);
void imx_anatop_init(void);
void imx_anatop_pre_suspend(void);
void imx_anatop_post_resume(void);
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode);
void imx6q_set_int_mem_clk_lpm(bool enable);
void imx6sl_set_wait_clk(bool enter);
+int imx_mmdc_get_ddr_type(void);
void imx_cpu_die(unsigned int cpu);
int imx_cpu_kill(unsigned int cpu);
@@ -157,5 +157,6 @@ static inline void imx_init_l2cache(void) {}
#endif
extern struct smp_operations imx_smp_ops;
+extern struct smp_operations ls1021a_smp_ops;
#endif
diff --git a/arch/arm/mach-imx/cpuidle-imx5.c b/arch/arm/mach-imx/cpuidle-imx5.c
index 5a47e3c..3feca52 100644
--- a/arch/arm/mach-imx/cpuidle-imx5.c
+++ b/arch/arm/mach-imx/cpuidle-imx5.c
@@ -24,7 +24,6 @@ static struct cpuidle_driver imx5_cpuidle_driver = {
.enter = imx5_cpuidle_enter,
.exit_latency = 2,
.target_residency = 1,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "IMX5 SRPG",
.desc = "CPU state retained,powered off",
},
diff --git a/arch/arm/mach-imx/cpuidle-imx6q.c b/arch/arm/mach-imx/cpuidle-imx6q.c
index aa93578..d76d086 100644
--- a/arch/arm/mach-imx/cpuidle-imx6q.c
+++ b/arch/arm/mach-imx/cpuidle-imx6q.c
@@ -53,8 +53,7 @@ static struct cpuidle_driver imx6q_cpuidle_driver = {
{
.exit_latency = 50,
.target_residency = 75,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.enter = imx6q_enter_wait,
.name = "WAIT",
.desc = "Clock off",
diff --git a/arch/arm/mach-imx/cpuidle-imx6sl.c b/arch/arm/mach-imx/cpuidle-imx6sl.c
index d4b6b81..7d92e65 100644
--- a/arch/arm/mach-imx/cpuidle-imx6sl.c
+++ b/arch/arm/mach-imx/cpuidle-imx6sl.c
@@ -40,8 +40,7 @@ static struct cpuidle_driver imx6sl_cpuidle_driver = {
{
.exit_latency = 50,
.target_residency = 75,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.enter = imx6sl_enter_wait,
.name = "WAIT",
.desc = "Clock off",
diff --git a/arch/arm/mach-imx/gpc.c b/arch/arm/mach-imx/gpc.c
index 82ea74e..5f3602e 100644
--- a/arch/arm/mach-imx/gpc.c
+++ b/arch/arm/mach-imx/gpc.c
@@ -56,14 +56,14 @@ void imx_gpc_post_resume(void)
static int imx_gpc_irq_set_wake(struct irq_data *d, unsigned int on)
{
- unsigned int idx = d->irq / 32 - 1;
+ unsigned int idx = d->hwirq / 32 - 1;
u32 mask;
/* Sanity check for SPI irq */
- if (d->irq < 32)
+ if (d->hwirq < 32)
return -EINVAL;
- mask = 1 << d->irq % 32;
+ mask = 1 << d->hwirq % 32;
gpc_wake_irqs[idx] = on ? gpc_wake_irqs[idx] | mask :
gpc_wake_irqs[idx] & ~mask;
@@ -91,34 +91,44 @@ void imx_gpc_restore_all(void)
writel_relaxed(gpc_saved_imrs[i], reg_imr1 + i * 4);
}
-void imx_gpc_irq_unmask(struct irq_data *d)
+void imx_gpc_hwirq_unmask(unsigned int hwirq)
{
void __iomem *reg;
u32 val;
- /* Sanity check for SPI irq */
- if (d->irq < 32)
- return;
-
- reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4;
+ reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4;
val = readl_relaxed(reg);
- val &= ~(1 << d->irq % 32);
+ val &= ~(1 << hwirq % 32);
writel_relaxed(val, reg);
}
-void imx_gpc_irq_mask(struct irq_data *d)
+void imx_gpc_hwirq_mask(unsigned int hwirq)
{
void __iomem *reg;
u32 val;
+ reg = gpc_base + GPC_IMR1 + (hwirq / 32 - 1) * 4;
+ val = readl_relaxed(reg);
+ val |= 1 << (hwirq % 32);
+ writel_relaxed(val, reg);
+}
+
+static void imx_gpc_irq_unmask(struct irq_data *d)
+{
+ /* Sanity check for SPI irq */
+ if (d->hwirq < 32)
+ return;
+
+ imx_gpc_hwirq_unmask(d->hwirq);
+}
+
+static void imx_gpc_irq_mask(struct irq_data *d)
+{
/* Sanity check for SPI irq */
- if (d->irq < 32)
+ if (d->hwirq < 32)
return;
- reg = gpc_base + GPC_IMR1 + (d->irq / 32 - 1) * 4;
- val = readl_relaxed(reg);
- val |= 1 << (d->irq % 32);
- writel_relaxed(val, reg);
+ imx_gpc_hwirq_mask(d->hwirq);
}
void __init imx_gpc_init(void)
diff --git a/arch/arm/mach-imx/imx25-dt.c b/arch/arm/mach-imx/imx25-dt.c
index cf8032b..25defbd 100644
--- a/arch/arm/mach-imx/imx25-dt.c
+++ b/arch/arm/mach-imx/imx25-dt.c
@@ -17,13 +17,6 @@
#include "common.h"
#include "mx25.h"
-static void __init imx25_dt_init(void)
-{
- mxc_arch_reset_init_dt();
-
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
static const char * const imx25_dt_board_compat[] __initconst = {
"fsl,imx25",
NULL
@@ -33,7 +26,5 @@ DT_MACHINE_START(IMX25_DT, "Freescale i.MX25 (Device Tree Support)")
.map_io = mx25_map_io,
.init_early = imx25_init_early,
.init_irq = mx25_init_irq,
- .init_machine = imx25_dt_init,
.dt_compat = imx25_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/imx27-dt.c b/arch/arm/mach-imx/imx27-dt.c
index dc8f1a6..bd42d1b 100644
--- a/arch/arm/mach-imx/imx27-dt.c
+++ b/arch/arm/mach-imx/imx27-dt.c
@@ -22,8 +22,6 @@ static void __init imx27_dt_init(void)
{
struct platform_device_info devinfo = { .name = "cpufreq-dt", };
- mxc_arch_reset_init_dt();
-
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
platform_device_register_full(&devinfo);
@@ -40,5 +38,4 @@ DT_MACHINE_START(IMX27_DT, "Freescale i.MX27 (Device Tree Support)")
.init_irq = mx27_init_irq,
.init_machine = imx27_dt_init,
.dt_compat = imx27_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/imx31-dt.c b/arch/arm/mach-imx/imx31-dt.c
index 418dbc8..3210022 100644
--- a/arch/arm/mach-imx/imx31-dt.c
+++ b/arch/arm/mach-imx/imx31-dt.c
@@ -18,13 +18,6 @@
#include "common.h"
#include "mx31.h"
-static void __init imx31_dt_init(void)
-{
- mxc_arch_reset_init_dt();
-
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
static const char * const imx31_dt_board_compat[] __initconst = {
"fsl,imx31",
NULL
@@ -40,7 +33,5 @@ DT_MACHINE_START(IMX31_DT, "Freescale i.MX31 (Device Tree Support)")
.init_early = imx31_init_early,
.init_irq = mx31_init_irq,
.init_time = imx31_dt_timer_init,
- .init_machine = imx31_dt_init,
.dt_compat = imx31_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/imx35-dt.c b/arch/arm/mach-imx/imx35-dt.c
index 584fbe1..e939603 100644
--- a/arch/arm/mach-imx/imx35-dt.c
+++ b/arch/arm/mach-imx/imx35-dt.c
@@ -20,14 +20,6 @@
#include "common.h"
#include "mx35.h"
-static void __init imx35_dt_init(void)
-{
- mxc_arch_reset_init_dt();
-
- of_platform_populate(NULL, of_default_bus_match_table,
- NULL, NULL);
-}
-
static void __init imx35_irq_init(void)
{
imx_init_l2cache();
@@ -43,7 +35,5 @@ DT_MACHINE_START(IMX35_DT, "Freescale i.MX35 (Device Tree Support)")
.map_io = mx35_map_io,
.init_early = imx35_init_early,
.init_irq = imx35_irq_init,
- .init_machine = imx35_dt_init,
.dt_compat = imx35_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/iomux-imx31.c b/arch/arm/mach-imx/iomux-imx31.c
index 1657fe6..d6a3075 100644
--- a/arch/arm/mach-imx/iomux-imx31.c
+++ b/arch/arm/mach-imx/iomux-imx31.c
@@ -44,9 +44,11 @@ static unsigned long mxc_pin_alloc_map[NB_PORTS * 32 / BITS_PER_LONG];
/*
* set the mode for a IOMUX pin.
*/
-int mxc_iomux_mode(unsigned int pin_mode)
+void mxc_iomux_mode(unsigned int pin_mode)
{
- u32 field, l, mode, ret = 0;
+ u32 field;
+ u32 l;
+ u32 mode;
void __iomem *reg;
reg = IOMUXSW_MUX_CTL + (pin_mode & IOMUX_REG_MASK);
@@ -61,8 +63,6 @@ int mxc_iomux_mode(unsigned int pin_mode)
__raw_writel(l, reg);
spin_unlock(&gpio_mux_lock);
-
- return ret;
}
/*
diff --git a/arch/arm/mach-imx/iomux-mx3.h b/arch/arm/mach-imx/iomux-mx3.h
index f79f78a..0a5adba 100644
--- a/arch/arm/mach-imx/iomux-mx3.h
+++ b/arch/arm/mach-imx/iomux-mx3.h
@@ -144,7 +144,7 @@ void mxc_iomux_set_gpr(enum iomux_gp_func, bool en);
* It is called by the setup functions and should not be called directly anymore.
* It is here visible for backward compatibility
*/
-int mxc_iomux_mode(unsigned int pin_mode);
+void mxc_iomux_mode(unsigned int pin_mode);
#define IOMUX_PADNUM_MASK 0x1ff
#define IOMUX_GPIONUM_SHIFT 9
diff --git a/arch/arm/mach-imx/mach-imx50.c b/arch/arm/mach-imx/mach-imx50.c
index b1e56a9..ecf58b9 100644
--- a/arch/arm/mach-imx/mach-imx50.c
+++ b/arch/arm/mach-imx/mach-imx50.c
@@ -16,13 +16,6 @@
#include "common.h"
-static void __init imx50_dt_init(void)
-{
- mxc_arch_reset_init_dt();
-
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
static const char * const imx50_dt_board_compat[] __initconst = {
"fsl,imx50",
NULL
@@ -30,7 +23,5 @@ static const char * const imx50_dt_board_compat[] __initconst = {
DT_MACHINE_START(IMX50_DT, "Freescale i.MX50 (Device Tree Support)")
.init_irq = tzic_init_irq,
- .init_machine = imx50_dt_init,
.dt_compat = imx50_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx51.c b/arch/arm/mach-imx/mach-imx51.c
index 2c5fcaf..b015129 100644
--- a/arch/arm/mach-imx/mach-imx51.c
+++ b/arch/arm/mach-imx/mach-imx51.c
@@ -53,7 +53,6 @@ static void __init imx51_dt_init(void)
{
struct platform_device_info devinfo = { .name = "cpufreq-dt", };
- mxc_arch_reset_init_dt();
imx51_ipu_mipi_setup();
imx_src_init();
@@ -78,5 +77,4 @@ DT_MACHINE_START(IMX51_DT, "Freescale i.MX51 (Device Tree Support)")
.init_machine = imx51_dt_init,
.init_late = imx51_init_late,
.dt_compat = imx51_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx53.c b/arch/arm/mach-imx/mach-imx53.c
index 03dd6ea..86316a9 100644
--- a/arch/arm/mach-imx/mach-imx53.c
+++ b/arch/arm/mach-imx/mach-imx53.c
@@ -30,7 +30,6 @@ static void __init imx53_init_early(void)
static void __init imx53_dt_init(void)
{
- mxc_arch_reset_init_dt();
imx_src_init();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
@@ -41,6 +40,8 @@ static void __init imx53_dt_init(void)
static void __init imx53_init_late(void)
{
imx53_pm_init();
+
+ platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
}
static const char * const imx53_dt_board_compat[] __initconst = {
@@ -54,5 +55,4 @@ DT_MACHINE_START(IMX53_DT, "Freescale i.MX53 (Device Tree Support)")
.init_machine = imx53_dt_init,
.init_late = imx53_init_late,
.dt_compat = imx53_dt_board_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx6q.c b/arch/arm/mach-imx/mach-imx6q.c
index d51c6e9..5057d61 100644
--- a/arch/arm/mach-imx/mach-imx6q.c
+++ b/arch/arm/mach-imx/mach-imx6q.c
@@ -268,8 +268,6 @@ static void __init imx6q_init_machine(void)
imx_print_silicon_rev(cpu_is_imx6dl() ? "i.MX6DL" : "i.MX6Q",
imx_get_soc_revision());
- mxc_arch_reset_init_dt();
-
parent = imx_soc_device_init();
if (parent == NULL)
pr_warn("failed to initialize soc device\n");
@@ -409,5 +407,4 @@ DT_MACHINE_START(IMX6Q, "Freescale i.MX6 Quad/DualLite (Device Tree)")
.init_machine = imx6q_init_machine,
.init_late = imx6q_init_late,
.dt_compat = imx6q_dt_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx6sl.c b/arch/arm/mach-imx/mach-imx6sl.c
index ed263a2..24bfaaf 100644
--- a/arch/arm/mach-imx/mach-imx6sl.c
+++ b/arch/arm/mach-imx/mach-imx6sl.c
@@ -48,8 +48,6 @@ static void __init imx6sl_init_machine(void)
{
struct device *parent;
- mxc_arch_reset_init_dt();
-
parent = imx_soc_device_init();
if (parent == NULL)
pr_warn("failed to initialize soc device\n");
@@ -76,10 +74,8 @@ static const char * const imx6sl_dt_compat[] __initconst = {
};
DT_MACHINE_START(IMX6SL, "Freescale i.MX6 SoloLite (Device Tree)")
- .map_io = debug_ll_io_init,
.init_irq = imx6sl_init_irq,
.init_machine = imx6sl_init_machine,
.init_late = imx6sl_init_late,
.dt_compat = imx6sl_dt_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-imx6sx.c b/arch/arm/mach-imx/mach-imx6sx.c
index 3de3b73..7a96c65 100644
--- a/arch/arm/mach-imx/mach-imx6sx.c
+++ b/arch/arm/mach-imx/mach-imx6sx.c
@@ -8,24 +8,73 @@
#include <linux/irqchip.h>
#include <linux/of_platform.h>
+#include <linux/phy.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/mfd/syscon/imx6q-iomuxc-gpr.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include "common.h"
#include "cpuidle.h"
+static int ar8031_phy_fixup(struct phy_device *dev)
+{
+ u16 val;
+
+ /* Set RGMII IO voltage to 1.8V */
+ phy_write(dev, 0x1d, 0x1f);
+ phy_write(dev, 0x1e, 0x8);
+
+ /* introduce tx clock delay */
+ phy_write(dev, 0x1d, 0x5);
+ val = phy_read(dev, 0x1e);
+ val |= 0x0100;
+ phy_write(dev, 0x1e, val);
+
+ return 0;
+}
+
+#define PHY_ID_AR8031 0x004dd074
+static void __init imx6sx_enet_phy_init(void)
+{
+ if (IS_BUILTIN(CONFIG_PHYLIB))
+ phy_register_fixup_for_uid(PHY_ID_AR8031, 0xffffffff,
+ ar8031_phy_fixup);
+}
+
+static void __init imx6sx_enet_clk_sel(void)
+{
+ struct regmap *gpr;
+
+ gpr = syscon_regmap_lookup_by_compatible("fsl,imx6sx-iomuxc-gpr");
+ if (!IS_ERR(gpr)) {
+ regmap_update_bits(gpr, IOMUXC_GPR1,
+ IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK, 0);
+ regmap_update_bits(gpr, IOMUXC_GPR1,
+ IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK, 0);
+ } else {
+ pr_err("failed to find fsl,imx6sx-iomux-gpr regmap\n");
+ }
+}
+
+static inline void imx6sx_enet_init(void)
+{
+ imx6sx_enet_phy_init();
+ imx6sx_enet_clk_sel();
+}
+
static void __init imx6sx_init_machine(void)
{
struct device *parent;
- mxc_arch_reset_init_dt();
-
parent = imx_soc_device_init();
if (parent == NULL)
pr_warn("failed to initialize soc device\n");
of_platform_populate(NULL, of_default_bus_match_table, NULL, parent);
+ imx6sx_enet_init();
imx_anatop_init();
imx6sx_pm_init();
}
@@ -53,10 +102,8 @@ static const char * const imx6sx_dt_compat[] __initconst = {
};
DT_MACHINE_START(IMX6SX, "Freescale i.MX6 SoloX (Device Tree)")
- .map_io = debug_ll_io_init,
.init_irq = imx6sx_init_irq,
.init_machine = imx6sx_init_machine,
.dt_compat = imx6sx_dt_compat,
.init_late = imx6sx_init_late,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mach-ls1021a.c b/arch/arm/mach-imx/mach-ls1021a.c
new file mode 100644
index 0000000..b89c858
--- /dev/null
+++ b/arch/arm/mach-imx/mach-ls1021a.c
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2013-2014 Freescale Semiconductor, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <asm/mach/arch.h>
+
+#include "common.h"
+
+static const char * const ls1021a_dt_compat[] __initconst = {
+ "fsl,ls1021a",
+ NULL,
+};
+
+DT_MACHINE_START(LS1021A, "Freescale LS1021A")
+ .smp = smp_ops(ls1021a_smp_ops),
+ .dt_compat = ls1021a_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-imx/mach-vf610.c b/arch/arm/mach-imx/mach-vf610.c
index ee7e57b..c11ab6a 100644
--- a/arch/arm/mach-imx/mach-vf610.c
+++ b/arch/arm/mach-imx/mach-vf610.c
@@ -12,14 +12,6 @@
#include <asm/mach/arch.h>
#include <asm/hardware/cache-l2x0.h>
-#include "common.h"
-
-static void __init vf610_init_machine(void)
-{
- mxc_arch_reset_init_dt();
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
static const char * const vf610_dt_compat[] __initconst = {
"fsl,vf610",
NULL,
@@ -28,7 +20,5 @@ static const char * const vf610_dt_compat[] __initconst = {
DT_MACHINE_START(VYBRID_VF610, "Freescale Vybrid VF610 (Device Tree)")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
- .init_machine = vf610_init_machine,
.dt_compat = vf610_dt_compat,
- .restart = mxc_restart,
MACHINE_END
diff --git a/arch/arm/mach-imx/mmdc.c b/arch/arm/mach-imx/mmdc.c
index 7a9686a..3729d90 100644
--- a/arch/arm/mach-imx/mmdc.c
+++ b/arch/arm/mach-imx/mmdc.c
@@ -21,6 +21,12 @@
#define BP_MMDC_MAPSR_PSD 0
#define BP_MMDC_MAPSR_PSS 4
+#define MMDC_MDMISC 0x18
+#define BM_MMDC_MDMISC_DDR_TYPE 0x18
+#define BP_MMDC_MDMISC_DDR_TYPE 0x3
+
+static int ddr_type;
+
static int imx_mmdc_probe(struct platform_device *pdev)
{
struct device_node *np = pdev->dev.of_node;
@@ -31,6 +37,12 @@ static int imx_mmdc_probe(struct platform_device *pdev)
mmdc_base = of_iomap(np, 0);
WARN_ON(!mmdc_base);
+ reg = mmdc_base + MMDC_MDMISC;
+ /* Get ddr type */
+ val = readl_relaxed(reg);
+ ddr_type = (val & BM_MMDC_MDMISC_DDR_TYPE) >>
+ BP_MMDC_MDMISC_DDR_TYPE;
+
reg = mmdc_base + MMDC_MAPSR;
/* Enable automatic power saving */
@@ -51,6 +63,11 @@ static int imx_mmdc_probe(struct platform_device *pdev)
return 0;
}
+int imx_mmdc_get_ddr_type(void)
+{
+ return ddr_type;
+}
+
static struct of_device_id imx_mmdc_dt_ids[] = {
{ .compatible = "fsl,imx6q-mmdc", },
{ /* sentinel */ }
diff --git a/arch/arm/mach-imx/mxc.h b/arch/arm/mach-imx/mxc.h
index 17a41ca..4c1343d 100644
--- a/arch/arm/mach-imx/mxc.h
+++ b/arch/arm/mach-imx/mxc.h
@@ -55,6 +55,8 @@
#define IMX_CHIP_REVISION_3_3 0x33
#define IMX_CHIP_REVISION_UNKNOWN 0xff
+#define IMX_DDR_TYPE_LPDDR2 1
+
#ifndef __ASSEMBLY__
extern unsigned int __mxc_cpu_type;
#endif
diff --git a/arch/arm/mach-imx/platsmp.c b/arch/arm/mach-imx/platsmp.c
index 771bd25..7f27001 100644
--- a/arch/arm/mach-imx/platsmp.c
+++ b/arch/arm/mach-imx/platsmp.c
@@ -11,7 +11,10 @@
*/
#include <linux/init.h>
+#include <linux/of_address.h>
+#include <linux/of.h>
#include <linux/smp.h>
+
#include <asm/cacheflush.h>
#include <asm/page.h>
#include <asm/smp_scu.h>
@@ -94,3 +97,33 @@ struct smp_operations imx_smp_ops __initdata = {
.cpu_kill = imx_cpu_kill,
#endif
};
+
+#define DCFG_CCSR_SCRATCHRW1 0x200
+
+static int ls1021a_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
+ return 0;
+}
+
+static void __init ls1021a_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *np;
+ void __iomem *dcfg_base;
+ unsigned long paddr;
+
+ np = of_find_compatible_node(NULL, NULL, "fsl,ls1021a-dcfg");
+ dcfg_base = of_iomap(np, 0);
+ BUG_ON(!dcfg_base);
+
+ paddr = virt_to_phys(secondary_startup);
+ writel_relaxed(cpu_to_be32(paddr), dcfg_base + DCFG_CCSR_SCRATCHRW1);
+
+ iounmap(dcfg_base);
+}
+
+struct smp_operations ls1021a_smp_ops __initdata = {
+ .smp_prepare_cpus = ls1021a_smp_prepare_cpus,
+ .smp_boot_secondary = ls1021a_boot_secondary,
+};
diff --git a/arch/arm/mach-imx/pm-imx6.c b/arch/arm/mach-imx/pm-imx6.c
index 5c3af8f..5d2c1bd 100644
--- a/arch/arm/mach-imx/pm-imx6.c
+++ b/arch/arm/mach-imx/pm-imx6.c
@@ -88,7 +88,7 @@ struct imx6_pm_base {
};
struct imx6_pm_socdata {
- u32 cpu_type;
+ u32 ddr_type;
const char *mmdc_compat;
const char *src_compat;
const char *iomuxc_compat;
@@ -138,7 +138,6 @@ static const u32 imx6sx_mmdc_io_offset[] __initconst = {
};
static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
- .cpu_type = MXC_CPU_IMX6Q,
.mmdc_compat = "fsl,imx6q-mmdc",
.src_compat = "fsl,imx6q-src",
.iomuxc_compat = "fsl,imx6q-iomuxc",
@@ -148,7 +147,6 @@ static const struct imx6_pm_socdata imx6q_pm_data __initconst = {
};
static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
- .cpu_type = MXC_CPU_IMX6DL,
.mmdc_compat = "fsl,imx6q-mmdc",
.src_compat = "fsl,imx6q-src",
.iomuxc_compat = "fsl,imx6dl-iomuxc",
@@ -158,7 +156,6 @@ static const struct imx6_pm_socdata imx6dl_pm_data __initconst = {
};
static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
- .cpu_type = MXC_CPU_IMX6SL,
.mmdc_compat = "fsl,imx6sl-mmdc",
.src_compat = "fsl,imx6sl-src",
.iomuxc_compat = "fsl,imx6sl-iomuxc",
@@ -168,7 +165,6 @@ static const struct imx6_pm_socdata imx6sl_pm_data __initconst = {
};
static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
- .cpu_type = MXC_CPU_IMX6SX,
.mmdc_compat = "fsl,imx6sx-mmdc",
.src_compat = "fsl,imx6sx-src",
.iomuxc_compat = "fsl,imx6sx-iomuxc",
@@ -187,7 +183,7 @@ static const struct imx6_pm_socdata imx6sx_pm_data __initconst = {
struct imx6_cpu_pm_info {
phys_addr_t pbase; /* The physical address of pm_info. */
phys_addr_t resume_addr; /* The physical resume address for asm code */
- u32 cpu_type;
+ u32 ddr_type;
u32 pm_info_size; /* Size of pm_info. */
struct imx6_pm_base mmdc_base;
struct imx6_pm_base src_base;
@@ -261,7 +257,6 @@ static void imx6q_enable_wb(bool enable)
int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
{
- struct irq_data *iomuxc_irq_data = irq_get_irq_data(32);
u32 val = readl_relaxed(ccm_base + CLPCR);
val &= ~BM_CLPCR_LPM;
@@ -316,9 +311,9 @@ int imx6q_set_lpm(enum mxc_cpu_pwr_mode mode)
* 3) Software should mask IRQ #32 right after CCM Low-Power mode
* is set (set bits 0-1 of CCM_CLPCR).
*/
- imx_gpc_irq_unmask(iomuxc_irq_data);
+ imx_gpc_hwirq_unmask(32);
writel_relaxed(val, ccm_base + CLPCR);
- imx_gpc_irq_mask(iomuxc_irq_data);
+ imx_gpc_hwirq_mask(32);
return 0;
}
@@ -522,7 +517,7 @@ static int __init imx6q_suspend_init(const struct imx6_pm_socdata *socdata)
goto pl310_cache_map_failed;
}
- pm_info->cpu_type = socdata->cpu_type;
+ pm_info->ddr_type = imx_mmdc_get_ddr_type();
pm_info->mmdc_io_num = socdata->mmdc_io_num;
mmdc_offset_array = socdata->mmdc_io_offset;
diff --git a/arch/arm/mach-imx/suspend-imx6.S b/arch/arm/mach-imx/suspend-imx6.S
index ca4ea2d..b99987b 100644
--- a/arch/arm/mach-imx/suspend-imx6.S
+++ b/arch/arm/mach-imx/suspend-imx6.S
@@ -45,7 +45,7 @@
*/
#define PM_INFO_PBASE_OFFSET 0x0
#define PM_INFO_RESUME_ADDR_OFFSET 0x4
-#define PM_INFO_CPU_TYPE_OFFSET 0x8
+#define PM_INFO_DDR_TYPE_OFFSET 0x8
#define PM_INFO_PM_INFO_SIZE_OFFSET 0xC
#define PM_INFO_MX6Q_MMDC_P_OFFSET 0x10
#define PM_INFO_MX6Q_MMDC_V_OFFSET 0x14
@@ -110,7 +110,7 @@
ldreq r11, [r0, #PM_INFO_MX6Q_MMDC_V_OFFSET]
ldrne r11, [r0, #PM_INFO_MX6Q_MMDC_P_OFFSET]
- cmp r3, #MXC_CPU_IMX6SL
+ cmp r3, #IMX_DDR_TYPE_LPDDR2
bne 4f
/* reset read FIFO, RST_RD_FIFO */
@@ -151,7 +151,7 @@
ENTRY(imx6_suspend)
ldr r1, [r0, #PM_INFO_PBASE_OFFSET]
ldr r2, [r0, #PM_INFO_RESUME_ADDR_OFFSET]
- ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
+ ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
ldr r4, [r0, #PM_INFO_PM_INFO_SIZE_OFFSET]
/*
@@ -209,8 +209,8 @@ poll_dvfs_set:
ldr r7, [r0, #PM_INFO_MMDC_IO_NUM_OFFSET]
ldr r8, =PM_INFO_MMDC_IO_VAL_OFFSET
add r8, r8, r0
- /* i.MX6SL's last 3 IOs need special setting */
- cmp r3, #MXC_CPU_IMX6SL
+ /* LPDDR2's last 3 IOs need special setting */
+ cmp r3, #IMX_DDR_TYPE_LPDDR2
subeq r7, r7, #0x3
set_mmdc_io_lpm:
ldr r9, [r8], #0x8
@@ -218,7 +218,7 @@ set_mmdc_io_lpm:
subs r7, r7, #0x1
bne set_mmdc_io_lpm
- cmp r3, #MXC_CPU_IMX6SL
+ cmp r3, #IMX_DDR_TYPE_LPDDR2
bne set_mmdc_io_lpm_done
ldr r6, =0x1000
ldr r9, [r8], #0x8
@@ -324,7 +324,7 @@ resume:
str r7, [r11, #MX6Q_SRC_GPR1]
str r7, [r11, #MX6Q_SRC_GPR2]
- ldr r3, [r0, #PM_INFO_CPU_TYPE_OFFSET]
+ ldr r3, [r0, #PM_INFO_DDR_TYPE_OFFSET]
mov r5, #0x1
resume_mmdc
diff --git a/arch/arm/mach-imx/system.c b/arch/arm/mach-imx/system.c
index d14c33f..51c3501 100644
--- a/arch/arm/mach-imx/system.c
+++ b/arch/arm/mach-imx/system.c
@@ -89,21 +89,6 @@ void __init mxc_arch_reset_init(void __iomem *base)
clk_prepare(wdog_clk);
}
-void __init mxc_arch_reset_init_dt(void)
-{
- struct device_node *np;
-
- np = of_find_compatible_node(NULL, NULL, "fsl,imx21-wdt");
- wdog_base = of_iomap(np, 0);
- WARN_ON(!wdog_base);
-
- wdog_clk = of_clk_get(np, 0);
- if (IS_ERR(wdog_clk))
- pr_warn("%s: failed to get wdog clock\n", __func__);
- else
- clk_prepare(wdog_clk);
-}
-
#ifdef CONFIG_CACHE_L2X0
void __init imx_init_l2cache(void)
{
diff --git a/arch/arm/mach-integrator/Kconfig b/arch/arm/mach-integrator/Kconfig
index c455e97..02d0834 100644
--- a/arch/arm/mach-integrator/Kconfig
+++ b/arch/arm/mach-integrator/Kconfig
@@ -1,3 +1,26 @@
+config ARCH_INTEGRATOR
+ bool "ARM Ltd. Integrator family" if (ARCH_MULTI_V4T || ARCH_MULTI_V5 || ARCH_MULTI_V6)
+ select ARM_AMBA
+ select ARM_PATCH_PHYS_VIRT if MMU
+ select AUTO_ZRELADDR
+ select COMMON_CLK
+ select COMMON_CLK_VERSATILE
+ select GENERIC_CLOCKEVENTS
+ select HAVE_TCM
+ select ICST
+ select MFD_SYSCON
+ select MULTI_IRQ_HANDLER
+ select PLAT_VERSATILE
+ select POWER_RESET
+ select POWER_RESET_VERSATILE
+ select POWER_SUPPLY
+ select SOC_INTEGRATOR_CM
+ select SPARSE_IRQ
+ select USE_OF
+ select VERSATILE_FPGA_IRQ
+ help
+ Support for ARM's Integrator platform.
+
if ARCH_INTEGRATOR
menu "Integrator Options"
diff --git a/arch/arm/mach-integrator/Makefile b/arch/arm/mach-integrator/Makefile
index ec759de..1ebe453 100644
--- a/arch/arm/mach-integrator/Makefile
+++ b/arch/arm/mach-integrator/Makefile
@@ -4,7 +4,7 @@
# Object file lists.
-obj-y := core.o lm.o leds.o
+obj-y := core.o lm.o
obj-$(CONFIG_ARCH_INTEGRATOR_AP) += integrator_ap.o
obj-$(CONFIG_ARCH_INTEGRATOR_CP) += integrator_cp.o
diff --git a/arch/arm/mach-integrator/cm.h b/arch/arm/mach-integrator/cm.h
index 4ecff7b..5b8ba82 100644
--- a/arch/arm/mach-integrator/cm.h
+++ b/arch/arm/mach-integrator/cm.h
@@ -11,7 +11,6 @@ void cm_clear_irqs(void);
#define CM_CTRL_LED (1 << 0)
#define CM_CTRL_nMBDET (1 << 1)
#define CM_CTRL_REMAP (1 << 2)
-#define CM_CTRL_RESET (1 << 3)
/*
* Integrator/AP,PP2 specific
diff --git a/arch/arm/mach-integrator/common.h b/arch/arm/mach-integrator/common.h
index ad0ac554..96c9dc5 100644
--- a/arch/arm/mach-integrator/common.h
+++ b/arch/arm/mach-integrator/common.h
@@ -4,5 +4,3 @@ 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(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 e3f3aca..948872a 100644
--- a/arch/arm/mach-integrator/core.c
+++ b/arch/arm/mach-integrator/core.c
@@ -60,40 +60,6 @@ void cm_control(u32 mask, u32 set)
raw_spin_unlock_irqrestore(&cm_lock, flags);
}
-static const char *integrator_arch_str(u32 id)
-{
- switch ((id >> 16) & 0xff) {
- case 0x00:
- return "ASB little-endian";
- case 0x01:
- return "AHB little-endian";
- case 0x03:
- return "AHB-Lite system bus, bi-endian";
- case 0x04:
- return "AHB";
- case 0x08:
- return "AHB system bus, ASB processor bus";
- default:
- return "Unknown";
- }
-}
-
-static const char *integrator_fpga_str(u32 id)
-{
- switch ((id >> 12) & 0xf) {
- case 0x01:
- return "XC4062";
- case 0x02:
- return "XC4085";
- case 0x03:
- return "XVC600";
- case 0x04:
- return "EPM7256AE (Altera PLD)";
- default:
- return "Unknown";
- }
-}
-
void cm_clear_irqs(void)
{
/* disable core module IRQs */
@@ -109,7 +75,6 @@ static const struct of_device_id cm_match[] = {
void cm_init(void)
{
struct device_node *cm = of_find_matching_node(NULL, cm_match);
- u32 val;
if (!cm) {
pr_crit("no core module node found in device tree\n");
@@ -121,13 +86,6 @@ void cm_init(void)
return;
}
cm_clear_irqs();
- val = readl(cm_base + INTEGRATOR_HDR_ID_OFFSET);
- pr_info("Detected ARM core module:\n");
- pr_info(" Manufacturer: %02x\n", (val >> 24));
- pr_info(" Architecture: %s\n", integrator_arch_str(val));
- pr_info(" FPGA: %s\n", integrator_fpga_str(val));
- pr_info(" Build: %02x\n", (val >> 4) & 0xFF);
- pr_info(" Rev: %c\n", ('A' + (val & 0x03)));
}
/*
@@ -139,64 +97,3 @@ void __init integrator_reserve(void)
{
memblock_reserve(PHYS_OFFSET, __pa(swapper_pg_dir) - PHYS_OFFSET);
}
-
-/*
- * To reset, we hit the on-board reset register in the system FPGA
- */
-void integrator_restart(enum reboot_mode mode, const char *cmd)
-{
- cm_control(CM_CTRL_RESET, CM_CTRL_RESET);
-}
-
-static u32 integrator_id;
-
-static ssize_t intcp_get_manf(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%02x\n", integrator_id >> 24);
-}
-
-static struct device_attribute intcp_manf_attr =
- __ATTR(manufacturer, S_IRUGO, intcp_get_manf, NULL);
-
-static ssize_t intcp_get_arch(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", integrator_arch_str(integrator_id));
-}
-
-static struct device_attribute intcp_arch_attr =
- __ATTR(architecture, S_IRUGO, intcp_get_arch, NULL);
-
-static ssize_t intcp_get_fpga(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%s\n", integrator_fpga_str(integrator_id));
-}
-
-static struct device_attribute intcp_fpga_attr =
- __ATTR(fpga, S_IRUGO, intcp_get_fpga, NULL);
-
-static ssize_t intcp_get_build(struct device *dev,
- struct device_attribute *attr,
- char *buf)
-{
- return sprintf(buf, "%02x\n", (integrator_id >> 4) & 0xFF);
-}
-
-static struct device_attribute intcp_build_attr =
- __ATTR(build, S_IRUGO, intcp_get_build, NULL);
-
-
-
-void integrator_init_sysfs(struct device *parent, u32 id)
-{
- integrator_id = id;
- device_create_file(parent, &intcp_manf_attr);
- device_create_file(parent, &intcp_arch_attr);
- device_create_file(parent, &intcp_fpga_attr);
- device_create_file(parent, &intcp_build_attr);
-}
diff --git a/arch/arm/mach-integrator/include/mach/uncompress.h b/arch/arm/mach-integrator/include/mach/uncompress.h
deleted file mode 100644
index 8f3cc99..0000000
--- a/arch/arm/mach-integrator/include/mach/uncompress.h
+++ /dev/null
@@ -1,48 +0,0 @@
-/*
- * arch/arm/mach-integrator/include/mach/uncompress.h
- *
- * Copyright (C) 1999 ARM Limited
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#define AMBA_UART_DR (*(volatile unsigned char *)0x16000000)
-#define AMBA_UART_LCRH (*(volatile unsigned char *)0x16000008)
-#define AMBA_UART_LCRM (*(volatile unsigned char *)0x1600000c)
-#define AMBA_UART_LCRL (*(volatile unsigned char *)0x16000010)
-#define AMBA_UART_CR (*(volatile unsigned char *)0x16000014)
-#define AMBA_UART_FR (*(volatile unsigned char *)0x16000018)
-
-/*
- * This does not append a newline
- */
-static void putc(int c)
-{
- while (AMBA_UART_FR & (1 << 5))
- barrier();
-
- AMBA_UART_DR = c;
-}
-
-static inline void flush(void)
-{
- while (AMBA_UART_FR & (1 << 3))
- barrier();
-}
-
-/*
- * nothing to do
- */
-#define arch_decomp_setup()
diff --git a/arch/arm/mach-integrator/integrator_ap.c b/arch/arm/mach-integrator/integrator_ap.c
index 8ca290b..30003ba 100644
--- a/arch/arm/mach-integrator/integrator_ap.c
+++ b/arch/arm/mach-integrator/integrator_ap.c
@@ -27,22 +27,15 @@
#include <linux/syscore_ops.h>
#include <linux/amba/bus.h>
#include <linux/amba/kmi.h>
-#include <linux/clocksource.h>
-#include <linux/clockchips.h>
-#include <linux/interrupt.h>
#include <linux/io.h>
#include <linux/irqchip.h>
#include <linux/mtd/physmap.h>
-#include <linux/clk.h>
#include <linux/platform_data/clk-integrator.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
#include <linux/stat.h>
-#include <linux/sys_soc.h>
#include <linux/termios.h>
-#include <linux/sched_clock.h>
-#include <linux/clk-provider.h>
#include <asm/hardware/arm_timer.h>
#include <asm/setup.h>
@@ -89,11 +82,6 @@ static void __iomem *ebi_base;
static struct map_desc ap_io_desc[] __initdata __maybe_unused = {
{
- .virtual = IO_ADDRESS(INTEGRATOR_CT_BASE),
- .pfn = __phys_to_pfn(INTEGRATOR_CT_BASE),
- .length = SZ_4K,
- .type = MT_DEVICE
- }, {
.virtual = IO_ADDRESS(INTEGRATOR_IC_BASE),
.pfn = __phys_to_pfn(INTEGRATOR_IC_BASE),
.length = SZ_4K,
@@ -257,188 +245,10 @@ struct amba_pl010_data ap_uart_data = {
.set_mctrl = integrator_uart_set_mctrl,
};
-/*
- * Where is the timer (VA)?
- */
-#define TIMER0_VA_BASE __io_address(INTEGRATOR_TIMER0_BASE)
-#define TIMER1_VA_BASE __io_address(INTEGRATOR_TIMER1_BASE)
-#define TIMER2_VA_BASE __io_address(INTEGRATOR_TIMER2_BASE)
-
-static unsigned long timer_reload;
-
-static u64 notrace integrator_read_sched_clock(void)
-{
- return -readl((void __iomem *) TIMER2_VA_BASE + TIMER_VALUE);
-}
-
-static void integrator_clocksource_init(unsigned long inrate,
- void __iomem *base)
-{
- u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
- unsigned long rate = inrate;
-
- if (rate >= 1500000) {
- rate /= 16;
- ctrl |= TIMER_CTRL_DIV16;
- }
-
- writel(0xffff, base + TIMER_LOAD);
- writel(ctrl, base + TIMER_CTRL);
-
- clocksource_mmio_init(base + TIMER_VALUE, "timer2",
- rate, 200, 16, clocksource_mmio_readl_down);
- sched_clock_register(integrator_read_sched_clock, 16, rate);
-}
-
-static void __iomem * clkevt_base;
-
-/*
- * IRQ handler for the timer
- */
-static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
-{
- struct clock_event_device *evt = dev_id;
-
- /* clear the interrupt */
- writel(1, clkevt_base + TIMER_INTCLR);
-
- evt->event_handler(evt);
-
- return IRQ_HANDLED;
-}
-
-static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
-{
- u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
-
- /* Disable timer */
- writel(ctrl, clkevt_base + TIMER_CTRL);
-
- switch (mode) {
- case CLOCK_EVT_MODE_PERIODIC:
- /* Enable the timer and start the periodic tick */
- writel(timer_reload, clkevt_base + TIMER_LOAD);
- ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
- writel(ctrl, clkevt_base + TIMER_CTRL);
- break;
- case CLOCK_EVT_MODE_ONESHOT:
- /* Leave the timer disabled, .set_next_event will enable it */
- ctrl &= ~TIMER_CTRL_PERIODIC;
- writel(ctrl, clkevt_base + TIMER_CTRL);
- break;
- case CLOCK_EVT_MODE_UNUSED:
- case CLOCK_EVT_MODE_SHUTDOWN:
- case CLOCK_EVT_MODE_RESUME:
- default:
- /* Just leave in disabled state */
- break;
- }
-
-}
-
-static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
-{
- unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
-
- writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
- writel(next, clkevt_base + TIMER_LOAD);
- writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
-
- return 0;
-}
-
-static struct clock_event_device integrator_clockevent = {
- .name = "timer1",
- .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
- .set_mode = clkevt_set_mode,
- .set_next_event = clkevt_set_next_event,
- .rating = 300,
-};
-
-static struct irqaction integrator_timer_irq = {
- .name = "timer",
- .flags = IRQF_TIMER | IRQF_IRQPOLL,
- .handler = integrator_timer_interrupt,
- .dev_id = &integrator_clockevent,
-};
-
-static void integrator_clockevent_init(unsigned long inrate,
- void __iomem *base, int irq)
-{
- unsigned long rate = inrate;
- unsigned int ctrl = 0;
-
- clkevt_base = base;
- /* Calculate and program a divisor */
- if (rate > 0x100000 * HZ) {
- rate /= 256;
- ctrl |= TIMER_CTRL_DIV256;
- } else if (rate > 0x10000 * HZ) {
- rate /= 16;
- ctrl |= TIMER_CTRL_DIV16;
- }
- timer_reload = rate / HZ;
- writel(ctrl, clkevt_base + TIMER_CTRL);
-
- setup_irq(irq, &integrator_timer_irq);
- clockevents_config_and_register(&integrator_clockevent,
- rate,
- 1,
- 0xffffU);
-}
-
void __init ap_init_early(void)
{
}
-static void __init ap_of_timer_init(void)
-{
- struct device_node *node;
- const char *path;
- void __iomem *base;
- int err;
- int irq;
- struct clk *clk;
- unsigned long rate;
-
- of_clk_init(NULL);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-primary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
-
- clk = of_clk_get(node, 0);
- BUG_ON(IS_ERR(clk));
- clk_prepare_enable(clk);
- rate = clk_get_rate(clk);
-
- writel(0, base + TIMER_CTRL);
- integrator_clocksource_init(rate, base);
-
- err = of_property_read_string(of_aliases,
- "arm,timer-secondary", &path);
- if (WARN_ON(err))
- return;
- node = of_find_node_by_path(path);
- base = of_iomap(node, 0);
- if (WARN_ON(!base))
- return;
- irq = irq_of_parse_and_map(node, 0);
-
- clk = of_clk_get(node, 0);
- BUG_ON(IS_ERR(clk));
- clk_prepare_enable(clk);
- rate = clk_get_rate(clk);
-
- writel(0, base + TIMER_CTRL);
- integrator_clockevent_init(rate, base, irq);
-}
-
static void __init ap_init_irq_of(void)
{
cm_init();
@@ -477,10 +287,6 @@ static void __init ap_init_of(void)
unsigned long sc_dec;
struct device_node *syscon;
struct device_node *ebi;
- struct device *parent;
- struct soc_device *soc_dev;
- struct soc_device_attribute *soc_dev_attr;
- u32 ap_sc_id;
int i;
syscon = of_find_matching_node(NULL, ap_syscon_match);
@@ -500,28 +306,6 @@ static void __init ap_init_of(void)
of_platform_populate(NULL, of_default_bus_match_table,
ap_auxdata_lookup, NULL);
- ap_sc_id = readl(ap_syscon_base);
-
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- return;
-
- soc_dev_attr->soc_id = "XVC";
- soc_dev_attr->machine = "Integrator/AP";
- soc_dev_attr->family = "Integrator";
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
- 'A' + (ap_sc_id & 0x0f));
-
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr->revision);
- kfree(soc_dev_attr);
- return;
- }
-
- parent = soc_device_to_device(soc_dev);
- integrator_init_sysfs(parent, ap_sc_id);
-
sc_dec = readl(ap_syscon_base + INTEGRATOR_SC_DEC_OFFSET);
for (i = 0; i < 4; i++) {
struct lm_device *lmdev;
@@ -553,8 +337,6 @@ DT_MACHINE_START(INTEGRATOR_AP_DT, "ARM Integrator/AP (Device Tree)")
.map_io = ap_map_io,
.init_early = ap_init_early,
.init_irq = ap_init_irq_of,
- .init_time = ap_of_timer_init,
.init_machine = ap_init_of,
- .restart = integrator_restart,
.dt_compat = ap_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-integrator/integrator_cp.c b/arch/arm/mach-integrator/integrator_cp.c
index cca02eb..b5fb71a 100644
--- a/arch/arm/mach-integrator/integrator_cp.c
+++ b/arch/arm/mach-integrator/integrator_cp.c
@@ -27,7 +27,6 @@
#include <linux/of_irq.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
-#include <linux/sys_soc.h>
#include <linux/sched_clock.h>
#include <asm/setup.h>
@@ -274,10 +273,6 @@ static const struct of_device_id intcp_syscon_match[] = {
static void __init intcp_init_of(void)
{
struct device_node *cpcon;
- struct device *parent;
- struct soc_device *soc_dev;
- struct soc_device_attribute *soc_dev_attr;
- u32 intcp_sc_id;
cpcon = of_find_matching_node(NULL, intcp_syscon_match);
if (!cpcon)
@@ -289,28 +284,6 @@ static void __init intcp_init_of(void)
of_platform_populate(NULL, of_default_bus_match_table,
intcp_auxdata_lookup, NULL);
-
- intcp_sc_id = readl(intcp_con_base);
-
- soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
- if (!soc_dev_attr)
- return;
-
- soc_dev_attr->soc_id = "XCV";
- soc_dev_attr->machine = "Integrator/CP";
- soc_dev_attr->family = "Integrator";
- soc_dev_attr->revision = kasprintf(GFP_KERNEL, "%c",
- 'A' + (intcp_sc_id & 0x0f));
-
- soc_dev = soc_device_register(soc_dev_attr);
- if (IS_ERR(soc_dev)) {
- kfree(soc_dev_attr->revision);
- kfree(soc_dev_attr);
- return;
- }
-
- parent = soc_device_to_device(soc_dev);
- integrator_init_sysfs(parent, intcp_sc_id);
}
static const char * intcp_dt_board_compat[] = {
@@ -324,6 +297,5 @@ DT_MACHINE_START(INTEGRATOR_CP_DT, "ARM Integrator/CP (Device Tree)")
.init_early = intcp_init_early,
.init_irq = intcp_init_irq_of,
.init_machine = intcp_init_of,
- .restart = integrator_restart,
.dt_compat = intcp_dt_board_compat,
MACHINE_END
diff --git a/arch/arm/mach-integrator/leds.c b/arch/arm/mach-integrator/leds.c
deleted file mode 100644
index f1dcb57..0000000
--- a/arch/arm/mach-integrator/leds.c
+++ /dev/null
@@ -1,124 +0,0 @@
-/*
- * Driver for the 4 user LEDs found on the Integrator AP/CP baseboard
- * Based on Versatile and RealView machine LED code
- *
- * License terms: GNU General Public License (GPL) version 2
- * Author: Bryan Wu <bryan.wu@canonical.com>
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/leds.h>
-
-#include "hardware.h"
-#include "cm.h"
-
-#if defined(CONFIG_NEW_LEDS) && defined(CONFIG_LEDS_CLASS)
-
-#define ALPHA_REG __io_address(INTEGRATOR_DBG_BASE)
-#define LEDREG (__io_address(INTEGRATOR_DBG_BASE) + INTEGRATOR_DBG_LEDS_OFFSET)
-
-struct integrator_led {
- struct led_classdev cdev;
- u8 mask;
-};
-
-/*
- * The triggers lines up below will only be used if the
- * LED triggers are compiled in.
- */
-static const struct {
- const char *name;
- const char *trigger;
-} integrator_leds[] = {
- { "integrator:green0", "heartbeat", },
- { "integrator:yellow", },
- { "integrator:red", },
- { "integrator:green1", },
- { "integrator:core_module", "cpu0", },
-};
-
-static void integrator_led_set(struct led_classdev *cdev,
- enum led_brightness b)
-{
- struct integrator_led *led = container_of(cdev,
- struct integrator_led, cdev);
- u32 reg = __raw_readl(LEDREG);
-
- if (b != LED_OFF)
- reg |= led->mask;
- else
- reg &= ~led->mask;
-
- while (__raw_readl(ALPHA_REG) & 1)
- cpu_relax();
-
- __raw_writel(reg, LEDREG);
-}
-
-static enum led_brightness integrator_led_get(struct led_classdev *cdev)
-{
- struct integrator_led *led = container_of(cdev,
- struct integrator_led, cdev);
- u32 reg = __raw_readl(LEDREG);
-
- return (reg & led->mask) ? LED_FULL : LED_OFF;
-}
-
-static void cm_led_set(struct led_classdev *cdev,
- enum led_brightness b)
-{
- if (b != LED_OFF)
- cm_control(CM_CTRL_LED, CM_CTRL_LED);
- else
- cm_control(CM_CTRL_LED, 0);
-}
-
-static enum led_brightness cm_led_get(struct led_classdev *cdev)
-{
- u32 reg = cm_get();
-
- return (reg & CM_CTRL_LED) ? LED_FULL : LED_OFF;
-}
-
-static int __init integrator_leds_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(integrator_leds); i++) {
- struct integrator_led *led;
-
- led = kzalloc(sizeof(*led), GFP_KERNEL);
- if (!led)
- break;
-
-
- led->cdev.name = integrator_leds[i].name;
-
- if (i == 4) { /* Setting for LED in core module */
- led->cdev.brightness_set = cm_led_set;
- led->cdev.brightness_get = cm_led_get;
- } else {
- led->cdev.brightness_set = integrator_led_set;
- led->cdev.brightness_get = integrator_led_get;
- }
-
- led->cdev.default_trigger = integrator_leds[i].trigger;
- led->mask = BIT(i);
-
- if (led_classdev_register(NULL, &led->cdev) < 0) {
- kfree(led);
- break;
- }
- }
-
- return 0;
-}
-
-/*
- * Since we may have triggers on any subsystem, defer registration
- * until after subsystem_init.
- */
-fs_initcall(integrator_leds_init);
-#endif
diff --git a/arch/arm/mach-iop13xx/msi.c b/arch/arm/mach-iop13xx/msi.c
index e7730cf..9f89e76 100644
--- a/arch/arm/mach-iop13xx/msi.c
+++ b/arch/arm/mach-iop13xx/msi.c
@@ -126,10 +126,10 @@ static void iop13xx_msi_nop(struct irq_data *d)
static struct irq_chip iop13xx_msi_chip = {
.name = "PCI-MSI",
.irq_ack = iop13xx_msi_nop,
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
@@ -153,7 +153,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
id = iop13xx_cpu_id();
msg.data = (id << IOP13XX_MU_MIMR_CORE_SELECT) | (irq & 0x7f);
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &iop13xx_msi_chip, handle_simple_irq);
return 0;
diff --git a/arch/arm/mach-ixp4xx/common.c b/arch/arm/mach-ixp4xx/common.c
index fc4b7b2..8537d4c 100644
--- a/arch/arm/mach-ixp4xx/common.c
+++ b/arch/arm/mach-ixp4xx/common.c
@@ -652,7 +652,7 @@ static void __iomem *ixp4xx_ioremap_caller(phys_addr_t addr, size_t size,
return (void __iomem *)addr;
}
-static void ixp4xx_iounmap(void __iomem *addr)
+static void ixp4xx_iounmap(volatile void __iomem *addr)
{
if (!is_pci_memory((__force u32)addr))
__iounmap(addr);
diff --git a/arch/arm/mach-ixp4xx/include/mach/io.h b/arch/arm/mach-ixp4xx/include/mach/io.h
index 7d11979..6a72286 100644
--- a/arch/arm/mach-ixp4xx/include/mach/io.h
+++ b/arch/arm/mach-ixp4xx/include/mach/io.h
@@ -58,6 +58,10 @@ static inline int is_pci_memory(u32 addr)
#define writew(v, p) __indirect_writew(v, p)
#define writel(v, p) __indirect_writel(v, p)
+#define writeb_relaxed(v, p) __indirect_writeb(v, p)
+#define writew_relaxed(v, p) __indirect_writew(v, p)
+#define writel_relaxed(v, p) __indirect_writel(v, p)
+
#define writesb(p, v, l) __indirect_writesb(p, v, l)
#define writesw(p, v, l) __indirect_writesw(p, v, l)
#define writesl(p, v, l) __indirect_writesl(p, v, l)
@@ -66,6 +70,10 @@ static inline int is_pci_memory(u32 addr)
#define readw(p) __indirect_readw(p)
#define readl(p) __indirect_readl(p)
+#define readb_relaxed(p) __indirect_readb(p)
+#define readw_relaxed(p) __indirect_readw(p)
+#define readl_relaxed(p) __indirect_readl(p)
+
#define readsb(p, v, l) __indirect_readsb(p, v, l)
#define readsw(p, v, l) __indirect_readsw(p, v, l)
#define readsl(p, v, l) __indirect_readsl(p, v, l)
@@ -99,7 +107,7 @@ static inline void __indirect_writew(u16 value, volatile void __iomem *p)
u32 n, byte_enables, data;
if (!is_pci_memory(addr)) {
- __raw_writew(value, addr);
+ __raw_writew(value, p);
return;
}
@@ -164,7 +172,7 @@ static inline unsigned short __indirect_readw(const volatile void __iomem *p)
u32 n, byte_enables, data;
if (!is_pci_memory(addr))
- return __raw_readw(addr);
+ return __raw_readw(p);
n = addr % 4;
byte_enables = (0xf & ~(BIT(n) | BIT(n+1))) << IXP4XX_PCI_NP_CBE_BESL;
@@ -226,6 +234,7 @@ static inline void __indirect_readsl(const volatile void __iomem *bus_addr,
* I/O functions.
*/
+#define outb outb
static inline void outb(u8 value, u32 addr)
{
u32 n, byte_enables, data;
@@ -235,12 +244,14 @@ static inline void outb(u8 value, u32 addr)
ixp4xx_pci_write(addr, byte_enables | NP_CMD_IOWRITE, data);
}
+#define outsb outsb
static inline void outsb(u32 io_addr, const u8 *vaddr, u32 count)
{
while (count--)
outb(*vaddr++, io_addr);
}
+#define outw outw
static inline void outw(u16 value, u32 addr)
{
u32 n, byte_enables, data;
@@ -250,23 +261,27 @@ static inline void outw(u16 value, u32 addr)
ixp4xx_pci_write(addr, byte_enables | NP_CMD_IOWRITE, data);
}
+#define outsw outsw
static inline void outsw(u32 io_addr, const u16 *vaddr, u32 count)
{
while (count--)
outw(cpu_to_le16(*vaddr++), io_addr);
}
+#define outl outl
static inline void outl(u32 value, u32 addr)
{
ixp4xx_pci_write(addr, NP_CMD_IOWRITE, value);
}
+#define outsl outsl
static inline void outsl(u32 io_addr, const u32 *vaddr, u32 count)
{
while (count--)
outl(cpu_to_le32(*vaddr++), io_addr);
}
+#define inb inb
static inline u8 inb(u32 addr)
{
u32 n, byte_enables, data;
@@ -278,12 +293,14 @@ static inline u8 inb(u32 addr)
return data >> (8*n);
}
+#define insb insb
static inline void insb(u32 io_addr, u8 *vaddr, u32 count)
{
while (count--)
*vaddr++ = inb(io_addr);
}
+#define inw inw
static inline u16 inw(u32 addr)
{
u32 n, byte_enables, data;
@@ -295,12 +312,14 @@ static inline u16 inw(u32 addr)
return data>>(8*n);
}
+#define insw insw
static inline void insw(u32 io_addr, u16 *vaddr, u32 count)
{
while (count--)
*vaddr++ = le16_to_cpu(inw(io_addr));
}
+#define inl inl
static inline u32 inl(u32 addr)
{
u32 data;
@@ -310,6 +329,7 @@ static inline u32 inl(u32 addr)
return data;
}
+#define insl insl
static inline void insl(u32 io_addr, u32 *vaddr, u32 count)
{
while (count--)
diff --git a/arch/arm/mach-keystone/Kconfig b/arch/arm/mach-keystone/Kconfig
index 98a156a..ea955f6db 100644
--- a/arch/arm/mach-keystone/Kconfig
+++ b/arch/arm/mach-keystone/Kconfig
@@ -9,6 +9,8 @@ config ARCH_KEYSTONE
select COMMON_CLK_KEYSTONE
select ARCH_SUPPORTS_BIG_ENDIAN
select ZONE_DMA if ARM_LPAE
+ select MIGHT_HAVE_PCI
+ select PCI_DOMAINS if PCI
help
Support for boards based on the Texas Instruments Keystone family of
SoCs.
diff --git a/arch/arm/mach-mediatek/Kconfig b/arch/arm/mach-mediatek/Kconfig
index 2c043a2..f73f588 100644
--- a/arch/arm/mach-mediatek/Kconfig
+++ b/arch/arm/mach-mediatek/Kconfig
@@ -1,6 +1,6 @@
config ARCH_MEDIATEK
- bool "Mediatek MT6589 SoC" if ARCH_MULTI_V7
+ bool "Mediatek MT65xx & MT81xx SoC" if ARCH_MULTI_V7
select ARM_GIC
select MTK_TIMER
help
- Support for Mediatek Cortex-A7 Quad-Core-SoC MT6589.
+ Support for Mediatek MT65xx & MT81xx SoCs
diff --git a/arch/arm/mach-mediatek/mediatek.c b/arch/arm/mach-mediatek/mediatek.c
index f2acf07..a954900 100644
--- a/arch/arm/mach-mediatek/mediatek.c
+++ b/arch/arm/mach-mediatek/mediatek.c
@@ -19,6 +19,9 @@
static const char * const mediatek_board_dt_compat[] = {
"mediatek,mt6589",
+ "mediatek,mt6592",
+ "mediatek,mt8127",
+ "mediatek,mt8135",
NULL,
};
diff --git a/arch/arm/mach-meson/Kconfig b/arch/arm/mach-meson/Kconfig
index 2c1154e..18301dc 100644
--- a/arch/arm/mach-meson/Kconfig
+++ b/arch/arm/mach-meson/Kconfig
@@ -2,6 +2,7 @@ menuconfig ARCH_MESON
bool "Amlogic Meson SoCs" if ARCH_MULTI_V7
select GENERIC_IRQ_CHIP
select ARM_GIC
+ select CACHE_L2X0
if ARCH_MESON
@@ -10,4 +11,9 @@ config MACH_MESON6
default ARCH_MESON
select MESON6_TIMER
+config MACH_MESON8
+ bool "Amlogic Meson8 SoCs support"
+ default ARCH_MESON
+ select MESON6_TIMER
+
endif
diff --git a/arch/arm/mach-meson/meson.c b/arch/arm/mach-meson/meson.c
index 5ee064f..5d6affe 100644
--- a/arch/arm/mach-meson/meson.c
+++ b/arch/arm/mach-meson/meson.c
@@ -16,12 +16,14 @@
#include <linux/of_platform.h>
#include <asm/mach/arch.h>
-static const char * const m6_common_board_compat[] = {
+static const char * const meson_common_board_compat[] = {
"amlogic,meson6",
+ "amlogic,meson8",
NULL,
};
-DT_MACHINE_START(AML8726_MX, "Amlogic Meson6 platform")
- .dt_compat = m6_common_board_compat,
+DT_MACHINE_START(MESON, "Amlogic Meson platform")
+ .dt_compat = meson_common_board_compat,
+ .l2c_aux_val = 0,
+ .l2c_aux_mask = ~0,
MACHINE_END
-
diff --git a/arch/arm/mach-mvebu/Makefile b/arch/arm/mach-mvebu/Makefile
index e24136b..b4f0149 100644
--- a/arch/arm/mach-mvebu/Makefile
+++ b/arch/arm/mach-mvebu/Makefile
@@ -7,7 +7,7 @@ CFLAGS_pmsu.o := -march=armv7-a
obj-$(CONFIG_MACH_MVEBU_ANY) += system-controller.o mvebu-soc-id.o
ifeq ($(CONFIG_MACH_MVEBU_V7),y)
-obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o
+obj-y += cpu-reset.o board-v7.o coherency.o coherency_ll.o pmsu.o pmsu_ll.o pm.o pm-board.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o platsmp-a9.o headsmp-a9.o
endif
diff --git a/arch/arm/mach-mvebu/armada-370-xp.h b/arch/arm/mach-mvebu/armada-370-xp.h
index 84cd90d..c55bbf8 100644
--- a/arch/arm/mach-mvebu/armada-370-xp.h
+++ b/arch/arm/mach-mvebu/armada-370-xp.h
@@ -16,14 +16,8 @@
#define __MACH_ARMADA_370_XP_H
#ifdef CONFIG_SMP
-#include <linux/cpumask.h>
-
-#define ARMADA_XP_MAX_CPUS 4
-
void armada_xp_secondary_startup(void);
extern struct smp_operations armada_xp_smp_ops;
#endif
-int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
-
#endif /* __MACH_ARMADA_370_XP_H */
diff --git a/arch/arm/mach-mvebu/board-v7.c b/arch/arm/mach-mvebu/board-v7.c
index d0d39f1..89a139e 100644
--- a/arch/arm/mach-mvebu/board-v7.c
+++ b/arch/arm/mach-mvebu/board-v7.c
@@ -16,10 +16,12 @@
#include <linux/init.h>
#include <linux/clk-provider.h>
#include <linux/of_address.h>
+#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/io.h>
#include <linux/clocksource.h>
#include <linux/dma-mapping.h>
+#include <linux/memblock.h>
#include <linux/mbus.h>
#include <linux/signal.h>
#include <linux/slab.h>
@@ -57,6 +59,54 @@ void __iomem *mvebu_get_scu_base(void)
}
/*
+ * When returning from suspend, the platform goes through the
+ * bootloader, which executes its DDR3 training code. This code has
+ * the unfortunate idea of using the first 10 KB of each DRAM bank to
+ * exercise the RAM and calculate the optimal timings. Therefore, this
+ * area of RAM is overwritten, and shouldn't be used by the kernel if
+ * suspend/resume is supported.
+ */
+
+#ifdef CONFIG_SUSPEND
+#define MVEBU_DDR_TRAINING_AREA_SZ (10 * SZ_1K)
+static int __init mvebu_scan_mem(unsigned long node, const char *uname,
+ int depth, void *data)
+{
+ const char *type = of_get_flat_dt_prop(node, "device_type", NULL);
+ const __be32 *reg, *endp;
+ int l;
+
+ if (type == NULL || strcmp(type, "memory"))
+ return 0;
+
+ reg = of_get_flat_dt_prop(node, "linux,usable-memory", &l);
+ if (reg == NULL)
+ reg = of_get_flat_dt_prop(node, "reg", &l);
+ if (reg == NULL)
+ return 0;
+
+ endp = reg + (l / sizeof(__be32));
+ while ((endp - reg) >= (dt_root_addr_cells + dt_root_size_cells)) {
+ u64 base, size;
+
+ base = dt_mem_next_cell(dt_root_addr_cells, &reg);
+ size = dt_mem_next_cell(dt_root_size_cells, &reg);
+
+ memblock_reserve(base, MVEBU_DDR_TRAINING_AREA_SZ);
+ }
+
+ return 0;
+}
+
+static void __init mvebu_memblock_reserve(void)
+{
+ of_scan_flat_dt(mvebu_scan_mem, NULL);
+}
+#else
+static void __init mvebu_memblock_reserve(void) {}
+#endif
+
+/*
* Early versions of Armada 375 SoC have a bug where the BootROM
* leaves an external data abort pending. The kernel is hit by this
* data abort as soon as it enters userspace, because it unmasks the
@@ -124,76 +174,12 @@ static void __init i2c_quirk(void)
return;
}
-#define A375_Z1_THERMAL_FIXUP_OFFSET 0xc
-
-static void __init thermal_quirk(void)
-{
- struct device_node *np;
- u32 dev, rev;
- int res;
-
- /*
- * The early SoC Z1 revision needs a quirk to be applied in order
- * for the thermal controller to work properly. This quirk breaks
- * the thermal support if applied on a SoC that doesn't need it,
- * so we enforce the SoC revision to be known.
- */
- res = mvebu_get_soc_id(&dev, &rev);
- if (res < 0 || (res == 0 && rev > ARMADA_375_Z1_REV))
- return;
-
- for_each_compatible_node(np, NULL, "marvell,armada375-thermal") {
- struct property *prop;
- __be32 newval, *newprop, *oldprop;
- int len;
-
- /*
- * The register offset is at a wrong location. This quirk
- * creates a new reg property as a clone of the previous
- * one and corrects the offset.
- */
- oldprop = (__be32 *)of_get_property(np, "reg", &len);
- if (!oldprop)
- continue;
-
- /* Create a duplicate of the 'reg' property */
- prop = kzalloc(sizeof(*prop), GFP_KERNEL);
- prop->length = len;
- prop->name = kstrdup("reg", GFP_KERNEL);
- prop->value = kzalloc(len, GFP_KERNEL);
- memcpy(prop->value, oldprop, len);
-
- /* Fixup the register offset of the second entry */
- oldprop += 2;
- newprop = (__be32 *)prop->value + 2;
- newval = cpu_to_be32(be32_to_cpu(*oldprop) -
- A375_Z1_THERMAL_FIXUP_OFFSET);
- *newprop = newval;
- of_update_property(np, prop);
-
- /*
- * The thermal controller needs some quirk too, so let's change
- * the compatible string to reflect this and allow the driver
- * the take the necessary action.
- */
- prop = kzalloc(sizeof(*prop), GFP_KERNEL);
- prop->name = kstrdup("compatible", GFP_KERNEL);
- prop->length = sizeof("marvell,armada375-z1-thermal");
- prop->value = kstrdup("marvell,armada375-z1-thermal",
- GFP_KERNEL);
- of_update_property(np, prop);
- }
- return;
-}
-
static void __init mvebu_dt_init(void)
{
if (of_machine_is_compatible("marvell,armadaxp"))
i2c_quirk();
- if (of_machine_is_compatible("marvell,a375-db")) {
+ if (of_machine_is_compatible("marvell,a375-db"))
external_abort_quirk();
- thermal_quirk();
- }
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
@@ -206,10 +192,16 @@ static const char * const armada_370_xp_dt_compat[] = {
DT_MACHINE_START(ARMADA_370_XP_DT, "Marvell Armada 370/XP (Device Tree)")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
+/*
+ * The following field (.smp) is still needed to ensure backward
+ * compatibility with old Device Trees that were not specifying the
+ * cpus enable-method property.
+ */
.smp = smp_ops(armada_xp_smp_ops),
.init_machine = mvebu_dt_init,
.init_irq = mvebu_init_irq,
.restart = mvebu_restart,
+ .reserve = mvebu_memblock_reserve,
.dt_compat = armada_370_xp_dt_compat,
MACHINE_END
diff --git a/arch/arm/mach-mvebu/coherency.c b/arch/arm/mach-mvebu/coherency.c
index 044b511..3585cb3 100644
--- a/arch/arm/mach-mvebu/coherency.c
+++ b/arch/arm/mach-mvebu/coherency.c
@@ -1,5 +1,6 @@
/*
- * Coherency fabric (Aurora) support for Armada 370 and XP platforms.
+ * Coherency fabric (Aurora) support for Armada 370, 375, 38x and XP
+ * platforms.
*
* Copyright (C) 2012 Marvell
*
@@ -11,7 +12,7 @@
* License version 2. This program is licensed "as is" without any
* warranty of any kind, whether express or implied.
*
- * The Armada 370 and Armada XP SOCs have a coherency fabric which is
+ * The Armada 370, 375, 38x and XP SOCs have a coherency fabric which is
* responsible for ensuring hardware coherency between all CPUs and between
* CPUs and I/O masters. This file initializes the coherency fabric and
* supplies basic routines for configuring and controlling hardware coherency
@@ -28,12 +29,10 @@
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/mbus.h>
-#include <linux/clk.h>
#include <linux/pci.h>
#include <asm/smp_plat.h>
#include <asm/cacheflush.h>
#include <asm/mach/map.h>
-#include "armada-370-xp.h"
#include "coherency.h"
#include "mvebu-soc-id.h"
@@ -42,8 +41,6 @@ void __iomem *coherency_base;
static void __iomem *coherency_cpu_base;
/* Coherency fabric registers */
-#define COHERENCY_FABRIC_CFG_OFFSET 0x4
-
#define IO_SYNC_BARRIER_CTL_OFFSET 0x0
enum {
@@ -79,157 +76,8 @@ int set_cpu_coherent(void)
return ll_enable_coherency();
}
-/*
- * The below code implements the I/O coherency workaround on Armada
- * 375. This workaround consists in using the two channels of the
- * first XOR engine to trigger a XOR transaction that serves as the
- * I/O coherency barrier.
- */
-
-static void __iomem *xor_base, *xor_high_base;
-static dma_addr_t coherency_wa_buf_phys[CONFIG_NR_CPUS];
-static void *coherency_wa_buf[CONFIG_NR_CPUS];
-static bool coherency_wa_enabled;
-
-#define XOR_CONFIG(chan) (0x10 + (chan * 4))
-#define XOR_ACTIVATION(chan) (0x20 + (chan * 4))
-#define WINDOW_BAR_ENABLE(chan) (0x240 + ((chan) << 2))
-#define WINDOW_BASE(w) (0x250 + ((w) << 2))
-#define WINDOW_SIZE(w) (0x270 + ((w) << 2))
-#define WINDOW_REMAP_HIGH(w) (0x290 + ((w) << 2))
-#define WINDOW_OVERRIDE_CTRL(chan) (0x2A0 + ((chan) << 2))
-#define XOR_DEST_POINTER(chan) (0x2B0 + (chan * 4))
-#define XOR_BLOCK_SIZE(chan) (0x2C0 + (chan * 4))
-#define XOR_INIT_VALUE_LOW 0x2E0
-#define XOR_INIT_VALUE_HIGH 0x2E4
-
-static inline void mvebu_hwcc_armada375_sync_io_barrier_wa(void)
-{
- int idx = smp_processor_id();
-
- /* Write '1' to the first word of the buffer */
- writel(0x1, coherency_wa_buf[idx]);
-
- /* Wait until the engine is idle */
- while ((readl(xor_base + XOR_ACTIVATION(idx)) >> 4) & 0x3)
- ;
-
- dmb();
-
- /* Trigger channel */
- writel(0x1, xor_base + XOR_ACTIVATION(idx));
-
- /* Poll the data until it is cleared by the XOR transaction */
- while (readl(coherency_wa_buf[idx]))
- ;
-}
-
-static void __init armada_375_coherency_init_wa(void)
-{
- const struct mbus_dram_target_info *dram;
- struct device_node *xor_node;
- struct property *xor_status;
- struct clk *xor_clk;
- u32 win_enable = 0;
- int i;
-
- pr_warn("enabling coherency workaround for Armada 375 Z1, one XOR engine disabled\n");
-
- /*
- * Since the workaround uses one XOR engine, we grab a
- * reference to its Device Tree node first.
- */
- xor_node = of_find_compatible_node(NULL, NULL, "marvell,orion-xor");
- BUG_ON(!xor_node);
-
- /*
- * Then we mark it as disabled so that the real XOR driver
- * will not use it.
- */
- xor_status = kzalloc(sizeof(struct property), GFP_KERNEL);
- BUG_ON(!xor_status);
-
- xor_status->value = kstrdup("disabled", GFP_KERNEL);
- BUG_ON(!xor_status->value);
-
- xor_status->length = 8;
- xor_status->name = kstrdup("status", GFP_KERNEL);
- BUG_ON(!xor_status->name);
-
- of_update_property(xor_node, xor_status);
-
- /*
- * And we remap the registers, get the clock, and do the
- * initial configuration of the XOR engine.
- */
- xor_base = of_iomap(xor_node, 0);
- xor_high_base = of_iomap(xor_node, 1);
-
- xor_clk = of_clk_get_by_name(xor_node, NULL);
- BUG_ON(!xor_clk);
-
- clk_prepare_enable(xor_clk);
-
- dram = mv_mbus_dram_info();
-
- for (i = 0; i < 8; i++) {
- writel(0, xor_base + WINDOW_BASE(i));
- writel(0, xor_base + WINDOW_SIZE(i));
- if (i < 4)
- writel(0, xor_base + WINDOW_REMAP_HIGH(i));
- }
-
- for (i = 0; i < dram->num_cs; i++) {
- const struct mbus_dram_window *cs = dram->cs + i;
- writel((cs->base & 0xffff0000) |
- (cs->mbus_attr << 8) |
- dram->mbus_dram_target_id, xor_base + WINDOW_BASE(i));
- writel((cs->size - 1) & 0xffff0000, xor_base + WINDOW_SIZE(i));
-
- win_enable |= (1 << i);
- win_enable |= 3 << (16 + (2 * i));
- }
-
- writel(win_enable, xor_base + WINDOW_BAR_ENABLE(0));
- writel(win_enable, xor_base + WINDOW_BAR_ENABLE(1));
- writel(0, xor_base + WINDOW_OVERRIDE_CTRL(0));
- writel(0, xor_base + WINDOW_OVERRIDE_CTRL(1));
-
- for (i = 0; i < CONFIG_NR_CPUS; i++) {
- coherency_wa_buf[i] = kzalloc(PAGE_SIZE, GFP_KERNEL);
- BUG_ON(!coherency_wa_buf[i]);
-
- /*
- * We can't use the DMA mapping API, since we don't
- * have a valid 'struct device' pointer
- */
- coherency_wa_buf_phys[i] =
- virt_to_phys(coherency_wa_buf[i]);
- BUG_ON(!coherency_wa_buf_phys[i]);
-
- /*
- * Configure the XOR engine for memset operation, with
- * a 128 bytes block size
- */
- writel(0x444, xor_base + XOR_CONFIG(i));
- writel(128, xor_base + XOR_BLOCK_SIZE(i));
- writel(coherency_wa_buf_phys[i],
- xor_base + XOR_DEST_POINTER(i));
- }
-
- writel(0x0, xor_base + XOR_INIT_VALUE_LOW);
- writel(0x0, xor_base + XOR_INIT_VALUE_HIGH);
-
- coherency_wa_enabled = true;
-}
-
static inline void mvebu_hwcc_sync_io_barrier(void)
{
- if (coherency_wa_enabled) {
- mvebu_hwcc_armada375_sync_io_barrier_wa();
- return;
- }
-
writel(0x1, coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET);
while (readl(coherency_cpu_base + IO_SYNC_BARRIER_CTL_OFFSET) & 0x1);
}
@@ -361,25 +209,41 @@ static int coherency_type(void)
{
struct device_node *np;
const struct of_device_id *match;
+ int type;
- np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
- if (np) {
- int type = (int) match->data;
+ /*
+ * The coherency fabric is needed:
+ * - For coherency between processors on Armada XP, so only
+ * when SMP is enabled.
+ * - For coherency between the processor and I/O devices, but
+ * this coherency requires many pre-requisites (write
+ * allocate cache policy, shareable pages, SMP bit set) that
+ * are only meant in SMP situations.
+ *
+ * Note that this means that on Armada 370, there is currently
+ * no way to use hardware I/O coherency, because even when
+ * CONFIG_SMP is enabled, is_smp() returns false due to the
+ * Armada 370 being a single-core processor. To lift this
+ * limitation, we would have to find a way to make the cache
+ * policy set to write-allocate (on all Armada SoCs), and to
+ * set the shareable attribute in page tables (on all Armada
+ * SoCs except the Armada 370). Unfortunately, such decisions
+ * are taken very early in the kernel boot process, at a point
+ * where we don't know yet on which SoC we are running.
- /* Armada 370/XP coherency works in both UP and SMP */
- if (type == COHERENCY_FABRIC_TYPE_ARMADA_370_XP)
- return type;
+ */
+ if (!is_smp())
+ return COHERENCY_FABRIC_TYPE_NONE;
- /* Armada 375 coherency works only on SMP */
- else if (type == COHERENCY_FABRIC_TYPE_ARMADA_375 && is_smp())
- return type;
+ np = of_find_matching_node_and_match(NULL, of_coherency_table, &match);
+ if (!np)
+ return COHERENCY_FABRIC_TYPE_NONE;
- /* Armada 380 coherency works only on SMP */
- else if (type == COHERENCY_FABRIC_TYPE_ARMADA_380 && is_smp())
- return type;
- }
+ type = (int) match->data;
- return COHERENCY_FABRIC_TYPE_NONE;
+ of_node_put(np);
+
+ return type;
}
int coherency_available(void)
@@ -407,22 +271,9 @@ int __init coherency_init(void)
static int __init coherency_late_init(void)
{
- int type = coherency_type();
-
- if (type == COHERENCY_FABRIC_TYPE_NONE)
- return 0;
-
- if (type == COHERENCY_FABRIC_TYPE_ARMADA_375) {
- u32 dev, rev;
-
- if (mvebu_get_soc_id(&dev, &rev) == 0 &&
- rev == ARMADA_375_Z1_REV)
- armada_375_coherency_init_wa();
- }
-
- bus_register_notifier(&platform_bus_type,
- &mvebu_hwcc_nb);
-
+ if (coherency_available())
+ bus_register_notifier(&platform_bus_type,
+ &mvebu_hwcc_nb);
return 0;
}
diff --git a/arch/arm/mach-mvebu/coherency_ll.S b/arch/arm/mach-mvebu/coherency_ll.S
index f5d881b..8b2fbc8 100644
--- a/arch/arm/mach-mvebu/coherency_ll.S
+++ b/arch/arm/mach-mvebu/coherency_ll.S
@@ -24,7 +24,10 @@
#include <asm/cp15.h>
.text
-/* Returns the coherency base address in r1 (r0 is untouched) */
+/*
+ * Returns the coherency base address in r1 (r0 is untouched), or 0 if
+ * the coherency fabric is not enabled.
+ */
ENTRY(ll_get_coherency_base)
mrc p15, 0, r1, c1, c0, 0
tst r1, #CR_M @ Check MMU bit enabled
@@ -32,8 +35,13 @@ ENTRY(ll_get_coherency_base)
/*
* MMU is disabled, use the physical address of the coherency
- * base address.
+ * base address. However, if the coherency fabric isn't mapped
+ * (i.e its virtual address is zero), it means coherency is
+ * not enabled, so we return 0.
*/
+ ldr r1, =coherency_base
+ cmp r1, #0
+ beq 2f
adr r1, 3f
ldr r3, [r1]
ldr r1, [r1, r3]
@@ -85,6 +93,9 @@ ENTRY(ll_add_cpu_to_smp_group)
*/
mov r0, lr
bl ll_get_coherency_base
+ /* Bail out if the coherency is not enabled */
+ cmp r1, #0
+ reteq r0
bl ll_get_coherency_cpumask
mov lr, r0
add r0, r1, #ARMADA_XP_CFB_CFG_REG_OFFSET
@@ -107,6 +118,9 @@ ENTRY(ll_enable_coherency)
*/
mov r0, lr
bl ll_get_coherency_base
+ /* Bail out if the coherency is not enabled */
+ cmp r1, #0
+ reteq r0
bl ll_get_coherency_cpumask
mov lr, r0
add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
@@ -131,6 +145,9 @@ ENTRY(ll_disable_coherency)
*/
mov r0, lr
bl ll_get_coherency_base
+ /* Bail out if the coherency is not enabled */
+ cmp r1, #0
+ reteq r0
bl ll_get_coherency_cpumask
mov lr, r0
add r0, r1, #ARMADA_XP_CFB_CTL_REG_OFFSET
diff --git a/arch/arm/mach-mvebu/common.h b/arch/arm/mach-mvebu/common.h
index 3ccb40c..3e0aca1 100644
--- a/arch/arm/mach-mvebu/common.h
+++ b/arch/arm/mach-mvebu/common.h
@@ -25,4 +25,6 @@ int mvebu_system_controller_get_soc_id(u32 *dev, u32 *rev);
void __iomem *mvebu_get_scu_base(void);
+int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd));
+
#endif
diff --git a/arch/arm/mach-mvebu/cpu-reset.c b/arch/arm/mach-mvebu/cpu-reset.c
index 60fb537..4a2cadd 100644
--- a/arch/arm/mach-mvebu/cpu-reset.c
+++ b/arch/arm/mach-mvebu/cpu-reset.c
@@ -15,7 +15,6 @@
#include <linux/of_address.h>
#include <linux/io.h>
#include <linux/resource.h>
-#include "armada-370-xp.h"
static void __iomem *cpu_reset_base;
static size_t cpu_reset_size;
diff --git a/arch/arm/mach-mvebu/headsmp-a9.S b/arch/arm/mach-mvebu/headsmp-a9.S
index be51c99..08d5ed4 100644
--- a/arch/arm/mach-mvebu/headsmp-a9.S
+++ b/arch/arm/mach-mvebu/headsmp-a9.S
@@ -22,5 +22,6 @@
ENTRY(mvebu_cortex_a9_secondary_startup)
ARM_BE8(setend be)
bl v7_invalidate_l1
+ bl armada_38x_scu_power_up
b secondary_startup
ENDPROC(mvebu_cortex_a9_secondary_startup)
diff --git a/arch/arm/mach-mvebu/platsmp-a9.c b/arch/arm/mach-mvebu/platsmp-a9.c
index 47a71a9..2ec1a42 100644
--- a/arch/arm/mach-mvebu/platsmp-a9.c
+++ b/arch/arm/mach-mvebu/platsmp-a9.c
@@ -43,21 +43,70 @@ static int __cpuinit mvebu_cortex_a9_boot_secondary(unsigned int cpu,
else
mvebu_pmsu_set_cpu_boot_addr(hw_cpu, mvebu_cortex_a9_secondary_startup);
smp_wmb();
+
+ /*
+ * Doing this before deasserting the CPUs is needed to wake up CPUs
+ * in the offline state after using CPU hotplug.
+ */
+ arch_send_wakeup_ipi_mask(cpumask_of(cpu));
+
ret = mvebu_cpu_reset_deassert(hw_cpu);
if (ret) {
pr_err("Could not start the secondary CPU: %d\n", ret);
return ret;
}
- arch_send_wakeup_ipi_mask(cpumask_of(cpu));
return 0;
}
+/*
+ * When a CPU is brought back online, either through CPU hotplug, or
+ * because of the boot of a kexec'ed kernel, the PMSU configuration
+ * for this CPU might be in the deep idle state, preventing this CPU
+ * from receiving interrupts. Here, we therefore take out the current
+ * CPU from this state, which was entered by armada_38x_cpu_die()
+ * below.
+ */
+static void armada_38x_secondary_init(unsigned int cpu)
+{
+ mvebu_v7_pmsu_idle_exit();
+}
+
+#ifdef CONFIG_HOTPLUG_CPU
+static void armada_38x_cpu_die(unsigned int cpu)
+{
+ /*
+ * CPU hotplug is implemented by putting offline CPUs into the
+ * deep idle sleep state.
+ */
+ armada_38x_do_cpu_suspend(true);
+}
+
+/*
+ * We need a dummy function, so that platform_can_cpu_hotplug() knows
+ * we support CPU hotplug. However, the function does not need to do
+ * anything, because CPUs going offline can enter the deep idle state
+ * by themselves, without any help from a still alive CPU.
+ */
+static int armada_38x_cpu_kill(unsigned int cpu)
+{
+ return 1;
+}
+#endif
static struct smp_operations mvebu_cortex_a9_smp_ops __initdata = {
.smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
};
+static struct smp_operations armada_38x_smp_ops __initdata = {
+ .smp_boot_secondary = mvebu_cortex_a9_boot_secondary,
+ .smp_secondary_init = armada_38x_secondary_init,
+#ifdef CONFIG_HOTPLUG_CPU
+ .cpu_die = armada_38x_cpu_die,
+ .cpu_kill = armada_38x_cpu_kill,
+#endif
+};
+
CPU_METHOD_OF_DECLARE(mvebu_armada_375_smp, "marvell,armada-375-smp",
&mvebu_cortex_a9_smp_ops);
CPU_METHOD_OF_DECLARE(mvebu_armada_380_smp, "marvell,armada-380-smp",
- &mvebu_cortex_a9_smp_ops);
+ &armada_38x_smp_ops);
diff --git a/arch/arm/mach-mvebu/platsmp.c b/arch/arm/mach-mvebu/platsmp.c
index 895dc37..58cc8c1 100644
--- a/arch/arm/mach-mvebu/platsmp.c
+++ b/arch/arm/mach-mvebu/platsmp.c
@@ -30,10 +30,12 @@
#include "pmsu.h"
#include "coherency.h"
+#define ARMADA_XP_MAX_CPUS 4
+
#define AXP_BOOTROM_BASE 0xfff00000
#define AXP_BOOTROM_SIZE 0x100000
-static struct clk *__init get_cpu_clk(int cpu)
+static struct clk *get_cpu_clk(int cpu)
{
struct clk *cpu_clk;
struct device_node *np = of_get_cpu_node(cpu, NULL);
@@ -46,29 +48,28 @@ static struct clk *__init get_cpu_clk(int cpu)
return cpu_clk;
}
-static void __init set_secondary_cpus_clock(void)
+static void set_secondary_cpu_clock(unsigned int cpu)
{
- int thiscpu, cpu;
+ int thiscpu;
unsigned long rate;
struct clk *cpu_clk;
- thiscpu = smp_processor_id();
+ thiscpu = get_cpu();
+
cpu_clk = get_cpu_clk(thiscpu);
if (!cpu_clk)
- return;
+ goto out;
clk_prepare_enable(cpu_clk);
rate = clk_get_rate(cpu_clk);
- /* set all the other CPU clk to the same rate than the boot CPU */
- for_each_possible_cpu(cpu) {
- if (cpu == thiscpu)
- continue;
- cpu_clk = get_cpu_clk(cpu);
- if (!cpu_clk)
- return;
- clk_set_rate(cpu_clk, rate);
- clk_prepare_enable(cpu_clk);
- }
+ cpu_clk = get_cpu_clk(cpu);
+ if (!cpu_clk)
+ goto out;
+ clk_set_rate(cpu_clk, rate);
+ clk_prepare_enable(cpu_clk);
+
+out:
+ put_cpu();
}
static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
@@ -78,6 +79,7 @@ static int armada_xp_boot_secondary(unsigned int cpu, struct task_struct *idle)
pr_info("Booting CPU %d\n", cpu);
hw_cpu = cpu_logical_map(cpu);
+ set_secondary_cpu_clock(hw_cpu);
mvebu_pmsu_set_cpu_boot_addr(hw_cpu, armada_xp_secondary_startup);
/*
@@ -126,7 +128,6 @@ static void __init armada_xp_smp_prepare_cpus(unsigned int max_cpus)
struct resource res;
int err;
- set_secondary_cpus_clock();
flush_cache_all();
set_cpu_coherent();
diff --git a/arch/arm/mach-mvebu/pm-board.c b/arch/arm/mach-mvebu/pm-board.c
new file mode 100644
index 0000000..6dfd4ab
--- /dev/null
+++ b/arch/arm/mach-mvebu/pm-board.c
@@ -0,0 +1,141 @@
+/*
+ * Board-level suspend/resume support.
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_gpio.h>
+#include <linux/slab.h>
+#include "common.h"
+
+#define ARMADA_XP_GP_PIC_NR_GPIOS 3
+
+static void __iomem *gpio_ctrl;
+static int pic_gpios[ARMADA_XP_GP_PIC_NR_GPIOS];
+static int pic_raw_gpios[ARMADA_XP_GP_PIC_NR_GPIOS];
+
+static void mvebu_armada_xp_gp_pm_enter(void __iomem *sdram_reg, u32 srcmd)
+{
+ u32 reg, ackcmd;
+ int i;
+
+ /* Put 001 as value on the GPIOs */
+ reg = readl(gpio_ctrl);
+ for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++)
+ reg &= ~BIT(pic_raw_gpios[i]);
+ reg |= BIT(pic_raw_gpios[0]);
+ writel(reg, gpio_ctrl);
+
+ /* Prepare writing 111 to the GPIOs */
+ ackcmd = readl(gpio_ctrl);
+ for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++)
+ ackcmd |= BIT(pic_raw_gpios[i]);
+
+ /*
+ * Wait a while, the PIC needs quite a bit of time between the
+ * two GPIO commands.
+ */
+ mdelay(3000);
+
+ asm volatile (
+ /* Align to a cache line */
+ ".balign 32\n\t"
+
+ /* Enter self refresh */
+ "str %[srcmd], [%[sdram_reg]]\n\t"
+
+ /*
+ * Wait 100 cycles for DDR to enter self refresh, by
+ * doing 50 times two instructions.
+ */
+ "mov r1, #50\n\t"
+ "1: subs r1, r1, #1\n\t"
+ "bne 1b\n\t"
+
+ /* Issue the command ACK */
+ "str %[ackcmd], [%[gpio_ctrl]]\n\t"
+
+ /* Trap the processor */
+ "b .\n\t"
+ : : [srcmd] "r" (srcmd), [sdram_reg] "r" (sdram_reg),
+ [ackcmd] "r" (ackcmd), [gpio_ctrl] "r" (gpio_ctrl) : "r1");
+}
+
+static int mvebu_armada_xp_gp_pm_init(void)
+{
+ struct device_node *np;
+ struct device_node *gpio_ctrl_np;
+ int ret = 0, i;
+
+ if (!of_machine_is_compatible("marvell,axp-gp"))
+ return -ENODEV;
+
+ np = of_find_node_by_name(NULL, "pm_pic");
+ if (!np)
+ return -ENODEV;
+
+ for (i = 0; i < ARMADA_XP_GP_PIC_NR_GPIOS; i++) {
+ char *name;
+ struct of_phandle_args args;
+
+ pic_gpios[i] = of_get_named_gpio(np, "ctrl-gpios", i);
+ if (pic_gpios[i] < 0) {
+ ret = -ENODEV;
+ goto out;
+ }
+
+ name = kasprintf(GFP_KERNEL, "pic-pin%d", i);
+ if (!name) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ ret = gpio_request(pic_gpios[i], name);
+ if (ret < 0) {
+ kfree(name);
+ goto out;
+ }
+
+ ret = gpio_direction_output(pic_gpios[i], 0);
+ if (ret < 0) {
+ gpio_free(pic_gpios[i]);
+ kfree(name);
+ goto out;
+ }
+
+ ret = of_parse_phandle_with_fixed_args(np, "ctrl-gpios", 2,
+ i, &args);
+ if (ret < 0) {
+ gpio_free(pic_gpios[i]);
+ kfree(name);
+ goto out;
+ }
+
+ gpio_ctrl_np = args.np;
+ pic_raw_gpios[i] = args.args[0];
+ }
+
+ gpio_ctrl = of_iomap(gpio_ctrl_np, 0);
+ if (!gpio_ctrl)
+ return -ENOMEM;
+
+ mvebu_pm_init(mvebu_armada_xp_gp_pm_enter);
+
+out:
+ of_node_put(np);
+ return ret;
+}
+
+late_initcall(mvebu_armada_xp_gp_pm_init);
diff --git a/arch/arm/mach-mvebu/pm.c b/arch/arm/mach-mvebu/pm.c
new file mode 100644
index 0000000..6573a8f
--- /dev/null
+++ b/arch/arm/mach-mvebu/pm.c
@@ -0,0 +1,218 @@
+/*
+ * Suspend/resume support. Currently supporting Armada XP only.
+ *
+ * Copyright (C) 2014 Marvell
+ *
+ * Thomas Petazzoni <thomas.petazzoni@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/cpu_pm.h>
+#include <linux/delay.h>
+#include <linux/gpio.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/mbus.h>
+#include <linux/of_address.h>
+#include <linux/suspend.h>
+#include <asm/cacheflush.h>
+#include <asm/outercache.h>
+#include <asm/suspend.h>
+
+#include "coherency.h"
+#include "pmsu.h"
+
+#define SDRAM_CONFIG_OFFS 0x0
+#define SDRAM_CONFIG_SR_MODE_BIT BIT(24)
+#define SDRAM_OPERATION_OFFS 0x18
+#define SDRAM_OPERATION_SELF_REFRESH 0x7
+#define SDRAM_DLB_EVICTION_OFFS 0x30c
+#define SDRAM_DLB_EVICTION_THRESHOLD_MASK 0xff
+
+static void (*mvebu_board_pm_enter)(void __iomem *sdram_reg, u32 srcmd);
+static void __iomem *sdram_ctrl;
+
+static int mvebu_pm_powerdown(unsigned long data)
+{
+ u32 reg, srcmd;
+
+ flush_cache_all();
+ outer_flush_all();
+
+ /*
+ * Issue a Data Synchronization Barrier instruction to ensure
+ * that all state saving has been completed.
+ */
+ dsb();
+
+ /* Flush the DLB and wait ~7 usec */
+ reg = readl(sdram_ctrl + SDRAM_DLB_EVICTION_OFFS);
+ reg &= ~SDRAM_DLB_EVICTION_THRESHOLD_MASK;
+ writel(reg, sdram_ctrl + SDRAM_DLB_EVICTION_OFFS);
+
+ udelay(7);
+
+ /* Set DRAM in battery backup mode */
+ reg = readl(sdram_ctrl + SDRAM_CONFIG_OFFS);
+ reg &= ~SDRAM_CONFIG_SR_MODE_BIT;
+ writel(reg, sdram_ctrl + SDRAM_CONFIG_OFFS);
+
+ /* Prepare to go to self-refresh */
+
+ srcmd = readl(sdram_ctrl + SDRAM_OPERATION_OFFS);
+ srcmd &= ~0x1F;
+ srcmd |= SDRAM_OPERATION_SELF_REFRESH;
+
+ mvebu_board_pm_enter(sdram_ctrl + SDRAM_OPERATION_OFFS, srcmd);
+
+ return 0;
+}
+
+#define BOOT_INFO_ADDR 0x3000
+#define BOOT_MAGIC_WORD 0xdeadb002
+#define BOOT_MAGIC_LIST_END 0xffffffff
+
+/*
+ * Those registers are accessed before switching the internal register
+ * base, which is why we hardcode the 0xd0000000 base address, the one
+ * used by the SoC out of reset.
+ */
+#define MBUS_WINDOW_12_CTRL 0xd00200b0
+#define MBUS_INTERNAL_REG_ADDRESS 0xd0020080
+
+#define SDRAM_WIN_BASE_REG(x) (0x20180 + (0x8*x))
+#define SDRAM_WIN_CTRL_REG(x) (0x20184 + (0x8*x))
+
+static phys_addr_t mvebu_internal_reg_base(void)
+{
+ struct device_node *np;
+ __be32 in_addr[2];
+
+ np = of_find_node_by_name(NULL, "internal-regs");
+ BUG_ON(!np);
+
+ /*
+ * Ask the DT what is the internal register address on this
+ * platform. In the mvebu-mbus DT binding, 0xf0010000
+ * corresponds to the internal register window.
+ */
+ in_addr[0] = cpu_to_be32(0xf0010000);
+ in_addr[1] = 0x0;
+
+ return of_translate_address(np, in_addr);
+}
+
+static void mvebu_pm_store_bootinfo(void)
+{
+ u32 *store_addr;
+ phys_addr_t resume_pc;
+
+ store_addr = phys_to_virt(BOOT_INFO_ADDR);
+ resume_pc = virt_to_phys(armada_370_xp_cpu_resume);
+
+ /*
+ * The bootloader expects the first two words to be a magic
+ * value (BOOT_MAGIC_WORD), followed by the address of the
+ * resume code to jump to. Then, it expects a sequence of
+ * (address, value) pairs, which can be used to restore the
+ * value of certain registers. This sequence must end with the
+ * BOOT_MAGIC_LIST_END magic value.
+ */
+
+ writel(BOOT_MAGIC_WORD, store_addr++);
+ writel(resume_pc, store_addr++);
+
+ /*
+ * Some platforms remap their internal register base address
+ * to 0xf1000000. However, out of reset, window 12 starts at
+ * 0xf0000000 and ends at 0xf7ffffff, which would overlap with
+ * the internal registers. Therefore, disable window 12.
+ */
+ writel(MBUS_WINDOW_12_CTRL, store_addr++);
+ writel(0x0, store_addr++);
+
+ /*
+ * Set the internal register base address to the value
+ * expected by Linux, as read from the Device Tree.
+ */
+ writel(MBUS_INTERNAL_REG_ADDRESS, store_addr++);
+ writel(mvebu_internal_reg_base(), store_addr++);
+
+ /*
+ * Ask the mvebu-mbus driver to store the SDRAM window
+ * configuration, which has to be restored by the bootloader
+ * before re-entering the kernel on resume.
+ */
+ store_addr += mvebu_mbus_save_cpu_target(store_addr);
+
+ writel(BOOT_MAGIC_LIST_END, store_addr);
+}
+
+static int mvebu_pm_enter(suspend_state_t state)
+{
+ if (state != PM_SUSPEND_MEM)
+ return -EINVAL;
+
+ cpu_pm_enter();
+
+ mvebu_pm_store_bootinfo();
+ cpu_suspend(0, mvebu_pm_powerdown);
+
+ outer_resume();
+
+ mvebu_v7_pmsu_idle_exit();
+
+ set_cpu_coherent();
+
+ cpu_pm_exit();
+
+ return 0;
+}
+
+static const struct platform_suspend_ops mvebu_pm_ops = {
+ .enter = mvebu_pm_enter,
+ .valid = suspend_valid_only_mem,
+};
+
+int mvebu_pm_init(void (*board_pm_enter)(void __iomem *sdram_reg, u32 srcmd))
+{
+ struct device_node *np;
+ struct resource res;
+
+ if (!of_machine_is_compatible("marvell,armadaxp"))
+ return -ENODEV;
+
+ np = of_find_compatible_node(NULL, NULL,
+ "marvell,armada-xp-sdram-controller");
+ if (!np)
+ return -ENODEV;
+
+ if (of_address_to_resource(np, 0, &res)) {
+ of_node_put(np);
+ return -ENODEV;
+ }
+
+ if (!request_mem_region(res.start, resource_size(&res),
+ np->full_name)) {
+ of_node_put(np);
+ return -EBUSY;
+ }
+
+ sdram_ctrl = ioremap(res.start, resource_size(&res));
+ if (!sdram_ctrl) {
+ release_mem_region(res.start, resource_size(&res));
+ of_node_put(np);
+ return -ENOMEM;
+ }
+
+ of_node_put(np);
+
+ mvebu_board_pm_enter = board_pm_enter;
+
+ suspend_set_ops(&mvebu_pm_ops);
+
+ return 0;
+}
diff --git a/arch/arm/mach-mvebu/pmsu.c b/arch/arm/mach-mvebu/pmsu.c
index bbd8664..d8ab605 100644
--- a/arch/arm/mach-mvebu/pmsu.c
+++ b/arch/arm/mach-mvebu/pmsu.c
@@ -20,6 +20,7 @@
#include <linux/clk.h>
#include <linux/cpu_pm.h>
+#include <linux/cpufreq-dt.h>
#include <linux/delay.h>
#include <linux/init.h>
#include <linux/io.h>
@@ -39,7 +40,6 @@
#include <asm/suspend.h>
#include <asm/tlbflush.h>
#include "common.h"
-#include "armada-370-xp.h"
#define PMSU_BASE_OFFSET 0x100
@@ -312,7 +312,7 @@ static int armada_370_xp_cpu_suspend(unsigned long deepidle)
return cpu_suspend(deepidle, armada_370_xp_pmsu_idle_enter);
}
-static int armada_38x_do_cpu_suspend(unsigned long deepidle)
+int armada_38x_do_cpu_suspend(unsigned long deepidle)
{
unsigned long flags = 0;
@@ -572,6 +572,10 @@ int mvebu_pmsu_dfs_request(int cpu)
return 0;
}
+struct cpufreq_dt_platform_data cpufreq_dt_pd = {
+ .independent_clocks = true,
+};
+
static int __init armada_xp_pmsu_cpufreq_init(void)
{
struct device_node *np;
@@ -644,7 +648,8 @@ static int __init armada_xp_pmsu_cpufreq_init(void)
}
}
- platform_device_register_simple("cpufreq-dt", -1, NULL, 0);
+ platform_device_register_data(NULL, "cpufreq-dt", -1,
+ &cpufreq_dt_pd, sizeof(cpufreq_dt_pd));
return 0;
}
diff --git a/arch/arm/mach-mvebu/pmsu.h b/arch/arm/mach-mvebu/pmsu.h
index 6b58c1f..ea79269 100644
--- a/arch/arm/mach-mvebu/pmsu.h
+++ b/arch/arm/mach-mvebu/pmsu.h
@@ -17,5 +17,8 @@ int mvebu_setup_boot_addr_wa(unsigned int crypto_eng_target,
phys_addr_t resume_addr_reg);
void mvebu_v7_pmsu_idle_exit(void);
+void armada_370_xp_cpu_resume(void);
+int armada_370_xp_pmsu_idle_enter(unsigned long deepidle);
+int armada_38x_do_cpu_suspend(unsigned long deepidle);
#endif /* __MACH_370_XP_PMSU_H */
diff --git a/arch/arm/mach-mvebu/pmsu_ll.S b/arch/arm/mach-mvebu/pmsu_ll.S
index a945756..8865122 100644
--- a/arch/arm/mach-mvebu/pmsu_ll.S
+++ b/arch/arm/mach-mvebu/pmsu_ll.S
@@ -12,12 +12,32 @@
#include <linux/linkage.h>
#include <asm/assembler.h>
+
+ENTRY(armada_38x_scu_power_up)
+ mrc p15, 4, r1, c15, c0 @ get SCU base address
+ orr r1, r1, #0x8 @ SCU CPU Power Status Register
+ mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID
+ and r0, r0, #15
+ add r1, r1, r0
+ mov r0, #0x0
+ strb r0, [r1] @ switch SCU power state to Normal mode
+ ret lr
+ENDPROC(armada_38x_scu_power_up)
+
/*
* This is the entry point through which CPUs exiting cpuidle deep
* idle state are going.
*/
ENTRY(armada_370_xp_cpu_resume)
ARM_BE8(setend be ) @ go BE8 if entered LE
+ /*
+ * Disable the MMU that might have been enabled in BootROM if
+ * this code is used in the resume path of a suspend/resume
+ * cycle.
+ */
+ mrc p15, 0, r1, c1, c0, 0
+ bic r1, #1
+ mcr p15, 0, r1, c1, c0, 0
bl ll_add_cpu_to_smp_group
bl ll_enable_coherency
b cpu_resume
@@ -27,13 +47,7 @@ ENTRY(armada_38x_cpu_resume)
/* do we need it for Armada 38x*/
ARM_BE8(setend be ) @ go BE8 if entered LE
bl v7_invalidate_l1
- mrc p15, 4, r1, c15, c0 @ get SCU base address
- orr r1, r1, #0x8 @ SCU CPU Power Status Register
- mrc 15, 0, r0, cr0, cr0, 5 @ get the CPU ID
- and r0, r0, #15
- add r1, r1, r0
- mov r0, #0x0
- strb r0, [r1] @ switch SCU power state to Normal mode
+ bl armada_38x_scu_power_up
b cpu_resume
ENDPROC(armada_38x_cpu_resume)
diff --git a/arch/arm/mach-nomadik/cpu-8815.c b/arch/arm/mach-nomadik/cpu-8815.c
index 9116ca4..9bda46f 100644
--- a/arch/arm/mach-nomadik/cpu-8815.c
+++ b/arch/arm/mach-nomadik/cpu-8815.c
@@ -144,6 +144,7 @@ static int __init cpu8815_mmcsd_init(void)
device_initcall(cpu8815_mmcsd_init);
static const char * cpu8815_board_compat[] = {
+ "st,nomadik-nhk-15",
"calaosystems,usb-s8815",
NULL,
};
diff --git a/arch/arm/mach-omap2/Kconfig b/arch/arm/mach-omap2/Kconfig
index f4d06ae..6e24932 100644
--- a/arch/arm/mach-omap2/Kconfig
+++ b/arch/arm/mach-omap2/Kconfig
@@ -79,7 +79,9 @@ config ARCH_OMAP2PLUS
select CLKSRC_MMIO
select GENERIC_IRQ_CHIP
select MACH_OMAP_GENERIC
+ select MEMORY
select OMAP_DM_TIMER
+ select OMAP_GPMC
select PINCTRL
select SOC_BUS
select TI_PRIV_EDMA
@@ -235,12 +237,6 @@ config MACH_TOUCHBOOK
default y
select OMAP_PACKAGE_CBB
-config MACH_OMAP_3430SDP
- bool "OMAP 3430 SDP board"
- depends on ARCH_OMAP3
- default y
- select OMAP_PACKAGE_CBB
-
config MACH_NOKIA_N810
bool
@@ -282,16 +278,6 @@ config MACH_SBC3530
default y
select OMAP_PACKAGE_CUS
-config MACH_TI8168EVM
- bool "TI8168 Evaluation Module"
- depends on SOC_TI81XX
- default y
-
-config MACH_TI8148EVM
- bool "TI8148 Evaluation Module"
- depends on SOC_TI81XX
- default y
-
config OMAP3_EMU
bool "OMAP3 debugging peripherals"
depends on ARCH_OMAP3
diff --git a/arch/arm/mach-omap2/Makefile b/arch/arm/mach-omap2/Makefile
index d9e9412..08cc944 100644
--- a/arch/arm/mach-omap2/Makefile
+++ b/arch/arm/mach-omap2/Makefile
@@ -6,7 +6,7 @@ ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
-I$(srctree)/arch/arm/plat-omap/include
# Common support
-obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o gpmc.o timer.o pm.o \
+obj-y := id.o io.o control.o mux.o devices.o fb.o serial.o timer.o pm.o \
common.o gpio.o dma.o wd_timer.o display.o i2c.o hdq1w.o omap_hwmod.o \
omap_device.o sram.o drm.o
@@ -113,7 +113,7 @@ obj-y += prm_common.o cm_common.o
obj-$(CONFIG_ARCH_OMAP2) += prm2xxx_3xxx.o prm2xxx.o cm2xxx.o
obj-$(CONFIG_ARCH_OMAP3) += prm2xxx_3xxx.o prm3xxx.o cm3xxx.o
obj-$(CONFIG_ARCH_OMAP3) += vc3xxx_data.o vp3xxx_data.o
-omap-prcm-4-5-common = cminst44xx.o cm44xx.o prm44xx.o \
+omap-prcm-4-5-common = cminst44xx.o prm44xx.o \
prcm_mpu44xx.o prminst44xx.o \
vc44xx_data.o vp44xx_data.o
obj-$(CONFIG_ARCH_OMAP4) += $(omap-prcm-4-5-common)
@@ -246,7 +246,6 @@ obj-$(CONFIG_MACH_OMAP3530_LV_SOM) += board-omap3logic.o
obj-$(CONFIG_MACH_OMAP3_TORPEDO) += board-omap3logic.o
obj-$(CONFIG_MACH_OVERO) += board-overo.o
obj-$(CONFIG_MACH_OMAP3_PANDORA) += board-omap3pandora.o
-obj-$(CONFIG_MACH_OMAP_3430SDP) += board-3430sdp.o
obj-$(CONFIG_MACH_NOKIA_N8X0) += board-n8x0.o
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51.o sdram-nokia.o
obj-$(CONFIG_MACH_NOKIA_RX51) += board-rx51-peripherals.o
@@ -260,8 +259,6 @@ obj-$(CONFIG_MACH_OMAP3517EVM) += board-am3517evm.o
obj-$(CONFIG_MACH_CRANEBOARD) += board-am3517crane.o
obj-$(CONFIG_MACH_SBC3530) += board-omap3stalker.o
-obj-$(CONFIG_MACH_TI8168EVM) += board-ti8168evm.o
-obj-$(CONFIG_MACH_TI8148EVM) += board-ti8168evm.o
# Platform specific device init code
@@ -284,9 +281,6 @@ obj-y += $(onenand-m) $(onenand-y)
nand-$(CONFIG_MTD_NAND_OMAP2) := gpmc-nand.o
obj-y += $(nand-m) $(nand-y)
-smc91x-$(CONFIG_SMC91X) := gpmc-smc91x.o
-obj-y += $(smc91x-m) $(smc91x-y)
-
smsc911x-$(CONFIG_SMSC911X) := gpmc-smsc911x.o
obj-y += $(smsc911x-m) $(smsc911x-y)
ifneq ($(CONFIG_HWSPINLOCK_OMAP),)
diff --git a/arch/arm/mach-omap2/am33xx-restart.c b/arch/arm/mach-omap2/am33xx-restart.c
index c88d8df7..5bace6a 100644
--- a/arch/arm/mach-omap2/am33xx-restart.c
+++ b/arch/arm/mach-omap2/am33xx-restart.c
@@ -9,8 +9,7 @@
#include <linux/reboot.h>
#include "common.h"
-#include "prm-regbits-33xx.h"
-#include "prm33xx.h"
+#include "prm.h"
/**
* am3xx_restart - trigger a software restart of the SoC
@@ -24,12 +23,5 @@ void am33xx_restart(enum reboot_mode mode, const char *cmd)
{
/* TODO: Handle mode and cmd if necessary */
- am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK,
- AM33XX_RST_GLOBAL_WARM_SW_MASK,
- AM33XX_PRM_DEVICE_MOD,
- AM33XX_PRM_RSTCTRL_OFFSET);
-
- /* OCP barrier */
- (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD,
- AM33XX_PRM_RSTCTRL_OFFSET);
+ omap_prm_reset_system();
}
diff --git a/arch/arm/mach-omap2/board-3430sdp.c b/arch/arm/mach-omap2/board-3430sdp.c
deleted file mode 100644
index d21a304..0000000
--- a/arch/arm/mach-omap2/board-3430sdp.c
+++ /dev/null
@@ -1,632 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/board-3430sdp.c
- *
- * Copyright (C) 2007 Texas Instruments
- *
- * Modified from mach-omap2/board-generic.c
- *
- * Initial code: Syed Mohammed Khasim
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/delay.h>
-#include <linux/input.h>
-#include <linux/input/matrix_keypad.h>
-#include <linux/spi/spi.h>
-#include <linux/i2c/twl.h>
-#include <linux/regulator/machine.h>
-#include <linux/io.h>
-#include <linux/gpio.h>
-#include <linux/mmc/host.h>
-#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/omap-twl4030.h>
-#include <linux/usb/phy.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-#include <linux/omap-dma.h>
-#include <video/omapdss.h>
-#include <video/omap-panel-data.h>
-
-#include "gpmc.h"
-#include "gpmc-smc91x.h"
-
-#include "soc.h"
-#include "board-flash.h"
-#include "mux.h"
-#include "sdram-qimonda-hyb18m512160af-6.h"
-#include "hsmmc.h"
-#include "pm.h"
-#include "control.h"
-#include "common-board-devices.h"
-
-#define CONFIG_DISABLE_HFCLK 1
-
-#define SDP3430_TS_GPIO_IRQ_SDPV1 3
-#define SDP3430_TS_GPIO_IRQ_SDPV2 2
-
-#define ENABLE_VAUX3_DEDICATED 0x03
-#define ENABLE_VAUX3_DEV_GRP 0x20
-
-#define TWL4030_MSECURE_GPIO 22
-
-static uint32_t board_keymap[] = {
- KEY(0, 0, KEY_LEFT),
- KEY(0, 1, KEY_RIGHT),
- KEY(0, 2, KEY_A),
- KEY(0, 3, KEY_B),
- KEY(0, 4, KEY_C),
- KEY(1, 0, KEY_DOWN),
- KEY(1, 1, KEY_UP),
- KEY(1, 2, KEY_E),
- KEY(1, 3, KEY_F),
- KEY(1, 4, KEY_G),
- KEY(2, 0, KEY_ENTER),
- KEY(2, 1, KEY_I),
- KEY(2, 2, KEY_J),
- KEY(2, 3, KEY_K),
- KEY(2, 4, KEY_3),
- KEY(3, 0, KEY_M),
- KEY(3, 1, KEY_N),
- KEY(3, 2, KEY_O),
- KEY(3, 3, KEY_P),
- KEY(3, 4, KEY_Q),
- KEY(4, 0, KEY_R),
- KEY(4, 1, KEY_4),
- KEY(4, 2, KEY_T),
- KEY(4, 3, KEY_U),
- KEY(4, 4, KEY_D),
- KEY(5, 0, KEY_V),
- KEY(5, 1, KEY_W),
- KEY(5, 2, KEY_L),
- KEY(5, 3, KEY_S),
- KEY(5, 4, KEY_H),
- 0
-};
-
-static struct matrix_keymap_data board_map_data = {
- .keymap = board_keymap,
- .keymap_size = ARRAY_SIZE(board_keymap),
-};
-
-static struct twl4030_keypad_data sdp3430_kp_data = {
- .keymap_data = &board_map_data,
- .rows = 5,
- .cols = 6,
- .rep = 1,
-};
-
-#define SDP3430_LCD_PANEL_BACKLIGHT_GPIO 8
-#define SDP3430_LCD_PANEL_ENABLE_GPIO 5
-
-static void __init sdp3430_display_init(void)
-{
- int r;
-
- /*
- * the backlight GPIO doesn't directly go to the panel, it enables
- * an internal circuit on 3430sdp to create the signal V_BKL_28V,
- * this is connected to LED+ pin of the sharp panel. This GPIO
- * is left enabled in the board file, and not passed to the panel
- * as platform_data.
- */
- r = gpio_request_one(SDP3430_LCD_PANEL_BACKLIGHT_GPIO,
- GPIOF_OUT_INIT_HIGH, "LCD Backlight");
- if (r)
- pr_err("failed to get LCD Backlight GPIO\n");
-
-}
-
-static struct panel_sharp_ls037v7dw01_platform_data sdp3430_lcd_pdata = {
- .name = "lcd",
- .source = "dpi.0",
-
- .data_lines = 16,
-
- .resb_gpio = SDP3430_LCD_PANEL_ENABLE_GPIO,
- .ini_gpio = -1,
- .mo_gpio = -1,
- .lr_gpio = -1,
- .ud_gpio = -1,
-};
-
-static struct platform_device sdp3430_lcd_device = {
- .name = "panel-sharp-ls037v7dw01",
- .id = 0,
- .dev.platform_data = &sdp3430_lcd_pdata,
-};
-
-static struct connector_dvi_platform_data sdp3430_dvi_connector_pdata = {
- .name = "dvi",
- .source = "tfp410.0",
- .i2c_bus_num = -1,
-};
-
-static struct platform_device sdp3430_dvi_connector_device = {
- .name = "connector-dvi",
- .id = 0,
- .dev.platform_data = &sdp3430_dvi_connector_pdata,
-};
-
-static struct encoder_tfp410_platform_data sdp3430_tfp410_pdata = {
- .name = "tfp410.0",
- .source = "dpi.0",
- .data_lines = 24,
- .power_down_gpio = -1,
-};
-
-static struct platform_device sdp3430_tfp410_device = {
- .name = "tfp410",
- .id = 0,
- .dev.platform_data = &sdp3430_tfp410_pdata,
-};
-
-static struct connector_atv_platform_data sdp3430_tv_pdata = {
- .name = "tv",
- .source = "venc.0",
- .connector_type = OMAP_DSS_VENC_TYPE_SVIDEO,
- .invert_polarity = false,
-};
-
-static struct platform_device sdp3430_tv_connector_device = {
- .name = "connector-analog-tv",
- .id = 0,
- .dev.platform_data = &sdp3430_tv_pdata,
-};
-
-static struct omap_dss_board_info sdp3430_dss_data = {
- .default_display_name = "lcd",
-};
-
-static struct omap2_hsmmc_info mmc[] = {
- {
- .mmc = 1,
- /* 8 bits (default) requires S6.3 == ON,
- * so the SIM card isn't used; else 4 bits.
- */
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
- .gpio_wp = 4,
- .deferred = true,
- },
- {
- .mmc = 2,
- .caps = MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA,
- .gpio_wp = 7,
- .deferred = true,
- },
- {} /* Terminator */
-};
-
-static struct omap_tw4030_pdata omap_twl4030_audio_data = {
- .voice_connected = true,
- .custom_routing = true,
-
- .has_hs = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
- .has_hf = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
-
- .has_mainmic = true,
- .has_submic = true,
- .has_hsmic = true,
- .has_linein = OMAP_TWL4030_LEFT | OMAP_TWL4030_RIGHT,
-};
-
-static int sdp3430_twl_gpio_setup(struct device *dev,
- unsigned gpio, unsigned ngpio)
-{
- /* gpio + 0 is "mmc0_cd" (input/IRQ),
- * gpio + 1 is "mmc1_cd" (input/IRQ)
- */
- mmc[0].gpio_cd = gpio + 0;
- mmc[1].gpio_cd = gpio + 1;
- omap_hsmmc_late_init(mmc);
-
- /* gpio + 7 is "sub_lcd_en_bkl" (output/PWM1) */
- gpio_request_one(gpio + 7, GPIOF_OUT_INIT_LOW, "sub_lcd_en_bkl");
-
- /* gpio + 15 is "sub_lcd_nRST" (output) */
- gpio_request_one(gpio + 15, GPIOF_OUT_INIT_LOW, "sub_lcd_nRST");
-
- omap_twl4030_audio_data.jack_detect = gpio + 2;
- omap_twl4030_audio_init("SDP3430", &omap_twl4030_audio_data);
-
- return 0;
-}
-
-static struct twl4030_gpio_platform_data sdp3430_gpio_data = {
- .pulldowns = BIT(2) | BIT(6) | BIT(8) | BIT(13)
- | BIT(16) | BIT(17),
- .setup = sdp3430_twl_gpio_setup,
-};
-
-/* regulator consumer mappings */
-
-/* ads7846 on SPI */
-static struct regulator_consumer_supply sdp3430_vaux3_supplies[] = {
- REGULATOR_SUPPLY("vcc", "spi1.0"),
-};
-
-static struct regulator_consumer_supply sdp3430_vmmc1_supplies[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.0"),
-};
-
-static struct regulator_consumer_supply sdp3430_vsim_supplies[] = {
- REGULATOR_SUPPLY("vmmc_aux", "omap_hsmmc.0"),
-};
-
-static struct regulator_consumer_supply sdp3430_vmmc2_supplies[] = {
- REGULATOR_SUPPLY("vmmc", "omap_hsmmc.1"),
-};
-
-/*
- * Apply all the fixed voltages since most versions of U-Boot
- * don't bother with that initialization.
- */
-
-/* VAUX1 for mainboard (irda and sub-lcd) */
-static struct regulator_init_data sdp3430_vaux1 = {
- .constraints = {
- .min_uV = 2800000,
- .max_uV = 2800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
-};
-
-/* VAUX2 for camera module */
-static struct regulator_init_data sdp3430_vaux2 = {
- .constraints = {
- .min_uV = 2800000,
- .max_uV = 2800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
-};
-
-/* VAUX3 for LCD board */
-static struct regulator_init_data sdp3430_vaux3 = {
- .constraints = {
- .min_uV = 2800000,
- .max_uV = 2800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(sdp3430_vaux3_supplies),
- .consumer_supplies = sdp3430_vaux3_supplies,
-};
-
-/* VAUX4 for OMAP VDD_CSI2 (camera) */
-static struct regulator_init_data sdp3430_vaux4 = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 1800000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
-};
-
-/* VMMC1 for OMAP VDD_MMC1 (i/o) and MMC1 card */
-static struct regulator_init_data sdp3430_vmmc1 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 3150000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(sdp3430_vmmc1_supplies),
- .consumer_supplies = sdp3430_vmmc1_supplies,
-};
-
-/* VMMC2 for MMC2 card */
-static struct regulator_init_data sdp3430_vmmc2 = {
- .constraints = {
- .min_uV = 1850000,
- .max_uV = 1850000,
- .apply_uV = true,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(sdp3430_vmmc2_supplies),
- .consumer_supplies = sdp3430_vmmc2_supplies,
-};
-
-/* VSIM for OMAP VDD_MMC1A (i/o for DAT4..DAT7) */
-static struct regulator_init_data sdp3430_vsim = {
- .constraints = {
- .min_uV = 1800000,
- .max_uV = 3000000,
- .valid_modes_mask = REGULATOR_MODE_NORMAL
- | REGULATOR_MODE_STANDBY,
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE
- | REGULATOR_CHANGE_MODE
- | REGULATOR_CHANGE_STATUS,
- },
- .num_consumer_supplies = ARRAY_SIZE(sdp3430_vsim_supplies),
- .consumer_supplies = sdp3430_vsim_supplies,
-};
-
-static struct twl4030_platform_data sdp3430_twldata = {
- /* platform_data for children goes here */
- .gpio = &sdp3430_gpio_data,
- .keypad = &sdp3430_kp_data,
-
- .vaux1 = &sdp3430_vaux1,
- .vaux2 = &sdp3430_vaux2,
- .vaux3 = &sdp3430_vaux3,
- .vaux4 = &sdp3430_vaux4,
- .vmmc1 = &sdp3430_vmmc1,
- .vmmc2 = &sdp3430_vmmc2,
- .vsim = &sdp3430_vsim,
-};
-
-static int __init omap3430_i2c_init(void)
-{
- /* i2c1 for PMIC only */
- omap3_pmic_get_config(&sdp3430_twldata,
- TWL_COMMON_PDATA_USB | TWL_COMMON_PDATA_BCI |
- TWL_COMMON_PDATA_MADC | TWL_COMMON_PDATA_AUDIO,
- TWL_COMMON_REGULATOR_VDAC | TWL_COMMON_REGULATOR_VPLL2);
- sdp3430_twldata.vdac->constraints.apply_uV = true;
- sdp3430_twldata.vpll2->constraints.apply_uV = true;
- sdp3430_twldata.vpll2->constraints.name = "VDVI";
-
- sdp3430_twldata.audio->codec->hs_extmute = 1;
- sdp3430_twldata.audio->codec->hs_extmute_gpio = -EINVAL;
-
- omap3_pmic_init("twl4030", &sdp3430_twldata);
-
- /* i2c2 on camera connector (for sensor control) and optional isp1301 */
- omap_register_i2c_bus(2, 400, NULL, 0);
- /* i2c3 on display connector (for DVI, tfp410) */
- omap_register_i2c_bus(3, 400, NULL, 0);
- return 0;
-}
-
-#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
-
-static struct omap_smc91x_platform_data board_smc91x_data = {
- .cs = 3,
- .flags = GPMC_MUX_ADD_DATA | GPMC_TIMINGS_SMC91C96 |
- IORESOURCE_IRQ_LOWLEVEL,
-};
-
-static void __init board_smc91x_init(void)
-{
- if (omap_rev() > OMAP3430_REV_ES1_0)
- board_smc91x_data.gpio_irq = 6;
- else
- board_smc91x_data.gpio_irq = 29;
-
- gpmc_smc91x_init(&board_smc91x_data);
-}
-
-#else
-
-static inline void board_smc91x_init(void)
-{
-}
-
-#endif
-
-static void enable_board_wakeup_source(void)
-{
- /* T2 interrupt line (keypad) */
- omap_mux_init_signal("sys_nirq",
- OMAP_WAKEUP_EN | OMAP_PIN_INPUT_PULLUP);
-}
-
-static struct usbhs_phy_data phy_data[] __initdata = {
- {
- .port = 1,
- .reset_gpio = 57,
- .vcc_gpio = -EINVAL,
- },
- {
- .port = 2,
- .reset_gpio = 61,
- .vcc_gpio = -EINVAL,
- },
-};
-
-static struct usbhs_omap_platform_data usbhs_bdata __initdata = {
-
- .port_mode[0] = OMAP_EHCI_PORT_MODE_PHY,
- .port_mode[1] = OMAP_EHCI_PORT_MODE_PHY,
-};
-
-#ifdef CONFIG_OMAP_MUX
-static struct omap_board_mux board_mux[] __initdata = {
- { .reg_offset = OMAP_MUX_TERMINATOR },
-};
-#else
-#define board_mux NULL
-#endif
-
-/*
- * SDP3430 V2 Board CS organization
- * Different from SDP3430 V1. Now 4 switches used to specify CS
- *
- * See also the Switch S8 settings in the comments.
- */
-static char chip_sel_3430[][GPMC_CS_NUM] = {
- {PDC_NOR, PDC_NAND, PDC_ONENAND, DBG_MPDB, 0, 0, 0, 0}, /* S8:1111 */
- {PDC_ONENAND, PDC_NAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1110 */
- {PDC_NAND, PDC_ONENAND, PDC_NOR, DBG_MPDB, 0, 0, 0, 0}, /* S8:1101 */
-};
-
-static struct mtd_partition sdp_nor_partitions[] = {
- /* bootloader (U-Boot, etc) in first sector */
- {
- .name = "Bootloader-NOR",
- .offset = 0,
- .size = SZ_256K,
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- /* bootloader params in the next sector */
- {
- .name = "Params-NOR",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_256K,
- .mask_flags = 0,
- },
- /* kernel */
- {
- .name = "Kernel-NOR",
- .offset = MTDPART_OFS_APPEND,
- .size = SZ_2M,
- .mask_flags = 0
- },
- /* file system */
- {
- .name = "Filesystem-NOR",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- .mask_flags = 0
- }
-};
-
-static struct mtd_partition sdp_onenand_partitions[] = {
- {
- .name = "X-Loader-OneNAND",
- .offset = 0,
- .size = 4 * (64 * 2048),
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },
- {
- .name = "U-Boot-OneNAND",
- .offset = MTDPART_OFS_APPEND,
- .size = 2 * (64 * 2048),
- .mask_flags = MTD_WRITEABLE /* force read-only */
- },
- {
- .name = "U-Boot Environment-OneNAND",
- .offset = MTDPART_OFS_APPEND,
- .size = 1 * (64 * 2048),
- },
- {
- .name = "Kernel-OneNAND",
- .offset = MTDPART_OFS_APPEND,
- .size = 16 * (64 * 2048),
- },
- {
- .name = "File System-OneNAND",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static struct mtd_partition sdp_nand_partitions[] = {
- /* All the partition sizes are listed in terms of NAND block size */
- {
- .name = "X-Loader-NAND",
- .offset = 0,
- .size = 4 * (64 * 2048),
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "U-Boot-NAND",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x80000 */
- .size = 10 * (64 * 2048),
- .mask_flags = MTD_WRITEABLE, /* force read-only */
- },
- {
- .name = "Boot Env-NAND",
-
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x1c0000 */
- .size = 6 * (64 * 2048),
- },
- {
- .name = "Kernel-NAND",
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x280000 */
- .size = 40 * (64 * 2048),
- },
- {
- .name = "File System - NAND",
- .size = MTDPART_SIZ_FULL,
- .offset = MTDPART_OFS_APPEND, /* Offset = 0x780000 */
- },
-};
-
-static struct flash_partitions sdp_flash_partitions[] = {
- {
- .parts = sdp_nor_partitions,
- .nr_parts = ARRAY_SIZE(sdp_nor_partitions),
- },
- {
- .parts = sdp_onenand_partitions,
- .nr_parts = ARRAY_SIZE(sdp_onenand_partitions),
- },
- {
- .parts = sdp_nand_partitions,
- .nr_parts = ARRAY_SIZE(sdp_nand_partitions),
- },
-};
-
-static void __init omap_3430sdp_init(void)
-{
- int gpio_pendown;
-
- omap3_mux_init(board_mux, OMAP_PACKAGE_CBB);
- omap_hsmmc_init(mmc);
- omap3430_i2c_init();
- omap_display_init(&sdp3430_dss_data);
- platform_device_register(&sdp3430_lcd_device);
- platform_device_register(&sdp3430_tfp410_device);
- platform_device_register(&sdp3430_dvi_connector_device);
- platform_device_register(&sdp3430_tv_connector_device);
-
- if (omap_rev() > OMAP3430_REV_ES1_0)
- gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV2;
- else
- gpio_pendown = SDP3430_TS_GPIO_IRQ_SDPV1;
- omap_ads7846_init(1, gpio_pendown, 310, NULL);
- omap_serial_init();
- omap_sdrc_init(hyb18m512160af6_sdrc_params, NULL);
- usb_bind_phy("musb-hdrc.0.auto", 0, "twl4030_usb");
- usb_musb_init(NULL);
- board_smc91x_init();
- board_flash_init(sdp_flash_partitions, chip_sel_3430, 0);
- sdp3430_display_init();
- enable_board_wakeup_source();
-
- usbhs_init_phys(phy_data, ARRAY_SIZE(phy_data));
- usbhs_init(&usbhs_bdata);
-}
-
-MACHINE_START(OMAP_3430SDP, "OMAP3430 3430SDP board")
- /* Maintainer: Syed Khasim - Texas Instruments Inc */
- .atag_offset = 0x100,
- .reserve = omap_reserve,
- .map_io = omap3_map_io,
- .init_early = omap3430_init_early,
- .init_irq = omap3_init_irq,
- .init_machine = omap_3430sdp_init,
- .init_late = omap3430_init_late,
- .init_time = omap3_sync32k_timer_init,
- .restart = omap3xxx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/board-am3517crane.c b/arch/arm/mach-omap2/board-am3517crane.c
index 212c316..8168dda 100644
--- a/arch/arm/mach-omap2/board-am3517crane.c
+++ b/arch/arm/mach-omap2/board-am3517crane.c
@@ -24,6 +24,7 @@
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
#include <linux/mtd/partitions.h>
+#include <linux/omap-gpmc.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
diff --git a/arch/arm/mach-omap2/board-cm-t35.c b/arch/arm/mach-omap2/board-cm-t35.c
index c6df8eec..91738a1 100644
--- a/arch/arm/mach-omap2/board-cm-t35.c
+++ b/arch/arm/mach-omap2/board-cm-t35.c
@@ -25,6 +25,7 @@
#include <linux/input/matrix_keypad.h>
#include <linux/delay.h>
#include <linux/gpio.h>
+#include <linux/omap-gpmc.h>
#include <linux/platform_data/gpio-omap.h>
#include <linux/platform_data/at24.h>
@@ -51,8 +52,6 @@
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
#include "common-board-devices.h"
-#include "gpmc.h"
-#include "gpmc-nand.h"
#define CM_T35_GPIO_PENDOWN 57
#define SB_T35_USB_HUB_RESET_GPIO 167
diff --git a/arch/arm/mach-omap2/board-cm-t3517.c b/arch/arm/mach-omap2/board-cm-t3517.c
index 8a2c167..794756d 100644
--- a/arch/arm/mach-omap2/board-cm-t3517.c
+++ b/arch/arm/mach-omap2/board-cm-t3517.c
@@ -28,6 +28,7 @@
#include <linux/delay.h>
#include <linux/gpio.h>
#include <linux/leds.h>
+#include <linux/omap-gpmc.h>
#include <linux/rtc-v3020.h>
#include <linux/mtd/mtd.h>
#include <linux/mtd/nand.h>
@@ -41,7 +42,6 @@
#include "common.h"
#include <linux/platform_data/mtd-nand-omap2.h>
-#include "gpmc.h"
#include "am35xx.h"
@@ -50,7 +50,6 @@
#include "hsmmc.h"
#include "common-board-devices.h"
#include "am35xx-emac.h"
-#include "gpmc-nand.h"
#if defined(CONFIG_LEDS_GPIO) || defined(CONFIG_LEDS_GPIO_MODULE)
static struct gpio_led cm_t3517_leds[] = {
diff --git a/arch/arm/mach-omap2/board-flash.c b/arch/arm/mach-omap2/board-flash.c
index 2d245c2..70b21cc 100644
--- a/arch/arm/mach-omap2/board-flash.c
+++ b/arch/arm/mach-omap2/board-flash.c
@@ -13,6 +13,7 @@
*/
#include <linux/kernel.h>
+#include <linux/omap-gpmc.h>
#include <linux/platform_device.h>
#include <linux/mtd/physmap.h>
#include <linux/io.h>
@@ -23,8 +24,6 @@
#include "soc.h"
#include "common.h"
#include "board-flash.h"
-#include "gpmc-onenand.h"
-#include "gpmc-nand.h"
#define REG_FPGA_REV 0x10
#define REG_FPGA_DIP_SWITCH_INPUT2 0x60
diff --git a/arch/arm/mach-omap2/board-flash.h b/arch/arm/mach-omap2/board-flash.h
index 2fb5d41..ea9aaeb 100644
--- a/arch/arm/mach-omap2/board-flash.h
+++ b/arch/arm/mach-omap2/board-flash.h
@@ -12,7 +12,6 @@
*/
#include <linux/mtd/mtd.h>
#include <linux/mtd/partitions.h>
-#include "gpmc.h"
#define PDC_NOR 1
#define PDC_NAND 2
diff --git a/arch/arm/mach-omap2/board-n8x0.c b/arch/arm/mach-omap2/board-n8x0.c
index 97767a2..b6443a4 100644
--- a/arch/arm/mach-omap2/board-n8x0.c
+++ b/arch/arm/mach-omap2/board-n8x0.c
@@ -21,8 +21,9 @@
#include <linux/i2c.h>
#include <linux/spi/spi.h>
#include <linux/usb/musb.h>
+#include <linux/mmc/host.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
-#include <linux/platform_data/mtd-onenand-omap2.h>
+#include <linux/platform_data/mmc-omap.h>
#include <linux/mfd/menelaus.h>
#include <sound/tlv320aic3x.h>
@@ -32,7 +33,6 @@
#include "common.h"
#include "mmc.h"
#include "soc.h"
-#include "gpmc-onenand.h"
#include "common-board-devices.h"
#define TUSB6010_ASYNC_CS 1
diff --git a/arch/arm/mach-omap2/board-omap3pandora.c b/arch/arm/mach-omap2/board-omap3pandora.c
index f322016..7f17087 100644
--- a/arch/arm/mach-omap2/board-omap3pandora.c
+++ b/arch/arm/mach-omap2/board-omap3pandora.c
@@ -24,6 +24,7 @@
#include <linux/spi/spi.h>
#include <linux/regulator/machine.h>
#include <linux/i2c/twl.h>
+#include <linux/omap-gpmc.h>
#include <linux/wl12xx.h>
#include <linux/mtd/partitions.h>
#include <linux/mtd/nand.h>
@@ -51,7 +52,6 @@
#include "sdram-micron-mt46h32m32lf-6.h"
#include "hsmmc.h"
#include "common-board-devices.h"
-#include "gpmc-nand.h"
#define PANDORA_WIFI_IRQ_GPIO 21
#define PANDORA_WIFI_NRESET_GPIO 23
diff --git a/arch/arm/mach-omap2/board-rx51-peripherals.c b/arch/arm/mach-omap2/board-rx51-peripherals.c
index ddfc8df..14edcd7 100644
--- a/arch/arm/mach-omap2/board-rx51-peripherals.c
+++ b/arch/arm/mach-omap2/board-rx51-peripherals.c
@@ -23,6 +23,8 @@
#include <linux/regulator/machine.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
+#include <linux/gpio/machine.h>
+#include <linux/omap-gpmc.h>
#include <linux/mmc/host.h>
#include <linux/power/isp1704_charger.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
@@ -32,13 +34,11 @@
#include "common.h"
#include <linux/omap-dma.h>
-#include "gpmc-smc91x.h"
#include "board-rx51.h"
#include <sound/tlv320aic3x.h>
#include <sound/tpa6130a2-plat.h>
-#include <media/radio-si4713.h>
#include <media/si4713.h>
#include <linux/platform_data/leds-lp55xx.h>
@@ -55,8 +55,6 @@
#include "omap-pm.h"
#include "hsmmc.h"
#include "common-board-devices.h"
-#include "gpmc.h"
-#include "gpmc-onenand.h"
#include "soc.h"
#include "omap-secure.h"
@@ -484,7 +482,7 @@ static struct omap_mux_partition *partition;
* Current flows to eMMC when eMMC is off and the data lines are pulled up,
* so pull them down. N.B. we pull 8 lines because we are using 8 lines.
*/
-static void rx51_mmc2_remux(struct device *dev, int slot, int power_on)
+static void rx51_mmc2_remux(struct device *dev, int power_on)
{
if (power_on)
omap_mux_write_array(partition, rx51_mmc2_on_mux);
@@ -500,7 +498,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.cover_only = true,
.gpio_cd = 160,
.gpio_wp = -EINVAL,
- .power_saving = true,
},
{
.name = "internal",
@@ -510,7 +507,6 @@ static struct omap2_hsmmc_info mmc[] __initdata = {
.gpio_cd = -EINVAL,
.gpio_wp = -EINVAL,
.nonremovable = true,
- .power_saving = true,
.remux = rx51_mmc2_remux,
},
{} /* Terminator */
@@ -760,46 +756,17 @@ static struct regulator_init_data rx51_vintdig = {
},
};
-static const char * const si4713_supply_names[] = {
- "vio",
- "vdd",
-};
-
-static struct si4713_platform_data rx51_si4713_i2c_data __initdata_or_module = {
- .supplies = ARRAY_SIZE(si4713_supply_names),
- .supply_names = si4713_supply_names,
- .gpio_reset = RX51_FMTX_RESET_GPIO,
-};
-
-static struct i2c_board_info rx51_si4713_board_info __initdata_or_module = {
- I2C_BOARD_INFO("si4713", SI4713_I2C_ADDR_BUSEN_HIGH),
- .platform_data = &rx51_si4713_i2c_data,
-};
-
-static struct radio_si4713_platform_data rx51_si4713_data __initdata_or_module = {
- .i2c_bus = 2,
- .subdev_board_info = &rx51_si4713_board_info,
-};
-
-static struct platform_device rx51_si4713_dev __initdata_or_module = {
- .name = "radio-si4713",
- .id = -1,
- .dev = {
- .platform_data = &rx51_si4713_data,
+static struct gpiod_lookup_table rx51_fmtx_gpios_table = {
+ .dev_id = "2-0063",
+ .table = {
+ GPIO_LOOKUP("gpio.6", 3, "reset", GPIO_ACTIVE_HIGH), /* 163 */
+ { },
},
};
-static __init void rx51_init_si4713(void)
+static __init void rx51_gpio_init(void)
{
- int err;
-
- err = gpio_request_one(RX51_FMTX_IRQ, GPIOF_DIR_IN, "si4713 irq");
- if (err) {
- printk(KERN_ERR "Cannot request si4713 irq gpio. %d\n", err);
- return;
- }
- rx51_si4713_board_info.irq = gpio_to_irq(RX51_FMTX_IRQ);
- platform_device_register(&rx51_si4713_dev);
+ gpiod_add_lookup_table(&rx51_fmtx_gpios_table);
}
static int rx51_twlgpio_setup(struct device *dev, unsigned gpio, unsigned n)
@@ -1029,7 +996,19 @@ static struct aic3x_pdata rx51_aic3x_data2 = {
.gpio_reset = 60,
};
+#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
+static struct si4713_platform_data rx51_si4713_platform_data = {
+ .is_platform_device = true
+};
+#endif
+
static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_2[] = {
+#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
+ {
+ I2C_BOARD_INFO("si4713", 0x63),
+ .platform_data = &rx51_si4713_platform_data,
+ },
+#endif
{
I2C_BOARD_INFO("tlv320aic3x", 0x18),
.platform_data = &rx51_aic3x_data,
@@ -1070,6 +1049,10 @@ static struct i2c_board_info __initdata rx51_peripherals_i2c_board_info_3[] = {
static int __init rx51_i2c_init(void)
{
+#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
+ int err;
+#endif
+
if ((system_rev >= SYSTEM_REV_S_USES_VAUX3 && system_rev < 0x100) ||
system_rev >= SYSTEM_REV_B_USES_VAUX3) {
rx51_twldata.vaux3 = &rx51_vaux3_mmc;
@@ -1087,6 +1070,14 @@ static int __init rx51_i2c_init(void)
rx51_twldata.vdac->constraints.name = "VDAC";
omap_pmic_init(1, 2200, "twl5030", 7 + OMAP_INTC_START, &rx51_twldata);
+#if IS_ENABLED(CONFIG_I2C_SI4713) && IS_ENABLED(CONFIG_PLATFORM_SI4713)
+ err = gpio_request_one(RX51_FMTX_IRQ, GPIOF_DIR_IN, "si4713 irq");
+ if (err) {
+ printk(KERN_ERR "Cannot request si4713 irq gpio. %d\n", err);
+ return err;
+ }
+ rx51_peripherals_i2c_board_info_2[0].irq = gpio_to_irq(RX51_FMTX_IRQ);
+#endif
omap_register_i2c_bus(2, 100, rx51_peripherals_i2c_board_info_2,
ARRAY_SIZE(rx51_peripherals_i2c_board_info_2));
#if defined(CONFIG_SENSORS_LIS3_I2C) || defined(CONFIG_SENSORS_LIS3_I2C_MODULE)
@@ -1146,33 +1137,6 @@ static struct omap_onenand_platform_data board_onenand_data[] = {
};
#endif
-#if defined(CONFIG_SMC91X) || defined(CONFIG_SMC91X_MODULE)
-
-static struct omap_smc91x_platform_data board_smc91x_data = {
- .cs = 1,
- .gpio_irq = 54,
- .gpio_pwrdwn = 86,
- .gpio_reset = 164,
- .flags = GPMC_TIMINGS_SMC91C96 | IORESOURCE_IRQ_HIGHLEVEL,
-};
-
-static void __init board_smc91x_init(void)
-{
- omap_mux_init_gpio(54, OMAP_PIN_INPUT_PULLDOWN);
- omap_mux_init_gpio(86, OMAP_PIN_OUTPUT);
- omap_mux_init_gpio(164, OMAP_PIN_OUTPUT);
-
- gpmc_smc91x_init(&board_smc91x_data);
-}
-
-#else
-
-static inline void board_smc91x_init(void)
-{
-}
-
-#endif
-
static struct gpio rx51_wl1251_gpios[] __initdata = {
{ RX51_WL1251_IRQ_GPIO, GPIOF_IN, "wl1251 irq" },
};
@@ -1300,14 +1264,13 @@ static void __init rx51_init_omap3_rom_rng(void)
void __init rx51_peripherals_init(void)
{
+ rx51_gpio_init();
rx51_i2c_init();
regulator_has_full_constraints();
gpmc_onenand_init(board_onenand_data);
- board_smc91x_init();
rx51_add_gpio_keys();
rx51_init_wl1251();
rx51_init_tsc2005();
- rx51_init_si4713();
rx51_init_lirc();
spi_register_board_info(rx51_peripherals_spi_board_info,
ARRAY_SIZE(rx51_peripherals_spi_board_info));
diff --git a/arch/arm/mach-omap2/board-ti8168evm.c b/arch/arm/mach-omap2/board-ti8168evm.c
deleted file mode 100644
index 6273c28..0000000
--- a/arch/arm/mach-omap2/board-ti8168evm.c
+++ /dev/null
@@ -1,62 +0,0 @@
-/*
- * Code for TI8168/TI8148 EVM.
- *
- * Copyright (C) 2010 Texas Instruments, Inc. - http://www.ti.com/
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation version 2.
- *
- * This program is distributed "as is" WITHOUT ANY WARRANTY of any
- * kind, whether express or implied; without even the implied warranty
- * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/platform_device.h>
-#include <linux/usb/musb.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-
-#include "common.h"
-
-static struct omap_musb_board_data musb_board_data = {
- .set_phy_power = ti81xx_musb_phy_power,
- .interface_type = MUSB_INTERFACE_ULPI,
- .mode = MUSB_OTG,
- .power = 500,
-};
-
-static void __init ti81xx_evm_init(void)
-{
- omap_serial_init();
- omap_sdrc_init(NULL, NULL);
- usb_musb_init(&musb_board_data);
-}
-
-MACHINE_START(TI8168EVM, "ti8168evm")
- /* Maintainer: Texas Instruments */
- .atag_offset = 0x100,
- .map_io = ti81xx_map_io,
- .init_early = ti81xx_init_early,
- .init_irq = ti81xx_init_irq,
- .init_time = omap3_sync32k_timer_init,
- .init_machine = ti81xx_evm_init,
- .init_late = ti81xx_init_late,
- .restart = omap44xx_restart,
-MACHINE_END
-
-MACHINE_START(TI8148EVM, "ti8148evm")
- /* Maintainer: Texas Instruments */
- .atag_offset = 0x100,
- .map_io = ti81xx_map_io,
- .init_early = ti81xx_init_early,
- .init_irq = ti81xx_init_irq,
- .init_time = omap3_sync32k_timer_init,
- .init_machine = ti81xx_evm_init,
- .init_late = ti81xx_init_late,
- .restart = omap44xx_restart,
-MACHINE_END
diff --git a/arch/arm/mach-omap2/cclock3xxx_data.c b/arch/arm/mach-omap2/cclock3xxx_data.c
index eb8c75e..5c5ebb4 100644
--- a/arch/arm/mach-omap2/cclock3xxx_data.c
+++ b/arch/arm/mach-omap2/cclock3xxx_data.c
@@ -257,6 +257,9 @@ static const struct clk_ops dpll1_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_noncore_dpll_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate,
};
@@ -367,6 +370,9 @@ static const struct clk_ops dpll4_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_dpll4_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate,
};
diff --git a/arch/arm/mach-omap2/clock.c b/arch/arm/mach-omap2/clock.c
index 500530d..6ad5b4d 100644
--- a/arch/arm/mach-omap2/clock.c
+++ b/arch/arm/mach-omap2/clock.c
@@ -171,7 +171,8 @@ static void _omap2_module_wait_ready(struct clk_hw_omap *clk)
_wait_idlest_generic(clk, idlest_reg, (1 << idlest_bit),
idlest_val, __clk_get_name(clk->hw.clk));
} else {
- cm_wait_module_ready(prcm_mod, idlest_reg_id, idlest_bit);
+ omap_cm_wait_module_ready(0, prcm_mod, idlest_reg_id,
+ idlest_bit);
};
}
@@ -771,4 +772,8 @@ void __init ti_clk_init_features(void)
ti_clk_features.cm_idlest_val = OMAP24XX_CM_IDLEST_VAL;
else if (cpu_is_omap34xx())
ti_clk_features.cm_idlest_val = OMAP34XX_CM_IDLEST_VAL;
+
+ /* On OMAP3430 ES1.0, DPLL4 can't be re-programmed */
+ if (omap_rev() == OMAP3430_REV_ES1_0)
+ ti_clk_features.flags |= TI_CLK_DPLL4_DENY_REPROGRAM;
}
diff --git a/arch/arm/mach-omap2/clock.h b/arch/arm/mach-omap2/clock.h
index 4592a27..641337c 100644
--- a/arch/arm/mach-omap2/clock.h
+++ b/arch/arm/mach-omap2/clock.h
@@ -234,6 +234,7 @@ struct ti_clk_features {
};
#define TI_CLK_DPLL_HAS_FREQSEL (1 << 0)
+#define TI_CLK_DPLL4_DENY_REPROGRAM (1 << 1)
extern struct ti_clk_features ti_clk_features;
diff --git a/arch/arm/mach-omap2/clock3xxx.c b/arch/arm/mach-omap2/clock3xxx.c
index 0b02b41..a9e86db 100644
--- a/arch/arm/mach-omap2/clock3xxx.c
+++ b/arch/arm/mach-omap2/clock3xxx.c
@@ -38,6 +38,18 @@
/* needed by omap3_core_dpll_m2_set_rate() */
struct clk *sdrc_ick_p, *arm_fck_p;
+
+/**
+ * omap3_dpll4_set_rate - set rate for omap3 per-dpll
+ * @hw: clock to change
+ * @rate: target rate for clock
+ * @parent_rate: rate of the parent clock
+ *
+ * Check if the current SoC supports the per-dpll reprogram operation
+ * or not, and then do the rate change if supported. Returns -EINVAL
+ * if not supported, 0 for success, and potential error codes from the
+ * clock rate change.
+ */
int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
@@ -46,7 +58,7 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
* on 3430ES1 prevents us from changing DPLL multipliers or dividers
* on DPLL4.
*/
- if (omap_rev() == OMAP3430_REV_ES1_0) {
+ if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
return -EINVAL;
}
@@ -54,6 +66,30 @@ int omap3_dpll4_set_rate(struct clk_hw *hw, unsigned long rate,
return omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
}
+/**
+ * omap3_dpll4_set_rate_and_parent - set rate and parent for omap3 per-dpll
+ * @hw: clock to change
+ * @rate: target rate for clock
+ * @parent_rate: rate of the parent clock
+ * @index: parent index, 0 - reference clock, 1 - bypass clock
+ *
+ * Check if the current SoC support the per-dpll reprogram operation
+ * or not, and then do the rate + parent change if supported. Returns
+ * -EINVAL if not supported, 0 for success, and potential error codes
+ * from the clock rate change.
+ */
+int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index)
+{
+ if (ti_clk_features.flags & TI_CLK_DPLL4_DENY_REPROGRAM) {
+ pr_err("clock: DPLL4 cannot change rate due to silicon 'Limitation 2.5' on 3430ES1.\n");
+ return -EINVAL;
+ }
+
+ return omap3_noncore_dpll_set_rate_and_parent(hw, rate, parent_rate,
+ index);
+}
+
void __init omap3_clk_lock_dpll5(void)
{
struct clk *dpll5_clk;
diff --git a/arch/arm/mach-omap2/cm.h b/arch/arm/mach-omap2/cm.h
index 93473f9..6222e87 100644
--- a/arch/arm/mach-omap2/cm.h
+++ b/arch/arm/mach-omap2/cm.h
@@ -45,17 +45,29 @@ extern void omap2_set_globals_cm(void __iomem *cm, void __iomem *cm2);
* struct cm_ll_data - fn ptrs to per-SoC CM function implementations
* @split_idlest_reg: ptr to the SoC CM-specific split_idlest_reg impl
* @wait_module_ready: ptr to the SoC CM-specific wait_module_ready impl
+ * @wait_module_idle: ptr to the SoC CM-specific wait_module_idle impl
+ * @module_enable: ptr to the SoC CM-specific module_enable impl
+ * @module_disable: ptr to the SoC CM-specific module_disable impl
*/
struct cm_ll_data {
int (*split_idlest_reg)(void __iomem *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id);
- int (*wait_module_ready)(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);
+ int (*wait_module_ready)(u8 part, s16 prcm_mod, u16 idlest_reg,
+ u8 idlest_shift);
+ int (*wait_module_idle)(u8 part, s16 prcm_mod, u16 idlest_reg,
+ u8 idlest_shift);
+ void (*module_enable)(u8 mode, u8 part, u16 inst, u16 clkctrl_offs);
+ void (*module_disable)(u8 part, u16 inst, u16 clkctrl_offs);
};
extern int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
u8 *idlest_reg_id);
-extern int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift);
-
+int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg,
+ u8 idlest_shift);
+int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg,
+ u8 idlest_shift);
+int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs);
+int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs);
extern int cm_register(struct cm_ll_data *cld);
extern int cm_unregister(struct cm_ll_data *cld);
diff --git a/arch/arm/mach-omap2/cm1_44xx.h b/arch/arm/mach-omap2/cm1_44xx.h
index 5ae8fe3..a594992 100644
--- a/arch/arm/mach-omap2/cm1_44xx.h
+++ b/arch/arm/mach-omap2/cm1_44xx.h
@@ -25,8 +25,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM1_44XX_H
#define __ARCH_ARM_MACH_OMAP2_CM1_44XX_H
-#include "cm_44xx_54xx.h"
-
/* CM1 base address */
#define OMAP4430_CM1_BASE 0x4a004000
diff --git a/arch/arm/mach-omap2/cm1_54xx.h b/arch/arm/mach-omap2/cm1_54xx.h
index 90b3348..fd245df 100644
--- a/arch/arm/mach-omap2/cm1_54xx.h
+++ b/arch/arm/mach-omap2/cm1_54xx.h
@@ -22,8 +22,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM1_54XX_H
#define __ARCH_ARM_MACH_OMAP2_CM1_54XX_H
-#include "cm_44xx_54xx.h"
-
/* CM1 base address */
#define OMAP54XX_CM_CORE_AON_BASE 0x4a004000
diff --git a/arch/arm/mach-omap2/cm1_7xx.h b/arch/arm/mach-omap2/cm1_7xx.h
index ca6fa1f..2f1c09e 100644
--- a/arch/arm/mach-omap2/cm1_7xx.h
+++ b/arch/arm/mach-omap2/cm1_7xx.h
@@ -23,8 +23,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM1_7XX_H
#define __ARCH_ARM_MACH_OMAP2_CM1_7XX_H
-#include "cm_44xx_54xx.h"
-
/* CM1 base address */
#define DRA7XX_CM_CORE_AON_BASE 0x4a005000
diff --git a/arch/arm/mach-omap2/cm2_44xx.h b/arch/arm/mach-omap2/cm2_44xx.h
index ee5136d..7521abf 100644
--- a/arch/arm/mach-omap2/cm2_44xx.h
+++ b/arch/arm/mach-omap2/cm2_44xx.h
@@ -25,8 +25,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM2_44XX_H
#define __ARCH_ARM_MACH_OMAP2_CM2_44XX_H
-#include "cm_44xx_54xx.h"
-
/* CM2 base address */
#define OMAP4430_CM2_BASE 0x4a008000
diff --git a/arch/arm/mach-omap2/cm2_54xx.h b/arch/arm/mach-omap2/cm2_54xx.h
index 2683231..ff4040c 100644
--- a/arch/arm/mach-omap2/cm2_54xx.h
+++ b/arch/arm/mach-omap2/cm2_54xx.h
@@ -21,8 +21,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM2_54XX_H
#define __ARCH_ARM_MACH_OMAP2_CM2_54XX_H
-#include "cm_44xx_54xx.h"
-
/* CM2 base address */
#define OMAP54XX_CM_CORE_BASE 0x4a008000
diff --git a/arch/arm/mach-omap2/cm2_7xx.h b/arch/arm/mach-omap2/cm2_7xx.h
index e966e3a..ce63fdb 100644
--- a/arch/arm/mach-omap2/cm2_7xx.h
+++ b/arch/arm/mach-omap2/cm2_7xx.h
@@ -22,8 +22,6 @@
#ifndef __ARCH_ARM_MACH_OMAP2_CM2_7XX_H
#define __ARCH_ARM_MACH_OMAP2_CM2_7XX_H
-#include "cm_44xx_54xx.h"
-
/* CM2 base address */
#define DRA7XX_CM_CORE_BASE 0x4a008000
diff --git a/arch/arm/mach-omap2/cm2xxx.c b/arch/arm/mach-omap2/cm2xxx.c
index 8be6ea5..a96d901 100644
--- a/arch/arm/mach-omap2/cm2xxx.c
+++ b/arch/arm/mach-omap2/cm2xxx.c
@@ -53,7 +53,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask)
omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL);
}
-bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
+static bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
{
u32 v;
@@ -64,12 +64,12 @@ bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
return (v == OMAP24XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0;
}
-void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
+static void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
{
_write_clktrctrl(OMAP24XX_CLKSTCTRL_ENABLE_AUTO, module, mask);
}
-void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
+static void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
{
_write_clktrctrl(OMAP24XX_CLKSTCTRL_DISABLE_AUTO, module, mask);
}
@@ -150,7 +150,7 @@ static int _omap2xxx_apll_enable(u8 enable_bit, u8 status_bit)
v |= m;
omap2_cm_write_mod_reg(v, PLL_MOD, CM_CLKEN);
- omap2xxx_cm_wait_module_ready(PLL_MOD, 1, status_bit);
+ omap2xxx_cm_wait_module_ready(0, PLL_MOD, 1, status_bit);
/*
* REVISIT: Should we return an error code if
@@ -204,8 +204,9 @@ void omap2xxx_cm_apll96_disable(void)
* XXX This function is only needed until absolute register addresses are
* removed from the OMAP struct clk records.
*/
-int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
- u8 *idlest_reg_id)
+static int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
+ s16 *prcm_inst,
+ u8 *idlest_reg_id)
{
unsigned long offs;
u8 idlest_offs;
@@ -238,6 +239,7 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
/**
* omap2xxx_cm_wait_module_ready - wait for a module to leave idle or standby
+ * @part: PRCM partition, ignored for OMAP2
* @prcm_mod: PRCM module offset
* @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check
@@ -246,7 +248,8 @@ int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
* (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
* success or -EBUSY if the module doesn't enable in time.
*/
-int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
+int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
+ u8 idlest_shift)
{
int ena = 0, i = 0;
u8 cm_idlest_reg;
diff --git a/arch/arm/mach-omap2/cm2xxx.h b/arch/arm/mach-omap2/cm2xxx.h
index 891d81c..c89502b 100644
--- a/arch/arm/mach-omap2/cm2xxx.h
+++ b/arch/arm/mach-omap2/cm2xxx.h
@@ -46,9 +46,6 @@
#ifndef __ASSEMBLER__
-extern void omap2xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask);
-extern void omap2xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
-
extern void omap2xxx_cm_set_dpll_disable_autoidle(void);
extern void omap2xxx_cm_set_dpll_auto_low_power_stop(void);
@@ -57,11 +54,8 @@ extern void omap2xxx_cm_set_apll54_auto_low_power_stop(void);
extern void omap2xxx_cm_set_apll96_disable_autoidle(void);
extern void omap2xxx_cm_set_apll96_auto_low_power_stop(void);
-extern bool omap2xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
-extern int omap2xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
- u8 idlest_shift);
-extern int omap2xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
- s16 *prcm_inst, u8 *idlest_reg_id);
+int omap2xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
+ u8 idlest_shift);
extern int omap2xxx_cm_fclks_active(void);
extern int omap2xxx_cm_mpu_retention_allowed(void);
extern u32 omap2xxx_cm_get_core_clk_src(void);
diff --git a/arch/arm/mach-omap2/cm33xx.c b/arch/arm/mach-omap2/cm33xx.c
index b3f99e9..b9ad463 100644
--- a/arch/arm/mach-omap2/cm33xx.c
+++ b/arch/arm/mach-omap2/cm33xx.c
@@ -96,13 +96,12 @@ static inline u32 am33xx_cm_read_reg_bits(u16 inst, s16 idx, u32 mask)
/**
* _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
* bit 0.
*/
-static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static u32 _clkctrl_idlest(u16 inst, u16 clkctrl_offs)
{
u32 v = am33xx_cm_read_reg(inst, clkctrl_offs);
v &= AM33XX_IDLEST_MASK;
@@ -113,17 +112,16 @@ static u32 _clkctrl_idlest(u16 inst, s16 cdoffs, u16 clkctrl_offs)
/**
* _is_module_ready - can module registers be accessed without causing an abort?
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
* *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
*/
-static bool _is_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static bool _is_module_ready(u16 inst, u16 clkctrl_offs)
{
u32 v;
- v = _clkctrl_idlest(inst, cdoffs, clkctrl_offs);
+ v = _clkctrl_idlest(inst, clkctrl_offs);
return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
@@ -158,7 +156,7 @@ static void _clktrctrl_write(u8 c, u16 inst, u16 cdoffs)
* Returns true if the clockdomain referred to by (@inst, @cdoffs)
* is in hardware-supervised idle mode, or 0 otherwise.
*/
-bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
+static bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
{
u32 v;
@@ -177,7 +175,7 @@ bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs)
* Put a clockdomain referred to by (@inst, @cdoffs) into
* hardware-supervised idle mode. No return value.
*/
-void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
+static void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, inst, cdoffs);
}
@@ -191,7 +189,7 @@ void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs)
* software-supervised idle mode, i.e., controlled manually by the
* Linux OMAP clockdomain code. No return value.
*/
-void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
+static void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, inst, cdoffs);
}
@@ -204,7 +202,7 @@ void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs)
* Put a clockdomain referred to by (@inst, @cdoffs) into idle
* No return value.
*/
-void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
+static void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, inst, cdoffs);
}
@@ -217,7 +215,7 @@ void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs)
* Take a clockdomain referred to by (@inst, @cdoffs) out of idle,
* waking it up. No return value.
*/
-void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
+static void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, inst, cdoffs);
}
@@ -228,20 +226,22 @@ void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs)
/**
* am33xx_cm_wait_module_ready - wait for a module to be in 'func' state
+ * @part: PRCM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ * @bit_shift: bit shift for the register, ignored for AM33xx
*
* Wait for the module IDLEST to be functional. If the idle state is in any
* the non functional state (trans, idle or disabled), module and thus the
* sysconfig cannot be accessed and will probably lead to an "imprecise
* external abort"
*/
-int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static int am33xx_cm_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
+ u8 bit_shift)
{
int i = 0;
- omap_test_timeout(_is_module_ready(inst, cdoffs, clkctrl_offs),
+ omap_test_timeout(_is_module_ready(inst, clkctrl_offs),
MAX_MODULE_READY_TIME, i);
return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
@@ -250,22 +250,24 @@ int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs, u16 clkctrl_offs)
/**
* am33xx_cm_wait_module_idle - wait for a module to be in 'disabled'
* state
+ * @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ * @bit_shift: bit shift for the register, ignored for AM33xx
*
* Wait for the module IDLEST to be disabled. Some PRCM transition,
* like reset assertion or parent clock de-activation must wait the
* module to be fully disabled.
*/
-int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static int am33xx_cm_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
+ u8 bit_shift)
{
int i = 0;
if (!clkctrl_offs)
return 0;
- omap_test_timeout((_clkctrl_idlest(inst, cdoffs, clkctrl_offs) ==
+ omap_test_timeout((_clkctrl_idlest(inst, clkctrl_offs) ==
CLKCTRL_IDLEST_DISABLED),
MAX_MODULE_READY_TIME, i);
@@ -275,13 +277,14 @@ int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs, u16 clkctrl_offs)
/**
* am33xx_cm_module_enable - Enable the modulemode inside CLKCTRL
* @mode: Module mode (SW or HW)
+ * @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* No return value.
*/
-void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static void am33xx_cm_module_enable(u8 mode, u8 part, u16 inst,
+ u16 clkctrl_offs)
{
u32 v;
@@ -293,13 +296,13 @@ void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs, u16 clkctrl_offs)
/**
* am33xx_cm_module_disable - Disable the module inside CLKCTRL
+ * @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* No return value.
*/
-void am33xx_cm_module_disable(u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static void am33xx_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
{
u32 v;
@@ -362,3 +365,21 @@ struct clkdm_ops am33xx_clkdm_operations = {
.clkdm_clk_enable = am33xx_clkdm_clk_enable,
.clkdm_clk_disable = am33xx_clkdm_clk_disable,
};
+
+static struct cm_ll_data am33xx_cm_ll_data = {
+ .wait_module_ready = &am33xx_cm_wait_module_ready,
+ .wait_module_idle = &am33xx_cm_wait_module_idle,
+ .module_enable = &am33xx_cm_module_enable,
+ .module_disable = &am33xx_cm_module_disable,
+};
+
+int __init am33xx_cm_init(void)
+{
+ return cm_register(&am33xx_cm_ll_data);
+}
+
+static void __exit am33xx_cm_exit(void)
+{
+ cm_unregister(&am33xx_cm_ll_data);
+}
+__exitcall(am33xx_cm_exit);
diff --git a/arch/arm/mach-omap2/cm33xx.h b/arch/arm/mach-omap2/cm33xx.h
index bd24417..046b4b2 100644
--- a/arch/arm/mach-omap2/cm33xx.h
+++ b/arch/arm/mach-omap2/cm33xx.h
@@ -374,41 +374,6 @@
#ifndef __ASSEMBLER__
-bool am33xx_cm_is_clkdm_in_hwsup(u16 inst, u16 cdoffs);
-void am33xx_cm_clkdm_enable_hwsup(u16 inst, u16 cdoffs);
-void am33xx_cm_clkdm_disable_hwsup(u16 inst, u16 cdoffs);
-void am33xx_cm_clkdm_force_sleep(u16 inst, u16 cdoffs);
-void am33xx_cm_clkdm_force_wakeup(u16 inst, u16 cdoffs);
-
-#if defined(CONFIG_SOC_AM33XX) || defined(CONFIG_SOC_AM43XX)
-extern int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-extern void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-extern void am33xx_cm_module_disable(u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-extern int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-#else
-static inline int am33xx_cm_wait_module_idle(u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
-{
- return 0;
-}
-static inline void am33xx_cm_module_enable(u8 mode, u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
-{
-}
-static inline void am33xx_cm_module_disable(u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
-{
-}
-static inline int am33xx_cm_wait_module_ready(u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
-{
- return 0;
-}
-#endif
-
+int am33xx_cm_init(void);
#endif /* ASSEMBLER */
#endif
diff --git a/arch/arm/mach-omap2/cm3xxx.c b/arch/arm/mach-omap2/cm3xxx.c
index 129a4e7..ebead8f 100644
--- a/arch/arm/mach-omap2/cm3xxx.c
+++ b/arch/arm/mach-omap2/cm3xxx.c
@@ -42,7 +42,7 @@ static void _write_clktrctrl(u8 c, s16 module, u32 mask)
omap2_cm_write_mod_reg(v, module, OMAP2_CM_CLKSTCTRL);
}
-bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
+static bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
{
u32 v;
@@ -53,22 +53,22 @@ bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask)
return (v == OMAP34XX_CLKSTCTRL_ENABLE_AUTO) ? 1 : 0;
}
-void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
+static void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask)
{
_write_clktrctrl(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, module, mask);
}
-void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
+static void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask)
{
_write_clktrctrl(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, module, mask);
}
-void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask)
+static void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask)
{
_write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, module, mask);
}
-void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
+static void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
{
_write_clktrctrl(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, module, mask);
}
@@ -79,6 +79,7 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
/**
* omap3xxx_cm_wait_module_ready - wait for a module to leave idle or standby
+ * @part: PRCM partition, ignored for OMAP3
* @prcm_mod: PRCM module offset
* @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check
@@ -87,7 +88,8 @@ void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask)
* (@prcm_mod, @idlest_id, @idlest_shift) is clocked. Return 0 upon
* success or -EBUSY if the module doesn't enable in time.
*/
-int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
+static int omap3xxx_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_id,
+ u8 idlest_shift)
{
int ena = 0, i = 0;
u8 cm_idlest_reg;
@@ -116,8 +118,9 @@ int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
* XXX This function is only needed until absolute register addresses are
* removed from the OMAP struct clk records.
*/
-int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
- u8 *idlest_reg_id)
+static int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
+ s16 *prcm_inst,
+ u8 *idlest_reg_id)
{
unsigned long offs;
u8 idlest_offs;
diff --git a/arch/arm/mach-omap2/cm3xxx.h b/arch/arm/mach-omap2/cm3xxx.h
index 7a16b55..734a858 100644
--- a/arch/arm/mach-omap2/cm3xxx.h
+++ b/arch/arm/mach-omap2/cm3xxx.h
@@ -68,18 +68,6 @@
#ifndef __ASSEMBLER__
-extern void omap3xxx_cm_clkdm_enable_hwsup(s16 module, u32 mask);
-extern void omap3xxx_cm_clkdm_disable_hwsup(s16 module, u32 mask);
-extern void omap3xxx_cm_clkdm_force_sleep(s16 module, u32 mask);
-extern void omap3xxx_cm_clkdm_force_wakeup(s16 module, u32 mask);
-
-extern bool omap3xxx_cm_is_clkdm_in_hwsup(s16 module, u32 mask);
-extern int omap3xxx_cm_wait_module_ready(s16 prcm_mod, u8 idlest_id,
- u8 idlest_shift);
-
-extern int omap3xxx_cm_split_idlest_reg(void __iomem *idlest_reg,
- s16 *prcm_inst, u8 *idlest_reg_id);
-
extern void omap3_cm_save_context(void);
extern void omap3_cm_restore_context(void);
extern void omap3_cm_save_scratchpad_contents(u32 *ptr);
diff --git a/arch/arm/mach-omap2/cm44xx.c b/arch/arm/mach-omap2/cm44xx.c
deleted file mode 100644
index fe5cc7b..0000000
--- a/arch/arm/mach-omap2/cm44xx.c
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * OMAP4 CM1, CM2 module low-level functions
- *
- * Copyright (C) 2010 Nokia Corporation
- * Paul Walmsley
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * These functions are intended to be used only by the cminst44xx.c file.
- * XXX Perhaps we should just move them there and make them static.
- */
-
-#include <linux/kernel.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/err.h>
-#include <linux/io.h>
-
-#include "cm.h"
-#include "cm1_44xx.h"
-#include "cm2_44xx.h"
-
-/* CM1 hardware module low-level functions */
-
-/* Read a register in CM1 */
-u32 omap4_cm1_read_inst_reg(s16 inst, u16 reg)
-{
- return readl_relaxed(cm_base + inst + reg);
-}
-
-/* Write into a register in CM1 */
-void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 reg)
-{
- writel_relaxed(val, cm_base + inst + reg);
-}
-
-/* Read a register in CM2 */
-u32 omap4_cm2_read_inst_reg(s16 inst, u16 reg)
-{
- return readl_relaxed(cm2_base + inst + reg);
-}
-
-/* Write into a register in CM2 */
-void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 reg)
-{
- writel_relaxed(val, cm2_base + inst + reg);
-}
diff --git a/arch/arm/mach-omap2/cm44xx.h b/arch/arm/mach-omap2/cm44xx.h
index 3380bee..728d06a 100644
--- a/arch/arm/mach-omap2/cm44xx.h
+++ b/arch/arm/mach-omap2/cm44xx.h
@@ -23,4 +23,7 @@
#define OMAP4_CM_CLKSTCTRL 0x0000
#define OMAP4_CM_STATICDEP 0x0004
+void omap_cm_base_init(void);
+int omap4_cm_init(void);
+
#endif
diff --git a/arch/arm/mach-omap2/cm_44xx_54xx.h b/arch/arm/mach-omap2/cm_44xx_54xx.h
deleted file mode 100644
index cbb2116..0000000
--- a/arch/arm/mach-omap2/cm_44xx_54xx.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * OMAP44xx and OMAP54xx CM1/CM2 function prototypes
- *
- * Copyright (C) 2009-2013 Texas Instruments, Inc.
- * Copyright (C) 2009-2010 Nokia Corporation
- *
- * Paul Walmsley (paul@pwsan.com)
- * Rajendra Nayak (rnayak@ti.com)
- * Benoit Cousson (b-cousson@ti.com)
- *
- * This file is automatically generated from the OMAP hardware databases.
- * We respectfully ask that any modifications to this file be coordinated
- * with the public linux-omap@vger.kernel.org mailing list and the
- * authors above to ensure that the autogeneration scripts are kept
- * up-to-date with the file contents.
- *
- * This program is free software; you can 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 __ARCH_ARM_MACH_OMAP2_CM_44XX_54XX_H
-#define __ARCH_ARM_MACH_OMAP2_CM_44XX_55XX_H
-
-/* CM1 Function prototypes */
-extern u32 omap4_cm1_read_inst_reg(s16 inst, u16 idx);
-extern void omap4_cm1_write_inst_reg(u32 val, s16 inst, u16 idx);
-extern u32 omap4_cm1_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
-
-/* CM2 Function prototypes */
-extern u32 omap4_cm2_read_inst_reg(s16 inst, u16 idx);
-extern void omap4_cm2_write_inst_reg(u32 val, s16 inst, u16 idx);
-extern u32 omap4_cm2_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
-
-#endif
diff --git a/arch/arm/mach-omap2/cm_common.c b/arch/arm/mach-omap2/cm_common.c
index 8f6c471..8fe02fce 100644
--- a/arch/arm/mach-omap2/cm_common.c
+++ b/arch/arm/mach-omap2/cm_common.c
@@ -72,9 +72,10 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
}
/**
- * cm_wait_module_ready - wait for a module to leave idle or standby
+ * omap_cm_wait_module_ready - wait for a module to leave idle or standby
+ * @part: PRCM partition
* @prcm_mod: PRCM module offset
- * @idlest_id: CM_IDLESTx register ID (i.e., x = 1, 2, 3)
+ * @idlest_reg: CM_IDLESTx register
* @idlest_shift: shift of the bit in the CM_IDLEST* register to check
*
* Wait for the PRCM to indicate that the module identified by
@@ -83,7 +84,8 @@ int cm_split_idlest_reg(void __iomem *idlest_reg, s16 *prcm_inst,
* no per-SoC wait_module_ready() function pointer has been registered
* or if the idlest register is unknown on the SoC.
*/
-int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
+int omap_cm_wait_module_ready(u8 part, s16 prcm_mod, u16 idlest_reg,
+ u8 idlest_shift)
{
if (!cm_ll_data->wait_module_ready) {
WARN_ONCE(1, "cm: %s: no low-level function defined\n",
@@ -91,7 +93,79 @@ int cm_wait_module_ready(s16 prcm_mod, u8 idlest_id, u8 idlest_shift)
return -EINVAL;
}
- return cm_ll_data->wait_module_ready(prcm_mod, idlest_id, idlest_shift);
+ return cm_ll_data->wait_module_ready(part, prcm_mod, idlest_reg,
+ idlest_shift);
+}
+
+/**
+ * omap_cm_wait_module_idle - wait for a module to enter idle or standby
+ * @part: PRCM partition
+ * @prcm_mod: PRCM module offset
+ * @idlest_reg: CM_IDLESTx register
+ * @idlest_shift: shift of the bit in the CM_IDLEST* register to check
+ *
+ * Wait for the PRCM to indicate that the module identified by
+ * (@prcm_mod, @idlest_id, @idlest_shift) is no longer clocked. Return
+ * 0 upon success, -EBUSY if the module doesn't enable in time, or
+ * -EINVAL if no per-SoC wait_module_idle() function pointer has been
+ * registered or if the idlest register is unknown on the SoC.
+ */
+int omap_cm_wait_module_idle(u8 part, s16 prcm_mod, u16 idlest_reg,
+ u8 idlest_shift)
+{
+ if (!cm_ll_data->wait_module_idle) {
+ WARN_ONCE(1, "cm: %s: no low-level function defined\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return cm_ll_data->wait_module_idle(part, prcm_mod, idlest_reg,
+ idlest_shift);
+}
+
+/**
+ * omap_cm_module_enable - enable a module
+ * @mode: target mode for the module
+ * @part: PRCM partition
+ * @inst: PRCM instance
+ * @clkctrl_offs: CM_CLKCTRL register offset for the module
+ *
+ * Enables clocks for a module identified by (@part, @inst, @clkctrl_offs)
+ * making its IO space accessible. Return 0 upon success, -EINVAL if no
+ * per-SoC module_enable() function pointer has been registered.
+ */
+int omap_cm_module_enable(u8 mode, u8 part, u16 inst, u16 clkctrl_offs)
+{
+ if (!cm_ll_data->module_enable) {
+ WARN_ONCE(1, "cm: %s: no low-level function defined\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ cm_ll_data->module_enable(mode, part, inst, clkctrl_offs);
+ return 0;
+}
+
+/**
+ * omap_cm_module_disable - disable a module
+ * @part: PRCM partition
+ * @inst: PRCM instance
+ * @clkctrl_offs: CM_CLKCTRL register offset for the module
+ *
+ * Disables clocks for a module identified by (@part, @inst, @clkctrl_offs)
+ * makings its IO space inaccessible. Return 0 upon success, -EINVAL if
+ * no per-SoC module_disable() function pointer has been registered.
+ */
+int omap_cm_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
+{
+ if (!cm_ll_data->module_disable) {
+ WARN_ONCE(1, "cm: %s: no low-level function defined\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ cm_ll_data->module_disable(part, inst, clkctrl_offs);
+ return 0;
}
/**
diff --git a/arch/arm/mach-omap2/cminst44xx.c b/arch/arm/mach-omap2/cminst44xx.c
index 12aca56..95a8cff 100644
--- a/arch/arm/mach-omap2/cminst44xx.c
+++ b/arch/arm/mach-omap2/cminst44xx.c
@@ -26,7 +26,6 @@
#include "cm1_44xx.h"
#include "cm2_44xx.h"
#include "cm44xx.h"
-#include "cminst44xx.h"
#include "cm-regbits-34xx.h"
#include "prcm44xx.h"
#include "prm44xx.h"
@@ -74,17 +73,18 @@ void omap_cm_base_init(void)
/* Private functions */
+static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
+
/**
* _clkctrl_idlest - read a CM_*_CLKCTRL register; mask & shift IDLEST bitfield
* @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* Return the IDLEST bitfield of a CM_*_CLKCTRL register, shifted down to
* bit 0.
*/
-static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static u32 _clkctrl_idlest(u8 part, u16 inst, u16 clkctrl_offs)
{
u32 v = omap4_cminst_read_inst_reg(part, inst, clkctrl_offs);
v &= OMAP4430_IDLEST_MASK;
@@ -96,26 +96,23 @@ static u32 _clkctrl_idlest(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
* _is_module_ready - can module registers be accessed without causing an abort?
* @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* Returns true if the module's CM_*_CLKCTRL.IDLEST bitfield is either
* *FUNCTIONAL or *INTERFACE_IDLE; false otherwise.
*/
-static bool _is_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static bool _is_module_ready(u8 part, u16 inst, u16 clkctrl_offs)
{
u32 v;
- v = _clkctrl_idlest(part, inst, cdoffs, clkctrl_offs);
+ v = _clkctrl_idlest(part, inst, clkctrl_offs);
return (v == CLKCTRL_IDLEST_FUNCTIONAL ||
v == CLKCTRL_IDLEST_INTERFACE_IDLE) ? true : false;
}
-/* Public functions */
-
/* Read a register in a CM instance */
-u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
+static u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
{
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION ||
@@ -124,7 +121,7 @@ u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx)
}
/* Write into a register in a CM instance */
-void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
+static void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
{
BUG_ON(part >= OMAP4_MAX_PRCM_PARTITIONS ||
part == OMAP4430_INVALID_PRCM_PARTITION ||
@@ -133,8 +130,8 @@ void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx)
}
/* Read-modify-write a register in CM1. Caller must lock */
-u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
- s16 idx)
+static u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
+ s16 idx)
{
u32 v;
@@ -146,17 +143,18 @@ u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part, u16 inst,
return v;
}
-u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
+static u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
{
return omap4_cminst_rmw_inst_reg_bits(bits, bits, part, inst, idx);
}
-u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst, s16 idx)
+static u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
+ s16 idx)
{
return omap4_cminst_rmw_inst_reg_bits(bits, 0x0, part, inst, idx);
}
-u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
+static u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx, u32 mask)
{
u32 v;
@@ -200,7 +198,7 @@ static void _clktrctrl_write(u8 c, u8 part, u16 inst, u16 cdoffs)
* Returns true if the clockdomain referred to by (@part, @inst, @cdoffs)
* is in hardware-supervised idle mode, or 0 otherwise.
*/
-bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
+static bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
{
u32 v;
@@ -220,7 +218,7 @@ bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs)
* Put a clockdomain referred to by (@part, @inst, @cdoffs) into
* hardware-supervised idle mode. No return value.
*/
-void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
+static void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_ENABLE_AUTO, part, inst, cdoffs);
}
@@ -235,7 +233,7 @@ void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs)
* software-supervised idle mode, i.e., controlled manually by the
* Linux OMAP clockdomain code. No return value.
*/
-void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
+static void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_DISABLE_AUTO, part, inst, cdoffs);
}
@@ -249,7 +247,7 @@ void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs)
* Take a clockdomain referred to by (@part, @inst, @cdoffs) out of idle,
* waking it up. No return value.
*/
-void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
+static void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_WAKEUP, part, inst, cdoffs);
}
@@ -258,7 +256,7 @@ void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs)
*
*/
-void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
+static void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
{
_clktrctrl_write(OMAP34XX_CLKSTCTRL_FORCE_SLEEP, part, inst, cdoffs);
}
@@ -267,23 +265,23 @@ void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs)
* omap4_cminst_wait_module_ready - wait for a module to be in 'func' state
* @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ * @bit_shift: bit shift for the register, ignored for OMAP4+
*
* Wait for the module IDLEST to be functional. If the idle state is in any
* the non functional state (trans, idle or disabled), module and thus the
* sysconfig cannot be accessed and will probably lead to an "imprecise
* external abort"
*/
-int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
+static int omap4_cminst_wait_module_ready(u8 part, s16 inst, u16 clkctrl_offs,
+ u8 bit_shift)
{
int i = 0;
if (!clkctrl_offs)
return 0;
- omap_test_timeout(_is_module_ready(part, inst, cdoffs, clkctrl_offs),
+ omap_test_timeout(_is_module_ready(part, inst, clkctrl_offs),
MAX_MODULE_READY_TIME, i);
return (i < MAX_MODULE_READY_TIME) ? 0 : -EBUSY;
@@ -294,21 +292,22 @@ int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs,
* state
* @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
+ * @bit_shift: Bit shift for the register, ignored for OMAP4+
*
* Wait for the module IDLEST to be disabled. Some PRCM transition,
* like reset assertion or parent clock de-activation must wait the
* module to be fully disabled.
*/
-int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs)
+static int omap4_cminst_wait_module_idle(u8 part, s16 inst, u16 clkctrl_offs,
+ u8 bit_shift)
{
int i = 0;
if (!clkctrl_offs)
return 0;
- omap_test_timeout((_clkctrl_idlest(part, inst, cdoffs, clkctrl_offs) ==
+ omap_test_timeout((_clkctrl_idlest(part, inst, clkctrl_offs) ==
CLKCTRL_IDLEST_DISABLED),
MAX_MODULE_DISABLE_TIME, i);
@@ -320,13 +319,12 @@ int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_off
* @mode: Module mode (SW or HW)
* @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* No return value.
*/
-void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
+static void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst,
+ u16 clkctrl_offs)
{
u32 v;
@@ -340,13 +338,11 @@ void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
* omap4_cminst_module_disable - Disable the module inside CLKCTRL
* @part: PRCM partition ID that the CM_CLKCTRL register exists in
* @inst: CM instance register offset (*_INST macro)
- * @cdoffs: Clockdomain register offset (*_CDOFFS macro)
* @clkctrl_offs: Module clock control register offset (*_CLKCTRL macro)
*
* No return value.
*/
-void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
- u16 clkctrl_offs)
+static void omap4_cminst_module_disable(u8 part, u16 inst, u16 clkctrl_offs)
{
u32 v;
@@ -510,3 +506,21 @@ struct clkdm_ops am43xx_clkdm_operations = {
.clkdm_clk_enable = omap4_clkdm_clk_enable,
.clkdm_clk_disable = omap4_clkdm_clk_disable,
};
+
+static struct cm_ll_data omap4xxx_cm_ll_data = {
+ .wait_module_ready = &omap4_cminst_wait_module_ready,
+ .wait_module_idle = &omap4_cminst_wait_module_idle,
+ .module_enable = &omap4_cminst_module_enable,
+ .module_disable = &omap4_cminst_module_disable,
+};
+
+int __init omap4_cm_init(void)
+{
+ return cm_register(&omap4xxx_cm_ll_data);
+}
+
+static void __exit omap4_cm_exit(void)
+{
+ cm_unregister(&omap4xxx_cm_ll_data);
+}
+__exitcall(omap4_cm_exit);
diff --git a/arch/arm/mach-omap2/cminst44xx.h b/arch/arm/mach-omap2/cminst44xx.h
deleted file mode 100644
index 7f56ea4..0000000
--- a/arch/arm/mach-omap2/cminst44xx.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * OMAP4 Clock Management (CM) function prototypes
- *
- * Copyright (C) 2010 Nokia Corporation
- * Paul Walmsley
- *
- * This program is free software; you can 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 __ARCH_ASM_MACH_OMAP2_CMINST44XX_H
-#define __ARCH_ASM_MACH_OMAP2_CMINST44XX_H
-
-bool omap4_cminst_is_clkdm_in_hwsup(u8 part, u16 inst, u16 cdoffs);
-void omap4_cminst_clkdm_enable_hwsup(u8 part, u16 inst, u16 cdoffs);
-void omap4_cminst_clkdm_disable_hwsup(u8 part, u16 inst, u16 cdoffs);
-void omap4_cminst_clkdm_force_sleep(u8 part, u16 inst, u16 cdoffs);
-void omap4_cminst_clkdm_force_wakeup(u8 part, u16 inst, u16 cdoffs);
-extern int omap4_cminst_wait_module_ready(u8 part, u16 inst, s16 cdoffs, u16 clkctrl_offs);
-extern int omap4_cminst_wait_module_idle(u8 part, u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-extern void omap4_cminst_module_enable(u8 mode, u8 part, u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-extern void omap4_cminst_module_disable(u8 part, u16 inst, s16 cdoffs,
- u16 clkctrl_offs);
-/*
- * In an ideal world, we would not export these low-level functions,
- * but this will probably take some time to fix properly
- */
-u32 omap4_cminst_read_inst_reg(u8 part, u16 inst, u16 idx);
-void omap4_cminst_write_inst_reg(u32 val, u8 part, u16 inst, u16 idx);
-u32 omap4_cminst_rmw_inst_reg_bits(u32 mask, u32 bits, u8 part,
- u16 inst, s16 idx);
-u32 omap4_cminst_set_inst_reg_bits(u32 bits, u8 part, u16 inst,
- s16 idx);
-u32 omap4_cminst_clear_inst_reg_bits(u32 bits, u8 part, u16 inst,
- s16 idx);
-extern u32 omap4_cminst_read_inst_reg_bits(u8 part, u16 inst, s16 idx,
- u32 mask);
-
-extern void omap_cm_base_init(void);
-
-#endif
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c b/arch/arm/mach-omap2/cpuidle34xx.c
index e18709d..aa7b379 100644
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -265,7 +265,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 2 + 2,
.target_residency = 5,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C1",
.desc = "MPU ON + CORE ON",
},
@@ -273,7 +272,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 10 + 10,
.target_residency = 30,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C2",
.desc = "MPU ON + CORE ON",
},
@@ -281,7 +279,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 50 + 50,
.target_residency = 300,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C3",
.desc = "MPU RET + CORE ON",
},
@@ -289,7 +286,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 1500 + 1800,
.target_residency = 4000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C4",
.desc = "MPU OFF + CORE ON",
},
@@ -297,7 +293,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 2500 + 7500,
.target_residency = 12000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C5",
.desc = "MPU RET + CORE RET",
},
@@ -305,7 +300,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 3000 + 8500,
.target_residency = 15000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C6",
.desc = "MPU OFF + CORE RET",
},
@@ -313,7 +307,6 @@ static struct cpuidle_driver omap3_idle_driver = {
.enter = omap3_enter_idle_bm,
.exit_latency = 10000 + 30000,
.target_residency = 30000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C7",
.desc = "MPU OFF + CORE OFF",
},
diff --git a/arch/arm/mach-omap2/cpuidle44xx.c b/arch/arm/mach-omap2/cpuidle44xx.c
index 2498ab0..01e398a 100644
--- a/arch/arm/mach-omap2/cpuidle44xx.c
+++ b/arch/arm/mach-omap2/cpuidle44xx.c
@@ -196,7 +196,6 @@ static struct cpuidle_driver omap4_idle_driver = {
/* C1 - CPU0 ON + CPU1 ON + MPU ON */
.exit_latency = 2 + 2,
.target_residency = 5,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = omap_enter_idle_simple,
.name = "C1",
.desc = "CPUx ON, MPUSS ON"
@@ -205,7 +204,7 @@ static struct cpuidle_driver omap4_idle_driver = {
/* C2 - CPU0 OFF + CPU1 OFF + MPU CSWR */
.exit_latency = 328 + 440,
.target_residency = 960,
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
+ .flags = CPUIDLE_FLAG_COUPLED,
.enter = omap_enter_idle_coupled,
.name = "C2",
.desc = "CPUx OFF, MPUSS CSWR",
@@ -214,7 +213,7 @@ static struct cpuidle_driver omap4_idle_driver = {
/* C3 - CPU0 OFF + CPU1 OFF + MPU OSWR */
.exit_latency = 460 + 518,
.target_residency = 1100,
- .flags = CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_COUPLED,
+ .flags = CPUIDLE_FLAG_COUPLED,
.enter = omap_enter_idle_coupled,
.name = "C3",
.desc = "CPUx OFF, MPUSS OSWR",
diff --git a/arch/arm/mach-omap2/devices.c b/arch/arm/mach-omap2/devices.c
index 324f02b..1afb50d 100644
--- a/arch/arm/mach-omap2/devices.c
+++ b/arch/arm/mach-omap2/devices.c
@@ -49,7 +49,7 @@ static int __init omap3_l3_init(void)
* To avoid code running on other OMAPs in
* multi-omap builds
*/
- if (!(cpu_is_omap34xx()))
+ if (!(cpu_is_omap34xx()) || of_have_populated_dt())
return -ENODEV;
snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main");
@@ -67,62 +67,6 @@ static int __init omap3_l3_init(void)
}
omap_postcore_initcall(omap3_l3_init);
-static int __init omap4_l3_init(void)
-{
- int i;
- struct omap_hwmod *oh[3];
- struct platform_device *pdev;
- char oh_name[L3_MODULES_MAX_LEN];
-
- /* If dtb is there, the devices will be created dynamically */
- if (of_have_populated_dt())
- return -ENODEV;
-
- /*
- * To avoid code running on other OMAPs in
- * multi-omap builds
- */
- if (!cpu_is_omap44xx() && !soc_is_omap54xx())
- return -ENODEV;
-
- for (i = 0; i < L3_MODULES; i++) {
- snprintf(oh_name, L3_MODULES_MAX_LEN, "l3_main_%d", i+1);
-
- oh[i] = omap_hwmod_lookup(oh_name);
- if (!(oh[i]))
- pr_err("could not look up %s\n", oh_name);
- }
-
- pdev = omap_device_build_ss("omap_l3_noc", 0, oh, 3, NULL, 0);
-
- WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
- return PTR_RET(pdev);
-}
-omap_postcore_initcall(omap4_l3_init);
-
-#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
-
-static struct resource omap2cam_resources[] = {
- {
- .start = OMAP24XX_CAMERA_BASE,
- .end = OMAP24XX_CAMERA_BASE + 0xfff,
- .flags = IORESOURCE_MEM,
- },
- {
- .start = 24 + OMAP_INTC_START,
- .flags = IORESOURCE_IRQ,
- }
-};
-
-static struct platform_device omap2cam_device = {
- .name = "omap24xxcam",
- .id = -1,
- .num_resources = ARRAY_SIZE(omap2cam_resources),
- .resource = omap2cam_resources,
-};
-#endif
-
#if defined(CONFIG_IOMMU_API)
#include <linux/platform_data/iommu-omap.h>
@@ -245,14 +189,6 @@ int omap3_init_camera(struct isp_platform_data *pdata)
#endif
-static inline void omap_init_camera(void)
-{
-#if defined(CONFIG_VIDEO_OMAP2) || defined(CONFIG_VIDEO_OMAP2_MODULE)
- if (cpu_is_omap24xx())
- platform_device_register(&omap2cam_device);
-#endif
-}
-
#if defined(CONFIG_OMAP2PLUS_MBOX) || defined(CONFIG_OMAP2PLUS_MBOX_MODULE)
static inline void __init omap_init_mbox(void)
{
@@ -431,7 +367,6 @@ static int __init omap2_init_devices(void)
* in alphabetical order so they're easier to sort through.
*/
omap_init_audio();
- omap_init_camera();
/* If dtb is there, the devices will be created dynamically */
if (!of_have_populated_dt()) {
omap_init_mbox();
@@ -445,3 +380,29 @@ static int __init omap2_init_devices(void)
return 0;
}
omap_arch_initcall(omap2_init_devices);
+
+static int __init omap_gpmc_init(void)
+{
+ struct omap_hwmod *oh;
+ struct platform_device *pdev;
+ char *oh_name = "gpmc";
+
+ /*
+ * if the board boots up with a populated DT, do not
+ * manually add the device from this initcall
+ */
+ if (of_have_populated_dt())
+ return -ENODEV;
+
+ oh = omap_hwmod_lookup(oh_name);
+ if (!oh) {
+ pr_err("Could not look up %s\n", oh_name);
+ return -ENODEV;
+ }
+
+ pdev = omap_device_build("omap-gpmc", -1, oh, NULL, 0);
+ WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
+
+ return PTR_RET(pdev);
+}
+omap_postcore_initcall(omap_gpmc_init);
diff --git a/arch/arm/mach-omap2/dpll3xxx.c b/arch/arm/mach-omap2/dpll3xxx.c
index ac3d789..20e120d 100644
--- a/arch/arm/mach-omap2/dpll3xxx.c
+++ b/arch/arm/mach-omap2/dpll3xxx.c
@@ -460,25 +460,24 @@ void omap3_noncore_dpll_disable(struct clk_hw *hw)
/* Non-CORE DPLL rate set code */
/**
- * omap3_noncore_dpll_set_rate - set non-core DPLL rate
- * @clk: struct clk * of DPLL to set
- * @rate: rounded target rate
+ * omap3_noncore_dpll_determine_rate - determine rate for a DPLL
+ * @hw: pointer to the clock to determine rate for
+ * @rate: target rate for the DPLL
+ * @best_parent_rate: pointer for returning best parent rate
+ * @best_parent_clk: pointer for returning best parent clock
*
- * Set the DPLL CLKOUT to the target rate. If the DPLL can enter
- * low-power bypass, and the target rate is the bypass source clock
- * rate, then configure the DPLL for bypass. Otherwise, round the
- * target rate if it hasn't been done already, then program and lock
- * the DPLL. Returns -EINVAL upon error, or 0 upon success.
+ * Determines which DPLL mode to use for reaching a desired target rate.
+ * Checks whether the DPLL shall be in bypass or locked mode, and if
+ * locked, calculates the M,N values for the DPLL via round-rate.
+ * Returns a positive clock rate with success, negative error value
+ * in failure.
*/
-int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
- unsigned long parent_rate)
+long omap3_noncore_dpll_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk)
{
struct clk_hw_omap *clk = to_clk_hw_omap(hw);
- struct clk *new_parent = NULL;
- unsigned long rrate;
- u16 freqsel = 0;
struct dpll_data *dd;
- int ret;
if (!hw || !rate)
return -EINVAL;
@@ -489,61 +488,121 @@ int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
if (__clk_get_rate(dd->clk_bypass) == rate &&
(dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
- pr_debug("%s: %s: set rate: entering bypass.\n",
- __func__, __clk_get_name(hw->clk));
+ *best_parent_clk = dd->clk_bypass;
+ } else {
+ rate = omap2_dpll_round_rate(hw, rate, best_parent_rate);
+ *best_parent_clk = dd->clk_ref;
+ }
+
+ *best_parent_rate = rate;
+
+ return rate;
+}
+
+/**
+ * omap3_noncore_dpll_set_parent - set parent for a DPLL clock
+ * @hw: pointer to the clock to set parent for
+ * @index: parent index to select
+ *
+ * Sets parent for a DPLL clock. This sets the DPLL into bypass or
+ * locked mode. Returns 0 with success, negative error value otherwise.
+ */
+int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ int ret;
- __clk_prepare(dd->clk_bypass);
- clk_enable(dd->clk_bypass);
+ if (!hw)
+ return -EINVAL;
+
+ if (index)
ret = _omap3_noncore_dpll_bypass(clk);
- if (!ret)
- new_parent = dd->clk_bypass;
- clk_disable(dd->clk_bypass);
- __clk_unprepare(dd->clk_bypass);
- } else {
- __clk_prepare(dd->clk_ref);
- clk_enable(dd->clk_ref);
-
- /* XXX this check is probably pointless in the CCF context */
- if (dd->last_rounded_rate != rate) {
- rrate = __clk_round_rate(hw->clk, rate);
- if (rrate != rate) {
- pr_warn("%s: %s: final rate %lu does not match desired rate %lu\n",
- __func__, __clk_get_name(hw->clk),
- rrate, rate);
- rate = rrate;
- }
- }
+ else
+ ret = _omap3_noncore_dpll_lock(clk);
- if (dd->last_rounded_rate == 0)
- return -EINVAL;
+ return ret;
+}
- /* Freqsel is available only on OMAP343X devices */
- if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
- freqsel = _omap3_dpll_compute_freqsel(clk,
- dd->last_rounded_n);
- WARN_ON(!freqsel);
- }
+/**
+ * omap3_noncore_dpll_set_rate - set rate for a DPLL clock
+ * @hw: pointer to the clock to set parent for
+ * @rate: target rate for the clock
+ * @parent_rate: rate of the parent clock
+ *
+ * Sets rate for a DPLL clock. First checks if the clock parent is
+ * reference clock (in bypass mode, the rate of the clock can't be
+ * changed) and proceeds with the rate change operation. Returns 0
+ * with success, negative error value otherwise.
+ */
+int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+ u16 freqsel = 0;
+ int ret;
+
+ if (!hw || !rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
- pr_debug("%s: %s: set rate: locking rate to %lu.\n",
- __func__, __clk_get_name(hw->clk), rate);
+ if (__clk_get_parent(hw->clk) != dd->clk_ref)
+ return -EINVAL;
+
+ if (dd->last_rounded_rate == 0)
+ return -EINVAL;
- ret = omap3_noncore_dpll_program(clk, freqsel);
- if (!ret)
- new_parent = dd->clk_ref;
- clk_disable(dd->clk_ref);
- __clk_unprepare(dd->clk_ref);
+ /* Freqsel is available only on OMAP343X devices */
+ if (ti_clk_features.flags & TI_CLK_DPLL_HAS_FREQSEL) {
+ freqsel = _omap3_dpll_compute_freqsel(clk, dd->last_rounded_n);
+ WARN_ON(!freqsel);
}
- /*
- * FIXME - this is all wrong. common code handles reparenting and
- * migrating prepare/enable counts. dplls should be a multiplexer
- * clock and this should be a set_parent operation so that all of that
- * stuff is inherited for free
- */
- if (!ret && clk_get_parent(hw->clk) != new_parent)
- __clk_reparent(hw->clk, new_parent);
+ pr_debug("%s: %s: set rate: locking rate to %lu.\n", __func__,
+ __clk_get_name(hw->clk), rate);
- return 0;
+ ret = omap3_noncore_dpll_program(clk, freqsel);
+
+ return ret;
+}
+
+/**
+ * omap3_noncore_dpll_set_rate_and_parent - set rate and parent for a DPLL clock
+ * @hw: pointer to the clock to set rate and parent for
+ * @rate: target rate for the DPLL
+ * @parent_rate: clock rate of the DPLL parent
+ * @index: new parent index for the DPLL, 0 - reference, 1 - bypass
+ *
+ * Sets rate and parent for a DPLL clock. If new parent is the bypass
+ * clock, only selects the parent. Otherwise proceeds with a rate
+ * change, as this will effectively also change the parent as the
+ * DPLL is put into locked mode. Returns 0 with success, negative error
+ * value otherwise.
+ */
+int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate,
+ u8 index)
+{
+ int ret;
+
+ if (!hw || !rate)
+ return -EINVAL;
+
+ /*
+ * clk-ref at index[0], in which case we only need to set rate,
+ * the parent will be changed automatically with the lock sequence.
+ * With clk-bypass case we only need to change parent.
+ */
+ if (index)
+ ret = omap3_noncore_dpll_set_parent(hw, index);
+ else
+ ret = omap3_noncore_dpll_set_rate(hw, rate, parent_rate);
+
+ return ret;
}
/* DPLL autoidle read/set code */
diff --git a/arch/arm/mach-omap2/dpll44xx.c b/arch/arm/mach-omap2/dpll44xx.c
index 4613f1e..535822f 100644
--- a/arch/arm/mach-omap2/dpll44xx.c
+++ b/arch/arm/mach-omap2/dpll44xx.c
@@ -207,3 +207,44 @@ out:
return dd->last_rounded_rate;
}
+
+/**
+ * omap4_dpll_regm4xen_determine_rate - determine rate for a DPLL
+ * @hw: pointer to the clock to determine rate for
+ * @rate: target rate for the DPLL
+ * @best_parent_rate: pointer for returning best parent rate
+ * @best_parent_clk: pointer for returning best parent clock
+ *
+ * Determines which DPLL mode to use for reaching a desired rate.
+ * Checks whether the DPLL shall be in bypass or locked mode, and if
+ * locked, calculates the M,N values for the DPLL via round-rate.
+ * Returns a positive clock rate with success, negative error value
+ * in failure.
+ */
+long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw, unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk)
+{
+ struct clk_hw_omap *clk = to_clk_hw_omap(hw);
+ struct dpll_data *dd;
+
+ if (!hw || !rate)
+ return -EINVAL;
+
+ dd = clk->dpll_data;
+ if (!dd)
+ return -EINVAL;
+
+ if (__clk_get_rate(dd->clk_bypass) == rate &&
+ (dd->modes & (1 << DPLL_LOW_POWER_BYPASS))) {
+ *best_parent_clk = dd->clk_bypass;
+ } else {
+ rate = omap4_dpll_regm4xen_round_rate(hw, rate,
+ best_parent_rate);
+ *best_parent_clk = dd->clk_ref;
+ }
+
+ *best_parent_rate = rate;
+
+ return rate;
+}
diff --git a/arch/arm/mach-omap2/gpmc-nand.c b/arch/arm/mach-omap2/gpmc-nand.c
index cb776431..d5951b1 100644
--- a/arch/arm/mach-omap2/gpmc-nand.c
+++ b/arch/arm/mach-omap2/gpmc-nand.c
@@ -12,14 +12,13 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/io.h>
+#include <linux/omap-gpmc.h>
#include <linux/mtd/nand.h>
#include <linux/platform_data/mtd-nand-omap2.h>
#include <asm/mach/flash.h>
-#include "gpmc.h"
#include "soc.h"
-#include "gpmc-nand.h"
/* minimum size for IO mapping */
#define NAND_IO_SIZE 4
diff --git a/arch/arm/mach-omap2/gpmc-nand.h b/arch/arm/mach-omap2/gpmc-nand.h
deleted file mode 100644
index d59e128..0000000
--- a/arch/arm/mach-omap2/gpmc-nand.h
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * arch/arm/mach-omap2/gpmc-nand.h
- *
- * 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 __OMAP2_GPMC_NAND_H
-#define __OMAP2_GPMC_NAND_H
-
-#include "gpmc.h"
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
-extern int gpmc_nand_init(struct omap_nand_platform_data *d,
- struct gpmc_timings *gpmc_t);
-#else
-static inline int gpmc_nand_init(struct omap_nand_platform_data *d,
- struct gpmc_timings *gpmc_t)
-{
- return 0;
-}
-#endif
-
-#endif
diff --git a/arch/arm/mach-omap2/gpmc-onenand.c b/arch/arm/mach-omap2/gpmc-onenand.c
index 8b6876c..53d197e 100644
--- a/arch/arm/mach-omap2/gpmc-onenand.c
+++ b/arch/arm/mach-omap2/gpmc-onenand.c
@@ -15,14 +15,13 @@
#include <linux/platform_device.h>
#include <linux/mtd/onenand_regs.h>
#include <linux/io.h>
+#include <linux/omap-gpmc.h>
#include <linux/platform_data/mtd-onenand-omap2.h>
#include <linux/err.h>
#include <asm/mach/flash.h>
-#include "gpmc.h"
#include "soc.h"
-#include "gpmc-onenand.h"
#define ONENAND_IO_SIZE SZ_128K
diff --git a/arch/arm/mach-omap2/gpmc-onenand.h b/arch/arm/mach-omap2/gpmc-onenand.h
deleted file mode 100644
index 216f23a..0000000
--- a/arch/arm/mach-omap2/gpmc-onenand.h
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- * arch/arm/mach-omap2/gpmc-onenand.h
- *
- * 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 __OMAP2_GPMC_ONENAND_H
-#define __OMAP2_GPMC_ONENAND_H
-
-#include <linux/platform_data/mtd-onenand-omap2.h>
-
-#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
-extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
-#else
-#define board_onenand_data NULL
-static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
-{
-}
-#endif
-
-#endif
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.c b/arch/arm/mach-omap2/gpmc-smc91x.c
deleted file mode 100644
index 61a0635..0000000
--- a/arch/arm/mach-omap2/gpmc-smc91x.c
+++ /dev/null
@@ -1,186 +0,0 @@
-/*
- * linux/arch/arm/mach-omap2/gpmc-smc91x.c
- *
- * Copyright (C) 2009 Nokia Corporation
- * Contact: Tony Lindgren
- *
- * This program is free software; you can 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/platform_device.h>
-#include <linux/gpio.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-#include <linux/smc91x.h>
-
-#include "gpmc.h"
-#include "gpmc-smc91x.h"
-
-#include "soc.h"
-
-static struct omap_smc91x_platform_data *gpmc_cfg;
-
-static struct resource gpmc_smc91x_resources[] = {
- [0] = {
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct smc91x_platdata gpmc_smc91x_info = {
- .flags = SMC91X_USE_16BIT | SMC91X_NOWAIT | SMC91X_IO_SHIFT_0,
- .leda = RPC_LED_100_10,
- .ledb = RPC_LED_TX_RX,
-};
-
-static struct platform_device gpmc_smc91x_device = {
- .name = "smc91x",
- .id = -1,
- .dev = {
- .platform_data = &gpmc_smc91x_info,
- },
- .num_resources = ARRAY_SIZE(gpmc_smc91x_resources),
- .resource = gpmc_smc91x_resources,
-};
-
-static struct gpmc_settings smc91x_settings = {
- .device_width = GPMC_DEVWIDTH_16BIT,
-};
-
-/*
- * Set the gpmc timings for smc91c96. The timings are taken
- * from the data sheet available at:
- * http://www.smsc.com/main/catalog/lan91c96.html
- * REVISIT: Level shifters can add at least to the access latency.
- */
-static int smc91c96_gpmc_retime(void)
-{
- struct gpmc_timings t;
- struct gpmc_device_timings dev_t;
- const int t3 = 10; /* Figure 12.2 read and 12.4 write */
- const int t4_r = 20; /* Figure 12.2 read */
- const int t4_w = 5; /* Figure 12.4 write */
- const int t5 = 25; /* Figure 12.2 read */
- const int t6 = 15; /* Figure 12.2 read */
- const int t7 = 5; /* Figure 12.4 write */
- const int t8 = 5; /* Figure 12.4 write */
- const int t20 = 185; /* Figure 12.2 read and 12.4 write */
-
- /*
- * FIXME: Calculate the address and data bus muxed timings.
- * Note that at least adv_rd_off needs to be changed according
- * to omap3430 TRM Figure 11-11. Are the sdp boards using the
- * FPGA in between smc91x and omap as the timings are different
- * from above?
- */
- if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
- return 0;
-
- memset(&dev_t, 0, sizeof(dev_t));
-
- dev_t.t_oeasu = t3 * 1000;
- dev_t.t_oe = t5 * 1000;
- dev_t.t_cez_r = t4_r * 1000;
- dev_t.t_oez = t6 * 1000;
- dev_t.t_rd_cycle = (t20 - t3) * 1000;
-
- dev_t.t_weasu = t3 * 1000;
- dev_t.t_wpl = t7 * 1000;
- dev_t.t_wph = t8 * 1000;
- dev_t.t_cez_w = t4_w * 1000;
- dev_t.t_wr_cycle = (t20 - t3) * 1000;
-
- gpmc_calc_timings(&t, &smc91x_settings, &dev_t);
-
- return gpmc_cs_set_timings(gpmc_cfg->cs, &t);
-}
-
-/*
- * Initialize smc91x device connected to the GPMC. Note that we
- * assume that pin multiplexing is done in the board-*.c file,
- * or in the bootloader.
- */
-void __init gpmc_smc91x_init(struct omap_smc91x_platform_data *board_data)
-{
- unsigned long cs_mem_base;
- int ret;
-
- gpmc_cfg = board_data;
-
- if (gpmc_cfg->flags & GPMC_TIMINGS_SMC91C96)
- gpmc_cfg->retime = smc91c96_gpmc_retime;
-
- if (gpmc_cs_request(gpmc_cfg->cs, SZ_16M, &cs_mem_base) < 0) {
- printk(KERN_ERR "Failed to request GPMC mem for smc91x\n");
- return;
- }
-
- gpmc_smc91x_resources[0].start = cs_mem_base + 0x300;
- gpmc_smc91x_resources[0].end = cs_mem_base + 0x30f;
- gpmc_smc91x_resources[1].flags |= (gpmc_cfg->flags & IRQF_TRIGGER_MASK);
-
- if (gpmc_cfg->flags & GPMC_MUX_ADD_DATA)
- smc91x_settings.mux_add_data = GPMC_MUX_AD;
- if (gpmc_cfg->flags & GPMC_READ_MON)
- smc91x_settings.wait_on_read = true;
- if (gpmc_cfg->flags & GPMC_WRITE_MON)
- smc91x_settings.wait_on_write = true;
- if (gpmc_cfg->wait_pin)
- smc91x_settings.wait_pin = gpmc_cfg->wait_pin;
- ret = gpmc_cs_program_settings(gpmc_cfg->cs, &smc91x_settings);
- if (ret < 0)
- goto free1;
-
- if (gpmc_cfg->retime) {
- ret = gpmc_cfg->retime();
- if (ret != 0)
- goto free1;
- }
-
- if (gpio_request_one(gpmc_cfg->gpio_irq, GPIOF_IN, "SMC91X irq") < 0)
- goto free1;
-
- gpmc_smc91x_resources[1].start = gpio_to_irq(gpmc_cfg->gpio_irq);
-
- if (gpmc_cfg->gpio_pwrdwn) {
- ret = gpio_request_one(gpmc_cfg->gpio_pwrdwn,
- GPIOF_OUT_INIT_LOW, "SMC91X powerdown");
- if (ret)
- goto free2;
- }
-
- if (gpmc_cfg->gpio_reset) {
- ret = gpio_request_one(gpmc_cfg->gpio_reset,
- GPIOF_OUT_INIT_LOW, "SMC91X reset");
- if (ret)
- goto free3;
-
- gpio_set_value(gpmc_cfg->gpio_reset, 1);
- msleep(100);
- gpio_set_value(gpmc_cfg->gpio_reset, 0);
- }
-
- if (platform_device_register(&gpmc_smc91x_device) < 0) {
- printk(KERN_ERR "Unable to register smc91x device\n");
- gpio_free(gpmc_cfg->gpio_reset);
- goto free3;
- }
-
- return;
-
-free3:
- if (gpmc_cfg->gpio_pwrdwn)
- gpio_free(gpmc_cfg->gpio_pwrdwn);
-free2:
- gpio_free(gpmc_cfg->gpio_irq);
-free1:
- gpmc_cs_free(gpmc_cfg->cs);
-
- printk(KERN_ERR "Could not initialize smc91x\n");
-}
diff --git a/arch/arm/mach-omap2/gpmc-smc91x.h b/arch/arm/mach-omap2/gpmc-smc91x.h
deleted file mode 100644
index b64fbee..0000000
--- a/arch/arm/mach-omap2/gpmc-smc91x.h
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * arch/arm/plat-omap/include/mach/gpmc-smc91x.h
- *
- * Copyright (C) 2009 Nokia 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 __ASM_ARCH_OMAP_GPMC_SMC91X_H__
-
-#define GPMC_TIMINGS_SMC91C96 (1 << 4)
-#define GPMC_MUX_ADD_DATA (1 << 5) /* GPMC_CONFIG1_MUXADDDATA */
-#define GPMC_READ_MON (1 << 6) /* GPMC_CONFIG1_WAIT_READ_MON */
-#define GPMC_WRITE_MON (1 << 7) /* GPMC_CONFIG1_WAIT_WRITE_MON */
-
-struct omap_smc91x_platform_data {
- int cs;
- int gpio_irq;
- int gpio_pwrdwn;
- int gpio_reset;
- int wait_pin; /* Optional GPMC_CONFIG1_WAITPINSELECT */
- u32 flags;
- int (*retime)(void);
-};
-
-#if defined(CONFIG_SMC91X) || \
- defined(CONFIG_SMC91X_MODULE)
-
-extern void gpmc_smc91x_init(struct omap_smc91x_platform_data *d);
-
-#else
-
-#define board_smc91x_data NULL
-
-static inline void gpmc_smc91x_init(struct omap_smc91x_platform_data *d)
-{
-}
-
-#endif
-#endif
diff --git a/arch/arm/mach-omap2/gpmc.h b/arch/arm/mach-omap2/gpmc.h
index 707f6d5..9caa41a 100644
--- a/arch/arm/mach-omap2/gpmc.h
+++ b/arch/arm/mach-omap2/gpmc.h
@@ -6,226 +6,9 @@
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
+ *
+ * Do not include this file in any new code, this will get removed
+ * once omap3 boots in device tree only mode.
+ *
*/
-
-#ifndef __OMAP2_GPMC_H
-#define __OMAP2_GPMC_H
-
-#include <linux/platform_data/mtd-nand-omap2.h>
-
-/* Maximum Number of Chip Selects */
-#define GPMC_CS_NUM 8
-
-#define GPMC_CS_CONFIG1 0x00
-#define GPMC_CS_CONFIG2 0x04
-#define GPMC_CS_CONFIG3 0x08
-#define GPMC_CS_CONFIG4 0x0c
-#define GPMC_CS_CONFIG5 0x10
-#define GPMC_CS_CONFIG6 0x14
-#define GPMC_CS_CONFIG7 0x18
-#define GPMC_CS_NAND_COMMAND 0x1c
-#define GPMC_CS_NAND_ADDRESS 0x20
-#define GPMC_CS_NAND_DATA 0x24
-
-/* Control Commands */
-#define GPMC_CONFIG_RDY_BSY 0x00000001
-#define GPMC_CONFIG_DEV_SIZE 0x00000002
-#define GPMC_CONFIG_DEV_TYPE 0x00000003
-#define GPMC_SET_IRQ_STATUS 0x00000004
-#define GPMC_CONFIG_WP 0x00000005
-
-#define GPMC_ENABLE_IRQ 0x0000000d
-
-/* ECC commands */
-#define GPMC_ECC_READ 0 /* Reset Hardware ECC for read */
-#define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */
-#define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */
-
-#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
-#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
-#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
-#define GPMC_CONFIG1_READTYPE_SYNC (1 << 29)
-#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
-#define GPMC_CONFIG1_WRITETYPE_ASYNC (0 << 27)
-#define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27)
-#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
-#define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23)
-#define GPMC_CONFIG1_WAIT_READ_MON (1 << 22)
-#define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
-#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
-#define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16)
-#define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12)
-#define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1)
-#define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10)
-#define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
-#define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8)
-#define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4)
-#define GPMC_CONFIG1_FCLK_DIV(val) (val & 3)
-#define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1))
-#define GPMC_CONFIG1_FCLK_DIV3 (GPMC_CONFIG1_FCLK_DIV(2))
-#define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3))
-#define GPMC_CONFIG7_CSVALID (1 << 6)
-
-#define GPMC_DEVICETYPE_NOR 0
-#define GPMC_DEVICETYPE_NAND 2
-#define GPMC_CONFIG_WRITEPROTECT 0x00000010
-#define WR_RD_PIN_MONITORING 0x00600000
-#define GPMC_IRQ_FIFOEVENTENABLE 0x01
-#define GPMC_IRQ_COUNT_EVENT 0x02
-
-#define GPMC_BURST_4 4 /* 4 word burst */
-#define GPMC_BURST_8 8 /* 8 word burst */
-#define GPMC_BURST_16 16 /* 16 word burst */
-#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */
-#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */
-#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
-#define GPMC_MUX_AD 2 /* Addr-Data multiplex */
-
-/* bool type time settings */
-struct gpmc_bool_timings {
- bool cycle2cyclediffcsen;
- bool cycle2cyclesamecsen;
- bool we_extra_delay;
- bool oe_extra_delay;
- bool adv_extra_delay;
- bool cs_extra_delay;
- bool time_para_granularity;
-};
-
-/*
- * Note that all values in this struct are in nanoseconds except sync_clk
- * (which is in picoseconds), while the register values are in gpmc_fck cycles.
- */
-struct gpmc_timings {
- /* Minimum clock period for synchronous mode (in picoseconds) */
- u32 sync_clk;
-
- /* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
- u32 cs_on; /* Assertion time */
- u32 cs_rd_off; /* Read deassertion time */
- u32 cs_wr_off; /* Write deassertion time */
-
- /* ADV signal timings corresponding to GPMC_CONFIG3 */
- u32 adv_on; /* Assertion time */
- u32 adv_rd_off; /* Read deassertion time */
- u32 adv_wr_off; /* Write deassertion time */
-
- /* WE signals timings corresponding to GPMC_CONFIG4 */
- u32 we_on; /* WE assertion time */
- u32 we_off; /* WE deassertion time */
-
- /* OE signals timings corresponding to GPMC_CONFIG4 */
- u32 oe_on; /* OE assertion time */
- u32 oe_off; /* OE deassertion time */
-
- /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
- u32 page_burst_access; /* Multiple access word delay */
- u32 access; /* Start-cycle to first data valid delay */
- u32 rd_cycle; /* Total read cycle time */
- u32 wr_cycle; /* Total write cycle time */
-
- u32 bus_turnaround;
- u32 cycle2cycle_delay;
-
- u32 wait_monitoring;
- u32 clk_activation;
-
- /* The following are only on OMAP3430 */
- u32 wr_access; /* WRACCESSTIME */
- u32 wr_data_mux_bus; /* WRDATAONADMUXBUS */
-
- struct gpmc_bool_timings bool_timings;
-};
-
-/* Device timings in picoseconds */
-struct gpmc_device_timings {
- u32 t_ceasu; /* address setup to CS valid */
- u32 t_avdasu; /* address setup to ADV valid */
- /* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
- * of tusb using these timings even for sync whilst
- * ideally for adv_rd/(wr)_off it should have considered
- * t_avdh instead. This indirectly necessitates r/w
- * variations of t_avdp as it is possible to have one
- * sync & other async
- */
- u32 t_avdp_r; /* ADV low time (what about t_cer ?) */
- u32 t_avdp_w;
- u32 t_aavdh; /* address hold time */
- u32 t_oeasu; /* address setup to OE valid */
- u32 t_aa; /* access time from ADV assertion */
- u32 t_iaa; /* initial access time */
- u32 t_oe; /* access time from OE assertion */
- u32 t_ce; /* access time from CS asertion */
- u32 t_rd_cycle; /* read cycle time */
- u32 t_cez_r; /* read CS deassertion to high Z */
- u32 t_cez_w; /* write CS deassertion to high Z */
- u32 t_oez; /* OE deassertion to high Z */
- u32 t_weasu; /* address setup to WE valid */
- u32 t_wpl; /* write assertion time */
- u32 t_wph; /* write deassertion time */
- u32 t_wr_cycle; /* write cycle time */
-
- u32 clk;
- u32 t_bacc; /* burst access valid clock to output delay */
- u32 t_ces; /* CS setup time to clk */
- u32 t_avds; /* ADV setup time to clk */
- u32 t_avdh; /* ADV hold time from clk */
- u32 t_ach; /* address hold time from clk */
- u32 t_rdyo; /* clk to ready valid */
-
- u32 t_ce_rdyz; /* XXX: description ?, or use t_cez instead */
- u32 t_ce_avd; /* CS on to ADV on delay */
-
- /* XXX: check the possibility of combining
- * cyc_aavhd_oe & cyc_aavdh_we
- */
- u8 cyc_aavdh_oe;/* read address hold time in cycles */
- u8 cyc_aavdh_we;/* write address hold time in cycles */
- u8 cyc_oe; /* access time from OE assertion in cycles */
- u8 cyc_wpl; /* write deassertion time in cycles */
- u32 cyc_iaa; /* initial access time in cycles */
-
- /* extra delays */
- bool ce_xdelay;
- bool avd_xdelay;
- bool oe_xdelay;
- bool we_xdelay;
-};
-
-struct gpmc_settings {
- bool burst_wrap; /* enables wrap bursting */
- bool burst_read; /* enables read page/burst mode */
- bool burst_write; /* enables write page/burst mode */
- bool device_nand; /* device is NAND */
- bool sync_read; /* enables synchronous reads */
- bool sync_write; /* enables synchronous writes */
- bool wait_on_read; /* monitor wait on reads */
- bool wait_on_write; /* monitor wait on writes */
- u32 burst_len; /* page/burst length */
- u32 device_width; /* device bus width (8 or 16 bit) */
- u32 mux_add_data; /* multiplex address & data */
- u32 wait_pin; /* wait-pin to be used */
-};
-
-extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
- struct gpmc_settings *gpmc_s,
- struct gpmc_device_timings *dev_t);
-
-extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
-extern int gpmc_get_client_irq(unsigned irq_config);
-
-extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
-
-extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
-extern int gpmc_calc_divider(unsigned int sync_clk);
-extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
-extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
-extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
-extern void gpmc_cs_free(int cs);
-extern void omap3_gpmc_save_context(void);
-extern void omap3_gpmc_restore_context(void);
-extern int gpmc_configure(int cmd, int wval);
-extern void gpmc_read_settings_dt(struct device_node *np,
- struct gpmc_settings *p);
-
-#endif
+#include <linux/omap-gpmc.h>
diff --git a/arch/arm/mach-omap2/hsmmc.c b/arch/arm/mach-omap2/hsmmc.c
index 07d4c7b..dc6e79c 100644
--- a/arch/arm/mach-omap2/hsmmc.c
+++ b/arch/arm/mach-omap2/hsmmc.c
@@ -14,14 +14,15 @@
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/gpio.h>
+#include <linux/mmc/host.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include "soc.h"
#include "omap_device.h"
#include "omap-pm.h"
#include "mux.h"
-#include "mmc.h"
#include "hsmmc.h"
#include "control.h"
@@ -32,25 +33,14 @@ static u16 control_devconf1_offset;
#define HSMMC_NAME_LEN 9
-#if defined(CONFIG_ARCH_OMAP3) && defined(CONFIG_PM)
-
-static int hsmmc_get_context_loss(struct device *dev)
-{
- return omap_pm_get_dev_context_loss_count(dev);
-}
-
-#else
-#define hsmmc_get_context_loss NULL
-#endif
-
-static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
- int power_on, int vdd)
+static void omap_hsmmc1_before_set_reg(struct device *dev,
+ int power_on, int vdd)
{
u32 reg, prog_io;
- struct omap_mmc_platform_data *mmc = dev->platform_data;
+ struct omap_hsmmc_platform_data *mmc = dev->platform_data;
- if (mmc->slots[0].remux)
- mmc->slots[0].remux(dev, slot, power_on);
+ if (mmc->remux)
+ mmc->remux(dev, power_on);
/*
* Assume we power both OMAP VMMC1 (for CMD, CLK, DAT0..3) and the
@@ -72,7 +62,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
omap_ctrl_writel(reg, OMAP243X_CONTROL_DEVCONF1);
}
- if (mmc->slots[0].internal_clock) {
+ if (mmc->internal_clock) {
reg = omap_ctrl_readl(OMAP2_CONTROL_DEVCONF0);
reg |= OMAP2_MMCSDIO1ADPCLKISEL;
omap_ctrl_writel(reg, OMAP2_CONTROL_DEVCONF0);
@@ -96,8 +86,7 @@ static void omap_hsmmc1_before_set_reg(struct device *dev, int slot,
}
}
-static void omap_hsmmc1_after_set_reg(struct device *dev, int slot,
- int power_on, int vdd)
+static void omap_hsmmc1_after_set_reg(struct device *dev, int power_on, int vdd)
{
u32 reg;
@@ -120,34 +109,32 @@ static void omap_hsmmc1_after_set_reg(struct device *dev, int slot,
}
}
-static void hsmmc2_select_input_clk_src(struct omap_mmc_platform_data *mmc)
+static void hsmmc2_select_input_clk_src(struct omap_hsmmc_platform_data *mmc)
{
u32 reg;
reg = omap_ctrl_readl(control_devconf1_offset);
- if (mmc->slots[0].internal_clock)
+ if (mmc->internal_clock)
reg |= OMAP2_MMCSDIO2ADPCLKISEL;
else
reg &= ~OMAP2_MMCSDIO2ADPCLKISEL;
omap_ctrl_writel(reg, control_devconf1_offset);
}
-static void hsmmc2_before_set_reg(struct device *dev, int slot,
- int power_on, int vdd)
+static void hsmmc2_before_set_reg(struct device *dev, int power_on, int vdd)
{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
+ struct omap_hsmmc_platform_data *mmc = dev->platform_data;
- if (mmc->slots[0].remux)
- mmc->slots[0].remux(dev, slot, power_on);
+ if (mmc->remux)
+ mmc->remux(dev, power_on);
if (power_on)
hsmmc2_select_input_clk_src(mmc);
}
-static int am35x_hsmmc2_set_power(struct device *dev, int slot,
- int power_on, int vdd)
+static int am35x_hsmmc2_set_power(struct device *dev, int power_on, int vdd)
{
- struct omap_mmc_platform_data *mmc = dev->platform_data;
+ struct omap_hsmmc_platform_data *mmc = dev->platform_data;
if (power_on)
hsmmc2_select_input_clk_src(mmc);
@@ -155,23 +142,22 @@ static int am35x_hsmmc2_set_power(struct device *dev, int slot,
return 0;
}
-static int nop_mmc_set_power(struct device *dev, int slot, int power_on,
- int vdd)
+static int nop_mmc_set_power(struct device *dev, int power_on, int vdd)
{
return 0;
}
-static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
- int controller_nr)
+static inline void omap_hsmmc_mux(struct omap_hsmmc_platform_data
+ *mmc_controller, int controller_nr)
{
- if (gpio_is_valid(mmc_controller->slots[0].switch_pin) &&
- (mmc_controller->slots[0].switch_pin < OMAP_MAX_GPIO_LINES))
- omap_mux_init_gpio(mmc_controller->slots[0].switch_pin,
- OMAP_PIN_INPUT_PULLUP);
- if (gpio_is_valid(mmc_controller->slots[0].gpio_wp) &&
- (mmc_controller->slots[0].gpio_wp < OMAP_MAX_GPIO_LINES))
- omap_mux_init_gpio(mmc_controller->slots[0].gpio_wp,
- OMAP_PIN_INPUT_PULLUP);
+ if (gpio_is_valid(mmc_controller->switch_pin) &&
+ (mmc_controller->switch_pin < OMAP_MAX_GPIO_LINES))
+ omap_mux_init_gpio(mmc_controller->switch_pin,
+ OMAP_PIN_INPUT_PULLUP);
+ if (gpio_is_valid(mmc_controller->gpio_wp) &&
+ (mmc_controller->gpio_wp < OMAP_MAX_GPIO_LINES))
+ omap_mux_init_gpio(mmc_controller->gpio_wp,
+ OMAP_PIN_INPUT_PULLUP);
if (cpu_is_omap34xx()) {
if (controller_nr == 0) {
omap_mux_init_signal("sdmmc1_clk",
@@ -180,7 +166,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
OMAP_PIN_INPUT_PULLUP);
omap_mux_init_signal("sdmmc1_dat0",
OMAP_PIN_INPUT_PULLUP);
- if (mmc_controller->slots[0].caps &
+ if (mmc_controller->caps &
(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
omap_mux_init_signal("sdmmc1_dat1",
OMAP_PIN_INPUT_PULLUP);
@@ -189,7 +175,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc1_dat3",
OMAP_PIN_INPUT_PULLUP);
}
- if (mmc_controller->slots[0].caps &
+ if (mmc_controller->caps &
MMC_CAP_8_BIT_DATA) {
omap_mux_init_signal("sdmmc1_dat4",
OMAP_PIN_INPUT_PULLUP);
@@ -214,7 +200,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
* For 8 wire configurations, Lines DAT4, 5, 6 and 7
* need to be muxed in the board-*.c files
*/
- if (mmc_controller->slots[0].caps &
+ if (mmc_controller->caps &
(MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)) {
omap_mux_init_signal("sdmmc2_dat1",
OMAP_PIN_INPUT_PULLUP);
@@ -223,7 +209,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
omap_mux_init_signal("sdmmc2_dat3",
OMAP_PIN_INPUT_PULLUP);
}
- if (mmc_controller->slots[0].caps &
+ if (mmc_controller->caps &
MMC_CAP_8_BIT_DATA) {
omap_mux_init_signal("sdmmc2_dat4.sdmmc2_dat4",
OMAP_PIN_INPUT_PULLUP);
@@ -243,7 +229,7 @@ static inline void omap_hsmmc_mux(struct omap_mmc_platform_data *mmc_controller,
}
static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
- struct omap_mmc_platform_data *mmc)
+ struct omap_hsmmc_platform_data *mmc)
{
char *hc_name;
@@ -259,38 +245,22 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
else
snprintf(hc_name, (HSMMC_NAME_LEN + 1), "mmc%islot%i",
c->mmc, 1);
- mmc->slots[0].name = hc_name;
- mmc->nr_slots = 1;
- mmc->slots[0].caps = c->caps;
- mmc->slots[0].pm_caps = c->pm_caps;
- mmc->slots[0].internal_clock = !c->ext_clock;
- mmc->max_freq = c->max_freq;
+ mmc->name = hc_name;
+ mmc->caps = c->caps;
+ mmc->internal_clock = !c->ext_clock;
mmc->reg_offset = 0;
- mmc->get_context_loss_count = hsmmc_get_context_loss;
- mmc->slots[0].switch_pin = c->gpio_cd;
- mmc->slots[0].gpio_wp = c->gpio_wp;
+ mmc->switch_pin = c->gpio_cd;
+ mmc->gpio_wp = c->gpio_wp;
- mmc->slots[0].remux = c->remux;
- mmc->slots[0].init_card = c->init_card;
+ mmc->remux = c->remux;
+ mmc->init_card = c->init_card;
if (c->cover_only)
- mmc->slots[0].cover = 1;
+ mmc->cover = 1;
if (c->nonremovable)
- mmc->slots[0].nonremovable = 1;
-
- if (c->power_saving)
- mmc->slots[0].power_saving = 1;
-
- if (c->no_off)
- mmc->slots[0].no_off = 1;
-
- if (c->no_off_init)
- mmc->slots[0].no_regulator_off_init = c->no_off_init;
-
- if (c->vcc_aux_disable_is_sleep)
- mmc->slots[0].vcc_aux_disable_is_sleep = 1;
+ mmc->nonremovable = 1;
/*
* NOTE: MMC slots should have a Vcc regulator set up.
@@ -300,42 +270,42 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
* temporary HACK: ocr_mask instead of fixed supply
*/
if (soc_is_am35xx())
- mmc->slots[0].ocr_mask = MMC_VDD_165_195 |
+ mmc->ocr_mask = MMC_VDD_165_195 |
MMC_VDD_26_27 |
MMC_VDD_27_28 |
MMC_VDD_29_30 |
MMC_VDD_30_31 |
MMC_VDD_31_32;
else
- mmc->slots[0].ocr_mask = c->ocr_mask;
+ mmc->ocr_mask = c->ocr_mask;
if (!soc_is_am35xx())
- mmc->slots[0].features |= HSMMC_HAS_PBIAS;
+ mmc->features |= HSMMC_HAS_PBIAS;
switch (c->mmc) {
case 1:
- if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
+ if (mmc->features & HSMMC_HAS_PBIAS) {
/* on-chip level shifting via PBIAS0/PBIAS1 */
- mmc->slots[0].before_set_reg =
+ mmc->before_set_reg =
omap_hsmmc1_before_set_reg;
- mmc->slots[0].after_set_reg =
+ mmc->after_set_reg =
omap_hsmmc1_after_set_reg;
}
if (soc_is_am35xx())
- mmc->slots[0].set_power = nop_mmc_set_power;
+ mmc->set_power = nop_mmc_set_power;
/* OMAP3630 HSMMC1 supports only 4-bit */
if (cpu_is_omap3630() &&
(c->caps & MMC_CAP_8_BIT_DATA)) {
c->caps &= ~MMC_CAP_8_BIT_DATA;
c->caps |= MMC_CAP_4_BIT_DATA;
- mmc->slots[0].caps = c->caps;
+ mmc->caps = c->caps;
}
break;
case 2:
if (soc_is_am35xx())
- mmc->slots[0].set_power = am35x_hsmmc2_set_power;
+ mmc->set_power = am35x_hsmmc2_set_power;
if (c->ext_clock)
c->transceiver = 1;
@@ -343,17 +313,17 @@ static int __init omap_hsmmc_pdata_init(struct omap2_hsmmc_info *c,
c->caps &= ~MMC_CAP_8_BIT_DATA;
c->caps |= MMC_CAP_4_BIT_DATA;
}
- if (mmc->slots[0].features & HSMMC_HAS_PBIAS) {
+ if (mmc->features & HSMMC_HAS_PBIAS) {
/* off-chip level shifting, or none */
- mmc->slots[0].before_set_reg = hsmmc2_before_set_reg;
- mmc->slots[0].after_set_reg = NULL;
+ mmc->before_set_reg = hsmmc2_before_set_reg;
+ mmc->after_set_reg = NULL;
}
break;
case 3:
case 4:
case 5:
- mmc->slots[0].before_set_reg = NULL;
- mmc->slots[0].after_set_reg = NULL;
+ mmc->before_set_reg = NULL;
+ mmc->after_set_reg = NULL;
break;
default:
pr_err("MMC%d configuration not supported!\n", c->mmc);
@@ -368,7 +338,7 @@ static int omap_hsmmc_done;
void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
{
struct platform_device *pdev;
- struct omap_mmc_platform_data *mmc_pdata;
+ struct omap_hsmmc_platform_data *mmc_pdata;
int res;
if (omap_hsmmc_done != 1)
@@ -388,8 +358,8 @@ void omap_hsmmc_late_init(struct omap2_hsmmc_info *c)
if (!mmc_pdata)
continue;
- mmc_pdata->slots[0].switch_pin = c->gpio_cd;
- mmc_pdata->slots[0].gpio_wp = c->gpio_wp;
+ mmc_pdata->switch_pin = c->gpio_cd;
+ mmc_pdata->gpio_wp = c->gpio_wp;
res = omap_device_register(pdev);
if (res)
@@ -408,12 +378,12 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
struct omap_device *od;
struct platform_device *pdev;
char oh_name[MAX_OMAP_MMC_HWMOD_NAME_LEN];
- struct omap_mmc_platform_data *mmc_data;
- struct omap_mmc_dev_attr *mmc_dev_attr;
+ struct omap_hsmmc_platform_data *mmc_data;
+ struct omap_hsmmc_dev_attr *mmc_dev_attr;
char *name;
int res;
- mmc_data = kzalloc(sizeof(struct omap_mmc_platform_data), GFP_KERNEL);
+ mmc_data = kzalloc(sizeof(*mmc_data), GFP_KERNEL);
if (!mmc_data) {
pr_err("Cannot allocate memory for mmc device!\n");
return;
@@ -463,7 +433,7 @@ static void __init omap_hsmmc_init_one(struct omap2_hsmmc_info *hsmmcinfo,
}
res = platform_device_add_data(pdev, mmc_data,
- sizeof(struct omap_mmc_platform_data));
+ sizeof(struct omap_hsmmc_platform_data));
if (res) {
pr_err("Could not add pdata for %s\n", name);
goto put_pdev;
@@ -489,7 +459,7 @@ put_pdev:
platform_device_put(pdev);
free_name:
- kfree(mmc_data->slots[0].name);
+ kfree(mmc_data->name);
free_mmc:
kfree(mmc_data);
diff --git a/arch/arm/mach-omap2/hsmmc.h b/arch/arm/mach-omap2/hsmmc.h
index 7f2e790..148cd9b 100644
--- a/arch/arm/mach-omap2/hsmmc.h
+++ b/arch/arm/mach-omap2/hsmmc.h
@@ -12,25 +12,18 @@ struct omap2_hsmmc_info {
u8 mmc; /* controller 1/2/3 */
u32 caps; /* 4/8 wires and any additional host
* capabilities OR'd (ref. linux/mmc/host.h) */
- u32 pm_caps; /* PM capabilities */
bool transceiver; /* MMC-2 option */
bool ext_clock; /* use external pin for input clock */
bool cover_only; /* No card detect - just cover switch */
bool nonremovable; /* Nonremovable e.g. eMMC */
- bool power_saving; /* Try to sleep or power off when possible */
- bool no_off; /* power_saving and power is not to go off */
- bool no_off_init; /* no power off when not in MMC sleep state */
- bool vcc_aux_disable_is_sleep; /* Regulator off remapped to sleep */
bool deferred; /* mmc needs a deferred probe */
int gpio_cd; /* or -EINVAL */
int gpio_wp; /* or -EINVAL */
char *name; /* or NULL for default */
struct platform_device *pdev; /* mmc controller instance */
int ocr_mask; /* temporary HACK */
- int max_freq; /* maximum clock, if constrained by external
- * circuitry, or 0 for default */
/* Remux (pad configuration) when powering on/off */
- void (*remux)(struct device *dev, int slot, int power_on);
+ void (*remux)(struct device *dev, int power_on);
/* init some special card */
void (*init_card)(struct mmc_card *card);
};
diff --git a/arch/arm/mach-omap2/io.c b/arch/arm/mach-omap2/io.c
index 03cbb16..4fc8383 100644
--- a/arch/arm/mach-omap2/io.c
+++ b/arch/arm/mach-omap2/io.c
@@ -45,13 +45,15 @@
#include "sram.h"
#include "cm2xxx.h"
#include "cm3xxx.h"
+#include "cm33xx.h"
+#include "cm44xx.h"
#include "prm.h"
#include "cm.h"
#include "prcm_mpu44xx.h"
#include "prminst44xx.h"
-#include "cminst44xx.h"
#include "prm2xxx.h"
#include "prm3xxx.h"
+#include "prm33xx.h"
#include "prm44xx.h"
#include "opp2xxx.h"
@@ -565,6 +567,8 @@ void __init am33xx_init_early(void)
omap2_set_globals_cm(AM33XX_L4_WK_IO_ADDRESS(AM33XX_PRCM_BASE), NULL);
omap3xxx_check_revision();
am33xx_check_features();
+ am33xx_prm_init();
+ am33xx_cm_init();
am33xx_powerdomains_init();
am33xx_clockdomains_init();
am33xx_hwmod_init();
@@ -591,6 +595,8 @@ void __init am43xx_init_early(void)
omap_cm_base_init();
omap3xxx_check_revision();
am33xx_check_features();
+ omap44xx_prm_init();
+ omap4_cm_init();
am43xx_powerdomains_init();
am43xx_clockdomains_init();
am43xx_hwmod_init();
@@ -620,6 +626,7 @@ void __init omap4430_init_early(void)
omap_cm_base_init();
omap4xxx_check_revision();
omap4xxx_check_features();
+ omap4_cm_init();
omap4_pm_init_early();
omap44xx_prm_init();
omap44xx_voltagedomains_init();
@@ -655,6 +662,7 @@ void __init omap5_init_early(void)
omap_cm_base_init();
omap44xx_prm_init();
omap5xxx_check_revision();
+ omap4_cm_init();
omap54xx_voltagedomains_init();
omap54xx_powerdomains_init();
omap54xx_clockdomains_init();
@@ -686,6 +694,7 @@ void __init dra7xx_init_early(void)
omap_cm_base_init();
omap44xx_prm_init();
dra7xxx_check_revision();
+ omap4_cm_init();
dra7xx_powerdomains_init();
dra7xx_clockdomains_init();
dra7xx_hwmod_init();
diff --git a/arch/arm/mach-omap2/mmc.h b/arch/arm/mach-omap2/mmc.h
index 0cd4b08..30d39b9 100644
--- a/arch/arm/mach-omap2/mmc.h
+++ b/arch/arm/mach-omap2/mmc.h
@@ -1,5 +1,3 @@
-#include <linux/mmc/host.h>
-#include <linux/platform_data/mmc-omap.h>
#define OMAP24XX_NR_MMC 2
#define OMAP2420_MMC_SIZE OMAP1_MMC_SIZE
@@ -7,14 +5,6 @@
#define OMAP4_MMC_REG_OFFSET 0x100
-#if defined(CONFIG_MMC_OMAP) || defined(CONFIG_MMC_OMAP_MODULE)
-void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data);
-#else
-static inline void omap242x_init_mmc(struct omap_mmc_platform_data **mmc_data)
-{
-}
-#endif
-
struct omap_hwmod;
int omap_msdi_reset(struct omap_hwmod *oh);
diff --git a/arch/arm/mach-omap2/omap-mpuss-lowpower.c b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
index 6944ae3..79f49d9 100644
--- a/arch/arm/mach-omap2/omap-mpuss-lowpower.c
+++ b/arch/arm/mach-omap2/omap-mpuss-lowpower.c
@@ -227,7 +227,7 @@ static void __init save_l2x0_context(void)
int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
{
struct omap4_cpu_pm_info *pm_info = &per_cpu(omap4_pm_info, cpu);
- unsigned int save_state = 0;
+ unsigned int save_state = 0, cpu_logic_state = PWRDM_POWER_RET;
unsigned int wakeup_cpu;
if (omap_rev() == OMAP4430_REV_ES1_0)
@@ -239,6 +239,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
save_state = 0;
break;
case PWRDM_POWER_OFF:
+ cpu_logic_state = PWRDM_POWER_OFF;
save_state = 1;
break;
case PWRDM_POWER_RET:
@@ -270,6 +271,7 @@ int omap4_enter_lowpower(unsigned int cpu, unsigned int power_state)
cpu_clear_prev_logic_pwrst(cpu);
pwrdm_set_next_pwrst(pm_info->pwrdm, power_state);
+ pwrdm_set_logic_retst(pm_info->pwrdm, cpu_logic_state);
set_cpu_wakeup_addr(cpu, virt_to_phys(omap_pm_ops.resume));
omap_pm_ops.scu_prepare(cpu, power_state);
l2x0_pwrst_prepare(cpu, save_state);
diff --git a/arch/arm/mach-omap2/omap2-restart.c b/arch/arm/mach-omap2/omap2-restart.c
index 68423e2..d937b2e 100644
--- a/arch/arm/mach-omap2/omap2-restart.c
+++ b/arch/arm/mach-omap2/omap2-restart.c
@@ -15,7 +15,7 @@
#include "soc.h"
#include "common.h"
-#include "prm2xxx.h"
+#include "prm.h"
/*
* reset_virt_prcm_set_ck, reset_sys_ck: pointers to the virt_prcm_set
@@ -40,8 +40,7 @@ void omap2xxx_restart(enum reboot_mode mode, const char *cmd)
/* XXX Should save the cmd argument for use after the reboot */
- omap2xxx_prm_dpll_reset(); /* never returns */
- while (1);
+ omap_prm_reset_system();
}
/**
diff --git a/arch/arm/mach-omap2/omap3-restart.c b/arch/arm/mach-omap2/omap3-restart.c
index 5de2a0c..103a49f 100644
--- a/arch/arm/mach-omap2/omap3-restart.c
+++ b/arch/arm/mach-omap2/omap3-restart.c
@@ -14,10 +14,8 @@
#include <linux/init.h>
#include <linux/reboot.h>
-#include "iomap.h"
-#include "common.h"
#include "control.h"
-#include "prm3xxx.h"
+#include "prm.h"
/* Global address base setup code */
@@ -32,6 +30,5 @@
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 */
- while (1);
+ omap_prm_reset_system();
}
diff --git a/arch/arm/mach-omap2/omap4-common.c b/arch/arm/mach-omap2/omap4-common.c
index 16b20ce..b7cb44a 100644
--- a/arch/arm/mach-omap2/omap4-common.c
+++ b/arch/arm/mach-omap2/omap4-common.c
@@ -36,7 +36,6 @@
#include "soc.h"
#include "iomap.h"
#include "common.h"
-#include "mmc.h"
#include "prminst44xx.h"
#include "prcm_mpu44xx.h"
#include "omap4-sar-layout.h"
diff --git a/arch/arm/mach-omap2/omap4-restart.c b/arch/arm/mach-omap2/omap4-restart.c
index 41dfd7d..a99e7f7 100644
--- a/arch/arm/mach-omap2/omap4-restart.c
+++ b/arch/arm/mach-omap2/omap4-restart.c
@@ -9,7 +9,7 @@
#include <linux/types.h>
#include <linux/reboot.h>
-#include "prminst44xx.h"
+#include "prm.h"
/**
* omap44xx_restart - trigger a software restart of the SoC
@@ -22,7 +22,5 @@
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 */
- while (1)
- ;
+ omap_prm_reset_system();
}
diff --git a/arch/arm/mach-omap2/omap_hwmod.c b/arch/arm/mach-omap2/omap_hwmod.c
index 716247e..cbb908d 100644
--- a/arch/arm/mach-omap2/omap_hwmod.c
+++ b/arch/arm/mach-omap2/omap_hwmod.c
@@ -153,7 +153,6 @@
#include "powerdomain.h"
#include "cm2xxx.h"
#include "cm3xxx.h"
-#include "cminst44xx.h"
#include "cm33xx.h"
#include "prm.h"
#include "prm3xxx.h"
@@ -979,31 +978,9 @@ static void _omap4_enable_module(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: %s: %d\n",
oh->name, __func__, oh->prcm.omap4.modulemode);
- omap4_cminst_module_enable(oh->prcm.omap4.modulemode,
- oh->clkdm->prcm_partition,
- oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
-}
-
-/**
- * _am33xx_enable_module - enable CLKCTRL modulemode on AM33XX
- * @oh: struct omap_hwmod *
- *
- * Enables the PRCM module mode related to the hwmod @oh.
- * No return value.
- */
-static void _am33xx_enable_module(struct omap_hwmod *oh)
-{
- if (!oh->clkdm || !oh->prcm.omap4.modulemode)
- return;
-
- pr_debug("omap_hwmod: %s: %s: %d\n",
- oh->name, __func__, oh->prcm.omap4.modulemode);
-
- am33xx_cm_module_enable(oh->prcm.omap4.modulemode, oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
+ omap_cm_module_enable(oh->prcm.omap4.modulemode,
+ oh->clkdm->prcm_partition,
+ oh->clkdm->cm_inst, oh->prcm.omap4.clkctrl_offs);
}
/**
@@ -1026,35 +1003,9 @@ static int _omap4_wait_target_disable(struct omap_hwmod *oh)
if (oh->flags & HWMOD_NO_IDLEST)
return 0;
- return omap4_cminst_wait_module_idle(oh->clkdm->prcm_partition,
- oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
-}
-
-/**
- * _am33xx_wait_target_disable - wait for a module to be disabled on AM33XX
- * @oh: struct omap_hwmod *
- *
- * Wait for a module @oh to enter slave idle. Returns 0 if the module
- * does not have an IDLEST bit or if the module successfully enters
- * slave idle; otherwise, pass along the return value of the
- * appropriate *_cm*_wait_module_idle() function.
- */
-static int _am33xx_wait_target_disable(struct omap_hwmod *oh)
-{
- if (!oh)
- return -EINVAL;
-
- if (oh->_int_flags & _HWMOD_NO_MPU_PORT)
- return 0;
-
- if (oh->flags & HWMOD_NO_IDLEST)
- return 0;
-
- return am33xx_cm_wait_module_idle(oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
+ return omap_cm_wait_module_idle(oh->clkdm->prcm_partition,
+ oh->clkdm->cm_inst,
+ oh->prcm.omap4.clkctrl_offs, 0);
}
/**
@@ -1859,10 +1810,8 @@ static int _omap4_disable_module(struct omap_hwmod *oh)
pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
- omap4_cminst_module_disable(oh->clkdm->prcm_partition,
- oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
+ omap_cm_module_disable(oh->clkdm->prcm_partition, oh->clkdm->cm_inst,
+ oh->prcm.omap4.clkctrl_offs);
v = _omap4_wait_target_disable(oh);
if (v)
@@ -1873,36 +1822,6 @@ static int _omap4_disable_module(struct omap_hwmod *oh)
}
/**
- * _am33xx_disable_module - enable CLKCTRL modulemode on AM33XX
- * @oh: struct omap_hwmod *
- *
- * Disable the PRCM module mode related to the hwmod @oh.
- * Return EINVAL if the modulemode is not supported and 0 in case of success.
- */
-static int _am33xx_disable_module(struct omap_hwmod *oh)
-{
- int v;
-
- if (!oh->clkdm || !oh->prcm.omap4.modulemode)
- return -EINVAL;
-
- pr_debug("omap_hwmod: %s: %s\n", oh->name, __func__);
-
- if (_are_any_hardreset_lines_asserted(oh))
- return 0;
-
- am33xx_cm_module_disable(oh->clkdm->cm_inst, oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
-
- v = _am33xx_wait_target_disable(oh);
- if (v)
- pr_warn("omap_hwmod: %s: _wait_target_disable failed\n",
- oh->name);
-
- return 0;
-}
-
-/**
* _ocp_softreset - reset an omap_hwmod via the OCP_SYSCONFIG bit
* @oh: struct omap_hwmod *
*
@@ -2065,10 +1984,7 @@ static void _reconfigure_io_chain(void)
spin_lock_irqsave(&io_chain_lock, flags);
- if (cpu_is_omap34xx())
- omap3xxx_prm_reconfigure_io_chain();
- else if (cpu_is_omap44xx())
- omap44xx_prm_reconfigure_io_chain();
+ omap_prm_reconfigure_io_chain();
spin_unlock_irqrestore(&io_chain_lock, flags);
}
@@ -2719,11 +2635,33 @@ static int __init _setup(struct omap_hwmod *oh, void *data)
if (oh->_state != _HWMOD_STATE_INITIALIZED)
return 0;
+ if (oh->parent_hwmod) {
+ int r;
+
+ r = _enable(oh->parent_hwmod);
+ WARN(r, "hwmod: %s: setup: failed to enable parent hwmod %s\n",
+ oh->name, oh->parent_hwmod->name);
+ }
+
_setup_iclk_autoidle(oh);
if (!_setup_reset(oh))
_setup_postsetup(oh);
+ if (oh->parent_hwmod) {
+ u8 postsetup_state;
+
+ postsetup_state = oh->parent_hwmod->_postsetup_state;
+
+ if (postsetup_state == _HWMOD_STATE_IDLE)
+ _idle(oh->parent_hwmod);
+ else if (postsetup_state == _HWMOD_STATE_DISABLED)
+ _shutdown(oh->parent_hwmod);
+ else if (postsetup_state != _HWMOD_STATE_ENABLED)
+ WARN(1, "hwmod: %s: unknown postsetup state %d! defaulting to enabled\n",
+ oh->parent_hwmod->name, postsetup_state);
+ }
+
return 0;
}
@@ -2832,12 +2770,10 @@ static int __init _add_link(struct omap_hwmod_ocp_if *oi)
_alloc_links(&ml, &sl);
ml->ocp_if = oi;
- INIT_LIST_HEAD(&ml->node);
list_add(&ml->node, &oi->master->master_ports);
oi->master->masters_cnt++;
sl->ocp_if = oi;
- INIT_LIST_HEAD(&sl->node);
list_add(&sl->node, &oi->slave->slave_ports);
oi->slave->slaves_cnt++;
@@ -2927,34 +2863,7 @@ static int __init _alloc_linkspace(struct omap_hwmod_ocp_if **ois)
/* Static functions intended only for use in soc_ops field function pointers */
/**
- * _omap2xxx_wait_target_ready - wait for a module to leave slave idle
- * @oh: struct omap_hwmod *
- *
- * Wait for a module @oh to leave slave idle. Returns 0 if the module
- * does not have an IDLEST bit or if the module successfully leaves
- * slave idle; otherwise, pass along the return value of the
- * appropriate *_cm*_wait_module_ready() function.
- */
-static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh)
-{
- if (!oh)
- return -EINVAL;
-
- if (oh->flags & HWMOD_NO_IDLEST)
- return 0;
-
- if (!_find_mpu_rt_port(oh))
- return 0;
-
- /* XXX check module SIDLEMODE, hardreset status, enabled clocks */
-
- return omap2xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs,
- oh->prcm.omap2.idlest_reg_id,
- oh->prcm.omap2.idlest_idle_bit);
-}
-
-/**
- * _omap3xxx_wait_target_ready - wait for a module to leave slave idle
+ * _omap2xxx_3xxx_wait_target_ready - wait for a module to leave slave idle
* @oh: struct omap_hwmod *
*
* Wait for a module @oh to leave slave idle. Returns 0 if the module
@@ -2962,7 +2871,7 @@ static int _omap2xxx_wait_target_ready(struct omap_hwmod *oh)
* slave idle; otherwise, pass along the return value of the
* appropriate *_cm*_wait_module_ready() function.
*/
-static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh)
+static int _omap2xxx_3xxx_wait_target_ready(struct omap_hwmod *oh)
{
if (!oh)
return -EINVAL;
@@ -2975,9 +2884,9 @@ static int _omap3xxx_wait_target_ready(struct omap_hwmod *oh)
/* XXX check module SIDLEMODE, hardreset status, enabled clocks */
- return omap3xxx_cm_wait_module_ready(oh->prcm.omap2.module_offs,
- oh->prcm.omap2.idlest_reg_id,
- oh->prcm.omap2.idlest_idle_bit);
+ return omap_cm_wait_module_ready(0, oh->prcm.omap2.module_offs,
+ oh->prcm.omap2.idlest_reg_id,
+ oh->prcm.omap2.idlest_idle_bit);
}
/**
@@ -3002,37 +2911,9 @@ static int _omap4_wait_target_ready(struct omap_hwmod *oh)
/* XXX check module SIDLEMODE, hardreset status */
- return omap4_cminst_wait_module_ready(oh->clkdm->prcm_partition,
- oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
-}
-
-/**
- * _am33xx_wait_target_ready - wait for a module to leave slave idle
- * @oh: struct omap_hwmod *
- *
- * Wait for a module @oh to leave slave idle. Returns 0 if the module
- * does not have an IDLEST bit or if the module successfully leaves
- * slave idle; otherwise, pass along the return value of the
- * appropriate *_cm*_wait_module_ready() function.
- */
-static int _am33xx_wait_target_ready(struct omap_hwmod *oh)
-{
- if (!oh || !oh->clkdm)
- return -EINVAL;
-
- if (oh->flags & HWMOD_NO_IDLEST)
- return 0;
-
- if (!_find_mpu_rt_port(oh))
- return 0;
-
- /* XXX check module SIDLEMODE, hardreset status */
-
- return am33xx_cm_wait_module_ready(oh->clkdm->cm_inst,
- oh->clkdm->clkdm_offs,
- oh->prcm.omap4.clkctrl_offs);
+ return omap_cm_wait_module_ready(oh->clkdm->prcm_partition,
+ oh->clkdm->cm_inst,
+ oh->prcm.omap4.clkctrl_offs, 0);
}
/**
@@ -3049,8 +2930,8 @@ static int _am33xx_wait_target_ready(struct omap_hwmod *oh)
static int _omap2_assert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- return omap2_prm_assert_hardreset(oh->prcm.omap2.module_offs,
- ohri->rst_shift);
+ return omap_prm_assert_hardreset(ohri->rst_shift, 0,
+ oh->prcm.omap2.module_offs, 0);
}
/**
@@ -3067,9 +2948,8 @@ static int _omap2_assert_hardreset(struct omap_hwmod *oh,
static int _omap2_deassert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- return omap2_prm_deassert_hardreset(oh->prcm.omap2.module_offs,
- ohri->rst_shift,
- ohri->st_shift);
+ return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
+ oh->prcm.omap2.module_offs, 0, 0);
}
/**
@@ -3087,8 +2967,8 @@ static int _omap2_deassert_hardreset(struct omap_hwmod *oh,
static int _omap2_is_hardreset_asserted(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- return omap2_prm_is_hardreset_asserted(oh->prcm.omap2.module_offs,
- ohri->st_shift);
+ return omap_prm_is_hardreset_asserted(ohri->st_shift, 0,
+ oh->prcm.omap2.module_offs, 0);
}
/**
@@ -3109,10 +2989,10 @@ static int _omap4_assert_hardreset(struct omap_hwmod *oh,
if (!oh->clkdm)
return -EINVAL;
- return omap4_prminst_assert_hardreset(ohri->rst_shift,
- oh->clkdm->pwrdm.ptr->prcm_partition,
- oh->clkdm->pwrdm.ptr->prcm_offs,
- oh->prcm.omap4.rstctrl_offs);
+ return omap_prm_assert_hardreset(ohri->rst_shift,
+ oh->clkdm->pwrdm.ptr->prcm_partition,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.rstctrl_offs);
}
/**
@@ -3136,10 +3016,10 @@ static int _omap4_deassert_hardreset(struct omap_hwmod *oh,
if (ohri->st_shift)
pr_err("omap_hwmod: %s: %s: hwmod data error: OMAP4 does not support st_shift\n",
oh->name, ohri->name);
- return omap4_prminst_deassert_hardreset(ohri->rst_shift,
- oh->clkdm->pwrdm.ptr->prcm_partition,
- oh->clkdm->pwrdm.ptr->prcm_offs,
- oh->prcm.omap4.rstctrl_offs);
+ return omap_prm_deassert_hardreset(ohri->rst_shift, 0,
+ oh->clkdm->pwrdm.ptr->prcm_partition,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.rstctrl_offs, 0);
}
/**
@@ -3160,10 +3040,11 @@ static int _omap4_is_hardreset_asserted(struct omap_hwmod *oh,
if (!oh->clkdm)
return -EINVAL;
- return omap4_prminst_is_hardreset_asserted(ohri->rst_shift,
- oh->clkdm->pwrdm.ptr->prcm_partition,
- oh->clkdm->pwrdm.ptr->prcm_offs,
- oh->prcm.omap4.rstctrl_offs);
+ return omap_prm_is_hardreset_asserted(ohri->rst_shift,
+ oh->clkdm->pwrdm.ptr->
+ prcm_partition,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.rstctrl_offs);
}
/**
@@ -3182,9 +3063,9 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- return am33xx_prm_assert_hardreset(ohri->rst_shift,
- oh->clkdm->pwrdm.ptr->prcm_offs,
- oh->prcm.omap4.rstctrl_offs);
+ return omap_prm_assert_hardreset(ohri->rst_shift, 0,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.rstctrl_offs);
}
/**
@@ -3202,11 +3083,10 @@ static int _am33xx_assert_hardreset(struct omap_hwmod *oh,
static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- return am33xx_prm_deassert_hardreset(ohri->rst_shift,
- ohri->st_shift,
- oh->clkdm->pwrdm.ptr->prcm_offs,
- oh->prcm.omap4.rstctrl_offs,
- oh->prcm.omap4.rstst_offs);
+ return omap_prm_deassert_hardreset(ohri->rst_shift, ohri->st_shift, 0,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.rstctrl_offs,
+ oh->prcm.omap4.rstst_offs);
}
/**
@@ -3224,9 +3104,9 @@ static int _am33xx_deassert_hardreset(struct omap_hwmod *oh,
static int _am33xx_is_hardreset_asserted(struct omap_hwmod *oh,
struct omap_hwmod_rst_info *ohri)
{
- return am33xx_prm_is_hardreset_asserted(ohri->rst_shift,
- oh->clkdm->pwrdm.ptr->prcm_offs,
- oh->prcm.omap4.rstctrl_offs);
+ return omap_prm_is_hardreset_asserted(ohri->rst_shift, 0,
+ oh->clkdm->pwrdm.ptr->prcm_offs,
+ oh->prcm.omap4.rstctrl_offs);
}
/* Public functions */
@@ -4234,12 +4114,12 @@ int omap_hwmod_pad_route_irq(struct omap_hwmod *oh, int pad_idx, int irq_idx)
void __init omap_hwmod_init(void)
{
if (cpu_is_omap24xx()) {
- soc_ops.wait_target_ready = _omap2xxx_wait_target_ready;
+ soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
soc_ops.assert_hardreset = _omap2_assert_hardreset;
soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
} else if (cpu_is_omap34xx()) {
- soc_ops.wait_target_ready = _omap3xxx_wait_target_ready;
+ soc_ops.wait_target_ready = _omap2xxx_3xxx_wait_target_ready;
soc_ops.assert_hardreset = _omap2_assert_hardreset;
soc_ops.deassert_hardreset = _omap2_deassert_hardreset;
soc_ops.is_hardreset_asserted = _omap2_is_hardreset_asserted;
@@ -4258,14 +4138,14 @@ void __init omap_hwmod_init(void)
soc_ops.enable_module = _omap4_enable_module;
soc_ops.disable_module = _omap4_disable_module;
soc_ops.wait_target_ready = _omap4_wait_target_ready;
- soc_ops.assert_hardreset = _am33xx_assert_hardreset;
- soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
- soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
+ soc_ops.assert_hardreset = _omap4_assert_hardreset;
+ soc_ops.deassert_hardreset = _omap4_deassert_hardreset;
+ soc_ops.is_hardreset_asserted = _omap4_is_hardreset_asserted;
soc_ops.init_clkdm = _init_clkdm;
} else if (soc_is_am33xx()) {
- soc_ops.enable_module = _am33xx_enable_module;
- soc_ops.disable_module = _am33xx_disable_module;
- soc_ops.wait_target_ready = _am33xx_wait_target_ready;
+ soc_ops.enable_module = _omap4_enable_module;
+ soc_ops.disable_module = _omap4_disable_module;
+ soc_ops.wait_target_ready = _omap4_wait_target_ready;
soc_ops.assert_hardreset = _am33xx_assert_hardreset;
soc_ops.deassert_hardreset = _am33xx_deassert_hardreset;
soc_ops.is_hardreset_asserted = _am33xx_is_hardreset_asserted;
diff --git a/arch/arm/mach-omap2/omap_hwmod.h b/arch/arm/mach-omap2/omap_hwmod.h
index 512f809..35ca6ef 100644
--- a/arch/arm/mach-omap2/omap_hwmod.h
+++ b/arch/arm/mach-omap2/omap_hwmod.h
@@ -633,6 +633,7 @@ struct omap_hwmod_link {
* @flags: hwmod flags (documented below)
* @_lock: spinlock serializing operations on this hwmod
* @node: list node for hwmod list (internal use)
+ * @parent_hwmod: (temporary) a pointer to the hierarchical parent of this hwmod
*
* @main_clk refers to this module's "main clock," which for our
* purposes is defined as "the functional clock needed for register
@@ -643,6 +644,12 @@ struct omap_hwmod_link {
* the omap_hwmod code and should not be set during initialization.
*
* @masters and @slaves are now deprecated.
+ *
+ * @parent_hwmod is temporary; there should be no need for it, as this
+ * information should already be expressed in the OCP interface
+ * structures. @parent_hwmod is present as a workaround until we improve
+ * handling for hwmods with multiple parents (e.g., OMAP4+ DSS with
+ * multiple register targets across different interconnects).
*/
struct omap_hwmod {
const char *name;
@@ -680,6 +687,7 @@ struct omap_hwmod {
u8 _int_flags;
u8 _state;
u8 _postsetup_state;
+ struct omap_hwmod *parent_hwmod;
};
struct omap_hwmod *omap_hwmod_lookup(const char *name);
diff --git a/arch/arm/mach-omap2/omap_hwmod_2430_data.c b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
index c2555cb..79127b3 100644
--- a/arch/arm/mach-omap2/omap_hwmod_2430_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_2430_data.c
@@ -15,12 +15,12 @@
#include <linux/i2c-omap.h>
#include <linux/platform_data/asoc-ti-mcbsp.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include <linux/omap-dma.h>
#include <plat/dmtimer.h>
#include "omap_hwmod.h"
-#include "mmc.h"
#include "l3_2xxx.h"
#include "soc.h"
@@ -372,7 +372,7 @@ static struct omap_hwmod_opt_clk omap2430_mmc1_opt_clks[] = {
{ .role = "dbck", .clk = "mmchsdb1_fck" },
};
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
index a579b89..cabc569 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_43xx_ipblock_data.c
@@ -15,10 +15,10 @@
*/
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include <linux/platform_data/spi-omap2-mcspi.h>
#include "omap_hwmod.h"
#include "i2c.h"
-#include "mmc.h"
#include "wd_timer.h"
#include "cm33xx.h"
#include "prm33xx.h"
@@ -836,7 +836,7 @@ static struct omap_hwmod_class am33xx_mmc_hwmod_class = {
};
/* mmc0 */
-static struct omap_mmc_dev_attr am33xx_mmc0_dev_attr = {
+static struct omap_hsmmc_dev_attr am33xx_mmc0_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@@ -854,7 +854,7 @@ struct omap_hwmod am33xx_mmc0_hwmod = {
};
/* mmc1 */
-static struct omap_mmc_dev_attr am33xx_mmc1_dev_attr = {
+static struct omap_hsmmc_dev_attr am33xx_mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@@ -872,7 +872,7 @@ struct omap_hwmod am33xx_mmc1_hwmod = {
};
/* mmc2 */
-static struct omap_mmc_dev_attr am33xx_mmc2_dev_attr = {
+static struct omap_hsmmc_dev_attr am33xx_mmc2_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
struct omap_hwmod am33xx_mmc2_hwmod = {
diff --git a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
index 6b406ca..0cf7b56 100644
--- a/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_33xx_data.c
@@ -27,7 +27,6 @@
#include "prm33xx.h"
#include "prm-regbits-33xx.h"
#include "i2c.h"
-#include "mmc.h"
#include "wd_timer.h"
#include "omap_hwmod_33xx_43xx_common_data.h"
diff --git a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
index 2a78b09..11468ee 100644
--- a/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_3xxx_data.c
@@ -18,6 +18,7 @@
#include <linux/i2c-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include <linux/omap-dma.h>
#include "l3_3xxx.h"
@@ -37,7 +38,6 @@
#include "cm-regbits-34xx.h"
#include "i2c.h"
-#include "mmc.h"
#include "wd_timer.h"
#include "serial.h"
@@ -1786,12 +1786,12 @@ static struct omap_hwmod_opt_clk omap34xx_mmc1_opt_clks[] = {
{ .role = "dbck", .clk = "omap_32k_fck", },
};
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
/* See 35xx errata 2.1.1.128 in SPRZ278F */
-static struct omap_mmc_dev_attr mmc1_pre_es3_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc1_pre_es3_dev_attr = {
.flags = (OMAP_HSMMC_SUPPORTS_DUAL_VOLT |
OMAP_HSMMC_BROKEN_MULTIBLOCK_READ),
};
@@ -1854,7 +1854,7 @@ static struct omap_hwmod_opt_clk omap34xx_mmc2_opt_clks[] = {
};
/* See 35xx errata 2.1.1.128 in SPRZ278F */
-static struct omap_mmc_dev_attr mmc2_pre_es3_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc2_pre_es3_dev_attr = {
.flags = OMAP_HSMMC_BROKEN_MULTIBLOCK_READ,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
index fea01aa..5c6c841 100644
--- a/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_43xx_data.c
@@ -417,6 +417,37 @@ static struct omap_hwmod am43xx_qspi_hwmod = {
},
};
+/*
+ * 'adc/tsc' class
+ * TouchScreen Controller (Analog-To-Digital Converter)
+ */
+static struct omap_hwmod_class_sysconfig am43xx_adc_tsc_sysc = {
+ .rev_offs = 0x00,
+ .sysc_offs = 0x10,
+ .sysc_flags = SYSC_HAS_SIDLEMODE,
+ .idlemodes = (SIDLE_FORCE | SIDLE_NO | SIDLE_SMART |
+ SIDLE_SMART_WKUP),
+ .sysc_fields = &omap_hwmod_sysc_type2,
+};
+
+static struct omap_hwmod_class am43xx_adc_tsc_hwmod_class = {
+ .name = "adc_tsc",
+ .sysc = &am43xx_adc_tsc_sysc,
+};
+
+static struct omap_hwmod am43xx_adc_tsc_hwmod = {
+ .name = "adc_tsc",
+ .class = &am43xx_adc_tsc_hwmod_class,
+ .clkdm_name = "l3s_tsc_clkdm",
+ .main_clk = "adc_tsc_fck",
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = AM43XX_CM_WKUP_ADC_TSC_CLKCTRL_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
/* dss */
static struct omap_hwmod am43xx_dss_core_hwmod = {
@@ -547,6 +578,13 @@ static struct omap_hwmod_ocp_if am43xx_l4_wkup__gpio0 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+static struct omap_hwmod_ocp_if am43xx_l4_wkup__adc_tsc = {
+ .master = &am33xx_l4_wkup_hwmod,
+ .slave = &am43xx_adc_tsc_hwmod,
+ .clk = "dpll_core_m4_div2_ck",
+ .user = OCP_USER_MPU,
+};
+
static struct omap_hwmod_ocp_if am43xx_l4_hs__cpgmac0 = {
.master = &am43xx_l4_hs_hwmod,
.slave = &am33xx_cpgmac0_hwmod,
@@ -789,6 +827,7 @@ static struct omap_hwmod_ocp_if *am43xx_hwmod_ocp_ifs[] __initdata = {
&am43xx_l4_wkup__i2c1,
&am43xx_l4_wkup__gpio0,
&am43xx_l4_wkup__wd_timer1,
+ &am43xx_l4_wkup__adc_tsc,
&am43xx_l3_s__qspi,
&am33xx_l4_per__dcan0,
&am33xx_l4_per__dcan1,
diff --git a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
index 44e5634..c314b3c 100644
--- a/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_44xx_data.c
@@ -22,6 +22,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h>
@@ -39,7 +40,6 @@
#include "prm44xx.h"
#include "prm-regbits-44xx.h"
#include "i2c.h"
-#include "mmc.h"
#include "wd_timer.h"
/* Base offset for all OMAP4 interrupts external to MPUSS */
@@ -589,6 +589,7 @@ static struct omap_hwmod omap44xx_dss_hwmod = {
.omap4 = {
.clkctrl_offs = OMAP4_CM_DSS_DSS_CLKCTRL_OFFSET,
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
},
},
.opt_clks = dss_opt_clks,
@@ -647,7 +648,8 @@ static struct omap_hwmod omap44xx_dss_dispc_hwmod = {
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
},
},
- .dev_attr = &omap44xx_dss_dispc_dev_attr
+ .dev_attr = &omap44xx_dss_dispc_dev_attr,
+ .parent_hwmod = &omap44xx_dss_hwmod,
};
/*
@@ -701,6 +703,7 @@ static struct omap_hwmod omap44xx_dss_dsi1_hwmod = {
},
.opt_clks = dss_dsi1_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_opt_clks),
+ .parent_hwmod = &omap44xx_dss_hwmod,
};
/* dss_dsi2 */
@@ -733,6 +736,7 @@ static struct omap_hwmod omap44xx_dss_dsi2_hwmod = {
},
.opt_clks = dss_dsi2_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi2_opt_clks),
+ .parent_hwmod = &omap44xx_dss_hwmod,
};
/*
@@ -790,6 +794,7 @@ static struct omap_hwmod omap44xx_dss_hdmi_hwmod = {
},
.opt_clks = dss_hdmi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks),
+ .parent_hwmod = &omap44xx_dss_hwmod,
};
/*
@@ -819,7 +824,7 @@ static struct omap_hwmod_dma_info omap44xx_dss_rfbi_sdma_reqs[] = {
};
static struct omap_hwmod_opt_clk dss_rfbi_opt_clks[] = {
- { .role = "ick", .clk = "dss_fck" },
+ { .role = "ick", .clk = "l3_div_ck" },
};
static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
@@ -836,6 +841,7 @@ static struct omap_hwmod omap44xx_dss_rfbi_hwmod = {
},
.opt_clks = dss_rfbi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
+ .parent_hwmod = &omap44xx_dss_hwmod,
};
/*
@@ -859,6 +865,7 @@ static struct omap_hwmod omap44xx_dss_venc_hwmod = {
.context_offs = OMAP4_RM_DSS_DSS_CONTEXT_OFFSET,
},
},
+ .parent_hwmod = &omap44xx_dss_hwmod,
};
/*
@@ -1952,7 +1959,7 @@ static struct omap_hwmod_dma_info omap44xx_mmc1_sdma_reqs[] = {
};
/* mmc1 dev_attr */
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@@ -3671,7 +3678,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_dma_addrs,
.user = OCP_USER_SDMA,
};
@@ -3707,7 +3714,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dispc_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dispc = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_dispc_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_dispc_dma_addrs,
.user = OCP_USER_SDMA,
};
@@ -3743,7 +3750,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi1_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi1 = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_dsi1_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_dsi1_dma_addrs,
.user = OCP_USER_SDMA,
};
@@ -3779,7 +3786,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_dsi2_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_dsi2 = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_dsi2_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_dsi2_dma_addrs,
.user = OCP_USER_SDMA,
};
@@ -3815,7 +3822,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_hdmi_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_hdmi = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_hdmi_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_hdmi_dma_addrs,
.user = OCP_USER_SDMA,
};
@@ -3851,7 +3858,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_rfbi_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_rfbi = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_rfbi_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_rfbi_dma_addrs,
.user = OCP_USER_SDMA,
};
@@ -3887,7 +3894,7 @@ static struct omap_hwmod_addr_space omap44xx_dss_venc_dma_addrs[] = {
static struct omap_hwmod_ocp_if omap44xx_l3_main_2__dss_venc = {
.master = &omap44xx_l3_main_2_hwmod,
.slave = &omap44xx_dss_venc_hwmod,
- .clk = "dss_fck",
+ .clk = "l3_div_ck",
.addr = omap44xx_dss_venc_dma_addrs,
.user = OCP_USER_SDMA,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
index 1103aa0..3e95230 100644
--- a/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_54xx_data.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h>
@@ -33,7 +34,6 @@
#include "cm2_54xx.h"
#include "prm54xx.h"
#include "i2c.h"
-#include "mmc.h"
#include "wd_timer.h"
/* Base offset for all OMAP5 interrupts external to MPUSS */
@@ -421,6 +421,7 @@ static struct omap_hwmod omap54xx_dss_dispc_hwmod = {
.opt_clks = dss_dispc_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dispc_opt_clks),
.dev_attr = &dss_dispc_dev_attr,
+ .parent_hwmod = &omap54xx_dss_hwmod,
};
/*
@@ -462,6 +463,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_a_hwmod = {
},
.opt_clks = dss_dsi1_a_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_a_opt_clks),
+ .parent_hwmod = &omap54xx_dss_hwmod,
};
/* dss_dsi1_c */
@@ -482,6 +484,7 @@ static struct omap_hwmod omap54xx_dss_dsi1_c_hwmod = {
},
.opt_clks = dss_dsi1_c_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_dsi1_c_opt_clks),
+ .parent_hwmod = &omap54xx_dss_hwmod,
};
/*
@@ -521,6 +524,7 @@ static struct omap_hwmod omap54xx_dss_hdmi_hwmod = {
},
.opt_clks = dss_hdmi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_hdmi_opt_clks),
+ .parent_hwmod = &omap54xx_dss_hwmod,
};
/*
@@ -560,6 +564,7 @@ static struct omap_hwmod omap54xx_dss_rfbi_hwmod = {
},
.opt_clks = dss_rfbi_opt_clks,
.opt_clks_cnt = ARRAY_SIZE(dss_rfbi_opt_clks),
+ .parent_hwmod = &omap54xx_dss_hwmod,
};
/*
@@ -1269,7 +1274,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
};
/* mmc1 dev_attr */
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
diff --git a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
index 5684f11..ffd6604 100644
--- a/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
+++ b/arch/arm/mach-omap2/omap_hwmod_7xx_data.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/platform_data/gpio-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
#include <linux/power/smartreflex.h>
#include <linux/i2c-omap.h>
@@ -33,7 +34,6 @@
#include "cm2_7xx.h"
#include "prm7xx.h"
#include "i2c.h"
-#include "mmc.h"
#include "wd_timer.h"
#include "soc.h"
@@ -1301,7 +1301,7 @@ static struct omap_hwmod_opt_clk mmc1_opt_clks[] = {
};
/* mmc1 dev_attr */
-static struct omap_mmc_dev_attr mmc1_dev_attr = {
+static struct omap_hsmmc_dev_attr mmc1_dev_attr = {
.flags = OMAP_HSMMC_SUPPORTS_DUAL_VOLT,
};
@@ -2075,6 +2075,70 @@ static struct omap_hwmod dra7xx_uart6_hwmod = {
},
};
+/* uart7 */
+static struct omap_hwmod dra7xx_uart7_hwmod = {
+ .name = "uart7",
+ .class = &dra7xx_uart_hwmod_class,
+ .clkdm_name = "l4per2_clkdm",
+ .main_clk = "uart7_gfclk_mux",
+ .flags = HWMOD_SWSUP_SIDLE_ACT,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DRA7XX_CM_L4PER2_UART7_CLKCTRL_OFFSET,
+ .context_offs = DRA7XX_RM_L4PER2_UART7_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+/* uart8 */
+static struct omap_hwmod dra7xx_uart8_hwmod = {
+ .name = "uart8",
+ .class = &dra7xx_uart_hwmod_class,
+ .clkdm_name = "l4per2_clkdm",
+ .main_clk = "uart8_gfclk_mux",
+ .flags = HWMOD_SWSUP_SIDLE_ACT,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DRA7XX_CM_L4PER2_UART8_CLKCTRL_OFFSET,
+ .context_offs = DRA7XX_RM_L4PER2_UART8_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+/* uart9 */
+static struct omap_hwmod dra7xx_uart9_hwmod = {
+ .name = "uart9",
+ .class = &dra7xx_uart_hwmod_class,
+ .clkdm_name = "l4per2_clkdm",
+ .main_clk = "uart9_gfclk_mux",
+ .flags = HWMOD_SWSUP_SIDLE_ACT,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DRA7XX_CM_L4PER2_UART9_CLKCTRL_OFFSET,
+ .context_offs = DRA7XX_RM_L4PER2_UART9_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
+/* uart10 */
+static struct omap_hwmod dra7xx_uart10_hwmod = {
+ .name = "uart10",
+ .class = &dra7xx_uart_hwmod_class,
+ .clkdm_name = "wkupaon_clkdm",
+ .main_clk = "uart10_gfclk_mux",
+ .flags = HWMOD_SWSUP_SIDLE_ACT,
+ .prcm = {
+ .omap4 = {
+ .clkctrl_offs = DRA7XX_CM_WKUPAON_UART10_CLKCTRL_OFFSET,
+ .context_offs = DRA7XX_RM_WKUPAON_UART10_CONTEXT_OFFSET,
+ .modulemode = MODULEMODE_SWCTRL,
+ },
+ },
+};
+
/*
* 'usb_otg_ss' class
*
@@ -3095,6 +3159,38 @@ static struct omap_hwmod_ocp_if dra7xx_l4_per1__uart6 = {
.user = OCP_USER_MPU | OCP_USER_SDMA,
};
+/* l4_per2 -> uart7 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart7 = {
+ .master = &dra7xx_l4_per2_hwmod,
+ .slave = &dra7xx_uart7_hwmod,
+ .clk = "l3_iclk_div",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per2 -> uart8 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart8 = {
+ .master = &dra7xx_l4_per2_hwmod,
+ .slave = &dra7xx_uart8_hwmod,
+ .clk = "l3_iclk_div",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_per2 -> uart9 */
+static struct omap_hwmod_ocp_if dra7xx_l4_per2__uart9 = {
+ .master = &dra7xx_l4_per2_hwmod,
+ .slave = &dra7xx_uart9_hwmod,
+ .clk = "l3_iclk_div",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
+/* l4_wkup -> uart10 */
+static struct omap_hwmod_ocp_if dra7xx_l4_wkup__uart10 = {
+ .master = &dra7xx_l4_wkup_hwmod,
+ .slave = &dra7xx_uart10_hwmod,
+ .clk = "wkupaon_iclk_mux",
+ .user = OCP_USER_MPU | OCP_USER_SDMA,
+};
+
/* l4_per3 -> usb_otg_ss1 */
static struct omap_hwmod_ocp_if dra7xx_l4_per3__usb_otg_ss1 = {
.master = &dra7xx_l4_per3_hwmod,
@@ -3259,6 +3355,10 @@ static struct omap_hwmod_ocp_if *dra7xx_hwmod_ocp_ifs[] __initdata = {
&dra7xx_l4_per1__uart4,
&dra7xx_l4_per1__uart5,
&dra7xx_l4_per1__uart6,
+ &dra7xx_l4_per2__uart7,
+ &dra7xx_l4_per2__uart8,
+ &dra7xx_l4_per2__uart9,
+ &dra7xx_l4_wkup__uart10,
&dra7xx_l4_per3__usb_otg_ss1,
&dra7xx_l4_per3__usb_otg_ss2,
&dra7xx_l4_per3__usb_otg_ss3,
diff --git a/arch/arm/mach-omap2/omap_phy_internal.c b/arch/arm/mach-omap2/omap_phy_internal.c
index 50640b3..1a19fa0 100644
--- a/arch/arm/mach-omap2/omap_phy_internal.c
+++ b/arch/arm/mach-omap2/omap_phy_internal.c
@@ -21,6 +21,8 @@
*
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/types.h>
#include <linux/delay.h>
#include <linux/clk.h>
@@ -97,13 +99,13 @@ void am35x_musb_phy_power(u8 on)
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
- pr_info(KERN_INFO "Waiting for PHY clock good...\n");
+ pr_info("Waiting for PHY clock good...\n");
while (!(omap_ctrl_readl(AM35XX_CONTROL_DEVCONF2)
& CONF2_PHYCLKGD)) {
cpu_relax();
if (time_after(jiffies, timeout)) {
- pr_err(KERN_ERR "musb PHY clock good timed out\n");
+ pr_err("musb PHY clock good timed out\n");
break;
}
}
@@ -145,7 +147,7 @@ void am35x_set_mode(u8 musb_mode)
devconf2 |= CONF2_NO_OVERRIDE;
break;
default:
- pr_info(KERN_INFO "Unsupported mode %u\n", musb_mode);
+ pr_info("Unsupported mode %u\n", musb_mode);
}
omap_ctrl_writel(devconf2, AM35XX_CONTROL_DEVCONF2);
diff --git a/arch/arm/mach-omap2/pdata-quirks.c b/arch/arm/mach-omap2/pdata-quirks.c
index cec9d6c..3d7eee1 100644
--- a/arch/arm/mach-omap2/pdata-quirks.c
+++ b/arch/arm/mach-omap2/pdata-quirks.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/of_platform.h>
+#include <linux/ti_wilink_st.h>
#include <linux/wl12xx.h>
#include <linux/platform_data/pinctrl-single.h>
@@ -130,17 +131,45 @@ static void __init omap3_sbc_t3730_legacy_init(void)
{
omap3_sbc_t3x_usb_hub_init(167, "sb-t35 usb hub");
legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 136);
- omap_ads7846_init(1, 57, 0, NULL);
}
static void __init omap3_sbc_t3530_legacy_init(void)
{
omap3_sbc_t3x_usb_hub_init(167, "sb-t35 usb hub");
- omap_ads7846_init(1, 57, 0, NULL);
}
-static void __init omap3_igep0020_legacy_init(void)
+struct ti_st_plat_data wilink_pdata = {
+ .nshutdown_gpio = 137,
+ .dev_name = "/dev/ttyO1",
+ .flow_cntrl = 1,
+ .baud_rate = 300000,
+};
+
+static struct platform_device wl18xx_device = {
+ .name = "kim",
+ .id = -1,
+ .dev = {
+ .platform_data = &wilink_pdata,
+ }
+};
+
+static struct platform_device btwilink_device = {
+ .name = "btwilink",
+ .id = -1,
+};
+
+static void __init omap3_igep0020_rev_f_legacy_init(void)
+{
+ legacy_init_wl12xx(0, 0, 177);
+ platform_device_register(&wl18xx_device);
+ platform_device_register(&btwilink_device);
+}
+
+static void __init omap3_igep0030_rev_g_legacy_init(void)
{
+ legacy_init_wl12xx(0, 0, 136);
+ platform_device_register(&wl18xx_device);
+ platform_device_register(&btwilink_device);
}
static void __init omap3_evm_legacy_init(void)
@@ -218,7 +247,6 @@ static void __init omap3_sbc_t3517_legacy_init(void)
hsmmc2_internal_input_clk();
omap3_sbc_t3517_wifi_init();
legacy_init_wl12xx(WL12XX_REFCLOCK_38, 0, 145);
- omap_ads7846_init(1, 57, 0, NULL);
}
static void __init am3517_evm_legacy_init(void)
@@ -390,7 +418,8 @@ static struct pdata_init pdata_quirks[] __initdata = {
{ "nokia,omap3-n900", nokia_n900_legacy_init, },
{ "nokia,omap3-n9", hsmmc2_internal_input_clk, },
{ "nokia,omap3-n950", hsmmc2_internal_input_clk, },
- { "isee,omap3-igep0020", omap3_igep0020_legacy_init, },
+ { "isee,omap3-igep0020-rev-f", omap3_igep0020_rev_f_legacy_init, },
+ { "isee,omap3-igep0030-rev-g", omap3_igep0030_rev_g_legacy_init, },
{ "ti,omap3-evm-37xx", omap3_evm_legacy_init, },
{ "ti,omap3-zoom3", omap3_zoom_legacy_init, },
{ "ti,am3517-evm", am3517_evm_legacy_init, },
diff --git a/arch/arm/mach-omap2/pm34xx.c b/arch/arm/mach-omap2/pm34xx.c
index 175564c..88721df 100644
--- a/arch/arm/mach-omap2/pm34xx.c
+++ b/arch/arm/mach-omap2/pm34xx.c
@@ -29,6 +29,7 @@
#include <linux/delay.h>
#include <linux/slab.h>
#include <linux/omap-dma.h>
+#include <linux/omap-gpmc.h>
#include <linux/platform_data/gpio-omap.h>
#include <trace/events/power.h>
@@ -43,7 +44,6 @@
#include "common.h"
#include "cm3xxx.h"
#include "cm-regbits-34xx.h"
-#include "gpmc.h"
#include "prm-regbits-34xx.h"
#include "prm3xxx.h"
#include "pm.h"
diff --git a/arch/arm/mach-omap2/pm44xx.c b/arch/arm/mach-omap2/pm44xx.c
index 503097c..d697cec 100644
--- a/arch/arm/mach-omap2/pm44xx.c
+++ b/arch/arm/mach-omap2/pm44xx.c
@@ -37,6 +37,16 @@ struct power_state {
struct list_head node;
};
+/**
+ * struct static_dep_map - Static dependency map
+ * @from: from clockdomain
+ * @to: to clockdomain
+ */
+struct static_dep_map {
+ const char *from;
+ const char *to;
+};
+
static u32 cpu_suspend_state = PWRDM_POWER_OFF;
static LIST_HEAD(pwrst_list);
@@ -148,94 +158,61 @@ static void omap_default_idle(void)
omap_do_wfi();
}
-/**
- * omap4_init_static_deps - Add OMAP4 static dependencies
- *
- * Add needed static clockdomain dependencies on OMAP4 devices.
- * Return: 0 on success or 'err' on failures
+/*
+ * The dynamic dependency between MPUSS -> MEMIF and
+ * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
+ * expected. The hardware recommendation is to enable static
+ * dependencies for these to avoid system lock ups or random crashes.
+ * The L4 wakeup depedency is added to workaround the OCP sync hardware
+ * BUG with 32K synctimer which lead to incorrect timer value read
+ * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
+ * are part of L4 wakeup clockdomain.
*/
-static inline int omap4_init_static_deps(void)
-{
- struct clockdomain *emif_clkdm, *mpuss_clkdm, *l3_1_clkdm;
- struct clockdomain *ducati_clkdm, *l3_2_clkdm;
- int ret = 0;
-
- if (omap_rev() == OMAP4430_REV_ES1_0) {
- WARN(1, "Power Management not supported on OMAP4430 ES1.0\n");
- return -ENODEV;
- }
-
- pr_err("Power Management for TI OMAP4.\n");
- /*
- * OMAP4 chip PM currently works only with certain (newer)
- * versions of bootloaders. This is due to missing code in the
- * kernel to properly reset and initialize some devices.
- * http://www.spinics.net/lists/arm-kernel/msg218641.html
- */
- pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
-
- ret = pwrdm_for_each(pwrdms_setup, NULL);
- if (ret) {
- pr_err("Failed to setup powerdomains\n");
- return ret;
- }
-
- /*
- * The dynamic dependency between MPUSS -> MEMIF and
- * MPUSS -> L4_PER/L3_* and DUCATI -> L3_* doesn't work as
- * expected. The hardware recommendation is to enable static
- * dependencies for these to avoid system lock ups or random crashes.
- * The L4 wakeup depedency is added to workaround the OCP sync hardware
- * BUG with 32K synctimer which lead to incorrect timer value read
- * from the 32K counter. The BUG applies for GPTIMER1 and WDT2 which
- * are part of L4 wakeup clockdomain.
- */
- mpuss_clkdm = clkdm_lookup("mpuss_clkdm");
- emif_clkdm = clkdm_lookup("l3_emif_clkdm");
- l3_1_clkdm = clkdm_lookup("l3_1_clkdm");
- l3_2_clkdm = clkdm_lookup("l3_2_clkdm");
- ducati_clkdm = clkdm_lookup("ducati_clkdm");
- if ((!mpuss_clkdm) || (!emif_clkdm) || (!l3_1_clkdm) ||
- (!l3_2_clkdm) || (!ducati_clkdm))
- return -EINVAL;
-
- ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
- ret |= clkdm_add_wkdep(mpuss_clkdm, l3_1_clkdm);
- ret |= clkdm_add_wkdep(mpuss_clkdm, l3_2_clkdm);
- ret |= clkdm_add_wkdep(ducati_clkdm, l3_1_clkdm);
- ret |= clkdm_add_wkdep(ducati_clkdm, l3_2_clkdm);
- if (ret) {
- pr_err("Failed to add MPUSS -> L3/EMIF/L4PER, DUCATI -> L3 wakeup dependency\n");
- return -EINVAL;
- }
+static const struct static_dep_map omap4_static_dep_map[] = {
+ {.from = "mpuss_clkdm", .to = "l3_emif_clkdm"},
+ {.from = "mpuss_clkdm", .to = "l3_1_clkdm"},
+ {.from = "mpuss_clkdm", .to = "l3_2_clkdm"},
+ {.from = "ducati_clkdm", .to = "l3_1_clkdm"},
+ {.from = "ducati_clkdm", .to = "l3_2_clkdm"},
+ {.from = NULL} /* TERMINATION */
+};
- return ret;
-}
+static const struct static_dep_map omap5_dra7_static_dep_map[] = {
+ {.from = "mpu_clkdm", .to = "emif_clkdm"},
+ {.from = NULL} /* TERMINATION */
+};
/**
- * omap5_dra7_init_static_deps - Init static clkdm dependencies on OMAP5 and
- * DRA7
- *
- * The dynamic dependency between MPUSS -> EMIF is broken and has
- * not worked as expected. The hardware recommendation is to
- * enable static dependencies for these to avoid system
- * lock ups or random crashes.
+ * omap4plus_init_static_deps() - Initialize a static dependency map
+ * @map: Mapping of clock domains
*/
-static inline int omap5_dra7_init_static_deps(void)
+static inline int omap4plus_init_static_deps(const struct static_dep_map *map)
{
- struct clockdomain *mpuss_clkdm, *emif_clkdm;
int ret;
+ struct clockdomain *from, *to;
+
+ if (!map)
+ return 0;
- mpuss_clkdm = clkdm_lookup("mpu_clkdm");
- emif_clkdm = clkdm_lookup("emif_clkdm");
- if (!mpuss_clkdm || !emif_clkdm)
- return -EINVAL;
+ while (map->from) {
+ from = clkdm_lookup(map->from);
+ to = clkdm_lookup(map->to);
+ if (!from || !to) {
+ pr_err("Failed lookup %s or %s for wakeup dependency\n",
+ map->from, map->to);
+ return -EINVAL;
+ }
+ ret = clkdm_add_wkdep(from, to);
+ if (ret) {
+ pr_err("Failed to add %s -> %s wakeup dependency(%d)\n",
+ map->from, map->to, ret);
+ return ret;
+ }
- ret = clkdm_add_wkdep(mpuss_clkdm, emif_clkdm);
- if (ret)
- pr_err("Failed to add MPUSS -> EMIF wakeup dependency\n");
+ map++;
+ };
- return ret;
+ return 0;
}
/**
@@ -272,6 +249,15 @@ int __init omap4_pm_init(void)
pr_info("Power Management for TI OMAP4+ devices.\n");
+ /*
+ * OMAP4 chip PM currently works only with certain (newer)
+ * versions of bootloaders. This is due to missing code in the
+ * kernel to properly reset and initialize some devices.
+ * http://www.spinics.net/lists/arm-kernel/msg218641.html
+ */
+ if (cpu_is_omap44xx())
+ pr_warn("OMAP4 PM: u-boot >= v2012.07 is required for full PM support\n");
+
ret = pwrdm_for_each(pwrdms_setup, NULL);
if (ret) {
pr_err("Failed to setup powerdomains.\n");
@@ -279,9 +265,9 @@ int __init omap4_pm_init(void)
}
if (cpu_is_omap44xx())
- ret = omap4_init_static_deps();
+ ret = omap4plus_init_static_deps(omap4_static_dep_map);
else if (soc_is_omap54xx() || soc_is_dra7xx())
- ret = omap5_dra7_init_static_deps();
+ ret = omap4plus_init_static_deps(omap5_dra7_static_dep_map);
if (ret) {
pr_err("Failed to initialise static dependencies.\n");
diff --git a/arch/arm/mach-omap2/prm.h b/arch/arm/mach-omap2/prm.h
index 48480d5..77752e4 100644
--- a/arch/arm/mach-omap2/prm.h
+++ b/arch/arm/mach-omap2/prm.h
@@ -29,6 +29,7 @@ int of_prcm_init(void);
* PRM_HAS_VOLTAGE: has voltage domains
*/
#define PRM_HAS_IO_WAKEUP (1 << 0)
+#define PRM_HAS_VOLTAGE (1 << 1)
/*
* MAX_MODULE_SOFTRESET_WAIT: Maximum microseconds to wait for OMAP
@@ -127,6 +128,8 @@ struct prm_reset_src_map {
* @was_any_context_lost_old: ptr to the SoC PRM context loss test fn
* @clear_context_loss_flags_old: ptr to the SoC PRM context loss flag clear fn
* @late_init: ptr to the late init function
+ * @assert_hardreset: ptr to the SoC PRM hardreset assert impl
+ * @deassert_hardreset: ptr to the SoC PRM hardreset deassert impl
*
* XXX @was_any_context_lost_old and @clear_context_loss_flags_old are
* deprecated.
@@ -136,14 +139,27 @@ struct prm_ll_data {
bool (*was_any_context_lost_old)(u8 part, s16 inst, u16 idx);
void (*clear_context_loss_flags_old)(u8 part, s16 inst, u16 idx);
int (*late_init)(void);
+ int (*assert_hardreset)(u8 shift, u8 part, s16 prm_mod, u16 offset);
+ int (*deassert_hardreset)(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
+ u16 offset, u16 st_offset);
+ int (*is_hardreset_asserted)(u8 shift, u8 part, s16 prm_mod,
+ u16 offset);
+ void (*reset_system)(void);
};
extern int prm_register(struct prm_ll_data *pld);
extern int prm_unregister(struct prm_ll_data *pld);
+int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset);
+int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
+ u16 offset, u16 st_offset);
+int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset);
extern u32 prm_read_reset_sources(void);
extern bool prm_was_any_context_lost_old(u8 part, s16 inst, u16 idx);
extern void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx);
+void omap_prm_reset_system(void);
+
+void omap_prm_reconfigure_io_chain(void);
#endif
diff --git a/arch/arm/mach-omap2/prm2xxx.c b/arch/arm/mach-omap2/prm2xxx.c
index 8695805..af0f152 100644
--- a/arch/arm/mach-omap2/prm2xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx.c
@@ -106,7 +106,7 @@ static int omap2xxx_pwrst_to_common_pwrst(u8 omap2xxx_pwrst)
* Set the DPLL reset bit, which should reboot the SoC. This is the
* recommended way to restart the SoC. No return value.
*/
-void omap2xxx_prm_dpll_reset(void)
+static void omap2xxx_prm_dpll_reset(void)
{
omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, WKUP_MOD,
OMAP2_RM_RSTCTRL);
@@ -212,6 +212,10 @@ struct pwrdm_ops omap2_pwrdm_operations = {
static struct prm_ll_data omap2xxx_prm_ll_data = {
.read_reset_sources = &omap2xxx_prm_read_reset_sources,
+ .assert_hardreset = &omap2_prm_assert_hardreset,
+ .deassert_hardreset = &omap2_prm_deassert_hardreset,
+ .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
+ .reset_system = &omap2xxx_prm_dpll_reset,
};
int __init omap2xxx_prm_init(void)
diff --git a/arch/arm/mach-omap2/prm2xxx.h b/arch/arm/mach-omap2/prm2xxx.h
index d734141..1d51643 100644
--- a/arch/arm/mach-omap2/prm2xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx.h
@@ -124,7 +124,6 @@
extern int omap2xxx_clkdm_sleep(struct clockdomain *clkdm);
extern int omap2xxx_clkdm_wakeup(struct clockdomain *clkdm);
-extern void omap2xxx_prm_dpll_reset(void);
void omap2xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 wkst_mask);
extern int __init omap2xxx_prm_init(void);
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.c b/arch/arm/mach-omap2/prm2xxx_3xxx.c
index c13b4e2..cc3341f 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.c
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.c
@@ -24,14 +24,16 @@
/**
* omap2_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module
- * @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to check
+ * @part: PRM partition, ignored for OMAP2
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @offset: register offset, ignored for OMAP2
*
* Returns 1 if the (sub)module hardreset line is currently asserted,
* 0 if the (sub)module hardreset line is not currently asserted, or
* -EINVAL if called while running on a non-OMAP2/3 chip.
*/
-int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
+int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
{
return omap2_prm_read_mod_bits_shift(prm_mod, OMAP2_RM_RSTCTRL,
(1 << shift));
@@ -39,8 +41,10 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
/**
* omap2_prm_assert_hardreset - assert the HW reset line of a submodule
- * @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @shift: register bit shift corresponding to the reset line to assert
+ * @part: PRM partition, ignored for OMAP2
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @offset: register offset, ignored for OMAP2
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
@@ -49,7 +53,7 @@ int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift)
* place the submodule into reset. Returns 0 upon success or -EINVAL
* upon an argument error.
*/
-int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
+int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
{
u32 mask;
@@ -64,6 +68,10 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
* @prm_mod: PRM submodule base (e.g. CORE_MOD)
* @rst_shift: register bit shift corresponding to the reset line to deassert
* @st_shift: register bit shift for the status of the deasserted submodule
+ * @part: PRM partition, not used for OMAP2
+ * @prm_mod: PRM submodule base (e.g. CORE_MOD)
+ * @rst_offset: reset register offset, not used for OMAP2
+ * @st_offset: reset status register offset, not used for OMAP2
*
* Some IPs like dsp or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
@@ -74,7 +82,8 @@ int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift)
* -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly.
*/
-int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift)
+int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part,
+ s16 prm_mod, u16 rst_offset, u16 st_offset)
{
u32 rst, st;
int c;
diff --git a/arch/arm/mach-omap2/prm2xxx_3xxx.h b/arch/arm/mach-omap2/prm2xxx_3xxx.h
index 1a3a963..f57e29b 100644
--- a/arch/arm/mach-omap2/prm2xxx_3xxx.h
+++ b/arch/arm/mach-omap2/prm2xxx_3xxx.h
@@ -100,9 +100,12 @@ static inline u32 omap2_prm_clear_mod_reg_bits(u32 bits, s16 module, s16 idx)
}
/* These omap2_ PRM functions apply to both OMAP2 and 3 */
-extern int omap2_prm_is_hardreset_asserted(s16 prm_mod, u8 shift);
-extern int omap2_prm_assert_hardreset(s16 prm_mod, u8 shift);
-extern int omap2_prm_deassert_hardreset(s16 prm_mod, u8 rst_shift, u8 st_shift);
+int omap2_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset);
+int omap2_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod,
+ u16 offset);
+int omap2_prm_deassert_hardreset(u8 rst_shift, u8 st_shift, u8 part,
+ s16 prm_mod, u16 reset_offset,
+ u16 st_offset);
extern int omap2_pwrdm_set_next_pwrst(struct powerdomain *pwrdm, u8 pwrst);
extern int omap2_pwrdm_read_next_pwrst(struct powerdomain *pwrdm);
diff --git a/arch/arm/mach-omap2/prm33xx.c b/arch/arm/mach-omap2/prm33xx.c
index 62709cd..02f62860 100644
--- a/arch/arm/mach-omap2/prm33xx.c
+++ b/arch/arm/mach-omap2/prm33xx.c
@@ -23,20 +23,24 @@
#include "prm33xx.h"
#include "prm-regbits-33xx.h"
+#define AM33XX_PRM_RSTCTRL_OFFSET 0x0000
+
+#define AM33XX_RST_GLOBAL_WARM_SW_MASK (1 << 0)
+
/* Read a register in a PRM instance */
-u32 am33xx_prm_read_reg(s16 inst, u16 idx)
+static u32 am33xx_prm_read_reg(s16 inst, u16 idx)
{
return readl_relaxed(prm_base + inst + idx);
}
/* Write into a register in a PRM instance */
-void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
+static void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx)
{
writel_relaxed(val, prm_base + inst + idx);
}
/* Read-modify-write a register in PRM. Caller must lock */
-u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
+static u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
{
u32 v;
@@ -52,6 +56,7 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
* am33xx_prm_is_hardreset_asserted - read the HW reset line state of
* submodules contained in the hwmod module
* @shift: register bit shift corresponding to the reset line to check
+ * @part: PRM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro)
* @rstctrl_offs: RM_RSTCTRL register address offset for this module
*
@@ -59,7 +64,8 @@ u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx)
* 0 if the (sub)module hardreset line is not currently asserted, or
* -EINVAL upon parameter error.
*/
-int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs)
+static int am33xx_prm_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
+ u16 rstctrl_offs)
{
u32 v;
@@ -73,6 +79,7 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs)
/**
* am33xx_prm_assert_hardreset - assert the HW reset line of a submodule
* @shift: register bit shift corresponding to the reset line to assert
+ * @part: CM partition, ignored for AM33xx
* @inst: CM instance register offset (*_INST macro)
* @rstctrl_reg: RM_RSTCTRL register address for this module
*
@@ -83,7 +90,8 @@ int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst, u16 rstctrl_offs)
* place the submodule into reset. Returns 0 upon success or -EINVAL
* upon an argument error.
*/
-int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs)
+static int am33xx_prm_assert_hardreset(u8 shift, u8 part, s16 inst,
+ u16 rstctrl_offs)
{
u32 mask = 1 << shift;
@@ -96,6 +104,8 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs)
* am33xx_prm_deassert_hardreset - deassert a submodule hardreset line and
* wait
* @shift: register bit shift corresponding to the reset line to deassert
+ * @st_shift: reset status register bit shift corresponding to the reset line
+ * @part: PRM partition, not used for AM33xx
* @inst: CM instance register offset (*_INST macro)
* @rstctrl_reg: RM_RSTCTRL register address for this module
* @rstst_reg: RM_RSTST register address for this module
@@ -109,14 +119,15 @@ int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs)
* -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly.
*/
-int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst,
- u16 rstctrl_offs, u16 rstst_offs)
+static int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
+ s16 inst, u16 rstctrl_offs,
+ u16 rstst_offs)
{
int c;
u32 mask = 1 << st_shift;
/* Check the current status to avoid de-asserting the line twice */
- if (am33xx_prm_is_hardreset_asserted(shift, inst, rstctrl_offs) == 0)
+ if (am33xx_prm_is_hardreset_asserted(shift, 0, inst, rstctrl_offs) == 0)
return -EEXIST;
/* Clear the reset status by writing 1 to the status bit */
@@ -128,7 +139,7 @@ int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst,
am33xx_prm_rmw_reg_bits(mask, 0, inst, rstctrl_offs);
/* wait the status to be set */
- omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, inst,
+ omap_test_timeout(am33xx_prm_is_hardreset_asserted(st_shift, 0, inst,
rstst_offs),
MAX_MODULE_HARDRESET_WAIT, c);
@@ -325,6 +336,23 @@ static int am33xx_check_vcvp(void)
return 0;
}
+/**
+ * am33xx_prm_global_warm_sw_reset - reboot the device via warm reset
+ *
+ * Immediately reboots the device through warm reset.
+ */
+static void am33xx_prm_global_warm_sw_reset(void)
+{
+ am33xx_prm_rmw_reg_bits(AM33XX_RST_GLOBAL_WARM_SW_MASK,
+ AM33XX_RST_GLOBAL_WARM_SW_MASK,
+ AM33XX_PRM_DEVICE_MOD,
+ AM33XX_PRM_RSTCTRL_OFFSET);
+
+ /* OCP barrier */
+ (void)am33xx_prm_read_reg(AM33XX_PRM_DEVICE_MOD,
+ AM33XX_PRM_RSTCTRL_OFFSET);
+}
+
struct pwrdm_ops am33xx_pwrdm_operations = {
.pwrdm_set_next_pwrst = am33xx_pwrdm_set_next_pwrst,
.pwrdm_read_next_pwrst = am33xx_pwrdm_read_next_pwrst,
@@ -342,3 +370,21 @@ struct pwrdm_ops am33xx_pwrdm_operations = {
.pwrdm_wait_transition = am33xx_pwrdm_wait_transition,
.pwrdm_has_voltdm = am33xx_check_vcvp,
};
+
+static struct prm_ll_data am33xx_prm_ll_data = {
+ .assert_hardreset = am33xx_prm_assert_hardreset,
+ .deassert_hardreset = am33xx_prm_deassert_hardreset,
+ .is_hardreset_asserted = am33xx_prm_is_hardreset_asserted,
+ .reset_system = am33xx_prm_global_warm_sw_reset,
+};
+
+int __init am33xx_prm_init(void)
+{
+ return prm_register(&am33xx_prm_ll_data);
+}
+
+static void __exit am33xx_prm_exit(void)
+{
+ prm_unregister(&am33xx_prm_ll_data);
+}
+__exitcall(am33xx_prm_exit);
diff --git a/arch/arm/mach-omap2/prm33xx.h b/arch/arm/mach-omap2/prm33xx.h
index 9b9918d..98ac41f 100644
--- a/arch/arm/mach-omap2/prm33xx.h
+++ b/arch/arm/mach-omap2/prm33xx.h
@@ -118,14 +118,7 @@
#define AM33XX_PM_CEFUSE_PWRSTST AM33XX_PRM_REGADDR(AM33XX_PRM_CEFUSE_MOD, 0x0004)
#ifndef __ASSEMBLER__
-extern u32 am33xx_prm_read_reg(s16 inst, u16 idx);
-extern void am33xx_prm_write_reg(u32 val, s16 inst, u16 idx);
-extern u32 am33xx_prm_rmw_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
-extern void am33xx_prm_global_warm_sw_reset(void);
-extern int am33xx_prm_is_hardreset_asserted(u8 shift, s16 inst,
- u16 rstctrl_offs);
-extern int am33xx_prm_assert_hardreset(u8 shift, s16 inst, u16 rstctrl_offs);
-extern int am33xx_prm_deassert_hardreset(u8 shift, u8 st_shift, s16 inst,
- u16 rstctrl_offs, u16 rstst_offs);
+int am33xx_prm_init(void);
+
#endif /* ASSEMBLER */
#endif
diff --git a/arch/arm/mach-omap2/prm3xxx.c b/arch/arm/mach-omap2/prm3xxx.c
index ff08da3..c5e00c6 100644
--- a/arch/arm/mach-omap2/prm3xxx.c
+++ b/arch/arm/mach-omap2/prm3xxx.c
@@ -30,6 +30,11 @@
#include "cm3xxx.h"
#include "cm-regbits-34xx.h"
+static void omap3xxx_prm_read_pending_irqs(unsigned long *events);
+static void omap3xxx_prm_ocp_barrier(void);
+static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
+static void omap3xxx_prm_restore_irqen(u32 *saved_mask);
+
static const struct omap_prcm_irq omap3_prcm_irqs[] = {
OMAP_PRCM_IRQ("wkup", 0, 0),
OMAP_PRCM_IRQ("io", 9, 1),
@@ -131,7 +136,7 @@ u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset)
* recommended way to restart the SoC, considering Errata i520. No
* return value.
*/
-void omap3xxx_prm_dpll3_reset(void)
+static void omap3xxx_prm_dpll3_reset(void)
{
omap2_prm_set_mod_reg_bits(OMAP_RST_DPLL3_MASK, OMAP3430_GR_MOD,
OMAP2_RM_RSTCTRL);
@@ -147,7 +152,7 @@ void omap3xxx_prm_dpll3_reset(void)
* MPU IRQs, and store the result into the u32 pointed to by @events.
* No return value.
*/
-void omap3xxx_prm_read_pending_irqs(unsigned long *events)
+static void omap3xxx_prm_read_pending_irqs(unsigned long *events)
{
u32 mask, st;
@@ -166,7 +171,7 @@ void omap3xxx_prm_read_pending_irqs(unsigned long *events)
* block, to avoid race conditions after acknowledging or clearing IRQ
* bits. No return value.
*/
-void omap3xxx_prm_ocp_barrier(void)
+static void omap3xxx_prm_ocp_barrier(void)
{
omap2_prm_read_mod_reg(OCP_MOD, OMAP3_PRM_REVISION_OFFSET);
}
@@ -182,7 +187,7 @@ void omap3xxx_prm_ocp_barrier(void)
* returning; otherwise, spurious interrupts might occur. No return
* value.
*/
-void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
+static void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
{
saved_mask[0] = omap2_prm_read_mod_reg(OCP_MOD,
OMAP3_PRM_IRQENABLE_MPU_OFFSET);
@@ -202,7 +207,7 @@ void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask)
* barrier should be needed here; any pending PRM interrupts will fire
* once the writes reach the PRM. No return value.
*/
-void omap3xxx_prm_restore_irqen(u32 *saved_mask)
+static void omap3xxx_prm_restore_irqen(u32 *saved_mask)
{
omap2_prm_write_mod_reg(saved_mask[0], OCP_MOD,
OMAP3_PRM_IRQENABLE_MPU_OFFSET);
@@ -375,7 +380,7 @@ void __init omap3_prm_init_pm(bool has_uart4, bool has_iva)
* The ST_IO_CHAIN bit does not exist in 3430 before es3.1. The only
* thing we can do is toggle EN_IO bit for earlier omaps.
*/
-void omap3430_pre_es3_1_reconfigure_io_chain(void)
+static void omap3430_pre_es3_1_reconfigure_io_chain(void)
{
omap2_prm_clear_mod_reg_bits(OMAP3430_EN_IO_MASK, WKUP_MOD,
PM_WKEN);
@@ -393,7 +398,7 @@ void omap3430_pre_es3_1_reconfigure_io_chain(void)
* deasserting WUCLKIN and clearing the ST_IO_CHAIN WKST bit. No
* return value. These registers are only available in 3430 es3.1 and later.
*/
-void omap3_prm_reconfigure_io_chain(void)
+static void omap3_prm_reconfigure_io_chain(void)
{
int i = 0;
@@ -416,15 +421,6 @@ void omap3_prm_reconfigure_io_chain(void)
}
/**
- * omap3xxx_prm_reconfigure_io_chain - reconfigure I/O chain
- */
-void omap3xxx_prm_reconfigure_io_chain(void)
-{
- if (omap3_prcm_irq_setup.reconfigure_io_chain)
- omap3_prcm_irq_setup.reconfigure_io_chain();
-}
-
-/**
* omap3xxx_prm_enable_io_wakeup - enable wakeup events from I/O wakeup latches
*
* Activates the I/O wakeup event latches and allows events logged by
@@ -664,6 +660,10 @@ static int omap3xxx_prm_late_init(void);
static struct prm_ll_data omap3xxx_prm_ll_data = {
.read_reset_sources = &omap3xxx_prm_read_reset_sources,
.late_init = &omap3xxx_prm_late_init,
+ .assert_hardreset = &omap2_prm_assert_hardreset,
+ .deassert_hardreset = &omap2_prm_deassert_hardreset,
+ .is_hardreset_asserted = &omap2_prm_is_hardreset_asserted,
+ .reset_system = &omap3xxx_prm_dpll3_reset,
};
int __init omap3xxx_prm_init(void)
diff --git a/arch/arm/mach-omap2/prm3xxx.h b/arch/arm/mach-omap2/prm3xxx.h
index bc37d42..cfde3f4 100644
--- a/arch/arm/mach-omap2/prm3xxx.h
+++ b/arch/arm/mach-omap2/prm3xxx.h
@@ -144,22 +144,6 @@ extern u32 omap3_prm_vcvp_read(u8 offset);
extern void omap3_prm_vcvp_write(u32 val, u8 offset);
extern u32 omap3_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
-#ifdef CONFIG_ARCH_OMAP3
-void omap3xxx_prm_reconfigure_io_chain(void);
-#else
-static inline void omap3xxx_prm_reconfigure_io_chain(void)
-{
-}
-#endif
-
-/* PRM interrupt-related functions */
-extern void omap3xxx_prm_read_pending_irqs(unsigned long *events);
-extern void omap3xxx_prm_ocp_barrier(void);
-extern void omap3xxx_prm_save_and_clear_irqen(u32 *saved_mask);
-extern void omap3xxx_prm_restore_irqen(u32 *saved_mask);
-
-extern void omap3xxx_prm_dpll3_reset(void);
-
extern int __init omap3xxx_prm_init(void);
extern u32 omap3xxx_prm_get_reset_sources(void);
int omap3xxx_prm_clear_mod_irqs(s16 module, u8 regs, u32 ignore_bits);
diff --git a/arch/arm/mach-omap2/prm44xx.c b/arch/arm/mach-omap2/prm44xx.c
index 0958d07..cc170fb 100644
--- a/arch/arm/mach-omap2/prm44xx.c
+++ b/arch/arm/mach-omap2/prm44xx.c
@@ -32,6 +32,12 @@
/* Static data */
+static void omap44xx_prm_read_pending_irqs(unsigned long *events);
+static void omap44xx_prm_ocp_barrier(void);
+static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
+static void omap44xx_prm_restore_irqen(u32 *saved_mask);
+static void omap44xx_prm_reconfigure_io_chain(void);
+
static const struct omap_prcm_irq omap4_prcm_irqs[] = {
OMAP_PRCM_IRQ("io", 9, 1),
};
@@ -80,19 +86,19 @@ static struct prm_reset_src_map omap44xx_prm_reset_src_map[] = {
/* PRM low-level functions */
/* Read a register in a CM/PRM instance in the PRM module */
-u32 omap4_prm_read_inst_reg(s16 inst, u16 reg)
+static u32 omap4_prm_read_inst_reg(s16 inst, u16 reg)
{
return readl_relaxed(prm_base + inst + reg);
}
/* Write into a register in a CM/PRM instance in the PRM module */
-void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg)
+static void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 reg)
{
writel_relaxed(val, prm_base + inst + reg);
}
/* Read-modify-write a register in a PRM module. Caller must lock */
-u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg)
+static u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 reg)
{
u32 v;
@@ -207,7 +213,7 @@ static inline u32 _read_pending_irq_reg(u16 irqen_offs, u16 irqst_offs)
* MPU IRQs, and store the result into the two u32s pointed to by @events.
* No return value.
*/
-void omap44xx_prm_read_pending_irqs(unsigned long *events)
+static void omap44xx_prm_read_pending_irqs(unsigned long *events)
{
events[0] = _read_pending_irq_reg(OMAP4_PRM_IRQENABLE_MPU_OFFSET,
OMAP4_PRM_IRQSTATUS_MPU_OFFSET);
@@ -224,7 +230,7 @@ void omap44xx_prm_read_pending_irqs(unsigned long *events)
* block, to avoid race conditions after acknowledging or clearing IRQ
* bits. No return value.
*/
-void omap44xx_prm_ocp_barrier(void)
+static void omap44xx_prm_ocp_barrier(void)
{
omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
OMAP4_REVISION_PRM_OFFSET);
@@ -241,7 +247,7 @@ void omap44xx_prm_ocp_barrier(void)
* interrupts reaches the PRM before returning; otherwise, spurious
* interrupts might occur. No return value.
*/
-void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
+static void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
{
saved_mask[0] =
omap4_prm_read_inst_reg(OMAP4430_PRM_OCP_SOCKET_INST,
@@ -270,7 +276,7 @@ void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask)
* No OCP barrier should be needed here; any pending PRM interrupts will fire
* once the writes reach the PRM. No return value.
*/
-void omap44xx_prm_restore_irqen(u32 *saved_mask)
+static void omap44xx_prm_restore_irqen(u32 *saved_mask)
{
omap4_prm_write_inst_reg(saved_mask[0], OMAP4430_PRM_OCP_SOCKET_INST,
OMAP4_PRM_IRQENABLE_MPU_OFFSET);
@@ -287,7 +293,7 @@ void omap44xx_prm_restore_irqen(u32 *saved_mask)
* deasserting WUCLKIN and waiting for WUCLKOUT to be deasserted.
* No return value. XXX Are the final two steps necessary?
*/
-void omap44xx_prm_reconfigure_io_chain(void)
+static void omap44xx_prm_reconfigure_io_chain(void)
{
int i = 0;
s32 inst = omap4_prmst_get_prm_dev_inst();
@@ -652,11 +658,10 @@ static int omap4_pwrdm_wait_transition(struct powerdomain *pwrdm)
static int omap4_check_vcvp(void)
{
- /* No VC/VP on dra7xx devices */
- if (soc_is_dra7xx())
- return 0;
+ if (prm_features & PRM_HAS_VOLTAGE)
+ return 1;
- return 1;
+ return 0;
}
struct pwrdm_ops omap4_pwrdm_operations = {
@@ -689,6 +694,10 @@ static struct prm_ll_data omap44xx_prm_ll_data = {
.was_any_context_lost_old = &omap44xx_prm_was_any_context_lost_old,
.clear_context_loss_flags_old = &omap44xx_prm_clear_context_loss_flags_old,
.late_init = &omap44xx_prm_late_init,
+ .assert_hardreset = omap4_prminst_assert_hardreset,
+ .deassert_hardreset = omap4_prminst_deassert_hardreset,
+ .is_hardreset_asserted = omap4_prminst_is_hardreset_asserted,
+ .reset_system = omap4_prminst_global_warm_sw_reset,
};
int __init omap44xx_prm_init(void)
@@ -696,6 +705,9 @@ int __init omap44xx_prm_init(void)
if (cpu_is_omap44xx() || soc_is_omap54xx() || soc_is_dra7xx())
prm_features |= PRM_HAS_IO_WAKEUP;
+ if (!soc_is_dra7xx())
+ prm_features |= PRM_HAS_VOLTAGE;
+
return prm_register(&omap44xx_prm_ll_data);
}
diff --git a/arch/arm/mach-omap2/prm44xx_54xx.h b/arch/arm/mach-omap2/prm44xx_54xx.h
index 8d95aa5..f751251 100644
--- a/arch/arm/mach-omap2/prm44xx_54xx.h
+++ b/arch/arm/mach-omap2/prm44xx_54xx.h
@@ -26,10 +26,6 @@
/* Function prototypes */
#ifndef __ASSEMBLER__
-extern u32 omap4_prm_read_inst_reg(s16 inst, u16 idx);
-extern void omap4_prm_write_inst_reg(u32 val, s16 inst, u16 idx);
-extern u32 omap4_prm_rmw_inst_reg_bits(u32 mask, u32 bits, s16 inst, s16 idx);
-
/* OMAP4/OMAP5-specific VP functions */
u32 omap4_prm_vp_check_txdone(u8 vp_id);
void omap4_prm_vp_clear_txdone(u8 vp_id);
@@ -42,21 +38,6 @@ extern u32 omap4_prm_vcvp_read(u8 offset);
extern void omap4_prm_vcvp_write(u32 val, u8 offset);
extern u32 omap4_prm_vcvp_rmw(u32 mask, u32 bits, u8 offset);
-#if defined(CONFIG_ARCH_OMAP4) || defined(CONFIG_SOC_OMAP5) || \
- defined(CONFIG_SOC_DRA7XX) || defined(CONFIG_SOC_AM43XX)
-void omap44xx_prm_reconfigure_io_chain(void);
-#else
-static inline void omap44xx_prm_reconfigure_io_chain(void)
-{
-}
-#endif
-
-/* PRM interrupt-related functions */
-extern void omap44xx_prm_read_pending_irqs(unsigned long *events);
-extern void omap44xx_prm_ocp_barrier(void);
-extern void omap44xx_prm_save_and_clear_irqen(u32 *saved_mask);
-extern void omap44xx_prm_restore_irqen(u32 *saved_mask);
-
extern int __init omap44xx_prm_init(void);
extern u32 omap44xx_prm_get_reset_sources(void);
diff --git a/arch/arm/mach-omap2/prm_common.c b/arch/arm/mach-omap2/prm_common.c
index ee2b522..779940c 100644
--- a/arch/arm/mach-omap2/prm_common.c
+++ b/arch/arm/mach-omap2/prm_common.c
@@ -423,6 +423,105 @@ void prm_clear_context_loss_flags_old(u8 part, s16 inst, u16 idx)
}
/**
+ * omap_prm_assert_hardreset - assert hardreset for an IP block
+ * @shift: register bit shift corresponding to the reset line
+ * @part: PRM partition
+ * @prm_mod: PRM submodule base or instance offset
+ * @offset: register offset
+ *
+ * Asserts a hardware reset line for an IP block.
+ */
+int omap_prm_assert_hardreset(u8 shift, u8 part, s16 prm_mod, u16 offset)
+{
+ if (!prm_ll_data->assert_hardreset) {
+ WARN_ONCE(1, "prm: %s: no mapping function defined\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return prm_ll_data->assert_hardreset(shift, part, prm_mod, offset);
+}
+
+/**
+ * omap_prm_deassert_hardreset - deassert hardreset for an IP block
+ * @shift: register bit shift corresponding to the reset line
+ * @st_shift: reset status bit shift corresponding to the reset line
+ * @part: PRM partition
+ * @prm_mod: PRM submodule base or instance offset
+ * @offset: register offset
+ * @st_offset: status register offset
+ *
+ * Deasserts a hardware reset line for an IP block.
+ */
+int omap_prm_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 prm_mod,
+ u16 offset, u16 st_offset)
+{
+ if (!prm_ll_data->deassert_hardreset) {
+ WARN_ONCE(1, "prm: %s: no mapping function defined\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return prm_ll_data->deassert_hardreset(shift, st_shift, part, prm_mod,
+ offset, st_offset);
+}
+
+/**
+ * omap_prm_is_hardreset_asserted - check the hardreset status for an IP block
+ * @shift: register bit shift corresponding to the reset line
+ * @part: PRM partition
+ * @prm_mod: PRM submodule base or instance offset
+ * @offset: register offset
+ *
+ * Checks if a hardware reset line for an IP block is enabled or not.
+ */
+int omap_prm_is_hardreset_asserted(u8 shift, u8 part, s16 prm_mod, u16 offset)
+{
+ if (!prm_ll_data->is_hardreset_asserted) {
+ WARN_ONCE(1, "prm: %s: no mapping function defined\n",
+ __func__);
+ return -EINVAL;
+ }
+
+ return prm_ll_data->is_hardreset_asserted(shift, part, prm_mod, offset);
+}
+
+/**
+ * omap_prm_reconfigure_io_chain - clear latches and reconfigure I/O chain
+ *
+ * Clear any previously-latched I/O wakeup events and ensure that the
+ * I/O wakeup gates are aligned with the current mux settings.
+ * Calls SoC specific I/O chain reconfigure function if available,
+ * otherwise does nothing.
+ */
+void omap_prm_reconfigure_io_chain(void)
+{
+ if (!prcm_irq_setup || !prcm_irq_setup->reconfigure_io_chain)
+ return;
+
+ prcm_irq_setup->reconfigure_io_chain();
+}
+
+/**
+ * omap_prm_reset_system - trigger global SW reset
+ *
+ * Triggers SoC specific global warm reset to reboot the device.
+ */
+void omap_prm_reset_system(void)
+{
+ if (!prm_ll_data->reset_system) {
+ WARN_ONCE(1, "prm: %s: no mapping function defined\n",
+ __func__);
+ return;
+ }
+
+ prm_ll_data->reset_system();
+
+ while (1)
+ cpu_relax();
+}
+
+/**
* prm_register - register per-SoC low-level data with the PRM
* @pld: low-level per-SoC OMAP PRM data & function pointers to register
*
diff --git a/arch/arm/mach-omap2/prminst44xx.c b/arch/arm/mach-omap2/prminst44xx.c
index 225e025..8adf7b1 100644
--- a/arch/arm/mach-omap2/prminst44xx.c
+++ b/arch/arm/mach-omap2/prminst44xx.c
@@ -148,8 +148,12 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
/**
* omap4_prminst_deassert_hardreset - deassert a submodule hardreset line and
* wait
- * @rstctrl_reg: RM_RSTCTRL register address for this module
* @shift: register bit shift corresponding to the reset line to deassert
+ * @st_shift: status bit offset, not used for OMAP4+
+ * @part: PRM partition
+ * @inst: PRM instance offset
+ * @rstctrl_offs: reset register offset
+ * @st_offs: reset status register offset, not used for OMAP4+
*
* Some IPs like dsp, ipu or iva contain processors that require an HW
* reset line to be asserted / deasserted in order to fully enable the
@@ -160,8 +164,8 @@ int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
* -EINVAL upon an argument error, -EEXIST if the submodule was already out
* of reset, or -EBUSY if the submodule did not exit reset promptly.
*/
-int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst,
- u16 rstctrl_offs)
+int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part, s16 inst,
+ u16 rstctrl_offs, u16 st_offs)
{
int c;
u32 mask = 1 << shift;
diff --git a/arch/arm/mach-omap2/prminst44xx.h b/arch/arm/mach-omap2/prminst44xx.h
index 583aa37..fb1c9d7 100644
--- a/arch/arm/mach-omap2/prminst44xx.h
+++ b/arch/arm/mach-omap2/prminst44xx.h
@@ -30,8 +30,9 @@ extern int omap4_prminst_is_hardreset_asserted(u8 shift, u8 part, s16 inst,
u16 rstctrl_offs);
extern int omap4_prminst_assert_hardreset(u8 shift, u8 part, s16 inst,
u16 rstctrl_offs);
-extern int omap4_prminst_deassert_hardreset(u8 shift, u8 part, s16 inst,
- u16 rstctrl_offs);
+int omap4_prminst_deassert_hardreset(u8 shift, u8 st_shift, u8 part,
+ s16 inst, u16 rstctrl_offs,
+ u16 rstst_offs);
extern void omap_prm_base_init(void);
diff --git a/arch/arm/mach-omap2/serial.c b/arch/arm/mach-omap2/serial.c
index a388f8c..57dee0c 100644
--- a/arch/arm/mach-omap2/serial.c
+++ b/arch/arm/mach-omap2/serial.c
@@ -263,9 +263,6 @@ void __init omap_serial_init_port(struct omap_board_data *bdata,
omap_up.dma_rx_timeout = info->dma_rx_timeout;
omap_up.dma_rx_poll_rate = info->dma_rx_poll_rate;
omap_up.autosuspend_timeout = info->autosuspend_timeout;
- omap_up.DTR_gpio = info->DTR_gpio;
- omap_up.DTR_inverted = info->DTR_inverted;
- omap_up.DTR_present = info->DTR_present;
pdata = &omap_up;
pdata_size = sizeof(struct omap_uart_port_info);
diff --git a/arch/arm/mach-pxa/Kconfig b/arch/arm/mach-pxa/Kconfig
index e6690a4..83efe91 100644
--- a/arch/arm/mach-pxa/Kconfig
+++ b/arch/arm/mach-pxa/Kconfig
@@ -4,6 +4,17 @@ menu "Intel PXA2xx/PXA3xx Implementations"
comment "Intel/Marvell Dev Platforms (sorted by hardware release time)"
+config MACH_PXA27X_DT
+ bool "Support PXA27x platforms from device tree"
+ select CPU_PXA27x
+ select POWER_SUPPLY
+ select PXA27x
+ select USE_OF
+ help
+ Include support for Marvell PXA27x based platforms using
+ the device tree. Needn't select any other machine while
+ MACH_PXA27X_DT is enabled.
+
config MACH_PXA3XX_DT
bool "Support PXA3xx platforms from device tree"
select CPU_PXA300
diff --git a/arch/arm/mach-pxa/Makefile b/arch/arm/mach-pxa/Makefile
index 2fe1824..eb0bf76 100644
--- a/arch/arm/mach-pxa/Makefile
+++ b/arch/arm/mach-pxa/Makefile
@@ -21,6 +21,7 @@ obj-$(CONFIG_CPU_PXA930) += pxa930.o
# Device Tree support
obj-$(CONFIG_MACH_PXA3XX_DT) += pxa-dt.o
+obj-$(CONFIG_MACH_PXA27X_DT) += pxa-dt.o
# Intel/Marvell Dev Platforms
obj-$(CONFIG_ARCH_LUBBOCK) += lubbock.o
diff --git a/arch/arm/mach-pxa/em-x270.c b/arch/arm/mach-pxa/em-x270.c
index 6915a9f..51531ec 100644
--- a/arch/arm/mach-pxa/em-x270.c
+++ b/arch/arm/mach-pxa/em-x270.c
@@ -378,7 +378,7 @@ static void __init em_x270_init_nand(void)
err = gpio_request(GPIO11_NAND_CS, "NAND CS");
if (err) {
- pr_warning("EM-X270: failed to request NAND CS gpio\n");
+ pr_warn("EM-X270: failed to request NAND CS gpio\n");
return;
}
@@ -386,7 +386,7 @@ static void __init em_x270_init_nand(void)
err = gpio_request(nand_rb, "NAND R/B");
if (err) {
- pr_warning("EM-X270: failed to request NAND R/B gpio\n");
+ pr_warn("EM-X270: failed to request NAND R/B gpio\n");
gpio_free(GPIO11_NAND_CS);
return;
}
diff --git a/arch/arm/mach-pxa/generic.h b/arch/arm/mach-pxa/generic.h
index 8963984..7a9fa1a 100644
--- a/arch/arm/mach-pxa/generic.h
+++ b/arch/arm/mach-pxa/generic.h
@@ -13,11 +13,11 @@
struct irq_data;
-extern void pxa_timer_init(void);
-
-extern void __init pxa_map_io(void);
-
extern unsigned int get_clk_frequency_khz(int info);
+extern void __init pxa_dt_irq_init(int (*fn)(struct irq_data *,
+ unsigned int));
+extern void __init pxa_map_io(void);
+extern void pxa_timer_init(void);
#define SET_BANK(__nr,__start,__size) \
mi->bank[__nr].start = (__start), \
@@ -25,6 +25,43 @@ extern unsigned int get_clk_frequency_khz(int info);
#define ARRAY_AND_SIZE(x) (x), ARRAY_SIZE(x)
+#define pxa25x_handle_irq icip_handle_irq
+extern void __init pxa25x_init_irq(void);
+extern void __init pxa25x_map_io(void);
+extern void __init pxa26x_init_irq(void);
+
+#define pxa27x_handle_irq ichp_handle_irq
+extern void __init pxa27x_dt_init_irq(void);
+extern unsigned pxa27x_get_clk_frequency_khz(int);
+extern void __init pxa27x_init_irq(void);
+extern void __init pxa27x_map_io(void);
+
+#define pxa3xx_handle_irq ichp_handle_irq
+extern void __init pxa3xx_dt_init_irq(void);
+extern void __init pxa3xx_init_irq(void);
+extern void __init pxa3xx_map_io(void);
+
+extern struct syscore_ops pxa_irq_syscore_ops;
+extern struct syscore_ops pxa2xx_mfp_syscore_ops;
+extern struct syscore_ops pxa3xx_mfp_syscore_ops;
+
+void __init pxa_set_ffuart_info(void *info);
+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(enum reboot_mode, const char *);
+
+#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
+extern void pxa2xx_clear_reset_status(unsigned int);
+#else
+static inline void pxa2xx_clear_reset_status(unsigned int mask) {}
+#endif
+
+/*
+ * Once fully converted to the clock framework, all these functions should be
+ * removed, and replaced with a clk_get(NULL, "core").
+ */
#ifdef CONFIG_PXA25x
extern unsigned pxa25x_get_clk_frequency_khz(int);
#else
@@ -32,30 +69,12 @@ extern unsigned pxa25x_get_clk_frequency_khz(int);
#endif
#ifdef CONFIG_PXA27x
-extern unsigned pxa27x_get_clk_frequency_khz(int);
#else
#define pxa27x_get_clk_frequency_khz(x) (0)
#endif
-#if defined(CONFIG_PXA25x) || defined(CONFIG_PXA27x)
-extern void pxa2xx_clear_reset_status(unsigned int);
-#else
-static inline void pxa2xx_clear_reset_status(unsigned int mask) {}
-#endif
-
#ifdef CONFIG_PXA3xx
-extern unsigned pxa3xx_get_clk_frequency_khz(int);
+extern unsigned pxa3xx_get_clk_frequency_khz(int);
#else
#define pxa3xx_get_clk_frequency_khz(x) (0)
#endif
-
-extern struct syscore_ops pxa_irq_syscore_ops;
-extern struct syscore_ops pxa2xx_mfp_syscore_ops;
-extern struct syscore_ops pxa3xx_mfp_syscore_ops;
-
-void __init pxa_set_ffuart_info(void *info);
-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(enum reboot_mode, const char *);
diff --git a/arch/arm/mach-pxa/gumstix.c b/arch/arm/mach-pxa/gumstix.c
index 00b92da..f6c76a3 100644
--- a/arch/arm/mach-pxa/gumstix.c
+++ b/arch/arm/mach-pxa/gumstix.c
@@ -140,8 +140,7 @@ static void gumstix_setup_bt_clock(void)
int timeout = 500;
if (!(OSCC & OSCC_OOK))
- pr_warning("32kHz clock was not on. Bootloader may need to "
- "be updated\n");
+ pr_warn("32kHz clock was not on. Bootloader may need to be updated\n");
else
return;
diff --git a/arch/arm/mach-pxa/include/mach/pxa25x.h b/arch/arm/mach-pxa/include/mach/pxa25x.h
index 3ac0baa..5a34175 100644
--- a/arch/arm/mach-pxa/include/mach/pxa25x.h
+++ b/arch/arm/mach-pxa/include/mach/pxa25x.h
@@ -6,12 +6,4 @@
#include <mach/mfp-pxa25x.h>
#include <mach/irqs.h>
-extern void __init pxa25x_map_io(void);
-extern void __init pxa25x_init_irq(void);
-#ifdef CONFIG_CPU_PXA26x
-extern void __init pxa26x_init_irq(void);
-#endif
-
-#define pxa25x_handle_irq icip_handle_irq
-
#endif /* __MACH_PXA25x_H */
diff --git a/arch/arm/mach-pxa/include/mach/pxa27x.h b/arch/arm/mach-pxa/include/mach/pxa27x.h
index 7cff640..599b925 100644
--- a/arch/arm/mach-pxa/include/mach/pxa27x.h
+++ b/arch/arm/mach-pxa/include/mach/pxa27x.h
@@ -19,11 +19,7 @@
#define ARB_CORE_PARK (1<<24) /* Be parked with core when idle */
#define ARB_LOCK_FLAG (1<<23) /* Only Locking masters gain access to the bus */
-extern void __init pxa27x_map_io(void);
-extern void __init pxa27x_init_irq(void);
extern int __init pxa27x_set_pwrmode(unsigned int mode);
extern void pxa27x_cpu_pm_enter(suspend_state_t state);
-#define pxa27x_handle_irq ichp_handle_irq
-
#endif /* __MACH_PXA27x_H */
diff --git a/arch/arm/mach-pxa/include/mach/pxa3xx.h b/arch/arm/mach-pxa/include/mach/pxa3xx.h
index 6dd7fa1..b4143fb 100644
--- a/arch/arm/mach-pxa/include/mach/pxa3xx.h
+++ b/arch/arm/mach-pxa/include/mach/pxa3xx.h
@@ -5,9 +5,4 @@
#include <mach/pxa3xx-regs.h>
#include <mach/irqs.h>
-extern void __init pxa3xx_map_io(void);
-extern void __init pxa3xx_init_irq(void);
-
-#define pxa3xx_handle_irq ichp_handle_irq
-
#endif /* __MACH_PXA3XX_H */
diff --git a/arch/arm/mach-pxa/mfp-pxa2xx.c b/arch/arm/mach-pxa/mfp-pxa2xx.c
index ef0426a..666b789 100644
--- a/arch/arm/mach-pxa/mfp-pxa2xx.c
+++ b/arch/arm/mach-pxa/mfp-pxa2xx.c
@@ -93,8 +93,8 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
break;
default:
/* warning and fall through, treat as MFP_LPM_DEFAULT */
- pr_warning("%s: GPIO%d: unsupported low power mode\n",
- __func__, gpio);
+ pr_warn("%s: GPIO%d: unsupported low power mode\n",
+ __func__, gpio);
break;
}
@@ -107,14 +107,12 @@ static int __mfp_config_gpio(unsigned gpio, unsigned long c)
* configurations of those pins not able to wakeup
*/
if ((c & MFP_LPM_CAN_WAKEUP) && !gpio_desc[gpio].can_wakeup) {
- pr_warning("%s: GPIO%d unable to wakeup\n",
- __func__, gpio);
+ pr_warn("%s: GPIO%d unable to wakeup\n", __func__, gpio);
return -EINVAL;
}
if ((c & MFP_LPM_CAN_WAKEUP) && is_out) {
- pr_warning("%s: output GPIO%d unable to wakeup\n",
- __func__, gpio);
+ pr_warn("%s: output GPIO%d unable to wakeup\n", __func__, gpio);
return -EINVAL;
}
@@ -126,7 +124,7 @@ static inline int __mfp_validate(int mfp)
int gpio = mfp_to_gpio(mfp);
if ((mfp > MFP_PIN_GPIO127) || !gpio_desc[gpio].valid) {
- pr_warning("%s: GPIO%d is invalid pin\n", __func__, gpio);
+ pr_warn("%s: GPIO%d is invalid pin\n", __func__, gpio);
return -1;
}
diff --git a/arch/arm/mach-pxa/poodle.c b/arch/arm/mach-pxa/poodle.c
index 1319916..29019be 100644
--- a/arch/arm/mach-pxa/poodle.c
+++ b/arch/arm/mach-pxa/poodle.c
@@ -446,7 +446,7 @@ static void __init poodle_init(void)
ret = platform_add_devices(devices, ARRAY_SIZE(devices));
if (ret)
- pr_warning("poodle: Unable to register LoCoMo device\n");
+ pr_warn("poodle: Unable to register LoCoMo device\n");
pxa_set_fb_info(&poodle_locomo_device.dev, &poodle_fb_info);
pxa_set_udc_info(&udc_info);
diff --git a/arch/arm/mach-pxa/pxa-dt.c b/arch/arm/mach-pxa/pxa-dt.c
index f6a2c4b..7e0e5bd 100644
--- a/arch/arm/mach-pxa/pxa-dt.c
+++ b/arch/arm/mach-pxa/pxa-dt.c
@@ -15,13 +15,10 @@
#include <asm/mach/arch.h>
#include <asm/mach/time.h>
#include <mach/irqs.h>
-#include <mach/pxa3xx.h>
#include "generic.h"
#ifdef CONFIG_PXA3xx
-extern void __init pxa3xx_dt_init_irq(void);
-
static const struct of_dev_auxdata pxa3xx_auxdata_lookup[] __initconst = {
OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40100000, "pxa2xx-uart.0", NULL),
OF_DEV_AUXDATA("mrvl,pxa-uart", 0x40200000, "pxa2xx-uart.1", NULL),
@@ -61,3 +58,18 @@ DT_MACHINE_START(PXA_DT, "Marvell PXA3xx (Device Tree Support)")
.dt_compat = pxa3xx_dt_board_compat,
MACHINE_END
#endif
+
+#ifdef CONFIG_PXA27x
+static const char * const pxa27x_dt_board_compat[] __initconst = {
+ "marvell,pxa270",
+ NULL,
+};
+
+DT_MACHINE_START(PXA27X_DT, "Marvell PXA2xx (Device Tree Support)")
+ .map_io = pxa27x_map_io,
+ .init_irq = pxa27x_dt_init_irq,
+ .handle_irq = pxa27x_handle_irq,
+ .restart = pxa_restart,
+ .dt_compat = pxa27x_dt_board_compat,
+MACHINE_END
+#endif
diff --git a/arch/arm/mach-pxa/pxa27x.c b/arch/arm/mach-pxa/pxa27x.c
index b040d7d..af423a4 100644
--- a/arch/arm/mach-pxa/pxa27x.c
+++ b/arch/arm/mach-pxa/pxa27x.c
@@ -398,6 +398,12 @@ void __init pxa27x_init_irq(void)
pxa_init_irq(34, pxa27x_set_wake);
}
+void __init pxa27x_dt_init_irq(void)
+{
+ if (IS_ENABLED(CONFIG_OF))
+ pxa_dt_irq_init(pxa27x_set_wake);
+}
+
static struct map_desc pxa27x_io_desc[] __initdata = {
{ /* Mem Ctl */
.virtual = (unsigned long)SMEMC_VIRT,
diff --git a/arch/arm/mach-pxa/pxa3xx-ulpi.c b/arch/arm/mach-pxa/pxa3xx-ulpi.c
index e329cce..614003e 100644
--- a/arch/arm/mach-pxa/pxa3xx-ulpi.c
+++ b/arch/arm/mach-pxa/pxa3xx-ulpi.c
@@ -74,7 +74,7 @@ static int pxa310_ulpi_poll(void)
cpu_relax();
}
- pr_warning("%s: ULPI access timed out!\n", __func__);
+ pr_warn("%s: ULPI access timed out!\n", __func__);
return -ETIMEDOUT;
}
@@ -84,7 +84,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
int err;
if (pxa310_ulpi_get_phymode() != SYNCH) {
- pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+ pr_warn("%s: PHY is not in SYNCH mode!\n", __func__);
return -EBUSY;
}
@@ -101,7 +101,7 @@ static int pxa310_ulpi_read(struct usb_phy *otg, u32 reg)
static int pxa310_ulpi_write(struct usb_phy *otg, u32 val, u32 reg)
{
if (pxa310_ulpi_get_phymode() != SYNCH) {
- pr_warning("%s: PHY is not in SYNCH mode!\n", __func__);
+ pr_warn("%s: PHY is not in SYNCH mode!\n", __func__);
return -EBUSY;
}
diff --git a/arch/arm/mach-pxa/raumfeld.c b/arch/arm/mach-pxa/raumfeld.c
index 8386dc3..a762b23 100644
--- a/arch/arm/mach-pxa/raumfeld.c
+++ b/arch/arm/mach-pxa/raumfeld.c
@@ -521,7 +521,7 @@ static void __init raumfeld_w1_init(void)
"W1 external pullup enable");
if (ret < 0)
- pr_warning("Unable to request GPIO_W1_PULLUP_ENABLE\n");
+ pr_warn("Unable to request GPIO_W1_PULLUP_ENABLE\n");
else
gpio_direction_output(GPIO_W1_PULLUP_ENABLE, 0);
@@ -600,7 +600,7 @@ static void __init raumfeld_lcd_init(void)
ret = gpio_request(GPIO_TFT_VA_EN, "display VA enable");
if (ret < 0)
- pr_warning("Unable to request GPIO_TFT_VA_EN\n");
+ pr_warn("Unable to request GPIO_TFT_VA_EN\n");
else
gpio_direction_output(GPIO_TFT_VA_EN, 1);
@@ -608,7 +608,7 @@ static void __init raumfeld_lcd_init(void)
ret = gpio_request(GPIO_DISPLAY_ENABLE, "display enable");
if (ret < 0)
- pr_warning("Unable to request GPIO_DISPLAY_ENABLE\n");
+ pr_warn("Unable to request GPIO_DISPLAY_ENABLE\n");
else
gpio_direction_output(GPIO_DISPLAY_ENABLE, 1);
@@ -814,17 +814,17 @@ static void __init raumfeld_power_init(void)
/* Set PEN2 high to enable maximum charge current */
ret = gpio_request(GPIO_CHRG_PEN2, "CHRG_PEN2");
if (ret < 0)
- pr_warning("Unable to request GPIO_CHRG_PEN2\n");
+ pr_warn("Unable to request GPIO_CHRG_PEN2\n");
else
gpio_direction_output(GPIO_CHRG_PEN2, 1);
ret = gpio_request(GPIO_CHARGE_DC_OK, "CABLE_DC_OK");
if (ret < 0)
- pr_warning("Unable to request GPIO_CHARGE_DC_OK\n");
+ pr_warn("Unable to request GPIO_CHARGE_DC_OK\n");
ret = gpio_request(GPIO_CHARGE_USB_SUSP, "CHARGE_USB_SUSP");
if (ret < 0)
- pr_warning("Unable to request GPIO_CHARGE_USB_SUSP\n");
+ pr_warn("Unable to request GPIO_CHARGE_USB_SUSP\n");
else
gpio_direction_output(GPIO_CHARGE_USB_SUSP, 0);
@@ -976,19 +976,19 @@ static void __init raumfeld_audio_init(void)
ret = gpio_request(GPIO_CODEC_RESET, "cs4270 reset");
if (ret < 0)
- pr_warning("unable to request GPIO_CODEC_RESET\n");
+ pr_warn("unable to request GPIO_CODEC_RESET\n");
else
gpio_direction_output(GPIO_CODEC_RESET, 1);
ret = gpio_request(GPIO_SPDIF_RESET, "ak4104 s/pdif reset");
if (ret < 0)
- pr_warning("unable to request GPIO_SPDIF_RESET\n");
+ pr_warn("unable to request GPIO_SPDIF_RESET\n");
else
gpio_direction_output(GPIO_SPDIF_RESET, 1);
ret = gpio_request(GPIO_MCLK_RESET, "MCLK reset");
if (ret < 0)
- pr_warning("unable to request GPIO_MCLK_RESET\n");
+ pr_warn("unable to request GPIO_MCLK_RESET\n");
else
gpio_direction_output(GPIO_MCLK_RESET, 1);
@@ -1019,20 +1019,20 @@ static void __init raumfeld_common_init(void)
ret = gpio_request(GPIO_W2W_RESET, "Wi2Wi reset");
if (ret < 0)
- pr_warning("Unable to request GPIO_W2W_RESET\n");
+ pr_warn("Unable to request GPIO_W2W_RESET\n");
else
gpio_direction_output(GPIO_W2W_RESET, 0);
ret = gpio_request(GPIO_W2W_PDN, "Wi2Wi powerup");
if (ret < 0)
- pr_warning("Unable to request GPIO_W2W_PDN\n");
+ pr_warn("Unable to request GPIO_W2W_PDN\n");
else
gpio_direction_output(GPIO_W2W_PDN, 0);
/* this can be used to switch off the device */
ret = gpio_request(GPIO_SHUTDOWN_SUPPLY, "supply shutdown");
if (ret < 0)
- pr_warning("Unable to request GPIO_SHUTDOWN_SUPPLY\n");
+ pr_warn("Unable to request GPIO_SHUTDOWN_SUPPLY\n");
else
gpio_direction_output(GPIO_SHUTDOWN_SUPPLY, 0);
@@ -1051,7 +1051,7 @@ static void __init raumfeld_controller_init(void)
ret = gpio_request(GPIO_SHUTDOWN_BATT, "battery shutdown");
if (ret < 0)
- pr_warning("Unable to request GPIO_SHUTDOWN_BATT\n");
+ pr_warn("Unable to request GPIO_SHUTDOWN_BATT\n");
else
gpio_direction_output(GPIO_SHUTDOWN_BATT, 0);
diff --git a/arch/arm/mach-pxa/spitz.c b/arch/arm/mach-pxa/spitz.c
index 840c3a4..962a7f3 100644
--- a/arch/arm/mach-pxa/spitz.c
+++ b/arch/arm/mach-pxa/spitz.c
@@ -924,6 +924,14 @@ static inline void spitz_i2c_init(void) {}
#endif
/******************************************************************************
+ * Audio devices
+ ******************************************************************************/
+static inline void spitz_audio_init(void)
+{
+ platform_device_register_simple("spitz-audio", -1, NULL, 0);
+}
+
+/******************************************************************************
* Machine init
******************************************************************************/
static void spitz_poweroff(void)
@@ -970,6 +978,7 @@ static void __init spitz_init(void)
spitz_nor_init();
spitz_nand_init();
spitz_i2c_init();
+ spitz_audio_init();
}
static void __init spitz_fixup(struct tag *tags, char **cmdline)
diff --git a/arch/arm/mach-pxa/tosa.c b/arch/arm/mach-pxa/tosa.c
index c158a6e..7780d1fa 100644
--- a/arch/arm/mach-pxa/tosa.c
+++ b/arch/arm/mach-pxa/tosa.c
@@ -30,7 +30,7 @@
#include <linux/gpio_keys.h>
#include <linux/input.h>
#include <linux/gpio.h>
-#include <linux/pda_power.h>
+#include <linux/power/gpio-charger.h>
#include <linux/spi/spi.h>
#include <linux/spi/pxa2xx_spi.h>
#include <linux/input/matrix_keypad.h>
@@ -361,44 +361,17 @@ static struct pxaficp_platform_data tosa_ficp_platform_data = {
/*
* Tosa AC IN
*/
-static int tosa_power_init(struct device *dev)
-{
- int ret = gpio_request(TOSA_GPIO_AC_IN, "ac in");
- if (ret)
- goto err_gpio_req;
-
- ret = gpio_direction_input(TOSA_GPIO_AC_IN);
- if (ret)
- goto err_gpio_in;
-
- return 0;
-
-err_gpio_in:
- gpio_free(TOSA_GPIO_AC_IN);
-err_gpio_req:
- return ret;
-}
-
-static void tosa_power_exit(struct device *dev)
-{
- gpio_free(TOSA_GPIO_AC_IN);
-}
-
-static int tosa_power_ac_online(void)
-{
- return gpio_get_value(TOSA_GPIO_AC_IN) == 0;
-}
-
static char *tosa_ac_supplied_to[] = {
"main-battery",
"backup-battery",
"jacket-battery",
};
-static struct pda_power_pdata tosa_power_data = {
- .init = tosa_power_init,
- .is_ac_online = tosa_power_ac_online,
- .exit = tosa_power_exit,
+static struct gpio_charger_platform_data tosa_power_data = {
+ .name = "charger",
+ .type = POWER_SUPPLY_TYPE_MAINS,
+ .gpio = TOSA_GPIO_AC_IN,
+ .gpio_active_low = 1,
.supplied_to = tosa_ac_supplied_to,
.num_supplicants = ARRAY_SIZE(tosa_ac_supplied_to),
};
@@ -415,7 +388,7 @@ static struct resource tosa_power_resource[] = {
};
static struct platform_device tosa_power_device = {
- .name = "pda-power",
+ .name = "gpio-charger",
.id = -1,
.dev.platform_data = &tosa_power_data,
.resource = tosa_power_resource,
diff --git a/arch/arm/mach-realview/Kconfig b/arch/arm/mach-realview/Kconfig
index 9db2029..565925f 100644
--- a/arch/arm/mach-realview/Kconfig
+++ b/arch/arm/mach-realview/Kconfig
@@ -1,6 +1,19 @@
menu "RealView platform type"
depends on ARCH_REALVIEW
+config REALVIEW_DT
+ bool "Support RealView(R) Device Tree based boot"
+ select ARM_GIC
+ select MFD_SYSCON
+ select POWER_RESET
+ select POWER_RESET_VERSATILE
+ select POWER_SUPPLY
+ select SOC_REALVIEW
+ select USE_OF
+ help
+ Include support for booting the ARM(R) RealView(R) evaluation
+ boards using a device tree machine description.
+
config MACH_REALVIEW_EB
bool "Support RealView(R) Emulation Baseboard"
select ARM_GIC
diff --git a/arch/arm/mach-realview/Makefile b/arch/arm/mach-realview/Makefile
index 541fa4c..e07fdf7 100644
--- a/arch/arm/mach-realview/Makefile
+++ b/arch/arm/mach-realview/Makefile
@@ -3,6 +3,7 @@
#
obj-y := core.o
+obj-$(CONFIG_REALVIEW_DT) += realview-dt.o
obj-$(CONFIG_MACH_REALVIEW_EB) += realview_eb.o
obj-$(CONFIG_MACH_REALVIEW_PB11MP) += realview_pb11mp.o
obj-$(CONFIG_MACH_REALVIEW_PB1176) += realview_pb1176.o
diff --git a/arch/arm/mach-realview/realview-dt.c b/arch/arm/mach-realview/realview-dt.c
new file mode 100644
index 0000000..cc28b89
--- /dev/null
+++ b/arch/arm/mach-realview/realview-dt.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/of_platform.h>
+#include <asm/mach/arch.h>
+#include <asm/hardware/cache-l2x0.h>
+#include "core.h"
+
+static const char *realview_dt_platform_compat[] __initconst = {
+ "arm,realview-eb",
+ "arm,realview-pb1176",
+ "arm,realview-pb11mp",
+ "arm,realview-pba8",
+ "arm,realview-pbx",
+ NULL,
+};
+
+DT_MACHINE_START(REALVIEW_DT, "ARM RealView Machine (Device Tree Support)")
+#ifdef CONFIG_ZONE_DMA
+ .dma_zone_size = SZ_256M,
+#endif
+ .dt_compat = realview_dt_platform_compat,
+ .l2c_aux_val = 0x0,
+ .l2c_aux_mask = ~0x0,
+MACHINE_END
diff --git a/arch/arm/mach-rockchip/headsmp.S b/arch/arm/mach-rockchip/headsmp.S
index 73206e3..46c22de 100644
--- a/arch/arm/mach-rockchip/headsmp.S
+++ b/arch/arm/mach-rockchip/headsmp.S
@@ -16,7 +16,10 @@
#include <linux/init.h>
ENTRY(rockchip_secondary_startup)
- bl v7_invalidate_l1
+ mrc p15, 0, r0, c0, c0, 0 @ read main ID register
+ ldr r1, =0x00000c09 @ Cortex-A9 primary part number
+ teq r0, r1
+ beq v7_invalidate_l1
b secondary_startup
ENDPROC(rockchip_secondary_startup)
diff --git a/arch/arm/mach-rockchip/platsmp.c b/arch/arm/mach-rockchip/platsmp.c
index 189684f..f26fcdc 100644
--- a/arch/arm/mach-rockchip/platsmp.c
+++ b/arch/arm/mach-rockchip/platsmp.c
@@ -19,7 +19,11 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/regmap.h>
+#include <linux/mfd/syscon.h>
+#include <linux/reset.h>
+#include <linux/cpu.h>
#include <asm/cacheflush.h>
#include <asm/cp15.h>
#include <asm/smp_scu.h>
@@ -37,23 +41,78 @@ static int ncores;
#define PMU_PWRDN_SCU 4
-static void __iomem *pmu_base_addr;
+static struct regmap *pmu;
-static inline bool pmu_power_domain_is_on(int pd)
+static int pmu_power_domain_is_on(int pd)
{
- return !(readl_relaxed(pmu_base_addr + PMU_PWRDN_ST) & BIT(pd));
+ u32 val;
+ int ret;
+
+ ret = regmap_read(pmu, PMU_PWRDN_ST, &val);
+ if (ret < 0)
+ return ret;
+
+ return !(val & BIT(pd));
}
-static void pmu_set_power_domain(int pd, bool on)
+struct reset_control *rockchip_get_core_reset(int cpu)
{
- u32 val = readl_relaxed(pmu_base_addr + PMU_PWRDN_CON);
- if (on)
- val &= ~BIT(pd);
+ struct device *dev = get_cpu_device(cpu);
+ struct device_node *np;
+
+ /* The cpu device is only available after the initial core bringup */
+ if (dev)
+ np = dev->of_node;
else
- val |= BIT(pd);
- writel(val, pmu_base_addr + PMU_PWRDN_CON);
+ np = of_get_cpu_node(cpu, 0);
- while (pmu_power_domain_is_on(pd) != on) { }
+ return of_reset_control_get(np, NULL);
+}
+
+static int pmu_set_power_domain(int pd, bool on)
+{
+ u32 val = (on) ? 0 : BIT(pd);
+ int ret;
+
+ /*
+ * We need to soft reset the cpu when we turn off the cpu power domain,
+ * or else the active processors might be stalled when the individual
+ * processor is powered down.
+ */
+ if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
+ struct reset_control *rstc = rockchip_get_core_reset(pd);
+
+ if (IS_ERR(rstc)) {
+ pr_err("%s: could not get reset control for core %d\n",
+ __func__, pd);
+ return PTR_ERR(rstc);
+ }
+
+ if (on)
+ reset_control_deassert(rstc);
+ else
+ reset_control_assert(rstc);
+
+ reset_control_put(rstc);
+ }
+
+ ret = regmap_update_bits(pmu, PMU_PWRDN_CON, BIT(pd), val);
+ if (ret < 0) {
+ pr_err("%s: could not update power domain\n", __func__);
+ return ret;
+ }
+
+ ret = -1;
+ while (ret != on) {
+ ret = pmu_power_domain_is_on(pd);
+ if (ret < 0) {
+ pr_err("%s: could not read power domain state\n",
+ __func__);
+ return ret;
+ }
+ }
+
+ return 0;
}
/*
@@ -63,7 +122,9 @@ static void pmu_set_power_domain(int pd, bool on)
static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
struct task_struct *idle)
{
- if (!sram_base_addr || !pmu_base_addr) {
+ int ret;
+
+ if (!sram_base_addr || !pmu) {
pr_err("%s: sram or pmu missing for cpu boot\n", __func__);
return -ENXIO;
}
@@ -75,7 +136,24 @@ static int __cpuinit rockchip_boot_secondary(unsigned int cpu,
}
/* start the core */
- pmu_set_power_domain(0 + cpu, true);
+ ret = pmu_set_power_domain(0 + cpu, true);
+ if (ret < 0)
+ return ret;
+
+ if (read_cpuid_part() != ARM_CPU_PART_CORTEX_A9) {
+ /* We communicate with the bootrom to active the cpus other
+ * than cpu0, after a blob of initialize code, they will
+ * stay at wfe state, once they are actived, they will check
+ * the mailbox:
+ * sram_base_addr + 4: 0xdeadbeaf
+ * sram_base_addr + 8: start address for pc
+ * */
+ udelay(10);
+ writel(virt_to_phys(rockchip_secondary_startup),
+ sram_base_addr + 8);
+ writel(0xDEADBEAF, sram_base_addr + 4);
+ dsb_sev();
+ }
return 0;
}
@@ -110,8 +188,6 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
return -EINVAL;
}
- sram_base_addr = of_iomap(node, 0);
-
/* set the boot function for the sram code */
rockchip_boot_fn = virt_to_phys(rockchip_secondary_startup);
@@ -125,54 +201,115 @@ static int __init rockchip_smp_prepare_sram(struct device_node *node)
return 0;
}
-static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
+static struct regmap_config rockchip_pmu_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
+static int __init rockchip_smp_prepare_pmu(void)
{
struct device_node *node;
- unsigned int i;
+ void __iomem *pmu_base;
- node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+ /*
+ * This function is only called via smp_ops->smp_prepare_cpu().
+ * That only happens if a "/cpus" device tree node exists
+ * and has an "enable-method" property that selects the SMP
+ * operations defined herein.
+ */
+ node = of_find_node_by_path("/cpus");
+
+ pmu = syscon_regmap_lookup_by_phandle(node, "rockchip,pmu");
+ of_node_put(node);
+ if (!IS_ERR(pmu))
+ return 0;
+
+ pmu = syscon_regmap_lookup_by_compatible("rockchip,rk3066-pmu");
+ if (!IS_ERR(pmu))
+ return 0;
+
+ /* fallback, create our own regmap for the pmu area */
+ pmu = NULL;
+ node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu");
if (!node) {
- pr_err("%s: missing scu\n", __func__);
- return;
+ pr_err("%s: could not find pmu dt node\n", __func__);
+ return -ENODEV;
}
- scu_base_addr = of_iomap(node, 0);
- if (!scu_base_addr) {
- pr_err("%s: could not map scu registers\n", __func__);
- return;
+ pmu_base = of_iomap(node, 0);
+ if (!pmu_base) {
+ pr_err("%s: could not map pmu registers\n", __func__);
+ return -ENOMEM;
}
- node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram");
- if (!node) {
- pr_err("%s: could not find sram dt node\n", __func__);
- return;
+ pmu = regmap_init_mmio(NULL, pmu_base, &rockchip_pmu_regmap_config);
+ if (IS_ERR(pmu)) {
+ int ret = PTR_ERR(pmu);
+
+ iounmap(pmu_base);
+ pmu = NULL;
+ pr_err("%s: regmap init failed\n", __func__);
+ return ret;
}
- if (rockchip_smp_prepare_sram(node))
- return;
+ return 0;
+}
- node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-pmu");
+static void __init rockchip_smp_prepare_cpus(unsigned int max_cpus)
+{
+ struct device_node *node;
+ unsigned int i;
+
+ node = of_find_compatible_node(NULL, NULL, "rockchip,rk3066-smp-sram");
if (!node) {
- pr_err("%s: could not find pmu dt node\n", __func__);
+ pr_err("%s: could not find sram dt node\n", __func__);
return;
}
- pmu_base_addr = of_iomap(node, 0);
- if (!pmu_base_addr) {
- pr_err("%s: could not map pmu registers\n", __func__);
+ sram_base_addr = of_iomap(node, 0);
+ if (!sram_base_addr) {
+ pr_err("%s: could not map sram registers\n", __func__);
return;
}
- /* enable the SCU power domain */
- pmu_set_power_domain(PMU_PWRDN_SCU, true);
-
- /*
- * While the number of cpus is gathered from dt, also get the number
- * of cores from the scu to verify this value when booting the cores.
- */
- ncores = scu_get_core_count(scu_base_addr);
+ if (rockchip_smp_prepare_pmu())
+ return;
- scu_enable(scu_base_addr);
+ if (read_cpuid_part() == ARM_CPU_PART_CORTEX_A9) {
+ if (rockchip_smp_prepare_sram(node))
+ return;
+
+ /* enable the SCU power domain */
+ pmu_set_power_domain(PMU_PWRDN_SCU, true);
+
+ node = of_find_compatible_node(NULL, NULL, "arm,cortex-a9-scu");
+ if (!node) {
+ pr_err("%s: missing scu\n", __func__);
+ return;
+ }
+
+ scu_base_addr = of_iomap(node, 0);
+ if (!scu_base_addr) {
+ pr_err("%s: could not map scu registers\n", __func__);
+ return;
+ }
+
+ /*
+ * While the number of cpus is gathered from dt, also get the
+ * number of cores from the scu to verify this value when
+ * booting the cores.
+ */
+ ncores = scu_get_core_count(scu_base_addr);
+ pr_err("%s: ncores %d\n", __func__, ncores);
+
+ scu_enable(scu_base_addr);
+ } else {
+ unsigned int l2ctlr;
+
+ asm ("mrc p15, 1, %0, c9, c0, 2\n" : "=r" (l2ctlr));
+ ncores = ((l2ctlr >> 24) & 0x3) + 1;
+ }
/* Make sure that all cores except the first are really off */
for (i = 1; i < ncores; i++)
diff --git a/arch/arm/mach-rockchip/rockchip.c b/arch/arm/mach-rockchip/rockchip.c
index 8ab9e0e..d226b71 100644
--- a/arch/arm/mach-rockchip/rockchip.c
+++ b/arch/arm/mach-rockchip/rockchip.c
@@ -24,6 +24,12 @@
#include <asm/hardware/cache-l2x0.h>
#include "core.h"
+static void __init rockchip_dt_init(void)
+{
+ of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+ platform_device_register_simple("cpufreq-dt", 0, NULL, 0);
+}
+
static const char * const rockchip_board_dt_compat[] = {
"rockchip,rk2928",
"rockchip,rk3066a",
@@ -37,4 +43,5 @@ DT_MACHINE_START(ROCKCHIP_DT, "Rockchip Cortex-A9 (Device Tree)")
.l2c_aux_val = 0,
.l2c_aux_mask = ~0,
.dt_compat = rockchip_board_dt_compat,
+ .init_machine = rockchip_dt_init,
MACHINE_END
diff --git a/arch/arm/mach-s3c24xx/h1940-bluetooth.c b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
index b4d14b8..9c8b127 100644
--- a/arch/arm/mach-s3c24xx/h1940-bluetooth.c
+++ b/arch/arm/mach-s3c24xx/h1940-bluetooth.c
@@ -41,7 +41,7 @@ static void h1940bt_enable(int on)
mdelay(10);
gpio_set_value(S3C2410_GPH(1), 0);
- h1940_led_blink_set(-EINVAL, GPIO_LED_BLINK, NULL, NULL);
+ h1940_led_blink_set(NULL, GPIO_LED_BLINK, NULL, NULL);
}
else {
gpio_set_value(S3C2410_GPH(1), 1);
@@ -50,7 +50,7 @@ static void h1940bt_enable(int on)
mdelay(10);
gpio_set_value(H1940_LATCH_BLUETOOTH_POWER, 0);
- h1940_led_blink_set(-EINVAL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
+ h1940_led_blink_set(NULL, GPIO_LED_NO_BLINK_LOW, NULL, NULL);
}
}
diff --git a/arch/arm/mach-s3c24xx/h1940.h b/arch/arm/mach-s3c24xx/h1940.h
index 2950cc4..596d9f6 100644
--- a/arch/arm/mach-s3c24xx/h1940.h
+++ b/arch/arm/mach-s3c24xx/h1940.h
@@ -19,8 +19,10 @@
#define H1940_SUSPEND_RESUMEAT (0x30081000)
#define H1940_SUSPEND_CHECK (0x30080000)
+struct gpio_desc;
+
extern void h1940_pm_return(void);
-extern int h1940_led_blink_set(unsigned gpio, int state,
+extern int h1940_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on,
unsigned long *delay_off);
diff --git a/arch/arm/mach-s3c24xx/mach-h1940.c b/arch/arm/mach-s3c24xx/mach-h1940.c
index d35ddc1..d40d4f5 100644
--- a/arch/arm/mach-s3c24xx/mach-h1940.c
+++ b/arch/arm/mach-s3c24xx/mach-h1940.c
@@ -359,10 +359,11 @@ static struct platform_device h1940_battery = {
static DEFINE_SPINLOCK(h1940_blink_spin);
-int h1940_led_blink_set(unsigned gpio, int state,
+int h1940_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
int blink_gpio, check_gpio1, check_gpio2;
+ int gpio = desc ? desc_to_gpio(desc) : -EINVAL;
switch (gpio) {
case H1940_LATCH_LED_GREEN:
diff --git a/arch/arm/mach-s3c24xx/mach-rx1950.c b/arch/arm/mach-s3c24xx/mach-rx1950.c
index c3f2682..1d35ff3 100644
--- a/arch/arm/mach-s3c24xx/mach-rx1950.c
+++ b/arch/arm/mach-s3c24xx/mach-rx1950.c
@@ -250,9 +250,10 @@ static void rx1950_disable_charger(void)
static DEFINE_SPINLOCK(rx1950_blink_spin);
-static int rx1950_led_blink_set(unsigned gpio, int state,
+static int rx1950_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
+ int gpio = desc_to_gpio(desc);
int blink_gpio, check_gpio;
switch (gpio) {
diff --git a/arch/arm/mach-s3c64xx/cpuidle.c b/arch/arm/mach-s3c64xx/cpuidle.c
index 3c8ab07..2eb0724 100644
--- a/arch/arm/mach-s3c64xx/cpuidle.c
+++ b/arch/arm/mach-s3c64xx/cpuidle.c
@@ -48,7 +48,6 @@ static struct cpuidle_driver s3c64xx_cpuidle_driver = {
.enter = s3c64xx_enter_idle,
.exit_latency = 1,
.target_residency = 1,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "IDLE",
.desc = "System active, ARM gated",
},
diff --git a/arch/arm/mach-sa1100/pci-nanoengine.c b/arch/arm/mach-sa1100/pci-nanoengine.c
index ff02e2da..b704433 100644
--- a/arch/arm/mach-sa1100/pci-nanoengine.c
+++ b/arch/arm/mach-sa1100/pci-nanoengine.c
@@ -33,12 +33,12 @@
static DEFINE_SPINLOCK(nano_lock);
static int nanoengine_get_pci_address(struct pci_bus *bus,
- unsigned int devfn, int where, unsigned long *address)
+ unsigned int devfn, int where, void __iomem **address)
{
int ret = PCIBIOS_DEVICE_NOT_FOUND;
unsigned int busnr = bus->number;
- *address = NANO_PCI_CONFIG_SPACE_VIRT +
+ *address = (void __iomem *)NANO_PCI_CONFIG_SPACE_VIRT +
((bus->number << 16) | (devfn << 8) | (where & ~3));
ret = (busnr > 255 || devfn > 255 || where > 255) ?
@@ -51,7 +51,7 @@ static int nanoengine_read_config(struct pci_bus *bus, unsigned int devfn, int w
int size, u32 *val)
{
int ret;
- unsigned long address;
+ void __iomem *address;
unsigned long flags;
u32 v;
@@ -85,7 +85,7 @@ static int nanoengine_write_config(struct pci_bus *bus, unsigned int devfn, int
int size, u32 val)
{
int ret;
- unsigned long address;
+ void __iomem *address;
unsigned long flags;
unsigned shift;
u32 v;
diff --git a/arch/arm/mach-shmobile/Kconfig b/arch/arm/mach-shmobile/Kconfig
index 21f457b..1b4fafe 100644
--- a/arch/arm/mach-shmobile/Kconfig
+++ b/arch/arm/mach-shmobile/Kconfig
@@ -1,5 +1,6 @@
config ARCH_SHMOBILE
bool
+ select ZONE_DMA if ARM_LPAE
config PM_RCAR
bool
@@ -18,6 +19,7 @@ config ARCH_RCAR_GEN2
select PM_RCAR if PM || SMP
select RENESAS_IRQC
select SYS_SUPPORTS_SH_CMT
+ select PCI_DOMAINS if PCI
config ARCH_RMOBILE
bool
@@ -36,7 +38,6 @@ menuconfig ARCH_SHMOBILE_MULTI
select NO_IOPORT_MAP
select PINCTRL
select ARCH_REQUIRE_GPIOLIB
- select ARCH_HAS_OPP
if ARCH_SHMOBILE_MULTI
@@ -73,11 +74,6 @@ config ARCH_R8A7794
comment "Renesas ARM SoCs Board Type"
-config MACH_KOELSCH
- bool "Koelsch board"
- depends on ARCH_R8A7791
- select MICREL_PHY if SH_ETH
-
config MACH_LAGER
bool "Lager board"
depends on ARCH_R8A7790
@@ -145,14 +141,6 @@ config ARCH_R8A7790
select MIGHT_HAVE_PCI
select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
-config ARCH_R8A7791
- bool "R-Car M2-W (R8A77910)"
- select ARCH_RCAR_GEN2
- select ARCH_WANT_OPTIONAL_GPIOLIB
- select ARM_GIC
- select MIGHT_HAVE_PCI
- select ARCH_DMA_ADDR_T_64BIT if ARM_LPAE
-
comment "Renesas ARM SoCs Board Type"
config MACH_APE6EVM
@@ -227,12 +215,6 @@ config MACH_LAGER
select MICREL_PHY if SH_ETH
select SND_SOC_AK4642 if SND_SIMPLE_CARD
-config MACH_KOELSCH
- bool "Koelsch board"
- depends on ARCH_R8A7791
- select USE_OF
- select MICREL_PHY if SH_ETH
-
config MACH_KZM9G
bool "KZM-A9-GT board"
depends on ARCH_SH73A0
diff --git a/arch/arm/mach-shmobile/Makefile b/arch/arm/mach-shmobile/Makefile
index e20f278..b55cac0 100644
--- a/arch/arm/mach-shmobile/Makefile
+++ b/arch/arm/mach-shmobile/Makefile
@@ -19,8 +19,8 @@ obj-$(CONFIG_ARCH_EMEV2) += setup-emev2.o
obj-$(CONFIG_ARCH_R7S72100) += setup-r7s72100.o
# Clock objects
-obj-y += clock.o
ifndef CONFIG_COMMON_CLK
+obj-y += clock.o
obj-$(CONFIG_ARCH_SH7372) += clock-sh7372.o
obj-$(CONFIG_ARCH_SH73A0) += clock-sh73a0.o
obj-$(CONFIG_ARCH_R8A73A4) += clock-r8a73a4.o
@@ -28,7 +28,6 @@ obj-$(CONFIG_ARCH_R8A7740) += clock-r8a7740.o
obj-$(CONFIG_ARCH_R8A7778) += clock-r8a7778.o
obj-$(CONFIG_ARCH_R8A7779) += clock-r8a7779.o
obj-$(CONFIG_ARCH_R8A7790) += clock-r8a7790.o
-obj-$(CONFIG_ARCH_R8A7791) += clock-r8a7791.o
endif
# CPU reset vector handling objects
@@ -36,6 +35,7 @@ cpu-y := platsmp.o headsmp.o
# Shared SoC family objects
obj-$(CONFIG_ARCH_RCAR_GEN2) += setup-rcar-gen2.o platsmp-apmu.o $(cpu-y)
+CFLAGS_setup-rcar-gen2.o += -march=armv7-a
# SMP objects
smp-y := $(cpu-y)
@@ -57,7 +57,6 @@ obj-$(CONFIG_ARCH_SH7372) += entry-intc.o sleep-sh7372.o
# Board objects
ifdef CONFIG_ARCH_SHMOBILE_MULTI
-obj-$(CONFIG_MACH_KOELSCH) += board-koelsch-reference.o
obj-$(CONFIG_MACH_LAGER) += board-lager-reference.o
obj-$(CONFIG_MACH_MARZEN) += board-marzen-reference.o
else
@@ -69,7 +68,6 @@ obj-$(CONFIG_MACH_BOCKW_REFERENCE) += board-bockw-reference.o
obj-$(CONFIG_MACH_MARZEN) += board-marzen.o
obj-$(CONFIG_MACH_LAGER) += board-lager.o
obj-$(CONFIG_MACH_ARMADILLO800EVA) += board-armadillo800eva.o
-obj-$(CONFIG_MACH_KOELSCH) += board-koelsch.o
obj-$(CONFIG_MACH_KZM9G) += board-kzm9g.o
obj-$(CONFIG_MACH_KZM9G_REFERENCE) += board-kzm9g-reference.o
endif
diff --git a/arch/arm/mach-shmobile/Makefile.boot b/arch/arm/mach-shmobile/Makefile.boot
index de9a238..57d00ed 100644
--- a/arch/arm/mach-shmobile/Makefile.boot
+++ b/arch/arm/mach-shmobile/Makefile.boot
@@ -5,7 +5,6 @@ loadaddr-$(CONFIG_MACH_APE6EVM_REFERENCE) += 0x40008000
loadaddr-$(CONFIG_MACH_ARMADILLO800EVA) += 0x40008000
loadaddr-$(CONFIG_MACH_BOCKW) += 0x60008000
loadaddr-$(CONFIG_MACH_BOCKW_REFERENCE) += 0x60008000
-loadaddr-$(CONFIG_MACH_KOELSCH) += 0x40008000
loadaddr-$(CONFIG_MACH_KZM9G) += 0x41008000
loadaddr-$(CONFIG_MACH_KZM9G_REFERENCE) += 0x41008000
loadaddr-$(CONFIG_MACH_LAGER) += 0x40008000
diff --git a/arch/arm/mach-shmobile/board-ape6evm-reference.c b/arch/arm/mach-shmobile/board-ape6evm-reference.c
index a6503d8..3b68370 100644
--- a/arch/arm/mach-shmobile/board-ape6evm-reference.c
+++ b/arch/arm/mach-shmobile/board-ape6evm-reference.c
@@ -12,10 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/gpio.h>
@@ -48,7 +44,6 @@ static void __init ape6evm_add_standard_devices(void)
clk_put(parent);
clk_put(mp);
- r8a73a4_add_dt_devices();
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
diff --git a/arch/arm/mach-shmobile/board-ape6evm.c b/arch/arm/mach-shmobile/board-ape6evm.c
index b222f68..66f6781 100644
--- a/arch/arm/mach-shmobile/board-ape6evm.c
+++ b/arch/arm/mach-shmobile/board-ape6evm.c
@@ -12,10 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/gpio.h>
diff --git a/arch/arm/mach-shmobile/board-armadillo800eva.c b/arch/arm/mach-shmobile/board-armadillo800eva.c
index e709835..6d949f1 100644
--- a/arch/arm/mach-shmobile/board-armadillo800eva.c
+++ b/arch/arm/mach-shmobile/board-armadillo800eva.c
@@ -12,53 +12,48 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/clk.h>
#include <linux/delay.h>
#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/input.h>
-#include <linux/platform_data/st1232_pdata.h>
-#include <linux/irq.h>
-#include <linux/platform_device.h>
#include <linux/gpio.h>
#include <linux/gpio_keys.h>
-#include <linux/regulator/driver.h>
+#include <linux/i2c-gpio.h>
+#include <linux/input.h>
+#include <linux/irq.h>
+#include <linux/kernel.h>
+#include <linux/mfd/tmio.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/sh_mmcif.h>
+#include <linux/mmc/sh_mobile_sdhi.h>
#include <linux/pinctrl/machine.h>
+#include <linux/platform_data/st1232_pdata.h>
+#include <linux/platform_device.h>
#include <linux/pwm.h>
#include <linux/pwm_backlight.h>
+#include <linux/reboot.h>
+#include <linux/regulator/driver.h>
#include <linux/regulator/fixed.h>
#include <linux/regulator/gpio-regulator.h>
#include <linux/regulator/machine.h>
#include <linux/sh_eth.h>
-#include <linux/videodev2.h>
#include <linux/usb/renesas_usbhs.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mmcif.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <linux/i2c-gpio.h>
-#include <linux/reboot.h>
+#include <linux/videodev2.h>
-#include <media/mt9t112.h>
-#include <media/sh_mobile_ceu.h>
-#include <media/soc_camera.h>
-#include <asm/page.h>
+#include <asm/hardware/cache-l2x0.h>
#include <asm/mach-types.h>
#include <asm/mach/arch.h>
#include <asm/mach/map.h>
#include <asm/mach/time.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <video/sh_mobile_lcdc.h>
-#include <video/sh_mobile_hdmi.h>
+#include <asm/page.h>
+#include <media/mt9t112.h>
+#include <media/sh_mobile_ceu.h>
+#include <media/soc_camera.h>
#include <sound/sh_fsi.h>
#include <sound/simple_card.h>
+#include <video/sh_mobile_hdmi.h>
+#include <video/sh_mobile_lcdc.h>
#include "common.h"
#include "irqs.h"
@@ -1234,8 +1229,15 @@ static void __init eva_init(void)
static struct pm_domain_device domain_devices[] __initdata = {
{ "A4LC", &lcdc0_device },
{ "A4LC", &hdmi_lcdc_device },
+ { "A4MP", &hdmi_device },
+ { "A4MP", &fsi_device },
+ { "A4R", &ceu0_device },
+ { "A4S", &sh_eth_device },
+ { "A3SP", &pwm_device },
+ { "A3SP", &sdhi0_device },
+ { "A3SP", &sh_mmcif_device },
};
- struct platform_device *usb = NULL;
+ struct platform_device *usb = NULL, *sdhi1 = NULL;
regulator_register_always_on(0, "fixed-3.3V", fixed3v3_power_consumers,
ARRAY_SIZE(fixed3v3_power_consumers), 3300000);
@@ -1304,6 +1306,7 @@ static void __init eva_init(void)
platform_device_register(&vcc_sdhi1);
platform_device_register(&sdhi1_device);
+ sdhi1 = &sdhi1_device;
}
@@ -1324,6 +1327,8 @@ static void __init eva_init(void)
ARRAY_SIZE(domain_devices));
if (usb)
rmobile_add_device_to_domain("A3SP", usb);
+ if (sdhi1)
+ rmobile_add_device_to_domain("A3SP", sdhi1);
r8a7740_pm_init();
}
diff --git a/arch/arm/mach-shmobile/board-bockw-reference.c b/arch/arm/mach-shmobile/board-bockw-reference.c
index 79c4784..d649ade 100644
--- a/arch/arm/mach-shmobile/board-bockw-reference.c
+++ b/arch/arm/mach-shmobile/board-bockw-reference.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/of_platform.h>
diff --git a/arch/arm/mach-shmobile/board-bockw.c b/arch/arm/mach-shmobile/board-bockw.c
index 1cf2c75..f27b5a8 100644
--- a/arch/arm/mach-shmobile/board-bockw.c
+++ b/arch/arm/mach-shmobile/board-bockw.c
@@ -13,10 +13,6 @@
* but WITHOUT 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/mfd/tmio.h>
diff --git a/arch/arm/mach-shmobile/board-koelsch-reference.c b/arch/arm/mach-shmobile/board-koelsch-reference.c
deleted file mode 100644
index 46aa540..0000000
--- a/arch/arm/mach-shmobile/board-koelsch-reference.c
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * Koelsch board support - Reference DT implementation
- *
- * Copyright (C) 2013 Renesas Electronics Corporation
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/kernel.h>
-#include <linux/of_platform.h>
-#include <linux/platform_data/rcar-du.h>
-
-#include <asm/mach/arch.h>
-
-#include "clock.h"
-#include "common.h"
-#include "irqs.h"
-#include "r8a7791.h"
-#include "rcar-gen2.h"
-
-/* DU */
-static struct rcar_du_encoder_data koelsch_du_encoders[] = {
- {
- .type = RCAR_DU_ENCODER_NONE,
- .output = RCAR_DU_OUTPUT_LVDS0,
- .connector.lvds.panel = {
- .width_mm = 210,
- .height_mm = 158,
- .mode = {
- .pixelclock = 65000000,
- .hactive = 1024,
- .hfront_porch = 20,
- .hback_porch = 160,
- .hsync_len = 136,
- .vactive = 768,
- .vfront_porch = 3,
- .vback_porch = 29,
- .vsync_len = 6,
- },
- },
- },
-};
-
-static struct rcar_du_platform_data koelsch_du_pdata = {
- .encoders = koelsch_du_encoders,
- .num_encoders = ARRAY_SIZE(koelsch_du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
- DEFINE_RES_MEM(0xfeb00000, 0x40000),
- DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"),
- DEFINE_RES_IRQ(gic_spi(256)),
- DEFINE_RES_IRQ(gic_spi(268)),
-};
-
-static void __init koelsch_add_du_device(void)
-{
- struct platform_device_info info = {
- .name = "rcar-du-r8a7791",
- .id = -1,
- .res = du_resources,
- .num_res = ARRAY_SIZE(du_resources),
- .data = &koelsch_du_pdata,
- .size_data = sizeof(koelsch_du_pdata),
- .dma_mask = DMA_BIT_MASK(32),
- };
-
- platform_device_register_full(&info);
-}
-
-/*
- * This is a really crude hack to provide clkdev support to platform
- * devices until they get moved to DT.
- */
-static const struct clk_name clk_names[] __initconst = {
- { "du0", "du.0", "rcar-du-r8a7791" },
- { "du1", "du.1", "rcar-du-r8a7791" },
- { "lvds0", "lvds.0", "rcar-du-r8a7791" },
-};
-
-static void __init koelsch_add_standard_devices(void)
-{
- shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
- koelsch_add_du_device();
-}
-
-static const char * const koelsch_boards_compat_dt[] __initconst = {
- "renesas,koelsch",
- "renesas,koelsch-reference",
- NULL,
-};
-
-DT_MACHINE_START(KOELSCH_DT, "koelsch")
- .smp = smp_ops(r8a7791_smp_ops),
- .init_early = shmobile_init_delay,
- .init_time = rcar_gen2_timer_init,
- .init_machine = koelsch_add_standard_devices,
- .init_late = shmobile_init_late,
- .reserve = rcar_gen2_reserve,
- .dt_compat = koelsch_boards_compat_dt,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-koelsch.c b/arch/arm/mach-shmobile/board-koelsch.c
deleted file mode 100644
index 7111b5c..0000000
--- a/arch/arm/mach-shmobile/board-koelsch.c
+++ /dev/null
@@ -1,527 +0,0 @@
-/*
- * Koelsch board support
- *
- * Copyright (C) 2013 Renesas Electronics Corporation
- * Copyright (C) 2013-2014 Renesas Solutions Corp.
- * Copyright (C) 2013 Magnus Damm
- * Copyright (C) 2014 Cogent Embedded, Inc.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-
-#include <linux/dma-mapping.h>
-#include <linux/gpio.h>
-#include <linux/gpio_keys.h>
-#include <linux/input.h>
-#include <linux/irq.h>
-#include <linux/kernel.h>
-#include <linux/leds.h>
-#include <linux/mfd/tmio.h>
-#include <linux/mmc/host.h>
-#include <linux/mmc/sh_mobile_sdhi.h>
-#include <linux/mtd/mtd.h>
-#include <linux/mtd/partitions.h>
-#include <linux/phy.h>
-#include <linux/pinctrl/machine.h>
-#include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/rcar-du.h>
-#include <linux/platform_device.h>
-#include <linux/regulator/driver.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/gpio-regulator.h>
-#include <linux/regulator/machine.h>
-#include <linux/sh_eth.h>
-#include <linux/spi/flash.h>
-#include <linux/spi/rspi.h>
-#include <linux/spi/spi.h>
-
-#include <asm/mach-types.h>
-#include <asm/mach/arch.h>
-
-#include "common.h"
-#include "irqs.h"
-#include "r8a7791.h"
-#include "rcar-gen2.h"
-
-/* DU */
-static struct rcar_du_encoder_data koelsch_du_encoders[] = {
- {
- .type = RCAR_DU_ENCODER_NONE,
- .output = RCAR_DU_OUTPUT_LVDS0,
- .connector.lvds.panel = {
- .width_mm = 210,
- .height_mm = 158,
- .mode = {
- .pixelclock = 65000000,
- .hactive = 1024,
- .hfront_porch = 20,
- .hback_porch = 160,
- .hsync_len = 136,
- .vactive = 768,
- .vfront_porch = 3,
- .vback_porch = 29,
- .vsync_len = 6,
- },
- },
- },
-};
-
-static const struct rcar_du_platform_data koelsch_du_pdata __initconst = {
- .encoders = koelsch_du_encoders,
- .num_encoders = ARRAY_SIZE(koelsch_du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
- DEFINE_RES_MEM(0xfeb00000, 0x40000),
- DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"),
- DEFINE_RES_IRQ(gic_spi(256)),
- DEFINE_RES_IRQ(gic_spi(268)),
-};
-
-static void __init koelsch_add_du_device(void)
-{
- struct platform_device_info info = {
- .name = "rcar-du-r8a7791",
- .id = -1,
- .res = du_resources,
- .num_res = ARRAY_SIZE(du_resources),
- .data = &koelsch_du_pdata,
- .size_data = sizeof(koelsch_du_pdata),
- .dma_mask = DMA_BIT_MASK(32),
- };
-
- platform_device_register_full(&info);
-}
-
-/* Ether */
-static const struct sh_eth_plat_data ether_pdata __initconst = {
- .phy = 0x1,
- .phy_irq = irq_pin(0),
- .edmac_endian = EDMAC_LITTLE_ENDIAN,
- .phy_interface = PHY_INTERFACE_MODE_RMII,
- .ether_link_active_low = 1,
-};
-
-static const struct resource ether_resources[] __initconst = {
- DEFINE_RES_MEM(0xee700000, 0x400),
- DEFINE_RES_IRQ(gic_spi(162)),
-};
-
-static const struct platform_device_info ether_info __initconst = {
- .name = "r8a7791-ether",
- .id = -1,
- .res = ether_resources,
- .num_res = ARRAY_SIZE(ether_resources),
- .data = &ether_pdata,
- .size_data = sizeof(ether_pdata),
- .dma_mask = DMA_BIT_MASK(32),
-};
-
-/* LEDS */
-static struct gpio_led koelsch_leds[] = {
- {
- .name = "led8",
- .gpio = RCAR_GP_PIN(2, 21),
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- }, {
- .name = "led7",
- .gpio = RCAR_GP_PIN(2, 20),
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- }, {
- .name = "led6",
- .gpio = RCAR_GP_PIN(2, 19),
- .default_state = LEDS_GPIO_DEFSTATE_ON,
- },
-};
-
-static const struct gpio_led_platform_data koelsch_leds_pdata __initconst = {
- .leds = koelsch_leds,
- .num_leds = ARRAY_SIZE(koelsch_leds),
-};
-
-/* GPIO KEY */
-#define GPIO_KEY(c, g, d, ...) \
- { .code = c, .gpio = g, .desc = d, .active_low = 1, \
- .wakeup = 1, .debounce_interval = 20 }
-
-static struct gpio_keys_button gpio_buttons[] = {
- GPIO_KEY(KEY_4, RCAR_GP_PIN(5, 3), "SW2-pin4"),
- GPIO_KEY(KEY_3, RCAR_GP_PIN(5, 2), "SW2-pin3"),
- GPIO_KEY(KEY_2, RCAR_GP_PIN(5, 1), "SW2-pin2"),
- GPIO_KEY(KEY_1, RCAR_GP_PIN(5, 0), "SW2-pin1"),
- GPIO_KEY(KEY_G, RCAR_GP_PIN(7, 6), "SW36"),
- GPIO_KEY(KEY_F, RCAR_GP_PIN(7, 5), "SW35"),
- GPIO_KEY(KEY_E, RCAR_GP_PIN(7, 4), "SW34"),
- GPIO_KEY(KEY_D, RCAR_GP_PIN(7, 3), "SW33"),
- GPIO_KEY(KEY_C, RCAR_GP_PIN(7, 2), "SW32"),
- GPIO_KEY(KEY_B, RCAR_GP_PIN(7, 1), "SW31"),
- GPIO_KEY(KEY_A, RCAR_GP_PIN(7, 0), "SW30"),
-};
-
-static const struct gpio_keys_platform_data koelsch_keys_pdata __initconst = {
- .buttons = gpio_buttons,
- .nbuttons = ARRAY_SIZE(gpio_buttons),
-};
-
-/* QSPI */
-static const struct resource qspi_resources[] __initconst = {
- DEFINE_RES_MEM(0xe6b10000, 0x1000),
- DEFINE_RES_IRQ_NAMED(gic_spi(184), "mux"),
-};
-
-static const struct rspi_plat_data qspi_pdata __initconst = {
- .num_chipselect = 1,
-};
-
-/* SPI Flash memory (Spansion S25FL512SAGMFIG11 64 MiB) */
-static struct mtd_partition spi_flash_part[] = {
- {
- .name = "loader",
- .offset = 0x00000000,
- .size = 512 * 1024,
- .mask_flags = MTD_WRITEABLE,
- },
- {
- .name = "bootenv",
- .offset = MTDPART_OFS_APPEND,
- .size = 512 * 1024,
- .mask_flags = MTD_WRITEABLE,
- },
- {
- .name = "data",
- .offset = MTDPART_OFS_APPEND,
- .size = MTDPART_SIZ_FULL,
- },
-};
-
-static const struct flash_platform_data spi_flash_data = {
- .name = "m25p80",
- .parts = spi_flash_part,
- .nr_parts = ARRAY_SIZE(spi_flash_part),
- .type = "s25fl512s",
-};
-
-static const struct spi_board_info spi_info[] __initconst = {
- {
- .modalias = "m25p80",
- .platform_data = &spi_flash_data,
- .mode = SPI_MODE_0 | SPI_TX_QUAD | SPI_RX_QUAD,
- .max_speed_hz = 30000000,
- .bus_num = 0,
- .chip_select = 0,
- },
-};
-
-/* SATA0 */
-static const struct resource sata0_resources[] __initconst = {
- DEFINE_RES_MEM(0xee300000, 0x2000),
- DEFINE_RES_IRQ(gic_spi(105)),
-};
-
-static const struct platform_device_info sata0_info __initconst = {
- .name = "sata-r8a7791",
- .id = 0,
- .res = sata0_resources,
- .num_res = ARRAY_SIZE(sata0_resources),
- .dma_mask = DMA_BIT_MASK(32),
-};
-
-/* I2C */
-static const struct resource i2c_resources[] __initconst = {
- /* I2C0 */
- DEFINE_RES_MEM(0xE6508000, 0x40),
- DEFINE_RES_IRQ(gic_spi(287)),
- /* I2C1 */
- DEFINE_RES_MEM(0xE6518000, 0x40),
- DEFINE_RES_IRQ(gic_spi(288)),
- /* I2C2 */
- DEFINE_RES_MEM(0xE6530000, 0x40),
- DEFINE_RES_IRQ(gic_spi(286)),
- /* I2C3 */
- DEFINE_RES_MEM(0xE6540000, 0x40),
- DEFINE_RES_IRQ(gic_spi(290)),
- /* I2C4 */
- DEFINE_RES_MEM(0xE6520000, 0x40),
- DEFINE_RES_IRQ(gic_spi(19)),
- /* I2C5 */
- DEFINE_RES_MEM(0xE6528000, 0x40),
- DEFINE_RES_IRQ(gic_spi(20)),
-};
-
-static void __init koelsch_add_i2c(unsigned idx)
-{
- unsigned res_idx = idx * 2;
-
- BUG_ON(res_idx >= ARRAY_SIZE(i2c_resources));
-
- platform_device_register_simple("i2c-rcar_gen2", idx,
- i2c_resources + res_idx, 2);
-}
-
-#define SDHI_REGULATOR(idx, vdd_pin, vccq_pin) \
-static struct regulator_consumer_supply vcc_sdhi##idx##_consumer = \
- REGULATOR_SUPPLY("vmmc", "sh_mobile_sdhi." #idx); \
- \
-static struct regulator_init_data vcc_sdhi##idx##_init_data = { \
- .constraints = { \
- .valid_ops_mask = REGULATOR_CHANGE_STATUS, \
- }, \
- .consumer_supplies = &vcc_sdhi##idx##_consumer, \
- .num_consumer_supplies = 1, \
-}; \
- \
-static const struct fixed_voltage_config vcc_sdhi##idx##_info __initconst = {\
- .supply_name = "SDHI" #idx "Vcc", \
- .microvolts = 3300000, \
- .gpio = vdd_pin, \
- .enable_high = 1, \
- .init_data = &vcc_sdhi##idx##_init_data, \
-}; \
- \
-static struct regulator_consumer_supply vccq_sdhi##idx##_consumer = \
- REGULATOR_SUPPLY("vqmmc", "sh_mobile_sdhi." #idx); \
- \
-static struct regulator_init_data vccq_sdhi##idx##_init_data = { \
- .constraints = { \
- .input_uV = 3300000, \
- .min_uV = 1800000, \
- .max_uV = 3300000, \
- .valid_ops_mask = REGULATOR_CHANGE_VOLTAGE | \
- REGULATOR_CHANGE_STATUS, \
- }, \
- .consumer_supplies = &vccq_sdhi##idx##_consumer, \
- .num_consumer_supplies = 1, \
-}; \
- \
-static struct gpio vccq_sdhi##idx##_gpio = \
- { vccq_pin, GPIOF_OUT_INIT_HIGH, "vccq-sdhi" #idx }; \
- \
-static struct gpio_regulator_state vccq_sdhi##idx##_states[] = { \
- { .value = 1800000, .gpios = 0 }, \
- { .value = 3300000, .gpios = 1 }, \
-}; \
- \
-static const struct gpio_regulator_config vccq_sdhi##idx##_info __initconst = {\
- .supply_name = "vqmmc", \
- .gpios = &vccq_sdhi##idx##_gpio, \
- .nr_gpios = 1, \
- .states = vccq_sdhi##idx##_states, \
- .nr_states = ARRAY_SIZE(vccq_sdhi##idx##_states), \
- .type = REGULATOR_VOLTAGE, \
- .init_data = &vccq_sdhi##idx##_init_data, \
-};
-
-SDHI_REGULATOR(0, RCAR_GP_PIN(7, 17), RCAR_GP_PIN(2, 12));
-SDHI_REGULATOR(1, RCAR_GP_PIN(7, 18), RCAR_GP_PIN(2, 13));
-SDHI_REGULATOR(2, RCAR_GP_PIN(7, 19), RCAR_GP_PIN(2, 26));
-
-/* SDHI0 */
-static struct sh_mobile_sdhi_info sdhi0_info __initdata = {
- .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
- MMC_CAP_POWER_OFF_CARD,
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static struct resource sdhi0_resources[] __initdata = {
- DEFINE_RES_MEM(0xee100000, 0x200),
- DEFINE_RES_IRQ(gic_spi(165)),
-};
-
-/* SDHI1 */
-static struct sh_mobile_sdhi_info sdhi1_info __initdata = {
- .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
- MMC_CAP_POWER_OFF_CARD,
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT,
-};
-
-static struct resource sdhi1_resources[] __initdata = {
- DEFINE_RES_MEM(0xee140000, 0x100),
- DEFINE_RES_IRQ(gic_spi(167)),
-};
-
-/* SDHI2 */
-static struct sh_mobile_sdhi_info sdhi2_info __initdata = {
- .tmio_caps = MMC_CAP_SD_HIGHSPEED | MMC_CAP_SDIO_IRQ |
- MMC_CAP_POWER_OFF_CARD,
- .tmio_flags = TMIO_MMC_HAS_IDLE_WAIT |
- TMIO_MMC_WRPROTECT_DISABLE,
-};
-
-static struct resource sdhi2_resources[] __initdata = {
- DEFINE_RES_MEM(0xee160000, 0x100),
- DEFINE_RES_IRQ(gic_spi(168)),
-};
-
-static const struct pinctrl_map koelsch_pinctrl_map[] = {
- /* DU */
- PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791",
- "du_rgb666", "du"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791",
- "du_sync", "du"),
- PIN_MAP_MUX_GROUP_DEFAULT("rcar-du-r8a7791", "pfc-r8a7791",
- "du_clk_out_0", "du"),
- /* Ether */
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791",
- "eth_link", "eth"),
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791",
- "eth_mdio", "eth"),
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791",
- "eth_rmii", "eth"),
- PIN_MAP_MUX_GROUP_DEFAULT("r8a7791-ether", "pfc-r8a7791",
- "intc_irq0", "intc"),
- /* QSPI */
- PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7791",
- "qspi_ctrl", "qspi"),
- PIN_MAP_MUX_GROUP_DEFAULT("qspi.0", "pfc-r8a7791",
- "qspi_data4", "qspi"),
- /* SCIF0 (CN19: DEBUG SERIAL0) */
- PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.6", "pfc-r8a7791",
- "scif0_data_d", "scif0"),
- /* SCIF1 (CN20: DEBUG SERIAL1) */
- PIN_MAP_MUX_GROUP_DEFAULT("sh-sci.7", "pfc-r8a7791",
- "scif1_data_d", "scif1"),
- /* I2C1 */
- PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.1", "pfc-r8a7791",
- "i2c1_e", "i2c1"),
- /* I2C2 */
- PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.2", "pfc-r8a7791",
- "i2c2", "i2c2"),
- /* I2C4 */
- PIN_MAP_MUX_GROUP_DEFAULT("i2c-rcar_gen2.4", "pfc-r8a7791",
- "i2c4_c", "i2c4"),
- /* SDHI0 */
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791",
- "sdhi0_data4", "sdhi0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791",
- "sdhi0_ctrl", "sdhi0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791",
- "sdhi0_cd", "sdhi0"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.0", "pfc-r8a7791",
- "sdhi0_wp", "sdhi0"),
- /* SDHI2 */
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791",
- "sdhi1_data4", "sdhi1"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791",
- "sdhi1_ctrl", "sdhi1"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791",
- "sdhi1_cd", "sdhi1"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.1", "pfc-r8a7791",
- "sdhi1_wp", "sdhi1"),
- /* SDHI2 */
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7791",
- "sdhi2_data4", "sdhi2"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7791",
- "sdhi2_ctrl", "sdhi2"),
- PIN_MAP_MUX_GROUP_DEFAULT("sh_mobile_sdhi.2", "pfc-r8a7791",
- "sdhi2_cd", "sdhi2"),
-};
-
-static void __init koelsch_add_standard_devices(void)
-{
- r8a7791_clock_init();
- pinctrl_register_mappings(koelsch_pinctrl_map,
- ARRAY_SIZE(koelsch_pinctrl_map));
- r8a7791_pinmux_init();
- r8a7791_add_standard_devices();
- platform_device_register_full(&ether_info);
- platform_device_register_data(NULL, "leds-gpio", -1,
- &koelsch_leds_pdata,
- sizeof(koelsch_leds_pdata));
- platform_device_register_data(NULL, "gpio-keys", -1,
- &koelsch_keys_pdata,
- sizeof(koelsch_keys_pdata));
- platform_device_register_resndata(NULL, "qspi", 0,
- qspi_resources,
- ARRAY_SIZE(qspi_resources),
- &qspi_pdata, sizeof(qspi_pdata));
- spi_register_board_info(spi_info, ARRAY_SIZE(spi_info));
-
- koelsch_add_du_device();
-
- platform_device_register_full(&sata0_info);
-
- koelsch_add_i2c(1);
- koelsch_add_i2c(2);
- koelsch_add_i2c(4);
- koelsch_add_i2c(5);
-
- platform_device_register_data(NULL, "reg-fixed-voltage", 0,
- &vcc_sdhi0_info, sizeof(struct fixed_voltage_config));
- platform_device_register_data(NULL, "reg-fixed-voltage", 1,
- &vcc_sdhi1_info, sizeof(struct fixed_voltage_config));
- platform_device_register_data(NULL, "reg-fixed-voltage", 2,
- &vcc_sdhi2_info, sizeof(struct fixed_voltage_config));
- platform_device_register_data(NULL, "gpio-regulator", 0,
- &vccq_sdhi0_info, sizeof(struct gpio_regulator_config));
- platform_device_register_data(NULL, "gpio-regulator", 1,
- &vccq_sdhi1_info, sizeof(struct gpio_regulator_config));
- platform_device_register_data(NULL, "gpio-regulator", 2,
- &vccq_sdhi2_info, sizeof(struct gpio_regulator_config));
-
- platform_device_register_resndata(NULL, "sh_mobile_sdhi", 0,
- sdhi0_resources, ARRAY_SIZE(sdhi0_resources),
- &sdhi0_info, sizeof(struct sh_mobile_sdhi_info));
-
- platform_device_register_resndata(NULL, "sh_mobile_sdhi", 1,
- sdhi1_resources, ARRAY_SIZE(sdhi1_resources),
- &sdhi1_info, sizeof(struct sh_mobile_sdhi_info));
-
- platform_device_register_resndata(NULL, "sh_mobile_sdhi", 2,
- sdhi2_resources, ARRAY_SIZE(sdhi2_resources),
- &sdhi2_info, sizeof(struct sh_mobile_sdhi_info));
-
-}
-
-/*
- * Ether LEDs on the Koelsch board are named LINK and ACTIVE which corresponds
- * to non-default 01 setting of the Micrel KSZ8041 PHY control register 1 bits
- * 14-15. We have to set them back to 01 from the default 00 value each time
- * the PHY is reset. It's also important because the PHY's LED0 signal is
- * connected to SoC's ETH_LINK signal and in the PHY's default mode it will
- * bounce on and off after each packet, which we apparently want to avoid.
- */
-static int koelsch_ksz8041_fixup(struct phy_device *phydev)
-{
- u16 phyctrl1 = phy_read(phydev, 0x1e);
-
- phyctrl1 &= ~0xc000;
- phyctrl1 |= 0x4000;
- return phy_write(phydev, 0x1e, phyctrl1);
-}
-
-static void __init koelsch_init(void)
-{
- koelsch_add_standard_devices();
-
- irq_set_irq_type(irq_pin(0), IRQ_TYPE_LEVEL_LOW);
-
- if (IS_ENABLED(CONFIG_PHYLIB))
- phy_register_fixup_for_id("r8a7791-ether-ff:01",
- koelsch_ksz8041_fixup);
-}
-
-static const char * const koelsch_boards_compat_dt[] __initconst = {
- "renesas,koelsch",
- NULL,
-};
-
-DT_MACHINE_START(KOELSCH_DT, "koelsch")
- .smp = smp_ops(r8a7791_smp_ops),
- .init_early = shmobile_init_delay,
- .init_time = rcar_gen2_timer_init,
- .init_machine = koelsch_init,
- .init_late = shmobile_init_late,
- .reserve = rcar_gen2_reserve,
- .dt_compat = koelsch_boards_compat_dt,
-MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9g-reference.c b/arch/arm/mach-shmobile/board-kzm9g-reference.c
index d9cdf9a..2e82e44 100644
--- a/arch/arm/mach-shmobile/board-kzm9g-reference.c
+++ b/arch/arm/mach-shmobile/board-kzm9g-reference.c
@@ -14,10 +14,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/delay.h>
@@ -43,6 +39,13 @@ static void __init kzm_init(void)
#endif
}
+#define RESCNT2 IOMEM(0xe6188020)
+static void kzm9g_restart(enum reboot_mode mode, const char *cmd)
+{
+ /* Do soft power on reset */
+ writel((1 << 31), RESCNT2);
+}
+
static const char *kzm9g_boards_compat_dt[] __initdata = {
"renesas,kzm9g-reference",
NULL,
@@ -54,5 +57,6 @@ DT_MACHINE_START(KZM9G_DT, "kzm9g-reference")
.init_early = shmobile_init_delay,
.init_machine = kzm_init,
.init_late = shmobile_init_late,
+ .restart = kzm9g_restart,
.dt_compat = kzm9g_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/board-kzm9g.c b/arch/arm/mach-shmobile/board-kzm9g.c
index 77e36fa..7c9b63b 100644
--- a/arch/arm/mach-shmobile/board-kzm9g.c
+++ b/arch/arm/mach-shmobile/board-kzm9g.c
@@ -11,10 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/delay.h>
diff --git a/arch/arm/mach-shmobile/board-lager-reference.c b/arch/arm/mach-shmobile/board-lager-reference.c
index bc4b483..fa06bdb 100644
--- a/arch/arm/mach-shmobile/board-lager-reference.c
+++ b/arch/arm/mach-shmobile/board-lager-reference.c
@@ -12,100 +12,17 @@
* but WITHOUT 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/dma-mapping.h>
#include <linux/init.h>
#include <linux/of_platform.h>
-#include <linux/platform_data/rcar-du.h>
#include <asm/mach/arch.h>
-#include "clock.h"
#include "common.h"
-#include "irqs.h"
#include "r8a7790.h"
#include "rcar-gen2.h"
-/* DU */
-static struct rcar_du_encoder_data lager_du_encoders[] = {
- {
- .type = RCAR_DU_ENCODER_VGA,
- .output = RCAR_DU_OUTPUT_DPAD0,
- }, {
- .type = RCAR_DU_ENCODER_NONE,
- .output = RCAR_DU_OUTPUT_LVDS1,
- .connector.lvds.panel = {
- .width_mm = 210,
- .height_mm = 158,
- .mode = {
- .pixelclock = 65000000,
- .hactive = 1024,
- .hfront_porch = 20,
- .hback_porch = 160,
- .hsync_len = 136,
- .vactive = 768,
- .vfront_porch = 3,
- .vback_porch = 29,
- .vsync_len = 6,
- },
- },
- },
-};
-
-static struct rcar_du_platform_data lager_du_pdata = {
- .encoders = lager_du_encoders,
- .num_encoders = ARRAY_SIZE(lager_du_encoders),
-};
-
-static const struct resource du_resources[] __initconst = {
- DEFINE_RES_MEM(0xfeb00000, 0x70000),
- DEFINE_RES_MEM_NAMED(0xfeb90000, 0x1c, "lvds.0"),
- DEFINE_RES_MEM_NAMED(0xfeb94000, 0x1c, "lvds.1"),
- DEFINE_RES_IRQ(gic_spi(256)),
- DEFINE_RES_IRQ(gic_spi(268)),
- DEFINE_RES_IRQ(gic_spi(269)),
-};
-
-static void __init lager_add_du_device(void)
-{
- struct platform_device_info info = {
- .name = "rcar-du-r8a7790",
- .id = -1,
- .res = du_resources,
- .num_res = ARRAY_SIZE(du_resources),
- .data = &lager_du_pdata,
- .size_data = sizeof(lager_du_pdata),
- .dma_mask = DMA_BIT_MASK(32),
- };
-
- platform_device_register_full(&info);
-}
-
-/*
- * This is a really crude hack to provide clkdev support to platform
- * devices until they get moved to DT.
- */
-static const struct clk_name clk_names[] __initconst = {
- { "du0", "du.0", "rcar-du-r8a7790" },
- { "du1", "du.1", "rcar-du-r8a7790" },
- { "du2", "du.2", "rcar-du-r8a7790" },
- { "lvds0", "lvds.0", "rcar-du-r8a7790" },
- { "lvds1", "lvds.1", "rcar-du-r8a7790" },
-};
-
-static void __init lager_add_standard_devices(void)
-{
- shmobile_clk_workaround(clk_names, ARRAY_SIZE(clk_names), false);
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-
- lager_add_du_device();
-}
-
static const char *lager_boards_compat_dt[] __initdata = {
"renesas,lager",
"renesas,lager-reference",
@@ -116,7 +33,6 @@ DT_MACHINE_START(LAGER_DT, "lager")
.smp = smp_ops(r8a7790_smp_ops),
.init_early = shmobile_init_delay,
.init_time = rcar_gen2_timer_init,
- .init_machine = lager_add_standard_devices,
.init_late = shmobile_init_late,
.reserve = rcar_gen2_reserve,
.dt_compat = lager_boards_compat_dt,
diff --git a/arch/arm/mach-shmobile/board-lager.c b/arch/arm/mach-shmobile/board-lager.c
index 571327b..b47262a 100644
--- a/arch/arm/mach-shmobile/board-lager.c
+++ b/arch/arm/mach-shmobile/board-lager.c
@@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/gpio.h>
diff --git a/arch/arm/mach-shmobile/board-mackerel.c b/arch/arm/mach-shmobile/board-mackerel.c
index ca5d34b..a1c1dfb 100644
--- a/arch/arm/mach-shmobile/board-mackerel.c
+++ b/arch/arm/mach-shmobile/board-mackerel.c
@@ -16,10 +16,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/delay.h>
#include <linux/kernel.h>
@@ -1153,7 +1149,7 @@ static struct soc_camera_platform_info camera_info = {
.format_name = "UYVY",
.format_depth = 16,
.format = {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.field = V4L2_FIELD_NONE,
.width = 640,
diff --git a/arch/arm/mach-shmobile/board-marzen-reference.c b/arch/arm/mach-shmobile/board-marzen-reference.c
index 38d9cdd..b15eb92 100644
--- a/arch/arm/mach-shmobile/board-marzen-reference.c
+++ b/arch/arm/mach-shmobile/board-marzen-reference.c
@@ -13,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/clk/shmobile.h>
@@ -26,7 +22,6 @@
#include <asm/irq.h>
#include <asm/mach/arch.h>
-#include "clock.h"
#include "common.h"
#include "irqs.h"
#include "r8a7779.h"
diff --git a/arch/arm/mach-shmobile/board-marzen.c b/arch/arm/mach-shmobile/board-marzen.c
index ce33d78..994dc7d 100644
--- a/arch/arm/mach-shmobile/board-marzen.c
+++ b/arch/arm/mach-shmobile/board-marzen.c
@@ -13,10 +13,6 @@
* but WITHOUT 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>
diff --git a/arch/arm/mach-shmobile/clock-r8a73a4.c b/arch/arm/mach-shmobile/clock-r8a73a4.c
index c2330ea..1cf44dc 100644
--- a/arch/arm/mach-shmobile/clock-r8a73a4.c
+++ b/arch/arm/mach-shmobile/clock-r8a73a4.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/io.h>
diff --git a/arch/arm/mach-shmobile/clock-r8a7740.c b/arch/arm/mach-shmobile/clock-r8a7740.c
index 19df9cb..9cac824 100644
--- a/arch/arm/mach-shmobile/clock-r8a7740.c
+++ b/arch/arm/mach-shmobile/clock-r8a7740.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/kernel.h>
diff --git a/arch/arm/mach-shmobile/clock-r8a7778.c b/arch/arm/mach-shmobile/clock-r8a7778.c
index 67980a0..e8510c3 100644
--- a/arch/arm/mach-shmobile/clock-r8a7778.c
+++ b/arch/arm/mach-shmobile/clock-r8a7778.c
@@ -17,10 +17,6 @@
* but WITHOUT 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
*/
/*
diff --git a/arch/arm/mach-shmobile/clock-r8a7779.c b/arch/arm/mach-shmobile/clock-r8a7779.c
index c51f9db..fa8ab2c 100644
--- a/arch/arm/mach-shmobile/clock-r8a7779.c
+++ b/arch/arm/mach-shmobile/clock-r8a7779.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/bitops.h>
#include <linux/init.h>
diff --git a/arch/arm/mach-shmobile/clock-r8a7790.c b/arch/arm/mach-shmobile/clock-r8a7790.c
index f622652..f9bbc5f 100644
--- a/arch/arm/mach-shmobile/clock-r8a7790.c
+++ b/arch/arm/mach-shmobile/clock-r8a7790.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/io.h>
diff --git a/arch/arm/mach-shmobile/clock-r8a7791.c b/arch/arm/mach-shmobile/clock-r8a7791.c
deleted file mode 100644
index 453b231..0000000
--- a/arch/arm/mach-shmobile/clock-r8a7791.c
+++ /dev/null
@@ -1,342 +0,0 @@
-/*
- * r8a7791 clock framework support
- *
- * Copyright (C) 2013 Renesas Electronics Corporation
- * Copyright (C) 2013 Renesas Solutions Corp.
- * Copyright (C) 2013 Magnus Damm
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- */
-#include <linux/init.h>
-#include <linux/io.h>
-#include <linux/kernel.h>
-#include <linux/sh_clk.h>
-#include <linux/clkdev.h>
-#include "clock.h"
-#include "common.h"
-#include "rcar-gen2.h"
-
-/*
- * MD EXTAL PLL0 PLL1 PLL3
- * 14 13 19 (MHz) *1 *1
- *---------------------------------------------------
- * 0 0 0 15 x 1 x172/2 x208/2 x106
- * 0 0 1 15 x 1 x172/2 x208/2 x88
- * 0 1 0 20 x 1 x130/2 x156/2 x80
- * 0 1 1 20 x 1 x130/2 x156/2 x66
- * 1 0 0 26 / 2 x200/2 x240/2 x122
- * 1 0 1 26 / 2 x200/2 x240/2 x102
- * 1 1 0 30 / 2 x172/2 x208/2 x106
- * 1 1 1 30 / 2 x172/2 x208/2 x88
- *
- * *1 : Table 7.6 indicates VCO ouput (PLLx = VCO/2)
- * see "p1 / 2" on R8A7791_CLOCK_ROOT() below
- */
-
-#define CPG_BASE 0xe6150000
-#define CPG_LEN 0x1000
-
-#define SMSTPCR0 0xE6150130
-#define SMSTPCR1 0xE6150134
-#define SMSTPCR2 0xe6150138
-#define SMSTPCR3 0xE615013C
-#define SMSTPCR5 0xE6150144
-#define SMSTPCR7 0xe615014c
-#define SMSTPCR8 0xE6150990
-#define SMSTPCR9 0xE6150994
-#define SMSTPCR10 0xE6150998
-#define SMSTPCR11 0xE615099C
-
-#define MSTPSR1 IOMEM(0xe6150038)
-#define MSTPSR2 IOMEM(0xe6150040)
-#define MSTPSR3 IOMEM(0xe6150048)
-#define MSTPSR5 IOMEM(0xe615003c)
-#define MSTPSR7 IOMEM(0xe61501c4)
-#define MSTPSR8 IOMEM(0xe61509a0)
-#define MSTPSR9 IOMEM(0xe61509a4)
-#define MSTPSR11 IOMEM(0xe61509ac)
-
-#define SDCKCR 0xE6150074
-#define SD1CKCR 0xE6150078
-#define SD2CKCR 0xE615026c
-#define MMC0CKCR 0xE6150240
-#define MMC1CKCR 0xE6150244
-#define SSPCKCR 0xE6150248
-#define SSPRSCKCR 0xE615024C
-
-static struct clk_mapping cpg_mapping = {
- .phys = CPG_BASE,
- .len = CPG_LEN,
-};
-
-static struct clk extal_clk = {
- /* .rate will be updated on r8a7791_clock_init() */
- .mapping = &cpg_mapping,
-};
-
-static struct sh_clk_ops followparent_clk_ops = {
- .recalc = followparent_recalc,
-};
-
-static struct clk main_clk = {
- /* .parent will be set r8a73a4_clock_init */
- .ops = &followparent_clk_ops,
-};
-
-/*
- * clock ratio of these clock will be updated
- * on r8a7791_clock_init()
- */
-SH_FIXED_RATIO_CLK_SET(pll1_clk, main_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(pll3_clk, main_clk, 1, 1);
-SH_FIXED_RATIO_CLK_SET(qspi_clk, pll1_clk, 1, 1);
-
-/* fixed ratio clock */
-SH_FIXED_RATIO_CLK_SET(extal_div2_clk, extal_clk, 1, 2);
-SH_FIXED_RATIO_CLK_SET(cp_clk, extal_clk, 1, 2);
-
-SH_FIXED_RATIO_CLK_SET(pll1_div2_clk, pll1_clk, 1, 2);
-SH_FIXED_RATIO_CLK_SET(hp_clk, pll1_clk, 1, 12);
-SH_FIXED_RATIO_CLK_SET(p_clk, pll1_clk, 1, 24);
-SH_FIXED_RATIO_CLK_SET(rclk_clk, pll1_clk, 1, (48 * 1024));
-SH_FIXED_RATIO_CLK_SET(mp_clk, pll1_div2_clk, 1, 15);
-SH_FIXED_RATIO_CLK_SET(zg_clk, pll1_clk, 1, 3);
-SH_FIXED_RATIO_CLK_SET(zx_clk, pll1_clk, 1, 3);
-SH_FIXED_RATIO_CLK_SET(zs_clk, pll1_clk, 1, 6);
-
-static struct clk *main_clks[] = {
- &extal_clk,
- &extal_div2_clk,
- &main_clk,
- &pll1_clk,
- &pll1_div2_clk,
- &pll3_clk,
- &hp_clk,
- &p_clk,
- &qspi_clk,
- &rclk_clk,
- &mp_clk,
- &cp_clk,
- &zg_clk,
- &zx_clk,
- &zs_clk,
-};
-
-/* SDHI (DIV4) clock */
-static int divisors[] = { 2, 3, 4, 6, 8, 12, 16, 18, 24, 0, 36, 48, 10 };
-
-static struct clk_div_mult_table div4_div_mult_table = {
- .divisors = divisors,
- .nr_divisors = ARRAY_SIZE(divisors),
-};
-
-static struct clk_div4_table div4_table = {
- .div_mult_table = &div4_div_mult_table,
-};
-
-enum {
- DIV4_SDH, DIV4_SD0,
- DIV4_NR
-};
-
-static struct clk div4_clks[DIV4_NR] = {
- [DIV4_SDH] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 8, 0x0dff, CLK_ENABLE_ON_INIT),
- [DIV4_SD0] = SH_CLK_DIV4(&pll1_clk, SDCKCR, 4, 0x1df0, CLK_ENABLE_ON_INIT),
-};
-
-/* DIV6 clocks */
-enum {
- DIV6_SD1, DIV6_SD2,
- DIV6_NR
-};
-
-static struct clk div6_clks[DIV6_NR] = {
- [DIV6_SD1] = SH_CLK_DIV6(&pll1_div2_clk, SD1CKCR, 0),
- [DIV6_SD2] = SH_CLK_DIV6(&pll1_div2_clk, SD2CKCR, 0),
-};
-
-/* MSTP */
-enum {
- MSTP1108, MSTP1107, MSTP1106,
- MSTP931, MSTP930, MSTP929, MSTP928, MSTP927, MSTP925,
- MSTP917,
- MSTP815, MSTP814,
- MSTP813,
- MSTP811, MSTP810, MSTP809,
- MSTP726, MSTP724, MSTP723, MSTP721, MSTP720,
- MSTP719, MSTP718, MSTP715, MSTP714,
- MSTP522,
- MSTP314, MSTP312, MSTP311,
- MSTP216, MSTP207, MSTP206,
- MSTP204, MSTP203, MSTP202,
- MSTP124,
- MSTP_NR
-};
-
-static struct clk mstp_clks[MSTP_NR] = {
- [MSTP1108] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 8, MSTPSR11, 0), /* SCIFA5 */
- [MSTP1107] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 7, MSTPSR11, 0), /* SCIFA4 */
- [MSTP1106] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR11, 6, MSTPSR11, 0), /* SCIFA3 */
- [MSTP931] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 31, MSTPSR9, 0), /* I2C0 */
- [MSTP930] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 30, MSTPSR9, 0), /* I2C1 */
- [MSTP929] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 29, MSTPSR9, 0), /* I2C2 */
- [MSTP928] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 28, MSTPSR9, 0), /* I2C3 */
- [MSTP927] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 27, MSTPSR9, 0), /* I2C4 */
- [MSTP925] = SH_CLK_MSTP32_STS(&hp_clk, SMSTPCR9, 25, MSTPSR9, 0), /* I2C5 */
- [MSTP917] = SH_CLK_MSTP32_STS(&qspi_clk, SMSTPCR9, 17, MSTPSR9, 0), /* QSPI */
- [MSTP815] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 15, MSTPSR8, 0), /* SATA0 */
- [MSTP814] = SH_CLK_MSTP32_STS(&zs_clk, SMSTPCR8, 14, MSTPSR8, 0), /* SATA1 */
- [MSTP813] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR8, 13, MSTPSR8, 0), /* Ether */
- [MSTP811] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 11, MSTPSR8, 0), /* VIN0 */
- [MSTP810] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 10, MSTPSR8, 0), /* VIN1 */
- [MSTP809] = SH_CLK_MSTP32_STS(&zg_clk, SMSTPCR8, 9, MSTPSR8, 0), /* VIN2 */
- [MSTP726] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 26, MSTPSR7, 0), /* LVDS0 */
- [MSTP724] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 24, MSTPSR7, 0), /* DU0 */
- [MSTP723] = SH_CLK_MSTP32_STS(&zx_clk, SMSTPCR7, 23, MSTPSR7, 0), /* DU1 */
- [MSTP721] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 21, MSTPSR7, 0), /* SCIF0 */
- [MSTP720] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 20, MSTPSR7, 0), /* SCIF1 */
- [MSTP719] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 19, MSTPSR7, 0), /* SCIF2 */
- [MSTP718] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 18, MSTPSR7, 0), /* SCIF3 */
- [MSTP715] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 15, MSTPSR7, 0), /* SCIF4 */
- [MSTP714] = SH_CLK_MSTP32_STS(&p_clk, SMSTPCR7, 14, MSTPSR7, 0), /* SCIF5 */
- [MSTP522] = SH_CLK_MSTP32_STS(&extal_clk, SMSTPCR5, 22, MSTPSR5, 0), /* Thermal */
- [MSTP314] = SH_CLK_MSTP32_STS(&div4_clks[DIV4_SD0], SMSTPCR3, 14, MSTPSR3, 0), /* SDHI0 */
- [MSTP312] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD1], SMSTPCR3, 12, MSTPSR3, 0), /* SDHI1 */
- [MSTP311] = SH_CLK_MSTP32_STS(&div6_clks[DIV6_SD2], SMSTPCR3, 11, MSTPSR3, 0), /* SDHI2 */
- [MSTP216] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 16, MSTPSR2, 0), /* SCIFB2 */
- [MSTP207] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 7, MSTPSR2, 0), /* SCIFB1 */
- [MSTP206] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 6, MSTPSR2, 0), /* SCIFB0 */
- [MSTP204] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 4, MSTPSR2, 0), /* SCIFA0 */
- [MSTP203] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 3, MSTPSR2, 0), /* SCIFA1 */
- [MSTP202] = SH_CLK_MSTP32_STS(&mp_clk, SMSTPCR2, 2, MSTPSR2, 0), /* SCIFA2 */
- [MSTP124] = SH_CLK_MSTP32_STS(&rclk_clk, SMSTPCR1, 24, MSTPSR1, 0), /* CMT0 */
-};
-
-static struct clk_lookup lookups[] = {
-
- /* main clocks */
- CLKDEV_CON_ID("extal", &extal_clk),
- CLKDEV_CON_ID("extal_div2", &extal_div2_clk),
- CLKDEV_CON_ID("main", &main_clk),
- CLKDEV_CON_ID("pll1", &pll1_clk),
- CLKDEV_CON_ID("pll1_div2", &pll1_div2_clk),
- CLKDEV_CON_ID("pll3", &pll3_clk),
- CLKDEV_CON_ID("zg", &zg_clk),
- CLKDEV_CON_ID("zs", &zs_clk),
- CLKDEV_CON_ID("hp", &hp_clk),
- CLKDEV_CON_ID("p", &p_clk),
- CLKDEV_CON_ID("qspi", &qspi_clk),
- CLKDEV_CON_ID("rclk", &rclk_clk),
- CLKDEV_CON_ID("mp", &mp_clk),
- CLKDEV_CON_ID("cp", &cp_clk),
- CLKDEV_CON_ID("peripheral_clk", &hp_clk),
-
- /* MSTP */
- CLKDEV_ICK_ID("lvds.0", "rcar-du-r8a7791", &mstp_clks[MSTP726]),
- CLKDEV_ICK_ID("du.0", "rcar-du-r8a7791", &mstp_clks[MSTP724]),
- CLKDEV_ICK_ID("du.1", "rcar-du-r8a7791", &mstp_clks[MSTP723]),
- CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
- CLKDEV_DEV_ID("sh-sci.1", &mstp_clks[MSTP203]), /* SCIFA1 */
- CLKDEV_DEV_ID("sh-sci.2", &mstp_clks[MSTP206]), /* SCIFB0 */
- CLKDEV_DEV_ID("sh-sci.3", &mstp_clks[MSTP207]), /* SCIFB1 */
- CLKDEV_DEV_ID("sh-sci.4", &mstp_clks[MSTP216]), /* SCIFB2 */
- CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP202]), /* SCIFA2 */
- CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP721]), /* SCIF0 */
- CLKDEV_DEV_ID("sh-sci.7", &mstp_clks[MSTP720]), /* SCIF1 */
- CLKDEV_DEV_ID("sh-sci.8", &mstp_clks[MSTP719]), /* SCIF2 */
- CLKDEV_DEV_ID("sh-sci.9", &mstp_clks[MSTP718]), /* SCIF3 */
- CLKDEV_DEV_ID("sh-sci.10", &mstp_clks[MSTP715]), /* SCIF4 */
- CLKDEV_DEV_ID("sh-sci.11", &mstp_clks[MSTP714]), /* SCIF5 */
- CLKDEV_DEV_ID("sh-sci.12", &mstp_clks[MSTP1106]), /* SCIFA3 */
- CLKDEV_DEV_ID("sh-sci.13", &mstp_clks[MSTP1107]), /* SCIFA4 */
- CLKDEV_DEV_ID("sh-sci.14", &mstp_clks[MSTP1108]), /* SCIFA5 */
- CLKDEV_DEV_ID("sh_mobile_sdhi.0", &mstp_clks[MSTP314]),
- CLKDEV_DEV_ID("sh_mobile_sdhi.1", &mstp_clks[MSTP312]),
- CLKDEV_DEV_ID("sh_mobile_sdhi.2", &mstp_clks[MSTP311]),
- CLKDEV_ICK_ID("fck", "sh-cmt-48-gen2.0", &mstp_clks[MSTP124]),
- CLKDEV_DEV_ID("qspi.0", &mstp_clks[MSTP917]),
- CLKDEV_DEV_ID("rcar_thermal", &mstp_clks[MSTP522]),
- CLKDEV_DEV_ID("i2c-rcar_gen2.0", &mstp_clks[MSTP931]),
- CLKDEV_DEV_ID("i2c-rcar_gen2.1", &mstp_clks[MSTP930]),
- CLKDEV_DEV_ID("i2c-rcar_gen2.2", &mstp_clks[MSTP929]),
- CLKDEV_DEV_ID("i2c-rcar_gen2.3", &mstp_clks[MSTP928]),
- CLKDEV_DEV_ID("i2c-rcar_gen2.4", &mstp_clks[MSTP927]),
- CLKDEV_DEV_ID("i2c-rcar_gen2.5", &mstp_clks[MSTP925]),
- CLKDEV_DEV_ID("r8a7791-ether", &mstp_clks[MSTP813]), /* Ether */
- CLKDEV_DEV_ID("r8a7791-vin.0", &mstp_clks[MSTP811]),
- CLKDEV_DEV_ID("r8a7791-vin.1", &mstp_clks[MSTP810]),
- CLKDEV_DEV_ID("r8a7791-vin.2", &mstp_clks[MSTP809]),
- CLKDEV_DEV_ID("sata-r8a7791.0", &mstp_clks[MSTP815]),
- CLKDEV_DEV_ID("sata-r8a7791.1", &mstp_clks[MSTP814]),
-};
-
-#define R8A7791_CLOCK_ROOT(e, m, p0, p1, p30, p31) \
- extal_clk.rate = e * 1000 * 1000; \
- main_clk.parent = m; \
- SH_CLK_SET_RATIO(&pll1_clk_ratio, p1 / 2, 1); \
- if (mode & MD(19)) \
- SH_CLK_SET_RATIO(&pll3_clk_ratio, p31, 1); \
- else \
- SH_CLK_SET_RATIO(&pll3_clk_ratio, p30, 1)
-
-
-void __init r8a7791_clock_init(void)
-{
- u32 mode = rcar_gen2_read_mode_pins();
- int k, ret = 0;
-
- switch (mode & (MD(14) | MD(13))) {
- case 0:
- R8A7791_CLOCK_ROOT(15, &extal_clk, 172, 208, 106, 88);
- break;
- case MD(13):
- R8A7791_CLOCK_ROOT(20, &extal_clk, 130, 156, 80, 66);
- break;
- case MD(14):
- R8A7791_CLOCK_ROOT(26, &extal_div2_clk, 200, 240, 122, 102);
- break;
- case MD(13) | MD(14):
- R8A7791_CLOCK_ROOT(30, &extal_div2_clk, 172, 208, 106, 88);
- break;
- }
-
- if ((mode & (MD(3) | MD(2) | MD(1))) == MD(2))
- SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 16);
- else
- SH_CLK_SET_RATIO(&qspi_clk_ratio, 1, 20);
-
- for (k = 0; !ret && (k < ARRAY_SIZE(main_clks)); k++)
- ret = clk_register(main_clks[k]);
-
- if (!ret)
- ret = sh_clk_div4_register(div4_clks, DIV4_NR, &div4_table);
-
- if (!ret)
- ret = sh_clk_div6_register(div6_clks, DIV6_NR);
-
- if (!ret)
- ret = sh_clk_mstp_register(mstp_clks, MSTP_NR);
-
- clkdev_add_table(lookups, ARRAY_SIZE(lookups));
-
- if (!ret)
- shmobile_clk_init();
- else
- goto epanic;
-
- return;
-
-epanic:
- panic("failed to setup r8a7791 clocks\n");
-}
diff --git a/arch/arm/mach-shmobile/clock-sh7372.c b/arch/arm/mach-shmobile/clock-sh7372.c
index 7071676..3bc92f4 100644
--- a/arch/arm/mach-shmobile/clock-sh7372.c
+++ b/arch/arm/mach-shmobile/clock-sh7372.c
@@ -11,10 +11,6 @@
* but WITHOUT 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/kernel.h>
diff --git a/arch/arm/mach-shmobile/clock-sh73a0.c b/arch/arm/mach-shmobile/clock-sh73a0.c
index 02a6f45..6b4c1f3 100644
--- a/arch/arm/mach-shmobile/clock-sh73a0.c
+++ b/arch/arm/mach-shmobile/clock-sh73a0.c
@@ -11,10 +11,6 @@
* but WITHOUT 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/kernel.h>
diff --git a/arch/arm/mach-shmobile/clock.c b/arch/arm/mach-shmobile/clock.c
index 806f940..34f056f 100644
--- a/arch/arm/mach-shmobile/clock.c
+++ b/arch/arm/mach-shmobile/clock.c
@@ -14,41 +14,13 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 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/export.h>
#include <linux/kernel.h>
#include <linux/init.h>
-
-#ifdef CONFIG_COMMON_CLK
-#include <linux/clk.h>
-#include <linux/clkdev.h>
-#include "clock.h"
-
-void __init shmobile_clk_workaround(const struct clk_name *clks,
- int nr_clks, bool enable)
-{
- const struct clk_name *clkn;
- struct clk *clk;
- unsigned int i;
-
- for (i = 0; i < nr_clks; ++i) {
- clkn = clks + i;
- clk = clk_get(NULL, clkn->clk);
- if (!IS_ERR(clk)) {
- clk_register_clkdev(clk, clkn->con_id, clkn->dev_id);
- if (enable)
- clk_prepare_enable(clk);
- clk_put(clk);
- }
- }
-}
-
-#else /* CONFIG_COMMON_CLK */
#include <linux/sh_clk.h>
-#include <linux/export.h>
+
#include "clock.h"
#include "common.h"
@@ -84,5 +56,3 @@ void __clk_put(struct clk *clk)
{
}
EXPORT_SYMBOL(__clk_put);
-
-#endif /* CONFIG_COMMON_CLK */
diff --git a/arch/arm/mach-shmobile/clock.h b/arch/arm/mach-shmobile/clock.h
index 31b6417..cf3552e 100644
--- a/arch/arm/mach-shmobile/clock.h
+++ b/arch/arm/mach-shmobile/clock.h
@@ -1,19 +1,6 @@
#ifndef CLOCK_H
#define CLOCK_H
-#ifdef CONFIG_COMMON_CLK
-/* temporary clock configuration helper for platform devices */
-
-struct clk_name {
- const char *clk;
- const char *con_id;
- const char *dev_id;
-};
-
-void shmobile_clk_workaround(const struct clk_name *clks, int nr_clks,
- bool enable);
-
-#else /* CONFIG_COMMON_CLK */
/* legacy clock implementation */
struct clk;
@@ -52,5 +39,4 @@ do { \
(p)->div = d; \
} while (0)
-#endif /* CONFIG_COMMON_CLK */
#endif
diff --git a/arch/arm/mach-shmobile/common.h b/arch/arm/mach-shmobile/common.h
index 72087c7..309025e 100644
--- a/arch/arm/mach-shmobile/common.h
+++ b/arch/arm/mach-shmobile/common.h
@@ -19,11 +19,6 @@ extern void shmobile_boot_scu(void);
extern void shmobile_smp_scu_prepare_cpus(unsigned int max_cpus);
extern void shmobile_smp_scu_cpu_die(unsigned int cpu);
extern int shmobile_smp_scu_cpu_kill(unsigned int cpu);
-extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus);
-extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
- struct task_struct *idle);
-extern void shmobile_smp_apmu_cpu_die(unsigned int cpu);
-extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu);
struct clk;
extern int shmobile_clk_init(void);
extern void shmobile_handle_irq_intc(struct pt_regs *);
diff --git a/arch/arm/mach-shmobile/console.c b/arch/arm/mach-shmobile/console.c
index f2e79f2..e329ccb 100644
--- a/arch/arm/mach-shmobile/console.c
+++ b/arch/arm/mach-shmobile/console.c
@@ -11,10 +11,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/headsmp-scu.S b/arch/arm/mach-shmobile/headsmp-scu.S
index f45dde7..69df8bf 100644
--- a/arch/arm/mach-shmobile/headsmp-scu.S
+++ b/arch/arm/mach-shmobile/headsmp-scu.S
@@ -12,11 +12,6 @@
* but WITHOUT 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/linkage.h>
diff --git a/arch/arm/mach-shmobile/intc-sh7372.c b/arch/arm/mach-shmobile/intc-sh7372.c
index e2af00b..1ccf49c 100644
--- a/arch/arm/mach-shmobile/intc-sh7372.c
+++ b/arch/arm/mach-shmobile/intc-sh7372.c
@@ -11,10 +11,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/intc-sh73a0.c b/arch/arm/mach-shmobile/intc-sh73a0.c
index 44457a9..9e36180 100644
--- a/arch/arm/mach-shmobile/intc-sh73a0.c
+++ b/arch/arm/mach-shmobile/intc-sh73a0.c
@@ -11,10 +11,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.c b/arch/arm/mach-shmobile/platsmp-apmu.c
index 2c06810..f483b56 100644
--- a/arch/arm/mach-shmobile/platsmp-apmu.c
+++ b/arch/arm/mach-shmobile/platsmp-apmu.c
@@ -1,6 +1,7 @@
/*
* SMP support for SoCs with APMU
*
+ * Copyright (C) 2014 Renesas Electronics Corporation
* Copyright (C) 2013 Magnus Damm
*
* This program is free software; you can redistribute it and/or modify
@@ -22,6 +23,7 @@
#include <asm/smp_plat.h>
#include <asm/suspend.h>
#include "common.h"
+#include "platsmp-apmu.h"
static struct {
void __iomem *iomem;
@@ -83,28 +85,15 @@ static void apmu_init_cpu(struct resource *res, int cpu, int bit)
pr_debug("apmu ioremap %d %d %pr\n", cpu, bit, res);
}
-static struct {
- struct resource iomem;
- int cpus[4];
-} apmu_config[] = {
- {
- .iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
- .cpus = { 0, 1, 2, 3 },
- },
- {
- .iomem = DEFINE_RES_MEM(0xe6151000, 0x88),
- .cpus = { 0x100, 0x101, 0x102, 0x103 },
- }
-};
-
-static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit))
+static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit),
+ struct rcar_apmu_config *apmu_config, int num)
{
u32 id;
int k;
int bit, index;
bool is_allowed;
- for (k = 0; k < ARRAY_SIZE(apmu_config); k++) {
+ for (k = 0; k < num; k++) {
/* only enable the cluster that includes the boot CPU */
is_allowed = false;
for (bit = 0; bit < ARRAY_SIZE(apmu_config[k].cpus); bit++) {
@@ -128,14 +117,16 @@ static void apmu_parse_cfg(void (*fn)(struct resource *res, int cpu, int bit))
}
}
-void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus)
+void __init shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
+ struct rcar_apmu_config *apmu_config,
+ int num)
{
/* install boot code shared by all CPUs */
shmobile_boot_fn = virt_to_phys(shmobile_smp_boot);
shmobile_boot_arg = MPIDR_HWID_BITMASK;
/* perform per-cpu setup */
- apmu_parse_cfg(apmu_init_cpu);
+ apmu_parse_cfg(apmu_init_cpu, apmu_config, num);
}
#ifdef CONFIG_SMP
diff --git a/arch/arm/mach-shmobile/platsmp-apmu.h b/arch/arm/mach-shmobile/platsmp-apmu.h
new file mode 100644
index 0000000..76512c9
--- /dev/null
+++ b/arch/arm/mach-shmobile/platsmp-apmu.h
@@ -0,0 +1,32 @@
+/*
+ * rmobile apmu definition
+ *
+ * Copyright (C) 2014 Renesas Electronics Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef PLATSMP_APMU_H
+#define PLATSMP_APMU_H
+
+struct rcar_apmu_config {
+ struct resource iomem;
+ int cpus[4];
+};
+
+extern void shmobile_smp_apmu_prepare_cpus(unsigned int max_cpus,
+ struct rcar_apmu_config *apmu_config,
+ int num);
+extern int shmobile_smp_apmu_boot_secondary(unsigned int cpu,
+ struct task_struct *idle);
+extern void shmobile_smp_apmu_cpu_die(unsigned int cpu);
+extern int shmobile_smp_apmu_cpu_kill(unsigned int cpu);
+
+#endif /* PLATSMP_APMU_H */
diff --git a/arch/arm/mach-shmobile/pm-r8a7740.c b/arch/arm/mach-shmobile/pm-r8a7740.c
index e3f1464..ac2eecd 100644
--- a/arch/arm/mach-shmobile/pm-r8a7740.c
+++ b/arch/arm/mach-shmobile/pm-r8a7740.c
@@ -14,10 +14,10 @@
#include "pm-rmobile.h"
#if defined(CONFIG_PM) && !defined(CONFIG_ARCH_MULTIPLATFORM)
-static int r8a7740_pd_a4s_suspend(void)
+static int r8a7740_pd_a3sm_suspend(void)
{
/*
- * The A4S domain contains the CPU core and therefore it should
+ * The A3SM domain contains the CPU core and therefore it should
* only be turned off if the CPU is not in use.
*/
return -EBUSY;
@@ -32,29 +32,65 @@ static int r8a7740_pd_a3sp_suspend(void)
return console_suspend_enabled ? 0 : -EBUSY;
}
+static int r8a7740_pd_d4_suspend(void)
+{
+ /*
+ * The D4 domain contains the Coresight-ETM hardware block and
+ * therefore it should only be turned off if the debug module is
+ * not in use.
+ */
+ return -EBUSY;
+}
+
static struct rmobile_pm_domain r8a7740_pm_domains[] = {
{
.genpd.name = "A4LC",
.bit_shift = 1,
}, {
+ .genpd.name = "A4MP",
+ .bit_shift = 2,
+ }, {
+ .genpd.name = "D4",
+ .bit_shift = 3,
+ .gov = &pm_domain_always_on_gov,
+ .suspend = r8a7740_pd_d4_suspend,
+ }, {
+ .genpd.name = "A4R",
+ .bit_shift = 5,
+ }, {
+ .genpd.name = "A3RV",
+ .bit_shift = 6,
+ }, {
.genpd.name = "A4S",
.bit_shift = 10,
- .gov = &pm_domain_always_on_gov,
.no_debug = true,
- .suspend = r8a7740_pd_a4s_suspend,
}, {
.genpd.name = "A3SP",
.bit_shift = 11,
.gov = &pm_domain_always_on_gov,
.no_debug = true,
.suspend = r8a7740_pd_a3sp_suspend,
+ }, {
+ .genpd.name = "A3SM",
+ .bit_shift = 12,
+ .gov = &pm_domain_always_on_gov,
+ .suspend = r8a7740_pd_a3sm_suspend,
+ }, {
+ .genpd.name = "A3SG",
+ .bit_shift = 13,
+ }, {
+ .genpd.name = "A4SU",
+ .bit_shift = 20,
},
};
void __init r8a7740_init_pm_domains(void)
{
rmobile_init_domains(r8a7740_pm_domains, ARRAY_SIZE(r8a7740_pm_domains));
+ pm_genpd_add_subdomain_names("A4R", "A3RV");
pm_genpd_add_subdomain_names("A4S", "A3SP");
+ pm_genpd_add_subdomain_names("A4S", "A3SM");
+ pm_genpd_add_subdomain_names("A4S", "A3SG");
}
#endif /* CONFIG_PM && !CONFIG_ARCH_MULTIPLATFORM */
diff --git a/arch/arm/mach-shmobile/pm-r8a7779.c b/arch/arm/mach-shmobile/pm-r8a7779.c
index 82fe3d7f..44a74c4 100644
--- a/arch/arm/mach-shmobile/pm-r8a7779.c
+++ b/arch/arm/mach-shmobile/pm-r8a7779.c
@@ -83,9 +83,8 @@ static void r8a7779_init_pm_domain(struct r8a7779_pm_domain *r8a7779_pd)
{
struct generic_pm_domain *genpd = &r8a7779_pd->genpd;
+ genpd->flags = GENPD_FLAG_PM_CLK;
pm_genpd_init(genpd, NULL, false);
- genpd->dev_ops.stop = pm_clk_suspend;
- genpd->dev_ops.start = pm_clk_resume;
genpd->dev_ops.active_wakeup = pd_active_wakeup;
genpd->power_off = pd_power_down;
genpd->power_on = pd_power_up;
diff --git a/arch/arm/mach-shmobile/pm-rmobile.c b/arch/arm/mach-shmobile/pm-rmobile.c
index 717e641..6f7d56e 100644
--- a/arch/arm/mach-shmobile/pm-rmobile.c
+++ b/arch/arm/mach-shmobile/pm-rmobile.c
@@ -106,9 +106,8 @@ static void rmobile_init_pm_domain(struct rmobile_pm_domain *rmobile_pd)
struct generic_pm_domain *genpd = &rmobile_pd->genpd;
struct dev_power_governor *gov = rmobile_pd->gov;
+ genpd->flags = GENPD_FLAG_PM_CLK;
pm_genpd_init(genpd, gov ? : &simple_qos_governor, false);
- genpd->dev_ops.stop = pm_clk_suspend;
- genpd->dev_ops.start = pm_clk_resume;
genpd->dev_ops.active_wakeup = rmobile_pd_active_wakeup;
genpd->power_off = rmobile_pd_power_down;
genpd->power_on = rmobile_pd_power_up;
diff --git a/arch/arm/mach-shmobile/pm-sh7372.c b/arch/arm/mach-shmobile/pm-sh7372.c
index 7e5c267..0e37da6 100644
--- a/arch/arm/mach-shmobile/pm-sh7372.c
+++ b/arch/arm/mach-shmobile/pm-sh7372.c
@@ -423,7 +423,6 @@ static struct cpuidle_driver sh7372_cpuidle_driver = {
.desc = "Core Standby Mode",
.exit_latency = 10,
.target_residency = 20 + 10,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = sh7372_enter_core_standby,
},
.states[2] = {
@@ -431,7 +430,6 @@ static struct cpuidle_driver sh7372_cpuidle_driver = {
.desc = "A3SM PLL ON",
.exit_latency = 20,
.target_residency = 30 + 20,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = sh7372_enter_a3sm_pll_on,
},
.states[3] = {
@@ -439,7 +437,6 @@ static struct cpuidle_driver sh7372_cpuidle_driver = {
.desc = "A3SM PLL OFF",
.exit_latency = 120,
.target_residency = 30 + 120,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = sh7372_enter_a3sm_pll_off,
},
.states[4] = {
@@ -447,7 +444,6 @@ static struct cpuidle_driver sh7372_cpuidle_driver = {
.desc = "A4S PLL OFF",
.exit_latency = 240,
.target_residency = 30 + 240,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = sh7372_enter_a4s,
.disabled = true,
},
diff --git a/arch/arm/mach-shmobile/r8a73a4.h b/arch/arm/mach-shmobile/r8a73a4.h
index 5fafd6f..70dcd84 100644
--- a/arch/arm/mach-shmobile/r8a73a4.h
+++ b/arch/arm/mach-shmobile/r8a73a4.h
@@ -11,7 +11,6 @@ enum {
};
void r8a73a4_add_standard_devices(void);
-void r8a73a4_add_dt_devices(void);
void r8a73a4_clock_init(void);
void r8a73a4_pinmux_init(void);
diff --git a/arch/arm/mach-shmobile/r8a7740.h b/arch/arm/mach-shmobile/r8a7740.h
index f369b4b..ca7805a 100644
--- a/arch/arm/mach-shmobile/r8a7740.h
+++ b/arch/arm/mach-shmobile/r8a7740.h
@@ -10,10 +10,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ASM_R8A7740_H__
diff --git a/arch/arm/mach-shmobile/r8a7778.h b/arch/arm/mach-shmobile/r8a7778.h
index f4076a5..f64fedb 100644
--- a/arch/arm/mach-shmobile/r8a7778.h
+++ b/arch/arm/mach-shmobile/r8a7778.h
@@ -11,10 +11,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#ifndef __ASM_R8A7778_H__
#define __ASM_R8A7778_H__
@@ -71,7 +67,6 @@ extern void r8a7778_add_standard_devices_dt(void);
extern void r8a7778_add_dt_devices(void);
extern void r8a7778_init_late(void);
-extern void r8a7778_init_delay(void);
extern void r8a7778_init_irq_dt(void);
extern void r8a7778_clock_init(void);
extern void r8a7778_init_irq_extpin(int irlm);
diff --git a/arch/arm/mach-shmobile/r8a7791.h b/arch/arm/mach-shmobile/r8a7791.h
index c1bf7ab..6cf11eb 100644
--- a/arch/arm/mach-shmobile/r8a7791.h
+++ b/arch/arm/mach-shmobile/r8a7791.h
@@ -1,9 +1,6 @@
#ifndef __ASM_R8A7791_H__
#define __ASM_R8A7791_H__
-void r8a7791_add_standard_devices(void);
-void r8a7791_clock_init(void);
-void r8a7791_pinmux_init(void);
void r8a7791_pm_init(void);
extern struct smp_operations r8a7791_smp_ops;
diff --git a/arch/arm/mach-shmobile/setup-emev2.c b/arch/arm/mach-shmobile/setup-emev2.c
index b06a9e8..aad97be 100644
--- a/arch/arm/mach-shmobile/setup-emev2.c
+++ b/arch/arm/mach-shmobile/setup-emev2.c
@@ -11,10 +11,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/setup-r7s72100.c b/arch/arm/mach-shmobile/setup-r7s72100.c
index 4122104..1711747 100644
--- a/arch/arm/mach-shmobile/setup-r7s72100.c
+++ b/arch/arm/mach-shmobile/setup-r7s72100.c
@@ -12,10 +12,6 @@
* but WITHOUT 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>
diff --git a/arch/arm/mach-shmobile/setup-r8a73a4.c b/arch/arm/mach-shmobile/setup-r8a73a4.c
index 53f40b7..c276822 100644
--- a/arch/arm/mach-shmobile/setup-r8a73a4.c
+++ b/arch/arm/mach-shmobile/setup-r8a73a4.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/irq.h>
#include <linux/kernel.h>
@@ -180,18 +176,13 @@ static struct resource cmt1_resources[] = {
DEFINE_RES_IRQ(gic_spi(120)),
};
-#define r8a7790_register_cmt(idx) \
+#define r8a73a4_register_cmt(idx) \
platform_device_register_resndata(NULL, "sh-cmt-48-gen2", \
idx, cmt##idx##_resources, \
ARRAY_SIZE(cmt##idx##_resources), \
&cmt##idx##_platform_data, \
sizeof(struct sh_timer_config))
-void __init r8a73a4_add_dt_devices(void)
-{
- r8a7790_register_cmt(1);
-}
-
/* DMA */
static const struct sh_dmae_slave_config dma_slaves[] = {
{
@@ -282,7 +273,7 @@ static struct resource dma_resources[] = {
void __init r8a73a4_add_standard_devices(void)
{
- r8a73a4_add_dt_devices();
+ r8a73a4_register_cmt(1);
r8a73a4_register_scif(0);
r8a73a4_register_scif(1);
r8a73a4_register_scif(2);
diff --git a/arch/arm/mach-shmobile/setup-r8a7740.c b/arch/arm/mach-shmobile/setup-r8a7740.c
index 8894e1b..79ad93d 100644
--- a/arch/arm/mach-shmobile/setup-r8a7740.c
+++ b/arch/arm/mach-shmobile/setup-r8a7740.c
@@ -12,10 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/delay.h>
#include <linux/dma-mapping.h>
@@ -71,6 +67,7 @@ static struct map_desc r8a7740_io_desc[] __initdata = {
void __init r8a7740_map_io(void)
{
+ debug_ll_io_init();
iotable_init(r8a7740_io_desc, ARRAY_SIZE(r8a7740_io_desc));
}
@@ -746,6 +743,12 @@ static void r8a7740_i2c_workaround(struct platform_device *pdev)
void __init r8a7740_add_standard_devices(void)
{
static struct pm_domain_device domain_devices[] __initdata = {
+ { "A4R", &tmu0_device },
+ { "A4R", &i2c0_device },
+ { "A4S", &irqpin0_device },
+ { "A4S", &irqpin1_device },
+ { "A4S", &irqpin2_device },
+ { "A4S", &irqpin3_device },
{ "A3SP", &scif0_device },
{ "A3SP", &scif1_device },
{ "A3SP", &scif2_device },
@@ -756,6 +759,11 @@ void __init r8a7740_add_standard_devices(void)
{ "A3SP", &scif7_device },
{ "A3SP", &scif8_device },
{ "A3SP", &i2c1_device },
+ { "A3SP", &ipmmu_device },
+ { "A3SP", &dma0_device },
+ { "A3SP", &dma1_device },
+ { "A3SP", &dma2_device },
+ { "A3SP", &usb_dma_device },
};
/* I2C work-around */
diff --git a/arch/arm/mach-shmobile/setup-r8a7778.c b/arch/arm/mach-shmobile/setup-r8a7778.c
index 85fe016..170bd14 100644
--- a/arch/arm/mach-shmobile/setup-r8a7778.c
+++ b/arch/arm/mach-shmobile/setup-r8a7778.c
@@ -13,10 +13,6 @@
* but WITHOUT 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>
@@ -292,8 +288,6 @@ void __init r8a7778_add_dt_devices(void)
l2x0_init(base, 0x00400000, 0xc20f0fff);
}
#endif
-
- r8a7778_register_tmu(0);
}
/* HPB-DMA */
@@ -501,6 +495,7 @@ static void __init r8a7778_register_hpb_dmae(void)
void __init r8a7778_add_standard_devices(void)
{
r8a7778_add_dt_devices();
+ r8a7778_register_tmu(0);
r8a7778_register_scif(0);
r8a7778_register_scif(1);
r8a7778_register_scif(2);
@@ -572,11 +567,6 @@ void __init r8a7778_init_irq_extpin(int irlm)
&irqpin_platform_data, sizeof(irqpin_platform_data));
}
-void __init r8a7778_init_delay(void)
-{
- shmobile_init_delay();
-}
-
#ifdef CONFIG_USE_OF
#define INT2SMSKCR0 0x82288 /* 0xfe782288 */
#define INT2SMSKCR1 0x8228c /* 0xfe78228c */
@@ -608,7 +598,7 @@ static const char *r8a7778_compat_dt[] __initdata = {
};
DT_MACHINE_START(R8A7778_DT, "Generic R8A7778 (Flattened Device Tree)")
- .init_early = r8a7778_init_delay,
+ .init_early = shmobile_init_delay,
.init_irq = r8a7778_init_irq_dt,
.init_late = shmobile_init_late,
.dt_compat = r8a7778_compat_dt,
diff --git a/arch/arm/mach-shmobile/setup-r8a7779.c b/arch/arm/mach-shmobile/setup-r8a7779.c
index 136078a..6156d17 100644
--- a/arch/arm/mach-shmobile/setup-r8a7779.c
+++ b/arch/arm/mach-shmobile/setup-r8a7779.c
@@ -13,10 +13,6 @@
* but WITHOUT 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/init.h>
@@ -52,14 +48,14 @@
#include "r8a7779.h"
static struct map_desc r8a7779_io_desc[] __initdata = {
- /* 2M entity map for 0xf0000000 (MPCORE) */
+ /* 2M identity mapping for 0xf0000000 (MPCORE) */
{
.virtual = 0xf0000000,
.pfn = __phys_to_pfn(0xf0000000),
.length = SZ_2M,
.type = MT_DEVICE_NONSHARED
},
- /* 16M entity map for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
+ /* 16M identity mapping for 0xfexxxxxx (DMAC-S/HPBREG/INTC2/LRAM/DBSC) */
{
.virtual = 0xfe000000,
.pfn = __phys_to_pfn(0xfe000000),
@@ -70,6 +66,7 @@ static struct map_desc r8a7779_io_desc[] __initdata = {
void __init r8a7779_map_io(void)
{
+ debug_ll_io_init();
iotable_init(r8a7779_io_desc, ARRAY_SIZE(r8a7779_io_desc));
}
@@ -683,7 +680,7 @@ void __init r8a7779_add_early_devices(void)
/* Early serial console setup is not included here due to
* memory map collisions. The SCIF serial ports in r8a7779
- * are difficult to entity map 1:1 due to collision with the
+ * are difficult to identity map 1:1 due to collision with the
* virtual memory range used by the coherent DMA code on ARM.
*
* Anyone wanting to debug early can remove UPF_IOREMAP from
diff --git a/arch/arm/mach-shmobile/setup-r8a7790.c b/arch/arm/mach-shmobile/setup-r8a7790.c
index 877fdeb..ec7d97d 100644
--- a/arch/arm/mach-shmobile/setup-r8a7790.c
+++ b/arch/arm/mach-shmobile/setup-r8a7790.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/irq.h>
diff --git a/arch/arm/mach-shmobile/setup-r8a7791.c b/arch/arm/mach-shmobile/setup-r8a7791.c
index 35d7863..ef8eb3a 100644
--- a/arch/arm/mach-shmobile/setup-r8a7791.c
+++ b/arch/arm/mach-shmobile/setup-r8a7791.c
@@ -13,198 +13,16 @@
* but WITHOUT 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/irq.h>
-#include <linux/kernel.h>
-#include <linux/of_platform.h>
-#include <linux/platform_data/gpio-rcar.h>
-#include <linux/platform_data/irq-renesas-irqc.h>
-#include <linux/serial_sci.h>
-#include <linux/sh_timer.h>
+#include <linux/init.h>
#include <asm/mach/arch.h>
#include "common.h"
-#include "irqs.h"
#include "r8a7791.h"
#include "rcar-gen2.h"
-static const struct resource pfc_resources[] __initconst = {
- DEFINE_RES_MEM(0xe6060000, 0x250),
-};
-
-#define r8a7791_register_pfc() \
- platform_device_register_simple("pfc-r8a7791", -1, pfc_resources, \
- ARRAY_SIZE(pfc_resources))
-
-#define R8A7791_GPIO(idx, base, nr) \
-static const struct resource r8a7791_gpio##idx##_resources[] __initconst = { \
- DEFINE_RES_MEM((base), 0x50), \
- DEFINE_RES_IRQ(gic_spi(4 + (idx))), \
-}; \
- \
-static const struct gpio_rcar_config \
-r8a7791_gpio##idx##_platform_data __initconst = { \
- .gpio_base = 32 * (idx), \
- .irq_base = 0, \
- .number_of_pins = (nr), \
- .pctl_name = "pfc-r8a7791", \
- .has_both_edge_trigger = 1, \
-}; \
-
-R8A7791_GPIO(0, 0xe6050000, 32);
-R8A7791_GPIO(1, 0xe6051000, 32);
-R8A7791_GPIO(2, 0xe6052000, 32);
-R8A7791_GPIO(3, 0xe6053000, 32);
-R8A7791_GPIO(4, 0xe6054000, 32);
-R8A7791_GPIO(5, 0xe6055000, 32);
-R8A7791_GPIO(6, 0xe6055400, 32);
-R8A7791_GPIO(7, 0xe6055800, 26);
-
-#define r8a7791_register_gpio(idx) \
- platform_device_register_resndata(NULL, "gpio_rcar", idx, \
- r8a7791_gpio##idx##_resources, \
- ARRAY_SIZE(r8a7791_gpio##idx##_resources), \
- &r8a7791_gpio##idx##_platform_data, \
- sizeof(r8a7791_gpio##idx##_platform_data))
-
-void __init r8a7791_pinmux_init(void)
-{
- r8a7791_register_pfc();
- r8a7791_register_gpio(0);
- r8a7791_register_gpio(1);
- r8a7791_register_gpio(2);
- r8a7791_register_gpio(3);
- r8a7791_register_gpio(4);
- r8a7791_register_gpio(5);
- r8a7791_register_gpio(6);
- r8a7791_register_gpio(7);
-}
-
-#define __R8A7791_SCIF(scif_type, index, baseaddr, irq) \
-static struct plat_sci_port scif##index##_platform_data = { \
- .type = scif_type, \
- .flags = UPF_BOOT_AUTOCONF | UPF_IOREMAP, \
- .scscr = SCSCR_RE | SCSCR_TE, \
-}; \
- \
-static struct resource scif##index##_resources[] = { \
- DEFINE_RES_MEM(baseaddr, 0x100), \
- DEFINE_RES_IRQ(irq), \
-}
-
-#define R8A7791_SCIF(index, baseaddr, irq) \
- __R8A7791_SCIF(PORT_SCIF, index, baseaddr, irq)
-
-#define R8A7791_SCIFA(index, baseaddr, irq) \
- __R8A7791_SCIF(PORT_SCIFA, index, baseaddr, irq)
-
-#define R8A7791_SCIFB(index, baseaddr, irq) \
- __R8A7791_SCIF(PORT_SCIFB, index, baseaddr, irq)
-
-R8A7791_SCIFA(0, 0xe6c40000, gic_spi(144)); /* SCIFA0 */
-R8A7791_SCIFA(1, 0xe6c50000, gic_spi(145)); /* SCIFA1 */
-R8A7791_SCIFB(2, 0xe6c20000, gic_spi(148)); /* SCIFB0 */
-R8A7791_SCIFB(3, 0xe6c30000, gic_spi(149)); /* SCIFB1 */
-R8A7791_SCIFB(4, 0xe6ce0000, gic_spi(150)); /* SCIFB2 */
-R8A7791_SCIFA(5, 0xe6c60000, gic_spi(151)); /* SCIFA2 */
-R8A7791_SCIF(6, 0xe6e60000, gic_spi(152)); /* SCIF0 */
-R8A7791_SCIF(7, 0xe6e68000, gic_spi(153)); /* SCIF1 */
-R8A7791_SCIF(8, 0xe6e58000, gic_spi(22)); /* SCIF2 */
-R8A7791_SCIF(9, 0xe6ea8000, gic_spi(23)); /* SCIF3 */
-R8A7791_SCIF(10, 0xe6ee0000, gic_spi(24)); /* SCIF4 */
-R8A7791_SCIF(11, 0xe6ee8000, gic_spi(25)); /* SCIF5 */
-R8A7791_SCIFA(12, 0xe6c70000, gic_spi(29)); /* SCIFA3 */
-R8A7791_SCIFA(13, 0xe6c78000, gic_spi(30)); /* SCIFA4 */
-R8A7791_SCIFA(14, 0xe6c80000, gic_spi(31)); /* SCIFA5 */
-
-#define r8a7791_register_scif(index) \
- platform_device_register_resndata(NULL, "sh-sci", index, \
- scif##index##_resources, \
- ARRAY_SIZE(scif##index##_resources), \
- &scif##index##_platform_data, \
- sizeof(scif##index##_platform_data))
-
-static struct sh_timer_config cmt0_platform_data = {
- .channels_mask = 0x60,
-};
-
-static struct resource cmt0_resources[] = {
- DEFINE_RES_MEM(0xffca0000, 0x1004),
- DEFINE_RES_IRQ(gic_spi(142)),
-};
-
-#define r8a7791_register_cmt(idx) \
- platform_device_register_resndata(NULL, "sh-cmt-48-gen2", \
- idx, cmt##idx##_resources, \
- ARRAY_SIZE(cmt##idx##_resources), \
- &cmt##idx##_platform_data, \
- sizeof(struct sh_timer_config))
-
-static struct renesas_irqc_config irqc0_data = {
- .irq_base = irq_pin(0), /* IRQ0 -> IRQ9 */
-};
-
-static struct resource irqc0_resources[] = {
- DEFINE_RES_MEM(0xe61c0000, 0x200), /* IRQC Event Detector Block_0 */
- DEFINE_RES_IRQ(gic_spi(0)), /* IRQ0 */
- DEFINE_RES_IRQ(gic_spi(1)), /* IRQ1 */
- DEFINE_RES_IRQ(gic_spi(2)), /* IRQ2 */
- DEFINE_RES_IRQ(gic_spi(3)), /* IRQ3 */
- DEFINE_RES_IRQ(gic_spi(12)), /* IRQ4 */
- DEFINE_RES_IRQ(gic_spi(13)), /* IRQ5 */
- DEFINE_RES_IRQ(gic_spi(14)), /* IRQ6 */
- DEFINE_RES_IRQ(gic_spi(15)), /* IRQ7 */
- DEFINE_RES_IRQ(gic_spi(16)), /* IRQ8 */
- DEFINE_RES_IRQ(gic_spi(17)), /* IRQ9 */
-};
-
-#define r8a7791_register_irqc(idx) \
- platform_device_register_resndata(NULL, "renesas_irqc", \
- idx, irqc##idx##_resources, \
- ARRAY_SIZE(irqc##idx##_resources), \
- &irqc##idx##_data, \
- sizeof(struct renesas_irqc_config))
-
-static const struct resource thermal_resources[] __initconst = {
- DEFINE_RES_MEM(0xe61f0000, 0x14),
- DEFINE_RES_MEM(0xe61f0100, 0x38),
- DEFINE_RES_IRQ(gic_spi(69)),
-};
-
-#define r8a7791_register_thermal() \
- platform_device_register_simple("rcar_thermal", -1, \
- thermal_resources, \
- ARRAY_SIZE(thermal_resources))
-
-void __init r8a7791_add_standard_devices(void)
-{
- r8a7791_register_scif(0);
- r8a7791_register_scif(1);
- r8a7791_register_scif(2);
- r8a7791_register_scif(3);
- r8a7791_register_scif(4);
- r8a7791_register_scif(5);
- r8a7791_register_scif(6);
- r8a7791_register_scif(7);
- r8a7791_register_scif(8);
- r8a7791_register_scif(9);
- r8a7791_register_scif(10);
- r8a7791_register_scif(11);
- r8a7791_register_scif(12);
- r8a7791_register_scif(13);
- r8a7791_register_scif(14);
- r8a7791_register_cmt(0);
- r8a7791_register_irqc(0);
- r8a7791_register_thermal();
-}
-
-#ifdef CONFIG_USE_OF
static const char *r8a7791_boards_compat_dt[] __initdata = {
"renesas,r8a7791",
NULL,
@@ -218,4 +36,3 @@ DT_MACHINE_START(R8A7791_DT, "Generic R8A7791 (Flattened Device Tree)")
.reserve = rcar_gen2_reserve,
.dt_compat = r8a7791_boards_compat_dt,
MACHINE_END
-#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/setup-rcar-gen2.c b/arch/arm/mach-shmobile/setup-rcar-gen2.c
index 42d5b43..3dd6edd 100644
--- a/arch/arm/mach-shmobile/setup-rcar-gen2.c
+++ b/arch/arm/mach-shmobile/setup-rcar-gen2.c
@@ -3,6 +3,7 @@
*
* Copyright (C) 2013 Renesas Solutions Corp.
* Copyright (C) 2013 Magnus Damm
+ * Copyright (C) 2014 Ulrich Hecht
*
* 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
@@ -12,10 +13,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
#include <linux/clk/shmobile.h>
@@ -24,6 +21,7 @@
#include <linux/dma-contiguous.h>
#include <linux/io.h>
#include <linux/kernel.h>
+#include <linux/of.h>
#include <linux/of_fdt.h>
#include <asm/mach/arch.h>
#include "common.h"
@@ -54,37 +52,61 @@ void __init rcar_gen2_timer_init(void)
{
#if defined(CONFIG_ARM_ARCH_TIMER) || defined(CONFIG_COMMON_CLK)
u32 mode = rcar_gen2_read_mode_pins();
+ bool is_e2 = (bool)of_find_compatible_node(NULL, NULL,
+ "renesas,r8a7794");
#endif
#ifdef CONFIG_ARM_ARCH_TIMER
void __iomem *base;
int extal_mhz = 0;
u32 freq;
- /* At Linux boot time the r8a7790 arch timer comes up
- * with the counter disabled. Moreover, it may also report
- * a potentially incorrect fixed 13 MHz frequency. To be
- * correct these registers need to be updated to use the
- * frequency EXTAL / 2 which can be determined by the MD pins.
- */
-
- switch (mode & (MD(14) | MD(13))) {
- case 0:
- extal_mhz = 15;
- break;
- case MD(13):
- extal_mhz = 20;
- break;
- case MD(14):
- extal_mhz = 26;
- break;
- case MD(13) | MD(14):
- extal_mhz = 30;
- break;
+ if (is_e2) {
+ freq = 260000000 / 8; /* ZS / 8 */
+ /* CNTVOFF has to be initialized either from non-secure
+ * Hypervisor mode or secure Monitor mode with SCR.NS==1.
+ * If TrustZone is enabled then it should be handled by the
+ * secure code.
+ */
+ asm volatile(
+ " cps 0x16\n"
+ " mrc p15, 0, r1, c1, c1, 0\n"
+ " orr r0, r1, #1\n"
+ " mcr p15, 0, r0, c1, c1, 0\n"
+ " isb\n"
+ " mov r0, #0\n"
+ " mcrr p15, 4, r0, r0, c14\n"
+ " isb\n"
+ " mcr p15, 0, r1, c1, c1, 0\n"
+ " isb\n"
+ " cps 0x13\n"
+ : : : "r0", "r1");
+ } else {
+ /* At Linux boot time the r8a7790 arch timer comes up
+ * with the counter disabled. Moreover, it may also report
+ * a potentially incorrect fixed 13 MHz frequency. To be
+ * correct these registers need to be updated to use the
+ * frequency EXTAL / 2 which can be determined by the MD pins.
+ */
+
+ switch (mode & (MD(14) | MD(13))) {
+ case 0:
+ extal_mhz = 15;
+ break;
+ case MD(13):
+ extal_mhz = 20;
+ break;
+ case MD(14):
+ extal_mhz = 26;
+ break;
+ case MD(13) | MD(14):
+ extal_mhz = 30;
+ break;
+ }
+
+ /* The arch timer frequency equals EXTAL / 2 */
+ freq = extal_mhz * (1000000 / 2);
}
- /* The arch timer frequency equals EXTAL / 2 */
- freq = extal_mhz * (1000000 / 2);
-
/* Remap "armgcnt address map" space */
base = ioremap(0xe6080000, PAGE_SIZE);
diff --git a/arch/arm/mach-shmobile/setup-sh7372.c b/arch/arm/mach-shmobile/setup-sh7372.c
index d646c8d..458a2cf 100644
--- a/arch/arm/mach-shmobile/setup-sh7372.c
+++ b/arch/arm/mach-shmobile/setup-sh7372.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/init.h>
@@ -47,7 +43,7 @@
#include "sh7372.h"
static struct map_desc sh7372_io_desc[] __initdata = {
- /* create a 1:1 entity map for 0xe6xxxxxx
+ /* create a 1:1 identity mapping for 0xe6xxxxxx
* used by CPGA, INTC and PFC.
*/
{
@@ -60,6 +56,7 @@ static struct map_desc sh7372_io_desc[] __initdata = {
void __init sh7372_map_io(void)
{
+ debug_ll_io_init();
iotable_init(sh7372_io_desc, ARRAY_SIZE(sh7372_io_desc));
}
@@ -1012,6 +1009,7 @@ DT_MACHINE_START(SH7372_DT, "Generic SH7372 (Flattened Device Tree)")
.init_irq = sh7372_init_irq,
.handle_irq = shmobile_handle_irq_intc,
.init_machine = sh7372_add_standard_devices_dt,
+ .init_late = shmobile_init_late,
.dt_compat = sh7372_boards_compat_dt,
MACHINE_END
diff --git a/arch/arm/mach-shmobile/setup-sh73a0.c b/arch/arm/mach-shmobile/setup-sh73a0.c
index 328657d..93ebe34 100644
--- a/arch/arm/mach-shmobile/setup-sh73a0.c
+++ b/arch/arm/mach-shmobile/setup-sh73a0.c
@@ -13,10 +13,6 @@
* but WITHOUT 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/init.h>
@@ -46,7 +42,7 @@
#include "sh73a0.h"
static struct map_desc sh73a0_io_desc[] __initdata = {
- /* create a 1:1 entity map for 0xe6xxxxxx
+ /* create a 1:1 identity mapping for 0xe6xxxxxx
* used by CPGA, INTC and PFC.
*/
{
@@ -59,6 +55,7 @@ static struct map_desc sh73a0_io_desc[] __initdata = {
void __init sh73a0_map_io(void)
{
+ debug_ll_io_init();
iotable_init(sh73a0_io_desc, ARRAY_SIZE(sh73a0_io_desc));
}
@@ -760,17 +757,12 @@ void __init sh73a0_add_standard_devices(void)
ARRAY_SIZE(sh73a0_late_devices));
}
-void __init sh73a0_init_delay(void)
-{
- shmobile_init_delay();
-}
-
/* do nothing for !CONFIG_SMP or !CONFIG_HAVE_TWD */
void __init __weak sh73a0_register_twd(void) { }
void __init sh73a0_earlytimer_init(void)
{
- sh73a0_init_delay();
+ shmobile_init_delay();
sh73a0_clock_init();
shmobile_earlytimer_init();
sh73a0_register_twd();
@@ -795,6 +787,13 @@ void __init sh73a0_add_standard_devices_dt(void)
of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
}
+#define RESCNT2 IOMEM(0xe6188020)
+static void sh73a0_restart(enum reboot_mode mode, const char *cmd)
+{
+ /* Do soft power on reset */
+ writel((1 << 31), RESCNT2);
+}
+
static const char *sh73a0_boards_compat_dt[] __initdata = {
"renesas,sh73a0",
NULL,
@@ -803,9 +802,10 @@ static const char *sh73a0_boards_compat_dt[] __initdata = {
DT_MACHINE_START(SH73A0_DT, "Generic SH73A0 (Flattened Device Tree)")
.smp = smp_ops(sh73a0_smp_ops),
.map_io = sh73a0_map_io,
- .init_early = sh73a0_init_delay,
+ .init_early = shmobile_init_delay,
.init_machine = sh73a0_add_standard_devices_dt,
.init_late = shmobile_init_late,
+ .restart = sh73a0_restart,
.dt_compat = sh73a0_boards_compat_dt,
MACHINE_END
#endif /* CONFIG_USE_OF */
diff --git a/arch/arm/mach-shmobile/sh73a0.h b/arch/arm/mach-shmobile/sh73a0.h
index 359b582..f037c64 100644
--- a/arch/arm/mach-shmobile/sh73a0.h
+++ b/arch/arm/mach-shmobile/sh73a0.h
@@ -71,7 +71,6 @@ enum {
#define SH73A0_PINT0_IRQ(irq) ((irq) + 700)
#define SH73A0_PINT1_IRQ(irq) ((irq) + 732)
-extern void sh73a0_init_delay(void);
extern void sh73a0_init_irq(void);
extern void sh73a0_init_irq_dt(void);
extern void sh73a0_map_io(void);
diff --git a/arch/arm/mach-shmobile/sleep-sh7372.S b/arch/arm/mach-shmobile/sleep-sh7372.S
index 9782862..146b8de 100644
--- a/arch/arm/mach-shmobile/sleep-sh7372.S
+++ b/arch/arm/mach-shmobile/sleep-sh7372.S
@@ -22,11 +22,6 @@
* but WITHOUT 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/linkage.h>
diff --git a/arch/arm/mach-shmobile/smp-emev2.c b/arch/arm/mach-shmobile/smp-emev2.c
index 6ff1df1..baff3b5 100644
--- a/arch/arm/mach-shmobile/smp-emev2.c
+++ b/arch/arm/mach-shmobile/smp-emev2.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/smp-r8a7779.c b/arch/arm/mach-shmobile/smp-r8a7779.c
index 3100e35..3f761f8 100644
--- a/arch/arm/mach-shmobile/smp-r8a7779.c
+++ b/arch/arm/mach-shmobile/smp-r8a7779.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/smp-r8a7790.c b/arch/arm/mach-shmobile/smp-r8a7790.c
index 2311694..9c3da13 100644
--- a/arch/arm/mach-shmobile/smp-r8a7790.c
+++ b/arch/arm/mach-shmobile/smp-r8a7790.c
@@ -21,6 +21,7 @@
#include <asm/smp_plat.h>
#include "common.h"
+#include "platsmp-apmu.h"
#include "pm-rcar.h"
#include "r8a7790.h"
@@ -34,10 +35,23 @@ static struct rcar_sysc_ch r8a7790_ca7_scu = {
.isr_bit = 21, /* CA7-SCU */
};
+static struct rcar_apmu_config r8a7790_apmu_config[] = {
+ {
+ .iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
+ .cpus = { 0, 1, 2, 3 },
+ },
+ {
+ .iomem = DEFINE_RES_MEM(0xe6151000, 0x88),
+ .cpus = { 0x100, 0x0101, 0x102, 0x103 },
+ }
+};
+
static void __init r8a7790_smp_prepare_cpus(unsigned int max_cpus)
{
/* let APMU code install data related to shmobile_boot_vector */
- shmobile_smp_apmu_prepare_cpus(max_cpus);
+ shmobile_smp_apmu_prepare_cpus(max_cpus,
+ r8a7790_apmu_config,
+ ARRAY_SIZE(r8a7790_apmu_config));
/* turn on power to SCU */
r8a7790_pm_init();
diff --git a/arch/arm/mach-shmobile/smp-r8a7791.c b/arch/arm/mach-shmobile/smp-r8a7791.c
index f743386..7e49e0a 100644
--- a/arch/arm/mach-shmobile/smp-r8a7791.c
+++ b/arch/arm/mach-shmobile/smp-r8a7791.c
@@ -21,13 +21,23 @@
#include <asm/smp_plat.h>
#include "common.h"
+#include "platsmp-apmu.h"
#include "r8a7791.h"
#include "rcar-gen2.h"
+static struct rcar_apmu_config r8a7791_apmu_config[] = {
+ {
+ .iomem = DEFINE_RES_MEM(0xe6152000, 0x88),
+ .cpus = { 0, 1 },
+ }
+};
+
static void __init r8a7791_smp_prepare_cpus(unsigned int max_cpus)
{
/* let APMU code install data related to shmobile_boot_vector */
- shmobile_smp_apmu_prepare_cpus(max_cpus);
+ shmobile_smp_apmu_prepare_cpus(max_cpus,
+ r8a7791_apmu_config,
+ ARRAY_SIZE(r8a7791_apmu_config));
r8a7791_pm_init();
}
diff --git a/arch/arm/mach-shmobile/smp-sh73a0.c b/arch/arm/mach-shmobile/smp-sh73a0.c
index 22d8f87..c16dbfe 100644
--- a/arch/arm/mach-shmobile/smp-sh73a0.c
+++ b/arch/arm/mach-shmobile/smp-sh73a0.c
@@ -12,10 +12,6 @@
* but WITHOUT 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/init.h>
diff --git a/arch/arm/mach-shmobile/timer.c b/arch/arm/mach-shmobile/timer.c
index 87c6be1..f1d027a 100644
--- a/arch/arm/mach-shmobile/timer.c
+++ b/arch/arm/mach-shmobile/timer.c
@@ -12,11 +12,6 @@
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
- *
*/
#include <linux/platform_device.h>
#include <linux/clocksource.h>
@@ -45,6 +40,7 @@ void __init shmobile_init_delay(void)
struct device_node *np, *cpus;
bool is_a7_a8_a9 = false;
bool is_a15 = false;
+ bool has_arch_timer = false;
u32 max_freq = 0;
cpus = of_find_node_by_path("/cpus");
@@ -57,12 +53,16 @@ void __init shmobile_init_delay(void)
if (!of_property_read_u32(np, "clock-frequency", &freq))
max_freq = max(max_freq, freq);
- if (of_device_is_compatible(np, "arm,cortex-a7") ||
- of_device_is_compatible(np, "arm,cortex-a8") ||
- of_device_is_compatible(np, "arm,cortex-a9"))
+ if (of_device_is_compatible(np, "arm,cortex-a8") ||
+ of_device_is_compatible(np, "arm,cortex-a9")) {
is_a7_a8_a9 = true;
- else if (of_device_is_compatible(np, "arm,cortex-a15"))
+ } else if (of_device_is_compatible(np, "arm,cortex-a7")) {
+ is_a7_a8_a9 = true;
+ has_arch_timer = true;
+ } else if (of_device_is_compatible(np, "arm,cortex-a15")) {
is_a15 = true;
+ has_arch_timer = true;
+ }
}
of_node_put(cpus);
@@ -70,10 +70,12 @@ void __init shmobile_init_delay(void)
if (!max_freq)
return;
- if (is_a7_a8_a9)
- shmobile_setup_delay_hz(max_freq, 1, 3);
- else if (is_a15 && !IS_ENABLED(CONFIG_ARM_ARCH_TIMER))
- shmobile_setup_delay_hz(max_freq, 2, 4);
+ if (!has_arch_timer || !IS_ENABLED(CONFIG_ARM_ARCH_TIMER)) {
+ if (is_a7_a8_a9)
+ shmobile_setup_delay_hz(max_freq, 1, 3);
+ else if (is_a15)
+ shmobile_setup_delay_hz(max_freq, 2, 4);
+ }
}
static void __init shmobile_late_time_init(void)
diff --git a/arch/arm/mach-socfpga/core.h b/arch/arm/mach-socfpga/core.h
index 60c443d..483cb46 100644
--- a/arch/arm/mach-socfpga/core.h
+++ b/arch/arm/mach-socfpga/core.h
@@ -21,6 +21,7 @@
#define __MACH_CORE_H
#define SOCFPGA_RSTMGR_CTRL 0x04
+#define SOCFPGA_RSTMGR_MODMPURST 0x10
#define SOCFPGA_RSTMGR_MODPERRST 0x14
#define SOCFPGA_RSTMGR_BRGMODRST 0x1c
@@ -28,6 +29,8 @@
#define RSTMGR_CTRL_SWCOLDRSTREQ 0x1 /* Cold Reset */
#define RSTMGR_CTRL_SWWARMRSTREQ 0x2 /* Warm Reset */
+#define RSTMGR_MPUMODRST_CPU1 0x2 /* CPU1 Reset */
+
extern void socfpga_secondary_startup(void);
extern void __iomem *socfpga_scu_base_addr;
diff --git a/arch/arm/mach-socfpga/platsmp.c b/arch/arm/mach-socfpga/platsmp.c
index 16ca97b..c64d89b 100644
--- a/arch/arm/mach-socfpga/platsmp.c
+++ b/arch/arm/mach-socfpga/platsmp.c
@@ -34,17 +34,21 @@ static int socfpga_boot_secondary(unsigned int cpu, struct task_struct *idle)
int trampoline_size = &secondary_trampoline_end - &secondary_trampoline;
if (socfpga_cpu1start_addr) {
+ /* This will put CPU #1 into reset. */
+ writel(RSTMGR_MPUMODRST_CPU1,
+ rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
+
memcpy(phys_to_virt(0), &secondary_trampoline, trampoline_size);
- __raw_writel(virt_to_phys(socfpga_secondary_startup),
- (sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff)));
+ writel(virt_to_phys(socfpga_secondary_startup),
+ sys_manager_base_addr + (socfpga_cpu1start_addr & 0x000000ff));
flush_cache_all();
smp_wmb();
outer_clean_range(0, trampoline_size);
- /* This will release CPU #1 out of reset.*/
- __raw_writel(0, rst_manager_base_addr + 0x10);
+ /* This will release CPU #1 out of reset. */
+ writel(0, rst_manager_base_addr + SOCFPGA_RSTMGR_MODMPURST);
}
return 0;
@@ -86,10 +90,9 @@ static void __init socfpga_smp_prepare_cpus(unsigned int max_cpus)
*/
static void socfpga_cpu_die(unsigned int cpu)
{
- cpu_do_idle();
-
- /* We should have never returned from idle */
- panic("cpu %d unexpectedly exit from shutdown\n", cpu);
+ /* Do WFI. If we wake up early, go back into WFI */
+ while (1)
+ cpu_do_idle();
}
struct smp_operations socfpga_smp_ops __initdata = {
diff --git a/arch/arm/mach-sti/Kconfig b/arch/arm/mach-sti/Kconfig
index 878e9ec..8825bc9 100644
--- a/arch/arm/mach-sti/Kconfig
+++ b/arch/arm/mach-sti/Kconfig
@@ -42,4 +42,14 @@ config SOC_STIH416
and other digital audio/video applications using Flattened Device
Trees.
+config SOC_STIH407
+ bool "STiH407 STMicroelectronics Consumer Electronics family"
+ default y
+ select STIH407_RESET
+ help
+ This enables support for STMicroelectronics Digital Consumer
+ Electronics family StiH407 parts, targetted at set-top-box
+ and other digital audio/video applications using Flattened Device
+ Trees.
+
endif
diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index 1aaa1e1..a77604f 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -42,4 +42,11 @@ config MACH_SUN8I
select MFD_SUN6I_PRCM
select RESET_CONTROLLER
+config MACH_SUN9I
+ bool "Allwinner (sun9i) SoCs support"
+ default ARCH_SUNXI
+ select ARCH_HAS_RESET_CONTROLLER
+ select ARM_GIC
+ select RESET_CONTROLLER
+
endif
diff --git a/arch/arm/mach-sunxi/platsmp.c b/arch/arm/mach-sunxi/platsmp.c
index c53077b..e44d028 100644
--- a/arch/arm/mach-sunxi/platsmp.c
+++ b/arch/arm/mach-sunxi/platsmp.c
@@ -116,7 +116,7 @@ static int sun6i_smp_boot_secondary(unsigned int cpu,
return 0;
}
-struct smp_operations sun6i_smp_ops __initdata = {
+static struct smp_operations sun6i_smp_ops __initdata = {
.smp_prepare_cpus = sun6i_smp_prepare_cpus,
.smp_boot_secondary = sun6i_smp_boot_secondary,
};
diff --git a/arch/arm/mach-sunxi/sunxi.c b/arch/arm/mach-sunxi/sunxi.c
index d7598ae..1f98675 100644
--- a/arch/arm/mach-sunxi/sunxi.c
+++ b/arch/arm/mach-sunxi/sunxi.c
@@ -63,3 +63,12 @@ static const char * const sun8i_board_dt_compat[] = {
DT_MACHINE_START(SUN8I_DT, "Allwinner sun8i (A23) Family")
.dt_compat = sun8i_board_dt_compat,
MACHINE_END
+
+static const char * const sun9i_board_dt_compat[] = {
+ "allwinner,sun9i-a80",
+ NULL,
+};
+
+DT_MACHINE_START(SUN9I_DT, "Allwinner sun9i Family")
+ .dt_compat = sun9i_board_dt_compat,
+MACHINE_END
diff --git a/arch/arm/mach-tegra/Kconfig b/arch/arm/mach-tegra/Kconfig
index 0953996..d0be9a1 100644
--- a/arch/arm/mach-tegra/Kconfig
+++ b/arch/arm/mach-tegra/Kconfig
@@ -2,6 +2,7 @@ menuconfig ARCH_TEGRA
bool "NVIDIA Tegra" if ARCH_MULTI_V7
select ARCH_REQUIRE_GPIOLIB
select ARCH_SUPPORTS_TRUSTED_FOUNDATIONS
+ select ARM_AMBA
select ARM_GIC
select CLKSRC_MMIO
select HAVE_ARM_SCU if SMP
@@ -59,12 +60,4 @@ config ARCH_TEGRA_124_SOC
Support for NVIDIA Tegra T124 processor family, based on the
ARM CortexA15MP CPU
-config TEGRA_AHB
- bool "Enable AHB driver for NVIDIA Tegra SoCs"
- default y
- help
- Adds AHB configuration functionality for NVIDIA Tegra SoCs,
- which controls AHB bus master arbitration and some
- performance parameters(priority, prefech size).
-
endif
diff --git a/arch/arm/mach-tegra/cpuidle-tegra114.c b/arch/arm/mach-tegra/cpuidle-tegra114.c
index e3ebdce..f2b586d 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra114.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra114.c
@@ -49,7 +49,7 @@ static int tegra114_idle_power_down(struct cpuidle_device *dev,
call_firmware_op(prepare_idle);
/* Do suspend by ourselves if the firmware does not implement it */
- if (call_firmware_op(do_idle) == -ENOSYS)
+ if (call_firmware_op(do_idle, 0) == -ENOSYS)
cpu_suspend(0, tegra30_sleep_cpu_secondary_finish);
clockevents_notify(CLOCK_EVT_NOTIFY_BROADCAST_EXIT, &dev->cpu);
@@ -75,7 +75,6 @@ static struct cpuidle_driver tegra_idle_driver = {
.exit_latency = 500,
.target_residency = 1000,
.power_usage = 0,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "powered-down",
.desc = "CPU power gated",
},
diff --git a/arch/arm/mach-tegra/cpuidle-tegra20.c b/arch/arm/mach-tegra/cpuidle-tegra20.c
index b30bf5c..4f25a7c 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra20.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra20.c
@@ -59,8 +59,7 @@ static struct cpuidle_driver tegra_idle_driver = {
.exit_latency = 5000,
.target_residency = 10000,
.power_usage = 0,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_COUPLED,
+ .flags = CPUIDLE_FLAG_COUPLED,
.name = "powered-down",
.desc = "CPU power gated",
},
diff --git a/arch/arm/mach-tegra/cpuidle-tegra30.c b/arch/arm/mach-tegra/cpuidle-tegra30.c
index 3556127..f8815ed 100644
--- a/arch/arm/mach-tegra/cpuidle-tegra30.c
+++ b/arch/arm/mach-tegra/cpuidle-tegra30.c
@@ -56,7 +56,6 @@ static struct cpuidle_driver tegra_idle_driver = {
.exit_latency = 2000,
.target_residency = 2200,
.power_usage = 0,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "powered-down",
.desc = "CPU power gated",
},
diff --git a/arch/arm/mach-tegra/reset-handler.S b/arch/arm/mach-tegra/reset-handler.S
index 7b2baab..71be4af 100644
--- a/arch/arm/mach-tegra/reset-handler.S
+++ b/arch/arm/mach-tegra/reset-handler.S
@@ -51,6 +51,7 @@ ENTRY(tegra_resume)
THUMB( it ne )
bne cpu_resume @ no
+ tegra_get_soc_id TEGRA_APB_MISC_BASE, r6
/* Are we on Tegra20? */
cmp r6, #TEGRA20
beq 1f @ Yes
diff --git a/arch/arm/mach-u300/dummyspichip.c b/arch/arm/mach-u300/dummyspichip.c
index ec0283c..1319968 100644
--- a/arch/arm/mach-u300/dummyspichip.c
+++ b/arch/arm/mach-u300/dummyspichip.c
@@ -80,8 +80,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 8bit mode\n");
status = spi_w8r8(spi, 0xAA);
if (status < 0)
- pr_warning("Siple test 1: FAILURE: spi_write_then_read "
- "failed with status %d\n", status);
+ pr_warn("Simple test 1: FAILURE: spi_write_then_read failed with status %d\n",
+ status);
else
pr_info("Simple test 1: SUCCESS!\n");
@@ -89,8 +89,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 8bit mode (full FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8);
if (status < 0)
- pr_warning("Simple test 2: FAILURE: spi_write_then_read() "
- "failed with status %d\n", status);
+ pr_warn("Simple test 2: FAILURE: spi_write_then_read() failed with status %d\n",
+ status);
else
pr_info("Simple test 2: SUCCESS!\n");
@@ -98,8 +98,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 8bit mode (see if we overflow FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14);
if (status < 0)
- pr_warning("Simple test 3: FAILURE: failed with status %d "
- "(probably FIFO overrun)\n", status);
+ pr_warn("Simple test 3: FAILURE: failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 3: SUCCESS!\n");
@@ -107,14 +107,14 @@ static ssize_t dummy_looptest(struct device *dev,
"bytes garbage with spi_read() in 8bit mode\n");
status = spi_write(spi, &txbuf[0], 8);
if (status < 0)
- pr_warning("Simple test 4 step 1: FAILURE: spi_write() "
- "failed with status %d\n", status);
+ pr_warn("Simple test 4 step 1: FAILURE: spi_write() failed with status %d\n",
+ status);
else
pr_info("Simple test 4 step 1: SUCCESS!\n");
status = spi_read(spi, &rxbuf[0], 8);
if (status < 0)
- pr_warning("Simple test 4 step 2: FAILURE: spi_read() "
- "failed with status %d\n", status);
+ pr_warn("Simple test 4 step 2: FAILURE: spi_read() failed with status %d\n",
+ status);
else
pr_info("Simple test 4 step 2: SUCCESS!\n");
@@ -122,16 +122,14 @@ static ssize_t dummy_looptest(struct device *dev,
"14 bytes garbage with spi_read() in 8bit mode\n");
status = spi_write(spi, &txbuf[0], 14);
if (status < 0)
- pr_warning("Simple test 5 step 1: FAILURE: spi_write() "
- "failed with status %d (probably FIFO overrun)\n",
- status);
+ pr_warn("Simple test 5 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 5 step 1: SUCCESS!\n");
status = spi_read(spi, &rxbuf[0], 14);
if (status < 0)
- pr_warning("Simple test 5 step 2: FAILURE: spi_read() "
- "failed with status %d (probably FIFO overrun)\n",
- status);
+ pr_warn("Simple test 5 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 5: SUCCESS!\n");
@@ -140,16 +138,14 @@ static ssize_t dummy_looptest(struct device *dev,
DMA_TEST_SIZE, DMA_TEST_SIZE);
status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0)
- pr_warning("Simple test 6 step 1: FAILURE: spi_write() "
- "failed with status %d (probably FIFO overrun)\n",
- status);
+ pr_warn("Simple test 6 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 6 step 1: SUCCESS!\n");
status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0)
- pr_warning("Simple test 6 step 2: FAILURE: spi_read() "
- "failed with status %d (probably FIFO overrun)\n",
- status);
+ pr_warn("Simple test 6 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 6: SUCCESS!\n");
@@ -169,18 +165,17 @@ static ssize_t dummy_looptest(struct device *dev,
pr_info("Simple test 7: SUCCESS! (expected failure with "
"status EIO)\n");
else if (status < 0)
- pr_warning("Siple test 7: FAILURE: spi_write_then_read "
- "failed with status %d\n", status);
+ pr_warn("Simple test 7: FAILURE: spi_write_then_read failed with status %d\n",
+ status);
else
- pr_warning("Siple test 7: FAILURE: spi_write_then_read "
- "succeeded but it was expected to fail!\n");
+ pr_warn("Simple test 7: FAILURE: spi_write_then_read succeeded but it was expected to fail!\n");
pr_info("Simple test 8: write 8 bytes, read back 8 bytes garbage "
"in 16bit mode (full FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 8, &rxbuf[0], 8);
if (status < 0)
- pr_warning("Simple test 8: FAILURE: spi_write_then_read() "
- "failed with status %d\n", status);
+ pr_warn("Simple test 8: FAILURE: spi_write_then_read() failed with status %d\n",
+ status);
else
pr_info("Simple test 8: SUCCESS!\n");
@@ -188,8 +183,8 @@ static ssize_t dummy_looptest(struct device *dev,
"in 16bit mode (see if we overflow FIFO)\n");
status = spi_write_then_read(spi, &txbuf[0], 14, &rxbuf[0], 14);
if (status < 0)
- pr_warning("Simple test 9: FAILURE: failed with status %d "
- "(probably FIFO overrun)\n", status);
+ pr_warn("Simple test 9: FAILURE: failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 9: SUCCESS!\n");
@@ -198,17 +193,15 @@ static ssize_t dummy_looptest(struct device *dev,
DMA_TEST_SIZE, DMA_TEST_SIZE);
status = spi_write(spi, &bigtxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0)
- pr_warning("Simple test 10 step 1: FAILURE: spi_write() "
- "failed with status %d (probably FIFO overrun)\n",
- status);
+ pr_warn("Simple test 10 step 1: FAILURE: spi_write() failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 10 step 1: SUCCESS!\n");
status = spi_read(spi, &bigrxbuf_virtual[0], DMA_TEST_SIZE);
if (status < 0)
- pr_warning("Simple test 10 step 2: FAILURE: spi_read() "
- "failed with status %d (probably FIFO overrun)\n",
- status);
+ pr_warn("Simple test 10 step 2: FAILURE: spi_read() failed with status %d (probably FIFO overrun)\n",
+ status);
else
pr_info("Simple test 10: SUCCESS!\n");
diff --git a/arch/arm/mach-ux500/Kconfig b/arch/arm/mach-ux500/Kconfig
index 699e860..c9ac19b 100644
--- a/arch/arm/mach-ux500/Kconfig
+++ b/arch/arm/mach-ux500/Kconfig
@@ -32,6 +32,7 @@ config UX500_SOC_DB8500
select PINCTRL_AB8540
select REGULATOR
select REGULATOR_DB8500_PRCMU
+ select PM_GENERIC_DOMAINS if PM
config MACH_MOP500
bool "U8500 Development platform, MOP500 versions"
diff --git a/arch/arm/mach-ux500/Makefile b/arch/arm/mach-ux500/Makefile
index 9741de95..4418a50 100644
--- a/arch/arm/mach-ux500/Makefile
+++ b/arch/arm/mach-ux500/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_MACH_MOP500) += board-mop500-regulators.o \
board-mop500-audio.o
obj-$(CONFIG_SMP) += platsmp.o headsmp.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug.o
+obj-$(CONFIG_PM_GENERIC_DOMAINS) += pm_domains.o
CFLAGS_hotplug.o += -march=armv7-a
diff --git a/arch/arm/mach-ux500/pm.c b/arch/arm/mach-ux500/pm.c
index b80a9a2..2cb587b 100644
--- a/arch/arm/mach-ux500/pm.c
+++ b/arch/arm/mach-ux500/pm.c
@@ -17,6 +17,7 @@
#include <linux/platform_data/arm-ux500-pm.h>
#include "db8500-regs.h"
+#include "pm_domains.h"
/* ARM WFI Standby signal register */
#define PRCM_ARM_WFI_STANDBY (prcmu_base + 0x130)
@@ -191,4 +192,7 @@ void __init ux500_pm_init(u32 phy_base, u32 size)
/* Set up ux500 suspend callbacks. */
suspend_set_ops(UX500_SUSPEND_OPS);
+
+ /* Initialize ux500 power domains */
+ ux500_pm_domains_init();
}
diff --git a/arch/arm/mach-ux500/pm_domains.c b/arch/arm/mach-ux500/pm_domains.c
new file mode 100644
index 0000000..0d4b5b4
--- /dev/null
+++ b/arch/arm/mach-ux500/pm_domains.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ * License terms: GNU General Public License (GPL) version 2
+ *
+ * Implements PM domains using the generic PM domain for ux500.
+ */
+#include <linux/printk.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+#include <linux/of.h>
+#include <linux/pm_domain.h>
+
+#include <dt-bindings/arm/ux500_pm_domains.h>
+#include "pm_domains.h"
+
+static int pd_power_off(struct generic_pm_domain *domain)
+{
+ /*
+ * Handle the gating of the PM domain regulator here.
+ *
+ * Drivers/subsystems handling devices in the PM domain needs to perform
+ * register context save/restore from their respective runtime PM
+ * callbacks, to be able to enable PM domain gating/ungating.
+ */
+ return 0;
+}
+
+static int pd_power_on(struct generic_pm_domain *domain)
+{
+ /*
+ * Handle the ungating of the PM domain regulator here.
+ *
+ * Drivers/subsystems handling devices in the PM domain needs to perform
+ * register context save/restore from their respective runtime PM
+ * callbacks, to be able to enable PM domain gating/ungating.
+ */
+ return 0;
+}
+
+static struct generic_pm_domain ux500_pm_domain_vape = {
+ .name = "VAPE",
+ .power_off = pd_power_off,
+ .power_on = pd_power_on,
+};
+
+static struct generic_pm_domain *ux500_pm_domains[NR_DOMAINS] = {
+ [DOMAIN_VAPE] = &ux500_pm_domain_vape,
+};
+
+static struct of_device_id ux500_pm_domain_matches[] = {
+ { .compatible = "stericsson,ux500-pm-domains", },
+ { },
+};
+
+int __init ux500_pm_domains_init(void)
+{
+ struct device_node *np;
+ struct genpd_onecell_data *genpd_data;
+ int i;
+
+ np = of_find_matching_node(NULL, ux500_pm_domain_matches);
+ if (!np)
+ return -ENODEV;
+
+ genpd_data = kzalloc(sizeof(*genpd_data), GFP_KERNEL);
+ if (!genpd_data)
+ return -ENOMEM;
+
+ genpd_data->domains = ux500_pm_domains;
+ genpd_data->num_domains = ARRAY_SIZE(ux500_pm_domains);
+
+ for (i = 0; i < ARRAY_SIZE(ux500_pm_domains); ++i)
+ pm_genpd_init(ux500_pm_domains[i], NULL, false);
+
+ of_genpd_add_provider_onecell(np, genpd_data);
+ return 0;
+}
diff --git a/arch/arm/mach-ux500/pm_domains.h b/arch/arm/mach-ux500/pm_domains.h
new file mode 100644
index 0000000..263d3ba
--- /dev/null
+++ b/arch/arm/mach-ux500/pm_domains.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef __MACH_UX500_PM_DOMAINS_H
+#define __MACH_UX500_PM_DOMAINS_H
+
+#ifdef CONFIG_PM_GENERIC_DOMAINS
+extern int __init ux500_pm_domains_init(void);
+#else
+static inline int ux500_pm_domains_init(void) { return 0; }
+#endif
+
+#endif
diff --git a/arch/arm/mach-vexpress/Kconfig b/arch/arm/mach-vexpress/Kconfig
index b2cfba16c..d6b16d9 100644
--- a/arch/arm/mach-vexpress/Kconfig
+++ b/arch/arm/mach-vexpress/Kconfig
@@ -16,6 +16,7 @@ menuconfig ARCH_VEXPRESS
select POWER_RESET
select POWER_RESET_VEXPRESS
select POWER_SUPPLY
+ select REGULATOR if MMC_ARMMMCI
select REGULATOR_FIXED_VOLTAGE if REGULATOR
select VEXPRESS_CONFIG
select VEXPRESS_SYSCFG
@@ -49,9 +50,6 @@ config ARCH_VEXPRESS_CORTEX_A5_A9_ERRATA
build a working kernel, you must also enable relevant core
tile support or Flattened Device Tree based support options.
-config ARCH_VEXPRESS_CA9X4
- bool "Versatile Express Cortex-A9x4 tile"
-
config ARCH_VEXPRESS_DCSCB
bool "Dual Cluster System Control Block (DCSCB) support"
depends on MCPM
diff --git a/arch/arm/mach-vexpress/Makefile b/arch/arm/mach-vexpress/Makefile
index fc649bc..f5c1006 100644
--- a/arch/arm/mach-vexpress/Makefile
+++ b/arch/arm/mach-vexpress/Makefile
@@ -1,11 +1,10 @@
#
# Makefile for the linux kernel.
#
-ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := -I$(srctree)/$(src)/include \
+ccflags-$(CONFIG_ARCH_MULTIPLATFORM) := \
-I$(srctree)/arch/arm/plat-versatile/include
obj-y := v2m.o
-obj-$(CONFIG_ARCH_VEXPRESS_CA9X4) += ct-ca9x4.o
obj-$(CONFIG_ARCH_VEXPRESS_DCSCB) += dcscb.o dcscb_setup.o
CFLAGS_dcscb.o += -march=armv7-a
CFLAGS_REMOVE_dcscb.o = -pg
diff --git a/arch/arm/mach-vexpress/core.h b/arch/arm/mach-vexpress/core.h
index 152fad9..2a11d3a 100644
--- a/arch/arm/mach-vexpress/core.h
+++ b/arch/arm/mach-vexpress/core.h
@@ -1,12 +1,5 @@
-/* 2MB large area for motherboard's peripherals static mapping */
-#define V2M_PERIPH 0xf8000000
-
-/* Tile's peripherals static mappings should start here */
-#define V2T_PERIPH 0xf8200000
-
bool vexpress_smp_init_ops(void);
-extern struct smp_operations vexpress_smp_ops;
extern struct smp_operations vexpress_smp_dt_ops;
extern void vexpress_cpu_die(unsigned int cpu);
diff --git a/arch/arm/mach-vexpress/ct-ca9x4.c b/arch/arm/mach-vexpress/ct-ca9x4.c
deleted file mode 100644
index 27bea04..0000000
--- a/arch/arm/mach-vexpress/ct-ca9x4.c
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * Versatile Express Core Tile Cortex A9x4 Support
- */
-#include <linux/init.h>
-#include <linux/gfp.h>
-#include <linux/device.h>
-#include <linux/dma-mapping.h>
-#include <linux/platform_device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/clcd.h>
-#include <linux/platform_data/video-clcd-versatile.h>
-#include <linux/clkdev.h>
-#include <linux/vexpress.h>
-#include <linux/irqchip/arm-gic.h>
-
-#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <asm/smp_scu.h>
-#include <asm/smp_twd.h>
-
-#include <mach/ct-ca9x4.h>
-
-#include <asm/hardware/timer-sp.h>
-
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-
-#include "core.h"
-
-#include <mach/motherboard.h>
-#include <mach/irqs.h>
-
-static struct map_desc ct_ca9x4_io_desc[] __initdata = {
- {
- .virtual = V2T_PERIPH,
- .pfn = __phys_to_pfn(CT_CA9X4_MPIC),
- .length = SZ_8K,
- .type = MT_DEVICE,
- },
-};
-
-static void __init ct_ca9x4_map_io(void)
-{
- iotable_init(ct_ca9x4_io_desc, ARRAY_SIZE(ct_ca9x4_io_desc));
-}
-
-static void __init ca9x4_l2_init(void)
-{
-#ifdef CONFIG_CACHE_L2X0
- void __iomem *l2x0_base = ioremap(CT_CA9X4_L2CC, SZ_4K);
-
- if (l2x0_base) {
- /* set RAM latencies to 1 cycle for this core tile. */
- writel(0, l2x0_base + L310_TAG_LATENCY_CTRL);
- writel(0, l2x0_base + L310_DATA_LATENCY_CTRL);
-
- l2x0_init(l2x0_base, 0x00400000, 0xfe0fffff);
- } else {
- pr_err("L2C: unable to map L2 cache controller\n");
- }
-#endif
-}
-
-#ifdef CONFIG_HAVE_ARM_TWD
-static DEFINE_TWD_LOCAL_TIMER(twd_local_timer, A9_MPCORE_TWD, IRQ_LOCALTIMER);
-
-static void __init ca9x4_twd_init(void)
-{
- int err = twd_local_timer_register(&twd_local_timer);
- if (err)
- pr_err("twd_local_timer_register failed %d\n", err);
-}
-#else
-#define ca9x4_twd_init() do {} while(0)
-#endif
-
-static void __init ct_ca9x4_init_irq(void)
-{
- gic_init(0, 29, ioremap(A9_MPCORE_GIC_DIST, SZ_4K),
- ioremap(A9_MPCORE_GIC_CPU, SZ_256));
- ca9x4_twd_init();
- ca9x4_l2_init();
-}
-
-static int ct_ca9x4_clcd_setup(struct clcd_fb *fb)
-{
- unsigned long framesize = 1024 * 768 * 2;
-
- fb->panel = versatile_clcd_get_panel("XVGA");
- if (!fb->panel)
- return -EINVAL;
-
- return versatile_clcd_setup_dma(fb, framesize);
-}
-
-static struct clcd_board ct_ca9x4_clcd_data = {
- .name = "CT-CA9X4",
- .caps = CLCD_CAP_5551 | CLCD_CAP_565,
- .check = clcdfb_check,
- .decode = clcdfb_decode,
- .setup = ct_ca9x4_clcd_setup,
- .mmap = versatile_clcd_mmap_dma,
- .remove = versatile_clcd_remove_dma,
-};
-
-static AMBA_AHB_DEVICE(clcd, "ct:clcd", 0, CT_CA9X4_CLCDC, IRQ_CT_CA9X4_CLCDC, &ct_ca9x4_clcd_data);
-static AMBA_APB_DEVICE(dmc, "ct:dmc", 0, CT_CA9X4_DMC, IRQ_CT_CA9X4_DMC, NULL);
-static AMBA_APB_DEVICE(smc, "ct:smc", 0, CT_CA9X4_SMC, IRQ_CT_CA9X4_SMC, NULL);
-static AMBA_APB_DEVICE(gpio, "ct:gpio", 0, CT_CA9X4_GPIO, IRQ_CT_CA9X4_GPIO, NULL);
-
-static struct amba_device *ct_ca9x4_amba_devs[] __initdata = {
- &clcd_device,
- &dmc_device,
- &smc_device,
- &gpio_device,
-};
-
-static struct resource pmu_resources[] = {
- [0] = {
- .start = IRQ_CT_CA9X4_PMU_CPU0,
- .end = IRQ_CT_CA9X4_PMU_CPU0,
- .flags = IORESOURCE_IRQ,
- },
- [1] = {
- .start = IRQ_CT_CA9X4_PMU_CPU1,
- .end = IRQ_CT_CA9X4_PMU_CPU1,
- .flags = IORESOURCE_IRQ,
- },
- [2] = {
- .start = IRQ_CT_CA9X4_PMU_CPU2,
- .end = IRQ_CT_CA9X4_PMU_CPU2,
- .flags = IORESOURCE_IRQ,
- },
- [3] = {
- .start = IRQ_CT_CA9X4_PMU_CPU3,
- .end = IRQ_CT_CA9X4_PMU_CPU3,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct platform_device pmu_device = {
- .name = "arm-pmu",
- .id = -1,
- .num_resources = ARRAY_SIZE(pmu_resources),
- .resource = pmu_resources,
-};
-
-static struct clk_lookup osc1_lookup = {
- .dev_id = "ct:clcd",
-};
-
-static struct platform_device osc1_device = {
- .name = "vexpress-osc",
- .id = 1,
- .num_resources = 1,
- .resource = (struct resource []) {
- VEXPRESS_RES_FUNC(0xf, 1),
- },
- .dev.platform_data = &osc1_lookup,
-};
-
-static void __init ct_ca9x4_init(void)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(ct_ca9x4_amba_devs); i++)
- amba_device_register(ct_ca9x4_amba_devs[i], &iomem_resource);
-
- platform_device_register(&pmu_device);
- vexpress_syscfg_device_register(&osc1_device);
-}
-
-#ifdef CONFIG_SMP
-static void *ct_ca9x4_scu_base __initdata;
-
-static void __init ct_ca9x4_init_cpu_map(void)
-{
- int i, ncores;
-
- ct_ca9x4_scu_base = ioremap(A9_MPCORE_SCU, SZ_128);
- if (WARN_ON(!ct_ca9x4_scu_base))
- return;
-
- ncores = scu_get_core_count(ct_ca9x4_scu_base);
-
- if (ncores > nr_cpu_ids) {
- pr_warn("SMP: %u cores greater than maximum (%u), clipping\n",
- ncores, nr_cpu_ids);
- ncores = nr_cpu_ids;
- }
-
- for (i = 0; i < ncores; ++i)
- set_cpu_possible(i, true);
-}
-
-static void __init ct_ca9x4_smp_enable(unsigned int max_cpus)
-{
- scu_enable(ct_ca9x4_scu_base);
-}
-#endif
-
-struct ct_desc ct_ca9x4_desc __initdata = {
- .id = V2M_CT_ID_CA9,
- .name = "CA9x4",
- .map_io = ct_ca9x4_map_io,
- .init_irq = ct_ca9x4_init_irq,
- .init_tile = ct_ca9x4_init,
-#ifdef CONFIG_SMP
- .init_cpu_map = ct_ca9x4_init_cpu_map,
- .smp_enable = ct_ca9x4_smp_enable,
-#endif
-};
diff --git a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h b/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
deleted file mode 100644
index 84acf84..0000000
--- a/arch/arm/mach-vexpress/include/mach/ct-ca9x4.h
+++ /dev/null
@@ -1,47 +0,0 @@
-#ifndef __MACH_CT_CA9X4_H
-#define __MACH_CT_CA9X4_H
-
-/*
- * Physical base addresses
- */
-#define CT_CA9X4_CLCDC (0x10020000)
-#define CT_CA9X4_AXIRAM (0x10060000)
-#define CT_CA9X4_DMC (0x100e0000)
-#define CT_CA9X4_SMC (0x100e1000)
-#define CT_CA9X4_SCC (0x100e2000)
-#define CT_CA9X4_SP804_TIMER (0x100e4000)
-#define CT_CA9X4_SP805_WDT (0x100e5000)
-#define CT_CA9X4_TZPC (0x100e6000)
-#define CT_CA9X4_GPIO (0x100e8000)
-#define CT_CA9X4_FASTAXI (0x100e9000)
-#define CT_CA9X4_SLOWAXI (0x100ea000)
-#define CT_CA9X4_TZASC (0x100ec000)
-#define CT_CA9X4_CORESIGHT (0x10200000)
-#define CT_CA9X4_MPIC (0x1e000000)
-#define CT_CA9X4_SYSTIMER (0x1e004000)
-#define CT_CA9X4_SYSWDT (0x1e007000)
-#define CT_CA9X4_L2CC (0x1e00a000)
-
-#define A9_MPCORE_SCU (CT_CA9X4_MPIC + 0x0000)
-#define A9_MPCORE_GIC_CPU (CT_CA9X4_MPIC + 0x0100)
-#define A9_MPCORE_GIT (CT_CA9X4_MPIC + 0x0200)
-#define A9_MPCORE_TWD (CT_CA9X4_MPIC + 0x0600)
-#define A9_MPCORE_GIC_DIST (CT_CA9X4_MPIC + 0x1000)
-
-/*
- * Interrupts. Those in {} are for AMBA devices
- */
-#define IRQ_CT_CA9X4_CLCDC { 76 }
-#define IRQ_CT_CA9X4_DMC { 0 }
-#define IRQ_CT_CA9X4_SMC { 77, 78 }
-#define IRQ_CT_CA9X4_TIMER0 80
-#define IRQ_CT_CA9X4_TIMER1 81
-#define IRQ_CT_CA9X4_GPIO { 82 }
-#define IRQ_CT_CA9X4_PMU_CPU0 92
-#define IRQ_CT_CA9X4_PMU_CPU1 93
-#define IRQ_CT_CA9X4_PMU_CPU2 94
-#define IRQ_CT_CA9X4_PMU_CPU3 95
-
-extern struct ct_desc ct_ca9x4_desc;
-
-#endif
diff --git a/arch/arm/mach-vexpress/include/mach/hardware.h b/arch/arm/mach-vexpress/include/mach/hardware.h
deleted file mode 100644
index 40a8c17..0000000
--- a/arch/arm/mach-vexpress/include/mach/hardware.h
+++ /dev/null
@@ -1 +0,0 @@
-/* empty */
diff --git a/arch/arm/mach-vexpress/include/mach/irqs.h b/arch/arm/mach-vexpress/include/mach/irqs.h
deleted file mode 100644
index f8f7f78..0000000
--- a/arch/arm/mach-vexpress/include/mach/irqs.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#define IRQ_LOCALTIMER 29
-#define IRQ_LOCALWDOG 30
-
-#ifndef CONFIG_SPARSE_IRQ
-#define NR_IRQS 256
-#endif
diff --git a/arch/arm/mach-vexpress/include/mach/motherboard.h b/arch/arm/mach-vexpress/include/mach/motherboard.h
deleted file mode 100644
index 68abc8b..0000000
--- a/arch/arm/mach-vexpress/include/mach/motherboard.h
+++ /dev/null
@@ -1,88 +0,0 @@
-#ifndef __MACH_MOTHERBOARD_H
-#define __MACH_MOTHERBOARD_H
-
-/*
- * Physical addresses, offset from V2M_PA_CS0-3
- */
-#define V2M_NOR0 (V2M_PA_CS0)
-#define V2M_NOR1 (V2M_PA_CS1)
-#define V2M_SRAM (V2M_PA_CS2)
-#define V2M_VIDEO_SRAM (V2M_PA_CS3 + 0x00000000)
-#define V2M_LAN9118 (V2M_PA_CS3 + 0x02000000)
-#define V2M_ISP1761 (V2M_PA_CS3 + 0x03000000)
-
-/*
- * Physical addresses, offset from V2M_PA_CS7
- */
-#define V2M_SYSREGS (V2M_PA_CS7 + 0x00000000)
-#define V2M_SYSCTL (V2M_PA_CS7 + 0x00001000)
-#define V2M_SERIAL_BUS_PCI (V2M_PA_CS7 + 0x00002000)
-
-#define V2M_AACI (V2M_PA_CS7 + 0x00004000)
-#define V2M_MMCI (V2M_PA_CS7 + 0x00005000)
-#define V2M_KMI0 (V2M_PA_CS7 + 0x00006000)
-#define V2M_KMI1 (V2M_PA_CS7 + 0x00007000)
-
-#define V2M_UART0 (V2M_PA_CS7 + 0x00009000)
-#define V2M_UART1 (V2M_PA_CS7 + 0x0000a000)
-#define V2M_UART2 (V2M_PA_CS7 + 0x0000b000)
-#define V2M_UART3 (V2M_PA_CS7 + 0x0000c000)
-
-#define V2M_WDT (V2M_PA_CS7 + 0x0000f000)
-
-#define V2M_TIMER01 (V2M_PA_CS7 + 0x00011000)
-#define V2M_TIMER23 (V2M_PA_CS7 + 0x00012000)
-
-#define V2M_SERIAL_BUS_DVI (V2M_PA_CS7 + 0x00016000)
-#define V2M_RTC (V2M_PA_CS7 + 0x00017000)
-
-#define V2M_CF (V2M_PA_CS7 + 0x0001a000)
-#define V2M_CLCD (V2M_PA_CS7 + 0x0001f000)
-
-
-/*
- * Interrupts. Those in {} are for AMBA devices
- */
-#define IRQ_V2M_WDT { (32 + 0) }
-#define IRQ_V2M_TIMER0 (32 + 2)
-#define IRQ_V2M_TIMER1 (32 + 2)
-#define IRQ_V2M_TIMER2 (32 + 3)
-#define IRQ_V2M_TIMER3 (32 + 3)
-#define IRQ_V2M_RTC { (32 + 4) }
-#define IRQ_V2M_UART0 { (32 + 5) }
-#define IRQ_V2M_UART1 { (32 + 6) }
-#define IRQ_V2M_UART2 { (32 + 7) }
-#define IRQ_V2M_UART3 { (32 + 8) }
-#define IRQ_V2M_MMCI { (32 + 9), (32 + 10) }
-#define IRQ_V2M_AACI { (32 + 11) }
-#define IRQ_V2M_KMI0 { (32 + 12) }
-#define IRQ_V2M_KMI1 { (32 + 13) }
-#define IRQ_V2M_CLCD { (32 + 14) }
-#define IRQ_V2M_LAN9118 (32 + 15)
-#define IRQ_V2M_ISP1761 (32 + 16)
-#define IRQ_V2M_PCIE (32 + 17)
-
-
-/*
- * Core tile IDs
- */
-#define V2M_CT_ID_CA9 0x0c000191
-#define V2M_CT_ID_UNSUPPORTED 0xff000191
-#define V2M_CT_ID_MASK 0xff000fff
-
-struct ct_desc {
- u32 id;
- const char *name;
- void (*map_io)(void);
- void (*init_early)(void);
- void (*init_irq)(void);
- void (*init_tile)(void);
-#ifdef CONFIG_SMP
- void (*init_cpu_map)(void);
- void (*smp_enable)(unsigned int);
-#endif
-};
-
-extern struct ct_desc *ct_desc;
-
-#endif
diff --git a/arch/arm/mach-vexpress/platsmp.c b/arch/arm/mach-vexpress/platsmp.c
index a1f3804..83188cf 100644
--- a/arch/arm/mach-vexpress/platsmp.c
+++ b/arch/arm/mach-vexpress/platsmp.c
@@ -19,48 +19,10 @@
#include <asm/smp_scu.h>
#include <asm/mach/map.h>
-#include <mach/motherboard.h>
-
#include <plat/platsmp.h>
#include "core.h"
-/*
- * Initialise the CPU possible map early - this describes the CPUs
- * which may be present or become present in the system.
- */
-static void __init vexpress_smp_init_cpus(void)
-{
- ct_desc->init_cpu_map();
-}
-
-static void __init vexpress_smp_prepare_cpus(unsigned int max_cpus)
-{
- /*
- * Initialise the present map, which describes the set of CPUs
- * actually populated at the present time.
- */
- ct_desc->smp_enable(max_cpus);
-
- /*
- * Write the address of secondary startup into the
- * system-wide flags register. The boot monitor waits
- * until it receives a soft interrupt, and then the
- * secondary CPU branches to this address.
- */
- vexpress_flags_set(virt_to_phys(versatile_secondary_startup));
-}
-
-struct smp_operations __initdata vexpress_smp_ops = {
- .smp_init_cpus = vexpress_smp_init_cpus,
- .smp_prepare_cpus = vexpress_smp_prepare_cpus,
- .smp_secondary_init = versatile_secondary_init,
- .smp_boot_secondary = versatile_boot_secondary,
-#ifdef CONFIG_HOTPLUG_CPU
- .cpu_die = vexpress_cpu_die,
-#endif
-};
-
bool __init vexpress_smp_init_ops(void)
{
#ifdef CONFIG_MCPM
@@ -79,8 +41,6 @@ bool __init vexpress_smp_init_ops(void)
return false;
}
-#if defined(CONFIG_OF)
-
static const struct of_device_id vexpress_smp_dt_scu_match[] __initconst = {
{ .compatible = "arm,cortex-a5-scu", },
{ .compatible = "arm,cortex-a9-scu", },
@@ -112,5 +72,3 @@ struct smp_operations __initdata vexpress_smp_dt_ops = {
.cpu_die = vexpress_cpu_die,
#endif
};
-
-#endif
diff --git a/arch/arm/mach-vexpress/v2m.c b/arch/arm/mach-vexpress/v2m.c
index 6ff681a..a0400f4 100644
--- a/arch/arm/mach-vexpress/v2m.c
+++ b/arch/arm/mach-vexpress/v2m.c
@@ -1,380 +1,7 @@
-/*
- * Versatile Express V2M Motherboard Support
- */
-#include <linux/device.h>
-#include <linux/amba/bus.h>
-#include <linux/amba/mmci.h>
-#include <linux/io.h>
-#include <linux/smp.h>
-#include <linux/init.h>
-#include <linux/of_address.h>
-#include <linux/of_fdt.h>
-#include <linux/of_irq.h>
-#include <linux/of_platform.h>
-#include <linux/platform_device.h>
-#include <linux/ata_platform.h>
-#include <linux/smsc911x.h>
-#include <linux/spinlock.h>
-#include <linux/usb/isp1760.h>
-#include <linux/mtd/physmap.h>
-#include <linux/regulator/fixed.h>
-#include <linux/regulator/machine.h>
-#include <linux/vexpress.h>
-#include <linux/clkdev.h>
-
-#include <asm/mach-types.h>
-#include <asm/sizes.h>
#include <asm/mach/arch.h>
-#include <asm/mach/map.h>
-#include <asm/mach/time.h>
-#include <asm/hardware/arm_timer.h>
-#include <asm/hardware/cache-l2x0.h>
-#include <asm/hardware/timer-sp.h>
-
-#include <mach/ct-ca9x4.h>
-#include <mach/motherboard.h>
-
-#include <plat/sched_clock.h>
-#include <plat/platsmp.h>
#include "core.h"
-#define V2M_PA_CS0 0x40000000
-#define V2M_PA_CS1 0x44000000
-#define V2M_PA_CS2 0x48000000
-#define V2M_PA_CS3 0x4c000000
-#define V2M_PA_CS7 0x10000000
-
-static struct map_desc v2m_io_desc[] __initdata = {
- {
- .virtual = V2M_PERIPH,
- .pfn = __phys_to_pfn(V2M_PA_CS7),
- .length = SZ_128K,
- .type = MT_DEVICE,
- },
-};
-
-static void __init v2m_sp804_init(void __iomem *base, unsigned int irq)
-{
- if (WARN_ON(!base || irq == NO_IRQ))
- return;
-
- sp804_clocksource_init(base + TIMER_2_BASE, "v2m-timer1");
- sp804_clockevents_init(base + TIMER_1_BASE, irq, "v2m-timer0");
-}
-
-
-static struct resource v2m_pcie_i2c_resource = {
- .start = V2M_SERIAL_BUS_PCI,
- .end = V2M_SERIAL_BUS_PCI + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device v2m_pcie_i2c_device = {
- .name = "versatile-i2c",
- .id = 0,
- .num_resources = 1,
- .resource = &v2m_pcie_i2c_resource,
-};
-
-static struct resource v2m_ddc_i2c_resource = {
- .start = V2M_SERIAL_BUS_DVI,
- .end = V2M_SERIAL_BUS_DVI + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
-};
-
-static struct platform_device v2m_ddc_i2c_device = {
- .name = "versatile-i2c",
- .id = 1,
- .num_resources = 1,
- .resource = &v2m_ddc_i2c_resource,
-};
-
-static struct resource v2m_eth_resources[] = {
- {
- .start = V2M_LAN9118,
- .end = V2M_LAN9118 + SZ_64K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_V2M_LAN9118,
- .end = IRQ_V2M_LAN9118,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct smsc911x_platform_config v2m_eth_config = {
- .flags = SMSC911X_USE_32BIT,
- .irq_polarity = SMSC911X_IRQ_POLARITY_ACTIVE_HIGH,
- .irq_type = SMSC911X_IRQ_TYPE_PUSH_PULL,
- .phy_interface = PHY_INTERFACE_MODE_MII,
-};
-
-static struct platform_device v2m_eth_device = {
- .name = "smsc911x",
- .id = -1,
- .resource = v2m_eth_resources,
- .num_resources = ARRAY_SIZE(v2m_eth_resources),
- .dev.platform_data = &v2m_eth_config,
-};
-
-static struct regulator_consumer_supply v2m_eth_supplies[] = {
- REGULATOR_SUPPLY("vddvario", "smsc911x"),
- REGULATOR_SUPPLY("vdd33a", "smsc911x"),
-};
-
-static struct resource v2m_usb_resources[] = {
- {
- .start = V2M_ISP1761,
- .end = V2M_ISP1761 + SZ_128K - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = IRQ_V2M_ISP1761,
- .end = IRQ_V2M_ISP1761,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static struct isp1760_platform_data v2m_usb_config = {
- .is_isp1761 = true,
- .bus_width_16 = false,
- .port1_otg = true,
- .analog_oc = false,
- .dack_polarity_high = false,
- .dreq_polarity_high = false,
-};
-
-static struct platform_device v2m_usb_device = {
- .name = "isp1760",
- .id = -1,
- .resource = v2m_usb_resources,
- .num_resources = ARRAY_SIZE(v2m_usb_resources),
- .dev.platform_data = &v2m_usb_config,
-};
-
-static struct physmap_flash_data v2m_flash_data = {
- .width = 4,
-};
-
-static struct resource v2m_flash_resources[] = {
- {
- .start = V2M_NOR0,
- .end = V2M_NOR0 + SZ_64M - 1,
- .flags = IORESOURCE_MEM,
- }, {
- .start = V2M_NOR1,
- .end = V2M_NOR1 + SZ_64M - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device v2m_flash_device = {
- .name = "physmap-flash",
- .id = -1,
- .resource = v2m_flash_resources,
- .num_resources = ARRAY_SIZE(v2m_flash_resources),
- .dev.platform_data = &v2m_flash_data,
-};
-
-static struct pata_platform_info v2m_pata_data = {
- .ioport_shift = 2,
-};
-
-static struct resource v2m_pata_resources[] = {
- {
- .start = V2M_CF,
- .end = V2M_CF + 0xff,
- .flags = IORESOURCE_MEM,
- }, {
- .start = V2M_CF + 0x100,
- .end = V2M_CF + SZ_4K - 1,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device v2m_cf_device = {
- .name = "pata_platform",
- .id = -1,
- .resource = v2m_pata_resources,
- .num_resources = ARRAY_SIZE(v2m_pata_resources),
- .dev.platform_data = &v2m_pata_data,
-};
-
-static struct mmci_platform_data v2m_mmci_data = {
- .ocr_mask = MMC_VDD_32_33|MMC_VDD_33_34,
- .status = vexpress_get_mci_cardin,
- .gpio_cd = -1,
- .gpio_wp = -1,
-};
-
-static struct resource v2m_sysreg_resources[] = {
- {
- .start = V2M_SYSREGS,
- .end = V2M_SYSREGS + 0xfff,
- .flags = IORESOURCE_MEM,
- },
-};
-
-static struct platform_device v2m_sysreg_device = {
- .name = "vexpress-sysreg",
- .id = -1,
- .resource = v2m_sysreg_resources,
- .num_resources = ARRAY_SIZE(v2m_sysreg_resources),
-};
-
-static struct platform_device v2m_muxfpga_device = {
- .name = "vexpress-muxfpga",
- .id = 0,
- .num_resources = 1,
- .resource = (struct resource []) {
- VEXPRESS_RES_FUNC(0, 7),
- }
-};
-
-static struct platform_device v2m_shutdown_device = {
- .name = "vexpress-shutdown",
- .id = 0,
- .num_resources = 1,
- .resource = (struct resource []) {
- VEXPRESS_RES_FUNC(0, 8),
- }
-};
-
-static struct platform_device v2m_reboot_device = {
- .name = "vexpress-reboot",
- .id = 0,
- .num_resources = 1,
- .resource = (struct resource []) {
- VEXPRESS_RES_FUNC(0, 9),
- }
-};
-
-static struct platform_device v2m_dvimode_device = {
- .name = "vexpress-dvimode",
- .id = 0,
- .num_resources = 1,
- .resource = (struct resource []) {
- VEXPRESS_RES_FUNC(0, 11),
- }
-};
-
-static AMBA_APB_DEVICE(aaci, "mb:aaci", 0, V2M_AACI, IRQ_V2M_AACI, NULL);
-static AMBA_APB_DEVICE(mmci, "mb:mmci", 0, V2M_MMCI, IRQ_V2M_MMCI, &v2m_mmci_data);
-static AMBA_APB_DEVICE(kmi0, "mb:kmi0", 0, V2M_KMI0, IRQ_V2M_KMI0, NULL);
-static AMBA_APB_DEVICE(kmi1, "mb:kmi1", 0, V2M_KMI1, IRQ_V2M_KMI1, NULL);
-static AMBA_APB_DEVICE(uart0, "mb:uart0", 0, V2M_UART0, IRQ_V2M_UART0, NULL);
-static AMBA_APB_DEVICE(uart1, "mb:uart1", 0, V2M_UART1, IRQ_V2M_UART1, NULL);
-static AMBA_APB_DEVICE(uart2, "mb:uart2", 0, V2M_UART2, IRQ_V2M_UART2, NULL);
-static AMBA_APB_DEVICE(uart3, "mb:uart3", 0, V2M_UART3, IRQ_V2M_UART3, NULL);
-static AMBA_APB_DEVICE(wdt, "mb:wdt", 0, V2M_WDT, IRQ_V2M_WDT, NULL);
-static AMBA_APB_DEVICE(rtc, "mb:rtc", 0, V2M_RTC, IRQ_V2M_RTC, NULL);
-
-static struct amba_device *v2m_amba_devs[] __initdata = {
- &aaci_device,
- &mmci_device,
- &kmi0_device,
- &kmi1_device,
- &uart0_device,
- &uart1_device,
- &uart2_device,
- &uart3_device,
- &wdt_device,
- &rtc_device,
-};
-
-static void __init v2m_timer_init(void)
-{
- vexpress_clk_init(ioremap(V2M_SYSCTL, SZ_4K));
- v2m_sp804_init(ioremap(V2M_TIMER01, SZ_4K), IRQ_V2M_TIMER0);
-}
-
-static void __init v2m_init_early(void)
-{
- if (ct_desc->init_early)
- ct_desc->init_early();
- versatile_sched_clock_init(vexpress_get_24mhz_clock_base(), 24000000);
-}
-
-struct ct_desc *ct_desc;
-
-static struct ct_desc *ct_descs[] __initdata = {
-#ifdef CONFIG_ARCH_VEXPRESS_CA9X4
- &ct_ca9x4_desc,
-#endif
-};
-
-static void __init v2m_populate_ct_desc(void)
-{
- int i;
- u32 current_tile_id;
-
- ct_desc = NULL;
- current_tile_id = vexpress_get_procid(VEXPRESS_SITE_MASTER)
- & V2M_CT_ID_MASK;
-
- for (i = 0; i < ARRAY_SIZE(ct_descs) && !ct_desc; ++i)
- if (ct_descs[i]->id == current_tile_id)
- ct_desc = ct_descs[i];
-
- if (!ct_desc)
- panic("vexpress: this kernel does not support core tile ID 0x%08x when booting via ATAGs.\n"
- "You may need a device tree blob or a different kernel to boot on this board.\n",
- current_tile_id);
-}
-
-static void __init v2m_map_io(void)
-{
- iotable_init(v2m_io_desc, ARRAY_SIZE(v2m_io_desc));
- vexpress_sysreg_early_init(ioremap(V2M_SYSREGS, SZ_4K));
- v2m_populate_ct_desc();
- ct_desc->map_io();
-}
-
-static void __init v2m_init_irq(void)
-{
- ct_desc->init_irq();
-}
-
-static void __init v2m_init(void)
-{
- int i;
-
- regulator_register_fixed(0, v2m_eth_supplies,
- ARRAY_SIZE(v2m_eth_supplies));
-
- platform_device_register(&v2m_sysreg_device);
- platform_device_register(&v2m_pcie_i2c_device);
- platform_device_register(&v2m_ddc_i2c_device);
- platform_device_register(&v2m_flash_device);
- platform_device_register(&v2m_cf_device);
- platform_device_register(&v2m_eth_device);
- platform_device_register(&v2m_usb_device);
-
- for (i = 0; i < ARRAY_SIZE(v2m_amba_devs); i++)
- amba_device_register(v2m_amba_devs[i], &iomem_resource);
-
- vexpress_syscfg_device_register(&v2m_muxfpga_device);
- vexpress_syscfg_device_register(&v2m_shutdown_device);
- vexpress_syscfg_device_register(&v2m_reboot_device);
- vexpress_syscfg_device_register(&v2m_dvimode_device);
-
- ct_desc->init_tile();
-}
-
-MACHINE_START(VEXPRESS, "ARM-Versatile Express")
- .atag_offset = 0x100,
- .smp = smp_ops(vexpress_smp_ops),
- .map_io = v2m_map_io,
- .init_early = v2m_init_early,
- .init_irq = v2m_init_irq,
- .init_time = v2m_timer_init,
- .init_machine = v2m_init,
-MACHINE_END
-
-static void __init v2m_dt_init(void)
-{
- of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
-}
-
static const char * const v2m_dt_match[] __initconst = {
"arm,vexpress",
NULL,
@@ -386,5 +13,4 @@ DT_MACHINE_START(VEXPRESS_DT, "ARM-Versatile Express")
.l2c_aux_mask = 0xfe0fffff,
.smp = smp_ops(vexpress_smp_dt_ops),
.smp_init = smp_init_ops(vexpress_smp_init_ops),
- .init_machine = v2m_dt_init,
MACHINE_END
diff --git a/arch/arm/mach-zynq/Makefile b/arch/arm/mach-zynq/Makefile
index c85fb3f..b03a97e 100644
--- a/arch/arm/mach-zynq/Makefile
+++ b/arch/arm/mach-zynq/Makefile
@@ -4,6 +4,4 @@
# Common support
obj-y := common.o slcr.o pm.o
-CFLAGS_REMOVE_hotplug.o =-march=armv6k
-CFLAGS_hotplug.o =-Wa,-march=armv7-a -mcpu=cortex-a9
obj-$(CONFIG_SMP) += headsmp.o platsmp.o
diff --git a/arch/arm/mach-zynq/common.h b/arch/arm/mach-zynq/common.h
index 2bc7127..382c60e 100644
--- a/arch/arm/mach-zynq/common.h
+++ b/arch/arm/mach-zynq/common.h
@@ -29,7 +29,6 @@ extern void zynq_slcr_cpu_state_write(int cpu, bool die);
extern u32 zynq_slcr_get_device_id(void);
#ifdef CONFIG_SMP
-extern void secondary_startup(void);
extern char zynq_secondary_trampoline;
extern char zynq_secondary_trampoline_jump;
extern char zynq_secondary_trampoline_end;
diff --git a/arch/arm/mach-zynq/hotplug.c b/arch/arm/mach-zynq/hotplug.c
deleted file mode 100644
index b685c89..0000000
--- a/arch/arm/mach-zynq/hotplug.c
+++ /dev/null
@@ -1,14 +0,0 @@
-/*
- * Copyright (C) 2012-2013 Xilinx
- *
- * based on linux/arch/arm/mach-realview/hotplug.c
- *
- * Copyright (C) 2002 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 <asm/proc-fns.h>
-
diff --git a/arch/arm/mm/Kconfig b/arch/arm/mm/Kconfig
index 7eb94e6..ab906b8 100644
--- a/arch/arm/mm/Kconfig
+++ b/arch/arm/mm/Kconfig
@@ -21,7 +21,7 @@ config CPU_ARM7TDMI
# ARM720T
config CPU_ARM720T
- bool "Support ARM720T processor" if ARCH_INTEGRATOR
+ bool "Support ARM720T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
select CPU_32v4T
select CPU_ABRT_LV4T
select CPU_CACHE_V4
@@ -39,7 +39,7 @@ config CPU_ARM720T
# ARM740T
config CPU_ARM740T
- bool "Support ARM740T processor" if ARCH_INTEGRATOR
+ bool "Support ARM740T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
depends on !MMU
select CPU_32v4T
select CPU_ABRT_LV4T
@@ -71,7 +71,7 @@ config CPU_ARM9TDMI
# ARM920T
config CPU_ARM920T
- bool "Support ARM920T processor" if ARCH_INTEGRATOR
+ bool "Support ARM920T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
select CPU_32v4T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -89,7 +89,7 @@ config CPU_ARM920T
# ARM922T
config CPU_ARM922T
- bool "Support ARM922T processor" if ARCH_INTEGRATOR
+ bool "Support ARM922T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
select CPU_32v4T
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -127,7 +127,7 @@ config CPU_ARM925T
# ARM926T
config CPU_ARM926T
- bool "Support ARM926T processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB
+ bool "Support ARM926T processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V5) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB)
select CPU_32v5
select CPU_ABRT_EV5TJ
select CPU_CACHE_VIVT
@@ -163,7 +163,7 @@ config CPU_FA526
# ARM940T
config CPU_ARM940T
- bool "Support ARM940T processor" if ARCH_INTEGRATOR
+ bool "Support ARM940T processor" if (ARCH_MULTI_V4T && ARCH_INTEGRATOR)
depends on !MMU
select CPU_32v4T
select CPU_ABRT_NOMMU
@@ -181,7 +181,7 @@ config CPU_ARM940T
# ARM946E-S
config CPU_ARM946E
- bool "Support ARM946E-S processor" if ARCH_INTEGRATOR
+ bool "Support ARM946E-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
depends on !MMU
select CPU_32v5
select CPU_ABRT_NOMMU
@@ -198,7 +198,7 @@ config CPU_ARM946E
# ARM1020 - needs validating
config CPU_ARM1020
- bool "Support ARM1020T (rev 0) processor" if ARCH_INTEGRATOR
+ bool "Support ARM1020T (rev 0) processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
select CPU_32v5
select CPU_ABRT_EV4T
select CPU_CACHE_V4WT
@@ -216,7 +216,7 @@ config CPU_ARM1020
# ARM1020E - needs validating
config CPU_ARM1020E
- bool "Support ARM1020E processor" if ARCH_INTEGRATOR
+ bool "Support ARM1020E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
depends on n
select CPU_32v5
select CPU_ABRT_EV4T
@@ -229,7 +229,7 @@ config CPU_ARM1020E
# ARM1022E
config CPU_ARM1022
- bool "Support ARM1022E processor" if ARCH_INTEGRATOR
+ bool "Support ARM1022E processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
select CPU_32v5
select CPU_ABRT_EV4T
select CPU_CACHE_VIVT
@@ -247,7 +247,7 @@ config CPU_ARM1022
# ARM1026EJ-S
config CPU_ARM1026
- bool "Support ARM1026EJ-S processor" if ARCH_INTEGRATOR
+ bool "Support ARM1026EJ-S processor" if (ARCH_MULTI_V5 && ARCH_INTEGRATOR)
select CPU_32v5
select CPU_ABRT_EV5T # But need Jazelle, but EV5TJ ignores bit 10
select CPU_CACHE_VIVT
@@ -358,7 +358,7 @@ config CPU_PJ4B
# ARMv6
config CPU_V6
- bool "Support ARM V6 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
+ bool "Support ARM V6 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
select CPU_32v6
select CPU_ABRT_EV6
select CPU_CACHE_V6
@@ -371,7 +371,7 @@ config CPU_V6
# ARMv6k
config CPU_V6K
- bool "Support ARM V6K processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
+ bool "Support ARM V6K processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V6) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
select CPU_32v6
select CPU_32v6K
select CPU_ABRT_EV6
@@ -385,7 +385,7 @@ config CPU_V6K
# ARMv7
config CPU_V7
- bool "Support ARM V7 processor" if ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX
+ bool "Support ARM V7 processor" if (!ARCH_MULTIPLATFORM || ARCH_MULTI_V7) && (ARCH_INTEGRATOR || MACH_REALVIEW_EB || MACH_REALVIEW_PBX)
select CPU_32v6K
select CPU_32v7
select CPU_ABRT_EV7
diff --git a/arch/arm/plat-orion/gpio.c b/arch/arm/plat-orion/gpio.c
index e048f61..5168a52 100644
--- a/arch/arm/plat-orion/gpio.c
+++ b/arch/arm/plat-orion/gpio.c
@@ -306,9 +306,10 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
#define ORION_BLINK_HALF_PERIOD 100 /* ms */
-int orion_gpio_led_blink_set(unsigned gpio, int state,
+int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off)
{
+ unsigned gpio = desc_to_gpio(desc);
if (delay_on && delay_off && !*delay_on && !*delay_off)
*delay_on = *delay_off = ORION_BLINK_HALF_PERIOD;
@@ -505,9 +506,9 @@ static void orion_gpio_unmask_irq(struct irq_data *d)
u32 mask = d->mask;
irq_gc_lock(gc);
- reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask);
+ reg_val = irq_reg_readl(gc, ct->regs.mask);
reg_val |= mask;
- irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask);
+ irq_reg_writel(gc, reg_val, ct->regs.mask);
irq_gc_unlock(gc);
}
@@ -519,9 +520,9 @@ static void orion_gpio_mask_irq(struct irq_data *d)
u32 reg_val;
irq_gc_lock(gc);
- reg_val = irq_reg_readl(gc->reg_base + ct->regs.mask);
+ reg_val = irq_reg_readl(gc, ct->regs.mask);
reg_val &= ~mask;
- irq_reg_writel(reg_val, gc->reg_base + ct->regs.mask);
+ irq_reg_writel(gc, reg_val, ct->regs.mask);
irq_gc_unlock(gc);
}
diff --git a/arch/arm/plat-orion/include/plat/orion-gpio.h b/arch/arm/plat-orion/include/plat/orion-gpio.h
index e763988..e856b073a 100644
--- a/arch/arm/plat-orion/include/plat/orion-gpio.h
+++ b/arch/arm/plat-orion/include/plat/orion-gpio.h
@@ -14,12 +14,15 @@
#include <linux/init.h>
#include <linux/types.h>
#include <linux/irqdomain.h>
+
+struct gpio_desc;
+
/*
* Orion-specific GPIO API extensions.
*/
void orion_gpio_set_unused(unsigned pin);
void orion_gpio_set_blink(unsigned pin, int blink);
-int orion_gpio_led_blink_set(unsigned gpio, int state,
+int orion_gpio_led_blink_set(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
#define GPIO_INPUT_OK (1 << 0)
diff --git a/arch/arm/plat-samsung/Makefile b/arch/arm/plat-samsung/Makefile
index f0a0084..87746c3 100644
--- a/arch/arm/plat-samsung/Makefile
+++ b/arch/arm/plat-samsung/Makefile
@@ -35,6 +35,7 @@ obj-$(CONFIG_SAMSUNG_DMADEV) += dma-ops.o
# PM support
obj-$(CONFIG_PM_SLEEP) += pm-common.o
+obj-$(CONFIG_EXYNOS_CPU_SUSPEND) += pm-common.o
obj-$(CONFIG_SAMSUNG_PM) += pm.o
obj-$(CONFIG_SAMSUNG_PM_GPIO) += pm-gpio.o
obj-$(CONFIG_SAMSUNG_PM_CHECK) += pm-check.o
diff --git a/arch/arm/plat-samsung/include/plat/map-s5p.h b/arch/arm/plat-samsung/include/plat/map-s5p.h
index f5b9d3f..f5cf2bd 100644
--- a/arch/arm/plat-samsung/include/plat/map-s5p.h
+++ b/arch/arm/plat-samsung/include/plat/map-s5p.h
@@ -15,43 +15,22 @@
#define S5P_VA_CHIPID S3C_ADDR(0x02000000)
#define S5P_VA_CMU S3C_ADDR(0x02100000)
-#define S5P_VA_GPIO S3C_ADDR(0x02200000)
-#define S5P_VA_GPIO1 S5P_VA_GPIO
-#define S5P_VA_GPIO2 S3C_ADDR(0x02240000)
-#define S5P_VA_GPIO3 S3C_ADDR(0x02280000)
-#define S5P_VA_SYSRAM S3C_ADDR(0x02400000)
-#define S5P_VA_SYSRAM_NS S3C_ADDR(0x02410000)
#define S5P_VA_DMC0 S3C_ADDR(0x02440000)
#define S5P_VA_DMC1 S3C_ADDR(0x02480000)
#define S5P_VA_SROMC S3C_ADDR(0x024C0000)
-#define S5P_VA_SYSTIMER S3C_ADDR(0x02500000)
-#define S5P_VA_L2CC S3C_ADDR(0x02600000)
-
-#define S5P_VA_COMBINER_BASE S3C_ADDR(0x02700000)
-#define S5P_VA_COMBINER(x) (S5P_VA_COMBINER_BASE + ((x) >> 2) * 0x10)
-
#define S5P_VA_COREPERI_BASE S3C_ADDR(0x02800000)
#define S5P_VA_COREPERI(x) (S5P_VA_COREPERI_BASE + (x))
#define S5P_VA_SCU S5P_VA_COREPERI(0x0)
#define S5P_VA_TWD S5P_VA_COREPERI(0x600)
-#define S5P_VA_GIC_CPU S3C_ADDR(0x02810000)
-#define S5P_VA_GIC_DIST S3C_ADDR(0x02820000)
-
#define VA_VIC(x) (S3C_VA_IRQ + ((x) * 0x10000))
#define VA_VIC0 VA_VIC(0)
#define VA_VIC1 VA_VIC(1)
#define VA_VIC2 VA_VIC(2)
#define VA_VIC3 VA_VIC(3)
-#define S5P_VA_UART(x) (S3C_VA_UART + ((x) * S3C_UART_OFFSET))
-#define S5P_VA_UART0 S5P_VA_UART(0)
-#define S5P_VA_UART1 S5P_VA_UART(1)
-#define S5P_VA_UART2 S5P_VA_UART(2)
-#define S5P_VA_UART3 S5P_VA_UART(3)
-
#ifndef S3C_UART_OFFSET
#define S3C_UART_OFFSET (0x400)
#endif
diff --git a/arch/arm/plat-versatile/Kconfig b/arch/arm/plat-versatile/Kconfig
index a301ca2..49b8ef9 100644
--- a/arch/arm/plat-versatile/Kconfig
+++ b/arch/arm/plat-versatile/Kconfig
@@ -4,6 +4,6 @@ config PLAT_VERSATILE_CLOCK
bool
config PLAT_VERSATILE_SCHED_CLOCK
- def_bool y
+ bool
endif
diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 9532f8d..6b1ebd9 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -24,9 +24,9 @@ config ARM64
select GENERIC_CLOCKEVENTS_BROADCAST if SMP
select GENERIC_CPU_AUTOPROBE
select GENERIC_EARLY_IOREMAP
- select GENERIC_IOMAP
select GENERIC_IRQ_PROBE
select GENERIC_IRQ_SHOW
+ select GENERIC_PCI_IOMAP
select GENERIC_SCHED_CLOCK
select GENERIC_SMP_IDLE_THREAD
select GENERIC_STRNCPY_FROM_USER
@@ -34,13 +34,16 @@ config ARM64
select GENERIC_TIME_VSYSCALL
select HANDLE_DOMAIN_IRQ
select HARDIRQS_SW_RESEND
+ select HAVE_ALIGNED_STRUCT_PAGE if SLUB
select HAVE_ARCH_AUDITSYSCALL
select HAVE_ARCH_JUMP_LABEL
select HAVE_ARCH_KGDB
+ select HAVE_ARCH_SECCOMP_FILTER
select HAVE_ARCH_TRACEHOOK
select HAVE_BPF_JIT
select HAVE_C_RECORDMCOUNT
select HAVE_CC_STACKPROTECTOR
+ select HAVE_CMPXCHG_DOUBLE
select HAVE_DEBUG_BUGVERBOSE
select HAVE_DEBUG_KMEMLEAK
select HAVE_DMA_API_DEBUG
@@ -142,6 +145,11 @@ source "kernel/Kconfig.freezer"
menu "Platform selection"
+config ARCH_SEATTLE
+ bool "AMD Seattle SoC Family"
+ help
+ This enables support for AMD Seattle SOC Family
+
config ARCH_THUNDER
bool "Cavium Inc. Thunder SoC Family"
help
@@ -166,9 +174,6 @@ endmenu
menu "Bus support"
-config ARM_AMBA
- bool
-
config PCI
bool "PCI support"
help
@@ -193,6 +198,114 @@ endmenu
menu "Kernel Features"
+menu "ARM errata workarounds via the alternatives framework"
+
+config ARM64_ERRATUM_826319
+ bool "Cortex-A53: 826319: System might deadlock if a write cannot complete until read data is accepted"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 826319 on Cortex-A53 parts up to r0p2 with an AMBA 4 ACE or
+ AXI master interface and an L2 cache.
+
+ If a Cortex-A53 uses an AMBA AXI4 ACE interface to other processors
+ and is unable to accept a certain write via this interface, it will
+ not progress on read data presented on the read data channel and the
+ system can deadlock.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_827319
+ bool "Cortex-A53: 827319: Data cache clean instructions might cause overlapping transactions to the interconnect"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 827319 on Cortex-A53 parts up to r0p2 with an AMBA 5 CHI
+ master interface and an L2 cache.
+
+ Under certain conditions this erratum can cause a clean line eviction
+ to occur at the same time as another transaction to the same address
+ on the AMBA 5 CHI interface, which can cause data corruption if the
+ interconnect reorders the two transactions.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_824069
+ bool "Cortex-A53: 824069: Cache line might not be marked as clean after a CleanShared snoop"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 824069 on Cortex-A53 parts up to r0p2 when it is connected
+ to a coherent interconnect.
+
+ If a Cortex-A53 processor is executing a store or prefetch for
+ write instruction at the same time as a processor in another
+ cluster is executing a cache maintenance operation to the same
+ address, then this erratum might cause a clean cache line to be
+ incorrectly marked as dirty.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this option does not necessarily enable the
+ workaround, as it depends on the alternative framework, which will
+ only patch the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_819472
+ bool "Cortex-A53: 819472: Store exclusive instructions might cause data corruption"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 819472 on Cortex-A53 parts up to r0p1 with an L2 cache
+ present when it is connected to a coherent interconnect.
+
+ If the processor is executing a load and store exclusive sequence at
+ the same time as a processor in another cluster is executing a cache
+ maintenance operation to the same address, then this erratum might
+ cause data corruption.
+
+ The workaround promotes data cache clean instructions to
+ data cache clean-and-invalidate.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+config ARM64_ERRATUM_832075
+ bool "Cortex-A57: 832075: possible deadlock on mixing exclusive memory accesses with device loads"
+ default y
+ help
+ This option adds an alternative code sequence to work around ARM
+ erratum 832075 on Cortex-A57 parts up to r1p2.
+
+ Affected Cortex-A57 parts might deadlock when exclusive load/store
+ instructions to Write-Back memory are mixed with Device loads.
+
+ The workaround is to promote device loads to use Load-Acquire
+ semantics.
+ Please note that this does not necessarily enable the workaround,
+ as it depends on the alternative framework, which will only patch
+ the kernel if an affected CPU is detected.
+
+ If unsure, say Y.
+
+endmenu
+
+
choice
prompt "Page size"
default ARM64_4K_PAGES
@@ -345,6 +458,19 @@ config ARCH_HAS_CACHE_LINE_SIZE
source "mm/Kconfig"
+config SECCOMP
+ bool "Enable seccomp to safely compute untrusted bytecode"
+ ---help---
+ This kernel feature is useful for number crunching applications
+ that may need to compute untrusted bytecode during their
+ execution. By using pipes or other transports made available to
+ the process as file descriptors supporting the read/write
+ syscalls, it's possible to isolate those applications in
+ their own address space using seccomp. Once seccomp is
+ enabled via prctl(PR_SET_SECCOMP), it cannot be disabled
+ and the task is only allowed to execute a few safe syscalls
+ defined by each seccomp mode.
+
config XEN_DOM0
def_bool y
depends on XEN
@@ -361,6 +487,58 @@ config FORCE_MAX_ZONEORDER
default "14" if (ARM64_64K_PAGES && TRANSPARENT_HUGEPAGE)
default "11"
+menuconfig ARMV8_DEPRECATED
+ bool "Emulate deprecated/obsolete ARMv8 instructions"
+ depends on COMPAT
+ help
+ Legacy software support may require certain instructions
+ that have been deprecated or obsoleted in the architecture.
+
+ Enable this config to enable selective emulation of these
+ features.
+
+ If unsure, say Y
+
+if ARMV8_DEPRECATED
+
+config SWP_EMULATION
+ bool "Emulate SWP/SWPB instructions"
+ help
+ ARMv8 obsoletes the use of A32 SWP/SWPB instructions such that
+ they are always undefined. Say Y here to enable software
+ emulation of these instructions for userspace using LDXR/STXR.
+
+ In some older versions of glibc [<=2.8] SWP is used during futex
+ trylock() operations with the assumption that the code will not
+ be preempted. This invalid assumption may be more likely to fail
+ with SWP emulation enabled, leading to deadlock of the user
+ application.
+
+ NOTE: when accessing uncached shared regions, LDXR/STXR rely
+ on an external transaction monitoring block called a global
+ monitor to maintain update atomicity. If your system does not
+ implement a global monitor, this option can cause programs that
+ perform SWP operations to uncached memory to deadlock.
+
+ If unsure, say Y
+
+config CP15_BARRIER_EMULATION
+ bool "Emulate CP15 Barrier instructions"
+ help
+ The CP15 barrier instructions - CP15ISB, CP15DSB, and
+ CP15DMB - are deprecated in ARMv8 (and ARMv7). It is
+ strongly recommended to use the ISB, DSB, and DMB
+ instructions instead.
+
+ Say Y here to enable software emulation of these
+ instructions for AArch32 userspace code. When this option is
+ enabled, CP15 barrier usage is traced which can help
+ identify software that needs updating.
+
+ If unsure, say Y
+
+endif
+
endmenu
menu "Boot options"
@@ -401,6 +579,17 @@ config EFI
allow the kernel to be booted as an EFI application. This
is only useful on systems that have UEFI firmware.
+config DMI
+ bool "Enable support for SMBIOS (DMI) tables"
+ depends on EFI
+ default y
+ help
+ This enables SMBIOS/DMI feature for systems.
+
+ This option is only useful on systems that have UEFI firmware.
+ However, even with this option, the resultant kernel should
+ continue to boot on existing non-UEFI platforms.
+
endmenu
menu "Userspace binary formats"
diff --git a/arch/arm64/Kconfig.debug b/arch/arm64/Kconfig.debug
index 0a12933..5fdd6dc 100644
--- a/arch/arm64/Kconfig.debug
+++ b/arch/arm64/Kconfig.debug
@@ -6,6 +6,18 @@ config FRAME_POINTER
bool
default y
+config ARM64_PTDUMP
+ bool "Export kernel pagetable layout to userspace via debugfs"
+ depends on DEBUG_KERNEL
+ select DEBUG_FS
+ help
+ Say Y here if you want to show the kernel pagetable layout in a
+ debugfs file. This information is only useful for kernel developers
+ who are working in architecture specific areas of the kernel.
+ It is probably not a good idea to enable this feature in a production
+ kernel.
+ If in doubt, say "N"
+
config STRICT_DEVMEM
bool "Filter access to /dev/mem"
depends on MMU
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 20901ff..1c43cec 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -70,8 +70,13 @@ zinstall install: vmlinux
%.dtb: scripts
$(Q)$(MAKE) $(build)=$(boot)/dts $(boot)/dts/$@
-dtbs: scripts
- $(Q)$(MAKE) $(build)=$(boot)/dts dtbs
+PHONY += dtbs dtbs_install
+
+dtbs: prepare scripts
+ $(Q)$(MAKE) $(build)=$(boot)/dts
+
+dtbs_install:
+ $(Q)$(MAKE) $(dtbinst)=$(boot)/dts
PHONY += vdso_install
vdso_install:
@@ -85,6 +90,7 @@ define archhelp
echo '* Image.gz - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
echo ' Image - Uncompressed kernel image (arch/$(ARCH)/boot/Image)'
echo '* dtbs - Build device tree blobs for enabled boards'
+ echo ' dtbs_install - Install dtbs to $(INSTALL_DTBS_PATH)'
echo ' install - Install uncompressed kernel'
echo ' zinstall - Install compressed kernel'
echo ' Install using (your) ~/bin/installkernel or'
diff --git a/arch/arm64/boot/dts/Makefile b/arch/arm64/boot/dts/Makefile
index f8001a6..3b8d427 100644
--- a/arch/arm64/boot/dts/Makefile
+++ b/arch/arm64/boot/dts/Makefile
@@ -1,10 +1,8 @@
-dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb
-dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb foundation-v8.dtb
-dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
+dts-dirs += amd
+dts-dirs += apm
+dts-dirs += arm
+dts-dirs += cavium
-targets += dtbs
-targets += $(dtb-y)
-
-dtbs: $(addprefix $(obj)/, $(dtb-y))
-
-clean-files := *.dtb
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/amd/Makefile b/arch/arm64/boot/dts/amd/Makefile
new file mode 100644
index 0000000..cfdf701
--- /dev/null
+++ b/arch/arm64/boot/dts/amd/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_SEATTLE) += amd-overdrive.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/amd/amd-overdrive.dts b/arch/arm64/boot/dts/amd/amd-overdrive.dts
new file mode 100644
index 0000000..564a3f7
--- /dev/null
+++ b/arch/arm64/boot/dts/amd/amd-overdrive.dts
@@ -0,0 +1,66 @@
+/*
+ * DTS file for AMD Seattle Overdrive Development Board
+ *
+ * Copyright (C) 2014 Advanced Micro Devices, Inc.
+ */
+
+/dts-v1/;
+
+/include/ "amd-seattle-soc.dtsi"
+
+/ {
+ model = "AMD Seattle Development Board (Overdrive)";
+ compatible = "amd,seattle-overdrive", "amd,seattle";
+
+ chosen {
+ stdout-path = &serial0;
+ linux,pci-probe-only;
+ };
+};
+
+&ccp0 {
+ status = "ok";
+};
+
+&gpio0 {
+ status = "ok";
+};
+
+&gpio1 {
+ status = "ok";
+};
+
+&i2c0 {
+ status = "ok";
+};
+
+&pcie0 {
+ status = "ok";
+};
+
+&spi0 {
+ status = "ok";
+};
+
+&spi1 {
+ status = "ok";
+ sdcard0: sdcard@0 {
+ compatible = "mmc-spi-slot";
+ reg = <0>;
+ spi-max-frequency = <20000000>;
+ voltage-ranges = <3200 3400>;
+ gpios = <&gpio0 7 0>;
+ interrupt-parent = <&gpio0>;
+ interrupts = <7 3>;
+ pl022,hierarchy = <0>;
+ pl022,interface = <0>;
+ pl022,com-mode = <0x0>;
+ pl022,rx-level-trig = <0>;
+ pl022,tx-level-trig = <0>;
+ };
+};
+
+&v2m0 {
+ arm,msi-base-spi = <64>;
+ arm,msi-num-spis = <256>;
+};
diff --git a/arch/arm64/boot/dts/amd/amd-seattle-clks.dtsi b/arch/arm64/boot/dts/amd/amd-seattle-clks.dtsi
new file mode 100644
index 0000000..f623c46
--- /dev/null
+++ b/arch/arm64/boot/dts/amd/amd-seattle-clks.dtsi
@@ -0,0 +1,54 @@
+/*
+ * DTS file for AMD Seattle Clocks
+ *
+ * Copyright (C) 2014 Advanced Micro Devices, Inc.
+ */
+
+ adl3clk_100mhz: clk100mhz_0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "adl3clk_100mhz";
+ };
+
+ ccpclk_375mhz: clk375mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <375000000>;
+ clock-output-names = "ccpclk_375mhz";
+ };
+
+ sataclk_333mhz: clk333mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <333000000>;
+ clock-output-names = "sataclk_333mhz";
+ };
+
+ pcieclk_500mhz: clk500mhz_0 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <500000000>;
+ clock-output-names = "pcieclk_500mhz";
+ };
+
+ dmaclk_500mhz: clk500mhz_1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <500000000>;
+ clock-output-names = "dmaclk_500mhz";
+ };
+
+ miscclk_250mhz: clk250mhz_4 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <250000000>;
+ clock-output-names = "miscclk_250mhz";
+ };
+
+ uartspiclk_100mhz: clk100mhz_1 {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "uartspiclk_100mhz";
+ };
diff --git a/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi b/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi
new file mode 100644
index 0000000..2874d92
--- /dev/null
+++ b/arch/arm64/boot/dts/amd/amd-seattle-soc.dtsi
@@ -0,0 +1,172 @@
+/*
+ * DTS file for AMD Seattle SoC
+ *
+ * Copyright (C) 2014 Advanced Micro Devices, Inc.
+ */
+
+/ {
+ compatible = "amd,seattle";
+ interrupt-parent = <&gic0>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ gic0: interrupt-controller@e1101000 {
+ compatible = "arm,gic-400", "arm,cortex-a15-gic";
+ interrupt-controller;
+ #interrupt-cells = <3>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+ reg = <0x0 0xe1110000 0 0x1000>,
+ <0x0 0xe112f000 0 0x2000>,
+ <0x0 0xe1140000 0 0x10000>,
+ <0x0 0xe1160000 0 0x10000>;
+ interrupts = <1 9 0xf04>;
+ ranges = <0 0 0 0xe1100000 0 0x100000>;
+ v2m0: v2m@e0080000 {
+ compatible = "arm,gic-v2m-frame";
+ msi-controller;
+ reg = <0x0 0x00080000 0 0x1000>;
+ };
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <1 13 0xff04>,
+ <1 14 0xff04>,
+ <1 11 0xff04>,
+ <1 10 0xff04>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <0 7 4>,
+ <0 8 4>,
+ <0 9 4>,
+ <0 10 4>,
+ <0 11 4>,
+ <0 12 4>,
+ <0 13 4>,
+ <0 14 4>;
+ };
+
+ smb0: smb {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <2>;
+ ranges;
+
+ /* DDR range is 40-bit addressing */
+ dma-ranges = <0x80 0x0 0x80 0x0 0x7f 0xffffffff>;
+
+ /include/ "amd-seattle-clks.dtsi"
+
+ sata0: sata@e0300000 {
+ compatible = "snps,dwc-ahci";
+ reg = <0 0xe0300000 0 0x800>;
+ interrupts = <0 355 4>;
+ clocks = <&sataclk_333mhz>;
+ dma-coherent;
+ };
+
+ i2c0: i2c@e1000000 {
+ status = "disabled";
+ compatible = "snps,designware-i2c";
+ reg = <0 0xe1000000 0 0x1000>;
+ interrupts = <0 357 4>;
+ clocks = <&uartspiclk_100mhz>;
+ };
+
+ serial0: serial@e1010000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0 0xe1010000 0 0x1000>;
+ interrupts = <0 328 4>;
+ clocks = <&uartspiclk_100mhz>, <&uartspiclk_100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ spi0: ssp@e1020000 {
+ status = "disabled";
+ compatible = "arm,pl022", "arm,primecell";
+ #gpio-cells = <2>;
+ reg = <0 0xe1020000 0 0x1000>;
+ spi-controller;
+ interrupts = <0 330 4>;
+ clocks = <&uartspiclk_100mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ spi1: ssp@e1030000 {
+ status = "disabled";
+ compatible = "arm,pl022", "arm,primecell";
+ #gpio-cells = <2>;
+ reg = <0 0xe1030000 0 0x1000>;
+ spi-controller;
+ interrupts = <0 329 4>;
+ clocks = <&uartspiclk_100mhz>;
+ clock-names = "apb_pclk";
+ num-cs = <1>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
+ gpio0: gpio@e1040000 {
+ status = "disabled";
+ compatible = "arm,pl061", "arm,primecell";
+ #gpio-cells = <2>;
+ reg = <0 0xe1040000 0 0x1000>;
+ gpio-controller;
+ interrupts = <0 359 4>;
+ interrupt-controller;
+ #interrupt-cells = <2>;
+ clocks = <&uartspiclk_100mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ gpio1: gpio@e1050000 {
+ status = "disabled";
+ compatible = "arm,pl061", "arm,primecell";
+ #gpio-cells = <2>;
+ reg = <0 0xe1050000 0 0x1000>;
+ gpio-controller;
+ interrupts = <0 358 4>;
+ clocks = <&uartspiclk_100mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ ccp0: ccp@e0100000 {
+ status = "disabled";
+ compatible = "amd,ccp-seattle-v1a";
+ reg = <0 0xe0100000 0 0x10000>;
+ interrupts = <0 3 4>;
+ dma-coherent;
+ };
+
+ pcie0: pcie@f0000000 {
+ compatible = "pci-host-ecam-generic";
+ #address-cells = <3>;
+ #size-cells = <2>;
+ #interrupt-cells = <1>;
+ device_type = "pci";
+ bus-range = <0 0x7f>;
+ msi-parent = <&v2m0>;
+ reg = <0 0xf0000000 0 0x10000000>;
+
+ interrupt-map-mask = <0xf800 0x0 0x0 0x7>;
+ interrupt-map =
+ <0x1000 0x0 0x0 0x1 &gic0 0x0 0x0 0x0 0x120 0x1>,
+ <0x1000 0x0 0x0 0x2 &gic0 0x0 0x0 0x0 0x121 0x1>,
+ <0x1000 0x0 0x0 0x3 &gic0 0x0 0x0 0x0 0x122 0x1>,
+ <0x1000 0x0 0x0 0x4 &gic0 0x0 0x0 0x0 0x123 0x1>;
+
+ dma-coherent;
+ dma-ranges = <0x43000000 0x80 0x0 0x80 0x0 0x7f 0xffffffff>;
+ ranges =
+ /* I/O Memory (size=64K) */
+ <0x01000000 0x00 0x00000000 0x00 0xefff0000 0x00 0x00010000>,
+ /* 32-bit MMIO (size=2G) */
+ <0x02000000 0x00 0x40000000 0x00 0x40000000 0x00 0x80000000>,
+ /* 64-bit MMIO (size= 124G) */
+ <0x03000000 0x01 0x00000000 0x01 0x00000000 0x7f 0x00000000>;
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/apm/Makefile b/arch/arm64/boot/dts/apm/Makefile
new file mode 100644
index 0000000..a2afabb
--- /dev/null
+++ b/arch/arm64/boot/dts/apm/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_XGENE) += apm-mustang.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/apm-mustang.dts b/arch/arm64/boot/dts/apm/apm-mustang.dts
index 2e25de08..2e25de08 100644
--- a/arch/arm64/boot/dts/apm-mustang.dts
+++ b/arch/arm64/boot/dts/apm/apm-mustang.dts
diff --git a/arch/arm64/boot/dts/apm-storm.dtsi b/arch/arm64/boot/dts/apm/apm-storm.dtsi
index f1ad9c2..f1ad9c2 100644
--- a/arch/arm64/boot/dts/apm-storm.dtsi
+++ b/arch/arm64/boot/dts/apm/apm-storm.dtsi
diff --git a/arch/arm64/boot/dts/arm/Makefile b/arch/arm64/boot/dts/arm/Makefile
new file mode 100644
index 0000000..301a0da
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/Makefile
@@ -0,0 +1,7 @@
+dtb-$(CONFIG_ARCH_VEXPRESS) += foundation-v8.dtb
+dtb-$(CONFIG_ARCH_VEXPRESS) += juno.dtb
+dtb-$(CONFIG_ARCH_VEXPRESS) += rtsm_ve-aemv8a.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/foundation-v8.dts b/arch/arm64/boot/dts/arm/foundation-v8.dts
index 4a06090..27f3296 100644
--- a/arch/arm64/boot/dts/foundation-v8.dts
+++ b/arch/arm64/boot/dts/arm/foundation-v8.dts
@@ -78,10 +78,10 @@
timer {
compatible = "arm,armv8-timer";
- interrupts = <1 13 0xff01>,
- <1 14 0xff01>,
- <1 11 0xff01>,
- <1 10 0xff01>;
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
clock-frequency = <100000000>;
};
diff --git a/arch/arm64/boot/dts/arm/juno-clocks.dtsi b/arch/arm64/boot/dts/arm/juno-clocks.dtsi
new file mode 100644
index 0000000..ea2b566
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/juno-clocks.dtsi
@@ -0,0 +1,44 @@
+/*
+ * ARM Juno Platform clocks
+ *
+ * Copyright (c) 2013-2014 ARM Ltd
+ *
+ * This file is licensed under a dual GPLv2 or BSD license.
+ *
+ */
+
+ /* SoC fixed clocks */
+ soc_uartclk: refclk72738khz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <7273800>;
+ clock-output-names = "juno:uartclk";
+ };
+
+ soc_usb48mhz: clk48mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <48000000>;
+ clock-output-names = "clk48mhz";
+ };
+
+ soc_smc50mhz: clk50mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <50000000>;
+ clock-output-names = "smc_clk";
+ };
+
+ soc_refclk100mhz: refclk100mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <100000000>;
+ clock-output-names = "apb_pclk";
+ };
+
+ soc_faxiclk: refclk533mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <533000000>;
+ clock-output-names = "faxi_clk";
+ };
diff --git a/arch/arm64/boot/dts/arm/juno-motherboard.dtsi b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
new file mode 100644
index 0000000..c138b95
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/juno-motherboard.dtsi
@@ -0,0 +1,129 @@
+/*
+ * ARM Juno Platform motherboard peripherals
+ *
+ * Copyright (c) 2013-2014 ARM Ltd
+ *
+ * This file is licensed under a dual GPLv2 or BSD license.
+ *
+ */
+
+ mb_clk24mhz: clk24mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <24000000>;
+ clock-output-names = "juno_mb:clk24mhz";
+ };
+
+ mb_clk25mhz: clk25mhz {
+ compatible = "fixed-clock";
+ #clock-cells = <0>;
+ clock-frequency = <25000000>;
+ clock-output-names = "juno_mb:clk25mhz";
+ };
+
+ motherboard {
+ compatible = "arm,vexpress,v2p-p1", "simple-bus";
+ #address-cells = <2>; /* SMB chipselect number and offset */
+ #size-cells = <1>;
+ #interrupt-cells = <1>;
+ ranges;
+ model = "V2M-Juno";
+ arm,hbi = <0x252>;
+ arm,vexpress,site = <0>;
+ arm,v2m-memory-map = "rs1";
+
+ mb_fixed_3v3: fixedregulator@0 {
+ compatible = "regulator-fixed";
+ regulator-name = "MCC_SB_3V3";
+ regulator-min-microvolt = <3300000>;
+ regulator-max-microvolt = <3300000>;
+ regulator-always-on;
+ };
+
+ ethernet@2,00000000 {
+ compatible = "smsc,lan9118", "smsc,lan9115";
+ reg = <2 0x00000000 0x10000>;
+ interrupts = <3>;
+ phy-mode = "mii";
+ reg-io-width = <4>;
+ smsc,irq-active-high;
+ smsc,irq-push-pull;
+ clocks = <&mb_clk25mhz>;
+ vdd33a-supply = <&mb_fixed_3v3>;
+ vddvario-supply = <&mb_fixed_3v3>;
+ };
+
+ usb@5,00000000 {
+ compatible = "nxp,usb-isp1763";
+ reg = <5 0x00000000 0x20000>;
+ bus-width = <16>;
+ interrupts = <4>;
+ };
+
+ iofpga@3,00000000 {
+ compatible = "arm,amba-bus", "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0 3 0 0x200000>;
+
+ mmci@050000 {
+ compatible = "arm,pl180", "arm,primecell";
+ reg = <0x050000 0x1000>;
+ interrupts = <5>;
+ /* cd-gpios = <&v2m_mmc_gpios 0 0>;
+ wp-gpios = <&v2m_mmc_gpios 1 0>; */
+ max-frequency = <12000000>;
+ vmmc-supply = <&mb_fixed_3v3>;
+ clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
+ clock-names = "mclk", "apb_pclk";
+ };
+
+ kmi@060000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x060000 0x1000>;
+ interrupts = <8>;
+ clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ kmi@070000 {
+ compatible = "arm,pl050", "arm,primecell";
+ reg = <0x070000 0x1000>;
+ interrupts = <8>;
+ clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
+ clock-names = "KMIREFCLK", "apb_pclk";
+ };
+
+ wdt@0f0000 {
+ compatible = "arm,sp805", "arm,primecell";
+ reg = <0x0f0000 0x10000>;
+ interrupts = <7>;
+ clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
+ clock-names = "wdogclk", "apb_pclk";
+ };
+
+ v2m_timer01: timer@110000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x110000 0x10000>;
+ interrupts = <9>;
+ clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
+ clock-names = "timclken1", "apb_pclk";
+ };
+
+ v2m_timer23: timer@120000 {
+ compatible = "arm,sp804", "arm,primecell";
+ reg = <0x120000 0x10000>;
+ interrupts = <9>;
+ clocks = <&mb_clk24mhz>, <&soc_smc50mhz>;
+ clock-names = "timclken1", "apb_pclk";
+ };
+
+ rtc@170000 {
+ compatible = "arm,pl031", "arm,primecell";
+ reg = <0x170000 0x10000>;
+ interrupts = <0>;
+ clocks = <&soc_smc50mhz>;
+ clock-names = "apb_pclk";
+ };
+ };
+ };
diff --git a/arch/arm64/boot/dts/arm/juno.dts b/arch/arm64/boot/dts/arm/juno.dts
new file mode 100644
index 0000000..cb3073e
--- /dev/null
+++ b/arch/arm64/boot/dts/arm/juno.dts
@@ -0,0 +1,218 @@
+/*
+ * ARM Ltd. Juno Platform
+ *
+ * Copyright (c) 2013-2014 ARM Ltd.
+ *
+ * This file is licensed under a dual GPLv2 or BSD license.
+ */
+
+/dts-v1/;
+
+#include <dt-bindings/interrupt-controller/arm-gic.h>
+
+/ {
+ model = "ARM Juno development board (r0)";
+ compatible = "arm,juno", "arm,vexpress";
+ interrupt-parent = <&gic>;
+ #address-cells = <2>;
+ #size-cells = <2>;
+
+ aliases {
+ serial0 = &soc_uart0;
+ };
+
+ chosen {
+ stdout-path = &soc_uart0;
+ };
+
+ psci {
+ compatible = "arm,psci-0.2";
+ method = "smc";
+ };
+
+ cpus {
+ #address-cells = <2>;
+ #size-cells = <0>;
+
+ A57_0: cpu@0 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x0>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ A57_1: cpu@1 {
+ compatible = "arm,cortex-a57","arm,armv8";
+ reg = <0x0 0x1>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ A53_0: cpu@100 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x100>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ A53_1: cpu@101 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x101>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ A53_2: cpu@102 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x102>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+
+ A53_3: cpu@103 {
+ compatible = "arm,cortex-a53","arm,armv8";
+ reg = <0x0 0x103>;
+ device_type = "cpu";
+ enable-method = "psci";
+ };
+ };
+
+ memory@80000000 {
+ device_type = "memory";
+ /* last 16MB of the first memory area is reserved for secure world use by firmware */
+ reg = <0x00000000 0x80000000 0x0 0x7f000000>,
+ <0x00000008 0x80000000 0x1 0x80000000>;
+ };
+
+ gic: interrupt-controller@2c001000 {
+ compatible = "arm,gic-400", "arm,cortex-a15-gic";
+ reg = <0x0 0x2c010000 0 0x1000>,
+ <0x0 0x2c02f000 0 0x2000>,
+ <0x0 0x2c04f000 0 0x2000>,
+ <0x0 0x2c06f000 0 0x2000>;
+ #address-cells = <0>;
+ #interrupt-cells = <3>;
+ interrupt-controller;
+ interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_HIGH)>;
+ };
+
+ timer {
+ compatible = "arm,armv8-timer";
+ interrupts = <GIC_PPI 13 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 14 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 11 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>,
+ <GIC_PPI 10 (GIC_CPU_MASK_SIMPLE(6) | IRQ_TYPE_LEVEL_LOW)>;
+ };
+
+ pmu {
+ compatible = "arm,armv8-pmuv3";
+ interrupts = <GIC_SPI 18 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 26 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 30 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 02 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 06 IRQ_TYPE_LEVEL_HIGH>;
+ };
+
+ /include/ "juno-clocks.dtsi"
+
+ dma@7ff00000 {
+ compatible = "arm,pl330", "arm,primecell";
+ reg = <0x0 0x7ff00000 0 0x1000>;
+ #dma-cells = <1>;
+ #dma-channels = <8>;
+ #dma-requests = <32>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 89 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 90 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 91 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 108 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 109 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 110 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 111 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_faxiclk>;
+ clock-names = "apb_pclk";
+ };
+
+ soc_uart0: uart@7ff80000 {
+ compatible = "arm,pl011", "arm,primecell";
+ reg = <0x0 0x7ff80000 0x0 0x1000>;
+ interrupts = <GIC_SPI 83 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_uartclk>, <&soc_refclk100mhz>;
+ clock-names = "uartclk", "apb_pclk";
+ };
+
+ i2c@7ffa0000 {
+ compatible = "snps,designware-i2c";
+ reg = <0x0 0x7ffa0000 0x0 0x1000>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ interrupts = <GIC_SPI 104 IRQ_TYPE_LEVEL_HIGH>;
+ clock-frequency = <400000>;
+ i2c-sda-hold-time-ns = <500>;
+ clocks = <&soc_smc50mhz>;
+
+ dvi0: dvi-transmitter@70 {
+ compatible = "nxp,tda998x";
+ reg = <0x70>;
+ };
+
+ dvi1: dvi-transmitter@71 {
+ compatible = "nxp,tda998x";
+ reg = <0x71>;
+ };
+ };
+
+ ohci@7ffb0000 {
+ compatible = "generic-ohci";
+ reg = <0x0 0x7ffb0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 116 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_usb48mhz>;
+ };
+
+ ehci@7ffc0000 {
+ compatible = "generic-ehci";
+ reg = <0x0 0x7ffc0000 0x0 0x10000>;
+ interrupts = <GIC_SPI 117 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_usb48mhz>;
+ };
+
+ memory-controller@7ffd0000 {
+ compatible = "arm,pl354", "arm,primecell";
+ reg = <0 0x7ffd0000 0 0x1000>;
+ interrupts = <GIC_SPI 86 IRQ_TYPE_LEVEL_HIGH>,
+ <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&soc_smc50mhz>;
+ clock-names = "apb_pclk";
+ };
+
+ smb {
+ compatible = "simple-bus";
+ #address-cells = <2>;
+ #size-cells = <1>;
+ ranges = <0 0 0 0x08000000 0x04000000>,
+ <1 0 0 0x14000000 0x04000000>,
+ <2 0 0 0x18000000 0x04000000>,
+ <3 0 0 0x1c000000 0x04000000>,
+ <4 0 0 0x0c000000 0x04000000>,
+ <5 0 0 0x10000000 0x04000000>;
+
+ #interrupt-cells = <1>;
+ interrupt-map-mask = <0 0 15>;
+ interrupt-map = <0 0 0 &gic 0 68 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 1 &gic 0 69 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 2 &gic 0 70 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 3 &gic 0 160 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 4 &gic 0 161 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 5 &gic 0 162 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 6 &gic 0 163 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 7 &gic 0 164 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 8 &gic 0 165 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 9 &gic 0 166 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 10 &gic 0 167 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 11 &gic 0 168 IRQ_TYPE_LEVEL_HIGH>,
+ <0 0 12 &gic 0 169 IRQ_TYPE_LEVEL_HIGH>;
+
+ /include/ "juno-motherboard.dtsi"
+ };
+};
diff --git a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
index 572005e..efc59b3 100644
--- a/arch/arm64/boot/dts/rtsm_ve-aemv8a.dts
+++ b/arch/arm64/boot/dts/arm/rtsm_ve-aemv8a.dts
@@ -81,10 +81,10 @@
timer {
compatible = "arm,armv8-timer";
- interrupts = <1 13 0xff01>,
- <1 14 0xff01>,
- <1 11 0xff01>,
- <1 10 0xff01>;
+ interrupts = <1 13 0xf08>,
+ <1 14 0xf08>,
+ <1 11 0xf08>,
+ <1 10 0xf08>;
clock-frequency = <100000000>;
};
diff --git a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi
index c46cbb2..c46cbb2 100644
--- a/arch/arm64/boot/dts/rtsm_ve-motherboard.dtsi
+++ b/arch/arm64/boot/dts/arm/rtsm_ve-motherboard.dtsi
diff --git a/arch/arm64/boot/dts/cavium/Makefile b/arch/arm64/boot/dts/cavium/Makefile
new file mode 100644
index 0000000..e34f89d
--- /dev/null
+++ b/arch/arm64/boot/dts/cavium/Makefile
@@ -0,0 +1,5 @@
+dtb-$(CONFIG_ARCH_THUNDER) += thunder-88xx.dtb
+
+always := $(dtb-y)
+subdir-y := $(dts-dirs)
+clean-files := *.dtb
diff --git a/arch/arm64/boot/dts/thunder-88xx.dts b/arch/arm64/boot/dts/cavium/thunder-88xx.dts
index 800ba65..800ba65 100644
--- a/arch/arm64/boot/dts/thunder-88xx.dts
+++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dts
diff --git a/arch/arm64/boot/dts/thunder-88xx.dtsi b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
index d8c0bdc..d8c0bdc 100644
--- a/arch/arm64/boot/dts/thunder-88xx.dtsi
+++ b/arch/arm64/boot/dts/cavium/thunder-88xx.dtsi
diff --git a/arch/arm64/boot/dts/include/dt-bindings b/arch/arm64/boot/dts/include/dt-bindings
new file mode 120000
index 0000000..08c00e4
--- /dev/null
+++ b/arch/arm64/boot/dts/include/dt-bindings
@@ -0,0 +1 @@
+../../../../../include/dt-bindings \ No newline at end of file
diff --git a/arch/arm64/crypto/Kconfig b/arch/arm64/crypto/Kconfig
index 5562652..a38b02c 100644
--- a/arch/arm64/crypto/Kconfig
+++ b/arch/arm64/crypto/Kconfig
@@ -27,20 +27,19 @@ config CRYPTO_AES_ARM64_CE
tristate "AES core cipher using ARMv8 Crypto Extensions"
depends on ARM64 && KERNEL_MODE_NEON
select CRYPTO_ALGAPI
- select CRYPTO_AES
config CRYPTO_AES_ARM64_CE_CCM
tristate "AES in CCM mode using ARMv8 Crypto Extensions"
depends on ARM64 && KERNEL_MODE_NEON
select CRYPTO_ALGAPI
- select CRYPTO_AES
+ select CRYPTO_AES_ARM64_CE
select CRYPTO_AEAD
config CRYPTO_AES_ARM64_CE_BLK
tristate "AES in ECB/CBC/CTR/XTS modes using ARMv8 Crypto Extensions"
depends on ARM64 && KERNEL_MODE_NEON
select CRYPTO_BLKCIPHER
- select CRYPTO_AES
+ select CRYPTO_AES_ARM64_CE
select CRYPTO_ABLK_HELPER
config CRYPTO_AES_ARM64_NEON_BLK
diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c
index 9e6cdde9..0ac73b8 100644
--- a/arch/arm64/crypto/aes-ce-ccm-glue.c
+++ b/arch/arm64/crypto/aes-ce-ccm-glue.c
@@ -16,6 +16,8 @@
#include <linux/crypto.h>
#include <linux/module.h>
+#include "aes-ce-setkey.h"
+
static int num_rounds(struct crypto_aes_ctx *ctx)
{
/*
@@ -48,7 +50,7 @@ static int ccm_setkey(struct crypto_aead *tfm, const u8 *in_key,
struct crypto_aes_ctx *ctx = crypto_aead_ctx(tfm);
int ret;
- ret = crypto_aes_expand_key(ctx, in_key, key_len);
+ ret = ce_aes_expandkey(ctx, in_key, key_len);
if (!ret)
return 0;
diff --git a/arch/arm64/crypto/aes-ce-cipher.c b/arch/arm64/crypto/aes-ce-cipher.c
index 2075e1a..ce47792 100644
--- a/arch/arm64/crypto/aes-ce-cipher.c
+++ b/arch/arm64/crypto/aes-ce-cipher.c
@@ -14,6 +14,8 @@
#include <linux/crypto.h>
#include <linux/module.h>
+#include "aes-ce-setkey.h"
+
MODULE_DESCRIPTION("Synchronous AES cipher using ARMv8 Crypto Extensions");
MODULE_AUTHOR("Ard Biesheuvel <ard.biesheuvel@linaro.org>");
MODULE_LICENSE("GPL v2");
@@ -124,6 +126,114 @@ static void aes_cipher_decrypt(struct crypto_tfm *tfm, u8 dst[], u8 const src[])
kernel_neon_end();
}
+/*
+ * aes_sub() - use the aese instruction to perform the AES sbox substitution
+ * on each byte in 'input'
+ */
+static u32 aes_sub(u32 input)
+{
+ u32 ret;
+
+ __asm__("dup v1.4s, %w[in] ;"
+ "movi v0.16b, #0 ;"
+ "aese v0.16b, v1.16b ;"
+ "umov %w[out], v0.4s[0] ;"
+
+ : [out] "=r"(ret)
+ : [in] "r"(input)
+ : "v0","v1");
+
+ return ret;
+}
+
+int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
+ unsigned int key_len)
+{
+ /*
+ * The AES key schedule round constants
+ */
+ static u8 const rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36,
+ };
+
+ u32 kwords = key_len / sizeof(u32);
+ struct aes_block *key_enc, *key_dec;
+ int i, j;
+
+ if (key_len != AES_KEYSIZE_128 &&
+ key_len != AES_KEYSIZE_192 &&
+ key_len != AES_KEYSIZE_256)
+ return -EINVAL;
+
+ memcpy(ctx->key_enc, in_key, key_len);
+ ctx->key_length = key_len;
+
+ kernel_neon_begin_partial(2);
+ for (i = 0; i < sizeof(rcon); i++) {
+ u32 *rki = ctx->key_enc + (i * kwords);
+ u32 *rko = rki + kwords;
+
+ rko[0] = ror32(aes_sub(rki[kwords - 1]), 8) ^ rcon[i] ^ rki[0];
+ rko[1] = rko[0] ^ rki[1];
+ rko[2] = rko[1] ^ rki[2];
+ rko[3] = rko[2] ^ rki[3];
+
+ if (key_len == AES_KEYSIZE_192) {
+ if (i >= 7)
+ break;
+ rko[4] = rko[3] ^ rki[4];
+ rko[5] = rko[4] ^ rki[5];
+ } else if (key_len == AES_KEYSIZE_256) {
+ if (i >= 6)
+ break;
+ rko[4] = aes_sub(rko[3]) ^ rki[4];
+ rko[5] = rko[4] ^ rki[5];
+ rko[6] = rko[5] ^ rki[6];
+ rko[7] = rko[6] ^ rki[7];
+ }
+ }
+
+ /*
+ * Generate the decryption keys for the Equivalent Inverse Cipher.
+ * This involves reversing the order of the round keys, and applying
+ * the Inverse Mix Columns transformation on all but the first and
+ * the last one.
+ */
+ key_enc = (struct aes_block *)ctx->key_enc;
+ key_dec = (struct aes_block *)ctx->key_dec;
+ j = num_rounds(ctx);
+
+ key_dec[0] = key_enc[j];
+ for (i = 1, j--; j > 0; i++, j--)
+ __asm__("ld1 {v0.16b}, %[in] ;"
+ "aesimc v1.16b, v0.16b ;"
+ "st1 {v1.16b}, %[out] ;"
+
+ : [out] "=Q"(key_dec[i])
+ : [in] "Q"(key_enc[j])
+ : "v0","v1");
+ key_dec[i] = key_enc[0];
+
+ kernel_neon_end();
+ return 0;
+}
+EXPORT_SYMBOL(ce_aes_expandkey);
+
+int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len)
+{
+ struct crypto_aes_ctx *ctx = crypto_tfm_ctx(tfm);
+ int ret;
+
+ ret = ce_aes_expandkey(ctx, in_key, key_len);
+ if (!ret)
+ return 0;
+
+ tfm->crt_flags |= CRYPTO_TFM_RES_BAD_KEY_LEN;
+ return -EINVAL;
+}
+EXPORT_SYMBOL(ce_aes_setkey);
+
static struct crypto_alg aes_alg = {
.cra_name = "aes",
.cra_driver_name = "aes-ce",
@@ -135,7 +245,7 @@ static struct crypto_alg aes_alg = {
.cra_cipher = {
.cia_min_keysize = AES_MIN_KEY_SIZE,
.cia_max_keysize = AES_MAX_KEY_SIZE,
- .cia_setkey = crypto_aes_set_key,
+ .cia_setkey = ce_aes_setkey,
.cia_encrypt = aes_cipher_encrypt,
.cia_decrypt = aes_cipher_decrypt
}
diff --git a/arch/arm64/crypto/aes-ce-setkey.h b/arch/arm64/crypto/aes-ce-setkey.h
new file mode 100644
index 0000000..f08a647
--- /dev/null
+++ b/arch/arm64/crypto/aes-ce-setkey.h
@@ -0,0 +1,5 @@
+
+int ce_aes_setkey(struct crypto_tfm *tfm, const u8 *in_key,
+ unsigned int key_len);
+int ce_aes_expandkey(struct crypto_aes_ctx *ctx, const u8 *in_key,
+ unsigned int key_len);
diff --git a/arch/arm64/crypto/aes-glue.c b/arch/arm64/crypto/aes-glue.c
index 79cd911..801aae3 100644
--- a/arch/arm64/crypto/aes-glue.c
+++ b/arch/arm64/crypto/aes-glue.c
@@ -16,9 +16,13 @@
#include <linux/module.h>
#include <linux/cpufeature.h>
+#include "aes-ce-setkey.h"
+
#ifdef USE_V8_CRYPTO_EXTENSIONS
#define MODE "ce"
#define PRIO 300
+#define aes_setkey ce_aes_setkey
+#define aes_expandkey ce_aes_expandkey
#define aes_ecb_encrypt ce_aes_ecb_encrypt
#define aes_ecb_decrypt ce_aes_ecb_decrypt
#define aes_cbc_encrypt ce_aes_cbc_encrypt
@@ -30,6 +34,8 @@ MODULE_DESCRIPTION("AES-ECB/CBC/CTR/XTS using ARMv8 Crypto Extensions");
#else
#define MODE "neon"
#define PRIO 200
+#define aes_setkey crypto_aes_set_key
+#define aes_expandkey crypto_aes_expand_key
#define aes_ecb_encrypt neon_aes_ecb_encrypt
#define aes_ecb_decrypt neon_aes_ecb_decrypt
#define aes_cbc_encrypt neon_aes_cbc_encrypt
@@ -79,10 +85,10 @@ static int xts_set_key(struct crypto_tfm *tfm, const u8 *in_key,
struct crypto_aes_xts_ctx *ctx = crypto_tfm_ctx(tfm);
int ret;
- ret = crypto_aes_expand_key(&ctx->key1, in_key, key_len / 2);
+ ret = aes_expandkey(&ctx->key1, in_key, key_len / 2);
if (!ret)
- ret = crypto_aes_expand_key(&ctx->key2, &in_key[key_len / 2],
- key_len / 2);
+ ret = aes_expandkey(&ctx->key2, &in_key[key_len / 2],
+ key_len / 2);
if (!ret)
return 0;
@@ -288,7 +294,7 @@ static struct crypto_alg aes_algs[] = { {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
- .setkey = crypto_aes_set_key,
+ .setkey = aes_setkey,
.encrypt = ecb_encrypt,
.decrypt = ecb_decrypt,
},
@@ -306,7 +312,7 @@ static struct crypto_alg aes_algs[] = { {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
- .setkey = crypto_aes_set_key,
+ .setkey = aes_setkey,
.encrypt = cbc_encrypt,
.decrypt = cbc_decrypt,
},
@@ -324,7 +330,7 @@ static struct crypto_alg aes_algs[] = { {
.min_keysize = AES_MIN_KEY_SIZE,
.max_keysize = AES_MAX_KEY_SIZE,
.ivsize = AES_BLOCK_SIZE,
- .setkey = crypto_aes_set_key,
+ .setkey = aes_setkey,
.encrypt = ctr_encrypt,
.decrypt = ctr_encrypt,
},
diff --git a/arch/arm64/include/asm/alternative-asm.h b/arch/arm64/include/asm/alternative-asm.h
new file mode 100644
index 0000000..919a678
--- /dev/null
+++ b/arch/arm64/include/asm/alternative-asm.h
@@ -0,0 +1,29 @@
+#ifndef __ASM_ALTERNATIVE_ASM_H
+#define __ASM_ALTERNATIVE_ASM_H
+
+#ifdef __ASSEMBLY__
+
+.macro altinstruction_entry orig_offset alt_offset feature orig_len alt_len
+ .word \orig_offset - .
+ .word \alt_offset - .
+ .hword \feature
+ .byte \orig_len
+ .byte \alt_len
+.endm
+
+.macro alternative_insn insn1 insn2 cap
+661: \insn1
+662: .pushsection .altinstructions, "a"
+ altinstruction_entry 661b, 663f, \cap, 662b-661b, 664f-663f
+ .popsection
+ .pushsection .altinstr_replacement, "ax"
+663: \insn2
+664: .popsection
+ .if ((664b-663b) != (662b-661b))
+ .error "Alternatives instruction length mismatch"
+ .endif
+.endm
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ALTERNATIVE_ASM_H */
diff --git a/arch/arm64/include/asm/alternative.h b/arch/arm64/include/asm/alternative.h
new file mode 100644
index 0000000..d261f01
--- /dev/null
+++ b/arch/arm64/include/asm/alternative.h
@@ -0,0 +1,44 @@
+#ifndef __ASM_ALTERNATIVE_H
+#define __ASM_ALTERNATIVE_H
+
+#include <linux/types.h>
+#include <linux/stddef.h>
+#include <linux/stringify.h>
+
+struct alt_instr {
+ s32 orig_offset; /* offset to original instruction */
+ s32 alt_offset; /* offset to replacement instruction */
+ u16 cpufeature; /* cpufeature bit set for replacement */
+ u8 orig_len; /* size of original instruction(s) */
+ u8 alt_len; /* size of new instruction(s), <= orig_len */
+};
+
+void apply_alternatives_all(void);
+void apply_alternatives(void *start, size_t length);
+void free_alternatives_memory(void);
+
+#define ALTINSTR_ENTRY(feature) \
+ " .word 661b - .\n" /* label */ \
+ " .word 663f - .\n" /* new instruction */ \
+ " .hword " __stringify(feature) "\n" /* feature bit */ \
+ " .byte 662b-661b\n" /* source len */ \
+ " .byte 664f-663f\n" /* replacement len */
+
+/* alternative assembly primitive: */
+#define ALTERNATIVE(oldinstr, newinstr, feature) \
+ "661:\n\t" \
+ oldinstr "\n" \
+ "662:\n" \
+ ".pushsection .altinstructions,\"a\"\n" \
+ ALTINSTR_ENTRY(feature) \
+ ".popsection\n" \
+ ".pushsection .altinstr_replacement, \"a\"\n" \
+ "663:\n\t" \
+ newinstr "\n" \
+ "664:\n\t" \
+ ".popsection\n\t" \
+ ".if ((664b-663b) != (662b-661b))\n\t" \
+ " .error \"Alternatives instruction length mismatch\"\n\t"\
+ ".endif\n"
+
+#endif /* __ASM_ALTERNATIVE_H */
diff --git a/arch/arm64/include/asm/arch_timer.h b/arch/arm64/include/asm/arch_timer.h
index f190971..b1fa4e6 100644
--- a/arch/arm64/include/asm/arch_timer.h
+++ b/arch/arm64/include/asm/arch_timer.h
@@ -104,6 +104,15 @@ static inline void arch_timer_set_cntkctl(u32 cntkctl)
asm volatile("msr cntkctl_el1, %0" : : "r" (cntkctl));
}
+static inline u64 arch_counter_get_cntpct(void)
+{
+ /*
+ * AArch64 kernel and user space mandate the use of CNTVCT.
+ */
+ BUG();
+ return 0;
+}
+
static inline u64 arch_counter_get_cntvct(void)
{
u64 cval;
diff --git a/arch/arm64/include/asm/cache.h b/arch/arm64/include/asm/cache.h
index 88cc05b..bde4499 100644
--- a/arch/arm64/include/asm/cache.h
+++ b/arch/arm64/include/asm/cache.h
@@ -32,6 +32,8 @@
#ifndef __ASSEMBLY__
+#define __read_mostly __attribute__((__section__(".data..read_mostly")))
+
static inline int cache_line_size(void)
{
u32 cwg = cache_type_cwg();
diff --git a/arch/arm64/include/asm/cacheflush.h b/arch/arm64/include/asm/cacheflush.h
index 689b637..7ae31a2 100644
--- a/arch/arm64/include/asm/cacheflush.h
+++ b/arch/arm64/include/asm/cacheflush.h
@@ -73,7 +73,7 @@ extern void flush_cache_all(void);
extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start, unsigned long end);
extern void flush_icache_range(unsigned long start, unsigned long end);
extern void __flush_dcache_area(void *addr, size_t len);
-extern void __flush_cache_user_range(unsigned long start, unsigned long end);
+extern long __flush_cache_user_range(unsigned long start, unsigned long end);
static inline void flush_cache_mm(struct mm_struct *mm)
{
diff --git a/arch/arm64/include/asm/cmpxchg.h b/arch/arm64/include/asm/cmpxchg.h
index ddb9d78..cb95930 100644
--- a/arch/arm64/include/asm/cmpxchg.h
+++ b/arch/arm64/include/asm/cmpxchg.h
@@ -19,6 +19,7 @@
#define __ASM_CMPXCHG_H
#include <linux/bug.h>
+#include <linux/mmdebug.h>
#include <asm/barrier.h>
@@ -152,6 +153,51 @@ static inline unsigned long __cmpxchg(volatile void *ptr, unsigned long old,
return oldval;
}
+#define system_has_cmpxchg_double() 1
+
+static inline int __cmpxchg_double(volatile void *ptr1, volatile void *ptr2,
+ unsigned long old1, unsigned long old2,
+ unsigned long new1, unsigned long new2, int size)
+{
+ unsigned long loop, lost;
+
+ switch (size) {
+ case 8:
+ VM_BUG_ON((unsigned long *)ptr2 - (unsigned long *)ptr1 != 1);
+ do {
+ asm volatile("// __cmpxchg_double8\n"
+ " ldxp %0, %1, %2\n"
+ " eor %0, %0, %3\n"
+ " eor %1, %1, %4\n"
+ " orr %1, %0, %1\n"
+ " mov %w0, #0\n"
+ " cbnz %1, 1f\n"
+ " stxp %w0, %5, %6, %2\n"
+ "1:\n"
+ : "=&r"(loop), "=&r"(lost), "+Q" (*(u64 *)ptr1)
+ : "r" (old1), "r"(old2), "r"(new1), "r"(new2));
+ } while (loop);
+ break;
+ default:
+ BUILD_BUG();
+ }
+
+ return !lost;
+}
+
+static inline int __cmpxchg_double_mb(volatile void *ptr1, volatile void *ptr2,
+ unsigned long old1, unsigned long old2,
+ unsigned long new1, unsigned long new2, int size)
+{
+ int ret;
+
+ smp_mb();
+ ret = __cmpxchg_double(ptr1, ptr2, old1, old2, new1, new2, size);
+ smp_mb();
+
+ return ret;
+}
+
static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
unsigned long new, int size)
{
@@ -182,6 +228,33 @@ static inline unsigned long __cmpxchg_mb(volatile void *ptr, unsigned long old,
__ret; \
})
+#define cmpxchg_double(ptr1, ptr2, o1, o2, n1, n2) \
+({\
+ int __ret;\
+ __ret = __cmpxchg_double_mb((ptr1), (ptr2), (unsigned long)(o1), \
+ (unsigned long)(o2), (unsigned long)(n1), \
+ (unsigned long)(n2), sizeof(*(ptr1)));\
+ __ret; \
+})
+
+#define cmpxchg_double_local(ptr1, ptr2, o1, o2, n1, n2) \
+({\
+ int __ret;\
+ __ret = __cmpxchg_double((ptr1), (ptr2), (unsigned long)(o1), \
+ (unsigned long)(o2), (unsigned long)(n1), \
+ (unsigned long)(n2), sizeof(*(ptr1)));\
+ __ret; \
+})
+
+#define this_cpu_cmpxchg_1(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
+#define this_cpu_cmpxchg_2(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
+#define this_cpu_cmpxchg_4(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
+#define this_cpu_cmpxchg_8(ptr, o, n) cmpxchg_local(raw_cpu_ptr(&(ptr)), o, n)
+
+#define this_cpu_cmpxchg_double_8(ptr1, ptr2, o1, o2, n1, n2) \
+ cmpxchg_double_local(raw_cpu_ptr(&(ptr1)), raw_cpu_ptr(&(ptr2)), \
+ o1, o2, n1, n2)
+
#define cmpxchg64(ptr,o,n) cmpxchg((ptr),(o),(n))
#define cmpxchg64_local(ptr,o,n) cmpxchg_local((ptr),(o),(n))
diff --git a/arch/arm64/include/asm/compat.h b/arch/arm64/include/asm/compat.h
index 56de5aa..3fb053f 100644
--- a/arch/arm64/include/asm/compat.h
+++ b/arch/arm64/include/asm/compat.h
@@ -205,6 +205,13 @@ typedef struct compat_siginfo {
compat_long_t _band; /* POLL_IN, POLL_OUT, POLL_MSG */
int _fd;
} _sigpoll;
+
+ /* SIGSYS */
+ struct {
+ compat_uptr_t _call_addr; /* calling user insn */
+ int _syscall; /* triggering system call number */
+ compat_uint_t _arch; /* AUDIT_ARCH_* of syscall */
+ } _sigsys;
} _sifields;
} compat_siginfo_t;
diff --git a/arch/arm64/include/asm/cpu.h b/arch/arm64/include/asm/cpu.h
index 0564430..ace7068 100644
--- a/arch/arm64/include/asm/cpu.h
+++ b/arch/arm64/include/asm/cpu.h
@@ -30,6 +30,8 @@ struct cpuinfo_arm64 {
u32 reg_dczid;
u32 reg_midr;
+ u64 reg_id_aa64dfr0;
+ u64 reg_id_aa64dfr1;
u64 reg_id_aa64isar0;
u64 reg_id_aa64isar1;
u64 reg_id_aa64mmfr0;
diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index cd4ac05..07547cc 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -21,9 +21,38 @@
#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap))
#define cpu_feature(x) ilog2(HWCAP_ ## x)
+#define ARM64_WORKAROUND_CLEAN_CACHE 0
+#define ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE 1
+
+#define ARM64_NCAPS 2
+
+#ifndef __ASSEMBLY__
+
+extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
+
static inline bool cpu_have_feature(unsigned int num)
{
return elf_hwcap & (1UL << num);
}
+static inline bool cpus_have_cap(unsigned int num)
+{
+ if (num >= ARM64_NCAPS)
+ return false;
+ return test_bit(num, cpu_hwcaps);
+}
+
+static inline void cpus_set_cap(unsigned int num)
+{
+ if (num >= ARM64_NCAPS)
+ pr_warn("Attempt to set an illegal CPU capability (%d >= %d)\n",
+ num, ARM64_NCAPS);
+ else
+ __set_bit(num, cpu_hwcaps);
+}
+
+void check_local_cpu_errata(void);
+
+#endif /* __ASSEMBLY__ */
+
#endif
diff --git a/arch/arm64/include/asm/cputype.h b/arch/arm64/include/asm/cputype.h
index 379d0b8..8adb986 100644
--- a/arch/arm64/include/asm/cputype.h
+++ b/arch/arm64/include/asm/cputype.h
@@ -57,6 +57,11 @@
#define MIDR_IMPLEMENTOR(midr) \
(((midr) & MIDR_IMPLEMENTOR_MASK) >> MIDR_IMPLEMENTOR_SHIFT)
+#define MIDR_CPU_PART(imp, partnum) \
+ (((imp) << MIDR_IMPLEMENTOR_SHIFT) | \
+ (0xf << MIDR_ARCHITECTURE_SHIFT) | \
+ ((partnum) << MIDR_PARTNUM_SHIFT))
+
#define ARM_CPU_IMP_ARM 0x41
#define ARM_CPU_IMP_APM 0x50
diff --git a/arch/arm64/include/asm/dmi.h b/arch/arm64/include/asm/dmi.h
new file mode 100644
index 0000000..69d37d8
--- /dev/null
+++ b/arch/arm64/include/asm/dmi.h
@@ -0,0 +1,31 @@
+/*
+ * arch/arm64/include/asm/dmi.h
+ *
+ * Copyright (C) 2013 Linaro Limited.
+ * Written by: Yi Li (yi.li@linaro.org)
+ *
+ * based on arch/ia64/include/asm/dmi.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef __ASM_DMI_H
+#define __ASM_DMI_H
+
+#include <linux/io.h>
+#include <linux/slab.h>
+
+/*
+ * According to section 2.3.6 of the UEFI spec, the firmware should not
+ * request a virtual mapping for configuration tables such as SMBIOS.
+ * This means we have to map them before use.
+ */
+#define dmi_early_remap(x, l) ioremap_cache(x, l)
+#define dmi_early_unmap(x, l) iounmap(x)
+#define dmi_remap(x, l) ioremap_cache(x, l)
+#define dmi_unmap(x) iounmap(x)
+#define dmi_alloc(l) kzalloc(l, GFP_KERNEL)
+
+#endif
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 5f7bfe6..9ef6eca 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -31,6 +31,7 @@
*
*/
enum fixed_addresses {
+ FIX_HOLE,
FIX_EARLYCON_MEM_BASE,
__end_of_permanent_fixed_addresses,
@@ -56,10 +57,11 @@ enum fixed_addresses {
#define FIXMAP_PAGE_IO __pgprot(PROT_DEVICE_nGnRE)
-extern void __early_set_fixmap(enum fixed_addresses idx,
- phys_addr_t phys, pgprot_t flags);
+void __init early_fixmap_init(void);
-#define __set_fixmap __early_set_fixmap
+#define __early_set_fixmap __set_fixmap
+
+extern void __set_fixmap(enum fixed_addresses idx, phys_addr_t phys, pgprot_t prot);
#include <asm-generic/fixmap.h>
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 024c461..0ad7351 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -30,6 +30,7 @@
#define COMPAT_HWCAP_IDIVA (1 << 17)
#define COMPAT_HWCAP_IDIVT (1 << 18)
#define COMPAT_HWCAP_IDIV (COMPAT_HWCAP_IDIVA|COMPAT_HWCAP_IDIVT)
+#define COMPAT_HWCAP_LPAE (1 << 20)
#define COMPAT_HWCAP_EVTSTRM (1 << 21)
#define COMPAT_HWCAP2_AES (1 << 0)
diff --git a/arch/arm64/include/asm/insn.h b/arch/arm64/include/asm/insn.h
index 56a9e63..e2ff32a 100644
--- a/arch/arm64/include/asm/insn.h
+++ b/arch/arm64/include/asm/insn.h
@@ -354,6 +354,16 @@ bool aarch64_insn_hotpatch_safe(u32 old_insn, u32 new_insn);
int aarch64_insn_patch_text_nosync(void *addr, u32 insn);
int aarch64_insn_patch_text_sync(void *addrs[], u32 insns[], int cnt);
int aarch64_insn_patch_text(void *addrs[], u32 insns[], int cnt);
+
+bool aarch32_insn_is_wide(u32 insn);
+
+#define A32_RN_OFFSET 16
+#define A32_RT_OFFSET 12
+#define A32_RT2_OFFSET 0
+
+u32 aarch32_insn_extract_reg_num(u32 insn, int offset);
+u32 aarch32_insn_mcr_extract_opc2(u32 insn);
+u32 aarch32_insn_mcr_extract_crm(u32 insn);
#endif /* __ASSEMBLY__ */
#endif /* __ASM_INSN_H */
diff --git a/arch/arm64/include/asm/io.h b/arch/arm64/include/asm/io.h
index 79f1d519..949c406 100644
--- a/arch/arm64/include/asm/io.h
+++ b/arch/arm64/include/asm/io.h
@@ -28,57 +28,80 @@
#include <asm/barrier.h>
#include <asm/pgtable.h>
#include <asm/early_ioremap.h>
+#include <asm/alternative.h>
+#include <asm/cpufeature.h>
#include <xen/xen.h>
/*
* Generic IO read/write. These perform native-endian accesses.
*/
+#define __raw_writeb __raw_writeb
static inline void __raw_writeb(u8 val, volatile void __iomem *addr)
{
asm volatile("strb %w0, [%1]" : : "r" (val), "r" (addr));
}
+#define __raw_writew __raw_writew
static inline void __raw_writew(u16 val, volatile void __iomem *addr)
{
asm volatile("strh %w0, [%1]" : : "r" (val), "r" (addr));
}
+#define __raw_writel __raw_writel
static inline void __raw_writel(u32 val, volatile void __iomem *addr)
{
asm volatile("str %w0, [%1]" : : "r" (val), "r" (addr));
}
+#define __raw_writeq __raw_writeq
static inline void __raw_writeq(u64 val, volatile void __iomem *addr)
{
asm volatile("str %0, [%1]" : : "r" (val), "r" (addr));
}
+#define __raw_readb __raw_readb
static inline u8 __raw_readb(const volatile void __iomem *addr)
{
u8 val;
- asm volatile("ldrb %w0, [%1]" : "=r" (val) : "r" (addr));
+ asm volatile(ALTERNATIVE("ldrb %w0, [%1]",
+ "ldarb %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
+#define __raw_readw __raw_readw
static inline u16 __raw_readw(const volatile void __iomem *addr)
{
u16 val;
- asm volatile("ldrh %w0, [%1]" : "=r" (val) : "r" (addr));
+
+ asm volatile(ALTERNATIVE("ldrh %w0, [%1]",
+ "ldarh %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
+#define __raw_readl __raw_readl
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
u32 val;
- asm volatile("ldr %w0, [%1]" : "=r" (val) : "r" (addr));
+ asm volatile(ALTERNATIVE("ldr %w0, [%1]",
+ "ldar %w0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
+#define __raw_readq __raw_readq
static inline u64 __raw_readq(const volatile void __iomem *addr)
{
u64 val;
- asm volatile("ldr %0, [%1]" : "=r" (val) : "r" (addr));
+ asm volatile(ALTERNATIVE("ldr %0, [%1]",
+ "ldar %0, [%1]",
+ ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE)
+ : "=r" (val) : "r" (addr));
return val;
}
@@ -125,94 +148,6 @@ static inline u64 __raw_readq(const volatile void __iomem *addr)
#define IO_SPACE_LIMIT (SZ_32M - 1)
#define PCI_IOBASE ((void __iomem *)(MODULES_VADDR - SZ_32M))
-static inline u8 inb(unsigned long addr)
-{
- return readb(addr + PCI_IOBASE);
-}
-
-static inline u16 inw(unsigned long addr)
-{
- return readw(addr + PCI_IOBASE);
-}
-
-static inline u32 inl(unsigned long addr)
-{
- return readl(addr + PCI_IOBASE);
-}
-
-static inline void outb(u8 b, unsigned long addr)
-{
- writeb(b, addr + PCI_IOBASE);
-}
-
-static inline void outw(u16 b, unsigned long addr)
-{
- writew(b, addr + PCI_IOBASE);
-}
-
-static inline void outl(u32 b, unsigned long addr)
-{
- writel(b, addr + PCI_IOBASE);
-}
-
-#define inb_p(addr) inb(addr)
-#define inw_p(addr) inw(addr)
-#define inl_p(addr) inl(addr)
-
-#define outb_p(x, addr) outb((x), (addr))
-#define outw_p(x, addr) outw((x), (addr))
-#define outl_p(x, addr) outl((x), (addr))
-
-static inline void insb(unsigned long addr, void *buffer, int count)
-{
- u8 *buf = buffer;
- while (count--)
- *buf++ = __raw_readb(addr + PCI_IOBASE);
-}
-
-static inline void insw(unsigned long addr, void *buffer, int count)
-{
- u16 *buf = buffer;
- while (count--)
- *buf++ = __raw_readw(addr + PCI_IOBASE);
-}
-
-static inline void insl(unsigned long addr, void *buffer, int count)
-{
- u32 *buf = buffer;
- while (count--)
- *buf++ = __raw_readl(addr + PCI_IOBASE);
-}
-
-static inline void outsb(unsigned long addr, const void *buffer, int count)
-{
- const u8 *buf = buffer;
- while (count--)
- __raw_writeb(*buf++, addr + PCI_IOBASE);
-}
-
-static inline void outsw(unsigned long addr, const void *buffer, int count)
-{
- const u16 *buf = buffer;
- while (count--)
- __raw_writew(*buf++, addr + PCI_IOBASE);
-}
-
-static inline void outsl(unsigned long addr, const void *buffer, int count)
-{
- const u32 *buf = buffer;
- while (count--)
- __raw_writel(*buf++, addr + PCI_IOBASE);
-}
-
-#define insb_p(port,to,len) insb(port,to,len)
-#define insw_p(port,to,len) insw(port,to,len)
-#define insl_p(port,to,len) insl(port,to,len)
-
-#define outsb_p(port,from,len) outsb(port,from,len)
-#define outsw_p(port,from,len) outsw(port,from,len)
-#define outsl_p(port,from,len) outsl(port,from,len)
-
/*
* String version of I/O memory access operations.
*/
@@ -236,18 +171,14 @@ extern void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size);
#define ioremap_wc(addr, size) __ioremap((addr), (size), __pgprot(PROT_NORMAL_NC))
#define iounmap __iounmap
-#define ARCH_HAS_IOREMAP_WC
-#include <asm-generic/iomap.h>
-
/*
- * More restrictive address range checking than the default implementation
- * (PHYS_OFFSET and PHYS_MASK taken into account).
+ * io{read,write}{16,32}be() macros
*/
-#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
-extern int valid_phys_addr_range(phys_addr_t addr, size_t size);
-extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+#define ioread16be(p) ({ __u16 __v = be16_to_cpu((__force __be16)__raw_readw(p)); __iormb(); __v; })
+#define ioread32be(p) ({ __u32 __v = be32_to_cpu((__force __be32)__raw_readl(p)); __iormb(); __v; })
-extern int devmem_is_allowed(unsigned long pfn);
+#define iowrite16be(v,p) ({ __iowmb(); __raw_writew((__force __u16)cpu_to_be16(v), p); })
+#define iowrite32be(v,p) ({ __iowmb(); __raw_writel((__force __u32)cpu_to_be32(v), p); })
/*
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
@@ -260,6 +191,18 @@ extern int devmem_is_allowed(unsigned long pfn);
*/
#define xlate_dev_kmem_ptr(p) p
+#include <asm-generic/io.h>
+
+/*
+ * More restrictive address range checking than the default implementation
+ * (PHYS_OFFSET and PHYS_MASK taken into account).
+ */
+#define ARCH_HAS_VALID_PHYS_ADDR_RANGE
+extern int valid_phys_addr_range(phys_addr_t addr, size_t size);
+extern int valid_mmap_phys_addr_range(unsigned long pfn, size_t size);
+
+extern int devmem_is_allowed(unsigned long pfn);
+
struct bio_vec;
extern bool xen_biovec_phys_mergeable(const struct bio_vec *vec1,
const struct bio_vec *vec2);
diff --git a/arch/arm64/include/asm/irq.h b/arch/arm64/include/asm/irq.h
index e1f7ecd..94c5367 100644
--- a/arch/arm64/include/asm/irq.h
+++ b/arch/arm64/include/asm/irq.h
@@ -3,7 +3,8 @@
#include <asm-generic/irq.h>
-extern void (*handle_arch_irq)(struct pt_regs *);
+struct pt_regs;
+
extern void migrate_irqs(void);
extern void set_handle_irq(void (*handle_irq)(struct pt_regs *));
diff --git a/arch/arm64/include/asm/kvm_arm.h b/arch/arm64/include/asm/kvm_arm.h
index 7fd3e27..8afb863 100644
--- a/arch/arm64/include/asm/kvm_arm.h
+++ b/arch/arm64/include/asm/kvm_arm.h
@@ -18,6 +18,7 @@
#ifndef __ARM64_KVM_ARM_H__
#define __ARM64_KVM_ARM_H__
+#include <asm/memory.h>
#include <asm/types.h>
/* Hyp Configuration Register (HCR) bits */
@@ -160,9 +161,9 @@
#endif
#define VTTBR_BADDR_SHIFT (VTTBR_X - 1)
-#define VTTBR_BADDR_MASK (((1LLU << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
-#define VTTBR_VMID_SHIFT (48LLU)
-#define VTTBR_VMID_MASK (0xffLLU << VTTBR_VMID_SHIFT)
+#define VTTBR_BADDR_MASK (((UL(1) << (PHYS_MASK_SHIFT - VTTBR_X)) - 1) << VTTBR_BADDR_SHIFT)
+#define VTTBR_VMID_SHIFT (UL(48))
+#define VTTBR_VMID_MASK (UL(0xFF) << VTTBR_VMID_SHIFT)
/* Hyp System Trap Register */
#define HSTR_EL2_TTEE (1 << 16)
@@ -185,13 +186,13 @@
/* 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_EC (UL(0x3f) << ESR_EL2_EC_SHIFT)
+#define ESR_EL2_IL (UL(1) << 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_ISV (UL(1) << ESR_EL2_ISV_SHIFT)
#define ESR_EL2_SAS_SHIFT (22)
-#define ESR_EL2_SAS (3U << ESR_EL2_SAS_SHIFT)
+#define ESR_EL2_SAS (UL(3) << 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)
@@ -205,16 +206,16 @@
#define ESR_EL2_FSC_TYPE (0x3c)
#define ESR_EL2_CV_SHIFT (24)
-#define ESR_EL2_CV (1U << ESR_EL2_CV_SHIFT)
+#define ESR_EL2_CV (UL(1) << ESR_EL2_CV_SHIFT)
#define ESR_EL2_COND_SHIFT (20)
-#define ESR_EL2_COND (0xfU << ESR_EL2_COND_SHIFT)
+#define ESR_EL2_COND (UL(0xf) << ESR_EL2_COND_SHIFT)
#define FSC_FAULT (0x04)
#define FSC_PERM (0x0c)
/* Hyp Prefetch Fault Address Register (HPFAR/HDFAR) */
-#define HPFAR_MASK (~0xFUL)
+#define HPFAR_MASK (~UL(0xf))
#define ESR_EL2_EC_UNKNOWN (0x00)
#define ESR_EL2_EC_WFI (0x01)
diff --git a/arch/arm64/include/asm/memory.h b/arch/arm64/include/asm/memory.h
index a62cd07..6486b2b 100644
--- a/arch/arm64/include/asm/memory.h
+++ b/arch/arm64/include/asm/memory.h
@@ -120,11 +120,13 @@ extern phys_addr_t memstart_addr;
* translation for translating DMA addresses. Use the driver
* DMA support - see dma-mapping.h.
*/
+#define virt_to_phys virt_to_phys
static inline phys_addr_t virt_to_phys(const volatile void *x)
{
return __virt_to_phys((unsigned long)(x));
}
+#define phys_to_virt phys_to_virt
static inline void *phys_to_virt(phys_addr_t x)
{
return (void *)(__phys_to_virt(x));
diff --git a/arch/arm64/include/asm/opcodes.h b/arch/arm64/include/asm/opcodes.h
new file mode 100644
index 0000000..4e603ea
--- /dev/null
+++ b/arch/arm64/include/asm/opcodes.h
@@ -0,0 +1 @@
+#include <../../arm/include/asm/opcodes.h>
diff --git a/arch/arm64/include/asm/percpu.h b/arch/arm64/include/asm/percpu.h
index 5279e57..09da25b 100644
--- a/arch/arm64/include/asm/percpu.h
+++ b/arch/arm64/include/asm/percpu.h
@@ -44,6 +44,221 @@ static inline unsigned long __my_cpu_offset(void)
#endif /* CONFIG_SMP */
+#define PERCPU_OP(op, asm_op) \
+static inline unsigned long __percpu_##op(void *ptr, \
+ unsigned long val, int size) \
+{ \
+ unsigned long loop, ret; \
+ \
+ switch (size) { \
+ case 1: \
+ do { \
+ asm ("//__per_cpu_" #op "_1\n" \
+ "ldxrb %w[ret], %[ptr]\n" \
+ #asm_op " %w[ret], %w[ret], %w[val]\n" \
+ "stxrb %w[loop], %w[ret], %[ptr]\n" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u8 *)ptr) \
+ : [val] "Ir" (val)); \
+ } while (loop); \
+ break; \
+ case 2: \
+ do { \
+ asm ("//__per_cpu_" #op "_2\n" \
+ "ldxrh %w[ret], %[ptr]\n" \
+ #asm_op " %w[ret], %w[ret], %w[val]\n" \
+ "stxrh %w[loop], %w[ret], %[ptr]\n" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u16 *)ptr) \
+ : [val] "Ir" (val)); \
+ } while (loop); \
+ break; \
+ case 4: \
+ do { \
+ asm ("//__per_cpu_" #op "_4\n" \
+ "ldxr %w[ret], %[ptr]\n" \
+ #asm_op " %w[ret], %w[ret], %w[val]\n" \
+ "stxr %w[loop], %w[ret], %[ptr]\n" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u32 *)ptr) \
+ : [val] "Ir" (val)); \
+ } while (loop); \
+ break; \
+ case 8: \
+ do { \
+ asm ("//__per_cpu_" #op "_8\n" \
+ "ldxr %[ret], %[ptr]\n" \
+ #asm_op " %[ret], %[ret], %[val]\n" \
+ "stxr %w[loop], %[ret], %[ptr]\n" \
+ : [loop] "=&r" (loop), [ret] "=&r" (ret), \
+ [ptr] "+Q"(*(u64 *)ptr) \
+ : [val] "Ir" (val)); \
+ } while (loop); \
+ break; \
+ default: \
+ BUILD_BUG(); \
+ } \
+ \
+ return ret; \
+}
+
+PERCPU_OP(add, add)
+PERCPU_OP(and, and)
+PERCPU_OP(or, orr)
+#undef PERCPU_OP
+
+static inline unsigned long __percpu_read(void *ptr, int size)
+{
+ unsigned long ret;
+
+ switch (size) {
+ case 1:
+ ret = ACCESS_ONCE(*(u8 *)ptr);
+ break;
+ case 2:
+ ret = ACCESS_ONCE(*(u16 *)ptr);
+ break;
+ case 4:
+ ret = ACCESS_ONCE(*(u32 *)ptr);
+ break;
+ case 8:
+ ret = ACCESS_ONCE(*(u64 *)ptr);
+ break;
+ default:
+ BUILD_BUG();
+ }
+
+ return ret;
+}
+
+static inline void __percpu_write(void *ptr, unsigned long val, int size)
+{
+ switch (size) {
+ case 1:
+ ACCESS_ONCE(*(u8 *)ptr) = (u8)val;
+ break;
+ case 2:
+ ACCESS_ONCE(*(u16 *)ptr) = (u16)val;
+ break;
+ case 4:
+ ACCESS_ONCE(*(u32 *)ptr) = (u32)val;
+ break;
+ case 8:
+ ACCESS_ONCE(*(u64 *)ptr) = (u64)val;
+ break;
+ default:
+ BUILD_BUG();
+ }
+}
+
+static inline unsigned long __percpu_xchg(void *ptr, unsigned long val,
+ int size)
+{
+ unsigned long ret, loop;
+
+ switch (size) {
+ case 1:
+ do {
+ asm ("//__percpu_xchg_1\n"
+ "ldxrb %w[ret], %[ptr]\n"
+ "stxrb %w[loop], %w[val], %[ptr]\n"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u8 *)ptr)
+ : [val] "r" (val));
+ } while (loop);
+ break;
+ case 2:
+ do {
+ asm ("//__percpu_xchg_2\n"
+ "ldxrh %w[ret], %[ptr]\n"
+ "stxrh %w[loop], %w[val], %[ptr]\n"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u16 *)ptr)
+ : [val] "r" (val));
+ } while (loop);
+ break;
+ case 4:
+ do {
+ asm ("//__percpu_xchg_4\n"
+ "ldxr %w[ret], %[ptr]\n"
+ "stxr %w[loop], %w[val], %[ptr]\n"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u32 *)ptr)
+ : [val] "r" (val));
+ } while (loop);
+ break;
+ case 8:
+ do {
+ asm ("//__percpu_xchg_8\n"
+ "ldxr %[ret], %[ptr]\n"
+ "stxr %w[loop], %[val], %[ptr]\n"
+ : [loop] "=&r"(loop), [ret] "=&r"(ret),
+ [ptr] "+Q"(*(u64 *)ptr)
+ : [val] "r" (val));
+ } while (loop);
+ break;
+ default:
+ BUILD_BUG();
+ }
+
+ return ret;
+}
+
+#define _percpu_add(pcp, val) \
+ __percpu_add(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+
+#define _percpu_add_return(pcp, val) (typeof(pcp)) (_percpu_add(pcp, val))
+
+#define _percpu_and(pcp, val) \
+ __percpu_and(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+
+#define _percpu_or(pcp, val) \
+ __percpu_or(raw_cpu_ptr(&(pcp)), val, sizeof(pcp))
+
+#define _percpu_read(pcp) (typeof(pcp)) \
+ (__percpu_read(raw_cpu_ptr(&(pcp)), sizeof(pcp)))
+
+#define _percpu_write(pcp, val) \
+ __percpu_write(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp))
+
+#define _percpu_xchg(pcp, val) (typeof(pcp)) \
+ (__percpu_xchg(raw_cpu_ptr(&(pcp)), (unsigned long)(val), sizeof(pcp)))
+
+#define this_cpu_add_1(pcp, val) _percpu_add(pcp, val)
+#define this_cpu_add_2(pcp, val) _percpu_add(pcp, val)
+#define this_cpu_add_4(pcp, val) _percpu_add(pcp, val)
+#define this_cpu_add_8(pcp, val) _percpu_add(pcp, val)
+
+#define this_cpu_add_return_1(pcp, val) _percpu_add_return(pcp, val)
+#define this_cpu_add_return_2(pcp, val) _percpu_add_return(pcp, val)
+#define this_cpu_add_return_4(pcp, val) _percpu_add_return(pcp, val)
+#define this_cpu_add_return_8(pcp, val) _percpu_add_return(pcp, val)
+
+#define this_cpu_and_1(pcp, val) _percpu_and(pcp, val)
+#define this_cpu_and_2(pcp, val) _percpu_and(pcp, val)
+#define this_cpu_and_4(pcp, val) _percpu_and(pcp, val)
+#define this_cpu_and_8(pcp, val) _percpu_and(pcp, val)
+
+#define this_cpu_or_1(pcp, val) _percpu_or(pcp, val)
+#define this_cpu_or_2(pcp, val) _percpu_or(pcp, val)
+#define this_cpu_or_4(pcp, val) _percpu_or(pcp, val)
+#define this_cpu_or_8(pcp, val) _percpu_or(pcp, val)
+
+#define this_cpu_read_1(pcp) _percpu_read(pcp)
+#define this_cpu_read_2(pcp) _percpu_read(pcp)
+#define this_cpu_read_4(pcp) _percpu_read(pcp)
+#define this_cpu_read_8(pcp) _percpu_read(pcp)
+
+#define this_cpu_write_1(pcp, val) _percpu_write(pcp, val)
+#define this_cpu_write_2(pcp, val) _percpu_write(pcp, val)
+#define this_cpu_write_4(pcp, val) _percpu_write(pcp, val)
+#define this_cpu_write_8(pcp, val) _percpu_write(pcp, val)
+
+#define this_cpu_xchg_1(pcp, val) _percpu_xchg(pcp, val)
+#define this_cpu_xchg_2(pcp, val) _percpu_xchg(pcp, val)
+#define this_cpu_xchg_4(pcp, val) _percpu_xchg(pcp, val)
+#define this_cpu_xchg_8(pcp, val) _percpu_xchg(pcp, val)
+
#include <asm-generic/percpu.h>
#endif /* __ASM_PERCPU_H */
diff --git a/arch/arm64/include/asm/pgalloc.h b/arch/arm64/include/asm/pgalloc.h
index d5bed02..e20df38 100644
--- a/arch/arm64/include/asm/pgalloc.h
+++ b/arch/arm64/include/asm/pgalloc.h
@@ -26,11 +26,13 @@
#define check_pgt_cache() do { } while (0)
+#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
+
#if CONFIG_ARM64_PGTABLE_LEVELS > 2
static inline pmd_t *pmd_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- return (pmd_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
+ return (pmd_t *)__get_free_page(PGALLOC_GFP);
}
static inline void pmd_free(struct mm_struct *mm, pmd_t *pmd)
@@ -50,7 +52,7 @@ static inline void pud_populate(struct mm_struct *mm, pud_t *pud, pmd_t *pmd)
static inline pud_t *pud_alloc_one(struct mm_struct *mm, unsigned long addr)
{
- return (pud_t *)get_zeroed_page(GFP_KERNEL | __GFP_REPEAT);
+ return (pud_t *)__get_free_page(PGALLOC_GFP);
}
static inline void pud_free(struct mm_struct *mm, pud_t *pud)
@@ -69,8 +71,6 @@ static inline void pgd_populate(struct mm_struct *mm, pgd_t *pgd, pud_t *pud)
extern pgd_t *pgd_alloc(struct mm_struct *mm);
extern void pgd_free(struct mm_struct *mm, pgd_t *pgd);
-#define PGALLOC_GFP (GFP_KERNEL | __GFP_NOTRACK | __GFP_REPEAT | __GFP_ZERO)
-
static inline pte_t *
pte_alloc_one_kernel(struct mm_struct *mm, unsigned long addr)
{
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index 41a43bf..df22314 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -279,6 +279,7 @@ void pmdp_splitting_flush(struct vm_area_struct *vma, unsigned long address,
#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
+#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
#define pmd_mksplitting(pmd) pte_pmd(pte_mkspecial(pmd_pte(pmd)))
diff --git a/arch/arm64/include/asm/seccomp.h b/arch/arm64/include/asm/seccomp.h
new file mode 100644
index 0000000..c76fac9
--- /dev/null
+++ b/arch/arm64/include/asm/seccomp.h
@@ -0,0 +1,25 @@
+/*
+ * arch/arm64/include/asm/seccomp.h
+ *
+ * Copyright (C) 2014 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_SECCOMP_H
+#define _ASM_SECCOMP_H
+
+#include <asm/unistd.h>
+
+#ifdef CONFIG_COMPAT
+#define __NR_seccomp_read_32 __NR_compat_read
+#define __NR_seccomp_write_32 __NR_compat_write
+#define __NR_seccomp_exit_32 __NR_compat_exit
+#define __NR_seccomp_sigreturn_32 __NR_compat_rt_sigreturn
+#endif /* CONFIG_COMPAT */
+
+#include <asm-generic/seccomp.h>
+
+#endif /* _ASM_SECCOMP_H */
diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index a82c0c5..c028fe3 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -19,10 +19,6 @@
#ifndef __ASM_TLB_H
#define __ASM_TLB_H
-#define __tlb_remove_pmd_tlb_entry __tlb_remove_pmd_tlb_entry
-
-#include <asm-generic/tlb.h>
-
#include <linux/pagemap.h>
#include <linux/swap.h>
@@ -37,71 +33,22 @@ static inline void __tlb_remove_table(void *_table)
#define tlb_remove_entry(tlb, entry) tlb_remove_page(tlb, entry)
#endif /* CONFIG_HAVE_RCU_TABLE_FREE */
-/*
- * There's three ways the TLB shootdown code is used:
- * 1. Unmapping a range of vmas. See zap_page_range(), unmap_region().
- * tlb->fullmm = 0, and tlb_start_vma/tlb_end_vma will be called.
- * 2. Unmapping all vmas. See exit_mmap().
- * tlb->fullmm = 1, and tlb_start_vma/tlb_end_vma will be called.
- * Page tables will be freed.
- * 3. Unmapping argument pages. See shift_arg_pages().
- * tlb->fullmm = 0, but tlb_start_vma/tlb_end_vma will not be called.
- */
+#include <asm-generic/tlb.h>
+
static inline void tlb_flush(struct mmu_gather *tlb)
{
if (tlb->fullmm) {
flush_tlb_mm(tlb->mm);
- } else if (tlb->end > 0) {
+ } else {
struct vm_area_struct vma = { .vm_mm = tlb->mm, };
flush_tlb_range(&vma, tlb->start, tlb->end);
- tlb->start = TASK_SIZE;
- tlb->end = 0;
- }
-}
-
-static inline void tlb_add_flush(struct mmu_gather *tlb, unsigned long addr)
-{
- if (!tlb->fullmm) {
- tlb->start = min(tlb->start, addr);
- tlb->end = max(tlb->end, addr + PAGE_SIZE);
- }
-}
-
-/*
- * Memorize the range for the TLB flush.
- */
-static inline void __tlb_remove_tlb_entry(struct mmu_gather *tlb, pte_t *ptep,
- unsigned long addr)
-{
- tlb_add_flush(tlb, addr);
-}
-
-/*
- * In the case of tlb vma handling, we can optimise these away in the
- * case where we're doing a full MM flush. When we're doing a munmap,
- * the vmas are adjusted to only cover the region to be torn down.
- */
-static inline void tlb_start_vma(struct mmu_gather *tlb,
- struct vm_area_struct *vma)
-{
- if (!tlb->fullmm) {
- tlb->start = TASK_SIZE;
- tlb->end = 0;
}
}
-static inline void tlb_end_vma(struct mmu_gather *tlb,
- struct vm_area_struct *vma)
-{
- if (!tlb->fullmm)
- tlb_flush(tlb);
-}
-
static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
unsigned long addr)
{
pgtable_page_dtor(pte);
- tlb_add_flush(tlb, addr);
tlb_remove_entry(tlb, pte);
}
@@ -109,7 +56,6 @@ static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
unsigned long addr)
{
- tlb_add_flush(tlb, addr);
tlb_remove_entry(tlb, virt_to_page(pmdp));
}
#endif
@@ -118,15 +64,8 @@ static inline void __pmd_free_tlb(struct mmu_gather *tlb, pmd_t *pmdp,
static inline void __pud_free_tlb(struct mmu_gather *tlb, pud_t *pudp,
unsigned long addr)
{
- tlb_add_flush(tlb, addr);
tlb_remove_entry(tlb, virt_to_page(pudp));
}
#endif
-static inline void __tlb_remove_pmd_tlb_entry(struct mmu_gather *tlb, pmd_t *pmdp,
- unsigned long address)
-{
- tlb_add_flush(tlb, address);
-}
-
#endif
diff --git a/arch/arm64/include/asm/traps.h b/arch/arm64/include/asm/traps.h
index 10ca8ff..232e4ba 100644
--- a/arch/arm64/include/asm/traps.h
+++ b/arch/arm64/include/asm/traps.h
@@ -18,6 +18,22 @@
#ifndef __ASM_TRAP_H
#define __ASM_TRAP_H
+#include <linux/list.h>
+
+struct pt_regs;
+
+struct undef_hook {
+ struct list_head node;
+ u32 instr_mask;
+ u32 instr_val;
+ u64 pstate_mask;
+ u64 pstate_val;
+ int (*fn)(struct pt_regs *regs, u32 instr);
+};
+
+void register_undef_hook(struct undef_hook *hook);
+void unregister_undef_hook(struct undef_hook *hook);
+
static inline int in_exception_text(unsigned long ptr)
{
extern char __exception_text_start[];
diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 6d2bf41..49c9aef 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -31,6 +31,9 @@
* Compat syscall numbers used by the AArch64 kernel.
*/
#define __NR_compat_restart_syscall 0
+#define __NR_compat_exit 1
+#define __NR_compat_read 3
+#define __NR_compat_write 4
#define __NR_compat_sigreturn 119
#define __NR_compat_rt_sigreturn 173
diff --git a/arch/arm64/include/asm/unistd32.h b/arch/arm64/include/asm/unistd32.h
index 9dfdac4..8893ceb 100644
--- a/arch/arm64/include/asm/unistd32.h
+++ b/arch/arm64/include/asm/unistd32.h
@@ -787,7 +787,8 @@ __SYSCALL(__NR_sched_setattr, sys_sched_setattr)
__SYSCALL(__NR_sched_getattr, sys_sched_getattr)
#define __NR_renameat2 382
__SYSCALL(__NR_renameat2, sys_renameat2)
- /* 383 for seccomp */
+#define __NR_seccomp 383
+__SYSCALL(__NR_seccomp, sys_seccomp)
#define __NR_getrandom 384
__SYSCALL(__NR_getrandom, sys_getrandom)
#define __NR_memfd_create 385
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index 5bd029b..eaa77ed 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -5,6 +5,7 @@
CPPFLAGS_vmlinux.lds := -DTEXT_OFFSET=$(TEXT_OFFSET)
AFLAGS_head.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
CFLAGS_efi-stub.o := -DTEXT_OFFSET=$(TEXT_OFFSET)
+CFLAGS_armv8_deprecated.o := -I$(src)
CFLAGS_REMOVE_ftrace.o = -pg
CFLAGS_REMOVE_insn.o = -pg
@@ -15,10 +16,11 @@ arm64-obj-y := cputable.o debug-monitors.o entry.o irq.o fpsimd.o \
entry-fpsimd.o process.o ptrace.o setup.o signal.o \
sys.o stacktrace.o time.o traps.o io.o vdso.o \
hyp-stub.o psci.o cpu_ops.o insn.o return_address.o \
- cpuinfo.o
+ cpuinfo.o cpu_errata.o alternative.o
arm64-obj-$(CONFIG_COMPAT) += sys32.o kuser32.o signal32.o \
- sys_compat.o
+ sys_compat.o \
+ ../../arm/kernel/opcodes.o
arm64-obj-$(CONFIG_FUNCTION_TRACER) += ftrace.o entry-ftrace.o
arm64-obj-$(CONFIG_MODULES) += arm64ksyms.o module.o
arm64-obj-$(CONFIG_SMP) += smp.o smp_spin_table.o topology.o
@@ -31,6 +33,7 @@ arm64-obj-$(CONFIG_JUMP_LABEL) += jump_label.o
arm64-obj-$(CONFIG_KGDB) += kgdb.o
arm64-obj-$(CONFIG_EFI) += efi.o efi-stub.o efi-entry.o
arm64-obj-$(CONFIG_PCI) += pci.o
+arm64-obj-$(CONFIG_ARMV8_DEPRECATED) += armv8_deprecated.o
obj-y += $(arm64-obj-y) vdso/
obj-m += $(arm64-obj-m)
diff --git a/arch/arm64/kernel/alternative.c b/arch/arm64/kernel/alternative.c
new file mode 100644
index 0000000..ad7821d
--- /dev/null
+++ b/arch/arm64/kernel/alternative.c
@@ -0,0 +1,85 @@
+/*
+ * alternative runtime patching
+ * inspired by the x86 version
+ *
+ * Copyright (C) 2014 ARM 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "alternatives: " fmt
+
+#include <linux/init.h>
+#include <linux/cpu.h>
+#include <asm/cacheflush.h>
+#include <asm/alternative.h>
+#include <asm/cpufeature.h>
+#include <linux/stop_machine.h>
+
+extern struct alt_instr __alt_instructions[], __alt_instructions_end[];
+
+struct alt_region {
+ struct alt_instr *begin;
+ struct alt_instr *end;
+};
+
+static int __apply_alternatives(void *alt_region)
+{
+ struct alt_instr *alt;
+ struct alt_region *region = alt_region;
+ u8 *origptr, *replptr;
+
+ for (alt = region->begin; alt < region->end; alt++) {
+ if (!cpus_have_cap(alt->cpufeature))
+ continue;
+
+ BUG_ON(alt->alt_len > alt->orig_len);
+
+ pr_info_once("patching kernel code\n");
+
+ origptr = (u8 *)&alt->orig_offset + alt->orig_offset;
+ replptr = (u8 *)&alt->alt_offset + alt->alt_offset;
+ memcpy(origptr, replptr, alt->alt_len);
+ flush_icache_range((uintptr_t)origptr,
+ (uintptr_t)(origptr + alt->alt_len));
+ }
+
+ return 0;
+}
+
+void apply_alternatives_all(void)
+{
+ struct alt_region region = {
+ .begin = __alt_instructions,
+ .end = __alt_instructions_end,
+ };
+
+ /* better not try code patching on a live SMP system */
+ stop_machine(__apply_alternatives, &region, NULL);
+}
+
+void apply_alternatives(void *start, size_t length)
+{
+ struct alt_region region = {
+ .begin = start,
+ .end = start + length,
+ };
+
+ __apply_alternatives(&region);
+}
+
+void free_alternatives_memory(void)
+{
+ free_reserved_area(__alt_instructions, __alt_instructions_end,
+ 0, "alternatives");
+}
diff --git a/arch/arm64/kernel/armv8_deprecated.c b/arch/arm64/kernel/armv8_deprecated.c
new file mode 100644
index 0000000..c363671
--- /dev/null
+++ b/arch/arm64/kernel/armv8_deprecated.c
@@ -0,0 +1,553 @@
+/*
+ * Copyright (C) 2014 ARM Limited
+ *
+ * This program is free software; you can 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/cpu.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/perf_event.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/sysctl.h>
+
+#include <asm/insn.h>
+#include <asm/opcodes.h>
+#include <asm/system_misc.h>
+#include <asm/traps.h>
+#include <asm/uaccess.h>
+
+#define CREATE_TRACE_POINTS
+#include "trace-events-emulation.h"
+
+/*
+ * The runtime support for deprecated instruction support can be in one of
+ * following three states -
+ *
+ * 0 = undef
+ * 1 = emulate (software emulation)
+ * 2 = hw (supported in hardware)
+ */
+enum insn_emulation_mode {
+ INSN_UNDEF,
+ INSN_EMULATE,
+ INSN_HW,
+};
+
+enum legacy_insn_status {
+ INSN_DEPRECATED,
+ INSN_OBSOLETE,
+};
+
+struct insn_emulation_ops {
+ const char *name;
+ enum legacy_insn_status status;
+ struct undef_hook *hooks;
+ int (*set_hw_mode)(bool enable);
+};
+
+struct insn_emulation {
+ struct list_head node;
+ struct insn_emulation_ops *ops;
+ int current_mode;
+ int min;
+ int max;
+};
+
+static LIST_HEAD(insn_emulation);
+static int nr_insn_emulated;
+static DEFINE_RAW_SPINLOCK(insn_emulation_lock);
+
+static void register_emulation_hooks(struct insn_emulation_ops *ops)
+{
+ struct undef_hook *hook;
+
+ BUG_ON(!ops->hooks);
+
+ for (hook = ops->hooks; hook->instr_mask; hook++)
+ register_undef_hook(hook);
+
+ pr_notice("Registered %s emulation handler\n", ops->name);
+}
+
+static void remove_emulation_hooks(struct insn_emulation_ops *ops)
+{
+ struct undef_hook *hook;
+
+ BUG_ON(!ops->hooks);
+
+ for (hook = ops->hooks; hook->instr_mask; hook++)
+ unregister_undef_hook(hook);
+
+ pr_notice("Removed %s emulation handler\n", ops->name);
+}
+
+static int update_insn_emulation_mode(struct insn_emulation *insn,
+ enum insn_emulation_mode prev)
+{
+ int ret = 0;
+
+ switch (prev) {
+ case INSN_UNDEF: /* Nothing to be done */
+ break;
+ case INSN_EMULATE:
+ remove_emulation_hooks(insn->ops);
+ break;
+ case INSN_HW:
+ if (insn->ops->set_hw_mode) {
+ insn->ops->set_hw_mode(false);
+ pr_notice("Disabled %s support\n", insn->ops->name);
+ }
+ break;
+ }
+
+ switch (insn->current_mode) {
+ case INSN_UNDEF:
+ break;
+ case INSN_EMULATE:
+ register_emulation_hooks(insn->ops);
+ break;
+ case INSN_HW:
+ if (insn->ops->set_hw_mode && insn->ops->set_hw_mode(true))
+ pr_notice("Enabled %s support\n", insn->ops->name);
+ else
+ ret = -EINVAL;
+ break;
+ }
+
+ return ret;
+}
+
+static void register_insn_emulation(struct insn_emulation_ops *ops)
+{
+ unsigned long flags;
+ struct insn_emulation *insn;
+
+ insn = kzalloc(sizeof(*insn), GFP_KERNEL);
+ insn->ops = ops;
+ insn->min = INSN_UNDEF;
+
+ switch (ops->status) {
+ case INSN_DEPRECATED:
+ insn->current_mode = INSN_EMULATE;
+ insn->max = INSN_HW;
+ break;
+ case INSN_OBSOLETE:
+ insn->current_mode = INSN_UNDEF;
+ insn->max = INSN_EMULATE;
+ break;
+ }
+
+ raw_spin_lock_irqsave(&insn_emulation_lock, flags);
+ list_add(&insn->node, &insn_emulation);
+ nr_insn_emulated++;
+ raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
+
+ /* Register any handlers if required */
+ update_insn_emulation_mode(insn, INSN_UNDEF);
+}
+
+static int emulation_proc_handler(struct ctl_table *table, int write,
+ void __user *buffer, size_t *lenp,
+ loff_t *ppos)
+{
+ int ret = 0;
+ struct insn_emulation *insn = (struct insn_emulation *) table->data;
+ enum insn_emulation_mode prev_mode = insn->current_mode;
+
+ table->data = &insn->current_mode;
+ ret = proc_dointvec_minmax(table, write, buffer, lenp, ppos);
+
+ if (ret || !write || prev_mode == insn->current_mode)
+ goto ret;
+
+ ret = update_insn_emulation_mode(insn, prev_mode);
+ if (ret) {
+ /* Mode change failed, revert to previous mode. */
+ insn->current_mode = prev_mode;
+ update_insn_emulation_mode(insn, INSN_UNDEF);
+ }
+ret:
+ table->data = insn;
+ return ret;
+}
+
+static struct ctl_table ctl_abi[] = {
+ {
+ .procname = "abi",
+ .mode = 0555,
+ },
+ { }
+};
+
+static void register_insn_emulation_sysctl(struct ctl_table *table)
+{
+ unsigned long flags;
+ int i = 0;
+ struct insn_emulation *insn;
+ struct ctl_table *insns_sysctl, *sysctl;
+
+ insns_sysctl = kzalloc(sizeof(*sysctl) * (nr_insn_emulated + 1),
+ GFP_KERNEL);
+
+ raw_spin_lock_irqsave(&insn_emulation_lock, flags);
+ list_for_each_entry(insn, &insn_emulation, node) {
+ sysctl = &insns_sysctl[i];
+
+ sysctl->mode = 0644;
+ sysctl->maxlen = sizeof(int);
+
+ sysctl->procname = insn->ops->name;
+ sysctl->data = insn;
+ sysctl->extra1 = &insn->min;
+ sysctl->extra2 = &insn->max;
+ sysctl->proc_handler = emulation_proc_handler;
+ i++;
+ }
+ raw_spin_unlock_irqrestore(&insn_emulation_lock, flags);
+
+ table->child = insns_sysctl;
+ register_sysctl_table(table);
+}
+
+/*
+ * Implement emulation of the SWP/SWPB instructions using load-exclusive and
+ * store-exclusive.
+ *
+ * Syntax of SWP{B} instruction: SWP{B}<c> <Rt>, <Rt2>, [<Rn>]
+ * Where: Rt = destination
+ * Rt2 = source
+ * Rn = address
+ */
+
+/*
+ * Error-checking SWP macros implemented using ldxr{b}/stxr{b}
+ */
+#define __user_swpX_asm(data, addr, res, temp, B) \
+ __asm__ __volatile__( \
+ " mov %w2, %w1\n" \
+ "0: ldxr"B" %w1, [%3]\n" \
+ "1: stxr"B" %w0, %w2, [%3]\n" \
+ " cbz %w0, 2f\n" \
+ " mov %w0, %w4\n" \
+ "2:\n" \
+ " .pushsection .fixup,\"ax\"\n" \
+ " .align 2\n" \
+ "3: mov %w0, %w5\n" \
+ " b 2b\n" \
+ " .popsection" \
+ " .pushsection __ex_table,\"a\"\n" \
+ " .align 3\n" \
+ " .quad 0b, 3b\n" \
+ " .quad 1b, 3b\n" \
+ " .popsection" \
+ : "=&r" (res), "+r" (data), "=&r" (temp) \
+ : "r" (addr), "i" (-EAGAIN), "i" (-EFAULT) \
+ : "memory")
+
+#define __user_swp_asm(data, addr, res, temp) \
+ __user_swpX_asm(data, addr, res, temp, "")
+#define __user_swpb_asm(data, addr, res, temp) \
+ __user_swpX_asm(data, addr, res, temp, "b")
+
+/*
+ * Bit 22 of the instruction encoding distinguishes between
+ * the SWP and SWPB variants (bit set means SWPB).
+ */
+#define TYPE_SWPB (1 << 22)
+
+/*
+ * Set up process info to signal segmentation fault - called on access error.
+ */
+static void set_segfault(struct pt_regs *regs, unsigned long addr)
+{
+ siginfo_t info;
+
+ down_read(&current->mm->mmap_sem);
+ if (find_vma(current->mm, addr) == NULL)
+ info.si_code = SEGV_MAPERR;
+ else
+ info.si_code = SEGV_ACCERR;
+ up_read(&current->mm->mmap_sem);
+
+ info.si_signo = SIGSEGV;
+ info.si_errno = 0;
+ info.si_addr = (void *) instruction_pointer(regs);
+
+ pr_debug("SWP{B} emulation: access caused memory abort!\n");
+ arm64_notify_die("Illegal memory access", regs, &info, 0);
+}
+
+static int emulate_swpX(unsigned int address, unsigned int *data,
+ unsigned int type)
+{
+ unsigned int res = 0;
+
+ if ((type != TYPE_SWPB) && (address & 0x3)) {
+ /* SWP to unaligned address not permitted */
+ pr_debug("SWP instruction on unaligned pointer!\n");
+ return -EFAULT;
+ }
+
+ while (1) {
+ unsigned long temp;
+
+ if (type == TYPE_SWPB)
+ __user_swpb_asm(*data, address, res, temp);
+ else
+ __user_swp_asm(*data, address, res, temp);
+
+ if (likely(res != -EAGAIN) || signal_pending(current))
+ break;
+
+ cond_resched();
+ }
+
+ return res;
+}
+
+/*
+ * swp_handler logs the id of calling process, dissects the instruction, sanity
+ * checks the memory location, calls emulate_swpX for the actual operation and
+ * deals with fixup/error handling before returning
+ */
+static int swp_handler(struct pt_regs *regs, u32 instr)
+{
+ u32 destreg, data, type, address = 0;
+ int rn, rt2, res = 0;
+
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+ type = instr & TYPE_SWPB;
+
+ switch (arm_check_condition(instr, regs->pstate)) {
+ case ARM_OPCODE_CONDTEST_PASS:
+ break;
+ case ARM_OPCODE_CONDTEST_FAIL:
+ /* Condition failed - return to next instruction */
+ goto ret;
+ case ARM_OPCODE_CONDTEST_UNCOND:
+ /* If unconditional encoding - not a SWP, undef */
+ return -EFAULT;
+ default:
+ return -EINVAL;
+ }
+
+ rn = aarch32_insn_extract_reg_num(instr, A32_RN_OFFSET);
+ rt2 = aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET);
+
+ address = (u32)regs->user_regs.regs[rn];
+ data = (u32)regs->user_regs.regs[rt2];
+ destreg = aarch32_insn_extract_reg_num(instr, A32_RT_OFFSET);
+
+ pr_debug("addr in r%d->0x%08x, dest is r%d, source in r%d->0x%08x)\n",
+ rn, address, destreg,
+ aarch32_insn_extract_reg_num(instr, A32_RT2_OFFSET), data);
+
+ /* Check access in reasonable access range for both SWP and SWPB */
+ if (!access_ok(VERIFY_WRITE, (address & ~3), 4)) {
+ pr_debug("SWP{B} emulation: access to 0x%08x not allowed!\n",
+ address);
+ goto fault;
+ }
+
+ res = emulate_swpX(address, &data, type);
+ if (res == -EFAULT)
+ goto fault;
+ else if (res == 0)
+ regs->user_regs.regs[destreg] = data;
+
+ret:
+ if (type == TYPE_SWPB)
+ trace_instruction_emulation("swpb", regs->pc);
+ else
+ trace_instruction_emulation("swp", regs->pc);
+
+ pr_warn_ratelimited("\"%s\" (%ld) uses obsolete SWP{B} instruction at 0x%llx\n",
+ current->comm, (unsigned long)current->pid, regs->pc);
+
+ regs->pc += 4;
+ return 0;
+
+fault:
+ set_segfault(regs, address);
+
+ return 0;
+}
+
+/*
+ * Only emulate SWP/SWPB executed in ARM state/User mode.
+ * The kernel must be SWP free and SWP{B} does not exist in Thumb.
+ */
+static struct undef_hook swp_hooks[] = {
+ {
+ .instr_mask = 0x0fb00ff0,
+ .instr_val = 0x01000090,
+ .pstate_mask = COMPAT_PSR_MODE_MASK,
+ .pstate_val = COMPAT_PSR_MODE_USR,
+ .fn = swp_handler
+ },
+ { }
+};
+
+static struct insn_emulation_ops swp_ops = {
+ .name = "swp",
+ .status = INSN_OBSOLETE,
+ .hooks = swp_hooks,
+ .set_hw_mode = NULL,
+};
+
+static int cp15barrier_handler(struct pt_regs *regs, u32 instr)
+{
+ perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, regs->pc);
+
+ switch (arm_check_condition(instr, regs->pstate)) {
+ case ARM_OPCODE_CONDTEST_PASS:
+ break;
+ case ARM_OPCODE_CONDTEST_FAIL:
+ /* Condition failed - return to next instruction */
+ goto ret;
+ case ARM_OPCODE_CONDTEST_UNCOND:
+ /* If unconditional encoding - not a barrier instruction */
+ return -EFAULT;
+ default:
+ return -EINVAL;
+ }
+
+ switch (aarch32_insn_mcr_extract_crm(instr)) {
+ case 10:
+ /*
+ * dmb - mcr p15, 0, Rt, c7, c10, 5
+ * dsb - mcr p15, 0, Rt, c7, c10, 4
+ */
+ if (aarch32_insn_mcr_extract_opc2(instr) == 5) {
+ dmb(sy);
+ trace_instruction_emulation(
+ "mcr p15, 0, Rt, c7, c10, 5 ; dmb", regs->pc);
+ } else {
+ dsb(sy);
+ trace_instruction_emulation(
+ "mcr p15, 0, Rt, c7, c10, 4 ; dsb", regs->pc);
+ }
+ break;
+ case 5:
+ /*
+ * isb - mcr p15, 0, Rt, c7, c5, 4
+ *
+ * Taking an exception or returning from one acts as an
+ * instruction barrier. So no explicit barrier needed here.
+ */
+ trace_instruction_emulation(
+ "mcr p15, 0, Rt, c7, c5, 4 ; isb", regs->pc);
+ break;
+ }
+
+ret:
+ pr_warn_ratelimited("\"%s\" (%ld) uses deprecated CP15 Barrier instruction at 0x%llx\n",
+ current->comm, (unsigned long)current->pid, regs->pc);
+
+ regs->pc += 4;
+ return 0;
+}
+
+#define SCTLR_EL1_CP15BEN (1 << 5)
+
+static inline void config_sctlr_el1(u32 clear, u32 set)
+{
+ u32 val;
+
+ asm volatile("mrs %0, sctlr_el1" : "=r" (val));
+ val &= ~clear;
+ val |= set;
+ asm volatile("msr sctlr_el1, %0" : : "r" (val));
+}
+
+static void enable_cp15_ben(void *info)
+{
+ config_sctlr_el1(0, SCTLR_EL1_CP15BEN);
+}
+
+static void disable_cp15_ben(void *info)
+{
+ config_sctlr_el1(SCTLR_EL1_CP15BEN, 0);
+}
+
+static int cpu_hotplug_notify(struct notifier_block *b,
+ unsigned long action, void *hcpu)
+{
+ switch (action) {
+ case CPU_STARTING:
+ case CPU_STARTING_FROZEN:
+ enable_cp15_ben(NULL);
+ return NOTIFY_DONE;
+ case CPU_DYING:
+ case CPU_DYING_FROZEN:
+ disable_cp15_ben(NULL);
+ return NOTIFY_DONE;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cpu_hotplug_notifier = {
+ .notifier_call = cpu_hotplug_notify,
+};
+
+static int cp15_barrier_set_hw_mode(bool enable)
+{
+ if (enable) {
+ register_cpu_notifier(&cpu_hotplug_notifier);
+ on_each_cpu(enable_cp15_ben, NULL, true);
+ } else {
+ unregister_cpu_notifier(&cpu_hotplug_notifier);
+ on_each_cpu(disable_cp15_ben, NULL, true);
+ }
+
+ return true;
+}
+
+static struct undef_hook cp15_barrier_hooks[] = {
+ {
+ .instr_mask = 0x0fff0fdf,
+ .instr_val = 0x0e070f9a,
+ .pstate_mask = COMPAT_PSR_MODE_MASK,
+ .pstate_val = COMPAT_PSR_MODE_USR,
+ .fn = cp15barrier_handler,
+ },
+ {
+ .instr_mask = 0x0fff0fff,
+ .instr_val = 0x0e070f95,
+ .pstate_mask = COMPAT_PSR_MODE_MASK,
+ .pstate_val = COMPAT_PSR_MODE_USR,
+ .fn = cp15barrier_handler,
+ },
+ { }
+};
+
+static struct insn_emulation_ops cp15_barrier_ops = {
+ .name = "cp15_barrier",
+ .status = INSN_DEPRECATED,
+ .hooks = cp15_barrier_hooks,
+ .set_hw_mode = cp15_barrier_set_hw_mode,
+};
+
+/*
+ * Invoked as late_initcall, since not needed before init spawned.
+ */
+static int __init armv8_deprecated_init(void)
+{
+ if (IS_ENABLED(CONFIG_SWP_EMULATION))
+ register_insn_emulation(&swp_ops);
+
+ if (IS_ENABLED(CONFIG_CP15_BARRIER_EMULATION))
+ register_insn_emulation(&cp15_barrier_ops);
+
+ register_insn_emulation_sysctl(ctl_abi);
+
+ return 0;
+}
+
+late_initcall(armv8_deprecated_init);
diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
new file mode 100644
index 0000000..fa62637
--- /dev/null
+++ b/arch/arm64/kernel/cpu_errata.c
@@ -0,0 +1,111 @@
+/*
+ * Contains CPU specific errata definitions
+ *
+ * Copyright (C) 2014 ARM 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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define pr_fmt(fmt) "alternatives: " fmt
+
+#include <linux/types.h>
+#include <asm/cpu.h>
+#include <asm/cputype.h>
+#include <asm/cpufeature.h>
+
+#define MIDR_CORTEX_A53 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A53)
+#define MIDR_CORTEX_A57 MIDR_CPU_PART(ARM_CPU_IMP_ARM, ARM_CPU_PART_CORTEX_A57)
+
+/*
+ * Add a struct or another datatype to the union below if you need
+ * different means to detect an affected CPU.
+ */
+struct arm64_cpu_capabilities {
+ const char *desc;
+ u16 capability;
+ bool (*is_affected)(struct arm64_cpu_capabilities *);
+ union {
+ struct {
+ u32 midr_model;
+ u32 midr_range_min, midr_range_max;
+ };
+ };
+};
+
+#define CPU_MODEL_MASK (MIDR_IMPLEMENTOR_MASK | MIDR_PARTNUM_MASK | \
+ MIDR_ARCHITECTURE_MASK)
+
+static bool __maybe_unused
+is_affected_midr_range(struct arm64_cpu_capabilities *entry)
+{
+ u32 midr = read_cpuid_id();
+
+ if ((midr & CPU_MODEL_MASK) != entry->midr_model)
+ return false;
+
+ midr &= MIDR_REVISION_MASK | MIDR_VARIANT_MASK;
+
+ return (midr >= entry->midr_range_min && midr <= entry->midr_range_max);
+}
+
+#define MIDR_RANGE(model, min, max) \
+ .is_affected = is_affected_midr_range, \
+ .midr_model = model, \
+ .midr_range_min = min, \
+ .midr_range_max = max
+
+struct arm64_cpu_capabilities arm64_errata[] = {
+#if defined(CONFIG_ARM64_ERRATUM_826319) || \
+ defined(CONFIG_ARM64_ERRATUM_827319) || \
+ defined(CONFIG_ARM64_ERRATUM_824069)
+ {
+ /* Cortex-A53 r0p[012] */
+ .desc = "ARM errata 826319, 827319, 824069",
+ .capability = ARM64_WORKAROUND_CLEAN_CACHE,
+ MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x02),
+ },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_819472
+ {
+ /* Cortex-A53 r0p[01] */
+ .desc = "ARM errata 819472",
+ .capability = ARM64_WORKAROUND_CLEAN_CACHE,
+ MIDR_RANGE(MIDR_CORTEX_A53, 0x00, 0x01),
+ },
+#endif
+#ifdef CONFIG_ARM64_ERRATUM_832075
+ {
+ /* Cortex-A57 r0p0 - r1p2 */
+ .desc = "ARM erratum 832075",
+ .capability = ARM64_WORKAROUND_DEVICE_LOAD_ACQUIRE,
+ MIDR_RANGE(MIDR_CORTEX_A57, 0x00, 0x12),
+ },
+#endif
+ {
+ }
+};
+
+void check_local_cpu_errata(void)
+{
+ struct arm64_cpu_capabilities *cpus = arm64_errata;
+ int i;
+
+ for (i = 0; cpus[i].desc; i++) {
+ if (!cpus[i].is_affected(&cpus[i]))
+ continue;
+
+ if (!cpus_have_cap(cpus[i].capability))
+ pr_info("enabling workaround for %s\n", cpus[i].desc);
+ cpus_set_cap(cpus[i].capability);
+ }
+}
diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c
index 504fdaa..57b6417 100644
--- a/arch/arm64/kernel/cpuinfo.c
+++ b/arch/arm64/kernel/cpuinfo.c
@@ -18,6 +18,7 @@
#include <asm/cachetype.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
+#include <asm/cpufeature.h>
#include <linux/bitops.h>
#include <linux/bug.h>
@@ -111,6 +112,15 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur)
diff |= CHECK(cntfrq, boot, cur, cpu);
/*
+ * The kernel uses self-hosted debug features and expects CPUs to
+ * support identical debug features. We presently need CTX_CMPs, WRPs,
+ * and BRPs to be identical.
+ * ID_AA64DFR1 is currently RES0.
+ */
+ diff |= CHECK(id_aa64dfr0, boot, cur, cpu);
+ diff |= CHECK(id_aa64dfr1, boot, cur, cpu);
+
+ /*
* Even in big.LITTLE, processors should be identical instruction-set
* wise.
*/
@@ -143,7 +153,12 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur)
diff |= CHECK(id_isar3, boot, cur, cpu);
diff |= CHECK(id_isar4, boot, cur, cpu);
diff |= CHECK(id_isar5, boot, cur, cpu);
- diff |= CHECK(id_mmfr0, boot, cur, cpu);
+ /*
+ * Regardless of the value of the AuxReg field, the AIFSR, ADFSR, and
+ * ACTLR formats could differ across CPUs and therefore would have to
+ * be trapped for virtualization anyway.
+ */
+ diff |= CHECK_MASK(id_mmfr0, 0xff0fffff, boot, cur, cpu);
diff |= CHECK(id_mmfr1, boot, cur, cpu);
diff |= CHECK(id_mmfr2, boot, cur, cpu);
diff |= CHECK(id_mmfr3, boot, cur, cpu);
@@ -155,7 +170,7 @@ static void cpuinfo_sanity_check(struct cpuinfo_arm64 *cur)
* pretend to support them.
*/
WARN_TAINT_ONCE(diff, TAINT_CPU_OUT_OF_SPEC,
- "Unsupported CPU feature variation.");
+ "Unsupported CPU feature variation.\n");
}
static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
@@ -165,6 +180,8 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_dczid = read_cpuid(DCZID_EL0);
info->reg_midr = read_cpuid_id();
+ info->reg_id_aa64dfr0 = read_cpuid(ID_AA64DFR0_EL1);
+ info->reg_id_aa64dfr1 = read_cpuid(ID_AA64DFR1_EL1);
info->reg_id_aa64isar0 = read_cpuid(ID_AA64ISAR0_EL1);
info->reg_id_aa64isar1 = read_cpuid(ID_AA64ISAR1_EL1);
info->reg_id_aa64mmfr0 = read_cpuid(ID_AA64MMFR0_EL1);
@@ -186,6 +203,8 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info)
info->reg_id_pfr1 = read_cpuid(ID_PFR1_EL1);
cpuinfo_detect_icache_policy(info);
+
+ check_local_cpu_errata();
}
void cpuinfo_store_cpu(void)
diff --git a/arch/arm64/kernel/efi-entry.S b/arch/arm64/kernel/efi-entry.S
index d18a449..8ce9b05 100644
--- a/arch/arm64/kernel/efi-entry.S
+++ b/arch/arm64/kernel/efi-entry.S
@@ -61,7 +61,8 @@ ENTRY(efi_stub_entry)
*/
mov x20, x0 // DTB address
ldr x0, [sp, #16] // relocated _text address
- mov x21, x0
+ ldr x21, =stext_offset
+ add x21, x0, x21
/*
* Calculate size of the kernel Image (same for original and copy).
diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index 95c49eb..6fac253 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -11,6 +11,7 @@
*
*/
+#include <linux/dmi.h>
#include <linux/efi.h>
#include <linux/export.h>
#include <linux/memblock.h>
@@ -112,8 +113,6 @@ static int __init uefi_init(void)
efi.systab->hdr.revision & 0xffff, vendor);
retval = efi_config_init(NULL);
- if (retval == 0)
- set_bit(EFI_CONFIG_TABLES, &efi.flags);
out:
early_memunmap(efi.systab, sizeof(efi_system_table_t));
@@ -125,17 +124,17 @@ out:
*/
static __init int is_reserve_region(efi_memory_desc_t *md)
{
- if (!is_normal_ram(md))
+ switch (md->type) {
+ case EFI_LOADER_CODE:
+ case EFI_LOADER_DATA:
+ case EFI_BOOT_SERVICES_CODE:
+ case EFI_BOOT_SERVICES_DATA:
+ case EFI_CONVENTIONAL_MEMORY:
return 0;
-
- if (md->attribute & EFI_MEMORY_RUNTIME)
- return 1;
-
- if (md->type == EFI_ACPI_RECLAIM_MEMORY ||
- md->type == EFI_RESERVED_TYPE)
- return 1;
-
- return 0;
+ default:
+ break;
+ }
+ return is_normal_ram(md);
}
static __init void reserve_regions(void)
@@ -471,3 +470,17 @@ err_unmap:
return -1;
}
early_initcall(arm64_enter_virtual_mode);
+
+static int __init arm64_dmi_init(void)
+{
+ /*
+ * On arm64, DMI depends on UEFI, and dmi_scan_machine() needs to
+ * be called early because dmi_id_init(), which is an arch_initcall
+ * itself, depends on dmi_scan_machine() having been called already.
+ */
+ dmi_scan_machine();
+ if (dmi_available)
+ dmi_set_dump_stack_arch_desc();
+ return 0;
+}
+core_initcall(arm64_dmi_init);
diff --git a/arch/arm64/kernel/entry-ftrace.S b/arch/arm64/kernel/entry-ftrace.S
index 38e704e..08cafc5 100644
--- a/arch/arm64/kernel/entry-ftrace.S
+++ b/arch/arm64/kernel/entry-ftrace.S
@@ -98,8 +98,8 @@
ENTRY(_mcount)
mcount_enter
- ldr x0, =ftrace_trace_function
- ldr x2, [x0]
+ adrp x0, ftrace_trace_function
+ ldr x2, [x0, #:lo12:ftrace_trace_function]
adr x0, ftrace_stub
cmp x0, x2 // if (ftrace_trace_function
b.eq skip_ftrace_call // != ftrace_stub) {
@@ -115,14 +115,15 @@ skip_ftrace_call: // return;
mcount_exit // return;
// }
skip_ftrace_call:
- ldr x1, =ftrace_graph_return
- ldr x2, [x1] // if ((ftrace_graph_return
- cmp x0, x2 // != ftrace_stub)
- b.ne ftrace_graph_caller
-
- ldr x1, =ftrace_graph_entry // || (ftrace_graph_entry
- ldr x2, [x1] // != ftrace_graph_entry_stub))
- ldr x0, =ftrace_graph_entry_stub
+ adrp x1, ftrace_graph_return
+ ldr x2, [x1, #:lo12:ftrace_graph_return]
+ cmp x0, x2 // if ((ftrace_graph_return
+ b.ne ftrace_graph_caller // != ftrace_stub)
+
+ adrp x1, ftrace_graph_entry // || (ftrace_graph_entry
+ adrp x0, ftrace_graph_entry_stub // != ftrace_graph_entry_stub))
+ ldr x2, [x1, #:lo12:ftrace_graph_entry]
+ add x0, x0, #:lo12:ftrace_graph_entry_stub
cmp x0, x2
b.ne ftrace_graph_caller // ftrace_graph_caller();
diff --git a/arch/arm64/kernel/entry.S b/arch/arm64/kernel/entry.S
index 726b910..fd4fa37 100644
--- a/arch/arm64/kernel/entry.S
+++ b/arch/arm64/kernel/entry.S
@@ -64,25 +64,26 @@
#define BAD_ERROR 3
.macro kernel_entry, el, regsize = 64
- sub sp, sp, #S_FRAME_SIZE - S_LR // room for LR, SP, SPSR, ELR
+ sub sp, sp, #S_FRAME_SIZE
.if \regsize == 32
mov w0, w0 // zero upper 32 bits of x0
.endif
- push x28, x29
- push x26, x27
- push x24, x25
- push x22, x23
- push x20, x21
- push x18, x19
- push x16, x17
- push x14, x15
- push x12, x13
- push x10, x11
- push x8, x9
- push x6, x7
- push x4, x5
- push x2, x3
- push x0, x1
+ stp x0, x1, [sp, #16 * 0]
+ stp x2, x3, [sp, #16 * 1]
+ stp x4, x5, [sp, #16 * 2]
+ stp x6, x7, [sp, #16 * 3]
+ stp x8, x9, [sp, #16 * 4]
+ stp x10, x11, [sp, #16 * 5]
+ stp x12, x13, [sp, #16 * 6]
+ stp x14, x15, [sp, #16 * 7]
+ stp x16, x17, [sp, #16 * 8]
+ stp x18, x19, [sp, #16 * 9]
+ stp x20, x21, [sp, #16 * 10]
+ stp x22, x23, [sp, #16 * 11]
+ stp x24, x25, [sp, #16 * 12]
+ stp x26, x27, [sp, #16 * 13]
+ stp x28, x29, [sp, #16 * 14]
+
.if \el == 0
mrs x21, sp_el0
get_thread_info tsk // Ensure MDSCR_EL1.SS is clear,
@@ -118,33 +119,31 @@
.if \el == 0
ct_user_enter
ldr x23, [sp, #S_SP] // load return stack pointer
+ msr sp_el0, x23
.endif
+ msr elr_el1, x21 // set up the return data
+ msr spsr_el1, x22
.if \ret
ldr x1, [sp, #S_X1] // preserve x0 (syscall return)
- add sp, sp, S_X2
.else
- pop x0, x1
+ ldp x0, x1, [sp, #16 * 0]
.endif
- pop x2, x3 // load the rest of the registers
- pop x4, x5
- pop x6, x7
- pop x8, x9
- msr elr_el1, x21 // set up the return data
- msr spsr_el1, x22
- .if \el == 0
- msr sp_el0, x23
- .endif
- pop x10, x11
- pop x12, x13
- pop x14, x15
- pop x16, x17
- pop x18, x19
- pop x20, x21
- pop x22, x23
- pop x24, x25
- pop x26, x27
- pop x28, x29
- ldr lr, [sp], #S_FRAME_SIZE - S_LR // load LR and restore SP
+ ldp x2, x3, [sp, #16 * 1]
+ ldp x4, x5, [sp, #16 * 2]
+ ldp x6, x7, [sp, #16 * 3]
+ ldp x8, x9, [sp, #16 * 4]
+ ldp x10, x11, [sp, #16 * 5]
+ ldp x12, x13, [sp, #16 * 6]
+ ldp x14, x15, [sp, #16 * 7]
+ ldp x16, x17, [sp, #16 * 8]
+ ldp x18, x19, [sp, #16 * 9]
+ ldp x20, x21, [sp, #16 * 10]
+ ldp x22, x23, [sp, #16 * 11]
+ ldp x24, x25, [sp, #16 * 12]
+ ldp x26, x27, [sp, #16 * 13]
+ ldp x28, x29, [sp, #16 * 14]
+ ldr lr, [sp, #S_LR]
+ add sp, sp, #S_FRAME_SIZE // restore sp
eret // return to kernel
.endm
@@ -168,7 +167,8 @@ tsk .req x28 // current thread_info
* Interrupt handling.
*/
.macro irq_handler
- ldr x1, handle_arch_irq
+ adrp x1, handle_arch_irq
+ ldr x1, [x1, #:lo12:handle_arch_irq]
mov x0, sp
blr x1
.endm
@@ -455,8 +455,8 @@ el0_da:
bic x0, x26, #(0xff << 56)
mov x1, x25
mov x2, sp
- adr lr, ret_to_user
- b do_mem_abort
+ bl do_mem_abort
+ b ret_to_user
el0_ia:
/*
* Instruction abort handling
@@ -468,8 +468,8 @@ el0_ia:
mov x0, x26
orr x1, x25, #1 << 24 // use reserved ISS bit for instruction aborts
mov x2, sp
- adr lr, ret_to_user
- b do_mem_abort
+ bl do_mem_abort
+ b ret_to_user
el0_fpsimd_acc:
/*
* Floating Point or Advanced SIMD access
@@ -478,8 +478,8 @@ el0_fpsimd_acc:
ct_user_exit
mov x0, x25
mov x1, sp
- adr lr, ret_to_user
- b do_fpsimd_acc
+ bl do_fpsimd_acc
+ b ret_to_user
el0_fpsimd_exc:
/*
* Floating Point or Advanced SIMD exception
@@ -488,8 +488,8 @@ el0_fpsimd_exc:
ct_user_exit
mov x0, x25
mov x1, sp
- adr lr, ret_to_user
- b do_fpsimd_exc
+ bl do_fpsimd_exc
+ b ret_to_user
el0_sp_pc:
/*
* Stack or PC alignment exception handling
@@ -500,8 +500,8 @@ el0_sp_pc:
mov x0, x26
mov x1, x25
mov x2, sp
- adr lr, ret_to_user
- b do_sp_pc_abort
+ bl do_sp_pc_abort
+ b ret_to_user
el0_undef:
/*
* Undefined instruction
@@ -510,8 +510,8 @@ el0_undef:
enable_dbg_and_irq
ct_user_exit
mov x0, sp
- adr lr, ret_to_user
- b do_undefinstr
+ bl do_undefinstr
+ b ret_to_user
el0_dbg:
/*
* Debug exception handling
@@ -530,8 +530,8 @@ el0_inv:
mov x0, sp
mov x1, #BAD_SYNC
mrs x2, esr_el1
- adr lr, ret_to_user
- b bad_mode
+ bl bad_mode
+ b ret_to_user
ENDPROC(el0_sync)
.align 6
@@ -653,14 +653,15 @@ el0_svc_naked: // compat entry point
ldr x16, [tsk, #TI_FLAGS] // check for syscall hooks
tst x16, #_TIF_SYSCALL_WORK
b.ne __sys_trace
- adr lr, ret_fast_syscall // return address
cmp scno, sc_nr // check upper syscall limit
b.hs ni_sys
ldr x16, [stbl, scno, lsl #3] // address in the syscall table
- br x16 // call sys_* routine
+ blr x16 // call sys_* routine
+ b ret_fast_syscall
ni_sys:
mov x0, sp
- b do_ni_syscall
+ bl do_ni_syscall
+ b ret_fast_syscall
ENDPROC(el0_svc)
/*
@@ -668,26 +669,38 @@ ENDPROC(el0_svc)
* switches, and waiting for our parent to respond.
*/
__sys_trace:
- mov x0, sp
+ mov w0, #-1 // set default errno for
+ cmp scno, x0 // user-issued syscall(-1)
+ b.ne 1f
+ mov x0, #-ENOSYS
+ str x0, [sp, #S_X0]
+1: mov x0, sp
bl syscall_trace_enter
- adr lr, __sys_trace_return // return address
+ cmp w0, #-1 // skip the syscall?
+ b.eq __sys_trace_return_skipped
uxtw scno, w0 // syscall number (possibly new)
mov x1, sp // pointer to regs
cmp scno, sc_nr // check upper syscall limit
- b.hs ni_sys
+ b.hs __ni_sys_trace
ldp x0, x1, [sp] // restore the syscall args
ldp x2, x3, [sp, #S_X2]
ldp x4, x5, [sp, #S_X4]
ldp x6, x7, [sp, #S_X6]
ldr x16, [stbl, scno, lsl #3] // address in the syscall table
- br x16 // call sys_* routine
+ blr x16 // call sys_* routine
__sys_trace_return:
- str x0, [sp] // save returned x0
+ str x0, [sp, #S_X0] // save returned x0
+__sys_trace_return_skipped:
mov x0, sp
bl syscall_trace_exit
b ret_to_user
+__ni_sys_trace:
+ mov x0, sp
+ bl do_ni_syscall
+ b __sys_trace_return
+
/*
* Special system call wrappers.
*/
@@ -695,6 +708,3 @@ ENTRY(sys_rt_sigreturn_wrapper)
mov x0, sp
b sys_rt_sigreturn
ENDPROC(sys_rt_sigreturn_wrapper)
-
-ENTRY(handle_arch_irq)
- .quad 0
diff --git a/arch/arm64/kernel/head.S b/arch/arm64/kernel/head.S
index 0a6e4f9..8ce88e0 100644
--- a/arch/arm64/kernel/head.S
+++ b/arch/arm64/kernel/head.S
@@ -132,6 +132,8 @@ efi_head:
#endif
#ifdef CONFIG_EFI
+ .globl stext_offset
+ .set stext_offset, stext - efi_head
.align 3
pe_header:
.ascii "PE"
@@ -155,12 +157,12 @@ optional_header:
.long 0 // SizeOfInitializedData
.long 0 // SizeOfUninitializedData
.long efi_stub_entry - efi_head // AddressOfEntryPoint
- .long stext - efi_head // BaseOfCode
+ .long stext_offset // BaseOfCode
extra_header_fields:
.quad 0 // ImageBase
- .long 0x20 // SectionAlignment
- .long 0x8 // FileAlignment
+ .long 0x1000 // SectionAlignment
+ .long PECOFF_FILE_ALIGNMENT // FileAlignment
.short 0 // MajorOperatingSystemVersion
.short 0 // MinorOperatingSystemVersion
.short 0 // MajorImageVersion
@@ -172,7 +174,7 @@ extra_header_fields:
.long _end - efi_head // SizeOfImage
// Everything before the kernel image is considered part of the header
- .long stext - efi_head // SizeOfHeaders
+ .long stext_offset // SizeOfHeaders
.long 0 // CheckSum
.short 0xa // Subsystem (EFI application)
.short 0 // DllCharacteristics
@@ -217,16 +219,24 @@ section_table:
.byte 0
.byte 0 // end of 0 padding of section name
.long _end - stext // VirtualSize
- .long stext - efi_head // VirtualAddress
+ .long stext_offset // VirtualAddress
.long _edata - stext // SizeOfRawData
- .long stext - efi_head // PointerToRawData
+ .long stext_offset // PointerToRawData
.long 0 // PointerToRelocations (0 for executables)
.long 0 // PointerToLineNumbers (0 for executables)
.short 0 // NumberOfRelocations (0 for executables)
.short 0 // NumberOfLineNumbers (0 for executables)
.long 0xe0500020 // Characteristics (section flags)
- .align 5
+
+ /*
+ * EFI will load stext onwards at the 4k section alignment
+ * described in the PE/COFF header. To ensure that instruction
+ * sequences using an adrp and a :lo12: immediate will function
+ * correctly at this alignment, we must ensure that stext is
+ * placed at a 4k boundary in the Image to begin with.
+ */
+ .align 12
#endif
ENTRY(stext)
@@ -238,7 +248,13 @@ ENTRY(stext)
mov x0, x22
bl lookup_processor_type
mov x23, x0 // x23=current cpu_table
- cbz x23, __error_p // invalid processor (x23=0)?
+ /*
+ * __error_p may end up out of range for cbz if text areas are
+ * aligned up to section sizes.
+ */
+ cbnz x23, 1f // invalid processor (x23=0)?
+ b __error_p
+1:
bl __vet_fdt
bl __create_page_tables // x25=TTBR0, x26=TTBR1
/*
@@ -250,13 +266,214 @@ ENTRY(stext)
*/
ldr x27, __switch_data // address to jump to after
// MMU has been enabled
- adr lr, __enable_mmu // return (PIC) address
+ adrp lr, __enable_mmu // return (PIC) address
+ add lr, lr, #:lo12:__enable_mmu
ldr x12, [x23, #CPU_INFO_SETUP]
add x12, x12, x28 // __virt_to_phys
br x12 // initialise processor
ENDPROC(stext)
/*
+ * Determine validity of the x21 FDT pointer.
+ * The dtb must be 8-byte aligned and live in the first 512M of memory.
+ */
+__vet_fdt:
+ tst x21, #0x7
+ b.ne 1f
+ cmp x21, x24
+ b.lt 1f
+ mov x0, #(1 << 29)
+ add x0, x0, x24
+ cmp x21, x0
+ b.ge 1f
+ ret
+1:
+ mov x21, #0
+ ret
+ENDPROC(__vet_fdt)
+/*
+ * Macro to create a table entry to the next page.
+ *
+ * tbl: page table address
+ * virt: virtual address
+ * shift: #imm page table shift
+ * ptrs: #imm pointers per table page
+ *
+ * Preserves: virt
+ * Corrupts: tmp1, tmp2
+ * Returns: tbl -> next level table page address
+ */
+ .macro create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2
+ lsr \tmp1, \virt, #\shift
+ and \tmp1, \tmp1, #\ptrs - 1 // table index
+ add \tmp2, \tbl, #PAGE_SIZE
+ orr \tmp2, \tmp2, #PMD_TYPE_TABLE // address of next table and entry type
+ str \tmp2, [\tbl, \tmp1, lsl #3]
+ add \tbl, \tbl, #PAGE_SIZE // next level table page
+ .endm
+
+/*
+ * Macro to populate the PGD (and possibily PUD) for the corresponding
+ * block entry in the next level (tbl) for the given virtual address.
+ *
+ * Preserves: tbl, next, virt
+ * Corrupts: tmp1, tmp2
+ */
+ .macro create_pgd_entry, tbl, virt, tmp1, tmp2
+ create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2
+#if SWAPPER_PGTABLE_LEVELS == 3
+ create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2
+#endif
+ .endm
+
+/*
+ * Macro to populate block entries in the page table for the start..end
+ * virtual range (inclusive).
+ *
+ * Preserves: tbl, flags
+ * Corrupts: phys, start, end, pstate
+ */
+ .macro create_block_map, tbl, flags, phys, start, end
+ lsr \phys, \phys, #BLOCK_SHIFT
+ lsr \start, \start, #BLOCK_SHIFT
+ and \start, \start, #PTRS_PER_PTE - 1 // table index
+ orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry
+ lsr \end, \end, #BLOCK_SHIFT
+ and \end, \end, #PTRS_PER_PTE - 1 // table end index
+9999: str \phys, [\tbl, \start, lsl #3] // store the entry
+ add \start, \start, #1 // next entry
+ add \phys, \phys, #BLOCK_SIZE // next block
+ cmp \start, \end
+ b.ls 9999b
+ .endm
+
+/*
+ * Setup the initial page tables. We only setup the barest amount which is
+ * required to get the kernel running. The following sections are required:
+ * - identity mapping to enable the MMU (low address, TTBR0)
+ * - first few MB of the kernel linear mapping to jump to once the MMU has
+ * been enabled, including the FDT blob (TTBR1)
+ * - pgd entry for fixed mappings (TTBR1)
+ */
+__create_page_tables:
+ pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses
+ mov x27, lr
+
+ /*
+ * Invalidate the idmap and swapper page tables to avoid potential
+ * dirty cache lines being evicted.
+ */
+ mov x0, x25
+ add x1, x26, #SWAPPER_DIR_SIZE
+ bl __inval_cache_range
+
+ /*
+ * Clear the idmap and swapper page tables.
+ */
+ mov x0, x25
+ add x6, x26, #SWAPPER_DIR_SIZE
+1: stp xzr, xzr, [x0], #16
+ stp xzr, xzr, [x0], #16
+ stp xzr, xzr, [x0], #16
+ stp xzr, xzr, [x0], #16
+ cmp x0, x6
+ b.lo 1b
+
+ ldr x7, =MM_MMUFLAGS
+
+ /*
+ * Create the identity mapping.
+ */
+ mov x0, x25 // idmap_pg_dir
+ ldr x3, =KERNEL_START
+ add x3, x3, x28 // __pa(KERNEL_START)
+ create_pgd_entry x0, x3, x5, x6
+ ldr x6, =KERNEL_END
+ mov x5, x3 // __pa(KERNEL_START)
+ add x6, x6, x28 // __pa(KERNEL_END)
+ create_block_map x0, x7, x3, x5, x6
+
+ /*
+ * Map the kernel image (starting with PHYS_OFFSET).
+ */
+ mov x0, x26 // swapper_pg_dir
+ mov x5, #PAGE_OFFSET
+ create_pgd_entry x0, x5, x3, x6
+ ldr x6, =KERNEL_END
+ mov x3, x24 // phys offset
+ create_block_map x0, x7, x3, x5, x6
+
+ /*
+ * Map the FDT blob (maximum 2MB; must be within 512MB of
+ * PHYS_OFFSET).
+ */
+ mov x3, x21 // FDT phys address
+ and x3, x3, #~((1 << 21) - 1) // 2MB aligned
+ mov x6, #PAGE_OFFSET
+ sub x5, x3, x24 // subtract PHYS_OFFSET
+ tst x5, #~((1 << 29) - 1) // within 512MB?
+ csel x21, xzr, x21, ne // zero the FDT pointer
+ b.ne 1f
+ add x5, x5, x6 // __va(FDT blob)
+ add x6, x5, #1 << 21 // 2MB for the FDT blob
+ sub x6, x6, #1 // inclusive range
+ create_block_map x0, x7, x3, x5, x6
+1:
+ /*
+ * Since the page tables have been populated with non-cacheable
+ * accesses (MMU disabled), invalidate the idmap and swapper page
+ * tables again to remove any speculatively loaded cache lines.
+ */
+ mov x0, x25
+ add x1, x26, #SWAPPER_DIR_SIZE
+ bl __inval_cache_range
+
+ mov lr, x27
+ ret
+ENDPROC(__create_page_tables)
+ .ltorg
+
+ .align 3
+ .type __switch_data, %object
+__switch_data:
+ .quad __mmap_switched
+ .quad __bss_start // x6
+ .quad __bss_stop // x7
+ .quad processor_id // x4
+ .quad __fdt_pointer // x5
+ .quad memstart_addr // x6
+ .quad init_thread_union + THREAD_START_SP // sp
+
+/*
+ * The following fragment of code is executed with the MMU on in MMU mode, and
+ * uses absolute addresses; this is not position independent.
+ */
+__mmap_switched:
+ adr x3, __switch_data + 8
+
+ ldp x6, x7, [x3], #16
+1: cmp x6, x7
+ b.hs 2f
+ str xzr, [x6], #8 // Clear BSS
+ b 1b
+2:
+ ldp x4, x5, [x3], #16
+ ldr x6, [x3], #8
+ ldr x16, [x3]
+ mov sp, x16
+ str x22, [x4] // Save processor ID
+ str x21, [x5] // Save FDT pointer
+ str x24, [x6] // Save PHYS_OFFSET
+ mov x29, #0
+ b start_kernel
+ENDPROC(__mmap_switched)
+
+/*
+ * end early head section, begin head code that is also used for
+ * hotplug and needs to have the same protections as the text region
+ */
+ .section ".text","ax"
+/*
* If we're fortunate enough to boot at EL2, ensure that the world is
* sane before dropping to EL1.
*
@@ -331,7 +548,8 @@ CPU_LE( movk x0, #0x30d0, lsl #16 ) // Clear EE and E0E on LE systems
msr vttbr_el2, xzr
/* Hypervisor stub */
- adr x0, __hyp_stub_vectors
+ adrp x0, __hyp_stub_vectors
+ add x0, x0, #:lo12:__hyp_stub_vectors
msr vbar_el2, x0
/* spsr */
@@ -492,183 +710,6 @@ ENDPROC(__calc_phys_offset)
.quad PAGE_OFFSET
/*
- * Macro to create a table entry to the next page.
- *
- * tbl: page table address
- * virt: virtual address
- * shift: #imm page table shift
- * ptrs: #imm pointers per table page
- *
- * Preserves: virt
- * Corrupts: tmp1, tmp2
- * Returns: tbl -> next level table page address
- */
- .macro create_table_entry, tbl, virt, shift, ptrs, tmp1, tmp2
- lsr \tmp1, \virt, #\shift
- and \tmp1, \tmp1, #\ptrs - 1 // table index
- add \tmp2, \tbl, #PAGE_SIZE
- orr \tmp2, \tmp2, #PMD_TYPE_TABLE // address of next table and entry type
- str \tmp2, [\tbl, \tmp1, lsl #3]
- add \tbl, \tbl, #PAGE_SIZE // next level table page
- .endm
-
-/*
- * Macro to populate the PGD (and possibily PUD) for the corresponding
- * block entry in the next level (tbl) for the given virtual address.
- *
- * Preserves: tbl, next, virt
- * Corrupts: tmp1, tmp2
- */
- .macro create_pgd_entry, tbl, virt, tmp1, tmp2
- create_table_entry \tbl, \virt, PGDIR_SHIFT, PTRS_PER_PGD, \tmp1, \tmp2
-#if SWAPPER_PGTABLE_LEVELS == 3
- create_table_entry \tbl, \virt, TABLE_SHIFT, PTRS_PER_PTE, \tmp1, \tmp2
-#endif
- .endm
-
-/*
- * Macro to populate block entries in the page table for the start..end
- * virtual range (inclusive).
- *
- * Preserves: tbl, flags
- * Corrupts: phys, start, end, pstate
- */
- .macro create_block_map, tbl, flags, phys, start, end
- lsr \phys, \phys, #BLOCK_SHIFT
- lsr \start, \start, #BLOCK_SHIFT
- and \start, \start, #PTRS_PER_PTE - 1 // table index
- orr \phys, \flags, \phys, lsl #BLOCK_SHIFT // table entry
- lsr \end, \end, #BLOCK_SHIFT
- and \end, \end, #PTRS_PER_PTE - 1 // table end index
-9999: str \phys, [\tbl, \start, lsl #3] // store the entry
- add \start, \start, #1 // next entry
- add \phys, \phys, #BLOCK_SIZE // next block
- cmp \start, \end
- b.ls 9999b
- .endm
-
-/*
- * Setup the initial page tables. We only setup the barest amount which is
- * required to get the kernel running. The following sections are required:
- * - identity mapping to enable the MMU (low address, TTBR0)
- * - first few MB of the kernel linear mapping to jump to once the MMU has
- * been enabled, including the FDT blob (TTBR1)
- * - pgd entry for fixed mappings (TTBR1)
- */
-__create_page_tables:
- pgtbl x25, x26, x28 // idmap_pg_dir and swapper_pg_dir addresses
- mov x27, lr
-
- /*
- * Invalidate the idmap and swapper page tables to avoid potential
- * dirty cache lines being evicted.
- */
- mov x0, x25
- add x1, x26, #SWAPPER_DIR_SIZE
- bl __inval_cache_range
-
- /*
- * Clear the idmap and swapper page tables.
- */
- mov x0, x25
- add x6, x26, #SWAPPER_DIR_SIZE
-1: stp xzr, xzr, [x0], #16
- stp xzr, xzr, [x0], #16
- stp xzr, xzr, [x0], #16
- stp xzr, xzr, [x0], #16
- cmp x0, x6
- b.lo 1b
-
- ldr x7, =MM_MMUFLAGS
-
- /*
- * Create the identity mapping.
- */
- mov x0, x25 // idmap_pg_dir
- ldr x3, =KERNEL_START
- add x3, x3, x28 // __pa(KERNEL_START)
- create_pgd_entry x0, x3, x5, x6
- ldr x6, =KERNEL_END
- mov x5, x3 // __pa(KERNEL_START)
- add x6, x6, x28 // __pa(KERNEL_END)
- create_block_map x0, x7, x3, x5, x6
-
- /*
- * Map the kernel image (starting with PHYS_OFFSET).
- */
- mov x0, x26 // swapper_pg_dir
- mov x5, #PAGE_OFFSET
- create_pgd_entry x0, x5, x3, x6
- ldr x6, =KERNEL_END
- mov x3, x24 // phys offset
- create_block_map x0, x7, x3, x5, x6
-
- /*
- * Map the FDT blob (maximum 2MB; must be within 512MB of
- * PHYS_OFFSET).
- */
- mov x3, x21 // FDT phys address
- and x3, x3, #~((1 << 21) - 1) // 2MB aligned
- mov x6, #PAGE_OFFSET
- sub x5, x3, x24 // subtract PHYS_OFFSET
- tst x5, #~((1 << 29) - 1) // within 512MB?
- csel x21, xzr, x21, ne // zero the FDT pointer
- b.ne 1f
- add x5, x5, x6 // __va(FDT blob)
- add x6, x5, #1 << 21 // 2MB for the FDT blob
- sub x6, x6, #1 // inclusive range
- create_block_map x0, x7, x3, x5, x6
-1:
- /*
- * Since the page tables have been populated with non-cacheable
- * accesses (MMU disabled), invalidate the idmap and swapper page
- * tables again to remove any speculatively loaded cache lines.
- */
- mov x0, x25
- add x1, x26, #SWAPPER_DIR_SIZE
- bl __inval_cache_range
-
- mov lr, x27
- ret
-ENDPROC(__create_page_tables)
- .ltorg
-
- .align 3
- .type __switch_data, %object
-__switch_data:
- .quad __mmap_switched
- .quad __bss_start // x6
- .quad __bss_stop // x7
- .quad processor_id // x4
- .quad __fdt_pointer // x5
- .quad memstart_addr // x6
- .quad init_thread_union + THREAD_START_SP // sp
-
-/*
- * The following fragment of code is executed with the MMU on in MMU mode, and
- * uses absolute addresses; this is not position independent.
- */
-__mmap_switched:
- adr x3, __switch_data + 8
-
- ldp x6, x7, [x3], #16
-1: cmp x6, x7
- b.hs 2f
- str xzr, [x6], #8 // Clear BSS
- b 1b
-2:
- ldp x4, x5, [x3], #16
- ldr x6, [x3], #8
- ldr x16, [x3]
- mov sp, x16
- str x22, [x4] // Save processor ID
- str x21, [x5] // Save FDT pointer
- str x24, [x6] // Save PHYS_OFFSET
- mov x29, #0
- b start_kernel
-ENDPROC(__mmap_switched)
-
-/*
* Exception handling. Something went wrong and we can't proceed. We ought to
* tell the user, but since we don't have any guarantee that we're even
* running on the right architecture, we do virtually nothing.
@@ -715,22 +756,3 @@ __lookup_processor_type_data:
.quad .
.quad cpu_table
.size __lookup_processor_type_data, . - __lookup_processor_type_data
-
-/*
- * Determine validity of the x21 FDT pointer.
- * The dtb must be 8-byte aligned and live in the first 512M of memory.
- */
-__vet_fdt:
- tst x21, #0x7
- b.ne 1f
- cmp x21, x24
- b.lt 1f
- mov x0, #(1 << 29)
- add x0, x0, x24
- cmp x21, x0
- b.ge 1f
- ret
-1:
- mov x21, #0
- ret
-ENDPROC(__vet_fdt)
diff --git a/arch/arm64/kernel/insn.c b/arch/arm64/kernel/insn.c
index 8cd27fe..7e9327a 100644
--- a/arch/arm64/kernel/insn.c
+++ b/arch/arm64/kernel/insn.c
@@ -960,3 +960,29 @@ u32 aarch64_insn_gen_logical_shifted_reg(enum aarch64_insn_register dst,
return aarch64_insn_encode_immediate(AARCH64_INSN_IMM_6, insn, shift);
}
+
+bool aarch32_insn_is_wide(u32 insn)
+{
+ return insn >= 0xe800;
+}
+
+/*
+ * Macros/defines for extracting register numbers from instruction.
+ */
+u32 aarch32_insn_extract_reg_num(u32 insn, int offset)
+{
+ return (insn & (0xf << offset)) >> offset;
+}
+
+#define OPC2_MASK 0x7
+#define OPC2_OFFSET 5
+u32 aarch32_insn_mcr_extract_opc2(u32 insn)
+{
+ return (insn & (OPC2_MASK << OPC2_OFFSET)) >> OPC2_OFFSET;
+}
+
+#define CRM_MASK 0xf
+u32 aarch32_insn_mcr_extract_crm(u32 insn)
+{
+ return insn & CRM_MASK;
+}
diff --git a/arch/arm64/kernel/io.c b/arch/arm64/kernel/io.c
index 7d37ead..354be2a 100644
--- a/arch/arm64/kernel/io.c
+++ b/arch/arm64/kernel/io.c
@@ -25,12 +25,26 @@
*/
void __memcpy_fromio(void *to, const volatile void __iomem *from, size_t count)
{
- unsigned char *t = to;
- while (count) {
+ while (count && (!IS_ALIGNED((unsigned long)from, 8) ||
+ !IS_ALIGNED((unsigned long)to, 8))) {
+ *(u8 *)to = __raw_readb(from);
+ from++;
+ to++;
count--;
- *t = readb(from);
- t++;
+ }
+
+ while (count >= 8) {
+ *(u64 *)to = __raw_readq(from);
+ from += 8;
+ to += 8;
+ count -= 8;
+ }
+
+ while (count) {
+ *(u8 *)to = __raw_readb(from);
from++;
+ to++;
+ count--;
}
}
EXPORT_SYMBOL(__memcpy_fromio);
@@ -40,12 +54,26 @@ EXPORT_SYMBOL(__memcpy_fromio);
*/
void __memcpy_toio(volatile void __iomem *to, const void *from, size_t count)
{
- const unsigned char *f = from;
- while (count) {
+ while (count && (!IS_ALIGNED((unsigned long)to, 8) ||
+ !IS_ALIGNED((unsigned long)from, 8))) {
+ __raw_writeb(*(volatile u8 *)from, to);
+ from++;
+ to++;
count--;
- writeb(*f, to);
- f++;
+ }
+
+ while (count >= 8) {
+ __raw_writeq(*(volatile u64 *)from, to);
+ from += 8;
+ to += 8;
+ count -= 8;
+ }
+
+ while (count) {
+ __raw_writeb(*(volatile u8 *)from, to);
+ from++;
to++;
+ count--;
}
}
EXPORT_SYMBOL(__memcpy_toio);
@@ -55,10 +83,28 @@ EXPORT_SYMBOL(__memcpy_toio);
*/
void __memset_io(volatile void __iomem *dst, int c, size_t count)
{
- while (count) {
+ u64 qc = (u8)c;
+
+ qc |= qc << 8;
+ qc |= qc << 16;
+ qc |= qc << 32;
+
+ while (count && !IS_ALIGNED((unsigned long)dst, 8)) {
+ __raw_writeb(c, dst);
+ dst++;
count--;
- writeb(c, dst);
+ }
+
+ while (count >= 8) {
+ __raw_writeq(qc, dst);
+ dst += 8;
+ count -= 8;
+ }
+
+ while (count) {
+ __raw_writeb(c, dst);
dst++;
+ count--;
}
}
EXPORT_SYMBOL(__memset_io);
diff --git a/arch/arm64/kernel/irq.c b/arch/arm64/kernel/irq.c
index 071a6ec..240b75c 100644
--- a/arch/arm64/kernel/irq.c
+++ b/arch/arm64/kernel/irq.c
@@ -40,6 +40,8 @@ int arch_show_interrupts(struct seq_file *p, int prec)
return 0;
}
+void (*handle_arch_irq)(struct pt_regs *) = NULL;
+
void __init set_handle_irq(void (*handle_irq)(struct pt_regs *))
{
if (handle_arch_irq)
diff --git a/arch/arm64/kernel/jump_label.c b/arch/arm64/kernel/jump_label.c
index 263a166..4f1fec7 100644
--- a/arch/arm64/kernel/jump_label.c
+++ b/arch/arm64/kernel/jump_label.c
@@ -22,9 +22,8 @@
#ifdef HAVE_JUMP_LABEL
-static void __arch_jump_label_transform(struct jump_entry *entry,
- enum jump_label_type type,
- bool is_static)
+void arch_jump_label_transform(struct jump_entry *entry,
+ enum jump_label_type type)
{
void *addr = (void *)entry->code;
u32 insn;
@@ -37,22 +36,18 @@ static void __arch_jump_label_transform(struct jump_entry *entry,
insn = aarch64_insn_gen_nop();
}
- if (is_static)
- aarch64_insn_patch_text_nosync(addr, insn);
- else
- aarch64_insn_patch_text(&addr, &insn, 1);
-}
-
-void arch_jump_label_transform(struct jump_entry *entry,
- enum jump_label_type type)
-{
- __arch_jump_label_transform(entry, type, false);
+ aarch64_insn_patch_text(&addr, &insn, 1);
}
void arch_jump_label_transform_static(struct jump_entry *entry,
enum jump_label_type type)
{
- __arch_jump_label_transform(entry, type, true);
+ /*
+ * We use the architected A64 NOP in arch_static_branch, so there's no
+ * need to patch an identical A64 NOP over the top of it here. The core
+ * will call arch_jump_label_transform from a module notifier if the
+ * NOP needs to be replaced by a branch.
+ */
}
#endif /* HAVE_JUMP_LABEL */
diff --git a/arch/arm64/kernel/module.c b/arch/arm64/kernel/module.c
index 1eb1cc9..fd027b1 100644
--- a/arch/arm64/kernel/module.c
+++ b/arch/arm64/kernel/module.c
@@ -26,6 +26,7 @@
#include <linux/moduleloader.h>
#include <linux/vmalloc.h>
#include <asm/insn.h>
+#include <asm/sections.h>
#define AARCH64_INSN_IMM_MOVNZ AARCH64_INSN_IMM_MAX
#define AARCH64_INSN_IMM_MOVK AARCH64_INSN_IMM_16
@@ -394,3 +395,20 @@ overflow:
me->name, (int)ELF64_R_TYPE(rel[i].r_info), val);
return -ENOEXEC;
}
+
+int module_finalize(const Elf_Ehdr *hdr,
+ const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ const Elf_Shdr *s, *se;
+ const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
+
+ for (s = sechdrs, se = sechdrs + hdr->e_shnum; s < se; s++) {
+ if (strcmp(".altinstructions", secstrs + s->sh_name) == 0) {
+ apply_alternatives((void *)s->sh_addr, s->sh_size);
+ return 0;
+ }
+ }
+
+ return 0;
+}
diff --git a/arch/arm64/kernel/perf_event.c b/arch/arm64/kernel/perf_event.c
index aa29ecb..25a5308 100644
--- a/arch/arm64/kernel/perf_event.c
+++ b/arch/arm64/kernel/perf_event.c
@@ -169,8 +169,14 @@ armpmu_event_set_period(struct perf_event *event,
ret = 1;
}
- if (left > (s64)armpmu->max_period)
- left = armpmu->max_period;
+ /*
+ * Limit the maximum period to prevent the counter value
+ * from overtaking the one we are about to program. In
+ * effect we are reducing max_period to account for
+ * interrupt latency (and we are being very conservative).
+ */
+ if (left > (armpmu->max_period >> 1))
+ left = armpmu->max_period >> 1;
local64_set(&hwc->prev_count, (u64)-left);
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 8a4ae8e..d882b83 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c
@@ -27,6 +27,7 @@
#include <linux/smp.h>
#include <linux/ptrace.h>
#include <linux/user.h>
+#include <linux/seccomp.h>
#include <linux/security.h>
#include <linux/init.h>
#include <linux/signal.h>
@@ -551,6 +552,32 @@ static int tls_set(struct task_struct *target, const struct user_regset *regset,
return ret;
}
+static int system_call_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ int syscallno = task_pt_regs(target)->syscallno;
+
+ return user_regset_copyout(&pos, &count, &kbuf, &ubuf,
+ &syscallno, 0, -1);
+}
+
+static int system_call_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ int syscallno, ret;
+
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, &syscallno, 0, -1);
+ if (ret)
+ return ret;
+
+ task_pt_regs(target)->syscallno = syscallno;
+ return ret;
+}
+
enum aarch64_regset {
REGSET_GPR,
REGSET_FPR,
@@ -559,6 +586,7 @@ enum aarch64_regset {
REGSET_HW_BREAK,
REGSET_HW_WATCH,
#endif
+ REGSET_SYSTEM_CALL,
};
static const struct user_regset aarch64_regsets[] = {
@@ -608,6 +636,14 @@ static const struct user_regset aarch64_regsets[] = {
.set = hw_break_set,
},
#endif
+ [REGSET_SYSTEM_CALL] = {
+ .core_note_type = NT_ARM_SYSTEM_CALL,
+ .n = 1,
+ .size = sizeof(int),
+ .align = sizeof(int),
+ .get = system_call_get,
+ .set = system_call_set,
+ },
};
static const struct user_regset_view user_aarch64_view = {
@@ -1114,6 +1150,10 @@ static void tracehook_report_syscall(struct pt_regs *regs,
asmlinkage int syscall_trace_enter(struct pt_regs *regs)
{
+ /* Do the secure computing check first; failures should be fast. */
+ if (secure_computing() == -1)
+ return -1;
+
if (test_thread_flag(TIF_SYSCALL_TRACE))
tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
diff --git a/arch/arm64/kernel/setup.c b/arch/arm64/kernel/setup.c
index 2437196..b809911 100644
--- a/arch/arm64/kernel/setup.c
+++ b/arch/arm64/kernel/setup.c
@@ -43,12 +43,14 @@
#include <linux/of_fdt.h>
#include <linux/of_platform.h>
#include <linux/efi.h>
+#include <linux/personality.h>
#include <asm/fixmap.h>
#include <asm/cpu.h>
#include <asm/cputype.h>
#include <asm/elf.h>
#include <asm/cputable.h>
+#include <asm/cpufeature.h>
#include <asm/cpu_ops.h>
#include <asm/sections.h>
#include <asm/setup.h>
@@ -72,13 +74,15 @@ EXPORT_SYMBOL_GPL(elf_hwcap);
COMPAT_HWCAP_FAST_MULT|COMPAT_HWCAP_EDSP|\
COMPAT_HWCAP_TLS|COMPAT_HWCAP_VFP|\
COMPAT_HWCAP_VFPv3|COMPAT_HWCAP_VFPv4|\
- COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV)
+ COMPAT_HWCAP_NEON|COMPAT_HWCAP_IDIV|\
+ COMPAT_HWCAP_LPAE)
unsigned int compat_elf_hwcap __read_mostly = COMPAT_ELF_HWCAP_DEFAULT;
unsigned int compat_elf_hwcap2 __read_mostly;
#endif
+DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
+
static const char *cpu_name;
-static const char *machine_name;
phys_addr_t __fdt_pointer __initdata;
/*
@@ -116,12 +120,16 @@ void __init early_print(const char *str, ...)
void __init smp_setup_processor_id(void)
{
+ u64 mpidr = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
+ cpu_logical_map(0) = mpidr;
+
/*
* 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);
+ pr_info("Booting Linux on physical CPU 0x%lx\n", (unsigned long)mpidr);
}
bool arch_match_cpu_phys_id(int cpu, u64 phys_id)
@@ -311,7 +319,7 @@ static void __init setup_machine_fdt(phys_addr_t dt_phys)
cpu_relax();
}
- machine_name = of_flat_dt_get_machine_name();
+ dump_stack_set_arch_desc("%s (DT)", of_flat_dt_get_machine_name());
}
/*
@@ -376,6 +384,7 @@ void __init setup_arch(char **cmdline_p)
*cmdline_p = boot_command_line;
+ early_fixmap_init();
early_ioremap_init();
parse_early_param();
@@ -398,7 +407,6 @@ void __init setup_arch(char **cmdline_p)
psci_init();
- cpu_logical_map(0) = read_cpuid_mpidr() & MPIDR_HWID_BITMASK;
cpu_read_bootcpu_ops();
#ifdef CONFIG_SMP
smp_init_cpus();
@@ -447,14 +455,50 @@ static const char *hwcap_str[] = {
NULL
};
+#ifdef CONFIG_COMPAT
+static const char *compat_hwcap_str[] = {
+ "swp",
+ "half",
+ "thumb",
+ "26bit",
+ "fastmult",
+ "fpa",
+ "vfp",
+ "edsp",
+ "java",
+ "iwmmxt",
+ "crunch",
+ "thumbee",
+ "neon",
+ "vfpv3",
+ "vfpv3d16",
+ "tls",
+ "vfpv4",
+ "idiva",
+ "idivt",
+ "vfpd32",
+ "lpae",
+ "evtstrm"
+};
+
+static const char *compat_hwcap2_str[] = {
+ "aes",
+ "pmull",
+ "sha1",
+ "sha2",
+ "crc32",
+ NULL
+};
+#endif /* CONFIG_COMPAT */
+
static int c_show(struct seq_file *m, void *v)
{
- int i;
-
- seq_printf(m, "Processor\t: %s rev %d (%s)\n",
- cpu_name, read_cpuid_id() & 15, ELF_PLATFORM);
+ int i, j;
for_each_online_cpu(i) {
+ struct cpuinfo_arm64 *cpuinfo = &per_cpu(cpu_data, i);
+ u32 midr = cpuinfo->reg_midr;
+
/*
* glibc reads /proc/cpuinfo to determine the number of
* online processors, looking for lines beginning with
@@ -463,24 +507,38 @@ static int c_show(struct seq_file *m, void *v)
#ifdef CONFIG_SMP
seq_printf(m, "processor\t: %d\n", i);
#endif
- }
-
- /* dump out the processor features */
- seq_puts(m, "Features\t: ");
-
- for (i = 0; hwcap_str[i]; i++)
- if (elf_hwcap & (1 << i))
- seq_printf(m, "%s ", hwcap_str[i]);
-
- seq_printf(m, "\nCPU implementer\t: 0x%02x\n", read_cpuid_id() >> 24);
- seq_printf(m, "CPU architecture: AArch64\n");
- seq_printf(m, "CPU variant\t: 0x%x\n", (read_cpuid_id() >> 20) & 15);
- seq_printf(m, "CPU part\t: 0x%03x\n", (read_cpuid_id() >> 4) & 0xfff);
- seq_printf(m, "CPU revision\t: %d\n", read_cpuid_id() & 15);
- seq_puts(m, "\n");
-
- seq_printf(m, "Hardware\t: %s\n", machine_name);
+ /*
+ * Dump out the common processor features in a single line.
+ * Userspace should read the hwcaps with getauxval(AT_HWCAP)
+ * rather than attempting to parse this, but there's a body of
+ * software which does already (at least for 32-bit).
+ */
+ seq_puts(m, "Features\t:");
+ if (personality(current->personality) == PER_LINUX32) {
+#ifdef CONFIG_COMPAT
+ for (j = 0; compat_hwcap_str[j]; j++)
+ if (compat_elf_hwcap & (1 << j))
+ seq_printf(m, " %s", compat_hwcap_str[j]);
+
+ for (j = 0; compat_hwcap2_str[j]; j++)
+ if (compat_elf_hwcap2 & (1 << j))
+ seq_printf(m, " %s", compat_hwcap2_str[j]);
+#endif /* CONFIG_COMPAT */
+ } else {
+ for (j = 0; hwcap_str[j]; j++)
+ if (elf_hwcap & (1 << j))
+ seq_printf(m, " %s", hwcap_str[j]);
+ }
+ seq_puts(m, "\n");
+
+ seq_printf(m, "CPU implementer\t: 0x%02x\n",
+ MIDR_IMPLEMENTOR(midr));
+ seq_printf(m, "CPU architecture: 8\n");
+ seq_printf(m, "CPU variant\t: 0x%x\n", MIDR_VARIANT(midr));
+ seq_printf(m, "CPU part\t: 0x%03x\n", MIDR_PARTNUM(midr));
+ seq_printf(m, "CPU revision\t: %d\n\n", MIDR_REVISION(midr));
+ }
return 0;
}
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 1b9ad02..5a1ba6e 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -186,6 +186,12 @@ int copy_siginfo_to_user32(compat_siginfo_t __user *to, const siginfo_t *from)
err |= __put_user(from->si_uid, &to->si_uid);
err |= __put_user((compat_uptr_t)(unsigned long)from->si_ptr, &to->si_ptr);
break;
+ case __SI_SYS:
+ err |= __put_user((compat_uptr_t)(unsigned long)
+ from->si_call_addr, &to->si_call_addr);
+ err |= __put_user(from->si_syscall, &to->si_syscall);
+ err |= __put_user(from->si_arch, &to->si_arch);
+ break;
default: /* this is just in case for now ... */
err |= __put_user(from->si_pid, &to->si_pid);
err |= __put_user(from->si_uid, &to->si_uid);
diff --git a/arch/arm64/kernel/sleep.S b/arch/arm64/kernel/sleep.S
index a564b44..ede186c 100644
--- a/arch/arm64/kernel/sleep.S
+++ b/arch/arm64/kernel/sleep.S
@@ -147,14 +147,12 @@ cpu_resume_after_mmu:
ret
ENDPROC(cpu_resume_after_mmu)
- .data
ENTRY(cpu_resume)
bl el2_setup // if in EL2 drop to EL1 cleanly
#ifdef CONFIG_SMP
mrs x1, mpidr_el1
- adr x4, mpidr_hash_ptr
- ldr x5, [x4]
- add x8, x4, x5 // x8 = struct mpidr_hash phys address
+ adrp x8, mpidr_hash
+ add x8, x8, #:lo12:mpidr_hash // x8 = struct mpidr_hash phys address
/* retrieve mpidr_hash members to compute the hash */
ldr x2, [x8, #MPIDR_HASH_MASK]
ldp w3, w4, [x8, #MPIDR_HASH_SHIFTS]
@@ -164,14 +162,15 @@ ENTRY(cpu_resume)
#else
mov x7, xzr
#endif
- adr x0, sleep_save_sp
+ adrp x0, sleep_save_sp
+ add x0, x0, #:lo12:sleep_save_sp
ldr x0, [x0, #SLEEP_SAVE_SP_PHYS]
ldr x0, [x0, x7, lsl #3]
/* load sp from context */
ldr x2, [x0, #CPU_CTX_SP]
- adr x1, sleep_idmap_phys
+ adrp x1, sleep_idmap_phys
/* load physical address of identity map page table in x1 */
- ldr x1, [x1]
+ ldr x1, [x1, #:lo12:sleep_idmap_phys]
mov sp, x2
/*
* cpu_do_resume expects x0 to contain context physical address
@@ -180,26 +179,3 @@ ENTRY(cpu_resume)
bl cpu_do_resume // PC relative jump, MMU off
b cpu_resume_mmu // Resume MMU, never returns
ENDPROC(cpu_resume)
-
- .align 3
-mpidr_hash_ptr:
- /*
- * offset of mpidr_hash symbol from current location
- * used to obtain run-time mpidr_hash address with MMU off
- */
- .quad mpidr_hash - .
-/*
- * physical address of identity mapped page tables
- */
- .type sleep_idmap_phys, #object
-ENTRY(sleep_idmap_phys)
- .quad 0
-/*
- * struct sleep_save_sp {
- * phys_addr_t *save_ptr_stash;
- * phys_addr_t save_ptr_stash_phys;
- * };
- */
- .type sleep_save_sp, #object
-ENTRY(sleep_save_sp)
- .space SLEEP_SAVE_SP_SZ // struct sleep_save_sp
diff --git a/arch/arm64/kernel/smp.c b/arch/arm64/kernel/smp.c
index b06d1d9..7ae6ee0 100644
--- a/arch/arm64/kernel/smp.c
+++ b/arch/arm64/kernel/smp.c
@@ -37,6 +37,7 @@
#include <linux/of.h>
#include <linux/irq_work.h>
+#include <asm/alternative.h>
#include <asm/atomic.h>
#include <asm/cacheflush.h>
#include <asm/cpu.h>
@@ -309,6 +310,7 @@ void cpu_die(void)
void __init smp_cpus_done(unsigned int max_cpus)
{
pr_info("SMP: Total of %d processors activated.\n", num_online_cpus());
+ apply_alternatives_all();
}
void __init smp_prepare_boot_cpu(void)
diff --git a/arch/arm64/kernel/suspend.c b/arch/arm64/kernel/suspend.c
index 13ad4db..3771b72 100644
--- a/arch/arm64/kernel/suspend.c
+++ b/arch/arm64/kernel/suspend.c
@@ -126,8 +126,8 @@ int __cpu_suspend(unsigned long arg, int (*fn)(unsigned long))
return ret;
}
-extern struct sleep_save_sp sleep_save_sp;
-extern phys_addr_t sleep_idmap_phys;
+struct sleep_save_sp sleep_save_sp;
+phys_addr_t sleep_idmap_phys;
static int __init cpu_suspend_init(void)
{
diff --git a/arch/arm64/kernel/sys_compat.c b/arch/arm64/kernel/sys_compat.c
index dc47e53..28c511b 100644
--- a/arch/arm64/kernel/sys_compat.c
+++ b/arch/arm64/kernel/sys_compat.c
@@ -28,29 +28,39 @@
#include <asm/cacheflush.h>
#include <asm/unistd.h>
-static inline void
-do_compat_cache_op(unsigned long start, unsigned long end, int flags)
+static long
+__do_compat_cache_op(unsigned long start, unsigned long end)
{
- struct mm_struct *mm = current->active_mm;
- struct vm_area_struct *vma;
+ long ret;
- if (end < start || flags)
- return;
+ do {
+ unsigned long chunk = min(PAGE_SIZE, end - start);
- down_read(&mm->mmap_sem);
- vma = find_vma(mm, start);
- if (vma && vma->vm_start < end) {
- if (start < vma->vm_start)
- start = vma->vm_start;
- if (end > vma->vm_end)
- end = vma->vm_end;
- up_read(&mm->mmap_sem);
- __flush_cache_user_range(start & PAGE_MASK, PAGE_ALIGN(end));
- return;
- }
- up_read(&mm->mmap_sem);
+ if (fatal_signal_pending(current))
+ return 0;
+
+ ret = __flush_cache_user_range(start, start + chunk);
+ if (ret)
+ return ret;
+
+ cond_resched();
+ start += chunk;
+ } while (start < end);
+
+ return 0;
}
+static inline long
+do_compat_cache_op(unsigned long start, unsigned long end, int flags)
+{
+ if (end < start || flags)
+ return -EINVAL;
+
+ if (!access_ok(VERIFY_READ, start, end - start))
+ return -EFAULT;
+
+ return __do_compat_cache_op(start, end);
+}
/*
* Handle all unrecognised system calls.
*/
@@ -74,8 +84,7 @@ long compat_arm_syscall(struct pt_regs *regs)
* the specified region).
*/
case __ARM_NR_compat_cacheflush:
- do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
- return 0;
+ return do_compat_cache_op(regs->regs[0], regs->regs[1], regs->regs[2]);
case __ARM_NR_compat_set_tls:
current->thread.tp_value = regs->regs[0];
diff --git a/arch/arm64/kernel/topology.c b/arch/arm64/kernel/topology.c
index b6ee26b..fcb8f7b 100644
--- a/arch/arm64/kernel/topology.c
+++ b/arch/arm64/kernel/topology.c
@@ -255,12 +255,15 @@ void store_cpu_topology(unsigned int cpuid)
/* Multiprocessor system : Multi-threads per core */
cpuid_topo->thread_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
- cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2);
+ cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 2) |
+ MPIDR_AFFINITY_LEVEL(mpidr, 3) << 8;
} else {
/* Multiprocessor system : Single-thread per core */
cpuid_topo->thread_id = -1;
cpuid_topo->core_id = MPIDR_AFFINITY_LEVEL(mpidr, 0);
- cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1);
+ cpuid_topo->cluster_id = MPIDR_AFFINITY_LEVEL(mpidr, 1) |
+ MPIDR_AFFINITY_LEVEL(mpidr, 2) << 8 |
+ MPIDR_AFFINITY_LEVEL(mpidr, 3) << 16;
}
pr_debug("CPU%u: cluster %d core %d thread %d mpidr %#016llx\n",
diff --git a/arch/arm64/kernel/trace-events-emulation.h b/arch/arm64/kernel/trace-events-emulation.h
new file mode 100644
index 0000000..ae1dd59
--- /dev/null
+++ b/arch/arm64/kernel/trace-events-emulation.h
@@ -0,0 +1,35 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM emulation
+
+#if !defined(_TRACE_EMULATION_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _TRACE_EMULATION_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(instruction_emulation,
+
+ TP_PROTO(const char *instr, u64 addr),
+ TP_ARGS(instr, addr),
+
+ TP_STRUCT__entry(
+ __string(instr, instr)
+ __field(u64, addr)
+ ),
+
+ TP_fast_assign(
+ __assign_str(instr, instr);
+ __entry->addr = addr;
+ ),
+
+ TP_printk("instr=\"%s\" addr=0x%llx", __get_str(instr), __entry->addr)
+);
+
+#endif /* _TRACE_EMULATION_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#undef TRACE_INCLUDE_FILE
+#define TRACE_INCLUDE_PATH .
+
+#define TRACE_INCLUDE_FILE trace-events-emulation
+#include <trace/define_trace.h>
diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
index de1b085..0a801e3 100644
--- a/arch/arm64/kernel/traps.c
+++ b/arch/arm64/kernel/traps.c
@@ -259,6 +259,69 @@ void arm64_notify_die(const char *str, struct pt_regs *regs,
}
}
+static LIST_HEAD(undef_hook);
+static DEFINE_RAW_SPINLOCK(undef_lock);
+
+void register_undef_hook(struct undef_hook *hook)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&undef_lock, flags);
+ list_add(&hook->node, &undef_hook);
+ raw_spin_unlock_irqrestore(&undef_lock, flags);
+}
+
+void unregister_undef_hook(struct undef_hook *hook)
+{
+ unsigned long flags;
+
+ raw_spin_lock_irqsave(&undef_lock, flags);
+ list_del(&hook->node);
+ raw_spin_unlock_irqrestore(&undef_lock, flags);
+}
+
+static int call_undef_hook(struct pt_regs *regs)
+{
+ struct undef_hook *hook;
+ unsigned long flags;
+ u32 instr;
+ int (*fn)(struct pt_regs *regs, u32 instr) = NULL;
+ void __user *pc = (void __user *)instruction_pointer(regs);
+
+ if (!user_mode(regs))
+ return 1;
+
+ if (compat_thumb_mode(regs)) {
+ /* 16-bit Thumb instruction */
+ if (get_user(instr, (u16 __user *)pc))
+ goto exit;
+ instr = le16_to_cpu(instr);
+ if (aarch32_insn_is_wide(instr)) {
+ u32 instr2;
+
+ if (get_user(instr2, (u16 __user *)(pc + 2)))
+ goto exit;
+ instr2 = le16_to_cpu(instr2);
+ instr = (instr << 16) | instr2;
+ }
+ } else {
+ /* 32-bit ARM instruction */
+ if (get_user(instr, (u32 __user *)pc))
+ goto exit;
+ instr = le32_to_cpu(instr);
+ }
+
+ raw_spin_lock_irqsave(&undef_lock, flags);
+ list_for_each_entry(hook, &undef_hook, node)
+ if ((instr & hook->instr_mask) == hook->instr_val &&
+ (regs->pstate & hook->pstate_mask) == hook->pstate_val)
+ fn = hook->fn;
+
+ raw_spin_unlock_irqrestore(&undef_lock, flags);
+exit:
+ return fn ? fn(regs, instr) : 1;
+}
+
asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
{
siginfo_t info;
@@ -268,6 +331,9 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
if (!aarch32_break_handler(regs))
return;
+ if (call_undef_hook(regs) == 0)
+ return;
+
if (show_unhandled_signals && unhandled_signal(current, SIGILL) &&
printk_ratelimit()) {
pr_info("%s[%d]: undefined instruction: pc=%p\n",
diff --git a/arch/arm64/kernel/vmlinux.lds.S b/arch/arm64/kernel/vmlinux.lds.S
index edf8715..9965ec8 100644
--- a/arch/arm64/kernel/vmlinux.lds.S
+++ b/arch/arm64/kernel/vmlinux.lds.S
@@ -11,8 +11,9 @@
#include "image.h"
-#define ARM_EXIT_KEEP(x)
-#define ARM_EXIT_DISCARD(x) x
+/* .exit.text needed in case of alternative patching */
+#define ARM_EXIT_KEEP(x) x
+#define ARM_EXIT_DISCARD(x)
OUTPUT_ARCH(aarch64)
ENTRY(_text)
@@ -32,6 +33,22 @@ jiffies = jiffies_64;
*(.hyp.text) \
VMLINUX_SYMBOL(__hyp_text_end) = .;
+/*
+ * The size of the PE/COFF section that covers the kernel image, which
+ * runs from stext to _edata, must be a round multiple of the PE/COFF
+ * FileAlignment, which we set to its minimum value of 0x200. 'stext'
+ * itself is 4 KB aligned, so padding out _edata to a 0x200 aligned
+ * boundary should be sufficient.
+ */
+PECOFF_FILE_ALIGNMENT = 0x200;
+
+#ifdef CONFIG_EFI
+#define PECOFF_EDATA_PADDING \
+ .pecoff_edata_padding : { BYTE(0); . = ALIGN(PECOFF_FILE_ALIGNMENT); }
+#else
+#define PECOFF_EDATA_PADDING
+#endif
+
SECTIONS
{
/*
@@ -100,9 +117,21 @@ SECTIONS
. = ALIGN(PAGE_SIZE);
__init_end = .;
+ . = ALIGN(4);
+ .altinstructions : {
+ __alt_instructions = .;
+ *(.altinstructions)
+ __alt_instructions_end = .;
+ }
+ .altinstr_replacement : {
+ *(.altinstr_replacement)
+ }
+
+ . = ALIGN(PAGE_SIZE);
_data = .;
_sdata = .;
RW_DATA_SECTION(64, PAGE_SIZE, THREAD_SIZE)
+ PECOFF_EDATA_PADDING
_edata = .;
BSS_SECTION(0, 0, 0)
diff --git a/arch/arm64/kvm/hyp.S b/arch/arm64/kvm/hyp.S
index b72aa9f..fbe909f 100644
--- a/arch/arm64/kvm/hyp.S
+++ b/arch/arm64/kvm/hyp.S
@@ -761,10 +761,10 @@
.macro activate_traps
ldr x2, [x0, #VCPU_HCR_EL2]
msr hcr_el2, x2
- ldr x2, =(CPTR_EL2_TTA)
+ mov x2, #CPTR_EL2_TTA
msr cptr_el2, x2
- ldr x2, =(1 << 15) // Trap CP15 Cr=15
+ mov x2, #(1 << 15) // Trap CP15 Cr=15
msr hstr_el2, x2
mrs x2, mdcr_el2
diff --git a/arch/arm64/mm/Makefile b/arch/arm64/mm/Makefile
index c56179e..773d37a 100644
--- a/arch/arm64/mm/Makefile
+++ b/arch/arm64/mm/Makefile
@@ -3,3 +3,4 @@ obj-y := dma-mapping.o extable.o fault.o init.o \
ioremap.o mmap.o pgd.o mmu.o \
context.o proc.o pageattr.o
obj-$(CONFIG_HUGETLB_PAGE) += hugetlbpage.o
+obj-$(CONFIG_ARM64_PTDUMP) += dump.o
diff --git a/arch/arm64/mm/cache.S b/arch/arm64/mm/cache.S
index 2366383..2560e1e 100644
--- a/arch/arm64/mm/cache.S
+++ b/arch/arm64/mm/cache.S
@@ -17,9 +17,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
+#include <linux/errno.h>
#include <linux/linkage.h>
#include <linux/init.h>
#include <asm/assembler.h>
+#include <asm/cpufeature.h>
+#include <asm/alternative-asm.h>
#include "proc-macros.S"
@@ -138,9 +141,12 @@ USER(9f, ic ivau, x4 ) // invalidate I line PoU
add x4, x4, x2
cmp x4, x1
b.lo 1b
-9: // ignore any faulting cache operation
dsb ish
isb
+ mov x0, #0
+ ret
+9:
+ mov x0, #-EFAULT
ret
ENDPROC(flush_icache_range)
ENDPROC(__flush_cache_user_range)
@@ -210,7 +216,7 @@ __dma_clean_range:
dcache_line_size x2, x3
sub x3, x2, #1
bic x0, x0, x3
-1: dc cvac, x0 // clean D / U line
+1: alternative_insn "dc cvac, x0", "dc civac, x0", ARM64_WORKAROUND_CLEAN_CACHE
add x0, x0, x2
cmp x0, x1
b.lo 1b
diff --git a/arch/arm64/mm/dump.c b/arch/arm64/mm/dump.c
new file mode 100644
index 0000000..bf69601
--- /dev/null
+++ b/arch/arm64/mm/dump.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ * Debug helper to dump the current kernel pagetables of the system
+ * so that we can see what the various memory ranges are set to.
+ *
+ * Derived from x86 and arm implementation:
+ * (C) Copyright 2008 Intel Corporation
+ *
+ * Author: Arjan van de Ven <arjan@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; version 2
+ * of the License.
+ */
+#include <linux/debugfs.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/seq_file.h>
+
+#include <asm/fixmap.h>
+#include <asm/pgtable.h>
+
+#define LOWEST_ADDR (UL(0xffffffffffffffff) << VA_BITS)
+
+struct addr_marker {
+ unsigned long start_address;
+ const char *name;
+};
+
+enum address_markers_idx {
+ VMALLOC_START_NR = 0,
+ VMALLOC_END_NR,
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+ VMEMMAP_START_NR,
+ VMEMMAP_END_NR,
+#endif
+ PCI_START_NR,
+ PCI_END_NR,
+ FIXADDR_START_NR,
+ FIXADDR_END_NR,
+ MODULES_START_NR,
+ MODUELS_END_NR,
+ KERNEL_SPACE_NR,
+};
+
+static struct addr_marker address_markers[] = {
+ { VMALLOC_START, "vmalloc() Area" },
+ { VMALLOC_END, "vmalloc() End" },
+#ifdef CONFIG_SPARSEMEM_VMEMMAP
+ { 0, "vmemmap start" },
+ { 0, "vmemmap end" },
+#endif
+ { (unsigned long) PCI_IOBASE, "PCI I/O start" },
+ { (unsigned long) PCI_IOBASE + SZ_16M, "PCI I/O end" },
+ { FIXADDR_START, "Fixmap start" },
+ { FIXADDR_TOP, "Fixmap end" },
+ { MODULES_VADDR, "Modules start" },
+ { MODULES_END, "Modules end" },
+ { PAGE_OFFSET, "Kernel Mapping" },
+ { -1, NULL },
+};
+
+struct pg_state {
+ struct seq_file *seq;
+ const struct addr_marker *marker;
+ unsigned long start_address;
+ unsigned level;
+ u64 current_prot;
+};
+
+struct prot_bits {
+ u64 mask;
+ u64 val;
+ const char *set;
+ const char *clear;
+};
+
+static const struct prot_bits pte_bits[] = {
+ {
+ .mask = PTE_USER,
+ .val = PTE_USER,
+ .set = "USR",
+ .clear = " ",
+ }, {
+ .mask = PTE_RDONLY,
+ .val = PTE_RDONLY,
+ .set = "ro",
+ .clear = "RW",
+ }, {
+ .mask = PTE_PXN,
+ .val = PTE_PXN,
+ .set = "NX",
+ .clear = "x ",
+ }, {
+ .mask = PTE_SHARED,
+ .val = PTE_SHARED,
+ .set = "SHD",
+ .clear = " ",
+ }, {
+ .mask = PTE_AF,
+ .val = PTE_AF,
+ .set = "AF",
+ .clear = " ",
+ }, {
+ .mask = PTE_NG,
+ .val = PTE_NG,
+ .set = "NG",
+ .clear = " ",
+ }, {
+ .mask = PTE_UXN,
+ .val = PTE_UXN,
+ .set = "UXN",
+ }, {
+ .mask = PTE_ATTRINDX_MASK,
+ .val = PTE_ATTRINDX(MT_DEVICE_nGnRnE),
+ .set = "DEVICE/nGnRnE",
+ }, {
+ .mask = PTE_ATTRINDX_MASK,
+ .val = PTE_ATTRINDX(MT_DEVICE_nGnRE),
+ .set = "DEVICE/nGnRE",
+ }, {
+ .mask = PTE_ATTRINDX_MASK,
+ .val = PTE_ATTRINDX(MT_DEVICE_GRE),
+ .set = "DEVICE/GRE",
+ }, {
+ .mask = PTE_ATTRINDX_MASK,
+ .val = PTE_ATTRINDX(MT_NORMAL_NC),
+ .set = "MEM/NORMAL-NC",
+ }, {
+ .mask = PTE_ATTRINDX_MASK,
+ .val = PTE_ATTRINDX(MT_NORMAL),
+ .set = "MEM/NORMAL",
+ }
+};
+
+struct pg_level {
+ const struct prot_bits *bits;
+ size_t num;
+ u64 mask;
+};
+
+static struct pg_level pg_level[] = {
+ {
+ }, { /* pgd */
+ .bits = pte_bits,
+ .num = ARRAY_SIZE(pte_bits),
+ }, { /* pud */
+ .bits = pte_bits,
+ .num = ARRAY_SIZE(pte_bits),
+ }, { /* pmd */
+ .bits = pte_bits,
+ .num = ARRAY_SIZE(pte_bits),
+ }, { /* pte */
+ .bits = pte_bits,
+ .num = ARRAY_SIZE(pte_bits),
+ },
+};
+
+static void dump_prot(struct pg_state *st, const struct prot_bits *bits,
+ size_t num)
+{
+ unsigned i;
+
+ for (i = 0; i < num; i++, bits++) {
+ const char *s;
+
+ if ((st->current_prot & bits->mask) == bits->val)
+ s = bits->set;
+ else
+ s = bits->clear;
+
+ if (s)
+ seq_printf(st->seq, " %s", s);
+ }
+}
+
+static void note_page(struct pg_state *st, unsigned long addr, unsigned level,
+ u64 val)
+{
+ static const char units[] = "KMGTPE";
+ u64 prot = val & pg_level[level].mask;
+
+ if (addr < LOWEST_ADDR)
+ return;
+
+ if (!st->level) {
+ st->level = level;
+ st->current_prot = prot;
+ st->start_address = addr;
+ seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ } else if (prot != st->current_prot || level != st->level ||
+ addr >= st->marker[1].start_address) {
+ const char *unit = units;
+ unsigned long delta;
+
+ if (st->current_prot) {
+ seq_printf(st->seq, "0x%16lx-0x%16lx ",
+ st->start_address, addr);
+
+ delta = (addr - st->start_address) >> 10;
+ while (!(delta & 1023) && unit[1]) {
+ delta >>= 10;
+ unit++;
+ }
+ seq_printf(st->seq, "%9lu%c", delta, *unit);
+ if (pg_level[st->level].bits)
+ dump_prot(st, pg_level[st->level].bits,
+ pg_level[st->level].num);
+ seq_puts(st->seq, "\n");
+ }
+
+ if (addr >= st->marker[1].start_address) {
+ st->marker++;
+ seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ }
+
+ st->start_address = addr;
+ st->current_prot = prot;
+ st->level = level;
+ }
+
+ if (addr >= st->marker[1].start_address) {
+ st->marker++;
+ seq_printf(st->seq, "---[ %s ]---\n", st->marker->name);
+ }
+
+}
+
+static void walk_pte(struct pg_state *st, pmd_t *pmd, unsigned long start)
+{
+ pte_t *pte = pte_offset_kernel(pmd, 0);
+ unsigned long addr;
+ unsigned i;
+
+ for (i = 0; i < PTRS_PER_PTE; i++, pte++) {
+ addr = start + i * PAGE_SIZE;
+ note_page(st, addr, 4, pte_val(*pte));
+ }
+}
+
+static void walk_pmd(struct pg_state *st, pud_t *pud, unsigned long start)
+{
+ pmd_t *pmd = pmd_offset(pud, 0);
+ unsigned long addr;
+ unsigned i;
+
+ for (i = 0; i < PTRS_PER_PMD; i++, pmd++) {
+ addr = start + i * PMD_SIZE;
+ if (pmd_none(*pmd) || pmd_sect(*pmd) || pmd_bad(*pmd))
+ note_page(st, addr, 3, pmd_val(*pmd));
+ else
+ walk_pte(st, pmd, addr);
+ }
+}
+
+static void walk_pud(struct pg_state *st, pgd_t *pgd, unsigned long start)
+{
+ pud_t *pud = pud_offset(pgd, 0);
+ unsigned long addr;
+ unsigned i;
+
+ for (i = 0; i < PTRS_PER_PUD; i++, pud++) {
+ addr = start + i * PUD_SIZE;
+ if (pud_none(*pud) || pud_sect(*pud) || pud_bad(*pud))
+ note_page(st, addr, 2, pud_val(*pud));
+ else
+ walk_pmd(st, pud, addr);
+ }
+}
+
+static void walk_pgd(struct pg_state *st, struct mm_struct *mm, unsigned long start)
+{
+ pgd_t *pgd = pgd_offset(mm, 0);
+ unsigned i;
+ unsigned long addr;
+
+ for (i = 0; i < PTRS_PER_PGD; i++, pgd++) {
+ addr = start + i * PGDIR_SIZE;
+ if (pgd_none(*pgd) || pgd_bad(*pgd))
+ note_page(st, addr, 1, pgd_val(*pgd));
+ else
+ walk_pud(st, pgd, addr);
+ }
+}
+
+static int ptdump_show(struct seq_file *m, void *v)
+{
+ struct pg_state st = {
+ .seq = m,
+ .marker = address_markers,
+ };
+
+ walk_pgd(&st, &init_mm, LOWEST_ADDR);
+
+ note_page(&st, 0, 0, 0);
+ return 0;
+}
+
+static int ptdump_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, ptdump_show, NULL);
+}
+
+static const struct file_operations ptdump_fops = {
+ .open = ptdump_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int ptdump_init(void)
+{
+ struct dentry *pe;
+ unsigned i, j;
+
+ for (i = 0; i < ARRAY_SIZE(pg_level); i++)
+ if (pg_level[i].bits)
+ for (j = 0; j < pg_level[i].num; j++)
+ pg_level[i].mask |= pg_level[i].bits[j].mask;
+
+ address_markers[VMEMMAP_START_NR].start_address =
+ (unsigned long)virt_to_page(PAGE_OFFSET);
+ address_markers[VMEMMAP_END_NR].start_address =
+ (unsigned long)virt_to_page(high_memory);
+
+ pe = debugfs_create_file("kernel_page_tables", 0400, NULL, NULL,
+ &ptdump_fops);
+ return pe ? 0 : -ENOMEM;
+}
+device_initcall(ptdump_init);
diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
index 41cb6d3..c11cd27 100644
--- a/arch/arm64/mm/fault.c
+++ b/arch/arm64/mm/fault.c
@@ -380,7 +380,7 @@ static struct fault_info {
{ do_bad, SIGBUS, 0, "level 1 address size fault" },
{ do_bad, SIGBUS, 0, "level 2 address size fault" },
{ do_bad, SIGBUS, 0, "level 3 address size fault" },
- { do_translation_fault, SIGSEGV, SEGV_MAPERR, "input address range fault" },
+ { do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 0 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 1 translation fault" },
{ do_translation_fault, SIGSEGV, SEGV_MAPERR, "level 2 translation fault" },
{ do_page_fault, SIGSEGV, SEGV_MAPERR, "level 3 translation fault" },
diff --git a/arch/arm64/mm/init.c b/arch/arm64/mm/init.c
index 494297c..bac492c 100644
--- a/arch/arm64/mm/init.c
+++ b/arch/arm64/mm/init.c
@@ -39,6 +39,7 @@
#include <asm/setup.h>
#include <asm/sizes.h>
#include <asm/tlb.h>
+#include <asm/alternative.h>
#include "mm.h"
@@ -325,6 +326,7 @@ void __init mem_init(void)
void free_initmem(void)
{
free_initmem_default(0);
+ free_alternatives_memory();
}
#ifdef CONFIG_BLK_DEV_INITRD
diff --git a/arch/arm64/mm/ioremap.c b/arch/arm64/mm/ioremap.c
index 4a07630..cbb99c8 100644
--- a/arch/arm64/mm/ioremap.c
+++ b/arch/arm64/mm/ioremap.c
@@ -103,97 +103,10 @@ void __iomem *ioremap_cache(phys_addr_t phys_addr, size_t size)
}
EXPORT_SYMBOL(ioremap_cache);
-static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
-#if CONFIG_ARM64_PGTABLE_LEVELS > 2
-static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
-#endif
-#if CONFIG_ARM64_PGTABLE_LEVELS > 3
-static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
-#endif
-
-static inline pud_t * __init early_ioremap_pud(unsigned long addr)
-{
- pgd_t *pgd;
-
- pgd = pgd_offset_k(addr);
- BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
-
- return pud_offset(pgd, addr);
-}
-
-static inline pmd_t * __init early_ioremap_pmd(unsigned long addr)
-{
- pud_t *pud = early_ioremap_pud(addr);
-
- BUG_ON(pud_none(*pud) || pud_bad(*pud));
-
- return pmd_offset(pud, addr);
-}
-
-static inline pte_t * __init early_ioremap_pte(unsigned long addr)
-{
- pmd_t *pmd = early_ioremap_pmd(addr);
-
- BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
-
- return pte_offset_kernel(pmd, addr);
-}
-
+/*
+ * Must be called after early_fixmap_init
+ */
void __init early_ioremap_init(void)
{
- pgd_t *pgd;
- pud_t *pud;
- pmd_t *pmd;
- unsigned long addr = fix_to_virt(FIX_BTMAP_BEGIN);
-
- pgd = pgd_offset_k(addr);
- pgd_populate(&init_mm, pgd, bm_pud);
- pud = pud_offset(pgd, addr);
- pud_populate(&init_mm, pud, bm_pmd);
- pmd = pmd_offset(pud, addr);
- pmd_populate_kernel(&init_mm, pmd, bm_pte);
-
- /*
- * The boot-ioremap range spans multiple pmds, for which
- * we are not prepared:
- */
- BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
- != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
-
- if (pmd != early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END))) {
- WARN_ON(1);
- pr_warn("pmd %p != %p\n",
- pmd, early_ioremap_pmd(fix_to_virt(FIX_BTMAP_END)));
- pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
- fix_to_virt(FIX_BTMAP_BEGIN));
- pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
- fix_to_virt(FIX_BTMAP_END));
-
- pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
- pr_warn("FIX_BTMAP_BEGIN: %d\n",
- FIX_BTMAP_BEGIN);
- }
-
early_ioremap_setup();
}
-
-void __init __early_set_fixmap(enum fixed_addresses idx,
- phys_addr_t phys, pgprot_t flags)
-{
- unsigned long addr = __fix_to_virt(idx);
- pte_t *pte;
-
- if (idx >= __end_of_fixed_addresses) {
- BUG();
- return;
- }
-
- pte = early_ioremap_pte(addr);
-
- if (pgprot_val(flags))
- set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
- else {
- pte_clear(&init_mm, addr, pte);
- flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
- }
-}
diff --git a/arch/arm64/mm/mm.h b/arch/arm64/mm/mm.h
index d519f4f..50c3351 100644
--- a/arch/arm64/mm/mm.h
+++ b/arch/arm64/mm/mm.h
@@ -1,2 +1 @@
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 1d73662..54922d1 100644
--- a/arch/arm64/mm/mmap.c
+++ b/arch/arm64/mm/mmap.c
@@ -47,22 +47,14 @@ static int mmap_is_legacy(void)
return sysctl_legacy_va_layout;
}
-/*
- * Since get_random_int() returns the same value within a 1 jiffy window, we
- * will almost always get the same randomisation for the stack and mmap
- * region. This will mean the relative distance between stack and mmap will be
- * the same.
- *
- * To avoid this we can shift the randomness by 1 bit.
- */
static unsigned long mmap_rnd(void)
{
unsigned long rnd = 0;
if (current->flags & PF_RANDOMIZE)
- rnd = (long)get_random_int() & (STACK_RND_MASK >> 1);
+ rnd = (long)get_random_int() & STACK_RND_MASK;
- return rnd << (PAGE_SHIFT + 1);
+ return rnd << PAGE_SHIFT;
}
static unsigned long mmap_base(void)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index f4f8b50..6032f3e 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -28,6 +28,7 @@
#include <linux/io.h>
#include <asm/cputype.h>
+#include <asm/fixmap.h>
#include <asm/sections.h>
#include <asm/setup.h>
#include <asm/sizes.h>
@@ -463,3 +464,96 @@ void vmemmap_free(unsigned long start, unsigned long end)
{
}
#endif /* CONFIG_SPARSEMEM_VMEMMAP */
+
+static pte_t bm_pte[PTRS_PER_PTE] __page_aligned_bss;
+#if CONFIG_ARM64_PGTABLE_LEVELS > 2
+static pmd_t bm_pmd[PTRS_PER_PMD] __page_aligned_bss;
+#endif
+#if CONFIG_ARM64_PGTABLE_LEVELS > 3
+static pud_t bm_pud[PTRS_PER_PUD] __page_aligned_bss;
+#endif
+
+static inline pud_t * fixmap_pud(unsigned long addr)
+{
+ pgd_t *pgd = pgd_offset_k(addr);
+
+ BUG_ON(pgd_none(*pgd) || pgd_bad(*pgd));
+
+ return pud_offset(pgd, addr);
+}
+
+static inline pmd_t * fixmap_pmd(unsigned long addr)
+{
+ pud_t *pud = fixmap_pud(addr);
+
+ BUG_ON(pud_none(*pud) || pud_bad(*pud));
+
+ return pmd_offset(pud, addr);
+}
+
+static inline pte_t * fixmap_pte(unsigned long addr)
+{
+ pmd_t *pmd = fixmap_pmd(addr);
+
+ BUG_ON(pmd_none(*pmd) || pmd_bad(*pmd));
+
+ return pte_offset_kernel(pmd, addr);
+}
+
+void __init early_fixmap_init(void)
+{
+ pgd_t *pgd;
+ pud_t *pud;
+ pmd_t *pmd;
+ unsigned long addr = FIXADDR_START;
+
+ pgd = pgd_offset_k(addr);
+ pgd_populate(&init_mm, pgd, bm_pud);
+ pud = pud_offset(pgd, addr);
+ pud_populate(&init_mm, pud, bm_pmd);
+ pmd = pmd_offset(pud, addr);
+ pmd_populate_kernel(&init_mm, pmd, bm_pte);
+
+ /*
+ * The boot-ioremap range spans multiple pmds, for which
+ * we are not preparted:
+ */
+ BUILD_BUG_ON((__fix_to_virt(FIX_BTMAP_BEGIN) >> PMD_SHIFT)
+ != (__fix_to_virt(FIX_BTMAP_END) >> PMD_SHIFT));
+
+ if ((pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)))
+ || pmd != fixmap_pmd(fix_to_virt(FIX_BTMAP_END))) {
+ WARN_ON(1);
+ pr_warn("pmd %p != %p, %p\n",
+ pmd, fixmap_pmd(fix_to_virt(FIX_BTMAP_BEGIN)),
+ fixmap_pmd(fix_to_virt(FIX_BTMAP_END)));
+ pr_warn("fix_to_virt(FIX_BTMAP_BEGIN): %08lx\n",
+ fix_to_virt(FIX_BTMAP_BEGIN));
+ pr_warn("fix_to_virt(FIX_BTMAP_END): %08lx\n",
+ fix_to_virt(FIX_BTMAP_END));
+
+ pr_warn("FIX_BTMAP_END: %d\n", FIX_BTMAP_END);
+ pr_warn("FIX_BTMAP_BEGIN: %d\n", FIX_BTMAP_BEGIN);
+ }
+}
+
+void __set_fixmap(enum fixed_addresses idx,
+ phys_addr_t phys, pgprot_t flags)
+{
+ unsigned long addr = __fix_to_virt(idx);
+ pte_t *pte;
+
+ if (idx >= __end_of_fixed_addresses) {
+ BUG();
+ return;
+ }
+
+ pte = fixmap_pte(addr);
+
+ if (pgprot_val(flags)) {
+ set_pte(pte, pfn_pte(phys >> PAGE_SHIFT, flags));
+ } else {
+ pte_clear(&init_mm, addr, pte);
+ flush_tlb_kernel_range(addr, addr+PAGE_SIZE);
+ }
+}
diff --git a/arch/arm64/mm/pgd.c b/arch/arm64/mm/pgd.c
index 6682b36..71ca104 100644
--- a/arch/arm64/mm/pgd.c
+++ b/arch/arm64/mm/pgd.c
@@ -35,9 +35,9 @@ static struct kmem_cache *pgd_cache;
pgd_t *pgd_alloc(struct mm_struct *mm)
{
if (PGD_SIZE == PAGE_SIZE)
- return (pgd_t *)get_zeroed_page(GFP_KERNEL);
+ return (pgd_t *)__get_free_page(PGALLOC_GFP);
else
- return kmem_cache_zalloc(pgd_cache, GFP_KERNEL);
+ return kmem_cache_alloc(pgd_cache, PGALLOC_GFP);
}
void pgd_free(struct mm_struct *mm, pgd_t *pgd)
diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c
index 41f1e3e..edba042 100644
--- a/arch/arm64/net/bpf_jit_comp.c
+++ b/arch/arm64/net/bpf_jit_comp.c
@@ -60,7 +60,7 @@ struct jit_ctx {
const struct bpf_prog *prog;
int idx;
int tmp_used;
- int body_offset;
+ int epilogue_offset;
int *offset;
u32 *image;
};
@@ -130,8 +130,8 @@ static void jit_fill_hole(void *area, unsigned int size)
static inline int epilogue_offset(const struct jit_ctx *ctx)
{
- int to = ctx->offset[ctx->prog->len - 1];
- int from = ctx->idx - ctx->body_offset;
+ int to = ctx->epilogue_offset;
+ int from = ctx->idx;
return to - from;
}
@@ -463,6 +463,8 @@ emit_cond_jmp:
}
/* function return */
case BPF_JMP | BPF_EXIT:
+ /* Optimization: when last instruction is EXIT,
+ simply fallthrough to epilogue. */
if (i == ctx->prog->len - 1)
break;
jmp_offset = epilogue_offset(ctx);
@@ -685,11 +687,13 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
/* 1. Initial fake pass to compute ctx->idx. */
- /* Fake pass to fill in ctx->offset. */
+ /* Fake pass to fill in ctx->offset and ctx->tmp_used. */
if (build_body(&ctx))
goto out;
build_prologue(&ctx);
+
+ ctx.epilogue_offset = ctx.idx;
build_epilogue(&ctx);
/* Now we know the actual image size. */
@@ -706,7 +710,6 @@ void bpf_int_jit_compile(struct bpf_prog *prog)
build_prologue(&ctx);
- ctx.body_offset = ctx.idx;
if (build_body(&ctx)) {
bpf_jit_binary_free(header);
goto out;
diff --git a/arch/avr32/mach-at32ap/at32ap700x.c b/arch/avr32/mach-at32ap/at32ap700x.c
index 37b7560..cc92cdb 100644
--- a/arch/avr32/mach-at32ap/at32ap700x.c
+++ b/arch/avr32/mach-at32ap/at32ap700x.c
@@ -17,7 +17,7 @@
#include <linux/spi/spi.h>
#include <linux/usb/atmel_usba_udc.h>
-#include <mach/atmel-mci.h>
+#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/atmel-mci.h>
#include <asm/io.h>
diff --git a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h b/arch/avr32/mach-at32ap/include/mach/atmel-mci.h
deleted file mode 100644
index 11d7f4b..0000000
--- a/arch/avr32/mach-at32ap/include/mach/atmel-mci.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#ifndef __MACH_ATMEL_MCI_H
-#define __MACH_ATMEL_MCI_H
-
-#include <linux/platform_data/dma-dw.h>
-
-/**
- * struct mci_dma_data - DMA data for MCI interface
- */
-struct mci_dma_data {
- struct dw_dma_slave sdata;
-};
-
-/* accessor macros */
-#define slave_data_ptr(s) (&(s)->sdata)
-#define find_slave_dev(s) ((s)->sdata.dma_dev)
-
-#endif /* __MACH_ATMEL_MCI_H */
diff --git a/arch/cris/include/asm/io.h b/arch/cris/include/asm/io.h
index e59dba1..752a3f4 100644
--- a/arch/cris/include/asm/io.h
+++ b/arch/cris/include/asm/io.h
@@ -112,6 +112,9 @@ static inline void writel(unsigned int b, volatile void __iomem *addr)
else
*(volatile unsigned int __force *) addr = b;
}
+#define writeb_relaxed(b, addr) writeb(b, addr)
+#define writew_relaxed(b, addr) writew(b, addr)
+#define writel_relaxed(b, addr) writel(b, addr)
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
diff --git a/arch/frv/include/asm/io.h b/arch/frv/include/asm/io.h
index 8cb50a2..99bb7ef 100644
--- a/arch/frv/include/asm/io.h
+++ b/arch/frv/include/asm/io.h
@@ -243,6 +243,9 @@ static inline void writel(uint32_t datum, volatile void __iomem *addr)
__flush_PCI_writes();
}
+#define writeb_relaxed writeb
+#define writew_relaxed writew
+#define writel_relaxed writel
/* Values for nocacheflag and cmode */
#define IOMAP_FULL_CACHING 0
diff --git a/arch/ia64/Kconfig b/arch/ia64/Kconfig
index c84c88b..536d13b 100644
--- a/arch/ia64/Kconfig
+++ b/arch/ia64/Kconfig
@@ -11,7 +11,6 @@ config IA64
select PCI if (!IA64_HP_SIM)
select ACPI if (!IA64_HP_SIM)
select ARCH_MIGHT_HAVE_ACPI_PDC if ACPI
- select PM if (!IA64_HP_SIM)
select HAVE_UNSTABLE_SCHED_CLOCK
select HAVE_IDE
select HAVE_OPROFILE
@@ -233,6 +232,7 @@ config IA64_SGI_UV
config IA64_HP_SIM
bool "Ski-simulator"
select SWIOTLB
+ depends on !PM_RUNTIME
endchoice
diff --git a/arch/ia64/include/asm/io.h b/arch/ia64/include/asm/io.h
index bee0acd..80a7e34 100644
--- a/arch/ia64/include/asm/io.h
+++ b/arch/ia64/include/asm/io.h
@@ -393,6 +393,10 @@ __writeq (unsigned long val, volatile void __iomem *addr)
#define writew(v,a) __writew((v), (a))
#define writel(v,a) __writel((v), (a))
#define writeq(v,a) __writeq((v), (a))
+#define writeb_relaxed(v,a) __writeb((v), (a))
+#define writew_relaxed(v,a) __writew((v), (a))
+#define writel_relaxed(v,a) __writel((v), (a))
+#define writeq_relaxed(v,a) __writeq((v), (a))
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
diff --git a/arch/ia64/include/asm/uaccess.h b/arch/ia64/include/asm/uaccess.h
index 449c8c0..103bedc 100644
--- a/arch/ia64/include/asm/uaccess.h
+++ b/arch/ia64/include/asm/uaccess.h
@@ -365,15 +365,15 @@ ia64_done_with_exception (struct pt_regs *regs)
}
#define ARCH_HAS_TRANSLATE_MEM_PTR 1
-static __inline__ char *
-xlate_dev_mem_ptr (unsigned long p)
+static __inline__ void *
+xlate_dev_mem_ptr(phys_addr_t p)
{
struct page *page;
- char * ptr;
+ void *ptr;
page = pfn_to_page(p >> PAGE_SHIFT);
if (PageUncached(page))
- ptr = (char *)p + __IA64_UNCACHED_OFFSET;
+ ptr = (void *)p + __IA64_UNCACHED_OFFSET;
else
ptr = __va(p);
@@ -383,15 +383,15 @@ xlate_dev_mem_ptr (unsigned long p)
/*
* Convert a virtual cached kernel memory pointer to an uncached pointer
*/
-static __inline__ char *
-xlate_dev_kmem_ptr (char * p)
+static __inline__ void *
+xlate_dev_kmem_ptr(void *p)
{
struct page *page;
- char * ptr;
+ void *ptr;
page = virt_to_page((unsigned long)p);
if (PageUncached(page))
- ptr = (char *)__pa(p) + __IA64_UNCACHED_OFFSET;
+ ptr = (void *)__pa(p) + __IA64_UNCACHED_OFFSET;
else
ptr = p;
diff --git a/arch/ia64/include/uapi/asm/siginfo.h b/arch/ia64/include/uapi/asm/siginfo.h
index 4ea6225..bce9bc1 100644
--- a/arch/ia64/include/uapi/asm/siginfo.h
+++ b/arch/ia64/include/uapi/asm/siginfo.h
@@ -63,6 +63,10 @@ typedef struct siginfo {
unsigned int _flags; /* see below */
unsigned long _isr; /* isr */
short _addr_lsb; /* lsb of faulting address */
+ struct {
+ void __user *_lower;
+ void __user *_upper;
+ } _addr_bnd;
} _sigfault;
/* SIGPOLL */
@@ -110,9 +114,9 @@ typedef struct siginfo {
/*
* SIGSEGV si_codes
*/
-#define __SEGV_PSTKOVF (__SI_FAULT|3) /* paragraph stack overflow */
+#define __SEGV_PSTKOVF (__SI_FAULT|4) /* paragraph stack overflow */
#undef NSIGSEGV
-#define NSIGSEGV 3
+#define NSIGSEGV 4
#undef NSIGTRAP
#define NSIGTRAP 4
diff --git a/arch/ia64/kernel/msi_ia64.c b/arch/ia64/kernel/msi_ia64.c
index 8c3730c..8ae36ea 100644
--- a/arch/ia64/kernel/msi_ia64.c
+++ b/arch/ia64/kernel/msi_ia64.c
@@ -35,7 +35,7 @@ static int ia64_set_msi_irq_affinity(struct irq_data *idata,
data |= MSI_DATA_VECTOR(irq_to_vector(irq));
msg.data = data;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
cpumask_copy(idata->affinity, cpumask_of(cpu));
return 0;
@@ -71,7 +71,7 @@ int ia64_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
MSI_DATA_DELIVERY_FIXED |
MSI_DATA_VECTOR(vector);
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &ia64_msi_chip, handle_edge_irq);
return 0;
@@ -102,8 +102,8 @@ static int ia64_msi_retrigger_irq(struct irq_data *data)
*/
static struct irq_chip ia64_msi_chip = {
.name = "PCI-MSI",
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
.irq_ack = ia64_ack_msi_irq,
#ifdef CONFIG_SMP
.irq_set_affinity = ia64_set_msi_irq_affinity,
diff --git a/arch/ia64/kernel/perfmon.c b/arch/ia64/kernel/perfmon.c
index 5845ffe..dc063fe 100644
--- a/arch/ia64/kernel/perfmon.c
+++ b/arch/ia64/kernel/perfmon.c
@@ -2662,7 +2662,7 @@ pfm_context_create(pfm_context_t *ctx, void *arg, int count, struct pt_regs *reg
ret = -ENOMEM;
- fd = get_unused_fd();
+ fd = get_unused_fd_flags(0);
if (fd < 0)
return fd;
diff --git a/arch/ia64/sn/kernel/msi_sn.c b/arch/ia64/sn/kernel/msi_sn.c
index 446e779..a0eb27b 100644
--- a/arch/ia64/sn/kernel/msi_sn.c
+++ b/arch/ia64/sn/kernel/msi_sn.c
@@ -145,7 +145,7 @@ int sn_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *entry)
msg.data = 0x100 + irq;
irq_set_msi_desc(irq, entry);
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &sn_msi_chip, handle_edge_irq);
return 0;
@@ -205,7 +205,7 @@ static int sn_set_msi_irq_affinity(struct irq_data *data,
msg.address_hi = (u32)(bus_addr >> 32);
msg.address_lo = (u32)(bus_addr & 0x00000000ffffffff);
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
cpumask_copy(data->affinity, cpu_mask);
return 0;
@@ -228,8 +228,8 @@ static int sn_msi_retrigger_irq(struct irq_data *data)
static struct irq_chip sn_msi_chip = {
.name = "PCI-MSI",
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
.irq_ack = sn_ack_msi_irq,
#ifdef CONFIG_SMP
.irq_set_affinity = sn_set_msi_irq_affinity,
diff --git a/arch/m32r/include/asm/io.h b/arch/m32r/include/asm/io.h
index 4010f1f..6e7787f 100644
--- a/arch/m32r/include/asm/io.h
+++ b/arch/m32r/include/asm/io.h
@@ -161,6 +161,9 @@ static inline void _writel(unsigned long l, unsigned long addr)
#define __raw_writeb writeb
#define __raw_writew writew
#define __raw_writel writel
+#define writeb_relaxed writeb
+#define writew_relaxed writew
+#define writel_relaxed writel
#define ioread8 read
#define ioread16 readw
diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c
index 01a6216..192b00f 100644
--- a/arch/m68k/atari/config.c
+++ b/arch/m68k/atari/config.c
@@ -858,6 +858,24 @@ static struct platform_device *atari_netusbee_devices[] __initdata = {
};
#endif /* CONFIG_ATARI_ETHERNEC */
+#ifdef CONFIG_ATARI_SCSI
+static const struct resource atari_scsi_st_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_MFP_FSCSI,
+ .end = IRQ_MFP_FSCSI,
+ },
+};
+
+static const struct resource atari_scsi_tt_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_TT_MFP_SCSI,
+ .end = IRQ_TT_MFP_SCSI,
+ },
+};
+#endif
+
int __init atari_platform_init(void)
{
int rv = 0;
@@ -892,6 +910,15 @@ int __init atari_platform_init(void)
}
#endif
+#ifdef CONFIG_ATARI_SCSI
+ if (ATARIHW_PRESENT(ST_SCSI))
+ platform_device_register_simple("atari_scsi", -1,
+ atari_scsi_st_rsrc, ARRAY_SIZE(atari_scsi_st_rsrc));
+ else if (ATARIHW_PRESENT(TT_SCSI))
+ platform_device_register_simple("atari_scsi", -1,
+ atari_scsi_tt_rsrc, ARRAY_SIZE(atari_scsi_tt_rsrc));
+#endif
+
return rv;
}
diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c
index ddbf43c..e5a6659 100644
--- a/arch/m68k/atari/stdma.c
+++ b/arch/m68k/atari/stdma.c
@@ -59,6 +59,31 @@ static irqreturn_t stdma_int (int irq, void *dummy);
/************************* End of Prototypes **************************/
+/**
+ * stdma_try_lock - attempt to acquire ST DMA interrupt "lock"
+ * @handler: interrupt handler to use after acquisition
+ *
+ * Returns !0 if lock was acquired; otherwise 0.
+ */
+
+int stdma_try_lock(irq_handler_t handler, void *data)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+ if (stdma_locked) {
+ local_irq_restore(flags);
+ return 0;
+ }
+
+ stdma_locked = 1;
+ stdma_isr = handler;
+ stdma_isr_data = data;
+ local_irq_restore(flags);
+ return 1;
+}
+EXPORT_SYMBOL(stdma_try_lock);
+
/*
* Function: void stdma_lock( isrfunc isr, void *data )
@@ -78,19 +103,10 @@ static irqreturn_t stdma_int (int irq, void *dummy);
void stdma_lock(irq_handler_t handler, void *data)
{
- unsigned long flags;
-
- local_irq_save(flags); /* protect lock */
-
/* Since the DMA is used for file system purposes, we
have to sleep uninterruptible (there may be locked
buffers) */
- wait_event(stdma_wait, !stdma_locked);
-
- stdma_locked = 1;
- stdma_isr = handler;
- stdma_isr_data = data;
- local_irq_restore(flags);
+ wait_event(stdma_wait, stdma_try_lock(handler, data));
}
EXPORT_SYMBOL(stdma_lock);
@@ -122,22 +138,25 @@ void stdma_release(void)
EXPORT_SYMBOL(stdma_release);
-/*
- * Function: int stdma_others_waiting( void )
- *
- * Purpose: Check if someone waits for the ST-DMA lock.
- *
- * Inputs: none
- *
- * Returns: 0 if no one is waiting, != 0 otherwise
+/**
+ * stdma_is_locked_by - allow lock holder to check whether it needs to release.
+ * @handler: interrupt handler previously used to acquire lock.
*
+ * Returns !0 if locked for the given handler; 0 otherwise.
*/
-int stdma_others_waiting(void)
+int stdma_is_locked_by(irq_handler_t handler)
{
- return waitqueue_active(&stdma_wait);
+ unsigned long flags;
+ int result;
+
+ local_irq_save(flags);
+ result = stdma_locked && (stdma_isr == handler);
+ local_irq_restore(flags);
+
+ return result;
}
-EXPORT_SYMBOL(stdma_others_waiting);
+EXPORT_SYMBOL(stdma_is_locked_by);
/*
diff --git a/arch/m68k/include/asm/atari_stdma.h b/arch/m68k/include/asm/atari_stdma.h
index 8e389b7..d24e34d 100644
--- a/arch/m68k/include/asm/atari_stdma.h
+++ b/arch/m68k/include/asm/atari_stdma.h
@@ -8,11 +8,11 @@
/***************************** Prototypes *****************************/
+int stdma_try_lock(irq_handler_t, void *);
void stdma_lock(irq_handler_t handler, void *data);
void stdma_release( void );
-int stdma_others_waiting( void );
int stdma_islocked( void );
-void *stdma_locked_by( void );
+int stdma_is_locked_by(irq_handler_t);
void stdma_init( void );
/************************* End of Prototypes **************************/
diff --git a/arch/m68k/include/asm/io.h b/arch/m68k/include/asm/io.h
index c70cc91..bccd5a9 100644
--- a/arch/m68k/include/asm/io.h
+++ b/arch/m68k/include/asm/io.h
@@ -3,3 +3,11 @@
#else
#include <asm/io_mm.h>
#endif
+
+#define readb_relaxed(addr) readb(addr)
+#define readw_relaxed(addr) readw(addr)
+#define readl_relaxed(addr) readl(addr)
+
+#define writeb_relaxed(b, addr) writeb(b, addr)
+#define writew_relaxed(b, addr) writew(b, addr)
+#define writel_relaxed(b, addr) writel(b, addr)
diff --git a/arch/m68k/include/asm/io_no.h b/arch/m68k/include/asm/io_no.h
index be4b5a8..a93c8cd 100644
--- a/arch/m68k/include/asm/io_no.h
+++ b/arch/m68k/include/asm/io_no.h
@@ -40,10 +40,6 @@ static inline unsigned int _swapl(volatile unsigned long v)
#define readl(addr) \
({ unsigned int __v = (*(volatile unsigned int *) (addr)); __v; })
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-
#define writeb(b,addr) (void)((*(volatile unsigned char *) (addr)) = (b))
#define writew(b,addr) (void)((*(volatile unsigned short *) (addr)) = (b))
#define writel(b,addr) (void)((*(volatile unsigned int *) (addr)) = (b))
diff --git a/arch/m68k/include/asm/macintosh.h b/arch/m68k/include/asm/macintosh.h
index d323b2c..29c7c6c 100644
--- a/arch/m68k/include/asm/macintosh.h
+++ b/arch/m68k/include/asm/macintosh.h
@@ -53,6 +53,10 @@ struct mac_model
#define MAC_SCSI_QUADRA 2
#define MAC_SCSI_QUADRA2 3
#define MAC_SCSI_QUADRA3 4
+#define MAC_SCSI_IIFX 5
+#define MAC_SCSI_DUO 6
+#define MAC_SCSI_CCL 7
+#define MAC_SCSI_LATE 8
#define MAC_IDE_NONE 0
#define MAC_IDE_QUADRA 1
diff --git a/arch/m68k/mac/config.c b/arch/m68k/mac/config.c
index a471eab..e9c3756 100644
--- a/arch/m68k/mac/config.c
+++ b/arch/m68k/mac/config.c
@@ -278,7 +278,7 @@ static struct mac_model mac_data_table[] = {
.name = "IIfx",
.adb_type = MAC_ADB_IOP,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_IIFX,
.scc_type = MAC_SCC_IOP,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_IOP,
@@ -329,7 +329,7 @@ static struct mac_model mac_data_table[] = {
.name = "Color Classic",
.adb_type = MAC_ADB_CUDA,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_CCL,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -338,7 +338,7 @@ static struct mac_model mac_data_table[] = {
.name = "Color Classic II",
.adb_type = MAC_ADB_CUDA,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_CCL,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -526,7 +526,7 @@ static struct mac_model mac_data_table[] = {
.name = "Performa 520",
.adb_type = MAC_ADB_CUDA,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_CCL,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -535,7 +535,7 @@ static struct mac_model mac_data_table[] = {
.name = "Performa 550",
.adb_type = MAC_ADB_CUDA,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_CCL,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -567,7 +567,7 @@ static struct mac_model mac_data_table[] = {
.name = "TV",
.adb_type = MAC_ADB_CUDA,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_CCL,
.scc_type = MAC_SCC_II,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -712,7 +712,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook 190",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_QUADRA,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_LATE,
.ide_type = MAC_IDE_BABOON,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
@@ -722,7 +722,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook 520",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_QUADRA,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_LATE,
.scc_type = MAC_SCC_QUADRA,
.ether_type = MAC_ETHER_SONIC,
.nubus_type = MAC_NUBUS,
@@ -740,7 +740,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook Duo 210",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_DUO,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -749,7 +749,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook Duo 230",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_DUO,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -758,7 +758,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook Duo 250",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_DUO,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -767,7 +767,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook Duo 270c",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_DUO,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -776,7 +776,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook Duo 280",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_DUO,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -785,7 +785,7 @@ static struct mac_model mac_data_table[] = {
.name = "PowerBook Duo 280c",
.adb_type = MAC_ADB_PB2,
.via_type = MAC_VIA_IICI,
- .scsi_type = MAC_SCSI_OLD,
+ .scsi_type = MAC_SCSI_DUO,
.scc_type = MAC_SCC_QUADRA,
.nubus_type = MAC_NUBUS,
.floppy_type = MAC_FLOPPY_SWIM_ADDR2,
@@ -929,6 +929,70 @@ static struct platform_device swim_pdev = {
.resource = &swim_rsrc,
};
+static const struct resource mac_scsi_iifx_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_MAC_SCSI,
+ .end = IRQ_MAC_SCSI,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x50008000,
+ .end = 0x50009FFF,
+ },
+};
+
+static const struct resource mac_scsi_duo_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_MEM,
+ .start = 0xFEE02000,
+ .end = 0xFEE03FFF,
+ },
+};
+
+static const struct resource mac_scsi_old_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_MAC_SCSI,
+ .end = IRQ_MAC_SCSI,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x50010000,
+ .end = 0x50011FFF,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x50006000,
+ .end = 0x50007FFF,
+ },
+};
+
+static const struct resource mac_scsi_late_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_MAC_SCSI,
+ .end = IRQ_MAC_SCSI,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x50010000,
+ .end = 0x50011FFF,
+ },
+};
+
+static const struct resource mac_scsi_ccl_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = IRQ_MAC_SCSI,
+ .end = IRQ_MAC_SCSI,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x50F10000,
+ .end = 0x50F11FFF,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x50F06000,
+ .end = 0x50F07FFF,
+ },
+};
+
static struct platform_device esp_0_pdev = {
.name = "mac_esp",
.id = 0,
@@ -1000,6 +1064,60 @@ int __init mac_platform_init(void)
(macintosh_config->ident == MAC_MODEL_Q950))
platform_device_register(&esp_1_pdev);
break;
+ case MAC_SCSI_IIFX:
+ /* Addresses from The Guide to Mac Family Hardware.
+ * $5000 8000 - $5000 9FFF: SCSI DMA
+ * $5000 C000 - $5000 DFFF: Alternate SCSI (DMA)
+ * $5000 E000 - $5000 FFFF: Alternate SCSI (Hsk)
+ * The SCSI DMA custom IC embeds the 53C80 core. mac_scsi does
+ * not make use of its DMA or hardware handshaking logic.
+ */
+ platform_device_register_simple("mac_scsi", 0,
+ mac_scsi_iifx_rsrc, ARRAY_SIZE(mac_scsi_iifx_rsrc));
+ break;
+ case MAC_SCSI_DUO:
+ /* Addresses from the Duo Dock II Developer Note.
+ * $FEE0 2000 - $FEE0 3FFF: normal mode
+ * $FEE0 4000 - $FEE0 5FFF: pseudo DMA without /DRQ
+ * $FEE0 6000 - $FEE0 7FFF: pseudo DMA with /DRQ
+ * The NetBSD code indicates that both 5380 chips share
+ * an IRQ (?) which would need careful handling (see mac_esp).
+ */
+ platform_device_register_simple("mac_scsi", 1,
+ mac_scsi_duo_rsrc, ARRAY_SIZE(mac_scsi_duo_rsrc));
+ /* fall through */
+ case MAC_SCSI_OLD:
+ /* Addresses from Developer Notes for Duo System,
+ * PowerBook 180 & 160, 140 & 170, Macintosh IIsi
+ * and also from The Guide to Mac Family Hardware for
+ * SE/30, II, IIx, IIcx, IIci.
+ * $5000 6000 - $5000 7FFF: pseudo-DMA with /DRQ
+ * $5001 0000 - $5001 1FFF: normal mode
+ * $5001 2000 - $5001 3FFF: pseudo-DMA without /DRQ
+ * GMFH says that $5000 0000 - $50FF FFFF "wraps
+ * $5000 0000 - $5001 FFFF eight times" (!)
+ * mess.org says IIci and Color Classic do not alias
+ * I/O address space.
+ */
+ platform_device_register_simple("mac_scsi", 0,
+ mac_scsi_old_rsrc, ARRAY_SIZE(mac_scsi_old_rsrc));
+ break;
+ case MAC_SCSI_LATE:
+ /* PDMA logic in 68040 PowerBooks is somehow different to
+ * '030 models. It's probably more like Quadras (see mac_esp).
+ */
+ platform_device_register_simple("mac_scsi", 0,
+ mac_scsi_late_rsrc, ARRAY_SIZE(mac_scsi_late_rsrc));
+ break;
+ case MAC_SCSI_CCL:
+ /* Addresses from the Color Classic Developer Note.
+ * $50F0 6000 - $50F0 7FFF: SCSI handshake
+ * $50F1 0000 - $50F1 1FFF: SCSI
+ * $50F1 2000 - $50F1 3FFF: SCSI DMA
+ */
+ platform_device_register_simple("mac_scsi", 0,
+ mac_scsi_ccl_rsrc, ARRAY_SIZE(mac_scsi_ccl_rsrc));
+ break;
}
/*
diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c
index acaff6a..b09a3cb 100644
--- a/arch/m68k/mm/init.c
+++ b/arch/m68k/mm/init.c
@@ -94,7 +94,6 @@ void __init paging_init(void)
high_memory = (void *) end_mem;
empty_zero_page = alloc_bootmem_pages(PAGE_SIZE);
- memset(empty_zero_page, 0, PAGE_SIZE);
/*
* Set up SFC/DFC registers (user data space).
diff --git a/arch/m68k/sun3/config.c b/arch/m68k/sun3/config.c
index f59ec58..a8b942b 100644
--- a/arch/m68k/sun3/config.c
+++ b/arch/m68k/sun3/config.c
@@ -16,6 +16,7 @@
#include <linux/console.h>
#include <linux/init.h>
#include <linux/bootmem.h>
+#include <linux/platform_device.h>
#include <asm/oplib.h>
#include <asm/setup.h>
@@ -27,6 +28,7 @@
#include <asm/sun3mmu.h>
#include <asm/rtc.h>
#include <asm/machdep.h>
+#include <asm/machines.h>
#include <asm/idprom.h>
#include <asm/intersil.h>
#include <asm/irq.h>
@@ -169,3 +171,61 @@ static void __init sun3_sched_init(irq_handler_t timer_routine)
intersil_clear();
}
+#ifdef CONFIG_SUN3_SCSI
+
+static const struct resource sun3_scsi_vme_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = SUN3_VEC_VMESCSI0,
+ .end = SUN3_VEC_VMESCSI0,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0xff200000,
+ .end = 0xff200021,
+ }, {
+ .flags = IORESOURCE_IRQ,
+ .start = SUN3_VEC_VMESCSI1,
+ .end = SUN3_VEC_VMESCSI1,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0xff204000,
+ .end = 0xff204021,
+ },
+};
+
+/*
+ * Int: level 2 autovector
+ * IO: type 1, base 0x00140000, 5 bits phys space: A<4..0>
+ */
+static const struct resource sun3_scsi_rsrc[] __initconst = {
+ {
+ .flags = IORESOURCE_IRQ,
+ .start = 2,
+ .end = 2,
+ }, {
+ .flags = IORESOURCE_MEM,
+ .start = 0x00140000,
+ .end = 0x0014001f,
+ },
+};
+
+int __init sun3_platform_init(void)
+{
+ switch (idprom->id_machtype) {
+ case SM_SUN3 | SM_3_160:
+ case SM_SUN3 | SM_3_260:
+ platform_device_register_simple("sun3_scsi_vme", -1,
+ sun3_scsi_vme_rsrc, ARRAY_SIZE(sun3_scsi_vme_rsrc));
+ break;
+ case SM_SUN3 | SM_3_50:
+ case SM_SUN3 | SM_3_60:
+ platform_device_register_simple("sun3_scsi", -1,
+ sun3_scsi_rsrc, ARRAY_SIZE(sun3_scsi_rsrc));
+ break;
+ }
+ return 0;
+}
+
+arch_initcall(sun3_platform_init);
+
+#endif
diff --git a/arch/microblaze/include/asm/io.h b/arch/microblaze/include/asm/io.h
index 433751b..940f5fc 100644
--- a/arch/microblaze/include/asm/io.h
+++ b/arch/microblaze/include/asm/io.h
@@ -69,12 +69,4 @@ extern void __iomem *ioremap(phys_addr_t address, unsigned long size);
#include <asm-generic/io.h>
-#define readb_relaxed readb
-#define readw_relaxed readw
-#define readl_relaxed readl
-
-#define writeb_relaxed writeb
-#define writew_relaxed writew
-#define writel_relaxed writel
-
#endif /* _ASM_MICROBLAZE_IO_H */
diff --git a/arch/microblaze/include/asm/tlb.h b/arch/microblaze/include/asm/tlb.h
index 8aa9781..99b6ded 100644
--- a/arch/microblaze/include/asm/tlb.h
+++ b/arch/microblaze/include/asm/tlb.h
@@ -14,7 +14,6 @@
#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
#include <linux/pagemap.h>
-#include <asm-generic/tlb.h>
#ifdef CONFIG_MMU
#define tlb_start_vma(tlb, vma) do { } while (0)
@@ -22,4 +21,6 @@
#define __tlb_remove_tlb_entry(tlb, pte, address) do { } while (0)
#endif
+#include <asm-generic/tlb.h>
+
#endif /* _ASM_MICROBLAZE_TLB_H */
diff --git a/arch/mips/include/asm/idle.h b/arch/mips/include/asm/idle.h
index 1c967ab..a2d18ab 100644
--- a/arch/mips/include/asm/idle.h
+++ b/arch/mips/include/asm/idle.h
@@ -22,7 +22,6 @@ extern int mips_cpuidle_wait_enter(struct cpuidle_device *dev,
.exit_latency = 1,\
.target_residency = 1,\
.power_usage = UINT_MAX,\
- .flags = CPUIDLE_FLAG_TIME_VALID,\
.name = "wait",\
.desc = "MIPS wait",\
}
diff --git a/arch/mips/include/uapi/asm/siginfo.h b/arch/mips/include/uapi/asm/siginfo.h
index e811744..d08f83f 100644
--- a/arch/mips/include/uapi/asm/siginfo.h
+++ b/arch/mips/include/uapi/asm/siginfo.h
@@ -92,6 +92,10 @@ typedef struct siginfo {
int _trapno; /* TRAP # which caused the signal */
#endif
short _addr_lsb;
+ struct {
+ void __user *_lower;
+ void __user *_upper;
+ } _addr_bnd;
} _sigfault;
/* SIGPOLL, SIGXFSZ (To do ...) */
diff --git a/arch/mips/pci/msi-octeon.c b/arch/mips/pci/msi-octeon.c
index 63bbe07..cffaaf4 100644
--- a/arch/mips/pci/msi-octeon.c
+++ b/arch/mips/pci/msi-octeon.c
@@ -178,7 +178,7 @@ msi_irq_allocated:
pci_write_config_word(dev, dev->msi_cap + PCI_MSI_FLAGS, control);
irq_set_msi_desc(irq, desc);
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
return 0;
}
diff --git a/arch/mips/pci/msi-xlp.c b/arch/mips/pci/msi-xlp.c
index f7ac3ed..6a40f24 100644
--- a/arch/mips/pci/msi-xlp.c
+++ b/arch/mips/pci/msi-xlp.c
@@ -217,7 +217,7 @@ static void xlp_msix_mask_ack(struct irq_data *d)
msixvec = nlm_irq_msixvec(d->irq);
link = nlm_irq_msixlink(msixvec);
- mask_msi_irq(d);
+ pci_msi_mask_irq(d);
md = irq_data_get_irq_handler_data(d);
/* Ack MSI on bridge */
@@ -239,10 +239,10 @@ static void xlp_msix_mask_ack(struct irq_data *d)
static struct irq_chip xlp_msix_chip = {
.name = "XLP-MSIX",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
.irq_mask_ack = xlp_msix_mask_ack,
- .irq_unmask = unmask_msi_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
void arch_teardown_msi_irq(unsigned int irq)
@@ -345,7 +345,7 @@ static int xlp_setup_msi(uint64_t lnkbase, int node, int link,
if (ret < 0)
return ret;
- write_msi_msg(xirq, &msg);
+ pci_write_msi_msg(xirq, &msg);
return 0;
}
@@ -446,7 +446,7 @@ static int xlp_setup_msix(uint64_t lnkbase, int node, int link,
if (ret < 0)
return ret;
- write_msi_msg(xirq, &msg);
+ pci_write_msi_msg(xirq, &msg);
return 0;
}
diff --git a/arch/mips/pci/pci-xlr.c b/arch/mips/pci/pci-xlr.c
index 0dde803..26d2dab 100644
--- a/arch/mips/pci/pci-xlr.c
+++ b/arch/mips/pci/pci-xlr.c
@@ -260,7 +260,7 @@ int arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
if (ret < 0)
return ret;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
return 0;
}
#endif
diff --git a/arch/mn10300/include/asm/io.h b/arch/mn10300/include/asm/io.h
index e6ed0d8..897ba3c 100644
--- a/arch/mn10300/include/asm/io.h
+++ b/arch/mn10300/include/asm/io.h
@@ -67,6 +67,10 @@ static inline void writel(u32 b, volatile void __iomem *addr)
#define __raw_writew writew
#define __raw_writel writel
+#define writeb_relaxed writeb
+#define writew_relaxed writew
+#define writel_relaxed writel
+
/*****************************************************************************/
/*
* traditional input/output functions
diff --git a/arch/nios2/Kconfig b/arch/nios2/Kconfig
new file mode 100644
index 0000000..2361acf
--- /dev/null
+++ b/arch/nios2/Kconfig
@@ -0,0 +1,206 @@
+config NIOS2
+ def_bool y
+ select ARCH_WANT_OPTIONAL_GPIOLIB
+ select CLKSRC_OF
+ select GENERIC_ATOMIC64
+ select GENERIC_CLOCKEVENTS
+ select GENERIC_CPU_DEVICES
+ select GENERIC_IRQ_PROBE
+ select GENERIC_IRQ_SHOW
+ select HAVE_ARCH_TRACEHOOK
+ select IRQ_DOMAIN
+ select MODULES_USE_ELF_RELA
+ select OF
+ select OF_EARLY_FLATTREE
+ select SOC_BUS
+ select SPARSE_IRQ
+ select USB_ARCH_HAS_HCD if USB_SUPPORT
+
+config GENERIC_CSUM
+ def_bool y
+
+config GENERIC_HWEIGHT
+ def_bool y
+
+config GENERIC_CALIBRATE_DELAY
+ def_bool y
+
+config NO_IOPORT_MAP
+ def_bool y
+
+config HAS_DMA
+ def_bool y
+
+config FPU
+ def_bool n
+
+config SWAP
+ def_bool n
+
+config RWSEM_GENERIC_SPINLOCK
+ def_bool y
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool n
+
+source "init/Kconfig"
+
+menu "Kernel features"
+
+source "kernel/Kconfig.preempt"
+
+source "kernel/Kconfig.freezer"
+
+source "kernel/Kconfig.hz"
+
+source "mm/Kconfig"
+
+config FORCE_MAX_ZONEORDER
+ int "Maximum zone order"
+ range 9 20
+ default "11"
+ help
+ The kernel memory allocator divides physically contiguous memory
+ blocks into "zones", where each zone is a power of two number of
+ pages. This option selects the largest power of two that the kernel
+ keeps in the memory allocator. If you need to allocate very large
+ blocks of physically contiguous memory, then you may need to
+ increase this value.
+
+ This config option is actually maximum order plus one. For example,
+ a value of 11 means that the largest free memory block is 2^10 pages.
+
+endmenu
+
+source "arch/nios2/platform/Kconfig.platform"
+
+menu "Processor type and features"
+
+config MMU
+ def_bool y
+
+config NR_CPUS
+ int
+ default "1"
+
+config NIOS2_ALIGNMENT_TRAP
+ bool "Catch alignment trap"
+ default y
+ help
+ Nios II CPUs cannot fetch/store data which is not bus aligned,
+ i.e., a 2 or 4 byte fetch must start at an address divisible by
+ 2 or 4. Any non-aligned load/store instructions will be trapped and
+ emulated in software if you say Y here, which has a performance
+ impact.
+
+comment "Boot options"
+
+config CMDLINE_BOOL
+ bool "Default bootloader kernel arguments"
+ default y
+
+config CMDLINE
+ string "Default kernel command string"
+ default ""
+ depends on CMDLINE_BOOL
+ help
+ On some platforms, there is currently no way for the boot loader to
+ pass arguments to the kernel. For these platforms, you can supply
+ some command-line options at build time by entering them here. In
+ other cases you can specify kernel args so that you don't have
+ to set them up in board prom initialization routines.
+
+config CMDLINE_FORCE
+ bool "Force default kernel command string"
+ depends on CMDLINE_BOOL
+ help
+ Set this to have arguments from the default kernel command string
+ override those passed by the boot loader.
+
+config NIOS2_CMDLINE_IGNORE_DTB
+ bool "Ignore kernel command string from DTB"
+ depends on CMDLINE_BOOL
+ depends on !CMDLINE_FORCE
+ default y
+ help
+ Set this to ignore the bootargs property from the devicetree's
+ chosen node and fall back to CMDLINE if nothing is passed.
+
+config NIOS2_PASS_CMDLINE
+ bool "Passed kernel command line from u-boot"
+ default n
+ help
+ Use bootargs env variable from u-boot for kernel command line.
+ will override "Default kernel command string".
+ Say N if you are unsure.
+
+endmenu
+
+menu "Advanced setup"
+
+config ADVANCED_OPTIONS
+ bool "Prompt for advanced kernel configuration options"
+ help
+
+comment "Default settings for advanced configuration options are used"
+ depends on !ADVANCED_OPTIONS
+
+config NIOS2_KERNEL_MMU_REGION_BASE_BOOL
+ bool "Set custom kernel MMU region base address"
+ depends on ADVANCED_OPTIONS
+ help
+ This option allows you to set the virtual address of the kernel MMU region.
+
+ Say N here unless you know what you are doing.
+
+config NIOS2_KERNEL_MMU_REGION_BASE
+ hex "Virtual base address of the kernel MMU region " if NIOS2_KERNEL_MMU_REGION_BASE_BOOL
+ default "0x80000000"
+ help
+ This option allows you to set the virtual base address of the kernel MMU region.
+
+config NIOS2_KERNEL_REGION_BASE_BOOL
+ bool "Set custom kernel region base address"
+ depends on ADVANCED_OPTIONS
+ help
+ This option allows you to set the virtual address of the kernel region.
+
+ Say N here unless you know what you are doing.
+
+config NIOS2_KERNEL_REGION_BASE
+ hex "Virtual base address of the kernel region " if NIOS2_KERNEL_REGION_BASE_BOOL
+ default "0xc0000000"
+
+config NIOS2_IO_REGION_BASE_BOOL
+ bool "Set custom I/O region base address"
+ depends on ADVANCED_OPTIONS
+ help
+ This option allows you to set the virtual address of the I/O region.
+
+ Say N here unless you know what you are doing.
+
+config NIOS2_IO_REGION_BASE
+ hex "Virtual base address of the I/O region" if NIOS2_IO_REGION_BASE_BOOL
+ default "0xe0000000"
+
+endmenu
+
+menu "Executable file formats"
+
+source "fs/Kconfig.binfmt"
+
+endmenu
+
+source "net/Kconfig"
+
+source "drivers/Kconfig"
+
+source "fs/Kconfig"
+
+source "arch/nios2/Kconfig.debug"
+
+source "security/Kconfig"
+
+source "crypto/Kconfig"
+
+source "lib/Kconfig"
diff --git a/arch/nios2/Kconfig.debug b/arch/nios2/Kconfig.debug
new file mode 100644
index 0000000..8d4e6ba
--- /dev/null
+++ b/arch/nios2/Kconfig.debug
@@ -0,0 +1,17 @@
+menu "Kernel hacking"
+
+config TRACE_IRQFLAGS_SUPPORT
+ def_bool y
+
+source "lib/Kconfig.debug"
+
+config DEBUG_STACK_USAGE
+ bool "Enable stack utilization instrumentation"
+ depends on DEBUG_KERNEL
+ help
+ Enables the display of the minimum amount of free stack which each
+ task has ever had available in the sysrq-T and sysrq-P debug output.
+
+ This option will slow down process creation somewhat.
+
+endmenu
diff --git a/arch/nios2/Makefile b/arch/nios2/Makefile
new file mode 100644
index 0000000..e142c9ee
--- /dev/null
+++ b/arch/nios2/Makefile
@@ -0,0 +1,73 @@
+#
+# 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 Altera Corporation
+# Copyright (C) 1994, 95, 96, 2003 by Wind River Systems
+# Written by Fredrik Markstrom
+#
+# This file is included by the global makefile so that you can add your own
+# architecture-specific flags and dependencies. Remember to do have actions
+# for "archclean" cleaning up for this architecture.
+#
+# Nios2 port by Wind River Systems Inc trough:
+# fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+
+UTS_SYSNAME = Linux
+
+export MMU
+
+LIBGCC := $(shell $(CC) $(KBUILD_CFLAGS) -print-libgcc-file-name)
+
+KBUILD_CFLAGS += -pipe -D__linux__ -D__ELF__
+KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_HW_MUL_SUPPORT),-mhw-mul,-mno-hw-mul)
+KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_HW_MULX_SUPPORT),-mhw-mulx,-mno-hw-mulx)
+KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_HW_DIV_SUPPORT),-mhw-div,-mno-hw-div)
+KBUILD_CFLAGS += $(if $(CONFIG_NIOS2_FPU_SUPPORT),-mcustom-fpu-cfg=60-1,)
+
+KBUILD_CFLAGS += -fno-optimize-sibling-calls
+KBUILD_CFLAGS += -DUTS_SYSNAME=\"$(UTS_SYSNAME)\"
+KBUILD_CFLAGS += -fno-builtin
+KBUILD_CFLAGS += -G 0
+
+head-y := arch/nios2/kernel/head.o
+libs-y += arch/nios2/lib/ $(LIBGCC)
+core-y += arch/nios2/kernel/ arch/nios2/mm/
+core-y += arch/nios2/platform/
+
+INSTALL_PATH ?= /tftpboot
+nios2-boot := arch/$(ARCH)/boot
+BOOT_TARGETS = vmImage zImage
+PHONY += $(BOOT_TARGETS) install
+KBUILD_IMAGE := $(nios2-boot)/vmImage
+
+ifneq ($(CONFIG_NIOS2_DTB_SOURCE),"")
+ core-y += $(nios2-boot)/
+endif
+
+all: vmImage
+
+archclean:
+ $(Q)$(MAKE) $(clean)=$(nios2-boot)
+
+%.dtb:
+ $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@
+
+dtbs:
+ $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@
+
+$(BOOT_TARGETS): vmlinux
+ $(Q)$(MAKE) $(build)=$(nios2-boot) $(nios2-boot)/$@
+
+install:
+ $(Q)$(MAKE) $(build)=$(nios2-boot) BOOTIMAGE=$(KBUILD_IMAGE) install
+
+define archhelp
+ echo '* vmImage - Kernel-only image for U-Boot ($(KBUILD_IMAGE))'
+ echo ' install - Install kernel using'
+ echo ' (your) ~/bin/$(INSTALLKERNEL) or'
+ echo ' (distribution) /sbin/$(INSTALLKERNEL) or'
+ echo ' install to $$(INSTALL_PATH)'
+ echo ' dtbs - Build device tree blobs for enabled boards'
+endef
diff --git a/arch/nios2/boot/Makefile b/arch/nios2/boot/Makefile
new file mode 100644
index 0000000..59392dc
--- /dev/null
+++ b/arch/nios2/boot/Makefile
@@ -0,0 +1,52 @@
+#
+# arch/nios2/boot/Makefile
+#
+# This file is subject to the terms and conditions of the GNU General Public
+# License. See the file "COPYING" in the main directory of this archive
+# for more details.
+#
+
+UIMAGE_LOADADDR = $(shell $(NM) vmlinux | awk '$$NF == "_stext" {print $$1}')
+UIMAGE_ENTRYADDR = $(shell $(NM) vmlinux | awk '$$NF == "_start" {print $$1}')
+UIMAGE_COMPRESSION = gzip
+
+OBJCOPYFLAGS_vmlinux.bin := -O binary
+
+targets += vmlinux.bin vmlinux.gz vmImage
+
+$(obj)/vmlinux.bin: vmlinux FORCE
+ $(call if_changed,objcopy)
+
+$(obj)/vmlinux.gz: $(obj)/vmlinux.bin FORCE
+ $(call if_changed,gzip)
+
+$(obj)/vmImage: $(obj)/vmlinux.gz
+ $(call if_changed,uimage)
+ @$(kecho) 'Kernel: $@ is ready'
+
+# Rule to build device tree blobs
+DTB_SRC := $(patsubst "%",%,$(CONFIG_NIOS2_DTB_SOURCE))
+
+# Make sure the generated dtb gets removed during clean
+extra-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += system.dtb
+
+$(obj)/system.dtb: $(DTB_SRC) FORCE
+ $(call cmd,dtc)
+
+# Ensure system.dtb exists
+$(obj)/linked_dtb.o: $(obj)/system.dtb
+
+obj-$(CONFIG_NIOS2_DTB_SOURCE_BOOL) += linked_dtb.o
+
+targets += $(dtb-y)
+
+# Rule to build device tree blobs with make command
+$(obj)/%.dtb: $(src)/dts/%.dts FORCE
+ $(call if_changed_dep,dtc)
+
+$(obj)/dtbs: $(addprefix $(obj)/, $(dtb-y))
+
+clean-files := *.dtb
+
+install:
+ sh $(srctree)/$(src)/install.sh $(KERNELRELEASE) $(BOOTIMAGE) System.map "$(INSTALL_PATH)"
diff --git a/arch/nios2/boot/dts/3c120_devboard.dts b/arch/nios2/boot/dts/3c120_devboard.dts
new file mode 100644
index 0000000..31c51f9
--- /dev/null
+++ b/arch/nios2/boot/dts/3c120_devboard.dts
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * This file is generated by sopc2dts.
+ */
+
+/dts-v1/;
+
+/ {
+ model = "altr,qsys_ghrd_3c120";
+ compatible = "altr,qsys_ghrd_3c120";
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ cpus {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ cpu: cpu@0x0 {
+ device_type = "cpu";
+ compatible = "altr,nios2-1.0";
+ reg = <0x00000000>;
+ interrupt-controller;
+ #interrupt-cells = <1>;
+ clock-frequency = <125000000>;
+ dcache-line-size = <32>;
+ icache-line-size = <32>;
+ dcache-size = <32768>;
+ icache-size = <32768>;
+ altr,implementation = "fast";
+ altr,pid-num-bits = <8>;
+ altr,tlb-num-ways = <16>;
+ altr,tlb-num-entries = <128>;
+ altr,tlb-ptr-sz = <7>;
+ altr,has-div = <1>;
+ altr,has-mul = <1>;
+ altr,reset-addr = <0xc2800000>;
+ altr,fast-tlb-miss-addr = <0xc7fff400>;
+ altr,exception-addr = <0xd0000020>;
+ altr,has-initda = <1>;
+ altr,has-mmu = <1>;
+ };
+ };
+
+ memory@0 {
+ device_type = "memory";
+ reg = <0x10000000 0x08000000>,
+ <0x07fff400 0x00000400>;
+ };
+
+ sopc@0 {
+ device_type = "soc";
+ ranges;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ compatible = "altr,avalon", "simple-bus";
+ bus-frequency = <125000000>;
+
+ pb_cpu_to_io: bridge@0x8000000 {
+ compatible = "simple-bus";
+ reg = <0x08000000 0x00800000>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+ ranges = <0x00002000 0x08002000 0x00002000>,
+ <0x00004000 0x08004000 0x00000400>,
+ <0x00004400 0x08004400 0x00000040>,
+ <0x00004800 0x08004800 0x00000040>,
+ <0x00004c80 0x08004c80 0x00000020>,
+ <0x00004d50 0x08004d50 0x00000008>,
+ <0x00008000 0x08008000 0x00000020>,
+ <0x00400000 0x08400000 0x00000020>;
+
+ timer_1ms: timer@0x400000 {
+ compatible = "altr,timer-1.0";
+ reg = <0x00400000 0x00000020>;
+ interrupt-parent = <&cpu>;
+ interrupts = <11>;
+ clock-frequency = <125000000>;
+ };
+
+ timer_0: timer@0x8000 {
+ compatible = "altr,timer-1.0";
+ reg = < 0x00008000 0x00000020 >;
+ interrupt-parent = < &cpu >;
+ interrupts = < 5 >;
+ clock-frequency = < 125000000 >;
+ };
+
+ jtag_uart: serial@0x4d50 {
+ compatible = "altr,juart-1.0";
+ reg = <0x00004d50 0x00000008>;
+ interrupt-parent = <&cpu>;
+ interrupts = <1>;
+ };
+
+ tse_mac: ethernet@0x4000 {
+ compatible = "altr,tse-1.0";
+ reg = <0x00004000 0x00000400>,
+ <0x00004400 0x00000040>,
+ <0x00004800 0x00000040>,
+ <0x00002000 0x00002000>;
+ reg-names = "control_port", "rx_csr", "tx_csr", "s1";
+ interrupt-parent = <&cpu>;
+ interrupts = <2 3>;
+ interrupt-names = "rx_irq", "tx_irq";
+ rx-fifo-depth = <8192>;
+ tx-fifo-depth = <8192>;
+ max-frame-size = <1518>;
+ local-mac-address = [ 00 00 00 00 00 00 ];
+ phy-mode = "rgmii-id";
+ phy-handle = <&phy0>;
+ tse_mac_mdio: mdio {
+ compatible = "altr,tse-mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ phy0: ethernet-phy@18 {
+ reg = <18>;
+ device_type = "ethernet-phy";
+ };
+ };
+ };
+
+ uart: serial@0x4c80 {
+ compatible = "altr,uart-1.0";
+ reg = <0x00004c80 0x00000020>;
+ interrupt-parent = <&cpu>;
+ interrupts = <10>;
+ current-speed = <115200>;
+ clock-frequency = <62500000>;
+ };
+ };
+
+ cfi_flash_64m: flash@0x0 {
+ compatible = "cfi-flash";
+ reg = <0x00000000 0x04000000>;
+ bank-width = <2>;
+ device-width = <1>;
+ #address-cells = <1>;
+ #size-cells = <1>;
+
+ partition@800000 {
+ reg = <0x00800000 0x01e00000>;
+ label = "JFFS2 Filesystem";
+ };
+ };
+ };
+
+ chosen {
+ bootargs = "debug console=ttyJ0,115200";
+ };
+};
diff --git a/arch/nios2/boot/install.sh b/arch/nios2/boot/install.sh
new file mode 100644
index 0000000..3cb3f46
--- /dev/null
+++ b/arch/nios2/boot/install.sh
@@ -0,0 +1,52 @@
+#!/bin/sh
+#
+# 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) 1995 by Linus Torvalds
+#
+# Adapted from code in arch/i386/boot/Makefile by H. Peter Anvin
+#
+# "make install" script for nios2 architecture
+#
+# Arguments:
+# $1 - kernel version
+# $2 - kernel image file
+# $3 - kernel map file
+# $4 - default install path (blank if root directory)
+#
+
+verify () {
+ if [ ! -f "$1" ]; then
+ echo "" 1>&2
+ echo " *** Missing file: $1" 1>&2
+ echo ' *** You need to run "make" before "make install".' 1>&2
+ echo "" 1>&2
+ exit 1
+ fi
+}
+
+# Make sure the files actually exist
+verify "$2"
+verify "$3"
+
+# User may have a custom install script
+
+if [ -x ~/bin/${INSTALLKERNEL} ]; then exec ~/bin/${INSTALLKERNEL} "$@"; fi
+if [ -x /sbin/${INSTALLKERNEL} ]; then exec /sbin/${INSTALLKERNEL} "$@"; fi
+
+# Default install - same as make zlilo
+
+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/vmlinuz
+cp $3 $4/System.map
+
+sync
diff --git a/arch/nios2/boot/linked_dtb.S b/arch/nios2/boot/linked_dtb.S
new file mode 100644
index 0000000..071f922
--- /dev/null
+++ b/arch/nios2/boot/linked_dtb.S
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+.section .dtb.init.rodata,"a"
+.incbin "arch/nios2/boot/system.dtb"
diff --git a/arch/nios2/configs/3c120_defconfig b/arch/nios2/configs/3c120_defconfig
new file mode 100644
index 0000000..87541f0
--- /dev/null
+++ b/arch/nios2/configs/3c120_defconfig
@@ -0,0 +1,77 @@
+CONFIG_SYSVIPC=y
+CONFIG_NO_HZ_IDLE=y
+CONFIG_BSD_PROCESS_ACCT=y
+CONFIG_LOG_BUF_SHIFT=14
+CONFIG_SYSCTL_SYSCALL=y
+# CONFIG_ELF_CORE is not set
+# CONFIG_EPOLL is not set
+# CONFIG_SIGNALFD is not set
+# CONFIG_TIMERFD is not set
+# CONFIG_EVENTFD is not set
+# CONFIG_SHMEM is not set
+# CONFIG_AIO is not set
+CONFIG_EMBEDDED=y
+CONFIG_SLAB=y
+CONFIG_MODULES=y
+CONFIG_MODULE_UNLOAD=y
+CONFIG_NIOS2_MEM_BASE=0x10000000
+CONFIG_NIOS2_HW_MUL_SUPPORT=y
+CONFIG_NIOS2_HW_DIV_SUPPORT=y
+CONFIG_CUSTOM_CACHE_SETTINGS=y
+CONFIG_NIOS2_DCACHE_SIZE=0x8000
+CONFIG_NIOS2_ICACHE_SIZE=0x8000
+# CONFIG_NIOS2_CMDLINE_IGNORE_DTB is not set
+CONFIG_NIOS2_PASS_CMDLINE=y
+CONFIG_NET=y
+CONFIG_PACKET=y
+CONFIG_UNIX=y
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+CONFIG_IP_PNP=y
+CONFIG_IP_PNP_DHCP=y
+CONFIG_IP_PNP_BOOTP=y
+CONFIG_IP_PNP_RARP=y
+# CONFIG_INET_XFRM_MODE_TRANSPORT is not set
+# CONFIG_INET_XFRM_MODE_TUNNEL is not set
+# CONFIG_INET_XFRM_MODE_BEET is not set
+# CONFIG_INET_LRO is not set
+# CONFIG_IPV6 is not set
+# CONFIG_WIRELESS is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_DEVTMPFS=y
+CONFIG_DEVTMPFS_MOUNT=y
+# CONFIG_FW_LOADER is not set
+CONFIG_MTD=y
+CONFIG_MTD_CMDLINE_PARTS=y
+CONFIG_MTD_BLOCK=y
+CONFIG_MTD_CFI=y
+CONFIG_MTD_CFI_INTELEXT=y
+CONFIG_MTD_CFI_AMDSTD=y
+CONFIG_MTD_PHYSMAP_OF=y
+CONFIG_BLK_DEV_LOOP=y
+CONFIG_NETDEVICES=y
+CONFIG_ALTERA_TSE=y
+CONFIG_MARVELL_PHY=y
+# CONFIG_WLAN is not set
+# CONFIG_INPUT_MOUSE is not set
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_VT is not set
+CONFIG_SERIAL_ALTERA_JTAGUART=y
+CONFIG_SERIAL_ALTERA_JTAGUART_CONSOLE=y
+CONFIG_SERIAL_ALTERA_UART=y
+# CONFIG_HW_RANDOM is not set
+# CONFIG_HWMON is not set
+# CONFIG_USB_SUPPORT is not set
+CONFIG_NEW_LEDS=y
+CONFIG_LEDS_CLASS=y
+CONFIG_LEDS_TRIGGERS=y
+CONFIG_LEDS_TRIGGER_HEARTBEAT=y
+# CONFIG_DNOTIFY is not set
+# CONFIG_INOTIFY_USER is not set
+CONFIG_JFFS2_FS=y
+CONFIG_NFS_FS=y
+CONFIG_NFS_V3_ACL=y
+CONFIG_ROOT_NFS=y
+CONFIG_SUNRPC_DEBUG=y
+CONFIG_DEBUG_INFO=y
+# CONFIG_ENABLE_WARN_DEPRECATED is not set
diff --git a/arch/nios2/include/asm/Kbuild b/arch/nios2/include/asm/Kbuild
new file mode 100644
index 0000000..01c75f3
--- /dev/null
+++ b/arch/nios2/include/asm/Kbuild
@@ -0,0 +1,65 @@
+generic-y += atomic.h
+generic-y += auxvec.h
+generic-y += barrier.h
+generic-y += bitops.h
+generic-y += bitsperlong.h
+generic-y += bug.h
+generic-y += bugs.h
+generic-y += clkdev.h
+generic-y += cputime.h
+generic-y += current.h
+generic-y += device.h
+generic-y += div64.h
+generic-y += dma.h
+generic-y += emergency-restart.h
+generic-y += errno.h
+generic-y += exec.h
+generic-y += fb.h
+generic-y += fcntl.h
+generic-y += ftrace.h
+generic-y += futex.h
+generic-y += hardirq.h
+generic-y += hw_irq.h
+generic-y += ioctl.h
+generic-y += ioctls.h
+generic-y += ipcbuf.h
+generic-y += irq_regs.h
+generic-y += irq_work.h
+generic-y += kdebug.h
+generic-y += kmap_types.h
+generic-y += kvm_para.h
+generic-y += local.h
+generic-y += mcs_spinlock.h
+generic-y += mman.h
+generic-y += module.h
+generic-y += msgbuf.h
+generic-y += param.h
+generic-y += pci.h
+generic-y += percpu.h
+generic-y += poll.h
+generic-y += posix_types.h
+generic-y += preempt.h
+generic-y += resource.h
+generic-y += scatterlist.h
+generic-y += sections.h
+generic-y += segment.h
+generic-y += sembuf.h
+generic-y += serial.h
+generic-y += shmbuf.h
+generic-y += shmparam.h
+generic-y += siginfo.h
+generic-y += signal.h
+generic-y += socket.h
+generic-y += sockios.h
+generic-y += spinlock.h
+generic-y += stat.h
+generic-y += statfs.h
+generic-y += termbits.h
+generic-y += termios.h
+generic-y += topology.h
+generic-y += trace_clock.h
+generic-y += types.h
+generic-y += unaligned.h
+generic-y += user.h
+generic-y += vga.h
+generic-y += xor.h
diff --git a/arch/nios2/include/asm/asm-macros.h b/arch/nios2/include/asm/asm-macros.h
new file mode 100644
index 0000000..29fa2e4
--- /dev/null
+++ b/arch/nios2/include/asm/asm-macros.h
@@ -0,0 +1,309 @@
+/*
+ * Macro used to simplify coding multi-line assembler.
+ * Some of the bit test macro can simplify down to one line
+ * depending on the mask value.
+ *
+ * Copyright (C) 2004 Microtronix Datacom 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 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ *
+ */
+#ifndef _ASM_NIOS2_ASMMACROS_H
+#define _ASM_NIOS2_ASMMACROS_H
+/*
+ * ANDs reg2 with mask and places the result in reg1.
+ *
+ * You cannnot use the same register for reg1 & reg2.
+ */
+
+.macro ANDI32 reg1, reg2, mask
+.if \mask & 0xffff
+ .if \mask & 0xffff0000
+ movhi \reg1, %hi(\mask)
+ movui \reg1, %lo(\mask)
+ and \reg1, \reg1, \reg2
+ .else
+ andi \reg1, \reg2, %lo(\mask)
+ .endif
+.else
+ andhi \reg1, \reg2, %hi(\mask)
+.endif
+.endm
+
+/*
+ * ORs reg2 with mask and places the result in reg1.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro ORI32 reg1, reg2, mask
+.if \mask & 0xffff
+ .if \mask & 0xffff0000
+ orhi \reg1, \reg2, %hi(\mask)
+ ori \reg1, \reg2, %lo(\mask)
+ .else
+ ori \reg1, \reg2, %lo(\mask)
+ .endif
+.else
+ orhi \reg1, \reg2, %hi(\mask)
+.endif
+.endm
+
+/*
+ * XORs reg2 with mask and places the result in reg1.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro XORI32 reg1, reg2, mask
+.if \mask & 0xffff
+ .if \mask & 0xffff0000
+ xorhi \reg1, \reg2, %hi(\mask)
+ xori \reg1, \reg1, %lo(\mask)
+ .else
+ xori \reg1, \reg2, %lo(\mask)
+ .endif
+.else
+ xorhi \reg1, \reg2, %hi(\mask)
+.endif
+.endm
+
+/*
+ * This is a support macro for BTBZ & BTBNZ. It checks
+ * the bit to make sure it is valid 32 value.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro BT reg1, reg2, bit
+.if \bit > 31
+ .err
+.else
+ .if \bit < 16
+ andi \reg1, \reg2, (1 << \bit)
+ .else
+ andhi \reg1, \reg2, (1 << (\bit - 16))
+ .endif
+.endif
+.endm
+
+/*
+ * Tests the bit in reg2 and branches to label if the
+ * bit is zero. The result of the bit test is stored in reg1.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTBZ reg1, reg2, bit, label
+ BT \reg1, \reg2, \bit
+ beq \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and branches to label if the
+ * bit is non-zero. The result of the bit test is stored in reg1.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTBNZ reg1, reg2, bit, label
+ BT \reg1, \reg2, \bit
+ bne \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and then compliments the bit in reg2.
+ * The result of the bit test is stored in reg1.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTC reg1, reg2, bit
+.if \bit > 31
+ .err
+.else
+ .if \bit < 16
+ andi \reg1, \reg2, (1 << \bit)
+ xori \reg2, \reg2, (1 << \bit)
+ .else
+ andhi \reg1, \reg2, (1 << (\bit - 16))
+ xorhi \reg2, \reg2, (1 << (\bit - 16))
+ .endif
+.endif
+.endm
+
+/*
+ * Tests the bit in reg2 and then sets the bit in reg2.
+ * The result of the bit test is stored in reg1.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTS reg1, reg2, bit
+.if \bit > 31
+ .err
+.else
+ .if \bit < 16
+ andi \reg1, \reg2, (1 << \bit)
+ ori \reg2, \reg2, (1 << \bit)
+ .else
+ andhi \reg1, \reg2, (1 << (\bit - 16))
+ orhi \reg2, \reg2, (1 << (\bit - 16))
+ .endif
+.endif
+.endm
+
+/*
+ * Tests the bit in reg2 and then resets the bit in reg2.
+ * The result of the bit test is stored in reg1.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTR reg1, reg2, bit
+.if \bit > 31
+ .err
+.else
+ .if \bit < 16
+ andi \reg1, \reg2, (1 << \bit)
+ andi \reg2, \reg2, %lo(~(1 << \bit))
+ .else
+ andhi \reg1, \reg2, (1 << (\bit - 16))
+ andhi \reg2, \reg2, %lo(~(1 << (\bit - 16)))
+ .endif
+.endif
+.endm
+
+/*
+ * Tests the bit in reg2 and then compliments the bit in reg2.
+ * The result of the bit test is stored in reg1. If the
+ * original bit was zero it branches to label.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTCBZ reg1, reg2, bit, label
+ BTC \reg1, \reg2, \bit
+ beq \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and then compliments the bit in reg2.
+ * The result of the bit test is stored in reg1. If the
+ * original bit was non-zero it branches to label.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTCBNZ reg1, reg2, bit, label
+ BTC \reg1, \reg2, \bit
+ bne \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and then sets the bit in reg2.
+ * The result of the bit test is stored in reg1. If the
+ * original bit was zero it branches to label.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTSBZ reg1, reg2, bit, label
+ BTS \reg1, \reg2, \bit
+ beq \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and then sets the bit in reg2.
+ * The result of the bit test is stored in reg1. If the
+ * original bit was non-zero it branches to label.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTSBNZ reg1, reg2, bit, label
+ BTS \reg1, \reg2, \bit
+ bne \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and then resets the bit in reg2.
+ * The result of the bit test is stored in reg1. If the
+ * original bit was zero it branches to label.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTRBZ reg1, reg2, bit, label
+ BTR \reg1, \reg2, \bit
+ bne \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bit in reg2 and then resets the bit in reg2.
+ * The result of the bit test is stored in reg1. If the
+ * original bit was non-zero it branches to label.
+ *
+ * It is NOT safe to use the same register for reg1 & reg2.
+ */
+
+.macro BTRBNZ reg1, reg2, bit, label
+ BTR \reg1, \reg2, \bit
+ bne \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bits in mask against reg2 stores the result in reg1.
+ * If the all the bits in the mask are zero it branches to label.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro TSTBZ reg1, reg2, mask, label
+ ANDI32 \reg1, \reg2, \mask
+ beq \reg1, r0, \label
+.endm
+
+/*
+ * Tests the bits in mask against reg2 stores the result in reg1.
+ * If the any of the bits in the mask are 1 it branches to label.
+ *
+ * It is safe to use the same register for reg1 & reg2.
+ */
+
+.macro TSTBNZ reg1, reg2, mask, label
+ ANDI32 \reg1, \reg2, \mask
+ bne \reg1, r0, \label
+.endm
+
+/*
+ * Pushes reg onto the stack.
+ */
+
+.macro PUSH reg
+ addi sp, sp, -4
+ stw \reg, 0(sp)
+.endm
+
+/*
+ * Pops the top of the stack into reg.
+ */
+
+.macro POP reg
+ ldw \reg, 0(sp)
+ addi sp, sp, 4
+.endm
+
+
+#endif /* _ASM_NIOS2_ASMMACROS_H */
diff --git a/arch/nios2/include/asm/asm-offsets.h b/arch/nios2/include/asm/asm-offsets.h
new file mode 100644
index 0000000..5b9f5e0
--- /dev/null
+++ b/arch/nios2/include/asm/asm-offsets.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <generated/asm-offsets.h>
diff --git a/arch/nios2/include/asm/cache.h b/arch/nios2/include/asm/cache.h
new file mode 100644
index 0000000..2293cf5
--- /dev/null
+++ b/arch/nios2/include/asm/cache.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2004 Microtronix Datacom 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 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef _ASM_NIOS2_CACHE_H
+#define _ASM_NIOS2_CACHE_H
+
+#define NIOS2_DCACHE_SIZE CONFIG_NIOS2_DCACHE_SIZE
+#define NIOS2_ICACHE_SIZE CONFIG_NIOS2_ICACHE_SIZE
+#define NIOS2_DCACHE_LINE_SIZE CONFIG_NIOS2_DCACHE_LINE_SIZE
+#define NIOS2_ICACHE_LINE_SHIFT 5
+#define NIOS2_ICACHE_LINE_SIZE (1 << NIOS2_ICACHE_LINE_SHIFT)
+
+/* bytes per L1 cache line */
+#define L1_CACHE_SHIFT NIOS2_ICACHE_LINE_SHIFT
+#define L1_CACHE_BYTES NIOS2_ICACHE_LINE_SIZE
+
+#define ARCH_DMA_MINALIGN L1_CACHE_BYTES
+
+#define __cacheline_aligned
+#define ____cacheline_aligned
+
+#endif
diff --git a/arch/nios2/include/asm/cacheflush.h b/arch/nios2/include/asm/cacheflush.h
new file mode 100644
index 0000000..52abba9
--- /dev/null
+++ b/arch/nios2/include/asm/cacheflush.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2003 Microtronix Datacom Ltd.
+ * Copyright (C) 2000-2002 Greg Ungerer <gerg@snapgear.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_CACHEFLUSH_H
+#define _ASM_NIOS2_CACHEFLUSH_H
+
+#include <linux/mm_types.h>
+
+/*
+ * This flag is used to indicate that the page pointed to by a pte is clean
+ * and does not require cleaning before returning it to the user.
+ */
+#define PG_dcache_clean PG_arch_1
+
+struct mm_struct;
+
+extern void flush_cache_all(void);
+extern void flush_cache_mm(struct mm_struct *mm);
+extern void flush_cache_dup_mm(struct mm_struct *mm);
+extern void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end);
+extern void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
+ unsigned long pfn);
+#define ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE 1
+extern void flush_dcache_page(struct page *page);
+
+extern void flush_icache_range(unsigned long start, unsigned long end);
+extern void flush_icache_page(struct vm_area_struct *vma, struct page *page);
+
+#define flush_cache_vmap(start, end) flush_dcache_range(start, end)
+#define flush_cache_vunmap(start, end) flush_dcache_range(start, end)
+
+extern void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr,
+ void *dst, void *src, int len);
+extern void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr,
+ void *dst, void *src, int len);
+
+extern void flush_dcache_range(unsigned long start, unsigned long end);
+extern void invalidate_dcache_range(unsigned long start, unsigned long end);
+
+#define flush_dcache_mmap_lock(mapping) do { } while (0)
+#define flush_dcache_mmap_unlock(mapping) do { } while (0)
+
+#endif /* _ASM_NIOS2_CACHEFLUSH_H */
diff --git a/arch/nios2/include/asm/checksum.h b/arch/nios2/include/asm/checksum.h
new file mode 100644
index 0000000..6bc1f0d
--- /dev/null
+++ b/arch/nios2/include/asm/checksum.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS_CHECKSUM_H
+#define _ASM_NIOS_CHECKSUM_H
+
+/* Take these from lib/checksum.c */
+extern __wsum csum_partial(const void *buff, int len, __wsum sum);
+extern __wsum csum_partial_copy(const void *src, void *dst, int len,
+ __wsum sum);
+extern __wsum csum_partial_copy_from_user(const void __user *src, void *dst,
+ int len, __wsum sum, int *csum_err);
+#define csum_partial_copy_nocheck(src, dst, len, sum) \
+ csum_partial_copy((src), (dst), (len), (sum))
+
+extern __sum16 ip_fast_csum(const void *iph, unsigned int ihl);
+extern __sum16 ip_compute_csum(const void *buff, int len);
+
+/*
+ * Fold a partial checksum
+ */
+static inline __sum16 csum_fold(__wsum sum)
+{
+ __asm__ __volatile__(
+ "add %0, %1, %0\n"
+ "cmpltu r8, %0, %1\n"
+ "srli %0, %0, 16\n"
+ "add %0, %0, r8\n"
+ "nor %0, %0, %0\n"
+ : "=r" (sum)
+ : "r" (sum << 16), "0" (sum)
+ : "r8");
+ return (__force __sum16) sum;
+}
+
+/*
+ * computes the checksum of the TCP/UDP pseudo-header
+ * returns a 16-bit checksum, already complemented
+ */
+#define csum_tcpudp_nofold csum_tcpudp_nofold
+static inline __wsum csum_tcpudp_nofold(__be32 saddr, __be32 daddr,
+ unsigned short len,
+ unsigned short proto,
+ __wsum sum)
+{
+ __asm__ __volatile__(
+ "add %0, %1, %0\n"
+ "cmpltu r8, %0, %1\n"
+ "add %0, %0, r8\n" /* add carry */
+ "add %0, %2, %0\n"
+ "cmpltu r8, %0, %2\n"
+ "add %0, %0, r8\n" /* add carry */
+ "add %0, %3, %0\n"
+ "cmpltu r8, %0, %3\n"
+ "add %0, %0, r8\n" /* add carry */
+ : "=r" (sum), "=r" (saddr)
+ : "r" (daddr), "r" ((ntohs(len) << 16) + (proto * 256)),
+ "0" (sum),
+ "1" (saddr)
+ : "r8");
+
+ return sum;
+}
+
+static inline __sum16 csum_tcpudp_magic(__be32 saddr, __be32 daddr,
+ unsigned short len,
+ unsigned short proto, __wsum sum)
+{
+ return csum_fold(csum_tcpudp_nofold(saddr, daddr, len, proto, sum));
+}
+
+#endif /* _ASM_NIOS_CHECKSUM_H */
diff --git a/arch/nios2/include/asm/cmpxchg.h b/arch/nios2/include/asm/cmpxchg.h
new file mode 100644
index 0000000..8593871
--- /dev/null
+++ b/arch/nios2/include/asm/cmpxchg.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_CMPXCHG_H
+#define _ASM_NIOS2_CMPXCHG_H
+
+#include <linux/irqflags.h>
+
+#define xchg(ptr, x) \
+ ((__typeof__(*(ptr)))__xchg((unsigned long)(x), (ptr), sizeof(*(ptr))))
+
+struct __xchg_dummy { unsigned long a[100]; };
+#define __xg(x) ((volatile struct __xchg_dummy *)(x))
+
+static inline unsigned long __xchg(unsigned long x, volatile void *ptr,
+ int size)
+{
+ unsigned long tmp, flags;
+
+ local_irq_save(flags);
+
+ switch (size) {
+ case 1:
+ __asm__ __volatile__(
+ "ldb %0, %2\n"
+ "stb %1, %2\n"
+ : "=&r" (tmp)
+ : "r" (x), "m" (*__xg(ptr))
+ : "memory");
+ break;
+ case 2:
+ __asm__ __volatile__(
+ "ldh %0, %2\n"
+ "sth %1, %2\n"
+ : "=&r" (tmp)
+ : "r" (x), "m" (*__xg(ptr))
+ : "memory");
+ break;
+ case 4:
+ __asm__ __volatile__(
+ "ldw %0, %2\n"
+ "stw %1, %2\n"
+ : "=&r" (tmp)
+ : "r" (x), "m" (*__xg(ptr))
+ : "memory");
+ break;
+ }
+
+ local_irq_restore(flags);
+ return tmp;
+}
+
+#include <asm-generic/cmpxchg.h>
+#include <asm-generic/cmpxchg-local.h>
+
+#endif /* _ASM_NIOS2_CMPXCHG_H */
diff --git a/arch/nios2/include/asm/cpuinfo.h b/arch/nios2/include/asm/cpuinfo.h
new file mode 100644
index 0000000..e88fcae
--- /dev/null
+++ b/arch/nios2/include/asm/cpuinfo.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _ASM_NIOS2_CPUINFO_H
+#define _ASM_NIOS2_CPUINFO_H
+
+#include <linux/types.h>
+
+struct cpuinfo {
+ /* Core CPU configuration */
+ char cpu_impl[12];
+ u32 cpu_clock_freq;
+ u32 mmu;
+ u32 has_div;
+ u32 has_mul;
+ u32 has_mulx;
+
+ /* CPU caches */
+ u32 icache_line_size;
+ u32 icache_size;
+ u32 dcache_line_size;
+ u32 dcache_size;
+
+ /* TLB */
+ u32 tlb_pid_num_bits; /* number of bits used for the PID in TLBMISC */
+ u32 tlb_num_ways;
+ u32 tlb_num_ways_log2;
+ u32 tlb_num_entries;
+ u32 tlb_num_lines;
+ u32 tlb_ptr_sz;
+
+ /* Addresses */
+ u32 reset_addr;
+ u32 exception_addr;
+ u32 fast_tlb_miss_exc_addr;
+};
+
+extern struct cpuinfo cpuinfo;
+
+extern void setup_cpuinfo(void);
+
+#endif /* _ASM_NIOS2_CPUINFO_H */
diff --git a/arch/nios2/include/asm/delay.h b/arch/nios2/include/asm/delay.h
new file mode 100644
index 0000000..098e49b
--- /dev/null
+++ b/arch/nios2/include/asm/delay.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 Altera Corporation
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_DELAY_H
+#define _ASM_NIOS2_DELAY_H
+
+#include <asm-generic/delay.h>
+
+/* Undefined functions to get compile-time errors */
+extern void __bad_udelay(void);
+extern void __bad_ndelay(void);
+
+extern unsigned long loops_per_jiffy;
+
+#endif /* _ASM_NIOS2_DELAY_H */
diff --git a/arch/nios2/include/asm/dma-mapping.h b/arch/nios2/include/asm/dma-mapping.h
new file mode 100644
index 0000000..b556723
--- /dev/null
+++ b/arch/nios2/include/asm/dma-mapping.h
@@ -0,0 +1,140 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#ifndef _ASM_NIOS2_DMA_MAPPING_H
+#define _ASM_NIOS2_DMA_MAPPING_H
+
+#include <linux/scatterlist.h>
+#include <linux/cache.h>
+#include <asm/cacheflush.h>
+
+static inline void __dma_sync_for_device(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+ switch (direction) {
+ case DMA_FROM_DEVICE:
+ invalidate_dcache_range((unsigned long)vaddr,
+ (unsigned long)(vaddr + size));
+ break;
+ case DMA_TO_DEVICE:
+ /*
+ * We just need to flush the caches here , but Nios2 flush
+ * instruction will do both writeback and invalidate.
+ */
+ case DMA_BIDIRECTIONAL: /* flush and invalidate */
+ flush_dcache_range((unsigned long)vaddr,
+ (unsigned long)(vaddr + size));
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline void __dma_sync_for_cpu(void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+ switch (direction) {
+ case DMA_BIDIRECTIONAL:
+ case DMA_FROM_DEVICE:
+ invalidate_dcache_range((unsigned long)vaddr,
+ (unsigned long)(vaddr + size));
+ break;
+ case DMA_TO_DEVICE:
+ break;
+ default:
+ BUG();
+ }
+}
+
+#define dma_alloc_noncoherent(d, s, h, f) dma_alloc_coherent(d, s, h, f)
+#define dma_free_noncoherent(d, s, v, h) dma_free_coherent(d, s, v, h)
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t flag);
+
+void dma_free_coherent(struct device *dev, size_t size,
+ void *vaddr, dma_addr_t dma_handle);
+
+static inline dma_addr_t dma_map_single(struct device *dev, void *ptr,
+ size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+ __dma_sync_for_device(ptr, size, direction);
+ return virt_to_phys(ptr);
+}
+
+static inline void dma_unmap_single(struct device *dev, dma_addr_t dma_addr,
+ size_t size, enum dma_data_direction direction)
+{
+}
+
+extern int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction);
+extern dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size, enum dma_data_direction direction);
+extern void dma_unmap_page(struct device *dev, dma_addr_t dma_address,
+ size_t size, enum dma_data_direction direction);
+extern void dma_unmap_sg(struct device *dev, struct scatterlist *sg,
+ int nhwentries, enum dma_data_direction direction);
+extern void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction);
+extern void dma_sync_single_for_device(struct device *dev,
+ dma_addr_t dma_handle, size_t size, enum dma_data_direction direction);
+extern void dma_sync_single_range_for_cpu(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_single_range_for_device(struct device *dev,
+ dma_addr_t dma_handle, unsigned long offset, size_t size,
+ enum dma_data_direction direction);
+extern void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction);
+extern void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction);
+
+static inline int dma_supported(struct device *dev, u64 mask)
+{
+ return 1;
+}
+
+static inline int dma_set_mask(struct device *dev, u64 mask)
+{
+ if (!dev->dma_mask || !dma_supported(dev, mask))
+ return -EIO;
+
+ *dev->dma_mask = mask;
+
+ return 0;
+}
+
+static inline int dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
+{
+ return 0;
+}
+
+/*
+* dma_alloc_noncoherent() returns non-cacheable memory, so there's no need to
+* do any flushing here.
+*/
+static inline void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
+ enum dma_data_direction direction)
+{
+}
+
+/* drivers/base/dma-mapping.c */
+extern int dma_common_mmap(struct device *dev, struct vm_area_struct *vma,
+ void *cpu_addr, dma_addr_t dma_addr, size_t size);
+extern int dma_common_get_sgtable(struct device *dev, struct sg_table *sgt,
+ void *cpu_addr, dma_addr_t dma_addr,
+ size_t size);
+
+#define dma_mmap_coherent(d, v, c, h, s) dma_common_mmap(d, v, c, h, s)
+#define dma_get_sgtable(d, t, v, h, s) dma_common_get_sgtable(d, t, v, h, s)
+
+#endif /* _ASM_NIOS2_DMA_MAPPING_H */
diff --git a/arch/nios2/include/asm/elf.h b/arch/nios2/include/asm/elf.h
new file mode 100644
index 0000000..b7d655d
--- /dev/null
+++ b/arch/nios2/include/asm/elf.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _ASM_NIOS2_ELF_H
+#define _ASM_NIOS2_ELF_H
+
+#include <uapi/asm/elf.h>
+
+/*
+ * This is used to ensure we don't load something for the wrong architecture.
+ */
+#define elf_check_arch(x) ((x)->e_machine == EM_ALTERA_NIOS2)
+
+#define ELF_PLAT_INIT(_r, load_addr)
+
+#define CORE_DUMP_USE_REGSET
+#define ELF_EXEC_PAGESIZE 4096
+
+/* This is the location that an ET_DYN program is loaded if exec'ed. Typical
+ use of this is to invoke "./ld.so someprog" to test out a new version of
+ the loader. We need to make sure that it is out of the way of the program
+ that it will "exec", and that there is sufficient room for the brk. */
+
+#define ELF_ET_DYN_BASE 0xD0000000UL
+
+/* regs is struct pt_regs, pr_reg is elf_gregset_t (which is
+ now struct_user_regs, they are different) */
+
+#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
+struct linux_binprm;
+extern int arch_setup_additional_pages(struct linux_binprm *bprm,
+ int uses_interp);
+#define ELF_CORE_COPY_REGS(pr_reg, regs) \
+{ do { \
+ /* Bleech. */ \
+ pr_reg[0] = regs->r8; \
+ pr_reg[1] = regs->r9; \
+ pr_reg[2] = regs->r10; \
+ pr_reg[3] = regs->r11; \
+ pr_reg[4] = regs->r12; \
+ pr_reg[5] = regs->r13; \
+ pr_reg[6] = regs->r14; \
+ pr_reg[7] = regs->r15; \
+ pr_reg[8] = regs->r1; \
+ pr_reg[9] = regs->r2; \
+ pr_reg[10] = regs->r3; \
+ pr_reg[11] = regs->r4; \
+ pr_reg[12] = regs->r5; \
+ pr_reg[13] = regs->r6; \
+ pr_reg[14] = regs->r7; \
+ pr_reg[15] = regs->orig_r2; \
+ pr_reg[16] = regs->ra; \
+ pr_reg[17] = regs->fp; \
+ pr_reg[18] = regs->sp; \
+ pr_reg[19] = regs->gp; \
+ pr_reg[20] = regs->estatus; \
+ pr_reg[21] = regs->ea; \
+ pr_reg[22] = regs->orig_r7; \
+ { \
+ struct switch_stack *sw = ((struct switch_stack *)regs) - 1; \
+ pr_reg[23] = sw->r16; \
+ pr_reg[24] = sw->r17; \
+ pr_reg[25] = sw->r18; \
+ pr_reg[26] = sw->r19; \
+ pr_reg[27] = sw->r20; \
+ pr_reg[28] = sw->r21; \
+ pr_reg[29] = sw->r22; \
+ pr_reg[30] = sw->r23; \
+ pr_reg[31] = sw->fp; \
+ pr_reg[32] = sw->gp; \
+ pr_reg[33] = sw->ra; \
+ } \
+} while (0); }
+
+/* This yields a mask that user programs can use to figure out what
+ instruction set this cpu supports. */
+
+#define ELF_HWCAP (0)
+
+/* This yields a string that ld.so will use to load implementation
+ specific libraries for optimization. This is more specific in
+ intent than poking at uname or /proc/cpuinfo. */
+
+#define ELF_PLATFORM (NULL)
+
+#endif /* _ASM_NIOS2_ELF_H */
diff --git a/arch/nios2/include/asm/entry.h b/arch/nios2/include/asm/entry.h
new file mode 100644
index 0000000..cf37f55
--- /dev/null
+++ b/arch/nios2/include/asm/entry.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_ENTRY_H
+#define _ASM_NIOS2_ENTRY_H
+
+#ifdef __ASSEMBLY__
+
+#include <asm/processor.h>
+#include <asm/registers.h>
+#include <asm/asm-offsets.h>
+
+/*
+ * Standard Nios2 interrupt entry and exit macros.
+ * Must be called with interrupts disabled.
+ */
+.macro SAVE_ALL
+ rdctl r24, estatus
+ andi r24, r24, ESTATUS_EU
+ beq r24, r0, 1f /* In supervisor mode, already on kernel stack */
+
+ movia r24, _current_thread /* Switch to current kernel stack */
+ ldw r24, 0(r24) /* using the thread_info */
+ addi r24, r24, THREAD_SIZE-PT_REGS_SIZE
+ stw sp, PT_SP(r24) /* Save user stack before changing */
+ mov sp, r24
+ br 2f
+
+1 : mov r24, sp
+ addi sp, sp, -PT_REGS_SIZE /* Backup the kernel stack pointer */
+ stw r24, PT_SP(sp)
+2 : stw r1, PT_R1(sp)
+ stw r2, PT_R2(sp)
+ stw r3, PT_R3(sp)
+ stw r4, PT_R4(sp)
+ stw r5, PT_R5(sp)
+ stw r6, PT_R6(sp)
+ stw r7, PT_R7(sp)
+ stw r8, PT_R8(sp)
+ stw r9, PT_R9(sp)
+ stw r10, PT_R10(sp)
+ stw r11, PT_R11(sp)
+ stw r12, PT_R12(sp)
+ stw r13, PT_R13(sp)
+ stw r14, PT_R14(sp)
+ stw r15, PT_R15(sp)
+ stw r2, PT_ORIG_R2(sp)
+ stw r7, PT_ORIG_R7(sp)
+
+ stw ra, PT_RA(sp)
+ stw fp, PT_FP(sp)
+ stw gp, PT_GP(sp)
+ rdctl r24, estatus
+ stw r24, PT_ESTATUS(sp)
+ stw ea, PT_EA(sp)
+.endm
+
+.macro RESTORE_ALL
+ ldw r1, PT_R1(sp) /* Restore registers */
+ ldw r2, PT_R2(sp)
+ ldw r3, PT_R3(sp)
+ ldw r4, PT_R4(sp)
+ ldw r5, PT_R5(sp)
+ ldw r6, PT_R6(sp)
+ ldw r7, PT_R7(sp)
+ ldw r8, PT_R8(sp)
+ ldw r9, PT_R9(sp)
+ ldw r10, PT_R10(sp)
+ ldw r11, PT_R11(sp)
+ ldw r12, PT_R12(sp)
+ ldw r13, PT_R13(sp)
+ ldw r14, PT_R14(sp)
+ ldw r15, PT_R15(sp)
+ ldw ra, PT_RA(sp)
+ ldw fp, PT_FP(sp)
+ ldw gp, PT_GP(sp)
+ ldw r24, PT_ESTATUS(sp)
+ wrctl estatus, r24
+ ldw ea, PT_EA(sp)
+ ldw sp, PT_SP(sp) /* Restore sp last */
+.endm
+
+.macro SAVE_SWITCH_STACK
+ addi sp, sp, -SWITCH_STACK_SIZE
+ stw r16, SW_R16(sp)
+ stw r17, SW_R17(sp)
+ stw r18, SW_R18(sp)
+ stw r19, SW_R19(sp)
+ stw r20, SW_R20(sp)
+ stw r21, SW_R21(sp)
+ stw r22, SW_R22(sp)
+ stw r23, SW_R23(sp)
+ stw fp, SW_FP(sp)
+ stw gp, SW_GP(sp)
+ stw ra, SW_RA(sp)
+.endm
+
+.macro RESTORE_SWITCH_STACK
+ ldw r16, SW_R16(sp)
+ ldw r17, SW_R17(sp)
+ ldw r18, SW_R18(sp)
+ ldw r19, SW_R19(sp)
+ ldw r20, SW_R20(sp)
+ ldw r21, SW_R21(sp)
+ ldw r22, SW_R22(sp)
+ ldw r23, SW_R23(sp)
+ ldw fp, SW_FP(sp)
+ ldw gp, SW_GP(sp)
+ ldw ra, SW_RA(sp)
+ addi sp, sp, SWITCH_STACK_SIZE
+.endm
+
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_NIOS2_ENTRY_H */
diff --git a/arch/nios2/include/asm/io.h b/arch/nios2/include/asm/io.h
new file mode 100644
index 0000000..9102bfd
--- /dev/null
+++ b/arch/nios2/include/asm/io.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2014 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_IO_H
+#define _ASM_NIOS2_IO_H
+
+#include <linux/types.h>
+#include <asm/pgtable-bits.h>
+
+/* PCI is not supported in nios2, set this to 0. */
+#define IO_SPACE_LIMIT 0
+
+#define readb_relaxed(addr) readb(addr)
+#define readw_relaxed(addr) readw(addr)
+#define readl_relaxed(addr) readl(addr)
+
+#define writeb_relaxed(x, addr) writeb(x, addr)
+#define writew_relaxed(x, addr) writew(x, addr)
+#define writel_relaxed(x, addr) writel(x, addr)
+
+extern void __iomem *__ioremap(unsigned long physaddr, unsigned long size,
+ unsigned long cacheflag);
+extern void __iounmap(void __iomem *addr);
+
+static inline void __iomem *ioremap(unsigned long physaddr, unsigned long size)
+{
+ return __ioremap(physaddr, size, 0);
+}
+
+static inline void __iomem *ioremap_nocache(unsigned long physaddr,
+ unsigned long size)
+{
+ return __ioremap(physaddr, size, 0);
+}
+
+static inline void iounmap(void __iomem *addr)
+{
+ __iounmap(addr);
+}
+
+/* Pages to physical address... */
+#define page_to_phys(page) virt_to_phys(page_to_virt(page))
+#define page_to_bus(page) page_to_virt(page)
+
+/* Macros used for converting between virtual and physical mappings. */
+#define phys_to_virt(vaddr) \
+ ((void *)((unsigned long)(vaddr) | CONFIG_NIOS2_KERNEL_REGION_BASE))
+/* Clear top 3 bits */
+#define virt_to_phys(vaddr) \
+ ((unsigned long)((unsigned long)(vaddr) & ~0xE0000000))
+
+#include <asm-generic/io.h>
+
+#endif /* _ASM_NIOS2_IO_H */
diff --git a/arch/nios2/include/asm/irq.h b/arch/nios2/include/asm/irq.h
new file mode 100644
index 0000000..8e40fd9
--- /dev/null
+++ b/arch/nios2/include/asm/irq.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _ASM_NIOS2_IRQ_H
+#define _ASM_NIOS2_IRQ_H
+
+#define NIOS2_CPU_NR_IRQS 32
+
+#include <asm-generic/irq.h>
+#include <linux/irqdomain.h>
+
+#endif
diff --git a/arch/nios2/include/asm/irqflags.h b/arch/nios2/include/asm/irqflags.h
new file mode 100644
index 0000000..75ab92e
--- /dev/null
+++ b/arch/nios2/include/asm/irqflags.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef _ASM_IRQFLAGS_H
+#define _ASM_IRQFLAGS_H
+
+#include <asm/registers.h>
+
+static inline unsigned long arch_local_save_flags(void)
+{
+ return RDCTL(CTL_STATUS);
+}
+
+/*
+ * This will restore ALL status register flags, not only the interrupt
+ * mask flag.
+ */
+static inline void arch_local_irq_restore(unsigned long flags)
+{
+ WRCTL(CTL_STATUS, flags);
+}
+
+static inline void arch_local_irq_disable(void)
+{
+ unsigned long flags;
+
+ flags = arch_local_save_flags();
+ arch_local_irq_restore(flags & ~STATUS_PIE);
+}
+
+static inline void arch_local_irq_enable(void)
+{
+ unsigned long flags;
+
+ flags = arch_local_save_flags();
+ arch_local_irq_restore(flags | STATUS_PIE);
+}
+
+static inline int arch_irqs_disabled_flags(unsigned long flags)
+{
+ return (flags & STATUS_PIE) == 0;
+}
+
+static inline int arch_irqs_disabled(void)
+{
+ return arch_irqs_disabled_flags(arch_local_save_flags());
+}
+
+static inline unsigned long arch_local_irq_save(void)
+{
+ unsigned long flags;
+
+ flags = arch_local_save_flags();
+ arch_local_irq_restore(flags & ~STATUS_PIE);
+ return flags;
+}
+
+#endif /* _ASM_IRQFLAGS_H */
diff --git a/arch/nios2/include/asm/linkage.h b/arch/nios2/include/asm/linkage.h
new file mode 100644
index 0000000..e0c6dec
--- /dev/null
+++ b/arch/nios2/include/asm/linkage.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef _ASM_NIOS2_LINKAGE_H
+#define _ASM_NIOS2_LINKAGE_H
+
+/* This file is required by include/linux/linkage.h */
+#define __ALIGN .align 4
+#define __ALIGN_STR ".align 4"
+
+#endif
diff --git a/arch/nios2/include/asm/mmu.h b/arch/nios2/include/asm/mmu.h
new file mode 100644
index 0000000..d9c0b10
--- /dev/null
+++ b/arch/nios2/include/asm/mmu.h
@@ -0,0 +1,16 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_MMU_H
+#define _ASM_NIOS2_MMU_H
+
+/* Default "unsigned long" context */
+typedef unsigned long mm_context_t;
+
+#endif /* _ASM_NIOS2_MMU_H */
diff --git a/arch/nios2/include/asm/mmu_context.h b/arch/nios2/include/asm/mmu_context.h
new file mode 100644
index 0000000..294b4b1
--- /dev/null
+++ b/arch/nios2/include/asm/mmu_context.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 1996, 1997, 1998, 1999 by Ralf Baechle
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ *
+ * based on MIPS asm/mmu_context.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_MMU_CONTEXT_H
+#define _ASM_NIOS2_MMU_CONTEXT_H
+
+#include <asm-generic/mm_hooks.h>
+
+extern void mmu_context_init(void);
+extern unsigned long get_pid_from_context(mm_context_t *ctx);
+
+/*
+ * For the fast tlb miss handlers, we keep a pointer to the current pgd.
+ * processor.
+ */
+extern pgd_t *pgd_current;
+
+static inline void enter_lazy_tlb(struct mm_struct *mm, struct task_struct *tsk)
+{
+}
+
+/*
+ * Initialize the context related info for a new mm_struct instance.
+ *
+ * Set all new contexts to 0, that way the generation will never match
+ * the currently running generation when this context is switched in.
+ */
+static inline int init_new_context(struct task_struct *tsk,
+ struct mm_struct *mm)
+{
+ mm->context = 0;
+ return 0;
+}
+
+/*
+ * Destroy context related info for an mm_struct that is about
+ * to be put to rest.
+ */
+static inline void destroy_context(struct mm_struct *mm)
+{
+}
+
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk);
+
+static inline void deactivate_mm(struct task_struct *tsk,
+ struct mm_struct *mm)
+{
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+void activate_mm(struct mm_struct *prev, struct mm_struct *next);
+
+#endif /* _ASM_NIOS2_MMU_CONTEXT_H */
diff --git a/arch/nios2/include/asm/mutex.h b/arch/nios2/include/asm/mutex.h
new file mode 100644
index 0000000..ff6101a
--- /dev/null
+++ b/arch/nios2/include/asm/mutex.h
@@ -0,0 +1 @@
+#include <asm-generic/mutex-dec.h>
diff --git a/arch/nios2/include/asm/page.h b/arch/nios2/include/asm/page.h
new file mode 100644
index 0000000..4b32d6f
--- /dev/null
+++ b/arch/nios2/include/asm/page.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * MMU support based on asm/page.h from mips which is:
+ *
+ * Copyright (C) 1994 - 1999, 2000, 03 Ralf Baechle
+ * Copyright (C) 1999, 2000 Silicon Graphics, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_PAGE_H
+#define _ASM_NIOS2_PAGE_H
+
+#include <linux/pfn.h>
+#include <linux/const.h>
+
+/*
+ * PAGE_SHIFT determines the page size
+ */
+#define PAGE_SHIFT 12
+#define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT)
+#define PAGE_MASK (~(PAGE_SIZE - 1))
+
+/*
+ * PAGE_OFFSET -- the first address of the first page of memory.
+ */
+#define PAGE_OFFSET \
+ (CONFIG_NIOS2_MEM_BASE + CONFIG_NIOS2_KERNEL_REGION_BASE)
+
+#ifndef __ASSEMBLY__
+
+/*
+ * This gives the physical RAM offset.
+ */
+#define PHYS_OFFSET CONFIG_NIOS2_MEM_BASE
+
+/*
+ * It's normally defined only for FLATMEM config but it's
+ * used in our early mem init code for all memory models.
+ * So always define it.
+ */
+#define ARCH_PFN_OFFSET PFN_UP(PHYS_OFFSET)
+
+#define clear_page(page) memset((page), 0, PAGE_SIZE)
+#define copy_page(to, from) memcpy((to), (from), PAGE_SIZE)
+
+struct page;
+
+extern void clear_user_page(void *addr, unsigned long vaddr, struct page *page);
+extern void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+ struct page *to);
+
+/*
+ * These are used to make use of C type-checking.
+ */
+typedef struct page *pgtable_t;
+typedef struct { unsigned long pte; } pte_t;
+typedef struct { unsigned long pgd; } pgd_t;
+typedef struct { unsigned long pgprot; } pgprot_t;
+
+#define pte_val(x) ((x).pte)
+#define pgd_val(x) ((x).pgd)
+#define pgprot_val(x) ((x).pgprot)
+
+#define __pte(x) ((pte_t) { (x) })
+#define __pgd(x) ((pgd_t) { (x) })
+#define __pgprot(x) ((pgprot_t) { (x) })
+
+extern unsigned long memory_start;
+extern unsigned long memory_end;
+extern unsigned long memory_size;
+
+extern struct page *mem_map;
+
+#endif /* !__ASSEMBLY__ */
+
+# define __pa(x) \
+ ((unsigned long)(x) - PAGE_OFFSET + PHYS_OFFSET)
+# define __va(x) \
+ ((void *)((unsigned long)(x) + PAGE_OFFSET - PHYS_OFFSET))
+
+#define page_to_virt(page) \
+ ((((page) - mem_map) << PAGE_SHIFT) + PAGE_OFFSET)
+
+# define pfn_to_kaddr(pfn) __va((pfn) << PAGE_SHIFT)
+# define pfn_valid(pfn) ((pfn) >= ARCH_PFN_OFFSET && \
+ (pfn) < max_mapnr)
+
+# define virt_to_page(vaddr) pfn_to_page(PFN_DOWN(virt_to_phys(vaddr)))
+# define virt_addr_valid(vaddr) pfn_valid(PFN_DOWN(virt_to_phys(vaddr)))
+
+# define VM_DATA_DEFAULT_FLAGS (VM_READ | VM_WRITE | \
+ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC)
+
+# define UNCAC_ADDR(addr) \
+ ((void *)((unsigned)(addr) | CONFIG_NIOS2_IO_REGION_BASE))
+# define CAC_ADDR(addr) \
+ ((void *)(((unsigned)(addr) & ~CONFIG_NIOS2_IO_REGION_BASE) | \
+ CONFIG_NIOS2_KERNEL_REGION_BASE))
+
+#include <asm-generic/memory_model.h>
+
+#include <asm-generic/getorder.h>
+
+#endif /* _ASM_NIOS2_PAGE_H */
diff --git a/arch/nios2/include/asm/pgalloc.h b/arch/nios2/include/asm/pgalloc.h
new file mode 100644
index 0000000..6e2985e
--- /dev/null
+++ b/arch/nios2/include/asm/pgalloc.h
@@ -0,0 +1,86 @@
+/*
+ * 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) 1994 - 2001, 2003 by Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
+ */
+
+#ifndef _ASM_NIOS2_PGALLOC_H
+#define _ASM_NIOS2_PGALLOC_H
+
+#include <linux/mm.h>
+
+static inline void pmd_populate_kernel(struct mm_struct *mm, pmd_t *pmd,
+ pte_t *pte)
+{
+ set_pmd(pmd, __pmd((unsigned long)pte));
+}
+
+static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd,
+ pgtable_t pte)
+{
+ set_pmd(pmd, __pmd((unsigned long)page_address(pte)));
+}
+#define pmd_pgtable(pmd) pmd_page(pmd)
+
+/*
+ * Initialize a new pmd table with invalid pointers.
+ */
+extern void pmd_init(unsigned long page, unsigned long pagetable);
+
+extern pgd_t *pgd_alloc(struct mm_struct *mm);
+
+static inline void pgd_free(struct mm_struct *mm, pgd_t *pgd)
+{
+ free_pages((unsigned long)pgd, PGD_ORDER);
+}
+
+static inline pte_t *pte_alloc_one_kernel(struct mm_struct *mm,
+ unsigned long address)
+{
+ pte_t *pte;
+
+ pte = (pte_t *) __get_free_pages(GFP_KERNEL|__GFP_REPEAT|__GFP_ZERO,
+ PTE_ORDER);
+
+ return pte;
+}
+
+static inline pgtable_t pte_alloc_one(struct mm_struct *mm,
+ unsigned long address)
+{
+ struct page *pte;
+
+ pte = alloc_pages(GFP_KERNEL | __GFP_REPEAT, PTE_ORDER);
+ if (pte) {
+ if (!pgtable_page_ctor(pte)) {
+ __free_page(pte);
+ return NULL;
+ }
+ clear_highpage(pte);
+ }
+ return pte;
+}
+
+static inline void pte_free_kernel(struct mm_struct *mm, pte_t *pte)
+{
+ free_pages((unsigned long)pte, PTE_ORDER);
+}
+
+static inline void pte_free(struct mm_struct *mm, struct page *pte)
+{
+ pgtable_page_dtor(pte);
+ __free_pages(pte, PTE_ORDER);
+}
+
+#define __pte_free_tlb(tlb, pte, addr) \
+ do { \
+ pgtable_page_dtor(pte); \
+ tlb_remove_page((tlb), (pte)); \
+ } while (0)
+
+#define check_pgt_cache() do { } while (0)
+
+#endif /* _ASM_NIOS2_PGALLOC_H */
diff --git a/arch/nios2/include/asm/pgtable-bits.h b/arch/nios2/include/asm/pgtable-bits.h
new file mode 100644
index 0000000..ce9e706
--- /dev/null
+++ b/arch/nios2/include/asm/pgtable-bits.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_PGTABLE_BITS_H
+#define _ASM_NIOS2_PGTABLE_BITS_H
+
+/*
+ * These are actual hardware defined protection bits in the tlbacc register
+ * which looks like this:
+ *
+ * 31 30 ... 26 25 24 23 22 21 20 19 18 ... 1 0
+ * ignored........ C R W X G PFN............
+ */
+#define _PAGE_GLOBAL (1<<20)
+#define _PAGE_EXEC (1<<21)
+#define _PAGE_WRITE (1<<22)
+#define _PAGE_READ (1<<23)
+#define _PAGE_CACHED (1<<24) /* C: data access cacheable */
+
+/*
+ * Software defined bits. They are ignored by the hardware and always read back
+ * as zero, but can be written as non-zero.
+ */
+#define _PAGE_PRESENT (1<<25) /* PTE contains a translation */
+#define _PAGE_ACCESSED (1<<26) /* page referenced */
+#define _PAGE_DIRTY (1<<27) /* dirty page */
+#define _PAGE_FILE (1<<28) /* PTE used for file mapping or swap */
+
+#endif /* _ASM_NIOS2_PGTABLE_BITS_H */
diff --git a/arch/nios2/include/asm/pgtable.h b/arch/nios2/include/asm/pgtable.h
new file mode 100644
index 0000000..ccbaffd
--- /dev/null
+++ b/arch/nios2/include/asm/pgtable.h
@@ -0,0 +1,310 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ *
+ * Based on asm/pgtable-32.h from mips which is:
+ *
+ * Copyright (C) 1994, 95, 96, 97, 98, 99, 2000, 2003 Ralf Baechle
+ * Copyright (C) 1999, 2000, 2001 Silicon Graphics, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_PGTABLE_H
+#define _ASM_NIOS2_PGTABLE_H
+
+#include <linux/io.h>
+#include <linux/bug.h>
+#include <asm/page.h>
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+#include <asm/pgtable-bits.h>
+#include <asm-generic/pgtable-nopmd.h>
+
+#define FIRST_USER_ADDRESS 0
+
+#define VMALLOC_START CONFIG_NIOS2_KERNEL_MMU_REGION_BASE
+#define VMALLOC_END (CONFIG_NIOS2_KERNEL_REGION_BASE - 1)
+
+struct mm_struct;
+
+/* Helper macro */
+#define MKP(x, w, r) __pgprot(_PAGE_PRESENT | _PAGE_CACHED | \
+ ((x) ? _PAGE_EXEC : 0) | \
+ ((r) ? _PAGE_READ : 0) | \
+ ((w) ? _PAGE_WRITE : 0))
+/*
+ * These are the macros that generic kernel code needs
+ * (to populate protection_map[])
+ */
+
+/* Remove W bit on private pages for COW support */
+#define __P000 MKP(0, 0, 0)
+#define __P001 MKP(0, 0, 1)
+#define __P010 MKP(0, 0, 0) /* COW */
+#define __P011 MKP(0, 0, 1) /* COW */
+#define __P100 MKP(1, 0, 0)
+#define __P101 MKP(1, 0, 1)
+#define __P110 MKP(1, 0, 0) /* COW */
+#define __P111 MKP(1, 0, 1) /* COW */
+
+/* Shared pages can have exact HW mapping */
+#define __S000 MKP(0, 0, 0)
+#define __S001 MKP(0, 0, 1)
+#define __S010 MKP(0, 1, 0)
+#define __S011 MKP(0, 1, 1)
+#define __S100 MKP(1, 0, 0)
+#define __S101 MKP(1, 0, 1)
+#define __S110 MKP(1, 1, 0)
+#define __S111 MKP(1, 1, 1)
+
+/* Used all over the kernel */
+#define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_CACHED | _PAGE_READ | \
+ _PAGE_WRITE | _PAGE_EXEC | _PAGE_GLOBAL)
+
+#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_CACHED | _PAGE_READ | \
+ _PAGE_WRITE | _PAGE_ACCESSED)
+
+#define PAGE_COPY MKP(0, 0, 1)
+
+#define PGD_ORDER 0
+#define PTE_ORDER 0
+
+#define PTRS_PER_PGD ((PAGE_SIZE << PGD_ORDER) / sizeof(pgd_t))
+#define PTRS_PER_PTE ((PAGE_SIZE << PTE_ORDER) / sizeof(pte_t))
+
+#define USER_PTRS_PER_PGD \
+ (CONFIG_NIOS2_KERNEL_MMU_REGION_BASE / PGDIR_SIZE)
+
+#define PGDIR_SHIFT 22
+#define PGDIR_SIZE (1UL << PGDIR_SHIFT)
+#define PGDIR_MASK (~(PGDIR_SIZE-1))
+
+/*
+ * ZERO_PAGE is a global shared page that is always zero: used
+ * for zero-mapped memory areas etc..
+ */
+extern unsigned long empty_zero_page[PAGE_SIZE / sizeof(unsigned long)];
+#define ZERO_PAGE(vaddr) (virt_to_page(empty_zero_page))
+
+extern pgd_t swapper_pg_dir[PTRS_PER_PGD];
+extern pte_t invalid_pte_table[PAGE_SIZE/sizeof(pte_t)];
+
+/*
+ * (pmds are folded into puds so this doesn't get actually called,
+ * but the define is needed for a generic inline function.)
+ */
+static inline void set_pmd(pmd_t *pmdptr, pmd_t pmdval)
+{
+ pmdptr->pud.pgd.pgd = pmdval.pud.pgd.pgd;
+}
+
+/* to find an entry in a page-table-directory */
+#define pgd_index(addr) (((addr) >> PGDIR_SHIFT) & (PTRS_PER_PGD - 1))
+#define pgd_offset(mm, addr) ((mm)->pgd + pgd_index(addr))
+
+static inline int pte_write(pte_t pte) \
+ { return pte_val(pte) & _PAGE_WRITE; }
+static inline int pte_dirty(pte_t pte) \
+ { return pte_val(pte) & _PAGE_DIRTY; }
+static inline int pte_young(pte_t pte) \
+ { return pte_val(pte) & _PAGE_ACCESSED; }
+static inline int pte_file(pte_t pte) \
+ { return pte_val(pte) & _PAGE_FILE; }
+static inline int pte_special(pte_t pte) { return 0; }
+
+#define pgprot_noncached pgprot_noncached
+
+static inline pgprot_t pgprot_noncached(pgprot_t _prot)
+{
+ unsigned long prot = pgprot_val(_prot);
+
+ prot &= ~_PAGE_CACHED;
+
+ return __pgprot(prot);
+}
+
+static inline int pte_none(pte_t pte)
+{
+ return !(pte_val(pte) & ~(_PAGE_GLOBAL|0xf));
+}
+
+static inline int pte_present(pte_t pte) \
+ { return pte_val(pte) & _PAGE_PRESENT; }
+
+/*
+ * The following only work if pte_present() is true.
+ * Undefined behaviour if not..
+ */
+static inline pte_t pte_wrprotect(pte_t pte)
+{
+ pte_val(pte) &= ~_PAGE_WRITE;
+ return pte;
+}
+
+static inline pte_t pte_mkclean(pte_t pte)
+{
+ pte_val(pte) &= ~_PAGE_DIRTY;
+ return pte;
+}
+
+static inline pte_t pte_mkold(pte_t pte)
+{
+ pte_val(pte) &= ~_PAGE_ACCESSED;
+ return pte;
+}
+
+static inline pte_t pte_mkwrite(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_WRITE;
+ return pte;
+}
+
+static inline pte_t pte_mkdirty(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_DIRTY;
+ return pte;
+}
+
+static inline pte_t pte_mkspecial(pte_t pte) { return pte; }
+
+static inline pte_t pte_mkyoung(pte_t pte)
+{
+ pte_val(pte) |= _PAGE_ACCESSED;
+ return pte;
+}
+
+static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
+{
+ const unsigned long mask = _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC;
+
+ pte_val(pte) = (pte_val(pte) & ~mask) | (pgprot_val(newprot) & mask);
+ return pte;
+}
+
+static inline int pmd_present(pmd_t pmd)
+{
+ return (pmd_val(pmd) != (unsigned long) invalid_pte_table)
+ && (pmd_val(pmd) != 0UL);
+}
+
+static inline void pmd_clear(pmd_t *pmdp)
+{
+ pmd_val(*pmdp) = (unsigned long) invalid_pte_table;
+}
+
+#define pte_pfn(pte) (pte_val(pte) & 0xfffff)
+#define pfn_pte(pfn, prot) (__pte(pfn | pgprot_val(prot)))
+#define pte_page(pte) (pfn_to_page(pte_pfn(pte)))
+
+/*
+ * Store a linux PTE into the linux page table.
+ */
+static inline void set_pte(pte_t *ptep, pte_t pteval)
+{
+ *ptep = pteval;
+}
+
+static inline void set_pte_at(struct mm_struct *mm, unsigned long addr,
+ pte_t *ptep, pte_t pteval)
+{
+ unsigned long paddr = page_to_virt(pte_page(pteval));
+
+ flush_dcache_range(paddr, paddr + PAGE_SIZE);
+ set_pte(ptep, pteval);
+}
+
+static inline int pmd_none(pmd_t pmd)
+{
+ return (pmd_val(pmd) ==
+ (unsigned long) invalid_pte_table) || (pmd_val(pmd) == 0UL);
+}
+
+#define pmd_bad(pmd) (pmd_val(pmd) & ~PAGE_MASK)
+
+static inline void pte_clear(struct mm_struct *mm,
+ unsigned long addr, pte_t *ptep)
+{
+ pte_t null;
+
+ pte_val(null) = (addr >> PAGE_SHIFT) & 0xf;
+
+ set_pte_at(mm, addr, ptep, null);
+ flush_tlb_one(addr);
+}
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define mk_pte(page, prot) (pfn_pte(page_to_pfn(page), prot))
+
+#define pte_unmap(pte) do { } while (0)
+
+/*
+ * Conversion functions: convert a page and protection to a page entry,
+ * and a page entry and page directory to the page they refer to.
+ */
+#define pmd_phys(pmd) virt_to_phys((void *)pmd_val(pmd))
+#define pmd_page(pmd) (pfn_to_page(pmd_phys(pmd) >> PAGE_SHIFT))
+#define pmd_page_vaddr(pmd) pmd_val(pmd)
+
+#define pte_offset_map(dir, addr) \
+ ((pte_t *) page_address(pmd_page(*dir)) + \
+ (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+
+/* to find an entry in a kernel page-table-directory */
+#define pgd_offset_k(addr) pgd_offset(&init_mm, addr)
+
+/* Get the address to the PTE for a vaddr in specific directory */
+#define pte_offset_kernel(dir, addr) \
+ ((pte_t *) pmd_page_vaddr(*(dir)) + \
+ (((addr) >> PAGE_SHIFT) & (PTRS_PER_PTE - 1)))
+
+#define pte_ERROR(e) \
+ pr_err("%s:%d: bad pte %08lx.\n", \
+ __FILE__, __LINE__, pte_val(e))
+#define pgd_ERROR(e) \
+ pr_err("%s:%d: bad pgd %08lx.\n", \
+ __FILE__, __LINE__, pgd_val(e))
+
+/*
+ * Encode and decode a swap entry (must be !pte_none(pte) && !pte_present(pte)
+ * && !pte_file(pte)):
+ *
+ * 31 30 29 28 27 26 25 24 23 22 21 20 19 18 ... 1 0
+ * 0 0 0 0 type. 0 0 0 0 0 0 offset.........
+ *
+ * This gives us up to 2**2 = 4 swap files and 2**20 * 4K = 4G per swap file.
+ *
+ * Note that the offset field is always non-zero, thus !pte_none(pte) is always
+ * true.
+ */
+#define __swp_type(swp) (((swp).val >> 26) & 0x3)
+#define __swp_offset(swp) ((swp).val & 0xfffff)
+#define __swp_entry(type, off) ((swp_entry_t) { (((type) & 0x3) << 26) \
+ | ((off) & 0xfffff) })
+#define __swp_entry_to_pte(swp) ((pte_t) { (swp).val })
+#define __pte_to_swp_entry(pte) ((swp_entry_t) { pte_val(pte) })
+
+/* Encode and decode a nonlinear file mapping entry */
+#define PTE_FILE_MAX_BITS 25
+#define pte_to_pgoff(pte) (pte_val(pte) & 0x1ffffff)
+#define pgoff_to_pte(off) __pte(((off) & 0x1ffffff) | _PAGE_FILE)
+
+#define kern_addr_valid(addr) (1)
+
+#include <asm-generic/pgtable.h>
+
+#define pgtable_cache_init() do { } while (0)
+
+extern void __init paging_init(void);
+extern void __init mmu_init(void);
+
+extern void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t *pte);
+
+#endif /* _ASM_NIOS2_PGTABLE_H */
diff --git a/arch/nios2/include/asm/processor.h b/arch/nios2/include/asm/processor.h
new file mode 100644
index 0000000..3bd3494
--- /dev/null
+++ b/arch/nios2/include/asm/processor.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ * Copyright (C) 2001 Ken Hill (khill@microtronix.com)
+ * Vic Phillips (vic@microtronix.com)
+ *
+ * based on SPARC asm/processor_32.h which is:
+ *
+ * Copyright (C) 1994 David S. Miller
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_PROCESSOR_H
+#define _ASM_NIOS2_PROCESSOR_H
+
+#include <asm/ptrace.h>
+#include <asm/registers.h>
+#include <asm/page.h>
+
+#define NIOS2_FLAG_KTHREAD 0x00000001 /* task is a kernel thread */
+
+#define NIOS2_OP_NOP 0x1883a
+#define NIOS2_OP_BREAK 0x3da03a
+
+#ifdef __KERNEL__
+
+#define STACK_TOP TASK_SIZE
+#define STACK_TOP_MAX STACK_TOP
+
+#endif /* __KERNEL__ */
+
+/* Kuser helpers is mapped to this user space address */
+#define KUSER_BASE 0x1000
+#define KUSER_SIZE (PAGE_SIZE)
+#ifndef __ASSEMBLY__
+
+/*
+ * Default implementation of macro that returns current
+ * instruction pointer ("program counter").
+ */
+#define current_text_addr() ({ __label__ _l; _l: &&_l; })
+
+# define TASK_SIZE 0x7FFF0000UL
+# define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3))
+
+/* The Nios processor specific thread struct. */
+struct thread_struct {
+ struct pt_regs *kregs;
+
+ /* Context switch saved kernel state. */
+ unsigned long ksp;
+ unsigned long kpsr;
+};
+
+#define INIT_MMAP \
+ { &init_mm, (0), (0), __pgprot(0x0), VM_READ | VM_WRITE | VM_EXEC }
+
+# define INIT_THREAD { \
+ .kregs = NULL, \
+ .ksp = 0, \
+ .kpsr = 0, \
+}
+
+extern void start_thread(struct pt_regs *regs, unsigned long pc,
+ unsigned long sp);
+
+struct task_struct;
+
+/* Free all resources held by a thread. */
+static inline void release_thread(struct task_struct *dead_task)
+{
+}
+
+/* Free current thread data structures etc.. */
+static inline void exit_thread(void)
+{
+}
+
+/* Return saved PC of a blocked thread. */
+#define thread_saved_pc(tsk) ((tsk)->thread.kregs->ea)
+
+extern unsigned long get_wchan(struct task_struct *p);
+
+/* Prepare to copy thread state - unlazy all lazy status */
+#define prepare_to_copy(tsk) do { } while (0)
+
+#define task_pt_regs(p) \
+ ((struct pt_regs *)(THREAD_SIZE + task_stack_page(p)) - 1)
+
+/* Used by procfs */
+#define KSTK_EIP(tsk) ((tsk)->thread.kregs->ea)
+#define KSTK_ESP(tsk) ((tsk)->thread.kregs->sp)
+
+#define cpu_relax() barrier()
+#define cpu_relax_lowlatency() cpu_relax()
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_NIOS2_PROCESSOR_H */
diff --git a/arch/nios2/include/asm/ptrace.h b/arch/nios2/include/asm/ptrace.h
new file mode 100644
index 0000000..20fb1cf
--- /dev/null
+++ b/arch/nios2/include/asm/ptrace.h
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * based on m68k asm/processor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_PTRACE_H
+#define _ASM_NIOS2_PTRACE_H
+
+#include <uapi/asm/ptrace.h>
+
+#ifndef __ASSEMBLY__
+#define user_mode(regs) (((regs)->estatus & ESTATUS_EU))
+
+#define instruction_pointer(regs) ((regs)->ra)
+#define profile_pc(regs) instruction_pointer(regs)
+#define user_stack_pointer(regs) ((regs)->sp)
+extern void show_regs(struct pt_regs *);
+
+#define current_pt_regs() \
+ ((struct pt_regs *)((unsigned long)current_thread_info() + THREAD_SIZE)\
+ - 1)
+
+int do_syscall_trace_enter(void);
+void do_syscall_trace_exit(void);
+#endif /* __ASSEMBLY__ */
+#endif /* _ASM_NIOS2_PTRACE_H */
diff --git a/arch/nios2/include/asm/registers.h b/arch/nios2/include/asm/registers.h
new file mode 100644
index 0000000..615bce1
--- /dev/null
+++ b/arch/nios2/include/asm/registers.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _ASM_NIOS2_REGISTERS_H
+#define _ASM_NIOS2_REGISTERS_H
+
+#ifndef __ASSEMBLY__
+#include <asm/cpuinfo.h>
+#endif
+
+/* control register numbers */
+#define CTL_STATUS 0
+#define CTL_ESTATUS 1
+#define CTL_BSTATUS 2
+#define CTL_IENABLE 3
+#define CTL_IPENDING 4
+#define CTL_CPUID 5
+#define CTL_RSV1 6
+#define CTL_EXCEPTION 7
+#define CTL_PTEADDR 8
+#define CTL_TLBACC 9
+#define CTL_TLBMISC 10
+#define CTL_RSV2 11
+#define CTL_BADADDR 12
+#define CTL_CONFIG 13
+#define CTL_MPUBASE 14
+#define CTL_MPUACC 15
+
+/* access control registers using GCC builtins */
+#define RDCTL(r) __builtin_rdctl(r)
+#define WRCTL(r, v) __builtin_wrctl(r, v)
+
+/* status register bits */
+#define STATUS_PIE (1 << 0) /* processor interrupt enable */
+#define STATUS_U (1 << 1) /* user mode */
+#define STATUS_EH (1 << 2) /* Exception mode */
+
+/* estatus register bits */
+#define ESTATUS_EPIE (1 << 0) /* processor interrupt enable */
+#define ESTATUS_EU (1 << 1) /* user mode */
+#define ESTATUS_EH (1 << 2) /* Exception mode */
+
+/* tlbmisc register bits */
+#define TLBMISC_PID_SHIFT 4
+#ifndef __ASSEMBLY__
+#define TLBMISC_PID_MASK ((1UL << cpuinfo.tlb_pid_num_bits) - 1)
+#endif
+#define TLBMISC_WAY_MASK 0xf
+#define TLBMISC_WAY_SHIFT 20
+
+#define TLBMISC_PID (TLBMISC_PID_MASK << TLBMISC_PID_SHIFT) /* TLB PID */
+#define TLBMISC_WE (1 << 18) /* TLB write enable */
+#define TLBMISC_RD (1 << 19) /* TLB read */
+#define TLBMISC_WAY (TLBMISC_WAY_MASK << TLBMISC_WAY_SHIFT) /* TLB way */
+
+#endif /* _ASM_NIOS2_REGISTERS_H */
diff --git a/arch/nios2/include/asm/setup.h b/arch/nios2/include/asm/setup.h
new file mode 100644
index 0000000..dcbf8cf
--- /dev/null
+++ b/arch/nios2/include/asm/setup.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _ASM_NIOS2_SETUP_H
+#define _ASM_NIOS2_SETUP_H
+
+#include <asm-generic/setup.h>
+
+#ifndef __ASSEMBLY__
+#ifdef __KERNEL__
+
+extern char exception_handler_hook[];
+extern char fast_handler[];
+extern char fast_handler_end[];
+
+extern void pagetable_init(void);
+
+extern void setup_early_printk(void);
+
+#endif/* __KERNEL__ */
+#endif /* __ASSEMBLY__ */
+
+#endif /* _ASM_NIOS2_SETUP_H */
diff --git a/arch/nios2/include/asm/signal.h b/arch/nios2/include/asm/signal.h
new file mode 100644
index 0000000..bbcf11e
--- /dev/null
+++ b/arch/nios2/include/asm/signal.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright Altera Corporation (C) 2013. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef _NIOS2_SIGNAL_H
+#define _NIOS2_SIGNAL_H
+
+#include <uapi/asm/signal.h>
+
+#endif /* _NIOS2_SIGNAL_H */
diff --git a/arch/nios2/include/asm/string.h b/arch/nios2/include/asm/string.h
new file mode 100644
index 0000000..14dd570
--- /dev/null
+++ b/arch/nios2/include/asm/string.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_STRING_H
+#define _ASM_NIOS2_STRING_H
+
+#ifdef __KERNEL__
+
+#define __HAVE_ARCH_MEMSET
+#define __HAVE_ARCH_MEMCPY
+#define __HAVE_ARCH_MEMMOVE
+
+extern void *memset(void *s, int c, size_t count);
+extern void *memcpy(void *d, const void *s, size_t count);
+extern void *memmove(void *d, const void *s, size_t count);
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_NIOS2_STRING_H */
diff --git a/arch/nios2/include/asm/switch_to.h b/arch/nios2/include/asm/switch_to.h
new file mode 100644
index 0000000..c47b3f4
--- /dev/null
+++ b/arch/nios2/include/asm/switch_to.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+#ifndef _ASM_NIOS2_SWITCH_TO_H
+#define _ASM_NIOS2_SWITCH_TO_H
+
+/*
+ * switch_to(n) should switch tasks to task ptr, first checking that
+ * ptr isn't the current task, in which case it does nothing. This
+ * also clears the TS-flag if the task we switched to has used the
+ * math co-processor latest.
+ */
+#define switch_to(prev, next, last) \
+{ \
+ void *_last; \
+ __asm__ __volatile__ ( \
+ "mov r4, %1\n" \
+ "mov r5, %2\n" \
+ "call resume\n" \
+ "mov %0,r4\n" \
+ : "=r" (_last) \
+ : "r" (prev), "r" (next) \
+ : "r4", "r5", "r7", "r8", "ra"); \
+ (last) = _last; \
+}
+
+#endif /* _ASM_NIOS2_SWITCH_TO_H */
diff --git a/arch/nios2/include/asm/syscall.h b/arch/nios2/include/asm/syscall.h
new file mode 100644
index 0000000..9de2208
--- /dev/null
+++ b/arch/nios2/include/asm/syscall.h
@@ -0,0 +1,138 @@
+/*
+ * Copyright Altera Corporation (C) <2014>. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __ASM_NIOS2_SYSCALL_H__
+#define __ASM_NIOS2_SYSCALL_H__
+
+#include <linux/err.h>
+#include <linux/sched.h>
+
+static inline int syscall_get_nr(struct task_struct *task, struct pt_regs *regs)
+{
+ return regs->r2;
+}
+
+static inline void syscall_rollback(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ regs->r2 = regs->orig_r2;
+ regs->r7 = regs->orig_r7;
+}
+
+static inline long syscall_get_error(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->r7 ? regs->r2 : 0;
+}
+
+static inline long syscall_get_return_value(struct task_struct *task,
+ struct pt_regs *regs)
+{
+ return regs->r2;
+}
+
+static inline void syscall_set_return_value(struct task_struct *task,
+ struct pt_regs *regs, int error, long val)
+{
+ if (error) {
+ /* error < 0, but nios2 uses > 0 return value */
+ regs->r2 = -error;
+ regs->r7 = 1;
+ } else {
+ regs->r2 = val;
+ regs->r7 = 0;
+ }
+}
+
+static inline void syscall_get_arguments(struct task_struct *task,
+ struct pt_regs *regs, unsigned int i, unsigned int n,
+ unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+
+ switch (i) {
+ case 0:
+ if (!n--)
+ break;
+ *args++ = regs->r4;
+ case 1:
+ if (!n--)
+ break;
+ *args++ = regs->r5;
+ case 2:
+ if (!n--)
+ break;
+ *args++ = regs->r6;
+ case 3:
+ if (!n--)
+ break;
+ *args++ = regs->r7;
+ case 4:
+ if (!n--)
+ break;
+ *args++ = regs->r8;
+ case 5:
+ if (!n--)
+ break;
+ *args++ = regs->r9;
+ case 6:
+ if (!n--)
+ break;
+ default:
+ BUG();
+ }
+}
+
+static inline void syscall_set_arguments(struct task_struct *task,
+ struct pt_regs *regs, unsigned int i, unsigned int n,
+ const unsigned long *args)
+{
+ BUG_ON(i + n > 6);
+
+ switch (i) {
+ case 0:
+ if (!n--)
+ break;
+ regs->r4 = *args++;
+ case 1:
+ if (!n--)
+ break;
+ regs->r5 = *args++;
+ case 2:
+ if (!n--)
+ break;
+ regs->r6 = *args++;
+ case 3:
+ if (!n--)
+ break;
+ regs->r7 = *args++;
+ case 4:
+ if (!n--)
+ break;
+ regs->r8 = *args++;
+ case 5:
+ if (!n--)
+ break;
+ regs->r9 = *args++;
+ case 6:
+ if (!n)
+ break;
+ default:
+ BUG();
+ }
+}
+
+#endif
diff --git a/arch/nios2/include/asm/syscalls.h b/arch/nios2/include/asm/syscalls.h
new file mode 100644
index 0000000..0245d78
--- /dev/null
+++ b/arch/nios2/include/asm/syscalls.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright Altera Corporation (C) 2013. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef __ASM_NIOS2_SYSCALLS_H
+#define __ASM_NIOS2_SYSCALLS_H
+
+int sys_cacheflush(unsigned long addr, unsigned long len,
+ unsigned int op);
+
+#include <asm-generic/syscalls.h>
+
+#endif /* __ASM_NIOS2_SYSCALLS_H */
diff --git a/arch/nios2/include/asm/thread_info.h b/arch/nios2/include/asm/thread_info.h
new file mode 100644
index 0000000..1f26657
--- /dev/null
+++ b/arch/nios2/include/asm/thread_info.h
@@ -0,0 +1,120 @@
+/*
+ * NiosII low-level thread information
+ *
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * Based on asm/thread_info_no.h from m68k which is:
+ *
+ * Copyright (C) 2002 David Howells <dhowells@redhat.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_THREAD_INFO_H
+#define _ASM_NIOS2_THREAD_INFO_H
+
+#ifdef __KERNEL__
+
+/*
+ * Size of the kernel stack for each process.
+ */
+#define THREAD_SIZE_ORDER 1
+#define THREAD_SIZE 8192 /* 2 * PAGE_SIZE */
+
+#ifndef __ASSEMBLY__
+
+typedef struct {
+ unsigned long seg;
+} mm_segment_t;
+
+/*
+ * low level task data that entry.S needs immediate access to
+ * - this struct should fit entirely inside of one cache line
+ * - this struct shares the supervisor stack pages
+ * - if the contents of this structure are changed, the assembly constants
+ * must also be changed
+ */
+struct thread_info {
+ struct task_struct *task; /* main task structure */
+ struct exec_domain *exec_domain; /* execution domain */
+ unsigned long flags; /* low level flags */
+ __u32 cpu; /* current CPU */
+ int preempt_count; /* 0 => preemptable,<0 => BUG */
+ mm_segment_t addr_limit; /* thread address space:
+ 0-0x7FFFFFFF for user-thead
+ 0-0xFFFFFFFF for kernel-thread
+ */
+ struct restart_block restart_block;
+ struct pt_regs *regs;
+};
+
+/*
+ * macros/functions for gaining access to the thread information structure
+ *
+ * preempt_count needs to be 1 initially, until the scheduler is functional.
+ */
+#define INIT_THREAD_INFO(tsk) \
+{ \
+ .task = &tsk, \
+ .exec_domain = &default_exec_domain, \
+ .flags = 0, \
+ .cpu = 0, \
+ .preempt_count = INIT_PREEMPT_COUNT, \
+ .addr_limit = KERNEL_DS, \
+ .restart_block = { \
+ .fn = do_no_restart_syscall, \
+ }, \
+}
+
+#define init_thread_info (init_thread_union.thread_info)
+#define init_stack (init_thread_union.stack)
+
+/* how to get the thread information struct from C */
+static inline struct thread_info *current_thread_info(void)
+{
+ register unsigned long sp asm("sp");
+
+ return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));
+}
+#endif /* !__ASSEMBLY__ */
+
+/*
+ * thread information flags
+ * - these are process state flags that various assembly files may need to
+ * access
+ * - pending work-to-be-done flags are in LSW
+ * - other flags in MSW
+ */
+#define TIF_SYSCALL_TRACE 0 /* syscall trace active */
+#define TIF_NOTIFY_RESUME 1 /* resumption notification requested */
+#define TIF_SIGPENDING 2 /* signal pending */
+#define TIF_NEED_RESCHED 3 /* rescheduling necessary */
+#define TIF_MEMDIE 4 /* is terminating due to OOM killer */
+#define TIF_SECCOMP 5 /* secure computing */
+#define TIF_SYSCALL_AUDIT 6 /* syscall auditing active */
+#define TIF_RESTORE_SIGMASK 9 /* restore signal mask in do_signal() */
+
+#define TIF_POLLING_NRFLAG 16 /* true if poll_idle() is polling
+ TIF_NEED_RESCHED */
+
+#define _TIF_SYSCALL_TRACE (1 << TIF_SYSCALL_TRACE)
+#define _TIF_NOTIFY_RESUME (1 << TIF_NOTIFY_RESUME)
+#define _TIF_SIGPENDING (1 << TIF_SIGPENDING)
+#define _TIF_NEED_RESCHED (1 << TIF_NEED_RESCHED)
+#define _TIF_SECCOMP (1 << TIF_SECCOMP)
+#define _TIF_SYSCALL_AUDIT (1 << TIF_SYSCALL_AUDIT)
+#define _TIF_RESTORE_SIGMASK (1 << TIF_RESTORE_SIGMASK)
+#define _TIF_POLLING_NRFLAG (1 << TIF_POLLING_NRFLAG)
+
+/* work to do on interrupt/exception return */
+#define _TIF_WORK_MASK 0x0000FFFE
+
+/* work to do on any return to u-space */
+# define _TIF_ALLWORK_MASK 0x0000FFFF
+
+#endif /* __KERNEL__ */
+
+#endif /* _ASM_NIOS2_THREAD_INFO_H */
diff --git a/arch/nios2/include/asm/timex.h b/arch/nios2/include/asm/timex.h
new file mode 100644
index 0000000..2f2abb2
--- /dev/null
+++ b/arch/nios2/include/asm/timex.h
@@ -0,0 +1,24 @@
+/* Copyright Altera Corporation (C) 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * 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 _ASM_NIOS2_TIMEX_H
+#define _ASM_NIOS2_TIMEX_H
+
+typedef unsigned long cycles_t;
+
+extern cycles_t get_cycles(void);
+
+#endif
diff --git a/arch/nios2/include/asm/tlb.h b/arch/nios2/include/asm/tlb.h
new file mode 100644
index 0000000..d3bc648
--- /dev/null
+++ b/arch/nios2/include/asm/tlb.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_TLB_H
+#define _ASM_NIOS2_TLB_H
+
+#define tlb_flush(tlb) flush_tlb_mm((tlb)->mm)
+
+extern void set_mmu_pid(unsigned long pid);
+
+/*
+ * NiosII doesn't need any special per-pte or per-vma handling, except
+ * we need to flush cache for the area to be unmapped.
+ */
+#define tlb_start_vma(tlb, vma) \
+ do { \
+ if (!tlb->fullmm) \
+ flush_cache_range(vma, vma->vm_start, vma->vm_end); \
+ } while (0)
+
+#define tlb_end_vma(tlb, vma) do { } while (0)
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+
+#include <linux/pagemap.h>
+#include <asm-generic/tlb.h>
+
+#endif /* _ASM_NIOS2_TLB_H */
diff --git a/arch/nios2/include/asm/tlbflush.h b/arch/nios2/include/asm/tlbflush.h
new file mode 100644
index 0000000..e19652f
--- /dev/null
+++ b/arch/nios2/include/asm/tlbflush.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#ifndef _ASM_NIOS2_TLBFLUSH_H
+#define _ASM_NIOS2_TLBFLUSH_H
+
+struct mm_struct;
+
+/*
+ * TLB flushing:
+ *
+ * - flush_tlb_all() flushes all processes TLB entries
+ * - flush_tlb_mm(mm) flushes the specified mm context TLB entries
+ * - flush_tlb_page(vma, vmaddr) flushes one page
+ * - flush_tlb_range(vma, start, end) flushes a range of pages
+ * - flush_tlb_kernel_range(start, end) flushes a range of kernel pages
+ */
+extern void flush_tlb_all(void);
+extern void flush_tlb_mm(struct mm_struct *mm);
+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_tlb_one(unsigned long vaddr);
+
+static inline void flush_tlb_page(struct vm_area_struct *vma,
+ unsigned long addr)
+{
+ flush_tlb_one(addr);
+}
+
+#endif /* _ASM_NIOS2_TLBFLUSH_H */
diff --git a/arch/nios2/include/asm/traps.h b/arch/nios2/include/asm/traps.h
new file mode 100644
index 0000000..82a4847
--- /dev/null
+++ b/arch/nios2/include/asm/traps.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_TRAPS_H
+#define _ASM_NIOS2_TRAPS_H
+
+#define TRAP_ID_SYSCALL 0
+
+#ifndef __ASSEMBLY__
+void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr);
+#endif
+
+#endif /* _ASM_NIOS2_TRAPS_H */
diff --git a/arch/nios2/include/asm/uaccess.h b/arch/nios2/include/asm/uaccess.h
new file mode 100644
index 0000000..acedc0a
--- /dev/null
+++ b/arch/nios2/include/asm/uaccess.h
@@ -0,0 +1,231 @@
+/*
+ * User space memory access functions for Nios II
+ *
+ * Copyright (C) 2010-2011, Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009, Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_UACCESS_H
+#define _ASM_NIOS2_UACCESS_H
+
+#include <linux/errno.h>
+#include <linux/thread_info.h>
+#include <linux/string.h>
+
+#include <asm/page.h>
+
+#define VERIFY_READ 0
+#define VERIFY_WRITE 1
+
+/*
+ * The exception table consists of pairs of addresses: the first is the
+ * address of an instruction that is allowed to fault, and the second is
+ * the address at which the program should continue. No registers are
+ * modified, so it is entirely up to the continuation code to figure out
+ * what to do.
+ *
+ * All the routines below use bits of fixup code that are out of line
+ * with the main instruction path. This means when everything is well,
+ * we don't even have to jump over them. Further, they do not intrude
+ * on our cache or tlb entries.
+ */
+struct exception_table_entry {
+ unsigned long insn;
+ unsigned long fixup;
+};
+
+extern int fixup_exception(struct pt_regs *regs);
+
+/*
+ * Segment stuff
+ */
+#define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
+#define USER_DS MAKE_MM_SEG(0x80000000UL)
+#define KERNEL_DS MAKE_MM_SEG(0)
+
+#define get_ds() (KERNEL_DS)
+
+#define get_fs() (current_thread_info()->addr_limit)
+#define set_fs(seg) (current_thread_info()->addr_limit = (seg))
+
+#define segment_eq(a, b) ((a).seg == (b).seg)
+
+#define __access_ok(addr, len) \
+ (((signed long)(((long)get_fs().seg) & \
+ ((long)(addr) | (((long)(addr)) + (len)) | (len)))) == 0)
+
+#define access_ok(type, addr, len) \
+ likely(__access_ok((unsigned long)(addr), (unsigned long)(len)))
+
+# define __EX_TABLE_SECTION ".section __ex_table,\"a\"\n"
+
+/*
+ * Zero Userspace
+ */
+
+static inline unsigned long __must_check __clear_user(void __user *to,
+ unsigned long n)
+{
+ __asm__ __volatile__ (
+ "1: stb zero, 0(%1)\n"
+ " addi %0, %0, -1\n"
+ " addi %1, %1, 1\n"
+ " bne %0, zero, 1b\n"
+ "2:\n"
+ __EX_TABLE_SECTION
+ ".word 1b, 2b\n"
+ ".previous\n"
+ : "=r" (n), "=r" (to)
+ : "0" (n), "1" (to)
+ );
+
+ return n;
+}
+
+static inline unsigned long __must_check clear_user(void __user *to,
+ unsigned long n)
+{
+ if (!access_ok(VERIFY_WRITE, to, n))
+ return n;
+ return __clear_user(to, n);
+}
+
+extern long __copy_from_user(void *to, const void __user *from,
+ unsigned long n);
+extern long __copy_to_user(void __user *to, const void *from, unsigned long n);
+
+static inline long copy_from_user(void *to, const void __user *from,
+ unsigned long n)
+{
+ if (!access_ok(VERIFY_READ, from, n))
+ return n;
+ return __copy_from_user(to, from, n);
+}
+
+static inline long copy_to_user(void __user *to, const void *from,
+ unsigned long n)
+{
+ if (!access_ok(VERIFY_WRITE, to, n))
+ return n;
+ return __copy_to_user(to, from, n);
+}
+
+extern long strncpy_from_user(char *__to, const char __user *__from,
+ long __len);
+extern long strnlen_user(const char __user *s, long n);
+
+#define __copy_from_user_inatomic __copy_from_user
+#define __copy_to_user_inatomic __copy_to_user
+
+/* Optimized macros */
+#define __get_user_asm(val, insn, addr, err) \
+{ \
+ __asm__ __volatile__( \
+ " movi %0, %3\n" \
+ "1: " insn " %1, 0(%2)\n" \
+ " movi %0, 0\n" \
+ "2:\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .word 1b, 2b\n" \
+ " .previous" \
+ : "=&r" (err), "=r" (val) \
+ : "r" (addr), "i" (-EFAULT)); \
+}
+
+#define __get_user_unknown(val, size, ptr, err) do { \
+ err = 0; \
+ if (copy_from_user(&(val), ptr, size)) { \
+ err = -EFAULT; \
+ } \
+ } while (0)
+
+#define __get_user_common(val, size, ptr, err) \
+do { \
+ switch (size) { \
+ case 1: \
+ __get_user_asm(val, "ldbu", ptr, err); \
+ break; \
+ case 2: \
+ __get_user_asm(val, "ldhu", ptr, err); \
+ break; \
+ case 4: \
+ __get_user_asm(val, "ldw", ptr, err); \
+ break; \
+ default: \
+ __get_user_unknown(val, size, ptr, err); \
+ break; \
+ } \
+} while (0)
+
+#define __get_user(x, ptr) \
+ ({ \
+ long __gu_err = -EFAULT; \
+ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
+ unsigned long __gu_val; \
+ __get_user_common(__gu_val, sizeof(*(ptr)), __gu_ptr, __gu_err);\
+ (x) = (__typeof__(x))__gu_val; \
+ __gu_err; \
+ })
+
+#define get_user(x, ptr) \
+({ \
+ long __gu_err = -EFAULT; \
+ const __typeof__(*(ptr)) __user *__gu_ptr = (ptr); \
+ unsigned long __gu_val = 0; \
+ if (access_ok(VERIFY_READ, __gu_ptr, sizeof(*__gu_ptr))) \
+ __get_user_common(__gu_val, sizeof(*__gu_ptr), \
+ __gu_ptr, __gu_err); \
+ (x) = (__typeof__(x))__gu_val; \
+ __gu_err; \
+})
+
+#define __put_user_asm(val, insn, ptr, err) \
+{ \
+ __asm__ __volatile__( \
+ " movi %0, %3\n" \
+ "1: " insn " %1, 0(%2)\n" \
+ " movi %0, 0\n" \
+ "2:\n" \
+ " .section __ex_table,\"a\"\n" \
+ " .word 1b, 2b\n" \
+ " .previous\n" \
+ : "=&r" (err) \
+ : "r" (val), "r" (ptr), "i" (-EFAULT)); \
+}
+
+#define put_user(x, ptr) \
+({ \
+ long __pu_err = -EFAULT; \
+ __typeof__(*(ptr)) __user *__pu_ptr = (ptr); \
+ __typeof__(*(ptr)) __pu_val = (__typeof(*ptr))(x); \
+ if (access_ok(VERIFY_WRITE, __pu_ptr, sizeof(*__pu_ptr))) { \
+ switch (sizeof(*__pu_ptr)) { \
+ case 1: \
+ __put_user_asm(__pu_val, "stb", __pu_ptr, __pu_err); \
+ break; \
+ case 2: \
+ __put_user_asm(__pu_val, "sth", __pu_ptr, __pu_err); \
+ break; \
+ case 4: \
+ __put_user_asm(__pu_val, "stw", __pu_ptr, __pu_err); \
+ break; \
+ default: \
+ /* XXX: This looks wrong... */ \
+ __pu_err = 0; \
+ if (copy_to_user(__pu_ptr, &(__pu_val), \
+ sizeof(*__pu_ptr))) \
+ __pu_err = -EFAULT; \
+ break; \
+ } \
+ } \
+ __pu_err; \
+})
+
+#define __put_user(x, ptr) put_user(x, ptr)
+
+#endif /* _ASM_NIOS2_UACCESS_H */
diff --git a/arch/nios2/include/asm/ucontext.h b/arch/nios2/include/asm/ucontext.h
new file mode 100644
index 0000000..2c87614
--- /dev/null
+++ b/arch/nios2/include/asm/ucontext.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _ASM_NIOS2_UCONTEXT_H
+#define _ASM_NIOS2_UCONTEXT_H
+
+typedef int greg_t;
+#define NGREG 32
+typedef greg_t gregset_t[NGREG];
+
+struct mcontext {
+ int version;
+ gregset_t gregs;
+};
+
+#define MCONTEXT_VERSION 2
+
+struct ucontext {
+ unsigned long uc_flags;
+ struct ucontext *uc_link;
+ stack_t uc_stack;
+ struct mcontext uc_mcontext;
+ sigset_t uc_sigmask; /* mask last for extensibility */
+};
+
+#endif
diff --git a/arch/nios2/include/uapi/asm/Kbuild b/arch/nios2/include/uapi/asm/Kbuild
new file mode 100644
index 0000000..4f07ca3f8
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/Kbuild
@@ -0,0 +1,4 @@
+include include/uapi/asm-generic/Kbuild.asm
+
+header-y += elf.h
+header-y += ucontext.h
diff --git a/arch/nios2/include/uapi/asm/byteorder.h b/arch/nios2/include/uapi/asm/byteorder.h
new file mode 100644
index 0000000..3ab5dc2
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/byteorder.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef _ASM_NIOS2_BYTEORDER_H
+#define _ASM_NIOS2_BYTEORDER_H
+
+#include <linux/byteorder/little_endian.h>
+
+#endif
diff --git a/arch/nios2/include/uapi/asm/elf.h b/arch/nios2/include/uapi/asm/elf.h
new file mode 100644
index 0000000..a5b91ae
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/elf.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+
+#ifndef _UAPI_ASM_NIOS2_ELF_H
+#define _UAPI_ASM_NIOS2_ELF_H
+
+#include <linux/ptrace.h>
+
+/* Relocation types */
+#define R_NIOS2_NONE 0
+#define R_NIOS2_S16 1
+#define R_NIOS2_U16 2
+#define R_NIOS2_PCREL16 3
+#define R_NIOS2_CALL26 4
+#define R_NIOS2_IMM5 5
+#define R_NIOS2_CACHE_OPX 6
+#define R_NIOS2_IMM6 7
+#define R_NIOS2_IMM8 8
+#define R_NIOS2_HI16 9
+#define R_NIOS2_LO16 10
+#define R_NIOS2_HIADJ16 11
+#define R_NIOS2_BFD_RELOC_32 12
+#define R_NIOS2_BFD_RELOC_16 13
+#define R_NIOS2_BFD_RELOC_8 14
+#define R_NIOS2_GPREL 15
+#define R_NIOS2_GNU_VTINHERIT 16
+#define R_NIOS2_GNU_VTENTRY 17
+#define R_NIOS2_UJMP 18
+#define R_NIOS2_CJMP 19
+#define R_NIOS2_CALLR 20
+#define R_NIOS2_ALIGN 21
+/* Keep this the last entry. */
+#define R_NIOS2_NUM 22
+
+typedef unsigned long elf_greg_t;
+
+#define ELF_NGREG \
+ ((sizeof(struct pt_regs) + sizeof(struct switch_stack)) / \
+ sizeof(elf_greg_t))
+typedef elf_greg_t elf_gregset_t[ELF_NGREG];
+
+typedef unsigned long elf_fpregset_t;
+
+/*
+ * These are used to set parameters in the core dumps.
+ */
+#define ELF_CLASS ELFCLASS32
+#define ELF_DATA ELFDATA2LSB
+#define ELF_ARCH EM_ALTERA_NIOS2
+
+#endif /* _UAPI_ASM_NIOS2_ELF_H */
diff --git a/arch/nios2/include/uapi/asm/ptrace.h b/arch/nios2/include/uapi/asm/ptrace.h
new file mode 100644
index 0000000..e83a7c9
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/ptrace.h
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * based on m68k asm/processor.h
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#ifndef _UAPI_ASM_NIOS2_PTRACE_H
+#define _UAPI_ASM_NIOS2_PTRACE_H
+
+#ifndef __ASSEMBLY__
+
+/*
+ * Register numbers used by 'ptrace' system call interface.
+ */
+
+/* GP registers */
+#define PTR_R0 0
+#define PTR_R1 1
+#define PTR_R2 2
+#define PTR_R3 3
+#define PTR_R4 4
+#define PTR_R5 5
+#define PTR_R6 6
+#define PTR_R7 7
+#define PTR_R8 8
+#define PTR_R9 9
+#define PTR_R10 10
+#define PTR_R11 11
+#define PTR_R12 12
+#define PTR_R13 13
+#define PTR_R14 14
+#define PTR_R15 15
+#define PTR_R16 16
+#define PTR_R17 17
+#define PTR_R18 18
+#define PTR_R19 19
+#define PTR_R20 20
+#define PTR_R21 21
+#define PTR_R22 22
+#define PTR_R23 23
+#define PTR_R24 24
+#define PTR_R25 25
+#define PTR_GP 26
+#define PTR_SP 27
+#define PTR_FP 28
+#define PTR_EA 29
+#define PTR_BA 30
+#define PTR_RA 31
+/* Control registers */
+#define PTR_PC 32
+#define PTR_STATUS 33
+#define PTR_ESTATUS 34
+#define PTR_BSTATUS 35
+#define PTR_IENABLE 36
+#define PTR_IPENDING 37
+#define PTR_CPUID 38
+#define PTR_CTL6 39
+#define PTR_CTL7 40
+#define PTR_PTEADDR 41
+#define PTR_TLBACC 42
+#define PTR_TLBMISC 43
+
+#define NUM_PTRACE_REG (PTR_TLBMISC + 1)
+
+/* this struct defines the way the registers are stored on the
+ stack during a system call.
+
+ There is a fake_regs in setup.c that has to match pt_regs.*/
+
+struct pt_regs {
+ unsigned long r8; /* r8-r15 Caller-saved GP registers */
+ unsigned long r9;
+ unsigned long r10;
+ unsigned long r11;
+ unsigned long r12;
+ unsigned long r13;
+ unsigned long r14;
+ unsigned long r15;
+ unsigned long r1; /* Assembler temporary */
+ unsigned long r2; /* Retval LS 32bits */
+ unsigned long r3; /* Retval MS 32bits */
+ unsigned long r4; /* r4-r7 Register arguments */
+ unsigned long r5;
+ unsigned long r6;
+ unsigned long r7;
+ unsigned long orig_r2; /* Copy of r2 ?? */
+ unsigned long ra; /* Return address */
+ unsigned long fp; /* Frame pointer */
+ unsigned long sp; /* Stack pointer */
+ unsigned long gp; /* Global pointer */
+ unsigned long estatus;
+ unsigned long ea; /* Exception return address (pc) */
+ unsigned long orig_r7;
+};
+
+/*
+ * This is the extended stack used by signal handlers and the context
+ * switcher: it's pushed after the normal "struct pt_regs".
+ */
+struct switch_stack {
+ unsigned long r16; /* r16-r23 Callee-saved GP registers */
+ unsigned long r17;
+ unsigned long r18;
+ unsigned long r19;
+ unsigned long r20;
+ unsigned long r21;
+ unsigned long r22;
+ unsigned long r23;
+ unsigned long fp;
+ unsigned long gp;
+ unsigned long ra;
+};
+
+#endif /* __ASSEMBLY__ */
+#endif /* _UAPI_ASM_NIOS2_PTRACE_H */
diff --git a/arch/nios2/include/uapi/asm/sigcontext.h b/arch/nios2/include/uapi/asm/sigcontext.h
new file mode 100644
index 0000000..7b8bb41
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/sigcontext.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2004, Microtronix Datacom 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 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, GOOD TITLE or
+ * NON INFRINGEMENT. See the GNU General Public License for more
+ * details.
+ */
+
+#ifndef _ASM_NIOS2_SIGCONTEXT_H
+#define _ASM_NIOS2_SIGCONTEXT_H
+
+#include <asm/ptrace.h>
+
+struct sigcontext {
+ struct pt_regs regs;
+ unsigned long sc_mask; /* old sigmask */
+};
+
+#endif
diff --git a/arch/nios2/include/uapi/asm/signal.h b/arch/nios2/include/uapi/asm/signal.h
new file mode 100644
index 0000000..f29ee63
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/signal.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright Altera Corporation (C) 2013. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#ifndef _ASM_NIOS2_SIGNAL_H
+#define _ASM_NIOS2_SIGNAL_H
+
+#define SA_RESTORER 0x04000000
+#include <asm-generic/signal.h>
+
+#endif /* _ASM_NIOS2_SIGNAL_H */
diff --git a/arch/nios2/include/uapi/asm/swab.h b/arch/nios2/include/uapi/asm/swab.h
new file mode 100644
index 0000000..b4e22eb
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/swab.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2012 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2011 Pyramid Technical Consultants, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#ifndef _ASM_NIOS2_SWAB_H
+#define _ASM_NIOS2_SWAB_H
+
+#include <linux/types.h>
+#include <asm-generic/swab.h>
+
+#ifdef CONFIG_NIOS2_CI_SWAB_SUPPORT
+#ifdef __GNUC__
+
+#define __nios2_swab(x) \
+ __builtin_custom_ini(CONFIG_NIOS2_CI_SWAB_NO, (x))
+
+static inline __attribute__((const)) __u16 __arch_swab16(__u16 x)
+{
+ return (__u16) __nios2_swab(((__u32) x) << 16);
+}
+#define __arch_swab16 __arch_swab16
+
+static inline __attribute__((const)) __u32 __arch_swab32(__u32 x)
+{
+ return (__u32) __nios2_swab(x);
+}
+#define __arch_swab32 __arch_swab32
+
+#endif /* __GNUC__ */
+#endif /* CONFIG_NIOS2_CI_SWAB_SUPPORT */
+
+#endif /* _ASM_NIOS2_SWAB_H */
diff --git a/arch/nios2/include/uapi/asm/unistd.h b/arch/nios2/include/uapi/asm/unistd.h
new file mode 100644
index 0000000..c4bf795
--- /dev/null
+++ b/arch/nios2/include/uapi/asm/unistd.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+ #define sys_mmap2 sys_mmap_pgoff
+
+/* Use the standard ABI for syscalls */
+#include <asm-generic/unistd.h>
+
+/* Additional Nios II specific syscalls. */
+#define __NR_cacheflush (__NR_arch_specific_syscall)
+__SYSCALL(__NR_cacheflush, sys_cacheflush)
diff --git a/arch/nios2/kernel/Makefile b/arch/nios2/kernel/Makefile
new file mode 100644
index 0000000..8ae7682
--- /dev/null
+++ b/arch/nios2/kernel/Makefile
@@ -0,0 +1,24 @@
+#
+# Makefile for the nios2 linux kernel.
+#
+
+extra-y += head.o
+extra-y += vmlinux.lds
+
+obj-y += cpuinfo.o
+obj-y += entry.o
+obj-y += insnemu.o
+obj-y += irq.o
+obj-y += nios2_ksyms.o
+obj-y += process.o
+obj-y += prom.o
+obj-y += ptrace.o
+obj-y += setup.o
+obj-y += signal.o
+obj-y += sys_nios2.o
+obj-y += syscall_table.o
+obj-y += time.o
+obj-y += traps.o
+
+obj-$(CONFIG_MODULES) += module.o
+obj-$(CONFIG_NIOS2_ALIGNMENT_TRAP) += misaligned.o
diff --git a/arch/nios2/kernel/asm-offsets.c b/arch/nios2/kernel/asm-offsets.c
new file mode 100644
index 0000000..c3ee73c
--- /dev/null
+++ b/arch/nios2/kernel/asm-offsets.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/stddef.h>
+#include <linux/sched.h>
+#include <linux/kernel_stat.h>
+#include <linux/ptrace.h>
+#include <linux/hardirq.h>
+#include <linux/thread_info.h>
+#include <linux/kbuild.h>
+
+int main(void)
+{
+ /* struct task_struct */
+ OFFSET(TASK_THREAD, task_struct, thread);
+ BLANK();
+
+ /* struct thread_struct */
+ OFFSET(THREAD_KSP, thread_struct, ksp);
+ OFFSET(THREAD_KPSR, thread_struct, kpsr);
+ BLANK();
+
+ /* struct pt_regs */
+ OFFSET(PT_ORIG_R2, pt_regs, orig_r2);
+ OFFSET(PT_ORIG_R7, pt_regs, orig_r7);
+
+ OFFSET(PT_R1, pt_regs, r1);
+ OFFSET(PT_R2, pt_regs, r2);
+ OFFSET(PT_R3, pt_regs, r3);
+ OFFSET(PT_R4, pt_regs, r4);
+ OFFSET(PT_R5, pt_regs, r5);
+ OFFSET(PT_R6, pt_regs, r6);
+ OFFSET(PT_R7, pt_regs, r7);
+ OFFSET(PT_R8, pt_regs, r8);
+ OFFSET(PT_R9, pt_regs, r9);
+ OFFSET(PT_R10, pt_regs, r10);
+ OFFSET(PT_R11, pt_regs, r11);
+ OFFSET(PT_R12, pt_regs, r12);
+ OFFSET(PT_R13, pt_regs, r13);
+ OFFSET(PT_R14, pt_regs, r14);
+ OFFSET(PT_R15, pt_regs, r15);
+ OFFSET(PT_EA, pt_regs, ea);
+ OFFSET(PT_RA, pt_regs, ra);
+ OFFSET(PT_FP, pt_regs, fp);
+ OFFSET(PT_SP, pt_regs, sp);
+ OFFSET(PT_GP, pt_regs, gp);
+ OFFSET(PT_ESTATUS, pt_regs, estatus);
+ DEFINE(PT_REGS_SIZE, sizeof(struct pt_regs));
+ BLANK();
+
+ /* struct switch_stack */
+ OFFSET(SW_R16, switch_stack, r16);
+ OFFSET(SW_R17, switch_stack, r17);
+ OFFSET(SW_R18, switch_stack, r18);
+ OFFSET(SW_R19, switch_stack, r19);
+ OFFSET(SW_R20, switch_stack, r20);
+ OFFSET(SW_R21, switch_stack, r21);
+ OFFSET(SW_R22, switch_stack, r22);
+ OFFSET(SW_R23, switch_stack, r23);
+ OFFSET(SW_FP, switch_stack, fp);
+ OFFSET(SW_GP, switch_stack, gp);
+ OFFSET(SW_RA, switch_stack, ra);
+ DEFINE(SWITCH_STACK_SIZE, sizeof(struct switch_stack));
+ BLANK();
+
+ /* struct thread_info */
+ OFFSET(TI_FLAGS, thread_info, flags);
+ OFFSET(TI_PREEMPT_COUNT, thread_info, preempt_count);
+ BLANK();
+
+ return 0;
+}
diff --git a/arch/nios2/kernel/cpuinfo.c b/arch/nios2/kernel/cpuinfo.c
new file mode 100644
index 0000000..51d5bb9
--- /dev/null
+++ b/arch/nios2/kernel/cpuinfo.c
@@ -0,0 +1,197 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * Based on cpuinfo.c from microblaze
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/seq_file.h>
+#include <linux/string.h>
+#include <linux/of.h>
+#include <asm/cpuinfo.h>
+
+struct cpuinfo cpuinfo;
+
+#define err_cpu(x) \
+ pr_err("ERROR: Nios II " x " different for kernel and DTS\n")
+
+static inline u32 fcpu(struct device_node *cpu, const char *n)
+{
+ u32 val = 0;
+
+ of_property_read_u32(cpu, n, &val);
+
+ return val;
+}
+
+static inline u32 fcpu_has(struct device_node *cpu, const char *n)
+{
+ return of_get_property(cpu, n, NULL) ? 1 : 0;
+}
+
+void __init setup_cpuinfo(void)
+{
+ struct device_node *cpu;
+ const char *str;
+ int len;
+
+ cpu = of_find_node_by_type(NULL, "cpu");
+ if (!cpu)
+ panic("%s: No CPU found in devicetree!\n", __func__);
+
+ if (!fcpu_has(cpu, "altr,has-initda"))
+ panic("initda instruction is unimplemented. Please update your "
+ "hardware system to have more than 4-byte line data "
+ "cache\n");
+
+ cpuinfo.cpu_clock_freq = fcpu(cpu, "clock-frequency");
+
+ str = of_get_property(cpu, "altr,implementation", &len);
+ if (str)
+ strlcpy(cpuinfo.cpu_impl, str, sizeof(cpuinfo.cpu_impl));
+ else
+ strcpy(cpuinfo.cpu_impl, "<unknown>");
+
+ cpuinfo.has_div = fcpu_has(cpu, "altr,has-div");
+ cpuinfo.has_mul = fcpu_has(cpu, "altr,has-mul");
+ cpuinfo.has_mulx = fcpu_has(cpu, "altr,has-mulx");
+
+ if (IS_ENABLED(CONFIG_NIOS2_HW_DIV_SUPPORT) && !cpuinfo.has_div)
+ err_cpu("DIV");
+
+ if (IS_ENABLED(CONFIG_NIOS2_HW_MUL_SUPPORT) && !cpuinfo.has_mul)
+ err_cpu("MUL");
+
+ if (IS_ENABLED(CONFIG_NIOS2_HW_MULX_SUPPORT) && !cpuinfo.has_mulx)
+ err_cpu("MULX");
+
+ cpuinfo.tlb_num_ways = fcpu(cpu, "altr,tlb-num-ways");
+ if (!cpuinfo.tlb_num_ways)
+ panic("altr,tlb-num-ways can't be 0. Please check your hardware "
+ "system\n");
+ cpuinfo.icache_line_size = fcpu(cpu, "icache-line-size");
+ cpuinfo.icache_size = fcpu(cpu, "icache-size");
+ if (CONFIG_NIOS2_ICACHE_SIZE != cpuinfo.icache_size)
+ pr_warn("Warning: icache size configuration mismatch "
+ "(0x%x vs 0x%x) of CONFIG_NIOS2_ICACHE_SIZE vs "
+ "device tree icache-size\n",
+ CONFIG_NIOS2_ICACHE_SIZE, cpuinfo.icache_size);
+
+ cpuinfo.dcache_line_size = fcpu(cpu, "dcache-line-size");
+ if (CONFIG_NIOS2_DCACHE_LINE_SIZE != cpuinfo.dcache_line_size)
+ pr_warn("Warning: dcache line size configuration mismatch "
+ "(0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_LINE_SIZE vs "
+ "device tree dcache-line-size\n",
+ CONFIG_NIOS2_DCACHE_LINE_SIZE, cpuinfo.dcache_line_size);
+ cpuinfo.dcache_size = fcpu(cpu, "dcache-size");
+ if (CONFIG_NIOS2_DCACHE_SIZE != cpuinfo.dcache_size)
+ pr_warn("Warning: dcache size configuration mismatch "
+ "(0x%x vs 0x%x) of CONFIG_NIOS2_DCACHE_SIZE vs "
+ "device tree dcache-size\n",
+ CONFIG_NIOS2_DCACHE_SIZE, cpuinfo.dcache_size);
+
+ cpuinfo.tlb_pid_num_bits = fcpu(cpu, "altr,pid-num-bits");
+ cpuinfo.tlb_num_ways_log2 = ilog2(cpuinfo.tlb_num_ways);
+ cpuinfo.tlb_num_entries = fcpu(cpu, "altr,tlb-num-entries");
+ cpuinfo.tlb_num_lines = cpuinfo.tlb_num_entries / cpuinfo.tlb_num_ways;
+ cpuinfo.tlb_ptr_sz = fcpu(cpu, "altr,tlb-ptr-sz");
+
+ cpuinfo.reset_addr = fcpu(cpu, "altr,reset-addr");
+ cpuinfo.exception_addr = fcpu(cpu, "altr,exception-addr");
+ cpuinfo.fast_tlb_miss_exc_addr = fcpu(cpu, "altr,fast-tlb-miss-addr");
+}
+
+#ifdef CONFIG_PROC_FS
+
+/*
+ * Get CPU information for use by the procfs.
+ */
+static int show_cpuinfo(struct seq_file *m, void *v)
+{
+ int count = 0;
+ const u32 clockfreq = cpuinfo.cpu_clock_freq;
+
+ count = seq_printf(m,
+ "CPU:\t\tNios II/%s\n"
+ "MMU:\t\t%s\n"
+ "FPU:\t\tnone\n"
+ "Clocking:\t%u.%02u MHz\n"
+ "BogoMips:\t%lu.%02lu\n"
+ "Calibration:\t%lu loops\n",
+ cpuinfo.cpu_impl,
+ cpuinfo.mmu ? "present" : "none",
+ clockfreq / 1000000, (clockfreq / 100000) % 10,
+ (loops_per_jiffy * HZ) / 500000,
+ ((loops_per_jiffy * HZ) / 5000) % 100,
+ (loops_per_jiffy * HZ));
+
+ count += seq_printf(m,
+ "HW:\n"
+ " MUL:\t\t%s\n"
+ " MULX:\t\t%s\n"
+ " DIV:\t\t%s\n",
+ cpuinfo.has_mul ? "yes" : "no",
+ cpuinfo.has_mulx ? "yes" : "no",
+ cpuinfo.has_div ? "yes" : "no");
+
+ count += seq_printf(m,
+ "Icache:\t\t%ukB, line length: %u\n",
+ cpuinfo.icache_size >> 10,
+ cpuinfo.icache_line_size);
+
+ count += seq_printf(m,
+ "Dcache:\t\t%ukB, line length: %u\n",
+ cpuinfo.dcache_size >> 10,
+ cpuinfo.dcache_line_size);
+
+ count += seq_printf(m,
+ "TLB:\t\t%u ways, %u entries, %u PID bits\n",
+ cpuinfo.tlb_num_ways,
+ cpuinfo.tlb_num_entries,
+ cpuinfo.tlb_pid_num_bits);
+
+ return 0;
+}
+
+static void *cpuinfo_start(struct seq_file *m, loff_t *pos)
+{
+ unsigned long i = *pos;
+
+ return i < num_possible_cpus() ? (void *) (i + 1) : NULL;
+}
+
+static void *cpuinfo_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ ++*pos;
+ return cpuinfo_start(m, pos);
+}
+
+static void cpuinfo_stop(struct seq_file *m, void *v)
+{
+}
+
+const struct seq_operations cpuinfo_op = {
+ .start = cpuinfo_start,
+ .next = cpuinfo_next,
+ .stop = cpuinfo_stop,
+ .show = show_cpuinfo
+};
+
+#endif /* CONFIG_PROC_FS */
diff --git a/arch/nios2/kernel/entry.S b/arch/nios2/kernel/entry.S
new file mode 100644
index 0000000..83bca17
--- /dev/null
+++ b/arch/nios2/kernel/entry.S
@@ -0,0 +1,555 @@
+/*
+ * linux/arch/nios2/kernel/entry.S
+ *
+ * Copyright (C) 2013-2014 Altera Corporation
+ * Copyright (C) 2009, Wind River Systems Inc
+ *
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * Copyright (C) 1999-2002, Greg Ungerer (gerg@snapgear.com)
+ * Copyright (C) 1998 D. Jeff Dionne <jeff@lineo.ca>,
+ * Kenneth Albanowski <kjahds@kjahds.com>,
+ * Copyright (C) 2000 Lineo Inc. (www.lineo.com)
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * 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.
+ *
+ * Linux/m68k support by Hamish Macdonald
+ *
+ * 68060 fixes by Jesper Skov
+ * ColdFire support by Greg Ungerer (gerg@snapgear.com)
+ * 5307 fixes by David W. Miller
+ * linux 2.4 support David McCullough <davidm@snapgear.com>
+ */
+
+#include <linux/sys.h>
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/asm-macros.h>
+#include <asm/thread_info.h>
+#include <asm/errno.h>
+#include <asm/setup.h>
+#include <asm/entry.h>
+#include <asm/unistd.h>
+#include <asm/processor.h>
+
+.macro GET_THREAD_INFO reg
+.if THREAD_SIZE & 0xffff0000
+ andhi \reg, sp, %hi(~(THREAD_SIZE-1))
+.else
+ addi \reg, r0, %lo(~(THREAD_SIZE-1))
+ and \reg, \reg, sp
+.endif
+.endm
+
+.macro kuser_cmpxchg_check
+ /*
+ * Make sure our user space atomic helper is restarted if it was
+ * interrupted in a critical region.
+ * ea-4 = address of interrupted insn (ea must be preserved).
+ * sp = saved regs.
+ * cmpxchg_ldw = first critical insn, cmpxchg_stw = last critical insn.
+ * If ea <= cmpxchg_stw and ea > cmpxchg_ldw then saved EA is set to
+ * cmpxchg_ldw + 4.
+ */
+ /* et = cmpxchg_stw + 4 */
+ movui et, (KUSER_BASE + 4 + (cmpxchg_stw - __kuser_helper_start))
+ bgtu ea, et, 1f
+
+ subi et, et, (cmpxchg_stw - cmpxchg_ldw) /* et = cmpxchg_ldw + 4 */
+ bltu ea, et, 1f
+ stw et, PT_EA(sp) /* fix up EA */
+ mov ea, et
+1:
+.endm
+
+.section .rodata
+.align 4
+exception_table:
+ .word unhandled_exception /* 0 - Reset */
+ .word unhandled_exception /* 1 - Processor-only Reset */
+ .word external_interrupt /* 2 - Interrupt */
+ .word handle_trap /* 3 - Trap Instruction */
+
+ .word instruction_trap /* 4 - Unimplemented instruction */
+ .word handle_illegal /* 5 - Illegal instruction */
+ .word handle_unaligned /* 6 - Misaligned data access */
+ .word handle_unaligned /* 7 - Misaligned destination address */
+
+ .word handle_diverror /* 8 - Division error */
+ .word protection_exception_ba /* 9 - Supervisor-only instr. address */
+ .word protection_exception_instr /* 10 - Supervisor only instruction */
+ .word protection_exception_ba /* 11 - Supervisor only data address */
+
+ .word unhandled_exception /* 12 - Double TLB miss (data) */
+ .word protection_exception_pte /* 13 - TLB permission violation (x) */
+ .word protection_exception_pte /* 14 - TLB permission violation (r) */
+ .word protection_exception_pte /* 15 - TLB permission violation (w) */
+
+ .word unhandled_exception /* 16 - MPU region violation */
+
+trap_table:
+ .word handle_system_call /* 0 */
+ .word instruction_trap /* 1 */
+ .word instruction_trap /* 2 */
+ .word instruction_trap /* 3 */
+ .word instruction_trap /* 4 */
+ .word instruction_trap /* 5 */
+ .word instruction_trap /* 6 */
+ .word instruction_trap /* 7 */
+ .word instruction_trap /* 8 */
+ .word instruction_trap /* 9 */
+ .word instruction_trap /* 10 */
+ .word instruction_trap /* 11 */
+ .word instruction_trap /* 12 */
+ .word instruction_trap /* 13 */
+ .word instruction_trap /* 14 */
+ .word instruction_trap /* 15 */
+ .word instruction_trap /* 16 */
+ .word instruction_trap /* 17 */
+ .word instruction_trap /* 18 */
+ .word instruction_trap /* 19 */
+ .word instruction_trap /* 20 */
+ .word instruction_trap /* 21 */
+ .word instruction_trap /* 22 */
+ .word instruction_trap /* 23 */
+ .word instruction_trap /* 24 */
+ .word instruction_trap /* 25 */
+ .word instruction_trap /* 26 */
+ .word instruction_trap /* 27 */
+ .word instruction_trap /* 28 */
+ .word instruction_trap /* 29 */
+ .word instruction_trap /* 30 */
+ .word handle_breakpoint /* 31 */
+
+.text
+.set noat
+.set nobreak
+
+ENTRY(inthandler)
+ SAVE_ALL
+
+ kuser_cmpxchg_check
+
+ /* Clear EH bit before we get a new excpetion in the kernel
+ * and after we have saved it to the exception frame. This is done
+ * whether it's trap, tlb-miss or interrupt. If we don't do this
+ * estatus is not updated the next exception.
+ */
+ rdctl r24, status
+ movi r9, %lo(~STATUS_EH)
+ and r24, r24, r9
+ wrctl status, r24
+
+ /* Read cause and vector and branch to the associated handler */
+ mov r4, sp
+ rdctl r5, exception
+ movia r9, exception_table
+ add r24, r9, r5
+ ldw r24, 0(r24)
+ jmp r24
+
+
+/***********************************************************************
+ * Handle traps
+ ***********************************************************************
+ */
+ENTRY(handle_trap)
+ ldw r24, -4(ea) /* instruction that caused the exception */
+ srli r24, r24, 4
+ andi r24, r24, 0x7c
+ movia r9,trap_table
+ add r24, r24, r9
+ ldw r24, 0(r24)
+ jmp r24
+
+
+/***********************************************************************
+ * Handle system calls
+ ***********************************************************************
+ */
+ENTRY(handle_system_call)
+ /* Enable interrupts */
+ rdctl r10, status
+ ori r10, r10, STATUS_PIE
+ wrctl status, r10
+
+ /* Reload registers destroyed by common code. */
+ ldw r4, PT_R4(sp)
+ ldw r5, PT_R5(sp)
+
+local_restart:
+ /* Check that the requested system call is within limits */
+ movui r1, __NR_syscalls
+ bgeu r2, r1, ret_invsyscall
+ slli r1, r2, 2
+ movhi r11, %hiadj(sys_call_table)
+ add r1, r1, r11
+ ldw r1, %lo(sys_call_table)(r1)
+ beq r1, r0, ret_invsyscall
+
+ /* Check if we are being traced */
+ GET_THREAD_INFO r11
+ ldw r11,TI_FLAGS(r11)
+ BTBNZ r11,r11,TIF_SYSCALL_TRACE,traced_system_call
+
+ /* Execute the system call */
+ callr r1
+
+ /* If the syscall returns a negative result:
+ * Set r7 to 1 to indicate error,
+ * Negate r2 to get a positive error code
+ * If the syscall returns zero or a positive value:
+ * Set r7 to 0.
+ * The sigreturn system calls will skip the code below by
+ * adding to register ra. To avoid destroying registers
+ */
+translate_rc_and_ret:
+ movi r1, 0
+ bge r2, zero, 3f
+ sub r2, zero, r2
+ movi r1, 1
+3:
+ stw r2, PT_R2(sp)
+ stw r1, PT_R7(sp)
+end_translate_rc_and_ret:
+
+ret_from_exception:
+ ldw r1, PT_ESTATUS(sp)
+ /* if so, skip resched, signals */
+ TSTBNZ r1, r1, ESTATUS_EU, Luser_return
+
+restore_all:
+ rdctl r10, status /* disable intrs */
+ andi r10, r10, %lo(~STATUS_PIE)
+ wrctl status, r10
+ RESTORE_ALL
+ eret
+
+ /* If the syscall number was invalid return ENOSYS */
+ret_invsyscall:
+ movi r2, -ENOSYS
+ br translate_rc_and_ret
+
+ /* This implements the same as above, except it calls
+ * do_syscall_trace_enter and do_syscall_trace_exit before and after the
+ * syscall in order for utilities like strace and gdb to work.
+ */
+traced_system_call:
+ SAVE_SWITCH_STACK
+ call do_syscall_trace_enter
+ RESTORE_SWITCH_STACK
+
+ /* Create system call register arguments. The 5th and 6th
+ arguments on stack are already in place at the beginning
+ of pt_regs. */
+ ldw r2, PT_R2(sp)
+ ldw r4, PT_R4(sp)
+ ldw r5, PT_R5(sp)
+ ldw r6, PT_R6(sp)
+ ldw r7, PT_R7(sp)
+
+ /* Fetch the syscall function, we don't need to check the boundaries
+ * since this is already done.
+ */
+ slli r1, r2, 2
+ movhi r11,%hiadj(sys_call_table)
+ add r1, r1, r11
+ ldw r1, %lo(sys_call_table)(r1)
+
+ callr r1
+
+ /* If the syscall returns a negative result:
+ * Set r7 to 1 to indicate error,
+ * Negate r2 to get a positive error code
+ * If the syscall returns zero or a positive value:
+ * Set r7 to 0.
+ * The sigreturn system calls will skip the code below by
+ * adding to register ra. To avoid destroying registers
+ */
+translate_rc_and_ret2:
+ movi r1, 0
+ bge r2, zero, 4f
+ sub r2, zero, r2
+ movi r1, 1
+4:
+ stw r2, PT_R2(sp)
+ stw r1, PT_R7(sp)
+end_translate_rc_and_ret2:
+ SAVE_SWITCH_STACK
+ call do_syscall_trace_exit
+ RESTORE_SWITCH_STACK
+ br ret_from_exception
+
+Luser_return:
+ GET_THREAD_INFO r11 /* get thread_info pointer */
+ ldw r10, TI_FLAGS(r11) /* get thread_info->flags */
+ ANDI32 r11, r10, _TIF_WORK_MASK
+ beq r11, r0, restore_all /* Nothing to do */
+ BTBZ r1, r10, TIF_NEED_RESCHED, Lsignal_return
+
+ /* Reschedule work */
+ call schedule
+ br ret_from_exception
+
+Lsignal_return:
+ ANDI32 r1, r10, _TIF_SIGPENDING | _TIF_NOTIFY_RESUME
+ beq r1, r0, restore_all
+ mov r4, sp /* pt_regs */
+ SAVE_SWITCH_STACK
+ call do_notify_resume
+ beq r2, r0, no_work_pending
+ RESTORE_SWITCH_STACK
+ /* prepare restart syscall here without leaving kernel */
+ ldw r2, PT_R2(sp) /* reload syscall number in r2 */
+ ldw r4, PT_R4(sp) /* reload syscall arguments r4-r9 */
+ ldw r5, PT_R5(sp)
+ ldw r6, PT_R6(sp)
+ ldw r7, PT_R7(sp)
+ ldw r8, PT_R8(sp)
+ ldw r9, PT_R9(sp)
+ br local_restart /* restart syscall */
+
+no_work_pending:
+ RESTORE_SWITCH_STACK
+ br ret_from_exception
+
+/***********************************************************************
+ * Handle external interrupts.
+ ***********************************************************************
+ */
+/*
+ * This is the generic interrupt handler (for all hardware interrupt
+ * sources). It figures out the vector number and calls the appropriate
+ * interrupt service routine directly.
+ */
+external_interrupt:
+ rdctl r12, ipending
+ rdctl r9, ienable
+ and r12, r12, r9
+ /* skip if no interrupt is pending */
+ beq r12, r0, ret_from_interrupt
+
+ movi r24, -1
+ stw r24, PT_ORIG_R2(sp)
+
+ /*
+ * Process an external hardware interrupt.
+ */
+
+ addi ea, ea, -4 /* re-issue the interrupted instruction */
+ stw ea, PT_EA(sp)
+2: movi r4, %lo(-1) /* Start from bit position 0,
+ highest priority */
+ /* This is the IRQ # for handler call */
+1: andi r10, r12, 1 /* Isolate bit we are interested in */
+ srli r12, r12, 1 /* shift count is costly without hardware
+ multiplier */
+ addi r4, r4, 1
+ beq r10, r0, 1b
+ mov r5, sp /* Setup pt_regs pointer for handler call */
+ call do_IRQ
+ rdctl r12, ipending /* check again if irq still pending */
+ rdctl r9, ienable /* Isolate possible interrupts */
+ and r12, r12, r9
+ bne r12, r0, 2b
+ /* br ret_from_interrupt */ /* fall through to ret_from_interrupt */
+
+ENTRY(ret_from_interrupt)
+ ldw r1, PT_ESTATUS(sp) /* check if returning to kernel */
+ TSTBNZ r1, r1, ESTATUS_EU, Luser_return
+
+#ifdef CONFIG_PREEMPT
+ GET_THREAD_INFO r1
+ ldw r4, TI_PREEMPT_COUNT(r1)
+ bne r4, r0, restore_all
+
+need_resched:
+ ldw r4, TI_FLAGS(r1) /* ? Need resched set */
+ BTBZ r10, r4, TIF_NEED_RESCHED, restore_all
+ ldw r4, PT_ESTATUS(sp) /* ? Interrupts off */
+ andi r10, r4, ESTATUS_EPIE
+ beq r10, r0, restore_all
+ movia r4, PREEMPT_ACTIVE
+ stw r4, TI_PREEMPT_COUNT(r1)
+ rdctl r10, status /* enable intrs again */
+ ori r10, r10 ,STATUS_PIE
+ wrctl status, r10
+ PUSH r1
+ call schedule
+ POP r1
+ mov r4, r0
+ stw r4, TI_PREEMPT_COUNT(r1)
+ rdctl r10, status /* disable intrs */
+ andi r10, r10, %lo(~STATUS_PIE)
+ wrctl status, r10
+ br need_resched
+#else
+ br restore_all
+#endif
+
+/***********************************************************************
+ * A few syscall wrappers
+ ***********************************************************************
+ */
+/*
+ * int clone(unsigned long clone_flags, unsigned long newsp,
+ * int __user * parent_tidptr, int __user * child_tidptr,
+ * int tls_val)
+ */
+ENTRY(sys_clone)
+ SAVE_SWITCH_STACK
+ addi sp, sp, -4
+ stw r7, 0(sp) /* Pass 5th arg thru stack */
+ mov r7, r6 /* 4th arg is 3rd of clone() */
+ mov r6, zero /* 3rd arg always 0 */
+ call do_fork
+ addi sp, sp, 4
+ RESTORE_SWITCH_STACK
+ ret
+
+ENTRY(sys_rt_sigreturn)
+ SAVE_SWITCH_STACK
+ mov r4, sp
+ call do_rt_sigreturn
+ RESTORE_SWITCH_STACK
+ addi ra, ra, (end_translate_rc_and_ret - translate_rc_and_ret)
+ ret
+
+/***********************************************************************
+ * A few other wrappers and stubs
+ ***********************************************************************
+ */
+protection_exception_pte:
+ rdctl r6, pteaddr
+ slli r6, r6, 10
+ call do_page_fault
+ br ret_from_exception
+
+protection_exception_ba:
+ rdctl r6, badaddr
+ call do_page_fault
+ br ret_from_exception
+
+protection_exception_instr:
+ call handle_supervisor_instr
+ br ret_from_exception
+
+handle_breakpoint:
+ call breakpoint_c
+ br ret_from_exception
+
+#ifdef CONFIG_NIOS2_ALIGNMENT_TRAP
+handle_unaligned:
+ SAVE_SWITCH_STACK
+ call handle_unaligned_c
+ RESTORE_SWITCH_STACK
+ br ret_from_exception
+#else
+handle_unaligned:
+ call handle_unaligned_c
+ br ret_from_exception
+#endif
+
+handle_illegal:
+ call handle_illegal_c
+ br ret_from_exception
+
+handle_diverror:
+ call handle_diverror_c
+ br ret_from_exception
+
+/*
+ * Beware - when entering resume, prev (the current task) is
+ * in r4, next (the new task) is in r5, don't change these
+ * registers.
+ */
+ENTRY(resume)
+
+ rdctl r7, status /* save thread status reg */
+ stw r7, TASK_THREAD + THREAD_KPSR(r4)
+
+ andi r7, r7, %lo(~STATUS_PIE) /* disable interrupts */
+ wrctl status, r7
+
+ SAVE_SWITCH_STACK
+ stw sp, TASK_THREAD + THREAD_KSP(r4)/* save kernel stack pointer */
+ ldw sp, TASK_THREAD + THREAD_KSP(r5)/* restore new thread stack */
+ movia r24, _current_thread /* save thread */
+ GET_THREAD_INFO r1
+ stw r1, 0(r24)
+ RESTORE_SWITCH_STACK
+
+ ldw r7, TASK_THREAD + THREAD_KPSR(r5)/* restore thread status reg */
+ wrctl status, r7
+ ret
+
+ENTRY(ret_from_fork)
+ call schedule_tail
+ br ret_from_exception
+
+ENTRY(ret_from_kernel_thread)
+ call schedule_tail
+ mov r4,r17 /* arg */
+ callr r16 /* function */
+ br ret_from_exception
+
+/*
+ * Kernel user helpers.
+ *
+ * Each segment is 64-byte aligned and will be mapped to the <User space>.
+ * New segments (if ever needed) must be added after the existing ones.
+ * This mechanism should be used only for things that are really small and
+ * justified, and not be abused freely.
+ *
+ */
+
+ /* Filling pads with undefined instructions. */
+.macro kuser_pad sym size
+ .if ((. - \sym) & 3)
+ .rept (4 - (. - \sym) & 3)
+ .byte 0
+ .endr
+ .endif
+ .rept ((\size - (. - \sym)) / 4)
+ .word 0xdeadbeef
+ .endr
+.endm
+
+ .align 6
+ .globl __kuser_helper_start
+__kuser_helper_start:
+
+__kuser_helper_version: /* @ 0x1000 */
+ .word ((__kuser_helper_end - __kuser_helper_start) >> 6)
+
+__kuser_cmpxchg: /* @ 0x1004 */
+ /*
+ * r4 pointer to exchange variable
+ * r5 old value
+ * r6 new value
+ */
+cmpxchg_ldw:
+ ldw r2, 0(r4) /* load current value */
+ sub r2, r2, r5 /* compare with old value */
+ bne r2, zero, cmpxchg_ret
+
+ /* We had a match, store the new value */
+cmpxchg_stw:
+ stw r6, 0(r4)
+cmpxchg_ret:
+ ret
+
+ kuser_pad __kuser_cmpxchg, 64
+
+ .globl __kuser_sigtramp
+__kuser_sigtramp:
+ movi r2, __NR_rt_sigreturn
+ trap
+
+ kuser_pad __kuser_sigtramp, 64
+
+ .globl __kuser_helper_end
+__kuser_helper_end:
diff --git a/arch/nios2/kernel/head.S b/arch/nios2/kernel/head.S
new file mode 100644
index 0000000..372ce4a
--- /dev/null
+++ b/arch/nios2/kernel/head.S
@@ -0,0 +1,175 @@
+/*
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ * Copyright (C) 2001 Vic Phillips, Microtronix Datacom Ltd.
+ *
+ * Based on head.S for Altera's Excalibur development board with nios processor
+ *
+ * Based on the following from the Excalibur sdk distribution:
+ * NA_MemoryMap.s, NR_JumpToStart.s, NR_Setup.s, NR_CWPManager.s
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <asm/thread_info.h>
+#include <asm/processor.h>
+#include <asm/cache.h>
+#include <asm/page.h>
+#include <asm/asm-offsets.h>
+#include <asm/asm-macros.h>
+
+/*
+ * ZERO_PAGE is a special page that is used for zero-initialized
+ * data and COW.
+ */
+.data
+.global empty_zero_page
+.align 12
+empty_zero_page:
+ .space PAGE_SIZE
+
+/*
+ * This global variable is used as an extension to the nios'
+ * STATUS register to emulate a user/supervisor mode.
+ */
+ .data
+ .align 2
+ .set noat
+
+ .global _current_thread
+_current_thread:
+ .long 0
+/*
+ * Input(s): passed from u-boot
+ * r4 - Optional pointer to a board information structure.
+ * r5 - Optional pointer to the physical starting address of the init RAM
+ * disk.
+ * r6 - Optional pointer to the physical ending address of the init RAM
+ * disk.
+ * r7 - Optional pointer to the physical starting address of any kernel
+ * command-line parameters.
+ */
+
+/*
+ * First executable code - detected and jumped to by the ROM bootstrap
+ * if the code resides in flash (looks for "Nios" at offset 0x0c from
+ * the potential executable image).
+ */
+ __HEAD
+ENTRY(_start)
+ wrctl status, r0 /* Disable interrupts */
+
+ /* Initialize all cache lines within the instruction cache */
+ movia r1, NIOS2_ICACHE_SIZE
+ movui r2, NIOS2_ICACHE_LINE_SIZE
+
+icache_init:
+ initi r1
+ sub r1, r1, r2
+ bgt r1, r0, icache_init
+ br 1f
+
+ /*
+ * This is the default location for the exception handler. Code in jump
+ * to our handler
+ */
+ENTRY(exception_handler_hook)
+ movia r24, inthandler
+ jmp r24
+
+ENTRY(fast_handler)
+ nextpc et
+helper:
+ stw r3, r3save - helper(et)
+
+ rdctl r3 , pteaddr
+ srli r3, r3, 12
+ slli r3, r3, 2
+ movia et, pgd_current
+
+ ldw et, 0(et)
+ add r3, et, r3
+ ldw et, 0(r3)
+
+ rdctl r3, pteaddr
+ andi r3, r3, 0xfff
+ add et, r3, et
+ ldw et, 0(et)
+ wrctl tlbacc, et
+ nextpc et
+helper2:
+ ldw r3, r3save - helper2(et)
+ subi ea, ea, 4
+ eret
+r3save:
+ .word 0x0
+ENTRY(fast_handler_end)
+
+1:
+ /*
+ * After the instruction cache is initialized, the data cache must
+ * also be initialized.
+ */
+ movia r1, NIOS2_DCACHE_SIZE
+ movui r2, NIOS2_DCACHE_LINE_SIZE
+
+dcache_init:
+ initd 0(r1)
+ sub r1, r1, r2
+ bgt r1, r0, dcache_init
+
+ nextpc r1 /* Find out where we are */
+chkadr:
+ movia r2, chkadr
+ beq r1, r2,finish_move /* We are running in RAM done */
+ addi r1, r1,(_start - chkadr) /* Source */
+ movia r2, _start /* Destination */
+ movia r3, __bss_start /* End of copy */
+
+loop_move: /* r1: src, r2: dest, r3: last dest */
+ ldw r8, 0(r1) /* load a word from [r1] */
+ stw r8, 0(r2) /* store a word to dest [r2] */
+ flushd 0(r2) /* Flush cache for safety */
+ addi r1, r1, 4 /* inc the src addr */
+ addi r2, r2, 4 /* inc the dest addr */
+ blt r2, r3, loop_move
+
+ movia r1, finish_move /* VMA(_start)->l1 */
+ jmp r1 /* jmp to _start */
+
+finish_move:
+
+ /* Mask off all possible interrupts */
+ wrctl ienable, r0
+
+ /* Clear .bss */
+ movia r2, __bss_start
+ movia r1, __bss_stop
+1:
+ stb r0, 0(r2)
+ addi r2, r2, 1
+ bne r1, r2, 1b
+
+ movia r1, init_thread_union /* set stack at top of the task union */
+ addi sp, r1, THREAD_SIZE
+ movia r2, _current_thread /* Remember current thread */
+ stw r1, 0(r2)
+
+ movia r1, nios2_boot_init /* save args r4-r7 passed from u-boot */
+ callr r1
+
+ movia r1, start_kernel /* call start_kernel as a subroutine */
+ callr r1
+
+ /* If we return from start_kernel, break to the oci debugger and
+ * buggered we are.
+ */
+ break
+
+ /* End of startup code */
+.set at
diff --git a/arch/nios2/kernel/insnemu.S b/arch/nios2/kernel/insnemu.S
new file mode 100644
index 0000000..1c6b651
--- /dev/null
+++ b/arch/nios2/kernel/insnemu.S
@@ -0,0 +1,592 @@
+/*
+ * Copyright (C) 2003-2013 Altera Corporation
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+
+#include <linux/linkage.h>
+#include <asm/entry.h>
+
+.set noat
+.set nobreak
+
+/*
+* Explicitly allow the use of r1 (the assembler temporary register)
+* within this code. This register is normally reserved for the use of
+* the compiler.
+*/
+
+ENTRY(instruction_trap)
+ ldw r1, PT_R1(sp) // Restore registers
+ ldw r2, PT_R2(sp)
+ ldw r3, PT_R3(sp)
+ ldw r4, PT_R4(sp)
+ ldw r5, PT_R5(sp)
+ ldw r6, PT_R6(sp)
+ ldw r7, PT_R7(sp)
+ ldw r8, PT_R8(sp)
+ ldw r9, PT_R9(sp)
+ ldw r10, PT_R10(sp)
+ ldw r11, PT_R11(sp)
+ ldw r12, PT_R12(sp)
+ ldw r13, PT_R13(sp)
+ ldw r14, PT_R14(sp)
+ ldw r15, PT_R15(sp)
+ ldw ra, PT_RA(sp)
+ ldw fp, PT_FP(sp)
+ ldw gp, PT_GP(sp)
+ ldw et, PT_ESTATUS(sp)
+ wrctl estatus, et
+ ldw ea, PT_EA(sp)
+ ldw et, PT_SP(sp) /* backup sp in et */
+
+ addi sp, sp, PT_REGS_SIZE
+
+ /* INSTRUCTION EMULATION
+ * ---------------------
+ *
+ * Nios II processors generate exceptions for unimplemented instructions.
+ * The routines below emulate these instructions. Depending on the
+ * processor core, the only instructions that might need to be emulated
+ * are div, divu, mul, muli, mulxss, mulxsu, and mulxuu.
+ *
+ * The emulations match the instructions, except for the following
+ * limitations:
+ *
+ * 1) The emulation routines do not emulate the use of the exception
+ * temporary register (et) as a source operand because the exception
+ * handler already has modified it.
+ *
+ * 2) The routines do not emulate the use of the stack pointer (sp) or
+ * the exception return address register (ea) as a destination because
+ * modifying these registers crashes the exception handler or the
+ * interrupted routine.
+ *
+ * Detailed Design
+ * ---------------
+ *
+ * The emulation routines expect the contents of integer registers r0-r31
+ * to be on the stack at addresses sp, 4(sp), 8(sp), ... 124(sp). The
+ * routines retrieve source operands from the stack and modify the
+ * destination register's value on the stack prior to the end of the
+ * exception handler. Then all registers except the destination register
+ * are restored to their previous values.
+ *
+ * The instruction that causes the exception is found at address -4(ea).
+ * The instruction's OP and OPX fields identify the operation to be
+ * performed.
+ *
+ * One instruction, muli, is an I-type instruction that is identified by
+ * an OP field of 0x24.
+ *
+ * muli AAAAA,BBBBB,IIIIIIIIIIIIIIII,-0x24-
+ * 27 22 6 0 <-- LSB of field
+ *
+ * The remaining emulated instructions are R-type and have an OP field
+ * of 0x3a. Their OPX fields identify them.
+ *
+ * R-type AAAAA,BBBBB,CCCCC,XXXXXX,NNNNN,-0x3a-
+ * 27 22 17 11 6 0 <-- LSB of field
+ *
+ *
+ * Opcode Encoding. muli is identified by its OP value. Then OPX & 0x02
+ * is used to differentiate between the division opcodes and the
+ * remaining multiplication opcodes.
+ *
+ * Instruction OP OPX OPX & 0x02
+ * ----------- ---- ---- ----------
+ * muli 0x24
+ * divu 0x3a 0x24 0
+ * div 0x3a 0x25 0
+ * mul 0x3a 0x27 != 0
+ * mulxuu 0x3a 0x07 != 0
+ * mulxsu 0x3a 0x17 != 0
+ * mulxss 0x3a 0x1f != 0
+ */
+
+
+ /*
+ * Save everything on the stack to make it easy for the emulation
+ * routines to retrieve the source register operands.
+ */
+
+ addi sp, sp, -128
+ stw zero, 0(sp) /* Save zero on stack to avoid special case for r0. */
+ stw r1, 4(sp)
+ stw r2, 8(sp)
+ stw r3, 12(sp)
+ stw r4, 16(sp)
+ stw r5, 20(sp)
+ stw r6, 24(sp)
+ stw r7, 28(sp)
+ stw r8, 32(sp)
+ stw r9, 36(sp)
+ stw r10, 40(sp)
+ stw r11, 44(sp)
+ stw r12, 48(sp)
+ stw r13, 52(sp)
+ stw r14, 56(sp)
+ stw r15, 60(sp)
+ stw r16, 64(sp)
+ stw r17, 68(sp)
+ stw r18, 72(sp)
+ stw r19, 76(sp)
+ stw r20, 80(sp)
+ stw r21, 84(sp)
+ stw r22, 88(sp)
+ stw r23, 92(sp)
+ /* Don't bother to save et. It's already been changed. */
+ rdctl r5, estatus
+ stw r5, 100(sp)
+
+ stw gp, 104(sp)
+ stw et, 108(sp) /* et contains previous sp value. */
+ stw fp, 112(sp)
+ stw ea, 116(sp)
+ stw ra, 120(sp)
+
+
+ /*
+ * Split the instruction into its fields. We need 4*A, 4*B, and 4*C as
+ * offsets to the stack pointer for access to the stored register values.
+ */
+ ldw r2,-4(ea) /* r2 = AAAAA,BBBBB,IIIIIIIIIIIIIIII,PPPPPP */
+ roli r3, r2, 7 /* r3 = BBB,IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BB */
+ roli r4, r3, 3 /* r4 = IIIIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB */
+ roli r5, r4, 2 /* r5 = IIIIIIIIIIIIII,PPPPPP,AAAAA,BBBBB,II */
+ srai r4, r4, 16 /* r4 = (sign-extended) IMM16 */
+ roli r6, r5, 5 /* r6 = XXXX,NNNNN,PPPPPP,AAAAA,BBBBB,CCCCC,XX */
+ andi r2, r2, 0x3f /* r2 = 00000000000000000000000000,PPPPPP */
+ andi r3, r3, 0x7c /* r3 = 0000000000000000000000000,AAAAA,00 */
+ andi r5, r5, 0x7c /* r5 = 0000000000000000000000000,BBBBB,00 */
+ andi r6, r6, 0x7c /* r6 = 0000000000000000000000000,CCCCC,00 */
+
+ /* Now
+ * r2 = OP
+ * r3 = 4*A
+ * r4 = IMM16 (sign extended)
+ * r5 = 4*B
+ * r6 = 4*C
+ */
+
+ /*
+ * Get the operands.
+ *
+ * It is necessary to check for muli because it uses an I-type
+ * instruction format, while the other instructions are have an R-type
+ * format.
+ *
+ * Prepare for either multiplication or division loop.
+ * They both loop 32 times.
+ */
+ movi r14, 32
+
+ add r3, r3, sp /* r3 = address of A-operand. */
+ ldw r3, 0(r3) /* r3 = A-operand. */
+ movi r7, 0x24 /* muli opcode (I-type instruction format) */
+ beq r2, r7, mul_immed /* muli doesn't use the B register as a source */
+
+ add r5, r5, sp /* r5 = address of B-operand. */
+ ldw r5, 0(r5) /* r5 = B-operand. */
+ /* r4 = SSSSSSSSSSSSSSSS,-----IMM16------ */
+ /* IMM16 not needed, align OPX portion */
+ /* r4 = SSSSSSSSSSSSSSSS,CCCCC,-OPX--,00000 */
+ srli r4, r4, 5 /* r4 = 00000,SSSSSSSSSSSSSSSS,CCCCC,-OPX-- */
+ andi r4, r4, 0x3f /* r4 = 00000000000000000000000000,-OPX-- */
+
+ /* Now
+ * r2 = OP
+ * r3 = src1
+ * r5 = src2
+ * r4 = OPX (no longer can be muli)
+ * r6 = 4*C
+ */
+
+
+ /*
+ * Multiply or Divide?
+ */
+ andi r7, r4, 0x02 /* For R-type multiply instructions,
+ OPX & 0x02 != 0 */
+ bne r7, zero, multiply
+
+
+ /* DIVISION
+ *
+ * Divide an unsigned dividend by an unsigned divisor using
+ * a shift-and-subtract algorithm. The example below shows
+ * 43 div 7 = 6 for 8-bit integers. This classic algorithm uses a
+ * single register to store both the dividend and the quotient,
+ * allowing both values to be shifted with a single instruction.
+ *
+ * remainder dividend:quotient
+ * --------- -----------------
+ * initialize 00000000 00101011:
+ * shift 00000000 0101011:_
+ * remainder >= divisor? no 00000000 0101011:0
+ * shift 00000000 101011:0_
+ * remainder >= divisor? no 00000000 101011:00
+ * shift 00000001 01011:00_
+ * remainder >= divisor? no 00000001 01011:000
+ * shift 00000010 1011:000_
+ * remainder >= divisor? no 00000010 1011:0000
+ * shift 00000101 011:0000_
+ * remainder >= divisor? no 00000101 011:00000
+ * shift 00001010 11:00000_
+ * remainder >= divisor? yes 00001010 11:000001
+ * remainder -= divisor - 00000111
+ * ----------
+ * 00000011 11:000001
+ * shift 00000111 1:000001_
+ * remainder >= divisor? yes 00000111 1:0000011
+ * remainder -= divisor - 00000111
+ * ----------
+ * 00000000 1:0000011
+ * shift 00000001 :0000011_
+ * remainder >= divisor? no 00000001 :00000110
+ *
+ * The quotient is 00000110.
+ */
+
+divide:
+ /*
+ * Prepare for division by assuming the result
+ * is unsigned, and storing its "sign" as 0.
+ */
+ movi r17, 0
+
+
+ /* Which division opcode? */
+ xori r7, r4, 0x25 /* OPX of div */
+ bne r7, zero, unsigned_division
+
+
+ /*
+ * OPX is div. Determine and store the sign of the quotient.
+ * Then take the absolute value of both operands.
+ */
+ xor r17, r3, r5 /* MSB contains sign of quotient */
+ bge r3,zero,dividend_is_nonnegative
+ sub r3, zero, r3 /* -r3 */
+dividend_is_nonnegative:
+ bge r5, zero, divisor_is_nonnegative
+ sub r5, zero, r5 /* -r5 */
+divisor_is_nonnegative:
+
+
+unsigned_division:
+ /* Initialize the unsigned-division loop. */
+ movi r13, 0 /* remainder = 0 */
+
+ /* Now
+ * r3 = dividend : quotient
+ * r4 = 0x25 for div, 0x24 for divu
+ * r5 = divisor
+ * r13 = remainder
+ * r14 = loop counter (already initialized to 32)
+ * r17 = MSB contains sign of quotient
+ */
+
+
+ /*
+ * for (count = 32; count > 0; --count)
+ * {
+ */
+divide_loop:
+
+ /*
+ * Division:
+ *
+ * (remainder:dividend:quotient) <<= 1;
+ */
+ slli r13, r13, 1
+ cmplt r7, r3, zero /* r7 = MSB of r3 */
+ or r13, r13, r7
+ slli r3, r3, 1
+
+
+ /*
+ * if (remainder >= divisor)
+ * {
+ * set LSB of quotient
+ * remainder -= divisor;
+ * }
+ */
+ bltu r13, r5, div_skip
+ ori r3, r3, 1
+ sub r13, r13, r5
+div_skip:
+
+ /*
+ * }
+ */
+ subi r14, r14, 1
+ bne r14, zero, divide_loop
+
+
+ /* Now
+ * r3 = quotient
+ * r4 = 0x25 for div, 0x24 for divu
+ * r6 = 4*C
+ * r17 = MSB contains sign of quotient
+ */
+
+
+ /*
+ * Conditionally negate signed quotient. If quotient is unsigned,
+ * the sign already is initialized to 0.
+ */
+ bge r17, zero, quotient_is_nonnegative
+ sub r3, zero, r3 /* -r3 */
+ quotient_is_nonnegative:
+
+
+ /*
+ * Final quotient is in r3.
+ */
+ add r6, r6, sp
+ stw r3, 0(r6) /* write quotient to stack */
+ br restore_registers
+
+
+
+
+ /* MULTIPLICATION
+ *
+ * A "product" is the number that one gets by summing a "multiplicand"
+ * several times. The "multiplier" specifies the number of copies of the
+ * multiplicand that are summed.
+ *
+ * Actual multiplication algorithms don't use repeated addition, however.
+ * Shift-and-add algorithms get the same answer as repeated addition, and
+ * they are faster. To compute the lower half of a product (pppp below)
+ * one shifts the product left before adding in each of the partial
+ * products (a * mmmm) through (d * mmmm).
+ *
+ * To compute the upper half of a product (PPPP below), one adds in the
+ * partial products (d * mmmm) through (a * mmmm), each time following
+ * the add by a right shift of the product.
+ *
+ * mmmm
+ * * abcd
+ * ------
+ * #### = d * mmmm
+ * #### = c * mmmm
+ * #### = b * mmmm
+ * #### = a * mmmm
+ * --------
+ * PPPPpppp
+ *
+ * The example above shows 4 partial products. Computing actual Nios II
+ * products requires 32 partials.
+ *
+ * It is possible to compute the result of mulxsu from the result of
+ * mulxuu because the only difference between the results of these two
+ * opcodes is the value of the partial product associated with the sign
+ * bit of rA.
+ *
+ * mulxsu = mulxuu - (rA < 0) ? rB : 0;
+ *
+ * It is possible to compute the result of mulxss from the result of
+ * mulxsu because the only difference between the results of these two
+ * opcodes is the value of the partial product associated with the sign
+ * bit of rB.
+ *
+ * mulxss = mulxsu - (rB < 0) ? rA : 0;
+ *
+ */
+
+mul_immed:
+ /* Opcode is muli. Change it into mul for remainder of algorithm. */
+ mov r6, r5 /* Field B is dest register, not field C. */
+ mov r5, r4 /* Field IMM16 is src2, not field B. */
+ movi r4, 0x27 /* OPX of mul is 0x27 */
+
+multiply:
+ /* Initialize the multiplication loop. */
+ movi r9, 0 /* mul_product = 0 */
+ movi r10, 0 /* mulxuu_product = 0 */
+ mov r11, r5 /* save original multiplier for mulxsu and mulxss */
+ mov r12, r5 /* mulxuu_multiplier (will be shifted) */
+ movi r16, 1 /* used to create "rori B,A,1" from "ror B,A,r16" */
+
+ /* Now
+ * r3 = multiplicand
+ * r5 = mul_multiplier
+ * r6 = 4 * dest_register (used later as offset to sp)
+ * r7 = temp
+ * r9 = mul_product
+ * r10 = mulxuu_product
+ * r11 = original multiplier
+ * r12 = mulxuu_multiplier
+ * r14 = loop counter (already initialized)
+ * r16 = 1
+ */
+
+
+ /*
+ * for (count = 32; count > 0; --count)
+ * {
+ */
+multiply_loop:
+
+ /*
+ * mul_product <<= 1;
+ * lsb = multiplier & 1;
+ */
+ slli r9, r9, 1
+ andi r7, r12, 1
+
+ /*
+ * if (lsb == 1)
+ * {
+ * mulxuu_product += multiplicand;
+ * }
+ */
+ beq r7, zero, mulx_skip
+ add r10, r10, r3
+ cmpltu r7, r10, r3 /* Save the carry from the MSB of mulxuu_product. */
+ ror r7, r7, r16 /* r7 = 0x80000000 on carry, or else 0x00000000 */
+mulx_skip:
+
+ /*
+ * if (MSB of mul_multiplier == 1)
+ * {
+ * mul_product += multiplicand;
+ * }
+ */
+ bge r5, zero, mul_skip
+ add r9, r9, r3
+mul_skip:
+
+ /*
+ * mulxuu_product >>= 1; logical shift
+ * mul_multiplier <<= 1; done with MSB
+ * mulx_multiplier >>= 1; done with LSB
+ */
+ srli r10, r10, 1
+ or r10, r10, r7 /* OR in the saved carry bit. */
+ slli r5, r5, 1
+ srli r12, r12, 1
+
+
+ /*
+ * }
+ */
+ subi r14, r14, 1
+ bne r14, zero, multiply_loop
+
+
+ /*
+ * Multiply emulation loop done.
+ */
+
+ /* Now
+ * r3 = multiplicand
+ * r4 = OPX
+ * r6 = 4 * dest_register (used later as offset to sp)
+ * r7 = temp
+ * r9 = mul_product
+ * r10 = mulxuu_product
+ * r11 = original multiplier
+ */
+
+
+ /* Calculate address for result from 4 * dest_register */
+ add r6, r6, sp
+
+
+ /*
+ * Select/compute the result based on OPX.
+ */
+
+
+ /* OPX == mul? Then store. */
+ xori r7, r4, 0x27
+ beq r7, zero, store_product
+
+ /* It's one of the mulx.. opcodes. Move over the result. */
+ mov r9, r10
+
+ /* OPX == mulxuu? Then store. */
+ xori r7, r4, 0x07
+ beq r7, zero, store_product
+
+ /* Compute mulxsu
+ *
+ * mulxsu = mulxuu - (rA < 0) ? rB : 0;
+ */
+ bge r3, zero, mulxsu_skip
+ sub r9, r9, r11
+mulxsu_skip:
+
+ /* OPX == mulxsu? Then store. */
+ xori r7, r4, 0x17
+ beq r7, zero, store_product
+
+ /* Compute mulxss
+ *
+ * mulxss = mulxsu - (rB < 0) ? rA : 0;
+ */
+ bge r11,zero,mulxss_skip
+ sub r9, r9, r3
+mulxss_skip:
+ /* At this point, assume that OPX is mulxss, so store*/
+
+
+store_product:
+ stw r9, 0(r6)
+
+
+restore_registers:
+ /* No need to restore r0. */
+ ldw r5, 100(sp)
+ wrctl estatus, r5
+
+ ldw r1, 4(sp)
+ ldw r2, 8(sp)
+ ldw r3, 12(sp)
+ ldw r4, 16(sp)
+ ldw r5, 20(sp)
+ ldw r6, 24(sp)
+ ldw r7, 28(sp)
+ ldw r8, 32(sp)
+ ldw r9, 36(sp)
+ ldw r10, 40(sp)
+ ldw r11, 44(sp)
+ ldw r12, 48(sp)
+ ldw r13, 52(sp)
+ ldw r14, 56(sp)
+ ldw r15, 60(sp)
+ ldw r16, 64(sp)
+ ldw r17, 68(sp)
+ ldw r18, 72(sp)
+ ldw r19, 76(sp)
+ ldw r20, 80(sp)
+ ldw r21, 84(sp)
+ ldw r22, 88(sp)
+ ldw r23, 92(sp)
+ /* Does not need to restore et */
+ ldw gp, 104(sp)
+
+ ldw fp, 112(sp)
+ ldw ea, 116(sp)
+ ldw ra, 120(sp)
+ ldw sp, 108(sp) /* last restore sp */
+ eret
+
+.set at
+.set break
diff --git a/arch/nios2/kernel/irq.c b/arch/nios2/kernel/irq.c
new file mode 100644
index 0000000..f5b74ae
--- /dev/null
+++ b/arch/nios2/kernel/irq.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2008 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * based on irq.c from m68k which is:
+ *
+ * Copyright (C) 2007 Greg Ungerer <gerg@snapgear.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/of.h>
+
+static u32 ienable;
+
+asmlinkage void do_IRQ(int hwirq, struct pt_regs *regs)
+{
+ struct pt_regs *oldregs = set_irq_regs(regs);
+ int irq;
+
+ irq_enter();
+ irq = irq_find_mapping(NULL, hwirq);
+ generic_handle_irq(irq);
+ irq_exit();
+
+ set_irq_regs(oldregs);
+}
+
+static void chip_unmask(struct irq_data *d)
+{
+ ienable |= (1 << d->hwirq);
+ WRCTL(CTL_IENABLE, ienable);
+}
+
+static void chip_mask(struct irq_data *d)
+{
+ ienable &= ~(1 << d->hwirq);
+ WRCTL(CTL_IENABLE, ienable);
+}
+
+static struct irq_chip m_irq_chip = {
+ .name = "NIOS2-INTC",
+ .irq_unmask = chip_unmask,
+ .irq_mask = chip_mask,
+};
+
+static int irq_map(struct irq_domain *h, unsigned int virq,
+ irq_hw_number_t hw_irq_num)
+{
+ irq_set_chip_and_handler(virq, &m_irq_chip, handle_level_irq);
+
+ return 0;
+}
+
+static struct irq_domain_ops irq_ops = {
+ .map = irq_map,
+ .xlate = irq_domain_xlate_onecell,
+};
+
+void __init init_IRQ(void)
+{
+ struct irq_domain *domain;
+ struct device_node *node;
+
+ node = of_find_compatible_node(NULL, NULL, "altr,nios2-1.0");
+ if (!node)
+ node = of_find_compatible_node(NULL, NULL, "altr,nios2-1.1");
+
+ BUG_ON(!node);
+
+ domain = irq_domain_add_linear(node, NIOS2_CPU_NR_IRQS, &irq_ops, NULL);
+ BUG_ON(!domain);
+
+ irq_set_default_host(domain);
+ of_node_put(node);
+ /* Load the initial ienable value */
+ ienable = RDCTL(CTL_IENABLE);
+}
diff --git a/arch/nios2/kernel/misaligned.c b/arch/nios2/kernel/misaligned.c
new file mode 100644
index 0000000..4e5907a
--- /dev/null
+++ b/arch/nios2/kernel/misaligned.c
@@ -0,0 +1,256 @@
+/*
+ * linux/arch/nios2/kernel/misaligned.c
+ *
+ * basic emulation for mis-aligned accesses on the NIOS II cpu
+ * modelled after the version for arm in arm/alignment.c
+ *
+ * Brad Parker <brad@heeltoe.com>
+ * Copyright (C) 2010 Ambient Corporation
+ * Copyright (c) 2010 Altera Corporation, San Jose, California, USA.
+ * Copyright (c) 2010 Arrow Electronics, Inc.
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of
+ * this archive for more details.
+ */
+
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/proc_fs.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+
+#include <asm/traps.h>
+#include <asm/unaligned.h>
+
+/* instructions we emulate */
+#define INST_LDHU 0x0b
+#define INST_STH 0x0d
+#define INST_LDH 0x0f
+#define INST_STW 0x15
+#define INST_LDW 0x17
+
+static unsigned long ma_user, ma_kern, ma_skipped, ma_half, ma_word;
+
+static unsigned int ma_usermode;
+#define UM_WARN 0x01
+#define UM_FIXUP 0x02
+#define UM_SIGNAL 0x04
+#define KM_WARN 0x08
+
+/* see arch/nios2/include/asm/ptrace.h */
+static u8 sys_stack_frame_reg_offset[] = {
+ /* struct pt_regs */
+ 8, 9, 10, 11, 12, 13, 14, 15, 1, 2, 3, 4, 5, 6, 7, 0,
+ /* struct switch_stack */
+ 16, 17, 18, 19, 20, 21, 22, 23, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+static int reg_offsets[32];
+
+static inline u32 get_reg_val(struct pt_regs *fp, int reg)
+{
+ u8 *p = ((u8 *)fp) + reg_offsets[reg];
+
+ return *(u32 *)p;
+}
+
+static inline void put_reg_val(struct pt_regs *fp, int reg, u32 val)
+{
+ u8 *p = ((u8 *)fp) + reg_offsets[reg];
+ *(u32 *)p = val;
+}
+
+/*
+ * (mis)alignment handler
+ */
+asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause)
+{
+ u32 isn, addr, val;
+ int in_kernel;
+ u8 a, b, d0, d1, d2, d3;
+ u16 imm16;
+ unsigned int fault;
+
+ /* back up one instruction */
+ fp->ea -= 4;
+
+ if (fixup_exception(fp)) {
+ ma_skipped++;
+ return;
+ }
+
+ in_kernel = !user_mode(fp);
+
+ isn = *(unsigned long *)(fp->ea);
+
+ fault = 0;
+
+ /* do fixup if in kernel or mode turned on */
+ if (in_kernel || (ma_usermode & UM_FIXUP)) {
+ /* decompose instruction */
+ a = (isn >> 27) & 0x1f;
+ b = (isn >> 22) & 0x1f;
+ imm16 = (isn >> 6) & 0xffff;
+ addr = get_reg_val(fp, a) + imm16;
+
+ /* do fixup to saved registers */
+ switch (isn & 0x3f) {
+ case INST_LDHU:
+ fault |= __get_user(d0, (u8 *)(addr+0));
+ fault |= __get_user(d1, (u8 *)(addr+1));
+ val = (d1 << 8) | d0;
+ put_reg_val(fp, b, val);
+ ma_half++;
+ break;
+ case INST_STH:
+ val = get_reg_val(fp, b);
+ d1 = val >> 8;
+ d0 = val >> 0;
+
+ pr_debug("sth: ra=%d (%08x) rb=%d (%08x), imm16 %04x addr %08x val %08x\n",
+ a, get_reg_val(fp, a),
+ b, get_reg_val(fp, b),
+ imm16, addr, val);
+
+ if (in_kernel) {
+ *(u8 *)(addr+0) = d0;
+ *(u8 *)(addr+1) = d1;
+ } else {
+ fault |= __put_user(d0, (u8 *)(addr+0));
+ fault |= __put_user(d1, (u8 *)(addr+1));
+ }
+ ma_half++;
+ break;
+ case INST_LDH:
+ fault |= __get_user(d0, (u8 *)(addr+0));
+ fault |= __get_user(d1, (u8 *)(addr+1));
+ val = (short)((d1 << 8) | d0);
+ put_reg_val(fp, b, val);
+ ma_half++;
+ break;
+ case INST_STW:
+ val = get_reg_val(fp, b);
+ d3 = val >> 24;
+ d2 = val >> 16;
+ d1 = val >> 8;
+ d0 = val >> 0;
+ if (in_kernel) {
+ *(u8 *)(addr+0) = d0;
+ *(u8 *)(addr+1) = d1;
+ *(u8 *)(addr+2) = d2;
+ *(u8 *)(addr+3) = d3;
+ } else {
+ fault |= __put_user(d0, (u8 *)(addr+0));
+ fault |= __put_user(d1, (u8 *)(addr+1));
+ fault |= __put_user(d2, (u8 *)(addr+2));
+ fault |= __put_user(d3, (u8 *)(addr+3));
+ }
+ ma_word++;
+ break;
+ case INST_LDW:
+ fault |= __get_user(d0, (u8 *)(addr+0));
+ fault |= __get_user(d1, (u8 *)(addr+1));
+ fault |= __get_user(d2, (u8 *)(addr+2));
+ fault |= __get_user(d3, (u8 *)(addr+3));
+ val = (d3 << 24) | (d2 << 16) | (d1 << 8) | d0;
+ put_reg_val(fp, b, val);
+ ma_word++;
+ break;
+ }
+ }
+
+ addr = RDCTL(CTL_BADADDR);
+ cause >>= 2;
+
+ if (fault) {
+ if (in_kernel) {
+ pr_err("fault during kernel misaligned fixup @ %#lx; addr 0x%08x; isn=0x%08x\n",
+ fp->ea, (unsigned int)addr,
+ (unsigned int)isn);
+ } else {
+ pr_err("fault during user misaligned fixup @ %#lx; isn=%08x addr=0x%08x sp=0x%08lx pid=%d\n",
+ fp->ea,
+ (unsigned int)isn, addr, fp->sp,
+ current->pid);
+
+ _exception(SIGSEGV, fp, SEGV_MAPERR, fp->ea);
+ return;
+ }
+ }
+
+ /*
+ * kernel mode -
+ * note exception and skip bad instruction (return)
+ */
+ if (in_kernel) {
+ ma_kern++;
+ fp->ea += 4;
+
+ if (ma_usermode & KM_WARN) {
+ pr_err("kernel unaligned access @ %#lx; BADADDR 0x%08x; cause=%d, isn=0x%08x\n",
+ fp->ea,
+ (unsigned int)addr, cause,
+ (unsigned int)isn);
+ /* show_regs(fp); */
+ }
+
+ return;
+ }
+
+ ma_user++;
+
+ /*
+ * user mode -
+ * possibly warn,
+ * possibly send SIGBUS signal to process
+ */
+ if (ma_usermode & UM_WARN) {
+ pr_err("user unaligned access @ %#lx; isn=0x%08lx ea=0x%08lx ra=0x%08lx sp=0x%08lx\n",
+ (unsigned long)addr, (unsigned long)isn,
+ fp->ea, fp->ra, fp->sp);
+ }
+
+ if (ma_usermode & UM_SIGNAL)
+ _exception(SIGBUS, fp, BUS_ADRALN, fp->ea);
+ else
+ fp->ea += 4; /* else advance */
+}
+
+static void __init misaligned_calc_reg_offsets(void)
+{
+ int i, r, offset;
+
+ /* pre-calc offsets of registers on sys call stack frame */
+ offset = 0;
+
+ /* struct pt_regs */
+ for (i = 0; i < 16; i++) {
+ r = sys_stack_frame_reg_offset[i];
+ reg_offsets[r] = offset;
+ offset += 4;
+ }
+
+ /* struct switch_stack */
+ offset = -sizeof(struct switch_stack);
+ for (i = 16; i < 32; i++) {
+ r = sys_stack_frame_reg_offset[i];
+ reg_offsets[r] = offset;
+ offset += 4;
+ }
+}
+
+
+static int __init misaligned_init(void)
+{
+ /* default mode - silent fix */
+ ma_usermode = UM_FIXUP | KM_WARN;
+
+ misaligned_calc_reg_offsets();
+
+ return 0;
+}
+
+fs_initcall(misaligned_init);
diff --git a/arch/nios2/kernel/module.c b/arch/nios2/kernel/module.c
new file mode 100644
index 0000000..cc924a3
--- /dev/null
+++ b/arch/nios2/kernel/module.c
@@ -0,0 +1,138 @@
+/*
+ * Kernel module support for Nios II.
+ *
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ * Written by Wentao Xu <xuwentao@microtronix.com>
+ * Copyright (C) 2001, 2003 Rusty Russell
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/moduleloader.h>
+#include <linux/elf.h>
+#include <linux/mm.h>
+#include <linux/vmalloc.h>
+#include <linux/slab.h>
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/kernel.h>
+
+#include <asm/pgtable.h>
+#include <asm/cacheflush.h>
+
+/*
+ * Modules should NOT be allocated with kmalloc for (obvious) reasons.
+ * But we do it for now to avoid relocation issues. CALL26/PCREL26 cannot reach
+ * from 0x80000000 (vmalloc area) to 0xc00000000 (kernel) (kmalloc returns
+ * addresses in 0xc0000000)
+ */
+void *module_alloc(unsigned long size)
+{
+ if (size == 0)
+ return NULL;
+ return kmalloc(size, GFP_KERNEL);
+}
+
+/* Free memory returned from module_alloc */
+void module_free(struct module *mod, void *module_region)
+{
+ kfree(module_region);
+}
+
+int apply_relocate_add(Elf32_Shdr *sechdrs, const char *strtab,
+ unsigned int symindex, unsigned int relsec,
+ struct module *mod)
+{
+ unsigned int i;
+ Elf32_Rela *rela = (void *)sechdrs[relsec].sh_addr;
+
+ pr_debug("Applying relocate section %u to %u\n", relsec,
+ sechdrs[relsec].sh_info);
+
+ for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rela); i++) {
+ /* This is where to make the change */
+ uint32_t word;
+ uint32_t *loc
+ = ((void *)sechdrs[sechdrs[relsec].sh_info].sh_addr
+ + rela[i].r_offset);
+ /* This is the symbol it is referring to. Note that all
+ undefined symbols have been resolved. */
+ Elf32_Sym *sym
+ = ((Elf32_Sym *)sechdrs[symindex].sh_addr
+ + ELF32_R_SYM(rela[i].r_info));
+ uint32_t v = sym->st_value + rela[i].r_addend;
+
+ pr_debug("reltype %d 0x%x name:<%s>\n",
+ ELF32_R_TYPE(rela[i].r_info),
+ rela[i].r_offset, strtab + sym->st_name);
+
+ switch (ELF32_R_TYPE(rela[i].r_info)) {
+ case R_NIOS2_NONE:
+ break;
+ case R_NIOS2_BFD_RELOC_32:
+ *loc += v;
+ break;
+ case R_NIOS2_PCREL16:
+ v -= (uint32_t)loc + 4;
+ if ((int32_t)v > 0x7fff ||
+ (int32_t)v < -(int32_t)0x8000) {
+ pr_err("module %s: relocation overflow\n",
+ mod->name);
+ return -ENOEXEC;
+ }
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+ (word & 0x3f);
+ break;
+ case R_NIOS2_CALL26:
+ if (v & 3) {
+ pr_err("module %s: dangerous relocation\n",
+ mod->name);
+ return -ENOEXEC;
+ }
+ if ((v >> 28) != ((uint32_t)loc >> 28)) {
+ pr_err("module %s: relocation overflow\n",
+ mod->name);
+ return -ENOEXEC;
+ }
+ *loc = (*loc & 0x3f) | ((v >> 2) << 6);
+ break;
+ case R_NIOS2_HI16:
+ word = *loc;
+ *loc = ((((word >> 22) << 16) |
+ ((v >> 16) & 0xffff)) << 6) | (word & 0x3f);
+ break;
+ case R_NIOS2_LO16:
+ word = *loc;
+ *loc = ((((word >> 22) << 16) | (v & 0xffff)) << 6) |
+ (word & 0x3f);
+ break;
+ case R_NIOS2_HIADJ16:
+ {
+ Elf32_Addr word2;
+
+ word = *loc;
+ word2 = ((v >> 16) + ((v >> 15) & 1)) & 0xffff;
+ *loc = ((((word >> 22) << 16) | word2) << 6) |
+ (word & 0x3f);
+ }
+ break;
+
+ default:
+ pr_err("module %s: Unknown reloc: %u\n",
+ mod->name, ELF32_R_TYPE(rela[i].r_info));
+ return -ENOEXEC;
+ }
+ }
+
+ return 0;
+}
+
+int module_finalize(const Elf_Ehdr *hdr, const Elf_Shdr *sechdrs,
+ struct module *me)
+{
+ flush_cache_all();
+ return 0;
+}
diff --git a/arch/nios2/kernel/nios2_ksyms.c b/arch/nios2/kernel/nios2_ksyms.c
new file mode 100644
index 0000000..bf2f55d
--- /dev/null
+++ b/arch/nios2/kernel/nios2_ksyms.c
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/string.h>
+
+/* string functions */
+
+EXPORT_SYMBOL(memcpy);
+EXPORT_SYMBOL(memset);
+EXPORT_SYMBOL(memmove);
+
+/*
+ * libgcc functions - functions that are used internally by the
+ * compiler... (prototypes are not correct though, but that
+ * doesn't really matter since they're not versioned).
+ */
+#define DECLARE_EXPORT(name) extern void name(void); EXPORT_SYMBOL(name)
+
+DECLARE_EXPORT(__gcc_bcmp);
+DECLARE_EXPORT(__divsi3);
+DECLARE_EXPORT(__moddi3);
+DECLARE_EXPORT(__modsi3);
+DECLARE_EXPORT(__udivmoddi4);
+DECLARE_EXPORT(__udivsi3);
+DECLARE_EXPORT(__umoddi3);
+DECLARE_EXPORT(__umodsi3);
+DECLARE_EXPORT(__muldi3);
diff --git a/arch/nios2/kernel/process.c b/arch/nios2/kernel/process.c
new file mode 100644
index 0000000..0e075b5
--- /dev/null
+++ b/arch/nios2/kernel/process.c
@@ -0,0 +1,258 @@
+/*
+ * Architecture-dependent parts of process handling.
+ *
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/tick.h>
+#include <linux/uaccess.h>
+
+#include <asm/unistd.h>
+#include <asm/traps.h>
+#include <asm/cpuinfo.h>
+
+asmlinkage void ret_from_fork(void);
+asmlinkage void ret_from_kernel_thread(void);
+
+void (*pm_power_off)(void) = NULL;
+EXPORT_SYMBOL(pm_power_off);
+
+void arch_cpu_idle(void)
+{
+ local_irq_enable();
+}
+
+/*
+ * The development boards have no way to pull a board reset. Just jump to the
+ * cpu reset address and let the boot loader or the code in head.S take care of
+ * resetting peripherals.
+ */
+void machine_restart(char *__unused)
+{
+ pr_notice("Machine restart (%08x)...\n", cpuinfo.reset_addr);
+ local_irq_disable();
+ __asm__ __volatile__ (
+ "jmp %0\n\t"
+ :
+ : "r" (cpuinfo.reset_addr)
+ : "r4");
+}
+
+void machine_halt(void)
+{
+ pr_notice("Machine halt...\n");
+ local_irq_disable();
+ for (;;)
+ ;
+}
+
+/*
+ * There is no way to power off the development boards. So just spin for now. If
+ * we ever have a way of resetting a board using a GPIO we should add that here.
+ */
+void machine_power_off(void)
+{
+ pr_notice("Machine power off...\n");
+ local_irq_disable();
+ for (;;)
+ ;
+}
+
+void show_regs(struct pt_regs *regs)
+{
+ pr_notice("\n");
+ show_regs_print_info(KERN_DEFAULT);
+
+ pr_notice("r1: %08lx r2: %08lx r3: %08lx r4: %08lx\n",
+ regs->r1, regs->r2, regs->r3, regs->r4);
+
+ pr_notice("r5: %08lx r6: %08lx r7: %08lx r8: %08lx\n",
+ regs->r5, regs->r6, regs->r7, regs->r8);
+
+ pr_notice("r9: %08lx r10: %08lx r11: %08lx r12: %08lx\n",
+ regs->r9, regs->r10, regs->r11, regs->r12);
+
+ pr_notice("r13: %08lx r14: %08lx r15: %08lx\n",
+ regs->r13, regs->r14, regs->r15);
+
+ pr_notice("ra: %08lx fp: %08lx sp: %08lx gp: %08lx\n",
+ regs->ra, regs->fp, regs->sp, regs->gp);
+
+ pr_notice("ea: %08lx estatus: %08lx\n",
+ regs->ea, regs->estatus);
+}
+
+void flush_thread(void)
+{
+ set_fs(USER_DS);
+}
+
+int copy_thread(unsigned long clone_flags,
+ unsigned long usp, unsigned long arg, struct task_struct *p)
+{
+ struct pt_regs *childregs = task_pt_regs(p);
+ struct pt_regs *regs;
+ struct switch_stack *stack;
+ struct switch_stack *childstack =
+ ((struct switch_stack *)childregs) - 1;
+
+ if (unlikely(p->flags & PF_KTHREAD)) {
+ memset(childstack, 0,
+ sizeof(struct switch_stack) + sizeof(struct pt_regs));
+
+ childstack->r16 = usp; /* fn */
+ childstack->r17 = arg;
+ childstack->ra = (unsigned long) ret_from_kernel_thread;
+ childregs->estatus = STATUS_PIE;
+ childregs->sp = (unsigned long) childstack;
+
+ p->thread.ksp = (unsigned long) childstack;
+ p->thread.kregs = childregs;
+ return 0;
+ }
+
+ regs = current_pt_regs();
+ *childregs = *regs;
+ childregs->r2 = 0; /* Set the return value for the child. */
+ childregs->r7 = 0;
+
+ stack = ((struct switch_stack *) regs) - 1;
+ *childstack = *stack;
+ childstack->ra = (unsigned long)ret_from_fork;
+ p->thread.kregs = childregs;
+ p->thread.ksp = (unsigned long) childstack;
+
+ if (usp)
+ childregs->sp = usp;
+
+ /* Initialize tls register. */
+ if (clone_flags & CLONE_SETTLS)
+ childstack->r23 = regs->r8;
+
+ return 0;
+}
+
+/*
+ * Generic dumping code. Used for panic and debug.
+ */
+void dump(struct pt_regs *fp)
+{
+ unsigned long *sp;
+ unsigned char *tp;
+ int i;
+
+ pr_emerg("\nCURRENT PROCESS:\n\n");
+ pr_emerg("COMM=%s PID=%d\n", current->comm, current->pid);
+
+ if (current->mm) {
+ pr_emerg("TEXT=%08x-%08x DATA=%08x-%08x BSS=%08x-%08x\n",
+ (int) current->mm->start_code,
+ (int) current->mm->end_code,
+ (int) current->mm->start_data,
+ (int) current->mm->end_data,
+ (int) current->mm->end_data,
+ (int) current->mm->brk);
+ pr_emerg("USER-STACK=%08x KERNEL-STACK=%08x\n\n",
+ (int) current->mm->start_stack,
+ (int)(((unsigned long) current) + THREAD_SIZE));
+ }
+
+ pr_emerg("PC: %08lx\n", fp->ea);
+ pr_emerg("SR: %08lx SP: %08lx\n",
+ (long) fp->estatus, (long) fp);
+
+ pr_emerg("r1: %08lx r2: %08lx r3: %08lx\n",
+ fp->r1, fp->r2, fp->r3);
+
+ pr_emerg("r4: %08lx r5: %08lx r6: %08lx r7: %08lx\n",
+ fp->r4, fp->r5, fp->r6, fp->r7);
+ pr_emerg("r8: %08lx r9: %08lx r10: %08lx r11: %08lx\n",
+ fp->r8, fp->r9, fp->r10, fp->r11);
+ pr_emerg("r12: %08lx r13: %08lx r14: %08lx r15: %08lx\n",
+ fp->r12, fp->r13, fp->r14, fp->r15);
+ pr_emerg("or2: %08lx ra: %08lx fp: %08lx sp: %08lx\n",
+ fp->orig_r2, fp->ra, fp->fp, fp->sp);
+ pr_emerg("\nUSP: %08x TRAPFRAME: %08x\n",
+ (unsigned int) fp->sp, (unsigned int) fp);
+
+ pr_emerg("\nCODE:");
+ tp = ((unsigned char *) fp->ea) - 0x20;
+ for (sp = (unsigned long *) tp, i = 0; (i < 0x40); i += 4) {
+ if ((i % 0x10) == 0)
+ pr_emerg("\n%08x: ", (int) (tp + i));
+ pr_emerg("%08x ", (int) *sp++);
+ }
+ pr_emerg("\n");
+
+ pr_emerg("\nKERNEL STACK:");
+ tp = ((unsigned char *) fp) - 0x40;
+ for (sp = (unsigned long *) tp, i = 0; (i < 0xc0); i += 4) {
+ if ((i % 0x10) == 0)
+ pr_emerg("\n%08x: ", (int) (tp + i));
+ pr_emerg("%08x ", (int) *sp++);
+ }
+ pr_emerg("\n");
+ pr_emerg("\n");
+
+ pr_emerg("\nUSER STACK:");
+ tp = (unsigned char *) (fp->sp - 0x10);
+ for (sp = (unsigned long *) tp, i = 0; (i < 0x80); i += 4) {
+ if ((i % 0x10) == 0)
+ pr_emerg("\n%08x: ", (int) (tp + i));
+ pr_emerg("%08x ", (int) *sp++);
+ }
+ pr_emerg("\n\n");
+}
+
+unsigned long get_wchan(struct task_struct *p)
+{
+ unsigned long fp, pc;
+ unsigned long stack_page;
+ int count = 0;
+
+ if (!p || p == current || p->state == TASK_RUNNING)
+ return 0;
+
+ stack_page = (unsigned long)p;
+ fp = ((struct switch_stack *)p->thread.ksp)->fp; /* ;dgt2 */
+ do {
+ if (fp < stack_page+sizeof(struct task_struct) ||
+ fp >= 8184+stack_page) /* ;dgt2;tmp */
+ return 0;
+ pc = ((unsigned long *)fp)[1];
+ if (!in_sched_functions(pc))
+ return pc;
+ fp = *(unsigned long *) fp;
+ } while (count++ < 16); /* ;dgt2;tmp */
+ return 0;
+}
+
+/*
+ * Do necessary setup to start up a newly executed thread.
+ * Will startup in user mode (status_extension = 0).
+ */
+void start_thread(struct pt_regs *regs, unsigned long pc, unsigned long sp)
+{
+ memset((void *) regs, 0, sizeof(struct pt_regs));
+ regs->estatus = ESTATUS_EPIE | ESTATUS_EU;
+ regs->ea = pc;
+ regs->sp = sp;
+}
+
+#include <linux/elfcore.h>
+
+/* Fill in the FPU structure for a core dump. */
+int dump_fpu(struct pt_regs *regs, elf_fpregset_t *r)
+{
+ return 0; /* Nios2 has no FPU and thus no FPU registers */
+}
diff --git a/arch/nios2/kernel/prom.c b/arch/nios2/kernel/prom.c
new file mode 100644
index 0000000..0522d33
--- /dev/null
+++ b/arch/nios2/kernel/prom.c
@@ -0,0 +1,65 @@
+/*
+ * Device tree support
+ *
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2010 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * Based on MIPS support for CONFIG_OF device tree support
+ *
+ * Copyright (C) 2010 Cisco Systems Inc. <dediao@cisco.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/bootmem.h>
+#include <linux/of.h>
+#include <linux/of_fdt.h>
+#include <linux/io.h>
+
+#include <asm/sections.h>
+
+void __init early_init_dt_add_memory_arch(u64 base, u64 size)
+{
+ u64 kernel_start = (u64)virt_to_phys(_text);
+
+ if (!memory_size &&
+ (kernel_start >= base) && (kernel_start < (base + size)))
+ memory_size = size;
+
+}
+
+void * __init early_init_dt_alloc_memory_arch(u64 size, u64 align)
+{
+ return alloc_bootmem_align(size, align);
+}
+
+void __init early_init_devtree(void *params)
+{
+ __be32 *dtb = (u32 *)__dtb_start;
+#if defined(CONFIG_NIOS2_DTB_AT_PHYS_ADDR)
+ if (be32_to_cpup((__be32 *)CONFIG_NIOS2_DTB_PHYS_ADDR) ==
+ OF_DT_HEADER) {
+ params = (void *)CONFIG_NIOS2_DTB_PHYS_ADDR;
+ early_init_dt_scan(params);
+ return;
+ }
+#endif
+ if (be32_to_cpu((__be32) *dtb) == OF_DT_HEADER)
+ params = (void *)__dtb_start;
+
+ early_init_dt_scan(params);
+}
diff --git a/arch/nios2/kernel/ptrace.c b/arch/nios2/kernel/ptrace.c
new file mode 100644
index 0000000..681dda9
--- /dev/null
+++ b/arch/nios2/kernel/ptrace.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2014 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/elf.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+#include <linux/regset.h>
+#include <linux/sched.h>
+#include <linux/tracehook.h>
+#include <linux/uaccess.h>
+#include <linux/user.h>
+
+static int genregs_get(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ void *kbuf, void __user *ubuf)
+{
+ const struct pt_regs *regs = task_pt_regs(target);
+ const struct switch_stack *sw = (struct switch_stack *)regs - 1;
+ int ret = 0;
+
+#define REG_O_ZERO_RANGE(START, END) \
+ if (!ret) \
+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf, \
+ START * 4, (END * 4) + 4);
+
+#define REG_O_ONE(PTR, LOC) \
+ if (!ret) \
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
+ LOC * 4, (LOC * 4) + 4);
+
+#define REG_O_RANGE(PTR, START, END) \
+ if (!ret) \
+ ret = user_regset_copyout(&pos, &count, &kbuf, &ubuf, PTR, \
+ START * 4, (END * 4) + 4);
+
+ REG_O_ZERO_RANGE(PTR_R0, PTR_R0);
+ REG_O_RANGE(&regs->r1, PTR_R1, PTR_R7);
+ REG_O_RANGE(&regs->r8, PTR_R8, PTR_R15);
+ REG_O_RANGE(sw, PTR_R16, PTR_R23);
+ REG_O_ZERO_RANGE(PTR_R24, PTR_R25); /* et and bt */
+ REG_O_ONE(&regs->gp, PTR_GP);
+ REG_O_ONE(&regs->sp, PTR_SP);
+ REG_O_ONE(&regs->fp, PTR_FP);
+ REG_O_ONE(&regs->ea, PTR_EA);
+ REG_O_ZERO_RANGE(PTR_BA, PTR_BA);
+ REG_O_ONE(&regs->ra, PTR_RA);
+ REG_O_ONE(&regs->ea, PTR_PC); /* use ea for PC */
+ if (!ret)
+ ret = user_regset_copyout_zero(&pos, &count, &kbuf, &ubuf,
+ PTR_STATUS * 4, -1);
+
+ return ret;
+}
+
+/*
+ * Set the thread state from a regset passed in via ptrace
+ */
+static int genregs_set(struct task_struct *target,
+ const struct user_regset *regset,
+ unsigned int pos, unsigned int count,
+ const void *kbuf, const void __user *ubuf)
+{
+ struct pt_regs *regs = task_pt_regs(target);
+ const struct switch_stack *sw = (struct switch_stack *)regs - 1;
+ int ret = 0;
+
+#define REG_IGNORE_RANGE(START, END) \
+ if (!ret) \
+ ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf, \
+ START * 4, (END * 4) + 4);
+
+#define REG_IN_ONE(PTR, LOC) \
+ if (!ret) \
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
+ (void *)(PTR), LOC * 4, (LOC * 4) + 4);
+
+#define REG_IN_RANGE(PTR, START, END) \
+ if (!ret) \
+ ret = user_regset_copyin(&pos, &count, &kbuf, &ubuf, \
+ (void *)(PTR), START * 4, (END * 4) + 4);
+
+ REG_IGNORE_RANGE(PTR_R0, PTR_R0);
+ REG_IN_RANGE(&regs->r1, PTR_R1, PTR_R7);
+ REG_IN_RANGE(&regs->r8, PTR_R8, PTR_R15);
+ REG_IN_RANGE(sw, PTR_R16, PTR_R23);
+ REG_IGNORE_RANGE(PTR_R24, PTR_R25); /* et and bt */
+ REG_IN_ONE(&regs->gp, PTR_GP);
+ REG_IN_ONE(&regs->sp, PTR_SP);
+ REG_IN_ONE(&regs->fp, PTR_FP);
+ REG_IN_ONE(&regs->ea, PTR_EA);
+ REG_IGNORE_RANGE(PTR_BA, PTR_BA);
+ REG_IN_ONE(&regs->ra, PTR_RA);
+ REG_IN_ONE(&regs->ea, PTR_PC); /* use ea for PC */
+ if (!ret)
+ ret = user_regset_copyin_ignore(&pos, &count, &kbuf, &ubuf,
+ PTR_STATUS * 4, -1);
+
+ return ret;
+}
+
+/*
+ * Define the register sets available on Nios2 under Linux
+ */
+enum nios2_regset {
+ REGSET_GENERAL,
+};
+
+static const struct user_regset nios2_regsets[] = {
+ [REGSET_GENERAL] = {
+ .core_note_type = NT_PRSTATUS,
+ .n = NUM_PTRACE_REG,
+ .size = sizeof(unsigned long),
+ .align = sizeof(unsigned long),
+ .get = genregs_get,
+ .set = genregs_set,
+ }
+};
+
+static const struct user_regset_view nios2_user_view = {
+ .name = "nios2",
+ .e_machine = ELF_ARCH,
+ .ei_osabi = ELF_OSABI,
+ .regsets = nios2_regsets,
+ .n = ARRAY_SIZE(nios2_regsets)
+};
+
+const struct user_regset_view *task_user_regset_view(struct task_struct *task)
+{
+ return &nios2_user_view;
+}
+
+void ptrace_disable(struct task_struct *child)
+{
+
+}
+
+long arch_ptrace(struct task_struct *child, long request, unsigned long addr,
+ unsigned long data)
+{
+ return ptrace_request(child, request, addr, data);
+}
+
+asmlinkage int do_syscall_trace_enter(void)
+{
+ int ret = 0;
+
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ ret = tracehook_report_syscall_entry(task_pt_regs(current));
+
+ return ret;
+}
+
+asmlinkage void do_syscall_trace_exit(void)
+{
+ if (test_thread_flag(TIF_SYSCALL_TRACE))
+ tracehook_report_syscall_exit(task_pt_regs(current), 0);
+}
diff --git a/arch/nios2/kernel/setup.c b/arch/nios2/kernel/setup.c
new file mode 100644
index 0000000..cb3121f
--- /dev/null
+++ b/arch/nios2/kernel/setup.c
@@ -0,0 +1,218 @@
+/*
+ * Nios2-specific parts of system setup
+ *
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ * Copyright (C) 2001 Vic Phillips <vic@microtronix.com>
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/console.h>
+#include <linux/bootmem.h>
+#include <linux/initrd.h>
+#include <linux/of_fdt.h>
+
+#include <asm/mmu_context.h>
+#include <asm/sections.h>
+#include <asm/setup.h>
+#include <asm/cpuinfo.h>
+
+unsigned long memory_start;
+EXPORT_SYMBOL(memory_start);
+
+unsigned long memory_end;
+EXPORT_SYMBOL(memory_end);
+
+unsigned long memory_size;
+
+static struct pt_regs fake_regs = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0,
+ 0};
+
+/* Copy a short hook instruction sequence to the exception address */
+static inline void copy_exception_handler(unsigned int addr)
+{
+ unsigned int start = (unsigned int) exception_handler_hook;
+ volatile unsigned int tmp = 0;
+
+ if (start == addr) {
+ /* The CPU exception address already points to the handler. */
+ return;
+ }
+
+ __asm__ __volatile__ (
+ "ldw %2,0(%0)\n"
+ "stw %2,0(%1)\n"
+ "ldw %2,4(%0)\n"
+ "stw %2,4(%1)\n"
+ "ldw %2,8(%0)\n"
+ "stw %2,8(%1)\n"
+ "flushd 0(%1)\n"
+ "flushd 4(%1)\n"
+ "flushd 8(%1)\n"
+ "flushi %1\n"
+ "addi %1,%1,4\n"
+ "flushi %1\n"
+ "addi %1,%1,4\n"
+ "flushi %1\n"
+ "flushp\n"
+ : /* no output registers */
+ : "r" (start), "r" (addr), "r" (tmp)
+ : "memory"
+ );
+}
+
+/* Copy the fast TLB miss handler */
+static inline void copy_fast_tlb_miss_handler(unsigned int addr)
+{
+ unsigned int start = (unsigned int) fast_handler;
+ unsigned int end = (unsigned int) fast_handler_end;
+ volatile unsigned int tmp = 0;
+
+ __asm__ __volatile__ (
+ "1:\n"
+ " ldw %3,0(%0)\n"
+ " stw %3,0(%1)\n"
+ " flushd 0(%1)\n"
+ " flushi %1\n"
+ " flushp\n"
+ " addi %0,%0,4\n"
+ " addi %1,%1,4\n"
+ " bne %0,%2,1b\n"
+ : /* no output registers */
+ : "r" (start), "r" (addr), "r" (end), "r" (tmp)
+ : "memory"
+ );
+}
+
+/*
+ * save args passed from u-boot, called from head.S
+ *
+ * @r4: NIOS magic
+ * @r5: initrd start
+ * @r6: initrd end or fdt
+ * @r7: kernel command line
+ */
+asmlinkage void __init nios2_boot_init(unsigned r4, unsigned r5, unsigned r6,
+ unsigned r7)
+{
+ unsigned dtb_passed = 0;
+ char cmdline_passed[COMMAND_LINE_SIZE] = { 0, };
+
+#if defined(CONFIG_NIOS2_PASS_CMDLINE)
+ if (r4 == 0x534f494e) { /* r4 is magic NIOS */
+#if defined(CONFIG_BLK_DEV_INITRD)
+ if (r5) { /* initramfs */
+ initrd_start = r5;
+ initrd_end = r6;
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+ dtb_passed = r6;
+
+ if (r7)
+ strncpy(cmdline_passed, (char *)r7, COMMAND_LINE_SIZE);
+ }
+#endif
+
+ early_init_devtree((void *)dtb_passed);
+
+#ifndef CONFIG_CMDLINE_FORCE
+ if (cmdline_passed[0])
+ strncpy(boot_command_line, cmdline_passed, COMMAND_LINE_SIZE);
+#ifdef CONFIG_NIOS2_CMDLINE_IGNORE_DTB
+ else
+ strncpy(boot_command_line, CONFIG_CMDLINE, COMMAND_LINE_SIZE);
+#endif
+#endif
+}
+
+void __init setup_arch(char **cmdline_p)
+{
+ int bootmap_size;
+
+ console_verbose();
+
+ memory_start = PAGE_ALIGN((unsigned long)__pa(_end));
+ memory_end = (unsigned long) CONFIG_NIOS2_MEM_BASE + memory_size;
+
+ 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;
+ init_task.thread.kregs = &fake_regs;
+
+ /* Keep a copy of command line */
+ *cmdline_p = boot_command_line;
+
+ min_low_pfn = PFN_UP(memory_start);
+ max_low_pfn = PFN_DOWN(memory_end);
+ max_mapnr = max_low_pfn;
+
+ /*
+ * give all the memory to the bootmap allocator, tell it to put the
+ * boot mem_map at the start of memory
+ */
+ pr_debug("init_bootmem_node(?,%#lx, %#x, %#lx)\n",
+ min_low_pfn, PFN_DOWN(PHYS_OFFSET), max_low_pfn);
+ bootmap_size = init_bootmem_node(NODE_DATA(0),
+ min_low_pfn, PFN_DOWN(PHYS_OFFSET),
+ max_low_pfn);
+
+ /*
+ * free the usable memory, we have to make sure we do not free
+ * the bootmem bitmap so we then reserve it after freeing it :-)
+ */
+ pr_debug("free_bootmem(%#lx, %#lx)\n",
+ memory_start, memory_end - memory_start);
+ free_bootmem(memory_start, memory_end - memory_start);
+
+ /*
+ * Reserve the bootmem bitmap itself as well. We do this in two
+ * steps (first step was init_bootmem()) because this catches
+ * the (very unlikely) case of us accidentally initializing the
+ * bootmem allocator with an invalid RAM area.
+ *
+ * Arguments are start, size
+ */
+ pr_debug("reserve_bootmem(%#lx, %#x)\n", memory_start, bootmap_size);
+ reserve_bootmem(memory_start, bootmap_size, BOOTMEM_DEFAULT);
+
+#ifdef CONFIG_BLK_DEV_INITRD
+ if (initrd_start) {
+ reserve_bootmem(virt_to_phys((void *)initrd_start),
+ initrd_end - initrd_start, BOOTMEM_DEFAULT);
+ }
+#endif /* CONFIG_BLK_DEV_INITRD */
+
+ unflatten_and_copy_device_tree();
+
+ setup_cpuinfo();
+
+ copy_exception_handler(cpuinfo.exception_addr);
+
+ mmu_init();
+
+ copy_fast_tlb_miss_handler(cpuinfo.fast_tlb_miss_exc_addr);
+
+ /*
+ * Initialize MMU context handling here because data from cpuinfo is
+ * needed for this.
+ */
+ mmu_context_init();
+
+ /*
+ * get kmalloc into gear
+ */
+ paging_init();
+
+#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
+ conswitchp = &dummy_con;
+#endif
+}
diff --git a/arch/nios2/kernel/signal.c b/arch/nios2/kernel/signal.c
new file mode 100644
index 0000000..f9d2788
--- /dev/null
+++ b/arch/nios2/kernel/signal.c
@@ -0,0 +1,323 @@
+/*
+ * Copyright (C) 2013-2014 Altera Corporation
+ * Copyright (C) 2011-2012 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file COPYING in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/signal.h>
+#include <linux/errno.h>
+#include <linux/ptrace.h>
+#include <linux/uaccess.h>
+#include <linux/unistd.h>
+#include <linux/personality.h>
+#include <linux/tracehook.h>
+
+#include <asm/ucontext.h>
+#include <asm/cacheflush.h>
+
+#define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
+
+/*
+ * Do a signal return; undo the signal stack.
+ *
+ * Keep the return code on the stack quadword aligned!
+ * That makes the cache flush below easier.
+ */
+
+struct rt_sigframe {
+ struct siginfo info;
+ struct ucontext uc;
+};
+
+static inline int rt_restore_ucontext(struct pt_regs *regs,
+ struct switch_stack *sw,
+ struct ucontext *uc, int *pr2)
+{
+ int temp;
+ greg_t *gregs = uc->uc_mcontext.gregs;
+ int err;
+
+ /* Always make any pending restarted system calls return -EINTR */
+ current_thread_info()->restart_block.fn = do_no_restart_syscall;
+
+ err = __get_user(temp, &uc->uc_mcontext.version);
+ if (temp != MCONTEXT_VERSION)
+ goto badframe;
+ /* restore passed registers */
+ err |= __get_user(regs->r1, &gregs[0]);
+ err |= __get_user(regs->r2, &gregs[1]);
+ err |= __get_user(regs->r3, &gregs[2]);
+ err |= __get_user(regs->r4, &gregs[3]);
+ err |= __get_user(regs->r5, &gregs[4]);
+ err |= __get_user(regs->r6, &gregs[5]);
+ err |= __get_user(regs->r7, &gregs[6]);
+ err |= __get_user(regs->r8, &gregs[7]);
+ err |= __get_user(regs->r9, &gregs[8]);
+ err |= __get_user(regs->r10, &gregs[9]);
+ err |= __get_user(regs->r11, &gregs[10]);
+ err |= __get_user(regs->r12, &gregs[11]);
+ err |= __get_user(regs->r13, &gregs[12]);
+ err |= __get_user(regs->r14, &gregs[13]);
+ err |= __get_user(regs->r15, &gregs[14]);
+ err |= __get_user(sw->r16, &gregs[15]);
+ err |= __get_user(sw->r17, &gregs[16]);
+ err |= __get_user(sw->r18, &gregs[17]);
+ err |= __get_user(sw->r19, &gregs[18]);
+ err |= __get_user(sw->r20, &gregs[19]);
+ err |= __get_user(sw->r21, &gregs[20]);
+ err |= __get_user(sw->r22, &gregs[21]);
+ err |= __get_user(sw->r23, &gregs[22]);
+ /* gregs[23] is handled below */
+ err |= __get_user(sw->fp, &gregs[24]); /* Verify, should this be
+ settable */
+ err |= __get_user(sw->gp, &gregs[25]); /* Verify, should this be
+ settable */
+
+ err |= __get_user(temp, &gregs[26]); /* Not really necessary no user
+ settable bits */
+ err |= __get_user(regs->ea, &gregs[27]);
+
+ err |= __get_user(regs->ra, &gregs[23]);
+ err |= __get_user(regs->sp, &gregs[28]);
+
+ regs->orig_r2 = -1; /* disable syscall checks */
+
+ err |= restore_altstack(&uc->uc_stack);
+ if (err)
+ goto badframe;
+
+ *pr2 = regs->r2;
+ return err;
+
+badframe:
+ return 1;
+}
+
+asmlinkage int do_rt_sigreturn(struct switch_stack *sw)
+{
+ struct pt_regs *regs = (struct pt_regs *)(sw + 1);
+ /* Verify, can we follow the stack back */
+ struct rt_sigframe *frame = (struct rt_sigframe *) regs->sp;
+ sigset_t set;
+ int rval;
+
+ if (!access_ok(VERIFY_READ, frame, sizeof(*frame)))
+ goto badframe;
+
+ if (__copy_from_user(&set, &frame->uc.uc_sigmask, sizeof(set)))
+ goto badframe;
+
+ set_current_blocked(&set);
+
+ if (rt_restore_ucontext(regs, sw, &frame->uc, &rval))
+ goto badframe;
+
+ return rval;
+
+badframe:
+ force_sig(SIGSEGV, current);
+ return 0;
+}
+
+static inline int rt_setup_ucontext(struct ucontext *uc, struct pt_regs *regs)
+{
+ struct switch_stack *sw = (struct switch_stack *)regs - 1;
+ greg_t *gregs = uc->uc_mcontext.gregs;
+ int err = 0;
+
+ err |= __put_user(MCONTEXT_VERSION, &uc->uc_mcontext.version);
+ err |= __put_user(regs->r1, &gregs[0]);
+ err |= __put_user(regs->r2, &gregs[1]);
+ err |= __put_user(regs->r3, &gregs[2]);
+ err |= __put_user(regs->r4, &gregs[3]);
+ err |= __put_user(regs->r5, &gregs[4]);
+ err |= __put_user(regs->r6, &gregs[5]);
+ err |= __put_user(regs->r7, &gregs[6]);
+ err |= __put_user(regs->r8, &gregs[7]);
+ err |= __put_user(regs->r9, &gregs[8]);
+ err |= __put_user(regs->r10, &gregs[9]);
+ err |= __put_user(regs->r11, &gregs[10]);
+ err |= __put_user(regs->r12, &gregs[11]);
+ err |= __put_user(regs->r13, &gregs[12]);
+ err |= __put_user(regs->r14, &gregs[13]);
+ err |= __put_user(regs->r15, &gregs[14]);
+ err |= __put_user(sw->r16, &gregs[15]);
+ err |= __put_user(sw->r17, &gregs[16]);
+ err |= __put_user(sw->r18, &gregs[17]);
+ err |= __put_user(sw->r19, &gregs[18]);
+ err |= __put_user(sw->r20, &gregs[19]);
+ err |= __put_user(sw->r21, &gregs[20]);
+ err |= __put_user(sw->r22, &gregs[21]);
+ err |= __put_user(sw->r23, &gregs[22]);
+ err |= __put_user(regs->ra, &gregs[23]);
+ err |= __put_user(sw->fp, &gregs[24]);
+ err |= __put_user(sw->gp, &gregs[25]);
+ err |= __put_user(regs->ea, &gregs[27]);
+ err |= __put_user(regs->sp, &gregs[28]);
+ return err;
+}
+
+static inline void *get_sigframe(struct ksignal *ksig, struct pt_regs *regs,
+ size_t frame_size)
+{
+ unsigned long usp;
+
+ /* Default to using normal stack. */
+ usp = regs->sp;
+
+ /* This is the X/Open sanctioned signal stack switching. */
+ usp = sigsp(usp, ksig);
+
+ /* Verify, is it 32 or 64 bit aligned */
+ return (void *)((usp - frame_size) & -8UL);
+}
+
+static int setup_rt_frame(struct ksignal *ksig, sigset_t *set,
+ struct pt_regs *regs)
+{
+ struct rt_sigframe *frame;
+ int err = 0;
+
+ frame = get_sigframe(ksig, regs, sizeof(*frame));
+
+ if (ksig->ka.sa.sa_flags & SA_SIGINFO)
+ err |= copy_siginfo_to_user(&frame->info, &ksig->info);
+
+ /* Create the ucontext. */
+ err |= __put_user(0, &frame->uc.uc_flags);
+ err |= __put_user(0, &frame->uc.uc_link);
+ err |= __save_altstack(&frame->uc.uc_stack, regs->sp);
+ err |= rt_setup_ucontext(&frame->uc, regs);
+ err |= copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set));
+
+ if (err)
+ goto give_sigsegv;
+
+ /* Set up to return from userspace; jump to fixed address sigreturn
+ trampoline on kuser page. */
+ regs->ra = (unsigned long) (0x1040);
+
+ /* Set up registers for signal handler */
+ regs->sp = (unsigned long) frame;
+ regs->r4 = (unsigned long) ksig->sig;
+ regs->r5 = (unsigned long) &frame->info;
+ regs->r6 = (unsigned long) &frame->uc;
+ regs->ea = (unsigned long) ksig->ka.sa.sa_handler;
+ return 0;
+
+give_sigsegv:
+ force_sigsegv(ksig->sig, current);
+ return -EFAULT;
+}
+
+/*
+ * OK, we're invoking a handler
+ */
+static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
+{
+ int ret;
+ sigset_t *oldset = sigmask_to_save();
+
+ /* set up the stack frame */
+ ret = setup_rt_frame(ksig, oldset, regs);
+
+ signal_setup_done(ret, ksig, 0);
+}
+
+static int do_signal(struct pt_regs *regs)
+{
+ unsigned int retval = 0, continue_addr = 0, restart_addr = 0;
+ int restart = 0;
+ struct ksignal ksig;
+
+ current->thread.kregs = regs;
+
+ /*
+ * If we were from a system call, check for system call restarting...
+ */
+ if (regs->orig_r2 >= 0) {
+ continue_addr = regs->ea;
+ restart_addr = continue_addr - 4;
+ retval = regs->r2;
+
+ /*
+ * Prepare for system call restart. We do this here so that a
+ * debugger will see the already changed PC.
+ */
+ switch (retval) {
+ case ERESTART_RESTARTBLOCK:
+ restart = -2;
+ case ERESTARTNOHAND:
+ case ERESTARTSYS:
+ case ERESTARTNOINTR:
+ restart++;
+ regs->r2 = regs->orig_r2;
+ regs->r7 = regs->orig_r7;
+ regs->ea = restart_addr;
+ break;
+ }
+ }
+
+ if (get_signal(&ksig)) {
+ /* handler */
+ if (unlikely(restart && regs->ea == restart_addr)) {
+ if (retval == ERESTARTNOHAND ||
+ retval == ERESTART_RESTARTBLOCK ||
+ (retval == ERESTARTSYS
+ && !(ksig.ka.sa.sa_flags & SA_RESTART))) {
+ regs->r2 = EINTR;
+ regs->r7 = 1;
+ regs->ea = continue_addr;
+ }
+ }
+ handle_signal(&ksig, regs);
+ return 0;
+ }
+
+ /*
+ * No handler present
+ */
+ if (unlikely(restart) && regs->ea == restart_addr) {
+ regs->ea = continue_addr;
+ regs->r2 = __NR_restart_syscall;
+ }
+
+ /*
+ * If there's no signal to deliver, we just put the saved sigmask back.
+ */
+ restore_saved_sigmask();
+
+ return restart;
+}
+
+asmlinkage int do_notify_resume(struct pt_regs *regs)
+{
+ /*
+ * We want the common case to go fast, which is why we may in certain
+ * cases get here from kernel mode. Just return without doing anything
+ * if so.
+ */
+ if (!user_mode(regs))
+ return 0;
+
+ if (test_thread_flag(TIF_SIGPENDING)) {
+ int restart = do_signal(regs);
+
+ if (unlikely(restart)) {
+ /*
+ * Restart without handlers.
+ * Deal with it without leaving
+ * the kernel space.
+ */
+ return restart;
+ }
+ } else if (test_and_clear_thread_flag(TIF_NOTIFY_RESUME))
+ tracehook_notify_resume(regs);
+
+ return 0;
+}
diff --git a/arch/nios2/kernel/sys_nios2.c b/arch/nios2/kernel/sys_nios2.c
new file mode 100644
index 0000000..cd390ec
--- /dev/null
+++ b/arch/nios2/kernel/sys_nios2.c
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2011-2012 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+
+#include <asm/cacheflush.h>
+#include <asm/traps.h>
+
+/* sys_cacheflush -- flush the processor cache. */
+asmlinkage int sys_cacheflush(unsigned long addr, unsigned long len,
+ unsigned int op)
+{
+ struct vm_area_struct *vma;
+
+ if (len == 0)
+ return 0;
+
+ /* We only support op 0 now, return error if op is non-zero.*/
+ if (op)
+ return -EINVAL;
+
+ /* Check for overflow */
+ if (addr + len < addr)
+ return -EFAULT;
+
+ /*
+ * Verify that the specified address region actually belongs
+ * to this process.
+ */
+ vma = find_vma(current->mm, addr);
+ if (vma == NULL || addr < vma->vm_start || addr + len > vma->vm_end)
+ return -EFAULT;
+
+ flush_cache_range(vma, addr, addr + len);
+
+ return 0;
+}
+
+asmlinkage int sys_getpagesize(void)
+{
+ return PAGE_SIZE;
+}
diff --git a/arch/nios2/kernel/syscall_table.c b/arch/nios2/kernel/syscall_table.c
new file mode 100644
index 0000000..06e6ac1
--- /dev/null
+++ b/arch/nios2/kernel/syscall_table.c
@@ -0,0 +1,29 @@
+/*
+ * Copyright Altera Corporation (C) 2013. All rights reserved
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/syscalls.h>
+#include <linux/signal.h>
+#include <linux/unistd.h>
+
+#include <asm/syscalls.h>
+
+#undef __SYSCALL
+#define __SYSCALL(nr, call) [nr] = (call),
+
+void *sys_call_table[__NR_syscalls] = {
+#include <asm/unistd.h>
+};
diff --git a/arch/nios2/kernel/time.c b/arch/nios2/kernel/time.c
new file mode 100644
index 0000000..7f45474
--- /dev/null
+++ b/arch/nios2/kernel/time.c
@@ -0,0 +1,308 @@
+/*
+ * Copyright (C) 2013-2014 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/interrupt.h>
+#include <linux/clockchips.h>
+#include <linux/clocksource.h>
+#include <linux/delay.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/of_irq.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+
+#define ALTERA_TIMER_STATUS_REG 0
+#define ALTERA_TIMER_CONTROL_REG 4
+#define ALTERA_TIMER_PERIODL_REG 8
+#define ALTERA_TIMER_PERIODH_REG 12
+#define ALTERA_TIMER_SNAPL_REG 16
+#define ALTERA_TIMER_SNAPH_REG 20
+
+#define ALTERA_TIMER_CONTROL_ITO_MSK (0x1)
+#define ALTERA_TIMER_CONTROL_CONT_MSK (0x2)
+#define ALTERA_TIMER_CONTROL_START_MSK (0x4)
+#define ALTERA_TIMER_CONTROL_STOP_MSK (0x8)
+
+struct nios2_timer {
+ void __iomem *base;
+ unsigned long freq;
+};
+
+struct nios2_clockevent_dev {
+ struct nios2_timer timer;
+ struct clock_event_device ced;
+};
+
+struct nios2_clocksource {
+ struct nios2_timer timer;
+ struct clocksource cs;
+};
+
+static inline struct nios2_clockevent_dev *
+ to_nios2_clkevent(struct clock_event_device *evt)
+{
+ return container_of(evt, struct nios2_clockevent_dev, ced);
+}
+
+static inline struct nios2_clocksource *
+ to_nios2_clksource(struct clocksource *cs)
+{
+ return container_of(cs, struct nios2_clocksource, cs);
+}
+
+static u16 timer_readw(struct nios2_timer *timer, u32 offs)
+{
+ return readw(timer->base + offs);
+}
+
+static void timer_writew(struct nios2_timer *timer, u16 val, u32 offs)
+{
+ writew(val, timer->base + offs);
+}
+
+static inline unsigned long read_timersnapshot(struct nios2_timer *timer)
+{
+ unsigned long count;
+
+ timer_writew(timer, 0, ALTERA_TIMER_SNAPL_REG);
+ count = timer_readw(timer, ALTERA_TIMER_SNAPH_REG) << 16 |
+ timer_readw(timer, ALTERA_TIMER_SNAPL_REG);
+
+ return count;
+}
+
+static cycle_t nios2_timer_read(struct clocksource *cs)
+{
+ struct nios2_clocksource *nios2_cs = to_nios2_clksource(cs);
+ unsigned long flags;
+ u32 count;
+
+ local_irq_save(flags);
+ count = read_timersnapshot(&nios2_cs->timer);
+ local_irq_restore(flags);
+
+ /* Counter is counting down */
+ return ~count;
+}
+
+static struct nios2_clocksource nios2_cs = {
+ .cs = {
+ .name = "nios2-clksrc",
+ .rating = 250,
+ .read = nios2_timer_read,
+ .mask = CLOCKSOURCE_MASK(32),
+ .flags = CLOCK_SOURCE_IS_CONTINUOUS,
+ },
+};
+
+cycles_t get_cycles(void)
+{
+ return nios2_timer_read(&nios2_cs.cs);
+}
+
+static void nios2_timer_start(struct nios2_timer *timer)
+{
+ u16 ctrl;
+
+ ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG);
+ ctrl |= ALTERA_TIMER_CONTROL_START_MSK;
+ timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG);
+}
+
+static void nios2_timer_stop(struct nios2_timer *timer)
+{
+ u16 ctrl;
+
+ ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG);
+ ctrl |= ALTERA_TIMER_CONTROL_STOP_MSK;
+ timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG);
+}
+
+static void nios2_timer_config(struct nios2_timer *timer, unsigned long period,
+ enum clock_event_mode mode)
+{
+ u16 ctrl;
+
+ /* The timer's actual period is one cycle greater than the value
+ * stored in the period register. */
+ period--;
+
+ ctrl = timer_readw(timer, ALTERA_TIMER_CONTROL_REG);
+ /* stop counter */
+ timer_writew(timer, ctrl | ALTERA_TIMER_CONTROL_STOP_MSK,
+ ALTERA_TIMER_CONTROL_REG);
+
+ /* write new count */
+ timer_writew(timer, period, ALTERA_TIMER_PERIODL_REG);
+ timer_writew(timer, period >> 16, ALTERA_TIMER_PERIODH_REG);
+
+ ctrl |= ALTERA_TIMER_CONTROL_START_MSK | ALTERA_TIMER_CONTROL_ITO_MSK;
+ if (mode == CLOCK_EVT_MODE_PERIODIC)
+ ctrl |= ALTERA_TIMER_CONTROL_CONT_MSK;
+ else
+ ctrl &= ~ALTERA_TIMER_CONTROL_CONT_MSK;
+ timer_writew(timer, ctrl, ALTERA_TIMER_CONTROL_REG);
+}
+
+static int nios2_timer_set_next_event(unsigned long delta,
+ struct clock_event_device *evt)
+{
+ struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
+
+ nios2_timer_config(&nios2_ced->timer, delta, evt->mode);
+
+ return 0;
+}
+
+static void nios2_timer_set_mode(enum clock_event_mode mode,
+ struct clock_event_device *evt)
+{
+ unsigned long period;
+ struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
+ struct nios2_timer *timer = &nios2_ced->timer;
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ period = DIV_ROUND_UP(timer->freq, HZ);
+ nios2_timer_config(timer, period, CLOCK_EVT_MODE_PERIODIC);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ nios2_timer_stop(timer);
+ break;
+ case CLOCK_EVT_MODE_RESUME:
+ nios2_timer_start(timer);
+ break;
+ }
+}
+
+irqreturn_t timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = (struct clock_event_device *) dev_id;
+ struct nios2_clockevent_dev *nios2_ced = to_nios2_clkevent(evt);
+
+ /* Clear the interrupt condition */
+ timer_writew(&nios2_ced->timer, 0, ALTERA_TIMER_STATUS_REG);
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static void __init nios2_timer_get_base_and_freq(struct device_node *np,
+ void __iomem **base, u32 *freq)
+{
+ *base = of_iomap(np, 0);
+ if (!*base)
+ panic("Unable to map reg for %s\n", np->name);
+
+ if (of_property_read_u32(np, "clock-frequency", freq))
+ panic("Unable to get %s clock frequency\n", np->name);
+}
+
+static struct nios2_clockevent_dev nios2_ce = {
+ .ced = {
+ .name = "nios2-clkevent",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .rating = 250,
+ .shift = 32,
+ .set_next_event = nios2_timer_set_next_event,
+ .set_mode = nios2_timer_set_mode,
+ },
+};
+
+static __init void nios2_clockevent_init(struct device_node *timer)
+{
+ void __iomem *iobase;
+ u32 freq;
+ int irq;
+
+ nios2_timer_get_base_and_freq(timer, &iobase, &freq);
+
+ irq = irq_of_parse_and_map(timer, 0);
+ if (!irq)
+ panic("Unable to parse timer irq\n");
+
+ nios2_ce.timer.base = iobase;
+ nios2_ce.timer.freq = freq;
+
+ nios2_ce.ced.cpumask = cpumask_of(0);
+ nios2_ce.ced.irq = irq;
+
+ nios2_timer_stop(&nios2_ce.timer);
+ /* clear pending interrupt */
+ timer_writew(&nios2_ce.timer, 0, ALTERA_TIMER_STATUS_REG);
+
+ if (request_irq(irq, timer_interrupt, IRQF_TIMER, timer->name,
+ &nios2_ce.ced))
+ panic("Unable to setup timer irq\n");
+
+ clockevents_config_and_register(&nios2_ce.ced, freq, 1, ULONG_MAX);
+}
+
+static __init void nios2_clocksource_init(struct device_node *timer)
+{
+ unsigned int ctrl;
+ void __iomem *iobase;
+ u32 freq;
+
+ nios2_timer_get_base_and_freq(timer, &iobase, &freq);
+
+ nios2_cs.timer.base = iobase;
+ nios2_cs.timer.freq = freq;
+
+ clocksource_register_hz(&nios2_cs.cs, freq);
+
+ timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODL_REG);
+ timer_writew(&nios2_cs.timer, USHRT_MAX, ALTERA_TIMER_PERIODH_REG);
+
+ /* interrupt disable + continuous + start */
+ ctrl = ALTERA_TIMER_CONTROL_CONT_MSK | ALTERA_TIMER_CONTROL_START_MSK;
+ timer_writew(&nios2_cs.timer, ctrl, ALTERA_TIMER_CONTROL_REG);
+
+ /* Calibrate the delay loop directly */
+ lpj_fine = freq / HZ;
+}
+
+/*
+ * The first timer instance will use as a clockevent. If there are two or
+ * more instances, the second one gets used as clocksource and all
+ * others are unused.
+*/
+static void __init nios2_time_init(struct device_node *timer)
+{
+ static int num_called;
+
+ switch (num_called) {
+ case 0:
+ nios2_clockevent_init(timer);
+ break;
+ case 1:
+ nios2_clocksource_init(timer);
+ break;
+ default:
+ break;
+ }
+
+ num_called++;
+}
+
+void read_persistent_clock(struct timespec *ts)
+{
+ ts->tv_sec = mktime(2007, 1, 1, 0, 0, 0);
+ ts->tv_nsec = 0;
+}
+
+void __init time_init(void)
+{
+ clocksource_of_init();
+}
+
+CLOCKSOURCE_OF_DECLARE(nios2_timer, "altr,timer-1.0", nios2_time_init);
diff --git a/arch/nios2/kernel/traps.c b/arch/nios2/kernel/traps.c
new file mode 100644
index 0000000..b7b97641
--- /dev/null
+++ b/arch/nios2/kernel/traps.c
@@ -0,0 +1,185 @@
+/*
+ * Hardware exception handling
+ *
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ * Copyright (C) 2001 Vic Phillips
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/signal.h>
+#include <linux/export.h>
+#include <linux/mm.h>
+#include <linux/ptrace.h>
+
+#include <asm/traps.h>
+#include <asm/sections.h>
+#include <asm/uaccess.h>
+
+static DEFINE_SPINLOCK(die_lock);
+
+void die(const char *str, struct pt_regs *regs, long err)
+{
+ console_verbose();
+ spin_lock_irq(&die_lock);
+ pr_warn("Oops: %s, sig: %ld\n", str, err);
+ show_regs(regs);
+ spin_unlock_irq(&die_lock);
+ /*
+ * do_exit() should take care of panic'ing from an interrupt
+ * context so we don't handle it here
+ */
+ do_exit(err);
+}
+
+void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr)
+{
+ siginfo_t info;
+
+ if (!user_mode(regs))
+ die("Exception in kernel mode", regs, signo);
+
+ info.si_signo = signo;
+ info.si_errno = 0;
+ info.si_code = code;
+ info.si_addr = (void __user *) addr;
+ force_sig_info(signo, &info, current);
+}
+
+/*
+ * The show_stack is an external API which we do not use ourselves.
+ */
+
+int kstack_depth_to_print = 48;
+
+void show_stack(struct task_struct *task, unsigned long *stack)
+{
+ unsigned long *endstack, addr;
+ int i;
+
+ if (!stack) {
+ if (task)
+ stack = (unsigned long *)task->thread.ksp;
+ else
+ stack = (unsigned long *)&stack;
+ }
+
+ addr = (unsigned long) stack;
+ endstack = (unsigned long *) PAGE_ALIGN(addr);
+
+ pr_emerg("Stack from %08lx:", (unsigned long)stack);
+ for (i = 0; i < kstack_depth_to_print; i++) {
+ if (stack + 1 > endstack)
+ break;
+ if (i % 8 == 0)
+ pr_emerg("\n ");
+ pr_emerg(" %08lx", *stack++);
+ }
+
+ pr_emerg("\nCall Trace:");
+ i = 0;
+ while (stack + 1 <= endstack) {
+ addr = *stack++;
+ /*
+ * If the address is either in the text segment of the
+ * kernel, or in the region which contains vmalloc'ed
+ * memory, it *may* be the address of a calling
+ * routine; if so, print it so that someone tracing
+ * down the cause of the crash will be able to figure
+ * out the call path that was taken.
+ */
+ if (((addr >= (unsigned long) _stext) &&
+ (addr <= (unsigned long) _etext))) {
+ if (i % 4 == 0)
+ pr_emerg("\n ");
+ pr_emerg(" [<%08lx>]", addr);
+ i++;
+ }
+ }
+ pr_emerg("\n");
+}
+
+void __init trap_init(void)
+{
+ /* Nothing to do here */
+}
+
+/* Breakpoint handler */
+asmlinkage void breakpoint_c(struct pt_regs *fp)
+{
+ /*
+ * The breakpoint entry code has moved the PC on by 4 bytes, so we must
+ * move it back. This could be done on the host but we do it here
+ * because monitor.S of JTAG gdbserver does it too.
+ */
+ fp->ea -= 4;
+ _exception(SIGTRAP, fp, TRAP_BRKPT, fp->ea);
+}
+
+#ifndef CONFIG_NIOS2_ALIGNMENT_TRAP
+/* Alignment exception handler */
+asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause)
+{
+ unsigned long addr = RDCTL(CTL_BADADDR);
+
+ cause >>= 2;
+ fp->ea -= 4;
+
+ if (fixup_exception(fp))
+ return;
+
+ if (!user_mode(fp)) {
+ pr_alert("Unaligned access from kernel mode, this might be a hardware\n");
+ pr_alert("problem, dump registers and restart the instruction\n");
+ pr_alert(" BADADDR 0x%08lx\n", addr);
+ pr_alert(" cause %d\n", cause);
+ pr_alert(" op-code 0x%08lx\n", *(unsigned long *)(fp->ea));
+ show_regs(fp);
+ return;
+ }
+
+ _exception(SIGBUS, fp, BUS_ADRALN, addr);
+}
+#endif /* CONFIG_NIOS2_ALIGNMENT_TRAP */
+
+/* Illegal instruction handler */
+asmlinkage void handle_illegal_c(struct pt_regs *fp)
+{
+ fp->ea -= 4;
+ _exception(SIGILL, fp, ILL_ILLOPC, fp->ea);
+}
+
+/* Supervisor instruction handler */
+asmlinkage void handle_supervisor_instr(struct pt_regs *fp)
+{
+ fp->ea -= 4;
+ _exception(SIGILL, fp, ILL_PRVOPC, fp->ea);
+}
+
+/* Division error handler */
+asmlinkage void handle_diverror_c(struct pt_regs *fp)
+{
+ fp->ea -= 4;
+ _exception(SIGFPE, fp, FPE_INTDIV, fp->ea);
+}
+
+/* Unhandled exception handler */
+asmlinkage void unhandled_exception(struct pt_regs *regs, int cause)
+{
+ unsigned long addr = RDCTL(CTL_BADADDR);
+
+ cause /= 4;
+
+ pr_emerg("Unhandled exception #%d in %s mode (badaddr=0x%08lx)\n",
+ cause, user_mode(regs) ? "user" : "kernel", addr);
+
+ regs->ea -= 4;
+ show_regs(regs);
+
+ pr_emerg("opcode: 0x%08lx\n", *(unsigned long *)(regs->ea));
+}
diff --git a/arch/nios2/kernel/vmlinux.lds.S b/arch/nios2/kernel/vmlinux.lds.S
new file mode 100644
index 0000000..326fab4
--- /dev/null
+++ b/arch/nios2/kernel/vmlinux.lds.S
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2009 Thomas Chou <thomas@wytron.com.tw>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+#include <asm/page.h>
+#include <asm-generic/vmlinux.lds.h>
+#include <asm/cache.h>
+#include <asm/thread_info.h>
+
+OUTPUT_FORMAT("elf32-littlenios2", "elf32-littlenios2", "elf32-littlenios2")
+
+OUTPUT_ARCH(nios)
+ENTRY(_start) /* Defined in head.S */
+
+jiffies = jiffies_64;
+
+SECTIONS
+{
+ . = CONFIG_NIOS2_MEM_BASE | CONFIG_NIOS2_KERNEL_REGION_BASE;
+
+ _text = .;
+ _stext = .;
+ HEAD_TEXT_SECTION
+ .text : {
+ TEXT_TEXT
+ SCHED_TEXT
+ LOCK_TEXT
+ IRQENTRY_TEXT
+ KPROBES_TEXT
+ } =0
+ _etext = .;
+
+ .got : {
+ *(.got.plt)
+ *(.igot.plt)
+ *(.got)
+ *(.igot)
+ }
+
+ EXCEPTION_TABLE(L1_CACHE_BYTES)
+
+ . = ALIGN(PAGE_SIZE);
+ __init_begin = .;
+ INIT_TEXT_SECTION(PAGE_SIZE)
+ INIT_DATA_SECTION(PAGE_SIZE)
+ PERCPU_SECTION(L1_CACHE_BYTES)
+ __init_end = .;
+
+ _sdata = .;
+ RO_DATA_SECTION(PAGE_SIZE)
+ RW_DATA_SECTION(L1_CACHE_BYTES, PAGE_SIZE, THREAD_SIZE)
+ _edata = .;
+
+ BSS_SECTION(0, 0, 0)
+ _end = .;
+
+ STABS_DEBUG
+ DWARF_DEBUG
+ NOTES
+
+ DISCARDS
+}
diff --git a/arch/nios2/lib/Makefile b/arch/nios2/lib/Makefile
new file mode 100644
index 0000000..5572566
--- /dev/null
+++ b/arch/nios2/lib/Makefile
@@ -0,0 +1,8 @@
+#
+# Makefile for Nios2-specific library files.
+#
+
+lib-y += delay.o
+lib-y += memcpy.o
+lib-y += memmove.o
+lib-y += memset.o
diff --git a/arch/nios2/lib/delay.c b/arch/nios2/lib/delay.c
new file mode 100644
index 0000000..088119c
--- /dev/null
+++ b/arch/nios2/lib/delay.c
@@ -0,0 +1,52 @@
+/* Copyright Altera Corporation (C) 2014. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License, version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#include <linux/module.h>
+#include <asm/delay.h>
+#include <asm/param.h>
+#include <asm/processor.h>
+#include <asm/timex.h>
+
+void __delay(unsigned long cycles)
+{
+ cycles_t start = get_cycles();
+
+ while ((get_cycles() - start) < cycles)
+ cpu_relax();
+}
+EXPORT_SYMBOL(__delay);
+
+void __const_udelay(unsigned long xloops)
+{
+ u64 loops;
+
+ loops = (u64)xloops * loops_per_jiffy * HZ;
+
+ __delay(loops >> 32);
+}
+EXPORT_SYMBOL(__const_udelay);
+
+void __udelay(unsigned long usecs)
+{
+ __const_udelay(usecs * 0x10C7UL); /* 2**32 / 1000000 (rounded up) */
+}
+EXPORT_SYMBOL(__udelay);
+
+void __ndelay(unsigned long nsecs)
+{
+ __const_udelay(nsecs * 0x5UL); /* 2**32 / 1000000000 (rounded up) */
+}
+EXPORT_SYMBOL(__ndelay);
diff --git a/arch/nios2/lib/memcpy.c b/arch/nios2/lib/memcpy.c
new file mode 100644
index 0000000..1715f5d
--- /dev/null
+++ b/arch/nios2/lib/memcpy.c
@@ -0,0 +1,202 @@
+/* Extracted from GLIBC memcpy.c and memcopy.h, which is:
+ Copyright (C) 1991, 1992, 1993, 1997, 2004 Free Software Foundation, Inc.
+ This file is part of the GNU C Library.
+ Contributed by Torbjorn Granlund (tege@sics.se).
+
+ The GNU C Library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU Lesser General Public
+ License as published by the Free Software Foundation; either
+ version 2.1 of the License, or (at your option) any later version.
+
+ The GNU C Library is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ Lesser General Public License for more details.
+
+ You should have received a copy of the GNU Lesser General Public
+ License along with the GNU C Library; if not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include <linux/types.h>
+
+/* Type to use for aligned memory operations.
+ This should normally be the biggest type supported by a single load
+ and store. */
+#define op_t unsigned long int
+#define OPSIZ (sizeof(op_t))
+
+/* Optimal type for storing bytes in registers. */
+#define reg_char char
+
+#define MERGE(w0, sh_1, w1, sh_2) (((w0) >> (sh_1)) | ((w1) << (sh_2)))
+
+/* Copy exactly NBYTES bytes from SRC_BP to DST_BP,
+ without any assumptions about alignment of the pointers. */
+#define BYTE_COPY_FWD(dst_bp, src_bp, nbytes) \
+do { \
+ size_t __nbytes = (nbytes); \
+ while (__nbytes > 0) { \
+ unsigned char __x = ((unsigned char *) src_bp)[0]; \
+ src_bp += 1; \
+ __nbytes -= 1; \
+ ((unsigned char *) dst_bp)[0] = __x; \
+ dst_bp += 1; \
+ } \
+} while (0)
+
+/* Copy *up to* NBYTES bytes from SRC_BP to DST_BP, with
+ the assumption that DST_BP is aligned on an OPSIZ multiple. If
+ not all bytes could be easily copied, store remaining number of bytes
+ in NBYTES_LEFT, otherwise store 0. */
+/* extern void _wordcopy_fwd_aligned __P ((long int, long int, size_t)); */
+/* extern void _wordcopy_fwd_dest_aligned __P ((long int, long int, size_t)); */
+#define WORD_COPY_FWD(dst_bp, src_bp, nbytes_left, nbytes) \
+do { \
+ if (src_bp % OPSIZ == 0) \
+ _wordcopy_fwd_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);\
+ else \
+ _wordcopy_fwd_dest_aligned(dst_bp, src_bp, (nbytes) / OPSIZ);\
+ src_bp += (nbytes) & -OPSIZ; \
+ dst_bp += (nbytes) & -OPSIZ; \
+ (nbytes_left) = (nbytes) % OPSIZ; \
+} while (0)
+
+
+/* Threshold value for when to enter the unrolled loops. */
+#define OP_T_THRES 16
+
+/* _wordcopy_fwd_aligned -- Copy block beginning at SRCP to
+ block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
+ Both SRCP and DSTP should be aligned for memory operations on `op_t's. */
+/* stream-lined (read x8 + write x8) */
+static void _wordcopy_fwd_aligned(long int dstp, long int srcp, size_t len)
+{
+ while (len > 7) {
+ register op_t a0, a1, a2, a3, a4, a5, a6, a7;
+
+ a0 = ((op_t *) srcp)[0];
+ a1 = ((op_t *) srcp)[1];
+ a2 = ((op_t *) srcp)[2];
+ a3 = ((op_t *) srcp)[3];
+ a4 = ((op_t *) srcp)[4];
+ a5 = ((op_t *) srcp)[5];
+ a6 = ((op_t *) srcp)[6];
+ a7 = ((op_t *) srcp)[7];
+ ((op_t *) dstp)[0] = a0;
+ ((op_t *) dstp)[1] = a1;
+ ((op_t *) dstp)[2] = a2;
+ ((op_t *) dstp)[3] = a3;
+ ((op_t *) dstp)[4] = a4;
+ ((op_t *) dstp)[5] = a5;
+ ((op_t *) dstp)[6] = a6;
+ ((op_t *) dstp)[7] = a7;
+
+ srcp += 8 * OPSIZ;
+ dstp += 8 * OPSIZ;
+ len -= 8;
+ }
+ while (len > 0) {
+ *(op_t *)dstp = *(op_t *)srcp;
+
+ srcp += OPSIZ;
+ dstp += OPSIZ;
+ len -= 1;
+ }
+}
+
+/* _wordcopy_fwd_dest_aligned -- Copy block beginning at SRCP to
+ block beginning at DSTP with LEN `op_t' words (not LEN bytes!).
+ DSTP should be aligned for memory operations on `op_t's, but SRCP must
+ *not* be aligned. */
+/* stream-lined (read x4 + write x4) */
+static void _wordcopy_fwd_dest_aligned(long int dstp, long int srcp,
+ size_t len)
+{
+ op_t ap;
+ int sh_1, sh_2;
+
+ /* Calculate how to shift a word read at the memory operation
+ aligned srcp to make it aligned for copy. */
+
+ sh_1 = 8 * (srcp % OPSIZ);
+ sh_2 = 8 * OPSIZ - sh_1;
+
+ /* Make SRCP aligned by rounding it down to the beginning of the `op_t'
+ it points in the middle of. */
+ srcp &= -OPSIZ;
+ ap = ((op_t *) srcp)[0];
+ srcp += OPSIZ;
+
+ while (len > 3) {
+ op_t a0, a1, a2, a3;
+
+ a0 = ((op_t *) srcp)[0];
+ a1 = ((op_t *) srcp)[1];
+ a2 = ((op_t *) srcp)[2];
+ a3 = ((op_t *) srcp)[3];
+ ((op_t *) dstp)[0] = MERGE(ap, sh_1, a0, sh_2);
+ ((op_t *) dstp)[1] = MERGE(a0, sh_1, a1, sh_2);
+ ((op_t *) dstp)[2] = MERGE(a1, sh_1, a2, sh_2);
+ ((op_t *) dstp)[3] = MERGE(a2, sh_1, a3, sh_2);
+
+ ap = a3;
+ srcp += 4 * OPSIZ;
+ dstp += 4 * OPSIZ;
+ len -= 4;
+ }
+ while (len > 0) {
+ register op_t a0;
+
+ a0 = ((op_t *) srcp)[0];
+ ((op_t *) dstp)[0] = MERGE(ap, sh_1, a0, sh_2);
+
+ ap = a0;
+ srcp += OPSIZ;
+ dstp += OPSIZ;
+ len -= 1;
+ }
+}
+
+void *memcpy(void *dstpp, const void *srcpp, size_t len)
+{
+ unsigned long int dstp = (long int) dstpp;
+ unsigned long int srcp = (long int) srcpp;
+
+ /* Copy from the beginning to the end. */
+
+ /* If there not too few bytes to copy, use word copy. */
+ if (len >= OP_T_THRES) {
+ /* Copy just a few bytes to make DSTP aligned. */
+ len -= (-dstp) % OPSIZ;
+ BYTE_COPY_FWD(dstp, srcp, (-dstp) % OPSIZ);
+
+ /* Copy whole pages from SRCP to DSTP by virtual address
+ manipulation, as much as possible. */
+
+ /* PAGE_COPY_FWD_MAYBE (dstp, srcp, len, len); */
+
+ /* Copy from SRCP to DSTP taking advantage of the known
+ alignment of DSTP. Number of bytes remaining is put in the
+ third argument, i.e. in LEN. This number may vary from
+ machine to machine. */
+
+ WORD_COPY_FWD(dstp, srcp, len, len);
+
+ /* Fall out and copy the tail. */
+ }
+
+ /* There are just a few bytes to copy. Use byte memory operations. */
+ BYTE_COPY_FWD(dstp, srcp, len);
+
+ return dstpp;
+}
+
+void *memcpyb(void *dstpp, const void *srcpp, unsigned len)
+{
+ unsigned long int dstp = (long int) dstpp;
+ unsigned long int srcp = (long int) srcpp;
+
+ BYTE_COPY_FWD(dstp, srcp, len);
+
+ return dstpp;
+}
diff --git a/arch/nios2/lib/memmove.c b/arch/nios2/lib/memmove.c
new file mode 100644
index 0000000..c65ef51
--- /dev/null
+++ b/arch/nios2/lib/memmove.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+#ifdef __HAVE_ARCH_MEMMOVE
+void *memmove(void *d, const void *s, size_t count)
+{
+ unsigned long dst, src;
+
+ if (!count)
+ return d;
+
+ if (d < s) {
+ dst = (unsigned long) d;
+ src = (unsigned long) s;
+
+ if ((count < 8) || ((dst ^ src) & 3))
+ goto restup;
+
+ if (dst & 1) {
+ *(char *)dst++ = *(char *)src++;
+ count--;
+ }
+ if (dst & 2) {
+ *(short *)dst = *(short *)src;
+ src += 2;
+ dst += 2;
+ count -= 2;
+ }
+ while (count > 3) {
+ *(long *)dst = *(long *)src;
+ src += 4;
+ dst += 4;
+ count -= 4;
+ }
+restup:
+ while (count--)
+ *(char *)dst++ = *(char *)src++;
+ } else {
+ dst = (unsigned long) d + count;
+ src = (unsigned long) s + count;
+
+ if ((count < 8) || ((dst ^ src) & 3))
+ goto restdown;
+
+ if (dst & 1) {
+ src--;
+ dst--;
+ count--;
+ *(char *)dst = *(char *)src;
+ }
+ if (dst & 2) {
+ src -= 2;
+ dst -= 2;
+ count -= 2;
+ *(short *)dst = *(short *)src;
+ }
+ while (count > 3) {
+ src -= 4;
+ dst -= 4;
+ count -= 4;
+ *(long *)dst = *(long *)src;
+ }
+restdown:
+ while (count--) {
+ src--;
+ dst--;
+ *(char *)dst = *(char *)src;
+ }
+ }
+
+ return d;
+}
+#endif /* __HAVE_ARCH_MEMMOVE */
diff --git a/arch/nios2/lib/memset.c b/arch/nios2/lib/memset.c
new file mode 100644
index 0000000..65e9780
--- /dev/null
+++ b/arch/nios2/lib/memset.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/string.h>
+
+#ifdef __HAVE_ARCH_MEMSET
+void *memset(void *s, int c, size_t count)
+{
+ int destptr, charcnt, dwordcnt, fill8reg, wrkrega;
+
+ if (!count)
+ return s;
+
+ c &= 0xFF;
+
+ if (count <= 8) {
+ char *xs = (char *) s;
+
+ while (count--)
+ *xs++ = c;
+ return s;
+ }
+
+ __asm__ __volatile__ (
+ /* fill8 %3, %5 (c & 0xff) */
+ " slli %4, %5, 8\n"
+ " or %4, %4, %5\n"
+ " slli %3, %4, 16\n"
+ " or %3, %3, %4\n"
+ /* Word-align %0 (s) if necessary */
+ " andi %4, %0, 0x01\n"
+ " beq %4, zero, 1f\n"
+ " addi %1, %1, -1\n"
+ " stb %3, 0(%0)\n"
+ " addi %0, %0, 1\n"
+ "1: mov %2, %1\n"
+ /* Dword-align %0 (s) if necessary */
+ " andi %4, %0, 0x02\n"
+ " beq %4, zero, 2f\n"
+ " addi %1, %1, -2\n"
+ " sth %3, 0(%0)\n"
+ " addi %0, %0, 2\n"
+ " mov %2, %1\n"
+ /* %1 and %2 are how many more bytes to set */
+ "2: srli %2, %2, 2\n"
+ /* %2 is how many dwords to set */
+ "3: stw %3, 0(%0)\n"
+ " addi %0, %0, 4\n"
+ " addi %2, %2, -1\n"
+ " bne %2, zero, 3b\n"
+ /* store residual word and/or byte if necessary */
+ " andi %4, %1, 0x02\n"
+ " beq %4, zero, 4f\n"
+ " sth %3, 0(%0)\n"
+ " addi %0, %0, 2\n"
+ /* store residual byte if necessary */
+ "4: andi %4, %1, 0x01\n"
+ " beq %4, zero, 5f\n"
+ " stb %3, 0(%0)\n"
+ "5:\n"
+ : "=r" (destptr), /* %0 Output */
+ "=r" (charcnt), /* %1 Output */
+ "=r" (dwordcnt), /* %2 Output */
+ "=r" (fill8reg), /* %3 Output */
+ "=r" (wrkrega) /* %4 Output */
+ : "r" (c), /* %5 Input */
+ "0" (s), /* %0 Input/Output */
+ "1" (count) /* %1 Input/Output */
+ : "memory" /* clobbered */
+ );
+
+ return s;
+}
+#endif /* __HAVE_ARCH_MEMSET */
diff --git a/arch/nios2/mm/Makefile b/arch/nios2/mm/Makefile
new file mode 100644
index 0000000..3cbd084
--- /dev/null
+++ b/arch/nios2/mm/Makefile
@@ -0,0 +1,14 @@
+#
+# Makefile for the Nios2-specific parts of the memory manager.
+#
+
+obj-y += cacheflush.o
+obj-y += dma-mapping.o
+obj-y += extable.o
+obj-y += fault.o
+obj-y += init.o
+obj-y += ioremap.o
+obj-y += mmu_context.o
+obj-y += pgtable.o
+obj-y += tlb.o
+obj-y += uaccess.o
diff --git a/arch/nios2/mm/cacheflush.c b/arch/nios2/mm/cacheflush.c
new file mode 100644
index 0000000..2ae482b4
--- /dev/null
+++ b/arch/nios2/mm/cacheflush.c
@@ -0,0 +1,271 @@
+/*
+ * 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) 2009, Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ */
+
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/fs.h>
+
+#include <asm/cacheflush.h>
+#include <asm/cpuinfo.h>
+
+static void __flush_dcache(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(cpuinfo.dcache_line_size - 1);
+ end += (cpuinfo.dcache_line_size - 1);
+ end &= ~(cpuinfo.dcache_line_size - 1);
+
+ if (end > start + cpuinfo.dcache_size)
+ end = start + cpuinfo.dcache_size;
+
+ for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) {
+ __asm__ __volatile__ (" flushda 0(%0)\n"
+ : /* Outputs */
+ : /* Inputs */ "r"(addr)
+ /* : No clobber */);
+ }
+}
+
+static void __flush_dcache_all(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(cpuinfo.dcache_line_size - 1);
+ end += (cpuinfo.dcache_line_size - 1);
+ end &= ~(cpuinfo.dcache_line_size - 1);
+
+ if (end > start + cpuinfo.dcache_size)
+ end = start + cpuinfo.dcache_size;
+
+ for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) {
+ __asm__ __volatile__ (" flushd 0(%0)\n"
+ : /* Outputs */
+ : /* Inputs */ "r"(addr)
+ /* : No clobber */);
+ }
+}
+
+static void __invalidate_dcache(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(cpuinfo.dcache_line_size - 1);
+ end += (cpuinfo.dcache_line_size - 1);
+ end &= ~(cpuinfo.dcache_line_size - 1);
+
+ if (end > start + cpuinfo.dcache_size)
+ end = start + cpuinfo.dcache_size;
+
+ for (addr = start; addr < end; addr += cpuinfo.dcache_line_size) {
+ __asm__ __volatile__ (" initda 0(%0)\n"
+ : /* Outputs */
+ : /* Inputs */ "r"(addr)
+ /* : No clobber */);
+ }
+}
+
+static void __flush_icache(unsigned long start, unsigned long end)
+{
+ unsigned long addr;
+
+ start &= ~(cpuinfo.icache_line_size - 1);
+ end += (cpuinfo.icache_line_size - 1);
+ end &= ~(cpuinfo.icache_line_size - 1);
+
+ if (end > start + cpuinfo.icache_size)
+ end = start + cpuinfo.icache_size;
+
+ for (addr = start; addr < end; addr += cpuinfo.icache_line_size) {
+ __asm__ __volatile__ (" flushi %0\n"
+ : /* Outputs */
+ : /* Inputs */ "r"(addr)
+ /* : No clobber */);
+ }
+ __asm__ __volatile(" flushp\n");
+}
+
+static void flush_aliases(struct address_space *mapping, struct page *page)
+{
+ struct mm_struct *mm = current->active_mm;
+ struct vm_area_struct *mpnt;
+ pgoff_t pgoff;
+
+ pgoff = page->index;
+
+ flush_dcache_mmap_lock(mapping);
+ vma_interval_tree_foreach(mpnt, &mapping->i_mmap, pgoff, pgoff) {
+ unsigned long offset;
+
+ if (mpnt->vm_mm != mm)
+ continue;
+ if (!(mpnt->vm_flags & VM_MAYSHARE))
+ continue;
+
+ offset = (pgoff - mpnt->vm_pgoff) << PAGE_SHIFT;
+ flush_cache_page(mpnt, mpnt->vm_start + offset,
+ page_to_pfn(page));
+ }
+ flush_dcache_mmap_unlock(mapping);
+}
+
+void flush_cache_all(void)
+{
+ __flush_dcache_all(0, cpuinfo.dcache_size);
+ __flush_icache(0, cpuinfo.icache_size);
+}
+
+void flush_cache_mm(struct mm_struct *mm)
+{
+ flush_cache_all();
+}
+
+void flush_cache_dup_mm(struct mm_struct *mm)
+{
+ flush_cache_all();
+}
+
+void flush_icache_range(unsigned long start, unsigned long end)
+{
+ __flush_icache(start, end);
+}
+
+void flush_dcache_range(unsigned long start, unsigned long end)
+{
+ __flush_dcache(start, end);
+}
+EXPORT_SYMBOL(flush_dcache_range);
+
+void invalidate_dcache_range(unsigned long start, unsigned long end)
+{
+ __invalidate_dcache(start, end);
+}
+EXPORT_SYMBOL(invalidate_dcache_range);
+
+void flush_cache_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ __flush_dcache(start, end);
+ if (vma == NULL || (vma->vm_flags & VM_EXEC))
+ __flush_icache(start, end);
+}
+
+void flush_icache_page(struct vm_area_struct *vma, struct page *page)
+{
+ unsigned long start = (unsigned long) page_address(page);
+ unsigned long end = start + PAGE_SIZE;
+
+ __flush_icache(start, end);
+}
+
+void flush_cache_page(struct vm_area_struct *vma, unsigned long vmaddr,
+ unsigned long pfn)
+{
+ unsigned long start = vmaddr;
+ unsigned long end = start + PAGE_SIZE;
+
+ __flush_dcache(start, end);
+ if (vma->vm_flags & VM_EXEC)
+ __flush_icache(start, end);
+}
+
+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);
+
+ /* Flush this page if there are aliases. */
+ if (mapping && !mapping_mapped(mapping)) {
+ clear_bit(PG_dcache_clean, &page->flags);
+ } else {
+ unsigned long start = (unsigned long)page_address(page);
+
+ __flush_dcache_all(start, start + PAGE_SIZE);
+ if (mapping)
+ flush_aliases(mapping, page);
+ set_bit(PG_dcache_clean, &page->flags);
+ }
+}
+EXPORT_SYMBOL(flush_dcache_page);
+
+void update_mmu_cache(struct vm_area_struct *vma,
+ unsigned long address, pte_t *pte)
+{
+ unsigned long pfn = pte_pfn(*pte);
+ struct page *page;
+
+ if (!pfn_valid(pfn))
+ return;
+
+ /*
+ * The zero page is never written to, so never has any dirty
+ * cache lines, and therefore never needs to be flushed.
+ */
+ page = pfn_to_page(pfn);
+ if (page == ZERO_PAGE(0))
+ return;
+
+ if (!PageReserved(page) &&
+ !test_and_set_bit(PG_dcache_clean, &page->flags)) {
+ unsigned long start = page_to_virt(page);
+ struct address_space *mapping;
+
+ __flush_dcache(start, start + PAGE_SIZE);
+
+ mapping = page_mapping(page);
+ if (mapping)
+ flush_aliases(mapping, page);
+ }
+}
+
+void copy_user_page(void *vto, void *vfrom, unsigned long vaddr,
+ struct page *to)
+{
+ __flush_dcache(vaddr, vaddr + PAGE_SIZE);
+ copy_page(vto, vfrom);
+ __flush_dcache((unsigned long)vto, (unsigned long)vto + PAGE_SIZE);
+}
+
+void clear_user_page(void *addr, unsigned long vaddr, struct page *page)
+{
+ __flush_dcache(vaddr, vaddr + PAGE_SIZE);
+ clear_page(addr);
+ __flush_dcache((unsigned long)addr, (unsigned long)addr + PAGE_SIZE);
+}
+
+void copy_from_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr,
+ void *dst, void *src, int len)
+{
+ flush_cache_page(vma, user_vaddr, page_to_pfn(page));
+ memcpy(dst, src, len);
+ __flush_dcache((unsigned long)src, (unsigned long)src + len);
+ if (vma->vm_flags & VM_EXEC)
+ __flush_icache((unsigned long)src, (unsigned long)src + len);
+}
+
+void copy_to_user_page(struct vm_area_struct *vma, struct page *page,
+ unsigned long user_vaddr,
+ void *dst, void *src, int len)
+{
+ flush_cache_page(vma, user_vaddr, page_to_pfn(page));
+ memcpy(dst, src, len);
+ __flush_dcache((unsigned long)dst, (unsigned long)dst + len);
+ if (vma->vm_flags & VM_EXEC)
+ __flush_icache((unsigned long)dst, (unsigned long)dst + len);
+}
diff --git a/arch/nios2/mm/dma-mapping.c b/arch/nios2/mm/dma-mapping.c
new file mode 100644
index 0000000..ac5da75
--- /dev/null
+++ b/arch/nios2/mm/dma-mapping.c
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * Based on DMA code from MIPS.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/types.h>
+#include <linux/mm.h>
+#include <linux/export.h>
+#include <linux/string.h>
+#include <linux/scatterlist.h>
+#include <linux/dma-mapping.h>
+#include <linux/io.h>
+#include <linux/cache.h>
+#include <asm/cacheflush.h>
+
+
+void *dma_alloc_coherent(struct device *dev, size_t size,
+ dma_addr_t *dma_handle, gfp_t gfp)
+{
+ void *ret;
+
+ /* ignore region specifiers */
+ gfp &= ~(__GFP_DMA | __GFP_HIGHMEM);
+
+ /* optimized page clearing */
+ gfp |= __GFP_ZERO;
+
+ if (dev == NULL || (dev->coherent_dma_mask < 0xffffffff))
+ gfp |= GFP_DMA;
+
+ ret = (void *) __get_free_pages(gfp, get_order(size));
+ if (ret != NULL) {
+ *dma_handle = virt_to_phys(ret);
+ flush_dcache_range((unsigned long) ret,
+ (unsigned long) ret + size);
+ ret = UNCAC_ADDR(ret);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL(dma_alloc_coherent);
+
+void dma_free_coherent(struct device *dev, size_t size, void *vaddr,
+ dma_addr_t dma_handle)
+{
+ unsigned long addr = (unsigned long) CAC_ADDR((unsigned long) vaddr);
+
+ free_pages(addr, get_order(size));
+}
+EXPORT_SYMBOL(dma_free_coherent);
+
+int dma_map_sg(struct device *dev, struct scatterlist *sg, int nents,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ for_each_sg(sg, sg, nents, i) {
+ void *addr;
+
+ addr = sg_virt(sg);
+ if (addr) {
+ __dma_sync_for_device(addr, sg->length, direction);
+ sg->dma_address = sg_phys(sg);
+ }
+ }
+
+ return nents;
+}
+EXPORT_SYMBOL(dma_map_sg);
+
+dma_addr_t dma_map_page(struct device *dev, struct page *page,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ void *addr;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ addr = page_address(page) + offset;
+ __dma_sync_for_device(addr, size, direction);
+
+ return page_to_phys(page) + offset;
+}
+EXPORT_SYMBOL(dma_map_page);
+
+void dma_unmap_page(struct device *dev, dma_addr_t dma_address, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+
+ __dma_sync_for_cpu(phys_to_virt(dma_address), size, direction);
+}
+EXPORT_SYMBOL(dma_unmap_page);
+
+void dma_unmap_sg(struct device *dev, struct scatterlist *sg, int nhwentries,
+ enum dma_data_direction direction)
+{
+ void *addr;
+ int i;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ if (direction == DMA_TO_DEVICE)
+ return;
+
+ for_each_sg(sg, sg, nhwentries, i) {
+ addr = sg_virt(sg);
+ if (addr)
+ __dma_sync_for_cpu(addr, sg->length, direction);
+ }
+}
+EXPORT_SYMBOL(dma_unmap_sg);
+
+void dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+
+ __dma_sync_for_cpu(phys_to_virt(dma_handle), size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_cpu);
+
+void dma_sync_single_for_device(struct device *dev, dma_addr_t dma_handle,
+ size_t size, enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+
+ __dma_sync_for_device(phys_to_virt(dma_handle), size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_for_device);
+
+void dma_sync_single_range_for_cpu(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+
+ __dma_sync_for_cpu(phys_to_virt(dma_handle), size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_cpu);
+
+void dma_sync_single_range_for_device(struct device *dev, dma_addr_t dma_handle,
+ unsigned long offset, size_t size,
+ enum dma_data_direction direction)
+{
+ BUG_ON(!valid_dma_direction(direction));
+
+ __dma_sync_for_device(phys_to_virt(dma_handle), size, direction);
+}
+EXPORT_SYMBOL(dma_sync_single_range_for_device);
+
+void dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg, int nelems,
+ enum dma_data_direction direction)
+{
+ int i;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ /* Make sure that gcc doesn't leave the empty loop body. */
+ for_each_sg(sg, sg, nelems, i)
+ __dma_sync_for_cpu(sg_virt(sg), sg->length, direction);
+}
+EXPORT_SYMBOL(dma_sync_sg_for_cpu);
+
+void dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
+ int nelems, enum dma_data_direction direction)
+{
+ int i;
+
+ BUG_ON(!valid_dma_direction(direction));
+
+ /* Make sure that gcc doesn't leave the empty loop body. */
+ for_each_sg(sg, sg, nelems, i)
+ __dma_sync_for_device(sg_virt(sg), sg->length, direction);
+
+}
+EXPORT_SYMBOL(dma_sync_sg_for_device);
diff --git a/arch/nios2/mm/extable.c b/arch/nios2/mm/extable.c
new file mode 100644
index 0000000..4d2fc5a
--- /dev/null
+++ b/arch/nios2/mm/extable.c
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2010, Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009, Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/uaccess.h>
+
+int fixup_exception(struct pt_regs *regs)
+{
+ const struct exception_table_entry *fixup;
+
+ fixup = search_exception_tables(regs->ea);
+ if (fixup) {
+ regs->ea = fixup->fixup;
+ return 1;
+ }
+
+ return 0;
+}
diff --git a/arch/nios2/mm/fault.c b/arch/nios2/mm/fault.c
new file mode 100644
index 0000000..15a0bb5
--- /dev/null
+++ b/arch/nios2/mm/fault.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * based on arch/mips/mm/fault.c which is:
+ *
+ * Copyright (C) 1995-2000 Ralf Baechle
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/module.h>
+#include <linux/uaccess.h>
+#include <linux/ptrace.h>
+
+#include <asm/mmu_context.h>
+#include <asm/traps.h>
+
+#define EXC_SUPERV_INSN_ACCESS 9 /* Supervisor only instruction address */
+#define EXC_SUPERV_DATA_ACCESS 11 /* Supervisor only data address */
+#define EXC_X_PROTECTION_FAULT 13 /* TLB permission violation (x) */
+#define EXC_R_PROTECTION_FAULT 14 /* TLB permission violation (r) */
+#define EXC_W_PROTECTION_FAULT 15 /* TLB permission violation (w) */
+
+/*
+ * This routine handles page faults. It determines the address,
+ * and the problem, and then passes it off to one of the appropriate
+ * routines.
+ */
+asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long cause,
+ unsigned long address)
+{
+ struct vm_area_struct *vma = NULL;
+ struct task_struct *tsk = current;
+ struct mm_struct *mm = tsk->mm;
+ int code = SEGV_MAPERR;
+ int fault;
+ unsigned int flags = 0;
+
+ cause >>= 2;
+
+ /* Restart the instruction */
+ regs->ea -= 4;
+
+ /*
+ * We fault-in kernel-space virtual memory on-demand. The
+ * 'reference' page table is init_mm.pgd.
+ *
+ * NOTE! We MUST NOT take any locks for this case. We may
+ * be in an interrupt or a critical region, and should
+ * only copy the information from the master page table,
+ * nothing more.
+ */
+ if (unlikely(address >= VMALLOC_START && address <= VMALLOC_END)) {
+ if (user_mode(regs))
+ goto bad_area_nosemaphore;
+ else
+ goto vmalloc_fault;
+ }
+
+ if (unlikely(address >= TASK_SIZE))
+ goto bad_area_nosemaphore;
+
+ /*
+ * If we're in an interrupt or have no user
+ * context, we must not take the fault..
+ */
+ if (in_atomic() || !mm)
+ goto bad_area_nosemaphore;
+
+ if (user_mode(regs))
+ flags |= FAULT_FLAG_USER;
+
+ if (!down_read_trylock(&mm->mmap_sem)) {
+ if (!user_mode(regs) && !search_exception_tables(regs->ea))
+ goto bad_area_nosemaphore;
+ down_read(&mm->mmap_sem);
+ }
+
+ vma = find_vma(mm, address);
+ if (!vma)
+ goto bad_area;
+ if (vma->vm_start <= address)
+ goto good_area;
+ if (!(vma->vm_flags & VM_GROWSDOWN))
+ goto bad_area;
+ if (expand_stack(vma, address))
+ goto bad_area;
+/*
+ * Ok, we have a good vm_area for this memory access, so
+ * we can handle it..
+ */
+good_area:
+ code = SEGV_ACCERR;
+
+ switch (cause) {
+ case EXC_SUPERV_INSN_ACCESS:
+ goto bad_area;
+ case EXC_SUPERV_DATA_ACCESS:
+ goto bad_area;
+ case EXC_X_PROTECTION_FAULT:
+ if (!(vma->vm_flags & VM_EXEC))
+ goto bad_area;
+ break;
+ case EXC_R_PROTECTION_FAULT:
+ if (!(vma->vm_flags & VM_READ))
+ goto bad_area;
+ break;
+ case EXC_W_PROTECTION_FAULT:
+ if (!(vma->vm_flags & VM_WRITE))
+ goto bad_area;
+ flags = FAULT_FLAG_WRITE;
+ break;
+ }
+
+survive:
+ /*
+ * If for any reason at all we couldn't handle the fault,
+ * make sure we exit gracefully rather than endlessly redo
+ * the fault.
+ */
+ fault = handle_mm_fault(mm, vma, address, flags);
+ if (unlikely(fault & VM_FAULT_ERROR)) {
+ if (fault & VM_FAULT_OOM)
+ goto out_of_memory;
+ else if (fault & VM_FAULT_SIGBUS)
+ goto do_sigbus;
+ BUG();
+ }
+ if (fault & VM_FAULT_MAJOR)
+ tsk->maj_flt++;
+ else
+ tsk->min_flt++;
+
+ up_read(&mm->mmap_sem);
+ return;
+
+/*
+ * Something tried to access memory that isn't in our memory map..
+ * Fix it, but check if it's kernel or user first..
+ */
+bad_area:
+ up_read(&mm->mmap_sem);
+
+bad_area_nosemaphore:
+ /* User mode accesses just cause a SIGSEGV */
+ if (user_mode(regs)) {
+ pr_alert("%s: unhandled page fault (%d) at 0x%08lx, "
+ "cause %ld\n", current->comm, SIGSEGV, address, cause);
+ show_regs(regs);
+ _exception(SIGSEGV, regs, code, address);
+ return;
+ }
+
+no_context:
+ /* Are we prepared to handle this kernel fault? */
+ if (fixup_exception(regs))
+ return;
+
+ /*
+ * Oops. The kernel tried to access some bad page. We'll have to
+ * terminate things with extreme prejudice.
+ */
+ bust_spinlocks(1);
+
+ pr_alert("Unable to handle kernel %s at virtual address %08lx",
+ address < PAGE_SIZE ? "NULL pointer dereference" :
+ "paging request", address);
+ pr_alert("ea = %08lx, ra = %08lx, cause = %ld\n", regs->ea, regs->ra,
+ cause);
+ panic("Oops");
+ return;
+
+/*
+ * We ran out of memory, or some other thing happened to us that made
+ * us unable to handle the page fault gracefully.
+ */
+out_of_memory:
+ up_read(&mm->mmap_sem);
+ if (is_global_init(tsk)) {
+ yield();
+ down_read(&mm->mmap_sem);
+ goto survive;
+ }
+ if (!user_mode(regs))
+ goto no_context;
+ pagefault_out_of_memory();
+ return;
+
+do_sigbus:
+ up_read(&mm->mmap_sem);
+
+ /* Kernel mode? Handle exceptions or die */
+ if (!user_mode(regs))
+ goto no_context;
+
+ _exception(SIGBUS, regs, BUS_ADRERR, address);
+ return;
+
+vmalloc_fault:
+ {
+ /*
+ * Synchronize this task's top level page-table
+ * with the 'reference' page table.
+ *
+ * Do _not_ use "tsk" here. We might be inside
+ * an interrupt in the middle of a task switch..
+ */
+ int offset = pgd_index(address);
+ pgd_t *pgd, *pgd_k;
+ pud_t *pud, *pud_k;
+ pmd_t *pmd, *pmd_k;
+ pte_t *pte_k;
+
+ pgd = pgd_current + offset;
+ pgd_k = init_mm.pgd + offset;
+
+ if (!pgd_present(*pgd_k))
+ goto no_context;
+ set_pgd(pgd, *pgd_k);
+
+ pud = pud_offset(pgd, address);
+ pud_k = pud_offset(pgd_k, address);
+ if (!pud_present(*pud_k))
+ goto no_context;
+ pmd = pmd_offset(pud, address);
+ pmd_k = pmd_offset(pud_k, address);
+ if (!pmd_present(*pmd_k))
+ goto no_context;
+ set_pmd(pmd, *pmd_k);
+
+ pte_k = pte_offset_kernel(pmd_k, address);
+ if (!pte_present(*pte_k))
+ goto no_context;
+
+ flush_tlb_one(address);
+ return;
+ }
+}
diff --git a/arch/nios2/mm/init.c b/arch/nios2/mm/init.c
new file mode 100644
index 0000000..e75c75d
--- /dev/null
+++ b/arch/nios2/mm/init.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ * Copyright (C) 2004 Microtronix Datacom Ltd
+ *
+ * based on arch/m68k/mm/init.c
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/mman.h>
+#include <linux/mm.h>
+#include <linux/init.h>
+#include <linux/pagemap.h>
+#include <linux/bootmem.h>
+#include <linux/slab.h>
+#include <linux/binfmts.h>
+
+#include <asm/setup.h>
+#include <asm/page.h>
+#include <asm/pgtable.h>
+#include <asm/sections.h>
+#include <asm/tlb.h>
+#include <asm/mmu_context.h>
+#include <asm/cpuinfo.h>
+#include <asm/processor.h>
+
+pgd_t *pgd_current;
+
+/*
+ * paging_init() continues the virtual memory environment setup which
+ * was begun by the code in arch/head.S.
+ * The parameters are pointers to where to stick the starting and ending
+ * addresses of available kernel virtual memory.
+ */
+void __init paging_init(void)
+{
+ unsigned long zones_size[MAX_NR_ZONES];
+
+ memset(zones_size, 0, sizeof(zones_size));
+
+ pagetable_init();
+ pgd_current = swapper_pg_dir;
+
+ zones_size[ZONE_NORMAL] = max_mapnr;
+
+ /* pass the memory from the bootmem allocator to the main allocator */
+ free_area_init(zones_size);
+
+ flush_dcache_range((unsigned long)empty_zero_page,
+ (unsigned long)empty_zero_page + PAGE_SIZE);
+}
+
+void __init mem_init(void)
+{
+ unsigned long end_mem = memory_end; /* this must not include
+ kernel stack at top */
+
+ pr_debug("mem_init: start=%lx, end=%lx\n", memory_start, memory_end);
+
+ end_mem &= PAGE_MASK;
+ high_memory = __va(end_mem);
+
+ /* this will put all memory onto the freelists */
+ free_all_bootmem();
+ mem_init_print_info(NULL);
+}
+
+void __init mmu_init(void)
+{
+ flush_tlb_all();
+}
+
+#ifdef CONFIG_BLK_DEV_INITRD
+void __init free_initrd_mem(unsigned long start, unsigned long end)
+{
+ free_reserved_area((void *)start, (void *)end, -1, "initrd");
+}
+#endif
+
+void __init_refok free_initmem(void)
+{
+ free_initmem_default(-1);
+}
+
+#define __page_aligned(order) __aligned(PAGE_SIZE << (order))
+pgd_t swapper_pg_dir[PTRS_PER_PGD] __page_aligned(PGD_ORDER);
+pte_t invalid_pte_table[PTRS_PER_PTE] __page_aligned(PTE_ORDER);
+static struct page *kuser_page[1];
+
+static int alloc_kuser_page(void)
+{
+ extern char __kuser_helper_start[], __kuser_helper_end[];
+ int kuser_sz = __kuser_helper_end - __kuser_helper_start;
+ unsigned long vpage;
+
+ vpage = get_zeroed_page(GFP_ATOMIC);
+ if (!vpage)
+ return -ENOMEM;
+
+ /* Copy kuser helpers */
+ memcpy((void *)vpage, __kuser_helper_start, kuser_sz);
+
+ flush_icache_range(vpage, vpage + KUSER_SIZE);
+ kuser_page[0] = virt_to_page(vpage);
+
+ return 0;
+}
+arch_initcall(alloc_kuser_page);
+
+int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+ struct mm_struct *mm = current->mm;
+ int ret;
+
+ down_write(&mm->mmap_sem);
+
+ /* Map kuser helpers to user space address */
+ ret = install_special_mapping(mm, KUSER_BASE, KUSER_SIZE,
+ VM_READ | VM_EXEC | VM_MAYREAD |
+ VM_MAYEXEC, kuser_page);
+
+ up_write(&mm->mmap_sem);
+
+ return ret;
+}
+
+const char *arch_vma_name(struct vm_area_struct *vma)
+{
+ return (vma->vm_start == KUSER_BASE) ? "[kuser]" : NULL;
+}
diff --git a/arch/nios2/mm/ioremap.c b/arch/nios2/mm/ioremap.c
new file mode 100644
index 0000000..3a28177
--- /dev/null
+++ b/arch/nios2/mm/ioremap.c
@@ -0,0 +1,187 @@
+/*
+ * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ * Copyright (C) 2004 Microtronix Datacom Ltd.
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/export.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/io.h>
+
+#include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
+
+static inline void remap_area_pte(pte_t *pte, unsigned long address,
+ unsigned long size, unsigned long phys_addr,
+ unsigned long flags)
+{
+ unsigned long end;
+ unsigned long pfn;
+ pgprot_t pgprot = __pgprot(_PAGE_GLOBAL | _PAGE_PRESENT | _PAGE_READ
+ | _PAGE_WRITE | flags);
+
+ address &= ~PMD_MASK;
+ end = address + size;
+ if (end > PMD_SIZE)
+ end = PMD_SIZE;
+ if (address >= end)
+ BUG();
+ pfn = PFN_DOWN(phys_addr);
+ do {
+ if (!pte_none(*pte)) {
+ pr_err("remap_area_pte: page already exists\n");
+ BUG();
+ }
+ set_pte(pte, pfn_pte(pfn, pgprot));
+ address += PAGE_SIZE;
+ pfn++;
+ pte++;
+ } while (address && (address < end));
+}
+
+static inline int remap_area_pmd(pmd_t *pmd, unsigned long address,
+ unsigned long size, unsigned long phys_addr,
+ unsigned long flags)
+{
+ unsigned long end;
+
+ address &= ~PGDIR_MASK;
+ end = address + size;
+ if (end > PGDIR_SIZE)
+ end = PGDIR_SIZE;
+ phys_addr -= address;
+ if (address >= end)
+ BUG();
+ do {
+ pte_t *pte = pte_alloc_kernel(pmd, address);
+
+ if (!pte)
+ return -ENOMEM;
+ remap_area_pte(pte, address, end - address, address + phys_addr,
+ flags);
+ address = (address + PMD_SIZE) & PMD_MASK;
+ pmd++;
+ } while (address && (address < end));
+ return 0;
+}
+
+static int remap_area_pages(unsigned long address, unsigned long phys_addr,
+ unsigned long size, unsigned long flags)
+{
+ int error;
+ pgd_t *dir;
+ unsigned long end = address + size;
+
+ phys_addr -= address;
+ dir = pgd_offset(&init_mm, address);
+ flush_cache_all();
+ if (address >= end)
+ BUG();
+ do {
+ pud_t *pud;
+ pmd_t *pmd;
+
+ error = -ENOMEM;
+ pud = pud_alloc(&init_mm, dir, address);
+ if (!pud)
+ break;
+ pmd = pmd_alloc(&init_mm, pud, address);
+ if (!pmd)
+ break;
+ if (remap_area_pmd(pmd, address, end - address,
+ phys_addr + address, flags))
+ break;
+ error = 0;
+ address = (address + PGDIR_SIZE) & PGDIR_MASK;
+ dir++;
+ } while (address && (address < end));
+ flush_tlb_all();
+ return error;
+}
+
+#define IS_MAPPABLE_UNCACHEABLE(addr) (addr < 0x20000000UL)
+
+/*
+ * Map some physical address range into the kernel address space.
+ */
+void __iomem *__ioremap(unsigned long phys_addr, unsigned long size,
+ unsigned long cacheflag)
+{
+ struct vm_struct *area;
+ unsigned long offset;
+ unsigned long last_addr;
+ void *addr;
+
+ /* Don't allow wraparound or zero size */
+ last_addr = phys_addr + size - 1;
+
+ if (!size || last_addr < phys_addr)
+ return NULL;
+
+ /* Don't allow anybody to remap normal RAM that we're using */
+ if (phys_addr > PHYS_OFFSET && phys_addr < virt_to_phys(high_memory)) {
+ char *t_addr, *t_end;
+ struct page *page;
+
+ t_addr = __va(phys_addr);
+ t_end = t_addr + (size - 1);
+ for (page = virt_to_page(t_addr);
+ page <= virt_to_page(t_end); page++)
+ if (!PageReserved(page))
+ return NULL;
+ }
+
+ /*
+ * Map uncached objects in the low part of address space to
+ * CONFIG_NIOS2_IO_REGION_BASE
+ */
+ if (IS_MAPPABLE_UNCACHEABLE(phys_addr) &&
+ IS_MAPPABLE_UNCACHEABLE(last_addr) &&
+ !(cacheflag & _PAGE_CACHED))
+ return (void __iomem *)(CONFIG_NIOS2_IO_REGION_BASE + phys_addr);
+
+ /* Mappings have to be page-aligned */
+ offset = phys_addr & ~PAGE_MASK;
+ phys_addr &= PAGE_MASK;
+ size = PAGE_ALIGN(last_addr + 1) - phys_addr;
+
+ /* Ok, go for it */
+ area = get_vm_area(size, VM_IOREMAP);
+ if (!area)
+ return NULL;
+ addr = area->addr;
+ if (remap_area_pages((unsigned long) addr, phys_addr, size,
+ cacheflag)) {
+ vunmap(addr);
+ return NULL;
+ }
+ return (void __iomem *) (offset + (char *)addr);
+}
+EXPORT_SYMBOL(__ioremap);
+
+/*
+ * __iounmap unmaps nearly everything, so be careful
+ * it doesn't free currently pointer/page tables anymore but it
+ * wasn't used anyway and might be added later.
+ */
+void __iounmap(void __iomem *addr)
+{
+ struct vm_struct *p;
+
+ if ((unsigned long) addr > CONFIG_NIOS2_IO_REGION_BASE)
+ return;
+
+ p = remove_vm_area((void *) (PAGE_MASK & (unsigned long __force) addr));
+ if (!p)
+ pr_err("iounmap: bad address %p\n", addr);
+ kfree(p);
+}
+EXPORT_SYMBOL(__iounmap);
diff --git a/arch/nios2/mm/mmu_context.c b/arch/nios2/mm/mmu_context.c
new file mode 100644
index 0000000..45d6b9c
--- /dev/null
+++ b/arch/nios2/mm/mmu_context.c
@@ -0,0 +1,116 @@
+/*
+ * MMU context handling.
+ *
+ * Copyright (C) 2011 Tobias Klauser <tklauser@distanz.ch>
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/mm.h>
+
+#include <asm/cpuinfo.h>
+#include <asm/mmu_context.h>
+#include <asm/tlb.h>
+
+/* The pids position and mask in context */
+#define PID_SHIFT 0
+#define PID_BITS (cpuinfo.tlb_pid_num_bits)
+#define PID_MASK ((1UL << PID_BITS) - 1)
+
+/* The versions position and mask in context */
+#define VERSION_BITS (32 - PID_BITS)
+#define VERSION_SHIFT (PID_SHIFT + PID_BITS)
+#define VERSION_MASK ((1UL << VERSION_BITS) - 1)
+
+/* Return the version part of a context */
+#define CTX_VERSION(c) (((c) >> VERSION_SHIFT) & VERSION_MASK)
+
+/* Return the pid part of a context */
+#define CTX_PID(c) (((c) >> PID_SHIFT) & PID_MASK)
+
+/* Value of the first context (version 1, pid 0) */
+#define FIRST_CTX ((1UL << VERSION_SHIFT) | (0 << PID_SHIFT))
+
+static mm_context_t next_mmu_context;
+
+/*
+ * Initialize MMU context management stuff.
+ */
+void __init mmu_context_init(void)
+{
+ /* We need to set this here because the value depends on runtime data
+ * from cpuinfo */
+ next_mmu_context = FIRST_CTX;
+}
+
+/*
+ * Set new context (pid), keep way
+ */
+static void set_context(mm_context_t context)
+{
+ set_mmu_pid(CTX_PID(context));
+}
+
+static mm_context_t get_new_context(void)
+{
+ /* Return the next pid */
+ next_mmu_context += (1UL << PID_SHIFT);
+
+ /* If the pid field wraps around we increase the version and
+ * flush the tlb */
+ if (unlikely(CTX_PID(next_mmu_context) == 0)) {
+ /* Version is incremented since the pid increment above
+ * overflows info version */
+ flush_cache_all();
+ flush_tlb_all();
+ }
+
+ /* If the version wraps we start over with the first generation, we do
+ * not need to flush the tlb here since it's always done above */
+ if (unlikely(CTX_VERSION(next_mmu_context) == 0))
+ next_mmu_context = FIRST_CTX;
+
+ return next_mmu_context;
+}
+
+void switch_mm(struct mm_struct *prev, struct mm_struct *next,
+ struct task_struct *tsk)
+{
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+ /* If the process context we are swapping in has a different context
+ * generation then we have it should get a new generation/pid */
+ if (unlikely(CTX_VERSION(next->context) !=
+ CTX_VERSION(next_mmu_context)))
+ next->context = get_new_context();
+
+ /* Save the current pgd so the fast tlb handler can find it */
+ pgd_current = next->pgd;
+
+ /* Set the current context */
+ set_context(next->context);
+
+ local_irq_restore(flags);
+}
+
+/*
+ * After we have set current->mm to a new value, this activates
+ * the context for the new mm so we see the new mappings.
+ */
+void activate_mm(struct mm_struct *prev, struct mm_struct *next)
+{
+ next->context = get_new_context();
+ set_context(next->context);
+ pgd_current = next->pgd;
+}
+
+unsigned long get_pid_from_context(mm_context_t *context)
+{
+ return CTX_PID((*context));
+}
diff --git a/arch/nios2/mm/pgtable.c b/arch/nios2/mm/pgtable.c
new file mode 100644
index 0000000..61e24a2
--- /dev/null
+++ b/arch/nios2/mm/pgtable.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2009 Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/mm.h>
+#include <linux/sched.h>
+
+#include <asm/pgtable.h>
+#include <asm/cpuinfo.h>
+
+/* pteaddr:
+ * ptbase | vpn* | zero
+ * 31-22 | 21-2 | 1-0
+ *
+ * *vpn is preserved on double fault
+ *
+ * tlbacc:
+ * IG |*flags| pfn
+ * 31-25|24-20 | 19-0
+ *
+ * *crwxg
+ *
+ * tlbmisc:
+ * resv |way |rd | we|pid |dbl|bad|perm|d
+ * 31-24 |23-20 |19 | 20|17-4|3 |2 |1 |0
+ *
+ */
+
+/*
+ * Initialize a new pgd / pmd table with invalid pointers.
+ */
+static void pgd_init(pgd_t *pgd)
+{
+ unsigned long *p = (unsigned long *) pgd;
+ int i;
+
+ for (i = 0; i < USER_PTRS_PER_PGD; i += 8) {
+ p[i + 0] = (unsigned long) invalid_pte_table;
+ p[i + 1] = (unsigned long) invalid_pte_table;
+ p[i + 2] = (unsigned long) invalid_pte_table;
+ p[i + 3] = (unsigned long) invalid_pte_table;
+ p[i + 4] = (unsigned long) invalid_pte_table;
+ p[i + 5] = (unsigned long) invalid_pte_table;
+ p[i + 6] = (unsigned long) invalid_pte_table;
+ p[i + 7] = (unsigned long) invalid_pte_table;
+ }
+}
+
+pgd_t *pgd_alloc(struct mm_struct *mm)
+{
+ pgd_t *ret, *init;
+
+ ret = (pgd_t *) __get_free_pages(GFP_KERNEL, PGD_ORDER);
+ if (ret) {
+ init = pgd_offset(&init_mm, 0UL);
+ pgd_init(ret);
+ memcpy(ret + USER_PTRS_PER_PGD, init + USER_PTRS_PER_PGD,
+ (PTRS_PER_PGD - USER_PTRS_PER_PGD) * sizeof(pgd_t));
+ }
+
+ return ret;
+}
+
+void __init pagetable_init(void)
+{
+ /* Initialize the entire pgd. */
+ pgd_init(swapper_pg_dir);
+ pgd_init(swapper_pg_dir + USER_PTRS_PER_PGD);
+}
diff --git a/arch/nios2/mm/tlb.c b/arch/nios2/mm/tlb.c
new file mode 100644
index 0000000..cf10326
--- /dev/null
+++ b/arch/nios2/mm/tlb.c
@@ -0,0 +1,275 @@
+/*
+ * Nios2 TLB handling
+ *
+ * Copyright (C) 2009, Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ *
+ * This file is subject to the terms and conditions of the GNU General Public
+ * License. See the file "COPYING" in the main directory of this archive
+ * for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <linux/mm.h>
+#include <linux/pagemap.h>
+
+#include <asm/tlb.h>
+#include <asm/mmu_context.h>
+#include <asm/pgtable.h>
+#include <asm/cpuinfo.h>
+
+#define TLB_INDEX_MASK \
+ ((((1UL << (cpuinfo.tlb_ptr_sz - cpuinfo.tlb_num_ways_log2))) - 1) \
+ << PAGE_SHIFT)
+
+/* Used as illegal PHYS_ADDR for TLB mappings
+ */
+#define MAX_PHYS_ADDR 0
+
+static void get_misc_and_pid(unsigned long *misc, unsigned long *pid)
+{
+ *misc = RDCTL(CTL_TLBMISC);
+ *misc &= (TLBMISC_PID | TLBMISC_WAY);
+ *pid = *misc & TLBMISC_PID;
+}
+
+/*
+ * All entries common to a mm share an asid. To effectively flush these
+ * entries, we just bump the asid.
+ */
+void flush_tlb_mm(struct mm_struct *mm)
+{
+ if (current->mm == mm)
+ flush_tlb_all();
+ else
+ memset(&mm->context, 0, sizeof(mm_context_t));
+}
+
+/*
+ * This one is only used for pages with the global bit set so we don't care
+ * much about the ASID.
+ */
+void flush_tlb_one_pid(unsigned long addr, unsigned long mmu_pid)
+{
+ unsigned int way;
+ unsigned long org_misc, pid_misc;
+
+ pr_debug("Flush tlb-entry for vaddr=%#lx\n", addr);
+
+ /* remember pid/way until we return. */
+ get_misc_and_pid(&org_misc, &pid_misc);
+
+ WRCTL(CTL_PTEADDR, (addr >> PAGE_SHIFT) << 2);
+
+ for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+ unsigned long pteaddr;
+ unsigned long tlbmisc;
+ unsigned long pid;
+
+ tlbmisc = pid_misc | TLBMISC_RD | (way << TLBMISC_WAY_SHIFT);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ pteaddr = RDCTL(CTL_PTEADDR);
+ tlbmisc = RDCTL(CTL_TLBMISC);
+ pid = (tlbmisc >> TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK;
+ if (((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) &&
+ pid == mmu_pid) {
+ unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE +
+ ((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) +
+ (addr & TLB_INDEX_MASK);
+ pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n",
+ vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT));
+
+ WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2);
+ tlbmisc = pid_misc | TLBMISC_WE |
+ (way << TLBMISC_WAY_SHIFT);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ }
+ }
+
+ WRCTL(CTL_TLBMISC, org_misc);
+}
+
+void flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
+ unsigned long end)
+{
+ unsigned long mmu_pid = get_pid_from_context(&vma->vm_mm->context);
+
+ while (start < end) {
+ flush_tlb_one_pid(start, mmu_pid);
+ start += PAGE_SIZE;
+ }
+}
+
+void flush_tlb_kernel_range(unsigned long start, unsigned long end)
+{
+ while (start < end) {
+ flush_tlb_one(start);
+ start += PAGE_SIZE;
+ }
+}
+
+/*
+ * This one is only used for pages with the global bit set so we don't care
+ * much about the ASID.
+ */
+void flush_tlb_one(unsigned long addr)
+{
+ unsigned int way;
+ unsigned long org_misc, pid_misc;
+
+ pr_debug("Flush tlb-entry for vaddr=%#lx\n", addr);
+
+ /* remember pid/way until we return. */
+ get_misc_and_pid(&org_misc, &pid_misc);
+
+ WRCTL(CTL_PTEADDR, (addr >> PAGE_SHIFT) << 2);
+
+ for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+ unsigned long pteaddr;
+ unsigned long tlbmisc;
+
+ tlbmisc = pid_misc | TLBMISC_RD | (way << TLBMISC_WAY_SHIFT);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ pteaddr = RDCTL(CTL_PTEADDR);
+ tlbmisc = RDCTL(CTL_TLBMISC);
+
+ if ((((pteaddr >> 2) & 0xfffff)) == (addr >> PAGE_SHIFT)) {
+ unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE +
+ ((PAGE_SIZE * cpuinfo.tlb_num_lines) * way) +
+ (addr & TLB_INDEX_MASK);
+
+ pr_debug("Flush entry by writing %#lx way=%dl pid=%ld\n",
+ vaddr, way, (pid_misc >> TLBMISC_PID_SHIFT));
+
+ tlbmisc = pid_misc | TLBMISC_WE |
+ (way << TLBMISC_WAY_SHIFT);
+ WRCTL(CTL_PTEADDR, (vaddr >> 12) << 2);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ }
+ }
+
+ WRCTL(CTL_TLBMISC, org_misc);
+}
+
+void dump_tlb_line(unsigned long line)
+{
+ unsigned int way;
+ unsigned long org_misc;
+
+ pr_debug("dump tlb-entries for line=%#lx (addr %08lx)\n", line,
+ line << (PAGE_SHIFT + cpuinfo.tlb_num_ways_log2));
+
+ /* remember pid/way until we return */
+ org_misc = (RDCTL(CTL_TLBMISC) & (TLBMISC_PID | TLBMISC_WAY));
+
+ WRCTL(CTL_PTEADDR, line << 2);
+
+ for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+ unsigned long pteaddr;
+ unsigned long tlbmisc;
+ unsigned long tlbacc;
+
+ WRCTL(CTL_TLBMISC, TLBMISC_RD | (way << TLBMISC_WAY_SHIFT));
+ pteaddr = RDCTL(CTL_PTEADDR);
+ tlbmisc = RDCTL(CTL_TLBMISC);
+ tlbacc = RDCTL(CTL_TLBACC);
+
+ if ((tlbacc << PAGE_SHIFT) != (MAX_PHYS_ADDR & PAGE_MASK)) {
+ pr_debug("-- way:%02x vpn:0x%08lx phys:0x%08lx pid:0x%02lx flags:%c%c%c%c%c\n",
+ way,
+ (pteaddr << (PAGE_SHIFT-2)),
+ (tlbacc << PAGE_SHIFT),
+ ((tlbmisc >> TLBMISC_PID_SHIFT) &
+ TLBMISC_PID_MASK),
+ (tlbacc & _PAGE_READ ? 'r' : '-'),
+ (tlbacc & _PAGE_WRITE ? 'w' : '-'),
+ (tlbacc & _PAGE_EXEC ? 'x' : '-'),
+ (tlbacc & _PAGE_GLOBAL ? 'g' : '-'),
+ (tlbacc & _PAGE_CACHED ? 'c' : '-'));
+ }
+ }
+
+ WRCTL(CTL_TLBMISC, org_misc);
+}
+
+void dump_tlb(void)
+{
+ unsigned int i;
+
+ for (i = 0; i < cpuinfo.tlb_num_lines; i++)
+ dump_tlb_line(i);
+}
+
+void flush_tlb_pid(unsigned long pid)
+{
+ unsigned int line;
+ unsigned int way;
+ unsigned long org_misc, pid_misc;
+
+ /* remember pid/way until we return */
+ get_misc_and_pid(&org_misc, &pid_misc);
+
+ for (line = 0; line < cpuinfo.tlb_num_lines; line++) {
+ WRCTL(CTL_PTEADDR, line << 2);
+
+ for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+ unsigned long pteaddr;
+ unsigned long tlbmisc;
+ unsigned long tlbacc;
+
+ tlbmisc = pid_misc | TLBMISC_RD |
+ (way << TLBMISC_WAY_SHIFT);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ pteaddr = RDCTL(CTL_PTEADDR);
+ tlbmisc = RDCTL(CTL_TLBMISC);
+ tlbacc = RDCTL(CTL_TLBACC);
+
+ if (((tlbmisc>>TLBMISC_PID_SHIFT) & TLBMISC_PID_MASK)
+ == pid) {
+ tlbmisc = pid_misc | TLBMISC_WE |
+ (way << TLBMISC_WAY_SHIFT);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ WRCTL(CTL_TLBACC,
+ (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ }
+ }
+
+ WRCTL(CTL_TLBMISC, org_misc);
+ }
+}
+
+void flush_tlb_all(void)
+{
+ int i;
+ unsigned long vaddr = CONFIG_NIOS2_IO_REGION_BASE;
+ unsigned int way;
+ unsigned long org_misc, pid_misc, tlbmisc;
+
+ /* remember pid/way until we return */
+ get_misc_and_pid(&org_misc, &pid_misc);
+ pid_misc |= TLBMISC_WE;
+
+ /* Map each TLB entry to physcal address 0 with no-access and a
+ bad ptbase */
+ for (way = 0; way < cpuinfo.tlb_num_ways; way++) {
+ tlbmisc = pid_misc | (way << TLBMISC_WAY_SHIFT);
+ for (i = 0; i < cpuinfo.tlb_num_lines; i++) {
+ WRCTL(CTL_PTEADDR, ((vaddr) >> PAGE_SHIFT) << 2);
+ WRCTL(CTL_TLBMISC, tlbmisc);
+ WRCTL(CTL_TLBACC, (MAX_PHYS_ADDR >> PAGE_SHIFT));
+ vaddr += 1UL << 12;
+ }
+ }
+
+ /* restore pid/way */
+ WRCTL(CTL_TLBMISC, org_misc);
+}
+
+void set_mmu_pid(unsigned long pid)
+{
+ WRCTL(CTL_TLBMISC, (RDCTL(CTL_TLBMISC) & TLBMISC_WAY) |
+ ((pid & TLBMISC_PID_MASK) << TLBMISC_PID_SHIFT));
+}
diff --git a/arch/nios2/mm/uaccess.c b/arch/nios2/mm/uaccess.c
new file mode 100644
index 0000000..7663e15
--- /dev/null
+++ b/arch/nios2/mm/uaccess.c
@@ -0,0 +1,163 @@
+/*
+ * 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) 2009, Wind River Systems Inc
+ * Implemented by fredrik.markstrom@gmail.com and ivarholmqvist@gmail.com
+ */
+
+#include <linux/export.h>
+#include <linux/uaccess.h>
+
+asm(".global __copy_from_user\n"
+ " .type __copy_from_user, @function\n"
+ "__copy_from_user:\n"
+ " movi r2,7\n"
+ " mov r3,r4\n"
+ " bge r2,r6,1f\n"
+ " xor r2,r4,r5\n"
+ " andi r2,r2,3\n"
+ " movi r7,3\n"
+ " beq r2,zero,4f\n"
+ "1: addi r6,r6,-1\n"
+ " movi r2,-1\n"
+ " beq r6,r2,3f\n"
+ " mov r7,r2\n"
+ "2: ldbu r2,0(r5)\n"
+ " addi r6,r6,-1\n"
+ " addi r5,r5,1\n"
+ " stb r2,0(r3)\n"
+ " addi r3,r3,1\n"
+ " bne r6,r7,2b\n"
+ "3:\n"
+ " addi r2,r6,1\n"
+ " ret\n"
+ "13:mov r2,r6\n"
+ " ret\n"
+ "4: andi r2,r4,1\n"
+ " cmpeq r2,r2,zero\n"
+ " beq r2,zero,7f\n"
+ "5: andi r2,r3,2\n"
+ " beq r2,zero,6f\n"
+ "9: ldhu r2,0(r5)\n"
+ " addi r6,r6,-2\n"
+ " addi r5,r5,2\n"
+ " sth r2,0(r3)\n"
+ " addi r3,r3,2\n"
+ "6: bge r7,r6,1b\n"
+ "10:ldw r2,0(r5)\n"
+ " addi r6,r6,-4\n"
+ " addi r5,r5,4\n"
+ " stw r2,0(r3)\n"
+ " addi r3,r3,4\n"
+ " br 6b\n"
+ "7: ldbu r2,0(r5)\n"
+ " addi r6,r6,-1\n"
+ " addi r5,r5,1\n"
+ " addi r3,r4,1\n"
+ " stb r2,0(r4)\n"
+ " br 5b\n"
+ ".section __ex_table,\"a\"\n"
+ ".word 2b,3b\n"
+ ".word 9b,13b\n"
+ ".word 10b,13b\n"
+ ".word 7b,13b\n"
+ ".previous\n"
+ );
+EXPORT_SYMBOL(__copy_from_user);
+
+asm(
+ " .global __copy_to_user\n"
+ " .type __copy_to_user, @function\n"
+ "__copy_to_user:\n"
+ " movi r2,7\n"
+ " mov r3,r4\n"
+ " bge r2,r6,1f\n"
+ " xor r2,r4,r5\n"
+ " andi r2,r2,3\n"
+ " movi r7,3\n"
+ " beq r2,zero,4f\n"
+ /* Bail if we try to copy zero bytes */
+ "1: addi r6,r6,-1\n"
+ " movi r2,-1\n"
+ " beq r6,r2,3f\n"
+ /* Copy byte by byte for small copies and if src^dst != 0 */
+ " mov r7,r2\n"
+ "2: ldbu r2,0(r5)\n"
+ " addi r5,r5,1\n"
+ "9: stb r2,0(r3)\n"
+ " addi r6,r6,-1\n"
+ " addi r3,r3,1\n"
+ " bne r6,r7,2b\n"
+ "3: addi r2,r6,1\n"
+ " ret\n"
+ "13:mov r2,r6\n"
+ " ret\n"
+ /* If 'to' is an odd address byte copy */
+ "4: andi r2,r4,1\n"
+ " cmpeq r2,r2,zero\n"
+ " beq r2,zero,7f\n"
+ /* If 'to' is not divideable by four copy halfwords */
+ "5: andi r2,r3,2\n"
+ " beq r2,zero,6f\n"
+ " ldhu r2,0(r5)\n"
+ " addi r5,r5,2\n"
+ "10:sth r2,0(r3)\n"
+ " addi r6,r6,-2\n"
+ " addi r3,r3,2\n"
+ /* Copy words */
+ "6: bge r7,r6,1b\n"
+ " ldw r2,0(r5)\n"
+ " addi r5,r5,4\n"
+ "11:stw r2,0(r3)\n"
+ " addi r6,r6,-4\n"
+ " addi r3,r3,4\n"
+ " br 6b\n"
+ /* Copy remaining bytes */
+ "7: ldbu r2,0(r5)\n"
+ " addi r5,r5,1\n"
+ " addi r3,r4,1\n"
+ "12: stb r2,0(r4)\n"
+ " addi r6,r6,-1\n"
+ " br 5b\n"
+ ".section __ex_table,\"a\"\n"
+ ".word 9b,3b\n"
+ ".word 10b,13b\n"
+ ".word 11b,13b\n"
+ ".word 12b,13b\n"
+ ".previous\n");
+EXPORT_SYMBOL(__copy_to_user);
+
+long strncpy_from_user(char *__to, const char __user *__from, long __len)
+{
+ int l = strnlen_user(__from, __len);
+ int is_zt = 1;
+
+ if (l > __len) {
+ is_zt = 0;
+ l = __len;
+ }
+
+ if (l == 0 || copy_from_user(__to, __from, l))
+ return -EFAULT;
+
+ if (is_zt)
+ l--;
+ return l;
+}
+
+long strnlen_user(const char __user *s, long n)
+{
+ long i;
+
+ for (i = 0; i < n; i++) {
+ char c;
+
+ if (get_user(c, s + i) == -EFAULT)
+ return 0;
+ if (c == 0)
+ return i + 1;
+ }
+ return n + 1;
+}
diff --git a/arch/nios2/platform/Kconfig.platform b/arch/nios2/platform/Kconfig.platform
new file mode 100644
index 0000000..d3e5df9
--- /dev/null
+++ b/arch/nios2/platform/Kconfig.platform
@@ -0,0 +1,129 @@
+menu "Platform options"
+
+comment "Memory settings"
+
+config NIOS2_MEM_BASE
+ hex "Memory base address"
+ default "0x00000000"
+ help
+ This is the physical address of the memory that the kernel will run
+ from. This address is used to link the kernel and setup initial memory
+ management. You should take the raw memory address without any MMU
+ or cache bits set.
+ Please not that this address is used directly so you have to manually
+ do address translation if it's connected to a bridge.
+
+comment "Device tree"
+
+config NIOS2_DTB_AT_PHYS_ADDR
+ bool "DTB at physical address"
+ default n
+ help
+ When enabled you can select a physical address to load the dtb from.
+ Normally this address is passed by a bootloader such as u-boot but
+ using this you can use a devicetree without a bootloader.
+ This way you can store a devicetree in NOR flash or an onchip rom.
+ Please note that this address is used directly so you have to manually
+ do address translation if it's connected to a bridge. Also take into
+ account that when using an MMU you'd have to ad 0xC0000000 to your
+ address
+
+config NIOS2_DTB_PHYS_ADDR
+ hex "DTB Address"
+ depends on NIOS2_DTB_AT_PHYS_ADDR
+ default "0xC0000000"
+ help
+ Physical address of a dtb blob.
+
+config NIOS2_DTB_SOURCE_BOOL
+ bool "Compile and link device tree into kernel image"
+ default n
+ help
+ This allows you to specify a dts (device tree source) file
+ which will be compiled and linked into the kernel image.
+
+config NIOS2_DTB_SOURCE
+ string "Device tree source file"
+ depends on NIOS2_DTB_SOURCE_BOOL
+ default ""
+ help
+ Absolute path to the device tree source (dts) file describing your
+ system.
+
+comment "Nios II instructions"
+
+config NIOS2_HW_MUL_SUPPORT
+ bool "Enable MUL instruction"
+ default n
+ help
+ Set to true if you configured the Nios II to include the MUL
+ instruction. This will enable the -mhw-mul compiler flag.
+
+config NIOS2_HW_MULX_SUPPORT
+ bool "Enable MULX instruction"
+ default n
+ help
+ Set to true if you configured the Nios II to include the MULX
+ instruction. Enables the -mhw-mulx compiler flag.
+
+config NIOS2_HW_DIV_SUPPORT
+ bool "Enable DIV instruction"
+ default n
+ help
+ Set to true if you configured the Nios II to include the DIV
+ instruction. Enables the -mhw-div compiler flag.
+
+config NIOS2_FPU_SUPPORT
+ bool "Custom floating point instr support"
+ default n
+ help
+ Enables the -mcustom-fpu-cfg=60-1 compiler flag.
+
+config NIOS2_CI_SWAB_SUPPORT
+ bool "Byteswap custom instruction"
+ default n
+ help
+ Use the byteswap (endian converter) Nios II custom instruction provided
+ by Altera and which can be enabled in QSYS builder. This accelerates
+ endian conversions in the kernel (e.g. ntohs).
+
+config NIOS2_CI_SWAB_NO
+ int "Byteswap custom instruction number" if NIOS2_CI_SWAB_SUPPORT
+ default 0
+ help
+ Number of the instruction as configured in QSYS Builder.
+
+comment "Cache settings"
+
+config CUSTOM_CACHE_SETTINGS
+ bool "Custom cache settings"
+ help
+ This option allows you to tweak the cache settings used during early
+ boot (where the information from device tree is not yet available).
+ There should be no reason to change these values. Linux will work
+ perfectly fine, even if the Nios II is configured with smaller caches.
+
+ Say N here unless you know what you are doing.
+
+config NIOS2_DCACHE_SIZE
+ hex "D-Cache size" if CUSTOM_CACHE_SETTINGS
+ range 0x200 0x10000
+ default "0x800"
+ help
+ Maximum possible data cache size.
+
+config NIOS2_DCACHE_LINE_SIZE
+ hex "D-Cache line size" if CUSTOM_CACHE_SETTINGS
+ range 0x10 0x20
+ default "0x20"
+ help
+ Minimum possible data cache line size.
+
+config NIOS2_ICACHE_SIZE
+ hex "I-Cache size" if CUSTOM_CACHE_SETTINGS
+ range 0x200 0x10000
+ default "0x1000"
+ help
+ Maximum possible instruction cache size.
+
+endmenu
diff --git a/arch/nios2/platform/Makefile b/arch/nios2/platform/Makefile
new file mode 100644
index 0000000..46364f1
--- /dev/null
+++ b/arch/nios2/platform/Makefile
@@ -0,0 +1 @@
+obj-y += platform.o
diff --git a/arch/nios2/platform/platform.c b/arch/nios2/platform/platform.c
new file mode 100644
index 0000000..d478773
--- /dev/null
+++ b/arch/nios2/platform/platform.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2013 Altera Corporation
+ * Copyright (C) 2011 Thomas Chou
+ * Copyright (C) 2011 Walter Goossens
+ *
+ * This file is subject to the terms and conditions of the GNU General
+ * Public License. See the file COPYING in the main directory of this
+ * archive for more details.
+ */
+
+#include <linux/init.h>
+#include <linux/of_platform.h>
+#include <linux/of_address.h>
+#include <linux/of_fdt.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/io.h>
+
+static int __init nios2_soc_device_init(void)
+{
+ struct soc_device *soc_dev;
+ struct soc_device_attribute *soc_dev_attr;
+ const char *machine;
+
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (soc_dev_attr) {
+ machine = of_flat_dt_get_machine_name();
+ if (machine)
+ soc_dev_attr->machine = kasprintf(GFP_KERNEL, "%s",
+ machine);
+
+ soc_dev_attr->family = "Nios II";
+
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev)) {
+ kfree(soc_dev_attr->machine);
+ kfree(soc_dev_attr);
+ }
+ }
+
+ return of_platform_populate(NULL, of_default_bus_match_table,
+ NULL, NULL);
+}
+
+device_initcall(nios2_soc_device_init);
diff --git a/arch/parisc/hpux/fs.c b/arch/parisc/hpux/fs.c
index 2bedafe..97a7bf8 100644
--- a/arch/parisc/hpux/fs.c
+++ b/arch/parisc/hpux/fs.c
@@ -56,11 +56,12 @@ struct getdents_callback {
#define NAME_OFFSET(de) ((int) ((de)->d_name - (char __user *) (de)))
-static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
- u64 ino, unsigned d_type)
+static int filldir(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned d_type)
{
struct hpux_dirent __user * dirent;
- struct getdents_callback * buf = (struct getdents_callback *) __buf;
+ struct getdents_callback *buf =
+ container_of(ctx, struct getdents_callback, ctx);
ino_t d_ino;
int reclen = ALIGN(NAME_OFFSET(dirent) + namlen + 1, sizeof(long));
diff --git a/arch/parisc/include/asm/io.h b/arch/parisc/include/asm/io.h
index 1f6d2ae..8cd0abf 100644
--- a/arch/parisc/include/asm/io.h
+++ b/arch/parisc/include/asm/io.h
@@ -217,10 +217,14 @@ static inline void writeq(unsigned long long q, volatile void __iomem *addr)
#define writel writel
#define writeq writeq
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-#define readq_relaxed(addr) readq(addr)
+#define readb_relaxed(addr) readb(addr)
+#define readw_relaxed(addr) readw(addr)
+#define readl_relaxed(addr) readl(addr)
+#define readq_relaxed(addr) readq(addr)
+#define writeb_relaxed(b, addr) writeb(b, addr)
+#define writew_relaxed(w, addr) writew(w, addr)
+#define writel_relaxed(l, addr) writel(l, addr)
+#define writeq_relaxed(q, addr) writeq(q, addr)
#define mmiowb() do { } while (0)
diff --git a/arch/powerpc/include/asm/io.h b/arch/powerpc/include/asm/io.h
index 97d3869..9eaf301 100644
--- a/arch/powerpc/include/asm/io.h
+++ b/arch/powerpc/include/asm/io.h
@@ -617,10 +617,14 @@ static inline void name at \
/*
* We don't do relaxed operations yet, at least not with this semantic
*/
-#define readb_relaxed(addr) readb(addr)
-#define readw_relaxed(addr) readw(addr)
-#define readl_relaxed(addr) readl(addr)
-#define readq_relaxed(addr) readq(addr)
+#define readb_relaxed(addr) readb(addr)
+#define readw_relaxed(addr) readw(addr)
+#define readl_relaxed(addr) readl(addr)
+#define readq_relaxed(addr) readq(addr)
+#define writeb_relaxed(v, addr) writeb(v, addr)
+#define writew_relaxed(v, addr) writew(v, addr)
+#define writel_relaxed(v, addr) writel(v, addr)
+#define writeq_relaxed(v, addr) writeq(v, addr)
#ifdef CONFIG_PPC32
#define mmiowb()
diff --git a/arch/powerpc/include/asm/iommu.h b/arch/powerpc/include/asm/iommu.h
index 42632c7..9cfa370 100644
--- a/arch/powerpc/include/asm/iommu.h
+++ b/arch/powerpc/include/asm/iommu.h
@@ -137,13 +137,16 @@ static inline void set_iommu_table_base_and_group(struct device *dev,
iommu_add_device(dev);
}
-extern int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
- struct scatterlist *sglist, int nelems,
- unsigned long mask, enum dma_data_direction direction,
- struct dma_attrs *attrs);
-extern void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction,
- struct dma_attrs *attrs);
+extern int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
+ struct scatterlist *sglist, int nelems,
+ unsigned long mask,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs);
+extern void ppc_iommu_unmap_sg(struct iommu_table *tbl,
+ struct scatterlist *sglist,
+ int nelems,
+ enum dma_data_direction direction,
+ struct dma_attrs *attrs);
extern void *iommu_alloc_coherent(struct device *dev, struct iommu_table *tbl,
size_t size, dma_addr_t *dma_handle,
diff --git a/arch/powerpc/include/asm/pgalloc.h b/arch/powerpc/include/asm/pgalloc.h
index e9a9f60..fc3ee06 100644
--- a/arch/powerpc/include/asm/pgalloc.h
+++ b/arch/powerpc/include/asm/pgalloc.h
@@ -3,7 +3,6 @@
#ifdef __KERNEL__
#include <linux/mm.h>
-#include <asm-generic/tlb.h>
#ifdef CONFIG_PPC_BOOK3E
extern void tlb_flush_pgtable(struct mmu_gather *tlb, unsigned long address);
@@ -14,6 +13,8 @@ static inline void tlb_flush_pgtable(struct mmu_gather *tlb,
}
#endif /* !CONFIG_PPC_BOOK3E */
+extern void tlb_remove_table(struct mmu_gather *tlb, void *table);
+
#ifdef CONFIG_PPC64
#include <asm/pgalloc-64.h>
#else
diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
index ae153c4..9b4b190 100644
--- a/arch/powerpc/include/asm/pgtable-ppc64.h
+++ b/arch/powerpc/include/asm/pgtable-ppc64.h
@@ -467,6 +467,7 @@ static inline pte_t *pmdp_ptep(pmd_t *pmd)
}
#define pmd_pfn(pmd) pte_pfn(pmd_pte(pmd))
+#define pmd_dirty(pmd) pte_dirty(pmd_pte(pmd))
#define pmd_young(pmd) pte_young(pmd_pte(pmd))
#define pmd_mkold(pmd) pte_pmd(pte_mkold(pmd_pte(pmd)))
#define pmd_wrprotect(pmd) pte_pmd(pte_wrprotect(pmd_pte(pmd)))
diff --git a/arch/powerpc/include/asm/tlb.h b/arch/powerpc/include/asm/tlb.h
index e2b428b..20733fa 100644
--- a/arch/powerpc/include/asm/tlb.h
+++ b/arch/powerpc/include/asm/tlb.h
@@ -27,6 +27,7 @@
#define tlb_start_vma(tlb, vma) do { } while (0)
#define tlb_end_vma(tlb, vma) do { } while (0)
+#define __tlb_remove_tlb_entry __tlb_remove_tlb_entry
extern void tlb_flush(struct mmu_gather *tlb);
diff --git a/arch/powerpc/kernel/dma-iommu.c b/arch/powerpc/kernel/dma-iommu.c
index 54d0116..4c68bfe 100644
--- a/arch/powerpc/kernel/dma-iommu.c
+++ b/arch/powerpc/kernel/dma-iommu.c
@@ -60,16 +60,16 @@ static int dma_iommu_map_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction,
struct dma_attrs *attrs)
{
- return iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems,
- device_to_mask(dev), direction, attrs);
+ return ppc_iommu_map_sg(dev, get_iommu_table_base(dev), sglist, nelems,
+ device_to_mask(dev), direction, attrs);
}
static void dma_iommu_unmap_sg(struct device *dev, struct scatterlist *sglist,
int nelems, enum dma_data_direction direction,
struct dma_attrs *attrs)
{
- iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems, direction,
- attrs);
+ ppc_iommu_unmap_sg(get_iommu_table_base(dev), sglist, nelems,
+ direction, attrs);
}
/* We support DMA to/from any memory page via the iommu */
diff --git a/arch/powerpc/kernel/ftrace.c b/arch/powerpc/kernel/ftrace.c
index 390311c..e66af6d 100644
--- a/arch/powerpc/kernel/ftrace.c
+++ b/arch/powerpc/kernel/ftrace.c
@@ -449,7 +449,7 @@ void ftrace_replace_code(int enable)
rec = ftrace_rec_iter_record(iter);
ret = __ftrace_replace_code(rec, enable);
if (ret) {
- ftrace_bug(ret, rec->ip);
+ ftrace_bug(ret, rec);
return;
}
}
diff --git a/arch/powerpc/kernel/iommu.c b/arch/powerpc/kernel/iommu.c
index a10642a..a83cf5e 100644
--- a/arch/powerpc/kernel/iommu.c
+++ b/arch/powerpc/kernel/iommu.c
@@ -428,10 +428,10 @@ static void iommu_free(struct iommu_table *tbl, dma_addr_t dma_addr,
ppc_md.tce_flush(tbl);
}
-int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
- struct scatterlist *sglist, int nelems,
- unsigned long mask, enum dma_data_direction direction,
- struct dma_attrs *attrs)
+int ppc_iommu_map_sg(struct device *dev, struct iommu_table *tbl,
+ struct scatterlist *sglist, int nelems,
+ unsigned long mask, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
{
dma_addr_t dma_next = 0, dma_addr;
struct scatterlist *s, *outs, *segstart;
@@ -539,7 +539,7 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
DBG("mapped %d elements:\n", outcount);
- /* For the sake of iommu_unmap_sg, we clear out the length in the
+ /* For the sake of ppc_iommu_unmap_sg, we clear out the length in the
* next entry of the sglist if we didn't fill the list completely
*/
if (outcount < incount) {
@@ -572,9 +572,9 @@ int iommu_map_sg(struct device *dev, struct iommu_table *tbl,
}
-void iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
- int nelems, enum dma_data_direction direction,
- struct dma_attrs *attrs)
+void ppc_iommu_unmap_sg(struct iommu_table *tbl, struct scatterlist *sglist,
+ int nelems, enum dma_data_direction direction,
+ struct dma_attrs *attrs)
{
struct scatterlist *sg;
diff --git a/arch/powerpc/mm/hugetlbpage.c b/arch/powerpc/mm/hugetlbpage.c
index 7e70ae9..6a4a5fc 100644
--- a/arch/powerpc/mm/hugetlbpage.c
+++ b/arch/powerpc/mm/hugetlbpage.c
@@ -517,8 +517,6 @@ static void free_hugepd_range(struct mmu_gather *tlb, hugepd_t *hpdp, int pdshif
for (i = 0; i < num_hugepd; i++, hpdp++)
hpdp->pd = 0;
- tlb->need_flush = 1;
-
#ifdef CONFIG_PPC_FSL_BOOK3E
hugepd_free(tlb, hugepte);
#else
diff --git a/arch/powerpc/mm/numa.c b/arch/powerpc/mm/numa.c
index b9d1dfd..9fe6002 100644
--- a/arch/powerpc/mm/numa.c
+++ b/arch/powerpc/mm/numa.c
@@ -1711,12 +1711,11 @@ static void stage_topology_update(int core_id)
static int dt_update_callback(struct notifier_block *nb,
unsigned long action, void *data)
{
- struct of_prop_reconfig *update;
+ struct of_reconfig_data *update = data;
int rc = NOTIFY_DONE;
switch (action) {
case OF_RECONFIG_UPDATE_PROPERTY:
- update = (struct of_prop_reconfig *)data;
if (!of_prop_cmp(update->dn->type, "cpu") &&
!of_prop_cmp(update->prop->name, "ibm,associativity")) {
u32 core_id;
diff --git a/arch/powerpc/oprofile/cell/spu_task_sync.c b/arch/powerpc/oprofile/cell/spu_task_sync.c
index 28f1af2..1c27831 100644
--- a/arch/powerpc/oprofile/cell/spu_task_sync.c
+++ b/arch/powerpc/oprofile/cell/spu_task_sync.c
@@ -331,8 +331,7 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
if (mm->exe_file) {
app_cookie = fast_get_dcookie(&mm->exe_file->f_path);
- pr_debug("got dcookie for %s\n",
- mm->exe_file->f_dentry->d_name.name);
+ pr_debug("got dcookie for %pD\n", mm->exe_file);
}
for (vma = mm->mmap; vma; vma = vma->vm_next) {
@@ -342,15 +341,14 @@ get_exec_dcookie_and_offset(struct spu *spu, unsigned int *offsetp,
if (!vma->vm_file)
goto fail_no_image_cookie;
- pr_debug("Found spu ELF at %X(object-id:%lx) for file %s\n",
- my_offset, spu_ref,
- vma->vm_file->f_dentry->d_name.name);
+ pr_debug("Found spu ELF at %X(object-id:%lx) for file %pD\n",
+ my_offset, spu_ref, vma->vm_file);
*offsetp = my_offset;
break;
}
*spu_bin_dcookie = fast_get_dcookie(&vma->vm_file->f_path);
- pr_debug("got dcookie for %s\n", vma->vm_file->f_dentry->d_name.name);
+ pr_debug("got dcookie for %pD\n", vma->vm_file);
up_read(&mm->mmap_sem);
diff --git a/arch/powerpc/platforms/cell/axon_msi.c b/arch/powerpc/platforms/cell/axon_msi.c
index 862b327..0883994 100644
--- a/arch/powerpc/platforms/cell/axon_msi.c
+++ b/arch/powerpc/platforms/cell/axon_msi.c
@@ -279,7 +279,7 @@ static int axon_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
irq_set_msi_desc(virq, entry);
msg.data = virq;
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
}
return 0;
@@ -301,9 +301,9 @@ static void axon_msi_teardown_msi_irqs(struct pci_dev *dev)
}
static struct irq_chip msic_irq_chip = {
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
- .irq_shutdown = mask_msi_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_shutdown = pci_msi_mask_irq,
.name = "AXON-MSI",
};
diff --git a/arch/powerpc/platforms/cell/iommu.c b/arch/powerpc/platforms/cell/iommu.c
index 2b90ff8..c7c8720 100644
--- a/arch/powerpc/platforms/cell/iommu.c
+++ b/arch/powerpc/platforms/cell/iommu.c
@@ -621,8 +621,9 @@ static int dma_fixed_map_sg(struct device *dev, struct scatterlist *sg,
if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
return dma_direct_ops.map_sg(dev, sg, nents, direction, attrs);
else
- return iommu_map_sg(dev, cell_get_iommu_table(dev), sg, nents,
- device_to_mask(dev), direction, attrs);
+ return ppc_iommu_map_sg(dev, cell_get_iommu_table(dev), sg,
+ nents, device_to_mask(dev),
+ direction, attrs);
}
static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg,
@@ -632,8 +633,8 @@ static void dma_fixed_unmap_sg(struct device *dev, struct scatterlist *sg,
if (iommu_fixed_is_weak == dma_get_attr(DMA_ATTR_WEAK_ORDERING, attrs))
dma_direct_ops.unmap_sg(dev, sg, nents, direction, attrs);
else
- iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents, direction,
- attrs);
+ ppc_iommu_unmap_sg(cell_get_iommu_table(dev), sg, nents,
+ direction, attrs);
}
static int dma_fixed_dma_supported(struct device *dev, u64 mask)
diff --git a/arch/powerpc/platforms/cell/spufs/inode.c b/arch/powerpc/platforms/cell/spufs/inode.c
index 87ba7cf..1a3429e 100644
--- a/arch/powerpc/platforms/cell/spufs/inode.c
+++ b/arch/powerpc/platforms/cell/spufs/inode.c
@@ -164,7 +164,7 @@ static void spufs_prune_dir(struct dentry *dir)
struct dentry *dentry, *tmp;
mutex_lock(&dir->d_inode->i_mutex);
- list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry_safe(dentry, tmp, &dir->d_subdirs, d_child) {
spin_lock(&dentry->d_lock);
if (!(d_unhashed(dentry)) && dentry->d_inode) {
dget_dlock(dentry);
@@ -301,7 +301,7 @@ static int spufs_context_open(struct path *path)
int ret;
struct file *filp;
- ret = get_unused_fd();
+ ret = get_unused_fd_flags(0);
if (ret < 0)
return ret;
@@ -518,7 +518,7 @@ static int spufs_gang_open(struct path *path)
int ret;
struct file *filp;
- ret = get_unused_fd();
+ ret = get_unused_fd_flags(0);
if (ret < 0)
return ret;
diff --git a/arch/powerpc/platforms/powernv/opal-sensor.c b/arch/powerpc/platforms/powernv/opal-sensor.c
index 10271ad..4ab67ef 100644
--- a/arch/powerpc/platforms/powernv/opal-sensor.c
+++ b/arch/powerpc/platforms/powernv/opal-sensor.c
@@ -20,7 +20,9 @@
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/of_platform.h>
#include <asm/opal.h>
+#include <asm/machdep.h>
static DEFINE_MUTEX(opal_sensor_mutex);
@@ -64,3 +66,21 @@ out:
return ret;
}
EXPORT_SYMBOL_GPL(opal_get_sensor_data);
+
+static __init int opal_sensor_init(void)
+{
+ struct platform_device *pdev;
+ struct device_node *sensor;
+
+ sensor = of_find_node_by_path("/ibm,opal/sensors");
+ if (!sensor) {
+ pr_err("Opal node 'sensors' not found\n");
+ return -ENODEV;
+ }
+
+ pdev = of_platform_device_create(sensor, "opal-sensor", NULL);
+ of_node_put(sensor);
+
+ return PTR_ERR_OR_ZERO(pdev);
+}
+machine_subsys_initcall(powernv, opal_sensor_init);
diff --git a/arch/powerpc/platforms/powernv/pci.c b/arch/powerpc/platforms/powernv/pci.c
index 4b20f2c..540fc6d 100644
--- a/arch/powerpc/platforms/powernv/pci.c
+++ b/arch/powerpc/platforms/powernv/pci.c
@@ -90,7 +90,7 @@ static int pnv_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
return rc;
}
irq_set_msi_desc(virq, entry);
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
}
return 0;
}
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 5c375f9..f30cf4d 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -340,16 +340,17 @@ static void pseries_remove_processor(struct device_node *np)
}
static int pseries_smp_notifier(struct notifier_block *nb,
- unsigned long action, void *node)
+ unsigned long action, void *data)
{
+ struct of_reconfig_data *rd = data;
int err = 0;
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
- err = pseries_add_processor(node);
+ err = pseries_add_processor(rd->dn);
break;
case OF_RECONFIG_DETACH_NODE:
- pseries_remove_processor(node);
+ pseries_remove_processor(rd->dn);
break;
}
return notifier_from_errno(err);
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 3c4c0dc..1bbb78f 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -183,7 +183,7 @@ static int pseries_add_mem_node(struct device_node *np)
return (ret < 0) ? -EINVAL : 0;
}
-static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
+static int pseries_update_drconf_memory(struct of_reconfig_data *pr)
{
struct of_drconf_cell *new_drmem, *old_drmem;
unsigned long memblock_size;
@@ -232,22 +232,21 @@ static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
}
static int pseries_memory_notifier(struct notifier_block *nb,
- unsigned long action, void *node)
+ unsigned long action, void *data)
{
- struct of_prop_reconfig *pr;
+ struct of_reconfig_data *rd = data;
int err = 0;
switch (action) {
case OF_RECONFIG_ATTACH_NODE:
- err = pseries_add_mem_node(node);
+ err = pseries_add_mem_node(rd->dn);
break;
case OF_RECONFIG_DETACH_NODE:
- err = pseries_remove_mem_node(node);
+ err = pseries_remove_mem_node(rd->dn);
break;
case OF_RECONFIG_UPDATE_PROPERTY:
- pr = (struct of_prop_reconfig *)node;
- if (!strcmp(pr->prop->name, "ibm,dynamic-memory"))
- err = pseries_update_drconf_memory(pr);
+ if (!strcmp(rd->prop->name, "ibm,dynamic-memory"))
+ err = pseries_update_drconf_memory(rd);
break;
}
return notifier_from_errno(err);
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c
index e32e009..3e5bfda 100644
--- a/arch/powerpc/platforms/pseries/iommu.c
+++ b/arch/powerpc/platforms/pseries/iommu.c
@@ -1251,10 +1251,11 @@ static struct notifier_block iommu_mem_nb = {
.notifier_call = iommu_mem_notifier,
};
-static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *data)
{
int err = NOTIFY_OK;
- struct device_node *np = node;
+ struct of_reconfig_data *rd = data;
+ struct device_node *np = rd->dn;
struct pci_dn *pci = PCI_DN(np);
struct direct_window *window;
diff --git a/arch/powerpc/platforms/pseries/msi.c b/arch/powerpc/platforms/pseries/msi.c
index 8b909e9..691a154 100644
--- a/arch/powerpc/platforms/pseries/msi.c
+++ b/arch/powerpc/platforms/pseries/msi.c
@@ -476,7 +476,7 @@ again:
irq_set_msi_desc(virq, entry);
/* Read config space back so we can restore after reset */
- __read_msi_msg(entry, &msg);
+ __pci_read_msi_msg(entry, &msg);
entry->msg = msg;
}
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c
index 125c589..ed8a900 100644
--- a/arch/powerpc/platforms/pseries/setup.c
+++ b/arch/powerpc/platforms/pseries/setup.c
@@ -251,9 +251,10 @@ static void __init pseries_discover_pic(void)
" interrupt-controller\n");
}
-static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *node)
+static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long action, void *data)
{
- struct device_node *np = node;
+ struct of_reconfig_data *rd = data;
+ struct device_node *np = rd->dn;
struct pci_dn *pci = NULL;
int err = NOTIFY_OK;
diff --git a/arch/powerpc/sysdev/fsl_msi.c b/arch/powerpc/sysdev/fsl_msi.c
index da08ed0..7aed8d0 100644
--- a/arch/powerpc/sysdev/fsl_msi.c
+++ b/arch/powerpc/sysdev/fsl_msi.c
@@ -82,8 +82,8 @@ static void fsl_msi_print_chip(struct irq_data *irqd, struct seq_file *p)
static struct irq_chip fsl_msi_chip = {
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
.irq_ack = fsl_msi_end_irq,
.irq_print_chip = fsl_msi_print_chip,
};
@@ -242,7 +242,7 @@ static int fsl_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
irq_set_msi_desc(virq, entry);
fsl_compose_msi_msg(pdev, hwirq, &msg, msi_data);
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
}
return 0;
diff --git a/arch/powerpc/sysdev/mpic_pasemi_msi.c b/arch/powerpc/sysdev/mpic_pasemi_msi.c
index 15dccd3..45c114b 100644
--- a/arch/powerpc/sysdev/mpic_pasemi_msi.c
+++ b/arch/powerpc/sysdev/mpic_pasemi_msi.c
@@ -42,7 +42,7 @@ static struct mpic *msi_mpic;
static void mpic_pasemi_msi_mask_irq(struct irq_data *data)
{
pr_debug("mpic_pasemi_msi_mask_irq %d\n", data->irq);
- mask_msi_irq(data);
+ pci_msi_mask_irq(data);
mpic_mask_irq(data);
}
@@ -50,7 +50,7 @@ static void mpic_pasemi_msi_unmask_irq(struct irq_data *data)
{
pr_debug("mpic_pasemi_msi_unmask_irq %d\n", data->irq);
mpic_unmask_irq(data);
- unmask_msi_irq(data);
+ pci_msi_unmask_irq(data);
}
static struct irq_chip mpic_pasemi_msi_chip = {
@@ -136,7 +136,7 @@ static int pasemi_msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
* register to generate MSI [512...1023]
*/
msg.data = hwirq-0x200;
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
}
return 0;
diff --git a/arch/powerpc/sysdev/mpic_u3msi.c b/arch/powerpc/sysdev/mpic_u3msi.c
index 623d7fb..0dff1cd 100644
--- a/arch/powerpc/sysdev/mpic_u3msi.c
+++ b/arch/powerpc/sysdev/mpic_u3msi.c
@@ -25,14 +25,14 @@ static struct mpic *msi_mpic;
static void mpic_u3msi_mask_irq(struct irq_data *data)
{
- mask_msi_irq(data);
+ pci_msi_mask_irq(data);
mpic_mask_irq(data);
}
static void mpic_u3msi_unmask_irq(struct irq_data *data)
{
mpic_unmask_irq(data);
- unmask_msi_irq(data);
+ pci_msi_unmask_irq(data);
}
static struct irq_chip mpic_u3msi_chip = {
@@ -171,7 +171,7 @@ static int u3msi_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
printk("u3msi: allocated virq 0x%x (hw 0x%x) addr 0x%lx\n",
virq, hwirq, (unsigned long)addr);
msg.data = hwirq;
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
hwirq++;
}
diff --git a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
index a6a4dbd..908105f 100644
--- a/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_hsta_msi.c
@@ -85,7 +85,7 @@ static int hsta_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
msi_bitmap_free_hwirqs(&ppc4xx_hsta_msi.bmp, irq, 1);
return -EINVAL;
}
- write_msi_msg(hwirq, &msg);
+ pci_write_msi_msg(hwirq, &msg);
}
return 0;
diff --git a/arch/powerpc/sysdev/ppc4xx_msi.c b/arch/powerpc/sysdev/ppc4xx_msi.c
index 22b5200..518eabb 100644
--- a/arch/powerpc/sysdev/ppc4xx_msi.c
+++ b/arch/powerpc/sysdev/ppc4xx_msi.c
@@ -116,7 +116,7 @@ static int ppc4xx_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
irq_set_msi_desc(virq, entry);
msg.data = int_no;
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
}
return 0;
}
diff --git a/arch/powerpc/sysdev/xics/ics-opal.c b/arch/powerpc/sysdev/xics/ics-opal.c
index 3c6ee1b..4ba554e 100644
--- a/arch/powerpc/sysdev/xics/ics-opal.c
+++ b/arch/powerpc/sysdev/xics/ics-opal.c
@@ -73,7 +73,7 @@ static unsigned int ics_opal_startup(struct irq_data *d)
* at that level, so we do it here by hand.
*/
if (d->msi_desc)
- unmask_msi_irq(d);
+ pci_msi_unmask_irq(d);
#endif
/* unmask it */
diff --git a/arch/powerpc/sysdev/xics/ics-rtas.c b/arch/powerpc/sysdev/xics/ics-rtas.c
index 936575d..bc81335b 100644
--- a/arch/powerpc/sysdev/xics/ics-rtas.c
+++ b/arch/powerpc/sysdev/xics/ics-rtas.c
@@ -76,7 +76,7 @@ static unsigned int ics_rtas_startup(struct irq_data *d)
* at that level, so we do it here by hand.
*/
if (d->msi_desc)
- unmask_msi_irq(d);
+ pci_msi_unmask_irq(d);
#endif
/* unmask it */
ics_rtas_unmask_irq(d);
diff --git a/arch/s390/hypfs/hypfs_dbfs.c b/arch/s390/hypfs/hypfs_dbfs.c
index 2badf2b..47fe105 100644
--- a/arch/s390/hypfs/hypfs_dbfs.c
+++ b/arch/s390/hypfs/hypfs_dbfs.c
@@ -83,10 +83,9 @@ static ssize_t dbfs_read(struct file *file, char __user *buf,
static long dbfs_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct hypfs_dbfs_file *df;
+ struct hypfs_dbfs_file *df = file_inode(file)->i_private;
long rc;
- df = file->f_path.dentry->d_inode->i_private;
mutex_lock(&df->lock);
if (df->unlocked_ioctl)
rc = df->unlocked_ioctl(file, cmd, arg);
diff --git a/arch/s390/include/asm/io.h b/arch/s390/include/asm/io.h
index cd6b9ee..6ad9013 100644
--- a/arch/s390/include/asm/io.h
+++ b/arch/s390/include/asm/io.h
@@ -13,9 +13,10 @@
#include <asm/page.h>
#include <asm/pci_io.h>
-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);
+void *xlate_dev_mem_ptr(phys_addr_t phys);
+#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr
+void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
/*
* Convert a virtual cached pointer to an uncached pointer
@@ -60,11 +61,6 @@ static inline void iounmap(volatile void __iomem *addr)
#define __raw_writel zpci_write_u32
#define __raw_writeq zpci_write_u64
-#define readb_relaxed readb
-#define readw_relaxed readw
-#define readl_relaxed readl
-#define readq_relaxed readq
-
#endif /* CONFIG_PCI */
#include <asm-generic/io.h>
diff --git a/arch/s390/include/asm/mmu_context.h b/arch/s390/include/asm/mmu_context.h
index 3815bfe..f49b719 100644
--- a/arch/s390/include/asm/mmu_context.h
+++ b/arch/s390/include/asm/mmu_context.h
@@ -120,4 +120,15 @@ static inline void arch_exit_mmap(struct mm_struct *mm)
{
}
+static inline void arch_unmap(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+
+static inline void arch_bprm_mm_init(struct mm_struct *mm,
+ struct vm_area_struct *vma)
+{
+}
+
#endif /* __S390_MMU_CONTEXT_H */
diff --git a/arch/s390/mm/maccess.c b/arch/s390/mm/maccess.c
index 2a2e354..2eb34bd 100644
--- a/arch/s390/mm/maccess.c
+++ b/arch/s390/mm/maccess.c
@@ -176,7 +176,7 @@ static int is_swapped(unsigned long addr)
* For swapped prefix pages a new buffer is returned that contains a copy of
* the absolute memory. The buffer size is maximum one page large.
*/
-void *xlate_dev_mem_ptr(unsigned long addr)
+void *xlate_dev_mem_ptr(phys_addr_t addr)
{
void *bounce = (void *) addr;
unsigned long size;
@@ -197,7 +197,7 @@ void *xlate_dev_mem_ptr(unsigned long addr)
/*
* Free converted buffer for /dev/mem access (if necessary)
*/
-void unxlate_dev_mem_ptr(unsigned long addr, void *buf)
+void unxlate_dev_mem_ptr(phys_addr_t addr, void *buf)
{
if ((void *) addr != buf)
free_page((unsigned long) buf);
diff --git a/arch/s390/pci/pci.c b/arch/s390/pci/pci.c
index 2fa7b14..d59c825 100644
--- a/arch/s390/pci/pci.c
+++ b/arch/s390/pci/pci.c
@@ -50,8 +50,8 @@ static DEFINE_SPINLOCK(zpci_list_lock);
static struct irq_chip zpci_irq_chip = {
.name = "zPCI",
- .irq_unmask = unmask_msi_irq,
- .irq_mask = mask_msi_irq,
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_mask = pci_msi_mask_irq,
};
static DECLARE_BITMAP(zpci_domain, ZPCI_NR_DEVICES);
@@ -403,7 +403,7 @@ int arch_setup_msi_irqs(struct pci_dev *pdev, int nvec, int type)
msg.data = hwirq;
msg.address_lo = zdev->msi_addr & 0xffffffff;
msg.address_hi = zdev->msi_addr >> 32;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
airq_iv_set_data(zdev->aibv, hwirq, irq);
hwirq++;
}
@@ -448,9 +448,9 @@ void arch_teardown_msi_irqs(struct pci_dev *pdev)
/* Release MSI interrupts */
list_for_each_entry(msi, &pdev->msi_list, list) {
if (msi->msi_attrib.is_msix)
- default_msix_mask_irq(msi, 1);
+ __pci_msix_desc_mask_irq(msi, 1);
else
- default_msi_mask_irq(msi, 1, 1);
+ __pci_msi_desc_mask_irq(msi, 1, 1);
irq_set_msi_desc(msi->irq, NULL);
irq_free_desc(msi->irq);
msi->msg.address_lo = 0;
diff --git a/arch/sh/Kconfig b/arch/sh/Kconfig
index 244fb4c..a140347 100644
--- a/arch/sh/Kconfig
+++ b/arch/sh/Kconfig
@@ -222,7 +222,6 @@ config CPU_SHX3
config ARCH_SHMOBILE
bool
select ARCH_SUSPEND_POSSIBLE
- select PM
select PM_RUNTIME
config CPU_HAS_PMU
diff --git a/arch/sh/boards/mach-ap325rxa/setup.c b/arch/sh/boards/mach-ap325rxa/setup.c
index 5620e33..d4b01d4 100644
--- a/arch/sh/boards/mach-ap325rxa/setup.c
+++ b/arch/sh/boards/mach-ap325rxa/setup.c
@@ -338,7 +338,7 @@ static struct soc_camera_platform_info camera_info = {
.format_name = "UYVY",
.format_depth = 16,
.format = {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
.field = V4L2_FIELD_NONE,
.width = 640,
diff --git a/arch/sh/kernel/cpu/shmobile/cpuidle.c b/arch/sh/kernel/cpu/shmobile/cpuidle.c
index e3abfd4..53b8eeb 100644
--- a/arch/sh/kernel/cpu/shmobile/cpuidle.c
+++ b/arch/sh/kernel/cpu/shmobile/cpuidle.c
@@ -59,7 +59,6 @@ static struct cpuidle_driver cpuidle_driver = {
.exit_latency = 1,
.target_residency = 1 * 2,
.power_usage = 3,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = cpuidle_sleep_enter,
.name = "C1",
.desc = "SuperH Sleep Mode",
@@ -68,7 +67,6 @@ static struct cpuidle_driver cpuidle_driver = {
.exit_latency = 100,
.target_residency = 1 * 2,
.power_usage = 1,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = cpuidle_sleep_enter,
.name = "C2",
.desc = "SuperH Sleep Mode [SF]",
@@ -78,7 +76,6 @@ static struct cpuidle_driver cpuidle_driver = {
.exit_latency = 2300,
.target_residency = 1 * 2,
.power_usage = 1,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.enter = cpuidle_sleep_enter,
.name = "C3",
.desc = "SuperH Mobile Standby Mode [SF]",
diff --git a/arch/sh/mm/numa.c b/arch/sh/mm/numa.c
index 3d85225..bce52ba 100644
--- a/arch/sh/mm/numa.c
+++ b/arch/sh/mm/numa.c
@@ -31,7 +31,7 @@ void __init setup_bootmem_node(int nid, unsigned long start, unsigned long end)
unsigned long bootmem_paddr;
/* Don't allow bogus node assignment */
- BUG_ON(nid > MAX_NUMNODES || nid <= 0);
+ BUG_ON(nid >= MAX_NUMNODES || nid <= 0);
start_pfn = start >> PAGE_SHIFT;
end_pfn = end >> PAGE_SHIFT;
diff --git a/arch/sparc/include/asm/io_32.h b/arch/sparc/include/asm/io_32.h
index 9f53290..407ac14 100644
--- a/arch/sparc/include/asm/io_32.h
+++ b/arch/sparc/include/asm/io_32.h
@@ -4,10 +4,6 @@
#include <linux/kernel.h>
#include <linux/ioport.h> /* struct resource */
-#define readb_relaxed(__addr) readb(__addr)
-#define readw_relaxed(__addr) readw(__addr)
-#define readl_relaxed(__addr) readl(__addr)
-
#define IO_SPACE_LIMIT 0xffffffff
#define memset_io(d,c,sz) _memset_io(d,c,sz)
diff --git a/arch/sparc/include/asm/io_64.h b/arch/sparc/include/asm/io_64.h
index 80b54b3..9b672be 100644
--- a/arch/sparc/include/asm/io_64.h
+++ b/arch/sparc/include/asm/io_64.h
@@ -101,6 +101,7 @@ static inline void __raw_writeq(u64 q, const volatile void __iomem *addr)
* the cache by using ASI_PHYS_BYPASS_EC_E_L
*/
#define readb readb
+#define readb_relaxed readb
static inline u8 readb(const volatile void __iomem *addr)
{ u8 ret;
@@ -112,6 +113,7 @@ static inline u8 readb(const volatile void __iomem *addr)
}
#define readw readw
+#define readw_relaxed readw
static inline u16 readw(const volatile void __iomem *addr)
{ u16 ret;
@@ -124,6 +126,7 @@ static inline u16 readw(const volatile void __iomem *addr)
}
#define readl readl
+#define readl_relaxed readl
static inline u32 readl(const volatile void __iomem *addr)
{ u32 ret;
@@ -136,6 +139,7 @@ static inline u32 readl(const volatile void __iomem *addr)
}
#define readq readq
+#define readq_relaxed readq
static inline u64 readq(const volatile void __iomem *addr)
{ u64 ret;
@@ -148,6 +152,7 @@ static inline u64 readq(const volatile void __iomem *addr)
}
#define writeb writeb
+#define writeb_relaxed writeb
static inline void writeb(u8 b, volatile void __iomem *addr)
{
__asm__ __volatile__("stba\t%r0, [%1] %2\t/* pci_writeb */"
@@ -157,6 +162,7 @@ static inline void writeb(u8 b, volatile void __iomem *addr)
}
#define writew writew
+#define writew_relaxed writew
static inline void writew(u16 w, volatile void __iomem *addr)
{
__asm__ __volatile__("stha\t%r0, [%1] %2\t/* pci_writew */"
@@ -166,6 +172,7 @@ static inline void writew(u16 w, volatile void __iomem *addr)
}
#define writel writel
+#define writel_relaxed writel
static inline void writel(u32 l, volatile void __iomem *addr)
{
__asm__ __volatile__("stwa\t%r0, [%1] %2\t/* pci_writel */"
@@ -175,6 +182,7 @@ static inline void writel(u32 l, volatile void __iomem *addr)
}
#define writeq writeq
+#define writeq_relaxed writeq
static inline void writeq(u64 q, volatile void __iomem *addr)
{
__asm__ __volatile__("stxa\t%r0, [%1] %2\t/* pci_writeq */"
@@ -183,7 +191,6 @@ static inline void writeq(u64 q, volatile void __iomem *addr)
: "memory");
}
-
#define inb inb
static inline u8 inb(unsigned long addr)
{
@@ -264,11 +271,6 @@ static inline void iowrite32_rep(void __iomem *port, const void *buf, unsigned l
outsl((unsigned long __force)port, buf, count);
}
-#define readb_relaxed(__addr) readb(__addr)
-#define readw_relaxed(__addr) readw(__addr)
-#define readl_relaxed(__addr) readl(__addr)
-#define readq_relaxed(__addr) readq(__addr)
-
/* Valid I/O Space regions are anywhere, because each PCI bus supported
* can live in an arbitrary area of the physical address range.
*/
diff --git a/arch/sparc/include/asm/pgtable_64.h b/arch/sparc/include/asm/pgtable_64.h
index bfeb626..1ff9e78 100644
--- a/arch/sparc/include/asm/pgtable_64.h
+++ b/arch/sparc/include/asm/pgtable_64.h
@@ -667,6 +667,13 @@ static inline unsigned long pmd_pfn(pmd_t pmd)
}
#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static inline unsigned long pmd_dirty(pmd_t pmd)
+{
+ pte_t pte = __pte(pmd_val(pmd));
+
+ return pte_dirty(pte);
+}
+
static inline unsigned long pmd_young(pmd_t pmd)
{
pte_t pte = __pte(pmd_val(pmd));
diff --git a/arch/sparc/kernel/pci_msi.c b/arch/sparc/kernel/pci_msi.c
index 580651a..84e16d8 100644
--- a/arch/sparc/kernel/pci_msi.c
+++ b/arch/sparc/kernel/pci_msi.c
@@ -111,10 +111,10 @@ static void free_msi(struct pci_pbm_info *pbm, int msi_num)
static struct irq_chip msi_irq = {
.name = "PCI-MSI",
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
/* XXX affinity XXX */
};
@@ -161,7 +161,7 @@ static int sparc64_setup_msi_irq(unsigned int *irq_p,
msg.data = msi;
irq_set_msi_desc(*irq_p, entry);
- write_msi_msg(*irq_p, &msg);
+ pci_write_msi_msg(*irq_p, &msg);
return 0;
diff --git a/arch/tile/include/asm/io.h b/arch/tile/include/asm/io.h
index 9fe4349..d372641 100644
--- a/arch/tile/include/asm/io.h
+++ b/arch/tile/include/asm/io.h
@@ -241,6 +241,10 @@ static inline void writeq(u64 val, unsigned long addr)
#define readw_relaxed readw
#define readl_relaxed readl
#define readq_relaxed readq
+#define writeb_relaxed writeb
+#define writew_relaxed writew
+#define writel_relaxed writel
+#define writeq_relaxed writeq
#define ioread8 readb
#define ioread16 readw
diff --git a/arch/tile/kernel/early_printk.c b/arch/tile/kernel/early_printk.c
index b608e00..aefb2c0 100644
--- a/arch/tile/kernel/early_printk.c
+++ b/arch/tile/kernel/early_printk.c
@@ -43,13 +43,20 @@ static struct console early_hv_console = {
void early_panic(const char *fmt, ...)
{
- va_list ap;
+ struct va_format vaf;
+ va_list args;
+
arch_local_irq_disable_all();
- va_start(ap, fmt);
- early_printk("Kernel panic - not syncing: ");
- early_vprintk(fmt, ap);
- early_printk("\n");
- va_end(ap);
+
+ va_start(args, fmt);
+
+ vaf.fmt = fmt;
+ vaf.va = &args;
+
+ early_printk("Kernel panic - not syncing: %pV", &vaf);
+
+ va_end(args);
+
dump_stack();
hv_halt();
}
diff --git a/arch/tile/kernel/pci_gx.c b/arch/tile/kernel/pci_gx.c
index e39f9c5..e717af20 100644
--- a/arch/tile/kernel/pci_gx.c
+++ b/arch/tile/kernel/pci_gx.c
@@ -1453,7 +1453,7 @@ static struct pci_ops tile_cfg_ops = {
static unsigned int tilegx_msi_startup(struct irq_data *d)
{
if (d->msi_desc)
- unmask_msi_irq(d);
+ pci_msi_unmask_irq(d);
return 0;
}
@@ -1465,14 +1465,14 @@ static void tilegx_msi_ack(struct irq_data *d)
static void tilegx_msi_mask(struct irq_data *d)
{
- mask_msi_irq(d);
+ pci_msi_mask_irq(d);
__insn_mtspr(SPR_IPI_MASK_SET_K, 1UL << d->irq);
}
static void tilegx_msi_unmask(struct irq_data *d)
{
__insn_mtspr(SPR_IPI_MASK_RESET_K, 1UL << d->irq);
- unmask_msi_irq(d);
+ pci_msi_unmask_irq(d);
}
static struct irq_chip tilegx_msi_chip = {
@@ -1590,7 +1590,7 @@ int arch_setup_msi_irq(struct pci_dev *pdev, struct msi_desc *desc)
msg.address_hi = msi_addr >> 32;
msg.address_lo = msi_addr & 0xffffffff;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
irq_set_chip_and_handler(irq, &tilegx_msi_chip, handle_level_irq);
irq_set_handler_data(irq, controller);
diff --git a/arch/tile/kernel/setup.c b/arch/tile/kernel/setup.c
index b9736de..7f079bb 100644
--- a/arch/tile/kernel/setup.c
+++ b/arch/tile/kernel/setup.c
@@ -534,11 +534,10 @@ static void __init setup_memory(void)
}
}
physpages -= dropped_pages;
- pr_warning("Only using %ldMB memory;"
- " ignoring %ldMB.\n",
- physpages >> (20 - PAGE_SHIFT),
- dropped_pages >> (20 - PAGE_SHIFT));
- pr_warning("Consider using a larger page size.\n");
+ pr_warn("Only using %ldMB memory - ignoring %ldMB\n",
+ physpages >> (20 - PAGE_SHIFT),
+ dropped_pages >> (20 - PAGE_SHIFT));
+ pr_warn("Consider using a larger page size\n");
}
#endif
@@ -566,9 +565,8 @@ static void __init setup_memory(void)
#ifndef __tilegx__
if (node_end_pfn[0] > MAXMEM_PFN) {
- pr_warning("Only using %ldMB LOWMEM.\n",
- MAXMEM>>20);
- pr_warning("Use a HIGHMEM enabled kernel.\n");
+ pr_warn("Only using %ldMB LOWMEM\n", MAXMEM >> 20);
+ pr_warn("Use a HIGHMEM enabled kernel\n");
max_low_pfn = MAXMEM_PFN;
max_pfn = MAXMEM_PFN;
node_end_pfn[0] = MAXMEM_PFN;
@@ -1112,8 +1110,8 @@ static void __init load_hv_initrd(void)
fd = hv_fs_findfile((HV_VirtAddr) initramfs_file);
if (fd == HV_ENOENT) {
if (set_initramfs_file) {
- pr_warning("No such hvfs initramfs file '%s'\n",
- initramfs_file);
+ pr_warn("No such hvfs initramfs file '%s'\n",
+ initramfs_file);
return;
} else {
/* Try old backwards-compatible name. */
@@ -1126,8 +1124,8 @@ static void __init load_hv_initrd(void)
stat = hv_fs_fstat(fd);
BUG_ON(stat.size < 0);
if (stat.flags & HV_FS_ISDIR) {
- pr_warning("Ignoring hvfs file '%s': it's a directory.\n",
- initramfs_file);
+ pr_warn("Ignoring hvfs file '%s': it's a directory\n",
+ initramfs_file);
return;
}
initrd = alloc_bootmem_pages(stat.size);
@@ -1185,9 +1183,8 @@ static void __init validate_hv(void)
HV_Topology topology = hv_inquire_topology();
BUG_ON(topology.coord.x != 0 || topology.coord.y != 0);
if (topology.width != 1 || topology.height != 1) {
- pr_warning("Warning: booting UP kernel on %dx%d grid;"
- " will ignore all but first tile.\n",
- topology.width, topology.height);
+ pr_warn("Warning: booting UP kernel on %dx%d grid; will ignore all but first tile\n",
+ topology.width, topology.height);
}
#endif
@@ -1208,9 +1205,8 @@ static void __init validate_hv(void)
* We use a struct cpumask for this, so it must be big enough.
*/
if ((smp_height * smp_width) > nr_cpu_ids)
- early_panic("Hypervisor %d x %d grid too big for Linux"
- " NR_CPUS %d\n", smp_height, smp_width,
- nr_cpu_ids);
+ early_panic("Hypervisor %d x %d grid too big for Linux NR_CPUS %d\n",
+ smp_height, smp_width, nr_cpu_ids);
#endif
/*
@@ -1265,10 +1261,9 @@ static void __init validate_va(void)
/* Kernel PCs must have their high bit set; see intvec.S. */
if ((long)VMALLOC_START >= 0)
- early_panic(
- "Linux VMALLOC region below the 2GB line (%#lx)!\n"
- "Reconfigure the kernel with smaller VMALLOC_RESERVE.\n",
- VMALLOC_START);
+ early_panic("Linux VMALLOC region below the 2GB line (%#lx)!\n"
+ "Reconfigure the kernel with smaller VMALLOC_RESERVE\n",
+ VMALLOC_START);
#endif
}
@@ -1395,7 +1390,7 @@ static void __init setup_cpu_maps(void)
static int __init dataplane(char *str)
{
- pr_warning("WARNING: dataplane support disabled in this kernel\n");
+ pr_warn("WARNING: dataplane support disabled in this kernel\n");
return 0;
}
@@ -1413,8 +1408,8 @@ void __init setup_arch(char **cmdline_p)
len = hv_get_command_line((HV_VirtAddr) boot_command_line,
COMMAND_LINE_SIZE);
if (boot_command_line[0])
- pr_warning("WARNING: ignoring dynamic command line \"%s\"\n",
- boot_command_line);
+ pr_warn("WARNING: ignoring dynamic command line \"%s\"\n",
+ boot_command_line);
strlcpy(boot_command_line, builtin_cmdline, COMMAND_LINE_SIZE);
#else
char *hv_cmdline;
diff --git a/arch/um/include/asm/mmu_context.h b/arch/um/include/asm/mmu_context.h
index aa4a743..941527e 100644
--- a/arch/um/include/asm/mmu_context.h
+++ b/arch/um/include/asm/mmu_context.h
@@ -10,7 +10,26 @@
#include <asm/mmu.h>
extern void uml_setup_stubs(struct mm_struct *mm);
+/*
+ * Needed since we do not use the asm-generic/mm_hooks.h:
+ */
+static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
+{
+ uml_setup_stubs(mm);
+}
extern void arch_exit_mmap(struct mm_struct *mm);
+static inline void arch_unmap(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+static inline void arch_bprm_mm_init(struct mm_struct *mm,
+ struct vm_area_struct *vma)
+{
+}
+/*
+ * end asm-generic/mm_hooks.h functions
+ */
#define deactivate_mm(tsk,mm) do { } while (0)
@@ -41,11 +60,6 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
}
}
-static inline void arch_dup_mmap(struct mm_struct *oldmm, struct mm_struct *mm)
-{
- uml_setup_stubs(mm);
-}
-
static inline void enter_lazy_tlb(struct mm_struct *mm,
struct task_struct *tsk)
{
diff --git a/arch/unicore32/include/asm/mmu_context.h b/arch/unicore32/include/asm/mmu_context.h
index ef470a7..1cb5220 100644
--- a/arch/unicore32/include/asm/mmu_context.h
+++ b/arch/unicore32/include/asm/mmu_context.h
@@ -86,4 +86,15 @@ static inline void arch_dup_mmap(struct mm_struct *oldmm,
{
}
+static inline void arch_unmap(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+
+static inline void arch_bprm_mm_init(struct mm_struct *mm,
+ struct vm_area_struct *vma)
+{
+}
+
#endif
diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig
index 41a503c..bea3a015 100644
--- a/arch/x86/Kconfig
+++ b/arch/x86/Kconfig
@@ -248,6 +248,10 @@ config HAVE_INTEL_TXT
def_bool y
depends on INTEL_IOMMU && ACPI
+config X86_INTEL_MPX
+ def_bool y
+ depends on CPU_SUP_INTEL
+
config X86_32_SMP
def_bool y
depends on X86_32 && SMP
@@ -988,6 +992,24 @@ config X86_ESPFIX64
def_bool y
depends on X86_16BIT && X86_64
+config X86_VSYSCALL_EMULATION
+ bool "Enable vsyscall emulation" if EXPERT
+ default y
+ depends on X86_64
+ ---help---
+ This enables emulation of the legacy vsyscall page. Disabling
+ it is roughly equivalent to booting with vsyscall=none, except
+ that it will also disable the helpful warning if a program
+ tries to use a vsyscall. With this option set to N, offending
+ programs will just segfault, citing addresses of the form
+ 0xffffffffff600?00.
+
+ This option is required by many programs built before 2013, and
+ care should be used even with newer programs if set to N.
+
+ Disabling this option saves about 7K of kernel size and
+ possibly 4K of additional runtime pagetable memory.
+
config TOSHIBA
tristate "Toshiba Laptop support"
depends on X86_32
diff --git a/arch/x86/boot/compressed/Makefile b/arch/x86/boot/compressed/Makefile
index be1e07d..d999398 100644
--- a/arch/x86/boot/compressed/Makefile
+++ b/arch/x86/boot/compressed/Makefile
@@ -3,6 +3,18 @@
#
# create a compressed vmlinux image from the original vmlinux
#
+# vmlinuz is:
+# decompression code (*.o)
+# asm globals (piggy.S), including:
+# vmlinux.bin.(gz|bz2|lzma|...)
+#
+# vmlinux.bin is:
+# vmlinux stripped of debugging and comments
+# vmlinux.bin.all is:
+# vmlinux.bin + vmlinux.relocs
+# vmlinux.bin.(gz|bz2|lzma|...) is:
+# (see scripts/Makefile.lib size_append)
+# compressed vmlinux.bin.all + u32 size of vmlinux.bin.all
targets := vmlinux vmlinux.bin vmlinux.bin.gz vmlinux.bin.bz2 vmlinux.bin.lzma \
vmlinux.bin.xz vmlinux.bin.lzo vmlinux.bin.lz4
@@ -35,7 +47,8 @@ vmlinux-objs-$(CONFIG_RANDOMIZE_BASE) += $(obj)/aslr.o
$(obj)/eboot.o: KBUILD_CFLAGS += -fshort-wchar -mno-red-zone
-vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o
+vmlinux-objs-$(CONFIG_EFI_STUB) += $(obj)/eboot.o $(obj)/efi_stub_$(BITS).o \
+ $(objtree)/drivers/firmware/efi/libstub/lib.a
$(obj)/vmlinux: $(vmlinux-objs-y) FORCE
$(call if_changed,ld)
@@ -76,7 +89,7 @@ suffix-$(CONFIG_KERNEL_XZ) := xz
suffix-$(CONFIG_KERNEL_LZO) := lzo
suffix-$(CONFIG_KERNEL_LZ4) := lz4
-RUN_SIZE = $(shell objdump -h vmlinux | \
+RUN_SIZE = $(shell $(OBJDUMP) -h vmlinux | \
perl $(srctree)/arch/x86/tools/calc_run_size.pl)
quiet_cmd_mkpiggy = MKPIGGY $@
cmd_mkpiggy = $(obj)/mkpiggy $< $(RUN_SIZE) > $@ || ( rm -f $@ ; false )
diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c
index 1acf605..92b9a5f 100644
--- a/arch/x86/boot/compressed/eboot.c
+++ b/arch/x86/boot/compressed/eboot.c
@@ -21,8 +21,10 @@ static efi_system_table_t *sys_table;
static struct efi_config *efi_early;
-#define efi_call_early(f, ...) \
- efi_early->call(efi_early->f, __VA_ARGS__);
+__pure const struct efi_config *__efi_early(void)
+{
+ return efi_early;
+}
#define BOOT_SERVICES(bits) \
static void setup_boot_services##bits(struct efi_config *c) \
@@ -285,8 +287,6 @@ void efi_char16_printk(efi_system_table_t *table, efi_char16_t *str)
}
}
-#include "../../../../drivers/firmware/efi/libstub/efi-stub-helper.c"
-
static void find_bits(unsigned long mask, u8 *pos, u8 *size)
{
u8 first, len;
diff --git a/arch/x86/boot/compressed/eboot.h b/arch/x86/boot/compressed/eboot.h
index c88c31e..d487e72 100644
--- a/arch/x86/boot/compressed/eboot.h
+++ b/arch/x86/boot/compressed/eboot.h
@@ -103,20 +103,4 @@ struct efi_uga_draw_protocol {
void *blt;
};
-struct efi_config {
- u64 image_handle;
- u64 table;
- u64 allocate_pool;
- u64 allocate_pages;
- u64 get_memory_map;
- u64 free_pool;
- u64 free_pages;
- u64 locate_handle;
- u64 handle_protocol;
- u64 exit_boot_services;
- u64 text_output;
- efi_status_t (*call)(unsigned long, ...);
- bool is64;
-} __packed;
-
#endif /* BOOT_COMPRESSED_EBOOT_H */
diff --git a/arch/x86/boot/compressed/misc.c b/arch/x86/boot/compressed/misc.c
index 30dd59a..dcc1c53 100644
--- a/arch/x86/boot/compressed/misc.c
+++ b/arch/x86/boot/compressed/misc.c
@@ -260,7 +260,7 @@ static void handle_relocations(void *output, unsigned long output_len)
/*
* Process relocations: 32 bit relocations first then 64 bit after.
- * Two sets of binary relocations are added to the end of the kernel
+ * Three sets of binary relocations are added to the end of the kernel
* before compression. Each relocation table entry is the kernel
* address of the location which needs to be updated stored as a
* 32-bit value which is sign extended to 64 bits.
@@ -270,6 +270,8 @@ static void handle_relocations(void *output, unsigned long output_len)
* kernel bits...
* 0 - zero terminator for 64 bit relocations
* 64 bit relocation repeated
+ * 0 - zero terminator for inverse 32 bit relocations
+ * 32 bit inverse relocation repeated
* 0 - zero terminator for 32 bit relocations
* 32 bit relocation repeated
*
@@ -286,6 +288,16 @@ static void handle_relocations(void *output, unsigned long output_len)
*(uint32_t *)ptr += delta;
}
#ifdef CONFIG_X86_64
+ while (*--reloc) {
+ long extended = *reloc;
+ extended += map;
+
+ ptr = (unsigned long)extended;
+ if (ptr < min_addr || ptr > max_addr)
+ error("inverse 32-bit relocation outside of kernel!\n");
+
+ *(int32_t *)ptr -= delta;
+ }
for (reloc--; *reloc; reloc--) {
long extended = *reloc;
extended += map;
diff --git a/arch/x86/configs/i386_defconfig b/arch/x86/configs/i386_defconfig
index 32d2e70..419819d 100644
--- a/arch/x86/configs/i386_defconfig
+++ b/arch/x86/configs/i386_defconfig
@@ -8,6 +8,7 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_FHANDLE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/x86/configs/x86_64_defconfig b/arch/x86/configs/x86_64_defconfig
index a481dd4..4c311dd 100644
--- a/arch/x86/configs/x86_64_defconfig
+++ b/arch/x86/configs/x86_64_defconfig
@@ -7,6 +7,7 @@ CONFIG_TASKSTATS=y
CONFIG_TASK_DELAY_ACCT=y
CONFIG_TASK_XACCT=y
CONFIG_TASK_IO_ACCOUNTING=y
+CONFIG_FHANDLE=y
CONFIG_AUDIT=y
CONFIG_NO_HZ=y
CONFIG_HIGH_RES_TIMERS=y
diff --git a/arch/x86/ia32/ia32_aout.c b/arch/x86/ia32/ia32_aout.c
index df91466..ae6aad1 100644
--- a/arch/x86/ia32/ia32_aout.c
+++ b/arch/x86/ia32/ia32_aout.c
@@ -342,8 +342,8 @@ static int load_aout_binary(struct linux_binprm *bprm)
time_after(jiffies, error_time + 5*HZ)) {
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert "
- "program: %s\n",
- bprm->file->f_path.dentry->d_name.name);
+ "program: %pD\n",
+ bprm->file);
error_time = jiffies;
}
#endif
@@ -429,8 +429,8 @@ static int load_aout_library(struct file *file)
if (time_after(jiffies, error_time + 5*HZ)) {
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert "
- "library: %s\n",
- file->f_path.dentry->d_name.name);
+ "library: %pD\n",
+ file);
error_time = jiffies;
}
#endif
diff --git a/arch/x86/include/asm/cacheflush.h b/arch/x86/include/asm/cacheflush.h
index 9863ee3..47c8e32 100644
--- a/arch/x86/include/asm/cacheflush.h
+++ b/arch/x86/include/asm/cacheflush.h
@@ -5,65 +5,6 @@
#include <asm-generic/cacheflush.h>
#include <asm/special_insns.h>
-#ifdef CONFIG_X86_PAT
-/*
- * X86 PAT uses page flags WC and Uncached together to keep track of
- * memory type of pages that have backing page struct. X86 PAT supports 3
- * different memory types, _PAGE_CACHE_WB, _PAGE_CACHE_WC and
- * _PAGE_CACHE_UC_MINUS and fourth state where page's memory type has not
- * been changed from its default (value of -1 used to denote this).
- * Note we do not support _PAGE_CACHE_UC here.
- */
-
-#define _PGMT_DEFAULT 0
-#define _PGMT_WC (1UL << PG_arch_1)
-#define _PGMT_UC_MINUS (1UL << PG_uncached)
-#define _PGMT_WB (1UL << PG_uncached | 1UL << PG_arch_1)
-#define _PGMT_MASK (1UL << PG_uncached | 1UL << PG_arch_1)
-#define _PGMT_CLEAR_MASK (~_PGMT_MASK)
-
-static inline unsigned long get_page_memtype(struct page *pg)
-{
- unsigned long pg_flags = pg->flags & _PGMT_MASK;
-
- if (pg_flags == _PGMT_DEFAULT)
- return -1;
- else if (pg_flags == _PGMT_WC)
- return _PAGE_CACHE_WC;
- else if (pg_flags == _PGMT_UC_MINUS)
- return _PAGE_CACHE_UC_MINUS;
- else
- return _PAGE_CACHE_WB;
-}
-
-static inline void set_page_memtype(struct page *pg, unsigned long memtype)
-{
- unsigned long memtype_flags = _PGMT_DEFAULT;
- unsigned long old_flags;
- unsigned long new_flags;
-
- switch (memtype) {
- case _PAGE_CACHE_WC:
- memtype_flags = _PGMT_WC;
- break;
- case _PAGE_CACHE_UC_MINUS:
- memtype_flags = _PGMT_UC_MINUS;
- break;
- case _PAGE_CACHE_WB:
- memtype_flags = _PGMT_WB;
- break;
- }
-
- do {
- old_flags = pg->flags;
- new_flags = (old_flags & _PGMT_CLEAR_MASK) | memtype_flags;
- } while (cmpxchg(&pg->flags, old_flags, new_flags) != old_flags);
-}
-#else
-static inline unsigned long get_page_memtype(struct page *pg) { return -1; }
-static inline void set_page_memtype(struct page *pg, unsigned long memtype) { }
-#endif
-
/*
* The set_memory_* API can be used to change various attributes of a virtual
* address range. The attributes include:
diff --git a/arch/x86/include/asm/cpufeature.h b/arch/x86/include/asm/cpufeature.h
index 0bb1335..aede2c3 100644
--- a/arch/x86/include/asm/cpufeature.h
+++ b/arch/x86/include/asm/cpufeature.h
@@ -189,6 +189,11 @@
#define X86_FEATURE_DTHERM ( 7*32+ 7) /* Digital Thermal Sensor */
#define X86_FEATURE_HW_PSTATE ( 7*32+ 8) /* AMD HW-PState */
#define X86_FEATURE_PROC_FEEDBACK ( 7*32+ 9) /* AMD ProcFeedbackInterface */
+#define X86_FEATURE_HWP ( 7*32+ 10) /* "hwp" Intel HWP */
+#define X86_FEATURE_HWP_NOITFY ( 7*32+ 11) /* Intel HWP_NOTIFY */
+#define X86_FEATURE_HWP_ACT_WINDOW ( 7*32+ 12) /* Intel HWP_ACT_WINDOW */
+#define X86_FEATURE_HWP_EPP ( 7*32+13) /* Intel HWP_EPP */
+#define X86_FEATURE_HWP_PKG_REQ ( 7*32+14) /* Intel HWP_PKG_REQ */
/* Virtualization flags: Linux defined, word 8 */
#define X86_FEATURE_TPR_SHADOW ( 8*32+ 0) /* Intel TPR Shadow */
diff --git a/arch/x86/include/asm/disabled-features.h b/arch/x86/include/asm/disabled-features.h
index 97534a7..f226df0 100644
--- a/arch/x86/include/asm/disabled-features.h
+++ b/arch/x86/include/asm/disabled-features.h
@@ -10,6 +10,12 @@
* cpu_feature_enabled().
*/
+#ifdef CONFIG_X86_INTEL_MPX
+# define DISABLE_MPX 0
+#else
+# define DISABLE_MPX (1<<(X86_FEATURE_MPX & 31))
+#endif
+
#ifdef CONFIG_X86_64
# define DISABLE_VME (1<<(X86_FEATURE_VME & 31))
# define DISABLE_K6_MTRR (1<<(X86_FEATURE_K6_MTRR & 31))
@@ -34,6 +40,6 @@
#define DISABLED_MASK6 0
#define DISABLED_MASK7 0
#define DISABLED_MASK8 0
-#define DISABLED_MASK9 0
+#define DISABLED_MASK9 (DISABLE_MPX)
#endif /* _ASM_X86_DISABLED_FEATURES_H */
diff --git a/arch/x86/include/asm/efi.h b/arch/x86/include/asm/efi.h
index 9b11757..25bce45 100644
--- a/arch/x86/include/asm/efi.h
+++ b/arch/x86/include/asm/efi.h
@@ -158,6 +158,30 @@ static inline efi_status_t efi_thunk_set_virtual_address_map(
}
#endif /* CONFIG_EFI_MIXED */
+
+/* arch specific definitions used by the stub code */
+
+struct efi_config {
+ u64 image_handle;
+ u64 table;
+ u64 allocate_pool;
+ u64 allocate_pages;
+ u64 get_memory_map;
+ u64 free_pool;
+ u64 free_pages;
+ u64 locate_handle;
+ u64 handle_protocol;
+ u64 exit_boot_services;
+ u64 text_output;
+ efi_status_t (*call)(unsigned long, ...);
+ bool is64;
+} __packed;
+
+__pure const struct efi_config *__efi_early(void);
+
+#define efi_call_early(f, ...) \
+ __efi_early()->call(__efi_early()->f, __VA_ARGS__);
+
extern bool efi_reboot_required(void);
#else
diff --git a/arch/x86/include/asm/fb.h b/arch/x86/include/asm/fb.h
index 2519d06..c3dd5e7 100644
--- a/arch/x86/include/asm/fb.h
+++ b/arch/x86/include/asm/fb.h
@@ -8,8 +8,12 @@
static inline void fb_pgprotect(struct file *file, struct vm_area_struct *vma,
unsigned long off)
{
+ unsigned long prot;
+
+ prot = pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK;
if (boot_cpu_data.x86 > 3)
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
+ pgprot_val(vma->vm_page_prot) =
+ prot | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
}
extern int fb_is_primary_device(struct fb_info *info);
diff --git a/arch/x86/include/asm/fixmap.h b/arch/x86/include/asm/fixmap.h
index ffb1733..f80d700 100644
--- a/arch/x86/include/asm/fixmap.h
+++ b/arch/x86/include/asm/fixmap.h
@@ -69,7 +69,9 @@ enum fixed_addresses {
#ifdef CONFIG_X86_32
FIX_HOLE,
#else
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
VSYSCALL_PAGE = (FIXADDR_TOP - VSYSCALL_ADDR) >> PAGE_SHIFT,
+#endif
#ifdef CONFIG_PARAVIRT_CLOCK
PVCLOCK_FIXMAP_BEGIN,
PVCLOCK_FIXMAP_END = PVCLOCK_FIXMAP_BEGIN+PVCLOCK_VSYSCALL_NR_PAGES-1,
@@ -136,9 +138,7 @@ enum fixed_addresses {
extern void reserve_top_address(unsigned long reserve);
#define FIXADDR_SIZE (__end_of_permanent_fixed_addresses << PAGE_SHIFT)
-#define FIXADDR_BOOT_SIZE (__end_of_fixed_addresses << PAGE_SHIFT)
#define FIXADDR_START (FIXADDR_TOP - FIXADDR_SIZE)
-#define FIXADDR_BOOT_START (FIXADDR_TOP - FIXADDR_BOOT_SIZE)
extern int fixmaps_set;
diff --git a/arch/x86/include/asm/ftrace.h b/arch/x86/include/asm/ftrace.h
index e1f7fec..f45acad 100644
--- a/arch/x86/include/asm/ftrace.h
+++ b/arch/x86/include/asm/ftrace.h
@@ -1,39 +1,6 @@
#ifndef _ASM_X86_FTRACE_H
#define _ASM_X86_FTRACE_H
-#ifdef __ASSEMBLY__
-
- /* skip is set if the stack was already partially adjusted */
- .macro MCOUNT_SAVE_FRAME skip=0
- /*
- * We add enough stack to save all regs.
- */
- subq $(SS+8-\skip), %rsp
- movq %rax, RAX(%rsp)
- movq %rcx, RCX(%rsp)
- movq %rdx, RDX(%rsp)
- movq %rsi, RSI(%rsp)
- movq %rdi, RDI(%rsp)
- movq %r8, R8(%rsp)
- movq %r9, R9(%rsp)
- /* Move RIP to its proper location */
- movq SS+8(%rsp), %rdx
- movq %rdx, RIP(%rsp)
- .endm
-
- .macro MCOUNT_RESTORE_FRAME skip=0
- movq R9(%rsp), %r9
- movq R8(%rsp), %r8
- movq RDI(%rsp), %rdi
- movq RSI(%rsp), %rsi
- movq RDX(%rsp), %rdx
- movq RCX(%rsp), %rcx
- movq RAX(%rsp), %rax
- addq $(SS+8-\skip), %rsp
- .endm
-
-#endif
-
#ifdef CONFIG_FUNCTION_TRACER
#ifdef CC_USING_FENTRY
# define MCOUNT_ADDR ((long)(__fentry__))
diff --git a/arch/x86/include/asm/highmem.h b/arch/x86/include/asm/highmem.h
index 302a323..04e9d02 100644
--- a/arch/x86/include/asm/highmem.h
+++ b/arch/x86/include/asm/highmem.h
@@ -38,17 +38,20 @@ extern unsigned long highstart_pfn, highend_pfn;
/*
* Ordering is:
*
- * FIXADDR_TOP
- * fixed_addresses
- * FIXADDR_START
- * temp fixed addresses
- * FIXADDR_BOOT_START
- * Persistent kmap area
- * PKMAP_BASE
- * VMALLOC_END
- * Vmalloc area
- * VMALLOC_START
- * high_memory
+ * high memory on: high_memory off:
+ * FIXADDR_TOP FIXADDR_TOP
+ * fixed addresses fixed addresses
+ * FIXADDR_START FIXADDR_START
+ * temp fixed addresses/persistent kmap area VMALLOC_END
+ * PKMAP_BASE temp fixed addresses/vmalloc area
+ * VMALLOC_END VMALLOC_START
+ * vmalloc area high_memory
+ * VMALLOC_START
+ * high_memory
+ *
+ * The temp fixed area is only used during boot for early_ioremap(), and
+ * it is unused when the ioremap() is functional. vmalloc/pkmap area become
+ * available after early boot so the temp fixed area is available for re-use.
*/
#define LAST_PKMAP_MASK (LAST_PKMAP-1)
#define PKMAP_NR(virt) ((virt-PKMAP_BASE) >> PAGE_SHIFT)
diff --git a/arch/x86/include/asm/insn.h b/arch/x86/include/asm/insn.h
index 48eb30a..47f29b1 100644
--- a/arch/x86/include/asm/insn.h
+++ b/arch/x86/include/asm/insn.h
@@ -65,6 +65,7 @@ struct insn {
unsigned char x86_64;
const insn_byte_t *kaddr; /* kernel address of insn to analyze */
+ const insn_byte_t *end_kaddr; /* kernel address of last insn in buffer */
const insn_byte_t *next_byte;
};
@@ -96,7 +97,7 @@ struct insn {
#define X86_VEX_P(vex) ((vex) & 0x03) /* VEX3 Byte2, VEX2 Byte1 */
#define X86_VEX_M_MAX 0x1f /* VEX3.M Maximum value */
-extern void insn_init(struct insn *insn, const void *kaddr, int x86_64);
+extern void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64);
extern void insn_get_prefixes(struct insn *insn);
extern void insn_get_opcode(struct insn *insn);
extern void insn_get_modrm(struct insn *insn);
@@ -115,12 +116,13 @@ static inline void insn_get_attribute(struct insn *insn)
extern int insn_rip_relative(struct insn *insn);
/* Init insn for kernel text */
-static inline void kernel_insn_init(struct insn *insn, const void *kaddr)
+static inline void kernel_insn_init(struct insn *insn,
+ const void *kaddr, int buf_len)
{
#ifdef CONFIG_X86_64
- insn_init(insn, kaddr, 1);
+ insn_init(insn, kaddr, buf_len, 1);
#else /* CONFIG_X86_32 */
- insn_init(insn, kaddr, 0);
+ insn_init(insn, kaddr, buf_len, 0);
#endif
}
diff --git a/arch/x86/include/asm/io.h b/arch/x86/include/asm/io.h
index b8237d8..34a5b93 100644
--- a/arch/x86/include/asm/io.h
+++ b/arch/x86/include/asm/io.h
@@ -74,6 +74,9 @@ build_mmio_write(__writel, "l", unsigned int, "r", )
#define __raw_readw __readw
#define __raw_readl __readl
+#define writeb_relaxed(v, a) __writeb(v, a)
+#define writew_relaxed(v, a) __writew(v, a)
+#define writel_relaxed(v, a) __writel(v, a)
#define __raw_writeb __writeb
#define __raw_writew __writew
#define __raw_writel __writel
@@ -86,6 +89,7 @@ build_mmio_read(readq, "q", unsigned long, "=r", :"memory")
build_mmio_write(writeq, "q", unsigned long, "r", :"memory")
#define readq_relaxed(a) readq(a)
+#define writeq_relaxed(v, a) writeq(v, a)
#define __raw_readq(a) readq(a)
#define __raw_writeq(val, addr) writeq(val, addr)
@@ -310,11 +314,11 @@ BUILDIO(b, b, char)
BUILDIO(w, w, short)
BUILDIO(l, , int)
-extern void *xlate_dev_mem_ptr(unsigned long phys);
-extern void unxlate_dev_mem_ptr(unsigned long phys, void *addr);
+extern void *xlate_dev_mem_ptr(phys_addr_t phys);
+extern void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr);
extern int ioremap_change_attr(unsigned long vaddr, unsigned long size,
- unsigned long prot_val);
+ enum page_cache_mode pcm);
extern void __iomem *ioremap_wc(resource_size_t offset, unsigned long size);
extern bool is_early_ioremap_ptep(pte_t *ptep);
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 958b90f..51b26e89 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -34,6 +34,10 @@
#define MCI_STATUS_S (1ULL<<56) /* Signaled machine check */
#define MCI_STATUS_AR (1ULL<<55) /* Action required */
+/* AMD-specific bits */
+#define MCI_STATUS_DEFERRED (1ULL<<44) /* declare an uncorrected error */
+#define MCI_STATUS_POISON (1ULL<<43) /* access poisonous data */
+
/*
* Note that the full MCACOD field of IA32_MCi_STATUS MSR is
* bits 15:0. But bit 12 is the 'F' bit, defined for corrected
@@ -78,7 +82,6 @@
/* Software defined banks */
#define MCE_EXTENDED_BANK 128
#define MCE_THERMAL_BANK (MCE_EXTENDED_BANK + 0)
-#define K8_MCE_THRESHOLD_BASE (MCE_EXTENDED_BANK + 1)
#define MCE_LOG_LEN 32
#define MCE_LOG_SIGNATURE "MACHINECHECK"
diff --git a/arch/x86/include/asm/microcode.h b/arch/x86/include/asm/microcode.h
index 64dc362..201b520 100644
--- a/arch/x86/include/asm/microcode.h
+++ b/arch/x86/include/asm/microcode.h
@@ -78,6 +78,7 @@ static inline void __exit exit_amd_microcode(void) {}
extern void __init load_ucode_bsp(void);
extern void load_ucode_ap(void);
extern int __init save_microcode_in_initrd(void);
+void reload_early_microcode(void);
#else
static inline void __init load_ucode_bsp(void) {}
static inline void load_ucode_ap(void) {}
@@ -85,6 +86,7 @@ static inline int __init save_microcode_in_initrd(void)
{
return 0;
}
+static inline void reload_early_microcode(void) {}
#endif
#endif /* _ASM_X86_MICROCODE_H */
diff --git a/arch/x86/include/asm/microcode_amd.h b/arch/x86/include/asm/microcode_amd.h
index b7b10b8..af93539 100644
--- a/arch/x86/include/asm/microcode_amd.h
+++ b/arch/x86/include/asm/microcode_amd.h
@@ -59,7 +59,7 @@ static inline u16 find_equiv_id(struct equiv_cpu_entry *equiv_cpu_table,
extern int __apply_microcode_amd(struct microcode_amd *mc_amd);
extern int apply_microcode_amd(int cpu);
-extern enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size);
+extern enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size);
#define PATCH_MAX_SIZE PAGE_SIZE
extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
@@ -68,10 +68,12 @@ extern u8 amd_ucode_patch[PATCH_MAX_SIZE];
extern void __init load_ucode_amd_bsp(void);
extern void load_ucode_amd_ap(void);
extern int __init save_microcode_in_initrd_amd(void);
+void reload_ucode_amd(void);
#else
static inline void __init load_ucode_amd_bsp(void) {}
static inline void load_ucode_amd_ap(void) {}
static inline int __init save_microcode_in_initrd_amd(void) { return -EINVAL; }
+void reload_ucode_amd(void) {}
#endif
#endif /* _ASM_X86_MICROCODE_AMD_H */
diff --git a/arch/x86/include/asm/microcode_intel.h b/arch/x86/include/asm/microcode_intel.h
index bbe296e..dd4c200 100644
--- a/arch/x86/include/asm/microcode_intel.h
+++ b/arch/x86/include/asm/microcode_intel.h
@@ -68,11 +68,13 @@ extern void __init load_ucode_intel_bsp(void);
extern void load_ucode_intel_ap(void);
extern void show_ucode_info_early(void);
extern int __init save_microcode_in_initrd_intel(void);
+void reload_ucode_intel(void);
#else
static inline __init void load_ucode_intel_bsp(void) {}
static inline void load_ucode_intel_ap(void) {}
static inline void show_ucode_info_early(void) {}
static inline int __init save_microcode_in_initrd_intel(void) { return -EINVAL; }
+static inline void reload_ucode_intel(void) {}
#endif
#if defined(CONFIG_MICROCODE_INTEL_EARLY) && defined(CONFIG_HOTPLUG_CPU)
diff --git a/arch/x86/include/asm/mmu_context.h b/arch/x86/include/asm/mmu_context.h
index 166af2a..40269a2 100644
--- a/arch/x86/include/asm/mmu_context.h
+++ b/arch/x86/include/asm/mmu_context.h
@@ -10,9 +10,8 @@
#include <asm/pgalloc.h>
#include <asm/tlbflush.h>
#include <asm/paravirt.h>
+#include <asm/mpx.h>
#ifndef CONFIG_PARAVIRT
-#include <asm-generic/mm_hooks.h>
-
static inline void paravirt_activate_mm(struct mm_struct *prev,
struct mm_struct *next)
{
@@ -53,7 +52,16 @@ static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next,
/* Stop flush ipis for the previous mm */
cpumask_clear_cpu(cpu, mm_cpumask(prev));
- /* Load the LDT, if the LDT is different: */
+ /*
+ * Load the LDT, if the LDT is different.
+ *
+ * It's possible leave_mm(prev) has been called. If so,
+ * then prev->context.ldt could be out of sync with the
+ * LDT descriptor or the LDT register. This can only happen
+ * if prev->context.ldt is non-null, since we never free
+ * an LDT. But LDTs can't be shared across mms, so
+ * prev->context.ldt won't be equal to next->context.ldt.
+ */
if (unlikely(prev->context.ldt != next->context.ldt))
load_LDT_nolock(&next->context);
}
@@ -102,4 +110,27 @@ do { \
} while (0)
#endif
+static inline void arch_dup_mmap(struct mm_struct *oldmm,
+ struct mm_struct *mm)
+{
+ paravirt_arch_dup_mmap(oldmm, mm);
+}
+
+static inline void arch_exit_mmap(struct mm_struct *mm)
+{
+ paravirt_arch_exit_mmap(mm);
+}
+
+static inline void arch_bprm_mm_init(struct mm_struct *mm,
+ struct vm_area_struct *vma)
+{
+ mpx_mm_init(mm);
+}
+
+static inline void arch_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ mpx_notify_unmap(mm, vma, start, end);
+}
+
#endif /* _ASM_X86_MMU_CONTEXT_H */
diff --git a/arch/x86/include/asm/mpx.h b/arch/x86/include/asm/mpx.h
new file mode 100644
index 0000000..a952a13d
--- /dev/null
+++ b/arch/x86/include/asm/mpx.h
@@ -0,0 +1,103 @@
+#ifndef _ASM_X86_MPX_H
+#define _ASM_X86_MPX_H
+
+#include <linux/types.h>
+#include <asm/ptrace.h>
+#include <asm/insn.h>
+
+/*
+ * NULL is theoretically a valid place to put the bounds
+ * directory, so point this at an invalid address.
+ */
+#define MPX_INVALID_BOUNDS_DIR ((void __user *)-1)
+#define MPX_BNDCFG_ENABLE_FLAG 0x1
+#define MPX_BD_ENTRY_VALID_FLAG 0x1
+
+#ifdef CONFIG_X86_64
+
+/* upper 28 bits [47:20] of the virtual address in 64-bit used to
+ * index into bounds directory (BD).
+ */
+#define MPX_BD_ENTRY_OFFSET 28
+#define MPX_BD_ENTRY_SHIFT 3
+/* bits [19:3] of the virtual address in 64-bit used to index into
+ * bounds table (BT).
+ */
+#define MPX_BT_ENTRY_OFFSET 17
+#define MPX_BT_ENTRY_SHIFT 5
+#define MPX_IGN_BITS 3
+#define MPX_BD_ENTRY_TAIL 3
+
+#else
+
+#define MPX_BD_ENTRY_OFFSET 20
+#define MPX_BD_ENTRY_SHIFT 2
+#define MPX_BT_ENTRY_OFFSET 10
+#define MPX_BT_ENTRY_SHIFT 4
+#define MPX_IGN_BITS 2
+#define MPX_BD_ENTRY_TAIL 2
+
+#endif
+
+#define MPX_BD_SIZE_BYTES (1UL<<(MPX_BD_ENTRY_OFFSET+MPX_BD_ENTRY_SHIFT))
+#define MPX_BT_SIZE_BYTES (1UL<<(MPX_BT_ENTRY_OFFSET+MPX_BT_ENTRY_SHIFT))
+
+#define MPX_BNDSTA_TAIL 2
+#define MPX_BNDCFG_TAIL 12
+#define MPX_BNDSTA_ADDR_MASK (~((1UL<<MPX_BNDSTA_TAIL)-1))
+#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
+#define MPX_BT_ADDR_MASK (~((1UL<<MPX_BD_ENTRY_TAIL)-1))
+
+#define MPX_BNDCFG_ADDR_MASK (~((1UL<<MPX_BNDCFG_TAIL)-1))
+#define MPX_BNDSTA_ERROR_CODE 0x3
+
+#define MPX_BD_ENTRY_MASK ((1<<MPX_BD_ENTRY_OFFSET)-1)
+#define MPX_BT_ENTRY_MASK ((1<<MPX_BT_ENTRY_OFFSET)-1)
+#define MPX_GET_BD_ENTRY_OFFSET(addr) ((((addr)>>(MPX_BT_ENTRY_OFFSET+ \
+ MPX_IGN_BITS)) & MPX_BD_ENTRY_MASK) << MPX_BD_ENTRY_SHIFT)
+#define MPX_GET_BT_ENTRY_OFFSET(addr) ((((addr)>>MPX_IGN_BITS) & \
+ MPX_BT_ENTRY_MASK) << MPX_BT_ENTRY_SHIFT)
+
+#ifdef CONFIG_X86_INTEL_MPX
+siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
+ struct xsave_struct *xsave_buf);
+int mpx_handle_bd_fault(struct xsave_struct *xsave_buf);
+static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
+{
+ return (mm->bd_addr != MPX_INVALID_BOUNDS_DIR);
+}
+static inline void mpx_mm_init(struct mm_struct *mm)
+{
+ /*
+ * NULL is theoretically a valid place to put the bounds
+ * directory, so point this at an invalid address.
+ */
+ mm->bd_addr = MPX_INVALID_BOUNDS_DIR;
+}
+void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end);
+#else
+static inline siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
+ struct xsave_struct *xsave_buf)
+{
+ return NULL;
+}
+static inline int mpx_handle_bd_fault(struct xsave_struct *xsave_buf)
+{
+ return -EINVAL;
+}
+static inline int kernel_managing_mpx_tables(struct mm_struct *mm)
+{
+ return 0;
+}
+static inline void mpx_mm_init(struct mm_struct *mm)
+{
+}
+static inline void mpx_notify_unmap(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+#endif /* CONFIG_X86_INTEL_MPX */
+
+#endif /* _ASM_X86_MPX_H */
diff --git a/arch/x86/include/asm/page_64.h b/arch/x86/include/asm/page_64.h
index f408caf..b3bebf9 100644
--- a/arch/x86/include/asm/page_64.h
+++ b/arch/x86/include/asm/page_64.h
@@ -39,6 +39,8 @@ void copy_page(void *to, void *from);
#endif /* !__ASSEMBLY__ */
-#define __HAVE_ARCH_GATE_AREA 1
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
+# define __HAVE_ARCH_GATE_AREA 1
+#endif
#endif /* _ASM_X86_PAGE_64_H */
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index cd6e161..32444ae 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -330,13 +330,13 @@ static inline void paravirt_activate_mm(struct mm_struct *prev,
PVOP_VCALL2(pv_mmu_ops.activate_mm, prev, next);
}
-static inline void arch_dup_mmap(struct mm_struct *oldmm,
- struct mm_struct *mm)
+static inline void paravirt_arch_dup_mmap(struct mm_struct *oldmm,
+ struct mm_struct *mm)
{
PVOP_VCALL2(pv_mmu_ops.dup_mmap, oldmm, mm);
}
-static inline void arch_exit_mmap(struct mm_struct *mm)
+static inline void paravirt_arch_exit_mmap(struct mm_struct *mm)
{
PVOP_VCALL1(pv_mmu_ops.exit_mmap, mm);
}
@@ -986,5 +986,15 @@ extern void default_banner(void);
#endif /* __ASSEMBLY__ */
#else /* CONFIG_PARAVIRT */
# define default_banner x86_init_noop
+#ifndef __ASSEMBLY__
+static inline void paravirt_arch_dup_mmap(struct mm_struct *oldmm,
+ struct mm_struct *mm)
+{
+}
+
+static inline void paravirt_arch_exit_mmap(struct mm_struct *mm)
+{
+}
+#endif /* __ASSEMBLY__ */
#endif /* !CONFIG_PARAVIRT */
#endif /* _ASM_X86_PARAVIRT_H */
diff --git a/arch/x86/include/asm/pat.h b/arch/x86/include/asm/pat.h
index e2c1668..91bc4ba 100644
--- a/arch/x86/include/asm/pat.h
+++ b/arch/x86/include/asm/pat.h
@@ -11,16 +11,17 @@ static const int pat_enabled;
#endif
extern void pat_init(void);
+void pat_init_cache_modes(void);
extern int reserve_memtype(u64 start, u64 end,
- unsigned long req_type, unsigned long *ret_type);
+ enum page_cache_mode req_pcm, enum page_cache_mode *ret_pcm);
extern int free_memtype(u64 start, u64 end);
extern int kernel_map_sync_memtype(u64 base, unsigned long size,
- unsigned long flag);
+ enum page_cache_mode pcm);
int io_reserve_memtype(resource_size_t start, resource_size_t end,
- unsigned long *type);
+ enum page_cache_mode *pcm);
void io_free_memtype(resource_size_t start, resource_size_t end);
diff --git a/arch/x86/include/asm/percpu.h b/arch/x86/include/asm/percpu.h
index fd47218..e0ba66c 100644
--- a/arch/x86/include/asm/percpu.h
+++ b/arch/x86/include/asm/percpu.h
@@ -64,7 +64,7 @@
#define __percpu_prefix ""
#endif
-#define __percpu_arg(x) __percpu_prefix "%P" #x
+#define __percpu_arg(x) __percpu_prefix "%" #x
/*
* Initialized pointers to per-cpu variables needed for the boot
@@ -179,29 +179,58 @@ do { \
} \
} while (0)
-#define percpu_from_op(op, var, constraint) \
+#define percpu_from_op(op, var) \
({ \
typeof(var) pfo_ret__; \
switch (sizeof(var)) { \
case 1: \
asm(op "b "__percpu_arg(1)",%0" \
: "=q" (pfo_ret__) \
- : constraint); \
+ : "m" (var)); \
break; \
case 2: \
asm(op "w "__percpu_arg(1)",%0" \
: "=r" (pfo_ret__) \
- : constraint); \
+ : "m" (var)); \
break; \
case 4: \
asm(op "l "__percpu_arg(1)",%0" \
: "=r" (pfo_ret__) \
- : constraint); \
+ : "m" (var)); \
break; \
case 8: \
asm(op "q "__percpu_arg(1)",%0" \
: "=r" (pfo_ret__) \
- : constraint); \
+ : "m" (var)); \
+ break; \
+ default: __bad_percpu_size(); \
+ } \
+ pfo_ret__; \
+})
+
+#define percpu_stable_op(op, var) \
+({ \
+ typeof(var) pfo_ret__; \
+ switch (sizeof(var)) { \
+ case 1: \
+ asm(op "b "__percpu_arg(P1)",%0" \
+ : "=q" (pfo_ret__) \
+ : "p" (&(var))); \
+ break; \
+ case 2: \
+ asm(op "w "__percpu_arg(P1)",%0" \
+ : "=r" (pfo_ret__) \
+ : "p" (&(var))); \
+ break; \
+ case 4: \
+ asm(op "l "__percpu_arg(P1)",%0" \
+ : "=r" (pfo_ret__) \
+ : "p" (&(var))); \
+ break; \
+ case 8: \
+ asm(op "q "__percpu_arg(P1)",%0" \
+ : "=r" (pfo_ret__) \
+ : "p" (&(var))); \
break; \
default: __bad_percpu_size(); \
} \
@@ -359,11 +388,11 @@ do { \
* per-thread variables implemented as per-cpu variables and thus
* stable for the duration of the respective task.
*/
-#define this_cpu_read_stable(var) percpu_from_op("mov", var, "p" (&(var)))
+#define this_cpu_read_stable(var) percpu_stable_op("mov", var)
-#define raw_cpu_read_1(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
-#define raw_cpu_read_2(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
-#define raw_cpu_read_4(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define raw_cpu_read_1(pcp) percpu_from_op("mov", pcp)
+#define raw_cpu_read_2(pcp) percpu_from_op("mov", pcp)
+#define raw_cpu_read_4(pcp) percpu_from_op("mov", pcp)
#define raw_cpu_write_1(pcp, val) percpu_to_op("mov", (pcp), val)
#define raw_cpu_write_2(pcp, val) percpu_to_op("mov", (pcp), val)
@@ -381,9 +410,9 @@ do { \
#define raw_cpu_xchg_2(pcp, val) percpu_xchg_op(pcp, val)
#define raw_cpu_xchg_4(pcp, val) percpu_xchg_op(pcp, val)
-#define this_cpu_read_1(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
-#define this_cpu_read_2(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
-#define this_cpu_read_4(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_read_1(pcp) percpu_from_op("mov", pcp)
+#define this_cpu_read_2(pcp) percpu_from_op("mov", pcp)
+#define this_cpu_read_4(pcp) percpu_from_op("mov", pcp)
#define this_cpu_write_1(pcp, val) percpu_to_op("mov", (pcp), val)
#define this_cpu_write_2(pcp, val) percpu_to_op("mov", (pcp), val)
#define this_cpu_write_4(pcp, val) percpu_to_op("mov", (pcp), val)
@@ -435,7 +464,7 @@ do { \
* 32 bit must fall back to generic operations.
*/
#ifdef CONFIG_X86_64
-#define raw_cpu_read_8(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define raw_cpu_read_8(pcp) percpu_from_op("mov", pcp)
#define raw_cpu_write_8(pcp, val) percpu_to_op("mov", (pcp), val)
#define raw_cpu_add_8(pcp, val) percpu_add_op((pcp), val)
#define raw_cpu_and_8(pcp, val) percpu_to_op("and", (pcp), val)
@@ -444,7 +473,7 @@ do { \
#define raw_cpu_xchg_8(pcp, nval) percpu_xchg_op(pcp, nval)
#define raw_cpu_cmpxchg_8(pcp, oval, nval) percpu_cmpxchg_op(pcp, oval, nval)
-#define this_cpu_read_8(pcp) percpu_from_op("mov", (pcp), "m"(pcp))
+#define this_cpu_read_8(pcp) percpu_from_op("mov", pcp)
#define this_cpu_write_8(pcp, val) percpu_to_op("mov", (pcp), val)
#define this_cpu_add_8(pcp, val) percpu_add_op((pcp), val)
#define this_cpu_and_8(pcp, val) percpu_to_op("and", (pcp), val)
@@ -522,7 +551,7 @@ static inline int x86_this_cpu_variable_test_bit(int nr,
#include <asm-generic/percpu.h>
/* We can use this directly for local CPU (faster). */
-DECLARE_PER_CPU(unsigned long, this_cpu_off);
+DECLARE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off);
#endif /* !__ASSEMBLY__ */
diff --git a/arch/x86/include/asm/perf_event.h b/arch/x86/include/asm/perf_event.h
index 8dfc9fd..dc0f6ed 100644
--- a/arch/x86/include/asm/perf_event.h
+++ b/arch/x86/include/asm/perf_event.h
@@ -177,6 +177,9 @@ struct x86_pmu_capability {
#define IBS_CAPS_BRNTRGT (1U<<5)
#define IBS_CAPS_OPCNTEXT (1U<<6)
#define IBS_CAPS_RIPINVALIDCHK (1U<<7)
+#define IBS_CAPS_OPBRNFUSE (1U<<8)
+#define IBS_CAPS_FETCHCTLEXTD (1U<<9)
+#define IBS_CAPS_OPDATA4 (1U<<10)
#define IBS_CAPS_DEFAULT (IBS_CAPS_AVAIL \
| IBS_CAPS_FETCHSAM \
diff --git a/arch/x86/include/asm/pgtable.h b/arch/x86/include/asm/pgtable.h
index aa97a07..e8a5454 100644
--- a/arch/x86/include/asm/pgtable.h
+++ b/arch/x86/include/asm/pgtable.h
@@ -9,9 +9,10 @@
/*
* Macro to mark a page protection value as UC-
*/
-#define pgprot_noncached(prot) \
- ((boot_cpu_data.x86 > 3) \
- ? (__pgprot(pgprot_val(prot) | _PAGE_CACHE_UC_MINUS)) \
+#define pgprot_noncached(prot) \
+ ((boot_cpu_data.x86 > 3) \
+ ? (__pgprot(pgprot_val(prot) | \
+ cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))) \
: (prot))
#ifndef __ASSEMBLY__
@@ -99,6 +100,11 @@ static inline int pte_young(pte_t pte)
return pte_flags(pte) & _PAGE_ACCESSED;
}
+static inline int pmd_dirty(pmd_t pmd)
+{
+ return pmd_flags(pmd) & _PAGE_DIRTY;
+}
+
static inline int pmd_young(pmd_t pmd)
{
return pmd_flags(pmd) & _PAGE_ACCESSED;
@@ -404,8 +410,8 @@ static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot)
#define canon_pgprot(p) __pgprot(massage_pgprot(p))
static inline int is_new_memtype_allowed(u64 paddr, unsigned long size,
- unsigned long flags,
- unsigned long new_flags)
+ enum page_cache_mode pcm,
+ enum page_cache_mode new_pcm)
{
/*
* PAT type is always WB for untracked ranges, so no need to check.
@@ -419,10 +425,10 @@ static inline int is_new_memtype_allowed(u64 paddr, unsigned long size,
* - request is uncached, return cannot be write-back
* - request is write-combine, return cannot be write-back
*/
- if ((flags == _PAGE_CACHE_UC_MINUS &&
- new_flags == _PAGE_CACHE_WB) ||
- (flags == _PAGE_CACHE_WC &&
- new_flags == _PAGE_CACHE_WB)) {
+ if ((pcm == _PAGE_CACHE_MODE_UC_MINUS &&
+ new_pcm == _PAGE_CACHE_MODE_WB) ||
+ (pcm == _PAGE_CACHE_MODE_WC &&
+ new_pcm == _PAGE_CACHE_MODE_WB)) {
return 0;
}
diff --git a/arch/x86/include/asm/pgtable_32_types.h b/arch/x86/include/asm/pgtable_32_types.h
index ed5903b..9fb2f2b 100644
--- a/arch/x86/include/asm/pgtable_32_types.h
+++ b/arch/x86/include/asm/pgtable_32_types.h
@@ -37,7 +37,7 @@ extern bool __vmalloc_start_set; /* set once high_memory is set */
#define LAST_PKMAP 1024
#endif
-#define PKMAP_BASE ((FIXADDR_BOOT_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
+#define PKMAP_BASE ((FIXADDR_START - PAGE_SIZE * (LAST_PKMAP + 1)) \
& PMD_MASK)
#ifdef CONFIG_HIGHMEM
diff --git a/arch/x86/include/asm/pgtable_64_types.h b/arch/x86/include/asm/pgtable_64_types.h
index 7166e25..602b602 100644
--- a/arch/x86/include/asm/pgtable_64_types.h
+++ b/arch/x86/include/asm/pgtable_64_types.h
@@ -63,6 +63,8 @@ typedef struct { pteval_t pte; } pte_t;
#define MODULES_LEN (MODULES_END - MODULES_VADDR)
#define ESPFIX_PGD_ENTRY _AC(-2, UL)
#define ESPFIX_BASE_ADDR (ESPFIX_PGD_ENTRY << PGDIR_SHIFT)
+#define EFI_VA_START ( -4 * (_AC(1, UL) << 30))
+#define EFI_VA_END (-68 * (_AC(1, UL) << 30))
#define EARLY_DYNAMIC_PAGE_TABLES 64
diff --git a/arch/x86/include/asm/pgtable_types.h b/arch/x86/include/asm/pgtable_types.h
index 0778964..af447f9 100644
--- a/arch/x86/include/asm/pgtable_types.h
+++ b/arch/x86/include/asm/pgtable_types.h
@@ -128,11 +128,28 @@
_PAGE_SOFT_DIRTY | _PAGE_NUMA)
#define _HPAGE_CHG_MASK (_PAGE_CHG_MASK | _PAGE_PSE | _PAGE_NUMA)
-#define _PAGE_CACHE_MASK (_PAGE_PCD | _PAGE_PWT)
-#define _PAGE_CACHE_WB (0)
-#define _PAGE_CACHE_WC (_PAGE_PWT)
-#define _PAGE_CACHE_UC_MINUS (_PAGE_PCD)
-#define _PAGE_CACHE_UC (_PAGE_PCD | _PAGE_PWT)
+/*
+ * The cache modes defined here are used to translate between pure SW usage
+ * and the HW defined cache mode bits and/or PAT entries.
+ *
+ * The resulting bits for PWT, PCD and PAT should be chosen in a way
+ * to have the WB mode at index 0 (all bits clear). This is the default
+ * right now and likely would break too much if changed.
+ */
+#ifndef __ASSEMBLY__
+enum page_cache_mode {
+ _PAGE_CACHE_MODE_WB = 0,
+ _PAGE_CACHE_MODE_WC = 1,
+ _PAGE_CACHE_MODE_UC_MINUS = 2,
+ _PAGE_CACHE_MODE_UC = 3,
+ _PAGE_CACHE_MODE_WT = 4,
+ _PAGE_CACHE_MODE_WP = 5,
+ _PAGE_CACHE_MODE_NUM = 8
+};
+#endif
+
+#define _PAGE_CACHE_MASK (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)
+#define _PAGE_NOCACHE (cachemode2protval(_PAGE_CACHE_MODE_UC))
#define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED)
#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | \
@@ -156,41 +173,27 @@
#define __PAGE_KERNEL_RO (__PAGE_KERNEL & ~_PAGE_RW)
#define __PAGE_KERNEL_RX (__PAGE_KERNEL_EXEC & ~_PAGE_RW)
-#define __PAGE_KERNEL_EXEC_NOCACHE (__PAGE_KERNEL_EXEC | _PAGE_PCD | _PAGE_PWT)
-#define __PAGE_KERNEL_WC (__PAGE_KERNEL | _PAGE_CACHE_WC)
-#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD | _PAGE_PWT)
-#define __PAGE_KERNEL_UC_MINUS (__PAGE_KERNEL | _PAGE_PCD)
+#define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_NOCACHE)
#define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER)
#define __PAGE_KERNEL_VVAR (__PAGE_KERNEL_RO | _PAGE_USER)
-#define __PAGE_KERNEL_VVAR_NOCACHE (__PAGE_KERNEL_VVAR | _PAGE_PCD | _PAGE_PWT)
#define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE)
-#define __PAGE_KERNEL_LARGE_NOCACHE (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE)
#define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE)
#define __PAGE_KERNEL_IO (__PAGE_KERNEL)
#define __PAGE_KERNEL_IO_NOCACHE (__PAGE_KERNEL_NOCACHE)
-#define __PAGE_KERNEL_IO_UC_MINUS (__PAGE_KERNEL_UC_MINUS)
-#define __PAGE_KERNEL_IO_WC (__PAGE_KERNEL_WC)
#define PAGE_KERNEL __pgprot(__PAGE_KERNEL)
#define PAGE_KERNEL_RO __pgprot(__PAGE_KERNEL_RO)
#define PAGE_KERNEL_EXEC __pgprot(__PAGE_KERNEL_EXEC)
#define PAGE_KERNEL_RX __pgprot(__PAGE_KERNEL_RX)
-#define PAGE_KERNEL_WC __pgprot(__PAGE_KERNEL_WC)
#define PAGE_KERNEL_NOCACHE __pgprot(__PAGE_KERNEL_NOCACHE)
-#define PAGE_KERNEL_UC_MINUS __pgprot(__PAGE_KERNEL_UC_MINUS)
-#define PAGE_KERNEL_EXEC_NOCACHE __pgprot(__PAGE_KERNEL_EXEC_NOCACHE)
#define PAGE_KERNEL_LARGE __pgprot(__PAGE_KERNEL_LARGE)
-#define PAGE_KERNEL_LARGE_NOCACHE __pgprot(__PAGE_KERNEL_LARGE_NOCACHE)
#define PAGE_KERNEL_LARGE_EXEC __pgprot(__PAGE_KERNEL_LARGE_EXEC)
#define PAGE_KERNEL_VSYSCALL __pgprot(__PAGE_KERNEL_VSYSCALL)
#define PAGE_KERNEL_VVAR __pgprot(__PAGE_KERNEL_VVAR)
-#define PAGE_KERNEL_VVAR_NOCACHE __pgprot(__PAGE_KERNEL_VVAR_NOCACHE)
#define PAGE_KERNEL_IO __pgprot(__PAGE_KERNEL_IO)
#define PAGE_KERNEL_IO_NOCACHE __pgprot(__PAGE_KERNEL_IO_NOCACHE)
-#define PAGE_KERNEL_IO_UC_MINUS __pgprot(__PAGE_KERNEL_IO_UC_MINUS)
-#define PAGE_KERNEL_IO_WC __pgprot(__PAGE_KERNEL_IO_WC)
/* xwr */
#define __P000 PAGE_NONE
@@ -341,6 +344,59 @@ static inline pmdval_t pmdnuma_flags(pmd_t pmd)
#define pgprot_val(x) ((x).pgprot)
#define __pgprot(x) ((pgprot_t) { (x) } )
+extern uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM];
+extern uint8_t __pte2cachemode_tbl[8];
+
+#define __pte2cm_idx(cb) \
+ ((((cb) >> (_PAGE_BIT_PAT - 2)) & 4) | \
+ (((cb) >> (_PAGE_BIT_PCD - 1)) & 2) | \
+ (((cb) >> _PAGE_BIT_PWT) & 1))
+#define __cm_idx2pte(i) \
+ ((((i) & 4) << (_PAGE_BIT_PAT - 2)) | \
+ (((i) & 2) << (_PAGE_BIT_PCD - 1)) | \
+ (((i) & 1) << _PAGE_BIT_PWT))
+
+static inline unsigned long cachemode2protval(enum page_cache_mode pcm)
+{
+ if (likely(pcm == 0))
+ return 0;
+ return __cachemode2pte_tbl[pcm];
+}
+static inline pgprot_t cachemode2pgprot(enum page_cache_mode pcm)
+{
+ return __pgprot(cachemode2protval(pcm));
+}
+static inline enum page_cache_mode pgprot2cachemode(pgprot_t pgprot)
+{
+ unsigned long masked;
+
+ masked = pgprot_val(pgprot) & _PAGE_CACHE_MASK;
+ if (likely(masked == 0))
+ return 0;
+ return __pte2cachemode_tbl[__pte2cm_idx(masked)];
+}
+static inline pgprot_t pgprot_4k_2_large(pgprot_t pgprot)
+{
+ pgprot_t new;
+ unsigned long val;
+
+ val = pgprot_val(pgprot);
+ pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
+ ((val & _PAGE_PAT) << (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
+ return new;
+}
+static inline pgprot_t pgprot_large_2_4k(pgprot_t pgprot)
+{
+ pgprot_t new;
+ unsigned long val;
+
+ val = pgprot_val(pgprot);
+ pgprot_val(new) = (val & ~(_PAGE_PAT | _PAGE_PAT_LARGE)) |
+ ((val & _PAGE_PAT_LARGE) >>
+ (_PAGE_BIT_PAT_LARGE - _PAGE_BIT_PAT));
+ return new;
+}
+
typedef struct page *pgtable_t;
diff --git a/arch/x86/include/asm/platform_sst_audio.h b/arch/x86/include/asm/platform_sst_audio.h
index 0a4e140..7249e6d 100644
--- a/arch/x86/include/asm/platform_sst_audio.h
+++ b/arch/x86/include/asm/platform_sst_audio.h
@@ -16,6 +16,9 @@
#include <linux/sfi.h>
+#define MAX_NUM_STREAMS_MRFLD 25
+#define MAX_NUM_STREAMS MAX_NUM_STREAMS_MRFLD
+
enum sst_audio_task_id_mrfld {
SST_TASK_ID_NONE = 0,
SST_TASK_ID_SBA = 1,
@@ -73,6 +76,65 @@ struct sst_platform_data {
unsigned int strm_map_size;
};
+struct sst_info {
+ u32 iram_start;
+ u32 iram_end;
+ bool iram_use;
+ u32 dram_start;
+ u32 dram_end;
+ bool dram_use;
+ u32 imr_start;
+ u32 imr_end;
+ bool imr_use;
+ u32 mailbox_start;
+ bool use_elf;
+ bool lpe_viewpt_rqd;
+ unsigned int max_streams;
+ u32 dma_max_len;
+ u8 num_probes;
+};
+
+struct sst_lib_dnld_info {
+ unsigned int mod_base;
+ unsigned int mod_end;
+ unsigned int mod_table_offset;
+ unsigned int mod_table_size;
+ bool mod_ddr_dnld;
+};
+
+struct sst_res_info {
+ unsigned int shim_offset;
+ unsigned int shim_size;
+ unsigned int shim_phy_addr;
+ unsigned int ssp0_offset;
+ unsigned int ssp0_size;
+ unsigned int dma0_offset;
+ unsigned int dma0_size;
+ unsigned int dma1_offset;
+ unsigned int dma1_size;
+ unsigned int iram_offset;
+ unsigned int iram_size;
+ unsigned int dram_offset;
+ unsigned int dram_size;
+ unsigned int mbox_offset;
+ unsigned int mbox_size;
+ unsigned int acpi_lpe_res_index;
+ unsigned int acpi_ddr_index;
+ unsigned int acpi_ipc_irq_index;
+};
+
+struct sst_ipc_info {
+ int ipc_offset;
+ unsigned int mbox_recv_off;
+};
+
+struct sst_platform_info {
+ const struct sst_info *probe_data;
+ const struct sst_ipc_info *ipc_info;
+ const struct sst_res_info *res_info;
+ const struct sst_lib_dnld_info *lib_info;
+ const char *platform;
+};
int add_sst_platform_device(void);
#endif
diff --git a/arch/x86/include/asm/preempt.h b/arch/x86/include/asm/preempt.h
index 4008734..8f327184 100644
--- a/arch/x86/include/asm/preempt.h
+++ b/arch/x86/include/asm/preempt.h
@@ -30,9 +30,6 @@ static __always_inline void preempt_count_set(int pc)
/*
* must be macros to avoid header recursion hell
*/
-#define task_preempt_count(p) \
- (task_thread_info(p)->saved_preempt_count & ~PREEMPT_NEED_RESCHED)
-
#define init_task_preempt_count(p) do { \
task_thread_info(p)->saved_preempt_count = PREEMPT_DISABLED; \
} while (0)
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h
index eb71ec7..a092a0c 100644
--- a/arch/x86/include/asm/processor.h
+++ b/arch/x86/include/asm/processor.h
@@ -127,7 +127,7 @@ struct cpuinfo_x86 {
/* Index into per_cpu list: */
u16 cpu_index;
u32 microcode;
-} __attribute__((__aligned__(SMP_CACHE_BYTES)));
+};
#define X86_VENDOR_INTEL 0
#define X86_VENDOR_CYRIX 1
@@ -151,7 +151,7 @@ extern __u32 cpu_caps_cleared[NCAPINTS];
extern __u32 cpu_caps_set[NCAPINTS];
#ifdef CONFIG_SMP
-DECLARE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
+DECLARE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
#define cpu_data(cpu) per_cpu(cpu_info, cpu)
#else
#define cpu_info boot_cpu_data
@@ -374,13 +374,14 @@ struct lwp_struct {
u8 reserved[128];
};
-struct bndregs_struct {
- u64 bndregs[8];
+struct bndreg {
+ u64 lower_bound;
+ u64 upper_bound;
} __packed;
-struct bndcsr_struct {
- u64 cfg_reg_u;
- u64 status_reg;
+struct bndcsr {
+ u64 bndcfgu;
+ u64 bndstatus;
} __packed;
struct xsave_hdr_struct {
@@ -394,8 +395,8 @@ struct xsave_struct {
struct xsave_hdr_struct xsave_hdr;
struct ymmh_struct ymmh;
struct lwp_struct lwp;
- struct bndregs_struct bndregs;
- struct bndcsr_struct bndcsr;
+ struct bndreg bndreg[4];
+ struct bndcsr bndcsr;
/* new processor state extensions will go here */
} __attribute__ ((packed, aligned (64)));
@@ -893,7 +894,13 @@ extern unsigned long thread_saved_pc(struct task_struct *tsk);
#else
/*
- * User space process size. 47bits minus one guard page.
+ * User space process size. 47bits minus one guard page. The guard
+ * page is necessary on Intel CPUs: if a SYSCALL instruction is at
+ * the highest possible canonical userspace address, then that
+ * syscall will enter the kernel with a non-canonical return
+ * address, and SYSRET will explode dangerously. We avoid this
+ * particular problem by preventing anything from being mapped
+ * at the maximum canonical address.
*/
#define TASK_SIZE_MAX ((1UL << 47) - PAGE_SIZE)
@@ -953,6 +960,24 @@ extern void start_thread(struct pt_regs *regs, unsigned long new_ip,
extern int get_tsc_mode(unsigned long adr);
extern int set_tsc_mode(unsigned int val);
+/* Register/unregister a process' MPX related resource */
+#define MPX_ENABLE_MANAGEMENT(tsk) mpx_enable_management((tsk))
+#define MPX_DISABLE_MANAGEMENT(tsk) mpx_disable_management((tsk))
+
+#ifdef CONFIG_X86_INTEL_MPX
+extern int mpx_enable_management(struct task_struct *tsk);
+extern int mpx_disable_management(struct task_struct *tsk);
+#else
+static inline int mpx_enable_management(struct task_struct *tsk)
+{
+ return -EINVAL;
+}
+static inline int mpx_disable_management(struct task_struct *tsk)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_X86_INTEL_MPX */
+
extern u16 amd_get_nb_id(int cpu);
static inline uint32_t hypervisor_cpuid_base(const char *sig, uint32_t leaves)
diff --git a/arch/x86/include/asm/spinlock.h b/arch/x86/include/asm/spinlock.h
index 9295016..a4efe47 100644
--- a/arch/x86/include/asm/spinlock.h
+++ b/arch/x86/include/asm/spinlock.h
@@ -183,8 +183,20 @@ static __always_inline void arch_spin_lock_flags(arch_spinlock_t *lock,
static inline void arch_spin_unlock_wait(arch_spinlock_t *lock)
{
- while (arch_spin_is_locked(lock))
+ __ticket_t head = ACCESS_ONCE(lock->tickets.head);
+
+ for (;;) {
+ struct __raw_tickets tmp = ACCESS_ONCE(lock->tickets);
+ /*
+ * We need to check "unlocked" in a loop, tmp.head == head
+ * can be false positive because of overflow.
+ */
+ if (tmp.head == (tmp.tail & ~TICKET_SLOWPATH_FLAG) ||
+ tmp.head != head)
+ break;
+
cpu_relax();
+ }
}
/*
diff --git a/arch/x86/include/asm/switch_to.h b/arch/x86/include/asm/switch_to.h
index d7f3b3b..751bf4b 100644
--- a/arch/x86/include/asm/switch_to.h
+++ b/arch/x86/include/asm/switch_to.h
@@ -79,12 +79,12 @@ do { \
#else /* CONFIG_X86_32 */
/* frame pointer must be last for get_wchan */
-#define SAVE_CONTEXT "pushf ; pushq %%rbp ; movq %%rsi,%%rbp\n\t"
-#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp ; popf\t"
+#define SAVE_CONTEXT "pushq %%rbp ; movq %%rsi,%%rbp\n\t"
+#define RESTORE_CONTEXT "movq %%rbp,%%rsi ; popq %%rbp\t"
#define __EXTRA_CLOBBER \
, "rcx", "rbx", "rdx", "r8", "r9", "r10", "r11", \
- "r12", "r13", "r14", "r15"
+ "r12", "r13", "r14", "r15", "flags"
#ifdef CONFIG_CC_STACKPROTECTOR
#define __switch_canary \
@@ -100,7 +100,11 @@ do { \
#define __switch_canary_iparam
#endif /* CC_STACKPROTECTOR */
-/* Save restore flags to clear handle leaking NT */
+/*
+ * There is no need to save or restore flags, because flags are always
+ * clean in kernel mode, with the possible exception of IOPL. Kernel IOPL
+ * has no effect.
+ */
#define switch_to(prev, next, last) \
asm volatile(SAVE_CONTEXT \
"movq %%rsp,%P[threadrsp](%[prev])\n\t" /* save RSP */ \
diff --git a/arch/x86/include/asm/uv/uv_bau.h b/arch/x86/include/asm/uv/uv_bau.h
index 2d60a78..fc808b8 100644
--- a/arch/x86/include/asm/uv/uv_bau.h
+++ b/arch/x86/include/asm/uv/uv_bau.h
@@ -33,8 +33,8 @@
* Each of the descriptors is 64 bytes in size (8*64 = 512 bytes in a set).
*/
-#define MAX_CPUS_PER_UVHUB 64
-#define MAX_CPUS_PER_SOCKET 32
+#define MAX_CPUS_PER_UVHUB 128
+#define MAX_CPUS_PER_SOCKET 64
#define ADP_SZ 64 /* hardware-provided max. */
#define UV_CPUS_PER_AS 32 /* hardware-provided max. */
#define ITEMS_PER_DESC 8
diff --git a/arch/x86/include/asm/vgtod.h b/arch/x86/include/asm/vgtod.h
index 3c3366c..e7e9682 100644
--- a/arch/x86/include/asm/vgtod.h
+++ b/arch/x86/include/asm/vgtod.h
@@ -70,4 +70,23 @@ static inline void gtod_write_end(struct vsyscall_gtod_data *s)
++s->seq;
}
+#ifdef CONFIG_X86_64
+
+#define VGETCPU_CPU_MASK 0xfff
+
+static inline unsigned int __getcpu(void)
+{
+ unsigned int p;
+
+ /*
+ * Load per CPU data from GDT. LSL is faster than RDTSCP and
+ * works on all CPUs.
+ */
+ asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
+
+ return p;
+}
+
+#endif /* CONFIG_X86_64 */
+
#endif /* _ASM_X86_VGTOD_H */
diff --git a/arch/x86/include/asm/vsyscall.h b/arch/x86/include/asm/vsyscall.h
index 2a46ca7..6ba66ee 100644
--- a/arch/x86/include/asm/vsyscall.h
+++ b/arch/x86/include/asm/vsyscall.h
@@ -4,15 +4,7 @@
#include <linux/seqlock.h>
#include <uapi/asm/vsyscall.h>
-#define VGETCPU_RDTSCP 1
-#define VGETCPU_LSL 2
-
-/* kernel space (writeable) */
-extern int vgetcpu_mode;
-extern struct timezone sys_tz;
-
-#include <asm/vvar.h>
-
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
extern void map_vsyscall(void);
/*
@@ -20,25 +12,12 @@ extern void map_vsyscall(void);
* Returns true if handled.
*/
extern bool emulate_vsyscall(struct pt_regs *regs, unsigned long address);
-
-#ifdef CONFIG_X86_64
-
-#define VGETCPU_CPU_MASK 0xfff
-
-static inline unsigned int __getcpu(void)
+#else
+static inline void map_vsyscall(void) {}
+static inline bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
{
- unsigned int p;
-
- if (VVAR(vgetcpu_mode) == VGETCPU_RDTSCP) {
- /* Load per CPU data from RDTSCP */
- native_read_tscp(&p);
- } else {
- /* Load per CPU data from GDT */
- asm("lsl %1,%0" : "=r" (p) : "r" (__PER_CPU_SEG));
- }
-
- return p;
+ return false;
}
-#endif /* CONFIG_X86_64 */
+#endif
#endif /* _ASM_X86_VSYSCALL_H */
diff --git a/arch/x86/include/asm/vvar.h b/arch/x86/include/asm/vvar.h
index 5d2b9ad..3f32dfc 100644
--- a/arch/x86/include/asm/vvar.h
+++ b/arch/x86/include/asm/vvar.h
@@ -44,8 +44,6 @@ extern char __vvar_page;
/* DECLARE_VVAR(offset, type, name) */
-DECLARE_VVAR(0, volatile unsigned long, jiffies)
-DECLARE_VVAR(16, int, vgetcpu_mode)
DECLARE_VVAR(128, struct vsyscall_gtod_data, vsyscall_gtod_data)
#undef DECLARE_VVAR
diff --git a/arch/x86/include/asm/x86_init.h b/arch/x86/include/asm/x86_init.h
index e45e4da..f58a9c7 100644
--- a/arch/x86/include/asm/x86_init.h
+++ b/arch/x86/include/asm/x86_init.h
@@ -172,7 +172,6 @@ struct x86_platform_ops {
struct pci_dev;
struct msi_msg;
-struct msi_desc;
struct x86_msi_ops {
int (*setup_msi_irqs)(struct pci_dev *dev, int nvec, int type);
@@ -183,8 +182,6 @@ struct x86_msi_ops {
void (*teardown_msi_irqs)(struct pci_dev *dev);
void (*restore_msi_irqs)(struct pci_dev *dev);
int (*setup_hpet_msi)(unsigned int irq, unsigned int id);
- u32 (*msi_mask_irq)(struct msi_desc *desc, u32 mask, u32 flag);
- u32 (*msix_mask_irq)(struct msi_desc *desc, u32 flag);
};
struct IO_APIC_route_entry;
diff --git a/arch/x86/include/uapi/asm/msr-index.h b/arch/x86/include/uapi/asm/msr-index.h
index e21331ce..c8aa65d 100644
--- a/arch/x86/include/uapi/asm/msr-index.h
+++ b/arch/x86/include/uapi/asm/msr-index.h
@@ -152,6 +152,45 @@
#define MSR_CC6_DEMOTION_POLICY_CONFIG 0x00000668
#define MSR_MC6_DEMOTION_POLICY_CONFIG 0x00000669
+/* Hardware P state interface */
+#define MSR_PPERF 0x0000064e
+#define MSR_PERF_LIMIT_REASONS 0x0000064f
+#define MSR_PM_ENABLE 0x00000770
+#define MSR_HWP_CAPABILITIES 0x00000771
+#define MSR_HWP_REQUEST_PKG 0x00000772
+#define MSR_HWP_INTERRUPT 0x00000773
+#define MSR_HWP_REQUEST 0x00000774
+#define MSR_HWP_STATUS 0x00000777
+
+/* CPUID.6.EAX */
+#define HWP_BASE_BIT (1<<7)
+#define HWP_NOTIFICATIONS_BIT (1<<8)
+#define HWP_ACTIVITY_WINDOW_BIT (1<<9)
+#define HWP_ENERGY_PERF_PREFERENCE_BIT (1<<10)
+#define HWP_PACKAGE_LEVEL_REQUEST_BIT (1<<11)
+
+/* IA32_HWP_CAPABILITIES */
+#define HWP_HIGHEST_PERF(x) (x & 0xff)
+#define HWP_GUARANTEED_PERF(x) ((x & (0xff << 8)) >>8)
+#define HWP_MOSTEFFICIENT_PERF(x) ((x & (0xff << 16)) >>16)
+#define HWP_LOWEST_PERF(x) ((x & (0xff << 24)) >>24)
+
+/* IA32_HWP_REQUEST */
+#define HWP_MIN_PERF(x) (x & 0xff)
+#define HWP_MAX_PERF(x) ((x & 0xff) << 8)
+#define HWP_DESIRED_PERF(x) ((x & 0xff) << 16)
+#define HWP_ENERGY_PERF_PREFERENCE(x) ((x & 0xff) << 24)
+#define HWP_ACTIVITY_WINDOW(x) ((x & 0xff3) << 32)
+#define HWP_PACKAGE_CONTROL(x) ((x & 0x1) << 42)
+
+/* IA32_HWP_STATUS */
+#define HWP_GUARANTEED_CHANGE(x) (x & 0x1)
+#define HWP_EXCURSION_TO_MINIMUM(x) (x & 0x4)
+
+/* IA32_HWP_INTERRUPT */
+#define HWP_CHANGE_TO_GUARANTEED_INT(x) (x & 0x1)
+#define HWP_EXCURSION_TO_MINIMUM_INT(x) (x & 0x2)
+
#define MSR_AMD64_MC0_MASK 0xc0010044
#define MSR_IA32_MCx_CTL(x) (MSR_IA32_MC0_CTL + 4*(x))
@@ -206,6 +245,7 @@
#define MSR_AMD64_IBSOP_REG_MASK ((1UL<<MSR_AMD64_IBSOP_REG_COUNT)-1)
#define MSR_AMD64_IBSCTL 0xc001103a
#define MSR_AMD64_IBSBRTARGET 0xc001103b
+#define MSR_AMD64_IBSOPDATA4 0xc001103d
#define MSR_AMD64_IBS_REG_COUNT_MAX 8 /* includes MSR_AMD64_IBSBRTARGET */
/* Fam 16h MSRs */
@@ -345,6 +385,8 @@
#define MSR_IA32_TEMPERATURE_TARGET 0x000001a2
+#define MSR_MISC_PWR_MGMT 0x000001aa
+
#define MSR_IA32_ENERGY_PERF_BIAS 0x000001b0
#define ENERGY_PERF_BIAS_PERFORMANCE 0
#define ENERGY_PERF_BIAS_NORMAL 6
diff --git a/arch/x86/kernel/Makefile b/arch/x86/kernel/Makefile
index 8f1e774..5d4502c 100644
--- a/arch/x86/kernel/Makefile
+++ b/arch/x86/kernel/Makefile
@@ -28,8 +28,7 @@ obj-$(CONFIG_X86_32) += i386_ksyms_32.o
obj-$(CONFIG_X86_64) += sys_x86_64.o x8664_ksyms_64.o
obj-$(CONFIG_X86_64) += mcount_64.o
obj-y += syscall_$(BITS).o vsyscall_gtod.o
-obj-$(CONFIG_X86_64) += vsyscall_64.o
-obj-$(CONFIG_X86_64) += vsyscall_emu_64.o
+obj-$(CONFIG_X86_VSYSCALL_EMULATION) += vsyscall_64.o vsyscall_emu_64.o
obj-$(CONFIG_X86_ESPFIX64) += espfix_64.o
obj-$(CONFIG_SYSFS) += ksysfs.o
obj-y += bootflag.o e820.o
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c
index f04dbb3..5caed1d 100644
--- a/arch/x86/kernel/amd_nb.c
+++ b/arch/x86/kernel/amd_nb.c
@@ -21,6 +21,7 @@ const struct pci_device_id amd_nb_misc_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M10H_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F3) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F3) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F3) },
{}
@@ -30,6 +31,7 @@ EXPORT_SYMBOL(amd_nb_misc_ids);
static const struct pci_device_id amd_nb_link_ids[] = {
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F4) },
+ { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_NB_F4) },
{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F4) },
{}
diff --git a/arch/x86/kernel/apic/apic_numachip.c b/arch/x86/kernel/apic/apic_numachip.c
index 4128b5f..c2fd21f 100644
--- a/arch/x86/kernel/apic/apic_numachip.c
+++ b/arch/x86/kernel/apic/apic_numachip.c
@@ -40,7 +40,7 @@ static unsigned int get_apic_id(unsigned long x)
unsigned int id;
rdmsrl(MSR_FAM10H_NODE_ID, value);
- id = ((x >> 24) & 0xffU) | ((value << 2) & 0x3f00U);
+ id = ((x >> 24) & 0xffU) | ((value << 2) & 0xff00U);
return id;
}
@@ -145,7 +145,7 @@ static void numachip_send_IPI_all(int vector)
static void numachip_send_IPI_self(int vector)
{
- __default_send_IPI_shortcut(APIC_DEST_SELF, vector, APIC_DEST_PHYSICAL);
+ apic_write(APIC_SELF_IPI, vector);
}
static int __init numachip_probe(void)
@@ -153,20 +153,8 @@ static int __init numachip_probe(void)
return apic == &apic_numachip;
}
-static void __init map_csrs(void)
-{
- printk(KERN_INFO "NumaChip: Mapping local CSR space (%016llx - %016llx)\n",
- NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_BASE + NUMACHIP_LCSR_SIZE - 1);
- init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE);
-
- printk(KERN_INFO "NumaChip: Mapping global CSR space (%016llx - %016llx)\n",
- NUMACHIP_GCSR_BASE, NUMACHIP_GCSR_BASE + NUMACHIP_GCSR_SIZE - 1);
- init_extra_mapping_uc(NUMACHIP_GCSR_BASE, NUMACHIP_GCSR_SIZE);
-}
-
static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
{
-
if (c->phys_proc_id != node) {
c->phys_proc_id = node;
per_cpu(cpu_llc_id, smp_processor_id()) = node;
@@ -175,19 +163,15 @@ static void fixup_cpu_id(struct cpuinfo_x86 *c, int node)
static int __init numachip_system_init(void)
{
- unsigned int val;
-
if (!numachip_system)
return 0;
+ init_extra_mapping_uc(NUMACHIP_LCSR_BASE, NUMACHIP_LCSR_SIZE);
+ init_extra_mapping_uc(NUMACHIP_GCSR_BASE, NUMACHIP_GCSR_SIZE);
+
x86_cpuinit.fixup_cpu_id = fixup_cpu_id;
x86_init.pci.arch_init = pci_numachip_init;
- map_csrs();
-
- val = read_lcsr(CSR_G0_NODE_IDS);
- printk(KERN_INFO "NumaChip: Local NodeID = %08x\n", val);
-
return 0;
}
early_initcall(numachip_system_init);
diff --git a/arch/x86/kernel/apic/hw_nmi.c b/arch/x86/kernel/apic/hw_nmi.c
index 6a1e71b..6873ab9 100644
--- a/arch/x86/kernel/apic/hw_nmi.c
+++ b/arch/x86/kernel/apic/hw_nmi.c
@@ -18,6 +18,7 @@
#include <linux/nmi.h>
#include <linux/module.h>
#include <linux/delay.h>
+#include <linux/seq_buf.h>
#ifdef CONFIG_HARDLOCKUP_DETECTOR
u64 hw_nmi_get_sample_period(int watchdog_thresh)
@@ -29,14 +30,35 @@ u64 hw_nmi_get_sample_period(int watchdog_thresh)
#ifdef arch_trigger_all_cpu_backtrace
/* For reliability, we're prepared to waste bits here. */
static DECLARE_BITMAP(backtrace_mask, NR_CPUS) __read_mostly;
+static cpumask_t printtrace_mask;
+
+#define NMI_BUF_SIZE 4096
+
+struct nmi_seq_buf {
+ unsigned char buffer[NMI_BUF_SIZE];
+ struct seq_buf seq;
+};
+
+/* Safe printing in NMI context */
+static DEFINE_PER_CPU(struct nmi_seq_buf, nmi_print_seq);
/* "in progress" flag of arch_trigger_all_cpu_backtrace */
static unsigned long backtrace_flag;
+static void print_seq_line(struct nmi_seq_buf *s, int start, int end)
+{
+ const char *buf = s->buffer + start;
+
+ printk("%.*s", (end - start) + 1, buf);
+}
+
void arch_trigger_all_cpu_backtrace(bool include_self)
{
+ struct nmi_seq_buf *s;
+ int len;
+ int cpu;
int i;
- int cpu = get_cpu();
+ int this_cpu = get_cpu();
if (test_and_set_bit(0, &backtrace_flag)) {
/*
@@ -49,7 +71,17 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
cpumask_copy(to_cpumask(backtrace_mask), cpu_online_mask);
if (!include_self)
- cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
+ cpumask_clear_cpu(this_cpu, to_cpumask(backtrace_mask));
+
+ cpumask_copy(&printtrace_mask, to_cpumask(backtrace_mask));
+ /*
+ * Set up per_cpu seq_buf buffers that the NMIs running on the other
+ * CPUs will write to.
+ */
+ for_each_cpu(cpu, to_cpumask(backtrace_mask)) {
+ s = &per_cpu(nmi_print_seq, cpu);
+ seq_buf_init(&s->seq, s->buffer, NMI_BUF_SIZE);
+ }
if (!cpumask_empty(to_cpumask(backtrace_mask))) {
pr_info("sending NMI to %s CPUs:\n",
@@ -65,11 +97,58 @@ void arch_trigger_all_cpu_backtrace(bool include_self)
touch_softlockup_watchdog();
}
+ /*
+ * Now that all the NMIs have triggered, we can dump out their
+ * back traces safely to the console.
+ */
+ for_each_cpu(cpu, &printtrace_mask) {
+ int last_i = 0;
+
+ s = &per_cpu(nmi_print_seq, cpu);
+ len = seq_buf_used(&s->seq);
+ if (!len)
+ continue;
+
+ /* Print line by line. */
+ for (i = 0; i < len; i++) {
+ if (s->buffer[i] == '\n') {
+ print_seq_line(s, last_i, i);
+ last_i = i + 1;
+ }
+ }
+ /* Check if there was a partial line. */
+ if (last_i < len) {
+ print_seq_line(s, last_i, len - 1);
+ pr_cont("\n");
+ }
+ }
+
clear_bit(0, &backtrace_flag);
smp_mb__after_atomic();
put_cpu();
}
+/*
+ * It is not safe to call printk() directly from NMI handlers.
+ * It may be fine if the NMI detected a lock up and we have no choice
+ * but to do so, but doing a NMI on all other CPUs to get a back trace
+ * can be done with a sysrq-l. We don't want that to lock up, which
+ * can happen if the NMI interrupts a printk in progress.
+ *
+ * Instead, we redirect the vprintk() to this nmi_vprintk() that writes
+ * the content into a per cpu seq_buf buffer. Then when the NMIs are
+ * all done, we can safely dump the contents of the seq_buf to a printk()
+ * from a non NMI context.
+ */
+static int nmi_vprintk(const char *fmt, va_list args)
+{
+ struct nmi_seq_buf *s = this_cpu_ptr(&nmi_print_seq);
+ unsigned int len = seq_buf_used(&s->seq);
+
+ seq_buf_vprintf(&s->seq, fmt, args);
+ return seq_buf_used(&s->seq) - len;
+}
+
static int
arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
{
@@ -78,12 +157,14 @@ arch_trigger_all_cpu_backtrace_handler(unsigned int cmd, struct pt_regs *regs)
cpu = smp_processor_id();
if (cpumask_test_cpu(cpu, to_cpumask(backtrace_mask))) {
- static arch_spinlock_t lock = __ARCH_SPIN_LOCK_UNLOCKED;
+ printk_func_t printk_func_save = this_cpu_read(printk_func);
- arch_spin_lock(&lock);
+ /* Replace printk to write into the NMI seq */
+ this_cpu_write(printk_func, nmi_vprintk);
printk(KERN_WARNING "NMI backtrace for cpu %d\n", cpu);
show_regs(regs);
- arch_spin_unlock(&lock);
+ this_cpu_write(printk_func, printk_func_save);
+
cpumask_clear_cpu(cpu, to_cpumask(backtrace_mask));
return NMI_HANDLED;
}
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 1183d54..7ffe0a2 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -3158,7 +3158,7 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
msg.address_lo &= ~MSI_ADDR_DEST_ID_MASK;
msg.address_lo |= MSI_ADDR_DEST_ID(dest);
- __write_msi_msg(data->msi_desc, &msg);
+ __pci_write_msi_msg(data->msi_desc, &msg);
return IRQ_SET_MASK_OK_NOCOPY;
}
@@ -3169,8 +3169,8 @@ msi_set_affinity(struct irq_data *data, const struct cpumask *mask, bool force)
*/
static struct irq_chip msi_chip = {
.name = "PCI-MSI",
- .irq_unmask = unmask_msi_irq,
- .irq_mask = mask_msi_irq,
+ .irq_unmask = pci_msi_unmask_irq,
+ .irq_mask = pci_msi_mask_irq,
.irq_ack = ack_apic_edge,
.irq_set_affinity = msi_set_affinity,
.irq_retrigger = ioapic_retrigger_irq,
@@ -3196,7 +3196,7 @@ int setup_msi_irq(struct pci_dev *dev, struct msi_desc *msidesc,
* MSI message denotes a contiguous group of IRQs, written for 0th IRQ.
*/
if (!irq_offset)
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
setup_remapped_irq(irq, irq_cfg(irq), chip);
diff --git a/arch/x86/kernel/apm_32.c b/arch/x86/kernel/apm_32.c
index 5848744..927ec92 100644
--- a/arch/x86/kernel/apm_32.c
+++ b/arch/x86/kernel/apm_32.c
@@ -378,7 +378,6 @@ static struct cpuidle_driver apm_idle_driver = {
{ /* entry 1 is for APM idle */
.name = "APM",
.desc = "APM idle",
- .flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 250, /* WAG */
.target_residency = 500, /* WAG */
.enter = &apm_cpu_idle
diff --git a/arch/x86/kernel/asm-offsets_64.c b/arch/x86/kernel/asm-offsets_64.c
index e7c798b..4f9359f 100644
--- a/arch/x86/kernel/asm-offsets_64.c
+++ b/arch/x86/kernel/asm-offsets_64.c
@@ -48,7 +48,6 @@ int main(void)
#define ENTRY(entry) OFFSET(pt_regs_ ## entry, pt_regs, entry)
ENTRY(bx);
- ENTRY(bx);
ENTRY(cx);
ENTRY(dx);
ENTRY(sp);
diff --git a/arch/x86/kernel/cpu/amd.c b/arch/x86/kernel/cpu/amd.c
index 813d29d..15c5df9 100644
--- a/arch/x86/kernel/cpu/amd.c
+++ b/arch/x86/kernel/cpu/amd.c
@@ -566,6 +566,17 @@ static void init_amd_k8(struct cpuinfo_x86 *c)
if (!c->x86_model_id[0])
strcpy(c->x86_model_id, "Hammer");
+
+#ifdef CONFIG_SMP
+ /*
+ * Disable TLB flush filter by setting HWCR.FFDIS on K8
+ * bit 6 of msr C001_0015
+ *
+ * Errata 63 for SH-B3 steppings
+ * Errata 122 for all steppings (F+ have it disabled by default)
+ */
+ msr_set_bit(MSR_K7_HWCR, 6);
+#endif
}
static void init_amd_gh(struct cpuinfo_x86 *c)
@@ -636,18 +647,6 @@ static void init_amd(struct cpuinfo_x86 *c)
{
u32 dummy;
-#ifdef CONFIG_SMP
- /*
- * Disable TLB flush filter by setting HWCR.FFDIS on K8
- * bit 6 of msr C001_0015
- *
- * Errata 63 for SH-B3 steppings
- * Errata 122 for all steppings (F+ have it disabled by default)
- */
- if (c->x86 == 0xf)
- msr_set_bit(MSR_K7_HWCR, 6);
-#endif
-
early_init_amd(c);
/*
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index cfa9b5b..c604965 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -958,14 +958,6 @@ static void identify_cpu(struct cpuinfo_x86 *c)
}
#ifdef CONFIG_X86_64
-static void vgetcpu_set_mode(void)
-{
- if (cpu_has(&boot_cpu_data, X86_FEATURE_RDTSCP))
- vgetcpu_mode = VGETCPU_RDTSCP;
- else
- vgetcpu_mode = VGETCPU_LSL;
-}
-
#ifdef CONFIG_IA32_EMULATION
/* May not be __init: called during resume */
static void syscall32_cpu_init(void)
@@ -1008,8 +1000,6 @@ void __init identify_boot_cpu(void)
#ifdef CONFIG_X86_32
sysenter_setup();
enable_sep_cpu();
-#else
- vgetcpu_set_mode();
#endif
cpu_detect_tlb(&boot_cpu_data);
}
diff --git a/arch/x86/kernel/cpu/mcheck/mce-internal.h b/arch/x86/kernel/cpu/mcheck/mce-internal.h
index 09edd0b..10b4690 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-internal.h
+++ b/arch/x86/kernel/cpu/mcheck/mce-internal.h
@@ -3,6 +3,8 @@
enum severity_level {
MCE_NO_SEVERITY,
+ MCE_DEFERRED_SEVERITY,
+ MCE_UCNA_SEVERITY = MCE_DEFERRED_SEVERITY,
MCE_KEEP_SEVERITY,
MCE_SOME_SEVERITY,
MCE_AO_SEVERITY,
@@ -21,7 +23,7 @@ struct mce_bank {
char attrname[ATTR_LEN]; /* attribute name */
};
-int mce_severity(struct mce *a, int tolerant, char **msg);
+int mce_severity(struct mce *a, int tolerant, char **msg, bool is_excp);
struct dentry *mce_get_debugfs_dir(void);
extern struct mce_bank *mce_banks;
diff --git a/arch/x86/kernel/cpu/mcheck/mce-severity.c b/arch/x86/kernel/cpu/mcheck/mce-severity.c
index c370e1c..8bb4330 100644
--- a/arch/x86/kernel/cpu/mcheck/mce-severity.c
+++ b/arch/x86/kernel/cpu/mcheck/mce-severity.c
@@ -31,6 +31,7 @@
enum context { IN_KERNEL = 1, IN_USER = 2 };
enum ser { SER_REQUIRED = 1, NO_SER = 2 };
+enum exception { EXCP_CONTEXT = 1, NO_EXCP = 2 };
static struct severity {
u64 mask;
@@ -40,6 +41,7 @@ static struct severity {
unsigned char mcgres;
unsigned char ser;
unsigned char context;
+ unsigned char excp;
unsigned char covered;
char *msg;
} severities[] = {
@@ -48,6 +50,8 @@ static struct severity {
#define USER .context = IN_USER
#define SER .ser = SER_REQUIRED
#define NOSER .ser = NO_SER
+#define EXCP .excp = EXCP_CONTEXT
+#define NOEXCP .excp = NO_EXCP
#define BITCLR(x) .mask = x, .result = 0
#define BITSET(x) .mask = x, .result = x
#define MCGMASK(x, y) .mcgmask = x, .mcgres = y
@@ -62,7 +66,7 @@ static struct severity {
),
MCESEV(
NO, "Not enabled",
- BITCLR(MCI_STATUS_EN)
+ EXCP, BITCLR(MCI_STATUS_EN)
),
MCESEV(
PANIC, "Processor context corrupt",
@@ -71,16 +75,20 @@ static struct severity {
/* When MCIP is not set something is very confused */
MCESEV(
PANIC, "MCIP not set in MCA handler",
- MCGMASK(MCG_STATUS_MCIP, 0)
+ EXCP, MCGMASK(MCG_STATUS_MCIP, 0)
),
/* Neither return not error IP -- no chance to recover -> PANIC */
MCESEV(
PANIC, "Neither restart nor error IP",
- MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0)
+ EXCP, MCGMASK(MCG_STATUS_RIPV|MCG_STATUS_EIPV, 0)
),
MCESEV(
PANIC, "In kernel and no restart IP",
- KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
+ EXCP, KERNEL, MCGMASK(MCG_STATUS_RIPV, 0)
+ ),
+ MCESEV(
+ DEFERRED, "Deferred error",
+ NOSER, MASK(MCI_STATUS_UC|MCI_STATUS_DEFERRED|MCI_STATUS_POISON, MCI_STATUS_DEFERRED)
),
MCESEV(
KEEP, "Corrected error",
@@ -89,7 +97,7 @@ static struct severity {
/* ignore OVER for UCNA */
MCESEV(
- KEEP, "Uncorrected no action required",
+ UCNA, "Uncorrected no action required",
SER, MASK(MCI_UC_SAR, MCI_STATUS_UC)
),
MCESEV(
@@ -178,8 +186,9 @@ static int error_context(struct mce *m)
return ((m->cs & 3) == 3) ? IN_USER : IN_KERNEL;
}
-int mce_severity(struct mce *m, int tolerant, char **msg)
+int mce_severity(struct mce *m, int tolerant, char **msg, bool is_excp)
{
+ enum exception excp = (is_excp ? EXCP_CONTEXT : NO_EXCP);
enum context ctx = error_context(m);
struct severity *s;
@@ -194,6 +203,8 @@ int mce_severity(struct mce *m, int tolerant, char **msg)
continue;
if (s->context && ctx != s->context)
continue;
+ if (s->excp && excp != s->excp)
+ continue;
if (msg)
*msg = s->msg;
s->covered = 1;
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 61a9668ce..d2c6116 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -292,10 +292,10 @@ static void print_mce(struct mce *m)
#define PANIC_TIMEOUT 5 /* 5 seconds */
-static atomic_t mce_paniced;
+static atomic_t mce_panicked;
static int fake_panic;
-static atomic_t mce_fake_paniced;
+static atomic_t mce_fake_panicked;
/* Panic in progress. Enable interrupts and wait for final IPI */
static void wait_for_panic(void)
@@ -319,7 +319,7 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
/*
* Make sure only one CPU runs in machine check panic
*/
- if (atomic_inc_return(&mce_paniced) > 1)
+ if (atomic_inc_return(&mce_panicked) > 1)
wait_for_panic();
barrier();
@@ -327,7 +327,7 @@ static void mce_panic(char *msg, struct mce *final, char *exp)
console_verbose();
} else {
/* Don't log too much for fake panic */
- if (atomic_inc_return(&mce_fake_paniced) > 1)
+ if (atomic_inc_return(&mce_fake_panicked) > 1)
return;
}
/* First print corrected ones that are still unlogged */
@@ -575,6 +575,37 @@ static void mce_read_aux(struct mce *m, int i)
}
}
+static bool memory_error(struct mce *m)
+{
+ struct cpuinfo_x86 *c = &boot_cpu_data;
+
+ if (c->x86_vendor == X86_VENDOR_AMD) {
+ /*
+ * coming soon
+ */
+ return false;
+ } else if (c->x86_vendor == X86_VENDOR_INTEL) {
+ /*
+ * Intel SDM Volume 3B - 15.9.2 Compound Error Codes
+ *
+ * Bit 7 of the MCACOD field of IA32_MCi_STATUS is used for
+ * indicating a memory error. Bit 8 is used for indicating a
+ * cache hierarchy error. The combination of bit 2 and bit 3
+ * is used for indicating a `generic' cache hierarchy error
+ * But we can't just blindly check the above bits, because if
+ * bit 11 is set, then it is a bus/interconnect error - and
+ * either way the above bits just gives more detail on what
+ * bus/interconnect error happened. Note that bit 12 can be
+ * ignored, as it's the "filter" bit.
+ */
+ return (m->status & 0xef80) == BIT(7) ||
+ (m->status & 0xef00) == BIT(8) ||
+ (m->status & 0xeffc) == 0xc;
+ }
+
+ return false;
+}
+
DEFINE_PER_CPU(unsigned, mce_poll_count);
/*
@@ -595,6 +626,7 @@ DEFINE_PER_CPU(unsigned, mce_poll_count);
void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
{
struct mce m;
+ int severity;
int i;
this_cpu_inc(mce_poll_count);
@@ -630,6 +662,20 @@ void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
if (!(flags & MCP_TIMESTAMP))
m.tsc = 0;
+
+ severity = mce_severity(&m, mca_cfg.tolerant, NULL, false);
+
+ /*
+ * In the cases where we don't have a valid address after all,
+ * do not add it into the ring buffer.
+ */
+ if (severity == MCE_DEFERRED_SEVERITY && memory_error(&m)) {
+ if (m.status & MCI_STATUS_ADDRV) {
+ mce_ring_add(m.addr >> PAGE_SHIFT);
+ mce_schedule_work();
+ }
+ }
+
/*
* Don't get the IP here because it's unlikely to
* have anything to do with the actual error location.
@@ -668,7 +714,8 @@ static int mce_no_way_out(struct mce *m, char **msg, unsigned long *validp,
if (quirk_no_way_out)
quirk_no_way_out(i, m, regs);
}
- if (mce_severity(m, mca_cfg.tolerant, msg) >= MCE_PANIC_SEVERITY)
+ if (mce_severity(m, mca_cfg.tolerant, msg, true) >=
+ MCE_PANIC_SEVERITY)
ret = 1;
}
return ret;
@@ -697,7 +744,7 @@ static int mce_timed_out(u64 *t)
* might have been modified by someone else.
*/
rmb();
- if (atomic_read(&mce_paniced))
+ if (atomic_read(&mce_panicked))
wait_for_panic();
if (!mca_cfg.monarch_timeout)
goto out;
@@ -754,7 +801,7 @@ static void mce_reign(void)
for_each_possible_cpu(cpu) {
int severity = mce_severity(&per_cpu(mces_seen, cpu),
mca_cfg.tolerant,
- &nmsg);
+ &nmsg, true);
if (severity > global_worst) {
msg = nmsg;
global_worst = severity;
@@ -1095,13 +1142,14 @@ void do_machine_check(struct pt_regs *regs, long error_code)
*/
add_taint(TAINT_MACHINE_CHECK, LOCKDEP_NOW_UNRELIABLE);
- severity = mce_severity(&m, cfg->tolerant, NULL);
+ severity = mce_severity(&m, cfg->tolerant, NULL, true);
/*
- * When machine check was for corrected handler don't touch,
- * unless we're panicing.
+ * When machine check was for corrected/deferred handler don't
+ * touch, unless we're panicing.
*/
- if (severity == MCE_KEEP_SEVERITY && !no_way_out)
+ if ((severity == MCE_KEEP_SEVERITY ||
+ severity == MCE_UCNA_SEVERITY) && !no_way_out)
continue;
__set_bit(i, toclear);
if (severity == MCE_NO_SEVERITY) {
@@ -2520,7 +2568,7 @@ struct dentry *mce_get_debugfs_dir(void)
static void mce_reset(void)
{
cpu_missing = 0;
- atomic_set(&mce_fake_paniced, 0);
+ atomic_set(&mce_fake_panicked, 0);
atomic_set(&mce_executing, 0);
atomic_set(&mce_callin, 0);
atomic_set(&global_nwo, 0);
diff --git a/arch/x86/kernel/cpu/mcheck/mce_amd.c b/arch/x86/kernel/cpu/mcheck/mce_amd.c
index 5d4999f..f1c3769 100644
--- a/arch/x86/kernel/cpu/mcheck/mce_amd.c
+++ b/arch/x86/kernel/cpu/mcheck/mce_amd.c
@@ -212,12 +212,12 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
unsigned int cpu = smp_processor_id();
u32 low = 0, high = 0, address = 0;
unsigned int bank, block;
- int offset = -1;
+ int offset = -1, new;
for (bank = 0; bank < mca_cfg.banks; ++bank) {
for (block = 0; block < NR_BLOCKS; ++block) {
if (block == 0)
- address = MSR_IA32_MC0_MISC + bank * 4;
+ address = MSR_IA32_MCx_MISC(bank);
else if (block == 1) {
address = (low & MASK_BLKPTR_LO) >> 21;
if (!address)
@@ -247,13 +247,18 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
b.address = address;
b.interrupt_capable = lvt_interrupt_supported(bank, high);
- if (b.interrupt_capable) {
- int new = (high & MASK_LVTOFF_HI) >> 20;
- offset = setup_APIC_mce(offset, new);
- }
+ if (!b.interrupt_capable)
+ goto init;
+
+ new = (high & MASK_LVTOFF_HI) >> 20;
+ offset = setup_APIC_mce(offset, new);
+
+ if ((offset == new) &&
+ (mce_threshold_vector != amd_threshold_interrupt))
+ mce_threshold_vector = amd_threshold_interrupt;
+init:
mce_threshold_block_init(&b, offset);
- mce_threshold_vector = amd_threshold_interrupt;
}
}
}
@@ -270,18 +275,17 @@ void mce_amd_feature_init(struct cpuinfo_x86 *c)
static void amd_threshold_interrupt(void)
{
u32 low = 0, high = 0, address = 0;
+ int cpu = smp_processor_id();
unsigned int bank, block;
struct mce m;
- mce_setup(&m);
-
/* assume first bank caused it */
for (bank = 0; bank < mca_cfg.banks; ++bank) {
- if (!(per_cpu(bank_map, m.cpu) & (1 << bank)))
+ if (!(per_cpu(bank_map, cpu) & (1 << bank)))
continue;
for (block = 0; block < NR_BLOCKS; ++block) {
if (block == 0) {
- address = MSR_IA32_MC0_MISC + bank * 4;
+ address = MSR_IA32_MCx_MISC(bank);
} else if (block == 1) {
address = (low & MASK_BLKPTR_LO) >> 21;
if (!address)
@@ -309,21 +313,20 @@ static void amd_threshold_interrupt(void)
* Log the machine check that caused the threshold
* event.
*/
- machine_check_poll(MCP_TIMESTAMP,
- this_cpu_ptr(&mce_poll_banks));
-
- if (high & MASK_OVERFLOW_HI) {
- rdmsrl(address, m.misc);
- rdmsrl(MSR_IA32_MC0_STATUS + bank * 4,
- m.status);
- m.bank = K8_MCE_THRESHOLD_BASE
- + bank * NR_BLOCKS
- + block;
- mce_log(&m);
- return;
- }
+ if (high & MASK_OVERFLOW_HI)
+ goto log;
}
}
+ return;
+
+log:
+ mce_setup(&m);
+ rdmsrl(MSR_IA32_MCx_STATUS(bank), m.status);
+ m.misc = ((u64)high << 32) | low;
+ m.bank = bank;
+ mce_log(&m);
+
+ wrmsrl(MSR_IA32_MCx_STATUS(bank), 0);
}
/*
@@ -617,8 +620,7 @@ static int threshold_create_bank(unsigned int cpu, unsigned int bank)
}
}
- err = allocate_threshold_blocks(cpu, bank, 0,
- MSR_IA32_MC0_MISC + bank * 4);
+ err = allocate_threshold_blocks(cpu, bank, 0, MSR_IA32_MCx_MISC(bank));
if (!err)
goto out;
diff --git a/arch/x86/kernel/cpu/microcode/amd.c b/arch/x86/kernel/cpu/microcode/amd.c
index 8fffd84..bfbbe61 100644
--- a/arch/x86/kernel/cpu/microcode/amd.c
+++ b/arch/x86/kernel/cpu/microcode/amd.c
@@ -376,7 +376,7 @@ static enum ucode_state __load_microcode_amd(u8 family, const u8 *data,
return UCODE_OK;
}
-enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
+enum ucode_state load_microcode_amd(int cpu, u8 family, const u8 *data, size_t size)
{
enum ucode_state ret;
@@ -390,8 +390,8 @@ enum ucode_state load_microcode_amd(u8 family, const u8 *data, size_t size)
#if defined(CONFIG_MICROCODE_AMD_EARLY) && defined(CONFIG_X86_32)
/* save BSP's matching patch for early load */
- if (cpu_data(smp_processor_id()).cpu_index == boot_cpu_data.cpu_index) {
- struct ucode_patch *p = find_patch(smp_processor_id());
+ if (cpu_data(cpu).cpu_index == boot_cpu_data.cpu_index) {
+ struct ucode_patch *p = find_patch(cpu);
if (p) {
memset(amd_ucode_patch, 0, PATCH_MAX_SIZE);
memcpy(amd_ucode_patch, p->data, min_t(u32, ksize(p->data),
@@ -444,7 +444,7 @@ static enum ucode_state request_microcode_amd(int cpu, struct device *device,
goto fw_release;
}
- ret = load_microcode_amd(c->x86, fw->data, fw->size);
+ ret = load_microcode_amd(cpu, c->x86, fw->data, fw->size);
fw_release:
release_firmware(fw);
diff --git a/arch/x86/kernel/cpu/microcode/amd_early.c b/arch/x86/kernel/cpu/microcode/amd_early.c
index 0667447..737737e 100644
--- a/arch/x86/kernel/cpu/microcode/amd_early.c
+++ b/arch/x86/kernel/cpu/microcode/amd_early.c
@@ -389,7 +389,7 @@ int __init save_microcode_in_initrd_amd(void)
eax = cpuid_eax(0x00000001);
eax = ((eax >> 8) & 0xf) + ((eax >> 20) & 0xff);
- ret = load_microcode_amd(eax, container, container_size);
+ ret = load_microcode_amd(smp_processor_id(), eax, container, container_size);
if (ret != UCODE_OK)
retval = -EINVAL;
@@ -402,3 +402,21 @@ int __init save_microcode_in_initrd_amd(void)
return retval;
}
+
+void reload_ucode_amd(void)
+{
+ struct microcode_amd *mc;
+ u32 rev, eax;
+
+ rdmsr(MSR_AMD64_PATCH_LEVEL, rev, eax);
+
+ mc = (struct microcode_amd *)amd_ucode_patch;
+
+ if (mc && rev < mc->hdr.patch_id) {
+ if (!__apply_microcode_amd(mc)) {
+ ucode_new_rev = mc->hdr.patch_id;
+ pr_info("microcode: reload patch_level=0x%08x\n",
+ ucode_new_rev);
+ }
+ }
+}
diff --git a/arch/x86/kernel/cpu/microcode/core.c b/arch/x86/kernel/cpu/microcode/core.c
index 2ce9051..15c2909 100644
--- a/arch/x86/kernel/cpu/microcode/core.c
+++ b/arch/x86/kernel/cpu/microcode/core.c
@@ -466,13 +466,7 @@ static void mc_bp_resume(void)
if (uci->valid && uci->mc)
microcode_ops->apply_microcode(cpu);
else if (!uci->mc)
- /*
- * We might resume and not have applied late microcode but still
- * have a newer patch stashed from the early loader. We don't
- * have it in uci->mc so we have to load it the same way we're
- * applying patches early on the APs.
- */
- load_ucode_ap();
+ reload_early_microcode();
}
static struct syscore_ops mc_syscore_ops = {
@@ -557,7 +551,7 @@ static int __init microcode_init(void)
struct cpuinfo_x86 *c = &cpu_data(0);
int error;
- if (dis_ucode_ldr)
+ if (paravirt_enabled() || dis_ucode_ldr)
return 0;
if (c->x86_vendor == X86_VENDOR_INTEL)
diff --git a/arch/x86/kernel/cpu/microcode/core_early.c b/arch/x86/kernel/cpu/microcode/core_early.c
index 2c017f2..d45df4bd 100644
--- a/arch/x86/kernel/cpu/microcode/core_early.c
+++ b/arch/x86/kernel/cpu/microcode/core_early.c
@@ -176,3 +176,24 @@ int __init save_microcode_in_initrd(void)
return 0;
}
+
+void reload_early_microcode(void)
+{
+ int vendor, x86;
+
+ vendor = x86_vendor();
+ x86 = x86_family();
+
+ switch (vendor) {
+ case X86_VENDOR_INTEL:
+ if (x86 >= 6)
+ reload_ucode_intel();
+ break;
+ case X86_VENDOR_AMD:
+ if (x86 >= 0x10)
+ reload_ucode_amd();
+ break;
+ default:
+ break;
+ }
+}
diff --git a/arch/x86/kernel/cpu/microcode/intel_early.c b/arch/x86/kernel/cpu/microcode/intel_early.c
index b88343f..ec9df6f 100644
--- a/arch/x86/kernel/cpu/microcode/intel_early.c
+++ b/arch/x86/kernel/cpu/microcode/intel_early.c
@@ -650,8 +650,7 @@ static inline void print_ucode(struct ucode_cpu_info *uci)
}
#endif
-static int apply_microcode_early(struct mc_saved_data *mc_saved_data,
- struct ucode_cpu_info *uci)
+static int apply_microcode_early(struct ucode_cpu_info *uci, bool early)
{
struct microcode_intel *mc_intel;
unsigned int val[2];
@@ -680,7 +679,10 @@ static int apply_microcode_early(struct mc_saved_data *mc_saved_data,
#endif
uci->cpu_sig.rev = val[1];
- print_ucode(uci);
+ if (early)
+ print_ucode(uci);
+ else
+ print_ucode_info(uci, mc_intel->hdr.date);
return 0;
}
@@ -715,12 +717,17 @@ _load_ucode_intel_bsp(struct mc_saved_data *mc_saved_data,
unsigned long initrd_end_early,
struct ucode_cpu_info *uci)
{
+ enum ucode_state ret;
+
collect_cpu_info_early(uci);
scan_microcode(initrd_start_early, initrd_end_early, mc_saved_data,
mc_saved_in_initrd, uci);
- load_microcode(mc_saved_data, mc_saved_in_initrd,
- initrd_start_early, uci);
- apply_microcode_early(mc_saved_data, uci);
+
+ ret = load_microcode(mc_saved_data, mc_saved_in_initrd,
+ initrd_start_early, uci);
+
+ if (ret == UCODE_OK)
+ apply_microcode_early(uci, true);
}
void __init
@@ -749,7 +756,8 @@ load_ucode_intel_bsp(void)
initrd_end_early = initrd_start_early + ramdisk_size;
_load_ucode_intel_bsp(&mc_saved_data, mc_saved_in_initrd,
- initrd_start_early, initrd_end_early, &uci);
+ initrd_start_early, initrd_end_early,
+ &uci);
#endif
}
@@ -783,5 +791,23 @@ void load_ucode_intel_ap(void)
collect_cpu_info_early(&uci);
load_microcode(mc_saved_data_p, mc_saved_in_initrd_p,
initrd_start_addr, &uci);
- apply_microcode_early(mc_saved_data_p, &uci);
+ apply_microcode_early(&uci, true);
+}
+
+void reload_ucode_intel(void)
+{
+ struct ucode_cpu_info uci;
+ enum ucode_state ret;
+
+ if (!mc_saved_data.mc_saved_count)
+ return;
+
+ collect_cpu_info_early(&uci);
+
+ ret = generic_load_microcode_early(mc_saved_data.mc_saved,
+ mc_saved_data.mc_saved_count, &uci);
+ if (ret != UCODE_OK)
+ return;
+
+ apply_microcode_early(&uci, false);
}
diff --git a/arch/x86/kernel/cpu/perf_event.h b/arch/x86/kernel/cpu/perf_event.h
index fc5eb39..4e6cdb0 100644
--- a/arch/x86/kernel/cpu/perf_event.h
+++ b/arch/x86/kernel/cpu/perf_event.h
@@ -253,6 +253,10 @@ struct cpu_hw_events {
#define INTEL_UEVENT_CONSTRAINT(c, n) \
EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK)
+/* Like UEVENT_CONSTRAINT, but match flags too */
+#define INTEL_FLAGS_UEVENT_CONSTRAINT(c, n) \
+ EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS)
+
#define INTEL_PLD_CONSTRAINT(c, n) \
__EVENT_CONSTRAINT(c, n, INTEL_ARCH_EVENT_MASK|X86_ALL_EVENT_FLAGS, \
HWEIGHT(n), 0, PERF_X86_EVENT_PEBS_LDLAT)
diff --git a/arch/x86/kernel/cpu/perf_event_amd_ibs.c b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
index cbb1be3e..a61f5c6 100644
--- a/arch/x86/kernel/cpu/perf_event_amd_ibs.c
+++ b/arch/x86/kernel/cpu/perf_event_amd_ibs.c
@@ -565,6 +565,21 @@ static int perf_ibs_handle_irq(struct perf_ibs *perf_ibs, struct pt_regs *iregs)
perf_ibs->offset_max,
offset + 1);
} while (offset < offset_max);
+ if (event->attr.sample_type & PERF_SAMPLE_RAW) {
+ /*
+ * Read IbsBrTarget and IbsOpData4 separately
+ * depending on their availability.
+ * Can't add to offset_max as they are staggered
+ */
+ if (ibs_caps & IBS_CAPS_BRNTRGT) {
+ rdmsrl(MSR_AMD64_IBSBRTARGET, *buf++);
+ size++;
+ }
+ if (ibs_caps & IBS_CAPS_OPDATA4) {
+ rdmsrl(MSR_AMD64_IBSOPDATA4, *buf++);
+ size++;
+ }
+ }
ibs_data.size = sizeof(u64) * size;
regs = *iregs;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_ds.c b/arch/x86/kernel/cpu/perf_event_intel_ds.c
index 46211bc..3c895d4 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_ds.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_ds.c
@@ -552,18 +552,18 @@ int intel_pmu_drain_bts_buffer(void)
* PEBS
*/
struct event_constraint intel_core2_pebs_event_constraints[] = {
- INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
- INTEL_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */
- INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */
- INTEL_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
- INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0xfec1, 0x1), /* X87_OPS_RETIRED.ANY */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* BR_INST_RETIRED.MISPRED */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x1fc7, 0x1), /* SIMD_INST_RETURED.ANY */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
EVENT_CONSTRAINT_END
};
struct event_constraint intel_atom_pebs_event_constraints[] = {
- INTEL_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
- INTEL_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
- INTEL_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c0, 0x1), /* INST_RETIRED.ANY */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x00c5, 0x1), /* MISPREDICTED_BRANCH_RETIRED */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0x1), /* MEM_LOAD_RETIRED.* */
EVENT_CONSTRAINT_END
};
@@ -577,36 +577,36 @@ struct event_constraint intel_slm_pebs_event_constraints[] = {
struct event_constraint intel_nehalem_pebs_event_constraints[] = {
INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
- INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
- INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf), /* INST_RETIRED.ANY */
INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
- INTEL_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
- INTEL_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
- INTEL_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
- INTEL_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x02c5, 0xf), /* BR_MISP_RETIRED.NEAR_CALL */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
EVENT_CONSTRAINT_END
};
struct event_constraint intel_westmere_pebs_event_constraints[] = {
INTEL_PLD_CONSTRAINT(0x100b, 0xf), /* MEM_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
- INTEL_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
- INTEL_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0x0f, 0xf), /* MEM_UNCORE_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x010c, 0xf), /* MEM_STORE_RETIRED.DTLB_MISS */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc0, 0xf), /* INSTR_RETIRED.* */
INTEL_EVENT_CONSTRAINT(0xc2, 0xf), /* UOPS_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
- INTEL_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
- INTEL_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
- INTEL_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc4, 0xf), /* BR_INST_RETIRED.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc5, 0xf), /* BR_MISP_RETIRED.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xc7, 0xf), /* SSEX_UOPS_RETIRED.* */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x20c8, 0xf), /* ITLB_MISS_RETIRED */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xcb, 0xf), /* MEM_LOAD_RETIRED.* */
+ INTEL_FLAGS_EVENT_CONSTRAINT(0xf7, 0xf), /* FP_ASSIST.* */
EVENT_CONSTRAINT_END
};
struct event_constraint intel_snb_pebs_event_constraints[] = {
- INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */
/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
@@ -617,7 +617,7 @@ struct event_constraint intel_snb_pebs_event_constraints[] = {
};
struct event_constraint intel_ivb_pebs_event_constraints[] = {
- INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
INTEL_PLD_CONSTRAINT(0x01cd, 0x8), /* MEM_TRANS_RETIRED.LAT_ABOVE_THR */
INTEL_PST_CONSTRAINT(0x02cd, 0x8), /* MEM_TRANS_RETIRED.PRECISE_STORES */
/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
@@ -628,7 +628,7 @@ struct event_constraint intel_ivb_pebs_event_constraints[] = {
};
struct event_constraint intel_hsw_pebs_event_constraints[] = {
- INTEL_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
+ INTEL_FLAGS_UEVENT_CONSTRAINT(0x01c0, 0x2), /* INST_RETIRED.PRECDIST */
INTEL_PLD_CONSTRAINT(0x01cd, 0xf), /* MEM_TRANS_RETIRED.* */
/* UOPS_RETIRED.ALL, inv=1, cmask=16 (cycles:p). */
INTEL_FLAGS_EVENT_CONSTRAINT(0x108001c2, 0xf),
@@ -724,6 +724,7 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
unsigned long ip = regs->ip;
int is_64bit = 0;
void *kaddr;
+ int size;
/*
* We don't need to fixup if the PEBS assist is fault like
@@ -758,11 +759,12 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
return 1;
}
+ size = ip - to;
if (!kernel_ip(ip)) {
- int size, bytes;
+ int bytes;
u8 *buf = this_cpu_read(insn_buffer);
- size = ip - to; /* Must fit our buffer, see above */
+ /* 'size' must fit our buffer, see above */
bytes = copy_from_user_nmi(buf, (void __user *)to, size);
if (bytes != 0)
return 0;
@@ -780,11 +782,20 @@ static int intel_pmu_pebs_fixup_ip(struct pt_regs *regs)
#ifdef CONFIG_X86_64
is_64bit = kernel_ip(to) || !test_thread_flag(TIF_IA32);
#endif
- insn_init(&insn, kaddr, is_64bit);
+ insn_init(&insn, kaddr, size, is_64bit);
insn_get_length(&insn);
+ /*
+ * Make sure there was not a problem decoding the
+ * instruction and getting the length. This is
+ * doubly important because we have an infinite
+ * loop if insn.length=0.
+ */
+ if (!insn.length)
+ break;
to += insn.length;
kaddr += insn.length;
+ size -= insn.length;
} while (to < ip);
if (to == ip) {
@@ -886,6 +897,29 @@ static void __intel_pmu_pebs_event(struct perf_event *event,
regs.bp = pebs->bp;
regs.sp = pebs->sp;
+ if (sample_type & PERF_SAMPLE_REGS_INTR) {
+ regs.ax = pebs->ax;
+ regs.bx = pebs->bx;
+ regs.cx = pebs->cx;
+ regs.dx = pebs->dx;
+ regs.si = pebs->si;
+ regs.di = pebs->di;
+ regs.bp = pebs->bp;
+ regs.sp = pebs->sp;
+
+ regs.flags = pebs->flags;
+#ifndef CONFIG_X86_32
+ regs.r8 = pebs->r8;
+ regs.r9 = pebs->r9;
+ regs.r10 = pebs->r10;
+ regs.r11 = pebs->r11;
+ regs.r12 = pebs->r12;
+ regs.r13 = pebs->r13;
+ regs.r14 = pebs->r14;
+ regs.r15 = pebs->r15;
+#endif
+ }
+
if (event->attr.precise_ip > 1 && x86_pmu.intel_cap.pebs_format >= 2) {
regs.ip = pebs->real_ip;
regs.flags |= PERF_EFLAGS_EXACT;
diff --git a/arch/x86/kernel/cpu/perf_event_intel_lbr.c b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
index 45fa730..58f1a94 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_lbr.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_lbr.c
@@ -465,7 +465,7 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
{
struct insn insn;
void *addr;
- int bytes, size = MAX_INSN_SIZE;
+ int bytes_read, bytes_left;
int ret = X86_BR_NONE;
int ext, to_plm, from_plm;
u8 buf[MAX_INSN_SIZE];
@@ -493,8 +493,10 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
return X86_BR_NONE;
/* may fail if text not present */
- bytes = copy_from_user_nmi(buf, (void __user *)from, size);
- if (bytes != 0)
+ bytes_left = copy_from_user_nmi(buf, (void __user *)from,
+ MAX_INSN_SIZE);
+ bytes_read = MAX_INSN_SIZE - bytes_left;
+ if (!bytes_read)
return X86_BR_NONE;
addr = buf;
@@ -505,10 +507,19 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
* Ensure we don't blindy read any address by validating it is
* a known text address.
*/
- if (kernel_text_address(from))
+ if (kernel_text_address(from)) {
addr = (void *)from;
- else
+ /*
+ * Assume we can get the maximum possible size
+ * when grabbing kernel data. This is not
+ * _strictly_ true since we could possibly be
+ * executing up next to a memory hole, but
+ * it is very unlikely to be a problem.
+ */
+ bytes_read = MAX_INSN_SIZE;
+ } else {
return X86_BR_NONE;
+ }
}
/*
@@ -518,8 +529,10 @@ static int branch_type(unsigned long from, unsigned long to, int abort)
#ifdef CONFIG_X86_64
is64 = kernel_ip((unsigned long)addr) || !test_thread_flag(TIF_IA32);
#endif
- insn_init(&insn, addr, is64);
+ insn_init(&insn, addr, bytes_read, is64);
insn_get_opcode(&insn);
+ if (!insn.opcode.got)
+ return X86_BR_ABORT;
switch (insn.opcode.bytes[0]) {
case 0xf:
diff --git a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
index f9ed429..745b158 100644
--- a/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
+++ b/arch/x86/kernel/cpu/perf_event_intel_uncore_snbep.c
@@ -449,7 +449,11 @@ static struct attribute *snbep_uncore_qpi_formats_attr[] = {
static struct uncore_event_desc snbep_uncore_imc_events[] = {
INTEL_UNCORE_EVENT_DESC(clockticks, "event=0xff,umask=0x00"),
INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),
INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),
{ /* end: all zeroes */ },
};
@@ -2036,7 +2040,11 @@ static struct intel_uncore_type hswep_uncore_ha = {
static struct uncore_event_desc hswep_uncore_imc_events[] = {
INTEL_UNCORE_EVENT_DESC(clockticks, "event=0x00,umask=0x00"),
INTEL_UNCORE_EVENT_DESC(cas_count_read, "event=0x04,umask=0x03"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_read.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_read.unit, "MiB"),
INTEL_UNCORE_EVENT_DESC(cas_count_write, "event=0x04,umask=0x0c"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_write.scale, "6.103515625e-5"),
+ INTEL_UNCORE_EVENT_DESC(cas_count_write.unit, "MiB"),
{ /* end: all zeroes */ },
};
diff --git a/arch/x86/kernel/cpu/proc.c b/arch/x86/kernel/cpu/proc.c
index 5433658..e7d8c76 100644
--- a/arch/x86/kernel/cpu/proc.c
+++ b/arch/x86/kernel/cpu/proc.c
@@ -72,7 +72,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
if (c->x86_mask || c->cpuid_level >= 0)
seq_printf(m, "stepping\t: %d\n", c->x86_mask);
else
- seq_printf(m, "stepping\t: unknown\n");
+ seq_puts(m, "stepping\t: unknown\n");
if (c->microcode)
seq_printf(m, "microcode\t: 0x%x\n", c->microcode);
@@ -92,12 +92,12 @@ static int show_cpuinfo(struct seq_file *m, void *v)
show_cpuinfo_core(m, c, cpu);
show_cpuinfo_misc(m, c);
- seq_printf(m, "flags\t\t:");
+ seq_puts(m, "flags\t\t:");
for (i = 0; i < 32*NCAPINTS; i++)
if (cpu_has(c, i) && x86_cap_flags[i] != NULL)
seq_printf(m, " %s", x86_cap_flags[i]);
- seq_printf(m, "\nbugs\t\t:");
+ seq_puts(m, "\nbugs\t\t:");
for (i = 0; i < 32*NBUGINTS; i++) {
unsigned int bug_bit = 32*NCAPINTS + i;
@@ -118,7 +118,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
seq_printf(m, "address sizes\t: %u bits physical, %u bits virtual\n",
c->x86_phys_bits, c->x86_virt_bits);
- seq_printf(m, "power management:");
+ seq_puts(m, "power management:");
for (i = 0; i < 32; i++) {
if (c->x86_power & (1 << i)) {
if (i < ARRAY_SIZE(x86_power_flags) &&
@@ -131,7 +131,7 @@ static int show_cpuinfo(struct seq_file *m, void *v)
}
}
- seq_printf(m, "\n\n");
+ seq_puts(m, "\n\n");
return 0;
}
diff --git a/arch/x86/kernel/cpu/scattered.c b/arch/x86/kernel/cpu/scattered.c
index 4a8013d..6063909 100644
--- a/arch/x86/kernel/cpu/scattered.c
+++ b/arch/x86/kernel/cpu/scattered.c
@@ -36,6 +36,11 @@ void init_scattered_cpuid_features(struct cpuinfo_x86 *c)
{ X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006, 0 },
{ X86_FEATURE_PLN, CR_EAX, 4, 0x00000006, 0 },
{ X86_FEATURE_PTS, CR_EAX, 6, 0x00000006, 0 },
+ { X86_FEATURE_HWP, CR_EAX, 7, 0x00000006, 0 },
+ { X86_FEATURE_HWP_NOITFY, CR_EAX, 8, 0x00000006, 0 },
+ { X86_FEATURE_HWP_ACT_WINDOW, CR_EAX, 9, 0x00000006, 0 },
+ { X86_FEATURE_HWP_EPP, CR_EAX,10, 0x00000006, 0 },
+ { X86_FEATURE_HWP_PKG_REQ, CR_EAX,11, 0x00000006, 0 },
{ X86_FEATURE_APERFMPERF, CR_ECX, 0, 0x00000006, 0 },
{ X86_FEATURE_EPB, CR_ECX, 3, 0x00000006, 0 },
{ X86_FEATURE_HW_PSTATE, CR_EDX, 7, 0x80000007, 0 },
diff --git a/arch/x86/kernel/cpuid.c b/arch/x86/kernel/cpuid.c
index 3225ae6c..83741a7 100644
--- a/arch/x86/kernel/cpuid.c
+++ b/arch/x86/kernel/cpuid.c
@@ -143,7 +143,7 @@ static int cpuid_device_create(int cpu)
dev = device_create(cpuid_class, NULL, MKDEV(CPUID_MAJOR, cpu), NULL,
"cpu%d", cpu);
- return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+ return PTR_ERR_OR_ZERO(dev);
}
static void cpuid_device_destroy(int cpu)
diff --git a/arch/x86/kernel/espfix_64.c b/arch/x86/kernel/espfix_64.c
index 94d857f..f5d0730 100644
--- a/arch/x86/kernel/espfix_64.c
+++ b/arch/x86/kernel/espfix_64.c
@@ -122,9 +122,6 @@ static void init_espfix_random(void)
void __init init_espfix_bsp(void)
{
pgd_t *pgd_p;
- pteval_t ptemask;
-
- ptemask = __supported_pte_mask;
/* Install the espfix pud into the kernel page directory */
pgd_p = &init_level4_pgt[pgd_index(ESPFIX_BASE_ADDR)];
diff --git a/arch/x86/kernel/ftrace.c b/arch/x86/kernel/ftrace.c
index 3386dc9..2142376 100644
--- a/arch/x86/kernel/ftrace.c
+++ b/arch/x86/kernel/ftrace.c
@@ -17,6 +17,7 @@
#include <linux/ftrace.h>
#include <linux/percpu.h>
#include <linux/sched.h>
+#include <linux/slab.h>
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
@@ -47,7 +48,7 @@ int ftrace_arch_code_modify_post_process(void)
union ftrace_code_union {
char code[MCOUNT_INSN_SIZE];
struct {
- char e8;
+ unsigned char e8;
int offset;
} __attribute__((packed));
};
@@ -582,7 +583,7 @@ void ftrace_replace_code(int enable)
remove_breakpoints:
pr_warn("Failed on %s (%d):\n", report, count);
- ftrace_bug(ret, rec ? rec->ip : 0);
+ ftrace_bug(ret, rec);
for_ftrace_rec_iter(iter) {
rec = ftrace_rec_iter_record(iter);
/*
@@ -644,13 +645,8 @@ int __init ftrace_dyn_arch_init(void)
{
return 0;
}
-#endif
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-extern void ftrace_graph_call(void);
+#if defined(CONFIG_X86_64) || defined(CONFIG_FUNCTION_GRAPH_TRACER)
static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
{
static union ftrace_code_union calc;
@@ -664,6 +660,280 @@ static unsigned char *ftrace_jmp_replace(unsigned long ip, unsigned long addr)
*/
return calc.code;
}
+#endif
+
+/* Currently only x86_64 supports dynamic trampolines */
+#ifdef CONFIG_X86_64
+
+#ifdef CONFIG_MODULES
+#include <linux/moduleloader.h>
+/* Module allocation simplifies allocating memory for code */
+static inline void *alloc_tramp(unsigned long size)
+{
+ return module_alloc(size);
+}
+static inline void tramp_free(void *tramp)
+{
+ module_free(NULL, tramp);
+}
+#else
+/* Trampolines can only be created if modules are supported */
+static inline void *alloc_tramp(unsigned long size)
+{
+ return NULL;
+}
+static inline void tramp_free(void *tramp) { }
+#endif
+
+/* Defined as markers to the end of the ftrace default trampolines */
+extern void ftrace_caller_end(void);
+extern void ftrace_regs_caller_end(void);
+extern void ftrace_return(void);
+extern void ftrace_caller_op_ptr(void);
+extern void ftrace_regs_caller_op_ptr(void);
+
+/* movq function_trace_op(%rip), %rdx */
+/* 0x48 0x8b 0x15 <offset-to-ftrace_trace_op (4 bytes)> */
+#define OP_REF_SIZE 7
+
+/*
+ * The ftrace_ops is passed to the function callback. Since the
+ * trampoline only services a single ftrace_ops, we can pass in
+ * that ops directly.
+ *
+ * The ftrace_op_code_union is used to create a pointer to the
+ * ftrace_ops that will be passed to the callback function.
+ */
+union ftrace_op_code_union {
+ char code[OP_REF_SIZE];
+ struct {
+ char op[3];
+ int offset;
+ } __attribute__((packed));
+};
+
+static unsigned long
+create_trampoline(struct ftrace_ops *ops, unsigned int *tramp_size)
+{
+ unsigned const char *jmp;
+ unsigned long start_offset;
+ unsigned long end_offset;
+ unsigned long op_offset;
+ unsigned long offset;
+ unsigned long size;
+ unsigned long ip;
+ unsigned long *ptr;
+ void *trampoline;
+ /* 48 8b 15 <offset> is movq <offset>(%rip), %rdx */
+ unsigned const char op_ref[] = { 0x48, 0x8b, 0x15 };
+ union ftrace_op_code_union op_ptr;
+ int ret;
+
+ if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) {
+ start_offset = (unsigned long)ftrace_regs_caller;
+ end_offset = (unsigned long)ftrace_regs_caller_end;
+ op_offset = (unsigned long)ftrace_regs_caller_op_ptr;
+ } else {
+ start_offset = (unsigned long)ftrace_caller;
+ end_offset = (unsigned long)ftrace_caller_end;
+ op_offset = (unsigned long)ftrace_caller_op_ptr;
+ }
+
+ size = end_offset - start_offset;
+
+ /*
+ * Allocate enough size to store the ftrace_caller code,
+ * the jmp to ftrace_return, as well as the address of
+ * the ftrace_ops this trampoline is used for.
+ */
+ trampoline = alloc_tramp(size + MCOUNT_INSN_SIZE + sizeof(void *));
+ if (!trampoline)
+ return 0;
+
+ *tramp_size = size + MCOUNT_INSN_SIZE + sizeof(void *);
+
+ /* Copy ftrace_caller onto the trampoline memory */
+ ret = probe_kernel_read(trampoline, (void *)start_offset, size);
+ if (WARN_ON(ret < 0)) {
+ tramp_free(trampoline);
+ return 0;
+ }
+
+ ip = (unsigned long)trampoline + size;
+
+ /* The trampoline ends with a jmp to ftrace_return */
+ jmp = ftrace_jmp_replace(ip, (unsigned long)ftrace_return);
+ memcpy(trampoline + size, jmp, MCOUNT_INSN_SIZE);
+
+ /*
+ * The address of the ftrace_ops that is used for this trampoline
+ * is stored at the end of the trampoline. This will be used to
+ * load the third parameter for the callback. Basically, that
+ * location at the end of the trampoline takes the place of
+ * the global function_trace_op variable.
+ */
+
+ ptr = (unsigned long *)(trampoline + size + MCOUNT_INSN_SIZE);
+ *ptr = (unsigned long)ops;
+
+ op_offset -= start_offset;
+ memcpy(&op_ptr, trampoline + op_offset, OP_REF_SIZE);
+
+ /* Are we pointing to the reference? */
+ if (WARN_ON(memcmp(op_ptr.op, op_ref, 3) != 0)) {
+ tramp_free(trampoline);
+ return 0;
+ }
+
+ /* Load the contents of ptr into the callback parameter */
+ offset = (unsigned long)ptr;
+ offset -= (unsigned long)trampoline + op_offset + OP_REF_SIZE;
+
+ op_ptr.offset = offset;
+
+ /* put in the new offset to the ftrace_ops */
+ memcpy(trampoline + op_offset, &op_ptr, OP_REF_SIZE);
+
+ /* ALLOC_TRAMP flags lets us know we created it */
+ ops->flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
+
+ return (unsigned long)trampoline;
+}
+
+static unsigned long calc_trampoline_call_offset(bool save_regs)
+{
+ unsigned long start_offset;
+ unsigned long call_offset;
+
+ if (save_regs) {
+ start_offset = (unsigned long)ftrace_regs_caller;
+ call_offset = (unsigned long)ftrace_regs_call;
+ } else {
+ start_offset = (unsigned long)ftrace_caller;
+ call_offset = (unsigned long)ftrace_call;
+ }
+
+ return call_offset - start_offset;
+}
+
+void arch_ftrace_update_trampoline(struct ftrace_ops *ops)
+{
+ ftrace_func_t func;
+ unsigned char *new;
+ unsigned long offset;
+ unsigned long ip;
+ unsigned int size;
+ int ret;
+
+ if (ops->trampoline) {
+ /*
+ * The ftrace_ops caller may set up its own trampoline.
+ * In such a case, this code must not modify it.
+ */
+ if (!(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
+ return;
+ } else {
+ ops->trampoline = create_trampoline(ops, &size);
+ if (!ops->trampoline)
+ return;
+ ops->trampoline_size = size;
+ }
+
+ offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);
+ ip = ops->trampoline + offset;
+
+ func = ftrace_ops_get_func(ops);
+
+ /* Do a safe modify in case the trampoline is executing */
+ new = ftrace_call_replace(ip, (unsigned long)func);
+ ret = update_ftrace_func(ip, new);
+
+ /* The update should never fail */
+ WARN_ON(ret);
+}
+
+/* Return the address of the function the trampoline calls */
+static void *addr_from_call(void *ptr)
+{
+ union ftrace_code_union calc;
+ int ret;
+
+ ret = probe_kernel_read(&calc, ptr, MCOUNT_INSN_SIZE);
+ if (WARN_ON_ONCE(ret < 0))
+ return NULL;
+
+ /* Make sure this is a call */
+ if (WARN_ON_ONCE(calc.e8 != 0xe8)) {
+ pr_warn("Expected e8, got %x\n", calc.e8);
+ return NULL;
+ }
+
+ return ptr + MCOUNT_INSN_SIZE + calc.offset;
+}
+
+void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
+ unsigned long frame_pointer);
+
+/*
+ * If the ops->trampoline was not allocated, then it probably
+ * has a static trampoline func, or is the ftrace caller itself.
+ */
+static void *static_tramp_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
+{
+ unsigned long offset;
+ bool save_regs = rec->flags & FTRACE_FL_REGS_EN;
+ void *ptr;
+
+ if (ops && ops->trampoline) {
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+ /*
+ * We only know about function graph tracer setting as static
+ * trampoline.
+ */
+ if (ops->trampoline == FTRACE_GRAPH_ADDR)
+ return (void *)prepare_ftrace_return;
+#endif
+ return NULL;
+ }
+
+ offset = calc_trampoline_call_offset(save_regs);
+
+ if (save_regs)
+ ptr = (void *)FTRACE_REGS_ADDR + offset;
+ else
+ ptr = (void *)FTRACE_ADDR + offset;
+
+ return addr_from_call(ptr);
+}
+
+void *arch_ftrace_trampoline_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
+{
+ unsigned long offset;
+
+ /* If we didn't allocate this trampoline, consider it static */
+ if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
+ return static_tramp_func(ops, rec);
+
+ offset = calc_trampoline_call_offset(ops->flags & FTRACE_OPS_FL_SAVE_REGS);
+ return addr_from_call((void *)ops->trampoline + offset);
+}
+
+void arch_ftrace_trampoline_free(struct ftrace_ops *ops)
+{
+ if (!ops || !(ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP))
+ return;
+
+ tramp_free((void *)ops->trampoline);
+ ops->trampoline = 0;
+}
+
+#endif /* CONFIG_X86_64 */
+#endif /* CONFIG_DYNAMIC_FTRACE */
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
+extern void ftrace_graph_call(void);
static int ftrace_mod_jmp(unsigned long ip, void *func)
{
@@ -694,7 +964,7 @@ int ftrace_disable_ftrace_graph_caller(void)
* Hook the return address and push it in the stack of return addrs
* in current thread info.
*/
-void prepare_ftrace_return(unsigned long *parent, unsigned long self_addr,
+void prepare_ftrace_return(unsigned long self_addr, unsigned long *parent,
unsigned long frame_pointer)
{
unsigned long old;
diff --git a/arch/x86/kernel/irq.c b/arch/x86/kernel/irq.c
index 922d285..6307a0f 100644
--- a/arch/x86/kernel/irq.c
+++ b/arch/x86/kernel/irq.c
@@ -59,78 +59,78 @@ int arch_show_interrupts(struct seq_file *p, int prec)
seq_printf(p, "%*s: ", prec, "NMI");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->__nmi_count);
- seq_printf(p, " Non-maskable interrupts\n");
+ seq_puts(p, " Non-maskable interrupts\n");
#ifdef CONFIG_X86_LOCAL_APIC
seq_printf(p, "%*s: ", prec, "LOC");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_timer_irqs);
- seq_printf(p, " Local timer interrupts\n");
+ seq_puts(p, " Local timer interrupts\n");
seq_printf(p, "%*s: ", prec, "SPU");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_spurious_count);
- seq_printf(p, " Spurious interrupts\n");
+ seq_puts(p, " Spurious interrupts\n");
seq_printf(p, "%*s: ", prec, "PMI");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_perf_irqs);
- seq_printf(p, " Performance monitoring interrupts\n");
+ seq_puts(p, " Performance monitoring interrupts\n");
seq_printf(p, "%*s: ", prec, "IWI");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->apic_irq_work_irqs);
- seq_printf(p, " IRQ work interrupts\n");
+ seq_puts(p, " IRQ work interrupts\n");
seq_printf(p, "%*s: ", prec, "RTR");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->icr_read_retry_count);
- seq_printf(p, " APIC ICR read retries\n");
+ seq_puts(p, " APIC ICR read retries\n");
#endif
if (x86_platform_ipi_callback) {
seq_printf(p, "%*s: ", prec, "PLT");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->x86_platform_ipis);
- seq_printf(p, " Platform interrupts\n");
+ seq_puts(p, " Platform interrupts\n");
}
#ifdef CONFIG_SMP
seq_printf(p, "%*s: ", prec, "RES");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_resched_count);
- seq_printf(p, " Rescheduling interrupts\n");
+ seq_puts(p, " Rescheduling interrupts\n");
seq_printf(p, "%*s: ", prec, "CAL");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_call_count -
irq_stats(j)->irq_tlb_count);
- seq_printf(p, " Function call interrupts\n");
+ seq_puts(p, " Function call interrupts\n");
seq_printf(p, "%*s: ", prec, "TLB");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_tlb_count);
- seq_printf(p, " TLB shootdowns\n");
+ seq_puts(p, " TLB shootdowns\n");
#endif
#ifdef CONFIG_X86_THERMAL_VECTOR
seq_printf(p, "%*s: ", prec, "TRM");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_thermal_count);
- seq_printf(p, " Thermal event interrupts\n");
+ seq_puts(p, " Thermal event interrupts\n");
#endif
#ifdef CONFIG_X86_MCE_THRESHOLD
seq_printf(p, "%*s: ", prec, "THR");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_threshold_count);
- seq_printf(p, " Threshold APIC interrupts\n");
+ seq_puts(p, " Threshold APIC interrupts\n");
#endif
#ifdef CONFIG_X86_MCE
seq_printf(p, "%*s: ", prec, "MCE");
for_each_online_cpu(j)
seq_printf(p, "%10u ", per_cpu(mce_exception_count, j));
- seq_printf(p, " Machine check exceptions\n");
+ seq_puts(p, " Machine check exceptions\n");
seq_printf(p, "%*s: ", prec, "MCP");
for_each_online_cpu(j)
seq_printf(p, "%10u ", per_cpu(mce_poll_count, j));
- seq_printf(p, " Machine check polls\n");
+ seq_puts(p, " Machine check polls\n");
#endif
#if IS_ENABLED(CONFIG_HYPERV) || defined(CONFIG_XEN)
seq_printf(p, "%*s: ", prec, "THR");
for_each_online_cpu(j)
seq_printf(p, "%10u ", irq_stats(j)->irq_hv_callback_count);
- seq_printf(p, " Hypervisor callback interrupts\n");
+ seq_puts(p, " Hypervisor callback interrupts\n");
#endif
seq_printf(p, "%*s: %10u\n", prec, "ERR", atomic_read(&irq_err_count));
#if defined(CONFIG_X86_IO_APIC)
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 67e6d19e..f7e3cd5 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -285,7 +285,7 @@ static int can_probe(unsigned long paddr)
* normally used, we just go through if there is no kprobe.
*/
__addr = recover_probed_instruction(buf, addr);
- kernel_insn_init(&insn, (void *)__addr);
+ kernel_insn_init(&insn, (void *)__addr, MAX_INSN_SIZE);
insn_get_length(&insn);
/*
@@ -330,8 +330,10 @@ int __copy_instruction(u8 *dest, u8 *src)
{
struct insn insn;
kprobe_opcode_t buf[MAX_INSN_SIZE];
+ unsigned long recovered_insn =
+ recover_probed_instruction(buf, (unsigned long)src);
- kernel_insn_init(&insn, (void *)recover_probed_instruction(buf, (unsigned long)src));
+ kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
insn_get_length(&insn);
/* Another subsystem puts a breakpoint, failed to recover */
if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
@@ -342,7 +344,7 @@ int __copy_instruction(u8 *dest, u8 *src)
if (insn_rip_relative(&insn)) {
s64 newdisp;
u8 *disp;
- kernel_insn_init(&insn, dest);
+ kernel_insn_init(&insn, dest, insn.length);
insn_get_displacement(&insn);
/*
* The copied instruction uses the %rip-relative addressing
diff --git a/arch/x86/kernel/kprobes/ftrace.c b/arch/x86/kernel/kprobes/ftrace.c
index 717b02a..5f8f0b3 100644
--- a/arch/x86/kernel/kprobes/ftrace.c
+++ b/arch/x86/kernel/kprobes/ftrace.c
@@ -27,7 +27,7 @@
static nokprobe_inline
int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
- struct kprobe_ctlblk *kcb)
+ struct kprobe_ctlblk *kcb, unsigned long orig_ip)
{
/*
* Emulate singlestep (and also recover regs->ip)
@@ -39,6 +39,8 @@ int __skip_singlestep(struct kprobe *p, struct pt_regs *regs,
p->post_handler(p, regs, 0);
}
__this_cpu_write(current_kprobe, NULL);
+ if (orig_ip)
+ regs->ip = orig_ip;
return 1;
}
@@ -46,7 +48,7 @@ int skip_singlestep(struct kprobe *p, struct pt_regs *regs,
struct kprobe_ctlblk *kcb)
{
if (kprobe_ftrace(p))
- return __skip_singlestep(p, regs, kcb);
+ return __skip_singlestep(p, regs, kcb, 0);
else
return 0;
}
@@ -71,13 +73,14 @@ void kprobe_ftrace_handler(unsigned long ip, unsigned long parent_ip,
if (kprobe_running()) {
kprobes_inc_nmissed_count(p);
} else {
+ unsigned long orig_ip = regs->ip;
/* Kprobe handler expects regs->ip = ip + 1 as breakpoint hit */
regs->ip = ip + sizeof(kprobe_opcode_t);
__this_cpu_write(current_kprobe, p);
kcb->kprobe_status = KPROBE_HIT_ACTIVE;
if (!p->pre_handler || !p->pre_handler(p, regs))
- __skip_singlestep(p, regs, kcb);
+ __skip_singlestep(p, regs, kcb, orig_ip);
/*
* If pre_handler returns !0, it sets regs->ip and
* resets current kprobe.
diff --git a/arch/x86/kernel/kprobes/opt.c b/arch/x86/kernel/kprobes/opt.c
index f1314d0..7c523bb 100644
--- a/arch/x86/kernel/kprobes/opt.c
+++ b/arch/x86/kernel/kprobes/opt.c
@@ -251,13 +251,15 @@ static int can_optimize(unsigned long paddr)
/* Decode instructions */
addr = paddr - offset;
while (addr < paddr - offset + size) { /* Decode until function end */
+ unsigned long recovered_insn;
if (search_exception_tables(addr))
/*
* Since some fixup code will jumps into this function,
* we can't optimize kprobe in this function.
*/
return 0;
- kernel_insn_init(&insn, (void *)recover_probed_instruction(buf, addr));
+ recovered_insn = recover_probed_instruction(buf, addr);
+ kernel_insn_init(&insn, (void *)recovered_insn, MAX_INSN_SIZE);
insn_get_length(&insn);
/* Another subsystem puts a breakpoint */
if (insn.opcode.bytes[0] == BREAKPOINT_INSTRUCTION)
diff --git a/arch/x86/kernel/mcount_64.S b/arch/x86/kernel/mcount_64.S
index c73aecf..94ea120 100644
--- a/arch/x86/kernel/mcount_64.S
+++ b/arch/x86/kernel/mcount_64.S
@@ -21,40 +21,159 @@
# define function_hook mcount
#endif
+/* All cases save the original rbp (8 bytes) */
+#ifdef CONFIG_FRAME_POINTER
+# ifdef CC_USING_FENTRY
+/* Save parent and function stack frames (rip and rbp) */
+# define MCOUNT_FRAME_SIZE (8+16*2)
+# else
+/* Save just function stack frame (rip and rbp) */
+# define MCOUNT_FRAME_SIZE (8+16)
+# endif
+#else
+/* No need to save a stack frame */
+# define MCOUNT_FRAME_SIZE 8
+#endif /* CONFIG_FRAME_POINTER */
+
+/* Size of stack used to save mcount regs in save_mcount_regs */
+#define MCOUNT_REG_SIZE (SS+8 + MCOUNT_FRAME_SIZE)
+
+/*
+ * gcc -pg option adds a call to 'mcount' in most functions.
+ * When -mfentry is used, the call is to 'fentry' and not 'mcount'
+ * and is done before the function's stack frame is set up.
+ * They both require a set of regs to be saved before calling
+ * any C code and restored before returning back to the function.
+ *
+ * On boot up, all these calls are converted into nops. When tracing
+ * is enabled, the call can jump to either ftrace_caller or
+ * ftrace_regs_caller. Callbacks (tracing functions) that require
+ * ftrace_regs_caller (like kprobes) need to have pt_regs passed to
+ * it. For this reason, the size of the pt_regs structure will be
+ * allocated on the stack and the required mcount registers will
+ * be saved in the locations that pt_regs has them in.
+ */
+
+/*
+ * @added: the amount of stack added before calling this
+ *
+ * After this is called, the following registers contain:
+ *
+ * %rdi - holds the address that called the trampoline
+ * %rsi - holds the parent function (traced function's return address)
+ * %rdx - holds the original %rbp
+ */
+.macro save_mcount_regs added=0
+
+ /* Always save the original rbp */
+ pushq %rbp
+
+#ifdef CONFIG_FRAME_POINTER
+ /*
+ * Stack traces will stop at the ftrace trampoline if the frame pointer
+ * is not set up properly. If fentry is used, we need to save a frame
+ * pointer for the parent as well as the function traced, because the
+ * fentry is called before the stack frame is set up, where as mcount
+ * is called afterward.
+ */
+#ifdef CC_USING_FENTRY
+ /* Save the parent pointer (skip orig rbp and our return address) */
+ pushq \added+8*2(%rsp)
+ pushq %rbp
+ movq %rsp, %rbp
+ /* Save the return address (now skip orig rbp, rbp and parent) */
+ pushq \added+8*3(%rsp)
+#else
+ /* Can't assume that rip is before this (unless added was zero) */
+ pushq \added+8(%rsp)
+#endif
+ pushq %rbp
+ movq %rsp, %rbp
+#endif /* CONFIG_FRAME_POINTER */
+
+ /*
+ * We add enough stack to save all regs.
+ */
+ subq $(MCOUNT_REG_SIZE - MCOUNT_FRAME_SIZE), %rsp
+ movq %rax, RAX(%rsp)
+ movq %rcx, RCX(%rsp)
+ movq %rdx, RDX(%rsp)
+ movq %rsi, RSI(%rsp)
+ movq %rdi, RDI(%rsp)
+ movq %r8, R8(%rsp)
+ movq %r9, R9(%rsp)
+ /*
+ * Save the original RBP. Even though the mcount ABI does not
+ * require this, it helps out callers.
+ */
+ movq MCOUNT_REG_SIZE-8(%rsp), %rdx
+ movq %rdx, RBP(%rsp)
+
+ /* Copy the parent address into %rsi (second parameter) */
+#ifdef CC_USING_FENTRY
+ movq MCOUNT_REG_SIZE+8+\added(%rsp), %rsi
+#else
+ /* %rdx contains original %rbp */
+ movq 8(%rdx), %rsi
+#endif
+
+ /* Move RIP to its proper location */
+ movq MCOUNT_REG_SIZE+\added(%rsp), %rdi
+ movq %rdi, RIP(%rsp)
+
+ /*
+ * Now %rdi (the first parameter) has the return address of
+ * where ftrace_call returns. But the callbacks expect the
+ * address of the call itself.
+ */
+ subq $MCOUNT_INSN_SIZE, %rdi
+ .endm
+
+.macro restore_mcount_regs
+ movq R9(%rsp), %r9
+ movq R8(%rsp), %r8
+ movq RDI(%rsp), %rdi
+ movq RSI(%rsp), %rsi
+ movq RDX(%rsp), %rdx
+ movq RCX(%rsp), %rcx
+ movq RAX(%rsp), %rax
+
+ /* ftrace_regs_caller can modify %rbp */
+ movq RBP(%rsp), %rbp
+
+ addq $MCOUNT_REG_SIZE, %rsp
+
+ .endm
+
#ifdef CONFIG_DYNAMIC_FTRACE
ENTRY(function_hook)
retq
END(function_hook)
-/* skip is set if stack has been adjusted */
-.macro ftrace_caller_setup skip=0
- MCOUNT_SAVE_FRAME \skip
+ENTRY(ftrace_caller)
+ /* save_mcount_regs fills in first two parameters */
+ save_mcount_regs
+GLOBAL(ftrace_caller_op_ptr)
/* Load the ftrace_ops into the 3rd parameter */
movq function_trace_op(%rip), %rdx
- /* Load ip into the first parameter */
- movq RIP(%rsp), %rdi
- subq $MCOUNT_INSN_SIZE, %rdi
- /* Load the parent_ip into the second parameter */
-#ifdef CC_USING_FENTRY
- movq SS+16(%rsp), %rsi
-#else
- movq 8(%rbp), %rsi
-#endif
-.endm
-
-ENTRY(ftrace_caller)
- ftrace_caller_setup
/* regs go into 4th parameter (but make it NULL) */
movq $0, %rcx
GLOBAL(ftrace_call)
call ftrace_stub
- MCOUNT_RESTORE_FRAME
-ftrace_return:
+ restore_mcount_regs
+
+ /*
+ * The copied trampoline must call ftrace_return as it
+ * still may need to call the function graph tracer.
+ */
+GLOBAL(ftrace_caller_end)
+
+GLOBAL(ftrace_return)
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
GLOBAL(ftrace_graph_call)
@@ -66,11 +185,16 @@ GLOBAL(ftrace_stub)
END(ftrace_caller)
ENTRY(ftrace_regs_caller)
- /* Save the current flags before compare (in SS location)*/
+ /* Save the current flags before any operations that can change them */
pushfq
- /* skip=8 to skip flags saved in SS */
- ftrace_caller_setup 8
+ /* added 8 bytes to save flags */
+ save_mcount_regs 8
+ /* save_mcount_regs fills in first two parameters */
+
+GLOBAL(ftrace_regs_caller_op_ptr)
+ /* Load the ftrace_ops into the 3rd parameter */
+ movq function_trace_op(%rip), %rdx
/* Save the rest of pt_regs */
movq %r15, R15(%rsp)
@@ -79,18 +203,17 @@ ENTRY(ftrace_regs_caller)
movq %r12, R12(%rsp)
movq %r11, R11(%rsp)
movq %r10, R10(%rsp)
- movq %rbp, RBP(%rsp)
movq %rbx, RBX(%rsp)
/* Copy saved flags */
- movq SS(%rsp), %rcx
+ movq MCOUNT_REG_SIZE(%rsp), %rcx
movq %rcx, EFLAGS(%rsp)
/* Kernel segments */
movq $__KERNEL_DS, %rcx
movq %rcx, SS(%rsp)
movq $__KERNEL_CS, %rcx
movq %rcx, CS(%rsp)
- /* Stack - skipping return address */
- leaq SS+16(%rsp), %rcx
+ /* Stack - skipping return address and flags */
+ leaq MCOUNT_REG_SIZE+8*2(%rsp), %rcx
movq %rcx, RSP(%rsp)
/* regs go into 4th parameter */
@@ -101,11 +224,11 @@ GLOBAL(ftrace_regs_call)
/* Copy flags back to SS, to restore them */
movq EFLAGS(%rsp), %rax
- movq %rax, SS(%rsp)
+ movq %rax, MCOUNT_REG_SIZE(%rsp)
/* Handlers can change the RIP */
movq RIP(%rsp), %rax
- movq %rax, SS+8(%rsp)
+ movq %rax, MCOUNT_REG_SIZE+8(%rsp)
/* restore the rest of pt_regs */
movq R15(%rsp), %r15
@@ -113,19 +236,22 @@ GLOBAL(ftrace_regs_call)
movq R13(%rsp), %r13
movq R12(%rsp), %r12
movq R10(%rsp), %r10
- movq RBP(%rsp), %rbp
movq RBX(%rsp), %rbx
- /* skip=8 to skip flags saved in SS */
- MCOUNT_RESTORE_FRAME 8
+ restore_mcount_regs
/* Restore flags */
popfq
- jmp ftrace_return
+ /*
+ * As this jmp to ftrace_return can be a short jump
+ * it must not be copied into the trampoline.
+ * The trampoline will add the code to jump
+ * to the return.
+ */
+GLOBAL(ftrace_regs_caller_end)
- popfq
- jmp ftrace_stub
+ jmp ftrace_return
END(ftrace_regs_caller)
@@ -136,6 +262,7 @@ ENTRY(function_hook)
cmpq $ftrace_stub, ftrace_trace_function
jnz trace
+fgraph_trace:
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
cmpq $ftrace_stub, ftrace_graph_return
jnz ftrace_graph_caller
@@ -148,42 +275,35 @@ GLOBAL(ftrace_stub)
retq
trace:
- MCOUNT_SAVE_FRAME
-
- movq RIP(%rsp), %rdi
-#ifdef CC_USING_FENTRY
- movq SS+16(%rsp), %rsi
-#else
- movq 8(%rbp), %rsi
-#endif
- subq $MCOUNT_INSN_SIZE, %rdi
+ /* save_mcount_regs fills in first two parameters */
+ save_mcount_regs
call *ftrace_trace_function
- MCOUNT_RESTORE_FRAME
+ restore_mcount_regs
- jmp ftrace_stub
+ jmp fgraph_trace
END(function_hook)
#endif /* CONFIG_DYNAMIC_FTRACE */
#endif /* CONFIG_FUNCTION_TRACER */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
ENTRY(ftrace_graph_caller)
- MCOUNT_SAVE_FRAME
+ /* Saves rbp into %rdx and fills first parameter */
+ save_mcount_regs
#ifdef CC_USING_FENTRY
- leaq SS+16(%rsp), %rdi
+ leaq MCOUNT_REG_SIZE+8(%rsp), %rsi
movq $0, %rdx /* No framepointers needed */
#else
- leaq 8(%rbp), %rdi
- movq (%rbp), %rdx
+ /* Save address of the return address of traced function */
+ leaq 8(%rdx), %rsi
+ /* ftrace does sanity checks against frame pointers */
+ movq (%rdx), %rdx
#endif
- movq RIP(%rsp), %rsi
- subq $MCOUNT_INSN_SIZE, %rsi
-
call prepare_ftrace_return
- MCOUNT_RESTORE_FRAME
+ restore_mcount_regs
retq
END(ftrace_graph_caller)
diff --git a/arch/x86/kernel/msr.c b/arch/x86/kernel/msr.c
index c9603ac..113e707 100644
--- a/arch/x86/kernel/msr.c
+++ b/arch/x86/kernel/msr.c
@@ -22,6 +22,8 @@
* an SMP box will direct the access to CPU %d.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/types.h>
@@ -50,11 +52,11 @@ static loff_t msr_seek(struct file *file, loff_t offset, int orig)
mutex_lock(&inode->i_mutex);
switch (orig) {
- case 0:
+ case SEEK_SET:
file->f_pos = offset;
ret = file->f_pos;
break;
- case 1:
+ case SEEK_CUR:
file->f_pos += offset;
ret = file->f_pos;
break;
@@ -206,7 +208,7 @@ static int msr_device_create(int cpu)
dev = device_create(msr_class, NULL, MKDEV(MSR_MAJOR, cpu), NULL,
"msr%d", cpu);
- return IS_ERR(dev) ? PTR_ERR(dev) : 0;
+ return PTR_ERR_OR_ZERO(dev);
}
static void msr_device_destroy(int cpu)
@@ -248,8 +250,7 @@ static int __init msr_init(void)
i = 0;
if (__register_chrdev(MSR_MAJOR, 0, NR_CPUS, "cpu/msr", &msr_fops)) {
- printk(KERN_ERR "msr: unable to get major %d for msr\n",
- MSR_MAJOR);
+ pr_err("unable to get major %d for msr\n", MSR_MAJOR);
err = -EBUSY;
goto out;
}
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index ab08aa2..ab4734e 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -960,6 +960,8 @@ void __init setup_arch(char **cmdline_p)
init_mm.end_data = (unsigned long) _edata;
init_mm.brk = _brk_end;
+ mpx_mm_init(&init_mm);
+
code_resource.start = __pa_symbol(_text);
code_resource.end = __pa_symbol(_etext)-1;
data_resource.start = __pa_symbol(_etext);
@@ -1190,9 +1192,7 @@ void __init setup_arch(char **cmdline_p)
tboot_probe();
-#ifdef CONFIG_X86_64
map_vsyscall();
-#endif
generic_apic_probe();
diff --git a/arch/x86/kernel/setup_percpu.c b/arch/x86/kernel/setup_percpu.c
index 5cdff03..e4fcb87 100644
--- a/arch/x86/kernel/setup_percpu.c
+++ b/arch/x86/kernel/setup_percpu.c
@@ -30,7 +30,7 @@ EXPORT_PER_CPU_SYMBOL(cpu_number);
#define BOOT_PERCPU_OFFSET 0
#endif
-DEFINE_PER_CPU(unsigned long, this_cpu_off) = BOOT_PERCPU_OFFSET;
+DEFINE_PER_CPU_READ_MOSTLY(unsigned long, this_cpu_off) = BOOT_PERCPU_OFFSET;
EXPORT_PER_CPU_SYMBOL(this_cpu_off);
unsigned long __per_cpu_offset[NR_CPUS] __read_mostly = {
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
index 668d8f2..7a8f584 100644
--- a/arch/x86/kernel/smpboot.c
+++ b/arch/x86/kernel/smpboot.c
@@ -99,7 +99,7 @@ EXPORT_PER_CPU_SYMBOL(cpu_core_map);
DEFINE_PER_CPU_READ_MOSTLY(cpumask_var_t, cpu_llc_shared_map);
/* Per CPU bogomips and other parameters */
-DEFINE_PER_CPU_SHARED_ALIGNED(struct cpuinfo_x86, cpu_info);
+DEFINE_PER_CPU_READ_MOSTLY(struct cpuinfo_x86, cpu_info);
EXPORT_PER_CPU_SYMBOL(cpu_info);
atomic_t init_deasserted;
diff --git a/arch/x86/kernel/sysfb.c b/arch/x86/kernel/sysfb.c
index 193ec2c..160386e 100644
--- a/arch/x86/kernel/sysfb.c
+++ b/arch/x86/kernel/sysfb.c
@@ -67,7 +67,7 @@ static __init int sysfb_init(void)
pd = platform_device_register_resndata(NULL, name, 0,
NULL, 0, si, sizeof(*si));
- return IS_ERR(pd) ? PTR_ERR(pd) : 0;
+ return PTR_ERR_OR_ZERO(pd);
}
/* must execute after PCI subsystem for EFI quirks */
diff --git a/arch/x86/kernel/sysfb_simplefb.c b/arch/x86/kernel/sysfb_simplefb.c
index 86179d4..764a29f 100644
--- a/arch/x86/kernel/sysfb_simplefb.c
+++ b/arch/x86/kernel/sysfb_simplefb.c
@@ -88,8 +88,5 @@ __init int create_simplefb(const struct screen_info *si,
pd = platform_device_register_resndata(NULL, "simple-framebuffer", 0,
&res, 1, mode, sizeof(*mode));
- if (IS_ERR(pd))
- return PTR_ERR(pd);
-
- return 0;
+ return PTR_ERR_OR_ZERO(pd);
}
diff --git a/arch/x86/kernel/time.c b/arch/x86/kernel/time.c
index 0fa2960..25adc0e 100644
--- a/arch/x86/kernel/time.c
+++ b/arch/x86/kernel/time.c
@@ -23,7 +23,7 @@
#include <asm/time.h>
#ifdef CONFIG_X86_64
-__visible DEFINE_VVAR(volatile unsigned long, jiffies) = INITIAL_JIFFIES;
+__visible volatile unsigned long jiffies __cacheline_aligned = INITIAL_JIFFIES;
#endif
unsigned long profile_pc(struct pt_regs *regs)
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index de801f2..a9ae205 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -60,6 +60,7 @@
#include <asm/fixmap.h>
#include <asm/mach_traps.h>
#include <asm/alternative.h>
+#include <asm/mpx.h>
#ifdef CONFIG_X86_64
#include <asm/x86_init.h>
@@ -228,7 +229,6 @@ dotraplinkage void do_##name(struct pt_regs *regs, long error_code) \
DO_ERROR(X86_TRAP_DE, SIGFPE, "divide error", divide_error)
DO_ERROR(X86_TRAP_OF, SIGSEGV, "overflow", overflow)
-DO_ERROR(X86_TRAP_BR, SIGSEGV, "bounds", bounds)
DO_ERROR(X86_TRAP_UD, SIGILL, "invalid opcode", invalid_op)
DO_ERROR(X86_TRAP_OLD_MF, SIGFPE, "coprocessor segment overrun",coprocessor_segment_overrun)
DO_ERROR(X86_TRAP_TS, SIGSEGV, "invalid TSS", invalid_TSS)
@@ -286,6 +286,89 @@ dotraplinkage void do_double_fault(struct pt_regs *regs, long error_code)
}
#endif
+dotraplinkage void do_bounds(struct pt_regs *regs, long error_code)
+{
+ struct task_struct *tsk = current;
+ struct xsave_struct *xsave_buf;
+ enum ctx_state prev_state;
+ struct bndcsr *bndcsr;
+ siginfo_t *info;
+
+ prev_state = exception_enter();
+ if (notify_die(DIE_TRAP, "bounds", regs, error_code,
+ X86_TRAP_BR, SIGSEGV) == NOTIFY_STOP)
+ goto exit;
+ conditional_sti(regs);
+
+ if (!user_mode(regs))
+ die("bounds", regs, error_code);
+
+ if (!cpu_feature_enabled(X86_FEATURE_MPX)) {
+ /* The exception is not from Intel MPX */
+ goto exit_trap;
+ }
+
+ /*
+ * We need to look at BNDSTATUS to resolve this exception.
+ * It is not directly accessible, though, so we need to
+ * do an xsave and then pull it out of the xsave buffer.
+ */
+ fpu_save_init(&tsk->thread.fpu);
+ xsave_buf = &(tsk->thread.fpu.state->xsave);
+ bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
+ if (!bndcsr)
+ goto exit_trap;
+
+ /*
+ * The error code field of the BNDSTATUS register communicates status
+ * information of a bound range exception #BR or operation involving
+ * bound directory.
+ */
+ switch (bndcsr->bndstatus & MPX_BNDSTA_ERROR_CODE) {
+ case 2: /* Bound directory has invalid entry. */
+ if (mpx_handle_bd_fault(xsave_buf))
+ goto exit_trap;
+ break; /* Success, it was handled */
+ case 1: /* Bound violation. */
+ info = mpx_generate_siginfo(regs, xsave_buf);
+ if (PTR_ERR(info)) {
+ /*
+ * We failed to decode the MPX instruction. Act as if
+ * the exception was not caused by MPX.
+ */
+ goto exit_trap;
+ }
+ /*
+ * Success, we decoded the instruction and retrieved
+ * an 'info' containing the address being accessed
+ * which caused the exception. This information
+ * allows and application to possibly handle the
+ * #BR exception itself.
+ */
+ do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, info);
+ kfree(info);
+ break;
+ case 0: /* No exception caused by Intel MPX operations. */
+ goto exit_trap;
+ default:
+ die("bounds", regs, error_code);
+ }
+
+exit:
+ exception_exit(prev_state);
+ return;
+exit_trap:
+ /*
+ * This path out is for all the cases where we could not
+ * handle the exception in some way (like allocating a
+ * table or telling userspace about it. We will also end
+ * up here if the kernel has MPX turned off at compile
+ * time..
+ */
+ do_trap(X86_TRAP_BR, SIGSEGV, "bounds", regs, error_code, NULL);
+ exception_exit(prev_state);
+}
+
dotraplinkage void
do_general_protection(struct pt_regs *regs, long error_code)
{
@@ -387,7 +470,7 @@ NOKPROBE_SYMBOL(do_int3);
* for scheduling or signal handling. The actual stack switch is done in
* entry.S
*/
-asmlinkage __visible struct pt_regs *sync_regs(struct pt_regs *eregs)
+asmlinkage __visible notrace struct pt_regs *sync_regs(struct pt_regs *eregs)
{
struct pt_regs *regs = eregs;
/* Did already sync */
@@ -413,7 +496,7 @@ struct bad_iret_stack {
struct pt_regs regs;
};
-asmlinkage __visible
+asmlinkage __visible notrace
struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
{
/*
@@ -436,6 +519,7 @@ struct bad_iret_stack *fixup_bad_iret(struct bad_iret_stack *s)
BUG_ON(!user_mode_vm(&new_stack->regs));
return new_stack;
}
+NOKPROBE_SYMBOL(fixup_bad_iret);
#endif
/*
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 5d1cbfe..8b96a94 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -219,7 +219,7 @@ static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool
{
u32 volatile *good_insns;
- insn_init(insn, auprobe->insn, x86_64);
+ insn_init(insn, auprobe->insn, sizeof(auprobe->insn), x86_64);
/* has the side-effect of processing the entire instruction */
insn_get_length(insn);
if (WARN_ON_ONCE(!insn_complete(insn)))
diff --git a/arch/x86/kernel/vmlinux.lds.S b/arch/x86/kernel/vmlinux.lds.S
index 49edf2d..00bf300 100644
--- a/arch/x86/kernel/vmlinux.lds.S
+++ b/arch/x86/kernel/vmlinux.lds.S
@@ -186,6 +186,8 @@ SECTIONS
* start another segment - init.
*/
PERCPU_VADDR(INTERNODE_CACHE_BYTES, 0, :percpu)
+ ASSERT(SIZEOF(.data..percpu) < CONFIG_PHYSICAL_START,
+ "per-CPU data too large - increase CONFIG_PHYSICAL_START")
#endif
INIT_TEXT_SECTION(PAGE_SIZE)
diff --git a/arch/x86/kernel/vsyscall_64.c b/arch/x86/kernel/vsyscall_64.c
index 957779f..2dcc6ff 100644
--- a/arch/x86/kernel/vsyscall_64.c
+++ b/arch/x86/kernel/vsyscall_64.c
@@ -1,59 +1,43 @@
/*
+ * Copyright (c) 2012-2014 Andy Lutomirski <luto@amacapital.net>
+ *
+ * Based on the original implementation which is:
* Copyright (C) 2001 Andrea Arcangeli <andrea@suse.de> SuSE
* Copyright 2003 Andi Kleen, SuSE Labs.
*
- * [ NOTE: this mechanism is now deprecated in favor of the vDSO. ]
+ * Parts of the original code have been moved to arch/x86/vdso/vma.c
+ *
+ * This file implements vsyscall emulation. vsyscalls are a legacy ABI:
+ * Userspace can request certain kernel services by calling fixed
+ * addresses. This concept is problematic:
*
- * Thanks to hpa@transmeta.com for some useful hint.
- * Special thanks to Ingo Molnar for his early experience with
- * a different vsyscall implementation for Linux/IA32 and for the name.
+ * - It interferes with ASLR.
+ * - It's awkward to write code that lives in kernel addresses but is
+ * callable by userspace at fixed addresses.
+ * - The whole concept is impossible for 32-bit compat userspace.
+ * - UML cannot easily virtualize a vsyscall.
*
- * vsyscall 1 is located at -10Mbyte, vsyscall 2 is located
- * at virtual address -10Mbyte+1024bytes etc... There are at max 4
- * vsyscalls. One vsyscall can reserve more than 1 slot to avoid
- * jumping out of line if necessary. We cannot add more with this
- * mechanism because older kernels won't return -ENOSYS.
+ * As of mid-2014, I believe that there is no new userspace code that
+ * will use a vsyscall if the vDSO is present. I hope that there will
+ * soon be no new userspace code that will ever use a vsyscall.
*
- * Note: the concept clashes with user mode linux. UML users should
- * use the vDSO.
+ * The code in this file emulates vsyscalls when notified of a page
+ * fault to a vsyscall address.
*/
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
-#include <linux/time.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/timer.h>
-#include <linux/seqlock.h>
-#include <linux/jiffies.h>
-#include <linux/sysctl.h>
-#include <linux/topology.h>
-#include <linux/timekeeper_internal.h>
-#include <linux/getcpu.h>
-#include <linux/cpu.h>
-#include <linux/smp.h>
-#include <linux/notifier.h>
#include <linux/syscalls.h>
#include <linux/ratelimit.h>
#include <asm/vsyscall.h>
-#include <asm/pgtable.h>
-#include <asm/compat.h>
-#include <asm/page.h>
#include <asm/unistd.h>
#include <asm/fixmap.h>
-#include <asm/errno.h>
-#include <asm/io.h>
-#include <asm/segment.h>
-#include <asm/desc.h>
-#include <asm/topology.h>
#include <asm/traps.h>
#define CREATE_TRACE_POINTS
#include "vsyscall_trace.h"
-DEFINE_VVAR(int, vgetcpu_mode);
-
static enum { EMULATE, NATIVE, NONE } vsyscall_mode = EMULATE;
static int __init vsyscall_setup(char *str)
@@ -222,6 +206,7 @@ bool emulate_vsyscall(struct pt_regs *regs, unsigned long address)
"seccomp tried to change syscall nr or ip");
do_exit(SIGSYS);
}
+ regs->orig_ax = -1;
if (tmp)
goto do_ret; /* skip requested */
@@ -284,46 +269,54 @@ sigsegv:
}
/*
- * Assume __initcall executes before all user space. Hopefully kmod
- * doesn't violate that. We'll find out if it does.
+ * A pseudo VMA to allow ptrace access for the vsyscall page. This only
+ * covers the 64bit vsyscall page now. 32bit has a real VMA now and does
+ * not need special handling anymore:
*/
-static void vsyscall_set_cpu(int cpu)
+static const char *gate_vma_name(struct vm_area_struct *vma)
{
- unsigned long d;
- unsigned long node = 0;
-#ifdef CONFIG_NUMA
- node = cpu_to_node(cpu);
-#endif
- if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP))
- write_rdtscp_aux((node << 12) | cpu);
-
- /*
- * Store cpu number in limit so that it can be loaded quickly
- * in user space in vgetcpu. (12 bits for the CPU and 8 bits for the node)
- */
- d = 0x0f40000000000ULL;
- d |= cpu;
- d |= (node & 0xf) << 12;
- d |= (node >> 4) << 48;
-
- write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S);
+ return "[vsyscall]";
}
-
-static void cpu_vsyscall_init(void *arg)
+static struct vm_operations_struct gate_vma_ops = {
+ .name = gate_vma_name,
+};
+static struct vm_area_struct gate_vma = {
+ .vm_start = VSYSCALL_ADDR,
+ .vm_end = VSYSCALL_ADDR + PAGE_SIZE,
+ .vm_page_prot = PAGE_READONLY_EXEC,
+ .vm_flags = VM_READ | VM_EXEC,
+ .vm_ops = &gate_vma_ops,
+};
+
+struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
{
- /* preemption should be already off */
- vsyscall_set_cpu(raw_smp_processor_id());
+#ifdef CONFIG_IA32_EMULATION
+ if (!mm || mm->context.ia32_compat)
+ return NULL;
+#endif
+ if (vsyscall_mode == NONE)
+ return NULL;
+ return &gate_vma;
}
-static int
-cpu_vsyscall_notifier(struct notifier_block *n, unsigned long action, void *arg)
+int in_gate_area(struct mm_struct *mm, unsigned long addr)
{
- long cpu = (long)arg;
+ struct vm_area_struct *vma = get_gate_vma(mm);
+
+ if (!vma)
+ return 0;
- if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
- smp_call_function_single(cpu, cpu_vsyscall_init, NULL, 1);
+ return (addr >= vma->vm_start) && (addr < vma->vm_end);
+}
- return NOTIFY_DONE;
+/*
+ * Use this when you have no reliable mm, typically from interrupt
+ * context. It is less reliable than using a task's mm and may give
+ * false positives.
+ */
+int in_gate_area_no_mm(unsigned long addr)
+{
+ return vsyscall_mode != NONE && (addr & PAGE_MASK) == VSYSCALL_ADDR;
}
void __init map_vsyscall(void)
@@ -331,24 +324,12 @@ void __init map_vsyscall(void)
extern char __vsyscall_page;
unsigned long physaddr_vsyscall = __pa_symbol(&__vsyscall_page);
- __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
- vsyscall_mode == NATIVE
- ? PAGE_KERNEL_VSYSCALL
- : PAGE_KERNEL_VVAR);
+ if (vsyscall_mode != NONE)
+ __set_fixmap(VSYSCALL_PAGE, physaddr_vsyscall,
+ vsyscall_mode == NATIVE
+ ? PAGE_KERNEL_VSYSCALL
+ : PAGE_KERNEL_VVAR);
+
BUILD_BUG_ON((unsigned long)__fix_to_virt(VSYSCALL_PAGE) !=
(unsigned long)VSYSCALL_ADDR);
}
-
-static int __init vsyscall_init(void)
-{
- cpu_notifier_register_begin();
-
- on_each_cpu(cpu_vsyscall_init, NULL, 1);
- /* notifier priority > KVM */
- __hotcpu_notifier(cpu_vsyscall_notifier, 30);
-
- cpu_notifier_register_done();
-
- return 0;
-}
-__initcall(vsyscall_init);
diff --git a/arch/x86/kernel/x86_init.c b/arch/x86/kernel/x86_init.c
index e48b674..234b072 100644
--- a/arch/x86/kernel/x86_init.c
+++ b/arch/x86/kernel/x86_init.c
@@ -116,8 +116,6 @@ struct x86_msi_ops x86_msi = {
.teardown_msi_irqs = default_teardown_msi_irqs,
.restore_msi_irqs = default_restore_msi_irqs,
.setup_hpet_msi = default_setup_hpet_msi,
- .msi_mask_irq = default_msi_mask_irq,
- .msix_mask_irq = default_msix_mask_irq,
};
/* MSI arch specific hooks */
@@ -140,14 +138,6 @@ void arch_restore_msi_irqs(struct pci_dev *dev)
{
x86_msi.restore_msi_irqs(dev);
}
-u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
-{
- return x86_msi.msi_mask_irq(desc, mask, flag);
-}
-u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
-{
- return x86_msi.msix_mask_irq(desc, flag);
-}
#endif
struct x86_io_apic_ops x86_io_apic_ops = {
diff --git a/arch/x86/kvm/mmutrace.h b/arch/x86/kvm/mmutrace.h
index 5aaf356..ce463a9 100644
--- a/arch/x86/kvm/mmutrace.h
+++ b/arch/x86/kvm/mmutrace.h
@@ -22,7 +22,7 @@
__entry->unsync = sp->unsync;
#define KVM_MMU_PAGE_PRINTK() ({ \
- const u32 saved_len = p->len; \
+ const char *saved_ptr = trace_seq_buffer_ptr(p); \
static const char *access_str[] = { \
"---", "--x", "w--", "w-x", "-u-", "-ux", "wu-", "wux" \
}; \
@@ -41,7 +41,7 @@
role.nxe ? "" : "!", \
__entry->root_count, \
__entry->unsync ? "unsync" : "sync", 0); \
- p->buffer + saved_len; \
+ saved_ptr; \
})
#define kvm_mmu_trace_pferr_flags \
diff --git a/arch/x86/lib/insn.c b/arch/x86/lib/insn.c
index 54fcffe..2480978b 100644
--- a/arch/x86/lib/insn.c
+++ b/arch/x86/lib/insn.c
@@ -28,7 +28,7 @@
/* Verify next sizeof(t) bytes can be on the same instruction */
#define validate_next(t, insn, n) \
- ((insn)->next_byte + sizeof(t) + n - (insn)->kaddr <= MAX_INSN_SIZE)
+ ((insn)->next_byte + sizeof(t) + n < (insn)->end_kaddr)
#define __get_next(t, insn) \
({ t r = *(t*)insn->next_byte; insn->next_byte += sizeof(t); r; })
@@ -50,10 +50,11 @@
* @kaddr: address (in kernel memory) of instruction (or copy thereof)
* @x86_64: !0 for 64-bit kernel or 64-bit app
*/
-void insn_init(struct insn *insn, const void *kaddr, int x86_64)
+void insn_init(struct insn *insn, const void *kaddr, int buf_len, int x86_64)
{
memset(insn, 0, sizeof(*insn));
insn->kaddr = kaddr;
+ insn->end_kaddr = kaddr + buf_len;
insn->next_byte = kaddr;
insn->x86_64 = x86_64 ? 1 : 0;
insn->opnd_bytes = 4;
diff --git a/arch/x86/mm/Makefile b/arch/x86/mm/Makefile
index 6a19ad9..ecfdc46 100644
--- a/arch/x86/mm/Makefile
+++ b/arch/x86/mm/Makefile
@@ -30,3 +30,5 @@ obj-$(CONFIG_ACPI_NUMA) += srat.o
obj-$(CONFIG_NUMA_EMU) += numa_emulation.o
obj-$(CONFIG_MEMTEST) += memtest.o
+
+obj-$(CONFIG_X86_INTEL_MPX) += mpx.o
diff --git a/arch/x86/mm/dump_pagetables.c b/arch/x86/mm/dump_pagetables.c
index 95a427e..f0cedf3 100644
--- a/arch/x86/mm/dump_pagetables.c
+++ b/arch/x86/mm/dump_pagetables.c
@@ -76,6 +76,9 @@ static struct addr_marker address_markers[] = {
# ifdef CONFIG_X86_ESPFIX64
{ ESPFIX_BASE_ADDR, "ESPfix Area", 16 },
# endif
+# ifdef CONFIG_EFI
+ { EFI_VA_END, "EFI Runtime Services" },
+# endif
{ __START_KERNEL_map, "High Kernel Mapping" },
{ MODULES_VADDR, "Modules" },
{ MODULES_END, "End Modules" },
@@ -126,7 +129,7 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
if (!pgprot_val(prot)) {
/* Not present */
- pt_dump_cont_printf(m, dmsg, " ");
+ pt_dump_cont_printf(m, dmsg, " ");
} else {
if (pr & _PAGE_USER)
pt_dump_cont_printf(m, dmsg, "USR ");
@@ -145,18 +148,16 @@ static void printk_prot(struct seq_file *m, pgprot_t prot, int level, bool dmsg)
else
pt_dump_cont_printf(m, dmsg, " ");
- /* Bit 9 has a different meaning on level 3 vs 4 */
- if (level <= 3) {
- if (pr & _PAGE_PSE)
- pt_dump_cont_printf(m, dmsg, "PSE ");
- else
- pt_dump_cont_printf(m, dmsg, " ");
- } else {
- if (pr & _PAGE_PAT)
- pt_dump_cont_printf(m, dmsg, "pat ");
- else
- pt_dump_cont_printf(m, dmsg, " ");
- }
+ /* Bit 7 has a different meaning on level 3 vs 4 */
+ if (level <= 3 && pr & _PAGE_PSE)
+ pt_dump_cont_printf(m, dmsg, "PSE ");
+ else
+ pt_dump_cont_printf(m, dmsg, " ");
+ if ((level == 4 && pr & _PAGE_PAT) ||
+ ((level == 3 || level == 2) && pr & _PAGE_PAT_LARGE))
+ pt_dump_cont_printf(m, dmsg, "pat ");
+ else
+ pt_dump_cont_printf(m, dmsg, " ");
if (pr & _PAGE_GLOBAL)
pt_dump_cont_printf(m, dmsg, "GLB ");
else
diff --git a/arch/x86/mm/init.c b/arch/x86/mm/init.c
index 66dba36..82b41d5 100644
--- a/arch/x86/mm/init.c
+++ b/arch/x86/mm/init.c
@@ -27,6 +27,35 @@
#include "mm_internal.h"
+/*
+ * Tables translating between page_cache_type_t and pte encoding.
+ * Minimal supported modes are defined statically, modified if more supported
+ * cache modes are available.
+ * Index into __cachemode2pte_tbl is the cachemode.
+ * Index into __pte2cachemode_tbl are the caching attribute bits of the pte
+ * (_PAGE_PWT, _PAGE_PCD, _PAGE_PAT) at index bit positions 0, 1, 2.
+ */
+uint16_t __cachemode2pte_tbl[_PAGE_CACHE_MODE_NUM] = {
+ [_PAGE_CACHE_MODE_WB] = 0,
+ [_PAGE_CACHE_MODE_WC] = _PAGE_PWT,
+ [_PAGE_CACHE_MODE_UC_MINUS] = _PAGE_PCD,
+ [_PAGE_CACHE_MODE_UC] = _PAGE_PCD | _PAGE_PWT,
+ [_PAGE_CACHE_MODE_WT] = _PAGE_PCD,
+ [_PAGE_CACHE_MODE_WP] = _PAGE_PCD,
+};
+EXPORT_SYMBOL_GPL(__cachemode2pte_tbl);
+uint8_t __pte2cachemode_tbl[8] = {
+ [__pte2cm_idx(0)] = _PAGE_CACHE_MODE_WB,
+ [__pte2cm_idx(_PAGE_PWT)] = _PAGE_CACHE_MODE_WC,
+ [__pte2cm_idx(_PAGE_PCD)] = _PAGE_CACHE_MODE_UC_MINUS,
+ [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD)] = _PAGE_CACHE_MODE_UC,
+ [__pte2cm_idx(_PAGE_PAT)] = _PAGE_CACHE_MODE_WB,
+ [__pte2cm_idx(_PAGE_PWT | _PAGE_PAT)] = _PAGE_CACHE_MODE_WC,
+ [__pte2cm_idx(_PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC_MINUS,
+ [__pte2cm_idx(_PAGE_PWT | _PAGE_PCD | _PAGE_PAT)] = _PAGE_CACHE_MODE_UC,
+};
+EXPORT_SYMBOL_GPL(__pte2cachemode_tbl);
+
static unsigned long __initdata pgt_buf_start;
static unsigned long __initdata pgt_buf_end;
static unsigned long __initdata pgt_buf_top;
@@ -687,3 +716,11 @@ void __init zone_sizes_init(void)
free_area_init_nodes(max_zone_pfns);
}
+void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache)
+{
+ /* entry 0 MUST be WB (hardwired to speed up translations) */
+ BUG_ON(!entry && cache != _PAGE_CACHE_MODE_WB);
+
+ __cachemode2pte_tbl[cache] = __cm_idx2pte(entry);
+ __pte2cachemode_tbl[entry] = cache;
+}
diff --git a/arch/x86/mm/init_64.c b/arch/x86/mm/init_64.c
index 4e5dfec..30eb05a 100644
--- a/arch/x86/mm/init_64.c
+++ b/arch/x86/mm/init_64.c
@@ -52,7 +52,6 @@
#include <asm/numa.h>
#include <asm/cacheflush.h>
#include <asm/init.h>
-#include <asm/uv/uv.h>
#include <asm/setup.h>
#include "mm_internal.h"
@@ -338,12 +337,15 @@ pte_t * __init populate_extra_pte(unsigned long vaddr)
* Create large page table mappings for a range of physical addresses.
*/
static void __init __init_extra_mapping(unsigned long phys, unsigned long size,
- pgprot_t prot)
+ enum page_cache_mode cache)
{
pgd_t *pgd;
pud_t *pud;
pmd_t *pmd;
+ pgprot_t prot;
+ pgprot_val(prot) = pgprot_val(PAGE_KERNEL_LARGE) |
+ pgprot_val(pgprot_4k_2_large(cachemode2pgprot(cache)));
BUG_ON((phys & ~PMD_MASK) || (size & ~PMD_MASK));
for (; size; phys += PMD_SIZE, size -= PMD_SIZE) {
pgd = pgd_offset_k((unsigned long)__va(phys));
@@ -366,12 +368,12 @@ static void __init __init_extra_mapping(unsigned long phys, unsigned long size,
void __init init_extra_mapping_wb(unsigned long phys, unsigned long size)
{
- __init_extra_mapping(phys, size, PAGE_KERNEL_LARGE);
+ __init_extra_mapping(phys, size, _PAGE_CACHE_MODE_WB);
}
void __init init_extra_mapping_uc(unsigned long phys, unsigned long size)
{
- __init_extra_mapping(phys, size, PAGE_KERNEL_LARGE_NOCACHE);
+ __init_extra_mapping(phys, size, _PAGE_CACHE_MODE_UC);
}
/*
@@ -1202,66 +1204,15 @@ int kern_addr_valid(unsigned long addr)
return pfn_valid(pte_pfn(*pte));
}
-/*
- * A pseudo VMA to allow ptrace access for the vsyscall page. This only
- * covers the 64bit vsyscall page now. 32bit has a real VMA now and does
- * not need special handling anymore:
- */
-static const char *gate_vma_name(struct vm_area_struct *vma)
-{
- return "[vsyscall]";
-}
-static struct vm_operations_struct gate_vma_ops = {
- .name = gate_vma_name,
-};
-static struct vm_area_struct gate_vma = {
- .vm_start = VSYSCALL_ADDR,
- .vm_end = VSYSCALL_ADDR + PAGE_SIZE,
- .vm_page_prot = PAGE_READONLY_EXEC,
- .vm_flags = VM_READ | VM_EXEC,
- .vm_ops = &gate_vma_ops,
-};
-
-struct vm_area_struct *get_gate_vma(struct mm_struct *mm)
-{
-#ifdef CONFIG_IA32_EMULATION
- if (!mm || mm->context.ia32_compat)
- return NULL;
-#endif
- return &gate_vma;
-}
-
-int in_gate_area(struct mm_struct *mm, unsigned long addr)
-{
- struct vm_area_struct *vma = get_gate_vma(mm);
-
- if (!vma)
- return 0;
-
- return (addr >= vma->vm_start) && (addr < vma->vm_end);
-}
-
-/*
- * Use this when you have no reliable mm, typically from interrupt
- * context. It is less reliable than using a task's mm and may give
- * false positives.
- */
-int in_gate_area_no_mm(unsigned long addr)
-{
- return (addr & PAGE_MASK) == VSYSCALL_ADDR;
-}
-
static unsigned long probe_memory_block_size(void)
{
/* start from 2g */
unsigned long bz = 1UL<<31;
-#ifdef CONFIG_X86_UV
- if (is_uv_system()) {
- printk(KERN_INFO "UV: memory block size 2GB\n");
+ if (totalram_pages >= (64ULL << (30 - PAGE_SHIFT))) {
+ pr_info("Using 2GB memory block size for large-memory system\n");
return 2UL * 1024 * 1024 * 1024;
}
-#endif
/* less than 64g installed */
if ((max_pfn << PAGE_SHIFT) < (16UL << 32))
diff --git a/arch/x86/mm/iomap_32.c b/arch/x86/mm/iomap_32.c
index 7b179b49..9ca35fc 100644
--- a/arch/x86/mm/iomap_32.c
+++ b/arch/x86/mm/iomap_32.c
@@ -33,17 +33,17 @@ static int is_io_mapping_possible(resource_size_t base, unsigned long size)
int iomap_create_wc(resource_size_t base, unsigned long size, pgprot_t *prot)
{
- unsigned long flag = _PAGE_CACHE_WC;
+ enum page_cache_mode pcm = _PAGE_CACHE_MODE_WC;
int ret;
if (!is_io_mapping_possible(base, size))
return -EINVAL;
- ret = io_reserve_memtype(base, base + size, &flag);
+ ret = io_reserve_memtype(base, base + size, &pcm);
if (ret)
return ret;
- *prot = __pgprot(__PAGE_KERNEL | flag);
+ *prot = __pgprot(__PAGE_KERNEL | cachemode2protval(pcm));
return 0;
}
EXPORT_SYMBOL_GPL(iomap_create_wc);
@@ -82,8 +82,10 @@ iomap_atomic_prot_pfn(unsigned long pfn, pgprot_t prot)
* MTRR is UC or WC. UC_MINUS gets the real intention, of the
* user, which is "WC if the MTRR is WC, UC if you can't do that."
*/
- if (!pat_enabled && pgprot_val(prot) == pgprot_val(PAGE_KERNEL_WC))
- prot = PAGE_KERNEL_UC_MINUS;
+ if (!pat_enabled && pgprot_val(prot) ==
+ (__PAGE_KERNEL | cachemode2protval(_PAGE_CACHE_MODE_WC)))
+ prot = __pgprot(__PAGE_KERNEL |
+ cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS));
return (void __force __iomem *) kmap_atomic_prot_pfn(pfn, prot);
}
diff --git a/arch/x86/mm/ioremap.c b/arch/x86/mm/ioremap.c
index af78e50..fdf617c 100644
--- a/arch/x86/mm/ioremap.c
+++ b/arch/x86/mm/ioremap.c
@@ -29,20 +29,20 @@
* conflicts.
*/
int ioremap_change_attr(unsigned long vaddr, unsigned long size,
- unsigned long prot_val)
+ enum page_cache_mode pcm)
{
unsigned long nrpages = size >> PAGE_SHIFT;
int err;
- switch (prot_val) {
- case _PAGE_CACHE_UC:
+ switch (pcm) {
+ case _PAGE_CACHE_MODE_UC:
default:
err = _set_memory_uc(vaddr, nrpages);
break;
- case _PAGE_CACHE_WC:
+ case _PAGE_CACHE_MODE_WC:
err = _set_memory_wc(vaddr, nrpages);
break;
- case _PAGE_CACHE_WB:
+ case _PAGE_CACHE_MODE_WB:
err = _set_memory_wb(vaddr, nrpages);
break;
}
@@ -75,14 +75,14 @@ static int __ioremap_check_ram(unsigned long start_pfn, unsigned long nr_pages,
* caller shouldn't need to know that small detail.
*/
static void __iomem *__ioremap_caller(resource_size_t phys_addr,
- unsigned long size, unsigned long prot_val, void *caller)
+ unsigned long size, enum page_cache_mode pcm, void *caller)
{
unsigned long offset, vaddr;
resource_size_t pfn, last_pfn, last_addr;
const resource_size_t unaligned_phys_addr = phys_addr;
const unsigned long unaligned_size = size;
struct vm_struct *area;
- unsigned long new_prot_val;
+ enum page_cache_mode new_pcm;
pgprot_t prot;
int retval;
void __iomem *ret_addr;
@@ -134,38 +134,40 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
size = PAGE_ALIGN(last_addr+1) - phys_addr;
retval = reserve_memtype(phys_addr, (u64)phys_addr + size,
- prot_val, &new_prot_val);
+ pcm, &new_pcm);
if (retval) {
printk(KERN_ERR "ioremap reserve_memtype failed %d\n", retval);
return NULL;
}
- if (prot_val != new_prot_val) {
- if (!is_new_memtype_allowed(phys_addr, size,
- prot_val, new_prot_val)) {
+ if (pcm != new_pcm) {
+ if (!is_new_memtype_allowed(phys_addr, size, pcm, new_pcm)) {
printk(KERN_ERR
- "ioremap error for 0x%llx-0x%llx, requested 0x%lx, got 0x%lx\n",
+ "ioremap error for 0x%llx-0x%llx, requested 0x%x, got 0x%x\n",
(unsigned long long)phys_addr,
(unsigned long long)(phys_addr + size),
- prot_val, new_prot_val);
+ pcm, new_pcm);
goto err_free_memtype;
}
- prot_val = new_prot_val;
+ pcm = new_pcm;
}
- switch (prot_val) {
- case _PAGE_CACHE_UC:
+ prot = PAGE_KERNEL_IO;
+ switch (pcm) {
+ case _PAGE_CACHE_MODE_UC:
default:
- prot = PAGE_KERNEL_IO_NOCACHE;
+ prot = __pgprot(pgprot_val(prot) |
+ cachemode2protval(_PAGE_CACHE_MODE_UC));
break;
- case _PAGE_CACHE_UC_MINUS:
- prot = PAGE_KERNEL_IO_UC_MINUS;
+ case _PAGE_CACHE_MODE_UC_MINUS:
+ prot = __pgprot(pgprot_val(prot) |
+ cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS));
break;
- case _PAGE_CACHE_WC:
- prot = PAGE_KERNEL_IO_WC;
+ case _PAGE_CACHE_MODE_WC:
+ prot = __pgprot(pgprot_val(prot) |
+ cachemode2protval(_PAGE_CACHE_MODE_WC));
break;
- case _PAGE_CACHE_WB:
- prot = PAGE_KERNEL_IO;
+ case _PAGE_CACHE_MODE_WB:
break;
}
@@ -178,7 +180,7 @@ static void __iomem *__ioremap_caller(resource_size_t phys_addr,
area->phys_addr = phys_addr;
vaddr = (unsigned long) area->addr;
- if (kernel_map_sync_memtype(phys_addr, size, prot_val))
+ if (kernel_map_sync_memtype(phys_addr, size, pcm))
goto err_free_area;
if (ioremap_page_range(vaddr, vaddr + size, phys_addr, prot))
@@ -227,14 +229,14 @@ void __iomem *ioremap_nocache(resource_size_t phys_addr, unsigned long size)
{
/*
* Ideally, this should be:
- * pat_enabled ? _PAGE_CACHE_UC : _PAGE_CACHE_UC_MINUS;
+ * pat_enabled ? _PAGE_CACHE_MODE_UC : _PAGE_CACHE_MODE_UC_MINUS;
*
* Till we fix all X drivers to use ioremap_wc(), we will use
* UC MINUS.
*/
- unsigned long val = _PAGE_CACHE_UC_MINUS;
+ enum page_cache_mode pcm = _PAGE_CACHE_MODE_UC_MINUS;
- return __ioremap_caller(phys_addr, size, val,
+ return __ioremap_caller(phys_addr, size, pcm,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_nocache);
@@ -252,7 +254,7 @@ EXPORT_SYMBOL(ioremap_nocache);
void __iomem *ioremap_wc(resource_size_t phys_addr, unsigned long size)
{
if (pat_enabled)
- return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WC,
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WC,
__builtin_return_address(0));
else
return ioremap_nocache(phys_addr, size);
@@ -261,7 +263,7 @@ EXPORT_SYMBOL(ioremap_wc);
void __iomem *ioremap_cache(resource_size_t phys_addr, unsigned long size)
{
- return __ioremap_caller(phys_addr, size, _PAGE_CACHE_WB,
+ return __ioremap_caller(phys_addr, size, _PAGE_CACHE_MODE_WB,
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_cache);
@@ -269,7 +271,8 @@ EXPORT_SYMBOL(ioremap_cache);
void __iomem *ioremap_prot(resource_size_t phys_addr, unsigned long size,
unsigned long prot_val)
{
- return __ioremap_caller(phys_addr, size, (prot_val & _PAGE_CACHE_MASK),
+ return __ioremap_caller(phys_addr, size,
+ pgprot2cachemode(__pgprot(prot_val)),
__builtin_return_address(0));
}
EXPORT_SYMBOL(ioremap_prot);
@@ -327,7 +330,7 @@ EXPORT_SYMBOL(iounmap);
* Convert a physical pointer to a virtual kernel pointer for /dev/mem
* access
*/
-void *xlate_dev_mem_ptr(unsigned long phys)
+void *xlate_dev_mem_ptr(phys_addr_t phys)
{
void *addr;
unsigned long start = phys & PAGE_MASK;
@@ -343,7 +346,7 @@ void *xlate_dev_mem_ptr(unsigned long phys)
return addr;
}
-void unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
{
if (page_is_ram(phys >> PAGE_SHIFT))
return;
diff --git a/arch/x86/mm/mm_internal.h b/arch/x86/mm/mm_internal.h
index 6b563a1..62474ba 100644
--- a/arch/x86/mm/mm_internal.h
+++ b/arch/x86/mm/mm_internal.h
@@ -16,4 +16,6 @@ void zone_sizes_init(void);
extern int after_bootmem;
+void update_cache_mode_entry(unsigned entry, enum page_cache_mode cache);
+
#endif /* __X86_MM_INTERNAL_H */
diff --git a/arch/x86/mm/mpx.c b/arch/x86/mm/mpx.c
new file mode 100644
index 0000000..67ebf57
--- /dev/null
+++ b/arch/x86/mm/mpx.c
@@ -0,0 +1,928 @@
+/*
+ * mpx.c - Memory Protection eXtensions
+ *
+ * Copyright (c) 2014, Intel Corporation.
+ * Qiaowei Ren <qiaowei.ren@intel.com>
+ * Dave Hansen <dave.hansen@intel.com>
+ */
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/syscalls.h>
+#include <linux/sched/sysctl.h>
+
+#include <asm/i387.h>
+#include <asm/insn.h>
+#include <asm/mman.h>
+#include <asm/mmu_context.h>
+#include <asm/mpx.h>
+#include <asm/processor.h>
+#include <asm/fpu-internal.h>
+
+static const char *mpx_mapping_name(struct vm_area_struct *vma)
+{
+ return "[mpx]";
+}
+
+static struct vm_operations_struct mpx_vma_ops = {
+ .name = mpx_mapping_name,
+};
+
+static int is_mpx_vma(struct vm_area_struct *vma)
+{
+ return (vma->vm_ops == &mpx_vma_ops);
+}
+
+/*
+ * This is really a simplified "vm_mmap". it only handles MPX
+ * bounds tables (the bounds directory is user-allocated).
+ *
+ * Later on, we use the vma->vm_ops to uniquely identify these
+ * VMAs.
+ */
+static unsigned long mpx_mmap(unsigned long len)
+{
+ unsigned long ret;
+ unsigned long addr, pgoff;
+ struct mm_struct *mm = current->mm;
+ vm_flags_t vm_flags;
+ struct vm_area_struct *vma;
+
+ /* Only bounds table and bounds directory can be allocated here */
+ if (len != MPX_BD_SIZE_BYTES && len != MPX_BT_SIZE_BYTES)
+ return -EINVAL;
+
+ down_write(&mm->mmap_sem);
+
+ /* Too many mappings? */
+ if (mm->map_count > sysctl_max_map_count) {
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ /* Obtain the address to map to. we verify (or select) it and ensure
+ * that it represents a valid section of the address space.
+ */
+ addr = get_unmapped_area(NULL, 0, len, 0, MAP_ANONYMOUS | MAP_PRIVATE);
+ if (addr & ~PAGE_MASK) {
+ ret = addr;
+ goto out;
+ }
+
+ vm_flags = VM_READ | VM_WRITE | VM_MPX |
+ mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC;
+
+ /* Set pgoff according to addr for anon_vma */
+ pgoff = addr >> PAGE_SHIFT;
+
+ ret = mmap_region(NULL, addr, len, vm_flags, pgoff);
+ if (IS_ERR_VALUE(ret))
+ goto out;
+
+ vma = find_vma(mm, ret);
+ if (!vma) {
+ ret = -ENOMEM;
+ goto out;
+ }
+ vma->vm_ops = &mpx_vma_ops;
+
+ if (vm_flags & VM_LOCKED) {
+ up_write(&mm->mmap_sem);
+ mm_populate(ret, len);
+ return ret;
+ }
+
+out:
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+enum reg_type {
+ REG_TYPE_RM = 0,
+ REG_TYPE_INDEX,
+ REG_TYPE_BASE,
+};
+
+static int get_reg_offset(struct insn *insn, struct pt_regs *regs,
+ enum reg_type type)
+{
+ int regno = 0;
+
+ static const int regoff[] = {
+ offsetof(struct pt_regs, ax),
+ offsetof(struct pt_regs, cx),
+ offsetof(struct pt_regs, dx),
+ offsetof(struct pt_regs, bx),
+ offsetof(struct pt_regs, sp),
+ offsetof(struct pt_regs, bp),
+ offsetof(struct pt_regs, si),
+ offsetof(struct pt_regs, di),
+#ifdef CONFIG_X86_64
+ offsetof(struct pt_regs, r8),
+ offsetof(struct pt_regs, r9),
+ offsetof(struct pt_regs, r10),
+ offsetof(struct pt_regs, r11),
+ offsetof(struct pt_regs, r12),
+ offsetof(struct pt_regs, r13),
+ offsetof(struct pt_regs, r14),
+ offsetof(struct pt_regs, r15),
+#endif
+ };
+ int nr_registers = ARRAY_SIZE(regoff);
+ /*
+ * Don't possibly decode a 32-bit instructions as
+ * reading a 64-bit-only register.
+ */
+ if (IS_ENABLED(CONFIG_X86_64) && !insn->x86_64)
+ nr_registers -= 8;
+
+ switch (type) {
+ case REG_TYPE_RM:
+ regno = X86_MODRM_RM(insn->modrm.value);
+ if (X86_REX_B(insn->rex_prefix.value) == 1)
+ regno += 8;
+ break;
+
+ case REG_TYPE_INDEX:
+ regno = X86_SIB_INDEX(insn->sib.value);
+ if (X86_REX_X(insn->rex_prefix.value) == 1)
+ regno += 8;
+ break;
+
+ case REG_TYPE_BASE:
+ regno = X86_SIB_BASE(insn->sib.value);
+ if (X86_REX_B(insn->rex_prefix.value) == 1)
+ regno += 8;
+ break;
+
+ default:
+ pr_err("invalid register type");
+ BUG();
+ break;
+ }
+
+ if (regno > nr_registers) {
+ WARN_ONCE(1, "decoded an instruction with an invalid register");
+ return -EINVAL;
+ }
+ return regoff[regno];
+}
+
+/*
+ * return the address being referenced be instruction
+ * for rm=3 returning the content of the rm reg
+ * for rm!=3 calculates the address using SIB and Disp
+ */
+static void __user *mpx_get_addr_ref(struct insn *insn, struct pt_regs *regs)
+{
+ unsigned long addr, base, indx;
+ int addr_offset, base_offset, indx_offset;
+ insn_byte_t sib;
+
+ insn_get_modrm(insn);
+ insn_get_sib(insn);
+ sib = insn->sib.value;
+
+ if (X86_MODRM_MOD(insn->modrm.value) == 3) {
+ addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
+ if (addr_offset < 0)
+ goto out_err;
+ addr = regs_get_register(regs, addr_offset);
+ } else {
+ if (insn->sib.nbytes) {
+ base_offset = get_reg_offset(insn, regs, REG_TYPE_BASE);
+ if (base_offset < 0)
+ goto out_err;
+
+ indx_offset = get_reg_offset(insn, regs, REG_TYPE_INDEX);
+ if (indx_offset < 0)
+ goto out_err;
+
+ base = regs_get_register(regs, base_offset);
+ indx = regs_get_register(regs, indx_offset);
+ addr = base + indx * (1 << X86_SIB_SCALE(sib));
+ } else {
+ addr_offset = get_reg_offset(insn, regs, REG_TYPE_RM);
+ if (addr_offset < 0)
+ goto out_err;
+ addr = regs_get_register(regs, addr_offset);
+ }
+ addr += insn->displacement.value;
+ }
+ return (void __user *)addr;
+out_err:
+ return (void __user *)-1;
+}
+
+static int mpx_insn_decode(struct insn *insn,
+ struct pt_regs *regs)
+{
+ unsigned char buf[MAX_INSN_SIZE];
+ int x86_64 = !test_thread_flag(TIF_IA32);
+ int not_copied;
+ int nr_copied;
+
+ not_copied = copy_from_user(buf, (void __user *)regs->ip, sizeof(buf));
+ nr_copied = sizeof(buf) - not_copied;
+ /*
+ * The decoder _should_ fail nicely if we pass it a short buffer.
+ * But, let's not depend on that implementation detail. If we
+ * did not get anything, just error out now.
+ */
+ if (!nr_copied)
+ return -EFAULT;
+ insn_init(insn, buf, nr_copied, x86_64);
+ insn_get_length(insn);
+ /*
+ * copy_from_user() tries to get as many bytes as we could see in
+ * the largest possible instruction. If the instruction we are
+ * after is shorter than that _and_ we attempt to copy from
+ * something unreadable, we might get a short read. This is OK
+ * as long as the read did not stop in the middle of the
+ * instruction. Check to see if we got a partial instruction.
+ */
+ if (nr_copied < insn->length)
+ return -EFAULT;
+
+ insn_get_opcode(insn);
+ /*
+ * We only _really_ need to decode bndcl/bndcn/bndcu
+ * Error out on anything else.
+ */
+ if (insn->opcode.bytes[0] != 0x0f)
+ goto bad_opcode;
+ if ((insn->opcode.bytes[1] != 0x1a) &&
+ (insn->opcode.bytes[1] != 0x1b))
+ goto bad_opcode;
+
+ return 0;
+bad_opcode:
+ return -EINVAL;
+}
+
+/*
+ * If a bounds overflow occurs then a #BR is generated. This
+ * function decodes MPX instructions to get violation address
+ * and set this address into extended struct siginfo.
+ *
+ * Note that this is not a super precise way of doing this.
+ * Userspace could have, by the time we get here, written
+ * anything it wants in to the instructions. We can not
+ * trust anything about it. They might not be valid
+ * instructions or might encode invalid registers, etc...
+ *
+ * The caller is expected to kfree() the returned siginfo_t.
+ */
+siginfo_t *mpx_generate_siginfo(struct pt_regs *regs,
+ struct xsave_struct *xsave_buf)
+{
+ struct bndreg *bndregs, *bndreg;
+ siginfo_t *info = NULL;
+ struct insn insn;
+ uint8_t bndregno;
+ int err;
+
+ err = mpx_insn_decode(&insn, regs);
+ if (err)
+ goto err_out;
+
+ /*
+ * We know at this point that we are only dealing with
+ * MPX instructions.
+ */
+ insn_get_modrm(&insn);
+ bndregno = X86_MODRM_REG(insn.modrm.value);
+ if (bndregno > 3) {
+ err = -EINVAL;
+ goto err_out;
+ }
+ /* get the bndregs _area_ of the xsave structure */
+ bndregs = get_xsave_addr(xsave_buf, XSTATE_BNDREGS);
+ if (!bndregs) {
+ err = -EINVAL;
+ goto err_out;
+ }
+ /* now go select the individual register in the set of 4 */
+ bndreg = &bndregs[bndregno];
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info) {
+ err = -ENOMEM;
+ goto err_out;
+ }
+ /*
+ * The registers are always 64-bit, but the upper 32
+ * bits are ignored in 32-bit mode. Also, note that the
+ * upper bounds are architecturally represented in 1's
+ * complement form.
+ *
+ * The 'unsigned long' cast is because the compiler
+ * complains when casting from integers to different-size
+ * pointers.
+ */
+ info->si_lower = (void __user *)(unsigned long)bndreg->lower_bound;
+ info->si_upper = (void __user *)(unsigned long)~bndreg->upper_bound;
+ info->si_addr_lsb = 0;
+ info->si_signo = SIGSEGV;
+ info->si_errno = 0;
+ info->si_code = SEGV_BNDERR;
+ info->si_addr = mpx_get_addr_ref(&insn, regs);
+ /*
+ * We were not able to extract an address from the instruction,
+ * probably because there was something invalid in it.
+ */
+ if (info->si_addr == (void *)-1) {
+ err = -EINVAL;
+ goto err_out;
+ }
+ return info;
+err_out:
+ /* info might be NULL, but kfree() handles that */
+ kfree(info);
+ return ERR_PTR(err);
+}
+
+static __user void *task_get_bounds_dir(struct task_struct *tsk)
+{
+ struct bndcsr *bndcsr;
+
+ if (!cpu_feature_enabled(X86_FEATURE_MPX))
+ return MPX_INVALID_BOUNDS_DIR;
+
+ /*
+ * The bounds directory pointer is stored in a register
+ * only accessible if we first do an xsave.
+ */
+ fpu_save_init(&tsk->thread.fpu);
+ bndcsr = get_xsave_addr(&tsk->thread.fpu.state->xsave, XSTATE_BNDCSR);
+ if (!bndcsr)
+ return MPX_INVALID_BOUNDS_DIR;
+
+ /*
+ * Make sure the register looks valid by checking the
+ * enable bit.
+ */
+ if (!(bndcsr->bndcfgu & MPX_BNDCFG_ENABLE_FLAG))
+ return MPX_INVALID_BOUNDS_DIR;
+
+ /*
+ * Lastly, mask off the low bits used for configuration
+ * flags, and return the address of the bounds table.
+ */
+ return (void __user *)(unsigned long)
+ (bndcsr->bndcfgu & MPX_BNDCFG_ADDR_MASK);
+}
+
+int mpx_enable_management(struct task_struct *tsk)
+{
+ void __user *bd_base = MPX_INVALID_BOUNDS_DIR;
+ struct mm_struct *mm = tsk->mm;
+ int ret = 0;
+
+ /*
+ * runtime in the userspace will be responsible for allocation of
+ * the bounds directory. Then, it will save the base of the bounds
+ * directory into XSAVE/XRSTOR Save Area and enable MPX through
+ * XRSTOR instruction.
+ *
+ * fpu_xsave() is expected to be very expensive. Storing the bounds
+ * directory here means that we do not have to do xsave in the unmap
+ * path; we can just use mm->bd_addr instead.
+ */
+ bd_base = task_get_bounds_dir(tsk);
+ down_write(&mm->mmap_sem);
+ mm->bd_addr = bd_base;
+ if (mm->bd_addr == MPX_INVALID_BOUNDS_DIR)
+ ret = -ENXIO;
+
+ up_write(&mm->mmap_sem);
+ return ret;
+}
+
+int mpx_disable_management(struct task_struct *tsk)
+{
+ struct mm_struct *mm = current->mm;
+
+ if (!cpu_feature_enabled(X86_FEATURE_MPX))
+ return -ENXIO;
+
+ down_write(&mm->mmap_sem);
+ mm->bd_addr = MPX_INVALID_BOUNDS_DIR;
+ up_write(&mm->mmap_sem);
+ return 0;
+}
+
+/*
+ * With 32-bit mode, MPX_BT_SIZE_BYTES is 4MB, and the size of each
+ * bounds table is 16KB. With 64-bit mode, MPX_BT_SIZE_BYTES is 2GB,
+ * and the size of each bounds table is 4MB.
+ */
+static int allocate_bt(long __user *bd_entry)
+{
+ unsigned long expected_old_val = 0;
+ unsigned long actual_old_val = 0;
+ unsigned long bt_addr;
+ int ret = 0;
+
+ /*
+ * Carve the virtual space out of userspace for the new
+ * bounds table:
+ */
+ bt_addr = mpx_mmap(MPX_BT_SIZE_BYTES);
+ if (IS_ERR((void *)bt_addr))
+ return PTR_ERR((void *)bt_addr);
+ /*
+ * Set the valid flag (kinda like _PAGE_PRESENT in a pte)
+ */
+ bt_addr = bt_addr | MPX_BD_ENTRY_VALID_FLAG;
+
+ /*
+ * Go poke the address of the new bounds table in to the
+ * bounds directory entry out in userspace memory. Note:
+ * we may race with another CPU instantiating the same table.
+ * In that case the cmpxchg will see an unexpected
+ * 'actual_old_val'.
+ *
+ * This can fault, but that's OK because we do not hold
+ * mmap_sem at this point, unlike some of the other part
+ * of the MPX code that have to pagefault_disable().
+ */
+ ret = user_atomic_cmpxchg_inatomic(&actual_old_val, bd_entry,
+ expected_old_val, bt_addr);
+ if (ret)
+ goto out_unmap;
+
+ /*
+ * The user_atomic_cmpxchg_inatomic() will only return nonzero
+ * for faults, *not* if the cmpxchg itself fails. Now we must
+ * verify that the cmpxchg itself completed successfully.
+ */
+ /*
+ * We expected an empty 'expected_old_val', but instead found
+ * an apparently valid entry. Assume we raced with another
+ * thread to instantiate this table and desclare succecss.
+ */
+ if (actual_old_val & MPX_BD_ENTRY_VALID_FLAG) {
+ ret = 0;
+ goto out_unmap;
+ }
+ /*
+ * We found a non-empty bd_entry but it did not have the
+ * VALID_FLAG set. Return an error which will result in
+ * a SEGV since this probably means that somebody scribbled
+ * some invalid data in to a bounds table.
+ */
+ if (expected_old_val != actual_old_val) {
+ ret = -EINVAL;
+ goto out_unmap;
+ }
+ return 0;
+out_unmap:
+ vm_munmap(bt_addr & MPX_BT_ADDR_MASK, MPX_BT_SIZE_BYTES);
+ return ret;
+}
+
+/*
+ * When a BNDSTX instruction attempts to save bounds to a bounds
+ * table, it will first attempt to look up the table in the
+ * first-level bounds directory. If it does not find a table in
+ * the directory, a #BR is generated and we get here in order to
+ * allocate a new table.
+ *
+ * With 32-bit mode, the size of BD is 4MB, and the size of each
+ * bound table is 16KB. With 64-bit mode, the size of BD is 2GB,
+ * and the size of each bound table is 4MB.
+ */
+static int do_mpx_bt_fault(struct xsave_struct *xsave_buf)
+{
+ unsigned long bd_entry, bd_base;
+ struct bndcsr *bndcsr;
+
+ bndcsr = get_xsave_addr(xsave_buf, XSTATE_BNDCSR);
+ if (!bndcsr)
+ return -EINVAL;
+ /*
+ * Mask off the preserve and enable bits
+ */
+ bd_base = bndcsr->bndcfgu & MPX_BNDCFG_ADDR_MASK;
+ /*
+ * The hardware provides the address of the missing or invalid
+ * entry via BNDSTATUS, so we don't have to go look it up.
+ */
+ bd_entry = bndcsr->bndstatus & MPX_BNDSTA_ADDR_MASK;
+ /*
+ * Make sure the directory entry is within where we think
+ * the directory is.
+ */
+ if ((bd_entry < bd_base) ||
+ (bd_entry >= bd_base + MPX_BD_SIZE_BYTES))
+ return -EINVAL;
+
+ return allocate_bt((long __user *)bd_entry);
+}
+
+int mpx_handle_bd_fault(struct xsave_struct *xsave_buf)
+{
+ /*
+ * Userspace never asked us to manage the bounds tables,
+ * so refuse to help.
+ */
+ if (!kernel_managing_mpx_tables(current->mm))
+ return -EINVAL;
+
+ if (do_mpx_bt_fault(xsave_buf)) {
+ force_sig(SIGSEGV, current);
+ /*
+ * The force_sig() is essentially "handling" this
+ * exception, so we do not pass up the error
+ * from do_mpx_bt_fault().
+ */
+ }
+ return 0;
+}
+
+/*
+ * A thin wrapper around get_user_pages(). Returns 0 if the
+ * fault was resolved or -errno if not.
+ */
+static int mpx_resolve_fault(long __user *addr, int write)
+{
+ long gup_ret;
+ int nr_pages = 1;
+ int force = 0;
+
+ gup_ret = get_user_pages(current, current->mm, (unsigned long)addr,
+ nr_pages, write, force, NULL, NULL);
+ /*
+ * get_user_pages() returns number of pages gotten.
+ * 0 means we failed to fault in and get anything,
+ * probably because 'addr' is bad.
+ */
+ if (!gup_ret)
+ return -EFAULT;
+ /* Other error, return it */
+ if (gup_ret < 0)
+ return gup_ret;
+ /* must have gup'd a page and gup_ret>0, success */
+ return 0;
+}
+
+/*
+ * Get the base of bounds tables pointed by specific bounds
+ * directory entry.
+ */
+static int get_bt_addr(struct mm_struct *mm,
+ long __user *bd_entry, unsigned long *bt_addr)
+{
+ int ret;
+ int valid_bit;
+
+ if (!access_ok(VERIFY_READ, (bd_entry), sizeof(*bd_entry)))
+ return -EFAULT;
+
+ while (1) {
+ int need_write = 0;
+
+ pagefault_disable();
+ ret = get_user(*bt_addr, bd_entry);
+ pagefault_enable();
+ if (!ret)
+ break;
+ if (ret == -EFAULT)
+ ret = mpx_resolve_fault(bd_entry, need_write);
+ /*
+ * If we could not resolve the fault, consider it
+ * userspace's fault and error out.
+ */
+ if (ret)
+ return ret;
+ }
+
+ valid_bit = *bt_addr & MPX_BD_ENTRY_VALID_FLAG;
+ *bt_addr &= MPX_BT_ADDR_MASK;
+
+ /*
+ * When the kernel is managing bounds tables, a bounds directory
+ * entry will either have a valid address (plus the valid bit)
+ * *OR* be completely empty. If we see a !valid entry *and* some
+ * data in the address field, we know something is wrong. This
+ * -EINVAL return will cause a SIGSEGV.
+ */
+ if (!valid_bit && *bt_addr)
+ return -EINVAL;
+ /*
+ * Do we have an completely zeroed bt entry? That is OK. It
+ * just means there was no bounds table for this memory. Make
+ * sure to distinguish this from -EINVAL, which will cause
+ * a SEGV.
+ */
+ if (!valid_bit)
+ return -ENOENT;
+
+ return 0;
+}
+
+/*
+ * Free the backing physical pages of bounds table 'bt_addr'.
+ * Assume start...end is within that bounds table.
+ */
+static int zap_bt_entries(struct mm_struct *mm,
+ unsigned long bt_addr,
+ unsigned long start, unsigned long end)
+{
+ struct vm_area_struct *vma;
+ unsigned long addr, len;
+
+ /*
+ * Find the first overlapping vma. If vma->vm_start > start, there
+ * will be a hole in the bounds table. This -EINVAL return will
+ * cause a SIGSEGV.
+ */
+ vma = find_vma(mm, start);
+ if (!vma || vma->vm_start > start)
+ return -EINVAL;
+
+ /*
+ * A NUMA policy on a VM_MPX VMA could cause this bouds table to
+ * be split. So we need to look across the entire 'start -> end'
+ * range of this bounds table, find all of the VM_MPX VMAs, and
+ * zap only those.
+ */
+ addr = start;
+ while (vma && vma->vm_start < end) {
+ /*
+ * We followed a bounds directory entry down
+ * here. If we find a non-MPX VMA, that's bad,
+ * so stop immediately and return an error. This
+ * probably results in a SIGSEGV.
+ */
+ if (!is_mpx_vma(vma))
+ return -EINVAL;
+
+ len = min(vma->vm_end, end) - addr;
+ zap_page_range(vma, addr, len, NULL);
+
+ vma = vma->vm_next;
+ addr = vma->vm_start;
+ }
+
+ return 0;
+}
+
+static int unmap_single_bt(struct mm_struct *mm,
+ long __user *bd_entry, unsigned long bt_addr)
+{
+ unsigned long expected_old_val = bt_addr | MPX_BD_ENTRY_VALID_FLAG;
+ unsigned long actual_old_val = 0;
+ int ret;
+
+ while (1) {
+ int need_write = 1;
+
+ pagefault_disable();
+ ret = user_atomic_cmpxchg_inatomic(&actual_old_val, bd_entry,
+ expected_old_val, 0);
+ pagefault_enable();
+ if (!ret)
+ break;
+ if (ret == -EFAULT)
+ ret = mpx_resolve_fault(bd_entry, need_write);
+ /*
+ * If we could not resolve the fault, consider it
+ * userspace's fault and error out.
+ */
+ if (ret)
+ return ret;
+ }
+ /*
+ * The cmpxchg was performed, check the results.
+ */
+ if (actual_old_val != expected_old_val) {
+ /*
+ * Someone else raced with us to unmap the table.
+ * There was no bounds table pointed to by the
+ * directory, so declare success. Somebody freed
+ * it.
+ */
+ if (!actual_old_val)
+ return 0;
+ /*
+ * Something messed with the bounds directory
+ * entry. We hold mmap_sem for read or write
+ * here, so it could not be a _new_ bounds table
+ * that someone just allocated. Something is
+ * wrong, so pass up the error and SIGSEGV.
+ */
+ return -EINVAL;
+ }
+
+ /*
+ * Note, we are likely being called under do_munmap() already. To
+ * avoid recursion, do_munmap() will check whether it comes
+ * from one bounds table through VM_MPX flag.
+ */
+ return do_munmap(mm, bt_addr, MPX_BT_SIZE_BYTES);
+}
+
+/*
+ * If the bounds table pointed by bounds directory 'bd_entry' is
+ * not shared, unmap this whole bounds table. Otherwise, only free
+ * those backing physical pages of bounds table entries covered
+ * in this virtual address region start...end.
+ */
+static int unmap_shared_bt(struct mm_struct *mm,
+ long __user *bd_entry, unsigned long start,
+ unsigned long end, bool prev_shared, bool next_shared)
+{
+ unsigned long bt_addr;
+ int ret;
+
+ ret = get_bt_addr(mm, bd_entry, &bt_addr);
+ /*
+ * We could see an "error" ret for not-present bounds
+ * tables (not really an error), or actual errors, but
+ * stop unmapping either way.
+ */
+ if (ret)
+ return ret;
+
+ if (prev_shared && next_shared)
+ ret = zap_bt_entries(mm, bt_addr,
+ bt_addr+MPX_GET_BT_ENTRY_OFFSET(start),
+ bt_addr+MPX_GET_BT_ENTRY_OFFSET(end));
+ else if (prev_shared)
+ ret = zap_bt_entries(mm, bt_addr,
+ bt_addr+MPX_GET_BT_ENTRY_OFFSET(start),
+ bt_addr+MPX_BT_SIZE_BYTES);
+ else if (next_shared)
+ ret = zap_bt_entries(mm, bt_addr, bt_addr,
+ bt_addr+MPX_GET_BT_ENTRY_OFFSET(end));
+ else
+ ret = unmap_single_bt(mm, bd_entry, bt_addr);
+
+ return ret;
+}
+
+/*
+ * A virtual address region being munmap()ed might share bounds table
+ * with adjacent VMAs. We only need to free the backing physical
+ * memory of these shared bounds tables entries covered in this virtual
+ * address region.
+ */
+static int unmap_edge_bts(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ int ret;
+ long __user *bde_start, *bde_end;
+ struct vm_area_struct *prev, *next;
+ bool prev_shared = false, next_shared = false;
+
+ bde_start = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(start);
+ bde_end = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(end-1);
+
+ /*
+ * Check whether bde_start and bde_end are shared with adjacent
+ * VMAs.
+ *
+ * We already unliked the VMAs from the mm's rbtree so 'start'
+ * is guaranteed to be in a hole. This gets us the first VMA
+ * before the hole in to 'prev' and the next VMA after the hole
+ * in to 'next'.
+ */
+ next = find_vma_prev(mm, start, &prev);
+ if (prev && (mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(prev->vm_end-1))
+ == bde_start)
+ prev_shared = true;
+ if (next && (mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(next->vm_start))
+ == bde_end)
+ next_shared = true;
+
+ /*
+ * This virtual address region being munmap()ed is only
+ * covered by one bounds table.
+ *
+ * In this case, if this table is also shared with adjacent
+ * VMAs, only part of the backing physical memory of the bounds
+ * table need be freeed. Otherwise the whole bounds table need
+ * be unmapped.
+ */
+ if (bde_start == bde_end) {
+ return unmap_shared_bt(mm, bde_start, start, end,
+ prev_shared, next_shared);
+ }
+
+ /*
+ * If more than one bounds tables are covered in this virtual
+ * address region being munmap()ed, we need to separately check
+ * whether bde_start and bde_end are shared with adjacent VMAs.
+ */
+ ret = unmap_shared_bt(mm, bde_start, start, end, prev_shared, false);
+ if (ret)
+ return ret;
+ ret = unmap_shared_bt(mm, bde_end, start, end, false, next_shared);
+ if (ret)
+ return ret;
+
+ return 0;
+}
+
+static int mpx_unmap_tables(struct mm_struct *mm,
+ unsigned long start, unsigned long end)
+{
+ int ret;
+ long __user *bd_entry, *bde_start, *bde_end;
+ unsigned long bt_addr;
+
+ /*
+ * "Edge" bounds tables are those which are being used by the region
+ * (start -> end), but that may be shared with adjacent areas. If they
+ * turn out to be completely unshared, they will be freed. If they are
+ * shared, we will free the backing store (like an MADV_DONTNEED) for
+ * areas used by this region.
+ */
+ ret = unmap_edge_bts(mm, start, end);
+ switch (ret) {
+ /* non-present tables are OK */
+ case 0:
+ case -ENOENT:
+ /* Success, or no tables to unmap */
+ break;
+ case -EINVAL:
+ case -EFAULT:
+ default:
+ return ret;
+ }
+
+ /*
+ * Only unmap the bounds table that are
+ * 1. fully covered
+ * 2. not at the edges of the mapping, even if full aligned
+ */
+ bde_start = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(start);
+ bde_end = mm->bd_addr + MPX_GET_BD_ENTRY_OFFSET(end-1);
+ for (bd_entry = bde_start + 1; bd_entry < bde_end; bd_entry++) {
+ ret = get_bt_addr(mm, bd_entry, &bt_addr);
+ switch (ret) {
+ case 0:
+ break;
+ case -ENOENT:
+ /* No table here, try the next one */
+ continue;
+ case -EINVAL:
+ case -EFAULT:
+ default:
+ /*
+ * Note: we are being strict here.
+ * Any time we run in to an issue
+ * unmapping tables, we stop and
+ * SIGSEGV.
+ */
+ return ret;
+ }
+
+ ret = unmap_single_bt(mm, bd_entry, bt_addr);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+/*
+ * Free unused bounds tables covered in a virtual address region being
+ * munmap()ed. Assume end > start.
+ *
+ * This function will be called by do_munmap(), and the VMAs covering
+ * the virtual address region start...end have already been split if
+ * necessary, and the 'vma' is the first vma in this range (start -> end).
+ */
+void mpx_notify_unmap(struct mm_struct *mm, struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ int ret;
+
+ /*
+ * Refuse to do anything unless userspace has asked
+ * the kernel to help manage the bounds tables,
+ */
+ if (!kernel_managing_mpx_tables(current->mm))
+ return;
+ /*
+ * This will look across the entire 'start -> end' range,
+ * and find all of the non-VM_MPX VMAs.
+ *
+ * To avoid recursion, if a VM_MPX vma is found in the range
+ * (start->end), we will not continue follow-up work. This
+ * recursion represents having bounds tables for bounds tables,
+ * which should not occur normally. Being strict about it here
+ * helps ensure that we do not have an exploitable stack overflow.
+ */
+ do {
+ if (vma->vm_flags & VM_MPX)
+ return;
+ vma = vma->vm_next;
+ } while (vma && vma->vm_start < end);
+
+ ret = mpx_unmap_tables(mm, start, end);
+ if (ret)
+ force_sig(SIGSEGV, current);
+}
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 36de293..a3a5d46 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -485,14 +485,23 @@ try_preserve_large_page(pte_t *kpte, unsigned long address,
/*
* We are safe now. Check whether the new pgprot is the same:
+ * Convert protection attributes to 4k-format, as cpa->mask* are set
+ * up accordingly.
*/
old_pte = *kpte;
- old_prot = req_prot = pte_pgprot(old_pte);
+ old_prot = req_prot = pgprot_large_2_4k(pte_pgprot(old_pte));
pgprot_val(req_prot) &= ~pgprot_val(cpa->mask_clr);
pgprot_val(req_prot) |= pgprot_val(cpa->mask_set);
/*
+ * req_prot is in format of 4k pages. It must be converted to large
+ * page format: the caching mode includes the PAT bit located at
+ * different bit positions in the two formats.
+ */
+ req_prot = pgprot_4k_2_large(req_prot);
+
+ /*
* Set the PSE and GLOBAL flags only if the PRESENT flag is
* set otherwise pmd_present/pmd_huge will return true even on
* a non present pmd. The canon_pgprot will clear _PAGE_GLOBAL
@@ -585,13 +594,10 @@ __split_large_page(struct cpa_data *cpa, pte_t *kpte, unsigned long address,
paravirt_alloc_pte(&init_mm, page_to_pfn(base));
ref_prot = pte_pgprot(pte_clrhuge(*kpte));
- /*
- * If we ever want to utilize the PAT bit, we need to
- * update this function to make sure it's converted from
- * bit 12 to bit 7 when we cross from the 2MB level to
- * the 4K level:
- */
- WARN_ON_ONCE(pgprot_val(ref_prot) & _PAGE_PAT_LARGE);
+
+ /* promote PAT bit to correct position */
+ if (level == PG_LEVEL_2M)
+ ref_prot = pgprot_large_2_4k(ref_prot);
#ifdef CONFIG_X86_64
if (level == PG_LEVEL_1G) {
@@ -879,6 +885,7 @@ static int populate_pmd(struct cpa_data *cpa,
{
unsigned int cur_pages = 0;
pmd_t *pmd;
+ pgprot_t pmd_pgprot;
/*
* Not on a 2M boundary?
@@ -910,6 +917,8 @@ static int populate_pmd(struct cpa_data *cpa,
if (num_pages == cur_pages)
return cur_pages;
+ pmd_pgprot = pgprot_4k_2_large(pgprot);
+
while (end - start >= PMD_SIZE) {
/*
@@ -921,7 +930,8 @@ static int populate_pmd(struct cpa_data *cpa,
pmd = pmd_offset(pud, start);
- set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot)));
+ set_pmd(pmd, __pmd(cpa->pfn | _PAGE_PSE |
+ massage_pgprot(pmd_pgprot)));
start += PMD_SIZE;
cpa->pfn += PMD_SIZE;
@@ -949,6 +959,7 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
pud_t *pud;
unsigned long end;
int cur_pages = 0;
+ pgprot_t pud_pgprot;
end = start + (cpa->numpages << PAGE_SHIFT);
@@ -986,12 +997,14 @@ static int populate_pud(struct cpa_data *cpa, unsigned long start, pgd_t *pgd,
return cur_pages;
pud = pud_offset(pgd, start);
+ pud_pgprot = pgprot_4k_2_large(pgprot);
/*
* Map everything starting from the Gb boundary, possibly with 1G pages
*/
while (end - start >= PUD_SIZE) {
- set_pud(pud, __pud(cpa->pfn | _PAGE_PSE | massage_pgprot(pgprot)));
+ set_pud(pud, __pud(cpa->pfn | _PAGE_PSE |
+ massage_pgprot(pud_pgprot)));
start += PUD_SIZE;
cpa->pfn += PUD_SIZE;
@@ -1304,12 +1317,6 @@ static int __change_page_attr_set_clr(struct cpa_data *cpa, int checkalias)
return 0;
}
-static inline int cache_attr(pgprot_t attr)
-{
- return pgprot_val(attr) &
- (_PAGE_PAT | _PAGE_PAT_LARGE | _PAGE_PWT | _PAGE_PCD);
-}
-
static int change_page_attr_set_clr(unsigned long *addr, int numpages,
pgprot_t mask_set, pgprot_t mask_clr,
int force_split, int in_flag,
@@ -1390,7 +1397,7 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
* No need to flush, when we did not set any of the caching
* attributes:
*/
- cache = cache_attr(mask_set);
+ cache = !!pgprot2cachemode(mask_set);
/*
* On success we use CLFLUSH, when the CPU supports it to
@@ -1445,7 +1452,8 @@ int _set_memory_uc(unsigned long addr, int numpages)
* for now UC MINUS. see comments in ioremap_nocache()
*/
return change_page_attr_set(&addr, numpages,
- __pgprot(_PAGE_CACHE_UC_MINUS), 0);
+ cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
+ 0);
}
int set_memory_uc(unsigned long addr, int numpages)
@@ -1456,7 +1464,7 @@ int set_memory_uc(unsigned long addr, int numpages)
* for now UC MINUS. see comments in ioremap_nocache()
*/
ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
- _PAGE_CACHE_UC_MINUS, NULL);
+ _PAGE_CACHE_MODE_UC_MINUS, NULL);
if (ret)
goto out_err;
@@ -1474,7 +1482,7 @@ out_err:
EXPORT_SYMBOL(set_memory_uc);
static int _set_memory_array(unsigned long *addr, int addrinarray,
- unsigned long new_type)
+ enum page_cache_mode new_type)
{
int i, j;
int ret;
@@ -1490,11 +1498,13 @@ static int _set_memory_array(unsigned long *addr, int addrinarray,
}
ret = change_page_attr_set(addr, addrinarray,
- __pgprot(_PAGE_CACHE_UC_MINUS), 1);
+ cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
+ 1);
- if (!ret && new_type == _PAGE_CACHE_WC)
+ if (!ret && new_type == _PAGE_CACHE_MODE_WC)
ret = change_page_attr_set_clr(addr, addrinarray,
- __pgprot(_PAGE_CACHE_WC),
+ cachemode2pgprot(
+ _PAGE_CACHE_MODE_WC),
__pgprot(_PAGE_CACHE_MASK),
0, CPA_ARRAY, NULL);
if (ret)
@@ -1511,13 +1521,13 @@ out_free:
int set_memory_array_uc(unsigned long *addr, int addrinarray)
{
- return _set_memory_array(addr, addrinarray, _PAGE_CACHE_UC_MINUS);
+ return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_UC_MINUS);
}
EXPORT_SYMBOL(set_memory_array_uc);
int set_memory_array_wc(unsigned long *addr, int addrinarray)
{
- return _set_memory_array(addr, addrinarray, _PAGE_CACHE_WC);
+ return _set_memory_array(addr, addrinarray, _PAGE_CACHE_MODE_WC);
}
EXPORT_SYMBOL(set_memory_array_wc);
@@ -1527,10 +1537,12 @@ int _set_memory_wc(unsigned long addr, int numpages)
unsigned long addr_copy = addr;
ret = change_page_attr_set(&addr, numpages,
- __pgprot(_PAGE_CACHE_UC_MINUS), 0);
+ cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS),
+ 0);
if (!ret) {
ret = change_page_attr_set_clr(&addr_copy, numpages,
- __pgprot(_PAGE_CACHE_WC),
+ cachemode2pgprot(
+ _PAGE_CACHE_MODE_WC),
__pgprot(_PAGE_CACHE_MASK),
0, 0, NULL);
}
@@ -1545,7 +1557,7 @@ int set_memory_wc(unsigned long addr, int numpages)
return set_memory_uc(addr, numpages);
ret = reserve_memtype(__pa(addr), __pa(addr) + numpages * PAGE_SIZE,
- _PAGE_CACHE_WC, NULL);
+ _PAGE_CACHE_MODE_WC, NULL);
if (ret)
goto out_err;
@@ -1564,6 +1576,7 @@ EXPORT_SYMBOL(set_memory_wc);
int _set_memory_wb(unsigned long addr, int numpages)
{
+ /* WB cache mode is hard wired to all cache attribute bits being 0 */
return change_page_attr_clear(&addr, numpages,
__pgprot(_PAGE_CACHE_MASK), 0);
}
@@ -1586,6 +1599,7 @@ int set_memory_array_wb(unsigned long *addr, int addrinarray)
int i;
int ret;
+ /* WB cache mode is hard wired to all cache attribute bits being 0 */
ret = change_page_attr_clear(addr, addrinarray,
__pgprot(_PAGE_CACHE_MASK), 1);
if (ret)
@@ -1648,7 +1662,7 @@ int set_pages_uc(struct page *page, int numpages)
EXPORT_SYMBOL(set_pages_uc);
static int _set_pages_array(struct page **pages, int addrinarray,
- unsigned long new_type)
+ enum page_cache_mode new_type)
{
unsigned long start;
unsigned long end;
@@ -1666,10 +1680,11 @@ static int _set_pages_array(struct page **pages, int addrinarray,
}
ret = cpa_set_pages_array(pages, addrinarray,
- __pgprot(_PAGE_CACHE_UC_MINUS));
- if (!ret && new_type == _PAGE_CACHE_WC)
+ cachemode2pgprot(_PAGE_CACHE_MODE_UC_MINUS));
+ if (!ret && new_type == _PAGE_CACHE_MODE_WC)
ret = change_page_attr_set_clr(NULL, addrinarray,
- __pgprot(_PAGE_CACHE_WC),
+ cachemode2pgprot(
+ _PAGE_CACHE_MODE_WC),
__pgprot(_PAGE_CACHE_MASK),
0, CPA_PAGES_ARRAY, pages);
if (ret)
@@ -1689,13 +1704,13 @@ err_out:
int set_pages_array_uc(struct page **pages, int addrinarray)
{
- return _set_pages_array(pages, addrinarray, _PAGE_CACHE_UC_MINUS);
+ return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_UC_MINUS);
}
EXPORT_SYMBOL(set_pages_array_uc);
int set_pages_array_wc(struct page **pages, int addrinarray)
{
- return _set_pages_array(pages, addrinarray, _PAGE_CACHE_WC);
+ return _set_pages_array(pages, addrinarray, _PAGE_CACHE_MODE_WC);
}
EXPORT_SYMBOL(set_pages_array_wc);
@@ -1714,6 +1729,7 @@ int set_pages_array_wb(struct page **pages, int addrinarray)
unsigned long end;
int i;
+ /* WB cache mode is hard wired to all cache attribute bits being 0 */
retval = cpa_clear_pages_array(pages, addrinarray,
__pgprot(_PAGE_CACHE_MASK));
if (retval)
diff --git a/arch/x86/mm/pat.c b/arch/x86/mm/pat.c
index 6574388..edf299c 100644
--- a/arch/x86/mm/pat.c
+++ b/arch/x86/mm/pat.c
@@ -31,6 +31,7 @@
#include <asm/io.h>
#include "pat_internal.h"
+#include "mm_internal.h"
#ifdef CONFIG_X86_PAT
int __read_mostly pat_enabled = 1;
@@ -66,6 +67,75 @@ __setup("debugpat", pat_debug_setup);
static u64 __read_mostly boot_pat_state;
+#ifdef CONFIG_X86_PAT
+/*
+ * X86 PAT uses page flags WC and Uncached together to keep track of
+ * memory type of pages that have backing page struct. X86 PAT supports 3
+ * different memory types, _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC and
+ * _PAGE_CACHE_MODE_UC_MINUS and fourth state where page's memory type has not
+ * been changed from its default (value of -1 used to denote this).
+ * Note we do not support _PAGE_CACHE_MODE_UC here.
+ */
+
+#define _PGMT_DEFAULT 0
+#define _PGMT_WC (1UL << PG_arch_1)
+#define _PGMT_UC_MINUS (1UL << PG_uncached)
+#define _PGMT_WB (1UL << PG_uncached | 1UL << PG_arch_1)
+#define _PGMT_MASK (1UL << PG_uncached | 1UL << PG_arch_1)
+#define _PGMT_CLEAR_MASK (~_PGMT_MASK)
+
+static inline enum page_cache_mode get_page_memtype(struct page *pg)
+{
+ unsigned long pg_flags = pg->flags & _PGMT_MASK;
+
+ if (pg_flags == _PGMT_DEFAULT)
+ return -1;
+ else if (pg_flags == _PGMT_WC)
+ return _PAGE_CACHE_MODE_WC;
+ else if (pg_flags == _PGMT_UC_MINUS)
+ return _PAGE_CACHE_MODE_UC_MINUS;
+ else
+ return _PAGE_CACHE_MODE_WB;
+}
+
+static inline void set_page_memtype(struct page *pg,
+ enum page_cache_mode memtype)
+{
+ unsigned long memtype_flags;
+ unsigned long old_flags;
+ unsigned long new_flags;
+
+ switch (memtype) {
+ case _PAGE_CACHE_MODE_WC:
+ memtype_flags = _PGMT_WC;
+ break;
+ case _PAGE_CACHE_MODE_UC_MINUS:
+ memtype_flags = _PGMT_UC_MINUS;
+ break;
+ case _PAGE_CACHE_MODE_WB:
+ memtype_flags = _PGMT_WB;
+ break;
+ default:
+ memtype_flags = _PGMT_DEFAULT;
+ break;
+ }
+
+ do {
+ old_flags = pg->flags;
+ new_flags = (old_flags & _PGMT_CLEAR_MASK) | memtype_flags;
+ } while (cmpxchg(&pg->flags, old_flags, new_flags) != old_flags);
+}
+#else
+static inline enum page_cache_mode get_page_memtype(struct page *pg)
+{
+ return -1;
+}
+static inline void set_page_memtype(struct page *pg,
+ enum page_cache_mode memtype)
+{
+}
+#endif
+
enum {
PAT_UC = 0, /* uncached */
PAT_WC = 1, /* Write combining */
@@ -75,6 +145,52 @@ enum {
PAT_UC_MINUS = 7, /* UC, but can be overriden by MTRR */
};
+#define CM(c) (_PAGE_CACHE_MODE_ ## c)
+
+static enum page_cache_mode pat_get_cache_mode(unsigned pat_val, char *msg)
+{
+ enum page_cache_mode cache;
+ char *cache_mode;
+
+ switch (pat_val) {
+ case PAT_UC: cache = CM(UC); cache_mode = "UC "; break;
+ case PAT_WC: cache = CM(WC); cache_mode = "WC "; break;
+ case PAT_WT: cache = CM(WT); cache_mode = "WT "; break;
+ case PAT_WP: cache = CM(WP); cache_mode = "WP "; break;
+ case PAT_WB: cache = CM(WB); cache_mode = "WB "; break;
+ case PAT_UC_MINUS: cache = CM(UC_MINUS); cache_mode = "UC- "; break;
+ default: cache = CM(WB); cache_mode = "WB "; break;
+ }
+
+ memcpy(msg, cache_mode, 4);
+
+ return cache;
+}
+
+#undef CM
+
+/*
+ * Update the cache mode to pgprot translation tables according to PAT
+ * configuration.
+ * Using lower indices is preferred, so we start with highest index.
+ */
+void pat_init_cache_modes(void)
+{
+ int i;
+ enum page_cache_mode cache;
+ char pat_msg[33];
+ u64 pat;
+
+ rdmsrl(MSR_IA32_CR_PAT, pat);
+ pat_msg[32] = 0;
+ for (i = 7; i >= 0; i--) {
+ cache = pat_get_cache_mode((pat >> (i * 8)) & 7,
+ pat_msg + 4 * i);
+ update_cache_mode_entry(i, cache);
+ }
+ pr_info("PAT configuration [0-7]: %s\n", pat_msg);
+}
+
#define PAT(x, y) ((u64)PAT_ ## y << ((x)*8))
void pat_init(void)
@@ -124,8 +240,7 @@ void pat_init(void)
wrmsrl(MSR_IA32_CR_PAT, pat);
if (boot_cpu)
- printk(KERN_INFO "x86 PAT enabled: cpu %d, old 0x%Lx, new 0x%Lx\n",
- smp_processor_id(), boot_pat_state, pat);
+ pat_init_cache_modes();
}
#undef PAT
@@ -139,20 +254,21 @@ static DEFINE_SPINLOCK(memtype_lock); /* protects memtype accesses */
* The intersection is based on "Effective Memory Type" tables in IA-32
* SDM vol 3a
*/
-static unsigned long pat_x_mtrr_type(u64 start, u64 end, unsigned long req_type)
+static unsigned long pat_x_mtrr_type(u64 start, u64 end,
+ enum page_cache_mode req_type)
{
/*
* Look for MTRR hint to get the effective type in case where PAT
* request is for WB.
*/
- if (req_type == _PAGE_CACHE_WB) {
+ if (req_type == _PAGE_CACHE_MODE_WB) {
u8 mtrr_type;
mtrr_type = mtrr_type_lookup(start, end);
if (mtrr_type != MTRR_TYPE_WRBACK)
- return _PAGE_CACHE_UC_MINUS;
+ return _PAGE_CACHE_MODE_UC_MINUS;
- return _PAGE_CACHE_WB;
+ return _PAGE_CACHE_MODE_WB;
}
return req_type;
@@ -207,25 +323,26 @@ static int pat_pagerange_is_ram(resource_size_t start, resource_size_t end)
* - Find the memtype of all the pages in the range, look for any conflicts
* - In case of no conflicts, set the new memtype for pages in the range
*/
-static int reserve_ram_pages_type(u64 start, u64 end, unsigned long req_type,
- unsigned long *new_type)
+static int reserve_ram_pages_type(u64 start, u64 end,
+ enum page_cache_mode req_type,
+ enum page_cache_mode *new_type)
{
struct page *page;
u64 pfn;
- if (req_type == _PAGE_CACHE_UC) {
+ if (req_type == _PAGE_CACHE_MODE_UC) {
/* We do not support strong UC */
WARN_ON_ONCE(1);
- req_type = _PAGE_CACHE_UC_MINUS;
+ req_type = _PAGE_CACHE_MODE_UC_MINUS;
}
for (pfn = (start >> PAGE_SHIFT); pfn < (end >> PAGE_SHIFT); ++pfn) {
- unsigned long type;
+ enum page_cache_mode type;
page = pfn_to_page(pfn);
type = get_page_memtype(page);
if (type != -1) {
- printk(KERN_INFO "reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%lx, req 0x%lx\n",
+ pr_info("reserve_ram_pages_type failed [mem %#010Lx-%#010Lx], track 0x%x, req 0x%x\n",
start, end - 1, type, req_type);
if (new_type)
*new_type = type;
@@ -258,21 +375,21 @@ static int free_ram_pages_type(u64 start, u64 end)
/*
* req_type typically has one of the:
- * - _PAGE_CACHE_WB
- * - _PAGE_CACHE_WC
- * - _PAGE_CACHE_UC_MINUS
- * - _PAGE_CACHE_UC
+ * - _PAGE_CACHE_MODE_WB
+ * - _PAGE_CACHE_MODE_WC
+ * - _PAGE_CACHE_MODE_UC_MINUS
+ * - _PAGE_CACHE_MODE_UC
*
* If new_type is NULL, function will return an error if it cannot reserve the
* region with req_type. If new_type is non-NULL, function will return
* available type in new_type in case of no error. In case of any error
* it will return a negative return value.
*/
-int reserve_memtype(u64 start, u64 end, unsigned long req_type,
- unsigned long *new_type)
+int reserve_memtype(u64 start, u64 end, enum page_cache_mode req_type,
+ enum page_cache_mode *new_type)
{
struct memtype *new;
- unsigned long actual_type;
+ enum page_cache_mode actual_type;
int is_range_ram;
int err = 0;
@@ -281,10 +398,10 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
if (!pat_enabled) {
/* This is identical to page table setting without PAT */
if (new_type) {
- if (req_type == _PAGE_CACHE_WC)
- *new_type = _PAGE_CACHE_UC_MINUS;
+ if (req_type == _PAGE_CACHE_MODE_WC)
+ *new_type = _PAGE_CACHE_MODE_UC_MINUS;
else
- *new_type = req_type & _PAGE_CACHE_MASK;
+ *new_type = req_type;
}
return 0;
}
@@ -292,7 +409,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
/* Low ISA region is always mapped WB in page table. No need to track */
if (x86_platform.is_untracked_pat_range(start, end)) {
if (new_type)
- *new_type = _PAGE_CACHE_WB;
+ *new_type = _PAGE_CACHE_MODE_WB;
return 0;
}
@@ -302,7 +419,7 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
* tools and ACPI tools). Use WB request for WB memory and use
* UC_MINUS otherwise.
*/
- actual_type = pat_x_mtrr_type(start, end, req_type & _PAGE_CACHE_MASK);
+ actual_type = pat_x_mtrr_type(start, end, req_type);
if (new_type)
*new_type = actual_type;
@@ -394,12 +511,12 @@ int free_memtype(u64 start, u64 end)
*
* Only to be called when PAT is enabled
*
- * Returns _PAGE_CACHE_WB, _PAGE_CACHE_WC, _PAGE_CACHE_UC_MINUS or
- * _PAGE_CACHE_UC
+ * Returns _PAGE_CACHE_MODE_WB, _PAGE_CACHE_MODE_WC, _PAGE_CACHE_MODE_UC_MINUS
+ * or _PAGE_CACHE_MODE_UC
*/
-static unsigned long lookup_memtype(u64 paddr)
+static enum page_cache_mode lookup_memtype(u64 paddr)
{
- int rettype = _PAGE_CACHE_WB;
+ enum page_cache_mode rettype = _PAGE_CACHE_MODE_WB;
struct memtype *entry;
if (x86_platform.is_untracked_pat_range(paddr, paddr + PAGE_SIZE))
@@ -414,7 +531,7 @@ static unsigned long lookup_memtype(u64 paddr)
* default state and not reserved, and hence of type WB
*/
if (rettype == -1)
- rettype = _PAGE_CACHE_WB;
+ rettype = _PAGE_CACHE_MODE_WB;
return rettype;
}
@@ -425,7 +542,7 @@ static unsigned long lookup_memtype(u64 paddr)
if (entry != NULL)
rettype = entry->type;
else
- rettype = _PAGE_CACHE_UC_MINUS;
+ rettype = _PAGE_CACHE_MODE_UC_MINUS;
spin_unlock(&memtype_lock);
return rettype;
@@ -442,11 +559,11 @@ static unsigned long lookup_memtype(u64 paddr)
* On failure, returns non-zero
*/
int io_reserve_memtype(resource_size_t start, resource_size_t end,
- unsigned long *type)
+ enum page_cache_mode *type)
{
resource_size_t size = end - start;
- unsigned long req_type = *type;
- unsigned long new_type;
+ enum page_cache_mode req_type = *type;
+ enum page_cache_mode new_type;
int ret;
WARN_ON_ONCE(iomem_map_sanity_check(start, size));
@@ -520,13 +637,13 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
unsigned long size, pgprot_t *vma_prot)
{
- unsigned long flags = _PAGE_CACHE_WB;
+ enum page_cache_mode pcm = _PAGE_CACHE_MODE_WB;
if (!range_is_allowed(pfn, size))
return 0;
if (file->f_flags & O_DSYNC)
- flags = _PAGE_CACHE_UC_MINUS;
+ pcm = _PAGE_CACHE_MODE_UC_MINUS;
#ifdef CONFIG_X86_32
/*
@@ -543,12 +660,12 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
boot_cpu_has(X86_FEATURE_CYRIX_ARR) ||
boot_cpu_has(X86_FEATURE_CENTAUR_MCR)) &&
(pfn << PAGE_SHIFT) >= __pa(high_memory)) {
- flags = _PAGE_CACHE_UC;
+ pcm = _PAGE_CACHE_MODE_UC;
}
#endif
*vma_prot = __pgprot((pgprot_val(*vma_prot) & ~_PAGE_CACHE_MASK) |
- flags);
+ cachemode2protval(pcm));
return 1;
}
@@ -556,7 +673,8 @@ int phys_mem_access_prot_allowed(struct file *file, unsigned long pfn,
* Change the memory type for the physial address range in kernel identity
* mapping space if that range is a part of identity map.
*/
-int kernel_map_sync_memtype(u64 base, unsigned long size, unsigned long flags)
+int kernel_map_sync_memtype(u64 base, unsigned long size,
+ enum page_cache_mode pcm)
{
unsigned long id_sz;
@@ -574,11 +692,11 @@ int kernel_map_sync_memtype(u64 base, unsigned long size, unsigned long flags)
__pa(high_memory) - base :
size;
- if (ioremap_change_attr((unsigned long)__va(base), id_sz, flags) < 0) {
+ if (ioremap_change_attr((unsigned long)__va(base), id_sz, pcm) < 0) {
printk(KERN_INFO "%s:%d ioremap_change_attr failed %s "
"for [mem %#010Lx-%#010Lx]\n",
current->comm, current->pid,
- cattr_name(flags),
+ cattr_name(pcm),
base, (unsigned long long)(base + size-1));
return -EINVAL;
}
@@ -595,8 +713,8 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
{
int is_ram = 0;
int ret;
- unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK);
- unsigned long flags = want_flags;
+ enum page_cache_mode want_pcm = pgprot2cachemode(*vma_prot);
+ enum page_cache_mode pcm = want_pcm;
is_ram = pat_pagerange_is_ram(paddr, paddr + size);
@@ -609,36 +727,36 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
if (!pat_enabled)
return 0;
- flags = lookup_memtype(paddr);
- if (want_flags != flags) {
+ pcm = lookup_memtype(paddr);
+ if (want_pcm != pcm) {
printk(KERN_WARNING "%s:%d map pfn RAM range req %s for [mem %#010Lx-%#010Lx], got %s\n",
current->comm, current->pid,
- cattr_name(want_flags),
+ cattr_name(want_pcm),
(unsigned long long)paddr,
(unsigned long long)(paddr + size - 1),
- cattr_name(flags));
+ cattr_name(pcm));
*vma_prot = __pgprot((pgprot_val(*vma_prot) &
- (~_PAGE_CACHE_MASK)) |
- flags);
+ (~_PAGE_CACHE_MASK)) |
+ cachemode2protval(pcm));
}
return 0;
}
- ret = reserve_memtype(paddr, paddr + size, want_flags, &flags);
+ ret = reserve_memtype(paddr, paddr + size, want_pcm, &pcm);
if (ret)
return ret;
- if (flags != want_flags) {
+ if (pcm != want_pcm) {
if (strict_prot ||
- !is_new_memtype_allowed(paddr, size, want_flags, flags)) {
+ !is_new_memtype_allowed(paddr, size, want_pcm, pcm)) {
free_memtype(paddr, paddr + size);
printk(KERN_ERR "%s:%d map pfn expected mapping type %s"
" for [mem %#010Lx-%#010Lx], got %s\n",
current->comm, current->pid,
- cattr_name(want_flags),
+ cattr_name(want_pcm),
(unsigned long long)paddr,
(unsigned long long)(paddr + size - 1),
- cattr_name(flags));
+ cattr_name(pcm));
return -EINVAL;
}
/*
@@ -647,10 +765,10 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
*/
*vma_prot = __pgprot((pgprot_val(*vma_prot) &
(~_PAGE_CACHE_MASK)) |
- flags);
+ cachemode2protval(pcm));
}
- if (kernel_map_sync_memtype(paddr, size, flags) < 0) {
+ if (kernel_map_sync_memtype(paddr, size, pcm) < 0) {
free_memtype(paddr, paddr + size);
return -EINVAL;
}
@@ -709,7 +827,7 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
unsigned long pfn, unsigned long addr, unsigned long size)
{
resource_size_t paddr = (resource_size_t)pfn << PAGE_SHIFT;
- unsigned long flags;
+ enum page_cache_mode pcm;
/* reserve the whole chunk starting from paddr */
if (addr == vma->vm_start && size == (vma->vm_end - vma->vm_start)) {
@@ -728,18 +846,18 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
* For anything smaller than the vma size we set prot based on the
* lookup.
*/
- flags = lookup_memtype(paddr);
+ pcm = lookup_memtype(paddr);
/* Check memtype for the remaining pages */
while (size > PAGE_SIZE) {
size -= PAGE_SIZE;
paddr += PAGE_SIZE;
- if (flags != lookup_memtype(paddr))
+ if (pcm != lookup_memtype(paddr))
return -EINVAL;
}
*prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
- flags);
+ cachemode2protval(pcm));
return 0;
}
@@ -747,15 +865,15 @@ int track_pfn_remap(struct vm_area_struct *vma, pgprot_t *prot,
int track_pfn_insert(struct vm_area_struct *vma, pgprot_t *prot,
unsigned long pfn)
{
- unsigned long flags;
+ enum page_cache_mode pcm;
if (!pat_enabled)
return 0;
/* Set prot based on lookup */
- flags = lookup_memtype((resource_size_t)pfn << PAGE_SHIFT);
+ pcm = lookup_memtype((resource_size_t)pfn << PAGE_SHIFT);
*prot = __pgprot((pgprot_val(vma->vm_page_prot) & (~_PAGE_CACHE_MASK)) |
- flags);
+ cachemode2protval(pcm));
return 0;
}
@@ -791,7 +909,8 @@ void untrack_pfn(struct vm_area_struct *vma, unsigned long pfn,
pgprot_t pgprot_writecombine(pgprot_t prot)
{
if (pat_enabled)
- return __pgprot(pgprot_val(prot) | _PAGE_CACHE_WC);
+ return __pgprot(pgprot_val(prot) |
+ cachemode2protval(_PAGE_CACHE_MODE_WC));
else
return pgprot_noncached(prot);
}
@@ -824,7 +943,7 @@ static void *memtype_seq_start(struct seq_file *seq, loff_t *pos)
{
if (*pos == 0) {
++*pos;
- seq_printf(seq, "PAT memtype list:\n");
+ seq_puts(seq, "PAT memtype list:\n");
}
return memtype_get_idx(*pos);
diff --git a/arch/x86/mm/pat_internal.h b/arch/x86/mm/pat_internal.h
index 77e5ba1..f641162 100644
--- a/arch/x86/mm/pat_internal.h
+++ b/arch/x86/mm/pat_internal.h
@@ -10,30 +10,32 @@ struct memtype {
u64 start;
u64 end;
u64 subtree_max_end;
- unsigned long type;
+ enum page_cache_mode type;
struct rb_node rb;
};
-static inline char *cattr_name(unsigned long flags)
+static inline char *cattr_name(enum page_cache_mode pcm)
{
- switch (flags & _PAGE_CACHE_MASK) {
- case _PAGE_CACHE_UC: return "uncached";
- case _PAGE_CACHE_UC_MINUS: return "uncached-minus";
- case _PAGE_CACHE_WB: return "write-back";
- case _PAGE_CACHE_WC: return "write-combining";
- default: return "broken";
+ switch (pcm) {
+ case _PAGE_CACHE_MODE_UC: return "uncached";
+ case _PAGE_CACHE_MODE_UC_MINUS: return "uncached-minus";
+ case _PAGE_CACHE_MODE_WB: return "write-back";
+ case _PAGE_CACHE_MODE_WC: return "write-combining";
+ case _PAGE_CACHE_MODE_WT: return "write-through";
+ case _PAGE_CACHE_MODE_WP: return "write-protected";
+ default: return "broken";
}
}
#ifdef CONFIG_X86_PAT
extern int rbt_memtype_check_insert(struct memtype *new,
- unsigned long *new_type);
+ enum page_cache_mode *new_type);
extern struct memtype *rbt_memtype_erase(u64 start, u64 end);
extern struct memtype *rbt_memtype_lookup(u64 addr);
extern int rbt_memtype_copy_nth_element(struct memtype *out, loff_t pos);
#else
static inline int rbt_memtype_check_insert(struct memtype *new,
- unsigned long *new_type)
+ enum page_cache_mode *new_type)
{ return 0; }
static inline struct memtype *rbt_memtype_erase(u64 start, u64 end)
{ return NULL; }
diff --git a/arch/x86/mm/pat_rbtree.c b/arch/x86/mm/pat_rbtree.c
index 415f6c4..6582adc 100644
--- a/arch/x86/mm/pat_rbtree.c
+++ b/arch/x86/mm/pat_rbtree.c
@@ -122,11 +122,12 @@ static struct memtype *memtype_rb_exact_match(struct rb_root *root,
static int memtype_rb_check_conflict(struct rb_root *root,
u64 start, u64 end,
- unsigned long reqtype, unsigned long *newtype)
+ enum page_cache_mode reqtype,
+ enum page_cache_mode *newtype)
{
struct rb_node *node;
struct memtype *match;
- int found_type = reqtype;
+ enum page_cache_mode found_type = reqtype;
match = memtype_rb_lowest_match(&memtype_rbroot, start, end);
if (match == NULL)
@@ -187,7 +188,8 @@ static void memtype_rb_insert(struct rb_root *root, struct memtype *newdata)
rb_insert_augmented(&newdata->rb, root, &memtype_rb_augment_cb);
}
-int rbt_memtype_check_insert(struct memtype *new, unsigned long *ret_type)
+int rbt_memtype_check_insert(struct memtype *new,
+ enum page_cache_mode *ret_type)
{
int err = 0;
diff --git a/arch/x86/pci/i386.c b/arch/x86/pci/i386.c
index 37c1435..9b18ef3 100644
--- a/arch/x86/pci/i386.c
+++ b/arch/x86/pci/i386.c
@@ -433,14 +433,14 @@ int pci_mmap_page_range(struct pci_dev *dev, struct vm_area_struct *vma,
return -EINVAL;
if (pat_enabled && write_combine)
- prot |= _PAGE_CACHE_WC;
+ prot |= cachemode2protval(_PAGE_CACHE_MODE_WC);
else if (pat_enabled || boot_cpu_data.x86 > 3)
/*
* ioremap() and ioremap_nocache() defaults to UC MINUS for now.
* To avoid attribute conflicts, request UC MINUS here
* as well.
*/
- prot |= _PAGE_CACHE_UC_MINUS;
+ prot |= cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
vma->vm_page_prot = __pgprot(prot);
diff --git a/arch/x86/pci/numachip.c b/arch/x86/pci/numachip.c
index 7307d9d..2e565e6 100644
--- a/arch/x86/pci/numachip.c
+++ b/arch/x86/pci/numachip.c
@@ -103,7 +103,7 @@ static int pci_mmcfg_write_numachip(unsigned int seg, unsigned int bus,
return 0;
}
-const struct pci_raw_ops pci_mmcfg_numachip = {
+static const struct pci_raw_ops pci_mmcfg_numachip = {
.read = pci_mmcfg_read_numachip,
.write = pci_mmcfg_write_numachip,
};
diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c
index 093f5f4..1819a91 100644
--- a/arch/x86/pci/xen.c
+++ b/arch/x86/pci/xen.c
@@ -229,7 +229,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
return 1;
list_for_each_entry(msidesc, &dev->msi_list, list) {
- __read_msi_msg(msidesc, &msg);
+ __pci_read_msi_msg(msidesc, &msg);
pirq = MSI_ADDR_EXT_DEST_ID(msg.address_hi) |
((msg.address_lo >> MSI_ADDR_DEST_ID_SHIFT) & 0xff);
if (msg.data != XEN_PIRQ_MSI_DATA ||
@@ -240,7 +240,7 @@ static int xen_hvm_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
goto error;
}
xen_msi_compose_msg(dev, pirq, &msg);
- __write_msi_msg(msidesc, &msg);
+ __pci_write_msi_msg(msidesc, &msg);
dev_dbg(&dev->dev, "xen: msi bound to pirq=%d\n", pirq);
} else {
dev_dbg(&dev->dev,
@@ -394,14 +394,7 @@ static void xen_teardown_msi_irq(unsigned int irq)
{
xen_destroy_irq(irq);
}
-static u32 xen_nop_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
-{
- return 0;
-}
-static u32 xen_nop_msix_mask_irq(struct msi_desc *desc, u32 flag)
-{
- return 0;
-}
+
#endif
int __init pci_xen_init(void)
@@ -425,8 +418,7 @@ int __init pci_xen_init(void)
x86_msi.setup_msi_irqs = xen_setup_msi_irqs;
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
x86_msi.teardown_msi_irqs = xen_teardown_msi_irqs;
- x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
- x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
+ pci_msi_ignore_mask = 1;
#endif
return 0;
}
@@ -506,8 +498,7 @@ int __init pci_xen_initial_domain(void)
x86_msi.setup_msi_irqs = xen_initdom_setup_msi_irqs;
x86_msi.teardown_msi_irq = xen_teardown_msi_irq;
x86_msi.restore_msi_irqs = xen_initdom_restore_msi_irqs;
- x86_msi.msi_mask_irq = xen_nop_msi_mask_irq;
- x86_msi.msix_mask_irq = xen_nop_msix_mask_irq;
+ pci_msi_ignore_mask = 1;
#endif
xen_setup_acpi_sci();
__acpi_register_gsi = acpi_register_gsi_xen;
diff --git a/arch/x86/platform/efi/efi_64.c b/arch/x86/platform/efi/efi_64.c
index 35aecb6..17e80d8 100644
--- a/arch/x86/platform/efi/efi_64.c
+++ b/arch/x86/platform/efi/efi_64.c
@@ -48,8 +48,7 @@ static unsigned long efi_flags __initdata;
* We allocate runtime services regions bottom-up, starting from -4G, i.e.
* 0xffff_ffff_0000_0000 and limit EFI VA mapping space to 64G.
*/
-static u64 efi_va = -4 * (1UL << 30);
-#define EFI_VA_END (-68 * (1UL << 30))
+static u64 efi_va = EFI_VA_START;
/*
* Scratch space used for switching the pagetable in the EFI stub
diff --git a/arch/x86/platform/uv/tlb_uv.c b/arch/x86/platform/uv/tlb_uv.c
index 3968d67..9947985 100644
--- a/arch/x86/platform/uv/tlb_uv.c
+++ b/arch/x86/platform/uv/tlb_uv.c
@@ -1367,23 +1367,25 @@ static int ptc_seq_show(struct seq_file *file, void *data)
cpu = *(loff_t *)data;
if (!cpu) {
- seq_printf(file,
- "# cpu bauoff sent stime self locals remotes ncpus localhub ");
- seq_printf(file,
- "remotehub numuvhubs numuvhubs16 numuvhubs8 ");
- seq_printf(file,
- "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries ");
- seq_printf(file,
- "rok resetp resett giveup sto bz throt disable ");
- seq_printf(file,
- "enable wars warshw warwaits enters ipidis plugged ");
- seq_printf(file,
- "ipiover glim cong swack recv rtime all one mult ");
- seq_printf(file,
- "none retry canc nocan reset rcan\n");
+ seq_puts(file,
+ "# cpu bauoff sent stime self locals remotes ncpus localhub ");
+ seq_puts(file, "remotehub numuvhubs numuvhubs16 numuvhubs8 ");
+ seq_puts(file,
+ "numuvhubs4 numuvhubs2 numuvhubs1 dto snacks retries ");
+ seq_puts(file,
+ "rok resetp resett giveup sto bz throt disable ");
+ seq_puts(file,
+ "enable wars warshw warwaits enters ipidis plugged ");
+ seq_puts(file,
+ "ipiover glim cong swack recv rtime all one mult ");
+ seq_puts(file, "none retry canc nocan reset rcan\n");
}
if (cpu < num_possible_cpus() && cpu_online(cpu)) {
bcp = &per_cpu(bau_control, cpu);
+ if (bcp->nobau) {
+ seq_printf(file, "cpu %d bau disabled\n", cpu);
+ return 0;
+ }
stat = bcp->statp;
/* source side statistics */
seq_printf(file,
diff --git a/arch/x86/purgatory/Makefile b/arch/x86/purgatory/Makefile
index f52e033..2c835e3 100644
--- a/arch/x86/purgatory/Makefile
+++ b/arch/x86/purgatory/Makefile
@@ -24,6 +24,7 @@ quiet_cmd_bin2c = BIN2C $@
$(obj)/kexec-purgatory.c: $(obj)/purgatory.ro FORCE
$(call if_changed,bin2c)
+ @:
obj-$(CONFIG_KEXEC_FILE) += kexec-purgatory.o
diff --git a/arch/x86/tools/insn_sanity.c b/arch/x86/tools/insn_sanity.c
index 872eb60..ba70ff2 100644
--- a/arch/x86/tools/insn_sanity.c
+++ b/arch/x86/tools/insn_sanity.c
@@ -254,7 +254,7 @@ int main(int argc, char **argv)
continue;
/* Decode an instruction */
- insn_init(&insn, insn_buf, x86_64);
+ insn_init(&insn, insn_buf, sizeof(insn_buf), x86_64);
insn_get_length(&insn);
if (insn.next_byte <= insn.kaddr ||
diff --git a/arch/x86/tools/relocs.c b/arch/x86/tools/relocs.c
index a5efb21..0c2fae8 100644
--- a/arch/x86/tools/relocs.c
+++ b/arch/x86/tools/relocs.c
@@ -20,7 +20,10 @@ struct relocs {
static struct relocs relocs16;
static struct relocs relocs32;
+#if ELF_BITS == 64
+static struct relocs relocs32neg;
static struct relocs relocs64;
+#endif
struct section {
Elf_Shdr shdr;
@@ -762,11 +765,16 @@ static int do_reloc64(struct section *sec, Elf_Rel *rel, ElfW(Sym) *sym,
switch (r_type) {
case R_X86_64_NONE:
+ /* NONE can be ignored. */
+ break;
+
case R_X86_64_PC32:
/*
- * NONE can be ignored and PC relative relocations don't
- * need to be adjusted.
+ * PC relative relocations don't need to be adjusted unless
+ * referencing a percpu symbol.
*/
+ if (is_percpu_sym(sym, symname))
+ add_reloc(&relocs32neg, offset);
break;
case R_X86_64_32:
@@ -986,7 +994,10 @@ static void emit_relocs(int as_text, int use_real_mode)
/* Order the relocations for more efficient processing */
sort_relocs(&relocs16);
sort_relocs(&relocs32);
+#if ELF_BITS == 64
+ sort_relocs(&relocs32neg);
sort_relocs(&relocs64);
+#endif
/* Print the relocations */
if (as_text) {
@@ -1007,14 +1018,21 @@ static void emit_relocs(int as_text, int use_real_mode)
for (i = 0; i < relocs32.count; i++)
write_reloc(relocs32.offset[i], stdout);
} else {
- if (ELF_BITS == 64) {
- /* Print a stop */
- write_reloc(0, stdout);
+#if ELF_BITS == 64
+ /* Print a stop */
+ write_reloc(0, stdout);
- /* Now print each relocation */
- for (i = 0; i < relocs64.count; i++)
- write_reloc(relocs64.offset[i], stdout);
- }
+ /* Now print each relocation */
+ for (i = 0; i < relocs64.count; i++)
+ write_reloc(relocs64.offset[i], stdout);
+
+ /* Print a stop */
+ write_reloc(0, stdout);
+
+ /* Now print each inverse 32-bit relocation */
+ for (i = 0; i < relocs32neg.count; i++)
+ write_reloc(relocs32neg.offset[i], stdout);
+#endif
/* Print a stop */
write_reloc(0, stdout);
diff --git a/arch/x86/tools/test_get_len.c b/arch/x86/tools/test_get_len.c
index 13403fc..56f04db 100644
--- a/arch/x86/tools/test_get_len.c
+++ b/arch/x86/tools/test_get_len.c
@@ -149,7 +149,7 @@ int main(int argc, char **argv)
break;
}
/* Decode an instruction */
- insn_init(&insn, insn_buf, x86_64);
+ insn_init(&insn, insn_buf, sizeof(insn_buf), x86_64);
insn_get_length(&insn);
if (insn.length != nb) {
warnings++;
diff --git a/arch/x86/vdso/vgetcpu.c b/arch/x86/vdso/vgetcpu.c
index 2f94b03..8ec3d1f 100644
--- a/arch/x86/vdso/vgetcpu.c
+++ b/arch/x86/vdso/vgetcpu.c
@@ -7,9 +7,7 @@
#include <linux/kernel.h>
#include <linux/getcpu.h>
-#include <linux/jiffies.h>
#include <linux/time.h>
-#include <asm/vsyscall.h>
#include <asm/vgtod.h>
notrace long
diff --git a/arch/x86/vdso/vma.c b/arch/x86/vdso/vma.c
index 970463b..009495b 100644
--- a/arch/x86/vdso/vma.c
+++ b/arch/x86/vdso/vma.c
@@ -1,7 +1,8 @@
/*
- * Set up the VMAs to tell the VM about the vDSO.
* Copyright 2007 Andi Kleen, SUSE Labs.
* Subject to the GPL, v.2
+ *
+ * This contains most of the x86 vDSO kernel-side code.
*/
#include <linux/mm.h>
#include <linux/err.h>
@@ -10,17 +11,17 @@
#include <linux/init.h>
#include <linux/random.h>
#include <linux/elf.h>
-#include <asm/vsyscall.h>
+#include <linux/cpu.h>
#include <asm/vgtod.h>
#include <asm/proto.h>
#include <asm/vdso.h>
+#include <asm/vvar.h>
#include <asm/page.h>
#include <asm/hpet.h>
+#include <asm/desc.h>
#if defined(CONFIG_X86_64)
unsigned int __read_mostly vdso64_enabled = 1;
-
-extern unsigned short vdso_sync_cpuid;
#endif
void __init init_vdso_image(const struct vdso_image *image)
@@ -38,20 +39,6 @@ void __init init_vdso_image(const struct vdso_image *image)
image->alt_len));
}
-#if defined(CONFIG_X86_64)
-static int __init init_vdso(void)
-{
- init_vdso_image(&vdso_image_64);
-
-#ifdef CONFIG_X86_X32_ABI
- init_vdso_image(&vdso_image_x32);
-#endif
-
- return 0;
-}
-subsys_initcall(init_vdso);
-#endif
-
struct linux_binprm;
/* Put the vdso above the (randomized) stack with another randomized offset.
@@ -238,3 +225,63 @@ static __init int vdso_setup(char *s)
}
__setup("vdso=", vdso_setup);
#endif
+
+#ifdef CONFIG_X86_64
+static void vgetcpu_cpu_init(void *arg)
+{
+ int cpu = smp_processor_id();
+ struct desc_struct d = { };
+ unsigned long node = 0;
+#ifdef CONFIG_NUMA
+ node = cpu_to_node(cpu);
+#endif
+ if (cpu_has(&cpu_data(cpu), X86_FEATURE_RDTSCP))
+ write_rdtscp_aux((node << 12) | cpu);
+
+ /*
+ * Store cpu number in limit so that it can be loaded
+ * quickly in user space in vgetcpu. (12 bits for the CPU
+ * and 8 bits for the node)
+ */
+ d.limit0 = cpu | ((node & 0xf) << 12);
+ d.limit = node >> 4;
+ d.type = 5; /* RO data, expand down, accessed */
+ d.dpl = 3; /* Visible to user code */
+ d.s = 1; /* Not a system segment */
+ d.p = 1; /* Present */
+ d.d = 1; /* 32-bit */
+
+ write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_PER_CPU, &d, DESCTYPE_S);
+}
+
+static int
+vgetcpu_cpu_notifier(struct notifier_block *n, unsigned long action, void *arg)
+{
+ long cpu = (long)arg;
+
+ if (action == CPU_ONLINE || action == CPU_ONLINE_FROZEN)
+ smp_call_function_single(cpu, vgetcpu_cpu_init, NULL, 1);
+
+ return NOTIFY_DONE;
+}
+
+static int __init init_vdso(void)
+{
+ init_vdso_image(&vdso_image_64);
+
+#ifdef CONFIG_X86_X32_ABI
+ init_vdso_image(&vdso_image_x32);
+#endif
+
+ cpu_notifier_register_begin();
+
+ on_each_cpu(vgetcpu_cpu_init, NULL, 1);
+ /* notifier priority > KVM */
+ __hotcpu_notifier(vgetcpu_cpu_notifier, 30);
+
+ cpu_notifier_register_done();
+
+ return 0;
+}
+subsys_initcall(init_vdso);
+#endif /* CONFIG_X86_64 */
diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index fac5e4f..6bf3a13 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -1100,12 +1100,6 @@ static int xen_write_msr_safe(unsigned int msr, unsigned low, unsigned high)
/* Fast syscall setup is all done in hypercalls, so
these are all ignored. Stub them out here to stop
Xen console noise. */
- break;
-
- case MSR_IA32_CR_PAT:
- if (smp_processor_id() == 0)
- xen_set_pat(((u64)high << 32) | low);
- break;
default:
ret = native_write_msr_safe(msr, low, high);
@@ -1561,10 +1555,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
/* Prevent unwanted bits from being set in PTEs. */
__supported_pte_mask &= ~_PAGE_GLOBAL;
-#if 0
- if (!xen_initial_domain())
-#endif
- __supported_pte_mask &= ~(_PAGE_PWT | _PAGE_PCD);
/*
* Prevent page tables from being allocated in highmem, even
@@ -1618,14 +1608,6 @@ asmlinkage __visible void __init xen_start_kernel(void)
*/
acpi_numa = -1;
#endif
-#ifdef CONFIG_X86_PAT
- /*
- * For right now disable the PAT. We should remove this once
- * git commit 8eaffa67b43e99ae581622c5133e20b0f48bcef1
- * (xen/pat: Disable PAT support for now) is reverted.
- */
- pat_enabled = 0;
-#endif
/* Don't do the full vcpu_info placement stuff until we have a
possible map and a non-dummy shared_info. */
per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
@@ -1636,6 +1618,13 @@ asmlinkage __visible void __init xen_start_kernel(void)
xen_raw_console_write("mapping kernel into physical memory\n");
xen_setup_kernel_pagetable((pgd_t *)xen_start_info->pt_base, xen_start_info->nr_pages);
+ /*
+ * Modify the cache mode translation tables to match Xen's PAT
+ * configuration.
+ */
+
+ pat_init_cache_modes();
+
/* keep using Xen gdt for now; no urgent need to change it */
#ifdef CONFIG_X86_32
diff --git a/arch/x86/xen/mmu.c b/arch/x86/xen/mmu.c
index a8a1a3d..8c8298d 100644
--- a/arch/x86/xen/mmu.c
+++ b/arch/x86/xen/mmu.c
@@ -410,13 +410,7 @@ static pteval_t pte_pfn_to_mfn(pteval_t val)
__visible pteval_t xen_pte_val(pte_t pte)
{
pteval_t pteval = pte.pte;
-#if 0
- /* If this is a WC pte, convert back from Xen WC to Linux WC */
- if ((pteval & (_PAGE_PAT | _PAGE_PCD | _PAGE_PWT)) == _PAGE_PAT) {
- WARN_ON(!pat_enabled);
- pteval = (pteval & ~_PAGE_PAT) | _PAGE_PWT;
- }
-#endif
+
return pte_mfn_to_pfn(pteval);
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pte_val);
@@ -427,47 +421,8 @@ __visible pgdval_t xen_pgd_val(pgd_t pgd)
}
PV_CALLEE_SAVE_REGS_THUNK(xen_pgd_val);
-/*
- * Xen's PAT setup is part of its ABI, though I assume entries 6 & 7
- * are reserved for now, to correspond to the Intel-reserved PAT
- * types.
- *
- * We expect Linux's PAT set as follows:
- *
- * Idx PTE flags Linux Xen Default
- * 0 WB WB WB
- * 1 PWT WC WT WT
- * 2 PCD UC- UC- UC-
- * 3 PCD PWT UC UC UC
- * 4 PAT WB WC WB
- * 5 PAT PWT WC WP WT
- * 6 PAT PCD UC- rsv UC-
- * 7 PAT PCD PWT UC rsv UC
- */
-
-void xen_set_pat(u64 pat)
-{
- /* We expect Linux to use a PAT setting of
- * UC UC- WC WB (ignoring the PAT flag) */
- WARN_ON(pat != 0x0007010600070106ull);
-}
-
__visible pte_t xen_make_pte(pteval_t pte)
{
-#if 0
- /* If Linux is trying to set a WC pte, then map to the Xen WC.
- * If _PAGE_PAT is set, then it probably means it is really
- * _PAGE_PSE, so avoid fiddling with the PAT mapping and hope
- * things work out OK...
- *
- * (We should never see kernel mappings with _PAGE_PSE set,
- * but we could see hugetlbfs mappings, I think.).
- */
- if (pat_enabled && !WARN_ON(pte & _PAGE_PAT)) {
- if ((pte & (_PAGE_PCD | _PAGE_PWT)) == _PAGE_PWT)
- pte = (pte & ~(_PAGE_PCD | _PAGE_PWT)) | _PAGE_PAT;
- }
-#endif
pte = pte_pfn_to_mfn(pte);
return native_make_pte(pte);
@@ -1457,8 +1412,10 @@ static int xen_pgd_alloc(struct mm_struct *mm)
page->private = (unsigned long)user_pgd;
if (user_pgd != NULL) {
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
user_pgd[pgd_index(VSYSCALL_ADDR)] =
__pgd(__pa(level3_user_vsyscall) | _PAGE_TABLE);
+#endif
ret = 0;
}
@@ -2021,7 +1978,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
# ifdef CONFIG_HIGHMEM
case FIX_KMAP_BEGIN ... FIX_KMAP_END:
# endif
-#else
+#elif defined(CONFIG_X86_VSYSCALL_EMULATION)
case VSYSCALL_PAGE:
#endif
case FIX_TEXT_POKE0:
@@ -2060,7 +2017,7 @@ static void xen_set_fixmap(unsigned idx, phys_addr_t phys, pgprot_t prot)
__native_set_fixmap(idx, pte);
-#ifdef CONFIG_X86_64
+#ifdef CONFIG_X86_VSYSCALL_EMULATION
/* Replicate changes to map the vsyscall page into the user
pagetable vsyscall mapping. */
if (idx == VSYSCALL_PAGE) {
diff --git a/arch/x86/xen/xen-ops.h b/arch/x86/xen/xen-ops.h
index 28c7e0b..4ab9298 100644
--- a/arch/x86/xen/xen-ops.h
+++ b/arch/x86/xen/xen-ops.h
@@ -33,7 +33,6 @@ extern unsigned long xen_max_p2m_pfn;
void xen_mm_pin_all(void);
void xen_mm_unpin_all(void);
-void xen_set_pat(u64);
char * __init xen_memory_setup(void);
char * xen_auto_xlated_memory_setup(void);
diff --git a/arch/xtensa/include/asm/io.h b/arch/xtensa/include/asm/io.h
index 7494420..fe1600a 100644
--- a/arch/xtensa/include/asm/io.h
+++ b/arch/xtensa/include/asm/io.h
@@ -74,13 +74,6 @@ static inline void iounmap(volatile void __iomem *addr)
#endif /* CONFIG_MMU */
-/*
- * Generic I/O
- */
-#define readb_relaxed readb
-#define readw_relaxed readw
-#define readl_relaxed readl
-
#endif /* __KERNEL__ */
#include <asm-generic/io.h>
diff --git a/block/blk-core.c b/block/blk-core.c
index 0421b53..ea1c4d0 100644
--- a/block/blk-core.c
+++ b/block/blk-core.c
@@ -1266,7 +1266,7 @@ void blk_requeue_request(struct request_queue *q, struct request *rq)
blk_clear_rq_complete(rq);
trace_block_rq_requeue(q, rq);
- if (blk_rq_tagged(rq))
+ if (rq->cmd_flags & REQ_QUEUED)
blk_queue_end_tag(q, rq);
BUG_ON(blk_queued_rq(rq));
@@ -1325,7 +1325,7 @@ void part_round_stats(int cpu, struct hd_struct *part)
}
EXPORT_SYMBOL_GPL(part_round_stats);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static void blk_pm_put_request(struct request *rq)
{
if (rq->q->dev && !(rq->cmd_flags & REQ_PM) && !--rq->q->nr_pending)
@@ -2134,7 +2134,7 @@ void blk_account_io_done(struct request *req)
}
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
/*
* Don't process normal requests when queue is suspended
* or in the process of suspending/resuming
@@ -2554,7 +2554,7 @@ EXPORT_SYMBOL_GPL(blk_unprep_request);
*/
void blk_finish_request(struct request *req, int error)
{
- if (blk_rq_tagged(req))
+ if (req->cmd_flags & REQ_QUEUED)
blk_queue_end_tag(req->q, req);
BUG_ON(blk_queued_rq(req));
@@ -3159,7 +3159,7 @@ void blk_finish_plug(struct blk_plug *plug)
}
EXPORT_SYMBOL(blk_finish_plug);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
/**
* blk_pm_runtime_init - Block layer runtime PM initialization routine
* @q: the queue of the device
diff --git a/block/blk-mq-tag.c b/block/blk-mq-tag.c
index 8317175..728b9a4 100644
--- a/block/blk-mq-tag.c
+++ b/block/blk-mq-tag.c
@@ -584,6 +584,34 @@ int blk_mq_tag_update_depth(struct blk_mq_tags *tags, unsigned int tdepth)
return 0;
}
+/**
+ * blk_mq_unique_tag() - return a tag that is unique queue-wide
+ * @rq: request for which to compute a unique tag
+ *
+ * The tag field in struct request is unique per hardware queue but not over
+ * all hardware queues. Hence this function that returns a tag with the
+ * hardware context index in the upper bits and the per hardware queue tag in
+ * the lower bits.
+ *
+ * Note: When called for a request that is queued on a non-multiqueue request
+ * queue, the hardware context index is set to zero.
+ */
+u32 blk_mq_unique_tag(struct request *rq)
+{
+ struct request_queue *q = rq->q;
+ struct blk_mq_hw_ctx *hctx;
+ int hwq = 0;
+
+ if (q->mq_ops) {
+ hctx = q->mq_ops->map_queue(q, rq->mq_ctx->cpu);
+ hwq = hctx->queue_num;
+ }
+
+ return (hwq << BLK_MQ_UNIQUE_TAG_BITS) |
+ (rq->tag & BLK_MQ_UNIQUE_TAG_MASK);
+}
+EXPORT_SYMBOL(blk_mq_unique_tag);
+
ssize_t blk_mq_tag_sysfs_show(struct blk_mq_tags *tags, char *page)
{
char *orig_page = page;
diff --git a/block/blk-mq.c b/block/blk-mq.c
index 1d016fc..92ceef0 100644
--- a/block/blk-mq.c
+++ b/block/blk-mq.c
@@ -2049,6 +2049,8 @@ static int blk_mq_alloc_rq_maps(struct blk_mq_tag_set *set)
*/
int blk_mq_alloc_tag_set(struct blk_mq_tag_set *set)
{
+ BUILD_BUG_ON(BLK_MQ_MAX_DEPTH > 1 << BLK_MQ_UNIQUE_TAG_BITS);
+
if (!set->nr_hw_queues)
return -EINVAL;
if (!set->queue_depth)
diff --git a/block/elevator.c b/block/elevator.c
index afa3b03..59794d0 100644
--- a/block/elevator.c
+++ b/block/elevator.c
@@ -539,7 +539,7 @@ void elv_bio_merged(struct request_queue *q, struct request *rq,
e->type->ops.elevator_bio_merged_fn(q, rq, bio);
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static void blk_pm_requeue_request(struct request *rq)
{
if (rq->q->dev && !(rq->cmd_flags & REQ_PM))
diff --git a/block/scsi_ioctl.c b/block/scsi_ioctl.c
index b0c2a61..28163fa 100644
--- a/block/scsi_ioctl.c
+++ b/block/scsi_ioctl.c
@@ -142,7 +142,7 @@ static void blk_set_cmd_filter_defaults(struct blk_cmd_filter *filter)
__set_bit(GPCMD_VERIFY_10, filter->read_ok);
__set_bit(VERIFY_16, filter->read_ok);
__set_bit(REPORT_LUNS, filter->read_ok);
- __set_bit(SERVICE_ACTION_IN, filter->read_ok);
+ __set_bit(SERVICE_ACTION_IN_16, filter->read_ok);
__set_bit(RECEIVE_DIAGNOSTIC, filter->read_ok);
__set_bit(MAINTENANCE_IN, filter->read_ok);
__set_bit(GPCMD_READ_BUFFER_CAPACITY, filter->read_ok);
diff --git a/drivers/Kconfig b/drivers/Kconfig
index 1a693d3..af02a8a 100644
--- a/drivers/Kconfig
+++ b/drivers/Kconfig
@@ -1,5 +1,7 @@
menu "Device Drivers"
+source "drivers/amba/Kconfig"
+
source "drivers/base/Kconfig"
source "drivers/bus/Kconfig"
diff --git a/drivers/acpi/Kconfig b/drivers/acpi/Kconfig
index b23fe37..8951cefb 100644
--- a/drivers/acpi/Kconfig
+++ b/drivers/acpi/Kconfig
@@ -360,15 +360,14 @@ config ACPI_BGRT
config ACPI_REDUCED_HARDWARE_ONLY
bool "Hardware-reduced ACPI support only" if EXPERT
def_bool n
- depends on ACPI
help
- This config item changes the way the ACPI code is built. When this
- option is selected, the kernel will use a specialized version of
- ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
- resulting kernel will be smaller but it will also be restricted to
- running in ACPI reduced hardware mode ONLY.
+ This config item changes the way the ACPI code is built. When this
+ option is selected, the kernel will use a specialized version of
+ ACPICA that ONLY supports the ACPI "reduced hardware" mode. The
+ resulting kernel will be smaller but it will also be restricted to
+ running in ACPI reduced hardware mode ONLY.
- If you are unsure what to do, do not enable this option.
+ If you are unsure what to do, do not enable this option.
source "drivers/acpi/apei/Kconfig"
@@ -394,4 +393,27 @@ config ACPI_EXTLOG
driver adds support for that functionality with corresponding
tracepoint which carries that information to userspace.
+menuconfig PMIC_OPREGION
+ bool "PMIC (Power Management Integrated Circuit) operation region support"
+ help
+ Select this option to enable support for ACPI operation
+ region of the PMIC chip. The operation region can be used
+ to control power rails and sensor reading/writing on the
+ PMIC chip.
+
+if PMIC_OPREGION
+config CRC_PMIC_OPREGION
+ bool "ACPI operation region support for CrystalCove PMIC"
+ depends on INTEL_SOC_PMIC
+ help
+ This config adds ACPI operation region support for CrystalCove PMIC.
+
+config XPOWER_PMIC_OPREGION
+ bool "ACPI operation region support for XPower AXP288 PMIC"
+ depends on AXP288_ADC = y
+ help
+ This config adds ACPI operation region support for XPower AXP288 PMIC.
+
+endif
+
endif # ACPI
diff --git a/drivers/acpi/Makefile b/drivers/acpi/Makefile
index c3b2fcb..f74317c 100644
--- a/drivers/acpi/Makefile
+++ b/drivers/acpi/Makefile
@@ -47,6 +47,7 @@ acpi-y += int340x_thermal.o
acpi-y += power.o
acpi-y += event.o
acpi-y += sysfs.o
+acpi-y += property.o
acpi-$(CONFIG_X86) += acpi_cmos_rtc.o
acpi-$(CONFIG_DEBUG_FS) += debugfs.o
acpi-$(CONFIG_ACPI_NUMA) += numa.o
@@ -87,3 +88,7 @@ obj-$(CONFIG_ACPI_PROCESSOR_AGGREGATOR) += acpi_pad.o
obj-$(CONFIG_ACPI_APEI) += apei/
obj-$(CONFIG_ACPI_EXTLOG) += acpi_extlog.o
+
+obj-$(CONFIG_PMIC_OPREGION) += pmic/intel_pmic.o
+obj-$(CONFIG_CRC_PMIC_OPREGION) += pmic/intel_pmic_crc.o
+obj-$(CONFIG_XPOWER_PMIC_OPREGION) += pmic/intel_pmic_xpower.o
diff --git a/drivers/acpi/acpi_lpss.c b/drivers/acpi/acpi_lpss.c
index 93d1606..4f3febf 100644
--- a/drivers/acpi/acpi_lpss.c
+++ b/drivers/acpi/acpi_lpss.c
@@ -1,7 +1,7 @@
/*
* ACPI support for Intel Lynxpoint LPSS.
*
- * Copyright (C) 2013, Intel Corporation
+ * Copyright (C) 2013, 2014, Intel Corporation
* Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
* Rafael J. Wysocki <rafael.j.wysocki@intel.com>
*
@@ -60,6 +60,8 @@ ACPI_MODULE_NAME("acpi_lpss");
#define LPSS_CLK_DIVIDER BIT(2)
#define LPSS_LTR BIT(3)
#define LPSS_SAVE_CTX BIT(4)
+#define LPSS_DEV_PROXY BIT(5)
+#define LPSS_PROXY_REQ BIT(6)
struct lpss_private_data;
@@ -70,8 +72,10 @@ struct lpss_device_desc {
void (*setup)(struct lpss_private_data *pdata);
};
+static struct device *proxy_device;
+
static struct lpss_device_desc lpss_dma_desc = {
- .flags = LPSS_CLK,
+ .flags = LPSS_CLK | LPSS_PROXY_REQ,
};
struct lpss_private_data {
@@ -146,22 +150,24 @@ static struct lpss_device_desc byt_pwm_dev_desc = {
};
static struct lpss_device_desc byt_uart_dev_desc = {
- .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+ LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = lpss_uart_setup,
};
static struct lpss_device_desc byt_spi_dev_desc = {
- .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_CLK_GATE | LPSS_CLK_DIVIDER | LPSS_SAVE_CTX |
+ LPSS_DEV_PROXY,
.prv_offset = 0x400,
};
static struct lpss_device_desc byt_sdio_dev_desc = {
- .flags = LPSS_CLK,
+ .flags = LPSS_CLK | LPSS_DEV_PROXY,
};
static struct lpss_device_desc byt_i2c_dev_desc = {
- .flags = LPSS_CLK | LPSS_SAVE_CTX,
+ .flags = LPSS_CLK | LPSS_SAVE_CTX | LPSS_DEV_PROXY,
.prv_offset = 0x800,
.setup = byt_i2c_setup,
};
@@ -368,6 +374,8 @@ static int acpi_lpss_create_device(struct acpi_device *adev,
adev->driver_data = pdata;
pdev = acpi_create_platform_device(adev);
if (!IS_ERR_OR_NULL(pdev)) {
+ if (!proxy_device && dev_desc->flags & LPSS_DEV_PROXY)
+ proxy_device = &pdev->dev;
return 1;
}
@@ -499,14 +507,15 @@ static void acpi_lpss_set_ltr(struct device *dev, s32 val)
/**
* acpi_lpss_save_ctx() - Save the private registers of LPSS device
* @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
*
* Most LPSS devices have private registers which may loose their context when
* the device is powered down. acpi_lpss_save_ctx() saves those registers into
* prv_reg_ctx array.
*/
-static void acpi_lpss_save_ctx(struct device *dev)
+static void acpi_lpss_save_ctx(struct device *dev,
+ struct lpss_private_data *pdata)
{
- struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
for (i = 0; i < LPSS_PRV_REG_COUNT; i++) {
@@ -521,12 +530,13 @@ static void acpi_lpss_save_ctx(struct device *dev)
/**
* acpi_lpss_restore_ctx() - Restore the private registers of LPSS device
* @dev: LPSS device
+ * @pdata: pointer to the private data of the LPSS device
*
* Restores the registers that were previously stored with acpi_lpss_save_ctx().
*/
-static void acpi_lpss_restore_ctx(struct device *dev)
+static void acpi_lpss_restore_ctx(struct device *dev,
+ struct lpss_private_data *pdata)
{
- struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
unsigned int i;
/*
@@ -549,54 +559,82 @@ static void acpi_lpss_restore_ctx(struct device *dev)
#ifdef CONFIG_PM_SLEEP
static int acpi_lpss_suspend_late(struct device *dev)
{
- int ret = pm_generic_suspend_late(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = pm_generic_suspend_late(dev);
if (ret)
return ret;
- acpi_lpss_save_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_save_ctx(dev, pdata);
+
return acpi_dev_suspend_late(dev);
}
static int acpi_lpss_resume_early(struct device *dev)
{
- int ret = acpi_dev_resume_early(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+ ret = acpi_dev_resume_early(dev);
if (ret)
return ret;
- acpi_lpss_restore_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_restore_ctx(dev, pdata);
+
return pm_generic_resume_early(dev);
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
static int acpi_lpss_runtime_suspend(struct device *dev)
{
- int ret = pm_generic_runtime_suspend(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ ret = pm_generic_runtime_suspend(dev);
+ if (ret)
+ return ret;
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_save_ctx(dev, pdata);
+
+ ret = acpi_dev_runtime_suspend(dev);
if (ret)
return ret;
- acpi_lpss_save_ctx(dev);
- return acpi_dev_runtime_suspend(dev);
+ if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device)
+ return pm_runtime_put_sync_suspend(proxy_device);
+
+ return 0;
}
static int acpi_lpss_runtime_resume(struct device *dev)
{
- int ret = acpi_dev_runtime_resume(dev);
+ struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev));
+ int ret;
+
+ if (pdata->dev_desc->flags & LPSS_PROXY_REQ && proxy_device) {
+ ret = pm_runtime_get_sync(proxy_device);
+ if (ret)
+ return ret;
+ }
+ ret = acpi_dev_runtime_resume(dev);
if (ret)
return ret;
- acpi_lpss_restore_ctx(dev);
+ if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
+ acpi_lpss_restore_ctx(dev, pdata);
+
return pm_generic_runtime_resume(dev);
}
-#endif /* CONFIG_PM_RUNTIME */
#endif /* CONFIG_PM */
static struct dev_pm_domain acpi_lpss_pm_domain = {
.ops = {
+#ifdef CONFIG_PM
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
@@ -608,7 +646,6 @@ static struct dev_pm_domain acpi_lpss_pm_domain = {
.poweroff_late = acpi_lpss_suspend_late,
.restore_early = acpi_lpss_resume_early,
#endif
-#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = acpi_lpss_runtime_suspend,
.runtime_resume = acpi_lpss_runtime_resume,
#endif
@@ -631,30 +668,27 @@ static int acpi_lpss_platform_notify(struct notifier_block *nb,
return 0;
pdata = acpi_driver_data(adev);
- if (!pdata || !pdata->mmio_base)
+ if (!pdata)
return 0;
- if (pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
+ if (pdata->mmio_base &&
+ pdata->mmio_size < pdata->dev_desc->prv_offset + LPSS_LTR_SIZE) {
dev_err(&pdev->dev, "MMIO size insufficient to access LTR\n");
return 0;
}
switch (action) {
- case BUS_NOTIFY_BOUND_DRIVER:
- if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
- pdev->dev.pm_domain = &acpi_lpss_pm_domain;
- break;
- case BUS_NOTIFY_UNBOUND_DRIVER:
- if (pdata->dev_desc->flags & LPSS_SAVE_CTX)
- pdev->dev.pm_domain = NULL;
- break;
case BUS_NOTIFY_ADD_DEVICE:
+ pdev->dev.pm_domain = &acpi_lpss_pm_domain;
if (pdata->dev_desc->flags & LPSS_LTR)
return sysfs_create_group(&pdev->dev.kobj,
&lpss_attr_group);
+ break;
case BUS_NOTIFY_DEL_DEVICE:
if (pdata->dev_desc->flags & LPSS_LTR)
sysfs_remove_group(&pdev->dev.kobj, &lpss_attr_group);
+ pdev->dev.pm_domain = NULL;
+ break;
default:
break;
}
diff --git a/drivers/acpi/acpica/acglobal.h b/drivers/acpi/acpica/acglobal.h
index ebf02cc..7f60582 100644
--- a/drivers/acpi/acpica/acglobal.h
+++ b/drivers/acpi/acpica/acglobal.h
@@ -305,6 +305,7 @@ ACPI_INIT_GLOBAL(u8, acpi_gbl_db_output_flags, ACPI_DB_CONSOLE_OUTPUT);
ACPI_INIT_GLOBAL(u8, acpi_gbl_no_resource_disassembly, FALSE);
ACPI_INIT_GLOBAL(u8, acpi_gbl_ignore_noop_operator, FALSE);
+ACPI_INIT_GLOBAL(u8, acpi_gbl_cstyle_disassembly, TRUE);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_disasm);
ACPI_GLOBAL(u8, acpi_gbl_db_opt_verbose);
diff --git a/drivers/acpi/acpica/aclocal.h b/drivers/acpi/acpica/aclocal.h
index c00e7e4..680d23b 100644
--- a/drivers/acpi/acpica/aclocal.h
+++ b/drivers/acpi/acpica/aclocal.h
@@ -454,6 +454,7 @@ struct acpi_gpe_register_info {
u16 base_gpe_number; /* Base GPE number for this register */
u8 enable_for_wake; /* GPEs to keep enabled when sleeping */
u8 enable_for_run; /* GPEs to keep enabled when running */
+ u8 enable_mask; /* Current mask of enabled GPEs */
};
/*
@@ -722,6 +723,7 @@ union acpi_parse_value {
ACPI_DISASM_ONLY_MEMBERS (\
u8 disasm_flags; /* Used during AML disassembly */\
u8 disasm_opcode; /* Subtype used for disassembly */\
+ char *operator_symbol;/* Used for C-style operator name strings */\
char aml_op_name[16]) /* Op name (debug only) */
/* Flags for disasm_flags field above */
@@ -827,6 +829,8 @@ struct acpi_parse_state {
#define ACPI_PARSEOP_EMPTY_TERMLIST 0x04
#define ACPI_PARSEOP_PREDEF_CHECKED 0x08
#define ACPI_PARSEOP_SPECIAL 0x10
+#define ACPI_PARSEOP_COMPOUND 0x20
+#define ACPI_PARSEOP_ASSIGNMENT 0x40
/*****************************************************************************
*
diff --git a/drivers/acpi/acpica/evgpe.c b/drivers/acpi/acpica/evgpe.c
index 2095dfb..aa70154 100644
--- a/drivers/acpi/acpica/evgpe.c
+++ b/drivers/acpi/acpica/evgpe.c
@@ -134,7 +134,7 @@ acpi_status acpi_ev_enable_gpe(struct acpi_gpe_event_info *gpe_event_info)
/* Enable the requested GPE */
- status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE);
+ status = acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_ENABLE_SAVE);
return_ACPI_STATUS(status);
}
@@ -213,7 +213,7 @@ acpi_ev_remove_gpe_reference(struct acpi_gpe_event_info *gpe_event_info)
if (ACPI_SUCCESS(status)) {
status =
acpi_hw_low_set_gpe(gpe_event_info,
- ACPI_GPE_DISABLE);
+ ACPI_GPE_DISABLE_SAVE);
}
if (ACPI_FAILURE(status)) {
@@ -616,8 +616,11 @@ static void ACPI_SYSTEM_XFACE acpi_ev_asynch_execute_gpe_method(void *context)
static void ACPI_SYSTEM_XFACE acpi_ev_asynch_enable_gpe(void *context)
{
struct acpi_gpe_event_info *gpe_event_info = context;
+ acpi_cpu_flags flags;
+ flags = acpi_os_acquire_lock(acpi_gbl_gpe_lock);
(void)acpi_ev_finish_gpe(gpe_event_info);
+ acpi_os_release_lock(acpi_gbl_gpe_lock, flags);
ACPI_FREE(gpe_event_info);
return;
@@ -655,7 +658,7 @@ acpi_status acpi_ev_finish_gpe(struct acpi_gpe_event_info * gpe_event_info)
/*
* Enable this GPE, conditionally. This means that the GPE will
- * only be physically enabled if the enable_for_run bit is set
+ * only be physically enabled if the enable_mask bit is set
* in the event_info.
*/
(void)acpi_hw_low_set_gpe(gpe_event_info, ACPI_GPE_CONDITIONAL_ENABLE);
diff --git a/drivers/acpi/acpica/hwgpe.c b/drivers/acpi/acpica/hwgpe.c
index 48ac7b7..494027f 100644
--- a/drivers/acpi/acpica/hwgpe.c
+++ b/drivers/acpi/acpica/hwgpe.c
@@ -115,12 +115,12 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/* Set or clear just the bit that corresponds to this GPE */
register_bit = acpi_hw_get_gpe_register_bit(gpe_event_info);
- switch (action) {
+ switch (action & ~ACPI_GPE_SAVE_MASK) {
case ACPI_GPE_CONDITIONAL_ENABLE:
- /* Only enable if the enable_for_run bit is set */
+ /* Only enable if the corresponding enable_mask bit is set */
- if (!(register_bit & gpe_register_info->enable_for_run)) {
+ if (!(register_bit & gpe_register_info->enable_mask)) {
return (AE_BAD_PARAMETER);
}
@@ -145,6 +145,9 @@ acpi_hw_low_set_gpe(struct acpi_gpe_event_info *gpe_event_info, u32 action)
/* Write the updated enable mask */
status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+ if (ACPI_SUCCESS(status) && (action & ACPI_GPE_SAVE_MASK)) {
+ gpe_register_info->enable_mask = enable_mask;
+ }
return (status);
}
@@ -262,6 +265,32 @@ acpi_hw_get_gpe_status(struct acpi_gpe_event_info * gpe_event_info,
/******************************************************************************
*
+ * FUNCTION: acpi_hw_gpe_enable_write
+ *
+ * PARAMETERS: enable_mask - Bit mask to write to the GPE register
+ * gpe_register_info - Gpe Register info
+ *
+ * RETURN: Status
+ *
+ * DESCRIPTION: Write the enable mask byte to the given GPE register.
+ *
+ ******************************************************************************/
+
+static acpi_status
+acpi_hw_gpe_enable_write(u8 enable_mask,
+ struct acpi_gpe_register_info *gpe_register_info)
+{
+ acpi_status status;
+
+ status = acpi_hw_write(enable_mask, &gpe_register_info->enable_address);
+ if (ACPI_SUCCESS(status)) {
+ gpe_register_info->enable_mask = enable_mask;
+ }
+ return (status);
+}
+
+/******************************************************************************
+ *
* FUNCTION: acpi_hw_disable_gpe_block
*
* PARAMETERS: gpe_xrupt_info - GPE Interrupt info
@@ -287,8 +316,8 @@ acpi_hw_disable_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
/* Disable all GPEs in this register */
status =
- acpi_hw_write(0x00,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(0x00,
+ &gpe_block->register_info[i]);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -355,21 +384,23 @@ acpi_hw_enable_runtime_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
{
u32 i;
acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
/* NOTE: assumes that all GPEs are currently disabled */
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
- if (!gpe_block->register_info[i].enable_for_run) {
+ gpe_register_info = &gpe_block->register_info[i];
+ if (!gpe_register_info->enable_for_run) {
continue;
}
/* Enable all "runtime" GPEs in this register */
status =
- acpi_hw_write(gpe_block->register_info[i].enable_for_run,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(gpe_register_info->enable_for_run,
+ gpe_register_info);
if (ACPI_FAILURE(status)) {
return (status);
}
@@ -399,10 +430,12 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
{
u32 i;
acpi_status status;
+ struct acpi_gpe_register_info *gpe_register_info;
/* Examine each GPE Register within the block */
for (i = 0; i < gpe_block->register_count; i++) {
+ gpe_register_info = &gpe_block->register_info[i];
/*
* Enable all "wake" GPEs in this register and disable the
@@ -410,8 +443,8 @@ acpi_hw_enable_wakeup_gpe_block(struct acpi_gpe_xrupt_info *gpe_xrupt_info,
*/
status =
- acpi_hw_write(gpe_block->register_info[i].enable_for_wake,
- &gpe_block->register_info[i].enable_address);
+ acpi_hw_gpe_enable_write(gpe_register_info->enable_for_wake,
+ gpe_register_info);
if (ACPI_FAILURE(status)) {
return (status);
}
diff --git a/drivers/acpi/acpica/utresrc.c b/drivers/acpi/acpica/utresrc.c
index 5cd017c..bc1ff82 100644
--- a/drivers/acpi/acpica/utresrc.c
+++ b/drivers/acpi/acpica/utresrc.c
@@ -263,7 +263,7 @@ const char *acpi_gbl_bpb_decode[] = {
/* UART serial bus stop bits */
const char *acpi_gbl_sb_decode[] = {
- "StopBitsNone",
+ "StopBitsZero",
"StopBitsOne",
"StopBitsOnePlusHalf",
"StopBitsTwo"
diff --git a/drivers/acpi/acpica/utxface.c b/drivers/acpi/acpica/utxface.c
index 502a849..49c873c 100644
--- a/drivers/acpi/acpica/utxface.c
+++ b/drivers/acpi/acpica/utxface.c
@@ -531,7 +531,9 @@ acpi_decode_pld_buffer(u8 *in_buffer,
ACPI_MOVE_32_TO_32(&dword, &buffer[0]);
pld_info->revision = ACPI_PLD_GET_REVISION(&dword);
pld_info->ignore_color = ACPI_PLD_GET_IGNORE_COLOR(&dword);
- pld_info->color = ACPI_PLD_GET_COLOR(&dword);
+ pld_info->red = ACPI_PLD_GET_RED(&dword);
+ pld_info->green = ACPI_PLD_GET_GREEN(&dword);
+ pld_info->blue = ACPI_PLD_GET_BLUE(&dword);
/* Second 32-bit DWord */
diff --git a/drivers/acpi/acpica/utxfinit.c b/drivers/acpi/acpica/utxfinit.c
index 13380d8..b1fd688 100644
--- a/drivers/acpi/acpica/utxfinit.c
+++ b/drivers/acpi/acpica/utxfinit.c
@@ -53,6 +53,9 @@
#define _COMPONENT ACPI_UTILITIES
ACPI_MODULE_NAME("utxfinit")
+/* For acpi_exec only */
+void ae_do_object_overrides(void);
+
/*******************************************************************************
*
* FUNCTION: acpi_initialize_subsystem
@@ -65,6 +68,7 @@ ACPI_MODULE_NAME("utxfinit")
* called, so any early initialization belongs here.
*
******************************************************************************/
+
acpi_status __init acpi_initialize_subsystem(void)
{
acpi_status status;
@@ -275,6 +279,13 @@ acpi_status __init acpi_initialize_objects(u32 flags)
return_ACPI_STATUS(status);
}
}
+#ifdef ACPI_EXEC_APP
+ /*
+ * This call implements the "initialization file" option for acpi_exec.
+ * This is the precise point that we want to perform the overrides.
+ */
+ ae_do_object_overrides();
+#endif
/*
* Execute any module-level code that was detected during the table load
diff --git a/drivers/acpi/apei/ghes.c b/drivers/acpi/apei/ghes.c
index fc5f780..1b6aa51 100644
--- a/drivers/acpi/apei/ghes.c
+++ b/drivers/acpi/apei/ghes.c
@@ -128,7 +128,7 @@ static DEFINE_SPINLOCK(ghes_ioremap_lock_irq);
static struct gen_pool *ghes_estatus_pool;
static unsigned long ghes_estatus_pool_size_request;
-struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
+static struct ghes_estatus_cache *ghes_estatus_caches[GHES_ESTATUS_CACHES_SIZE];
static atomic_t ghes_estatus_cache_alloced;
static int ghes_ioremap_init(void)
@@ -738,20 +738,6 @@ static LIST_HEAD(ghes_nmi);
static int ghes_panic_timeout __read_mostly = 30;
-static struct llist_node *llist_nodes_reverse(struct llist_node *llnode)
-{
- struct llist_node *next, *tail = NULL;
-
- while (llnode) {
- next = llnode->next;
- llnode->next = tail;
- tail = llnode;
- llnode = next;
- }
-
- return tail;
-}
-
static void ghes_proc_in_irq(struct irq_work *irq_work)
{
struct llist_node *llnode, *next;
@@ -765,7 +751,7 @@ static void ghes_proc_in_irq(struct irq_work *irq_work)
* Because the time order of estatus in list is reversed,
* revert it back to proper order.
*/
- llnode = llist_nodes_reverse(llnode);
+ llnode = llist_reverse_order(llnode);
while (llnode) {
next = llnode->next;
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
@@ -798,7 +784,7 @@ static void ghes_print_queued_estatus(void)
* Because the time order of estatus in list is reversed,
* revert it back to proper order.
*/
- llnode = llist_nodes_reverse(llnode);
+ llnode = llist_reverse_order(llnode);
while (llnode) {
estatus_node = llist_entry(llnode, struct ghes_estatus_node,
llnode);
diff --git a/drivers/acpi/battery.c b/drivers/acpi/battery.c
index 8ec8a89..d98ba43 100644
--- a/drivers/acpi/battery.c
+++ b/drivers/acpi/battery.c
@@ -1180,6 +1180,10 @@ static int acpi_battery_add(struct acpi_device *device)
if (!device)
return -EINVAL;
+
+ if (device->dep_unmet)
+ return -EPROBE_DEFER;
+
battery = kzalloc(sizeof(struct acpi_battery), GFP_KERNEL);
if (!battery)
return -ENOMEM;
diff --git a/drivers/acpi/device_pm.c b/drivers/acpi/device_pm.c
index 7db1931..8976401 100644
--- a/drivers/acpi/device_pm.c
+++ b/drivers/acpi/device_pm.c
@@ -201,7 +201,7 @@ int acpi_device_set_power(struct acpi_device *device, int state)
* Transition Power
* ----------------
* In accordance with the ACPI specification first apply power (via
- * power resources) and then evalute _PSx.
+ * power resources) and then evaluate _PSx.
*/
if (device->power.flags.power_resources) {
result = acpi_power_transition(device, state);
@@ -692,7 +692,6 @@ static int acpi_device_wakeup(struct acpi_device *adev, u32 target_state,
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
/**
* acpi_pm_device_run_wake - Enable/disable remote wakeup for given device.
* @dev: Device to enable/disable the platform to wake up.
@@ -714,7 +713,6 @@ int acpi_pm_device_run_wake(struct device *phys_dev, bool enable)
return acpi_device_wakeup(adev, ACPI_STATE_S0, enable);
}
EXPORT_SYMBOL(acpi_pm_device_run_wake);
-#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
/**
@@ -773,7 +771,6 @@ static int acpi_dev_pm_full_power(struct acpi_device *adev)
acpi_device_set_power(adev, ACPI_STATE_D0) : 0;
}
-#ifdef CONFIG_PM_RUNTIME
/**
* acpi_dev_runtime_suspend - Put device into a low-power state using ACPI.
* @dev: Device to put into a low-power state.
@@ -855,7 +852,6 @@ int acpi_subsys_runtime_resume(struct device *dev)
return ret ? ret : pm_generic_runtime_resume(dev);
}
EXPORT_SYMBOL_GPL(acpi_subsys_runtime_resume);
-#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
/**
@@ -1023,10 +1019,9 @@ EXPORT_SYMBOL_GPL(acpi_subsys_freeze);
static struct dev_pm_domain acpi_general_pm_domain = {
.ops = {
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
.runtime_suspend = acpi_subsys_runtime_suspend,
.runtime_resume = acpi_subsys_runtime_resume,
-#endif
#ifdef CONFIG_PM_SLEEP
.prepare = acpi_subsys_prepare,
.complete = acpi_subsys_complete,
@@ -1038,6 +1033,7 @@ static struct dev_pm_domain acpi_general_pm_domain = {
.poweroff_late = acpi_subsys_suspend_late,
.restore_early = acpi_subsys_resume_early,
#endif
+#endif
},
};
diff --git a/drivers/acpi/internal.h b/drivers/acpi/internal.h
index 447f6d6..163e82f 100644
--- a/drivers/acpi/internal.h
+++ b/drivers/acpi/internal.h
@@ -173,4 +173,10 @@ static inline void suspend_nvs_restore(void) {}
bool acpi_osi_is_win8(void);
#endif
+/*--------------------------------------------------------------------------
+ Device properties
+ -------------------------------------------------------------------------- */
+void acpi_init_properties(struct acpi_device *adev);
+void acpi_free_properties(struct acpi_device *adev);
+
#endif /* _ACPI_INTERNAL_H_ */
diff --git a/drivers/acpi/osl.c b/drivers/acpi/osl.c
index 9964f70..f9eeae8 100644
--- a/drivers/acpi/osl.c
+++ b/drivers/acpi/osl.c
@@ -436,7 +436,7 @@ static void acpi_os_drop_map_ref(struct acpi_ioremap *map)
static void acpi_os_map_cleanup(struct acpi_ioremap *map)
{
if (!map->refcount) {
- synchronize_rcu();
+ synchronize_rcu_expedited();
acpi_unmap(map->phys, map->virt);
kfree(map);
}
@@ -1188,6 +1188,12 @@ EXPORT_SYMBOL(acpi_os_execute);
void acpi_os_wait_events_complete(void)
{
+ /*
+ * Make sure the GPE handler or the fixed event handler is not used
+ * on another CPU after removal.
+ */
+ if (acpi_irq_handler)
+ synchronize_hardirq(acpi_gbl_FADT.sci_interrupt);
flush_workqueue(kacpid_wq);
flush_workqueue(kacpi_notify_wq);
}
diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c
index 6e6b80e..7cc4e33 100644
--- a/drivers/acpi/pci_irq.c
+++ b/drivers/acpi/pci_irq.c
@@ -484,7 +484,7 @@ void acpi_pci_irq_disable(struct pci_dev *dev)
/* Keep IOAPIC pin configuration when suspending */
if (dev->dev.power.is_prepared)
return;
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
if (dev->dev.power.runtime_status == RPM_SUSPENDING)
return;
#endif
diff --git a/drivers/acpi/pmic/intel_pmic.c b/drivers/acpi/pmic/intel_pmic.c
new file mode 100644
index 0000000..a732e5d
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic.c
@@ -0,0 +1,354 @@
+/*
+ * intel_pmic.c - Intel PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/regmap.h>
+#include "intel_pmic.h"
+
+#define PMIC_POWER_OPREGION_ID 0x8d
+#define PMIC_THERMAL_OPREGION_ID 0x8c
+
+struct acpi_lpat {
+ int temp;
+ int raw;
+};
+
+struct intel_pmic_opregion {
+ struct mutex lock;
+ struct acpi_lpat *lpat;
+ int lpat_count;
+ struct regmap *regmap;
+ struct intel_pmic_opregion_data *data;
+};
+
+static int pmic_get_reg_bit(int address, struct pmic_table *table,
+ int count, int *reg, int *bit)
+{
+ int i;
+
+ for (i = 0; i < count; i++) {
+ if (table[i].address == address) {
+ *reg = table[i].reg;
+ if (bit)
+ *bit = table[i].bit;
+ return 0;
+ }
+ }
+ return -ENOENT;
+}
+
+/**
+ * raw_to_temp(): Return temperature from raw value through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @raw: the raw value, used as a key to get the temerature from the
+ * above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int raw_to_temp(struct acpi_lpat *lpat, int count, int raw)
+{
+ int i, delta_temp, delta_raw, temp;
+
+ for (i = 0; i < count - 1; i++) {
+ if ((raw >= lpat[i].raw && raw <= lpat[i+1].raw) ||
+ (raw <= lpat[i].raw && raw >= lpat[i+1].raw))
+ break;
+ }
+
+ if (i == count - 1)
+ return -ENOENT;
+
+ delta_temp = lpat[i+1].temp - lpat[i].temp;
+ delta_raw = lpat[i+1].raw - lpat[i].raw;
+ temp = lpat[i].temp + (raw - lpat[i].raw) * delta_temp / delta_raw;
+
+ return temp;
+}
+
+/**
+ * temp_to_raw(): Return raw value from temperature through LPAT table
+ *
+ * @lpat: the temperature_raw mapping table
+ * @count: the count of the above mapping table
+ * @temp: the temperature, used as a key to get the raw value from the
+ * above mapping table
+ *
+ * A positive value will be returned on success, a negative errno will
+ * be returned in error cases.
+ */
+static int temp_to_raw(struct acpi_lpat *lpat, int count, int temp)
+{
+ int i, delta_temp, delta_raw, raw;
+
+ for (i = 0; i < count - 1; i++) {
+ if (temp >= lpat[i].temp && temp <= lpat[i+1].temp)
+ break;
+ }
+
+ if (i == count - 1)
+ return -ENOENT;
+
+ delta_temp = lpat[i+1].temp - lpat[i].temp;
+ delta_raw = lpat[i+1].raw - lpat[i].raw;
+ raw = lpat[i].raw + (temp - lpat[i].temp) * delta_raw / delta_temp;
+
+ return raw;
+}
+
+static void pmic_thermal_lpat(struct intel_pmic_opregion *opregion,
+ acpi_handle handle, struct device *dev)
+{
+ struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+ union acpi_object *obj_p, *obj_e;
+ int *lpat, i;
+ acpi_status status;
+
+ status = acpi_evaluate_object(handle, "LPAT", NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ return;
+
+ obj_p = (union acpi_object *)buffer.pointer;
+ if (!obj_p || (obj_p->type != ACPI_TYPE_PACKAGE) ||
+ (obj_p->package.count % 2) || (obj_p->package.count < 4))
+ goto out;
+
+ lpat = devm_kmalloc(dev, sizeof(int) * obj_p->package.count,
+ GFP_KERNEL);
+ if (!lpat)
+ goto out;
+
+ for (i = 0; i < obj_p->package.count; i++) {
+ obj_e = &obj_p->package.elements[i];
+ if (obj_e->type != ACPI_TYPE_INTEGER) {
+ devm_kfree(dev, lpat);
+ goto out;
+ }
+ lpat[i] = (s64)obj_e->integer.value;
+ }
+
+ opregion->lpat = (struct acpi_lpat *)lpat;
+ opregion->lpat_count = obj_p->package.count / 2;
+
+out:
+ kfree(buffer.pointer);
+}
+
+static acpi_status intel_pmic_power_handler(u32 function,
+ acpi_physical_address address, u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ struct intel_pmic_opregion *opregion = region_context;
+ struct regmap *regmap = opregion->regmap;
+ struct intel_pmic_opregion_data *d = opregion->data;
+ int reg, bit, result;
+
+ if (bits != 32 || !value64)
+ return AE_BAD_PARAMETER;
+
+ if (function == ACPI_WRITE && !(*value64 == 0 || *value64 == 1))
+ return AE_BAD_PARAMETER;
+
+ result = pmic_get_reg_bit(address, d->power_table,
+ d->power_table_count, &reg, &bit);
+ if (result == -ENOENT)
+ return AE_BAD_PARAMETER;
+
+ mutex_lock(&opregion->lock);
+
+ result = function == ACPI_READ ?
+ d->get_power(regmap, reg, bit, value64) :
+ d->update_power(regmap, reg, bit, *value64 == 1);
+
+ mutex_unlock(&opregion->lock);
+
+ return result ? AE_ERROR : AE_OK;
+}
+
+static int pmic_read_temp(struct intel_pmic_opregion *opregion,
+ int reg, u64 *value)
+{
+ int raw_temp, temp;
+
+ if (!opregion->data->get_raw_temp)
+ return -ENXIO;
+
+ raw_temp = opregion->data->get_raw_temp(opregion->regmap, reg);
+ if (raw_temp < 0)
+ return raw_temp;
+
+ if (!opregion->lpat) {
+ *value = raw_temp;
+ return 0;
+ }
+
+ temp = raw_to_temp(opregion->lpat, opregion->lpat_count, raw_temp);
+ if (temp < 0)
+ return temp;
+
+ *value = temp;
+ return 0;
+}
+
+static int pmic_thermal_temp(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ return function == ACPI_READ ?
+ pmic_read_temp(opregion, reg, value) : -EINVAL;
+}
+
+static int pmic_thermal_aux(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ int raw_temp;
+
+ if (function == ACPI_READ)
+ return pmic_read_temp(opregion, reg, value);
+
+ if (!opregion->data->update_aux)
+ return -ENXIO;
+
+ if (opregion->lpat) {
+ raw_temp = temp_to_raw(opregion->lpat, opregion->lpat_count,
+ *value);
+ if (raw_temp < 0)
+ return raw_temp;
+ } else {
+ raw_temp = *value;
+ }
+
+ return opregion->data->update_aux(opregion->regmap, reg, raw_temp);
+}
+
+static int pmic_thermal_pen(struct intel_pmic_opregion *opregion, int reg,
+ u32 function, u64 *value)
+{
+ struct intel_pmic_opregion_data *d = opregion->data;
+ struct regmap *regmap = opregion->regmap;
+
+ if (!d->get_policy || !d->update_policy)
+ return -ENXIO;
+
+ if (function == ACPI_READ)
+ return d->get_policy(regmap, reg, value);
+
+ if (*value != 0 && *value != 1)
+ return -EINVAL;
+
+ return d->update_policy(regmap, reg, *value);
+}
+
+static bool pmic_thermal_is_temp(int address)
+{
+ return (address <= 0x3c) && !(address % 12);
+}
+
+static bool pmic_thermal_is_aux(int address)
+{
+ return (address >= 4 && address <= 0x40 && !((address - 4) % 12)) ||
+ (address >= 8 && address <= 0x44 && !((address - 8) % 12));
+}
+
+static bool pmic_thermal_is_pen(int address)
+{
+ return address >= 0x48 && address <= 0x5c;
+}
+
+static acpi_status intel_pmic_thermal_handler(u32 function,
+ acpi_physical_address address, u32 bits, u64 *value64,
+ void *handler_context, void *region_context)
+{
+ struct intel_pmic_opregion *opregion = region_context;
+ struct intel_pmic_opregion_data *d = opregion->data;
+ int reg, result;
+
+ if (bits != 32 || !value64)
+ return AE_BAD_PARAMETER;
+
+ result = pmic_get_reg_bit(address, d->thermal_table,
+ d->thermal_table_count, &reg, NULL);
+ if (result == -ENOENT)
+ return AE_BAD_PARAMETER;
+
+ mutex_lock(&opregion->lock);
+
+ if (pmic_thermal_is_temp(address))
+ result = pmic_thermal_temp(opregion, reg, function, value64);
+ else if (pmic_thermal_is_aux(address))
+ result = pmic_thermal_aux(opregion, reg, function, value64);
+ else if (pmic_thermal_is_pen(address))
+ result = pmic_thermal_pen(opregion, reg, function, value64);
+ else
+ result = -EINVAL;
+
+ mutex_unlock(&opregion->lock);
+
+ if (result < 0) {
+ if (result == -EINVAL)
+ return AE_BAD_PARAMETER;
+ else
+ return AE_ERROR;
+ }
+
+ return AE_OK;
+}
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle,
+ struct regmap *regmap,
+ struct intel_pmic_opregion_data *d)
+{
+ acpi_status status;
+ struct intel_pmic_opregion *opregion;
+
+ if (!dev || !regmap || !d)
+ return -EINVAL;
+
+ if (!handle)
+ return -ENODEV;
+
+ opregion = devm_kzalloc(dev, sizeof(*opregion), GFP_KERNEL);
+ if (!opregion)
+ return -ENOMEM;
+
+ mutex_init(&opregion->lock);
+ opregion->regmap = regmap;
+ pmic_thermal_lpat(opregion, handle, dev);
+
+ status = acpi_install_address_space_handler(handle,
+ PMIC_POWER_OPREGION_ID,
+ intel_pmic_power_handler,
+ NULL, opregion);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ status = acpi_install_address_space_handler(handle,
+ PMIC_THERMAL_OPREGION_ID,
+ intel_pmic_thermal_handler,
+ NULL, opregion);
+ if (ACPI_FAILURE(status)) {
+ acpi_remove_address_space_handler(handle, PMIC_POWER_OPREGION_ID,
+ intel_pmic_power_handler);
+ return -ENODEV;
+ }
+
+ opregion->data = d;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(intel_pmic_install_opregion_handler);
+
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic.h b/drivers/acpi/pmic/intel_pmic.h
new file mode 100644
index 0000000..d4e90af
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic.h
@@ -0,0 +1,25 @@
+#ifndef __INTEL_PMIC_H
+#define __INTEL_PMIC_H
+
+struct pmic_table {
+ int address; /* operation region address */
+ int reg; /* corresponding thermal register */
+ int bit; /* control bit for power */
+};
+
+struct intel_pmic_opregion_data {
+ int (*get_power)(struct regmap *r, int reg, int bit, u64 *value);
+ int (*update_power)(struct regmap *r, int reg, int bit, bool on);
+ int (*get_raw_temp)(struct regmap *r, int reg);
+ int (*update_aux)(struct regmap *r, int reg, int raw_temp);
+ int (*get_policy)(struct regmap *r, int reg, u64 *value);
+ int (*update_policy)(struct regmap *r, int reg, int enable);
+ struct pmic_table *power_table;
+ int power_table_count;
+ struct pmic_table *thermal_table;
+ int thermal_table_count;
+};
+
+int intel_pmic_install_opregion_handler(struct device *dev, acpi_handle handle, struct regmap *regmap, struct intel_pmic_opregion_data *d);
+
+#endif
diff --git a/drivers/acpi/pmic/intel_pmic_crc.c b/drivers/acpi/pmic/intel_pmic_crc.c
new file mode 100644
index 0000000..ef7d8ff
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic_crc.c
@@ -0,0 +1,211 @@
+/*
+ * intel_pmic_crc.c - Intel CrystalCove PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/intel_soc_pmic.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include "intel_pmic.h"
+
+#define PWR_SOURCE_SELECT BIT(1)
+
+#define PMIC_A0LOCK_REG 0xc5
+
+static struct pmic_table power_table[] = {
+ {
+ .address = 0x24,
+ .reg = 0x66,
+ .bit = 0x00,
+ },
+ {
+ .address = 0x48,
+ .reg = 0x5d,
+ .bit = 0x00,
+ },
+};
+
+static struct pmic_table thermal_table[] = {
+ {
+ .address = 0x00,
+ .reg = 0x75
+ },
+ {
+ .address = 0x04,
+ .reg = 0x95
+ },
+ {
+ .address = 0x08,
+ .reg = 0x97
+ },
+ {
+ .address = 0x0c,
+ .reg = 0x77
+ },
+ {
+ .address = 0x10,
+ .reg = 0x9a
+ },
+ {
+ .address = 0x14,
+ .reg = 0x9c
+ },
+ {
+ .address = 0x18,
+ .reg = 0x79
+ },
+ {
+ .address = 0x1c,
+ .reg = 0x9f
+ },
+ {
+ .address = 0x20,
+ .reg = 0xa1
+ },
+ {
+ .address = 0x48,
+ .reg = 0x94
+ },
+ {
+ .address = 0x4c,
+ .reg = 0x99
+ },
+ {
+ .address = 0x50,
+ .reg = 0x9e
+ },
+};
+
+static int intel_crc_pmic_get_power(struct regmap *regmap, int reg,
+ int bit, u64 *value)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ *value = (data & PWR_SOURCE_SELECT) && (data & BIT(bit)) ? 1 : 0;
+ return 0;
+}
+
+static int intel_crc_pmic_update_power(struct regmap *regmap, int reg,
+ int bit, bool on)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ if (on) {
+ data |= PWR_SOURCE_SELECT | BIT(bit);
+ } else {
+ data &= ~BIT(bit);
+ data |= PWR_SOURCE_SELECT;
+ }
+
+ if (regmap_write(regmap, reg, data))
+ return -EIO;
+ return 0;
+}
+
+static int intel_crc_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+ int temp_l, temp_h;
+
+ /*
+ * Raw temperature value is 10bits: 8bits in reg
+ * and 2bits in reg-1: bit0,1
+ */
+ if (regmap_read(regmap, reg, &temp_l) ||
+ regmap_read(regmap, reg - 1, &temp_h))
+ return -EIO;
+
+ return temp_l | (temp_h & 0x3) << 8;
+}
+
+static int intel_crc_pmic_update_aux(struct regmap *regmap, int reg, int raw)
+{
+ return regmap_write(regmap, reg, raw) ||
+ regmap_update_bits(regmap, reg - 1, 0x3, raw >> 8) ? -EIO : 0;
+}
+
+static int intel_crc_pmic_get_policy(struct regmap *regmap, int reg, u64 *value)
+{
+ int pen;
+
+ if (regmap_read(regmap, reg, &pen))
+ return -EIO;
+ *value = pen >> 7;
+ return 0;
+}
+
+static int intel_crc_pmic_update_policy(struct regmap *regmap,
+ int reg, int enable)
+{
+ int alert0;
+
+ /* Update to policy enable bit requires unlocking a0lock */
+ if (regmap_read(regmap, PMIC_A0LOCK_REG, &alert0))
+ return -EIO;
+
+ if (regmap_update_bits(regmap, PMIC_A0LOCK_REG, 0x01, 0))
+ return -EIO;
+
+ if (regmap_update_bits(regmap, reg, 0x80, enable << 7))
+ return -EIO;
+
+ /* restore alert0 */
+ if (regmap_write(regmap, PMIC_A0LOCK_REG, alert0))
+ return -EIO;
+
+ return 0;
+}
+
+static struct intel_pmic_opregion_data intel_crc_pmic_opregion_data = {
+ .get_power = intel_crc_pmic_get_power,
+ .update_power = intel_crc_pmic_update_power,
+ .get_raw_temp = intel_crc_pmic_get_raw_temp,
+ .update_aux = intel_crc_pmic_update_aux,
+ .get_policy = intel_crc_pmic_get_policy,
+ .update_policy = intel_crc_pmic_update_policy,
+ .power_table = power_table,
+ .power_table_count= ARRAY_SIZE(power_table),
+ .thermal_table = thermal_table,
+ .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static int intel_crc_pmic_opregion_probe(struct platform_device *pdev)
+{
+ struct intel_soc_pmic *pmic = dev_get_drvdata(pdev->dev.parent);
+ return intel_pmic_install_opregion_handler(&pdev->dev,
+ ACPI_HANDLE(pdev->dev.parent), pmic->regmap,
+ &intel_crc_pmic_opregion_data);
+}
+
+static struct platform_driver intel_crc_pmic_opregion_driver = {
+ .probe = intel_crc_pmic_opregion_probe,
+ .driver = {
+ .name = "crystal_cove_pmic",
+ },
+};
+
+static int __init intel_crc_pmic_opregion_driver_init(void)
+{
+ return platform_driver_register(&intel_crc_pmic_opregion_driver);
+}
+module_init(intel_crc_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("CrystalCove ACPI opration region driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/pmic/intel_pmic_xpower.c b/drivers/acpi/pmic/intel_pmic_xpower.c
new file mode 100644
index 0000000..6a082d4
--- /dev/null
+++ b/drivers/acpi/pmic/intel_pmic_xpower.c
@@ -0,0 +1,268 @@
+/*
+ * intel_pmic_xpower.c - XPower AXP288 PMIC operation region driver
+ *
+ * Copyright (C) 2014 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/acpi.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/regmap.h>
+#include <linux/platform_device.h>
+#include <linux/iio/consumer.h>
+#include "intel_pmic.h"
+
+#define XPOWER_GPADC_LOW 0x5b
+
+static struct pmic_table power_table[] = {
+ {
+ .address = 0x00,
+ .reg = 0x13,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x04,
+ .reg = 0x13,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x08,
+ .reg = 0x13,
+ .bit = 0x07,
+ },
+ {
+ .address = 0x0c,
+ .reg = 0x12,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x10,
+ .reg = 0x12,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x14,
+ .reg = 0x12,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x18,
+ .reg = 0x12,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x1c,
+ .reg = 0x12,
+ .bit = 0x00,
+ },
+ {
+ .address = 0x20,
+ .reg = 0x12,
+ .bit = 0x01,
+ },
+ {
+ .address = 0x24,
+ .reg = 0x12,
+ .bit = 0x02,
+ },
+ {
+ .address = 0x28,
+ .reg = 0x13,
+ .bit = 0x02,
+ },
+ {
+ .address = 0x2c,
+ .reg = 0x13,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x30,
+ .reg = 0x13,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x38,
+ .reg = 0x10,
+ .bit = 0x03,
+ },
+ {
+ .address = 0x3c,
+ .reg = 0x10,
+ .bit = 0x06,
+ },
+ {
+ .address = 0x40,
+ .reg = 0x10,
+ .bit = 0x05,
+ },
+ {
+ .address = 0x44,
+ .reg = 0x10,
+ .bit = 0x04,
+ },
+ {
+ .address = 0x48,
+ .reg = 0x10,
+ .bit = 0x01,
+ },
+ {
+ .address = 0x4c,
+ .reg = 0x10,
+ .bit = 0x00
+ },
+};
+
+/* TMP0 - TMP5 are the same, all from GPADC */
+static struct pmic_table thermal_table[] = {
+ {
+ .address = 0x00,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x0c,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x18,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x24,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x30,
+ .reg = XPOWER_GPADC_LOW
+ },
+ {
+ .address = 0x3c,
+ .reg = XPOWER_GPADC_LOW
+ },
+};
+
+static int intel_xpower_pmic_get_power(struct regmap *regmap, int reg,
+ int bit, u64 *value)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ *value = (data & BIT(bit)) ? 1 : 0;
+ return 0;
+}
+
+static int intel_xpower_pmic_update_power(struct regmap *regmap, int reg,
+ int bit, bool on)
+{
+ int data;
+
+ if (regmap_read(regmap, reg, &data))
+ return -EIO;
+
+ if (on)
+ data |= BIT(bit);
+ else
+ data &= ~BIT(bit);
+
+ if (regmap_write(regmap, reg, data))
+ return -EIO;
+
+ return 0;
+}
+
+/**
+ * intel_xpower_pmic_get_raw_temp(): Get raw temperature reading from the PMIC
+ *
+ * @regmap: regmap of the PMIC device
+ * @reg: register to get the reading
+ *
+ * We could get the sensor value by manipulating the HW regs here, but since
+ * the axp288 IIO driver may also access the same regs at the same time, the
+ * APIs provided by IIO subsystem are used here instead to avoid problems. As
+ * a result, the two passed in params are of no actual use.
+ *
+ * Return a positive value on success, errno on failure.
+ */
+static int intel_xpower_pmic_get_raw_temp(struct regmap *regmap, int reg)
+{
+ struct iio_channel *gpadc_chan;
+ int ret, val;
+
+ gpadc_chan = iio_channel_get(NULL, "axp288-system-temp");
+ if (IS_ERR_OR_NULL(gpadc_chan))
+ return -EACCES;
+
+ ret = iio_read_channel_raw(gpadc_chan, &val);
+ if (ret < 0)
+ val = ret;
+
+ iio_channel_release(gpadc_chan);
+ return val;
+}
+
+static struct intel_pmic_opregion_data intel_xpower_pmic_opregion_data = {
+ .get_power = intel_xpower_pmic_get_power,
+ .update_power = intel_xpower_pmic_update_power,
+ .get_raw_temp = intel_xpower_pmic_get_raw_temp,
+ .power_table = power_table,
+ .power_table_count = ARRAY_SIZE(power_table),
+ .thermal_table = thermal_table,
+ .thermal_table_count = ARRAY_SIZE(thermal_table),
+};
+
+static acpi_status intel_xpower_pmic_gpio_handler(u32 function,
+ acpi_physical_address address, u32 bit_width, u64 *value,
+ void *handler_context, void *region_context)
+{
+ return AE_OK;
+}
+
+static int intel_xpower_pmic_opregion_probe(struct platform_device *pdev)
+{
+ struct device *parent = pdev->dev.parent;
+ struct axp20x_dev *axp20x = dev_get_drvdata(parent);
+ acpi_status status;
+ int result;
+
+ status = acpi_install_address_space_handler(ACPI_HANDLE(parent),
+ ACPI_ADR_SPACE_GPIO, intel_xpower_pmic_gpio_handler,
+ NULL, NULL);
+ if (ACPI_FAILURE(status))
+ return -ENODEV;
+
+ result = intel_pmic_install_opregion_handler(&pdev->dev,
+ ACPI_HANDLE(parent), axp20x->regmap,
+ &intel_xpower_pmic_opregion_data);
+ if (result)
+ acpi_remove_address_space_handler(ACPI_HANDLE(parent),
+ ACPI_ADR_SPACE_GPIO,
+ intel_xpower_pmic_gpio_handler);
+
+ return result;
+}
+
+static struct platform_driver intel_xpower_pmic_opregion_driver = {
+ .probe = intel_xpower_pmic_opregion_probe,
+ .driver = {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
+static int __init intel_xpower_pmic_opregion_driver_init(void)
+{
+ return platform_driver_register(&intel_xpower_pmic_opregion_driver);
+}
+module_init(intel_xpower_pmic_opregion_driver_init);
+
+MODULE_DESCRIPTION("XPower AXP288 ACPI operation region driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 17f9ec5..4995365 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -334,10 +334,10 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
{
- acpi_status status = 0;
+ acpi_status status;
u64 count;
int current_count;
- int i;
+ int i, ret = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cst;
@@ -358,7 +358,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
printk(KERN_ERR PREFIX "not enough elements in _CST\n");
- status = -EFAULT;
+ ret = -EFAULT;
goto end;
}
@@ -367,7 +367,7 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* Validate number of power states. */
if (count < 1 || count != cst->package.count - 1) {
printk(KERN_ERR PREFIX "count given by _CST is not valid\n");
- status = -EFAULT;
+ ret = -EFAULT;
goto end;
}
@@ -489,12 +489,12 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
/* Validate number of power states discovered */
if (current_count < 2)
- status = -EFAULT;
+ ret = -EFAULT;
end:
kfree(buffer.pointer);
- return status;
+ return ret;
}
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
@@ -985,8 +985,8 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
state->flags = 0;
switch (cx->type) {
case ACPI_STATE_C1:
- if (cx->entry_method == ACPI_CSTATE_FFH)
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
+ if (cx->entry_method != ACPI_CSTATE_FFH)
+ state->flags |= CPUIDLE_FLAG_TIME_INVALID;
state->enter = acpi_idle_enter_c1;
state->enter_dead = acpi_idle_play_dead;
@@ -994,14 +994,12 @@ static int acpi_processor_setup_cpuidle_states(struct acpi_processor *pr)
break;
case ACPI_STATE_C2:
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = acpi_idle_enter_simple;
state->enter_dead = acpi_idle_play_dead;
drv->safe_state_index = count;
break;
case ACPI_STATE_C3:
- state->flags |= CPUIDLE_FLAG_TIME_VALID;
state->enter = pr->flags.bm_check ?
acpi_idle_enter_bm :
acpi_idle_enter_simple;
@@ -1111,7 +1109,7 @@ static int acpi_processor_registered;
int acpi_processor_power_init(struct acpi_processor *pr)
{
- acpi_status status = 0;
+ acpi_status status;
int retval;
struct cpuidle_device *dev;
static int first_run;
diff --git a/drivers/acpi/property.c b/drivers/acpi/property.c
new file mode 100644
index 0000000..0d08373
--- /dev/null
+++ b/drivers/acpi/property.c
@@ -0,0 +1,551 @@
+/*
+ * ACPI device specific properties support.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * All rights reserved.
+ *
+ * Authors: Mika Westerberg <mika.westerberg@linux.intel.com>
+ * Darren Hart <dvhart@linux.intel.com>
+ * 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/export.h>
+
+#include "internal.h"
+
+/* ACPI _DSD device properties UUID: daffd814-6eba-4d8c-8a91-bc9bbf4aa301 */
+static const u8 prp_uuid[16] = {
+ 0x14, 0xd8, 0xff, 0xda, 0xba, 0x6e, 0x8c, 0x4d,
+ 0x8a, 0x91, 0xbc, 0x9b, 0xbf, 0x4a, 0xa3, 0x01
+};
+
+static bool acpi_property_value_ok(const union acpi_object *value)
+{
+ int j;
+
+ /*
+ * The value must be an integer, a string, a reference, or a package
+ * whose every element must be an integer, a string, or a reference.
+ */
+ switch (value->type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ return true;
+
+ case ACPI_TYPE_PACKAGE:
+ for (j = 0; j < value->package.count; j++)
+ switch (value->package.elements[j].type) {
+ case ACPI_TYPE_INTEGER:
+ case ACPI_TYPE_STRING:
+ case ACPI_TYPE_LOCAL_REFERENCE:
+ continue;
+
+ default:
+ return false;
+ }
+
+ return true;
+ }
+ return false;
+}
+
+static bool acpi_properties_format_valid(const union acpi_object *properties)
+{
+ int i;
+
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+ /*
+ * Only two elements allowed, the first one must be a string and
+ * the second one has to satisfy certain conditions.
+ */
+ if (property->package.count != 2
+ || property->package.elements[0].type != ACPI_TYPE_STRING
+ || !acpi_property_value_ok(&property->package.elements[1]))
+ return false;
+ }
+ return true;
+}
+
+static void acpi_init_of_compatible(struct acpi_device *adev)
+{
+ const union acpi_object *of_compatible;
+ struct acpi_hardware_id *hwid;
+ bool acpi_of = false;
+ int ret;
+
+ /*
+ * Check if the special PRP0001 ACPI ID is present and in that
+ * case we fill in Device Tree compatible properties for this
+ * device.
+ */
+ list_for_each_entry(hwid, &adev->pnp.ids, list) {
+ if (!strcmp(hwid->id, "PRP0001")) {
+ acpi_of = true;
+ break;
+ }
+ }
+
+ if (!acpi_of)
+ return;
+
+ ret = acpi_dev_get_property_array(adev, "compatible", ACPI_TYPE_STRING,
+ &of_compatible);
+ if (ret) {
+ ret = acpi_dev_get_property(adev, "compatible",
+ ACPI_TYPE_STRING, &of_compatible);
+ if (ret) {
+ acpi_handle_warn(adev->handle,
+ "PRP0001 requires compatible property\n");
+ return;
+ }
+ }
+ adev->data.of_compatible = of_compatible;
+}
+
+void acpi_init_properties(struct acpi_device *adev)
+{
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *desc;
+ acpi_status status;
+ int i;
+
+ status = acpi_evaluate_object_typed(adev->handle, "_DSD", NULL, &buf,
+ ACPI_TYPE_PACKAGE);
+ if (ACPI_FAILURE(status))
+ return;
+
+ desc = buf.pointer;
+ if (desc->package.count % 2)
+ goto fail;
+
+ /* Look for the device properties UUID. */
+ for (i = 0; i < desc->package.count; i += 2) {
+ const union acpi_object *uuid, *properties;
+
+ uuid = &desc->package.elements[i];
+ properties = &desc->package.elements[i + 1];
+
+ /*
+ * The first element must be a UUID and the second one must be
+ * a package.
+ */
+ if (uuid->type != ACPI_TYPE_BUFFER || uuid->buffer.length != 16
+ || properties->type != ACPI_TYPE_PACKAGE)
+ break;
+
+ if (memcmp(uuid->buffer.pointer, prp_uuid, sizeof(prp_uuid)))
+ continue;
+
+ /*
+ * We found the matching UUID. Now validate the format of the
+ * package immediately following it.
+ */
+ if (!acpi_properties_format_valid(properties))
+ break;
+
+ adev->data.pointer = buf.pointer;
+ adev->data.properties = properties;
+
+ acpi_init_of_compatible(adev);
+ return;
+ }
+
+ fail:
+ dev_warn(&adev->dev, "Returned _DSD data is not valid, skipping\n");
+ ACPI_FREE(buf.pointer);
+}
+
+void acpi_free_properties(struct acpi_device *adev)
+{
+ ACPI_FREE((void *)adev->data.pointer);
+ adev->data.of_compatible = NULL;
+ adev->data.pointer = NULL;
+ adev->data.properties = NULL;
+}
+
+/**
+ * acpi_dev_get_property - return an ACPI property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected property type
+ * @obj: Location to store the property value (if not %NULL)
+ *
+ * Look up a property with @name and store a pointer to the resulting ACPI
+ * object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. These objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if property with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property value type doesn't match @type.
+ */
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj)
+{
+ const union acpi_object *properties;
+ int i;
+
+ if (!adev || !name)
+ return -EINVAL;
+
+ if (!adev->data.pointer || !adev->data.properties)
+ return -ENODATA;
+
+ properties = adev->data.properties;
+ for (i = 0; i < properties->package.count; i++) {
+ const union acpi_object *propname, *propvalue;
+ const union acpi_object *property;
+
+ property = &properties->package.elements[i];
+
+ propname = &property->package.elements[0];
+ propvalue = &property->package.elements[1];
+
+ if (!strcmp(name, propname->string.pointer)) {
+ if (type != ACPI_TYPE_ANY && propvalue->type != type)
+ return -EPROTO;
+ else if (obj)
+ *obj = propvalue;
+
+ return 0;
+ }
+ }
+ return -ENODATA;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property);
+
+/**
+ * acpi_dev_get_property_array - return an ACPI array property with given name
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @type: Expected type of array elements
+ * @obj: Location to store a pointer to the property value (if not NULL)
+ *
+ * Look up an array property with @name and store a pointer to the resulting
+ * ACPI object at the location pointed to by @obj if found.
+ *
+ * Callers must not attempt to free the returned objects. Those objects will be
+ * freed by the ACPI core automatically during the removal of @adev.
+ *
+ * Return: %0 if array property (package) with @name has been found (success),
+ * %-EINVAL if the arguments are invalid,
+ * %-ENODATA if the property doesn't exist,
+ * %-EPROTO if the property is not a package or the type of its elements
+ * doesn't match @type.
+ */
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ const union acpi_object *prop;
+ int ret, i;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_PACKAGE, &prop);
+ if (ret)
+ return ret;
+
+ if (type != ACPI_TYPE_ANY) {
+ /* Check that all elements are of correct type. */
+ for (i = 0; i < prop->package.count; i++)
+ if (prop->package.elements[i].type != type)
+ return -EPROTO;
+ }
+ if (obj)
+ *obj = prop;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_array);
+
+/**
+ * acpi_dev_get_property_reference - returns handle to the referenced object
+ * @adev: ACPI device to get property
+ * @name: Name of the property
+ * @index: Index of the reference to return
+ * @args: Location to store the returned reference with optional arguments
+ *
+ * Find property with @name, verifify that it is a package containing at least
+ * one object reference and if so, store the ACPI device object pointer to the
+ * target object in @args->adev. If the reference includes arguments, store
+ * them in the @args->args[] array.
+ *
+ * If there's more than one reference in the property value package, @index is
+ * used to select the one to return.
+ *
+ * Return: %0 on success, negative error code on failure.
+ */
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, size_t index,
+ struct acpi_reference_args *args)
+{
+ const union acpi_object *element, *end;
+ const union acpi_object *obj;
+ struct acpi_device *device;
+ int ret, idx = 0;
+
+ ret = acpi_dev_get_property(adev, name, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ /*
+ * The simplest case is when the value is a single reference. Just
+ * return that reference then.
+ */
+ if (obj->type == ACPI_TYPE_LOCAL_REFERENCE) {
+ if (index)
+ return -EINVAL;
+
+ ret = acpi_bus_get_device(obj->reference.handle, &device);
+ if (ret)
+ return ret;
+
+ args->adev = device;
+ args->nargs = 0;
+ return 0;
+ }
+
+ /*
+ * If it is not a single reference, then it is a package of
+ * references followed by number of ints as follows:
+ *
+ * Package () { REF, INT, REF, INT, INT }
+ *
+ * The index argument is then used to determine which reference
+ * the caller wants (along with the arguments).
+ */
+ if (obj->type != ACPI_TYPE_PACKAGE || index >= obj->package.count)
+ return -EPROTO;
+
+ element = obj->package.elements;
+ end = element + obj->package.count;
+
+ while (element < end) {
+ u32 nargs, i;
+
+ if (element->type != ACPI_TYPE_LOCAL_REFERENCE)
+ return -EPROTO;
+
+ ret = acpi_bus_get_device(element->reference.handle, &device);
+ if (ret)
+ return -ENODEV;
+
+ element++;
+ nargs = 0;
+
+ /* assume following integer elements are all args */
+ for (i = 0; element + i < end; i++) {
+ int type = element[i].type;
+
+ if (type == ACPI_TYPE_INTEGER)
+ nargs++;
+ else if (type == ACPI_TYPE_LOCAL_REFERENCE)
+ break;
+ else
+ return -EPROTO;
+ }
+
+ if (idx++ == index) {
+ args->adev = device;
+ args->nargs = nargs;
+ for (i = 0; i < nargs; i++)
+ args->args[i] = element[i].integer.value;
+
+ return 0;
+ }
+
+ element += nargs;
+ }
+
+ return -EPROTO;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_get_property_reference);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr)
+{
+ return acpi_dev_get_property(adev, propname, ACPI_TYPE_ANY,
+ (const union acpi_object **)valptr);
+}
+
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val)
+{
+ const union acpi_object *obj;
+ int ret;
+
+ if (!val)
+ return -EINVAL;
+
+ if (proptype >= DEV_PROP_U8 && proptype <= DEV_PROP_U64) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_INTEGER, &obj);
+ if (ret)
+ return ret;
+
+ switch (proptype) {
+ case DEV_PROP_U8:
+ if (obj->integer.value > U8_MAX)
+ return -EOVERFLOW;
+ *(u8 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U16:
+ if (obj->integer.value > U16_MAX)
+ return -EOVERFLOW;
+ *(u16 *)val = obj->integer.value;
+ break;
+ case DEV_PROP_U32:
+ if (obj->integer.value > U32_MAX)
+ return -EOVERFLOW;
+ *(u32 *)val = obj->integer.value;
+ break;
+ default:
+ *(u64 *)val = obj->integer.value;
+ break;
+ }
+ } else if (proptype == DEV_PROP_STRING) {
+ ret = acpi_dev_get_property(adev, propname, ACPI_TYPE_STRING, &obj);
+ if (ret)
+ return ret;
+
+ *(char **)val = obj->string.pointer;
+ } else {
+ ret = -EINVAL;
+ }
+ return ret;
+}
+
+static int acpi_copy_property_array_u8(const union acpi_object *items, u8 *val,
+ size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U8_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u16(const union acpi_object *items,
+ u16 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U16_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u32(const union acpi_object *items,
+ u32 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+ if (items[i].integer.value > U32_MAX)
+ return -EOVERFLOW;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_u64(const union acpi_object *items,
+ u64 *val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_INTEGER)
+ return -EPROTO;
+
+ val[i] = items[i].integer.value;
+ }
+ return 0;
+}
+
+static int acpi_copy_property_array_string(const union acpi_object *items,
+ char **val, size_t nval)
+{
+ int i;
+
+ for (i = 0; i < nval; i++) {
+ if (items[i].type != ACPI_TYPE_STRING)
+ return -EPROTO;
+
+ val[i] = items[i].string.pointer;
+ }
+ return 0;
+}
+
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval)
+{
+ const union acpi_object *obj;
+ const union acpi_object *items;
+ int ret;
+
+ if (val && nval == 1) {
+ ret = acpi_dev_prop_read_single(adev, propname, proptype, val);
+ if (!ret)
+ return ret;
+ }
+
+ ret = acpi_dev_get_property_array(adev, propname, ACPI_TYPE_ANY, &obj);
+ if (ret)
+ return ret;
+
+ if (!val)
+ return obj->package.count;
+ else if (nval <= 0)
+ return -EINVAL;
+
+ if (nval > obj->package.count)
+ return -EOVERFLOW;
+
+ items = obj->package.elements;
+ switch (proptype) {
+ case DEV_PROP_U8:
+ ret = acpi_copy_property_array_u8(items, (u8 *)val, nval);
+ break;
+ case DEV_PROP_U16:
+ ret = acpi_copy_property_array_u16(items, (u16 *)val, nval);
+ break;
+ case DEV_PROP_U32:
+ ret = acpi_copy_property_array_u32(items, (u32 *)val, nval);
+ break;
+ case DEV_PROP_U64:
+ ret = acpi_copy_property_array_u64(items, (u64 *)val, nval);
+ break;
+ case DEV_PROP_STRING:
+ ret = acpi_copy_property_array_string(items, (char **)val, nval);
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ return ret;
+}
diff --git a/drivers/acpi/scan.c b/drivers/acpi/scan.c
index 0476e90..1b1cf55 100644
--- a/drivers/acpi/scan.c
+++ b/drivers/acpi/scan.c
@@ -36,6 +36,8 @@ bool acpi_force_hot_remove;
static const char *dummy_hid = "device";
+static LIST_HEAD(acpi_dep_list);
+static DEFINE_MUTEX(acpi_dep_list_lock);
static LIST_HEAD(acpi_bus_id_list);
static DEFINE_MUTEX(acpi_scan_lock);
static LIST_HEAD(acpi_scan_handlers_list);
@@ -43,6 +45,12 @@ DEFINE_MUTEX(acpi_device_lock);
LIST_HEAD(acpi_wakeup_device_list);
static DEFINE_MUTEX(acpi_hp_context_lock);
+struct acpi_dep_data {
+ struct list_head node;
+ acpi_handle master;
+ acpi_handle slave;
+};
+
struct acpi_device_bus_id{
char bus_id[15];
unsigned int instance_no;
@@ -124,17 +132,56 @@ static int create_modalias(struct acpi_device *acpi_dev, char *modalias,
if (list_empty(&acpi_dev->pnp.ids))
return 0;
- len = snprintf(modalias, size, "acpi:");
- size -= len;
-
- list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
- count = snprintf(&modalias[len], size, "%s:", id->id);
- if (count < 0)
- return -EINVAL;
- if (count >= size)
- return -ENOMEM;
- len += count;
- size -= count;
+ /*
+ * If the device has PRP0001 we expose DT compatible modalias
+ * instead in form of of:NnameTCcompatible.
+ */
+ if (acpi_dev->data.of_compatible) {
+ struct acpi_buffer buf = { ACPI_ALLOCATE_BUFFER };
+ const union acpi_object *of_compatible, *obj;
+ int i, nval;
+ char *c;
+
+ acpi_get_name(acpi_dev->handle, ACPI_SINGLE_NAME, &buf);
+ /* DT strings are all in lower case */
+ for (c = buf.pointer; *c != '\0'; c++)
+ *c = tolower(*c);
+
+ len = snprintf(modalias, size, "of:N%sT", (char *)buf.pointer);
+ ACPI_FREE(buf.pointer);
+
+ of_compatible = acpi_dev->data.of_compatible;
+ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+ nval = of_compatible->package.count;
+ obj = of_compatible->package.elements;
+ } else { /* Must be ACPI_TYPE_STRING. */
+ nval = 1;
+ obj = of_compatible;
+ }
+ for (i = 0; i < nval; i++, obj++) {
+ count = snprintf(&modalias[len], size, "C%s",
+ obj->string.pointer);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+
+ len += count;
+ size -= count;
+ }
+ } else {
+ len = snprintf(modalias, size, "acpi:");
+ size -= len;
+
+ list_for_each_entry(id, &acpi_dev->pnp.ids, list) {
+ count = snprintf(&modalias[len], size, "%s:", id->id);
+ if (count < 0)
+ return -EINVAL;
+ if (count >= size)
+ return -ENOMEM;
+ len += count;
+ size -= count;
+ }
}
modalias[len] = '\0';
@@ -902,6 +949,51 @@ int acpi_match_device_ids(struct acpi_device *device,
}
EXPORT_SYMBOL(acpi_match_device_ids);
+/* Performs match against special "PRP0001" shoehorn ACPI ID */
+static bool acpi_of_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ const union acpi_object *of_compatible, *obj;
+ struct acpi_device *adev;
+ int i, nval;
+
+ adev = ACPI_COMPANION(dev);
+ if (!adev)
+ return false;
+
+ of_compatible = adev->data.of_compatible;
+ if (!drv->of_match_table || !of_compatible)
+ return false;
+
+ if (of_compatible->type == ACPI_TYPE_PACKAGE) {
+ nval = of_compatible->package.count;
+ obj = of_compatible->package.elements;
+ } else { /* Must be ACPI_TYPE_STRING. */
+ nval = 1;
+ obj = of_compatible;
+ }
+ /* Now we can look for the driver DT compatible strings */
+ for (i = 0; i < nval; i++, obj++) {
+ const struct of_device_id *id;
+
+ for (id = drv->of_match_table; id->compatible[0]; id++)
+ if (!strcasecmp(obj->string.pointer, id->compatible))
+ return true;
+ }
+
+ return false;
+}
+
+bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv)
+{
+ if (!drv->acpi_match_table)
+ return acpi_of_driver_match_device(dev, drv);
+
+ return !!acpi_match_device(drv->acpi_match_table, dev);
+}
+EXPORT_SYMBOL_GPL(acpi_driver_match_device);
+
static void acpi_free_power_resources_lists(struct acpi_device *device)
{
int i;
@@ -922,6 +1014,7 @@ static void acpi_device_release(struct device *dev)
{
struct acpi_device *acpi_dev = to_acpi_device(dev);
+ acpi_free_properties(acpi_dev);
acpi_free_pnp_ids(&acpi_dev->pnp);
acpi_free_power_resources_lists(acpi_dev);
kfree(acpi_dev);
@@ -1304,6 +1397,26 @@ int acpi_device_add(struct acpi_device *device,
return result;
}
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ struct acpi_device *adev = ACPI_COMPANION(dev);
+ struct list_head *head, *next;
+
+ if (!adev)
+ return NULL;
+
+ head = &adev->children;
+ if (list_empty(head))
+ return NULL;
+
+ if (!child)
+ return list_first_entry(head, struct acpi_device, node);
+
+ next = child->node.next;
+ return next == head ? NULL : list_entry(next, struct acpi_device, node);
+}
+
/* --------------------------------------------------------------------------
Driver Management
-------------------------------------------------------------------------- */
@@ -1923,9 +2036,11 @@ void acpi_init_device_object(struct acpi_device *device, acpi_handle handle,
device->device_type = type;
device->handle = handle;
device->parent = acpi_bus_get_parent(handle);
+ device->fwnode.type = FWNODE_ACPI;
acpi_set_device_status(device, sta);
acpi_device_get_busid(device);
acpi_set_pnp_ids(handle, &device->pnp, type);
+ acpi_init_properties(device);
acpi_bus_get_flags(device);
device->flags.match_driver = false;
device->flags.initialized = true;
@@ -2086,6 +2201,59 @@ static void acpi_scan_init_hotplug(struct acpi_device *adev)
}
}
+static void acpi_device_dep_initialize(struct acpi_device *adev)
+{
+ struct acpi_dep_data *dep;
+ struct acpi_handle_list dep_devices;
+ acpi_status status;
+ int i;
+
+ if (!acpi_has_method(adev->handle, "_DEP"))
+ return;
+
+ status = acpi_evaluate_reference(adev->handle, "_DEP", NULL,
+ &dep_devices);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Failed to evaluate _DEP.\n");
+ return;
+ }
+
+ for (i = 0; i < dep_devices.count; i++) {
+ struct acpi_device_info *info;
+ int skip;
+
+ status = acpi_get_object_info(dep_devices.handles[i], &info);
+ if (ACPI_FAILURE(status)) {
+ dev_err(&adev->dev, "Error reading device info\n");
+ continue;
+ }
+
+ /*
+ * Skip the dependency of Windows System Power
+ * Management Controller
+ */
+ skip = info->valid & ACPI_VALID_HID &&
+ !strcmp(info->hardware_id.string, "INT3396");
+
+ kfree(info);
+
+ if (skip)
+ continue;
+
+ dep = kzalloc(sizeof(struct acpi_dep_data), GFP_KERNEL);
+ if (!dep)
+ return;
+
+ dep->master = dep_devices.handles[i];
+ dep->slave = adev->handle;
+ adev->dep_unmet++;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_add_tail(&dep->node , &acpi_dep_list);
+ mutex_unlock(&acpi_dep_list_lock);
+ }
+}
+
static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
void *not_used, void **return_value)
{
@@ -2112,6 +2280,7 @@ static acpi_status acpi_bus_check_add(acpi_handle handle, u32 lvl_not_used,
return AE_CTRL_DEPTH;
acpi_scan_init_hotplug(device);
+ acpi_device_dep_initialize(device);
out:
if (!*return_value)
@@ -2232,6 +2401,29 @@ static void acpi_bus_attach(struct acpi_device *device)
device->handler->hotplug.notify_online(device);
}
+void acpi_walk_dep_device_list(acpi_handle handle)
+{
+ struct acpi_dep_data *dep, *tmp;
+ struct acpi_device *adev;
+
+ mutex_lock(&acpi_dep_list_lock);
+ list_for_each_entry_safe(dep, tmp, &acpi_dep_list, node) {
+ if (dep->master == handle) {
+ acpi_bus_get_device(dep->slave, &adev);
+ if (!adev)
+ continue;
+
+ adev->dep_unmet--;
+ if (!adev->dep_unmet)
+ acpi_bus_attach(adev);
+ list_del(&dep->node);
+ kfree(dep);
+ }
+ }
+ mutex_unlock(&acpi_dep_list_lock);
+}
+EXPORT_SYMBOL_GPL(acpi_walk_dep_device_list);
+
/**
* acpi_bus_scan - Add ACPI device node objects in a given namespace scope.
* @handle: Root of the namespace scope to scan.
diff --git a/drivers/acpi/sleep.c b/drivers/acpi/sleep.c
index 05a31b5..8aa9254 100644
--- a/drivers/acpi/sleep.c
+++ b/drivers/acpi/sleep.c
@@ -630,6 +630,7 @@ static int acpi_freeze_begin(void)
static int acpi_freeze_prepare(void)
{
acpi_enable_all_wakeup_gpes();
+ acpi_os_wait_events_complete();
enable_irq_wake(acpi_gbl_FADT.sci_interrupt);
return 0;
}
@@ -825,6 +826,7 @@ static void acpi_power_off_prepare(void)
/* Prepare to power off the system */
acpi_sleep_prepare(ACPI_STATE_S5);
acpi_disable_all_gpes();
+ acpi_os_wait_events_complete();
}
static void acpi_power_off(void)
diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c
index 6d5a6cd..93b8152 100644
--- a/drivers/acpi/tables.c
+++ b/drivers/acpi/tables.c
@@ -190,30 +190,24 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header)
}
}
-
int __init
-acpi_table_parse_entries(char *id,
- unsigned long table_size,
- int entry_id,
- acpi_tbl_entry_handler handler,
- unsigned int max_entries)
+acpi_parse_entries(char *id, unsigned long table_size,
+ acpi_tbl_entry_handler handler,
+ struct acpi_table_header *table_header,
+ int entry_id, unsigned int max_entries)
{
- struct acpi_table_header *table_header = NULL;
struct acpi_subtable_header *entry;
- unsigned int count = 0;
+ int count = 0;
unsigned long table_end;
- acpi_size tbl_size;
if (acpi_disabled)
return -ENODEV;
- if (!handler)
+ if (!id || !handler)
return -EINVAL;
- if (strncmp(id, ACPI_SIG_MADT, 4) == 0)
- acpi_get_table_with_size(id, acpi_apic_instance, &table_header, &tbl_size);
- else
- acpi_get_table_with_size(id, 0, &table_header, &tbl_size);
+ if (!table_size)
+ return -EINVAL;
if (!table_header) {
pr_warn("%4.4s not present\n", id);
@@ -230,9 +224,12 @@ acpi_table_parse_entries(char *id,
while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
table_end) {
if (entry->type == entry_id
- && (!max_entries || count++ < max_entries))
+ && (!max_entries || count < max_entries)) {
if (handler(entry, table_end))
- goto err;
+ return -EINVAL;
+
+ count++;
+ }
/*
* If entry->length is 0, break from this loop to avoid
@@ -240,22 +237,53 @@ acpi_table_parse_entries(char *id,
*/
if (entry->length == 0) {
pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, entry_id);
- goto err;
+ return -EINVAL;
}
entry = (struct acpi_subtable_header *)
((unsigned long)entry + entry->length);
}
+
if (max_entries && count > max_entries) {
pr_warn("[%4.4s:0x%02x] ignored %i entries of %i found\n",
id, entry_id, count - max_entries, count);
}
- early_acpi_os_unmap_memory((char *)table_header, tbl_size);
return count;
-err:
+}
+
+int __init
+acpi_table_parse_entries(char *id,
+ unsigned long table_size,
+ int entry_id,
+ acpi_tbl_entry_handler handler,
+ unsigned int max_entries)
+{
+ struct acpi_table_header *table_header = NULL;
+ acpi_size tbl_size;
+ int count;
+ u32 instance = 0;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ if (!id || !handler)
+ return -EINVAL;
+
+ if (!strncmp(id, ACPI_SIG_MADT, 4))
+ instance = acpi_apic_instance;
+
+ acpi_get_table_with_size(id, instance, &table_header, &tbl_size);
+ if (!table_header) {
+ pr_warn("%4.4s not present\n", id);
+ return -ENODEV;
+ }
+
+ count = acpi_parse_entries(id, table_size, handler, table_header,
+ entry_id, max_entries);
+
early_acpi_os_unmap_memory((char *)table_header, tbl_size);
- return -EINVAL;
+ return count;
}
int __init
diff --git a/drivers/acpi/utils.c b/drivers/acpi/utils.c
index 371ac12..dd8ff63 100644
--- a/drivers/acpi/utils.c
+++ b/drivers/acpi/utils.c
@@ -136,8 +136,7 @@ acpi_extract_package(union acpi_object *package,
break;
case 'B':
size_required +=
- sizeof(u8 *) +
- (element->buffer.length * sizeof(u8));
+ sizeof(u8 *) + element->buffer.length;
tail_offset += sizeof(u8 *);
break;
default:
@@ -255,7 +254,7 @@ acpi_extract_package(union acpi_object *package,
memcpy(tail, element->buffer.pointer,
element->buffer.length);
head += sizeof(u8 *);
- tail += element->buffer.length * sizeof(u8);
+ tail += element->buffer.length;
break;
default:
/* Should never get here */
diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c
index 807a88a..185a57d 100644
--- a/drivers/acpi/video.c
+++ b/drivers/acpi/video.c
@@ -1164,7 +1164,8 @@ static bool acpi_video_device_in_dod(struct acpi_video_device *device)
return true;
for (i = 0; i < video->attached_count; i++) {
- if (video->attached_array[i].bind_info == device)
+ if ((video->attached_array[i].value.int_val & 0xfff) ==
+ (device->device_id & 0xfff))
return true;
}
@@ -1680,6 +1681,19 @@ static void acpi_video_dev_register_backlight(struct acpi_video_device *device)
printk(KERN_ERR PREFIX "Create sysfs link\n");
}
+static void acpi_video_run_bcl_for_osi(struct acpi_video_bus *video)
+{
+ struct acpi_video_device *dev;
+ union acpi_object *levels;
+
+ mutex_lock(&video->device_list_lock);
+ list_for_each_entry(dev, &video->video_device_list, entry) {
+ if (!acpi_video_device_lcd_query_levels(dev, &levels))
+ kfree(levels);
+ }
+ mutex_unlock(&video->device_list_lock);
+}
+
static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
{
struct acpi_video_device *dev;
@@ -1687,6 +1701,8 @@ static int acpi_video_bus_register_backlight(struct acpi_video_bus *video)
if (video->backlight_registered)
return 0;
+ acpi_video_run_bcl_for_osi(video);
+
if (!acpi_video_verify_backlight_support())
return 0;
diff --git a/drivers/amba/Kconfig b/drivers/amba/Kconfig
new file mode 100644
index 0000000..4a5c9d2
--- /dev/null
+++ b/drivers/amba/Kconfig
@@ -0,0 +1,14 @@
+config ARM_AMBA
+ bool
+
+if ARM_AMBA
+
+config TEGRA_AHB
+ bool "Enable AHB driver for NVIDIA Tegra SoCs"
+ default y if ARCH_TEGRA
+ help
+ Adds AHB configuration functionality for NVIDIA Tegra SoCs,
+ which controls AHB bus master arbitration and some performance
+ parameters (priority, prefetch size).
+
+endif
diff --git a/drivers/amba/bus.c b/drivers/amba/bus.c
index 47bbdc1..973a333 100644
--- a/drivers/amba/bus.c
+++ b/drivers/amba/bus.c
@@ -124,7 +124,7 @@ static const struct dev_pm_ops amba_pm = {
.thaw = pm_generic_thaw,
.poweroff = pm_generic_poweroff,
.restore = pm_generic_restore,
- SET_PM_RUNTIME_PM_OPS(
+ SET_RUNTIME_PM_OPS(
amba_pm_runtime_suspend,
amba_pm_runtime_resume,
NULL
diff --git a/drivers/ata/ahci.c b/drivers/ata/ahci.c
index e45f837..49f1e68 100644
--- a/drivers/ata/ahci.c
+++ b/drivers/ata/ahci.c
@@ -321,6 +321,9 @@ static const struct pci_device_id ahci_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, 0x8c87), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x8c8e), board_ahci }, /* 9 Series RAID */
{ PCI_VDEVICE(INTEL, 0x8c8f), board_ahci }, /* 9 Series RAID */
+ { PCI_VDEVICE(INTEL, 0x9d03), board_ahci }, /* Sunrise Point-LP AHCI */
+ { PCI_VDEVICE(INTEL, 0x9d05), board_ahci }, /* Sunrise Point-LP RAID */
+ { PCI_VDEVICE(INTEL, 0x9d07), board_ahci }, /* Sunrise Point-LP RAID */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H AHCI */
{ PCI_VDEVICE(INTEL, 0xa103), board_ahci }, /* Sunrise Point-H RAID */
{ PCI_VDEVICE(INTEL, 0xa105), board_ahci }, /* Sunrise Point-H RAID */
@@ -492,6 +495,7 @@ static const struct pci_device_id ahci_pci_tbl[] = {
* enabled. https://bugzilla.kernel.org/show_bug.cgi?id=60731
*/
{ PCI_VDEVICE(SAMSUNG, 0x1600), board_ahci_nomsi },
+ { PCI_VDEVICE(SAMSUNG, 0xa800), board_ahci_nomsi },
/* Enmotus */
{ PCI_DEVICE(0x1c44, 0x8000), board_ahci },
diff --git a/drivers/ata/libata-scsi.c b/drivers/ata/libata-scsi.c
index 0586f66..dd45c6a 100644
--- a/drivers/ata/libata-scsi.c
+++ b/drivers/ata/libata-scsi.c
@@ -1164,7 +1164,7 @@ static int ata_scsi_dev_config(struct scsi_device *sdev,
depth = min(sdev->host->can_queue, ata_id_queue_depth(dev->id));
depth = min(ATA_MAX_QUEUE - 1, depth);
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
+ scsi_change_queue_depth(sdev, depth);
}
blk_queue_flush_queueable(q, false);
@@ -1243,21 +1243,17 @@ void ata_scsi_slave_destroy(struct scsi_device *sdev)
* @ap: ATA port to which the device change the queue depth
* @sdev: SCSI device to configure queue depth for
* @queue_depth: new queue depth
- * @reason: calling context
*
* libsas and libata have different approaches for associating a sdev to
* its ata_port.
*
*/
int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
- int queue_depth, int reason)
+ int queue_depth)
{
struct ata_device *dev;
unsigned long flags;
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (queue_depth < 1 || queue_depth == sdev->queue_depth)
return sdev->queue_depth;
@@ -1282,15 +1278,13 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
if (sdev->queue_depth == queue_depth)
return -EINVAL;
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, queue_depth);
- return queue_depth;
+ return scsi_change_queue_depth(sdev, queue_depth);
}
/**
* ata_scsi_change_queue_depth - SCSI callback for queue depth config
* @sdev: SCSI device to configure queue depth for
* @queue_depth: new queue depth
- * @reason: calling context
*
* This is libata standard hostt->change_queue_depth callback.
* SCSI will call into this callback when user tries to set queue
@@ -1302,12 +1296,11 @@ int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
* RETURNS:
* Newly configured queue depth.
*/
-int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth,
- int reason)
+int ata_scsi_change_queue_depth(struct scsi_device *sdev, int queue_depth)
{
struct ata_port *ap = ata_shost_to_port(sdev->host);
- return __ata_change_queue_depth(ap, sdev, queue_depth, reason);
+ return __ata_change_queue_depth(ap, sdev, queue_depth);
}
/**
@@ -3570,7 +3563,7 @@ void ata_scsi_simulate(struct ata_device *dev, struct scsi_cmnd *cmd)
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
break;
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
if ((scsicmd[1] & 0x1f) == SAI_READ_CAPACITY_16)
ata_scsi_rbuf_fill(&args, ata_scsiop_read_cap);
else
diff --git a/drivers/ata/sata_fsl.c b/drivers/ata/sata_fsl.c
index 07bc7e4..6507159 100644
--- a/drivers/ata/sata_fsl.c
+++ b/drivers/ata/sata_fsl.c
@@ -1488,7 +1488,7 @@ static int sata_fsl_probe(struct platform_device *ofdev)
host_priv->csr_base = csr_base;
irq = irq_of_parse_and_map(ofdev->dev.of_node, 0);
- if (irq < 0) {
+ if (!irq) {
dev_err(&ofdev->dev, "invalid irq from platform\n");
goto error_exit_with_cleanup;
}
diff --git a/drivers/ata/sata_nv.c b/drivers/ata/sata_nv.c
index cdf99fa..1db6f5c 100644
--- a/drivers/ata/sata_nv.c
+++ b/drivers/ata/sata_nv.c
@@ -1951,7 +1951,7 @@ static int nv_swncq_slave_config(struct scsi_device *sdev)
ata_id_c_string(dev->id, model_num, ATA_ID_PROD, sizeof(model_num));
if (strncmp(model_num, "Maxtor", 6) == 0) {
- ata_scsi_change_queue_depth(sdev, 1, SCSI_QDEPTH_DEFAULT);
+ ata_scsi_change_queue_depth(sdev, 1);
ata_dev_notice(dev, "Disabling SWNCQ mode (depth %x)\n",
sdev->queue_depth);
}
diff --git a/drivers/base/Kconfig b/drivers/base/Kconfig
index df04227..98504ec 100644
--- a/drivers/base/Kconfig
+++ b/drivers/base/Kconfig
@@ -267,18 +267,24 @@ comment "Default contiguous memory area size:"
config CMA_SIZE_MBYTES
int "Size in Mega Bytes"
depends on !CMA_SIZE_SEL_PERCENTAGE
+ default 0 if X86
default 16
help
Defines the size (in MiB) of the default memory area for Contiguous
- Memory Allocator.
+ Memory Allocator. If the size of 0 is selected, CMA is disabled by
+ default, but it can be enabled by passing cma=size[MG] to the kernel.
+
config CMA_SIZE_PERCENTAGE
int "Percentage of total memory"
depends on !CMA_SIZE_SEL_MBYTES
+ default 0 if X86
default 10
help
Defines the size of the default memory area for Contiguous Memory
Allocator as a percentage of the total memory in the system.
+ If 0 percent is selected, CMA is disabled by default, but it can be
+ enabled by passing cma=size[MG] to the kernel.
choice
prompt "Selected region size"
diff --git a/drivers/base/Makefile b/drivers/base/Makefile
index 6922cd6..53c3fe1 100644
--- a/drivers/base/Makefile
+++ b/drivers/base/Makefile
@@ -4,7 +4,7 @@ obj-y := component.o core.o bus.o dd.o syscore.o \
driver.o class.o platform.o \
cpu.o firmware.o init.o map.o devres.o \
attribute_container.o transport_class.o \
- topology.o container.o
+ topology.o container.o property.o
obj-$(CONFIG_DEVTMPFS) += devtmpfs.o
obj-$(CONFIG_DMA_CMA) += dma-contiguous.o
obj-y += power/
diff --git a/drivers/base/platform.c b/drivers/base/platform.c
index b2afc29..233ecec 100644
--- a/drivers/base/platform.c
+++ b/drivers/base/platform.c
@@ -1006,6 +1006,7 @@ int __init platform_bus_init(void)
error = bus_register(&platform_bus_type);
if (error)
device_unregister(&platform_bus);
+ of_platform_register_reconfig_notifier();
return error;
}
diff --git a/drivers/base/power/clock_ops.c b/drivers/base/power/clock_ops.c
index 7836930..d626576 100644
--- a/drivers/base/power/clock_ops.c
+++ b/drivers/base/power/clock_ops.c
@@ -12,6 +12,7 @@
#include <linux/pm.h>
#include <linux/pm_clock.h>
#include <linux/clk.h>
+#include <linux/clkdev.h>
#include <linux/slab.h>
#include <linux/err.h>
@@ -34,14 +35,20 @@ struct pm_clock_entry {
/**
* pm_clk_enable - Enable a clock, reporting any errors
* @dev: The device for the given clock
- * @clk: The clock being enabled.
+ * @ce: PM clock entry corresponding to the clock.
*/
-static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
+static inline int __pm_clk_enable(struct device *dev, struct pm_clock_entry *ce)
{
- int ret = clk_enable(clk);
- if (ret)
- dev_err(dev, "%s: failed to enable clk %p, error %d\n",
- __func__, clk, ret);
+ int ret;
+
+ if (ce->status < PCE_STATUS_ERROR) {
+ ret = clk_enable(ce->clk);
+ if (!ret)
+ ce->status = PCE_STATUS_ENABLED;
+ else
+ dev_err(dev, "%s: failed to enable clk %p, error %d\n",
+ __func__, ce->clk, ret);
+ }
return ret;
}
@@ -53,7 +60,8 @@ static inline int __pm_clk_enable(struct device *dev, struct clk *clk)
*/
static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
{
- ce->clk = clk_get(dev, ce->con_id);
+ if (!ce->clk)
+ ce->clk = clk_get(dev, ce->con_id);
if (IS_ERR(ce->clk)) {
ce->status = PCE_STATUS_ERROR;
} else {
@@ -63,15 +71,8 @@ static void pm_clk_acquire(struct device *dev, struct pm_clock_entry *ce)
}
}
-/**
- * pm_clk_add - Start using a device clock for power management.
- * @dev: Device whose clock is going to be used for power management.
- * @con_id: Connection ID of the clock.
- *
- * Add the clock represented by @con_id to the list of clocks used for
- * the power management of @dev.
- */
-int pm_clk_add(struct device *dev, const char *con_id)
+static int __pm_clk_add(struct device *dev, const char *con_id,
+ struct clk *clk)
{
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
@@ -93,6 +94,12 @@ int pm_clk_add(struct device *dev, const char *con_id)
kfree(ce);
return -ENOMEM;
}
+ } else {
+ if (IS_ERR(ce->clk) || !__clk_get(clk)) {
+ kfree(ce);
+ return -ENOENT;
+ }
+ ce->clk = clk;
}
pm_clk_acquire(dev, ce);
@@ -104,6 +111,32 @@ int pm_clk_add(struct device *dev, const char *con_id)
}
/**
+ * pm_clk_add - Start using a device clock for power management.
+ * @dev: Device whose clock is going to be used for power management.
+ * @con_id: Connection ID of the clock.
+ *
+ * Add the clock represented by @con_id to the list of clocks used for
+ * the power management of @dev.
+ */
+int pm_clk_add(struct device *dev, const char *con_id)
+{
+ return __pm_clk_add(dev, con_id, NULL);
+}
+
+/**
+ * pm_clk_add_clk - Start using a device clock for power management.
+ * @dev: Device whose clock is going to be used for power management.
+ * @clk: Clock pointer
+ *
+ * Add the clock to the list of clocks used for the power management of @dev.
+ * It will increment refcount on clock pointer, use clk_put() on it when done.
+ */
+int pm_clk_add_clk(struct device *dev, struct clk *clk)
+{
+ return __pm_clk_add(dev, NULL, clk);
+}
+
+/**
* __pm_clk_remove - Destroy PM clock entry.
* @ce: PM clock entry to destroy.
*/
@@ -223,10 +256,6 @@ void pm_clk_destroy(struct device *dev)
}
}
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
-
/**
* pm_clk_suspend - Disable clocks in a device's PM clock list.
* @dev: Device to disable the clocks for.
@@ -266,7 +295,6 @@ int pm_clk_resume(struct device *dev)
struct pm_subsys_data *psd = dev_to_psd(dev);
struct pm_clock_entry *ce;
unsigned long flags;
- int ret;
dev_dbg(dev, "%s()\n", __func__);
@@ -275,13 +303,8 @@ int pm_clk_resume(struct device *dev)
spin_lock_irqsave(&psd->lock, flags);
- list_for_each_entry(ce, &psd->clock_list, node) {
- if (ce->status < PCE_STATUS_ERROR) {
- ret = __pm_clk_enable(dev, ce->clk);
- if (!ret)
- ce->status = PCE_STATUS_ENABLED;
- }
- }
+ list_for_each_entry(ce, &psd->clock_list, node)
+ __pm_clk_enable(dev, ce);
spin_unlock_irqrestore(&psd->lock, flags);
@@ -346,74 +369,7 @@ static int pm_clk_notify(struct notifier_block *nb,
return 0;
}
-#else /* !CONFIG_PM_RUNTIME */
-
-#ifdef CONFIG_PM
-
-/**
- * pm_clk_suspend - Disable clocks in a device's PM clock list.
- * @dev: Device to disable the clocks for.
- */
-int pm_clk_suspend(struct device *dev)
-{
- struct pm_subsys_data *psd = dev_to_psd(dev);
- struct pm_clock_entry *ce;
- unsigned long flags;
-
- dev_dbg(dev, "%s()\n", __func__);
-
- /* If there is no driver, the clocks are already disabled. */
- if (!psd || !dev->driver)
- return 0;
-
- spin_lock_irqsave(&psd->lock, flags);
-
- list_for_each_entry_reverse(ce, &psd->clock_list, node) {
- if (ce->status < PCE_STATUS_ERROR) {
- if (ce->status == PCE_STATUS_ENABLED)
- clk_disable(ce->clk);
- ce->status = PCE_STATUS_ACQUIRED;
- }
- }
-
- spin_unlock_irqrestore(&psd->lock, flags);
-
- return 0;
-}
-
-/**
- * pm_clk_resume - Enable clocks in a device's PM clock list.
- * @dev: Device to enable the clocks for.
- */
-int pm_clk_resume(struct device *dev)
-{
- struct pm_subsys_data *psd = dev_to_psd(dev);
- struct pm_clock_entry *ce;
- unsigned long flags;
- int ret;
-
- dev_dbg(dev, "%s()\n", __func__);
-
- /* If there is no driver, the clocks should remain disabled. */
- if (!psd || !dev->driver)
- return 0;
-
- spin_lock_irqsave(&psd->lock, flags);
-
- list_for_each_entry(ce, &psd->clock_list, node) {
- if (ce->status < PCE_STATUS_ERROR) {
- ret = __pm_clk_enable(dev, ce->clk);
- if (!ret)
- ce->status = PCE_STATUS_ENABLED;
- }
- }
-
- spin_unlock_irqrestore(&psd->lock, flags);
-
- return 0;
-}
-
-#endif /* CONFIG_PM */
+#else /* !CONFIG_PM */
/**
* enable_clock - Enable a device clock.
@@ -493,7 +449,7 @@ static int pm_clk_notify(struct notifier_block *nb,
return 0;
}
-#endif /* !CONFIG_PM_RUNTIME */
+#endif /* !CONFIG_PM */
/**
* pm_clk_add_notifier - Add bus type notifier for power management clocks.
diff --git a/drivers/base/power/domain.c b/drivers/base/power/domain.c
index fb83d4a..6a103a3 100644
--- a/drivers/base/power/domain.c
+++ b/drivers/base/power/domain.c
@@ -12,6 +12,7 @@
#include <linux/pm_runtime.h>
#include <linux/pm_domain.h>
#include <linux/pm_qos.h>
+#include <linux/pm_clock.h>
#include <linux/slab.h>
#include <linux/err.h>
#include <linux/sched.h>
@@ -151,6 +152,59 @@ static void genpd_recalc_cpu_exit_latency(struct generic_pm_domain *genpd)
genpd->cpuidle_data->idle_state->exit_latency = usecs64;
}
+static int genpd_power_on(struct generic_pm_domain *genpd)
+{
+ ktime_t time_start;
+ s64 elapsed_ns;
+ int ret;
+
+ if (!genpd->power_on)
+ return 0;
+
+ time_start = ktime_get();
+ ret = genpd->power_on(genpd);
+ if (ret)
+ return ret;
+
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns <= genpd->power_on_latency_ns)
+ return ret;
+
+ genpd->power_on_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
+ genpd_recalc_cpu_exit_latency(genpd);
+ pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
+ genpd->name, "on", elapsed_ns);
+
+ return ret;
+}
+
+static int genpd_power_off(struct generic_pm_domain *genpd)
+{
+ ktime_t time_start;
+ s64 elapsed_ns;
+ int ret;
+
+ if (!genpd->power_off)
+ return 0;
+
+ time_start = ktime_get();
+ ret = genpd->power_off(genpd);
+ if (ret == -EBUSY)
+ return ret;
+
+ elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
+ if (elapsed_ns <= genpd->power_off_latency_ns)
+ return ret;
+
+ genpd->power_off_latency_ns = elapsed_ns;
+ genpd->max_off_time_changed = true;
+ pr_warn("%s: Power-%s latency exceeded, new value %lld ns\n",
+ genpd->name, "off", elapsed_ns);
+
+ return ret;
+}
+
/**
* __pm_genpd_poweron - Restore power to a given PM domain and its masters.
* @genpd: PM domain to power up.
@@ -222,25 +276,9 @@ static int __pm_genpd_poweron(struct generic_pm_domain *genpd)
}
}
- if (genpd->power_on) {
- ktime_t time_start = ktime_get();
- s64 elapsed_ns;
-
- ret = genpd->power_on(genpd);
- if (ret)
- goto err;
-
- elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns > genpd->power_on_latency_ns) {
- genpd->power_on_latency_ns = elapsed_ns;
- genpd->max_off_time_changed = true;
- genpd_recalc_cpu_exit_latency(genpd);
- if (genpd->name)
- pr_warning("%s: Power-on latency exceeded, "
- "new value %lld ns\n", genpd->name,
- elapsed_ns);
- }
- }
+ ret = genpd_power_on(genpd);
+ if (ret)
+ goto err;
out:
genpd_set_active(genpd);
@@ -280,8 +318,6 @@ int pm_genpd_name_poweron(const char *domain_name)
return genpd ? pm_genpd_poweron(genpd) : -EINVAL;
}
-#ifdef CONFIG_PM_RUNTIME
-
static int genpd_start_dev_no_timing(struct generic_pm_domain *genpd,
struct device *dev)
{
@@ -544,16 +580,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
}
if (genpd->power_off) {
- ktime_t time_start;
- s64 elapsed_ns;
-
if (atomic_read(&genpd->sd_count) > 0) {
ret = -EBUSY;
goto out;
}
- time_start = ktime_get();
-
/*
* If sd_count > 0 at this point, one of the subdomains hasn't
* managed to call pm_genpd_poweron() for the master yet after
@@ -562,21 +593,11 @@ static int pm_genpd_poweroff(struct generic_pm_domain *genpd)
* the pm_genpd_poweron() restore power for us (this shouldn't
* happen very often).
*/
- ret = genpd->power_off(genpd);
+ ret = genpd_power_off(genpd);
if (ret == -EBUSY) {
genpd_set_active(genpd);
goto out;
}
-
- elapsed_ns = ktime_to_ns(ktime_sub(ktime_get(), time_start));
- if (elapsed_ns > genpd->power_off_latency_ns) {
- genpd->power_off_latency_ns = elapsed_ns;
- genpd->max_off_time_changed = true;
- if (genpd->name)
- pr_warning("%s: Power-off latency exceeded, "
- "new value %lld ns\n", genpd->name,
- elapsed_ns);
- }
}
genpd->status = GPD_STATE_POWER_OFF;
@@ -755,33 +776,15 @@ static int __init genpd_poweroff_unused(void)
}
late_initcall(genpd_poweroff_unused);
-#else
-
-static inline int genpd_dev_pm_qos_notifier(struct notifier_block *nb,
- unsigned long val, void *ptr)
-{
- return NOTIFY_DONE;
-}
-
-static inline void
-genpd_queue_power_off_work(struct generic_pm_domain *genpd) {}
-
-static inline void genpd_power_off_work_fn(struct work_struct *work) {}
-
-#define pm_genpd_runtime_suspend NULL
-#define pm_genpd_runtime_resume NULL
-
-#endif /* CONFIG_PM_RUNTIME */
-
#ifdef CONFIG_PM_SLEEP
/**
* pm_genpd_present - Check if the given PM domain has been initialized.
* @genpd: PM domain to check.
*/
-static bool pm_genpd_present(struct generic_pm_domain *genpd)
+static bool pm_genpd_present(const struct generic_pm_domain *genpd)
{
- struct generic_pm_domain *gpd;
+ const struct generic_pm_domain *gpd;
if (IS_ERR_OR_NULL(genpd))
return false;
@@ -822,8 +825,7 @@ static void pm_genpd_sync_poweroff(struct generic_pm_domain *genpd)
|| atomic_read(&genpd->sd_count) > 0)
return;
- if (genpd->power_off)
- genpd->power_off(genpd);
+ genpd_power_off(genpd);
genpd->status = GPD_STATE_POWER_OFF;
@@ -854,8 +856,7 @@ static void pm_genpd_sync_poweron(struct generic_pm_domain *genpd)
genpd_sd_counter_inc(link->master);
}
- if (genpd->power_on)
- genpd->power_on(genpd);
+ genpd_power_on(genpd);
genpd->status = GPD_STATE_ACTIVE;
}
@@ -1277,8 +1278,7 @@ static int pm_genpd_restore_noirq(struct device *dev)
* If the domain was off before the hibernation, make
* sure it will be off going forward.
*/
- if (genpd->power_off)
- genpd->power_off(genpd);
+ genpd_power_off(genpd);
return 0;
}
@@ -1364,7 +1364,7 @@ void pm_genpd_syscore_poweron(struct device *dev)
}
EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron);
-#else
+#else /* !CONFIG_PM_SLEEP */
#define pm_genpd_prepare NULL
#define pm_genpd_suspend NULL
@@ -1929,6 +1929,12 @@ void pm_genpd_init(struct generic_pm_domain *genpd,
genpd->domain.ops.complete = pm_genpd_complete;
genpd->dev_ops.save_state = pm_genpd_default_save_state;
genpd->dev_ops.restore_state = pm_genpd_default_restore_state;
+
+ if (genpd->flags & GENPD_FLAG_PM_CLK) {
+ genpd->dev_ops.stop = pm_clk_suspend;
+ genpd->dev_ops.start = pm_clk_resume;
+ }
+
mutex_lock(&gpd_list_lock);
list_add(&genpd->gpd_list_node, &gpd_list);
mutex_unlock(&gpd_list_lock);
@@ -2216,11 +2222,12 @@ int genpd_dev_pm_attach(struct device *dev)
}
dev->pm_domain->detach = genpd_dev_pm_detach;
+ pm_genpd_poweron(pd);
return 0;
}
EXPORT_SYMBOL_GPL(genpd_dev_pm_attach);
-#endif
+#endif /* CONFIG_PM_GENERIC_DOMAINS_OF */
/*** debugfs support ***/
@@ -2236,10 +2243,8 @@ static struct dentry *pm_genpd_debugfs_dir;
/*
* TODO: This function is a slightly modified version of rtpm_status_show
- * from sysfs.c, but dependencies between PM_GENERIC_DOMAINS and PM_RUNTIME
- * are too loose to generalize it.
+ * from sysfs.c, so generalize it.
*/
-#ifdef CONFIG_PM_RUNTIME
static void rtpm_status_str(struct seq_file *s, struct device *dev)
{
static const char * const status_lookup[] = {
@@ -2261,12 +2266,6 @@ static void rtpm_status_str(struct seq_file *s, struct device *dev)
seq_puts(s, p);
}
-#else
-static void rtpm_status_str(struct seq_file *s, struct device *dev)
-{
- seq_puts(s, "active");
-}
-#endif
static int pm_genpd_summary_one(struct seq_file *s,
struct generic_pm_domain *gpd)
diff --git a/drivers/base/power/domain_governor.c b/drivers/base/power/domain_governor.c
index d88a62e..2a4154a 100644
--- a/drivers/base/power/domain_governor.c
+++ b/drivers/base/power/domain_governor.c
@@ -11,8 +11,6 @@
#include <linux/pm_qos.h>
#include <linux/hrtimer.h>
-#ifdef CONFIG_PM_RUNTIME
-
static int dev_update_qos_constraint(struct device *dev, void *data)
{
s64 *constraint_ns_p = data;
@@ -227,15 +225,6 @@ static bool always_on_power_down_ok(struct dev_pm_domain *domain)
return false;
}
-#else /* !CONFIG_PM_RUNTIME */
-
-static inline bool default_stop_ok(struct device *dev) { return false; }
-
-#define default_power_down_ok NULL
-#define always_on_power_down_ok NULL
-
-#endif /* !CONFIG_PM_RUNTIME */
-
struct dev_power_governor simple_qos_governor = {
.stop_ok = default_stop_ok,
.power_down_ok = default_power_down_ok,
diff --git a/drivers/base/power/opp.c b/drivers/base/power/opp.c
index 89ced95..2d195f3 100644
--- a/drivers/base/power/opp.c
+++ b/drivers/base/power/opp.c
@@ -49,11 +49,12 @@
* are protected by the dev_opp_list_lock for integrity.
* IMPORTANT: the opp nodes should be maintained in increasing
* order.
+ * @dynamic: not-created from static DT entries.
* @available: true/false - marks if this OPP as available or not
* @rate: Frequency in hertz
* @u_volt: Nominal voltage in microvolts corresponding to this OPP
* @dev_opp: points back to the device_opp struct this opp belongs to
- * @head: RCU callback head used for deferred freeing
+ * @rcu_head: RCU callback head used for deferred freeing
*
* This structure stores the OPP information for a given device.
*/
@@ -61,11 +62,12 @@ struct dev_pm_opp {
struct list_head node;
bool available;
+ bool dynamic;
unsigned long rate;
unsigned long u_volt;
struct device_opp *dev_opp;
- struct rcu_head head;
+ struct rcu_head rcu_head;
};
/**
@@ -76,7 +78,8 @@ struct dev_pm_opp {
* RCU usage: nodes are not modified in the list of device_opp,
* however addition is possible and is secured by dev_opp_list_lock
* @dev: device pointer
- * @head: notifier head to notify the OPP availability changes.
+ * @srcu_head: notifier head to notify the OPP availability changes.
+ * @rcu_head: RCU callback head used for deferred freeing
* @opp_list: list of opps
*
* This is an internal data structure maintaining the link to opps attached to
@@ -87,7 +90,8 @@ struct device_opp {
struct list_head node;
struct device *dev;
- struct srcu_notifier_head head;
+ struct srcu_notifier_head srcu_head;
+ struct rcu_head rcu_head;
struct list_head opp_list;
};
@@ -378,30 +382,8 @@ struct dev_pm_opp *dev_pm_opp_find_freq_floor(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_opp_find_freq_floor);
-/**
- * dev_pm_opp_add() - Add an OPP table from a table definitions
- * @dev: device for which we do this operation
- * @freq: Frequency in Hz for this OPP
- * @u_volt: Voltage in uVolts for this OPP
- *
- * This function adds an opp definition to the opp list and returns status.
- * The opp is made available by default and it can be controlled using
- * dev_pm_opp_enable/disable functions.
- *
- * Locking: The internal device_opp and opp structures are RCU protected.
- * Hence this function internally uses RCU updater strategy with mutex locks
- * to keep the integrity of the internal data structures. Callers should ensure
- * that this function is *NOT* called under RCU protection or in contexts where
- * mutex cannot be locked.
- *
- * Return:
- * 0: On success OR
- * Duplicate OPPs (both freq and volt are same) and opp->available
- * -EEXIST: Freq are same and volt are different OR
- * Duplicate OPPs (both freq and volt are same) and !opp->available
- * -ENOMEM: Memory allocation failure
- */
-int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
+static int dev_pm_opp_add_dynamic(struct device *dev, unsigned long freq,
+ unsigned long u_volt, bool dynamic)
{
struct device_opp *dev_opp = NULL;
struct dev_pm_opp *opp, *new_opp;
@@ -417,6 +399,13 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
/* Hold our list modification lock here */
mutex_lock(&dev_opp_list_lock);
+ /* populate the opp table */
+ new_opp->dev_opp = dev_opp;
+ new_opp->rate = freq;
+ new_opp->u_volt = u_volt;
+ new_opp->available = true;
+ new_opp->dynamic = dynamic;
+
/* Check for existing list for 'dev' */
dev_opp = find_device_opp(dev);
if (IS_ERR(dev_opp)) {
@@ -436,19 +425,15 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
}
dev_opp->dev = dev;
- srcu_init_notifier_head(&dev_opp->head);
+ srcu_init_notifier_head(&dev_opp->srcu_head);
INIT_LIST_HEAD(&dev_opp->opp_list);
/* Secure the device list modification */
list_add_rcu(&dev_opp->node, &dev_opp_list);
+ head = &dev_opp->opp_list;
+ goto list_add;
}
- /* populate the opp table */
- new_opp->dev_opp = dev_opp;
- new_opp->rate = freq;
- new_opp->u_volt = u_volt;
- new_opp->available = true;
-
/*
* Insert new OPP in order of increasing frequency
* and discard if already present
@@ -474,6 +459,7 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
return ret;
}
+list_add:
list_add_rcu(&new_opp->node, head);
mutex_unlock(&dev_opp_list_lock);
@@ -481,11 +467,109 @@ int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
* Notify the changes in the availability of the operable
* frequency/voltage list.
*/
- srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ADD, new_opp);
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ADD, new_opp);
return 0;
}
+
+/**
+ * dev_pm_opp_add() - Add an OPP table from a table definitions
+ * @dev: device for which we do this operation
+ * @freq: Frequency in Hz for this OPP
+ * @u_volt: Voltage in uVolts for this OPP
+ *
+ * This function adds an opp definition to the opp list and returns status.
+ * The opp is made available by default and it can be controlled using
+ * dev_pm_opp_enable/disable functions.
+ *
+ * Locking: The internal device_opp and opp structures are RCU protected.
+ * Hence this function internally uses RCU updater strategy with mutex locks
+ * to keep the integrity of the internal data structures. Callers should ensure
+ * that this function is *NOT* called under RCU protection or in contexts where
+ * mutex cannot be locked.
+ *
+ * Return:
+ * 0: On success OR
+ * Duplicate OPPs (both freq and volt are same) and opp->available
+ * -EEXIST: Freq are same and volt are different OR
+ * Duplicate OPPs (both freq and volt are same) and !opp->available
+ * -ENOMEM: Memory allocation failure
+ */
+int dev_pm_opp_add(struct device *dev, unsigned long freq, unsigned long u_volt)
+{
+ return dev_pm_opp_add_dynamic(dev, freq, u_volt, true);
+}
EXPORT_SYMBOL_GPL(dev_pm_opp_add);
+static void kfree_opp_rcu(struct rcu_head *head)
+{
+ struct dev_pm_opp *opp = container_of(head, struct dev_pm_opp, rcu_head);
+
+ kfree_rcu(opp, rcu_head);
+}
+
+static void kfree_device_rcu(struct rcu_head *head)
+{
+ struct device_opp *device_opp = container_of(head, struct device_opp, rcu_head);
+
+ kfree(device_opp);
+}
+
+void __dev_pm_opp_remove(struct device_opp *dev_opp, struct dev_pm_opp *opp)
+{
+ /*
+ * Notify the changes in the availability of the operable
+ * frequency/voltage list.
+ */
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_REMOVE, opp);
+ list_del_rcu(&opp->node);
+ call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
+
+ if (list_empty(&dev_opp->opp_list)) {
+ list_del_rcu(&dev_opp->node);
+ call_srcu(&dev_opp->srcu_head.srcu, &dev_opp->rcu_head,
+ kfree_device_rcu);
+ }
+}
+
+/**
+ * dev_pm_opp_remove() - Remove an OPP from OPP list
+ * @dev: device for which we do this operation
+ * @freq: OPP to remove with matching 'freq'
+ *
+ * This function removes an opp from the opp list.
+ */
+void dev_pm_opp_remove(struct device *dev, unsigned long freq)
+{
+ struct dev_pm_opp *opp;
+ struct device_opp *dev_opp;
+ bool found = false;
+
+ /* Hold our list modification lock here */
+ mutex_lock(&dev_opp_list_lock);
+
+ dev_opp = find_device_opp(dev);
+ if (IS_ERR(dev_opp))
+ goto unlock;
+
+ list_for_each_entry(opp, &dev_opp->opp_list, node) {
+ if (opp->rate == freq) {
+ found = true;
+ break;
+ }
+ }
+
+ if (!found) {
+ dev_warn(dev, "%s: Couldn't find OPP with freq: %lu\n",
+ __func__, freq);
+ goto unlock;
+ }
+
+ __dev_pm_opp_remove(dev_opp, opp);
+unlock:
+ mutex_unlock(&dev_opp_list_lock);
+}
+EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
+
/**
* opp_set_availability() - helper to set the availability of an opp
* @dev: device for which we do this operation
@@ -557,14 +641,14 @@ static int opp_set_availability(struct device *dev, unsigned long freq,
list_replace_rcu(&opp->node, &new_opp->node);
mutex_unlock(&dev_opp_list_lock);
- kfree_rcu(opp, head);
+ call_srcu(&dev_opp->srcu_head.srcu, &opp->rcu_head, kfree_opp_rcu);
/* Notify the change of the OPP availability */
if (availability_req)
- srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_ENABLE,
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_ENABLE,
new_opp);
else
- srcu_notifier_call_chain(&dev_opp->head, OPP_EVENT_DISABLE,
+ srcu_notifier_call_chain(&dev_opp->srcu_head, OPP_EVENT_DISABLE,
new_opp);
return 0;
@@ -629,7 +713,7 @@ struct srcu_notifier_head *dev_pm_opp_get_notifier(struct device *dev)
if (IS_ERR(dev_opp))
return ERR_CAST(dev_opp); /* matching type */
- return &dev_opp->head;
+ return &dev_opp->srcu_head;
}
#ifdef CONFIG_OF
@@ -666,7 +750,7 @@ int of_init_opp_table(struct device *dev)
unsigned long freq = be32_to_cpup(val++) * 1000;
unsigned long volt = be32_to_cpup(val++);
- if (dev_pm_opp_add(dev, freq, volt))
+ if (dev_pm_opp_add_dynamic(dev, freq, volt, false))
dev_warn(dev, "%s: Failed to add OPP %ld\n",
__func__, freq);
nr -= 2;
@@ -675,4 +759,34 @@ int of_init_opp_table(struct device *dev)
return 0;
}
EXPORT_SYMBOL_GPL(of_init_opp_table);
+
+/**
+ * of_free_opp_table() - Free OPP table entries created from static DT entries
+ * @dev: device pointer used to lookup device OPPs.
+ *
+ * Free OPPs created using static entries present in DT.
+ */
+void of_free_opp_table(struct device *dev)
+{
+ struct device_opp *dev_opp = find_device_opp(dev);
+ struct dev_pm_opp *opp, *tmp;
+
+ /* Check for existing list for 'dev' */
+ dev_opp = find_device_opp(dev);
+ if (WARN(IS_ERR(dev_opp), "%s: dev_opp: %ld\n", dev_name(dev),
+ PTR_ERR(dev_opp)))
+ return;
+
+ /* Hold our list modification lock here */
+ mutex_lock(&dev_opp_list_lock);
+
+ /* Free static OPPs */
+ list_for_each_entry_safe(opp, tmp, &dev_opp->opp_list, node) {
+ if (!opp->dynamic)
+ __dev_pm_opp_remove(dev_opp, opp);
+ }
+
+ mutex_unlock(&dev_opp_list_lock);
+}
+EXPORT_SYMBOL_GPL(of_free_opp_table);
#endif
diff --git a/drivers/base/power/power.h b/drivers/base/power/power.h
index a21223d..b6b8a27 100644
--- a/drivers/base/power/power.h
+++ b/drivers/base/power/power.h
@@ -9,7 +9,7 @@ static inline void device_pm_init_common(struct device *dev)
}
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static inline void pm_runtime_early_init(struct device *dev)
{
@@ -20,7 +20,21 @@ static inline void pm_runtime_early_init(struct device *dev)
extern void pm_runtime_init(struct device *dev);
extern void pm_runtime_remove(struct device *dev);
-#else /* !CONFIG_PM_RUNTIME */
+/*
+ * sysfs.c
+ */
+
+extern int dpm_sysfs_add(struct device *dev);
+extern void dpm_sysfs_remove(struct device *dev);
+extern void rpm_sysfs_remove(struct device *dev);
+extern int wakeup_sysfs_add(struct device *dev);
+extern void wakeup_sysfs_remove(struct device *dev);
+extern int pm_qos_sysfs_add_resume_latency(struct device *dev);
+extern void pm_qos_sysfs_remove_resume_latency(struct device *dev);
+extern int pm_qos_sysfs_add_flags(struct device *dev);
+extern void pm_qos_sysfs_remove_flags(struct device *dev);
+
+#else /* CONFIG_PM */
static inline void pm_runtime_early_init(struct device *dev)
{
@@ -30,7 +44,15 @@ static inline void pm_runtime_early_init(struct device *dev)
static inline void pm_runtime_init(struct device *dev) {}
static inline void pm_runtime_remove(struct device *dev) {}
-#endif /* !CONFIG_PM_RUNTIME */
+static inline int dpm_sysfs_add(struct device *dev) { return 0; }
+static inline void dpm_sysfs_remove(struct device *dev) {}
+static inline void rpm_sysfs_remove(struct device *dev) {}
+static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
+static inline void wakeup_sysfs_remove(struct device *dev) {}
+static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
+static inline void pm_qos_sysfs_remove(struct device *dev) {}
+
+#endif
#ifdef CONFIG_PM_SLEEP
@@ -77,31 +99,3 @@ static inline void device_pm_init(struct device *dev)
device_pm_sleep_init(dev);
pm_runtime_init(dev);
}
-
-#ifdef CONFIG_PM
-
-/*
- * sysfs.c
- */
-
-extern int dpm_sysfs_add(struct device *dev);
-extern void dpm_sysfs_remove(struct device *dev);
-extern void rpm_sysfs_remove(struct device *dev);
-extern int wakeup_sysfs_add(struct device *dev);
-extern void wakeup_sysfs_remove(struct device *dev);
-extern int pm_qos_sysfs_add_resume_latency(struct device *dev);
-extern void pm_qos_sysfs_remove_resume_latency(struct device *dev);
-extern int pm_qos_sysfs_add_flags(struct device *dev);
-extern void pm_qos_sysfs_remove_flags(struct device *dev);
-
-#else /* CONFIG_PM */
-
-static inline int dpm_sysfs_add(struct device *dev) { return 0; }
-static inline void dpm_sysfs_remove(struct device *dev) {}
-static inline void rpm_sysfs_remove(struct device *dev) {}
-static inline int wakeup_sysfs_add(struct device *dev) { return 0; }
-static inline void wakeup_sysfs_remove(struct device *dev) {}
-static inline int pm_qos_sysfs_add(struct device *dev) { return 0; }
-static inline void pm_qos_sysfs_remove(struct device *dev) {}
-
-#endif
diff --git a/drivers/base/power/qos.c b/drivers/base/power/qos.c
index 36b9eb4..a8fe4c1 100644
--- a/drivers/base/power/qos.c
+++ b/drivers/base/power/qos.c
@@ -599,7 +599,6 @@ int dev_pm_qos_add_ancestor_request(struct device *dev,
}
EXPORT_SYMBOL_GPL(dev_pm_qos_add_ancestor_request);
-#ifdef CONFIG_PM_RUNTIME
static void __dev_pm_qos_drop_user_request(struct device *dev,
enum dev_pm_qos_req_type type)
{
@@ -880,7 +879,3 @@ int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val)
mutex_unlock(&dev_pm_qos_mtx);
return ret;
}
-#else /* !CONFIG_PM_RUNTIME */
-static void __dev_pm_qos_hide_latency_limit(struct device *dev) {}
-static void __dev_pm_qos_hide_flags(struct device *dev) {}
-#endif /* CONFIG_PM_RUNTIME */
diff --git a/drivers/base/power/runtime.c b/drivers/base/power/runtime.c
index 67c7938..5070c4f 100644
--- a/drivers/base/power/runtime.c
+++ b/drivers/base/power/runtime.c
@@ -13,43 +13,38 @@
#include <trace/events/rpm.h>
#include "power.h"
-#define RPM_GET_CALLBACK(dev, cb) \
-({ \
- int (*__rpm_cb)(struct device *__d); \
- \
- if (dev->pm_domain) \
- __rpm_cb = dev->pm_domain->ops.cb; \
- else if (dev->type && dev->type->pm) \
- __rpm_cb = dev->type->pm->cb; \
- else if (dev->class && dev->class->pm) \
- __rpm_cb = dev->class->pm->cb; \
- else if (dev->bus && dev->bus->pm) \
- __rpm_cb = dev->bus->pm->cb; \
- else \
- __rpm_cb = NULL; \
- \
- if (!__rpm_cb && dev->driver && dev->driver->pm) \
- __rpm_cb = dev->driver->pm->cb; \
- \
- __rpm_cb; \
-})
-
-static int (*rpm_get_suspend_cb(struct device *dev))(struct device *)
-{
- return RPM_GET_CALLBACK(dev, runtime_suspend);
-}
+typedef int (*pm_callback_t)(struct device *);
-static int (*rpm_get_resume_cb(struct device *dev))(struct device *)
+static pm_callback_t __rpm_get_callback(struct device *dev, size_t cb_offset)
{
- return RPM_GET_CALLBACK(dev, runtime_resume);
-}
+ pm_callback_t cb;
+ const struct dev_pm_ops *ops;
+
+ if (dev->pm_domain)
+ ops = &dev->pm_domain->ops;
+ else if (dev->type && dev->type->pm)
+ ops = dev->type->pm;
+ else if (dev->class && dev->class->pm)
+ ops = dev->class->pm;
+ else if (dev->bus && dev->bus->pm)
+ ops = dev->bus->pm;
+ else
+ ops = NULL;
-#ifdef CONFIG_PM_RUNTIME
-static int (*rpm_get_idle_cb(struct device *dev))(struct device *)
-{
- return RPM_GET_CALLBACK(dev, runtime_idle);
+ if (ops)
+ cb = *(pm_callback_t *)((void *)ops + cb_offset);
+ else
+ cb = NULL;
+
+ if (!cb && dev->driver && dev->driver->pm)
+ cb = *(pm_callback_t *)((void *)dev->driver->pm + cb_offset);
+
+ return cb;
}
+#define RPM_GET_CALLBACK(dev, callback) \
+ __rpm_get_callback(dev, offsetof(struct dev_pm_ops, callback))
+
static int rpm_resume(struct device *dev, int rpmflags);
static int rpm_suspend(struct device *dev, int rpmflags);
@@ -347,7 +342,7 @@ static int rpm_idle(struct device *dev, int rpmflags)
dev->power.idle_notification = true;
- callback = rpm_get_idle_cb(dev);
+ callback = RPM_GET_CALLBACK(dev, runtime_idle);
if (callback)
retval = __rpm_callback(callback, dev);
@@ -517,7 +512,7 @@ static int rpm_suspend(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_SUSPENDING);
- callback = rpm_get_suspend_cb(dev);
+ callback = RPM_GET_CALLBACK(dev, runtime_suspend);
retval = rpm_callback(callback, dev);
if (retval)
@@ -737,7 +732,7 @@ static int rpm_resume(struct device *dev, int rpmflags)
__update_runtime_status(dev, RPM_RESUMING);
- callback = rpm_get_resume_cb(dev);
+ callback = RPM_GET_CALLBACK(dev, runtime_resume);
retval = rpm_callback(callback, dev);
if (retval) {
@@ -1402,7 +1397,6 @@ void pm_runtime_remove(struct device *dev)
if (dev->power.irq_safe && dev->parent)
pm_runtime_put(dev->parent);
}
-#endif
/**
* pm_runtime_force_suspend - Force a device into suspend state if needed.
@@ -1422,16 +1416,10 @@ int pm_runtime_force_suspend(struct device *dev)
int ret = 0;
pm_runtime_disable(dev);
-
- /*
- * Note that pm_runtime_status_suspended() returns false while
- * !CONFIG_PM_RUNTIME, which means the device will be put into low
- * power state.
- */
if (pm_runtime_status_suspended(dev))
return 0;
- callback = rpm_get_suspend_cb(dev);
+ callback = RPM_GET_CALLBACK(dev, runtime_suspend);
if (!callback) {
ret = -ENOSYS;
@@ -1467,7 +1455,7 @@ int pm_runtime_force_resume(struct device *dev)
int (*callback)(struct device *);
int ret = 0;
- callback = rpm_get_resume_cb(dev);
+ callback = RPM_GET_CALLBACK(dev, runtime_resume);
if (!callback) {
ret = -ENOSYS;
diff --git a/drivers/base/power/sysfs.c b/drivers/base/power/sysfs.c
index a9d26ed..d2be3f9 100644
--- a/drivers/base/power/sysfs.c
+++ b/drivers/base/power/sysfs.c
@@ -95,7 +95,6 @@
const char power_group_name[] = "power";
EXPORT_SYMBOL_GPL(power_group_name);
-#ifdef CONFIG_PM_RUNTIME
static const char ctrl_auto[] = "auto";
static const char ctrl_on[] = "on";
@@ -330,7 +329,6 @@ static ssize_t pm_qos_remote_wakeup_store(struct device *dev,
static DEVICE_ATTR(pm_qos_remote_wakeup, 0644,
pm_qos_remote_wakeup_show, pm_qos_remote_wakeup_store);
-#endif /* CONFIG_PM_RUNTIME */
#ifdef CONFIG_PM_SLEEP
static const char _enabled[] = "enabled";
@@ -531,8 +529,6 @@ static DEVICE_ATTR(wakeup_prevent_sleep_time_ms, 0444,
#endif /* CONFIG_PM_SLEEP */
#ifdef CONFIG_PM_ADVANCED_DEBUG
-#ifdef CONFIG_PM_RUNTIME
-
static ssize_t rtpm_usagecount_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -562,10 +558,7 @@ static DEVICE_ATTR(runtime_usage, 0444, rtpm_usagecount_show, NULL);
static DEVICE_ATTR(runtime_active_kids, 0444, rtpm_children_show, NULL);
static DEVICE_ATTR(runtime_enabled, 0444, rtpm_enabled_show, NULL);
-#endif
-
#ifdef CONFIG_PM_SLEEP
-
static ssize_t async_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -595,7 +588,7 @@ static ssize_t async_store(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR(async, 0644, async_show, async_store);
-#endif
+#endif /* CONFIG_PM_SLEEP */
#endif /* CONFIG_PM_ADVANCED_DEBUG */
static struct attribute *power_attrs[] = {
@@ -603,12 +596,10 @@ static struct attribute *power_attrs[] = {
#ifdef CONFIG_PM_SLEEP
&dev_attr_async.attr,
#endif
-#ifdef CONFIG_PM_RUNTIME
&dev_attr_runtime_status.attr,
&dev_attr_runtime_usage.attr,
&dev_attr_runtime_active_kids.attr,
&dev_attr_runtime_enabled.attr,
-#endif
#endif /* CONFIG_PM_ADVANCED_DEBUG */
NULL,
};
@@ -640,7 +631,6 @@ static struct attribute_group pm_wakeup_attr_group = {
};
static struct attribute *runtime_attrs[] = {
-#ifdef CONFIG_PM_RUNTIME
#ifndef CONFIG_PM_ADVANCED_DEBUG
&dev_attr_runtime_status.attr,
#endif
@@ -648,7 +638,6 @@ static struct attribute *runtime_attrs[] = {
&dev_attr_runtime_suspended_time.attr,
&dev_attr_runtime_active_time.attr,
&dev_attr_autosuspend_delay_ms.attr,
-#endif /* CONFIG_PM_RUNTIME */
NULL,
};
static struct attribute_group pm_runtime_attr_group = {
@@ -657,9 +646,7 @@ static struct attribute_group pm_runtime_attr_group = {
};
static struct attribute *pm_qos_resume_latency_attrs[] = {
-#ifdef CONFIG_PM_RUNTIME
&dev_attr_pm_qos_resume_latency_us.attr,
-#endif /* CONFIG_PM_RUNTIME */
NULL,
};
static struct attribute_group pm_qos_resume_latency_attr_group = {
@@ -668,9 +655,7 @@ static struct attribute_group pm_qos_resume_latency_attr_group = {
};
static struct attribute *pm_qos_latency_tolerance_attrs[] = {
-#ifdef CONFIG_PM_RUNTIME
&dev_attr_pm_qos_latency_tolerance_us.attr,
-#endif /* CONFIG_PM_RUNTIME */
NULL,
};
static struct attribute_group pm_qos_latency_tolerance_attr_group = {
@@ -679,10 +664,8 @@ static struct attribute_group pm_qos_latency_tolerance_attr_group = {
};
static struct attribute *pm_qos_flags_attrs[] = {
-#ifdef CONFIG_PM_RUNTIME
&dev_attr_pm_qos_no_power_off.attr,
&dev_attr_pm_qos_remote_wakeup.attr,
-#endif /* CONFIG_PM_RUNTIME */
NULL,
};
static struct attribute_group pm_qos_flags_attr_group = {
diff --git a/drivers/base/property.c b/drivers/base/property.c
new file mode 100644
index 0000000..c458458
--- /dev/null
+++ b/drivers/base/property.c
@@ -0,0 +1,431 @@
+/*
+ * property.c - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ * Mika Westerberg <mika.westerberg@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/property.h>
+#include <linux/export.h>
+#include <linux/acpi.h>
+#include <linux/of.h>
+
+/**
+ * device_property_present - check if a property of a device is present
+ * @dev: Device whose property is being checked
+ * @propname: Name of the property
+ *
+ * Check if property @propname is present in the device firmware description.
+ */
+bool device_property_present(struct device *dev, const char *propname)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node)
+ return of_property_read_bool(dev->of_node, propname);
+
+ return !acpi_dev_prop_get(ACPI_COMPANION(dev), propname, NULL);
+}
+EXPORT_SYMBOL_GPL(device_property_present);
+
+/**
+ * fwnode_property_present - check if a property of a firmware node is present
+ * @fwnode: Firmware node whose property to check
+ * @propname: Name of the property
+ */
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_bool(of_node(fwnode), propname);
+ else if (is_acpi_node(fwnode))
+ return !acpi_dev_prop_get(acpi_node(fwnode), propname, NULL);
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_present);
+
+#define OF_DEV_PROP_READ_ARRAY(node, propname, type, val, nval) \
+ (val) ? of_property_read_##type##_array((node), (propname), (val), (nval)) \
+ : of_property_count_elems_of_size((node), (propname), sizeof(type))
+
+#define DEV_PROP_READ_ARRAY(_dev_, _propname_, _type_, _proptype_, _val_, _nval_) \
+ IS_ENABLED(CONFIG_OF) && _dev_->of_node ? \
+ (OF_DEV_PROP_READ_ARRAY(_dev_->of_node, _propname_, _type_, \
+ _val_, _nval_)) : \
+ acpi_dev_prop_read(ACPI_COMPANION(_dev_), _propname_, \
+ _proptype_, _val_, _nval_)
+
+/**
+ * device_property_read_u8_array - return a u8 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u8 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u8, DEV_PROP_U8, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u8_array);
+
+/**
+ * device_property_read_u16_array - return a u16 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u16 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u16, DEV_PROP_U16, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u16_array);
+
+/**
+ * device_property_read_u32_array - return a u32 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u32 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u32, DEV_PROP_U32, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u32_array);
+
+/**
+ * device_property_read_u64_array - return a u64 array property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of u64 properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval)
+{
+ return DEV_PROP_READ_ARRAY(dev, propname, u64, DEV_PROP_U64, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_u64_array);
+
+/**
+ * device_property_read_string_array - return a string array property of device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Function reads an array of string properties with @propname from the device
+ * firmware description and stores them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected.
+ */
+int device_property_read_string_array(struct device *dev, const char *propname,
+ const char **val, size_t nval)
+{
+ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+ of_property_read_string_array(dev->of_node, propname, val, nval) :
+ acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val, nval);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string_array);
+
+/**
+ * device_property_read_string - return a string property of a device
+ * @dev: Device to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Function reads property @propname from the device firmware description and
+ * stores the value into @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property type is not a string.
+ */
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val)
+{
+ return IS_ENABLED(CONFIG_OF) && dev->of_node ?
+ of_property_read_string(dev->of_node, propname, val) :
+ acpi_dev_prop_read(ACPI_COMPANION(dev), propname,
+ DEV_PROP_STRING, val, 1);
+}
+EXPORT_SYMBOL_GPL(device_property_read_string);
+
+#define FWNODE_PROP_READ_ARRAY(_fwnode_, _propname_, _type_, _proptype_, _val_, _nval_) \
+({ \
+ int _ret_; \
+ if (is_of_node(_fwnode_)) \
+ _ret_ = OF_DEV_PROP_READ_ARRAY(of_node(_fwnode_), _propname_, \
+ _type_, _val_, _nval_); \
+ else if (is_acpi_node(_fwnode_)) \
+ _ret_ = acpi_dev_prop_read(acpi_node(_fwnode_), _propname_, \
+ _proptype_, _val_, _nval_); \
+ else \
+ _ret_ = -ENXIO; \
+ _ret_; \
+})
+
+/**
+ * fwnode_property_read_u8_array - return a u8 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u8 properties with @propname from @fwnode and stores them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u8, DEV_PROP_U8,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u8_array);
+
+/**
+ * fwnode_property_read_u16_array - return a u16 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u16 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u16, DEV_PROP_U16,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u16_array);
+
+/**
+ * fwnode_property_read_u32_array - return a u32 array property of firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u32 properties with @propname from @fwnode store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u32, DEV_PROP_U32,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u32_array);
+
+/**
+ * fwnode_property_read_u64_array - return a u64 array property firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an array of u64 properties with @propname from @fwnode and store them to
+ * @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of numbers,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val, size_t nval)
+{
+ return FWNODE_PROP_READ_ARRAY(fwnode, propname, u64, DEV_PROP_U64,
+ val, nval);
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_u64_array);
+
+/**
+ * fwnode_property_read_string_array - return string array property of a node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The values are stored here
+ * @nval: Size of the @val array
+ *
+ * Read an string list property @propname from the given firmware node and store
+ * them to @val if found.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO if the property is not an array of strings,
+ * %-EOVERFLOW if the size of the property is not as expected,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, const char **val,
+ size_t nval)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string_array(of_node(fwnode), propname,
+ val, nval);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, nval);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string_array);
+
+/**
+ * fwnode_property_read_string - return a string property of a firmware node
+ * @fwnode: Firmware node to get the property of
+ * @propname: Name of the property
+ * @val: The value is stored here
+ *
+ * Read property @propname from the given firmware node and store the value into
+ * @val if found. The value is checked to be a string.
+ *
+ * Return: %0 if the property was found (success),
+ * %-EINVAL if given arguments are not valid,
+ * %-ENODATA if the property does not have a value,
+ * %-EPROTO or %-EILSEQ if the property is not a string,
+ * %-ENXIO if no suitable firmware interface is present.
+ */
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val)
+{
+ if (is_of_node(fwnode))
+ return of_property_read_string(of_node(fwnode),propname, val);
+ else if (is_acpi_node(fwnode))
+ return acpi_dev_prop_read(acpi_node(fwnode), propname,
+ DEV_PROP_STRING, val, 1);
+
+ return -ENXIO;
+}
+EXPORT_SYMBOL_GPL(fwnode_property_read_string);
+
+/**
+ * device_get_next_child_node - Return the next child node handle for a device
+ * @dev: Device to find the next child node for.
+ * @child: Handle to one of the device's child nodes or a null handle.
+ */
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child)
+{
+ if (IS_ENABLED(CONFIG_OF) && dev->of_node) {
+ struct device_node *node;
+
+ node = of_get_next_available_child(dev->of_node, of_node(child));
+ if (node)
+ return &node->fwnode;
+ } else if (IS_ENABLED(CONFIG_ACPI)) {
+ struct acpi_device *node;
+
+ node = acpi_get_next_child(dev, acpi_node(child));
+ if (node)
+ return acpi_fwnode_handle(node);
+ }
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(device_get_next_child_node);
+
+/**
+ * fwnode_handle_put - Drop reference to a device node
+ * @fwnode: Pointer to the device node to drop the reference to.
+ *
+ * This has to be used when terminating device_for_each_child_node() iteration
+ * with break or return to prevent stale device node references from being left
+ * behind.
+ */
+void fwnode_handle_put(struct fwnode_handle *fwnode)
+{
+ if (is_of_node(fwnode))
+ of_node_put(of_node(fwnode));
+}
+EXPORT_SYMBOL_GPL(fwnode_handle_put);
+
+/**
+ * device_get_child_node_count - return the number of child nodes for device
+ * @dev: Device to cound the child nodes for
+ */
+unsigned int device_get_child_node_count(struct device *dev)
+{
+ struct fwnode_handle *child;
+ unsigned int count = 0;
+
+ device_for_each_child_node(dev, child)
+ count++;
+
+ return count;
+}
+EXPORT_SYMBOL_GPL(device_get_child_node_count);
diff --git a/drivers/base/regmap/Kconfig b/drivers/base/regmap/Kconfig
index 8a3f51f..db9d00c3 100644
--- a/drivers/base/regmap/Kconfig
+++ b/drivers/base/regmap/Kconfig
@@ -3,12 +3,15 @@
# subsystems should select the appropriate symbols.
config REGMAP
- default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_MMIO || REGMAP_IRQ)
+ default y if (REGMAP_I2C || REGMAP_SPI || REGMAP_SPMI || REGMAP_AC97 || REGMAP_MMIO || REGMAP_IRQ)
select LZO_COMPRESS
select LZO_DECOMPRESS
select IRQ_DOMAIN if REGMAP_IRQ
bool
+config REGMAP_AC97
+ tristate
+
config REGMAP_I2C
tristate
depends on I2C
diff --git a/drivers/base/regmap/Makefile b/drivers/base/regmap/Makefile
index a7c670b..0a53365 100644
--- a/drivers/base/regmap/Makefile
+++ b/drivers/base/regmap/Makefile
@@ -1,6 +1,7 @@
obj-$(CONFIG_REGMAP) += regmap.o regcache.o
obj-$(CONFIG_REGMAP) += regcache-rbtree.o regcache-lzo.o regcache-flat.o
obj-$(CONFIG_DEBUG_FS) += regmap-debugfs.o
+obj-$(CONFIG_REGMAP_AC97) += regmap-ac97.o
obj-$(CONFIG_REGMAP_I2C) += regmap-i2c.o
obj-$(CONFIG_REGMAP_SPI) += regmap-spi.o
obj-$(CONFIG_REGMAP_SPMI) += regmap-spmi.o
diff --git a/drivers/base/regmap/regcache-flat.c b/drivers/base/regmap/regcache-flat.c
index d9762e4..0246f44 100644
--- a/drivers/base/regmap/regcache-flat.c
+++ b/drivers/base/regmap/regcache-flat.c
@@ -10,9 +10,9 @@
* published by the Free Software Foundation.
*/
-#include <linux/slab.h>
#include <linux/device.h>
#include <linux/seq_file.h>
+#include <linux/slab.h>
#include "internal.h"
diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c
index e210a6d..2d53f6f 100644
--- a/drivers/base/regmap/regcache-lzo.c
+++ b/drivers/base/regmap/regcache-lzo.c
@@ -10,9 +10,9 @@
* published by the Free Software Foundation.
*/
-#include <linux/slab.h>
#include <linux/device.h>
#include <linux/lzo.h>
+#include <linux/slab.h>
#include "internal.h"
diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c
index f3e8fe0..d453a2c 100644
--- a/drivers/base/regmap/regcache-rbtree.c
+++ b/drivers/base/regmap/regcache-rbtree.c
@@ -10,11 +10,11 @@
* published by the Free Software Foundation.
*/
-#include <linux/slab.h>
-#include <linux/device.h>
#include <linux/debugfs.h>
+#include <linux/device.h>
#include <linux/rbtree.h>
#include <linux/seq_file.h>
+#include <linux/slab.h>
#include "internal.h"
diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c
index f1280dc..f373c35 100644
--- a/drivers/base/regmap/regcache.c
+++ b/drivers/base/regmap/regcache.c
@@ -10,12 +10,12 @@
* published by the Free Software Foundation.
*/
-#include <linux/slab.h>
-#include <linux/export.h>
-#include <linux/device.h>
-#include <trace/events/regmap.h>
#include <linux/bsearch.h>
+#include <linux/device.h>
+#include <linux/export.h>
+#include <linux/slab.h>
#include <linux/sort.h>
+#include <trace/events/regmap.h>
#include "internal.h"
@@ -36,6 +36,23 @@ static int regcache_hw_init(struct regmap *map)
if (!map->num_reg_defaults_raw)
return -EINVAL;
+ /* calculate the size of reg_defaults */
+ for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++)
+ if (!regmap_volatile(map, i * map->reg_stride))
+ count++;
+
+ /* all registers are volatile, so just bypass */
+ if (!count) {
+ map->cache_bypass = true;
+ return 0;
+ }
+
+ map->num_reg_defaults = count;
+ map->reg_defaults = kmalloc_array(count, sizeof(struct reg_default),
+ GFP_KERNEL);
+ if (!map->reg_defaults)
+ return -ENOMEM;
+
if (!map->reg_defaults_raw) {
u32 cache_bypass = map->cache_bypass;
dev_warn(map->dev, "No cache defaults, reading back from HW\n");
@@ -43,40 +60,25 @@ static int regcache_hw_init(struct regmap *map)
/* Bypass the cache access till data read from HW*/
map->cache_bypass = 1;
tmp_buf = kmalloc(map->cache_size_raw, GFP_KERNEL);
- if (!tmp_buf)
- return -EINVAL;
+ if (!tmp_buf) {
+ ret = -ENOMEM;
+ goto err_free;
+ }
ret = regmap_raw_read(map, 0, tmp_buf,
map->num_reg_defaults_raw);
map->cache_bypass = cache_bypass;
- if (ret < 0) {
- kfree(tmp_buf);
- return ret;
- }
+ if (ret < 0)
+ goto err_cache_free;
+
map->reg_defaults_raw = tmp_buf;
map->cache_free = 1;
}
- /* calculate the size of reg_defaults */
- for (count = 0, i = 0; i < map->num_reg_defaults_raw; i++) {
- val = regcache_get_val(map, map->reg_defaults_raw, i);
- if (regmap_volatile(map, i * map->reg_stride))
- continue;
- count++;
- }
-
- map->reg_defaults = kmalloc(count * sizeof(struct reg_default),
- GFP_KERNEL);
- if (!map->reg_defaults) {
- ret = -ENOMEM;
- goto err_free;
- }
-
/* fill the reg_defaults */
- map->num_reg_defaults = count;
for (i = 0, j = 0; i < map->num_reg_defaults_raw; i++) {
- val = regcache_get_val(map, map->reg_defaults_raw, i);
if (regmap_volatile(map, i * map->reg_stride))
continue;
+ val = regcache_get_val(map, map->reg_defaults_raw, i);
map->reg_defaults[j].reg = i * map->reg_stride;
map->reg_defaults[j].def = val;
j++;
@@ -84,9 +86,10 @@ static int regcache_hw_init(struct regmap *map)
return 0;
+err_cache_free:
+ kfree(tmp_buf);
err_free:
- if (map->cache_free)
- kfree(map->reg_defaults_raw);
+ kfree(map->reg_defaults);
return ret;
}
@@ -150,6 +153,8 @@ int regcache_init(struct regmap *map, const struct regmap_config *config)
ret = regcache_hw_init(map);
if (ret < 0)
return ret;
+ if (map->cache_bypass)
+ return 0;
}
if (!map->max_register)
diff --git a/drivers/base/regmap/regmap-ac97.c b/drivers/base/regmap/regmap-ac97.c
new file mode 100644
index 0000000..e4c45d2
--- /dev/null
+++ b/drivers/base/regmap/regmap-ac97.c
@@ -0,0 +1,114 @@
+/*
+ * Register map access API - AC'97 support
+ *
+ * Copyright 2013 Linaro Ltd. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#include <sound/ac97_codec.h>
+
+bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AC97_RESET:
+ case AC97_POWERDOWN:
+ case AC97_INT_PAGING:
+ case AC97_EXTENDED_ID:
+ case AC97_EXTENDED_STATUS:
+ case AC97_EXTENDED_MID:
+ case AC97_EXTENDED_MSTATUS:
+ case AC97_GPIO_STATUS:
+ case AC97_MISC_AFE:
+ case AC97_VENDOR_ID1:
+ case AC97_VENDOR_ID2:
+ case AC97_CODEC_CLASS_REV:
+ case AC97_PCI_SVID:
+ case AC97_PCI_SID:
+ case AC97_FUNC_SELECT:
+ case AC97_FUNC_INFO:
+ case AC97_SENSE_INFO:
+ return true;
+ default:
+ return false;
+ }
+}
+EXPORT_SYMBOL_GPL(regmap_ac97_default_volatile);
+
+static int regmap_ac97_reg_read(void *context, unsigned int reg,
+ unsigned int *val)
+{
+ struct snd_ac97 *ac97 = context;
+
+ *val = ac97->bus->ops->read(ac97, reg);
+
+ return 0;
+}
+
+static int regmap_ac97_reg_write(void *context, unsigned int reg,
+ unsigned int val)
+{
+ struct snd_ac97 *ac97 = context;
+
+ ac97->bus->ops->write(ac97, reg, val);
+
+ return 0;
+}
+
+static const struct regmap_bus ac97_regmap_bus = {
+ .reg_write = regmap_ac97_reg_write,
+ .reg_read = regmap_ac97_reg_read,
+};
+
+/**
+ * regmap_init_ac97(): Initialise AC'97 register map
+ *
+ * @ac97: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer to
+ * a struct regmap.
+ */
+struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
+ const struct regmap_config *config)
+{
+ return regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
+}
+EXPORT_SYMBOL_GPL(regmap_init_ac97);
+
+/**
+ * devm_regmap_init_ac97(): Initialise AC'97 register map
+ *
+ * @ac97: Device that will be interacted with
+ * @config: Configuration for register map
+ *
+ * The return value will be an ERR_PTR() on error or a valid pointer
+ * to a struct regmap. The regmap will be automatically freed by the
+ * device management code.
+ */
+struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
+ const struct regmap_config *config)
+{
+ return devm_regmap_init(&ac97->dev, &ac97_regmap_bus, ac97, config);
+}
+EXPORT_SYMBOL_GPL(devm_regmap_init_ac97);
+
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/block/drbd/drbd_debugfs.c b/drivers/block/drbd/drbd_debugfs.c
index 900d4d3..9a95002 100644
--- a/drivers/block/drbd/drbd_debugfs.c
+++ b/drivers/block/drbd/drbd_debugfs.c
@@ -419,7 +419,7 @@ static int in_flight_summary_show(struct seq_file *m, void *pos)
return 0;
}
-/* simple_positive(file->f_dentry) respectively debugfs_positive(),
+/* simple_positive(file->f_path.dentry) respectively debugfs_positive(),
* but neither is "reachable" from here.
* So we have our own inline version of it above. :-( */
static inline int debugfs_positive(struct dentry *dentry)
@@ -437,14 +437,14 @@ static int drbd_single_open(struct file *file, int (*show)(struct seq_file *, vo
/* Are we still linked,
* or has debugfs_remove() already been called? */
- parent = file->f_dentry->d_parent;
+ parent = file->f_path.dentry->d_parent;
/* not sure if this can happen: */
if (!parent || !parent->d_inode)
goto out;
/* serialize with d_delete() */
mutex_lock(&parent->d_inode->i_mutex);
/* Make sure the object is still alive */
- if (debugfs_positive(file->f_dentry)
+ if (debugfs_positive(file->f_path.dentry)
&& kref_get_unless_zero(kref))
ret = 0;
mutex_unlock(&parent->d_inode->i_mutex);
diff --git a/drivers/block/nvme-scsi.c b/drivers/block/nvme-scsi.c
index a4cd6d6..0b4b277 100644
--- a/drivers/block/nvme-scsi.c
+++ b/drivers/block/nvme-scsi.c
@@ -329,7 +329,7 @@ INQUIRY_EVPD_BIT_MASK) ? 1 : 0)
(GET_U32_FROM_CDB(cdb, READ_CAP_16_CDB_ALLOC_LENGTH_OFFSET))
#define IS_READ_CAP_16(cdb) \
-((cdb[0] == SERVICE_ACTION_IN && cdb[1] == SAI_READ_CAPACITY_16) ? 1 : 0)
+((cdb[0] == SERVICE_ACTION_IN_16 && cdb[1] == SAI_READ_CAPACITY_16) ? 1 : 0)
/* Request Sense Helper Macros */
#define GET_REQUEST_SENSE_ALLOC_LENGTH(cdb) \
@@ -2947,7 +2947,7 @@ static int nvme_scsi_translate(struct nvme_ns *ns, struct sg_io_hdr *hdr)
case READ_CAPACITY:
retcode = nvme_trans_read_capacity(ns, hdr, cmd);
break;
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
if (IS_READ_CAP_16(cmd))
retcode = nvme_trans_read_capacity(ns, hdr, cmd);
else
diff --git a/drivers/block/virtio_blk.c b/drivers/block/virtio_blk.c
index c6a27d5..1fb9e09 100644
--- a/drivers/block/virtio_blk.c
+++ b/drivers/block/virtio_blk.c
@@ -80,7 +80,7 @@ static int __virtblk_add_req(struct virtqueue *vq,
{
struct scatterlist hdr, status, cmd, sense, inhdr, *sgs[6];
unsigned int num_out = 0, num_in = 0;
- int type = vbr->out_hdr.type & ~VIRTIO_BLK_T_OUT;
+ __virtio32 type = vbr->out_hdr.type & ~cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT);
sg_init_one(&hdr, &vbr->out_hdr, sizeof(vbr->out_hdr));
sgs[num_out++] = &hdr;
@@ -91,19 +91,19 @@ static int __virtblk_add_req(struct virtqueue *vq,
* block, and before the normal inhdr we put the sense data and the
* inhdr with additional status information.
*/
- if (type == VIRTIO_BLK_T_SCSI_CMD) {
+ if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
sg_init_one(&cmd, vbr->req->cmd, vbr->req->cmd_len);
sgs[num_out++] = &cmd;
}
if (have_data) {
- if (vbr->out_hdr.type & VIRTIO_BLK_T_OUT)
+ if (vbr->out_hdr.type & cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_OUT))
sgs[num_out++] = data_sg;
else
sgs[num_out + num_in++] = data_sg;
}
- if (type == VIRTIO_BLK_T_SCSI_CMD) {
+ if (type == cpu_to_virtio32(vq->vdev, VIRTIO_BLK_T_SCSI_CMD)) {
sg_init_one(&sense, vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
sgs[num_out + num_in++] = &sense;
sg_init_one(&inhdr, &vbr->in_hdr, sizeof(vbr->in_hdr));
@@ -119,12 +119,13 @@ static int __virtblk_add_req(struct virtqueue *vq,
static inline void virtblk_request_done(struct request *req)
{
struct virtblk_req *vbr = blk_mq_rq_to_pdu(req);
+ struct virtio_blk *vblk = req->q->queuedata;
int error = virtblk_result(vbr);
if (req->cmd_type == REQ_TYPE_BLOCK_PC) {
- req->resid_len = vbr->in_hdr.residual;
- req->sense_len = vbr->in_hdr.sense_len;
- req->errors = vbr->in_hdr.errors;
+ req->resid_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.residual);
+ req->sense_len = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.sense_len);
+ req->errors = virtio32_to_cpu(vblk->vdev, vbr->in_hdr.errors);
} else if (req->cmd_type == REQ_TYPE_SPECIAL) {
req->errors = (error != 0);
}
@@ -173,25 +174,25 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req,
vbr->req = req;
if (req->cmd_flags & REQ_FLUSH) {
- vbr->out_hdr.type = VIRTIO_BLK_T_FLUSH;
+ vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_FLUSH);
vbr->out_hdr.sector = 0;
- vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+ vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
} else {
switch (req->cmd_type) {
case REQ_TYPE_FS:
vbr->out_hdr.type = 0;
- vbr->out_hdr.sector = blk_rq_pos(vbr->req);
- vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+ vbr->out_hdr.sector = cpu_to_virtio64(vblk->vdev, blk_rq_pos(vbr->req));
+ vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
break;
case REQ_TYPE_BLOCK_PC:
- vbr->out_hdr.type = VIRTIO_BLK_T_SCSI_CMD;
+ vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_SCSI_CMD);
vbr->out_hdr.sector = 0;
- vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+ vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
break;
case REQ_TYPE_SPECIAL:
- vbr->out_hdr.type = VIRTIO_BLK_T_GET_ID;
+ vbr->out_hdr.type = cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_GET_ID);
vbr->out_hdr.sector = 0;
- vbr->out_hdr.ioprio = req_get_ioprio(vbr->req);
+ vbr->out_hdr.ioprio = cpu_to_virtio32(vblk->vdev, req_get_ioprio(vbr->req));
break;
default:
/* We don't put anything else in the queue. */
@@ -204,9 +205,9 @@ static int virtio_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req,
num = blk_rq_map_sg(hctx->queue, vbr->req, vbr->sg);
if (num) {
if (rq_data_dir(vbr->req) == WRITE)
- vbr->out_hdr.type |= VIRTIO_BLK_T_OUT;
+ vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_OUT);
else
- vbr->out_hdr.type |= VIRTIO_BLK_T_IN;
+ vbr->out_hdr.type |= cpu_to_virtio32(vblk->vdev, VIRTIO_BLK_T_IN);
}
spin_lock_irqsave(&vblk->vqs[qid].lock, flags);
@@ -331,7 +332,8 @@ static ssize_t virtblk_serial_show(struct device *dev,
return err;
}
-DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
+
+static DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
static void virtblk_config_changed_work(struct work_struct *work)
{
@@ -476,7 +478,8 @@ static int virtblk_get_cache_mode(struct virtio_device *vdev)
struct virtio_blk_config, wce,
&writeback);
if (err)
- writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE);
+ writeback = virtio_has_feature(vdev, VIRTIO_BLK_F_WCE) ||
+ virtio_has_feature(vdev, VIRTIO_F_VERSION_1);
return writeback;
}
@@ -821,25 +824,34 @@ static const struct virtio_device_id id_table[] = {
{ 0 },
};
-static unsigned int features[] = {
+static unsigned int features_legacy[] = {
VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE, VIRTIO_BLK_F_SCSI,
VIRTIO_BLK_F_WCE, VIRTIO_BLK_F_TOPOLOGY, VIRTIO_BLK_F_CONFIG_WCE,
VIRTIO_BLK_F_MQ,
+}
+;
+static unsigned int features[] = {
+ VIRTIO_BLK_F_SEG_MAX, VIRTIO_BLK_F_SIZE_MAX, VIRTIO_BLK_F_GEOMETRY,
+ VIRTIO_BLK_F_RO, VIRTIO_BLK_F_BLK_SIZE,
+ VIRTIO_BLK_F_TOPOLOGY,
+ VIRTIO_BLK_F_MQ,
};
static struct virtio_driver virtio_blk = {
- .feature_table = features,
- .feature_table_size = ARRAY_SIZE(features),
- .driver.name = KBUILD_MODNAME,
- .driver.owner = THIS_MODULE,
- .id_table = id_table,
- .probe = virtblk_probe,
- .remove = virtblk_remove,
- .config_changed = virtblk_config_changed,
+ .feature_table = features,
+ .feature_table_size = ARRAY_SIZE(features),
+ .feature_table_legacy = features_legacy,
+ .feature_table_size_legacy = ARRAY_SIZE(features_legacy),
+ .driver.name = KBUILD_MODNAME,
+ .driver.owner = THIS_MODULE,
+ .id_table = id_table,
+ .probe = virtblk_probe,
+ .remove = virtblk_remove,
+ .config_changed = virtblk_config_changed,
#ifdef CONFIG_PM_SLEEP
- .freeze = virtblk_freeze,
- .restore = virtblk_restore,
+ .freeze = virtblk_freeze,
+ .restore = virtblk_restore,
#endif
};
@@ -871,8 +883,8 @@ out_destroy_workqueue:
static void __exit fini(void)
{
- unregister_blkdev(major, "virtblk");
unregister_virtio_driver(&virtio_blk);
+ unregister_blkdev(major, "virtblk");
destroy_workqueue(virtblk_wq);
}
module_init(init);
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 603eb1b..b99729e 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -6,7 +6,7 @@ menu "Bus devices"
config BRCMSTB_GISB_ARB
bool "Broadcom STB GISB bus arbiter"
- depends on ARM
+ depends on ARM || MIPS
help
Driver for the Broadcom Set Top Box System-on-a-chip internal bus
arbiter. This driver provides timeout and target abort error handling
diff --git a/drivers/bus/arm-cci.c b/drivers/bus/arm-cci.c
index 7af78df..860da40 100644
--- a/drivers/bus/arm-cci.c
+++ b/drivers/bus/arm-cci.c
@@ -16,17 +16,17 @@
#include <linux/arm-cci.h>
#include <linux/io.h>
+#include <linux/interrupt.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_irq.h>
#include <linux/of_platform.h>
+#include <linux/perf_event.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <asm/cacheflush.h>
-#include <asm/irq_regs.h>
-#include <asm/pmu.h>
#include <asm/smp_plat.h>
#define DRIVER_NAME "CCI-400"
@@ -98,6 +98,8 @@ static unsigned long cci_ctrl_phys;
#define CCI_PMU_CNTR_BASE(idx) ((idx) * SZ_4K)
+#define CCI_PMU_CNTR_MASK ((1ULL << 32) -1)
+
/*
* Instead of an event id to monitor CCI cycles, a dedicated counter is
* provided. Use 0xff to represent CCI cycles and hope that no future revisions
@@ -170,18 +172,29 @@ static char *const pmu_names[] = {
[CCI_REV_R1] = "CCI_400_r1",
};
-struct cci_pmu_drv_data {
+struct cci_pmu_hw_events {
+ struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
+ unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
+ raw_spinlock_t pmu_lock;
+};
+
+struct cci_pmu {
void __iomem *base;
- struct arm_pmu *cci_pmu;
+ struct pmu pmu;
int nr_irqs;
int irqs[CCI_PMU_MAX_HW_EVENTS];
unsigned long active_irqs;
- struct perf_event *events[CCI_PMU_MAX_HW_EVENTS];
- unsigned long used_mask[BITS_TO_LONGS(CCI_PMU_MAX_HW_EVENTS)];
struct pmu_port_event_ranges *port_ranges;
- struct pmu_hw_events hw_events;
+ struct cci_pmu_hw_events hw_events;
+ struct platform_device *plat_device;
+ int num_events;
+ atomic_t active_events;
+ struct mutex reserve_mutex;
+ cpumask_t cpus;
};
-static struct cci_pmu_drv_data *pmu;
+static struct cci_pmu *pmu;
+
+#define to_cci_pmu(c) (container_of(c, struct cci_pmu, pmu))
static bool is_duplicate_irq(int irq, int *irqs, int nr_irqs)
{
@@ -252,7 +265,7 @@ static int pmu_validate_hw_event(u8 hw_event)
return -ENOENT;
}
-static int pmu_is_valid_counter(struct arm_pmu *cci_pmu, int idx)
+static int pmu_is_valid_counter(struct cci_pmu *cci_pmu, int idx)
{
return CCI_PMU_CYCLE_CNTR_IDX <= idx &&
idx <= CCI_PMU_CNTR_LAST(cci_pmu);
@@ -293,14 +306,9 @@ static u32 pmu_get_max_counters(void)
return n_cnts + 1;
}
-static struct pmu_hw_events *pmu_get_hw_events(void)
-{
- return &pmu->hw_events;
-}
-
-static int pmu_get_event_idx(struct pmu_hw_events *hw, struct perf_event *event)
+static int pmu_get_event_idx(struct cci_pmu_hw_events *hw, struct perf_event *event)
{
- struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
struct hw_perf_event *hw_event = &event->hw;
unsigned long cci_event = hw_event->config_base & CCI_PMU_EVENT_MASK;
int idx;
@@ -336,7 +344,7 @@ static int pmu_map_event(struct perf_event *event)
return mapping;
}
-static int pmu_request_irq(struct arm_pmu *cci_pmu, irq_handler_t handler)
+static int pmu_request_irq(struct cci_pmu *cci_pmu, irq_handler_t handler)
{
int i;
struct platform_device *pmu_device = cci_pmu->plat_device;
@@ -371,17 +379,91 @@ static int pmu_request_irq(struct arm_pmu *cci_pmu, irq_handler_t handler)
return 0;
}
+static void pmu_free_irq(struct cci_pmu *cci_pmu)
+{
+ int i;
+
+ for (i = 0; i < pmu->nr_irqs; i++) {
+ if (!test_and_clear_bit(i, &pmu->active_irqs))
+ continue;
+
+ free_irq(pmu->irqs[i], cci_pmu);
+ }
+}
+
+static u32 pmu_read_counter(struct perf_event *event)
+{
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ struct hw_perf_event *hw_counter = &event->hw;
+ int idx = hw_counter->idx;
+ u32 value;
+
+ if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) {
+ dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
+ return 0;
+ }
+ value = pmu_read_register(idx, CCI_PMU_CNTR);
+
+ return value;
+}
+
+static void pmu_write_counter(struct perf_event *event, u32 value)
+{
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ struct hw_perf_event *hw_counter = &event->hw;
+ int idx = hw_counter->idx;
+
+ if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
+ dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
+ else
+ pmu_write_register(value, idx, CCI_PMU_CNTR);
+}
+
+static u64 pmu_event_update(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ u64 delta, prev_raw_count, new_raw_count;
+
+ do {
+ prev_raw_count = local64_read(&hwc->prev_count);
+ new_raw_count = pmu_read_counter(event);
+ } while (local64_cmpxchg(&hwc->prev_count, prev_raw_count,
+ new_raw_count) != prev_raw_count);
+
+ delta = (new_raw_count - prev_raw_count) & CCI_PMU_CNTR_MASK;
+
+ local64_add(delta, &event->count);
+
+ return new_raw_count;
+}
+
+static void pmu_read(struct perf_event *event)
+{
+ pmu_event_update(event);
+}
+
+void pmu_event_set_period(struct perf_event *event)
+{
+ struct hw_perf_event *hwc = &event->hw;
+ /*
+ * The CCI PMU counters have a period of 2^32. To account for the
+ * possiblity of extreme interrupt latency we program for a period of
+ * half that. Hopefully we can handle the interrupt before another 2^31
+ * events occur and the counter overtakes its previous value.
+ */
+ u64 val = 1ULL << 31;
+ local64_set(&hwc->prev_count, val);
+ pmu_write_counter(event, val);
+}
+
static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
{
unsigned long flags;
- struct arm_pmu *cci_pmu = (struct arm_pmu *)dev;
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
- struct perf_sample_data data;
- struct pt_regs *regs;
+ struct cci_pmu *cci_pmu = dev;
+ struct cci_pmu_hw_events *events = &pmu->hw_events;
int idx, handled = IRQ_NONE;
raw_spin_lock_irqsave(&events->pmu_lock, flags);
- regs = get_irq_regs();
/*
* Iterate over counters and update the corresponding perf events.
* This should work regardless of whether we have per-counter overflow
@@ -403,154 +485,407 @@ static irqreturn_t pmu_handle_irq(int irq_num, void *dev)
pmu_write_register(CCI_PMU_OVRFLW_FLAG, idx, CCI_PMU_OVRFLW);
+ pmu_event_update(event);
+ pmu_event_set_period(event);
handled = IRQ_HANDLED;
-
- armpmu_event_update(event);
- perf_sample_data_init(&data, 0, hw_counter->last_period);
- if (!armpmu_event_set_period(event))
- continue;
-
- if (perf_event_overflow(event, &data, regs))
- cci_pmu->disable(event);
}
raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
return IRQ_RETVAL(handled);
}
-static void pmu_free_irq(struct arm_pmu *cci_pmu)
+static int cci_pmu_get_hw(struct cci_pmu *cci_pmu)
{
- int i;
+ int ret = pmu_request_irq(cci_pmu, pmu_handle_irq);
+ if (ret) {
+ pmu_free_irq(cci_pmu);
+ return ret;
+ }
+ return 0;
+}
- for (i = 0; i < pmu->nr_irqs; i++) {
- if (!test_and_clear_bit(i, &pmu->active_irqs))
- continue;
+static void cci_pmu_put_hw(struct cci_pmu *cci_pmu)
+{
+ pmu_free_irq(cci_pmu);
+}
- free_irq(pmu->irqs[i], cci_pmu);
+static void hw_perf_event_destroy(struct perf_event *event)
+{
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ atomic_t *active_events = &cci_pmu->active_events;
+ struct mutex *reserve_mutex = &cci_pmu->reserve_mutex;
+
+ if (atomic_dec_and_mutex_lock(active_events, reserve_mutex)) {
+ cci_pmu_put_hw(cci_pmu);
+ mutex_unlock(reserve_mutex);
}
}
-static void pmu_enable_event(struct perf_event *event)
+static void cci_pmu_enable(struct pmu *pmu)
{
+ struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
+ struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
+ int enabled = bitmap_weight(hw_events->used_mask, cci_pmu->num_events);
unsigned long flags;
- struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
- struct hw_perf_event *hw_counter = &event->hw;
- int idx = hw_counter->idx;
+ u32 val;
+
+ if (!enabled)
+ return;
+
+ raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
+
+ /* Enable all the PMU counters. */
+ val = readl_relaxed(cci_ctrl_base + CCI_PMCR) | CCI_PMCR_CEN;
+ writel(val, cci_ctrl_base + CCI_PMCR);
+ raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
+
+}
+
+static void cci_pmu_disable(struct pmu *pmu)
+{
+ struct cci_pmu *cci_pmu = to_cci_pmu(pmu);
+ struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
+ unsigned long flags;
+ u32 val;
+
+ raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
+
+ /* Disable all the PMU counters. */
+ val = readl_relaxed(cci_ctrl_base + CCI_PMCR) & ~CCI_PMCR_CEN;
+ writel(val, cci_ctrl_base + CCI_PMCR);
+ raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
+}
+
+static void cci_pmu_start(struct perf_event *event, int pmu_flags)
+{
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+ unsigned long flags;
+
+ /*
+ * To handle interrupt latency, we always reprogram the period
+ * regardlesss of PERF_EF_RELOAD.
+ */
+ if (pmu_flags & PERF_EF_RELOAD)
+ WARN_ON_ONCE(!(hwc->state & PERF_HES_UPTODATE));
+
+ hwc->state = 0;
if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) {
dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
return;
}
- raw_spin_lock_irqsave(&events->pmu_lock, flags);
+ raw_spin_lock_irqsave(&hw_events->pmu_lock, flags);
/* Configure the event to count, unless you are counting cycles */
if (idx != CCI_PMU_CYCLE_CNTR_IDX)
- pmu_set_event(idx, hw_counter->config_base);
+ pmu_set_event(idx, hwc->config_base);
+ pmu_event_set_period(event);
pmu_enable_counter(idx);
- raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+ raw_spin_unlock_irqrestore(&hw_events->pmu_lock, flags);
}
-static void pmu_disable_event(struct perf_event *event)
+static void cci_pmu_stop(struct perf_event *event, int pmu_flags)
{
- struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
- struct hw_perf_event *hw_counter = &event->hw;
- int idx = hw_counter->idx;
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
+
+ if (hwc->state & PERF_HES_STOPPED)
+ return;
if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) {
dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
return;
}
+ /*
+ * We always reprogram the counter, so ignore PERF_EF_UPDATE. See
+ * cci_pmu_start()
+ */
pmu_disable_counter(idx);
+ pmu_event_update(event);
+ hwc->state |= PERF_HES_STOPPED | PERF_HES_UPTODATE;
}
-static void pmu_start(struct arm_pmu *cci_pmu)
+static int cci_pmu_add(struct perf_event *event, int flags)
{
- u32 val;
- unsigned long flags;
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx;
+ int err = 0;
- raw_spin_lock_irqsave(&events->pmu_lock, flags);
+ perf_pmu_disable(event->pmu);
- /* Enable all the PMU counters. */
- val = readl_relaxed(cci_ctrl_base + CCI_PMCR) | CCI_PMCR_CEN;
- writel(val, cci_ctrl_base + CCI_PMCR);
+ /* If we don't have a space for the counter then finish early. */
+ idx = pmu_get_event_idx(hw_events, event);
+ if (idx < 0) {
+ err = idx;
+ goto out;
+ }
- raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+ event->hw.idx = idx;
+ hw_events->events[idx] = event;
+
+ hwc->state = PERF_HES_STOPPED | PERF_HES_UPTODATE;
+ if (flags & PERF_EF_START)
+ cci_pmu_start(event, PERF_EF_RELOAD);
+
+ /* Propagate our changes to the userspace mapping. */
+ perf_event_update_userpage(event);
+
+out:
+ perf_pmu_enable(event->pmu);
+ return err;
}
-static void pmu_stop(struct arm_pmu *cci_pmu)
+static void cci_pmu_del(struct perf_event *event, int flags)
{
- u32 val;
- unsigned long flags;
- struct pmu_hw_events *events = cci_pmu->get_hw_events();
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ struct cci_pmu_hw_events *hw_events = &cci_pmu->hw_events;
+ struct hw_perf_event *hwc = &event->hw;
+ int idx = hwc->idx;
- raw_spin_lock_irqsave(&events->pmu_lock, flags);
+ cci_pmu_stop(event, PERF_EF_UPDATE);
+ hw_events->events[idx] = NULL;
+ clear_bit(idx, hw_events->used_mask);
- /* Disable all the PMU counters. */
- val = readl_relaxed(cci_ctrl_base + CCI_PMCR) & ~CCI_PMCR_CEN;
- writel(val, cci_ctrl_base + CCI_PMCR);
+ perf_event_update_userpage(event);
+}
- raw_spin_unlock_irqrestore(&events->pmu_lock, flags);
+static int
+validate_event(struct cci_pmu_hw_events *hw_events,
+ struct perf_event *event)
+{
+ if (is_software_event(event))
+ return 1;
+
+ if (event->state < PERF_EVENT_STATE_OFF)
+ return 1;
+
+ if (event->state == PERF_EVENT_STATE_OFF && !event->attr.enable_on_exec)
+ return 1;
+
+ return pmu_get_event_idx(hw_events, event) >= 0;
}
-static u32 pmu_read_counter(struct perf_event *event)
+static int
+validate_group(struct perf_event *event)
{
- struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
- struct hw_perf_event *hw_counter = &event->hw;
- int idx = hw_counter->idx;
- u32 value;
+ struct perf_event *sibling, *leader = event->group_leader;
+ struct cci_pmu_hw_events fake_pmu = {
+ /*
+ * Initialise the fake PMU. We only need to populate the
+ * used_mask for the purposes of validation.
+ */
+ .used_mask = CPU_BITS_NONE,
+ };
- if (unlikely(!pmu_is_valid_counter(cci_pmu, idx))) {
- dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
- return 0;
+ if (!validate_event(&fake_pmu, leader))
+ return -EINVAL;
+
+ list_for_each_entry(sibling, &leader->sibling_list, group_entry) {
+ if (!validate_event(&fake_pmu, sibling))
+ return -EINVAL;
}
- value = pmu_read_register(idx, CCI_PMU_CNTR);
- return value;
+ if (!validate_event(&fake_pmu, event))
+ return -EINVAL;
+
+ return 0;
}
-static void pmu_write_counter(struct perf_event *event, u32 value)
+static int
+__hw_perf_event_init(struct perf_event *event)
{
- struct arm_pmu *cci_pmu = to_arm_pmu(event->pmu);
- struct hw_perf_event *hw_counter = &event->hw;
- int idx = hw_counter->idx;
+ struct hw_perf_event *hwc = &event->hw;
+ int mapping;
- if (unlikely(!pmu_is_valid_counter(cci_pmu, idx)))
- dev_err(&cci_pmu->plat_device->dev, "Invalid CCI PMU counter %d\n", idx);
- else
- pmu_write_register(value, idx, CCI_PMU_CNTR);
+ mapping = pmu_map_event(event);
+
+ if (mapping < 0) {
+ pr_debug("event %x:%llx not supported\n", event->attr.type,
+ event->attr.config);
+ return mapping;
+ }
+
+ /*
+ * We don't assign an index until we actually place the event onto
+ * hardware. Use -1 to signify that we haven't decided where to put it
+ * yet.
+ */
+ hwc->idx = -1;
+ hwc->config_base = 0;
+ hwc->config = 0;
+ hwc->event_base = 0;
+
+ /*
+ * Store the event encoding into the config_base field.
+ */
+ hwc->config_base |= (unsigned long)mapping;
+
+ /*
+ * Limit the sample_period to half of the counter width. That way, the
+ * new counter value is far less likely to overtake the previous one
+ * unless you have some serious IRQ latency issues.
+ */
+ hwc->sample_period = CCI_PMU_CNTR_MASK >> 1;
+ hwc->last_period = hwc->sample_period;
+ local64_set(&hwc->period_left, hwc->sample_period);
+
+ if (event->group_leader != event) {
+ if (validate_group(event) != 0)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int cci_pmu_event_init(struct perf_event *event)
+{
+ struct cci_pmu *cci_pmu = to_cci_pmu(event->pmu);
+ atomic_t *active_events = &cci_pmu->active_events;
+ int err = 0;
+ int cpu;
+
+ if (event->attr.type != event->pmu->type)
+ return -ENOENT;
+
+ /* Shared by all CPUs, no meaningful state to sample */
+ if (is_sampling_event(event) || event->attach_state & PERF_ATTACH_TASK)
+ return -EOPNOTSUPP;
+
+ /* We have no filtering of any kind */
+ if (event->attr.exclude_user ||
+ event->attr.exclude_kernel ||
+ event->attr.exclude_hv ||
+ event->attr.exclude_idle ||
+ event->attr.exclude_host ||
+ event->attr.exclude_guest)
+ return -EINVAL;
+
+ /*
+ * Following the example set by other "uncore" PMUs, we accept any CPU
+ * and rewrite its affinity dynamically rather than having perf core
+ * handle cpu == -1 and pid == -1 for this case.
+ *
+ * The perf core will pin online CPUs for the duration of this call and
+ * the event being installed into its context, so the PMU's CPU can't
+ * change under our feet.
+ */
+ cpu = cpumask_first(&cci_pmu->cpus);
+ if (event->cpu < 0 || cpu < 0)
+ return -EINVAL;
+ event->cpu = cpu;
+
+ event->destroy = hw_perf_event_destroy;
+ if (!atomic_inc_not_zero(active_events)) {
+ mutex_lock(&cci_pmu->reserve_mutex);
+ if (atomic_read(active_events) == 0)
+ err = cci_pmu_get_hw(cci_pmu);
+ if (!err)
+ atomic_inc(active_events);
+ mutex_unlock(&cci_pmu->reserve_mutex);
+ }
+ if (err)
+ return err;
+
+ err = __hw_perf_event_init(event);
+ if (err)
+ hw_perf_event_destroy(event);
+
+ return err;
}
-static int cci_pmu_init(struct arm_pmu *cci_pmu, struct platform_device *pdev)
+static ssize_t pmu_attr_cpumask_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
- *cci_pmu = (struct arm_pmu){
- .name = pmu_names[probe_cci_revision()],
- .max_period = (1LLU << 32) - 1,
- .get_hw_events = pmu_get_hw_events,
- .get_event_idx = pmu_get_event_idx,
- .map_event = pmu_map_event,
- .request_irq = pmu_request_irq,
- .handle_irq = pmu_handle_irq,
- .free_irq = pmu_free_irq,
- .enable = pmu_enable_event,
- .disable = pmu_disable_event,
- .start = pmu_start,
- .stop = pmu_stop,
- .read_counter = pmu_read_counter,
- .write_counter = pmu_write_counter,
+ int n = cpulist_scnprintf(buf, PAGE_SIZE - 2, &pmu->cpus);
+
+ buf[n++] = '\n';
+ buf[n] = '\0';
+ return n;
+}
+
+static DEVICE_ATTR(cpumask, S_IRUGO, pmu_attr_cpumask_show, NULL);
+
+static struct attribute *pmu_attrs[] = {
+ &dev_attr_cpumask.attr,
+ NULL,
+};
+
+static struct attribute_group pmu_attr_group = {
+ .attrs = pmu_attrs,
+};
+
+static const struct attribute_group *pmu_attr_groups[] = {
+ &pmu_attr_group,
+ NULL
+};
+
+static int cci_pmu_init(struct cci_pmu *cci_pmu, struct platform_device *pdev)
+{
+ char *name = pmu_names[probe_cci_revision()];
+ cci_pmu->pmu = (struct pmu) {
+ .name = pmu_names[probe_cci_revision()],
+ .task_ctx_nr = perf_invalid_context,
+ .pmu_enable = cci_pmu_enable,
+ .pmu_disable = cci_pmu_disable,
+ .event_init = cci_pmu_event_init,
+ .add = cci_pmu_add,
+ .del = cci_pmu_del,
+ .start = cci_pmu_start,
+ .stop = cci_pmu_stop,
+ .read = pmu_read,
+ .attr_groups = pmu_attr_groups,
};
cci_pmu->plat_device = pdev;
cci_pmu->num_events = pmu_get_max_counters();
- return armpmu_register(cci_pmu, -1);
+ return perf_pmu_register(&cci_pmu->pmu, name, -1);
}
+static int cci_pmu_cpu_notifier(struct notifier_block *self,
+ unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (long)hcpu;
+ unsigned int target;
+
+ switch (action & ~CPU_TASKS_FROZEN) {
+ case CPU_DOWN_PREPARE:
+ if (!cpumask_test_and_clear_cpu(cpu, &pmu->cpus))
+ break;
+ target = cpumask_any_but(cpu_online_mask, cpu);
+ if (target < 0) // UP, last CPU
+ break;
+ /*
+ * TODO: migrate context once core races on event->ctx have
+ * been fixed.
+ */
+ cpumask_set_cpu(target, &pmu->cpus);
+ default:
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block cci_pmu_cpu_nb = {
+ .notifier_call = cci_pmu_cpu_notifier,
+ /*
+ * to migrate uncore events, our notifier should be executed
+ * before perf core's notifier.
+ */
+ .priority = CPU_PRI_PERF + 1,
+};
+
static const struct of_device_id arm_cci_pmu_matches[] = {
{
.compatible = "arm,cci-400-pmu",
@@ -604,15 +939,16 @@ static int cci_pmu_probe(struct platform_device *pdev)
return -EINVAL;
}
- pmu->cci_pmu = devm_kzalloc(&pdev->dev, sizeof(*(pmu->cci_pmu)), GFP_KERNEL);
- if (!pmu->cci_pmu)
- return -ENOMEM;
-
- pmu->hw_events.events = pmu->events;
- pmu->hw_events.used_mask = pmu->used_mask;
raw_spin_lock_init(&pmu->hw_events.pmu_lock);
+ mutex_init(&pmu->reserve_mutex);
+ atomic_set(&pmu->active_events, 0);
+ cpumask_set_cpu(smp_processor_id(), &pmu->cpus);
+
+ ret = register_cpu_notifier(&cci_pmu_cpu_nb);
+ if (ret)
+ return ret;
- ret = cci_pmu_init(pmu->cci_pmu, pdev);
+ ret = cci_pmu_init(pmu, pdev);
if (ret)
return ret;
diff --git a/drivers/bus/brcmstb_gisb.c b/drivers/bus/brcmstb_gisb.c
index f2cd6a2d..46de8dc 100644
--- a/drivers/bus/brcmstb_gisb.c
+++ b/drivers/bus/brcmstb_gisb.c
@@ -23,35 +23,103 @@
#include <linux/list.h>
#include <linux/of.h>
#include <linux/bitops.h>
+#include <linux/pm.h>
+#ifdef CONFIG_ARM
#include <asm/bug.h>
#include <asm/signal.h>
+#endif
-#define ARB_TIMER 0x008
-#define ARB_ERR_CAP_CLR 0x7e4
#define ARB_ERR_CAP_CLEAR (1 << 0)
-#define ARB_ERR_CAP_HI_ADDR 0x7e8
-#define ARB_ERR_CAP_ADDR 0x7ec
-#define ARB_ERR_CAP_DATA 0x7f0
-#define ARB_ERR_CAP_STATUS 0x7f4
#define ARB_ERR_CAP_STATUS_TIMEOUT (1 << 12)
#define ARB_ERR_CAP_STATUS_TEA (1 << 11)
#define ARB_ERR_CAP_STATUS_BS_SHIFT (1 << 2)
#define ARB_ERR_CAP_STATUS_BS_MASK 0x3c
#define ARB_ERR_CAP_STATUS_WRITE (1 << 1)
#define ARB_ERR_CAP_STATUS_VALID (1 << 0)
-#define ARB_ERR_CAP_MASTER 0x7f8
+
+enum {
+ ARB_TIMER,
+ ARB_ERR_CAP_CLR,
+ ARB_ERR_CAP_HI_ADDR,
+ ARB_ERR_CAP_ADDR,
+ ARB_ERR_CAP_DATA,
+ ARB_ERR_CAP_STATUS,
+ ARB_ERR_CAP_MASTER,
+};
+
+static const int gisb_offsets_bcm7038[] = {
+ [ARB_TIMER] = 0x00c,
+ [ARB_ERR_CAP_CLR] = 0x0c4,
+ [ARB_ERR_CAP_HI_ADDR] = -1,
+ [ARB_ERR_CAP_ADDR] = 0x0c8,
+ [ARB_ERR_CAP_DATA] = 0x0cc,
+ [ARB_ERR_CAP_STATUS] = 0x0d0,
+ [ARB_ERR_CAP_MASTER] = -1,
+};
+
+static const int gisb_offsets_bcm7400[] = {
+ [ARB_TIMER] = 0x00c,
+ [ARB_ERR_CAP_CLR] = 0x0c8,
+ [ARB_ERR_CAP_HI_ADDR] = -1,
+ [ARB_ERR_CAP_ADDR] = 0x0cc,
+ [ARB_ERR_CAP_DATA] = 0x0d0,
+ [ARB_ERR_CAP_STATUS] = 0x0d4,
+ [ARB_ERR_CAP_MASTER] = 0x0d8,
+};
+
+static const int gisb_offsets_bcm7435[] = {
+ [ARB_TIMER] = 0x00c,
+ [ARB_ERR_CAP_CLR] = 0x168,
+ [ARB_ERR_CAP_HI_ADDR] = -1,
+ [ARB_ERR_CAP_ADDR] = 0x16c,
+ [ARB_ERR_CAP_DATA] = 0x170,
+ [ARB_ERR_CAP_STATUS] = 0x174,
+ [ARB_ERR_CAP_MASTER] = 0x178,
+};
+
+static const int gisb_offsets_bcm7445[] = {
+ [ARB_TIMER] = 0x008,
+ [ARB_ERR_CAP_CLR] = 0x7e4,
+ [ARB_ERR_CAP_HI_ADDR] = 0x7e8,
+ [ARB_ERR_CAP_ADDR] = 0x7ec,
+ [ARB_ERR_CAP_DATA] = 0x7f0,
+ [ARB_ERR_CAP_STATUS] = 0x7f4,
+ [ARB_ERR_CAP_MASTER] = 0x7f8,
+};
struct brcmstb_gisb_arb_device {
void __iomem *base;
+ const int *gisb_offsets;
struct mutex lock;
struct list_head next;
u32 valid_mask;
const char *master_names[sizeof(u32) * BITS_PER_BYTE];
+ u32 saved_timeout;
};
static LIST_HEAD(brcmstb_gisb_arb_device_list);
+static u32 gisb_read(struct brcmstb_gisb_arb_device *gdev, int reg)
+{
+ int offset = gdev->gisb_offsets[reg];
+
+ /* return 1 if the hardware doesn't have ARB_ERR_CAP_MASTER */
+ if (offset == -1)
+ return 1;
+
+ return ioread32(gdev->base + offset);
+}
+
+static void gisb_write(struct brcmstb_gisb_arb_device *gdev, u32 val, int reg)
+{
+ int offset = gdev->gisb_offsets[reg];
+
+ if (offset == -1)
+ return;
+ iowrite32(val, gdev->base + reg);
+}
+
static ssize_t gisb_arb_get_timeout(struct device *dev,
struct device_attribute *attr,
char *buf)
@@ -61,7 +129,7 @@ static ssize_t gisb_arb_get_timeout(struct device *dev,
u32 timeout;
mutex_lock(&gdev->lock);
- timeout = ioread32(gdev->base + ARB_TIMER);
+ timeout = gisb_read(gdev, ARB_TIMER);
mutex_unlock(&gdev->lock);
return sprintf(buf, "%d", timeout);
@@ -83,7 +151,7 @@ static ssize_t gisb_arb_set_timeout(struct device *dev,
return -EINVAL;
mutex_lock(&gdev->lock);
- iowrite32(val, gdev->base + ARB_TIMER);
+ gisb_write(gdev, val, ARB_TIMER);
mutex_unlock(&gdev->lock);
return count;
@@ -110,18 +178,18 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
const char *m_name;
char m_fmt[11];
- cap_status = ioread32(gdev->base + ARB_ERR_CAP_STATUS);
+ cap_status = gisb_read(gdev, ARB_ERR_CAP_STATUS);
/* Invalid captured address, bail out */
if (!(cap_status & ARB_ERR_CAP_STATUS_VALID))
return 1;
/* Read the address and master */
- arb_addr = ioread32(gdev->base + ARB_ERR_CAP_ADDR) & 0xffffffff;
+ arb_addr = gisb_read(gdev, ARB_ERR_CAP_ADDR) & 0xffffffff;
#if (IS_ENABLED(CONFIG_PHYS_ADDR_T_64BIT))
- arb_addr |= (u64)ioread32(gdev->base + ARB_ERR_CAP_HI_ADDR) << 32;
+ arb_addr |= (u64)gisb_read(gdev, ARB_ERR_CAP_HI_ADDR) << 32;
#endif
- master = ioread32(gdev->base + ARB_ERR_CAP_MASTER);
+ master = gisb_read(gdev, ARB_ERR_CAP_MASTER);
m_name = brcmstb_gisb_master_to_str(gdev, master);
if (!m_name) {
@@ -136,11 +204,12 @@ static int brcmstb_gisb_arb_decode_addr(struct brcmstb_gisb_arb_device *gdev,
m_name);
/* clear the GISB error */
- iowrite32(ARB_ERR_CAP_CLEAR, gdev->base + ARB_ERR_CAP_CLR);
+ gisb_write(gdev, ARB_ERR_CAP_CLEAR, ARB_ERR_CAP_CLR);
return 0;
}
+#ifdef CONFIG_ARM
static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
struct pt_regs *regs)
{
@@ -159,12 +228,7 @@ static int brcmstb_bus_error_handler(unsigned long addr, unsigned int fsr,
return ret;
}
-
-void __init brcmstb_hook_fault_code(void)
-{
- hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
- "imprecise external abort");
-}
+#endif
static irqreturn_t brcmstb_gisb_timeout_handler(int irq, void *dev_id)
{
@@ -192,10 +256,20 @@ static struct attribute_group gisb_arb_sysfs_attr_group = {
.attrs = gisb_arb_sysfs_attrs,
};
-static int brcmstb_gisb_arb_probe(struct platform_device *pdev)
+static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
+ { .compatible = "brcm,gisb-arb", .data = gisb_offsets_bcm7445 },
+ { .compatible = "brcm,bcm7445-gisb-arb", .data = gisb_offsets_bcm7445 },
+ { .compatible = "brcm,bcm7435-gisb-arb", .data = gisb_offsets_bcm7435 },
+ { .compatible = "brcm,bcm7400-gisb-arb", .data = gisb_offsets_bcm7400 },
+ { .compatible = "brcm,bcm7038-gisb-arb", .data = gisb_offsets_bcm7038 },
+ { },
+};
+
+static int __init brcmstb_gisb_arb_probe(struct platform_device *pdev)
{
struct device_node *dn = pdev->dev.of_node;
struct brcmstb_gisb_arb_device *gdev;
+ const struct of_device_id *of_id;
struct resource *r;
int err, timeout_irq, tea_irq;
unsigned int num_masters, j = 0;
@@ -216,6 +290,13 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev)
if (IS_ERR(gdev->base))
return PTR_ERR(gdev->base);
+ of_id = of_match_node(brcmstb_gisb_arb_of_match, dn);
+ if (!of_id) {
+ pr_err("failed to look up compatible string\n");
+ return -EINVAL;
+ }
+ gdev->gisb_offsets = of_id->data;
+
err = devm_request_irq(&pdev->dev, timeout_irq,
brcmstb_gisb_timeout_handler, 0, pdev->name,
gdev);
@@ -261,29 +342,63 @@ static int brcmstb_gisb_arb_probe(struct platform_device *pdev)
list_add_tail(&gdev->next, &brcmstb_gisb_arb_device_list);
+#ifdef CONFIG_ARM
+ hook_fault_code(22, brcmstb_bus_error_handler, SIGBUS, 0,
+ "imprecise external abort");
+#endif
+
dev_info(&pdev->dev, "registered mem: %p, irqs: %d, %d\n",
gdev->base, timeout_irq, tea_irq);
return 0;
}
-static const struct of_device_id brcmstb_gisb_arb_of_match[] = {
- { .compatible = "brcm,gisb-arb" },
- { },
+#ifdef CONFIG_PM_SLEEP
+static int brcmstb_gisb_arb_suspend(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
+
+ gdev->saved_timeout = gisb_read(gdev, ARB_TIMER);
+
+ return 0;
+}
+
+/* Make sure we provide the same timeout value that was configured before, and
+ * do this before the GISB timeout interrupt handler has any chance to run.
+ */
+static int brcmstb_gisb_arb_resume_noirq(struct device *dev)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct brcmstb_gisb_arb_device *gdev = platform_get_drvdata(pdev);
+
+ gisb_write(gdev, gdev->saved_timeout, ARB_TIMER);
+
+ return 0;
+}
+#else
+#define brcmstb_gisb_arb_suspend NULL
+#define brcmstb_gisb_arb_resume_noirq NULL
+#endif
+
+static const struct dev_pm_ops brcmstb_gisb_arb_pm_ops = {
+ .suspend = brcmstb_gisb_arb_suspend,
+ .resume_noirq = brcmstb_gisb_arb_resume_noirq,
};
static struct platform_driver brcmstb_gisb_arb_driver = {
- .probe = brcmstb_gisb_arb_probe,
.driver = {
.name = "brcm-gisb-arb",
.owner = THIS_MODULE,
.of_match_table = brcmstb_gisb_arb_of_match,
+ .pm = &brcmstb_gisb_arb_pm_ops,
},
};
static int __init brcm_gisb_driver_init(void)
{
- return platform_driver_register(&brcmstb_gisb_arb_driver);
+ return platform_driver_probe(&brcmstb_gisb_arb_driver,
+ brcmstb_gisb_arb_probe);
}
module_init(brcm_gisb_driver_init);
diff --git a/drivers/bus/mvebu-mbus.c b/drivers/bus/mvebu-mbus.c
index 26c3779d..eb7682d 100644
--- a/drivers/bus/mvebu-mbus.c
+++ b/drivers/bus/mvebu-mbus.c
@@ -57,6 +57,7 @@
#include <linux/of_address.h>
#include <linux/debugfs.h>
#include <linux/log2.h>
+#include <linux/syscore_ops.h>
/*
* DDR target is the same on all platforms.
@@ -94,20 +95,42 @@
#define DOVE_DDR_BASE_CS_OFF(n) ((n) << 4)
+/* Relative to mbusbridge_base */
+#define MBUS_BRIDGE_CTRL_OFF 0x0
+#define MBUS_BRIDGE_BASE_OFF 0x4
+
+/* Maximum number of windows, for all known platforms */
+#define MBUS_WINS_MAX 20
+
struct mvebu_mbus_state;
struct mvebu_mbus_soc_data {
unsigned int num_wins;
unsigned int num_remappable_wins;
+ bool has_mbus_bridge;
unsigned int (*win_cfg_offset)(const int win);
void (*setup_cpu_target)(struct mvebu_mbus_state *s);
+ int (*save_cpu_target)(struct mvebu_mbus_state *s,
+ u32 *store_addr);
int (*show_cpu_target)(struct mvebu_mbus_state *s,
struct seq_file *seq, void *v);
};
+/*
+ * Used to store the state of one MBus window accross suspend/resume.
+ */
+struct mvebu_mbus_win_data {
+ u32 ctrl;
+ u32 base;
+ u32 remap_lo;
+ u32 remap_hi;
+};
+
struct mvebu_mbus_state {
void __iomem *mbuswins_base;
void __iomem *sdramwins_base;
+ void __iomem *mbusbridge_base;
+ phys_addr_t sdramwins_phys_base;
struct dentry *debugfs_root;
struct dentry *debugfs_sdram;
struct dentry *debugfs_devs;
@@ -115,6 +138,11 @@ struct mvebu_mbus_state {
struct resource pcie_io_aperture;
const struct mvebu_mbus_soc_data *soc;
int hw_io_coherency;
+
+ /* Used during suspend/resume */
+ u32 mbus_bridge_ctrl;
+ u32 mbus_bridge_base;
+ struct mvebu_mbus_win_data wins[MBUS_WINS_MAX];
};
static struct mvebu_mbus_state mbus_state;
@@ -516,6 +544,28 @@ mvebu_mbus_default_setup_cpu_target(struct mvebu_mbus_state *mbus)
mvebu_mbus_dram_info.num_cs = cs;
}
+static int
+mvebu_mbus_default_save_cpu_target(struct mvebu_mbus_state *mbus,
+ u32 *store_addr)
+{
+ int i;
+
+ for (i = 0; i < 4; i++) {
+ u32 base = readl(mbus->sdramwins_base + DDR_BASE_CS_OFF(i));
+ u32 size = readl(mbus->sdramwins_base + DDR_SIZE_CS_OFF(i));
+
+ writel(mbus->sdramwins_phys_base + DDR_BASE_CS_OFF(i),
+ store_addr++);
+ writel(base, store_addr++);
+ writel(mbus->sdramwins_phys_base + DDR_SIZE_CS_OFF(i),
+ store_addr++);
+ writel(size, store_addr++);
+ }
+
+ /* We've written 16 words to the store address */
+ return 16;
+}
+
static void __init
mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
{
@@ -546,10 +596,35 @@ mvebu_mbus_dove_setup_cpu_target(struct mvebu_mbus_state *mbus)
mvebu_mbus_dram_info.num_cs = cs;
}
+static int
+mvebu_mbus_dove_save_cpu_target(struct mvebu_mbus_state *mbus,
+ u32 *store_addr)
+{
+ int i;
+
+ for (i = 0; i < 2; i++) {
+ u32 map = readl(mbus->sdramwins_base + DOVE_DDR_BASE_CS_OFF(i));
+
+ writel(mbus->sdramwins_phys_base + DOVE_DDR_BASE_CS_OFF(i),
+ store_addr++);
+ writel(map, store_addr++);
+ }
+
+ /* We've written 4 words to the store address */
+ return 4;
+}
+
+int mvebu_mbus_save_cpu_target(u32 *store_addr)
+{
+ return mbus_state.soc->save_cpu_target(&mbus_state, store_addr);
+}
+
static const struct mvebu_mbus_soc_data armada_370_xp_mbus_data = {
.num_wins = 20,
.num_remappable_wins = 8,
+ .has_mbus_bridge = true,
.win_cfg_offset = armada_370_xp_mbus_win_offset,
+ .save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
@@ -558,6 +633,7 @@ static const struct mvebu_mbus_soc_data kirkwood_mbus_data = {
.num_wins = 8,
.num_remappable_wins = 4,
.win_cfg_offset = orion_mbus_win_offset,
+ .save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
@@ -566,6 +642,7 @@ static const struct mvebu_mbus_soc_data dove_mbus_data = {
.num_wins = 8,
.num_remappable_wins = 4,
.win_cfg_offset = orion_mbus_win_offset,
+ .save_cpu_target = mvebu_mbus_dove_save_cpu_target,
.setup_cpu_target = mvebu_mbus_dove_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_dove,
};
@@ -578,6 +655,7 @@ static const struct mvebu_mbus_soc_data orion5x_4win_mbus_data = {
.num_wins = 8,
.num_remappable_wins = 4,
.win_cfg_offset = orion_mbus_win_offset,
+ .save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
@@ -586,6 +664,7 @@ static const struct mvebu_mbus_soc_data orion5x_2win_mbus_data = {
.num_wins = 8,
.num_remappable_wins = 2,
.win_cfg_offset = orion_mbus_win_offset,
+ .save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
@@ -594,6 +673,7 @@ static const struct mvebu_mbus_soc_data mv78xx0_mbus_data = {
.num_wins = 14,
.num_remappable_wins = 8,
.win_cfg_offset = mv78xx0_mbus_win_offset,
+ .save_cpu_target = mvebu_mbus_default_save_cpu_target,
.setup_cpu_target = mvebu_mbus_default_setup_cpu_target,
.show_cpu_target = mvebu_sdram_debug_show_orion,
};
@@ -698,11 +778,73 @@ static __init int mvebu_mbus_debugfs_init(void)
}
fs_initcall(mvebu_mbus_debugfs_init);
+static int mvebu_mbus_suspend(void)
+{
+ struct mvebu_mbus_state *s = &mbus_state;
+ int win;
+
+ if (!s->mbusbridge_base)
+ return -ENODEV;
+
+ for (win = 0; win < s->soc->num_wins; win++) {
+ void __iomem *addr = s->mbuswins_base +
+ s->soc->win_cfg_offset(win);
+
+ s->wins[win].base = readl(addr + WIN_BASE_OFF);
+ s->wins[win].ctrl = readl(addr + WIN_CTRL_OFF);
+
+ if (win >= s->soc->num_remappable_wins)
+ continue;
+
+ s->wins[win].remap_lo = readl(addr + WIN_REMAP_LO_OFF);
+ s->wins[win].remap_hi = readl(addr + WIN_REMAP_HI_OFF);
+ }
+
+ s->mbus_bridge_ctrl = readl(s->mbusbridge_base +
+ MBUS_BRIDGE_CTRL_OFF);
+ s->mbus_bridge_base = readl(s->mbusbridge_base +
+ MBUS_BRIDGE_BASE_OFF);
+
+ return 0;
+}
+
+static void mvebu_mbus_resume(void)
+{
+ struct mvebu_mbus_state *s = &mbus_state;
+ int win;
+
+ writel(s->mbus_bridge_ctrl,
+ s->mbusbridge_base + MBUS_BRIDGE_CTRL_OFF);
+ writel(s->mbus_bridge_base,
+ s->mbusbridge_base + MBUS_BRIDGE_BASE_OFF);
+
+ for (win = 0; win < s->soc->num_wins; win++) {
+ void __iomem *addr = s->mbuswins_base +
+ s->soc->win_cfg_offset(win);
+
+ writel(s->wins[win].base, addr + WIN_BASE_OFF);
+ writel(s->wins[win].ctrl, addr + WIN_CTRL_OFF);
+
+ if (win >= s->soc->num_remappable_wins)
+ continue;
+
+ writel(s->wins[win].remap_lo, addr + WIN_REMAP_LO_OFF);
+ writel(s->wins[win].remap_hi, addr + WIN_REMAP_HI_OFF);
+ }
+}
+
+struct syscore_ops mvebu_mbus_syscore_ops = {
+ .suspend = mvebu_mbus_suspend,
+ .resume = mvebu_mbus_resume,
+};
+
static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
phys_addr_t mbuswins_phys_base,
size_t mbuswins_size,
phys_addr_t sdramwins_phys_base,
- size_t sdramwins_size)
+ size_t sdramwins_size,
+ phys_addr_t mbusbridge_phys_base,
+ size_t mbusbridge_size)
{
int win;
@@ -716,11 +858,26 @@ static int __init mvebu_mbus_common_init(struct mvebu_mbus_state *mbus,
return -ENOMEM;
}
+ mbus->sdramwins_phys_base = sdramwins_phys_base;
+
+ if (mbusbridge_phys_base) {
+ mbus->mbusbridge_base = ioremap(mbusbridge_phys_base,
+ mbusbridge_size);
+ if (!mbus->mbusbridge_base) {
+ iounmap(mbus->sdramwins_base);
+ iounmap(mbus->mbuswins_base);
+ return -ENOMEM;
+ }
+ } else
+ mbus->mbusbridge_base = NULL;
+
for (win = 0; win < mbus->soc->num_wins; win++)
mvebu_mbus_disable_window(mbus, win);
mbus->soc->setup_cpu_target(mbus);
+ register_syscore_ops(&mvebu_mbus_syscore_ops);
+
return 0;
}
@@ -746,7 +903,7 @@ int __init mvebu_mbus_init(const char *soc, phys_addr_t mbuswins_phys_base,
mbuswins_phys_base,
mbuswins_size,
sdramwins_phys_base,
- sdramwins_size);
+ sdramwins_size, 0, 0);
}
#ifdef CONFIG_OF
@@ -887,7 +1044,7 @@ static void __init mvebu_mbus_get_pcie_resources(struct device_node *np,
int __init mvebu_mbus_dt_init(bool is_coherent)
{
- struct resource mbuswins_res, sdramwins_res;
+ struct resource mbuswins_res, sdramwins_res, mbusbridge_res;
struct device_node *np, *controller;
const struct of_device_id *of_id;
const __be32 *prop;
@@ -923,6 +1080,19 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
return -EINVAL;
}
+ /*
+ * Set the resource to 0 so that it can be left unmapped by
+ * mvebu_mbus_common_init() if the DT doesn't carry the
+ * necessary information. This is needed to preserve backward
+ * compatibility.
+ */
+ memset(&mbusbridge_res, 0, sizeof(mbusbridge_res));
+
+ if (mbus_state.soc->has_mbus_bridge) {
+ if (of_address_to_resource(controller, 2, &mbusbridge_res))
+ pr_warn(FW_WARN "deprecated mbus-mvebu Device Tree, suspend/resume will not work\n");
+ }
+
mbus_state.hw_io_coherency = is_coherent;
/* Get optional pcie-{mem,io}-aperture properties */
@@ -933,7 +1103,9 @@ int __init mvebu_mbus_dt_init(bool is_coherent)
mbuswins_res.start,
resource_size(&mbuswins_res),
sdramwins_res.start,
- resource_size(&sdramwins_res));
+ resource_size(&sdramwins_res),
+ mbusbridge_res.start,
+ resource_size(&mbusbridge_res));
if (ret)
return ret;
diff --git a/drivers/bus/omap_l3_noc.c b/drivers/bus/omap_l3_noc.c
index 531ae59..17d8659 100644
--- a/drivers/bus/omap_l3_noc.c
+++ b/drivers/bus/omap_l3_noc.c
@@ -222,10 +222,14 @@ static irqreturn_t l3_interrupt_handler(int irq, void *_l3)
}
/* Error found so break the for loop */
- break;
+ return IRQ_HANDLED;
}
}
- return IRQ_HANDLED;
+
+ dev_err(l3->dev, "L3 %s IRQ not handled!!\n",
+ inttype ? "debug" : "application");
+
+ return IRQ_NONE;
}
static const struct of_device_id l3_noc_match[] = {
@@ -296,11 +300,66 @@ static int omap_l3_probe(struct platform_device *pdev)
return ret;
}
+#ifdef CONFIG_PM
+
+/**
+ * l3_resume_noirq() - resume function for l3_noc
+ * @dev: pointer to l3_noc device structure
+ *
+ * We only have the resume handler only since we
+ * have already maintained the delta register
+ * configuration as part of configuring the system
+ */
+static int l3_resume_noirq(struct device *dev)
+{
+ struct omap_l3 *l3 = dev_get_drvdata(dev);
+ int i;
+ struct l3_flagmux_data *flag_mux;
+ void __iomem *base, *mask_regx = NULL;
+ u32 mask_val;
+
+ for (i = 0; i < l3->num_modules; i++) {
+ base = l3->l3_base[i];
+ flag_mux = l3->l3_flagmux[i];
+ if (!flag_mux->mask_app_bits && !flag_mux->mask_dbg_bits)
+ continue;
+
+ mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
+ (L3_APPLICATION_ERROR << 3);
+ mask_val = readl_relaxed(mask_regx);
+ mask_val &= ~(flag_mux->mask_app_bits);
+
+ writel_relaxed(mask_val, mask_regx);
+ mask_regx = base + flag_mux->offset + L3_FLAGMUX_MASK0 +
+ (L3_DEBUG_ERROR << 3);
+ mask_val = readl_relaxed(mask_regx);
+ mask_val &= ~(flag_mux->mask_dbg_bits);
+
+ writel_relaxed(mask_val, mask_regx);
+ }
+
+ /* Dummy read to force OCP barrier */
+ if (mask_regx)
+ (void)readl(mask_regx);
+
+ return 0;
+}
+
+static const struct dev_pm_ops l3_dev_pm_ops = {
+ .resume_noirq = l3_resume_noirq,
+};
+
+#define L3_DEV_PM_OPS (&l3_dev_pm_ops)
+#else
+#define L3_DEV_PM_OPS NULL
+#endif
+
static struct platform_driver omap_l3_driver = {
.probe = omap_l3_probe,
.driver = {
.name = "omap_l3_noc",
.owner = THIS_MODULE,
+ .pm = L3_DEV_PM_OPS,
.of_match_table = of_match_ptr(l3_noc_match),
},
};
diff --git a/drivers/bus/omap_l3_smx.c b/drivers/bus/omap_l3_smx.c
index acc2164..597fdae 100644
--- a/drivers/bus/omap_l3_smx.c
+++ b/drivers/bus/omap_l3_smx.c
@@ -27,6 +27,10 @@
#include <linux/platform_device.h>
#include <linux/interrupt.h>
#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+
#include "omap_l3_smx.h"
static inline u64 omap3_l3_readll(void __iomem *base, u16 reg)
@@ -211,7 +215,17 @@ static irqreturn_t omap3_l3_app_irq(int irq, void *_l3)
return ret;
}
-static int __init omap3_l3_probe(struct platform_device *pdev)
+#if IS_BUILTIN(CONFIG_OF)
+static const struct of_device_id omap3_l3_match[] = {
+ {
+ .compatible = "ti,omap3-l3-smx",
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(of, omap3_l3_match);
+#endif
+
+static int omap3_l3_probe(struct platform_device *pdev)
{
struct omap3_l3 *l3;
struct resource *res;
@@ -265,7 +279,7 @@ err0:
return ret;
}
-static int __exit omap3_l3_remove(struct platform_device *pdev)
+static int omap3_l3_remove(struct platform_device *pdev)
{
struct omap3_l3 *l3 = platform_get_drvdata(pdev);
@@ -278,15 +292,17 @@ static int __exit omap3_l3_remove(struct platform_device *pdev)
}
static struct platform_driver omap3_l3_driver = {
- .remove = __exit_p(omap3_l3_remove),
+ .probe = omap3_l3_probe,
+ .remove = omap3_l3_remove,
.driver = {
- .name = "omap_l3_smx",
+ .name = "omap_l3_smx",
+ .of_match_table = of_match_ptr(omap3_l3_match),
},
};
static int __init omap3_l3_init(void)
{
- return platform_driver_probe(&omap3_l3_driver, omap3_l3_probe);
+ return platform_driver_register(&omap3_l3_driver);
}
postcore_initcall_sync(omap3_l3_init);
diff --git a/drivers/char/hw_random/exynos-rng.c b/drivers/char/hw_random/exynos-rng.c
index 9f8277c..993efd7 100644
--- a/drivers/char/hw_random/exynos-rng.c
+++ b/drivers/char/hw_random/exynos-rng.c
@@ -143,7 +143,7 @@ static int exynos_rng_remove(struct platform_device *pdev)
return 0;
}
-#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+#ifdef CONFIG_PM
static int exynos_rng_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 524b707..4c58333 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -84,9 +84,12 @@ static inline int range_is_allowed(unsigned long pfn, unsigned long size)
}
#endif
-void __weak unxlate_dev_mem_ptr(unsigned long phys, void *addr)
+#ifndef unxlate_dev_mem_ptr
+#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr
+void __weak unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
{
}
+#endif
/*
* This funcion reads the *physical* memory. The f_pos points directly to the
@@ -97,7 +100,7 @@ static ssize_t read_mem(struct file *file, char __user *buf,
{
phys_addr_t p = *ppos;
ssize_t read, sz;
- char *ptr;
+ void *ptr;
if (p != *ppos)
return 0;
@@ -400,7 +403,7 @@ static ssize_t read_kmem(struct file *file, char __user *buf,
* uncached, then it must also be accessed uncached
* by the kernel or data corruption may occur
*/
- kbuf = xlate_dev_kmem_ptr((char *)p);
+ kbuf = xlate_dev_kmem_ptr((void *)p);
if (copy_to_user(buf, kbuf, sz))
return -EFAULT;
@@ -461,7 +464,7 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
#endif
while (count > 0) {
- char *ptr;
+ void *ptr;
sz = size_inside_page(p, count);
@@ -470,7 +473,7 @@ static ssize_t do_write_kmem(unsigned long p, const char __user *buf,
* it must also be accessed uncached by the kernel or data
* corruption may occur.
*/
- ptr = xlate_dev_kmem_ptr((char *)p);
+ ptr = xlate_dev_kmem_ptr((void *)p);
copied = copy_from_user(ptr, buf, sz);
if (copied) {
diff --git a/drivers/char/virtio_console.c b/drivers/char/virtio_console.c
index cf7a561..de03df9 100644
--- a/drivers/char/virtio_console.c
+++ b/drivers/char/virtio_console.c
@@ -355,7 +355,7 @@ static inline bool use_multiport(struct ports_device *portdev)
*/
if (!portdev->vdev)
return 0;
- return portdev->vdev->features[0] & (1 << VIRTIO_CONSOLE_F_MULTIPORT);
+ return __virtio_test_bit(portdev->vdev, VIRTIO_CONSOLE_F_MULTIPORT);
}
static DEFINE_SPINLOCK(dma_bufs_lock);
@@ -566,9 +566,9 @@ static ssize_t __send_control_msg(struct ports_device *portdev, u32 port_id,
if (!use_multiport(portdev))
return 0;
- cpkt.id = port_id;
- cpkt.event = event;
- cpkt.value = value;
+ cpkt.id = cpu_to_virtio32(portdev->vdev, port_id);
+ cpkt.event = cpu_to_virtio16(portdev->vdev, event);
+ cpkt.value = cpu_to_virtio16(portdev->vdev, value);
vq = portdev->c_ovq;
@@ -669,8 +669,8 @@ done:
* Give out the data that's requested from the buffer that we have
* queued up.
*/
-static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
- bool to_user)
+static ssize_t fill_readbuf(struct port *port, char __user *out_buf,
+ size_t out_count, bool to_user)
{
struct port_buffer *buf;
unsigned long flags;
@@ -688,7 +688,8 @@ static ssize_t fill_readbuf(struct port *port, char *out_buf, size_t out_count,
if (ret)
return -EFAULT;
} else {
- memcpy(out_buf, buf->buf + buf->offset, out_count);
+ memcpy((__force char *)out_buf, buf->buf + buf->offset,
+ out_count);
}
buf->offset += out_count;
@@ -1162,7 +1163,7 @@ static int get_chars(u32 vtermno, char *buf, int count)
/* If we don't have an input queue yet, we can't get input. */
BUG_ON(!port->in_vq);
- return fill_readbuf(port, buf, count, false);
+ return fill_readbuf(port, (__force char __user *)buf, count, false);
}
static void resize_console(struct port *port)
@@ -1602,7 +1603,8 @@ static void unplug_port(struct port *port)
}
/* Any private messages that the Host and Guest want to share */
-static void handle_control_message(struct ports_device *portdev,
+static void handle_control_message(struct virtio_device *vdev,
+ struct ports_device *portdev,
struct port_buffer *buf)
{
struct virtio_console_control *cpkt;
@@ -1612,15 +1614,16 @@ static void handle_control_message(struct ports_device *portdev,
cpkt = (struct virtio_console_control *)(buf->buf + buf->offset);
- port = find_port_by_id(portdev, cpkt->id);
- if (!port && cpkt->event != VIRTIO_CONSOLE_PORT_ADD) {
+ port = find_port_by_id(portdev, virtio32_to_cpu(vdev, cpkt->id));
+ if (!port &&
+ cpkt->event != cpu_to_virtio16(vdev, VIRTIO_CONSOLE_PORT_ADD)) {
/* No valid header at start of buffer. Drop it. */
dev_dbg(&portdev->vdev->dev,
"Invalid index %u in control packet\n", cpkt->id);
return;
}
- switch (cpkt->event) {
+ switch (virtio16_to_cpu(vdev, cpkt->event)) {
case VIRTIO_CONSOLE_PORT_ADD:
if (port) {
dev_dbg(&portdev->vdev->dev,
@@ -1628,13 +1631,15 @@ static void handle_control_message(struct ports_device *portdev,
send_control_msg(port, VIRTIO_CONSOLE_PORT_READY, 1);
break;
}
- if (cpkt->id >= portdev->config.max_nr_ports) {
+ if (virtio32_to_cpu(vdev, cpkt->id) >=
+ portdev->config.max_nr_ports) {
dev_warn(&portdev->vdev->dev,
- "Request for adding port with out-of-bound id %u, max. supported id: %u\n",
+ "Request for adding port with "
+ "out-of-bound id %u, max. supported id: %u\n",
cpkt->id, portdev->config.max_nr_ports - 1);
break;
}
- add_port(portdev, cpkt->id);
+ add_port(portdev, virtio32_to_cpu(vdev, cpkt->id));
break;
case VIRTIO_CONSOLE_PORT_REMOVE:
unplug_port(port);
@@ -1670,7 +1675,7 @@ static void handle_control_message(struct ports_device *portdev,
break;
}
case VIRTIO_CONSOLE_PORT_OPEN:
- port->host_connected = cpkt->value;
+ port->host_connected = virtio16_to_cpu(vdev, cpkt->value);
wake_up_interruptible(&port->waitqueue);
/*
* If the host port got closed and the host had any
@@ -1752,7 +1757,7 @@ static void control_work_handler(struct work_struct *work)
buf->len = len;
buf->offset = 0;
- handle_control_message(portdev, buf);
+ handle_control_message(vq->vdev, portdev, buf);
spin_lock(&portdev->c_ivq_lock);
if (add_inbuf(portdev->c_ivq, buf) < 0) {
diff --git a/drivers/clk/clk-s2mps11.c b/drivers/clk/clk-s2mps11.c
index b7797fb..7bb13af 100644
--- a/drivers/clk/clk-s2mps11.c
+++ b/drivers/clk/clk-s2mps11.c
@@ -23,6 +23,7 @@
#include <linux/clk-provider.h>
#include <linux/platform_device.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s5m8767.h>
#include <linux/mfd/samsung/core.h>
@@ -120,6 +121,24 @@ static struct clk_init_data s2mps11_clks_init[S2MPS11_CLKS_NUM] = {
},
};
+static struct clk_init_data s2mps13_clks_init[S2MPS11_CLKS_NUM] = {
+ [S2MPS11_CLK_AP] = {
+ .name = "s2mps13_ap",
+ .ops = &s2mps11_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [S2MPS11_CLK_CP] = {
+ .name = "s2mps13_cp",
+ .ops = &s2mps11_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+ [S2MPS11_CLK_BT] = {
+ .name = "s2mps13_bt",
+ .ops = &s2mps11_clk_ops,
+ .flags = CLK_IS_ROOT,
+ },
+};
+
static struct clk_init_data s2mps14_clks_init[S2MPS11_CLKS_NUM] = {
[S2MPS11_CLK_AP] = {
.name = "s2mps14_ap",
@@ -184,6 +203,10 @@ static int s2mps11_clk_probe(struct platform_device *pdev)
s2mps11_reg = S2MPS11_REG_RTC_CTRL;
clks_init = s2mps11_clks_init;
break;
+ case S2MPS13X:
+ s2mps11_reg = S2MPS13_REG_RTCCTRL;
+ clks_init = s2mps13_clks_init;
+ break;
case S2MPS14X:
s2mps11_reg = S2MPS14_REG_RTCCTRL;
clks_init = s2mps14_clks_init;
@@ -279,6 +302,7 @@ static int s2mps11_clk_remove(struct platform_device *pdev)
static const struct platform_device_id s2mps11_clk_id[] = {
{ "s2mps11-clk", S2MPS11X},
+ { "s2mps13-clk", S2MPS13X},
{ "s2mps14-clk", S2MPS14X},
{ "s5m8767-clk", S5M8767X},
{ },
diff --git a/drivers/clk/mvebu/common.c b/drivers/clk/mvebu/common.c
index b7fcb46..0d4d121 100644
--- a/drivers/clk/mvebu/common.c
+++ b/drivers/clk/mvebu/common.c
@@ -19,6 +19,7 @@
#include <linux/io.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/syscore_ops.h>
#include "common.h"
@@ -177,14 +178,17 @@ struct clk_gating_ctrl {
spinlock_t *lock;
struct clk **gates;
int num_gates;
+ void __iomem *base;
+ u32 saved_reg;
};
#define to_clk_gate(_hw) container_of(_hw, struct clk_gate, hw)
+static struct clk_gating_ctrl *ctrl;
+
static struct clk *clk_gating_get_src(
struct of_phandle_args *clkspec, void *data)
{
- struct clk_gating_ctrl *ctrl = (struct clk_gating_ctrl *)data;
int n;
if (clkspec->args_count < 1)
@@ -199,15 +203,35 @@ static struct clk *clk_gating_get_src(
return ERR_PTR(-ENODEV);
}
+static int mvebu_clk_gating_suspend(void)
+{
+ ctrl->saved_reg = readl(ctrl->base);
+ return 0;
+}
+
+static void mvebu_clk_gating_resume(void)
+{
+ writel(ctrl->saved_reg, ctrl->base);
+}
+
+static struct syscore_ops clk_gate_syscore_ops = {
+ .suspend = mvebu_clk_gating_suspend,
+ .resume = mvebu_clk_gating_resume,
+};
+
void __init mvebu_clk_gating_setup(struct device_node *np,
const struct clk_gating_soc_desc *desc)
{
- struct clk_gating_ctrl *ctrl;
struct clk *clk;
void __iomem *base;
const char *default_parent = NULL;
int n;
+ if (ctrl) {
+ pr_err("mvebu-clk-gating: cannot instantiate more than one gatable clock device\n");
+ return;
+ }
+
base = of_iomap(np, 0);
if (WARN_ON(!base))
return;
@@ -225,6 +249,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
/* lock must already be initialized */
ctrl->lock = &ctrl_gating_lock;
+ ctrl->base = base;
+
/* Count, allocate, and register clock gates */
for (n = 0; desc[n].name;)
n++;
@@ -246,6 +272,8 @@ void __init mvebu_clk_gating_setup(struct device_node *np,
of_clk_add_provider(np, clk_gating_get_src, ctrl);
+ register_syscore_ops(&clk_gate_syscore_ops);
+
return;
gates_out:
kfree(ctrl);
diff --git a/drivers/clk/samsung/clk-exynos5440.c b/drivers/clk/samsung/clk-exynos5440.c
index 00d1d00..979e813 100644
--- a/drivers/clk/samsung/clk-exynos5440.c
+++ b/drivers/clk/samsung/clk-exynos5440.c
@@ -15,6 +15,8 @@
#include <linux/clk-provider.h>
#include <linux/of.h>
#include <linux/of_address.h>
+#include <linux/notifier.h>
+#include <linux/reboot.h>
#include "clk.h"
#include "clk-pll.h"
@@ -23,6 +25,8 @@
#define CPU_CLK_STATUS 0xfc
#define MISC_DOUT1 0x558
+static void __iomem *reg_base;
+
/* parent clock name list */
PNAME(mout_armclk_p) = { "cplla", "cpllb" };
PNAME(mout_spi_p) = { "div125", "div200" };
@@ -89,10 +93,30 @@ static const struct of_device_id ext_clk_match[] __initconst = {
{},
};
+static int exynos5440_clk_restart_notify(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ u32 val, status;
+
+ status = readl_relaxed(reg_base + 0xbc);
+ val = readl_relaxed(reg_base + 0xcc);
+ val = (val & 0xffff0000) | (status & 0xffff);
+ writel_relaxed(val, reg_base + 0xcc);
+
+ return NOTIFY_DONE;
+}
+
+/*
+ * Exynos5440 Clock restart notifier, handles restart functionality
+ */
+static struct notifier_block exynos5440_clk_restart_handler = {
+ .notifier_call = exynos5440_clk_restart_notify,
+ .priority = 128,
+};
+
/* register exynos5440 clocks */
static void __init exynos5440_clk_init(struct device_node *np)
{
- void __iomem *reg_base;
struct samsung_clk_provider *ctx;
reg_base = of_iomap(np, 0);
@@ -125,6 +149,9 @@ static void __init exynos5440_clk_init(struct device_node *np)
samsung_clk_of_add_provider(np, ctx);
+ if (register_restart_handler(&exynos5440_clk_restart_handler))
+ pr_warn("exynos5440 clock can't register restart handler\n");
+
pr_info("Exynos5440: arm_clk = %ldHz\n", _get_rate("arm_clk"));
pr_info("exynos5440 clock initialization complete\n");
}
diff --git a/drivers/clk/tegra/clk-divider.c b/drivers/clk/tegra/clk-divider.c
index 290f9c1..59a5714 100644
--- a/drivers/clk/tegra/clk-divider.c
+++ b/drivers/clk/tegra/clk-divider.c
@@ -185,3 +185,16 @@ struct clk *tegra_clk_register_divider(const char *name,
return clk;
}
+
+static const struct clk_div_table mc_div_table[] = {
+ { .val = 0, .div = 2 },
+ { .val = 1, .div = 1 },
+ { .val = 0, .div = 0 },
+};
+
+struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
+ void __iomem *reg, spinlock_t *lock)
+{
+ return clk_register_divider_table(NULL, name, parent_name, 0, reg,
+ 16, 1, 0, mc_div_table, lock);
+}
diff --git a/drivers/clk/tegra/clk-tegra114.c b/drivers/clk/tegra/clk-tegra114.c
index f760f31..0b03d2c 100644
--- a/drivers/clk/tegra/clk-tegra114.c
+++ b/drivers/clk/tegra/clk-tegra114.c
@@ -173,6 +173,7 @@ static DEFINE_SPINLOCK(pll_d_lock);
static DEFINE_SPINLOCK(pll_d2_lock);
static DEFINE_SPINLOCK(pll_u_lock);
static DEFINE_SPINLOCK(pll_re_lock);
+static DEFINE_SPINLOCK(emc_lock);
static struct div_nmp pllxc_nmp = {
.divm_shift = 0,
@@ -1228,7 +1229,11 @@ static __init void tegra114_periph_clk_init(void __iomem *clk_base,
ARRAY_SIZE(mux_pllmcp_clkm),
CLK_SET_RATE_NO_REPARENT,
clk_base + CLK_SOURCE_EMC,
- 29, 3, 0, NULL);
+ 29, 3, 0, &emc_lock);
+
+ clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+ &emc_lock);
+ clks[TEGRA114_CLK_MC] = clk;
for (i = 0; i < ARRAY_SIZE(tegra_periph_clk_list); i++) {
data = &tegra_periph_clk_list[i];
diff --git a/drivers/clk/tegra/clk-tegra124.c b/drivers/clk/tegra/clk-tegra124.c
index e3a8584..f5f9bac 100644
--- a/drivers/clk/tegra/clk-tegra124.c
+++ b/drivers/clk/tegra/clk-tegra124.c
@@ -132,6 +132,7 @@ static DEFINE_SPINLOCK(pll_d2_lock);
static DEFINE_SPINLOCK(pll_e_lock);
static DEFINE_SPINLOCK(pll_re_lock);
static DEFINE_SPINLOCK(pll_u_lock);
+static DEFINE_SPINLOCK(emc_lock);
/* possible OSC frequencies in Hz */
static unsigned long tegra124_input_freq[] = {
@@ -1127,7 +1128,11 @@ static __init void tegra124_periph_clk_init(void __iomem *clk_base,
clk = clk_register_mux(NULL, "emc_mux", mux_pllmcp_clkm,
ARRAY_SIZE(mux_pllmcp_clkm), 0,
clk_base + CLK_SOURCE_EMC,
- 29, 3, 0, NULL);
+ 29, 3, 0, &emc_lock);
+
+ clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+ &emc_lock);
+ clks[TEGRA124_CLK_MC] = clk;
/* cml0 */
clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
diff --git a/drivers/clk/tegra/clk-tegra20.c b/drivers/clk/tegra/clk-tegra20.c
index dace2b1..41272dc 100644
--- a/drivers/clk/tegra/clk-tegra20.c
+++ b/drivers/clk/tegra/clk-tegra20.c
@@ -140,6 +140,8 @@ static struct cpu_clk_suspend_context {
static void __iomem *clk_base;
static void __iomem *pmc_base;
+static DEFINE_SPINLOCK(emc_lock);
+
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
_clk_num, _gate_flags, _clk_id) \
TEGRA_INIT_DATA(_name, NULL, NULL, _parents, _offset, \
@@ -819,11 +821,15 @@ static void __init tegra20_periph_clk_init(void)
ARRAY_SIZE(mux_pllmcp_clkm),
CLK_SET_RATE_NO_REPARENT,
clk_base + CLK_SOURCE_EMC,
- 30, 2, 0, NULL);
+ 30, 2, 0, &emc_lock);
clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
57, periph_clk_enb_refcnt);
clks[TEGRA20_CLK_EMC] = clk;
+ clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+ &emc_lock);
+ clks[TEGRA20_CLK_MC] = clk;
+
/* dsi */
clk = tegra_clk_register_periph_gate("dsi", "pll_d", 0, clk_base, 0,
48, periph_clk_enb_refcnt);
diff --git a/drivers/clk/tegra/clk-tegra30.c b/drivers/clk/tegra/clk-tegra30.c
index 5bbacd0..4b9d8bd 100644
--- a/drivers/clk/tegra/clk-tegra30.c
+++ b/drivers/clk/tegra/clk-tegra30.c
@@ -177,6 +177,7 @@ static unsigned long input_freq;
static DEFINE_SPINLOCK(cml_lock);
static DEFINE_SPINLOCK(pll_d_lock);
+static DEFINE_SPINLOCK(emc_lock);
#define TEGRA_INIT_DATA_MUX(_name, _parents, _offset, \
_clk_num, _gate_flags, _clk_id) \
@@ -1157,11 +1158,15 @@ static void __init tegra30_periph_clk_init(void)
ARRAY_SIZE(mux_pllmcp_clkm),
CLK_SET_RATE_NO_REPARENT,
clk_base + CLK_SOURCE_EMC,
- 30, 2, 0, NULL);
+ 30, 2, 0, &emc_lock);
clk = tegra_clk_register_periph_gate("emc", "emc_mux", 0, clk_base, 0,
57, periph_clk_enb_refcnt);
clks[TEGRA30_CLK_EMC] = clk;
+ clk = tegra_clk_register_mc("mc", "emc_mux", clk_base + CLK_SOURCE_EMC,
+ &emc_lock);
+ clks[TEGRA30_CLK_MC] = clk;
+
/* cml0 */
clk = clk_register_gate(NULL, "cml0", "pll_e", 0, clk_base + PLLE_AUX,
0, 0, &cml_lock);
diff --git a/drivers/clk/tegra/clk.h b/drivers/clk/tegra/clk.h
index 16ec8d6..4e458aa 100644
--- a/drivers/clk/tegra/clk.h
+++ b/drivers/clk/tegra/clk.h
@@ -86,6 +86,8 @@ struct clk *tegra_clk_register_divider(const char *name,
const char *parent_name, void __iomem *reg,
unsigned long flags, u8 clk_divider_flags, u8 shift, u8 width,
u8 frac_width, spinlock_t *lock);
+struct clk *tegra_clk_register_mc(const char *name, const char *parent_name,
+ void __iomem *reg, spinlock_t *lock);
/*
* Tegra PLL:
diff --git a/drivers/clk/ti/dpll.c b/drivers/clk/ti/dpll.c
index 79791e1..85ac0dd 100644
--- a/drivers/clk/ti/dpll.c
+++ b/drivers/clk/ti/dpll.c
@@ -33,6 +33,9 @@ static const struct clk_ops dpll_m4xen_ck_ops = {
.recalc_rate = &omap4_dpll_regm4xen_recalc,
.round_rate = &omap4_dpll_regm4xen_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
+ .determine_rate = &omap4_dpll_regm4xen_determine_rate,
.get_parent = &omap2_init_dpll_parent,
};
#else
@@ -53,6 +56,9 @@ static const struct clk_ops dpll_ck_ops = {
.recalc_rate = &omap3_dpll_recalc,
.round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
.get_parent = &omap2_init_dpll_parent,
};
@@ -61,6 +67,9 @@ static const struct clk_ops dpll_no_gate_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.round_rate = &omap2_dpll_round_rate,
.set_rate = &omap3_noncore_dpll_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
};
#else
static const struct clk_ops dpll_core_ck_ops = {};
@@ -97,6 +106,9 @@ static const struct clk_ops omap3_dpll_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_noncore_dpll_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_noncore_dpll_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate,
};
@@ -106,6 +118,9 @@ static const struct clk_ops omap3_dpll_per_ck_ops = {
.get_parent = &omap2_init_dpll_parent,
.recalc_rate = &omap3_dpll_recalc,
.set_rate = &omap3_dpll4_set_rate,
+ .set_parent = &omap3_noncore_dpll_set_parent,
+ .set_rate_and_parent = &omap3_dpll4_set_rate_and_parent,
+ .determine_rate = &omap3_noncore_dpll_determine_rate,
.round_rate = &omap2_dpll_round_rate,
};
#endif
diff --git a/drivers/clk/versatile/Makefile b/drivers/clk/versatile/Makefile
index 162e519..8ff0374 100644
--- a/drivers/clk/versatile/Makefile
+++ b/drivers/clk/versatile/Makefile
@@ -2,6 +2,5 @@
obj-$(CONFIG_ICST) += clk-icst.o clk-versatile.o
obj-$(CONFIG_INTEGRATOR_IMPD1) += clk-impd1.o
obj-$(CONFIG_ARCH_REALVIEW) += clk-realview.o
-obj-$(CONFIG_ARCH_VEXPRESS) += clk-vexpress.o
obj-$(CONFIG_CLK_SP810) += clk-sp810.o
obj-$(CONFIG_CLK_VEXPRESS_OSC) += clk-vexpress-osc.o
diff --git a/drivers/clk/versatile/clk-vexpress-osc.c b/drivers/clk/versatile/clk-vexpress-osc.c
index 529a59c..765f1e0 100644
--- a/drivers/clk/versatile/clk-vexpress-osc.c
+++ b/drivers/clk/versatile/clk-vexpress-osc.c
@@ -70,7 +70,6 @@ static struct clk_ops vexpress_osc_ops = {
static int vexpress_osc_probe(struct platform_device *pdev)
{
- struct clk_lookup *cl = pdev->dev.platform_data; /* Non-DT lookup */
struct clk_init_data init;
struct vexpress_osc *osc;
struct clk *clk;
@@ -106,12 +105,6 @@ static int vexpress_osc_probe(struct platform_device *pdev)
of_clk_add_provider(pdev->dev.of_node, of_clk_src_simple_get, clk);
- /* Only happens for non-DT cases */
- if (cl) {
- cl->clk = clk;
- clkdev_add(cl);
- }
-
dev_dbg(&pdev->dev, "Registered clock '%s'\n", init.name);
return 0;
diff --git a/drivers/clk/versatile/clk-vexpress.c b/drivers/clk/versatile/clk-vexpress.c
deleted file mode 100644
index 2d5e1b4..0000000
--- a/drivers/clk/versatile/clk-vexpress.c
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * Copyright (C) 2012 ARM Limited
- */
-
-#include <linux/amba/sp810.h>
-#include <linux/clkdev.h>
-#include <linux/clk-provider.h>
-#include <linux/err.h>
-#include <linux/vexpress.h>
-
-static struct clk *vexpress_sp810_timerclken[4];
-static DEFINE_SPINLOCK(vexpress_sp810_lock);
-
-static void __init vexpress_sp810_init(void __iomem *base)
-{
- int i;
-
- if (WARN_ON(!base))
- return;
-
- for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++) {
- char name[12];
- const char *parents[] = {
- "v2m:refclk32khz", /* REFCLK */
- "v2m:refclk1mhz" /* TIMCLK */
- };
-
- snprintf(name, ARRAY_SIZE(name), "timerclken%d", i);
-
- vexpress_sp810_timerclken[i] = clk_register_mux(NULL, name,
- parents, 2, CLK_SET_RATE_NO_REPARENT,
- base + SCCTRL, SCCTRL_TIMERENnSEL_SHIFT(i), 1,
- 0, &vexpress_sp810_lock);
-
- if (WARN_ON(IS_ERR(vexpress_sp810_timerclken[i])))
- break;
- }
-}
-
-
-static const char * const vexpress_clk_24mhz_periphs[] __initconst = {
- "mb:uart0", "mb:uart1", "mb:uart2", "mb:uart3",
- "mb:mmci", "mb:kmi0", "mb:kmi1"
-};
-
-void __init vexpress_clk_init(void __iomem *sp810_base)
-{
- struct clk *clk;
- int i;
-
- clk = clk_register_fixed_rate(NULL, "dummy_apb_pclk", NULL,
- CLK_IS_ROOT, 0);
- WARN_ON(clk_register_clkdev(clk, "apb_pclk", NULL));
-
- clk = clk_register_fixed_rate(NULL, "v2m:clk_24mhz", NULL,
- CLK_IS_ROOT, 24000000);
- for (i = 0; i < ARRAY_SIZE(vexpress_clk_24mhz_periphs); i++)
- WARN_ON(clk_register_clkdev(clk, NULL,
- vexpress_clk_24mhz_periphs[i]));
-
- clk = clk_register_fixed_rate(NULL, "v2m:refclk32khz", NULL,
- CLK_IS_ROOT, 32768);
- WARN_ON(clk_register_clkdev(clk, NULL, "v2m:wdt"));
-
- clk = clk_register_fixed_rate(NULL, "v2m:refclk1mhz", NULL,
- CLK_IS_ROOT, 1000000);
-
- vexpress_sp810_init(sp810_base);
-
- for (i = 0; i < ARRAY_SIZE(vexpress_sp810_timerclken); i++)
- WARN_ON(clk_set_parent(vexpress_sp810_timerclken[i], clk));
-
- WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[0],
- "v2m-timer0", "sp804"));
- WARN_ON(clk_register_clkdev(vexpress_sp810_timerclken[1],
- "v2m-timer1", "sp804"));
-}
diff --git a/drivers/clocksource/Kconfig b/drivers/clocksource/Kconfig
index 9042060..f657a48 100644
--- a/drivers/clocksource/Kconfig
+++ b/drivers/clocksource/Kconfig
@@ -32,6 +32,7 @@ config ARMADA_370_XP_TIMER
config MESON6_TIMER
bool
+ select CLKSRC_MMIO
config ORION_TIMER
select CLKSRC_OF
diff --git a/drivers/clocksource/Makefile b/drivers/clocksource/Makefile
index 756f6f1..fae0435 100644
--- a/drivers/clocksource/Makefile
+++ b/drivers/clocksource/Makefile
@@ -45,4 +45,5 @@ obj-$(CONFIG_ARM_GLOBAL_TIMER) += arm_global_timer.o
obj-$(CONFIG_CLKSRC_METAG_GENERIC) += metag_generic.o
obj-$(CONFIG_ARCH_HAS_TICK_BROADCAST) += dummy_timer.o
obj-$(CONFIG_ARCH_KEYSTONE) += timer-keystone.o
+obj-$(CONFIG_ARCH_INTEGRATOR_AP) += timer-integrator-ap.o
obj-$(CONFIG_CLKSRC_VERSATILE) += versatile.o
diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c
index 43005d4..6a79fc4 100644
--- a/drivers/clocksource/arm_arch_timer.c
+++ b/drivers/clocksource/arm_arch_timer.c
@@ -462,7 +462,10 @@ static void __init arch_counter_register(unsigned type)
/* Register the CP15 based counter if we have one */
if (type & ARCH_CP15_TIMER) {
- arch_timer_read_counter = arch_counter_get_cntvct;
+ if (arch_timer_use_virtual)
+ arch_timer_read_counter = arch_counter_get_cntvct;
+ else
+ arch_timer_read_counter = arch_counter_get_cntpct;
} else {
arch_timer_read_counter = arch_counter_get_cntvct_mem;
@@ -702,6 +705,14 @@ static void __init arch_timer_init(struct device_node *np)
arch_timer_detect_rate(NULL, np);
/*
+ * If we cannot rely on firmware initializing the timer registers then
+ * we should use the physical timers instead.
+ */
+ if (IS_ENABLED(CONFIG_ARM) &&
+ of_property_read_bool(np, "arm,cpu-registers-not-fw-configured"))
+ arch_timer_use_virtual = false;
+
+ /*
* If HYP mode is available, we know that the physical timer
* has been configured to be accessible from PL1. Use it, so
* that a guest can use the virtual timer instead.
diff --git a/drivers/clocksource/time-armada-370-xp.c b/drivers/clocksource/time-armada-370-xp.c
index 0451e62..0c8c5e3 100644
--- a/drivers/clocksource/time-armada-370-xp.c
+++ b/drivers/clocksource/time-armada-370-xp.c
@@ -43,6 +43,7 @@
#include <linux/module.h>
#include <linux/sched_clock.h>
#include <linux/percpu.h>
+#include <linux/syscore_ops.h>
/*
* Timer block registers.
@@ -223,6 +224,28 @@ static struct notifier_block armada_370_xp_timer_cpu_nb = {
.notifier_call = armada_370_xp_timer_cpu_notify,
};
+static u32 timer0_ctrl_reg, timer0_local_ctrl_reg;
+
+static int armada_370_xp_timer_suspend(void)
+{
+ timer0_ctrl_reg = readl(timer_base + TIMER_CTRL_OFF);
+ timer0_local_ctrl_reg = readl(local_base + TIMER_CTRL_OFF);
+ return 0;
+}
+
+static void armada_370_xp_timer_resume(void)
+{
+ writel(0xffffffff, timer_base + TIMER0_VAL_OFF);
+ writel(0xffffffff, timer_base + TIMER0_RELOAD_OFF);
+ writel(timer0_ctrl_reg, timer_base + TIMER_CTRL_OFF);
+ writel(timer0_local_ctrl_reg, local_base + TIMER_CTRL_OFF);
+}
+
+struct syscore_ops armada_370_xp_timer_syscore_ops = {
+ .suspend = armada_370_xp_timer_suspend,
+ .resume = armada_370_xp_timer_resume,
+};
+
static void __init armada_370_xp_timer_common_init(struct device_node *np)
{
u32 clr = 0, set = 0;
@@ -285,6 +308,8 @@ static void __init armada_370_xp_timer_common_init(struct device_node *np)
/* Immediately configure the timer on the boot CPU */
if (!res)
armada_370_xp_timer_setup(this_cpu_ptr(armada_370_xp_evt));
+
+ register_syscore_ops(&armada_370_xp_timer_syscore_ops);
}
static void __init armada_xp_timer_init(struct device_node *np)
@@ -293,6 +318,7 @@ static void __init armada_xp_timer_init(struct device_node *np)
/* The 25Mhz fixed clock is mandatory, and must always be available */
BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
timer_clk = clk_get_rate(clk);
armada_370_xp_timer_common_init(np);
@@ -300,11 +326,40 @@ static void __init armada_xp_timer_init(struct device_node *np)
CLOCKSOURCE_OF_DECLARE(armada_xp, "marvell,armada-xp-timer",
armada_xp_timer_init);
+static void __init armada_375_timer_init(struct device_node *np)
+{
+ struct clk *clk;
+
+ clk = of_clk_get_by_name(np, "fixed");
+ if (!IS_ERR(clk)) {
+ clk_prepare_enable(clk);
+ timer_clk = clk_get_rate(clk);
+ } else {
+
+ /*
+ * This fallback is required in order to retain proper
+ * devicetree backwards compatibility.
+ */
+ clk = of_clk_get(np, 0);
+
+ /* Must have at least a clock */
+ BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
+ timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
+ timer25Mhz = false;
+ }
+
+ armada_370_xp_timer_common_init(np);
+}
+CLOCKSOURCE_OF_DECLARE(armada_375, "marvell,armada-375-timer",
+ armada_375_timer_init);
+
static void __init armada_370_timer_init(struct device_node *np)
{
struct clk *clk = of_clk_get(np, 0);
BUG_ON(IS_ERR(clk));
+ clk_prepare_enable(clk);
timer_clk = clk_get_rate(clk) / TIMER_DIVIDER;
timer25Mhz = false;
diff --git a/drivers/clocksource/timer-atmel-pit.c b/drivers/clocksource/timer-atmel-pit.c
index d528909..b5b4d45 100644
--- a/drivers/clocksource/timer-atmel-pit.c
+++ b/drivers/clocksource/timer-atmel-pit.c
@@ -262,35 +262,3 @@ static void __init at91sam926x_pit_dt_init(struct device_node *node)
}
CLOCKSOURCE_OF_DECLARE(at91sam926x_pit, "atmel,at91sam9260-pit",
at91sam926x_pit_dt_init);
-
-static void __iomem *pit_base_addr;
-
-void __init at91sam926x_pit_init(int irq)
-{
- struct pit_data *data;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data)
- panic(pr_fmt("Unable to allocate memory\n"));
-
- data->base = pit_base_addr;
-
- data->mck = clk_get(NULL, "mck");
- if (IS_ERR(data->mck))
- panic(pr_fmt("Unable to get mck clk\n"));
-
- data->irq = irq;
-
- at91sam926x_pit_common_init(data);
-}
-
-void __init at91sam926x_ioremap_pit(u32 addr)
-{
- if (of_have_populated_dt())
- return;
-
- pit_base_addr = ioremap(addr, 16);
-
- if (!pit_base_addr)
- panic(pr_fmt("Impossible to ioremap PIT\n"));
-}
diff --git a/drivers/clocksource/timer-integrator-ap.c b/drivers/clocksource/timer-integrator-ap.c
new file mode 100644
index 0000000..b9efd30
--- /dev/null
+++ b/drivers/clocksource/timer-integrator-ap.c
@@ -0,0 +1,210 @@
+/*
+ * Integrator/AP timer driver
+ * Copyright (C) 2000-2003 Deep Blue Solutions Ltd
+ * Copyright (c) 2014, Linaro Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/clk.h>
+#include <linux/clocksource.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/of_platform.h>
+#include <linux/clockchips.h>
+#include <linux/interrupt.h>
+#include <linux/sched_clock.h>
+#include <asm/hardware/arm_timer.h>
+
+static void __iomem * sched_clk_base;
+
+static u64 notrace integrator_read_sched_clock(void)
+{
+ return -readl(sched_clk_base + TIMER_VALUE);
+}
+
+static void integrator_clocksource_init(unsigned long inrate,
+ void __iomem *base)
+{
+ u32 ctrl = TIMER_CTRL_ENABLE | TIMER_CTRL_PERIODIC;
+ unsigned long rate = inrate;
+
+ if (rate >= 1500000) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
+ }
+
+ writel(0xffff, base + TIMER_LOAD);
+ writel(ctrl, base + TIMER_CTRL);
+
+ clocksource_mmio_init(base + TIMER_VALUE, "timer2",
+ rate, 200, 16, clocksource_mmio_readl_down);
+
+ sched_clk_base = base;
+ sched_clock_register(integrator_read_sched_clock, 16, rate);
+}
+
+static unsigned long timer_reload;
+static void __iomem * clkevt_base;
+
+/*
+ * IRQ handler for the timer
+ */
+static irqreturn_t integrator_timer_interrupt(int irq, void *dev_id)
+{
+ struct clock_event_device *evt = dev_id;
+
+ /* clear the interrupt */
+ writel(1, clkevt_base + TIMER_INTCLR);
+
+ evt->event_handler(evt);
+
+ return IRQ_HANDLED;
+}
+
+static void clkevt_set_mode(enum clock_event_mode mode, struct clock_event_device *evt)
+{
+ u32 ctrl = readl(clkevt_base + TIMER_CTRL) & ~TIMER_CTRL_ENABLE;
+
+ /* Disable timer */
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+
+ switch (mode) {
+ case CLOCK_EVT_MODE_PERIODIC:
+ /* Enable the timer and start the periodic tick */
+ writel(timer_reload, clkevt_base + TIMER_LOAD);
+ ctrl |= TIMER_CTRL_PERIODIC | TIMER_CTRL_ENABLE;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_ONESHOT:
+ /* Leave the timer disabled, .set_next_event will enable it */
+ ctrl &= ~TIMER_CTRL_PERIODIC;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+ break;
+ case CLOCK_EVT_MODE_UNUSED:
+ case CLOCK_EVT_MODE_SHUTDOWN:
+ case CLOCK_EVT_MODE_RESUME:
+ default:
+ /* Just leave in disabled state */
+ break;
+ }
+
+}
+
+static int clkevt_set_next_event(unsigned long next, struct clock_event_device *evt)
+{
+ unsigned long ctrl = readl(clkevt_base + TIMER_CTRL);
+
+ writel(ctrl & ~TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+ writel(next, clkevt_base + TIMER_LOAD);
+ writel(ctrl | TIMER_CTRL_ENABLE, clkevt_base + TIMER_CTRL);
+
+ return 0;
+}
+
+static struct clock_event_device integrator_clockevent = {
+ .name = "timer1",
+ .features = CLOCK_EVT_FEAT_PERIODIC | CLOCK_EVT_FEAT_ONESHOT,
+ .set_mode = clkevt_set_mode,
+ .set_next_event = clkevt_set_next_event,
+ .rating = 300,
+};
+
+static struct irqaction integrator_timer_irq = {
+ .name = "timer",
+ .flags = IRQF_TIMER | IRQF_IRQPOLL,
+ .handler = integrator_timer_interrupt,
+ .dev_id = &integrator_clockevent,
+};
+
+static void integrator_clockevent_init(unsigned long inrate,
+ void __iomem *base, int irq)
+{
+ unsigned long rate = inrate;
+ unsigned int ctrl = 0;
+
+ clkevt_base = base;
+ /* Calculate and program a divisor */
+ if (rate > 0x100000 * HZ) {
+ rate /= 256;
+ ctrl |= TIMER_CTRL_DIV256;
+ } else if (rate > 0x10000 * HZ) {
+ rate /= 16;
+ ctrl |= TIMER_CTRL_DIV16;
+ }
+ timer_reload = rate / HZ;
+ writel(ctrl, clkevt_base + TIMER_CTRL);
+
+ setup_irq(irq, &integrator_timer_irq);
+ clockevents_config_and_register(&integrator_clockevent,
+ rate,
+ 1,
+ 0xffffU);
+}
+
+static void __init integrator_ap_timer_init_of(struct device_node *node)
+{
+ const char *path;
+ void __iomem *base;
+ int err;
+ int irq;
+ struct clk *clk;
+ unsigned long rate;
+ struct device_node *pri_node;
+ struct device_node *sec_node;
+
+ base = of_io_request_and_map(node, 0, "integrator-timer");
+ if (!base)
+ return;
+
+ clk = of_clk_get(node, 0);
+ if (IS_ERR(clk)) {
+ pr_err("No clock for %s\n", node->name);
+ return;
+ }
+ clk_prepare_enable(clk);
+ rate = clk_get_rate(clk);
+ writel(0, base + TIMER_CTRL);
+
+ err = of_property_read_string(of_aliases,
+ "arm,timer-primary", &path);
+ if (WARN_ON(err))
+ return;
+ pri_node = of_find_node_by_path(path);
+ err = of_property_read_string(of_aliases,
+ "arm,timer-secondary", &path);
+ if (WARN_ON(err))
+ return;
+ sec_node = of_find_node_by_path(path);
+
+ if (node == pri_node) {
+ /* The primary timer lacks IRQ, use as clocksource */
+ integrator_clocksource_init(rate, base);
+ return;
+ }
+
+ if (node == sec_node) {
+ /* The secondary timer will drive the clock event */
+ irq = irq_of_parse_and_map(node, 0);
+ integrator_clockevent_init(rate, base, irq);
+ return;
+ }
+
+ pr_info("Timer @%p unused\n", base);
+ clk_disable_unprepare(clk);
+}
+
+CLOCKSOURCE_OF_DECLARE(integrator_ap_timer, "arm,integrator-timer",
+ integrator_ap_timer_init_of);
diff --git a/drivers/clocksource/timer-marco.c b/drivers/clocksource/timer-marco.c
index caf7a20..361a789 100644
--- a/drivers/clocksource/timer-marco.c
+++ b/drivers/clocksource/timer-marco.c
@@ -20,8 +20,6 @@
#include <linux/of_address.h>
#include <linux/sched_clock.h>
-#define MARCO_CLOCK_FREQ 1000000
-
#define SIRFSOC_TIMER_32COUNTER_0_CTRL 0x0000
#define SIRFSOC_TIMER_32COUNTER_1_CTRL 0x0004
#define SIRFSOC_TIMER_MATCH_0 0x0018
@@ -40,6 +38,8 @@
#define SIRFSOC_TIMER_REG_CNT 6
+static unsigned long marco_timer_rate;
+
static const u32 sirfsoc_timer_reg_list[SIRFSOC_TIMER_REG_CNT] = {
SIRFSOC_TIMER_WATCHDOG_EN,
SIRFSOC_TIMER_32COUNTER_0_CTRL,
@@ -195,7 +195,7 @@ static int sirfsoc_local_timer_setup(struct clock_event_device *ce)
ce->rating = 200;
ce->set_mode = sirfsoc_timer_set_mode;
ce->set_next_event = sirfsoc_timer_set_next_event;
- clockevents_calc_mult_shift(ce, MARCO_CLOCK_FREQ, 60);
+ clockevents_calc_mult_shift(ce, marco_timer_rate, 60);
ce->max_delta_ns = clockevent_delta2ns(-2, ce);
ce->min_delta_ns = clockevent_delta2ns(2, ce);
ce->cpumask = cpumask_of(cpu);
@@ -257,7 +257,6 @@ static void __init sirfsoc_clockevent_init(void)
/* initialize the kernel jiffy timer source */
static void __init sirfsoc_marco_timer_init(struct device_node *np)
{
- unsigned long rate;
u32 timer_div;
struct clk *clk;
@@ -266,16 +265,12 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np)
BUG_ON(clk_prepare_enable(clk));
- rate = clk_get_rate(clk);
-
- BUG_ON(rate < MARCO_CLOCK_FREQ);
- BUG_ON(rate % MARCO_CLOCK_FREQ);
+ marco_timer_rate = clk_get_rate(clk);
- /* Initialize the timer dividers */
- timer_div = rate / MARCO_CLOCK_FREQ - 1;
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
- writel_relaxed(timer_div << 16, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
+ /* timer dividers: 0, not divided */
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_CTRL);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_0_CTRL);
+ writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_32COUNTER_1_CTRL);
/* Initialize timer counters to 0 */
writel_relaxed(0, sirfsoc_timer_base + SIRFSOC_TIMER_64COUNTER_LOAD_LO);
@@ -288,7 +283,7 @@ static void __init sirfsoc_marco_timer_init(struct device_node *np)
/* Clear all interrupts */
writel_relaxed(0xFFFF, sirfsoc_timer_base + SIRFSOC_TIMER_INTR_STATUS);
- BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, MARCO_CLOCK_FREQ));
+ BUG_ON(clocksource_register_hz(&sirfsoc_clocksource, marco_timer_rate));
sirfsoc_clockevent_init();
}
diff --git a/drivers/cpufreq/Kconfig b/drivers/cpufreq/Kconfig
index 3489f8f..29b2ef5 100644
--- a/drivers/cpufreq/Kconfig
+++ b/drivers/cpufreq/Kconfig
@@ -63,7 +63,6 @@ config CPU_FREQ_DEFAULT_GOV_PERFORMANCE
config CPU_FREQ_DEFAULT_GOV_POWERSAVE
bool "powersave"
- depends on EXPERT
select CPU_FREQ_GOV_POWERSAVE
help
Use the CPUFreq governor 'powersave' as default. This sets
@@ -183,6 +182,8 @@ config CPU_FREQ_GOV_CONSERVATIVE
If in doubt, say N.
+comment "CPU frequency scaling drivers"
+
config CPUFREQ_DT
tristate "Generic DT based cpufreq driver"
depends on HAVE_CLK && OF
@@ -196,19 +197,19 @@ config CPUFREQ_DT
If in doubt, say N.
-menu "x86 CPU frequency scaling drivers"
-depends on X86
+if X86
source "drivers/cpufreq/Kconfig.x86"
-endmenu
+endif
-menu "ARM CPU frequency scaling drivers"
-depends on ARM || ARM64
+if ARM || ARM64
source "drivers/cpufreq/Kconfig.arm"
-endmenu
+endif
-menu "AVR32 CPU frequency scaling drivers"
-depends on AVR32
+if PPC32 || PPC64
+source "drivers/cpufreq/Kconfig.powerpc"
+endif
+if AVR32
config AVR32_AT32AP_CPUFREQ
bool "CPU frequency driver for AT32AP"
depends on PLATFORM_AT32AP
@@ -216,12 +217,9 @@ config AVR32_AT32AP_CPUFREQ
help
This enables the CPU frequency driver for AT32AP processors.
If in doubt, say N.
+endif
-endmenu
-
-menu "CPUFreq processor drivers"
-depends on IA64
-
+if IA64
config IA64_ACPI_CPUFREQ
tristate "ACPI Processor P-States driver"
depends on ACPI_PROCESSOR
@@ -232,12 +230,9 @@ config IA64_ACPI_CPUFREQ
For details, take a look at <file:Documentation/cpu-freq/>.
If in doubt, say N.
+endif
-endmenu
-
-menu "MIPS CPUFreq processor drivers"
-depends on MIPS
-
+if MIPS
config LOONGSON2_CPUFREQ
tristate "Loongson2 CPUFreq Driver"
help
@@ -250,15 +245,18 @@ config LOONGSON2_CPUFREQ
If in doubt, say N.
-endmenu
+config LOONGSON1_CPUFREQ
+ tristate "Loongson1 CPUFreq Driver"
+ help
+ This option adds a CPUFreq driver for loongson1 processors which
+ support software configurable cpu frequency.
-menu "PowerPC CPU frequency scaling drivers"
-depends on PPC32 || PPC64
-source "drivers/cpufreq/Kconfig.powerpc"
-endmenu
+ For details, take a look at <file:Documentation/cpu-freq/>.
-menu "SPARC CPU frequency scaling drivers"
-depends on SPARC64
+ If in doubt, say N.
+endif
+
+if SPARC64
config SPARC_US3_CPUFREQ
tristate "UltraSPARC-III CPU Frequency driver"
help
@@ -276,10 +274,9 @@ config SPARC_US2E_CPUFREQ
For details, take a look at <file:Documentation/cpu-freq>.
If in doubt, say N.
-endmenu
+endif
-menu "SH CPU Frequency scaling"
-depends on SUPERH
+if SUPERH
config SH_CPU_FREQ
tristate "SuperH CPU Frequency driver"
help
@@ -293,7 +290,7 @@ config SH_CPU_FREQ
For details, take a look at <file:Documentation/cpu-freq>.
If unsure, say N.
-endmenu
+endif
endif
endmenu
diff --git a/drivers/cpufreq/Kconfig.arm b/drivers/cpufreq/Kconfig.arm
index 83a75dc..0f9a2c3 100644
--- a/drivers/cpufreq/Kconfig.arm
+++ b/drivers/cpufreq/Kconfig.arm
@@ -247,3 +247,11 @@ config ARM_TEGRA_CPUFREQ
default y
help
This adds the CPUFreq driver support for TEGRA SOCs.
+
+config ARM_PXA2xx_CPUFREQ
+ tristate "Intel PXA2xx CPUfreq driver"
+ depends on PXA27x || PXA25x
+ help
+ This add the CPUFreq driver support for Intel PXA2xx SOCs.
+
+ If in doubt, say N.
diff --git a/drivers/cpufreq/Makefile b/drivers/cpufreq/Makefile
index 40c53dc..b3ca7b0 100644
--- a/drivers/cpufreq/Makefile
+++ b/drivers/cpufreq/Makefile
@@ -61,8 +61,7 @@ obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
-obj-$(CONFIG_PXA25x) += pxa2xx-cpufreq.o
-obj-$(CONFIG_PXA27x) += pxa2xx-cpufreq.o
+obj-$(CONFIG_ARM_PXA2xx_CPUFREQ) += pxa2xx-cpufreq.o
obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o
obj-$(CONFIG_ARM_S3C24XX_CPUFREQ) += s3c24xx-cpufreq.o
obj-$(CONFIG_ARM_S3C24XX_CPUFREQ_DEBUGFS) += s3c24xx-cpufreq-debugfs.o
@@ -98,6 +97,7 @@ 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
obj-$(CONFIG_LOONGSON2_CPUFREQ) += loongson2_cpufreq.o
+obj-$(CONFIG_LOONGSON1_CPUFREQ) += ls1x-cpufreq.o
obj-$(CONFIG_SH_CPU_FREQ) += sh-cpufreq.o
obj-$(CONFIG_SPARC_US2E_CPUFREQ) += sparc-us2e-cpufreq.o
obj-$(CONFIG_SPARC_US3_CPUFREQ) += sparc-us3-cpufreq.o
diff --git a/drivers/cpufreq/arm_big_little.c b/drivers/cpufreq/arm_big_little.c
index a46c223..e1a6ba6 100644
--- a/drivers/cpufreq/arm_big_little.c
+++ b/drivers/cpufreq/arm_big_little.c
@@ -289,6 +289,8 @@ static void _put_cluster_clk_and_freq_table(struct device *cpu_dev)
clk_put(clk[cluster]);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+ if (arm_bL_ops->free_opp_table)
+ arm_bL_ops->free_opp_table(cpu_dev);
dev_dbg(cpu_dev, "%s: cluster: %d\n", __func__, cluster);
}
@@ -337,7 +339,7 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
if (ret) {
dev_err(cpu_dev, "%s: failed to init cpufreq table, cpu: %d, err: %d\n",
__func__, cpu_dev->id, ret);
- goto out;
+ goto free_opp_table;
}
name[12] = cluster + '0';
@@ -354,6 +356,9 @@ static int _get_cluster_clk_and_freq_table(struct device *cpu_dev)
ret = PTR_ERR(clk[cluster]);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table[cluster]);
+free_opp_table:
+ if (arm_bL_ops->free_opp_table)
+ arm_bL_ops->free_opp_table(cpu_dev);
out:
dev_err(cpu_dev, "%s: Failed to get data for cluster: %d\n", __func__,
cluster);
diff --git a/drivers/cpufreq/arm_big_little.h b/drivers/cpufreq/arm_big_little.h
index 70f18fc..a211f7d 100644
--- a/drivers/cpufreq/arm_big_little.h
+++ b/drivers/cpufreq/arm_big_little.h
@@ -25,13 +25,16 @@
struct cpufreq_arm_bL_ops {
char name[CPUFREQ_NAME_LEN];
- int (*get_transition_latency)(struct device *cpu_dev);
/*
* This must set opp table for cpu_dev in a similar way as done by
* of_init_opp_table().
*/
int (*init_opp_table)(struct device *cpu_dev);
+
+ /* Optional */
+ int (*get_transition_latency)(struct device *cpu_dev);
+ void (*free_opp_table)(struct device *cpu_dev);
};
int bL_cpufreq_register(struct cpufreq_arm_bL_ops *ops);
diff --git a/drivers/cpufreq/arm_big_little_dt.c b/drivers/cpufreq/arm_big_little_dt.c
index 4550f69..ef0b3f1 100644
--- a/drivers/cpufreq/arm_big_little_dt.c
+++ b/drivers/cpufreq/arm_big_little_dt.c
@@ -82,6 +82,7 @@ static struct cpufreq_arm_bL_ops dt_bL_ops = {
.name = "dt-bl",
.get_transition_latency = dt_get_transition_latency,
.init_opp_table = dt_init_opp_table,
+ .free_opp_table = of_free_opp_table,
};
static int generic_bL_probe(struct platform_device *pdev)
diff --git a/drivers/cpufreq/cpufreq-dt.c b/drivers/cpufreq/cpufreq-dt.c
index f657c57..9bc2720 100644
--- a/drivers/cpufreq/cpufreq-dt.c
+++ b/drivers/cpufreq/cpufreq-dt.c
@@ -58,6 +58,8 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
old_freq = clk_get_rate(cpu_clk) / 1000;
if (!IS_ERR(cpu_reg)) {
+ unsigned long opp_freq;
+
rcu_read_lock();
opp = dev_pm_opp_find_freq_ceil(cpu_dev, &freq_Hz);
if (IS_ERR(opp)) {
@@ -67,13 +69,16 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
return PTR_ERR(opp);
}
volt = dev_pm_opp_get_voltage(opp);
+ opp_freq = dev_pm_opp_get_freq(opp);
rcu_read_unlock();
tol = volt * priv->voltage_tolerance / 100;
volt_old = regulator_get_voltage(cpu_reg);
+ dev_dbg(cpu_dev, "Found OPP: %ld kHz, %ld uV\n",
+ opp_freq / 1000, volt);
}
dev_dbg(cpu_dev, "%u MHz, %ld mV --> %u MHz, %ld mV\n",
- old_freq / 1000, volt_old ? volt_old / 1000 : -1,
+ old_freq / 1000, (volt_old > 0) ? volt_old / 1000 : -1,
new_freq / 1000, volt ? volt / 1000 : -1);
/* scaling up? scale voltage before frequency */
@@ -89,7 +94,7 @@ static int set_target(struct cpufreq_policy *policy, unsigned int index)
ret = clk_set_rate(cpu_clk, freq_exact);
if (ret) {
dev_err(cpu_dev, "failed to set clock rate: %d\n", ret);
- if (!IS_ERR(cpu_reg))
+ if (!IS_ERR(cpu_reg) && volt_old > 0)
regulator_set_voltage_tol(cpu_reg, volt_old, tol);
return ret;
}
@@ -181,7 +186,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
{
struct cpufreq_dt_platform_data *pd;
struct cpufreq_frequency_table *freq_table;
- struct thermal_cooling_device *cdev;
struct device_node *np;
struct private_data *priv;
struct device *cpu_dev;
@@ -210,7 +214,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
priv = kzalloc(sizeof(*priv), GFP_KERNEL);
if (!priv) {
ret = -ENOMEM;
- goto out_put_node;
+ goto out_free_opp;
}
of_property_read_u32(np, "voltage-tolerance", &priv->voltage_tolerance);
@@ -264,20 +268,6 @@ static int cpufreq_init(struct cpufreq_policy *policy)
goto out_free_priv;
}
- /*
- * For now, just loading the cooling device;
- * thermal DT code takes care of matching them.
- */
- if (of_find_property(np, "#cooling-cells", NULL)) {
- cdev = of_cpufreq_cooling_register(np, cpu_present_mask);
- if (IS_ERR(cdev))
- dev_err(cpu_dev,
- "running cpufreq without cooling device: %ld\n",
- PTR_ERR(cdev));
- else
- priv->cdev = cdev;
- }
-
priv->cpu_dev = cpu_dev;
priv->cpu_reg = cpu_reg;
policy->driver_data = priv;
@@ -287,7 +277,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
if (ret) {
dev_err(cpu_dev, "%s: invalid frequency table: %d\n", __func__,
ret);
- goto out_cooling_unregister;
+ goto out_free_cpufreq_table;
}
policy->cpuinfo.transition_latency = transition_latency;
@@ -300,12 +290,12 @@ static int cpufreq_init(struct cpufreq_policy *policy)
return 0;
-out_cooling_unregister:
- cpufreq_cooling_unregister(priv->cdev);
+out_free_cpufreq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
out_free_priv:
kfree(priv);
-out_put_node:
+out_free_opp:
+ of_free_opp_table(cpu_dev);
of_node_put(np);
out_put_reg_clk:
clk_put(cpu_clk);
@@ -319,8 +309,10 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
{
struct private_data *priv = policy->driver_data;
- cpufreq_cooling_unregister(priv->cdev);
+ if (priv->cdev)
+ cpufreq_cooling_unregister(priv->cdev);
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
+ of_free_opp_table(priv->cpu_dev);
clk_put(policy->clk);
if (!IS_ERR(priv->cpu_reg))
regulator_put(priv->cpu_reg);
@@ -329,6 +321,33 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
return 0;
}
+static void cpufreq_ready(struct cpufreq_policy *policy)
+{
+ struct private_data *priv = policy->driver_data;
+ struct device_node *np = of_node_get(priv->cpu_dev->of_node);
+
+ if (WARN_ON(!np))
+ return;
+
+ /*
+ * For now, just loading the cooling device;
+ * thermal DT code takes care of matching them.
+ */
+ if (of_find_property(np, "#cooling-cells", NULL)) {
+ priv->cdev = of_cpufreq_cooling_register(np,
+ policy->related_cpus);
+ if (IS_ERR(priv->cdev)) {
+ dev_err(priv->cpu_dev,
+ "running cpufreq without cooling device: %ld\n",
+ PTR_ERR(priv->cdev));
+
+ priv->cdev = NULL;
+ }
+ }
+
+ of_node_put(np);
+}
+
static struct cpufreq_driver dt_cpufreq_driver = {
.flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
.verify = cpufreq_generic_frequency_table_verify,
@@ -336,6 +355,7 @@ static struct cpufreq_driver dt_cpufreq_driver = {
.get = cpufreq_generic_get,
.init = cpufreq_init,
.exit = cpufreq_exit,
+ .ready = cpufreq_ready,
.name = "cpufreq-dt",
.attr = cpufreq_generic_attr,
};
diff --git a/drivers/cpufreq/cpufreq.c b/drivers/cpufreq/cpufreq.c
index 4473eba..a09a29c 100644
--- a/drivers/cpufreq/cpufreq.c
+++ b/drivers/cpufreq/cpufreq.c
@@ -535,7 +535,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
static ssize_t store_##file_name \
(struct cpufreq_policy *policy, const char *buf, size_t count) \
{ \
- int ret; \
+ int ret, temp; \
struct cpufreq_policy new_policy; \
\
ret = cpufreq_get_policy(&new_policy, policy->cpu); \
@@ -546,8 +546,10 @@ static ssize_t store_##file_name \
if (ret != 1) \
return -EINVAL; \
\
+ temp = new_policy.object; \
ret = cpufreq_set_policy(policy, &new_policy); \
- policy->user_policy.object = policy->object; \
+ if (!ret) \
+ policy->user_policy.object = temp; \
\
return ret ? ret : count; \
}
@@ -898,46 +900,31 @@ static int cpufreq_add_dev_interface(struct cpufreq_policy *policy,
struct freq_attr **drv_attr;
int ret = 0;
- /* prepare interface data */
- ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
- &dev->kobj, "cpufreq");
- if (ret)
- return ret;
-
/* set up files for this cpu device */
drv_attr = cpufreq_driver->attr;
while ((drv_attr) && (*drv_attr)) {
ret = sysfs_create_file(&policy->kobj, &((*drv_attr)->attr));
if (ret)
- goto err_out_kobj_put;
+ return ret;
drv_attr++;
}
if (cpufreq_driver->get) {
ret = sysfs_create_file(&policy->kobj, &cpuinfo_cur_freq.attr);
if (ret)
- goto err_out_kobj_put;
+ return ret;
}
ret = sysfs_create_file(&policy->kobj, &scaling_cur_freq.attr);
if (ret)
- goto err_out_kobj_put;
+ return ret;
if (cpufreq_driver->bios_limit) {
ret = sysfs_create_file(&policy->kobj, &bios_limit.attr);
if (ret)
- goto err_out_kobj_put;
+ return ret;
}
- ret = cpufreq_add_dev_symlink(policy);
- if (ret)
- goto err_out_kobj_put;
-
- return ret;
-
-err_out_kobj_put:
- kobject_put(&policy->kobj);
- wait_for_completion(&policy->kobj_unregister);
- return ret;
+ return cpufreq_add_dev_symlink(policy);
}
static void cpufreq_init_policy(struct cpufreq_policy *policy)
@@ -1196,6 +1183,8 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
goto err_set_policy_cpu;
}
+ down_write(&policy->rwsem);
+
/* related cpus should atleast have policy->cpus */
cpumask_or(policy->related_cpus, policy->related_cpus, policy->cpus);
@@ -1208,9 +1197,17 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
if (!recover_policy) {
policy->user_policy.min = policy->min;
policy->user_policy.max = policy->max;
+
+ /* prepare interface data */
+ ret = kobject_init_and_add(&policy->kobj, &ktype_cpufreq,
+ &dev->kobj, "cpufreq");
+ if (ret) {
+ pr_err("%s: failed to init policy->kobj: %d\n",
+ __func__, ret);
+ goto err_init_policy_kobj;
+ }
}
- down_write(&policy->rwsem);
write_lock_irqsave(&cpufreq_driver_lock, flags);
for_each_cpu(j, policy->cpus)
per_cpu(cpufreq_cpu_data, j) = policy;
@@ -1288,8 +1285,13 @@ static int __cpufreq_add_dev(struct device *dev, struct subsys_interface *sif)
up_write(&policy->rwsem);
kobject_uevent(&policy->kobj, KOBJ_ADD);
+
up_read(&cpufreq_rwsem);
+ /* Callback for handling stuff after policy is ready */
+ if (cpufreq_driver->ready)
+ cpufreq_driver->ready(policy);
+
pr_debug("initialization complete\n");
return 0;
@@ -1301,6 +1303,11 @@ err_get_freq:
per_cpu(cpufreq_cpu_data, j) = NULL;
write_unlock_irqrestore(&cpufreq_driver_lock, flags);
+ if (!recover_policy) {
+ kobject_put(&policy->kobj);
+ wait_for_completion(&policy->kobj_unregister);
+ }
+err_init_policy_kobj:
up_write(&policy->rwsem);
if (cpufreq_driver->exit)
diff --git a/drivers/cpufreq/exynos5440-cpufreq.c b/drivers/cpufreq/exynos5440-cpufreq.c
index f33f25b..27a57ed 100644
--- a/drivers/cpufreq/exynos5440-cpufreq.c
+++ b/drivers/cpufreq/exynos5440-cpufreq.c
@@ -371,7 +371,7 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
if (ret) {
dev_err(dvfs_info->dev,
"failed to init cpufreq table: %d\n", ret);
- goto err_put_node;
+ goto err_free_opp;
}
dvfs_info->freq_count = dev_pm_opp_get_opp_count(dvfs_info->dev);
exynos_sort_descend_freq_table();
@@ -423,6 +423,8 @@ static int exynos_cpufreq_probe(struct platform_device *pdev)
err_free_table:
dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+err_free_opp:
+ of_free_opp_table(dvfs_info->dev);
err_put_node:
of_node_put(np);
dev_err(&pdev->dev, "%s: failed initialization\n", __func__);
@@ -433,6 +435,7 @@ static int exynos_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&exynos_driver);
dev_pm_opp_free_cpufreq_table(dvfs_info->dev, &dvfs_info->freq_table);
+ of_free_opp_table(dvfs_info->dev);
return 0;
}
diff --git a/drivers/cpufreq/imx6q-cpufreq.c b/drivers/cpufreq/imx6q-cpufreq.c
index c2d3076..5da1d13 100644
--- a/drivers/cpufreq/imx6q-cpufreq.c
+++ b/drivers/cpufreq/imx6q-cpufreq.c
@@ -31,6 +31,7 @@ static struct clk *step_clk;
static struct clk *pll2_pfd2_396m_clk;
static struct device *cpu_dev;
+static bool free_opp;
static struct cpufreq_frequency_table *freq_table;
static unsigned int transition_latency;
@@ -207,11 +208,14 @@ static int imx6q_cpufreq_probe(struct platform_device *pdev)
goto put_reg;
}
+ /* Because we have added the OPPs here, we must free them */
+ free_opp = true;
+
num = dev_pm_opp_get_opp_count(cpu_dev);
if (num < 0) {
ret = num;
dev_err(cpu_dev, "no OPP table is found: %d\n", ret);
- goto put_reg;
+ goto out_free_opp;
}
}
@@ -306,6 +310,9 @@ soc_opp_out:
free_freq_table:
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+out_free_opp:
+ if (free_opp)
+ of_free_opp_table(cpu_dev);
put_reg:
if (!IS_ERR(arm_reg))
regulator_put(arm_reg);
@@ -332,6 +339,8 @@ static int imx6q_cpufreq_remove(struct platform_device *pdev)
{
cpufreq_unregister_driver(&imx6q_cpufreq_driver);
dev_pm_opp_free_cpufreq_table(cpu_dev, &freq_table);
+ if (free_opp)
+ of_free_opp_table(cpu_dev);
regulator_put(arm_reg);
if (!IS_ERR(pu_reg))
regulator_put(pu_reg);
diff --git a/drivers/cpufreq/intel_pstate.c b/drivers/cpufreq/intel_pstate.c
index 27bb6d3..1405b39 100644
--- a/drivers/cpufreq/intel_pstate.c
+++ b/drivers/cpufreq/intel_pstate.c
@@ -137,6 +137,7 @@ struct cpu_defaults {
static struct pstate_adjust_policy pid_params;
static struct pstate_funcs pstate_funcs;
+static int hwp_active;
struct perf_limits {
int no_turbo;
@@ -244,6 +245,34 @@ static inline void update_turbo_state(void)
cpu->pstate.max_pstate == cpu->pstate.turbo_pstate);
}
+#define PCT_TO_HWP(x) (x * 255 / 100)
+static void intel_pstate_hwp_set(void)
+{
+ int min, max, cpu;
+ u64 value, freq;
+
+ get_online_cpus();
+
+ for_each_online_cpu(cpu) {
+ rdmsrl_on_cpu(cpu, MSR_HWP_REQUEST, &value);
+ min = PCT_TO_HWP(limits.min_perf_pct);
+ value &= ~HWP_MIN_PERF(~0L);
+ value |= HWP_MIN_PERF(min);
+
+ max = PCT_TO_HWP(limits.max_perf_pct);
+ if (limits.no_turbo) {
+ rdmsrl( MSR_HWP_CAPABILITIES, freq);
+ max = HWP_GUARANTEED_PERF(freq);
+ }
+
+ value &= ~HWP_MAX_PERF(~0L);
+ value |= HWP_MAX_PERF(max);
+ wrmsrl_on_cpu(cpu, MSR_HWP_REQUEST, value);
+ }
+
+ put_online_cpus();
+}
+
/************************** debugfs begin ************************/
static int pid_param_set(void *data, u64 val)
{
@@ -279,6 +308,8 @@ static void __init intel_pstate_debug_expose_params(void)
struct dentry *debugfs_parent;
int i = 0;
+ if (hwp_active)
+ return;
debugfs_parent = debugfs_create_dir("pstate_snb", NULL);
if (IS_ERR_OR_NULL(debugfs_parent))
return;
@@ -329,8 +360,12 @@ static ssize_t store_no_turbo(struct kobject *a, struct attribute *b,
pr_warn("Turbo disabled by BIOS or unavailable on processor\n");
return -EPERM;
}
+
limits.no_turbo = clamp_t(int, input, 0, 1);
+ if (hwp_active)
+ intel_pstate_hwp_set();
+
return count;
}
@@ -348,6 +383,8 @@ static ssize_t store_max_perf_pct(struct kobject *a, struct attribute *b,
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+ if (hwp_active)
+ intel_pstate_hwp_set();
return count;
}
@@ -363,6 +400,8 @@ static ssize_t store_min_perf_pct(struct kobject *a, struct attribute *b,
limits.min_perf_pct = clamp_t(int, input, 0 , 100);
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
+ if (hwp_active)
+ intel_pstate_hwp_set();
return count;
}
@@ -395,8 +434,16 @@ static void __init intel_pstate_sysfs_expose_params(void)
rc = sysfs_create_group(intel_pstate_kobject, &intel_pstate_attr_group);
BUG_ON(rc);
}
-
/************************** sysfs end ************************/
+
+static void intel_pstate_hwp_enable(void)
+{
+ hwp_active++;
+ pr_info("intel_pstate HWP enabled\n");
+
+ wrmsrl( MSR_PM_ENABLE, 0x1);
+}
+
static int byt_get_min_pstate(void)
{
u64 value;
@@ -648,6 +695,14 @@ static inline void intel_pstate_sample(struct cpudata *cpu)
cpu->prev_mperf = mperf;
}
+static inline void intel_hwp_set_sample_time(struct cpudata *cpu)
+{
+ int delay;
+
+ delay = msecs_to_jiffies(50);
+ mod_timer_pinned(&cpu->timer, jiffies + delay);
+}
+
static inline void intel_pstate_set_sample_time(struct cpudata *cpu)
{
int delay;
@@ -694,6 +749,14 @@ static inline void intel_pstate_adjust_busy_pstate(struct cpudata *cpu)
intel_pstate_set_pstate(cpu, cpu->pstate.current_pstate - ctl);
}
+static void intel_hwp_timer_func(unsigned long __data)
+{
+ struct cpudata *cpu = (struct cpudata *) __data;
+
+ intel_pstate_sample(cpu);
+ intel_hwp_set_sample_time(cpu);
+}
+
static void intel_pstate_timer_func(unsigned long __data)
{
struct cpudata *cpu = (struct cpudata *) __data;
@@ -730,6 +793,7 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
ICPU(0x3f, core_params),
ICPU(0x45, core_params),
ICPU(0x46, core_params),
+ ICPU(0x47, core_params),
ICPU(0x4c, byt_params),
ICPU(0x4f, core_params),
ICPU(0x56, core_params),
@@ -737,6 +801,11 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = {
};
MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
+static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] = {
+ ICPU(0x56, core_params),
+ {}
+};
+
static int intel_pstate_init_cpu(unsigned int cpunum)
{
struct cpudata *cpu;
@@ -753,9 +822,14 @@ static int intel_pstate_init_cpu(unsigned int cpunum)
intel_pstate_get_cpu_pstates(cpu);
init_timer_deferrable(&cpu->timer);
- cpu->timer.function = intel_pstate_timer_func;
cpu->timer.data = (unsigned long)cpu;
cpu->timer.expires = jiffies + HZ/100;
+
+ if (!hwp_active)
+ cpu->timer.function = intel_pstate_timer_func;
+ else
+ cpu->timer.function = intel_hwp_timer_func;
+
intel_pstate_busy_pid_reset(cpu);
intel_pstate_sample(cpu);
@@ -792,6 +866,7 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits.no_turbo = 0;
return 0;
}
+
limits.min_perf_pct = (policy->min * 100) / policy->cpuinfo.max_freq;
limits.min_perf_pct = clamp_t(int, limits.min_perf_pct, 0 , 100);
limits.min_perf = div_fp(int_tofp(limits.min_perf_pct), int_tofp(100));
@@ -801,6 +876,9 @@ static int intel_pstate_set_policy(struct cpufreq_policy *policy)
limits.max_perf_pct = min(limits.max_policy_pct, limits.max_sysfs_pct);
limits.max_perf = div_fp(int_tofp(limits.max_perf_pct), int_tofp(100));
+ if (hwp_active)
+ intel_pstate_hwp_set();
+
return 0;
}
@@ -823,6 +901,9 @@ static void intel_pstate_stop_cpu(struct cpufreq_policy *policy)
pr_info("intel_pstate CPU %d exiting\n", cpu_num);
del_timer_sync(&all_cpu_data[cpu_num]->timer);
+ if (hwp_active)
+ return;
+
intel_pstate_set_pstate(cpu, cpu->pstate.min_pstate);
}
@@ -866,6 +947,7 @@ static struct cpufreq_driver intel_pstate_driver = {
};
static int __initdata no_load;
+static int __initdata no_hwp;
static int intel_pstate_msrs_not_valid(void)
{
@@ -943,15 +1025,46 @@ static bool intel_pstate_no_acpi_pss(void)
return true;
}
+static bool intel_pstate_has_acpi_ppc(void)
+{
+ int i;
+
+ for_each_possible_cpu(i) {
+ struct acpi_processor *pr = per_cpu(processors, i);
+
+ if (!pr)
+ continue;
+ if (acpi_has_method(pr->handle, "_PPC"))
+ return true;
+ }
+ return false;
+}
+
+enum {
+ PSS,
+ PPC,
+};
+
struct hw_vendor_info {
u16 valid;
char oem_id[ACPI_OEM_ID_SIZE];
char oem_table_id[ACPI_OEM_TABLE_ID_SIZE];
+ int oem_pwr_table;
};
/* Hardware vendor-specific info that has its own power management modes */
static struct hw_vendor_info vendor_info[] = {
- {1, "HP ", "ProLiant"},
+ {1, "HP ", "ProLiant", PSS},
+ {1, "ORACLE", "X4-2 ", PPC},
+ {1, "ORACLE", "X4-2L ", PPC},
+ {1, "ORACLE", "X4-2B ", PPC},
+ {1, "ORACLE", "X3-2 ", PPC},
+ {1, "ORACLE", "X3-2L ", PPC},
+ {1, "ORACLE", "X3-2B ", PPC},
+ {1, "ORACLE", "X4470M2 ", PPC},
+ {1, "ORACLE", "X4270M3 ", PPC},
+ {1, "ORACLE", "X4270M2 ", PPC},
+ {1, "ORACLE", "X4170M2 ", PPC},
{0, "", ""},
};
@@ -959,6 +1072,15 @@ static bool intel_pstate_platform_pwr_mgmt_exists(void)
{
struct acpi_table_header hdr;
struct hw_vendor_info *v_info;
+ const struct x86_cpu_id *id;
+ u64 misc_pwr;
+
+ id = x86_match_cpu(intel_pstate_cpu_oob_ids);
+ if (id) {
+ rdmsrl(MSR_MISC_PWR_MGMT, misc_pwr);
+ if ( misc_pwr & (1 << 8))
+ return true;
+ }
if (acpi_disabled ||
ACPI_FAILURE(acpi_get_table_header(ACPI_SIG_FADT, 0, &hdr)))
@@ -966,15 +1088,21 @@ static bool intel_pstate_platform_pwr_mgmt_exists(void)
for (v_info = vendor_info; v_info->valid; v_info++) {
if (!strncmp(hdr.oem_id, v_info->oem_id, ACPI_OEM_ID_SIZE) &&
- !strncmp(hdr.oem_table_id, v_info->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
- intel_pstate_no_acpi_pss())
- return true;
+ !strncmp(hdr.oem_table_id, v_info->oem_table_id,
+ ACPI_OEM_TABLE_ID_SIZE))
+ switch (v_info->oem_pwr_table) {
+ case PSS:
+ return intel_pstate_no_acpi_pss();
+ case PPC:
+ return intel_pstate_has_acpi_ppc();
+ }
}
return false;
}
#else /* CONFIG_ACPI not enabled */
static inline bool intel_pstate_platform_pwr_mgmt_exists(void) { return false; }
+static inline bool intel_pstate_has_acpi_ppc(void) { return false; }
#endif /* CONFIG_ACPI */
static int __init intel_pstate_init(void)
@@ -982,6 +1110,7 @@ static int __init intel_pstate_init(void)
int cpu, rc = 0;
const struct x86_cpu_id *id;
struct cpu_defaults *cpu_info;
+ struct cpuinfo_x86 *c = &boot_cpu_data;
if (no_load)
return -ENODEV;
@@ -1011,6 +1140,9 @@ static int __init intel_pstate_init(void)
if (!all_cpu_data)
return -ENOMEM;
+ if (cpu_has(c,X86_FEATURE_HWP) && !no_hwp)
+ intel_pstate_hwp_enable();
+
rc = cpufreq_register_driver(&intel_pstate_driver);
if (rc)
goto out;
@@ -1041,6 +1173,8 @@ static int __init intel_pstate_setup(char *str)
if (!strcmp(str, "disable"))
no_load = 1;
+ if (!strcmp(str, "no_hwp"))
+ no_hwp = 1;
return 0;
}
early_param("intel_pstate", intel_pstate_setup);
diff --git a/drivers/cpufreq/ls1x-cpufreq.c b/drivers/cpufreq/ls1x-cpufreq.c
new file mode 100644
index 0000000..25fbd6a1
--- /dev/null
+++ b/drivers/cpufreq/ls1x-cpufreq.c
@@ -0,0 +1,223 @@
+/*
+ * CPU Frequency Scaling for Loongson 1 SoC
+ *
+ * Copyright (C) 2014 Zhang, Keguang <keguang.zhang@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/clk.h>
+#include <linux/clk-provider.h>
+#include <linux/cpu.h>
+#include <linux/cpufreq.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include <asm/mach-loongson1/cpufreq.h>
+#include <asm/mach-loongson1/loongson1.h>
+
+static struct {
+ struct device *dev;
+ struct clk *clk; /* CPU clk */
+ struct clk *mux_clk; /* MUX of CPU clk */
+ struct clk *pll_clk; /* PLL clk */
+ struct clk *osc_clk; /* OSC clk */
+ unsigned int max_freq;
+ unsigned int min_freq;
+} ls1x_cpufreq;
+
+static int ls1x_cpufreq_notifier(struct notifier_block *nb,
+ unsigned long val, void *data)
+{
+ if (val == CPUFREQ_POSTCHANGE)
+ current_cpu_data.udelay_val = loops_per_jiffy;
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block ls1x_cpufreq_notifier_block = {
+ .notifier_call = ls1x_cpufreq_notifier
+};
+
+static int ls1x_cpufreq_target(struct cpufreq_policy *policy,
+ unsigned int index)
+{
+ unsigned int old_freq, new_freq;
+
+ old_freq = policy->cur;
+ new_freq = policy->freq_table[index].frequency;
+
+ /*
+ * The procedure of reconfiguring CPU clk is as below.
+ *
+ * - Reparent CPU clk to OSC clk
+ * - Reset CPU clock (very important)
+ * - Reconfigure CPU DIV
+ * - Reparent CPU clk back to CPU DIV clk
+ */
+
+ dev_dbg(ls1x_cpufreq.dev, "%u KHz --> %u KHz\n", old_freq, new_freq);
+ clk_set_parent(policy->clk, ls1x_cpufreq.osc_clk);
+ __raw_writel(__raw_readl(LS1X_CLK_PLL_DIV) | RST_CPU_EN | RST_CPU,
+ LS1X_CLK_PLL_DIV);
+ __raw_writel(__raw_readl(LS1X_CLK_PLL_DIV) & ~(RST_CPU_EN | RST_CPU),
+ LS1X_CLK_PLL_DIV);
+ clk_set_rate(ls1x_cpufreq.mux_clk, new_freq * 1000);
+ clk_set_parent(policy->clk, ls1x_cpufreq.mux_clk);
+
+ return 0;
+}
+
+static int ls1x_cpufreq_init(struct cpufreq_policy *policy)
+{
+ struct cpufreq_frequency_table *freq_tbl;
+ unsigned int pll_freq, freq;
+ int steps, i, ret;
+
+ pll_freq = clk_get_rate(ls1x_cpufreq.pll_clk) / 1000;
+
+ steps = 1 << DIV_CPU_WIDTH;
+ freq_tbl = kzalloc(sizeof(*freq_tbl) * steps, GFP_KERNEL);
+ if (!freq_tbl) {
+ dev_err(ls1x_cpufreq.dev,
+ "failed to alloc cpufreq_frequency_table\n");
+ ret = -ENOMEM;
+ goto out;
+ }
+
+ for (i = 0; i < (steps - 1); i++) {
+ freq = pll_freq / (i + 1);
+ if ((freq < ls1x_cpufreq.min_freq) ||
+ (freq > ls1x_cpufreq.max_freq))
+ freq_tbl[i].frequency = CPUFREQ_ENTRY_INVALID;
+ else
+ freq_tbl[i].frequency = freq;
+ dev_dbg(ls1x_cpufreq.dev,
+ "cpufreq table: index %d: frequency %d\n", i,
+ freq_tbl[i].frequency);
+ }
+ freq_tbl[i].frequency = CPUFREQ_TABLE_END;
+
+ policy->clk = ls1x_cpufreq.clk;
+ ret = cpufreq_generic_init(policy, freq_tbl, 0);
+ if (ret)
+ kfree(freq_tbl);
+out:
+ return ret;
+}
+
+static int ls1x_cpufreq_exit(struct cpufreq_policy *policy)
+{
+ kfree(policy->freq_table);
+ return 0;
+}
+
+static struct cpufreq_driver ls1x_cpufreq_driver = {
+ .name = "cpufreq-ls1x",
+ .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
+ .verify = cpufreq_generic_frequency_table_verify,
+ .target_index = ls1x_cpufreq_target,
+ .get = cpufreq_generic_get,
+ .init = ls1x_cpufreq_init,
+ .exit = ls1x_cpufreq_exit,
+ .attr = cpufreq_generic_attr,
+};
+
+static int ls1x_cpufreq_remove(struct platform_device *pdev)
+{
+ cpufreq_unregister_notifier(&ls1x_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+ cpufreq_unregister_driver(&ls1x_cpufreq_driver);
+
+ return 0;
+}
+
+static int ls1x_cpufreq_probe(struct platform_device *pdev)
+{
+ struct plat_ls1x_cpufreq *pdata = pdev->dev.platform_data;
+ struct clk *clk;
+ int ret;
+
+ if (!pdata || !pdata->clk_name || !pdata->osc_clk_name)
+ return -EINVAL;
+
+ ls1x_cpufreq.dev = &pdev->dev;
+
+ clk = devm_clk_get(&pdev->dev, pdata->clk_name);
+ if (IS_ERR(clk)) {
+ dev_err(ls1x_cpufreq.dev, "unable to get %s clock\n",
+ pdata->clk_name);
+ ret = PTR_ERR(clk);
+ goto out;
+ }
+ ls1x_cpufreq.clk = clk;
+
+ clk = clk_get_parent(clk);
+ if (IS_ERR(clk)) {
+ dev_err(ls1x_cpufreq.dev, "unable to get parent of %s clock\n",
+ __clk_get_name(ls1x_cpufreq.clk));
+ ret = PTR_ERR(clk);
+ goto out;
+ }
+ ls1x_cpufreq.mux_clk = clk;
+
+ clk = clk_get_parent(clk);
+ if (IS_ERR(clk)) {
+ dev_err(ls1x_cpufreq.dev, "unable to get parent of %s clock\n",
+ __clk_get_name(ls1x_cpufreq.mux_clk));
+ ret = PTR_ERR(clk);
+ goto out;
+ }
+ ls1x_cpufreq.pll_clk = clk;
+
+ clk = devm_clk_get(&pdev->dev, pdata->osc_clk_name);
+ if (IS_ERR(clk)) {
+ dev_err(ls1x_cpufreq.dev, "unable to get %s clock\n",
+ pdata->osc_clk_name);
+ ret = PTR_ERR(clk);
+ goto out;
+ }
+ ls1x_cpufreq.osc_clk = clk;
+
+ ls1x_cpufreq.max_freq = pdata->max_freq;
+ ls1x_cpufreq.min_freq = pdata->min_freq;
+
+ ret = cpufreq_register_driver(&ls1x_cpufreq_driver);
+ if (ret) {
+ dev_err(ls1x_cpufreq.dev,
+ "failed to register cpufreq driver: %d\n", ret);
+ goto out;
+ }
+
+ ret = cpufreq_register_notifier(&ls1x_cpufreq_notifier_block,
+ CPUFREQ_TRANSITION_NOTIFIER);
+
+ if (!ret)
+ goto out;
+
+ dev_err(ls1x_cpufreq.dev, "failed to register cpufreq notifier: %d\n",
+ ret);
+
+ cpufreq_unregister_driver(&ls1x_cpufreq_driver);
+out:
+ return ret;
+}
+
+static struct platform_driver ls1x_cpufreq_platdrv = {
+ .driver = {
+ .name = "ls1x-cpufreq",
+ .owner = THIS_MODULE,
+ },
+ .probe = ls1x_cpufreq_probe,
+ .remove = ls1x_cpufreq_remove,
+};
+
+module_platform_driver(ls1x_cpufreq_platdrv);
+
+MODULE_AUTHOR("Kelvin Cheung <keguang.zhang@gmail.com>");
+MODULE_DESCRIPTION("Loongson 1 CPUFreq driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/cpufreq/pcc-cpufreq.c b/drivers/cpufreq/pcc-cpufreq.c
index 4d2c8e8..2a0d589 100644
--- a/drivers/cpufreq/pcc-cpufreq.c
+++ b/drivers/cpufreq/pcc-cpufreq.c
@@ -603,6 +603,13 @@ static void __exit pcc_cpufreq_exit(void)
free_percpu(pcc_cpu_info);
}
+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_AUTHOR("Matthew Garrett, Naga Chumbalkar");
MODULE_VERSION(PCC_VERSION);
MODULE_DESCRIPTION("Processor Clocking Control interface driver");
diff --git a/drivers/cpuidle/cpuidle-arm64.c b/drivers/cpuidle/cpuidle-arm64.c
index 50997ea..80704b9 100644
--- a/drivers/cpuidle/cpuidle-arm64.c
+++ b/drivers/cpuidle/cpuidle-arm64.c
@@ -73,7 +73,6 @@ static struct cpuidle_driver arm64_idle_driver = {
.exit_latency = 1,
.target_residency = 1,
.power_usage = UINT_MAX,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "WFI",
.desc = "ARM64 WFI",
}
@@ -104,11 +103,8 @@ static int __init arm64_idle_init(void)
* reason to initialize the idle driver if only wfi is supported.
*/
ret = dt_init_idle_driver(drv, arm64_idle_state_match, 1);
- if (ret <= 0) {
- if (ret)
- pr_err("failed to initialize idle states\n");
+ if (ret <= 0)
return ret ? : -ENODEV;
- }
/*
* Call arch CPU operations in order to initialize
@@ -122,12 +118,6 @@ static int __init arm64_idle_init(void)
}
}
- ret = cpuidle_register(drv, NULL);
- if (ret) {
- pr_err("failed to register cpuidle driver\n");
- return ret;
- }
-
- return 0;
+ return cpuidle_register(drv, NULL);
}
device_initcall(arm64_idle_init);
diff --git a/drivers/cpuidle/cpuidle-at91.c b/drivers/cpuidle/cpuidle-at91.c
index a077437..1964ff0 100644
--- a/drivers/cpuidle/cpuidle-at91.c
+++ b/drivers/cpuidle/cpuidle-at91.c
@@ -43,7 +43,6 @@ static struct cpuidle_driver at91_idle_driver = {
.enter = at91_enter_idle,
.exit_latency = 10,
.target_residency = 10000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "RAM_SR",
.desc = "WFI and DDR Self Refresh",
},
diff --git a/drivers/cpuidle/cpuidle-big_little.c b/drivers/cpuidle/cpuidle-big_little.c
index fbc00a1..e3e225f 100644
--- a/drivers/cpuidle/cpuidle-big_little.c
+++ b/drivers/cpuidle/cpuidle-big_little.c
@@ -67,8 +67,7 @@ static struct cpuidle_driver bl_idle_little_driver = {
.enter = bl_enter_powerdown,
.exit_latency = 700,
.target_residency = 2500,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.name = "C1",
.desc = "ARM little-cluster power down",
},
@@ -89,8 +88,7 @@ static struct cpuidle_driver bl_idle_big_driver = {
.enter = bl_enter_powerdown,
.exit_latency = 500,
.target_residency = 2000,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.name = "C1",
.desc = "ARM big-cluster power down",
},
diff --git a/drivers/cpuidle/cpuidle-calxeda.c b/drivers/cpuidle/cpuidle-calxeda.c
index 6e51114..6541b0b 100644
--- a/drivers/cpuidle/cpuidle-calxeda.c
+++ b/drivers/cpuidle/cpuidle-calxeda.c
@@ -55,7 +55,6 @@ static struct cpuidle_driver calxeda_idle_driver = {
{
.name = "PG",
.desc = "Power Gate",
- .flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 30,
.power_usage = 50,
.target_residency = 200,
diff --git a/drivers/cpuidle/cpuidle-cps.c b/drivers/cpuidle/cpuidle-cps.c
index fc7b627..1adb698 100644
--- a/drivers/cpuidle/cpuidle-cps.c
+++ b/drivers/cpuidle/cpuidle-cps.c
@@ -79,7 +79,6 @@ static struct cpuidle_driver cps_driver = {
.enter = cps_nc_enter,
.exit_latency = 200,
.target_residency = 450,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "nc-wait",
.desc = "non-coherent MIPS wait",
},
@@ -87,8 +86,7 @@ static struct cpuidle_driver cps_driver = {
.enter = cps_nc_enter,
.exit_latency = 300,
.target_residency = 700,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.name = "clock-gated",
.desc = "core clock gated",
},
@@ -96,8 +94,7 @@ static struct cpuidle_driver cps_driver = {
.enter = cps_nc_enter,
.exit_latency = 600,
.target_residency = 1000,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.name = "power-gated",
.desc = "core power gated",
},
diff --git a/drivers/cpuidle/cpuidle-exynos.c b/drivers/cpuidle/cpuidle-exynos.c
index ba9b34b..64d12a8 100644
--- a/drivers/cpuidle/cpuidle-exynos.c
+++ b/drivers/cpuidle/cpuidle-exynos.c
@@ -47,7 +47,6 @@ static struct cpuidle_driver exynos_idle_driver = {
.enter = exynos_enter_lowpower,
.exit_latency = 300,
.target_residency = 100000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "C1",
.desc = "ARM power down",
},
diff --git a/drivers/cpuidle/cpuidle-kirkwood.c b/drivers/cpuidle/cpuidle-kirkwood.c
index 41ba843..d88f8d7 100644
--- a/drivers/cpuidle/cpuidle-kirkwood.c
+++ b/drivers/cpuidle/cpuidle-kirkwood.c
@@ -47,7 +47,6 @@ static struct cpuidle_driver kirkwood_idle_driver = {
.enter = kirkwood_enter_idle,
.exit_latency = 10,
.target_residency = 100000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "DDR SR",
.desc = "WFI and DDR Self Refresh",
},
diff --git a/drivers/cpuidle/cpuidle-mvebu-v7.c b/drivers/cpuidle/cpuidle-mvebu-v7.c
index 45371bb..dd4c176 100644
--- a/drivers/cpuidle/cpuidle-mvebu-v7.c
+++ b/drivers/cpuidle/cpuidle-mvebu-v7.c
@@ -53,7 +53,6 @@ static struct cpuidle_driver armadaxp_idle_driver = {
.exit_latency = 10,
.power_usage = 50,
.target_residency = 100,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "MV CPU IDLE",
.desc = "CPU power down",
},
@@ -62,8 +61,7 @@ static struct cpuidle_driver armadaxp_idle_driver = {
.exit_latency = 100,
.power_usage = 5,
.target_residency = 1000,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- MVEBU_V7_FLAG_DEEP_IDLE,
+ .flags = MVEBU_V7_FLAG_DEEP_IDLE,
.name = "MV CPU DEEP IDLE",
.desc = "CPU and L2 Fabric power down",
},
@@ -78,8 +76,7 @@ static struct cpuidle_driver armada370_idle_driver = {
.exit_latency = 100,
.power_usage = 5,
.target_residency = 1000,
- .flags = (CPUIDLE_FLAG_TIME_VALID |
- MVEBU_V7_FLAG_DEEP_IDLE),
+ .flags = MVEBU_V7_FLAG_DEEP_IDLE,
.name = "Deep Idle",
.desc = "CPU and L2 Fabric power down",
},
@@ -94,7 +91,6 @@ static struct cpuidle_driver armada38x_idle_driver = {
.exit_latency = 10,
.power_usage = 5,
.target_residency = 100,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "Idle",
.desc = "CPU and SCU power down",
},
diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
index 7d3a349..e9248bb 100644
--- a/drivers/cpuidle/cpuidle-powernv.c
+++ b/drivers/cpuidle/cpuidle-powernv.c
@@ -93,7 +93,6 @@ static struct cpuidle_state powernv_states[MAX_POWERNV_IDLE_STATES] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
- .flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 0,
.target_residency = 0,
.enter = &snooze_loop },
@@ -202,7 +201,7 @@ static int powernv_add_idle_states(void)
/* Add NAP state */
strcpy(powernv_states[nr_idle_states].name, "Nap");
strcpy(powernv_states[nr_idle_states].desc, "Nap");
- powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
+ powernv_states[nr_idle_states].flags = 0;
powernv_states[nr_idle_states].exit_latency =
((unsigned int)latency_ns) / 1000;
powernv_states[nr_idle_states].target_residency =
@@ -215,8 +214,7 @@ static int powernv_add_idle_states(void)
/* Add FASTSLEEP state */
strcpy(powernv_states[nr_idle_states].name, "FastSleep");
strcpy(powernv_states[nr_idle_states].desc, "FastSleep");
- powernv_states[nr_idle_states].flags =
- CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
+ powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP;
powernv_states[nr_idle_states].exit_latency =
((unsigned int)latency_ns) / 1000;
powernv_states[nr_idle_states].target_residency =
diff --git a/drivers/cpuidle/cpuidle-pseries.c b/drivers/cpuidle/cpuidle-pseries.c
index 6f7b019..bb9e2b6 100644
--- a/drivers/cpuidle/cpuidle-pseries.c
+++ b/drivers/cpuidle/cpuidle-pseries.c
@@ -142,14 +142,12 @@ static struct cpuidle_state dedicated_states[] = {
{ /* Snooze */
.name = "snooze",
.desc = "snooze",
- .flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 0,
.target_residency = 0,
.enter = &snooze_loop },
{ /* CEDE */
.name = "CEDE",
.desc = "CEDE",
- .flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 10,
.target_residency = 100,
.enter = &dedicated_cede_loop },
@@ -162,7 +160,6 @@ static struct cpuidle_state shared_states[] = {
{ /* Shared Cede */
.name = "Shared Cede",
.desc = "Shared Cede",
- .flags = CPUIDLE_FLAG_TIME_VALID,
.exit_latency = 0,
.target_residency = 0,
.enter = &shared_cede_loop },
diff --git a/drivers/cpuidle/cpuidle-ux500.c b/drivers/cpuidle/cpuidle-ux500.c
index 5e35804..292e65a 100644
--- a/drivers/cpuidle/cpuidle-ux500.c
+++ b/drivers/cpuidle/cpuidle-ux500.c
@@ -101,8 +101,7 @@ static struct cpuidle_driver ux500_idle_driver = {
.enter = ux500_enter_idle,
.exit_latency = 70,
.target_residency = 260,
- .flags = CPUIDLE_FLAG_TIME_VALID |
- CPUIDLE_FLAG_TIMER_STOP,
+ .flags = CPUIDLE_FLAG_TIMER_STOP,
.name = "ApIdle",
.desc = "ARM Retention",
},
diff --git a/drivers/cpuidle/cpuidle-zynq.c b/drivers/cpuidle/cpuidle-zynq.c
index c61b8b2..022dec8 100644
--- a/drivers/cpuidle/cpuidle-zynq.c
+++ b/drivers/cpuidle/cpuidle-zynq.c
@@ -52,7 +52,6 @@ static struct cpuidle_driver zynq_idle_driver = {
.enter = zynq_enter_idle,
.exit_latency = 10,
.target_residency = 10000,
- .flags = CPUIDLE_FLAG_TIME_VALID,
.name = "RAM_SR",
.desc = "WFI and RAM Self Refresh",
},
diff --git a/drivers/cpuidle/driver.c b/drivers/cpuidle/driver.c
index e431d11..2697e87 100644
--- a/drivers/cpuidle/driver.c
+++ b/drivers/cpuidle/driver.c
@@ -201,7 +201,6 @@ static void poll_idle_init(struct cpuidle_driver *drv)
state->exit_latency = 0;
state->target_residency = 0;
state->power_usage = -1;
- state->flags = CPUIDLE_FLAG_TIME_VALID;
state->enter = poll_idle;
state->disabled = false;
}
diff --git a/drivers/cpuidle/dt_idle_states.c b/drivers/cpuidle/dt_idle_states.c
index 52f4d11..a5c111b 100644
--- a/drivers/cpuidle/dt_idle_states.c
+++ b/drivers/cpuidle/dt_idle_states.c
@@ -27,6 +27,7 @@ static int init_state_node(struct cpuidle_state *idle_state,
{
int err;
const struct of_device_id *match_id;
+ const char *desc;
match_id = of_match_node(matches, state_node);
if (!match_id)
@@ -73,7 +74,11 @@ static int init_state_node(struct cpuidle_state *idle_state,
return -EINVAL;
}
- idle_state->flags = CPUIDLE_FLAG_TIME_VALID;
+ err = of_property_read_string(state_node, "idle-state-name", &desc);
+ if (err)
+ desc = state_node->name;
+
+ idle_state->flags = 0;
if (of_property_read_bool(state_node, "local-timer-stop"))
idle_state->flags |= CPUIDLE_FLAG_TIMER_STOP;
/*
@@ -82,7 +87,7 @@ static int init_state_node(struct cpuidle_state *idle_state,
* and desc become string pointers
*/
strncpy(idle_state->name, state_node->name, CPUIDLE_NAME_LEN - 1);
- strncpy(idle_state->desc, state_node->name, CPUIDLE_DESC_LEN - 1);
+ strncpy(idle_state->desc, desc, CPUIDLE_DESC_LEN - 1);
return 0;
}
@@ -169,6 +174,9 @@ int dt_init_idle_driver(struct cpuidle_driver *drv,
if (!state_node)
break;
+ if (!of_device_is_available(state_node))
+ continue;
+
if (!idle_state_valid(state_node, i, cpumask)) {
pr_warn("%s idle state not valid, bailing out\n",
state_node->full_name);
diff --git a/drivers/cpuidle/governors/ladder.c b/drivers/cpuidle/governors/ladder.c
index 06b57c4..37263d9 100644
--- a/drivers/cpuidle/governors/ladder.c
+++ b/drivers/cpuidle/governors/ladder.c
@@ -79,7 +79,7 @@ static int ladder_select_state(struct cpuidle_driver *drv,
last_state = &ldev->states[last_idx];
- if (drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_VALID) {
+ if (!(drv->states[last_idx].flags & CPUIDLE_FLAG_TIME_INVALID)) {
last_residency = cpuidle_get_last_residency(dev) - \
drv->states[last_idx].exit_latency;
}
diff --git a/drivers/cpuidle/governors/menu.c b/drivers/cpuidle/governors/menu.c
index 710a233..659d7b0 100644
--- a/drivers/cpuidle/governors/menu.c
+++ b/drivers/cpuidle/governors/menu.c
@@ -405,7 +405,7 @@ static void menu_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
* the measured amount of time is less than the exit latency,
* assume the state was never reached and the exit latency is 0.
*/
- if (unlikely(!(target->flags & CPUIDLE_FLAG_TIME_VALID))) {
+ if (unlikely(target->flags & CPUIDLE_FLAG_TIME_INVALID)) {
/* Use timer value as is */
measured_us = data->next_timer_us;
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c
index 061407d..887196e 100644
--- a/drivers/crypto/nx/nx-842.c
+++ b/drivers/crypto/nx/nx-842.c
@@ -1009,9 +1009,9 @@ error_out:
* notifier_to_errno() to decode this value
*/
static int nx842_OF_notifier(struct notifier_block *np, unsigned long action,
- void *update)
+ void *data)
{
- struct of_prop_reconfig *upd = update;
+ struct of_reconfig_data *upd = data;
struct nx842_devdata *local_devdata;
struct device_node *node = NULL;
diff --git a/drivers/dma/dw/core.c b/drivers/dma/dw/core.c
index 2447221..3804785 100644
--- a/drivers/dma/dw/core.c
+++ b/drivers/dma/dw/core.c
@@ -22,6 +22,7 @@
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/pm_runtime.h>
#include "../dmaengine.h"
#include "internal.h"
@@ -1504,6 +1505,9 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
dw->regs = chip->regs;
chip->dw = dw;
+ pm_runtime_enable(chip->dev);
+ pm_runtime_get_sync(chip->dev);
+
dw_params = dma_read_byaddr(chip->regs, DW_PARAMS);
autocfg = dw_params >> DW_PARAMS_EN & 0x1;
@@ -1667,11 +1671,14 @@ int dw_dma_probe(struct dw_dma_chip *chip, struct dw_dma_platform_data *pdata)
dev_info(chip->dev, "DesignWare DMA Controller, %d channels\n",
nr_channels);
+ pm_runtime_put_sync_suspend(chip->dev);
+
return 0;
err_dma_register:
free_irq(chip->irq, dw);
err_pdata:
+ pm_runtime_put_sync_suspend(chip->dev);
return err;
}
EXPORT_SYMBOL_GPL(dw_dma_probe);
@@ -1681,6 +1688,8 @@ int dw_dma_remove(struct dw_dma_chip *chip)
struct dw_dma *dw = chip->dw;
struct dw_dma_chan *dwc, *_dwc;
+ pm_runtime_get_sync(chip->dev);
+
dw_dma_off(dw);
dma_async_device_unregister(&dw->dma);
@@ -1693,6 +1702,8 @@ int dw_dma_remove(struct dw_dma_chip *chip)
channel_clear_bit(dw, CH_EN, dwc->mask);
}
+ pm_runtime_put_sync_suspend(chip->dev);
+ pm_runtime_disable(chip->dev);
return 0;
}
EXPORT_SYMBOL_GPL(dw_dma_remove);
diff --git a/drivers/dma/nbpfaxi.c b/drivers/dma/nbpfaxi.c
index 5aeada5..bda20e6 100644
--- a/drivers/dma/nbpfaxi.c
+++ b/drivers/dma/nbpfaxi.c
@@ -1479,7 +1479,7 @@ static struct platform_device_id nbpf_ids[] = {
};
MODULE_DEVICE_TABLE(platform, nbpf_ids);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int nbpf_runtime_suspend(struct device *dev)
{
struct nbpf_device *nbpf = platform_get_drvdata(to_platform_device(dev));
diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c
index 5fe5933..d9ca3e3 100644
--- a/drivers/dma/ste_dma40.c
+++ b/drivers/dma/ste_dma40.c
@@ -3051,7 +3051,7 @@ static int dma40_runtime_resume(struct device *dev)
static const struct dev_pm_ops dma40_pm_ops = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(dma40_suspend, dma40_resume)
- SET_PM_RUNTIME_PM_OPS(dma40_runtime_suspend,
+ SET_RUNTIME_PM_OPS(dma40_runtime_suspend,
dma40_runtime_resume,
NULL)
};
diff --git a/drivers/dma/tegra20-apb-dma.c b/drivers/dma/tegra20-apb-dma.c
index 16efa60..1c867d03 100644
--- a/drivers/dma/tegra20-apb-dma.c
+++ b/drivers/dma/tegra20-apb-dma.c
@@ -1587,7 +1587,7 @@ static int tegra_dma_pm_resume(struct device *dev)
#endif
static const struct dev_pm_ops tegra_dma_dev_pm_ops = {
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
.runtime_suspend = tegra_dma_runtime_suspend,
.runtime_resume = tegra_dma_runtime_resume,
#endif
diff --git a/drivers/edac/Kconfig b/drivers/edac/Kconfig
index 7072c28..49c2652 100644
--- a/drivers/edac/Kconfig
+++ b/drivers/edac/Kconfig
@@ -61,14 +61,14 @@ config EDAC_DECODE_MCE
has been initialized.
config EDAC_MCE_INJ
- tristate "Simple MCE injection interface over /sysfs"
- depends on EDAC_DECODE_MCE
+ tristate "Simple MCE injection interface"
+ depends on EDAC_DECODE_MCE && DEBUG_FS
default n
help
- This is a simple interface to inject MCEs over /sysfs and test
- the MCE decoding code in EDAC.
+ This is a simple debugfs interface to inject MCEs and test different
+ aspects of the MCE handling code.
- This is currently AMD-only.
+ WARNING: Do not even assume this interface is staying stable!
config EDAC_MM_EDAC
tristate "Main Memory EDAC (Error Detection And Correction) reporting"
@@ -105,11 +105,11 @@ config EDAC_GHES
In doubt, say 'Y'.
config EDAC_AMD64
- tristate "AMD64 (Opteron, Athlon64) K8, F10h"
- depends on EDAC_MM_EDAC && AMD_NB && X86_64 && EDAC_DECODE_MCE
+ tristate "AMD64 (Opteron, Athlon64)"
+ depends on EDAC_MM_EDAC && AMD_NB && EDAC_DECODE_MCE
help
Support for error detection and correction of DRAM ECC errors on
- the AMD64 families of memory controllers (K8 and F10h)
+ the AMD64 families (>= K8) of memory controllers.
config EDAC_AMD64_ERROR_INJECTION
bool "Sysfs HW Error injection facilities"
diff --git a/drivers/edac/Makefile b/drivers/edac/Makefile
index 359aa49..d40c69a 100644
--- a/drivers/edac/Makefile
+++ b/drivers/edac/Makefile
@@ -9,7 +9,7 @@
obj-$(CONFIG_EDAC) := edac_stub.o
obj-$(CONFIG_EDAC_MM_EDAC) += edac_core.o
-edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o edac_pci_sysfs.o
+edac_core-y := edac_mc.o edac_device.o edac_mc_sysfs.o
edac_core-y += edac_module.o edac_device_sysfs.o
ifdef CONFIG_PCI
diff --git a/drivers/edac/amd64_edac.c b/drivers/edac/amd64_edac.c
index bbd6514..17638d7 100644
--- a/drivers/edac/amd64_edac.c
+++ b/drivers/edac/amd64_edac.c
@@ -692,9 +692,19 @@ static void debug_dump_dramcfg_low(struct amd64_pvt *pvt, u32 dclr, int chan)
{
edac_dbg(1, "F2x%d90 (DRAM Cfg Low): 0x%08x\n", chan, dclr);
- edac_dbg(1, " DIMM type: %sbuffered; all DIMMs support ECC: %s\n",
- (dclr & BIT(16)) ? "un" : "",
- (dclr & BIT(19)) ? "yes" : "no");
+ if (pvt->dram_type == MEM_LRDDR3) {
+ u32 dcsm = pvt->csels[chan].csmasks[0];
+ /*
+ * It's assumed all LRDIMMs in a DCT are going to be of
+ * same 'type' until proven otherwise. So, use a cs
+ * value of '0' here to get dcsm value.
+ */
+ edac_dbg(1, " LRDIMM %dx rank multiply\n", (dcsm & 0x3));
+ }
+
+ edac_dbg(1, "All DIMMs support ECC:%s\n",
+ (dclr & BIT(19)) ? "yes" : "no");
+
edac_dbg(1, " PAR/ERR parity: %s\n",
(dclr & BIT(8)) ? "enabled" : "disabled");
@@ -756,7 +766,7 @@ static void prep_chip_selects(struct amd64_pvt *pvt)
if (pvt->fam == 0xf && pvt->ext_model < K8_REV_F) {
pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 8;
pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 8;
- } else if (pvt->fam == 0x15 && pvt->model >= 0x30) {
+ } else if (pvt->fam == 0x15 && pvt->model == 0x30) {
pvt->csels[0].b_cnt = pvt->csels[1].b_cnt = 4;
pvt->csels[0].m_cnt = pvt->csels[1].m_cnt = 2;
} else {
@@ -813,25 +823,63 @@ static void read_dct_base_mask(struct amd64_pvt *pvt)
}
}
-static enum mem_type determine_memory_type(struct amd64_pvt *pvt, int cs)
+static void determine_memory_type(struct amd64_pvt *pvt)
{
- enum mem_type type;
+ u32 dram_ctrl, dcsm;
- /* F15h supports only DDR3 */
- if (pvt->fam >= 0x15)
- type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
- else if (pvt->fam == 0x10 || pvt->ext_model >= K8_REV_F) {
+ switch (pvt->fam) {
+ case 0xf:
+ if (pvt->ext_model >= K8_REV_F)
+ goto ddr3;
+
+ pvt->dram_type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
+ return;
+
+ case 0x10:
if (pvt->dchr0 & DDR3_MODE)
- type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
+ goto ddr3;
+
+ pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
+ return;
+
+ case 0x15:
+ if (pvt->model < 0x60)
+ goto ddr3;
+
+ /*
+ * Model 0x60h needs special handling:
+ *
+ * We use a Chip Select value of '0' to obtain dcsm.
+ * Theoretically, it is possible to populate LRDIMMs of different
+ * 'Rank' value on a DCT. But this is not the common case. So,
+ * it's reasonable to assume all DIMMs are going to be of same
+ * 'type' until proven otherwise.
+ */
+ amd64_read_dct_pci_cfg(pvt, 0, DRAM_CONTROL, &dram_ctrl);
+ dcsm = pvt->csels[0].csmasks[0];
+
+ if (((dram_ctrl >> 8) & 0x7) == 0x2)
+ pvt->dram_type = MEM_DDR4;
+ else if (pvt->dclr0 & BIT(16))
+ pvt->dram_type = MEM_DDR3;
+ else if (dcsm & 0x3)
+ pvt->dram_type = MEM_LRDDR3;
else
- type = (pvt->dclr0 & BIT(16)) ? MEM_DDR2 : MEM_RDDR2;
- } else {
- type = (pvt->dclr0 & BIT(18)) ? MEM_DDR : MEM_RDDR;
- }
+ pvt->dram_type = MEM_RDDR3;
- amd64_info("CS%d: %s\n", cs, edac_mem_types[type]);
+ return;
- return type;
+ case 0x16:
+ goto ddr3;
+
+ default:
+ WARN(1, KERN_ERR "%s: Family??? 0x%x\n", __func__, pvt->fam);
+ pvt->dram_type = MEM_EMPTY;
+ }
+ return;
+
+ddr3:
+ pvt->dram_type = (pvt->dclr0 & BIT(16)) ? MEM_DDR3 : MEM_RDDR3;
}
/* Get the number of DCT channels the memory controller is using. */
@@ -958,8 +1006,12 @@ static void read_dram_base_limit_regs(struct amd64_pvt *pvt, unsigned range)
if (WARN_ON(!nb))
return;
- pci_func = (pvt->model == 0x30) ? PCI_DEVICE_ID_AMD_15H_M30H_NB_F1
- : PCI_DEVICE_ID_AMD_15H_NB_F1;
+ if (pvt->model == 0x60)
+ pci_func = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1;
+ else if (pvt->model == 0x30)
+ pci_func = PCI_DEVICE_ID_AMD_15H_M30H_NB_F1;
+ else
+ pci_func = PCI_DEVICE_ID_AMD_15H_NB_F1;
f1 = pci_get_related_function(nb->misc->vendor, pci_func, nb->misc);
if (WARN_ON(!f1))
@@ -1049,7 +1101,7 @@ static int ddr2_cs_size(unsigned i, bool dct_width)
}
static int k8_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
- unsigned cs_mode)
+ unsigned cs_mode, int cs_mask_nr)
{
u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
@@ -1167,8 +1219,43 @@ static int ddr3_cs_size(unsigned i, bool dct_width)
return cs_size;
}
+static int ddr3_lrdimm_cs_size(unsigned i, unsigned rank_multiply)
+{
+ unsigned shift = 0;
+ int cs_size = 0;
+
+ if (i < 4 || i == 6)
+ cs_size = -1;
+ else if (i == 12)
+ shift = 7;
+ else if (!(i & 0x1))
+ shift = i >> 1;
+ else
+ shift = (i + 1) >> 1;
+
+ if (cs_size != -1)
+ cs_size = rank_multiply * (128 << shift);
+
+ return cs_size;
+}
+
+static int ddr4_cs_size(unsigned i)
+{
+ int cs_size = 0;
+
+ if (i == 0)
+ cs_size = -1;
+ else if (i == 1)
+ cs_size = 1024;
+ else
+ /* Min cs_size = 1G */
+ cs_size = 1024 * (1 << (i >> 1));
+
+ return cs_size;
+}
+
static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
- unsigned cs_mode)
+ unsigned cs_mode, int cs_mask_nr)
{
u32 dclr = dct ? pvt->dclr1 : pvt->dclr0;
@@ -1184,18 +1271,49 @@ static int f10_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
* F15h supports only 64bit DCT interfaces
*/
static int f15_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
- unsigned cs_mode)
+ unsigned cs_mode, int cs_mask_nr)
{
WARN_ON(cs_mode > 12);
return ddr3_cs_size(cs_mode, false);
}
+/* F15h M60h supports DDR4 mapping as well.. */
+static int f15_m60h_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
+ unsigned cs_mode, int cs_mask_nr)
+{
+ int cs_size;
+ u32 dcsm = pvt->csels[dct].csmasks[cs_mask_nr];
+
+ WARN_ON(cs_mode > 12);
+
+ if (pvt->dram_type == MEM_DDR4) {
+ if (cs_mode > 9)
+ return -1;
+
+ cs_size = ddr4_cs_size(cs_mode);
+ } else if (pvt->dram_type == MEM_LRDDR3) {
+ unsigned rank_multiply = dcsm & 0xf;
+
+ if (rank_multiply == 3)
+ rank_multiply = 4;
+ cs_size = ddr3_lrdimm_cs_size(cs_mode, rank_multiply);
+ } else {
+ /* Minimum cs size is 512mb for F15hM60h*/
+ if (cs_mode == 0x1)
+ return -1;
+
+ cs_size = ddr3_cs_size(cs_mode, false);
+ }
+
+ return cs_size;
+}
+
/*
* F16h and F15h model 30h have only limited cs_modes.
*/
static int f16_dbam_to_chip_select(struct amd64_pvt *pvt, u8 dct,
- unsigned cs_mode)
+ unsigned cs_mode, int cs_mask_nr)
{
WARN_ON(cs_mode > 12);
@@ -1757,13 +1875,20 @@ static void debug_display_dimm_sizes(struct amd64_pvt *pvt, u8 ctrl)
size0 = 0;
if (dcsb[dimm*2] & DCSB_CS_ENABLE)
+ /* For f15m60h, need multiplier for LRDIMM cs_size
+ * calculation. We pass 'dimm' value to the dbam_to_cs
+ * mapper so we can find the multiplier from the
+ * corresponding DCSM.
+ */
size0 = pvt->ops->dbam_to_cs(pvt, ctrl,
- DBAM_DIMM(dimm, dbam));
+ DBAM_DIMM(dimm, dbam),
+ dimm);
size1 = 0;
if (dcsb[dimm*2 + 1] & DCSB_CS_ENABLE)
size1 = pvt->ops->dbam_to_cs(pvt, ctrl,
- DBAM_DIMM(dimm, dbam));
+ DBAM_DIMM(dimm, dbam),
+ dimm);
amd64_info(EDAC_MC ": %d: %5dMB %d: %5dMB\n",
dimm * 2, size0,
@@ -1812,6 +1937,16 @@ static struct amd64_family_type family_types[] = {
.dbam_to_cs = f16_dbam_to_chip_select,
}
},
+ [F15_M60H_CPUS] = {
+ .ctl_name = "F15h_M60h",
+ .f1_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F1,
+ .f3_id = PCI_DEVICE_ID_AMD_15H_M60H_NB_F3,
+ .ops = {
+ .early_channel_count = f1x_early_channel_count,
+ .map_sysaddr_to_csrow = f1x_map_sysaddr_to_csrow,
+ .dbam_to_cs = f15_m60h_dbam_to_chip_select,
+ }
+ },
[F16_CPUS] = {
.ctl_name = "F16h",
.f1_id = PCI_DEVICE_ID_AMD_16H_NB_F1,
@@ -2175,6 +2310,8 @@ static void read_mc_regs(struct amd64_pvt *pvt)
}
pvt->ecc_sym_sz = 4;
+ determine_memory_type(pvt);
+ edac_dbg(1, " DIMM type: %s\n", edac_mem_types[pvt->dram_type]);
if (pvt->fam >= 0x10) {
amd64_read_pci_cfg(pvt->F3, EXT_NB_MCA_CFG, &tmp);
@@ -2238,7 +2375,8 @@ static u32 get_csrow_nr_pages(struct amd64_pvt *pvt, u8 dct, int csrow_nr)
*/
cs_mode = DBAM_DIMM(csrow_nr / 2, dbam);
- nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode) << (20 - PAGE_SHIFT);
+ nr_pages = pvt->ops->dbam_to_cs(pvt, dct, cs_mode, (csrow_nr / 2))
+ << (20 - PAGE_SHIFT);
edac_dbg(0, "csrow: %d, channel: %d, DBAM idx: %d\n",
csrow_nr, dct, cs_mode);
@@ -2257,7 +2395,6 @@ static int init_csrows(struct mem_ctl_info *mci)
struct csrow_info *csrow;
struct dimm_info *dimm;
enum edac_type edac_mode;
- enum mem_type mtype;
int i, j, empty = 1;
int nr_pages = 0;
u32 val;
@@ -2302,8 +2439,6 @@ static int init_csrows(struct mem_ctl_info *mci)
nr_pages += row_dct1_pages;
}
- mtype = determine_memory_type(pvt, i);
-
edac_dbg(1, "Total csrow%d pages: %u\n", i, nr_pages);
/*
@@ -2317,7 +2452,7 @@ static int init_csrows(struct mem_ctl_info *mci)
for (j = 0; j < pvt->channel_count; j++) {
dimm = csrow->channels[j]->dimm;
- dimm->mtype = mtype;
+ dimm->mtype = pvt->dram_type;
dimm->edac_mode = edac_mode;
}
}
@@ -2604,6 +2739,10 @@ static struct amd64_family_type *per_family_init(struct amd64_pvt *pvt)
fam_type = &family_types[F15_M30H_CPUS];
pvt->ops = &family_types[F15_M30H_CPUS].ops;
break;
+ } else if (pvt->model == 0x60) {
+ fam_type = &family_types[F15_M60H_CPUS];
+ pvt->ops = &family_types[F15_M60H_CPUS].ops;
+ break;
}
fam_type = &family_types[F15_CPUS];
@@ -2828,55 +2967,13 @@ static void remove_one_instance(struct pci_dev *pdev)
* inquiry this table to see if this driver is for a given device found.
*/
static const struct pci_device_id amd64_pci_table[] = {
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_K8_NB_MEMCTL,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_10H_NB_DRAM,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_15H_NB_F2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_15H_M30H_NB_F2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_16H_NB_F2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- },
- {
- .vendor = PCI_VENDOR_ID_AMD,
- .device = PCI_DEVICE_ID_AMD_16H_M30H_NB_F2,
- .subvendor = PCI_ANY_ID,
- .subdevice = PCI_ANY_ID,
- .class = 0,
- .class_mask = 0,
- },
-
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_K8_NB_MEMCTL) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_10H_NB_DRAM) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_NB_F2) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M30H_NB_F2) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_15H_M60H_NB_F2) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_NB_F2) },
+ { PCI_VDEVICE(AMD, PCI_DEVICE_ID_AMD_16H_M30H_NB_F2) },
{0, }
};
MODULE_DEVICE_TABLE(pci, amd64_pci_table);
@@ -2938,6 +3035,11 @@ static int __init amd64_edac_init(void)
goto err_no_instances;
setup_pci_device();
+
+#ifdef CONFIG_X86_32
+ amd64_err("%s on 32-bit is unsupported. USE AT YOUR OWN RISK!\n", EDAC_MOD_STR);
+#endif
+
return 0;
err_no_instances:
diff --git a/drivers/edac/amd64_edac.h b/drivers/edac/amd64_edac.h
index 55fb594..d8468c6 100644
--- a/drivers/edac/amd64_edac.h
+++ b/drivers/edac/amd64_edac.h
@@ -162,10 +162,12 @@
/*
* PCI-defined configuration space registers
*/
-#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b
-#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c
#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
+#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F1 0x141b
+#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F2 0x141c
+#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F1 0x1571
+#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F2 0x1572
#define PCI_DEVICE_ID_AMD_16H_NB_F1 0x1531
#define PCI_DEVICE_ID_AMD_16H_NB_F2 0x1532
#define PCI_DEVICE_ID_AMD_16H_M30H_NB_F1 0x1581
@@ -221,6 +223,8 @@
#define csrow_enabled(i, dct, pvt) ((pvt)->csels[(dct)].csbases[(i)] & DCSB_CS_ENABLE)
+#define DRAM_CONTROL 0x78
+
#define DBAM0 0x80
#define DBAM1 0x180
@@ -301,6 +305,7 @@ enum amd_families {
F10_CPUS,
F15_CPUS,
F15_M30H_CPUS,
+ F15_M60H_CPUS,
F16_CPUS,
F16_M30H_CPUS,
NUM_FAMILIES,
@@ -379,6 +384,9 @@ struct amd64_pvt {
/* place to store error injection parameters prior to issue */
struct error_injection injection;
+
+ /* cache the dram_type */
+ enum mem_type dram_type;
};
enum err_codes {
@@ -480,7 +488,8 @@ struct low_ops {
int (*early_channel_count) (struct amd64_pvt *pvt);
void (*map_sysaddr_to_csrow) (struct mem_ctl_info *mci, u64 sys_addr,
struct err_info *);
- int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct, unsigned cs_mode);
+ int (*dbam_to_cs) (struct amd64_pvt *pvt, u8 dct,
+ unsigned cs_mode, int cs_mask_nr);
};
struct amd64_family_type {
diff --git a/drivers/edac/edac_mc.c b/drivers/edac/edac_mc.c
index c3893b0..1747906 100644
--- a/drivers/edac/edac_mc.c
+++ b/drivers/edac/edac_mc.c
@@ -125,27 +125,27 @@ static void edac_mc_dump_mci(struct mem_ctl_info *mci)
#endif /* CONFIG_EDAC_DEBUG */
-/*
- * keep those in sync with the enum mem_type
- */
const char * const edac_mem_types[] = {
- "Empty csrow",
- "Reserved csrow type",
- "Unknown csrow type",
- "Fast page mode RAM",
- "Extended data out RAM",
- "Burst Extended data out RAM",
- "Single data rate SDRAM",
- "Registered single data rate SDRAM",
- "Double data rate SDRAM",
- "Registered Double data rate SDRAM",
- "Rambus DRAM",
- "Unbuffered DDR2 RAM",
- "Fully buffered DDR2",
- "Registered DDR2 RAM",
- "Rambus XDR",
- "Unbuffered DDR3 RAM",
- "Registered DDR3 RAM",
+ [MEM_EMPTY] = "Empty csrow",
+ [MEM_RESERVED] = "Reserved csrow type",
+ [MEM_UNKNOWN] = "Unknown csrow type",
+ [MEM_FPM] = "Fast page mode RAM",
+ [MEM_EDO] = "Extended data out RAM",
+ [MEM_BEDO] = "Burst Extended data out RAM",
+ [MEM_SDR] = "Single data rate SDRAM",
+ [MEM_RDR] = "Registered single data rate SDRAM",
+ [MEM_DDR] = "Double data rate SDRAM",
+ [MEM_RDDR] = "Registered Double data rate SDRAM",
+ [MEM_RMBS] = "Rambus DRAM",
+ [MEM_DDR2] = "Unbuffered DDR2 RAM",
+ [MEM_FB_DDR2] = "Fully buffered DDR2",
+ [MEM_RDDR2] = "Registered DDR2 RAM",
+ [MEM_XDR] = "Rambus XDR",
+ [MEM_DDR3] = "Unbuffered DDR3 RAM",
+ [MEM_RDDR3] = "Registered DDR3 RAM",
+ [MEM_LRDDR3] = "Load-Reduced DDR3 RAM",
+ [MEM_DDR4] = "Unbuffered DDR4 RAM",
+ [MEM_RDDR4] = "Registered DDR4 RAM",
};
EXPORT_SYMBOL_GPL(edac_mem_types);
diff --git a/drivers/edac/edac_mc_sysfs.c b/drivers/edac/edac_mc_sysfs.c
index a6cd361..670d282 100644
--- a/drivers/edac/edac_mc_sysfs.c
+++ b/drivers/edac/edac_mc_sysfs.c
@@ -372,7 +372,7 @@ static int edac_create_csrow_object(struct mem_ctl_info *mci,
{
int err, chan;
- if (csrow->nr_channels >= EDAC_NR_CHANNELS)
+ if (csrow->nr_channels > EDAC_NR_CHANNELS)
return -ENODEV;
csrow->dev.type = &csrow_attr_type;
diff --git a/drivers/edac/edac_pci_sysfs.c b/drivers/edac/edac_pci_sysfs.c
index e8658e4..24d877f 100644
--- a/drivers/edac/edac_pci_sysfs.c
+++ b/drivers/edac/edac_pci_sysfs.c
@@ -14,9 +14,6 @@
#include "edac_core.h"
#include "edac_module.h"
-/* Turn off this whole feature if PCI is not configured */
-#ifdef CONFIG_PCI
-
#define EDAC_PCI_SYMLINK "device"
/* data variables exported via sysfs */
@@ -761,5 +758,3 @@ MODULE_PARM_DESC(check_pci_errors,
module_param(edac_pci_panic_on_pe, int, 0644);
MODULE_PARM_DESC(edac_pci_panic_on_pe,
"Panic on PCI Bus Parity error: 0=off 1=on");
-
-#endif /* CONFIG_PCI */
diff --git a/drivers/edac/ghes_edac.c b/drivers/edac/ghes_edac.c
index 8399b4e..b246819 100644
--- a/drivers/edac/ghes_edac.c
+++ b/drivers/edac/ghes_edac.c
@@ -413,8 +413,8 @@ void ghes_edac_report_mem_error(struct ghes *ghes, int sev,
/* Generate the trace event */
grain_bits = fls_long(e->grain);
- sprintf(pvt->detail_location, "APEI location: %s %s",
- e->location, e->other_detail);
+ snprintf(pvt->detail_location, sizeof(pvt->detail_location),
+ "APEI location: %s %s", e->location, e->other_detail);
trace_mc_event(type, e->msg, e->label, e->error_count,
mci->mc_idx, e->top_layer, e->mid_layer, e->low_layer,
PAGES_TO_MiB(e->page_frame_number) | e->offset_in_page,
diff --git a/drivers/edac/i3000_edac.c b/drivers/edac/i3000_edac.c
index cd28b96..5cb36a6 100644
--- a/drivers/edac/i3000_edac.c
+++ b/drivers/edac/i3000_edac.c
@@ -542,8 +542,7 @@ fail1:
pci_unregister_driver(&i3000_driver);
fail0:
- if (mci_pdev)
- pci_dev_put(mci_pdev);
+ pci_dev_put(mci_pdev);
return pci_rc;
}
diff --git a/drivers/edac/i3200_edac.c b/drivers/edac/i3200_edac.c
index aa98b13..4ad062b 100644
--- a/drivers/edac/i3200_edac.c
+++ b/drivers/edac/i3200_edac.c
@@ -523,8 +523,7 @@ fail1:
pci_unregister_driver(&i3200_driver);
fail0:
- if (mci_pdev)
- pci_dev_put(mci_pdev);
+ pci_dev_put(mci_pdev);
return pci_rc;
}
diff --git a/drivers/edac/i82443bxgx_edac.c b/drivers/edac/i82443bxgx_edac.c
index d730e276..b4705d9 100644
--- a/drivers/edac/i82443bxgx_edac.c
+++ b/drivers/edac/i82443bxgx_edac.c
@@ -458,8 +458,7 @@ static void __exit i82443bxgx_edacmc_exit(void)
if (!i82443bxgx_registered)
i82443bxgx_edacmc_remove_one(mci_pdev);
- if (mci_pdev)
- pci_dev_put(mci_pdev);
+ pci_dev_put(mci_pdev);
}
module_init(i82443bxgx_edacmc_init);
diff --git a/drivers/edac/mce_amd.c b/drivers/edac/mce_amd.c
index f78c1c5..58586d5 100644
--- a/drivers/edac/mce_amd.c
+++ b/drivers/edac/mce_amd.c
@@ -138,6 +138,15 @@ static const char * const mc5_mce_desc[] = {
"Retire status queue"
};
+static const char * const mc6_mce_desc[] = {
+ "Hardware Assertion",
+ "Free List",
+ "Physical Register File",
+ "Retire Queue",
+ "Scheduler table",
+ "Status Register File",
+};
+
static bool f12h_mc0_mce(u16 ec, u8 xec)
{
bool ret = false;
@@ -432,8 +441,8 @@ static bool k8_mc2_mce(u16 ec, u8 xec)
pr_cont(": %s error in the L2 cache tags.\n", R4_MSG(ec));
else if (xec == 0x0) {
if (TLB_ERROR(ec))
- pr_cont(": %s error in a Page Descriptor Cache or "
- "Guest TLB.\n", TT_MSG(ec));
+ pr_cont("%s error in a Page Descriptor Cache or Guest TLB.\n",
+ TT_MSG(ec));
else if (BUS_ERROR(ec))
pr_cont(": %s/ECC error in data read from NB: %s.\n",
R4_MSG(ec), PP_MSG(ec));
@@ -672,38 +681,10 @@ static void decode_mc6_mce(struct mce *m)
pr_emerg(HW_ERR "MC6 Error: ");
- switch (xec) {
- case 0x0:
- pr_cont("Hardware Assertion");
- break;
-
- case 0x1:
- pr_cont("Free List");
- break;
-
- case 0x2:
- pr_cont("Physical Register File");
- break;
-
- case 0x3:
- pr_cont("Retire Queue");
- break;
-
- case 0x4:
- pr_cont("Scheduler table");
- break;
-
- case 0x5:
- pr_cont("Status Register File");
- break;
-
- default:
+ if (xec > 0x5)
goto wrong_mc6_mce;
- break;
- }
-
- pr_cont(" parity error.\n");
+ pr_cont("%s parity error.\n", mc6_mce_desc[xec]);
return;
wrong_mc6_mce:
@@ -800,7 +781,7 @@ int amd_decode_mce(struct notifier_block *nb, unsigned long val, void *data)
pr_cont("]: 0x%016llx\n", m->status);
if (m->status & MCI_STATUS_ADDRV)
- pr_emerg(HW_ERR "MC%d_ADDR: 0x%016llx\n", m->bank, m->addr);
+ pr_emerg(HW_ERR "MC%d Error Address: 0x%016llx\n", m->bank, m->addr);
if (!fam_ops)
goto err_code;
diff --git a/drivers/edac/mce_amd.h b/drivers/edac/mce_amd.h
index 51b7e3a..c2359a1 100644
--- a/drivers/edac/mce_amd.h
+++ b/drivers/edac/mce_amd.h
@@ -32,9 +32,6 @@
#define R4(x) (((x) >> 4) & 0xf)
#define R4_MSG(x) ((R4(x) < 9) ? rrrr_msgs[R4(x)] : "Wrong R4!")
-#define MCI_STATUS_DEFERRED BIT_64(44)
-#define MCI_STATUS_POISON BIT_64(43)
-
extern const char * const pp_msgs[];
enum tt_ids {
diff --git a/drivers/edac/mce_amd_inj.c b/drivers/edac/mce_amd_inj.c
index 5e46a9f..0bd91a8 100644
--- a/drivers/edac/mce_amd_inj.c
+++ b/drivers/edac/mce_amd_inj.c
@@ -1,173 +1,262 @@
/*
- * A simple MCE injection facility for testing the MCE decoding code. This
- * driver should be built as module so that it can be loaded on production
- * kernels for testing purposes.
+ * A simple MCE injection facility for testing different aspects of the RAS
+ * code. This driver should be built as module so that it can be loaded
+ * on production kernels for testing purposes.
*
* This file may be distributed under the terms of the GNU General Public
* License version 2.
*
- * Copyright (c) 2010: Borislav Petkov <bp@alien8.de>
+ * Copyright (c) 2010-14: Borislav Petkov <bp@alien8.de>
* Advanced Micro Devices Inc.
*/
#include <linux/kobject.h>
+#include <linux/debugfs.h>
#include <linux/device.h>
-#include <linux/edac.h>
#include <linux/module.h>
+#include <linux/cpu.h>
#include <asm/mce.h>
#include "mce_amd.h"
-struct edac_mce_attr {
- struct attribute attr;
- ssize_t (*show) (struct kobject *kobj, struct edac_mce_attr *attr, char *buf);
- ssize_t (*store)(struct kobject *kobj, struct edac_mce_attr *attr,
- const char *buf, size_t count);
-};
-
-#define EDAC_MCE_ATTR(_name, _mode, _show, _store) \
-static struct edac_mce_attr mce_attr_##_name = __ATTR(_name, _mode, _show, _store)
-
-static struct kobject *mce_kobj;
-
/*
* Collect all the MCi_XXX settings
*/
static struct mce i_mce;
+static struct dentry *dfs_inj;
-#define MCE_INJECT_STORE(reg) \
-static ssize_t edac_inject_##reg##_store(struct kobject *kobj, \
- struct edac_mce_attr *attr, \
- const char *data, size_t count)\
+#define MCE_INJECT_SET(reg) \
+static int inj_##reg##_set(void *data, u64 val) \
{ \
- int ret = 0; \
- unsigned long value; \
- \
- ret = kstrtoul(data, 16, &value); \
- if (ret < 0) \
- printk(KERN_ERR "Error writing MCE " #reg " field.\n"); \
+ struct mce *m = (struct mce *)data; \
\
- i_mce.reg = value; \
- \
- return count; \
+ m->reg = val; \
+ return 0; \
}
-MCE_INJECT_STORE(status);
-MCE_INJECT_STORE(misc);
-MCE_INJECT_STORE(addr);
+MCE_INJECT_SET(status);
+MCE_INJECT_SET(misc);
+MCE_INJECT_SET(addr);
-#define MCE_INJECT_SHOW(reg) \
-static ssize_t edac_inject_##reg##_show(struct kobject *kobj, \
- struct edac_mce_attr *attr, \
- char *buf) \
+#define MCE_INJECT_GET(reg) \
+static int inj_##reg##_get(void *data, u64 *val) \
{ \
- return sprintf(buf, "0x%016llx\n", i_mce.reg); \
+ struct mce *m = (struct mce *)data; \
+ \
+ *val = m->reg; \
+ return 0; \
}
-MCE_INJECT_SHOW(status);
-MCE_INJECT_SHOW(misc);
-MCE_INJECT_SHOW(addr);
+MCE_INJECT_GET(status);
+MCE_INJECT_GET(misc);
+MCE_INJECT_GET(addr);
-EDAC_MCE_ATTR(status, 0644, edac_inject_status_show, edac_inject_status_store);
-EDAC_MCE_ATTR(misc, 0644, edac_inject_misc_show, edac_inject_misc_store);
-EDAC_MCE_ATTR(addr, 0644, edac_inject_addr_show, edac_inject_addr_store);
+DEFINE_SIMPLE_ATTRIBUTE(status_fops, inj_status_get, inj_status_set, "%llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(misc_fops, inj_misc_get, inj_misc_set, "%llx\n");
+DEFINE_SIMPLE_ATTRIBUTE(addr_fops, inj_addr_get, inj_addr_set, "%llx\n");
/*
- * This denotes into which bank we're injecting and triggers
- * the injection, at the same time.
+ * Caller needs to be make sure this cpu doesn't disappear
+ * from under us, i.e.: get_cpu/put_cpu.
*/
-static ssize_t edac_inject_bank_store(struct kobject *kobj,
- struct edac_mce_attr *attr,
- const char *data, size_t count)
+static int toggle_hw_mce_inject(unsigned int cpu, bool enable)
{
- int ret = 0;
- unsigned long value;
+ u32 l, h;
+ int err;
- ret = kstrtoul(data, 10, &value);
- if (ret < 0) {
- printk(KERN_ERR "Invalid bank value!\n");
- return -EINVAL;
+ err = rdmsr_on_cpu(cpu, MSR_K7_HWCR, &l, &h);
+ if (err) {
+ pr_err("%s: error reading HWCR\n", __func__);
+ return err;
}
- if (value > 5)
- if (boot_cpu_data.x86 != 0x15 || value > 6) {
- printk(KERN_ERR "Non-existent MCE bank: %lu\n", value);
- return -EINVAL;
- }
+ enable ? (l |= BIT(18)) : (l &= ~BIT(18));
- i_mce.bank = value;
+ err = wrmsr_on_cpu(cpu, MSR_K7_HWCR, l, h);
+ if (err)
+ pr_err("%s: error writing HWCR\n", __func__);
- amd_decode_mce(NULL, 0, &i_mce);
+ return err;
+}
- return count;
+static int flags_get(void *data, u64 *val)
+{
+ struct mce *m = (struct mce *)data;
+
+ *val = m->inject_flags;
+
+ return 0;
}
-static ssize_t edac_inject_bank_show(struct kobject *kobj,
- struct edac_mce_attr *attr, char *buf)
+static int flags_set(void *data, u64 val)
{
- return sprintf(buf, "%d\n", i_mce.bank);
+ struct mce *m = (struct mce *)data;
+
+ m->inject_flags = (u8)val;
+ return 0;
}
-EDAC_MCE_ATTR(bank, 0644, edac_inject_bank_show, edac_inject_bank_store);
+DEFINE_SIMPLE_ATTRIBUTE(flags_fops, flags_get, flags_set, "%llu\n");
-static struct edac_mce_attr *sysfs_attrs[] = { &mce_attr_status, &mce_attr_misc,
- &mce_attr_addr, &mce_attr_bank
-};
+/*
+ * On which CPU to inject?
+ */
+MCE_INJECT_GET(extcpu);
-static int __init edac_init_mce_inject(void)
+static int inj_extcpu_set(void *data, u64 val)
{
- struct bus_type *edac_subsys = NULL;
- int i, err = 0;
+ struct mce *m = (struct mce *)data;
- edac_subsys = edac_get_sysfs_subsys();
- if (!edac_subsys)
+ if (val >= nr_cpu_ids || !cpu_online(val)) {
+ pr_err("%s: Invalid CPU: %llu\n", __func__, val);
return -EINVAL;
+ }
+ m->extcpu = val;
+ return 0;
+}
+
+DEFINE_SIMPLE_ATTRIBUTE(extcpu_fops, inj_extcpu_get, inj_extcpu_set, "%llu\n");
- mce_kobj = kobject_create_and_add("mce", &edac_subsys->dev_root->kobj);
- if (!mce_kobj) {
- printk(KERN_ERR "Error creating a mce kset.\n");
- err = -ENOMEM;
- goto err_mce_kobj;
+static void trigger_mce(void *info)
+{
+ asm volatile("int $18");
+}
+
+static void do_inject(void)
+{
+ u64 mcg_status = 0;
+ unsigned int cpu = i_mce.extcpu;
+ u8 b = i_mce.bank;
+
+ if (!(i_mce.inject_flags & MCJ_EXCEPTION)) {
+ amd_decode_mce(NULL, 0, &i_mce);
+ return;
}
- for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++) {
- err = sysfs_create_file(mce_kobj, &sysfs_attrs[i]->attr);
- if (err) {
- printk(KERN_ERR "Error creating %s in sysfs.\n",
- sysfs_attrs[i]->attr.name);
- goto err_sysfs_create;
+ get_online_cpus();
+ if (!cpu_online(cpu))
+ goto err;
+
+ /* prep MCE global settings for the injection */
+ mcg_status = MCG_STATUS_MCIP | MCG_STATUS_EIPV;
+
+ if (!(i_mce.status & MCI_STATUS_PCC))
+ mcg_status |= MCG_STATUS_RIPV;
+
+ toggle_hw_mce_inject(cpu, true);
+
+ wrmsr_on_cpu(cpu, MSR_IA32_MCG_STATUS,
+ (u32)mcg_status, (u32)(mcg_status >> 32));
+
+ wrmsr_on_cpu(cpu, MSR_IA32_MCx_STATUS(b),
+ (u32)i_mce.status, (u32)(i_mce.status >> 32));
+
+ wrmsr_on_cpu(cpu, MSR_IA32_MCx_ADDR(b),
+ (u32)i_mce.addr, (u32)(i_mce.addr >> 32));
+
+ wrmsr_on_cpu(cpu, MSR_IA32_MCx_MISC(b),
+ (u32)i_mce.misc, (u32)(i_mce.misc >> 32));
+
+ toggle_hw_mce_inject(cpu, false);
+
+ smp_call_function_single(cpu, trigger_mce, NULL, 0);
+
+err:
+ put_online_cpus();
+
+}
+
+/*
+ * This denotes into which bank we're injecting and triggers
+ * the injection, at the same time.
+ */
+static int inj_bank_set(void *data, u64 val)
+{
+ struct mce *m = (struct mce *)data;
+
+ if (val > 5) {
+ if (boot_cpu_data.x86 != 0x15 || val > 6) {
+ pr_err("Non-existent MCE bank: %llu\n", val);
+ return -EINVAL;
}
}
- return 0;
-err_sysfs_create:
- while (--i >= 0)
- sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
+ m->bank = val;
+ do_inject();
- kobject_del(mce_kobj);
+ return 0;
+}
-err_mce_kobj:
- edac_put_sysfs_subsys();
+static int inj_bank_get(void *data, u64 *val)
+{
+ struct mce *m = (struct mce *)data;
- return err;
+ *val = m->bank;
+ return 0;
}
-static void __exit edac_exit_mce_inject(void)
+DEFINE_SIMPLE_ATTRIBUTE(bank_fops, inj_bank_get, inj_bank_set, "%llu\n");
+
+struct dfs_node {
+ char *name;
+ struct dentry *d;
+ const struct file_operations *fops;
+} dfs_fls[] = {
+ { .name = "status", .fops = &status_fops },
+ { .name = "misc", .fops = &misc_fops },
+ { .name = "addr", .fops = &addr_fops },
+ { .name = "bank", .fops = &bank_fops },
+ { .name = "flags", .fops = &flags_fops },
+ { .name = "cpu", .fops = &extcpu_fops },
+};
+
+static int __init init_mce_inject(void)
{
int i;
- for (i = 0; i < ARRAY_SIZE(sysfs_attrs); i++)
- sysfs_remove_file(mce_kobj, &sysfs_attrs[i]->attr);
+ dfs_inj = debugfs_create_dir("mce-inject", NULL);
+ if (!dfs_inj)
+ return -EINVAL;
+
+ for (i = 0; i < ARRAY_SIZE(dfs_fls); i++) {
+ dfs_fls[i].d = debugfs_create_file(dfs_fls[i].name,
+ S_IRUSR | S_IWUSR,
+ dfs_inj,
+ &i_mce,
+ dfs_fls[i].fops);
+
+ if (!dfs_fls[i].d)
+ goto err_dfs_add;
+ }
+
+ return 0;
+
+err_dfs_add:
+ while (--i >= 0)
+ debugfs_remove(dfs_fls[i].d);
- kobject_del(mce_kobj);
+ debugfs_remove(dfs_inj);
+ dfs_inj = NULL;
- edac_put_sysfs_subsys();
+ return -ENOMEM;
}
-module_init(edac_init_mce_inject);
-module_exit(edac_exit_mce_inject);
+static void __exit exit_mce_inject(void)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dfs_fls); i++)
+ debugfs_remove(dfs_fls[i].d);
+
+ memset(&dfs_fls, 0, sizeof(dfs_fls));
+
+ debugfs_remove(dfs_inj);
+ dfs_inj = NULL;
+}
+module_init(init_mce_inject);
+module_exit(exit_mce_inject);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("Borislav Petkov <bp@alien8.de>");
MODULE_AUTHOR("AMD Inc.");
-MODULE_DESCRIPTION("MCE injection facility for testing MCE decoding");
+MODULE_DESCRIPTION("MCE injection facility for RAS testing");
diff --git a/drivers/edac/mv64x60_edac.c b/drivers/edac/mv64x60_edac.c
index 542fad7..6366e88 100644
--- a/drivers/edac/mv64x60_edac.c
+++ b/drivers/edac/mv64x60_edac.c
@@ -178,7 +178,7 @@ static int mv64x60_pci_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev,
pdata->irq,
mv64x60_pci_isr,
- IRQF_DISABLED,
+ 0,
"[EDAC] PCI err",
pci);
if (res < 0) {
@@ -345,7 +345,7 @@ static int mv64x60_sram_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev,
pdata->irq,
mv64x60_sram_isr,
- IRQF_DISABLED,
+ 0,
"[EDAC] SRAM err",
edac_dev);
if (res < 0) {
@@ -540,7 +540,7 @@ static int mv64x60_cpu_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev,
pdata->irq,
mv64x60_cpu_isr,
- IRQF_DISABLED,
+ 0,
"[EDAC] CPU err",
edac_dev);
if (res < 0) {
@@ -800,7 +800,7 @@ static int mv64x60_mc_err_probe(struct platform_device *pdev)
res = devm_request_irq(&pdev->dev,
pdata->irq,
mv64x60_mc_isr,
- IRQF_DISABLED,
+ 0,
"[EDAC] MC err",
mci);
if (res < 0) {
diff --git a/drivers/edac/ppc4xx_edac.c b/drivers/edac/ppc4xx_edac.c
index 0f04d5e..4159353 100644
--- a/drivers/edac/ppc4xx_edac.c
+++ b/drivers/edac/ppc4xx_edac.c
@@ -1120,7 +1120,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op,
status = request_irq(ded_irq,
ppc4xx_edac_isr,
- IRQF_DISABLED,
+ 0,
"[EDAC] MC ECCDED",
mci);
@@ -1134,7 +1134,7 @@ static int ppc4xx_edac_register_irq(struct platform_device *op,
status = request_irq(sec_irq,
ppc4xx_edac_isr,
- IRQF_DISABLED,
+ 0,
"[EDAC] MC ECCSEC",
mci);
diff --git a/drivers/edac/sb_edac.c b/drivers/edac/sb_edac.c
index e9bb1af..63aa673 100644
--- a/drivers/edac/sb_edac.c
+++ b/drivers/edac/sb_edac.c
@@ -135,6 +135,7 @@ static inline int sad_pkg(const struct interleave_pkg *table, u32 reg,
#define TOLM 0x80
#define TOHM 0x84
+#define HASWELL_TOLM 0xd0
#define HASWELL_TOHM_0 0xd4
#define HASWELL_TOHM_1 0xd8
@@ -261,6 +262,7 @@ enum type {
SANDY_BRIDGE,
IVY_BRIDGE,
HASWELL,
+ BROADWELL,
};
struct sbridge_pvt;
@@ -445,7 +447,7 @@ static const struct pci_id_table pci_dev_descr_ibridge_table[] = {
* - each SMI channel interfaces with a scalable memory buffer
* - each scalable memory buffer supports 4 DDR3/DDR4 channels, 3 DPC
*/
-#define HASWELL_DDRCRCLKCONTROLS 0xa10
+#define HASWELL_DDRCRCLKCONTROLS 0xa10 /* Ditto on Broadwell */
#define HASWELL_HASYSDEFEATURE2 0x84
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_VTD_MISC 0x2f28
#define PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0 0x2fa0
@@ -497,12 +499,53 @@ static const struct pci_id_table pci_dev_descr_haswell_table[] = {
};
/*
+ * Broadwell support
+ *
+ * DE processor:
+ * - 1 IMC
+ * - 2 DDR3 channels, 2 DPC per channel
+ */
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC 0x6f28
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0 0x6fa0
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA 0x6fa8
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL 0x6f71
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0 0x6ffc
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1 0x6ffd
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0 0x6faa
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1 0x6fab
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2 0x6fac
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3 0x6fad
+#define PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0 0x6faf
+
+static const struct pci_id_descr pci_dev_descr_broadwell[] = {
+ /* first item must be the HA */
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0, 0) },
+
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1, 0) },
+
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3, 0) },
+ { PCI_DESCR(PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0, 1) },
+};
+
+static const struct pci_id_table pci_dev_descr_broadwell_table[] = {
+ PCI_ID_TABLE_ENTRY(pci_dev_descr_broadwell),
+ {0,} /* 0 terminated list. */
+};
+
+/*
* pci_device_id table for which devices we are looking for
*/
static const struct pci_device_id sbridge_pci_tbl[] = {
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_HA0)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA)},
{PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0)},
+ {PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0)},
{0,} /* 0 terminated list. */
};
@@ -706,8 +749,8 @@ static u64 haswell_get_tolm(struct sbridge_pvt *pvt)
{
u32 reg;
- pci_read_config_dword(pvt->info.pci_vtd, TOLM, &reg);
- return (GET_BITFIELD(reg, 26, 31) << 26) | 0x1ffffff;
+ pci_read_config_dword(pvt->info.pci_vtd, HASWELL_TOLM, &reg);
+ return (GET_BITFIELD(reg, 26, 31) << 26) | 0x3ffffff;
}
static u64 haswell_get_tohm(struct sbridge_pvt *pvt)
@@ -767,12 +810,22 @@ static int check_if_ecc_is_active(const u8 bus, enum type type)
struct pci_dev *pdev = NULL;
u32 mcmtr, id;
- if (type == IVY_BRIDGE)
+ switch (type) {
+ case IVY_BRIDGE:
id = PCI_DEVICE_ID_INTEL_IBRIDGE_IMC_HA0_TA;
- else if (type == HASWELL)
+ break;
+ case HASWELL:
id = PCI_DEVICE_ID_INTEL_HASWELL_IMC_HA0_TA;
- else
+ break;
+ case SANDY_BRIDGE:
id = PCI_DEVICE_ID_INTEL_SBRIDGE_IMC_TA;
+ break;
+ case BROADWELL:
+ id = PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA;
+ break;
+ default:
+ return -ENODEV;
+ }
pdev = get_pdev_same_bus(bus, id);
if (!pdev) {
@@ -800,7 +853,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
enum edac_type mode;
enum mem_type mtype;
- if (pvt->info.type == HASWELL)
+ if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL)
pci_read_config_dword(pvt->pci_sad1, SAD_TARGET, &reg);
else
pci_read_config_dword(pvt->pci_br0, SAD_TARGET, &reg);
@@ -848,7 +901,7 @@ static int get_dimm_config(struct mem_ctl_info *mci)
else
edac_dbg(0, "Memory is unregistered\n");
- if (mtype == MEM_DDR4 || MEM_RDDR4)
+ if (mtype == MEM_DDR4 || mtype == MEM_RDDR4)
banks = 16;
else
banks = 8;
@@ -909,7 +962,7 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
u32 reg;
u64 limit, prv = 0;
u64 tmp_mb;
- u32 mb, kb;
+ u32 gb, mb;
u32 rir_way;
/*
@@ -919,15 +972,17 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
pvt->tolm = pvt->info.get_tolm(pvt);
tmp_mb = (1 + pvt->tolm) >> 20;
- mb = div_u64_rem(tmp_mb, 1000, &kb);
- edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tolm);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
+ edac_dbg(0, "TOLM: %u.%03u GB (0x%016Lx)\n",
+ gb, (mb*1000)/1024, (u64)pvt->tolm);
/* Address range is already 45:25 */
pvt->tohm = pvt->info.get_tohm(pvt);
tmp_mb = (1 + pvt->tohm) >> 20;
- mb = div_u64_rem(tmp_mb, 1000, &kb);
- edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n", mb, kb, (u64)pvt->tohm);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
+ edac_dbg(0, "TOHM: %u.%03u GB (0x%016Lx)\n",
+ gb, (mb*1000)/1024, (u64)pvt->tohm);
/*
* Step 2) Get SAD range and SAD Interleave list
@@ -949,11 +1004,11 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
break;
tmp_mb = (limit + 1) >> 20;
- mb = div_u64_rem(tmp_mb, 1000, &kb);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
edac_dbg(0, "SAD#%d %s up to %u.%03u GB (0x%016Lx) Interleave: %s reg=0x%08x\n",
n_sads,
get_dram_attr(reg),
- mb, kb,
+ gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
INTERLEAVE_MODE(reg) ? "8:6" : "[8:6]XOR[18:16]",
reg);
@@ -984,9 +1039,9 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
break;
tmp_mb = (limit + 1) >> 20;
- mb = div_u64_rem(tmp_mb, 1000, &kb);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
edac_dbg(0, "TAD#%d: up to %u.%03u GB (0x%016Lx), socket interleave %d, memory interleave %d, TGT: %d, %d, %d, %d, reg=0x%08x\n",
- n_tads, mb, kb,
+ n_tads, gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
(u32)TAD_SOCK(reg),
(u32)TAD_CH(reg),
@@ -1009,10 +1064,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
tad_ch_nilv_offset[j],
&reg);
tmp_mb = TAD_OFFSET(reg) >> 20;
- mb = div_u64_rem(tmp_mb, 1000, &kb);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
edac_dbg(0, "TAD CH#%d, offset #%d: %u.%03u GB (0x%016Lx), reg=0x%08x\n",
i, j,
- mb, kb,
+ gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
reg);
}
@@ -1034,10 +1089,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
tmp_mb = pvt->info.rir_limit(reg) >> 20;
rir_way = 1 << RIR_WAY(reg);
- mb = div_u64_rem(tmp_mb, 1000, &kb);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
edac_dbg(0, "CH#%d RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d, reg=0x%08x\n",
i, j,
- mb, kb,
+ gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
rir_way,
reg);
@@ -1048,10 +1103,10 @@ static void get_memory_layout(const struct mem_ctl_info *mci)
&reg);
tmp_mb = RIR_OFFSET(reg) << 6;
- mb = div_u64_rem(tmp_mb, 1000, &kb);
+ gb = div_u64_rem(tmp_mb, 1024, &mb);
edac_dbg(0, "CH#%d RIR#%d INTL#%d, offset %u.%03u GB (0x%016Lx), tgt: %d, reg=0x%08x\n",
i, j, k,
- mb, kb,
+ gb, (mb*1000)/1024,
((u64)tmp_mb) << 20L,
(u32)RIR_RNK_TGT(reg),
reg);
@@ -1089,7 +1144,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
u8 ch_way, sck_way, pkg, sad_ha = 0;
u32 tad_offset;
u32 rir_way;
- u32 mb, kb;
+ u32 mb, gb;
u64 ch_addr, offset, limit = 0, prv = 0;
@@ -1179,7 +1234,7 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
*socket = sad_interleave[idx];
edac_dbg(0, "SAD interleave index: %d (wayness %d) = CPU socket %d\n",
idx, sad_way, *socket);
- } else if (pvt->info.type == HASWELL) {
+ } else if (pvt->info.type == HASWELL || pvt->info.type == BROADWELL) {
int bits, a7mode = A7MODE(dram_rule);
if (a7mode) {
@@ -1358,10 +1413,10 @@ static int get_memory_error_data(struct mem_ctl_info *mci,
continue;
limit = pvt->info.rir_limit(reg);
- mb = div_u64_rem(limit >> 20, 1000, &kb);
+ gb = div_u64_rem(limit >> 20, 1024, &mb);
edac_dbg(0, "RIR#%d, limit: %u.%03u GB (0x%016Lx), way: %d\n",
n_rir,
- mb, kb,
+ gb, (mb*1000)/1024,
limit,
1 << RIR_WAY(reg));
if (ch_addr <= limit)
@@ -1828,6 +1883,82 @@ enodev:
return -ENODEV;
}
+static int broadwell_mci_bind_devs(struct mem_ctl_info *mci,
+ struct sbridge_dev *sbridge_dev)
+{
+ struct sbridge_pvt *pvt = mci->pvt_info;
+ struct pci_dev *pdev;
+ int i;
+
+ /* there's only one device per system; not tied to any bus */
+ if (pvt->info.pci_vtd == NULL)
+ /* result will be checked later */
+ pvt->info.pci_vtd = pci_get_device(PCI_VENDOR_ID_INTEL,
+ PCI_DEVICE_ID_INTEL_BROADWELL_IMC_VTD_MISC,
+ NULL);
+
+ for (i = 0; i < sbridge_dev->n_devs; i++) {
+ pdev = sbridge_dev->pdev[i];
+ if (!pdev)
+ continue;
+
+ switch (pdev->device) {
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD0:
+ pvt->pci_sad0 = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_CBO_SAD1:
+ pvt->pci_sad1 = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
+ pvt->pci_ha0 = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TA:
+ pvt->pci_ta = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_THERMAL:
+ pvt->pci_ras = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD0:
+ pvt->pci_tad[0] = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD1:
+ pvt->pci_tad[1] = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD2:
+ pvt->pci_tad[2] = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0_TAD3:
+ pvt->pci_tad[3] = pdev;
+ break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_DDRIO0:
+ pvt->pci_ddrio = pdev;
+ break;
+ default:
+ break;
+ }
+
+ edac_dbg(0, "Associated PCI %02x.%02d.%d with dev = %p\n",
+ sbridge_dev->bus,
+ PCI_SLOT(pdev->devfn), PCI_FUNC(pdev->devfn),
+ pdev);
+ }
+
+ /* Check if everything were registered */
+ if (!pvt->pci_sad0 || !pvt->pci_ha0 || !pvt->pci_sad1 ||
+ !pvt->pci_ras || !pvt->pci_ta || !pvt->info.pci_vtd)
+ goto enodev;
+
+ for (i = 0; i < NUM_CHANNELS; i++) {
+ if (!pvt->pci_tad[i])
+ goto enodev;
+ }
+ return 0;
+
+enodev:
+ sbridge_printk(KERN_ERR, "Some needed devices are missing\n");
+ return -ENODEV;
+}
+
/****************************************************************************
Error check routines
****************************************************************************/
@@ -2240,6 +2371,25 @@ static int sbridge_register_mci(struct sbridge_dev *sbridge_dev, enum type type)
if (unlikely(rc < 0))
goto fail0;
break;
+ case BROADWELL:
+ /* rankcfgr isn't used */
+ pvt->info.get_tolm = haswell_get_tolm;
+ pvt->info.get_tohm = haswell_get_tohm;
+ pvt->info.dram_rule = ibridge_dram_rule;
+ pvt->info.get_memory_type = haswell_get_memory_type;
+ pvt->info.get_node_id = haswell_get_node_id;
+ pvt->info.rir_limit = haswell_rir_limit;
+ pvt->info.max_sad = ARRAY_SIZE(ibridge_dram_rule);
+ pvt->info.interleave_list = ibridge_interleave_list;
+ pvt->info.max_interleave = ARRAY_SIZE(ibridge_interleave_list);
+ pvt->info.interleave_pkg = ibridge_interleave_pkg;
+ mci->ctl_name = kasprintf(GFP_KERNEL, "Broadwell Socket#%d", mci->mc_idx);
+
+ /* Store pci devices at mci for faster access */
+ rc = broadwell_mci_bind_devs(mci, sbridge_dev);
+ if (unlikely(rc < 0))
+ goto fail0;
+ break;
}
/* Get dimm basic config and the memory layout */
@@ -2305,6 +2455,10 @@ static int sbridge_probe(struct pci_dev *pdev, const struct pci_device_id *id)
rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_haswell_table);
type = HASWELL;
break;
+ case PCI_DEVICE_ID_INTEL_BROADWELL_IMC_HA0:
+ rc = sbridge_get_all_devices(&num_mc, pci_dev_descr_broadwell_table);
+ type = BROADWELL;
+ break;
}
if (unlikely(rc < 0))
goto fail0;
diff --git a/drivers/edac/x38_edac.c b/drivers/edac/x38_edac.c
index e644b52..7c5cdc6 100644
--- a/drivers/edac/x38_edac.c
+++ b/drivers/edac/x38_edac.c
@@ -500,8 +500,7 @@ fail1:
pci_unregister_driver(&x38_driver);
fail0:
- if (mci_pdev)
- pci_dev_put(mci_pdev);
+ pci_dev_put(mci_pdev);
return pci_rc;
}
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index 17afc51..c5f7b4e 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -93,6 +93,12 @@ static void dmi_table(u8 *buf, int len, int num,
const struct dmi_header *dm = (const struct dmi_header *)data;
/*
+ * 7.45 End-of-Table (Type 127) [SMBIOS reference spec v3.0.0]
+ */
+ if (dm->type == DMI_ENTRY_END_OF_TABLE)
+ break;
+
+ /*
* We want to know the total length (formatted area and
* strings) before decoding to make sure we won't run off the
* table in dmi_decode or dmi_string
@@ -107,7 +113,7 @@ static void dmi_table(u8 *buf, int len, int num,
}
}
-static u32 dmi_base;
+static phys_addr_t dmi_base;
static u16 dmi_len;
static u16 dmi_num;
@@ -467,7 +473,7 @@ static int __init dmi_present(const u8 *buf)
if (memcmp(buf, "_SM_", 4) == 0 &&
buf[5] < 32 && dmi_checksum(buf, buf[5])) {
- smbios_ver = (buf[6] << 8) + buf[7];
+ smbios_ver = get_unaligned_be16(buf + 6);
/* Some BIOS report weird SMBIOS version, fix that up */
switch (smbios_ver) {
@@ -489,10 +495,9 @@ static int __init dmi_present(const u8 *buf)
buf += 16;
if (memcmp(buf, "_DMI_", 5) == 0 && dmi_checksum(buf, 15)) {
- dmi_num = (buf[13] << 8) | buf[12];
- dmi_len = (buf[7] << 8) | buf[6];
- dmi_base = (buf[11] << 24) | (buf[10] << 16) |
- (buf[9] << 8) | buf[8];
+ dmi_num = get_unaligned_le16(buf + 12);
+ dmi_len = get_unaligned_le16(buf + 6);
+ dmi_base = get_unaligned_le32(buf + 8);
if (dmi_walk_early(dmi_decode) == 0) {
if (smbios_ver) {
@@ -514,12 +519,72 @@ static int __init dmi_present(const u8 *buf)
return 1;
}
+/*
+ * Check for the SMBIOS 3.0 64-bit entry point signature. Unlike the legacy
+ * 32-bit entry point, there is no embedded DMI header (_DMI_) in here.
+ */
+static int __init dmi_smbios3_present(const u8 *buf)
+{
+ if (memcmp(buf, "_SM3_", 5) == 0 &&
+ buf[6] < 32 && dmi_checksum(buf, buf[6])) {
+ dmi_ver = get_unaligned_be16(buf + 7);
+ dmi_len = get_unaligned_le32(buf + 12);
+ dmi_base = get_unaligned_le64(buf + 16);
+
+ /*
+ * The 64-bit SMBIOS 3.0 entry point no longer has a field
+ * containing the number of structures present in the table.
+ * Instead, it defines the table size as a maximum size, and
+ * relies on the end-of-table structure type (#127) to be used
+ * to signal the end of the table.
+ * So let's define dmi_num as an upper bound as well: each
+ * structure has a 4 byte header, so dmi_len / 4 is an upper
+ * bound for the number of structures in the table.
+ */
+ dmi_num = dmi_len / 4;
+
+ if (dmi_walk_early(dmi_decode) == 0) {
+ pr_info("SMBIOS %d.%d present.\n",
+ dmi_ver >> 8, dmi_ver & 0xFF);
+ dmi_format_ids(dmi_ids_string, sizeof(dmi_ids_string));
+ pr_debug("DMI: %s\n", dmi_ids_string);
+ return 0;
+ }
+ }
+ return 1;
+}
+
void __init dmi_scan_machine(void)
{
char __iomem *p, *q;
char buf[32];
if (efi_enabled(EFI_CONFIG_TABLES)) {
+ /*
+ * According to the DMTF SMBIOS reference spec v3.0.0, it is
+ * allowed to define both the 64-bit entry point (smbios3) and
+ * the 32-bit entry point (smbios), in which case they should
+ * either both point to the same SMBIOS structure table, or the
+ * table pointed to by the 64-bit entry point should contain a
+ * superset of the table contents pointed to by the 32-bit entry
+ * point (section 5.2)
+ * This implies that the 64-bit entry point should have
+ * precedence if it is defined and supported by the OS. If we
+ * have the 64-bit entry point, but fail to decode it, fall
+ * back to the legacy one (if available)
+ */
+ if (efi.smbios3 != EFI_INVALID_TABLE_ADDR) {
+ p = dmi_early_remap(efi.smbios3, 32);
+ if (p == NULL)
+ goto error;
+ memcpy_fromio(buf, p, 32);
+ dmi_early_unmap(p, 32);
+
+ if (!dmi_smbios3_present(buf)) {
+ dmi_available = 1;
+ goto out;
+ }
+ }
if (efi.smbios == EFI_INVALID_TABLE_ADDR)
goto error;
@@ -552,7 +617,7 @@ void __init dmi_scan_machine(void)
memset(buf, 0, 16);
for (q = p; q < p + 0x10000; q += 16) {
memcpy_fromio(buf + 16, q, 16);
- if (!dmi_present(buf)) {
+ if (!dmi_smbios3_present(buf) || !dmi_present(buf)) {
dmi_available = 1;
dmi_early_unmap(p, 0x10000);
goto out;
diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile
index aef6a95..d8be608 100644
--- a/drivers/firmware/efi/Makefile
+++ b/drivers/firmware/efi/Makefile
@@ -7,4 +7,4 @@ obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o
obj-$(CONFIG_UEFI_CPER) += cper.o
obj-$(CONFIG_EFI_RUNTIME_MAP) += runtime-map.o
obj-$(CONFIG_EFI_RUNTIME_WRAPPERS) += runtime-wrappers.o
-obj-$(CONFIG_EFI_ARM_STUB) += libstub/
+obj-$(CONFIG_EFI_STUB) += libstub/
diff --git a/drivers/firmware/efi/cper.c b/drivers/firmware/efi/cper.c
index 5b53d61..4fd9961 100644
--- a/drivers/firmware/efi/cper.c
+++ b/drivers/firmware/efi/cper.c
@@ -294,7 +294,7 @@ void cper_mem_err_pack(const struct cper_sec_mem_err *mem,
const char *cper_mem_err_unpack(struct trace_seq *p,
struct cper_mem_err_compact *cmem)
{
- const char *ret = p->buffer + p->len;
+ const char *ret = trace_seq_buffer_ptr(p);
if (cper_mem_err_location(cmem, rcd_decode_str))
trace_seq_printf(p, "%s", rcd_decode_str);
diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
index 8590099..9035c1b 100644
--- a/drivers/firmware/efi/efi.c
+++ b/drivers/firmware/efi/efi.c
@@ -30,6 +30,7 @@ struct efi __read_mostly efi = {
.acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR,
+ .smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR,
@@ -86,6 +87,8 @@ static ssize_t systab_show(struct kobject *kobj,
str += sprintf(str, "ACPI=0x%lx\n", efi.acpi);
if (efi.smbios != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "SMBIOS=0x%lx\n", efi.smbios);
+ if (efi.smbios3 != EFI_INVALID_TABLE_ADDR)
+ str += sprintf(str, "SMBIOS3=0x%lx\n", efi.smbios3);
if (efi.hcdp != EFI_INVALID_TABLE_ADDR)
str += sprintf(str, "HCDP=0x%lx\n", efi.hcdp);
if (efi.boot_info != EFI_INVALID_TABLE_ADDR)
@@ -260,6 +263,7 @@ static __initdata efi_config_table_type_t common_tables[] = {
{MPS_TABLE_GUID, "MPS", &efi.mps},
{SAL_SYSTEM_TABLE_GUID, "SALsystab", &efi.sal_systab},
{SMBIOS_TABLE_GUID, "SMBIOS", &efi.smbios},
+ {SMBIOS3_TABLE_GUID, "SMBIOS 3.0", &efi.smbios3},
{UGA_IO_PROTOCOL_GUID, "UGA", &efi.uga},
{NULL_GUID, NULL, NULL},
};
diff --git a/drivers/firmware/efi/libstub/arm-stub.c b/drivers/firmware/efi/libstub/arm-stub.c
index 75ee059..eb48a1a 100644
--- a/drivers/firmware/efi/libstub/arm-stub.c
+++ b/drivers/firmware/efi/libstub/arm-stub.c
@@ -247,9 +247,18 @@ unsigned long __init efi_entry(void *handle, efi_system_table_t *sys_table,
goto fail_free_cmdline;
}
}
- if (!fdt_addr)
+
+ if (fdt_addr) {
+ pr_efi(sys_table, "Using DTB from command line\n");
+ } else {
/* Look for a device tree configuration table entry. */
fdt_addr = (uintptr_t)get_fdt(sys_table);
+ if (fdt_addr)
+ pr_efi(sys_table, "Using DTB from configuration table\n");
+ }
+
+ if (!fdt_addr)
+ pr_efi(sys_table, "Generating empty DTB\n");
status = handle_cmdline_files(sys_table, image, cmdline_ptr,
"initrd=", dram_base + SZ_512M,
diff --git a/drivers/gpio/Kconfig b/drivers/gpio/Kconfig
index 0959ca9..23dfd5f 100644
--- a/drivers/gpio/Kconfig
+++ b/drivers/gpio/Kconfig
@@ -905,4 +905,16 @@ config GPIO_VIPERBOARD
River Tech's viperboard.h for detailed meaning
of the module parameters.
+config GPIO_DLN2
+ tristate "Diolan DLN2 GPIO support"
+ depends on MFD_DLN2
+ select GPIOLIB_IRQCHIP
+
+ help
+ Select this option to enable GPIO driver for the Diolan DLN2
+ board.
+
+ This driver can also be built as a module. If so, the module
+ will be called gpio-dln2.
+
endif
diff --git a/drivers/gpio/Makefile b/drivers/gpio/Makefile
index e5d346c..e60677b 100644
--- a/drivers/gpio/Makefile
+++ b/drivers/gpio/Makefile
@@ -26,6 +26,7 @@ obj-$(CONFIG_GPIO_CRYSTAL_COVE) += gpio-crystalcove.o
obj-$(CONFIG_GPIO_DA9052) += gpio-da9052.o
obj-$(CONFIG_GPIO_DA9055) += gpio-da9055.o
obj-$(CONFIG_GPIO_DAVINCI) += gpio-davinci.o
+obj-$(CONFIG_GPIO_DLN2) += gpio-dln2.o
obj-$(CONFIG_GPIO_DWAPB) += gpio-dwapb.o
obj-$(CONFIG_GPIO_EM) += gpio-em.o
obj-$(CONFIG_GPIO_EP93XX) += gpio-ep93xx.o
diff --git a/drivers/gpio/devres.c b/drivers/gpio/devres.c
index 954b9f6..13dbd3d 100644
--- a/drivers/gpio/devres.c
+++ b/drivers/gpio/devres.c
@@ -109,6 +109,38 @@ struct gpio_desc *__must_check __devm_gpiod_get_index(struct device *dev,
EXPORT_SYMBOL(__devm_gpiod_get_index);
/**
+ * devm_get_gpiod_from_child - get a GPIO descriptor from a device's child node
+ * @dev: GPIO consumer
+ * @child: firmware node (child of @dev)
+ *
+ * GPIO descriptors returned from this function are automatically disposed on
+ * driver detach.
+ */
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child)
+{
+ struct gpio_desc **dr;
+ struct gpio_desc *desc;
+
+ dr = devres_alloc(devm_gpiod_release, sizeof(struct gpio_desc *),
+ GFP_KERNEL);
+ if (!dr)
+ return ERR_PTR(-ENOMEM);
+
+ desc = fwnode_get_named_gpiod(child, "gpios");
+ if (IS_ERR(desc)) {
+ devres_free(dr);
+ return desc;
+ }
+
+ *dr = desc;
+ devres_add(dev, dr);
+
+ return desc;
+}
+EXPORT_SYMBOL(devm_get_gpiod_from_child);
+
+/**
* devm_gpiod_get_index_optional - Resource-managed gpiod_get_index_optional()
* @dev: GPIO consumer
* @con_id: function within the GPIO consumer
diff --git a/drivers/gpio/gpio-dln2.c b/drivers/gpio/gpio-dln2.c
new file mode 100644
index 0000000..978b51e
--- /dev/null
+++ b/drivers/gpio/gpio-dln2.c
@@ -0,0 +1,553 @@
+/*
+ * Driver for the Diolan DLN-2 USB-GPIO adapter
+ *
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+#include <linux/irqdomain.h>
+#include <linux/irq.h>
+#include <linux/irqchip/chained_irq.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/dln2.h>
+
+#define DLN2_GPIO_ID 0x01
+
+#define DLN2_GPIO_GET_PIN_COUNT DLN2_CMD(0x01, DLN2_GPIO_ID)
+#define DLN2_GPIO_SET_DEBOUNCE DLN2_CMD(0x04, DLN2_GPIO_ID)
+#define DLN2_GPIO_GET_DEBOUNCE DLN2_CMD(0x05, DLN2_GPIO_ID)
+#define DLN2_GPIO_PORT_GET_VAL DLN2_CMD(0x06, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_GET_VAL DLN2_CMD(0x0B, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_SET_OUT_VAL DLN2_CMD(0x0C, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_GET_OUT_VAL DLN2_CMD(0x0D, DLN2_GPIO_ID)
+#define DLN2_GPIO_CONDITION_MET_EV DLN2_CMD(0x0F, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_ENABLE DLN2_CMD(0x10, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_DISABLE DLN2_CMD(0x11, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_SET_DIRECTION DLN2_CMD(0x13, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_GET_DIRECTION DLN2_CMD(0x14, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_SET_EVENT_CFG DLN2_CMD(0x1E, DLN2_GPIO_ID)
+#define DLN2_GPIO_PIN_GET_EVENT_CFG DLN2_CMD(0x1F, DLN2_GPIO_ID)
+
+#define DLN2_GPIO_EVENT_NONE 0
+#define DLN2_GPIO_EVENT_CHANGE 1
+#define DLN2_GPIO_EVENT_LVL_HIGH 2
+#define DLN2_GPIO_EVENT_LVL_LOW 3
+#define DLN2_GPIO_EVENT_CHANGE_RISING 0x11
+#define DLN2_GPIO_EVENT_CHANGE_FALLING 0x21
+#define DLN2_GPIO_EVENT_MASK 0x0F
+
+#define DLN2_GPIO_MAX_PINS 32
+
+struct dln2_irq_work {
+ struct work_struct work;
+ struct dln2_gpio *dln2;
+ int pin;
+ int type;
+};
+
+struct dln2_gpio {
+ struct platform_device *pdev;
+ struct gpio_chip gpio;
+
+ /*
+ * Cache pin direction to save us one transfer, since the hardware has
+ * separate commands to read the in and out values.
+ */
+ DECLARE_BITMAP(output_enabled, DLN2_GPIO_MAX_PINS);
+
+ DECLARE_BITMAP(irqs_masked, DLN2_GPIO_MAX_PINS);
+ DECLARE_BITMAP(irqs_enabled, DLN2_GPIO_MAX_PINS);
+ DECLARE_BITMAP(irqs_pending, DLN2_GPIO_MAX_PINS);
+ struct dln2_irq_work *irq_work;
+};
+
+struct dln2_gpio_pin {
+ __le16 pin;
+};
+
+struct dln2_gpio_pin_val {
+ __le16 pin __packed;
+ u8 value;
+};
+
+static int dln2_gpio_get_pin_count(struct platform_device *pdev)
+{
+ int ret;
+ __le16 count;
+ int len = sizeof(count);
+
+ ret = dln2_transfer_rx(pdev, DLN2_GPIO_GET_PIN_COUNT, &count, &len);
+ if (ret < 0)
+ return ret;
+ if (len < sizeof(count))
+ return -EPROTO;
+
+ return le16_to_cpu(count);
+}
+
+static int dln2_gpio_pin_cmd(struct dln2_gpio *dln2, int cmd, unsigned pin)
+{
+ struct dln2_gpio_pin req = {
+ .pin = cpu_to_le16(pin),
+ };
+
+ return dln2_transfer_tx(dln2->pdev, cmd, &req, sizeof(req));
+}
+
+static int dln2_gpio_pin_val(struct dln2_gpio *dln2, int cmd, unsigned int pin)
+{
+ int ret;
+ struct dln2_gpio_pin req = {
+ .pin = cpu_to_le16(pin),
+ };
+ struct dln2_gpio_pin_val rsp;
+ int len = sizeof(rsp);
+
+ ret = dln2_transfer(dln2->pdev, cmd, &req, sizeof(req), &rsp, &len);
+ if (ret < 0)
+ return ret;
+ if (len < sizeof(rsp) || req.pin != rsp.pin)
+ return -EPROTO;
+
+ return rsp.value;
+}
+
+static int dln2_gpio_pin_get_in_val(struct dln2_gpio *dln2, unsigned int pin)
+{
+ int ret;
+
+ ret = dln2_gpio_pin_val(dln2, DLN2_GPIO_PIN_GET_VAL, pin);
+ if (ret < 0)
+ return ret;
+ return !!ret;
+}
+
+static int dln2_gpio_pin_get_out_val(struct dln2_gpio *dln2, unsigned int pin)
+{
+ int ret;
+
+ ret = dln2_gpio_pin_val(dln2, DLN2_GPIO_PIN_GET_OUT_VAL, pin);
+ if (ret < 0)
+ return ret;
+ return !!ret;
+}
+
+static void dln2_gpio_pin_set_out_val(struct dln2_gpio *dln2,
+ unsigned int pin, int value)
+{
+ struct dln2_gpio_pin_val req = {
+ .pin = cpu_to_le16(pin),
+ .value = value,
+ };
+
+ dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_OUT_VAL, &req,
+ sizeof(req));
+}
+
+#define DLN2_GPIO_DIRECTION_IN 0
+#define DLN2_GPIO_DIRECTION_OUT 1
+
+static int dln2_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio_pin req = {
+ .pin = cpu_to_le16(offset),
+ };
+ struct dln2_gpio_pin_val rsp;
+ int len = sizeof(rsp);
+ int ret;
+
+ ret = dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_ENABLE, offset);
+ if (ret < 0)
+ return ret;
+
+ /* cache the pin direction */
+ ret = dln2_transfer(dln2->pdev, DLN2_GPIO_PIN_GET_DIRECTION,
+ &req, sizeof(req), &rsp, &len);
+ if (ret < 0)
+ return ret;
+ if (len < sizeof(rsp) || req.pin != rsp.pin) {
+ ret = -EPROTO;
+ goto out_disable;
+ }
+
+ switch (rsp.value) {
+ case DLN2_GPIO_DIRECTION_IN:
+ clear_bit(offset, dln2->output_enabled);
+ return 0;
+ case DLN2_GPIO_DIRECTION_OUT:
+ set_bit(offset, dln2->output_enabled);
+ return 0;
+ default:
+ ret = -EPROTO;
+ goto out_disable;
+ }
+
+out_disable:
+ dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_DISABLE, offset);
+ return ret;
+}
+
+static void dln2_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+
+ dln2_gpio_pin_cmd(dln2, DLN2_GPIO_PIN_DISABLE, offset);
+}
+
+static int dln2_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+
+ if (test_bit(offset, dln2->output_enabled))
+ return GPIOF_DIR_OUT;
+
+ return GPIOF_DIR_IN;
+}
+
+static int dln2_gpio_get(struct gpio_chip *chip, unsigned int offset)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ int dir;
+
+ dir = dln2_gpio_get_direction(chip, offset);
+ if (dir < 0)
+ return dir;
+
+ if (dir == GPIOF_DIR_IN)
+ return dln2_gpio_pin_get_in_val(dln2, offset);
+
+ return dln2_gpio_pin_get_out_val(dln2, offset);
+}
+
+static void dln2_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+
+ dln2_gpio_pin_set_out_val(dln2, offset, value);
+}
+
+static int dln2_gpio_set_direction(struct gpio_chip *chip, unsigned offset,
+ unsigned dir)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ struct dln2_gpio_pin_val req = {
+ .pin = cpu_to_le16(offset),
+ .value = dir,
+ };
+ int ret;
+
+ ret = dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_DIRECTION,
+ &req, sizeof(req));
+ if (ret < 0)
+ return ret;
+
+ if (dir == DLN2_GPIO_DIRECTION_OUT)
+ set_bit(offset, dln2->output_enabled);
+ else
+ clear_bit(offset, dln2->output_enabled);
+
+ return ret;
+}
+
+static int dln2_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_IN);
+}
+
+static int dln2_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ return dln2_gpio_set_direction(chip, offset, DLN2_GPIO_DIRECTION_OUT);
+}
+
+static int dln2_gpio_set_debounce(struct gpio_chip *chip, unsigned offset,
+ unsigned debounce)
+{
+ struct dln2_gpio *dln2 = container_of(chip, struct dln2_gpio, gpio);
+ __le32 duration = cpu_to_le32(debounce);
+
+ return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_SET_DEBOUNCE,
+ &duration, sizeof(duration));
+}
+
+static int dln2_gpio_set_event_cfg(struct dln2_gpio *dln2, unsigned pin,
+ unsigned type, unsigned period)
+{
+ struct {
+ __le16 pin;
+ u8 type;
+ __le16 period;
+ } __packed req = {
+ .pin = cpu_to_le16(pin),
+ .type = type,
+ .period = cpu_to_le16(period),
+ };
+
+ return dln2_transfer_tx(dln2->pdev, DLN2_GPIO_PIN_SET_EVENT_CFG,
+ &req, sizeof(req));
+}
+
+static void dln2_irq_work(struct work_struct *w)
+{
+ struct dln2_irq_work *iw = container_of(w, struct dln2_irq_work, work);
+ struct dln2_gpio *dln2 = iw->dln2;
+ u8 type = iw->type & DLN2_GPIO_EVENT_MASK;
+
+ if (test_bit(iw->pin, dln2->irqs_enabled))
+ dln2_gpio_set_event_cfg(dln2, iw->pin, type, 0);
+ else
+ dln2_gpio_set_event_cfg(dln2, iw->pin, DLN2_GPIO_EVENT_NONE, 0);
+}
+
+static void dln2_irq_enable(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ int pin = irqd_to_hwirq(irqd);
+
+ set_bit(pin, dln2->irqs_enabled);
+ schedule_work(&dln2->irq_work[pin].work);
+}
+
+static void dln2_irq_disable(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ int pin = irqd_to_hwirq(irqd);
+
+ clear_bit(pin, dln2->irqs_enabled);
+ schedule_work(&dln2->irq_work[pin].work);
+}
+
+static void dln2_irq_mask(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ int pin = irqd_to_hwirq(irqd);
+
+ set_bit(pin, dln2->irqs_masked);
+}
+
+static void dln2_irq_unmask(struct irq_data *irqd)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ struct device *dev = dln2->gpio.dev;
+ int pin = irqd_to_hwirq(irqd);
+
+ if (test_and_clear_bit(pin, dln2->irqs_pending)) {
+ int irq;
+
+ irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
+ if (!irq) {
+ dev_err(dev, "pin %d not mapped to IRQ\n", pin);
+ return;
+ }
+
+ generic_handle_irq(irq);
+ }
+}
+
+static int dln2_irq_set_type(struct irq_data *irqd, unsigned type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(irqd);
+ struct dln2_gpio *dln2 = container_of(gc, struct dln2_gpio, gpio);
+ int pin = irqd_to_hwirq(irqd);
+
+ switch (type) {
+ case IRQ_TYPE_LEVEL_HIGH:
+ dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_HIGH;
+ break;
+ case IRQ_TYPE_LEVEL_LOW:
+ dln2->irq_work[pin].type = DLN2_GPIO_EVENT_LVL_LOW;
+ break;
+ case IRQ_TYPE_EDGE_BOTH:
+ dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE;
+ break;
+ case IRQ_TYPE_EDGE_RISING:
+ dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_RISING;
+ break;
+ case IRQ_TYPE_EDGE_FALLING:
+ dln2->irq_work[pin].type = DLN2_GPIO_EVENT_CHANGE_FALLING;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct irq_chip dln2_gpio_irqchip = {
+ .name = "dln2-irq",
+ .irq_enable = dln2_irq_enable,
+ .irq_disable = dln2_irq_disable,
+ .irq_mask = dln2_irq_mask,
+ .irq_unmask = dln2_irq_unmask,
+ .irq_set_type = dln2_irq_set_type,
+};
+
+static void dln2_gpio_event(struct platform_device *pdev, u16 echo,
+ const void *data, int len)
+{
+ int pin, irq;
+ const struct {
+ __le16 count;
+ __u8 type;
+ __le16 pin;
+ __u8 value;
+ } __packed *event = data;
+ struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
+
+ if (len < sizeof(*event)) {
+ dev_err(dln2->gpio.dev, "short event message\n");
+ return;
+ }
+
+ pin = le16_to_cpu(event->pin);
+ if (pin >= dln2->gpio.ngpio) {
+ dev_err(dln2->gpio.dev, "out of bounds pin %d\n", pin);
+ return;
+ }
+
+ irq = irq_find_mapping(dln2->gpio.irqdomain, pin);
+ if (!irq) {
+ dev_err(dln2->gpio.dev, "pin %d not mapped to IRQ\n", pin);
+ return;
+ }
+
+ if (!test_bit(pin, dln2->irqs_enabled))
+ return;
+ if (test_bit(pin, dln2->irqs_masked)) {
+ set_bit(pin, dln2->irqs_pending);
+ return;
+ }
+
+ switch (dln2->irq_work[pin].type) {
+ case DLN2_GPIO_EVENT_CHANGE_RISING:
+ if (event->value)
+ generic_handle_irq(irq);
+ break;
+ case DLN2_GPIO_EVENT_CHANGE_FALLING:
+ if (!event->value)
+ generic_handle_irq(irq);
+ break;
+ default:
+ generic_handle_irq(irq);
+ }
+}
+
+static int dln2_gpio_probe(struct platform_device *pdev)
+{
+ struct dln2_gpio *dln2;
+ struct device *dev = &pdev->dev;
+ int pins;
+ int i, ret;
+
+ pins = dln2_gpio_get_pin_count(pdev);
+ if (pins < 0) {
+ dev_err(dev, "failed to get pin count: %d\n", pins);
+ return pins;
+ }
+ if (pins > DLN2_GPIO_MAX_PINS) {
+ pins = DLN2_GPIO_MAX_PINS;
+ dev_warn(dev, "clamping pins to %d\n", DLN2_GPIO_MAX_PINS);
+ }
+
+ dln2 = devm_kzalloc(&pdev->dev, sizeof(*dln2), GFP_KERNEL);
+ if (!dln2)
+ return -ENOMEM;
+
+ dln2->irq_work = devm_kcalloc(&pdev->dev, pins,
+ sizeof(struct dln2_irq_work), GFP_KERNEL);
+ if (!dln2->irq_work)
+ return -ENOMEM;
+ for (i = 0; i < pins; i++) {
+ INIT_WORK(&dln2->irq_work[i].work, dln2_irq_work);
+ dln2->irq_work[i].pin = i;
+ dln2->irq_work[i].dln2 = dln2;
+ }
+
+ dln2->pdev = pdev;
+
+ dln2->gpio.label = "dln2";
+ dln2->gpio.dev = dev;
+ dln2->gpio.owner = THIS_MODULE;
+ dln2->gpio.base = -1;
+ dln2->gpio.ngpio = pins;
+ dln2->gpio.exported = true;
+ dln2->gpio.can_sleep = true;
+ dln2->gpio.irq_not_threaded = true;
+ dln2->gpio.set = dln2_gpio_set;
+ dln2->gpio.get = dln2_gpio_get;
+ dln2->gpio.request = dln2_gpio_request;
+ dln2->gpio.free = dln2_gpio_free;
+ dln2->gpio.get_direction = dln2_gpio_get_direction;
+ dln2->gpio.direction_input = dln2_gpio_direction_input;
+ dln2->gpio.direction_output = dln2_gpio_direction_output;
+ dln2->gpio.set_debounce = dln2_gpio_set_debounce;
+
+ platform_set_drvdata(pdev, dln2);
+
+ ret = gpiochip_add(&dln2->gpio);
+ if (ret < 0) {
+ dev_err(dev, "failed to add gpio chip: %d\n", ret);
+ goto out;
+ }
+
+ ret = gpiochip_irqchip_add(&dln2->gpio, &dln2_gpio_irqchip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+ if (ret < 0) {
+ dev_err(dev, "failed to add irq chip: %d\n", ret);
+ goto out_gpiochip_remove;
+ }
+
+ ret = dln2_register_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV,
+ dln2_gpio_event);
+ if (ret) {
+ dev_err(dev, "failed to register event cb: %d\n", ret);
+ goto out_gpiochip_remove;
+ }
+
+ return 0;
+
+out_gpiochip_remove:
+ gpiochip_remove(&dln2->gpio);
+out:
+ return ret;
+}
+
+static int dln2_gpio_remove(struct platform_device *pdev)
+{
+ struct dln2_gpio *dln2 = platform_get_drvdata(pdev);
+ int i;
+
+ dln2_unregister_event_cb(pdev, DLN2_GPIO_CONDITION_MET_EV);
+ for (i = 0; i < dln2->gpio.ngpio; i++)
+ flush_work(&dln2->irq_work[i].work);
+ gpiochip_remove(&dln2->gpio);
+
+ return 0;
+}
+
+static struct platform_driver dln2_gpio_driver = {
+ .driver.name = "dln2-gpio",
+ .probe = dln2_gpio_probe,
+ .remove = dln2_gpio_remove,
+};
+
+module_platform_driver(dln2_gpio_driver);
+
+MODULE_AUTHOR("Daniel Baluta <daniel.baluta@intel.com");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 GPIO interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dln2-gpio");
diff --git a/drivers/gpio/gpio-omap.c b/drivers/gpio/gpio-omap.c
index 415682f..3d6b445 100644
--- a/drivers/gpio/gpio-omap.c
+++ b/drivers/gpio/gpio-omap.c
@@ -1259,7 +1259,7 @@ static int omap_gpio_probe(struct platform_device *pdev)
#ifdef CONFIG_ARCH_OMAP2PLUS
-#if defined(CONFIG_PM_RUNTIME)
+#if defined(CONFIG_PM)
static void omap_gpio_restore_context(struct gpio_bank *bank);
static int omap_gpio_runtime_suspend(struct device *dev)
@@ -1440,7 +1440,7 @@ static int omap_gpio_runtime_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
void omap2_gpio_prepare_for_idle(int pwr_mode)
{
@@ -1468,7 +1468,7 @@ void omap2_gpio_resume_after_idle(void)
}
}
-#if defined(CONFIG_PM_RUNTIME)
+#if defined(CONFIG_PM)
static void omap_gpio_init_context(struct gpio_bank *p)
{
struct omap_gpio_reg_offs *regs = p->regs;
@@ -1525,7 +1525,7 @@ static void omap_gpio_restore_context(struct gpio_bank *bank)
writel_relaxed(bank->context.irqenable2,
bank->base + bank->regs->irqenable2);
}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
#else
#define omap_gpio_runtime_suspend NULL
#define omap_gpio_runtime_resume NULL
diff --git a/drivers/gpio/gpio-sch.c b/drivers/gpio/gpio-sch.c
index 41e91d7..99720c8 100644
--- a/drivers/gpio/gpio-sch.c
+++ b/drivers/gpio/gpio-sch.c
@@ -29,290 +29,221 @@
#include <linux/gpio.h>
-static DEFINE_SPINLOCK(gpio_lock);
-
-#define CGEN (0x00)
-#define CGIO (0x04)
-#define CGLV (0x08)
-
-#define RGEN (0x20)
-#define RGIO (0x24)
-#define RGLV (0x28)
-
-static unsigned short gpio_ba;
-
-static int sch_gpio_core_direction_in(struct gpio_chip *gc, unsigned gpio_num)
-{
- u8 curr_dirs;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
-
- if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+#define GEN 0x00
+#define GIO 0x04
+#define GLV 0x08
+
+struct sch_gpio {
+ struct gpio_chip chip;
+ spinlock_t lock;
+ unsigned short iobase;
+ unsigned short core_base;
+ unsigned short resume_base;
+};
- spin_unlock(&gpio_lock);
- return 0;
-}
+#define to_sch_gpio(c) container_of(c, struct sch_gpio, chip)
-static int sch_gpio_core_get(struct gpio_chip *gc, unsigned gpio_num)
+static unsigned sch_gpio_offset(struct sch_gpio *sch, unsigned gpio,
+ unsigned reg)
{
- int res;
- unsigned short offset, bit;
+ unsigned base = 0;
- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ if (gpio >= sch->resume_base) {
+ gpio -= sch->resume_base;
+ base += 0x20;
+ }
- res = !!(inb(gpio_ba + offset) & (1 << bit));
- return res;
+ return base + reg + gpio / 8;
}
-static void sch_gpio_core_set(struct gpio_chip *gc, unsigned gpio_num, int val)
+static unsigned sch_gpio_bit(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_vals;
- unsigned short offset, bit;
-
- spin_lock(&gpio_lock);
-
- offset = CGLV + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_vals = inb(gpio_ba + offset);
-
- if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
- else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
- spin_unlock(&gpio_lock);
+ if (gpio >= sch->resume_base)
+ gpio -= sch->resume_base;
+ return gpio % 8;
}
-static int sch_gpio_core_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_enable(struct sch_gpio *sch, unsigned gpio)
{
- u8 curr_dirs;
unsigned short offset, bit;
+ u8 enable;
- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);
- offset = CGIO + gpio_num / 8;
- bit = gpio_num % 8;
-
- curr_dirs = inb(gpio_ba + offset);
- if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ offset = sch_gpio_offset(sch, gpio, GEN);
+ bit = sch_gpio_bit(sch, gpio);
- spin_unlock(&gpio_lock);
+ enable = inb(sch->iobase + offset);
+ if (!(enable & (1 << bit)))
+ outb(enable | (1 << bit), sch->iobase + offset);
- /*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_core_set(gc, gpio_num, val);
- return 0;
+ spin_unlock(&sch->lock);
}
-static struct gpio_chip sch_gpio_core = {
- .label = "sch_gpio_core",
- .owner = THIS_MODULE,
- .direction_input = sch_gpio_core_direction_in,
- .get = sch_gpio_core_get,
- .direction_output = sch_gpio_core_direction_out,
- .set = sch_gpio_core_set,
-};
-
-static int sch_gpio_resume_direction_in(struct gpio_chip *gc,
- unsigned gpio_num)
+static int sch_gpio_direction_in(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;
- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);
- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);
- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);
if (!(curr_dirs & (1 << bit)))
- outb(curr_dirs | (1 << bit), gpio_ba + offset);
+ outb(curr_dirs | (1 << bit), sch->iobase + offset);
- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
return 0;
}
-static int sch_gpio_resume_get(struct gpio_chip *gc, unsigned gpio_num)
+static int sch_gpio_get(struct gpio_chip *gc, unsigned gpio_num)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
+ int res;
unsigned short offset, bit;
- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);
+
+ res = !!(inb(sch->iobase + offset) & (1 << bit));
- return !!(inb(gpio_ba + offset) & (1 << bit));
+ return res;
}
-static void sch_gpio_resume_set(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static void sch_gpio_set(struct gpio_chip *gc, unsigned gpio_num, int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_vals;
unsigned short offset, bit;
- spin_lock(&gpio_lock);
+ spin_lock(&sch->lock);
- offset = RGLV + gpio_num / 8;
- bit = gpio_num % 8;
+ offset = sch_gpio_offset(sch, gpio_num, GLV);
+ bit = sch_gpio_bit(sch, gpio_num);
- curr_vals = inb(gpio_ba + offset);
+ curr_vals = inb(sch->iobase + offset);
if (val)
- outb(curr_vals | (1 << bit), gpio_ba + offset);
+ outb(curr_vals | (1 << bit), sch->iobase + offset);
else
- outb((curr_vals & ~(1 << bit)), gpio_ba + offset);
+ outb((curr_vals & ~(1 << bit)), sch->iobase + offset);
- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
}
-static int sch_gpio_resume_direction_out(struct gpio_chip *gc,
- unsigned gpio_num, int val)
+static int sch_gpio_direction_out(struct gpio_chip *gc, unsigned gpio_num,
+ int val)
{
+ struct sch_gpio *sch = to_sch_gpio(gc);
u8 curr_dirs;
unsigned short offset, bit;
- offset = RGIO + gpio_num / 8;
- bit = gpio_num % 8;
+ spin_lock(&sch->lock);
- spin_lock(&gpio_lock);
+ offset = sch_gpio_offset(sch, gpio_num, GIO);
+ bit = sch_gpio_bit(sch, gpio_num);
- curr_dirs = inb(gpio_ba + offset);
+ curr_dirs = inb(sch->iobase + offset);
if (curr_dirs & (1 << bit))
- outb(curr_dirs & ~(1 << bit), gpio_ba + offset);
+ outb(curr_dirs & ~(1 << bit), sch->iobase + offset);
- spin_unlock(&gpio_lock);
+ spin_unlock(&sch->lock);
/*
- * according to the datasheet, writing to the level register has no
- * effect when GPIO is programmed as input.
- * Actually the the level register is read-only when configured as input.
- * Thus presetting the output level before switching to output is _NOT_ possible.
- * Hence we set the level after configuring the GPIO as output.
- * But we cannot prevent a short low pulse if direction is set to high
- * and an external pull-up is connected.
- */
- sch_gpio_resume_set(gc, gpio_num, val);
+ * according to the datasheet, writing to the level register has no
+ * effect when GPIO is programmed as input.
+ * Actually the the level register is read-only when configured as input.
+ * Thus presetting the output level before switching to output is _NOT_ possible.
+ * Hence we set the level after configuring the GPIO as output.
+ * But we cannot prevent a short low pulse if direction is set to high
+ * and an external pull-up is connected.
+ */
+ sch_gpio_set(gc, gpio_num, val);
return 0;
}
-static struct gpio_chip sch_gpio_resume = {
- .label = "sch_gpio_resume",
+static struct gpio_chip sch_gpio_chip = {
+ .label = "sch_gpio",
.owner = THIS_MODULE,
- .direction_input = sch_gpio_resume_direction_in,
- .get = sch_gpio_resume_get,
- .direction_output = sch_gpio_resume_direction_out,
- .set = sch_gpio_resume_set,
+ .direction_input = sch_gpio_direction_in,
+ .get = sch_gpio_get,
+ .direction_output = sch_gpio_direction_out,
+ .set = sch_gpio_set,
};
static int sch_gpio_probe(struct platform_device *pdev)
{
+ struct sch_gpio *sch;
struct resource *res;
- int err, id;
- id = pdev->id;
- if (!id)
- return -ENODEV;
+ sch = devm_kzalloc(&pdev->dev, sizeof(*sch), GFP_KERNEL);
+ if (!sch)
+ return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_IO, 0);
if (!res)
return -EBUSY;
- if (!request_region(res->start, resource_size(res), pdev->name))
+ if (!devm_request_region(&pdev->dev, res->start, resource_size(res),
+ pdev->name))
return -EBUSY;
- gpio_ba = res->start;
+ spin_lock_init(&sch->lock);
+ sch->iobase = res->start;
+ sch->chip = sch_gpio_chip;
+ sch->chip.label = dev_name(&pdev->dev);
+ sch->chip.dev = &pdev->dev;
- switch (id) {
+ switch (pdev->id) {
case PCI_DEVICE_ID_INTEL_SCH_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 10;
- sch_gpio_resume.base = 10;
- sch_gpio_resume.ngpio = 4;
+ sch->core_base = 0;
+ sch->resume_base = 10;
+ sch->chip.ngpio = 14;
+
/*
* GPIO[6:0] enabled by default
* GPIO7 is configured by the CMC as SLPIOVR
* Enable GPIO[9:8] core powered gpios explicitly
*/
- outb(0x3, gpio_ba + CGEN + 1);
+ sch_gpio_enable(sch, 8);
+ sch_gpio_enable(sch, 9);
/*
* SUS_GPIO[2:0] enabled by default
* Enable SUS_GPIO3 resume powered gpio explicitly
*/
- outb(0x8, gpio_ba + RGEN);
+ sch_gpio_enable(sch, 13);
break;
case PCI_DEVICE_ID_INTEL_ITC_LPC:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 5;
- sch_gpio_resume.base = 5;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 5;
+ sch->chip.ngpio = 14;
break;
case PCI_DEVICE_ID_INTEL_CENTERTON_ILB:
- sch_gpio_core.base = 0;
- sch_gpio_core.ngpio = 21;
- sch_gpio_resume.base = 21;
- sch_gpio_resume.ngpio = 9;
+ sch->core_base = 0;
+ sch->resume_base = 21;
+ sch->chip.ngpio = 30;
break;
default:
- err = -ENODEV;
- goto err_sch_gpio_core;
+ return -ENODEV;
}
- sch_gpio_core.dev = &pdev->dev;
- sch_gpio_resume.dev = &pdev->dev;
-
- err = gpiochip_add(&sch_gpio_core);
- if (err < 0)
- goto err_sch_gpio_core;
+ platform_set_drvdata(pdev, sch);
- err = gpiochip_add(&sch_gpio_resume);
- if (err < 0)
- goto err_sch_gpio_resume;
-
- return 0;
-
-err_sch_gpio_resume:
- gpiochip_remove(&sch_gpio_core);
-
-err_sch_gpio_core:
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
-
- return err;
+ return gpiochip_add(&sch->chip);
}
static int sch_gpio_remove(struct platform_device *pdev)
{
- struct resource *res;
- if (gpio_ba) {
-
- gpiochip_remove(&sch_gpio_core);
- gpiochip_remove(&sch_gpio_resume);
-
- res = platform_get_resource(pdev, IORESOURCE_IO, 0);
-
- release_region(res->start, resource_size(res));
- gpio_ba = 0;
- }
+ struct sch_gpio *sch = platform_get_drvdata(pdev);
+ gpiochip_remove(&sch->chip);
return 0;
}
diff --git a/drivers/gpio/gpio-tc3589x.c b/drivers/gpio/gpio-tc3589x.c
index ae0f646..abdcf58 100644
--- a/drivers/gpio/gpio-tc3589x.c
+++ b/drivers/gpio/gpio-tc3589x.c
@@ -262,7 +262,7 @@ static int tc3589x_gpio_probe(struct platform_device *pdev)
tc3589x_gpio->chip = template_chip;
tc3589x_gpio->chip.ngpio = tc3589x->num_gpio;
tc3589x_gpio->chip.dev = &pdev->dev;
- tc3589x_gpio->chip.base = (pdata) ? pdata->gpio_base : -1;
+ tc3589x_gpio->chip.base = -1;
#ifdef CONFIG_OF_GPIO
tc3589x_gpio->chip.of_node = np;
diff --git a/drivers/gpio/gpio-tz1090.c b/drivers/gpio/gpio-tz1090.c
index 5246a60..6107d06 100644
--- a/drivers/gpio/gpio-tz1090.c
+++ b/drivers/gpio/gpio-tz1090.c
@@ -446,7 +446,7 @@ static int tz1090_gpio_bank_probe(struct tz1090_gpio_bank_info *info)
bank->irq = irq_of_parse_and_map(np, 0);
/* The interrupt is optional (it may be used by another core on chip) */
- if (bank->irq < 0) {
+ if (!bank->irq) {
dev_info(dev, "IRQ not provided for bank %u, IRQs disabled\n",
info->index);
return 0;
diff --git a/drivers/gpio/gpio-zynq.c b/drivers/gpio/gpio-zynq.c
index 74cd480..184c4b1 100644
--- a/drivers/gpio/gpio-zynq.c
+++ b/drivers/gpio/gpio-zynq.c
@@ -578,7 +578,7 @@ static void zynq_gpio_free(struct gpio_chip *chip, unsigned offset)
static const struct dev_pm_ops zynq_gpio_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(zynq_gpio_suspend, zynq_gpio_resume)
- SET_PM_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend,
+ SET_RUNTIME_PM_OPS(zynq_gpio_runtime_suspend,
zynq_gpio_runtime_resume, NULL)
};
diff --git a/drivers/gpio/gpiolib-acpi.c b/drivers/gpio/gpiolib-acpi.c
index 05c6275..c3bdaff 100644
--- a/drivers/gpio/gpiolib-acpi.c
+++ b/drivers/gpio/gpiolib-acpi.c
@@ -11,12 +11,14 @@
*/
#include <linux/errno.h>
+#include <linux/gpio.h>
#include <linux/gpio/consumer.h>
#include <linux/gpio/driver.h>
#include <linux/export.h>
#include <linux/acpi.h>
#include <linux/interrupt.h>
#include <linux/mutex.h>
+#include <linux/pinctrl/pinctrl.h>
#include "gpiolib.h"
@@ -55,6 +57,58 @@ static int acpi_gpiochip_find(struct gpio_chip *gc, void *data)
return ACPI_HANDLE(gc->dev) == data;
}
+#ifdef CONFIG_PINCTRL
+/**
+ * acpi_gpiochip_pin_to_gpio_offset() - translates ACPI GPIO to Linux GPIO
+ * @chip: GPIO chip
+ * @pin: ACPI GPIO pin number from GpioIo/GpioInt resource
+ *
+ * Function takes ACPI GpioIo/GpioInt pin number as a parameter and
+ * translates it to a corresponding offset suitable to be passed to a
+ * GPIO controller driver.
+ *
+ * Typically the returned offset is same as @pin, but if the GPIO
+ * controller uses pin controller and the mapping is not contigous the
+ * offset might be different.
+ */
+static int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip, int pin)
+{
+ struct gpio_pin_range *pin_range;
+
+ /* If there are no ranges in this chip, use 1:1 mapping */
+ if (list_empty(&chip->pin_ranges))
+ return pin;
+
+ list_for_each_entry(pin_range, &chip->pin_ranges, node) {
+ const struct pinctrl_gpio_range *range = &pin_range->range;
+ int i;
+
+ if (range->pins) {
+ for (i = 0; i < range->npins; i++) {
+ if (range->pins[i] == pin)
+ return range->base + i - chip->base;
+ }
+ } else {
+ if (pin >= range->pin_base &&
+ pin < range->pin_base + range->npins) {
+ unsigned gpio_base;
+
+ gpio_base = range->base - chip->base;
+ return gpio_base + pin - range->pin_base;
+ }
+ }
+ }
+
+ return -EINVAL;
+}
+#else
+static inline int acpi_gpiochip_pin_to_gpio_offset(struct gpio_chip *chip,
+ int pin)
+{
+ return pin;
+}
+#endif
+
/**
* acpi_get_gpiod() - Translate ACPI GPIO pin to GPIO descriptor usable with GPIO API
* @path: ACPI GPIO controller full path name, (e.g. "\\_SB.GPO1")
@@ -69,6 +123,7 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
struct gpio_chip *chip;
acpi_handle handle;
acpi_status status;
+ int offset;
status = acpi_get_handle(NULL, path, &handle);
if (ACPI_FAILURE(status))
@@ -78,10 +133,11 @@ static struct gpio_desc *acpi_get_gpiod(char *path, int pin)
if (!chip)
return ERR_PTR(-ENODEV);
- if (pin < 0 || pin > chip->ngpio)
- return ERR_PTR(-EINVAL);
+ offset = acpi_gpiochip_pin_to_gpio_offset(chip, pin);
+ if (offset < 0)
+ return ERR_PTR(offset);
- return gpiochip_get_desc(chip, pin);
+ return gpiochip_get_desc(chip, offset);
}
static irqreturn_t acpi_gpio_irq_handler(int irq, void *data)
@@ -287,9 +343,45 @@ void acpi_gpiochip_free_interrupts(struct gpio_chip *chip)
}
}
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios)
+{
+ if (adev && gpios) {
+ adev->driver_gpios = gpios;
+ return 0;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL_GPL(acpi_dev_add_driver_gpios);
+
+static bool acpi_get_driver_gpio_data(struct acpi_device *adev,
+ const char *name, int index,
+ struct acpi_reference_args *args)
+{
+ const struct acpi_gpio_mapping *gm;
+
+ if (!adev->driver_gpios)
+ return false;
+
+ for (gm = adev->driver_gpios; gm->name; gm++)
+ if (!strcmp(name, gm->name) && gm->data && index < gm->size) {
+ const struct acpi_gpio_params *par = gm->data + index;
+
+ args->adev = adev;
+ args->args[0] = par->crs_entry_index;
+ args->args[1] = par->line_index;
+ args->args[2] = par->active_low;
+ args->nargs = 3;
+ return true;
+ }
+
+ return false;
+}
+
struct acpi_gpio_lookup {
struct acpi_gpio_info info;
int index;
+ int pin_index;
struct gpio_desc *desc;
int n;
};
@@ -303,13 +395,24 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
if (lookup->n++ == lookup->index && !lookup->desc) {
const struct acpi_resource_gpio *agpio = &ares->data.gpio;
+ int pin_index = lookup->pin_index;
+
+ if (pin_index >= agpio->pin_table_length)
+ return 1;
lookup->desc = acpi_get_gpiod(agpio->resource_source.string_ptr,
- agpio->pin_table[0]);
+ agpio->pin_table[pin_index]);
lookup->info.gpioint =
agpio->connection_type == ACPI_RESOURCE_GPIO_TYPE_INT;
- lookup->info.active_low =
- agpio->polarity == ACPI_ACTIVE_LOW;
+
+ /*
+ * ActiveLow is only specified for GpioInt resource. If
+ * GpioIo is used then the only way to set the flag is
+ * to use _DSD "gpios" property.
+ */
+ if (lookup->info.gpioint)
+ lookup->info.active_low =
+ agpio->polarity == ACPI_ACTIVE_LOW;
}
return 1;
@@ -317,40 +420,79 @@ static int acpi_find_gpio(struct acpi_resource *ares, void *data)
/**
* acpi_get_gpiod_by_index() - get a GPIO descriptor from device resources
- * @dev: pointer to a device to get GPIO from
+ * @adev: pointer to a ACPI device to get GPIO from
+ * @propname: Property name of the GPIO (optional)
* @index: index of GpioIo/GpioInt resource (starting from %0)
* @info: info pointer to fill in (optional)
*
- * Function goes through ACPI resources for @dev and based on @index looks
+ * Function goes through ACPI resources for @adev and based on @index looks
* up a GpioIo/GpioInt resource, translates it to the Linux GPIO descriptor,
* and returns it. @index matches GpioIo/GpioInt resources only so if there
* are total %3 GPIO resources, the index goes from %0 to %2.
*
+ * If @propname is specified the GPIO is looked using device property. In
+ * that case @index is used to select the GPIO entry in the property value
+ * (in case of multiple).
+ *
* If the GPIO cannot be translated or there is an error an ERR_PTR is
* returned.
*
* Note: if the GPIO resource has multiple entries in the pin list, this
* function only returns the first.
*/
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info)
{
struct acpi_gpio_lookup lookup;
struct list_head resource_list;
- struct acpi_device *adev;
- acpi_handle handle;
+ bool active_low = false;
int ret;
- if (!dev)
- return ERR_PTR(-EINVAL);
-
- handle = ACPI_HANDLE(dev);
- if (!handle || acpi_bus_get_device(handle, &adev))
+ if (!adev)
return ERR_PTR(-ENODEV);
memset(&lookup, 0, sizeof(lookup));
lookup.index = index;
+ if (propname) {
+ struct acpi_reference_args args;
+
+ dev_dbg(&adev->dev, "GPIO: looking up %s\n", propname);
+
+ memset(&args, 0, sizeof(args));
+ ret = acpi_dev_get_property_reference(adev, propname,
+ index, &args);
+ if (ret) {
+ bool found = acpi_get_driver_gpio_data(adev, propname,
+ index, &args);
+ if (!found)
+ return ERR_PTR(ret);
+ }
+
+ /*
+ * The property was found and resolved so need to
+ * lookup the GPIO based on returned args instead.
+ */
+ adev = args.adev;
+ if (args.nargs >= 2) {
+ lookup.index = args.args[0];
+ lookup.pin_index = args.args[1];
+ /*
+ * 3rd argument, if present is used to
+ * specify active_low.
+ */
+ if (args.nargs >= 3)
+ active_low = !!args.args[2];
+ }
+
+ dev_dbg(&adev->dev, "GPIO: _DSD returned %s %zd %llu %llu %llu\n",
+ dev_name(&adev->dev), args.nargs,
+ args.args[0], args.args[1], args.args[2]);
+ } else {
+ dev_dbg(&adev->dev, "GPIO: looking up %d in _CRS\n", index);
+ }
+
INIT_LIST_HEAD(&resource_list);
ret = acpi_dev_get_resources(adev, &resource_list, acpi_find_gpio,
&lookup);
@@ -359,8 +501,11 @@ struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
acpi_dev_free_resource_list(&resource_list);
- if (lookup.desc && info)
+ if (lookup.desc && info) {
*info = lookup.info;
+ if (active_low)
+ info->active_low = active_low;
+ }
return lookup.desc ? lookup.desc : ERR_PTR(-ENOENT);
}
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index e8e98ca..58659db 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1505,14 +1505,36 @@ static struct gpio_desc *acpi_find_gpio(struct device *dev, const char *con_id,
unsigned int idx,
enum gpio_lookup_flags *flags)
{
+ static const char * const suffixes[] = { "gpios", "gpio" };
+ struct acpi_device *adev = ACPI_COMPANION(dev);
struct acpi_gpio_info info;
struct gpio_desc *desc;
+ char propname[32];
+ int i;
- desc = acpi_get_gpiod_by_index(dev, idx, &info);
- if (IS_ERR(desc))
- return desc;
+ /* Try first from _DSD */
+ for (i = 0; i < ARRAY_SIZE(suffixes); i++) {
+ if (con_id && strcmp(con_id, "gpios")) {
+ snprintf(propname, sizeof(propname), "%s-%s",
+ con_id, suffixes[i]);
+ } else {
+ snprintf(propname, sizeof(propname), "%s",
+ suffixes[i]);
+ }
+
+ desc = acpi_get_gpiod_by_index(adev, propname, idx, &info);
+ if (!IS_ERR(desc) || (PTR_ERR(desc) == -EPROBE_DEFER))
+ break;
+ }
- if (info.gpioint && info.active_low)
+ /* Then from plain _CRS GPIOs */
+ if (IS_ERR(desc)) {
+ desc = acpi_get_gpiod_by_index(adev, NULL, idx, &info);
+ if (IS_ERR(desc))
+ return desc;
+ }
+
+ if (info.active_low)
*flags |= GPIO_ACTIVE_LOW;
return desc;
@@ -1713,6 +1735,61 @@ struct gpio_desc *__must_check __gpiod_get_index(struct device *dev,
EXPORT_SYMBOL_GPL(__gpiod_get_index);
/**
+ * fwnode_get_named_gpiod - obtain a GPIO from firmware node
+ * @fwnode: handle of the firmware node
+ * @propname: name of the firmware property representing the GPIO
+ *
+ * This function can be used for drivers that get their configuration
+ * from firmware.
+ *
+ * Function properly finds the corresponding GPIO using whatever is the
+ * underlying firmware interface and then makes sure that the GPIO
+ * descriptor is requested before it is returned to the caller.
+ *
+ * In case of error an ERR_PTR() is returned.
+ */
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname)
+{
+ struct gpio_desc *desc = ERR_PTR(-ENODEV);
+ bool active_low = false;
+ int ret;
+
+ if (!fwnode)
+ return ERR_PTR(-EINVAL);
+
+ if (is_of_node(fwnode)) {
+ enum of_gpio_flags flags;
+
+ desc = of_get_named_gpiod_flags(of_node(fwnode), propname, 0,
+ &flags);
+ if (!IS_ERR(desc))
+ active_low = flags & OF_GPIO_ACTIVE_LOW;
+ } else if (is_acpi_node(fwnode)) {
+ struct acpi_gpio_info info;
+
+ desc = acpi_get_gpiod_by_index(acpi_node(fwnode), propname, 0,
+ &info);
+ if (!IS_ERR(desc))
+ active_low = info.active_low;
+ }
+
+ if (IS_ERR(desc))
+ return desc;
+
+ ret = gpiod_request(desc, NULL);
+ if (ret)
+ return ERR_PTR(ret);
+
+ /* Only value flag can be set from both DT and ACPI is active_low */
+ if (active_low)
+ set_bit(FLAG_ACTIVE_LOW, &desc->flags);
+
+ return desc;
+}
+EXPORT_SYMBOL_GPL(fwnode_get_named_gpiod);
+
+/**
* gpiod_get_index_optional - obtain an optional GPIO from a multi-index GPIO
* function
* @dev: GPIO consumer, can be NULL for system-global GPIOs
diff --git a/drivers/gpio/gpiolib.h b/drivers/gpio/gpiolib.h
index 9db2b6a..e3a5211 100644
--- a/drivers/gpio/gpiolib.h
+++ b/drivers/gpio/gpiolib.h
@@ -34,7 +34,8 @@ void acpi_gpiochip_remove(struct gpio_chip *chip);
void acpi_gpiochip_request_interrupts(struct gpio_chip *chip);
void acpi_gpiochip_free_interrupts(struct gpio_chip *chip);
-struct gpio_desc *acpi_get_gpiod_by_index(struct device *dev, int index,
+struct gpio_desc *acpi_get_gpiod_by_index(struct acpi_device *adev,
+ const char *propname, int index,
struct acpi_gpio_info *info);
#else
static inline void acpi_gpiochip_add(struct gpio_chip *chip) { }
@@ -47,8 +48,8 @@ static inline void
acpi_gpiochip_free_interrupts(struct gpio_chip *chip) { }
static inline struct gpio_desc *
-acpi_get_gpiod_by_index(struct device *dev, int index,
- struct acpi_gpio_info *info)
+acpi_get_gpiod_by_index(struct acpi_device *adev, const char *propname,
+ int index, struct acpi_gpio_info *info)
{
return ERR_PTR(-ENOSYS);
}
diff --git a/drivers/gpu/drm/armada/armada_gem.c b/drivers/gpu/drm/armada/armada_gem.c
index 7496f55..ef5feee 100644
--- a/drivers/gpu/drm/armada/armada_gem.c
+++ b/drivers/gpu/drm/armada/armada_gem.c
@@ -226,7 +226,7 @@ struct armada_gem_object *armada_gem_alloc_object(struct drm_device *dev,
obj->dev_addr = DMA_ERROR_CODE;
- mapping = obj->obj.filp->f_path.dentry->d_inode->i_mapping;
+ mapping = file_inode(obj->obj.filp)->i_mapping;
mapping_set_gfp_mask(mapping, GFP_HIGHUSER | __GFP_RECLAIMABLE);
DRM_DEBUG_DRIVER("alloc obj %p size %zu\n", obj, size);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_fimc.c b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
index 68d38eb..835b6af 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_fimc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_fimc.c
@@ -1817,7 +1817,7 @@ static int fimc_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int fimc_runtime_suspend(struct device *dev)
{
struct fimc_context *ctx = get_fimc_context(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_g2d.c b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
index 6ff8599..81a2508 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_g2d.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_g2d.c
@@ -1540,7 +1540,7 @@ static int g2d_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int g2d_runtime_suspend(struct device *dev)
{
struct g2d_data *g2d = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_gsc.c b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
index c6a013f..0261468 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_gsc.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_gsc.c
@@ -1764,7 +1764,7 @@ static int gsc_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int gsc_runtime_suspend(struct device *dev)
{
struct gsc_context *ctx = get_gsc_context(dev);
diff --git a/drivers/gpu/drm/exynos/exynos_drm_rotator.c b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
index b6a37d4..425e706 100644
--- a/drivers/gpu/drm/exynos/exynos_drm_rotator.c
+++ b/drivers/gpu/drm/exynos/exynos_drm_rotator.c
@@ -822,7 +822,7 @@ static int rotator_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int rotator_runtime_suspend(struct device *dev)
{
struct rot_context *rot = dev_get_drvdata(dev);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 8bcdb98..9cb5c95 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -4325,7 +4325,6 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
ironlake_fdi_disable(crtc);
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 */
@@ -4389,7 +4388,6 @@ 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);
}
diff --git a/drivers/gpu/drm/i915/intel_lvds.c b/drivers/gpu/drm/i915/intel_lvds.c
index a6bd142..c0bbf21 100644
--- a/drivers/gpu/drm/i915/intel_lvds.c
+++ b/drivers/gpu/drm/i915/intel_lvds.c
@@ -899,6 +899,17 @@ void intel_lvds_init(struct drm_device *dev)
int pipe;
u8 pin;
+ /*
+ * Unlock registers and just leave them unlocked. Do this before
+ * checking quirk lists to avoid bogus WARNINGs.
+ */
+ if (HAS_PCH_SPLIT(dev)) {
+ I915_WRITE(PCH_PP_CONTROL,
+ I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
+ } else {
+ I915_WRITE(PP_CONTROL,
+ I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
+ }
if (!intel_lvds_supported(dev))
return;
@@ -1097,17 +1108,6 @@ out:
lvds_encoder->a3_power = I915_READ(lvds_encoder->reg) &
LVDS_A3_POWER_MASK;
- /*
- * Unlock registers and just
- * leave them unlocked
- */
- if (HAS_PCH_SPLIT(dev)) {
- I915_WRITE(PCH_PP_CONTROL,
- I915_READ(PCH_PP_CONTROL) | PANEL_UNLOCK_REGS);
- } else {
- I915_WRITE(PP_CONTROL,
- I915_READ(PP_CONTROL) | PANEL_UNLOCK_REGS);
- }
lvds_connector->lid_notifier.notifier_call = intel_lid_notify;
if (acpi_lid_notifier_register(&lvds_connector->lid_notifier)) {
DRM_DEBUG_KMS("lid notifier registration failed\n");
diff --git a/drivers/gpu/ipu-v3/ipu-csi.c b/drivers/gpu/ipu-v3/ipu-csi.c
index d6f56471..752cdd2 100644
--- a/drivers/gpu/ipu-v3/ipu-csi.c
+++ b/drivers/gpu/ipu-v3/ipu-csi.c
@@ -227,83 +227,83 @@ static int ipu_csi_set_testgen_mclk(struct ipu_csi *csi, u32 pixel_clk,
static int mbus_code_to_bus_cfg(struct ipu_csi_bus_config *cfg, u32 mbus_code)
{
switch (mbus_code) {
- case V4L2_MBUS_FMT_BGR565_2X8_BE:
- case V4L2_MBUS_FMT_BGR565_2X8_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_BGR565_2X8_BE:
+ case MEDIA_BUS_FMT_BGR565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB565;
cfg->mipi_dt = MIPI_DT_RGB565;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE:
- case V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB444;
cfg->mipi_dt = MIPI_DT_RGB444;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_RGB555;
cfg->mipi_dt = MIPI_DT_RGB555;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_UYVY;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
break;
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_YUV422_YUYV;
cfg->mipi_dt = MIPI_DT_YUV422;
cfg->data_width = IPU_CSI_DATA_WIDTH_16;
break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SGBRG8_1X8:
- case V4L2_MBUS_FMT_SGRBG8_1X8:
- case V4L2_MBUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW8;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+ case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW10;
cfg->data_width = IPU_CSI_DATA_WIDTH_8;
break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- case V4L2_MBUS_FMT_SGBRG10_1X10:
- case V4L2_MBUS_FMT_SGRBG10_1X10:
- case V4L2_MBUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW10;
cfg->data_width = IPU_CSI_DATA_WIDTH_10;
break;
- case V4L2_MBUS_FMT_SBGGR12_1X12:
- case V4L2_MBUS_FMT_SGBRG12_1X12:
- case V4L2_MBUS_FMT_SGRBG12_1X12:
- case V4L2_MBUS_FMT_SRGGB12_1X12:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
+ case MEDIA_BUS_FMT_SGBRG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_BAYER;
cfg->mipi_dt = MIPI_DT_RAW12;
cfg->data_width = IPU_CSI_DATA_WIDTH_12;
break;
- case V4L2_MBUS_FMT_JPEG_1X8:
+ case MEDIA_BUS_FMT_JPEG_1X8:
/* TODO */
cfg->data_fmt = CSI_SENS_CONF_DATA_FMT_JPEG;
cfg->mipi_dt = MIPI_DT_RAW8;
diff --git a/drivers/hid/hid-sensor-hub.c b/drivers/hid/hid-sensor-hub.c
index e6d8e18..6a58b6c 100644
--- a/drivers/hid/hid-sensor-hub.c
+++ b/drivers/hid/hid-sensor-hub.c
@@ -641,9 +641,6 @@ static int sensor_hub_probe(struct hid_device *hdev,
goto err_stop_hw;
}
sd->hid_sensor_hub_client_devs[
- sd->hid_sensor_client_cnt].id =
- PLATFORM_DEVID_AUTO;
- sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].name = name;
sd->hid_sensor_hub_client_devs[
sd->hid_sensor_client_cnt].platform_data =
@@ -659,8 +656,9 @@ static int sensor_hub_probe(struct hid_device *hdev,
if (last_hsdev)
last_hsdev->end_collection_index = i;
- ret = mfd_add_devices(&hdev->dev, 0, sd->hid_sensor_hub_client_devs,
- sd->hid_sensor_client_cnt, NULL, 0, NULL);
+ ret = mfd_add_hotplug_devices(&hdev->dev,
+ sd->hid_sensor_hub_client_devs,
+ sd->hid_sensor_client_cnt);
if (ret < 0)
goto err_stop_hw;
diff --git a/drivers/hid/i2c-hid/i2c-hid.c b/drivers/hid/i2c-hid/i2c-hid.c
index 747d544..f09e70c 100644
--- a/drivers/hid/i2c-hid/i2c-hid.c
+++ b/drivers/hid/i2c-hid/i2c-hid.c
@@ -1095,7 +1095,7 @@ static int i2c_hid_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int i2c_hid_runtime_suspend(struct device *dev)
{
struct i2c_client *client = to_i2c_client(dev);
diff --git a/drivers/hsi/controllers/omap_ssi.c b/drivers/hsi/controllers/omap_ssi.c
index bf0eace..4d5b682 100644
--- a/drivers/hsi/controllers/omap_ssi.c
+++ b/drivers/hsi/controllers/omap_ssi.c
@@ -555,7 +555,7 @@ static int __exit ssi_remove(struct platform_device *pd)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int omap_ssi_runtime_suspend(struct device *dev)
{
struct hsi_controller *ssi = dev_get_drvdata(dev);
diff --git a/drivers/hsi/controllers/omap_ssi_port.c b/drivers/hsi/controllers/omap_ssi_port.c
index 4c0b582..d836cfe 100644
--- a/drivers/hsi/controllers/omap_ssi_port.c
+++ b/drivers/hsi/controllers/omap_ssi_port.c
@@ -1260,7 +1260,7 @@ static int __exit ssi_port_remove(struct platform_device *pd)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int ssi_save_port_ctx(struct omap_ssi_port *omap_port)
{
struct hsi_port *port = to_hsi_port(omap_port->dev);
diff --git a/drivers/hwmon/Kconfig b/drivers/hwmon/Kconfig
index 5286d7c..6529c09 100644
--- a/drivers/hwmon/Kconfig
+++ b/drivers/hwmon/Kconfig
@@ -1028,11 +1028,11 @@ config SENSORS_LM93
will be called lm93.
config SENSORS_LM95234
- tristate "National Semiconductor LM95234"
+ tristate "National Semiconductor LM95234 and compatibles"
depends on I2C
help
- If you say yes here you get support for the LM95234 temperature
- sensor.
+ If you say yes here you get support for the LM95233 and LM95234
+ temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called lm95234.
@@ -1048,10 +1048,11 @@ config SENSORS_LM95241
will be called lm95241.
config SENSORS_LM95245
- tristate "National Semiconductor LM95245 sensor chip"
+ tristate "National Semiconductor LM95245 and compatibles"
depends on I2C
help
- If you say yes here you get support for LM95245 sensor chip.
+ If you say yes here you get support for LM95235 and LM95245
+ temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called lm95245.
@@ -1117,12 +1118,23 @@ config SENSORS_NCT6775
help
If you say yes here you get support for the hardware monitoring
functionality of the Nuvoton NCT6106D, NCT6775F, NCT6776F, NCT6779D,
- NCT6791D and compatible Super-I/O chips. This driver replaces the
- w83627ehf driver for NCT6775F and NCT6776F.
+ NCT6791D, NCT6792D and compatible Super-I/O chips. This driver
+ replaces the w83627ehf driver for NCT6775F and NCT6776F.
This driver can also be built as a module. If so, the module
will be called nct6775.
+config SENSORS_NCT7802
+ tristate "Nuvoton NCT7802Y"
+ depends on I2C
+ select REGMAP_I2C
+ help
+ If you say yes here you get support for the Nuvoton NCT7802Y
+ hardware monitoring chip.
+
+ This driver can also be built as a module. If so, the module
+ will be called nct7802.
+
config SENSORS_PCF8591
tristate "Philips PCF8591 ADC/DAC"
depends on I2C
@@ -1454,7 +1466,7 @@ config SENSORS_TMP401
depends on I2C
help
If you say yes here you get support for Texas Instruments TMP401,
- TMP411, TMP431, and TMP432 temperature sensor chips.
+ TMP411, TMP431, TMP432 and TMP435 temperature sensor chips.
This driver can also be built as a module. If so, the module
will be called tmp401.
diff --git a/drivers/hwmon/Makefile b/drivers/hwmon/Makefile
index c90a761..6728064 100644
--- a/drivers/hwmon/Makefile
+++ b/drivers/hwmon/Makefile
@@ -118,6 +118,7 @@ obj-$(CONFIG_SENSORS_MCP3021) += mcp3021.o
obj-$(CONFIG_SENSORS_MENF21BMC_HWMON) += menf21bmc_hwmon.o
obj-$(CONFIG_SENSORS_NCT6683) += nct6683.o
obj-$(CONFIG_SENSORS_NCT6775) += nct6775.o
+obj-$(CONFIG_SENSORS_NCT7802) += nct7802.o
obj-$(CONFIG_SENSORS_NTC_THERMISTOR) += ntc_thermistor.o
obj-$(CONFIG_SENSORS_PC87360) += pc87360.o
obj-$(CONFIG_SENSORS_PC87427) += pc87427.o
diff --git a/drivers/hwmon/gpio-fan.c b/drivers/hwmon/gpio-fan.c
index 4efa173..36abf81 100644
--- a/drivers/hwmon/gpio-fan.c
+++ b/drivers/hwmon/gpio-fan.c
@@ -79,7 +79,7 @@ static ssize_t show_fan_alarm(struct device *dev,
{
struct gpio_fan_data *fan_data = dev_get_drvdata(dev);
struct gpio_fan_alarm *alarm = fan_data->alarm;
- int value = gpio_get_value(alarm->gpio);
+ int value = gpio_get_value_cansleep(alarm->gpio);
if (alarm->active_low)
value = !value;
@@ -131,7 +131,7 @@ static void __set_fan_ctrl(struct gpio_fan_data *fan_data, int ctrl_val)
int i;
for (i = 0; i < fan_data->num_ctrl; i++)
- gpio_set_value(fan_data->ctrl[i], (ctrl_val >> i) & 1);
+ gpio_set_value_cansleep(fan_data->ctrl[i], (ctrl_val >> i) & 1);
}
static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
@@ -142,7 +142,7 @@ static int __get_fan_ctrl(struct gpio_fan_data *fan_data)
for (i = 0; i < fan_data->num_ctrl; i++) {
int value;
- value = gpio_get_value(fan_data->ctrl[i]);
+ value = gpio_get_value_cansleep(fan_data->ctrl[i]);
ctrl_val |= (value << i);
}
return ctrl_val;
@@ -369,7 +369,8 @@ static int fan_ctrl_init(struct gpio_fan_data *fan_data,
if (err)
return err;
- err = gpio_direction_output(ctrl[i], gpio_get_value(ctrl[i]));
+ err = gpio_direction_output(ctrl[i],
+ gpio_get_value_cansleep(ctrl[i]));
if (err)
return err;
}
@@ -549,6 +550,14 @@ static int gpio_fan_probe(struct platform_device *pdev)
return 0;
}
+static void gpio_fan_shutdown(struct platform_device *pdev)
+{
+ struct gpio_fan_data *fan_data = dev_get_drvdata(&pdev->dev);
+
+ if (fan_data->ctrl)
+ set_fan_speed(fan_data, 0);
+}
+
#ifdef CONFIG_PM_SLEEP
static int gpio_fan_suspend(struct device *dev)
{
@@ -580,6 +589,7 @@ static SIMPLE_DEV_PM_OPS(gpio_fan_pm, gpio_fan_suspend, gpio_fan_resume);
static struct platform_driver gpio_fan_driver = {
.probe = gpio_fan_probe,
+ .shutdown = gpio_fan_shutdown,
.driver = {
.name = "gpio-fan",
.pm = GPIO_FAN_PM,
diff --git a/drivers/hwmon/ibmpowernv.c b/drivers/hwmon/ibmpowernv.c
index 6a30eee..7c2c7be 100644
--- a/drivers/hwmon/ibmpowernv.c
+++ b/drivers/hwmon/ibmpowernv.c
@@ -74,9 +74,6 @@ struct platform_data {
u32 sensors_count; /* Total count of sensors from each group */
};
-/* Platform device representing all the ibmpowernv sensors */
-static struct platform_device *pdevice;
-
static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
char *buf)
{
@@ -99,7 +96,7 @@ static ssize_t show_sensor(struct device *dev, struct device_attribute *devattr,
return sprintf(buf, "%u\n", x);
}
-static int __init get_sensor_index_attr(const char *name, u32 *index,
+static int get_sensor_index_attr(const char *name, u32 *index,
char *attr)
{
char *hash_pos = strchr(name, '#');
@@ -136,7 +133,7 @@ static int __init get_sensor_index_attr(const char *name, u32 *index,
* which need to be mapped as fan2_input, temp1_max respectively before
* populating them inside hwmon device class.
*/
-static int __init create_hwmon_attr_name(struct device *dev, enum sensors type,
+static int create_hwmon_attr_name(struct device *dev, enum sensors type,
const char *node_name,
char *hwmon_attr_name)
{
@@ -172,7 +169,7 @@ static int __init create_hwmon_attr_name(struct device *dev, enum sensors type,
return 0;
}
-static int __init populate_attr_groups(struct platform_device *pdev)
+static int populate_attr_groups(struct platform_device *pdev)
{
struct platform_data *pdata = platform_get_drvdata(pdev);
const struct attribute_group **pgroups = pdata->attr_groups;
@@ -180,11 +177,6 @@ static int __init populate_attr_groups(struct platform_device *pdev)
enum sensors type;
opal = of_find_node_by_path("/ibm,opal/sensors");
- if (!opal) {
- dev_dbg(&pdev->dev, "Opal node 'sensors' not found\n");
- return -ENODEV;
- }
-
for_each_child_of_node(opal, np) {
if (np->name == NULL)
continue;
@@ -221,7 +213,7 @@ static int __init populate_attr_groups(struct platform_device *pdev)
* to the name required by the higher 'hwmon' driver like fan1_input, temp1_max
* etc..
*/
-static int __init create_device_attrs(struct platform_device *pdev)
+static int create_device_attrs(struct platform_device *pdev)
{
struct platform_data *pdata = platform_get_drvdata(pdev);
const struct attribute_group **pgroups = pdata->attr_groups;
@@ -280,7 +272,7 @@ exit_put_node:
return err;
}
-static int __init ibmpowernv_probe(struct platform_device *pdev)
+static int ibmpowernv_probe(struct platform_device *pdev)
{
struct platform_data *pdata;
struct device *hwmon_dev;
@@ -309,57 +301,25 @@ static int __init ibmpowernv_probe(struct platform_device *pdev)
return PTR_ERR_OR_ZERO(hwmon_dev);
}
-static struct platform_driver ibmpowernv_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = DRVNAME,
+static const struct platform_device_id opal_sensor_driver_ids[] = {
+ {
+ .name = "opal-sensor",
},
+ { }
};
+MODULE_DEVICE_TABLE(platform, opal_sensor_driver_ids);
-static int __init ibmpowernv_init(void)
-{
- int err;
-
- pdevice = platform_device_alloc(DRVNAME, 0);
- if (!pdevice) {
- pr_err("Device allocation failed\n");
- err = -ENOMEM;
- goto exit;
- }
-
- err = platform_device_add(pdevice);
- if (err) {
- pr_err("Device addition failed (%d)\n", err);
- goto exit_device_put;
- }
-
- err = platform_driver_probe(&ibmpowernv_driver, ibmpowernv_probe);
- if (err) {
- if (err != -ENODEV)
- pr_err("Platform driver probe failed (%d)\n", err);
-
- goto exit_device_del;
- }
-
- return 0;
-
-exit_device_del:
- platform_device_del(pdevice);
-exit_device_put:
- platform_device_put(pdevice);
-exit:
- return err;
-}
+static struct platform_driver ibmpowernv_driver = {
+ .probe = ibmpowernv_probe,
+ .id_table = opal_sensor_driver_ids,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = DRVNAME,
+ },
+};
-static void __exit ibmpowernv_exit(void)
-{
- platform_driver_unregister(&ibmpowernv_driver);
- platform_device_unregister(pdevice);
-}
+module_platform_driver(ibmpowernv_driver);
MODULE_AUTHOR("Neelesh Gupta <neelegup@linux.vnet.ibm.com>");
MODULE_DESCRIPTION("IBM POWERNV platform sensors");
MODULE_LICENSE("GPL");
-
-module_init(ibmpowernv_init);
-module_exit(ibmpowernv_exit);
diff --git a/drivers/hwmon/iio_hwmon.c b/drivers/hwmon/iio_hwmon.c
index 14c82da..9801756 100644
--- a/drivers/hwmon/iio_hwmon.c
+++ b/drivers/hwmon/iio_hwmon.c
@@ -63,7 +63,7 @@ static int iio_hwmon_probe(struct platform_device *pdev)
struct iio_hwmon_state *st;
struct sensor_device_attribute *a;
int ret, i;
- int in_i = 1, temp_i = 1, curr_i = 1;
+ int in_i = 1, temp_i = 1, curr_i = 1, humidity_i = 1;
enum iio_chan_type type;
struct iio_channel *channels;
const char *name = "iio_hwmon";
@@ -123,6 +123,11 @@ static int iio_hwmon_probe(struct platform_device *pdev)
"curr%d_input",
curr_i++);
break;
+ case IIO_HUMIDITYRELATIVE:
+ a->dev_attr.attr.name = kasprintf(GFP_KERNEL,
+ "humidity%d_input",
+ humidity_i++);
+ break;
default:
ret = -EINVAL;
goto error_release_channels;
diff --git a/drivers/hwmon/ina2xx.c b/drivers/hwmon/ina2xx.c
index bfd3f3e..e01feba 100644
--- a/drivers/hwmon/ina2xx.c
+++ b/drivers/hwmon/ina2xx.c
@@ -223,6 +223,7 @@ static int ina2xx_probe(struct i2c_client *client,
struct device *hwmon_dev;
long shunt = 10000; /* default shunt value 10mOhms */
u32 val;
+ int ret;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA))
return -ENODEV;
@@ -247,12 +248,25 @@ static int ina2xx_probe(struct i2c_client *client,
data->config = &ina2xx_config[data->kind];
/* device configuration */
- i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
- data->config->config_default);
- /* set current LSB to 1mA, shunt is in uOhms */
- /* (equation 13 in datasheet) */
- i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
- data->config->calibration_factor / shunt);
+ ret = i2c_smbus_write_word_swapped(client, INA2XX_CONFIG,
+ data->config->config_default);
+ if (ret < 0) {
+ dev_err(dev,
+ "error writing to the config register: %d", ret);
+ return -ENODEV;
+ }
+
+ /*
+ * Set current LSB to 1mA, shunt is in uOhms
+ * (equation 13 in datasheet).
+ */
+ ret = i2c_smbus_write_word_swapped(client, INA2XX_CALIBRATION,
+ data->config->calibration_factor / shunt);
+ if (ret < 0) {
+ dev_err(dev,
+ "error writing to the calibration register: %d", ret);
+ return -ENODEV;
+ }
data->client = client;
mutex_init(&data->update_lock);
diff --git a/drivers/hwmon/lm75.c b/drivers/hwmon/lm75.c
index d16dbb3..6753fd9 100644
--- a/drivers/hwmon/lm75.c
+++ b/drivers/hwmon/lm75.c
@@ -44,6 +44,7 @@ enum lm75_type { /* keep sorted in alphabetical order */
g751,
lm75,
lm75a,
+ lm75b,
max6625,
max6626,
mcp980x,
@@ -233,6 +234,10 @@ lm75_probe(struct i2c_client *client, const struct i2c_device_id *id)
data->resolution = 9;
data->sample_time = HZ / 2;
break;
+ case lm75b:
+ data->resolution = 11;
+ data->sample_time = HZ / 4;
+ break;
case max6625:
data->resolution = 9;
data->sample_time = HZ / 4;
@@ -322,6 +327,7 @@ static const struct i2c_device_id lm75_ids[] = {
{ "g751", g751, },
{ "lm75", lm75, },
{ "lm75a", lm75a, },
+ { "lm75b", lm75b, },
{ "max6625", max6625, },
{ "max6626", max6626, },
{ "mcp980x", mcp980x, },
@@ -409,6 +415,12 @@ static int lm75_detect(struct i2c_client *new_client,
|| i2c_smbus_read_byte_data(new_client, 7) != os)
return -ENODEV;
}
+ /*
+ * It is very unlikely that this is a LM75 if both
+ * hysteresis and temperature limit registers are 0.
+ */
+ if (hyst == 0 && os == 0)
+ return -ENODEV;
/* Addresses cycling */
for (i = 8; i <= 248; i += 40) {
diff --git a/drivers/hwmon/lm95234.c b/drivers/hwmon/lm95234.c
index 411202b..8796de3 100644
--- a/drivers/hwmon/lm95234.c
+++ b/drivers/hwmon/lm95234.c
@@ -1,7 +1,7 @@
/*
* Driver for Texas Instruments / National Semiconductor LM95234
*
- * Copyright (c) 2013 Guenter Roeck <linux@roeck-us.net>
+ * Copyright (c) 2013, 2014 Guenter Roeck <linux@roeck-us.net>
*
* Derived from lm95241.c
* Copyright (C) 2008, 2010 Davide Rizzo <elpa.rizzo@gmail.com>
@@ -30,7 +30,10 @@
#define DRVNAME "lm95234"
-static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
+enum chips { lm95233, lm95234 };
+
+static const unsigned short normal_i2c[] = {
+ 0x18, 0x2a, 0x2b, 0x4d, 0x4e, I2C_CLIENT_END };
/* LM95234 registers */
#define LM95234_REG_MAN_ID 0xFE
@@ -53,11 +56,13 @@ static const unsigned short normal_i2c[] = { 0x18, 0x4d, 0x4e, I2C_CLIENT_END };
#define LM95234_REG_TCRIT_HYST 0x5a
#define NATSEMI_MAN_ID 0x01
+#define LM95233_CHIP_ID 0x89
#define LM95234_CHIP_ID 0x79
/* Client data (each client gets its own) */
struct lm95234_data {
struct i2c_client *client;
+ const struct attribute_group *groups[3];
struct mutex update_lock;
unsigned long last_updated, interval; /* in jiffies */
bool valid; /* false until following fields are valid */
@@ -564,35 +569,23 @@ static SENSOR_DEVICE_ATTR(temp5_offset, S_IWUSR | S_IRUGO, show_offset,
static DEVICE_ATTR(update_interval, S_IWUSR | S_IRUGO, show_interval,
set_interval);
-static struct attribute *lm95234_attrs[] = {
+static struct attribute *lm95234_common_attrs[] = {
&sensor_dev_attr_temp1_input.dev_attr.attr,
&sensor_dev_attr_temp2_input.dev_attr.attr,
&sensor_dev_attr_temp3_input.dev_attr.attr,
- &sensor_dev_attr_temp4_input.dev_attr.attr,
- &sensor_dev_attr_temp5_input.dev_attr.attr,
&sensor_dev_attr_temp2_fault.dev_attr.attr,
&sensor_dev_attr_temp3_fault.dev_attr.attr,
- &sensor_dev_attr_temp4_fault.dev_attr.attr,
- &sensor_dev_attr_temp5_fault.dev_attr.attr,
&sensor_dev_attr_temp2_type.dev_attr.attr,
&sensor_dev_attr_temp3_type.dev_attr.attr,
- &sensor_dev_attr_temp4_type.dev_attr.attr,
- &sensor_dev_attr_temp5_type.dev_attr.attr,
&sensor_dev_attr_temp1_max.dev_attr.attr,
&sensor_dev_attr_temp2_max.dev_attr.attr,
&sensor_dev_attr_temp3_max.dev_attr.attr,
- &sensor_dev_attr_temp4_max.dev_attr.attr,
- &sensor_dev_attr_temp5_max.dev_attr.attr,
&sensor_dev_attr_temp1_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp2_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp3_max_hyst.dev_attr.attr,
- &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
- &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
&sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
- &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_crit.dev_attr.attr,
&sensor_dev_attr_temp3_crit.dev_attr.attr,
&sensor_dev_attr_temp2_crit_hyst.dev_attr.attr,
@@ -601,18 +594,44 @@ static struct attribute *lm95234_attrs[] = {
&sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
&sensor_dev_attr_temp2_offset.dev_attr.attr,
&sensor_dev_attr_temp3_offset.dev_attr.attr,
+ &dev_attr_update_interval.attr,
+ NULL
+};
+
+static const struct attribute_group lm95234_common_group = {
+ .attrs = lm95234_common_attrs,
+};
+
+static struct attribute *lm95234_attrs[] = {
+ &sensor_dev_attr_temp4_input.dev_attr.attr,
+ &sensor_dev_attr_temp5_input.dev_attr.attr,
+ &sensor_dev_attr_temp4_fault.dev_attr.attr,
+ &sensor_dev_attr_temp5_fault.dev_attr.attr,
+ &sensor_dev_attr_temp4_type.dev_attr.attr,
+ &sensor_dev_attr_temp5_type.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_hyst.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
&sensor_dev_attr_temp4_offset.dev_attr.attr,
&sensor_dev_attr_temp5_offset.dev_attr.attr,
- &dev_attr_update_interval.attr,
NULL
};
-ATTRIBUTE_GROUPS(lm95234);
+
+static const struct attribute_group lm95234_group = {
+ .attrs = lm95234_attrs,
+};
static int lm95234_detect(struct i2c_client *client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = client->adapter;
+ int address = client->addr;
+ u8 config_mask, model_mask;
int mfg_id, chip_id, val;
+ const char *name;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
@@ -622,15 +641,31 @@ static int lm95234_detect(struct i2c_client *client,
return -ENODEV;
chip_id = i2c_smbus_read_byte_data(client, LM95234_REG_CHIP_ID);
- if (chip_id != LM95234_CHIP_ID)
+ switch (chip_id) {
+ case LM95233_CHIP_ID:
+ if (address != 0x18 && address != 0x2a && address != 0x2b)
+ return -ENODEV;
+ config_mask = 0xbf;
+ model_mask = 0xf9;
+ name = "lm95233";
+ break;
+ case LM95234_CHIP_ID:
+ if (address != 0x18 && address != 0x4d && address != 0x4e)
+ return -ENODEV;
+ config_mask = 0xbc;
+ model_mask = 0xe1;
+ name = "lm95234";
+ break;
+ default:
return -ENODEV;
+ }
val = i2c_smbus_read_byte_data(client, LM95234_REG_STATUS);
if (val & 0x30)
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONFIG);
- if (val & 0xbc)
+ if (val & config_mask)
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_CONVRATE);
@@ -638,14 +673,14 @@ static int lm95234_detect(struct i2c_client *client,
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL);
- if (val & 0xe1)
+ if (val & model_mask)
return -ENODEV;
val = i2c_smbus_read_byte_data(client, LM95234_REG_REM_MODEL_STS);
- if (val & 0xe1)
+ if (val & model_mask)
return -ENODEV;
- strlcpy(info->type, "lm95234", I2C_NAME_SIZE);
+ strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
@@ -698,15 +733,19 @@ static int lm95234_probe(struct i2c_client *client,
if (err < 0)
return err;
+ data->groups[0] = &lm95234_common_group;
+ if (id->driver_data == lm95234)
+ data->groups[1] = &lm95234_group;
+
hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
- data,
- lm95234_groups);
+ data, data->groups);
return PTR_ERR_OR_ZERO(hwmon_dev);
}
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95234_id[] = {
- { "lm95234", 0 },
+ { "lm95233", lm95233 },
+ { "lm95234", lm95234 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95234_id);
@@ -725,5 +764,5 @@ static struct i2c_driver lm95234_driver = {
module_i2c_driver(lm95234_driver);
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
-MODULE_DESCRIPTION("LM95234 sensor driver");
+MODULE_DESCRIPTION("LM95233/LM95234 sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/lm95245.c b/drivers/hwmon/lm95245.c
index 0ae0dfd..e7aef45 100644
--- a/drivers/hwmon/lm95245.c
+++ b/drivers/hwmon/lm95245.c
@@ -1,10 +1,8 @@
/*
* Copyright (C) 2011 Alexander Stein <alexander.stein@systec-electronic.com>
*
- * The LM95245 is a sensor chip made by National Semiconductors.
+ * The LM95245 is a sensor chip made by TI / National Semiconductor.
* It reports up to two temperatures (its own plus an external one).
- * Complete datasheet can be obtained from National's website at:
- * http://www.national.com/ds.cgi/LM/LM95245.pdf
*
* This driver is based on lm95241.c
*
@@ -34,8 +32,6 @@
#include <linux/mutex.h>
#include <linux/sysfs.h>
-#define DEVNAME "lm95245"
-
static const unsigned short normal_i2c[] = {
0x18, 0x19, 0x29, 0x4c, 0x4d, I2C_CLIENT_END };
@@ -98,7 +94,8 @@ static const unsigned short normal_i2c[] = {
#define STATUS1_LOC 0x01
#define MANUFACTURER_ID 0x01
-#define DEFAULT_REVISION 0xB3
+#define LM95235_REVISION 0xB1
+#define LM95245_REVISION 0xB3
static const u8 lm95245_reg_address[] = {
LM95245_REG_R_LOCAL_TEMPH_S,
@@ -427,17 +424,32 @@ static int lm95245_detect(struct i2c_client *new_client,
struct i2c_board_info *info)
{
struct i2c_adapter *adapter = new_client->adapter;
+ int address = new_client->addr;
+ const char *name;
+ int rev, id;
if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA))
return -ENODEV;
- if (i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID)
- != MANUFACTURER_ID
- || i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID)
- != DEFAULT_REVISION)
+ id = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_MAN_ID);
+ if (id != MANUFACTURER_ID)
return -ENODEV;
- strlcpy(info->type, DEVNAME, I2C_NAME_SIZE);
+ rev = i2c_smbus_read_byte_data(new_client, LM95245_REG_R_CHIP_ID);
+ switch (rev) {
+ case LM95235_REVISION:
+ if (address != 0x18 && address != 0x29 && address != 0x4c)
+ return -ENODEV;
+ name = "lm95235";
+ break;
+ case LM95245_REVISION:
+ name = "lm95245";
+ break;
+ default:
+ return -ENODEV;
+ }
+
+ strlcpy(info->type, name, I2C_NAME_SIZE);
return 0;
}
@@ -484,7 +496,8 @@ static int lm95245_probe(struct i2c_client *client,
/* Driver data (common to all clients) */
static const struct i2c_device_id lm95245_id[] = {
- { DEVNAME, 0 },
+ { "lm95235", 0 },
+ { "lm95245", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, lm95245_id);
@@ -492,7 +505,7 @@ MODULE_DEVICE_TABLE(i2c, lm95245_id);
static struct i2c_driver lm95245_driver = {
.class = I2C_CLASS_HWMON,
.driver = {
- .name = DEVNAME,
+ .name = "lm95245",
},
.probe = lm95245_probe,
.id_table = lm95245_id,
@@ -503,5 +516,5 @@ static struct i2c_driver lm95245_driver = {
module_i2c_driver(lm95245_driver);
MODULE_AUTHOR("Alexander Stein <alexander.stein@systec-electronic.com>");
-MODULE_DESCRIPTION("LM95245 sensor driver");
+MODULE_DESCRIPTION("LM95235/LM95245 sensor driver");
MODULE_LICENSE("GPL");
diff --git a/drivers/hwmon/nct6775.c b/drivers/hwmon/nct6775.c
index 504cbdd..dc0df57 100644
--- a/drivers/hwmon/nct6775.c
+++ b/drivers/hwmon/nct6775.c
@@ -38,6 +38,7 @@
* nct6776f 9 5 3 6+3 0xc330 0xc1 0x5ca3
* nct6779d 15 5 5 2+6 0xc560 0xc1 0x5ca3
* nct6791d 15 6 6 2+6 0xc800 0xc1 0x5ca3
+ * nct6792d 15 6 6 2+6 0xc910 0xc1 0x5ca3
*
* #temp lists the number of monitored temperature sources (first value) plus
* the number of directly connectable temperature sensors (second value).
@@ -61,7 +62,7 @@
#define USE_ALTERNATE
-enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791 };
+enum kinds { nct6106, nct6775, nct6776, nct6779, nct6791, nct6792 };
/* used to set data->name = nct6775_device_names[data->sio_kind] */
static const char * const nct6775_device_names[] = {
@@ -70,6 +71,7 @@ static const char * const nct6775_device_names[] = {
"nct6776",
"nct6779",
"nct6791",
+ "nct6792",
};
static unsigned short force_id;
@@ -100,6 +102,7 @@ MODULE_PARM_DESC(fan_debounce, "Enable debouncing for fan RPM signal");
#define SIO_NCT6776_ID 0xc330
#define SIO_NCT6779_ID 0xc560
#define SIO_NCT6791_ID 0xc800
+#define SIO_NCT6792_ID 0xc910
#define SIO_ID_MASK 0xFFF0
enum pwm_enable { off, manual, thermal_cruise, speed_cruise, sf3, sf4 };
@@ -529,6 +532,12 @@ static const s8 NCT6791_ALARM_BITS[] = {
4, 5, 13, -1, -1, -1, /* temp1..temp6 */
12, 9 }; /* intrusion0, intrusion1 */
+/* NCT6792 specific data */
+
+static const u16 NCT6792_REG_TEMP_MON[] = {
+ 0x73, 0x75, 0x77, 0x79, 0x7b, 0x7d };
+static const u16 NCT6792_REG_BEEP[NUM_REG_BEEP] = {
+ 0xb2, 0xb3, 0xb4, 0xb5, 0xbf };
/* NCT6102D/NCT6106D specific data */
@@ -1043,13 +1052,14 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
reg == 0x73 || reg == 0x75 || reg == 0x77;
case nct6779:
case nct6791:
+ case nct6792:
return reg == 0x150 || reg == 0x153 || reg == 0x155 ||
((reg & 0xfff0) == 0x4b0 && (reg & 0x000f) < 0x0b) ||
reg == 0x402 ||
reg == 0x63a || reg == 0x63c || reg == 0x63e ||
reg == 0x640 || reg == 0x642 ||
reg == 0x73 || reg == 0x75 || reg == 0x77 || reg == 0x79 ||
- reg == 0x7b;
+ reg == 0x7b || reg == 0x7d;
}
return false;
}
@@ -1063,6 +1073,7 @@ static bool is_word_sized(struct nct6775_data *data, u16 reg)
static inline void nct6775_set_bank(struct nct6775_data *data, u16 reg)
{
u8 bank = reg >> 8;
+
if (data->bank != bank) {
outb_p(NCT6775_REG_BANK, data->addr + ADDR_REG_OFFSET);
outb_p(bank, data->addr + DATA_REG_OFFSET);
@@ -1300,6 +1311,7 @@ static void nct6775_update_pwm(struct device *dev)
if (!data->target_speed_tolerance[i] ||
data->pwm_enable[i] == speed_cruise) {
u8 t = fanmodecfg & 0x0f;
+
if (data->REG_TOLERANCE_H) {
t |= (nct6775_read_value(data,
data->REG_TOLERANCE_H[i]) & 0x70) >> 1;
@@ -1391,6 +1403,7 @@ static void nct6775_update_pwm_limits(struct device *dev)
case nct6106:
case nct6779:
case nct6791:
+ case nct6792:
reg = nct6775_read_value(data,
data->REG_CRITICAL_PWM_ENABLE[i]);
if (reg & data->CRITICAL_PWM_ENABLE_MASK)
@@ -1473,6 +1486,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->alarms = 0;
for (i = 0; i < NUM_REG_ALARM; i++) {
u8 alarm;
+
if (!data->REG_ALARM[i])
continue;
alarm = nct6775_read_value(data, data->REG_ALARM[i]);
@@ -1482,6 +1496,7 @@ static struct nct6775_data *nct6775_update_device(struct device *dev)
data->beeps = 0;
for (i = 0; i < NUM_REG_BEEP; i++) {
u8 beep;
+
if (!data->REG_BEEP[i])
continue;
beep = nct6775_read_value(data, data->REG_BEEP[i]);
@@ -1504,8 +1519,9 @@ show_in_reg(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
- int nr = sattr->nr;
int index = sattr->index;
+ int nr = sattr->nr;
+
return sprintf(buf, "%ld\n", in_from_reg(data->in[nr][index], nr));
}
@@ -1515,10 +1531,12 @@ store_in_reg(struct device *dev, struct device_attribute *attr, const char *buf,
{
struct nct6775_data *data = dev_get_drvdata(dev);
struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
- int nr = sattr->nr;
int index = sattr->index;
+ int nr = sattr->nr;
unsigned long val;
- int err = kstrtoul(buf, 10, &val);
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
mutex_lock(&data->update_lock);
@@ -1535,6 +1553,7 @@ show_alarm(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = data->ALARM_BITS[sattr->index];
+
return sprintf(buf, "%u\n",
(unsigned int)((data->alarms >> nr) & 0x01));
}
@@ -1570,6 +1589,7 @@ show_temp_alarm(struct device *dev, struct device_attribute *attr, char *buf)
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);
@@ -1595,8 +1615,9 @@ store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
int nr = data->BEEP_BITS[sattr->index];
int regindex = nr >> 3;
unsigned long val;
+ int err;
- int err = kstrtoul(buf, 10, &val);
+ err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
if (val > 1)
@@ -1629,6 +1650,7 @@ show_temp_beep(struct device *dev, struct device_attribute *attr, char *buf)
nr = find_temp_source(data, sattr->index, data->num_temp_beeps);
if (nr >= 0) {
int bit = data->BEEP_BITS[nr + TEMP_ALARM_BASE];
+
beep = (data->beeps >> bit) & 0x01;
}
return sprintf(buf, "%u\n", beep);
@@ -1642,8 +1664,9 @@ store_temp_beep(struct device *dev, struct device_attribute *attr,
struct nct6775_data *data = dev_get_drvdata(dev);
int nr, bit, regindex;
unsigned long val;
+ int err;
- int err = kstrtoul(buf, 10, &val);
+ err = kstrtoul(buf, 10, &val);
if (err < 0)
return err;
if (val > 1)
@@ -1715,6 +1738,7 @@ show_fan(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
+
return sprintf(buf, "%d\n", data->rpm[nr]);
}
@@ -1724,6 +1748,7 @@ show_fan_min(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
+
return sprintf(buf, "%d\n",
data->fan_from_reg_min(data->fan_min[nr],
data->fan_div[nr]));
@@ -1735,6 +1760,7 @@ show_fan_div(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
+
return sprintf(buf, "%u\n", div_from_reg(data->fan_div[nr]));
}
@@ -1746,9 +1772,9 @@ store_fan_min(struct device *dev, struct device_attribute *attr,
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
unsigned long val;
- int err;
unsigned int reg;
u8 new_div;
+ int err;
err = kstrtoul(buf, 10, &val);
if (err < 0)
@@ -1932,6 +1958,7 @@ show_temp_label(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
+
return sprintf(buf, "%s\n", data->temp_label[data->temp_src[nr]]);
}
@@ -2008,6 +2035,7 @@ show_temp_type(struct device *dev, struct device_attribute *attr, char *buf)
struct nct6775_data *data = nct6775_update_device(dev);
struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
int nr = sattr->index;
+
return sprintf(buf, "%d\n", (int)data->temp_type[nr]);
}
@@ -2790,6 +2818,7 @@ store_auto_pwm(struct device *dev, struct device_attribute *attr,
case nct6106:
case nct6779:
case nct6791:
+ case nct6792:
nct6775_write_value(data, data->REG_CRITICAL_PWM[nr],
val);
reg = nct6775_read_value(data,
@@ -2997,6 +3026,7 @@ static ssize_t
show_vid(struct device *dev, struct device_attribute *attr, char *buf)
{
struct nct6775_data *data = dev_get_drvdata(dev);
+
return sprintf(buf, "%d\n", vid_from_reg(data->vid, data->vrm));
}
@@ -3202,7 +3232,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
pwm4pin = false;
pwm5pin = false;
pwm6pin = false;
- } else { /* NCT6779D or NCT6791D */
+ } else { /* NCT6779D, NCT6791D, or NCT6792D */
regval = superio_inb(sioreg, 0x1c);
fan3pin = !(regval & (1 << 5));
@@ -3215,7 +3245,7 @@ nct6775_check_fan_inputs(struct nct6775_data *data)
fan4min = fan4pin;
- if (data->kind == nct6791) {
+ if (data->kind == nct6791 || data->kind == nct6792) {
regval = superio_inb(sioreg, 0x2d);
fan6pin = (regval & (1 << 1));
pwm6pin = (regval & (1 << 0));
@@ -3588,6 +3618,7 @@ static int nct6775_probe(struct platform_device *pdev)
break;
case nct6791:
+ case nct6792:
data->in_num = 15;
data->pwm_num = 6;
data->auto_pwm_num = 4;
@@ -3650,12 +3681,20 @@ static int nct6775_probe(struct platform_device *pdev)
data->REG_WEIGHT_TEMP[1] = NCT6791_REG_WEIGHT_TEMP_STEP_TOL;
data->REG_WEIGHT_TEMP[2] = NCT6791_REG_WEIGHT_TEMP_BASE;
data->REG_ALARM = NCT6791_REG_ALARM;
- data->REG_BEEP = NCT6776_REG_BEEP;
+ if (data->kind == nct6791)
+ data->REG_BEEP = NCT6776_REG_BEEP;
+ else
+ data->REG_BEEP = NCT6792_REG_BEEP;
reg_temp = NCT6779_REG_TEMP;
- reg_temp_mon = NCT6779_REG_TEMP_MON;
num_reg_temp = ARRAY_SIZE(NCT6779_REG_TEMP);
- num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
+ if (data->kind == nct6791) {
+ reg_temp_mon = NCT6779_REG_TEMP_MON;
+ num_reg_temp_mon = ARRAY_SIZE(NCT6779_REG_TEMP_MON);
+ } else {
+ reg_temp_mon = NCT6792_REG_TEMP_MON;
+ num_reg_temp_mon = ARRAY_SIZE(NCT6792_REG_TEMP_MON);
+ }
reg_temp_over = NCT6779_REG_TEMP_OVER;
reg_temp_hyst = NCT6779_REG_TEMP_HYST;
reg_temp_config = NCT6779_REG_TEMP_CONFIG;
@@ -3854,6 +3893,7 @@ static int nct6775_probe(struct platform_device *pdev)
case nct6106:
case nct6779:
case nct6791:
+ case nct6792:
break;
}
@@ -3885,6 +3925,7 @@ static int nct6775_probe(struct platform_device *pdev)
tmp |= 0x3e;
break;
case nct6791:
+ case nct6792:
tmp |= 0x7e;
break;
}
@@ -3972,7 +4013,7 @@ static int nct6775_resume(struct device *dev)
mutex_lock(&data->update_lock);
data->bank = 0xff; /* Force initial bank selection */
- if (data->kind == nct6791) {
+ if (data->kind == nct6791 || data->kind == nct6792) {
err = superio_enter(data->sioreg);
if (err)
goto abort;
@@ -4052,6 +4093,7 @@ static const char * const nct6775_sio_names[] __initconst = {
"NCT6776D/F",
"NCT6779D",
"NCT6791D",
+ "NCT6792D",
};
/* nct6775_find() looks for a '627 in the Super-I/O config space */
@@ -4086,6 +4128,9 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
case SIO_NCT6791_ID:
sio_data->kind = nct6791;
break;
+ case SIO_NCT6792_ID:
+ sio_data->kind = nct6792;
+ break;
default:
if (val != 0xffff)
pr_debug("unsupported chip ID: 0x%04x\n", val);
@@ -4111,7 +4156,7 @@ static int __init nct6775_find(int sioaddr, struct nct6775_sio_data *sio_data)
superio_outb(sioaddr, SIO_REG_ENABLE, val | 0x01);
}
- if (sio_data->kind == nct6791)
+ if (sio_data->kind == nct6791 || sio_data->kind == nct6792)
nct6791_enable_io_mapping(sioaddr);
superio_exit(sioaddr);
@@ -4221,7 +4266,7 @@ static void __exit sensors_nct6775_exit(void)
}
MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
-MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D driver");
+MODULE_DESCRIPTION("NCT6106D/NCT6775F/NCT6776F/NCT6779D/NCT6791D/NCT6792D driver");
MODULE_LICENSE("GPL");
module_init(sensors_nct6775_init);
diff --git a/drivers/hwmon/nct7802.c b/drivers/hwmon/nct7802.c
new file mode 100644
index 0000000..ec56782
--- /dev/null
+++ b/drivers/hwmon/nct7802.c
@@ -0,0 +1,860 @@
+/*
+ * nct7802 - Driver for Nuvoton NCT7802Y
+ *
+ * Copyright (C) 2014 Guenter Roeck <linux@roeck-us.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/err.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/hwmon.h>
+#include <linux/hwmon-sysfs.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+
+#define DRVNAME "nct7802"
+
+static const u8 REG_VOLTAGE[5] = { 0x09, 0x0a, 0x0c, 0x0d, 0x0e };
+
+static const u8 REG_VOLTAGE_LIMIT_LSB[2][5] = {
+ { 0x40, 0x00, 0x42, 0x44, 0x46 },
+ { 0x3f, 0x00, 0x41, 0x43, 0x45 },
+};
+
+static const u8 REG_VOLTAGE_LIMIT_MSB[5] = { 0x48, 0x00, 0x47, 0x47, 0x48 };
+
+static const u8 REG_VOLTAGE_LIMIT_MSB_SHIFT[2][5] = {
+ { 0, 0, 4, 0, 4 },
+ { 2, 0, 6, 2, 6 },
+};
+
+#define REG_BANK 0x00
+#define REG_TEMP_LSB 0x05
+#define REG_TEMP_PECI_LSB 0x08
+#define REG_VOLTAGE_LOW 0x0f
+#define REG_FANCOUNT_LOW 0x13
+#define REG_START 0x21
+#define REG_MODE 0x22
+#define REG_PECI_ENABLE 0x23
+#define REG_FAN_ENABLE 0x24
+#define REG_VMON_ENABLE 0x25
+#define REG_VENDOR_ID 0xfd
+#define REG_CHIP_ID 0xfe
+#define REG_VERSION_ID 0xff
+
+/*
+ * Data structures and manipulation thereof
+ */
+
+struct nct7802_data {
+ struct regmap *regmap;
+ struct mutex access_lock; /* for multi-byte read and write operations */
+};
+
+static int nct7802_read_temp(struct nct7802_data *data,
+ u8 reg_temp, u8 reg_temp_low, int *temp)
+{
+ unsigned int t1, t2 = 0;
+ int err;
+
+ *temp = 0;
+
+ mutex_lock(&data->access_lock);
+ err = regmap_read(data->regmap, reg_temp, &t1);
+ if (err < 0)
+ goto abort;
+ t1 <<= 8;
+ if (reg_temp_low) { /* 11 bit data */
+ err = regmap_read(data->regmap, reg_temp_low, &t2);
+ if (err < 0)
+ goto abort;
+ }
+ t1 |= t2 & 0xe0;
+ *temp = (s16)t1 / 32 * 125;
+abort:
+ mutex_unlock(&data->access_lock);
+ return err;
+}
+
+static int nct7802_read_fan(struct nct7802_data *data, u8 reg_fan)
+{
+ unsigned int f1, f2;
+ int ret;
+
+ mutex_lock(&data->access_lock);
+ ret = regmap_read(data->regmap, reg_fan, &f1);
+ if (ret < 0)
+ goto abort;
+ ret = regmap_read(data->regmap, REG_FANCOUNT_LOW, &f2);
+ if (ret < 0)
+ goto abort;
+ ret = (f1 << 5) | (f2 >> 3);
+ /* convert fan count to rpm */
+ if (ret == 0x1fff) /* maximum value, assume fan is stopped */
+ ret = 0;
+ else if (ret)
+ ret = DIV_ROUND_CLOSEST(1350000U, ret);
+abort:
+ mutex_unlock(&data->access_lock);
+ return ret;
+}
+
+static int nct7802_read_fan_min(struct nct7802_data *data, u8 reg_fan_low,
+ u8 reg_fan_high)
+{
+ unsigned int f1, f2;
+ int ret;
+
+ mutex_lock(&data->access_lock);
+ ret = regmap_read(data->regmap, reg_fan_low, &f1);
+ if (ret < 0)
+ goto abort;
+ ret = regmap_read(data->regmap, reg_fan_high, &f2);
+ if (ret < 0)
+ goto abort;
+ ret = f1 | ((f2 & 0xf8) << 5);
+ /* convert fan count to rpm */
+ if (ret == 0x1fff) /* maximum value, assume no limit */
+ ret = 0;
+ else if (ret)
+ ret = DIV_ROUND_CLOSEST(1350000U, ret);
+abort:
+ mutex_unlock(&data->access_lock);
+ return ret;
+}
+
+static int nct7802_write_fan_min(struct nct7802_data *data, u8 reg_fan_low,
+ u8 reg_fan_high, unsigned int limit)
+{
+ int err;
+
+ if (limit)
+ limit = DIV_ROUND_CLOSEST(1350000U, limit);
+ else
+ limit = 0x1fff;
+ limit = clamp_val(limit, 0, 0x1fff);
+
+ mutex_lock(&data->access_lock);
+ err = regmap_write(data->regmap, reg_fan_low, limit & 0xff);
+ if (err < 0)
+ goto abort;
+
+ err = regmap_write(data->regmap, reg_fan_high, (limit & 0x1f00) >> 5);
+abort:
+ mutex_unlock(&data->access_lock);
+ return err;
+}
+
+static u8 nct7802_vmul[] = { 4, 2, 2, 2, 2 };
+
+static int nct7802_read_voltage(struct nct7802_data *data, int nr, int index)
+{
+ unsigned int v1, v2;
+ int ret;
+
+ mutex_lock(&data->access_lock);
+ if (index == 0) { /* voltage */
+ ret = regmap_read(data->regmap, REG_VOLTAGE[nr], &v1);
+ if (ret < 0)
+ goto abort;
+ ret = regmap_read(data->regmap, REG_VOLTAGE_LOW, &v2);
+ if (ret < 0)
+ goto abort;
+ ret = ((v1 << 2) | (v2 >> 6)) * nct7802_vmul[nr];
+ } else { /* limit */
+ int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
+
+ ret = regmap_read(data->regmap,
+ REG_VOLTAGE_LIMIT_LSB[index - 1][nr], &v1);
+ if (ret < 0)
+ goto abort;
+ ret = regmap_read(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr],
+ &v2);
+ if (ret < 0)
+ goto abort;
+ ret = (v1 | ((v2 << shift) & 0x300)) * nct7802_vmul[nr];
+ }
+abort:
+ mutex_unlock(&data->access_lock);
+ return ret;
+}
+
+static int nct7802_write_voltage(struct nct7802_data *data, int nr, int index,
+ unsigned int voltage)
+{
+ int shift = 8 - REG_VOLTAGE_LIMIT_MSB_SHIFT[index - 1][nr];
+ int err;
+
+ voltage = DIV_ROUND_CLOSEST(voltage, nct7802_vmul[nr]);
+ voltage = clamp_val(voltage, 0, 0x3ff);
+
+ mutex_lock(&data->access_lock);
+ err = regmap_write(data->regmap,
+ REG_VOLTAGE_LIMIT_LSB[index - 1][nr],
+ voltage & 0xff);
+ if (err < 0)
+ goto abort;
+
+ err = regmap_update_bits(data->regmap, REG_VOLTAGE_LIMIT_MSB[nr],
+ 0x0300 >> shift, (voltage & 0x0300) >> shift);
+abort:
+ mutex_unlock(&data->access_lock);
+ return err;
+}
+
+static ssize_t show_in(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ int voltage;
+
+ voltage = nct7802_read_voltage(data, sattr->nr, sattr->index);
+ if (voltage < 0)
+ return voltage;
+
+ return sprintf(buf, "%d\n", voltage);
+}
+
+static ssize_t store_in(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ int index = sattr->index;
+ int nr = sattr->nr;
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ err = nct7802_write_voltage(data, nr, index, val);
+ return err ? : count;
+}
+
+static ssize_t show_temp(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int err, temp;
+
+ err = nct7802_read_temp(data, sattr->nr, sattr->index, &temp);
+ if (err < 0)
+ return err;
+
+ return sprintf(buf, "%d\n", temp);
+}
+
+static ssize_t store_temp(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ int nr = sattr->nr;
+ long val;
+ int err;
+
+ err = kstrtol(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp_val(DIV_ROUND_CLOSEST(val, 1000), -128, 127);
+
+ err = regmap_write(data->regmap, nr, val & 0xff);
+ return err ? : count;
+}
+
+static ssize_t show_fan(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute *sattr = to_sensor_dev_attr(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ int speed;
+
+ speed = nct7802_read_fan(data, sattr->index);
+ if (speed < 0)
+ return speed;
+
+ return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t show_fan_min(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ int speed;
+
+ speed = nct7802_read_fan_min(data, sattr->nr, sattr->index);
+ if (speed < 0)
+ return speed;
+
+ return sprintf(buf, "%d\n", speed);
+}
+
+static ssize_t store_fan_min(struct device *dev, struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+
+ err = nct7802_write_fan_min(data, sattr->nr, sattr->index, val);
+ return err ? : count;
+}
+
+static ssize_t show_alarm(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ int bit = sattr->index;
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(data->regmap, sattr->nr, &val);
+ if (ret < 0)
+ return ret;
+
+ return sprintf(buf, "%u\n", !!(val & (1 << bit)));
+}
+
+static ssize_t
+show_beep(struct device *dev, struct device_attribute *attr, char *buf)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ unsigned int regval;
+ int err;
+
+ err = regmap_read(data->regmap, sattr->nr, &regval);
+ if (err)
+ return err;
+
+ return sprintf(buf, "%u\n", !!(regval & (1 << sattr->index)));
+}
+
+static ssize_t
+store_beep(struct device *dev, struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct sensor_device_attribute_2 *sattr = to_sensor_dev_attr_2(attr);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ unsigned long val;
+ int err;
+
+ err = kstrtoul(buf, 10, &val);
+ if (err < 0)
+ return err;
+ if (val > 1)
+ return -EINVAL;
+
+ err = regmap_update_bits(data->regmap, sattr->nr, 1 << sattr->index,
+ val ? 1 << sattr->index : 0);
+ return err ? : count;
+}
+
+static SENSOR_DEVICE_ATTR_2(temp1_input, S_IRUGO, show_temp, NULL, 0x01,
+ REG_TEMP_LSB);
+static SENSOR_DEVICE_ATTR_2(temp1_min, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x31, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_max, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x30, 0);
+static SENSOR_DEVICE_ATTR_2(temp1_crit, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x3a, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp2_input, S_IRUGO, show_temp, NULL, 0x02,
+ REG_TEMP_LSB);
+static SENSOR_DEVICE_ATTR_2(temp2_min, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x33, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_max, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x32, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_crit, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x3b, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp3_input, S_IRUGO, show_temp, NULL, 0x03,
+ REG_TEMP_LSB);
+static SENSOR_DEVICE_ATTR_2(temp3_min, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x35, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_max, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x34, 0);
+static SENSOR_DEVICE_ATTR_2(temp3_crit, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x3c, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp4_input, S_IRUGO, show_temp, NULL, 0x04, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_min, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x37, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_max, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x36, 0);
+static SENSOR_DEVICE_ATTR_2(temp4_crit, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x3d, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp5_input, S_IRUGO, show_temp, NULL, 0x06,
+ REG_TEMP_PECI_LSB);
+static SENSOR_DEVICE_ATTR_2(temp5_min, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x39, 0);
+static SENSOR_DEVICE_ATTR_2(temp5_max, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x38, 0);
+static SENSOR_DEVICE_ATTR_2(temp5_crit, S_IRUGO | S_IWUSR, show_temp,
+ store_temp, 0x3e, 0);
+
+static SENSOR_DEVICE_ATTR_2(temp6_input, S_IRUGO, show_temp, NULL, 0x07,
+ REG_TEMP_PECI_LSB);
+
+static SENSOR_DEVICE_ATTR_2(temp1_min_alarm, S_IRUGO, show_alarm, NULL,
+ 0x18, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_min_alarm, S_IRUGO, show_alarm, NULL,
+ 0x18, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_min_alarm, S_IRUGO, show_alarm, NULL,
+ 0x18, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_min_alarm, S_IRUGO, show_alarm, NULL,
+ 0x18, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_min_alarm, S_IRUGO, show_alarm, NULL,
+ 0x18, 4);
+
+static SENSOR_DEVICE_ATTR_2(temp1_max_alarm, S_IRUGO, show_alarm, NULL,
+ 0x19, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_max_alarm, S_IRUGO, show_alarm, NULL,
+ 0x19, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_max_alarm, S_IRUGO, show_alarm, NULL,
+ 0x19, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_max_alarm, S_IRUGO, show_alarm, NULL,
+ 0x19, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_max_alarm, S_IRUGO, show_alarm, NULL,
+ 0x19, 4);
+
+static SENSOR_DEVICE_ATTR_2(temp1_crit_alarm, S_IRUGO, show_alarm, NULL,
+ 0x1b, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_crit_alarm, S_IRUGO, show_alarm, NULL,
+ 0x1b, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_crit_alarm, S_IRUGO, show_alarm, NULL,
+ 0x1b, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_crit_alarm, S_IRUGO, show_alarm, NULL,
+ 0x1b, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_crit_alarm, S_IRUGO, show_alarm, NULL,
+ 0x1b, 4);
+
+static SENSOR_DEVICE_ATTR_2(temp1_fault, S_IRUGO, show_alarm, NULL, 0x17, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_fault, S_IRUGO, show_alarm, NULL, 0x17, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_fault, S_IRUGO, show_alarm, NULL, 0x17, 2);
+
+static SENSOR_DEVICE_ATTR_2(temp1_beep, S_IRUGO | S_IWUSR, show_beep,
+ store_beep, 0x5c, 0);
+static SENSOR_DEVICE_ATTR_2(temp2_beep, S_IRUGO | S_IWUSR, show_beep,
+ store_beep, 0x5c, 1);
+static SENSOR_DEVICE_ATTR_2(temp3_beep, S_IRUGO | S_IWUSR, show_beep,
+ store_beep, 0x5c, 2);
+static SENSOR_DEVICE_ATTR_2(temp4_beep, S_IRUGO | S_IWUSR, show_beep,
+ store_beep, 0x5c, 3);
+static SENSOR_DEVICE_ATTR_2(temp5_beep, S_IRUGO | S_IWUSR, show_beep,
+ store_beep, 0x5c, 4);
+static SENSOR_DEVICE_ATTR_2(temp6_beep, S_IRUGO | S_IWUSR, show_beep,
+ store_beep, 0x5c, 5);
+
+static struct attribute *nct7802_temp_attrs[] = {
+ &sensor_dev_attr_temp1_input.dev_attr.attr,
+ &sensor_dev_attr_temp1_min.dev_attr.attr,
+ &sensor_dev_attr_temp1_max.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit.dev_attr.attr,
+ &sensor_dev_attr_temp1_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp1_fault.dev_attr.attr,
+ &sensor_dev_attr_temp1_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp2_input.dev_attr.attr, /* 9 */
+ &sensor_dev_attr_temp2_min.dev_attr.attr,
+ &sensor_dev_attr_temp2_max.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit.dev_attr.attr,
+ &sensor_dev_attr_temp2_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp2_fault.dev_attr.attr,
+ &sensor_dev_attr_temp2_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp3_input.dev_attr.attr, /* 18 */
+ &sensor_dev_attr_temp3_min.dev_attr.attr,
+ &sensor_dev_attr_temp3_max.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit.dev_attr.attr,
+ &sensor_dev_attr_temp3_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp3_fault.dev_attr.attr,
+ &sensor_dev_attr_temp3_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp4_input.dev_attr.attr, /* 27 */
+ &sensor_dev_attr_temp4_min.dev_attr.attr,
+ &sensor_dev_attr_temp4_max.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit.dev_attr.attr,
+ &sensor_dev_attr_temp4_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp4_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp5_input.dev_attr.attr, /* 35 */
+ &sensor_dev_attr_temp5_min.dev_attr.attr,
+ &sensor_dev_attr_temp5_max.dev_attr.attr,
+ &sensor_dev_attr_temp5_crit.dev_attr.attr,
+ &sensor_dev_attr_temp5_min_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_max_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_crit_alarm.dev_attr.attr,
+ &sensor_dev_attr_temp5_beep.dev_attr.attr,
+
+ &sensor_dev_attr_temp6_input.dev_attr.attr, /* 43 */
+ &sensor_dev_attr_temp6_beep.dev_attr.attr,
+
+ NULL
+};
+
+static umode_t nct7802_temp_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ unsigned int reg;
+ int err;
+
+ err = regmap_read(data->regmap, REG_MODE, &reg);
+ if (err < 0)
+ return 0;
+
+ if (index < 9 &&
+ (reg & 03) != 0x01 && (reg & 0x03) != 0x02) /* RD1 */
+ return 0;
+ if (index >= 9 && index < 18 &&
+ (reg & 0x0c) != 0x04 && (reg & 0x0c) != 0x08) /* RD2 */
+ return 0;
+ if (index >= 18 && index < 27 && (reg & 0x30) != 0x10) /* RD3 */
+ return 0;
+ if (index >= 27 && index < 35) /* local */
+ return attr->mode;
+
+ err = regmap_read(data->regmap, REG_PECI_ENABLE, &reg);
+ if (err < 0)
+ return 0;
+
+ if (index >= 35 && index < 43 && !(reg & 0x01)) /* PECI 0 */
+ return 0;
+
+ if (index >= 0x43 && (!(reg & 0x02))) /* PECI 1 */
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute_group nct7802_temp_group = {
+ .attrs = nct7802_temp_attrs,
+ .is_visible = nct7802_temp_is_visible,
+};
+
+static SENSOR_DEVICE_ATTR_2(in0_input, S_IRUGO, show_in, NULL, 0, 0);
+static SENSOR_DEVICE_ATTR_2(in0_min, S_IRUGO | S_IWUSR, show_in, store_in,
+ 0, 1);
+static SENSOR_DEVICE_ATTR_2(in0_max, S_IRUGO | S_IWUSR, show_in, store_in,
+ 0, 2);
+static SENSOR_DEVICE_ATTR_2(in0_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 3);
+static SENSOR_DEVICE_ATTR_2(in0_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5a, 3);
+
+static SENSOR_DEVICE_ATTR_2(in1_input, S_IRUGO, show_in, NULL, 1, 0);
+
+static SENSOR_DEVICE_ATTR_2(in2_input, S_IRUGO, show_in, NULL, 2, 0);
+static SENSOR_DEVICE_ATTR_2(in2_min, S_IRUGO | S_IWUSR, show_in, store_in,
+ 2, 1);
+static SENSOR_DEVICE_ATTR_2(in2_max, S_IRUGO | S_IWUSR, show_in, store_in,
+ 2, 2);
+static SENSOR_DEVICE_ATTR_2(in2_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 0);
+static SENSOR_DEVICE_ATTR_2(in2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5a, 0);
+
+static SENSOR_DEVICE_ATTR_2(in3_input, S_IRUGO, show_in, NULL, 3, 0);
+static SENSOR_DEVICE_ATTR_2(in3_min, S_IRUGO | S_IWUSR, show_in, store_in,
+ 3, 1);
+static SENSOR_DEVICE_ATTR_2(in3_max, S_IRUGO | S_IWUSR, show_in, store_in,
+ 3, 2);
+static SENSOR_DEVICE_ATTR_2(in3_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 1);
+static SENSOR_DEVICE_ATTR_2(in3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5a, 1);
+
+static SENSOR_DEVICE_ATTR_2(in4_input, S_IRUGO, show_in, NULL, 4, 0);
+static SENSOR_DEVICE_ATTR_2(in4_min, S_IRUGO | S_IWUSR, show_in, store_in,
+ 4, 1);
+static SENSOR_DEVICE_ATTR_2(in4_max, S_IRUGO | S_IWUSR, show_in, store_in,
+ 4, 2);
+static SENSOR_DEVICE_ATTR_2(in4_alarm, S_IRUGO, show_alarm, NULL, 0x1e, 2);
+static SENSOR_DEVICE_ATTR_2(in4_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5a, 2);
+
+static struct attribute *nct7802_in_attrs[] = {
+ &sensor_dev_attr_in0_input.dev_attr.attr,
+ &sensor_dev_attr_in0_min.dev_attr.attr,
+ &sensor_dev_attr_in0_max.dev_attr.attr,
+ &sensor_dev_attr_in0_alarm.dev_attr.attr,
+ &sensor_dev_attr_in0_beep.dev_attr.attr,
+
+ &sensor_dev_attr_in1_input.dev_attr.attr, /* 5 */
+
+ &sensor_dev_attr_in2_input.dev_attr.attr, /* 6 */
+ &sensor_dev_attr_in2_min.dev_attr.attr,
+ &sensor_dev_attr_in2_max.dev_attr.attr,
+ &sensor_dev_attr_in2_alarm.dev_attr.attr,
+ &sensor_dev_attr_in2_beep.dev_attr.attr,
+
+ &sensor_dev_attr_in3_input.dev_attr.attr, /* 11 */
+ &sensor_dev_attr_in3_min.dev_attr.attr,
+ &sensor_dev_attr_in3_max.dev_attr.attr,
+ &sensor_dev_attr_in3_alarm.dev_attr.attr,
+ &sensor_dev_attr_in3_beep.dev_attr.attr,
+
+ &sensor_dev_attr_in4_input.dev_attr.attr, /* 17 */
+ &sensor_dev_attr_in4_min.dev_attr.attr,
+ &sensor_dev_attr_in4_max.dev_attr.attr,
+ &sensor_dev_attr_in4_alarm.dev_attr.attr,
+ &sensor_dev_attr_in4_beep.dev_attr.attr,
+
+ NULL,
+};
+
+static umode_t nct7802_in_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ unsigned int reg;
+ int err;
+
+ if (index < 6) /* VCC, VCORE */
+ return attr->mode;
+
+ err = regmap_read(data->regmap, REG_MODE, &reg);
+ if (err < 0)
+ return 0;
+
+ if (index >= 6 && index < 11 && (reg & 0x03) != 0x03) /* VSEN1 */
+ return 0;
+ if (index >= 11 && index < 17 && (reg & 0x0c) != 0x0c) /* VSEN2 */
+ return 0;
+ if (index >= 17 && (reg & 0x30) != 0x30) /* VSEN3 */
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute_group nct7802_in_group = {
+ .attrs = nct7802_in_attrs,
+ .is_visible = nct7802_in_is_visible,
+};
+
+static SENSOR_DEVICE_ATTR(fan1_input, S_IRUGO, show_fan, NULL, 0x10);
+static SENSOR_DEVICE_ATTR_2(fan1_min, S_IRUGO | S_IWUSR, show_fan_min,
+ store_fan_min, 0x49, 0x4c);
+static SENSOR_DEVICE_ATTR_2(fan1_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 0);
+static SENSOR_DEVICE_ATTR_2(fan1_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5b, 0);
+static SENSOR_DEVICE_ATTR(fan2_input, S_IRUGO, show_fan, NULL, 0x11);
+static SENSOR_DEVICE_ATTR_2(fan2_min, S_IRUGO | S_IWUSR, show_fan_min,
+ store_fan_min, 0x4a, 0x4d);
+static SENSOR_DEVICE_ATTR_2(fan2_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 1);
+static SENSOR_DEVICE_ATTR_2(fan2_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5b, 1);
+static SENSOR_DEVICE_ATTR(fan3_input, S_IRUGO, show_fan, NULL, 0x12);
+static SENSOR_DEVICE_ATTR_2(fan3_min, S_IRUGO | S_IWUSR, show_fan_min,
+ store_fan_min, 0x4b, 0x4e);
+static SENSOR_DEVICE_ATTR_2(fan3_alarm, S_IRUGO, show_alarm, NULL, 0x1a, 2);
+static SENSOR_DEVICE_ATTR_2(fan3_beep, S_IRUGO | S_IWUSR, show_beep, store_beep,
+ 0x5b, 2);
+
+static struct attribute *nct7802_fan_attrs[] = {
+ &sensor_dev_attr_fan1_input.dev_attr.attr,
+ &sensor_dev_attr_fan1_min.dev_attr.attr,
+ &sensor_dev_attr_fan1_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan1_beep.dev_attr.attr,
+ &sensor_dev_attr_fan2_input.dev_attr.attr,
+ &sensor_dev_attr_fan2_min.dev_attr.attr,
+ &sensor_dev_attr_fan2_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan2_beep.dev_attr.attr,
+ &sensor_dev_attr_fan3_input.dev_attr.attr,
+ &sensor_dev_attr_fan3_min.dev_attr.attr,
+ &sensor_dev_attr_fan3_alarm.dev_attr.attr,
+ &sensor_dev_attr_fan3_beep.dev_attr.attr,
+
+ NULL
+};
+
+static umode_t nct7802_fan_is_visible(struct kobject *kobj,
+ struct attribute *attr, int index)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct nct7802_data *data = dev_get_drvdata(dev);
+ int fan = index / 4; /* 4 attributes per fan */
+ unsigned int reg;
+ int err;
+
+ err = regmap_read(data->regmap, REG_FAN_ENABLE, &reg);
+ if (err < 0 || !(reg & (1 << fan)))
+ return 0;
+
+ return attr->mode;
+}
+
+static struct attribute_group nct7802_fan_group = {
+ .attrs = nct7802_fan_attrs,
+ .is_visible = nct7802_fan_is_visible,
+};
+
+static const struct attribute_group *nct7802_groups[] = {
+ &nct7802_temp_group,
+ &nct7802_in_group,
+ &nct7802_fan_group,
+ NULL
+};
+
+static int nct7802_detect(struct i2c_client *client,
+ struct i2c_board_info *info)
+{
+ int reg;
+
+ /*
+ * Chip identification registers are only available in bank 0,
+ * so only attempt chip detection if bank 0 is selected
+ */
+ reg = i2c_smbus_read_byte_data(client, REG_BANK);
+ if (reg != 0x00)
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, REG_VENDOR_ID);
+ if (reg != 0x50)
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, REG_CHIP_ID);
+ if (reg != 0xc3)
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, REG_VERSION_ID);
+ if (reg < 0 || (reg & 0xf0) != 0x20)
+ return -ENODEV;
+
+ /* Also validate lower bits of voltage and temperature registers */
+ reg = i2c_smbus_read_byte_data(client, REG_TEMP_LSB);
+ if (reg < 0 || (reg & 0x1f))
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, REG_TEMP_PECI_LSB);
+ if (reg < 0 || (reg & 0x3f))
+ return -ENODEV;
+
+ reg = i2c_smbus_read_byte_data(client, REG_VOLTAGE_LOW);
+ if (reg < 0 || (reg & 0x3f))
+ return -ENODEV;
+
+ strlcpy(info->type, "nct7802", I2C_NAME_SIZE);
+ return 0;
+}
+
+static bool nct7802_regmap_is_volatile(struct device *dev, unsigned int reg)
+{
+ return reg != REG_BANK && reg <= 0x20;
+}
+
+static struct regmap_config nct7802_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .cache_type = REGCACHE_RBTREE,
+ .volatile_reg = nct7802_regmap_is_volatile,
+};
+
+static int nct7802_init_chip(struct nct7802_data *data)
+{
+ int err;
+
+ /* Enable ADC */
+ err = regmap_update_bits(data->regmap, REG_START, 0x01, 0x01);
+ if (err)
+ return err;
+
+ /* Enable local temperature sensor */
+ err = regmap_update_bits(data->regmap, REG_MODE, 0x40, 0x40);
+ if (err)
+ return err;
+
+ /* Enable Vcore and VCC voltage monitoring */
+ return regmap_update_bits(data->regmap, REG_VMON_ENABLE, 0x03, 0x03);
+}
+
+static int nct7802_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct device *dev = &client->dev;
+ struct nct7802_data *data;
+ struct device *hwmon_dev;
+ int ret;
+
+ data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->regmap = devm_regmap_init_i2c(client, &nct7802_regmap_config);
+ if (IS_ERR(data->regmap))
+ return PTR_ERR(data->regmap);
+
+ mutex_init(&data->access_lock);
+
+ ret = nct7802_init_chip(data);
+ if (ret < 0)
+ return ret;
+
+ hwmon_dev = devm_hwmon_device_register_with_groups(dev, client->name,
+ data,
+ nct7802_groups);
+ return PTR_ERR_OR_ZERO(hwmon_dev);
+}
+
+static const unsigned short nct7802_address_list[] = {
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, I2C_CLIENT_END
+};
+
+static const struct i2c_device_id nct7802_idtable[] = {
+ { "nct7802", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, nct7802_idtable);
+
+static struct i2c_driver nct7802_driver = {
+ .class = I2C_CLASS_HWMON,
+ .driver = {
+ .name = DRVNAME,
+ },
+ .detect = nct7802_detect,
+ .probe = nct7802_probe,
+ .id_table = nct7802_idtable,
+ .address_list = nct7802_address_list,
+};
+
+module_i2c_driver(nct7802_driver);
+
+MODULE_AUTHOR("Guenter Roeck <linux@roeck-us.net>");
+MODULE_DESCRIPTION("NCT7802Y Hardware Monitoring Driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/hwmon/pmbus/Kconfig b/drivers/hwmon/pmbus/Kconfig
index 6e1e493..a674cd8 100644
--- a/drivers/hwmon/pmbus/Kconfig
+++ b/drivers/hwmon/pmbus/Kconfig
@@ -47,15 +47,22 @@ config SENSORS_LM25066
be called lm25066.
config SENSORS_LTC2978
- tristate "Linear Technologies LTC2974, LTC2978, LTC3880, and LTC3883"
+ tristate "Linear Technologies LTC2978 and compatibles"
default n
help
If you say yes here you get hardware monitoring support for Linear
- Technology LTC2974, LTC2978, LTC3880, and LTC3883.
+ Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
This driver can also be built as a module. If so, the module will
be called ltc2978.
+config SENSORS_LTC2978_REGULATOR
+ boolean "Regulator support for LTC2978 and compatibles"
+ depends on SENSORS_LTC2978 && REGULATOR
+ help
+ If you say yes here you get regulator support for Linear
+ Technology LTC2974, LTC2977, LTC2978, LTC3880, LTC3883, and LTM4676.
+
config SENSORS_MAX16064
tristate "Maxim MAX16064"
default n
diff --git a/drivers/hwmon/pmbus/ltc2978.c b/drivers/hwmon/pmbus/ltc2978.c
index e24ed52..0835050 100644
--- a/drivers/hwmon/pmbus/ltc2978.c
+++ b/drivers/hwmon/pmbus/ltc2978.c
@@ -22,6 +22,7 @@
#include <linux/err.h>
#include <linux/slab.h>
#include <linux/i2c.h>
+#include <linux/regulator/driver.h>
#include "pmbus.h"
enum chips { ltc2974, ltc2977, ltc2978, ltc3880, ltc3883, ltm4676 };
@@ -374,6 +375,19 @@ static const struct i2c_device_id ltc2978_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ltc2978_id);
+#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
+static const struct regulator_desc ltc2978_reg_desc[] = {
+ PMBUS_REGULATOR("vout", 0),
+ PMBUS_REGULATOR("vout", 1),
+ PMBUS_REGULATOR("vout", 2),
+ PMBUS_REGULATOR("vout", 3),
+ PMBUS_REGULATOR("vout", 4),
+ PMBUS_REGULATOR("vout", 5),
+ PMBUS_REGULATOR("vout", 6),
+ PMBUS_REGULATOR("vout", 7),
+};
+#endif /* CONFIG_SENSORS_LTC2978_REGULATOR */
+
static int ltc2978_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -487,13 +501,36 @@ static int ltc2978_probe(struct i2c_client *client,
default:
return -ENODEV;
}
+
+#if IS_ENABLED(CONFIG_SENSORS_LTC2978_REGULATOR)
+ info->num_regulators = info->pages;
+ info->reg_desc = ltc2978_reg_desc;
+ if (info->num_regulators > ARRAY_SIZE(ltc2978_reg_desc)) {
+ dev_err(&client->dev, "num_regulators too large!");
+ info->num_regulators = ARRAY_SIZE(ltc2978_reg_desc);
+ }
+#endif
+
return pmbus_do_probe(client, id, info);
}
-/* This is the driver that will be inserted */
+#ifdef CONFIG_OF
+static const struct of_device_id ltc2978_of_match[] = {
+ { .compatible = "lltc,ltc2974" },
+ { .compatible = "lltc,ltc2977" },
+ { .compatible = "lltc,ltc2978" },
+ { .compatible = "lltc,ltc3880" },
+ { .compatible = "lltc,ltc3883" },
+ { .compatible = "lltc,ltm4676" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ltc2978_of_match);
+#endif
+
static struct i2c_driver ltc2978_driver = {
.driver = {
.name = "ltc2978",
+ .of_match_table = of_match_ptr(ltc2978_of_match),
},
.probe = ltc2978_probe,
.remove = pmbus_do_remove,
diff --git a/drivers/hwmon/pmbus/pmbus.h b/drivers/hwmon/pmbus/pmbus.h
index fa9beb3..89a23ff 100644
--- a/drivers/hwmon/pmbus/pmbus.h
+++ b/drivers/hwmon/pmbus/pmbus.h
@@ -19,6 +19,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/regulator/driver.h>
+
#ifndef PMBUS_H
#define PMBUS_H
@@ -186,6 +188,11 @@
#define PMBUS_VIRT_STATUS_VMON (PMBUS_VIRT_BASE + 35)
/*
+ * OPERATION
+ */
+#define PB_OPERATION_CONTROL_ON (1<<7)
+
+/*
* CAPABILITY
*/
#define PB_CAPABILITY_SMBALERT (1<<4)
@@ -365,8 +372,27 @@ struct pmbus_driver_info {
*/
int (*identify)(struct i2c_client *client,
struct pmbus_driver_info *info);
+
+ /* Regulator functionality, if supported by this chip driver. */
+ int num_regulators;
+ const struct regulator_desc *reg_desc;
};
+/* Regulator ops */
+
+extern struct regulator_ops pmbus_regulator_ops;
+
+/* Macro for filling in array of struct regulator_desc */
+#define PMBUS_REGULATOR(_name, _id) \
+ [_id] = { \
+ .name = (_name # _id), \
+ .id = (_id), \
+ .of_match = of_match_ptr(_name # _id), \
+ .regulators_node = of_match_ptr("regulators"), \
+ .ops = &pmbus_regulator_ops, \
+ .owner = THIS_MODULE, \
+ }
+
/* Function declarations */
void pmbus_clear_cache(struct i2c_client *client);
@@ -375,6 +401,10 @@ int pmbus_read_word_data(struct i2c_client *client, u8 page, u8 reg);
int pmbus_write_word_data(struct i2c_client *client, u8 page, u8 reg, u16 word);
int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg);
int pmbus_write_byte(struct i2c_client *client, int page, u8 value);
+int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg,
+ u8 value);
+int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
+ u8 mask, u8 value);
void pmbus_clear_faults(struct i2c_client *client);
bool pmbus_check_byte_register(struct i2c_client *client, int page, int reg);
bool pmbus_check_word_register(struct i2c_client *client, int page, int reg);
diff --git a/drivers/hwmon/pmbus/pmbus_core.c b/drivers/hwmon/pmbus/pmbus_core.c
index 291d11f..f2e47c7 100644
--- a/drivers/hwmon/pmbus/pmbus_core.c
+++ b/drivers/hwmon/pmbus/pmbus_core.c
@@ -29,6 +29,8 @@
#include <linux/hwmon-sysfs.h>
#include <linux/jiffies.h>
#include <linux/i2c/pmbus.h>
+#include <linux/regulator/driver.h>
+#include <linux/regulator/machine.h>
#include "pmbus.h"
/*
@@ -253,6 +255,37 @@ int pmbus_read_byte_data(struct i2c_client *client, int page, u8 reg)
}
EXPORT_SYMBOL_GPL(pmbus_read_byte_data);
+int pmbus_write_byte_data(struct i2c_client *client, int page, u8 reg, u8 value)
+{
+ int rv;
+
+ rv = pmbus_set_page(client, page);
+ if (rv < 0)
+ return rv;
+
+ return i2c_smbus_write_byte_data(client, reg, value);
+}
+EXPORT_SYMBOL_GPL(pmbus_write_byte_data);
+
+int pmbus_update_byte_data(struct i2c_client *client, int page, u8 reg,
+ u8 mask, u8 value)
+{
+ unsigned int tmp;
+ int rv;
+
+ rv = pmbus_read_byte_data(client, page, reg);
+ if (rv < 0)
+ return rv;
+
+ tmp = (rv & ~mask) | (value & mask);
+
+ if (tmp != rv)
+ rv = pmbus_write_byte_data(client, page, reg, tmp);
+
+ return rv;
+}
+EXPORT_SYMBOL_GPL(pmbus_update_byte_data);
+
/*
* _pmbus_read_byte_data() is similar to pmbus_read_byte_data(), but checks if
* a device specific mapping function exists and calls it if necessary.
@@ -1727,6 +1760,84 @@ static int pmbus_init_common(struct i2c_client *client, struct pmbus_data *data,
return 0;
}
+#if IS_ENABLED(CONFIG_REGULATOR)
+static int pmbus_regulator_is_enabled(struct regulator_dev *rdev)
+{
+ struct device *dev = rdev_get_dev(rdev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ u8 page = rdev_get_id(rdev);
+ int ret;
+
+ ret = pmbus_read_byte_data(client, page, PMBUS_OPERATION);
+ if (ret < 0)
+ return ret;
+
+ return !!(ret & PB_OPERATION_CONTROL_ON);
+}
+
+static int _pmbus_regulator_on_off(struct regulator_dev *rdev, bool enable)
+{
+ struct device *dev = rdev_get_dev(rdev);
+ struct i2c_client *client = to_i2c_client(dev->parent);
+ u8 page = rdev_get_id(rdev);
+
+ return pmbus_update_byte_data(client, page, PMBUS_OPERATION,
+ PB_OPERATION_CONTROL_ON,
+ enable ? PB_OPERATION_CONTROL_ON : 0);
+}
+
+static int pmbus_regulator_enable(struct regulator_dev *rdev)
+{
+ return _pmbus_regulator_on_off(rdev, 1);
+}
+
+static int pmbus_regulator_disable(struct regulator_dev *rdev)
+{
+ return _pmbus_regulator_on_off(rdev, 0);
+}
+
+struct regulator_ops pmbus_regulator_ops = {
+ .enable = pmbus_regulator_enable,
+ .disable = pmbus_regulator_disable,
+ .is_enabled = pmbus_regulator_is_enabled,
+};
+EXPORT_SYMBOL_GPL(pmbus_regulator_ops);
+
+static int pmbus_regulator_register(struct pmbus_data *data)
+{
+ struct device *dev = data->dev;
+ const struct pmbus_driver_info *info = data->info;
+ const struct pmbus_platform_data *pdata = dev_get_platdata(dev);
+ struct regulator_dev *rdev;
+ int i;
+
+ for (i = 0; i < info->num_regulators; i++) {
+ struct regulator_config config = { };
+
+ config.dev = dev;
+ config.driver_data = data;
+
+ if (pdata && pdata->reg_init_data)
+ config.init_data = &pdata->reg_init_data[i];
+
+ rdev = devm_regulator_register(dev, &info->reg_desc[i],
+ &config);
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "Failed to register %s regulator\n",
+ info->reg_desc[i].name);
+ return PTR_ERR(rdev);
+ }
+ }
+
+ return 0;
+}
+#else
+static int pmbus_regulator_register(struct pmbus_data *data)
+{
+ return 0;
+}
+#endif
+
int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
struct pmbus_driver_info *info)
{
@@ -1781,8 +1892,15 @@ int pmbus_do_probe(struct i2c_client *client, const struct i2c_device_id *id,
dev_err(dev, "Failed to register hwmon device\n");
goto out_kfree;
}
+
+ ret = pmbus_regulator_register(data);
+ if (ret)
+ goto out_unregister;
+
return 0;
+out_unregister:
+ hwmon_device_unregister(data->hwmon_dev);
out_kfree:
kfree(data->group.attrs);
return ret;
diff --git a/drivers/hwmon/tmp401.c b/drivers/hwmon/tmp401.c
index 7fa6e7d..99664eb 100644
--- a/drivers/hwmon/tmp401.c
+++ b/drivers/hwmon/tmp401.c
@@ -44,9 +44,10 @@
#include <linux/sysfs.h>
/* Addresses to scan */
-static const unsigned short normal_i2c[] = { 0x4c, 0x4d, 0x4e, I2C_CLIENT_END };
+static const unsigned short normal_i2c[] = { 0x37, 0x48, 0x49, 0x4a, 0x4c, 0x4d,
+ 0x4e, 0x4f, I2C_CLIENT_END };
-enum chips { tmp401, tmp411, tmp431, tmp432 };
+enum chips { tmp401, tmp411, tmp431, tmp432, tmp435 };
/*
* The TMP401 registers, note some registers have different addresses for
@@ -136,6 +137,7 @@ static const u8 TMP432_STATUS_REG[] = {
#define TMP411C_DEVICE_ID 0x10
#define TMP431_DEVICE_ID 0x31
#define TMP432_DEVICE_ID 0x32
+#define TMP435_DEVICE_ID 0x35
/*
* Driver data (common to all clients)
@@ -146,6 +148,7 @@ static const struct i2c_device_id tmp401_id[] = {
{ "tmp411", tmp411 },
{ "tmp431", tmp431 },
{ "tmp432", tmp432 },
+ { "tmp435", tmp435 },
{ }
};
MODULE_DEVICE_TABLE(i2c, tmp401_id);
@@ -613,10 +616,10 @@ static const struct attribute_group tmp432_group = {
* Begin non sysfs callback code (aka Real code)
*/
-static void tmp401_init_client(struct tmp401_data *data,
- struct i2c_client *client)
+static int tmp401_init_client(struct tmp401_data *data,
+ struct i2c_client *client)
{
- int config, config_orig;
+ int config, config_orig, status = 0;
/* Set the conversion rate to 2 Hz */
i2c_smbus_write_byte_data(client, TMP401_CONVERSION_RATE_WRITE, 5);
@@ -624,16 +627,18 @@ static void tmp401_init_client(struct tmp401_data *data,
/* Start conversions (disable shutdown if necessary) */
config = i2c_smbus_read_byte_data(client, TMP401_CONFIG_READ);
- if (config < 0) {
- dev_warn(&client->dev, "Initialization failed!\n");
- return;
- }
+ if (config < 0)
+ return config;
config_orig = config;
config &= ~TMP401_CONFIG_SHUTDOWN;
if (config != config_orig)
- i2c_smbus_write_byte_data(client, TMP401_CONFIG_WRITE, config);
+ status = i2c_smbus_write_byte_data(client,
+ TMP401_CONFIG_WRITE,
+ config);
+
+ return status;
}
static int tmp401_detect(struct i2c_client *client,
@@ -675,15 +680,18 @@ static int tmp401_detect(struct i2c_client *client,
kind = tmp411;
break;
case TMP431_DEVICE_ID:
- if (client->addr == 0x4e)
+ if (client->addr != 0x4c && client->addr != 0x4d)
return -ENODEV;
kind = tmp431;
break;
case TMP432_DEVICE_ID:
- if (client->addr == 0x4e)
+ if (client->addr != 0x4c && client->addr != 0x4d)
return -ENODEV;
kind = tmp432;
break;
+ case TMP435_DEVICE_ID:
+ kind = tmp435;
+ break;
default:
return -ENODEV;
}
@@ -705,11 +713,13 @@ static int tmp401_detect(struct i2c_client *client,
static int tmp401_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
- const char *names[] = { "TMP401", "TMP411", "TMP431", "TMP432" };
+ static const char * const names[] = {
+ "TMP401", "TMP411", "TMP431", "TMP432", "TMP435"
+ };
struct device *dev = &client->dev;
struct device *hwmon_dev;
struct tmp401_data *data;
- int groups = 0;
+ int groups = 0, status;
data = devm_kzalloc(dev, sizeof(struct tmp401_data), GFP_KERNEL);
if (!data)
@@ -720,7 +730,9 @@ static int tmp401_probe(struct i2c_client *client,
data->kind = id->driver_data;
/* Initialize the TMP401 chip */
- tmp401_init_client(data, client);
+ status = tmp401_init_client(data, client);
+ if (status < 0)
+ return status;
/* Register sysfs hooks */
data->groups[groups++] = &tmp401_group;
diff --git a/drivers/i2c/busses/Kconfig b/drivers/i2c/busses/Kconfig
index 917c358..b4d135c 100644
--- a/drivers/i2c/busses/Kconfig
+++ b/drivers/i2c/busses/Kconfig
@@ -881,6 +881,16 @@ config I2C_DIOLAN_U2C
This driver can also be built as a module. If so, the module
will be called i2c-diolan-u2c.
+config I2C_DLN2
+ tristate "Diolan DLN-2 USB I2C adapter"
+ depends on MFD_DLN2
+ help
+ If you say yes to this option, support will be included for Diolan
+ DLN2, a USB to I2C interface.
+
+ This driver can also be built as a module. If so, the module
+ will be called i2c-dln2.
+
config I2C_PARPORT
tristate "Parallel port adapter"
depends on PARPORT
diff --git a/drivers/i2c/busses/Makefile b/drivers/i2c/busses/Makefile
index 78d56c5..cdac7f1 100644
--- a/drivers/i2c/busses/Makefile
+++ b/drivers/i2c/busses/Makefile
@@ -87,6 +87,7 @@ obj-$(CONFIG_I2C_RCAR) += i2c-rcar.o
# External I2C/SMBus adapter drivers
obj-$(CONFIG_I2C_DIOLAN_U2C) += i2c-diolan-u2c.o
+obj-$(CONFIG_I2C_DLN2) += i2c-dln2.o
obj-$(CONFIG_I2C_PARPORT) += i2c-parport.o
obj-$(CONFIG_I2C_PARPORT_LIGHT) += i2c-parport-light.o
obj-$(CONFIG_I2C_ROBOTFUZZ_OSIF) += i2c-robotfuzz-osif.o
diff --git a/drivers/i2c/busses/i2c-cadence.c b/drivers/i2c/busses/i2c-cadence.c
index 63f3f03..c604f4c 100644
--- a/drivers/i2c/busses/i2c-cadence.c
+++ b/drivers/i2c/busses/i2c-cadence.c
@@ -111,6 +111,8 @@
#define CDNS_I2C_DIVA_MAX 4
#define CDNS_I2C_DIVB_MAX 64
+#define CDNS_I2C_TIMEOUT_MAX 0xFF
+
#define cdns_i2c_readreg(offset) readl_relaxed(id->membase + offset)
#define cdns_i2c_writereg(val, offset) writel_relaxed(val, id->membase + offset)
@@ -852,6 +854,15 @@ static int cdns_i2c_probe(struct platform_device *pdev)
goto err_clk_dis;
}
+ /*
+ * Cadence I2C controller has a bug wherein it generates
+ * invalid read transaction after HW timeout in master receiver mode.
+ * HW timeout is not used by this driver and the interrupt is disabled.
+ * But the feature itself cannot be disabled. Hence maximum value
+ * is written to this register to reduce the chances of error.
+ */
+ cdns_i2c_writereg(CDNS_I2C_TIMEOUT_MAX, CDNS_I2C_TIME_OUT_OFFSET);
+
dev_info(&pdev->dev, "%u kHz mmio %08lx irq %d\n",
id->i2c_clk / 1000, (unsigned long)r_mem->start, id->irq);
diff --git a/drivers/i2c/busses/i2c-davinci.c b/drivers/i2c/busses/i2c-davinci.c
index d15b7c9..01f0cd8 100644
--- a/drivers/i2c/busses/i2c-davinci.c
+++ b/drivers/i2c/busses/i2c-davinci.c
@@ -407,11 +407,9 @@ i2c_davinci_xfer_msg(struct i2c_adapter *adap, struct i2c_msg *msg, int stop)
if (dev->cmd_err & DAVINCI_I2C_STR_NACK) {
if (msg->flags & I2C_M_IGNORE_NAK)
return msg->len;
- if (stop) {
- w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
- w |= DAVINCI_I2C_MDR_STP;
- davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
- }
+ w = davinci_i2c_read_reg(dev, DAVINCI_I2C_MDR_REG);
+ w |= DAVINCI_I2C_MDR_STP;
+ davinci_i2c_write_reg(dev, DAVINCI_I2C_MDR_REG, w);
return -EREMOTEIO;
}
return -EIO;
diff --git a/drivers/i2c/busses/i2c-dln2.c b/drivers/i2c/busses/i2c-dln2.c
new file mode 100644
index 0000000..b3fb86a
--- /dev/null
+++ b/drivers/i2c/busses/i2c-dln2.c
@@ -0,0 +1,262 @@
+/*
+ * Driver for the Diolan DLN-2 USB-I2C adapter
+ *
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Derived from:
+ * i2c-diolan-u2c.c
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/dln2.h>
+
+#define DLN2_I2C_MODULE_ID 0x03
+#define DLN2_I2C_CMD(cmd) DLN2_CMD(cmd, DLN2_I2C_MODULE_ID)
+
+/* I2C commands */
+#define DLN2_I2C_GET_PORT_COUNT DLN2_I2C_CMD(0x00)
+#define DLN2_I2C_ENABLE DLN2_I2C_CMD(0x01)
+#define DLN2_I2C_DISABLE DLN2_I2C_CMD(0x02)
+#define DLN2_I2C_IS_ENABLED DLN2_I2C_CMD(0x03)
+#define DLN2_I2C_WRITE DLN2_I2C_CMD(0x06)
+#define DLN2_I2C_READ DLN2_I2C_CMD(0x07)
+#define DLN2_I2C_SCAN_DEVICES DLN2_I2C_CMD(0x08)
+#define DLN2_I2C_PULLUP_ENABLE DLN2_I2C_CMD(0x09)
+#define DLN2_I2C_PULLUP_DISABLE DLN2_I2C_CMD(0x0A)
+#define DLN2_I2C_PULLUP_IS_ENABLED DLN2_I2C_CMD(0x0B)
+#define DLN2_I2C_TRANSFER DLN2_I2C_CMD(0x0C)
+#define DLN2_I2C_SET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0D)
+#define DLN2_I2C_GET_MAX_REPLY_COUNT DLN2_I2C_CMD(0x0E)
+
+#define DLN2_I2C_MAX_XFER_SIZE 256
+#define DLN2_I2C_BUF_SIZE (DLN2_I2C_MAX_XFER_SIZE + 16)
+
+struct dln2_i2c {
+ struct platform_device *pdev;
+ struct i2c_adapter adapter;
+ u8 port;
+ /*
+ * Buffer to hold the packet for read or write transfers. One is enough
+ * since we can't have multiple transfers in parallel on the i2c bus.
+ */
+ void *buf;
+};
+
+static int dln2_i2c_enable(struct dln2_i2c *dln2, bool enable)
+{
+ u16 cmd;
+ struct {
+ u8 port;
+ } tx;
+
+ tx.port = dln2->port;
+
+ if (enable)
+ cmd = DLN2_I2C_ENABLE;
+ else
+ cmd = DLN2_I2C_DISABLE;
+
+ return dln2_transfer_tx(dln2->pdev, cmd, &tx, sizeof(tx));
+}
+
+static int dln2_i2c_write(struct dln2_i2c *dln2, u8 addr,
+ u8 *data, u16 data_len)
+{
+ int ret;
+ struct {
+ u8 port;
+ u8 addr;
+ u8 mem_addr_len;
+ __le32 mem_addr;
+ __le16 buf_len;
+ u8 buf[DLN2_I2C_MAX_XFER_SIZE];
+ } __packed *tx = dln2->buf;
+ unsigned len;
+
+ BUILD_BUG_ON(sizeof(*tx) > DLN2_I2C_BUF_SIZE);
+
+ tx->port = dln2->port;
+ tx->addr = addr;
+ tx->mem_addr_len = 0;
+ tx->mem_addr = 0;
+ tx->buf_len = cpu_to_le16(data_len);
+ memcpy(tx->buf, data, data_len);
+
+ len = sizeof(*tx) + data_len - DLN2_I2C_MAX_XFER_SIZE;
+ ret = dln2_transfer_tx(dln2->pdev, DLN2_I2C_WRITE, tx, len);
+ if (ret < 0)
+ return ret;
+
+ return data_len;
+}
+
+static int dln2_i2c_read(struct dln2_i2c *dln2, u16 addr, u8 *data,
+ u16 data_len)
+{
+ int ret;
+ struct {
+ u8 port;
+ u8 addr;
+ u8 mem_addr_len;
+ __le32 mem_addr;
+ __le16 buf_len;
+ } __packed tx;
+ struct {
+ __le16 buf_len;
+ u8 buf[DLN2_I2C_MAX_XFER_SIZE];
+ } __packed *rx = dln2->buf;
+ unsigned rx_len = sizeof(*rx);
+
+ BUILD_BUG_ON(sizeof(*rx) > DLN2_I2C_BUF_SIZE);
+
+ tx.port = dln2->port;
+ tx.addr = addr;
+ tx.mem_addr_len = 0;
+ tx.mem_addr = 0;
+ tx.buf_len = cpu_to_le16(data_len);
+
+ ret = dln2_transfer(dln2->pdev, DLN2_I2C_READ, &tx, sizeof(tx),
+ rx, &rx_len);
+ if (ret < 0)
+ return ret;
+ if (rx_len < sizeof(rx->buf_len) + data_len)
+ return -EPROTO;
+ if (le16_to_cpu(rx->buf_len) != data_len)
+ return -EPROTO;
+
+ memcpy(data, rx->buf, data_len);
+
+ return data_len;
+}
+
+static int dln2_i2c_xfer(struct i2c_adapter *adapter,
+ struct i2c_msg *msgs, int num)
+{
+ struct dln2_i2c *dln2 = i2c_get_adapdata(adapter);
+ struct i2c_msg *pmsg;
+ struct device *dev = &dln2->adapter.dev;
+ int i;
+
+ for (i = 0; i < num; i++) {
+ int ret;
+
+ pmsg = &msgs[i];
+
+ if (pmsg->len > DLN2_I2C_MAX_XFER_SIZE) {
+ dev_warn(dev, "maximum transfer size exceeded\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (pmsg->flags & I2C_M_RD) {
+ ret = dln2_i2c_read(dln2, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ if (ret < 0)
+ return ret;
+
+ pmsg->len = ret;
+ } else {
+ ret = dln2_i2c_write(dln2, pmsg->addr, pmsg->buf,
+ pmsg->len);
+ if (ret != pmsg->len)
+ return -EPROTO;
+ }
+ }
+
+ return num;
+}
+
+static u32 dln2_i2c_func(struct i2c_adapter *a)
+{
+ return I2C_FUNC_I2C | I2C_FUNC_SMBUS_BYTE | I2C_FUNC_SMBUS_BYTE_DATA |
+ I2C_FUNC_SMBUS_WORD_DATA | I2C_FUNC_SMBUS_BLOCK_PROC_CALL |
+ I2C_FUNC_SMBUS_I2C_BLOCK;
+}
+
+static const struct i2c_algorithm dln2_i2c_usb_algorithm = {
+ .master_xfer = dln2_i2c_xfer,
+ .functionality = dln2_i2c_func,
+};
+
+static int dln2_i2c_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct dln2_i2c *dln2;
+ struct device *dev = &pdev->dev;
+ struct dln2_platform_data *pdata = dev_get_platdata(&pdev->dev);
+
+ dln2 = devm_kzalloc(dev, sizeof(*dln2), GFP_KERNEL);
+ if (!dln2)
+ return -ENOMEM;
+
+ dln2->buf = devm_kmalloc(dev, DLN2_I2C_BUF_SIZE, GFP_KERNEL);
+ if (!dln2->buf)
+ return -ENOMEM;
+
+ dln2->pdev = pdev;
+ dln2->port = pdata->port;
+
+ /* setup i2c adapter description */
+ dln2->adapter.owner = THIS_MODULE;
+ dln2->adapter.class = I2C_CLASS_HWMON;
+ dln2->adapter.algo = &dln2_i2c_usb_algorithm;
+ dln2->adapter.dev.parent = dev;
+ i2c_set_adapdata(&dln2->adapter, dln2);
+ snprintf(dln2->adapter.name, sizeof(dln2->adapter.name), "%s-%s-%d",
+ "dln2-i2c", dev_name(pdev->dev.parent), dln2->port);
+
+ platform_set_drvdata(pdev, dln2);
+
+ /* initialize the i2c interface */
+ ret = dln2_i2c_enable(dln2, true);
+ if (ret < 0) {
+ dev_err(dev, "failed to initialize adapter: %d\n", ret);
+ return ret;
+ }
+
+ /* and finally attach to i2c layer */
+ ret = i2c_add_adapter(&dln2->adapter);
+ if (ret < 0) {
+ dev_err(dev, "failed to add I2C adapter: %d\n", ret);
+ goto out_disable;
+ }
+
+ return 0;
+
+out_disable:
+ dln2_i2c_enable(dln2, false);
+
+ return ret;
+}
+
+static int dln2_i2c_remove(struct platform_device *pdev)
+{
+ struct dln2_i2c *dln2 = platform_get_drvdata(pdev);
+
+ i2c_del_adapter(&dln2->adapter);
+ dln2_i2c_enable(dln2, false);
+
+ return 0;
+}
+
+static struct platform_driver dln2_i2c_driver = {
+ .driver.name = "dln2-i2c",
+ .probe = dln2_i2c_probe,
+ .remove = dln2_i2c_remove,
+};
+
+module_platform_driver(dln2_i2c_driver);
+
+MODULE_AUTHOR("Laurentiu Palcu <laurentiu.palcu@intel.com>");
+MODULE_DESCRIPTION("Driver for the Diolan DLN2 I2C master interface");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:dln2-i2c");
diff --git a/drivers/i2c/busses/i2c-hix5hd2.c b/drivers/i2c/busses/i2c-hix5hd2.c
index 9490d0f..8fe78d0 100644
--- a/drivers/i2c/busses/i2c-hix5hd2.c
+++ b/drivers/i2c/busses/i2c-hix5hd2.c
@@ -528,7 +528,7 @@ static int hix5hd2_i2c_runtime_resume(struct device *dev)
#endif
static const struct dev_pm_ops hix5hd2_i2c_pm_ops = {
- SET_PM_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend,
+ SET_RUNTIME_PM_OPS(hix5hd2_i2c_runtime_suspend,
hix5hd2_i2c_runtime_resume,
NULL)
};
diff --git a/drivers/i2c/busses/i2c-nomadik.c b/drivers/i2c/busses/i2c-nomadik.c
index 9ad038d..9799894 100644
--- a/drivers/i2c/busses/i2c-nomadik.c
+++ b/drivers/i2c/busses/i2c-nomadik.c
@@ -932,7 +932,7 @@ static int nmk_i2c_runtime_resume(struct device *dev)
static const struct dev_pm_ops nmk_i2c_pm = {
SET_LATE_SYSTEM_SLEEP_PM_OPS(nmk_i2c_suspend_late, nmk_i2c_resume_early)
- SET_PM_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend,
+ SET_RUNTIME_PM_OPS(nmk_i2c_runtime_suspend,
nmk_i2c_runtime_resume,
NULL)
};
diff --git a/drivers/i2c/busses/i2c-omap.c b/drivers/i2c/busses/i2c-omap.c
index 277a228..0e650a0 100644
--- a/drivers/i2c/busses/i2c-omap.c
+++ b/drivers/i2c/busses/i2c-omap.c
@@ -1280,7 +1280,6 @@ static int omap_i2c_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM
-#ifdef CONFIG_PM_RUNTIME
static int omap_i2c_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
@@ -1318,7 +1317,6 @@ static int omap_i2c_runtime_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_RUNTIME */
static struct dev_pm_ops omap_i2c_pm_ops = {
SET_RUNTIME_PM_OPS(omap_i2c_runtime_suspend,
diff --git a/drivers/i2c/i2c-core.c b/drivers/i2c/i2c-core.c
index f43b4e1..229a89e 100644
--- a/drivers/i2c/i2c-core.c
+++ b/drivers/i2c/i2c-core.c
@@ -49,6 +49,7 @@
#include <linux/acpi.h>
#include <linux/jump_label.h>
#include <asm/uaccess.h>
+#include <linux/err.h>
#include "i2c-core.h"
@@ -403,6 +404,7 @@ static int acpi_i2c_install_space_handler(struct i2c_adapter *adapter)
return -ENOMEM;
}
+ acpi_walk_dep_device_list(handle);
return 0;
}
@@ -1368,63 +1370,69 @@ static void i2c_scan_static_board_info(struct i2c_adapter *adapter)
/* OF support code */
#if IS_ENABLED(CONFIG_OF)
-static void of_i2c_register_devices(struct i2c_adapter *adap)
+static struct i2c_client *of_i2c_register_device(struct i2c_adapter *adap,
+ struct device_node *node)
{
- void *result;
- struct device_node *node;
+ struct i2c_client *result;
+ struct i2c_board_info info = {};
+ struct dev_archdata dev_ad = {};
+ const __be32 *addr;
+ int len;
- /* Only register child devices if the adapter has a node pointer set */
- if (!adap->dev.of_node)
- return;
+ dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
- dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
+ if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
+ dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
+ node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
- for_each_available_child_of_node(adap->dev.of_node, node) {
- struct i2c_board_info info = {};
- struct dev_archdata dev_ad = {};
- const __be32 *addr;
- int len;
+ addr = of_get_property(node, "reg", &len);
+ if (!addr || (len < sizeof(int))) {
+ dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
+ node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
- dev_dbg(&adap->dev, "of_i2c: register %s\n", node->full_name);
+ info.addr = be32_to_cpup(addr);
+ if (info.addr > (1 << 10) - 1) {
+ dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
+ info.addr, node->full_name);
+ return ERR_PTR(-EINVAL);
+ }
- if (of_modalias_node(node, info.type, sizeof(info.type)) < 0) {
- dev_err(&adap->dev, "of_i2c: modalias failure on %s\n",
- node->full_name);
- continue;
- }
+ info.irq = irq_of_parse_and_map(node, 0);
+ info.of_node = of_node_get(node);
+ info.archdata = &dev_ad;
- addr = of_get_property(node, "reg", &len);
- if (!addr || (len < sizeof(int))) {
- dev_err(&adap->dev, "of_i2c: invalid reg on %s\n",
- node->full_name);
- continue;
- }
+ if (of_get_property(node, "wakeup-source", NULL))
+ info.flags |= I2C_CLIENT_WAKE;
- info.addr = be32_to_cpup(addr);
- if (info.addr > (1 << 10) - 1) {
- dev_err(&adap->dev, "of_i2c: invalid addr=%x on %s\n",
- info.addr, node->full_name);
- continue;
- }
+ request_module("%s%s", I2C_MODULE_PREFIX, info.type);
+
+ result = i2c_new_device(adap, &info);
+ if (result == NULL) {
+ dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
+ node->full_name);
+ of_node_put(node);
+ irq_dispose_mapping(info.irq);
+ return ERR_PTR(-EINVAL);
+ }
+ return result;
+}
- info.irq = irq_of_parse_and_map(node, 0);
- info.of_node = of_node_get(node);
- info.archdata = &dev_ad;
+static void of_i2c_register_devices(struct i2c_adapter *adap)
+{
+ struct device_node *node;
- if (of_get_property(node, "wakeup-source", NULL))
- info.flags |= I2C_CLIENT_WAKE;
+ /* Only register child devices if the adapter has a node pointer set */
+ if (!adap->dev.of_node)
+ return;
- request_module("%s%s", I2C_MODULE_PREFIX, info.type);
+ dev_dbg(&adap->dev, "of_i2c: walking child nodes\n");
- result = i2c_new_device(adap, &info);
- if (result == NULL) {
- dev_err(&adap->dev, "of_i2c: Failure registering %s\n",
- node->full_name);
- of_node_put(node);
- irq_dispose_mapping(info.irq);
- continue;
- }
- }
+ for_each_available_child_of_node(adap->dev.of_node, node)
+ of_i2c_register_device(adap, node);
}
static int of_dev_node_match(struct device *dev, void *data)
@@ -1944,6 +1952,52 @@ void i2c_clients_command(struct i2c_adapter *adap, unsigned int cmd, void *arg)
}
EXPORT_SYMBOL(i2c_clients_command);
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+static int of_i2c_notify(struct notifier_block *nb, unsigned long action,
+ void *arg)
+{
+ struct of_reconfig_data *rd = arg;
+ struct i2c_adapter *adap;
+ struct i2c_client *client;
+
+ switch (of_reconfig_get_state_change(action, rd)) {
+ case OF_RECONFIG_CHANGE_ADD:
+ adap = of_find_i2c_adapter_by_node(rd->dn->parent);
+ if (adap == NULL)
+ return NOTIFY_OK; /* not for us */
+
+ client = of_i2c_register_device(adap, rd->dn);
+ put_device(&adap->dev);
+
+ if (IS_ERR(client)) {
+ pr_err("%s: failed to create for '%s'\n",
+ __func__, rd->dn->full_name);
+ return notifier_from_errno(PTR_ERR(client));
+ }
+ break;
+ case OF_RECONFIG_CHANGE_REMOVE:
+ /* find our device by node */
+ client = of_find_i2c_device_by_node(rd->dn);
+ if (client == NULL)
+ return NOTIFY_OK; /* no? not meant for us */
+
+ /* unregister takes one ref away */
+ i2c_unregister_device(client);
+
+ /* and put the reference of the find */
+ put_device(&client->dev);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+static struct notifier_block i2c_of_notifier = {
+ .notifier_call = of_i2c_notify,
+};
+#else
+extern struct notifier_block i2c_of_notifier;
+#endif /* CONFIG_OF_DYNAMIC */
+
static int __init i2c_init(void)
{
int retval;
@@ -1961,6 +2015,10 @@ static int __init i2c_init(void)
retval = i2c_add_driver(&dummy_driver);
if (retval)
goto class_err;
+
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_register(&i2c_of_notifier));
+
return 0;
class_err:
@@ -1974,6 +2032,8 @@ bus_err:
static void __exit i2c_exit(void)
{
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_unregister(&i2c_of_notifier));
i2c_del_driver(&dummy_driver);
#ifdef CONFIG_I2C_COMPAT
class_compat_unregister(i2c_adapter_compat_class);
diff --git a/drivers/idle/intel_idle.c b/drivers/idle/intel_idle.c
index 9b7ee7e..9cceacb 100644
--- a/drivers/idle/intel_idle.c
+++ b/drivers/idle/intel_idle.c
@@ -128,28 +128,28 @@ static struct cpuidle_state nehalem_cstates[] = {
{
.name = "C1-NHM",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 3,
.target_residency = 6,
.enter = &intel_idle },
{
.name = "C1E-NHM",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{
.name = "C3-NHM",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 20,
.target_residency = 80,
.enter = &intel_idle },
{
.name = "C6-NHM",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 200,
.target_residency = 800,
.enter = &intel_idle },
@@ -161,35 +161,35 @@ static struct cpuidle_state snb_cstates[] = {
{
.name = "C1-SNB",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
.enter = &intel_idle },
{
.name = "C1E-SNB",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{
.name = "C3-SNB",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 211,
.enter = &intel_idle },
{
.name = "C6-SNB",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 104,
.target_residency = 345,
.enter = &intel_idle },
{
.name = "C7-SNB",
.desc = "MWAIT 0x30",
- .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 109,
.target_residency = 345,
.enter = &intel_idle },
@@ -201,42 +201,42 @@ static struct cpuidle_state byt_cstates[] = {
{
.name = "C1-BYT",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
.enter = &intel_idle },
{
.name = "C1E-BYT",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 15,
.target_residency = 30,
.enter = &intel_idle },
{
.name = "C6N-BYT",
.desc = "MWAIT 0x58",
- .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x58) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 40,
.target_residency = 275,
.enter = &intel_idle },
{
.name = "C6S-BYT",
.desc = "MWAIT 0x52",
- .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
.target_residency = 560,
.enter = &intel_idle },
{
.name = "C7-BYT",
.desc = "MWAIT 0x60",
- .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 1200,
.target_residency = 1500,
.enter = &intel_idle },
{
.name = "C7S-BYT",
.desc = "MWAIT 0x64",
- .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x64) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 10000,
.target_residency = 20000,
.enter = &intel_idle },
@@ -248,35 +248,35 @@ static struct cpuidle_state ivb_cstates[] = {
{
.name = "C1-IVB",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
.enter = &intel_idle },
{
.name = "C1E-IVB",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{
.name = "C3-IVB",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 156,
.enter = &intel_idle },
{
.name = "C6-IVB",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 80,
.target_residency = 300,
.enter = &intel_idle },
{
.name = "C7-IVB",
.desc = "MWAIT 0x30",
- .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 87,
.target_residency = 300,
.enter = &intel_idle },
@@ -288,28 +288,28 @@ static struct cpuidle_state ivt_cstates[] = {
{
.name = "C1-IVT",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
.enter = &intel_idle },
{
.name = "C1E-IVT",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 80,
.enter = &intel_idle },
{
.name = "C3-IVT",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 156,
.enter = &intel_idle },
{
.name = "C6-IVT",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 82,
.target_residency = 300,
.enter = &intel_idle },
@@ -321,28 +321,28 @@ static struct cpuidle_state ivt_cstates_4s[] = {
{
.name = "C1-IVT-4S",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
.enter = &intel_idle },
{
.name = "C1E-IVT-4S",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 250,
.enter = &intel_idle },
{
.name = "C3-IVT-4S",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 300,
.enter = &intel_idle },
{
.name = "C6-IVT-4S",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 84,
.target_residency = 400,
.enter = &intel_idle },
@@ -354,28 +354,28 @@ static struct cpuidle_state ivt_cstates_8s[] = {
{
.name = "C1-IVT-8S",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 1,
.target_residency = 1,
.enter = &intel_idle },
{
.name = "C1E-IVT-8S",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 500,
.enter = &intel_idle },
{
.name = "C3-IVT-8S",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 59,
.target_residency = 600,
.enter = &intel_idle },
{
.name = "C6-IVT-8S",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 88,
.target_residency = 700,
.enter = &intel_idle },
@@ -387,56 +387,56 @@ static struct cpuidle_state hsw_cstates[] = {
{
.name = "C1-HSW",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
.enter = &intel_idle },
{
.name = "C1E-HSW",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{
.name = "C3-HSW",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 33,
.target_residency = 100,
.enter = &intel_idle },
{
.name = "C6-HSW",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 133,
.target_residency = 400,
.enter = &intel_idle },
{
.name = "C7s-HSW",
.desc = "MWAIT 0x32",
- .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 166,
.target_residency = 500,
.enter = &intel_idle },
{
.name = "C8-HSW",
.desc = "MWAIT 0x40",
- .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 300,
.target_residency = 900,
.enter = &intel_idle },
{
.name = "C9-HSW",
.desc = "MWAIT 0x50",
- .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 600,
.target_residency = 1800,
.enter = &intel_idle },
{
.name = "C10-HSW",
.desc = "MWAIT 0x60",
- .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 2600,
.target_residency = 7700,
.enter = &intel_idle },
@@ -447,56 +447,56 @@ static struct cpuidle_state bdw_cstates[] = {
{
.name = "C1-BDW",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
.enter = &intel_idle },
{
.name = "C1E-BDW",
.desc = "MWAIT 0x01",
- .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x01),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{
.name = "C3-BDW",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 40,
.target_residency = 100,
.enter = &intel_idle },
{
.name = "C6-BDW",
.desc = "MWAIT 0x20",
- .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 133,
.target_residency = 400,
.enter = &intel_idle },
{
.name = "C7s-BDW",
.desc = "MWAIT 0x32",
- .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x32) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 166,
.target_residency = 500,
.enter = &intel_idle },
{
.name = "C8-BDW",
.desc = "MWAIT 0x40",
- .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x40) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 300,
.target_residency = 900,
.enter = &intel_idle },
{
.name = "C9-BDW",
.desc = "MWAIT 0x50",
- .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x50) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 600,
.target_residency = 1800,
.enter = &intel_idle },
{
.name = "C10-BDW",
.desc = "MWAIT 0x60",
- .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x60) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 2600,
.target_residency = 7700,
.enter = &intel_idle },
@@ -508,28 +508,28 @@ static struct cpuidle_state atom_cstates[] = {
{
.name = "C1E-ATM",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 10,
.target_residency = 20,
.enter = &intel_idle },
{
.name = "C2-ATM",
.desc = "MWAIT 0x10",
- .flags = MWAIT2flg(0x10) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x10),
.exit_latency = 20,
.target_residency = 80,
.enter = &intel_idle },
{
.name = "C4-ATM",
.desc = "MWAIT 0x30",
- .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x30) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 100,
.target_residency = 400,
.enter = &intel_idle },
{
.name = "C6-ATM",
.desc = "MWAIT 0x52",
- .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x52) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 140,
.target_residency = 560,
.enter = &intel_idle },
@@ -540,14 +540,14 @@ static struct cpuidle_state avn_cstates[] = {
{
.name = "C1-AVN",
.desc = "MWAIT 0x00",
- .flags = MWAIT2flg(0x00) | CPUIDLE_FLAG_TIME_VALID,
+ .flags = MWAIT2flg(0x00),
.exit_latency = 2,
.target_residency = 2,
.enter = &intel_idle },
{
.name = "C6-AVN",
.desc = "MWAIT 0x51",
- .flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TLB_FLUSHED,
+ .flags = MWAIT2flg(0x51) | CPUIDLE_FLAG_TLB_FLUSHED,
.exit_latency = 15,
.target_residency = 45,
.enter = &intel_idle },
diff --git a/drivers/iio/accel/bmc150-accel.c b/drivers/iio/accel/bmc150-accel.c
index 513bd6d..066d0c0 100644
--- a/drivers/iio/accel/bmc150-accel.c
+++ b/drivers/iio/accel/bmc150-accel.c
@@ -513,7 +513,7 @@ static int bmc150_accel_get_bw(struct bmc150_accel_data *data, int *val,
return -EINVAL;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int bmc150_accel_get_startup_times(struct bmc150_accel_data *data)
{
int i;
@@ -1371,7 +1371,7 @@ static int bmc150_accel_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int bmc150_accel_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
diff --git a/drivers/iio/accel/kxcjk-1013.c b/drivers/iio/accel/kxcjk-1013.c
index 320aa72..da2fe93 100644
--- a/drivers/iio/accel/kxcjk-1013.c
+++ b/drivers/iio/accel/kxcjk-1013.c
@@ -360,7 +360,7 @@ static int kxcjk1013_chip_init(struct kxcjk1013_data *data)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int kxcjk1013_get_startup_times(struct kxcjk1013_data *data)
{
int i;
@@ -1359,7 +1359,7 @@ static int kxcjk1013_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int kxcjk1013_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
diff --git a/drivers/iio/adc/Kconfig b/drivers/iio/adc/Kconfig
index 88bdc8f..bc4e787 100644
--- a/drivers/iio/adc/Kconfig
+++ b/drivers/iio/adc/Kconfig
@@ -127,6 +127,14 @@ config AT91_ADC
help
Say yes here to build support for Atmel AT91 ADC.
+config AXP288_ADC
+ tristate "X-Powers AXP288 ADC driver"
+ depends on MFD_AXP20X
+ help
+ Say yes here to have support for X-Powers power management IC (PMIC) ADC
+ device. Depending on platform configuration, this general purpose ADC can
+ be used for sampling sensors such as thermal resistors.
+
config EXYNOS_ADC
tristate "Exynos ADC driver support"
depends on ARCH_EXYNOS || ARCH_S3C24XX || ARCH_S3C64XX || (OF && COMPILE_TEST)
diff --git a/drivers/iio/adc/Makefile b/drivers/iio/adc/Makefile
index cb88a6a..f30093f 100644
--- a/drivers/iio/adc/Makefile
+++ b/drivers/iio/adc/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_AD7793) += ad7793.o
obj-$(CONFIG_AD7887) += ad7887.o
obj-$(CONFIG_AD799X) += ad799x.o
obj-$(CONFIG_AT91_ADC) += at91_adc.o
+obj-$(CONFIG_AXP288_ADC) += axp288_adc.o
obj-$(CONFIG_EXYNOS_ADC) += exynos_adc.o
obj-$(CONFIG_LP8788_ADC) += lp8788_adc.o
obj-$(CONFIG_MAX1027) += max1027.o
diff --git a/drivers/iio/adc/axp288_adc.c b/drivers/iio/adc/axp288_adc.c
new file mode 100644
index 0000000..08bcfb0
--- /dev/null
+++ b/drivers/iio/adc/axp288_adc.c
@@ -0,0 +1,261 @@
+/*
+ * axp288_adc.c - X-Powers AXP288 PMIC ADC Driver
+ *
+ * Copyright (C) 2014 Intel Corporation
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/device.h>
+#include <linux/regmap.h>
+#include <linux/mfd/axp20x.h>
+#include <linux/platform_device.h>
+
+#include <linux/iio/iio.h>
+#include <linux/iio/machine.h>
+#include <linux/iio/driver.h>
+
+#define AXP288_ADC_EN_MASK 0xF1
+#define AXP288_ADC_TS_PIN_GPADC 0xF2
+#define AXP288_ADC_TS_PIN_ON 0xF3
+
+enum axp288_adc_id {
+ AXP288_ADC_TS,
+ AXP288_ADC_PMIC,
+ AXP288_ADC_GP,
+ AXP288_ADC_BATT_CHRG_I,
+ AXP288_ADC_BATT_DISCHRG_I,
+ AXP288_ADC_BATT_V,
+ AXP288_ADC_NR_CHAN,
+};
+
+struct axp288_adc_info {
+ int irq;
+ struct regmap *regmap;
+};
+
+static const struct iio_chan_spec const axp288_adc_channels[] = {
+ {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = 0,
+ .address = AXP288_TS_ADC_H,
+ .datasheet_name = "TS_PIN",
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = 1,
+ .address = AXP288_PMIC_ADC_H,
+ .datasheet_name = "PMIC_TEMP",
+ }, {
+ .indexed = 1,
+ .type = IIO_TEMP,
+ .channel = 2,
+ .address = AXP288_GP_ADC_H,
+ .datasheet_name = "GPADC",
+ }, {
+ .indexed = 1,
+ .type = IIO_CURRENT,
+ .channel = 3,
+ .address = AXP20X_BATT_CHRG_I_H,
+ .datasheet_name = "BATT_CHG_I",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .indexed = 1,
+ .type = IIO_CURRENT,
+ .channel = 4,
+ .address = AXP20X_BATT_DISCHRG_I_H,
+ .datasheet_name = "BATT_DISCHRG_I",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ }, {
+ .indexed = 1,
+ .type = IIO_VOLTAGE,
+ .channel = 5,
+ .address = AXP20X_BATT_V_H,
+ .datasheet_name = "BATT_V",
+ .info_mask_separate = BIT(IIO_CHAN_INFO_PROCESSED),
+ },
+};
+
+#define AXP288_ADC_MAP(_adc_channel_label, _consumer_dev_name, \
+ _consumer_channel) \
+ { \
+ .adc_channel_label = _adc_channel_label, \
+ .consumer_dev_name = _consumer_dev_name, \
+ .consumer_channel = _consumer_channel, \
+ }
+
+/* for consumer drivers */
+static struct iio_map axp288_adc_default_maps[] = {
+ AXP288_ADC_MAP("TS_PIN", "axp288-batt", "axp288-batt-temp"),
+ AXP288_ADC_MAP("PMIC_TEMP", "axp288-pmic", "axp288-pmic-temp"),
+ AXP288_ADC_MAP("GPADC", "axp288-gpadc", "axp288-system-temp"),
+ AXP288_ADC_MAP("BATT_CHG_I", "axp288-chrg", "axp288-chrg-curr"),
+ AXP288_ADC_MAP("BATT_DISCHRG_I", "axp288-chrg", "axp288-chrg-d-curr"),
+ AXP288_ADC_MAP("BATT_V", "axp288-batt", "axp288-batt-volt"),
+ {},
+};
+
+static int axp288_adc_read_channel(int *val, unsigned long address,
+ struct regmap *regmap)
+{
+ u8 buf[2];
+
+ if (regmap_bulk_read(regmap, address, buf, 2))
+ return -EIO;
+ *val = (buf[0] << 4) + ((buf[1] >> 4) & 0x0F);
+
+ return IIO_VAL_INT;
+}
+
+static int axp288_adc_set_ts(struct regmap *regmap, unsigned int mode,
+ unsigned long address)
+{
+ /* channels other than GPADC do not need to switch TS pin */
+ if (address != AXP288_GP_ADC_H)
+ return 0;
+
+ return regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, mode);
+}
+
+static int axp288_adc_read_raw(struct iio_dev *indio_dev,
+ struct iio_chan_spec const *chan,
+ int *val, int *val2, long mask)
+{
+ int ret;
+ struct axp288_adc_info *info = iio_priv(indio_dev);
+
+ mutex_lock(&indio_dev->mlock);
+ switch (mask) {
+ case IIO_CHAN_INFO_RAW:
+ if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_GPADC,
+ chan->address)) {
+ dev_err(&indio_dev->dev, "GPADC mode\n");
+ ret = -EINVAL;
+ break;
+ }
+ ret = axp288_adc_read_channel(val, chan->address, info->regmap);
+ if (axp288_adc_set_ts(info->regmap, AXP288_ADC_TS_PIN_ON,
+ chan->address))
+ dev_err(&indio_dev->dev, "TS pin restore\n");
+ break;
+ case IIO_CHAN_INFO_PROCESSED:
+ ret = axp288_adc_read_channel(val, chan->address, info->regmap);
+ break;
+ default:
+ ret = -EINVAL;
+ }
+ mutex_unlock(&indio_dev->mlock);
+
+ return ret;
+}
+
+static int axp288_adc_set_state(struct regmap *regmap)
+{
+ /* ADC should be always enabled for internal FG to function */
+ if (regmap_write(regmap, AXP288_ADC_TS_PIN_CTRL, AXP288_ADC_TS_PIN_ON))
+ return -EIO;
+
+ return regmap_write(regmap, AXP20X_ADC_EN1, AXP288_ADC_EN_MASK);
+}
+
+static const struct iio_info axp288_adc_iio_info = {
+ .read_raw = &axp288_adc_read_raw,
+ .driver_module = THIS_MODULE,
+};
+
+static int axp288_adc_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct axp288_adc_info *info;
+ struct iio_dev *indio_dev;
+ struct axp20x_dev *axp20x = dev_get_drvdata(pdev->dev.parent);
+
+ indio_dev = devm_iio_device_alloc(&pdev->dev, sizeof(*info));
+ if (!indio_dev)
+ return -ENOMEM;
+
+ info = iio_priv(indio_dev);
+ info->irq = platform_get_irq(pdev, 0);
+ if (info->irq < 0) {
+ dev_err(&pdev->dev, "no irq resource?\n");
+ return info->irq;
+ }
+ platform_set_drvdata(pdev, indio_dev);
+ info->regmap = axp20x->regmap;
+ /*
+ * Set ADC to enabled state at all time, including system suspend.
+ * otherwise internal fuel gauge functionality may be affected.
+ */
+ ret = axp288_adc_set_state(axp20x->regmap);
+ if (ret) {
+ dev_err(&pdev->dev, "unable to enable ADC device\n");
+ return ret;
+ }
+
+ indio_dev->dev.parent = &pdev->dev;
+ indio_dev->name = pdev->name;
+ indio_dev->channels = axp288_adc_channels;
+ indio_dev->num_channels = ARRAY_SIZE(axp288_adc_channels);
+ indio_dev->info = &axp288_adc_iio_info;
+ indio_dev->modes = INDIO_DIRECT_MODE;
+ ret = iio_map_array_register(indio_dev, axp288_adc_default_maps);
+ if (ret < 0)
+ return ret;
+
+ ret = iio_device_register(indio_dev);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "unable to register iio device\n");
+ goto err_array_unregister;
+ }
+ return 0;
+
+err_array_unregister:
+ iio_map_array_unregister(indio_dev);
+
+ return ret;
+}
+
+static int axp288_adc_remove(struct platform_device *pdev)
+{
+ struct iio_dev *indio_dev = platform_get_drvdata(pdev);
+
+ iio_device_unregister(indio_dev);
+ iio_map_array_unregister(indio_dev);
+
+ return 0;
+}
+
+static struct platform_device_id axp288_adc_id_table[] = {
+ { .name = "axp288_adc" },
+ {},
+};
+
+static struct platform_driver axp288_adc_driver = {
+ .probe = axp288_adc_probe,
+ .remove = axp288_adc_remove,
+ .id_table = axp288_adc_id_table,
+ .driver = {
+ .name = "axp288_adc",
+ },
+};
+
+MODULE_DEVICE_TABLE(platform, axp288_adc_id_table);
+
+module_platform_driver(axp288_adc_driver);
+
+MODULE_AUTHOR("Jacob Pan <jacob.jun.pan@linux.intel.com>");
+MODULE_DESCRIPTION("X-Powers AXP288 ADC Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/iio/gyro/bmg160.c b/drivers/iio/gyro/bmg160.c
index d2fa526..60451b3 100644
--- a/drivers/iio/gyro/bmg160.c
+++ b/drivers/iio/gyro/bmg160.c
@@ -256,7 +256,7 @@ static int bmg160_chip_init(struct bmg160_data *data)
static int bmg160_set_power_state(struct bmg160_data *data, bool on)
{
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
int ret;
if (on)
@@ -1202,7 +1202,7 @@ static int bmg160_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int bmg160_runtime_suspend(struct device *dev)
{
struct iio_dev *indio_dev = i2c_get_clientdata(to_i2c_client(dev));
diff --git a/drivers/infiniband/ulp/iser/iscsi_iser.c b/drivers/infiniband/ulp/iser/iscsi_iser.c
index f42ab14..20ca6a6 100644
--- a/drivers/infiniband/ulp/iser/iscsi_iser.c
+++ b/drivers/infiniband/ulp/iser/iscsi_iser.c
@@ -911,7 +911,7 @@ static struct scsi_host_template iscsi_iser_sht = {
.module = THIS_MODULE,
.name = "iSCSI Initiator over iSER",
.queuecommand = iscsi_queuecommand,
- .change_queue_depth = iscsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.sg_tablesize = ISCSI_ISER_SG_TABLESIZE,
.max_sectors = 1024,
.cmd_per_lun = ISER_DEF_CMD_PER_LUN,
@@ -922,6 +922,7 @@ static struct scsi_host_template iscsi_iser_sht = {
.use_clustering = DISABLE_CLUSTERING,
.proc_name = "iscsi_iser",
.this_id = -1,
+ .track_queue_depth = 1,
};
static struct iscsi_transport iscsi_iser_transport = {
diff --git a/drivers/infiniband/ulp/srp/ib_srp.c b/drivers/infiniband/ulp/srp/ib_srp.c
index 62d2a18..5461924 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.c
+++ b/drivers/infiniband/ulp/srp/ib_srp.c
@@ -123,10 +123,15 @@ MODULE_PARM_DESC(dev_loss_tmo,
" if fast_io_fail_tmo has not been set. \"off\" means that"
" this functionality is disabled.");
+static unsigned ch_count;
+module_param(ch_count, uint, 0444);
+MODULE_PARM_DESC(ch_count,
+ "Number of RDMA channels to use for communication with an SRP target. Using more than one channel improves performance if the HCA supports multiple completion vectors. The default value is the minimum of four times the number of online CPU sockets and the number of completion vectors supported by the HCA.");
+
static void srp_add_one(struct ib_device *device);
static void srp_remove_one(struct ib_device *device);
-static void srp_recv_completion(struct ib_cq *cq, void *target_ptr);
-static void srp_send_completion(struct ib_cq *cq, void *target_ptr);
+static void srp_recv_completion(struct ib_cq *cq, void *ch_ptr);
+static void srp_send_completion(struct ib_cq *cq, void *ch_ptr);
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event);
static struct scsi_transport_template *ib_srp_transport_template;
@@ -262,7 +267,7 @@ static int srp_init_qp(struct srp_target_port *target,
ret = ib_find_pkey(target->srp_host->srp_dev->dev,
target->srp_host->port,
- be16_to_cpu(target->path.pkey),
+ be16_to_cpu(target->pkey),
&attr->pkey_index);
if (ret)
goto out;
@@ -283,18 +288,23 @@ out:
return ret;
}
-static int srp_new_cm_id(struct srp_target_port *target)
+static int srp_new_cm_id(struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
struct ib_cm_id *new_cm_id;
new_cm_id = ib_create_cm_id(target->srp_host->srp_dev->dev,
- srp_cm_handler, target);
+ srp_cm_handler, ch);
if (IS_ERR(new_cm_id))
return PTR_ERR(new_cm_id);
- if (target->cm_id)
- ib_destroy_cm_id(target->cm_id);
- target->cm_id = new_cm_id;
+ if (ch->cm_id)
+ ib_destroy_cm_id(ch->cm_id);
+ ch->cm_id = new_cm_id;
+ ch->path.sgid = target->sgid;
+ ch->path.dgid = target->orig_dgid;
+ ch->path.pkey = target->pkey;
+ ch->path.service_id = target->service_id;
return 0;
}
@@ -443,8 +453,44 @@ static struct srp_fr_pool *srp_alloc_fr_pool(struct srp_target_port *target)
dev->max_pages_per_mr);
}
-static int srp_create_target_ib(struct srp_target_port *target)
+/**
+ * srp_destroy_qp() - destroy an RDMA queue pair
+ * @ch: SRP RDMA channel.
+ *
+ * Change a queue pair into the error state and wait until all receive
+ * completions have been processed before destroying it. This avoids that
+ * the receive completion handler can access the queue pair while it is
+ * being destroyed.
+ */
+static void srp_destroy_qp(struct srp_rdma_ch *ch)
+{
+ struct srp_target_port *target = ch->target;
+ static struct ib_qp_attr attr = { .qp_state = IB_QPS_ERR };
+ static struct ib_recv_wr wr = { .wr_id = SRP_LAST_WR_ID };
+ struct ib_recv_wr *bad_wr;
+ int ret;
+
+ /* Destroying a QP and reusing ch->done is only safe if not connected */
+ WARN_ON_ONCE(target->connected);
+
+ ret = ib_modify_qp(ch->qp, &attr, IB_QP_STATE);
+ WARN_ONCE(ret, "ib_cm_init_qp_attr() returned %d\n", ret);
+ if (ret)
+ goto out;
+
+ init_completion(&ch->done);
+ ret = ib_post_recv(ch->qp, &wr, &bad_wr);
+ WARN_ONCE(ret, "ib_post_recv() returned %d\n", ret);
+ if (ret == 0)
+ wait_for_completion(&ch->done);
+
+out:
+ ib_destroy_qp(ch->qp);
+}
+
+static int srp_create_ch_ib(struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_qp_init_attr *init_attr;
struct ib_cq *recv_cq, *send_cq;
@@ -458,15 +504,16 @@ static int srp_create_target_ib(struct srp_target_port *target)
if (!init_attr)
return -ENOMEM;
- recv_cq = ib_create_cq(dev->dev, srp_recv_completion, NULL, target,
- target->queue_size, target->comp_vector);
+ /* + 1 for SRP_LAST_WR_ID */
+ recv_cq = ib_create_cq(dev->dev, srp_recv_completion, NULL, ch,
+ target->queue_size + 1, ch->comp_vector);
if (IS_ERR(recv_cq)) {
ret = PTR_ERR(recv_cq);
goto err;
}
- send_cq = ib_create_cq(dev->dev, srp_send_completion, NULL, target,
- m * target->queue_size, target->comp_vector);
+ send_cq = ib_create_cq(dev->dev, srp_send_completion, NULL, ch,
+ m * target->queue_size, ch->comp_vector);
if (IS_ERR(send_cq)) {
ret = PTR_ERR(send_cq);
goto err_recv_cq;
@@ -476,7 +523,7 @@ static int srp_create_target_ib(struct srp_target_port *target)
init_attr->event_handler = srp_qp_event;
init_attr->cap.max_send_wr = m * target->queue_size;
- init_attr->cap.max_recv_wr = target->queue_size;
+ init_attr->cap.max_recv_wr = target->queue_size + 1;
init_attr->cap.max_recv_sge = 1;
init_attr->cap.max_send_sge = 1;
init_attr->sq_sig_type = IB_SIGNAL_REQ_WR;
@@ -502,9 +549,9 @@ static int srp_create_target_ib(struct srp_target_port *target)
"FR pool allocation failed (%d)\n", ret);
goto err_qp;
}
- if (target->fr_pool)
- srp_destroy_fr_pool(target->fr_pool);
- target->fr_pool = fr_pool;
+ if (ch->fr_pool)
+ srp_destroy_fr_pool(ch->fr_pool);
+ ch->fr_pool = fr_pool;
} else if (!dev->use_fast_reg && dev->has_fmr) {
fmr_pool = srp_alloc_fmr_pool(target);
if (IS_ERR(fmr_pool)) {
@@ -513,21 +560,21 @@ static int srp_create_target_ib(struct srp_target_port *target)
"FMR pool allocation failed (%d)\n", ret);
goto err_qp;
}
- if (target->fmr_pool)
- ib_destroy_fmr_pool(target->fmr_pool);
- target->fmr_pool = fmr_pool;
+ if (ch->fmr_pool)
+ ib_destroy_fmr_pool(ch->fmr_pool);
+ ch->fmr_pool = fmr_pool;
}
- if (target->qp)
- ib_destroy_qp(target->qp);
- if (target->recv_cq)
- ib_destroy_cq(target->recv_cq);
- if (target->send_cq)
- ib_destroy_cq(target->send_cq);
+ if (ch->qp)
+ srp_destroy_qp(ch);
+ if (ch->recv_cq)
+ ib_destroy_cq(ch->recv_cq);
+ if (ch->send_cq)
+ ib_destroy_cq(ch->send_cq);
- target->qp = qp;
- target->recv_cq = recv_cq;
- target->send_cq = send_cq;
+ ch->qp = qp;
+ ch->recv_cq = recv_cq;
+ ch->send_cq = send_cq;
kfree(init_attr);
return 0;
@@ -548,93 +595,117 @@ err:
/*
* Note: this function may be called without srp_alloc_iu_bufs() having been
- * invoked. Hence the target->[rt]x_ring checks.
+ * invoked. Hence the ch->[rt]x_ring checks.
*/
-static void srp_free_target_ib(struct srp_target_port *target)
+static void srp_free_ch_ib(struct srp_target_port *target,
+ struct srp_rdma_ch *ch)
{
struct srp_device *dev = target->srp_host->srp_dev;
int i;
+ if (!ch->target)
+ return;
+
+ if (ch->cm_id) {
+ ib_destroy_cm_id(ch->cm_id);
+ ch->cm_id = NULL;
+ }
+
+ /* If srp_new_cm_id() succeeded but srp_create_ch_ib() not, return. */
+ if (!ch->qp)
+ return;
+
if (dev->use_fast_reg) {
- if (target->fr_pool)
- srp_destroy_fr_pool(target->fr_pool);
+ if (ch->fr_pool)
+ srp_destroy_fr_pool(ch->fr_pool);
} else {
- if (target->fmr_pool)
- ib_destroy_fmr_pool(target->fmr_pool);
+ if (ch->fmr_pool)
+ ib_destroy_fmr_pool(ch->fmr_pool);
}
- ib_destroy_qp(target->qp);
- ib_destroy_cq(target->send_cq);
- ib_destroy_cq(target->recv_cq);
+ srp_destroy_qp(ch);
+ ib_destroy_cq(ch->send_cq);
+ ib_destroy_cq(ch->recv_cq);
+
+ /*
+ * Avoid that the SCSI error handler tries to use this channel after
+ * it has been freed. The SCSI error handler can namely continue
+ * trying to perform recovery actions after scsi_remove_host()
+ * returned.
+ */
+ ch->target = NULL;
- target->qp = NULL;
- target->send_cq = target->recv_cq = NULL;
+ ch->qp = NULL;
+ ch->send_cq = ch->recv_cq = NULL;
- if (target->rx_ring) {
+ if (ch->rx_ring) {
for (i = 0; i < target->queue_size; ++i)
- srp_free_iu(target->srp_host, target->rx_ring[i]);
- kfree(target->rx_ring);
- target->rx_ring = NULL;
+ srp_free_iu(target->srp_host, ch->rx_ring[i]);
+ kfree(ch->rx_ring);
+ ch->rx_ring = NULL;
}
- if (target->tx_ring) {
+ if (ch->tx_ring) {
for (i = 0; i < target->queue_size; ++i)
- srp_free_iu(target->srp_host, target->tx_ring[i]);
- kfree(target->tx_ring);
- target->tx_ring = NULL;
+ srp_free_iu(target->srp_host, ch->tx_ring[i]);
+ kfree(ch->tx_ring);
+ ch->tx_ring = NULL;
}
}
static void srp_path_rec_completion(int status,
struct ib_sa_path_rec *pathrec,
- void *target_ptr)
+ void *ch_ptr)
{
- struct srp_target_port *target = target_ptr;
+ struct srp_rdma_ch *ch = ch_ptr;
+ struct srp_target_port *target = ch->target;
- target->status = status;
+ ch->status = status;
if (status)
shost_printk(KERN_ERR, target->scsi_host,
PFX "Got failed path rec status %d\n", status);
else
- target->path = *pathrec;
- complete(&target->done);
+ ch->path = *pathrec;
+ complete(&ch->done);
}
-static int srp_lookup_path(struct srp_target_port *target)
+static int srp_lookup_path(struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
int ret;
- target->path.numb_path = 1;
-
- init_completion(&target->done);
-
- target->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
- target->srp_host->srp_dev->dev,
- target->srp_host->port,
- &target->path,
- IB_SA_PATH_REC_SERVICE_ID |
- IB_SA_PATH_REC_DGID |
- IB_SA_PATH_REC_SGID |
- IB_SA_PATH_REC_NUMB_PATH |
- IB_SA_PATH_REC_PKEY,
- SRP_PATH_REC_TIMEOUT_MS,
- GFP_KERNEL,
- srp_path_rec_completion,
- target, &target->path_query);
- if (target->path_query_id < 0)
- return target->path_query_id;
-
- ret = wait_for_completion_interruptible(&target->done);
+ ch->path.numb_path = 1;
+
+ init_completion(&ch->done);
+
+ ch->path_query_id = ib_sa_path_rec_get(&srp_sa_client,
+ target->srp_host->srp_dev->dev,
+ target->srp_host->port,
+ &ch->path,
+ IB_SA_PATH_REC_SERVICE_ID |
+ IB_SA_PATH_REC_DGID |
+ IB_SA_PATH_REC_SGID |
+ IB_SA_PATH_REC_NUMB_PATH |
+ IB_SA_PATH_REC_PKEY,
+ SRP_PATH_REC_TIMEOUT_MS,
+ GFP_KERNEL,
+ srp_path_rec_completion,
+ ch, &ch->path_query);
+ if (ch->path_query_id < 0)
+ return ch->path_query_id;
+
+ ret = wait_for_completion_interruptible(&ch->done);
if (ret < 0)
return ret;
- if (target->status < 0)
+ if (ch->status < 0)
shost_printk(KERN_WARNING, target->scsi_host,
PFX "Path record query failed\n");
- return target->status;
+ return ch->status;
}
-static int srp_send_req(struct srp_target_port *target)
+static int srp_send_req(struct srp_rdma_ch *ch, bool multich)
{
+ struct srp_target_port *target = ch->target;
struct {
struct ib_cm_req_param param;
struct srp_login_req priv;
@@ -645,11 +716,11 @@ static int srp_send_req(struct srp_target_port *target)
if (!req)
return -ENOMEM;
- req->param.primary_path = &target->path;
+ req->param.primary_path = &ch->path;
req->param.alternate_path = NULL;
req->param.service_id = target->service_id;
- req->param.qp_num = target->qp->qp_num;
- req->param.qp_type = target->qp->qp_type;
+ req->param.qp_num = ch->qp->qp_num;
+ req->param.qp_type = ch->qp->qp_type;
req->param.private_data = &req->priv;
req->param.private_data_len = sizeof req->priv;
req->param.flow_control = 1;
@@ -673,6 +744,8 @@ static int srp_send_req(struct srp_target_port *target)
req->priv.req_it_iu_len = cpu_to_be32(target->max_iu_len);
req->priv.req_buf_fmt = cpu_to_be16(SRP_BUF_FORMAT_DIRECT |
SRP_BUF_FORMAT_INDIRECT);
+ req->priv.req_flags = (multich ? SRP_MULTICHAN_MULTI :
+ SRP_MULTICHAN_SINGLE);
/*
* In the published SRP specification (draft rev. 16a), the
* port identifier format is 8 bytes of ID extension followed
@@ -684,7 +757,7 @@ static int srp_send_req(struct srp_target_port *target)
*/
if (target->io_class == SRP_REV10_IB_IO_CLASS) {
memcpy(req->priv.initiator_port_id,
- &target->path.sgid.global.interface_id, 8);
+ &target->sgid.global.interface_id, 8);
memcpy(req->priv.initiator_port_id + 8,
&target->initiator_ext, 8);
memcpy(req->priv.target_port_id, &target->ioc_guid, 8);
@@ -693,7 +766,7 @@ static int srp_send_req(struct srp_target_port *target)
memcpy(req->priv.initiator_port_id,
&target->initiator_ext, 8);
memcpy(req->priv.initiator_port_id + 8,
- &target->path.sgid.global.interface_id, 8);
+ &target->sgid.global.interface_id, 8);
memcpy(req->priv.target_port_id, &target->id_ext, 8);
memcpy(req->priv.target_port_id + 8, &target->ioc_guid, 8);
}
@@ -713,7 +786,7 @@ static int srp_send_req(struct srp_target_port *target)
&target->srp_host->srp_dev->dev->node_guid, 8);
}
- status = ib_send_cm_req(target->cm_id, &req->param);
+ status = ib_send_cm_req(ch->cm_id, &req->param);
kfree(req);
@@ -754,28 +827,35 @@ static bool srp_change_conn_state(struct srp_target_port *target,
static void srp_disconnect_target(struct srp_target_port *target)
{
+ struct srp_rdma_ch *ch;
+ int i;
+
if (srp_change_conn_state(target, false)) {
/* XXX should send SRP_I_LOGOUT request */
- if (ib_send_cm_dreq(target->cm_id, NULL, 0)) {
- shost_printk(KERN_DEBUG, target->scsi_host,
- PFX "Sending CM DREQ failed\n");
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ if (ch->cm_id && ib_send_cm_dreq(ch->cm_id, NULL, 0)) {
+ shost_printk(KERN_DEBUG, target->scsi_host,
+ PFX "Sending CM DREQ failed\n");
+ }
}
}
}
-static void srp_free_req_data(struct srp_target_port *target)
+static void srp_free_req_data(struct srp_target_port *target,
+ struct srp_rdma_ch *ch)
{
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_device *ibdev = dev->dev;
struct srp_request *req;
int i;
- if (!target->req_ring)
+ if (!ch->target || !ch->req_ring)
return;
for (i = 0; i < target->req_ring_size; ++i) {
- req = &target->req_ring[i];
+ req = &ch->req_ring[i];
if (dev->use_fast_reg)
kfree(req->fr_list);
else
@@ -789,12 +869,13 @@ static void srp_free_req_data(struct srp_target_port *target)
kfree(req->indirect_desc);
}
- kfree(target->req_ring);
- target->req_ring = NULL;
+ kfree(ch->req_ring);
+ ch->req_ring = NULL;
}
-static int srp_alloc_req_data(struct srp_target_port *target)
+static int srp_alloc_req_data(struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
struct srp_device *srp_dev = target->srp_host->srp_dev;
struct ib_device *ibdev = srp_dev->dev;
struct srp_request *req;
@@ -802,15 +883,13 @@ static int srp_alloc_req_data(struct srp_target_port *target)
dma_addr_t dma_addr;
int i, ret = -ENOMEM;
- INIT_LIST_HEAD(&target->free_reqs);
-
- target->req_ring = kzalloc(target->req_ring_size *
- sizeof(*target->req_ring), GFP_KERNEL);
- if (!target->req_ring)
+ ch->req_ring = kcalloc(target->req_ring_size, sizeof(*ch->req_ring),
+ GFP_KERNEL);
+ if (!ch->req_ring)
goto out;
for (i = 0; i < target->req_ring_size; ++i) {
- req = &target->req_ring[i];
+ req = &ch->req_ring[i];
mr_list = kmalloc(target->cmd_sg_cnt * sizeof(void *),
GFP_KERNEL);
if (!mr_list)
@@ -834,8 +913,6 @@ static int srp_alloc_req_data(struct srp_target_port *target)
goto out;
req->indirect_dma_addr = dma_addr;
- req->index = i;
- list_add_tail(&req->list, &target->free_reqs);
}
ret = 0;
@@ -860,6 +937,9 @@ static void srp_del_scsi_host_attr(struct Scsi_Host *shost)
static void srp_remove_target(struct srp_target_port *target)
{
+ struct srp_rdma_ch *ch;
+ int i;
+
WARN_ON_ONCE(target->state != SRP_TARGET_REMOVED);
srp_del_scsi_host_attr(target->scsi_host);
@@ -868,11 +948,18 @@ static void srp_remove_target(struct srp_target_port *target)
scsi_remove_host(target->scsi_host);
srp_stop_rport_timers(target->rport);
srp_disconnect_target(target);
- ib_destroy_cm_id(target->cm_id);
- srp_free_target_ib(target);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ srp_free_ch_ib(target, ch);
+ }
cancel_work_sync(&target->tl_err_work);
srp_rport_put(target->rport);
- srp_free_req_data(target);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ srp_free_req_data(target, ch);
+ }
+ kfree(target->ch);
+ target->ch = NULL;
spin_lock(&target->srp_host->target_lock);
list_del(&target->list);
@@ -898,25 +985,25 @@ static void srp_rport_delete(struct srp_rport *rport)
srp_queue_remove_work(target);
}
-static int srp_connect_target(struct srp_target_port *target)
+static int srp_connect_ch(struct srp_rdma_ch *ch, bool multich)
{
- int retries = 3;
+ struct srp_target_port *target = ch->target;
int ret;
- WARN_ON_ONCE(target->connected);
+ WARN_ON_ONCE(!multich && target->connected);
target->qp_in_error = false;
- ret = srp_lookup_path(target);
+ ret = srp_lookup_path(ch);
if (ret)
return ret;
while (1) {
- init_completion(&target->done);
- ret = srp_send_req(target);
+ init_completion(&ch->done);
+ ret = srp_send_req(ch, multich);
if (ret)
return ret;
- ret = wait_for_completion_interruptible(&target->done);
+ ret = wait_for_completion_interruptible(&ch->done);
if (ret < 0)
return ret;
@@ -926,13 +1013,13 @@ static int srp_connect_target(struct srp_target_port *target)
* back, or SRP_DLID_REDIRECT if we get a lid/qp
* redirect REJ back.
*/
- switch (target->status) {
+ switch (ch->status) {
case 0:
srp_change_conn_state(target, true);
return 0;
case SRP_PORT_REDIRECT:
- ret = srp_lookup_path(target);
+ ret = srp_lookup_path(ch);
if (ret)
return ret;
break;
@@ -941,27 +1028,18 @@ static int srp_connect_target(struct srp_target_port *target)
break;
case SRP_STALE_CONN:
- /* Our current CM id was stale, and is now in timewait.
- * Try to reconnect with a new one.
- */
- if (!retries-- || srp_new_cm_id(target)) {
- shost_printk(KERN_ERR, target->scsi_host, PFX
- "giving up on stale connection\n");
- target->status = -ECONNRESET;
- return target->status;
- }
-
shost_printk(KERN_ERR, target->scsi_host, PFX
- "retrying stale connection\n");
- break;
+ "giving up on stale connection\n");
+ ch->status = -ECONNRESET;
+ return ch->status;
default:
- return target->status;
+ return ch->status;
}
}
}
-static int srp_inv_rkey(struct srp_target_port *target, u32 rkey)
+static int srp_inv_rkey(struct srp_rdma_ch *ch, u32 rkey)
{
struct ib_send_wr *bad_wr;
struct ib_send_wr wr = {
@@ -973,13 +1051,14 @@ static int srp_inv_rkey(struct srp_target_port *target, u32 rkey)
.ex.invalidate_rkey = rkey,
};
- return ib_post_send(target->qp, &wr, &bad_wr);
+ return ib_post_send(ch->qp, &wr, &bad_wr);
}
static void srp_unmap_data(struct scsi_cmnd *scmnd,
- struct srp_target_port *target,
+ struct srp_rdma_ch *ch,
struct srp_request *req)
{
+ struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_device *ibdev = dev->dev;
int i, res;
@@ -993,7 +1072,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
struct srp_fr_desc **pfr;
for (i = req->nmdesc, pfr = req->fr_list; i > 0; i--, pfr++) {
- res = srp_inv_rkey(target, (*pfr)->mr->rkey);
+ res = srp_inv_rkey(ch, (*pfr)->mr->rkey);
if (res < 0) {
shost_printk(KERN_ERR, target->scsi_host, PFX
"Queueing INV WR for rkey %#x failed (%d)\n",
@@ -1003,7 +1082,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
}
}
if (req->nmdesc)
- srp_fr_pool_put(target->fr_pool, req->fr_list,
+ srp_fr_pool_put(ch->fr_pool, req->fr_list,
req->nmdesc);
} else {
struct ib_pool_fmr **pfmr;
@@ -1018,7 +1097,7 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
/**
* srp_claim_req - Take ownership of the scmnd associated with a request.
- * @target: SRP target port.
+ * @ch: SRP RDMA channel.
* @req: SRP request.
* @sdev: If not NULL, only take ownership for this SCSI device.
* @scmnd: If NULL, take ownership of @req->scmnd. If not NULL, only take
@@ -1027,14 +1106,14 @@ static void srp_unmap_data(struct scsi_cmnd *scmnd,
* Return value:
* Either NULL or a pointer to the SCSI command the caller became owner of.
*/
-static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target,
+static struct scsi_cmnd *srp_claim_req(struct srp_rdma_ch *ch,
struct srp_request *req,
struct scsi_device *sdev,
struct scsi_cmnd *scmnd)
{
unsigned long flags;
- spin_lock_irqsave(&target->lock, flags);
+ spin_lock_irqsave(&ch->lock, flags);
if (req->scmnd &&
(!sdev || req->scmnd->device == sdev) &&
(!scmnd || req->scmnd == scmnd)) {
@@ -1043,40 +1122,37 @@ static struct scsi_cmnd *srp_claim_req(struct srp_target_port *target,
} else {
scmnd = NULL;
}
- spin_unlock_irqrestore(&target->lock, flags);
+ spin_unlock_irqrestore(&ch->lock, flags);
return scmnd;
}
/**
* srp_free_req() - Unmap data and add request to the free request list.
- * @target: SRP target port.
+ * @ch: SRP RDMA channel.
* @req: Request to be freed.
* @scmnd: SCSI command associated with @req.
* @req_lim_delta: Amount to be added to @target->req_lim.
*/
-static void srp_free_req(struct srp_target_port *target,
- struct srp_request *req, struct scsi_cmnd *scmnd,
- s32 req_lim_delta)
+static void srp_free_req(struct srp_rdma_ch *ch, struct srp_request *req,
+ struct scsi_cmnd *scmnd, s32 req_lim_delta)
{
unsigned long flags;
- srp_unmap_data(scmnd, target, req);
+ srp_unmap_data(scmnd, ch, req);
- spin_lock_irqsave(&target->lock, flags);
- target->req_lim += req_lim_delta;
- list_add_tail(&req->list, &target->free_reqs);
- spin_unlock_irqrestore(&target->lock, flags);
+ spin_lock_irqsave(&ch->lock, flags);
+ ch->req_lim += req_lim_delta;
+ spin_unlock_irqrestore(&ch->lock, flags);
}
-static void srp_finish_req(struct srp_target_port *target,
- struct srp_request *req, struct scsi_device *sdev,
- int result)
+static void srp_finish_req(struct srp_rdma_ch *ch, struct srp_request *req,
+ struct scsi_device *sdev, int result)
{
- struct scsi_cmnd *scmnd = srp_claim_req(target, req, sdev, NULL);
+ struct scsi_cmnd *scmnd = srp_claim_req(ch, req, sdev, NULL);
if (scmnd) {
- srp_free_req(target, req, scmnd, 0);
+ srp_free_req(ch, req, scmnd, 0);
scmnd->result = result;
scmnd->scsi_done(scmnd);
}
@@ -1085,9 +1161,10 @@ static void srp_finish_req(struct srp_target_port *target,
static void srp_terminate_io(struct srp_rport *rport)
{
struct srp_target_port *target = rport->lld_data;
+ struct srp_rdma_ch *ch;
struct Scsi_Host *shost = target->scsi_host;
struct scsi_device *sdev;
- int i;
+ int i, j;
/*
* Invoking srp_terminate_io() while srp_queuecommand() is running
@@ -1096,9 +1173,15 @@ static void srp_terminate_io(struct srp_rport *rport)
shost_for_each_device(sdev, shost)
WARN_ON_ONCE(sdev->request_queue->request_fn_active);
- for (i = 0; i < target->req_ring_size; ++i) {
- struct srp_request *req = &target->req_ring[i];
- srp_finish_req(target, req, NULL, DID_TRANSPORT_FAILFAST << 16);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+
+ for (j = 0; j < target->req_ring_size; ++j) {
+ struct srp_request *req = &ch->req_ring[j];
+
+ srp_finish_req(ch, req, NULL,
+ DID_TRANSPORT_FAILFAST << 16);
+ }
}
}
@@ -1114,34 +1197,61 @@ static void srp_terminate_io(struct srp_rport *rport)
static int srp_rport_reconnect(struct srp_rport *rport)
{
struct srp_target_port *target = rport->lld_data;
- int i, ret;
+ struct srp_rdma_ch *ch;
+ int i, j, ret = 0;
+ bool multich = false;
srp_disconnect_target(target);
+
+ if (target->state == SRP_TARGET_SCANNING)
+ return -ENODEV;
+
/*
* Now get a new local CM ID so that we avoid confusing the target in
* case things are really fouled up. Doing so also ensures that all CM
* callbacks will have finished before a new QP is allocated.
*/
- ret = srp_new_cm_id(target);
-
- for (i = 0; i < target->req_ring_size; ++i) {
- struct srp_request *req = &target->req_ring[i];
- srp_finish_req(target, req, NULL, DID_RESET << 16);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ if (!ch->target)
+ break;
+ ret += srp_new_cm_id(ch);
}
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ if (!ch->target)
+ break;
+ for (j = 0; j < target->req_ring_size; ++j) {
+ struct srp_request *req = &ch->req_ring[j];
- /*
- * Whether or not creating a new CM ID succeeded, create a new
- * QP. This guarantees that all callback functions for the old QP have
- * finished before any send requests are posted on the new QP.
- */
- ret += srp_create_target_ib(target);
-
- INIT_LIST_HEAD(&target->free_tx);
- for (i = 0; i < target->queue_size; ++i)
- list_add(&target->tx_ring[i]->list, &target->free_tx);
+ srp_finish_req(ch, req, NULL, DID_RESET << 16);
+ }
+ }
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ if (!ch->target)
+ break;
+ /*
+ * Whether or not creating a new CM ID succeeded, create a new
+ * QP. This guarantees that all completion callback function
+ * invocations have finished before request resetting starts.
+ */
+ ret += srp_create_ch_ib(ch);
- if (ret == 0)
- ret = srp_connect_target(target);
+ INIT_LIST_HEAD(&ch->free_tx);
+ for (j = 0; j < target->queue_size; ++j)
+ list_add(&ch->tx_ring[j]->list, &ch->free_tx);
+ }
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ if (ret || !ch->target) {
+ if (i > 1)
+ ret = 0;
+ break;
+ }
+ ret = srp_connect_ch(ch, multich);
+ multich = true;
+ }
if (ret == 0)
shost_printk(KERN_INFO, target->scsi_host,
@@ -1165,12 +1275,12 @@ static void srp_map_desc(struct srp_map_state *state, dma_addr_t dma_addr,
}
static int srp_map_finish_fmr(struct srp_map_state *state,
- struct srp_target_port *target)
+ struct srp_rdma_ch *ch)
{
struct ib_pool_fmr *fmr;
u64 io_addr = 0;
- fmr = ib_fmr_pool_map_phys(target->fmr_pool, state->pages,
+ fmr = ib_fmr_pool_map_phys(ch->fmr_pool, state->pages,
state->npages, io_addr);
if (IS_ERR(fmr))
return PTR_ERR(fmr);
@@ -1184,15 +1294,16 @@ static int srp_map_finish_fmr(struct srp_map_state *state,
}
static int srp_map_finish_fr(struct srp_map_state *state,
- struct srp_target_port *target)
+ struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_send_wr *bad_wr;
struct ib_send_wr wr;
struct srp_fr_desc *desc;
u32 rkey;
- desc = srp_fr_pool_get(target->fr_pool);
+ desc = srp_fr_pool_get(ch->fr_pool);
if (!desc)
return -ENOMEM;
@@ -1221,12 +1332,13 @@ static int srp_map_finish_fr(struct srp_map_state *state,
srp_map_desc(state, state->base_dma_addr, state->dma_len,
desc->mr->rkey);
- return ib_post_send(target->qp, &wr, &bad_wr);
+ return ib_post_send(ch->qp, &wr, &bad_wr);
}
static int srp_finish_mapping(struct srp_map_state *state,
- struct srp_target_port *target)
+ struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
int ret = 0;
if (state->npages == 0)
@@ -1237,8 +1349,8 @@ static int srp_finish_mapping(struct srp_map_state *state,
target->rkey);
else
ret = target->srp_host->srp_dev->use_fast_reg ?
- srp_map_finish_fr(state, target) :
- srp_map_finish_fmr(state, target);
+ srp_map_finish_fr(state, ch) :
+ srp_map_finish_fmr(state, ch);
if (ret == 0) {
state->npages = 0;
@@ -1258,10 +1370,11 @@ static void srp_map_update_start(struct srp_map_state *state,
}
static int srp_map_sg_entry(struct srp_map_state *state,
- struct srp_target_port *target,
+ struct srp_rdma_ch *ch,
struct scatterlist *sg, int sg_index,
bool use_mr)
{
+ struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_device *ibdev = dev->dev;
dma_addr_t dma_addr = ib_sg_dma_address(ibdev, sg);
@@ -1290,7 +1403,7 @@ static int srp_map_sg_entry(struct srp_map_state *state,
*/
if ((!dev->use_fast_reg && dma_addr & ~dev->mr_page_mask) ||
dma_len > dev->mr_max_size) {
- ret = srp_finish_mapping(state, target);
+ ret = srp_finish_mapping(state, ch);
if (ret)
return ret;
@@ -1311,7 +1424,7 @@ static int srp_map_sg_entry(struct srp_map_state *state,
while (dma_len) {
unsigned offset = dma_addr & ~dev->mr_page_mask;
if (state->npages == dev->max_pages_per_mr || offset != 0) {
- ret = srp_finish_mapping(state, target);
+ ret = srp_finish_mapping(state, ch);
if (ret)
return ret;
@@ -1335,17 +1448,18 @@ static int srp_map_sg_entry(struct srp_map_state *state,
*/
ret = 0;
if (len != dev->mr_page_size) {
- ret = srp_finish_mapping(state, target);
+ ret = srp_finish_mapping(state, ch);
if (!ret)
srp_map_update_start(state, NULL, 0, 0);
}
return ret;
}
-static int srp_map_sg(struct srp_map_state *state,
- struct srp_target_port *target, struct srp_request *req,
- struct scatterlist *scat, int count)
+static int srp_map_sg(struct srp_map_state *state, struct srp_rdma_ch *ch,
+ struct srp_request *req, struct scatterlist *scat,
+ int count)
{
+ struct srp_target_port *target = ch->target;
struct srp_device *dev = target->srp_host->srp_dev;
struct ib_device *ibdev = dev->dev;
struct scatterlist *sg;
@@ -1356,14 +1470,14 @@ static int srp_map_sg(struct srp_map_state *state,
state->pages = req->map_page;
if (dev->use_fast_reg) {
state->next_fr = req->fr_list;
- use_mr = !!target->fr_pool;
+ use_mr = !!ch->fr_pool;
} else {
state->next_fmr = req->fmr_list;
- use_mr = !!target->fmr_pool;
+ use_mr = !!ch->fmr_pool;
}
for_each_sg(scat, sg, count, i) {
- if (srp_map_sg_entry(state, target, sg, i, use_mr)) {
+ if (srp_map_sg_entry(state, ch, sg, i, use_mr)) {
/*
* Memory registration failed, so backtrack to the
* first unmapped entry and continue on without using
@@ -1385,7 +1499,7 @@ backtrack:
}
}
- if (use_mr && srp_finish_mapping(state, target))
+ if (use_mr && srp_finish_mapping(state, ch))
goto backtrack;
req->nmdesc = state->nmdesc;
@@ -1393,9 +1507,10 @@ backtrack:
return 0;
}
-static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
+static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_rdma_ch *ch,
struct srp_request *req)
{
+ struct srp_target_port *target = ch->target;
struct scatterlist *scat;
struct srp_cmd *cmd = req->cmd->buf;
int len, nents, count;
@@ -1457,7 +1572,7 @@ static int srp_map_data(struct scsi_cmnd *scmnd, struct srp_target_port *target,
target->indirect_size, DMA_TO_DEVICE);
memset(&state, 0, sizeof(state));
- srp_map_sg(&state, target, req, scat, count);
+ srp_map_sg(&state, ch, req, scat, count);
/* We've mapped the request, now pull as much of the indirect
* descriptor table as we can into the command buffer. If this
@@ -1518,20 +1633,20 @@ map_complete:
/*
* Return an IU and possible credit to the free pool
*/
-static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu,
+static void srp_put_tx_iu(struct srp_rdma_ch *ch, struct srp_iu *iu,
enum srp_iu_type iu_type)
{
unsigned long flags;
- spin_lock_irqsave(&target->lock, flags);
- list_add(&iu->list, &target->free_tx);
+ spin_lock_irqsave(&ch->lock, flags);
+ list_add(&iu->list, &ch->free_tx);
if (iu_type != SRP_IU_RSP)
- ++target->req_lim;
- spin_unlock_irqrestore(&target->lock, flags);
+ ++ch->req_lim;
+ spin_unlock_irqrestore(&ch->lock, flags);
}
/*
- * Must be called with target->lock held to protect req_lim and free_tx.
+ * Must be called with ch->lock held to protect req_lim and free_tx.
* If IU is not sent, it must be returned using srp_put_tx_iu().
*
* Note:
@@ -1543,35 +1658,36 @@ static void srp_put_tx_iu(struct srp_target_port *target, struct srp_iu *iu,
* - SRP_IU_RSP: 1, since a conforming SRP target never sends more than
* one unanswered SRP request to an initiator.
*/
-static struct srp_iu *__srp_get_tx_iu(struct srp_target_port *target,
+static struct srp_iu *__srp_get_tx_iu(struct srp_rdma_ch *ch,
enum srp_iu_type iu_type)
{
+ struct srp_target_port *target = ch->target;
s32 rsv = (iu_type == SRP_IU_TSK_MGMT) ? 0 : SRP_TSK_MGMT_SQ_SIZE;
struct srp_iu *iu;
- srp_send_completion(target->send_cq, target);
+ srp_send_completion(ch->send_cq, ch);
- if (list_empty(&target->free_tx))
+ if (list_empty(&ch->free_tx))
return NULL;
/* Initiator responses to target requests do not consume credits */
if (iu_type != SRP_IU_RSP) {
- if (target->req_lim <= rsv) {
+ if (ch->req_lim <= rsv) {
++target->zero_req_lim;
return NULL;
}
- --target->req_lim;
+ --ch->req_lim;
}
- iu = list_first_entry(&target->free_tx, struct srp_iu, list);
+ iu = list_first_entry(&ch->free_tx, struct srp_iu, list);
list_del(&iu->list);
return iu;
}
-static int srp_post_send(struct srp_target_port *target,
- struct srp_iu *iu, int len)
+static int srp_post_send(struct srp_rdma_ch *ch, struct srp_iu *iu, int len)
{
+ struct srp_target_port *target = ch->target;
struct ib_sge list;
struct ib_send_wr wr, *bad_wr;
@@ -1586,11 +1702,12 @@ static int srp_post_send(struct srp_target_port *target,
wr.opcode = IB_WR_SEND;
wr.send_flags = IB_SEND_SIGNALED;
- return ib_post_send(target->qp, &wr, &bad_wr);
+ return ib_post_send(ch->qp, &wr, &bad_wr);
}
-static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu)
+static int srp_post_recv(struct srp_rdma_ch *ch, struct srp_iu *iu)
{
+ struct srp_target_port *target = ch->target;
struct ib_recv_wr wr, *bad_wr;
struct ib_sge list;
@@ -1603,35 +1720,39 @@ static int srp_post_recv(struct srp_target_port *target, struct srp_iu *iu)
wr.sg_list = &list;
wr.num_sge = 1;
- return ib_post_recv(target->qp, &wr, &bad_wr);
+ return ib_post_recv(ch->qp, &wr, &bad_wr);
}
-static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
+static void srp_process_rsp(struct srp_rdma_ch *ch, struct srp_rsp *rsp)
{
+ struct srp_target_port *target = ch->target;
struct srp_request *req;
struct scsi_cmnd *scmnd;
unsigned long flags;
if (unlikely(rsp->tag & SRP_TAG_TSK_MGMT)) {
- spin_lock_irqsave(&target->lock, flags);
- target->req_lim += be32_to_cpu(rsp->req_lim_delta);
- spin_unlock_irqrestore(&target->lock, flags);
+ spin_lock_irqsave(&ch->lock, flags);
+ ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
+ spin_unlock_irqrestore(&ch->lock, flags);
- target->tsk_mgmt_status = -1;
+ ch->tsk_mgmt_status = -1;
if (be32_to_cpu(rsp->resp_data_len) >= 4)
- target->tsk_mgmt_status = rsp->data[3];
- complete(&target->tsk_mgmt_done);
+ ch->tsk_mgmt_status = rsp->data[3];
+ complete(&ch->tsk_mgmt_done);
} else {
- req = &target->req_ring[rsp->tag];
- scmnd = srp_claim_req(target, req, NULL, NULL);
+ scmnd = scsi_host_find_tag(target->scsi_host, rsp->tag);
+ if (scmnd) {
+ req = (void *)scmnd->host_scribble;
+ scmnd = srp_claim_req(ch, req, NULL, scmnd);
+ }
if (!scmnd) {
shost_printk(KERN_ERR, target->scsi_host,
- "Null scmnd for RSP w/tag %016llx\n",
- (unsigned long long) rsp->tag);
+ "Null scmnd for RSP w/tag %#016llx received on ch %td / QP %#x\n",
+ rsp->tag, ch - target->ch, ch->qp->qp_num);
- spin_lock_irqsave(&target->lock, flags);
- target->req_lim += be32_to_cpu(rsp->req_lim_delta);
- spin_unlock_irqrestore(&target->lock, flags);
+ spin_lock_irqsave(&ch->lock, flags);
+ ch->req_lim += be32_to_cpu(rsp->req_lim_delta);
+ spin_unlock_irqrestore(&ch->lock, flags);
return;
}
@@ -1653,7 +1774,7 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
else if (unlikely(rsp->flags & SRP_RSP_FLAG_DOOVER))
scsi_set_resid(scmnd, -be32_to_cpu(rsp->data_out_res_cnt));
- srp_free_req(target, req, scmnd,
+ srp_free_req(ch, req, scmnd,
be32_to_cpu(rsp->req_lim_delta));
scmnd->host_scribble = NULL;
@@ -1661,18 +1782,19 @@ static void srp_process_rsp(struct srp_target_port *target, struct srp_rsp *rsp)
}
}
-static int srp_response_common(struct srp_target_port *target, s32 req_delta,
+static int srp_response_common(struct srp_rdma_ch *ch, s32 req_delta,
void *rsp, int len)
{
+ struct srp_target_port *target = ch->target;
struct ib_device *dev = target->srp_host->srp_dev->dev;
unsigned long flags;
struct srp_iu *iu;
int err;
- spin_lock_irqsave(&target->lock, flags);
- target->req_lim += req_delta;
- iu = __srp_get_tx_iu(target, SRP_IU_RSP);
- spin_unlock_irqrestore(&target->lock, flags);
+ spin_lock_irqsave(&ch->lock, flags);
+ ch->req_lim += req_delta;
+ iu = __srp_get_tx_iu(ch, SRP_IU_RSP);
+ spin_unlock_irqrestore(&ch->lock, flags);
if (!iu) {
shost_printk(KERN_ERR, target->scsi_host, PFX
@@ -1684,17 +1806,17 @@ static int srp_response_common(struct srp_target_port *target, s32 req_delta,
memcpy(iu->buf, rsp, len);
ib_dma_sync_single_for_device(dev, iu->dma, len, DMA_TO_DEVICE);
- err = srp_post_send(target, iu, len);
+ err = srp_post_send(ch, iu, len);
if (err) {
shost_printk(KERN_ERR, target->scsi_host, PFX
"unable to post response: %d\n", err);
- srp_put_tx_iu(target, iu, SRP_IU_RSP);
+ srp_put_tx_iu(ch, iu, SRP_IU_RSP);
}
return err;
}
-static void srp_process_cred_req(struct srp_target_port *target,
+static void srp_process_cred_req(struct srp_rdma_ch *ch,
struct srp_cred_req *req)
{
struct srp_cred_rsp rsp = {
@@ -1703,14 +1825,15 @@ static void srp_process_cred_req(struct srp_target_port *target,
};
s32 delta = be32_to_cpu(req->req_lim_delta);
- if (srp_response_common(target, delta, &rsp, sizeof rsp))
- shost_printk(KERN_ERR, target->scsi_host, PFX
+ if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
+ shost_printk(KERN_ERR, ch->target->scsi_host, PFX
"problems processing SRP_CRED_REQ\n");
}
-static void srp_process_aer_req(struct srp_target_port *target,
+static void srp_process_aer_req(struct srp_rdma_ch *ch,
struct srp_aer_req *req)
{
+ struct srp_target_port *target = ch->target;
struct srp_aer_rsp rsp = {
.opcode = SRP_AER_RSP,
.tag = req->tag,
@@ -1720,19 +1843,20 @@ static void srp_process_aer_req(struct srp_target_port *target,
shost_printk(KERN_ERR, target->scsi_host, PFX
"ignoring AER for LUN %llu\n", be64_to_cpu(req->lun));
- if (srp_response_common(target, delta, &rsp, sizeof rsp))
+ if (srp_response_common(ch, delta, &rsp, sizeof(rsp)))
shost_printk(KERN_ERR, target->scsi_host, PFX
"problems processing SRP_AER_REQ\n");
}
-static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
+static void srp_handle_recv(struct srp_rdma_ch *ch, struct ib_wc *wc)
{
+ struct srp_target_port *target = ch->target;
struct ib_device *dev = target->srp_host->srp_dev->dev;
struct srp_iu *iu = (struct srp_iu *) (uintptr_t) wc->wr_id;
int res;
u8 opcode;
- ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_ti_iu_len,
+ ib_dma_sync_single_for_cpu(dev, iu->dma, ch->max_ti_iu_len,
DMA_FROM_DEVICE);
opcode = *(u8 *) iu->buf;
@@ -1746,15 +1870,15 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
switch (opcode) {
case SRP_RSP:
- srp_process_rsp(target, iu->buf);
+ srp_process_rsp(ch, iu->buf);
break;
case SRP_CRED_REQ:
- srp_process_cred_req(target, iu->buf);
+ srp_process_cred_req(ch, iu->buf);
break;
case SRP_AER_REQ:
- srp_process_aer_req(target, iu->buf);
+ srp_process_aer_req(ch, iu->buf);
break;
case SRP_T_LOGOUT:
@@ -1769,10 +1893,10 @@ static void srp_handle_recv(struct srp_target_port *target, struct ib_wc *wc)
break;
}
- ib_dma_sync_single_for_device(dev, iu->dma, target->max_ti_iu_len,
+ ib_dma_sync_single_for_device(dev, iu->dma, ch->max_ti_iu_len,
DMA_FROM_DEVICE);
- res = srp_post_recv(target, iu);
+ res = srp_post_recv(ch, iu);
if (res != 0)
shost_printk(KERN_ERR, target->scsi_host,
PFX "Recv failed with error code %d\n", res);
@@ -1795,8 +1919,15 @@ static void srp_tl_err_work(struct work_struct *work)
}
static void srp_handle_qp_err(u64 wr_id, enum ib_wc_status wc_status,
- bool send_err, struct srp_target_port *target)
+ bool send_err, struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
+
+ if (wr_id == SRP_LAST_WR_ID) {
+ complete(&ch->done);
+ return;
+ }
+
if (target->connected && !target->qp_in_error) {
if (wr_id & LOCAL_INV_WR_ID_MASK) {
shost_printk(KERN_ERR, target->scsi_host, PFX
@@ -1817,33 +1948,33 @@ static void srp_handle_qp_err(u64 wr_id, enum ib_wc_status wc_status,
target->qp_in_error = true;
}
-static void srp_recv_completion(struct ib_cq *cq, void *target_ptr)
+static void srp_recv_completion(struct ib_cq *cq, void *ch_ptr)
{
- struct srp_target_port *target = target_ptr;
+ struct srp_rdma_ch *ch = ch_ptr;
struct ib_wc wc;
ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
while (ib_poll_cq(cq, 1, &wc) > 0) {
if (likely(wc.status == IB_WC_SUCCESS)) {
- srp_handle_recv(target, &wc);
+ srp_handle_recv(ch, &wc);
} else {
- srp_handle_qp_err(wc.wr_id, wc.status, false, target);
+ srp_handle_qp_err(wc.wr_id, wc.status, false, ch);
}
}
}
-static void srp_send_completion(struct ib_cq *cq, void *target_ptr)
+static void srp_send_completion(struct ib_cq *cq, void *ch_ptr)
{
- struct srp_target_port *target = target_ptr;
+ struct srp_rdma_ch *ch = ch_ptr;
struct ib_wc wc;
struct srp_iu *iu;
while (ib_poll_cq(cq, 1, &wc) > 0) {
if (likely(wc.status == IB_WC_SUCCESS)) {
iu = (struct srp_iu *) (uintptr_t) wc.wr_id;
- list_add(&iu->list, &target->free_tx);
+ list_add(&iu->list, &ch->free_tx);
} else {
- srp_handle_qp_err(wc.wr_id, wc.status, true, target);
+ srp_handle_qp_err(wc.wr_id, wc.status, true, ch);
}
}
}
@@ -1852,11 +1983,14 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(shost);
struct srp_rport *rport = target->rport;
+ struct srp_rdma_ch *ch;
struct srp_request *req;
struct srp_iu *iu;
struct srp_cmd *cmd;
struct ib_device *dev;
unsigned long flags;
+ u32 tag;
+ u16 idx;
int len, ret;
const bool in_scsi_eh = !in_interrupt() && current == shost->ehandler;
@@ -1873,15 +2007,22 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
if (unlikely(scmnd->result))
goto err;
- spin_lock_irqsave(&target->lock, flags);
- iu = __srp_get_tx_iu(target, SRP_IU_CMD);
- if (!iu)
- goto err_unlock;
+ WARN_ON_ONCE(scmnd->request->tag < 0);
+ tag = blk_mq_unique_tag(scmnd->request);
+ ch = &target->ch[blk_mq_unique_tag_to_hwq(tag)];
+ idx = blk_mq_unique_tag_to_tag(tag);
+ WARN_ONCE(idx >= target->req_ring_size, "%s: tag %#x: idx %d >= %d\n",
+ dev_name(&shost->shost_gendev), tag, idx,
+ target->req_ring_size);
- req = list_first_entry(&target->free_reqs, struct srp_request, list);
- list_del(&req->list);
- spin_unlock_irqrestore(&target->lock, flags);
+ spin_lock_irqsave(&ch->lock, flags);
+ iu = __srp_get_tx_iu(ch, SRP_IU_CMD);
+ spin_unlock_irqrestore(&ch->lock, flags);
+ if (!iu)
+ goto err;
+
+ req = &ch->req_ring[idx];
dev = target->srp_host->srp_dev->dev;
ib_dma_sync_single_for_cpu(dev, iu->dma, target->max_iu_len,
DMA_TO_DEVICE);
@@ -1893,13 +2034,13 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
cmd->opcode = SRP_CMD;
cmd->lun = cpu_to_be64((u64) scmnd->device->lun << 48);
- cmd->tag = req->index;
+ cmd->tag = tag;
memcpy(cmd->cdb, scmnd->cmnd, scmnd->cmd_len);
req->scmnd = scmnd;
req->cmd = iu;
- len = srp_map_data(scmnd, target, req);
+ len = srp_map_data(scmnd, ch, req);
if (len < 0) {
shost_printk(KERN_ERR, target->scsi_host,
PFX "Failed to map data (%d)\n", len);
@@ -1917,7 +2058,7 @@ static int srp_queuecommand(struct Scsi_Host *shost, struct scsi_cmnd *scmnd)
ib_dma_sync_single_for_device(dev, iu->dma, target->max_iu_len,
DMA_TO_DEVICE);
- if (srp_post_send(target, iu, len)) {
+ if (srp_post_send(ch, iu, len)) {
shost_printk(KERN_ERR, target->scsi_host, PFX "Send failed\n");
goto err_unmap;
}
@@ -1931,10 +2072,10 @@ unlock_rport:
return ret;
err_unmap:
- srp_unmap_data(scmnd, target, req);
+ srp_unmap_data(scmnd, ch, req);
err_iu:
- srp_put_tx_iu(target, iu, SRP_IU_CMD);
+ srp_put_tx_iu(ch, iu, SRP_IU_CMD);
/*
* Avoid that the loops that iterate over the request ring can
@@ -1942,12 +2083,6 @@ err_iu:
*/
req->scmnd = NULL;
- spin_lock_irqsave(&target->lock, flags);
- list_add(&req->list, &target->free_reqs);
-
-err_unlock:
- spin_unlock_irqrestore(&target->lock, flags);
-
err:
if (scmnd->result) {
scmnd->scsi_done(scmnd);
@@ -1961,53 +2096,54 @@ err:
/*
* Note: the resources allocated in this function are freed in
- * srp_free_target_ib().
+ * srp_free_ch_ib().
*/
-static int srp_alloc_iu_bufs(struct srp_target_port *target)
+static int srp_alloc_iu_bufs(struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
int i;
- target->rx_ring = kzalloc(target->queue_size * sizeof(*target->rx_ring),
- GFP_KERNEL);
- if (!target->rx_ring)
+ ch->rx_ring = kcalloc(target->queue_size, sizeof(*ch->rx_ring),
+ GFP_KERNEL);
+ if (!ch->rx_ring)
goto err_no_ring;
- target->tx_ring = kzalloc(target->queue_size * sizeof(*target->tx_ring),
- GFP_KERNEL);
- if (!target->tx_ring)
+ ch->tx_ring = kcalloc(target->queue_size, sizeof(*ch->tx_ring),
+ GFP_KERNEL);
+ if (!ch->tx_ring)
goto err_no_ring;
for (i = 0; i < target->queue_size; ++i) {
- target->rx_ring[i] = srp_alloc_iu(target->srp_host,
- target->max_ti_iu_len,
- GFP_KERNEL, DMA_FROM_DEVICE);
- if (!target->rx_ring[i])
+ ch->rx_ring[i] = srp_alloc_iu(target->srp_host,
+ ch->max_ti_iu_len,
+ GFP_KERNEL, DMA_FROM_DEVICE);
+ if (!ch->rx_ring[i])
goto err;
}
for (i = 0; i < target->queue_size; ++i) {
- target->tx_ring[i] = srp_alloc_iu(target->srp_host,
- target->max_iu_len,
- GFP_KERNEL, DMA_TO_DEVICE);
- if (!target->tx_ring[i])
+ ch->tx_ring[i] = srp_alloc_iu(target->srp_host,
+ target->max_iu_len,
+ GFP_KERNEL, DMA_TO_DEVICE);
+ if (!ch->tx_ring[i])
goto err;
- list_add(&target->tx_ring[i]->list, &target->free_tx);
+ list_add(&ch->tx_ring[i]->list, &ch->free_tx);
}
return 0;
err:
for (i = 0; i < target->queue_size; ++i) {
- srp_free_iu(target->srp_host, target->rx_ring[i]);
- srp_free_iu(target->srp_host, target->tx_ring[i]);
+ srp_free_iu(target->srp_host, ch->rx_ring[i]);
+ srp_free_iu(target->srp_host, ch->tx_ring[i]);
}
err_no_ring:
- kfree(target->tx_ring);
- target->tx_ring = NULL;
- kfree(target->rx_ring);
- target->rx_ring = NULL;
+ kfree(ch->tx_ring);
+ ch->tx_ring = NULL;
+ kfree(ch->rx_ring);
+ ch->rx_ring = NULL;
return -ENOMEM;
}
@@ -2041,23 +2177,24 @@ static uint32_t srp_compute_rq_tmo(struct ib_qp_attr *qp_attr, int attr_mask)
static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
struct srp_login_rsp *lrsp,
- struct srp_target_port *target)
+ struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
struct ib_qp_attr *qp_attr = NULL;
int attr_mask = 0;
int ret;
int i;
if (lrsp->opcode == SRP_LOGIN_RSP) {
- target->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
- target->req_lim = be32_to_cpu(lrsp->req_lim_delta);
+ ch->max_ti_iu_len = be32_to_cpu(lrsp->max_ti_iu_len);
+ ch->req_lim = be32_to_cpu(lrsp->req_lim_delta);
/*
* Reserve credits for task management so we don't
* bounce requests back to the SCSI mid-layer.
*/
target->scsi_host->can_queue
- = min(target->req_lim - SRP_TSK_MGMT_SQ_SIZE,
+ = min(ch->req_lim - SRP_TSK_MGMT_SQ_SIZE,
target->scsi_host->can_queue);
target->scsi_host->cmd_per_lun
= min_t(int, target->scsi_host->can_queue,
@@ -2069,8 +2206,8 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
goto error;
}
- if (!target->rx_ring) {
- ret = srp_alloc_iu_bufs(target);
+ if (!ch->rx_ring) {
+ ret = srp_alloc_iu_bufs(ch);
if (ret)
goto error;
}
@@ -2085,13 +2222,14 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
if (ret)
goto error_free;
- ret = ib_modify_qp(target->qp, qp_attr, attr_mask);
+ ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
if (ret)
goto error_free;
for (i = 0; i < target->queue_size; i++) {
- struct srp_iu *iu = target->rx_ring[i];
- ret = srp_post_recv(target, iu);
+ struct srp_iu *iu = ch->rx_ring[i];
+
+ ret = srp_post_recv(ch, iu);
if (ret)
goto error_free;
}
@@ -2103,7 +2241,7 @@ static void srp_cm_rep_handler(struct ib_cm_id *cm_id,
target->rq_tmo_jiffies = srp_compute_rq_tmo(qp_attr, attr_mask);
- ret = ib_modify_qp(target->qp, qp_attr, attr_mask);
+ ret = ib_modify_qp(ch->qp, qp_attr, attr_mask);
if (ret)
goto error_free;
@@ -2113,13 +2251,14 @@ error_free:
kfree(qp_attr);
error:
- target->status = ret;
+ ch->status = ret;
}
static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
struct ib_cm_event *event,
- struct srp_target_port *target)
+ struct srp_rdma_ch *ch)
{
+ struct srp_target_port *target = ch->target;
struct Scsi_Host *shost = target->scsi_host;
struct ib_class_port_info *cpi;
int opcode;
@@ -2127,12 +2266,12 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
switch (event->param.rej_rcvd.reason) {
case IB_CM_REJ_PORT_CM_REDIRECT:
cpi = event->param.rej_rcvd.ari;
- target->path.dlid = cpi->redirect_lid;
- target->path.pkey = cpi->redirect_pkey;
+ ch->path.dlid = cpi->redirect_lid;
+ ch->path.pkey = cpi->redirect_pkey;
cm_id->remote_cm_qpn = be32_to_cpu(cpi->redirect_qp) & 0x00ffffff;
- memcpy(target->path.dgid.raw, cpi->redirect_gid, 16);
+ memcpy(ch->path.dgid.raw, cpi->redirect_gid, 16);
- target->status = target->path.dlid ?
+ ch->status = ch->path.dlid ?
SRP_DLID_REDIRECT : SRP_PORT_REDIRECT;
break;
@@ -2143,26 +2282,26 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
* reject reason code 25 when they mean 24
* (port redirect).
*/
- memcpy(target->path.dgid.raw,
+ memcpy(ch->path.dgid.raw,
event->param.rej_rcvd.ari, 16);
shost_printk(KERN_DEBUG, shost,
PFX "Topspin/Cisco redirect to target port GID %016llx%016llx\n",
- (unsigned long long) be64_to_cpu(target->path.dgid.global.subnet_prefix),
- (unsigned long long) be64_to_cpu(target->path.dgid.global.interface_id));
+ be64_to_cpu(ch->path.dgid.global.subnet_prefix),
+ be64_to_cpu(ch->path.dgid.global.interface_id));
- target->status = SRP_PORT_REDIRECT;
+ ch->status = SRP_PORT_REDIRECT;
} else {
shost_printk(KERN_WARNING, shost,
" REJ reason: IB_CM_REJ_PORT_REDIRECT\n");
- target->status = -ECONNRESET;
+ ch->status = -ECONNRESET;
}
break;
case IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID:
shost_printk(KERN_WARNING, shost,
" REJ reason: IB_CM_REJ_DUPLICATE_LOCAL_COMM_ID\n");
- target->status = -ECONNRESET;
+ ch->status = -ECONNRESET;
break;
case IB_CM_REJ_CONSUMER_DEFINED:
@@ -2177,30 +2316,31 @@ static void srp_cm_rej_handler(struct ib_cm_id *cm_id,
else
shost_printk(KERN_WARNING, shost, PFX
"SRP LOGIN from %pI6 to %pI6 REJECTED, reason 0x%08x\n",
- target->path.sgid.raw,
- target->orig_dgid, reason);
+ target->sgid.raw,
+ target->orig_dgid.raw, reason);
} else
shost_printk(KERN_WARNING, shost,
" REJ reason: IB_CM_REJ_CONSUMER_DEFINED,"
" opcode 0x%02x\n", opcode);
- target->status = -ECONNRESET;
+ ch->status = -ECONNRESET;
break;
case IB_CM_REJ_STALE_CONN:
shost_printk(KERN_WARNING, shost, " REJ reason: stale connection\n");
- target->status = SRP_STALE_CONN;
+ ch->status = SRP_STALE_CONN;
break;
default:
shost_printk(KERN_WARNING, shost, " REJ reason 0x%x\n",
event->param.rej_rcvd.reason);
- target->status = -ECONNRESET;
+ ch->status = -ECONNRESET;
}
}
static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
{
- struct srp_target_port *target = cm_id->context;
+ struct srp_rdma_ch *ch = cm_id->context;
+ struct srp_target_port *target = ch->target;
int comp = 0;
switch (event->event) {
@@ -2208,19 +2348,19 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
shost_printk(KERN_DEBUG, target->scsi_host,
PFX "Sending CM REQ failed\n");
comp = 1;
- target->status = -ECONNRESET;
+ ch->status = -ECONNRESET;
break;
case IB_CM_REP_RECEIVED:
comp = 1;
- srp_cm_rep_handler(cm_id, event->private_data, target);
+ srp_cm_rep_handler(cm_id, event->private_data, ch);
break;
case IB_CM_REJ_RECEIVED:
shost_printk(KERN_DEBUG, target->scsi_host, PFX "REJ received\n");
comp = 1;
- srp_cm_rej_handler(cm_id, event, target);
+ srp_cm_rej_handler(cm_id, event, ch);
break;
case IB_CM_DREQ_RECEIVED:
@@ -2238,7 +2378,7 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
PFX "connection closed\n");
comp = 1;
- target->status = 0;
+ ch->status = 0;
break;
case IB_CM_MRA_RECEIVED:
@@ -2253,65 +2393,30 @@ static int srp_cm_handler(struct ib_cm_id *cm_id, struct ib_cm_event *event)
}
if (comp)
- complete(&target->done);
+ complete(&ch->done);
return 0;
}
/**
- * srp_change_queue_type - changing device queue tag type
- * @sdev: scsi device struct
- * @tag_type: requested tag type
- *
- * Returns queue tag type.
- */
-static int
-srp_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
-}
-
-/**
* srp_change_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
- * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
- * (see include/scsi/scsi_host.h for definition)
*
* Returns queue depth.
*/
static int
-srp_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+srp_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
- struct Scsi_Host *shost = sdev->host;
- int max_depth;
- if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) {
- max_depth = shost->can_queue;
- if (!sdev->tagged_supported)
- max_depth = 1;
- if (qdepth > max_depth)
- qdepth = max_depth;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- } else if (reason == SCSI_QDEPTH_QFULL)
- scsi_track_queue_full(sdev, qdepth);
- else
- return -EOPNOTSUPP;
-
- return sdev->queue_depth;
+ if (!sdev->tagged_supported)
+ qdepth = 1;
+ return scsi_change_queue_depth(sdev, qdepth);
}
-static int srp_send_tsk_mgmt(struct srp_target_port *target,
- u64 req_tag, unsigned int lun, u8 func)
+static int srp_send_tsk_mgmt(struct srp_rdma_ch *ch, u64 req_tag,
+ unsigned int lun, u8 func)
{
+ struct srp_target_port *target = ch->target;
struct srp_rport *rport = target->rport;
struct ib_device *dev = target->srp_host->srp_dev->dev;
struct srp_iu *iu;
@@ -2320,16 +2425,16 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
if (!target->connected || target->qp_in_error)
return -1;
- init_completion(&target->tsk_mgmt_done);
+ init_completion(&ch->tsk_mgmt_done);
/*
- * Lock the rport mutex to avoid that srp_create_target_ib() is
+ * Lock the rport mutex to avoid that srp_create_ch_ib() is
* invoked while a task management function is being sent.
*/
mutex_lock(&rport->mutex);
- spin_lock_irq(&target->lock);
- iu = __srp_get_tx_iu(target, SRP_IU_TSK_MGMT);
- spin_unlock_irq(&target->lock);
+ spin_lock_irq(&ch->lock);
+ iu = __srp_get_tx_iu(ch, SRP_IU_TSK_MGMT);
+ spin_unlock_irq(&ch->lock);
if (!iu) {
mutex_unlock(&rport->mutex);
@@ -2350,15 +2455,15 @@ static int srp_send_tsk_mgmt(struct srp_target_port *target,
ib_dma_sync_single_for_device(dev, iu->dma, sizeof *tsk_mgmt,
DMA_TO_DEVICE);
- if (srp_post_send(target, iu, sizeof *tsk_mgmt)) {
- srp_put_tx_iu(target, iu, SRP_IU_TSK_MGMT);
+ if (srp_post_send(ch, iu, sizeof(*tsk_mgmt))) {
+ srp_put_tx_iu(ch, iu, SRP_IU_TSK_MGMT);
mutex_unlock(&rport->mutex);
return -1;
}
mutex_unlock(&rport->mutex);
- if (!wait_for_completion_timeout(&target->tsk_mgmt_done,
+ if (!wait_for_completion_timeout(&ch->tsk_mgmt_done,
msecs_to_jiffies(SRP_ABORT_TIMEOUT_MS)))
return -1;
@@ -2369,20 +2474,32 @@ static int srp_abort(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
struct srp_request *req = (struct srp_request *) scmnd->host_scribble;
+ u32 tag;
+ u16 ch_idx;
+ struct srp_rdma_ch *ch;
int ret;
shost_printk(KERN_ERR, target->scsi_host, "SRP abort called\n");
- if (!req || !srp_claim_req(target, req, NULL, scmnd))
+ if (!req)
+ return SUCCESS;
+ tag = blk_mq_unique_tag(scmnd->request);
+ ch_idx = blk_mq_unique_tag_to_hwq(tag);
+ if (WARN_ON_ONCE(ch_idx >= target->ch_count))
return SUCCESS;
- if (srp_send_tsk_mgmt(target, req->index, scmnd->device->lun,
+ ch = &target->ch[ch_idx];
+ if (!srp_claim_req(ch, req, NULL, scmnd))
+ return SUCCESS;
+ shost_printk(KERN_ERR, target->scsi_host,
+ "Sending SRP abort for tag %#x\n", tag);
+ if (srp_send_tsk_mgmt(ch, tag, scmnd->device->lun,
SRP_TSK_ABORT_TASK) == 0)
ret = SUCCESS;
else if (target->rport->state == SRP_RPORT_LOST)
ret = FAST_IO_FAIL;
else
ret = FAILED;
- srp_free_req(target, req, scmnd, 0);
+ srp_free_req(ch, req, scmnd, 0);
scmnd->result = DID_ABORT << 16;
scmnd->scsi_done(scmnd);
@@ -2392,19 +2509,25 @@ static int srp_abort(struct scsi_cmnd *scmnd)
static int srp_reset_device(struct scsi_cmnd *scmnd)
{
struct srp_target_port *target = host_to_target(scmnd->device->host);
+ struct srp_rdma_ch *ch;
int i;
shost_printk(KERN_ERR, target->scsi_host, "SRP reset_device called\n");
- if (srp_send_tsk_mgmt(target, SRP_TAG_NO_REQ, scmnd->device->lun,
+ ch = &target->ch[0];
+ if (srp_send_tsk_mgmt(ch, SRP_TAG_NO_REQ, scmnd->device->lun,
SRP_TSK_LUN_RESET))
return FAILED;
- if (target->tsk_mgmt_status)
+ if (ch->tsk_mgmt_status)
return FAILED;
- for (i = 0; i < target->req_ring_size; ++i) {
- struct srp_request *req = &target->req_ring[i];
- srp_finish_req(target, req, scmnd->device, DID_RESET << 16);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ for (i = 0; i < target->req_ring_size; ++i) {
+ struct srp_request *req = &ch->req_ring[i];
+
+ srp_finish_req(ch, req, scmnd->device, DID_RESET << 16);
+ }
}
return SUCCESS;
@@ -2466,7 +2589,7 @@ static ssize_t show_pkey(struct device *dev, struct device_attribute *attr,
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
- return sprintf(buf, "0x%04x\n", be16_to_cpu(target->path.pkey));
+ return sprintf(buf, "0x%04x\n", be16_to_cpu(target->pkey));
}
static ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
@@ -2474,15 +2597,16 @@ static ssize_t show_sgid(struct device *dev, struct device_attribute *attr,
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
- return sprintf(buf, "%pI6\n", target->path.sgid.raw);
+ return sprintf(buf, "%pI6\n", target->sgid.raw);
}
static ssize_t show_dgid(struct device *dev, struct device_attribute *attr,
char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
+ struct srp_rdma_ch *ch = &target->ch[0];
- return sprintf(buf, "%pI6\n", target->path.dgid.raw);
+ return sprintf(buf, "%pI6\n", ch->path.dgid.raw);
}
static ssize_t show_orig_dgid(struct device *dev,
@@ -2490,15 +2614,21 @@ static ssize_t show_orig_dgid(struct device *dev,
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
- return sprintf(buf, "%pI6\n", target->orig_dgid);
+ return sprintf(buf, "%pI6\n", target->orig_dgid.raw);
}
static ssize_t show_req_lim(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct srp_target_port *target = host_to_target(class_to_shost(dev));
+ struct srp_rdma_ch *ch;
+ int i, req_lim = INT_MAX;
- return sprintf(buf, "%d\n", target->req_lim);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ req_lim = min(req_lim, ch->req_lim);
+ }
+ return sprintf(buf, "%d\n", req_lim);
}
static ssize_t show_zero_req_lim(struct device *dev,
@@ -2525,6 +2655,14 @@ static ssize_t show_local_ib_device(struct device *dev,
return sprintf(buf, "%s\n", target->srp_host->srp_dev->dev->name);
}
+static ssize_t show_ch_count(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ struct srp_target_port *target = host_to_target(class_to_shost(dev));
+
+ return sprintf(buf, "%d\n", target->ch_count);
+}
+
static ssize_t show_comp_vector(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -2568,6 +2706,7 @@ static DEVICE_ATTR(req_lim, S_IRUGO, show_req_lim, NULL);
static DEVICE_ATTR(zero_req_lim, S_IRUGO, show_zero_req_lim, NULL);
static DEVICE_ATTR(local_ib_port, S_IRUGO, show_local_ib_port, NULL);
static DEVICE_ATTR(local_ib_device, S_IRUGO, show_local_ib_device, NULL);
+static DEVICE_ATTR(ch_count, S_IRUGO, show_ch_count, NULL);
static DEVICE_ATTR(comp_vector, S_IRUGO, show_comp_vector, NULL);
static DEVICE_ATTR(tl_retry_count, S_IRUGO, show_tl_retry_count, NULL);
static DEVICE_ATTR(cmd_sg_entries, S_IRUGO, show_cmd_sg_entries, NULL);
@@ -2585,6 +2724,7 @@ static struct device_attribute *srp_host_attrs[] = {
&dev_attr_zero_req_lim,
&dev_attr_local_ib_port,
&dev_attr_local_ib_device,
+ &dev_attr_ch_count,
&dev_attr_comp_vector,
&dev_attr_tl_retry_count,
&dev_attr_cmd_sg_entries,
@@ -2600,7 +2740,7 @@ static struct scsi_host_template srp_template = {
.info = srp_target_info,
.queuecommand = srp_queuecommand,
.change_queue_depth = srp_change_queue_depth,
- .change_queue_type = srp_change_queue_type,
+ .change_queue_type = scsi_change_queue_type,
.eh_abort_handler = srp_abort,
.eh_device_reset_handler = srp_reset_device,
.eh_host_reset_handler = srp_reset_host,
@@ -2610,14 +2750,28 @@ static struct scsi_host_template srp_template = {
.this_id = -1,
.cmd_per_lun = SRP_DEFAULT_CMD_SQ_SIZE,
.use_clustering = ENABLE_CLUSTERING,
- .shost_attrs = srp_host_attrs
+ .shost_attrs = srp_host_attrs,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
+static int srp_sdev_count(struct Scsi_Host *host)
+{
+ struct scsi_device *sdev;
+ int c = 0;
+
+ shost_for_each_device(sdev, host)
+ c++;
+
+ return c;
+}
+
static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
{
struct srp_rport_identifiers ids;
struct srp_rport *rport;
+ target->state = SRP_TARGET_SCANNING;
sprintf(target->target_name, "SRP.T10:%016llX",
(unsigned long long) be64_to_cpu(target->id_ext));
@@ -2640,11 +2794,26 @@ static int srp_add_target(struct srp_host *host, struct srp_target_port *target)
list_add_tail(&target->list, &host->target_list);
spin_unlock(&host->target_lock);
- target->state = SRP_TARGET_LIVE;
-
scsi_scan_target(&target->scsi_host->shost_gendev,
0, target->scsi_id, SCAN_WILD_CARD, 0);
+ if (!target->connected || target->qp_in_error) {
+ shost_printk(KERN_INFO, target->scsi_host,
+ PFX "SCSI scan failed - removing SCSI host\n");
+ srp_queue_remove_work(target);
+ goto out;
+ }
+
+ pr_debug(PFX "%s: SCSI scan succeeded - detected %d LUNs\n",
+ dev_name(&target->scsi_host->shost_gendev),
+ srp_sdev_count(target->scsi_host));
+
+ spin_lock_irq(&target->lock);
+ if (target->state == SRP_TARGET_SCANNING)
+ target->state = SRP_TARGET_LIVE;
+ spin_unlock_irq(&target->lock);
+
+out:
return 0;
}
@@ -2801,11 +2970,15 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
}
for (i = 0; i < 16; ++i) {
- strlcpy(dgid, p + i * 2, 3);
- target->path.dgid.raw[i] = simple_strtoul(dgid, NULL, 16);
+ strlcpy(dgid, p + i * 2, sizeof(dgid));
+ if (sscanf(dgid, "%hhx",
+ &target->orig_dgid.raw[i]) < 1) {
+ ret = -EINVAL;
+ kfree(p);
+ goto out;
+ }
}
kfree(p);
- memcpy(target->orig_dgid, target->path.dgid.raw, 16);
break;
case SRP_OPT_PKEY:
@@ -2813,7 +2986,7 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
pr_warn("bad P_Key parameter '%s'\n", p);
goto out;
}
- target->path.pkey = cpu_to_be16(token);
+ target->pkey = cpu_to_be16(token);
break;
case SRP_OPT_SERVICE_ID:
@@ -2823,7 +2996,6 @@ static int srp_parse_options(const char *buf, struct srp_target_port *target)
goto out;
}
target->service_id = cpu_to_be64(simple_strtoull(p, NULL, 16));
- target->path.service_id = target->service_id;
kfree(p);
break;
@@ -2960,9 +3132,11 @@ static ssize_t srp_create_target(struct device *dev,
container_of(dev, struct srp_host, dev);
struct Scsi_Host *target_host;
struct srp_target_port *target;
+ struct srp_rdma_ch *ch;
struct srp_device *srp_dev = host->srp_dev;
struct ib_device *ibdev = srp_dev->dev;
- int ret;
+ int ret, node_idx, node, cpu, i;
+ bool multich = false;
target_host = scsi_host_alloc(&srp_template,
sizeof (struct srp_target_port));
@@ -2988,12 +3162,22 @@ static ssize_t srp_create_target(struct device *dev,
target->tl_retry_count = 7;
target->queue_size = SRP_DEFAULT_QUEUE_SIZE;
+ /*
+ * Avoid that the SCSI host can be removed by srp_remove_target()
+ * before this function returns.
+ */
+ scsi_host_get(target->scsi_host);
+
mutex_lock(&host->add_target_mutex);
ret = srp_parse_options(buf, target);
if (ret)
goto err;
+ ret = scsi_init_shared_tag_map(target_host, target_host->can_queue);
+ if (ret)
+ goto err;
+
target->req_ring_size = target->queue_size - SRP_TSK_MGMT_SQ_SIZE;
if (!srp_conn_unique(target->srp_host, target)) {
@@ -3022,59 +3206,115 @@ static ssize_t srp_create_target(struct device *dev,
INIT_WORK(&target->tl_err_work, srp_tl_err_work);
INIT_WORK(&target->remove_work, srp_remove_work);
spin_lock_init(&target->lock);
- INIT_LIST_HEAD(&target->free_tx);
- ret = srp_alloc_req_data(target);
+ ret = ib_query_gid(ibdev, host->port, 0, &target->sgid);
if (ret)
- goto err_free_mem;
+ goto err;
- ret = ib_query_gid(ibdev, host->port, 0, &target->path.sgid);
- if (ret)
- goto err_free_mem;
+ ret = -ENOMEM;
+ target->ch_count = max_t(unsigned, num_online_nodes(),
+ min(ch_count ? :
+ min(4 * num_online_nodes(),
+ ibdev->num_comp_vectors),
+ num_online_cpus()));
+ target->ch = kcalloc(target->ch_count, sizeof(*target->ch),
+ GFP_KERNEL);
+ if (!target->ch)
+ goto err;
- ret = srp_create_target_ib(target);
- if (ret)
- goto err_free_mem;
+ node_idx = 0;
+ for_each_online_node(node) {
+ const int ch_start = (node_idx * target->ch_count /
+ num_online_nodes());
+ const int ch_end = ((node_idx + 1) * target->ch_count /
+ num_online_nodes());
+ const int cv_start = (node_idx * ibdev->num_comp_vectors /
+ num_online_nodes() + target->comp_vector)
+ % ibdev->num_comp_vectors;
+ const int cv_end = ((node_idx + 1) * ibdev->num_comp_vectors /
+ num_online_nodes() + target->comp_vector)
+ % ibdev->num_comp_vectors;
+ int cpu_idx = 0;
+
+ for_each_online_cpu(cpu) {
+ if (cpu_to_node(cpu) != node)
+ continue;
+ if (ch_start + cpu_idx >= ch_end)
+ continue;
+ ch = &target->ch[ch_start + cpu_idx];
+ ch->target = target;
+ ch->comp_vector = cv_start == cv_end ? cv_start :
+ cv_start + cpu_idx % (cv_end - cv_start);
+ spin_lock_init(&ch->lock);
+ INIT_LIST_HEAD(&ch->free_tx);
+ ret = srp_new_cm_id(ch);
+ if (ret)
+ goto err_disconnect;
- ret = srp_new_cm_id(target);
- if (ret)
- goto err_free_ib;
+ ret = srp_create_ch_ib(ch);
+ if (ret)
+ goto err_disconnect;
- ret = srp_connect_target(target);
- if (ret) {
- shost_printk(KERN_ERR, target->scsi_host,
- PFX "Connection failed\n");
- goto err_cm_id;
+ ret = srp_alloc_req_data(ch);
+ if (ret)
+ goto err_disconnect;
+
+ ret = srp_connect_ch(ch, multich);
+ if (ret) {
+ shost_printk(KERN_ERR, target->scsi_host,
+ PFX "Connection %d/%d failed\n",
+ ch_start + cpu_idx,
+ target->ch_count);
+ if (node_idx == 0 && cpu_idx == 0) {
+ goto err_disconnect;
+ } else {
+ srp_free_ch_ib(target, ch);
+ srp_free_req_data(target, ch);
+ target->ch_count = ch - target->ch;
+ break;
+ }
+ }
+
+ multich = true;
+ cpu_idx++;
+ }
+ node_idx++;
}
+ target->scsi_host->nr_hw_queues = target->ch_count;
+
ret = srp_add_target(host, target);
if (ret)
goto err_disconnect;
- shost_printk(KERN_DEBUG, target->scsi_host, PFX
- "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
- be64_to_cpu(target->id_ext),
- be64_to_cpu(target->ioc_guid),
- be16_to_cpu(target->path.pkey),
- be64_to_cpu(target->service_id),
- target->path.sgid.raw, target->path.dgid.raw);
+ if (target->state != SRP_TARGET_REMOVED) {
+ shost_printk(KERN_DEBUG, target->scsi_host, PFX
+ "new target: id_ext %016llx ioc_guid %016llx pkey %04x service_id %016llx sgid %pI6 dgid %pI6\n",
+ be64_to_cpu(target->id_ext),
+ be64_to_cpu(target->ioc_guid),
+ be16_to_cpu(target->pkey),
+ be64_to_cpu(target->service_id),
+ target->sgid.raw, target->orig_dgid.raw);
+ }
ret = count;
out:
mutex_unlock(&host->add_target_mutex);
+
+ scsi_host_put(target->scsi_host);
+
return ret;
err_disconnect:
srp_disconnect_target(target);
-err_cm_id:
- ib_destroy_cm_id(target->cm_id);
-
-err_free_ib:
- srp_free_target_ib(target);
+ for (i = 0; i < target->ch_count; i++) {
+ ch = &target->ch[i];
+ srp_free_ch_ib(target, ch);
+ srp_free_req_data(target, ch);
+ }
-err_free_mem:
- srp_free_req_data(target);
+ kfree(target->ch);
err:
scsi_host_put(target_host);
diff --git a/drivers/infiniband/ulp/srp/ib_srp.h b/drivers/infiniband/ulp/srp/ib_srp.h
index e46ecb1..a611556 100644
--- a/drivers/infiniband/ulp/srp/ib_srp.h
+++ b/drivers/infiniband/ulp/srp/ib_srp.h
@@ -70,9 +70,12 @@ enum {
LOCAL_INV_WR_ID_MASK = 1,
FAST_REG_WR_ID_MASK = 2,
+
+ SRP_LAST_WR_ID = 0xfffffffcU,
};
enum srp_target_state {
+ SRP_TARGET_SCANNING,
SRP_TARGET_LIVE,
SRP_TARGET_REMOVED,
};
@@ -115,7 +118,6 @@ struct srp_host {
};
struct srp_request {
- struct list_head list;
struct scsi_cmnd *scmnd;
struct srp_iu *cmd;
union {
@@ -126,24 +128,62 @@ struct srp_request {
struct srp_direct_buf *indirect_desc;
dma_addr_t indirect_dma_addr;
short nmdesc;
- short index;
};
-struct srp_target_port {
+/**
+ * struct srp_rdma_ch
+ * @comp_vector: Completion vector used by this RDMA channel.
+ */
+struct srp_rdma_ch {
/* These are RW in the hot path, and commonly used together */
struct list_head free_tx;
- struct list_head free_reqs;
spinlock_t lock;
s32 req_lim;
/* These are read-only in the hot path */
- struct ib_cq *send_cq ____cacheline_aligned_in_smp;
+ struct srp_target_port *target ____cacheline_aligned_in_smp;
+ struct ib_cq *send_cq;
struct ib_cq *recv_cq;
struct ib_qp *qp;
union {
struct ib_fmr_pool *fmr_pool;
struct srp_fr_pool *fr_pool;
};
+
+ /* Everything above this point is used in the hot path of
+ * command processing. Try to keep them packed into cachelines.
+ */
+
+ struct completion done;
+ int status;
+
+ struct ib_sa_path_rec path;
+ struct ib_sa_query *path_query;
+ int path_query_id;
+
+ struct ib_cm_id *cm_id;
+ struct srp_iu **tx_ring;
+ struct srp_iu **rx_ring;
+ struct srp_request *req_ring;
+ int max_ti_iu_len;
+ int comp_vector;
+
+ struct completion tsk_mgmt_done;
+ u8 tsk_mgmt_status;
+};
+
+/**
+ * struct srp_target_port
+ * @comp_vector: Completion vector used by the first RDMA channel created for
+ * this target port.
+ */
+struct srp_target_port {
+ /* read and written in the hot path */
+ spinlock_t lock;
+
+ /* read only in the hot path */
+ struct srp_rdma_ch *ch;
+ u32 ch_count;
u32 lkey;
u32 rkey;
enum srp_target_state state;
@@ -152,10 +192,8 @@ struct srp_target_port {
unsigned int indirect_size;
bool allow_ext_sg;
- /* Everything above this point is used in the hot path of
- * command processing. Try to keep them packed into cachelines.
- */
-
+ /* other member variables */
+ union ib_gid sgid;
__be64 id_ext;
__be64 ioc_guid;
__be64 service_id;
@@ -172,34 +210,19 @@ struct srp_target_port {
int comp_vector;
int tl_retry_count;
- struct ib_sa_path_rec path;
- __be16 orig_dgid[8];
- struct ib_sa_query *path_query;
- int path_query_id;
+ union ib_gid orig_dgid;
+ __be16 pkey;
u32 rq_tmo_jiffies;
bool connected;
- struct ib_cm_id *cm_id;
-
- int max_ti_iu_len;
-
int zero_req_lim;
- struct srp_iu **tx_ring;
- struct srp_iu **rx_ring;
- struct srp_request *req_ring;
-
struct work_struct tl_err_work;
struct work_struct remove_work;
struct list_head list;
- struct completion done;
- int status;
bool qp_in_error;
-
- struct completion tsk_mgmt_done;
- u8 tsk_mgmt_status;
};
struct srp_iu {
diff --git a/drivers/input/keyboard/gpio_keys_polled.c b/drivers/input/keyboard/gpio_keys_polled.c
index 432d363..c9c1c8c 100644
--- a/drivers/input/keyboard/gpio_keys_polled.c
+++ b/drivers/input/keyboard/gpio_keys_polled.c
@@ -23,10 +23,9 @@
#include <linux/ioport.h>
#include <linux/platform_device.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/gpio_keys.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-#include <linux/of_gpio.h>
+#include <linux/property.h>
#define DRV_NAME "gpio-keys-polled"
@@ -51,15 +50,14 @@ static void gpio_keys_polled_check_state(struct input_dev *input,
int state;
if (bdata->can_sleep)
- state = !!gpio_get_value_cansleep(button->gpio);
+ state = !!gpiod_get_value_cansleep(button->gpiod);
else
- state = !!gpio_get_value(button->gpio);
+ state = !!gpiod_get_value(button->gpiod);
if (state != bdata->last_state) {
unsigned int type = button->type ?: EV_KEY;
- input_event(input, type, button->code,
- !!(state ^ button->active_low));
+ input_event(input, type, button->code, state);
input_sync(input);
bdata->count = 0;
bdata->last_state = state;
@@ -102,21 +100,15 @@ static void gpio_keys_polled_close(struct input_polled_dev *dev)
pdata->disable(bdev->dev);
}
-#ifdef CONFIG_OF
static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct device *dev)
{
- struct device_node *node, *pp;
struct gpio_keys_platform_data *pdata;
struct gpio_keys_button *button;
+ struct fwnode_handle *child;
int error;
int nbuttons;
- int i;
-
- node = dev->of_node;
- if (!node)
- return NULL;
- nbuttons = of_get_child_count(node);
+ nbuttons = device_get_child_node_count(dev);
if (nbuttons == 0)
return NULL;
@@ -126,52 +118,44 @@ static struct gpio_keys_platform_data *gpio_keys_polled_get_devtree_pdata(struct
return ERR_PTR(-ENOMEM);
pdata->buttons = (struct gpio_keys_button *)(pdata + 1);
- pdata->nbuttons = nbuttons;
- pdata->rep = !!of_get_property(node, "autorepeat", NULL);
- of_property_read_u32(node, "poll-interval", &pdata->poll_interval);
+ pdata->rep = device_property_present(dev, "autorepeat");
+ device_property_read_u32(dev, "poll-interval", &pdata->poll_interval);
- i = 0;
- for_each_child_of_node(node, pp) {
- int gpio;
- enum of_gpio_flags flags;
+ device_for_each_child_node(dev, child) {
+ struct gpio_desc *desc;
- if (!of_find_property(pp, "gpios", NULL)) {
- pdata->nbuttons--;
- dev_warn(dev, "Found button without gpios\n");
- continue;
- }
-
- gpio = of_get_gpio_flags(pp, 0, &flags);
- if (gpio < 0) {
- error = gpio;
+ desc = devm_get_gpiod_from_child(dev, child);
+ if (IS_ERR(desc)) {
+ error = PTR_ERR(desc);
if (error != -EPROBE_DEFER)
dev_err(dev,
"Failed to get gpio flags, error: %d\n",
error);
+ fwnode_handle_put(child);
return ERR_PTR(error);
}
- button = &pdata->buttons[i++];
-
- button->gpio = gpio;
- button->active_low = flags & OF_GPIO_ACTIVE_LOW;
+ button = &pdata->buttons[pdata->nbuttons++];
+ button->gpiod = desc;
- if (of_property_read_u32(pp, "linux,code", &button->code)) {
- dev_err(dev, "Button without keycode: 0x%x\n",
- button->gpio);
+ if (fwnode_property_read_u32(child, "linux,code", &button->code)) {
+ dev_err(dev, "Button without keycode: %d\n",
+ pdata->nbuttons - 1);
+ fwnode_handle_put(child);
return ERR_PTR(-EINVAL);
}
- button->desc = of_get_property(pp, "label", NULL);
+ fwnode_property_read_string(child, "label", &button->desc);
- if (of_property_read_u32(pp, "linux,input-type", &button->type))
+ if (fwnode_property_read_u32(child, "linux,input-type",
+ &button->type))
button->type = EV_KEY;
- button->wakeup = !!of_get_property(pp, "gpio-key,wakeup", NULL);
+ button->wakeup = fwnode_property_present(child, "gpio-key,wakeup");
- if (of_property_read_u32(pp, "debounce-interval",
- &button->debounce_interval))
+ if (fwnode_property_read_u32(child, "debounce-interval",
+ &button->debounce_interval))
button->debounce_interval = 5;
}
@@ -187,15 +171,6 @@ static const struct of_device_id gpio_keys_polled_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gpio_keys_polled_of_match);
-#else
-
-static inline struct gpio_keys_platform_data *
-gpio_keys_polled_get_devtree_pdata(struct device *dev)
-{
- return NULL;
-}
-#endif
-
static int gpio_keys_polled_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -259,7 +234,6 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
for (i = 0; i < pdata->nbuttons; i++) {
struct gpio_keys_button *button = &pdata->buttons[i];
struct gpio_keys_button_data *bdata = &bdev->data[i];
- unsigned int gpio = button->gpio;
unsigned int type = button->type ?: EV_KEY;
if (button->wakeup) {
@@ -267,15 +241,31 @@ static int gpio_keys_polled_probe(struct platform_device *pdev)
return -EINVAL;
}
- error = devm_gpio_request_one(&pdev->dev, gpio, GPIOF_IN,
- button->desc ? : DRV_NAME);
- if (error) {
- dev_err(dev, "unable to claim gpio %u, err=%d\n",
- gpio, error);
- return error;
+ /*
+ * Legacy GPIO number so request the GPIO here and
+ * convert it to descriptor.
+ */
+ if (!button->gpiod && gpio_is_valid(button->gpio)) {
+ unsigned flags = 0;
+
+ if (button->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
+
+ error = devm_gpio_request_one(&pdev->dev, button->gpio,
+ flags, button->desc ? : DRV_NAME);
+ if (error) {
+ dev_err(dev, "unable to claim gpio %u, err=%d\n",
+ button->gpio, error);
+ return error;
+ }
+
+ button->gpiod = gpio_to_desc(button->gpio);
}
- bdata->can_sleep = gpio_cansleep(gpio);
+ if (IS_ERR(button->gpiod))
+ return PTR_ERR(button->gpiod);
+
+ bdata->can_sleep = gpiod_cansleep(button->gpiod);
bdata->last_state = -1;
bdata->threshold = DIV_ROUND_UP(button->debounce_interval,
pdata->poll_interval);
@@ -308,7 +298,7 @@ static struct platform_driver gpio_keys_polled_driver = {
.driver = {
.name = DRV_NAME,
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(gpio_keys_polled_of_match),
+ .of_match_table = gpio_keys_polled_of_match,
},
};
module_platform_driver(gpio_keys_polled_driver);
diff --git a/drivers/input/keyboard/samsung-keypad.c b/drivers/input/keyboard/samsung-keypad.c
index 5e80fbf..c994e3b 100644
--- a/drivers/input/keyboard/samsung-keypad.c
+++ b/drivers/input/keyboard/samsung-keypad.c
@@ -463,7 +463,7 @@ static int samsung_keypad_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int samsung_keypad_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
diff --git a/drivers/input/touchscreen/cyttsp4_core.c b/drivers/input/touchscreen/cyttsp4_core.c
index a035a39..568a3d3 100644
--- a/drivers/input/touchscreen/cyttsp4_core.c
+++ b/drivers/input/touchscreen/cyttsp4_core.c
@@ -1716,7 +1716,7 @@ static void cyttsp4_free_si_ptrs(struct cyttsp4 *cd)
kfree(si->btn_rec_data);
}
-#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
+#ifdef CONFIG_PM
static int cyttsp4_core_sleep(struct cyttsp4 *cd)
{
int rc;
diff --git a/drivers/iommu/Kconfig b/drivers/iommu/Kconfig
index dd51122..6dbfbc2 100644
--- a/drivers/iommu/Kconfig
+++ b/drivers/iommu/Kconfig
@@ -163,14 +163,14 @@ config TEGRA_IOMMU_GART
hardware included on Tegra SoCs.
config TEGRA_IOMMU_SMMU
- bool "Tegra SMMU IOMMU Support"
- depends on ARCH_TEGRA && TEGRA_AHB
+ bool "NVIDIA Tegra SMMU Support"
+ depends on ARCH_TEGRA
+ depends on TEGRA_AHB
+ depends on TEGRA_MC
select IOMMU_API
help
- Enables support for remapping discontiguous physical memory
- shared with the operating system into contiguous I/O virtual
- space through the SMMU (System Memory Management Unit)
- hardware included on Tegra SoCs.
+ This driver supports the IOMMU hardware (SMMU) found on NVIDIA Tegra
+ SoCs (Tegra30 up to Tegra124).
config EXYNOS_IOMMU
bool "Exynos IOMMU Support"
diff --git a/drivers/iommu/amd_iommu.c b/drivers/iommu/amd_iommu.c
index 505a9ad..2d84c9e 100644
--- a/drivers/iommu/amd_iommu.c
+++ b/drivers/iommu/amd_iommu.c
@@ -3424,6 +3424,7 @@ static const struct iommu_ops amd_iommu_ops = {
.detach_dev = amd_iommu_detach_device,
.map = amd_iommu_map,
.unmap = amd_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = amd_iommu_iova_to_phys,
.pgsize_bitmap = AMD_IOMMU_PGSIZES,
};
diff --git a/drivers/iommu/arm-smmu.c b/drivers/iommu/arm-smmu.c
index 60558f7..e393ae0 100644
--- a/drivers/iommu/arm-smmu.c
+++ b/drivers/iommu/arm-smmu.c
@@ -1652,6 +1652,7 @@ static const struct iommu_ops arm_smmu_ops = {
.detach_dev = arm_smmu_detach_dev,
.map = arm_smmu_map,
.unmap = arm_smmu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = arm_smmu_iova_to_phys,
.add_device = arm_smmu_add_device,
.remove_device = arm_smmu_remove_device,
diff --git a/drivers/iommu/exynos-iommu.c b/drivers/iommu/exynos-iommu.c
index 7423318..28372b8 100644
--- a/drivers/iommu/exynos-iommu.c
+++ b/drivers/iommu/exynos-iommu.c
@@ -1178,6 +1178,7 @@ static const struct iommu_ops exynos_iommu_ops = {
.detach_dev = exynos_iommu_detach_device,
.map = exynos_iommu_map,
.unmap = exynos_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = exynos_iommu_iova_to_phys,
.add_device = exynos_iommu_add_device,
.remove_device = exynos_iommu_remove_device,
diff --git a/drivers/iommu/intel-iommu.c b/drivers/iommu/intel-iommu.c
index a27d6cb..02cd26a 100644
--- a/drivers/iommu/intel-iommu.c
+++ b/drivers/iommu/intel-iommu.c
@@ -4467,6 +4467,7 @@ static const struct iommu_ops intel_iommu_ops = {
.detach_dev = intel_iommu_detach_device,
.map = intel_iommu_map,
.unmap = intel_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = intel_iommu_iova_to_phys,
.add_device = intel_iommu_add_device,
.remove_device = intel_iommu_remove_device,
diff --git a/drivers/iommu/iommu.c b/drivers/iommu/iommu.c
index ed8b048..02e4313 100644
--- a/drivers/iommu/iommu.c
+++ b/drivers/iommu/iommu.c
@@ -818,7 +818,15 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
kfree(nb);
return err;
}
- return bus_for_each_dev(bus, NULL, &cb, add_iommu_group);
+
+ err = bus_for_each_dev(bus, NULL, &cb, add_iommu_group);
+ if (err) {
+ bus_unregister_notifier(bus, nb);
+ kfree(nb);
+ return err;
+ }
+
+ return 0;
}
/**
@@ -836,13 +844,19 @@ static int iommu_bus_init(struct bus_type *bus, const struct iommu_ops *ops)
*/
int bus_set_iommu(struct bus_type *bus, const struct iommu_ops *ops)
{
+ int err;
+
if (bus->iommu_ops != NULL)
return -EBUSY;
bus->iommu_ops = ops;
/* Do IOMMU specific setup for this bus-type */
- return iommu_bus_init(bus, ops);
+ err = iommu_bus_init(bus, ops);
+ if (err)
+ bus->iommu_ops = NULL;
+
+ return err;
}
EXPORT_SYMBOL_GPL(bus_set_iommu);
@@ -1124,6 +1138,38 @@ size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova, size_t size)
}
EXPORT_SYMBOL_GPL(iommu_unmap);
+size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+ struct scatterlist *sg, unsigned int nents, int prot)
+{
+ struct scatterlist *s;
+ size_t mapped = 0;
+ unsigned int i;
+ int ret;
+
+ for_each_sg(sg, s, nents, i) {
+ phys_addr_t phys = page_to_phys(sg_page(s));
+
+ /* We are mapping on page boundarys, so offset must be 0 */
+ if (s->offset)
+ goto out_err;
+
+ ret = iommu_map(domain, iova + mapped, phys, s->length, prot);
+ if (ret)
+ goto out_err;
+
+ mapped += s->length;
+ }
+
+ return mapped;
+
+out_err:
+ /* undo mappings already done */
+ iommu_unmap(domain, iova, mapped);
+
+ return 0;
+
+}
+EXPORT_SYMBOL_GPL(default_iommu_map_sg);
int iommu_domain_window_enable(struct iommu_domain *domain, u32 wnd_nr,
phys_addr_t paddr, u64 size, int prot)
diff --git a/drivers/iommu/ipmmu-vmsa.c b/drivers/iommu/ipmmu-vmsa.c
index 7dab5cb..e509c58 100644
--- a/drivers/iommu/ipmmu-vmsa.c
+++ b/drivers/iommu/ipmmu-vmsa.c
@@ -1127,6 +1127,7 @@ static const struct iommu_ops ipmmu_ops = {
.detach_dev = ipmmu_detach_device,
.map = ipmmu_map,
.unmap = ipmmu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = ipmmu_iova_to_phys,
.add_device = ipmmu_add_device,
.remove_device = ipmmu_remove_device,
diff --git a/drivers/iommu/irq_remapping.c b/drivers/iommu/irq_remapping.c
index 74a1767..2c3f5ad 100644
--- a/drivers/iommu/irq_remapping.c
+++ b/drivers/iommu/irq_remapping.c
@@ -56,19 +56,13 @@ static int do_setup_msi_irqs(struct pci_dev *dev, int nvec)
unsigned int irq;
struct msi_desc *msidesc;
- 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);
irq = irq_alloc_hwirqs(nvec, dev_to_node(&dev->dev));
if (irq == 0)
return -ENOSPC;
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_pow2);
@@ -96,8 +90,6 @@ 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.c b/drivers/iommu/msm_iommu.c
index 6e3dcc28..1c7b78e 100644
--- a/drivers/iommu/msm_iommu.c
+++ b/drivers/iommu/msm_iommu.c
@@ -681,6 +681,7 @@ static const struct iommu_ops msm_iommu_ops = {
.detach_dev = msm_iommu_detach_dev,
.map = msm_iommu_map,
.unmap = msm_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = msm_iommu_iova_to_phys,
.pgsize_bitmap = MSM_IOMMU_PGSIZES,
};
diff --git a/drivers/iommu/omap-iommu.c b/drivers/iommu/omap-iommu.c
index 3627887..18003c04 100644
--- a/drivers/iommu/omap-iommu.c
+++ b/drivers/iommu/omap-iommu.c
@@ -1288,6 +1288,7 @@ static const struct iommu_ops omap_iommu_ops = {
.detach_dev = omap_iommu_detach_dev,
.map = omap_iommu_map,
.unmap = omap_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = omap_iommu_iova_to_phys,
.add_device = omap_iommu_add_device,
.remove_device = omap_iommu_remove_device,
diff --git a/drivers/iommu/shmobile-iommu.c b/drivers/iommu/shmobile-iommu.c
index 1333e6fb..f1b0077 100644
--- a/drivers/iommu/shmobile-iommu.c
+++ b/drivers/iommu/shmobile-iommu.c
@@ -361,6 +361,7 @@ static const struct iommu_ops shmobile_iommu_ops = {
.detach_dev = shmobile_iommu_detach_device,
.map = shmobile_iommu_map,
.unmap = shmobile_iommu_unmap,
+ .map_sg = default_iommu_map_sg,
.iova_to_phys = shmobile_iommu_iova_to_phys,
.add_device = shmobile_iommu_add_device,
.pgsize_bitmap = SZ_1M | SZ_64K | SZ_4K,
diff --git a/drivers/iommu/tegra-smmu.c b/drivers/iommu/tegra-smmu.c
index 3afdf43..6e134c7 100644
--- a/drivers/iommu/tegra-smmu.c
+++ b/drivers/iommu/tegra-smmu.c
@@ -1,1295 +1,732 @@
/*
- * IOMMU API for SMMU in Tegra30
+ * Copyright (C) 2011-2014 NVIDIA CORPORATION. All rights reserved.
*
- * Copyright (c) 2011-2013, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+ * This program is free software; you can 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) "%s(): " fmt, __func__
-
#include <linux/err.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/pagemap.h>
-#include <linux/device.h>
-#include <linux/sched.h>
#include <linux/iommu.h>
-#include <linux/io.h>
+#include <linux/kernel.h>
#include <linux/of.h>
-#include <linux/of_iommu.h>
-#include <linux/debugfs.h>
-#include <linux/seq_file.h>
+#include <linux/of_device.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <soc/tegra/ahb.h>
+#include <soc/tegra/mc.h>
-#include <asm/page.h>
-#include <asm/cacheflush.h>
-
-enum smmu_hwgrp {
- HWGRP_AFI,
- HWGRP_AVPC,
- HWGRP_DC,
- HWGRP_DCB,
- HWGRP_EPP,
- HWGRP_G2,
- HWGRP_HC,
- HWGRP_HDA,
- HWGRP_ISP,
- HWGRP_MPE,
- HWGRP_NV,
- HWGRP_NV2,
- HWGRP_PPCS,
- HWGRP_SATA,
- HWGRP_VDE,
- HWGRP_VI,
-
- HWGRP_COUNT,
-
- HWGRP_END = ~0,
-};
+struct tegra_smmu {
+ void __iomem *regs;
+ struct device *dev;
-#define HWG_AFI (1 << HWGRP_AFI)
-#define HWG_AVPC (1 << HWGRP_AVPC)
-#define HWG_DC (1 << HWGRP_DC)
-#define HWG_DCB (1 << HWGRP_DCB)
-#define HWG_EPP (1 << HWGRP_EPP)
-#define HWG_G2 (1 << HWGRP_G2)
-#define HWG_HC (1 << HWGRP_HC)
-#define HWG_HDA (1 << HWGRP_HDA)
-#define HWG_ISP (1 << HWGRP_ISP)
-#define HWG_MPE (1 << HWGRP_MPE)
-#define HWG_NV (1 << HWGRP_NV)
-#define HWG_NV2 (1 << HWGRP_NV2)
-#define HWG_PPCS (1 << HWGRP_PPCS)
-#define HWG_SATA (1 << HWGRP_SATA)
-#define HWG_VDE (1 << HWGRP_VDE)
-#define HWG_VI (1 << HWGRP_VI)
-
-/* bitmap of the page sizes currently supported */
-#define SMMU_IOMMU_PGSIZES (SZ_4K)
-
-#define SMMU_CONFIG 0x10
-#define SMMU_CONFIG_DISABLE 0
-#define SMMU_CONFIG_ENABLE 1
-
-/* REVISIT: To support multiple MCs */
-enum {
- _MC = 0,
-};
+ struct tegra_mc *mc;
+ const struct tegra_smmu_soc *soc;
-enum {
- _TLB = 0,
- _PTC,
-};
+ unsigned long *asids;
+ struct mutex lock;
-#define SMMU_CACHE_CONFIG_BASE 0x14
-#define __SMMU_CACHE_CONFIG(mc, cache) (SMMU_CACHE_CONFIG_BASE + 4 * cache)
-#define SMMU_CACHE_CONFIG(cache) __SMMU_CACHE_CONFIG(_MC, cache)
-
-#define SMMU_CACHE_CONFIG_STATS_SHIFT 31
-#define SMMU_CACHE_CONFIG_STATS_ENABLE (1 << SMMU_CACHE_CONFIG_STATS_SHIFT)
-#define SMMU_CACHE_CONFIG_STATS_TEST_SHIFT 30
-#define SMMU_CACHE_CONFIG_STATS_TEST (1 << SMMU_CACHE_CONFIG_STATS_TEST_SHIFT)
-
-#define SMMU_TLB_CONFIG_HIT_UNDER_MISS__ENABLE (1 << 29)
-#define SMMU_TLB_CONFIG_ACTIVE_LINES__VALUE 0x10
-#define SMMU_TLB_CONFIG_RESET_VAL 0x20000010
-
-#define SMMU_PTC_CONFIG_CACHE__ENABLE (1 << 29)
-#define SMMU_PTC_CONFIG_INDEX_MAP__PATTERN 0x3f
-#define SMMU_PTC_CONFIG_RESET_VAL 0x2000003f
-
-#define SMMU_PTB_ASID 0x1c
-#define SMMU_PTB_ASID_CURRENT_SHIFT 0
-
-#define SMMU_PTB_DATA 0x20
-#define SMMU_PTB_DATA_RESET_VAL 0
-#define SMMU_PTB_DATA_ASID_NONSECURE_SHIFT 29
-#define SMMU_PTB_DATA_ASID_WRITABLE_SHIFT 30
-#define SMMU_PTB_DATA_ASID_READABLE_SHIFT 31
-
-#define SMMU_TLB_FLUSH 0x30
-#define SMMU_TLB_FLUSH_VA_MATCH_ALL 0
-#define SMMU_TLB_FLUSH_VA_MATCH_SECTION 2
-#define SMMU_TLB_FLUSH_VA_MATCH_GROUP 3
-#define SMMU_TLB_FLUSH_ASID_SHIFT 29
-#define SMMU_TLB_FLUSH_ASID_MATCH_DISABLE 0
-#define SMMU_TLB_FLUSH_ASID_MATCH_ENABLE 1
-#define SMMU_TLB_FLUSH_ASID_MATCH_SHIFT 31
-
-#define SMMU_PTC_FLUSH 0x34
-#define SMMU_PTC_FLUSH_TYPE_ALL 0
-#define SMMU_PTC_FLUSH_TYPE_ADR 1
-#define SMMU_PTC_FLUSH_ADR_SHIFT 4
-
-#define SMMU_ASID_SECURITY 0x38
-
-#define SMMU_STATS_CACHE_COUNT_BASE 0x1f0
-
-#define SMMU_STATS_CACHE_COUNT(mc, cache, hitmiss) \
- (SMMU_STATS_CACHE_COUNT_BASE + 8 * cache + 4 * hitmiss)
-
-#define SMMU_TRANSLATION_ENABLE_0 0x228
-#define SMMU_TRANSLATION_ENABLE_1 0x22c
-#define SMMU_TRANSLATION_ENABLE_2 0x230
-
-#define SMMU_AFI_ASID 0x238 /* PCIE */
-#define SMMU_AVPC_ASID 0x23c /* AVP */
-#define SMMU_DC_ASID 0x240 /* Display controller */
-#define SMMU_DCB_ASID 0x244 /* Display controller B */
-#define SMMU_EPP_ASID 0x248 /* Encoder pre-processor */
-#define SMMU_G2_ASID 0x24c /* 2D engine */
-#define SMMU_HC_ASID 0x250 /* Host1x */
-#define SMMU_HDA_ASID 0x254 /* High-def audio */
-#define SMMU_ISP_ASID 0x258 /* Image signal processor */
-#define SMMU_MPE_ASID 0x264 /* MPEG encoder */
-#define SMMU_NV_ASID 0x268 /* (3D) */
-#define SMMU_NV2_ASID 0x26c /* (3D) */
-#define SMMU_PPCS_ASID 0x270 /* AHB */
-#define SMMU_SATA_ASID 0x278 /* SATA */
-#define SMMU_VDE_ASID 0x27c /* Video decoder */
-#define SMMU_VI_ASID 0x280 /* Video input */
-
-#define SMMU_PDE_NEXT_SHIFT 28
-
-#define SMMU_TLB_FLUSH_VA_SECTION__MASK 0xffc00000
-#define SMMU_TLB_FLUSH_VA_SECTION__SHIFT 12 /* right shift */
-#define SMMU_TLB_FLUSH_VA_GROUP__MASK 0xffffc000
-#define SMMU_TLB_FLUSH_VA_GROUP__SHIFT 12 /* right shift */
-#define SMMU_TLB_FLUSH_VA(iova, which) \
- ((((iova) & SMMU_TLB_FLUSH_VA_##which##__MASK) >> \
- SMMU_TLB_FLUSH_VA_##which##__SHIFT) | \
- SMMU_TLB_FLUSH_VA_MATCH_##which)
-#define SMMU_PTB_ASID_CUR(n) \
- ((n) << SMMU_PTB_ASID_CURRENT_SHIFT)
-#define SMMU_TLB_FLUSH_ASID_MATCH_disable \
- (SMMU_TLB_FLUSH_ASID_MATCH_DISABLE << \
- SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
-#define SMMU_TLB_FLUSH_ASID_MATCH__ENABLE \
- (SMMU_TLB_FLUSH_ASID_MATCH_ENABLE << \
- SMMU_TLB_FLUSH_ASID_MATCH_SHIFT)
-
-#define SMMU_PAGE_SHIFT 12
-#define SMMU_PAGE_SIZE (1 << SMMU_PAGE_SHIFT)
-#define SMMU_PAGE_MASK ((1 << SMMU_PAGE_SHIFT) - 1)
-
-#define SMMU_PDIR_COUNT 1024
-#define SMMU_PDIR_SIZE (sizeof(unsigned long) * SMMU_PDIR_COUNT)
-#define SMMU_PTBL_COUNT 1024
-#define SMMU_PTBL_SIZE (sizeof(unsigned long) * SMMU_PTBL_COUNT)
-#define SMMU_PDIR_SHIFT 12
-#define SMMU_PDE_SHIFT 12
-#define SMMU_PTE_SHIFT 12
-#define SMMU_PFN_MASK 0x000fffff
-
-#define SMMU_ADDR_TO_PFN(addr) ((addr) >> 12)
-#define SMMU_ADDR_TO_PDN(addr) ((addr) >> 22)
-#define SMMU_PDN_TO_ADDR(pdn) ((pdn) << 22)
-
-#define _READABLE (1 << SMMU_PTB_DATA_ASID_READABLE_SHIFT)
-#define _WRITABLE (1 << SMMU_PTB_DATA_ASID_WRITABLE_SHIFT)
-#define _NONSECURE (1 << SMMU_PTB_DATA_ASID_NONSECURE_SHIFT)
-#define _PDE_NEXT (1 << SMMU_PDE_NEXT_SHIFT)
-#define _MASK_ATTR (_READABLE | _WRITABLE | _NONSECURE)
-
-#define _PDIR_ATTR (_READABLE | _WRITABLE | _NONSECURE)
-
-#define _PDE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
-#define _PDE_ATTR_N (_PDE_ATTR | _PDE_NEXT)
-#define _PDE_VACANT(pdn) (((pdn) << 10) | _PDE_ATTR)
-
-#define _PTE_ATTR (_READABLE | _WRITABLE | _NONSECURE)
-#define _PTE_VACANT(addr) (((addr) >> SMMU_PAGE_SHIFT) | _PTE_ATTR)
-
-#define SMMU_MK_PDIR(page, attr) \
- ((page_to_phys(page) >> SMMU_PDIR_SHIFT) | (attr))
-#define SMMU_MK_PDE(page, attr) \
- (unsigned long)((page_to_phys(page) >> SMMU_PDE_SHIFT) | (attr))
-#define SMMU_EX_PTBL_PAGE(pde) \
- pfn_to_page((unsigned long)(pde) & SMMU_PFN_MASK)
-#define SMMU_PFN_TO_PTE(pfn, attr) (unsigned long)((pfn) | (attr))
-
-#define SMMU_ASID_ENABLE(asid) ((asid) | (1 << 31))
-#define SMMU_ASID_DISABLE 0
-#define SMMU_ASID_ASID(n) ((n) & ~SMMU_ASID_ENABLE(0))
-
-#define NUM_SMMU_REG_BANKS 3
-
-#define smmu_client_enable_hwgrp(c, m) smmu_client_set_hwgrp(c, m, 1)
-#define smmu_client_disable_hwgrp(c) smmu_client_set_hwgrp(c, 0, 0)
-#define __smmu_client_enable_hwgrp(c, m) __smmu_client_set_hwgrp(c, m, 1)
-#define __smmu_client_disable_hwgrp(c) __smmu_client_set_hwgrp(c, 0, 0)
-
-#define HWGRP_INIT(client) [HWGRP_##client] = SMMU_##client##_ASID
-
-static const u32 smmu_hwgrp_asid_reg[] = {
- HWGRP_INIT(AFI),
- HWGRP_INIT(AVPC),
- HWGRP_INIT(DC),
- HWGRP_INIT(DCB),
- HWGRP_INIT(EPP),
- HWGRP_INIT(G2),
- HWGRP_INIT(HC),
- HWGRP_INIT(HDA),
- HWGRP_INIT(ISP),
- HWGRP_INIT(MPE),
- HWGRP_INIT(NV),
- HWGRP_INIT(NV2),
- HWGRP_INIT(PPCS),
- HWGRP_INIT(SATA),
- HWGRP_INIT(VDE),
- HWGRP_INIT(VI),
+ struct list_head list;
};
-#define HWGRP_ASID_REG(x) (smmu_hwgrp_asid_reg[x])
-/*
- * Per client for address space
- */
-struct smmu_client {
- struct device *dev;
- struct list_head list;
- struct smmu_as *as;
- u32 hwgrp;
+struct tegra_smmu_as {
+ struct iommu_domain *domain;
+ struct tegra_smmu *smmu;
+ unsigned int use_count;
+ struct page *count;
+ struct page *pd;
+ unsigned id;
+ u32 attr;
};
-/*
- * Per address space
- */
-struct smmu_as {
- struct smmu_device *smmu; /* back pointer to container */
- unsigned int asid;
- spinlock_t lock; /* for pagetable */
- struct page *pdir_page;
- unsigned long pdir_attr;
- unsigned long pde_attr;
- unsigned long pte_attr;
- unsigned int *pte_count;
-
- struct list_head client;
- spinlock_t client_lock; /* for client list */
-};
+static inline void smmu_writel(struct tegra_smmu *smmu, u32 value,
+ unsigned long offset)
+{
+ writel(value, smmu->regs + offset);
+}
-struct smmu_debugfs_info {
- struct smmu_device *smmu;
- int mc;
- int cache;
-};
+static inline u32 smmu_readl(struct tegra_smmu *smmu, unsigned long offset)
+{
+ return readl(smmu->regs + offset);
+}
-/*
- * Per SMMU device - IOMMU device
- */
-struct smmu_device {
- void __iomem *regbase; /* register offset base */
- void __iomem **regs; /* register block start address array */
- void __iomem **rege; /* register block end address array */
- int nregs; /* number of register blocks */
-
- unsigned long iovmm_base; /* remappable base address */
- unsigned long page_count; /* total remappable size */
- spinlock_t lock;
- char *name;
- struct device *dev;
- struct page *avp_vector_page; /* dummy page shared by all AS's */
+#define SMMU_CONFIG 0x010
+#define SMMU_CONFIG_ENABLE (1 << 0)
- /*
- * Register image savers for suspend/resume
- */
- unsigned long translation_enable_0;
- unsigned long translation_enable_1;
- unsigned long translation_enable_2;
- unsigned long asid_security;
+#define SMMU_TLB_CONFIG 0x14
+#define SMMU_TLB_CONFIG_HIT_UNDER_MISS (1 << 29)
+#define SMMU_TLB_CONFIG_ROUND_ROBIN_ARBITRATION (1 << 28)
+#define SMMU_TLB_CONFIG_ACTIVE_LINES(x) ((x) & 0x3f)
- struct dentry *debugfs_root;
- struct smmu_debugfs_info *debugfs_info;
+#define SMMU_PTC_CONFIG 0x18
+#define SMMU_PTC_CONFIG_ENABLE (1 << 29)
+#define SMMU_PTC_CONFIG_REQ_LIMIT(x) (((x) & 0x0f) << 24)
+#define SMMU_PTC_CONFIG_INDEX_MAP(x) ((x) & 0x3f)
- struct device_node *ahb;
+#define SMMU_PTB_ASID 0x01c
+#define SMMU_PTB_ASID_VALUE(x) ((x) & 0x7f)
- int num_as;
- struct smmu_as as[0]; /* Run-time allocated array */
-};
+#define SMMU_PTB_DATA 0x020
+#define SMMU_PTB_DATA_VALUE(page, attr) (page_to_phys(page) >> 12 | (attr))
-static struct smmu_device *smmu_handle; /* unique for a system */
+#define SMMU_MK_PDE(page, attr) (page_to_phys(page) >> SMMU_PTE_SHIFT | (attr))
-/*
- * SMMU register accessors
- */
-static bool inline smmu_valid_reg(struct smmu_device *smmu,
- void __iomem *addr)
-{
- int i;
+#define SMMU_TLB_FLUSH 0x030
+#define SMMU_TLB_FLUSH_VA_MATCH_ALL (0 << 0)
+#define SMMU_TLB_FLUSH_VA_MATCH_SECTION (2 << 0)
+#define SMMU_TLB_FLUSH_VA_MATCH_GROUP (3 << 0)
+#define SMMU_TLB_FLUSH_ASID(x) (((x) & 0x7f) << 24)
+#define SMMU_TLB_FLUSH_VA_SECTION(addr) ((((addr) & 0xffc00000) >> 12) | \
+ SMMU_TLB_FLUSH_VA_MATCH_SECTION)
+#define SMMU_TLB_FLUSH_VA_GROUP(addr) ((((addr) & 0xffffc000) >> 12) | \
+ SMMU_TLB_FLUSH_VA_MATCH_GROUP)
+#define SMMU_TLB_FLUSH_ASID_MATCH (1 << 31)
- for (i = 0; i < smmu->nregs; i++) {
- if (addr < smmu->regs[i])
- break;
- if (addr <= smmu->rege[i])
- return true;
- }
+#define SMMU_PTC_FLUSH 0x034
+#define SMMU_PTC_FLUSH_TYPE_ALL (0 << 0)
+#define SMMU_PTC_FLUSH_TYPE_ADR (1 << 0)
- return false;
-}
+#define SMMU_PTC_FLUSH_HI 0x9b8
+#define SMMU_PTC_FLUSH_HI_MASK 0x3
-static inline u32 smmu_read(struct smmu_device *smmu, size_t offs)
-{
- void __iomem *addr = smmu->regbase + offs;
+/* per-SWGROUP SMMU_*_ASID register */
+#define SMMU_ASID_ENABLE (1 << 31)
+#define SMMU_ASID_MASK 0x7f
+#define SMMU_ASID_VALUE(x) ((x) & SMMU_ASID_MASK)
- BUG_ON(!smmu_valid_reg(smmu, addr));
+/* page table definitions */
+#define SMMU_NUM_PDE 1024
+#define SMMU_NUM_PTE 1024
- return readl(addr);
-}
+#define SMMU_SIZE_PD (SMMU_NUM_PDE * 4)
+#define SMMU_SIZE_PT (SMMU_NUM_PTE * 4)
-static inline void smmu_write(struct smmu_device *smmu, u32 val, size_t offs)
-{
- void __iomem *addr = smmu->regbase + offs;
+#define SMMU_PDE_SHIFT 22
+#define SMMU_PTE_SHIFT 12
- BUG_ON(!smmu_valid_reg(smmu, addr));
+#define SMMU_PFN_MASK 0x000fffff
- writel(val, addr);
-}
+#define SMMU_PD_READABLE (1 << 31)
+#define SMMU_PD_WRITABLE (1 << 30)
+#define SMMU_PD_NONSECURE (1 << 29)
-#define VA_PAGE_TO_PA(va, page) \
- (page_to_phys(page) + ((unsigned long)(va) & ~PAGE_MASK))
+#define SMMU_PDE_READABLE (1 << 31)
+#define SMMU_PDE_WRITABLE (1 << 30)
+#define SMMU_PDE_NONSECURE (1 << 29)
+#define SMMU_PDE_NEXT (1 << 28)
-#define FLUSH_CPU_DCACHE(va, page, size) \
- do { \
- unsigned long _pa_ = VA_PAGE_TO_PA(va, page); \
- __cpuc_flush_dcache_area((void *)(va), (size_t)(size)); \
- outer_flush_range(_pa_, _pa_+(size_t)(size)); \
- } while (0)
+#define SMMU_PTE_READABLE (1 << 31)
+#define SMMU_PTE_WRITABLE (1 << 30)
+#define SMMU_PTE_NONSECURE (1 << 29)
-/*
- * Any interaction between any block on PPSB and a block on APB or AHB
- * must have these read-back barriers to ensure the APB/AHB bus
- * transaction is complete before initiating activity on the PPSB
- * block.
- */
-#define FLUSH_SMMU_REGS(smmu) smmu_read(smmu, SMMU_CONFIG)
+#define SMMU_PDE_ATTR (SMMU_PDE_READABLE | SMMU_PDE_WRITABLE | \
+ SMMU_PDE_NONSECURE)
+#define SMMU_PTE_ATTR (SMMU_PTE_READABLE | SMMU_PTE_WRITABLE | \
+ SMMU_PTE_NONSECURE)
-#define smmu_client_hwgrp(c) (u32)((c)->dev->platform_data)
-
-static int __smmu_client_set_hwgrp(struct smmu_client *c,
- unsigned long map, int on)
+static inline void smmu_flush_ptc(struct tegra_smmu *smmu, struct page *page,
+ unsigned long offset)
{
- int i;
- struct smmu_as *as = c->as;
- u32 val, offs, mask = SMMU_ASID_ENABLE(as->asid);
- struct smmu_device *smmu = as->smmu;
-
- WARN_ON(!on && map);
- if (on && !map)
- return -EINVAL;
- if (!on)
- map = smmu_client_hwgrp(c);
-
- for_each_set_bit(i, &map, HWGRP_COUNT) {
- offs = HWGRP_ASID_REG(i);
- val = smmu_read(smmu, offs);
- if (on) {
- if (WARN_ON(val & mask))
- goto err_hw_busy;
- val |= mask;
- } else {
- WARN_ON((val & mask) == mask);
- val &= ~mask;
+ phys_addr_t phys = page ? page_to_phys(page) : 0;
+ u32 value;
+
+ if (page) {
+ offset &= ~(smmu->mc->soc->atom_size - 1);
+
+ if (smmu->mc->soc->num_address_bits > 32) {
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ value = (phys >> 32) & SMMU_PTC_FLUSH_HI_MASK;
+#else
+ value = 0;
+#endif
+ smmu_writel(smmu, value, SMMU_PTC_FLUSH_HI);
}
- smmu_write(smmu, val, offs);
- }
- FLUSH_SMMU_REGS(smmu);
- c->hwgrp = map;
- return 0;
-err_hw_busy:
- for_each_set_bit(i, &map, HWGRP_COUNT) {
- offs = HWGRP_ASID_REG(i);
- val = smmu_read(smmu, offs);
- val &= ~mask;
- smmu_write(smmu, val, offs);
+ value = (phys + offset) | SMMU_PTC_FLUSH_TYPE_ADR;
+ } else {
+ value = SMMU_PTC_FLUSH_TYPE_ALL;
}
- return -EBUSY;
+
+ smmu_writel(smmu, value, SMMU_PTC_FLUSH);
}
-static int smmu_client_set_hwgrp(struct smmu_client *c, u32 map, int on)
+static inline void smmu_flush_tlb(struct tegra_smmu *smmu)
{
- u32 val;
- unsigned long flags;
- struct smmu_as *as = c->as;
- struct smmu_device *smmu = as->smmu;
-
- spin_lock_irqsave(&smmu->lock, flags);
- val = __smmu_client_set_hwgrp(c, map, on);
- spin_unlock_irqrestore(&smmu->lock, flags);
- return val;
+ smmu_writel(smmu, SMMU_TLB_FLUSH_VA_MATCH_ALL, SMMU_TLB_FLUSH);
}
-/*
- * Flush all TLB entries and all PTC entries
- * Caller must lock smmu
- */
-static void smmu_flush_regs(struct smmu_device *smmu, int enable)
+static inline void smmu_flush_tlb_asid(struct tegra_smmu *smmu,
+ unsigned long asid)
{
- u32 val;
-
- smmu_write(smmu, SMMU_PTC_FLUSH_TYPE_ALL, SMMU_PTC_FLUSH);
- FLUSH_SMMU_REGS(smmu);
- val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
- SMMU_TLB_FLUSH_ASID_MATCH_disable;
- smmu_write(smmu, val, SMMU_TLB_FLUSH);
+ u32 value;
- if (enable)
- smmu_write(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG);
- FLUSH_SMMU_REGS(smmu);
+ value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
+ SMMU_TLB_FLUSH_VA_MATCH_ALL;
+ smmu_writel(smmu, value, SMMU_TLB_FLUSH);
}
-static int smmu_setup_regs(struct smmu_device *smmu)
+static inline void smmu_flush_tlb_section(struct tegra_smmu *smmu,
+ unsigned long asid,
+ unsigned long iova)
{
- int i;
- u32 val;
+ u32 value;
- for (i = 0; i < smmu->num_as; i++) {
- struct smmu_as *as = &smmu->as[i];
- struct smmu_client *c;
-
- smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
- val = as->pdir_page ?
- SMMU_MK_PDIR(as->pdir_page, as->pdir_attr) :
- SMMU_PTB_DATA_RESET_VAL;
- smmu_write(smmu, val, SMMU_PTB_DATA);
-
- list_for_each_entry(c, &as->client, list)
- __smmu_client_set_hwgrp(c, c->hwgrp, 1);
- }
-
- smmu_write(smmu, smmu->translation_enable_0, SMMU_TRANSLATION_ENABLE_0);
- smmu_write(smmu, smmu->translation_enable_1, SMMU_TRANSLATION_ENABLE_1);
- smmu_write(smmu, smmu->translation_enable_2, SMMU_TRANSLATION_ENABLE_2);
- smmu_write(smmu, smmu->asid_security, SMMU_ASID_SECURITY);
- smmu_write(smmu, SMMU_TLB_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_TLB));
- smmu_write(smmu, SMMU_PTC_CONFIG_RESET_VAL, SMMU_CACHE_CONFIG(_PTC));
-
- smmu_flush_regs(smmu, 1);
-
- return tegra_ahb_enable_smmu(smmu->ahb);
+ value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
+ SMMU_TLB_FLUSH_VA_SECTION(iova);
+ smmu_writel(smmu, value, SMMU_TLB_FLUSH);
}
-static void flush_ptc_and_tlb(struct smmu_device *smmu,
- struct smmu_as *as, dma_addr_t iova,
- unsigned long *pte, struct page *page, int is_pde)
+static inline void smmu_flush_tlb_group(struct tegra_smmu *smmu,
+ unsigned long asid,
+ unsigned long iova)
{
- u32 val;
- unsigned long tlb_flush_va = is_pde
- ? SMMU_TLB_FLUSH_VA(iova, SECTION)
- : SMMU_TLB_FLUSH_VA(iova, GROUP);
-
- val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pte, page);
- smmu_write(smmu, val, SMMU_PTC_FLUSH);
- FLUSH_SMMU_REGS(smmu);
- val = tlb_flush_va |
- SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
- (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
- smmu_write(smmu, val, SMMU_TLB_FLUSH);
- FLUSH_SMMU_REGS(smmu);
-}
+ u32 value;
-static void free_ptbl(struct smmu_as *as, dma_addr_t iova)
-{
- unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
- unsigned long *pdir = (unsigned long *)page_address(as->pdir_page);
-
- if (pdir[pdn] != _PDE_VACANT(pdn)) {
- dev_dbg(as->smmu->dev, "pdn: %lx\n", pdn);
-
- ClearPageReserved(SMMU_EX_PTBL_PAGE(pdir[pdn]));
- __free_page(SMMU_EX_PTBL_PAGE(pdir[pdn]));
- pdir[pdn] = _PDE_VACANT(pdn);
- FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
- flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
- as->pdir_page, 1);
- }
+ value = SMMU_TLB_FLUSH_ASID_MATCH | SMMU_TLB_FLUSH_ASID(asid) |
+ SMMU_TLB_FLUSH_VA_GROUP(iova);
+ smmu_writel(smmu, value, SMMU_TLB_FLUSH);
}
-static void free_pdir(struct smmu_as *as)
+static inline void smmu_flush(struct tegra_smmu *smmu)
{
- unsigned addr;
- int count;
- struct device *dev = as->smmu->dev;
-
- if (!as->pdir_page)
- return;
-
- addr = as->smmu->iovmm_base;
- count = as->smmu->page_count;
- while (count-- > 0) {
- free_ptbl(as, addr);
- addr += SMMU_PAGE_SIZE * SMMU_PTBL_COUNT;
- }
- ClearPageReserved(as->pdir_page);
- __free_page(as->pdir_page);
- as->pdir_page = NULL;
- devm_kfree(dev, as->pte_count);
- as->pte_count = NULL;
+ smmu_readl(smmu, SMMU_CONFIG);
}
-/*
- * Maps PTBL for given iova and returns the PTE address
- * Caller must unmap the mapped PTBL returned in *ptbl_page_p
- */
-static unsigned long *locate_pte(struct smmu_as *as,
- dma_addr_t iova, bool allocate,
- struct page **ptbl_page_p,
- unsigned int **count)
+static int tegra_smmu_alloc_asid(struct tegra_smmu *smmu, unsigned int *idp)
{
- unsigned long ptn = SMMU_ADDR_TO_PFN(iova);
- unsigned long pdn = SMMU_ADDR_TO_PDN(iova);
- unsigned long *pdir = page_address(as->pdir_page);
- unsigned long *ptbl;
-
- if (pdir[pdn] != _PDE_VACANT(pdn)) {
- /* Mapped entry table already exists */
- *ptbl_page_p = SMMU_EX_PTBL_PAGE(pdir[pdn]);
- ptbl = page_address(*ptbl_page_p);
- } else if (!allocate) {
- return NULL;
- } else {
- int pn;
- unsigned long addr = SMMU_PDN_TO_ADDR(pdn);
+ unsigned long id;
- /* Vacant - allocate a new page table */
- dev_dbg(as->smmu->dev, "New PTBL pdn: %lx\n", pdn);
+ mutex_lock(&smmu->lock);
- *ptbl_page_p = alloc_page(GFP_ATOMIC);
- if (!*ptbl_page_p) {
- dev_err(as->smmu->dev,
- "failed to allocate smmu_device page table\n");
- return NULL;
- }
- SetPageReserved(*ptbl_page_p);
- ptbl = (unsigned long *)page_address(*ptbl_page_p);
- for (pn = 0; pn < SMMU_PTBL_COUNT;
- pn++, addr += SMMU_PAGE_SIZE) {
- ptbl[pn] = _PTE_VACANT(addr);
- }
- FLUSH_CPU_DCACHE(ptbl, *ptbl_page_p, SMMU_PTBL_SIZE);
- pdir[pdn] = SMMU_MK_PDE(*ptbl_page_p,
- as->pde_attr | _PDE_NEXT);
- FLUSH_CPU_DCACHE(&pdir[pdn], as->pdir_page, sizeof pdir[pdn]);
- flush_ptc_and_tlb(as->smmu, as, iova, &pdir[pdn],
- as->pdir_page, 1);
+ id = find_first_zero_bit(smmu->asids, smmu->soc->num_asids);
+ if (id >= smmu->soc->num_asids) {
+ mutex_unlock(&smmu->lock);
+ return -ENOSPC;
}
- *count = &as->pte_count[pdn];
- return &ptbl[ptn % SMMU_PTBL_COUNT];
+ set_bit(id, smmu->asids);
+ *idp = id;
+
+ mutex_unlock(&smmu->lock);
+ return 0;
}
-#ifdef CONFIG_SMMU_SIG_DEBUG
-static void put_signature(struct smmu_as *as,
- dma_addr_t iova, unsigned long pfn)
+static void tegra_smmu_free_asid(struct tegra_smmu *smmu, unsigned int id)
{
- struct page *page;
- unsigned long *vaddr;
-
- page = pfn_to_page(pfn);
- vaddr = page_address(page);
- if (!vaddr)
- return;
-
- vaddr[0] = iova;
- vaddr[1] = pfn << PAGE_SHIFT;
- FLUSH_CPU_DCACHE(vaddr, page, sizeof(vaddr[0]) * 2);
+ mutex_lock(&smmu->lock);
+ clear_bit(id, smmu->asids);
+ mutex_unlock(&smmu->lock);
}
-#else
-static inline void put_signature(struct smmu_as *as,
- unsigned long addr, unsigned long pfn)
+
+static bool tegra_smmu_capable(enum iommu_cap cap)
{
+ return false;
}
-#endif
-/*
- * Caller must not hold as->lock
- */
-static int alloc_pdir(struct smmu_as *as)
+static int tegra_smmu_domain_init(struct iommu_domain *domain)
{
- unsigned long *pdir, flags;
- int pdn, err = 0;
- u32 val;
- struct smmu_device *smmu = as->smmu;
- struct page *page;
- unsigned int *cnt;
+ struct tegra_smmu_as *as;
+ unsigned int i;
+ uint32_t *pd;
- /*
- * do the allocation, then grab as->lock
- */
- cnt = devm_kzalloc(smmu->dev,
- sizeof(cnt[0]) * SMMU_PDIR_COUNT,
- GFP_KERNEL);
- page = alloc_page(GFP_KERNEL | __GFP_DMA);
+ as = kzalloc(sizeof(*as), GFP_KERNEL);
+ if (!as)
+ return -ENOMEM;
- spin_lock_irqsave(&as->lock, flags);
+ as->attr = SMMU_PD_READABLE | SMMU_PD_WRITABLE | SMMU_PD_NONSECURE;
+ as->domain = domain;
- if (as->pdir_page) {
- /* We raced, free the redundant */
- err = -EAGAIN;
- goto err_out;
+ as->pd = alloc_page(GFP_KERNEL | __GFP_DMA);
+ if (!as->pd) {
+ kfree(as);
+ return -ENOMEM;
}
- if (!page || !cnt) {
- dev_err(smmu->dev, "failed to allocate at %s\n", __func__);
- err = -ENOMEM;
- goto err_out;
+ as->count = alloc_page(GFP_KERNEL);
+ if (!as->count) {
+ __free_page(as->pd);
+ kfree(as);
+ return -ENOMEM;
}
- as->pdir_page = page;
- as->pte_count = cnt;
+ /* clear PDEs */
+ pd = page_address(as->pd);
+ SetPageReserved(as->pd);
- SetPageReserved(as->pdir_page);
- pdir = page_address(as->pdir_page);
+ for (i = 0; i < SMMU_NUM_PDE; i++)
+ pd[i] = 0;
- for (pdn = 0; pdn < SMMU_PDIR_COUNT; pdn++)
- pdir[pdn] = _PDE_VACANT(pdn);
- FLUSH_CPU_DCACHE(pdir, as->pdir_page, SMMU_PDIR_SIZE);
- val = SMMU_PTC_FLUSH_TYPE_ADR | VA_PAGE_TO_PA(pdir, as->pdir_page);
- smmu_write(smmu, val, SMMU_PTC_FLUSH);
- FLUSH_SMMU_REGS(as->smmu);
- val = SMMU_TLB_FLUSH_VA_MATCH_ALL |
- SMMU_TLB_FLUSH_ASID_MATCH__ENABLE |
- (as->asid << SMMU_TLB_FLUSH_ASID_SHIFT);
- smmu_write(smmu, val, SMMU_TLB_FLUSH);
- FLUSH_SMMU_REGS(as->smmu);
+ /* clear PDE usage counters */
+ pd = page_address(as->count);
+ SetPageReserved(as->count);
- spin_unlock_irqrestore(&as->lock, flags);
-
- return 0;
+ for (i = 0; i < SMMU_NUM_PDE; i++)
+ pd[i] = 0;
-err_out:
- spin_unlock_irqrestore(&as->lock, flags);
+ domain->priv = as;
- devm_kfree(smmu->dev, cnt);
- if (page)
- __free_page(page);
- return err;
+ return 0;
}
-static void __smmu_iommu_unmap(struct smmu_as *as, dma_addr_t iova)
+static void tegra_smmu_domain_destroy(struct iommu_domain *domain)
{
- unsigned long *pte;
- struct page *page;
- unsigned int *count;
+ struct tegra_smmu_as *as = domain->priv;
- pte = locate_pte(as, iova, false, &page, &count);
- if (WARN_ON(!pte))
- return;
+ /* TODO: free page directory and page tables */
+ ClearPageReserved(as->pd);
- if (WARN_ON(*pte == _PTE_VACANT(iova)))
- return;
-
- *pte = _PTE_VACANT(iova);
- FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
- flush_ptc_and_tlb(as->smmu, as, iova, pte, page, 0);
- if (!--(*count))
- free_ptbl(as, iova);
+ kfree(as);
}
-static void __smmu_iommu_map_pfn(struct smmu_as *as, dma_addr_t iova,
- unsigned long pfn)
+static const struct tegra_smmu_swgroup *
+tegra_smmu_find_swgroup(struct tegra_smmu *smmu, unsigned int swgroup)
{
- struct smmu_device *smmu = as->smmu;
- unsigned long *pte;
- unsigned int *count;
- struct page *page;
+ const struct tegra_smmu_swgroup *group = NULL;
+ unsigned int i;
- pte = locate_pte(as, iova, true, &page, &count);
- if (WARN_ON(!pte))
- return;
+ for (i = 0; i < smmu->soc->num_swgroups; i++) {
+ if (smmu->soc->swgroups[i].swgroup == swgroup) {
+ group = &smmu->soc->swgroups[i];
+ break;
+ }
+ }
- if (*pte == _PTE_VACANT(iova))
- (*count)++;
- *pte = SMMU_PFN_TO_PTE(pfn, as->pte_attr);
- if (unlikely((*pte == _PTE_VACANT(iova))))
- (*count)--;
- FLUSH_CPU_DCACHE(pte, page, sizeof(*pte));
- flush_ptc_and_tlb(smmu, as, iova, pte, page, 0);
- put_signature(as, iova, pfn);
+ return group;
}
-static int smmu_iommu_map(struct iommu_domain *domain, unsigned long iova,
- phys_addr_t pa, size_t bytes, int prot)
+static void tegra_smmu_enable(struct tegra_smmu *smmu, unsigned int swgroup,
+ unsigned int asid)
{
- struct smmu_as *as = domain->priv;
- unsigned long pfn = __phys_to_pfn(pa);
- unsigned long flags;
+ const struct tegra_smmu_swgroup *group;
+ unsigned int i;
+ u32 value;
- dev_dbg(as->smmu->dev, "[%d] %08lx:%pa\n", as->asid, iova, &pa);
+ for (i = 0; i < smmu->soc->num_clients; i++) {
+ const struct tegra_mc_client *client = &smmu->soc->clients[i];
- if (!pfn_valid(pfn))
- return -ENOMEM;
-
- spin_lock_irqsave(&as->lock, flags);
- __smmu_iommu_map_pfn(as, iova, pfn);
- spin_unlock_irqrestore(&as->lock, flags);
- return 0;
-}
-
-static size_t smmu_iommu_unmap(struct iommu_domain *domain, unsigned long iova,
- size_t bytes)
-{
- struct smmu_as *as = domain->priv;
- unsigned long flags;
+ if (client->swgroup != swgroup)
+ continue;
- dev_dbg(as->smmu->dev, "[%d] %08lx\n", as->asid, iova);
+ value = smmu_readl(smmu, client->smmu.reg);
+ value |= BIT(client->smmu.bit);
+ smmu_writel(smmu, value, client->smmu.reg);
+ }
- spin_lock_irqsave(&as->lock, flags);
- __smmu_iommu_unmap(as, iova);
- spin_unlock_irqrestore(&as->lock, flags);
- return SMMU_PAGE_SIZE;
+ group = tegra_smmu_find_swgroup(smmu, swgroup);
+ if (group) {
+ value = smmu_readl(smmu, group->reg);
+ value &= ~SMMU_ASID_MASK;
+ value |= SMMU_ASID_VALUE(asid);
+ value |= SMMU_ASID_ENABLE;
+ smmu_writel(smmu, value, group->reg);
+ }
}
-static phys_addr_t smmu_iommu_iova_to_phys(struct iommu_domain *domain,
- dma_addr_t iova)
+static void tegra_smmu_disable(struct tegra_smmu *smmu, unsigned int swgroup,
+ unsigned int asid)
{
- struct smmu_as *as = domain->priv;
- unsigned long *pte;
- unsigned int *count;
- struct page *page;
- unsigned long pfn;
- unsigned long flags;
+ const struct tegra_smmu_swgroup *group;
+ unsigned int i;
+ u32 value;
- spin_lock_irqsave(&as->lock, flags);
+ group = tegra_smmu_find_swgroup(smmu, swgroup);
+ if (group) {
+ value = smmu_readl(smmu, group->reg);
+ value &= ~SMMU_ASID_MASK;
+ value |= SMMU_ASID_VALUE(asid);
+ value &= ~SMMU_ASID_ENABLE;
+ smmu_writel(smmu, value, group->reg);
+ }
- pte = locate_pte(as, iova, true, &page, &count);
- pfn = *pte & SMMU_PFN_MASK;
- WARN_ON(!pfn_valid(pfn));
- dev_dbg(as->smmu->dev,
- "iova:%08llx pfn:%08lx asid:%d\n", (unsigned long long)iova,
- pfn, as->asid);
+ for (i = 0; i < smmu->soc->num_clients; i++) {
+ const struct tegra_mc_client *client = &smmu->soc->clients[i];
- spin_unlock_irqrestore(&as->lock, flags);
- return PFN_PHYS(pfn);
-}
+ if (client->swgroup != swgroup)
+ continue;
-static bool smmu_iommu_capable(enum iommu_cap cap)
-{
- return false;
+ value = smmu_readl(smmu, client->smmu.reg);
+ value &= ~BIT(client->smmu.bit);
+ smmu_writel(smmu, value, client->smmu.reg);
+ }
}
-static int smmu_iommu_attach_dev(struct iommu_domain *domain,
- struct device *dev)
+static int tegra_smmu_as_prepare(struct tegra_smmu *smmu,
+ struct tegra_smmu_as *as)
{
- struct smmu_as *as = domain->priv;
- struct smmu_device *smmu = as->smmu;
- struct smmu_client *client, *c;
- u32 map;
+ u32 value;
int err;
- client = devm_kzalloc(smmu->dev, sizeof(*c), GFP_KERNEL);
- if (!client)
- return -ENOMEM;
- client->dev = dev;
- client->as = as;
- map = (unsigned long)dev->platform_data;
- if (!map)
- return -EINVAL;
-
- err = smmu_client_enable_hwgrp(client, map);
- if (err)
- goto err_hwgrp;
-
- spin_lock(&as->client_lock);
- list_for_each_entry(c, &as->client, list) {
- if (c->dev == dev) {
- dev_err(smmu->dev,
- "%s is already attached\n", dev_name(c->dev));
- err = -EINVAL;
- goto err_client;
- }
+ if (as->use_count > 0) {
+ as->use_count++;
+ return 0;
}
- list_add(&client->list, &as->client);
- spin_unlock(&as->client_lock);
- /*
- * Reserve "page zero" for AVP vectors using a common dummy
- * page.
- */
- if (map & HWG_AVPC) {
- struct page *page;
+ err = tegra_smmu_alloc_asid(smmu, &as->id);
+ if (err < 0)
+ return err;
- page = as->smmu->avp_vector_page;
- __smmu_iommu_map_pfn(as, 0, page_to_pfn(page));
+ smmu->soc->ops->flush_dcache(as->pd, 0, SMMU_SIZE_PD);
+ smmu_flush_ptc(smmu, as->pd, 0);
+ smmu_flush_tlb_asid(smmu, as->id);
- pr_info("Reserve \"page zero\" for AVP vectors using a common dummy\n");
- }
+ smmu_writel(smmu, as->id & 0x7f, SMMU_PTB_ASID);
+ value = SMMU_PTB_DATA_VALUE(as->pd, as->attr);
+ smmu_writel(smmu, value, SMMU_PTB_DATA);
+ smmu_flush(smmu);
- dev_dbg(smmu->dev, "%s is attached\n", dev_name(dev));
- return 0;
+ as->smmu = smmu;
+ as->use_count++;
-err_client:
- smmu_client_disable_hwgrp(client);
- spin_unlock(&as->client_lock);
-err_hwgrp:
- devm_kfree(smmu->dev, client);
- return err;
+ return 0;
}
-static void smmu_iommu_detach_dev(struct iommu_domain *domain,
- struct device *dev)
+static void tegra_smmu_as_unprepare(struct tegra_smmu *smmu,
+ struct tegra_smmu_as *as)
{
- struct smmu_as *as = domain->priv;
- struct smmu_device *smmu = as->smmu;
- struct smmu_client *c;
-
- spin_lock(&as->client_lock);
-
- list_for_each_entry(c, &as->client, list) {
- if (c->dev == dev) {
- smmu_client_disable_hwgrp(c);
- list_del(&c->list);
- devm_kfree(smmu->dev, c);
- c->as = NULL;
- dev_dbg(smmu->dev,
- "%s is detached\n", dev_name(c->dev));
- goto out;
- }
- }
- dev_err(smmu->dev, "Couldn't find %s\n", dev_name(dev));
-out:
- spin_unlock(&as->client_lock);
+ if (--as->use_count > 0)
+ return;
+
+ tegra_smmu_free_asid(smmu, as->id);
+ as->smmu = NULL;
}
-static int smmu_iommu_domain_init(struct iommu_domain *domain)
+static int tegra_smmu_attach_dev(struct iommu_domain *domain,
+ struct device *dev)
{
- int i, err = -EAGAIN;
- unsigned long flags;
- struct smmu_as *as;
- struct smmu_device *smmu = smmu_handle;
+ struct tegra_smmu *smmu = dev->archdata.iommu;
+ struct tegra_smmu_as *as = domain->priv;
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args args;
+ unsigned int index = 0;
+ int err = 0;
- /* Look for a free AS with lock held */
- for (i = 0; i < smmu->num_as; i++) {
- as = &smmu->as[i];
+ while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index,
+ &args)) {
+ unsigned int swgroup = args.args[0];
- if (as->pdir_page)
+ if (args.np != smmu->dev->of_node) {
+ of_node_put(args.np);
continue;
+ }
- err = alloc_pdir(as);
- if (!err)
- goto found;
+ of_node_put(args.np);
- if (err != -EAGAIN)
- break;
+ err = tegra_smmu_as_prepare(smmu, as);
+ if (err < 0)
+ return err;
+
+ tegra_smmu_enable(smmu, swgroup, as->id);
+ index++;
}
- if (i == smmu->num_as)
- dev_err(smmu->dev, "no free AS\n");
- return err;
-found:
- spin_lock_irqsave(&smmu->lock, flags);
+ if (index == 0)
+ return -ENODEV;
- /* Update PDIR register */
- smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
- smmu_write(smmu,
- SMMU_MK_PDIR(as->pdir_page, as->pdir_attr), SMMU_PTB_DATA);
- FLUSH_SMMU_REGS(smmu);
+ return 0;
+}
- spin_unlock_irqrestore(&smmu->lock, flags);
+static void tegra_smmu_detach_dev(struct iommu_domain *domain, struct device *dev)
+{
+ struct tegra_smmu_as *as = domain->priv;
+ struct device_node *np = dev->of_node;
+ struct tegra_smmu *smmu = as->smmu;
+ struct of_phandle_args args;
+ unsigned int index = 0;
- domain->priv = as;
+ while (!of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index,
+ &args)) {
+ unsigned int swgroup = args.args[0];
- domain->geometry.aperture_start = smmu->iovmm_base;
- domain->geometry.aperture_end = smmu->iovmm_base +
- smmu->page_count * SMMU_PAGE_SIZE - 1;
- domain->geometry.force_aperture = true;
+ if (args.np != smmu->dev->of_node) {
+ of_node_put(args.np);
+ continue;
+ }
- dev_dbg(smmu->dev, "smmu_as@%p\n", as);
+ of_node_put(args.np);
- return 0;
+ tegra_smmu_disable(smmu, swgroup, as->id);
+ tegra_smmu_as_unprepare(smmu, as);
+ index++;
+ }
}
-static void smmu_iommu_domain_destroy(struct iommu_domain *domain)
+static u32 *as_get_pte(struct tegra_smmu_as *as, dma_addr_t iova,
+ struct page **pagep)
{
- struct smmu_as *as = domain->priv;
- struct smmu_device *smmu = as->smmu;
- unsigned long flags;
+ u32 *pd = page_address(as->pd), *pt, *count;
+ u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
+ u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff;
+ struct tegra_smmu *smmu = as->smmu;
+ struct page *page;
+ unsigned int i;
+
+ if (pd[pde] == 0) {
+ page = alloc_page(GFP_KERNEL | __GFP_DMA);
+ if (!page)
+ return NULL;
- spin_lock_irqsave(&as->lock, flags);
+ pt = page_address(page);
+ SetPageReserved(page);
- if (as->pdir_page) {
- spin_lock(&smmu->lock);
- smmu_write(smmu, SMMU_PTB_ASID_CUR(as->asid), SMMU_PTB_ASID);
- smmu_write(smmu, SMMU_PTB_DATA_RESET_VAL, SMMU_PTB_DATA);
- FLUSH_SMMU_REGS(smmu);
- spin_unlock(&smmu->lock);
+ for (i = 0; i < SMMU_NUM_PTE; i++)
+ pt[i] = 0;
- free_pdir(as);
- }
+ smmu->soc->ops->flush_dcache(page, 0, SMMU_SIZE_PT);
- if (!list_empty(&as->client)) {
- struct smmu_client *c;
+ pd[pde] = SMMU_MK_PDE(page, SMMU_PDE_ATTR | SMMU_PDE_NEXT);
- list_for_each_entry(c, &as->client, list)
- smmu_iommu_detach_dev(domain, c->dev);
+ smmu->soc->ops->flush_dcache(as->pd, pde << 2, 4);
+ smmu_flush_ptc(smmu, as->pd, pde << 2);
+ smmu_flush_tlb_section(smmu, as->id, iova);
+ smmu_flush(smmu);
+ } else {
+ page = pfn_to_page(pd[pde] & SMMU_PFN_MASK);
+ pt = page_address(page);
}
- spin_unlock_irqrestore(&as->lock, flags);
+ *pagep = page;
- domain->priv = NULL;
- dev_dbg(smmu->dev, "smmu_as@%p\n", as);
-}
+ /* Keep track of entries in this page table. */
+ count = page_address(as->count);
+ if (pt[pte] == 0)
+ count[pde]++;
-static const struct iommu_ops smmu_iommu_ops = {
- .capable = smmu_iommu_capable,
- .domain_init = smmu_iommu_domain_init,
- .domain_destroy = smmu_iommu_domain_destroy,
- .attach_dev = smmu_iommu_attach_dev,
- .detach_dev = smmu_iommu_detach_dev,
- .map = smmu_iommu_map,
- .unmap = smmu_iommu_unmap,
- .iova_to_phys = smmu_iommu_iova_to_phys,
- .pgsize_bitmap = SMMU_IOMMU_PGSIZES,
-};
-
-/* Should be in the order of enum */
-static const char * const smmu_debugfs_mc[] = { "mc", };
-static const char * const smmu_debugfs_cache[] = { "tlb", "ptc", };
+ return &pt[pte];
+}
-static ssize_t smmu_debugfs_stats_write(struct file *file,
- const char __user *buffer,
- size_t count, loff_t *pos)
+static void as_put_pte(struct tegra_smmu_as *as, dma_addr_t iova)
{
- struct smmu_debugfs_info *info;
- struct smmu_device *smmu;
- int i;
- enum {
- _OFF = 0,
- _ON,
- _RESET,
- };
- const char * const command[] = {
- [_OFF] = "off",
- [_ON] = "on",
- [_RESET] = "reset",
- };
- char str[] = "reset";
- u32 val;
- size_t offs;
+ u32 pde = (iova >> SMMU_PDE_SHIFT) & 0x3ff;
+ u32 pte = (iova >> SMMU_PTE_SHIFT) & 0x3ff;
+ u32 *count = page_address(as->count);
+ u32 *pd = page_address(as->pd), *pt;
+ struct page *page;
- count = min_t(size_t, count, sizeof(str));
- if (copy_from_user(str, buffer, count))
- return -EINVAL;
+ page = pfn_to_page(pd[pde] & SMMU_PFN_MASK);
+ pt = page_address(page);
- for (i = 0; i < ARRAY_SIZE(command); i++)
- if (strncmp(str, command[i],
- strlen(command[i])) == 0)
- break;
+ /*
+ * When no entries in this page table are used anymore, return the
+ * memory page to the system.
+ */
+ if (pt[pte] != 0) {
+ if (--count[pde] == 0) {
+ ClearPageReserved(page);
+ __free_page(page);
+ pd[pde] = 0;
+ }
- if (i == ARRAY_SIZE(command))
- return -EINVAL;
-
- info = file_inode(file)->i_private;
- smmu = info->smmu;
-
- offs = SMMU_CACHE_CONFIG(info->cache);
- val = smmu_read(smmu, offs);
- switch (i) {
- case _OFF:
- val &= ~SMMU_CACHE_CONFIG_STATS_ENABLE;
- val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
- smmu_write(smmu, val, offs);
- break;
- case _ON:
- val |= SMMU_CACHE_CONFIG_STATS_ENABLE;
- val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
- smmu_write(smmu, val, offs);
- break;
- case _RESET:
- val |= SMMU_CACHE_CONFIG_STATS_TEST;
- smmu_write(smmu, val, offs);
- val &= ~SMMU_CACHE_CONFIG_STATS_TEST;
- smmu_write(smmu, val, offs);
- break;
- default:
- BUG();
- break;
+ pt[pte] = 0;
}
-
- dev_dbg(smmu->dev, "%s() %08x, %08x @%08x\n", __func__,
- val, smmu_read(smmu, offs), offs);
-
- return count;
}
-static int smmu_debugfs_stats_show(struct seq_file *s, void *v)
+static int tegra_smmu_map(struct iommu_domain *domain, unsigned long iova,
+ phys_addr_t paddr, size_t size, int prot)
{
- struct smmu_debugfs_info *info = s->private;
- struct smmu_device *smmu = info->smmu;
- int i;
- const char * const stats[] = { "hit", "miss", };
+ struct tegra_smmu_as *as = domain->priv;
+ struct tegra_smmu *smmu = as->smmu;
+ unsigned long offset;
+ struct page *page;
+ u32 *pte;
+ pte = as_get_pte(as, iova, &page);
+ if (!pte)
+ return -ENOMEM;
- for (i = 0; i < ARRAY_SIZE(stats); i++) {
- u32 val;
- size_t offs;
+ *pte = __phys_to_pfn(paddr) | SMMU_PTE_ATTR;
+ offset = offset_in_page(pte);
- offs = SMMU_STATS_CACHE_COUNT(info->mc, info->cache, i);
- val = smmu_read(smmu, offs);
- seq_printf(s, "%s:%08x ", stats[i], val);
+ smmu->soc->ops->flush_dcache(page, offset, 4);
+ smmu_flush_ptc(smmu, page, offset);
+ smmu_flush_tlb_group(smmu, as->id, iova);
+ smmu_flush(smmu);
- dev_dbg(smmu->dev, "%s() %s %08x @%08x\n", __func__,
- stats[i], val, offs);
- }
- seq_printf(s, "\n");
return 0;
}
-static int smmu_debugfs_stats_open(struct inode *inode, struct file *file)
+static size_t tegra_smmu_unmap(struct iommu_domain *domain, unsigned long iova,
+ size_t size)
{
- return single_open(file, smmu_debugfs_stats_show, inode->i_private);
-}
+ struct tegra_smmu_as *as = domain->priv;
+ struct tegra_smmu *smmu = as->smmu;
+ unsigned long offset;
+ struct page *page;
+ u32 *pte;
-static const struct file_operations smmu_debugfs_stats_fops = {
- .open = smmu_debugfs_stats_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = smmu_debugfs_stats_write,
-};
+ pte = as_get_pte(as, iova, &page);
+ if (!pte)
+ return 0;
-static void smmu_debugfs_delete(struct smmu_device *smmu)
-{
- debugfs_remove_recursive(smmu->debugfs_root);
- kfree(smmu->debugfs_info);
+ offset = offset_in_page(pte);
+ as_put_pte(as, iova);
+
+ smmu->soc->ops->flush_dcache(page, offset, 4);
+ smmu_flush_ptc(smmu, page, offset);
+ smmu_flush_tlb_group(smmu, as->id, iova);
+ smmu_flush(smmu);
+
+ return size;
}
-static void smmu_debugfs_create(struct smmu_device *smmu)
+static phys_addr_t tegra_smmu_iova_to_phys(struct iommu_domain *domain,
+ dma_addr_t iova)
{
- int i;
- size_t bytes;
- struct dentry *root;
-
- bytes = ARRAY_SIZE(smmu_debugfs_mc) * ARRAY_SIZE(smmu_debugfs_cache) *
- sizeof(*smmu->debugfs_info);
- smmu->debugfs_info = kmalloc(bytes, GFP_KERNEL);
- if (!smmu->debugfs_info)
- return;
-
- root = debugfs_create_dir(dev_name(smmu->dev), NULL);
- if (!root)
- goto err_out;
- smmu->debugfs_root = root;
-
- for (i = 0; i < ARRAY_SIZE(smmu_debugfs_mc); i++) {
- int j;
- struct dentry *mc;
-
- mc = debugfs_create_dir(smmu_debugfs_mc[i], root);
- if (!mc)
- goto err_out;
-
- for (j = 0; j < ARRAY_SIZE(smmu_debugfs_cache); j++) {
- struct dentry *cache;
- struct smmu_debugfs_info *info;
-
- info = smmu->debugfs_info;
- info += i * ARRAY_SIZE(smmu_debugfs_mc) + j;
- info->smmu = smmu;
- info->mc = i;
- info->cache = j;
-
- cache = debugfs_create_file(smmu_debugfs_cache[j],
- S_IWUGO | S_IRUGO, mc,
- (void *)info,
- &smmu_debugfs_stats_fops);
- if (!cache)
- goto err_out;
- }
- }
+ struct tegra_smmu_as *as = domain->priv;
+ struct page *page;
+ unsigned long pfn;
+ u32 *pte;
- return;
+ pte = as_get_pte(as, iova, &page);
+ pfn = *pte & SMMU_PFN_MASK;
-err_out:
- smmu_debugfs_delete(smmu);
+ return PFN_PHYS(pfn);
}
-static int tegra_smmu_suspend(struct device *dev)
+static struct tegra_smmu *tegra_smmu_find(struct device_node *np)
{
- struct smmu_device *smmu = dev_get_drvdata(dev);
+ struct platform_device *pdev;
+ struct tegra_mc *mc;
- smmu->translation_enable_0 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_0);
- smmu->translation_enable_1 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_1);
- smmu->translation_enable_2 = smmu_read(smmu, SMMU_TRANSLATION_ENABLE_2);
- smmu->asid_security = smmu_read(smmu, SMMU_ASID_SECURITY);
- return 0;
+ pdev = of_find_device_by_node(np);
+ if (!pdev)
+ return NULL;
+
+ mc = platform_get_drvdata(pdev);
+ if (!mc)
+ return NULL;
+
+ return mc->smmu;
}
-static int tegra_smmu_resume(struct device *dev)
+static int tegra_smmu_add_device(struct device *dev)
{
- struct smmu_device *smmu = dev_get_drvdata(dev);
- unsigned long flags;
- int err;
+ struct device_node *np = dev->of_node;
+ struct of_phandle_args args;
+ unsigned int index = 0;
- spin_lock_irqsave(&smmu->lock, flags);
- err = smmu_setup_regs(smmu);
- spin_unlock_irqrestore(&smmu->lock, flags);
- return err;
+ while (of_parse_phandle_with_args(np, "iommus", "#iommu-cells", index,
+ &args) == 0) {
+ struct tegra_smmu *smmu;
+
+ smmu = tegra_smmu_find(args.np);
+ if (smmu) {
+ /*
+ * Only a single IOMMU master interface is currently
+ * supported by the Linux kernel, so abort after the
+ * first match.
+ */
+ dev->archdata.iommu = smmu;
+ break;
+ }
+
+ index++;
+ }
+
+ return 0;
}
-static int tegra_smmu_probe(struct platform_device *pdev)
+static void tegra_smmu_remove_device(struct device *dev)
{
- struct smmu_device *smmu;
- struct device *dev = &pdev->dev;
- int i, asids, err = 0;
- dma_addr_t uninitialized_var(base);
- size_t bytes, uninitialized_var(size);
+ dev->archdata.iommu = NULL;
+}
- if (smmu_handle)
- return -EIO;
+static const struct iommu_ops tegra_smmu_ops = {
+ .capable = tegra_smmu_capable,
+ .domain_init = tegra_smmu_domain_init,
+ .domain_destroy = tegra_smmu_domain_destroy,
+ .attach_dev = tegra_smmu_attach_dev,
+ .detach_dev = tegra_smmu_detach_dev,
+ .add_device = tegra_smmu_add_device,
+ .remove_device = tegra_smmu_remove_device,
+ .map = tegra_smmu_map,
+ .unmap = tegra_smmu_unmap,
+ .map_sg = default_iommu_map_sg,
+ .iova_to_phys = tegra_smmu_iova_to_phys,
- BUILD_BUG_ON(PAGE_SHIFT != SMMU_PAGE_SHIFT);
+ .pgsize_bitmap = SZ_4K,
+};
- if (of_property_read_u32(dev->of_node, "nvidia,#asids", &asids))
- return -ENODEV;
+static void tegra_smmu_ahb_enable(void)
+{
+ static const struct of_device_id ahb_match[] = {
+ { .compatible = "nvidia,tegra30-ahb", },
+ { }
+ };
+ struct device_node *ahb;
- bytes = sizeof(*smmu) + asids * sizeof(*smmu->as);
- smmu = devm_kzalloc(dev, bytes, GFP_KERNEL);
- if (!smmu) {
- dev_err(dev, "failed to allocate smmu_device\n");
- return -ENOMEM;
+ ahb = of_find_matching_node(NULL, ahb_match);
+ if (ahb) {
+ tegra_ahb_enable_smmu(ahb);
+ of_node_put(ahb);
}
+}
- smmu->nregs = pdev->num_resources;
- smmu->regs = devm_kzalloc(dev, 2 * smmu->nregs * sizeof(*smmu->regs),
- GFP_KERNEL);
- smmu->rege = smmu->regs + smmu->nregs;
- if (!smmu->regs)
- return -ENOMEM;
- for (i = 0; i < smmu->nregs; i++) {
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- smmu->regs[i] = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(smmu->regs[i]))
- return PTR_ERR(smmu->regs[i]);
- smmu->rege[i] = smmu->regs[i] + resource_size(res) - 1;
- }
- /* Same as "mc" 1st regiter block start address */
- smmu->regbase = (void __iomem *)((u32)smmu->regs[0] & PAGE_MASK);
+struct tegra_smmu *tegra_smmu_probe(struct device *dev,
+ const struct tegra_smmu_soc *soc,
+ struct tegra_mc *mc)
+{
+ struct tegra_smmu *smmu;
+ size_t size;
+ u32 value;
+ int err;
- err = of_get_dma_window(dev->of_node, NULL, 0, NULL, &base, &size);
- if (err)
- return -ENODEV;
+ /* This can happen on Tegra20 which doesn't have an SMMU */
+ if (!soc)
+ return NULL;
- if (size & SMMU_PAGE_MASK)
- return -EINVAL;
+ smmu = devm_kzalloc(dev, sizeof(*smmu), GFP_KERNEL);
+ if (!smmu)
+ return ERR_PTR(-ENOMEM);
- size >>= SMMU_PAGE_SHIFT;
- if (!size)
- return -EINVAL;
+ /*
+ * This is a bit of a hack. Ideally we'd want to simply return this
+ * value. However the IOMMU registration process will attempt to add
+ * all devices to the IOMMU when bus_set_iommu() is called. In order
+ * not to rely on global variables to track the IOMMU instance, we
+ * set it here so that it can be looked up from the .add_device()
+ * callback via the IOMMU device's .drvdata field.
+ */
+ mc->smmu = smmu;
- smmu->ahb = of_parse_phandle(dev->of_node, "nvidia,ahb", 0);
- if (!smmu->ahb)
- return -ENODEV;
+ size = BITS_TO_LONGS(soc->num_asids) * sizeof(long);
- smmu->dev = dev;
- smmu->num_as = asids;
- smmu->iovmm_base = base;
- smmu->page_count = size;
-
- smmu->translation_enable_0 = ~0;
- smmu->translation_enable_1 = ~0;
- smmu->translation_enable_2 = ~0;
- smmu->asid_security = 0;
-
- for (i = 0; i < smmu->num_as; i++) {
- struct smmu_as *as = &smmu->as[i];
-
- as->smmu = smmu;
- as->asid = i;
- as->pdir_attr = _PDIR_ATTR;
- as->pde_attr = _PDE_ATTR;
- as->pte_attr = _PTE_ATTR;
-
- spin_lock_init(&as->lock);
- spin_lock_init(&as->client_lock);
- INIT_LIST_HEAD(&as->client);
- }
- spin_lock_init(&smmu->lock);
- err = smmu_setup_regs(smmu);
- if (err)
- return err;
- platform_set_drvdata(pdev, smmu);
+ smmu->asids = devm_kzalloc(dev, size, GFP_KERNEL);
+ if (!smmu->asids)
+ return ERR_PTR(-ENOMEM);
- smmu->avp_vector_page = alloc_page(GFP_KERNEL);
- if (!smmu->avp_vector_page)
- return -ENOMEM;
+ mutex_init(&smmu->lock);
- smmu_debugfs_create(smmu);
- smmu_handle = smmu;
- bus_set_iommu(&platform_bus_type, &smmu_iommu_ops);
- return 0;
-}
+ smmu->regs = mc->regs;
+ smmu->soc = soc;
+ smmu->dev = dev;
+ smmu->mc = mc;
-static int tegra_smmu_remove(struct platform_device *pdev)
-{
- struct smmu_device *smmu = platform_get_drvdata(pdev);
- int i;
+ value = SMMU_PTC_CONFIG_ENABLE | SMMU_PTC_CONFIG_INDEX_MAP(0x3f);
- smmu_debugfs_delete(smmu);
+ if (soc->supports_request_limit)
+ value |= SMMU_PTC_CONFIG_REQ_LIMIT(8);
- smmu_write(smmu, SMMU_CONFIG_DISABLE, SMMU_CONFIG);
- for (i = 0; i < smmu->num_as; i++)
- free_pdir(&smmu->as[i]);
- __free_page(smmu->avp_vector_page);
- smmu_handle = NULL;
- return 0;
-}
+ smmu_writel(smmu, value, SMMU_PTC_CONFIG);
-static const struct dev_pm_ops tegra_smmu_pm_ops = {
- .suspend = tegra_smmu_suspend,
- .resume = tegra_smmu_resume,
-};
+ value = SMMU_TLB_CONFIG_HIT_UNDER_MISS |
+ SMMU_TLB_CONFIG_ACTIVE_LINES(0x20);
-static const struct of_device_id tegra_smmu_of_match[] = {
- { .compatible = "nvidia,tegra30-smmu", },
- { },
-};
-MODULE_DEVICE_TABLE(of, tegra_smmu_of_match);
-
-static struct platform_driver tegra_smmu_driver = {
- .probe = tegra_smmu_probe,
- .remove = tegra_smmu_remove,
- .driver = {
- .owner = THIS_MODULE,
- .name = "tegra-smmu",
- .pm = &tegra_smmu_pm_ops,
- .of_match_table = tegra_smmu_of_match,
- },
-};
+ if (soc->supports_round_robin_arbitration)
+ value |= SMMU_TLB_CONFIG_ROUND_ROBIN_ARBITRATION;
-static int tegra_smmu_init(void)
-{
- return platform_driver_register(&tegra_smmu_driver);
-}
+ smmu_writel(smmu, value, SMMU_TLB_CONFIG);
-static void __exit tegra_smmu_exit(void)
-{
- platform_driver_unregister(&tegra_smmu_driver);
-}
+ smmu_flush_ptc(smmu, NULL, 0);
+ smmu_flush_tlb(smmu);
+ smmu_writel(smmu, SMMU_CONFIG_ENABLE, SMMU_CONFIG);
+ smmu_flush(smmu);
+
+ tegra_smmu_ahb_enable();
-subsys_initcall(tegra_smmu_init);
-module_exit(tegra_smmu_exit);
+ err = bus_set_iommu(&platform_bus_type, &tegra_smmu_ops);
+ if (err < 0)
+ return ERR_PTR(err);
-MODULE_DESCRIPTION("IOMMU API for SMMU in Tegra30");
-MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
-MODULE_ALIAS("platform:tegra-smmu");
-MODULE_LICENSE("GPL v2");
+ return smmu;
+}
diff --git a/drivers/irqchip/Kconfig b/drivers/irqchip/Kconfig
index b21f12f..9efe5f1 100644
--- a/drivers/irqchip/Kconfig
+++ b/drivers/irqchip/Kconfig
@@ -48,14 +48,19 @@ config ATMEL_AIC5_IRQ
select MULTI_IRQ_HANDLER
select SPARSE_IRQ
+config BCM7120_L2_IRQ
+ bool
+ select GENERIC_IRQ_CHIP
+ select IRQ_DOMAIN
+
config BRCMSTB_L2_IRQ
bool
- depends on ARM
select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
config DW_APB_ICTL
bool
+ select GENERIC_IRQ_CHIP
select IRQ_DOMAIN
config IMGPDC_IRQ
diff --git a/drivers/irqchip/Makefile b/drivers/irqchip/Makefile
index 173bb5f..f0909d0 100644
--- a/drivers/irqchip/Makefile
+++ b/drivers/irqchip/Makefile
@@ -35,6 +35,6 @@ obj-$(CONFIG_TB10X_IRQC) += irq-tb10x.o
obj-$(CONFIG_XTENSA) += irq-xtensa-pic.o
obj-$(CONFIG_XTENSA_MX) += irq-xtensa-mx.o
obj-$(CONFIG_IRQ_CROSSBAR) += irq-crossbar.o
-obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o \
- irq-bcm7120-l2.o
+obj-$(CONFIG_BCM7120_L2_IRQ) += irq-bcm7120-l2.o
+obj-$(CONFIG_BRCMSTB_L2_IRQ) += irq-brcmstb-l2.o
obj-$(CONFIG_KEYSTONE_IRQ) += irq-keystone.o
diff --git a/drivers/irqchip/irq-armada-370-xp.c b/drivers/irqchip/irq-armada-370-xp.c
index 6a2e168..463c235 100644
--- a/drivers/irqchip/irq-armada-370-xp.c
+++ b/drivers/irqchip/irq-armada-370-xp.c
@@ -26,6 +26,7 @@
#include <linux/of_pci.h>
#include <linux/irqdomain.h>
#include <linux/slab.h>
+#include <linux/syscore_ops.h>
#include <linux/msi.h>
#include <asm/mach/arch.h>
#include <asm/exception.h>
@@ -67,6 +68,7 @@
static void __iomem *per_cpu_int_base;
static void __iomem *main_int_base;
static struct irq_domain *armada_370_xp_mpic_domain;
+static u32 doorbell_mask_reg;
#ifdef CONFIG_PCI_MSI
static struct irq_domain *armada_370_xp_msi_domain;
static DECLARE_BITMAP(msi_used, PCI_MSI_DOORBELL_NR);
@@ -130,7 +132,7 @@ static void armada_370_xp_free_msi(int hwirq)
mutex_unlock(&msi_used_lock);
}
-static int armada_370_xp_setup_msi_irq(struct msi_chip *chip,
+static int armada_370_xp_setup_msi_irq(struct msi_controller *chip,
struct pci_dev *pdev,
struct msi_desc *desc)
{
@@ -157,11 +159,11 @@ static int armada_370_xp_setup_msi_irq(struct msi_chip *chip,
msg.address_hi = 0;
msg.data = 0xf00 | (hwirq + 16);
- write_msi_msg(virq, &msg);
+ pci_write_msi_msg(virq, &msg);
return 0;
}
-static void armada_370_xp_teardown_msi_irq(struct msi_chip *chip,
+static void armada_370_xp_teardown_msi_irq(struct msi_controller *chip,
unsigned int irq)
{
struct irq_data *d = irq_get_irq_data(irq);
@@ -173,10 +175,10 @@ static void armada_370_xp_teardown_msi_irq(struct msi_chip *chip,
static struct irq_chip armada_370_xp_msi_irq_chip = {
.name = "armada_370_xp_msi_irq",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
static int armada_370_xp_msi_map(struct irq_domain *domain, unsigned int virq,
@@ -196,7 +198,7 @@ static const struct irq_domain_ops armada_370_xp_msi_irq_ops = {
static int armada_370_xp_msi_init(struct device_node *node,
phys_addr_t main_int_phys_base)
{
- struct msi_chip *msi_chip;
+ struct msi_controller *msi_chip;
u32 reg;
int ret;
@@ -266,7 +268,7 @@ static int armada_xp_set_affinity(struct irq_data *d,
writel(reg, main_int_base + ARMADA_370_XP_INT_SOURCE_CTL(hwirq));
raw_spin_unlock(&irq_controller_lock);
- return 0;
+ return IRQ_SET_MASK_OK;
}
#endif
@@ -485,6 +487,54 @@ armada_370_xp_handle_irq(struct pt_regs *regs)
} while (1);
}
+static int armada_370_xp_mpic_suspend(void)
+{
+ doorbell_mask_reg = readl(per_cpu_int_base +
+ ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+ return 0;
+}
+
+static void armada_370_xp_mpic_resume(void)
+{
+ int nirqs;
+ irq_hw_number_t irq;
+
+ /* Re-enable interrupts */
+ nirqs = (readl(main_int_base + ARMADA_370_XP_INT_CONTROL) >> 2) & 0x3ff;
+ for (irq = 0; irq < nirqs; irq++) {
+ struct irq_data *data;
+ int virq;
+
+ virq = irq_linear_revmap(armada_370_xp_mpic_domain, irq);
+ if (virq == 0)
+ continue;
+
+ if (irq != ARMADA_370_XP_TIMER0_PER_CPU_IRQ)
+ writel(irq, per_cpu_int_base +
+ ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+ else
+ writel(irq, main_int_base +
+ ARMADA_370_XP_INT_SET_ENABLE_OFFS);
+
+ data = irq_get_irq_data(virq);
+ if (!irqd_irq_disabled(data))
+ armada_370_xp_irq_unmask(data);
+ }
+
+ /* Reconfigure doorbells for IPIs and MSIs */
+ writel(doorbell_mask_reg,
+ per_cpu_int_base + ARMADA_370_XP_IN_DRBEL_MSK_OFFS);
+ if (doorbell_mask_reg & IPI_DOORBELL_MASK)
+ writel(0, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+ if (doorbell_mask_reg & PCI_MSI_DOORBELL_MASK)
+ writel(1, per_cpu_int_base + ARMADA_370_XP_INT_CLEAR_MASK_OFFS);
+}
+
+struct syscore_ops armada_370_xp_mpic_syscore_ops = {
+ .suspend = armada_370_xp_mpic_suspend,
+ .resume = armada_370_xp_mpic_resume,
+};
+
static int __init armada_370_xp_mpic_of_init(struct device_node *node,
struct device_node *parent)
{
@@ -541,6 +591,8 @@ static int __init armada_370_xp_mpic_of_init(struct device_node *node,
armada_370_xp_mpic_handle_cascade_irq);
}
+ register_syscore_ops(&armada_370_xp_mpic_syscore_ops);
+
return 0;
}
diff --git a/drivers/irqchip/irq-atmel-aic-common.c b/drivers/irqchip/irq-atmel-aic-common.c
index cc4f9d8..d111ac7 100644
--- a/drivers/irqchip/irq-atmel-aic-common.c
+++ b/drivers/irqchip/irq-atmel-aic-common.c
@@ -167,6 +167,32 @@ void __init aic_common_rtc_irq_fixup(struct device_node *root)
iounmap(regs);
}
+#define AT91_RTT_MR 0x00 /* Real-time Mode Register */
+#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */
+#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */
+
+void __init aic_common_rtt_irq_fixup(struct device_node *root)
+{
+ struct device_node *np;
+ void __iomem *regs;
+
+ /*
+ * The at91sam9263 SoC has 2 instances of the RTT block, hence we
+ * iterate over the DT to find each occurrence.
+ */
+ for_each_compatible_node(np, NULL, "atmel,at91sam9260-rtt") {
+ regs = of_iomap(np, 0);
+ if (!regs)
+ continue;
+
+ writel(readl(regs + AT91_RTT_MR) &
+ ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN),
+ regs + AT91_RTT_MR);
+
+ iounmap(regs);
+ }
+}
+
void __init aic_common_irq_fixup(const struct of_device_id *matches)
{
struct device_node *root = of_find_node_by_path("/");
diff --git a/drivers/irqchip/irq-atmel-aic-common.h b/drivers/irqchip/irq-atmel-aic-common.h
index 90aa00e..603f0a9 100644
--- a/drivers/irqchip/irq-atmel-aic-common.h
+++ b/drivers/irqchip/irq-atmel-aic-common.h
@@ -34,6 +34,8 @@ struct irq_domain *__init aic_common_of_init(struct device_node *node,
void __init aic_common_rtc_irq_fixup(struct device_node *root);
+void __init aic_common_rtt_irq_fixup(struct device_node *root);
+
void __init aic_common_irq_fixup(const struct of_device_id *matches);
#endif /* __IRQ_ATMEL_AIC_COMMON_H */
diff --git a/drivers/irqchip/irq-atmel-aic.c b/drivers/irqchip/irq-atmel-aic.c
index 9a2cf3c..dae3604 100644
--- a/drivers/irqchip/irq-atmel-aic.c
+++ b/drivers/irqchip/irq-atmel-aic.c
@@ -65,11 +65,11 @@ aic_handle(struct pt_regs *regs)
u32 irqnr;
u32 irqstat;
- irqnr = irq_reg_readl(gc->reg_base + AT91_AIC_IVR);
- irqstat = irq_reg_readl(gc->reg_base + AT91_AIC_ISR);
+ irqnr = irq_reg_readl(gc, AT91_AIC_IVR);
+ irqstat = irq_reg_readl(gc, AT91_AIC_ISR);
if (!irqstat)
- irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
+ irq_reg_writel(gc, 0, AT91_AIC_EOICR);
else
handle_domain_irq(aic_domain, irqnr, regs);
}
@@ -80,7 +80,7 @@ static int aic_retrigger(struct irq_data *d)
/* Enable interrupt on AIC5 */
irq_gc_lock(gc);
- irq_reg_writel(d->mask, gc->reg_base + AT91_AIC_ISCR);
+ irq_reg_writel(gc, d->mask, AT91_AIC_ISCR);
irq_gc_unlock(gc);
return 0;
@@ -92,12 +92,12 @@ static int aic_set_type(struct irq_data *d, unsigned type)
unsigned int smr;
int ret;
- smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(d->hwirq));
+ smr = irq_reg_readl(gc, AT91_AIC_SMR(d->hwirq));
ret = aic_common_set_type(d, type, &smr);
if (ret)
return ret;
- irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(d->hwirq));
+ irq_reg_writel(gc, smr, AT91_AIC_SMR(d->hwirq));
return 0;
}
@@ -108,8 +108,8 @@ static void aic_suspend(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
irq_gc_lock(gc);
- irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IDCR);
- irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IECR);
+ irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IDCR);
+ irq_reg_writel(gc, gc->wake_active, AT91_AIC_IECR);
irq_gc_unlock(gc);
}
@@ -118,8 +118,8 @@ static void aic_resume(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
irq_gc_lock(gc);
- irq_reg_writel(gc->wake_active, gc->reg_base + AT91_AIC_IDCR);
- irq_reg_writel(gc->mask_cache, gc->reg_base + AT91_AIC_IECR);
+ irq_reg_writel(gc, gc->wake_active, AT91_AIC_IDCR);
+ irq_reg_writel(gc, gc->mask_cache, AT91_AIC_IECR);
irq_gc_unlock(gc);
}
@@ -128,8 +128,8 @@ static void aic_pm_shutdown(struct irq_data *d)
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
irq_gc_lock(gc);
- irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR);
- irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR);
+ irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR);
+ irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR);
irq_gc_unlock(gc);
}
#else
@@ -148,24 +148,24 @@ static void __init aic_hw_init(struct irq_domain *domain)
* will not Lock out nIRQ
*/
for (i = 0; i < 8; i++)
- irq_reg_writel(0, gc->reg_base + AT91_AIC_EOICR);
+ irq_reg_writel(gc, 0, AT91_AIC_EOICR);
/*
* Spurious Interrupt ID in Spurious Vector Register.
* When there is no current interrupt, the IRQ Vector Register
* reads the value stored in AIC_SPU
*/
- irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_SPU);
+ irq_reg_writel(gc, 0xffffffff, AT91_AIC_SPU);
/* No debugging in AIC: Debug (Protect) Control Register */
- irq_reg_writel(0, gc->reg_base + AT91_AIC_DCR);
+ irq_reg_writel(gc, 0, AT91_AIC_DCR);
/* Disable and clear all interrupts initially */
- irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_IDCR);
- irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC_ICCR);
+ irq_reg_writel(gc, 0xffffffff, AT91_AIC_IDCR);
+ irq_reg_writel(gc, 0xffffffff, AT91_AIC_ICCR);
for (i = 0; i < 32; i++)
- irq_reg_writel(i, gc->reg_base + AT91_AIC_SVR(i));
+ irq_reg_writel(gc, i, AT91_AIC_SVR(i));
}
static int aic_irq_domain_xlate(struct irq_domain *d,
@@ -195,10 +195,10 @@ static int aic_irq_domain_xlate(struct irq_domain *d,
gc = dgc->gc[idx];
irq_gc_lock(gc);
- smr = irq_reg_readl(gc->reg_base + AT91_AIC_SMR(*out_hwirq));
+ smr = irq_reg_readl(gc, AT91_AIC_SMR(*out_hwirq));
ret = aic_common_set_priority(intspec[2], &smr);
if (!ret)
- irq_reg_writel(smr, gc->reg_base + AT91_AIC_SMR(*out_hwirq));
+ irq_reg_writel(gc, smr, AT91_AIC_SMR(*out_hwirq));
irq_gc_unlock(gc);
return ret;
@@ -209,16 +209,32 @@ static const struct irq_domain_ops aic_irq_ops = {
.xlate = aic_irq_domain_xlate,
};
-static void __init at91sam9_aic_irq_fixup(struct device_node *root)
+static void __init at91rm9200_aic_irq_fixup(struct device_node *root)
{
aic_common_rtc_irq_fixup(root);
}
+static void __init at91sam9260_aic_irq_fixup(struct device_node *root)
+{
+ aic_common_rtt_irq_fixup(root);
+}
+
+static void __init at91sam9g45_aic_irq_fixup(struct device_node *root)
+{
+ aic_common_rtc_irq_fixup(root);
+ aic_common_rtt_irq_fixup(root);
+}
+
static const struct of_device_id __initdata aic_irq_fixups[] = {
- { .compatible = "atmel,at91sam9g45", .data = at91sam9_aic_irq_fixup },
- { .compatible = "atmel,at91sam9n12", .data = at91sam9_aic_irq_fixup },
- { .compatible = "atmel,at91sam9rl", .data = at91sam9_aic_irq_fixup },
- { .compatible = "atmel,at91sam9x5", .data = at91sam9_aic_irq_fixup },
+ { .compatible = "atmel,at91rm9200", .data = at91rm9200_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9g45", .data = at91sam9g45_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9n12", .data = at91rm9200_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9rl", .data = at91sam9g45_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9x5", .data = at91rm9200_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9260", .data = at91sam9260_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9261", .data = at91sam9260_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9263", .data = at91sam9260_aic_irq_fixup },
+ { .compatible = "atmel,at91sam9g20", .data = at91sam9260_aic_irq_fixup },
{ /* sentinel */ },
};
diff --git a/drivers/irqchip/irq-atmel-aic5.c b/drivers/irqchip/irq-atmel-aic5.c
index a11aae8..a2e8c3f 100644
--- a/drivers/irqchip/irq-atmel-aic5.c
+++ b/drivers/irqchip/irq-atmel-aic5.c
@@ -75,11 +75,11 @@ aic5_handle(struct pt_regs *regs)
u32 irqnr;
u32 irqstat;
- irqnr = irq_reg_readl(gc->reg_base + AT91_AIC5_IVR);
- irqstat = irq_reg_readl(gc->reg_base + AT91_AIC5_ISR);
+ irqnr = irq_reg_readl(gc, AT91_AIC5_IVR);
+ irqstat = irq_reg_readl(gc, AT91_AIC5_ISR);
if (!irqstat)
- irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
+ irq_reg_writel(gc, 0, AT91_AIC5_EOICR);
else
handle_domain_irq(aic5_domain, irqnr, regs);
}
@@ -92,8 +92,8 @@ static void aic5_mask(struct irq_data *d)
/* Disable interrupt on AIC5 */
irq_gc_lock(gc);
- irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
- irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR);
+ irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
+ irq_reg_writel(gc, 1, AT91_AIC5_IDCR);
gc->mask_cache &= ~d->mask;
irq_gc_unlock(gc);
}
@@ -106,8 +106,8 @@ static void aic5_unmask(struct irq_data *d)
/* Enable interrupt on AIC5 */
irq_gc_lock(gc);
- irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
- irq_reg_writel(1, gc->reg_base + AT91_AIC5_IECR);
+ irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
+ irq_reg_writel(gc, 1, AT91_AIC5_IECR);
gc->mask_cache |= d->mask;
irq_gc_unlock(gc);
}
@@ -120,8 +120,8 @@ static int aic5_retrigger(struct irq_data *d)
/* Enable interrupt on AIC5 */
irq_gc_lock(gc);
- irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
- irq_reg_writel(1, gc->reg_base + AT91_AIC5_ISCR);
+ irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
+ irq_reg_writel(gc, 1, AT91_AIC5_ISCR);
irq_gc_unlock(gc);
return 0;
@@ -136,11 +136,11 @@ static int aic5_set_type(struct irq_data *d, unsigned type)
int ret;
irq_gc_lock(gc);
- irq_reg_writel(d->hwirq, gc->reg_base + AT91_AIC5_SSR);
- smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR);
+ irq_reg_writel(gc, d->hwirq, AT91_AIC5_SSR);
+ smr = irq_reg_readl(gc, AT91_AIC5_SMR);
ret = aic_common_set_type(d, type, &smr);
if (!ret)
- irq_reg_writel(smr, gc->reg_base + AT91_AIC5_SMR);
+ irq_reg_writel(gc, smr, AT91_AIC5_SMR);
irq_gc_unlock(gc);
return ret;
@@ -162,12 +162,11 @@ static void aic5_suspend(struct irq_data *d)
if ((mask & gc->mask_cache) == (mask & gc->wake_active))
continue;
- irq_reg_writel(i + gc->irq_base,
- bgc->reg_base + AT91_AIC5_SSR);
+ irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
if (mask & gc->wake_active)
- irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR);
+ irq_reg_writel(bgc, 1, AT91_AIC5_IECR);
else
- irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
+ irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
}
irq_gc_unlock(bgc);
}
@@ -187,12 +186,11 @@ static void aic5_resume(struct irq_data *d)
if ((mask & gc->mask_cache) == (mask & gc->wake_active))
continue;
- irq_reg_writel(i + gc->irq_base,
- bgc->reg_base + AT91_AIC5_SSR);
+ irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
if (mask & gc->mask_cache)
- irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IECR);
+ irq_reg_writel(bgc, 1, AT91_AIC5_IECR);
else
- irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
+ irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
}
irq_gc_unlock(bgc);
}
@@ -207,10 +205,9 @@ static void aic5_pm_shutdown(struct irq_data *d)
irq_gc_lock(bgc);
for (i = 0; i < dgc->irqs_per_chip; i++) {
- irq_reg_writel(i + gc->irq_base,
- bgc->reg_base + AT91_AIC5_SSR);
- irq_reg_writel(1, bgc->reg_base + AT91_AIC5_IDCR);
- irq_reg_writel(1, bgc->reg_base + AT91_AIC5_ICCR);
+ irq_reg_writel(bgc, i + gc->irq_base, AT91_AIC5_SSR);
+ irq_reg_writel(bgc, 1, AT91_AIC5_IDCR);
+ irq_reg_writel(bgc, 1, AT91_AIC5_ICCR);
}
irq_gc_unlock(bgc);
}
@@ -230,24 +227,24 @@ static void __init aic5_hw_init(struct irq_domain *domain)
* will not Lock out nIRQ
*/
for (i = 0; i < 8; i++)
- irq_reg_writel(0, gc->reg_base + AT91_AIC5_EOICR);
+ irq_reg_writel(gc, 0, AT91_AIC5_EOICR);
/*
* Spurious Interrupt ID in Spurious Vector Register.
* When there is no current interrupt, the IRQ Vector Register
* reads the value stored in AIC_SPU
*/
- irq_reg_writel(0xffffffff, gc->reg_base + AT91_AIC5_SPU);
+ irq_reg_writel(gc, 0xffffffff, AT91_AIC5_SPU);
/* No debugging in AIC: Debug (Protect) Control Register */
- irq_reg_writel(0, gc->reg_base + AT91_AIC5_DCR);
+ irq_reg_writel(gc, 0, AT91_AIC5_DCR);
/* Disable and clear all interrupts initially */
for (i = 0; i < domain->revmap_size; i++) {
- irq_reg_writel(i, gc->reg_base + AT91_AIC5_SSR);
- irq_reg_writel(i, gc->reg_base + AT91_AIC5_SVR);
- irq_reg_writel(1, gc->reg_base + AT91_AIC5_IDCR);
- irq_reg_writel(1, gc->reg_base + AT91_AIC5_ICCR);
+ irq_reg_writel(gc, i, AT91_AIC5_SSR);
+ irq_reg_writel(gc, i, AT91_AIC5_SVR);
+ irq_reg_writel(gc, 1, AT91_AIC5_IDCR);
+ irq_reg_writel(gc, 1, AT91_AIC5_ICCR);
}
}
@@ -273,11 +270,11 @@ static int aic5_irq_domain_xlate(struct irq_domain *d,
gc = dgc->gc[0];
irq_gc_lock(gc);
- irq_reg_writel(*out_hwirq, gc->reg_base + AT91_AIC5_SSR);
- smr = irq_reg_readl(gc->reg_base + AT91_AIC5_SMR);
+ irq_reg_writel(gc, *out_hwirq, AT91_AIC5_SSR);
+ smr = irq_reg_readl(gc, AT91_AIC5_SMR);
ret = aic_common_set_priority(intspec[2], &smr);
if (!ret)
- irq_reg_writel(intspec[2] | smr, gc->reg_base + AT91_AIC5_SMR);
+ irq_reg_writel(gc, intspec[2] | smr, AT91_AIC5_SMR);
irq_gc_unlock(gc);
return ret;
diff --git a/drivers/irqchip/irq-bcm7120-l2.c b/drivers/irqchip/irq-bcm7120-l2.c
index 5fb38a2..8eec8e1 100644
--- a/drivers/irqchip/irq-bcm7120-l2.c
+++ b/drivers/irqchip/irq-bcm7120-l2.c
@@ -13,6 +13,7 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/kconfig.h>
#include <linux/platform_device.h>
#include <linux/of.h>
#include <linux/of_irq.h>
@@ -23,47 +24,52 @@
#include <linux/io.h>
#include <linux/irqdomain.h>
#include <linux/reboot.h>
+#include <linux/bitops.h>
#include <linux/irqchip/chained_irq.h>
#include "irqchip.h"
-#include <asm/mach/irq.h>
-
/* Register offset in the L2 interrupt controller */
#define IRQEN 0x00
#define IRQSTAT 0x04
+#define MAX_WORDS 4
+#define IRQS_PER_WORD 32
+
struct bcm7120_l2_intc_data {
- void __iomem *base;
+ unsigned int n_words;
+ void __iomem *base[MAX_WORDS];
struct irq_domain *domain;
bool can_wake;
- u32 irq_fwd_mask;
- u32 irq_map_mask;
- u32 saved_mask;
+ u32 irq_fwd_mask[MAX_WORDS];
+ u32 irq_map_mask[MAX_WORDS];
};
static void bcm7120_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
{
struct bcm7120_l2_intc_data *b = irq_desc_get_handler_data(desc);
struct irq_chip *chip = irq_desc_get_chip(desc);
- u32 status;
+ unsigned int idx;
chained_irq_enter(chip, desc);
- status = __raw_readl(b->base + IRQSTAT);
-
- if (status == 0) {
- do_bad_IRQ(irq, desc);
- goto out;
+ for (idx = 0; idx < b->n_words; idx++) {
+ int base = idx * IRQS_PER_WORD;
+ struct irq_chip_generic *gc =
+ irq_get_domain_generic_chip(b->domain, base);
+ unsigned long pending;
+ int hwirq;
+
+ irq_gc_lock(gc);
+ pending = irq_reg_readl(gc, IRQSTAT) & gc->mask_cache;
+ irq_gc_unlock(gc);
+
+ for_each_set_bit(hwirq, &pending, IRQS_PER_WORD) {
+ generic_handle_irq(irq_find_mapping(b->domain,
+ base + hwirq));
+ }
}
- do {
- irq = ffs(status) - 1;
- status &= ~(1 << irq);
- generic_handle_irq(irq_find_mapping(b->domain, irq));
- } while (status);
-
-out:
chained_irq_exit(chip, desc);
}
@@ -71,26 +77,20 @@ static void bcm7120_l2_intc_suspend(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
struct bcm7120_l2_intc_data *b = gc->private;
- u32 reg;
irq_gc_lock(gc);
- /* Save the current mask and the interrupt forward mask */
- b->saved_mask = __raw_readl(b->base) | b->irq_fwd_mask;
- if (b->can_wake) {
- reg = b->saved_mask | gc->wake_active;
- __raw_writel(reg, b->base);
- }
+ if (b->can_wake)
+ irq_reg_writel(gc, gc->mask_cache | gc->wake_active, IRQEN);
irq_gc_unlock(gc);
}
static void bcm7120_l2_intc_resume(struct irq_data *d)
{
struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
- struct bcm7120_l2_intc_data *b = gc->private;
/* Restore the saved mask */
irq_gc_lock(gc);
- __raw_writel(b->saved_mask, b->base);
+ irq_reg_writel(gc, gc->mask_cache, IRQEN);
irq_gc_unlock(gc);
}
@@ -99,6 +99,7 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
int irq, const __be32 *map_mask)
{
int parent_irq;
+ unsigned int idx;
parent_irq = irq_of_parse_and_map(dn, irq);
if (!parent_irq) {
@@ -106,7 +107,12 @@ static int bcm7120_l2_intc_init_one(struct device_node *dn,
return -EINVAL;
}
- data->irq_map_mask |= be32_to_cpup(map_mask + irq);
+ /* For multiple parent IRQs with multiple words, this looks like:
+ * <irq0_w0 irq0_w1 irq1_w0 irq1_w1 ...>
+ */
+ for (idx = 0; idx < data->n_words; idx++)
+ data->irq_map_mask[idx] |=
+ be32_to_cpup(map_mask + irq * data->n_words + idx);
irq_set_handler_data(parent_irq, data);
irq_set_chained_handler(parent_irq, bcm7120_l2_intc_irq_handle);
@@ -123,26 +129,41 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
struct irq_chip_type *ct;
const __be32 *map_mask;
int num_parent_irqs;
- int ret = 0, len, irq;
+ int ret = 0, len;
+ unsigned int idx, irq, flags;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
return -ENOMEM;
- data->base = of_iomap(dn, 0);
- if (!data->base) {
+ for (idx = 0; idx < MAX_WORDS; idx++) {
+ data->base[idx] = of_iomap(dn, idx);
+ if (!data->base[idx])
+ break;
+ data->n_words = idx + 1;
+ }
+ if (!data->n_words) {
pr_err("failed to remap intc L2 registers\n");
ret = -ENOMEM;
- goto out_free;
+ goto out_unmap;
}
- if (of_property_read_u32(dn, "brcm,int-fwd-mask", &data->irq_fwd_mask))
- data->irq_fwd_mask = 0;
-
- /* Enable all interrupt specified in the interrupt forward mask and have
- * the other disabled
+ /* Enable all interrupts specified in the interrupt forward mask;
+ * disable all others. If the property doesn't exist (-EINVAL),
+ * assume all zeroes.
*/
- __raw_writel(data->irq_fwd_mask, data->base + IRQEN);
+ ret = of_property_read_u32_array(dn, "brcm,int-fwd-mask",
+ data->irq_fwd_mask, data->n_words);
+ if (ret == 0 || ret == -EINVAL) {
+ for (idx = 0; idx < data->n_words; idx++)
+ __raw_writel(data->irq_fwd_mask[idx],
+ data->base[idx] + IRQEN);
+ } else {
+ /* property exists but has the wrong number of words */
+ pr_err("invalid int-fwd-mask property\n");
+ ret = -EINVAL;
+ goto out_unmap;
+ }
num_parent_irqs = of_irq_count(dn);
if (num_parent_irqs <= 0) {
@@ -152,7 +173,8 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
}
map_mask = of_get_property(dn, "brcm,int-map-mask", &len);
- if (!map_mask || (len != (sizeof(*map_mask) * num_parent_irqs))) {
+ if (!map_mask ||
+ (len != (sizeof(*map_mask) * num_parent_irqs * data->n_words))) {
pr_err("invalid brcm,int-map-mask property\n");
ret = -EINVAL;
goto out_unmap;
@@ -164,56 +186,70 @@ int __init bcm7120_l2_intc_of_init(struct device_node *dn,
goto out_unmap;
}
- data->domain = irq_domain_add_linear(dn, 32,
- &irq_generic_chip_ops, NULL);
+ data->domain = irq_domain_add_linear(dn, IRQS_PER_WORD * data->n_words,
+ &irq_generic_chip_ops, NULL);
if (!data->domain) {
ret = -ENOMEM;
goto out_unmap;
}
- ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
- dn->full_name, handle_level_irq, clr, 0,
- IRQ_GC_INIT_MASK_CACHE);
+ /* MIPS chips strapped for BE will automagically configure the
+ * peripheral registers for CPU-native byte order.
+ */
+ flags = IRQ_GC_INIT_MASK_CACHE;
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ flags |= IRQ_GC_BE_IO;
+
+ ret = irq_alloc_domain_generic_chips(data->domain, IRQS_PER_WORD, 1,
+ dn->full_name, handle_level_irq, clr, 0, flags);
if (ret) {
pr_err("failed to allocate generic irq chip\n");
goto out_free_domain;
}
- gc = irq_get_domain_generic_chip(data->domain, 0);
- gc->unused = 0xfffffff & ~data->irq_map_mask;
- gc->reg_base = data->base;
- gc->private = data;
- ct = gc->chip_types;
-
- ct->regs.mask = IRQEN;
- ct->chip.irq_mask = irq_gc_mask_clr_bit;
- ct->chip.irq_unmask = irq_gc_mask_set_bit;
- ct->chip.irq_ack = irq_gc_noop;
- ct->chip.irq_suspend = bcm7120_l2_intc_suspend;
- ct->chip.irq_resume = bcm7120_l2_intc_resume;
-
- if (of_property_read_bool(dn, "brcm,irq-can-wake")) {
+ if (of_property_read_bool(dn, "brcm,irq-can-wake"))
data->can_wake = true;
- /* This IRQ chip can wake the system, set all relevant child
- * interupts in wake_enabled mask
- */
- gc->wake_enabled = 0xffffffff;
- gc->wake_enabled &= ~gc->unused;
- ct->chip.irq_set_wake = irq_gc_set_wake;
+
+ for (idx = 0; idx < data->n_words; idx++) {
+ irq = idx * IRQS_PER_WORD;
+ gc = irq_get_domain_generic_chip(data->domain, irq);
+
+ gc->unused = 0xffffffff & ~data->irq_map_mask[idx];
+ gc->reg_base = data->base[idx];
+ gc->private = data;
+ ct = gc->chip_types;
+
+ ct->regs.mask = IRQEN;
+ ct->chip.irq_mask = irq_gc_mask_clr_bit;
+ ct->chip.irq_unmask = irq_gc_mask_set_bit;
+ ct->chip.irq_ack = irq_gc_noop;
+ ct->chip.irq_suspend = bcm7120_l2_intc_suspend;
+ ct->chip.irq_resume = bcm7120_l2_intc_resume;
+
+ if (data->can_wake) {
+ /* This IRQ chip can wake the system, set all
+ * relevant child interupts in wake_enabled mask
+ */
+ gc->wake_enabled = 0xffffffff;
+ gc->wake_enabled &= ~gc->unused;
+ ct->chip.irq_set_wake = irq_gc_set_wake;
+ }
}
pr_info("registered BCM7120 L2 intc (mem: 0x%p, parent IRQ(s): %d)\n",
- data->base, num_parent_irqs);
+ data->base[0], num_parent_irqs);
return 0;
out_free_domain:
irq_domain_remove(data->domain);
out_unmap:
- iounmap(data->base);
-out_free:
+ for (idx = 0; idx < MAX_WORDS; idx++) {
+ if (data->base[idx])
+ iounmap(data->base[idx]);
+ }
kfree(data);
return ret;
}
-IRQCHIP_DECLARE(brcmstb_l2_intc, "brcm,bcm7120-l2-intc",
+IRQCHIP_DECLARE(bcm7120_l2_intc, "brcm,bcm7120-l2-intc",
bcm7120_l2_intc_of_init);
diff --git a/drivers/irqchip/irq-brcmstb-l2.c b/drivers/irqchip/irq-brcmstb-l2.c
index 14691a4..313c2c6 100644
--- a/drivers/irqchip/irq-brcmstb-l2.c
+++ b/drivers/irqchip/irq-brcmstb-l2.c
@@ -18,7 +18,9 @@
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/module.h>
+#include <linux/kconfig.h>
#include <linux/platform_device.h>
+#include <linux/spinlock.h>
#include <linux/of.h>
#include <linux/of_irq.h>
#include <linux/of_address.h>
@@ -30,8 +32,6 @@
#include <linux/irqchip.h>
#include <linux/irqchip/chained_irq.h>
-#include <asm/mach/irq.h>
-
#include "irqchip.h"
/* Register offsets in the L2 interrupt controller */
@@ -54,23 +54,26 @@ struct brcmstb_l2_intc_data {
static void brcmstb_l2_intc_irq_handle(unsigned int irq, struct irq_desc *desc)
{
struct brcmstb_l2_intc_data *b = irq_desc_get_handler_data(desc);
+ struct irq_chip_generic *gc = irq_get_domain_generic_chip(b->domain, 0);
struct irq_chip *chip = irq_desc_get_chip(desc);
u32 status;
chained_irq_enter(chip, desc);
- status = __raw_readl(b->base + CPU_STATUS) &
- ~(__raw_readl(b->base + CPU_MASK_STATUS));
+ status = irq_reg_readl(gc, CPU_STATUS) &
+ ~(irq_reg_readl(gc, CPU_MASK_STATUS));
if (status == 0) {
- do_bad_IRQ(irq, desc);
+ raw_spin_lock(&desc->lock);
+ handle_bad_irq(irq, desc);
+ raw_spin_unlock(&desc->lock);
goto out;
}
do {
irq = ffs(status) - 1;
/* ack at our level */
- __raw_writel(1 << irq, b->base + CPU_CLEAR);
+ irq_reg_writel(gc, 1 << irq, CPU_CLEAR);
status &= ~(1 << irq);
generic_handle_irq(irq_find_mapping(b->domain, irq));
} while (status);
@@ -85,12 +88,12 @@ static void brcmstb_l2_intc_suspend(struct irq_data *d)
irq_gc_lock(gc);
/* Save the current mask */
- b->saved_mask = __raw_readl(b->base + CPU_MASK_STATUS);
+ b->saved_mask = irq_reg_readl(gc, CPU_MASK_STATUS);
if (b->can_wake) {
/* Program the wakeup mask */
- __raw_writel(~gc->wake_active, b->base + CPU_MASK_SET);
- __raw_writel(gc->wake_active, b->base + CPU_MASK_CLEAR);
+ irq_reg_writel(gc, ~gc->wake_active, CPU_MASK_SET);
+ irq_reg_writel(gc, gc->wake_active, CPU_MASK_CLEAR);
}
irq_gc_unlock(gc);
}
@@ -102,11 +105,11 @@ static void brcmstb_l2_intc_resume(struct irq_data *d)
irq_gc_lock(gc);
/* Clear unmasked non-wakeup interrupts */
- __raw_writel(~b->saved_mask & ~gc->wake_active, b->base + CPU_CLEAR);
+ irq_reg_writel(gc, ~b->saved_mask & ~gc->wake_active, CPU_CLEAR);
/* Restore the saved mask */
- __raw_writel(b->saved_mask, b->base + CPU_MASK_SET);
- __raw_writel(~b->saved_mask, b->base + CPU_MASK_CLEAR);
+ irq_reg_writel(gc, b->saved_mask, CPU_MASK_SET);
+ irq_reg_writel(gc, ~b->saved_mask, CPU_MASK_CLEAR);
irq_gc_unlock(gc);
}
@@ -118,6 +121,7 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
struct irq_chip_generic *gc;
struct irq_chip_type *ct;
int ret;
+ unsigned int flags;
data = kzalloc(sizeof(*data), GFP_KERNEL);
if (!data)
@@ -131,8 +135,8 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
}
/* Disable all interrupts by default */
- __raw_writel(0xffffffff, data->base + CPU_MASK_SET);
- __raw_writel(0xffffffff, data->base + CPU_CLEAR);
+ writel(0xffffffff, data->base + CPU_MASK_SET);
+ writel(0xffffffff, data->base + CPU_CLEAR);
data->parent_irq = irq_of_parse_and_map(np, 0);
if (!data->parent_irq) {
@@ -148,9 +152,16 @@ int __init brcmstb_l2_intc_of_init(struct device_node *np,
goto out_unmap;
}
+ /* MIPS chips strapped for BE will automagically configure the
+ * peripheral registers for CPU-native byte order.
+ */
+ flags = 0;
+ if (IS_ENABLED(CONFIG_MIPS) && IS_ENABLED(CONFIG_CPU_BIG_ENDIAN))
+ flags |= IRQ_GC_BE_IO;
+
/* Allocate a single Generic IRQ chip for this node */
ret = irq_alloc_domain_generic_chips(data->domain, 32, 1,
- np->full_name, handle_edge_irq, clr, 0, 0);
+ np->full_name, handle_edge_irq, clr, 0, flags);
if (ret) {
pr_err("failed to allocate generic irq chip\n");
goto out_free_domain;
diff --git a/drivers/irqchip/irq-dw-apb-ictl.c b/drivers/irqchip/irq-dw-apb-ictl.c
index 31e231e..53bb732 100644
--- a/drivers/irqchip/irq-dw-apb-ictl.c
+++ b/drivers/irqchip/irq-dw-apb-ictl.c
@@ -50,6 +50,21 @@ static void dw_apb_ictl_handler(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
+#ifdef CONFIG_PM
+static void dw_apb_ictl_resume(struct irq_data *d)
+{
+ struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
+ struct irq_chip_type *ct = irq_data_get_chip_type(d);
+
+ irq_gc_lock(gc);
+ writel_relaxed(~0, gc->reg_base + ct->regs.enable);
+ writel_relaxed(*ct->mask_cache, gc->reg_base + ct->regs.mask);
+ irq_gc_unlock(gc);
+}
+#else
+#define dw_apb_ictl_resume NULL
+#endif /* CONFIG_PM */
+
static int __init dw_apb_ictl_init(struct device_node *np,
struct device_node *parent)
{
@@ -94,16 +109,16 @@ static int __init dw_apb_ictl_init(struct device_node *np,
*/
/* mask and enable all interrupts */
- writel(~0, iobase + APB_INT_MASK_L);
- writel(~0, iobase + APB_INT_MASK_H);
- writel(~0, iobase + APB_INT_ENABLE_L);
- writel(~0, iobase + APB_INT_ENABLE_H);
+ writel_relaxed(~0, iobase + APB_INT_MASK_L);
+ writel_relaxed(~0, iobase + APB_INT_MASK_H);
+ writel_relaxed(~0, iobase + APB_INT_ENABLE_L);
+ writel_relaxed(~0, iobase + APB_INT_ENABLE_H);
- reg = readl(iobase + APB_INT_ENABLE_H);
+ reg = readl_relaxed(iobase + APB_INT_ENABLE_H);
if (reg)
nrirqs = 32 + fls(reg);
else
- nrirqs = fls(readl(iobase + APB_INT_ENABLE_L));
+ nrirqs = fls(readl_relaxed(iobase + APB_INT_ENABLE_L));
domain = irq_domain_add_linear(np, nrirqs,
&irq_generic_chip_ops, NULL);
@@ -115,6 +130,7 @@ static int __init dw_apb_ictl_init(struct device_node *np,
ret = irq_alloc_domain_generic_chips(domain, 32, (nrirqs > 32) ? 2 : 1,
np->name, handle_level_irq, clr, 0,
+ IRQ_GC_MASK_CACHE_PER_TYPE |
IRQ_GC_INIT_MASK_CACHE);
if (ret) {
pr_err("%s: unable to alloc irq domain gc\n", np->full_name);
@@ -126,13 +142,17 @@ static int __init dw_apb_ictl_init(struct device_node *np,
gc->reg_base = iobase;
gc->chip_types[0].regs.mask = APB_INT_MASK_L;
+ gc->chip_types[0].regs.enable = APB_INT_ENABLE_L;
gc->chip_types[0].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_clr_bit;
+ gc->chip_types[0].chip.irq_resume = dw_apb_ictl_resume;
if (nrirqs > 32) {
gc->chip_types[1].regs.mask = APB_INT_MASK_H;
+ gc->chip_types[1].regs.enable = APB_INT_ENABLE_H;
gc->chip_types[1].chip.irq_mask = irq_gc_mask_set_bit;
gc->chip_types[1].chip.irq_unmask = irq_gc_mask_clr_bit;
+ gc->chip_types[1].chip.irq_resume = dw_apb_ictl_resume;
}
irq_set_handler_data(irq, gc);
diff --git a/drivers/irqchip/irq-gic.c b/drivers/irqchip/irq-gic.c
index 38493ff..7f9be07 100644
--- a/drivers/irqchip/irq-gic.c
+++ b/drivers/irqchip/irq-gic.c
@@ -1041,6 +1041,8 @@ gic_of_init(struct device_node *node, struct device_node *parent)
return 0;
}
IRQCHIP_DECLARE(gic_400, "arm,gic-400", gic_of_init);
+IRQCHIP_DECLARE(arm11mp_gic, "arm,arm11mp-gic", gic_of_init);
+IRQCHIP_DECLARE(arm1176jzf_dc_gic, "arm,arm1176jzf-devchip-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a15_gic, "arm,cortex-a15-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a9_gic, "arm,cortex-a9-gic", gic_of_init);
IRQCHIP_DECLARE(cortex_a7_gic, "arm,cortex-a7-gic", gic_of_init);
diff --git a/drivers/irqchip/irq-hip04.c b/drivers/irqchip/irq-hip04.c
index 9c8f8335..29b8f21 100644
--- a/drivers/irqchip/irq-hip04.c
+++ b/drivers/irqchip/irq-hip04.c
@@ -176,8 +176,7 @@ static void __exception_irq_entry hip04_handle_irq(struct pt_regs *regs)
irqnr = irqstat & GICC_IAR_INT_ID_MASK;
if (likely(irqnr > 15 && irqnr <= HIP04_MAX_IRQS)) {
- irqnr = irq_find_mapping(hip04_data.domain, irqnr);
- handle_IRQ(irqnr, regs);
+ handle_domain_irq(hip04_data.domain, irqnr, regs);
continue;
}
if (irqnr < 16) {
diff --git a/drivers/irqchip/irq-sunxi-nmi.c b/drivers/irqchip/irq-sunxi-nmi.c
index 12f547a..4a9ce5b 100644
--- a/drivers/irqchip/irq-sunxi-nmi.c
+++ b/drivers/irqchip/irq-sunxi-nmi.c
@@ -50,12 +50,12 @@ static struct sunxi_sc_nmi_reg_offs sun6i_reg_offs = {
static inline void sunxi_sc_nmi_write(struct irq_chip_generic *gc, u32 off,
u32 val)
{
- irq_reg_writel(val, gc->reg_base + off);
+ irq_reg_writel(gc, val, off);
}
static inline u32 sunxi_sc_nmi_read(struct irq_chip_generic *gc, u32 off)
{
- return irq_reg_readl(gc->reg_base + off);
+ return irq_reg_readl(gc, off);
}
static void sunxi_sc_nmi_handle_irq(unsigned int irq, struct irq_desc *desc)
diff --git a/drivers/irqchip/irq-tb10x.c b/drivers/irqchip/irq-tb10x.c
index 7c44c99..accc200 100644
--- a/drivers/irqchip/irq-tb10x.c
+++ b/drivers/irqchip/irq-tb10x.c
@@ -43,12 +43,12 @@
static inline void ab_irqctl_writereg(struct irq_chip_generic *gc, u32 reg,
u32 val)
{
- irq_reg_writel(val, gc->reg_base + reg);
+ irq_reg_writel(gc, val, reg);
}
static inline u32 ab_irqctl_readreg(struct irq_chip_generic *gc, u32 reg)
{
- return irq_reg_readl(gc->reg_base + reg);
+ return irq_reg_readl(gc, reg);
}
static int tb10x_irq_set_type(struct irq_data *data, unsigned int flow_type)
diff --git a/drivers/leds/leds-gpio.c b/drivers/leds/leds-gpio.c
index b4518c8..868e6fc 100644
--- a/drivers/leds/leds-gpio.c
+++ b/drivers/leds/leds-gpio.c
@@ -12,25 +12,23 @@
*/
#include <linux/err.h>
#include <linux/gpio.h>
+#include <linux/gpio/consumer.h>
#include <linux/kernel.h>
#include <linux/leds.h>
#include <linux/module.h>
-#include <linux/of.h>
-#include <linux/of_gpio.h>
-#include <linux/of_platform.h>
#include <linux/platform_device.h>
+#include <linux/property.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
struct gpio_led_data {
struct led_classdev cdev;
- unsigned gpio;
+ struct gpio_desc *gpiod;
struct work_struct work;
u8 new_level;
u8 can_sleep;
- u8 active_low;
u8 blinking;
- int (*platform_gpio_blink_set)(unsigned gpio, int state,
+ int (*platform_gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on, unsigned long *delay_off);
};
@@ -40,12 +38,11 @@ static void gpio_led_work(struct work_struct *work)
container_of(work, struct gpio_led_data, work);
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio,
- led_dat->new_level,
- NULL, NULL);
+ led_dat->platform_gpio_blink_set(led_dat->gpiod,
+ led_dat->new_level, NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value_cansleep(led_dat->gpio, led_dat->new_level);
+ gpiod_set_value_cansleep(led_dat->gpiod, led_dat->new_level);
}
static void gpio_led_set(struct led_classdev *led_cdev,
@@ -60,9 +57,6 @@ static void gpio_led_set(struct led_classdev *led_cdev,
else
level = 1;
- if (led_dat->active_low)
- level = !level;
-
/* Setting GPIOs with I2C/etc requires a task context, and we don't
* seem to have a reliable way to know if we're already in one; so
* let's just assume the worst.
@@ -72,11 +66,11 @@ static void gpio_led_set(struct led_classdev *led_cdev,
schedule_work(&led_dat->work);
} else {
if (led_dat->blinking) {
- led_dat->platform_gpio_blink_set(led_dat->gpio, level,
+ led_dat->platform_gpio_blink_set(led_dat->gpiod, level,
NULL, NULL);
led_dat->blinking = 0;
} else
- gpio_set_value(led_dat->gpio, level);
+ gpiod_set_value(led_dat->gpiod, level);
}
}
@@ -87,34 +81,49 @@ static int gpio_blink_set(struct led_classdev *led_cdev,
container_of(led_cdev, struct gpio_led_data, cdev);
led_dat->blinking = 1;
- return led_dat->platform_gpio_blink_set(led_dat->gpio, GPIO_LED_BLINK,
+ return led_dat->platform_gpio_blink_set(led_dat->gpiod, GPIO_LED_BLINK,
delay_on, delay_off);
}
static int create_gpio_led(const struct gpio_led *template,
struct gpio_led_data *led_dat, struct device *parent,
- int (*blink_set)(unsigned, int, unsigned long *, unsigned long *))
+ int (*blink_set)(struct gpio_desc *, int, unsigned long *,
+ unsigned long *))
{
int ret, state;
- led_dat->gpio = -1;
+ led_dat->gpiod = template->gpiod;
+ if (!led_dat->gpiod) {
+ /*
+ * This is the legacy code path for platform code that
+ * still uses GPIO numbers. Ultimately we would like to get
+ * rid of this block completely.
+ */
+ unsigned long flags = 0;
+
+ /* skip leds that aren't available */
+ if (!gpio_is_valid(template->gpio)) {
+ dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
+ template->gpio, template->name);
+ return 0;
+ }
- /* skip leds that aren't available */
- if (!gpio_is_valid(template->gpio)) {
- dev_info(parent, "Skipping unavailable LED gpio %d (%s)\n",
- template->gpio, template->name);
- return 0;
- }
+ if (template->active_low)
+ flags |= GPIOF_ACTIVE_LOW;
- ret = devm_gpio_request(parent, template->gpio, template->name);
- if (ret < 0)
- return ret;
+ ret = devm_gpio_request_one(parent, template->gpio, flags,
+ template->name);
+ if (ret < 0)
+ return ret;
+
+ led_dat->gpiod = gpio_to_desc(template->gpio);
+ if (IS_ERR(led_dat->gpiod))
+ return PTR_ERR(led_dat->gpiod);
+ }
led_dat->cdev.name = template->name;
led_dat->cdev.default_trigger = template->default_trigger;
- led_dat->gpio = template->gpio;
- led_dat->can_sleep = gpio_cansleep(template->gpio);
- led_dat->active_low = template->active_low;
+ led_dat->can_sleep = gpiod_cansleep(led_dat->gpiod);
led_dat->blinking = 0;
if (blink_set) {
led_dat->platform_gpio_blink_set = blink_set;
@@ -122,30 +131,24 @@ static int create_gpio_led(const struct gpio_led *template,
}
led_dat->cdev.brightness_set = gpio_led_set;
if (template->default_state == LEDS_GPIO_DEFSTATE_KEEP)
- state = !!gpio_get_value_cansleep(led_dat->gpio) ^ led_dat->active_low;
+ state = !!gpiod_get_value_cansleep(led_dat->gpiod);
else
state = (template->default_state == LEDS_GPIO_DEFSTATE_ON);
led_dat->cdev.brightness = state ? LED_FULL : LED_OFF;
if (!template->retain_state_suspended)
led_dat->cdev.flags |= LED_CORE_SUSPENDRESUME;
- ret = gpio_direction_output(led_dat->gpio, led_dat->active_low ^ state);
+ ret = gpiod_direction_output(led_dat->gpiod, state);
if (ret < 0)
return ret;
INIT_WORK(&led_dat->work, gpio_led_work);
- ret = led_classdev_register(parent, &led_dat->cdev);
- if (ret < 0)
- return ret;
-
- return 0;
+ return led_classdev_register(parent, &led_dat->cdev);
}
static void delete_gpio_led(struct gpio_led_data *led)
{
- if (!gpio_is_valid(led->gpio))
- return;
led_classdev_unregister(&led->cdev);
cancel_work_sync(&led->work);
}
@@ -161,40 +164,47 @@ static inline int sizeof_gpio_leds_priv(int num_leds)
(sizeof(struct gpio_led_data) * num_leds);
}
-/* Code to create from OpenFirmware platform devices */
-#ifdef CONFIG_OF_GPIO
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
+static struct gpio_leds_priv *gpio_leds_create(struct platform_device *pdev)
{
- struct device_node *np = pdev->dev.of_node, *child;
+ struct device *dev = &pdev->dev;
+ struct fwnode_handle *child;
struct gpio_leds_priv *priv;
int count, ret;
+ struct device_node *np;
- /* count LEDs in this device, so we know how much to allocate */
- count = of_get_available_child_count(np);
+ count = device_get_child_node_count(dev);
if (!count)
return ERR_PTR(-ENODEV);
- for_each_available_child_of_node(np, child)
- if (of_get_gpio(child, 0) == -EPROBE_DEFER)
- return ERR_PTR(-EPROBE_DEFER);
-
- priv = devm_kzalloc(&pdev->dev, sizeof_gpio_leds_priv(count),
- GFP_KERNEL);
+ priv = devm_kzalloc(dev, sizeof_gpio_leds_priv(count), GFP_KERNEL);
if (!priv)
return ERR_PTR(-ENOMEM);
- for_each_available_child_of_node(np, child) {
+ device_for_each_child_node(dev, child) {
struct gpio_led led = {};
- enum of_gpio_flags flags;
- const char *state;
-
- led.gpio = of_get_gpio_flags(child, 0, &flags);
- led.active_low = flags & OF_GPIO_ACTIVE_LOW;
- led.name = of_get_property(child, "label", NULL) ? : child->name;
- led.default_trigger =
- of_get_property(child, "linux,default-trigger", NULL);
- state = of_get_property(child, "default-state", NULL);
- if (state) {
+ const char *state = NULL;
+
+ led.gpiod = devm_get_gpiod_from_child(dev, child);
+ if (IS_ERR(led.gpiod)) {
+ fwnode_handle_put(child);
+ goto err;
+ }
+
+ np = of_node(child);
+
+ if (fwnode_property_present(child, "label")) {
+ fwnode_property_read_string(child, "label", &led.name);
+ } else {
+ if (IS_ENABLED(CONFIG_OF) && !led.name && np)
+ led.name = np->name;
+ if (!led.name)
+ return ERR_PTR(-EINVAL);
+ }
+ fwnode_property_read_string(child, "linux,default-trigger",
+ &led.default_trigger);
+
+ if (!fwnode_property_read_string(child, "linux,default_state",
+ &state)) {
if (!strcmp(state, "keep"))
led.default_state = LEDS_GPIO_DEFSTATE_KEEP;
else if (!strcmp(state, "on"))
@@ -203,13 +213,13 @@ static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
led.default_state = LEDS_GPIO_DEFSTATE_OFF;
}
- if (of_get_property(child, "retain-state-suspended", NULL))
+ if (fwnode_property_present(child, "retain-state-suspended"))
led.retain_state_suspended = 1;
ret = create_gpio_led(&led, &priv->leds[priv->num_leds++],
- &pdev->dev, NULL);
+ dev, NULL);
if (ret < 0) {
- of_node_put(child);
+ fwnode_handle_put(child);
goto err;
}
}
@@ -228,12 +238,6 @@ static const struct of_device_id of_gpio_leds_match[] = {
};
MODULE_DEVICE_TABLE(of, of_gpio_leds_match);
-#else /* CONFIG_OF_GPIO */
-static struct gpio_leds_priv *gpio_leds_create_of(struct platform_device *pdev)
-{
- return ERR_PTR(-ENODEV);
-}
-#endif /* CONFIG_OF_GPIO */
static int gpio_led_probe(struct platform_device *pdev)
{
@@ -261,7 +265,7 @@ static int gpio_led_probe(struct platform_device *pdev)
}
}
} else {
- priv = gpio_leds_create_of(pdev);
+ priv = gpio_leds_create(pdev);
if (IS_ERR(priv))
return PTR_ERR(priv);
}
@@ -288,7 +292,7 @@ static struct platform_driver gpio_led_driver = {
.driver = {
.name = "leds-gpio",
.owner = THIS_MODULE,
- .of_match_table = of_match_ptr(of_gpio_leds_match),
+ .of_match_table = of_gpio_leds_match,
},
};
diff --git a/drivers/lguest/lguest_device.c b/drivers/lguest/lguest_device.c
index d0a1d8a..89088d6 100644
--- a/drivers/lguest/lguest_device.c
+++ b/drivers/lguest/lguest_device.c
@@ -94,7 +94,7 @@ static unsigned desc_size(const struct lguest_device_desc *desc)
}
/* This gets the device's feature bits. */
-static u32 lg_get_features(struct virtio_device *vdev)
+static u64 lg_get_features(struct virtio_device *vdev)
{
unsigned int i;
u32 features = 0;
@@ -126,7 +126,7 @@ static void status_notify(struct virtio_device *vdev)
* sorted out, this routine is called so we can tell the Host which features we
* understand and accept.
*/
-static void lg_finalize_features(struct virtio_device *vdev)
+static int lg_finalize_features(struct virtio_device *vdev)
{
unsigned int i, bits;
struct lguest_device_desc *desc = to_lgdev(vdev)->desc;
@@ -136,20 +136,25 @@ static void lg_finalize_features(struct virtio_device *vdev)
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
+ /* Make sure we don't have any features > 32 bits! */
+ BUG_ON((u32)vdev->features != vdev->features);
+
/*
- * The vdev->feature array is a Linux bitmask: this isn't the same as a
- * the simple array of bits used by lguest devices for features. So we
- * do this slow, manual conversion which is completely general.
+ * Since lguest is currently x86-only, we're little-endian. That
+ * means we could just memcpy. But it's not time critical, and in
+ * case someone copies this code, we do it the slow, obvious way.
*/
memset(out_features, 0, desc->feature_len);
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
for (i = 0; i < bits; i++) {
- if (test_bit(i, vdev->features))
+ if (__virtio_test_bit(vdev, i))
out_features[i / 8] |= (1 << (i % 8));
}
/* Tell Host we've finished with this device's feature negotiation */
status_notify(vdev);
+
+ return 0;
}
/* Once they've found a field, getting a copy of it is easy. */
diff --git a/drivers/mailbox/Kconfig b/drivers/mailbox/Kconfig
index 9fd9c67..c04fed9 100644
--- a/drivers/mailbox/Kconfig
+++ b/drivers/mailbox/Kconfig
@@ -33,4 +33,16 @@ config OMAP_MBOX_KFIFO_SIZE
Specify the default size of mailbox's kfifo buffers (bytes).
This can also be changed at runtime (via the mbox_kfifo_size
module parameter).
+
+config PCC
+ bool "Platform Communication Channel Driver"
+ depends on ACPI
+ help
+ ACPI 5.0+ spec defines a generic mode of communication
+ between the OS and a platform such as the BMC. This medium
+ (PCC) is typically used by CPPC (ACPI CPU Performance management),
+ RAS (ACPI reliability protocol) and MPST (ACPI Memory power
+ states). Select this driver if your platform implements the
+ PCC clients mentioned above.
+
endif
diff --git a/drivers/mailbox/Makefile b/drivers/mailbox/Makefile
index 94ed7ce..dd412c2 100644
--- a/drivers/mailbox/Makefile
+++ b/drivers/mailbox/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_MAILBOX) += mailbox.o
obj-$(CONFIG_PL320_MBOX) += pl320-ipc.o
obj-$(CONFIG_OMAP2PLUS_MBOX) += omap-mailbox.o
+
+obj-$(CONFIG_PCC) += pcc.o
diff --git a/drivers/mailbox/mailbox.c b/drivers/mailbox/mailbox.c
index afcb430..59aad4d5 100644
--- a/drivers/mailbox/mailbox.c
+++ b/drivers/mailbox/mailbox.c
@@ -21,13 +21,13 @@
#include <linux/mailbox_client.h>
#include <linux/mailbox_controller.h>
-#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
-#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
-#define TXDONE_BY_ACK BIT(2) /* S/W ACK recevied by Client ticks the TX */
+#include "mailbox.h"
static LIST_HEAD(mbox_cons);
static DEFINE_MUTEX(con_mutex);
+static void poll_txdone(unsigned long data);
+
static int add_to_rbuf(struct mbox_chan *chan, void *mssg)
{
int idx;
@@ -60,7 +60,7 @@ static void msg_submit(struct mbox_chan *chan)
unsigned count, idx;
unsigned long flags;
void *data;
- int err;
+ int err = -EBUSY;
spin_lock_irqsave(&chan->lock, flags);
@@ -76,6 +76,8 @@ static void msg_submit(struct mbox_chan *chan)
data = chan->msg_data[idx];
+ if (chan->cl->tx_prepare)
+ chan->cl->tx_prepare(chan->cl, data);
/* Try to submit a message to the MBOX controller */
err = chan->mbox->ops->send_data(chan, data);
if (!err) {
@@ -84,6 +86,9 @@ static void msg_submit(struct mbox_chan *chan)
}
exit:
spin_unlock_irqrestore(&chan->lock, flags);
+
+ if (!err && chan->txdone_method == TXDONE_BY_POLL)
+ poll_txdone((unsigned long)chan->mbox);
}
static void tx_tick(struct mbox_chan *chan, int r)
@@ -117,10 +122,11 @@ static void poll_txdone(unsigned long data)
struct mbox_chan *chan = &mbox->chans[i];
if (chan->active_req && chan->cl) {
- resched = true;
txdone = chan->mbox->ops->last_tx_done(chan);
if (txdone)
tx_tick(chan, 0);
+ else
+ resched = true;
}
}
@@ -252,9 +258,6 @@ int mbox_send_message(struct mbox_chan *chan, void *mssg)
msg_submit(chan);
- if (chan->txdone_method == TXDONE_BY_POLL)
- poll_txdone((unsigned long)chan->mbox);
-
if (chan->cl->tx_block && chan->active_req) {
unsigned long wait;
int ret;
diff --git a/drivers/mailbox/mailbox.h b/drivers/mailbox/mailbox.h
new file mode 100644
index 0000000..456ba68
--- /dev/null
+++ b/drivers/mailbox/mailbox.h
@@ -0,0 +1,14 @@
+/*
+ * This program is free software; you can 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 __MAILBOX_H
+#define __MAILBOX_H
+
+#define TXDONE_BY_IRQ BIT(0) /* controller has remote RTR irq */
+#define TXDONE_BY_POLL BIT(1) /* controller can read status of last TX */
+#define TXDONE_BY_ACK BIT(2) /* S/W ACK recevied by Client ticks the TX */
+
+#endif /* __MAILBOX_H */
diff --git a/drivers/mailbox/omap-mailbox.c b/drivers/mailbox/omap-mailbox.c
index bcc7ee1..66b83ca 100644
--- a/drivers/mailbox/omap-mailbox.c
+++ b/drivers/mailbox/omap-mailbox.c
@@ -29,13 +29,14 @@
#include <linux/slab.h>
#include <linux/kfifo.h>
#include <linux/err.h>
-#include <linux/notifier.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mailbox-omap.h>
#include <linux/omap-mailbox.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
#define MAILBOX_REVISION 0x000
#define MAILBOX_MESSAGE(m) (0x040 + 4 * (m))
@@ -80,7 +81,6 @@ struct omap_mbox_queue {
spinlock_t lock;
struct kfifo fifo;
struct work_struct work;
- struct tasklet_struct tasklet;
struct omap_mbox *mbox;
bool full;
};
@@ -92,6 +92,7 @@ struct omap_mbox_device {
u32 num_users;
u32 num_fifos;
struct omap_mbox **mboxes;
+ struct mbox_controller controller;
struct list_head elem;
};
@@ -110,15 +111,14 @@ struct omap_mbox_fifo_info {
struct omap_mbox {
const char *name;
int irq;
- struct omap_mbox_queue *txq, *rxq;
+ struct omap_mbox_queue *rxq;
struct device *dev;
struct omap_mbox_device *parent;
struct omap_mbox_fifo tx_fifo;
struct omap_mbox_fifo rx_fifo;
u32 ctx[OMAP4_MBOX_NR_REGS];
u32 intr_type;
- int use_count;
- struct blocking_notifier_head notifier;
+ struct mbox_chan *chan;
};
/* global variables for the mailbox devices */
@@ -129,6 +129,14 @@ static unsigned int mbox_kfifo_size = CONFIG_OMAP_MBOX_KFIFO_SIZE;
module_param(mbox_kfifo_size, uint, S_IRUGO);
MODULE_PARM_DESC(mbox_kfifo_size, "Size of omap's mailbox kfifo (bytes)");
+static struct omap_mbox *mbox_chan_to_omap_mbox(struct mbox_chan *chan)
+{
+ if (!chan || !chan->con_priv)
+ return NULL;
+
+ return (struct omap_mbox *)chan->con_priv;
+}
+
static inline
unsigned int mbox_read_reg(struct omap_mbox_device *mdev, size_t ofs)
{
@@ -194,41 +202,14 @@ static int is_mbox_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
return (int)(enable & status & bit);
}
-/*
- * message sender
- */
-int omap_mbox_msg_send(struct omap_mbox *mbox, mbox_msg_t msg)
-{
- struct omap_mbox_queue *mq = mbox->txq;
- int ret = 0, len;
-
- spin_lock_bh(&mq->lock);
-
- if (kfifo_avail(&mq->fifo) < sizeof(msg)) {
- ret = -ENOMEM;
- goto out;
- }
-
- if (kfifo_is_empty(&mq->fifo) && !mbox_fifo_full(mbox)) {
- mbox_fifo_write(mbox, msg);
- goto out;
- }
-
- len = kfifo_in(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
- WARN_ON(len != sizeof(msg));
-
- tasklet_schedule(&mbox->txq->tasklet);
-
-out:
- spin_unlock_bh(&mq->lock);
- return ret;
-}
-EXPORT_SYMBOL(omap_mbox_msg_send);
-
-void omap_mbox_save_ctx(struct omap_mbox *mbox)
+void omap_mbox_save_ctx(struct mbox_chan *chan)
{
int i;
int nr_regs;
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+
+ if (WARN_ON(!mbox))
+ return;
if (mbox->intr_type)
nr_regs = OMAP4_MBOX_NR_REGS;
@@ -243,10 +224,14 @@ void omap_mbox_save_ctx(struct omap_mbox *mbox)
}
EXPORT_SYMBOL(omap_mbox_save_ctx);
-void omap_mbox_restore_ctx(struct omap_mbox *mbox)
+void omap_mbox_restore_ctx(struct mbox_chan *chan)
{
int i;
int nr_regs;
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+
+ if (WARN_ON(!mbox))
+ return;
if (mbox->intr_type)
nr_regs = OMAP4_MBOX_NR_REGS;
@@ -254,14 +239,13 @@ void omap_mbox_restore_ctx(struct omap_mbox *mbox)
nr_regs = MBOX_NR_REGS;
for (i = 0; i < nr_regs; i++) {
mbox_write_reg(mbox->parent, mbox->ctx[i], i * sizeof(u32));
-
dev_dbg(mbox->dev, "%s: [%02x] %08x\n", __func__,
i, mbox->ctx[i]);
}
}
EXPORT_SYMBOL(omap_mbox_restore_ctx);
-void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+static void _omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{
u32 l;
struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?
@@ -273,9 +257,8 @@ void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
l |= bit;
mbox_write_reg(mbox->parent, l, irqenable);
}
-EXPORT_SYMBOL(omap_mbox_enable_irq);
-void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
+static void _omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
{
struct omap_mbox_fifo *fifo = (irq == IRQ_TX) ?
&mbox->tx_fifo : &mbox->rx_fifo;
@@ -291,28 +274,28 @@ void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq)
mbox_write_reg(mbox->parent, bit, irqdisable);
}
-EXPORT_SYMBOL(omap_mbox_disable_irq);
-static void mbox_tx_tasklet(unsigned long tx_data)
+void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq)
{
- struct omap_mbox *mbox = (struct omap_mbox *)tx_data;
- struct omap_mbox_queue *mq = mbox->txq;
- mbox_msg_t msg;
- int ret;
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
- while (kfifo_len(&mq->fifo)) {
- if (mbox_fifo_full(mbox)) {
- omap_mbox_enable_irq(mbox, IRQ_TX);
- break;
- }
+ if (WARN_ON(!mbox))
+ return;
- ret = kfifo_out(&mq->fifo, (unsigned char *)&msg,
- sizeof(msg));
- WARN_ON(ret != sizeof(msg));
+ _omap_mbox_enable_irq(mbox, irq);
+}
+EXPORT_SYMBOL(omap_mbox_enable_irq);
- mbox_fifo_write(mbox, msg);
- }
+void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq)
+{
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+
+ if (WARN_ON(!mbox))
+ return;
+
+ _omap_mbox_disable_irq(mbox, irq);
}
+EXPORT_SYMBOL(omap_mbox_disable_irq);
/*
* Message receiver(workqueue)
@@ -328,12 +311,11 @@ static void mbox_rx_work(struct work_struct *work)
len = kfifo_out(&mq->fifo, (unsigned char *)&msg, sizeof(msg));
WARN_ON(len != sizeof(msg));
- blocking_notifier_call_chain(&mq->mbox->notifier, len,
- (void *)msg);
+ mbox_chan_received_data(mq->mbox->chan, (void *)msg);
spin_lock_irq(&mq->lock);
if (mq->full) {
mq->full = false;
- omap_mbox_enable_irq(mq->mbox, IRQ_RX);
+ _omap_mbox_enable_irq(mq->mbox, IRQ_RX);
}
spin_unlock_irq(&mq->lock);
}
@@ -344,9 +326,9 @@ static void mbox_rx_work(struct work_struct *work)
*/
static void __mbox_tx_interrupt(struct omap_mbox *mbox)
{
- omap_mbox_disable_irq(mbox, IRQ_TX);
+ _omap_mbox_disable_irq(mbox, IRQ_TX);
ack_mbox_irq(mbox, IRQ_TX);
- tasklet_schedule(&mbox->txq->tasklet);
+ mbox_chan_txdone(mbox->chan, 0);
}
static void __mbox_rx_interrupt(struct omap_mbox *mbox)
@@ -357,7 +339,7 @@ static void __mbox_rx_interrupt(struct omap_mbox *mbox)
while (!mbox_fifo_empty(mbox)) {
if (unlikely(kfifo_avail(&mq->fifo) < sizeof(msg))) {
- omap_mbox_disable_irq(mbox, IRQ_RX);
+ _omap_mbox_disable_irq(mbox, IRQ_RX);
mq->full = true;
goto nomem;
}
@@ -388,11 +370,13 @@ static irqreturn_t mbox_interrupt(int irq, void *p)
}
static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
- void (*work) (struct work_struct *),
- void (*tasklet)(unsigned long))
+ void (*work)(struct work_struct *))
{
struct omap_mbox_queue *mq;
+ if (!work)
+ return NULL;
+
mq = kzalloc(sizeof(struct omap_mbox_queue), GFP_KERNEL);
if (!mq)
return NULL;
@@ -402,12 +386,9 @@ static struct omap_mbox_queue *mbox_queue_alloc(struct omap_mbox *mbox,
if (kfifo_alloc(&mq->fifo, mbox_kfifo_size, GFP_KERNEL))
goto error;
- if (work)
- INIT_WORK(&mq->work, work);
-
- if (tasklet)
- tasklet_init(&mq->tasklet, tasklet, (unsigned long)mbox);
+ INIT_WORK(&mq->work, work);
return mq;
+
error:
kfree(mq);
return NULL;
@@ -423,71 +404,35 @@ static int omap_mbox_startup(struct omap_mbox *mbox)
{
int ret = 0;
struct omap_mbox_queue *mq;
- struct omap_mbox_device *mdev = mbox->parent;
- mutex_lock(&mdev->cfg_lock);
- ret = pm_runtime_get_sync(mdev->dev);
- if (unlikely(ret < 0))
- goto fail_startup;
-
- if (!mbox->use_count++) {
- mq = mbox_queue_alloc(mbox, NULL, mbox_tx_tasklet);
- if (!mq) {
- ret = -ENOMEM;
- goto fail_alloc_txq;
- }
- mbox->txq = mq;
+ mq = mbox_queue_alloc(mbox, mbox_rx_work);
+ if (!mq)
+ return -ENOMEM;
+ mbox->rxq = mq;
+ mq->mbox = mbox;
+
+ ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
+ mbox->name, mbox);
+ if (unlikely(ret)) {
+ pr_err("failed to register mailbox interrupt:%d\n", ret);
+ goto fail_request_irq;
+ }
- mq = mbox_queue_alloc(mbox, mbox_rx_work, NULL);
- if (!mq) {
- ret = -ENOMEM;
- goto fail_alloc_rxq;
- }
- mbox->rxq = mq;
- mq->mbox = mbox;
- ret = request_irq(mbox->irq, mbox_interrupt, IRQF_SHARED,
- mbox->name, mbox);
- if (unlikely(ret)) {
- pr_err("failed to register mailbox interrupt:%d\n",
- ret);
- goto fail_request_irq;
- }
+ _omap_mbox_enable_irq(mbox, IRQ_RX);
- omap_mbox_enable_irq(mbox, IRQ_RX);
- }
- mutex_unlock(&mdev->cfg_lock);
return 0;
fail_request_irq:
mbox_queue_free(mbox->rxq);
-fail_alloc_rxq:
- mbox_queue_free(mbox->txq);
-fail_alloc_txq:
- pm_runtime_put_sync(mdev->dev);
- mbox->use_count--;
-fail_startup:
- mutex_unlock(&mdev->cfg_lock);
return ret;
}
static void omap_mbox_fini(struct omap_mbox *mbox)
{
- struct omap_mbox_device *mdev = mbox->parent;
-
- mutex_lock(&mdev->cfg_lock);
-
- if (!--mbox->use_count) {
- omap_mbox_disable_irq(mbox, IRQ_RX);
- free_irq(mbox->irq, mbox);
- tasklet_kill(&mbox->txq->tasklet);
- flush_work(&mbox->rxq->work);
- mbox_queue_free(mbox->txq);
- mbox_queue_free(mbox->rxq);
- }
-
- pm_runtime_put_sync(mdev->dev);
-
- mutex_unlock(&mdev->cfg_lock);
+ _omap_mbox_disable_irq(mbox, IRQ_RX);
+ free_irq(mbox->irq, mbox);
+ flush_work(&mbox->rxq->work);
+ mbox_queue_free(mbox->rxq);
}
static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev,
@@ -509,42 +454,55 @@ static struct omap_mbox *omap_mbox_device_find(struct omap_mbox_device *mdev,
return mbox;
}
-struct omap_mbox *omap_mbox_get(const char *name, struct notifier_block *nb)
+struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl,
+ const char *chan_name)
{
+ struct device *dev = cl->dev;
struct omap_mbox *mbox = NULL;
struct omap_mbox_device *mdev;
+ struct mbox_chan *chan;
+ unsigned long flags;
int ret;
+ if (!dev)
+ return ERR_PTR(-ENODEV);
+
+ if (dev->of_node) {
+ pr_err("%s: please use mbox_request_channel(), this API is supported only for OMAP non-DT usage\n",
+ __func__);
+ return ERR_PTR(-ENODEV);
+ }
+
mutex_lock(&omap_mbox_devices_lock);
list_for_each_entry(mdev, &omap_mbox_devices, elem) {
- mbox = omap_mbox_device_find(mdev, name);
+ mbox = omap_mbox_device_find(mdev, chan_name);
if (mbox)
break;
}
mutex_unlock(&omap_mbox_devices_lock);
- if (!mbox)
+ if (!mbox || !mbox->chan)
return ERR_PTR(-ENOENT);
- if (nb)
- blocking_notifier_chain_register(&mbox->notifier, nb);
+ chan = mbox->chan;
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->msg_free = 0;
+ chan->msg_count = 0;
+ chan->active_req = NULL;
+ chan->cl = cl;
+ init_completion(&chan->tx_complete);
+ spin_unlock_irqrestore(&chan->lock, flags);
- ret = omap_mbox_startup(mbox);
+ ret = chan->mbox->ops->startup(chan);
if (ret) {
- blocking_notifier_chain_unregister(&mbox->notifier, nb);
- return ERR_PTR(-ENODEV);
+ pr_err("Unable to startup the chan (%d)\n", ret);
+ mbox_free_channel(chan);
+ chan = ERR_PTR(ret);
}
- return mbox;
-}
-EXPORT_SYMBOL(omap_mbox_get);
-
-void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb)
-{
- blocking_notifier_chain_unregister(&mbox->notifier, nb);
- omap_mbox_fini(mbox);
+ return chan;
}
-EXPORT_SYMBOL(omap_mbox_put);
+EXPORT_SYMBOL(omap_mbox_request_channel);
static struct class omap_mbox_class = { .name = "mbox", };
@@ -560,25 +518,25 @@ static int omap_mbox_register(struct omap_mbox_device *mdev)
mboxes = mdev->mboxes;
for (i = 0; mboxes[i]; i++) {
struct omap_mbox *mbox = mboxes[i];
- mbox->dev = device_create(&omap_mbox_class,
- mdev->dev, 0, mbox, "%s", mbox->name);
+ mbox->dev = device_create(&omap_mbox_class, mdev->dev,
+ 0, mbox, "%s", mbox->name);
if (IS_ERR(mbox->dev)) {
ret = PTR_ERR(mbox->dev);
goto err_out;
}
-
- BLOCKING_INIT_NOTIFIER_HEAD(&mbox->notifier);
}
mutex_lock(&omap_mbox_devices_lock);
list_add(&mdev->elem, &omap_mbox_devices);
mutex_unlock(&omap_mbox_devices_lock);
- return 0;
+ ret = mbox_controller_register(&mdev->controller);
err_out:
- while (i--)
- device_unregister(mboxes[i]->dev);
+ if (ret) {
+ while (i--)
+ device_unregister(mboxes[i]->dev);
+ }
return ret;
}
@@ -594,12 +552,64 @@ static int omap_mbox_unregister(struct omap_mbox_device *mdev)
list_del(&mdev->elem);
mutex_unlock(&omap_mbox_devices_lock);
+ mbox_controller_unregister(&mdev->controller);
+
mboxes = mdev->mboxes;
for (i = 0; mboxes[i]; i++)
device_unregister(mboxes[i]->dev);
return 0;
}
+static int omap_mbox_chan_startup(struct mbox_chan *chan)
+{
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+ struct omap_mbox_device *mdev = mbox->parent;
+ int ret = 0;
+
+ mutex_lock(&mdev->cfg_lock);
+ pm_runtime_get_sync(mdev->dev);
+ ret = omap_mbox_startup(mbox);
+ if (ret)
+ pm_runtime_put_sync(mdev->dev);
+ mutex_unlock(&mdev->cfg_lock);
+ return ret;
+}
+
+static void omap_mbox_chan_shutdown(struct mbox_chan *chan)
+{
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+ struct omap_mbox_device *mdev = mbox->parent;
+
+ mutex_lock(&mdev->cfg_lock);
+ omap_mbox_fini(mbox);
+ pm_runtime_put_sync(mdev->dev);
+ mutex_unlock(&mdev->cfg_lock);
+}
+
+static int omap_mbox_chan_send_data(struct mbox_chan *chan, void *data)
+{
+ struct omap_mbox *mbox = mbox_chan_to_omap_mbox(chan);
+ int ret = -EBUSY;
+
+ if (!mbox)
+ return -EINVAL;
+
+ if (!mbox_fifo_full(mbox)) {
+ mbox_fifo_write(mbox, (mbox_msg_t)data);
+ ret = 0;
+ }
+
+ /* always enable the interrupt */
+ _omap_mbox_enable_irq(mbox, IRQ_TX);
+ return ret;
+}
+
+static struct mbox_chan_ops omap_mbox_chan_ops = {
+ .startup = omap_mbox_chan_startup,
+ .send_data = omap_mbox_chan_send_data,
+ .shutdown = omap_mbox_chan_shutdown,
+};
+
static const struct of_device_id omap_mailbox_of_match[] = {
{
.compatible = "ti,omap2-mailbox",
@@ -619,10 +629,35 @@ static const struct of_device_id omap_mailbox_of_match[] = {
};
MODULE_DEVICE_TABLE(of, omap_mailbox_of_match);
+static struct mbox_chan *omap_mbox_of_xlate(struct mbox_controller *controller,
+ const struct of_phandle_args *sp)
+{
+ phandle phandle = sp->args[0];
+ struct device_node *node;
+ struct omap_mbox_device *mdev;
+ struct omap_mbox *mbox;
+
+ mdev = container_of(controller, struct omap_mbox_device, controller);
+ if (WARN_ON(!mdev))
+ return NULL;
+
+ node = of_find_node_by_phandle(phandle);
+ if (!node) {
+ pr_err("%s: could not find node phandle 0x%x\n",
+ __func__, phandle);
+ return NULL;
+ }
+
+ mbox = omap_mbox_device_find(mdev, node->name);
+ of_node_put(node);
+ return mbox ? mbox->chan : NULL;
+}
+
static int omap_mbox_probe(struct platform_device *pdev)
{
struct resource *mem;
int ret;
+ struct mbox_chan *chnls;
struct omap_mbox **list, *mbox, *mboxblk;
struct omap_mbox_pdata *pdata = pdev->dev.platform_data;
struct omap_mbox_dev_info *info = NULL;
@@ -727,6 +762,11 @@ static int omap_mbox_probe(struct platform_device *pdev)
if (!list)
return -ENOMEM;
+ chnls = devm_kzalloc(&pdev->dev, (info_count + 1) * sizeof(*chnls),
+ GFP_KERNEL);
+ if (!chnls)
+ return -ENOMEM;
+
mboxblk = devm_kzalloc(&pdev->dev, info_count * sizeof(*mbox),
GFP_KERNEL);
if (!mboxblk)
@@ -758,6 +798,8 @@ static int omap_mbox_probe(struct platform_device *pdev)
mbox->irq = platform_get_irq(pdev, finfo->tx_irq);
if (mbox->irq < 0)
return mbox->irq;
+ mbox->chan = &chnls[i];
+ chnls[i].con_priv = mbox;
list[i] = mbox++;
}
@@ -766,6 +808,14 @@ static int omap_mbox_probe(struct platform_device *pdev)
mdev->num_users = num_users;
mdev->num_fifos = num_fifos;
mdev->mboxes = list;
+
+ /* OMAP does not have a Tx-Done IRQ, but rather a Tx-Ready IRQ */
+ mdev->controller.txdone_irq = true;
+ mdev->controller.dev = mdev->dev;
+ mdev->controller.ops = &omap_mbox_chan_ops;
+ mdev->controller.chans = chnls;
+ mdev->controller.num_chans = info_count;
+ mdev->controller.of_xlate = omap_mbox_of_xlate;
ret = omap_mbox_register(mdev);
if (ret)
return ret;
diff --git a/drivers/mailbox/pcc.c b/drivers/mailbox/pcc.c
new file mode 100644
index 0000000..6dbf6fc
--- /dev/null
+++ b/drivers/mailbox/pcc.c
@@ -0,0 +1,403 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ * Author: Ashwin Chaugule <ashwin.chaugule@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * PCC (Platform Communication Channel) is defined in the ACPI 5.0+
+ * specification. It is a mailbox like mechanism to allow clients
+ * such as CPPC (Collaborative Processor Performance Control), RAS
+ * (Reliability, Availability and Serviceability) and MPST (Memory
+ * Node Power State Table) to talk to the platform (e.g. BMC) through
+ * shared memory regions as defined in the PCC table entries. The PCC
+ * specification supports a Doorbell mechanism for the PCC clients
+ * to notify the platform about new data. This Doorbell information
+ * is also specified in each PCC table entry. See pcc_send_data()
+ * and pcc_tx_done() for basic mode of operation.
+ *
+ * For more details about PCC, please see the ACPI specification from
+ * http://www.uefi.org/ACPIv5.1 Section 14.
+ *
+ * This file implements PCC as a Mailbox controller and allows for PCC
+ * clients to be implemented as its Mailbox Client Channels.
+ */
+
+#include <linux/acpi.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/init.h>
+#include <linux/list.h>
+#include <linux/platform_device.h>
+#include <linux/mailbox_controller.h>
+#include <linux/mailbox_client.h>
+
+#include "mailbox.h"
+
+#define MAX_PCC_SUBSPACES 256
+#define PCCS_SS_SIG_MAGIC 0x50434300
+#define PCC_CMD_COMPLETE 0x1
+
+static struct mbox_chan *pcc_mbox_channels;
+
+static struct mbox_controller pcc_mbox_ctrl = {};
+/**
+ * get_pcc_channel - Given a PCC subspace idx, get
+ * the respective mbox_channel.
+ * @id: PCC subspace index.
+ *
+ * Return: ERR_PTR(errno) if error, else pointer
+ * to mbox channel.
+ */
+static struct mbox_chan *get_pcc_channel(int id)
+{
+ struct mbox_chan *pcc_chan;
+
+ if (id < 0 || id > pcc_mbox_ctrl.num_chans)
+ return ERR_PTR(-ENOENT);
+
+ pcc_chan = (struct mbox_chan *)
+ (unsigned long) pcc_mbox_channels +
+ (id * sizeof(*pcc_chan));
+
+ return pcc_chan;
+}
+
+/**
+ * get_subspace_id - Given a Mailbox channel, find out the
+ * PCC subspace id.
+ * @chan: Pointer to Mailbox Channel from which we want
+ * the index.
+ * Return: Errno if not found, else positive index number.
+ */
+static int get_subspace_id(struct mbox_chan *chan)
+{
+ unsigned int id = chan - pcc_mbox_channels;
+
+ if (id < 0 || id > pcc_mbox_ctrl.num_chans)
+ return -ENOENT;
+
+ return id;
+}
+
+/**
+ * pcc_mbox_request_channel - PCC clients call this function to
+ * request a pointer to their PCC subspace, from which they
+ * can get the details of communicating with the remote.
+ * @cl: Pointer to Mailbox client, so we know where to bind the
+ * Channel.
+ * @subspace_id: The PCC Subspace index as parsed in the PCC client
+ * ACPI package. This is used to lookup the array of PCC
+ * subspaces as parsed by the PCC Mailbox controller.
+ *
+ * Return: Pointer to the Mailbox Channel if successful or
+ * ERR_PTR.
+ */
+struct mbox_chan *pcc_mbox_request_channel(struct mbox_client *cl,
+ int subspace_id)
+{
+ struct device *dev = pcc_mbox_ctrl.dev;
+ struct mbox_chan *chan;
+ unsigned long flags;
+
+ /*
+ * Each PCC Subspace is a Mailbox Channel.
+ * The PCC Clients get their PCC Subspace ID
+ * from their own tables and pass it here.
+ * This returns a pointer to the PCC subspace
+ * for the Client to operate on.
+ */
+ chan = get_pcc_channel(subspace_id);
+
+ if (!chan || chan->cl) {
+ dev_err(dev, "%s: PCC mailbox not free\n", __func__);
+ return ERR_PTR(-EBUSY);
+ }
+
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->msg_free = 0;
+ chan->msg_count = 0;
+ chan->active_req = NULL;
+ chan->cl = cl;
+ init_completion(&chan->tx_complete);
+
+ if (chan->txdone_method == TXDONE_BY_POLL && cl->knows_txdone)
+ chan->txdone_method |= TXDONE_BY_ACK;
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+
+ return chan;
+}
+EXPORT_SYMBOL_GPL(pcc_mbox_request_channel);
+
+/**
+ * pcc_mbox_free_channel - Clients call this to free their Channel.
+ *
+ * @chan: Pointer to the mailbox channel as returned by
+ * pcc_mbox_request_channel()
+ */
+void pcc_mbox_free_channel(struct mbox_chan *chan)
+{
+ unsigned long flags;
+
+ if (!chan || !chan->cl)
+ return;
+
+ spin_lock_irqsave(&chan->lock, flags);
+ chan->cl = NULL;
+ chan->active_req = NULL;
+ if (chan->txdone_method == (TXDONE_BY_POLL | TXDONE_BY_ACK))
+ chan->txdone_method = TXDONE_BY_POLL;
+
+ spin_unlock_irqrestore(&chan->lock, flags);
+}
+EXPORT_SYMBOL_GPL(pcc_mbox_free_channel);
+
+/**
+ * pcc_tx_done - Callback from Mailbox controller code to
+ * check if PCC message transmission completed.
+ * @chan: Pointer to Mailbox channel on which previous
+ * transmission occurred.
+ *
+ * Return: TRUE if succeeded.
+ */
+static bool pcc_tx_done(struct mbox_chan *chan)
+{
+ struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv;
+ struct acpi_pcct_shared_memory *generic_comm_base =
+ (struct acpi_pcct_shared_memory *) pcct_ss->base_address;
+ u16 cmd_delay = pcct_ss->latency;
+ unsigned int retries = 0;
+
+ /* Try a few times while waiting for platform to consume */
+ while (!(readw_relaxed(&generic_comm_base->status)
+ & PCC_CMD_COMPLETE)) {
+
+ if (retries++ < 5)
+ udelay(cmd_delay);
+ else {
+ /*
+ * If the remote is dead, this will cause the Mbox
+ * controller to timeout after mbox client.tx_tout
+ * msecs.
+ */
+ pr_err("PCC platform did not respond.\n");
+ return false;
+ }
+ }
+ return true;
+}
+
+/**
+ * pcc_send_data - Called from Mailbox Controller code to finally
+ * transmit data over channel.
+ * @chan: Pointer to Mailbox channel over which to send data.
+ * @data: Actual data to be written over channel.
+ *
+ * Return: Err if something failed else 0 for success.
+ */
+static int pcc_send_data(struct mbox_chan *chan, void *data)
+{
+ struct acpi_pcct_hw_reduced *pcct_ss = chan->con_priv;
+ struct acpi_pcct_shared_memory *generic_comm_base =
+ (struct acpi_pcct_shared_memory *) pcct_ss->base_address;
+ struct acpi_generic_address doorbell;
+ u64 doorbell_preserve;
+ u64 doorbell_val;
+ u64 doorbell_write;
+ u16 cmd = *(u16 *) data;
+ u16 ss_idx = -1;
+
+ ss_idx = get_subspace_id(chan);
+
+ if (ss_idx < 0) {
+ pr_err("Invalid Subspace ID from PCC client\n");
+ return -EINVAL;
+ }
+
+ doorbell = pcct_ss->doorbell_register;
+ doorbell_preserve = pcct_ss->preserve_mask;
+ doorbell_write = pcct_ss->write_mask;
+
+ /* Write to the shared comm region. */
+ writew(cmd, &generic_comm_base->command);
+
+ /* Write Subspace MAGIC value so platform can identify destination. */
+ writel((PCCS_SS_SIG_MAGIC | ss_idx), &generic_comm_base->signature);
+
+ /* Flip CMD COMPLETE bit */
+ writew(0, &generic_comm_base->status);
+
+ /* Sync notification from OSPM to Platform. */
+ acpi_read(&doorbell_val, &doorbell);
+ acpi_write((doorbell_val & doorbell_preserve) | doorbell_write,
+ &doorbell);
+
+ return 0;
+}
+
+static struct mbox_chan_ops pcc_chan_ops = {
+ .send_data = pcc_send_data,
+ .last_tx_done = pcc_tx_done,
+};
+
+/**
+ * parse_pcc_subspace - Parse the PCC table and verify PCC subspace
+ * entries. There should be one entry per PCC client.
+ * @header: Pointer to the ACPI subtable header under the PCCT.
+ * @end: End of subtable entry.
+ *
+ * Return: 0 for Success, else errno.
+ *
+ * This gets called for each entry in the PCC table.
+ */
+static int parse_pcc_subspace(struct acpi_subtable_header *header,
+ const unsigned long end)
+{
+ struct acpi_pcct_hw_reduced *pcct_ss;
+
+ if (pcc_mbox_ctrl.num_chans <= MAX_PCC_SUBSPACES) {
+ pcct_ss = (struct acpi_pcct_hw_reduced *) header;
+
+ if (pcct_ss->header.type !=
+ ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE) {
+ pr_err("Incorrect PCC Subspace type detected\n");
+ return -EINVAL;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * acpi_pcc_probe - Parse the ACPI tree for the PCCT.
+ *
+ * Return: 0 for Success, else errno.
+ */
+static int __init acpi_pcc_probe(void)
+{
+ acpi_size pcct_tbl_header_size;
+ struct acpi_table_header *pcct_tbl;
+ struct acpi_subtable_header *pcct_entry;
+ int count, i;
+ acpi_status status = AE_OK;
+
+ /* Search for PCCT */
+ status = acpi_get_table_with_size(ACPI_SIG_PCCT, 0,
+ &pcct_tbl,
+ &pcct_tbl_header_size);
+
+ if (ACPI_FAILURE(status) || !pcct_tbl) {
+ pr_warn("PCCT header not found.\n");
+ return -ENODEV;
+ }
+
+ count = acpi_table_parse_entries(ACPI_SIG_PCCT,
+ sizeof(struct acpi_table_pcct),
+ ACPI_PCCT_TYPE_HW_REDUCED_SUBSPACE,
+ parse_pcc_subspace, MAX_PCC_SUBSPACES);
+
+ if (count <= 0) {
+ pr_err("Error parsing PCC subspaces from PCCT\n");
+ return -EINVAL;
+ }
+
+ pcc_mbox_channels = kzalloc(sizeof(struct mbox_chan) *
+ count, GFP_KERNEL);
+
+ if (!pcc_mbox_channels) {
+ pr_err("Could not allocate space for PCC mbox channels\n");
+ return -ENOMEM;
+ }
+
+ /* Point to the first PCC subspace entry */
+ pcct_entry = (struct acpi_subtable_header *) (
+ (unsigned long) pcct_tbl + sizeof(struct acpi_table_pcct));
+
+ for (i = 0; i < count; i++) {
+ pcc_mbox_channels[i].con_priv = pcct_entry;
+ pcct_entry = (struct acpi_subtable_header *)
+ ((unsigned long) pcct_entry + pcct_entry->length);
+ }
+
+ pcc_mbox_ctrl.num_chans = count;
+
+ pr_info("Detected %d PCC Subspaces\n", pcc_mbox_ctrl.num_chans);
+
+ return 0;
+}
+
+/**
+ * pcc_mbox_probe - Called when we find a match for the
+ * PCCT platform device. This is purely used to represent
+ * the PCCT as a virtual device for registering with the
+ * generic Mailbox framework.
+ *
+ * @pdev: Pointer to platform device returned when a match
+ * is found.
+ *
+ * Return: 0 for Success, else errno.
+ */
+static int pcc_mbox_probe(struct platform_device *pdev)
+{
+ int ret = 0;
+
+ pcc_mbox_ctrl.chans = pcc_mbox_channels;
+ pcc_mbox_ctrl.ops = &pcc_chan_ops;
+ pcc_mbox_ctrl.txdone_poll = true;
+ pcc_mbox_ctrl.txpoll_period = 10;
+ pcc_mbox_ctrl.dev = &pdev->dev;
+
+ pr_info("Registering PCC driver as Mailbox controller\n");
+ ret = mbox_controller_register(&pcc_mbox_ctrl);
+
+ if (ret) {
+ pr_err("Err registering PCC as Mailbox controller: %d\n", ret);
+ ret = -ENODEV;
+ }
+
+ return ret;
+}
+
+struct platform_driver pcc_mbox_driver = {
+ .probe = pcc_mbox_probe,
+ .driver = {
+ .name = "PCCT",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init pcc_init(void)
+{
+ int ret;
+ struct platform_device *pcc_pdev;
+
+ if (acpi_disabled)
+ return -ENODEV;
+
+ /* Check if PCC support is available. */
+ ret = acpi_pcc_probe();
+
+ if (ret) {
+ pr_err("ACPI PCC probe failed.\n");
+ return -ENODEV;
+ }
+
+ pcc_pdev = platform_create_bundle(&pcc_mbox_driver,
+ pcc_mbox_probe, NULL, 0, NULL, 0);
+
+ if (!pcc_pdev) {
+ pr_err("Err creating PCC platform bundle\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+device_initcall(pcc_init);
diff --git a/drivers/md/dm-bio-prison.c b/drivers/md/dm-bio-prison.c
index f752d12..be06530 100644
--- a/drivers/md/dm-bio-prison.c
+++ b/drivers/md/dm-bio-prison.c
@@ -14,68 +14,38 @@
/*----------------------------------------------------------------*/
-struct bucket {
- spinlock_t lock;
- struct hlist_head cells;
-};
+#define MIN_CELLS 1024
struct dm_bio_prison {
+ spinlock_t lock;
mempool_t *cell_pool;
-
- unsigned nr_buckets;
- unsigned hash_mask;
- struct bucket *buckets;
+ struct rb_root cells;
};
-/*----------------------------------------------------------------*/
-
-static uint32_t calc_nr_buckets(unsigned nr_cells)
-{
- uint32_t n = 128;
-
- nr_cells /= 4;
- nr_cells = min(nr_cells, 8192u);
-
- while (n < nr_cells)
- n <<= 1;
-
- return n;
-}
-
static struct kmem_cache *_cell_cache;
-static void init_bucket(struct bucket *b)
-{
- spin_lock_init(&b->lock);
- INIT_HLIST_HEAD(&b->cells);
-}
+/*----------------------------------------------------------------*/
/*
* @nr_cells should be the number of cells you want in use _concurrently_.
* Don't confuse it with the number of distinct keys.
*/
-struct dm_bio_prison *dm_bio_prison_create(unsigned nr_cells)
+struct dm_bio_prison *dm_bio_prison_create(void)
{
- unsigned i;
- uint32_t nr_buckets = calc_nr_buckets(nr_cells);
- size_t len = sizeof(struct dm_bio_prison) +
- (sizeof(struct bucket) * nr_buckets);
- struct dm_bio_prison *prison = kmalloc(len, GFP_KERNEL);
+ struct dm_bio_prison *prison = kmalloc(sizeof(*prison), GFP_KERNEL);
if (!prison)
return NULL;
- prison->cell_pool = mempool_create_slab_pool(nr_cells, _cell_cache);
+ spin_lock_init(&prison->lock);
+
+ prison->cell_pool = mempool_create_slab_pool(MIN_CELLS, _cell_cache);
if (!prison->cell_pool) {
kfree(prison);
return NULL;
}
- prison->nr_buckets = nr_buckets;
- prison->hash_mask = nr_buckets - 1;
- prison->buckets = (struct bucket *) (prison + 1);
- for (i = 0; i < nr_buckets; i++)
- init_bucket(prison->buckets + i);
+ prison->cells = RB_ROOT;
return prison;
}
@@ -101,68 +71,73 @@ void dm_bio_prison_free_cell(struct dm_bio_prison *prison,
}
EXPORT_SYMBOL_GPL(dm_bio_prison_free_cell);
-static uint32_t hash_key(struct dm_bio_prison *prison, struct dm_cell_key *key)
+static void __setup_new_cell(struct dm_cell_key *key,
+ struct bio *holder,
+ struct dm_bio_prison_cell *cell)
{
- const unsigned long BIG_PRIME = 4294967291UL;
- uint64_t hash = key->block * BIG_PRIME;
-
- return (uint32_t) (hash & prison->hash_mask);
+ memcpy(&cell->key, key, sizeof(cell->key));
+ cell->holder = holder;
+ bio_list_init(&cell->bios);
}
-static int keys_equal(struct dm_cell_key *lhs, struct dm_cell_key *rhs)
+static int cmp_keys(struct dm_cell_key *lhs,
+ struct dm_cell_key *rhs)
{
- return (lhs->virtual == rhs->virtual) &&
- (lhs->dev == rhs->dev) &&
- (lhs->block == rhs->block);
-}
+ if (lhs->virtual < rhs->virtual)
+ return -1;
-static struct bucket *get_bucket(struct dm_bio_prison *prison,
- struct dm_cell_key *key)
-{
- return prison->buckets + hash_key(prison, key);
-}
+ if (lhs->virtual > rhs->virtual)
+ return 1;
-static struct dm_bio_prison_cell *__search_bucket(struct bucket *b,
- struct dm_cell_key *key)
-{
- struct dm_bio_prison_cell *cell;
+ if (lhs->dev < rhs->dev)
+ return -1;
- hlist_for_each_entry(cell, &b->cells, list)
- if (keys_equal(&cell->key, key))
- return cell;
+ if (lhs->dev > rhs->dev)
+ return 1;
- return NULL;
-}
+ if (lhs->block_end <= rhs->block_begin)
+ return -1;
-static void __setup_new_cell(struct bucket *b,
- struct dm_cell_key *key,
- struct bio *holder,
- struct dm_bio_prison_cell *cell)
-{
- memcpy(&cell->key, key, sizeof(cell->key));
- cell->holder = holder;
- bio_list_init(&cell->bios);
- hlist_add_head(&cell->list, &b->cells);
+ if (lhs->block_begin >= rhs->block_end)
+ return 1;
+
+ return 0;
}
-static int __bio_detain(struct bucket *b,
+static int __bio_detain(struct dm_bio_prison *prison,
struct dm_cell_key *key,
struct bio *inmate,
struct dm_bio_prison_cell *cell_prealloc,
struct dm_bio_prison_cell **cell_result)
{
- struct dm_bio_prison_cell *cell;
-
- cell = __search_bucket(b, key);
- if (cell) {
- if (inmate)
- bio_list_add(&cell->bios, inmate);
- *cell_result = cell;
- return 1;
+ int r;
+ struct rb_node **new = &prison->cells.rb_node, *parent = NULL;
+
+ while (*new) {
+ struct dm_bio_prison_cell *cell =
+ container_of(*new, struct dm_bio_prison_cell, node);
+
+ r = cmp_keys(key, &cell->key);
+
+ parent = *new;
+ if (r < 0)
+ new = &((*new)->rb_left);
+ else if (r > 0)
+ new = &((*new)->rb_right);
+ else {
+ if (inmate)
+ bio_list_add(&cell->bios, inmate);
+ *cell_result = cell;
+ return 1;
+ }
}
- __setup_new_cell(b, key, inmate, cell_prealloc);
+ __setup_new_cell(key, inmate, cell_prealloc);
*cell_result = cell_prealloc;
+
+ rb_link_node(&cell_prealloc->node, parent, new);
+ rb_insert_color(&cell_prealloc->node, &prison->cells);
+
return 0;
}
@@ -174,11 +149,10 @@ static int bio_detain(struct dm_bio_prison *prison,
{
int r;
unsigned long flags;
- struct bucket *b = get_bucket(prison, key);
- spin_lock_irqsave(&b->lock, flags);
- r = __bio_detain(b, key, inmate, cell_prealloc, cell_result);
- spin_unlock_irqrestore(&b->lock, flags);
+ spin_lock_irqsave(&prison->lock, flags);
+ r = __bio_detain(prison, key, inmate, cell_prealloc, cell_result);
+ spin_unlock_irqrestore(&prison->lock, flags);
return r;
}
@@ -205,10 +179,11 @@ EXPORT_SYMBOL_GPL(dm_get_cell);
/*
* @inmates must have been initialised prior to this call
*/
-static void __cell_release(struct dm_bio_prison_cell *cell,
+static void __cell_release(struct dm_bio_prison *prison,
+ struct dm_bio_prison_cell *cell,
struct bio_list *inmates)
{
- hlist_del(&cell->list);
+ rb_erase(&cell->node, &prison->cells);
if (inmates) {
if (cell->holder)
@@ -222,21 +197,21 @@ void dm_cell_release(struct dm_bio_prison *prison,
struct bio_list *bios)
{
unsigned long flags;
- struct bucket *b = get_bucket(prison, &cell->key);
- spin_lock_irqsave(&b->lock, flags);
- __cell_release(cell, bios);
- spin_unlock_irqrestore(&b->lock, flags);
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release(prison, cell, bios);
+ spin_unlock_irqrestore(&prison->lock, flags);
}
EXPORT_SYMBOL_GPL(dm_cell_release);
/*
* Sometimes we don't want the holder, just the additional bios.
*/
-static void __cell_release_no_holder(struct dm_bio_prison_cell *cell,
+static void __cell_release_no_holder(struct dm_bio_prison *prison,
+ struct dm_bio_prison_cell *cell,
struct bio_list *inmates)
{
- hlist_del(&cell->list);
+ rb_erase(&cell->node, &prison->cells);
bio_list_merge(inmates, &cell->bios);
}
@@ -245,11 +220,10 @@ void dm_cell_release_no_holder(struct dm_bio_prison *prison,
struct bio_list *inmates)
{
unsigned long flags;
- struct bucket *b = get_bucket(prison, &cell->key);
- spin_lock_irqsave(&b->lock, flags);
- __cell_release_no_holder(cell, inmates);
- spin_unlock_irqrestore(&b->lock, flags);
+ spin_lock_irqsave(&prison->lock, flags);
+ __cell_release_no_holder(prison, cell, inmates);
+ spin_unlock_irqrestore(&prison->lock, flags);
}
EXPORT_SYMBOL_GPL(dm_cell_release_no_holder);
@@ -267,6 +241,20 @@ void dm_cell_error(struct dm_bio_prison *prison,
}
EXPORT_SYMBOL_GPL(dm_cell_error);
+void dm_cell_visit_release(struct dm_bio_prison *prison,
+ void (*visit_fn)(void *, struct dm_bio_prison_cell *),
+ void *context,
+ struct dm_bio_prison_cell *cell)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&prison->lock, flags);
+ visit_fn(context, cell);
+ rb_erase(&cell->node, &prison->cells);
+ spin_unlock_irqrestore(&prison->lock, flags);
+}
+EXPORT_SYMBOL_GPL(dm_cell_visit_release);
+
/*----------------------------------------------------------------*/
#define DEFERRED_SET_SIZE 64
diff --git a/drivers/md/dm-bio-prison.h b/drivers/md/dm-bio-prison.h
index 6805a14..74cf011 100644
--- a/drivers/md/dm-bio-prison.h
+++ b/drivers/md/dm-bio-prison.h
@@ -10,8 +10,8 @@
#include "persistent-data/dm-block-manager.h" /* FIXME: for dm_block_t */
#include "dm-thin-metadata.h" /* FIXME: for dm_thin_id */
-#include <linux/list.h>
#include <linux/bio.h>
+#include <linux/rbtree.h>
/*----------------------------------------------------------------*/
@@ -23,11 +23,14 @@
*/
struct dm_bio_prison;
-/* FIXME: this needs to be more abstract */
+/*
+ * Keys define a range of blocks within either a virtual or physical
+ * device.
+ */
struct dm_cell_key {
int virtual;
dm_thin_id dev;
- dm_block_t block;
+ dm_block_t block_begin, block_end;
};
/*
@@ -35,13 +38,15 @@ struct dm_cell_key {
* themselves.
*/
struct dm_bio_prison_cell {
- struct hlist_node list;
+ struct list_head user_list; /* for client use */
+ struct rb_node node;
+
struct dm_cell_key key;
struct bio *holder;
struct bio_list bios;
};
-struct dm_bio_prison *dm_bio_prison_create(unsigned nr_cells);
+struct dm_bio_prison *dm_bio_prison_create(void);
void dm_bio_prison_destroy(struct dm_bio_prison *prison);
/*
@@ -57,7 +62,7 @@ void dm_bio_prison_free_cell(struct dm_bio_prison *prison,
struct dm_bio_prison_cell *cell);
/*
- * Creates, or retrieves a cell for the given key.
+ * Creates, or retrieves a cell that overlaps the given key.
*
* Returns 1 if pre-existing cell returned, zero if new cell created using
* @cell_prealloc.
@@ -68,7 +73,8 @@ int dm_get_cell(struct dm_bio_prison *prison,
struct dm_bio_prison_cell **cell_result);
/*
- * An atomic op that combines retrieving a cell, and adding a bio to it.
+ * An atomic op that combines retrieving or creating a cell, and adding a
+ * bio to it.
*
* Returns 1 if the cell was already held, 0 if @inmate is the new holder.
*/
@@ -87,6 +93,14 @@ void dm_cell_release_no_holder(struct dm_bio_prison *prison,
void dm_cell_error(struct dm_bio_prison *prison,
struct dm_bio_prison_cell *cell, int error);
+/*
+ * Visits the cell and then releases. Guarantees no new inmates are
+ * inserted between the visit and release.
+ */
+void dm_cell_visit_release(struct dm_bio_prison *prison,
+ void (*visit_fn)(void *, struct dm_bio_prison_cell *),
+ void *context, struct dm_bio_prison_cell *cell);
+
/*----------------------------------------------------------------*/
/*
diff --git a/drivers/md/dm-bufio.c b/drivers/md/dm-bufio.c
index afe7971..c33b497 100644
--- a/drivers/md/dm-bufio.c
+++ b/drivers/md/dm-bufio.c
@@ -14,6 +14,7 @@
#include <linux/vmalloc.h>
#include <linux/shrinker.h>
#include <linux/module.h>
+#include <linux/rbtree.h>
#define DM_MSG_PREFIX "bufio"
@@ -34,26 +35,23 @@
/*
* Check buffer ages in this interval (seconds)
*/
-#define DM_BUFIO_WORK_TIMER_SECS 10
+#define DM_BUFIO_WORK_TIMER_SECS 30
/*
* Free buffers when they are older than this (seconds)
*/
-#define DM_BUFIO_DEFAULT_AGE_SECS 60
+#define DM_BUFIO_DEFAULT_AGE_SECS 300
/*
- * The number of bvec entries that are embedded directly in the buffer.
- * If the chunk size is larger, dm-io is used to do the io.
+ * The nr of bytes of cached data to keep around.
*/
-#define DM_BUFIO_INLINE_VECS 16
+#define DM_BUFIO_DEFAULT_RETAIN_BYTES (256 * 1024)
/*
- * Buffer hash
+ * The number of bvec entries that are embedded directly in the buffer.
+ * If the chunk size is larger, dm-io is used to do the io.
*/
-#define DM_BUFIO_HASH_BITS 20
-#define DM_BUFIO_HASH(block) \
- ((((block) >> DM_BUFIO_HASH_BITS) ^ (block)) & \
- ((1 << DM_BUFIO_HASH_BITS) - 1))
+#define DM_BUFIO_INLINE_VECS 16
/*
* Don't try to use kmem_cache_alloc for blocks larger than this.
@@ -106,7 +104,7 @@ struct dm_bufio_client {
unsigned minimum_buffers;
- struct hlist_head *cache_hash;
+ struct rb_root buffer_tree;
wait_queue_head_t free_buffer_wait;
int async_write_error;
@@ -135,7 +133,7 @@ enum data_mode {
};
struct dm_buffer {
- struct hlist_node hash_list;
+ struct rb_node node;
struct list_head lru_list;
sector_t block;
void *data;
@@ -223,6 +221,7 @@ static DEFINE_SPINLOCK(param_spinlock);
* Buffers are freed after this timeout
*/
static unsigned dm_bufio_max_age = DM_BUFIO_DEFAULT_AGE_SECS;
+static unsigned dm_bufio_retain_bytes = DM_BUFIO_DEFAULT_RETAIN_BYTES;
static unsigned long dm_bufio_peak_allocated;
static unsigned long dm_bufio_allocated_kmem_cache;
@@ -253,6 +252,53 @@ static LIST_HEAD(dm_bufio_all_clients);
*/
static DEFINE_MUTEX(dm_bufio_clients_lock);
+/*----------------------------------------------------------------
+ * A red/black tree acts as an index for all the buffers.
+ *--------------------------------------------------------------*/
+static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
+{
+ struct rb_node *n = c->buffer_tree.rb_node;
+ struct dm_buffer *b;
+
+ while (n) {
+ b = container_of(n, struct dm_buffer, node);
+
+ if (b->block == block)
+ return b;
+
+ n = (b->block < block) ? n->rb_left : n->rb_right;
+ }
+
+ return NULL;
+}
+
+static void __insert(struct dm_bufio_client *c, struct dm_buffer *b)
+{
+ struct rb_node **new = &c->buffer_tree.rb_node, *parent = NULL;
+ struct dm_buffer *found;
+
+ while (*new) {
+ found = container_of(*new, struct dm_buffer, node);
+
+ if (found->block == b->block) {
+ BUG_ON(found != b);
+ return;
+ }
+
+ parent = *new;
+ new = (found->block < b->block) ?
+ &((*new)->rb_left) : &((*new)->rb_right);
+ }
+
+ rb_link_node(&b->node, parent, new);
+ rb_insert_color(&b->node, &c->buffer_tree);
+}
+
+static void __remove(struct dm_bufio_client *c, struct dm_buffer *b)
+{
+ rb_erase(&b->node, &c->buffer_tree);
+}
+
/*----------------------------------------------------------------*/
static void adjust_total_allocated(enum data_mode data_mode, long diff)
@@ -434,7 +480,7 @@ static void __link_buffer(struct dm_buffer *b, sector_t block, int dirty)
b->block = block;
b->list_mode = dirty;
list_add(&b->lru_list, &c->lru[dirty]);
- hlist_add_head(&b->hash_list, &c->cache_hash[DM_BUFIO_HASH(block)]);
+ __insert(b->c, b);
b->last_accessed = jiffies;
}
@@ -448,7 +494,7 @@ static void __unlink_buffer(struct dm_buffer *b)
BUG_ON(!c->n_buffers[b->list_mode]);
c->n_buffers[b->list_mode]--;
- hlist_del(&b->hash_list);
+ __remove(b->c, b);
list_del(&b->lru_list);
}
@@ -532,6 +578,19 @@ static void use_dmio(struct dm_buffer *b, int rw, sector_t block,
end_io(&b->bio, r);
}
+static void inline_endio(struct bio *bio, int error)
+{
+ bio_end_io_t *end_fn = bio->bi_private;
+
+ /*
+ * Reset the bio to free any attached resources
+ * (e.g. bio integrity profiles).
+ */
+ bio_reset(bio);
+
+ end_fn(bio, error);
+}
+
static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block,
bio_end_io_t *end_io)
{
@@ -543,7 +602,12 @@ static void use_inline_bio(struct dm_buffer *b, int rw, sector_t block,
b->bio.bi_max_vecs = DM_BUFIO_INLINE_VECS;
b->bio.bi_iter.bi_sector = block << b->c->sectors_per_block_bits;
b->bio.bi_bdev = b->c->bdev;
- b->bio.bi_end_io = end_io;
+ b->bio.bi_end_io = inline_endio;
+ /*
+ * Use of .bi_private isn't a problem here because
+ * the dm_buffer's inline bio is local to bufio.
+ */
+ b->bio.bi_private = end_io;
/*
* We assume that if len >= PAGE_SIZE ptr is page-aligned.
@@ -887,23 +951,6 @@ static void __check_watermark(struct dm_bufio_client *c,
__write_dirty_buffers_async(c, 1, write_list);
}
-/*
- * Find a buffer in the hash.
- */
-static struct dm_buffer *__find(struct dm_bufio_client *c, sector_t block)
-{
- struct dm_buffer *b;
-
- hlist_for_each_entry(b, &c->cache_hash[DM_BUFIO_HASH(block)],
- hash_list) {
- dm_bufio_cond_resched();
- if (b->block == block)
- return b;
- }
-
- return NULL;
-}
-
/*----------------------------------------------------------------
* Getting a buffer
*--------------------------------------------------------------*/
@@ -1433,45 +1480,52 @@ static void drop_buffers(struct dm_bufio_client *c)
}
/*
- * Test if the buffer is unused and too old, and commit it.
+ * We may not be able to evict this buffer if IO pending or the client
+ * is still using it. Caller is expected to know buffer is too old.
+ *
* And if GFP_NOFS is used, we must not do any I/O because we hold
* dm_bufio_clients_lock and we would risk deadlock if the I/O gets
* rerouted to different bufio client.
*/
-static int __cleanup_old_buffer(struct dm_buffer *b, gfp_t gfp,
- unsigned long max_jiffies)
+static bool __try_evict_buffer(struct dm_buffer *b, gfp_t gfp)
{
- if (jiffies - b->last_accessed < max_jiffies)
- return 0;
-
if (!(gfp & __GFP_FS)) {
if (test_bit(B_READING, &b->state) ||
test_bit(B_WRITING, &b->state) ||
test_bit(B_DIRTY, &b->state))
- return 0;
+ return false;
}
if (b->hold_count)
- return 0;
+ return false;
__make_buffer_clean(b);
__unlink_buffer(b);
__free_buffer_wake(b);
- return 1;
+ return true;
}
-static long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
- gfp_t gfp_mask)
+static unsigned get_retain_buffers(struct dm_bufio_client *c)
+{
+ unsigned retain_bytes = ACCESS_ONCE(dm_bufio_retain_bytes);
+ return retain_bytes / c->block_size;
+}
+
+static unsigned long __scan(struct dm_bufio_client *c, unsigned long nr_to_scan,
+ gfp_t gfp_mask)
{
int l;
struct dm_buffer *b, *tmp;
- long freed = 0;
+ unsigned long freed = 0;
+ unsigned long count = nr_to_scan;
+ unsigned retain_target = get_retain_buffers(c);
for (l = 0; l < LIST_SIZE; l++) {
list_for_each_entry_safe_reverse(b, tmp, &c->lru[l], lru_list) {
- freed += __cleanup_old_buffer(b, gfp_mask, 0);
- if (!--nr_to_scan)
+ if (__try_evict_buffer(b, gfp_mask))
+ freed++;
+ if (!--nr_to_scan || ((count - freed) <= retain_target))
return freed;
dm_bufio_cond_resched();
}
@@ -1533,11 +1587,7 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
r = -ENOMEM;
goto bad_client;
}
- c->cache_hash = vmalloc(sizeof(struct hlist_head) << DM_BUFIO_HASH_BITS);
- if (!c->cache_hash) {
- r = -ENOMEM;
- goto bad_hash;
- }
+ c->buffer_tree = RB_ROOT;
c->bdev = bdev;
c->block_size = block_size;
@@ -1556,9 +1606,6 @@ struct dm_bufio_client *dm_bufio_client_create(struct block_device *bdev, unsign
c->n_buffers[i] = 0;
}
- for (i = 0; i < 1 << DM_BUFIO_HASH_BITS; i++)
- INIT_HLIST_HEAD(&c->cache_hash[i]);
-
mutex_init(&c->lock);
INIT_LIST_HEAD(&c->reserved_buffers);
c->need_reserved_buffers = reserved_buffers;
@@ -1632,8 +1679,6 @@ bad_cache:
}
dm_io_client_destroy(c->dm_io);
bad_dm_io:
- vfree(c->cache_hash);
-bad_hash:
kfree(c);
bad_client:
return ERR_PTR(r);
@@ -1660,9 +1705,7 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
mutex_unlock(&dm_bufio_clients_lock);
- for (i = 0; i < 1 << DM_BUFIO_HASH_BITS; i++)
- BUG_ON(!hlist_empty(&c->cache_hash[i]));
-
+ BUG_ON(!RB_EMPTY_ROOT(&c->buffer_tree));
BUG_ON(c->need_reserved_buffers);
while (!list_empty(&c->reserved_buffers)) {
@@ -1680,36 +1723,60 @@ void dm_bufio_client_destroy(struct dm_bufio_client *c)
BUG_ON(c->n_buffers[i]);
dm_io_client_destroy(c->dm_io);
- vfree(c->cache_hash);
kfree(c);
}
EXPORT_SYMBOL_GPL(dm_bufio_client_destroy);
-static void cleanup_old_buffers(void)
+static unsigned get_max_age_hz(void)
{
- unsigned long max_age = ACCESS_ONCE(dm_bufio_max_age);
- struct dm_bufio_client *c;
+ unsigned max_age = ACCESS_ONCE(dm_bufio_max_age);
- if (max_age > ULONG_MAX / HZ)
- max_age = ULONG_MAX / HZ;
+ if (max_age > UINT_MAX / HZ)
+ max_age = UINT_MAX / HZ;
- mutex_lock(&dm_bufio_clients_lock);
- list_for_each_entry(c, &dm_bufio_all_clients, client_list) {
- if (!dm_bufio_trylock(c))
- continue;
+ return max_age * HZ;
+}
- while (!list_empty(&c->lru[LIST_CLEAN])) {
- struct dm_buffer *b;
- b = list_entry(c->lru[LIST_CLEAN].prev,
- struct dm_buffer, lru_list);
- if (!__cleanup_old_buffer(b, 0, max_age * HZ))
- break;
- dm_bufio_cond_resched();
- }
+static bool older_than(struct dm_buffer *b, unsigned long age_hz)
+{
+ return (jiffies - b->last_accessed) >= age_hz;
+}
+
+static void __evict_old_buffers(struct dm_bufio_client *c, unsigned long age_hz)
+{
+ struct dm_buffer *b, *tmp;
+ unsigned retain_target = get_retain_buffers(c);
+ unsigned count;
+
+ dm_bufio_lock(c);
+
+ count = c->n_buffers[LIST_CLEAN] + c->n_buffers[LIST_DIRTY];
+ list_for_each_entry_safe_reverse(b, tmp, &c->lru[LIST_CLEAN], lru_list) {
+ if (count <= retain_target)
+ break;
+
+ if (!older_than(b, age_hz))
+ break;
+
+ if (__try_evict_buffer(b, 0))
+ count--;
- dm_bufio_unlock(c);
dm_bufio_cond_resched();
}
+
+ dm_bufio_unlock(c);
+}
+
+static void cleanup_old_buffers(void)
+{
+ unsigned long max_age_hz = get_max_age_hz();
+ struct dm_bufio_client *c;
+
+ mutex_lock(&dm_bufio_clients_lock);
+
+ list_for_each_entry(c, &dm_bufio_all_clients, client_list)
+ __evict_old_buffers(c, max_age_hz);
+
mutex_unlock(&dm_bufio_clients_lock);
}
@@ -1834,6 +1901,9 @@ MODULE_PARM_DESC(max_cache_size_bytes, "Size of metadata cache");
module_param_named(max_age_seconds, dm_bufio_max_age, uint, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(max_age_seconds, "Max age of a buffer in seconds");
+module_param_named(retain_bytes, dm_bufio_retain_bytes, uint, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(retain_bytes, "Try to keep at least this many bytes cached in memory");
+
module_param_named(peak_allocated_bytes, dm_bufio_peak_allocated, ulong, S_IRUGO | S_IWUSR);
MODULE_PARM_DESC(peak_allocated_bytes, "Tracks the maximum allocated memory");
diff --git a/drivers/md/dm-cache-block-types.h b/drivers/md/dm-cache-block-types.h
index aac0e2d..bed4ad4 100644
--- a/drivers/md/dm-cache-block-types.h
+++ b/drivers/md/dm-cache-block-types.h
@@ -19,6 +19,7 @@
typedef dm_block_t __bitwise__ dm_oblock_t;
typedef uint32_t __bitwise__ dm_cblock_t;
+typedef dm_block_t __bitwise__ dm_dblock_t;
static inline dm_oblock_t to_oblock(dm_block_t b)
{
@@ -40,4 +41,14 @@ static inline uint32_t from_cblock(dm_cblock_t b)
return (__force uint32_t) b;
}
+static inline dm_dblock_t to_dblock(dm_block_t b)
+{
+ return (__force dm_dblock_t) b;
+}
+
+static inline dm_block_t from_dblock(dm_dblock_t b)
+{
+ return (__force dm_block_t) b;
+}
+
#endif /* DM_CACHE_BLOCK_TYPES_H */
diff --git a/drivers/md/dm-cache-metadata.c b/drivers/md/dm-cache-metadata.c
index 0670925..9fc616c 100644
--- a/drivers/md/dm-cache-metadata.c
+++ b/drivers/md/dm-cache-metadata.c
@@ -109,7 +109,7 @@ struct dm_cache_metadata {
dm_block_t discard_root;
sector_t discard_block_size;
- dm_oblock_t discard_nr_blocks;
+ dm_dblock_t discard_nr_blocks;
sector_t data_block_size;
dm_cblock_t cache_blocks;
@@ -329,7 +329,7 @@ static int __write_initial_superblock(struct dm_cache_metadata *cmd)
disk_super->hint_root = cpu_to_le64(cmd->hint_root);
disk_super->discard_root = cpu_to_le64(cmd->discard_root);
disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size);
- disk_super->discard_nr_blocks = cpu_to_le64(from_oblock(cmd->discard_nr_blocks));
+ disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks));
disk_super->metadata_block_size = cpu_to_le32(DM_CACHE_METADATA_BLOCK_SIZE);
disk_super->data_block_size = cpu_to_le32(cmd->data_block_size);
disk_super->cache_blocks = cpu_to_le32(0);
@@ -528,7 +528,7 @@ static void read_superblock_fields(struct dm_cache_metadata *cmd,
cmd->hint_root = le64_to_cpu(disk_super->hint_root);
cmd->discard_root = le64_to_cpu(disk_super->discard_root);
cmd->discard_block_size = le64_to_cpu(disk_super->discard_block_size);
- cmd->discard_nr_blocks = to_oblock(le64_to_cpu(disk_super->discard_nr_blocks));
+ cmd->discard_nr_blocks = to_dblock(le64_to_cpu(disk_super->discard_nr_blocks));
cmd->data_block_size = le32_to_cpu(disk_super->data_block_size);
cmd->cache_blocks = to_cblock(le32_to_cpu(disk_super->cache_blocks));
strncpy(cmd->policy_name, disk_super->policy_name, sizeof(cmd->policy_name));
@@ -626,7 +626,7 @@ static int __commit_transaction(struct dm_cache_metadata *cmd,
disk_super->hint_root = cpu_to_le64(cmd->hint_root);
disk_super->discard_root = cpu_to_le64(cmd->discard_root);
disk_super->discard_block_size = cpu_to_le64(cmd->discard_block_size);
- disk_super->discard_nr_blocks = cpu_to_le64(from_oblock(cmd->discard_nr_blocks));
+ disk_super->discard_nr_blocks = cpu_to_le64(from_dblock(cmd->discard_nr_blocks));
disk_super->cache_blocks = cpu_to_le32(from_cblock(cmd->cache_blocks));
strncpy(disk_super->policy_name, cmd->policy_name, sizeof(disk_super->policy_name));
disk_super->policy_version[0] = cpu_to_le32(cmd->policy_version[0]);
@@ -797,15 +797,15 @@ out:
int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
sector_t discard_block_size,
- dm_oblock_t new_nr_entries)
+ dm_dblock_t new_nr_entries)
{
int r;
down_write(&cmd->root_lock);
r = dm_bitset_resize(&cmd->discard_info,
cmd->discard_root,
- from_oblock(cmd->discard_nr_blocks),
- from_oblock(new_nr_entries),
+ from_dblock(cmd->discard_nr_blocks),
+ from_dblock(new_nr_entries),
false, &cmd->discard_root);
if (!r) {
cmd->discard_block_size = discard_block_size;
@@ -818,28 +818,28 @@ int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
return r;
}
-static int __set_discard(struct dm_cache_metadata *cmd, dm_oblock_t b)
+static int __set_discard(struct dm_cache_metadata *cmd, dm_dblock_t b)
{
return dm_bitset_set_bit(&cmd->discard_info, cmd->discard_root,
- from_oblock(b), &cmd->discard_root);
+ from_dblock(b), &cmd->discard_root);
}
-static int __clear_discard(struct dm_cache_metadata *cmd, dm_oblock_t b)
+static int __clear_discard(struct dm_cache_metadata *cmd, dm_dblock_t b)
{
return dm_bitset_clear_bit(&cmd->discard_info, cmd->discard_root,
- from_oblock(b), &cmd->discard_root);
+ from_dblock(b), &cmd->discard_root);
}
-static int __is_discarded(struct dm_cache_metadata *cmd, dm_oblock_t b,
+static int __is_discarded(struct dm_cache_metadata *cmd, dm_dblock_t b,
bool *is_discarded)
{
return dm_bitset_test_bit(&cmd->discard_info, cmd->discard_root,
- from_oblock(b), &cmd->discard_root,
+ from_dblock(b), &cmd->discard_root,
is_discarded);
}
static int __discard(struct dm_cache_metadata *cmd,
- dm_oblock_t dblock, bool discard)
+ dm_dblock_t dblock, bool discard)
{
int r;
@@ -852,7 +852,7 @@ static int __discard(struct dm_cache_metadata *cmd,
}
int dm_cache_set_discard(struct dm_cache_metadata *cmd,
- dm_oblock_t dblock, bool discard)
+ dm_dblock_t dblock, bool discard)
{
int r;
@@ -870,8 +870,8 @@ static int __load_discards(struct dm_cache_metadata *cmd,
dm_block_t b;
bool discard;
- for (b = 0; b < from_oblock(cmd->discard_nr_blocks); b++) {
- dm_oblock_t dblock = to_oblock(b);
+ for (b = 0; b < from_dblock(cmd->discard_nr_blocks); b++) {
+ dm_dblock_t dblock = to_dblock(b);
if (cmd->clean_when_opened) {
r = __is_discarded(cmd, dblock, &discard);
diff --git a/drivers/md/dm-cache-metadata.h b/drivers/md/dm-cache-metadata.h
index 7383c90..4ecc403 100644
--- a/drivers/md/dm-cache-metadata.h
+++ b/drivers/md/dm-cache-metadata.h
@@ -70,14 +70,14 @@ dm_cblock_t dm_cache_size(struct dm_cache_metadata *cmd);
int dm_cache_discard_bitset_resize(struct dm_cache_metadata *cmd,
sector_t discard_block_size,
- dm_oblock_t new_nr_entries);
+ dm_dblock_t new_nr_entries);
typedef int (*load_discard_fn)(void *context, sector_t discard_block_size,
- dm_oblock_t dblock, bool discarded);
+ dm_dblock_t dblock, bool discarded);
int dm_cache_load_discards(struct dm_cache_metadata *cmd,
load_discard_fn fn, void *context);
-int dm_cache_set_discard(struct dm_cache_metadata *cmd, dm_oblock_t dblock, bool discard);
+int dm_cache_set_discard(struct dm_cache_metadata *cmd, dm_dblock_t dblock, bool discard);
int dm_cache_remove_mapping(struct dm_cache_metadata *cmd, dm_cblock_t cblock);
int dm_cache_insert_mapping(struct dm_cache_metadata *cmd, dm_cblock_t cblock, dm_oblock_t oblock);
diff --git a/drivers/md/dm-cache-policy-mq.c b/drivers/md/dm-cache-policy-mq.c
index 0e385e4..13f547a 100644
--- a/drivers/md/dm-cache-policy-mq.c
+++ b/drivers/md/dm-cache-policy-mq.c
@@ -181,24 +181,30 @@ static void queue_shift_down(struct queue *q)
* Gives us the oldest entry of the lowest popoulated level. If the first
* level is emptied then we shift down one level.
*/
-static struct list_head *queue_pop(struct queue *q)
+static struct list_head *queue_peek(struct queue *q)
{
unsigned level;
- struct list_head *r;
for (level = 0; level < NR_QUEUE_LEVELS; level++)
- if (!list_empty(q->qs + level)) {
- r = q->qs[level].next;
- list_del(r);
+ if (!list_empty(q->qs + level))
+ return q->qs[level].next;
- /* have we just emptied the bottom level? */
- if (level == 0 && list_empty(q->qs))
- queue_shift_down(q);
+ return NULL;
+}
- return r;
- }
+static struct list_head *queue_pop(struct queue *q)
+{
+ struct list_head *r = queue_peek(q);
- return NULL;
+ if (r) {
+ list_del(r);
+
+ /* have we just emptied the bottom level? */
+ if (list_empty(q->qs))
+ queue_shift_down(q);
+ }
+
+ return r;
}
static struct list_head *list_pop(struct list_head *lh)
@@ -383,13 +389,6 @@ struct mq_policy {
unsigned generation;
unsigned generation_period; /* in lookups (will probably change) */
- /*
- * Entries in the pre_cache whose hit count passes the promotion
- * threshold move to the cache proper. Working out the correct
- * value for the promotion_threshold is crucial to this policy.
- */
- unsigned promote_threshold;
-
unsigned discard_promote_adjustment;
unsigned read_promote_adjustment;
unsigned write_promote_adjustment;
@@ -406,6 +405,7 @@ struct mq_policy {
#define DEFAULT_DISCARD_PROMOTE_ADJUSTMENT 1
#define DEFAULT_READ_PROMOTE_ADJUSTMENT 4
#define DEFAULT_WRITE_PROMOTE_ADJUSTMENT 8
+#define DISCOURAGE_DEMOTING_DIRTY_THRESHOLD 128
/*----------------------------------------------------------------*/
@@ -518,6 +518,12 @@ static struct entry *pop(struct mq_policy *mq, struct queue *q)
return e;
}
+static struct entry *peek(struct queue *q)
+{
+ struct list_head *h = queue_peek(q);
+ return h ? container_of(h, struct entry, list) : NULL;
+}
+
/*
* Has this entry already been updated?
*/
@@ -570,10 +576,6 @@ static void check_generation(struct mq_policy *mq)
break;
}
}
-
- mq->promote_threshold = nr ? total / nr : 1;
- if (mq->promote_threshold * nr < total)
- mq->promote_threshold++;
}
}
@@ -641,6 +643,30 @@ static int demote_cblock(struct mq_policy *mq, dm_oblock_t *oblock)
}
/*
+ * Entries in the pre_cache whose hit count passes the promotion
+ * threshold move to the cache proper. Working out the correct
+ * value for the promotion_threshold is crucial to this policy.
+ */
+static unsigned promote_threshold(struct mq_policy *mq)
+{
+ struct entry *e;
+
+ if (any_free_cblocks(mq))
+ return 0;
+
+ e = peek(&mq->cache_clean);
+ if (e)
+ return e->hit_count;
+
+ e = peek(&mq->cache_dirty);
+ if (e)
+ return e->hit_count + DISCOURAGE_DEMOTING_DIRTY_THRESHOLD;
+
+ /* This should never happen */
+ return 0;
+}
+
+/*
* We modify the basic promotion_threshold depending on the specific io.
*
* If the origin block has been discarded then there's no cost to copy it
@@ -653,7 +679,7 @@ static unsigned adjusted_promote_threshold(struct mq_policy *mq,
bool discarded_oblock, int data_dir)
{
if (data_dir == READ)
- return mq->promote_threshold + mq->read_promote_adjustment;
+ return promote_threshold(mq) + mq->read_promote_adjustment;
if (discarded_oblock && (any_free_cblocks(mq) || any_clean_cblocks(mq))) {
/*
@@ -663,7 +689,7 @@ static unsigned adjusted_promote_threshold(struct mq_policy *mq,
return mq->discard_promote_adjustment;
}
- return mq->promote_threshold + mq->write_promote_adjustment;
+ return promote_threshold(mq) + mq->write_promote_adjustment;
}
static bool should_promote(struct mq_policy *mq, struct entry *e,
@@ -839,7 +865,8 @@ static int map(struct mq_policy *mq, dm_oblock_t oblock,
if (e && in_cache(mq, e))
r = cache_entry_found(mq, e, result);
- else if (iot_pattern(&mq->tracker) == PATTERN_SEQUENTIAL)
+ else if (mq->tracker.thresholds[PATTERN_SEQUENTIAL] &&
+ iot_pattern(&mq->tracker) == PATTERN_SEQUENTIAL)
result->op = POLICY_MISS;
else if (e)
@@ -1230,7 +1257,6 @@ static struct dm_cache_policy *mq_create(dm_cblock_t cache_size,
mq->tick = 0;
mq->hit_count = 0;
mq->generation = 0;
- mq->promote_threshold = 0;
mq->discard_promote_adjustment = DEFAULT_DISCARD_PROMOTE_ADJUSTMENT;
mq->read_promote_adjustment = DEFAULT_READ_PROMOTE_ADJUSTMENT;
mq->write_promote_adjustment = DEFAULT_WRITE_PROMOTE_ADJUSTMENT;
@@ -1265,7 +1291,7 @@ bad_pre_cache_init:
static struct dm_cache_policy_type mq_policy_type = {
.name = "mq",
- .version = {1, 2, 0},
+ .version = {1, 3, 0},
.hint_size = 4,
.owner = THIS_MODULE,
.create = mq_create
@@ -1273,7 +1299,7 @@ static struct dm_cache_policy_type mq_policy_type = {
static struct dm_cache_policy_type default_policy_type = {
.name = "default",
- .version = {1, 2, 0},
+ .version = {1, 3, 0},
.hint_size = 4,
.owner = THIS_MODULE,
.create = mq_create,
diff --git a/drivers/md/dm-cache-target.c b/drivers/md/dm-cache-target.c
index 7130505..1e96d78 100644
--- a/drivers/md/dm-cache-target.c
+++ b/drivers/md/dm-cache-target.c
@@ -95,7 +95,6 @@ static void dm_unhook_bio(struct dm_hook_info *h, struct bio *bio)
/*----------------------------------------------------------------*/
-#define PRISON_CELLS 1024
#define MIGRATION_POOL_SIZE 128
#define COMMIT_PERIOD HZ
#define MIGRATION_COUNT_WINDOW 10
@@ -237,8 +236,9 @@ struct cache {
/*
* origin_blocks entries, discarded if set.
*/
- dm_oblock_t discard_nr_blocks;
+ dm_dblock_t discard_nr_blocks;
unsigned long *discard_bitset;
+ uint32_t discard_block_size; /* a power of 2 times sectors per block */
/*
* Rather than reconstructing the table line for the status we just
@@ -310,6 +310,7 @@ struct dm_cache_migration {
dm_cblock_t cblock;
bool err:1;
+ bool discard:1;
bool writeback:1;
bool demote:1;
bool promote:1;
@@ -433,11 +434,12 @@ static void prealloc_put_cell(struct prealloc *p, struct dm_bio_prison_cell *cel
/*----------------------------------------------------------------*/
-static void build_key(dm_oblock_t oblock, struct dm_cell_key *key)
+static void build_key(dm_oblock_t begin, dm_oblock_t end, struct dm_cell_key *key)
{
key->virtual = 0;
key->dev = 0;
- key->block = from_oblock(oblock);
+ key->block_begin = from_oblock(begin);
+ key->block_end = from_oblock(end);
}
/*
@@ -447,15 +449,15 @@ static void build_key(dm_oblock_t oblock, struct dm_cell_key *key)
*/
typedef void (*cell_free_fn)(void *context, struct dm_bio_prison_cell *cell);
-static int bio_detain(struct cache *cache, dm_oblock_t oblock,
- struct bio *bio, struct dm_bio_prison_cell *cell_prealloc,
- cell_free_fn free_fn, void *free_context,
- struct dm_bio_prison_cell **cell_result)
+static int bio_detain_range(struct cache *cache, dm_oblock_t oblock_begin, dm_oblock_t oblock_end,
+ struct bio *bio, struct dm_bio_prison_cell *cell_prealloc,
+ cell_free_fn free_fn, void *free_context,
+ struct dm_bio_prison_cell **cell_result)
{
int r;
struct dm_cell_key key;
- build_key(oblock, &key);
+ build_key(oblock_begin, oblock_end, &key);
r = dm_bio_detain(cache->prison, &key, bio, cell_prealloc, cell_result);
if (r)
free_fn(free_context, cell_prealloc);
@@ -463,6 +465,16 @@ static int bio_detain(struct cache *cache, dm_oblock_t oblock,
return r;
}
+static int bio_detain(struct cache *cache, dm_oblock_t oblock,
+ struct bio *bio, struct dm_bio_prison_cell *cell_prealloc,
+ cell_free_fn free_fn, void *free_context,
+ struct dm_bio_prison_cell **cell_result)
+{
+ dm_oblock_t end = to_oblock(from_oblock(oblock) + 1ULL);
+ return bio_detain_range(cache, oblock, end, bio,
+ cell_prealloc, free_fn, free_context, cell_result);
+}
+
static int get_cell(struct cache *cache,
dm_oblock_t oblock,
struct prealloc *structs,
@@ -474,7 +486,7 @@ static int get_cell(struct cache *cache,
cell_prealloc = prealloc_get_cell(structs);
- build_key(oblock, &key);
+ build_key(oblock, to_oblock(from_oblock(oblock) + 1ULL), &key);
r = dm_get_cell(cache->prison, &key, cell_prealloc, cell_result);
if (r)
prealloc_put_cell(structs, cell_prealloc);
@@ -524,33 +536,57 @@ static dm_block_t block_div(dm_block_t b, uint32_t n)
return b;
}
-static void set_discard(struct cache *cache, dm_oblock_t b)
+static dm_block_t oblocks_per_dblock(struct cache *cache)
+{
+ dm_block_t oblocks = cache->discard_block_size;
+
+ if (block_size_is_power_of_two(cache))
+ oblocks >>= cache->sectors_per_block_shift;
+ else
+ oblocks = block_div(oblocks, cache->sectors_per_block);
+
+ return oblocks;
+}
+
+static dm_dblock_t oblock_to_dblock(struct cache *cache, dm_oblock_t oblock)
+{
+ return to_dblock(block_div(from_oblock(oblock),
+ oblocks_per_dblock(cache)));
+}
+
+static dm_oblock_t dblock_to_oblock(struct cache *cache, dm_dblock_t dblock)
+{
+ return to_oblock(from_dblock(dblock) * oblocks_per_dblock(cache));
+}
+
+static void set_discard(struct cache *cache, dm_dblock_t b)
{
unsigned long flags;
+ BUG_ON(from_dblock(b) >= from_dblock(cache->discard_nr_blocks));
atomic_inc(&cache->stats.discard_count);
spin_lock_irqsave(&cache->lock, flags);
- set_bit(from_oblock(b), cache->discard_bitset);
+ set_bit(from_dblock(b), cache->discard_bitset);
spin_unlock_irqrestore(&cache->lock, flags);
}
-static void clear_discard(struct cache *cache, dm_oblock_t b)
+static void clear_discard(struct cache *cache, dm_dblock_t b)
{
unsigned long flags;
spin_lock_irqsave(&cache->lock, flags);
- clear_bit(from_oblock(b), cache->discard_bitset);
+ clear_bit(from_dblock(b), cache->discard_bitset);
spin_unlock_irqrestore(&cache->lock, flags);
}
-static bool is_discarded(struct cache *cache, dm_oblock_t b)
+static bool is_discarded(struct cache *cache, dm_dblock_t b)
{
int r;
unsigned long flags;
spin_lock_irqsave(&cache->lock, flags);
- r = test_bit(from_oblock(b), cache->discard_bitset);
+ r = test_bit(from_dblock(b), cache->discard_bitset);
spin_unlock_irqrestore(&cache->lock, flags);
return r;
@@ -562,7 +598,8 @@ static bool is_discarded_oblock(struct cache *cache, dm_oblock_t b)
unsigned long flags;
spin_lock_irqsave(&cache->lock, flags);
- r = test_bit(from_oblock(b), cache->discard_bitset);
+ r = test_bit(from_dblock(oblock_to_dblock(cache, b)),
+ cache->discard_bitset);
spin_unlock_irqrestore(&cache->lock, flags);
return r;
@@ -687,7 +724,7 @@ static void remap_to_origin_clear_discard(struct cache *cache, struct bio *bio,
check_if_tick_bio_needed(cache, bio);
remap_to_origin(cache, bio);
if (bio_data_dir(bio) == WRITE)
- clear_discard(cache, oblock);
+ clear_discard(cache, oblock_to_dblock(cache, oblock));
}
static void remap_to_cache_dirty(struct cache *cache, struct bio *bio,
@@ -697,7 +734,7 @@ static void remap_to_cache_dirty(struct cache *cache, struct bio *bio,
remap_to_cache(cache, bio, cblock);
if (bio_data_dir(bio) == WRITE) {
set_dirty(cache, oblock, cblock);
- clear_discard(cache, oblock);
+ clear_discard(cache, oblock_to_dblock(cache, oblock));
}
}
@@ -951,10 +988,14 @@ static void migration_success_post_commit(struct dm_cache_migration *mg)
}
} else {
- clear_dirty(cache, mg->new_oblock, mg->cblock);
- if (mg->requeue_holder)
+ if (mg->requeue_holder) {
+ clear_dirty(cache, mg->new_oblock, mg->cblock);
cell_defer(cache, mg->new_ocell, true);
- else {
+ } else {
+ /*
+ * The block was promoted via an overwrite, so it's dirty.
+ */
+ set_dirty(cache, mg->new_oblock, mg->cblock);
bio_endio(mg->new_ocell->holder, 0);
cell_defer(cache, mg->new_ocell, false);
}
@@ -978,7 +1019,7 @@ static void copy_complete(int read_err, unsigned long write_err, void *context)
wake_worker(cache);
}
-static void issue_copy_real(struct dm_cache_migration *mg)
+static void issue_copy(struct dm_cache_migration *mg)
{
int r;
struct dm_io_region o_region, c_region;
@@ -1057,11 +1098,46 @@ static void avoid_copy(struct dm_cache_migration *mg)
migration_success_pre_commit(mg);
}
-static void issue_copy(struct dm_cache_migration *mg)
+static void calc_discard_block_range(struct cache *cache, struct bio *bio,
+ dm_dblock_t *b, dm_dblock_t *e)
+{
+ sector_t sb = bio->bi_iter.bi_sector;
+ sector_t se = bio_end_sector(bio);
+
+ *b = to_dblock(dm_sector_div_up(sb, cache->discard_block_size));
+
+ if (se - sb < cache->discard_block_size)
+ *e = *b;
+ else
+ *e = to_dblock(block_div(se, cache->discard_block_size));
+}
+
+static void issue_discard(struct dm_cache_migration *mg)
+{
+ dm_dblock_t b, e;
+ struct bio *bio = mg->new_ocell->holder;
+
+ calc_discard_block_range(mg->cache, bio, &b, &e);
+ while (b != e) {
+ set_discard(mg->cache, b);
+ b = to_dblock(from_dblock(b) + 1);
+ }
+
+ bio_endio(bio, 0);
+ cell_defer(mg->cache, mg->new_ocell, false);
+ free_migration(mg);
+}
+
+static void issue_copy_or_discard(struct dm_cache_migration *mg)
{
bool avoid;
struct cache *cache = mg->cache;
+ if (mg->discard) {
+ issue_discard(mg);
+ return;
+ }
+
if (mg->writeback || mg->demote)
avoid = !is_dirty(cache, mg->cblock) ||
is_discarded_oblock(cache, mg->old_oblock);
@@ -1070,13 +1146,14 @@ static void issue_copy(struct dm_cache_migration *mg)
avoid = is_discarded_oblock(cache, mg->new_oblock);
- if (!avoid && bio_writes_complete_block(cache, bio)) {
+ if (writeback_mode(&cache->features) &&
+ !avoid && bio_writes_complete_block(cache, bio)) {
issue_overwrite(mg, bio);
return;
}
}
- avoid ? avoid_copy(mg) : issue_copy_real(mg);
+ avoid ? avoid_copy(mg) : issue_copy(mg);
}
static void complete_migration(struct dm_cache_migration *mg)
@@ -1161,6 +1238,7 @@ static void promote(struct cache *cache, struct prealloc *structs,
struct dm_cache_migration *mg = prealloc_get_migration(structs);
mg->err = false;
+ mg->discard = false;
mg->writeback = false;
mg->demote = false;
mg->promote = true;
@@ -1184,6 +1262,7 @@ static void writeback(struct cache *cache, struct prealloc *structs,
struct dm_cache_migration *mg = prealloc_get_migration(structs);
mg->err = false;
+ mg->discard = false;
mg->writeback = true;
mg->demote = false;
mg->promote = false;
@@ -1209,6 +1288,7 @@ static void demote_then_promote(struct cache *cache, struct prealloc *structs,
struct dm_cache_migration *mg = prealloc_get_migration(structs);
mg->err = false;
+ mg->discard = false;
mg->writeback = false;
mg->demote = true;
mg->promote = true;
@@ -1237,6 +1317,7 @@ static void invalidate(struct cache *cache, struct prealloc *structs,
struct dm_cache_migration *mg = prealloc_get_migration(structs);
mg->err = false;
+ mg->discard = false;
mg->writeback = false;
mg->demote = true;
mg->promote = false;
@@ -1253,6 +1334,26 @@ static void invalidate(struct cache *cache, struct prealloc *structs,
quiesce_migration(mg);
}
+static void discard(struct cache *cache, struct prealloc *structs,
+ struct dm_bio_prison_cell *cell)
+{
+ struct dm_cache_migration *mg = prealloc_get_migration(structs);
+
+ mg->err = false;
+ mg->discard = true;
+ mg->writeback = false;
+ mg->demote = false;
+ mg->promote = false;
+ mg->requeue_holder = false;
+ mg->invalidate = false;
+ mg->cache = cache;
+ mg->old_ocell = NULL;
+ mg->new_ocell = cell;
+ mg->start_jiffies = jiffies;
+
+ quiesce_migration(mg);
+}
+
/*----------------------------------------------------------------
* bio processing
*--------------------------------------------------------------*/
@@ -1286,31 +1387,27 @@ static void process_flush_bio(struct cache *cache, struct bio *bio)
issue(cache, bio);
}
-/*
- * People generally discard large parts of a device, eg, the whole device
- * when formatting. Splitting these large discards up into cache block
- * sized ios and then quiescing (always neccessary for discard) takes too
- * long.
- *
- * We keep it simple, and allow any size of discard to come in, and just
- * mark off blocks on the discard bitset. No passdown occurs!
- *
- * To implement passdown we need to change the bio_prison such that a cell
- * can have a key that spans many blocks.
- */
-static void process_discard_bio(struct cache *cache, struct bio *bio)
+static void process_discard_bio(struct cache *cache, struct prealloc *structs,
+ struct bio *bio)
{
- dm_block_t start_block = dm_sector_div_up(bio->bi_iter.bi_sector,
- cache->sectors_per_block);
- dm_block_t end_block = bio_end_sector(bio);
- dm_block_t b;
+ int r;
+ dm_dblock_t b, e;
+ struct dm_bio_prison_cell *cell_prealloc, *new_ocell;
- end_block = block_div(end_block, cache->sectors_per_block);
+ calc_discard_block_range(cache, bio, &b, &e);
+ if (b == e) {
+ bio_endio(bio, 0);
+ return;
+ }
- for (b = start_block; b < end_block; b++)
- set_discard(cache, to_oblock(b));
+ cell_prealloc = prealloc_get_cell(structs);
+ r = bio_detain_range(cache, dblock_to_oblock(cache, b), dblock_to_oblock(cache, e), bio, cell_prealloc,
+ (cell_free_fn) prealloc_put_cell,
+ structs, &new_ocell);
+ if (r > 0)
+ return;
- bio_endio(bio, 0);
+ discard(cache, structs, new_ocell);
}
static bool spare_migration_bandwidth(struct cache *cache)
@@ -1340,9 +1437,8 @@ static void process_bio(struct cache *cache, struct prealloc *structs,
dm_oblock_t block = get_bio_block(cache, bio);
struct dm_bio_prison_cell *cell_prealloc, *old_ocell, *new_ocell;
struct policy_result lookup_result;
- bool discarded_block = is_discarded_oblock(cache, block);
bool passthrough = passthrough_mode(&cache->features);
- bool can_migrate = !passthrough && (discarded_block || spare_migration_bandwidth(cache));
+ bool discarded_block, can_migrate;
/*
* Check to see if that block is currently migrating.
@@ -1354,6 +1450,9 @@ static void process_bio(struct cache *cache, struct prealloc *structs,
if (r > 0)
return;
+ discarded_block = is_discarded_oblock(cache, block);
+ can_migrate = !passthrough && (discarded_block || spare_migration_bandwidth(cache));
+
r = policy_map(cache->policy, block, true, can_migrate, discarded_block,
bio, &lookup_result);
@@ -1500,7 +1599,7 @@ static void process_deferred_bios(struct cache *cache)
if (bio->bi_rw & REQ_FLUSH)
process_flush_bio(cache, bio);
else if (bio->bi_rw & REQ_DISCARD)
- process_discard_bio(cache, bio);
+ process_discard_bio(cache, &structs, bio);
else
process_bio(cache, &structs, bio);
}
@@ -1715,7 +1814,7 @@ static void do_worker(struct work_struct *ws)
process_invalidation_requests(cache);
}
- process_migrations(cache, &cache->quiesced_migrations, issue_copy);
+ process_migrations(cache, &cache->quiesced_migrations, issue_copy_or_discard);
process_migrations(cache, &cache->completed_migrations, complete_migration);
if (commit_if_needed(cache)) {
@@ -2180,6 +2279,45 @@ static int create_cache_policy(struct cache *cache, struct cache_args *ca,
return 0;
}
+/*
+ * We want the discard block size to be at least the size of the cache
+ * block size and have no more than 2^14 discard blocks across the origin.
+ */
+#define MAX_DISCARD_BLOCKS (1 << 14)
+
+static bool too_many_discard_blocks(sector_t discard_block_size,
+ sector_t origin_size)
+{
+ (void) sector_div(origin_size, discard_block_size);
+
+ return origin_size > MAX_DISCARD_BLOCKS;
+}
+
+static sector_t calculate_discard_block_size(sector_t cache_block_size,
+ sector_t origin_size)
+{
+ sector_t discard_block_size = cache_block_size;
+
+ if (origin_size)
+ while (too_many_discard_blocks(discard_block_size, origin_size))
+ discard_block_size *= 2;
+
+ return discard_block_size;
+}
+
+static void set_cache_size(struct cache *cache, dm_cblock_t size)
+{
+ dm_block_t nr_blocks = from_cblock(size);
+
+ if (nr_blocks > (1 << 20) && cache->cache_size != size)
+ DMWARN_LIMIT("You have created a cache device with a lot of individual cache blocks (%llu)\n"
+ "All these mappings can consume a lot of kernel memory, and take some time to read/write.\n"
+ "Please consider increasing the cache block size to reduce the overall cache block count.",
+ (unsigned long long) nr_blocks);
+
+ cache->cache_size = size;
+}
+
#define DEFAULT_MIGRATION_THRESHOLD 2048
static int cache_create(struct cache_args *ca, struct cache **result)
@@ -2204,8 +2342,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
ti->num_discard_bios = 1;
ti->discards_supported = true;
ti->discard_zeroes_data_unsupported = true;
- /* Discard bios must be split on a block boundary */
- ti->split_discard_bios = true;
+ ti->split_discard_bios = false;
cache->features = ca->features;
ti->per_bio_data_size = get_per_bio_data_size(cache);
@@ -2235,10 +2372,10 @@ static int cache_create(struct cache_args *ca, struct cache **result)
cache->sectors_per_block_shift = -1;
cache_size = block_div(cache_size, ca->block_size);
- cache->cache_size = to_cblock(cache_size);
+ set_cache_size(cache, to_cblock(cache_size));
} else {
cache->sectors_per_block_shift = __ffs(ca->block_size);
- cache->cache_size = to_cblock(ca->cache_sectors >> cache->sectors_per_block_shift);
+ set_cache_size(cache, to_cblock(ca->cache_sectors >> cache->sectors_per_block_shift));
}
r = create_cache_policy(cache, ca, error);
@@ -2303,13 +2440,17 @@ static int cache_create(struct cache_args *ca, struct cache **result)
}
clear_bitset(cache->dirty_bitset, from_cblock(cache->cache_size));
- cache->discard_nr_blocks = cache->origin_blocks;
- cache->discard_bitset = alloc_bitset(from_oblock(cache->discard_nr_blocks));
+ cache->discard_block_size =
+ calculate_discard_block_size(cache->sectors_per_block,
+ cache->origin_sectors);
+ cache->discard_nr_blocks = to_dblock(dm_sector_div_up(cache->origin_sectors,
+ cache->discard_block_size));
+ cache->discard_bitset = alloc_bitset(from_dblock(cache->discard_nr_blocks));
if (!cache->discard_bitset) {
*error = "could not allocate discard bitset";
goto bad;
}
- clear_bitset(cache->discard_bitset, from_oblock(cache->discard_nr_blocks));
+ clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks));
cache->copier = dm_kcopyd_client_create(&dm_kcopyd_throttle);
if (IS_ERR(cache->copier)) {
@@ -2327,7 +2468,7 @@ static int cache_create(struct cache_args *ca, struct cache **result)
INIT_DELAYED_WORK(&cache->waker, do_waker);
cache->last_commit_jiffies = jiffies;
- cache->prison = dm_bio_prison_create(PRISON_CELLS);
+ cache->prison = dm_bio_prison_create();
if (!cache->prison) {
*error = "could not create bio prison";
goto bad;
@@ -2549,11 +2690,11 @@ static int __cache_map(struct cache *cache, struct bio *bio, struct dm_bio_priso
static int cache_map(struct dm_target *ti, struct bio *bio)
{
int r;
- struct dm_bio_prison_cell *cell;
+ struct dm_bio_prison_cell *cell = NULL;
struct cache *cache = ti->private;
r = __cache_map(cache, bio, &cell);
- if (r == DM_MAPIO_REMAPPED) {
+ if (r == DM_MAPIO_REMAPPED && cell) {
inc_ds(cache, bio, cell);
cell_defer(cache, cell, false);
}
@@ -2599,16 +2740,16 @@ static int write_discard_bitset(struct cache *cache)
{
unsigned i, r;
- r = dm_cache_discard_bitset_resize(cache->cmd, cache->sectors_per_block,
- cache->origin_blocks);
+ r = dm_cache_discard_bitset_resize(cache->cmd, cache->discard_block_size,
+ cache->discard_nr_blocks);
if (r) {
DMERR("could not resize on-disk discard bitset");
return r;
}
- for (i = 0; i < from_oblock(cache->discard_nr_blocks); i++) {
- r = dm_cache_set_discard(cache->cmd, to_oblock(i),
- is_discarded(cache, to_oblock(i)));
+ for (i = 0; i < from_dblock(cache->discard_nr_blocks); i++) {
+ r = dm_cache_set_discard(cache->cmd, to_dblock(i),
+ is_discarded(cache, to_dblock(i)));
if (r)
return r;
}
@@ -2680,15 +2821,86 @@ static int load_mapping(void *context, dm_oblock_t oblock, dm_cblock_t cblock,
return 0;
}
+/*
+ * The discard block size in the on disk metadata is not
+ * neccessarily the same as we're currently using. So we have to
+ * be careful to only set the discarded attribute if we know it
+ * covers a complete block of the new size.
+ */
+struct discard_load_info {
+ struct cache *cache;
+
+ /*
+ * These blocks are sized using the on disk dblock size, rather
+ * than the current one.
+ */
+ dm_block_t block_size;
+ dm_block_t discard_begin, discard_end;
+};
+
+static void discard_load_info_init(struct cache *cache,
+ struct discard_load_info *li)
+{
+ li->cache = cache;
+ li->discard_begin = li->discard_end = 0;
+}
+
+static void set_discard_range(struct discard_load_info *li)
+{
+ sector_t b, e;
+
+ if (li->discard_begin == li->discard_end)
+ return;
+
+ /*
+ * Convert to sectors.
+ */
+ b = li->discard_begin * li->block_size;
+ e = li->discard_end * li->block_size;
+
+ /*
+ * Then convert back to the current dblock size.
+ */
+ b = dm_sector_div_up(b, li->cache->discard_block_size);
+ sector_div(e, li->cache->discard_block_size);
+
+ /*
+ * The origin may have shrunk, so we need to check we're still in
+ * bounds.
+ */
+ if (e > from_dblock(li->cache->discard_nr_blocks))
+ e = from_dblock(li->cache->discard_nr_blocks);
+
+ for (; b < e; b++)
+ set_discard(li->cache, to_dblock(b));
+}
+
static int load_discard(void *context, sector_t discard_block_size,
- dm_oblock_t oblock, bool discard)
+ dm_dblock_t dblock, bool discard)
{
- struct cache *cache = context;
+ struct discard_load_info *li = context;
- if (discard)
- set_discard(cache, oblock);
- else
- clear_discard(cache, oblock);
+ li->block_size = discard_block_size;
+
+ if (discard) {
+ if (from_dblock(dblock) == li->discard_end)
+ /*
+ * We're already in a discard range, just extend it.
+ */
+ li->discard_end = li->discard_end + 1ULL;
+
+ else {
+ /*
+ * Emit the old range and start a new one.
+ */
+ set_discard_range(li);
+ li->discard_begin = from_dblock(dblock);
+ li->discard_end = li->discard_begin + 1ULL;
+ }
+ } else {
+ set_discard_range(li);
+ li->discard_begin = li->discard_end = 0;
+ }
return 0;
}
@@ -2730,7 +2942,7 @@ static int resize_cache_dev(struct cache *cache, dm_cblock_t new_size)
return r;
}
- cache->cache_size = new_size;
+ set_cache_size(cache, new_size);
return 0;
}
@@ -2772,11 +2984,22 @@ static int cache_preresume(struct dm_target *ti)
}
if (!cache->loaded_discards) {
- r = dm_cache_load_discards(cache->cmd, load_discard, cache);
+ struct discard_load_info li;
+
+ /*
+ * The discard bitset could have been resized, or the
+ * discard block size changed. To be safe we start by
+ * setting every dblock to not discarded.
+ */
+ clear_bitset(cache->discard_bitset, from_dblock(cache->discard_nr_blocks));
+
+ discard_load_info_init(cache, &li);
+ r = dm_cache_load_discards(cache->cmd, load_discard, &li);
if (r) {
DMERR("could not load origin discards");
return r;
}
+ set_discard_range(&li);
cache->loaded_discards = true;
}
@@ -3079,8 +3302,9 @@ static void set_discard_limits(struct cache *cache, struct queue_limits *limits)
/*
* FIXME: these limits may be incompatible with the cache device
*/
- limits->max_discard_sectors = cache->sectors_per_block;
- limits->discard_granularity = cache->sectors_per_block << SECTOR_SHIFT;
+ limits->max_discard_sectors = min_t(sector_t, cache->discard_block_size * 1024,
+ cache->origin_sectors);
+ limits->discard_granularity = cache->discard_block_size << SECTOR_SHIFT;
}
static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
@@ -3104,7 +3328,7 @@ static void cache_io_hints(struct dm_target *ti, struct queue_limits *limits)
static struct target_type cache_target = {
.name = "cache",
- .version = {1, 5, 0},
+ .version = {1, 6, 0},
.module = THIS_MODULE,
.ctr = cache_ctr,
.dtr = cache_dtr,
diff --git a/drivers/md/dm-crypt.c b/drivers/md/dm-crypt.c
index fc93b93..08981be 100644
--- a/drivers/md/dm-crypt.c
+++ b/drivers/md/dm-crypt.c
@@ -705,7 +705,7 @@ static int crypt_iv_tcw_whitening(struct crypt_config *cc,
for (i = 0; i < ((1 << SECTOR_SHIFT) / 8); i++)
crypto_xor(data + i * 8, buf, 8);
out:
- memset(buf, 0, sizeof(buf));
+ memzero_explicit(buf, sizeof(buf));
return r;
}
diff --git a/drivers/md/dm-ioctl.c b/drivers/md/dm-ioctl.c
index 0be9381..73f791b 100644
--- a/drivers/md/dm-ioctl.c
+++ b/drivers/md/dm-ioctl.c
@@ -684,11 +684,14 @@ static void __dev_status(struct mapped_device *md, struct dm_ioctl *param)
int srcu_idx;
param->flags &= ~(DM_SUSPEND_FLAG | DM_READONLY_FLAG |
- DM_ACTIVE_PRESENT_FLAG);
+ DM_ACTIVE_PRESENT_FLAG | DM_INTERNAL_SUSPEND_FLAG);
if (dm_suspended_md(md))
param->flags |= DM_SUSPEND_FLAG;
+ if (dm_suspended_internally_md(md))
+ param->flags |= DM_INTERNAL_SUSPEND_FLAG;
+
if (dm_test_deferred_remove_flag(md))
param->flags |= DM_DEFERRED_REMOVE;
diff --git a/drivers/md/dm-stats.c b/drivers/md/dm-stats.c
index 87f86c7..f478a4c 100644
--- a/drivers/md/dm-stats.c
+++ b/drivers/md/dm-stats.c
@@ -824,7 +824,7 @@ static int message_stats_create(struct mapped_device *md,
return 1;
id = dm_stats_create(dm_get_stats(md), start, end, step, program_id, aux_data,
- dm_internal_suspend, dm_internal_resume, md);
+ dm_internal_suspend_fast, dm_internal_resume_fast, md);
if (id < 0)
return id;
diff --git a/drivers/md/dm-table.c b/drivers/md/dm-table.c
index b2bd1eb..3afae9e 100644
--- a/drivers/md/dm-table.c
+++ b/drivers/md/dm-table.c
@@ -1521,18 +1521,32 @@ fmode_t dm_table_get_mode(struct dm_table *t)
}
EXPORT_SYMBOL(dm_table_get_mode);
-static void suspend_targets(struct dm_table *t, unsigned postsuspend)
+enum suspend_mode {
+ PRESUSPEND,
+ PRESUSPEND_UNDO,
+ POSTSUSPEND,
+};
+
+static void suspend_targets(struct dm_table *t, enum suspend_mode mode)
{
int i = t->num_targets;
struct dm_target *ti = t->targets;
while (i--) {
- if (postsuspend) {
+ switch (mode) {
+ case PRESUSPEND:
+ if (ti->type->presuspend)
+ ti->type->presuspend(ti);
+ break;
+ case PRESUSPEND_UNDO:
+ if (ti->type->presuspend_undo)
+ ti->type->presuspend_undo(ti);
+ break;
+ case POSTSUSPEND:
if (ti->type->postsuspend)
ti->type->postsuspend(ti);
- } else if (ti->type->presuspend)
- ti->type->presuspend(ti);
-
+ break;
+ }
ti++;
}
}
@@ -1542,7 +1556,15 @@ void dm_table_presuspend_targets(struct dm_table *t)
if (!t)
return;
- suspend_targets(t, 0);
+ suspend_targets(t, PRESUSPEND);
+}
+
+void dm_table_presuspend_undo_targets(struct dm_table *t)
+{
+ if (!t)
+ return;
+
+ suspend_targets(t, PRESUSPEND_UNDO);
}
void dm_table_postsuspend_targets(struct dm_table *t)
@@ -1550,7 +1572,7 @@ void dm_table_postsuspend_targets(struct dm_table *t)
if (!t)
return;
- suspend_targets(t, 1);
+ suspend_targets(t, POSTSUSPEND);
}
int dm_table_resume_targets(struct dm_table *t)
diff --git a/drivers/md/dm-thin-metadata.c b/drivers/md/dm-thin-metadata.c
index e9d33ad..43adbb8 100644
--- a/drivers/md/dm-thin-metadata.c
+++ b/drivers/md/dm-thin-metadata.c
@@ -1384,42 +1384,38 @@ static bool __snapshotted_since(struct dm_thin_device *td, uint32_t time)
}
int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
- int can_block, struct dm_thin_lookup_result *result)
+ int can_issue_io, struct dm_thin_lookup_result *result)
{
- int r = -EINVAL;
- uint64_t block_time = 0;
+ int r;
__le64 value;
struct dm_pool_metadata *pmd = td->pmd;
dm_block_t keys[2] = { td->id, block };
struct dm_btree_info *info;
- if (can_block) {
- down_read(&pmd->root_lock);
- info = &pmd->info;
- } else if (down_read_trylock(&pmd->root_lock))
- info = &pmd->nb_info;
- else
- return -EWOULDBLOCK;
-
if (pmd->fail_io)
- goto out;
+ return -EINVAL;
- r = dm_btree_lookup(info, pmd->root, keys, &value);
- if (!r)
- block_time = le64_to_cpu(value);
+ down_read(&pmd->root_lock);
-out:
- up_read(&pmd->root_lock);
+ if (can_issue_io) {
+ info = &pmd->info;
+ } else
+ info = &pmd->nb_info;
+ r = dm_btree_lookup(info, pmd->root, keys, &value);
if (!r) {
+ uint64_t block_time = 0;
dm_block_t exception_block;
uint32_t exception_time;
+
+ block_time = le64_to_cpu(value);
unpack_block_time(block_time, &exception_block,
&exception_time);
result->block = exception_block;
result->shared = __snapshotted_since(td, exception_time);
}
+ up_read(&pmd->root_lock);
return r;
}
@@ -1813,3 +1809,8 @@ bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd)
return needs_check;
}
+
+void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd)
+{
+ dm_tm_issue_prefetches(pmd->tm);
+}
diff --git a/drivers/md/dm-thin-metadata.h b/drivers/md/dm-thin-metadata.h
index e3c857d..921d15e 100644
--- a/drivers/md/dm-thin-metadata.h
+++ b/drivers/md/dm-thin-metadata.h
@@ -139,12 +139,12 @@ struct dm_thin_lookup_result {
/*
* Returns:
- * -EWOULDBLOCK iff @can_block is set and would block.
+ * -EWOULDBLOCK iff @can_issue_io is set and would issue IO
* -ENODATA iff that mapping is not present.
* 0 success
*/
int dm_thin_find_block(struct dm_thin_device *td, dm_block_t block,
- int can_block, struct dm_thin_lookup_result *result);
+ int can_issue_io, struct dm_thin_lookup_result *result);
/*
* Obtain an unused block.
@@ -213,6 +213,11 @@ int dm_pool_register_metadata_threshold(struct dm_pool_metadata *pmd,
int dm_pool_metadata_set_needs_check(struct dm_pool_metadata *pmd);
bool dm_pool_metadata_needs_check(struct dm_pool_metadata *pmd);
+/*
+ * Issue any prefetches that may be useful.
+ */
+void dm_pool_issue_prefetches(struct dm_pool_metadata *pmd);
+
/*----------------------------------------------------------------*/
#endif
diff --git a/drivers/md/dm-thin.c b/drivers/md/dm-thin.c
index 0f86d80..8735543 100644
--- a/drivers/md/dm-thin.c
+++ b/drivers/md/dm-thin.c
@@ -11,11 +11,13 @@
#include <linux/device-mapper.h>
#include <linux/dm-io.h>
#include <linux/dm-kcopyd.h>
+#include <linux/log2.h>
#include <linux/list.h>
#include <linux/rculist.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/sort.h>
#include <linux/rbtree.h>
#define DM_MSG_PREFIX "thin"
@@ -25,7 +27,6 @@
*/
#define ENDIO_HOOK_POOL_SIZE 1024
#define MAPPING_POOL_SIZE 1024
-#define PRISON_CELLS 1024
#define COMMIT_PERIOD HZ
#define NO_SPACE_TIMEOUT_SECS 60
@@ -114,7 +115,8 @@ static void build_data_key(struct dm_thin_device *td,
{
key->virtual = 0;
key->dev = dm_thin_dev_id(td);
- key->block = b;
+ key->block_begin = b;
+ key->block_end = b + 1ULL;
}
static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
@@ -122,7 +124,55 @@ static void build_virtual_key(struct dm_thin_device *td, dm_block_t b,
{
key->virtual = 1;
key->dev = dm_thin_dev_id(td);
- key->block = b;
+ key->block_begin = b;
+ key->block_end = b + 1ULL;
+}
+
+/*----------------------------------------------------------------*/
+
+#define THROTTLE_THRESHOLD (1 * HZ)
+
+struct throttle {
+ struct rw_semaphore lock;
+ unsigned long threshold;
+ bool throttle_applied;
+};
+
+static void throttle_init(struct throttle *t)
+{
+ init_rwsem(&t->lock);
+ t->throttle_applied = false;
+}
+
+static void throttle_work_start(struct throttle *t)
+{
+ t->threshold = jiffies + THROTTLE_THRESHOLD;
+}
+
+static void throttle_work_update(struct throttle *t)
+{
+ if (!t->throttle_applied && jiffies > t->threshold) {
+ down_write(&t->lock);
+ t->throttle_applied = true;
+ }
+}
+
+static void throttle_work_complete(struct throttle *t)
+{
+ if (t->throttle_applied) {
+ t->throttle_applied = false;
+ up_write(&t->lock);
+ }
+}
+
+static void throttle_lock(struct throttle *t)
+{
+ down_read(&t->lock);
+}
+
+static void throttle_unlock(struct throttle *t)
+{
+ up_read(&t->lock);
}
/*----------------------------------------------------------------*/
@@ -155,8 +205,11 @@ struct pool_features {
struct thin_c;
typedef void (*process_bio_fn)(struct thin_c *tc, struct bio *bio);
+typedef void (*process_cell_fn)(struct thin_c *tc, struct dm_bio_prison_cell *cell);
typedef void (*process_mapping_fn)(struct dm_thin_new_mapping *m);
+#define CELL_SORT_ARRAY_SIZE 8192
+
struct pool {
struct list_head list;
struct dm_target *ti; /* Only set if a pool target is bound */
@@ -171,11 +224,13 @@ struct pool {
struct pool_features pf;
bool low_water_triggered:1; /* A dm event has been sent */
+ bool suspended:1;
struct dm_bio_prison *prison;
struct dm_kcopyd_client *copier;
struct workqueue_struct *wq;
+ struct throttle throttle;
struct work_struct worker;
struct delayed_work waker;
struct delayed_work no_space_timeout;
@@ -198,8 +253,13 @@ struct pool {
process_bio_fn process_bio;
process_bio_fn process_discard;
+ process_cell_fn process_cell;
+ process_cell_fn process_discard_cell;
+
process_mapping_fn process_prepared_mapping;
process_mapping_fn process_prepared_discard;
+
+ struct dm_bio_prison_cell *cell_sort_array[CELL_SORT_ARRAY_SIZE];
};
static enum pool_mode get_pool_mode(struct pool *pool);
@@ -232,8 +292,11 @@ struct thin_c {
struct pool *pool;
struct dm_thin_device *td;
+ struct mapped_device *thin_md;
+
bool requeue_mode:1;
spinlock_t lock;
+ struct list_head deferred_cells;
struct bio_list deferred_bio_list;
struct bio_list retry_on_resume_list;
struct rb_root sort_bio_list; /* sorted list of deferred bios */
@@ -290,6 +353,15 @@ static void cell_release(struct pool *pool,
dm_bio_prison_free_cell(pool->prison, cell);
}
+static void cell_visit_release(struct pool *pool,
+ void (*fn)(void *, struct dm_bio_prison_cell *),
+ void *context,
+ struct dm_bio_prison_cell *cell)
+{
+ dm_cell_visit_release(pool->prison, fn, context, cell);
+ dm_bio_prison_free_cell(pool->prison, cell);
+}
+
static void cell_release_no_holder(struct pool *pool,
struct dm_bio_prison_cell *cell,
struct bio_list *bios)
@@ -298,19 +370,6 @@ static void cell_release_no_holder(struct pool *pool,
dm_bio_prison_free_cell(pool->prison, cell);
}
-static void cell_defer_no_holder_no_free(struct thin_c *tc,
- struct dm_bio_prison_cell *cell)
-{
- struct pool *pool = tc->pool;
- unsigned long flags;
-
- spin_lock_irqsave(&tc->lock, flags);
- dm_cell_release_no_holder(pool->prison, cell, &tc->deferred_bio_list);
- spin_unlock_irqrestore(&tc->lock, flags);
-
- wake_worker(pool);
-}
-
static void cell_error_with_code(struct pool *pool,
struct dm_bio_prison_cell *cell, int error_code)
{
@@ -323,6 +382,16 @@ static void cell_error(struct pool *pool, struct dm_bio_prison_cell *cell)
cell_error_with_code(pool, cell, -EIO);
}
+static void cell_success(struct pool *pool, struct dm_bio_prison_cell *cell)
+{
+ cell_error_with_code(pool, cell, 0);
+}
+
+static void cell_requeue(struct pool *pool, struct dm_bio_prison_cell *cell)
+{
+ cell_error_with_code(pool, cell, DM_ENDIO_REQUEUE);
+}
+
/*----------------------------------------------------------------*/
/*
@@ -393,44 +462,65 @@ struct dm_thin_endio_hook {
struct rb_node rb_node;
};
-static void requeue_bio_list(struct thin_c *tc, struct bio_list *master)
+static void __merge_bio_list(struct bio_list *bios, struct bio_list *master)
+{
+ bio_list_merge(bios, master);
+ bio_list_init(master);
+}
+
+static void error_bio_list(struct bio_list *bios, int error)
{
struct bio *bio;
+
+ while ((bio = bio_list_pop(bios)))
+ bio_endio(bio, error);
+}
+
+static void error_thin_bio_list(struct thin_c *tc, struct bio_list *master, int error)
+{
struct bio_list bios;
unsigned long flags;
bio_list_init(&bios);
spin_lock_irqsave(&tc->lock, flags);
- bio_list_merge(&bios, master);
- bio_list_init(master);
+ __merge_bio_list(&bios, master);
spin_unlock_irqrestore(&tc->lock, flags);
- while ((bio = bio_list_pop(&bios)))
- bio_endio(bio, DM_ENDIO_REQUEUE);
+ error_bio_list(&bios, error);
}
-static void requeue_io(struct thin_c *tc)
+static void requeue_deferred_cells(struct thin_c *tc)
{
- requeue_bio_list(tc, &tc->deferred_bio_list);
- requeue_bio_list(tc, &tc->retry_on_resume_list);
+ struct pool *pool = tc->pool;
+ unsigned long flags;
+ struct list_head cells;
+ struct dm_bio_prison_cell *cell, *tmp;
+
+ INIT_LIST_HEAD(&cells);
+
+ spin_lock_irqsave(&tc->lock, flags);
+ list_splice_init(&tc->deferred_cells, &cells);
+ spin_unlock_irqrestore(&tc->lock, flags);
+
+ list_for_each_entry_safe(cell, tmp, &cells, user_list)
+ cell_requeue(pool, cell);
}
-static void error_thin_retry_list(struct thin_c *tc)
+static void requeue_io(struct thin_c *tc)
{
- struct bio *bio;
- unsigned long flags;
struct bio_list bios;
+ unsigned long flags;
bio_list_init(&bios);
spin_lock_irqsave(&tc->lock, flags);
- bio_list_merge(&bios, &tc->retry_on_resume_list);
- bio_list_init(&tc->retry_on_resume_list);
+ __merge_bio_list(&bios, &tc->deferred_bio_list);
+ __merge_bio_list(&bios, &tc->retry_on_resume_list);
spin_unlock_irqrestore(&tc->lock, flags);
- while ((bio = bio_list_pop(&bios)))
- bio_io_error(bio);
+ error_bio_list(&bios, DM_ENDIO_REQUEUE);
+ requeue_deferred_cells(tc);
}
static void error_retry_list(struct pool *pool)
@@ -439,7 +529,7 @@ static void error_retry_list(struct pool *pool)
rcu_read_lock();
list_for_each_entry_rcu(tc, &pool->active_thins, list)
- error_thin_retry_list(tc);
+ error_thin_bio_list(tc, &tc->retry_on_resume_list, -EIO);
rcu_read_unlock();
}
@@ -629,33 +719,75 @@ static void overwrite_endio(struct bio *bio, int err)
*/
/*
- * This sends the bios in the cell back to the deferred_bios list.
+ * This sends the bios in the cell, except the original holder, back
+ * to the deferred_bios list.
*/
-static void cell_defer(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *cell)
{
struct pool *pool = tc->pool;
unsigned long flags;
spin_lock_irqsave(&tc->lock, flags);
- cell_release(pool, cell, &tc->deferred_bio_list);
+ cell_release_no_holder(pool, cell, &tc->deferred_bio_list);
spin_unlock_irqrestore(&tc->lock, flags);
wake_worker(pool);
}
-/*
- * Same as cell_defer above, except it omits the original holder of the cell.
- */
-static void cell_defer_no_holder(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+static void thin_defer_bio(struct thin_c *tc, struct bio *bio);
+
+struct remap_info {
+ struct thin_c *tc;
+ struct bio_list defer_bios;
+ struct bio_list issue_bios;
+};
+
+static void __inc_remap_and_issue_cell(void *context,
+ struct dm_bio_prison_cell *cell)
{
- struct pool *pool = tc->pool;
- unsigned long flags;
+ struct remap_info *info = context;
+ struct bio *bio;
- spin_lock_irqsave(&tc->lock, flags);
- cell_release_no_holder(pool, cell, &tc->deferred_bio_list);
- spin_unlock_irqrestore(&tc->lock, flags);
+ while ((bio = bio_list_pop(&cell->bios))) {
+ if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA))
+ bio_list_add(&info->defer_bios, bio);
+ else {
+ inc_all_io_entry(info->tc->pool, bio);
- wake_worker(pool);
+ /*
+ * We can't issue the bios with the bio prison lock
+ * held, so we add them to a list to issue on
+ * return from this function.
+ */
+ bio_list_add(&info->issue_bios, bio);
+ }
+ }
+}
+
+static void inc_remap_and_issue_cell(struct thin_c *tc,
+ struct dm_bio_prison_cell *cell,
+ dm_block_t block)
+{
+ struct bio *bio;
+ struct remap_info info;
+
+ info.tc = tc;
+ bio_list_init(&info.defer_bios);
+ bio_list_init(&info.issue_bios);
+
+ /*
+ * We have to be careful to inc any bios we're about to issue
+ * before the cell is released, and avoid a race with new bios
+ * being added to the cell.
+ */
+ cell_visit_release(tc->pool, __inc_remap_and_issue_cell,
+ &info, cell);
+
+ while ((bio = bio_list_pop(&info.defer_bios)))
+ thin_defer_bio(tc, bio);
+
+ while ((bio = bio_list_pop(&info.issue_bios)))
+ remap_and_issue(info.tc, bio, block);
}
static void process_prepared_mapping_fail(struct dm_thin_new_mapping *m)
@@ -706,10 +838,13 @@ static void process_prepared_mapping(struct dm_thin_new_mapping *m)
* the bios in the cell.
*/
if (bio) {
- cell_defer_no_holder(tc, m->cell);
+ inc_remap_and_issue_cell(tc, m->cell, m->data_block);
bio_endio(bio, 0);
- } else
- cell_defer(tc, m->cell);
+ } else {
+ inc_all_io_entry(tc->pool, m->cell->holder);
+ remap_and_issue(tc, m->cell->holder, m->data_block);
+ inc_remap_and_issue_cell(tc, m->cell, m->data_block);
+ }
out:
list_del(&m->list);
@@ -842,6 +977,20 @@ static void ll_zero(struct thin_c *tc, struct dm_thin_new_mapping *m,
}
}
+static void remap_and_issue_overwrite(struct thin_c *tc, struct bio *bio,
+ dm_block_t data_block,
+ struct dm_thin_new_mapping *m)
+{
+ struct pool *pool = tc->pool;
+ struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
+
+ h->overwrite_mapping = m;
+ m->bio = bio;
+ save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
+ inc_all_io_entry(pool, bio);
+ remap_and_issue(tc, bio, data_block);
+}
+
/*
* A partial copy also needs to zero the uncopied region.
*/
@@ -876,15 +1025,9 @@ static void schedule_copy(struct thin_c *tc, dm_block_t virt_block,
* If the whole block of data is being overwritten, we can issue the
* bio immediately. Otherwise we use kcopyd to clone the data first.
*/
- if (io_overwrites_block(pool, bio)) {
- struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
-
- h->overwrite_mapping = m;
- m->bio = bio;
- save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
- inc_all_io_entry(pool, bio);
- remap_and_issue(tc, bio, data_dest);
- } else {
+ if (io_overwrites_block(pool, bio))
+ remap_and_issue_overwrite(tc, bio, data_dest, m);
+ else {
struct dm_io_region from, to;
from.bdev = origin->bdev;
@@ -953,16 +1096,10 @@ static void schedule_zero(struct thin_c *tc, dm_block_t virt_block,
if (!pool->pf.zero_new_blocks)
process_prepared_mapping(m);
- else if (io_overwrites_block(pool, bio)) {
- struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
-
- h->overwrite_mapping = m;
- m->bio = bio;
- save_and_set_endio(bio, &m->saved_bi_end_io, overwrite_endio);
- inc_all_io_entry(pool, bio);
- remap_and_issue(tc, bio, data_block);
+ else if (io_overwrites_block(pool, bio))
+ remap_and_issue_overwrite(tc, bio, data_block, m);
- } else
+ else
ll_zero(tc, m,
data_block * pool->sectors_per_block,
(data_block + 1) * pool->sectors_per_block);
@@ -1134,29 +1271,25 @@ static void retry_bios_on_resume(struct pool *pool, struct dm_bio_prison_cell *c
bio_list_init(&bios);
cell_release(pool, cell, &bios);
- error = should_error_unserviceable_bio(pool);
- if (error)
- while ((bio = bio_list_pop(&bios)))
- bio_endio(bio, error);
- else
- while ((bio = bio_list_pop(&bios)))
- retry_on_resume(bio);
+ while ((bio = bio_list_pop(&bios)))
+ retry_on_resume(bio);
}
-static void process_discard(struct thin_c *tc, struct bio *bio)
+static void process_discard_cell(struct thin_c *tc, struct dm_bio_prison_cell *cell)
{
int r;
- unsigned long flags;
+ struct bio *bio = cell->holder;
struct pool *pool = tc->pool;
- struct dm_bio_prison_cell *cell, *cell2;
- struct dm_cell_key key, key2;
+ struct dm_bio_prison_cell *cell2;
+ struct dm_cell_key key2;
dm_block_t block = get_bio_block(tc, bio);
struct dm_thin_lookup_result lookup_result;
struct dm_thin_new_mapping *m;
- build_virtual_key(tc->td, block, &key);
- if (bio_detain(tc->pool, &key, bio, &cell))
+ if (tc->requeue_mode) {
+ cell_requeue(pool, cell);
return;
+ }
r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
switch (r) {
@@ -1187,12 +1320,9 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
m->cell2 = cell2;
m->bio = bio;
- if (!dm_deferred_set_add_work(pool->all_io_ds, &m->list)) {
- spin_lock_irqsave(&pool->lock, flags);
- list_add_tail(&m->list, &pool->prepared_discards);
- spin_unlock_irqrestore(&pool->lock, flags);
- wake_worker(pool);
- }
+ if (!dm_deferred_set_add_work(pool->all_io_ds, &m->list))
+ pool->process_prepared_discard(m);
+
} else {
inc_all_io_entry(pool, bio);
cell_defer_no_holder(tc, cell);
@@ -1227,6 +1357,19 @@ static void process_discard(struct thin_c *tc, struct bio *bio)
}
}
+static void process_discard_bio(struct thin_c *tc, struct bio *bio)
+{
+ struct dm_bio_prison_cell *cell;
+ struct dm_cell_key key;
+ dm_block_t block = get_bio_block(tc, bio);
+
+ build_virtual_key(tc->td, block, &key);
+ if (bio_detain(tc->pool, &key, bio, &cell))
+ return;
+
+ process_discard_cell(tc, cell);
+}
+
static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
struct dm_cell_key *key,
struct dm_thin_lookup_result *lookup_result,
@@ -1255,11 +1398,53 @@ static void break_sharing(struct thin_c *tc, struct bio *bio, dm_block_t block,
}
}
+static void __remap_and_issue_shared_cell(void *context,
+ struct dm_bio_prison_cell *cell)
+{
+ struct remap_info *info = context;
+ struct bio *bio;
+
+ while ((bio = bio_list_pop(&cell->bios))) {
+ if ((bio_data_dir(bio) == WRITE) ||
+ (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)))
+ bio_list_add(&info->defer_bios, bio);
+ else {
+ struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));;
+
+ h->shared_read_entry = dm_deferred_entry_inc(info->tc->pool->shared_read_ds);
+ inc_all_io_entry(info->tc->pool, bio);
+ bio_list_add(&info->issue_bios, bio);
+ }
+ }
+}
+
+static void remap_and_issue_shared_cell(struct thin_c *tc,
+ struct dm_bio_prison_cell *cell,
+ dm_block_t block)
+{
+ struct bio *bio;
+ struct remap_info info;
+
+ info.tc = tc;
+ bio_list_init(&info.defer_bios);
+ bio_list_init(&info.issue_bios);
+
+ cell_visit_release(tc->pool, __remap_and_issue_shared_cell,
+ &info, cell);
+
+ while ((bio = bio_list_pop(&info.defer_bios)))
+ thin_defer_bio(tc, bio);
+
+ while ((bio = bio_list_pop(&info.issue_bios)))
+ remap_and_issue(tc, bio, block);
+}
+
static void process_shared_bio(struct thin_c *tc, struct bio *bio,
dm_block_t block,
- struct dm_thin_lookup_result *lookup_result)
+ struct dm_thin_lookup_result *lookup_result,
+ struct dm_bio_prison_cell *virt_cell)
{
- struct dm_bio_prison_cell *cell;
+ struct dm_bio_prison_cell *data_cell;
struct pool *pool = tc->pool;
struct dm_cell_key key;
@@ -1268,19 +1453,23 @@ static void process_shared_bio(struct thin_c *tc, struct bio *bio,
* of being broken so we have nothing further to do here.
*/
build_data_key(tc->td, lookup_result->block, &key);
- if (bio_detain(pool, &key, bio, &cell))
+ if (bio_detain(pool, &key, bio, &data_cell)) {
+ cell_defer_no_holder(tc, virt_cell);
return;
+ }
- if (bio_data_dir(bio) == WRITE && bio->bi_iter.bi_size)
- break_sharing(tc, bio, block, &key, lookup_result, cell);
- else {
+ if (bio_data_dir(bio) == WRITE && bio->bi_iter.bi_size) {
+ break_sharing(tc, bio, block, &key, lookup_result, data_cell);
+ cell_defer_no_holder(tc, virt_cell);
+ } else {
struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
h->shared_read_entry = dm_deferred_entry_inc(pool->shared_read_ds);
inc_all_io_entry(pool, bio);
- cell_defer_no_holder(tc, cell);
-
remap_and_issue(tc, bio, lookup_result->block);
+
+ remap_and_issue_shared_cell(tc, data_cell, lookup_result->block);
+ remap_and_issue_shared_cell(tc, virt_cell, lookup_result->block);
}
}
@@ -1333,34 +1522,28 @@ static void provision_block(struct thin_c *tc, struct bio *bio, dm_block_t block
}
}
-static void process_bio(struct thin_c *tc, struct bio *bio)
+static void process_cell(struct thin_c *tc, struct dm_bio_prison_cell *cell)
{
int r;
struct pool *pool = tc->pool;
+ struct bio *bio = cell->holder;
dm_block_t block = get_bio_block(tc, bio);
- struct dm_bio_prison_cell *cell;
- struct dm_cell_key key;
struct dm_thin_lookup_result lookup_result;
- /*
- * If cell is already occupied, then the block is already
- * being provisioned so we have nothing further to do here.
- */
- build_virtual_key(tc->td, block, &key);
- if (bio_detain(pool, &key, bio, &cell))
+ if (tc->requeue_mode) {
+ cell_requeue(pool, cell);
return;
+ }
r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
switch (r) {
case 0:
- if (lookup_result.shared) {
- process_shared_bio(tc, bio, block, &lookup_result);
- cell_defer_no_holder(tc, cell); /* FIXME: pass this cell into process_shared? */
- } else {
+ if (lookup_result.shared)
+ process_shared_bio(tc, bio, block, &lookup_result, cell);
+ else {
inc_all_io_entry(pool, bio);
- cell_defer_no_holder(tc, cell);
-
remap_and_issue(tc, bio, lookup_result.block);
+ inc_remap_and_issue_cell(tc, cell, lookup_result.block);
}
break;
@@ -1394,7 +1577,26 @@ static void process_bio(struct thin_c *tc, struct bio *bio)
}
}
-static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
+static void process_bio(struct thin_c *tc, struct bio *bio)
+{
+ struct pool *pool = tc->pool;
+ dm_block_t block = get_bio_block(tc, bio);
+ struct dm_bio_prison_cell *cell;
+ struct dm_cell_key key;
+
+ /*
+ * If cell is already occupied, then the block is already
+ * being provisioned so we have nothing further to do here.
+ */
+ build_virtual_key(tc->td, block, &key);
+ if (bio_detain(pool, &key, bio, &cell))
+ return;
+
+ process_cell(tc, cell);
+}
+
+static void __process_bio_read_only(struct thin_c *tc, struct bio *bio,
+ struct dm_bio_prison_cell *cell)
{
int r;
int rw = bio_data_dir(bio);
@@ -1404,15 +1606,21 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
r = dm_thin_find_block(tc->td, block, 1, &lookup_result);
switch (r) {
case 0:
- if (lookup_result.shared && (rw == WRITE) && bio->bi_iter.bi_size)
+ if (lookup_result.shared && (rw == WRITE) && bio->bi_iter.bi_size) {
handle_unserviceable_bio(tc->pool, bio);
- else {
+ if (cell)
+ cell_defer_no_holder(tc, cell);
+ } else {
inc_all_io_entry(tc->pool, bio);
remap_and_issue(tc, bio, lookup_result.block);
+ if (cell)
+ inc_remap_and_issue_cell(tc, cell, lookup_result.block);
}
break;
case -ENODATA:
+ if (cell)
+ cell_defer_no_holder(tc, cell);
if (rw != READ) {
handle_unserviceable_bio(tc->pool, bio);
break;
@@ -1431,11 +1639,23 @@ static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
default:
DMERR_LIMIT("%s: dm_thin_find_block() failed: error = %d",
__func__, r);
+ if (cell)
+ cell_defer_no_holder(tc, cell);
bio_io_error(bio);
break;
}
}
+static void process_bio_read_only(struct thin_c *tc, struct bio *bio)
+{
+ __process_bio_read_only(tc, bio, NULL);
+}
+
+static void process_cell_read_only(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+{
+ __process_bio_read_only(tc, cell->holder, cell);
+}
+
static void process_bio_success(struct thin_c *tc, struct bio *bio)
{
bio_endio(bio, 0);
@@ -1446,6 +1666,16 @@ static void process_bio_fail(struct thin_c *tc, struct bio *bio)
bio_io_error(bio);
}
+static void process_cell_success(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+{
+ cell_success(tc->pool, cell);
+}
+
+static void process_cell_fail(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+{
+ cell_error(tc->pool, cell);
+}
+
/*
* FIXME: should we also commit due to size of transaction, measured in
* metadata blocks?
@@ -1527,9 +1757,10 @@ static void process_thin_deferred_bios(struct thin_c *tc)
struct bio *bio;
struct bio_list bios;
struct blk_plug plug;
+ unsigned count = 0;
if (tc->requeue_mode) {
- requeue_bio_list(tc, &tc->deferred_bio_list);
+ error_thin_bio_list(tc, &tc->deferred_bio_list, DM_ENDIO_REQUEUE);
return;
}
@@ -1568,10 +1799,97 @@ static void process_thin_deferred_bios(struct thin_c *tc)
pool->process_discard(tc, bio);
else
pool->process_bio(tc, bio);
+
+ if ((count++ & 127) == 0) {
+ throttle_work_update(&pool->throttle);
+ dm_pool_issue_prefetches(pool->pmd);
+ }
}
blk_finish_plug(&plug);
}
+static int cmp_cells(const void *lhs, const void *rhs)
+{
+ struct dm_bio_prison_cell *lhs_cell = *((struct dm_bio_prison_cell **) lhs);
+ struct dm_bio_prison_cell *rhs_cell = *((struct dm_bio_prison_cell **) rhs);
+
+ BUG_ON(!lhs_cell->holder);
+ BUG_ON(!rhs_cell->holder);
+
+ if (lhs_cell->holder->bi_iter.bi_sector < rhs_cell->holder->bi_iter.bi_sector)
+ return -1;
+
+ if (lhs_cell->holder->bi_iter.bi_sector > rhs_cell->holder->bi_iter.bi_sector)
+ return 1;
+
+ return 0;
+}
+
+static unsigned sort_cells(struct pool *pool, struct list_head *cells)
+{
+ unsigned count = 0;
+ struct dm_bio_prison_cell *cell, *tmp;
+
+ list_for_each_entry_safe(cell, tmp, cells, user_list) {
+ if (count >= CELL_SORT_ARRAY_SIZE)
+ break;
+
+ pool->cell_sort_array[count++] = cell;
+ list_del(&cell->user_list);
+ }
+
+ sort(pool->cell_sort_array, count, sizeof(cell), cmp_cells, NULL);
+
+ return count;
+}
+
+static void process_thin_deferred_cells(struct thin_c *tc)
+{
+ struct pool *pool = tc->pool;
+ unsigned long flags;
+ struct list_head cells;
+ struct dm_bio_prison_cell *cell;
+ unsigned i, j, count;
+
+ INIT_LIST_HEAD(&cells);
+
+ spin_lock_irqsave(&tc->lock, flags);
+ list_splice_init(&tc->deferred_cells, &cells);
+ spin_unlock_irqrestore(&tc->lock, flags);
+
+ if (list_empty(&cells))
+ return;
+
+ do {
+ count = sort_cells(tc->pool, &cells);
+
+ for (i = 0; i < count; i++) {
+ cell = pool->cell_sort_array[i];
+ BUG_ON(!cell->holder);
+
+ /*
+ * If we've got no free new_mapping structs, and processing
+ * this bio might require one, we pause until there are some
+ * prepared mappings to process.
+ */
+ if (ensure_next_mapping(pool)) {
+ for (j = i; j < count; j++)
+ list_add(&pool->cell_sort_array[j]->user_list, &cells);
+
+ spin_lock_irqsave(&tc->lock, flags);
+ list_splice(&cells, &tc->deferred_cells);
+ spin_unlock_irqrestore(&tc->lock, flags);
+ return;
+ }
+
+ if (cell->holder->bi_rw & REQ_DISCARD)
+ pool->process_discard_cell(tc, cell);
+ else
+ pool->process_cell(tc, cell);
+ }
+ } while (!list_empty(&cells));
+}
+
static void thin_get(struct thin_c *tc);
static void thin_put(struct thin_c *tc);
@@ -1620,6 +1938,7 @@ static void process_deferred_bios(struct pool *pool)
tc = get_first_thin(pool);
while (tc) {
+ process_thin_deferred_cells(tc);
process_thin_deferred_bios(tc);
tc = get_next_thin(pool, tc);
}
@@ -1653,9 +1972,15 @@ static void do_worker(struct work_struct *ws)
{
struct pool *pool = container_of(ws, struct pool, worker);
+ throttle_work_start(&pool->throttle);
+ dm_pool_issue_prefetches(pool->pmd);
+ throttle_work_update(&pool->throttle);
process_prepared(pool, &pool->prepared_mappings, &pool->process_prepared_mapping);
+ throttle_work_update(&pool->throttle);
process_prepared(pool, &pool->prepared_discards, &pool->process_prepared_discard);
+ throttle_work_update(&pool->throttle);
process_deferred_bios(pool);
+ throttle_work_complete(&pool->throttle);
}
/*
@@ -1792,6 +2117,8 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
dm_pool_metadata_read_only(pool->pmd);
pool->process_bio = process_bio_fail;
pool->process_discard = process_bio_fail;
+ pool->process_cell = process_cell_fail;
+ pool->process_discard_cell = process_cell_fail;
pool->process_prepared_mapping = process_prepared_mapping_fail;
pool->process_prepared_discard = process_prepared_discard_fail;
@@ -1804,6 +2131,8 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
dm_pool_metadata_read_only(pool->pmd);
pool->process_bio = process_bio_read_only;
pool->process_discard = process_bio_success;
+ pool->process_cell = process_cell_read_only;
+ pool->process_discard_cell = process_cell_success;
pool->process_prepared_mapping = process_prepared_mapping_fail;
pool->process_prepared_discard = process_prepared_discard_passdown;
@@ -1822,7 +2151,9 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
if (old_mode != new_mode)
notify_of_pool_mode_change(pool, "out-of-data-space");
pool->process_bio = process_bio_read_only;
- pool->process_discard = process_discard;
+ pool->process_discard = process_discard_bio;
+ pool->process_cell = process_cell_read_only;
+ pool->process_discard_cell = process_discard_cell;
pool->process_prepared_mapping = process_prepared_mapping;
pool->process_prepared_discard = process_prepared_discard_passdown;
@@ -1835,7 +2166,9 @@ static void set_pool_mode(struct pool *pool, enum pool_mode new_mode)
notify_of_pool_mode_change(pool, "write");
dm_pool_metadata_read_write(pool->pmd);
pool->process_bio = process_bio;
- pool->process_discard = process_discard;
+ pool->process_discard = process_discard_bio;
+ pool->process_cell = process_cell;
+ pool->process_discard_cell = process_discard_cell;
pool->process_prepared_mapping = process_prepared_mapping;
pool->process_prepared_discard = process_prepared_discard;
break;
@@ -1895,6 +2228,29 @@ static void thin_defer_bio(struct thin_c *tc, struct bio *bio)
wake_worker(pool);
}
+static void thin_defer_bio_with_throttle(struct thin_c *tc, struct bio *bio)
+{
+ struct pool *pool = tc->pool;
+
+ throttle_lock(&pool->throttle);
+ thin_defer_bio(tc, bio);
+ throttle_unlock(&pool->throttle);
+}
+
+static void thin_defer_cell(struct thin_c *tc, struct dm_bio_prison_cell *cell)
+{
+ unsigned long flags;
+ struct pool *pool = tc->pool;
+
+ throttle_lock(&pool->throttle);
+ spin_lock_irqsave(&tc->lock, flags);
+ list_add_tail(&cell->user_list, &tc->deferred_cells);
+ spin_unlock_irqrestore(&tc->lock, flags);
+ throttle_unlock(&pool->throttle);
+
+ wake_worker(pool);
+}
+
static void thin_hook_bio(struct thin_c *tc, struct bio *bio)
{
struct dm_thin_endio_hook *h = dm_per_bio_data(bio, sizeof(struct dm_thin_endio_hook));
@@ -1915,8 +2271,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
dm_block_t block = get_bio_block(tc, bio);
struct dm_thin_device *td = tc->td;
struct dm_thin_lookup_result result;
- struct dm_bio_prison_cell cell1, cell2;
- struct dm_bio_prison_cell *cell_result;
+ struct dm_bio_prison_cell *virt_cell, *data_cell;
struct dm_cell_key key;
thin_hook_bio(tc, bio);
@@ -1932,7 +2287,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
}
if (bio->bi_rw & (REQ_DISCARD | REQ_FLUSH | REQ_FUA)) {
- thin_defer_bio(tc, bio);
+ thin_defer_bio_with_throttle(tc, bio);
return DM_MAPIO_SUBMITTED;
}
@@ -1941,7 +2296,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
* there's a race with discard.
*/
build_virtual_key(tc->td, block, &key);
- if (dm_bio_detain(tc->pool->prison, &key, bio, &cell1, &cell_result))
+ if (bio_detain(tc->pool, &key, bio, &virt_cell))
return DM_MAPIO_SUBMITTED;
r = dm_thin_find_block(td, block, 0, &result);
@@ -1966,20 +2321,19 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
* More distant ancestors are irrelevant. The
* shared flag will be set in their case.
*/
- thin_defer_bio(tc, bio);
- cell_defer_no_holder_no_free(tc, &cell1);
+ thin_defer_cell(tc, virt_cell);
return DM_MAPIO_SUBMITTED;
}
build_data_key(tc->td, result.block, &key);
- if (dm_bio_detain(tc->pool->prison, &key, bio, &cell2, &cell_result)) {
- cell_defer_no_holder_no_free(tc, &cell1);
+ if (bio_detain(tc->pool, &key, bio, &data_cell)) {
+ cell_defer_no_holder(tc, virt_cell);
return DM_MAPIO_SUBMITTED;
}
inc_all_io_entry(tc->pool, bio);
- cell_defer_no_holder_no_free(tc, &cell2);
- cell_defer_no_holder_no_free(tc, &cell1);
+ cell_defer_no_holder(tc, data_cell);
+ cell_defer_no_holder(tc, virt_cell);
remap(tc, bio, result.block);
return DM_MAPIO_REMAPPED;
@@ -1991,18 +2345,13 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
* of doing so.
*/
handle_unserviceable_bio(tc->pool, bio);
- cell_defer_no_holder_no_free(tc, &cell1);
+ cell_defer_no_holder(tc, virt_cell);
return DM_MAPIO_SUBMITTED;
}
/* fall through */
case -EWOULDBLOCK:
- /*
- * In future, the failed dm_thin_find_block above could
- * provide the hint to load the metadata into cache.
- */
- thin_defer_bio(tc, bio);
- cell_defer_no_holder_no_free(tc, &cell1);
+ thin_defer_cell(tc, virt_cell);
return DM_MAPIO_SUBMITTED;
default:
@@ -2012,7 +2361,7 @@ static int thin_bio_map(struct dm_target *ti, struct bio *bio)
* pool is switched to fail-io mode.
*/
bio_io_error(bio);
- cell_defer_no_holder_no_free(tc, &cell1);
+ cell_defer_no_holder(tc, virt_cell);
return DM_MAPIO_SUBMITTED;
}
}
@@ -2193,7 +2542,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
pool->sectors_per_block_shift = __ffs(block_size);
pool->low_water_blocks = 0;
pool_features_init(&pool->pf);
- pool->prison = dm_bio_prison_create(PRISON_CELLS);
+ pool->prison = dm_bio_prison_create();
if (!pool->prison) {
*error = "Error creating pool's bio prison";
err_p = ERR_PTR(-ENOMEM);
@@ -2219,6 +2568,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
goto bad_wq;
}
+ throttle_init(&pool->throttle);
INIT_WORK(&pool->worker, do_worker);
INIT_DELAYED_WORK(&pool->waker, do_waker);
INIT_DELAYED_WORK(&pool->no_space_timeout, do_no_space_timeout);
@@ -2228,6 +2578,7 @@ static struct pool *pool_create(struct mapped_device *pool_md,
INIT_LIST_HEAD(&pool->prepared_discards);
INIT_LIST_HEAD(&pool->active_thins);
pool->low_water_triggered = false;
+ pool->suspended = true;
pool->shared_read_ds = dm_deferred_set_create();
if (!pool->shared_read_ds) {
@@ -2764,20 +3115,77 @@ static int pool_preresume(struct dm_target *ti)
return 0;
}
+static void pool_suspend_active_thins(struct pool *pool)
+{
+ struct thin_c *tc;
+
+ /* Suspend all active thin devices */
+ tc = get_first_thin(pool);
+ while (tc) {
+ dm_internal_suspend_noflush(tc->thin_md);
+ tc = get_next_thin(pool, tc);
+ }
+}
+
+static void pool_resume_active_thins(struct pool *pool)
+{
+ struct thin_c *tc;
+
+ /* Resume all active thin devices */
+ tc = get_first_thin(pool);
+ while (tc) {
+ dm_internal_resume(tc->thin_md);
+ tc = get_next_thin(pool, tc);
+ }
+}
+
static void pool_resume(struct dm_target *ti)
{
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
unsigned long flags;
+ /*
+ * Must requeue active_thins' bios and then resume
+ * active_thins _before_ clearing 'suspend' flag.
+ */
+ requeue_bios(pool);
+ pool_resume_active_thins(pool);
+
spin_lock_irqsave(&pool->lock, flags);
pool->low_water_triggered = false;
+ pool->suspended = false;
spin_unlock_irqrestore(&pool->lock, flags);
- requeue_bios(pool);
do_waker(&pool->waker.work);
}
+static void pool_presuspend(struct dm_target *ti)
+{
+ struct pool_c *pt = ti->private;
+ struct pool *pool = pt->pool;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pool->lock, flags);
+ pool->suspended = true;
+ spin_unlock_irqrestore(&pool->lock, flags);
+
+ pool_suspend_active_thins(pool);
+}
+
+static void pool_presuspend_undo(struct dm_target *ti)
+{
+ struct pool_c *pt = ti->private;
+ struct pool *pool = pt->pool;
+ unsigned long flags;
+
+ pool_resume_active_thins(pool);
+
+ spin_lock_irqsave(&pool->lock, flags);
+ pool->suspended = false;
+ spin_unlock_irqrestore(&pool->lock, flags);
+}
+
static void pool_postsuspend(struct dm_target *ti)
{
struct pool_c *pt = ti->private;
@@ -2949,7 +3357,6 @@ static int process_release_metadata_snap_mesg(unsigned argc, char **argv, struct
* create_thin <dev_id>
* create_snap <dev_id> <origin_id>
* delete <dev_id>
- * trim <dev_id> <new_size_in_sectors>
* set_transaction_id <current_trans_id> <new_trans_id>
* reserve_metadata_snap
* release_metadata_snap
@@ -3177,15 +3584,35 @@ static void pool_io_hints(struct dm_target *ti, struct queue_limits *limits)
{
struct pool_c *pt = ti->private;
struct pool *pool = pt->pool;
- uint64_t io_opt_sectors = limits->io_opt >> SECTOR_SHIFT;
+ sector_t io_opt_sectors = limits->io_opt >> SECTOR_SHIFT;
+
+ /*
+ * If max_sectors is smaller than pool->sectors_per_block adjust it
+ * to the highest possible power-of-2 factor of pool->sectors_per_block.
+ * This is especially beneficial when the pool's data device is a RAID
+ * device that has a full stripe width that matches pool->sectors_per_block
+ * -- because even though partial RAID stripe-sized IOs will be issued to a
+ * single RAID stripe; when aggregated they will end on a full RAID stripe
+ * boundary.. which avoids additional partial RAID stripe writes cascading
+ */
+ if (limits->max_sectors < pool->sectors_per_block) {
+ while (!is_factor(pool->sectors_per_block, limits->max_sectors)) {
+ if ((limits->max_sectors & (limits->max_sectors - 1)) == 0)
+ limits->max_sectors--;
+ limits->max_sectors = rounddown_pow_of_two(limits->max_sectors);
+ }
+ }
/*
* If the system-determined stacked limits are compatible with the
* pool's blocksize (io_opt is a factor) do not override them.
*/
if (io_opt_sectors < pool->sectors_per_block ||
- do_div(io_opt_sectors, pool->sectors_per_block)) {
- blk_limits_io_min(limits, pool->sectors_per_block << SECTOR_SHIFT);
+ !is_factor(io_opt_sectors, pool->sectors_per_block)) {
+ if (is_factor(pool->sectors_per_block, limits->max_sectors))
+ blk_limits_io_min(limits, limits->max_sectors << SECTOR_SHIFT);
+ else
+ blk_limits_io_min(limits, pool->sectors_per_block << SECTOR_SHIFT);
blk_limits_io_opt(limits, pool->sectors_per_block << SECTOR_SHIFT);
}
@@ -3214,11 +3641,13 @@ static struct target_type pool_target = {
.name = "thin-pool",
.features = DM_TARGET_SINGLETON | DM_TARGET_ALWAYS_WRITEABLE |
DM_TARGET_IMMUTABLE,
- .version = {1, 13, 0},
+ .version = {1, 14, 0},
.module = THIS_MODULE,
.ctr = pool_ctr,
.dtr = pool_dtr,
.map = pool_map,
+ .presuspend = pool_presuspend,
+ .presuspend_undo = pool_presuspend_undo,
.postsuspend = pool_postsuspend,
.preresume = pool_preresume,
.resume = pool_resume,
@@ -3248,14 +3677,14 @@ static void thin_dtr(struct dm_target *ti)
struct thin_c *tc = ti->private;
unsigned long flags;
- thin_put(tc);
- wait_for_completion(&tc->can_destroy);
-
spin_lock_irqsave(&tc->pool->lock, flags);
list_del_rcu(&tc->list);
spin_unlock_irqrestore(&tc->pool->lock, flags);
synchronize_rcu();
+ thin_put(tc);
+ wait_for_completion(&tc->can_destroy);
+
mutex_lock(&dm_thin_pool_table.mutex);
__pool_dec(tc->pool);
@@ -3302,7 +3731,9 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
r = -ENOMEM;
goto out_unlock;
}
+ tc->thin_md = dm_table_get_md(ti->table);
spin_lock_init(&tc->lock);
+ INIT_LIST_HEAD(&tc->deferred_cells);
bio_list_init(&tc->deferred_bio_list);
bio_list_init(&tc->retry_on_resume_list);
tc->sort_bio_list = RB_ROOT;
@@ -3347,18 +3778,18 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
if (get_pool_mode(tc->pool) == PM_FAIL) {
ti->error = "Couldn't open thin device, Pool is in fail mode";
r = -EINVAL;
- goto bad_thin_open;
+ goto bad_pool;
}
r = dm_pool_open_thin_device(tc->pool->pmd, tc->dev_id, &tc->td);
if (r) {
ti->error = "Couldn't open thin internal device";
- goto bad_thin_open;
+ goto bad_pool;
}
r = dm_set_target_max_io_len(ti, tc->pool->sectors_per_block);
if (r)
- goto bad_target_max_io_len;
+ goto bad;
ti->num_flush_bios = 1;
ti->flush_supported = true;
@@ -3373,14 +3804,16 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
ti->split_discard_bios = true;
}
- dm_put(pool_md);
-
mutex_unlock(&dm_thin_pool_table.mutex);
- atomic_set(&tc->refcount, 1);
- init_completion(&tc->can_destroy);
-
spin_lock_irqsave(&tc->pool->lock, flags);
+ if (tc->pool->suspended) {
+ spin_unlock_irqrestore(&tc->pool->lock, flags);
+ mutex_lock(&dm_thin_pool_table.mutex); /* reacquire for __pool_dec */
+ ti->error = "Unable to activate thin device while pool is suspended";
+ r = -EINVAL;
+ goto bad;
+ }
list_add_tail_rcu(&tc->list, &tc->pool->active_thins);
spin_unlock_irqrestore(&tc->pool->lock, flags);
/*
@@ -3391,11 +3824,16 @@ static int thin_ctr(struct dm_target *ti, unsigned argc, char **argv)
*/
synchronize_rcu();
+ dm_put(pool_md);
+
+ atomic_set(&tc->refcount, 1);
+ init_completion(&tc->can_destroy);
+
return 0;
-bad_target_max_io_len:
+bad:
dm_pool_close_thin_device(tc->td);
-bad_thin_open:
+bad_pool:
__pool_dec(tc->pool);
bad_pool_lookup:
dm_put(pool_md);
@@ -3541,6 +3979,21 @@ err:
DMEMIT("Error");
}
+static int thin_merge(struct dm_target *ti, struct bvec_merge_data *bvm,
+ struct bio_vec *biovec, int max_size)
+{
+ struct thin_c *tc = ti->private;
+ struct request_queue *q = bdev_get_queue(tc->pool_dev->bdev);
+
+ if (!q->merge_bvec_fn)
+ return max_size;
+
+ bvm->bi_bdev = tc->pool_dev->bdev;
+ bvm->bi_sector = dm_target_offset(ti, bvm->bi_sector);
+
+ return min(max_size, q->merge_bvec_fn(q, bvm, biovec));
+}
+
static int thin_iterate_devices(struct dm_target *ti,
iterate_devices_callout_fn fn, void *data)
{
@@ -3565,7 +4018,7 @@ static int thin_iterate_devices(struct dm_target *ti,
static struct target_type thin_target = {
.name = "thin",
- .version = {1, 13, 0},
+ .version = {1, 14, 0},
.module = THIS_MODULE,
.ctr = thin_ctr,
.dtr = thin_dtr,
@@ -3575,6 +4028,7 @@ static struct target_type thin_target = {
.presuspend = thin_presuspend,
.postsuspend = thin_postsuspend,
.status = thin_status,
+ .merge = thin_merge,
.iterate_devices = thin_iterate_devices,
};
diff --git a/drivers/md/dm.c b/drivers/md/dm.c
index 58f3927..8f37ed2 100644
--- a/drivers/md/dm.c
+++ b/drivers/md/dm.c
@@ -19,6 +19,7 @@
#include <linux/idr.h>
#include <linux/hdreg.h>
#include <linux/delay.h>
+#include <linux/wait.h>
#include <trace/events/block.h>
@@ -117,6 +118,7 @@ EXPORT_SYMBOL_GPL(dm_get_rq_mapinfo);
#define DMF_NOFLUSH_SUSPENDING 5
#define DMF_MERGE_IS_OPTIONAL 6
#define DMF_DEFERRED_REMOVE 7
+#define DMF_SUSPENDED_INTERNALLY 8
/*
* A dummy definition to make RCU happy.
@@ -140,7 +142,7 @@ struct mapped_device {
* Use dm_get_live_table{_fast} or take suspend_lock for
* dereference.
*/
- struct dm_table *map;
+ struct dm_table __rcu *map;
struct list_head table_devices;
struct mutex table_devices_lock;
@@ -525,14 +527,15 @@ retry:
goto out;
tgt = dm_table_get_target(map, 0);
+ if (!tgt->type->ioctl)
+ goto out;
if (dm_suspended_md(md)) {
r = -EAGAIN;
goto out;
}
- if (tgt->type->ioctl)
- r = tgt->type->ioctl(tgt, cmd, arg);
+ r = tgt->type->ioctl(tgt, cmd, arg);
out:
dm_put_live_table(md, srcu_idx);
@@ -1607,9 +1610,9 @@ static int dm_merge_bvec(struct request_queue *q,
* Find maximum amount of I/O that won't need splitting
*/
max_sectors = min(max_io_len(bvm->bi_sector, ti),
- (sector_t) BIO_MAX_SECTORS);
+ (sector_t) queue_max_sectors(q));
max_size = (max_sectors << SECTOR_SHIFT) - bvm->bi_size;
- if (max_size < 0)
+ if (unlikely(max_size < 0)) /* this shouldn't _ever_ happen */
max_size = 0;
/*
@@ -1621,10 +1624,10 @@ static int dm_merge_bvec(struct request_queue *q,
max_size = ti->type->merge(ti, bvm, biovec, max_size);
/*
* If the target doesn't support merge method and some of the devices
- * provided their merge_bvec method (we know this by looking at
- * queue_max_hw_sectors), then we can't allow bios with multiple vector
- * entries. So always set max_size to 0, and the code below allows
- * just one page.
+ * provided their merge_bvec method (we know this by looking for the
+ * max_hw_sectors that dm_set_device_limits may set), then we can't
+ * allow bios with multiple vector entries. So always set max_size
+ * to 0, and the code below allows just one page.
*/
else if (queue_max_hw_sectors(q) <= PAGE_SIZE >> 9)
max_size = 0;
@@ -2332,7 +2335,7 @@ static struct dm_table *__bind(struct mapped_device *md, struct dm_table *t,
merge_is_optional = dm_table_merge_is_optional(t);
- old_map = md->map;
+ old_map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
rcu_assign_pointer(md->map, t);
md->immutable_target_type = dm_table_get_immutable_target_type(t);
@@ -2341,7 +2344,8 @@ 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);
- dm_sync_table(md);
+ if (old_map)
+ dm_sync_table(md);
return old_map;
}
@@ -2351,7 +2355,7 @@ 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;
+ struct dm_table *map = rcu_dereference_protected(md->map, 1);
if (!map)
return NULL;
@@ -2716,36 +2720,18 @@ static void unlock_fs(struct mapped_device *md)
}
/*
- * We need to be able to change a mapping table under a mounted
- * filesystem. For example we might want to move some data in
- * the background. Before the table can be swapped with
- * dm_bind_table, dm_suspend must be called to flush any in
- * flight bios and ensure that any further io gets deferred.
- */
-/*
- * Suspend mechanism in request-based dm.
+ * If __dm_suspend returns 0, the device is completely quiescent
+ * now. There is no request-processing activity. All new requests
+ * are being added to md->deferred list.
*
- * 1. Flush all I/Os by lock_fs() if needed.
- * 2. Stop dispatching any I/O by stopping the request_queue.
- * 3. Wait for all in-flight I/Os to be completed or requeued.
- *
- * To abort suspend, start the request_queue.
+ * Caller must hold md->suspend_lock
*/
-int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
+static int __dm_suspend(struct mapped_device *md, struct dm_table *map,
+ unsigned suspend_flags, int interruptible)
{
- struct dm_table *map = NULL;
- int r = 0;
- int do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG ? 1 : 0;
- int noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG ? 1 : 0;
-
- mutex_lock(&md->suspend_lock);
-
- if (dm_suspended_md(md)) {
- r = -EINVAL;
- goto out_unlock;
- }
-
- map = md->map;
+ bool do_lockfs = suspend_flags & DM_SUSPEND_LOCKFS_FLAG;
+ bool noflush = suspend_flags & DM_SUSPEND_NOFLUSH_FLAG;
+ int r;
/*
* DMF_NOFLUSH_SUSPENDING must be set before presuspend.
@@ -2754,7 +2740,10 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
if (noflush)
set_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
- /* This does not get reverted if there's an error later. */
+ /*
+ * This gets reverted if there's an error later and the targets
+ * provide the .presuspend_undo hook.
+ */
dm_table_presuspend_targets(map);
/*
@@ -2765,8 +2754,10 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
*/
if (!noflush && do_lockfs) {
r = lock_fs(md);
- if (r)
- goto out_unlock;
+ if (r) {
+ dm_table_presuspend_undo_targets(map);
+ return r;
+ }
}
/*
@@ -2782,7 +2773,8 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
* flush_workqueue(md->wq).
*/
set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
- synchronize_srcu(&md->io_barrier);
+ if (map)
+ synchronize_srcu(&md->io_barrier);
/*
* Stop md->queue before flushing md->wq in case request-based
@@ -2798,11 +2790,12 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
* We call dm_wait_for_completion to wait for all existing requests
* to finish.
*/
- r = dm_wait_for_completion(md, TASK_INTERRUPTIBLE);
+ r = dm_wait_for_completion(md, interruptible);
if (noflush)
clear_bit(DMF_NOFLUSH_SUSPENDING, &md->flags);
- synchronize_srcu(&md->io_barrier);
+ if (map)
+ synchronize_srcu(&md->io_barrier);
/* were we interrupted ? */
if (r < 0) {
@@ -2812,14 +2805,56 @@ int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
start_queue(md->queue);
unlock_fs(md);
- goto out_unlock; /* pushback list is already flushed, so skip flush */
+ dm_table_presuspend_undo_targets(map);
+ /* pushback list is already flushed, so skip flush */
}
- /*
- * If dm_wait_for_completion returned 0, the device is completely
- * quiescent now. There is no request-processing activity. All new
- * requests are being added to md->deferred list.
- */
+ return r;
+}
+
+/*
+ * We need to be able to change a mapping table under a mounted
+ * filesystem. For example we might want to move some data in
+ * the background. Before the table can be swapped with
+ * dm_bind_table, dm_suspend must be called to flush any in
+ * flight bios and ensure that any further io gets deferred.
+ */
+/*
+ * Suspend mechanism in request-based dm.
+ *
+ * 1. Flush all I/Os by lock_fs() if needed.
+ * 2. Stop dispatching any I/O by stopping the request_queue.
+ * 3. Wait for all in-flight I/Os to be completed or requeued.
+ *
+ * To abort suspend, start the request_queue.
+ */
+int dm_suspend(struct mapped_device *md, unsigned suspend_flags)
+{
+ struct dm_table *map = NULL;
+ int r = 0;
+
+retry:
+ mutex_lock_nested(&md->suspend_lock, SINGLE_DEPTH_NESTING);
+
+ if (dm_suspended_md(md)) {
+ r = -EINVAL;
+ goto out_unlock;
+ }
+
+ if (dm_suspended_internally_md(md)) {
+ /* already internally suspended, wait for internal resume */
+ mutex_unlock(&md->suspend_lock);
+ r = wait_on_bit(&md->flags, DMF_SUSPENDED_INTERNALLY, TASK_INTERRUPTIBLE);
+ if (r)
+ return r;
+ goto retry;
+ }
+
+ map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
+
+ r = __dm_suspend(md, map, suspend_flags, TASK_INTERRUPTIBLE);
+ if (r)
+ goto out_unlock;
set_bit(DMF_SUSPENDED, &md->flags);
@@ -2830,22 +2865,13 @@ out_unlock:
return r;
}
-int dm_resume(struct mapped_device *md)
+static int __dm_resume(struct mapped_device *md, struct dm_table *map)
{
- int r = -EINVAL;
- struct dm_table *map = NULL;
-
- mutex_lock(&md->suspend_lock);
- if (!dm_suspended_md(md))
- goto out;
-
- map = md->map;
- if (!map || !dm_table_get_size(map))
- goto out;
-
- r = dm_table_resume_targets(map);
- if (r)
- goto out;
+ if (map) {
+ int r = dm_table_resume_targets(map);
+ if (r)
+ return r;
+ }
dm_queue_flush(md);
@@ -2859,6 +2885,37 @@ int dm_resume(struct mapped_device *md)
unlock_fs(md);
+ return 0;
+}
+
+int dm_resume(struct mapped_device *md)
+{
+ int r = -EINVAL;
+ struct dm_table *map = NULL;
+
+retry:
+ mutex_lock_nested(&md->suspend_lock, SINGLE_DEPTH_NESTING);
+
+ if (!dm_suspended_md(md))
+ goto out;
+
+ if (dm_suspended_internally_md(md)) {
+ /* already internally suspended, wait for internal resume */
+ mutex_unlock(&md->suspend_lock);
+ r = wait_on_bit(&md->flags, DMF_SUSPENDED_INTERNALLY, TASK_INTERRUPTIBLE);
+ if (r)
+ return r;
+ goto retry;
+ }
+
+ map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
+ if (!map || !dm_table_get_size(map))
+ goto out;
+
+ r = __dm_resume(md, map);
+ if (r)
+ goto out;
+
clear_bit(DMF_SUSPENDED, &md->flags);
r = 0;
@@ -2872,15 +2929,80 @@ out:
* Internal suspend/resume works like userspace-driven suspend. It waits
* until all bios finish and prevents issuing new bios to the target drivers.
* It may be used only from the kernel.
- *
- * Internal suspend holds md->suspend_lock, which prevents interaction with
- * userspace-driven suspend.
*/
-void dm_internal_suspend(struct mapped_device *md)
+static void __dm_internal_suspend(struct mapped_device *md, unsigned suspend_flags)
{
- mutex_lock(&md->suspend_lock);
+ struct dm_table *map = NULL;
+
+ if (dm_suspended_internally_md(md))
+ return; /* nested internal suspend */
+
+ if (dm_suspended_md(md)) {
+ set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+ return; /* nest suspend */
+ }
+
+ map = rcu_dereference_protected(md->map, lockdep_is_held(&md->suspend_lock));
+
+ /*
+ * Using TASK_UNINTERRUPTIBLE because only NOFLUSH internal suspend is
+ * supported. Properly supporting a TASK_INTERRUPTIBLE internal suspend
+ * would require changing .presuspend to return an error -- avoid this
+ * until there is a need for more elaborate variants of internal suspend.
+ */
+ (void) __dm_suspend(md, map, suspend_flags, TASK_UNINTERRUPTIBLE);
+
+ set_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+
+ dm_table_postsuspend_targets(map);
+}
+
+static void __dm_internal_resume(struct mapped_device *md)
+{
+ if (!dm_suspended_internally_md(md))
+ return; /* resume from nested internal suspend */
+
if (dm_suspended_md(md))
+ goto done; /* resume from nested suspend */
+
+ /*
+ * NOTE: existing callers don't need to call dm_table_resume_targets
+ * (which may fail -- so best to avoid it for now by passing NULL map)
+ */
+ (void) __dm_resume(md, NULL);
+
+done:
+ clear_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+ smp_mb__after_atomic();
+ wake_up_bit(&md->flags, DMF_SUSPENDED_INTERNALLY);
+}
+
+void dm_internal_suspend_noflush(struct mapped_device *md)
+{
+ mutex_lock(&md->suspend_lock);
+ __dm_internal_suspend(md, DM_SUSPEND_NOFLUSH_FLAG);
+ mutex_unlock(&md->suspend_lock);
+}
+EXPORT_SYMBOL_GPL(dm_internal_suspend_noflush);
+
+void dm_internal_resume(struct mapped_device *md)
+{
+ mutex_lock(&md->suspend_lock);
+ __dm_internal_resume(md);
+ mutex_unlock(&md->suspend_lock);
+}
+EXPORT_SYMBOL_GPL(dm_internal_resume);
+
+/*
+ * Fast variants of internal suspend/resume hold md->suspend_lock,
+ * which prevents interaction with userspace-driven suspend.
+ */
+
+void dm_internal_suspend_fast(struct mapped_device *md)
+{
+ mutex_lock(&md->suspend_lock);
+ if (dm_suspended_md(md) || dm_suspended_internally_md(md))
return;
set_bit(DMF_BLOCK_IO_FOR_SUSPEND, &md->flags);
@@ -2889,9 +3011,9 @@ void dm_internal_suspend(struct mapped_device *md)
dm_wait_for_completion(md, TASK_UNINTERRUPTIBLE);
}
-void dm_internal_resume(struct mapped_device *md)
+void dm_internal_resume_fast(struct mapped_device *md)
{
- if (dm_suspended_md(md))
+ if (dm_suspended_md(md) || dm_suspended_internally_md(md))
goto done;
dm_queue_flush(md);
@@ -2977,6 +3099,11 @@ int dm_suspended_md(struct mapped_device *md)
return test_bit(DMF_SUSPENDED, &md->flags);
}
+int dm_suspended_internally_md(struct mapped_device *md)
+{
+ return test_bit(DMF_SUSPENDED_INTERNALLY, &md->flags);
+}
+
int dm_test_deferred_remove_flag(struct mapped_device *md)
{
return test_bit(DMF_DEFERRED_REMOVE, &md->flags);
diff --git a/drivers/md/dm.h b/drivers/md/dm.h
index 988c7fb..84b0f9e4 100644
--- a/drivers/md/dm.h
+++ b/drivers/md/dm.h
@@ -65,6 +65,7 @@ void dm_table_set_restrictions(struct dm_table *t, struct request_queue *q,
struct queue_limits *limits);
struct list_head *dm_table_get_devices(struct dm_table *t);
void dm_table_presuspend_targets(struct dm_table *t);
+void dm_table_presuspend_undo_targets(struct dm_table *t);
void dm_table_postsuspend_targets(struct dm_table *t);
int dm_table_resume_targets(struct dm_table *t);
int dm_table_any_congested(struct dm_table *t, int bdi_bits);
@@ -129,6 +130,15 @@ int dm_deleting_md(struct mapped_device *md);
int dm_suspended_md(struct mapped_device *md);
/*
+ * Internal suspend and resume methods.
+ */
+int dm_suspended_internally_md(struct mapped_device *md);
+void dm_internal_suspend_fast(struct mapped_device *md);
+void dm_internal_resume_fast(struct mapped_device *md);
+void dm_internal_suspend_noflush(struct mapped_device *md);
+void dm_internal_resume(struct mapped_device *md);
+
+/*
* Test if the device is scheduled for deferred remove.
*/
int dm_test_deferred_remove_flag(struct mapped_device *md);
diff --git a/drivers/md/persistent-data/dm-array.c b/drivers/md/persistent-data/dm-array.c
index 1d75b1d..e64b61ad 100644
--- a/drivers/md/persistent-data/dm-array.c
+++ b/drivers/md/persistent-data/dm-array.c
@@ -645,8 +645,10 @@ static int array_resize(struct dm_array_info *info, dm_block_t root,
int r;
struct resize resize;
- if (old_size == new_size)
+ if (old_size == new_size) {
+ *new_root = root;
return 0;
+ }
resize.info = info;
resize.root = root;
diff --git a/drivers/md/persistent-data/dm-space-map-metadata.c b/drivers/md/persistent-data/dm-space-map-metadata.c
index 786b689..e8a9042 100644
--- a/drivers/md/persistent-data/dm-space-map-metadata.c
+++ b/drivers/md/persistent-data/dm-space-map-metadata.c
@@ -564,7 +564,9 @@ static int sm_bootstrap_get_nr_blocks(struct dm_space_map *sm, dm_block_t *count
{
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
- return smm->ll.nr_blocks;
+ *count = smm->ll.nr_blocks;
+
+ return 0;
}
static int sm_bootstrap_get_nr_free(struct dm_space_map *sm, dm_block_t *count)
@@ -581,7 +583,9 @@ static int sm_bootstrap_get_count(struct dm_space_map *sm, dm_block_t b,
{
struct sm_metadata *smm = container_of(sm, struct sm_metadata, sm);
- return b < smm->begin ? 1 : 0;
+ *result = (b < smm->begin) ? 1 : 0;
+
+ return 0;
}
static int sm_bootstrap_count_is_more_than_one(struct dm_space_map *sm,
diff --git a/drivers/md/persistent-data/dm-transaction-manager.c b/drivers/md/persistent-data/dm-transaction-manager.c
index 3bc30a0..9cb797d 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.c
+++ b/drivers/md/persistent-data/dm-transaction-manager.c
@@ -10,6 +10,8 @@
#include "dm-persistent-data-internal.h"
#include <linux/export.h>
+#include <linux/mutex.h>
+#include <linux/hash.h>
#include <linux/slab.h>
#include <linux/device-mapper.h>
@@ -17,6 +19,61 @@
/*----------------------------------------------------------------*/
+#define PREFETCH_SIZE 128
+#define PREFETCH_BITS 7
+#define PREFETCH_SENTINEL ((dm_block_t) -1ULL)
+
+struct prefetch_set {
+ struct mutex lock;
+ dm_block_t blocks[PREFETCH_SIZE];
+};
+
+static unsigned prefetch_hash(dm_block_t b)
+{
+ return hash_64(b, PREFETCH_BITS);
+}
+
+static void prefetch_wipe(struct prefetch_set *p)
+{
+ unsigned i;
+ for (i = 0; i < PREFETCH_SIZE; i++)
+ p->blocks[i] = PREFETCH_SENTINEL;
+}
+
+static void prefetch_init(struct prefetch_set *p)
+{
+ mutex_init(&p->lock);
+ prefetch_wipe(p);
+}
+
+static void prefetch_add(struct prefetch_set *p, dm_block_t b)
+{
+ unsigned h = prefetch_hash(b);
+
+ mutex_lock(&p->lock);
+ if (p->blocks[h] == PREFETCH_SENTINEL)
+ p->blocks[h] = b;
+
+ mutex_unlock(&p->lock);
+}
+
+static void prefetch_issue(struct prefetch_set *p, struct dm_block_manager *bm)
+{
+ unsigned i;
+
+ mutex_lock(&p->lock);
+
+ for (i = 0; i < PREFETCH_SIZE; i++)
+ if (p->blocks[i] != PREFETCH_SENTINEL) {
+ dm_bm_prefetch(bm, p->blocks[i]);
+ p->blocks[i] = PREFETCH_SENTINEL;
+ }
+
+ mutex_unlock(&p->lock);
+}
+
+/*----------------------------------------------------------------*/
+
struct shadow_info {
struct hlist_node hlist;
dm_block_t where;
@@ -37,6 +94,8 @@ struct dm_transaction_manager {
spinlock_t lock;
struct hlist_head buckets[DM_HASH_SIZE];
+
+ struct prefetch_set prefetches;
};
/*----------------------------------------------------------------*/
@@ -117,6 +176,8 @@ static struct dm_transaction_manager *dm_tm_create(struct dm_block_manager *bm,
for (i = 0; i < DM_HASH_SIZE; i++)
INIT_HLIST_HEAD(tm->buckets + i);
+ prefetch_init(&tm->prefetches);
+
return tm;
}
@@ -268,8 +329,14 @@ int dm_tm_read_lock(struct dm_transaction_manager *tm, dm_block_t b,
struct dm_block_validator *v,
struct dm_block **blk)
{
- if (tm->is_clone)
- return dm_bm_read_try_lock(tm->real->bm, b, v, blk);
+ if (tm->is_clone) {
+ int r = dm_bm_read_try_lock(tm->real->bm, b, v, blk);
+
+ if (r == -EWOULDBLOCK)
+ prefetch_add(&tm->real->prefetches, b);
+
+ return r;
+ }
return dm_bm_read_lock(tm->bm, b, v, blk);
}
@@ -317,6 +384,12 @@ struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm)
return tm->bm;
}
+void dm_tm_issue_prefetches(struct dm_transaction_manager *tm)
+{
+ prefetch_issue(&tm->prefetches, tm->bm);
+}
+EXPORT_SYMBOL_GPL(dm_tm_issue_prefetches);
+
/*----------------------------------------------------------------*/
static int dm_tm_create_internal(struct dm_block_manager *bm,
diff --git a/drivers/md/persistent-data/dm-transaction-manager.h b/drivers/md/persistent-data/dm-transaction-manager.h
index 2772ed2..2e0d4d6 100644
--- a/drivers/md/persistent-data/dm-transaction-manager.h
+++ b/drivers/md/persistent-data/dm-transaction-manager.h
@@ -109,6 +109,13 @@ int dm_tm_ref(struct dm_transaction_manager *tm, dm_block_t b,
struct dm_block_manager *dm_tm_get_bm(struct dm_transaction_manager *tm);
/*
+ * If you're using a non-blocking clone the tm will build up a list of
+ * requested blocks that weren't in core. This call will request those
+ * blocks to be prefetched.
+ */
+void dm_tm_issue_prefetches(struct dm_transaction_manager *tm);
+
+/*
* A little utility that ties the knot by producing a transaction manager
* that has a space map managed by the transaction manager...
*
diff --git a/drivers/media/common/cx2341x.c b/drivers/media/common/cx2341x.c
index be76315..c07b9db 100644
--- a/drivers/media/common/cx2341x.c
+++ b/drivers/media/common/cx2341x.c
@@ -931,6 +931,35 @@ static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
}
}
+/* Check for correctness of the ctrl's value based on the data from
+ struct v4l2_queryctrl and the available menu items. Note that
+ menu_items may be NULL, in that case it is ignored. */
+static int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
+ const char * const *menu_items)
+{
+ if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+ if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
+ return -EBUSY;
+ if (qctrl->type == V4L2_CTRL_TYPE_STRING)
+ return 0;
+ if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
+ qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return 0;
+ if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
+ return -ERANGE;
+ if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
+ if (menu_items[ctrl->value] == NULL ||
+ menu_items[ctrl->value][0] == '\0')
+ return -EINVAL;
+ }
+ if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
+ (ctrl->value & ~qctrl->maximum))
+ return -ERANGE;
+ return 0;
+}
+
int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
struct v4l2_ext_controls *ctrls, unsigned int cmd)
{
diff --git a/drivers/media/common/saa7146/saa7146_core.c b/drivers/media/common/saa7146/saa7146_core.c
index 4418119..1ff9f53 100644
--- a/drivers/media/common/saa7146/saa7146_core.c
+++ b/drivers/media/common/saa7146/saa7146_core.c
@@ -71,7 +71,7 @@ static inline int saa7146_wait_for_debi_done_sleep(struct saa7146_dev *dev,
if (saa7146_read(dev, MC2) & 2)
break;
if (err) {
- pr_err("%s: %s timed out while waiting for registers getting programmed\n",
+ pr_debug("%s: %s timed out while waiting for registers getting programmed\n",
dev->name, __func__);
return -ETIMEDOUT;
}
diff --git a/drivers/media/common/siano/smsir.c b/drivers/media/common/siano/smsir.c
index 273043e..35d0e88 100644
--- a/drivers/media/common/siano/smsir.c
+++ b/drivers/media/common/siano/smsir.c
@@ -107,8 +107,7 @@ int sms_ir_init(struct smscore_device_t *coredev)
void sms_ir_exit(struct smscore_device_t *coredev)
{
- if (coredev->ir.dev)
- rc_unregister_device(coredev->ir.dev);
+ rc_unregister_device(coredev->ir.dev);
sms_log("");
}
diff --git a/drivers/media/common/tveeprom.c b/drivers/media/common/tveeprom.c
index c7dace6..47da0378 100644
--- a/drivers/media/common/tveeprom.c
+++ b/drivers/media/common/tveeprom.c
@@ -286,9 +286,17 @@ static const struct {
{ TUNER_ABSENT, "Xceive XC5200C"},
{ TUNER_ABSENT, "NXP 18273"},
{ TUNER_ABSENT, "Montage M88TS2022"},
- /* 180-189 */
+ /* 180-188 */
{ TUNER_ABSENT, "NXP 18272M"},
{ TUNER_ABSENT, "NXP 18272S"},
+
+ { TUNER_ABSENT, "Mirics MSi003"},
+ { TUNER_ABSENT, "MaxLinear MxL256"},
+ { TUNER_ABSENT, "SiLabs Si2158"},
+ { TUNER_ABSENT, "SiLabs Si2178"},
+ { TUNER_ABSENT, "SiLabs Si2157"},
+ { TUNER_ABSENT, "SiLabs Si2177"},
+ { TUNER_ABSENT, "ITE IT9137FN"},
};
/* Use TVEEPROM_AUDPROC_INTERNAL for those audio 'chips' that are
@@ -351,6 +359,16 @@ static const struct {
{ TVEEPROM_AUDPROC_INTERNAL, "CX23887" },
{ TVEEPROM_AUDPROC_INTERNAL, "SAA7164" },
{ TVEEPROM_AUDPROC_INTERNAL, "AU8522" },
+ /* 45-49 */
+ { TVEEPROM_AUDPROC_INTERNAL, "AVF4910B" },
+ { TVEEPROM_AUDPROC_INTERNAL, "SAA7231" },
+ { TVEEPROM_AUDPROC_INTERNAL, "CX23102" },
+ { TVEEPROM_AUDPROC_INTERNAL, "SAA7163" },
+ { TVEEPROM_AUDPROC_OTHER, "AK4113" },
+ /* 50-52 */
+ { TVEEPROM_AUDPROC_OTHER, "CS5340" },
+ { TVEEPROM_AUDPROC_OTHER, "CS8416" },
+ { TVEEPROM_AUDPROC_OTHER, "CX20810" },
};
/* This list is supplied by Hauppauge. Thanks! */
@@ -371,8 +389,12 @@ static const char *decoderIC[] = {
"CX25843", "CX23418", "NEC61153", "CX23885", "CX23888",
/* 35-39 */
"SAA7131", "CX25837", "CX23887", "CX23885A", "CX23887A",
- /* 40-42 */
- "SAA7164", "CX23885B", "AU8522"
+ /* 40-44 */
+ "SAA7164", "CX23885B", "AU8522", "ADV7401", "AVF4910B",
+ /* 45-49 */
+ "SAA7231", "CX23102", "SAA7163", "ADV7441A", "ADV7181C",
+ /* 50-53 */
+ "CX25836", "TDA9955", "TDA19977", "ADV7842"
};
static int hasRadioTuner(int tunerType)
@@ -548,10 +570,10 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
tvee->serial_number =
eeprom_data[i+5] +
(eeprom_data[i+6] << 8) +
- (eeprom_data[i+7] << 16);
+ (eeprom_data[i+7] << 16)+
+ (eeprom_data[i+8] << 24);
- if ((eeprom_data[i + 8] & 0xf0) &&
- (tvee->serial_number < 0xffffff)) {
+ if (eeprom_data[i + 8] == 0xf0) {
tvee->MAC_address[0] = 0x00;
tvee->MAC_address[1] = 0x0D;
tvee->MAC_address[2] = 0xFE;
@@ -696,7 +718,7 @@ void tveeprom_hauppauge_analog(struct i2c_client *c, struct tveeprom *tvee,
}
}
- tveeprom_info("Hauppauge model %d, rev %s, serial# %d\n",
+ tveeprom_info("Hauppauge model %d, rev %s, serial# %u\n",
tvee->model, tvee->rev_str, tvee->serial_number);
if (tvee->has_MAC_address == 1)
tveeprom_info("MAC address is %pM\n", tvee->MAC_address);
diff --git a/drivers/media/dvb-core/dvb-usb-ids.h b/drivers/media/dvb-core/dvb-usb-ids.h
index e07a84e..80ab8d0 100644
--- a/drivers/media/dvb-core/dvb-usb-ids.h
+++ b/drivers/media/dvb-core/dvb-usb-ids.h
@@ -356,6 +356,7 @@
#define USB_PID_MSI_DIGI_VOX_MINI_III 0x8807
#define USB_PID_SONY_PLAYTV 0x0003
#define USB_PID_MYGICA_D689 0xd811
+#define USB_PID_MYGICA_T230 0xc688
#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011
#define USB_PID_ELGATO_EYETV_DTT 0x0021
#define USB_PID_ELGATO_EYETV_DTT_2 0x003f
diff --git a/drivers/media/dvb-core/dvb_net.c b/drivers/media/dvb-core/dvb_net.c
index 059e611..e4041f0 100644
--- a/drivers/media/dvb-core/dvb_net.c
+++ b/drivers/media/dvb-core/dvb_net.c
@@ -379,7 +379,9 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
/* Check TS error conditions: sync_byte, transport_error_indicator, scrambling_control . */
if ((ts[0] != TS_SYNC) || (ts[1] & TS_TEI) || ((ts[3] & TS_SC) != 0)) {
printk(KERN_WARNING "%lu: Invalid TS cell: SYNC %#x, TEI %u, SC %#x.\n",
- priv->ts_count, ts[0], ts[1] & TS_TEI >> 7, ts[3] & 0xC0 >> 6);
+ priv->ts_count, ts[0],
+ (ts[1] & TS_TEI) >> 7,
+ (ts[3] & TS_SC) >> 6);
/* Drop partly decoded SNDU, reset state, resync on PUSI. */
if (priv->ule_skb) {
diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 5a13454..6c75418 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -648,12 +648,15 @@ config DVB_MB86A20S
A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
Say Y when you want to support this frontend.
+comment "ISDB-S (satellite) & ISDB-T (terrestrial) frontends"
+ depends on DVB_CORE
+
config DVB_TC90522
tristate "Toshiba TC90522"
depends on DVB_CORE && I2C
default m if !MEDIA_SUBDRV_AUTOSELECT
help
- A Toshiba TC90522 2xISDB-T + 2xISDB-S demodulator.
+ Toshiba TC90522 2xISDB-S 8PSK + 2xISDB-T OFDM demodulator.
Say Y when you want to support this frontend.
comment "Digital terrestrial only tuners/PLL"
diff --git a/drivers/media/dvb-frontends/af9033.c b/drivers/media/dvb-frontends/af9033.c
index 63a89c1..82ce47b 100644
--- a/drivers/media/dvb-frontends/af9033.c
+++ b/drivers/media/dvb-frontends/af9033.c
@@ -291,6 +291,12 @@ static int af9033_init(struct dvb_frontend *fe)
if (clock_adc_lut[i].clock == dev->cfg.clock)
break;
}
+ if (i == ARRAY_SIZE(clock_adc_lut)) {
+ dev_err(&dev->client->dev,
+ "Couldn't find ADC config for clock=%d\n",
+ dev->cfg.clock);
+ goto err;
+ }
adc_cw = af9033_div(dev, clock_adc_lut[i].adc, 1000000ul, 19ul);
buf[0] = (adc_cw >> 0) & 0xff;
@@ -580,7 +586,15 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
break;
}
}
- ret = af9033_wr_regs(dev, 0x800001,
+ if (i == ARRAY_SIZE(coeff_lut)) {
+ dev_err(&dev->client->dev,
+ "Couldn't find LUT config for clock=%d\n",
+ dev->cfg.clock);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = af9033_wr_regs(dev, 0x800001,
coeff_lut[i].val, sizeof(coeff_lut[i].val));
}
@@ -592,6 +606,13 @@ static int af9033_set_frontend(struct dvb_frontend *fe)
if (clock_adc_lut[i].clock == dev->cfg.clock)
break;
}
+ if (i == ARRAY_SIZE(clock_adc_lut)) {
+ dev_err(&dev->client->dev,
+ "Couldn't find ADC clock for clock=%d\n",
+ dev->cfg.clock);
+ ret = -EINVAL;
+ goto err;
+ }
adc_freq = clock_adc_lut[i].adc;
/* get used IF frequency */
@@ -849,29 +870,97 @@ static int af9033_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct af9033_dev *dev = fe->demodulator_priv;
struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+ int ret;
+ u8 u8tmp;
/* use DVBv5 CNR */
- if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL)
- *snr = div_s64(c->cnr.stat[0].svalue, 100); /* 1000x => 10x */
- else
+ if (c->cnr.stat[0].scale == FE_SCALE_DECIBEL) {
+ /* Return 0.1 dB for AF9030 and 0-0xffff for IT9130. */
+ if (dev->is_af9035) {
+ /* 1000x => 10x (0.1 dB) */
+ *snr = div_s64(c->cnr.stat[0].svalue, 100);
+ } else {
+ /* 1000x => 1x (1 dB) */
+ *snr = div_s64(c->cnr.stat[0].svalue, 1000);
+
+ /* read current modulation */
+ ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
+ if (ret)
+ goto err;
+
+ /* scale value to 0x0000-0xffff */
+ switch ((u8tmp >> 0) & 3) {
+ case 0:
+ *snr = *snr * 0xffff / 23;
+ break;
+ case 1:
+ *snr = *snr * 0xffff / 26;
+ break;
+ case 2:
+ *snr = *snr * 0xffff / 32;
+ break;
+ default:
+ goto err;
+ }
+ }
+ } else {
*snr = 0;
+ }
return 0;
+
+err:
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+
+ return ret;
}
static int af9033_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
{
struct af9033_dev *dev = fe->demodulator_priv;
- int ret;
- u8 strength2;
+ struct dtv_frontend_properties *c = &dev->fe.dtv_property_cache;
+ int ret, tmp, power_real;
+ u8 u8tmp, gain_offset, buf[7];
- /* read signal strength of 0-100 scale */
- ret = af9033_rd_reg(dev, 0x800048, &strength2);
- if (ret < 0)
- goto err;
+ if (dev->is_af9035) {
+ /* read signal strength of 0-100 scale */
+ ret = af9033_rd_reg(dev, 0x800048, &u8tmp);
+ if (ret < 0)
+ goto err;
+
+ /* scale value to 0x0000-0xffff */
+ *strength = u8tmp * 0xffff / 100;
+ } else {
+ ret = af9033_rd_reg(dev, 0x8000f7, &u8tmp);
+ if (ret < 0)
+ goto err;
+
+ ret = af9033_rd_regs(dev, 0x80f900, buf, 7);
+ if (ret < 0)
+ goto err;
+
+ if (c->frequency <= 300000000)
+ gain_offset = 7; /* VHF */
+ else
+ gain_offset = 4; /* UHF */
+
+ power_real = (u8tmp - 100 - gain_offset) -
+ power_reference[((buf[3] >> 0) & 3)][((buf[6] >> 0) & 7)];
+
+ if (power_real < -15)
+ tmp = 0;
+ else if ((power_real >= -15) && (power_real < 0))
+ tmp = (2 * (power_real + 15)) / 3;
+ else if ((power_real >= 0) && (power_real < 20))
+ tmp = 4 * power_real + 10;
+ else if ((power_real >= 20) && (power_real < 35))
+ tmp = (2 * (power_real - 20)) / 3 + 90;
+ else
+ tmp = 100;
- /* scale value to 0x0000-0xffff */
- *strength = strength2 * 0xffff / 100;
+ /* scale value to 0x0000-0xffff */
+ *strength = tmp * 0xffff / 100;
+ }
return 0;
@@ -1011,6 +1100,33 @@ static void af9033_stat_work(struct work_struct *work)
snr_val = (buf[2] << 16) | (buf[1] << 8) | (buf[0] << 0);
+ /* read superframe number */
+ ret = af9033_rd_reg(dev, 0x80f78b, &u8tmp);
+ if (ret)
+ goto err;
+
+ if (u8tmp)
+ snr_val /= u8tmp;
+
+ /* read current transmission mode */
+ ret = af9033_rd_reg(dev, 0x80f900, &u8tmp);
+ if (ret)
+ goto err;
+
+ switch ((u8tmp >> 0) & 3) {
+ case 0:
+ snr_val *= 4;
+ break;
+ case 1:
+ snr_val *= 1;
+ break;
+ case 2:
+ snr_val *= 2;
+ break;
+ default:
+ goto err_schedule_delayed_work;
+ }
+
/* read current modulation */
ret = af9033_rd_reg(dev, 0x80f903, &u8tmp);
if (ret)
diff --git a/drivers/media/dvb-frontends/af9033_priv.h b/drivers/media/dvb-frontends/af9033_priv.h
index c12c92c..8e23275 100644
--- a/drivers/media/dvb-frontends/af9033_priv.h
+++ b/drivers/media/dvb-frontends/af9033_priv.h
@@ -181,7 +181,10 @@ static const struct val_snr qam64_snr_lut[] = {
{ 0x05570d, 26 },
{ 0x059feb, 27 },
{ 0x05bf38, 28 },
- { 0xffffff, 29 },
+ { 0x05f78f, 29 },
+ { 0x0612c3, 30 },
+ { 0x0626be, 31 },
+ { 0xffffff, 32 },
};
static const struct reg_val ofsm_init[] = {
@@ -2051,4 +2054,10 @@ static const struct reg_val tuner_init_it9135_62[] = {
{ 0x80fd8b, 0x00 },
};
+/* NorDig power reference table */
+static const int power_reference[][5] = {
+ {-93, -91, -90, -89, -88}, /* QPSK 1/2 ~ 7/8 */
+ {-87, -85, -84, -83, -82}, /* 16QAM 1/2 ~ 7/8 */
+ {-82, -80, -78, -77, -76}, /* 64QAM 1/2 ~ 7/8 */
+};
#endif /* AF9033_PRIV_H */
diff --git a/drivers/media/dvb-frontends/au8522_dig.c b/drivers/media/dvb-frontends/au8522_dig.c
index a68974f..5d06c99 100644
--- a/drivers/media/dvb-frontends/au8522_dig.c
+++ b/drivers/media/dvb-frontends/au8522_dig.c
@@ -29,6 +29,7 @@
#include "au8522_priv.h"
static int debug;
+static int zv_mode = 1; /* default to on */
#define dprintk(arg...)\
do { if (debug)\
@@ -469,6 +470,87 @@ static struct {
{ 0x8526, 0x01 },
};
+static struct {
+ u16 reg;
+ u16 data;
+} QAM256_mod_tab_zv_mode[] = {
+ { 0x80a3, 0x09 },
+ { 0x80a4, 0x00 },
+ { 0x8081, 0xc4 },
+ { 0x80a5, 0x40 },
+ { 0x80b5, 0xfb },
+ { 0x80b6, 0x8e },
+ { 0x80b7, 0x39 },
+ { 0x80aa, 0x77 },
+ { 0x80ad, 0x77 },
+ { 0x80a6, 0x67 },
+ { 0x8262, 0x20 },
+ { 0x821c, 0x30 },
+ { 0x80b8, 0x3e },
+ { 0x80b9, 0xf0 },
+ { 0x80ba, 0x01 },
+ { 0x80bb, 0x18 },
+ { 0x80bc, 0x50 },
+ { 0x80bd, 0x00 },
+ { 0x80be, 0xea },
+ { 0x80bf, 0xef },
+ { 0x80c0, 0xfc },
+ { 0x80c1, 0xbd },
+ { 0x80c2, 0x1f },
+ { 0x80c3, 0xfc },
+ { 0x80c4, 0xdd },
+ { 0x80c5, 0xaf },
+ { 0x80c6, 0x00 },
+ { 0x80c7, 0x38 },
+ { 0x80c8, 0x30 },
+ { 0x80c9, 0x05 },
+ { 0x80ca, 0x4a },
+ { 0x80cb, 0xd0 },
+ { 0x80cc, 0x01 },
+ { 0x80cd, 0xd9 },
+ { 0x80ce, 0x6f },
+ { 0x80cf, 0xf9 },
+ { 0x80d0, 0x70 },
+ { 0x80d1, 0xdf },
+ { 0x80d2, 0xf7 },
+ { 0x80d3, 0xc2 },
+ { 0x80d4, 0xdf },
+ { 0x80d5, 0x02 },
+ { 0x80d6, 0x9a },
+ { 0x80d7, 0xd0 },
+ { 0x8250, 0x0d },
+ { 0x8251, 0xcd },
+ { 0x8252, 0xe0 },
+ { 0x8253, 0x05 },
+ { 0x8254, 0xa7 },
+ { 0x8255, 0xff },
+ { 0x8256, 0xed },
+ { 0x8257, 0x5b },
+ { 0x8258, 0xae },
+ { 0x8259, 0xe6 },
+ { 0x825a, 0x3d },
+ { 0x825b, 0x0f },
+ { 0x825c, 0x0d },
+ { 0x825d, 0xea },
+ { 0x825e, 0xf2 },
+ { 0x825f, 0x51 },
+ { 0x8260, 0xf5 },
+ { 0x8261, 0x06 },
+ { 0x821a, 0x01 },
+ { 0x8546, 0x40 },
+ { 0x8210, 0x26 },
+ { 0x8211, 0xf6 },
+ { 0x8212, 0x84 },
+ { 0x8213, 0x02 },
+ { 0x8502, 0x01 },
+ { 0x8121, 0x04 },
+ { 0x8122, 0x04 },
+ { 0x852e, 0x10 },
+ { 0x80a4, 0xca },
+ { 0x80a7, 0x40 },
+ { 0x8526, 0x01 },
+};
+
static int au8522_enable_modulation(struct dvb_frontend *fe,
fe_modulation_t m)
{
@@ -495,12 +577,23 @@ static int au8522_enable_modulation(struct dvb_frontend *fe,
au8522_set_if(fe, state->config->qam_if);
break;
case QAM_256:
- dprintk("%s() QAM 256\n", __func__);
- for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
- au8522_writereg(state,
- QAM256_mod_tab[i].reg,
- QAM256_mod_tab[i].data);
- au8522_set_if(fe, state->config->qam_if);
+ if (zv_mode) {
+ dprintk("%s() QAM 256 (zv_mode)\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab_zv_mode); i++)
+ au8522_writereg(state,
+ QAM256_mod_tab_zv_mode[i].reg,
+ QAM256_mod_tab_zv_mode[i].data);
+ au8522_set_if(fe, state->config->qam_if);
+ msleep(100);
+ au8522_writereg(state, 0x821a, 0x00);
+ } else {
+ dprintk("%s() QAM 256\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM256_mod_tab); i++)
+ au8522_writereg(state,
+ QAM256_mod_tab[i].reg,
+ QAM256_mod_tab[i].data);
+ au8522_set_if(fe, state->config->qam_if);
+ }
break;
default:
dprintk("%s() Invalid modulation\n", __func__);
@@ -537,7 +630,12 @@ static int au8522_set_frontend(struct dvb_frontend *fe)
return ret;
/* Allow the tuner to settle */
- msleep(100);
+ if (zv_mode) {
+ dprintk("%s() increase tuner settling time for zv_mode\n",
+ __func__);
+ msleep(250);
+ } else
+ msleep(100);
au8522_enable_modulation(fe, c->modulation);
@@ -823,6 +921,11 @@ static struct dvb_frontend_ops au8522_ops = {
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+module_param(zv_mode, int, 0644);
+MODULE_PARM_DESC(zv_mode, "Turn on/off ZeeVee modulator compatability mode (default:on).\n"
+ "\t\ton - modified AU8522 QAM256 initialization.\n"
+ "\t\tProvides faster lock when using ZeeVee modulator based sources");
+
MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb-frontends/cx22700.c b/drivers/media/dvb-frontends/cx22700.c
index 3d399d9..8656326 100644
--- a/drivers/media/dvb-frontends/cx22700.c
+++ b/drivers/media/dvb-frontends/cx22700.c
@@ -169,6 +169,9 @@ static int cx22700_set_tps(struct cx22700_state *state,
cx22700_writereg (state, 0x04, val);
+ if (p->code_rate_HP - FEC_1_2 >= sizeof(fec_tab) ||
+ p->code_rate_LP - FEC_1_2 >= sizeof(fec_tab))
+ return -EINVAL;
val = fec_tab[p->code_rate_HP - FEC_1_2] << 3;
val |= fec_tab[p->code_rate_LP - FEC_1_2];
diff --git a/drivers/media/dvb-frontends/cx24110.c b/drivers/media/dvb-frontends/cx24110.c
index 95b981c..7b510f2 100644
--- a/drivers/media/dvb-frontends/cx24110.c
+++ b/drivers/media/dvb-frontends/cx24110.c
@@ -177,47 +177,45 @@ static int cx24110_set_inversion (struct cx24110_state* state, fe_spectral_inver
return 0;
}
-static int cx24110_set_fec (struct cx24110_state* state, fe_code_rate_t fec)
+static int cx24110_set_fec(struct cx24110_state* state, fe_code_rate_t fec)
{
-/* fixme (low): error handling */
-
- static const int rate[]={-1,1,2,3,5,7,-1};
- static const int g1[]={-1,0x01,0x02,0x05,0x15,0x45,-1};
- static const int g2[]={-1,0x01,0x03,0x06,0x1a,0x7a,-1};
+ static const int rate[FEC_AUTO] = {-1, 1, 2, 3, 5, 7, -1};
+ static const int g1[FEC_AUTO] = {-1, 0x01, 0x02, 0x05, 0x15, 0x45, -1};
+ static const int g2[FEC_AUTO] = {-1, 0x01, 0x03, 0x06, 0x1a, 0x7a, -1};
/* Well, the AutoAcq engine of the cx24106 and 24110 automatically
searches all enabled viterbi rates, and can handle non-standard
rates as well. */
- if (fec>FEC_AUTO)
- fec=FEC_AUTO;
+ if (fec > FEC_AUTO)
+ fec = FEC_AUTO;
- if (fec==FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
- cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)&0xdf);
+ if (fec == FEC_AUTO) { /* (re-)establish AutoAcq behaviour */
+ cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) & 0xdf);
/* clear AcqVitDis bit */
- cx24110_writereg(state,0x18,0xae);
+ cx24110_writereg(state, 0x18, 0xae);
/* allow all DVB standard code rates */
- cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|0x3);
+ cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | 0x3);
/* set nominal Viterbi rate 3/4 */
- cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|0x3);
+ cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | 0x3);
/* set current Viterbi rate 3/4 */
- cx24110_writereg(state,0x1a,0x05); cx24110_writereg(state,0x1b,0x06);
+ cx24110_writereg(state, 0x1a, 0x05);
+ cx24110_writereg(state, 0x1b, 0x06);
/* set the puncture registers for code rate 3/4 */
return 0;
} else {
- cx24110_writereg(state,0x37,cx24110_readreg(state,0x37)|0x20);
+ cx24110_writereg(state, 0x37, cx24110_readreg(state, 0x37) | 0x20);
/* set AcqVitDis bit */
- if(rate[fec]>0) {
- cx24110_writereg(state,0x05,(cx24110_readreg(state,0x05)&0xf0)|rate[fec]);
- /* set nominal Viterbi rate */
- cx24110_writereg(state,0x22,(cx24110_readreg(state,0x22)&0xf0)|rate[fec]);
- /* set current Viterbi rate */
- cx24110_writereg(state,0x1a,g1[fec]);
- cx24110_writereg(state,0x1b,g2[fec]);
- /* not sure if this is the right way: I always used AutoAcq mode */
- } else
- return -EOPNOTSUPP;
-/* fixme (low): which is the correct return code? */
+ if (rate[fec] < 0)
+ return -EINVAL;
+
+ cx24110_writereg(state, 0x05, (cx24110_readreg(state, 0x05) & 0xf0) | rate[fec]);
+ /* set nominal Viterbi rate */
+ cx24110_writereg(state, 0x22, (cx24110_readreg(state, 0x22) & 0xf0) | rate[fec]);
+ /* set current Viterbi rate */
+ cx24110_writereg(state, 0x1a, g1[fec]);
+ cx24110_writereg(state, 0x1b, g2[fec]);
+ /* not sure if this is the right way: I always used AutoAcq mode */
}
return 0;
}
diff --git a/drivers/media/dvb-frontends/cx24117.c b/drivers/media/dvb-frontends/cx24117.c
index a6c3c9e..acb965c 100644
--- a/drivers/media/dvb-frontends/cx24117.c
+++ b/drivers/media/dvb-frontends/cx24117.c
@@ -459,7 +459,7 @@ static int cx24117_firmware_ondemand(struct dvb_frontend *fe)
if (state->priv->skip_fw_load)
return 0;
- /* check if firmware if already running */
+ /* check if firmware is already running */
if (cx24117_readreg(state, 0xeb) != 0xa) {
/* Load firmware */
/* request the firmware, this will block until loaded */
diff --git a/drivers/media/dvb-frontends/dib7000p.c b/drivers/media/dvb-frontends/dib7000p.c
index 589134e..c505d69 100644
--- a/drivers/media/dvb-frontends/dib7000p.c
+++ b/drivers/media/dvb-frontends/dib7000p.c
@@ -1780,7 +1780,7 @@ static u32 interpolate_value(u32 value, struct linear_segments *segments,
}
/* FIXME: may require changes - this one was borrowed from dib8000 */
-static u32 dib7000p_get_time_us(struct dvb_frontend *demod, int layer)
+static u32 dib7000p_get_time_us(struct dvb_frontend *demod)
{
struct dtv_frontend_properties *c = &demod->dtv_property_cache;
u64 time_us, tmp64;
@@ -1881,7 +1881,6 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
{
struct dib7000p_state *state = demod->demodulator_priv;
struct dtv_frontend_properties *c = &demod->dtv_property_cache;
- int i;
int show_per_stats = 0;
u32 time_us = 0, val, snr;
u64 blocks, ucb;
@@ -1935,7 +1934,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
/* Estimate the number of packets based on bitrate */
if (!time_us)
- time_us = dib7000p_get_time_us(demod, -1);
+ time_us = dib7000p_get_time_us(demod);
if (time_us) {
blocks = 1250000ULL * 1000000ULL;
@@ -1949,7 +1948,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
/* Get post-BER measures */
if (time_after(jiffies, state->ber_jiffies_stats)) {
- time_us = dib7000p_get_time_us(demod, -1);
+ time_us = dib7000p_get_time_us(demod);
state->ber_jiffies_stats = jiffies + msecs_to_jiffies((time_us + 500) / 1000);
dprintk("Next all layers stats available in %u us.", time_us);
@@ -1969,7 +1968,7 @@ static int dib7000p_get_stats(struct dvb_frontend *demod, fe_status_t stat)
c->block_error.stat[0].scale = FE_SCALE_COUNTER;
c->block_error.stat[0].uvalue += val;
- time_us = dib7000p_get_time_us(demod, i);
+ time_us = dib7000p_get_time_us(demod);
if (time_us) {
blocks = 1250000ULL * 1000000ULL;
do_div(blocks, time_us * 8 * 204);
diff --git a/drivers/media/dvb-frontends/drx39xyj/drxj.c b/drivers/media/dvb-frontends/drx39xyj/drxj.c
index 5ec221f..2bfa7a4 100644
--- a/drivers/media/dvb-frontends/drx39xyj/drxj.c
+++ b/drivers/media/dvb-frontends/drx39xyj/drxj.c
@@ -12255,8 +12255,7 @@ static void drx39xxj_release(struct dvb_frontend *fe)
kfree(demod->my_ext_attr);
kfree(demod->my_common_attr);
kfree(demod->my_i2c_dev_addr);
- if (demod->firmware)
- release_firmware(demod->firmware);
+ release_firmware(demod->firmware);
kfree(demod);
kfree(state);
}
diff --git a/drivers/media/dvb-frontends/drxk_hard.c b/drivers/media/dvb-frontends/drxk_hard.c
index 6721951..d46cf5f 100644
--- a/drivers/media/dvb-frontends/drxk_hard.c
+++ b/drivers/media/dvb-frontends/drxk_hard.c
@@ -166,9 +166,9 @@ static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
-#define dprintk(level, fmt, arg...) do { \
-if (debug >= level) \
- pr_debug(fmt, ##arg); \
+#define dprintk(level, fmt, arg...) do { \
+if (debug >= level) \
+ printk(KERN_DEBUG KBUILD_MODNAME ": %s " fmt, __func__, ##arg); \
} while (0)
@@ -6310,8 +6310,7 @@ static void drxk_release(struct dvb_frontend *fe)
struct drxk_state *state = fe->demodulator_priv;
dprintk(1, "\n");
- if (state->fw)
- release_firmware(state->fw);
+ release_firmware(state->fw);
kfree(state);
}
diff --git a/drivers/media/dvb-frontends/m88ds3103.c b/drivers/media/dvb-frontends/m88ds3103.c
index 81657e9..ba4ee0b 100644
--- a/drivers/media/dvb-frontends/m88ds3103.c
+++ b/drivers/media/dvb-frontends/m88ds3103.c
@@ -1,5 +1,5 @@
/*
- * Montage M88DS3103 demodulator driver
+ * Montage M88DS3103/M88RS6000 demodulator driver
*
* Copyright (C) 2013 Antti Palosaari <crope@iki.fi>
*
@@ -162,7 +162,7 @@ static int m88ds3103_wr_reg_val_tab(struct m88ds3103_priv *priv,
dev_dbg(&priv->i2c->dev, "%s: tab_len=%d\n", __func__, tab_len);
- if (tab_len > 83) {
+ if (tab_len > 86) {
ret = -EINVAL;
goto err;
}
@@ -245,9 +245,9 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
struct dtv_frontend_properties *c = &fe->dtv_property_cache;
int ret, len;
const struct m88ds3103_reg_val *init;
- u8 u8tmp, u8tmp1, u8tmp2;
- u8 buf[2];
- u16 u16tmp, divide_ratio;
+ u8 u8tmp, u8tmp1 = 0, u8tmp2 = 0; /* silence compiler warning */
+ u8 buf[3];
+ u16 u16tmp, divide_ratio = 0;
u32 tuner_frequency, target_mclk;
s32 s32tmp;
@@ -262,6 +262,22 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
goto err;
}
+ /* reset */
+ ret = m88ds3103_wr_reg(priv, 0x07, 0x80);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_wr_reg(priv, 0x07, 0x00);
+ if (ret)
+ goto err;
+
+ /* Disable demod clock path */
+ if (priv->chip_id == M88RS6000_CHIP_ID) {
+ ret = m88ds3103_wr_reg(priv, 0x06, 0xe0);
+ if (ret)
+ goto err;
+ }
+
/* program tuner */
if (fe->ops.tuner_ops.set_params) {
ret = fe->ops.tuner_ops.set_params(fe);
@@ -282,49 +298,44 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
tuner_frequency = c->frequency;
}
- /* reset */
- ret = m88ds3103_wr_reg(priv, 0x07, 0x80);
- if (ret)
- goto err;
-
- ret = m88ds3103_wr_reg(priv, 0x07, 0x00);
- if (ret)
- goto err;
-
- ret = m88ds3103_wr_reg(priv, 0xb2, 0x01);
- if (ret)
- goto err;
+ /* select M88RS6000 demod main mclk and ts mclk from tuner die. */
+ if (priv->chip_id == M88RS6000_CHIP_ID) {
+ if (c->symbol_rate > 45010000)
+ priv->mclk_khz = 110250;
+ else
+ priv->mclk_khz = 96000;
- ret = m88ds3103_wr_reg(priv, 0x00, 0x01);
- if (ret)
- goto err;
+ if (c->delivery_system == SYS_DVBS)
+ target_mclk = 96000;
+ else
+ target_mclk = 144000;
- switch (c->delivery_system) {
- case SYS_DVBS:
- len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals);
- init = m88ds3103_dvbs_init_reg_vals;
- target_mclk = 96000;
- break;
- case SYS_DVBS2:
- len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals);
- init = m88ds3103_dvbs2_init_reg_vals;
+ /* Enable demod clock path */
+ ret = m88ds3103_wr_reg(priv, 0x06, 0x00);
+ if (ret)
+ goto err;
+ usleep_range(10000, 20000);
+ } else {
+ /* set M88DS3103 mclk and ts mclk. */
+ priv->mclk_khz = 96000;
switch (priv->cfg->ts_mode) {
case M88DS3103_TS_SERIAL:
case M88DS3103_TS_SERIAL_D7:
- if (c->symbol_rate < 18000000)
- target_mclk = 96000;
- else
- target_mclk = 144000;
+ target_mclk = priv->cfg->ts_clk;
break;
case M88DS3103_TS_PARALLEL:
case M88DS3103_TS_CI:
- if (c->symbol_rate < 18000000)
+ if (c->delivery_system == SYS_DVBS)
target_mclk = 96000;
- else if (c->symbol_rate < 28000000)
- target_mclk = 144000;
- else
- target_mclk = 192000;
+ else {
+ if (c->symbol_rate < 18000000)
+ target_mclk = 96000;
+ else if (c->symbol_rate < 28000000)
+ target_mclk = 144000;
+ else
+ target_mclk = 192000;
+ }
break;
default:
dev_dbg(&priv->i2c->dev, "%s: invalid ts_mode\n",
@@ -332,6 +343,55 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
ret = -EINVAL;
goto err;
}
+
+ switch (target_mclk) {
+ case 96000:
+ u8tmp1 = 0x02; /* 0b10 */
+ u8tmp2 = 0x01; /* 0b01 */
+ break;
+ case 144000:
+ u8tmp1 = 0x00; /* 0b00 */
+ u8tmp2 = 0x01; /* 0b01 */
+ break;
+ case 192000:
+ u8tmp1 = 0x03; /* 0b11 */
+ u8tmp2 = 0x00; /* 0b00 */
+ break;
+ }
+ ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0);
+ if (ret)
+ goto err;
+ ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0);
+ if (ret)
+ goto err;
+ }
+
+ ret = m88ds3103_wr_reg(priv, 0xb2, 0x01);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_wr_reg(priv, 0x00, 0x01);
+ if (ret)
+ goto err;
+
+ switch (c->delivery_system) {
+ case SYS_DVBS:
+ if (priv->chip_id == M88RS6000_CHIP_ID) {
+ len = ARRAY_SIZE(m88rs6000_dvbs_init_reg_vals);
+ init = m88rs6000_dvbs_init_reg_vals;
+ } else {
+ len = ARRAY_SIZE(m88ds3103_dvbs_init_reg_vals);
+ init = m88ds3103_dvbs_init_reg_vals;
+ }
+ break;
+ case SYS_DVBS2:
+ if (priv->chip_id == M88RS6000_CHIP_ID) {
+ len = ARRAY_SIZE(m88rs6000_dvbs2_init_reg_vals);
+ init = m88rs6000_dvbs2_init_reg_vals;
+ } else {
+ len = ARRAY_SIZE(m88ds3103_dvbs2_init_reg_vals);
+ init = m88ds3103_dvbs2_init_reg_vals;
+ }
break;
default:
dev_dbg(&priv->i2c->dev, "%s: invalid delivery_system\n",
@@ -347,7 +407,30 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
goto err;
}
- u8tmp1 = 0; /* silence compiler warning */
+ if (priv->chip_id == M88RS6000_CHIP_ID) {
+ if ((c->delivery_system == SYS_DVBS2)
+ && ((c->symbol_rate / 1000) <= 5000)) {
+ ret = m88ds3103_wr_reg(priv, 0xc0, 0x04);
+ if (ret)
+ goto err;
+ buf[0] = 0x09;
+ buf[1] = 0x22;
+ buf[2] = 0x88;
+ ret = m88ds3103_wr_regs(priv, 0x8a, buf, 3);
+ if (ret)
+ goto err;
+ }
+ ret = m88ds3103_wr_reg_mask(priv, 0x9d, 0x08, 0x08);
+ if (ret)
+ goto err;
+ ret = m88ds3103_wr_reg(priv, 0xf1, 0x01);
+ if (ret)
+ goto err;
+ ret = m88ds3103_wr_reg_mask(priv, 0x30, 0x80, 0x80);
+ if (ret)
+ goto err;
+ }
+
switch (priv->cfg->ts_mode) {
case M88DS3103_TS_SERIAL:
u8tmp1 = 0x00;
@@ -383,16 +466,15 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
ret = m88ds3103_wr_reg_mask(priv, 0x29, u8tmp1, 0x20);
if (ret)
goto err;
- }
-
- if (priv->cfg->ts_clk) {
- divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk);
- u8tmp1 = divide_ratio / 2;
- u8tmp2 = DIV_ROUND_UP(divide_ratio, 2);
- } else {
- divide_ratio = 0;
u8tmp1 = 0;
u8tmp2 = 0;
+ break;
+ default:
+ if (priv->cfg->ts_clk) {
+ divide_ratio = DIV_ROUND_UP(target_mclk, priv->cfg->ts_clk);
+ u8tmp1 = divide_ratio / 2;
+ u8tmp2 = DIV_ROUND_UP(divide_ratio, 2);
+ }
}
dev_dbg(&priv->i2c->dev,
@@ -420,29 +502,6 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
- switch (target_mclk) {
- case 96000:
- u8tmp1 = 0x02; /* 0b10 */
- u8tmp2 = 0x01; /* 0b01 */
- break;
- case 144000:
- u8tmp1 = 0x00; /* 0b00 */
- u8tmp2 = 0x01; /* 0b01 */
- break;
- case 192000:
- u8tmp1 = 0x03; /* 0b11 */
- u8tmp2 = 0x00; /* 0b00 */
- break;
- }
-
- ret = m88ds3103_wr_reg_mask(priv, 0x22, u8tmp1 << 6, 0xc0);
- if (ret)
- goto err;
-
- ret = m88ds3103_wr_reg_mask(priv, 0x24, u8tmp2 << 6, 0xc0);
- if (ret)
- goto err;
-
if (c->symbol_rate <= 3000000)
u8tmp = 0x20;
else if (c->symbol_rate <= 10000000)
@@ -466,7 +525,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
- u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, M88DS3103_MCLK_KHZ / 2);
+ u16tmp = DIV_ROUND_CLOSEST((c->symbol_rate / 1000) << 15, priv->mclk_khz / 2);
buf[0] = (u16tmp >> 0) & 0xff;
buf[1] = (u16tmp >> 8) & 0xff;
ret = m88ds3103_wr_regs(priv, 0x61, buf, 2);
@@ -489,7 +548,7 @@ static int m88ds3103_set_frontend(struct dvb_frontend *fe)
(tuner_frequency - c->frequency));
s32tmp = 0x10000 * (tuner_frequency - c->frequency);
- s32tmp = DIV_ROUND_CLOSEST(s32tmp, M88DS3103_MCLK_KHZ);
+ s32tmp = DIV_ROUND_CLOSEST(s32tmp, priv->mclk_khz);
if (s32tmp < 0)
s32tmp += 0x10000;
@@ -520,7 +579,7 @@ static int m88ds3103_init(struct dvb_frontend *fe)
struct m88ds3103_priv *priv = fe->demodulator_priv;
int ret, len, remaining;
const struct firmware *fw = NULL;
- u8 *fw_file = M88DS3103_FIRMWARE;
+ u8 *fw_file;
u8 u8tmp;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
@@ -541,15 +600,6 @@ static int m88ds3103_init(struct dvb_frontend *fe)
if (ret)
goto err;
- /* reset */
- ret = m88ds3103_wr_reg(priv, 0x07, 0x60);
- if (ret)
- goto err;
-
- ret = m88ds3103_wr_reg(priv, 0x07, 0x00);
- if (ret)
- goto err;
-
/* firmware status */
ret = m88ds3103_rd_reg(priv, 0xb9, &u8tmp);
if (ret)
@@ -560,10 +610,23 @@ static int m88ds3103_init(struct dvb_frontend *fe)
if (u8tmp)
goto skip_fw_download;
+ /* global reset, global diseqc reset, golbal fec reset */
+ ret = m88ds3103_wr_reg(priv, 0x07, 0xe0);
+ if (ret)
+ goto err;
+
+ ret = m88ds3103_wr_reg(priv, 0x07, 0x00);
+ if (ret)
+ goto err;
+
/* cold state - try to download firmware */
dev_info(&priv->i2c->dev, "%s: found a '%s' in cold state\n",
KBUILD_MODNAME, m88ds3103_ops.info.name);
+ if (priv->chip_id == M88RS6000_CHIP_ID)
+ fw_file = M88RS6000_FIRMWARE;
+ else
+ fw_file = M88DS3103_FIRMWARE;
/* request the firmware, this will block and timeout */
ret = request_firmware(&fw, fw_file, priv->i2c->dev.parent);
if (ret) {
@@ -577,7 +640,7 @@ static int m88ds3103_init(struct dvb_frontend *fe)
ret = m88ds3103_wr_reg(priv, 0xb2, 0x01);
if (ret)
- goto err;
+ goto error_fw_release;
for (remaining = fw->size; remaining > 0;
remaining -= (priv->cfg->i2c_wr_max - 1)) {
@@ -591,13 +654,13 @@ static int m88ds3103_init(struct dvb_frontend *fe)
dev_err(&priv->i2c->dev,
"%s: firmware download failed=%d\n",
KBUILD_MODNAME, ret);
- goto err;
+ goto error_fw_release;
}
}
ret = m88ds3103_wr_reg(priv, 0xb2, 0x00);
if (ret)
- goto err;
+ goto error_fw_release;
release_firmware(fw);
fw = NULL;
@@ -623,10 +686,10 @@ skip_fw_download:
priv->warm = true;
return 0;
-err:
- if (fw)
- release_firmware(fw);
+error_fw_release:
+ release_firmware(fw);
+err:
dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
return ret;
}
@@ -635,13 +698,18 @@ static int m88ds3103_sleep(struct dvb_frontend *fe)
{
struct m88ds3103_priv *priv = fe->demodulator_priv;
int ret;
+ u8 u8tmp;
dev_dbg(&priv->i2c->dev, "%s:\n", __func__);
priv->delivery_system = SYS_UNDEFINED;
/* TS Hi-Z */
- ret = m88ds3103_wr_reg_mask(priv, 0x27, 0x00, 0x01);
+ if (priv->chip_id == M88RS6000_CHIP_ID)
+ u8tmp = 0x29;
+ else
+ u8tmp = 0x27;
+ ret = m88ds3103_wr_reg_mask(priv, u8tmp, 0x00, 0x01);
if (ret)
goto err;
@@ -830,7 +898,7 @@ static int m88ds3103_get_frontend(struct dvb_frontend *fe)
goto err;
c->symbol_rate = 1ull * ((buf[1] << 8) | (buf[0] << 0)) *
- M88DS3103_MCLK_KHZ * 1000 / 0x10000;
+ priv->mclk_khz * 1000 / 0x10000;
return 0;
err:
@@ -1310,18 +1378,22 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
priv->i2c = i2c;
mutex_init(&priv->i2c_mutex);
- ret = m88ds3103_rd_reg(priv, 0x01, &chip_id);
+ /* 0x00: chip id[6:0], 0x01: chip ver[7:0], 0x02: chip ver[15:8] */
+ ret = m88ds3103_rd_reg(priv, 0x00, &chip_id);
if (ret)
goto err;
- dev_dbg(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
+ chip_id >>= 1;
+ dev_info(&priv->i2c->dev, "%s: chip_id=%02x\n", __func__, chip_id);
switch (chip_id) {
- case 0xd0:
+ case M88RS6000_CHIP_ID:
+ case M88DS3103_CHIP_ID:
break;
default:
goto err;
}
+ priv->chip_id = chip_id;
switch (priv->cfg->clock_out) {
case M88DS3103_CLOCK_OUT_DISABLED:
@@ -1337,6 +1409,11 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
goto err;
}
+ /* 0x29 register is defined differently for m88rs6000. */
+ /* set internal tuner address to 0x21 */
+ if (chip_id == M88RS6000_CHIP_ID)
+ u8tmp = 0x00;
+
ret = m88ds3103_wr_reg(priv, 0x29, u8tmp);
if (ret)
goto err;
@@ -1364,6 +1441,9 @@ struct dvb_frontend *m88ds3103_attach(const struct m88ds3103_config *cfg,
/* create dvb_frontend */
memcpy(&priv->fe.ops, &m88ds3103_ops, sizeof(struct dvb_frontend_ops));
+ if (priv->chip_id == M88RS6000_CHIP_ID)
+ strncpy(priv->fe.ops.info.name,
+ "Montage M88RS6000", sizeof(priv->fe.ops.info.name));
priv->fe.demodulator_priv = priv;
return &priv->fe;
@@ -1423,3 +1503,4 @@ MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_DESCRIPTION("Montage M88DS3103 DVB-S/S2 demodulator driver");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(M88DS3103_FIRMWARE);
+MODULE_FIRMWARE(M88RS6000_FIRMWARE);
diff --git a/drivers/media/dvb-frontends/m88ds3103_priv.h b/drivers/media/dvb-frontends/m88ds3103_priv.h
index 9169fdd..a2c0958 100644
--- a/drivers/media/dvb-frontends/m88ds3103_priv.h
+++ b/drivers/media/dvb-frontends/m88ds3103_priv.h
@@ -25,7 +25,10 @@
#include <linux/math64.h>
#define M88DS3103_FIRMWARE "dvb-demod-m88ds3103.fw"
+#define M88RS6000_FIRMWARE "dvb-demod-m88rs6000.fw"
#define M88DS3103_MCLK_KHZ 96000
+#define M88RS6000_CHIP_ID 0x74
+#define M88DS3103_CHIP_ID 0x70
struct m88ds3103_priv {
struct i2c_adapter *i2c;
@@ -38,6 +41,10 @@ struct m88ds3103_priv {
u32 ber;
bool warm; /* FW running */
struct i2c_adapter *i2c_adapter;
+ /* auto detect chip id to do different config */
+ u8 chip_id;
+ /* main mclk is calculated for M88RS6000 dynamically */
+ u32 mclk_khz;
};
struct m88ds3103_reg_val {
@@ -214,4 +221,178 @@ static const struct m88ds3103_reg_val m88ds3103_dvbs2_init_reg_vals[] = {
{0xb8, 0x00},
};
+static const struct m88ds3103_reg_val m88rs6000_dvbs_init_reg_vals[] = {
+ {0x23, 0x07},
+ {0x08, 0x03},
+ {0x0c, 0x02},
+ {0x20, 0x00},
+ {0x21, 0x54},
+ {0x25, 0x82},
+ {0x27, 0x31},
+ {0x30, 0x08},
+ {0x31, 0x40},
+ {0x32, 0x32},
+ {0x33, 0x35},
+ {0x35, 0xff},
+ {0x3a, 0x00},
+ {0x37, 0x10},
+ {0x38, 0x10},
+ {0x39, 0x02},
+ {0x42, 0x60},
+ {0x4a, 0x80},
+ {0x4b, 0x04},
+ {0x4d, 0x91},
+ {0x5d, 0xc8},
+ {0x50, 0x36},
+ {0x51, 0x36},
+ {0x52, 0x36},
+ {0x53, 0x36},
+ {0x63, 0x0f},
+ {0x64, 0x30},
+ {0x65, 0x40},
+ {0x68, 0x26},
+ {0x69, 0x4c},
+ {0x70, 0x20},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x40},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x60},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x80},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0xa0},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x1f},
+ {0x76, 0x38},
+ {0x77, 0xa6},
+ {0x78, 0x0c},
+ {0x79, 0x80},
+ {0x7f, 0x14},
+ {0x7c, 0x00},
+ {0xae, 0x82},
+ {0x80, 0x64},
+ {0x81, 0x66},
+ {0x82, 0x44},
+ {0x85, 0x04},
+ {0xcd, 0xf4},
+ {0x90, 0x33},
+ {0xa0, 0x44},
+ {0xbe, 0x00},
+ {0xc0, 0x08},
+ {0xc3, 0x10},
+ {0xc4, 0x08},
+ {0xc5, 0xf0},
+ {0xc6, 0xff},
+ {0xc7, 0x00},
+ {0xc8, 0x1a},
+ {0xc9, 0x80},
+ {0xe0, 0xf8},
+ {0xe6, 0x8b},
+ {0xd0, 0x40},
+ {0xf8, 0x20},
+ {0xfa, 0x0f},
+ {0x00, 0x00},
+ {0xbd, 0x01},
+ {0xb8, 0x00},
+ {0x29, 0x11},
+};
+
+static const struct m88ds3103_reg_val m88rs6000_dvbs2_init_reg_vals[] = {
+ {0x23, 0x07},
+ {0x08, 0x07},
+ {0x0c, 0x02},
+ {0x20, 0x00},
+ {0x21, 0x54},
+ {0x25, 0x82},
+ {0x27, 0x31},
+ {0x30, 0x08},
+ {0x32, 0x32},
+ {0x33, 0x35},
+ {0x35, 0xff},
+ {0x3a, 0x00},
+ {0x37, 0x10},
+ {0x38, 0x10},
+ {0x39, 0x02},
+ {0x42, 0x60},
+ {0x4a, 0x80},
+ {0x4b, 0x04},
+ {0x4d, 0x91},
+ {0x5d, 0xc8},
+ {0x50, 0x36},
+ {0x51, 0x36},
+ {0x52, 0x36},
+ {0x53, 0x36},
+ {0x63, 0x0f},
+ {0x64, 0x10},
+ {0x65, 0x20},
+ {0x68, 0x46},
+ {0x69, 0xcd},
+ {0x70, 0x20},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x40},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x60},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x80},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0xa0},
+ {0x71, 0x70},
+ {0x72, 0x04},
+ {0x73, 0x00},
+ {0x70, 0x1f},
+ {0x76, 0x38},
+ {0x77, 0xa6},
+ {0x78, 0x0c},
+ {0x79, 0x80},
+ {0x7f, 0x14},
+ {0x85, 0x08},
+ {0xcd, 0xf4},
+ {0x90, 0x33},
+ {0x86, 0x00},
+ {0x87, 0x0f},
+ {0x89, 0x00},
+ {0x8b, 0x44},
+ {0x8c, 0x66},
+ {0x9d, 0xc1},
+ {0x8a, 0x10},
+ {0xad, 0x40},
+ {0xa0, 0x44},
+ {0xbe, 0x00},
+ {0xc0, 0x08},
+ {0xc1, 0x10},
+ {0xc2, 0x08},
+ {0xc3, 0x10},
+ {0xc4, 0x08},
+ {0xc5, 0xf0},
+ {0xc6, 0xff},
+ {0xc7, 0x00},
+ {0xc8, 0x1a},
+ {0xc9, 0x80},
+ {0xca, 0x23},
+ {0xcb, 0x24},
+ {0xcc, 0xf4},
+ {0xce, 0x74},
+ {0x00, 0x00},
+ {0xbd, 0x01},
+ {0xb8, 0x00},
+ {0x29, 0x01},
+};
#endif
diff --git a/drivers/media/dvb-frontends/mn88472.h b/drivers/media/dvb-frontends/mn88472.h
new file mode 100644
index 0000000..da4558b
--- /dev/null
+++ b/drivers/media/dvb-frontends/mn88472.h
@@ -0,0 +1,38 @@
+/*
+ * Panasonic MN88472 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2013 Antti Palosaari <crope@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MN88472_H
+#define MN88472_H
+
+#include <linux/dvb/frontend.h>
+
+struct mn88472_config {
+ /*
+ * Max num of bytes given I2C adapter could write at once.
+ * Default: none
+ */
+ u16 i2c_wr_max;
+
+
+ /* Everything after that is returned by the driver. */
+
+ /*
+ * DVB frontend.
+ */
+ struct dvb_frontend **fe;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/mn88473.h b/drivers/media/dvb-frontends/mn88473.h
new file mode 100644
index 0000000..a373ec9
--- /dev/null
+++ b/drivers/media/dvb-frontends/mn88473.h
@@ -0,0 +1,38 @@
+/*
+ * Panasonic MN88473 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MN88473_H
+#define MN88473_H
+
+#include <linux/dvb/frontend.h>
+
+struct mn88473_config {
+ /*
+ * Max num of bytes given I2C adapter could write at once.
+ * Default: none
+ */
+ u16 i2c_wr_max;
+
+
+ /* Everything after that is returned by the driver. */
+
+ /*
+ * DVB frontend.
+ */
+ struct dvb_frontend **fe;
+};
+
+#endif
diff --git a/drivers/media/dvb-frontends/rtl2832.c b/drivers/media/dvb-frontends/rtl2832.c
index eb737cf..9026e1a 100644
--- a/drivers/media/dvb-frontends/rtl2832.c
+++ b/drivers/media/dvb-frontends/rtl2832.c
@@ -258,13 +258,11 @@ static int rtl2832_rd_regs(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val,
return rtl2832_rd(priv, reg, val, len);
}
-#if 0 /* currently not used */
/* write single register */
static int rtl2832_wr_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 val)
{
return rtl2832_wr_regs(priv, reg, page, &val, 1);
}
-#endif
/* read single register */
static int rtl2832_rd_reg(struct rtl2832_priv *priv, u8 reg, u8 page, u8 *val)
@@ -599,6 +597,11 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
if (fe->ops.tuner_ops.set_params)
fe->ops.tuner_ops.set_params(fe);
+ /* PIP mode related */
+ ret = rtl2832_wr_regs(priv, 0x92, 1, "\x00\x0f\xff", 3);
+ if (ret)
+ goto err;
+
/* If the frontend has get_if_frequency(), use it */
if (fe->ops.tuner_ops.get_if_frequency) {
u32 if_freq;
@@ -661,7 +664,6 @@ static int rtl2832_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
-
/* soft reset */
ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
if (ret)
@@ -1020,6 +1022,58 @@ static int rtl2832_deselect(struct i2c_adapter *adap, void *mux_priv,
return 0;
}
+int rtl2832_enable_external_ts_if(struct dvb_frontend *fe)
+{
+ struct rtl2832_priv *priv = fe->demodulator_priv;
+ int ret;
+
+ dev_dbg(&priv->i2c->dev, "%s: setting PIP mode\n", __func__);
+
+ ret = rtl2832_wr_regs(priv, 0x0c, 1, "\x5f\xff", 2);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_PIP_ON, 0x1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_reg(priv, 0xbc, 0, 0x18);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_reg(priv, 0x22, 0, 0x01);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_reg(priv, 0x26, 0, 0x1f);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_reg(priv, 0x27, 0, 0xff);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_regs(priv, 0x92, 1, "\x7f\xf7\xff", 3);
+ if (ret)
+ goto err;
+
+ /* soft reset */
+ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x1);
+ if (ret)
+ goto err;
+
+ ret = rtl2832_wr_demod_reg(priv, DVBT_SOFT_RST, 0x0);
+ if (ret)
+ goto err;
+
+ return 0;
+err:
+ dev_dbg(&priv->i2c->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+
+}
+EXPORT_SYMBOL(rtl2832_enable_external_ts_if);
+
struct i2c_adapter *rtl2832_get_i2c_adapter(struct dvb_frontend *fe)
{
struct rtl2832_priv *priv = fe->demodulator_priv;
diff --git a/drivers/media/dvb-frontends/rtl2832.h b/drivers/media/dvb-frontends/rtl2832.h
index cb3b6b0..5254c1d 100644
--- a/drivers/media/dvb-frontends/rtl2832.h
+++ b/drivers/media/dvb-frontends/rtl2832.h
@@ -64,6 +64,10 @@ extern struct i2c_adapter *rtl2832_get_private_i2c_adapter(
struct dvb_frontend *fe
);
+extern int rtl2832_enable_external_ts_if(
+ struct dvb_frontend *fe
+);
+
#else
static inline struct dvb_frontend *rtl2832_attach(
@@ -89,6 +93,13 @@ static inline struct i2c_adapter *rtl2832_get_private_i2c_adapter(
return NULL;
}
+static inline int rtl2832_enable_external_ts_if(
+ struct dvb_frontend *fe
+)
+{
+ return -ENODEV;
+}
+
#endif
diff --git a/drivers/media/dvb-frontends/rtl2832_sdr.c b/drivers/media/dvb-frontends/rtl2832_sdr.c
index 7bf98cf..2896b47 100644
--- a/drivers/media/dvb-frontends/rtl2832_sdr.c
+++ b/drivers/media/dvb-frontends/rtl2832_sdr.c
@@ -1013,6 +1013,10 @@ static int rtl2832_sdr_start_streaming(struct vb2_queue *vq, unsigned int count)
if (s->d->props->power_ctrl)
s->d->props->power_ctrl(s->d, 1);
+ /* enable ADC */
+ if (s->d->props->frontend_ctrl)
+ s->d->props->frontend_ctrl(s->fe, 1);
+
set_bit(POWER_ON, &s->flags);
ret = rtl2832_sdr_set_tuner(s);
@@ -1064,6 +1068,10 @@ static void rtl2832_sdr_stop_streaming(struct vb2_queue *vq)
clear_bit(POWER_ON, &s->flags);
+ /* disable ADC */
+ if (s->d->props->frontend_ctrl)
+ s->d->props->frontend_ctrl(s->fe, 0);
+
if (s->d->props->power_ctrl)
s->d->props->power_ctrl(s->d, 0);
diff --git a/drivers/media/dvb-frontends/si2168.c b/drivers/media/dvb-frontends/si2168.c
index 1cd93be..ce9ab44 100644
--- a/drivers/media/dvb-frontends/si2168.c
+++ b/drivers/media/dvb-frontends/si2168.c
@@ -308,14 +308,16 @@ static int si2168_set_frontend(struct dvb_frontend *fe)
if (ret)
goto err;
- memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x18", 6);
+ memcpy(cmd.args, "\x14\x00\x09\x10\xe3\x08", 6);
+ cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
if (ret)
goto err;
- memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x15", 6);
+ memcpy(cmd.args, "\x14\x00\x08\x10\xd7\x05", 6);
+ cmd.args[5] |= s->ts_clock_inv ? 0x00 : 0x10;
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2168_cmd_execute(s, &cmd);
@@ -453,27 +455,45 @@ static int si2168_init(struct dvb_frontend *fe)
dev_err(&s->client->dev,
"firmware file '%s' not found\n",
fw_file);
- goto err;
+ goto error_fw_release;
}
}
dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
fw_file);
- for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
- len = remaining;
- if (len > i2c_wr_max)
- len = i2c_wr_max;
-
- memcpy(cmd.args, &fw->data[fw->size - remaining], len);
- cmd.wlen = len;
- cmd.rlen = 1;
- ret = si2168_cmd_execute(s, &cmd);
- if (ret) {
- dev_err(&s->client->dev,
- "firmware download failed=%d\n",
- ret);
- goto err;
+ if ((fw->size % 17 == 0) && (fw->data[0] > 5)) {
+ /* firmware is in the new format */
+ for (remaining = fw->size; remaining > 0; remaining -= 17) {
+ len = fw->data[fw->size - remaining];
+ memcpy(cmd.args, &fw->data[(fw->size - remaining) + 1], len);
+ cmd.wlen = len;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret) {
+ dev_err(&s->client->dev,
+ "firmware download failed=%d\n",
+ ret);
+ goto error_fw_release;
+ }
+ }
+ } else {
+ /* firmware is in the old format */
+ for (remaining = fw->size; remaining > 0; remaining -= i2c_wr_max) {
+ len = remaining;
+ if (len > i2c_wr_max)
+ len = i2c_wr_max;
+
+ memcpy(cmd.args, &fw->data[fw->size - remaining], len);
+ cmd.wlen = len;
+ cmd.rlen = 1;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret) {
+ dev_err(&s->client->dev,
+ "firmware download failed=%d\n",
+ ret);
+ goto error_fw_release;
+ }
}
}
@@ -487,6 +507,17 @@ static int si2168_init(struct dvb_frontend *fe)
if (ret)
goto err;
+ /* query firmware version */
+ memcpy(cmd.args, "\x11", 1);
+ cmd.wlen = 1;
+ cmd.rlen = 10;
+ ret = si2168_cmd_execute(s, &cmd);
+ if (ret)
+ goto err;
+
+ dev_dbg(&s->client->dev, "firmware version: %c.%c.%d\n",
+ cmd.args[6], cmd.args[7], cmd.args[8]);
+
/* set ts mode */
memcpy(cmd.args, "\x14\x00\x01\x10\x10\x00", 6);
cmd.args[4] |= s->ts_mode;
@@ -498,17 +529,16 @@ static int si2168_init(struct dvb_frontend *fe)
s->fw_loaded = true;
-warm:
dev_info(&s->client->dev, "found a '%s' in warm state\n",
si2168_ops.info.name);
-
+warm:
s->active = true;
return 0;
-err:
- if (fw)
- release_firmware(fw);
+error_fw_release:
+ release_firmware(fw);
+err:
dev_dbg(&s->client->dev, "failed=%d\n", ret);
return ret;
}
@@ -670,6 +700,7 @@ static int si2168_probe(struct i2c_client *client,
*config->i2c_adapter = s->adapter;
*config->fe = &s->fe;
s->ts_mode = config->ts_mode;
+ s->ts_clock_inv = config->ts_clock_inv;
s->fw_loaded = false;
i2c_set_clientdata(client, s);
diff --git a/drivers/media/dvb-frontends/si2168.h b/drivers/media/dvb-frontends/si2168.h
index e086d67..87bc121 100644
--- a/drivers/media/dvb-frontends/si2168.h
+++ b/drivers/media/dvb-frontends/si2168.h
@@ -37,6 +37,10 @@ struct si2168_config {
/* TS mode */
u8 ts_mode;
+
+ /* TS clock inverted */
+ bool ts_clock_inv;
+
};
#define SI2168_TS_PARALLEL 0x06
diff --git a/drivers/media/dvb-frontends/si2168_priv.h b/drivers/media/dvb-frontends/si2168_priv.h
index e13983e..60bc334 100644
--- a/drivers/media/dvb-frontends/si2168_priv.h
+++ b/drivers/media/dvb-frontends/si2168_priv.h
@@ -38,6 +38,7 @@ struct si2168 {
bool active;
bool fw_loaded;
u8 ts_mode;
+ bool ts_clock_inv;
};
/* firmare command struct */
diff --git a/drivers/media/dvb-frontends/sp2.c b/drivers/media/dvb-frontends/sp2.c
index 15bf431..cc1ef96 100644
--- a/drivers/media/dvb-frontends/sp2.c
+++ b/drivers/media/dvb-frontends/sp2.c
@@ -92,6 +92,9 @@ static int sp2_write_i2c(struct sp2 *s, u8 reg, u8 *buf, int len)
return -EIO;
}
+ dev_dbg(&s->client->dev, "addr=0x%04x, reg = 0x%02x, data = %*ph\n",
+ client->addr, reg, len, buf);
+
return 0;
}
@@ -103,9 +106,6 @@ static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
int mem, ret;
int (*ci_op_cam)(void*, u8, int, u8, int*) = s->ci_control;
- dev_dbg(&s->client->dev, "slot=%d, acs=0x%02x, addr=0x%04x, data = 0x%02x",
- slot, acs, addr, data);
-
if (slot != 0)
return -EINVAL;
@@ -140,13 +140,16 @@ static int sp2_ci_op_cam(struct dvb_ca_en50221 *en50221, int slot, u8 acs,
if (ret)
return ret;
- if (read) {
- dev_dbg(&s->client->dev, "cam read, addr=0x%04x, data = 0x%04x",
- addr, mem);
+ dev_dbg(&s->client->dev, "%s: slot=%d, addr=0x%04x, %s, data=%x",
+ (read) ? "read" : "write", slot, addr,
+ (acs == SP2_CI_ATTR_ACS) ? "attr" : "io",
+ (read) ? mem : data);
+
+ if (read)
return mem;
- } else {
+ else
return 0;
- }
+
}
int sp2_ci_read_attribute_mem(struct dvb_ca_en50221 *en50221,
@@ -407,7 +410,7 @@ err:
static int sp2_remove(struct i2c_client *client)
{
- struct si2157 *s = i2c_get_clientdata(client);
+ struct sp2 *s = i2c_get_clientdata(client);
dev_dbg(&client->dev, "\n");
diff --git a/drivers/media/dvb-frontends/stb0899_drv.c b/drivers/media/dvb-frontends/stb0899_drv.c
index 07cd5ea..19646fb 100644
--- a/drivers/media/dvb-frontends/stb0899_drv.c
+++ b/drivers/media/dvb-frontends/stb0899_drv.c
@@ -705,7 +705,7 @@ static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma
struct stb0899_state *state = fe->demodulator_priv;
u8 reg, i;
- if (cmd->msg_len > 8)
+ if (cmd->msg_len > sizeof(cmd->msg))
return -EINVAL;
/* enable FIFO precharge */
diff --git a/drivers/media/dvb-frontends/stv090x.c b/drivers/media/dvb-frontends/stv090x.c
index 23e872f..0b2a934 100644
--- a/drivers/media/dvb-frontends/stv090x.c
+++ b/drivers/media/dvb-frontends/stv090x.c
@@ -2146,7 +2146,7 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
u32 reg;
s32 car_step, steps, cur_step, dir, freq, timeout_lock;
- int lock = 0;
+ int lock;
if (state->srate >= 10000000)
timeout_lock = timeout_dmd / 3;
@@ -2154,98 +2154,96 @@ static int stv090x_get_coldlock(struct stv090x_state *state, s32 timeout_dmd)
timeout_lock = timeout_dmd / 2;
lock = stv090x_get_dmdlock(state, timeout_lock); /* cold start wait */
- if (!lock) {
- if (state->srate >= 10000000) {
- if (stv090x_chk_tmg(state)) {
- if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
- goto err;
- if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
- goto err;
- lock = stv090x_get_dmdlock(state, timeout_dmd);
- } else {
- lock = 0;
- }
- } else {
- if (state->srate <= 4000000)
- car_step = 1000;
- else if (state->srate <= 7000000)
- car_step = 2000;
- else if (state->srate <= 10000000)
- car_step = 3000;
- else
- car_step = 5000;
-
- steps = (state->search_range / 1000) / car_step;
- steps /= 2;
- steps = 2 * (steps + 1);
- if (steps < 0)
- steps = 2;
- else if (steps > 12)
- steps = 12;
-
- cur_step = 1;
- dir = 1;
-
- if (!lock) {
- freq = state->frequency;
- state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
- while ((cur_step <= steps) && (!lock)) {
- if (dir > 0)
- freq += cur_step * car_step;
- else
- freq -= cur_step * car_step;
-
- /* Setup tuner */
- if (stv090x_i2c_gate_ctrl(state, 1) < 0)
- goto err;
+ if (lock)
+ return lock;
- if (state->config->tuner_set_frequency) {
- if (state->config->tuner_set_frequency(fe, freq) < 0)
- goto err_gateoff;
- }
+ if (state->srate >= 10000000) {
+ if (stv090x_chk_tmg(state)) {
+ if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+ goto err;
+ if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+ goto err;
+ return stv090x_get_dmdlock(state, timeout_dmd);
+ }
+ return 0;
+ }
- if (state->config->tuner_set_bandwidth) {
- if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
- goto err_gateoff;
- }
+ if (state->srate <= 4000000)
+ car_step = 1000;
+ else if (state->srate <= 7000000)
+ car_step = 2000;
+ else if (state->srate <= 10000000)
+ car_step = 3000;
+ else
+ car_step = 5000;
- if (stv090x_i2c_gate_ctrl(state, 0) < 0)
- goto err;
+ steps = (state->search_range / 1000) / car_step;
+ steps /= 2;
+ steps = 2 * (steps + 1);
+ if (steps < 0)
+ steps = 2;
+ else if (steps > 12)
+ steps = 12;
- msleep(50);
+ cur_step = 1;
+ dir = 1;
- if (stv090x_i2c_gate_ctrl(state, 1) < 0)
- goto err;
+ freq = state->frequency;
+ state->tuner_bw = stv090x_car_width(state->srate, state->rolloff) + state->srate;
+ while ((cur_step <= steps) && (!lock)) {
+ if (dir > 0)
+ freq += cur_step * car_step;
+ else
+ freq -= cur_step * car_step;
- if (state->config->tuner_get_status) {
- if (state->config->tuner_get_status(fe, &reg) < 0)
- goto err_gateoff;
- }
+ /* Setup tuner */
+ if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+ goto err;
- if (reg)
- dprintk(FE_DEBUG, 1, "Tuner phase locked");
- else
- dprintk(FE_DEBUG, 1, "Tuner unlocked");
+ if (state->config->tuner_set_frequency) {
+ if (state->config->tuner_set_frequency(fe, freq) < 0)
+ goto err_gateoff;
+ }
- if (stv090x_i2c_gate_ctrl(state, 0) < 0)
- goto err;
+ if (state->config->tuner_set_bandwidth) {
+ if (state->config->tuner_set_bandwidth(fe, state->tuner_bw) < 0)
+ goto err_gateoff;
+ }
- STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
- if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
- goto err;
- if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
- goto err;
- if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
- goto err;
- if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
- goto err;
- lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
+ if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+ goto err;
- dir *= -1;
- cur_step++;
- }
- }
+ msleep(50);
+
+ if (stv090x_i2c_gate_ctrl(state, 1) < 0)
+ goto err;
+
+ if (state->config->tuner_get_status) {
+ if (state->config->tuner_get_status(fe, &reg) < 0)
+ goto err_gateoff;
}
+
+ if (reg)
+ dprintk(FE_DEBUG, 1, "Tuner phase locked");
+ else
+ dprintk(FE_DEBUG, 1, "Tuner unlocked");
+
+ if (stv090x_i2c_gate_ctrl(state, 0) < 0)
+ goto err;
+
+ STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1c);
+ if (STV090x_WRITE_DEMOD(state, CFRINIT1, 0x00) < 0)
+ goto err;
+ if (STV090x_WRITE_DEMOD(state, CFRINIT0, 0x00) < 0)
+ goto err;
+ if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x1f) < 0)
+ goto err;
+ if (STV090x_WRITE_DEMOD(state, DMDISTATE, 0x15) < 0)
+ goto err;
+ lock = stv090x_get_dmdlock(state, (timeout_dmd / 3));
+
+ dir *= -1;
+ cur_step++;
}
return lock;
@@ -2663,13 +2661,9 @@ static enum stv090x_signal_state stv090x_get_sig_params(struct stv090x_state *st
return STV090x_RANGEOK;
else if (abs(offst_freq) <= (stv090x_car_width(state->srate, state->rolloff) / 2000))
return STV090x_RANGEOK;
- else
- return STV090x_OUTOFRANGE; /* Out of Range */
} else {
if (abs(offst_freq) <= ((state->search_range / 2000) + 500))
return STV090x_RANGEOK;
- else
- return STV090x_OUTOFRANGE;
}
return STV090x_OUTOFRANGE;
@@ -2789,6 +2783,12 @@ static u8 stv090x_optimize_carloop(struct stv090x_state *state, enum stv090x_mod
aclc = car_loop[i].crl_pilots_off_30;
}
} else { /* 16APSK and 32APSK */
+ /*
+ * This should never happen in practice, except if
+ * something is really wrong at the car_loop table.
+ */
+ if (i >= 11)
+ i = 10;
if (state->srate <= 3000000)
aclc = car_loop_apsk_low[i].crl_pilots_on_2;
else if (state->srate <= 7000000)
@@ -3470,7 +3470,20 @@ static enum dvbfe_search stv090x_search(struct dvb_frontend *fe)
if (props->frequency == 0)
return DVBFE_ALGO_SEARCH_INVALID;
- state->delsys = props->delivery_system;
+ switch (props->delivery_system) {
+ case SYS_DSS:
+ state->delsys = STV090x_DSS;
+ break;
+ case SYS_DVBS:
+ state->delsys = STV090x_DVBS1;
+ break;
+ case SYS_DVBS2:
+ state->delsys = STV090x_DVBS2;
+ break;
+ default:
+ return DVBFE_ALGO_SEARCH_INVALID;
+ }
+
state->frequency = props->frequency;
state->srate = props->symbol_rate;
state->search_mode = STV090x_SEARCH_AUTO;
@@ -4859,8 +4872,8 @@ err:
return -1;
}
-int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
- u8 xor_value)
+static int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir,
+ u8 value, u8 xor_value)
{
struct stv090x_state *state = fe->demodulator_priv;
u8 reg = 0;
@@ -4871,7 +4884,6 @@ int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
return stv090x_write_reg(state, STV090x_GPIOxCFG(gpio), reg);
}
-EXPORT_SYMBOL(stv090x_set_gpio);
static struct dvb_frontend_ops stv090x_ops = {
.delsys = { SYS_DVBS, SYS_DVBS2, SYS_DSS },
@@ -4908,7 +4920,7 @@ static struct dvb_frontend_ops stv090x_ops = {
};
-struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
+struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
struct i2c_adapter *i2c,
enum stv090x_demodulator demod)
{
@@ -4969,6 +4981,8 @@ struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
if (config->diseqc_envelope_mode)
stv090x_send_diseqc_burst(&state->frontend, SEC_MINI_A);
+ config->set_gpio = stv090x_set_gpio;
+
dprintk(FE_ERROR, 1, "Attaching %s demodulator(%d) Cut=0x%02x",
state->device == STV0900 ? "STV0900" : "STV0903",
demod,
diff --git a/drivers/media/dvb-frontends/stv090x.h b/drivers/media/dvb-frontends/stv090x.h
index 0bd6adc..742eeda 100644
--- a/drivers/media/dvb-frontends/stv090x.h
+++ b/drivers/media/dvb-frontends/stv090x.h
@@ -89,29 +89,29 @@ struct stv090x_config {
bool diseqc_envelope_mode;
- int (*tuner_init) (struct dvb_frontend *fe);
- int (*tuner_sleep) (struct dvb_frontend *fe);
- int (*tuner_set_mode) (struct dvb_frontend *fe, enum tuner_mode mode);
- int (*tuner_set_frequency) (struct dvb_frontend *fe, u32 frequency);
- int (*tuner_get_frequency) (struct dvb_frontend *fe, u32 *frequency);
- int (*tuner_set_bandwidth) (struct dvb_frontend *fe, u32 bandwidth);
- int (*tuner_get_bandwidth) (struct dvb_frontend *fe, u32 *bandwidth);
- int (*tuner_set_bbgain) (struct dvb_frontend *fe, u32 gain);
- int (*tuner_get_bbgain) (struct dvb_frontend *fe, u32 *gain);
- int (*tuner_set_refclk) (struct dvb_frontend *fe, u32 refclk);
- int (*tuner_get_status) (struct dvb_frontend *fe, u32 *status);
- void (*tuner_i2c_lock) (struct dvb_frontend *fe, int lock);
+ int (*tuner_init)(struct dvb_frontend *fe);
+ int (*tuner_sleep)(struct dvb_frontend *fe);
+ int (*tuner_set_mode)(struct dvb_frontend *fe, enum tuner_mode mode);
+ int (*tuner_set_frequency)(struct dvb_frontend *fe, u32 frequency);
+ int (*tuner_get_frequency)(struct dvb_frontend *fe, u32 *frequency);
+ int (*tuner_set_bandwidth)(struct dvb_frontend *fe, u32 bandwidth);
+ int (*tuner_get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
+ int (*tuner_set_bbgain)(struct dvb_frontend *fe, u32 gain);
+ int (*tuner_get_bbgain)(struct dvb_frontend *fe, u32 *gain);
+ int (*tuner_set_refclk)(struct dvb_frontend *fe, u32 refclk);
+ int (*tuner_get_status)(struct dvb_frontend *fe, u32 *status);
+ void (*tuner_i2c_lock)(struct dvb_frontend *fe, int lock);
+
+ /* dir = 0 -> output, dir = 1 -> input/open-drain */
+ int (*set_gpio)(struct dvb_frontend *fe, u8 gpio, u8 dir, u8 value,
+ u8 xor_value);
};
#if IS_ENABLED(CONFIG_DVB_STV090x)
-extern struct dvb_frontend *stv090x_attach(const struct stv090x_config *config,
- struct i2c_adapter *i2c,
- enum stv090x_demodulator demod);
-
-/* dir = 0 -> output, dir = 1 -> input/open-drain */
-extern int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
- u8 dir, u8 value, u8 xor_value);
+struct dvb_frontend *stv090x_attach(struct stv090x_config *config,
+ struct i2c_adapter *i2c,
+ enum stv090x_demodulator demod);
#else
@@ -123,12 +123,6 @@ static inline struct dvb_frontend *stv090x_attach(const struct stv090x_config *c
return NULL;
}
-static inline int stv090x_set_gpio(struct dvb_frontend *fe, u8 gpio,
- u8 opd, u8 value, u8 xor_value)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return -ENODEV;
-}
#endif /* CONFIG_DVB_STV090x */
#endif /* __STV090x_H */
diff --git a/drivers/media/firewire/firedtv-ci.c b/drivers/media/firewire/firedtv-ci.c
index e5ebdbf..e63f582 100644
--- a/drivers/media/firewire/firedtv-ci.c
+++ b/drivers/media/firewire/firedtv-ci.c
@@ -253,6 +253,5 @@ int fdtv_ca_register(struct firedtv *fdtv)
void fdtv_ca_release(struct firedtv *fdtv)
{
- if (fdtv->cadev)
- dvb_unregister_device(fdtv->cadev);
+ dvb_unregister_device(fdtv->cadev);
}
diff --git a/drivers/media/firewire/firedtv.h b/drivers/media/firewire/firedtv.h
index c2ba085..346a85b 100644
--- a/drivers/media/firewire/firedtv.h
+++ b/drivers/media/firewire/firedtv.h
@@ -96,7 +96,7 @@ struct firedtv {
enum model_type type;
char subunit;
- char isochannel;
+ s8 isochannel;
struct fdtv_ir_context *ir_context;
fe_sec_voltage_t voltage;
diff --git a/drivers/media/i2c/adv7170.c b/drivers/media/i2c/adv7170.c
index 04bb297..40a1a95 100644
--- a/drivers/media/i2c/adv7170.c
+++ b/drivers/media/i2c/adv7170.c
@@ -63,9 +63,9 @@ static inline struct adv7170 *to_adv7170(struct v4l2_subdev *sd)
static char *inputs[] = { "pass_through", "play_back" };
-static enum v4l2_mbus_pixelcode adv7170_codes[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_UYVY8_1X16,
+static u32 adv7170_codes[] = {
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_UYVY8_1X16,
};
/* ----------------------------------------------------------------------- */
@@ -263,7 +263,7 @@ static int adv7170_s_routing(struct v4l2_subdev *sd,
}
static int adv7170_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(adv7170_codes))
return -EINVAL;
@@ -278,9 +278,9 @@ static int adv7170_g_fmt(struct v4l2_subdev *sd,
u8 val = adv7170_read(sd, 0x7);
if ((val & 0x40) == (1 << 6))
- mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
else
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
mf->width = 0;
@@ -297,11 +297,11 @@ static int adv7170_s_fmt(struct v4l2_subdev *sd,
int ret;
switch (mf->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
val &= ~0x40;
break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
val |= 0x40;
break;
diff --git a/drivers/media/i2c/adv7175.c b/drivers/media/i2c/adv7175.c
index b88f3b3..d220af5 100644
--- a/drivers/media/i2c/adv7175.c
+++ b/drivers/media/i2c/adv7175.c
@@ -60,9 +60,9 @@ static inline struct adv7175 *to_adv7175(struct v4l2_subdev *sd)
static char *inputs[] = { "pass_through", "play_back", "color_bar" };
-static enum v4l2_mbus_pixelcode adv7175_codes[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_UYVY8_1X16,
+static u32 adv7175_codes[] = {
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_UYVY8_1X16,
};
/* ----------------------------------------------------------------------- */
@@ -301,7 +301,7 @@ static int adv7175_s_routing(struct v4l2_subdev *sd,
}
static int adv7175_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(adv7175_codes))
return -EINVAL;
@@ -316,9 +316,9 @@ static int adv7175_g_fmt(struct v4l2_subdev *sd,
u8 val = adv7175_read(sd, 0x7);
if ((val & 0x40) == (1 << 6))
- mf->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ mf->code = MEDIA_BUS_FMT_UYVY8_1X16;
else
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
mf->width = 0;
@@ -335,11 +335,11 @@ static int adv7175_s_fmt(struct v4l2_subdev *sd,
int ret;
switch (mf->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
val &= ~0x40;
break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
val |= 0x40;
break;
diff --git a/drivers/media/i2c/adv7180.c b/drivers/media/i2c/adv7180.c
index 821178d..bffe6eb 100644
--- a/drivers/media/i2c/adv7180.c
+++ b/drivers/media/i2c/adv7180.c
@@ -422,12 +422,12 @@ static void adv7180_exit_controls(struct adv7180_state *state)
}
static int adv7180_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index > 0)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8;
+ *code = MEDIA_BUS_FMT_YUYV8_2X8;
return 0;
}
@@ -437,7 +437,7 @@ static int adv7180_mbus_fmt(struct v4l2_subdev *sd,
{
struct adv7180_state *state = to_state(sd);
- fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
fmt->field = V4L2_FIELD_INTERLACED;
fmt->width = 720;
diff --git a/drivers/media/i2c/adv7183.c b/drivers/media/i2c/adv7183.c
index df461b0..28940cc 100644
--- a/drivers/media/i2c/adv7183.c
+++ b/drivers/media/i2c/adv7183.c
@@ -421,12 +421,12 @@ static int adv7183_g_input_status(struct v4l2_subdev *sd, u32 *status)
}
static int adv7183_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index > 0)
return -EINVAL;
- *code = V4L2_MBUS_FMT_UYVY8_2X8;
+ *code = MEDIA_BUS_FMT_UYVY8_2X8;
return 0;
}
@@ -435,7 +435,7 @@ static int adv7183_try_mbus_fmt(struct v4l2_subdev *sd,
{
struct adv7183 *decoder = to_adv7183(sd);
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
if (decoder->std & V4L2_STD_525_60) {
fmt->field = V4L2_FIELD_SEQ_TB;
diff --git a/drivers/media/i2c/adv7511.c b/drivers/media/i2c/adv7511.c
index f98acf4..81736aa 100644
--- a/drivers/media/i2c/adv7511.c
+++ b/drivers/media/i2c/adv7511.c
@@ -26,6 +26,7 @@
#include <linux/videodev2.h>
#include <linux/gpio.h>
#include <linux/workqueue.h>
+#include <linux/hdmi.h>
#include <linux/v4l2-dv-timings.h>
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
@@ -96,6 +97,10 @@ struct adv7511_state {
bool have_monitor;
/* timings from s_dv_timings */
struct v4l2_dv_timings dv_timings;
+ u32 fmt_code;
+ u32 colorspace;
+ u32 ycbcr_enc;
+ u32 quantization;
/* controls */
struct v4l2_ctrl *hdmi_mode_ctrl;
struct v4l2_ctrl *hotplug_ctrl;
@@ -779,26 +784,234 @@ static int adv7511_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
{
struct adv7511_state *state = get_adv7511_state(sd);
+ memset(edid->reserved, 0, sizeof(edid->reserved));
+
if (edid->pad != 0)
return -EINVAL;
- if ((edid->blocks == 0) || (edid->blocks > 256))
- return -EINVAL;
- if (!state->edid.segments) {
- v4l2_dbg(1, debug, sd, "EDID segment 0 not found\n");
- return -ENODATA;
+
+ if (edid->start_block == 0 && edid->blocks == 0) {
+ edid->blocks = state->edid.segments * 2;
+ return 0;
}
+
+ if (state->edid.segments == 0)
+ return -ENODATA;
+
if (edid->start_block >= state->edid.segments * 2)
- return -E2BIG;
- if ((edid->blocks + edid->start_block) >= state->edid.segments * 2)
+ return -EINVAL;
+
+ if (edid->start_block + edid->blocks > state->edid.segments * 2)
edid->blocks = state->edid.segments * 2 - edid->start_block;
memcpy(edid->edid, &state->edid.data[edid->start_block * 128],
128 * edid->blocks);
+
+ return 0;
+}
+
+static int adv7511_enum_mbus_code(struct v4l2_subdev *sd,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_mbus_code_enum *code)
+{
+ if (code->pad != 0)
+ return -EINVAL;
+
+ switch (code->index) {
+ case 0:
+ code->code = MEDIA_BUS_FMT_RGB888_1X24;
+ break;
+ case 1:
+ code->code = MEDIA_BUS_FMT_YUYV8_1X16;
+ break;
+ case 2:
+ code->code = MEDIA_BUS_FMT_UYVY8_1X16;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void adv7511_fill_format(struct adv7511_state *state,
+ struct v4l2_mbus_framefmt *format)
+{
+ memset(format, 0, sizeof(*format));
+
+ format->width = state->dv_timings.bt.width;
+ format->height = state->dv_timings.bt.height;
+ format->field = V4L2_FIELD_NONE;
+}
+
+static int adv7511_get_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct adv7511_state *state = get_adv7511_state(sd);
+
+ if (format->pad != 0)
+ return -EINVAL;
+
+ adv7511_fill_format(state, &format->format);
+
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_try_format(fh, format->pad);
+ format->format.code = fmt->code;
+ format->format.colorspace = fmt->colorspace;
+ format->format.ycbcr_enc = fmt->ycbcr_enc;
+ format->format.quantization = fmt->quantization;
+ } else {
+ format->format.code = state->fmt_code;
+ format->format.colorspace = state->colorspace;
+ format->format.ycbcr_enc = state->ycbcr_enc;
+ format->format.quantization = state->quantization;
+ }
+
+ return 0;
+}
+
+static int adv7511_set_fmt(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *format)
+{
+ struct adv7511_state *state = get_adv7511_state(sd);
+ /*
+ * Bitfield namings come the CEA-861-F standard, table 8 "Auxiliary
+ * Video Information (AVI) InfoFrame Format"
+ *
+ * c = Colorimetry
+ * ec = Extended Colorimetry
+ * y = RGB or YCbCr
+ * q = RGB Quantization Range
+ * yq = YCC Quantization Range
+ */
+ u8 c = HDMI_COLORIMETRY_NONE;
+ u8 ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+ u8 y = HDMI_COLORSPACE_RGB;
+ u8 q = HDMI_QUANTIZATION_RANGE_DEFAULT;
+ u8 yq = HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+
+ if (format->pad != 0)
+ return -EINVAL;
+ switch (format->format.code) {
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ adv7511_fill_format(state, &format->format);
+ if (format->which == V4L2_SUBDEV_FORMAT_TRY) {
+ struct v4l2_mbus_framefmt *fmt;
+
+ fmt = v4l2_subdev_get_try_format(fh, format->pad);
+ fmt->code = format->format.code;
+ fmt->colorspace = format->format.colorspace;
+ fmt->ycbcr_enc = format->format.ycbcr_enc;
+ fmt->quantization = format->format.quantization;
+ return 0;
+ }
+
+ switch (format->format.code) {
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01);
+ adv7511_wr_and_or(sd, 0x16, 0x03, 0xb8);
+ y = HDMI_COLORSPACE_YUV422;
+ break;
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ adv7511_wr_and_or(sd, 0x15, 0xf0, 0x01);
+ adv7511_wr_and_or(sd, 0x16, 0x03, 0xbc);
+ y = HDMI_COLORSPACE_YUV422;
+ break;
+ case MEDIA_BUS_FMT_RGB888_1X24:
+ default:
+ adv7511_wr_and_or(sd, 0x15, 0xf0, 0x00);
+ adv7511_wr_and_or(sd, 0x16, 0x03, 0x00);
+ break;
+ }
+ state->fmt_code = format->format.code;
+ state->colorspace = format->format.colorspace;
+ state->ycbcr_enc = format->format.ycbcr_enc;
+ state->quantization = format->format.quantization;
+
+ switch (format->format.colorspace) {
+ case V4L2_COLORSPACE_ADOBERGB:
+ c = HDMI_COLORIMETRY_EXTENDED;
+ ec = y ? HDMI_EXTENDED_COLORIMETRY_ADOBE_YCC_601 :
+ HDMI_EXTENDED_COLORIMETRY_ADOBE_RGB;
+ break;
+ case V4L2_COLORSPACE_SMPTE170M:
+ c = y ? HDMI_COLORIMETRY_ITU_601 : HDMI_COLORIMETRY_NONE;
+ if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV601) {
+ c = HDMI_COLORIMETRY_EXTENDED;
+ ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+ }
+ break;
+ case V4L2_COLORSPACE_REC709:
+ c = y ? HDMI_COLORIMETRY_ITU_709 : HDMI_COLORIMETRY_NONE;
+ if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_XV709) {
+ c = HDMI_COLORIMETRY_EXTENDED;
+ ec = HDMI_EXTENDED_COLORIMETRY_XV_YCC_709;
+ }
+ break;
+ case V4L2_COLORSPACE_SRGB:
+ c = y ? HDMI_COLORIMETRY_EXTENDED : HDMI_COLORIMETRY_NONE;
+ ec = y ? HDMI_EXTENDED_COLORIMETRY_S_YCC_601 :
+ HDMI_EXTENDED_COLORIMETRY_XV_YCC_601;
+ break;
+ case V4L2_COLORSPACE_BT2020:
+ c = HDMI_COLORIMETRY_EXTENDED;
+ if (y && format->format.ycbcr_enc == V4L2_YCBCR_ENC_BT2020_CONST_LUM)
+ ec = 5; /* Not yet available in hdmi.h */
+ else
+ ec = 6; /* Not yet available in hdmi.h */
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * CEA-861-F says that for RGB formats the YCC range must match the
+ * RGB range, although sources should ignore the YCC range.
+ *
+ * The RGB quantization range shouldn't be non-zero if the EDID doesn't
+ * have the Q bit set in the Video Capabilities Data Block, however this
+ * isn't checked at the moment. The assumption is that the application
+ * knows the EDID and can detect this.
+ *
+ * The same is true for the YCC quantization range: non-standard YCC
+ * quantization ranges should only be sent if the EDID has the YQ bit
+ * set in the Video Capabilities Data Block.
+ */
+ switch (format->format.quantization) {
+ case V4L2_QUANTIZATION_FULL_RANGE:
+ q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT :
+ HDMI_QUANTIZATION_RANGE_FULL;
+ yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_FULL;
+ break;
+ case V4L2_QUANTIZATION_LIM_RANGE:
+ q = y ? HDMI_QUANTIZATION_RANGE_DEFAULT :
+ HDMI_QUANTIZATION_RANGE_LIMITED;
+ yq = q ? q - 1 : HDMI_YCC_QUANTIZATION_RANGE_LIMITED;
+ break;
+ }
+
+ adv7511_wr_and_or(sd, 0x4a, 0xbf, 0);
+ adv7511_wr_and_or(sd, 0x55, 0x9f, y << 5);
+ adv7511_wr_and_or(sd, 0x56, 0x3f, c << 6);
+ adv7511_wr_and_or(sd, 0x57, 0x83, (ec << 4) | (q << 2));
+ adv7511_wr_and_or(sd, 0x59, 0x0f, yq << 4);
+ adv7511_wr_and_or(sd, 0x4a, 0xff, 1);
+
return 0;
}
static const struct v4l2_subdev_pad_ops adv7511_pad_ops = {
.get_edid = adv7511_get_edid,
+ .enum_mbus_code = adv7511_enum_mbus_code,
+ .get_fmt = adv7511_get_fmt,
+ .set_fmt = adv7511_set_fmt,
.enum_dv_timings = adv7511_enum_dv_timings,
.dv_timings_cap = adv7511_dv_timings_cap,
};
@@ -1116,6 +1329,8 @@ static int adv7511_probe(struct i2c_client *client, const struct i2c_device_id *
return -ENODEV;
}
memcpy(&state->pdata, pdata, sizeof(state->pdata));
+ state->fmt_code = MEDIA_BUS_FMT_RGB888_1X24;
+ state->colorspace = V4L2_COLORSPACE_SRGB;
sd = &state->sd;
diff --git a/drivers/media/i2c/adv7604.c b/drivers/media/i2c/adv7604.c
index 47795ff..e43dd2e 100644
--- a/drivers/media/i2c/adv7604.c
+++ b/drivers/media/i2c/adv7604.c
@@ -88,7 +88,7 @@ struct adv7604_reg_seq {
};
struct adv7604_format_info {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
u8 op_ch_sel;
bool rgb_out;
bool swap_cb_cr;
@@ -749,77 +749,77 @@ static void adv7604_write_reg_seq(struct v4l2_subdev *sd,
*/
static const struct adv7604_format_info adv7604_formats[] = {
- { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
+ { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV10_2X10, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
- { V4L2_MBUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU10_2X10, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_10BIT },
- { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
+ { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
+ { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false,
+ { MEDIA_BUS_FMT_UYVY10_1X20, ADV7604_OP_CH_SEL_RBG, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { V4L2_MBUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true,
+ { MEDIA_BUS_FMT_VYUY10_1X20, ADV7604_OP_CH_SEL_RBG, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { V4L2_MBUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV10_1X20, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { V4L2_MBUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU10_1X20, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_10BIT },
- { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
+ { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
+ { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
};
static const struct adv7604_format_info adv7611_formats[] = {
- { V4L2_MBUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
+ { MEDIA_BUS_FMT_RGB888_1X24, ADV7604_OP_CH_SEL_RGB, true, false,
ADV7604_OP_MODE_SEL_SDR_444 | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV8_2X8, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU8_2X8, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV12_2X12, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU12_2X12, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422 | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
+ { MEDIA_BUS_FMT_UYVY8_1X16, ADV7604_OP_CH_SEL_RBG, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
+ { MEDIA_BUS_FMT_VYUY8_1X16, ADV7604_OP_CH_SEL_RBG, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV8_1X16, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU8_1X16, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_8BIT },
- { V4L2_MBUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
+ { MEDIA_BUS_FMT_UYVY12_1X24, ADV7604_OP_CH_SEL_RBG, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
+ { MEDIA_BUS_FMT_VYUY12_1X24, ADV7604_OP_CH_SEL_RBG, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
+ { MEDIA_BUS_FMT_YUYV12_1X24, ADV7604_OP_CH_SEL_RGB, false, false,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
- { V4L2_MBUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true,
+ { MEDIA_BUS_FMT_YVYU12_1X24, ADV7604_OP_CH_SEL_RGB, false, true,
ADV7604_OP_MODE_SEL_SDR_422_2X | ADV7604_OP_FORMAT_SEL_12BIT },
};
static const struct adv7604_format_info *
-adv7604_format_info(struct adv7604_state *state, enum v4l2_mbus_pixelcode code)
+adv7604_format_info(struct adv7604_state *state, u32 code)
{
unsigned int i;
@@ -1917,7 +1917,7 @@ static int adv7604_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
info = adv7604_format_info(state, format->format.code);
if (info == NULL)
- info = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8);
+ info = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
adv7604_fill_format(state, &format->format);
format->format.code = info->code;
@@ -1997,19 +1997,7 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
struct adv7604_state *state = to_state(sd);
u8 *data = NULL;
- if (edid->pad > ADV7604_PAD_HDMI_PORT_D)
- return -EINVAL;
- if (edid->blocks == 0)
- return -EINVAL;
- if (edid->blocks > 2)
- return -EINVAL;
- if (edid->start_block > 1)
- return -EINVAL;
- if (edid->start_block == 1)
- edid->blocks = 1;
-
- if (edid->blocks > state->edid.blocks)
- edid->blocks = state->edid.blocks;
+ memset(edid->reserved, 0, sizeof(edid->reserved));
switch (edid->pad) {
case ADV7604_PAD_HDMI_PORT_A:
@@ -2021,14 +2009,24 @@ static int adv7604_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
break;
default:
return -EINVAL;
- break;
}
- if (!data)
+
+ if (edid->start_block == 0 && edid->blocks == 0) {
+ edid->blocks = data ? state->edid.blocks : 0;
+ return 0;
+ }
+
+ if (data == NULL)
return -ENODATA;
- memcpy(edid->edid,
- data + edid->start_block * 128,
- edid->blocks * 128);
+ if (edid->start_block >= state->edid.blocks)
+ return -EINVAL;
+
+ if (edid->start_block + edid->blocks > state->edid.blocks)
+ edid->blocks = state->edid.blocks - edid->start_block;
+
+ memcpy(edid->edid, data + edid->start_block * 128, edid->blocks * 128);
+
return 0;
}
@@ -2068,6 +2066,8 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
int err;
int i;
+ memset(edid->reserved, 0, sizeof(edid->reserved));
+
if (edid->pad > ADV7604_PAD_HDMI_PORT_D)
return -EINVAL;
if (edid->start_block != 0)
@@ -2164,7 +2164,6 @@ static int adv7604_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
return -EIO;
}
-
/* enable hotplug after 100 ms */
queue_delayed_work(state->work_queues,
&state->delayed_work_enable_hotplug, HZ / 10);
@@ -2807,7 +2806,7 @@ static int adv7604_probe(struct i2c_client *client,
}
state->timings = cea640x480;
- state->format = adv7604_format_info(state, V4L2_MBUS_FMT_YUYV8_2X8);
+ state->format = adv7604_format_info(state, MEDIA_BUS_FMT_YUYV8_2X8);
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &adv7604_ops);
diff --git a/drivers/media/i2c/adv7842.c b/drivers/media/i2c/adv7842.c
index 48b628b..75d26df 100644
--- a/drivers/media/i2c/adv7842.c
+++ b/drivers/media/i2c/adv7842.c
@@ -1877,12 +1877,12 @@ static int adv7842_s_routing(struct v4l2_subdev *sd,
}
static int adv7842_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index)
return -EINVAL;
/* Good enough for now */
- *code = V4L2_MBUS_FMT_FIXED;
+ *code = MEDIA_BUS_FMT_FIXED;
return 0;
}
@@ -1893,7 +1893,7 @@ static int adv7842_g_mbus_fmt(struct v4l2_subdev *sd,
fmt->width = state->timings.bt.width;
fmt->height = state->timings.bt.height;
- fmt->code = V4L2_MBUS_FMT_FIXED;
+ fmt->code = MEDIA_BUS_FMT_FIXED;
fmt->field = V4L2_FIELD_NONE;
if (state->mode == ADV7842_MODE_SDP) {
@@ -2028,16 +2028,7 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
struct adv7842_state *state = to_state(sd);
u8 *data = NULL;
- if (edid->pad > ADV7842_EDID_PORT_VGA)
- return -EINVAL;
- if (edid->blocks == 0)
- return -EINVAL;
- if (edid->blocks > 2)
- return -EINVAL;
- if (edid->start_block > 1)
- return -EINVAL;
- if (edid->start_block == 1)
- edid->blocks = 1;
+ memset(edid->reserved, 0, sizeof(edid->reserved));
switch (edid->pad) {
case ADV7842_EDID_PORT_A:
@@ -2052,12 +2043,23 @@ static int adv7842_get_edid(struct v4l2_subdev *sd, struct v4l2_edid *edid)
default:
return -EINVAL;
}
+
+ if (edid->start_block == 0 && edid->blocks == 0) {
+ edid->blocks = data ? 2 : 0;
+ return 0;
+ }
+
if (!data)
return -ENODATA;
- memcpy(edid->edid,
- data + edid->start_block * 128,
- edid->blocks * 128);
+ if (edid->start_block >= 2)
+ return -EINVAL;
+
+ if (edid->start_block + edid->blocks > 2)
+ edid->blocks = 2 - edid->start_block;
+
+ memcpy(edid->edid, data + edid->start_block * 128, edid->blocks * 128);
+
return 0;
}
@@ -2066,12 +2068,16 @@ static int adv7842_set_edid(struct v4l2_subdev *sd, struct v4l2_edid *e)
struct adv7842_state *state = to_state(sd);
int err = 0;
+ memset(e->reserved, 0, sizeof(e->reserved));
+
if (e->pad > ADV7842_EDID_PORT_VGA)
return -EINVAL;
if (e->start_block != 0)
return -EINVAL;
- if (e->blocks > 2)
+ if (e->blocks > 2) {
+ e->blocks = 2;
return -E2BIG;
+ }
/* todo, per edid */
state->aspect_ratio = v4l2_calc_aspect_ratio(e->edid[0x15],
diff --git a/drivers/media/i2c/ak881x.c b/drivers/media/i2c/ak881x.c
index c14e667..69aeaf3 100644
--- a/drivers/media/i2c/ak881x.c
+++ b/drivers/media/i2c/ak881x.c
@@ -102,7 +102,7 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 0, 720, 2,
&mf->height, 0, ak881x->lines, 1, 0);
mf->field = V4L2_FIELD_INTERLACED;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
@@ -112,19 +112,19 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
if (mf->field != V4L2_FIELD_INTERLACED ||
- mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
+ mf->code != MEDIA_BUS_FMT_YUYV8_2X8)
return -EINVAL;
return ak881x_try_g_mbus_fmt(sd, mf);
}
static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8;
+ *code = MEDIA_BUS_FMT_YUYV8_2X8;
return 0;
}
diff --git a/drivers/media/i2c/cx25840/cx25840-core.c b/drivers/media/i2c/cx25840/cx25840-core.c
index e453a3f..573e088 100644
--- a/drivers/media/i2c/cx25840/cx25840-core.c
+++ b/drivers/media/i2c/cx25840/cx25840-core.c
@@ -879,7 +879,7 @@ void cx25840_std_setup(struct i2c_client *client)
/* Sets horizontal blanking delay and active lines */
cx25840_write(client, 0x470, hblank);
cx25840_write(client, 0x471,
- 0xff & (((hblank >> 8) & 0x3) | (hactive << 4)));
+ (((hblank >> 8) & 0x3) | (hactive << 4)) & 0xff);
cx25840_write(client, 0x472, hactive >> 4);
/* Sets burst gate delay */
@@ -888,13 +888,13 @@ void cx25840_std_setup(struct i2c_client *client)
/* Sets vertical blanking delay and active duration */
cx25840_write(client, 0x474, vblank);
cx25840_write(client, 0x475,
- 0xff & (((vblank >> 8) & 0x3) | (vactive << 4)));
+ (((vblank >> 8) & 0x3) | (vactive << 4)) & 0xff);
cx25840_write(client, 0x476, vactive >> 4);
cx25840_write(client, 0x477, vblank656);
/* Sets src decimation rate */
- cx25840_write(client, 0x478, 0xff & src_decimation);
- cx25840_write(client, 0x479, 0xff & (src_decimation >> 8));
+ cx25840_write(client, 0x478, src_decimation & 0xff);
+ cx25840_write(client, 0x479, (src_decimation >> 8) & 0xff);
/* Sets Luma and UV Low pass filters */
cx25840_write(client, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
@@ -904,8 +904,8 @@ void cx25840_std_setup(struct i2c_client *client)
/* Sets SC Step*/
cx25840_write(client, 0x47c, sc);
- cx25840_write(client, 0x47d, 0xff & sc >> 8);
- cx25840_write(client, 0x47e, 0xff & sc >> 16);
+ cx25840_write(client, 0x47d, (sc >> 8) & 0xff);
+ cx25840_write(client, 0x47e, (sc >> 16) & 0xff);
/* Sets VBI parameters */
if (std & V4L2_STD_625_50) {
@@ -1373,7 +1373,7 @@ static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
int is_50Hz = !(state->std & V4L2_STD_525_60);
- if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ if (fmt->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
fmt->field = V4L2_FIELD_INTERLACED;
diff --git a/drivers/media/i2c/cx25840/cx25840-firmware.c b/drivers/media/i2c/cx25840/cx25840-firmware.c
index b3169f9..9bbb31a 100644
--- a/drivers/media/i2c/cx25840/cx25840-firmware.c
+++ b/drivers/media/i2c/cx25840/cx25840-firmware.c
@@ -113,7 +113,7 @@ int cx25840_loadfw(struct i2c_client *client)
const u8 *ptr;
const char *fwname = get_fw_name(client);
int size, retval;
- int MAX_BUF_SIZE = FWSEND;
+ int max_buf_size = FWSEND;
u32 gpio_oe = 0, gpio_da = 0;
if (is_cx2388x(state)) {
@@ -122,10 +122,9 @@ int cx25840_loadfw(struct i2c_client *client)
gpio_da = cx25840_read(client, 0x164);
}
- if (is_cx231xx(state) && MAX_BUF_SIZE > 16) {
- v4l_err(client, " Firmware download size changed to 16 bytes max length\n");
- MAX_BUF_SIZE = 16; /* cx231xx cannot accept more than 16 bytes at a time */
- }
+ /* cx231xx cannot accept more than 16 bytes at a time */
+ if (is_cx231xx(state) && max_buf_size > 16)
+ max_buf_size = 16;
if (request_firmware(&fw, fwname, FWDEV(client)) != 0) {
v4l_err(client, "unable to open firmware %s\n", fwname);
@@ -140,7 +139,7 @@ int cx25840_loadfw(struct i2c_client *client)
size = fw->size;
ptr = fw->data;
while (size > 0) {
- int len = min(MAX_BUF_SIZE - 2, size);
+ int len = min(max_buf_size - 2, size);
memcpy(buffer + 2, ptr, len);
diff --git a/drivers/media/i2c/ir-kbd-i2c.c b/drivers/media/i2c/ir-kbd-i2c.c
index 8311f1a..175a761 100644
--- a/drivers/media/i2c/ir-kbd-i2c.c
+++ b/drivers/media/i2c/ir-kbd-i2c.c
@@ -464,8 +464,7 @@ static int ir_remove(struct i2c_client *client)
cancel_delayed_work_sync(&ir->work);
/* unregister device */
- if (ir->rc)
- rc_unregister_device(ir->rc);
+ rc_unregister_device(ir->rc);
/* free memory */
return 0;
diff --git a/drivers/media/i2c/m5mols/m5mols_core.c b/drivers/media/i2c/m5mols/m5mols_core.c
index 8d870b7..2820f7c 100644
--- a/drivers/media/i2c/m5mols/m5mols_core.c
+++ b/drivers/media/i2c/m5mols/m5mols_core.c
@@ -57,14 +57,14 @@ static struct v4l2_mbus_framefmt m5mols_default_ffmt[M5MOLS_RESTYPE_MAX] = {
[M5MOLS_RESTYPE_MONITOR] = {
.width = 1920,
.height = 1080,
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_JPEG,
},
[M5MOLS_RESTYPE_CAPTURE] = {
.width = 1920,
.height = 1080,
- .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .code = MEDIA_BUS_FMT_JPEG_1X8,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_JPEG,
},
@@ -479,7 +479,7 @@ static int m5mols_get_version(struct v4l2_subdev *sd)
* __find_restype - Lookup M-5MOLS resolution type according to pixel code
* @code: pixel code
*/
-static enum m5mols_restype __find_restype(enum v4l2_mbus_pixelcode code)
+static enum m5mols_restype __find_restype(u32 code)
{
enum m5mols_restype type = M5MOLS_RESTYPE_MONITOR;
diff --git a/drivers/media/i2c/ml86v7667.c b/drivers/media/i2c/ml86v7667.c
index 2cace73..d730786 100644
--- a/drivers/media/i2c/ml86v7667.c
+++ b/drivers/media/i2c/ml86v7667.c
@@ -192,12 +192,12 @@ static int ml86v7667_g_input_status(struct v4l2_subdev *sd, u32 *status)
}
static int ml86v7667_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index > 0)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8;
+ *code = MEDIA_BUS_FMT_YUYV8_2X8;
return 0;
}
@@ -207,7 +207,7 @@ static int ml86v7667_mbus_fmt(struct v4l2_subdev *sd,
{
struct ml86v7667_priv *priv = to_ml86v7667(sd);
- fmt->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt->code = MEDIA_BUS_FMT_YUYV8_2X8;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
/* The top field is always transferred first by the chip */
fmt->field = V4L2_FIELD_INTERLACED_TB;
diff --git a/drivers/media/i2c/mt9m032.c b/drivers/media/i2c/mt9m032.c
index 85ec3ba..45b3fca 100644
--- a/drivers/media/i2c/mt9m032.c
+++ b/drivers/media/i2c/mt9m032.c
@@ -323,7 +323,7 @@ static int mt9m032_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index != 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_Y8_1X8;
+ code->code = MEDIA_BUS_FMT_Y8_1X8;
return 0;
}
@@ -331,7 +331,7 @@ static int mt9m032_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse)
{
- if (fse->index != 0 || fse->code != V4L2_MBUS_FMT_Y8_1X8)
+ if (fse->index != 0 || fse->code != MEDIA_BUS_FMT_Y8_1X8)
return -EINVAL;
fse->min_width = MT9M032_COLUMN_SIZE_DEF;
@@ -759,7 +759,7 @@ static int mt9m032_probe(struct i2c_client *client,
sensor->format.width = sensor->crop.width;
sensor->format.height = sensor->crop.height;
- sensor->format.code = V4L2_MBUS_FMT_Y8_1X8;
+ sensor->format.code = MEDIA_BUS_FMT_Y8_1X8;
sensor->format.field = V4L2_FIELD_NONE;
sensor->format.colorspace = V4L2_COLORSPACE_SRGB;
diff --git a/drivers/media/i2c/mt9p031.c b/drivers/media/i2c/mt9p031.c
index e18797f..edb76bd 100644
--- a/drivers/media/i2c/mt9p031.c
+++ b/drivers/media/i2c/mt9p031.c
@@ -950,9 +950,9 @@ static int mt9p031_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
format = v4l2_subdev_get_try_format(fh, 0);
if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
- format->code = V4L2_MBUS_FMT_Y12_1X12;
+ format->code = MEDIA_BUS_FMT_Y12_1X12;
else
- format->code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ format->code = MEDIA_BUS_FMT_SGRBG12_1X12;
format->width = MT9P031_WINDOW_WIDTH_DEF;
format->height = MT9P031_WINDOW_HEIGHT_DEF;
@@ -1120,9 +1120,9 @@ static int mt9p031_probe(struct i2c_client *client,
mt9p031->crop.top = MT9P031_ROW_START_DEF;
if (mt9p031->model == MT9P031_MODEL_MONOCHROME)
- mt9p031->format.code = V4L2_MBUS_FMT_Y12_1X12;
+ mt9p031->format.code = MEDIA_BUS_FMT_Y12_1X12;
else
- mt9p031->format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ mt9p031->format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
mt9p031->format.width = MT9P031_WINDOW_WIDTH_DEF;
mt9p031->format.height = MT9P031_WINDOW_HEIGHT_DEF;
diff --git a/drivers/media/i2c/mt9t001.c b/drivers/media/i2c/mt9t001.c
index 422e068..d9e9889 100644
--- a/drivers/media/i2c/mt9t001.c
+++ b/drivers/media/i2c/mt9t001.c
@@ -333,7 +333,7 @@ static int mt9t001_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index > 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
return 0;
}
@@ -341,7 +341,7 @@ static int mt9t001_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse)
{
- if (fse->index >= 8 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+ if (fse->index >= 8 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
return -EINVAL;
fse->min_width = (MT9T001_WINDOW_WIDTH_DEF + 1) / fse->index;
@@ -792,7 +792,7 @@ static int mt9t001_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
crop->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
format = v4l2_subdev_get_try_format(fh, 0);
- format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
format->width = MT9T001_WINDOW_WIDTH_DEF + 1;
format->height = MT9T001_WINDOW_HEIGHT_DEF + 1;
format->field = V4L2_FIELD_NONE;
@@ -917,7 +917,7 @@ static int mt9t001_probe(struct i2c_client *client,
mt9t001->crop.width = MT9T001_WINDOW_WIDTH_DEF + 1;
mt9t001->crop.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
- mt9t001->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ mt9t001->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
mt9t001->format.width = MT9T001_WINDOW_WIDTH_DEF + 1;
mt9t001->format.height = MT9T001_WINDOW_HEIGHT_DEF + 1;
mt9t001->format.field = V4L2_FIELD_NONE;
diff --git a/drivers/media/i2c/mt9v011.c b/drivers/media/i2c/mt9v011.c
index 47e4753..a10f7f8 100644
--- a/drivers/media/i2c/mt9v011.c
+++ b/drivers/media/i2c/mt9v011.c
@@ -325,18 +325,18 @@ static int mt9v011_reset(struct v4l2_subdev *sd, u32 val)
}
static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index > 0)
return -EINVAL;
- *code = V4L2_MBUS_FMT_SGRBG8_1X8;
+ *code = MEDIA_BUS_FMT_SGRBG8_1X8;
return 0;
}
static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8)
+ if (fmt->code != MEDIA_BUS_FMT_SGRBG8_1X8)
return -EINVAL;
v4l_bound_align_image(&fmt->width, 48, 639, 1,
diff --git a/drivers/media/i2c/mt9v032.c b/drivers/media/i2c/mt9v032.c
index d044bce..93687c1 100644
--- a/drivers/media/i2c/mt9v032.c
+++ b/drivers/media/i2c/mt9v032.c
@@ -454,7 +454,7 @@ static int mt9v032_enum_mbus_code(struct v4l2_subdev *subdev,
if (code->index > 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ code->code = MEDIA_BUS_FMT_SGRBG10_1X10;
return 0;
}
@@ -462,7 +462,7 @@ static int mt9v032_enum_frame_size(struct v4l2_subdev *subdev,
struct v4l2_subdev_fh *fh,
struct v4l2_subdev_frame_size_enum *fse)
{
- if (fse->index >= 3 || fse->code != V4L2_MBUS_FMT_SGRBG10_1X10)
+ if (fse->index >= 3 || fse->code != MEDIA_BUS_FMT_SGRBG10_1X10)
return -EINVAL;
fse->min_width = MT9V032_WINDOW_WIDTH_DEF / (1 << fse->index);
@@ -814,9 +814,9 @@ static int mt9v032_open(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh)
format = v4l2_subdev_get_try_format(fh, 0);
if (mt9v032->model->color)
- format->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format->code = MEDIA_BUS_FMT_SGRBG10_1X10;
else
- format->code = V4L2_MBUS_FMT_Y10_1X10;
+ format->code = MEDIA_BUS_FMT_Y10_1X10;
format->width = MT9V032_WINDOW_WIDTH_DEF;
format->height = MT9V032_WINDOW_HEIGHT_DEF;
@@ -966,9 +966,9 @@ static int mt9v032_probe(struct i2c_client *client,
mt9v032->crop.height = MT9V032_WINDOW_HEIGHT_DEF;
if (mt9v032->model->color)
- mt9v032->format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ mt9v032->format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
else
- mt9v032->format.code = V4L2_MBUS_FMT_Y10_1X10;
+ mt9v032->format.code = MEDIA_BUS_FMT_Y10_1X10;
mt9v032->format.width = MT9V032_WINDOW_WIDTH_DEF;
mt9v032->format.height = MT9V032_WINDOW_HEIGHT_DEF;
diff --git a/drivers/media/i2c/noon010pc30.c b/drivers/media/i2c/noon010pc30.c
index 7eae487..00c7b26 100644
--- a/drivers/media/i2c/noon010pc30.c
+++ b/drivers/media/i2c/noon010pc30.c
@@ -112,7 +112,7 @@ MODULE_PARM_DESC(debug, "Enable module debug trace. Set to 1 to enable.");
#define REG_TERM 0xFFFF
struct noon010_format {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
u16 ispctl1_reg;
};
@@ -175,23 +175,23 @@ static const struct noon010_frmsize noon010_sizes[] = {
/* Supported pixel formats. */
static const struct noon010_format noon010_formats[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x03,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x02,
}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0,
}, {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x01,
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x40,
},
diff --git a/drivers/media/i2c/ov7670.c b/drivers/media/i2c/ov7670.c
index dd3db24..957927f 100644
--- a/drivers/media/i2c/ov7670.c
+++ b/drivers/media/i2c/ov7670.c
@@ -632,31 +632,31 @@ static int ov7670_detect(struct v4l2_subdev *sd)
* The magic matrix numbers come from OmniVision.
*/
static struct ov7670_format_struct {
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
enum v4l2_colorspace colorspace;
struct regval_list *regs;
int cmatrix[CMATRIX_LEN];
} ov7670_formats[] = {
{
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.regs = ov7670_fmt_yuv422,
.cmatrix = { 128, -128, 0, -34, -94, 128 },
},
{
- .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.regs = ov7670_fmt_rgb444,
.cmatrix = { 179, -179, 0, -61, -176, 228 },
},
{
- .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.regs = ov7670_fmt_rgb565,
.cmatrix = { 179, -179, 0, -61, -176, 228 },
},
{
- .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
.colorspace = V4L2_COLORSPACE_SRGB,
.regs = ov7670_fmt_raw,
.cmatrix = { 0, 0, 0, 0, 0, 0 },
@@ -772,7 +772,7 @@ static void ov7675_get_framerate(struct v4l2_subdev *sd,
pll_factor = PLL_FACTOR;
clkrc++;
- if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8)
clkrc = (clkrc >> 1);
tpf->numerator = 1;
@@ -810,7 +810,7 @@ static int ov7675_set_framerate(struct v4l2_subdev *sd,
} else {
clkrc = (5 * pll_factor * info->clock_speed * tpf->numerator) /
(4 * tpf->denominator);
- if (info->fmt->mbus_code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ if (info->fmt->mbus_code == MEDIA_BUS_FMT_SBGGR8_1X8)
clkrc = (clkrc << 1);
clkrc--;
}
@@ -900,7 +900,7 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= N_OV7670_FMTS)
return -EINVAL;
diff --git a/drivers/media/i2c/ov9650.c b/drivers/media/i2c/ov9650.c
index 4da90c6..2246bd5 100644
--- a/drivers/media/i2c/ov9650.c
+++ b/drivers/media/i2c/ov9650.c
@@ -384,17 +384,17 @@ static const struct ov965x_framesize ov965x_framesizes[] = {
};
struct ov965x_pixfmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
u32 colorspace;
/* REG_TSLB value, only bits [3:2] may be set. */
u8 tslb_reg;
};
static const struct ov965x_pixfmt ov965x_formats[] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 0x00},
- { V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG, 0x04},
- { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG, 0x0c},
- { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 0x08},
+ { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 0x00},
+ { MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG, 0x04},
+ { MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG, 0x0c},
+ { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 0x08},
};
/*
diff --git a/drivers/media/i2c/s5c73m3/s5c73m3.h b/drivers/media/i2c/s5c73m3/s5c73m3.h
index 9656b67..13aed59 100644
--- a/drivers/media/i2c/s5c73m3/s5c73m3.h
+++ b/drivers/media/i2c/s5c73m3/s5c73m3.h
@@ -27,8 +27,8 @@
#define DRIVER_NAME "S5C73M3"
-#define S5C73M3_ISP_FMT V4L2_MBUS_FMT_VYUY8_2X8
-#define S5C73M3_JPEG_FMT V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8
+#define S5C73M3_ISP_FMT MEDIA_BUS_FMT_VYUY8_2X8
+#define S5C73M3_JPEG_FMT MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8
/* Subdevs pad index definitions */
enum s5c73m3_pads {
@@ -402,7 +402,7 @@ struct s5c73m3 {
const struct s5c73m3_frame_size *sensor_pix_size[2];
const struct s5c73m3_frame_size *oif_pix_size[2];
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
const struct s5c73m3_interval *fiv;
diff --git a/drivers/media/i2c/s5k4ecgx.c b/drivers/media/i2c/s5k4ecgx.c
index 1fcc76f..d1c50c9 100644
--- a/drivers/media/i2c/s5k4ecgx.c
+++ b/drivers/media/i2c/s5k4ecgx.c
@@ -151,7 +151,7 @@ static const struct s5k4ecgx_frmsize s5k4ecgx_prev_sizes[] = {
#define S5K4ECGX_NUM_PREV ARRAY_SIZE(s5k4ecgx_prev_sizes)
struct s5k4ecgx_pixfmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
u32 colorspace;
/* REG_TC_PCFG_Format register value */
u16 reg_p_format;
@@ -159,7 +159,7 @@ struct s5k4ecgx_pixfmt {
/* By default value, output from sensor will be YUV422 0-255 */
static const struct s5k4ecgx_pixfmt s5k4ecgx_formats[] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
+ { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
};
static const char * const s5k4ecgx_supply_names[] = {
diff --git a/drivers/media/i2c/s5k5baf.c b/drivers/media/i2c/s5k5baf.c
index 0e461a6..60a74d8 100644
--- a/drivers/media/i2c/s5k5baf.c
+++ b/drivers/media/i2c/s5k5baf.c
@@ -248,7 +248,7 @@ enum s5k5baf_gpio_id {
#define NUM_ISP_PADS 2
struct s5k5baf_pixfmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
u32 colorspace;
/* REG_P_FMT(x) register value */
u16 reg_p_fmt;
@@ -331,10 +331,10 @@ struct s5k5baf {
};
static const struct s5k5baf_pixfmt s5k5baf_formats[] = {
- { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 5 },
+ { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG, 5 },
/* range 16-240 */
- { V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_REC709, 6 },
- { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
+ { MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_REC709, 6 },
+ { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
};
static struct v4l2_rect s5k5baf_cis_rect = {
@@ -1206,7 +1206,7 @@ static int s5k5baf_enum_mbus_code(struct v4l2_subdev *sd,
if (code->pad == PAD_CIS) {
if (code->index > 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_FIXED;
+ code->code = MEDIA_BUS_FMT_FIXED;
return 0;
}
@@ -1227,7 +1227,7 @@ static int s5k5baf_enum_frame_size(struct v4l2_subdev *sd,
return -EINVAL;
if (fse->pad == PAD_CIS) {
- fse->code = V4L2_MBUS_FMT_FIXED;
+ fse->code = MEDIA_BUS_FMT_FIXED;
fse->min_width = S5K5BAF_CIS_WIDTH;
fse->max_width = S5K5BAF_CIS_WIDTH;
fse->min_height = S5K5BAF_CIS_HEIGHT;
@@ -1252,7 +1252,7 @@ static void s5k5baf_try_cis_format(struct v4l2_mbus_framefmt *mf)
{
mf->width = S5K5BAF_CIS_WIDTH;
mf->height = S5K5BAF_CIS_HEIGHT;
- mf->code = V4L2_MBUS_FMT_FIXED;
+ mf->code = MEDIA_BUS_FMT_FIXED;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mf->field = V4L2_FIELD_NONE;
}
diff --git a/drivers/media/i2c/s5k6a3.c b/drivers/media/i2c/s5k6a3.c
index c11a408..91b841a 100644
--- a/drivers/media/i2c/s5k6a3.c
+++ b/drivers/media/i2c/s5k6a3.c
@@ -80,7 +80,7 @@ static inline struct s5k6a3 *sd_to_s5k6a3(struct v4l2_subdev *sd)
static const struct v4l2_mbus_framefmt s5k6a3_formats[] = {
{
- .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
.colorspace = V4L2_COLORSPACE_SRGB,
.field = V4L2_FIELD_NONE,
}
diff --git a/drivers/media/i2c/s5k6aa.c b/drivers/media/i2c/s5k6aa.c
index 629a5cd..2851581 100644
--- a/drivers/media/i2c/s5k6aa.c
+++ b/drivers/media/i2c/s5k6aa.c
@@ -191,7 +191,7 @@ struct s5k6aa_regval {
};
struct s5k6aa_pixfmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
u32 colorspace;
/* REG_P_FMT(x) register value */
u16 reg_p_fmt;
@@ -285,10 +285,10 @@ static struct s5k6aa_regval s5k6aa_analog_config[] = {
/* TODO: Add RGB888 and Bayer format */
static const struct s5k6aa_pixfmt s5k6aa_formats[] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
+ { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG, 5 },
/* range 16-240 */
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 },
- { V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
+ { MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_REC709, 6 },
+ { MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_JPEG, 0 },
};
static const struct s5k6aa_interval s5k6aa_intervals[] = {
diff --git a/drivers/media/i2c/saa6752hs.c b/drivers/media/i2c/saa6752hs.c
index 4024ea6..f14c0e6 100644
--- a/drivers/media/i2c/saa6752hs.c
+++ b/drivers/media/i2c/saa6752hs.c
@@ -562,7 +562,7 @@ static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
h->video_format = SAA6752HS_VF_D1;
f->width = v4l2_format_table[h->video_format].fmt.pix.width;
f->height = v4l2_format_table[h->video_format].fmt.pix.height;
- f->code = V4L2_MBUS_FMT_FIXED;
+ f->code = MEDIA_BUS_FMT_FIXED;
f->field = V4L2_FIELD_INTERLACED;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
@@ -572,7 +572,7 @@ static int saa6752hs_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_frame
{
int dist_352, dist_480, dist_720;
- f->code = V4L2_MBUS_FMT_FIXED;
+ f->code = MEDIA_BUS_FMT_FIXED;
dist_352 = abs(f->width - 352);
dist_480 = abs(f->width - 480);
@@ -599,7 +599,7 @@ static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefm
{
struct saa6752hs_state *h = to_state(sd);
- if (f->code != V4L2_MBUS_FMT_FIXED)
+ if (f->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
/*
diff --git a/drivers/media/i2c/saa7115.c b/drivers/media/i2c/saa7115.c
index 35a4464..7147c8b 100644
--- a/drivers/media/i2c/saa7115.c
+++ b/drivers/media/i2c/saa7115.c
@@ -1172,7 +1172,7 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ if (fmt->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
fmt->field = V4L2_FIELD_INTERLACED;
fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
diff --git a/drivers/media/i2c/saa717x.c b/drivers/media/i2c/saa717x.c
index 6922a9f..0d0f9a9 100644
--- a/drivers/media/i2c/saa717x.c
+++ b/drivers/media/i2c/saa717x.c
@@ -998,7 +998,7 @@ static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
v4l2_dbg(1, debug, sd, "decoder set size\n");
- if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ if (fmt->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
/* FIXME need better bounds checking here */
diff --git a/drivers/media/i2c/smiapp-pll.c b/drivers/media/i2c/smiapp-pll.c
index 2335529..e40d902 100644
--- a/drivers/media/i2c/smiapp-pll.c
+++ b/drivers/media/i2c/smiapp-pll.c
@@ -65,26 +65,89 @@ static int bounds_check(struct device *dev, uint32_t val,
static void print_pll(struct device *dev, struct smiapp_pll *pll)
{
- dev_dbg(dev, "pre_pll_clk_div\t%d\n", pll->pre_pll_clk_div);
- dev_dbg(dev, "pll_multiplier \t%d\n", pll->pll_multiplier);
- if (pll->flags != SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
- dev_dbg(dev, "op_sys_clk_div \t%d\n", pll->op_sys_clk_div);
- dev_dbg(dev, "op_pix_clk_div \t%d\n", pll->op_pix_clk_div);
+ dev_dbg(dev, "pre_pll_clk_div\t%u\n", pll->pre_pll_clk_div);
+ dev_dbg(dev, "pll_multiplier \t%u\n", pll->pll_multiplier);
+ if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) {
+ dev_dbg(dev, "op_sys_clk_div \t%u\n", pll->op.sys_clk_div);
+ dev_dbg(dev, "op_pix_clk_div \t%u\n", pll->op.pix_clk_div);
}
- dev_dbg(dev, "vt_sys_clk_div \t%d\n", pll->vt_sys_clk_div);
- dev_dbg(dev, "vt_pix_clk_div \t%d\n", pll->vt_pix_clk_div);
-
- dev_dbg(dev, "ext_clk_freq_hz \t%d\n", pll->ext_clk_freq_hz);
- dev_dbg(dev, "pll_ip_clk_freq_hz \t%d\n", pll->pll_ip_clk_freq_hz);
- dev_dbg(dev, "pll_op_clk_freq_hz \t%d\n", pll->pll_op_clk_freq_hz);
- if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
- dev_dbg(dev, "op_sys_clk_freq_hz \t%d\n",
- pll->op_sys_clk_freq_hz);
- dev_dbg(dev, "op_pix_clk_freq_hz \t%d\n",
- pll->op_pix_clk_freq_hz);
+ dev_dbg(dev, "vt_sys_clk_div \t%u\n", pll->vt.sys_clk_div);
+ dev_dbg(dev, "vt_pix_clk_div \t%u\n", pll->vt.pix_clk_div);
+
+ dev_dbg(dev, "ext_clk_freq_hz \t%u\n", pll->ext_clk_freq_hz);
+ dev_dbg(dev, "pll_ip_clk_freq_hz \t%u\n", pll->pll_ip_clk_freq_hz);
+ dev_dbg(dev, "pll_op_clk_freq_hz \t%u\n", pll->pll_op_clk_freq_hz);
+ if (!(pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)) {
+ dev_dbg(dev, "op_sys_clk_freq_hz \t%u\n",
+ pll->op.sys_clk_freq_hz);
+ dev_dbg(dev, "op_pix_clk_freq_hz \t%u\n",
+ pll->op.pix_clk_freq_hz);
}
- dev_dbg(dev, "vt_sys_clk_freq_hz \t%d\n", pll->vt_sys_clk_freq_hz);
- dev_dbg(dev, "vt_pix_clk_freq_hz \t%d\n", pll->vt_pix_clk_freq_hz);
+ dev_dbg(dev, "vt_sys_clk_freq_hz \t%u\n", pll->vt.sys_clk_freq_hz);
+ dev_dbg(dev, "vt_pix_clk_freq_hz \t%u\n", pll->vt.pix_clk_freq_hz);
+}
+
+static int check_all_bounds(struct device *dev,
+ const struct smiapp_pll_limits *limits,
+ const struct smiapp_pll_branch_limits *op_limits,
+ struct smiapp_pll *pll,
+ struct smiapp_pll_branch *op_pll)
+{
+ int rval;
+
+ rval = bounds_check(dev, pll->pll_ip_clk_freq_hz,
+ limits->min_pll_ip_freq_hz,
+ limits->max_pll_ip_freq_hz,
+ "pll_ip_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_multiplier,
+ limits->min_pll_multiplier, limits->max_pll_multiplier,
+ "pll_multiplier");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->pll_op_clk_freq_hz,
+ limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
+ "pll_op_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, op_pll->sys_clk_div,
+ op_limits->min_sys_clk_div, op_limits->max_sys_clk_div,
+ "op_sys_clk_div");
+ if (!rval)
+ rval = bounds_check(
+ dev, op_pll->sys_clk_freq_hz,
+ op_limits->min_sys_clk_freq_hz,
+ op_limits->max_sys_clk_freq_hz,
+ "op_sys_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, op_pll->pix_clk_freq_hz,
+ op_limits->min_pix_clk_freq_hz,
+ op_limits->max_pix_clk_freq_hz,
+ "op_pix_clk_freq_hz");
+
+ /*
+ * If there are no OP clocks, the VT clocks are contained in
+ * the OP clock struct.
+ */
+ if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS)
+ return rval;
+
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->vt.sys_clk_freq_hz,
+ limits->vt.min_sys_clk_freq_hz,
+ limits->vt.max_sys_clk_freq_hz,
+ "vt_sys_clk_freq_hz");
+ if (!rval)
+ rval = bounds_check(
+ dev, pll->vt.pix_clk_freq_hz,
+ limits->vt.min_pix_clk_freq_hz,
+ limits->vt.max_pix_clk_freq_hz,
+ "vt_pix_clk_freq_hz");
+
+ return rval;
}
/*
@@ -98,10 +161,11 @@ static void print_pll(struct device *dev, struct smiapp_pll *pll)
*
* @return Zero on success, error code on error.
*/
-static int __smiapp_pll_calculate(struct device *dev,
- const struct smiapp_pll_limits *limits,
- struct smiapp_pll *pll, uint32_t mul,
- uint32_t div, uint32_t lane_op_clock_ratio)
+static int __smiapp_pll_calculate(
+ struct device *dev, const struct smiapp_pll_limits *limits,
+ const struct smiapp_pll_branch_limits *op_limits,
+ struct smiapp_pll *pll, struct smiapp_pll_branch *op_pll, uint32_t mul,
+ uint32_t div, uint32_t lane_op_clock_ratio)
{
uint32_t sys_div;
uint32_t best_pix_div = INT_MAX >> 1;
@@ -117,17 +181,16 @@ static int __smiapp_pll_calculate(struct device *dev,
uint32_t min_vt_div, max_vt_div, vt_div;
uint32_t min_sys_div, max_sys_div;
unsigned int i;
- int rval;
/*
* Get pre_pll_clk_div so that our pll_op_clk_freq_hz won't be
* too high.
*/
- dev_dbg(dev, "pre_pll_clk_div %d\n", pll->pre_pll_clk_div);
+ dev_dbg(dev, "pre_pll_clk_div %u\n", pll->pre_pll_clk_div);
/* Don't go above max pll multiplier. */
more_mul_max = limits->max_pll_multiplier / mul;
- dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %d\n",
+ dev_dbg(dev, "more_mul_max: max_pll_multiplier check: %u\n",
more_mul_max);
/* Don't go above max pll op frequency. */
more_mul_max =
@@ -135,30 +198,30 @@ static int __smiapp_pll_calculate(struct device *dev,
more_mul_max,
limits->max_pll_op_freq_hz
/ (pll->ext_clk_freq_hz / pll->pre_pll_clk_div * mul));
- dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %d\n",
+ dev_dbg(dev, "more_mul_max: max_pll_op_freq_hz check: %u\n",
more_mul_max);
/* Don't go above the division capability of op sys clock divider. */
more_mul_max = min(more_mul_max,
- limits->op.max_sys_clk_div * pll->pre_pll_clk_div
+ op_limits->max_sys_clk_div * pll->pre_pll_clk_div
/ div);
- dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %d\n",
+ dev_dbg(dev, "more_mul_max: max_op_sys_clk_div check: %u\n",
more_mul_max);
/* Ensure we won't go above min_pll_multiplier. */
more_mul_max = min(more_mul_max,
DIV_ROUND_UP(limits->max_pll_multiplier, mul));
- dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %d\n",
+ dev_dbg(dev, "more_mul_max: min_pll_multiplier check: %u\n",
more_mul_max);
/* Ensure we won't go below min_pll_op_freq_hz. */
more_mul_min = DIV_ROUND_UP(limits->min_pll_op_freq_hz,
pll->ext_clk_freq_hz / pll->pre_pll_clk_div
* mul);
- dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %d\n",
+ dev_dbg(dev, "more_mul_min: min_pll_op_freq_hz check: %u\n",
more_mul_min);
/* Ensure we won't go below min_pll_multiplier. */
more_mul_min = max(more_mul_min,
DIV_ROUND_UP(limits->min_pll_multiplier, mul));
- dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %d\n",
+ dev_dbg(dev, "more_mul_min: min_pll_multiplier check: %u\n",
more_mul_min);
if (more_mul_min > more_mul_max) {
@@ -168,23 +231,23 @@ static int __smiapp_pll_calculate(struct device *dev,
}
more_mul_factor = lcm(div, pll->pre_pll_clk_div) / div;
- dev_dbg(dev, "more_mul_factor: %d\n", more_mul_factor);
- more_mul_factor = lcm(more_mul_factor, limits->op.min_sys_clk_div);
+ dev_dbg(dev, "more_mul_factor: %u\n", more_mul_factor);
+ more_mul_factor = lcm(more_mul_factor, op_limits->min_sys_clk_div);
dev_dbg(dev, "more_mul_factor: min_op_sys_clk_div: %d\n",
more_mul_factor);
i = roundup(more_mul_min, more_mul_factor);
if (!is_one_or_even(i))
i <<= 1;
- dev_dbg(dev, "final more_mul: %d\n", i);
+ dev_dbg(dev, "final more_mul: %u\n", i);
if (i > more_mul_max) {
- dev_dbg(dev, "final more_mul is bad, max %d\n", more_mul_max);
+ dev_dbg(dev, "final more_mul is bad, max %u\n", more_mul_max);
return -EINVAL;
}
pll->pll_multiplier = mul * i;
- pll->op_sys_clk_div = div * i / pll->pre_pll_clk_div;
- dev_dbg(dev, "op_sys_clk_div: %d\n", pll->op_sys_clk_div);
+ op_pll->sys_clk_div = div * i / pll->pre_pll_clk_div;
+ dev_dbg(dev, "op_sys_clk_div: %u\n", op_pll->sys_clk_div);
pll->pll_ip_clk_freq_hz = pll->ext_clk_freq_hz
/ pll->pre_pll_clk_div;
@@ -193,14 +256,19 @@ static int __smiapp_pll_calculate(struct device *dev,
* pll->pll_multiplier;
/* Derive pll_op_clk_freq_hz. */
- pll->op_sys_clk_freq_hz =
- pll->pll_op_clk_freq_hz / pll->op_sys_clk_div;
+ op_pll->sys_clk_freq_hz =
+ pll->pll_op_clk_freq_hz / op_pll->sys_clk_div;
+
+ op_pll->pix_clk_div = pll->bits_per_pixel;
+ dev_dbg(dev, "op_pix_clk_div: %u\n", op_pll->pix_clk_div);
- pll->op_pix_clk_div = pll->bits_per_pixel;
- dev_dbg(dev, "op_pix_clk_div: %d\n", pll->op_pix_clk_div);
+ op_pll->pix_clk_freq_hz =
+ op_pll->sys_clk_freq_hz / op_pll->pix_clk_div;
- pll->op_pix_clk_freq_hz =
- pll->op_sys_clk_freq_hz / pll->op_pix_clk_div;
+ if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+ /* No OP clocks --- VT clocks are used instead. */
+ goto out_skip_vt_calc;
+ }
/*
* Some sensors perform analogue binning and some do this
@@ -214,7 +282,7 @@ static int __smiapp_pll_calculate(struct device *dev,
vt_op_binning_div = pll->binning_horizontal;
else
vt_op_binning_div = 1;
- dev_dbg(dev, "vt_op_binning_div: %d\n", vt_op_binning_div);
+ dev_dbg(dev, "vt_op_binning_div: %u\n", vt_op_binning_div);
/*
* Profile 2 supports vt_pix_clk_div E [4, 10]
@@ -227,30 +295,30 @@ static int __smiapp_pll_calculate(struct device *dev,
*
* Find absolute limits for the factor of vt divider.
*/
- dev_dbg(dev, "scale_m: %d\n", pll->scale_m);
- min_vt_div = DIV_ROUND_UP(pll->op_pix_clk_div * pll->op_sys_clk_div
+ dev_dbg(dev, "scale_m: %u\n", pll->scale_m);
+ min_vt_div = DIV_ROUND_UP(op_pll->pix_clk_div * op_pll->sys_clk_div
* pll->scale_n,
lane_op_clock_ratio * vt_op_binning_div
* pll->scale_m);
/* Find smallest and biggest allowed vt divisor. */
- dev_dbg(dev, "min_vt_div: %d\n", min_vt_div);
+ dev_dbg(dev, "min_vt_div: %u\n", min_vt_div);
min_vt_div = max(min_vt_div,
DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
limits->vt.max_pix_clk_freq_hz));
- dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %d\n",
+ dev_dbg(dev, "min_vt_div: max_vt_pix_clk_freq_hz: %u\n",
min_vt_div);
min_vt_div = max_t(uint32_t, min_vt_div,
limits->vt.min_pix_clk_div
* limits->vt.min_sys_clk_div);
- dev_dbg(dev, "min_vt_div: min_vt_clk_div: %d\n", min_vt_div);
+ dev_dbg(dev, "min_vt_div: min_vt_clk_div: %u\n", min_vt_div);
max_vt_div = limits->vt.max_sys_clk_div * limits->vt.max_pix_clk_div;
- dev_dbg(dev, "max_vt_div: %d\n", max_vt_div);
+ dev_dbg(dev, "max_vt_div: %u\n", max_vt_div);
max_vt_div = min(max_vt_div,
DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
limits->vt.min_pix_clk_freq_hz));
- dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %d\n",
+ dev_dbg(dev, "max_vt_div: min_vt_pix_clk_freq_hz: %u\n",
max_vt_div);
/*
@@ -258,28 +326,28 @@ static int __smiapp_pll_calculate(struct device *dev,
* with all values of pix_clk_div.
*/
min_sys_div = limits->vt.min_sys_clk_div;
- dev_dbg(dev, "min_sys_div: %d\n", min_sys_div);
+ dev_dbg(dev, "min_sys_div: %u\n", min_sys_div);
min_sys_div = max(min_sys_div,
DIV_ROUND_UP(min_vt_div,
limits->vt.max_pix_clk_div));
- dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %d\n", min_sys_div);
+ dev_dbg(dev, "min_sys_div: max_vt_pix_clk_div: %u\n", min_sys_div);
min_sys_div = max(min_sys_div,
pll->pll_op_clk_freq_hz
/ limits->vt.max_sys_clk_freq_hz);
- dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %d\n", min_sys_div);
+ dev_dbg(dev, "min_sys_div: max_pll_op_clk_freq_hz: %u\n", min_sys_div);
min_sys_div = clk_div_even_up(min_sys_div);
- dev_dbg(dev, "min_sys_div: one or even: %d\n", min_sys_div);
+ dev_dbg(dev, "min_sys_div: one or even: %u\n", min_sys_div);
max_sys_div = limits->vt.max_sys_clk_div;
- dev_dbg(dev, "max_sys_div: %d\n", max_sys_div);
+ dev_dbg(dev, "max_sys_div: %u\n", max_sys_div);
max_sys_div = min(max_sys_div,
DIV_ROUND_UP(max_vt_div,
limits->vt.min_pix_clk_div));
- dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %d\n", max_sys_div);
+ dev_dbg(dev, "max_sys_div: min_vt_pix_clk_div: %u\n", max_sys_div);
max_sys_div = min(max_sys_div,
DIV_ROUND_UP(pll->pll_op_clk_freq_hz,
limits->vt.min_pix_clk_freq_hz));
- dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %d\n", max_sys_div);
+ dev_dbg(dev, "max_sys_div: min_vt_pix_clk_freq_hz: %u\n", max_sys_div);
/*
* Find pix_div such that a legal pix_div * sys_div results
@@ -296,7 +364,7 @@ static int __smiapp_pll_calculate(struct device *dev,
if (pix_div < limits->vt.min_pix_clk_div
|| pix_div > limits->vt.max_pix_clk_div) {
dev_dbg(dev,
- "pix_div %d too small or too big (%d--%d)\n",
+ "pix_div %u too small or too big (%u--%u)\n",
pix_div,
limits->vt.min_pix_clk_div,
limits->vt.max_pix_clk_div);
@@ -312,73 +380,28 @@ static int __smiapp_pll_calculate(struct device *dev,
break;
}
- pll->vt_sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
- pll->vt_pix_clk_div = best_pix_div;
+ pll->vt.sys_clk_div = DIV_ROUND_UP(min_vt_div, best_pix_div);
+ pll->vt.pix_clk_div = best_pix_div;
- pll->vt_sys_clk_freq_hz =
- pll->pll_op_clk_freq_hz / pll->vt_sys_clk_div;
- pll->vt_pix_clk_freq_hz =
- pll->vt_sys_clk_freq_hz / pll->vt_pix_clk_div;
+ pll->vt.sys_clk_freq_hz =
+ pll->pll_op_clk_freq_hz / pll->vt.sys_clk_div;
+ pll->vt.pix_clk_freq_hz =
+ pll->vt.sys_clk_freq_hz / pll->vt.pix_clk_div;
+out_skip_vt_calc:
pll->pixel_rate_csi =
- pll->op_pix_clk_freq_hz * lane_op_clock_ratio;
+ op_pll->pix_clk_freq_hz * lane_op_clock_ratio;
+ pll->pixel_rate_pixel_array = pll->vt.pix_clk_freq_hz;
- rval = bounds_check(dev, pll->pll_ip_clk_freq_hz,
- limits->min_pll_ip_freq_hz,
- limits->max_pll_ip_freq_hz,
- "pll_ip_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->pll_multiplier,
- limits->min_pll_multiplier, limits->max_pll_multiplier,
- "pll_multiplier");
- if (!rval)
- rval = bounds_check(
- dev, pll->pll_op_clk_freq_hz,
- limits->min_pll_op_freq_hz, limits->max_pll_op_freq_hz,
- "pll_op_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_sys_clk_div,
- limits->op.min_sys_clk_div, limits->op.max_sys_clk_div,
- "op_sys_clk_div");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_pix_clk_div,
- limits->op.min_pix_clk_div, limits->op.max_pix_clk_div,
- "op_pix_clk_div");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_sys_clk_freq_hz,
- limits->op.min_sys_clk_freq_hz,
- limits->op.max_sys_clk_freq_hz,
- "op_sys_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->op_pix_clk_freq_hz,
- limits->op.min_pix_clk_freq_hz,
- limits->op.max_pix_clk_freq_hz,
- "op_pix_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->vt_sys_clk_freq_hz,
- limits->vt.min_sys_clk_freq_hz,
- limits->vt.max_sys_clk_freq_hz,
- "vt_sys_clk_freq_hz");
- if (!rval)
- rval = bounds_check(
- dev, pll->vt_pix_clk_freq_hz,
- limits->vt.min_pix_clk_freq_hz,
- limits->vt.max_pix_clk_freq_hz,
- "vt_pix_clk_freq_hz");
-
- return rval;
+ return check_all_bounds(dev, limits, op_limits, pll, op_pll);
}
int smiapp_pll_calculate(struct device *dev,
const struct smiapp_pll_limits *limits,
struct smiapp_pll *pll)
{
+ const struct smiapp_pll_branch_limits *op_limits = &limits->op;
+ struct smiapp_pll_branch *op_pll = &pll->op;
uint16_t min_pre_pll_clk_div;
uint16_t max_pre_pll_clk_div;
uint32_t lane_op_clock_ratio;
@@ -386,13 +409,23 @@ int smiapp_pll_calculate(struct device *dev,
unsigned int i;
int rval = -EINVAL;
+ if (pll->flags & SMIAPP_PLL_FLAG_NO_OP_CLOCKS) {
+ /*
+ * If there's no OP PLL at all, use the VT values
+ * instead. The OP values are ignored for the rest of
+ * the PLL calculation.
+ */
+ op_limits = &limits->vt;
+ op_pll = &pll->vt;
+ }
+
if (pll->flags & SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE)
lane_op_clock_ratio = pll->csi2.lanes;
else
lane_op_clock_ratio = 1;
- dev_dbg(dev, "lane_op_clock_ratio: %d\n", lane_op_clock_ratio);
+ dev_dbg(dev, "lane_op_clock_ratio: %u\n", lane_op_clock_ratio);
- dev_dbg(dev, "binning: %dx%d\n", pll->binning_horizontal,
+ dev_dbg(dev, "binning: %ux%u\n", pll->binning_horizontal,
pll->binning_vertical);
switch (pll->bus_type) {
@@ -411,7 +444,7 @@ int smiapp_pll_calculate(struct device *dev,
}
/* Figure out limits for pre-pll divider based on extclk */
- dev_dbg(dev, "min / max pre_pll_clk_div: %d / %d\n",
+ dev_dbg(dev, "min / max pre_pll_clk_div: %u / %u\n",
limits->min_pre_pll_clk_div, limits->max_pre_pll_clk_div);
max_pre_pll_clk_div =
min_t(uint16_t, limits->max_pre_pll_clk_div,
@@ -422,26 +455,27 @@ int smiapp_pll_calculate(struct device *dev,
clk_div_even_up(
DIV_ROUND_UP(pll->ext_clk_freq_hz,
limits->max_pll_ip_freq_hz)));
- dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %d / %d\n",
+ dev_dbg(dev, "pre-pll check: min / max pre_pll_clk_div: %u / %u\n",
min_pre_pll_clk_div, max_pre_pll_clk_div);
i = gcd(pll->pll_op_clk_freq_hz, pll->ext_clk_freq_hz);
mul = div_u64(pll->pll_op_clk_freq_hz, i);
div = pll->ext_clk_freq_hz / i;
- dev_dbg(dev, "mul %d / div %d\n", mul, div);
+ dev_dbg(dev, "mul %u / div %u\n", mul, div);
min_pre_pll_clk_div =
max_t(uint16_t, min_pre_pll_clk_div,
clk_div_even_up(
DIV_ROUND_UP(mul * pll->ext_clk_freq_hz,
limits->max_pll_op_freq_hz)));
- dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %d / %d\n",
+ dev_dbg(dev, "pll_op check: min / max pre_pll_clk_div: %u / %u\n",
min_pre_pll_clk_div, max_pre_pll_clk_div);
for (pll->pre_pll_clk_div = min_pre_pll_clk_div;
pll->pre_pll_clk_div <= max_pre_pll_clk_div;
pll->pre_pll_clk_div += 2 - (pll->pre_pll_clk_div & 1)) {
- rval = __smiapp_pll_calculate(dev, limits, pll, mul, div,
+ rval = __smiapp_pll_calculate(dev, limits, op_limits, pll,
+ op_pll, mul, div,
lane_op_clock_ratio);
if (rval)
continue;
diff --git a/drivers/media/i2c/smiapp-pll.h b/drivers/media/i2c/smiapp-pll.h
index 5ce2b61..e8f035a 100644
--- a/drivers/media/i2c/smiapp-pll.h
+++ b/drivers/media/i2c/smiapp-pll.h
@@ -35,6 +35,13 @@
#define SMIAPP_PLL_FLAG_OP_PIX_CLOCK_PER_LANE (1 << 0)
#define SMIAPP_PLL_FLAG_NO_OP_CLOCKS (1 << 1)
+struct smiapp_pll_branch {
+ uint16_t sys_clk_div;
+ uint16_t pix_clk_div;
+ uint32_t sys_clk_freq_hz;
+ uint32_t pix_clk_freq_hz;
+};
+
struct smiapp_pll {
/* input values */
uint8_t bus_type;
@@ -53,24 +60,18 @@ struct smiapp_pll {
uint8_t scale_n;
uint8_t bits_per_pixel;
uint32_t link_freq;
+ uint32_t ext_clk_freq_hz;
/* output values */
uint16_t pre_pll_clk_div;
uint16_t pll_multiplier;
- uint16_t op_sys_clk_div;
- uint16_t op_pix_clk_div;
- uint16_t vt_sys_clk_div;
- uint16_t vt_pix_clk_div;
-
- uint32_t ext_clk_freq_hz;
uint32_t pll_ip_clk_freq_hz;
uint32_t pll_op_clk_freq_hz;
- uint32_t op_sys_clk_freq_hz;
- uint32_t op_pix_clk_freq_hz;
- uint32_t vt_sys_clk_freq_hz;
- uint32_t vt_pix_clk_freq_hz;
+ struct smiapp_pll_branch vt;
+ struct smiapp_pll_branch op;
uint32_t pixel_rate_csi;
+ uint32_t pixel_rate_pixel_array;
};
struct smiapp_pll_branch_limits {
diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index 932ed9b..0df5070e 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -205,12 +205,12 @@ static int smiapp_pll_configure(struct smiapp_sensor *sensor)
int rval;
rval = smiapp_write(
- sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt_pix_clk_div);
+ sensor, SMIAPP_REG_U16_VT_PIX_CLK_DIV, pll->vt.pix_clk_div);
if (rval < 0)
return rval;
rval = smiapp_write(
- sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt_sys_clk_div);
+ sensor, SMIAPP_REG_U16_VT_SYS_CLK_DIV, pll->vt.sys_clk_div);
if (rval < 0)
return rval;
@@ -227,20 +227,21 @@ static int smiapp_pll_configure(struct smiapp_sensor *sensor)
/* Lane op clock ratio does not apply here. */
rval = smiapp_write(
sensor, SMIAPP_REG_U32_REQUESTED_LINK_BIT_RATE_MBPS,
- DIV_ROUND_UP(pll->op_sys_clk_freq_hz, 1000000 / 256 / 256));
+ DIV_ROUND_UP(pll->op.sys_clk_freq_hz, 1000000 / 256 / 256));
if (rval < 0 || sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
return rval;
rval = smiapp_write(
- sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op_pix_clk_div);
+ sensor, SMIAPP_REG_U16_OP_PIX_CLK_DIV, pll->op.pix_clk_div);
if (rval < 0)
return rval;
return smiapp_write(
- sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op_sys_clk_div);
+ sensor, SMIAPP_REG_U16_OP_SYS_CLK_DIV, pll->op.sys_clk_div);
}
-static int smiapp_pll_update(struct smiapp_sensor *sensor)
+static int smiapp_pll_try(struct smiapp_sensor *sensor,
+ struct smiapp_pll *pll)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
struct smiapp_pll_limits lim = {
@@ -274,19 +275,15 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
.min_line_length_pck_bin = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK_BIN],
.min_line_length_pck = sensor->limits[SMIAPP_LIMIT_MIN_LINE_LENGTH_PCK],
};
+
+ return smiapp_pll_calculate(&client->dev, &lim, pll);
+}
+
+static int smiapp_pll_update(struct smiapp_sensor *sensor)
+{
struct smiapp_pll *pll = &sensor->pll;
int rval;
- if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0) {
- /*
- * Fill in operational clock divisors limits from the
- * video timing ones. On profile 0 sensors the
- * requirements regarding them are essentially the
- * same as on VT ones.
- */
- lim.op = lim.vt;
- }
-
pll->binning_horizontal = sensor->binning_horizontal;
pll->binning_vertical = sensor->binning_vertical;
pll->link_freq =
@@ -294,12 +291,12 @@ static int smiapp_pll_update(struct smiapp_sensor *sensor)
pll->scale_m = sensor->scale_m;
pll->bits_per_pixel = sensor->csi_format->compressed;
- rval = smiapp_pll_calculate(&client->dev, &lim, pll);
+ rval = smiapp_pll_try(sensor, pll);
if (rval < 0)
return rval;
__v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_parray,
- pll->vt_pix_clk_freq_hz);
+ pll->pixel_rate_pixel_array);
__v4l2_ctrl_s_ctrl_int64(sensor->pixel_rate_csi, pll->pixel_rate_csi);
return 0;
@@ -333,22 +330,22 @@ static void __smiapp_update_exposure_limits(struct smiapp_sensor *sensor)
* orders must be defined.
*/
static const struct smiapp_csi_data_format smiapp_csi_data_formats[] = {
- { V4L2_MBUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
- { V4L2_MBUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
- { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
- { V4L2_MBUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
- { V4L2_MBUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
- { V4L2_MBUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
- { V4L2_MBUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GRBG, },
+ { MEDIA_BUS_FMT_SRGGB12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_RGGB, },
+ { MEDIA_BUS_FMT_SBGGR12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_BGGR, },
+ { MEDIA_BUS_FMT_SGBRG12_1X12, 12, 12, SMIAPP_PIXEL_ORDER_GBRG, },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GRBG, },
+ { MEDIA_BUS_FMT_SRGGB10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_RGGB, },
+ { MEDIA_BUS_FMT_SBGGR10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_BGGR, },
+ { MEDIA_BUS_FMT_SGBRG10_1X10, 10, 10, SMIAPP_PIXEL_ORDER_GBRG, },
+ { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+ { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+ { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+ { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, 10, 8, SMIAPP_PIXEL_ORDER_GBRG, },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GRBG, },
+ { MEDIA_BUS_FMT_SRGGB8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_RGGB, },
+ { MEDIA_BUS_FMT_SBGGR8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_BGGR, },
+ { MEDIA_BUS_FMT_SGBRG8_1X8, 8, 8, SMIAPP_PIXEL_ORDER_GBRG, },
};
const char *pixel_order_str[] = { "GRBG", "RGGB", "BGGR", "GBRG" };
@@ -526,6 +523,8 @@ static const struct v4l2_ctrl_ops smiapp_ctrl_ops = {
static int smiapp_init_controls(struct smiapp_sensor *sensor)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ unsigned long *valid_link_freqs = &sensor->valid_link_freqs[
+ sensor->csi_format->compressed - SMIAPP_COMPRESSED_BASE];
unsigned int max, i;
int rval;
@@ -608,8 +607,8 @@ static int smiapp_init_controls(struct smiapp_sensor *sensor)
sensor->link_freq = v4l2_ctrl_new_int_menu(
&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
- V4L2_CID_LINK_FREQ, max, 0,
- sensor->platform_data->op_sys_clock);
+ V4L2_CID_LINK_FREQ, __fls(*valid_link_freqs),
+ __ffs(*valid_link_freqs), sensor->platform_data->op_sys_clock);
sensor->pixel_rate_csi = v4l2_ctrl_new_std(
&sensor->src->ctrl_handler, &smiapp_ctrl_ops,
@@ -745,6 +744,7 @@ static int smiapp_get_limits_binning(struct smiapp_sensor *sensor)
static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
{
struct i2c_client *client = v4l2_get_subdevdata(&sensor->src->sd);
+ struct smiapp_pll *pll = &sensor->pll;
unsigned int type, n;
unsigned int i, pixel_order;
int rval;
@@ -808,14 +808,57 @@ static int smiapp_get_mbus_formats(struct smiapp_sensor *sensor)
dev_dbg(&client->dev, "jolly good! %d\n", j);
sensor->default_mbus_frame_fmts |= 1 << j;
- if (!sensor->csi_format
- || f->width > sensor->csi_format->width
- || (f->width == sensor->csi_format->width
- && f->compressed
- > sensor->csi_format->compressed)) {
- sensor->csi_format = f;
- sensor->internal_csi_format = f;
- }
+ }
+ }
+
+ /* Figure out which BPP values can be used with which formats. */
+ pll->binning_horizontal = 1;
+ pll->binning_vertical = 1;
+ pll->scale_m = sensor->scale_m;
+
+ for (i = 0; i < ARRAY_SIZE(smiapp_csi_data_formats); i++) {
+ const struct smiapp_csi_data_format *f =
+ &smiapp_csi_data_formats[i];
+ unsigned long *valid_link_freqs =
+ &sensor->valid_link_freqs[
+ f->compressed - SMIAPP_COMPRESSED_BASE];
+ unsigned int j;
+
+ BUG_ON(f->compressed < SMIAPP_COMPRESSED_BASE);
+ BUG_ON(f->compressed > SMIAPP_COMPRESSED_MAX);
+
+ if (!(sensor->default_mbus_frame_fmts & 1 << i))
+ continue;
+
+ pll->bits_per_pixel = f->compressed;
+
+ for (j = 0; sensor->platform_data->op_sys_clock[j]; j++) {
+ pll->link_freq = sensor->platform_data->op_sys_clock[j];
+
+ rval = smiapp_pll_try(sensor, pll);
+ dev_dbg(&client->dev, "link freq %u Hz, bpp %u %s\n",
+ pll->link_freq, pll->bits_per_pixel,
+ rval ? "not ok" : "ok");
+ if (rval)
+ continue;
+
+ set_bit(j, valid_link_freqs);
+ }
+
+ if (!*valid_link_freqs) {
+ dev_info(&client->dev,
+ "no valid link frequencies for %u bpp\n",
+ f->compressed);
+ sensor->default_mbus_frame_fmts &= ~BIT(i);
+ continue;
+ }
+
+ if (!sensor->csi_format
+ || f->width > sensor->csi_format->width
+ || (f->width == sensor->csi_format->width
+ && f->compressed > sensor->csi_format->compressed)) {
+ sensor->csi_format = f;
+ sensor->internal_csi_format = f;
}
}
@@ -904,7 +947,7 @@ static int smiapp_update_mode(struct smiapp_sensor *sensor)
dev_dbg(&client->dev, "hblank\t\t%d\n", sensor->hblank->val);
dev_dbg(&client->dev, "real timeperframe\t100/%d\n",
- sensor->pll.vt_pix_clk_freq_hz /
+ sensor->pll.pixel_rate_pixel_array /
((sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].width
+ sensor->hblank->val) *
(sensor->pixel_array->crop[SMIAPP_PA_PAD_SRC].height
@@ -1687,51 +1730,77 @@ static const struct smiapp_csi_data_format
return csi_format;
}
-static int smiapp_set_format(struct v4l2_subdev *subdev,
- struct v4l2_subdev_fh *fh,
- struct v4l2_subdev_format *fmt)
+static int smiapp_set_format_source(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
{
struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
- struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
- struct v4l2_rect *crops[SMIAPP_PADS];
+ const struct smiapp_csi_data_format *csi_format,
+ *old_csi_format = sensor->csi_format;
+ unsigned long *valid_link_freqs;
+ u32 code = fmt->format.code;
+ unsigned int i;
+ int rval;
- mutex_lock(&sensor->mutex);
+ rval = __smiapp_get_format(subdev, fh, fmt);
+ if (rval)
+ return rval;
/*
* Media bus code is changeable on src subdev's source pad. On
* other source pads we just get format here.
*/
- if (fmt->pad == ssd->source_pad) {
- u32 code = fmt->format.code;
- int rval = __smiapp_get_format(subdev, fh, fmt);
- bool range_changed = false;
- unsigned int i;
-
- if (!rval && subdev == &sensor->src->sd) {
- const struct smiapp_csi_data_format *csi_format =
- smiapp_validate_csi_data_format(sensor, code);
+ if (subdev != &sensor->src->sd)
+ return 0;
- if (fmt->which == V4L2_SUBDEV_FORMAT_ACTIVE) {
- if (csi_format->width !=
- sensor->csi_format->width)
- range_changed = true;
+ csi_format = smiapp_validate_csi_data_format(sensor, code);
- sensor->csi_format = csi_format;
- }
+ fmt->format.code = csi_format->code;
- fmt->format.code = csi_format->code;
- }
+ if (fmt->which != V4L2_SUBDEV_FORMAT_ACTIVE)
+ return 0;
- mutex_unlock(&sensor->mutex);
- if (rval || !range_changed)
- return rval;
+ sensor->csi_format = csi_format;
+ if (csi_format->width != old_csi_format->width)
for (i = 0; i < ARRAY_SIZE(sensor->test_data); i++)
- v4l2_ctrl_modify_range(
- sensor->test_data[i],
- 0, (1 << sensor->csi_format->width) - 1, 1, 0);
+ __v4l2_ctrl_modify_range(
+ sensor->test_data[i], 0,
+ (1 << csi_format->width) - 1, 1, 0);
+ if (csi_format->compressed == old_csi_format->compressed)
return 0;
+
+ valid_link_freqs =
+ &sensor->valid_link_freqs[sensor->csi_format->compressed
+ - SMIAPP_COMPRESSED_BASE];
+
+ __v4l2_ctrl_modify_range(
+ sensor->link_freq, 0,
+ __fls(*valid_link_freqs), ~*valid_link_freqs,
+ __ffs(*valid_link_freqs));
+
+ return smiapp_pll_update(sensor);
+}
+
+static int smiapp_set_format(struct v4l2_subdev *subdev,
+ struct v4l2_subdev_fh *fh,
+ struct v4l2_subdev_format *fmt)
+{
+ struct smiapp_sensor *sensor = to_smiapp_sensor(subdev);
+ struct smiapp_subdev *ssd = to_smiapp_subdev(subdev);
+ struct v4l2_rect *crops[SMIAPP_PADS];
+
+ mutex_lock(&sensor->mutex);
+
+ if (fmt->pad == ssd->source_pad) {
+ int rval;
+
+ rval = smiapp_set_format_source(subdev, fh, fmt);
+
+ mutex_unlock(&sensor->mutex);
+
+ return rval;
}
/* Sink pad. Width and height are changeable here. */
@@ -2023,6 +2092,11 @@ static int __smiapp_sel_supported(struct v4l2_subdev *subdev,
== SMIAPP_DIGITAL_CROP_CAPABILITY_INPUT_CROP)
return 0;
return -EINVAL;
+ case V4L2_SEL_TGT_NATIVE_SIZE:
+ if (ssd == sensor->pixel_array
+ && sel->pad == SMIAPP_PA_PAD_SRC)
+ return 0;
+ return -EINVAL;
case V4L2_SEL_TGT_COMPOSE:
case V4L2_SEL_TGT_COMPOSE_BOUNDS:
if (sel->pad == ssd->source_pad)
@@ -2121,7 +2195,9 @@ static int __smiapp_get_selection(struct v4l2_subdev *subdev,
switch (sel->target) {
case V4L2_SEL_TGT_CROP_BOUNDS:
+ case V4L2_SEL_TGT_NATIVE_SIZE:
if (ssd == sensor->pixel_array) {
+ sel->r.left = sel->r.top = 0;
sel->r.width =
sensor->limits[SMIAPP_LIMIT_X_ADDR_MAX] + 1;
sel->r.height =
@@ -2190,7 +2266,7 @@ static int smiapp_set_selection(struct v4l2_subdev *subdev,
ret = smiapp_set_compose(subdev, fh, sel);
break;
default:
- BUG();
+ ret = -EINVAL;
}
mutex_unlock(&sensor->mutex);
@@ -2482,12 +2558,6 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
goto out_power_off;
}
- rval = smiapp_get_mbus_formats(sensor);
- if (rval) {
- rval = -ENODEV;
- goto out_power_off;
- }
-
if (sensor->limits[SMIAPP_LIMIT_BINNING_CAPABILITY]) {
u32 val;
@@ -2569,6 +2639,22 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
sensor->scale_m = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ /* prepare PLL configuration input values */
+ pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
+ pll->csi2.lanes = sensor->platform_data->lanes;
+ pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
+ pll->flags = smiapp_call_quirk(sensor, pll_flags);
+ pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
+ /* Profile 0 sensors have no separate OP clock branch. */
+ if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
+ pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
+
+ rval = smiapp_get_mbus_formats(sensor);
+ if (rval) {
+ rval = -ENODEV;
+ goto out_nvm_release;
+ }
+
for (i = 0; i < SMIAPP_SUBDEVS; i++) {
struct {
struct smiapp_subdev *ssd;
@@ -2666,18 +2752,9 @@ static int smiapp_registered(struct v4l2_subdev *subdev)
if (rval < 0)
goto out_nvm_release;
- /* prepare PLL configuration input values */
- pll->bus_type = SMIAPP_PLL_BUS_TYPE_CSI2;
- pll->csi2.lanes = sensor->platform_data->lanes;
- pll->ext_clk_freq_hz = sensor->platform_data->ext_clk;
- pll->flags = smiapp_call_quirk(sensor, pll_flags);
-
- /* Profile 0 sensors have no separate OP clock branch. */
- if (sensor->minfo.smiapp_profile == SMIAPP_PROFILE_0)
- pll->flags |= SMIAPP_PLL_FLAG_NO_OP_CLOCKS;
- pll->scale_n = sensor->limits[SMIAPP_LIMIT_SCALER_N_MIN];
-
+ mutex_lock(&sensor->mutex);
rval = smiapp_update_mode(sensor);
+ mutex_unlock(&sensor->mutex);
if (rval) {
dev_err(&client->dev, "update mode failed\n");
goto out_nvm_release;
diff --git a/drivers/media/i2c/smiapp/smiapp.h b/drivers/media/i2c/smiapp/smiapp.h
index 874b49f..f88f8ec 100644
--- a/drivers/media/i2c/smiapp/smiapp.h
+++ b/drivers/media/i2c/smiapp/smiapp.h
@@ -156,6 +156,11 @@ struct smiapp_csi_data_format {
#define SMIAPP_PAD_SRC 1
#define SMIAPP_PADS 2
+#define SMIAPP_COMPRESSED_BASE 8
+#define SMIAPP_COMPRESSED_MAX 12
+#define SMIAPP_NR_OF_COMPRESSED (SMIAPP_COMPRESSED_MAX - \
+ SMIAPP_COMPRESSED_BASE + 1)
+
struct smiapp_binning_subtype {
u8 horizontal:4;
u8 vertical:4;
@@ -232,6 +237,9 @@ struct smiapp_sensor {
struct smiapp_pll pll;
+ /* Is a default format supported for a given BPP? */
+ unsigned long valid_link_freqs[SMIAPP_NR_OF_COMPRESSED];
+
/* Pixel array controls */
struct v4l2_ctrl *analog_gain;
struct v4l2_ctrl *exposure;
diff --git a/drivers/media/i2c/soc_camera/imx074.c b/drivers/media/i2c/soc_camera/imx074.c
index 5b91593..ec89cfa 100644
--- a/drivers/media/i2c/soc_camera/imx074.c
+++ b/drivers/media/i2c/soc_camera/imx074.c
@@ -71,7 +71,7 @@
/* IMX074 has only one fixed colorspace per pixelcode */
struct imx074_datafmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
@@ -82,7 +82,7 @@ struct imx074 {
};
static const struct imx074_datafmt imx074_colour_fmts[] = {
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
};
static struct imx074 *to_imx074(const struct i2c_client *client)
@@ -91,7 +91,7 @@ static struct imx074 *to_imx074(const struct i2c_client *client)
}
/* Find a data format by a pixel code in an array */
-static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code)
+static const struct imx074_datafmt *imx074_find_datafmt(u32 code)
{
int i;
@@ -236,7 +236,7 @@ static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
}
static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/mt9m001.c b/drivers/media/i2c/soc_camera/mt9m001.c
index dbd8c14..2e9a535 100644
--- a/drivers/media/i2c/soc_camera/mt9m001.c
+++ b/drivers/media/i2c/soc_camera/mt9m001.c
@@ -53,13 +53,13 @@
/* MT9M001 has only one fixed colorspace per pixelcode */
struct mt9m001_datafmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
/* Find a data format by a pixel code in an array */
static const struct mt9m001_datafmt *mt9m001_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct mt9m001_datafmt *fmt,
+ u32 code, const struct mt9m001_datafmt *fmt,
int n)
{
int i;
@@ -75,14 +75,14 @@ static const struct mt9m001_datafmt mt9m001_colour_fmts[] = {
* Order important: first natively supported,
* second supported with a GPIO extender
*/
- {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
};
static const struct mt9m001_datafmt mt9m001_monochrome_fmts[] = {
/* Order important - see above */
- {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
};
struct mt9m001 {
@@ -563,7 +563,7 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
};
static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
diff --git a/drivers/media/i2c/soc_camera/mt9m111.c b/drivers/media/i2c/soc_camera/mt9m111.c
index b51e856..5992ea9 100644
--- a/drivers/media/i2c/soc_camera/mt9m111.c
+++ b/drivers/media/i2c/soc_camera/mt9m111.c
@@ -182,23 +182,23 @@ static struct mt9m111_context context_b = {
/* MT9M111 has only one fixed colorspace per pixelcode */
struct mt9m111_datafmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_BGR565_2X8_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_BGR565_2X8_BE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
};
struct mt9m111 {
@@ -218,7 +218,7 @@ struct mt9m111 {
/* Find a data format by a pixel code */
static const struct mt9m111_datafmt *mt9m111_find_datafmt(struct mt9m111 *mt9m111,
- enum v4l2_mbus_pixelcode code)
+ u32 code)
{
int i;
for (i = 0; i < ARRAY_SIZE(mt9m111_colour_fmts); i++)
@@ -331,7 +331,7 @@ static int mt9m111_setup_rect_ctx(struct mt9m111 *mt9m111,
}
static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rect,
- int width, int height, enum v4l2_mbus_pixelcode code)
+ int width, int height, u32 code)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
int ret;
@@ -345,7 +345,7 @@ static int mt9m111_setup_geometry(struct mt9m111 *mt9m111, struct v4l2_rect *rec
if (!ret)
ret = reg_write(WINDOW_HEIGHT, rect->height);
- if (code != V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+ if (code != MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
/* IFP in use, down-scaling possible */
if (!ret)
ret = mt9m111_setup_rect_ctx(mt9m111, &context_b,
@@ -393,8 +393,8 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, const struct v4l2_crop *a)
if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
- mt9m111->fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+ if (mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
+ mt9m111->fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
/* Bayer format - even size lengths */
rect.width = ALIGN(rect.width, 2);
rect.height = ALIGN(rect.height, 2);
@@ -462,7 +462,7 @@ static int mt9m111_g_fmt(struct v4l2_subdev *sd,
}
static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
- enum v4l2_mbus_pixelcode code)
+ u32 code)
{
struct i2c_client *client = v4l2_get_subdevdata(&mt9m111->subdev);
u16 data_outfmt2, mask_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
@@ -474,46 +474,46 @@ static int mt9m111_set_pixfmt(struct mt9m111 *mt9m111,
int ret;
switch (code) {
- case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
data_outfmt2 = MT9M111_OUTFMT_PROCESSED_BAYER |
MT9M111_OUTFMT_RGB;
break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
data_outfmt2 = MT9M111_OUTFMT_BYPASS_IFP | MT9M111_OUTFMT_RGB;
break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB555;
break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
break;
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565;
break;
- case V4L2_MBUS_FMT_BGR565_2X8_BE:
+ case MEDIA_BUS_FMT_BGR565_2X8_BE:
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
break;
- case V4L2_MBUS_FMT_BGR565_2X8_LE:
+ case MEDIA_BUS_FMT_BGR565_2X8_LE:
data_outfmt2 = MT9M111_OUTFMT_RGB | MT9M111_OUTFMT_RGB565 |
MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
break;
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
data_outfmt2 = 0;
break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN;
break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
data_outfmt2 = MT9M111_OUTFMT_SWAP_YCbCr_C_Y_RGB_EVEN |
MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr_RGB_R_B;
break;
@@ -542,8 +542,8 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd,
fmt = mt9m111_find_datafmt(mt9m111, mf->code);
- bayer = fmt->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
- fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE;
+ bayer = fmt->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
+ fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE;
/*
* With Bayer format enforce even side lengths, but let the user play
@@ -554,7 +554,7 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd,
rect->height = ALIGN(rect->height, 2);
}
- if (fmt->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE) {
+ if (fmt->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE) {
/* IFP bypass mode, no scaling */
mf->width = rect->width;
mf->height = rect->height;
@@ -840,7 +840,7 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
};
static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(mt9m111_colour_fmts))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/mt9t031.c b/drivers/media/i2c/soc_camera/mt9t031.c
index f8358c4..35d9c8d 100644
--- a/drivers/media/i2c/soc_camera/mt9t031.c
+++ b/drivers/media/i2c/soc_camera/mt9t031.c
@@ -345,7 +345,7 @@ static int mt9t031_g_fmt(struct v4l2_subdev *sd,
mf->width = mt9t031->rect.width / mt9t031->xskip;
mf->height = mt9t031->rect.height / mt9t031->yskip;
- mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mf->code = MEDIA_BUS_FMT_SBGGR10_1X10;
mf->colorspace = V4L2_COLORSPACE_SRGB;
mf->field = V4L2_FIELD_NONE;
@@ -367,7 +367,7 @@ static int mt9t031_s_fmt(struct v4l2_subdev *sd,
xskip = mt9t031_skip(&rect.width, mf->width, MT9T031_MAX_WIDTH);
yskip = mt9t031_skip(&rect.height, mf->height, MT9T031_MAX_HEIGHT);
- mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mf->code = MEDIA_BUS_FMT_SBGGR10_1X10;
mf->colorspace = V4L2_COLORSPACE_SRGB;
/* mt9t031_set_params() doesn't change width and height */
@@ -385,7 +385,7 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
&mf->width, MT9T031_MIN_WIDTH, MT9T031_MAX_WIDTH, 1,
&mf->height, MT9T031_MIN_HEIGHT, MT9T031_MAX_HEIGHT, 1, 0);
- mf->code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ mf->code = MEDIA_BUS_FMT_SBGGR10_1X10;
mf->colorspace = V4L2_COLORSPACE_SRGB;
return 0;
@@ -673,12 +673,12 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
};
static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_SBGGR10_1X10;
+ *code = MEDIA_BUS_FMT_SBGGR10_1X10;
return 0;
}
diff --git a/drivers/media/i2c/soc_camera/mt9t112.c b/drivers/media/i2c/soc_camera/mt9t112.c
index 996d7b4..64f0836 100644
--- a/drivers/media/i2c/soc_camera/mt9t112.c
+++ b/drivers/media/i2c/soc_camera/mt9t112.c
@@ -77,7 +77,7 @@
struct
************************************************************************/
struct mt9t112_format {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
u16 fmt;
u16 order;
@@ -103,32 +103,32 @@ struct mt9t112_priv {
static const struct mt9t112_format mt9t112_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 0,
}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 1,
}, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 2,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 3,
}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.fmt = 8,
.order = 2,
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.fmt = 4,
.order = 2,
@@ -840,7 +840,7 @@ static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
static int mt9t112_set_params(struct mt9t112_priv *priv,
const struct v4l2_rect *rect,
- enum v4l2_mbus_pixelcode code)
+ u32 code)
{
int i;
@@ -953,7 +953,7 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd,
break;
if (i == priv->num_formats) {
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
} else {
mf->colorspace = mt9t112_cfmts[i].colorspace;
@@ -967,7 +967,7 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd,
}
static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
@@ -1101,7 +1101,7 @@ static int mt9t112_probe(struct i2c_client *client,
/* Cannot fail: using the default supported pixel code */
if (!ret)
- mt9t112_set_params(priv, &rect, V4L2_MBUS_FMT_UYVY8_2X8);
+ mt9t112_set_params(priv, &rect, MEDIA_BUS_FMT_UYVY8_2X8);
else
v4l2_clk_put(priv->clk);
diff --git a/drivers/media/i2c/soc_camera/mt9v022.c b/drivers/media/i2c/soc_camera/mt9v022.c
index 99022c8..a246d4d 100644
--- a/drivers/media/i2c/soc_camera/mt9v022.c
+++ b/drivers/media/i2c/soc_camera/mt9v022.c
@@ -85,13 +85,13 @@ MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"");
/* MT9V022 has only one fixed colorspace per pixelcode */
struct mt9v022_datafmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
/* Find a data format by a pixel code in an array */
static const struct mt9v022_datafmt *mt9v022_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct mt9v022_datafmt *fmt,
+ u32 code, const struct mt9v022_datafmt *fmt,
int n)
{
int i;
@@ -107,14 +107,14 @@ static const struct mt9v022_datafmt mt9v022_colour_fmts[] = {
* Order important: first natively supported,
* second supported with a GPIO extender
*/
- {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
};
static const struct mt9v022_datafmt mt9v022_monochrome_fmts[] = {
/* Order important - see above */
- {V4L2_MBUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_Y10_1X10, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_Y8_1X8, V4L2_COLORSPACE_JPEG},
};
/* only registers with different addresses on different mt9v02x sensors */
@@ -410,13 +410,13 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
* .try_mbus_fmt(), datawidth is from our supported format list
*/
switch (mf->code) {
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_Y10_1X10:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_Y10_1X10:
if (mt9v022->model != MT9V022IX7ATM)
return -EINVAL;
break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
if (mt9v022->model != MT9V022IX7ATC)
return -EINVAL;
break;
@@ -443,8 +443,8 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
const struct mt9v022_datafmt *fmt;
- int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_1X10;
+ int align = mf->code == MEDIA_BUS_FMT_SBGGR8_1X8 ||
+ mf->code == MEDIA_BUS_FMT_SBGGR10_1X10;
v4l_bound_align_image(&mf->width, MT9V022_MIN_WIDTH,
MT9V022_MAX_WIDTH, align,
@@ -759,7 +759,7 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
};
static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
diff --git a/drivers/media/i2c/soc_camera/ov2640.c b/drivers/media/i2c/soc_camera/ov2640.c
index 6c6b1c3..6f2dd90 100644
--- a/drivers/media/i2c/soc_camera/ov2640.c
+++ b/drivers/media/i2c/soc_camera/ov2640.c
@@ -302,7 +302,7 @@ struct ov2640_win_size {
struct ov2640_priv {
struct v4l2_subdev subdev;
struct v4l2_ctrl_handler hdl;
- enum v4l2_mbus_pixelcode cfmt_code;
+ u32 cfmt_code;
struct v4l2_clk *clk;
const struct ov2640_win_size *win;
};
@@ -623,11 +623,11 @@ static const struct regval_list ov2640_rgb565_le_regs[] = {
ENDMARKER,
};
-static enum v4l2_mbus_pixelcode ov2640_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_RGB565_2X8_BE,
- V4L2_MBUS_FMT_RGB565_2X8_LE,
+static u32 ov2640_codes[] = {
+ MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_RGB565_2X8_BE,
+ MEDIA_BUS_FMT_RGB565_2X8_LE,
};
/*
@@ -785,7 +785,7 @@ static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height)
}
static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
- enum v4l2_mbus_pixelcode code)
+ u32 code)
{
struct ov2640_priv *priv = to_ov2640(client);
const struct regval_list *selected_cfmt_regs;
@@ -797,20 +797,20 @@ static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
/* select format */
priv->cfmt_code = 0;
switch (code) {
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
dev_dbg(&client->dev, "%s: Selected cfmt RGB565 BE", __func__);
selected_cfmt_regs = ov2640_rgb565_be_regs;
break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
dev_dbg(&client->dev, "%s: Selected cfmt RGB565 LE", __func__);
selected_cfmt_regs = ov2640_rgb565_le_regs;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
dev_dbg(&client->dev, "%s: Selected cfmt YUYV (YUV422)", __func__);
selected_cfmt_regs = ov2640_yuyv_regs;
break;
default:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
dev_dbg(&client->dev, "%s: Selected cfmt UYVY", __func__);
selected_cfmt_regs = ov2640_uyvy_regs;
}
@@ -869,7 +869,7 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd,
if (!priv->win) {
u32 width = W_SVGA, height = H_SVGA;
priv->win = ov2640_select_win(&width, &height);
- priv->cfmt_code = V4L2_MBUS_FMT_UYVY8_2X8;
+ priv->cfmt_code = MEDIA_BUS_FMT_UYVY8_2X8;
}
mf->width = priv->win->width;
@@ -877,13 +877,13 @@ static int ov2640_g_fmt(struct v4l2_subdev *sd,
mf->code = priv->cfmt_code;
switch (mf->code) {
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
mf->field = V4L2_FIELD_NONE;
@@ -899,14 +899,14 @@ static int ov2640_s_fmt(struct v4l2_subdev *sd,
switch (mf->code) {
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
@@ -926,14 +926,14 @@ static int ov2640_try_fmt(struct v4l2_subdev *sd,
mf->field = V4L2_FIELD_NONE;
switch (mf->code) {
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
@@ -941,7 +941,7 @@ static int ov2640_try_fmt(struct v4l2_subdev *sd,
}
static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(ov2640_codes))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/ov5642.c b/drivers/media/i2c/soc_camera/ov5642.c
index d2daa6a..93ae031 100644
--- a/drivers/media/i2c/soc_camera/ov5642.c
+++ b/drivers/media/i2c/soc_camera/ov5642.c
@@ -602,7 +602,7 @@ static struct regval_list ov5642_default_regs_finalise[] = {
};
struct ov5642_datafmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
@@ -618,7 +618,7 @@ struct ov5642 {
};
static const struct ov5642_datafmt ov5642_colour_fmts[] = {
- {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
};
static struct ov5642 *to_ov5642(const struct i2c_client *client)
@@ -628,7 +628,7 @@ static struct ov5642 *to_ov5642(const struct i2c_client *client)
/* Find a data format by a pixel code in an array */
static const struct ov5642_datafmt
- *ov5642_find_datafmt(enum v4l2_mbus_pixelcode code)
+ *ov5642_find_datafmt(u32 code)
{
int i;
@@ -840,7 +840,7 @@ static int ov5642_g_fmt(struct v4l2_subdev *sd,
}
static int ov5642_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(ov5642_colour_fmts))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/ov6650.c b/drivers/media/i2c/soc_camera/ov6650.c
index ab01598..f4eef2f 100644
--- a/drivers/media/i2c/soc_camera/ov6650.c
+++ b/drivers/media/i2c/soc_camera/ov6650.c
@@ -202,18 +202,18 @@ struct ov6650 {
unsigned long pclk_limit; /* from host */
unsigned long pclk_max; /* from resolution and format */
struct v4l2_fract tpf; /* as requested with s_parm */
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
-static enum v4l2_mbus_pixelcode ov6650_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_YVYU8_2X8,
- V4L2_MBUS_FMT_VYUY8_2X8,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_Y8_1X8,
+static u32 ov6650_codes[] = {
+ MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_YVYU8_2X8,
+ MEDIA_BUS_FMT_VYUY8_2X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_Y8_1X8,
};
/* read a register */
@@ -555,29 +555,29 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
.height = mf->height << half_scale,
},
};
- enum v4l2_mbus_pixelcode code = mf->code;
+ u32 code = mf->code;
unsigned long mclk, pclk;
u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
int ret;
/* select color matrix configuration for given color encoding */
switch (code) {
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
coma_set |= COMA_BW;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n");
coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP;
coma_set |= COMA_WORD_SWAP;
break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n");
coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP |
COMA_BYTE_SWAP;
break;
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n");
if (half_scale) {
coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
@@ -587,7 +587,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
}
break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n");
if (half_scale) {
coma_mask |= COMA_RGB | COMA_BW;
@@ -597,7 +597,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
coma_set |= COMA_BYTE_SWAP;
}
break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n");
coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
coma_set |= COMA_RAW_RGB | COMA_RGB;
@@ -608,8 +608,8 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
}
priv->code = code;
- if (code == V4L2_MBUS_FMT_Y8_1X8 ||
- code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+ if (code == MEDIA_BUS_FMT_Y8_1X8 ||
+ code == MEDIA_BUS_FMT_SBGGR8_1X8) {
coml_mask = COML_ONE_CHANNEL;
coml_set = 0;
priv->pclk_max = 4000000;
@@ -619,7 +619,7 @@ static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
priv->pclk_max = 8000000;
}
- if (code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ if (code == MEDIA_BUS_FMT_SBGGR8_1X8)
priv->colorspace = V4L2_COLORSPACE_SRGB;
else if (code != 0)
priv->colorspace = V4L2_COLORSPACE_JPEG;
@@ -697,18 +697,18 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd,
mf->field = V4L2_FIELD_NONE;
switch (mf->code) {
- case V4L2_MBUS_FMT_Y10_1X10:
- mf->code = V4L2_MBUS_FMT_Y8_1X8;
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_Y10_1X10:
+ mf->code = MEDIA_BUS_FMT_Y8_1X8;
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
break;
default:
- mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
+ mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
}
@@ -717,7 +717,7 @@ static int ov6650_try_fmt(struct v4l2_subdev *sd,
}
static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(ov6650_codes))
return -EINVAL;
@@ -1013,7 +1013,7 @@ static int ov6650_probe(struct i2c_client *client,
priv->rect.width = W_CIF;
priv->rect.height = H_CIF;
priv->half_scale = false;
- priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ priv->code = MEDIA_BUS_FMT_YUYV8_2X8;
priv->colorspace = V4L2_COLORSPACE_JPEG;
priv->clk = v4l2_clk_get(&client->dev, "mclk");
diff --git a/drivers/media/i2c/soc_camera/ov772x.c b/drivers/media/i2c/soc_camera/ov772x.c
index 970a04e..8daac88 100644
--- a/drivers/media/i2c/soc_camera/ov772x.c
+++ b/drivers/media/i2c/soc_camera/ov772x.c
@@ -376,7 +376,7 @@
*/
struct ov772x_color_format {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
u8 dsp3;
u8 dsp4;
@@ -408,7 +408,7 @@ struct ov772x_priv {
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_YUV,
@@ -416,7 +416,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = UV_ON,
.dsp4 = DSP_OFMT_YUV,
@@ -424,7 +424,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_YUV,
@@ -432,7 +432,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_YUV,
@@ -440,7 +440,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_YUV,
@@ -448,7 +448,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
.com7 = FMT_RGB555 | OFMT_RGB,
},
{
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_YUV,
@@ -456,7 +456,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
.com7 = FMT_RGB565 | OFMT_RGB,
},
{
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_YUV,
@@ -468,7 +468,7 @@ static const struct ov772x_color_format ov772x_cfmts[] = {
* regardless of the COM7 value. We can thus only support 10-bit
* Bayer until someone figures it out.
*/
- .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
.colorspace = V4L2_COLORSPACE_SRGB,
.dsp3 = 0x0,
.dsp4 = DSP_OFMT_RAW10,
@@ -990,7 +990,7 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
};
static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(ov772x_cfmts))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/ov9640.c b/drivers/media/i2c/soc_camera/ov9640.c
index bc74224..aa93d2e 100644
--- a/drivers/media/i2c/soc_camera/ov9640.c
+++ b/drivers/media/i2c/soc_camera/ov9640.c
@@ -159,10 +159,10 @@ static const struct ov9640_reg ov9640_regs_rgb[] = {
{ OV9640_MTXS, 0x65 },
};
-static enum v4l2_mbus_pixelcode ov9640_codes[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
- V4L2_MBUS_FMT_RGB565_2X8_LE,
+static u32 ov9640_codes[] = {
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
+ MEDIA_BUS_FMT_RGB565_2X8_LE,
};
/* read a register */
@@ -351,22 +351,22 @@ static void ov9640_res_roundup(u32 *width, u32 *height)
}
/* Prepare necessary register changes depending on color encoding */
-static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
+static void ov9640_alter_regs(u32 code,
struct ov9640_reg_alt *alt)
{
switch (code) {
default:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
alt->com12 = OV9640_COM12_YUV_AVG;
alt->com13 = OV9640_COM13_Y_DELAY_EN |
OV9640_COM13_YUV_DLY(0x01);
break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
alt->com7 = OV9640_COM7_RGB;
alt->com13 = OV9640_COM13_RGB_AVG;
alt->com15 = OV9640_COM15_RGB_555;
break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
alt->com7 = OV9640_COM7_RGB;
alt->com13 = OV9640_COM13_RGB_AVG;
alt->com15 = OV9640_COM15_RGB_565;
@@ -376,7 +376,7 @@ static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
/* Setup registers according to resolution and color encoding */
static int ov9640_write_regs(struct i2c_client *client, u32 width,
- enum v4l2_mbus_pixelcode code, struct ov9640_reg_alt *alts)
+ u32 code, struct ov9640_reg_alt *alts)
{
const struct ov9640_reg *ov9640_regs, *matrix_regs;
int ov9640_regs_len, matrix_regs_len;
@@ -419,7 +419,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width,
}
/* select color matrix configuration for given color encoding */
- if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ if (code == MEDIA_BUS_FMT_UYVY8_2X8) {
matrix_regs = ov9640_regs_yuv;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
} else {
@@ -487,7 +487,7 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9640_reg_alt alts = {0};
enum v4l2_colorspace cspace;
- enum v4l2_mbus_pixelcode code = mf->code;
+ u32 code = mf->code;
int ret;
ov9640_res_roundup(&mf->width, &mf->height);
@@ -500,13 +500,13 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
return ret;
switch (code) {
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
cspace = V4L2_COLORSPACE_SRGB;
break;
default:
- code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ code = MEDIA_BUS_FMT_UYVY8_2X8;
+ case MEDIA_BUS_FMT_UYVY8_2X8:
cspace = V4L2_COLORSPACE_JPEG;
}
@@ -527,13 +527,13 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
mf->field = V4L2_FIELD_NONE;
switch (mf->code) {
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
+ case MEDIA_BUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
@@ -541,7 +541,7 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
}
static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(ov9640_codes))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/ov9740.c b/drivers/media/i2c/soc_camera/ov9740.c
index ee9eb63..841dc55 100644
--- a/drivers/media/i2c/soc_camera/ov9740.c
+++ b/drivers/media/i2c/soc_camera/ov9740.c
@@ -392,8 +392,8 @@ static const struct ov9740_reg ov9740_defaults[] = {
{ OV9740_ISP_CTRL19, 0x02 },
};
-static enum v4l2_mbus_pixelcode ov9740_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
+static u32 ov9740_codes[] = {
+ MEDIA_BUS_FMT_YUYV8_2X8,
};
/* read a register */
@@ -674,13 +674,13 @@ static int ov9740_s_fmt(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9740_priv *priv = to_ov9740(sd);
enum v4l2_colorspace cspace;
- enum v4l2_mbus_pixelcode code = mf->code;
+ u32 code = mf->code;
int ret;
ov9740_res_roundup(&mf->width, &mf->height);
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
cspace = V4L2_COLORSPACE_SRGB;
break;
default:
@@ -710,14 +710,14 @@ static int ov9740_try_fmt(struct v4l2_subdev *sd,
ov9740_res_roundup(&mf->width, &mf->height);
mf->field = V4L2_FIELD_NONE;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
mf->colorspace = V4L2_COLORSPACE_SRGB;
return 0;
}
static int ov9740_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(ov9740_codes))
return -EINVAL;
diff --git a/drivers/media/i2c/soc_camera/rj54n1cb0c.c b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
index 7e6d978..1752428 100644
--- a/drivers/media/i2c/soc_camera/rj54n1cb0c.c
+++ b/drivers/media/i2c/soc_camera/rj54n1cb0c.c
@@ -111,13 +111,13 @@
/* RJ54N1CB0C has only one fixed colorspace per pixelcode */
struct rj54n1_datafmt {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
};
/* Find a data format by a pixel code in an array */
static const struct rj54n1_datafmt *rj54n1_find_datafmt(
- enum v4l2_mbus_pixelcode code, const struct rj54n1_datafmt *fmt,
+ u32 code, const struct rj54n1_datafmt *fmt,
int n)
{
int i;
@@ -129,15 +129,15 @@ static const struct rj54n1_datafmt *rj54n1_find_datafmt(
}
static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
- {V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {MEDIA_BUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE, V4L2_COLORSPACE_SRGB},
+ {MEDIA_BUS_FMT_SBGGR10_1X10, V4L2_COLORSPACE_SRGB},
};
struct rj54n1_clock_div {
@@ -486,7 +486,7 @@ static int reg_write_multiple(struct i2c_client *client,
}
static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(rj54n1_colour_fmts))
return -EINVAL;
@@ -965,11 +965,11 @@ static int rj54n1_try_fmt(struct v4l2_subdev *sd,
struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct rj54n1_datafmt *fmt;
- int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE ||
- mf->code == V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE;
+ int align = mf->code == MEDIA_BUS_FMT_SBGGR10_1X10 ||
+ mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE ||
+ mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE ||
+ mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE ||
+ mf->code == MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE;
dev_dbg(&client->dev, "%s: code = %d, width = %u, height = %u\n",
__func__, mf->code, mf->width, mf->height);
@@ -1025,55 +1025,55 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
switch (mf->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
ret = reg_write(client, RJ54N1_OUT_SEL, 0x11);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 0);
break;
- case V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE:
ret = reg_write(client, RJ54N1_OUT_SEL, 4);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
if (!ret)
ret = reg_write(client, RJ54N1_RA_SEL_UL, 8);
break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
ret = reg_write(client, RJ54N1_OUT_SEL, 5);
break;
default:
@@ -1083,7 +1083,7 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
/* Special case: a raw mode with 10 bits of data per clock tick */
if (!ret)
ret = reg_set(client, RJ54N1_OCLK_SEL_EN,
- (mf->code == V4L2_MBUS_FMT_SBGGR10_1X10) << 1, 2);
+ (mf->code == MEDIA_BUS_FMT_SBGGR10_1X10) << 1, 2);
if (ret < 0)
return ret;
diff --git a/drivers/media/i2c/soc_camera/tw9910.c b/drivers/media/i2c/soc_camera/tw9910.c
index 416402e..9b85321 100644
--- a/drivers/media/i2c/soc_camera/tw9910.c
+++ b/drivers/media/i2c/soc_camera/tw9910.c
@@ -705,7 +705,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
mf->width = priv->scale->width;
mf->height = priv->scale->height;
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mf->field = V4L2_FIELD_INTERLACED_BT;
@@ -724,7 +724,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
/*
* check color format
*/
- if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
+ if (mf->code != MEDIA_BUS_FMT_UYVY8_2X8)
return -EINVAL;
mf->colorspace = V4L2_COLORSPACE_JPEG;
@@ -751,7 +751,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
return -EINVAL;
}
- mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ mf->code = MEDIA_BUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
/*
@@ -822,12 +822,12 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
};
static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_UYVY8_2X8;
+ *code = MEDIA_BUS_FMT_UYVY8_2X8;
return 0;
}
diff --git a/drivers/media/i2c/sr030pc30.c b/drivers/media/i2c/sr030pc30.c
index 118f8ee..10c735c 100644
--- a/drivers/media/i2c/sr030pc30.c
+++ b/drivers/media/i2c/sr030pc30.c
@@ -165,7 +165,7 @@ struct sr030pc30_info {
};
struct sr030pc30_format {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
enum v4l2_colorspace colorspace;
u16 ispctl1_reg;
};
@@ -201,23 +201,23 @@ static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
/* supported pixel formats */
static const struct sr030pc30_format sr030pc30_formats[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x03,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x02,
}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0,
}, {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x01,
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
.colorspace = V4L2_COLORSPACE_JPEG,
.ispctl1_reg = 0x40,
},
@@ -472,7 +472,7 @@ static int sr030pc30_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (!code || index >= ARRAY_SIZE(sr030pc30_formats))
return -EINVAL;
diff --git a/drivers/media/i2c/tvp514x.c b/drivers/media/i2c/tvp514x.c
index b9dabc9..2042042 100644
--- a/drivers/media/i2c/tvp514x.c
+++ b/drivers/media/i2c/tvp514x.c
@@ -756,12 +756,12 @@ static int tvp514x_s_ctrl(struct v4l2_ctrl *ctrl)
*/
static int
tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV10_2X10;
+ *code = MEDIA_BUS_FMT_YUYV10_2X10;
return 0;
}
@@ -784,7 +784,7 @@ tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
/* Calculate height and width based on current standard */
current_std = decoder->current_std;
- f->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ f->code = MEDIA_BUS_FMT_YUYV8_2X8;
f->width = decoder->std_list[current_std].width;
f->height = decoder->std_list[current_std].height;
f->field = V4L2_FIELD_INTERLACED;
@@ -942,7 +942,7 @@ static int tvp514x_enum_mbus_code(struct v4l2_subdev *sd,
if (index != 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ code->code = MEDIA_BUS_FMT_YUYV8_2X8;
return 0;
}
@@ -967,7 +967,7 @@ static int tvp514x_get_pad_format(struct v4l2_subdev *sd,
return 0;
}
- format->format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ format->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
format->format.width = tvp514x_std_list[decoder->current_std].width;
format->format.height = tvp514x_std_list[decoder->current_std].height;
format->format.colorspace = V4L2_COLORSPACE_SMPTE170M;
@@ -991,7 +991,7 @@ static int tvp514x_set_pad_format(struct v4l2_subdev *sd,
struct tvp514x_decoder *decoder = to_decoder(sd);
if (fmt->format.field != V4L2_FIELD_INTERLACED ||
- fmt->format.code != V4L2_MBUS_FMT_YUYV8_2X8 ||
+ fmt->format.code != MEDIA_BUS_FMT_YUYV8_2X8 ||
fmt->format.colorspace != V4L2_COLORSPACE_SMPTE170M ||
fmt->format.width != tvp514x_std_list[decoder->current_std].width ||
fmt->format.height != tvp514x_std_list[decoder->current_std].height)
diff --git a/drivers/media/i2c/tvp5150.c b/drivers/media/i2c/tvp5150.c
index 193e7d6..68cdab9 100644
--- a/drivers/media/i2c/tvp5150.c
+++ b/drivers/media/i2c/tvp5150.c
@@ -818,12 +818,12 @@ static v4l2_std_id tvp5150_read_std(struct v4l2_subdev *sd)
}
static int tvp5150_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_UYVY8_2X8;
+ *code = MEDIA_BUS_FMT_UYVY8_2X8;
return 0;
}
@@ -840,7 +840,7 @@ static int tvp5150_mbus_fmt(struct v4l2_subdev *sd,
f->width = decoder->rect.width;
f->height = decoder->rect.height;
- f->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ f->code = MEDIA_BUS_FMT_UYVY8_2X8;
f->field = V4L2_FIELD_SEQ_TB;
f->colorspace = V4L2_COLORSPACE_SMPTE170M;
diff --git a/drivers/media/i2c/tvp7002.c b/drivers/media/i2c/tvp7002.c
index 51bac76..fe4870e 100644
--- a/drivers/media/i2c/tvp7002.c
+++ b/drivers/media/i2c/tvp7002.c
@@ -626,7 +626,7 @@ static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f
f->width = bt->width;
f->height = bt->height;
- f->code = V4L2_MBUS_FMT_YUYV10_1X20;
+ f->code = MEDIA_BUS_FMT_YUYV10_1X20;
f->field = device->current_timings->scanmode;
f->colorspace = device->current_timings->color_space;
@@ -756,12 +756,12 @@ static int tvp7002_s_register(struct v4l2_subdev *sd,
*/
static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
/* Check requested format index is within range */
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV10_1X20;
+ *code = MEDIA_BUS_FMT_YUYV10_1X20;
return 0;
}
@@ -859,7 +859,7 @@ tvp7002_enum_mbus_code(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
if (code->index != 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_YUYV10_1X20;
+ code->code = MEDIA_BUS_FMT_YUYV10_1X20;
return 0;
}
@@ -878,7 +878,7 @@ tvp7002_get_pad_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
{
struct tvp7002 *tvp7002 = to_tvp7002(sd);
- fmt->format.code = V4L2_MBUS_FMT_YUYV10_1X20;
+ fmt->format.code = MEDIA_BUS_FMT_YUYV10_1X20;
fmt->format.width = tvp7002->current_timings->timings.bt.width;
fmt->format.height = tvp7002->current_timings->timings.bt.height;
fmt->format.field = tvp7002->current_timings->scanmode;
diff --git a/drivers/media/i2c/vs6624.c b/drivers/media/i2c/vs6624.c
index 373f2df..00e7f04 100644
--- a/drivers/media/i2c/vs6624.c
+++ b/drivers/media/i2c/vs6624.c
@@ -45,19 +45,19 @@ struct vs6624 {
};
static const struct vs6624_format {
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
enum v4l2_colorspace colorspace;
} vs6624_formats[] = {
{
- .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
},
{
- .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.colorspace = V4L2_COLORSPACE_SRGB,
},
};
@@ -65,7 +65,7 @@ static const struct vs6624_format {
static struct v4l2_mbus_framefmt vs6624_default_fmt = {
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.field = V4L2_FIELD_NONE,
.colorspace = V4L2_COLORSPACE_JPEG,
};
@@ -558,7 +558,7 @@ static int vs6624_s_ctrl(struct v4l2_ctrl *ctrl)
}
static int vs6624_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
if (index >= ARRAY_SIZE(vs6624_formats))
return -EINVAL;
@@ -605,15 +605,15 @@ static int vs6624_s_mbus_fmt(struct v4l2_subdev *sd,
/* set image format */
switch (fmt->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
vs6624_write(sd, VS6624_YUV_SETUP, 0x1);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
vs6624_write(sd, VS6624_IMG_FMT0, 0x0);
vs6624_write(sd, VS6624_YUV_SETUP, 0x3);
break;
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
vs6624_write(sd, VS6624_IMG_FMT0, 0x4);
vs6624_write(sd, VS6624_RGB_SETUP, 0x0);
break;
diff --git a/drivers/media/media-entity.c b/drivers/media/media-entity.c
index 37c334e..4d8e01c 100644
--- a/drivers/media/media-entity.c
+++ b/drivers/media/media-entity.c
@@ -279,8 +279,14 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
continue;
ret = entity->ops->link_validate(link);
- if (ret < 0 && ret != -ENOIOCTLCMD)
+ if (ret < 0 && ret != -ENOIOCTLCMD) {
+ dev_dbg(entity->parent->dev,
+ "link validation failed for \"%s\":%u -> \"%s\":%u, error %d\n",
+ entity->name, link->source->index,
+ link->sink->entity->name,
+ link->sink->index, ret);
goto error;
+ }
}
/* Either no links or validated links are fine. */
@@ -288,6 +294,11 @@ __must_check int media_entity_pipeline_start(struct media_entity *entity,
if (!bitmap_full(active, entity->num_pads)) {
ret = -EPIPE;
+ dev_dbg(entity->parent->dev,
+ "\"%s\":%u must be connected by an enabled link\n",
+ entity->name,
+ (unsigned)find_first_zero_bit(
+ active, entity->num_pads));
goto error;
}
}
diff --git a/drivers/media/pci/Kconfig b/drivers/media/pci/Kconfig
index f8cec8e..218144a 100644
--- a/drivers/media/pci/Kconfig
+++ b/drivers/media/pci/Kconfig
@@ -46,6 +46,7 @@ source "drivers/media/pci/pt3/Kconfig"
source "drivers/media/pci/mantis/Kconfig"
source "drivers/media/pci/ngene/Kconfig"
source "drivers/media/pci/ddbridge/Kconfig"
+source "drivers/media/pci/smipcie/Kconfig"
endif
endif #MEDIA_PCI_SUPPORT
diff --git a/drivers/media/pci/Makefile b/drivers/media/pci/Makefile
index a12926e..0baf0d29 100644
--- a/drivers/media/pci/Makefile
+++ b/drivers/media/pci/Makefile
@@ -11,7 +11,8 @@ obj-y += ttpci/ \
mantis/ \
ngene/ \
ddbridge/ \
- saa7146/
+ saa7146/ \
+ smipcie/
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_ZORAN) += zoran/
diff --git a/drivers/media/pci/bt8xx/bttv-cards.c b/drivers/media/pci/bt8xx/bttv-cards.c
index d8ec583..4105560 100644
--- a/drivers/media/pci/bt8xx/bttv-cards.c
+++ b/drivers/media/pci/bt8xx/bttv-cards.c
@@ -3870,10 +3870,10 @@ static void osprey_eeprom(struct bttv *btv, const u8 ee[256])
} else {
unsigned short type;
- for (i = 4*16; i < 8*16; i += 16) {
- u16 checksum = ip_compute_csum(ee + i, 16);
+ for (i = 4 * 16; i < 8 * 16; i += 16) {
+ u16 checksum = (__force u16)ip_compute_csum(ee + i, 16);
- if ((checksum&0xff) + (checksum>>8) == 0xff)
+ if ((checksum & 0xff) + (checksum >> 8) == 0xff)
break;
}
if (i >= 8*16)
diff --git a/drivers/media/pci/bt8xx/bttv-risc.c b/drivers/media/pci/bt8xx/bttv-risc.c
index 82cc47d..4d3f05a 100644
--- a/drivers/media/pci/bt8xx/bttv-risc.c
+++ b/drivers/media/pci/bt8xx/bttv-risc.c
@@ -84,7 +84,7 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
continue;
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
if (bpl <= sg_dma_len(sg)-offset) {
/* fits into current chunk */
@@ -100,13 +100,13 @@ bttv_risc_packed(struct bttv *btv, struct btcx_riscmem *risc,
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
todo -= (sg_dma_len(sg)-offset);
offset = 0;
- sg++;
+ sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++)=cpu_to_le32(BT848_RISC_WRITE|
sg_dma_len(sg));
*(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
*(rp++)=cpu_to_le32(BT848_RISC_WRITE|BT848_RISC_EOL|
todo);
@@ -187,15 +187,15 @@ bttv_risc_planar(struct bttv *btv, struct btcx_riscmem *risc,
/* go to next sg entry if needed */
while (yoffset && yoffset >= sg_dma_len(ysg)) {
yoffset -= sg_dma_len(ysg);
- ysg++;
+ ysg = sg_next(ysg);
}
while (uoffset && uoffset >= sg_dma_len(usg)) {
uoffset -= sg_dma_len(usg);
- usg++;
+ usg = sg_next(usg);
}
while (voffset && voffset >= sg_dma_len(vsg)) {
voffset -= sg_dma_len(vsg);
- vsg++;
+ vsg = sg_next(vsg);
}
/* calculate max number of bytes we can write */
diff --git a/drivers/media/pci/cx18/cx18-av-core.c b/drivers/media/pci/cx18/cx18-av-core.c
index 2d3afe0..5a55630 100644
--- a/drivers/media/pci/cx18/cx18-av-core.c
+++ b/drivers/media/pci/cx18/cx18-av-core.c
@@ -490,8 +490,8 @@ void cx18_av_std_setup(struct cx18 *cx)
/* Sets horizontal blanking delay and active lines */
cx18_av_write(cx, 0x470, hblank);
- cx18_av_write(cx, 0x471, 0xff & (((hblank >> 8) & 0x3) |
- (hactive << 4)));
+ cx18_av_write(cx, 0x471,
+ (((hblank >> 8) & 0x3) | (hactive << 4)) & 0xff);
cx18_av_write(cx, 0x472, hactive >> 4);
/* Sets burst gate delay */
@@ -499,14 +499,14 @@ void cx18_av_std_setup(struct cx18 *cx)
/* Sets vertical blanking delay and active duration */
cx18_av_write(cx, 0x474, vblank);
- cx18_av_write(cx, 0x475, 0xff & (((vblank >> 8) & 0x3) |
- (vactive << 4)));
+ cx18_av_write(cx, 0x475,
+ (((vblank >> 8) & 0x3) | (vactive << 4)) & 0xff);
cx18_av_write(cx, 0x476, vactive >> 4);
cx18_av_write(cx, 0x477, vblank656);
/* Sets src decimation rate */
- cx18_av_write(cx, 0x478, 0xff & src_decimation);
- cx18_av_write(cx, 0x479, 0xff & (src_decimation >> 8));
+ cx18_av_write(cx, 0x478, src_decimation & 0xff);
+ cx18_av_write(cx, 0x479, (src_decimation >> 8) & 0xff);
/* Sets Luma and UV Low pass filters */
cx18_av_write(cx, 0x47a, luma_lpf << 6 | ((uv_lpf << 4) & 0x30));
@@ -516,8 +516,8 @@ void cx18_av_std_setup(struct cx18 *cx)
/* Sets SC Step*/
cx18_av_write(cx, 0x47c, sc);
- cx18_av_write(cx, 0x47d, 0xff & sc >> 8);
- cx18_av_write(cx, 0x47e, 0xff & sc >> 16);
+ cx18_av_write(cx, 0x47d, (sc >> 8) & 0xff);
+ cx18_av_write(cx, 0x47e, (sc >> 16) & 0xff);
if (std & V4L2_STD_625_50) {
state->slicer_line_delay = 1;
@@ -952,7 +952,7 @@ static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
int is_50Hz = !(state->std & V4L2_STD_525_60);
- if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ if (fmt->code != MEDIA_BUS_FMT_FIXED)
return -EINVAL;
fmt->field = V4L2_FIELD_INTERLACED;
diff --git a/drivers/media/pci/cx18/cx18-cards.h b/drivers/media/pci/cx18/cx18-cards.h
index add7391..f6b921f 100644
--- a/drivers/media/pci/cx18/cx18-cards.h
+++ b/drivers/media/pci/cx18/cx18-cards.h
@@ -57,7 +57,8 @@
/* V4L2 capability aliases */
#define CX18_CAP_ENCODER (V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_TUNER | \
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE | \
- V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE)
+ V4L2_CAP_STREAMING | V4L2_CAP_VBI_CAPTURE | \
+ V4L2_CAP_SLICED_VBI_CAPTURE)
struct cx18_card_video_input {
u8 video_type; /* video input type */
diff --git a/drivers/media/pci/cx18/cx18-controls.c b/drivers/media/pci/cx18/cx18-controls.c
index 282a3d2..4aeb7c6 100644
--- a/drivers/media/pci/cx18/cx18-controls.c
+++ b/drivers/media/pci/cx18/cx18-controls.c
@@ -98,7 +98,7 @@ static int cx18_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
/* fix videodecoder resolution */
fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
fmt.height = cxhdl->height;
- fmt.code = V4L2_MBUS_FMT_FIXED;
+ fmt.code = MEDIA_BUS_FMT_FIXED;
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-driver.h b/drivers/media/pci/cx18/cx18-driver.h
index 57f4688..dcfd7a1 100644
--- a/drivers/media/pci/cx18/cx18-driver.h
+++ b/drivers/media/pci/cx18/cx18-driver.h
@@ -379,6 +379,7 @@ struct cx18_stream {
const char *name; /* name of the stream */
int type; /* stream type */
u32 handle; /* task handle */
+ u32 v4l2_dev_caps; /* device capabilities */
unsigned int mdl_base_idx;
u32 id;
diff --git a/drivers/media/pci/cx18/cx18-ioctl.c b/drivers/media/pci/cx18/cx18-ioctl.c
index 6f2b590..b8e4b68 100644
--- a/drivers/media/pci/cx18/cx18-ioctl.c
+++ b/drivers/media/pci/cx18/cx18-ioctl.c
@@ -294,7 +294,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
mbus_fmt.width = cx->cxhdl.width = w;
mbus_fmt.height = cx->cxhdl.height = h;
- mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ mbus_fmt.code = MEDIA_BUS_FMT_FIXED;
v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
return cx18_g_fmt_vid_cap(file, fh, fmt);
}
@@ -393,15 +393,16 @@ static int cx18_querycap(struct file *file, void *fh,
struct v4l2_capability *vcap)
{
struct cx18_open_id *id = fh2id(fh);
+ struct cx18_stream *s = video_drvdata(file);
struct cx18 *cx = id->cx;
strlcpy(vcap->driver, CX18_DRIVER_NAME, sizeof(vcap->driver));
strlcpy(vcap->card, cx->card_name, sizeof(vcap->card));
snprintf(vcap->bus_info, sizeof(vcap->bus_info),
"PCI:%s", pci_name(cx->pci_dev));
- vcap->capabilities = cx->v4l2_cap; /* capabilities */
- if (id->type == CX18_ENC_STREAM_TYPE_YUV)
- vcap->capabilities |= V4L2_CAP_STREAMING;
+ vcap->capabilities = cx->v4l2_cap; /* capabilities */
+ vcap->device_caps = s->v4l2_dev_caps; /* device capabilities */
+ vcap->capabilities |= V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/pci/cx18/cx18-streams.c b/drivers/media/pci/cx18/cx18-streams.c
index f3541b5..369445f 100644
--- a/drivers/media/pci/cx18/cx18-streams.c
+++ b/drivers/media/pci/cx18/cx18-streams.c
@@ -58,11 +58,14 @@ static struct {
int vfl_type;
int num_offset;
int dma;
+ u32 caps;
} cx18_stream_info[] = {
{ /* CX18_ENC_STREAM_TYPE_MPG */
"encoder MPEG",
VFL_TYPE_GRABBER, 0,
PCI_DMA_FROMDEVICE,
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_AUDIO | V4L2_CAP_TUNER
},
{ /* CX18_ENC_STREAM_TYPE_TS */
"TS",
@@ -73,11 +76,15 @@ static struct {
"encoder YUV",
VFL_TYPE_GRABBER, CX18_V4L2_ENC_YUV_OFFSET,
PCI_DMA_FROMDEVICE,
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING | V4L2_CAP_AUDIO | V4L2_CAP_TUNER
},
{ /* CX18_ENC_STREAM_TYPE_VBI */
"encoder VBI",
VFL_TYPE_VBI, 0,
PCI_DMA_FROMDEVICE,
+ V4L2_CAP_VBI_CAPTURE | V4L2_CAP_SLICED_VBI_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_TUNER
},
{ /* CX18_ENC_STREAM_TYPE_PCM */
"encoder PCM audio",
@@ -93,6 +100,7 @@ static struct {
"encoder radio",
VFL_TYPE_RADIO, 0,
PCI_DMA_NONE,
+ V4L2_CAP_RADIO | V4L2_CAP_TUNER
},
};
@@ -260,6 +268,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
s->handle = CX18_INVALID_TASK_HANDLE;
s->dma = cx18_stream_info[type].dma;
+ s->v4l2_dev_caps = cx18_stream_info[type].caps;
s->buffers = cx->stream_buffers[type];
s->buf_size = cx->stream_buf_size[type];
INIT_LIST_HEAD(&s->buf_pool);
diff --git a/drivers/media/pci/cx23885/cx23885-417.c b/drivers/media/pci/cx23885/cx23885-417.c
index 3948db3..e4901a5 100644
--- a/drivers/media/pci/cx23885/cx23885-417.c
+++ b/drivers/media/pci/cx23885/cx23885-417.c
@@ -1148,6 +1148,7 @@ static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
dev->ts1.ts_packet_count = mpeglines;
*num_planes = 1;
sizes[0] = mpeglinesize * mpeglines;
+ alloc_ctxs[0] = dev->alloc_ctx;
*num_buffers = mpegbufs;
return 0;
}
@@ -1166,11 +1167,8 @@ static void buffer_finish(struct vb2_buffer *vb)
struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf = container_of(vb,
struct cx23885_buffer, vb);
- struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
cx23885_free_buffer(dev, buf);
-
- dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
static void buffer_queue(struct vb2_buffer *vb)
diff --git a/drivers/media/pci/cx23885/cx23885-cards.c b/drivers/media/pci/cx23885/cx23885-cards.c
index 88c257d..db99ca2 100644
--- a/drivers/media/pci/cx23885/cx23885-cards.c
+++ b/drivers/media/pci/cx23885/cx23885-cards.c
@@ -680,6 +680,32 @@ struct cx23885_board cx23885_boards[] = {
.portb = CX23885_MPEG_DVB,
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_DVBSKY_T980C] = {
+ .name = "DVBSky T980C",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVBSKY_S950C] = {
+ .name = "DVBSky S950C",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_TT_CT2_4500_CI] = {
+ .name = "Technotrend TT-budget CT2-4500 CI",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVBSKY_S950] = {
+ .name = "DVBSky S950",
+ .portb = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVBSKY_S952] = {
+ .name = "DVBSky S952",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_DVBSKY_T982] = {
+ .name = "DVBSky T982",
+ .portb = CX23885_MPEG_DVB,
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -939,6 +965,30 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x4254,
.subdevice = 0x9580,
.card = CX23885_BOARD_DVBSKY_T9580,
+ }, {
+ .subvendor = 0x4254,
+ .subdevice = 0x980c,
+ .card = CX23885_BOARD_DVBSKY_T980C,
+ }, {
+ .subvendor = 0x4254,
+ .subdevice = 0x950c,
+ .card = CX23885_BOARD_DVBSKY_S950C,
+ }, {
+ .subvendor = 0x13c2,
+ .subdevice = 0x3013,
+ .card = CX23885_BOARD_TT_CT2_4500_CI,
+ }, {
+ .subvendor = 0x4254,
+ .subdevice = 0x0950,
+ .card = CX23885_BOARD_DVBSKY_S950,
+ }, {
+ .subvendor = 0x4254,
+ .subdevice = 0x0952,
+ .card = CX23885_BOARD_DVBSKY_S952,
+ }, {
+ .subvendor = 0x4254,
+ .subdevice = 0x0982,
+ .card = CX23885_BOARD_DVBSKY_T982,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -1534,6 +1584,8 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
mdelay(60);
break;
case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
/* enable GPIO3-18 pins */
cx_write(MC417_CTL, 0x00000037);
cx23885_gpio_enable(dev, GPIO_2 | GPIO_11, 1);
@@ -1541,6 +1593,45 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
mdelay(100);
cx23885_gpio_set(dev, GPIO_2 | GPIO_11);
break;
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ /*
+ * GPIO-0 INTA from CiMax, input
+ * GPIO-1 reset CiMax, output, high active
+ * GPIO-2 reset demod, output, low active
+ * GPIO-3 to GPIO-10 data/addr for CAM
+ * GPIO-11 ~CS0 to CiMax1
+ * GPIO-12 ~CS1 to CiMax2
+ * GPIO-13 ADL0 load LSB addr
+ * GPIO-14 ADL1 load MSB addr
+ * GPIO-15 ~RDY from CiMax
+ * GPIO-17 ~RD to CiMax
+ * GPIO-18 ~WR to CiMax
+ */
+
+ cx_set(GP0_IO, 0x00060002); /* GPIO 1/2 as output */
+ cx_clear(GP0_IO, 0x00010004); /* GPIO 0 as input */
+ mdelay(100); /* reset delay */
+ cx_set(GP0_IO, 0x00060004); /* GPIO as out, reset high */
+ cx_clear(GP0_IO, 0x00010002);
+ cx_write(MC417_CTL, 0x00000037); /* enable GPIO3-18 pins */
+
+ /* GPIO-15 IN as ~ACK, rest as OUT */
+ cx_write(MC417_OEN, 0x00001000);
+
+ /* ~RD, ~WR high; ADL0, ADL1 low; ~CS0, ~CS1 high */
+ cx_write(MC417_RWD, 0x0000c300);
+
+ /* enable irq */
+ cx_write(GPIO_ISM, 0x00000000); /* INTERRUPTS active low */
+ break;
+ case CX23885_BOARD_DVBSKY_S950:
+ cx23885_gpio_enable(dev, GPIO_2, 1);
+ cx23885_gpio_clear(dev, GPIO_2);
+ msleep(100);
+ cx23885_gpio_set(dev, GPIO_2);
+ break;
}
}
@@ -1621,6 +1712,13 @@ int cx23885_ir_init(struct cx23885_dev *dev)
case CX23885_BOARD_MYGICA_X8507:
case CX23885_BOARD_TBS_6980:
case CX23885_BOARD_TBS_6981:
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
if (!enable_885_ir)
break;
dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
@@ -1667,6 +1765,13 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
case CX23885_BOARD_MYGICA_X8507:
case CX23885_BOARD_TBS_6980:
case CX23885_BOARD_TBS_6981:
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
/* sd_ir is a duplicate pointer to the AV Core, just clear it */
dev->sd_ir = NULL;
@@ -1714,6 +1819,13 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
case CX23885_BOARD_MYGICA_X8507:
case CX23885_BOARD_TBS_6980:
case CX23885_BOARD_TBS_6981:
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
if (dev->sd_ir)
cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
break;
@@ -1817,6 +1929,10 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_TEVII_S471:
case CX23885_BOARD_DVBWORLD_2005:
case CX23885_BOARD_PROF_8000:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
ts1->gen_ctrl_val = 0x5; /* Parallel */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -1865,6 +1981,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T982:
ts1->gen_ctrl_val = 0x5; /* Parallel */
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
@@ -1872,6 +1989,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_DVBSKY_S952:
+ ts1->gen_ctrl_val = 0x5; /* Parallel */
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ ts2->gen_ctrl_val = 0xe; /* Serial bus */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -1935,6 +2060,12 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_TBS_6980:
case CX23885_BOARD_TBS_6981:
case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
"cx25840", 0x88 >> 1, NULL);
diff --git a/drivers/media/pci/cx23885/cx23885-core.c b/drivers/media/pci/cx23885/cx23885-core.c
index 331edda..1d9d0f8 100644
--- a/drivers/media/pci/cx23885/cx23885-core.c
+++ b/drivers/media/pci/cx23885/cx23885-core.c
@@ -1078,7 +1078,7 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
if (lpi && line > 0 && !(line % lpi))
@@ -1101,14 +1101,14 @@ static __le32 *cx23885_risc_field(__le32 *rp, struct scatterlist *sglist,
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg)-offset);
offset = 0;
- sg++;
+ sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
*(rp++) = cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
*(rp++) = cpu_to_le32(sg_dma_address(sg));
@@ -1453,17 +1453,12 @@ int cx23885_buf_prepare(struct cx23885_buffer *buf, struct cx23885_tsport *port)
struct cx23885_dev *dev = port->dev;
int size = port->ts_packet_size * port->ts_packet_count;
struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
- int rc;
dprintk(1, "%s: %p\n", __func__, buf);
if (vb2_plane_size(&buf->vb, 0) < size)
return -EINVAL;
vb2_set_plane_payload(&buf->vb, 0, size);
- rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
- if (!rc)
- return -EIO;
-
cx23885_risc_databuffer(dev->pci, &buf->risc,
sgt->sgl,
port->ts_packet_size, port->ts_packet_count, 0);
@@ -1997,9 +1992,14 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
if (!pci_dma_supported(pci_dev, 0xffffffff)) {
printk("%s/0: Oops: no 32bit PCI DMA ???\n", dev->name);
err = -EIO;
- goto fail_irq;
+ goto fail_context;
}
+ dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
+ if (IS_ERR(dev->alloc_ctx)) {
+ err = PTR_ERR(dev->alloc_ctx);
+ goto fail_context;
+ }
err = request_irq(pci_dev->irq, cx23885_irq,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
@@ -2028,6 +2028,8 @@ static int cx23885_initdev(struct pci_dev *pci_dev,
return 0;
fail_irq:
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
+fail_context:
cx23885_dev_unregister(dev);
fail_ctrl:
v4l2_ctrl_handler_free(hdl);
@@ -2053,6 +2055,7 @@ static void cx23885_finidev(struct pci_dev *pci_dev)
free_irq(pci_dev->irq, dev);
cx23885_dev_unregister(dev);
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
v4l2_ctrl_handler_free(&dev->ctrl_handler);
v4l2_device_unregister(v4l2_dev);
kfree(dev);
diff --git a/drivers/media/pci/cx23885/cx23885-dvb.c b/drivers/media/pci/cx23885/cx23885-dvb.c
index 4cb9031..c47d182 100644
--- a/drivers/media/pci/cx23885/cx23885-dvb.c
+++ b/drivers/media/pci/cx23885/cx23885-dvb.c
@@ -71,6 +71,7 @@
#include "si2165.h"
#include "si2168.h"
#include "si2157.h"
+#include "sp2.h"
#include "m88ds3103.h"
#include "m88ts2022.h"
@@ -101,6 +102,7 @@ static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
port->ts_packet_count = 32;
*num_planes = 1;
sizes[0] = port->ts_packet_size * port->ts_packet_count;
+ alloc_ctxs[0] = port->dev->alloc_ctx;
*num_buffers = 32;
return 0;
}
@@ -121,11 +123,8 @@ static void buffer_finish(struct vb2_buffer *vb)
struct cx23885_dev *dev = port->dev;
struct cx23885_buffer *buf = container_of(vb,
struct cx23885_buffer, vb);
- struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
cx23885_free_buffer(dev, buf);
-
- dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
static void buffer_queue(struct vb2_buffer *vb)
@@ -616,6 +615,103 @@ static int dvbsky_t9580_set_voltage(struct dvb_frontend *fe,
return 0;
}
+static int dvbsky_s952_portc_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx23885_tsport *port = fe->dvb->priv;
+ struct cx23885_dev *dev = port->dev;
+
+ cx23885_gpio_enable(dev, GPIO_12 | GPIO_13, 1);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ cx23885_gpio_set(dev, GPIO_13);
+ cx23885_gpio_clear(dev, GPIO_12);
+ break;
+ case SEC_VOLTAGE_18:
+ cx23885_gpio_set(dev, GPIO_13);
+ cx23885_gpio_set(dev, GPIO_12);
+ break;
+ case SEC_VOLTAGE_OFF:
+ cx23885_gpio_clear(dev, GPIO_13);
+ cx23885_gpio_clear(dev, GPIO_12);
+ break;
+ }
+ /* call the frontend set_voltage function */
+ return port->fe_set_voltage(fe, voltage);
+}
+
+static int cx23885_sp2_ci_ctrl(void *priv, u8 read, int addr,
+ u8 data, int *mem)
+{
+ /* MC417 */
+ #define SP2_DATA 0x000000ff
+ #define SP2_WR 0x00008000
+ #define SP2_RD 0x00004000
+ #define SP2_ACK 0x00001000
+ #define SP2_ADHI 0x00000800
+ #define SP2_ADLO 0x00000400
+ #define SP2_CS1 0x00000200
+ #define SP2_CS0 0x00000100
+ #define SP2_EN_ALL 0x00001000
+ #define SP2_CTRL_OFF (SP2_CS1 | SP2_CS0 | SP2_WR | SP2_RD)
+
+ struct cx23885_tsport *port = priv;
+ struct cx23885_dev *dev = port->dev;
+ int ret;
+ int tmp = 0;
+ unsigned long timeout;
+
+ mutex_lock(&dev->gpio_lock);
+
+ /* write addr */
+ cx_write(MC417_OEN, SP2_EN_ALL);
+ cx_write(MC417_RWD, SP2_CTRL_OFF |
+ SP2_ADLO | (0xff & addr));
+ cx_clear(MC417_RWD, SP2_ADLO);
+ cx_write(MC417_RWD, SP2_CTRL_OFF |
+ SP2_ADHI | (0xff & (addr >> 8)));
+ cx_clear(MC417_RWD, SP2_ADHI);
+
+ if (read)
+ /* data in */
+ cx_write(MC417_OEN, SP2_EN_ALL | SP2_DATA);
+ else
+ /* data out */
+ cx_write(MC417_RWD, SP2_CTRL_OFF | data);
+
+ /* chip select 0 */
+ cx_clear(MC417_RWD, SP2_CS0);
+
+ /* read/write */
+ cx_clear(MC417_RWD, (read) ? SP2_RD : SP2_WR);
+
+ /* wait for a maximum of 1 msec */
+ timeout = jiffies + msecs_to_jiffies(1);
+ while (!time_after(jiffies, timeout)) {
+ tmp = cx_read(MC417_RWD);
+ if ((tmp & SP2_ACK) == 0)
+ break;
+ usleep_range(50, 100);
+ }
+
+ cx_set(MC417_RWD, SP2_CTRL_OFF);
+ *mem = tmp & 0xff;
+
+ mutex_unlock(&dev->gpio_lock);
+
+ if (!read) {
+ if (*mem < 0) {
+ ret = -EREMOTEIO;
+ goto err;
+ }
+ }
+
+ return 0;
+err:
+ return ret;
+}
+
static int cx23885_dvb_set_frontend(struct dvb_frontend *fe)
{
struct dtv_frontend_properties *p = &fe->dtv_property_cache;
@@ -793,6 +889,32 @@ static const struct m88ds3103_config dvbsky_t9580_m88ds3103_config = {
.agc = 0x99,
};
+static const struct m88ds3103_config dvbsky_s950c_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_CI,
+ .ts_clk = 10000,
+ .ts_clk_pol = 1,
+ .lnb_en_pol = 1,
+ .lnb_hv_pol = 0,
+ .agc = 0x99,
+};
+
+static const struct m88ds3103_config dvbsky_s952_portc_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_SERIAL,
+ .ts_clk = 96000,
+ .ts_clk_pol = 0,
+ .lnb_en_pol = 1,
+ .lnb_hv_pol = 0,
+ .agc = 0x99,
+};
+
static int netup_altera_fpga_rw(void *device, int flag, int data, int read)
{
struct cx23885_dev *dev = (struct cx23885_dev *)device;
@@ -944,11 +1066,13 @@ static int dvb_register(struct cx23885_tsport *port)
struct vb2_dvb_frontend *fe0, *fe1 = NULL;
struct si2168_config si2168_config;
struct si2157_config si2157_config;
+ struct sp2_config sp2_config;
struct m88ts2022_config m88ts2022_config;
struct i2c_board_info info;
struct i2c_adapter *adapter;
- struct i2c_client *client_demod;
- struct i2c_client *client_tuner;
+ struct i2c_client *client_demod = NULL, *client_tuner = NULL, *client_ci = NULL;
+ const struct m88ds3103_config *p_m88ds3103_config = NULL;
+ int (*p_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage) = NULL;
int mfe_shared = 0; /* bus not shared by default */
int ret;
@@ -973,11 +1097,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_generic_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(mt2131_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_generic_tunerconfig, 0);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1270:
case CX23885_BOARD_HAUPPAUGE_HVR1275:
@@ -985,11 +1109,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(lgdt3305_attach,
&hauppauge_lgdt3305_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_hvr127x_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr127x_config);
if (dev->board == CX23885_BOARD_HAUPPAUGE_HVR1275)
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
break;
@@ -999,11 +1123,12 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&hcw_s5h1411_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_tda18271_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_tda18271_config);
tda18271_attach(&dev->ts1.analog_fe,
0x60, &dev->i2c_bus[1].i2c_adap,
@@ -1018,14 +1143,15 @@ static int dvb_register(struct cx23885_tsport *port)
dvb_attach(s5h1409_attach,
&hauppauge_ezqam_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda829x_attach, fe0->dvb.frontend,
- &dev->i2c_bus[1].i2c_adap, 0x42,
- &tda829x_no_probe);
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_tda18271_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_bus[1].i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_tda18271_config);
break;
case 0:
default:
@@ -1033,11 +1159,11 @@ static int dvb_register(struct cx23885_tsport *port)
dvb_attach(s5h1409_attach,
&hauppauge_generic_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(mt2131_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_generic_tunerconfig, 0);
- break;
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
@@ -1045,32 +1171,33 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1800lp_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(mt2131_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_generic_tunerconfig, 0);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(mt2131_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_generic_tunerconfig, 0);
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP:
i2c_bus = &dev->i2c_bus[0];
fe0->dvb.frontend = dvb_attach(lgdt330x_attach,
&fusionhdtv_5_express,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap, 0x61,
- TUNER_LG_TDVS_H06XF);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(simple_tuner_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
i2c_bus = &dev->i2c_bus[1];
fe0->dvb.frontend = dvb_attach(s5h1409_attach,
&hauppauge_hvr1500q_config,
&dev->i2c_bus[0].i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(xc5000_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_hvr1500q_tunerconfig);
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_hvr1500q_tunerconfig);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
i2c_bus = &dev->i2c_bus[1];
@@ -1101,14 +1228,14 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(tda10048_attach,
&hauppauge_hvr1200_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(tda829x_attach, fe0->dvb.frontend,
- &dev->i2c_bus[1].i2c_adap, 0x42,
- &tda829x_no_probe);
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[1].i2c_adap,
- &hauppauge_hvr1200_tuner_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_bus[1].i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr1200_tuner_config);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1210:
i2c_bus = &dev->i2c_bus[0];
@@ -1367,12 +1494,10 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
&mygica_x8506_lgs8gl5_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
- &i2c_bus2->i2c_adap,
- &mygica_x8506_xc5000_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap, &mygica_x8506_xc5000_config);
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
break;
case CX23885_BOARD_MYGICA_X8507:
@@ -1381,12 +1506,12 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
&mygica_x8507_mb86a20s_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
- &i2c_bus2->i2c_adap,
- &mygica_x8507_xc5000_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &mygica_x8507_xc5000_config);
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
break;
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
@@ -1395,12 +1520,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(lgs8gxx_attach,
&magicpro_prohdtve2_lgs8g75_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
- &i2c_bus2->i2c_adap,
- &magicpro_prohdtve2_xc5000_config);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(xc5000_attach, fe0->dvb.frontend,
+ &i2c_bus2->i2c_adap,
+ &magicpro_prohdtve2_xc5000_config);
cx23885_set_frontend_hook(port, fe0->dvb.frontend);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1850:
@@ -1408,10 +1532,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&hcw_s5h1411_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[0].i2c_adap,
- &hauppauge_tda18271_config);
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[0].i2c_adap,
+ &hauppauge_tda18271_config);
tda18271_attach(&dev->ts1.analog_fe,
0x60, &dev->i2c_bus[1].i2c_adap,
@@ -1423,10 +1548,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(s5h1411_attach,
&hcw_s5h1411_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL)
- dvb_attach(tda18271_attach, fe0->dvb.frontend,
- 0x60, &dev->i2c_bus[0].i2c_adap,
- &hauppauge_tda18271_config);
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_bus[0].i2c_adap,
+ &hauppauge_tda18271_config);
break;
case CX23885_BOARD_MYGICA_X8558PRO:
switch (port->nr) {
@@ -1436,12 +1562,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(atbm8830_attach,
&mygica_x8558pro_atbm8830_cfg1,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(max2165_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &mygic_x8558pro_max2165_cfg1);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(max2165_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &mygic_x8558pro_max2165_cfg1);
break;
/* port C */
case 2:
@@ -1449,13 +1574,11 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(atbm8830_attach,
&mygica_x8558pro_atbm8830_cfg2,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(max2165_attach,
- fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &mygic_x8558pro_max2165_cfg2);
- }
- break;
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(max2165_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &mygic_x8558pro_max2165_cfg2);
}
break;
case CX23885_BOARD_NETUP_DUAL_DVB_T_C_CI_RF:
@@ -1467,15 +1590,15 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(stv0367ter_attach,
&netup_stv0367_config[port->nr - 1],
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (NULL == dvb_attach(xc5000_attach,
- fe0->dvb.frontend,
+ if (fe0->dvb.frontend == NULL)
+ break;
+ if (NULL == dvb_attach(xc5000_attach, fe0->dvb.frontend,
&i2c_bus->i2c_adap,
&netup_xc5000_config[port->nr - 1]))
- goto frontend_detach;
- /* load xc5000 firmware */
- fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
- }
+ goto frontend_detach;
+ /* load xc5000 firmware */
+ fe0->dvb.frontend->ops.tuner_ops.init(fe0->dvb.frontend);
+
/* MFE frontend 2 */
fe1 = vb2_dvb_get_frontend(&port->frontends, 2);
if (fe1 == NULL)
@@ -1484,14 +1607,15 @@ static int dvb_register(struct cx23885_tsport *port)
fe1->dvb.frontend = dvb_attach(stv0367cab_attach,
&netup_stv0367_config[port->nr - 1],
&i2c_bus->i2c_adap);
- if (fe1->dvb.frontend != NULL) {
- fe1->dvb.frontend->id = 1;
- if (NULL == dvb_attach(xc5000_attach,
- fe1->dvb.frontend,
- &i2c_bus->i2c_adap,
- &netup_xc5000_config[port->nr - 1]))
- goto frontend_detach;
- }
+ if (fe1->dvb.frontend == NULL)
+ break;
+
+ fe1->dvb.frontend->id = 1;
+ if (NULL == dvb_attach(xc5000_attach,
+ fe1->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &netup_xc5000_config[port->nr - 1]))
+ goto frontend_detach;
break;
case CX23885_BOARD_TERRATEC_CINERGY_T_PCIE_DUAL:
i2c_bus = &dev->i2c_bus[0];
@@ -1503,26 +1627,26 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(drxk_attach,
&terratec_drxk_config[0],
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(mt2063_attach,
- fe0->dvb.frontend,
- &terratec_mt2063_config[0],
- &i2c_bus2->i2c_adap))
- goto frontend_detach;
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ if (!dvb_attach(mt2063_attach,
+ fe0->dvb.frontend,
+ &terratec_mt2063_config[0],
+ &i2c_bus2->i2c_adap))
+ goto frontend_detach;
break;
/* port c */
case 2:
fe0->dvb.frontend = dvb_attach(drxk_attach,
&terratec_drxk_config[1],
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(mt2063_attach,
- fe0->dvb.frontend,
- &terratec_mt2063_config[1],
- &i2c_bus2->i2c_adap))
- goto frontend_detach;
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ if (!dvb_attach(mt2063_attach,
+ fe0->dvb.frontend,
+ &terratec_mt2063_config[1],
+ &i2c_bus2->i2c_adap))
+ goto frontend_detach;
break;
}
break;
@@ -1532,10 +1656,10 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(ds3000_attach,
&tevii_ds3000_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- dvb_attach(ts2020_attach, fe0->dvb.frontend,
- &tevii_ts2020_config, &i2c_bus->i2c_adap);
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ dvb_attach(ts2020_attach, fe0->dvb.frontend,
+ &tevii_ts2020_config, &i2c_bus->i2c_adap);
break;
case CX23885_BOARD_PROF_8000:
i2c_bus = &dev->i2c_bus[0];
@@ -1544,15 +1668,15 @@ static int dvb_register(struct cx23885_tsport *port)
&prof_8000_stv090x_config,
&i2c_bus->i2c_adap,
STV090x_DEMODULATOR_0);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(stb6100_attach,
- fe0->dvb.frontend,
- &prof_8000_stb6100_config,
- &i2c_bus->i2c_adap))
- goto frontend_detach;
+ if (fe0->dvb.frontend == NULL)
+ break;
+ if (!dvb_attach(stb6100_attach,
+ fe0->dvb.frontend,
+ &prof_8000_stb6100_config,
+ &i2c_bus->i2c_adap))
+ goto frontend_detach;
- fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage;
- }
+ fe0->dvb.frontend->ops.set_voltage = p8000_set_voltage;
break;
case CX23885_BOARD_HAUPPAUGE_HVR4400:
i2c_bus = &dev->i2c_bus[0];
@@ -1563,30 +1687,31 @@ static int dvb_register(struct cx23885_tsport *port)
fe0->dvb.frontend = dvb_attach(tda10071_attach,
&hauppauge_tda10071_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- if (!dvb_attach(a8293_attach, fe0->dvb.frontend,
- &i2c_bus->i2c_adap,
- &hauppauge_a8293_config))
- goto frontend_detach;
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ if (!dvb_attach(a8293_attach, fe0->dvb.frontend,
+ &i2c_bus->i2c_adap,
+ &hauppauge_a8293_config))
+ goto frontend_detach;
break;
/* port c */
case 2:
fe0->dvb.frontend = dvb_attach(si2165_attach,
&hauppauge_hvr4400_si2165_config,
&i2c_bus->i2c_adap);
- if (fe0->dvb.frontend != NULL) {
- fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
- if (!dvb_attach(tda18271_attach,
- fe0->dvb.frontend,
- 0x60, &i2c_bus2->i2c_adap,
- &hauppauge_hvr4400_tuner_config))
- goto frontend_detach;
- }
+ if (fe0->dvb.frontend == NULL)
+ break;
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (!dvb_attach(tda18271_attach,
+ fe0->dvb.frontend,
+ 0x60, &i2c_bus2->i2c_adap,
+ &hauppauge_hvr4400_tuner_config))
+ goto frontend_detach;
break;
}
break;
case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_S950:
i2c_bus = &dev->i2c_bus[0];
i2c_bus2 = &dev->i2c_bus[1];
switch (port->nr) {
@@ -1680,6 +1805,201 @@ static int dvb_register(struct cx23885_tsport *port)
break;
}
break;
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ i2c_bus = &dev->i2c_bus[1];
+ i2c_bus2 = &dev->i2c_bus[0];
+
+ /* attach frontend */
+ memset(&si2168_config, 0, sizeof(si2168_config));
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &fe0->dvb.frontend;
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ if (client_demod == NULL ||
+ client_demod->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_demod->dev.driver->owner)) {
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ port->i2c_client_demod = client_demod;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = fe0->dvb.frontend;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
+ break;
+ case CX23885_BOARD_DVBSKY_S950C:
+ i2c_bus = &dev->i2c_bus[1];
+ i2c_bus2 = &dev->i2c_bus[0];
+
+ /* attach frontend */
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+ &dvbsky_s950c_m88ds3103_config,
+ &i2c_bus->i2c_adap, &adapter);
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ /* attach tuner */
+ memset(&m88ts2022_config, 0, sizeof(m88ts2022_config));
+ m88ts2022_config.fe = fe0->dvb.frontend;
+ m88ts2022_config.clock = 27000000;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &m88ts2022_config;
+ request_module(info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ goto frontend_detach;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ fe0->dvb.frontend->ops.read_signal_strength =
+ fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+
+ port->i2c_client_tuner = client_tuner;
+ break;
+ case CX23885_BOARD_DVBSKY_S952:
+ switch (port->nr) {
+ /* port b */
+ case 1:
+ i2c_bus = &dev->i2c_bus[1];
+ p_m88ds3103_config = &dvbsky_t9580_m88ds3103_config;
+ p_set_voltage = dvbsky_t9580_set_voltage;
+ break;
+ /* port c */
+ case 2:
+ i2c_bus = &dev->i2c_bus[0];
+ p_m88ds3103_config = &dvbsky_s952_portc_m88ds3103_config;
+ p_set_voltage = dvbsky_s952_portc_set_voltage;
+ break;
+ }
+
+ /* attach frontend */
+ fe0->dvb.frontend = dvb_attach(m88ds3103_attach,
+ p_m88ds3103_config,
+ &i2c_bus->i2c_adap, &adapter);
+ if (fe0->dvb.frontend == NULL)
+ break;
+
+ /* attach tuner */
+ memset(&m88ts2022_config, 0, sizeof(m88ts2022_config));
+ m88ts2022_config.fe = fe0->dvb.frontend;
+ m88ts2022_config.clock = 27000000;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &m88ts2022_config;
+ request_module(info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ goto frontend_detach;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ fe0->dvb.frontend->ops.read_signal_strength =
+ fe0->dvb.frontend->ops.tuner_ops.get_rf_strength;
+
+ /*
+ * for setting the voltage we need to set GPIOs on
+ * the card.
+ */
+ port->fe_set_voltage =
+ fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage = p_set_voltage;
+
+ port->i2c_client_tuner = client_tuner;
+ break;
+ case CX23885_BOARD_DVBSKY_T982:
+ memset(&si2168_config, 0, sizeof(si2168_config));
+ switch (port->nr) {
+ /* port b */
+ case 1:
+ i2c_bus = &dev->i2c_bus[1];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+ break;
+ /* port c */
+ case 2:
+ i2c_bus = &dev->i2c_bus[0];
+ si2168_config.ts_mode = SI2168_TS_SERIAL;
+ break;
+ }
+
+ /* attach frontend */
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &fe0->dvb.frontend;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client_demod = i2c_new_device(&i2c_bus->i2c_adap, &info);
+ if (client_demod == NULL ||
+ client_demod->dev.driver == NULL)
+ goto frontend_detach;
+ if (!try_module_get(client_demod->dev.driver->owner)) {
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ port->i2c_client_demod = client_demod;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = fe0->dvb.frontend;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module(info.type);
+ client_tuner = i2c_new_device(adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ goto frontend_detach;
+ }
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ i2c_unregister_device(client_tuner);
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ port->i2c_client_demod = NULL;
+ goto frontend_detach;
+ }
+ port->i2c_client_tuner = client_tuner;
+ break;
default:
printk(KERN_INFO "%s: The frontend of your DVB/ATSC card "
" isn't supported yet\n",
@@ -1754,7 +2074,10 @@ static int dvb_register(struct cx23885_tsport *port)
memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
break;
}
- case CX23885_BOARD_DVBSKY_T9580: {
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982: {
u8 eeprom[256]; /* 24C02 i2c eeprom */
if (port->nr > 2)
@@ -1764,12 +2087,67 @@ static int dvb_register(struct cx23885_tsport *port)
dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
sizeof(eeprom));
- printk(KERN_INFO "DVBSky T9580 port %d MAC address: %pM\n",
- port->nr, eeprom + 0xc0 + (port->nr-1) * 8);
+ printk(KERN_INFO "%s port %d MAC address: %pM\n",
+ cx23885_boards[dev->board].name, port->nr,
+ eeprom + 0xc0 + (port->nr-1) * 8);
memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0 +
(port->nr-1) * 8, 6);
break;
}
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_TT_CT2_4500_CI: {
+ u8 eeprom[256]; /* 24C02 i2c eeprom */
+
+ /* attach CI */
+ memset(&sp2_config, 0, sizeof(sp2_config));
+ sp2_config.dvb_adap = &port->frontends.adapter;
+ sp2_config.priv = port;
+ sp2_config.ci_control = cx23885_sp2_ci_ctrl;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+ info.addr = 0x40;
+ info.platform_data = &sp2_config;
+ request_module(info.type);
+ client_ci = i2c_new_device(&i2c_bus2->i2c_adap, &info);
+ if (client_ci == NULL ||
+ client_ci->dev.driver == NULL) {
+ if (client_tuner) {
+ module_put(client_tuner->dev.driver->owner);
+ i2c_unregister_device(client_tuner);
+ }
+ if (client_demod) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ }
+ goto frontend_detach;
+ }
+ if (!try_module_get(client_ci->dev.driver->owner)) {
+ i2c_unregister_device(client_ci);
+ if (client_tuner) {
+ module_put(client_tuner->dev.driver->owner);
+ i2c_unregister_device(client_tuner);
+ }
+ if (client_demod) {
+ module_put(client_demod->dev.driver->owner);
+ i2c_unregister_device(client_demod);
+ }
+ goto frontend_detach;
+ }
+ port->i2c_client_ci = client_ci;
+
+ if (port->nr != 1)
+ break;
+
+ /* Read entire EEPROM */
+ dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom,
+ sizeof(eeprom));
+ printk(KERN_INFO "%s MAC address: %pM\n",
+ cx23885_boards[dev->board].name, eeprom + 0xc0);
+ memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xc0, 6);
+ break;
+ }
}
return ret;
@@ -1810,7 +2188,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
fe0 = vb2_dvb_get_frontend(&port->frontends, i);
if (!fe0)
- err = -EINVAL;
+ return -EINVAL;
dprintk(1, "%s\n", __func__);
dprintk(1, " ->probed by Card=%d Name=%s, PCI %02x:%02x\n",
@@ -1853,6 +2231,13 @@ int cx23885_dvb_unregister(struct cx23885_tsport *port)
struct vb2_dvb_frontend *fe0;
struct i2c_client *client;
+ /* remove I2C client for CI */
+ client = port->i2c_client_ci;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
/* remove I2C client for tuner */
client = port->i2c_client_tuner;
if (client) {
diff --git a/drivers/media/pci/cx23885/cx23885-input.c b/drivers/media/pci/cx23885/cx23885-input.c
index 9d37fe6..088799c 100644
--- a/drivers/media/pci/cx23885/cx23885-input.c
+++ b/drivers/media/pci/cx23885/cx23885-input.c
@@ -87,6 +87,13 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
case CX23885_BOARD_MYGICA_X8507:
case CX23885_BOARD_TBS_6980:
case CX23885_BOARD_TBS_6981:
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
/*
* The only boards we handle right now. However other boards
* using the CX2388x integrated IR controller should be similar
@@ -139,6 +146,13 @@ static int cx23885_input_ir_start(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_MYGICA_X8507:
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
/*
* The IR controller on this board only returns pulse widths.
* Any other mode setting will fail to set up the device.
@@ -305,6 +319,23 @@ int cx23885_input_init(struct cx23885_dev *dev)
/* A guess at the remote */
rc_map = RC_MAP_TBS_NEC;
break;
+ case CX23885_BOARD_DVBSKY_T9580:
+ case CX23885_BOARD_DVBSKY_T980C:
+ case CX23885_BOARD_DVBSKY_S950C:
+ case CX23885_BOARD_DVBSKY_S950:
+ case CX23885_BOARD_DVBSKY_S952:
+ case CX23885_BOARD_DVBSKY_T982:
+ /* Integrated CX23885 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_BIT_ALL;
+ rc_map = RC_MAP_DVBSKY;
+ break;
+ case CX23885_BOARD_TT_CT2_4500_CI:
+ /* Integrated CX23885 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_BIT_ALL;
+ rc_map = RC_MAP_TT_1500;
+ break;
default:
return -ENODEV;
}
diff --git a/drivers/media/pci/cx23885/cx23885-vbi.c b/drivers/media/pci/cx23885/cx23885-vbi.c
index a7c6ef8..d362d38 100644
--- a/drivers/media/pci/cx23885/cx23885-vbi.c
+++ b/drivers/media/pci/cx23885/cx23885-vbi.c
@@ -132,6 +132,7 @@ static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
lines = VBI_NTSC_LINE_COUNT;
*num_planes = 1;
sizes[0] = lines * VBI_LINE_LENGTH * 2;
+ alloc_ctxs[0] = dev->alloc_ctx;
return 0;
}
@@ -142,7 +143,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
struct cx23885_buffer, vb);
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
unsigned lines = VBI_PAL_LINE_COUNT;
- int ret;
if (dev->tvnorm & V4L2_STD_525_60)
lines = VBI_NTSC_LINE_COUNT;
@@ -151,10 +151,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
return -EINVAL;
vb2_set_plane_payload(vb, 0, lines * VBI_LINE_LENGTH * 2);
- ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
- if (!ret)
- return -EIO;
-
cx23885_risc_vbibuffer(dev->pci, &buf->risc,
sgt->sgl,
0, VBI_LINE_LENGTH * lines,
@@ -165,14 +161,10 @@ static int buffer_prepare(struct vb2_buffer *vb)
static void buffer_finish(struct vb2_buffer *vb)
{
- struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf = container_of(vb,
struct cx23885_buffer, vb);
- struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
-
- dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
/*
diff --git a/drivers/media/pci/cx23885/cx23885-video.c b/drivers/media/pci/cx23885/cx23885-video.c
index 682a4f9..5e93c68 100644
--- a/drivers/media/pci/cx23885/cx23885-video.c
+++ b/drivers/media/pci/cx23885/cx23885-video.c
@@ -323,6 +323,7 @@ static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
*num_planes = 1;
sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+ alloc_ctxs[0] = dev->alloc_ctx;
return 0;
}
@@ -334,7 +335,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
u32 line0_offset, line1_offset;
struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
int field_tff;
- int ret;
buf->bpl = (dev->width * dev->fmt->depth) >> 3;
@@ -342,10 +342,6 @@ static int buffer_prepare(struct vb2_buffer *vb)
return -EINVAL;
vb2_set_plane_payload(vb, 0, dev->height * buf->bpl);
- ret = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
- if (!ret)
- return -EIO;
-
switch (dev->field) {
case V4L2_FIELD_TOP:
cx23885_risc_buffer(dev->pci, &buf->risc,
@@ -413,14 +409,10 @@ static int buffer_prepare(struct vb2_buffer *vb)
static void buffer_finish(struct vb2_buffer *vb)
{
- struct cx23885_dev *dev = vb->vb2_queue->drv_priv;
struct cx23885_buffer *buf = container_of(vb,
struct cx23885_buffer, vb);
- struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
cx23885_free_buffer(vb->vb2_queue->drv_priv, buf);
-
- dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
/*
@@ -608,7 +600,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dev->field = f->fmt.pix.field;
dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
dev->width, dev->height, dev->field);
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
call_all(dev, video, s_mbus_fmt, &mbus_fmt);
v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
/* s_mbus_fmt overwrites f->fmt.pix.field, restore it */
diff --git a/drivers/media/pci/cx23885/cx23885.h b/drivers/media/pci/cx23885/cx23885.h
index 6c35e61..f55cd12 100644
--- a/drivers/media/pci/cx23885/cx23885.h
+++ b/drivers/media/pci/cx23885/cx23885.h
@@ -93,6 +93,12 @@
#define CX23885_BOARD_HAUPPAUGE_IMPACTVCBE 43
#define CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP2 44
#define CX23885_BOARD_DVBSKY_T9580 45
+#define CX23885_BOARD_DVBSKY_T980C 46
+#define CX23885_BOARD_DVBSKY_S950C 47
+#define CX23885_BOARD_TT_CT2_4500_CI 48
+#define CX23885_BOARD_DVBSKY_S950 49
+#define CX23885_BOARD_DVBSKY_S952 50
+#define CX23885_BOARD_DVBSKY_T982 51
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -296,6 +302,7 @@ struct cx23885_tsport {
struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
+ struct i2c_client *i2c_client_ci;
int (*set_frontend)(struct dvb_frontend *fe);
int (*fe_set_voltage)(struct dvb_frontend *fe,
@@ -418,6 +425,7 @@ struct cx23885_dev {
struct vb2_queue vb2_vidq;
struct cx23885_dmaqueue vbiq;
struct vb2_queue vb2_vbiq;
+ void *alloc_ctx;
spinlock_t slock;
diff --git a/drivers/media/pci/cx25821/cx25821-core.c b/drivers/media/pci/cx25821/cx25821-core.c
index e81173c..389fffd 100644
--- a/drivers/media/pci/cx25821/cx25821-core.c
+++ b/drivers/media/pci/cx25821/cx25821-core.c
@@ -996,7 +996,7 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
if (bpl <= sg_dma_len(sg) - offset) {
/* fits into current chunk */
@@ -1014,14 +1014,14 @@ static __le32 *cx25821_risc_field(__le32 * rp, struct scatterlist *sglist,
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg) - offset);
offset = 0;
- sg++;
+ sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE |
sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
*(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
*(rp++) = cpu_to_le32(sg_dma_address(sg));
@@ -1101,7 +1101,7 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
if (lpi && line > 0 && !(line % lpi))
@@ -1125,14 +1125,14 @@ static __le32 *cx25821_risc_field_audio(__le32 * rp, struct scatterlist *sglist,
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= (sg_dma_len(sg) - offset);
offset = 0;
- sg++;
+ sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++) = cpu_to_le32(RISC_WRITE |
sg_dma_len(sg));
*(rp++) = cpu_to_le32(sg_dma_address(sg));
*(rp++) = cpu_to_le32(0); /* bits 63-32 */
todo -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
*(rp++) = cpu_to_le32(RISC_WRITE | RISC_EOL | todo);
*(rp++) = cpu_to_le32(sg_dma_address(sg));
diff --git a/drivers/media/pci/cx88/Kconfig b/drivers/media/pci/cx88/Kconfig
index a63a9ad..14b813d6 100644
--- a/drivers/media/pci/cx88/Kconfig
+++ b/drivers/media/pci/cx88/Kconfig
@@ -2,8 +2,7 @@ config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
depends on VIDEO_DEV && PCI && I2C && RC_CORE
select I2C_ALGOBIT
- select VIDEO_BTCX
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF2_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_WM8775 if MEDIA_SUBDRV_AUTOSELECT
@@ -45,7 +44,7 @@ config VIDEO_CX88_BLACKBIRD
config VIDEO_CX88_DVB
tristate "DVB/ATSC Support for cx2388x based TV cards"
depends on VIDEO_CX88 && DVB_CORE
- select VIDEOBUF_DVB
+ select VIDEOBUF2_DVB
select DVB_PLL if MEDIA_SUBDRV_AUTOSELECT
select DVB_MT352 if MEDIA_SUBDRV_AUTOSELECT
select DVB_ZL10353 if MEDIA_SUBDRV_AUTOSELECT
diff --git a/drivers/media/pci/cx88/Makefile b/drivers/media/pci/cx88/Makefile
index 8619c1b..d3679c3 100644
--- a/drivers/media/pci/cx88/Makefile
+++ b/drivers/media/pci/cx88/Makefile
@@ -11,7 +11,6 @@ obj-$(CONFIG_VIDEO_CX88_DVB) += cx88-dvb.o
obj-$(CONFIG_VIDEO_CX88_VP3054) += cx88-vp3054-i2c.o
ccflags-y += -Idrivers/media/i2c
-ccflags-y += -Idrivers/media/common
ccflags-y += -Idrivers/media/tuners
ccflags-y += -Idrivers/media/dvb-core
ccflags-y += -Idrivers/media/dvb-frontends
diff --git a/drivers/media/pci/cx88/cx88-alsa.c b/drivers/media/pci/cx88/cx88-alsa.c
index a72579a..7f8dc60 100644
--- a/drivers/media/pci/cx88/cx88-alsa.c
+++ b/drivers/media/pci/cx88/cx88-alsa.c
@@ -61,8 +61,11 @@
struct cx88_audio_buffer {
unsigned int bpl;
- struct btcx_riscmem risc;
- struct videobuf_dmabuf dma;
+ struct cx88_riscmem risc;
+ void *vaddr;
+ struct scatterlist *sglist;
+ int sglen;
+ int nr_pages;
};
struct cx88_audio_dev {
@@ -84,8 +87,6 @@ struct cx88_audio_dev {
unsigned int period_size;
unsigned int num_periods;
- struct videobuf_dmabuf *dma_risc;
-
struct cx88_audio_buffer *buf;
struct snd_pcm_substream *substream;
@@ -290,19 +291,97 @@ static irqreturn_t cx8801_irq(int irq, void *dev_id)
return IRQ_RETVAL(handled);
}
+static int cx88_alsa_dma_init(struct cx88_audio_dev *chip, int nr_pages)
+{
+ struct cx88_audio_buffer *buf = chip->buf;
+ struct page *pg;
+ int i;
+
+ buf->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == buf->vaddr) {
+ dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
+ return -ENOMEM;
+ }
+
+ dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
+ (unsigned long)buf->vaddr,
+ nr_pages << PAGE_SHIFT);
+
+ memset(buf->vaddr, 0, nr_pages << PAGE_SHIFT);
+ buf->nr_pages = nr_pages;
+
+ buf->sglist = vzalloc(buf->nr_pages * sizeof(*buf->sglist));
+ if (NULL == buf->sglist)
+ goto vzalloc_err;
+
+ sg_init_table(buf->sglist, buf->nr_pages);
+ for (i = 0; i < buf->nr_pages; i++) {
+ pg = vmalloc_to_page(buf->vaddr + i * PAGE_SIZE);
+ if (NULL == pg)
+ goto vmalloc_to_page_err;
+ sg_set_page(&buf->sglist[i], pg, PAGE_SIZE, 0);
+ }
+ return 0;
+
+vmalloc_to_page_err:
+ vfree(buf->sglist);
+ buf->sglist = NULL;
+vzalloc_err:
+ vfree(buf->vaddr);
+ buf->vaddr = NULL;
+ return -ENOMEM;
+}
+
+static int cx88_alsa_dma_map(struct cx88_audio_dev *dev)
+{
+ struct cx88_audio_buffer *buf = dev->buf;
+
+ buf->sglen = dma_map_sg(&dev->pci->dev, buf->sglist,
+ buf->nr_pages, PCI_DMA_FROMDEVICE);
+
+ if (0 == buf->sglen) {
+ pr_warn("%s: cx88_alsa_map_sg failed\n", __func__);
+ return -ENOMEM;
+ }
+ return 0;
+}
+
+static int cx88_alsa_dma_unmap(struct cx88_audio_dev *dev)
+{
+ struct cx88_audio_buffer *buf = dev->buf;
+
+ if (!buf->sglen)
+ return 0;
+
+ dma_unmap_sg(&dev->pci->dev, buf->sglist, buf->sglen, PCI_DMA_FROMDEVICE);
+ buf->sglen = 0;
+ return 0;
+}
+
+static int cx88_alsa_dma_free(struct cx88_audio_buffer *buf)
+{
+ vfree(buf->sglist);
+ buf->sglist = NULL;
+ vfree(buf->vaddr);
+ buf->vaddr = NULL;
+ return 0;
+}
+
static int dsp_buffer_free(snd_cx88_card_t *chip)
{
+ struct cx88_riscmem *risc = &chip->buf->risc;
+
BUG_ON(!chip->dma_size);
dprintk(2,"Freeing buffer\n");
- videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
- videobuf_dma_free(chip->dma_risc);
- btcx_riscmem_free(chip->pci,&chip->buf->risc);
+ cx88_alsa_dma_unmap(chip);
+ cx88_alsa_dma_free(chip->buf);
+ if (risc->cpu)
+ pci_free_consistent(chip->pci, risc->size, risc->cpu, risc->dma);
kfree(chip->buf);
- chip->dma_risc = NULL;
- chip->dma_size = 0;
+ chip->buf = NULL;
return 0;
}
@@ -387,7 +466,6 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
struct snd_pcm_hw_params * hw_params)
{
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
- struct videobuf_dmabuf *dma;
struct cx88_audio_buffer *buf;
int ret;
@@ -408,20 +486,19 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
if (NULL == buf)
return -ENOMEM;
+ chip->buf = buf;
buf->bpl = chip->period_size;
- dma = &buf->dma;
- videobuf_dma_init(dma);
- ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
+ ret = cx88_alsa_dma_init(chip,
(PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
- ret = videobuf_dma_map(&chip->pci->dev, dma);
+ ret = cx88_alsa_dma_map(chip);
if (ret < 0)
goto error;
- ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
+ ret = cx88_risc_databuffer(chip->pci, &buf->risc, buf->sglist,
chip->period_size, chip->num_periods, 1);
if (ret < 0)
goto error;
@@ -430,10 +507,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- chip->buf = buf;
- chip->dma_risc = dma;
-
- substream->runtime->dma_area = chip->dma_risc->vaddr;
+ substream->runtime->dma_area = chip->buf->vaddr;
substream->runtime->dma_bytes = chip->dma_size;
substream->runtime->dma_addr = 0;
return 0;
diff --git a/drivers/media/pci/cx88/cx88-blackbird.c b/drivers/media/pci/cx88/cx88-blackbird.c
index 150bb76..4160ca4 100644
--- a/drivers/media/pci/cx88/cx88-blackbird.c
+++ b/drivers/media/pci/cx88/cx88-blackbird.c
@@ -45,10 +45,6 @@ MODULE_AUTHOR("Jelle Foks <jelle@foks.us>, Gerd Knorr <kraxel@bytesex.org> [SuSE
MODULE_LICENSE("GPL");
MODULE_VERSION(CX88_VERSION);
-static unsigned int mpegbufs = 32;
-module_param(mpegbufs,int,0644);
-MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
-
static unsigned int debug;
module_param(debug,int,0644);
MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
@@ -326,13 +322,13 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat
memory_read(dev->core, dev->mailbox - 4, &value);
if (value != 0x12345678) {
dprintk(0, "Firmware and/or mailbox pointer not initialized or corrupted\n");
- return -1;
+ return -EIO;
}
memory_read(dev->core, dev->mailbox, &flag);
if (flag) {
dprintk(0, "ERROR: Mailbox appears to be in use (%x)\n", flag);
- return -1;
+ return -EIO;
}
flag |= 1; /* tell 'em we're working on it */
@@ -352,14 +348,14 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat
memory_write(dev->core, dev->mailbox, flag);
/* wait for firmware to handle the API command */
- timeout = jiffies + msecs_to_jiffies(10);
+ timeout = jiffies + msecs_to_jiffies(1000);
for (;;) {
memory_read(dev->core, dev->mailbox, &flag);
if (0 != (flag & 4))
break;
if (time_after(jiffies,timeout)) {
- dprintk(0, "ERROR: API Mailbox timeout\n");
- return -1;
+ dprintk(0, "ERROR: API Mailbox timeout %x\n", command);
+ return -EIO;
}
udelay(10);
}
@@ -420,7 +416,7 @@ static int blackbird_find_mailbox(struct cx8802_dev *dev)
}
}
dprintk(0, "Mailbox signature values not found!\n");
- return -1;
+ return -EIO;
}
static int blackbird_load_firmware(struct cx8802_dev *dev)
@@ -432,7 +428,7 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
int i, retval = 0;
u32 value = 0;
u32 checksum = 0;
- u32 *dataptr;
+ __le32 *dataptr;
retval = register_write(dev->core, IVTV_REG_VPU, 0xFFFFFFED);
retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
@@ -449,29 +445,28 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
if (retval != 0) {
- dprintk(0, "ERROR: Hotplug firmware request failed (%s).\n",
+ pr_err("Hotplug firmware request failed (%s).\n",
CX2341X_FIRM_ENC_FILENAME);
- dprintk(0, "Please fix your hotplug setup, the board will "
- "not work without firmware loaded!\n");
- return -1;
+ pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");
+ return -EIO;
}
if (firmware->size != BLACKBIRD_FIRM_IMAGE_SIZE) {
- dprintk(0, "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+ pr_err("Firmware size mismatch (have %zd, expected %d)\n",
firmware->size, BLACKBIRD_FIRM_IMAGE_SIZE);
release_firmware(firmware);
- return -1;
+ return -EINVAL;
}
if (0 != memcmp(firmware->data, magic, 8)) {
- dprintk(0, "ERROR: Firmware magic mismatch, wrong file?\n");
+ pr_err("Firmware magic mismatch, wrong file?\n");
release_firmware(firmware);
- return -1;
+ return -EINVAL;
}
/* transfer to the chip */
dprintk(1,"Loading firmware ...\n");
- dataptr = (u32*)firmware->data;
+ dataptr = (__le32 *)firmware->data;
for (i = 0; i < (firmware->size >> 2); i++) {
value = le32_to_cpu(*dataptr);
checksum += ~value;
@@ -484,12 +479,11 @@ static int blackbird_load_firmware(struct cx8802_dev *dev)
memory_read(dev->core, i, &value);
checksum -= ~value;
}
+ release_firmware(firmware);
if (checksum) {
- dprintk(0, "ERROR: Firmware load failed (checksum mismatch).\n");
- release_firmware(firmware);
- return -1;
+ pr_err("Firmware load might have failed (checksum mismatch).\n");
+ return -EIO;
}
- release_firmware(firmware);
dprintk(0, "Firmware upload successful.\n");
retval |= register_write(dev->core, IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
@@ -521,12 +515,14 @@ DB* DVD | MPEG2 | 720x576PAL | CBR | 600 :Good | 6000 Kbps | 25fps | M
static void blackbird_codec_settings(struct cx8802_dev *dev)
{
+ struct cx88_core *core = dev->core;
+
/* assign frame size */
blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
- dev->height, dev->width);
+ core->height, core->width);
- dev->cxhdl.width = dev->width;
- dev->cxhdl.height = dev->height;
+ dev->cxhdl.width = core->width;
+ dev->cxhdl.height = core->height;
cx2341x_handler_set_50hz(&dev->cxhdl, dev->core->tvnorm & V4L2_STD_625_50);
cx2341x_handler_setup(&dev->cxhdl);
}
@@ -540,9 +536,6 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
dprintk(1,"Initialize codec\n");
retval = blackbird_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
-
- dev->mpeg_active = 0;
-
/* ping was not successful, reset and upload firmware */
cx_write(MO_SRST_IO, 0); /* SYS_RSTO=0 */
cx_write(MO_SRST_IO, 1); /* SYS_RSTO=1 */
@@ -589,9 +582,8 @@ static int blackbird_initialize_codec(struct cx8802_dev *dev)
return 0;
}
-static int blackbird_start_codec(struct file *file, void *priv)
+static int blackbird_start_codec(struct cx8802_dev *dev)
{
- struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
struct cx88_core *core = dev->core;
/* start capturing to the host interface */
u32 reg;
@@ -627,7 +619,6 @@ static int blackbird_start_codec(struct file *file, void *priv)
BLACKBIRD_RAW_BITS_NONE
);
- dev->mpeg_active = 1;
return 0;
}
@@ -641,51 +632,139 @@ static int blackbird_stop_codec(struct cx8802_dev *dev)
cx2341x_handler_set_busy(&dev->cxhdl, 0);
- dev->mpeg_active = 0;
return 0;
}
/* ------------------------------------------------------------------ */
-static int bb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx8802_fh *fh = q->priv_data;
-
- fh->dev->ts_packet_size = 188 * 4; /* was: 512 */
- fh->dev->ts_packet_count = mpegbufs; /* was: 100 */
+ struct cx8802_dev *dev = q->drv_priv;
- *size = fh->dev->ts_packet_size * fh->dev->ts_packet_count;
- *count = fh->dev->ts_packet_count;
+ *num_planes = 1;
+ dev->ts_packet_size = 188 * 4;
+ dev->ts_packet_count = 32;
+ sizes[0] = dev->ts_packet_size * dev->ts_packet_count;
return 0;
}
-static int
-bb_buf_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx8802_fh *fh = q->priv_data;
- return cx8802_buf_prepare(q, fh->dev, (struct cx88_buffer*)vb, field);
+ struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+
+ return cx8802_buf_prepare(vb->vb2_queue, dev, buf);
}
-static void
-bb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_finish(struct vb2_buffer *vb)
{
- struct cx8802_fh *fh = q->priv_data;
- cx8802_buf_queue(fh->dev, (struct cx88_buffer*)vb);
+ struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ struct cx88_riscmem *risc = &buf->risc;
+
+ if (risc->cpu)
+ pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ memset(risc, 0, sizeof(*risc));
+
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void
-bb_buf_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
- cx88_free_buffer(q, (struct cx88_buffer*)vb);
+ struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+
+ cx8802_buf_queue(dev, buf);
+}
+
+static int start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct cx8802_dev *dev = q->drv_priv;
+ struct cx88_dmaqueue *dmaq = &dev->mpegq;
+ struct cx8802_driver *drv;
+ struct cx88_buffer *buf;
+ unsigned long flags;
+ int err;
+
+ /* Make sure we can acquire the hardware */
+ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+ if (!drv) {
+ dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
+ err = -ENODEV;
+ goto fail;
+ }
+
+ err = drv->request_acquire(drv);
+ if (err != 0) {
+ dprintk(1, "%s: Unable to acquire hardware, %d\n", __func__, err);
+ goto fail;
+ }
+
+ if (blackbird_initialize_codec(dev) < 0) {
+ drv->request_release(drv);
+ err = -EINVAL;
+ goto fail;
+ }
+
+ err = blackbird_start_codec(dev);
+ if (err == 0) {
+ buf = list_entry(dmaq->active.next, struct cx88_buffer, list);
+ cx8802_start_dma(dev, dmaq, buf);
+ return 0;
+ }
+
+fail:
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_QUEUED);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return err;
}
-static struct videobuf_queue_ops blackbird_qops = {
- .buf_setup = bb_buf_setup,
- .buf_prepare = bb_buf_prepare,
- .buf_queue = bb_buf_queue,
- .buf_release = bb_buf_release,
+static void stop_streaming(struct vb2_queue *q)
+{
+ struct cx8802_dev *dev = q->drv_priv;
+ struct cx88_dmaqueue *dmaq = &dev->mpegq;
+ struct cx8802_driver *drv = NULL;
+ unsigned long flags;
+
+ cx8802_cancel_buffers(dev);
+ blackbird_stop_codec(dev);
+
+ /* Make sure we release the hardware */
+ drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
+ WARN_ON(!drv);
+ if (drv)
+ drv->request_release(drv);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+static struct vb2_ops blackbird_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
};
/* ------------------------------------------------------------------ */
@@ -693,8 +772,8 @@ static struct videobuf_queue_ops blackbird_qops = {
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
- struct cx88_core *core = dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx88_blackbird");
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
@@ -714,131 +793,111 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx8802_fh *fh = priv;
- struct cx8802_dev *dev = fh->dev;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.field = fh->mpegq.field;
- dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
+ f->fmt.pix.width = core->width;
+ f->fmt.pix.height = core->height;
+ f->fmt.pix.field = core->field;
return 0;
}
-static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx8802_fh *fh = priv;
- struct cx8802_dev *dev = fh->dev;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
+ unsigned maxw, maxh;
+ enum v4l2_field field;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */
+ f->fmt.pix.sizeimage = dev->ts_packet_size * dev->ts_packet_count;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
- dev->width, dev->height, fh->mpegq.field );
+
+ maxw = norm_maxw(core->tvnorm);
+ maxh = norm_maxh(core->tvnorm);
+
+ field = f->fmt.pix.field;
+
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_BT:
+ case V4L2_FIELD_SEQ_TB:
+ break;
+ default:
+ field = (f->fmt.pix.height > maxh / 2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ break;
+ }
+ if (V4L2_FIELD_HAS_T_OR_B(field))
+ maxh /= 2;
+
+ v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
+ &f->fmt.pix.height, 32, maxh, 0, 0);
+ f->fmt.pix.field = field;
return 0;
}
-static int vidioc_s_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx8802_fh *fh = priv;
- struct cx8802_dev *dev = fh->dev;
+ struct cx8802_dev *dev = video_drvdata(file);
struct cx88_core *core = dev->core;
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
- f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = 188 * 4 * mpegbufs; /* 188 * 4 * 1024; */
- f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
- dev->width = f->fmt.pix.width;
- dev->height = f->fmt.pix.height;
- fh->mpegq.field = f->fmt.pix.field;
+ if (vb2_is_busy(&dev->vb2_mpegq))
+ return -EBUSY;
+ if (core->v4ldev && (vb2_is_busy(&core->v4ldev->vb2_vidq) ||
+ vb2_is_busy(&core->v4ldev->vb2_vbiq)))
+ return -EBUSY;
+ vidioc_try_fmt_vid_cap(file, priv, f);
+ core->width = f->fmt.pix.width;
+ core->height = f->fmt.pix.height;
+ core->field = f->fmt.pix.field;
cx88_set_scale(core, f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
blackbird_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
f->fmt.pix.height, f->fmt.pix.width);
- dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
- f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field );
return 0;
}
-static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
-{
- struct cx8802_fh *fh = priv;
- return (videobuf_reqbufs(&fh->mpegq, p));
-}
-
-static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx8802_fh *fh = priv;
- return (videobuf_querybuf(&fh->mpegq, p));
-}
-
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx8802_fh *fh = priv;
- return (videobuf_qbuf(&fh->mpegq, p));
-}
-
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
-{
- struct cx8802_fh *fh = priv;
- return (videobuf_dqbuf(&fh->mpegq, p,
- file->f_flags & O_NONBLOCK));
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx8802_fh *fh = priv;
- struct cx8802_dev *dev = fh->dev;
-
- if (!dev->mpeg_active)
- blackbird_start_codec(file, fh);
- return videobuf_streamon(&fh->mpegq);
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct cx8802_fh *fh = priv;
- struct cx8802_dev *dev = fh->dev;
-
- if (dev->mpeg_active)
- blackbird_stop_codec(dev);
- return videobuf_streamoff(&fh->mpegq);
-}
-
static int vidioc_s_frequency (struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct cx8802_fh *fh = priv;
- struct cx8802_dev *dev = fh->dev;
- struct cx88_core *core = dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
+ bool streaming;
if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
if (unlikely(f->tuner != 0))
return -EINVAL;
- if (dev->mpeg_active)
+ streaming = vb2_start_streaming_called(&dev->vb2_mpegq);
+ if (streaming)
blackbird_stop_codec(dev);
cx88_set_freq (core,f);
blackbird_initialize_codec(dev);
- cx88_set_scale(dev->core, dev->width, dev->height,
- fh->mpegq.field);
+ cx88_set_scale(core, core->width, core->height,
+ core->field);
+ if (streaming)
+ blackbird_start_codec(dev);
return 0;
}
static int vidioc_log_status (struct file *file, void *priv)
{
- struct cx8802_dev *dev = ((struct cx8802_fh *)priv)->dev;
- struct cx88_core *core = dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
char name[32 + 2];
snprintf(name, sizeof(name), "%s/2", core->name);
@@ -850,15 +909,16 @@ static int vidioc_log_status (struct file *file, void *priv)
static int vidioc_enum_input (struct file *file, void *priv,
struct v4l2_input *i)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
return cx88_enum_input (core,i);
}
static int vidioc_g_frequency (struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct cx8802_fh *fh = priv;
- struct cx88_core *core = fh->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
@@ -873,7 +933,8 @@ static int vidioc_g_frequency (struct file *file, void *priv,
static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
*i = core->input;
return 0;
@@ -881,24 +942,24 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (i >= 4)
return -EINVAL;
if (0 == INPUT(i).type)
return -EINVAL;
- mutex_lock(&core->lock);
cx88_newstation(core);
cx88_video_mux(core,i);
- mutex_unlock(&core->lock);
return 0;
}
static int vidioc_g_tuner (struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
u32 reg;
if (unlikely(UNSET == core->board.tuner_type))
@@ -920,7 +981,8 @@ static int vidioc_g_tuner (struct file *file, void *priv,
static int vidioc_s_tuner (struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (UNSET == core->board.tuner_type)
return -EINVAL;
@@ -933,7 +995,8 @@ static int vidioc_s_tuner (struct file *file, void *priv,
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
+ struct cx8802_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
*tvnorm = core->tvnorm;
return 0;
@@ -941,155 +1004,20 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id id)
{
- struct cx88_core *core = ((struct cx8802_fh *)priv)->dev->core;
-
- mutex_lock(&core->lock);
- cx88_set_tvnorm(core, id);
- mutex_unlock(&core->lock);
- return 0;
-}
-
-/* FIXME: cx88_ioctl_hook not implemented */
-
-static int mpeg_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
struct cx8802_dev *dev = video_drvdata(file);
- struct cx8802_fh *fh;
- struct cx8802_driver *drv = NULL;
- int err;
-
- dprintk( 1, "%s\n", __func__);
-
- mutex_lock(&dev->core->lock);
-
- /* Make sure we can acquire the hardware */
- drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
- if (!drv) {
- dprintk(1, "%s: blackbird driver is not loaded\n", __func__);
- mutex_unlock(&dev->core->lock);
- return -ENODEV;
- }
-
- err = drv->request_acquire(drv);
- if (err != 0) {
- dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
- mutex_unlock(&dev->core->lock);
- return err;
- }
-
- if (!dev->core->mpeg_users && blackbird_initialize_codec(dev) < 0) {
- drv->request_release(drv);
- mutex_unlock(&dev->core->lock);
- return -EINVAL;
- }
- dprintk(1, "open dev=%s\n", video_device_node_name(vdev));
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh) {
- drv->request_release(drv);
- mutex_unlock(&dev->core->lock);
- return -ENOMEM;
- }
- v4l2_fh_init(&fh->fh, vdev);
- file->private_data = fh;
- fh->dev = dev;
-
- videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx88_buffer),
- fh, NULL);
-
- /* FIXME: locking against other video device */
- cx88_set_scale(dev->core, dev->width, dev->height,
- fh->mpegq.field);
-
- dev->core->mpeg_users++;
- mutex_unlock(&dev->core->lock);
- v4l2_fh_add(&fh->fh);
- return 0;
-}
-
-static int mpeg_release(struct file *file)
-{
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
- struct cx8802_driver *drv = NULL;
-
- mutex_lock(&dev->core->lock);
-
- if (dev->mpeg_active && dev->core->mpeg_users == 1)
- blackbird_stop_codec(dev);
-
- cx8802_cancel_buffers(fh->dev);
- /* stop mpeg capture */
- videobuf_stop(&fh->mpegq);
-
- videobuf_mmap_free(&fh->mpegq);
-
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- file->private_data = NULL;
- kfree(fh);
-
- /* Make sure we release the hardware */
- drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
- WARN_ON(!drv);
- if (drv)
- drv->request_release(drv);
-
- dev->core->mpeg_users--;
-
- mutex_unlock(&dev->core->lock);
-
- return 0;
-}
-
-static ssize_t
-mpeg_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
-
- if (!dev->mpeg_active)
- blackbird_start_codec(file, fh);
-
- return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
- file->f_flags & O_NONBLOCK);
-}
-
-static unsigned int
-mpeg_poll(struct file *file, struct poll_table_struct *wait)
-{
- unsigned long req_events = poll_requested_events(wait);
- struct cx8802_fh *fh = file->private_data;
- struct cx8802_dev *dev = fh->dev;
-
- if (!dev->mpeg_active && (req_events & (POLLIN | POLLRDNORM)))
- blackbird_start_codec(file, fh);
-
- return v4l2_ctrl_poll(file, wait) | videobuf_poll_stream(file, &fh->mpegq, wait);
-}
-
-static int
-mpeg_mmap(struct file *file, struct vm_area_struct * vma)
-{
- struct cx8802_fh *fh = file->private_data;
+ struct cx88_core *core = dev->core;
- return videobuf_mmap_mapper(&fh->mpegq, vma);
+ return cx88_set_tvnorm(core, id);
}
static const struct v4l2_file_operations mpeg_fops =
{
.owner = THIS_MODULE,
- .open = mpeg_open,
- .release = mpeg_release,
- .read = mpeg_read,
- .poll = mpeg_poll,
- .mmap = mpeg_mmap,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
@@ -1099,12 +1027,12 @@ static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_s_frequency = vidioc_s_frequency,
.vidioc_log_status = vidioc_log_status,
.vidioc_enum_input = vidioc_enum_input,
@@ -1189,11 +1117,12 @@ static int blackbird_register_video(struct cx8802_dev *dev)
{
int err;
- dev->mpeg_dev = cx88_vdev_init(dev->core,dev->pci,
- &cx8802_mpeg_template,"mpeg");
+ dev->mpeg_dev = cx88_vdev_init(dev->core, dev->pci,
+ &cx8802_mpeg_template, "mpeg");
dev->mpeg_dev->ctrl_handler = &dev->cxhdl.hdl;
video_set_drvdata(dev->mpeg_dev, dev);
- err = video_register_device(dev->mpeg_dev,VFL_TYPE_GRABBER, -1);
+ dev->mpeg_dev->queue = &dev->vb2_mpegq;
+ err = video_register_device(dev->mpeg_dev, VFL_TYPE_GRABBER, -1);
if (err < 0) {
printk(KERN_INFO "%s/2: can't register mpeg device\n",
dev->core->name);
@@ -1210,6 +1139,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
struct cx8802_dev *dev = core->dvbdev;
+ struct vb2_queue *q;
int err;
dprintk( 1, "%s\n", __func__);
@@ -1223,15 +1153,9 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
if (!(core->board.mpeg & CX88_MPEG_BLACKBIRD))
goto fail_core;
- dev->width = 720;
- if (core->tvnorm & V4L2_STD_525_60) {
- dev->height = 480;
- } else {
- dev->height = 576;
- }
dev->cxhdl.port = CX2341X_PORT_STREAMING;
- dev->cxhdl.width = dev->width;
- dev->cxhdl.height = dev->height;
+ dev->cxhdl.width = core->width;
+ dev->cxhdl.height = core->height;
dev->cxhdl.func = blackbird_mbox_func;
dev->cxhdl.priv = dev;
err = cx2341x_handler_init(&dev->cxhdl, 36);
@@ -1250,13 +1174,30 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
// init_controls(core);
cx88_set_tvnorm(core,core->tvnorm);
cx88_video_mux(core,0);
- cx2341x_handler_set_50hz(&dev->cxhdl, dev->height == 576);
+ cx2341x_handler_set_50hz(&dev->cxhdl, core->height == 576);
cx2341x_handler_setup(&dev->cxhdl);
+
+ q = &dev->vb2_mpegq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx88_buffer);
+ q->ops = &blackbird_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &core->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_core;
+
blackbird_register_video(dev);
return 0;
- fail_core:
+fail_core:
return err;
}
diff --git a/drivers/media/pci/cx88/cx88-cards.c b/drivers/media/pci/cx88/cx88-cards.c
index 851754b..8f2556e 100644
--- a/drivers/media/pci/cx88/cx88-cards.c
+++ b/drivers/media/pci/cx88/cx88-cards.c
@@ -347,7 +347,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_IODATA_GVVCP3PCI] = {
.name = "IODATA GV-VCP3/PCI",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -436,7 +436,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_KWORLD_DVB_T] = {
.name = "KWorld/VStream XPert DVB-T",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -455,7 +455,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T1] = {
.name = "DViCO FusionHDTV DVB-T1",
- .tuner_type = TUNER_ABSENT, /* No analog tuner */
+ .tuner_type = UNSET, /* No analog tuner */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -542,7 +542,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_HAUPPAUGE_DVB_T1] = {
.name = "Hauppauge Nova-T DVB-T",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -554,7 +554,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_CONEXANT_DVB_T1] = {
.name = "Conexant DVB-T reference design",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -579,7 +579,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS] = {
.name = "DViCO FusionHDTV DVB-T Plus",
- .tuner_type = TUNER_ABSENT, /* No analog tuner */
+ .tuner_type = UNSET, /* No analog tuner */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -596,7 +596,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DNTV_LIVE_DVB_T] = {
.name = "digitalnow DNTV Live! DVB-T",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -787,7 +787,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_ADSTECH_DVB_T_PCI] = {
.name = "ADS Tech Instant TV DVB-T PCI",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -806,7 +806,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1] = {
.name = "TerraTec Cinergy 1400 DVB-T",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.input = { {
.type = CX88_VMUX_DVB,
.vmux = 0,
@@ -924,7 +924,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_WINFAST_DTV1000] = {
.name = "WinFast DTV1000-T",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -972,7 +972,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1] = {
.name = "Hauppauge Nova-S-Plus DVB-S",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -998,7 +998,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_HAUPPAUGE_NOVASE2_S1] = {
.name = "Hauppauge Nova-SE2 DVB-S",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1010,7 +1010,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_KWORLD_DVBS_100] = {
.name = "KWorld DVB-S 100",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1102,7 +1102,7 @@ static const struct cx88_board cx88_boards[] = {
/* DTT 7579 Conexant CX22702-19 Conexant CX2388x */
/* Manenti Marco <marco_manenti@colman.it> */
.name = "KWorld/VStream XPert DVB-T with cx22702",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1121,7 +1121,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL] = {
.name = "DViCO FusionHDTV DVB-T Dual Digital",
- .tuner_type = TUNER_ABSENT, /* No analog tuner */
+ .tuner_type = UNSET, /* No analog tuner */
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1356,7 +1356,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_GENIATECH_DVBS] = {
.name = "Geniatech DVB-S",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1494,7 +1494,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_SAMSUNG_SMT_7020] = {
.name = "Samsung SMT 7020 DVB-S",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1506,7 +1506,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_ADSTECH_PTV_390] = {
.name = "ADS Tech Instant Video PCI",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -1553,7 +1553,7 @@ static const struct cx88_board cx88_boards[] = {
[CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
.name = "DViCO FusionHDTV 5 PCI nano",
/* xc3008 tuner, digital only for now */
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2069,7 +2069,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_TBS_8920] = {
.name = "TBS 8920 DVB-S/S2",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2304,7 +2304,7 @@ static const struct cx88_board cx88_boards[] = {
},
[CX88_BOARD_TWINHAN_VP1027_DVBS] = {
.name = "Twinhan VP-1027 DVB-S",
- .tuner_type = TUNER_ABSENT,
+ .tuner_type = UNSET,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -2921,33 +2921,33 @@ static const struct {
int fm;
const char *name;
} gdi_tuner[] = {
- [ 0x01 ] = { .id = TUNER_ABSENT,
+ [ 0x01 ] = { .id = UNSET,
.name = "NTSC_M" },
- [ 0x02 ] = { .id = TUNER_ABSENT,
+ [ 0x02 ] = { .id = UNSET,
.name = "PAL_B" },
- [ 0x03 ] = { .id = TUNER_ABSENT,
+ [ 0x03 ] = { .id = UNSET,
.name = "PAL_I" },
- [ 0x04 ] = { .id = TUNER_ABSENT,
+ [ 0x04 ] = { .id = UNSET,
.name = "PAL_D" },
- [ 0x05 ] = { .id = TUNER_ABSENT,
+ [ 0x05 ] = { .id = UNSET,
.name = "SECAM" },
- [ 0x10 ] = { .id = TUNER_ABSENT,
+ [ 0x10 ] = { .id = UNSET,
.fm = 1,
.name = "TEMIC_4049" },
[ 0x11 ] = { .id = TUNER_TEMIC_4136FY5,
.name = "TEMIC_4136" },
- [ 0x12 ] = { .id = TUNER_ABSENT,
+ [ 0x12 ] = { .id = UNSET,
.name = "TEMIC_4146" },
[ 0x20 ] = { .id = TUNER_PHILIPS_FQ1216ME,
.fm = 1,
.name = "PHILIPS_FQ1216_MK3" },
- [ 0x21 ] = { .id = TUNER_ABSENT, .fm = 1,
+ [ 0x21 ] = { .id = UNSET, .fm = 1,
.name = "PHILIPS_FQ1236_MK3" },
- [ 0x22 ] = { .id = TUNER_ABSENT,
+ [ 0x22 ] = { .id = UNSET,
.name = "PHILIPS_FI1236_MK3" },
- [ 0x23 ] = { .id = TUNER_ABSENT,
+ [ 0x23 ] = { .id = UNSET,
.name = "PHILIPS_FI1216_MK3" },
};
@@ -3564,7 +3564,7 @@ static void cx88_card_setup(struct cx88_core *core)
mode_mask &= ~T_RADIO;
}
- if (core->board.tuner_type != TUNER_ABSENT) {
+ if (core->board.tuner_type != UNSET) {
tun_setup.mode_mask = mode_mask;
tun_setup.type = core->board.tuner_type;
tun_setup.addr = core->board.tuner_addr;
@@ -3691,6 +3691,11 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
core->nr = nr;
sprintf(core->name, "cx88[%d]", core->nr);
+ core->tvnorm = V4L2_STD_NTSC_M;
+ core->width = 320;
+ core->height = 240;
+ core->field = V4L2_FIELD_INTERLACED;
+
strcpy(core->v4l2_dev.name, core->name);
if (v4l2_device_register(NULL, &core->v4l2_dev)) {
kfree(core);
@@ -3772,7 +3777,7 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
cx88_i2c_init(core, pci);
/* load tuner module, if needed */
- if (TUNER_ABSENT != core->board.tuner_type) {
+ if (UNSET != core->board.tuner_type) {
/* Ignore 0x6b and 0x6f on cx88 boards.
* FusionHDTV5 RT Gold has an ir receiver at 0x6b
* and an RTC at 0x6f which can get corrupted if probed. */
diff --git a/drivers/media/pci/cx88/cx88-core.c b/drivers/media/pci/cx88/cx88-core.c
index 7163023..dee177e 100644
--- a/drivers/media/pci/cx88/cx88-core.c
+++ b/drivers/media/pci/cx88/cx88-core.c
@@ -76,11 +76,16 @@ static DEFINE_MUTEX(devlist);
static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
unsigned int offset, u32 sync_line,
unsigned int bpl, unsigned int padding,
- unsigned int lines, unsigned int lpi)
+ unsigned int lines, unsigned int lpi, bool jump)
{
struct scatterlist *sg;
unsigned int line,todo,sol;
+ if (jump) {
+ (*rp++) = cpu_to_le32(RISC_JUMP);
+ (*rp++) = 0;
+ }
+
/* sync instruction */
if (sync_line != NO_SYNC_LINE)
*(rp++) = cpu_to_le32(RISC_RESYNC | sync_line);
@@ -90,7 +95,7 @@ static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
for (line = 0; line < lines; line++) {
while (offset && offset >= sg_dma_len(sg)) {
offset -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
if (lpi && line>0 && !(line % lpi))
sol = RISC_SOL | RISC_IRQ1 | RISC_CNT_INC;
@@ -109,13 +114,13 @@ static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
*(rp++)=cpu_to_le32(sg_dma_address(sg)+offset);
todo -= (sg_dma_len(sg)-offset);
offset = 0;
- sg++;
+ sg = sg_next(sg);
while (todo > sg_dma_len(sg)) {
*(rp++)=cpu_to_le32(RISC_WRITE|
sg_dma_len(sg));
*(rp++)=cpu_to_le32(sg_dma_address(sg));
todo -= sg_dma_len(sg);
- sg++;
+ sg = sg_next(sg);
}
*(rp++)=cpu_to_le32(RISC_WRITE|RISC_EOL|todo);
*(rp++)=cpu_to_le32(sg_dma_address(sg));
@@ -127,14 +132,13 @@ static __le32* cx88_risc_field(__le32 *rp, struct scatterlist *sglist,
return rp;
}
-int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc,
struct scatterlist *sglist,
unsigned int top_offset, unsigned int bottom_offset,
unsigned int bpl, unsigned int padding, unsigned int lines)
{
u32 instructions,fields;
__le32 *rp;
- int rc;
fields = 0;
if (UNSET != top_offset)
@@ -147,18 +151,21 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
can cause next bpl to start close to a page border. First DMA
region may be smaller than PAGE_SIZE */
instructions = fields * (1 + ((bpl + padding) * lines) / PAGE_SIZE + lines);
- instructions += 2;
- if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
- return rc;
+ instructions += 4;
+ risc->size = instructions * 8;
+ risc->dma = 0;
+ risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma);
+ if (NULL == risc->cpu)
+ return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
if (UNSET != top_offset)
rp = cx88_risc_field(rp, sglist, top_offset, 0,
- bpl, padding, lines, 0);
+ bpl, padding, lines, 0, true);
if (UNSET != bottom_offset)
rp = cx88_risc_field(rp, sglist, bottom_offset, 0x200,
- bpl, padding, lines, 0);
+ bpl, padding, lines, 0, top_offset == UNSET);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -166,26 +173,28 @@ int cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
return 0;
}
-int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+int cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc,
struct scatterlist *sglist, unsigned int bpl,
unsigned int lines, unsigned int lpi)
{
u32 instructions;
__le32 *rp;
- int rc;
/* estimate risc mem: worst case is one write per page border +
one write per scan line + syncs + jump (all 2 dwords). Here
there is no padding and no sync. First DMA region may be smaller
than PAGE_SIZE */
instructions = 1 + (bpl * lines) / PAGE_SIZE + lines;
- instructions += 1;
- if ((rc = btcx_riscmem_alloc(pci,risc,instructions*8)) < 0)
- return rc;
+ instructions += 3;
+ risc->size = instructions * 8;
+ risc->dma = 0;
+ risc->cpu = pci_zalloc_consistent(pci, risc->size, &risc->dma);
+ if (NULL == risc->cpu)
+ return -ENOMEM;
/* write risc instructions */
rp = risc->cpu;
- rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi);
+ rp = cx88_risc_field(rp, sglist, 0, NO_SYNC_LINE, bpl, 0, lines, lpi, !lpi);
/* save pointer to jmp instruction address */
risc->jmp = rp;
@@ -193,39 +202,6 @@ int cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
return 0;
}
-int cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value)
-{
- __le32 *rp;
- int rc;
-
- if ((rc = btcx_riscmem_alloc(pci, risc, 4*16)) < 0)
- return rc;
-
- /* write risc instructions */
- rp = risc->cpu;
- *(rp++) = cpu_to_le32(RISC_WRITECR | RISC_IRQ2 | RISC_IMM);
- *(rp++) = cpu_to_le32(reg);
- *(rp++) = cpu_to_le32(value);
- *(rp++) = cpu_to_le32(mask);
- *(rp++) = cpu_to_le32(RISC_JUMP);
- *(rp++) = cpu_to_le32(risc->dma);
- return 0;
-}
-
-void
-cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
-{
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
-
- BUG_ON(in_interrupt());
- videobuf_waiton(q, &buf->vb, 0, 0);
- videobuf_dma_unmap(q->dev, dma);
- videobuf_dma_free(dma);
- btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
- buf->vb.state = VIDEOBUF_NEEDS_INIT;
-}
-
/* ------------------------------------------------------------------ */
/* our SRAM memory layout */
@@ -539,33 +515,12 @@ void cx88_wakeup(struct cx88_core *core,
struct cx88_dmaqueue *q, u32 count)
{
struct cx88_buffer *buf;
- int bc;
-
- for (bc = 0;; bc++) {
- if (list_empty(&q->active))
- break;
- buf = list_entry(q->active.next,
- struct cx88_buffer, vb.queue);
- /* count comes from the hw and is is 16bit wide --
- * this trick handles wrap-arounds correctly for
- * up to 32767 buffers in flight... */
- if ((s16) (count - buf->count) < 0)
- break;
- v4l2_get_timestamp(&buf->vb.ts);
- dprintk(2,"[%p/%d] wakeup reg=%d buf=%d\n",buf,buf->vb.i,
- count, buf->count);
- buf->vb.state = VIDEOBUF_DONE;
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
- }
- if (list_empty(&q->active)) {
- del_timer(&q->timeout);
- } else {
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- }
- if (bc != 1)
- dprintk(2, "%s: %d buffers handled (should be 1)\n",
- __func__, bc);
+
+ buf = list_entry(q->active.next,
+ struct cx88_buffer, list);
+ v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
void cx88_shutdown(struct cx88_core *core)
@@ -909,6 +864,13 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
u32 bdelay,agcdelay,htotal;
u32 cxiformat, cxoformat;
+ if (norm == core->tvnorm)
+ return 0;
+ if (core->v4ldev && (vb2_is_busy(&core->v4ldev->vb2_vidq) ||
+ vb2_is_busy(&core->v4ldev->vb2_vbiq)))
+ return -EBUSY;
+ if (core->dvbdev && vb2_is_busy(&core->dvbdev->vb2_mpegq))
+ return -EBUSY;
core->tvnorm = norm;
fsc8 = norm_fsc8(norm);
adc_clock = xtal;
@@ -1043,6 +1005,7 @@ struct video_device *cx88_vdev_init(struct cx88_core *core,
vfd->v4l2_dev = &core->v4l2_dev;
vfd->dev_parent = &pci->dev;
vfd->release = video_device_release;
+ vfd->lock = &core->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)",
core->name, type, core->board.name);
return vfd;
@@ -1114,8 +1077,6 @@ EXPORT_SYMBOL(cx88_shutdown);
EXPORT_SYMBOL(cx88_risc_buffer);
EXPORT_SYMBOL(cx88_risc_databuffer);
-EXPORT_SYMBOL(cx88_risc_stopper);
-EXPORT_SYMBOL(cx88_free_buffer);
EXPORT_SYMBOL(cx88_sram_channels);
EXPORT_SYMBOL(cx88_sram_channel_setup);
diff --git a/drivers/media/pci/cx88/cx88-dvb.c b/drivers/media/pci/cx88/cx88-dvb.c
index 053ed1b..c344bfd 100644
--- a/drivers/media/pci/cx88/cx88-dvb.c
+++ b/drivers/media/pci/cx88/cx88-dvb.c
@@ -82,43 +82,89 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
/* ------------------------------------------------------------------ */
-static int dvb_buf_setup(struct videobuf_queue *q,
- unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx8802_dev *dev = q->priv_data;
+ struct cx8802_dev *dev = q->drv_priv;
+ *num_planes = 1;
dev->ts_packet_size = 188 * 4;
dev->ts_packet_count = dvb_buf_tscnt;
-
- *size = dev->ts_packet_size * dev->ts_packet_count;
- *count = dvb_buf_tscnt;
+ sizes[0] = dev->ts_packet_size * dev->ts_packet_count;
+ *num_buffers = dvb_buf_tscnt;
return 0;
}
-static int dvb_buf_prepare(struct videobuf_queue *q,
- struct videobuf_buffer *vb, enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
+{
+ struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+
+ return cx8802_buf_prepare(vb->vb2_queue, dev, buf);
+}
+
+static void buffer_finish(struct vb2_buffer *vb)
+{
+ struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ struct cx88_riscmem *risc = &buf->risc;
+
+ if (risc->cpu)
+ pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ memset(risc, 0, sizeof(*risc));
+
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+}
+
+static void buffer_queue(struct vb2_buffer *vb)
{
- struct cx8802_dev *dev = q->priv_data;
- return cx8802_buf_prepare(q, dev, (struct cx88_buffer*)vb,field);
+ struct cx8802_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+
+ cx8802_buf_queue(dev, buf);
}
-static void dvb_buf_queue(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct cx8802_dev *dev = q->priv_data;
- cx8802_buf_queue(dev, (struct cx88_buffer*)vb);
+ struct cx8802_dev *dev = q->drv_priv;
+ struct cx88_dmaqueue *dmaq = &dev->mpegq;
+ struct cx88_buffer *buf;
+
+ buf = list_entry(dmaq->active.next, struct cx88_buffer, list);
+ cx8802_start_dma(dev, dmaq, buf);
+ return 0;
}
-static void dvb_buf_release(struct videobuf_queue *q,
- struct videobuf_buffer *vb)
+static void stop_streaming(struct vb2_queue *q)
{
- cx88_free_buffer(q, (struct cx88_buffer*)vb);
+ struct cx8802_dev *dev = q->drv_priv;
+ struct cx88_dmaqueue *dmaq = &dev->mpegq;
+ unsigned long flags;
+
+ cx8802_cancel_buffers(dev);
+
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static const struct videobuf_queue_ops dvb_qops = {
- .buf_setup = dvb_buf_setup,
- .buf_prepare = dvb_buf_prepare,
- .buf_queue = dvb_buf_queue,
- .buf_release = dvb_buf_release,
+static struct vb2_ops dvb_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
};
/* ------------------------------------------------------------------ */
@@ -130,7 +176,7 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
int ret = 0;
int fe_id;
- fe_id = videobuf_dvb_find_frontend(&dev->frontends, fe);
+ fe_id = vb2_dvb_find_frontend(&dev->frontends, fe);
if (!fe_id) {
printk(KERN_ERR "%s() No frontend found\n", __func__);
return -EINVAL;
@@ -154,8 +200,8 @@ static int cx88_dvb_bus_ctrl(struct dvb_frontend* fe, int acquire)
static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open)
{
- struct videobuf_dvb_frontends *f;
- struct videobuf_dvb_frontend *fe;
+ struct vb2_dvb_frontends *f;
+ struct vb2_dvb_frontend *fe;
if (!core->dvbdev)
return;
@@ -166,9 +212,9 @@ static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open)
return;
if (f->gate <= 1) /* undefined or fe0 */
- fe = videobuf_dvb_get_frontend(f, 1);
+ fe = vb2_dvb_get_frontend(f, 1);
else
- fe = videobuf_dvb_get_frontend(f, f->gate);
+ fe = vb2_dvb_get_frontend(f, f->gate);
if (fe && fe->dvb.frontend && fe->dvb.frontend->ops.i2c_gate_ctrl)
fe->dvb.frontend->ops.i2c_gate_ctrl(fe->dvb.frontend, open);
@@ -565,7 +611,7 @@ static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
{
struct dvb_frontend *fe;
- struct videobuf_dvb_frontend *fe0 = NULL;
+ struct vb2_dvb_frontend *fe0 = NULL;
struct xc2028_ctrl ctl;
struct xc2028_config cfg = {
.i2c_adap = &dev->core->i2c_adap,
@@ -574,7 +620,7 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
};
/* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
@@ -611,10 +657,10 @@ static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
static int attach_xc4000(struct cx8802_dev *dev, struct xc4000_config *cfg)
{
struct dvb_frontend *fe;
- struct videobuf_dvb_frontend *fe0 = NULL;
+ struct vb2_dvb_frontend *fe0 = NULL;
/* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
return -EINVAL;
@@ -745,7 +791,7 @@ static const struct stv0288_config tevii_tuner_earda_config = {
static int cx8802_alloc_frontends(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
- struct videobuf_dvb_frontend *fe = NULL;
+ struct vb2_dvb_frontend *fe = NULL;
int i;
mutex_init(&dev->frontends.lock);
@@ -757,10 +803,10 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev)
printk(KERN_INFO "%s() allocating %d frontend(s)\n", __func__,
core->board.num_frontends);
for (i = 1; i <= core->board.num_frontends; i++) {
- fe = videobuf_dvb_alloc_frontend(&dev->frontends, i);
+ fe = vb2_dvb_alloc_frontend(&dev->frontends, i);
if (!fe) {
printk(KERN_ERR "%s() failed to alloc\n", __func__);
- videobuf_dvb_dealloc_frontends(&dev->frontends);
+ vb2_dvb_dealloc_frontends(&dev->frontends);
return -ENOMEM;
}
}
@@ -958,7 +1004,7 @@ static const struct stv0299_config samsung_stv0299_config = {
static int dvb_register(struct cx8802_dev *dev)
{
struct cx88_core *core = dev->core;
- struct videobuf_dvb_frontend *fe0, *fe1 = NULL;
+ struct vb2_dvb_frontend *fe0, *fe1 = NULL;
int mfe_shared = 0; /* bus not shared by default */
int res = -EINVAL;
@@ -968,7 +1014,7 @@ static int dvb_register(struct cx8802_dev *dev)
}
/* Get the first frontend */
- fe0 = videobuf_dvb_get_frontend(&dev->frontends, 1);
+ fe0 = vb2_dvb_get_frontend(&dev->frontends, 1);
if (!fe0)
goto frontend_detach;
@@ -1046,7 +1092,7 @@ static int dvb_register(struct cx8802_dev *dev)
goto frontend_detach;
}
/* MFE frontend 2 */
- fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+ fe1 = vb2_dvb_get_frontend(&dev->frontends, 2);
if (!fe1)
goto frontend_detach;
/* DVB-T init */
@@ -1415,7 +1461,7 @@ static int dvb_register(struct cx8802_dev *dev)
goto frontend_detach;
}
/* MFE frontend 2 */
- fe1 = videobuf_dvb_get_frontend(&dev->frontends, 2);
+ fe1 = vb2_dvb_get_frontend(&dev->frontends, 2);
if (!fe1)
goto frontend_detach;
/* DVB-T Init */
@@ -1594,7 +1640,7 @@ static int dvb_register(struct cx8802_dev *dev)
call_all(core, core, s_power, 0);
/* register everything */
- res = videobuf_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
+ res = vb2_dvb_register_bus(&dev->frontends, THIS_MODULE, dev,
&dev->pci->dev, adapter_nr, mfe_shared);
if (res)
goto frontend_detach;
@@ -1602,7 +1648,7 @@ static int dvb_register(struct cx8802_dev *dev)
frontend_detach:
core->gate_ctrl = NULL;
- videobuf_dvb_dealloc_frontends(&dev->frontends);
+ vb2_dvb_dealloc_frontends(&dev->frontends);
return res;
}
@@ -1697,7 +1743,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
struct cx88_core *core = drv->core;
struct cx8802_dev *dev = drv->core->dvbdev;
int err;
- struct videobuf_dvb_frontend *fe;
+ struct vb2_dvb_frontend *fe;
int i;
dprintk( 1, "%s\n", __func__);
@@ -1726,19 +1772,31 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
err = -ENODEV;
for (i = 1; i <= core->board.num_frontends; i++) {
- fe = videobuf_dvb_get_frontend(&core->dvbdev->frontends, i);
+ struct vb2_queue *q;
+
+ fe = vb2_dvb_get_frontend(&core->dvbdev->frontends, i);
if (fe == NULL) {
printk(KERN_ERR "%s() failed to get frontend(%d)\n",
__func__, i);
goto fail_probe;
}
- videobuf_queue_sg_init(&fe->dvb.dvbq, &dvb_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_TOP,
- sizeof(struct cx88_buffer),
- dev, NULL);
- /* init struct videobuf_dvb */
+ q = &fe->dvb.dvbq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx88_buffer);
+ q->ops = &dvb_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &core->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_probe;
+
+ /* init struct vb2_dvb */
fe->dvb.name = dev->core->name;
}
@@ -1749,7 +1807,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
core->name, err);
return err;
fail_probe:
- videobuf_dvb_dealloc_frontends(&core->dvbdev->frontends);
+ vb2_dvb_dealloc_frontends(&core->dvbdev->frontends);
fail_core:
return err;
}
@@ -1761,7 +1819,7 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
dprintk( 1, "%s\n", __func__);
- videobuf_dvb_unregister_bus(&dev->frontends);
+ vb2_dvb_unregister_bus(&dev->frontends);
vp3054_i2c_remove(dev);
diff --git a/drivers/media/pci/cx88/cx88-mpeg.c b/drivers/media/pci/cx88/cx88-mpeg.c
index 74b7b86..f181a3a 100644
--- a/drivers/media/pci/cx88/cx88-mpeg.c
+++ b/drivers/media/pci/cx88/cx88-mpeg.c
@@ -86,21 +86,21 @@ static LIST_HEAD(cx8802_devlist);
static DEFINE_MUTEX(cx8802_mutex);
/* ------------------------------------------------------------------ */
-static int cx8802_start_dma(struct cx8802_dev *dev,
+int cx8802_start_dma(struct cx8802_dev *dev,
struct cx88_dmaqueue *q,
struct cx88_buffer *buf)
{
struct cx88_core *core = dev->core;
dprintk(1, "cx8802_start_dma w: %d, h: %d, f: %d\n",
- buf->vb.width, buf->vb.height, buf->vb.field);
+ core->width, core->height, core->field);
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH28],
dev->ts_packet_size, buf->risc.dma);
/* write TS length to chip */
- cx_write(MO_TS_LNGTH, buf->vb.width);
+ cx_write(MO_TS_LNGTH, dev->ts_packet_size);
/* FIXME: this needs a review.
* also: move to cx88-blackbird + cx88-dvb source files? */
@@ -210,83 +210,44 @@ static int cx8802_restart_queue(struct cx8802_dev *dev,
dprintk( 1, "cx8802_restart_queue\n" );
if (list_empty(&q->active))
- {
- struct cx88_buffer *prev;
- prev = NULL;
-
- dprintk(1, "cx8802_restart_queue: queue is empty\n" );
-
- for (;;) {
- if (list_empty(&q->queued))
- return 0;
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
- if (NULL == prev) {
- list_move_tail(&buf->vb.queue, &q->active);
- cx8802_start_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(1,"[%p/%d] restart_queue - first active\n",
- buf,buf->vb.i);
-
- } else if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_move_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(1,"[%p/%d] restart_queue - move to active\n",
- buf,buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
return 0;
- }
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx88_buffer, list);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
cx8802_start_dma(dev, q, buf);
- list_for_each_entry(buf, &q->active, vb.queue)
+ list_for_each_entry(buf, &q->active, list)
buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
/* ------------------------------------------------------------------ */
-int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
- struct cx88_buffer *buf, enum v4l2_field field)
+int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev,
+ struct cx88_buffer *buf)
{
int size = dev->ts_packet_size * dev->ts_packet_count;
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(&buf->vb, 0);
+ struct cx88_riscmem *risc = &buf->risc;
int rc;
- dprintk(1, "%s: %p\n", __func__, buf);
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ if (vb2_plane_size(&buf->vb, 0) < size)
return -EINVAL;
+ vb2_set_plane_payload(&buf->vb, 0, size);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- buf->vb.width = dev->ts_packet_size;
- buf->vb.height = dev->ts_packet_count;
- buf->vb.size = size;
- buf->vb.field = field /*V4L2_FIELD_TOP*/;
-
- if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
- goto fail;
- cx88_risc_databuffer(dev->pci, &buf->risc,
- dma->sglist,
- buf->vb.width, buf->vb.height, 0);
+ rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+ if (!rc)
+ return -EIO;
+
+ rc = cx88_risc_databuffer(dev->pci, risc, sgt->sgl,
+ dev->ts_packet_size, dev->ts_packet_count, 0);
+ if (rc) {
+ if (risc->cpu)
+ pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ memset(risc, 0, sizeof(*risc));
+ return rc;
}
- buf->vb.state = VIDEOBUF_PREPARED;
return 0;
-
- fail:
- cx88_free_buffer(q,buf);
- return rc;
}
void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
@@ -295,35 +256,33 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
struct cx88_dmaqueue *cx88q = &dev->mpegq;
dprintk( 1, "cx8802_buf_queue\n" );
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(cx88q->stopper.dma);
+ /* add jump to start */
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 8);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 8);
if (list_empty(&cx88q->active)) {
dprintk( 1, "queue is empty - first active\n" );
- list_add_tail(&buf->vb.queue,&cx88q->active);
- cx8802_start_dma(dev, cx88q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
+ list_add_tail(&buf->list, &cx88q->active);
buf->count = cx88q->count++;
- mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
dprintk(1,"[%p/%d] %s - first active\n",
- buf, buf->vb.i, __func__);
+ buf, buf->vb.v4l2_buf.index, __func__);
} else {
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
dprintk( 1, "queue is not empty - append to active\n" );
- prev = list_entry(cx88q->active.prev, struct cx88_buffer, vb.queue);
- list_add_tail(&buf->vb.queue,&cx88q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
+ prev = list_entry(cx88q->active.prev, struct cx88_buffer, list);
+ list_add_tail(&buf->list, &cx88q->active);
buf->count = cx88q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
dprintk( 1, "[%p/%d] %s - append to active\n",
- buf, buf->vb.i, __func__);
+ buf, buf->vb.v4l2_buf.index, __func__);
}
}
/* ----------------------------------------------------------- */
-static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart)
+static void do_cancel_buffers(struct cx8802_dev *dev)
{
struct cx88_dmaqueue *q = &dev->mpegq;
struct cx88_buffer *buf;
@@ -331,41 +290,18 @@ static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int re
spin_lock_irqsave(&dev->slock,flags);
while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- dprintk(1,"[%p/%d] %s - dma=0x%08lx\n",
- buf, buf->vb.i, reason, (unsigned long)buf->risc.dma);
- }
- if (restart)
- {
- dprintk(1, "restarting queue\n" );
- cx8802_restart_queue(dev,q);
+ buf = list_entry(q->active.next, struct cx88_buffer, list);
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
spin_unlock_irqrestore(&dev->slock,flags);
}
void cx8802_cancel_buffers(struct cx8802_dev *dev)
{
- struct cx88_dmaqueue *q = &dev->mpegq;
-
dprintk( 1, "cx8802_cancel_buffers" );
- del_timer_sync(&q->timeout);
cx8802_stop_dma(dev);
- do_cancel_buffers(dev,"cancel",0);
-}
-
-static void cx8802_timeout(unsigned long data)
-{
- struct cx8802_dev *dev = (struct cx8802_dev*)data;
-
- dprintk(1, "%s\n",__func__);
-
- if (debug)
- cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
- cx8802_stop_dma(dev);
- do_cancel_buffers(dev,"timeout",1);
+ do_cancel_buffers(dev);
}
static const char * cx88_mpeg_irqs[32] = {
@@ -411,19 +347,11 @@ static void cx8802_mpeg_irq(struct cx8802_dev *dev)
spin_unlock(&dev->slock);
}
- /* risc2 y */
- if (status & 0x10) {
- spin_lock(&dev->slock);
- cx8802_restart_queue(dev,&dev->mpegq);
- spin_unlock(&dev->slock);
- }
-
/* other general errors */
if (status & 0x1f0100) {
dprintk( 0, "general errors: 0x%08x\n", status & 0x1f0100 );
spin_lock(&dev->slock);
cx8802_stop_dma(dev);
- cx8802_restart_queue(dev,&dev->mpegq);
spin_unlock(&dev->slock);
}
}
@@ -490,12 +418,6 @@ static int cx8802_init_common(struct cx8802_dev *dev)
/* init dma queue */
INIT_LIST_HEAD(&dev->mpegq.active);
- INIT_LIST_HEAD(&dev->mpegq.queued);
- dev->mpegq.timeout.function = cx8802_timeout;
- dev->mpegq.timeout.data = (unsigned long)dev;
- init_timer(&dev->mpegq.timeout);
- cx88_risc_stopper(dev->pci,&dev->mpegq.stopper,
- MO_TS_DMACNTRL,0x11,0x00);
/* get irq */
err = request_irq(dev->pci->irq, cx8802_irq,
@@ -520,9 +442,6 @@ static void cx8802_fini_common(struct cx8802_dev *dev)
/* unregister stuff */
free_irq(dev->pci->irq, dev);
-
- /* free memory */
- btcx_riscmem_free(dev->pci,&dev->mpegq.stopper);
}
/* ----------------------------------------------------------- */
@@ -539,7 +458,6 @@ static int cx8802_suspend_common(struct pci_dev *pci_dev, pm_message_t state)
dprintk( 2, "suspend\n" );
printk("%s: suspend mpeg\n", core->name);
cx8802_stop_dma(dev);
- del_timer(&dev->mpegq.timeout);
}
spin_unlock_irqrestore(&dev->slock, flags);
@@ -907,6 +825,7 @@ module_pci_driver(cx8802_pci_driver);
EXPORT_SYMBOL(cx8802_buf_prepare);
EXPORT_SYMBOL(cx8802_buf_queue);
EXPORT_SYMBOL(cx8802_cancel_buffers);
+EXPORT_SYMBOL(cx8802_start_dma);
EXPORT_SYMBOL(cx8802_register_driver);
EXPORT_SYMBOL(cx8802_unregister_driver);
diff --git a/drivers/media/pci/cx88/cx88-vbi.c b/drivers/media/pci/cx88/cx88-vbi.c
index f8f8389..6ab6e27 100644
--- a/drivers/media/pci/cx88/cx88-vbi.c
+++ b/drivers/media/pci/cx88/cx88-vbi.c
@@ -6,10 +6,6 @@
#include "cx88.h"
-static unsigned int vbibufs = 4;
-module_param(vbibufs,int,0644);
-MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
-
static unsigned int vbi_debug;
module_param(vbi_debug,int,0644);
MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
@@ -22,26 +18,27 @@ MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
int cx8800_vbi_fmt (struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx8800_fh *fh = priv;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = video_drvdata(file);
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
f->fmt.vbi.offset = 244;
- f->fmt.vbi.count[0] = VBI_LINE_COUNT;
- f->fmt.vbi.count[1] = VBI_LINE_COUNT;
if (dev->core->tvnorm & V4L2_STD_525_60) {
/* ntsc */
f->fmt.vbi.sampling_rate = 28636363;
f->fmt.vbi.start[0] = 10;
f->fmt.vbi.start[1] = 273;
+ f->fmt.vbi.count[0] = VBI_LINE_NTSC_COUNT;
+ f->fmt.vbi.count[1] = VBI_LINE_NTSC_COUNT;
} else if (dev->core->tvnorm & V4L2_STD_625_50) {
/* pal */
f->fmt.vbi.sampling_rate = 35468950;
- f->fmt.vbi.start[0] = 7 -1;
- f->fmt.vbi.start[1] = 319 -1;
+ f->fmt.vbi.start[0] = V4L2_VBI_ITU_625_F1_START + 5;
+ f->fmt.vbi.start[1] = V4L2_VBI_ITU_625_F2_START + 5;
+ f->fmt.vbi.count[0] = VBI_LINE_PAL_COUNT;
+ f->fmt.vbi.count[1] = VBI_LINE_PAL_COUNT;
}
return 0;
}
@@ -54,7 +51,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
/* setup fifo + format */
cx88_sram_channel_setup(dev->core, &cx88_sram_channels[SRAM_CH24],
- buf->vb.width, buf->risc.dma);
+ VBI_LINE_LENGTH, buf->risc.dma);
cx_write(MO_VBOS_CONTROL, ( (1 << 18) | // comb filter delay fixup
(1 << 15) | // enable vbi capture
@@ -78,7 +75,7 @@ static int cx8800_start_vbi_dma(struct cx8800_dev *dev,
return 0;
}
-int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
+void cx8800_stop_vbi_dma(struct cx8800_dev *dev)
{
struct cx88_core *core = dev->core;
@@ -91,7 +88,6 @@ int cx8800_stop_vbi_dma(struct cx8800_dev *dev)
/* disable irqs */
cx_clear(MO_PCI_INTMSK, PCI_INT_VIDINT);
cx_clear(MO_VID_INTMSK, 0x0f0088);
- return 0;
}
int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
@@ -102,144 +98,144 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
if (list_empty(&q->active))
return 0;
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx88_buffer, list);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
cx8800_start_vbi_dma(dev, q, buf);
- list_for_each_entry(buf, &q->active, vb.queue)
+ list_for_each_entry(buf, &q->active, list)
buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
return 0;
}
-void cx8800_vbi_timeout(unsigned long data)
-{
- struct cx8800_dev *dev = (struct cx8800_dev*)data;
- struct cx88_core *core = dev->core;
- struct cx88_dmaqueue *q = &dev->vbiq;
- struct cx88_buffer *buf;
- unsigned long flags;
-
- cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH24]);
-
- cx_clear(MO_VID_DMACNTRL, 0x88);
- cx_clear(VID_CAPTURE_CONTROL, 0x18);
-
- spin_lock_irqsave(&dev->slock,flags);
- while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", dev->core->name,
- buf, buf->vb.i, (unsigned long)buf->risc.dma);
- }
- cx8800_restart_vbi_queue(dev,q);
- spin_unlock_irqrestore(&dev->slock,flags);
-}
-
/* ------------------------------------------------------------------ */
-static int
-vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- *size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
- if (0 == *count)
- *count = vbibufs;
- if (*count < 2)
- *count = 2;
- if (*count > 32)
- *count = 32;
+ struct cx8800_dev *dev = q->drv_priv;
+
+ *num_planes = 1;
+ if (dev->core->tvnorm & V4L2_STD_525_60)
+ sizes[0] = VBI_LINE_NTSC_COUNT * VBI_LINE_LENGTH * 2;
+ else
+ sizes[0] = VBI_LINE_PAL_COUNT * VBI_LINE_LENGTH * 2;
return 0;
}
-static int
-vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx8800_fh *fh = q->priv_data;
- struct cx8800_dev *dev = fh->dev;
- struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ unsigned int lines;
unsigned int size;
int rc;
- size = VBI_LINE_COUNT * VBI_LINE_LENGTH * 2;
- if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ if (dev->core->tvnorm & V4L2_STD_525_60)
+ lines = VBI_LINE_NTSC_COUNT;
+ else
+ lines = VBI_LINE_PAL_COUNT;
+ size = lines * VBI_LINE_LENGTH * 2;
+ if (vb2_plane_size(vb, 0) < size)
return -EINVAL;
+ vb2_set_plane_payload(vb, 0, size);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- buf->vb.width = VBI_LINE_LENGTH;
- buf->vb.height = VBI_LINE_COUNT;
- buf->vb.size = size;
- buf->vb.field = V4L2_FIELD_SEQ_TB;
-
- if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
- goto fail;
- cx88_risc_buffer(dev->pci, &buf->risc,
- dma->sglist,
- 0, buf->vb.width * buf->vb.height,
- buf->vb.width, 0,
- buf->vb.height);
- }
- buf->vb.state = VIDEOBUF_PREPARED;
+ rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+ if (!rc)
+ return -EIO;
+
+ cx88_risc_buffer(dev->pci, &buf->risc, sgt->sgl,
+ 0, VBI_LINE_LENGTH * lines,
+ VBI_LINE_LENGTH, 0,
+ lines);
return 0;
+}
- fail:
- cx88_free_buffer(q,buf);
- return rc;
+static void buffer_finish(struct vb2_buffer *vb)
+{
+ struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ struct cx88_riscmem *risc = &buf->risc;
+
+ if (risc->cpu)
+ pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ memset(risc, 0, sizeof(*risc));
+
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void
-vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
- struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
struct cx88_buffer *prev;
- struct cx8800_fh *fh = vq->priv_data;
- struct cx8800_dev *dev = fh->dev;
struct cx88_dmaqueue *q = &dev->vbiq;
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+ /* add jump to start */
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 8);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 8);
if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue,&q->active);
+ list_add_tail(&buf->list, &q->active);
cx8800_start_vbi_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
dprintk(2,"[%p/%d] vbi_queue - first active\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
} else {
- prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
- list_add_tail(&buf->vb.queue,&q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
+ prev = list_entry(q->active.prev, struct cx88_buffer, list);
+ list_add_tail(&buf->list, &q->active);
buf->count = q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
dprintk(2,"[%p/%d] buffer_queue - append to active\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
}
}
-static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx8800_dev *dev = q->drv_priv;
+ struct cx88_dmaqueue *dmaq = &dev->vbiq;
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
- cx88_free_buffer(q,buf);
+ cx8800_start_vbi_dma(dev, dmaq, buf);
+ return 0;
}
-const struct videobuf_queue_ops cx8800_vbi_qops = {
- .buf_setup = vbi_setup,
- .buf_prepare = vbi_prepare,
- .buf_queue = vbi_queue,
- .buf_release = vbi_release,
-};
+static void stop_streaming(struct vb2_queue *q)
+{
+ struct cx8800_dev *dev = q->drv_priv;
+ struct cx88_core *core = dev->core;
+ struct cx88_dmaqueue *dmaq = &dev->vbiq;
+ unsigned long flags;
-/* ------------------------------------------------------------------ */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+ cx_clear(MO_VID_DMACNTRL, 0x11);
+ cx_clear(VID_CAPTURE_CONTROL, 0x06);
+ cx8800_stop_vbi_dma(dev);
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+const struct vb2_ops cx8800_vbi_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
diff --git a/drivers/media/pci/cx88/cx88-video.c b/drivers/media/pci/cx88/cx88-video.c
index ce27e6d..a64ae31 100644
--- a/drivers/media/pci/cx88/cx88-video.c
+++ b/drivers/media/pci/cx88/cx88-video.c
@@ -70,10 +70,6 @@ static unsigned int irq_debug;
module_param(irq_debug,int,0644);
MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
-static unsigned int vid_limit = 16;
-module_param(vid_limit,int,0644);
-MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
-
#define dprintk(level,fmt, arg...) if (video_debug >= level) \
printk(KERN_DEBUG "%s/0: " fmt, core->name , ## arg)
@@ -297,56 +293,6 @@ enum {
CX8800_AUD_CTLS = ARRAY_SIZE(cx8800_aud_ctls),
};
-/* ------------------------------------------------------------------- */
-/* resource management */
-
-static int res_get(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bit)
-{
- struct cx88_core *core = dev->core;
- if (fh->resources & bit)
- /* have it already allocated */
- return 1;
-
- /* is it free? */
- mutex_lock(&core->lock);
- if (dev->resources & bit) {
- /* no, someone else uses it */
- mutex_unlock(&core->lock);
- return 0;
- }
- /* it's free, grab it */
- fh->resources |= bit;
- dev->resources |= bit;
- dprintk(1,"res: get %d\n",bit);
- mutex_unlock(&core->lock);
- return 1;
-}
-
-static
-int res_check(struct cx8800_fh *fh, unsigned int bit)
-{
- return (fh->resources & bit);
-}
-
-static
-int res_locked(struct cx8800_dev *dev, unsigned int bit)
-{
- return (dev->resources & bit);
-}
-
-static
-void res_free(struct cx8800_dev *dev, struct cx8800_fh *fh, unsigned int bits)
-{
- struct cx88_core *core = dev->core;
- BUG_ON((fh->resources & bits) != bits);
-
- mutex_lock(&core->lock);
- fh->resources &= ~bits;
- dev->resources &= ~bits;
- dprintk(1,"res: put %d\n",bits);
- mutex_unlock(&core->lock);
-}
-
/* ------------------------------------------------------------------ */
int cx88_video_mux(struct cx88_core *core, unsigned int input)
@@ -419,8 +365,8 @@ static int start_video_dma(struct cx8800_dev *dev,
/* setup fifo + format */
cx88_sram_channel_setup(core, &cx88_sram_channels[SRAM_CH21],
buf->bpl, buf->risc.dma);
- cx88_set_scale(core, buf->vb.width, buf->vb.height, buf->vb.field);
- cx_write(MO_COLOR_CTRL, buf->fmt->cxformat | ColorFormatGamma);
+ cx88_set_scale(core, core->width, core->height, core->field);
+ cx_write(MO_COLOR_CTRL, dev->fmt->cxformat | ColorFormatGamma);
/* reset counter */
cx_write(MO_VIDY_GPCNTRL,GP_COUNT_CONTROL_RESET);
@@ -470,433 +416,211 @@ static int restart_video_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q)
{
struct cx88_core *core = dev->core;
- struct cx88_buffer *buf, *prev;
+ struct cx88_buffer *buf;
if (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
+ buf = list_entry(q->active.next, struct cx88_buffer, list);
dprintk(2,"restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
start_video_dma(dev, q, buf);
- list_for_each_entry(buf, &q->active, vb.queue)
+ list_for_each_entry(buf, &q->active, list)
buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- return 0;
- }
-
- prev = NULL;
- for (;;) {
- if (list_empty(&q->queued))
- return 0;
- buf = list_entry(q->queued.next, struct cx88_buffer, vb.queue);
- if (NULL == prev) {
- list_move_tail(&buf->vb.queue, &q->active);
- start_video_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(2,"[%p/%d] restart_queue - first active\n",
- buf,buf->vb.i);
-
- } else if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_move_tail(&buf->vb.queue, &q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(2,"[%p/%d] restart_queue - move to active\n",
- buf,buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
}
+ return 0;
}
/* ------------------------------------------------------------------ */
-static int
-buffer_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
+ unsigned int *num_buffers, unsigned int *num_planes,
+ unsigned int sizes[], void *alloc_ctxs[])
{
- struct cx8800_fh *fh = q->priv_data;
- struct cx8800_dev *dev = fh->dev;
-
- *size = dev->fmt->depth * dev->width * dev->height >> 3;
- if (0 == *count)
- *count = 32;
- if (*size * *count > vid_limit * 1024 * 1024)
- *count = (vid_limit * 1024 * 1024) / *size;
+ struct cx8800_dev *dev = q->drv_priv;
+ struct cx88_core *core = dev->core;
+
+ *num_planes = 1;
+ sizes[0] = (dev->fmt->depth * core->width * core->height) >> 3;
return 0;
}
-static int
-buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
- enum v4l2_field field)
+static int buffer_prepare(struct vb2_buffer *vb)
{
- struct cx8800_fh *fh = q->priv_data;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
struct cx88_core *core = dev->core;
- struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
- struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
- int rc, init_buffer = 0;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ int rc;
- BUG_ON(NULL == dev->fmt);
- if (dev->width < 48 || dev->width > norm_maxw(core->tvnorm) ||
- dev->height < 32 || dev->height > norm_maxh(core->tvnorm))
- return -EINVAL;
- buf->vb.size = (dev->width * dev->height * dev->fmt->depth) >> 3;
- if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
- return -EINVAL;
+ buf->bpl = core->width * dev->fmt->depth >> 3;
- if (buf->fmt != dev->fmt ||
- buf->vb.width != dev->width ||
- buf->vb.height != dev->height ||
- buf->vb.field != field) {
- buf->fmt = dev->fmt;
- buf->vb.width = dev->width;
- buf->vb.height = dev->height;
- buf->vb.field = field;
- init_buffer = 1;
- }
+ if (vb2_plane_size(vb, 0) < core->height * buf->bpl)
+ return -EINVAL;
+ vb2_set_plane_payload(vb, 0, core->height * buf->bpl);
- if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
- init_buffer = 1;
- if (0 != (rc = videobuf_iolock(q,&buf->vb,NULL)))
- goto fail;
- }
+ rc = dma_map_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
+ if (!rc)
+ return -EIO;
- if (init_buffer) {
- buf->bpl = buf->vb.width * buf->fmt->depth >> 3;
- switch (buf->vb.field) {
- case V4L2_FIELD_TOP:
- cx88_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, 0, UNSET,
- buf->bpl, 0, buf->vb.height);
- break;
- case V4L2_FIELD_BOTTOM:
- cx88_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, UNSET, 0,
- buf->bpl, 0, buf->vb.height);
- break;
- case V4L2_FIELD_INTERLACED:
- cx88_risc_buffer(dev->pci, &buf->risc,
- dma->sglist, 0, buf->bpl,
- buf->bpl, buf->bpl,
- buf->vb.height >> 1);
- break;
- case V4L2_FIELD_SEQ_TB:
- cx88_risc_buffer(dev->pci, &buf->risc,
- dma->sglist,
- 0, buf->bpl * (buf->vb.height >> 1),
- buf->bpl, 0,
- buf->vb.height >> 1);
- break;
- case V4L2_FIELD_SEQ_BT:
- cx88_risc_buffer(dev->pci, &buf->risc,
- dma->sglist,
- buf->bpl * (buf->vb.height >> 1), 0,
- buf->bpl, 0,
- buf->vb.height >> 1);
- break;
- default:
- BUG();
- }
+ switch (core->field) {
+ case V4L2_FIELD_TOP:
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, 0, UNSET,
+ buf->bpl, 0, core->height);
+ break;
+ case V4L2_FIELD_BOTTOM:
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, UNSET, 0,
+ buf->bpl, 0, core->height);
+ break;
+ case V4L2_FIELD_SEQ_TB:
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ 0, buf->bpl * (core->height >> 1),
+ buf->bpl, 0,
+ core->height >> 1);
+ break;
+ case V4L2_FIELD_SEQ_BT:
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl,
+ buf->bpl * (core->height >> 1), 0,
+ buf->bpl, 0,
+ core->height >> 1);
+ break;
+ case V4L2_FIELD_INTERLACED:
+ default:
+ cx88_risc_buffer(dev->pci, &buf->risc,
+ sgt->sgl, 0, buf->bpl,
+ buf->bpl, buf->bpl,
+ core->height >> 1);
+ break;
}
dprintk(2,"[%p/%d] buffer_prepare - %dx%d %dbpp \"%s\" - dma=0x%08lx\n",
- buf, buf->vb.i,
- dev->width, dev->height, dev->fmt->depth, dev->fmt->name,
+ buf, buf->vb.v4l2_buf.index,
+ core->width, core->height, dev->fmt->depth, dev->fmt->name,
(unsigned long)buf->risc.dma);
-
- buf->vb.state = VIDEOBUF_PREPARED;
return 0;
+}
+
+static void buffer_finish(struct vb2_buffer *vb)
+{
+ struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
+ struct sg_table *sgt = vb2_dma_sg_plane_desc(vb, 0);
+ struct cx88_riscmem *risc = &buf->risc;
+
+ if (risc->cpu)
+ pci_free_consistent(dev->pci, risc->size, risc->cpu, risc->dma);
+ memset(risc, 0, sizeof(*risc));
- fail:
- cx88_free_buffer(q,buf);
- return rc;
+ dma_unmap_sg(&dev->pci->dev, sgt->sgl, sgt->nents, DMA_FROM_DEVICE);
}
-static void
-buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+static void buffer_queue(struct vb2_buffer *vb)
{
- struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx8800_dev *dev = vb->vb2_queue->drv_priv;
+ struct cx88_buffer *buf = container_of(vb, struct cx88_buffer, vb);
struct cx88_buffer *prev;
- struct cx8800_fh *fh = vq->priv_data;
- struct cx8800_dev *dev = fh->dev;
struct cx88_core *core = dev->core;
struct cx88_dmaqueue *q = &dev->vidq;
- /* add jump to stopper */
- buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_IRQ1 | RISC_CNT_INC);
- buf->risc.jmp[1] = cpu_to_le32(q->stopper.dma);
+ /* add jump to start */
+ buf->risc.cpu[1] = cpu_to_le32(buf->risc.dma + 8);
+ buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP | RISC_CNT_INC);
+ buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma + 8);
- if (!list_empty(&q->queued)) {
- list_add_tail(&buf->vb.queue,&q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2,"[%p/%d] buffer_queue - append to queued\n",
- buf, buf->vb.i);
-
- } else if (list_empty(&q->active)) {
- list_add_tail(&buf->vb.queue,&q->active);
+ if (list_empty(&q->active)) {
+ list_add_tail(&buf->list, &q->active);
start_video_dma(dev, q, buf);
- buf->vb.state = VIDEOBUF_ACTIVE;
buf->count = q->count++;
- mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
dprintk(2,"[%p/%d] buffer_queue - first active\n",
- buf, buf->vb.i);
+ buf, buf->vb.v4l2_buf.index);
} else {
- prev = list_entry(q->active.prev, struct cx88_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue,&q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- buf->count = q->count++;
- prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- dprintk(2,"[%p/%d] buffer_queue - append to active\n",
- buf, buf->vb.i);
-
- } else {
- list_add_tail(&buf->vb.queue,&q->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(2,"[%p/%d] buffer_queue - first queued\n",
- buf, buf->vb.i);
- }
+ buf->risc.cpu[0] |= cpu_to_le32(RISC_IRQ1);
+ prev = list_entry(q->active.prev, struct cx88_buffer, list);
+ list_add_tail(&buf->list, &q->active);
+ buf->count = q->count++;
+ prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
+ dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+ buf, buf->vb.v4l2_buf.index);
}
}
-static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+static int start_streaming(struct vb2_queue *q, unsigned int count)
{
- struct cx88_buffer *buf = container_of(vb,struct cx88_buffer,vb);
+ struct cx8800_dev *dev = q->drv_priv;
+ struct cx88_dmaqueue *dmaq = &dev->vidq;
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
- cx88_free_buffer(q,buf);
+ start_video_dma(dev, dmaq, buf);
+ return 0;
}
-static const struct videobuf_queue_ops cx8800_video_qops = {
- .buf_setup = buffer_setup,
- .buf_prepare = buffer_prepare,
- .buf_queue = buffer_queue,
- .buf_release = buffer_release,
-};
-
-/* ------------------------------------------------------------------ */
-
-
-/* ------------------------------------------------------------------ */
-
-static struct videobuf_queue *get_queue(struct file *file)
+static void stop_streaming(struct vb2_queue *q)
{
- struct video_device *vdev = video_devdata(file);
- struct cx8800_fh *fh = file->private_data;
+ struct cx8800_dev *dev = q->drv_priv;
+ struct cx88_core *core = dev->core;
+ struct cx88_dmaqueue *dmaq = &dev->vidq;
+ unsigned long flags;
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- return &fh->vidq;
- case VFL_TYPE_VBI:
- return &fh->vbiq;
- default:
- BUG();
+ cx_clear(MO_VID_DMACNTRL, 0x11);
+ cx_clear(VID_CAPTURE_CONTROL, 0x06);
+ spin_lock_irqsave(&dev->slock, flags);
+ while (!list_empty(&dmaq->active)) {
+ struct cx88_buffer *buf = list_entry(dmaq->active.next,
+ struct cx88_buffer, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
}
+ spin_unlock_irqrestore(&dev->slock, flags);
}
-static int get_resource(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
+static struct vb2_ops cx8800_video_qops = {
+ .queue_setup = queue_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_finish = buffer_finish,
+ .buf_queue = buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = start_streaming,
+ .stop_streaming = stop_streaming,
+};
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- return RESOURCE_VIDEO;
- case VFL_TYPE_VBI:
- return RESOURCE_VBI;
- default:
- BUG();
- }
-}
+/* ------------------------------------------------------------------ */
-static int video_open(struct file *file)
+static int radio_open(struct file *file)
{
- struct video_device *vdev = video_devdata(file);
struct cx8800_dev *dev = video_drvdata(file);
struct cx88_core *core = dev->core;
- struct cx8800_fh *fh;
- enum v4l2_buf_type type = 0;
- int radio = 0;
+ int ret = v4l2_fh_open(file);
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- break;
- case VFL_TYPE_VBI:
- type = V4L2_BUF_TYPE_VBI_CAPTURE;
- break;
- case VFL_TYPE_RADIO:
- radio = 1;
- break;
- }
-
- dprintk(1, "open dev=%s radio=%d type=%s\n",
- video_device_node_name(vdev), radio, v4l2_type_names[type]);
-
- /* allocate + initialize per filehandle data */
- fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (unlikely(!fh))
- return -ENOMEM;
-
- v4l2_fh_init(&fh->fh, vdev);
- file->private_data = fh;
- fh->dev = dev;
+ if (ret)
+ return ret;
- mutex_lock(&core->lock);
-
- videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_INTERLACED,
- sizeof(struct cx88_buffer),
- fh, NULL);
- videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops,
- &dev->pci->dev, &dev->slock,
- V4L2_BUF_TYPE_VBI_CAPTURE,
- V4L2_FIELD_SEQ_TB,
- sizeof(struct cx88_buffer),
- fh, NULL);
-
- if (vdev->vfl_type == VFL_TYPE_RADIO) {
- dprintk(1,"video_open: setting radio device\n");
- cx_write(MO_GP3_IO, core->board.radio.gpio3);
- cx_write(MO_GP0_IO, core->board.radio.gpio0);
- cx_write(MO_GP1_IO, core->board.radio.gpio1);
- cx_write(MO_GP2_IO, core->board.radio.gpio2);
- if (core->board.radio.audioroute) {
- if (core->sd_wm8775) {
- call_all(core, audio, s_routing,
+ cx_write(MO_GP3_IO, core->board.radio.gpio3);
+ cx_write(MO_GP0_IO, core->board.radio.gpio0);
+ cx_write(MO_GP1_IO, core->board.radio.gpio1);
+ cx_write(MO_GP2_IO, core->board.radio.gpio2);
+ if (core->board.radio.audioroute) {
+ if (core->sd_wm8775) {
+ call_all(core, audio, s_routing,
core->board.radio.audioroute, 0, 0);
- }
- /* "I2S ADC mode" */
- core->tvaudio = WW_I2SADC;
- cx88_set_tvaudio(core);
- } else {
- /* FM Mode */
- core->tvaudio = WW_FM;
- cx88_set_tvaudio(core);
- cx88_set_stereo(core,V4L2_TUNER_MODE_STEREO,1);
}
- call_all(core, tuner, s_radio);
- }
-
- core->users++;
- mutex_unlock(&core->lock);
- v4l2_fh_add(&fh->fh);
-
- return 0;
-}
-
-static ssize_t
-video_read(struct file *file, char __user *data, size_t count, loff_t *ppos)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx8800_fh *fh = file->private_data;
-
- switch (vdev->vfl_type) {
- case VFL_TYPE_GRABBER:
- if (res_locked(fh->dev,RESOURCE_VIDEO))
- return -EBUSY;
- return videobuf_read_one(&fh->vidq, data, count, ppos,
- file->f_flags & O_NONBLOCK);
- case VFL_TYPE_VBI:
- if (!res_get(fh->dev,fh,RESOURCE_VBI))
- return -EBUSY;
- return videobuf_read_stream(&fh->vbiq, data, count, ppos, 1,
- file->f_flags & O_NONBLOCK);
- default:
- BUG();
- }
-}
-
-static unsigned int
-video_poll(struct file *file, struct poll_table_struct *wait)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx8800_fh *fh = file->private_data;
- struct cx88_buffer *buf;
- unsigned int rc = v4l2_ctrl_poll(file, wait);
-
- if (vdev->vfl_type == VFL_TYPE_VBI) {
- if (!res_get(fh->dev,fh,RESOURCE_VBI))
- return rc | POLLERR;
- return rc | videobuf_poll_stream(file, &fh->vbiq, wait);
- }
- mutex_lock(&fh->vidq.vb_lock);
- if (res_check(fh,RESOURCE_VIDEO)) {
- /* streaming capture */
- if (list_empty(&fh->vidq.stream))
- goto done;
- buf = list_entry(fh->vidq.stream.next,struct cx88_buffer,vb.stream);
+ /* "I2S ADC mode" */
+ core->tvaudio = WW_I2SADC;
+ cx88_set_tvaudio(core);
} else {
- /* read() capture */
- buf = (struct cx88_buffer*)fh->vidq.read_buf;
- if (NULL == buf)
- goto done;
- }
- poll_wait(file, &buf->vb.done, wait);
- if (buf->vb.state == VIDEOBUF_DONE ||
- buf->vb.state == VIDEOBUF_ERROR)
- rc |= POLLIN|POLLRDNORM;
-done:
- mutex_unlock(&fh->vidq.vb_lock);
- return rc;
-}
-
-static int video_release(struct file *file)
-{
- struct cx8800_fh *fh = file->private_data;
- struct cx8800_dev *dev = fh->dev;
-
- /* turn off overlay */
- if (res_check(fh, RESOURCE_OVERLAY)) {
- /* FIXME */
- res_free(dev,fh,RESOURCE_OVERLAY);
- }
-
- /* stop video capture */
- if (res_check(fh, RESOURCE_VIDEO)) {
- videobuf_queue_cancel(&fh->vidq);
- res_free(dev,fh,RESOURCE_VIDEO);
+ /* FM Mode */
+ core->tvaudio = WW_FM;
+ cx88_set_tvaudio(core);
+ cx88_set_stereo(core, V4L2_TUNER_MODE_STEREO, 1);
}
- if (fh->vidq.read_buf) {
- buffer_release(&fh->vidq,fh->vidq.read_buf);
- kfree(fh->vidq.read_buf);
- }
-
- /* stop vbi capture */
- if (res_check(fh, RESOURCE_VBI)) {
- videobuf_stop(&fh->vbiq);
- res_free(dev,fh,RESOURCE_VBI);
- }
-
- videobuf_mmap_free(&fh->vidq);
- videobuf_mmap_free(&fh->vbiq);
-
- mutex_lock(&dev->core->lock);
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- file->private_data = NULL;
- kfree(fh);
-
- dev->core->users--;
- if (!dev->core->users)
- call_all(dev->core, core, s_power, 0);
- mutex_unlock(&dev->core->lock);
-
+ call_all(core, tuner, s_radio);
return 0;
}
-static int
-video_mmap(struct file *file, struct vm_area_struct * vma)
-{
- return videobuf_mmap_mapper(get_queue(file), vma);
-}
-
/* ------------------------------------------------------------------ */
/* VIDEO CTRL IOCTLS */
@@ -999,12 +723,12 @@ static int cx8800_s_aud_ctrl(struct v4l2_ctrl *ctrl)
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx8800_fh *fh = priv;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
- f->fmt.pix.width = dev->width;
- f->fmt.pix.height = dev->height;
- f->fmt.pix.field = fh->vidq.field;
+ f->fmt.pix.width = core->width;
+ f->fmt.pix.height = core->height;
+ f->fmt.pix.field = core->field;
f->fmt.pix.pixelformat = dev->fmt->fourcc;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * dev->fmt->depth) >> 3;
@@ -1017,7 +741,8 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
const struct cx8800_fmt *fmt;
enum v4l2_field field;
unsigned int maxw, maxh;
@@ -1026,30 +751,30 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
if (NULL == fmt)
return -EINVAL;
- field = f->fmt.pix.field;
- maxw = norm_maxw(core->tvnorm);
- maxh = norm_maxh(core->tvnorm);
+ maxw = norm_maxw(core->tvnorm);
+ maxh = norm_maxh(core->tvnorm);
- if (V4L2_FIELD_ANY == field) {
- field = (f->fmt.pix.height > maxh/2)
- ? V4L2_FIELD_INTERLACED
- : V4L2_FIELD_BOTTOM;
- }
+ field = f->fmt.pix.field;
switch (field) {
case V4L2_FIELD_TOP:
case V4L2_FIELD_BOTTOM:
- maxh = maxh / 2;
- break;
case V4L2_FIELD_INTERLACED:
+ case V4L2_FIELD_SEQ_BT:
+ case V4L2_FIELD_SEQ_TB:
break;
default:
- return -EINVAL;
+ field = (f->fmt.pix.height > maxh / 2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_BOTTOM;
+ break;
}
+ if (V4L2_FIELD_HAS_T_OR_B(field))
+ maxh /= 2;
- f->fmt.pix.field = field;
v4l_bound_align_image(&f->fmt.pix.width, 48, maxw, 2,
&f->fmt.pix.height, 32, maxh, 0, 0);
+ f->fmt.pix.field = field;
f->fmt.pix.bytesperline =
(f->fmt.pix.width * fmt->depth) >> 3;
f->fmt.pix.sizeimage =
@@ -1061,16 +786,20 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct cx8800_fh *fh = priv;
- struct cx8800_dev *dev = fh->dev;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
int err = vidioc_try_fmt_vid_cap (file,priv,f);
if (0 != err)
return err;
- dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- dev->width = f->fmt.pix.width;
- dev->height = f->fmt.pix.height;
- fh->vidq.field = f->fmt.pix.field;
+ if (vb2_is_busy(&dev->vb2_vidq) || vb2_is_busy(&dev->vb2_vbiq))
+ return -EBUSY;
+ if (core->dvbdev && vb2_is_busy(&core->dvbdev->vb2_mpegq))
+ return -EBUSY;
+ dev->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ core->width = f->fmt.pix.width;
+ core->height = f->fmt.pix.height;
+ core->field = f->fmt.pix.field;
return 0;
}
@@ -1104,8 +833,8 @@ EXPORT_SYMBOL(cx88_querycap);
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct cx8800_dev *dev = ((struct cx8800_fh *)priv)->dev;
- struct cx88_core *core = dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
strcpy(cap->driver, "cx8800");
sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
@@ -1125,64 +854,10 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
return 0;
}
-static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
-{
- return videobuf_reqbufs(get_queue(file), p);
-}
-
-static int vidioc_querybuf (struct file *file, void *priv, struct v4l2_buffer *p)
-{
- return videobuf_querybuf(get_queue(file), p);
-}
-
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *p)
-{
- return videobuf_qbuf(get_queue(file), p);
-}
-
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *p)
-{
- return videobuf_dqbuf(get_queue(file), p,
- file->f_flags & O_NONBLOCK);
-}
-
-static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx8800_fh *fh = priv;
- struct cx8800_dev *dev = fh->dev;
-
- if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- if (unlikely(!res_get(dev, fh, get_resource(file))))
- return -EBUSY;
- return videobuf_streamon(get_queue(file));
-}
-
-static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
-{
- struct video_device *vdev = video_devdata(file);
- struct cx8800_fh *fh = priv;
- struct cx8800_dev *dev = fh->dev;
- int err, res;
-
- if ((vdev->vfl_type == VFL_TYPE_GRABBER && i != V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
- (vdev->vfl_type == VFL_TYPE_VBI && i != V4L2_BUF_TYPE_VBI_CAPTURE))
- return -EINVAL;
-
- res = get_resource(file);
- err = videobuf_streamoff(get_queue(file));
- if (err < 0)
- return err;
- res_free(dev,fh,res);
- return 0;
-}
-
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
*tvnorm = core->tvnorm;
return 0;
@@ -1190,13 +865,10 @@ static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *tvnorm)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id tvnorms)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
-
- mutex_lock(&core->lock);
- cx88_set_tvnorm(core, tvnorms);
- mutex_unlock(&core->lock);
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
- return 0;
+ return cx88_set_tvnorm(core, tvnorms);
}
/* only one input in this sample driver */
@@ -1233,13 +905,15 @@ EXPORT_SYMBOL(cx88_enum_input);
static int vidioc_enum_input (struct file *file, void *priv,
struct v4l2_input *i)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
return cx88_enum_input (core,i);
}
static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
*i = core->input;
return 0;
@@ -1247,24 +921,24 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *i)
static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (i >= 4)
return -EINVAL;
if (0 == INPUT(i).type)
return -EINVAL;
- mutex_lock(&core->lock);
cx88_newstation(core);
cx88_video_mux(core,i);
- mutex_unlock(&core->lock);
return 0;
}
static int vidioc_g_tuner (struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
u32 reg;
if (unlikely(UNSET == core->board.tuner_type))
@@ -1286,7 +960,8 @@ static int vidioc_g_tuner (struct file *file, void *priv,
static int vidioc_s_tuner (struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (UNSET == core->board.tuner_type)
return -EINVAL;
@@ -1300,8 +975,8 @@ static int vidioc_s_tuner (struct file *file, void *priv,
static int vidioc_g_frequency (struct file *file, void *priv,
struct v4l2_frequency *f)
{
- struct cx8800_fh *fh = priv;
- struct cx88_core *core = fh->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (unlikely(UNSET == core->board.tuner_type))
return -EINVAL;
@@ -1325,7 +1000,6 @@ int cx88_set_freq (struct cx88_core *core,
if (unlikely(f->tuner != 0))
return -EINVAL;
- mutex_lock(&core->lock);
cx88_newstation(core);
call_all(core, tuner, s_frequency, f);
call_all(core, tuner, g_frequency, &new_freq);
@@ -1335,8 +1009,6 @@ int cx88_set_freq (struct cx88_core *core,
msleep (10);
cx88_set_tvaudio(core);
- mutex_unlock(&core->lock);
-
return 0;
}
EXPORT_SYMBOL(cx88_set_freq);
@@ -1344,8 +1016,8 @@ EXPORT_SYMBOL(cx88_set_freq);
static int vidioc_s_frequency (struct file *file, void *priv,
const struct v4l2_frequency *f)
{
- struct cx8800_fh *fh = priv;
- struct cx88_core *core = fh->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
return cx88_set_freq(core, f);
}
@@ -1354,7 +1026,8 @@ static int vidioc_s_frequency (struct file *file, void *priv,
static int vidioc_g_register (struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
/* cx2388x has a 24-bit register space */
reg->val = cx_read(reg->reg & 0xfffffc);
@@ -1365,7 +1038,8 @@ static int vidioc_g_register (struct file *file, void *fh,
static int vidioc_s_register (struct file *file, void *fh,
const struct v4l2_dbg_register *reg)
{
- struct cx88_core *core = ((struct cx8800_fh*)fh)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
cx_write(reg->reg & 0xfffffc, reg->val);
return 0;
@@ -1379,7 +1053,8 @@ static int vidioc_s_register (struct file *file, void *fh,
static int radio_g_tuner (struct file *file, void *priv,
struct v4l2_tuner *t)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (unlikely(t->index > 0))
return -EINVAL;
@@ -1393,7 +1068,8 @@ static int radio_g_tuner (struct file *file, void *priv,
static int radio_s_tuner (struct file *file, void *priv,
const struct v4l2_tuner *t)
{
- struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+ struct cx8800_dev *dev = video_drvdata(file);
+ struct cx88_core *core = dev->core;
if (0 != t->index)
return -EINVAL;
@@ -1404,32 +1080,6 @@ static int radio_s_tuner (struct file *file, void *priv,
/* ----------------------------------------------------------- */
-static void cx8800_vid_timeout(unsigned long data)
-{
- struct cx8800_dev *dev = (struct cx8800_dev*)data;
- struct cx88_core *core = dev->core;
- struct cx88_dmaqueue *q = &dev->vidq;
- struct cx88_buffer *buf;
- unsigned long flags;
-
- cx88_sram_channel_dump(core, &cx88_sram_channels[SRAM_CH21]);
-
- cx_clear(MO_VID_DMACNTRL, 0x11);
- cx_clear(VID_CAPTURE_CONTROL, 0x06);
-
- spin_lock_irqsave(&dev->slock,flags);
- while (!list_empty(&q->active)) {
- buf = list_entry(q->active.next, struct cx88_buffer, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- printk("%s/0: [%p/%d] timeout - dma=0x%08lx\n", core->name,
- buf, buf->vb.i, (unsigned long)buf->risc.dma);
- }
- restart_video_queue(dev,q);
- spin_unlock_irqrestore(&dev->slock,flags);
-}
-
static const char *cx88_vid_irqs[32] = {
"y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
"y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
@@ -1476,22 +1126,6 @@ static void cx8800_vid_irq(struct cx8800_dev *dev)
cx88_wakeup(core, &dev->vbiq, count);
spin_unlock(&dev->slock);
}
-
- /* risc2 y */
- if (status & 0x10) {
- dprintk(2,"stopper video\n");
- spin_lock(&dev->slock);
- restart_video_queue(dev,&dev->vidq);
- spin_unlock(&dev->slock);
- }
-
- /* risc2 vbi */
- if (status & 0x80) {
- dprintk(2,"stopper vbi\n");
- spin_lock(&dev->slock);
- cx8800_restart_vbi_queue(dev,&dev->vbiq);
- spin_unlock(&dev->slock);
- }
}
static irqreturn_t cx8800_irq(int irq, void *dev_id)
@@ -1530,11 +1164,11 @@ static irqreturn_t cx8800_irq(int irq, void *dev_id)
static const struct v4l2_file_operations video_fops =
{
.owner = THIS_MODULE,
- .open = video_open,
- .release = video_release,
- .read = video_read,
- .poll = video_poll,
- .mmap = video_mmap,
+ .open = v4l2_fh_open,
+ .release = vb2_fop_release,
+ .read = vb2_fop_read,
+ .poll = vb2_fop_poll,
+ .mmap = vb2_fop_mmap,
.unlocked_ioctl = video_ioctl2,
};
@@ -1544,17 +1178,17 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1579,17 +1213,17 @@ static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
.vidioc_g_fmt_vbi_cap = cx8800_vbi_fmt,
.vidioc_try_fmt_vbi_cap = cx8800_vbi_fmt,
.vidioc_s_fmt_vbi_cap = cx8800_vbi_fmt,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
.vidioc_g_std = vidioc_g_std,
.vidioc_s_std = vidioc_s_std,
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1610,9 +1244,9 @@ static const struct video_device cx8800_vbi_template = {
static const struct v4l2_file_operations radio_fops =
{
.owner = THIS_MODULE,
- .open = video_open,
+ .open = radio_open,
.poll = v4l2_ctrl_poll,
- .release = video_release,
+ .release = v4l2_fh_release,
.unlocked_ioctl = video_ioctl2,
};
@@ -1676,6 +1310,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
{
struct cx8800_dev *dev;
struct cx88_core *core;
+ struct vb2_queue *q;
int err;
int i;
@@ -1713,25 +1348,12 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
/* initialize driver struct */
spin_lock_init(&dev->slock);
- core->tvnorm = V4L2_STD_NTSC_M;
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
- dev->vidq.timeout.function = cx8800_vid_timeout;
- dev->vidq.timeout.data = (unsigned long)dev;
- init_timer(&dev->vidq.timeout);
- cx88_risc_stopper(dev->pci,&dev->vidq.stopper,
- MO_VID_DMACNTRL,0x11,0x00);
/* init vbi dma queues */
INIT_LIST_HEAD(&dev->vbiq.active);
- INIT_LIST_HEAD(&dev->vbiq.queued);
- dev->vbiq.timeout.function = cx8800_vbi_timeout;
- dev->vbiq.timeout.data = (unsigned long)dev;
- init_timer(&dev->vbiq.timeout);
- cx88_risc_stopper(dev->pci,&dev->vbiq.stopper,
- MO_VID_DMACNTRL,0x88,0x00);
/* get irq */
err = request_irq(pci_dev->irq, cx8800_irq,
@@ -1820,9 +1442,10 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
/* Sets device info at pci_dev */
pci_set_drvdata(pci_dev, dev);
- dev->width = 320;
- dev->height = 240;
- dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+ dev->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+
+ /* Maintain a reference so cx88-blackbird can query the 8800 device. */
+ core->v4ldev = dev;
/* initial device configuration */
mutex_lock(&core->lock);
@@ -1831,11 +1454,44 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
v4l2_ctrl_handler_setup(&core->audio_hdl);
cx88_video_mux(core, 0);
+ q = &dev->vb2_vidq;
+ q->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx88_buffer);
+ q->ops = &cx8800_video_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &core->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_unreg;
+
+ q = &dev->vb2_vbiq;
+ q->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF | VB2_READ;
+ q->gfp_flags = GFP_DMA32;
+ q->min_buffers_needed = 2;
+ q->drv_priv = dev;
+ q->buf_struct_size = sizeof(struct cx88_buffer);
+ q->ops = &cx8800_vbi_qops;
+ q->mem_ops = &vb2_dma_sg_memops;
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &core->lock;
+
+ err = vb2_queue_init(q);
+ if (err < 0)
+ goto fail_unreg;
+
/* register v4l devices */
dev->video_dev = cx88_vdev_init(core,dev->pci,
&cx8800_video_template,"video");
video_set_drvdata(dev->video_dev, dev);
dev->video_dev->ctrl_handler = &core->video_hdl;
+ dev->video_dev->queue = &dev->vb2_vidq;
err = video_register_device(dev->video_dev,VFL_TYPE_GRABBER,
video_nr[core->nr]);
if (err < 0) {
@@ -1848,6 +1504,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
dev->vbi_dev = cx88_vdev_init(core,dev->pci,&cx8800_vbi_template,"vbi");
video_set_drvdata(dev->vbi_dev, dev);
+ dev->vbi_dev->queue = &dev->vb2_vbiq;
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[core->nr]);
if (err < 0) {
@@ -1875,7 +1532,7 @@ static int cx8800_initdev(struct pci_dev *pci_dev,
}
/* start tvaudio thread */
- if (core->board.tuner_type != TUNER_ABSENT) {
+ if (core->board.tuner_type != UNSET) {
core->kthread = kthread_run(cx88_audio_thread, core, "cx88 tvaudio");
if (IS_ERR(core->kthread)) {
err = PTR_ERR(core->kthread);
@@ -1892,6 +1549,7 @@ fail_unreg:
free_irq(pci_dev->irq, dev);
mutex_unlock(&core->lock);
fail_core:
+ core->v4ldev = NULL;
cx88_core_put(core,dev->pci);
fail_free:
kfree(dev);
@@ -1913,15 +1571,16 @@ static void cx8800_finidev(struct pci_dev *pci_dev)
cx88_ir_stop(core);
cx88_shutdown(core); /* FIXME */
- pci_disable_device(pci_dev);
/* unregister stuff */
free_irq(pci_dev->irq, dev);
cx8800_unregister_video(dev);
+ pci_disable_device(pci_dev);
+
+ core->v4ldev = NULL;
/* free memory */
- btcx_riscmem_free(dev->pci,&dev->vidq.stopper);
cx88_core_put(core,dev->pci);
kfree(dev);
}
@@ -1938,12 +1597,10 @@ static int cx8800_suspend(struct pci_dev *pci_dev, pm_message_t state)
if (!list_empty(&dev->vidq.active)) {
printk("%s/0: suspend video\n", core->name);
stop_video_dma(dev);
- del_timer(&dev->vidq.timeout);
}
if (!list_empty(&dev->vbiq.active)) {
printk("%s/0: suspend vbi\n", core->name);
cx8800_stop_vbi_dma(dev);
- del_timer(&dev->vbiq.timeout);
}
spin_unlock_irqrestore(&dev->slock, flags);
diff --git a/drivers/media/pci/cx88/cx88.h b/drivers/media/pci/cx88/cx88.h
index 28893a6..3b0ae75 100644
--- a/drivers/media/pci/cx88/cx88.h
+++ b/drivers/media/pci/cx88/cx88.h
@@ -29,19 +29,18 @@
#include <media/v4l2-fh.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf2-dma-sg.h>
#include <media/cx2341x.h>
-#include <media/videobuf-dvb.h>
+#include <media/videobuf2-dvb.h>
#include <media/ir-kbd-i2c.h>
#include <media/wm8775.h>
-#include "btcx-risc.h"
#include "cx88-reg.h"
#include "tuner-xc2028.h"
#include <linux/mutex.h>
-#define CX88_VERSION "0.0.9"
+#define CX88_VERSION "1.0.0"
#define UNSET (-1U)
@@ -62,7 +61,8 @@
#define FORMAT_FLAGS_PACKED 0x01
#define FORMAT_FLAGS_PLANAR 0x02
-#define VBI_LINE_COUNT 17
+#define VBI_LINE_PAL_COUNT 18
+#define VBI_LINE_NTSC_COUNT 12
#define VBI_LINE_LENGTH 2048
#define AUD_RDS_LINES 4
@@ -95,13 +95,13 @@ enum cx8802_board_access {
static inline unsigned int norm_maxw(v4l2_std_id norm)
{
- return (norm & (V4L2_STD_MN & ~V4L2_STD_PAL_Nc)) ? 720 : 768;
+ return 720;
}
static inline unsigned int norm_maxh(v4l2_std_id norm)
{
- return (norm & V4L2_STD_625_50) ? 576 : 480;
+ return (norm & V4L2_STD_525_60) ? 480 : 576;
}
/* ----------------------------------------------------------- */
@@ -311,26 +311,33 @@ enum cx88_tvaudio {
#define BUFFER_TIMEOUT msecs_to_jiffies(2000)
+struct cx88_riscmem {
+ unsigned int size;
+ __le32 *cpu;
+ __le32 *jmp;
+ dma_addr_t dma;
+};
+
/* buffer for one video frame */
struct cx88_buffer {
/* common v4l buffer stuff -- must be first */
- struct videobuf_buffer vb;
+ struct vb2_buffer vb;
+ struct list_head list;
/* cx88 specific */
unsigned int bpl;
- struct btcx_riscmem risc;
- const struct cx8800_fmt *fmt;
+ struct cx88_riscmem risc;
u32 count;
};
struct cx88_dmaqueue {
struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
- struct btcx_riscmem stopper;
u32 count;
};
+struct cx8800_dev;
+struct cx8802_dev;
+
struct cx88_core {
struct list_head devlist;
atomic_t refcount;
@@ -376,6 +383,8 @@ struct cx88_core {
/* state info */
struct task_struct *kthread;
v4l2_std_id tvnorm;
+ unsigned width, height;
+ unsigned field;
enum cx88_tvaudio tvaudio;
u32 audiomode_manual;
u32 audiomode_current;
@@ -395,11 +404,14 @@ struct cx88_core {
struct mutex lock;
/* various v4l controls */
u32 freq;
- int users;
- int mpeg_users;
- /* cx88-video needs to access cx8802 for hybrid tuner pll access. */
+ /*
+ * cx88-video needs to access cx8802 for hybrid tuner pll access and
+ * for vb2_is_busy() checks.
+ */
struct cx8802_dev *dvbdev;
+ /* cx88-blackbird needs to access cx8800 for vb2_is_busy() checks */
+ struct cx8800_dev *v4ldev;
enum cx88_board_type active_type_id;
int active_ref;
int active_fe_id;
@@ -453,24 +465,9 @@ static inline struct cx88_core *to_core(struct v4l2_device *v4l2_dev)
val; \
})
-struct cx8800_dev;
-struct cx8802_dev;
-
/* ----------------------------------------------------------- */
/* function 0: video stuff */
-struct cx8800_fh {
- struct v4l2_fh fh;
- struct cx8800_dev *dev;
- unsigned int resources;
-
- /* video capture */
- struct videobuf_queue vidq;
-
- /* vbi capture */
- struct videobuf_queue vbiq;
-};
-
struct cx8800_suspend_state {
int disabled;
};
@@ -490,11 +487,12 @@ struct cx8800_dev {
unsigned char pci_rev,pci_lat;
const struct cx8800_fmt *fmt;
- unsigned int width, height;
/* capture queues */
struct cx88_dmaqueue vidq;
+ struct vb2_queue vb2_vidq;
struct cx88_dmaqueue vbiq;
+ struct vb2_queue vb2_vbiq;
/* various v4l controls */
@@ -510,12 +508,6 @@ struct cx8800_dev {
/* ----------------------------------------------------------- */
/* function 2: mpeg stuff */
-struct cx8802_fh {
- struct v4l2_fh fh;
- struct cx8802_dev *dev;
- struct videobuf_queue mpegq;
-};
-
struct cx8802_suspend_state {
int disabled;
};
@@ -559,6 +551,7 @@ struct cx8802_dev {
/* dma queues */
struct cx88_dmaqueue mpegq;
+ struct vb2_queue vb2_mpegq;
u32 ts_packet_size;
u32 ts_packet_count;
@@ -570,9 +563,6 @@ struct cx8802_dev {
#if IS_ENABLED(CONFIG_VIDEO_CX88_BLACKBIRD)
struct video_device *mpeg_dev;
u32 mailbox;
- int width;
- int height;
- unsigned char mpeg_active; /* nonzero if mpeg encoder is active */
/* mpeg params */
struct cx2341x_handler cxhdl;
@@ -580,7 +570,7 @@ struct cx8802_dev {
#if IS_ENABLED(CONFIG_VIDEO_CX88_DVB)
/* for dvb only */
- struct videobuf_dvb_frontends frontends;
+ struct vb2_dvb_frontends frontends;
#endif
#if IS_ENABLED(CONFIG_VIDEO_CX88_VP3054)
@@ -634,22 +624,17 @@ extern void cx88_shutdown(struct cx88_core *core);
extern int cx88_reset(struct cx88_core *core);
extern int
-cx88_risc_buffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+cx88_risc_buffer(struct pci_dev *pci, struct cx88_riscmem *risc,
struct scatterlist *sglist,
unsigned int top_offset, unsigned int bottom_offset,
unsigned int bpl, unsigned int padding, unsigned int lines);
extern int
-cx88_risc_databuffer(struct pci_dev *pci, struct btcx_riscmem *risc,
+cx88_risc_databuffer(struct pci_dev *pci, struct cx88_riscmem *risc,
struct scatterlist *sglist, unsigned int bpl,
unsigned int lines, unsigned int lpi);
-extern int
-cx88_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
- u32 reg, u32 mask, u32 value);
-extern void
-cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
extern void cx88_risc_disasm(struct cx88_core *core,
- struct btcx_riscmem *risc);
+ struct cx88_riscmem *risc);
extern int cx88_sram_channel_setup(struct cx88_core *core,
const struct sram_channel *ch,
unsigned int bpl, u32 risc);
@@ -664,7 +649,7 @@ extern struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
const struct video_device *template_,
const char *type);
-extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
+extern struct cx88_core *cx88_core_get(struct pci_dev *pci);
extern void cx88_core_put(struct cx88_core *core,
struct pci_dev *pci);
@@ -684,12 +669,10 @@ int cx8800_start_vbi_dma(struct cx8800_dev *dev,
struct cx88_dmaqueue *q,
struct cx88_buffer *buf);
*/
-int cx8800_stop_vbi_dma(struct cx8800_dev *dev);
-int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
- struct cx88_dmaqueue *q);
-void cx8800_vbi_timeout(unsigned long data);
+void cx8800_stop_vbi_dma(struct cx8800_dev *dev);
+int cx8800_restart_vbi_queue(struct cx8800_dev *dev, struct cx88_dmaqueue *q);
-extern const struct videobuf_queue_ops cx8800_vbi_qops;
+extern const struct vb2_ops cx8800_vbi_qops;
/* ----------------------------------------------------------- */
/* cx88-i2c.c */
@@ -739,14 +722,17 @@ extern void cx88_i2c_init_ir(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
-int cx8802_buf_prepare(struct videobuf_queue *q,struct cx8802_dev *dev,
- struct cx88_buffer *buf, enum v4l2_field field);
+int cx8802_buf_prepare(struct vb2_queue *q, struct cx8802_dev *dev,
+ struct cx88_buffer *buf);
void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf);
void cx8802_cancel_buffers(struct cx8802_dev *dev);
+int cx8802_start_dma(struct cx8802_dev *dev,
+ struct cx88_dmaqueue *q,
+ struct cx88_buffer *buf);
/* ----------------------------------------------------------- */
/* cx88-video.c*/
-int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
+int cx88_enum_input(struct cx88_core *core, struct v4l2_input *i);
int cx88_set_freq(struct cx88_core *core, const struct v4l2_frequency *f);
int cx88_video_mux(struct cx88_core *core, unsigned int input);
void cx88_querycap(struct file *file, struct cx88_core *core,
diff --git a/drivers/media/pci/ddbridge/ddbridge-core.c b/drivers/media/pci/ddbridge/ddbridge-core.c
index c82e855..9e3492e 100644
--- a/drivers/media/pci/ddbridge/ddbridge-core.c
+++ b/drivers/media/pci/ddbridge/ddbridge-core.c
@@ -1118,8 +1118,7 @@ static void ddb_ports_detach(struct ddb *dev)
dvb_input_detach(port->input[1]);
break;
case DDB_PORT_CI:
- if (port->output->dev)
- dvb_unregister_device(port->output->dev);
+ dvb_unregister_device(port->output->dev);
if (port->en) {
ddb_input_stop(port->input[0]);
ddb_output_stop(port->output);
diff --git a/drivers/media/pci/ivtv/ivtv-controls.c b/drivers/media/pci/ivtv/ivtv-controls.c
index 2b0ab26..ccf548c 100644
--- a/drivers/media/pci/ivtv/ivtv-controls.c
+++ b/drivers/media/pci/ivtv/ivtv-controls.c
@@ -69,7 +69,7 @@ static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
/* fix videodecoder resolution */
fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
fmt.height = cxhdl->height;
- fmt.code = V4L2_MBUS_FMT_FIXED;
+ fmt.code = MEDIA_BUS_FMT_FIXED;
v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt);
return 0;
}
diff --git a/drivers/media/pci/ivtv/ivtv-ioctl.c b/drivers/media/pci/ivtv/ivtv-ioctl.c
index 3e0cb77..4d8ee18 100644
--- a/drivers/media/pci/ivtv/ivtv-ioctl.c
+++ b/drivers/media/pci/ivtv/ivtv-ioctl.c
@@ -595,7 +595,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
fmt->fmt.pix.width /= 2;
mbus_fmt.width = fmt->fmt.pix.width;
mbus_fmt.height = h;
- mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ mbus_fmt.code = MEDIA_BUS_FMT_FIXED;
v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt);
return ivtv_g_fmt_vid_cap(file, fh, fmt);
}
diff --git a/drivers/media/pci/ivtv/ivtv-udma.c b/drivers/media/pci/ivtv/ivtv-udma.c
index 7338cb2..bee2329 100644
--- a/drivers/media/pci/ivtv/ivtv-udma.c
+++ b/drivers/media/pci/ivtv/ivtv-udma.c
@@ -76,7 +76,7 @@ void ivtv_udma_fill_sg_array (struct ivtv_user_dma *dma, u32 buffer_offset, u32
int i;
struct scatterlist *sg;
- for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg++) {
+ for (i = 0, sg = dma->SGlist; i < dma->SG_length; i++, sg = sg_next(sg)) {
dma->SGarray[i].size = cpu_to_le32(sg_dma_len(sg));
dma->SGarray[i].src = cpu_to_le32(sg_dma_address(sg));
dma->SGarray[i].dst = cpu_to_le32(buffer_offset);
diff --git a/drivers/media/pci/meye/meye.c b/drivers/media/pci/meye/meye.c
index aeae547..9d9f90c 100644
--- a/drivers/media/pci/meye/meye.c
+++ b/drivers/media/pci/meye/meye.c
@@ -1031,9 +1031,6 @@ static int vidioc_querycap(struct file *file, void *fh,
strcpy(cap->card, "meye");
sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
- cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
- MEYE_DRIVER_MINORVERSION;
-
cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
diff --git a/drivers/media/pci/pt1/pt1.c b/drivers/media/pci/pt1/pt1.c
index db887b0..acc35b4 100644
--- a/drivers/media/pci/pt1/pt1.c
+++ b/drivers/media/pci/pt1/pt1.c
@@ -109,9 +109,6 @@ struct pt1_adapter {
int sleep;
};
-#define pt1_printk(level, pt1, format, arg...) \
- dev_printk(level, &(pt1)->pdev->dev, format, ##arg)
-
static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
{
writel(data, pt1->regs + reg * 4);
@@ -154,7 +151,7 @@ static int pt1_sync(struct pt1 *pt1)
return 0;
pt1_write_reg(pt1, 0, 0x00000008);
}
- pt1_printk(KERN_ERR, pt1, "could not sync\n");
+ dev_err(&pt1->pdev->dev, "could not sync\n");
return -EIO;
}
@@ -179,7 +176,7 @@ static int pt1_unlock(struct pt1 *pt1)
return 0;
schedule_timeout_uninterruptible((HZ + 999) / 1000);
}
- pt1_printk(KERN_ERR, pt1, "could not unlock\n");
+ dev_err(&pt1->pdev->dev, "could not unlock\n");
return -EIO;
}
@@ -193,7 +190,7 @@ static int pt1_reset_pci(struct pt1 *pt1)
return 0;
schedule_timeout_uninterruptible((HZ + 999) / 1000);
}
- pt1_printk(KERN_ERR, pt1, "could not reset PCI\n");
+ dev_err(&pt1->pdev->dev, "could not reset PCI\n");
return -EIO;
}
@@ -207,7 +204,7 @@ static int pt1_reset_ram(struct pt1 *pt1)
return 0;
schedule_timeout_uninterruptible((HZ + 999) / 1000);
}
- pt1_printk(KERN_ERR, pt1, "could not reset RAM\n");
+ dev_err(&pt1->pdev->dev, "could not reset RAM\n");
return -EIO;
}
@@ -224,7 +221,7 @@ static int pt1_do_enable_ram(struct pt1 *pt1)
}
schedule_timeout_uninterruptible((HZ + 999) / 1000);
}
- pt1_printk(KERN_ERR, pt1, "could not enable RAM\n");
+ dev_err(&pt1->pdev->dev, "could not enable RAM\n");
return -EIO;
}
diff --git a/drivers/media/pci/pt3/pt3.c b/drivers/media/pci/pt3/pt3.c
index 1fdeac1..7a37e8f 100644
--- a/drivers/media/pci/pt3/pt3.c
+++ b/drivers/media/pci/pt3/pt3.c
@@ -255,7 +255,7 @@ static int pt3_fe_init(struct pt3_board *pt3)
pt3_i2c_reset(pt3);
ret = pt3_init_all_demods(pt3);
if (ret < 0) {
- dev_warn(&pt3->pdev->dev, "Failed to init demod chips.");
+ dev_warn(&pt3->pdev->dev, "Failed to init demod chips\n");
return ret;
}
@@ -271,7 +271,7 @@ static int pt3_fe_init(struct pt3_board *pt3)
init0_ter, ARRAY_SIZE(init0_ter));
if (ret < 0) {
dev_warn(&pt3->pdev->dev,
- "demod[%d] faild in init sequence0.", i);
+ "demod[%d] failed in init sequence0\n", i);
return ret;
}
ret = fe->ops.init(fe);
@@ -282,7 +282,7 @@ static int pt3_fe_init(struct pt3_board *pt3)
usleep_range(2000, 4000);
ret = pt3_set_tuner_power(pt3, true, false);
if (ret < 0) {
- dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+ dev_warn(&pt3->pdev->dev, "Failed to control tuner module\n");
return ret;
}
@@ -297,7 +297,7 @@ static int pt3_fe_init(struct pt3_board *pt3)
cfg_ter, ARRAY_SIZE(cfg_ter));
if (ret < 0) {
dev_warn(&pt3->pdev->dev,
- "demod[%d] faild in init sequence1.", i);
+ "demod[%d] failed in init sequence1\n", i);
return ret;
}
}
@@ -311,19 +311,19 @@ static int pt3_fe_init(struct pt3_board *pt3)
ret = fe->ops.tuner_ops.init(fe);
if (ret < 0) {
dev_warn(&pt3->pdev->dev,
- "Failed to init SAT-tuner[%d].", i);
+ "Failed to init SAT-tuner[%d]\n", i);
return ret;
}
}
ret = pt3_init_all_mxl301rf(pt3);
if (ret < 0) {
- dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners.");
+ dev_warn(&pt3->pdev->dev, "Failed to init TERR-tuners\n");
return ret;
}
ret = pt3_set_tuner_power(pt3, true, true);
if (ret < 0) {
- dev_warn(&pt3->pdev->dev, "Failed to control tuner module.");
+ dev_warn(&pt3->pdev->dev, "Failed to control tuner module\n");
return ret;
}
@@ -344,7 +344,7 @@ static int pt3_fe_init(struct pt3_board *pt3)
}
if (ret < 0) {
dev_warn(&pt3->pdev->dev,
- "Failed in initial tuning of tuner[%d].", i);
+ "Failed in initial tuning of tuner[%d]\n", i);
return ret;
}
}
@@ -366,7 +366,7 @@ static int pt3_fe_init(struct pt3_board *pt3)
fe->ops.set_lna = &pt3_set_lna;
}
if (i < PT3_NUM_FE) {
- dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby.", i);
+ dev_warn(&pt3->pdev->dev, "FE[%d] failed to standby\n", i);
return ret;
}
return 0;
@@ -453,8 +453,8 @@ static int pt3_fetch_thread(void *data)
pt3_init_dmabuf(adap);
adap->num_discard = PT3_INITIAL_BUF_DROPS;
- dev_dbg(adap->dvb_adap.device,
- "PT3: [%s] started.\n", adap->thread->comm);
+ dev_dbg(adap->dvb_adap.device, "PT3: [%s] started\n",
+ adap->thread->comm);
set_freezable();
while (!kthread_freezable_should_stop(&was_frozen)) {
if (was_frozen)
@@ -468,8 +468,8 @@ static int pt3_fetch_thread(void *data)
PT3_FETCH_DELAY_DELTA * NSEC_PER_MSEC,
HRTIMER_MODE_REL);
}
- dev_dbg(adap->dvb_adap.device,
- "PT3: [%s] exited.\n", adap->thread->comm);
+ dev_dbg(adap->dvb_adap.device, "PT3: [%s] exited\n",
+ adap->thread->comm);
adap->thread = NULL;
return 0;
}
@@ -485,8 +485,8 @@ static int pt3_start_streaming(struct pt3_adapter *adap)
int ret = PTR_ERR(thread);
dev_warn(adap->dvb_adap.device,
- "PT3 (adap:%d, dmx:%d): failed to start kthread.\n",
- adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+ "PT3 (adap:%d, dmx:%d): failed to start kthread\n",
+ adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
return ret;
}
adap->thread = thread;
@@ -501,8 +501,8 @@ static int pt3_stop_streaming(struct pt3_adapter *adap)
ret = pt3_stop_dma(adap);
if (ret)
dev_warn(adap->dvb_adap.device,
- "PT3: failed to stop streaming of adap:%d/FE:%d\n",
- adap->dvb_adap.num, adap->fe->id);
+ "PT3: failed to stop streaming of adap:%d/FE:%d\n",
+ adap->dvb_adap.num, adap->fe->id);
/* kill the fetching thread */
ret = kthread_stop(adap->thread);
@@ -522,8 +522,8 @@ static int pt3_start_feed(struct dvb_demux_feed *feed)
return 0;
if (adap->num_feeds != 1) {
dev_warn(adap->dvb_adap.device,
- "%s: unmatched start/stop_feed in adap:%i/dmx:%i.\n",
- __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
+ "%s: unmatched start/stop_feed in adap:%i/dmx:%i\n",
+ __func__, adap->dvb_adap.num, adap->dmxdev.dvbdev->id);
adap->num_feeds = 1;
}
@@ -553,10 +553,9 @@ static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
struct dvb_adapter *da;
adap = kzalloc(sizeof(*adap), GFP_KERNEL);
- if (!adap) {
- dev_err(&pt3->pdev->dev, "failed to alloc mem for adapter.\n");
+ if (!adap)
return -ENOMEM;
- }
+
pt3->adaps[index] = adap;
adap->adap_idx = index;
@@ -565,7 +564,7 @@ static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
THIS_MODULE, &pt3->pdev->dev, adapter_nr);
if (ret < 0) {
dev_err(&pt3->pdev->dev,
- "failed to register adapter dev.\n");
+ "failed to register adapter dev\n");
goto err_mem;
}
da = &adap->dvb_adap;
@@ -581,7 +580,7 @@ static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
adap->demux.stop_feed = pt3_stop_feed;
ret = dvb_dmx_init(&adap->demux);
if (ret < 0) {
- dev_err(&pt3->pdev->dev, "failed to init dmx dev.\n");
+ dev_err(&pt3->pdev->dev, "failed to init dmx dev\n");
goto err_adap;
}
@@ -589,13 +588,13 @@ static int pt3_alloc_adapter(struct pt3_board *pt3, int index)
adap->dmxdev.demux = &adap->demux.dmx;
ret = dvb_dmxdev_init(&adap->dmxdev, da);
if (ret < 0) {
- dev_err(&pt3->pdev->dev, "failed to init dmxdev.\n");
+ dev_err(&pt3->pdev->dev, "failed to init dmxdev\n");
goto err_demux;
}
ret = pt3_alloc_dmabuf(adap);
if (ret) {
- dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers.\n");
+ dev_err(&pt3->pdev->dev, "failed to alloc DMA buffers\n");
goto err_dmabuf;
}
@@ -695,7 +694,7 @@ static int pt3_resume(struct device *dev)
dvb_frontend_resume(adap->fe);
ret = pt3_alloc_dmabuf(adap);
if (ret) {
- dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs.\n");
+ dev_err(&pt3->pdev->dev, "failed to alloc DMA bufs\n");
continue;
}
if (adap->num_feeds > 0)
@@ -753,15 +752,14 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (ret == 0)
dma_set_coherent_mask(&pdev->dev, DMA_BIT_MASK(32));
else {
- dev_err(&pdev->dev, "Failed to set DMA mask.\n");
+ dev_err(&pdev->dev, "Failed to set DMA mask\n");
goto err_release_regions;
}
- dev_info(&pdev->dev, "Use 32bit DMA.\n");
+ dev_info(&pdev->dev, "Use 32bit DMA\n");
}
pt3 = kzalloc(sizeof(*pt3), GFP_KERNEL);
if (!pt3) {
- dev_err(&pdev->dev, "Failed to alloc mem for this dev.\n");
ret = -ENOMEM;
goto err_release_regions;
}
@@ -771,15 +769,15 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pt3->regs[0] = pci_ioremap_bar(pdev, 0);
pt3->regs[1] = pci_ioremap_bar(pdev, 2);
if (pt3->regs[0] == NULL || pt3->regs[1] == NULL) {
- dev_err(&pdev->dev, "Failed to ioremap.\n");
+ dev_err(&pdev->dev, "Failed to ioremap\n");
ret = -ENOMEM;
goto err_kfree;
}
ver = ioread32(pt3->regs[0] + REG_VERSION);
if ((ver >> 16) != 0x0301) {
- dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported",
- ver >> 24, (ver & 0x00ff0000) >> 16);
+ dev_warn(&pdev->dev, "PT%d, I/F-ver.:%d not supported\n",
+ ver >> 24, (ver & 0x00ff0000) >> 16);
ret = -ENODEV;
goto err_iounmap;
}
@@ -788,7 +786,6 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pt3->i2c_buf = kmalloc(sizeof(*pt3->i2c_buf), GFP_KERNEL);
if (pt3->i2c_buf == NULL) {
- dev_err(&pdev->dev, "Failed to alloc mem for i2c.\n");
ret = -ENOMEM;
goto err_iounmap;
}
@@ -801,7 +798,7 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
i2c_set_adapdata(i2c, pt3);
ret = i2c_add_adapter(i2c);
if (ret < 0) {
- dev_err(&pdev->dev, "Failed to add i2c adapter.\n");
+ dev_err(&pdev->dev, "Failed to add i2c adapter\n");
goto err_i2cbuf;
}
@@ -815,20 +812,20 @@ static int pt3_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
break;
}
if (i < PT3_NUM_FE) {
- dev_err(&pdev->dev, "Failed to create FE%d.\n", i);
+ dev_err(&pdev->dev, "Failed to create FE%d\n", i);
goto err_cleanup_adapters;
}
ret = pt3_fe_init(pt3);
if (ret < 0) {
- dev_err(&pdev->dev, "Failed to init frontends.\n");
+ dev_err(&pdev->dev, "Failed to init frontends\n");
i = PT3_NUM_FE - 1;
goto err_cleanup_adapters;
}
dev_info(&pdev->dev,
- "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x).\n",
- ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff);
+ "successfully init'ed PT%d (fw:0x%02x, I/F:0x%02x)\n",
+ ver >> 24, (ver >> 8) & 0xff, (ver >> 16) & 0xff);
return 0;
err_cleanup_adapters:
diff --git a/drivers/media/pci/saa7134/saa7134-alsa.c b/drivers/media/pci/saa7134/saa7134-alsa.c
index 4056989..ac3cd74 100644
--- a/drivers/media/pci/saa7134/saa7134-alsa.c
+++ b/drivers/media/pci/saa7134/saa7134-alsa.c
@@ -173,9 +173,7 @@ static void saa7134_irq_alsa_done(struct saa7134_dev *dev,
dprintk("irq: overrun [full=%d/%d] - Blocks in %d\n",dev->dmasound.read_count,
dev->dmasound.bufsize, dev->dmasound.blocks);
spin_unlock(&dev->slock);
- snd_pcm_stream_lock(dev->dmasound.substream);
- snd_pcm_stop(dev->dmasound.substream,SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(dev->dmasound.substream);
+ snd_pcm_stop_xrun(dev->dmasound.substream);
return;
}
diff --git a/drivers/media/pci/saa7134/saa7134-core.c b/drivers/media/pci/saa7134/saa7134-core.c
index 236ed72..a349e96 100644
--- a/drivers/media/pci/saa7134/saa7134-core.c
+++ b/drivers/media/pci/saa7134/saa7134-core.c
@@ -1001,13 +1001,18 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
saa7134_board_init1(dev);
saa7134_hwinit1(dev);
+ dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
+ if (IS_ERR(dev->alloc_ctx)) {
+ err = PTR_ERR(dev->alloc_ctx);
+ goto fail3;
+ }
/* get irq */
err = request_irq(pci_dev->irq, saa7134_irq,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
dev->name,pci_dev->irq);
- goto fail3;
+ goto fail4;
}
/* wait a bit, register i2c bus */
@@ -1065,7 +1070,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
if (err < 0) {
printk(KERN_INFO "%s: can't register video device\n",
dev->name);
- goto fail4;
+ goto fail5;
}
printk(KERN_INFO "%s: registered device %s [v4l2]\n",
dev->name, video_device_node_name(dev->video_dev));
@@ -1078,7 +1083,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = video_register_device(dev->vbi_dev,VFL_TYPE_VBI,
vbi_nr[dev->nr]);
if (err < 0)
- goto fail4;
+ goto fail5;
printk(KERN_INFO "%s: registered device %s\n",
dev->name, video_device_node_name(dev->vbi_dev));
@@ -1089,7 +1094,7 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
err = video_register_device(dev->radio_dev,VFL_TYPE_RADIO,
radio_nr[dev->nr]);
if (err < 0)
- goto fail4;
+ goto fail5;
printk(KERN_INFO "%s: registered device %s\n",
dev->name, video_device_node_name(dev->radio_dev));
}
@@ -1103,10 +1108,12 @@ static int saa7134_initdev(struct pci_dev *pci_dev,
request_submodules(dev);
return 0;
- fail4:
+ fail5:
saa7134_unregister_video(dev);
saa7134_i2c_unregister(dev);
free_irq(pci_dev->irq, dev);
+ fail4:
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
fail3:
saa7134_hwfini(dev);
iounmap(dev->lmmio);
@@ -1173,6 +1180,7 @@ static void saa7134_finidev(struct pci_dev *pci_dev)
/* release resources */
free_irq(pci_dev->irq, dev);
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
iounmap(dev->lmmio);
release_mem_region(pci_resource_start(pci_dev,0),
pci_resource_len(pci_dev,0));
diff --git a/drivers/media/pci/saa7134/saa7134-empress.c b/drivers/media/pci/saa7134/saa7134-empress.c
index e4ea85f..594dc3a 100644
--- a/drivers/media/pci/saa7134/saa7134-empress.c
+++ b/drivers/media/pci/saa7134/saa7134-empress.c
@@ -96,7 +96,6 @@ static struct vb2_ops saa7134_empress_qops = {
.queue_setup = saa7134_ts_queue_setup,
.buf_init = saa7134_ts_buffer_init,
.buf_prepare = saa7134_ts_buffer_prepare,
- .buf_finish = saa7134_ts_buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
@@ -140,7 +139,7 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
@@ -157,7 +156,7 @@ static int empress_try_fmt_vid_cap(struct file *file, void *priv,
struct saa7134_dev *dev = video_drvdata(file);
struct v4l2_mbus_framefmt mbus_fmt;
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
saa_call_all(dev, video, try_mbus_fmt, &mbus_fmt);
v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
diff --git a/drivers/media/pci/saa7134/saa7134-ts.c b/drivers/media/pci/saa7134/saa7134-ts.c
index bd25323..2709b83 100644
--- a/drivers/media/pci/saa7134/saa7134-ts.c
+++ b/drivers/media/pci/saa7134/saa7134-ts.c
@@ -94,7 +94,6 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(vb2, 0);
unsigned int lines, llength, size;
- int ret;
dprintk("buffer_prepare [%p]\n", buf);
@@ -108,25 +107,11 @@ int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2)
vb2_set_plane_payload(vb2, 0, size);
vb2->v4l2_buf.field = dev->field;
- ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
- if (!ret)
- return -EIO;
return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
saa7134_buffer_startpage(buf));
}
EXPORT_SYMBOL_GPL(saa7134_ts_buffer_prepare);
-void saa7134_ts_buffer_finish(struct vb2_buffer *vb2)
-{
- struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
- struct saa7134_dev *dev = dmaq->dev;
- struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
- struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
-
- dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
-}
-EXPORT_SYMBOL_GPL(saa7134_ts_buffer_finish);
-
int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
@@ -142,6 +127,7 @@ int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
*nbuffers = 3;
*nplanes = 1;
sizes[0] = size;
+ alloc_ctxs[0] = dev->alloc_ctx;
return 0;
}
EXPORT_SYMBOL_GPL(saa7134_ts_queue_setup);
@@ -187,7 +173,6 @@ struct vb2_ops saa7134_ts_qops = {
.queue_setup = saa7134_ts_queue_setup,
.buf_init = saa7134_ts_buffer_init,
.buf_prepare = saa7134_ts_buffer_prepare,
- .buf_finish = saa7134_ts_buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
diff --git a/drivers/media/pci/saa7134/saa7134-vbi.c b/drivers/media/pci/saa7134/saa7134-vbi.c
index 4f0b101..5306e54 100644
--- a/drivers/media/pci/saa7134/saa7134-vbi.c
+++ b/drivers/media/pci/saa7134/saa7134-vbi.c
@@ -120,7 +120,6 @@ static int buffer_prepare(struct vb2_buffer *vb2)
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
unsigned int size;
- int ret;
if (dma->sgl->offset) {
pr_err("The buffer is not page-aligned\n");
@@ -132,9 +131,6 @@ static int buffer_prepare(struct vb2_buffer *vb2)
vb2_set_plane_payload(vb2, 0, size);
- ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
- if (!ret)
- return -EIO;
return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
saa7134_buffer_startpage(buf));
}
@@ -156,6 +152,7 @@ static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
*nbuffers = saa7134_buffer_count(size, *nbuffers);
*nplanes = 1;
sizes[0] = size;
+ alloc_ctxs[0] = dev->alloc_ctx;
return 0;
}
@@ -169,21 +166,10 @@ static int buffer_init(struct vb2_buffer *vb2)
return 0;
}
-static void buffer_finish(struct vb2_buffer *vb2)
-{
- struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
- struct saa7134_dev *dev = dmaq->dev;
- struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
- struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
-
- dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
-}
-
struct vb2_ops saa7134_vbi_qops = {
.queue_setup = queue_setup,
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
- .buf_finish = buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
diff --git a/drivers/media/pci/saa7134/saa7134-video.c b/drivers/media/pci/saa7134/saa7134-video.c
index fc4a427..701b52f 100644
--- a/drivers/media/pci/saa7134/saa7134-video.c
+++ b/drivers/media/pci/saa7134/saa7134-video.c
@@ -883,7 +883,6 @@ static int buffer_prepare(struct vb2_buffer *vb2)
struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
unsigned int size;
- int ret;
if (dma->sgl->offset) {
pr_err("The buffer is not page-aligned\n");
@@ -896,23 +895,10 @@ static int buffer_prepare(struct vb2_buffer *vb2)
vb2_set_plane_payload(vb2, 0, size);
vb2->v4l2_buf.field = dev->field;
- ret = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
- if (!ret)
- return -EIO;
return saa7134_pgtable_build(dev->pci, &dmaq->pt, dma->sgl, dma->nents,
saa7134_buffer_startpage(buf));
}
-static void buffer_finish(struct vb2_buffer *vb2)
-{
- struct saa7134_dmaqueue *dmaq = vb2->vb2_queue->drv_priv;
- struct saa7134_dev *dev = dmaq->dev;
- struct saa7134_buf *buf = container_of(vb2, struct saa7134_buf, vb2);
- struct sg_table *dma = vb2_dma_sg_plane_desc(&buf->vb2, 0);
-
- dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
-}
-
static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
@@ -932,6 +918,7 @@ static int queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
*nbuffers = saa7134_buffer_count(size, *nbuffers);
*nplanes = 1;
sizes[0] = size;
+ alloc_ctxs[0] = dev->alloc_ctx;
return 0;
}
@@ -1004,7 +991,6 @@ static struct vb2_ops vb2_qops = {
.queue_setup = queue_setup,
.buf_init = buffer_init,
.buf_prepare = buffer_prepare,
- .buf_finish = buffer_finish,
.buf_queue = saa7134_vb2_buffer_queue,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
diff --git a/drivers/media/pci/saa7134/saa7134.h b/drivers/media/pci/saa7134/saa7134.h
index 1a82dd0..8bf0553 100644
--- a/drivers/media/pci/saa7134/saa7134.h
+++ b/drivers/media/pci/saa7134/saa7134.h
@@ -588,6 +588,7 @@ struct saa7134_dev {
/* video+ts+vbi capture */
+ void *alloc_ctx;
struct saa7134_dmaqueue video_q;
struct vb2_queue video_vbq;
struct saa7134_dmaqueue vbi_q;
@@ -814,7 +815,6 @@ void saa7134_video_fini(struct saa7134_dev *dev);
int saa7134_ts_buffer_init(struct vb2_buffer *vb2);
int saa7134_ts_buffer_prepare(struct vb2_buffer *vb2);
-void saa7134_ts_buffer_finish(struct vb2_buffer *vb2);
int saa7134_ts_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[]);
diff --git a/drivers/media/pci/saa7164/saa7164-buffer.c b/drivers/media/pci/saa7164/saa7164-buffer.c
index 66696fa..9bd1f73 100644
--- a/drivers/media/pci/saa7164/saa7164-buffer.c
+++ b/drivers/media/pci/saa7164/saa7164-buffer.c
@@ -130,9 +130,9 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
goto fail2;
/* init the buffers to a known pattern, easier during debugging */
- memset_io(buf->cpu, 0xff, buf->pci_size);
+ memset(buf->cpu, 0xff, buf->pci_size);
buf->crc = crc32(0, buf->cpu, buf->actual_size);
- memset_io(buf->pt_cpu, 0xff, buf->pt_size);
+ memset(buf->pt_cpu, 0xff, buf->pt_size);
dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p (%d pageptrs)\n",
__func__, buf, params->numpagetables);
diff --git a/drivers/media/pci/saa7164/saa7164-bus.c b/drivers/media/pci/saa7164/saa7164-bus.c
index 5f6f309..6c73f5b 100644
--- a/drivers/media/pci/saa7164/saa7164-bus.c
+++ b/drivers/media/pci/saa7164/saa7164-bus.c
@@ -33,12 +33,12 @@ int saa7164_bus_setup(struct saa7164_dev *dev)
b->Type = TYPE_BUS_PCIe;
b->m_wMaxReqSize = SAA_DEVICE_MAXREQUESTSIZE;
- b->m_pdwSetRing = (u8 *)(dev->bmmio +
+ b->m_pdwSetRing = (u8 __iomem *)(dev->bmmio +
((u32)dev->busdesc.CommandRing));
b->m_dwSizeSetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
- b->m_pdwGetRing = (u8 *)(dev->bmmio +
+ b->m_pdwGetRing = (u8 __iomem *)(dev->bmmio +
((u32)dev->busdesc.ResponseRing));
b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
@@ -138,6 +138,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
u32 new_swp, space_rem;
int ret = SAA_ERR_BAD_PARAMETER;
+ u16 size;
if (!msg) {
printk(KERN_ERR "%s() !msg\n", __func__);
@@ -148,10 +149,6 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
saa7164_bus_verify(dev);
- msg->size = cpu_to_le16(msg->size);
- msg->command = cpu_to_le32(msg->command);
- msg->controlselector = cpu_to_le16(msg->controlselector);
-
if (msg->size > dev->bus.m_wMaxReqSize) {
printk(KERN_ERR "%s() Exceeded dev->bus.m_wMaxReqSize\n",
__func__);
@@ -169,8 +166,8 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
bytes_to_write = sizeof(*msg) + msg->size;
free_write_space = 0;
timeout = SAA_BUS_TIMEOUT;
- curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
- curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos));
+ curr_srp = saa7164_readl(bus->m_dwSetReadPos);
+ curr_swp = saa7164_readl(bus->m_dwSetWritePos);
/* Deal with ring wrapping issues */
if (curr_srp > curr_swp)
@@ -203,7 +200,7 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
mdelay(1);
/* Check the space usage again */
- curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
+ curr_srp = saa7164_readl(bus->m_dwSetReadPos);
/* Deal with ring wrapping issues */
if (curr_srp > curr_swp)
@@ -223,6 +220,16 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
dprintk(DBGLVL_BUS, "%s() bus->m_dwSizeSetRing = %x\n", __func__,
bus->m_dwSizeSetRing);
+ /*
+ * Make a copy of msg->size before it is converted to le16 since it is
+ * used in the code below.
+ */
+ size = msg->size;
+ /* Convert to le16/le32 */
+ msg->size = (__force u16)cpu_to_le16(msg->size);
+ msg->command = (__force u32)cpu_to_le32(msg->command);
+ msg->controlselector = (__force u16)cpu_to_le16(msg->controlselector);
+
/* Mental Note: line 462 tmmhComResBusPCIe.cpp */
/* Check if we're going to wrap again */
@@ -243,28 +250,28 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
dprintk(DBGLVL_BUS, "%s() tr4\n", __func__);
/* Split the msg into pieces as the ring wraps */
- memcpy(bus->m_pdwSetRing + curr_swp, msg, space_rem);
- memcpy(bus->m_pdwSetRing, (u8 *)msg + space_rem,
+ memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, space_rem);
+ memcpy_toio(bus->m_pdwSetRing, (u8 *)msg + space_rem,
sizeof(*msg) - space_rem);
- memcpy(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
- buf, msg->size);
+ memcpy_toio(bus->m_pdwSetRing + sizeof(*msg) - space_rem,
+ buf, size);
} else if (space_rem == sizeof(*msg)) {
dprintk(DBGLVL_BUS, "%s() tr5\n", __func__);
/* Additional data at the beginning of the ring */
- memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
- memcpy(bus->m_pdwSetRing, buf, msg->size);
+ memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+ memcpy_toio(bus->m_pdwSetRing, buf, size);
} else {
/* Additional data wraps around the ring */
- memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
- if (msg->size > 0) {
- memcpy(bus->m_pdwSetRing + curr_swp +
+ memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+ if (size > 0) {
+ memcpy_toio(bus->m_pdwSetRing + curr_swp +
sizeof(*msg), buf, space_rem -
sizeof(*msg));
- memcpy(bus->m_pdwSetRing, (u8 *)buf +
+ memcpy_toio(bus->m_pdwSetRing, (u8 *)buf +
space_rem - sizeof(*msg),
bytes_to_write - space_rem);
}
@@ -276,15 +283,20 @@ int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
dprintk(DBGLVL_BUS, "%s() tr6\n", __func__);
/* The ring buffer doesn't wrap, two simple copies */
- memcpy(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
- memcpy(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
- msg->size);
+ memcpy_toio(bus->m_pdwSetRing + curr_swp, msg, sizeof(*msg));
+ memcpy_toio(bus->m_pdwSetRing + curr_swp + sizeof(*msg), buf,
+ size);
}
dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
/* Update the bus write position */
- saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp));
+ saa7164_writel(bus->m_dwSetWritePos, new_swp);
+
+ /* Convert back to cpu after writing the msg to the ringbuffer. */
+ msg->size = le16_to_cpu((__force __le16)msg->size);
+ msg->command = le32_to_cpu((__force __le32)msg->command);
+ msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
ret = SAA_OK;
out:
@@ -336,8 +348,8 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
/* Peek the bus to see if a msg exists, if it's not what we're expecting
* then return cleanly else read the message from the bus.
*/
- curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos));
- curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos));
+ curr_gwp = saa7164_readl(bus->m_dwGetWritePos);
+ curr_grp = saa7164_readl(bus->m_dwGetReadPos);
if (curr_gwp == curr_grp) {
ret = SAA_ERR_EMPTY;
@@ -369,14 +381,18 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
new_grp -= bus->m_dwSizeGetRing;
space_rem = bus->m_dwSizeGetRing - curr_grp;
- memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
- memcpy((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
+ memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, space_rem);
+ memcpy_fromio((u8 *)&msg_tmp + space_rem, bus->m_pdwGetRing,
bytes_to_read - space_rem);
} else {
/* No wrapping */
- memcpy(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
+ memcpy_fromio(&msg_tmp, bus->m_pdwGetRing + curr_grp, bytes_to_read);
}
+ /* Convert from little endian to CPU */
+ msg_tmp.size = le16_to_cpu((__force __le16)msg_tmp.size);
+ msg_tmp.command = le32_to_cpu((__force __le32)msg_tmp.command);
+ msg_tmp.controlselector = le16_to_cpu((__force __le16)msg_tmp.controlselector);
/* No need to update the read positions, because this was a peek */
/* If the caller specifically want to peek, return */
@@ -427,24 +443,24 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
if (space_rem < sizeof(*msg)) {
/* msg wraps around the ring */
- memcpy(msg, bus->m_pdwGetRing + curr_grp, space_rem);
- memcpy((u8 *)msg + space_rem, bus->m_pdwGetRing,
+ memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, space_rem);
+ memcpy_fromio((u8 *)msg + space_rem, bus->m_pdwGetRing,
sizeof(*msg) - space_rem);
if (buf)
- memcpy(buf, bus->m_pdwGetRing + sizeof(*msg) -
+ memcpy_fromio(buf, bus->m_pdwGetRing + sizeof(*msg) -
space_rem, buf_size);
} else if (space_rem == sizeof(*msg)) {
- memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
+ memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf)
- memcpy(buf, bus->m_pdwGetRing, buf_size);
+ memcpy_fromio(buf, bus->m_pdwGetRing, buf_size);
} else {
/* Additional data wraps around the ring */
- memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
+ memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf) {
- memcpy(buf, bus->m_pdwGetRing + curr_grp +
+ memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp +
sizeof(*msg), space_rem - sizeof(*msg));
- memcpy(buf + space_rem - sizeof(*msg),
+ memcpy_fromio(buf + space_rem - sizeof(*msg),
bus->m_pdwGetRing, bytes_to_read -
space_rem);
}
@@ -453,19 +469,20 @@ int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
} else {
/* No wrapping */
- memcpy(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
+ memcpy_fromio(msg, bus->m_pdwGetRing + curr_grp, sizeof(*msg));
if (buf)
- memcpy(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
+ memcpy_fromio(buf, bus->m_pdwGetRing + curr_grp + sizeof(*msg),
buf_size);
}
+ /* Convert from little endian to CPU */
+ msg->size = le16_to_cpu((__force __le16)msg->size);
+ msg->command = le32_to_cpu((__force __le32)msg->command);
+ msg->controlselector = le16_to_cpu((__force __le16)msg->controlselector);
/* Update the read positions, adjusting the ring */
- saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp));
+ saa7164_writel(bus->m_dwGetReadPos, new_grp);
peekout:
- msg->size = le16_to_cpu(msg->size);
- msg->command = le32_to_cpu(msg->command);
- msg->controlselector = le16_to_cpu(msg->controlselector);
ret = SAA_OK;
out:
mutex_unlock(&bus->lock);
diff --git a/drivers/media/pci/saa7164/saa7164-core.c b/drivers/media/pci/saa7164/saa7164-core.c
index cc1be8a..4b0bec3 100644
--- a/drivers/media/pci/saa7164/saa7164-core.c
+++ b/drivers/media/pci/saa7164/saa7164-core.c
@@ -119,7 +119,7 @@ static void saa7164_ts_verifier(struct saa7164_buffer *buf)
u32 i;
u8 cc, a;
u16 pid;
- u8 __iomem *bufcpu = (u8 *)buf->cpu;
+ u8 *bufcpu = (u8 *)buf->cpu;
port->sync_errors = 0;
port->v_cc_errors = 0;
@@ -260,7 +260,7 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
struct saa7164_user_buffer *ubuf = NULL;
struct list_head *c, *n;
int i = 0;
- u8 __iomem *p;
+ u8 *p;
mutex_lock(&port->dmaqueue_lock);
list_for_each_safe(c, n, &port->dmaqueue.list) {
@@ -318,8 +318,7 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
if (buf->actual_size <= ubuf->actual_size) {
- memcpy_fromio(ubuf->data, buf->cpu,
- ubuf->actual_size);
+ memcpy(ubuf->data, buf->cpu, ubuf->actual_size);
if (crc_checking) {
/* Throw a new checksum on the read buffer */
@@ -346,7 +345,7 @@ static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
* with known bad data. We check for this data at a later point
* in time. */
saa7164_buffer_zero_offsets(port, bufnr);
- memset_io(buf->cpu, 0xff, buf->pci_size);
+ memset(buf->cpu, 0xff, buf->pci_size);
if (crc_checking) {
/* Throw yet aanother new checksum on the dma buffer */
buf->crc = crc32(0, buf->cpu, buf->actual_size);
@@ -1096,7 +1095,7 @@ static int saa7164_proc_show(struct seq_file *m, void *v)
if (c == 0)
seq_printf(m, " %04x:", i);
- seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
+ seq_printf(m, " %02x", readb(b->m_pdwSetRing + i));
if (++c == 16) {
seq_printf(m, "\n");
@@ -1111,7 +1110,7 @@ static int saa7164_proc_show(struct seq_file *m, void *v)
if (c == 0)
seq_printf(m, " %04x:", i);
- seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
+ seq_printf(m, " %02x", readb(b->m_pdwGetRing + i));
if (++c == 16) {
seq_printf(m, "\n");
diff --git a/drivers/media/pci/saa7164/saa7164-fw.c b/drivers/media/pci/saa7164/saa7164-fw.c
index 8676320..add06ab 100644
--- a/drivers/media/pci/saa7164/saa7164-fw.c
+++ b/drivers/media/pci/saa7164/saa7164-fw.c
@@ -72,7 +72,7 @@ static int saa7164_dl_wait_clr(struct saa7164_dev *dev, u32 reg)
/* TODO: move dlflags into dev-> and change to write/readl/b */
/* TODO: Excessive levels of debug */
static int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
- u32 dlflags, u8 *dst, u32 dstsize)
+ u32 dlflags, u8 __iomem *dst, u32 dstsize)
{
u32 reg, timeout, offset;
u8 *srcbuf = NULL;
@@ -136,7 +136,7 @@ static int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
srcsize -= dstsize, offset += dstsize) {
dprintk(DBGLVL_FW, "%s() memcpy %d\n", __func__, dstsize);
- memcpy(dst, srcbuf + offset, dstsize);
+ memcpy_toio(dst, srcbuf + offset, dstsize);
/* Flag the data as ready */
saa7164_writel(drflag, 1);
@@ -154,7 +154,7 @@ static int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
dprintk(DBGLVL_FW, "%s() memcpy(l) %d\n", __func__, dstsize);
/* Write last block to the device */
- memcpy(dst, srcbuf+offset, srcsize);
+ memcpy_toio(dst, srcbuf+offset, srcsize);
/* Flag the data as ready */
saa7164_writel(drflag, 1);
diff --git a/drivers/media/pci/saa7164/saa7164-types.h b/drivers/media/pci/saa7164/saa7164-types.h
index 1d2140a..f48ba97 100644
--- a/drivers/media/pci/saa7164/saa7164-types.h
+++ b/drivers/media/pci/saa7164/saa7164-types.h
@@ -78,9 +78,9 @@ enum tmBusType {
struct tmComResBusInfo {
enum tmBusType Type;
u16 m_wMaxReqSize;
- u8 *m_pdwSetRing;
+ u8 __iomem *m_pdwSetRing;
u32 m_dwSizeSetRing;
- u8 *m_pdwGetRing;
+ u8 __iomem *m_pdwGetRing;
u32 m_dwSizeGetRing;
u32 m_dwSetWritePos;
u32 m_dwSetReadPos;
diff --git a/drivers/media/pci/saa7164/saa7164.h b/drivers/media/pci/saa7164/saa7164.h
index 8b29e89..cd1a07c 100644
--- a/drivers/media/pci/saa7164/saa7164.h
+++ b/drivers/media/pci/saa7164/saa7164.h
@@ -313,13 +313,13 @@ struct saa7164_buffer {
/* A block of page align PCI memory */
u32 pci_size; /* PCI allocation size in bytes */
- u64 __iomem *cpu; /* Virtual address */
+ u64 *cpu; /* Virtual address */
dma_addr_t dma; /* Physical address */
u32 crc; /* Checksum for the entire buffer data */
/* A page table that splits the block into a number of entries */
u32 pt_size; /* PCI allocation size in bytes */
- u64 __iomem *pt_cpu; /* Virtual address */
+ u64 *pt_cpu; /* Virtual address */
dma_addr_t pt_dma; /* Physical address */
/* Encoder fops */
diff --git a/drivers/media/pci/smipcie/Kconfig b/drivers/media/pci/smipcie/Kconfig
new file mode 100644
index 0000000..c8de53f
--- /dev/null
+++ b/drivers/media/pci/smipcie/Kconfig
@@ -0,0 +1,17 @@
+config DVB_SMIPCIE
+ tristate "SMI PCIe DVBSky cards"
+ depends on DVB_CORE && PCI && I2C
+ select I2C_ALGOBIT
+ select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_M88RS6000T if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+ help
+ Support for cards with SMI PCIe bridge:
+ - DVBSky S950 V3
+ - DVBSky S952 V3
+ - DVBSky T9580 V3
+
+ Say Y or M if you own such a device and want to use it.
+ If unsure say N.
diff --git a/drivers/media/pci/smipcie/Makefile b/drivers/media/pci/smipcie/Makefile
new file mode 100644
index 0000000..be55481
--- /dev/null
+++ b/drivers/media/pci/smipcie/Makefile
@@ -0,0 +1,6 @@
+obj-$(CONFIG_DVB_SMIPCIE) += smipcie.o
+
+ccflags-y += -Idrivers/media/tuners
+ccflags-y += -Idrivers/media/dvb-core
+ccflags-y += -Idrivers/media/dvb-frontends
+
diff --git a/drivers/media/pci/smipcie/smipcie.c b/drivers/media/pci/smipcie/smipcie.c
new file mode 100644
index 0000000..f773350
--- /dev/null
+++ b/drivers/media/pci/smipcie/smipcie.c
@@ -0,0 +1,1099 @@
+/*
+ * SMI PCIe driver for DVBSky cards.
+ *
+ * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "smipcie.h"
+#include "m88ds3103.h"
+#include "m88ts2022.h"
+#include "m88rs6000t.h"
+#include "si2168.h"
+#include "si2157.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int smi_hw_init(struct smi_dev *dev)
+{
+ u32 port_mux, port_ctrl, int_stat;
+
+ /* set port mux.*/
+ port_mux = smi_read(MUX_MODE_CTRL);
+ port_mux &= ~(rbPaMSMask);
+ port_mux |= rbPaMSDtvNoGpio;
+ port_mux &= ~(rbPbMSMask);
+ port_mux |= rbPbMSDtvNoGpio;
+ port_mux &= ~(0x0f0000);
+ port_mux |= 0x50000;
+ smi_write(MUX_MODE_CTRL, port_mux);
+
+ /* set DTV register.*/
+ /* Port A */
+ port_ctrl = smi_read(VIDEO_CTRL_STATUS_A);
+ port_ctrl &= ~0x01;
+ smi_write(VIDEO_CTRL_STATUS_A, port_ctrl);
+ port_ctrl = smi_read(MPEG2_CTRL_A);
+ port_ctrl &= ~0x40;
+ port_ctrl |= 0x80;
+ smi_write(MPEG2_CTRL_A, port_ctrl);
+ /* Port B */
+ port_ctrl = smi_read(VIDEO_CTRL_STATUS_B);
+ port_ctrl &= ~0x01;
+ smi_write(VIDEO_CTRL_STATUS_B, port_ctrl);
+ port_ctrl = smi_read(MPEG2_CTRL_B);
+ port_ctrl &= ~0x40;
+ port_ctrl |= 0x80;
+ smi_write(MPEG2_CTRL_B, port_ctrl);
+
+ /* disable and clear interrupt.*/
+ smi_write(MSI_INT_ENA_CLR, ALL_INT);
+ int_stat = smi_read(MSI_INT_STATUS);
+ smi_write(MSI_INT_STATUS_CLR, int_stat);
+
+ /* reset demod.*/
+ smi_clear(PERIPHERAL_CTRL, 0x0303);
+ msleep(50);
+ smi_set(PERIPHERAL_CTRL, 0x0101);
+ return 0;
+}
+
+/* i2c bit bus.*/
+static void smi_i2c_cfg(struct smi_dev *dev, u32 sw_ctl)
+{
+ u32 dwCtrl;
+
+ dwCtrl = smi_read(sw_ctl);
+ dwCtrl &= ~0x18; /* disable output.*/
+ dwCtrl |= 0x21; /* reset and software mode.*/
+ dwCtrl &= ~0xff00;
+ dwCtrl |= 0x6400;
+ smi_write(sw_ctl, dwCtrl);
+ msleep(20);
+ dwCtrl = smi_read(sw_ctl);
+ dwCtrl &= ~0x20;
+ smi_write(sw_ctl, dwCtrl);
+}
+
+static void smi_i2c_setsda(struct smi_dev *dev, int state, u32 sw_ctl)
+{
+ if (state) {
+ /* set as input.*/
+ smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN);
+ } else {
+ smi_clear(sw_ctl, SW_I2C_MSK_DAT_OUT);
+ /* set as output.*/
+ smi_set(sw_ctl, SW_I2C_MSK_DAT_EN);
+ }
+}
+
+static void smi_i2c_setscl(void *data, int state, u32 sw_ctl)
+{
+ struct smi_dev *dev = data;
+
+ if (state) {
+ /* set as input.*/
+ smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN);
+ } else {
+ smi_clear(sw_ctl, SW_I2C_MSK_CLK_OUT);
+ /* set as output.*/
+ smi_set(sw_ctl, SW_I2C_MSK_CLK_EN);
+ }
+}
+
+static int smi_i2c_getsda(void *data, u32 sw_ctl)
+{
+ struct smi_dev *dev = data;
+ /* set as input.*/
+ smi_clear(sw_ctl, SW_I2C_MSK_DAT_EN);
+ udelay(1);
+ return (smi_read(sw_ctl) & SW_I2C_MSK_DAT_IN) ? 1 : 0;
+}
+
+static int smi_i2c_getscl(void *data, u32 sw_ctl)
+{
+ struct smi_dev *dev = data;
+ /* set as input.*/
+ smi_clear(sw_ctl, SW_I2C_MSK_CLK_EN);
+ udelay(1);
+ return (smi_read(sw_ctl) & SW_I2C_MSK_CLK_IN) ? 1 : 0;
+}
+/* i2c 0.*/
+static void smi_i2c0_setsda(void *data, int state)
+{
+ struct smi_dev *dev = data;
+
+ smi_i2c_setsda(dev, state, I2C_A_SW_CTL);
+}
+
+static void smi_i2c0_setscl(void *data, int state)
+{
+ struct smi_dev *dev = data;
+
+ smi_i2c_setscl(dev, state, I2C_A_SW_CTL);
+}
+
+static int smi_i2c0_getsda(void *data)
+{
+ struct smi_dev *dev = data;
+
+ return smi_i2c_getsda(dev, I2C_A_SW_CTL);
+}
+
+static int smi_i2c0_getscl(void *data)
+{
+ struct smi_dev *dev = data;
+
+ return smi_i2c_getscl(dev, I2C_A_SW_CTL);
+}
+/* i2c 1.*/
+static void smi_i2c1_setsda(void *data, int state)
+{
+ struct smi_dev *dev = data;
+
+ smi_i2c_setsda(dev, state, I2C_B_SW_CTL);
+}
+
+static void smi_i2c1_setscl(void *data, int state)
+{
+ struct smi_dev *dev = data;
+
+ smi_i2c_setscl(dev, state, I2C_B_SW_CTL);
+}
+
+static int smi_i2c1_getsda(void *data)
+{
+ struct smi_dev *dev = data;
+
+ return smi_i2c_getsda(dev, I2C_B_SW_CTL);
+}
+
+static int smi_i2c1_getscl(void *data)
+{
+ struct smi_dev *dev = data;
+
+ return smi_i2c_getscl(dev, I2C_B_SW_CTL);
+}
+
+static int smi_i2c_init(struct smi_dev *dev)
+{
+ int ret;
+
+ /* i2c bus 0 */
+ smi_i2c_cfg(dev, I2C_A_SW_CTL);
+ i2c_set_adapdata(&dev->i2c_bus[0], dev);
+ strcpy(dev->i2c_bus[0].name, "SMI-I2C0");
+ dev->i2c_bus[0].owner = THIS_MODULE;
+ dev->i2c_bus[0].dev.parent = &dev->pci_dev->dev;
+ dev->i2c_bus[0].algo_data = &dev->i2c_bit[0];
+ dev->i2c_bit[0].data = dev;
+ dev->i2c_bit[0].setsda = smi_i2c0_setsda;
+ dev->i2c_bit[0].setscl = smi_i2c0_setscl;
+ dev->i2c_bit[0].getsda = smi_i2c0_getsda;
+ dev->i2c_bit[0].getscl = smi_i2c0_getscl;
+ dev->i2c_bit[0].udelay = 12;
+ dev->i2c_bit[0].timeout = 10;
+ /* Raise SCL and SDA */
+ smi_i2c0_setsda(dev, 1);
+ smi_i2c0_setscl(dev, 1);
+
+ ret = i2c_bit_add_bus(&dev->i2c_bus[0]);
+ if (ret < 0)
+ return ret;
+
+ /* i2c bus 1 */
+ smi_i2c_cfg(dev, I2C_B_SW_CTL);
+ i2c_set_adapdata(&dev->i2c_bus[1], dev);
+ strcpy(dev->i2c_bus[1].name, "SMI-I2C1");
+ dev->i2c_bus[1].owner = THIS_MODULE;
+ dev->i2c_bus[1].dev.parent = &dev->pci_dev->dev;
+ dev->i2c_bus[1].algo_data = &dev->i2c_bit[1];
+ dev->i2c_bit[1].data = dev;
+ dev->i2c_bit[1].setsda = smi_i2c1_setsda;
+ dev->i2c_bit[1].setscl = smi_i2c1_setscl;
+ dev->i2c_bit[1].getsda = smi_i2c1_getsda;
+ dev->i2c_bit[1].getscl = smi_i2c1_getscl;
+ dev->i2c_bit[1].udelay = 12;
+ dev->i2c_bit[1].timeout = 10;
+ /* Raise SCL and SDA */
+ smi_i2c1_setsda(dev, 1);
+ smi_i2c1_setscl(dev, 1);
+
+ ret = i2c_bit_add_bus(&dev->i2c_bus[1]);
+ if (ret < 0)
+ i2c_del_adapter(&dev->i2c_bus[0]);
+
+ return ret;
+}
+
+static void smi_i2c_exit(struct smi_dev *dev)
+{
+ i2c_del_adapter(&dev->i2c_bus[0]);
+ i2c_del_adapter(&dev->i2c_bus[1]);
+}
+
+static int smi_read_eeprom(struct i2c_adapter *i2c, u16 reg, u8 *data, u16 size)
+{
+ int ret;
+ u8 b0[2] = { (reg >> 8) & 0xff, reg & 0xff };
+
+ struct i2c_msg msg[] = {
+ { .addr = 0x50, .flags = 0,
+ .buf = b0, .len = 2 },
+ { .addr = 0x50, .flags = I2C_M_RD,
+ .buf = data, .len = size }
+ };
+
+ ret = i2c_transfer(i2c, msg, 2);
+
+ if (ret != 2) {
+ dev_err(&i2c->dev, "%s: reg=0x%x (error=%d)\n",
+ __func__, reg, ret);
+ return ret;
+ }
+ return ret;
+}
+
+/* ts port interrupt operations */
+static void smi_port_disableInterrupt(struct smi_port *port)
+{
+ struct smi_dev *dev = port->dev;
+
+ smi_write(MSI_INT_ENA_CLR,
+ (port->_dmaInterruptCH0 | port->_dmaInterruptCH1));
+}
+
+static void smi_port_enableInterrupt(struct smi_port *port)
+{
+ struct smi_dev *dev = port->dev;
+
+ smi_write(MSI_INT_ENA_SET,
+ (port->_dmaInterruptCH0 | port->_dmaInterruptCH1));
+}
+
+static void smi_port_clearInterrupt(struct smi_port *port)
+{
+ struct smi_dev *dev = port->dev;
+
+ smi_write(MSI_INT_STATUS_CLR,
+ (port->_dmaInterruptCH0 | port->_dmaInterruptCH1));
+}
+
+/* tasklet handler: DMA data to dmx.*/
+static void smi_dma_xfer(unsigned long data)
+{
+ struct smi_port *port = (struct smi_port *) data;
+ struct smi_dev *dev = port->dev;
+ u32 intr_status, finishedData, dmaManagement;
+ u8 dmaChan0State, dmaChan1State;
+
+ intr_status = port->_int_status;
+ dmaManagement = smi_read(port->DMA_MANAGEMENT);
+ dmaChan0State = (u8)((dmaManagement & 0x00000030) >> 4);
+ dmaChan1State = (u8)((dmaManagement & 0x00300000) >> 20);
+
+ /* CH-0 DMA interrupt.*/
+ if ((intr_status & port->_dmaInterruptCH0) && (dmaChan0State == 0x01)) {
+ dev_dbg(&dev->pci_dev->dev,
+ "Port[%d]-DMA CH0 engine complete successful !\n",
+ port->idx);
+ finishedData = smi_read(port->DMA_CHAN0_TRANS_STATE);
+ finishedData &= 0x003FFFFF;
+ /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0]
+ * indicate dma total transfer length and
+ * zero of [21:0] indicate dma total transfer length
+ * equal to 0x400000 (4MB)*/
+ if (finishedData == 0)
+ finishedData = 0x00400000;
+ if (finishedData != SMI_TS_DMA_BUF_SIZE) {
+ dev_dbg(&dev->pci_dev->dev,
+ "DMA CH0 engine complete length mismatched, finish data=%d !\n",
+ finishedData);
+ }
+ dvb_dmx_swfilter_packets(&port->demux,
+ port->cpu_addr[0], (finishedData / 188));
+ /*dvb_dmx_swfilter(&port->demux,
+ port->cpu_addr[0], finishedData);*/
+ }
+ /* CH-1 DMA interrupt.*/
+ if ((intr_status & port->_dmaInterruptCH1) && (dmaChan1State == 0x01)) {
+ dev_dbg(&dev->pci_dev->dev,
+ "Port[%d]-DMA CH1 engine complete successful !\n",
+ port->idx);
+ finishedData = smi_read(port->DMA_CHAN1_TRANS_STATE);
+ finishedData &= 0x003FFFFF;
+ /* value of DMA_PORT0_CHAN0_TRANS_STATE register [21:0]
+ * indicate dma total transfer length and
+ * zero of [21:0] indicate dma total transfer length
+ * equal to 0x400000 (4MB)*/
+ if (finishedData == 0)
+ finishedData = 0x00400000;
+ if (finishedData != SMI_TS_DMA_BUF_SIZE) {
+ dev_dbg(&dev->pci_dev->dev,
+ "DMA CH1 engine complete length mismatched, finish data=%d !\n",
+ finishedData);
+ }
+ dvb_dmx_swfilter_packets(&port->demux,
+ port->cpu_addr[1], (finishedData / 188));
+ /*dvb_dmx_swfilter(&port->demux,
+ port->cpu_addr[1], finishedData);*/
+ }
+ /* restart DMA.*/
+ if (intr_status & port->_dmaInterruptCH0)
+ dmaManagement |= 0x00000002;
+ if (intr_status & port->_dmaInterruptCH1)
+ dmaManagement |= 0x00020000;
+ smi_write(port->DMA_MANAGEMENT, dmaManagement);
+ /* Re-enable interrupts */
+ smi_port_enableInterrupt(port);
+}
+
+static void smi_port_dma_free(struct smi_port *port)
+{
+ if (port->cpu_addr[0]) {
+ pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE,
+ port->cpu_addr[0], port->dma_addr[0]);
+ port->cpu_addr[0] = NULL;
+ }
+ if (port->cpu_addr[1]) {
+ pci_free_consistent(port->dev->pci_dev, SMI_TS_DMA_BUF_SIZE,
+ port->cpu_addr[1], port->dma_addr[1]);
+ port->cpu_addr[1] = NULL;
+ }
+}
+
+static int smi_port_init(struct smi_port *port, int dmaChanUsed)
+{
+ dev_dbg(&port->dev->pci_dev->dev,
+ "%s, port %d, dmaused %d\n", __func__, port->idx, dmaChanUsed);
+ port->enable = 0;
+ if (port->idx == 0) {
+ /* Port A */
+ port->_dmaInterruptCH0 = dmaChanUsed & 0x01;
+ port->_dmaInterruptCH1 = dmaChanUsed & 0x02;
+
+ port->DMA_CHAN0_ADDR_LOW = DMA_PORTA_CHAN0_ADDR_LOW;
+ port->DMA_CHAN0_ADDR_HI = DMA_PORTA_CHAN0_ADDR_HI;
+ port->DMA_CHAN0_TRANS_STATE = DMA_PORTA_CHAN0_TRANS_STATE;
+ port->DMA_CHAN0_CONTROL = DMA_PORTA_CHAN0_CONTROL;
+ port->DMA_CHAN1_ADDR_LOW = DMA_PORTA_CHAN1_ADDR_LOW;
+ port->DMA_CHAN1_ADDR_HI = DMA_PORTA_CHAN1_ADDR_HI;
+ port->DMA_CHAN1_TRANS_STATE = DMA_PORTA_CHAN1_TRANS_STATE;
+ port->DMA_CHAN1_CONTROL = DMA_PORTA_CHAN1_CONTROL;
+ port->DMA_MANAGEMENT = DMA_PORTA_MANAGEMENT;
+ } else {
+ /* Port B */
+ port->_dmaInterruptCH0 = (dmaChanUsed << 2) & 0x04;
+ port->_dmaInterruptCH1 = (dmaChanUsed << 2) & 0x08;
+
+ port->DMA_CHAN0_ADDR_LOW = DMA_PORTB_CHAN0_ADDR_LOW;
+ port->DMA_CHAN0_ADDR_HI = DMA_PORTB_CHAN0_ADDR_HI;
+ port->DMA_CHAN0_TRANS_STATE = DMA_PORTB_CHAN0_TRANS_STATE;
+ port->DMA_CHAN0_CONTROL = DMA_PORTB_CHAN0_CONTROL;
+ port->DMA_CHAN1_ADDR_LOW = DMA_PORTB_CHAN1_ADDR_LOW;
+ port->DMA_CHAN1_ADDR_HI = DMA_PORTB_CHAN1_ADDR_HI;
+ port->DMA_CHAN1_TRANS_STATE = DMA_PORTB_CHAN1_TRANS_STATE;
+ port->DMA_CHAN1_CONTROL = DMA_PORTB_CHAN1_CONTROL;
+ port->DMA_MANAGEMENT = DMA_PORTB_MANAGEMENT;
+ }
+
+ if (port->_dmaInterruptCH0) {
+ port->cpu_addr[0] = pci_alloc_consistent(port->dev->pci_dev,
+ SMI_TS_DMA_BUF_SIZE,
+ &port->dma_addr[0]);
+ if (!port->cpu_addr[0]) {
+ dev_err(&port->dev->pci_dev->dev,
+ "Port[%d] DMA CH0 memory allocation failed!\n",
+ port->idx);
+ goto err;
+ }
+ }
+
+ if (port->_dmaInterruptCH1) {
+ port->cpu_addr[1] = pci_alloc_consistent(port->dev->pci_dev,
+ SMI_TS_DMA_BUF_SIZE,
+ &port->dma_addr[1]);
+ if (!port->cpu_addr[1]) {
+ dev_err(&port->dev->pci_dev->dev,
+ "Port[%d] DMA CH1 memory allocation failed!\n",
+ port->idx);
+ goto err;
+ }
+ }
+
+ smi_port_disableInterrupt(port);
+ tasklet_init(&port->tasklet, smi_dma_xfer, (unsigned long)port);
+ tasklet_disable(&port->tasklet);
+ port->enable = 1;
+ return 0;
+err:
+ smi_port_dma_free(port);
+ return -ENOMEM;
+}
+
+static void smi_port_exit(struct smi_port *port)
+{
+ smi_port_disableInterrupt(port);
+ tasklet_kill(&port->tasklet);
+ smi_port_dma_free(port);
+ port->enable = 0;
+}
+
+static void smi_port_irq(struct smi_port *port, u32 int_status)
+{
+ u32 port_req_irq = port->_dmaInterruptCH0 | port->_dmaInterruptCH1;
+
+ if (int_status & port_req_irq) {
+ smi_port_disableInterrupt(port);
+ port->_int_status = int_status;
+ smi_port_clearInterrupt(port);
+ tasklet_schedule(&port->tasklet);
+ }
+}
+
+static irqreturn_t smi_irq_handler(int irq, void *dev_id)
+{
+ struct smi_dev *dev = dev_id;
+ struct smi_port *port0 = &dev->ts_port[0];
+ struct smi_port *port1 = &dev->ts_port[1];
+
+ u32 intr_status = smi_read(MSI_INT_STATUS);
+
+ /* ts0 interrupt.*/
+ if (dev->info->ts_0)
+ smi_port_irq(port0, intr_status);
+
+ /* ts1 interrupt.*/
+ if (dev->info->ts_1)
+ smi_port_irq(port1, intr_status);
+
+ return IRQ_HANDLED;
+}
+
+static struct i2c_client *smi_add_i2c_client(struct i2c_adapter *adapter,
+ struct i2c_board_info *info)
+{
+ struct i2c_client *client;
+
+ request_module(info->type);
+ client = i2c_new_device(adapter, info);
+ if (client == NULL || client->dev.driver == NULL)
+ goto err_add_i2c_client;
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ goto err_add_i2c_client;
+ }
+ return client;
+
+err_add_i2c_client:
+ client = NULL;
+ return client;
+}
+
+static void smi_del_i2c_client(struct i2c_client *client)
+{
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+}
+
+static const struct m88ds3103_config smi_dvbsky_m88ds3103_cfg = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_PARALLEL,
+ .ts_clk = 16000,
+ .ts_clk_pol = 1,
+ .agc = 0x99,
+ .lnb_hv_pol = 0,
+ .lnb_en_pol = 1,
+};
+
+static int smi_dvbsky_m88ds3103_fe_attach(struct smi_port *port)
+{
+ int ret = 0;
+ struct smi_dev *dev = port->dev;
+ struct i2c_adapter *i2c;
+ /* tuner I2C module */
+ struct i2c_adapter *tuner_i2c_adapter;
+ struct i2c_client *tuner_client;
+ struct i2c_board_info tuner_info;
+ struct m88ts2022_config m88ts2022_config = {
+ .clock = 27000000,
+ };
+ memset(&tuner_info, 0, sizeof(struct i2c_board_info));
+ i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1];
+
+ /* attach demod */
+ port->fe = dvb_attach(m88ds3103_attach,
+ &smi_dvbsky_m88ds3103_cfg, i2c, &tuner_i2c_adapter);
+ if (!port->fe) {
+ ret = -ENODEV;
+ return ret;
+ }
+ /* attach tuner */
+ m88ts2022_config.fe = port->fe;
+ strlcpy(tuner_info.type, "m88ts2022", I2C_NAME_SIZE);
+ tuner_info.addr = 0x60;
+ tuner_info.platform_data = &m88ts2022_config;
+ tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info);
+ if (!tuner_client) {
+ ret = -ENODEV;
+ goto err_tuner_i2c_device;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ port->fe->ops.read_signal_strength =
+ port->fe->ops.tuner_ops.get_rf_strength;
+
+ port->i2c_client_tuner = tuner_client;
+ return ret;
+
+err_tuner_i2c_device:
+ dvb_frontend_detach(port->fe);
+ return ret;
+}
+
+static const struct m88ds3103_config smi_dvbsky_m88rs6000_cfg = {
+ .i2c_addr = 0x69,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .ts_mode = M88DS3103_TS_PARALLEL,
+ .ts_clk = 16000,
+ .ts_clk_pol = 1,
+ .agc = 0x99,
+ .lnb_hv_pol = 0,
+ .lnb_en_pol = 1,
+};
+
+static int smi_dvbsky_m88rs6000_fe_attach(struct smi_port *port)
+{
+ int ret = 0;
+ struct smi_dev *dev = port->dev;
+ struct i2c_adapter *i2c;
+ /* tuner I2C module */
+ struct i2c_adapter *tuner_i2c_adapter;
+ struct i2c_client *tuner_client;
+ struct i2c_board_info tuner_info;
+ struct m88rs6000t_config m88rs6000t_config;
+
+ memset(&tuner_info, 0, sizeof(struct i2c_board_info));
+ i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1];
+
+ /* attach demod */
+ port->fe = dvb_attach(m88ds3103_attach,
+ &smi_dvbsky_m88rs6000_cfg, i2c, &tuner_i2c_adapter);
+ if (!port->fe) {
+ ret = -ENODEV;
+ return ret;
+ }
+ /* attach tuner */
+ m88rs6000t_config.fe = port->fe;
+ strlcpy(tuner_info.type, "m88rs6000t", I2C_NAME_SIZE);
+ tuner_info.addr = 0x21;
+ tuner_info.platform_data = &m88rs6000t_config;
+ tuner_client = smi_add_i2c_client(tuner_i2c_adapter, &tuner_info);
+ if (!tuner_client) {
+ ret = -ENODEV;
+ goto err_tuner_i2c_device;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ port->fe->ops.read_signal_strength =
+ port->fe->ops.tuner_ops.get_rf_strength;
+
+ port->i2c_client_tuner = tuner_client;
+ return ret;
+
+err_tuner_i2c_device:
+ dvb_frontend_detach(port->fe);
+ return ret;
+}
+
+static int smi_dvbsky_sit2_fe_attach(struct smi_port *port)
+{
+ int ret = 0;
+ struct smi_dev *dev = port->dev;
+ struct i2c_adapter *i2c;
+ struct i2c_adapter *tuner_i2c_adapter;
+ struct i2c_client *client_tuner, *client_demod;
+ struct i2c_board_info client_info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+
+ /* select i2c bus */
+ i2c = (port->idx == 0) ? &dev->i2c_bus[0] : &dev->i2c_bus[1];
+
+ /* attach demod */
+ memset(&si2168_config, 0, sizeof(si2168_config));
+ si2168_config.i2c_adapter = &tuner_i2c_adapter;
+ si2168_config.fe = &port->fe;
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+
+ memset(&client_info, 0, sizeof(struct i2c_board_info));
+ strlcpy(client_info.type, "si2168", I2C_NAME_SIZE);
+ client_info.addr = 0x64;
+ client_info.platform_data = &si2168_config;
+
+ client_demod = smi_add_i2c_client(i2c, &client_info);
+ if (!client_demod) {
+ ret = -ENODEV;
+ return ret;
+ }
+ port->i2c_client_demod = client_demod;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = port->fe;
+
+ memset(&client_info, 0, sizeof(struct i2c_board_info));
+ strlcpy(client_info.type, "si2157", I2C_NAME_SIZE);
+ client_info.addr = 0x60;
+ client_info.platform_data = &si2157_config;
+
+ client_tuner = smi_add_i2c_client(tuner_i2c_adapter, &client_info);
+ if (!client_tuner) {
+ smi_del_i2c_client(port->i2c_client_demod);
+ port->i2c_client_demod = NULL;
+ ret = -ENODEV;
+ return ret;
+ }
+ port->i2c_client_tuner = client_tuner;
+ return ret;
+}
+
+static int smi_fe_init(struct smi_port *port)
+{
+ int ret = 0;
+ struct smi_dev *dev = port->dev;
+ struct dvb_adapter *adap = &port->dvb_adapter;
+ u8 mac_ee[16];
+
+ dev_dbg(&port->dev->pci_dev->dev,
+ "%s: port %d, fe_type = %d\n",
+ __func__, port->idx, port->fe_type);
+ switch (port->fe_type) {
+ case DVBSKY_FE_M88DS3103:
+ ret = smi_dvbsky_m88ds3103_fe_attach(port);
+ break;
+ case DVBSKY_FE_M88RS6000:
+ ret = smi_dvbsky_m88rs6000_fe_attach(port);
+ break;
+ case DVBSKY_FE_SIT2:
+ ret = smi_dvbsky_sit2_fe_attach(port);
+ break;
+ }
+ if (ret < 0)
+ return ret;
+
+ /* register dvb frontend */
+ ret = dvb_register_frontend(adap, port->fe);
+ if (ret < 0) {
+ if (port->i2c_client_tuner)
+ smi_del_i2c_client(port->i2c_client_tuner);
+ if (port->i2c_client_demod)
+ smi_del_i2c_client(port->i2c_client_demod);
+ dvb_frontend_detach(port->fe);
+ return ret;
+ }
+ /* init MAC.*/
+ ret = smi_read_eeprom(&dev->i2c_bus[0], 0xc0, mac_ee, 16);
+ dev_info(&port->dev->pci_dev->dev,
+ "DVBSky SMI PCIe MAC= %pM\n", mac_ee + (port->idx)*8);
+ memcpy(adap->proposed_mac, mac_ee + (port->idx)*8, 6);
+ return ret;
+}
+
+static void smi_fe_exit(struct smi_port *port)
+{
+ dvb_unregister_frontend(port->fe);
+ /* remove I2C demod and tuner */
+ if (port->i2c_client_tuner)
+ smi_del_i2c_client(port->i2c_client_tuner);
+ if (port->i2c_client_demod)
+ smi_del_i2c_client(port->i2c_client_demod);
+ dvb_frontend_detach(port->fe);
+}
+
+static int my_dvb_dmx_ts_card_init(struct dvb_demux *dvbdemux, char *id,
+ int (*start_feed)(struct dvb_demux_feed *),
+ int (*stop_feed)(struct dvb_demux_feed *),
+ void *priv)
+{
+ dvbdemux->priv = priv;
+
+ dvbdemux->filternum = 256;
+ dvbdemux->feednum = 256;
+ dvbdemux->start_feed = start_feed;
+ dvbdemux->stop_feed = stop_feed;
+ dvbdemux->write_to_decoder = NULL;
+ dvbdemux->dmx.capabilities = (DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING);
+ return dvb_dmx_init(dvbdemux);
+}
+
+static int my_dvb_dmxdev_ts_card_init(struct dmxdev *dmxdev,
+ struct dvb_demux *dvbdemux,
+ struct dmx_frontend *hw_frontend,
+ struct dmx_frontend *mem_frontend,
+ struct dvb_adapter *dvb_adapter)
+{
+ int ret;
+
+ dmxdev->filternum = 256;
+ dmxdev->demux = &dvbdemux->dmx;
+ dmxdev->capabilities = 0;
+ ret = dvb_dmxdev_init(dmxdev, dvb_adapter);
+ if (ret < 0)
+ return ret;
+
+ hw_frontend->source = DMX_FRONTEND_0;
+ dvbdemux->dmx.add_frontend(&dvbdemux->dmx, hw_frontend);
+ mem_frontend->source = DMX_MEMORY_FE;
+ dvbdemux->dmx.add_frontend(&dvbdemux->dmx, mem_frontend);
+ return dvbdemux->dmx.connect_frontend(&dvbdemux->dmx, hw_frontend);
+}
+
+static u32 smi_config_DMA(struct smi_port *port)
+{
+ struct smi_dev *dev = port->dev;
+ u32 totalLength = 0, dmaMemPtrLow, dmaMemPtrHi, dmaCtlReg;
+ u8 chanLatencyTimer = 0, dmaChanEnable = 1, dmaTransStart = 1;
+ u32 dmaManagement = 0, tlpTransUnit = DMA_TRANS_UNIT_188;
+ u8 tlpTc = 0, tlpTd = 1, tlpEp = 0, tlpAttr = 0;
+ u64 mem;
+
+ dmaManagement = smi_read(port->DMA_MANAGEMENT);
+ /* Setup Channel-0 */
+ if (port->_dmaInterruptCH0) {
+ totalLength = SMI_TS_DMA_BUF_SIZE;
+ mem = port->dma_addr[0];
+ dmaMemPtrLow = mem & 0xffffffff;
+ dmaMemPtrHi = mem >> 32;
+ dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25)
+ | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30);
+ dmaManagement |= dmaChanEnable | (dmaTransStart << 1)
+ | (chanLatencyTimer << 8);
+ /* write DMA register, start DMA engine */
+ smi_write(port->DMA_CHAN0_ADDR_LOW, dmaMemPtrLow);
+ smi_write(port->DMA_CHAN0_ADDR_HI, dmaMemPtrHi);
+ smi_write(port->DMA_CHAN0_CONTROL, dmaCtlReg);
+ }
+ /* Setup Channel-1 */
+ if (port->_dmaInterruptCH1) {
+ totalLength = SMI_TS_DMA_BUF_SIZE;
+ mem = port->dma_addr[1];
+ dmaMemPtrLow = mem & 0xffffffff;
+ dmaMemPtrHi = mem >> 32;
+ dmaCtlReg = (totalLength) | (tlpTransUnit << 22) | (tlpTc << 25)
+ | (tlpTd << 28) | (tlpEp << 29) | (tlpAttr << 30);
+ dmaManagement |= (dmaChanEnable << 16) | (dmaTransStart << 17)
+ | (chanLatencyTimer << 24);
+ /* write DMA register, start DMA engine */
+ smi_write(port->DMA_CHAN1_ADDR_LOW, dmaMemPtrLow);
+ smi_write(port->DMA_CHAN1_ADDR_HI, dmaMemPtrHi);
+ smi_write(port->DMA_CHAN1_CONTROL, dmaCtlReg);
+ }
+ return dmaManagement;
+}
+
+static int smi_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct smi_port *port = dvbdmx->priv;
+ struct smi_dev *dev = port->dev;
+ u32 dmaManagement;
+
+ if (port->users++ == 0) {
+ dmaManagement = smi_config_DMA(port);
+ smi_port_clearInterrupt(port);
+ smi_port_enableInterrupt(port);
+ smi_write(port->DMA_MANAGEMENT, dmaManagement);
+ tasklet_enable(&port->tasklet);
+ }
+ return port->users;
+}
+
+static int smi_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ struct dvb_demux *dvbdmx = dvbdmxfeed->demux;
+ struct smi_port *port = dvbdmx->priv;
+ struct smi_dev *dev = port->dev;
+
+ if (--port->users)
+ return port->users;
+
+ tasklet_disable(&port->tasklet);
+ smi_port_disableInterrupt(port);
+ smi_clear(port->DMA_MANAGEMENT, 0x30003);
+ return 0;
+}
+
+static int smi_dvb_init(struct smi_port *port)
+{
+ int ret;
+ struct dvb_adapter *adap = &port->dvb_adapter;
+ struct dvb_demux *dvbdemux = &port->demux;
+
+ dev_dbg(&port->dev->pci_dev->dev,
+ "%s, port %d\n", __func__, port->idx);
+
+ ret = dvb_register_adapter(adap, "SMI_DVB", THIS_MODULE,
+ &port->dev->pci_dev->dev,
+ adapter_nr);
+ if (ret < 0) {
+ dev_err(&port->dev->pci_dev->dev, "Fail to register DVB adapter.\n");
+ return ret;
+ }
+ ret = my_dvb_dmx_ts_card_init(dvbdemux, "SW demux",
+ smi_start_feed,
+ smi_stop_feed, port);
+ if (ret < 0)
+ goto err_del_dvb_register_adapter;
+
+ ret = my_dvb_dmxdev_ts_card_init(&port->dmxdev, &port->demux,
+ &port->hw_frontend,
+ &port->mem_frontend, adap);
+ if (ret < 0)
+ goto err_del_dvb_dmx;
+
+ ret = dvb_net_init(adap, &port->dvbnet, port->dmxdev.demux);
+ if (ret < 0)
+ goto err_del_dvb_dmxdev;
+ return 0;
+err_del_dvb_dmxdev:
+ dvbdemux->dmx.close(&dvbdemux->dmx);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend);
+ dvb_dmxdev_release(&port->dmxdev);
+err_del_dvb_dmx:
+ dvb_dmx_release(&port->demux);
+err_del_dvb_register_adapter:
+ dvb_unregister_adapter(&port->dvb_adapter);
+ return ret;
+}
+
+static void smi_dvb_exit(struct smi_port *port)
+{
+ struct dvb_demux *dvbdemux = &port->demux;
+
+ dvb_net_release(&port->dvbnet);
+
+ dvbdemux->dmx.close(&dvbdemux->dmx);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->hw_frontend);
+ dvbdemux->dmx.remove_frontend(&dvbdemux->dmx, &port->mem_frontend);
+ dvb_dmxdev_release(&port->dmxdev);
+ dvb_dmx_release(&port->demux);
+
+ dvb_unregister_adapter(&port->dvb_adapter);
+}
+
+static int smi_port_attach(struct smi_dev *dev,
+ struct smi_port *port, int index)
+{
+ int ret, dmachs;
+
+ port->dev = dev;
+ port->idx = index;
+ port->fe_type = (index == 0) ? dev->info->fe_0 : dev->info->fe_1;
+ dmachs = (index == 0) ? dev->info->ts_0 : dev->info->ts_1;
+ /* port init.*/
+ ret = smi_port_init(port, dmachs);
+ if (ret < 0)
+ return ret;
+ /* dvb init.*/
+ ret = smi_dvb_init(port);
+ if (ret < 0)
+ goto err_del_port_init;
+ /* fe init.*/
+ ret = smi_fe_init(port);
+ if (ret < 0)
+ goto err_del_dvb_init;
+ return 0;
+err_del_dvb_init:
+ smi_dvb_exit(port);
+err_del_port_init:
+ smi_port_exit(port);
+ return ret;
+}
+
+static void smi_port_detach(struct smi_port *port)
+{
+ smi_fe_exit(port);
+ smi_dvb_exit(port);
+ smi_port_exit(port);
+}
+
+static int smi_probe(struct pci_dev *pdev, const struct pci_device_id *id)
+{
+ struct smi_dev *dev;
+ int ret = -ENOMEM;
+
+ if (pci_enable_device(pdev) < 0)
+ return -ENODEV;
+
+ dev = kzalloc(sizeof(struct smi_dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ goto err_pci_disable_device;
+ }
+
+ dev->pci_dev = pdev;
+ pci_set_drvdata(pdev, dev);
+ dev->info = (struct smi_cfg_info *) id->driver_data;
+ dev_info(&dev->pci_dev->dev,
+ "card detected: %s\n", dev->info->name);
+
+ dev->nr = dev->info->type;
+ dev->lmmio = ioremap(pci_resource_start(dev->pci_dev, 0),
+ pci_resource_len(dev->pci_dev, 0));
+ if (!dev->lmmio) {
+ ret = -ENOMEM;
+ goto err_kfree;
+ }
+
+ /* should we set to 32bit DMA? */
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (ret < 0)
+ goto err_pci_iounmap;
+
+ pci_set_master(pdev);
+
+ ret = smi_hw_init(dev);
+ if (ret < 0)
+ goto err_pci_iounmap;
+
+ ret = smi_i2c_init(dev);
+ if (ret < 0)
+ goto err_pci_iounmap;
+
+ if (dev->info->ts_0) {
+ ret = smi_port_attach(dev, &dev->ts_port[0], 0);
+ if (ret < 0)
+ goto err_del_i2c_adaptor;
+ }
+
+ if (dev->info->ts_1) {
+ ret = smi_port_attach(dev, &dev->ts_port[1], 1);
+ if (ret < 0)
+ goto err_del_port0_attach;
+ }
+
+#ifdef CONFIG_PCI_MSI /* to do msi interrupt.???*/
+ if (pci_msi_enabled())
+ ret = pci_enable_msi(dev->pci_dev);
+ if (ret)
+ dev_info(&dev->pci_dev->dev, "MSI not available.\n");
+#endif
+
+ ret = request_irq(dev->pci_dev->irq, smi_irq_handler,
+ IRQF_SHARED, "SMI_PCIE", dev);
+ if (ret < 0)
+ goto err_del_port1_attach;
+
+ return 0;
+
+err_del_port1_attach:
+ if (dev->info->ts_1)
+ smi_port_detach(&dev->ts_port[1]);
+err_del_port0_attach:
+ if (dev->info->ts_0)
+ smi_port_detach(&dev->ts_port[0]);
+err_del_i2c_adaptor:
+ smi_i2c_exit(dev);
+err_pci_iounmap:
+ iounmap(dev->lmmio);
+err_kfree:
+ pci_set_drvdata(pdev, NULL);
+ kfree(dev);
+err_pci_disable_device:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void smi_remove(struct pci_dev *pdev)
+{
+ struct smi_dev *dev = pci_get_drvdata(pdev);
+
+ smi_write(MSI_INT_ENA_CLR, ALL_INT);
+ free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+ pci_disable_msi(dev->pci_dev);
+#endif
+ if (dev->info->ts_1)
+ smi_port_detach(&dev->ts_port[1]);
+ if (dev->info->ts_0)
+ smi_port_detach(&dev->ts_port[0]);
+
+ smi_i2c_exit(dev);
+ iounmap(dev->lmmio);
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+ kfree(dev);
+}
+
+/* DVBSky cards */
+static struct smi_cfg_info dvbsky_s950_cfg = {
+ .type = SMI_DVBSKY_S950,
+ .name = "DVBSky S950 V3",
+ .ts_0 = SMI_TS_NULL,
+ .ts_1 = SMI_TS_DMA_BOTH,
+ .fe_0 = DVBSKY_FE_NULL,
+ .fe_1 = DVBSKY_FE_M88DS3103,
+};
+
+static struct smi_cfg_info dvbsky_s952_cfg = {
+ .type = SMI_DVBSKY_S952,
+ .name = "DVBSky S952 V3",
+ .ts_0 = SMI_TS_DMA_BOTH,
+ .ts_1 = SMI_TS_DMA_BOTH,
+ .fe_0 = DVBSKY_FE_M88RS6000,
+ .fe_1 = DVBSKY_FE_M88RS6000,
+};
+
+static struct smi_cfg_info dvbsky_t9580_cfg = {
+ .type = SMI_DVBSKY_T9580,
+ .name = "DVBSky T9580 V3",
+ .ts_0 = SMI_TS_DMA_BOTH,
+ .ts_1 = SMI_TS_DMA_BOTH,
+ .fe_0 = DVBSKY_FE_SIT2,
+ .fe_1 = DVBSKY_FE_M88DS3103,
+};
+
+/* PCI IDs */
+#define SMI_ID(_subvend, _subdev, _driverdata) { \
+ .vendor = SMI_VID, .device = SMI_PID, \
+ .subvendor = _subvend, .subdevice = _subdev, \
+ .driver_data = (unsigned long)&_driverdata }
+
+static const struct pci_device_id smi_id_table[] = {
+ SMI_ID(0x4254, 0x0550, dvbsky_s950_cfg),
+ SMI_ID(0x4254, 0x0552, dvbsky_s952_cfg),
+ SMI_ID(0x4254, 0x5580, dvbsky_t9580_cfg),
+ {0}
+};
+MODULE_DEVICE_TABLE(pci, smi_id_table);
+
+static struct pci_driver smipcie_driver = {
+ .name = "SMI PCIe driver",
+ .id_table = smi_id_table,
+ .probe = smi_probe,
+ .remove = smi_remove,
+};
+
+module_pci_driver(smipcie_driver);
+
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
+MODULE_DESCRIPTION("SMI PCIe driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/pci/smipcie/smipcie.h b/drivers/media/pci/smipcie/smipcie.h
new file mode 100644
index 0000000..10cdf20
--- /dev/null
+++ b/drivers/media/pci/smipcie/smipcie.h
@@ -0,0 +1,299 @@
+/*
+ * SMI PCIe driver for DVBSky cards.
+ *
+ * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _SMI_PCIE_H_
+#define _SMI_PCIE_H_
+
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+#include <media/rc-core.h>
+
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+/* -------- Register Base -------- */
+#define MSI_CONTROL_REG_BASE 0x0800
+#define SYSTEM_CONTROL_REG_BASE 0x0880
+#define PCIE_EP_DEBUG_REG_BASE 0x08C0
+#define IR_CONTROL_REG_BASE 0x0900
+#define I2C_A_CONTROL_REG_BASE 0x0940
+#define I2C_B_CONTROL_REG_BASE 0x0980
+#define ATV_PORTA_CONTROL_REG_BASE 0x09C0
+#define DTV_PORTA_CONTROL_REG_BASE 0x0A00
+#define AES_PORTA_CONTROL_REG_BASE 0x0A80
+#define DMA_PORTA_CONTROL_REG_BASE 0x0AC0
+#define ATV_PORTB_CONTROL_REG_BASE 0x0B00
+#define DTV_PORTB_CONTROL_REG_BASE 0x0B40
+#define AES_PORTB_CONTROL_REG_BASE 0x0BC0
+#define DMA_PORTB_CONTROL_REG_BASE 0x0C00
+#define UART_A_REGISTER_BASE 0x0C40
+#define UART_B_REGISTER_BASE 0x0C80
+#define GPS_CONTROL_REG_BASE 0x0CC0
+#define DMA_PORTC_CONTROL_REG_BASE 0x0D00
+#define DMA_PORTD_CONTROL_REG_BASE 0x0D00
+#define AES_RANDOM_DATA_BASE 0x0D80
+#define AES_KEY_IN_BASE 0x0D90
+#define RANDOM_DATA_LIB_BASE 0x0E00
+#define IR_DATA_BUFFER_BASE 0x0F00
+#define PORTA_TS_BUFFER_BASE 0x1000
+#define PORTA_I2S_BUFFER_BASE 0x1400
+#define PORTB_TS_BUFFER_BASE 0x1800
+#define PORTB_I2S_BUFFER_BASE 0x1C00
+
+/* -------- MSI control and state register -------- */
+#define MSI_DELAY_TIMER (MSI_CONTROL_REG_BASE + 0x00)
+#define MSI_INT_STATUS (MSI_CONTROL_REG_BASE + 0x08)
+#define MSI_INT_STATUS_CLR (MSI_CONTROL_REG_BASE + 0x0C)
+#define MSI_INT_STATUS_SET (MSI_CONTROL_REG_BASE + 0x10)
+#define MSI_INT_ENA (MSI_CONTROL_REG_BASE + 0x14)
+#define MSI_INT_ENA_CLR (MSI_CONTROL_REG_BASE + 0x18)
+#define MSI_INT_ENA_SET (MSI_CONTROL_REG_BASE + 0x1C)
+#define MSI_SOFT_RESET (MSI_CONTROL_REG_BASE + 0x20)
+#define MSI_CFG_SRC0 (MSI_CONTROL_REG_BASE + 0x24)
+
+/* -------- Hybird Controller System Control register -------- */
+#define MUX_MODE_CTRL (SYSTEM_CONTROL_REG_BASE + 0x00)
+ #define rbPaMSMask 0x07
+ #define rbPaMSDtvNoGpio 0x00 /*[2:0], DTV Simple mode */
+ #define rbPaMSDtv4bitGpio 0x01 /*[2:0], DTV TS2 Serial mode)*/
+ #define rbPaMSDtv7bitGpio 0x02 /*[2:0], DTV TS0 Serial mode*/
+ #define rbPaMS8bitGpio 0x03 /*[2:0], GPIO mode selected;(8bit GPIO)*/
+ #define rbPaMSAtv 0x04 /*[2:0], 3'b1xx: ATV mode select*/
+ #define rbPbMSMask 0x38
+ #define rbPbMSDtvNoGpio 0x00 /*[5:3], DTV Simple mode */
+ #define rbPbMSDtv4bitGpio 0x08 /*[5:3], DTV TS2 Serial mode*/
+ #define rbPbMSDtv7bitGpio 0x10 /*[5:3], DTV TS0 Serial mode*/
+ #define rbPbMS8bitGpio 0x18 /*[5:3], GPIO mode selected;(8bit GPIO)*/
+ #define rbPbMSAtv 0x20 /*[5:3], 3'b1xx: ATV mode select*/
+ #define rbPaAESEN 0x40 /*[6], port A AES enable bit*/
+ #define rbPbAESEN 0x80 /*[7], port B AES enable bit*/
+
+#define INTERNAL_RST (SYSTEM_CONTROL_REG_BASE + 0x04)
+#define PERIPHERAL_CTRL (SYSTEM_CONTROL_REG_BASE + 0x08)
+#define GPIO_0to7_CTRL (SYSTEM_CONTROL_REG_BASE + 0x0C)
+#define GPIO_8to15_CTRL (SYSTEM_CONTROL_REG_BASE + 0x10)
+#define GPIO_16to24_CTRL (SYSTEM_CONTROL_REG_BASE + 0x14)
+#define GPIO_INT_SRC_CFG (SYSTEM_CONTROL_REG_BASE + 0x18)
+#define SYS_BUF_STATUS (SYSTEM_CONTROL_REG_BASE + 0x1C)
+#define PCIE_IP_REG_ACS (SYSTEM_CONTROL_REG_BASE + 0x20)
+#define PCIE_IP_REG_ACS_ADDR (SYSTEM_CONTROL_REG_BASE + 0x24)
+#define PCIE_IP_REG_ACS_DATA (SYSTEM_CONTROL_REG_BASE + 0x28)
+
+/* -------- IR Control register -------- */
+#define IR_Init_Reg (IR_CONTROL_REG_BASE + 0x00)
+#define IR_Idle_Cnt_Low (IR_CONTROL_REG_BASE + 0x04)
+#define IR_Idle_Cnt_High (IR_CONTROL_REG_BASE + 0x05)
+#define IR_Unit_Cnt_Low (IR_CONTROL_REG_BASE + 0x06)
+#define IR_Unit_Cnt_High (IR_CONTROL_REG_BASE + 0x07)
+#define IR_Data_Cnt (IR_CONTROL_REG_BASE + 0x08)
+#define rbIRen 0x80
+#define rbIRhighidle 0x10
+#define rbIRlowidle 0x00
+#define rbIRVld 0x04
+
+/* -------- I2C A control and state register -------- */
+#define I2C_A_CTL_STATUS (I2C_A_CONTROL_REG_BASE + 0x00)
+#define I2C_A_ADDR (I2C_A_CONTROL_REG_BASE + 0x04)
+#define I2C_A_SW_CTL (I2C_A_CONTROL_REG_BASE + 0x08)
+#define I2C_A_TIME_OUT_CNT (I2C_A_CONTROL_REG_BASE + 0x0C)
+#define I2C_A_FIFO_STATUS (I2C_A_CONTROL_REG_BASE + 0x10)
+#define I2C_A_FS_EN (I2C_A_CONTROL_REG_BASE + 0x14)
+#define I2C_A_FIFO_DATA (I2C_A_CONTROL_REG_BASE + 0x20)
+
+/* -------- I2C B control and state register -------- */
+#define I2C_B_CTL_STATUS (I2C_B_CONTROL_REG_BASE + 0x00)
+#define I2C_B_ADDR (I2C_B_CONTROL_REG_BASE + 0x04)
+#define I2C_B_SW_CTL (I2C_B_CONTROL_REG_BASE + 0x08)
+#define I2C_B_TIME_OUT_CNT (I2C_B_CONTROL_REG_BASE + 0x0C)
+#define I2C_B_FIFO_STATUS (I2C_B_CONTROL_REG_BASE + 0x10)
+#define I2C_B_FS_EN (I2C_B_CONTROL_REG_BASE + 0x14)
+#define I2C_B_FIFO_DATA (I2C_B_CONTROL_REG_BASE + 0x20)
+
+#define VIDEO_CTRL_STATUS_A (ATV_PORTA_CONTROL_REG_BASE + 0x04)
+
+/* -------- Digital TV control register, Port A -------- */
+#define MPEG2_CTRL_A (DTV_PORTA_CONTROL_REG_BASE + 0x00)
+#define SERIAL_IN_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x4C)
+#define VLD_CNT_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x60)
+#define ERR_CNT_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x64)
+#define BRD_CNT_ADDR_A (DTV_PORTA_CONTROL_REG_BASE + 0x68)
+
+/* -------- DMA Control Register, Port A -------- */
+#define DMA_PORTA_CHAN0_ADDR_LOW (DMA_PORTA_CONTROL_REG_BASE + 0x00)
+#define DMA_PORTA_CHAN0_ADDR_HI (DMA_PORTA_CONTROL_REG_BASE + 0x04)
+#define DMA_PORTA_CHAN0_TRANS_STATE (DMA_PORTA_CONTROL_REG_BASE + 0x08)
+#define DMA_PORTA_CHAN0_CONTROL (DMA_PORTA_CONTROL_REG_BASE + 0x0C)
+#define DMA_PORTA_CHAN1_ADDR_LOW (DMA_PORTA_CONTROL_REG_BASE + 0x10)
+#define DMA_PORTA_CHAN1_ADDR_HI (DMA_PORTA_CONTROL_REG_BASE + 0x14)
+#define DMA_PORTA_CHAN1_TRANS_STATE (DMA_PORTA_CONTROL_REG_BASE + 0x18)
+#define DMA_PORTA_CHAN1_CONTROL (DMA_PORTA_CONTROL_REG_BASE + 0x1C)
+#define DMA_PORTA_MANAGEMENT (DMA_PORTA_CONTROL_REG_BASE + 0x20)
+#define VIDEO_CTRL_STATUS_B (ATV_PORTB_CONTROL_REG_BASE + 0x04)
+
+/* -------- Digital TV control register, Port B -------- */
+#define MPEG2_CTRL_B (DTV_PORTB_CONTROL_REG_BASE + 0x00)
+#define SERIAL_IN_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x4C)
+#define VLD_CNT_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x60)
+#define ERR_CNT_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x64)
+#define BRD_CNT_ADDR_B (DTV_PORTB_CONTROL_REG_BASE + 0x68)
+
+/* -------- AES control register, Port B -------- */
+#define AES_CTRL_B (AES_PORTB_CONTROL_REG_BASE + 0x00)
+#define AES_KEY_BASE_B (AES_PORTB_CONTROL_REG_BASE + 0x04)
+
+/* -------- DMA Control Register, Port B -------- */
+#define DMA_PORTB_CHAN0_ADDR_LOW (DMA_PORTB_CONTROL_REG_BASE + 0x00)
+#define DMA_PORTB_CHAN0_ADDR_HI (DMA_PORTB_CONTROL_REG_BASE + 0x04)
+#define DMA_PORTB_CHAN0_TRANS_STATE (DMA_PORTB_CONTROL_REG_BASE + 0x08)
+#define DMA_PORTB_CHAN0_CONTROL (DMA_PORTB_CONTROL_REG_BASE + 0x0C)
+#define DMA_PORTB_CHAN1_ADDR_LOW (DMA_PORTB_CONTROL_REG_BASE + 0x10)
+#define DMA_PORTB_CHAN1_ADDR_HI (DMA_PORTB_CONTROL_REG_BASE + 0x14)
+#define DMA_PORTB_CHAN1_TRANS_STATE (DMA_PORTB_CONTROL_REG_BASE + 0x18)
+#define DMA_PORTB_CHAN1_CONTROL (DMA_PORTB_CONTROL_REG_BASE + 0x1C)
+#define DMA_PORTB_MANAGEMENT (DMA_PORTB_CONTROL_REG_BASE + 0x20)
+
+#define DMA_TRANS_UNIT_188 (0x00000007)
+
+/* -------- Macro define of 24 interrupt resource --------*/
+#define DMA_A_CHAN0_DONE_INT (0x00000001)
+#define DMA_A_CHAN1_DONE_INT (0x00000002)
+#define DMA_B_CHAN0_DONE_INT (0x00000004)
+#define DMA_B_CHAN1_DONE_INT (0x00000008)
+#define DMA_C_CHAN0_DONE_INT (0x00000010)
+#define DMA_C_CHAN1_DONE_INT (0x00000020)
+#define DMA_D_CHAN0_DONE_INT (0x00000040)
+#define DMA_D_CHAN1_DONE_INT (0x00000080)
+#define DATA_BUF_OVERFLOW_INT (0x00000100)
+#define UART_0_X_INT (0x00000200)
+#define UART_1_X_INT (0x00000400)
+#define IR_X_INT (0x00000800)
+#define GPIO_0_INT (0x00001000)
+#define GPIO_1_INT (0x00002000)
+#define GPIO_2_INT (0x00004000)
+#define GPIO_3_INT (0x00008000)
+#define ALL_INT (0x0000FFFF)
+
+/* software I2C bit mask */
+#define SW_I2C_MSK_MODE 0x01
+#define SW_I2C_MSK_CLK_OUT 0x02
+#define SW_I2C_MSK_DAT_OUT 0x04
+#define SW_I2C_MSK_CLK_EN 0x08
+#define SW_I2C_MSK_DAT_EN 0x10
+#define SW_I2C_MSK_DAT_IN 0x40
+#define SW_I2C_MSK_CLK_IN 0x80
+
+#define SMI_VID 0x1ADE
+#define SMI_PID 0x3038
+#define SMI_TS_DMA_BUF_SIZE (1024 * 188)
+
+struct smi_cfg_info {
+#define SMI_DVBSKY_S952 0
+#define SMI_DVBSKY_S950 1
+#define SMI_DVBSKY_T9580 2
+#define SMI_DVBSKY_T982 3
+ int type;
+ char *name;
+#define SMI_TS_NULL 0
+#define SMI_TS_DMA_SINGLE 1
+#define SMI_TS_DMA_BOTH 3
+/* SMI_TS_NULL: not use;
+ * SMI_TS_DMA_SINGLE: use DMA 0 only;
+ * SMI_TS_DMA_BOTH:use DMA 0 and 1.*/
+ int ts_0;
+ int ts_1;
+#define DVBSKY_FE_NULL 0
+#define DVBSKY_FE_M88RS6000 1
+#define DVBSKY_FE_M88DS3103 2
+#define DVBSKY_FE_SIT2 3
+ int fe_0;
+ int fe_1;
+};
+
+struct smi_port {
+ struct smi_dev *dev;
+ int idx;
+ int enable;
+ int fe_type;
+ /* regs */
+ u32 DMA_CHAN0_ADDR_LOW;
+ u32 DMA_CHAN0_ADDR_HI;
+ u32 DMA_CHAN0_TRANS_STATE;
+ u32 DMA_CHAN0_CONTROL;
+ u32 DMA_CHAN1_ADDR_LOW;
+ u32 DMA_CHAN1_ADDR_HI;
+ u32 DMA_CHAN1_TRANS_STATE;
+ u32 DMA_CHAN1_CONTROL;
+ u32 DMA_MANAGEMENT;
+ /* dma */
+ dma_addr_t dma_addr[2];
+ u8 *cpu_addr[2];
+ u32 _dmaInterruptCH0;
+ u32 _dmaInterruptCH1;
+ u32 _int_status;
+ struct tasklet_struct tasklet;
+ /* dvb */
+ struct dmx_frontend hw_frontend;
+ struct dmx_frontend mem_frontend;
+ struct dmxdev dmxdev;
+ struct dvb_adapter dvb_adapter;
+ struct dvb_demux demux;
+ struct dvb_net dvbnet;
+ int users;
+ struct dvb_frontend *fe;
+ /* frontend i2c module */
+ struct i2c_client *i2c_client_demod;
+ struct i2c_client *i2c_client_tuner;
+};
+
+struct smi_dev {
+ int nr;
+ struct smi_cfg_info *info;
+
+ /* pcie */
+ struct pci_dev *pci_dev;
+ u32 __iomem *lmmio;
+
+ /* ts port */
+ struct smi_port ts_port[2];
+
+ /* i2c */
+ struct i2c_adapter i2c_bus[2];
+ struct i2c_algo_bit_data i2c_bit[2];
+};
+
+#define smi_read(reg) readl(dev->lmmio + ((reg)>>2))
+#define smi_write(reg, value) writel((value), dev->lmmio + ((reg)>>2))
+
+#define smi_andor(reg, mask, value) \
+ writel((readl(dev->lmmio+((reg)>>2)) & ~(mask)) |\
+ ((value) & (mask)), dev->lmmio+((reg)>>2))
+
+#define smi_set(reg, bit) smi_andor((reg), (bit), (bit))
+#define smi_clear(reg, bit) smi_andor((reg), (bit), 0)
+
+#endif /* #ifndef _SMI_PCIE_H_ */
diff --git a/drivers/media/pci/solo6x10/solo6x10-core.c b/drivers/media/pci/solo6x10/solo6x10-core.c
index 172583d..8cbe6b4 100644
--- a/drivers/media/pci/solo6x10/solo6x10-core.c
+++ b/drivers/media/pci/solo6x10/solo6x10-core.c
@@ -105,11 +105,8 @@ static irqreturn_t solo_isr(int irq, void *data)
if (!status)
return IRQ_NONE;
- if (status & ~solo_dev->irq_mask) {
- solo_reg_write(solo_dev, SOLO_IRQ_STAT,
- status & ~solo_dev->irq_mask);
- status &= solo_dev->irq_mask;
- }
+ /* Acknowledge all interrupts immediately */
+ solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
if (status & SOLO_IRQ_PCI_ERR)
solo_p2m_error_isr(solo_dev);
@@ -132,9 +129,6 @@ static irqreturn_t solo_isr(int irq, void *data)
if (status & SOLO_IRQ_G723)
solo_g723_isr(solo_dev);
- /* Clear all interrupts handled */
- solo_reg_write(solo_dev, SOLO_IRQ_STAT, status);
-
return IRQ_HANDLED;
}
diff --git a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
index 28023f9..6e933d3 100644
--- a/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
+++ b/drivers/media/pci/solo6x10/solo6x10-v4l2-enc.c
@@ -463,7 +463,6 @@ static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
struct solo_dev *solo_dev = solo_enc->solo_dev;
struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
int frame_size;
- int ret;
vb->v4l2_buf.flags |= V4L2_BUF_FLAG_KEYFRAME;
@@ -473,22 +472,10 @@ static int solo_fill_jpeg(struct solo_enc_dev *solo_enc,
frame_size = ALIGN(vop_jpeg_size(vh) + solo_enc->jpeg_len, DMA_ALIGN);
vb2_set_plane_payload(vb, 0, vop_jpeg_size(vh) + solo_enc->jpeg_len);
- /* may discard all previous data in vbuf->sgl */
- if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
- DMA_FROM_DEVICE))
- return -ENOMEM;
- ret = solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
+ return solo_send_desc(solo_enc, solo_enc->jpeg_len, vbuf,
vop_jpeg_offset(vh) - SOLO_JPEG_EXT_ADDR(solo_dev),
frame_size, SOLO_JPEG_EXT_ADDR(solo_dev),
SOLO_JPEG_EXT_SIZE(solo_dev));
- dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
- DMA_FROM_DEVICE);
-
- /* add the header only after dma_unmap_sg() */
- sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
- solo_enc->jpeg_header, solo_enc->jpeg_len);
-
- return ret;
}
static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
@@ -498,7 +485,6 @@ static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
int frame_off, frame_size;
int skip = 0;
- int ret;
if (vb2_plane_size(vb, 0) < vop_mpeg_size(vh))
return -EIO;
@@ -521,21 +507,9 @@ static int solo_fill_mpeg(struct solo_enc_dev *solo_enc,
sizeof(*vh)) % SOLO_MP4E_EXT_SIZE(solo_dev);
frame_size = ALIGN(vop_mpeg_size(vh) + skip, DMA_ALIGN);
- /* may discard all previous data in vbuf->sgl */
- if (!dma_map_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
- DMA_FROM_DEVICE))
- return -ENOMEM;
- ret = solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
+ return solo_send_desc(solo_enc, skip, vbuf, frame_off, frame_size,
SOLO_MP4E_EXT_ADDR(solo_dev),
SOLO_MP4E_EXT_SIZE(solo_dev));
- dma_unmap_sg(&solo_dev->pdev->dev, vbuf->sgl, vbuf->nents,
- DMA_FROM_DEVICE);
-
- /* add the header only after dma_unmap_sg() */
- if (!vop_type(vh))
- sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
- solo_enc->vop, solo_enc->vop_len);
- return ret;
}
static int solo_enc_fillbuf(struct solo_enc_dev *solo_enc,
@@ -703,9 +677,7 @@ static int solo_ring_thread(void *data)
if (timeout == -ERESTARTSYS || kthread_should_stop())
break;
- solo_irq_off(solo_dev, SOLO_IRQ_ENCODER);
solo_handle_ring(solo_dev);
- solo_irq_on(solo_dev, SOLO_IRQ_ENCODER);
try_to_freeze();
}
@@ -720,7 +692,10 @@ static int solo_enc_queue_setup(struct vb2_queue *q,
unsigned int *num_planes, unsigned int sizes[],
void *alloc_ctxs[])
{
+ struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
+
sizes[0] = FRAME_BUF_SIZE;
+ alloc_ctxs[0] = solo_enc->alloc_ctx;
*num_planes = 1;
if (*num_buffers < MIN_VID_BUFFERS)
@@ -770,26 +745,51 @@ static void solo_ring_stop(struct solo_dev *solo_dev)
static int solo_enc_start_streaming(struct vb2_queue *q, unsigned int count)
{
struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
- int ret;
- ret = solo_enc_on(solo_enc);
- if (ret)
- return ret;
- return solo_ring_start(solo_enc->solo_dev);
+ return solo_enc_on(solo_enc);
}
static void solo_enc_stop_streaming(struct vb2_queue *q)
{
struct solo_enc_dev *solo_enc = vb2_get_drv_priv(q);
+ unsigned long flags;
+ spin_lock_irqsave(&solo_enc->av_lock, flags);
solo_enc_off(solo_enc);
- INIT_LIST_HEAD(&solo_enc->vidq_active);
- solo_ring_stop(solo_enc->solo_dev);
+ while (!list_empty(&solo_enc->vidq_active)) {
+ struct solo_vb2_buf *buf = list_entry(
+ solo_enc->vidq_active.next,
+ struct solo_vb2_buf, list);
+
+ list_del(&buf->list);
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
+ }
+ spin_unlock_irqrestore(&solo_enc->av_lock, flags);
+}
+
+static void solo_enc_buf_finish(struct vb2_buffer *vb)
+{
+ struct solo_enc_dev *solo_enc = vb2_get_drv_priv(vb->vb2_queue);
+ struct sg_table *vbuf = vb2_dma_sg_plane_desc(vb, 0);
+
+ switch (solo_enc->fmt) {
+ case V4L2_PIX_FMT_MPEG4:
+ case V4L2_PIX_FMT_H264:
+ if (vb->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME)
+ sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
+ solo_enc->vop, solo_enc->vop_len);
+ break;
+ default: /* V4L2_PIX_FMT_MJPEG */
+ sg_copy_from_buffer(vbuf->sgl, vbuf->nents,
+ solo_enc->jpeg_header, solo_enc->jpeg_len);
+ break;
+ }
}
static struct vb2_ops solo_enc_video_qops = {
.queue_setup = solo_enc_queue_setup,
.buf_queue = solo_enc_buf_queue,
+ .buf_finish = solo_enc_buf_finish,
.start_streaming = solo_enc_start_streaming,
.stop_streaming = solo_enc_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
@@ -1263,6 +1263,11 @@ static struct solo_enc_dev *solo_enc_alloc(struct solo_dev *solo_dev,
return ERR_PTR(-ENOMEM);
hdl = &solo_enc->hdl;
+ solo_enc->alloc_ctx = vb2_dma_sg_init_ctx(&solo_dev->pdev->dev);
+ if (IS_ERR(solo_enc->alloc_ctx)) {
+ ret = PTR_ERR(solo_enc->alloc_ctx);
+ goto hdl_free;
+ }
v4l2_ctrl_handler_init(hdl, 10);
v4l2_ctrl_new_std(hdl, &solo_ctrl_ops,
V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
@@ -1366,6 +1371,7 @@ pci_free:
solo_enc->desc_items, solo_enc->desc_dma);
hdl_free:
v4l2_ctrl_handler_free(hdl);
+ vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx);
kfree(solo_enc);
return ERR_PTR(ret);
}
@@ -1375,8 +1381,12 @@ static void solo_enc_free(struct solo_enc_dev *solo_enc)
if (solo_enc == NULL)
return;
+ pci_free_consistent(solo_enc->solo_dev->pdev,
+ sizeof(struct solo_p2m_desc) * solo_enc->desc_nelts,
+ solo_enc->desc_items, solo_enc->desc_dma);
video_unregister_device(solo_enc->vfd);
v4l2_ctrl_handler_free(&solo_enc->hdl);
+ vb2_dma_sg_cleanup_ctx(solo_enc->alloc_ctx);
kfree(solo_enc);
}
@@ -1419,13 +1429,15 @@ int solo_enc_v4l2_init(struct solo_dev *solo_dev, unsigned nr)
solo_dev->v4l2_enc[0]->vfd->num,
solo_dev->v4l2_enc[solo_dev->nr_chans - 1]->vfd->num);
- return 0;
+ return solo_ring_start(solo_dev);
}
void solo_enc_v4l2_exit(struct solo_dev *solo_dev)
{
int i;
+ solo_ring_stop(solo_dev);
+
for (i = 0; i < solo_dev->nr_chans; i++)
solo_enc_free(solo_dev->v4l2_enc[i]);
diff --git a/drivers/media/pci/solo6x10/solo6x10.h b/drivers/media/pci/solo6x10/solo6x10.h
index 72017b7..bd8edfa 100644
--- a/drivers/media/pci/solo6x10/solo6x10.h
+++ b/drivers/media/pci/solo6x10/solo6x10.h
@@ -180,6 +180,7 @@ struct solo_enc_dev {
u32 sequence;
struct vb2_queue vidq;
struct list_head vidq_active;
+ void *alloc_ctx;
int desc_count;
int desc_nelts;
struct solo_p2m_desc *desc_items;
diff --git a/drivers/media/pci/tw68/tw68-core.c b/drivers/media/pci/tw68/tw68-core.c
index 63f0b64..c135165 100644
--- a/drivers/media/pci/tw68/tw68-core.c
+++ b/drivers/media/pci/tw68/tw68-core.c
@@ -304,13 +304,19 @@ static int tw68_initdev(struct pci_dev *pci_dev,
/* Then do any initialisation wanted before interrupts are on */
tw68_hw_init1(dev);
+ dev->alloc_ctx = vb2_dma_sg_init_ctx(&pci_dev->dev);
+ if (IS_ERR(dev->alloc_ctx)) {
+ err = PTR_ERR(dev->alloc_ctx);
+ goto fail3;
+ }
+
/* get irq */
err = devm_request_irq(&pci_dev->dev, pci_dev->irq, tw68_irq,
IRQF_SHARED, dev->name, dev);
if (err < 0) {
pr_err("%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
- goto fail3;
+ goto fail4;
}
/*
@@ -324,7 +330,7 @@ static int tw68_initdev(struct pci_dev *pci_dev,
if (err < 0) {
pr_err("%s: can't register video device\n",
dev->name);
- goto fail4;
+ goto fail5;
}
tw_setl(TW68_INTMASK, dev->pci_irqmask);
@@ -333,8 +339,10 @@ static int tw68_initdev(struct pci_dev *pci_dev,
return 0;
-fail4:
+fail5:
video_unregister_device(&dev->vdev);
+fail4:
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
fail3:
iounmap(dev->lmmio);
fail2:
@@ -358,6 +366,7 @@ static void tw68_finidev(struct pci_dev *pci_dev)
/* unregister */
video_unregister_device(&dev->vdev);
v4l2_ctrl_handler_free(&dev->hdl);
+ vb2_dma_sg_cleanup_ctx(dev->alloc_ctx);
/* release resources */
iounmap(dev->lmmio);
diff --git a/drivers/media/pci/tw68/tw68-video.c b/drivers/media/pci/tw68/tw68-video.c
index 5c94ac7..8355e55 100644
--- a/drivers/media/pci/tw68/tw68-video.c
+++ b/drivers/media/pci/tw68/tw68-video.c
@@ -384,6 +384,7 @@ static int tw68_queue_setup(struct vb2_queue *q, const struct v4l2_format *fmt,
unsigned tot_bufs = q->num_buffers + *num_buffers;
sizes[0] = (dev->fmt->depth * dev->width * dev->height) >> 3;
+ alloc_ctxs[0] = dev->alloc_ctx;
/*
* We allow create_bufs, but only if the sizeimage is the same as the
* current sizeimage. The tw68_buffer_count calculation becomes quite
@@ -461,17 +462,12 @@ static int tw68_buf_prepare(struct vb2_buffer *vb)
struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
unsigned size, bpl;
- int rc;
size = (dev->width * dev->height * dev->fmt->depth) >> 3;
if (vb2_plane_size(vb, 0) < size)
return -EINVAL;
vb2_set_plane_payload(vb, 0, size);
- rc = dma_map_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
- if (!rc)
- return -EIO;
-
bpl = (dev->width * dev->fmt->depth) >> 3;
switch (dev->field) {
case V4L2_FIELD_TOP:
@@ -505,11 +501,8 @@ static void tw68_buf_finish(struct vb2_buffer *vb)
{
struct vb2_queue *vq = vb->vb2_queue;
struct tw68_dev *dev = vb2_get_drv_priv(vq);
- struct sg_table *dma = vb2_dma_sg_plane_desc(vb, 0);
struct tw68_buf *buf = container_of(vb, struct tw68_buf, vb);
- dma_unmap_sg(&dev->pci->dev, dma->sgl, dma->nents, DMA_FROM_DEVICE);
-
pci_free_consistent(dev->pci, buf->size, buf->cpu, buf->dma);
}
diff --git a/drivers/media/pci/tw68/tw68.h b/drivers/media/pci/tw68/tw68.h
index 2c8abe2..7a7501b 100644
--- a/drivers/media/pci/tw68/tw68.h
+++ b/drivers/media/pci/tw68/tw68.h
@@ -181,6 +181,7 @@ struct tw68_dev {
unsigned field;
struct vb2_queue vidq;
struct list_head active;
+ void *alloc_ctx;
/* various v4l controls */
const struct tw68_tvnorm *tvnorm; /* video */
diff --git a/drivers/media/pci/zoran/zoran_driver.c b/drivers/media/pci/zoran/zoran_driver.c
index 099d5fb..2b25d31 100644
--- a/drivers/media/pci/zoran/zoran_driver.c
+++ b/drivers/media/pci/zoran/zoran_driver.c
@@ -1528,8 +1528,9 @@ static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability
strncpy(cap->driver, "zoran", sizeof(cap->driver)-1);
snprintf(cap->bus_info, sizeof(cap->bus_info), "PCI:%s",
pci_name(zr->pci_dev));
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_VIDEO_OVERLAY;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/pci/zoran/zoran_procfs.c b/drivers/media/pci/zoran/zoran_procfs.c
index f7ceee0..4376527 100644
--- a/drivers/media/pci/zoran/zoran_procfs.c
+++ b/drivers/media/pci/zoran/zoran_procfs.c
@@ -157,8 +157,8 @@ static ssize_t zoran_write(struct file *file, const char __user *buffer,
return -EFAULT;
}
string[count] = 0;
- dprintk(4, KERN_INFO "%s: write_proc: name=%s count=%zu zr=%p\n",
- ZR_DEVNAME(zr), file->f_path.dentry->d_name.name, count, zr);
+ dprintk(4, KERN_INFO "%s: write_proc: name=%pD count=%zu zr=%p\n",
+ ZR_DEVNAME(zr), file, count, zr);
ldelim = " \t\n";
tdelim = "=";
line = strpbrk(sp, ldelim);
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 3aac88f..0c61155 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -267,8 +267,8 @@ if V4L_TEST_DRIVERS
source "drivers/media/platform/vivid/Kconfig"
-config VIDEO_MEM2MEM_TESTDEV
- tristate "Virtual test device for mem2mem framework"
+config VIDEO_VIM2M
+ tristate "Virtual Memory-to-Memory Driver"
depends on VIDEO_DEV && VIDEO_V4L2
select VIDEOBUF2_VMALLOC
select V4L2_MEM2MEM_DEV
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index 579046b..b818afb 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -17,7 +17,7 @@ obj-$(CONFIG_VIDEO_OMAP3) += omap3isp/
obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
obj-$(CONFIG_VIDEO_VIVID) += vivid/
-obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
+obj-$(CONFIG_VIDEO_VIM2M) += vim2m.o
obj-$(CONFIG_VIDEO_TI_VPE) += ti-vpe/
diff --git a/drivers/media/platform/blackfin/bfin_capture.c b/drivers/media/platform/blackfin/bfin_capture.c
index 9b5daa6..3112844 100644
--- a/drivers/media/platform/blackfin/bfin_capture.c
+++ b/drivers/media/platform/blackfin/bfin_capture.c
@@ -49,7 +49,7 @@
struct bcap_format {
char *desc;
u32 pixelformat;
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
int bpp; /* bits per pixel */
int dlen; /* data length for ppi in bits */
};
@@ -116,35 +116,35 @@ static const struct bcap_format bcap_formats[] = {
{
.desc = "YCbCr 4:2:2 Interleaved UYVY",
.pixelformat = V4L2_PIX_FMT_UYVY,
- .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.bpp = 16,
.dlen = 8,
},
{
.desc = "YCbCr 4:2:2 Interleaved YUYV",
.pixelformat = V4L2_PIX_FMT_YUYV,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 16,
.dlen = 8,
},
{
.desc = "YCbCr 4:2:2 Interleaved UYVY",
.pixelformat = V4L2_PIX_FMT_UYVY,
- .mbus_code = V4L2_MBUS_FMT_UYVY8_1X16,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_1X16,
.bpp = 16,
.dlen = 16,
},
{
.desc = "RGB 565",
.pixelformat = V4L2_PIX_FMT_RGB565,
- .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.bpp = 16,
.dlen = 8,
},
{
.desc = "RGB 444",
.pixelformat = V4L2_PIX_FMT_RGB444,
- .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
.bpp = 16,
.dlen = 8,
},
@@ -161,7 +161,7 @@ static struct bcap_buffer *to_bcap_vb(struct vb2_buffer *vb)
static int bcap_init_sensor_formats(struct bcap_device *bcap_dev)
{
- enum v4l2_mbus_pixelcode code;
+ u32 code;
struct bcap_format *sf;
unsigned int num_formats = 0;
int i, j;
@@ -349,18 +349,6 @@ static void bcap_buffer_cleanup(struct vb2_buffer *vb)
spin_unlock_irqrestore(&bcap_dev->lock, flags);
}
-static void bcap_lock(struct vb2_queue *vq)
-{
- struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
- mutex_lock(&bcap_dev->mutex);
-}
-
-static void bcap_unlock(struct vb2_queue *vq)
-{
- struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
- mutex_unlock(&bcap_dev->mutex);
-}
-
static int bcap_start_streaming(struct vb2_queue *vq, unsigned int count)
{
struct bcap_device *bcap_dev = vb2_get_drv_priv(vq);
@@ -457,8 +445,8 @@ static struct vb2_ops bcap_video_qops = {
.buf_prepare = bcap_buffer_prepare,
.buf_cleanup = bcap_buffer_cleanup,
.buf_queue = bcap_buffer_queue,
- .wait_prepare = bcap_unlock,
- .wait_finish = bcap_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.start_streaming = bcap_start_streaming,
.stop_streaming = bcap_stop_streaming,
};
@@ -841,7 +829,8 @@ static int bcap_querycap(struct file *file, void *priv,
{
struct bcap_device *bcap_dev = video_drvdata(file);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
strlcpy(cap->bus_info, "Blackfin Platform", sizeof(cap->bus_info));
strlcpy(cap->card, bcap_dev->cfg->card_name, sizeof(cap->card));
@@ -995,6 +984,7 @@ static int bcap_probe(struct platform_device *pdev)
q->ops = &bcap_video_qops;
q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->lock = &bcap_dev->mutex;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/coda/Makefile b/drivers/media/platform/coda/Makefile
index 3543291..25ce155 100644
--- a/drivers/media/platform/coda/Makefile
+++ b/drivers/media/platform/coda/Makefile
@@ -1,3 +1,3 @@
-coda-objs := coda-common.o coda-bit.o coda-h264.o
+coda-objs := coda-common.o coda-bit.o coda-h264.o coda-jpeg.o
obj-$(CONFIG_VIDEO_CODA) += coda.o
diff --git a/drivers/media/platform/coda/coda-bit.c b/drivers/media/platform/coda/coda-bit.c
index 9b8ea8b..b4029ae 100644
--- a/drivers/media/platform/coda/coda-bit.c
+++ b/drivers/media/platform/coda/coda-bit.c
@@ -217,11 +217,34 @@ static bool coda_bitstream_try_queue(struct coda_ctx *ctx,
void coda_fill_bitstream(struct coda_ctx *ctx)
{
struct vb2_buffer *src_buf;
- struct coda_timestamp *ts;
+ struct coda_buffer_meta *meta;
+ u32 start;
while (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) > 0) {
+ /*
+ * Only queue a single JPEG into the bitstream buffer, except
+ * to increase payload over 512 bytes or if in hold state.
+ */
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
+ (coda_get_bitstream_payload(ctx) >= 512) && !ctx->hold)
+ break;
+
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ /* Drop frames that do not start/end with a SOI/EOI markers */
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG &&
+ !coda_jpeg_check_buffer(ctx, src_buf)) {
+ v4l2_err(&ctx->dev->v4l2_dev,
+ "dropping invalid JPEG frame\n");
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_ERROR);
+ continue;
+ }
+
+ /* Buffer start position */
+ start = ctx->bitstream_fifo.kfifo.in &
+ ctx->bitstream_fifo.kfifo.mask;
+
if (coda_bitstream_try_queue(ctx, src_buf)) {
/*
* Source buffer is queued in the bitstream ringbuffer;
@@ -229,12 +252,16 @@ void coda_fill_bitstream(struct coda_ctx *ctx)
*/
src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
- ts = kmalloc(sizeof(*ts), GFP_KERNEL);
- if (ts) {
- ts->sequence = src_buf->v4l2_buf.sequence;
- ts->timecode = src_buf->v4l2_buf.timecode;
- ts->timestamp = src_buf->v4l2_buf.timestamp;
- list_add_tail(&ts->list, &ctx->timestamp_list);
+ meta = kmalloc(sizeof(*meta), GFP_KERNEL);
+ if (meta) {
+ meta->sequence = src_buf->v4l2_buf.sequence;
+ meta->timecode = src_buf->v4l2_buf.timecode;
+ meta->timestamp = src_buf->v4l2_buf.timestamp;
+ meta->start = start;
+ meta->end = ctx->bitstream_fifo.kfifo.in &
+ ctx->bitstream_fifo.kfifo.mask;
+ list_add_tail(&meta->list,
+ &ctx->buffer_meta_list);
}
v4l2_m2m_buf_done(src_buf, VB2_BUF_STATE_DONE);
@@ -691,6 +718,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
struct vb2_buffer *buf;
int gamma, ret, value;
u32 dst_fourcc;
+ u32 stride;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
@@ -710,6 +738,14 @@ static int coda_start_encoding(struct coda_ctx *ctx)
return -EFAULT;
}
+ if (dst_fourcc == V4L2_PIX_FMT_JPEG) {
+ if (!ctx->params.jpeg_qmat_tab[0])
+ ctx->params.jpeg_qmat_tab[0] = kmalloc(64, GFP_KERNEL);
+ if (!ctx->params.jpeg_qmat_tab[1])
+ ctx->params.jpeg_qmat_tab[1] = kmalloc(64, GFP_KERNEL);
+ coda_set_jpeg_compression_quality(ctx, ctx->params.jpeg_quality);
+ }
+
mutex_lock(&dev->coda_mutex);
coda_write(dev, ctx->parabuf.paddr, CODA_REG_BIT_PARA_BUF_ADDR);
@@ -729,10 +765,10 @@ static int coda_start_encoding(struct coda_ctx *ctx)
break;
}
- value = coda_read(dev, CODA_REG_BIT_FRAME_MEM_CTRL);
- value &= ~(1 << 2 | 0x7 << 9);
- ctx->frame_mem_ctrl = value;
- coda_write(dev, value, CODA_REG_BIT_FRAME_MEM_CTRL);
+ ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE;
+ if (q_data_src->fourcc == V4L2_PIX_FMT_NV12)
+ ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
+ coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
if (dev->devtype->product == CODA_DX6) {
/* Configure the coda */
@@ -741,6 +777,7 @@ static int coda_start_encoding(struct coda_ctx *ctx)
}
/* Could set rotation here if needed */
+ value = 0;
switch (dev->devtype->product) {
case CODA_DX6:
value = (q_data_src->width & CODADX6_PICWIDTH_MASK)
@@ -764,6 +801,8 @@ static int coda_start_encoding(struct coda_ctx *ctx)
<< CODA_PICHEIGHT_OFFSET;
}
coda_write(dev, value, CODA_CMD_ENC_SEQ_SRC_SIZE);
+ if (dst_fourcc == V4L2_PIX_FMT_JPEG)
+ ctx->params.framerate = 0;
coda_write(dev, ctx->params.framerate,
CODA_CMD_ENC_SEQ_SRC_F_RATE);
@@ -797,6 +836,16 @@ static int coda_start_encoding(struct coda_ctx *ctx)
}
coda_write(dev, value, CODA_CMD_ENC_SEQ_264_PARA);
break;
+ case V4L2_PIX_FMT_JPEG:
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_PARA);
+ coda_write(dev, ctx->params.jpeg_restart_interval,
+ CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_EN);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE);
+ coda_write(dev, 0, CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET);
+
+ coda_jpeg_write_tables(ctx);
+ break;
default:
v4l2_err(v4l2_dev,
"dst format (0x%08x) invalid.\n", dst_fourcc);
@@ -804,28 +853,36 @@ static int coda_start_encoding(struct coda_ctx *ctx)
goto out;
}
- switch (ctx->params.slice_mode) {
- case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
- value = 0;
- break;
- case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
- value = (ctx->params.slice_max_mb & CODA_SLICING_SIZE_MASK)
- << CODA_SLICING_SIZE_OFFSET;
- value |= (1 & CODA_SLICING_UNIT_MASK)
- << CODA_SLICING_UNIT_OFFSET;
- value |= 1 & CODA_SLICING_MODE_MASK;
- break;
- case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
- value = (ctx->params.slice_max_bits & CODA_SLICING_SIZE_MASK)
- << CODA_SLICING_SIZE_OFFSET;
- value |= (0 & CODA_SLICING_UNIT_MASK)
- << CODA_SLICING_UNIT_OFFSET;
- value |= 1 & CODA_SLICING_MODE_MASK;
- break;
+ /*
+ * slice mode and GOP size registers are used for thumb size/offset
+ * in JPEG mode
+ */
+ if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
+ switch (ctx->params.slice_mode) {
+ case V4L2_MPEG_VIDEO_MULTI_SLICE_MODE_SINGLE:
+ value = 0;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_MB:
+ value = (ctx->params.slice_max_mb &
+ CODA_SLICING_SIZE_MASK)
+ << CODA_SLICING_SIZE_OFFSET;
+ value |= (1 & CODA_SLICING_UNIT_MASK)
+ << CODA_SLICING_UNIT_OFFSET;
+ value |= 1 & CODA_SLICING_MODE_MASK;
+ break;
+ case V4L2_MPEG_VIDEO_MULTI_SICE_MODE_MAX_BYTES:
+ value = (ctx->params.slice_max_bits &
+ CODA_SLICING_SIZE_MASK)
+ << CODA_SLICING_SIZE_OFFSET;
+ value |= (0 & CODA_SLICING_UNIT_MASK)
+ << CODA_SLICING_UNIT_OFFSET;
+ value |= 1 & CODA_SLICING_MODE_MASK;
+ break;
+ }
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
+ value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
+ coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
}
- coda_write(dev, value, CODA_CMD_ENC_SEQ_SLICE_MODE);
- value = ctx->params.gop_size & CODA_GOP_SIZE_MASK;
- coda_write(dev, value, CODA_CMD_ENC_SEQ_GOP_SIZE);
if (ctx->params.bitrate) {
/* Rate control enabled */
@@ -916,19 +973,24 @@ static int coda_start_encoding(struct coda_ctx *ctx)
goto out;
}
- if (dev->devtype->product == CODA_960)
- ctx->num_internal_frames = 4;
- else
- ctx->num_internal_frames = 2;
- ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
- if (ret < 0) {
- v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
- goto out;
+ if (dst_fourcc != V4L2_PIX_FMT_JPEG) {
+ if (dev->devtype->product == CODA_960)
+ ctx->num_internal_frames = 4;
+ else
+ ctx->num_internal_frames = 2;
+ ret = coda_alloc_framebuffers(ctx, q_data_src, dst_fourcc);
+ if (ret < 0) {
+ v4l2_err(v4l2_dev, "failed to allocate framebuffers\n");
+ goto out;
+ }
+ stride = q_data_src->bytesperline;
+ } else {
+ ctx->num_internal_frames = 0;
+ stride = 0;
}
-
coda_write(dev, ctx->num_internal_frames, CODA_CMD_SET_FRAME_BUF_NUM);
- coda_write(dev, q_data_src->bytesperline,
- CODA_CMD_SET_FRAME_BUF_STRIDE);
+ coda_write(dev, stride, CODA_CMD_SET_FRAME_BUF_STRIDE);
+
if (dev->devtype->product == CODA_7541) {
coda_write(dev, q_data_src->bytesperline,
CODA7_CMD_SET_FRAME_SOURCE_BUF_STRIDE);
@@ -1036,9 +1098,10 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
struct coda_dev *dev = ctx->dev;
int force_ipicture;
int quant_param = 0;
- u32 picture_y, picture_cb, picture_cr;
u32 pic_stream_buffer_addr, pic_stream_buffer_size;
+ u32 rot_mode = 0;
u32 dst_fourcc;
+ u32 reg;
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
@@ -1076,7 +1139,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
ctx->vpu_header_size[0] +
ctx->vpu_header_size[1] +
ctx->vpu_header_size[2];
- pic_stream_buffer_size = CODA_MAX_FRAME_SIZE -
+ pic_stream_buffer_size = q_data_dst->sizeimage -
ctx->vpu_header_size[0] -
ctx->vpu_header_size[1] -
ctx->vpu_header_size[2];
@@ -1090,7 +1153,7 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
} else {
pic_stream_buffer_addr =
vb2_dma_contig_plane_dma_addr(dst_buf, 0);
- pic_stream_buffer_size = CODA_MAX_FRAME_SIZE;
+ pic_stream_buffer_size = q_data_dst->sizeimage;
}
if (src_buf->v4l2_buf.flags & V4L2_BUF_FLAG_KEYFRAME) {
@@ -1102,6 +1165,9 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
case V4L2_PIX_FMT_MPEG4:
quant_param = ctx->params.mpeg4_intra_qp;
break;
+ case V4L2_PIX_FMT_JPEG:
+ quant_param = 30;
+ break;
default:
v4l2_warn(&ctx->dev->v4l2_dev,
"cannot set intra qp, fmt not supported\n");
@@ -1124,42 +1190,22 @@ static int coda_prepare_encode(struct coda_ctx *ctx)
}
/* submit */
- coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
- CODA_CMD_ENC_PIC_ROT_MODE);
+ if (ctx->params.rot_mode)
+ rot_mode = CODA_ROT_MIR_ENABLE | ctx->params.rot_mode;
+ coda_write(dev, rot_mode, CODA_CMD_ENC_PIC_ROT_MODE);
coda_write(dev, quant_param, CODA_CMD_ENC_PIC_QS);
-
- picture_y = vb2_dma_contig_plane_dma_addr(src_buf, 0);
- switch (q_data_src->fourcc) {
- case V4L2_PIX_FMT_YVU420:
- /* Switch Cb and Cr for YVU420 format */
- picture_cr = picture_y + q_data_src->bytesperline *
- q_data_src->height;
- picture_cb = picture_cr + q_data_src->bytesperline / 2 *
- q_data_src->height / 2;
- break;
- case V4L2_PIX_FMT_YUV420:
- default:
- picture_cb = picture_y + q_data_src->bytesperline *
- q_data_src->height;
- picture_cr = picture_cb + q_data_src->bytesperline / 2 *
- q_data_src->height / 2;
- break;
- }
-
if (dev->devtype->product == CODA_960) {
coda_write(dev, 4/*FIXME: 0*/, CODA9_CMD_ENC_PIC_SRC_INDEX);
coda_write(dev, q_data_src->width, CODA9_CMD_ENC_PIC_SRC_STRIDE);
coda_write(dev, 0, CODA9_CMD_ENC_PIC_SUB_FRAME_SYNC);
- coda_write(dev, picture_y, CODA9_CMD_ENC_PIC_SRC_ADDR_Y);
- coda_write(dev, picture_cb, CODA9_CMD_ENC_PIC_SRC_ADDR_CB);
- coda_write(dev, picture_cr, CODA9_CMD_ENC_PIC_SRC_ADDR_CR);
+ reg = CODA9_CMD_ENC_PIC_SRC_ADDR_Y;
} else {
- coda_write(dev, picture_y, CODA_CMD_ENC_PIC_SRC_ADDR_Y);
- coda_write(dev, picture_cb, CODA_CMD_ENC_PIC_SRC_ADDR_CB);
- coda_write(dev, picture_cr, CODA_CMD_ENC_PIC_SRC_ADDR_CR);
+ reg = CODA_CMD_ENC_PIC_SRC_ADDR_Y;
}
+ coda_write_base(ctx, q_data_src, src_buf, reg);
+
coda_write(dev, force_ipicture << 1 & 0x2,
CODA_CMD_ENC_PIC_OPTION);
@@ -1293,7 +1339,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
u32 bitstream_buf, bitstream_size;
struct coda_dev *dev = ctx->dev;
int width, height;
- u32 src_fourcc;
+ u32 src_fourcc, dst_fourcc;
u32 val;
int ret;
@@ -1303,6 +1349,7 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
bitstream_buf = ctx->bitstream.paddr;
bitstream_size = ctx->bitstream.size;
src_fourcc = q_data_src->fourcc;
+ dst_fourcc = q_data_dst->fourcc;
/* Allocate per-instance buffers */
ret = coda_alloc_context_buffers(ctx, q_data_src);
@@ -1314,6 +1361,11 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
/* Update coda bitstream read and write pointers from kfifo */
coda_kfifo_sync_to_device_full(ctx);
+ ctx->frame_mem_ctrl &= ~CODA_FRAME_CHROMA_INTERLEAVE;
+ if (dst_fourcc == V4L2_PIX_FMT_NV12)
+ ctx->frame_mem_ctrl |= CODA_FRAME_CHROMA_INTERLEAVE;
+ coda_write(dev, ctx->frame_mem_ctrl, CODA_REG_BIT_FRAME_MEM_CTRL);
+
ctx->display_idx = -1;
ctx->frm_dis_flg = 0;
coda_write(dev, 0, CODA_REG_BIT_FRM_DIS_FLG(ctx->reg_idx));
@@ -1327,6 +1379,8 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
if ((dev->devtype->product == CODA_7541) ||
(dev->devtype->product == CODA_960))
val |= CODA_REORDER_ENABLE;
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG)
+ val |= CODA_NO_INT_ENABLE;
coda_write(dev, val, CODA_CMD_DEC_SEQ_OPTION);
ctx->params.codec_mode = ctx->codec->mode;
@@ -1442,13 +1496,23 @@ static int __coda_start_decoding(struct coda_ctx *ctx)
}
if (dev->devtype->product == CODA_960) {
- coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
+ int cbb_size, crb_size;
+ coda_write(dev, -1, CODA9_CMD_SET_FRAME_DELAY);
+ /* Luma 2x0 page, 2x6 cache, chroma 2x0 page, 2x4 cache size */
coda_write(dev, 0x20262024, CODA9_CMD_SET_FRAME_CACHE_SIZE);
+
+ if (dst_fourcc == V4L2_PIX_FMT_NV12) {
+ cbb_size = 0;
+ crb_size = 16;
+ } else {
+ cbb_size = 8;
+ crb_size = 8;
+ }
coda_write(dev, 2 << CODA9_CACHE_PAGEMERGE_OFFSET |
32 << CODA9_CACHE_LUMA_BUFFER_SIZE_OFFSET |
- 8 << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
- 8 << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
+ cbb_size << CODA9_CACHE_CB_BUFFER_SIZE_OFFSET |
+ crb_size << CODA9_CACHE_CR_BUFFER_SIZE_OFFSET,
CODA9_CMD_SET_FRAME_CACHE_CONFIG);
}
@@ -1501,20 +1565,11 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
struct vb2_buffer *dst_buf;
struct coda_dev *dev = ctx->dev;
struct coda_q_data *q_data_dst;
- u32 stridey, height;
- u32 picture_y, picture_cb, picture_cr;
+ u32 reg_addr, reg_stride;
dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- if (ctx->params.rot_mode & CODA_ROT_90) {
- stridey = q_data_dst->height;
- height = q_data_dst->width;
- } else {
- stridey = q_data_dst->width;
- height = q_data_dst->height;
- }
-
/* Try to copy source buffer contents into the bitstream ringbuffer */
mutex_lock(&ctx->bitstream_mutex);
coda_fill_bitstream(ctx);
@@ -1545,17 +1600,6 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
if (dev->devtype->product == CODA_960)
coda_set_gdi_regs(ctx);
- /* Set rotator output */
- picture_y = vb2_dma_contig_plane_dma_addr(dst_buf, 0);
- if (q_data_dst->fourcc == V4L2_PIX_FMT_YVU420) {
- /* Switch Cr and Cb for YVU420 format */
- picture_cr = picture_y + stridey * height;
- picture_cb = picture_cr + stridey / 2 * height / 2;
- } else {
- picture_cb = picture_y + stridey * height;
- picture_cr = picture_cb + stridey / 2 * height / 2;
- }
-
if (dev->devtype->product == CODA_960) {
/*
* The CODA960 seems to have an internal list of buffers with
@@ -1565,16 +1609,16 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
*/
coda_write(dev, CODA_MAX_FRAMEBUFFERS + dst_buf->v4l2_buf.index,
CODA9_CMD_DEC_PIC_ROT_INDEX);
- coda_write(dev, picture_y, CODA9_CMD_DEC_PIC_ROT_ADDR_Y);
- coda_write(dev, picture_cb, CODA9_CMD_DEC_PIC_ROT_ADDR_CB);
- coda_write(dev, picture_cr, CODA9_CMD_DEC_PIC_ROT_ADDR_CR);
- coda_write(dev, stridey, CODA9_CMD_DEC_PIC_ROT_STRIDE);
+
+ reg_addr = CODA9_CMD_DEC_PIC_ROT_ADDR_Y;
+ reg_stride = CODA9_CMD_DEC_PIC_ROT_STRIDE;
} else {
- coda_write(dev, picture_y, CODA_CMD_DEC_PIC_ROT_ADDR_Y);
- coda_write(dev, picture_cb, CODA_CMD_DEC_PIC_ROT_ADDR_CB);
- coda_write(dev, picture_cr, CODA_CMD_DEC_PIC_ROT_ADDR_CR);
- coda_write(dev, stridey, CODA_CMD_DEC_PIC_ROT_STRIDE);
+ reg_addr = CODA_CMD_DEC_PIC_ROT_ADDR_Y;
+ reg_stride = CODA_CMD_DEC_PIC_ROT_STRIDE;
}
+ coda_write_base(ctx, q_data_dst, dst_buf, reg_addr);
+ coda_write(dev, q_data_dst->bytesperline, reg_stride);
+
coda_write(dev, CODA_ROT_MIR_ENABLE | ctx->params.rot_mode,
CODA_CMD_DEC_PIC_ROT_MODE);
@@ -1599,6 +1643,26 @@ static int coda_prepare_decode(struct coda_ctx *ctx)
coda_write(dev, ctx->iram_info.axi_sram_use,
CODA7_REG_BIT_AXI_SRAM_USE);
+ if (ctx->codec->src_fourcc == V4L2_PIX_FMT_JPEG) {
+ struct coda_buffer_meta *meta;
+
+ /* If this is the last buffer in the bitstream, add padding */
+ meta = list_first_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+ if (meta->end == (ctx->bitstream_fifo.kfifo.in &
+ ctx->bitstream_fifo.kfifo.mask)) {
+ static unsigned char buf[512];
+ unsigned int pad;
+
+ /* Pad to multiple of 256 and then add 256 more */
+ pad = ((0 - meta->end) & 0xff) + 256;
+
+ memset(buf, 0xff, sizeof(buf));
+
+ kfifo_in(&ctx->bitstream_fifo, buf, pad);
+ }
+ }
+
coda_kfifo_sync_to_device_full(ctx);
coda_command_async(ctx, CODA_COMMAND_PIC_RUN);
@@ -1612,7 +1676,8 @@ static void coda_finish_decode(struct coda_ctx *ctx)
struct coda_q_data *q_data_src;
struct coda_q_data *q_data_dst;
struct vb2_buffer *dst_buf;
- struct coda_timestamp *ts;
+ struct coda_buffer_meta *meta;
+ unsigned long payload;
int width, height;
int decoded_idx;
int display_idx;
@@ -1739,23 +1804,23 @@ static void coda_finish_decode(struct coda_ctx *ctx)
val = coda_read(dev, CODA_RET_DEC_PIC_FRAME_NUM) - 1;
val -= ctx->sequence_offset;
mutex_lock(&ctx->bitstream_mutex);
- if (!list_empty(&ctx->timestamp_list)) {
- ts = list_first_entry(&ctx->timestamp_list,
- struct coda_timestamp, list);
- list_del(&ts->list);
- if (val != (ts->sequence & 0xffff)) {
+ if (!list_empty(&ctx->buffer_meta_list)) {
+ meta = list_first_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+ list_del(&meta->list);
+ if (val != (meta->sequence & 0xffff)) {
v4l2_err(&dev->v4l2_dev,
"sequence number mismatch (%d(%d) != %d)\n",
val, ctx->sequence_offset,
- ts->sequence);
+ meta->sequence);
}
- ctx->frame_timestamps[decoded_idx] = *ts;
- kfree(ts);
+ ctx->frame_metas[decoded_idx] = *meta;
+ kfree(meta);
} else {
v4l2_err(&dev->v4l2_dev, "empty timestamp list!\n");
- memset(&ctx->frame_timestamps[decoded_idx], 0,
- sizeof(struct coda_timestamp));
- ctx->frame_timestamps[decoded_idx].sequence = val;
+ memset(&ctx->frame_metas[decoded_idx], 0,
+ sizeof(struct coda_buffer_meta));
+ ctx->frame_metas[decoded_idx].sequence = val;
}
mutex_unlock(&ctx->bitstream_mutex);
@@ -1794,11 +1859,22 @@ static void coda_finish_decode(struct coda_ctx *ctx)
V4L2_BUF_FLAG_PFRAME |
V4L2_BUF_FLAG_BFRAME);
dst_buf->v4l2_buf.flags |= ctx->frame_types[ctx->display_idx];
- ts = &ctx->frame_timestamps[ctx->display_idx];
- dst_buf->v4l2_buf.timecode = ts->timecode;
- dst_buf->v4l2_buf.timestamp = ts->timestamp;
-
- vb2_set_plane_payload(dst_buf, 0, width * height * 3 / 2);
+ meta = &ctx->frame_metas[ctx->display_idx];
+ dst_buf->v4l2_buf.timecode = meta->timecode;
+ dst_buf->v4l2_buf.timestamp = meta->timestamp;
+
+ switch (q_data_dst->fourcc) {
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_NV12:
+ default:
+ payload = width * height * 3 / 2;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ payload = width * height * 2;
+ break;
+ }
+ vb2_set_plane_payload(dst_buf, 0, payload);
v4l2_m2m_buf_done(dst_buf, ctx->frame_errors[display_idx] ?
VB2_BUF_STATE_ERROR : VB2_BUF_STATE_DONE);
diff --git a/drivers/media/platform/coda/coda-common.c b/drivers/media/platform/coda/coda-common.c
index ced4760..90b7791 100644
--- a/drivers/media/platform/coda/coda-common.c
+++ b/drivers/media/platform/coda/coda-common.c
@@ -43,6 +43,7 @@
#define CODA_NAME "coda"
#define CODADX6_MAX_INSTANCES 4
+#define CODA_MAX_FORMATS 4
#define CODA_PARA_BUF_SIZE (10 * 1024)
#define CODA_ISRAM_SIZE (2048 * 2)
@@ -82,6 +83,34 @@ unsigned int coda_read(struct coda_dev *dev, u32 reg)
return data;
}
+void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
+ struct vb2_buffer *buf, unsigned int reg_y)
+{
+ u32 base_y = vb2_dma_contig_plane_dma_addr(buf, 0);
+ u32 base_cb, base_cr;
+
+ switch (q_data->fourcc) {
+ case V4L2_PIX_FMT_YVU420:
+ /* Switch Cb and Cr for YVU420 format */
+ base_cr = base_y + q_data->bytesperline * q_data->height;
+ base_cb = base_cr + q_data->bytesperline * q_data->height / 4;
+ break;
+ case V4L2_PIX_FMT_YUV420:
+ case V4L2_PIX_FMT_NV12:
+ default:
+ base_cb = base_y + q_data->bytesperline * q_data->height;
+ base_cr = base_cb + q_data->bytesperline * q_data->height / 4;
+ break;
+ case V4L2_PIX_FMT_YUV422P:
+ base_cb = base_y + q_data->bytesperline * q_data->height;
+ base_cr = base_cb + q_data->bytesperline * q_data->height / 2;
+ }
+
+ coda_write(ctx->dev, base_y, reg_y);
+ coda_write(ctx->dev, base_cb, reg_y + 4);
+ coda_write(ctx->dev, base_cr, reg_y + 8);
+}
+
/*
* Array of all formats supported by any version of Coda:
*/
@@ -95,6 +124,14 @@ static const struct coda_fmt coda_formats[] = {
.fourcc = V4L2_PIX_FMT_YVU420,
},
{
+ .name = "YUV 4:2:0 Partial interleaved Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ },
+ {
+ .name = "YUV 4:2:2 Planar, YCbCr",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ },
+ {
.name = "H264 Encoded Stream",
.fourcc = V4L2_PIX_FMT_H264,
},
@@ -102,6 +139,10 @@ static const struct coda_fmt coda_formats[] = {
.name = "MPEG4 Encoded Stream",
.fourcc = V4L2_PIX_FMT_MPEG4,
},
+ {
+ .name = "JPEG Encoded Images",
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ },
};
#define CODA_CODEC(mode, src_fourcc, dst_fourcc, max_w, max_h) \
@@ -122,8 +163,10 @@ static const struct coda_codec codadx6_codecs[] = {
static const struct coda_codec coda7_codecs[] = {
CODA_CODEC(CODA7_MODE_ENCODE_H264, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_H264, 1280, 720),
CODA_CODEC(CODA7_MODE_ENCODE_MP4, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_MPEG4, 1280, 720),
+ CODA_CODEC(CODA7_MODE_ENCODE_MJPG, V4L2_PIX_FMT_YUV420, V4L2_PIX_FMT_JPEG, 8192, 8192),
CODA_CODEC(CODA7_MODE_DECODE_H264, V4L2_PIX_FMT_H264, V4L2_PIX_FMT_YUV420, 1920, 1088),
CODA_CODEC(CODA7_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
+ CODA_CODEC(CODA7_MODE_DECODE_MJPG, V4L2_PIX_FMT_JPEG, V4L2_PIX_FMT_YUV420, 8192, 8192),
};
static const struct coda_codec coda9_codecs[] = {
@@ -133,17 +176,115 @@ static const struct coda_codec coda9_codecs[] = {
CODA_CODEC(CODA9_MODE_DECODE_MP4, V4L2_PIX_FMT_MPEG4, V4L2_PIX_FMT_YUV420, 1920, 1088),
};
+struct coda_video_device {
+ const char *name;
+ enum coda_inst_type type;
+ const struct coda_context_ops *ops;
+ u32 src_formats[CODA_MAX_FORMATS];
+ u32 dst_formats[CODA_MAX_FORMATS];
+};
+
+static const struct coda_video_device coda_bit_encoder = {
+ .name = "coda-encoder",
+ .type = CODA_INST_ENCODER,
+ .ops = &coda_bit_encode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_MPEG4,
+ },
+};
+
+static const struct coda_video_device coda_bit_jpeg_encoder = {
+ .name = "coda-jpeg-encoder",
+ .type = CODA_INST_ENCODER,
+ .ops = &coda_bit_encode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV422P,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_JPEG,
+ },
+};
+
+static const struct coda_video_device coda_bit_decoder = {
+ .name = "coda-decoder",
+ .type = CODA_INST_DECODER,
+ .ops = &coda_bit_decode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_H264,
+ V4L2_PIX_FMT_MPEG4,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ },
+};
+
+static const struct coda_video_device coda_bit_jpeg_decoder = {
+ .name = "coda-jpeg-decoder",
+ .type = CODA_INST_DECODER,
+ .ops = &coda_bit_decode_ops,
+ .src_formats = {
+ V4L2_PIX_FMT_JPEG,
+ },
+ .dst_formats = {
+ V4L2_PIX_FMT_YUV420,
+ V4L2_PIX_FMT_YVU420,
+ V4L2_PIX_FMT_NV12,
+ V4L2_PIX_FMT_YUV422P,
+ },
+};
+
+static const struct coda_video_device *codadx6_video_devices[] = {
+ &coda_bit_encoder,
+};
+
+static const struct coda_video_device *coda7_video_devices[] = {
+ &coda_bit_jpeg_encoder,
+ &coda_bit_jpeg_decoder,
+ &coda_bit_encoder,
+ &coda_bit_decoder,
+};
+
+static const struct coda_video_device *coda9_video_devices[] = {
+ &coda_bit_encoder,
+ &coda_bit_decoder,
+};
+
static bool coda_format_is_yuv(u32 fourcc)
{
switch (fourcc) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
+ case V4L2_PIX_FMT_NV12:
+ case V4L2_PIX_FMT_YUV422P:
return true;
default:
return false;
}
}
+static const char *coda_format_name(u32 fourcc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(coda_formats); i++) {
+ if (coda_formats[i].fourcc == fourcc)
+ return coda_formats[i].name;
+ }
+
+ return NULL;
+}
+
/*
* Normalize all supported YUV 4:2:0 formats to the value used in the codec
* tables.
@@ -202,6 +343,17 @@ static void coda_get_max_dimensions(struct coda_dev *dev,
*max_h = h;
}
+const struct coda_video_device *to_coda_video_device(struct video_device *vdev)
+{
+ struct coda_dev *dev = video_get_drvdata(vdev);
+ unsigned int i = vdev - dev->vfd;
+
+ if (i >= dev->devtype->num_vdevs)
+ return NULL;
+
+ return dev->devtype->vdevs[i];
+}
+
const char *coda_product_name(int product)
{
static char buf[9];
@@ -240,58 +392,28 @@ static int coda_querycap(struct file *file, void *priv,
static int coda_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct coda_ctx *ctx = fh_to_ctx(priv);
- const struct coda_codec *codecs = ctx->dev->devtype->codecs;
- const struct coda_fmt *formats = coda_formats;
- const struct coda_fmt *fmt;
- int num_codecs = ctx->dev->devtype->num_codecs;
- int num_formats = ARRAY_SIZE(coda_formats);
- int i, k, num = 0;
- bool yuv;
-
- if (ctx->inst_type == CODA_INST_ENCODER)
- yuv = (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ struct video_device *vdev = video_devdata(file);
+ const struct coda_video_device *cvd = to_coda_video_device(vdev);
+ const u32 *formats;
+ const char *name;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ formats = cvd->src_formats;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ formats = cvd->dst_formats;
else
- yuv = (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE);
-
- for (i = 0; i < num_formats; i++) {
- /* Skip either raw or compressed formats */
- if (yuv != coda_format_is_yuv(formats[i].fourcc))
- continue;
- /* All uncompressed formats are always supported */
- if (yuv) {
- if (num == f->index)
- break;
- ++num;
- continue;
- }
- /* Compressed formats may be supported, check the codec list */
- for (k = 0; k < num_codecs; k++) {
- if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- formats[i].fourcc == codecs[k].dst_fourcc)
- break;
- if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
- formats[i].fourcc == codecs[k].src_fourcc)
- break;
- }
- if (k < num_codecs) {
- if (num == f->index)
- break;
- ++num;
- }
- }
+ return -EINVAL;
- if (i < num_formats) {
- fmt = &formats[i];
- strlcpy(f->description, fmt->name, sizeof(f->description));
- f->pixelformat = fmt->fourcc;
- if (!yuv)
- f->flags |= V4L2_FMT_FLAG_COMPRESSED;
- return 0;
- }
+ if (f->index >= CODA_MAX_FORMATS || formats[f->index] == 0)
+ return -EINVAL;
+
+ name = coda_format_name(formats[f->index]);
+ strlcpy(f->description, name, sizeof(f->description));
+ f->pixelformat = formats[f->index];
+ if (!coda_format_is_yuv(formats[f->index]))
+ f->flags |= V4L2_FMT_FLAG_COMPRESSED;
- /* Format not found */
- return -EINVAL;
+ return 0;
}
static int coda_g_fmt(struct file *file, void *priv,
@@ -311,7 +433,37 @@ static int coda_g_fmt(struct file *file, void *priv,
f->fmt.pix.bytesperline = q_data->bytesperline;
f->fmt.pix.sizeimage = q_data->sizeimage;
- f->fmt.pix.colorspace = ctx->colorspace;
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ f->fmt.pix.colorspace = ctx->colorspace;
+
+ return 0;
+}
+
+static int coda_try_pixelformat(struct coda_ctx *ctx, struct v4l2_format *f)
+{
+ struct coda_q_data *q_data;
+ const u32 *formats;
+ int i;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ formats = ctx->cvd->src_formats;
+ else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ formats = ctx->cvd->dst_formats;
+ else
+ return -EINVAL;
+
+ for (i = 0; i < CODA_MAX_FORMATS; i++) {
+ if (formats[i] == f->fmt.pix.pixelformat) {
+ f->fmt.pix.pixelformat = formats[i];
+ return 0;
+ }
+ }
+
+ /* Fall back to currently set pixelformat */
+ q_data = get_q_data(ctx, f->type);
+ f->fmt.pix.pixelformat = q_data->fourcc;
return 0;
}
@@ -320,7 +472,6 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
struct v4l2_format *f)
{
struct coda_dev *dev = ctx->dev;
- struct coda_q_data *q_data;
unsigned int max_w, max_h;
enum v4l2_field field;
@@ -342,30 +493,35 @@ static int coda_try_fmt(struct coda_ctx *ctx, const struct coda_codec *codec,
switch (f->fmt.pix.pixelformat) {
case V4L2_PIX_FMT_YUV420:
case V4L2_PIX_FMT_YVU420:
- case V4L2_PIX_FMT_H264:
- case V4L2_PIX_FMT_MPEG4:
- case V4L2_PIX_FMT_JPEG:
- break;
- default:
- q_data = get_q_data(ctx, f->type);
- if (!q_data)
- return -EINVAL;
- f->fmt.pix.pixelformat = q_data->fourcc;
- }
-
- switch (f->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_YUV420:
- case V4L2_PIX_FMT_YVU420:
- /* Frame stride must be multiple of 8, but 16 for h.264 */
+ case V4L2_PIX_FMT_NV12:
+ /*
+ * Frame stride must be at least multiple of 8,
+ * but multiple of 16 for h.264 or JPEG 4:2:x
+ */
f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
f->fmt.pix.height * 3 / 2;
break;
+ case V4L2_PIX_FMT_YUV422P:
+ f->fmt.pix.bytesperline = round_up(f->fmt.pix.width, 16);
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline *
+ f->fmt.pix.height * 2;
+ break;
+ case V4L2_PIX_FMT_JPEG:
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ /* fallthrough */
case V4L2_PIX_FMT_H264:
case V4L2_PIX_FMT_MPEG4:
- case V4L2_PIX_FMT_JPEG:
f->fmt.pix.bytesperline = 0;
- f->fmt.pix.sizeimage = CODA_MAX_FRAME_SIZE;
+ /*
+ * This is a rough estimate for sensible compressed buffer
+ * sizes (between 1 and 16 bits per pixel). This could be
+ * improved by better format specific worst case estimates.
+ */
+ f->fmt.pix.sizeimage = round_up(clamp(f->fmt.pix.sizeimage,
+ f->fmt.pix.width * f->fmt.pix.height / 8,
+ f->fmt.pix.width * f->fmt.pix.height * 2),
+ PAGE_SIZE);
break;
default:
BUG();
@@ -378,34 +534,35 @@ static int coda_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- const struct coda_codec *codec = NULL;
+ const struct coda_q_data *q_data_src;
+ const struct coda_codec *codec;
struct vb2_queue *src_vq;
int ret;
+ ret = coda_try_pixelformat(ctx, f);
+ if (ret < 0)
+ return ret;
+
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+
/*
- * If the source format is already fixed, try to find a codec that
- * converts to the given destination format
+ * If the source format is already fixed, only allow the same output
+ * resolution
*/
src_vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (vb2_is_streaming(src_vq)) {
- struct coda_q_data *q_data_src;
-
- q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
- codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
- f->fmt.pix.pixelformat);
- if (!codec)
- return -EINVAL;
-
f->fmt.pix.width = q_data_src->width;
f->fmt.pix.height = q_data_src->height;
- } else {
- /* Otherwise determine codec by encoded format, if possible */
- codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_YUV420,
- f->fmt.pix.pixelformat);
}
f->fmt.pix.colorspace = ctx->colorspace;
+ q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
+ codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
+ f->fmt.pix.pixelformat);
+ if (!codec)
+ return -EINVAL;
+
ret = coda_try_fmt(ctx, codec, f);
if (ret < 0)
return ret;
@@ -426,21 +583,24 @@ static int coda_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
struct coda_ctx *ctx = fh_to_ctx(priv);
- const struct coda_codec *codec = NULL;
+ struct coda_dev *dev = ctx->dev;
+ const struct coda_q_data *q_data_dst;
+ const struct coda_codec *codec;
+ int ret;
- /* Determine codec by encoded format, returns NULL if raw or invalid */
- if (ctx->inst_type == CODA_INST_DECODER) {
- codec = coda_find_codec(ctx->dev, f->fmt.pix.pixelformat,
- V4L2_PIX_FMT_YUV420);
- if (!codec)
- codec = coda_find_codec(ctx->dev, V4L2_PIX_FMT_H264,
- V4L2_PIX_FMT_YUV420);
- if (!codec)
- return -EINVAL;
+ ret = coda_try_pixelformat(ctx, f);
+ if (ret < 0)
+ return ret;
+
+ if (!f->fmt.pix.colorspace) {
+ if (f->fmt.pix.pixelformat == V4L2_PIX_FMT_JPEG)
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_JPEG;
+ else
+ f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
}
- if (!f->fmt.pix.colorspace)
- f->fmt.pix.colorspace = V4L2_COLORSPACE_REC709;
+ q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
+ codec = coda_find_codec(dev, f->fmt.pix.pixelformat, q_data_dst->fourcc);
return coda_try_fmt(ctx, codec, f);
}
@@ -781,6 +941,7 @@ static int coda_job_ready(void *m2m_priv)
if (ctx->hold ||
((ctx->inst_type == CODA_INST_DECODER) &&
+ !v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) &&
(coda_get_bitstream_payload(ctx) < 512) &&
!(ctx->bit_stream_param & CODA_BIT_STREAM_END_FLAG))) {
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
@@ -862,25 +1023,17 @@ static void coda_set_tiled_map_type(struct coda_ctx *ctx, int tiled_map_type)
static void set_default_params(struct coda_ctx *ctx)
{
- u32 src_fourcc, dst_fourcc;
- int max_w;
- int max_h;
+ unsigned int max_w, max_h, size;
- if (ctx->inst_type == CODA_INST_ENCODER) {
- src_fourcc = V4L2_PIX_FMT_YUV420;
- dst_fourcc = V4L2_PIX_FMT_H264;
- } else {
- src_fourcc = V4L2_PIX_FMT_H264;
- dst_fourcc = V4L2_PIX_FMT_YUV420;
- }
- ctx->codec = coda_find_codec(ctx->dev, src_fourcc, dst_fourcc);
- max_w = ctx->codec->max_w;
- max_h = ctx->codec->max_h;
+ ctx->codec = coda_find_codec(ctx->dev, ctx->cvd->src_formats[0],
+ ctx->cvd->dst_formats[0]);
+ max_w = min(ctx->codec->max_w, 1920U);
+ max_h = min(ctx->codec->max_h, 1088U);
+ size = max_w * max_h * 3 / 2;
ctx->params.codec_mode = ctx->codec->mode;
ctx->colorspace = V4L2_COLORSPACE_REC709;
ctx->params.framerate = 30;
- ctx->aborting = 0;
/* Default formats for output and input queues */
ctx->q_data[V4L2_M2M_SRC].fourcc = ctx->codec->src_fourcc;
@@ -891,14 +1044,14 @@ static void set_default_params(struct coda_ctx *ctx)
ctx->q_data[V4L2_M2M_DST].height = max_h;
if (ctx->codec->src_fourcc == V4L2_PIX_FMT_YUV420) {
ctx->q_data[V4L2_M2M_SRC].bytesperline = max_w;
- ctx->q_data[V4L2_M2M_SRC].sizeimage = (max_w * max_h * 3) / 2;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = size;
ctx->q_data[V4L2_M2M_DST].bytesperline = 0;
- ctx->q_data[V4L2_M2M_DST].sizeimage = CODA_MAX_FRAME_SIZE;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = round_up(size, PAGE_SIZE);
} else {
ctx->q_data[V4L2_M2M_SRC].bytesperline = 0;
- ctx->q_data[V4L2_M2M_SRC].sizeimage = CODA_MAX_FRAME_SIZE;
+ ctx->q_data[V4L2_M2M_SRC].sizeimage = round_up(size, PAGE_SIZE);
ctx->q_data[V4L2_M2M_DST].bytesperline = max_w;
- ctx->q_data[V4L2_M2M_DST].sizeimage = (max_w * max_h * 3) / 2;
+ ctx->q_data[V4L2_M2M_DST].sizeimage = size;
}
ctx->q_data[V4L2_M2M_SRC].rect.width = max_w;
ctx->q_data[V4L2_M2M_SRC].rect.height = max_h;
@@ -964,7 +1117,7 @@ static void coda_buf_queue(struct vb2_buffer *vb)
* In the decoder case, immediately try to copy the buffer into the
* bitstream ringbuffer and mark it as ready to be dequeued.
*/
- if (q_data->fourcc == V4L2_PIX_FMT_H264 &&
+ if (ctx->inst_type == CODA_INST_DECODER &&
vb->vb2_queue->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
/*
* For backwards compatibility, queuing an empty buffer marks
@@ -1027,12 +1180,13 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
struct v4l2_device *v4l2_dev = &ctx->dev->v4l2_dev;
struct coda_q_data *q_data_src, *q_data_dst;
struct vb2_buffer *buf;
- u32 dst_fourcc;
int ret = 0;
q_data_src = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_OUTPUT);
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
- if (q_data_src->fourcc == V4L2_PIX_FMT_H264) {
+ if (q_data_src->fourcc == V4L2_PIX_FMT_H264 ||
+ (q_data_src->fourcc == V4L2_PIX_FMT_JPEG &&
+ ctx->dev->devtype->product == CODA_7541)) {
/* copy the buffers that where queued before streamon */
mutex_lock(&ctx->bitstream_mutex);
coda_fill_bitstream(ctx);
@@ -1063,13 +1217,12 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
if (!(ctx->streamon_out & ctx->streamon_cap))
return 0;
- /* Allow decoder device_run with no new buffers queued */
+ /* Allow BIT decoder device_run with no new buffers queued */
if (ctx->inst_type == CODA_INST_DECODER)
v4l2_m2m_set_src_buffered(ctx->fh.m2m_ctx, true);
ctx->gopcounter = ctx->params.gop_size - 1;
q_data_dst = get_q_data(ctx, V4L2_BUF_TYPE_VIDEO_CAPTURE);
- dst_fourcc = q_data_dst->fourcc;
ctx->codec = coda_find_codec(ctx->dev, q_data_src->fourcc,
q_data_dst->fourcc);
@@ -1079,6 +1232,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
goto err;
}
+ if (q_data_dst->fourcc == V4L2_PIX_FMT_JPEG)
+ ctx->params.gop_size = 1;
+ ctx->gopcounter = ctx->params.gop_size - 1;
+
ret = ctx->ops->start_streaming(ctx);
if (ctx->inst_type == CODA_INST_DECODER) {
if (ret == -EAGAIN)
@@ -1093,10 +1250,10 @@ static int coda_start_streaming(struct vb2_queue *q, unsigned int count)
err:
if (q->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
while ((buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx)))
- v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
} else {
while ((buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx)))
- v4l2_m2m_buf_done(buf, VB2_BUF_STATE_DEQUEUED);
+ v4l2_m2m_buf_done(buf, VB2_BUF_STATE_QUEUED);
}
return ret;
}
@@ -1131,19 +1288,20 @@ static void coda_stop_streaming(struct vb2_queue *q)
}
if (!ctx->streamon_out && !ctx->streamon_cap) {
- struct coda_timestamp *ts;
+ struct coda_buffer_meta *meta;
mutex_lock(&ctx->bitstream_mutex);
- while (!list_empty(&ctx->timestamp_list)) {
- ts = list_first_entry(&ctx->timestamp_list,
- struct coda_timestamp, list);
- list_del(&ts->list);
- kfree(ts);
+ while (!list_empty(&ctx->buffer_meta_list)) {
+ meta = list_first_entry(&ctx->buffer_meta_list,
+ struct coda_buffer_meta, list);
+ list_del(&meta->list);
+ kfree(meta);
}
mutex_unlock(&ctx->bitstream_mutex);
kfifo_init(&ctx->bitstream_fifo,
ctx->bitstream.vaddr, ctx->bitstream.size);
ctx->runcounter = 0;
+ ctx->aborting = 0;
}
}
@@ -1226,6 +1384,12 @@ static int coda_s_ctrl(struct v4l2_ctrl *ctrl)
case V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB:
ctx->params.intra_refresh = ctrl->val;
break;
+ case V4L2_CID_JPEG_COMPRESSION_QUALITY:
+ coda_set_jpeg_compression_quality(ctx, ctrl->val);
+ break;
+ case V4L2_CID_JPEG_RESTART_INTERVAL:
+ ctx->params.jpeg_restart_interval = ctrl->val;
+ break;
default:
v4l2_dbg(1, coda_debug, &ctx->dev->v4l2_dev,
"Invalid control, id=%d, val=%d\n",
@@ -1240,14 +1404,8 @@ static const struct v4l2_ctrl_ops coda_ctrl_ops = {
.s_ctrl = coda_s_ctrl,
};
-static int coda_ctrls_setup(struct coda_ctx *ctx)
+static void coda_encode_ctrls(struct coda_ctx *ctx)
{
- v4l2_ctrl_handler_init(&ctx->ctrls, 9);
-
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
- V4L2_CID_VFLIP, 0, 1, 1, 0);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_BITRATE, 0, 32767000, 1, 0);
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
@@ -1291,6 +1449,30 @@ static int coda_ctrls_setup(struct coda_ctx *ctx)
v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
V4L2_CID_MPEG_VIDEO_CYCLIC_INTRA_REFRESH_MB, 0,
1920 * 1088 / 256, 1, 0);
+}
+
+static void coda_jpeg_encode_ctrls(struct coda_ctx *ctx)
+{
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_JPEG_COMPRESSION_QUALITY, 5, 100, 1, 50);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_JPEG_RESTART_INTERVAL, 0, 100, 1, 0);
+}
+
+static int coda_ctrls_setup(struct coda_ctx *ctx)
+{
+ v4l2_ctrl_handler_init(&ctx->ctrls, 2);
+
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&ctx->ctrls, &coda_ctrl_ops,
+ V4L2_CID_VFLIP, 0, 1, 1, 0);
+ if (ctx->inst_type == CODA_INST_ENCODER) {
+ if (ctx->cvd->dst_formats[0] == V4L2_PIX_FMT_JPEG)
+ coda_jpeg_encode_ctrls(ctx);
+ else
+ coda_encode_ctrls(ctx);
+ }
if (ctx->ctrls.error) {
v4l2_err(&ctx->dev->v4l2_dev,
@@ -1364,10 +1546,14 @@ static int coda_next_free_instance(struct coda_dev *dev)
return idx;
}
-static int coda_open(struct file *file, enum coda_inst_type inst_type,
- const struct coda_context_ops *ctx_ops)
+/*
+ * File operations
+ */
+
+static int coda_open(struct file *file)
{
- struct coda_dev *dev = video_drvdata(file);
+ struct video_device *vdev = video_devdata(file);
+ struct coda_dev *dev = video_get_drvdata(vdev);
struct coda_ctx *ctx = NULL;
char *name;
int ret;
@@ -1388,8 +1574,9 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type,
ctx->debugfs_entry = debugfs_create_dir(name, dev->debugfs_root);
kfree(name);
- ctx->inst_type = inst_type;
- ctx->ops = ctx_ops;
+ ctx->cvd = to_coda_video_device(vdev);
+ ctx->inst_type = ctx->cvd->type;
+ ctx->ops = ctx->cvd->ops;
init_completion(&ctx->completion);
INIT_WORK(&ctx->pic_run_work, coda_pic_run_work);
INIT_WORK(&ctx->seq_end_work, ctx->ops->seq_end_work);
@@ -1399,8 +1586,10 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type,
ctx->dev = dev;
ctx->idx = idx;
switch (dev->devtype->product) {
- case CODA_7541:
case CODA_960:
+ ctx->frame_mem_ctrl = 1 << 12;
+ /* fallthrough */
+ case CODA_7541:
ctx->reg_idx = 0;
break;
default:
@@ -1441,16 +1630,17 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type,
ctx->fh.ctrl_handler = &ctx->ctrls;
- ret = coda_alloc_context_buf(ctx, &ctx->parabuf, CODA_PARA_BUF_SIZE,
- "parabuf");
+ ret = coda_alloc_context_buf(ctx, &ctx->parabuf,
+ CODA_PARA_BUF_SIZE, "parabuf");
if (ret < 0) {
v4l2_err(&dev->v4l2_dev, "failed to allocate parabuf");
goto err_dma_alloc;
}
ctx->bitstream.size = CODA_MAX_FRAME_SIZE;
- ctx->bitstream.vaddr = dma_alloc_writecombine(&dev->plat_dev->dev,
- ctx->bitstream.size, &ctx->bitstream.paddr, GFP_KERNEL);
+ ctx->bitstream.vaddr = dma_alloc_writecombine(
+ &dev->plat_dev->dev, ctx->bitstream.size,
+ &ctx->bitstream.paddr, GFP_KERNEL);
if (!ctx->bitstream.vaddr) {
v4l2_err(&dev->v4l2_dev,
"failed to allocate bitstream ringbuffer");
@@ -1461,7 +1651,7 @@ static int coda_open(struct file *file, enum coda_inst_type inst_type,
ctx->bitstream.vaddr, ctx->bitstream.size);
mutex_init(&ctx->bitstream_mutex);
mutex_init(&ctx->buffer_mutex);
- INIT_LIST_HEAD(&ctx->timestamp_list);
+ INIT_LIST_HEAD(&ctx->buffer_meta_list);
coda_lock(ctx);
list_add(&ctx->list, &dev->instances);
@@ -1495,16 +1685,6 @@ err_coda_max:
return ret;
}
-static int coda_encoder_open(struct file *file)
-{
- return coda_open(file, CODA_INST_ENCODER, &coda_bit_encode_ops);
-}
-
-static int coda_decoder_open(struct file *file)
-{
- return coda_open(file, CODA_INST_DECODER, &coda_bit_decode_ops);
-}
-
static int coda_release(struct file *file)
{
struct coda_dev *dev = video_drvdata(file);
@@ -1515,6 +1695,9 @@ static int coda_release(struct file *file)
debugfs_remove_recursive(ctx->debugfs_entry);
+ if (ctx->inst_type == CODA_INST_DECODER)
+ coda_bit_stream_end_flag(ctx);
+
/* If this instance is running, call .job_abort and wait for it to end */
v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
@@ -1528,8 +1711,10 @@ static int coda_release(struct file *file)
list_del(&ctx->list);
coda_unlock(ctx);
- dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
- ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ if (ctx->bitstream.vaddr) {
+ dma_free_writecombine(&dev->plat_dev->dev, ctx->bitstream.size,
+ ctx->bitstream.vaddr, ctx->bitstream.paddr);
+ }
if (ctx->dev->devtype->product == CODA_DX6)
coda_free_aux_buf(dev, &ctx->workbuf);
@@ -1548,18 +1733,9 @@ static int coda_release(struct file *file)
return 0;
}
-static const struct v4l2_file_operations coda_encoder_fops = {
- .owner = THIS_MODULE,
- .open = coda_encoder_open,
- .release = coda_release,
- .poll = v4l2_m2m_fop_poll,
- .unlocked_ioctl = video_ioctl2,
- .mmap = v4l2_m2m_fop_mmap,
-};
-
-static const struct v4l2_file_operations coda_decoder_fops = {
+static const struct v4l2_file_operations coda_fops = {
.owner = THIS_MODULE,
- .open = coda_decoder_open,
+ .open = coda_open,
.release = coda_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
@@ -1664,8 +1840,16 @@ err_clk_per:
return ret;
}
-static int coda_register_device(struct coda_dev *dev, struct video_device *vfd)
+static int coda_register_device(struct coda_dev *dev, int i)
{
+ struct video_device *vfd = &dev->vfd[i];
+
+ if (i > ARRAY_SIZE(dev->vfd))
+ return -EINVAL;
+
+ snprintf(vfd->name, sizeof(vfd->name), dev->devtype->vdevs[i]->name);
+ vfd->fops = &coda_fops;
+ vfd->ioctl_ops = &coda_ioctl_ops;
vfd->release = video_device_release_empty,
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
@@ -1684,7 +1868,7 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
{
struct coda_dev *dev = context;
struct platform_device *pdev = dev->plat_dev;
- int ret;
+ int i, ret;
if (!fw) {
v4l2_err(&dev->v4l2_dev, "firmware request failed\n");
@@ -1725,33 +1909,25 @@ static void coda_fw_callback(const struct firmware *fw, void *context)
goto rel_ctx;
}
- dev->vfd[0].fops = &coda_encoder_fops,
- dev->vfd[0].ioctl_ops = &coda_ioctl_ops;
- snprintf(dev->vfd[0].name, sizeof(dev->vfd[0].name), "coda-encoder");
- ret = coda_register_device(dev, &dev->vfd[0]);
- if (ret) {
- v4l2_err(&dev->v4l2_dev,
- "Failed to register encoder video device\n");
- goto rel_m2m;
- }
-
- dev->vfd[1].fops = &coda_decoder_fops,
- dev->vfd[1].ioctl_ops = &coda_ioctl_ops;
- snprintf(dev->vfd[1].name, sizeof(dev->vfd[1].name), "coda-decoder");
- ret = coda_register_device(dev, &dev->vfd[1]);
- if (ret) {
- v4l2_err(&dev->v4l2_dev,
- "Failed to register decoder video device\n");
- goto rel_m2m;
+ for (i = 0; i < dev->devtype->num_vdevs; i++) {
+ ret = coda_register_device(dev, i);
+ if (ret) {
+ v4l2_err(&dev->v4l2_dev,
+ "Failed to register %s video device: %d\n",
+ dev->devtype->vdevs[i]->name, ret);
+ goto rel_vfd;
+ }
}
v4l2_info(&dev->v4l2_dev, "codec registered as /dev/video[%d-%d]\n",
- dev->vfd[0].num, dev->vfd[1].num);
+ dev->vfd[0].num, dev->vfd[i - 1].num);
pm_runtime_put_sync(&pdev->dev);
return;
-rel_m2m:
+rel_vfd:
+ while (--i >= 0)
+ video_unregister_device(&dev->vfd[i]);
v4l2_m2m_release(dev->m2m_dev);
rel_ctx:
vb2_dma_contig_cleanup_ctx(dev->alloc_ctx);
@@ -1783,6 +1959,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_DX6,
.codecs = codadx6_codecs,
.num_codecs = ARRAY_SIZE(codadx6_codecs),
+ .vdevs = codadx6_video_devices,
+ .num_vdevs = ARRAY_SIZE(codadx6_video_devices),
.workbuf_size = 288 * 1024 + FMO_SLICE_SAVE_BUF_SIZE * 8 * 1024,
.iram_size = 0xb000,
},
@@ -1791,6 +1969,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_7541,
.codecs = coda7_codecs,
.num_codecs = ARRAY_SIZE(coda7_codecs),
+ .vdevs = coda7_video_devices,
+ .num_vdevs = ARRAY_SIZE(coda7_video_devices),
.workbuf_size = 128 * 1024,
.tempbuf_size = 304 * 1024,
.iram_size = 0x14000,
@@ -1800,6 +1980,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_960,
.codecs = coda9_codecs,
.num_codecs = ARRAY_SIZE(coda9_codecs),
+ .vdevs = coda9_video_devices,
+ .num_vdevs = ARRAY_SIZE(coda9_video_devices),
.workbuf_size = 80 * 1024,
.tempbuf_size = 204 * 1024,
.iram_size = 0x21000,
@@ -1809,6 +1991,8 @@ static const struct coda_devtype coda_devdata[] = {
.product = CODA_960,
.codecs = coda9_codecs,
.num_codecs = ARRAY_SIZE(coda9_codecs),
+ .vdevs = coda9_video_devices,
+ .num_vdevs = ARRAY_SIZE(coda9_video_devices),
.workbuf_size = 80 * 1024,
.tempbuf_size = 204 * 1024,
.iram_size = 0x20000,
@@ -1846,10 +2030,18 @@ static int coda_probe(struct platform_device *pdev)
int ret, irq;
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
- if (!dev) {
- dev_err(&pdev->dev, "Not enough memory for %s\n",
- CODA_NAME);
+ if (!dev)
return -ENOMEM;
+
+ pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
+
+ if (of_id) {
+ dev->devtype = of_id->data;
+ } else if (pdev_id) {
+ dev->devtype = &coda_devdata[pdev_id->driver_data];
+ } else {
+ ret = -EINVAL;
+ goto err_v4l2_register;
}
spin_lock_init(&dev->irqlock);
@@ -1919,17 +2111,6 @@ static int coda_probe(struct platform_device *pdev)
mutex_init(&dev->dev_mutex);
mutex_init(&dev->coda_mutex);
- pdev_id = of_id ? of_id->data : platform_get_device_id(pdev);
-
- if (of_id) {
- dev->devtype = of_id->data;
- } else if (pdev_id) {
- dev->devtype = &coda_devdata[pdev_id->driver_data];
- } else {
- v4l2_device_unregister(&dev->v4l2_dev);
- return -EINVAL;
- }
-
dev->debugfs_root = debugfs_create_dir("coda", NULL);
if (!dev->debugfs_root)
dev_warn(&pdev->dev, "failed to create debugfs root\n");
@@ -1941,8 +2122,7 @@ static int coda_probe(struct platform_device *pdev)
dev->debugfs_root);
if (ret < 0) {
dev_err(&pdev->dev, "failed to allocate work buffer\n");
- v4l2_device_unregister(&dev->v4l2_dev);
- return ret;
+ goto err_v4l2_register;
}
}
@@ -1952,8 +2132,7 @@ static int coda_probe(struct platform_device *pdev)
dev->debugfs_root);
if (ret < 0) {
dev_err(&pdev->dev, "failed to allocate temp buffer\n");
- v4l2_device_unregister(&dev->v4l2_dev);
- return ret;
+ goto err_v4l2_register;
}
}
@@ -1973,14 +2152,15 @@ static int coda_probe(struct platform_device *pdev)
dev->workqueue = alloc_workqueue("coda", WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!dev->workqueue) {
dev_err(&pdev->dev, "unable to alloc workqueue\n");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto err_v4l2_register;
}
platform_set_drvdata(pdev, dev);
/*
* Start activated so we can directly call coda_hw_init in
- * coda_fw_callback regardless of whether CONFIG_PM_RUNTIME is
+ * coda_fw_callback regardless of whether CONFIG_PM is
* enabled or whether the device is associated with a PM domain.
*/
pm_runtime_get_noresume(&pdev->dev);
@@ -1988,14 +2168,21 @@ static int coda_probe(struct platform_device *pdev)
pm_runtime_enable(&pdev->dev);
return coda_firmware_request(dev);
+
+err_v4l2_register:
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return ret;
}
static int coda_remove(struct platform_device *pdev)
{
struct coda_dev *dev = platform_get_drvdata(pdev);
+ int i;
- video_unregister_device(&dev->vfd[0]);
- video_unregister_device(&dev->vfd[1]);
+ for (i = 0; i < ARRAY_SIZE(dev->vfd); i++) {
+ if (video_get_drvdata(&dev->vfd[i]))
+ video_unregister_device(&dev->vfd[i]);
+ }
if (dev->m2m_dev)
v4l2_m2m_release(dev->m2m_dev);
pm_runtime_disable(&pdev->dev);
@@ -2013,7 +2200,7 @@ static int coda_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int coda_runtime_resume(struct device *dev)
{
struct coda_dev *cdev = dev_get_drvdata(dev);
diff --git a/drivers/media/platform/coda/coda-jpeg.c b/drivers/media/platform/coda/coda-jpeg.c
new file mode 100644
index 0000000..8fa3e35
--- /dev/null
+++ b/drivers/media/platform/coda/coda-jpeg.c
@@ -0,0 +1,238 @@
+/*
+ * Coda multi-standard codec IP - JPEG support functions
+ *
+ * Copyright (C) 2014 Philipp Zabel, Pengutronix
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/kernel.h>
+#include <linux/swab.h>
+
+#include "coda.h"
+
+#define SOI_MARKER 0xffd8
+#define EOI_MARKER 0xffd9
+
+/*
+ * Typical Huffman tables for 8-bit precision luminance and
+ * chrominance from JPEG ITU-T.81 (ISO/IEC 10918-1) Annex K.3
+ */
+
+static const unsigned char luma_dc_bits[16] = {
+ 0x00, 0x01, 0x05, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char luma_dc_value[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const unsigned char chroma_dc_bits[16] = {
+ 0x00, 0x03, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const unsigned char chroma_dc_value[12] = {
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b,
+};
+
+static const unsigned char luma_ac_bits[16] = {
+ 0x00, 0x02, 0x01, 0x03, 0x03, 0x02, 0x04, 0x03,
+ 0x05, 0x05, 0x04, 0x04, 0x00, 0x00, 0x01, 0x7d,
+};
+
+static const unsigned char luma_ac_value[162 + 2] = {
+ 0x01, 0x02, 0x03, 0x00, 0x04, 0x11, 0x05, 0x12,
+ 0x21, 0x31, 0x41, 0x06, 0x13, 0x51, 0x61, 0x07,
+ 0x22, 0x71, 0x14, 0x32, 0x81, 0x91, 0xa1, 0x08,
+ 0x23, 0x42, 0xb1, 0xc1, 0x15, 0x52, 0xd1, 0xf0,
+ 0x24, 0x33, 0x62, 0x72, 0x82, 0x09, 0x0a, 0x16,
+ 0x17, 0x18, 0x19, 0x1a, 0x25, 0x26, 0x27, 0x28,
+ 0x29, 0x2a, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39,
+ 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49,
+ 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59,
+ 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69,
+ 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79,
+ 0x7a, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89,
+ 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,
+ 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6,
+ 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3, 0xc4, 0xc5,
+ 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2, 0xd3, 0xd4,
+ 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xe1, 0xe2,
+ 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea,
+ 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, /* padded to 32-bit */
+};
+
+static const unsigned char chroma_ac_bits[16] = {
+ 0x00, 0x02, 0x01, 0x02, 0x04, 0x04, 0x03, 0x04,
+ 0x07, 0x05, 0x04, 0x04, 0x00, 0x01, 0x02, 0x77,
+};
+
+static const unsigned char chroma_ac_value[162 + 2] = {
+ 0x00, 0x01, 0x02, 0x03, 0x11, 0x04, 0x05, 0x21,
+ 0x31, 0x06, 0x12, 0x41, 0x51, 0x07, 0x61, 0x71,
+ 0x13, 0x22, 0x32, 0x81, 0x08, 0x14, 0x42, 0x91,
+ 0xa1, 0xb1, 0xc1, 0x09, 0x23, 0x33, 0x52, 0xf0,
+ 0x15, 0x62, 0x72, 0xd1, 0x0a, 0x16, 0x24, 0x34,
+ 0xe1, 0x25, 0xf1, 0x17, 0x18, 0x19, 0x1a, 0x26,
+ 0x27, 0x28, 0x29, 0x2a, 0x35, 0x36, 0x37, 0x38,
+ 0x39, 0x3a, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48,
+ 0x49, 0x4a, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58,
+ 0x59, 0x5a, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x69, 0x6a, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78,
+ 0x79, 0x7a, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x92, 0x93, 0x94, 0x95, 0x96,
+ 0x97, 0x98, 0x99, 0x9a, 0xa2, 0xa3, 0xa4, 0xa5,
+ 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xb2, 0xb3, 0xb4,
+ 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xc2, 0xc3,
+ 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xd2,
+ 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda,
+ 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9,
+ 0xea, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8,
+ 0xf9, 0xfa, /* padded to 32-bit */
+};
+
+/*
+ * Quantization tables for luminance and chrominance components in
+ * zig-zag scan order from the Freescale i.MX VPU libaries
+ */
+
+static unsigned char luma_q[64] = {
+ 0x06, 0x04, 0x04, 0x04, 0x05, 0x04, 0x06, 0x05,
+ 0x05, 0x06, 0x09, 0x06, 0x05, 0x06, 0x09, 0x0b,
+ 0x08, 0x06, 0x06, 0x08, 0x0b, 0x0c, 0x0a, 0x0a,
+ 0x0b, 0x0a, 0x0a, 0x0c, 0x10, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x10, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+};
+
+static unsigned char chroma_q[64] = {
+ 0x07, 0x07, 0x07, 0x0d, 0x0c, 0x0d, 0x18, 0x10,
+ 0x10, 0x18, 0x14, 0x0e, 0x0e, 0x0e, 0x14, 0x14,
+ 0x0e, 0x0e, 0x0e, 0x0e, 0x14, 0x11, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x11, 0x11, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x11, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+ 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c,
+};
+
+struct coda_memcpy_desc {
+ int offset;
+ const void *src;
+ size_t len;
+};
+
+static void coda_memcpy_parabuf(void *parabuf,
+ const struct coda_memcpy_desc *desc)
+{
+ u32 *dst = parabuf + desc->offset;
+ const u32 *src = desc->src;
+ int len = desc->len / 4;
+ int i;
+
+ for (i = 0; i < len; i += 2) {
+ dst[i + 1] = swab32(src[i]);
+ dst[i] = swab32(src[i + 1]);
+ }
+}
+
+int coda_jpeg_write_tables(struct coda_ctx *ctx)
+{
+ int i;
+ static const struct coda_memcpy_desc huff[8] = {
+ { 0, luma_dc_bits, sizeof(luma_dc_bits) },
+ { 16, luma_dc_value, sizeof(luma_dc_value) },
+ { 32, luma_ac_bits, sizeof(luma_ac_bits) },
+ { 48, luma_ac_value, sizeof(luma_ac_value) },
+ { 216, chroma_dc_bits, sizeof(chroma_dc_bits) },
+ { 232, chroma_dc_value, sizeof(chroma_dc_value) },
+ { 248, chroma_ac_bits, sizeof(chroma_ac_bits) },
+ { 264, chroma_ac_value, sizeof(chroma_ac_value) },
+ };
+ struct coda_memcpy_desc qmat[3] = {
+ { 512, ctx->params.jpeg_qmat_tab[0], 64 },
+ { 576, ctx->params.jpeg_qmat_tab[1], 64 },
+ { 640, ctx->params.jpeg_qmat_tab[1], 64 },
+ };
+
+ /* Write huffman tables to parameter memory */
+ for (i = 0; i < ARRAY_SIZE(huff); i++)
+ coda_memcpy_parabuf(ctx->parabuf.vaddr, huff + i);
+
+ /* Write Q-matrix to parameter memory */
+ for (i = 0; i < ARRAY_SIZE(qmat); i++)
+ coda_memcpy_parabuf(ctx->parabuf.vaddr, qmat + i);
+
+ return 0;
+}
+
+bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb)
+{
+ void *vaddr = vb2_plane_vaddr(vb, 0);
+ u16 soi = be16_to_cpup((__be16 *)vaddr);
+ u16 eoi = be16_to_cpup((__be16 *)(vaddr +
+ vb2_get_plane_payload(vb, 0) - 2));
+
+ return soi == SOI_MARKER && eoi == EOI_MARKER;
+}
+
+/*
+ * Scale quantization table using nonlinear scaling factor
+ * u8 qtab[64], scale [50,190]
+ */
+static void coda_scale_quant_table(u8 *q_tab, int scale)
+{
+ unsigned int temp;
+ int i;
+
+ for (i = 0; i < 64; i++) {
+ temp = DIV_ROUND_CLOSEST((unsigned int)q_tab[i] * scale, 100);
+ if (temp <= 0)
+ temp = 1;
+ if (temp > 255)
+ temp = 255;
+ q_tab[i] = (unsigned char)temp;
+ }
+}
+
+void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality)
+{
+ unsigned int scale;
+
+ ctx->params.jpeg_quality = quality;
+
+ /* Clip quality setting to [5,100] interval */
+ if (quality > 100)
+ quality = 100;
+ if (quality < 5)
+ quality = 5;
+
+ /*
+ * Non-linear scaling factor:
+ * [5,50] -> [1000..100], [51,100] -> [98..0]
+ */
+ if (quality < 50)
+ scale = 5000 / quality;
+ else
+ scale = 200 - 2 * quality;
+
+ if (ctx->params.jpeg_qmat_tab[0]) {
+ memcpy(ctx->params.jpeg_qmat_tab[0], luma_q, 64);
+ coda_scale_quant_table(ctx->params.jpeg_qmat_tab[0], scale);
+ }
+ if (ctx->params.jpeg_qmat_tab[1]) {
+ memcpy(ctx->params.jpeg_qmat_tab[1], chroma_q, 64);
+ coda_scale_quant_table(ctx->params.jpeg_qmat_tab[1], scale);
+ }
+}
diff --git a/drivers/media/platform/coda/coda.h b/drivers/media/platform/coda/coda.h
index bbc18c0..5dd47e5 100644
--- a/drivers/media/platform/coda/coda.h
+++ b/drivers/media/platform/coda/coda.h
@@ -45,11 +45,15 @@ enum coda_product {
CODA_960 = 0xf020,
};
+struct coda_video_device;
+
struct coda_devtype {
char *firmware;
enum coda_product product;
const struct coda_codec *codecs;
unsigned int num_codecs;
+ const struct coda_video_device **vdevs;
+ unsigned int num_vdevs;
size_t workbuf_size;
size_t tempbuf_size;
size_t iram_size;
@@ -65,7 +69,7 @@ struct coda_aux_buf {
struct coda_dev {
struct v4l2_device v4l2_dev;
- struct video_device vfd[2];
+ struct video_device vfd[5];
struct platform_device *plat_dev;
const struct coda_devtype *devtype;
@@ -114,6 +118,9 @@ struct coda_params {
u8 mpeg4_inter_qp;
u8 gop_size;
int intra_refresh;
+ u8 jpeg_quality;
+ u8 jpeg_restart_interval;
+ u8 *jpeg_qmat_tab[3];
int codec_mode;
int codec_mode_aux;
enum v4l2_mpeg_video_multi_slice_mode slice_mode;
@@ -123,11 +130,13 @@ struct coda_params {
u32 slice_max_mb;
};
-struct coda_timestamp {
+struct coda_buffer_meta {
struct list_head list;
u32 sequence;
struct v4l2_timecode timecode;
struct timeval timestamp;
+ u32 start;
+ u32 end;
};
/* Per-queue, driver-specific private data */
@@ -183,6 +192,7 @@ struct coda_ctx {
struct work_struct pic_run_work;
struct work_struct seq_end_work;
struct completion completion;
+ const struct coda_video_device *cvd;
const struct coda_context_ops *ops;
int aborting;
int initialized;
@@ -212,9 +222,9 @@ struct coda_ctx {
struct coda_aux_buf slicebuf;
struct coda_aux_buf internal_frames[CODA_MAX_FRAMEBUFFERS];
u32 frame_types[CODA_MAX_FRAMEBUFFERS];
- struct coda_timestamp frame_timestamps[CODA_MAX_FRAMEBUFFERS];
+ struct coda_buffer_meta frame_metas[CODA_MAX_FRAMEBUFFERS];
u32 frame_errors[CODA_MAX_FRAMEBUFFERS];
- struct list_head timestamp_list;
+ struct list_head buffer_meta_list;
struct coda_aux_buf workbuf;
int num_internal_frames;
int idx;
@@ -232,6 +242,8 @@ extern int coda_debug;
void coda_write(struct coda_dev *dev, u32 data, u32 reg);
unsigned int coda_read(struct coda_dev *dev, u32 reg);
+void coda_write_base(struct coda_ctx *ctx, struct coda_q_data *q_data,
+ struct vb2_buffer *buf, unsigned int reg_y);
int coda_alloc_aux_buf(struct coda_dev *dev, struct coda_aux_buf *buf,
size_t size, const char *name, struct dentry *parent);
@@ -281,6 +293,10 @@ void coda_bit_stream_end_flag(struct coda_ctx *ctx);
int coda_h264_padding(int size, char *p);
+bool coda_jpeg_check_buffer(struct coda_ctx *ctx, struct vb2_buffer *vb);
+int coda_jpeg_write_tables(struct coda_ctx *ctx);
+void coda_set_jpeg_compression_quality(struct coda_ctx *ctx, int quality);
+
extern const struct coda_context_ops coda_bit_encode_ops;
extern const struct coda_context_ops coda_bit_decode_ops;
diff --git a/drivers/media/platform/coda/coda_regs.h b/drivers/media/platform/coda/coda_regs.h
index c791275..8e015b8 100644
--- a/drivers/media/platform/coda/coda_regs.h
+++ b/drivers/media/platform/coda/coda_regs.h
@@ -147,6 +147,7 @@
#define CODA_CMD_DEC_SEQ_BB_START 0x180
#define CODA_CMD_DEC_SEQ_BB_SIZE 0x184
#define CODA_CMD_DEC_SEQ_OPTION 0x188
+#define CODA_NO_INT_ENABLE (1 << 10)
#define CODA_REORDER_ENABLE (1 << 1)
#define CODADX6_QP_REPORT (1 << 0)
#define CODA7_MP4_DEBLK_ENABLE (1 << 0)
@@ -332,6 +333,12 @@
#define CODA9_CMD_ENC_SEQ_ME_OPTION 0x1d8
#define CODA_RET_ENC_SEQ_SUCCESS 0x1c0
+#define CODA_CMD_ENC_SEQ_JPG_PARA 0x198
+#define CODA_CMD_ENC_SEQ_JPG_RST_INTERVAL 0x19C
+#define CODA_CMD_ENC_SEQ_JPG_THUMB_EN 0x1a0
+#define CODA_CMD_ENC_SEQ_JPG_THUMB_SIZE 0x1a4
+#define CODA_CMD_ENC_SEQ_JPG_THUMB_OFFSET 0x1a8
+
/* Encoder Picture Run */
#define CODA9_CMD_ENC_PIC_SRC_INDEX 0x180
#define CODA9_CMD_ENC_PIC_SRC_STRIDE 0x184
diff --git a/drivers/media/platform/davinci/vpbe.c b/drivers/media/platform/davinci/vpbe.c
index 33b9660..244d3d6 100644
--- a/drivers/media/platform/davinci/vpbe.c
+++ b/drivers/media/platform/davinci/vpbe.c
@@ -227,7 +227,7 @@ static int vpbe_set_output(struct vpbe_device *vpbe_dev, int index)
vpbe_current_encoder_info(vpbe_dev);
struct vpbe_config *cfg = vpbe_dev->cfg;
struct venc_platform_data *venc_device = vpbe_dev->venc_device;
- enum v4l2_mbus_pixelcode if_params;
+ u32 if_params;
int enc_out_index;
int sd_index;
int ret = 0;
@@ -341,7 +341,7 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev,
if (!(cfg->outputs[out_index].output.capabilities &
V4L2_OUT_CAP_DV_TIMINGS))
- return -EINVAL;
+ return -ENODATA;
for (i = 0; i < output->num_modes; i++) {
if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS &&
@@ -384,6 +384,13 @@ static int vpbe_s_dv_timings(struct vpbe_device *vpbe_dev,
static int vpbe_g_dv_timings(struct vpbe_device *vpbe_dev,
struct v4l2_dv_timings *dv_timings)
{
+ struct vpbe_config *cfg = vpbe_dev->cfg;
+ int out_index = vpbe_dev->current_out_index;
+
+ if (!(cfg->outputs[out_index].output.capabilities &
+ V4L2_OUT_CAP_DV_TIMINGS))
+ return -ENODATA;
+
if (vpbe_dev->current_timings.timings_type &
VPBE_ENC_DV_TIMINGS) {
*dv_timings = vpbe_dev->current_timings.dv_timings;
@@ -409,7 +416,7 @@ static int vpbe_enum_dv_timings(struct vpbe_device *vpbe_dev,
int i;
if (!(output->output.capabilities & V4L2_OUT_CAP_DV_TIMINGS))
- return -EINVAL;
+ return -ENODATA;
for (i = 0; i < output->num_modes; i++) {
if (output->modes[i].timings_type == VPBE_ENC_DV_TIMINGS) {
@@ -440,7 +447,7 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id)
if (!(cfg->outputs[out_index].output.capabilities &
V4L2_OUT_CAP_STD))
- return -EINVAL;
+ return -ENODATA;
ret = vpbe_get_std_info(vpbe_dev, std_id);
if (ret)
@@ -473,6 +480,11 @@ static int vpbe_s_std(struct vpbe_device *vpbe_dev, v4l2_std_id std_id)
static int vpbe_g_std(struct vpbe_device *vpbe_dev, v4l2_std_id *std_id)
{
struct vpbe_enc_mode_info *cur_timings = &vpbe_dev->current_timings;
+ struct vpbe_config *cfg = vpbe_dev->cfg;
+ int out_index = vpbe_dev->current_out_index;
+
+ if (!(cfg->outputs[out_index].output.capabilities & V4L2_OUT_CAP_STD))
+ return -ENODATA;
if (cur_timings->timings_type & VPBE_ENC_STD) {
*std_id = cur_timings->std_id;
@@ -613,6 +625,7 @@ static int vpbe_initialize(struct device *dev, struct vpbe_device *vpbe_dev)
}
if (clk_prepare_enable(vpbe_dev->dac_clk)) {
ret = -ENODEV;
+ clk_put(vpbe_dev->dac_clk);
goto fail_mutex_unlock;
}
}
diff --git a/drivers/media/platform/davinci/vpbe_display.c b/drivers/media/platform/davinci/vpbe_display.c
index 73496d9..21a5a56 100644
--- a/drivers/media/platform/davinci/vpbe_display.c
+++ b/drivers/media/platform/davinci/vpbe_display.c
@@ -152,8 +152,8 @@ static irqreturn_t venc_isr(int irq, void *arg)
for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
layer = disp_dev->dev[i];
- /* If streaming is started in this layer */
- if (!layer->started)
+
+ if (!vb2_start_streaming_called(&layer->buffer_queue))
continue;
if (layer->layer_first_int) {
@@ -207,31 +207,23 @@ static irqreturn_t venc_isr(int irq, void *arg)
*/
static int vpbe_buffer_prepare(struct vb2_buffer *vb)
{
- struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
struct vb2_queue *q = vb->vb2_queue;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = vb2_get_drv_priv(q);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
unsigned long addr;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"vpbe_buffer_prepare\n");
- if (vb->state != VB2_BUF_STATE_ACTIVE &&
- vb->state != VB2_BUF_STATE_PREPARED) {
- vb2_set_plane_payload(vb, 0, layer->pix_fmt.sizeimage);
- if (vb2_plane_vaddr(vb, 0) &&
- vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
- return -EINVAL;
+ vb2_set_plane_payload(vb, 0, layer->pix_fmt.sizeimage);
+ if (vb2_get_plane_payload(vb, 0) > vb2_plane_size(vb, 0))
+ return -EINVAL;
- addr = vb2_dma_contig_plane_dma_addr(vb, 0);
- if (q->streaming) {
- if (!IS_ALIGNED(addr, 8)) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "buffer_prepare:offset is \
- not aligned to 32 bytes\n");
- return -EINVAL;
- }
- }
+ addr = vb2_dma_contig_plane_dma_addr(vb, 0);
+ if (!IS_ALIGNED(addr, 8)) {
+ v4l2_err(&vpbe_dev->v4l2_dev,
+ "buffer_prepare:offset is not aligned to 32 bytes\n");
+ return -EINVAL;
}
return 0;
}
@@ -247,18 +239,20 @@ vpbe_buffer_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
{
/* Get the file handle object and layer object */
- struct vpbe_fh *fh = vb2_get_drv_priv(vq);
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = vb2_get_drv_priv(vq);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_buffer_setup\n");
+ if (fmt && fmt->fmt.pix.sizeimage < layer->pix_fmt.sizeimage)
+ return -EINVAL;
+
/* Store number of buffers allocated in numbuffer member */
- if (*nbuffers < VPBE_DEFAULT_NUM_BUFS)
- *nbuffers = layer->numbuffers = VPBE_DEFAULT_NUM_BUFS;
+ if (vq->num_buffers + *nbuffers < VPBE_DEFAULT_NUM_BUFS)
+ *nbuffers = VPBE_DEFAULT_NUM_BUFS - vq->num_buffers;
*nplanes = 1;
- sizes[0] = layer->pix_fmt.sizeimage;
+ sizes[0] = fmt ? fmt->fmt.pix.sizeimage : layer->pix_fmt.sizeimage;
alloc_ctxs[0] = layer->alloc_ctx;
return 0;
@@ -271,12 +265,11 @@ vpbe_buffer_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
static void vpbe_buffer_queue(struct vb2_buffer *vb)
{
/* Get the file handle object and layer object */
- struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
struct vpbe_disp_buffer *buf = container_of(vb,
struct vpbe_disp_buffer, vb);
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp = fh->disp_dev;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = vb2_get_drv_priv(vb->vb2_queue);
+ struct vpbe_display *disp = layer->disp_dev;
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
unsigned long flags;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
@@ -288,61 +281,14 @@ static void vpbe_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&disp->dma_queue_lock, flags);
}
-/*
- * vpbe_buf_cleanup()
- * This function is called from the vb2 layer to free memory allocated to
- * the buffers
- */
-static void vpbe_buf_cleanup(struct vb2_buffer *vb)
-{
- /* Get the file handle object and layer object */
- struct vpbe_fh *fh = vb2_get_drv_priv(vb->vb2_queue);
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct vpbe_disp_buffer *buf = container_of(vb,
- struct vpbe_disp_buffer, vb);
- unsigned long flags;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe_buf_cleanup\n");
-
- spin_lock_irqsave(&layer->irqlock, flags);
- if (vb->state == VB2_BUF_STATE_ACTIVE)
- list_del_init(&buf->list);
- spin_unlock_irqrestore(&layer->irqlock, flags);
-}
-
-static void vpbe_wait_prepare(struct vb2_queue *vq)
-{
- struct vpbe_fh *fh = vb2_get_drv_priv(vq);
- struct vpbe_layer *layer = fh->layer;
-
- mutex_unlock(&layer->opslock);
-}
-
-static void vpbe_wait_finish(struct vb2_queue *vq)
-{
- struct vpbe_fh *fh = vb2_get_drv_priv(vq);
- struct vpbe_layer *layer = fh->layer;
-
- mutex_lock(&layer->opslock);
-}
-
-static int vpbe_buffer_init(struct vb2_buffer *vb)
-{
- struct vpbe_disp_buffer *buf = container_of(vb,
- struct vpbe_disp_buffer, vb);
-
- INIT_LIST_HEAD(&buf->list);
- return 0;
-}
-
static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
{
- struct vpbe_fh *fh = vb2_get_drv_priv(vq);
- struct vpbe_layer *layer = fh->layer;
+ struct vpbe_layer *layer = vb2_get_drv_priv(vq);
+ struct osd_state *osd_device = layer->disp_dev->osd_device;
int ret;
+ osd_device->ops.disable_layer(osd_device, layer->layer_info.id);
+
/* Get the next frame from the buffer queue */
layer->next_frm = layer->cur_frm = list_entry(layer->dma_queue.next,
struct vpbe_disp_buffer, list);
@@ -354,7 +300,7 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
layer->field_id = 0;
/* Set parameters in OSD and VENC */
- ret = vpbe_set_osd_display_params(fh->disp_dev, layer);
+ ret = vpbe_set_osd_display_params(layer->disp_dev, layer);
if (ret < 0) {
struct vpbe_disp_buffer *buf, *tmp;
@@ -371,7 +317,6 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
* if request format is yuv420 semiplanar, need to
* enable both video windows
*/
- layer->started = 1;
layer->layer_first_int = 1;
return ret;
@@ -379,14 +324,16 @@ static int vpbe_start_streaming(struct vb2_queue *vq, unsigned int count)
static void vpbe_stop_streaming(struct vb2_queue *vq)
{
- struct vpbe_fh *fh = vb2_get_drv_priv(vq);
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp = fh->disp_dev;
+ struct vpbe_layer *layer = vb2_get_drv_priv(vq);
+ struct osd_state *osd_device = layer->disp_dev->osd_device;
+ struct vpbe_display *disp = layer->disp_dev;
unsigned long flags;
if (!vb2_is_streaming(vq))
return;
+ osd_device->ops.disable_layer(osd_device, layer->layer_info.id);
+
/* release all active buffers */
spin_lock_irqsave(&disp->dma_queue_lock, flags);
if (layer->cur_frm == layer->next_frm) {
@@ -411,13 +358,11 @@ static void vpbe_stop_streaming(struct vb2_queue *vq)
static struct vb2_ops video_qops = {
.queue_setup = vpbe_buffer_queue_setup,
- .wait_prepare = vpbe_wait_prepare,
- .wait_finish = vpbe_wait_finish,
- .buf_init = vpbe_buffer_init,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
.buf_prepare = vpbe_buffer_prepare,
.start_streaming = vpbe_start_streaming,
.stop_streaming = vpbe_stop_streaming,
- .buf_cleanup = vpbe_buf_cleanup,
.buf_queue = vpbe_buffer_queue,
};
@@ -691,10 +636,9 @@ static int vpbe_try_format(struct vpbe_display *disp_dev,
static int vpbe_display_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
- cap->version = VPBE_DISPLAY_VERSION_CODE;
cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
snprintf(cap->driver, sizeof(cap->driver), "%s",
@@ -709,9 +653,8 @@ static int vpbe_display_querycap(struct file *file, void *priv,
static int vpbe_display_s_crop(struct file *file, void *priv,
const struct v4l2_crop *crop)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_display *disp_dev = layer->disp_dev;
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
struct osd_layer_config *cfg = &layer->layer_info.config;
struct osd_state *osd_device = disp_dev->osd_device;
@@ -778,11 +721,10 @@ static int vpbe_display_s_crop(struct file *file, void *priv,
static int vpbe_display_g_crop(struct file *file, void *priv,
struct v4l2_crop *crop)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
+ struct vpbe_layer *layer = video_drvdata(file);
struct osd_layer_config *cfg = &layer->layer_info.config;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct osd_state *osd_device = fh->disp_dev->osd_device;
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
+ struct osd_state *osd_device = layer->disp_dev->osd_device;
struct v4l2_rect *rect = &crop->c;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
@@ -806,8 +748,8 @@ static int vpbe_display_g_crop(struct file *file, void *priv,
static int vpbe_display_cropcap(struct file *file, void *priv,
struct v4l2_cropcap *cropcap)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_CROPCAP ioctl\n");
@@ -824,9 +766,8 @@ static int vpbe_display_cropcap(struct file *file, void *priv,
static int vpbe_display_g_fmt(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"VIDIOC_G_FMT, layer id = %d\n",
@@ -846,9 +787,8 @@ static int vpbe_display_g_fmt(struct file *file, void *priv,
static int vpbe_display_enum_fmt(struct file *file, void *priv,
struct v4l2_fmtdesc *fmt)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
unsigned int index = 0;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
@@ -878,9 +818,8 @@ static int vpbe_display_enum_fmt(struct file *file, void *priv,
static int vpbe_display_s_fmt(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_display *disp_dev = layer->disp_dev;
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
struct osd_layer_config *cfg = &layer->layer_info.config;
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
@@ -891,11 +830,9 @@ static int vpbe_display_s_fmt(struct file *file, void *priv,
"VIDIOC_S_FMT, layer id = %d\n",
layer->device_id);
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ if (vb2_is_busy(&layer->buffer_queue))
return -EBUSY;
- }
+
if (V4L2_BUF_TYPE_VIDEO_OUTPUT != fmt->type) {
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "invalid type\n");
return -EINVAL;
@@ -967,9 +904,9 @@ static int vpbe_display_s_fmt(struct file *file, void *priv,
static int vpbe_display_try_fmt(struct file *file, void *priv,
struct v4l2_format *fmt)
{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_display *disp_dev = layer->disp_dev;
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_TRY_FMT\n");
@@ -993,18 +930,15 @@ static int vpbe_display_try_fmt(struct file *file, void *priv,
static int vpbe_display_s_std(struct file *file, void *priv,
v4l2_std_id std_id)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_STD\n");
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ if (vb2_is_busy(&layer->buffer_queue))
return -EBUSY;
- }
+
if (NULL != vpbe_dev->ops.s_std) {
ret = vpbe_dev->ops.s_std(vpbe_dev, std_id);
if (ret) {
@@ -1028,8 +962,8 @@ static int vpbe_display_s_std(struct file *file, void *priv,
static int vpbe_display_g_std(struct file *file, void *priv,
v4l2_std_id *std_id)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_STD\n");
@@ -1051,8 +985,8 @@ static int vpbe_display_g_std(struct file *file, void *priv,
static int vpbe_display_enum_output(struct file *file, void *priv,
struct v4l2_output *output)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_OUTPUT\n");
@@ -1079,17 +1013,15 @@ static int vpbe_display_enum_output(struct file *file, void *priv,
static int vpbe_display_s_output(struct file *file, void *priv,
unsigned int i)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_OUTPUT\n");
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+
+ if (vb2_is_busy(&layer->buffer_queue))
return -EBUSY;
- }
+
if (NULL == vpbe_dev->ops.set_output)
return -EINVAL;
@@ -1110,8 +1042,8 @@ static int vpbe_display_s_output(struct file *file, void *priv,
static int vpbe_display_g_output(struct file *file, void *priv,
unsigned int *i)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_OUTPUT\n");
/* Get the standard from the current encoder */
@@ -1130,8 +1062,8 @@ static int
vpbe_display_enum_dv_timings(struct file *file, void *priv,
struct v4l2_enum_dv_timings *timings)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_ENUM_DV_TIMINGS\n");
@@ -1160,19 +1092,14 @@ static int
vpbe_display_s_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *timings)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
int ret;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_S_DV_TIMINGS\n");
-
- /* If streaming is started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Streaming is started\n");
+ if (vb2_is_busy(&layer->buffer_queue))
return -EBUSY;
- }
/* Set the given standard in the encoder */
if (!vpbe_dev->ops.s_dv_timings)
@@ -1198,8 +1125,8 @@ static int
vpbe_display_g_dv_timings(struct file *file, void *priv,
struct v4l2_dv_timings *dv_timings)
{
- struct vpbe_fh *fh = priv;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
+ struct vpbe_layer *layer = video_drvdata(file);
+ struct vpbe_device *vpbe_dev = layer->disp_dev->vpbe_dev;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_G_DV_TIMINGS\n");
@@ -1215,259 +1142,6 @@ vpbe_display_g_dv_timings(struct file *file, void *priv,
return 0;
}
-static int vpbe_display_streamoff(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct osd_state *osd_device = fh->disp_dev->osd_device;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_STREAMOFF,layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If io is allowed for this file handle, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
-
- /* If streaming is not started, return error */
- if (!layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "streaming not started in layer"
- " id = %d\n", layer->device_id);
- return -EINVAL;
- }
-
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
- layer->started = 0;
- ret = vb2_streamoff(&layer->buffer_queue, buf_type);
-
- return ret;
-}
-
-static int vpbe_display_streamon(struct file *file, void *priv,
- enum v4l2_buf_type buf_type)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_display *disp_dev = fh->disp_dev;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct osd_state *osd_device = disp_dev->osd_device;
- int ret;
-
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "VIDIOC_STREAMON, layerid=%d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf_type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If file handle is not allowed IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
- /* If Streaming is already started, return error */
- if (layer->started) {
- v4l2_err(&vpbe_dev->v4l2_dev, "layer is already streaming\n");
- return -EBUSY;
- }
-
- /*
- * Call vb2_streamon to start streaming
- * in videobuf
- */
- ret = vb2_streamon(&layer->buffer_queue, buf_type);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "error in vb2_streamon\n");
- return ret;
- }
- return ret;
-}
-
-static int vpbe_display_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_DQBUF, layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
- /* If this file handle is not allowed to do IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
- if (file->f_flags & O_NONBLOCK)
- /* Call videobuf_dqbuf for non blocking mode */
- ret = vb2_dqbuf(&layer->buffer_queue, buf, 1);
- else
- /* Call videobuf_dqbuf for blocking mode */
- ret = vb2_dqbuf(&layer->buffer_queue, buf, 0);
-
- return ret;
-}
-
-static int vpbe_display_qbuf(struct file *file, void *priv,
- struct v4l2_buffer *p)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_QBUF, layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != p->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If this file handle is not allowed to do IO, return error */
- if (!fh->io_allowed) {
- v4l2_err(&vpbe_dev->v4l2_dev, "No io_allowed\n");
- return -EACCES;
- }
-
- return vb2_qbuf(&layer->buffer_queue, p);
-}
-
-static int vpbe_display_querybuf(struct file *file, void *priv,
- struct v4l2_buffer *buf)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "VIDIOC_QUERYBUF, layer id = %d\n",
- layer->device_id);
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != buf->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
- /* Call vb2_querybuf to get information */
- return vb2_querybuf(&layer->buffer_queue, buf);
-}
-
-static int vpbe_display_reqbufs(struct file *file, void *priv,
- struct v4l2_requestbuffers *req_buf)
-{
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- struct vb2_queue *q;
- int ret;
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_reqbufs\n");
-
- if (V4L2_BUF_TYPE_VIDEO_OUTPUT != req_buf->type) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Invalid buffer type\n");
- return -EINVAL;
- }
-
- /* If io users of the layer is not zero, return error */
- if (0 != layer->io_usrs) {
- v4l2_err(&vpbe_dev->v4l2_dev, "not IO user\n");
- return -EBUSY;
- }
- /* Initialize videobuf queue as per the buffer type */
- layer->alloc_ctx = vb2_dma_contig_init_ctx(vpbe_dev->pdev);
- if (IS_ERR(layer->alloc_ctx)) {
- v4l2_err(&vpbe_dev->v4l2_dev, "Failed to get the context\n");
- return PTR_ERR(layer->alloc_ctx);
- }
- q = &layer->buffer_queue;
- memset(q, 0, sizeof(*q));
- q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
- q->io_modes = VB2_MMAP | VB2_USERPTR;
- q->drv_priv = fh;
- q->ops = &video_qops;
- q->mem_ops = &vb2_dma_contig_memops;
- q->buf_struct_size = sizeof(struct vpbe_disp_buffer);
- q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
- q->min_buffers_needed = 1;
-
- ret = vb2_queue_init(q);
- if (ret) {
- v4l2_err(&vpbe_dev->v4l2_dev, "vb2_queue_init() failed\n");
- vb2_dma_contig_cleanup_ctx(layer->alloc_ctx);
- return ret;
- }
- /* Set io allowed member of file handle to TRUE */
- fh->io_allowed = 1;
- /* Increment io usrs member of layer object to 1 */
- layer->io_usrs = 1;
- /* Store type of memory requested in layer object */
- layer->memory = req_buf->memory;
- /* Initialize buffer queue */
- INIT_LIST_HEAD(&layer->dma_queue);
- /* Allocate buffers */
- return vb2_reqbufs(q, req_buf);
-}
-
-/*
- * vpbe_display_mmap()
- * It is used to map kernel space buffers into user spaces
- */
-static int vpbe_display_mmap(struct file *filep, struct vm_area_struct *vma)
-{
- /* Get the layer object and file handle object */
- struct vpbe_fh *fh = filep->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- int ret;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_mmap\n");
-
- if (mutex_lock_interruptible(&layer->opslock))
- return -ERESTARTSYS;
- ret = vb2_mmap(&layer->buffer_queue, vma);
- mutex_unlock(&layer->opslock);
- return ret;
-}
-
-/* vpbe_display_poll(): It is used for select/poll system call
- */
-static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
-{
- struct vpbe_fh *fh = filep->private_data;
- struct vpbe_layer *layer = fh->layer;
- struct vpbe_device *vpbe_dev = fh->disp_dev->vpbe_dev;
- unsigned int err = 0;
-
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_poll\n");
- if (layer->started) {
- mutex_lock(&layer->opslock);
- err = vb2_poll(&layer->buffer_queue, filep, wait);
- mutex_unlock(&layer->opslock);
- }
- return err;
-}
-
/*
* vpbe_display_open()
* It creates object of file handle structure and stores it in private_data
@@ -1475,30 +1149,22 @@ static unsigned int vpbe_display_poll(struct file *filep, poll_table *wait)
*/
static int vpbe_display_open(struct file *file)
{
- struct vpbe_fh *fh = NULL;
struct vpbe_layer *layer = video_drvdata(file);
- struct video_device *vdev = video_devdata(file);
struct vpbe_display *disp_dev = layer->disp_dev;
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
struct osd_state *osd_device = disp_dev->osd_device;
int err;
- /* Allocate memory for the file handle object */
- fh = kmalloc(sizeof(struct vpbe_fh), GFP_KERNEL);
- if (fh == NULL) {
- v4l2_err(&vpbe_dev->v4l2_dev,
- "unable to allocate memory for file handle object\n");
- return -ENOMEM;
+ /* creating context for file descriptor */
+ err = v4l2_fh_open(file);
+ if (err) {
+ v4l2_err(&vpbe_dev->v4l2_dev, "v4l2_fh_open failed\n");
+ return err;
}
- v4l2_fh_init(&fh->fh, vdev);
- v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
- "vpbe display open plane = %d\n",
- layer->device_id);
- /* store pointer to fh in private_data member of filep */
- file->private_data = fh;
- fh->layer = layer;
- fh->disp_dev = disp_dev;
+ /* leaving if layer is already initialized */
+ if (!v4l2_fh_is_singular_file(file))
+ return err;
if (!layer->usrs) {
if (mutex_lock_interruptible(&layer->opslock))
@@ -1511,15 +1177,12 @@ static int vpbe_display_open(struct file *file)
/* Couldn't get layer */
v4l2_err(&vpbe_dev->v4l2_dev,
"Display Manager failed to allocate layer\n");
- kfree(fh);
+ v4l2_fh_release(file);
return -EINVAL;
}
}
/* Increment layer usrs counter */
layer->usrs++;
- /* Set io_allowed member to false */
- fh->io_allowed = 0;
- v4l2_fh_add(&fh->fh);
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev,
"vpbe display device opened successfully\n");
return 0;
@@ -1532,30 +1195,18 @@ static int vpbe_display_open(struct file *file)
*/
static int vpbe_display_release(struct file *file)
{
- /* Get the layer object and file handle object */
- struct vpbe_fh *fh = file->private_data;
- struct vpbe_layer *layer = fh->layer;
+ struct vpbe_layer *layer = video_drvdata(file);
struct osd_layer_config *cfg = &layer->layer_info.config;
- struct vpbe_display *disp_dev = fh->disp_dev;
+ struct vpbe_display *disp_dev = layer->disp_dev;
struct vpbe_device *vpbe_dev = disp_dev->vpbe_dev;
struct osd_state *osd_device = disp_dev->osd_device;
v4l2_dbg(1, debug, &vpbe_dev->v4l2_dev, "vpbe_display_release\n");
mutex_lock(&layer->opslock);
- /* if this instance is doing IO */
- if (fh->io_allowed) {
- /* Reset io_usrs member of layer object */
- layer->io_usrs = 0;
-
- osd_device->ops.disable_layer(osd_device,
- layer->layer_info.id);
- layer->started = 0;
- /* Free buffers allocated */
- vb2_queue_release(&layer->buffer_queue);
- vb2_dma_contig_cleanup_ctx(&layer->buffer_queue);
- }
+ osd_device->ops.disable_layer(osd_device,
+ layer->layer_info.id);
/* Decrement layer usrs counter */
layer->usrs--;
/* If this file handle has initialize encoder device, reset it */
@@ -1575,14 +1226,9 @@ static int vpbe_display_release(struct file *file)
layer->layer_info.id);
}
- v4l2_fh_del(&fh->fh);
- v4l2_fh_exit(&fh->fh);
- file->private_data = NULL;
+ _vb2_fop_release(file, NULL);
mutex_unlock(&layer->opslock);
- /* Free memory allocated to file handle object */
- kfree(fh);
-
disp_dev->cbcr_ofst = 0;
return 0;
@@ -1595,20 +1241,27 @@ static const struct v4l2_ioctl_ops vpbe_ioctl_ops = {
.vidioc_enum_fmt_vid_out = vpbe_display_enum_fmt,
.vidioc_s_fmt_vid_out = vpbe_display_s_fmt,
.vidioc_try_fmt_vid_out = vpbe_display_try_fmt,
- .vidioc_reqbufs = vpbe_display_reqbufs,
- .vidioc_querybuf = vpbe_display_querybuf,
- .vidioc_qbuf = vpbe_display_qbuf,
- .vidioc_dqbuf = vpbe_display_dqbuf,
- .vidioc_streamon = vpbe_display_streamon,
- .vidioc_streamoff = vpbe_display_streamoff,
+
+ .vidioc_reqbufs = vb2_ioctl_reqbufs,
+ .vidioc_create_bufs = vb2_ioctl_create_bufs,
+ .vidioc_querybuf = vb2_ioctl_querybuf,
+ .vidioc_qbuf = vb2_ioctl_qbuf,
+ .vidioc_dqbuf = vb2_ioctl_dqbuf,
+ .vidioc_streamon = vb2_ioctl_streamon,
+ .vidioc_streamoff = vb2_ioctl_streamoff,
+ .vidioc_expbuf = vb2_ioctl_expbuf,
+
.vidioc_cropcap = vpbe_display_cropcap,
.vidioc_g_crop = vpbe_display_g_crop,
.vidioc_s_crop = vpbe_display_s_crop,
+
.vidioc_s_std = vpbe_display_s_std,
.vidioc_g_std = vpbe_display_g_std,
+
.vidioc_enum_output = vpbe_display_enum_output,
.vidioc_s_output = vpbe_display_s_output,
.vidioc_g_output = vpbe_display_g_output,
+
.vidioc_s_dv_timings = vpbe_display_s_dv_timings,
.vidioc_g_dv_timings = vpbe_display_g_dv_timings,
.vidioc_enum_dv_timings = vpbe_display_enum_dv_timings,
@@ -1619,8 +1272,8 @@ static struct v4l2_file_operations vpbe_fops = {
.open = vpbe_display_open,
.release = vpbe_display_release,
.unlocked_ioctl = video_ioctl2,
- .mmap = vpbe_display_mmap,
- .poll = vpbe_display_poll
+ .mmap = vb2_fop_mmap,
+ .poll = vb2_fop_poll,
};
static int vpbe_device_get(struct device *dev, void *data)
@@ -1700,6 +1353,7 @@ static int register_device(struct vpbe_layer *vpbe_display_layer,
(int)vpbe_display_layer,
(int)&vpbe_display_layer->video_dev);
+ vpbe_display_layer->video_dev.queue = &vpbe_display_layer->buffer_queue;
err = video_register_device(&vpbe_display_layer->video_dev,
VFL_TYPE_GRABBER,
-1);
@@ -1724,9 +1378,10 @@ static int register_device(struct vpbe_layer *vpbe_display_layer,
*/
static int vpbe_display_probe(struct platform_device *pdev)
{
- struct vpbe_layer *vpbe_display_layer;
struct vpbe_display *disp_dev;
+ struct v4l2_device *v4l2_dev;
struct resource *res = NULL;
+ struct vb2_queue *q;
int k;
int i;
int err;
@@ -1748,13 +1403,14 @@ static int vpbe_display_probe(struct platform_device *pdev)
vpbe_device_get);
if (err < 0)
return err;
+
+ v4l2_dev = &disp_dev->vpbe_dev->v4l2_dev;
/* Initialize the vpbe display controller */
if (NULL != disp_dev->vpbe_dev->ops.initialize) {
err = disp_dev->vpbe_dev->ops.initialize(&pdev->dev,
disp_dev->vpbe_dev);
if (err) {
- v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
- "Error initing vpbe\n");
+ v4l2_err(v4l2_dev, "Error initing vpbe\n");
err = -ENOMEM;
goto probe_out;
}
@@ -1769,8 +1425,7 @@ static int vpbe_display_probe(struct platform_device *pdev)
res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!res) {
- v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
- "Unable to get VENC interrupt resource\n");
+ v4l2_err(v4l2_dev, "Unable to get VENC interrupt resource\n");
err = -ENODEV;
goto probe_out;
}
@@ -1779,30 +1434,57 @@ static int vpbe_display_probe(struct platform_device *pdev)
err = devm_request_irq(&pdev->dev, irq, venc_isr, 0,
VPBE_DISPLAY_DRIVER, disp_dev);
if (err) {
- v4l2_err(&disp_dev->vpbe_dev->v4l2_dev,
- "Unable to request interrupt\n");
+ v4l2_err(v4l2_dev, "VPBE IRQ request failed\n");
goto probe_out;
}
for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
+ /* initialize vb2 queue */
+ q = &disp_dev->dev[i]->buffer_queue;
+ memset(q, 0, sizeof(*q));
+ q->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ q->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
+ q->drv_priv = disp_dev->dev[i];
+ q->ops = &video_qops;
+ q->mem_ops = &vb2_dma_contig_memops;
+ q->buf_struct_size = sizeof(struct vpbe_disp_buffer);
+ q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
+ q->min_buffers_needed = 1;
+ q->lock = &disp_dev->dev[i]->opslock;
+ err = vb2_queue_init(q);
+ if (err) {
+ v4l2_err(v4l2_dev, "vb2_queue_init() failed\n");
+ goto probe_out;
+ }
+
+ disp_dev->dev[i]->alloc_ctx =
+ vb2_dma_contig_init_ctx(disp_dev->vpbe_dev->pdev);
+ if (IS_ERR(disp_dev->dev[i]->alloc_ctx)) {
+ v4l2_err(v4l2_dev, "Failed to get the context\n");
+ err = PTR_ERR(disp_dev->dev[i]->alloc_ctx);
+ goto probe_out;
+ }
+
+ INIT_LIST_HEAD(&disp_dev->dev[i]->dma_queue);
+
if (register_device(disp_dev->dev[i], disp_dev, pdev)) {
err = -ENODEV;
goto probe_out;
}
}
- printk(KERN_DEBUG "Successfully completed the probing of vpbe v4l2 device\n");
+ v4l2_dbg(1, debug, v4l2_dev,
+ "Successfully completed the probing of vpbe v4l2 device\n");
+
return 0;
probe_out:
for (k = 0; k < VPBE_DISPLAY_MAX_DEVICES; k++) {
- /* Get the pointer to the layer object */
- vpbe_display_layer = disp_dev->dev[k];
/* Unregister video device */
- if (vpbe_display_layer) {
- video_unregister_device(
- &vpbe_display_layer->video_dev);
- kfree(disp_dev->dev[k]);
+ if (disp_dev->dev[k] != NULL) {
+ vb2_dma_contig_cleanup_ctx(disp_dev->dev[k]->alloc_ctx);
+ video_unregister_device(&disp_dev->dev[k]->video_dev);
+ kfree(disp_dev->dev[k]);
}
}
return err;
@@ -1828,6 +1510,7 @@ static int vpbe_display_remove(struct platform_device *pdev)
for (i = 0; i < VPBE_DISPLAY_MAX_DEVICES; i++) {
/* Get the pointer to the layer object */
vpbe_display_layer = disp_dev->dev[i];
+ vb2_dma_contig_cleanup_ctx(vpbe_display_layer->alloc_ctx);
/* Unregister video device */
video_unregister_device(&vpbe_display_layer->video_dev);
diff --git a/drivers/media/platform/davinci/vpfe_capture.c b/drivers/media/platform/davinci/vpfe_capture.c
index de55f47..271c460 100644
--- a/drivers/media/platform/davinci/vpfe_capture.c
+++ b/drivers/media/platform/davinci/vpfe_capture.c
@@ -414,13 +414,13 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
/* assume V4L2_PIX_FMT_UYVY as default */
pix->pixelformat = V4L2_PIX_FMT_UYVY;
v4l2_fill_mbus_format(&mbus_fmt, pix,
- V4L2_MBUS_FMT_YUYV10_2X10);
+ MEDIA_BUS_FMT_YUYV10_2X10);
} else {
pix->field = V4L2_FIELD_NONE;
/* assume V4L2_PIX_FMT_SBGGR8 */
pix->pixelformat = V4L2_PIX_FMT_SBGGR8;
v4l2_fill_mbus_format(&mbus_fmt, pix,
- V4L2_MBUS_FMT_SBGGR8_1X8);
+ MEDIA_BUS_FMT_SBGGR8_1X8);
}
/* if sub device supports g_mbus_fmt, override the defaults */
@@ -930,8 +930,8 @@ static int vpfe_querycap(struct file *file, void *priv,
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
- cap->version = VPFE_CAPTURE_VERSION_CODE;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 3ccb26f..d8e1b98 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -311,6 +311,8 @@ static struct vb2_ops video_qops = {
.start_streaming = vpif_start_streaming,
.stop_streaming = vpif_stop_streaming,
.buf_queue = vpif_buffer_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/**
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.c b/drivers/media/platform/exynos-gsc/gsc-core.c
index b4c9f1d..3062e9f 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.c
+++ b/drivers/media/platform/exynos-gsc/gsc-core.c
@@ -54,7 +54,7 @@ static const struct gsc_fmt gsc_formats[] = {
.corder = GSC_CBCR,
.num_planes = 1,
.num_comp = 1,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
}, {
.name = "YUV 4:2:2 packed, CbYCrY",
.pixelformat = V4L2_PIX_FMT_UYVY,
@@ -64,7 +64,7 @@ static const struct gsc_fmt gsc_formats[] = {
.corder = GSC_CBCR,
.num_planes = 1,
.num_comp = 1,
- .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
.pixelformat = V4L2_PIX_FMT_VYUY,
@@ -74,7 +74,7 @@ static const struct gsc_fmt gsc_formats[] = {
.corder = GSC_CRCB,
.num_planes = 1,
.num_comp = 1,
- .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
.pixelformat = V4L2_PIX_FMT_YVYU,
@@ -84,7 +84,7 @@ static const struct gsc_fmt gsc_formats[] = {
.corder = GSC_CRCB,
.num_planes = 1,
.num_comp = 1,
- .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
}, {
.name = "YUV 4:4:4 planar, YCbYCr",
.pixelformat = V4L2_PIX_FMT_YUV32,
@@ -319,21 +319,22 @@ int gsc_enum_fmt_mplane(struct v4l2_fmtdesc *f)
return 0;
}
-static u32 get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index)
+static int get_plane_info(struct gsc_frame *frm, u32 addr, u32 *index, u32 *ret_addr)
{
if (frm->addr.y == addr) {
*index = 0;
- return frm->addr.y;
+ *ret_addr = frm->addr.y;
} else if (frm->addr.cb == addr) {
*index = 1;
- return frm->addr.cb;
+ *ret_addr = frm->addr.cb;
} else if (frm->addr.cr == addr) {
*index = 2;
- return frm->addr.cr;
+ *ret_addr = frm->addr.cr;
} else {
pr_err("Plane address is wrong");
return -EINVAL;
}
+ return 0;
}
void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
@@ -352,9 +353,11 @@ void gsc_set_prefbuf(struct gsc_dev *gsc, struct gsc_frame *frm)
u32 t_min, t_max;
t_min = min3(frm->addr.y, frm->addr.cb, frm->addr.cr);
- low_addr = get_plane_info(frm, t_min, &low_plane);
+ if (get_plane_info(frm, t_min, &low_plane, &low_addr))
+ return;
t_max = max3(frm->addr.y, frm->addr.cb, frm->addr.cr);
- high_addr = get_plane_info(frm, t_max, &high_plane);
+ if (get_plane_info(frm, t_max, &high_plane, &high_addr))
+ return;
mid_plane = 3 - (low_plane + high_plane);
if (mid_plane == 0)
diff --git a/drivers/media/platform/exynos-gsc/gsc-core.h b/drivers/media/platform/exynos-gsc/gsc-core.h
index ef0a656..0abdb17 100644
--- a/drivers/media/platform/exynos-gsc/gsc-core.h
+++ b/drivers/media/platform/exynos-gsc/gsc-core.h
@@ -117,7 +117,7 @@ enum gsc_yuv_fmt {
* @flags: flags indicating which operation mode format applies to
*/
struct gsc_fmt {
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
char *name;
u32 pixelformat;
u32 color;
diff --git a/drivers/media/platform/exynos4-is/fimc-capture.c b/drivers/media/platform/exynos4-is/fimc-capture.c
index 3d2babd..8a2fd8c 100644
--- a/drivers/media/platform/exynos4-is/fimc-capture.c
+++ b/drivers/media/platform/exynos4-is/fimc-capture.c
@@ -749,7 +749,7 @@ static int fimc_cap_enum_fmt_mplane(struct file *file, void *priv,
return -EINVAL;
strncpy(f->description, fmt->name, sizeof(f->description) - 1);
f->pixelformat = fmt->fourcc;
- if (fmt->fourcc == V4L2_MBUS_FMT_JPEG_1X8)
+ if (fmt->fourcc == MEDIA_BUS_FMT_JPEG_1X8)
f->flags |= V4L2_FMT_FLAG_COMPRESSED;
return 0;
}
diff --git a/drivers/media/platform/exynos4-is/fimc-core.c b/drivers/media/platform/exynos4-is/fimc-core.c
index aee92d9..2acc195 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.c
+++ b/drivers/media/platform/exynos4-is/fimc-core.c
@@ -81,7 +81,7 @@ static struct fimc_fmt fimc_formats[] = {
.flags = FMT_FLAGS_M2M_OUT | FMT_HAS_ALPHA,
}, {
.name = "YUV 4:4:4",
- .mbus_code = V4L2_MBUS_FMT_YUV10_1X30,
+ .mbus_code = MEDIA_BUS_FMT_YUV10_1X30,
.flags = FMT_FLAGS_WRITEBACK,
}, {
.name = "YUV 4:2:2 packed, YCbYCr",
@@ -90,7 +90,7 @@ static struct fimc_fmt fimc_formats[] = {
.color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
.colplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, CbYCrY",
@@ -99,7 +99,7 @@ static struct fimc_fmt fimc_formats[] = {
.color = FIMC_FMT_CBYCRY422,
.memplanes = 1,
.colplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
@@ -108,7 +108,7 @@ static struct fimc_fmt fimc_formats[] = {
.color = FIMC_FMT_CRYCBY422,
.memplanes = 1,
.colplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
@@ -117,7 +117,7 @@ static struct fimc_fmt fimc_formats[] = {
.color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
.colplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
.flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
}, {
.name = "YUV 4:2:2 planar, Y/Cb/Cr",
@@ -190,7 +190,7 @@ static struct fimc_fmt fimc_formats[] = {
.depth = { 8 },
.memplanes = 1,
.colplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_JPEG_1X8,
+ .mbus_code = MEDIA_BUS_FMT_JPEG_1X8,
.flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
}, {
.name = "S5C73MX interleaved UYVY/JPEG",
@@ -200,7 +200,7 @@ static struct fimc_fmt fimc_formats[] = {
.memplanes = 2,
.colplanes = 1,
.mdataplanes = 0x2, /* plane 1 holds frame meta data */
- .mbus_code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
+ .mbus_code = MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8,
.flags = FMT_FLAGS_CAM | FMT_FLAGS_COMPRESSED,
},
};
@@ -832,7 +832,7 @@ err:
return -ENXIO;
}
-#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
+#ifdef CONFIG_PM
static int fimc_m2m_suspend(struct fimc_dev *fimc)
{
unsigned long flags;
@@ -871,7 +871,7 @@ static int fimc_m2m_resume(struct fimc_dev *fimc)
return 0;
}
-#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
static const struct of_device_id fimc_of_match[];
@@ -1039,7 +1039,7 @@ err_sclk:
return ret;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int fimc_runtime_resume(struct device *dev)
{
struct fimc_dev *fimc = dev_get_drvdata(dev);
diff --git a/drivers/media/platform/exynos4-is/fimc-core.h b/drivers/media/platform/exynos4-is/fimc-core.h
index 6c75c6c..7328f08 100644
--- a/drivers/media/platform/exynos4-is/fimc-core.h
+++ b/drivers/media/platform/exynos4-is/fimc-core.h
@@ -579,8 +579,8 @@ static inline bool fimc_jpeg_fourcc(u32 pixelformat)
static inline bool fimc_user_defined_mbus_fmt(u32 code)
{
- return (code == V4L2_MBUS_FMT_JPEG_1X8 ||
- code == V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8);
+ return (code == MEDIA_BUS_FMT_JPEG_1X8 ||
+ code == MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8);
}
/* Return the alpha component bit mask */
diff --git a/drivers/media/platform/exynos4-is/fimc-is-i2c.c b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
index 371cad4..d830331 100644
--- a/drivers/media/platform/exynos4-is/fimc-is-i2c.c
+++ b/drivers/media/platform/exynos4-is/fimc-is-i2c.c
@@ -81,7 +81,7 @@ static int fimc_is_i2c_remove(struct platform_device *pdev)
return 0;
}
-#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
+#ifdef CONFIG_PM
static int fimc_is_i2c_runtime_suspend(struct device *dev)
{
struct fimc_is_i2c *isp_i2c = dev_get_drvdata(dev);
diff --git a/drivers/media/platform/exynos4-is/fimc-is.c b/drivers/media/platform/exynos4-is/fimc-is.c
index 22162b2..2a0cbef 100644
--- a/drivers/media/platform/exynos4-is/fimc-is.c
+++ b/drivers/media/platform/exynos4-is/fimc-is.c
@@ -428,8 +428,7 @@ static void fimc_is_load_firmware(const struct firmware *fw, void *context)
* needed around for copying to the IS working memory every
* time before the Cortex-A5 is restarted.
*/
- if (is->fw.f_w)
- release_firmware(is->fw.f_w);
+ release_firmware(is->fw.f_w);
is->fw.f_w = fw;
done:
mutex_unlock(&is->lock);
@@ -814,9 +813,9 @@ static int fimc_is_probe(struct platform_device *pdev)
return -ENOMEM;
is->irq = irq_of_parse_and_map(dev->of_node, 0);
- if (is->irq < 0) {
+ if (!is->irq) {
dev_err(dev, "no irq found\n");
- return is->irq;
+ return -EINVAL;
}
ret = fimc_is_get_clocks(is);
@@ -937,8 +936,7 @@ static int fimc_is_remove(struct platform_device *pdev)
vb2_dma_contig_cleanup_ctx(is->alloc_ctx);
fimc_is_put_clocks(is);
fimc_is_debugfs_remove(is);
- if (is->fw.f_w)
- release_firmware(is->fw.f_w);
+ release_firmware(is->fw.f_w);
fimc_is_free_cpu_memory(is);
return 0;
diff --git a/drivers/media/platform/exynos4-is/fimc-isp.c b/drivers/media/platform/exynos4-is/fimc-isp.c
index be62d6b..60c7449 100644
--- a/drivers/media/platform/exynos4-is/fimc-isp.c
+++ b/drivers/media/platform/exynos4-is/fimc-isp.c
@@ -41,21 +41,21 @@ static const struct fimc_fmt fimc_isp_formats[FIMC_ISP_NUM_FORMATS] = {
.depth = { 8 },
.color = FIMC_FMT_RAW8,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
}, {
.name = "RAW10 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG10,
.depth = { 10 },
.color = FIMC_FMT_RAW10,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
}, {
.name = "RAW12 (GRBG)",
.fourcc = V4L2_PIX_FMT_SGRBG12,
.depth = { 12 },
.color = FIMC_FMT_RAW12,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
},
};
@@ -149,7 +149,7 @@ static int fimc_isp_subdev_get_fmt(struct v4l2_subdev *sd,
if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
mf->colorspace = V4L2_COLORSPACE_JPEG;
- mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+ mf->code = MEDIA_BUS_FMT_YUV10_1X30;
}
}
@@ -175,7 +175,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
FIMC_ISP_SINK_WIDTH_MAX, 0,
&mf->height, FIMC_ISP_SINK_HEIGHT_MIN,
FIMC_ISP_SINK_HEIGHT_MAX, 0, 0);
- mf->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ mf->code = MEDIA_BUS_FMT_SGRBG10_1X10;
} else {
if (fmt->which == V4L2_SUBDEV_FORMAT_TRY)
format = v4l2_subdev_get_try_format(fh,
@@ -188,7 +188,7 @@ static void __isp_subdev_try_format(struct fimc_isp *isp,
mf->height = format->height - FIMC_ISP_CAC_MARGIN_HEIGHT;
if (fmt->pad == FIMC_ISP_SD_PAD_SRC_FIFO) {
- mf->code = V4L2_MBUS_FMT_YUV10_1X30;
+ mf->code = MEDIA_BUS_FMT_YUV10_1X30;
mf->colorspace = V4L2_COLORSPACE_JPEG;
} else {
mf->code = format->code;
@@ -680,11 +680,11 @@ static void __isp_subdev_set_default_format(struct fimc_isp *isp)
FIMC_ISP_CAC_MARGIN_WIDTH;
isp->sink_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT +
FIMC_ISP_CAC_MARGIN_HEIGHT;
- isp->sink_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ isp->sink_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10;
isp->src_fmt.width = DEFAULT_PREVIEW_STILL_WIDTH;
isp->src_fmt.height = DEFAULT_PREVIEW_STILL_HEIGHT;
- isp->src_fmt.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ isp->src_fmt.code = MEDIA_BUS_FMT_SGRBG10_1X10;
__is_set_frame_size(is, &isp->src_fmt);
}
diff --git a/drivers/media/platform/exynos4-is/fimc-lite-reg.c b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
index bc3ec7d..0477716 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite-reg.c
@@ -112,24 +112,24 @@ void flite_hw_set_test_pattern(struct fimc_lite *dev, bool on)
}
static const u32 src_pixfmt_map[8][3] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
+ { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCBYCR,
FLITE_REG_CIGCTRL_YUV422_1P },
- { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
+ { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_YCRYCB,
FLITE_REG_CIGCTRL_YUV422_1P },
- { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
+ { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CBYCRY,
FLITE_REG_CIGCTRL_YUV422_1P },
- { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
+ { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CISRCSIZE_ORDER422_IN_CRYCBY,
FLITE_REG_CIGCTRL_YUV422_1P },
- { V4L2_MBUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 },
- { V4L2_MBUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 },
- { V4L2_MBUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 },
- { V4L2_MBUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
+ { MEDIA_BUS_FMT_SGRBG8_1X8, 0, FLITE_REG_CIGCTRL_RAW8 },
+ { MEDIA_BUS_FMT_SGRBG10_1X10, 0, FLITE_REG_CIGCTRL_RAW10 },
+ { MEDIA_BUS_FMT_SGRBG12_1X12, 0, FLITE_REG_CIGCTRL_RAW12 },
+ { MEDIA_BUS_FMT_JPEG_1X8, 0, FLITE_REG_CIGCTRL_USER(1) },
};
/* Set camera input pixel format and resolution */
void flite_hw_set_source_format(struct fimc_lite *dev, struct flite_frame *f)
{
- enum v4l2_mbus_pixelcode pixelcode = f->fmt->mbus_code;
+ u32 pixelcode = f->fmt->mbus_code;
int i = ARRAY_SIZE(src_pixfmt_map);
u32 cfg;
@@ -232,10 +232,10 @@ static void flite_hw_set_pack12(struct fimc_lite *dev, int on)
static void flite_hw_set_out_order(struct fimc_lite *dev, struct flite_frame *f)
{
static const u32 pixcode[4][2] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
- { V4L2_MBUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
- { V4L2_MBUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
- { V4L2_MBUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
+ { MEDIA_BUS_FMT_YUYV8_2X8, FLITE_REG_CIODMAFMT_YCBYCR },
+ { MEDIA_BUS_FMT_YVYU8_2X8, FLITE_REG_CIODMAFMT_YCRYCB },
+ { MEDIA_BUS_FMT_UYVY8_2X8, FLITE_REG_CIODMAFMT_CBYCRY },
+ { MEDIA_BUS_FMT_VYUY8_2X8, FLITE_REG_CIODMAFMT_CRYCBY },
};
u32 cfg = readl(dev->regs + FLITE_REG_CIODMAFMT);
int i = ARRAY_SIZE(pixcode);
diff --git a/drivers/media/platform/exynos4-is/fimc-lite.c b/drivers/media/platform/exynos4-is/fimc-lite.c
index a97d235..7e86873 100644
--- a/drivers/media/platform/exynos4-is/fimc-lite.c
+++ b/drivers/media/platform/exynos4-is/fimc-lite.c
@@ -48,7 +48,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 16 },
.color = FIMC_FMT_YCBYCR422,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, CbYCrY",
@@ -57,7 +57,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 16 },
.color = FIMC_FMT_CBYCRY422,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_UYVY8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, CrYCbY",
@@ -66,7 +66,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 16 },
.color = FIMC_FMT_CRYCBY422,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_VYUY8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "YUV 4:2:2 packed, YCrYCb",
@@ -75,7 +75,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 16 },
.color = FIMC_FMT_YCRYCB422,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YVYU8_2X8,
.flags = FMT_FLAGS_YUV,
}, {
.name = "RAW8 (GRBG)",
@@ -84,7 +84,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 8 },
.color = FIMC_FMT_RAW8,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG8_1X8,
.flags = FMT_FLAGS_RAW_BAYER,
}, {
.name = "RAW10 (GRBG)",
@@ -93,7 +93,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 16 },
.color = FIMC_FMT_RAW10,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG10_1X10,
.flags = FMT_FLAGS_RAW_BAYER,
}, {
.name = "RAW12 (GRBG)",
@@ -102,7 +102,7 @@ static const struct fimc_fmt fimc_lite_formats[] = {
.depth = { 16 },
.color = FIMC_FMT_RAW12,
.memplanes = 1,
- .mbus_code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .mbus_code = MEDIA_BUS_FMT_SGRBG12_1X12,
.flags = FMT_FLAGS_RAW_BAYER,
},
};
@@ -1588,7 +1588,7 @@ err_clk_put:
return ret;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int fimc_lite_runtime_resume(struct device *dev)
{
struct fimc_lite *fimc = dev_get_drvdata(dev);
diff --git a/drivers/media/platform/exynos4-is/fimc-reg.c b/drivers/media/platform/exynos4-is/fimc-reg.c
index 2d77fd8..df0cbcb 100644
--- a/drivers/media/platform/exynos4-is/fimc-reg.c
+++ b/drivers/media/platform/exynos4-is/fimc-reg.c
@@ -592,10 +592,10 @@ struct mbus_pixfmt_desc {
};
static const struct mbus_pixfmt_desc pix_desc[] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 },
- { V4L2_MBUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 },
- { V4L2_MBUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 },
- { V4L2_MBUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 },
+ { MEDIA_BUS_FMT_YUYV8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCBYCR, 8 },
+ { MEDIA_BUS_FMT_YVYU8_2X8, FIMC_REG_CISRCFMT_ORDER422_YCRYCB, 8 },
+ { MEDIA_BUS_FMT_VYUY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CRYCBY, 8 },
+ { MEDIA_BUS_FMT_UYVY8_2X8, FIMC_REG_CISRCFMT_ORDER422_CBYCRY, 8 },
};
int fimc_hw_set_camera_source(struct fimc_dev *fimc,
@@ -689,11 +689,11 @@ int fimc_hw_set_camera_type(struct fimc_dev *fimc,
/* TODO: add remaining supported formats. */
switch (vid_cap->ci_fmt.code) {
- case V4L2_MBUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
tmp = FIMC_REG_CSIIMGFMT_YCBCR422_8BIT;
break;
- case V4L2_MBUS_FMT_JPEG_1X8:
- case V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8:
+ case MEDIA_BUS_FMT_JPEG_1X8:
+ case MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8:
tmp = FIMC_REG_CSIIMGFMT_USER(1);
cfg |= FIMC_REG_CIGCTRL_CAM_JPEG;
break;
diff --git a/drivers/media/platform/exynos4-is/mipi-csis.c b/drivers/media/platform/exynos4-is/mipi-csis.c
index db6fd14..9e1056d 100644
--- a/drivers/media/platform/exynos4-is/mipi-csis.c
+++ b/drivers/media/platform/exynos4-is/mipi-csis.c
@@ -238,34 +238,34 @@ struct csis_state {
*/
struct csis_pix_format {
unsigned int pix_width_alignment;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
u32 fmt_reg;
u8 data_alignment;
};
static const struct csis_pix_format s5pcsis_formats[] = {
{
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.fmt_reg = S5PCSIS_CFG_FMT_YCBCR422_8BIT,
.data_alignment = 32,
}, {
- .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .code = MEDIA_BUS_FMT_JPEG_1X8,
.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
.data_alignment = 32,
}, {
- .code = V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8,
+ .code = MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8,
.fmt_reg = S5PCSIS_CFG_FMT_USER(1),
.data_alignment = 32,
}, {
- .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
.fmt_reg = S5PCSIS_CFG_FMT_RAW8,
.data_alignment = 24,
}, {
- .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
.fmt_reg = S5PCSIS_CFG_FMT_RAW10,
.data_alignment = 24,
}, {
- .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
.fmt_reg = S5PCSIS_CFG_FMT_RAW12,
.data_alignment = 24,
}
@@ -978,7 +978,7 @@ static int s5pcsis_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int s5pcsis_runtime_suspend(struct device *dev)
{
return s5pcsis_pm_suspend(dev, true);
diff --git a/drivers/media/platform/fsl-viu.c b/drivers/media/platform/fsl-viu.c
index d5dc198..8afee3c 100644
--- a/drivers/media/platform/fsl-viu.c
+++ b/drivers/media/platform/fsl-viu.c
@@ -604,10 +604,11 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strcpy(cap->driver, "viu");
strcpy(cap->card, "viu");
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_STREAMING |
V4L2_CAP_VIDEO_OVERLAY |
V4L2_CAP_READWRITE;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.c b/drivers/media/platform/marvell-ccic/mcam-core.c
index 7a86c77..193373f 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.c
+++ b/drivers/media/platform/marvell-ccic/mcam-core.c
@@ -106,61 +106,61 @@ static struct mcam_format_struct {
__u32 pixelformat;
int bpp; /* Bytes per pixel */
bool planar;
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
} mcam_formats[] = {
{
.desc = "YUYV 4:2:2",
.pixelformat = V4L2_PIX_FMT_YUYV,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = false,
},
{
.desc = "UYVY 4:2:2",
.pixelformat = V4L2_PIX_FMT_UYVY,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = false,
},
{
.desc = "YUV 4:2:2 PLANAR",
.pixelformat = V4L2_PIX_FMT_YUV422P,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = true,
},
{
.desc = "YUV 4:2:0 PLANAR",
.pixelformat = V4L2_PIX_FMT_YUV420,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = true,
},
{
.desc = "YVU 4:2:0 PLANAR",
.pixelformat = V4L2_PIX_FMT_YVU420,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
.planar = true,
},
{
.desc = "RGB 444",
.pixelformat = V4L2_PIX_FMT_RGB444,
- .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE,
.bpp = 2,
.planar = false,
},
{
.desc = "RGB 565",
.pixelformat = V4L2_PIX_FMT_RGB565,
- .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .mbus_code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.bpp = 2,
.planar = false,
},
{
.desc = "Raw RGB Bayer",
.pixelformat = V4L2_PIX_FMT_SBGGR8,
- .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .mbus_code = MEDIA_BUS_FMT_SBGGR8_1X8,
.bpp = 1,
.planar = false,
},
@@ -190,8 +190,7 @@ static const struct v4l2_pix_format mcam_def_pix_format = {
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
};
-static const enum v4l2_mbus_pixelcode mcam_def_mbus_code =
- V4L2_MBUS_FMT_YUYV8_2X8;
+static const u32 mcam_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8;
/*
@@ -1080,6 +1079,8 @@ static int mcam_vb_queue_setup(struct vb2_queue *vq,
*nbufs = minbufs;
if (cam->buffer_mode == B_DMA_contig)
alloc_ctxs[0] = cam->vb_alloc_ctx;
+ else if (cam->buffer_mode == B_DMA_sg)
+ alloc_ctxs[0] = cam->vb_alloc_ctx_sg;
return 0;
}
@@ -1101,26 +1102,6 @@ static void mcam_vb_buf_queue(struct vb2_buffer *vb)
mcam_read_setup(cam);
}
-
-/*
- * vb2 uses these to release the mutex when waiting in dqbuf. I'm
- * not actually sure we need to do this (I'm not sure that vb2_dqbuf() needs
- * to be called with the mutex held), but better safe than sorry.
- */
-static void mcam_vb_wait_prepare(struct vb2_queue *vq)
-{
- struct mcam_camera *cam = vb2_get_drv_priv(vq);
-
- mutex_unlock(&cam->s_mutex);
-}
-
-static void mcam_vb_wait_finish(struct vb2_queue *vq)
-{
- struct mcam_camera *cam = vb2_get_drv_priv(vq);
-
- mutex_lock(&cam->s_mutex);
-}
-
/*
* These need to be called with the mutex held from vb2
*/
@@ -1190,8 +1171,8 @@ static const struct vb2_ops mcam_vb2_ops = {
.buf_queue = mcam_vb_buf_queue,
.start_streaming = mcam_vb_start_streaming,
.stop_streaming = mcam_vb_stop_streaming,
- .wait_prepare = mcam_vb_wait_prepare,
- .wait_finish = mcam_vb_wait_finish,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
@@ -1219,17 +1200,12 @@ static int mcam_vb_sg_buf_init(struct vb2_buffer *vb)
static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
{
struct mcam_vb_buffer *mvb = vb_to_mvb(vb);
- struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0);
struct mcam_dma_desc *desc = mvb->dma_desc;
struct scatterlist *sg;
int i;
- mvb->dma_desc_nent = dma_map_sg(cam->dev, sg_table->sgl,
- sg_table->nents, DMA_FROM_DEVICE);
- if (mvb->dma_desc_nent <= 0)
- return -EIO; /* Not sure what's right here */
- for_each_sg(sg_table->sgl, sg, mvb->dma_desc_nent, i) {
+ for_each_sg(sg_table->sgl, sg, sg_table->nents, i) {
desc->dma_addr = sg_dma_address(sg);
desc->segment_len = sg_dma_len(sg);
desc++;
@@ -1237,16 +1213,6 @@ static int mcam_vb_sg_buf_prepare(struct vb2_buffer *vb)
return 0;
}
-static void mcam_vb_sg_buf_finish(struct vb2_buffer *vb)
-{
- struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
- struct sg_table *sg_table = vb2_dma_sg_plane_desc(vb, 0);
-
- if (sg_table)
- dma_unmap_sg(cam->dev, sg_table->sgl,
- sg_table->nents, DMA_FROM_DEVICE);
-}
-
static void mcam_vb_sg_buf_cleanup(struct vb2_buffer *vb)
{
struct mcam_camera *cam = vb2_get_drv_priv(vb->vb2_queue);
@@ -1263,12 +1229,11 @@ static const struct vb2_ops mcam_vb2_sg_ops = {
.buf_init = mcam_vb_sg_buf_init,
.buf_prepare = mcam_vb_sg_buf_prepare,
.buf_queue = mcam_vb_buf_queue,
- .buf_finish = mcam_vb_sg_buf_finish,
.buf_cleanup = mcam_vb_sg_buf_cleanup,
.start_streaming = mcam_vb_start_streaming,
.stop_streaming = mcam_vb_stop_streaming,
- .wait_prepare = mcam_vb_wait_prepare,
- .wait_finish = mcam_vb_wait_finish,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
#endif /* MCAM_MODE_DMA_SG */
@@ -1280,6 +1245,7 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
memset(vq, 0, sizeof(*vq));
vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
vq->drv_priv = cam;
+ vq->lock = &cam->s_mutex;
INIT_LIST_HEAD(&cam->buffers);
switch (cam->buffer_mode) {
case B_DMA_contig:
@@ -1287,10 +1253,12 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
vq->ops = &mcam_vb2_ops;
vq->mem_ops = &vb2_dma_contig_memops;
vq->buf_struct_size = sizeof(struct mcam_vb_buffer);
- cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
vq->io_modes = VB2_MMAP | VB2_USERPTR;
cam->dma_setup = mcam_ctlr_dma_contig;
cam->frame_complete = mcam_dma_contig_done;
+ cam->vb_alloc_ctx = vb2_dma_contig_init_ctx(cam->dev);
+ if (IS_ERR(cam->vb_alloc_ctx))
+ return PTR_ERR(cam->vb_alloc_ctx);
#endif
break;
case B_DMA_sg:
@@ -1301,6 +1269,9 @@ static int mcam_setup_vb2(struct mcam_camera *cam)
vq->io_modes = VB2_MMAP | VB2_USERPTR;
cam->dma_setup = mcam_ctlr_dma_sg;
cam->frame_complete = mcam_dma_sg_done;
+ cam->vb_alloc_ctx_sg = vb2_dma_sg_init_ctx(cam->dev);
+ if (IS_ERR(cam->vb_alloc_ctx_sg))
+ return PTR_ERR(cam->vb_alloc_ctx_sg);
#endif
break;
case B_vmalloc:
@@ -1326,6 +1297,10 @@ static void mcam_cleanup_vb2(struct mcam_camera *cam)
if (cam->buffer_mode == B_DMA_contig)
vb2_dma_contig_cleanup_ctx(cam->vb_alloc_ctx);
#endif
+#ifdef MCAM_MODE_DMA_SG
+ if (cam->buffer_mode == B_DMA_sg)
+ vb2_dma_sg_cleanup_ctx(cam->vb_alloc_ctx_sg);
+#endif
}
@@ -1414,9 +1389,9 @@ static int mcam_vidioc_querycap(struct file *file, void *priv,
{
strcpy(cap->driver, "marvell_ccic");
strcpy(cap->card, "marvell_ccic");
- cap->version = 1;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/marvell-ccic/mcam-core.h b/drivers/media/platform/marvell-ccic/mcam-core.h
index e0e628c..aa0c6ea 100644
--- a/drivers/media/platform/marvell-ccic/mcam-core.h
+++ b/drivers/media/platform/marvell-ccic/mcam-core.h
@@ -176,6 +176,7 @@ struct mcam_camera {
/* DMA buffers - DMA modes */
struct mcam_vb_buffer *vb_bufs[MAX_DMA_BUFS];
struct vb2_alloc_ctx *vb_alloc_ctx;
+ struct vb2_alloc_ctx *vb_alloc_ctx_sg;
/* Mode-specific ops, set at open time */
void (*dma_setup)(struct mcam_camera *cam);
@@ -183,7 +184,7 @@ struct mcam_camera {
/* Current operating parameters */
struct v4l2_pix_format pix_format;
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
/* Locks */
struct mutex s_mutex; /* Access to this structure */
diff --git a/drivers/media/platform/mx2_emmaprp.c b/drivers/media/platform/mx2_emmaprp.c
index 4971ff2..f923d1b 100644
--- a/drivers/media/platform/mx2_emmaprp.c
+++ b/drivers/media/platform/mx2_emmaprp.c
@@ -402,13 +402,8 @@ static int vidioc_querycap(struct file *file, void *priv,
{
strncpy(cap->driver, MEM2MEM_NAME, sizeof(cap->driver) - 1);
strncpy(cap->card, MEM2MEM_NAME, sizeof(cap->card) - 1);
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/omap/Kconfig b/drivers/media/platform/omap/Kconfig
index 05de442..dc2aaab 100644
--- a/drivers/media/platform/omap/Kconfig
+++ b/drivers/media/platform/omap/Kconfig
@@ -3,7 +3,8 @@ config VIDEO_OMAP2_VOUT_VRFB
config VIDEO_OMAP2_VOUT
tristate "OMAP2/OMAP3 V4L2-Display driver"
- depends on ARCH_OMAP2 || ARCH_OMAP3 || (COMPILE_TEST && HAS_MMU)
+ depends on MMU
+ depends on ARCH_OMAP2 || ARCH_OMAP3
select VIDEOBUF_GEN
select VIDEOBUF_DMA_CONTIG
select OMAP2_DSS if HAS_IOMEM && ARCH_OMAP2PLUS
diff --git a/drivers/media/platform/omap/omap_vout.c b/drivers/media/platform/omap/omap_vout.c
index 64ab6fb..ba2d8f9 100644
--- a/drivers/media/platform/omap/omap_vout.c
+++ b/drivers/media/platform/omap/omap_vout.c
@@ -198,7 +198,7 @@ static int omap_vout_try_format(struct v4l2_pix_format *pix)
* omap_vout_uservirt_to_phys: This inline function is used to convert user
* space virtual address to physical address.
*/
-static u32 omap_vout_uservirt_to_phys(u32 virtp)
+static unsigned long omap_vout_uservirt_to_phys(unsigned long virtp)
{
unsigned long physp = 0;
struct vm_area_struct *vma;
@@ -418,10 +418,10 @@ static int omapvid_setup_overlay(struct omap_vout_device *vout,
}
v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev,
- "%s enable=%d addr=%x width=%d\n height=%d color_mode=%d\n"
+ "%s enable=%d addr=%pad width=%d\n height=%d color_mode=%d\n"
"rotation=%d mirror=%d posx=%d posy=%d out_width = %d \n"
"out_height=%d rotation_type=%d screen_width=%d\n",
- __func__, ovl->is_enabled(ovl), info.paddr, info.width, info.height,
+ __func__, ovl->is_enabled(ovl), &info.paddr, info.width, info.height,
info.color_mode, info.rotation, info.mirror, info.pos_x,
info.pos_y, info.out_width, info.out_height, info.rotation_type,
info.screen_width);
@@ -794,7 +794,7 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
vout->queued_buf_addr[vb->i] = (u8 *)
omap_vout_uservirt_to_phys(vb->baddr);
} else {
- u32 addr, dma_addr;
+ unsigned long addr, dma_addr;
unsigned long size;
addr = (unsigned long) vout->buf_virt_addr[vb->i];
@@ -1054,8 +1054,9 @@ static int vidioc_querycap(struct file *file, void *fh,
strlcpy(cap->driver, VOUT_NAME, sizeof(cap->driver));
strlcpy(cap->card, vout->vfd->name, sizeof(cap->card));
cap->bus_info[0] = '\0';
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_OUTPUT |
V4L2_CAP_VIDEO_OUTPUT_OVERLAY;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/omap3isp/ispccdc.c b/drivers/media/platform/omap3isp/ispccdc.c
index 81a9dc0..587489a 100644
--- a/drivers/media/platform/omap3isp/ispccdc.c
+++ b/drivers/media/platform/omap3isp/ispccdc.c
@@ -36,23 +36,23 @@ __ccdc_get_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
unsigned int pad, enum v4l2_subdev_format_whence which);
static const unsigned int ccdc_fmts[] = {
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y12_1X12,
- V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGRBG12_1X12,
- V4L2_MBUS_FMT_SRGGB12_1X12,
- V4L2_MBUS_FMT_SBGGR12_1X12,
- V4L2_MBUS_FMT_SGBRG12_1X12,
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_Y12_1X12,
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_SRGGB12_1X12,
+ MEDIA_BUS_FMT_SBGGR12_1X12,
+ MEDIA_BUS_FMT_SGBRG12_1X12,
+ MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
};
/*
@@ -266,10 +266,10 @@ static int __ccdc_lsc_enable(struct isp_ccdc_device *ccdc, int enable)
__ccdc_get_format(ccdc, NULL, CCDC_PAD_SINK,
V4L2_SUBDEV_FORMAT_ACTIVE);
- if ((format->code != V4L2_MBUS_FMT_SGRBG10_1X10) &&
- (format->code != V4L2_MBUS_FMT_SRGGB10_1X10) &&
- (format->code != V4L2_MBUS_FMT_SBGGR10_1X10) &&
- (format->code != V4L2_MBUS_FMT_SGBRG10_1X10))
+ if ((format->code != MEDIA_BUS_FMT_SGRBG10_1X10) &&
+ (format->code != MEDIA_BUS_FMT_SRGGB10_1X10) &&
+ (format->code != MEDIA_BUS_FMT_SBGGR10_1X10) &&
+ (format->code != MEDIA_BUS_FMT_SGBRG10_1X10))
return -EINVAL;
if (enable)
@@ -971,8 +971,8 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
format = &ccdc->formats[CCDC_PAD_SINK];
- if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
- format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ format->code == MEDIA_BUS_FMT_UYVY8_2X8) {
/* According to the OMAP3 TRM the input mode only affects SYNC
* mode, enabling BT.656 mode should take precedence. However,
* in practice setting the input mode to YCbCr data on 8 bits
@@ -1020,7 +1020,7 @@ static void ccdc_config_sync_if(struct isp_ccdc_device *ccdc,
/* The CCDC_CFG.Y8POS bit is used in YCbCr8 input mode only. The
* hardware seems to ignore it in all other input modes.
*/
- if (format->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ if (format->code == MEDIA_BUS_FMT_UYVY8_2X8)
isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
ISPCCDC_CFG_Y8POS);
else
@@ -1168,9 +1168,9 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
if (ccdc->bt656)
bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
- else if (fmt_info->code == V4L2_MBUS_FMT_YUYV8_2X8)
+ else if (fmt_info->code == MEDIA_BUS_FMT_YUYV8_2X8)
bridge = ISPCTRL_PAR_BRIDGE_LENDIAN;
- else if (fmt_info->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ else if (fmt_info->code == MEDIA_BUS_FMT_UYVY8_2X8)
bridge = ISPCTRL_PAR_BRIDGE_BENDIAN;
else
bridge = ISPCTRL_PAR_BRIDGE_DISABLE;
@@ -1199,16 +1199,16 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
/* Mosaic filter */
switch (format->code) {
- case V4L2_MBUS_FMT_SRGGB10_1X10:
- case V4L2_MBUS_FMT_SRGGB12_1X12:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SRGGB12_1X12:
ccdc_pattern = ccdc_srggb_pattern;
break;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- case V4L2_MBUS_FMT_SBGGR12_1X12:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
ccdc_pattern = ccdc_sbggr_pattern;
break;
- case V4L2_MBUS_FMT_SGBRG10_1X10:
- case V4L2_MBUS_FMT_SGBRG12_1X12:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG12_1X12:
ccdc_pattern = ccdc_sgbrg_pattern;
break;
default:
@@ -1267,7 +1267,7 @@ static void ccdc_configure(struct isp_ccdc_device *ccdc)
/* The CCDC outputs data in UYVY order by default. Swap bytes to get
* YUYV.
*/
- if (format->code == V4L2_MBUS_FMT_YUYV8_1X16)
+ if (format->code == MEDIA_BUS_FMT_YUYV8_1X16)
isp_reg_set(isp, OMAP3_ISP_IOMEM_CCDC, ISPCCDC_CFG,
ISPCCDC_CFG_BSWD);
else
@@ -1967,7 +1967,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
enum v4l2_subdev_format_whence which)
{
const struct isp_format_info *info;
- enum v4l2_mbus_pixelcode pixelcode;
+ u32 pixelcode;
unsigned int width = fmt->width;
unsigned int height = fmt->height;
struct v4l2_rect *crop;
@@ -1983,7 +1983,7 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
/* If not found, use SGRBG10 as default */
if (i >= ARRAY_SIZE(ccdc_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
/* Clamp the input size. */
fmt->width = clamp_t(u32, width, 32, 4096);
@@ -2007,19 +2007,19 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
* configured to pack bytes in BT.656, hiding the inaccuracy.
* In all cases bytes can be swapped.
*/
- if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
- fmt->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ fmt->code == MEDIA_BUS_FMT_UYVY8_2X8) {
/* Use the user requested format if YUV. */
- if (pixelcode == V4L2_MBUS_FMT_YUYV8_2X8 ||
- pixelcode == V4L2_MBUS_FMT_UYVY8_2X8 ||
- pixelcode == V4L2_MBUS_FMT_YUYV8_1X16 ||
- pixelcode == V4L2_MBUS_FMT_UYVY8_1X16)
+ if (pixelcode == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ pixelcode == MEDIA_BUS_FMT_UYVY8_2X8 ||
+ pixelcode == MEDIA_BUS_FMT_YUYV8_1X16 ||
+ pixelcode == MEDIA_BUS_FMT_UYVY8_1X16)
fmt->code = pixelcode;
- if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8)
- fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
- else if (fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
- fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8)
+ fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
+ else if (fmt->code == MEDIA_BUS_FMT_UYVY8_2X8)
+ fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
}
/* Hardcode the output size to the crop rectangle size. */
@@ -2047,8 +2047,8 @@ ccdc_try_format(struct isp_ccdc_device *ccdc, struct v4l2_subdev_fh *fh,
fmt->code = info->truncated;
/* YUV formats are not supported by the video port. */
- if (fmt->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
- fmt->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ if (fmt->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ fmt->code == MEDIA_BUS_FMT_UYVY8_2X8)
fmt->code = 0;
/* The number of lines that can be clocked out from the video
@@ -2083,7 +2083,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
* to keep the Bayer pattern.
*/
info = omap3isp_video_format_info(sink->code);
- if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+ if (info->flavor != MEDIA_BUS_FMT_Y8_1X8) {
crop->left &= ~1;
crop->top &= ~1;
}
@@ -2103,7 +2103,7 @@ static void ccdc_try_crop(struct isp_ccdc_device *ccdc,
sink->height - crop->top);
/* Odd width/height values don't make sense for Bayer formats. */
- if (info->flavor != V4L2_MBUS_FMT_Y8_1X8) {
+ if (info->flavor != MEDIA_BUS_FMT_Y8_1X8) {
crop->width &= ~1;
crop->height &= ~1;
}
@@ -2135,13 +2135,13 @@ static int ccdc_enum_mbus_code(struct v4l2_subdev *sd,
format = __ccdc_get_format(ccdc, fh, code->pad,
V4L2_SUBDEV_FORMAT_TRY);
- if (format->code == V4L2_MBUS_FMT_YUYV8_2X8 ||
- format->code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ if (format->code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ format->code == MEDIA_BUS_FMT_UYVY8_2X8) {
/* In YUV mode the CCDC can swap bytes. */
if (code->index == 0)
- code->code = V4L2_MBUS_FMT_YUYV8_1X16;
+ code->code = MEDIA_BUS_FMT_YUYV8_1X16;
else if (code->index == 1)
- code->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ code->code = MEDIA_BUS_FMT_UYVY8_1X16;
else
return -EINVAL;
} else {
@@ -2383,9 +2383,7 @@ static int ccdc_set_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
* return true if the combination is possible
* return false otherwise
*/
-static bool ccdc_is_shiftable(enum v4l2_mbus_pixelcode in,
- enum v4l2_mbus_pixelcode out,
- unsigned int additional_shift)
+static bool ccdc_is_shiftable(u32 in, u32 out, unsigned int additional_shift)
{
const struct isp_format_info *in_info, *out_info;
@@ -2452,7 +2450,7 @@ static int ccdc_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = CCDC_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
ccdc_set_format(sd, fh, &format);
diff --git a/drivers/media/platform/omap3isp/ispccp2.c b/drivers/media/platform/omap3isp/ispccp2.c
index 9cb49b3..f4aedb3 100644
--- a/drivers/media/platform/omap3isp/ispccp2.c
+++ b/drivers/media/platform/omap3isp/ispccp2.c
@@ -289,10 +289,10 @@ static void ccp2_lcx_config(struct isp_ccp2_device *ccp2,
u32 val, format;
switch (config->format) {
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
format = ISPCCP2_LCx_CTRL_FORMAT_RAW8_DPCM10_VP;
break;
- case V4L2_MBUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
default:
format = ISPCCP2_LCx_CTRL_FORMAT_RAW10_VP; /* RAW10+VP */
break;
@@ -438,7 +438,7 @@ static void ccp2_mem_configure(struct isp_ccp2_device *ccp2,
u32 val, hwords;
if (sink_pixcode != source_pixcode &&
- sink_pixcode == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
+ sink_pixcode == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8)
dpcm_decompress = 1;
ccp2_pwr_cfg(ccp2);
@@ -604,8 +604,8 @@ void omap3isp_ccp2_isr(struct isp_ccp2_device *ccp2)
*/
static const unsigned int ccp2_fmts[] = {
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
};
/*
@@ -643,8 +643,8 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
switch (pad) {
case CCP2_PAD_SINK:
- if (fmt->code != V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8)
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ if (fmt->code != MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8)
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
if (ccp2->input == CCP2_INPUT_SENSOR) {
fmt->width = clamp_t(u32, fmt->width,
@@ -671,7 +671,7 @@ static void ccp2_try_format(struct isp_ccp2_device *ccp2,
*/
format = __ccp2_get_format(ccp2, fh, CCP2_PAD_SINK, which);
memcpy(fmt, format, sizeof(*fmt));
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
break;
}
@@ -808,7 +808,7 @@ static int ccp2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = CCP2_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
ccp2_set_format(sd, fh, &format);
diff --git a/drivers/media/platform/omap3isp/ispcsi2.c b/drivers/media/platform/omap3isp/ispcsi2.c
index 6530b25..09c686d 100644
--- a/drivers/media/platform/omap3isp/ispcsi2.c
+++ b/drivers/media/platform/omap3isp/ispcsi2.c
@@ -78,15 +78,15 @@ static void csi2_recv_config(struct isp_device *isp,
}
static const unsigned int csi2_input_fmts[] = {
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
- V4L2_MBUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_YUYV8_2X8,
};
/* To set the format on the CSI2 requires a mapping function that takes
@@ -171,19 +171,19 @@ static u16 csi2_ctx_map_format(struct isp_csi2_device *csi2)
int fmtidx, destidx, is_3630;
switch (fmt->code) {
- case V4L2_MBUS_FMT_SGRBG10_1X10:
- case V4L2_MBUS_FMT_SRGGB10_1X10:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- case V4L2_MBUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
fmtidx = 0;
break;
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
fmtidx = 1;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
fmtidx = 2;
break;
default:
@@ -843,7 +843,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
- enum v4l2_mbus_pixelcode pixelcode;
+ u32 pixelcode;
struct v4l2_mbus_framefmt *format;
const struct isp_format_info *info;
unsigned int i;
@@ -858,7 +858,7 @@ csi2_try_format(struct isp_csi2_device *csi2, struct v4l2_subdev_fh *fh,
/* If not found, use SGRBG10 as default */
if (i >= ARRAY_SIZE(csi2_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
fmt->width = clamp_t(u32, fmt->width, 1, 8191);
fmt->height = clamp_t(u32, fmt->height, 1, 8191);
@@ -1029,7 +1029,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = CSI2_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
csi2_set_format(sd, fh, &format);
diff --git a/drivers/media/platform/omap3isp/isppreview.c b/drivers/media/platform/omap3isp/isppreview.c
index 605f57e..dd9eed4 100644
--- a/drivers/media/platform/omap3isp/isppreview.c
+++ b/drivers/media/platform/omap3isp/isppreview.c
@@ -964,18 +964,16 @@ static void preview_setup_hw(struct isp_prev_device *prev, u32 update,
* @prev: pointer to previewer private structure
* @pixelcode: pixel code
*/
-static void
-preview_config_ycpos(struct isp_prev_device *prev,
- enum v4l2_mbus_pixelcode pixelcode)
+static void preview_config_ycpos(struct isp_prev_device *prev, u32 pixelcode)
{
struct isp_device *isp = to_isp_device(prev);
enum preview_ycpos_mode mode;
switch (pixelcode) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
mode = YCPOS_CrYCbY;
break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
mode = YCPOS_YCrYCb;
break;
default:
@@ -1028,16 +1026,16 @@ static void preview_config_input_format(struct isp_prev_device *prev,
ISPPRV_PCR_WIDTH);
switch (info->flavor) {
- case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
prev->params.cfa_order = 0;
break;
- case V4L2_MBUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
prev->params.cfa_order = 1;
break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
prev->params.cfa_order = 2;
break;
- case V4L2_MBUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
prev->params.cfa_order = 3;
break;
default:
@@ -1078,8 +1076,8 @@ static void preview_config_input_size(struct isp_prev_device *prev, u32 active)
unsigned int elv = prev->crop.top + prev->crop.height - 1;
u32 features;
- if (format->code != V4L2_MBUS_FMT_Y8_1X8 &&
- format->code != V4L2_MBUS_FMT_Y10_1X10) {
+ if (format->code != MEDIA_BUS_FMT_Y8_1X8 &&
+ format->code != MEDIA_BUS_FMT_Y10_1X10) {
sph -= 2;
eph += 2;
slv -= 2;
@@ -1709,21 +1707,21 @@ __preview_get_crop(struct isp_prev_device *prev, struct v4l2_subdev_fh *fh,
/* previewer format descriptions */
static const unsigned int preview_input_fmts[] = {
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
};
static const unsigned int preview_output_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16,
};
/*
@@ -1742,7 +1740,7 @@ static void preview_try_format(struct isp_prev_device *prev,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
- enum v4l2_mbus_pixelcode pixelcode;
+ u32 pixelcode;
struct v4l2_rect *crop;
unsigned int i;
@@ -1774,7 +1772,7 @@ static void preview_try_format(struct isp_prev_device *prev,
/* If not found, use SGRBG10 as default */
if (i >= ARRAY_SIZE(preview_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
break;
case PREV_PAD_SOURCE:
@@ -1782,13 +1780,13 @@ static void preview_try_format(struct isp_prev_device *prev,
*fmt = *__preview_get_format(prev, fh, PREV_PAD_SINK, which);
switch (pixelcode) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
fmt->code = pixelcode;
break;
default:
- fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+ fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
break;
}
@@ -1843,8 +1841,8 @@ static void preview_try_crop(struct isp_prev_device *prev,
* and no columns in other modes. Increase the margins based on the sink
* format.
*/
- if (sink->code != V4L2_MBUS_FMT_Y8_1X8 &&
- sink->code != V4L2_MBUS_FMT_Y10_1X10) {
+ if (sink->code != MEDIA_BUS_FMT_Y8_1X8 &&
+ sink->code != MEDIA_BUS_FMT_Y10_1X10) {
left += 2;
right -= 2;
top += 2;
@@ -2092,7 +2090,7 @@ static int preview_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = PREV_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
preview_set_format(sd, fh, &format);
diff --git a/drivers/media/platform/omap3isp/ispresizer.c b/drivers/media/platform/omap3isp/ispresizer.c
index 05d1ace..2b9bc48 100644
--- a/drivers/media/platform/omap3isp/ispresizer.c
+++ b/drivers/media/platform/omap3isp/ispresizer.c
@@ -198,17 +198,16 @@ static void resizer_set_bilinear(struct isp_res_device *res,
* @res: Device context.
* @pixelcode: pixel code.
*/
-static void resizer_set_ycpos(struct isp_res_device *res,
- enum v4l2_mbus_pixelcode pixelcode)
+static void resizer_set_ycpos(struct isp_res_device *res, u32 pixelcode)
{
struct isp_device *isp = to_isp_device(res);
switch (pixelcode) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
isp_reg_set(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
ISPRSZ_CNT_YCPOS);
break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
isp_reg_clr(isp, OMAP3_ISP_IOMEM_RESZ, ISPRSZ_CNT,
ISPRSZ_CNT_YCPOS);
break;
@@ -1348,8 +1347,8 @@ static int resizer_set_selection(struct v4l2_subdev *sd,
/* resizer pixel formats */
static const unsigned int resizer_formats[] = {
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16,
};
static unsigned int resizer_max_in_width(struct isp_res_device *res)
@@ -1385,9 +1384,9 @@ static void resizer_try_format(struct isp_res_device *res,
switch (pad) {
case RESZ_PAD_SINK:
- if (fmt->code != V4L2_MBUS_FMT_YUYV8_1X16 &&
- fmt->code != V4L2_MBUS_FMT_UYVY8_1X16)
- fmt->code = V4L2_MBUS_FMT_YUYV8_1X16;
+ if (fmt->code != MEDIA_BUS_FMT_YUYV8_1X16 &&
+ fmt->code != MEDIA_BUS_FMT_UYVY8_1X16)
+ fmt->code = MEDIA_BUS_FMT_YUYV8_1X16;
fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
resizer_max_in_width(res));
@@ -1571,7 +1570,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESZ_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_YUYV8_1X16;
+ format.format.code = MEDIA_BUS_FMT_YUYV8_1X16;
format.format.width = 4096;
format.format.height = 4096;
resizer_set_format(sd, fh, &format);
diff --git a/drivers/media/platform/omap3isp/ispvideo.c b/drivers/media/platform/omap3isp/ispvideo.c
index bc38c88..b463fe1 100644
--- a/drivers/media/platform/omap3isp/ispvideo.c
+++ b/drivers/media/platform/omap3isp/ispvideo.c
@@ -39,74 +39,74 @@
* corresponding in-memory formats to the table below!!!
*/
static struct isp_format_info formats[] = {
- { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+ { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
V4L2_PIX_FMT_GREY, 8, 1, },
- { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+ { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8,
V4L2_PIX_FMT_Y10, 10, 2, },
- { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+ { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8,
V4L2_PIX_FMT_Y12, 12, 2, },
- { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+ { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR8, 8, 1, },
- { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+ { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
V4L2_PIX_FMT_SGBRG8, 8, 1, },
- { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+ { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
V4L2_PIX_FMT_SGRBG8, 8, 1, },
- { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+ { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB8, 8, 1, },
- { V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8, V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10, 0,
+ { MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8, MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SBGGR10_1X10, 0,
V4L2_PIX_FMT_SBGGR10DPCM8, 8, 1, },
- { V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8, V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGBRG10_1X10, 0,
+ { MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8, MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGBRG10_1X10, 0,
V4L2_PIX_FMT_SGBRG10DPCM8, 8, 1, },
- { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+ { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_1X10, 0,
V4L2_PIX_FMT_SGRBG10DPCM8, 8, 1, },
- { V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8, V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
- V4L2_MBUS_FMT_SRGGB10_1X10, 0,
+ { MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8, MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SRGGB10_1X10, 0,
V4L2_PIX_FMT_SRGGB10DPCM8, 8, 1, },
- { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+ { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR10, 10, 2, },
- { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+ { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8,
V4L2_PIX_FMT_SGBRG10, 10, 2, },
- { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+ { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8,
V4L2_PIX_FMT_SGRBG10, 10, 2, },
- { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+ { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB10, 10, 2, },
- { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+ { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR12, 12, 2, },
- { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+ { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8,
V4L2_PIX_FMT_SGBRG12, 12, 2, },
- { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+ { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8,
V4L2_PIX_FMT_SGRBG12, 12, 2, },
- { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+ { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB12, 12, 2, },
- { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_UYVY8_1X16, 0,
+ { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_UYVY8_1X16, 0,
V4L2_PIX_FMT_UYVY, 16, 2, },
- { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16, 0,
+ { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16, 0,
V4L2_PIX_FMT_YUYV, 16, 2, },
- { V4L2_MBUS_FMT_UYVY8_2X8, V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8, 0,
+ { MEDIA_BUS_FMT_UYVY8_2X8, MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8, 0,
V4L2_PIX_FMT_UYVY, 8, 2, },
- { V4L2_MBUS_FMT_YUYV8_2X8, V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_YUYV8_2X8, 0,
+ { MEDIA_BUS_FMT_YUYV8_2X8, MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_YUYV8_2X8, 0,
V4L2_PIX_FMT_YUYV, 8, 2, },
/* Empty entry to catch the unsupported pixel code (0) used by the CCDC
* module and avoid NULL pointer dereferences.
@@ -114,8 +114,7 @@ static struct isp_format_info formats[] = {
{ 0, }
};
-const struct isp_format_info *
-omap3isp_video_format_info(enum v4l2_mbus_pixelcode code)
+const struct isp_format_info *omap3isp_video_format_info(u32 code)
{
unsigned int i;
diff --git a/drivers/media/platform/omap3isp/ispvideo.h b/drivers/media/platform/omap3isp/ispvideo.h
index 0b7efed..4071dd7 100644
--- a/drivers/media/platform/omap3isp/ispvideo.h
+++ b/drivers/media/platform/omap3isp/ispvideo.h
@@ -44,10 +44,10 @@ struct v4l2_pix_format;
* @bpp: Bytes per pixel (when stored in memory)
*/
struct isp_format_info {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_mbus_pixelcode truncated;
- enum v4l2_mbus_pixelcode uncompressed;
- enum v4l2_mbus_pixelcode flavor;
+ u32 code;
+ u32 truncated;
+ u32 uncompressed;
+ u32 flavor;
u32 pixelformat;
unsigned int width;
unsigned int bpp;
@@ -206,6 +206,6 @@ void omap3isp_video_resume(struct isp_video *video, int continuous);
struct media_pad *omap3isp_video_remote_pad(struct isp_video *video);
const struct isp_format_info *
-omap3isp_video_format_info(enum v4l2_mbus_pixelcode code);
+omap3isp_video_format_info(u32 code);
#endif /* OMAP3_ISP_VIDEO_H */
diff --git a/drivers/media/platform/s3c-camif/camif-capture.c b/drivers/media/platform/s3c-camif/camif-capture.c
index 4f81b4c..aa40c82 100644
--- a/drivers/media/platform/s3c-camif/camif-capture.c
+++ b/drivers/media/platform/s3c-camif/camif-capture.c
@@ -1218,11 +1218,11 @@ void s3c_camif_unregister_video_node(struct camif_dev *camif, int idx)
}
/* Media bus pixel formats supported at the camif input */
-static const enum v4l2_mbus_pixelcode camif_mbus_formats[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_YVYU8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_VYUY8_2X8,
+static const u32 camif_mbus_formats[] = {
+ MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_YVYU8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_VYUY8_2X8,
};
/*
diff --git a/drivers/media/platform/s3c-camif/camif-core.c b/drivers/media/platform/s3c-camif/camif-core.c
index b385747..3b09b5b 100644
--- a/drivers/media/platform/s3c-camif/camif-core.c
+++ b/drivers/media/platform/s3c-camif/camif-core.c
@@ -256,8 +256,7 @@ static void camif_unregister_sensor(struct camif_dev *camif)
v4l2_device_unregister_subdev(sd);
camif->sensor.sd = NULL;
i2c_unregister_device(client);
- if (adapter)
- i2c_put_adapter(adapter);
+ i2c_put_adapter(adapter);
}
static int camif_create_media_links(struct camif_dev *camif)
diff --git a/drivers/media/platform/s3c-camif/camif-regs.c b/drivers/media/platform/s3c-camif/camif-regs.c
index 6e0c998..812fb3a 100644
--- a/drivers/media/platform/s3c-camif/camif-regs.c
+++ b/drivers/media/platform/s3c-camif/camif-regs.c
@@ -96,10 +96,10 @@ void camif_hw_set_effect(struct camif_dev *camif, unsigned int effect,
}
static const u32 src_pixfmt_map[8][2] = {
- { V4L2_MBUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR },
- { V4L2_MBUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB },
- { V4L2_MBUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY },
- { V4L2_MBUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY },
+ { MEDIA_BUS_FMT_YUYV8_2X8, CISRCFMT_ORDER422_YCBYCR },
+ { MEDIA_BUS_FMT_YVYU8_2X8, CISRCFMT_ORDER422_YCRYCB },
+ { MEDIA_BUS_FMT_UYVY8_2X8, CISRCFMT_ORDER422_CBYCRY },
+ { MEDIA_BUS_FMT_VYUY8_2X8, CISRCFMT_ORDER422_CRYCBY },
};
/* Set camera input pixel format and resolution */
diff --git a/drivers/media/platform/s5p-g2d/g2d.c b/drivers/media/platform/s5p-g2d/g2d.c
index d79e214..51e4edc 100644
--- a/drivers/media/platform/s5p-g2d/g2d.c
+++ b/drivers/media/platform/s5p-g2d/g2d.c
@@ -297,14 +297,8 @@ static int vidioc_querycap(struct file *file, void *priv,
strncpy(cap->driver, G2D_NAME, sizeof(cap->driver) - 1);
strncpy(cap->card, G2D_NAME, sizeof(cap->card) - 1);
cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
- V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_M2M | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/s5p-jpeg/jpeg-core.c b/drivers/media/platform/s5p-jpeg/jpeg-core.c
index 6fcc7f0..3ecf0e0 100644
--- a/drivers/media/platform/s5p-jpeg/jpeg-core.c
+++ b/drivers/media/platform/s5p-jpeg/jpeg-core.c
@@ -1001,13 +1001,8 @@ static int s5p_jpeg_querycap(struct file *file, void *priv,
sizeof(cap->card));
}
cap->bus_info[0] = 0;
- /*
- * This is only a mem-to-mem video device. The capture and output
- * device capability flags are left only for backward compatibility
- * and are scheduled for removal.
- */
- cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M |
- V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
+ cap->device_caps = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_M2M;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -2632,7 +2627,7 @@ static int s5p_jpeg_remove(struct platform_device *pdev)
return 0;
}
-#if defined(CONFIG_PM_RUNTIME) || defined(CONFIG_PM_SLEEP)
+#ifdef CONFIG_PM
static int s5p_jpeg_runtime_suspend(struct device *dev)
{
struct s5p_jpeg *jpeg = dev_get_drvdata(dev);
@@ -2682,7 +2677,7 @@ static int s5p_jpeg_runtime_resume(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_RUNTIME || CONFIG_PM_SLEEP */
+#endif /* CONFIG_PM */
#ifdef CONFIG_PM_SLEEP
static int s5p_jpeg_suspend(struct device *dev)
diff --git a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
index 51cb2dd..83e01f3 100644
--- a/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
+++ b/drivers/media/platform/s5p-mfc/regs-mfc-v6.h
@@ -71,6 +71,7 @@
#define S5P_FIMV_R2H_CMD_ENC_BUFFER_FUL_RET_V6 16
#define S5P_FIMV_R2H_CMD_ERR_RET_V6 32
+#define S5P_FIMV_MFC_BUS_RESET_CTRL 0x7110
#define S5P_FIMV_FW_VERSION_V6 0xf000
#define S5P_FIMV_INSTANCE_ID_V6 0xf008
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc.c b/drivers/media/platform/s5p-mfc/s5p_mfc.c
index 165bc86..b80a576 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc.c
@@ -159,6 +159,10 @@ static void s5p_mfc_watchdog_worker(struct work_struct *work)
}
clear_bit(0, &dev->hw_lock);
spin_unlock_irqrestore(&dev->irqlock, flags);
+
+ /* De-init MFC */
+ s5p_mfc_deinit_hw(dev);
+
/* Double check if there is at least one instance running.
* If no instance is in memory than no firmware should be present */
if (dev->num_inst > 0) {
@@ -220,11 +224,14 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
size_t dec_y_addr;
unsigned int frame_type;
- dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev);
+ /* Make sure we actually have a new frame before continuing. */
frame_type = s5p_mfc_hw_call(dev->mfc_ops, get_dec_frame_type, dev);
+ if (frame_type == S5P_FIMV_DECODE_FRAME_SKIPPED)
+ return;
+ dec_y_addr = s5p_mfc_hw_call(dev->mfc_ops, get_dec_y_adr, dev);
/* Copy timestamp / timecode from decoded src to dst and set
- appropriate flags */
+ appropriate flags. */
src_buf = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
list_for_each_entry(dst_buf, &ctx->dst_queue, list) {
if (vb2_dma_contig_plane_dma_addr(dst_buf->b, 0) == dec_y_addr) {
@@ -250,6 +257,11 @@ static void s5p_mfc_handle_frame_copy_time(struct s5p_mfc_ctx *ctx)
dst_buf->b->v4l2_buf.flags |=
V4L2_BUF_FLAG_BFRAME;
break;
+ default:
+ /* Don't know how to handle
+ S5P_FIMV_DECODE_FRAME_OTHER_FRAME. */
+ mfc_debug(2, "Unexpected frame type: %d\n",
+ frame_type);
}
break;
}
@@ -334,8 +346,7 @@ static void s5p_mfc_handle_frame(struct s5p_mfc_ctx *ctx,
ctx->state = MFCINST_RES_CHANGE_INIT;
s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
return;
@@ -407,8 +418,7 @@ leave_handle_frame:
clear_work_bit(ctx);
s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
/* if suspending, wake up device and do not try_run again*/
if (test_bit(0, &dev->enter_suspend))
@@ -455,8 +465,7 @@ static void s5p_mfc_handle_error(struct s5p_mfc_dev *dev,
break;
}
}
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
s5p_mfc_clock_off();
wake_up_dev(dev, reason, err);
@@ -510,8 +519,7 @@ static void s5p_mfc_handle_seq_done(struct s5p_mfc_ctx *ctx,
}
s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
clear_work_bit(ctx);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
wake_up_ctx(ctx, reason, err);
@@ -549,16 +557,14 @@ static void s5p_mfc_handle_init_buffers(struct s5p_mfc_ctx *ctx,
} else {
ctx->dpb_flush_flag = 0;
}
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
wake_up(&ctx->queue);
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
} else {
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
@@ -635,8 +641,7 @@ static irqreturn_t s5p_mfc_irq(int irq, void *priv)
mfc_err("post_frame_start() failed\n");
s5p_mfc_hw_call_void(dev->mfc_ops, clear_int_flags, dev);
wake_up_ctx(ctx, reason, err);
- if (test_and_clear_bit(0, &dev->hw_lock) == 0)
- BUG();
+ WARN_ON(test_and_clear_bit(0, &dev->hw_lock) == 0);
s5p_mfc_clock_off();
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
} else {
@@ -815,7 +820,7 @@ static int s5p_mfc_open(struct file *file)
ret = -ENOENT;
goto err_queue_init;
}
- q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
if (ret) {
@@ -837,7 +842,7 @@ static int s5p_mfc_open(struct file *file)
ret = -ENOENT;
goto err_queue_init;
}
- q->mem_ops = (struct vb2_mem_ops *)&vb2_dma_contig_memops;
+ q->mem_ops = &vb2_dma_contig_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
ret = vb2_queue_init(q);
if (ret) {
@@ -1284,11 +1289,17 @@ static int s5p_mfc_suspend(struct device *dev)
m_dev->int_cond, msecs_to_jiffies(MFC_INT_TIMEOUT));
if (ret == 0) {
mfc_err("Waiting for hardware to finish timed out\n");
+ clear_bit(0, &m_dev->enter_suspend);
return -EIO;
}
}
- return s5p_mfc_sleep(m_dev);
+ ret = s5p_mfc_sleep(m_dev);
+ if (ret) {
+ clear_bit(0, &m_dev->enter_suspend);
+ clear_bit(0, &m_dev->hw_lock);
+ }
+ return ret;
}
static int s5p_mfc_resume(struct device *dev)
@@ -1302,7 +1313,7 @@ static int s5p_mfc_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int s5p_mfc_runtime_suspend(struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
index 3e41ca1..15f7663 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_common.h
@@ -237,8 +237,6 @@ struct s5p_mfc_variant {
/**
* struct s5p_mfc_priv_buf - represents internal used buffer
- * @alloc: allocation-specific context for each buffer
- * (videobuf2 allocator)
* @ofs: offset of each buffer, will be used for MFC
* @virt: kernel virtual address, only valid when the
* buffer accessed by driver
@@ -246,7 +244,6 @@ struct s5p_mfc_variant {
* @size: size of the buffer
*/
struct s5p_mfc_priv_buf {
- void *alloc;
unsigned long ofs;
void *virt;
dma_addr_t dma;
@@ -340,6 +337,7 @@ struct s5p_mfc_dev {
struct s5p_mfc_hw_cmds *mfc_cmds;
const struct s5p_mfc_regs *mfc_regs;
enum s5p_mfc_fw_ver fw_ver;
+ bool risc_on; /* indicates if RISC is on or off */
};
/**
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
index 0c885a8..40d8a03 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_ctrl.c
@@ -129,6 +129,25 @@ int s5p_mfc_release_firmware(struct s5p_mfc_dev *dev)
return 0;
}
+static int s5p_mfc_bus_reset(struct s5p_mfc_dev *dev)
+{
+ unsigned int status;
+ unsigned long timeout;
+
+ /* Reset */
+ mfc_write(dev, 0x1, S5P_FIMV_MFC_BUS_RESET_CTRL);
+ timeout = jiffies + msecs_to_jiffies(MFC_BW_TIMEOUT);
+ /* Check bus status */
+ do {
+ if (time_after(jiffies, timeout)) {
+ mfc_err("Timeout while resetting MFC.\n");
+ return -EIO;
+ }
+ status = mfc_read(dev, S5P_FIMV_MFC_BUS_RESET_CTRL);
+ } while ((status & 0x2) == 0);
+ return 0;
+}
+
/* Reset the device */
int s5p_mfc_reset(struct s5p_mfc_dev *dev)
{
@@ -139,12 +158,6 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev)
mfc_debug_enter();
if (IS_MFCV6_PLUS(dev)) {
- /* Reset IP */
- /* except RISC, reset */
- mfc_write(dev, 0xFEE, S5P_FIMV_MFC_RESET_V6);
- /* reset release */
- mfc_write(dev, 0x0, S5P_FIMV_MFC_RESET_V6);
-
/* Zero Initialization of MFC registers */
mfc_write(dev, 0, S5P_FIMV_RISC2HOST_CMD_V6);
mfc_write(dev, 0, S5P_FIMV_HOST2RISC_CMD_V6);
@@ -153,8 +166,17 @@ int s5p_mfc_reset(struct s5p_mfc_dev *dev)
for (i = 0; i < S5P_FIMV_REG_CLEAR_COUNT_V6; i++)
mfc_write(dev, 0, S5P_FIMV_REG_CLEAR_BEGIN_V6 + (i*4));
- /* Reset */
- mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6);
+ /* check bus reset control before reset */
+ if (dev->risc_on)
+ if (s5p_mfc_bus_reset(dev))
+ return -EIO;
+ /* Reset
+ * set RISC_ON to 0 during power_on & wake_up.
+ * V6 needs RISC_ON set to 0 during reset also.
+ */
+ if ((!dev->risc_on) || (!IS_MFCV7_PLUS(dev)))
+ mfc_write(dev, 0, S5P_FIMV_RISC_ON_V6);
+
mfc_write(dev, 0x1FFF, S5P_FIMV_MFC_RESET_V6);
mfc_write(dev, 0, S5P_FIMV_MFC_RESET_V6);
} else {
@@ -226,6 +248,7 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
/* 0. MFC reset */
mfc_debug(2, "MFC reset..\n");
s5p_mfc_clock_on();
+ dev->risc_on = 0;
ret = s5p_mfc_reset(dev);
if (ret) {
mfc_err("Failed to reset MFC - timeout\n");
@@ -238,8 +261,10 @@ int s5p_mfc_init_hw(struct s5p_mfc_dev *dev)
s5p_mfc_clear_cmds(dev);
/* 3. Release reset signal to the RISC */
s5p_mfc_clean_dev_int_flags(dev);
- if (IS_MFCV6_PLUS(dev))
+ if (IS_MFCV6_PLUS(dev)) {
+ dev->risc_on = 1;
mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
+ }
else
mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
mfc_debug(2, "Will now wait for completion of firmware transfer\n");
@@ -328,6 +353,58 @@ int s5p_mfc_sleep(struct s5p_mfc_dev *dev)
return ret;
}
+static int s5p_mfc_v8_wait_wakeup(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ /* Release reset signal to the RISC */
+ dev->risc_on = 1;
+ mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
+
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_FW_STATUS_RET)) {
+ mfc_err("Failed to reset MFCV8\n");
+ return -EIO;
+ }
+ mfc_debug(2, "Write command to wakeup MFCV8\n");
+ ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFCV8 - timeout\n");
+ return ret;
+ }
+
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
+ mfc_err("Failed to wakeup MFC\n");
+ return -EIO;
+ }
+ return ret;
+}
+
+static int s5p_mfc_wait_wakeup(struct s5p_mfc_dev *dev)
+{
+ int ret;
+
+ /* Send MFC wakeup command */
+ ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
+ if (ret) {
+ mfc_err("Failed to send command to MFC - timeout\n");
+ return ret;
+ }
+
+ /* Release reset signal to the RISC */
+ if (IS_MFCV6_PLUS(dev)) {
+ dev->risc_on = 1;
+ mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
+ } else {
+ mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
+ }
+
+ if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
+ mfc_err("Failed to wakeup MFC\n");
+ return -EIO;
+ }
+ return ret;
+}
+
int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
{
int ret;
@@ -336,9 +413,11 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
/* 0. MFC reset */
mfc_debug(2, "MFC reset..\n");
s5p_mfc_clock_on();
+ dev->risc_on = 0;
ret = s5p_mfc_reset(dev);
if (ret) {
mfc_err("Failed to reset MFC - timeout\n");
+ s5p_mfc_clock_off();
return ret;
}
mfc_debug(2, "Done MFC reset..\n");
@@ -347,23 +426,16 @@ int s5p_mfc_wakeup(struct s5p_mfc_dev *dev)
/* 2. Initialize registers of channel I/F */
s5p_mfc_clear_cmds(dev);
s5p_mfc_clean_dev_int_flags(dev);
- /* 3. Initialize firmware */
- ret = s5p_mfc_hw_call(dev->mfc_cmds, wakeup_cmd, dev);
- if (ret) {
- mfc_err("Failed to send command to MFC - timeout\n");
- return ret;
- }
- /* 4. Release reset signal to the RISC */
- if (IS_MFCV6_PLUS(dev))
- mfc_write(dev, 0x1, S5P_FIMV_RISC_ON_V6);
+ /* 3. Send MFC wakeup command and wait for completion*/
+ if (IS_MFCV8(dev))
+ ret = s5p_mfc_v8_wait_wakeup(dev);
else
- mfc_write(dev, 0x3ff, S5P_FIMV_SW_RESET);
- mfc_debug(2, "Ok, now will write a command to wakeup the system\n");
- if (s5p_mfc_wait_for_done_dev(dev, S5P_MFC_R2H_CMD_WAKEUP_RET)) {
- mfc_err("Failed to load firmware\n");
- return -EIO;
- }
+ ret = s5p_mfc_wait_wakeup(dev);
+
s5p_mfc_clock_off();
+ if (ret)
+ return ret;
+
dev->int_cond = 0;
if (dev->int_err != 0 || dev->int_type !=
S5P_MFC_R2H_CMD_WAKEUP_RET) {
@@ -396,7 +468,6 @@ int s5p_mfc_open_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
}
set_work_bit_irqsave(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
if (s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_OPEN_INSTANCE_RET, 0)) {
@@ -422,7 +493,6 @@ void s5p_mfc_close_mfc_inst(struct s5p_mfc_dev *dev, struct s5p_mfc_ctx *ctx)
{
ctx->state = MFCINST_RETURN_INST;
set_work_bit_irqsave(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
/* Wait until instance is returned or timeout occurred */
if (s5p_mfc_wait_for_done_ctx(ctx,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
index a98fe02..c6c3452 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_dec.c
@@ -269,15 +269,13 @@ static int vidioc_querycap(struct file *file, void *priv,
strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
/*
* This is only a mem-to-mem video device. The capture and output
* device capability flags are left only for backward compatibility
* and are scheduled for removal.
*/
- cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_CAPTURE_MPLANE |
- V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -334,7 +332,6 @@ static int vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
MFCINST_RES_CHANGE_END)) {
/* If the MFC is parsing the header,
* so wait until it is finished */
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_wait_for_done_ctx(ctx, S5P_MFC_R2H_CMD_SEQ_DONE_RET,
0);
}
@@ -740,12 +737,12 @@ static int s5p_mfc_dec_g_v_ctrl(struct v4l2_ctrl *ctrl)
ctx->state < MFCINST_ABORT) {
ctrl->val = ctx->pb_count;
break;
- } else if (ctx->state != MFCINST_INIT) {
+ } else if (ctx->state != MFCINST_INIT &&
+ ctx->state != MFCINST_RES_CHANGE_END) {
v4l2_err(&dev->v4l2_dev, "Decoding not initialised\n");
return -EINVAL;
}
/* Should wait for the header to be parsed */
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0);
if (ctx->state >= MFCINST_HEAD_PARSED &&
@@ -1057,7 +1054,6 @@ static void s5p_mfc_stop_streaming(struct vb2_queue *q)
if (IS_MFCV6_PLUS(dev) && (ctx->state == MFCINST_RUNNING)) {
ctx->state = MFCINST_FLUSH;
set_work_bit_irqsave(ctx);
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_hw_call_void(dev->mfc_ops, try_run, dev);
if (s5p_mfc_wait_for_done_ctx(ctx,
S5P_MFC_R2H_CMD_DPB_FLUSH_RET, 0))
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
index a904a1c..bd64f1d 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_enc.c
@@ -32,7 +32,7 @@
#include "s5p_mfc_intr.h"
#include "s5p_mfc_opr.h"
-#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12MT
+#define DEF_SRC_FMT_ENC V4L2_PIX_FMT_NV12M
#define DEF_DST_FMT_ENC V4L2_PIX_FMT_H264
static struct s5p_mfc_fmt formats[] = {
@@ -67,8 +67,7 @@ static struct s5p_mfc_fmt formats[] = {
.codec_mode = S5P_MFC_CODEC_NONE,
.type = MFC_FMT_RAW,
.num_planes = 2,
- .versions = MFC_V5_BIT | MFC_V6_BIT | MFC_V7_BIT |
- MFC_V8_BIT,
+ .versions = MFC_V6_BIT | MFC_V7_BIT | MFC_V8_BIT,
},
{
.name = "H264 Encoded Stream",
@@ -690,6 +689,16 @@ static struct mfc_control controls[] = {
.step = 1,
.default_value = 0,
},
+ {
+ .id = V4L2_CID_MIN_BUFFERS_FOR_OUTPUT,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Minimum number of output bufs",
+ .minimum = 1,
+ .maximum = 32,
+ .step = 1,
+ .default_value = 1,
+ .is_volatile = 1,
+ },
};
#define NUM_CTRLS ARRAY_SIZE(controls)
@@ -938,15 +947,13 @@ static int vidioc_querycap(struct file *file, void *priv,
strncpy(cap->driver, dev->plat_dev->name, sizeof(cap->driver) - 1);
strncpy(cap->card, dev->plat_dev->name, sizeof(cap->card) - 1);
cap->bus_info[0] = 0;
- cap->version = KERNEL_VERSION(1, 0, 0);
/*
* This is only a mem-to-mem video device. The capture and output
* device capability flags are left only for backward compatibility
* and are scheduled for removal.
*/
- cap->capabilities = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING |
- V4L2_CAP_VIDEO_CAPTURE_MPLANE |
- V4L2_CAP_VIDEO_OUTPUT_MPLANE;
+ cap->device_caps = V4L2_CAP_VIDEO_M2M_MPLANE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -1137,6 +1144,11 @@ static int vidioc_reqbufs(struct file *file, void *priv,
(reqbufs->memory != V4L2_MEMORY_USERPTR))
return -EINVAL;
if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE) {
+ if (reqbufs->count == 0) {
+ ret = vb2_reqbufs(&ctx->vq_dst, reqbufs);
+ ctx->capture_state = QUEUE_FREE;
+ return ret;
+ }
if (ctx->capture_state != QUEUE_FREE) {
mfc_err("invalid capture state: %d\n",
ctx->capture_state);
@@ -1158,6 +1170,14 @@ static int vidioc_reqbufs(struct file *file, void *priv,
return -ENOMEM;
}
} else if (reqbufs->type == V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE) {
+ if (reqbufs->count == 0) {
+ mfc_debug(2, "Freeing buffers\n");
+ ret = vb2_reqbufs(&ctx->vq_src, reqbufs);
+ s5p_mfc_hw_call_void(dev->mfc_ops, release_codec_buffers,
+ ctx);
+ ctx->output_state = QUEUE_FREE;
+ return ret;
+ }
if (ctx->output_state != QUEUE_FREE) {
mfc_err("invalid output state: %d\n",
ctx->output_state);
@@ -1624,8 +1644,39 @@ static int s5p_mfc_enc_s_ctrl(struct v4l2_ctrl *ctrl)
return ret;
}
+static int s5p_mfc_enc_g_v_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct s5p_mfc_ctx *ctx = ctrl_to_ctx(ctrl);
+ struct s5p_mfc_dev *dev = ctx->dev;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MIN_BUFFERS_FOR_OUTPUT:
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->val = ctx->pb_count;
+ break;
+ } else if (ctx->state != MFCINST_INIT) {
+ v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n");
+ return -EINVAL;
+ }
+ /* Should wait for the header to be produced */
+ s5p_mfc_wait_for_done_ctx(ctx,
+ S5P_MFC_R2H_CMD_SEQ_DONE_RET, 0);
+ if (ctx->state >= MFCINST_HEAD_PARSED &&
+ ctx->state < MFCINST_ABORT) {
+ ctrl->val = ctx->pb_count;
+ } else {
+ v4l2_err(&dev->v4l2_dev, "Encoding not initialised\n");
+ return -EINVAL;
+ }
+ break;
+ }
+ return 0;
+}
+
static const struct v4l2_ctrl_ops s5p_mfc_enc_ctrl_ops = {
.s_ctrl = s5p_mfc_enc_s_ctrl,
+ .g_volatile_ctrl = s5p_mfc_enc_g_v_ctrl,
};
static int vidioc_s_parm(struct file *file, void *priv,
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
index 7cf0796..0c4fcf2 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v5.c
@@ -1178,7 +1178,6 @@ static void s5p_mfc_run_res_change(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_decode_one_frame_v5(ctx, MFC_DEC_RES_CHANGE);
}
@@ -1192,7 +1191,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
last_frame = MFC_DEC_LAST_FRAME;
s5p_mfc_set_dec_stream_buffer_v5(ctx, 0, 0, 0);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_decode_one_frame_v5(ctx, last_frame);
return 0;
}
@@ -1212,7 +1210,6 @@ static int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx, int last_frame)
ctx->consumed_stream, temp_vb->b->v4l2_planes[0].bytesused);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
last_frame = MFC_DEC_LAST_FRAME;
mfc_debug(2, "Setting ctx->state to FINISHING\n");
@@ -1273,7 +1270,6 @@ static int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
mfc_debug(2, "encoding buffer with index=%d state=%d\n",
src_mb ? src_mb->b->v4l2_buf.index : -1, ctx->state);
s5p_mfc_encode_one_frame_v5(ctx);
@@ -1297,7 +1293,6 @@ static void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
0, temp_vb->b->v4l2_planes[0].bytesused);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_init_decode_v5(ctx);
}
@@ -1317,7 +1312,6 @@ static void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_stream_buffer_v5(ctx, dst_addr, dst_size);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_init_encode_v5(ctx);
}
@@ -1352,7 +1346,6 @@ static int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
0, temp_vb->b->v4l2_planes[0].bytesused);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_set_dec_frame_buffer_v5(ctx);
if (ret) {
mfc_err("Failed to alloc frame mem\n");
@@ -1396,6 +1389,8 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
* Now obtaining frames from MFC buffer
*/
s5p_mfc_clock_on();
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
if (ctx->type == MFCINST_DECODER) {
s5p_mfc_set_dec_desc_buffer(ctx);
switch (ctx->state) {
@@ -1406,12 +1401,10 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
ret = s5p_mfc_run_dec_frame(ctx, MFC_DEC_FRAME);
break;
case MFCINST_INIT:
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd,
ctx);
break;
case MFCINST_RETURN_INST:
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd,
ctx);
break;
@@ -1444,12 +1437,10 @@ static void s5p_mfc_try_run_v5(struct s5p_mfc_dev *dev)
ret = s5p_mfc_run_enc_frame(ctx);
break;
case MFCINST_INIT:
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd,
ctx);
break;
case MFCINST_RETURN_INST:
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd,
ctx);
break;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
index 8798b14..9aea179 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_opr_v6.c
@@ -1394,7 +1394,6 @@ static inline void s5p_mfc_set_flush(struct s5p_mfc_ctx *ctx, int flush)
if (flush) {
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
writel(ctx->inst_no, mfc_regs->instance_id);
s5p_mfc_hw_call_void(dev->mfc_cmds, cmd_host2risc, dev,
S5P_FIMV_H2R_CMD_FLUSH_V6, NULL);
@@ -1532,27 +1531,10 @@ static inline int s5p_mfc_get_new_ctx(struct s5p_mfc_dev *dev)
static inline void s5p_mfc_run_dec_last_frames(struct s5p_mfc_ctx *ctx)
{
struct s5p_mfc_dev *dev = ctx->dev;
- struct s5p_mfc_buf *temp_vb;
- unsigned long flags;
-
- spin_lock_irqsave(&dev->irqlock, flags);
-
- /* Frames are being decoded */
- if (list_empty(&ctx->src_queue)) {
- mfc_debug(2, "No src buffers.\n");
- spin_unlock_irqrestore(&dev->irqlock, flags);
- return;
- }
- /* Get the next source buffer */
- temp_vb = list_entry(ctx->src_queue.next, struct s5p_mfc_buf, list);
- temp_vb->flags |= MFC_BUF_FLAG_USED;
- s5p_mfc_set_dec_stream_buffer_v6(ctx,
- vb2_dma_contig_plane_dma_addr(temp_vb->b, 0), 0, 0);
- spin_unlock_irqrestore(&dev->irqlock, flags);
+ s5p_mfc_set_dec_stream_buffer_v6(ctx, 0, 0, 0);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
- s5p_mfc_decode_one_frame_v6(ctx, 1);
+ s5p_mfc_decode_one_frame_v6(ctx, MFC_DEC_LAST_FRAME);
}
static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
@@ -1588,7 +1570,6 @@ static inline int s5p_mfc_run_dec_frame(struct s5p_mfc_ctx *ctx)
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
if (temp_vb->b->v4l2_planes[0].bytesused == 0) {
last_frame = 1;
mfc_debug(2, "Setting ctx->state to FINISHING\n");
@@ -1645,7 +1626,6 @@ static inline int s5p_mfc_run_enc_frame(struct s5p_mfc_ctx *ctx)
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_encode_one_frame_v6(ctx);
return 0;
@@ -1667,7 +1647,6 @@ static inline void s5p_mfc_run_init_dec(struct s5p_mfc_ctx *ctx)
temp_vb->b->v4l2_planes[0].bytesused);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_init_decode_v6(ctx);
}
@@ -1687,7 +1666,6 @@ static inline void s5p_mfc_run_init_enc(struct s5p_mfc_ctx *ctx)
s5p_mfc_set_enc_stream_buffer_v6(ctx, dst_addr, dst_size);
spin_unlock_irqrestore(&dev->irqlock, flags);
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
s5p_mfc_init_encode_v6(ctx);
}
@@ -1707,7 +1685,6 @@ static inline int s5p_mfc_run_init_dec_buffers(struct s5p_mfc_ctx *ctx)
}
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_set_dec_frame_buffer_v6(ctx);
if (ret) {
mfc_err("Failed to alloc frame mem.\n");
@@ -1722,7 +1699,6 @@ static inline int s5p_mfc_run_init_enc_buffers(struct s5p_mfc_ctx *ctx)
int ret;
dev->curr_ctx = ctx->num;
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_set_enc_ref_buffer_v6(ctx);
if (ret) {
mfc_err("Failed to alloc frame mem.\n");
@@ -1771,6 +1747,8 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
* Now obtaining frames from MFC buffer */
s5p_mfc_clock_on();
+ s5p_mfc_clean_ctx_int_flags(ctx);
+
if (ctx->type == MFCINST_DECODER) {
switch (ctx->state) {
case MFCINST_FINISHING:
@@ -1780,12 +1758,10 @@ static void s5p_mfc_try_run_v6(struct s5p_mfc_dev *dev)
ret = s5p_mfc_run_dec_frame(ctx);
break;
case MFCINST_INIT:
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_hw_call(dev->mfc_cmds, open_inst_cmd,
ctx);
break;
case MFCINST_RETURN_INST:
- s5p_mfc_clean_ctx_int_flags(ctx);
ret = s5p_mfc_hw_call(dev->mfc_cmds, close_inst_cmd,
ctx);
break;
diff --git a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
index 826c489..5f97a33 100644
--- a/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
+++ b/drivers/media/platform/s5p-mfc/s5p_mfc_pm.c
@@ -13,9 +13,7 @@
#include <linux/clk.h>
#include <linux/err.h>
#include <linux/platform_device.h>
-#ifdef CONFIG_PM_RUNTIME
#include <linux/pm_runtime.h>
-#endif
#include "s5p_mfc_common.h"
#include "s5p_mfc_debug.h"
#include "s5p_mfc_pm.h"
@@ -67,7 +65,7 @@ int s5p_mfc_init_pm(struct s5p_mfc_dev *dev)
}
atomic_set(&pm->power, 0);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
pm->device = &dev->plat_dev->dev;
pm_runtime_enable(pm->device);
#endif
@@ -93,7 +91,7 @@ void s5p_mfc_final_pm(struct s5p_mfc_dev *dev)
}
clk_unprepare(pm->clock_gate);
clk_put(pm->clock_gate);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
pm_runtime_disable(pm->device);
#endif
}
@@ -120,7 +118,7 @@ void s5p_mfc_clock_off(void)
int s5p_mfc_power_on(void)
{
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
return pm_runtime_get_sync(pm->device);
#else
atomic_set(&pm->power, 1);
@@ -130,7 +128,7 @@ int s5p_mfc_power_on(void)
int s5p_mfc_power_off(void)
{
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
return pm_runtime_put_sync(pm->device);
#else
atomic_set(&pm->power, 0);
diff --git a/drivers/media/platform/s5p-tv/hdmi_drv.c b/drivers/media/platform/s5p-tv/hdmi_drv.c
index 37c8bd6..1d1ef211 100644
--- a/drivers/media/platform/s5p-tv/hdmi_drv.c
+++ b/drivers/media/platform/s5p-tv/hdmi_drv.c
@@ -660,7 +660,7 @@ static int hdmi_g_mbus_fmt(struct v4l2_subdev *sd,
memset(fmt, 0, sizeof(*fmt));
fmt->width = t->hact.end - t->hact.beg;
fmt->height = t->vact[0].end - t->vact[0].beg;
- fmt->code = V4L2_MBUS_FMT_FIXED; /* means RGB888 */
+ fmt->code = MEDIA_BUS_FMT_FIXED; /* means RGB888 */
fmt->colorspace = V4L2_COLORSPACE_SRGB;
if (t->interlaced) {
fmt->field = V4L2_FIELD_INTERLACED;
diff --git a/drivers/media/platform/s5p-tv/sdo_drv.c b/drivers/media/platform/s5p-tv/sdo_drv.c
index 72cf892..46f4d56 100644
--- a/drivers/media/platform/s5p-tv/sdo_drv.c
+++ b/drivers/media/platform/s5p-tv/sdo_drv.c
@@ -170,7 +170,7 @@ static int sdo_g_mbus_fmt(struct v4l2_subdev *sd,
/* all modes are 720 pixels wide */
fmt->width = 720;
fmt->height = sdev->fmt->height;
- fmt->code = V4L2_MBUS_FMT_FIXED;
+ fmt->code = MEDIA_BUS_FMT_FIXED;
fmt->field = V4L2_FIELD_INTERLACED;
fmt->colorspace = V4L2_COLORSPACE_JPEG;
return 0;
diff --git a/drivers/media/platform/sh_vou.c b/drivers/media/platform/sh_vou.c
index e5f1d4c..154ef0b 100644
--- a/drivers/media/platform/sh_vou.c
+++ b/drivers/media/platform/sh_vou.c
@@ -396,7 +396,8 @@ static int sh_vou_querycap(struct file *file, void *priv,
dev_dbg(vou_dev->v4l2_dev.dev, "%s()\n", __func__);
strlcpy(cap->card, "SuperH VOU", sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -680,7 +681,7 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
@@ -733,7 +734,7 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
(unsigned)mbfmt.height > img_height_max ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
+ mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8)
return -EIO;
if (mbfmt.width != geo.output.width ||
@@ -943,7 +944,7 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
@@ -994,7 +995,7 @@ static int sh_vou_s_crop(struct file *file, void *fh, const struct v4l2_crop *a)
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
(unsigned)mbfmt.height > img_height_max ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
+ mbfmt.code != MEDIA_BUS_FMT_YUYV8_2X8)
return -EIO;
geo.output.width = mbfmt.width;
diff --git a/drivers/media/platform/soc_camera/atmel-isi.c b/drivers/media/platform/soc_camera/atmel-isi.c
index c5291b0..ee5650f 100644
--- a/drivers/media/platform/soc_camera/atmel-isi.c
+++ b/drivers/media/platform/soc_camera/atmel-isi.c
@@ -105,25 +105,25 @@ static u32 isi_readl(struct atmel_isi *isi, u32 reg)
}
static int configure_geometry(struct atmel_isi *isi, u32 width,
- u32 height, enum v4l2_mbus_pixelcode code)
+ u32 height, u32 code)
{
u32 cfg2, cr;
switch (code) {
/* YUV, including grey */
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
cr = ISI_CFG2_GRAYSCALE;
break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
cr = ISI_CFG2_YCC_SWAP_MODE_3;
break;
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
cr = ISI_CFG2_YCC_SWAP_MODE_2;
break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
cr = ISI_CFG2_YCC_SWAP_MODE_1;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
cr = ISI_CFG2_YCC_SWAP_DEFAULT;
break;
/* RGB, TODO */
@@ -645,7 +645,7 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int formats = 0, ret;
/* sensor format */
- enum v4l2_mbus_pixelcode code;
+ u32 code;
/* soc camera host format */
const struct soc_mbus_pixelfmt *fmt;
@@ -670,10 +670,10 @@ static int isi_camera_get_formats(struct soc_camera_device *icd,
}
switch (code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
formats++;
if (xlate) {
xlate->host_fmt = &isi_camera_formats[0];
diff --git a/drivers/media/platform/soc_camera/mx2_camera.c b/drivers/media/platform/soc_camera/mx2_camera.c
index 2347612a..ce72bd2 100644
--- a/drivers/media/platform/soc_camera/mx2_camera.c
+++ b/drivers/media/platform/soc_camera/mx2_camera.c
@@ -211,7 +211,7 @@ struct emma_prp_resize {
/* prp configuration for a client-host fmt pair */
struct mx2_fmt_cfg {
- enum v4l2_mbus_pixelcode in_fmt;
+ u32 in_fmt;
u32 out_fmt;
struct mx2_prp_cfg cfg;
};
@@ -309,7 +309,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
}
},
{
- .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8,
+ .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8,
.out_fmt = V4L2_PIX_FMT_YUYV,
.cfg = {
.channel = 1,
@@ -323,7 +323,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
}
},
{
- .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8,
+ .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8,
.out_fmt = V4L2_PIX_FMT_YUYV,
.cfg = {
.channel = 1,
@@ -337,7 +337,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
}
},
{
- .in_fmt = V4L2_MBUS_FMT_YUYV8_2X8,
+ .in_fmt = MEDIA_BUS_FMT_YUYV8_2X8,
.out_fmt = V4L2_PIX_FMT_YUV420,
.cfg = {
.channel = 2,
@@ -351,7 +351,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
}
},
{
- .in_fmt = V4L2_MBUS_FMT_UYVY8_2X8,
+ .in_fmt = MEDIA_BUS_FMT_UYVY8_2X8,
.out_fmt = V4L2_PIX_FMT_YUV420,
.cfg = {
.channel = 2,
@@ -366,9 +366,7 @@ static struct mx2_fmt_cfg mx27_emma_prp_table[] = {
},
};
-static struct mx2_fmt_cfg *mx27_emma_prp_get_format(
- enum v4l2_mbus_pixelcode in_fmt,
- u32 out_fmt)
+static struct mx2_fmt_cfg *mx27_emma_prp_get_format(u32 in_fmt, u32 out_fmt)
{
int i;
@@ -945,7 +943,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
const struct soc_mbus_pixelfmt *fmt;
struct device *dev = icd->parent;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
int ret, formats = 0;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
@@ -959,8 +957,8 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
return 0;
}
- if (code == V4L2_MBUS_FMT_YUYV8_2X8 ||
- code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ if (code == MEDIA_BUS_FMT_YUYV8_2X8 ||
+ code == MEDIA_BUS_FMT_UYVY8_2X8) {
formats++;
if (xlate) {
/*
@@ -968,7 +966,7 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
* soc_mediabus.c
*/
xlate->host_fmt =
- soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_1_5X8);
+ soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_1_5X8);
xlate->code = code;
dev_dbg(dev, "Providing host format %s for sensor code %d\n",
xlate->host_fmt->name, code);
@@ -976,11 +974,11 @@ static int mx2_camera_get_formats(struct soc_camera_device *icd,
}
}
- if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
+ if (code == MEDIA_BUS_FMT_UYVY8_2X8) {
formats++;
if (xlate) {
xlate->host_fmt =
- soc_mbus_get_fmtdesc(V4L2_MBUS_FMT_YUYV8_2X8);
+ soc_mbus_get_fmtdesc(MEDIA_BUS_FMT_YUYV8_2X8);
xlate->code = code;
dev_dbg(dev, "Providing host format %s for sensor code %d\n",
xlate->host_fmt->name, code);
diff --git a/drivers/media/platform/soc_camera/mx3_camera.c b/drivers/media/platform/soc_camera/mx3_camera.c
index 7696a87..8e52ccc 100644
--- a/drivers/media/platform/soc_camera/mx3_camera.c
+++ b/drivers/media/platform/soc_camera/mx3_camera.c
@@ -656,7 +656,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
int formats = 0, ret;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
const struct soc_mbus_pixelfmt *fmt;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
@@ -677,7 +677,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
return 0;
switch (code) {
- case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
formats++;
if (xlate) {
xlate->host_fmt = &mx3_camera_formats[0];
@@ -687,7 +687,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int id
mx3_camera_formats[0].name, code);
}
break;
- case V4L2_MBUS_FMT_Y10_1X10:
+ case MEDIA_BUS_FMT_Y10_1X10:
formats++;
if (xlate) {
xlate->host_fmt = &mx3_camera_formats[1];
diff --git a/drivers/media/platform/soc_camera/omap1_camera.c b/drivers/media/platform/soc_camera/omap1_camera.c
index 74ce8b6..e6b9328 100644
--- a/drivers/media/platform/soc_camera/omap1_camera.c
+++ b/drivers/media/platform/soc_camera/omap1_camera.c
@@ -140,7 +140,7 @@
/* buffer for one video frame */
struct omap1_cam_buf {
struct videobuf_buffer vb;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
int inwork;
struct scatterlist *sgbuf;
int sgcount;
@@ -980,7 +980,7 @@ static void omap1_cam_clock_stop(struct soc_camera_host *ici)
/* Duplicate standard formats based on host capability of byte swapping */
static const struct soc_mbus_lookup omap1_cam_formats[] = {
{
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
@@ -990,7 +990,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
@@ -1000,7 +1000,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
@@ -1010,7 +1010,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
@@ -1020,7 +1020,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
@@ -1030,7 +1030,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
@@ -1040,7 +1040,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
@@ -1050,7 +1050,7 @@ static const struct soc_mbus_lookup omap1_cam_formats[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
@@ -1068,7 +1068,7 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->parent;
int formats = 0, ret;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
const struct soc_mbus_pixelfmt *fmt;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
@@ -1088,14 +1088,14 @@ static int omap1_cam_get_formats(struct soc_camera_device *icd,
return 0;
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
formats++;
if (xlate) {
xlate->host_fmt = soc_mbus_find_fmtdesc(code,
diff --git a/drivers/media/platform/soc_camera/pxa_camera.c b/drivers/media/platform/soc_camera/pxa_camera.c
index 66178fc..951226a 100644
--- a/drivers/media/platform/soc_camera/pxa_camera.c
+++ b/drivers/media/platform/soc_camera/pxa_camera.c
@@ -187,7 +187,7 @@ struct pxa_cam_dma {
struct pxa_buffer {
/* common v4l buffer stuff -- must be first */
struct videobuf_buffer vb;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
/* our descriptor lists for Y, U and V channels */
struct pxa_cam_dma dmas[3];
int inwork;
@@ -1253,7 +1253,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
struct device *dev = icd->parent;
int formats = 0, ret;
struct pxa_cam *cam;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
const struct soc_mbus_pixelfmt *fmt;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
@@ -1283,7 +1283,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
}
switch (code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
formats++;
if (xlate) {
xlate->host_fmt = &pxa_camera_formats[0];
@@ -1292,11 +1292,11 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int id
dev_dbg(dev, "Providing format %s using code %d\n",
pxa_camera_formats[0].name, code);
}
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
- case V4L2_MBUS_FMT_RGB565_2X8_LE:
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_RGB565_2X8_LE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE:
if (xlate)
dev_dbg(dev, "Providing format %s packed\n",
fmt->name);
diff --git a/drivers/media/platform/soc_camera/rcar_vin.c b/drivers/media/platform/soc_camera/rcar_vin.c
index 20defcb..8d8438b 100644
--- a/drivers/media/platform/soc_camera/rcar_vin.c
+++ b/drivers/media/platform/soc_camera/rcar_vin.c
@@ -272,16 +272,16 @@ static int rcar_vin_setup(struct rcar_vin_priv *priv)
/* input interface */
switch (icd->current_fmt->code) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
/* BT.601/BT.1358 16bit YCbCr422 */
vnmc |= VNMC_INF_YUV16;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ?
VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
break;
- case V4L2_MBUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
vnmc |= priv->pdata_flags & RCAR_VIN_BT656 ?
VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
@@ -921,7 +921,7 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
int ret, k, n;
int formats = 0;
struct rcar_vin_cam *cam;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
const struct soc_mbus_pixelfmt *fmt;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
@@ -1010,9 +1010,9 @@ static int rcar_vin_get_formats(struct soc_camera_device *icd, unsigned int idx,
cam->extra_fmt = NULL;
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
if (cam->extra_fmt)
break;
diff --git a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
index 20ad4a5..5f58ed9 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_ceu_camera.c
@@ -149,7 +149,7 @@ struct sh_mobile_ceu_cam {
/* Camera cropping rectangle */
struct v4l2_rect rect;
const struct soc_mbus_pixelfmt *extra_fmt;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
};
static struct sh_mobile_ceu_buffer *to_ceu_vb(struct vb2_buffer *vb)
@@ -861,16 +861,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd)
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
switch (cam->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
break;
- case V4L2_MBUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
break;
default:
@@ -1048,7 +1048,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
int ret, k, n;
int formats = 0;
struct sh_mobile_ceu_cam *cam;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
const struct soc_mbus_pixelfmt *fmt;
ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
@@ -1141,10 +1141,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int
cam->extra_fmt = NULL;
switch (code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_VYUY8_2X8:
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_YVYU8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_VYUY8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YVYU8_2X8:
if (cam->extra_fmt)
break;
diff --git a/drivers/media/platform/soc_camera/sh_mobile_csi2.c b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
index 05dd21a..c738e27 100644
--- a/drivers/media/platform/soc_camera/sh_mobile_csi2.c
+++ b/drivers/media/platform/soc_camera/sh_mobile_csi2.c
@@ -59,28 +59,28 @@ static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
switch (pdata->type) {
case SH_CSI2C:
switch (mf->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */
- case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */
- case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8: /* YUV422 */
+ case MEDIA_BUS_FMT_YUYV8_1_5X8: /* YUV420 */
+ case MEDIA_BUS_FMT_Y8_1X8: /* RAW8 */
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
break;
default:
/* All MIPI CSI-2 devices must support one of primary formats */
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ mf->code = MEDIA_BUS_FMT_YUYV8_2X8;
}
break;
case SH_CSI2I:
switch (mf->code) {
- case V4L2_MBUS_FMT_Y8_1X8: /* RAW8 */
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SGRBG8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */
- case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */
+ case MEDIA_BUS_FMT_Y8_1X8: /* RAW8 */
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SBGGR10_1X10: /* RAW10 */
+ case MEDIA_BUS_FMT_SBGGR12_1X12: /* RAW12 */
break;
default:
/* All MIPI CSI-2 devices must support one of primary formats */
- mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+ mf->code = MEDIA_BUS_FMT_SBGGR8_1X8;
}
break;
}
@@ -104,21 +104,21 @@ static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
return -EINVAL;
switch (mf->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
tmp |= 0x1e; /* YUV422 8 bit */
break;
- case V4L2_MBUS_FMT_YUYV8_1_5X8:
+ case MEDIA_BUS_FMT_YUYV8_1_5X8:
tmp |= 0x18; /* YUV420 8 bit */
break;
- case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE:
tmp |= 0x21; /* RGB555 */
break;
- case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case MEDIA_BUS_FMT_RGB565_2X8_BE:
tmp |= 0x22; /* RGB565 */
break;
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
tmp |= 0x2a; /* RAW8 */
break;
default:
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 8e61b97..f4be2a1 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -460,7 +460,7 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
struct soc_camera_host *ici = to_soc_camera_host(icd->parent);
unsigned int i, fmts = 0, raw_fmts = 0;
int ret;
- enum v4l2_mbus_pixelcode code;
+ u32 code;
while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
raw_fmts++;
diff --git a/drivers/media/platform/soc_camera/soc_camera_platform.c b/drivers/media/platform/soc_camera/soc_camera_platform.c
index ceaddfb..f2ce1ab 100644
--- a/drivers/media/platform/soc_camera/soc_camera_platform.c
+++ b/drivers/media/platform/soc_camera/soc_camera_platform.c
@@ -62,7 +62,7 @@ static struct v4l2_subdev_core_ops platform_subdev_core_ops = {
};
static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code)
+ u32 *code)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
diff --git a/drivers/media/platform/soc_camera/soc_mediabus.c b/drivers/media/platform/soc_camera/soc_mediabus.c
index dc02dec..1dbcd42 100644
--- a/drivers/media/platform/soc_camera/soc_mediabus.c
+++ b/drivers/media/platform/soc_camera/soc_mediabus.c
@@ -17,7 +17,7 @@
static const struct soc_mbus_lookup mbus_fmt[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .code = MEDIA_BUS_FMT_YUYV8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
@@ -27,7 +27,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .code = MEDIA_BUS_FMT_YVYU8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
@@ -37,7 +37,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .code = MEDIA_BUS_FMT_UYVY8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
@@ -47,7 +47,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .code = MEDIA_BUS_FMT_VYUY8_2X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
@@ -57,7 +57,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB555,
.name = "RGB555",
@@ -67,7 +67,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE,
+ .code = MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB555X,
.name = "RGB555X",
@@ -77,7 +77,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB565,
.name = "RGB565",
@@ -87,7 +87,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .code = MEDIA_BUS_FMT_RGB565_2X8_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB565X,
.name = "RGB565X",
@@ -97,7 +97,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB666_1X18,
+ .code = MEDIA_BUS_FMT_RGB666_1X18,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB32,
.name = "RGB666/32bpp",
@@ -106,7 +106,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_RGB888_1X24,
+ .code = MEDIA_BUS_FMT_RGB888_1X24,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB32,
.name = "RGB888/32bpp",
@@ -115,7 +115,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_RGB888_2X12_BE,
+ .code = MEDIA_BUS_FMT_RGB888_2X12_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB32,
.name = "RGB888/32bpp",
@@ -124,7 +124,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_BE,
},
}, {
- .code = V4L2_MBUS_FMT_RGB888_2X12_LE,
+ .code = MEDIA_BUS_FMT_RGB888_2X12_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB32,
.name = "RGB888/32bpp",
@@ -133,7 +133,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.order = SOC_MBUS_ORDER_LE,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .code = MEDIA_BUS_FMT_SBGGR8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR8,
.name = "Bayer 8 BGGR",
@@ -143,7 +143,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_1X10,
+ .code = MEDIA_BUS_FMT_SBGGR10_1X10,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
@@ -153,7 +153,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_Y8_1X8,
+ .code = MEDIA_BUS_FMT_Y8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_GREY,
.name = "Grey",
@@ -163,7 +163,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_Y10_1X10,
+ .code = MEDIA_BUS_FMT_Y10_1X10,
.fmt = {
.fourcc = V4L2_PIX_FMT_Y10,
.name = "Grey 10bit",
@@ -173,7 +173,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE,
+ .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
@@ -183,7 +183,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE,
+ .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
@@ -193,7 +193,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE,
+ .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
@@ -203,7 +203,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE,
+ .code = MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR10,
.name = "Bayer 10 BGGR",
@@ -213,7 +213,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_JPEG_1X8,
+ .code = MEDIA_BUS_FMT_JPEG_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_JPEG,
.name = "JPEG",
@@ -223,7 +223,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE,
+ .code = MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE,
.fmt = {
.fourcc = V4L2_PIX_FMT_RGB444,
.name = "RGB444",
@@ -233,7 +233,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YUYV8_1_5X8,
+ .code = MEDIA_BUS_FMT_YUYV8_1_5X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_YUV420,
.name = "YUYV 4:2:0",
@@ -243,7 +243,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YVYU8_1_5X8,
+ .code = MEDIA_BUS_FMT_YVYU8_1_5X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_YVU420,
.name = "YVYU 4:2:0",
@@ -253,7 +253,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_UYVY8_1X16,
+ .code = MEDIA_BUS_FMT_UYVY8_1X16,
.fmt = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY 16bit",
@@ -263,7 +263,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_VYUY8_1X16,
+ .code = MEDIA_BUS_FMT_VYUY8_1X16,
.fmt = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY 16bit",
@@ -273,7 +273,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YUYV8_1X16,
+ .code = MEDIA_BUS_FMT_YUYV8_1X16,
.fmt = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV 16bit",
@@ -283,7 +283,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_YVYU8_1X16,
+ .code = MEDIA_BUS_FMT_YVYU8_1X16,
.fmt = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU 16bit",
@@ -293,7 +293,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SGRBG8_1X8,
+ .code = MEDIA_BUS_FMT_SGRBG8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGRBG8,
.name = "Bayer 8 GRBG",
@@ -303,7 +303,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ .code = MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGRBG10DPCM8,
.name = "Bayer 10 BGGR DPCM 8",
@@ -313,7 +313,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SGBRG10_1X10,
+ .code = MEDIA_BUS_FMT_SGBRG10_1X10,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGBRG10,
.name = "Bayer 10 GBRG",
@@ -323,7 +323,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SGRBG10_1X10,
+ .code = MEDIA_BUS_FMT_SGRBG10_1X10,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGRBG10,
.name = "Bayer 10 GRBG",
@@ -333,7 +333,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SRGGB10_1X10,
+ .code = MEDIA_BUS_FMT_SRGGB10_1X10,
.fmt = {
.fourcc = V4L2_PIX_FMT_SRGGB10,
.name = "Bayer 10 RGGB",
@@ -343,7 +343,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SBGGR12_1X12,
+ .code = MEDIA_BUS_FMT_SBGGR12_1X12,
.fmt = {
.fourcc = V4L2_PIX_FMT_SBGGR12,
.name = "Bayer 12 BGGR",
@@ -353,7 +353,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SGBRG12_1X12,
+ .code = MEDIA_BUS_FMT_SGBRG12_1X12,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGBRG12,
.name = "Bayer 12 GBRG",
@@ -363,7 +363,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SGRBG12_1X12,
+ .code = MEDIA_BUS_FMT_SGRBG12_1X12,
.fmt = {
.fourcc = V4L2_PIX_FMT_SGRBG12,
.name = "Bayer 12 GRBG",
@@ -373,7 +373,7 @@ static const struct soc_mbus_lookup mbus_fmt[] = {
.layout = SOC_MBUS_LAYOUT_PACKED,
},
}, {
- .code = V4L2_MBUS_FMT_SRGGB12_1X12,
+ .code = MEDIA_BUS_FMT_SRGGB12_1X12,
.fmt = {
.fourcc = V4L2_PIX_FMT_SRGGB12,
.name = "Bayer 12 RGGB",
@@ -458,7 +458,7 @@ s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
EXPORT_SYMBOL(soc_mbus_image_size);
const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
- enum v4l2_mbus_pixelcode code,
+ u32 code,
const struct soc_mbus_lookup *lookup,
int n)
{
@@ -473,7 +473,7 @@ const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
EXPORT_SYMBOL(soc_mbus_find_fmtdesc);
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
- enum v4l2_mbus_pixelcode code)
+ u32 code)
{
return soc_mbus_find_fmtdesc(code, mbus_fmt, ARRAY_SIZE(mbus_fmt));
}
diff --git a/drivers/media/platform/ti-vpe/csc.c b/drivers/media/platform/ti-vpe/csc.c
index 940df40..bec6749 100644
--- a/drivers/media/platform/ti-vpe/csc.c
+++ b/drivers/media/platform/ti-vpe/csc.c
@@ -93,12 +93,8 @@ void csc_dump_regs(struct csc_data *csc)
{
struct device *dev = &csc->pdev->dev;
- u32 read_reg(struct csc_data *csc, int offset)
- {
- return ioread32(csc->base + offset);
- }
-
-#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(csc, CSC_##r))
+#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \
+ ioread32(csc->base + CSC_##r))
DUMPREG(CSC00);
DUMPREG(CSC01);
@@ -189,7 +185,7 @@ struct csc_data *csc_create(struct platform_device *pdev)
csc->base = devm_ioremap_resource(&pdev->dev, csc->res);
if (IS_ERR(csc->base)) {
dev_err(&pdev->dev, "failed to ioremap\n");
- return csc->base;
+ return ERR_CAST(csc->base);
}
return csc;
diff --git a/drivers/media/platform/ti-vpe/sc.c b/drivers/media/platform/ti-vpe/sc.c
index 6314171..f82d1c7 100644
--- a/drivers/media/platform/ti-vpe/sc.c
+++ b/drivers/media/platform/ti-vpe/sc.c
@@ -24,12 +24,8 @@ void sc_dump_regs(struct sc_data *sc)
{
struct device *dev = &sc->pdev->dev;
- u32 read_reg(struct sc_data *sc, int offset)
- {
- return ioread32(sc->base + offset);
- }
-
-#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, read_reg(sc, CFG_##r))
+#define DUMPREG(r) dev_dbg(dev, "%-35s %08x\n", #r, \
+ ioread32(sc->base + CFG_##r))
DUMPREG(SC0);
DUMPREG(SC1);
@@ -304,7 +300,7 @@ struct sc_data *sc_create(struct platform_device *pdev)
sc->base = devm_ioremap_resource(&pdev->dev, sc->res);
if (IS_ERR(sc->base)) {
dev_err(&pdev->dev, "failed to ioremap\n");
- return sc->base;
+ return ERR_CAST(sc->base);
}
return sc;
diff --git a/drivers/media/platform/via-camera.c b/drivers/media/platform/via-camera.c
index ae6870c..86989d8 100644
--- a/drivers/media/platform/via-camera.c
+++ b/drivers/media/platform/via-camera.c
@@ -101,7 +101,7 @@ struct via_camera {
*/
struct v4l2_pix_format sensor_format;
struct v4l2_pix_format user_format;
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
};
/*
@@ -143,12 +143,12 @@ static struct via_format {
__u8 *desc;
__u32 pixelformat;
int bpp; /* Bytes per pixel */
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
} via_formats[] = {
{
.desc = "YUYV 4:2:2",
.pixelformat = V4L2_PIX_FMT_YUYV,
- .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .mbus_code = MEDIA_BUS_FMT_YUYV8_2X8,
.bpp = 2,
},
/* RGB444 and Bayer should be doable, but have never been
@@ -849,7 +849,7 @@ static const struct v4l2_pix_format viacam_def_pix_format = {
.sizeimage = VGA_WIDTH * VGA_HEIGHT * 2,
};
-static const enum v4l2_mbus_pixelcode via_def_mbus_code = V4L2_MBUS_FMT_YUYV8_2X8;
+static const u32 via_def_mbus_code = MEDIA_BUS_FMT_YUYV8_2X8;
static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_fmtdesc *fmt)
@@ -985,9 +985,9 @@ static int viacam_querycap(struct file *filp, void *priv,
{
strcpy(cap->driver, "via-camera");
strcpy(cap->card, "via-camera");
- cap->version = 1;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/mem2mem_testdev.c b/drivers/media/platform/vim2m.c
index c1b03cf..1105c11 100644
--- a/drivers/media/platform/mem2mem_testdev.c
+++ b/drivers/media/platform/vim2m.c
@@ -31,12 +31,11 @@
#include <media/v4l2-event.h>
#include <media/videobuf2-vmalloc.h>
-#define MEM2MEM_TEST_MODULE_NAME "mem2mem-testdev"
-
MODULE_DESCRIPTION("Virtual device for mem2mem framework testing");
MODULE_AUTHOR("Pawel Osciak, <pawel@osciak.com>");
MODULE_LICENSE("GPL");
MODULE_VERSION("0.1.1");
+MODULE_ALIAS("mem2mem_testdev");
static unsigned debug;
module_param(debug, uint, 0644);
@@ -52,7 +51,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define MEM2MEM_CAPTURE (1 << 0)
#define MEM2MEM_OUTPUT (1 << 1)
-#define MEM2MEM_NAME "m2m-testdev"
+#define MEM2MEM_NAME "vim2m"
/* Per queue */
#define MEM2MEM_DEF_NUM_BUFS VIDEO_MAX_FRAME
@@ -72,15 +71,15 @@ MODULE_PARM_DESC(debug, "activates debug info");
v4l2_dbg(1, debug, &dev->v4l2_dev, "%s: " fmt, __func__, ## arg)
-static void m2mtest_dev_release(struct device *dev)
+static void vim2m_dev_release(struct device *dev)
{}
-static struct platform_device m2mtest_pdev = {
+static struct platform_device vim2m_pdev = {
.name = MEM2MEM_NAME,
- .dev.release = m2mtest_dev_release,
+ .dev.release = vim2m_dev_release,
};
-struct m2mtest_fmt {
+struct vim2m_fmt {
char *name;
u32 fourcc;
int depth;
@@ -88,7 +87,7 @@ struct m2mtest_fmt {
u32 types;
};
-static struct m2mtest_fmt formats[] = {
+static struct vim2m_fmt formats[] = {
{
.name = "RGB565 (BE)",
.fourcc = V4L2_PIX_FMT_RGB565X, /* rrrrrggg gggbbbbb */
@@ -108,12 +107,12 @@ static struct m2mtest_fmt formats[] = {
#define NUM_FORMATS ARRAY_SIZE(formats)
/* Per-queue, driver-specific private data */
-struct m2mtest_q_data {
+struct vim2m_q_data {
unsigned int width;
unsigned int height;
unsigned int sizeimage;
unsigned int sequence;
- struct m2mtest_fmt *fmt;
+ struct vim2m_fmt *fmt;
};
enum {
@@ -124,9 +123,9 @@ enum {
#define V4L2_CID_TRANS_TIME_MSEC (V4L2_CID_USER_BASE + 0x1000)
#define V4L2_CID_TRANS_NUM_BUFS (V4L2_CID_USER_BASE + 0x1001)
-static struct m2mtest_fmt *find_format(struct v4l2_format *f)
+static struct vim2m_fmt *find_format(struct v4l2_format *f)
{
- struct m2mtest_fmt *fmt;
+ struct vim2m_fmt *fmt;
unsigned int k;
for (k = 0; k < NUM_FORMATS; k++) {
@@ -141,7 +140,7 @@ static struct m2mtest_fmt *find_format(struct v4l2_format *f)
return &formats[k];
}
-struct m2mtest_dev {
+struct vim2m_dev {
struct v4l2_device v4l2_dev;
struct video_device *vfd;
@@ -154,9 +153,9 @@ struct m2mtest_dev {
struct v4l2_m2m_dev *m2m_dev;
};
-struct m2mtest_ctx {
+struct vim2m_ctx {
struct v4l2_fh fh;
- struct m2mtest_dev *dev;
+ struct vim2m_dev *dev;
struct v4l2_ctrl_handler hdl;
@@ -177,15 +176,15 @@ struct m2mtest_ctx {
enum v4l2_colorspace colorspace;
/* Source and destination queue data */
- struct m2mtest_q_data q_data[2];
+ struct vim2m_q_data q_data[2];
};
-static inline struct m2mtest_ctx *file2ctx(struct file *file)
+static inline struct vim2m_ctx *file2ctx(struct file *file)
{
- return container_of(file->private_data, struct m2mtest_ctx, fh);
+ return container_of(file->private_data, struct vim2m_ctx, fh);
}
-static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx,
+static struct vim2m_q_data *get_q_data(struct vim2m_ctx *ctx,
enum v4l2_buf_type type)
{
switch (type) {
@@ -200,12 +199,12 @@ static struct m2mtest_q_data *get_q_data(struct m2mtest_ctx *ctx,
}
-static int device_process(struct m2mtest_ctx *ctx,
+static int device_process(struct vim2m_ctx *ctx,
struct vb2_buffer *in_vb,
struct vb2_buffer *out_vb)
{
- struct m2mtest_dev *dev = ctx->dev;
- struct m2mtest_q_data *q_data;
+ struct vim2m_dev *dev = ctx->dev;
+ struct vim2m_q_data *q_data;
u8 *p_in, *p_out;
int x, y, t, w;
int tile_w, bytes_left;
@@ -334,7 +333,7 @@ static int device_process(struct m2mtest_ctx *ctx,
return 0;
}
-static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
+static void schedule_irq(struct vim2m_dev *dev, int msec_timeout)
{
dprintk(dev, "Scheduling a simulated irq\n");
mod_timer(&dev->timer, jiffies + msecs_to_jiffies(msec_timeout));
@@ -349,7 +348,7 @@ static void schedule_irq(struct m2mtest_dev *dev, int msec_timeout)
*/
static int job_ready(void *priv)
{
- struct m2mtest_ctx *ctx = priv;
+ struct vim2m_ctx *ctx = priv;
if (v4l2_m2m_num_src_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen
|| v4l2_m2m_num_dst_bufs_ready(ctx->fh.m2m_ctx) < ctx->translen) {
@@ -362,7 +361,7 @@ static int job_ready(void *priv)
static void job_abort(void *priv)
{
- struct m2mtest_ctx *ctx = priv;
+ struct vim2m_ctx *ctx = priv;
/* Will cancel the transaction in the next interrupt handler */
ctx->aborting = 1;
@@ -376,8 +375,8 @@ static void job_abort(void *priv)
*/
static void device_run(void *priv)
{
- struct m2mtest_ctx *ctx = priv;
- struct m2mtest_dev *dev = ctx->dev;
+ struct vim2m_ctx *ctx = priv;
+ struct vim2m_dev *dev = ctx->dev;
struct vb2_buffer *src_buf, *dst_buf;
src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
@@ -391,12 +390,12 @@ static void device_run(void *priv)
static void device_isr(unsigned long priv)
{
- struct m2mtest_dev *m2mtest_dev = (struct m2mtest_dev *)priv;
- struct m2mtest_ctx *curr_ctx;
+ struct vim2m_dev *vim2m_dev = (struct vim2m_dev *)priv;
+ struct vim2m_ctx *curr_ctx;
struct vb2_buffer *src_vb, *dst_vb;
unsigned long flags;
- curr_ctx = v4l2_m2m_get_curr_priv(m2mtest_dev->m2m_dev);
+ curr_ctx = v4l2_m2m_get_curr_priv(vim2m_dev->m2m_dev);
if (NULL == curr_ctx) {
pr_err("Instance released before the end of transaction\n");
@@ -408,16 +407,16 @@ static void device_isr(unsigned long priv)
curr_ctx->num_processed++;
- spin_lock_irqsave(&m2mtest_dev->irqlock, flags);
+ spin_lock_irqsave(&vim2m_dev->irqlock, flags);
v4l2_m2m_buf_done(src_vb, VB2_BUF_STATE_DONE);
v4l2_m2m_buf_done(dst_vb, VB2_BUF_STATE_DONE);
- spin_unlock_irqrestore(&m2mtest_dev->irqlock, flags);
+ spin_unlock_irqrestore(&vim2m_dev->irqlock, flags);
if (curr_ctx->num_processed == curr_ctx->translen
|| curr_ctx->aborting) {
dprintk(curr_ctx->dev, "Finishing transaction\n");
curr_ctx->num_processed = 0;
- v4l2_m2m_job_finish(m2mtest_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
+ v4l2_m2m_job_finish(vim2m_dev->m2m_dev, curr_ctx->fh.m2m_ctx);
} else {
device_run(curr_ctx);
}
@@ -441,7 +440,7 @@ static int vidioc_querycap(struct file *file, void *priv,
static int enum_fmt(struct v4l2_fmtdesc *f, u32 type)
{
int i, num;
- struct m2mtest_fmt *fmt;
+ struct vim2m_fmt *fmt;
num = 0;
@@ -480,10 +479,10 @@ static int vidioc_enum_fmt_vid_out(struct file *file, void *priv,
return enum_fmt(f, MEM2MEM_OUTPUT);
}
-static int vidioc_g_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+static int vidioc_g_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
{
struct vb2_queue *vq;
- struct m2mtest_q_data *q_data;
+ struct vim2m_q_data *q_data;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
if (!vq)
@@ -514,7 +513,7 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
return vidioc_g_fmt(file2ctx(file), f);
}
-static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
+static int vidioc_try_fmt(struct v4l2_format *f, struct vim2m_fmt *fmt)
{
/* V4L2 specification suggests the driver corrects the format struct
* if any of the dimensions is unsupported */
@@ -539,8 +538,8 @@ static int vidioc_try_fmt(struct v4l2_format *f, struct m2mtest_fmt *fmt)
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct m2mtest_fmt *fmt;
- struct m2mtest_ctx *ctx = file2ctx(file);
+ struct vim2m_fmt *fmt;
+ struct vim2m_ctx *ctx = file2ctx(file);
fmt = find_format(f);
if (!fmt) {
@@ -561,8 +560,8 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct m2mtest_fmt *fmt;
- struct m2mtest_ctx *ctx = file2ctx(file);
+ struct vim2m_fmt *fmt;
+ struct vim2m_ctx *ctx = file2ctx(file);
fmt = find_format(f);
if (!fmt) {
@@ -581,9 +580,9 @@ static int vidioc_try_fmt_vid_out(struct file *file, void *priv,
return vidioc_try_fmt(f, fmt);
}
-static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
+static int vidioc_s_fmt(struct vim2m_ctx *ctx, struct v4l2_format *f)
{
- struct m2mtest_q_data *q_data;
+ struct vim2m_q_data *q_data;
struct vb2_queue *vq;
vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
@@ -627,7 +626,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
struct v4l2_format *f)
{
- struct m2mtest_ctx *ctx = file2ctx(file);
+ struct vim2m_ctx *ctx = file2ctx(file);
int ret;
ret = vidioc_try_fmt_vid_out(file, priv, f);
@@ -640,10 +639,10 @@ static int vidioc_s_fmt_vid_out(struct file *file, void *priv,
return ret;
}
-static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
+static int vim2m_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct m2mtest_ctx *ctx =
- container_of(ctrl->handler, struct m2mtest_ctx, hdl);
+ struct vim2m_ctx *ctx =
+ container_of(ctrl->handler, struct vim2m_ctx, hdl);
switch (ctrl->id) {
case V4L2_CID_HFLIP:
@@ -676,12 +675,12 @@ static int m2mtest_s_ctrl(struct v4l2_ctrl *ctrl)
return 0;
}
-static const struct v4l2_ctrl_ops m2mtest_ctrl_ops = {
- .s_ctrl = m2mtest_s_ctrl,
+static const struct v4l2_ctrl_ops vim2m_ctrl_ops = {
+ .s_ctrl = vim2m_s_ctrl,
};
-static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
+static const struct v4l2_ioctl_ops vim2m_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
@@ -698,6 +697,7 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
.vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
.vidioc_qbuf = v4l2_m2m_ioctl_qbuf,
.vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
.vidioc_streamon = v4l2_m2m_ioctl_streamon,
.vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
@@ -711,13 +711,13 @@ static const struct v4l2_ioctl_ops m2mtest_ioctl_ops = {
* Queue operations
*/
-static int m2mtest_queue_setup(struct vb2_queue *vq,
+static int vim2m_queue_setup(struct vb2_queue *vq,
const struct v4l2_format *fmt,
unsigned int *nbuffers, unsigned int *nplanes,
unsigned int sizes[], void *alloc_ctxs[])
{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(vq);
- struct m2mtest_q_data *q_data;
+ struct vim2m_ctx *ctx = vb2_get_drv_priv(vq);
+ struct vim2m_q_data *q_data;
unsigned int size, count = *nbuffers;
q_data = get_q_data(ctx, vq->type);
@@ -741,10 +741,10 @@ static int m2mtest_queue_setup(struct vb2_queue *vq,
return 0;
}
-static int m2mtest_buf_prepare(struct vb2_buffer *vb)
+static int vim2m_buf_prepare(struct vb2_buffer *vb)
{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
- struct m2mtest_q_data *q_data;
+ struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vim2m_q_data *q_data;
dprintk(ctx->dev, "type: %d\n", vb->vb2_queue->type);
@@ -770,25 +770,25 @@ static int m2mtest_buf_prepare(struct vb2_buffer *vb)
return 0;
}
-static void m2mtest_buf_queue(struct vb2_buffer *vb)
+static void vim2m_buf_queue(struct vb2_buffer *vb)
{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct vim2m_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, vb);
}
-static int m2mtest_start_streaming(struct vb2_queue *q, unsigned count)
+static int vim2m_start_streaming(struct vb2_queue *q, unsigned count)
{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
- struct m2mtest_q_data *q_data = get_q_data(ctx, q->type);
+ struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
+ struct vim2m_q_data *q_data = get_q_data(ctx, q->type);
q_data->sequence = 0;
return 0;
}
-static void m2mtest_stop_streaming(struct vb2_queue *q)
+static void vim2m_stop_streaming(struct vb2_queue *q)
{
- struct m2mtest_ctx *ctx = vb2_get_drv_priv(q);
+ struct vim2m_ctx *ctx = vb2_get_drv_priv(q);
struct vb2_buffer *vb;
unsigned long flags;
@@ -805,26 +805,26 @@ static void m2mtest_stop_streaming(struct vb2_queue *q)
}
}
-static struct vb2_ops m2mtest_qops = {
- .queue_setup = m2mtest_queue_setup,
- .buf_prepare = m2mtest_buf_prepare,
- .buf_queue = m2mtest_buf_queue,
- .start_streaming = m2mtest_start_streaming,
- .stop_streaming = m2mtest_stop_streaming,
+static struct vb2_ops vim2m_qops = {
+ .queue_setup = vim2m_queue_setup,
+ .buf_prepare = vim2m_buf_prepare,
+ .buf_queue = vim2m_buf_queue,
+ .start_streaming = vim2m_start_streaming,
+ .stop_streaming = vim2m_stop_streaming,
.wait_prepare = vb2_ops_wait_prepare,
.wait_finish = vb2_ops_wait_finish,
};
static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *dst_vq)
{
- struct m2mtest_ctx *ctx = priv;
+ struct vim2m_ctx *ctx = priv;
int ret;
src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT;
src_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
src_vq->drv_priv = ctx;
src_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- src_vq->ops = &m2mtest_qops;
+ src_vq->ops = &vim2m_qops;
src_vq->mem_ops = &vb2_vmalloc_memops;
src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
src_vq->lock = &ctx->dev->dev_mutex;
@@ -837,7 +837,7 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
dst_vq->io_modes = VB2_MMAP | VB2_USERPTR | VB2_DMABUF;
dst_vq->drv_priv = ctx;
dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
- dst_vq->ops = &m2mtest_qops;
+ dst_vq->ops = &vim2m_qops;
dst_vq->mem_ops = &vb2_vmalloc_memops;
dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
dst_vq->lock = &ctx->dev->dev_mutex;
@@ -845,8 +845,8 @@ static int queue_init(void *priv, struct vb2_queue *src_vq, struct vb2_queue *ds
return vb2_queue_init(dst_vq);
}
-static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
- .ops = &m2mtest_ctrl_ops,
+static const struct v4l2_ctrl_config vim2m_ctrl_trans_time_msec = {
+ .ops = &vim2m_ctrl_ops,
.id = V4L2_CID_TRANS_TIME_MSEC,
.name = "Transaction Time (msec)",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -856,8 +856,8 @@ static const struct v4l2_ctrl_config m2mtest_ctrl_trans_time_msec = {
.step = 1,
};
-static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
- .ops = &m2mtest_ctrl_ops,
+static const struct v4l2_ctrl_config vim2m_ctrl_trans_num_bufs = {
+ .ops = &vim2m_ctrl_ops,
.id = V4L2_CID_TRANS_NUM_BUFS,
.name = "Buffers Per Transaction",
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -870,10 +870,10 @@ static const struct v4l2_ctrl_config m2mtest_ctrl_trans_num_bufs = {
/*
* File operations
*/
-static int m2mtest_open(struct file *file)
+static int vim2m_open(struct file *file)
{
- struct m2mtest_dev *dev = video_drvdata(file);
- struct m2mtest_ctx *ctx = NULL;
+ struct vim2m_dev *dev = video_drvdata(file);
+ struct vim2m_ctx *ctx = NULL;
struct v4l2_ctrl_handler *hdl;
int rc = 0;
@@ -890,10 +890,10 @@ static int m2mtest_open(struct file *file)
ctx->dev = dev;
hdl = &ctx->hdl;
v4l2_ctrl_handler_init(hdl, 4);
- v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_std(hdl, &m2mtest_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
- v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_time_msec, NULL);
- v4l2_ctrl_new_custom(hdl, &m2mtest_ctrl_trans_num_bufs, NULL);
+ v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_HFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_std(hdl, &vim2m_ctrl_ops, V4L2_CID_VFLIP, 0, 1, 1, 0);
+ v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_time_msec, NULL);
+ v4l2_ctrl_new_custom(hdl, &vim2m_ctrl_trans_num_bufs, NULL);
if (hdl->error) {
rc = hdl->error;
v4l2_ctrl_handler_free(hdl);
@@ -933,10 +933,10 @@ open_unlock:
return rc;
}
-static int m2mtest_release(struct file *file)
+static int vim2m_release(struct file *file)
{
- struct m2mtest_dev *dev = video_drvdata(file);
- struct m2mtest_ctx *ctx = file2ctx(file);
+ struct vim2m_dev *dev = video_drvdata(file);
+ struct vim2m_ctx *ctx = file2ctx(file);
dprintk(dev, "Releasing instance %p\n", ctx);
@@ -953,20 +953,20 @@ static int m2mtest_release(struct file *file)
return 0;
}
-static const struct v4l2_file_operations m2mtest_fops = {
+static const struct v4l2_file_operations vim2m_fops = {
.owner = THIS_MODULE,
- .open = m2mtest_open,
- .release = m2mtest_release,
+ .open = vim2m_open,
+ .release = vim2m_release,
.poll = v4l2_m2m_fop_poll,
.unlocked_ioctl = video_ioctl2,
.mmap = v4l2_m2m_fop_mmap,
};
-static struct video_device m2mtest_videodev = {
+static struct video_device vim2m_videodev = {
.name = MEM2MEM_NAME,
.vfl_dir = VFL_DIR_M2M,
- .fops = &m2mtest_fops,
- .ioctl_ops = &m2mtest_ioctl_ops,
+ .fops = &vim2m_fops,
+ .ioctl_ops = &vim2m_ioctl_ops,
.minor = -1,
.release = video_device_release,
};
@@ -977,9 +977,9 @@ static struct v4l2_m2m_ops m2m_ops = {
.job_abort = job_abort,
};
-static int m2mtest_probe(struct platform_device *pdev)
+static int vim2m_probe(struct platform_device *pdev)
{
- struct m2mtest_dev *dev;
+ struct vim2m_dev *dev;
struct video_device *vfd;
int ret;
@@ -1003,7 +1003,7 @@ static int m2mtest_probe(struct platform_device *pdev)
goto unreg_dev;
}
- *vfd = m2mtest_videodev;
+ *vfd = vim2m_videodev;
vfd->lock = &dev->dev_mutex;
vfd->v4l2_dev = &dev->v4l2_dev;
@@ -1014,7 +1014,7 @@ static int m2mtest_probe(struct platform_device *pdev)
}
video_set_drvdata(vfd, dev);
- snprintf(vfd->name, sizeof(vfd->name), "%s", m2mtest_videodev.name);
+ snprintf(vfd->name, sizeof(vfd->name), "%s", vim2m_videodev.name);
dev->vfd = vfd;
v4l2_info(&dev->v4l2_dev,
"Device registered as /dev/video%d\n", vfd->num);
@@ -1042,11 +1042,11 @@ unreg_dev:
return ret;
}
-static int m2mtest_remove(struct platform_device *pdev)
+static int vim2m_remove(struct platform_device *pdev)
{
- struct m2mtest_dev *dev = platform_get_drvdata(pdev);
+ struct vim2m_dev *dev = platform_get_drvdata(pdev);
- v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_TEST_MODULE_NAME);
+ v4l2_info(&dev->v4l2_dev, "Removing " MEM2MEM_NAME);
v4l2_m2m_release(dev->m2m_dev);
del_timer_sync(&dev->timer);
video_unregister_device(dev->vfd);
@@ -1055,35 +1055,35 @@ static int m2mtest_remove(struct platform_device *pdev)
return 0;
}
-static struct platform_driver m2mtest_pdrv = {
- .probe = m2mtest_probe,
- .remove = m2mtest_remove,
+static struct platform_driver vim2m_pdrv = {
+ .probe = vim2m_probe,
+ .remove = vim2m_remove,
.driver = {
.name = MEM2MEM_NAME,
.owner = THIS_MODULE,
},
};
-static void __exit m2mtest_exit(void)
+static void __exit vim2m_exit(void)
{
- platform_driver_unregister(&m2mtest_pdrv);
- platform_device_unregister(&m2mtest_pdev);
+ platform_driver_unregister(&vim2m_pdrv);
+ platform_device_unregister(&vim2m_pdev);
}
-static int __init m2mtest_init(void)
+static int __init vim2m_init(void)
{
int ret;
- ret = platform_device_register(&m2mtest_pdev);
+ ret = platform_device_register(&vim2m_pdev);
if (ret)
return ret;
- ret = platform_driver_register(&m2mtest_pdrv);
+ ret = platform_driver_register(&vim2m_pdrv);
if (ret)
- platform_device_unregister(&m2mtest_pdev);
+ platform_device_unregister(&vim2m_pdev);
return 0;
}
-module_init(m2mtest_init);
-module_exit(m2mtest_exit);
+module_init(vim2m_init);
+module_exit(vim2m_exit);
diff --git a/drivers/media/platform/vino.c b/drivers/media/platform/vino.c
index 91d44ea1..2c85357 100644
--- a/drivers/media/platform/vino.c
+++ b/drivers/media/platform/vino.c
@@ -2932,10 +2932,8 @@ static int vino_querycap(struct file *file, void *__fh,
strcpy(cap->driver, vino_driver_name);
strcpy(cap->card, vino_driver_description);
strcpy(cap->bus_info, vino_bus_name);
- cap->capabilities =
- V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING;
- // V4L2_CAP_OVERLAY, V4L2_CAP_READWRITE
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/platform/vivid/vivid-core.c b/drivers/media/platform/vivid/vivid-core.c
index 686c3c2..a7e033a 100644
--- a/drivers/media/platform/vivid/vivid-core.c
+++ b/drivers/media/platform/vivid/vivid-core.c
@@ -195,20 +195,6 @@ static const u8 vivid_hdmi_edid[256] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xd7
};
-void vivid_lock(struct vb2_queue *vq)
-{
- struct vivid_dev *dev = vb2_get_drv_priv(vq);
-
- mutex_lock(&dev->mutex);
-}
-
-void vivid_unlock(struct vb2_queue *vq)
-{
- struct vivid_dev *dev = vb2_get_drv_priv(vq);
-
- mutex_unlock(&dev->mutex);
-}
-
static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -586,7 +572,7 @@ static const struct v4l2_ioctl_ops vivid_ioctl_ops = {
.vidioc_querybuf = vb2_ioctl_querybuf,
.vidioc_qbuf = vb2_ioctl_qbuf,
.vidioc_dqbuf = vb2_ioctl_dqbuf,
-/* Not yet .vidioc_expbuf = vb2_ioctl_expbuf,*/
+ .vidioc_expbuf = vb2_ioctl_expbuf,
.vidioc_streamon = vb2_ioctl_streamon,
.vidioc_streamoff = vb2_ioctl_streamoff,
@@ -1018,6 +1004,7 @@ static int __init vivid_create_instance(int inst)
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
ret = vb2_queue_init(q);
if (ret)
@@ -1036,6 +1023,7 @@ static int __init vivid_create_instance(int inst)
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
ret = vb2_queue_init(q);
if (ret)
@@ -1054,6 +1042,7 @@ static int __init vivid_create_instance(int inst)
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
ret = vb2_queue_init(q);
if (ret)
@@ -1072,6 +1061,7 @@ static int __init vivid_create_instance(int inst)
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 2;
+ q->lock = &dev->mutex;
ret = vb2_queue_init(q);
if (ret)
@@ -1089,6 +1079,7 @@ static int __init vivid_create_instance(int inst)
q->mem_ops = &vb2_vmalloc_memops;
q->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_MONOTONIC;
q->min_buffers_needed = 8;
+ q->lock = &dev->mutex;
ret = vb2_queue_init(q);
if (ret)
diff --git a/drivers/media/platform/vivid/vivid-core.h b/drivers/media/platform/vivid/vivid-core.h
index 811c286..4b497df 100644
--- a/drivers/media/platform/vivid/vivid-core.h
+++ b/drivers/media/platform/vivid/vivid-core.h
@@ -116,6 +116,17 @@ enum vivid_signal_mode {
CUSTOM_DV_TIMINGS,
};
+enum vivid_colorspace {
+ VIVID_CS_170M,
+ VIVID_CS_709,
+ VIVID_CS_SRGB,
+ VIVID_CS_ADOBERGB,
+ VIVID_CS_2020,
+ VIVID_CS_240M,
+ VIVID_CS_SYS_M,
+ VIVID_CS_SYS_BG,
+};
+
#define VIVID_INVALID_SIGNAL(mode) \
((mode) == NO_SIGNAL || (mode) == NO_LOCK || (mode) == OUT_OF_RANGE)
@@ -318,6 +329,8 @@ struct vivid_dev {
v4l2_std_id std_out;
struct v4l2_dv_timings dv_timings_out;
u32 colorspace_out;
+ u32 ycbcr_enc_out;
+ u32 quantization_out;
u32 service_set_out;
u32 bytesperline_out[2];
unsigned tv_field_out;
@@ -514,7 +527,4 @@ static inline bool vivid_is_hdmi_out(const struct vivid_dev *dev)
return dev->output_type[dev->output] == HDMI;
}
-void vivid_lock(struct vb2_queue *vq);
-void vivid_unlock(struct vb2_queue *vq);
-
#endif
diff --git a/drivers/media/platform/vivid/vivid-ctrls.c b/drivers/media/platform/vivid/vivid-ctrls.c
index d5cbf00..857e786 100644
--- a/drivers/media/platform/vivid/vivid-ctrls.c
+++ b/drivers/media/platform/vivid/vivid-ctrls.c
@@ -40,6 +40,9 @@
#define VIVID_CID_STRING (VIVID_CID_CUSTOM_BASE + 5)
#define VIVID_CID_BITMASK (VIVID_CID_CUSTOM_BASE + 6)
#define VIVID_CID_INTMENU (VIVID_CID_CUSTOM_BASE + 7)
+#define VIVID_CID_U32_ARRAY (VIVID_CID_CUSTOM_BASE + 8)
+#define VIVID_CID_U16_MATRIX (VIVID_CID_CUSTOM_BASE + 9)
+#define VIVID_CID_U8_4D_ARRAY (VIVID_CID_CUSTOM_BASE + 10)
#define VIVID_CID_VIVID_BASE (0x00f00000 | 0xf000)
#define VIVID_CID_VIVID_CLASS (0x00f00000 | 1)
@@ -59,19 +62,21 @@
#define VIVID_CID_DV_TIMINGS_ASPECT_RATIO (VIVID_CID_VIVID_BASE + 23)
#define VIVID_CID_TSTAMP_SRC (VIVID_CID_VIVID_BASE + 24)
#define VIVID_CID_COLORSPACE (VIVID_CID_VIVID_BASE + 25)
-#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 26)
-#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 27)
-#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 28)
-#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 29)
-#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 30)
-#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 31)
-#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 32)
-#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 33)
-#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 34)
-#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 35)
-#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 36)
-#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 37)
-#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 38)
+#define VIVID_CID_YCBCR_ENC (VIVID_CID_VIVID_BASE + 26)
+#define VIVID_CID_QUANTIZATION (VIVID_CID_VIVID_BASE + 27)
+#define VIVID_CID_LIMITED_RGB_RANGE (VIVID_CID_VIVID_BASE + 28)
+#define VIVID_CID_ALPHA_MODE (VIVID_CID_VIVID_BASE + 29)
+#define VIVID_CID_HAS_CROP_CAP (VIVID_CID_VIVID_BASE + 30)
+#define VIVID_CID_HAS_COMPOSE_CAP (VIVID_CID_VIVID_BASE + 31)
+#define VIVID_CID_HAS_SCALER_CAP (VIVID_CID_VIVID_BASE + 32)
+#define VIVID_CID_HAS_CROP_OUT (VIVID_CID_VIVID_BASE + 33)
+#define VIVID_CID_HAS_COMPOSE_OUT (VIVID_CID_VIVID_BASE + 34)
+#define VIVID_CID_HAS_SCALER_OUT (VIVID_CID_VIVID_BASE + 35)
+#define VIVID_CID_LOOP_VIDEO (VIVID_CID_VIVID_BASE + 36)
+#define VIVID_CID_SEQ_WRAP (VIVID_CID_VIVID_BASE + 37)
+#define VIVID_CID_TIME_WRAP (VIVID_CID_VIVID_BASE + 38)
+#define VIVID_CID_MAX_EDID_BLOCKS (VIVID_CID_VIVID_BASE + 39)
+#define VIVID_CID_PERCENTAGE_FILL (VIVID_CID_VIVID_BASE + 40)
#define VIVID_CID_STD_SIGNAL_MODE (VIVID_CID_VIVID_BASE + 60)
#define VIVID_CID_STANDARD (VIVID_CID_VIVID_BASE + 61)
@@ -163,6 +168,42 @@ static const struct v4l2_ctrl_config vivid_ctrl_int64 = {
.step = 1,
};
+static const struct v4l2_ctrl_config vivid_ctrl_u32_array = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_U32_ARRAY,
+ .name = "U32 1 Element Array",
+ .type = V4L2_CTRL_TYPE_U32,
+ .def = 0x18,
+ .min = 0x10,
+ .max = 0x20000,
+ .step = 1,
+ .dims = { 1 },
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_u16_matrix = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_U16_MATRIX,
+ .name = "U16 8x16 Matrix",
+ .type = V4L2_CTRL_TYPE_U16,
+ .def = 0x18,
+ .min = 0x10,
+ .max = 0x2000,
+ .step = 1,
+ .dims = { 8, 16 },
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_u8_4d_array = {
+ .ops = &vivid_user_gen_ctrl_ops,
+ .id = VIVID_CID_U8_4D_ARRAY,
+ .name = "U8 2x3x4x5 Array",
+ .type = V4L2_CTRL_TYPE_U8,
+ .def = 0x18,
+ .min = 0x10,
+ .max = 0x20,
+ .step = 1,
+ .dims = { 2, 3, 4, 5 },
+};
+
static const char * const vivid_ctrl_menu_strings[] = {
"Menu Item 0 (Skipped)",
"Menu Item 1",
@@ -294,6 +335,16 @@ static const struct v4l2_ctrl_ops vivid_user_vid_ctrl_ops = {
static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ static const u32 colorspaces[] = {
+ V4L2_COLORSPACE_SMPTE170M,
+ V4L2_COLORSPACE_REC709,
+ V4L2_COLORSPACE_SRGB,
+ V4L2_COLORSPACE_ADOBERGB,
+ V4L2_COLORSPACE_BT2020,
+ V4L2_COLORSPACE_SMPTE240M,
+ V4L2_COLORSPACE_470_SYSTEM_M,
+ V4L2_COLORSPACE_470_SYSTEM_BG,
+ };
struct vivid_dev *dev = container_of(ctrl->handler, struct vivid_dev, ctrl_hdl_vid_cap);
unsigned i;
@@ -303,7 +354,21 @@ static int vivid_vid_cap_s_ctrl(struct v4l2_ctrl *ctrl)
tpg_s_pattern(&dev->tpg, ctrl->val);
break;
case VIVID_CID_COLORSPACE:
- tpg_s_colorspace(&dev->tpg, ctrl->val);
+ tpg_s_colorspace(&dev->tpg, colorspaces[ctrl->val]);
+ vivid_send_source_change(dev, TV);
+ vivid_send_source_change(dev, SVID);
+ vivid_send_source_change(dev, HDMI);
+ vivid_send_source_change(dev, WEBCAM);
+ break;
+ case VIVID_CID_YCBCR_ENC:
+ tpg_s_ycbcr_enc(&dev->tpg, ctrl->val);
+ vivid_send_source_change(dev, TV);
+ vivid_send_source_change(dev, SVID);
+ vivid_send_source_change(dev, HDMI);
+ vivid_send_source_change(dev, WEBCAM);
+ break;
+ case VIVID_CID_QUANTIZATION:
+ tpg_s_quantization(&dev->tpg, ctrl->val);
vivid_send_source_change(dev, TV);
vivid_send_source_change(dev, SVID);
vivid_send_source_change(dev, HDMI);
@@ -623,15 +688,14 @@ static const struct v4l2_ctrl_config vivid_ctrl_max_edid_blocks = {
};
static const char * const vivid_ctrl_colorspace_strings[] = {
- "",
"SMPTE 170M",
- "SMPTE 240M",
"REC 709",
- "", /* Skip Bt878 entry */
+ "sRGB",
+ "AdobeRGB",
+ "BT.2020",
+ "SMPTE 240M",
"470 System M",
"470 System BG",
- "", /* Skip JPEG entry */
- "sRGB",
NULL,
};
@@ -640,13 +704,49 @@ static const struct v4l2_ctrl_config vivid_ctrl_colorspace = {
.id = VIVID_CID_COLORSPACE,
.name = "Colorspace",
.type = V4L2_CTRL_TYPE_MENU,
- .min = 1,
- .max = 8,
- .menu_skip_mask = (1 << 4) | (1 << 7),
- .def = 8,
+ .max = 7,
+ .def = 2,
.qmenu = vivid_ctrl_colorspace_strings,
};
+static const char * const vivid_ctrl_ycbcr_enc_strings[] = {
+ "Default",
+ "ITU-R 601",
+ "Rec. 709",
+ "xvYCC 601",
+ "xvYCC 709",
+ "sYCC",
+ "BT.2020 Non-Constant Luminance",
+ "BT.2020 Constant Luminance",
+ "SMPTE 240M",
+ NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_ycbcr_enc = {
+ .ops = &vivid_vid_cap_ctrl_ops,
+ .id = VIVID_CID_YCBCR_ENC,
+ .name = "Y'CbCr Encoding",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .max = 8,
+ .qmenu = vivid_ctrl_ycbcr_enc_strings,
+};
+
+static const char * const vivid_ctrl_quantization_strings[] = {
+ "Default",
+ "Full Range",
+ "Limited Range",
+ NULL,
+};
+
+static const struct v4l2_ctrl_config vivid_ctrl_quantization = {
+ .ops = &vivid_vid_cap_ctrl_ops,
+ .id = VIVID_CID_QUANTIZATION,
+ .name = "Quantization",
+ .type = V4L2_CTRL_TYPE_MENU,
+ .max = 2,
+ .qmenu = vivid_ctrl_quantization_strings,
+};
+
static const struct v4l2_ctrl_config vivid_ctrl_alpha_mode = {
.ops = &vivid_vid_cap_ctrl_ops,
.id = VIVID_CID_ALPHA_MODE,
@@ -723,8 +823,12 @@ static int vivid_vid_out_s_ctrl(struct v4l2_ctrl *ctrl)
dev->colorspace_out = V4L2_COLORSPACE_SMPTE170M;
else
dev->colorspace_out = V4L2_COLORSPACE_REC709;
+ dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
} else {
dev->colorspace_out = V4L2_COLORSPACE_SRGB;
+ dev->quantization_out = dev->dvi_d_out ?
+ V4L2_QUANTIZATION_LIM_RANGE :
+ V4L2_QUANTIZATION_DEFAULT;
}
if (dev->loop_video)
vivid_send_source_change(dev, HDMI);
@@ -792,15 +896,15 @@ static int vivid_streaming_s_ctrl(struct v4l2_ctrl *ctrl)
dev->start_streaming_error = true;
break;
case VIVID_CID_QUEUE_ERROR:
- if (dev->vb_vid_cap_q.start_streaming_called)
+ if (vb2_start_streaming_called(&dev->vb_vid_cap_q))
vb2_queue_error(&dev->vb_vid_cap_q);
- if (dev->vb_vbi_cap_q.start_streaming_called)
+ if (vb2_start_streaming_called(&dev->vb_vbi_cap_q))
vb2_queue_error(&dev->vb_vbi_cap_q);
- if (dev->vb_vid_out_q.start_streaming_called)
+ if (vb2_start_streaming_called(&dev->vb_vid_out_q))
vb2_queue_error(&dev->vb_vid_out_q);
- if (dev->vb_vbi_out_q.start_streaming_called)
+ if (vb2_start_streaming_called(&dev->vb_vbi_out_q))
vb2_queue_error(&dev->vb_vbi_out_q);
- if (dev->vb_sdr_cap_q.start_streaming_called)
+ if (vb2_start_streaming_called(&dev->vb_sdr_cap_q))
vb2_queue_error(&dev->vb_sdr_cap_q);
break;
case VIVID_CID_SEQ_WRAP:
@@ -1222,6 +1326,9 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
dev->string = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_string, NULL);
dev->bitmask = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_bitmask, NULL);
dev->int_menu = v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_int_menu, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u32_array, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u16_matrix, NULL);
+ v4l2_ctrl_new_custom(hdl_user_gen, &vivid_ctrl_u8_4d_array, NULL);
if (dev->has_vid_cap) {
/* Image Processing Controls */
@@ -1258,6 +1365,8 @@ int vivid_create_controls(struct vivid_dev *dev, bool show_ccs_cap,
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_tstamp_src, NULL);
dev->colorspace = v4l2_ctrl_new_custom(hdl_vid_cap,
&vivid_ctrl_colorspace, NULL);
+ v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_ycbcr_enc, NULL);
+ v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_quantization, NULL);
v4l2_ctrl_new_custom(hdl_vid_cap, &vivid_ctrl_alpha_mode, NULL);
}
diff --git a/drivers/media/platform/vivid/vivid-sdr-cap.c b/drivers/media/platform/vivid/vivid-sdr-cap.c
index 8c5d661..4af55f1 100644
--- a/drivers/media/platform/vivid/vivid-sdr-cap.c
+++ b/drivers/media/platform/vivid/vivid-sdr-cap.c
@@ -297,8 +297,8 @@ const struct vb2_ops vivid_sdr_cap_qops = {
.buf_queue = sdr_cap_buf_queue,
.start_streaming = sdr_cap_start_streaming,
.stop_streaming = sdr_cap_stop_streaming,
- .wait_prepare = vivid_unlock,
- .wait_finish = vivid_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
int vivid_sdr_enum_freq_bands(struct file *file, void *fh, struct v4l2_frequency_band *band)
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.c b/drivers/media/platform/vivid/vivid-tpg-colors.c
index 2adddc0..424aa7a 100644
--- a/drivers/media/platform/vivid/vivid-tpg-colors.c
+++ b/drivers/media/platform/vivid/vivid-tpg-colors.c
@@ -12,7 +12,7 @@
* This source also contains the code used to generate the tpg_csc_colors
* table. Run the following command to compile it:
*
- * gcc vivid-colors.c -DCOMPILE_APP -o gen-colors -lm
+ * gcc vivid-tpg-colors.c -DCOMPILE_APP -o gen-colors -lm
*
* and run the utility.
*
@@ -78,22 +78,542 @@ const struct color tpg_colors[TPG_COLOR_MAX] = {
#ifndef COMPILE_APP
/* Generated table */
-const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {
- [V4L2_COLORSPACE_SMPTE170M][0] = { 2953, 2939, 2939 },
- [V4L2_COLORSPACE_SMPTE170M][1] = { 2954, 2963, 585 },
- [V4L2_COLORSPACE_SMPTE170M][2] = { 84, 2967, 2937 },
- [V4L2_COLORSPACE_SMPTE170M][3] = { 93, 2990, 575 },
- [V4L2_COLORSPACE_SMPTE170M][4] = { 3030, 259, 2933 },
- [V4L2_COLORSPACE_SMPTE170M][5] = { 3031, 406, 557 },
- [V4L2_COLORSPACE_SMPTE170M][6] = { 544, 428, 2931 },
- [V4L2_COLORSPACE_SMPTE170M][7] = { 551, 547, 547 },
+const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {
+ 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 6, 7, 7,
+ 7, 7, 8, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 12, 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14,
+ 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 17, 17, 17, 17, 18,
+ 18, 18, 18, 18, 19, 19, 19, 19, 20, 20, 20, 20, 20, 21, 21, 21,
+ 21, 22, 22, 22, 22, 22, 23, 23, 23, 23, 24, 24, 24, 24, 24, 25,
+ 25, 25, 25, 26, 26, 26, 26, 26, 27, 27, 27, 27, 28, 28, 28, 28,
+ 28, 29, 29, 29, 29, 30, 30, 30, 30, 30, 31, 31, 31, 31, 32, 32,
+ 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 38, 39, 39,
+ 39, 39, 40, 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 42,
+ 43, 43, 43, 43, 44, 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46,
+ 46, 46, 47, 47, 47, 47, 48, 48, 48, 48, 48, 49, 49, 49, 49, 50,
+ 50, 50, 50, 50, 51, 51, 51, 51, 52, 52, 52, 52, 52, 53, 53, 53,
+ 53, 54, 54, 54, 54, 54, 55, 55, 55, 55, 56, 56, 56, 56, 56, 57,
+ 57, 57, 57, 58, 58, 58, 58, 58, 59, 59, 59, 59, 60, 60, 60, 60,
+ 60, 61, 61, 61, 61, 62, 62, 62, 62, 62, 63, 63, 63, 63, 64, 64,
+ 64, 64, 64, 65, 65, 65, 65, 66, 66, 66, 66, 66, 67, 67, 67, 67,
+ 68, 68, 68, 68, 68, 69, 69, 69, 69, 70, 70, 70, 70, 70, 71, 71,
+ 71, 71, 72, 72, 72, 72, 72, 73, 73, 73, 73, 73, 74, 74, 74, 74,
+ 74, 75, 75, 75, 75, 76, 76, 76, 76, 76, 77, 77, 77, 77, 78, 78,
+ 78, 78, 79, 79, 79, 79, 79, 80, 80, 80, 80, 81, 81, 81, 81, 82,
+ 82, 82, 82, 82, 83, 83, 83, 83, 84, 84, 84, 84, 85, 85, 85, 85,
+ 86, 86, 86, 86, 87, 87, 87, 87, 88, 88, 88, 88, 89, 89, 89, 89,
+ 90, 90, 90, 90, 91, 91, 91, 91, 92, 92, 92, 92, 93, 93, 93, 93,
+ 94, 94, 94, 94, 95, 95, 95, 95, 96, 96, 96, 96, 97, 97, 97, 97,
+ 98, 98, 98, 98, 99, 99, 99, 99, 100, 100, 100, 101, 101, 101, 101, 102,
+ 102, 102, 102, 103, 103, 103, 103, 104, 104, 104, 105, 105, 105, 105, 106, 106,
+ 106, 106, 107, 107, 107, 107, 108, 108, 108, 109, 109, 109, 109, 110, 110, 110,
+ 111, 111, 111, 111, 112, 112, 112, 112, 113, 113, 113, 114, 114, 114, 114, 115,
+ 115, 115, 116, 116, 116, 116, 117, 117, 117, 118, 118, 118, 118, 119, 119, 119,
+ 120, 120, 120, 120, 121, 121, 121, 122, 122, 122, 123, 123, 123, 123, 124, 124,
+ 124, 125, 125, 125, 125, 126, 126, 126, 127, 127, 127, 128, 128, 128, 128, 129,
+ 129, 129, 130, 130, 130, 131, 131, 131, 132, 132, 132, 132, 133, 133, 133, 134,
+ 134, 134, 135, 135, 135, 136, 136, 136, 136, 137, 137, 137, 138, 138, 138, 139,
+ 139, 139, 140, 140, 140, 141, 141, 141, 142, 142, 142, 142, 143, 143, 143, 144,
+ 144, 144, 145, 145, 145, 146, 146, 146, 147, 147, 147, 148, 148, 148, 149, 149,
+ 149, 150, 150, 150, 151, 151, 151, 152, 152, 152, 153, 153, 153, 154, 154, 154,
+ 155, 155, 155, 156, 156, 156, 157, 157, 157, 158, 158, 158, 159, 159, 159, 160,
+ 160, 160, 161, 161, 161, 162, 162, 162, 163, 163, 163, 164, 164, 164, 165, 165,
+ 165, 166, 166, 167, 167, 167, 168, 168, 168, 169, 169, 169, 170, 170, 170, 171,
+ 171, 171, 172, 172, 172, 173, 173, 174, 174, 174, 175, 175, 175, 176, 176, 176,
+ 177, 177, 177, 178, 178, 179, 179, 179, 180, 180, 180, 181, 181, 181, 182, 182,
+ 183, 183, 183, 184, 184, 184, 185, 185, 186, 186, 186, 187, 187, 187, 188, 188,
+ 188, 189, 189, 190, 190, 190, 191, 191, 191, 192, 192, 193, 193, 193, 194, 194,
+ 194, 195, 195, 196, 196, 196, 197, 197, 198, 198, 198, 199, 199, 199, 200, 200,
+ 201, 201, 201, 202, 202, 203, 203, 203, 204, 204, 204, 205, 205, 206, 206, 206,
+ 207, 207, 208, 208, 208, 209, 209, 210, 210, 210, 211, 211, 212, 212, 212, 213,
+ 213, 214, 214, 214, 215, 215, 216, 216, 216, 217, 217, 218, 218, 218, 219, 219,
+ 220, 220, 220, 221, 221, 222, 222, 222, 223, 223, 224, 224, 224, 225, 225, 226,
+ 226, 227, 227, 227, 228, 228, 229, 229, 229, 230, 230, 231, 231, 232, 232, 232,
+ 233, 233, 234, 234, 234, 235, 235, 236, 236, 237, 237, 237, 238, 238, 239, 239,
+ 240, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244, 245, 245, 246, 246,
+ 246, 247, 247, 248, 248, 249, 249, 249, 250, 250, 251, 251, 252, 252, 252, 253,
+ 253, 254, 254, 255, 255, 256, 256, 256, 257, 257, 258, 258, 259, 259, 260, 260,
+ 260, 261, 261, 262, 262, 263, 263, 264, 264, 264, 265, 265, 266, 266, 267, 267,
+ 268, 268, 269, 269, 269, 270, 270, 271, 271, 272, 272, 273, 273, 274, 274, 274,
+ 275, 275, 276, 276, 277, 277, 278, 278, 279, 279, 279, 280, 280, 281, 281, 282,
+ 282, 283, 283, 284, 284, 285, 285, 286, 286, 286, 287, 287, 288, 288, 289, 289,
+ 290, 290, 291, 291, 292, 292, 293, 293, 294, 294, 295, 295, 295, 296, 296, 297,
+ 297, 298, 298, 299, 299, 300, 300, 301, 301, 302, 302, 303, 303, 304, 304, 305,
+ 305, 306, 306, 307, 307, 308, 308, 309, 309, 309, 310, 310, 311, 311, 312, 312,
+ 313, 313, 314, 314, 315, 315, 316, 316, 317, 317, 318, 318, 319, 319, 320, 320,
+ 321, 321, 322, 322, 323, 323, 324, 324, 325, 325, 326, 326, 327, 327, 328, 328,
+ 329, 329, 330, 330, 331, 331, 332, 332, 333, 333, 334, 335, 335, 336, 336, 337,
+ 337, 338, 338, 339, 339, 340, 340, 341, 341, 342, 342, 343, 343, 344, 344, 345,
+ 345, 346, 346, 347, 347, 348, 348, 349, 349, 350, 351, 351, 352, 352, 353, 353,
+ 354, 354, 355, 355, 356, 356, 357, 357, 358, 358, 359, 360, 360, 361, 361, 362,
+ 362, 363, 363, 364, 364, 365, 365, 366, 366, 367, 368, 368, 369, 369, 370, 370,
+ 371, 371, 372, 372, 373, 373, 374, 375, 375, 376, 376, 377, 377, 378, 378, 379,
+ 379, 380, 381, 381, 382, 382, 383, 383, 384, 384, 385, 386, 386, 387, 387, 388,
+ 388, 389, 389, 390, 391, 391, 392, 392, 393, 393, 394, 394, 395, 396, 396, 397,
+ 397, 398, 398, 399, 399, 400, 401, 401, 402, 402, 403, 403, 404, 405, 405, 406,
+ 406, 407, 407, 408, 409, 409, 410, 410, 411, 411, 412, 413, 413, 414, 414, 415,
+ 415, 416, 417, 417, 418, 418, 419, 419, 420, 421, 421, 422, 422, 423, 424, 424,
+ 425, 425, 426, 426, 427, 428, 428, 429, 429, 430, 431, 431, 432, 432, 433, 433,
+ 434, 435, 435, 436, 436, 437, 438, 438, 439, 439, 440, 441, 441, 442, 442, 443,
+ 444, 444, 445, 445, 446, 447, 447, 448, 448, 449, 450, 450, 451, 451, 452, 453,
+ 453, 454, 454, 455, 456, 456, 457, 457, 458, 459, 459, 460, 460, 461, 462, 462,
+ 463, 463, 464, 465, 465, 466, 467, 467, 468, 468, 469, 470, 470, 471, 471, 472,
+ 473, 473, 474, 475, 475, 476, 476, 477, 478, 478, 479, 480, 480, 481, 481, 482,
+ 483, 483, 484, 485, 485, 486, 486, 487, 488, 488, 489, 490, 490, 491, 491, 492,
+ 493, 493, 494, 495, 495, 496, 497, 497, 498, 498, 499, 500, 500, 501, 502, 502,
+ 503, 504, 504, 505, 505, 506, 507, 507, 508, 509, 509, 510, 511, 511, 512, 513,
+ 513, 514, 514, 515, 516, 516, 517, 518, 518, 519, 520, 520, 521, 522, 522, 523,
+ 524, 524, 525, 526, 526, 527, 528, 528, 529, 529, 530, 531, 531, 532, 533, 533,
+ 534, 535, 535, 536, 537, 537, 538, 539, 539, 540, 541, 541, 542, 543, 543, 544,
+ 545, 545, 546, 547, 547, 548, 549, 549, 550, 551, 551, 552, 553, 553, 554, 555,
+ 555, 556, 557, 557, 558, 559, 560, 560, 561, 562, 562, 563, 564, 564, 565, 566,
+ 566, 567, 568, 568, 569, 570, 570, 571, 572, 572, 573, 574, 575, 575, 576, 577,
+ 577, 578, 579, 579, 580, 581, 581, 582, 583, 584, 584, 585, 586, 586, 587, 588,
+ 588, 589, 590, 590, 591, 592, 593, 593, 594, 595, 595, 596, 597, 598, 598, 599,
+ 600, 600, 601, 602, 602, 603, 604, 605, 605, 606, 607, 607, 608, 609, 610, 610,
+ 611, 612, 612, 613, 614, 615, 615, 616, 617, 617, 618, 619, 620, 620, 621, 622,
+ 622, 623, 624, 625, 625, 626, 627, 627, 628, 629, 630, 630, 631, 632, 632, 633,
+ 634, 635, 635, 636, 637, 638, 638, 639, 640, 640, 641, 642, 643, 643, 644, 645,
+ 646, 646, 647, 648, 649, 649, 650, 651, 652, 652, 653, 654, 654, 655, 656, 657,
+ 657, 658, 659, 660, 660, 661, 662, 663, 663, 664, 665, 666, 666, 667, 668, 669,
+ 669, 670, 671, 672, 672, 673, 674, 675, 675, 676, 677, 678, 678, 679, 680, 681,
+ 681, 682, 683, 684, 684, 685, 686, 687, 687, 688, 689, 690, 690, 691, 692, 693,
+ 694, 694, 695, 696, 697, 697, 698, 699, 700, 700, 701, 702, 703, 703, 704, 705,
+ 706, 707, 707, 708, 709, 710, 710, 711, 712, 713, 714, 714, 715, 716, 717, 717,
+ 718, 719, 720, 720, 721, 722, 723, 724, 724, 725, 726, 727, 728, 728, 729, 730,
+ 731, 731, 732, 733, 734, 735, 735, 736, 737, 738, 739, 739, 740, 741, 742, 742,
+ 743, 744, 745, 746, 746, 747, 748, 749, 750, 750, 751, 752, 753, 754, 754, 755,
+ 756, 757, 758, 758, 759, 760, 761, 762, 762, 763, 764, 765, 766, 766, 767, 768,
+ 769, 770, 771, 771, 772, 773, 774, 775, 775, 776, 777, 778, 779, 779, 780, 781,
+ 782, 783, 783, 784, 785, 786, 787, 788, 788, 789, 790, 791, 792, 793, 793, 794,
+ 795, 796, 797, 797, 798, 799, 800, 801, 802, 802, 803, 804, 805, 806, 807, 807,
+ 808, 809, 810, 811, 812, 812, 813, 814, 815, 816, 817, 817, 818, 819, 820, 821,
+ 822, 822, 823, 824, 825, 826, 827, 827, 828, 829, 830, 831, 832, 832, 833, 834,
+ 835, 836, 837, 838, 838, 839, 840, 841, 842, 843, 843, 844, 845, 846, 847, 848,
+ 849, 849, 850, 851, 852, 853, 854, 855, 855, 856, 857, 858, 859, 860, 861, 861,
+ 862, 863, 864, 865, 866, 867, 867, 868, 869, 870, 871, 872, 873, 873, 874, 875,
+ 876, 877, 878, 879, 880, 880, 881, 882, 883, 884, 885, 886, 887, 887, 888, 889,
+ 890, 891, 892, 893, 894, 894, 895, 896, 897, 898, 899, 900, 901, 901, 902, 903,
+ 904, 905, 906, 907, 908, 909, 909, 910, 911, 912, 913, 914, 915, 916, 916, 917,
+ 918, 919, 920, 921, 922, 923, 924, 925, 925, 926, 927, 928, 929, 930, 931, 932,
+ 933, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 942, 943, 944, 945, 946,
+ 947, 948, 949, 950, 951, 952, 952, 953, 954, 955, 956, 957, 958, 959, 960, 961,
+ 962, 962, 963, 964, 965, 966, 967, 968, 969, 970, 971, 972, 973, 973, 974, 975,
+ 976, 977, 978, 979, 980, 981, 982, 983, 984, 985, 985, 986, 987, 988, 989, 990,
+ 991, 992, 993, 994, 995, 996, 997, 998, 998, 999, 1000, 1001, 1002, 1003, 1004, 1005,
+ 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1013, 1014, 1015, 1016, 1017, 1018, 1019, 1020,
+ 1021, 1022, 1023, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1030, 1031, 1032, 1033, 1034, 1035,
+ 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1050,
+ 1051, 1052, 1053, 1054, 1055, 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1064, 1065, 1066,
+ 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 1076, 1077, 1078, 1078, 1079, 1080, 1081,
+ 1082, 1083, 1084, 1085, 1086, 1087, 1088, 1089, 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097,
+ 1098, 1099, 1100, 1101, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113,
+ 1114, 1115, 1116, 1117, 1118, 1119, 1120, 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129,
+ 1130, 1131, 1132, 1133, 1134, 1135, 1136, 1137, 1138, 1139, 1140, 1141, 1142, 1143, 1144, 1145,
+ 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161,
+ 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, 1175, 1176, 1177,
+ 1178, 1179, 1180, 1181, 1182, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1193, 1194,
+ 1195, 1196, 1197, 1198, 1199, 1200, 1201, 1202, 1203, 1204, 1205, 1206, 1207, 1208, 1209, 1210,
+ 1211, 1212, 1213, 1214, 1215, 1216, 1217, 1218, 1219, 1220, 1221, 1223, 1224, 1225, 1226, 1227,
+ 1228, 1229, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 1240, 1241, 1242, 1243,
+ 1245, 1246, 1247, 1248, 1249, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 1259, 1260,
+ 1261, 1262, 1264, 1265, 1266, 1267, 1268, 1269, 1270, 1271, 1272, 1273, 1274, 1275, 1276, 1277,
+ 1278, 1280, 1281, 1282, 1283, 1284, 1285, 1286, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1295,
+ 1296, 1297, 1298, 1299, 1300, 1301, 1302, 1303, 1304, 1305, 1306, 1307, 1309, 1310, 1311, 1312,
+ 1313, 1314, 1315, 1316, 1317, 1318, 1319, 1320, 1322, 1323, 1324, 1325, 1326, 1327, 1328, 1329,
+ 1330, 1331, 1332, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 1345, 1346, 1347,
+ 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1356, 1357, 1358, 1359, 1360, 1361, 1362, 1363, 1364,
+ 1365, 1367, 1368, 1369, 1370, 1371, 1372, 1373, 1374, 1375, 1377, 1378, 1379, 1380, 1381, 1382,
+ 1383, 1384, 1385, 1387, 1388, 1389, 1390, 1391, 1392, 1393, 1394, 1396, 1397, 1398, 1399, 1400,
+ 1401, 1402, 1403, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1414, 1415, 1416, 1417, 1418,
+ 1419, 1420, 1421, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 1431, 1432, 1433, 1434, 1435, 1436,
+ 1437, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1448, 1449, 1450, 1451, 1452, 1453, 1455,
+ 1456, 1457, 1458, 1459, 1460, 1461, 1463, 1464, 1465, 1466, 1467, 1468, 1469, 1471, 1472, 1473,
+ 1474, 1475, 1476, 1478, 1479, 1480, 1481, 1482, 1483, 1484, 1486, 1487, 1488, 1489, 1490, 1491,
+ 1493, 1494, 1495, 1496, 1497, 1498, 1500, 1501, 1502, 1503, 1504, 1505, 1507, 1508, 1509, 1510,
+ 1511, 1512, 1514, 1515, 1516, 1517, 1518, 1519, 1521, 1522, 1523, 1524, 1525, 1527, 1528, 1529,
+ 1530, 1531, 1532, 1534, 1535, 1536, 1537, 1538, 1540, 1541, 1542, 1543, 1544, 1545, 1547, 1548,
+ 1549, 1550, 1551, 1553, 1554, 1555, 1556, 1557, 1559, 1560, 1561, 1562, 1563, 1564, 1566, 1567,
+ 1568, 1569, 1570, 1572, 1573, 1574, 1575, 1576, 1578, 1579, 1580, 1581, 1582, 1584, 1585, 1586,
+ 1587, 1588, 1590, 1591, 1592, 1593, 1594, 1596, 1597, 1598, 1599, 1601, 1602, 1603, 1604, 1605,
+ 1607, 1608, 1609, 1610, 1611, 1613, 1614, 1615, 1616, 1617, 1619, 1620, 1621, 1622, 1624, 1625,
+ 1626, 1627, 1628, 1630, 1631, 1632, 1633, 1635, 1636, 1637, 1638, 1639, 1641, 1642, 1643, 1644,
+ 1646, 1647, 1648, 1649, 1650, 1652, 1653, 1654, 1655, 1657, 1658, 1659, 1660, 1662, 1663, 1664,
+ 1665, 1667, 1668, 1669, 1670, 1671, 1673, 1674, 1675, 1676, 1678, 1679, 1680, 1681, 1683, 1684,
+ 1685, 1686, 1688, 1689, 1690, 1691, 1693, 1694, 1695, 1696, 1698, 1699, 1700, 1701, 1703, 1704,
+ 1705, 1706, 1708, 1709, 1710, 1711, 1713, 1714, 1715, 1716, 1718, 1719, 1720, 1721, 1723, 1724,
+ 1725, 1726, 1728, 1729, 1730, 1731, 1733, 1734, 1735, 1737, 1738, 1739, 1740, 1742, 1743, 1744,
+ 1745, 1747, 1748, 1749, 1750, 1752, 1753, 1754, 1756, 1757, 1758, 1759, 1761, 1762, 1763, 1764,
+ 1766, 1767, 1768, 1770, 1771, 1772, 1773, 1775, 1776, 1777, 1778, 1780, 1781, 1782, 1784, 1785,
+ 1786, 1787, 1789, 1790, 1791, 1793, 1794, 1795, 1796, 1798, 1799, 1800, 1802, 1803, 1804, 1806,
+ 1807, 1808, 1809, 1811, 1812, 1813, 1815, 1816, 1817, 1818, 1820, 1821, 1822, 1824, 1825, 1826,
+ 1828, 1829, 1830, 1831, 1833, 1834, 1835, 1837, 1838, 1839, 1841, 1842, 1843, 1844, 1846, 1847,
+ 1848, 1850, 1851, 1852, 1854, 1855, 1856, 1858, 1859, 1860, 1862, 1863, 1864, 1865, 1867, 1868,
+ 1869, 1871, 1872, 1873, 1875, 1876, 1877, 1879, 1880, 1881, 1883, 1884, 1885, 1887, 1888, 1889,
+ 1891, 1892, 1893, 1894, 1896, 1897, 1898, 1900, 1901, 1902, 1904, 1905, 1906, 1908, 1909, 1910,
+ 1912, 1913, 1914, 1916, 1917, 1918, 1920, 1921, 1922, 1924, 1925, 1926, 1928, 1929, 1930, 1932,
+ 1933, 1935, 1936, 1937, 1939, 1940, 1941, 1943, 1944, 1945, 1947, 1948, 1949, 1951, 1952, 1953,
+ 1955, 1956, 1957, 1959, 1960, 1961, 1963, 1964, 1965, 1967, 1968, 1970, 1971, 1972, 1974, 1975,
+ 1976, 1978, 1979, 1980, 1982, 1983, 1984, 1986, 1987, 1989, 1990, 1991, 1993, 1994, 1995, 1997,
+ 1998, 1999, 2001, 2002, 2004, 2005, 2006, 2008, 2009, 2010, 2012, 2013, 2015, 2016, 2017, 2019,
+ 2020, 2021, 2023, 2024, 2026, 2027, 2028, 2030, 2031, 2032, 2034, 2035, 2037, 2038, 2039, 2041,
+ 2042, 2043, 2045, 2046, 2048, 2049, 2050, 2052, 2053, 2055, 2056, 2057, 2059, 2060, 2061, 2063,
+ 2064, 2066, 2067, 2068, 2070, 2071, 2073, 2074, 2075, 2077, 2078, 2080, 2081, 2082, 2084, 2085,
+ 2087, 2088, 2089, 2091, 2092, 2094, 2095, 2096, 2098, 2099, 2101, 2102, 2103, 2105, 2106, 2108,
+ 2109, 2110, 2112, 2113, 2115, 2116, 2117, 2119, 2120, 2122, 2123, 2124, 2126, 2127, 2129, 2130,
+ 2132, 2133, 2134, 2136, 2137, 2139, 2140, 2141, 2143, 2144, 2146, 2147, 2149, 2150, 2151, 2153,
+ 2154, 2156, 2157, 2159, 2160, 2161, 2163, 2164, 2166, 2167, 2169, 2170, 2171, 2173, 2174, 2176,
+ 2177, 2179, 2180, 2181, 2183, 2184, 2186, 2187, 2189, 2190, 2191, 2193, 2194, 2196, 2197, 2199,
+ 2200, 2202, 2203, 2204, 2206, 2207, 2209, 2210, 2212, 2213, 2214, 2216, 2217, 2219, 2220, 2222,
+ 2223, 2225, 2226, 2228, 2229, 2230, 2232, 2233, 2235, 2236, 2238, 2239, 2241, 2242, 2243, 2245,
+ 2246, 2248, 2249, 2251, 2252, 2254, 2255, 2257, 2258, 2260, 2261, 2262, 2264, 2265, 2267, 2268,
+ 2270, 2271, 2273, 2274, 2276, 2277, 2279, 2280, 2282, 2283, 2284, 2286, 2287, 2289, 2290, 2292,
+ 2293, 2295, 2296, 2298, 2299, 2301, 2302, 2304, 2305, 2307, 2308, 2310, 2311, 2312, 2314, 2315,
+ 2317, 2318, 2320, 2321, 2323, 2324, 2326, 2327, 2329, 2330, 2332, 2333, 2335, 2336, 2338, 2339,
+ 2341, 2342, 2344, 2345, 2347, 2348, 2350, 2351, 2353, 2354, 2356, 2357, 2359, 2360, 2362, 2363,
+ 2365, 2366, 2368, 2369, 2371, 2372, 2374, 2375, 2377, 2378, 2380, 2381, 2383, 2384, 2386, 2387,
+ 2389, 2390, 2392, 2393, 2395, 2396, 2398, 2399, 2401, 2402, 2404, 2405, 2407, 2408, 2410, 2411,
+ 2413, 2414, 2416, 2417, 2419, 2420, 2422, 2423, 2425, 2426, 2428, 2429, 2431, 2433, 2434, 2436,
+ 2437, 2439, 2440, 2442, 2443, 2445, 2446, 2448, 2449, 2451, 2452, 2454, 2455, 2457, 2458, 2460,
+ 2462, 2463, 2465, 2466, 2468, 2469, 2471, 2472, 2474, 2475, 2477, 2478, 2480, 2481, 2483, 2485,
+ 2486, 2488, 2489, 2491, 2492, 2494, 2495, 2497, 2498, 2500, 2502, 2503, 2505, 2506, 2508, 2509,
+ 2511, 2512, 2514, 2515, 2517, 2519, 2520, 2522, 2523, 2525, 2526, 2528, 2529, 2531, 2533, 2534,
+ 2536, 2537, 2539, 2540, 2542, 2543, 2545, 2547, 2548, 2550, 2551, 2553, 2554, 2556, 2557, 2559,
+ 2561, 2562, 2564, 2565, 2567, 2568, 2570, 2572, 2573, 2575, 2576, 2578, 2579, 2581, 2583, 2584,
+ 2586, 2587, 2589, 2590, 2592, 2594, 2595, 2597, 2598, 2600, 2601, 2603, 2605, 2606, 2608, 2609,
+ 2611, 2613, 2614, 2616, 2617, 2619, 2620, 2622, 2624, 2625, 2627, 2628, 2630, 2632, 2633, 2635,
+ 2636, 2638, 2640, 2641, 2643, 2644, 2646, 2647, 2649, 2651, 2652, 2654, 2655, 2657, 2659, 2660,
+ 2662, 2663, 2665, 2667, 2668, 2670, 2671, 2673, 2675, 2676, 2678, 2679, 2681, 2683, 2684, 2686,
+ 2687, 2689, 2691, 2692, 2694, 2696, 2697, 2699, 2700, 2702, 2704, 2705, 2707, 2708, 2710, 2712,
+ 2713, 2715, 2716, 2718, 2720, 2721, 2723, 2725, 2726, 2728, 2729, 2731, 2733, 2734, 2736, 2738,
+ 2739, 2741, 2742, 2744, 2746, 2747, 2749, 2751, 2752, 2754, 2755, 2757, 2759, 2760, 2762, 2764,
+ 2765, 2767, 2769, 2770, 2772, 2773, 2775, 2777, 2778, 2780, 2782, 2783, 2785, 2787, 2788, 2790,
+ 2791, 2793, 2795, 2796, 2798, 2800, 2801, 2803, 2805, 2806, 2808, 2810, 2811, 2813, 2814, 2816,
+ 2818, 2819, 2821, 2823, 2824, 2826, 2828, 2829, 2831, 2833, 2834, 2836, 2838, 2839, 2841, 2843,
+ 2844, 2846, 2848, 2849, 2851, 2853, 2854, 2856, 2857, 2859, 2861, 2862, 2864, 2866, 2867, 2869,
+ 2871, 2872, 2874, 2876, 2877, 2879, 2881, 2882, 2884, 2886, 2888, 2889, 2891, 2893, 2894, 2896,
+ 2898, 2899, 2901, 2903, 2904, 2906, 2908, 2909, 2911, 2913, 2914, 2916, 2918, 2919, 2921, 2923,
+ 2924, 2926, 2928, 2929, 2931, 2933, 2935, 2936, 2938, 2940, 2941, 2943, 2945, 2946, 2948, 2950,
+ 2951, 2953, 2955, 2956, 2958, 2960, 2962, 2963, 2965, 2967, 2968, 2970, 2972, 2973, 2975, 2977,
+ 2979, 2980, 2982, 2984, 2985, 2987, 2989, 2990, 2992, 2994, 2996, 2997, 2999, 3001, 3002, 3004,
+ 3006, 3008, 3009, 3011, 3013, 3014, 3016, 3018, 3020, 3021, 3023, 3025, 3026, 3028, 3030, 3032,
+ 3033, 3035, 3037, 3038, 3040, 3042, 3044, 3045, 3047, 3049, 3050, 3052, 3054, 3056, 3057, 3059,
+ 3061, 3063, 3064, 3066, 3068, 3069, 3071, 3073, 3075, 3076, 3078, 3080, 3082, 3083, 3085, 3087,
+ 3089, 3090, 3092, 3094, 3095, 3097, 3099, 3101, 3102, 3104, 3106, 3108, 3109, 3111, 3113, 3115,
+ 3116, 3118, 3120, 3122, 3123, 3125, 3127, 3129, 3130, 3132, 3134, 3136, 3137, 3139, 3141, 3143,
+ 3144, 3146, 3148, 3150, 3151, 3153, 3155, 3157, 3158, 3160, 3162, 3164, 3165, 3167, 3169, 3171,
+ 3172, 3174, 3176, 3178, 3179, 3181, 3183, 3185, 3187, 3188, 3190, 3192, 3194, 3195, 3197, 3199,
+ 3201, 3202, 3204, 3206, 3208, 3209, 3211, 3213, 3215, 3217, 3218, 3220, 3222, 3224, 3225, 3227,
+ 3229, 3231, 3233, 3234, 3236, 3238, 3240, 3241, 3243, 3245, 3247, 3249, 3250, 3252, 3254, 3256,
+ 3258, 3259, 3261, 3263, 3265, 3266, 3268, 3270, 3272, 3274, 3275, 3277, 3279, 3281, 3283, 3284,
+ 3286, 3288, 3290, 3292, 3293, 3295, 3297, 3299, 3301, 3302, 3304, 3306, 3308, 3310, 3311, 3313,
+ 3315, 3317, 3319, 3320, 3322, 3324, 3326, 3328, 3329, 3331, 3333, 3335, 3337, 3338, 3340, 3342,
+ 3344, 3346, 3348, 3349, 3351, 3353, 3355, 3357, 3358, 3360, 3362, 3364, 3366, 3368, 3369, 3371,
+ 3373, 3375, 3377, 3378, 3380, 3382, 3384, 3386, 3388, 3389, 3391, 3393, 3395, 3397, 3399, 3400,
+ 3402, 3404, 3406, 3408, 3410, 3411, 3413, 3415, 3417, 3419, 3421, 3422, 3424, 3426, 3428, 3430,
+ 3432, 3433, 3435, 3437, 3439, 3441, 3443, 3444, 3446, 3448, 3450, 3452, 3454, 3455, 3457, 3459,
+ 3461, 3463, 3465, 3467, 3468, 3470, 3472, 3474, 3476, 3478, 3480, 3481, 3483, 3485, 3487, 3489,
+ 3491, 3492, 3494, 3496, 3498, 3500, 3502, 3504, 3506, 3507, 3509, 3511, 3513, 3515, 3517, 3519,
+ 3520, 3522, 3524, 3526, 3528, 3530, 3532, 3533, 3535, 3537, 3539, 3541, 3543, 3545, 3547, 3548,
+ 3550, 3552, 3554, 3556, 3558, 3560, 3562, 3563, 3565, 3567, 3569, 3571, 3573, 3575, 3577, 3578,
+ 3580, 3582, 3584, 3586, 3588, 3590, 3592, 3594, 3595, 3597, 3599, 3601, 3603, 3605, 3607, 3609,
+ 3611, 3612, 3614, 3616, 3618, 3620, 3622, 3624, 3626, 3628, 3629, 3631, 3633, 3635, 3637, 3639,
+ 3641, 3643, 3645, 3647, 3648, 3650, 3652, 3654, 3656, 3658, 3660, 3662, 3664, 3666, 3667, 3669,
+ 3671, 3673, 3675, 3677, 3679, 3681, 3683, 3685, 3687, 3688, 3690, 3692, 3694, 3696, 3698, 3700,
+ 3702, 3704, 3706, 3708, 3710, 3711, 3713, 3715, 3717, 3719, 3721, 3723, 3725, 3727, 3729, 3731,
+ 3733, 3735, 3736, 3738, 3740, 3742, 3744, 3746, 3748, 3750, 3752, 3754, 3756, 3758, 3760, 3762,
+ 3764, 3765, 3767, 3769, 3771, 3773, 3775, 3777, 3779, 3781, 3783, 3785, 3787, 3789, 3791, 3793,
+ 3795, 3796, 3798, 3800, 3802, 3804, 3806, 3808, 3810, 3812, 3814, 3816, 3818, 3820, 3822, 3824,
+ 3826, 3828, 3830, 3832, 3833, 3835, 3837, 3839, 3841, 3843, 3845, 3847, 3849, 3851, 3853, 3855,
+ 3857, 3859, 3861, 3863, 3865, 3867, 3869, 3871, 3873, 3875, 3877, 3879, 3881, 3883, 3884, 3886,
+ 3888, 3890, 3892, 3894, 3896, 3898, 3900, 3902, 3904, 3906, 3908, 3910, 3912, 3914, 3916, 3918,
+ 3920, 3922, 3924, 3926, 3928, 3930, 3932, 3934, 3936, 3938, 3940, 3942, 3944, 3946, 3948, 3950,
+ 3952, 3954, 3956, 3958, 3960, 3962, 3964, 3966, 3968, 3970, 3972, 3974, 3976, 3978, 3980, 3982,
+ 3984, 3986, 3988, 3990, 3992, 3994, 3996, 3998, 4000, 4002, 4004, 4006, 4008, 4010, 4012, 4014,
+ 4016, 4018, 4020, 4022, 4024, 4026, 4028, 4030, 4032, 4034, 4036, 4038, 4040, 4042, 4044, 4046,
+ 4048, 4050, 4052, 4054, 4056, 4058, 4060, 4062, 4064, 4066, 4068, 4070, 4072, 4074, 4076, 4078,
+ 4080,
+};
+
+/* Generated table */
+const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {
+ 0, 5, 9, 14, 18, 22, 27, 32, 36, 41, 45, 50, 54, 59, 63, 68,
+ 72, 77, 81, 86, 90, 95, 99, 104, 108, 113, 117, 122, 126, 131, 135, 139,
+ 144, 149, 153, 158, 162, 167, 171, 176, 180, 185, 189, 194, 198, 203, 207, 212,
+ 216, 221, 225, 230, 234, 239, 243, 248, 252, 257, 261, 266, 270, 275, 279, 284,
+ 288, 293, 297, 302, 306, 311, 315, 320, 324, 328, 334, 338, 343, 347, 352, 356,
+ 360, 365, 369, 373, 377, 381, 386, 390, 394, 398, 402, 406, 410, 414, 418, 422,
+ 426, 430, 433, 437, 441, 445, 449, 452, 456, 460, 464, 467, 471, 475, 478, 482,
+ 485, 489, 492, 496, 499, 503, 506, 510, 513, 517, 520, 524, 527, 530, 534, 537,
+ 540, 544, 547, 550, 554, 557, 560, 563, 566, 570, 573, 576, 579, 582, 586, 589,
+ 592, 595, 598, 601, 604, 607, 610, 613, 616, 619, 622, 625, 628, 631, 634, 637,
+ 640, 643, 646, 649, 652, 655, 658, 660, 663, 666, 669, 672, 675, 677, 680, 683,
+ 686, 689, 691, 694, 697, 700, 702, 705, 708, 711, 713, 716, 719, 721, 724, 727,
+ 729, 732, 735, 737, 740, 743, 745, 748, 750, 753, 756, 758, 761, 763, 766, 768,
+ 771, 773, 776, 779, 781, 784, 786, 789, 791, 794, 796, 799, 801, 803, 806, 808,
+ 811, 813, 816, 818, 821, 823, 825, 828, 830, 833, 835, 837, 840, 842, 844, 847,
+ 849, 851, 854, 856, 858, 861, 863, 865, 868, 870, 872, 875, 877, 879, 881, 884,
+ 886, 888, 891, 893, 895, 897, 900, 902, 904, 906, 908, 911, 913, 915, 917, 919,
+ 922, 924, 926, 928, 930, 933, 935, 937, 939, 941, 943, 946, 948, 950, 952, 954,
+ 956, 958, 960, 963, 965, 967, 969, 971, 973, 975, 977, 979, 981, 984, 986, 988,
+ 990, 992, 994, 996, 998, 1000, 1002, 1004, 1006, 1008, 1010, 1012, 1014, 1016, 1018, 1020,
+ 1022, 1024, 1026, 1028, 1030, 1032, 1034, 1036, 1038, 1040, 1042, 1044, 1046, 1048, 1050, 1052,
+ 1054, 1056, 1058, 1060, 1062, 1064, 1066, 1068, 1069, 1071, 1073, 1075, 1077, 1079, 1081, 1083,
+ 1085, 1087, 1089, 1090, 1092, 1094, 1096, 1098, 1100, 1102, 1104, 1106, 1107, 1109, 1111, 1113,
+ 1115, 1117, 1119, 1120, 1122, 1124, 1126, 1128, 1130, 1131, 1133, 1135, 1137, 1139, 1141, 1142,
+ 1144, 1146, 1148, 1150, 1151, 1153, 1155, 1157, 1159, 1160, 1162, 1164, 1166, 1168, 1169, 1171,
+ 1173, 1175, 1176, 1178, 1180, 1182, 1184, 1185, 1187, 1189, 1191, 1192, 1194, 1196, 1198, 1199,
+ 1201, 1203, 1204, 1206, 1208, 1210, 1211, 1213, 1215, 1217, 1218, 1220, 1222, 1223, 1225, 1227,
+ 1228, 1230, 1232, 1234, 1235, 1237, 1239, 1240, 1242, 1244, 1245, 1247, 1249, 1250, 1252, 1254,
+ 1255, 1257, 1259, 1260, 1262, 1264, 1265, 1267, 1269, 1270, 1272, 1274, 1275, 1277, 1279, 1280,
+ 1282, 1283, 1285, 1287, 1288, 1290, 1292, 1293, 1295, 1296, 1298, 1300, 1301, 1303, 1305, 1306,
+ 1308, 1309, 1311, 1313, 1314, 1316, 1317, 1319, 1321, 1322, 1324, 1325, 1327, 1328, 1330, 1332,
+ 1333, 1335, 1336, 1338, 1339, 1341, 1343, 1344, 1346, 1347, 1349, 1350, 1352, 1354, 1355, 1357,
+ 1358, 1360, 1361, 1363, 1364, 1366, 1367, 1369, 1371, 1372, 1374, 1375, 1377, 1378, 1380, 1381,
+ 1383, 1384, 1386, 1387, 1389, 1390, 1392, 1393, 1395, 1396, 1398, 1399, 1401, 1402, 1404, 1405,
+ 1407, 1408, 1410, 1411, 1413, 1414, 1416, 1417, 1419, 1420, 1422, 1423, 1425, 1426, 1428, 1429,
+ 1431, 1432, 1434, 1435, 1437, 1438, 1440, 1441, 1442, 1444, 1445, 1447, 1448, 1450, 1451, 1453,
+ 1454, 1456, 1457, 1458, 1460, 1461, 1463, 1464, 1466, 1467, 1469, 1470, 1471, 1473, 1474, 1476,
+ 1477, 1479, 1480, 1481, 1483, 1484, 1486, 1487, 1489, 1490, 1491, 1493, 1494, 1496, 1497, 1498,
+ 1500, 1501, 1503, 1504, 1505, 1507, 1508, 1510, 1511, 1512, 1514, 1515, 1517, 1518, 1519, 1521,
+ 1522, 1524, 1525, 1526, 1528, 1529, 1531, 1532, 1533, 1535, 1536, 1537, 1539, 1540, 1542, 1543,
+ 1544, 1546, 1547, 1548, 1550, 1551, 1553, 1554, 1555, 1557, 1558, 1559, 1561, 1562, 1563, 1565,
+ 1566, 1567, 1569, 1570, 1571, 1573, 1574, 1576, 1577, 1578, 1580, 1581, 1582, 1584, 1585, 1586,
+ 1588, 1589, 1590, 1592, 1593, 1594, 1596, 1597, 1598, 1600, 1601, 1602, 1603, 1605, 1606, 1607,
+ 1609, 1610, 1611, 1613, 1614, 1615, 1617, 1618, 1619, 1621, 1622, 1623, 1624, 1626, 1627, 1628,
+ 1630, 1631, 1632, 1634, 1635, 1636, 1637, 1639, 1640, 1641, 1643, 1644, 1645, 1647, 1648, 1649,
+ 1650, 1652, 1653, 1654, 1655, 1657, 1658, 1659, 1661, 1662, 1663, 1664, 1666, 1667, 1668, 1670,
+ 1671, 1672, 1673, 1675, 1676, 1677, 1678, 1680, 1681, 1682, 1683, 1685, 1686, 1687, 1688, 1690,
+ 1691, 1692, 1693, 1695, 1696, 1697, 1698, 1700, 1701, 1702, 1703, 1705, 1706, 1707, 1708, 1710,
+ 1711, 1712, 1713, 1715, 1716, 1717, 1718, 1720, 1721, 1722, 1723, 1724, 1726, 1727, 1728, 1729,
+ 1731, 1732, 1733, 1734, 1736, 1737, 1738, 1739, 1740, 1742, 1743, 1744, 1745, 1746, 1748, 1749,
+ 1750, 1751, 1753, 1754, 1755, 1756, 1757, 1759, 1760, 1761, 1762, 1763, 1765, 1766, 1767, 1768,
+ 1769, 1771, 1772, 1773, 1774, 1775, 1777, 1778, 1779, 1780, 1781, 1783, 1784, 1785, 1786, 1787,
+ 1788, 1790, 1791, 1792, 1793, 1794, 1796, 1797, 1798, 1799, 1800, 1801, 1803, 1804, 1805, 1806,
+ 1807, 1809, 1810, 1811, 1812, 1813, 1814, 1816, 1817, 1818, 1819, 1820, 1821, 1823, 1824, 1825,
+ 1826, 1827, 1828, 1829, 1831, 1832, 1833, 1834, 1835, 1836, 1838, 1839, 1840, 1841, 1842, 1843,
+ 1845, 1846, 1847, 1848, 1849, 1850, 1851, 1853, 1854, 1855, 1856, 1857, 1858, 1859, 1861, 1862,
+ 1863, 1864, 1865, 1866, 1867, 1868, 1870, 1871, 1872, 1873, 1874, 1875, 1876, 1878, 1879, 1880,
+ 1881, 1882, 1883, 1884, 1885, 1887, 1888, 1889, 1890, 1891, 1892, 1893, 1894, 1896, 1897, 1898,
+ 1899, 1900, 1901, 1902, 1903, 1904, 1906, 1907, 1908, 1909, 1910, 1911, 1912, 1913, 1914, 1916,
+ 1917, 1918, 1919, 1920, 1921, 1922, 1923, 1924, 1925, 1927, 1928, 1929, 1930, 1931, 1932, 1933,
+ 1934, 1935, 1936, 1938, 1939, 1940, 1941, 1942, 1943, 1944, 1945, 1946, 1947, 1948, 1950, 1951,
+ 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1960, 1961, 1963, 1964, 1965, 1966, 1967, 1968,
+ 1969, 1970, 1971, 1972, 1973, 1974, 1975, 1977, 1978, 1979, 1980, 1981, 1982, 1983, 1984, 1985,
+ 1986, 1987, 1988, 1989, 1990, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+ 2003, 2004, 2005, 2006, 2007, 2008, 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019,
+ 2020, 2021, 2022, 2023, 2024, 2025, 2026, 2027, 2028, 2029, 2031, 2032, 2033, 2034, 2035, 2036,
+ 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 2049, 2050, 2051, 2052,
+ 2053, 2054, 2055, 2056, 2057, 2058, 2060, 2061, 2062, 2063, 2064, 2065, 2066, 2067, 2068, 2069,
+ 2070, 2071, 2072, 2073, 2074, 2075, 2076, 2077, 2078, 2079, 2080, 2081, 2082, 2083, 2084, 2085,
+ 2086, 2087, 2088, 2089, 2090, 2091, 2092, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101,
+ 2102, 2103, 2104, 2105, 2106, 2107, 2108, 2109, 2110, 2111, 2112, 2113, 2114, 2115, 2116, 2117,
+ 2118, 2119, 2120, 2121, 2122, 2123, 2124, 2125, 2126, 2127, 2128, 2129, 2130, 2131, 2132, 2133,
+ 2134, 2135, 2136, 2137, 2138, 2139, 2140, 2141, 2142, 2143, 2144, 2145, 2146, 2147, 2148, 2149,
+ 2150, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 2165,
+ 2166, 2167, 2168, 2169, 2170, 2171, 2172, 2173, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 2180,
+ 2181, 2182, 2183, 2184, 2185, 2186, 2187, 2188, 2189, 2190, 2191, 2192, 2193, 2194, 2195, 2196,
+ 2197, 2198, 2199, 2200, 2201, 2202, 2202, 2203, 2204, 2205, 2206, 2207, 2208, 2209, 2210, 2211,
+ 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 2223, 2224, 2224, 2225, 2226,
+ 2227, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 2238, 2239, 2240, 2241, 2241,
+ 2242, 2243, 2244, 2245, 2246, 2247, 2248, 2249, 2250, 2251, 2252, 2253, 2254, 2255, 2256, 2257,
+ 2257, 2258, 2259, 2260, 2261, 2262, 2263, 2264, 2265, 2266, 2267, 2268, 2269, 2270, 2271, 2271,
+ 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 2281, 2282, 2283, 2283, 2284, 2285, 2286,
+ 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 2295, 2296, 2297, 2298, 2299, 2300, 2301,
+ 2302, 2303, 2304, 2305, 2306, 2306, 2307, 2308, 2309, 2310, 2311, 2312, 2313, 2314, 2315, 2316,
+ 2317, 2317, 2318, 2319, 2320, 2321, 2322, 2323, 2324, 2325, 2326, 2327, 2327, 2328, 2329, 2330,
+ 2331, 2332, 2333, 2334, 2335, 2336, 2336, 2337, 2338, 2339, 2340, 2341, 2342, 2343, 2344, 2345,
+ 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 2354, 2354, 2355, 2356, 2357, 2358, 2359,
+ 2360, 2361, 2362, 2363, 2363, 2364, 2365, 2366, 2367, 2368, 2369, 2370, 2371, 2371, 2372, 2373,
+ 2374, 2375, 2376, 2377, 2378, 2379, 2379, 2380, 2381, 2382, 2383, 2384, 2385, 2386, 2386, 2387,
+ 2388, 2389, 2390, 2391, 2392, 2393, 2394, 2394, 2395, 2396, 2397, 2398, 2399, 2400, 2401, 2401,
+ 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2408, 2409, 2410, 2411, 2412, 2413, 2414, 2415, 2415,
+ 2416, 2417, 2418, 2419, 2420, 2421, 2422, 2422, 2423, 2424, 2425, 2426, 2427, 2428, 2428, 2429,
+ 2430, 2431, 2432, 2433, 2434, 2435, 2435, 2436, 2437, 2438, 2439, 2440, 2441, 2441, 2442, 2443,
+ 2444, 2445, 2446, 2447, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2453, 2454, 2455, 2456, 2457,
+ 2458, 2459, 2459, 2460, 2461, 2462, 2463, 2464, 2465, 2465, 2466, 2467, 2468, 2469, 2470, 2471,
+ 2471, 2472, 2473, 2474, 2475, 2476, 2477, 2477, 2478, 2479, 2480, 2481, 2482, 2482, 2483, 2484,
+ 2485, 2486, 2487, 2488, 2488, 2489, 2490, 2491, 2492, 2493, 2493, 2494, 2495, 2496, 2497, 2498,
+ 2499, 2499, 2500, 2501, 2502, 2503, 2504, 2504, 2505, 2506, 2507, 2508, 2509, 2509, 2510, 2511,
+ 2512, 2513, 2514, 2514, 2515, 2516, 2517, 2518, 2519, 2519, 2520, 2521, 2522, 2523, 2524, 2524,
+ 2525, 2526, 2527, 2528, 2529, 2529, 2530, 2531, 2532, 2533, 2534, 2534, 2535, 2536, 2537, 2538,
+ 2539, 2539, 2540, 2541, 2542, 2543, 2544, 2544, 2545, 2546, 2547, 2548, 2548, 2549, 2550, 2551,
+ 2552, 2553, 2553, 2554, 2555, 2556, 2557, 2558, 2558, 2559, 2560, 2561, 2562, 2562, 2563, 2564,
+ 2565, 2566, 2567, 2567, 2568, 2569, 2570, 2571, 2571, 2572, 2573, 2574, 2575, 2576, 2576, 2577,
+ 2578, 2579, 2580, 2580, 2581, 2582, 2583, 2584, 2584, 2585, 2586, 2587, 2588, 2589, 2589, 2590,
+ 2591, 2592, 2593, 2593, 2594, 2595, 2596, 2597, 2597, 2598, 2599, 2600, 2601, 2601, 2602, 2603,
+ 2604, 2605, 2605, 2606, 2607, 2608, 2609, 2610, 2610, 2611, 2612, 2613, 2614, 2614, 2615, 2616,
+ 2617, 2618, 2618, 2619, 2620, 2621, 2622, 2622, 2623, 2624, 2625, 2626, 2626, 2627, 2628, 2629,
+ 2630, 2630, 2631, 2632, 2633, 2634, 2634, 2635, 2636, 2637, 2637, 2638, 2639, 2640, 2641, 2641,
+ 2642, 2643, 2644, 2645, 2645, 2646, 2647, 2648, 2649, 2649, 2650, 2651, 2652, 2653, 2653, 2654,
+ 2655, 2656, 2656, 2657, 2658, 2659, 2660, 2660, 2661, 2662, 2663, 2664, 2664, 2665, 2666, 2667,
+ 2668, 2668, 2669, 2670, 2671, 2671, 2672, 2673, 2674, 2675, 2675, 2676, 2677, 2678, 2678, 2679,
+ 2680, 2681, 2682, 2682, 2683, 2684, 2685, 2686, 2686, 2687, 2688, 2689, 2689, 2690, 2691, 2692,
+ 2693, 2693, 2694, 2695, 2696, 2696, 2697, 2698, 2699, 2700, 2700, 2701, 2702, 2703, 2703, 2704,
+ 2705, 2706, 2706, 2707, 2708, 2709, 2710, 2710, 2711, 2712, 2713, 2713, 2714, 2715, 2716, 2717,
+ 2717, 2718, 2719, 2720, 2720, 2721, 2722, 2723, 2723, 2724, 2725, 2726, 2727, 2727, 2728, 2729,
+ 2730, 2730, 2731, 2732, 2733, 2733, 2734, 2735, 2736, 2736, 2737, 2738, 2739, 2740, 2740, 2741,
+ 2742, 2743, 2743, 2744, 2745, 2746, 2746, 2747, 2748, 2749, 2749, 2750, 2751, 2752, 2752, 2753,
+ 2754, 2755, 2755, 2756, 2757, 2758, 2759, 2759, 2760, 2761, 2762, 2762, 2763, 2764, 2765, 2765,
+ 2766, 2767, 2768, 2768, 2769, 2770, 2771, 2771, 2772, 2773, 2774, 2774, 2775, 2776, 2777, 2777,
+ 2778, 2779, 2780, 2780, 2781, 2782, 2783, 2783, 2784, 2785, 2786, 2786, 2787, 2788, 2789, 2789,
+ 2790, 2791, 2792, 2792, 2793, 2794, 2795, 2795, 2796, 2797, 2798, 2798, 2799, 2800, 2801, 2801,
+ 2802, 2803, 2804, 2804, 2805, 2806, 2807, 2807, 2808, 2809, 2810, 2810, 2811, 2812, 2813, 2813,
+ 2814, 2815, 2815, 2816, 2817, 2818, 2818, 2819, 2820, 2821, 2821, 2822, 2823, 2824, 2824, 2825,
+ 2826, 2827, 2827, 2828, 2829, 2830, 2830, 2831, 2832, 2832, 2833, 2834, 2835, 2835, 2836, 2837,
+ 2838, 2838, 2839, 2840, 2841, 2841, 2842, 2843, 2844, 2844, 2845, 2846, 2846, 2847, 2848, 2849,
+ 2849, 2850, 2851, 2852, 2852, 2853, 2854, 2855, 2855, 2856, 2857, 2857, 2858, 2859, 2860, 2860,
+ 2861, 2862, 2863, 2863, 2864, 2865, 2865, 2866, 2867, 2868, 2868, 2869, 2870, 2871, 2871, 2872,
+ 2873, 2873, 2874, 2875, 2876, 2876, 2877, 2878, 2879, 2879, 2880, 2881, 2881, 2882, 2883, 2884,
+ 2884, 2885, 2886, 2886, 2887, 2888, 2889, 2889, 2890, 2891, 2892, 2892, 2893, 2894, 2894, 2895,
+ 2896, 2897, 2897, 2898, 2899, 2899, 2900, 2901, 2902, 2902, 2903, 2904, 2904, 2905, 2906, 2907,
+ 2907, 2908, 2909, 2909, 2910, 2911, 2912, 2912, 2913, 2914, 2914, 2915, 2916, 2917, 2917, 2918,
+ 2919, 2919, 2920, 2921, 2922, 2922, 2923, 2924, 2924, 2925, 2926, 2927, 2927, 2928, 2929, 2929,
+ 2930, 2931, 2932, 2932, 2933, 2934, 2934, 2935, 2936, 2937, 2937, 2938, 2939, 2939, 2940, 2941,
+ 2941, 2942, 2943, 2944, 2944, 2945, 2946, 2946, 2947, 2948, 2949, 2949, 2950, 2951, 2951, 2952,
+ 2953, 2953, 2954, 2955, 2956, 2956, 2957, 2958, 2958, 2959, 2960, 2961, 2961, 2962, 2963, 2963,
+ 2964, 2965, 2965, 2966, 2967, 2968, 2968, 2969, 2970, 2970, 2971, 2972, 2972, 2973, 2974, 2975,
+ 2975, 2976, 2977, 2977, 2978, 2979, 2979, 2980, 2981, 2982, 2982, 2983, 2984, 2984, 2985, 2986,
+ 2986, 2987, 2988, 2988, 2989, 2990, 2991, 2991, 2992, 2993, 2993, 2994, 2995, 2995, 2996, 2997,
+ 2998, 2998, 2999, 3000, 3000, 3001, 3002, 3002, 3003, 3004, 3004, 3005, 3006, 3006, 3007, 3008,
+ 3009, 3009, 3010, 3011, 3011, 3012, 3013, 3013, 3014, 3015, 3015, 3016, 3017, 3018, 3018, 3019,
+ 3020, 3020, 3021, 3022, 3022, 3023, 3024, 3024, 3025, 3026, 3026, 3027, 3028, 3029, 3029, 3030,
+ 3031, 3031, 3032, 3033, 3033, 3034, 3035, 3035, 3036, 3037, 3037, 3038, 3039, 3039, 3040, 3041,
+ 3042, 3042, 3043, 3044, 3044, 3045, 3046, 3046, 3047, 3048, 3048, 3049, 3050, 3050, 3051, 3052,
+ 3052, 3053, 3054, 3054, 3055, 3056, 3056, 3057, 3058, 3059, 3059, 3060, 3061, 3061, 3062, 3063,
+ 3063, 3064, 3065, 3065, 3066, 3067, 3067, 3068, 3069, 3069, 3070, 3071, 3071, 3072, 3073, 3073,
+ 3074, 3075, 3075, 3076, 3077, 3077, 3078, 3079, 3079, 3080, 3081, 3081, 3082, 3083, 3084, 3084,
+ 3085, 3086, 3086, 3087, 3088, 3088, 3089, 3090, 3090, 3091, 3092, 3092, 3093, 3094, 3094, 3095,
+ 3096, 3096, 3097, 3098, 3098, 3099, 3100, 3100, 3101, 3102, 3102, 3103, 3104, 3104, 3105, 3106,
+ 3106, 3107, 3108, 3108, 3109, 3110, 3110, 3111, 3112, 3112, 3113, 3114, 3114, 3115, 3116, 3116,
+ 3117, 3118, 3118, 3119, 3120, 3120, 3121, 3122, 3122, 3123, 3124, 3124, 3125, 3126, 3126, 3127,
+ 3128, 3128, 3129, 3130, 3130, 3131, 3132, 3132, 3133, 3134, 3134, 3135, 3135, 3136, 3137, 3137,
+ 3138, 3139, 3139, 3140, 3141, 3141, 3142, 3143, 3143, 3144, 3145, 3145, 3146, 3147, 3147, 3148,
+ 3149, 3149, 3150, 3151, 3151, 3152, 3153, 3153, 3154, 3155, 3155, 3156, 3157, 3157, 3158, 3159,
+ 3159, 3160, 3160, 3161, 3162, 3162, 3163, 3164, 3164, 3165, 3166, 3166, 3167, 3168, 3168, 3169,
+ 3170, 3170, 3171, 3172, 3172, 3173, 3174, 3174, 3175, 3175, 3176, 3177, 3177, 3178, 3179, 3179,
+ 3180, 3181, 3181, 3182, 3183, 3183, 3184, 3185, 3185, 3186, 3187, 3187, 3188, 3188, 3189, 3190,
+ 3190, 3191, 3192, 3192, 3193, 3194, 3194, 3195, 3196, 3196, 3197, 3198, 3198, 3199, 3199, 3200,
+ 3201, 3201, 3202, 3203, 3203, 3204, 3205, 3205, 3206, 3207, 3207, 3208, 3209, 3209, 3210, 3210,
+ 3211, 3212, 3212, 3213, 3214, 3214, 3215, 3216, 3216, 3217, 3218, 3218, 3219, 3219, 3220, 3221,
+ 3221, 3222, 3223, 3223, 3224, 3225, 3225, 3226, 3227, 3227, 3228, 3228, 3229, 3230, 3230, 3231,
+ 3232, 3232, 3233, 3234, 3234, 3235, 3235, 3236, 3237, 3237, 3238, 3239, 3239, 3240, 3241, 3241,
+ 3242, 3242, 3243, 3244, 3244, 3245, 3246, 3246, 3247, 3248, 3248, 3249, 3249, 3250, 3251, 3251,
+ 3252, 3253, 3253, 3254, 3255, 3255, 3256, 3256, 3257, 3258, 3258, 3259, 3260, 3260, 3261, 3262,
+ 3262, 3263, 3263, 3264, 3265, 3265, 3266, 3267, 3267, 3268, 3268, 3269, 3270, 3270, 3271, 3272,
+ 3272, 3273, 3274, 3274, 3275, 3275, 3276, 3277, 3277, 3278, 3279, 3279, 3280, 3280, 3281, 3282,
+ 3282, 3283, 3284, 3284, 3285, 3285, 3286, 3287, 3287, 3288, 3289, 3289, 3290, 3290, 3291, 3292,
+ 3292, 3293, 3294, 3294, 3295, 3295, 3296, 3297, 3297, 3298, 3299, 3299, 3300, 3300, 3301, 3302,
+ 3302, 3303, 3304, 3304, 3305, 3305, 3306, 3307, 3307, 3308, 3309, 3309, 3310, 3310, 3311, 3312,
+ 3312, 3313, 3314, 3314, 3315, 3315, 3316, 3317, 3317, 3318, 3319, 3319, 3320, 3320, 3321, 3322,
+ 3322, 3323, 3323, 3324, 3325, 3325, 3326, 3327, 3327, 3328, 3328, 3329, 3330, 3330, 3331, 3332,
+ 3332, 3333, 3333, 3334, 3335, 3335, 3336, 3336, 3337, 3338, 3338, 3339, 3340, 3340, 3341, 3341,
+ 3342, 3343, 3343, 3344, 3345, 3345, 3346, 3346, 3347, 3348, 3348, 3349, 3349, 3350, 3351, 3351,
+ 3352, 3352, 3353, 3354, 3354, 3355, 3356, 3356, 3357, 3357, 3358, 3359, 3359, 3360, 3360, 3361,
+ 3362, 3362, 3363, 3364, 3364, 3365, 3365, 3366, 3367, 3367, 3368, 3368, 3369, 3370, 3370, 3371,
+ 3371, 3372, 3373, 3373, 3374, 3375, 3375, 3376, 3376, 3377, 3378, 3378, 3379, 3379, 3380, 3381,
+ 3381, 3382, 3382, 3383, 3384, 3384, 3385, 3385, 3386, 3387, 3387, 3388, 3389, 3389, 3390, 3390,
+ 3391, 3392, 3392, 3393, 3393, 3394, 3395, 3395, 3396, 3396, 3397, 3398, 3398, 3399, 3399, 3400,
+ 3401, 3401, 3402, 3402, 3403, 3404, 3404, 3405, 3405, 3406, 3407, 3407, 3408, 3408, 3409, 3410,
+ 3410, 3411, 3411, 3412, 3413, 3413, 3414, 3414, 3415, 3416, 3416, 3417, 3418, 3418, 3419, 3419,
+ 3420, 3421, 3421, 3422, 3422, 3423, 3424, 3424, 3425, 3425, 3426, 3427, 3427, 3428, 3428, 3429,
+ 3430, 3430, 3431, 3431, 3432, 3433, 3433, 3434, 3434, 3435, 3435, 3436, 3437, 3437, 3438, 3438,
+ 3439, 3440, 3440, 3441, 3441, 3442, 3443, 3443, 3444, 3444, 3445, 3446, 3446, 3447, 3447, 3448,
+ 3449, 3449, 3450, 3450, 3451, 3452, 3452, 3453, 3453, 3454, 3455, 3455, 3456, 3456, 3457, 3458,
+ 3458, 3459, 3459, 3460, 3461, 3461, 3462, 3462, 3463, 3463, 3464, 3465, 3465, 3466, 3466, 3467,
+ 3468, 3468, 3469, 3469, 3470, 3471, 3471, 3472, 3472, 3473, 3474, 3474, 3475, 3475, 3476, 3476,
+ 3477, 3478, 3478, 3479, 3479, 3480, 3481, 3481, 3482, 3482, 3483, 3484, 3484, 3485, 3485, 3486,
+ 3486, 3487, 3488, 3488, 3489, 3489, 3490, 3491, 3491, 3492, 3492, 3493, 3494, 3494, 3495, 3495,
+ 3496, 3496, 3497, 3498, 3498, 3499, 3499, 3500, 3501, 3501, 3502, 3502, 3503, 3504, 3504, 3505,
+ 3505, 3506, 3506, 3507, 3508, 3508, 3509, 3509, 3510, 3511, 3511, 3512, 3512, 3513, 3513, 3514,
+ 3515, 3515, 3516, 3516, 3517, 3518, 3518, 3519, 3519, 3520, 3520, 3521, 3522, 3522, 3523, 3523,
+ 3524, 3525, 3525, 3526, 3526, 3527, 3527, 3528, 3529, 3529, 3530, 3530, 3531, 3531, 3532, 3533,
+ 3533, 3534, 3534, 3535, 3536, 3536, 3537, 3537, 3538, 3538, 3539, 3540, 3540, 3541, 3541, 3542,
+ 3542, 3543, 3544, 3544, 3545, 3545, 3546, 3547, 3547, 3548, 3548, 3549, 3549, 3550, 3551, 3551,
+ 3552, 3552, 3553, 3553, 3554, 3555, 3555, 3556, 3556, 3557, 3557, 3558, 3559, 3559, 3560, 3560,
+ 3561, 3561, 3562, 3563, 3563, 3564, 3564, 3565, 3566, 3566, 3567, 3567, 3568, 3568, 3569, 3570,
+ 3570, 3571, 3571, 3572, 3572, 3573, 3574, 3574, 3575, 3575, 3576, 3576, 3577, 3578, 3578, 3579,
+ 3579, 3580, 3580, 3581, 3582, 3582, 3583, 3583, 3584, 3584, 3585, 3586, 3586, 3587, 3587, 3588,
+ 3588, 3589, 3590, 3590, 3591, 3591, 3592, 3592, 3593, 3594, 3594, 3595, 3595, 3596, 3596, 3597,
+ 3597, 3598, 3599, 3599, 3600, 3600, 3601, 3601, 3602, 3603, 3603, 3604, 3604, 3605, 3605, 3606,
+ 3607, 3607, 3608, 3608, 3609, 3609, 3610, 3611, 3611, 3612, 3612, 3613, 3613, 3614, 3615, 3615,
+ 3616, 3616, 3617, 3617, 3618, 3618, 3619, 3620, 3620, 3621, 3621, 3622, 3622, 3623, 3624, 3624,
+ 3625, 3625, 3626, 3626, 3627, 3627, 3628, 3629, 3629, 3630, 3630, 3631, 3631, 3632, 3633, 3633,
+ 3634, 3634, 3635, 3635, 3636, 3636, 3637, 3638, 3638, 3639, 3639, 3640, 3640, 3641, 3642, 3642,
+ 3643, 3643, 3644, 3644, 3645, 3645, 3646, 3647, 3647, 3648, 3648, 3649, 3649, 3650, 3650, 3651,
+ 3652, 3652, 3653, 3653, 3654, 3654, 3655, 3656, 3656, 3657, 3657, 3658, 3658, 3659, 3659, 3660,
+ 3661, 3661, 3662, 3662, 3663, 3663, 3664, 3664, 3665, 3666, 3666, 3667, 3667, 3668, 3668, 3669,
+ 3669, 3670, 3671, 3671, 3672, 3672, 3673, 3673, 3674, 3674, 3675, 3676, 3676, 3677, 3677, 3678,
+ 3678, 3679, 3679, 3680, 3681, 3681, 3682, 3682, 3683, 3683, 3684, 3684, 3685, 3686, 3686, 3687,
+ 3687, 3688, 3688, 3689, 3689, 3690, 3691, 3691, 3692, 3692, 3693, 3693, 3694, 3694, 3695, 3695,
+ 3696, 3697, 3697, 3698, 3698, 3699, 3699, 3700, 3700, 3701, 3702, 3702, 3703, 3703, 3704, 3704,
+ 3705, 3705, 3706, 3707, 3707, 3708, 3708, 3709, 3709, 3710, 3710, 3711, 3711, 3712, 3713, 3713,
+ 3714, 3714, 3715, 3715, 3716, 3716, 3717, 3717, 3718, 3719, 3719, 3720, 3720, 3721, 3721, 3722,
+ 3722, 3723, 3724, 3724, 3725, 3725, 3726, 3726, 3727, 3727, 3728, 3728, 3729, 3730, 3730, 3731,
+ 3731, 3732, 3732, 3733, 3733, 3734, 3734, 3735, 3736, 3736, 3737, 3737, 3738, 3738, 3739, 3739,
+ 3740, 3740, 3741, 3742, 3742, 3743, 3743, 3744, 3744, 3745, 3745, 3746, 3746, 3747, 3748, 3748,
+ 3749, 3749, 3750, 3750, 3751, 3751, 3752, 3752, 3753, 3753, 3754, 3755, 3755, 3756, 3756, 3757,
+ 3757, 3758, 3758, 3759, 3759, 3760, 3761, 3761, 3762, 3762, 3763, 3763, 3764, 3764, 3765, 3765,
+ 3766, 3766, 3767, 3768, 3768, 3769, 3769, 3770, 3770, 3771, 3771, 3772, 3772, 3773, 3773, 3774,
+ 3775, 3775, 3776, 3776, 3777, 3777, 3778, 3778, 3779, 3779, 3780, 3781, 3781, 3782, 3782, 3783,
+ 3783, 3784, 3784, 3785, 3785, 3786, 3786, 3787, 3787, 3788, 3789, 3789, 3790, 3790, 3791, 3791,
+ 3792, 3792, 3793, 3793, 3794, 3794, 3795, 3796, 3796, 3797, 3797, 3798, 3798, 3799, 3799, 3800,
+ 3800, 3801, 3801, 3802, 3802, 3803, 3804, 3804, 3805, 3805, 3806, 3806, 3807, 3807, 3808, 3808,
+ 3809, 3809, 3810, 3811, 3811, 3812, 3812, 3813, 3813, 3814, 3814, 3815, 3815, 3816, 3816, 3817,
+ 3817, 3818, 3819, 3819, 3820, 3820, 3821, 3821, 3822, 3822, 3823, 3823, 3824, 3824, 3825, 3825,
+ 3826, 3826, 3827, 3828, 3828, 3829, 3829, 3830, 3830, 3831, 3831, 3832, 3832, 3833, 3833, 3834,
+ 3834, 3835, 3835, 3836, 3837, 3837, 3838, 3838, 3839, 3839, 3840, 3840, 3841, 3841, 3842, 3842,
+ 3843, 3843, 3844, 3844, 3845, 3846, 3846, 3847, 3847, 3848, 3848, 3849, 3849, 3850, 3850, 3851,
+ 3851, 3852, 3852, 3853, 3853, 3854, 3855, 3855, 3856, 3856, 3857, 3857, 3858, 3858, 3859, 3859,
+ 3860, 3860, 3861, 3861, 3862, 3862, 3863, 3863, 3864, 3864, 3865, 3866, 3866, 3867, 3867, 3868,
+ 3868, 3869, 3869, 3870, 3870, 3871, 3871, 3872, 3872, 3873, 3873, 3874, 3874, 3875, 3876, 3876,
+ 3877, 3877, 3878, 3878, 3879, 3879, 3880, 3880, 3881, 3881, 3882, 3882, 3883, 3883, 3884, 3884,
+ 3885, 3885, 3886, 3886, 3887, 3888, 3888, 3889, 3889, 3890, 3890, 3891, 3891, 3892, 3892, 3893,
+ 3893, 3894, 3894, 3895, 3895, 3896, 3896, 3897, 3897, 3898, 3898, 3899, 3900, 3900, 3901, 3901,
+ 3902, 3902, 3903, 3903, 3904, 3904, 3905, 3905, 3906, 3906, 3907, 3907, 3908, 3908, 3909, 3909,
+ 3910, 3910, 3911, 3911, 3912, 3912, 3913, 3914, 3914, 3915, 3915, 3916, 3916, 3917, 3917, 3918,
+ 3918, 3919, 3919, 3920, 3920, 3921, 3921, 3922, 3922, 3923, 3923, 3924, 3924, 3925, 3925, 3926,
+ 3926, 3927, 3927, 3928, 3929, 3929, 3930, 3930, 3931, 3931, 3932, 3932, 3933, 3933, 3934, 3934,
+ 3935, 3935, 3936, 3936, 3937, 3937, 3938, 3938, 3939, 3939, 3940, 3940, 3941, 3941, 3942, 3942,
+ 3943, 3943, 3944, 3944, 3945, 3945, 3946, 3947, 3947, 3948, 3948, 3949, 3949, 3950, 3950, 3951,
+ 3951, 3952, 3952, 3953, 3953, 3954, 3954, 3955, 3955, 3956, 3956, 3957, 3957, 3958, 3958, 3959,
+ 3959, 3960, 3960, 3961, 3961, 3962, 3962, 3963, 3963, 3964, 3964, 3965, 3965, 3966, 3966, 3967,
+ 3967, 3968, 3969, 3969, 3970, 3970, 3971, 3971, 3972, 3972, 3973, 3973, 3974, 3974, 3975, 3975,
+ 3976, 3976, 3977, 3977, 3978, 3978, 3979, 3979, 3980, 3980, 3981, 3981, 3982, 3982, 3983, 3983,
+ 3984, 3984, 3985, 3985, 3986, 3986, 3987, 3987, 3988, 3988, 3989, 3989, 3990, 3990, 3991, 3991,
+ 3992, 3992, 3993, 3993, 3994, 3994, 3995, 3995, 3996, 3996, 3997, 3997, 3998, 3998, 3999, 3999,
+ 4000, 4001, 4001, 4002, 4002, 4003, 4003, 4004, 4004, 4005, 4005, 4006, 4006, 4007, 4007, 4008,
+ 4008, 4009, 4009, 4010, 4010, 4011, 4011, 4012, 4012, 4013, 4013, 4014, 4014, 4015, 4015, 4016,
+ 4016, 4017, 4017, 4018, 4018, 4019, 4019, 4020, 4020, 4021, 4021, 4022, 4022, 4023, 4023, 4024,
+ 4024, 4025, 4025, 4026, 4026, 4027, 4027, 4028, 4028, 4029, 4029, 4030, 4030, 4031, 4031, 4032,
+ 4032, 4033, 4033, 4034, 4034, 4035, 4035, 4036, 4036, 4037, 4037, 4038, 4038, 4039, 4039, 4040,
+ 4040, 4041, 4041, 4042, 4042, 4043, 4043, 4044, 4044, 4045, 4045, 4046, 4046, 4047, 4047, 4048,
+ 4048, 4049, 4049, 4050, 4050, 4051, 4051, 4052, 4052, 4053, 4053, 4054, 4054, 4055, 4055, 4056,
+ 4056, 4057, 4057, 4058, 4058, 4059, 4059, 4060, 4060, 4061, 4061, 4062, 4062, 4063, 4063, 4064,
+ 4064, 4065, 4065, 4066, 4066, 4067, 4067, 4068, 4068, 4069, 4069, 4070, 4070, 4071, 4071, 4072,
+ 4072, 4073, 4073, 4074, 4074, 4075, 4075, 4076, 4076, 4077, 4077, 4078, 4078, 4079, 4079, 4080,
+ 4080,
+};
+
+/* Generated table */
+const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][TPG_COLOR_CSC_BLACK + 1] = {
+ [V4L2_COLORSPACE_SMPTE170M][0] = { 2939, 2939, 2939 },
+ [V4L2_COLORSPACE_SMPTE170M][1] = { 2953, 2963, 586 },
+ [V4L2_COLORSPACE_SMPTE170M][2] = { 0, 2967, 2937 },
+ [V4L2_COLORSPACE_SMPTE170M][3] = { 88, 2990, 575 },
+ [V4L2_COLORSPACE_SMPTE170M][4] = { 3016, 259, 2933 },
+ [V4L2_COLORSPACE_SMPTE170M][5] = { 3030, 405, 558 },
+ [V4L2_COLORSPACE_SMPTE170M][6] = { 478, 428, 2931 },
+ [V4L2_COLORSPACE_SMPTE170M][7] = { 547, 547, 547 },
[V4L2_COLORSPACE_SMPTE240M][0] = { 2926, 2926, 2926 },
- [V4L2_COLORSPACE_SMPTE240M][1] = { 2926, 2926, 857 },
- [V4L2_COLORSPACE_SMPTE240M][2] = { 1594, 2901, 2901 },
- [V4L2_COLORSPACE_SMPTE240M][3] = { 1594, 2901, 774 },
- [V4L2_COLORSPACE_SMPTE240M][4] = { 2484, 618, 2858 },
- [V4L2_COLORSPACE_SMPTE240M][5] = { 2484, 618, 617 },
- [V4L2_COLORSPACE_SMPTE240M][6] = { 507, 507, 2832 },
+ [V4L2_COLORSPACE_SMPTE240M][1] = { 2941, 2950, 546 },
+ [V4L2_COLORSPACE_SMPTE240M][2] = { 0, 2954, 2924 },
+ [V4L2_COLORSPACE_SMPTE240M][3] = { 78, 2978, 536 },
+ [V4L2_COLORSPACE_SMPTE240M][4] = { 3004, 230, 2920 },
+ [V4L2_COLORSPACE_SMPTE240M][5] = { 3018, 363, 518 },
+ [V4L2_COLORSPACE_SMPTE240M][6] = { 437, 387, 2918 },
[V4L2_COLORSPACE_SMPTE240M][7] = { 507, 507, 507 },
[V4L2_COLORSPACE_REC709][0] = { 2939, 2939, 2939 },
[V4L2_COLORSPACE_REC709][1] = { 2939, 2939, 547 },
@@ -103,21 +623,21 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLAC
[V4L2_COLORSPACE_REC709][5] = { 2939, 547, 547 },
[V4L2_COLORSPACE_REC709][6] = { 547, 547, 2939 },
[V4L2_COLORSPACE_REC709][7] = { 547, 547, 547 },
- [V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2894, 2988, 2808 },
- [V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2847, 3070, 843 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][0] = { 2892, 2988, 2807 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][1] = { 2846, 3070, 843 },
[V4L2_COLORSPACE_470_SYSTEM_M][2] = { 1656, 2962, 2783 },
[V4L2_COLORSPACE_470_SYSTEM_M][3] = { 1572, 3045, 763 },
- [V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2477, 229, 2743 },
- [V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2422, 672, 614 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][4] = { 2476, 229, 2742 },
+ [V4L2_COLORSPACE_470_SYSTEM_M][5] = { 2420, 672, 614 },
[V4L2_COLORSPACE_470_SYSTEM_M][6] = { 725, 63, 2718 },
[V4L2_COLORSPACE_470_SYSTEM_M][7] = { 534, 561, 509 },
[V4L2_COLORSPACE_470_SYSTEM_BG][0] = { 2939, 2939, 2939 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 621 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][1] = { 2939, 2939, 464 },
[V4L2_COLORSPACE_470_SYSTEM_BG][2] = { 786, 2939, 2939 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 621 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2923 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][3] = { 786, 2939, 464 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][4] = { 2879, 547, 2956 },
[V4L2_COLORSPACE_470_SYSTEM_BG][5] = { 2879, 547, 547 },
- [V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2923 },
+ [V4L2_COLORSPACE_470_SYSTEM_BG][6] = { 547, 547, 2956 },
[V4L2_COLORSPACE_470_SYSTEM_BG][7] = { 547, 547, 547 },
[V4L2_COLORSPACE_SRGB][0] = { 3056, 3056, 3056 },
[V4L2_COLORSPACE_SRGB][1] = { 3056, 3056, 800 },
@@ -127,6 +647,22 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLAC
[V4L2_COLORSPACE_SRGB][5] = { 3056, 800, 800 },
[V4L2_COLORSPACE_SRGB][6] = { 800, 800, 3056 },
[V4L2_COLORSPACE_SRGB][7] = { 800, 800, 800 },
+ [V4L2_COLORSPACE_ADOBERGB][0] = { 3033, 3033, 3033 },
+ [V4L2_COLORSPACE_ADOBERGB][1] = { 3033, 3033, 1063 },
+ [V4L2_COLORSPACE_ADOBERGB][2] = { 1828, 3033, 3033 },
+ [V4L2_COLORSPACE_ADOBERGB][3] = { 1828, 3033, 1063 },
+ [V4L2_COLORSPACE_ADOBERGB][4] = { 2633, 851, 2979 },
+ [V4L2_COLORSPACE_ADOBERGB][5] = { 2633, 851, 851 },
+ [V4L2_COLORSPACE_ADOBERGB][6] = { 851, 851, 2979 },
+ [V4L2_COLORSPACE_ADOBERGB][7] = { 851, 851, 851 },
+ [V4L2_COLORSPACE_BT2020][0] = { 2939, 2939, 2939 },
+ [V4L2_COLORSPACE_BT2020][1] = { 2877, 2923, 1058 },
+ [V4L2_COLORSPACE_BT2020][2] = { 1837, 2840, 2916 },
+ [V4L2_COLORSPACE_BT2020][3] = { 1734, 2823, 993 },
+ [V4L2_COLORSPACE_BT2020][4] = { 2427, 961, 2812 },
+ [V4L2_COLORSPACE_BT2020][5] = { 2351, 912, 648 },
+ [V4L2_COLORSPACE_BT2020][6] = { 792, 618, 2788 },
+ [V4L2_COLORSPACE_BT2020][7] = { 547, 547, 547 },
};
#else
@@ -138,29 +674,40 @@ const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLAC
#include <stdlib.h>
static const double rec709_to_ntsc1953[3][3] = {
- { 0.6698, 0.2678, 0.0323 },
- { 0.0185, 1.0742, -0.0603 },
- { 0.0162, 0.0432, 0.8551 }
+ { 0.6689794, 0.2678309, 0.0323187 },
+ { 0.0184901, 1.0742442, -0.0602820 },
+ { 0.0162259, 0.0431716, 0.8549253 }
};
static const double rec709_to_ebu[3][3] = {
- { 0.9578, 0.0422, 0 },
- { 0 , 1 , 0 },
- { 0 , 0.0118, 0.9882 }
+ { 0.9578221, 0.0421779, -0.0000000 },
+ { -0.0000000, 1.0000000, 0.0000000 },
+ { -0.0000000, -0.0119367, 1.0119367 }
};
static const double rec709_to_170m[3][3] = {
- { 1.0654, -0.0554, -0.0010 },
- { -0.0196, 1.0364, -0.0167 },
- { 0.0016, 0.0044, 0.9940 }
+ { 1.0653640, -0.0553900, -0.0099740 },
+ { -0.0196361, 1.0363630, -0.0167269 },
+ { 0.0016327, 0.0044133, 0.9939540 },
};
static const double rec709_to_240m[3][3] = {
- { 0.7151, 0.2849, 0 },
- { 0.0179, 0.9821, 0 },
- { 0.0177, 0.0472, 0.9350 }
+ { 1.0653640, -0.0553900, -0.0099740 },
+ { -0.0196361, 1.0363630, -0.0167269 },
+ { 0.0016327, 0.0044133, 0.9939540 },
+};
+
+static const double rec709_to_adobergb[3][3] = {
+ { 0.7151627, 0.2848373, -0.0000000 },
+ { 0.0000000, 1.0000000, 0.0000000 },
+ { -0.0000000, 0.0411705, 0.9588295 },
};
+static const double rec709_to_bt2020[3][3] = {
+ { 0.6274524, 0.3292485, 0.0432991 },
+ { 0.0691092, 0.9195311, 0.0113597 },
+ { 0.0163976, 0.0880301, 0.8955723 },
+};
static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
{
@@ -176,7 +723,18 @@ static void mult_matrix(double *r, double *g, double *b, const double m[3][3])
static double transfer_srgb_to_rgb(double v)
{
- return (v <= 0.03928) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
+ if (v < -0.04045)
+ return pow((-v + 0.055) / 1.055, 2.4);
+ return (v <= 0.04045) ? v / 12.92 : pow((v + 0.055) / 1.055, 2.4);
+}
+
+static double transfer_rgb_to_srgb(double v)
+{
+ if (v <= -0.0031308)
+ return -1.055 * pow(-v, 1.0 / 2.4) + 0.055;
+ if (v <= 0.0031308)
+ return v * 12.92;
+ return 1.055 * pow(v, 1.0 / 2.4) - 0.055;
}
static double transfer_rgb_to_smpte240m(double v)
@@ -186,9 +744,21 @@ static double transfer_rgb_to_smpte240m(double v)
static double transfer_rgb_to_rec709(double v)
{
+ if (v <= -0.018)
+ return -1.099 * pow(-v, 0.45) + 0.099;
return (v < 0.018) ? v * 4.5 : 1.099 * pow(v, 0.45) - 0.099;
}
+static double transfer_rec709_to_rgb(double v)
+{
+ return (v < 0.081) ? v / 4.5 : pow((v + 0.099) / 1.099, 1.0 / 0.45);
+}
+
+static double transfer_rgb_to_adobergb(double v)
+{
+ return pow(v, 1.0 / 2.19921875);
+}
+
static double transfer_srgb_to_rec709(double v)
{
return transfer_rgb_to_rec709(transfer_srgb_to_rgb(v));
@@ -196,6 +766,8 @@ static double transfer_srgb_to_rec709(double v)
static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b)
{
+ int clamp = 1;
+
/* Convert the primaries of Rec. 709 Linear RGB */
switch (colorspace) {
case V4L2_COLORSPACE_SMPTE240M:
@@ -222,15 +794,29 @@ static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b
*b = transfer_srgb_to_rgb(*b);
mult_matrix(r, g, b, rec709_to_ntsc1953);
break;
+ case V4L2_COLORSPACE_ADOBERGB:
+ *r = transfer_srgb_to_rgb(*r);
+ *g = transfer_srgb_to_rgb(*g);
+ *b = transfer_srgb_to_rgb(*b);
+ mult_matrix(r, g, b, rec709_to_adobergb);
+ break;
+ case V4L2_COLORSPACE_BT2020:
+ *r = transfer_srgb_to_rgb(*r);
+ *g = transfer_srgb_to_rgb(*g);
+ *b = transfer_srgb_to_rgb(*b);
+ mult_matrix(r, g, b, rec709_to_bt2020);
+ break;
case V4L2_COLORSPACE_SRGB:
case V4L2_COLORSPACE_REC709:
default:
break;
}
- *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
- *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
- *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
+ if (clamp) {
+ *r = ((*r) < 0) ? 0 : (((*r) > 1) ? 1 : (*r));
+ *g = ((*g) < 0) ? 0 : (((*g) > 1) ? 1 : (*g));
+ *b = ((*b) < 0) ? 0 : (((*b) > 1) ? 1 : (*b));
+ }
/* Encode to gamma corrected colorspace */
switch (colorspace) {
@@ -242,12 +828,18 @@ static void csc(enum v4l2_colorspace colorspace, double *r, double *g, double *b
case V4L2_COLORSPACE_SMPTE170M:
case V4L2_COLORSPACE_470_SYSTEM_M:
case V4L2_COLORSPACE_470_SYSTEM_BG:
+ case V4L2_COLORSPACE_BT2020:
*r = transfer_rgb_to_rec709(*r);
*g = transfer_rgb_to_rec709(*g);
*b = transfer_rgb_to_rec709(*b);
break;
case V4L2_COLORSPACE_SRGB:
break;
+ case V4L2_COLORSPACE_ADOBERGB:
+ *r = transfer_rgb_to_adobergb(*r);
+ *g = transfer_rgb_to_adobergb(*g);
+ *b = transfer_rgb_to_adobergb(*b);
+ break;
case V4L2_COLORSPACE_REC709:
default:
*r = transfer_srgb_to_rec709(*r);
@@ -269,6 +861,8 @@ int main(int argc, char **argv)
V4L2_COLORSPACE_470_SYSTEM_BG,
0,
V4L2_COLORSPACE_SRGB,
+ V4L2_COLORSPACE_ADOBERGB,
+ V4L2_COLORSPACE_BT2020,
};
static const char * const colorspace_names[] = {
"",
@@ -280,13 +874,39 @@ int main(int argc, char **argv)
"V4L2_COLORSPACE_470_SYSTEM_BG",
"",
"V4L2_COLORSPACE_SRGB",
+ "V4L2_COLORSPACE_ADOBERGB",
+ "V4L2_COLORSPACE_BT2020",
};
int i;
int c;
printf("/* Generated table */\n");
- printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
- for (c = 0; c <= V4L2_COLORSPACE_SRGB; c++) {
+ printf("const unsigned short tpg_rec709_to_linear[255 * 16 + 1] = {");
+ for (i = 0; i <= 255 * 16; i++) {
+ if (i % 16 == 0)
+ printf("\n\t");
+ printf("%4d,%s",
+ (int)(0.5 + 16.0 * 255.0 *
+ transfer_rec709_to_rgb(i / (16.0 * 255.0))),
+ i % 16 == 15 || i == 255 * 16 ? "" : " ");
+ }
+ printf("\n};\n\n");
+
+ printf("/* Generated table */\n");
+ printf("const unsigned short tpg_linear_to_rec709[255 * 16 + 1] = {");
+ for (i = 0; i <= 255 * 16; i++) {
+ if (i % 16 == 0)
+ printf("\n\t");
+ printf("%4d,%s",
+ (int)(0.5 + 16.0 * 255.0 *
+ transfer_rgb_to_rec709(i / (16.0 * 255.0))),
+ i % 16 == 15 || i == 255 * 16 ? "" : " ");
+ }
+ printf("\n};\n\n");
+
+ printf("/* Generated table */\n");
+ printf("const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][TPG_COLOR_CSC_BLACK + 1] = {\n");
+ for (c = 0; c <= V4L2_COLORSPACE_BT2020; c++) {
for (i = 0; i <= TPG_COLOR_CSC_BLACK; i++) {
double r, g, b;
diff --git a/drivers/media/platform/vivid/vivid-tpg-colors.h b/drivers/media/platform/vivid/vivid-tpg-colors.h
index a2678fb..2c33335 100644
--- a/drivers/media/platform/vivid/vivid-tpg-colors.h
+++ b/drivers/media/platform/vivid/vivid-tpg-colors.h
@@ -59,6 +59,8 @@ enum tpg_color {
};
extern const struct color tpg_colors[TPG_COLOR_MAX];
-extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_SRGB + 1][TPG_COLOR_CSC_BLACK + 1];
+extern const unsigned short tpg_rec709_to_linear[255 * 16 + 1];
+extern const unsigned short tpg_linear_to_rec709[255 * 16 + 1];
+extern const struct color16 tpg_csc_colors[V4L2_COLORSPACE_BT2020 + 1][TPG_COLOR_CSC_BLACK + 1];
#endif
diff --git a/drivers/media/platform/vivid/vivid-tpg.c b/drivers/media/platform/vivid/vivid-tpg.c
index cbcd625..fc9c653 100644
--- a/drivers/media/platform/vivid/vivid-tpg.c
+++ b/drivers/media/platform/vivid/vivid-tpg.c
@@ -296,127 +296,193 @@ static enum tpg_color tpg_get_textfg_color(struct tpg_data *tpg)
}
}
-static u16 color_to_y(struct tpg_data *tpg, int r, int g, int b)
+static inline int rec709_to_linear(int v)
{
- switch (tpg->colorspace) {
- case V4L2_COLORSPACE_SMPTE170M:
- case V4L2_COLORSPACE_470_SYSTEM_M:
- case V4L2_COLORSPACE_470_SYSTEM_BG:
- return ((16829 * r + 33039 * g + 6416 * b + 16 * 32768) >> 16) + (16 << 4);
- case V4L2_COLORSPACE_SMPTE240M:
- return ((11932 * r + 39455 * g + 4897 * b + 16 * 32768) >> 16) + (16 << 4);
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_SRGB:
- default:
- return ((11966 * r + 40254 * g + 4064 * b + 16 * 32768) >> 16) + (16 << 4);
- }
+ v = clamp(v, 0, 0xff0);
+ return tpg_rec709_to_linear[v];
}
-static u16 color_to_cb(struct tpg_data *tpg, int r, int g, int b)
+static inline int linear_to_rec709(int v)
{
- switch (tpg->colorspace) {
- case V4L2_COLORSPACE_SMPTE170M:
- case V4L2_COLORSPACE_470_SYSTEM_M:
- case V4L2_COLORSPACE_470_SYSTEM_BG:
- return ((-9714 * r - 19070 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
- case V4L2_COLORSPACE_SMPTE240M:
- return ((-6684 * r - 22100 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_SRGB:
- default:
- return ((-6596 * r - 22189 * g + 28784 * b + 16 * 32768) >> 16) + (128 << 4);
- }
+ v = clamp(v, 0, 0xff0);
+ return tpg_linear_to_rec709[v];
}
-static u16 color_to_cr(struct tpg_data *tpg, int r, int g, int b)
+static void rgb2ycbcr(const int m[3][3], int r, int g, int b,
+ int y_offset, int *y, int *cb, int *cr)
{
- switch (tpg->colorspace) {
- case V4L2_COLORSPACE_SMPTE170M:
- case V4L2_COLORSPACE_470_SYSTEM_M:
- case V4L2_COLORSPACE_470_SYSTEM_BG:
- return ((28784 * r - 24103 * g - 4681 * b + 16 * 32768) >> 16) + (128 << 4);
- case V4L2_COLORSPACE_SMPTE240M:
- return ((28784 * r - 25606 * g - 3178 * b + 16 * 32768) >> 16) + (128 << 4);
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_SRGB:
- default:
- return ((28784 * r - 26145 * g - 2639 * b + 16 * 32768) >> 16) + (128 << 4);
- }
+ *y = ((m[0][0] * r + m[0][1] * g + m[0][2] * b) >> 16) + (y_offset << 4);
+ *cb = ((m[1][0] * r + m[1][1] * g + m[1][2] * b) >> 16) + (128 << 4);
+ *cr = ((m[2][0] * r + m[2][1] * g + m[2][2] * b) >> 16) + (128 << 4);
}
-static u16 ycbcr_to_r(struct tpg_data *tpg, int y, int cb, int cr)
+static void color_to_ycbcr(struct tpg_data *tpg, int r, int g, int b,
+ int *y, int *cb, int *cr)
{
- int r;
+#define COEFF(v, r) ((int)(0.5 + (v) * (r) * 256.0))
- y -= 16 << 4;
- cb -= 128 << 4;
- cr -= 128 << 4;
- switch (tpg->colorspace) {
- case V4L2_COLORSPACE_SMPTE170M:
- case V4L2_COLORSPACE_470_SYSTEM_M:
- case V4L2_COLORSPACE_470_SYSTEM_BG:
- r = 4769 * y + 6537 * cr;
+ static const int bt601[3][3] = {
+ { COEFF(0.299, 219), COEFF(0.587, 219), COEFF(0.114, 219) },
+ { COEFF(-0.169, 224), COEFF(-0.331, 224), COEFF(0.5, 224) },
+ { COEFF(0.5, 224), COEFF(-0.419, 224), COEFF(-0.081, 224) },
+ };
+ static const int bt601_full[3][3] = {
+ { COEFF(0.299, 255), COEFF(0.587, 255), COEFF(0.114, 255) },
+ { COEFF(-0.169, 255), COEFF(-0.331, 255), COEFF(0.5, 255) },
+ { COEFF(0.5, 255), COEFF(-0.419, 255), COEFF(-0.081, 255) },
+ };
+ static const int rec709[3][3] = {
+ { COEFF(0.2126, 219), COEFF(0.7152, 219), COEFF(0.0722, 219) },
+ { COEFF(-0.1146, 224), COEFF(-0.3854, 224), COEFF(0.5, 224) },
+ { COEFF(0.5, 224), COEFF(-0.4542, 224), COEFF(-0.0458, 224) },
+ };
+ static const int rec709_full[3][3] = {
+ { COEFF(0.2126, 255), COEFF(0.7152, 255), COEFF(0.0722, 255) },
+ { COEFF(-0.1146, 255), COEFF(-0.3854, 255), COEFF(0.5, 255) },
+ { COEFF(0.5, 255), COEFF(-0.4542, 255), COEFF(-0.0458, 255) },
+ };
+ static const int smpte240m[3][3] = {
+ { COEFF(0.212, 219), COEFF(0.701, 219), COEFF(0.087, 219) },
+ { COEFF(-0.116, 224), COEFF(-0.384, 224), COEFF(0.5, 224) },
+ { COEFF(0.5, 224), COEFF(-0.445, 224), COEFF(-0.055, 224) },
+ };
+ static const int bt2020[3][3] = {
+ { COEFF(0.2726, 219), COEFF(0.6780, 219), COEFF(0.0593, 219) },
+ { COEFF(-0.1396, 224), COEFF(-0.3604, 224), COEFF(0.5, 224) },
+ { COEFF(0.5, 224), COEFF(-0.4629, 224), COEFF(-0.0405, 224) },
+ };
+ bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
+ int lin_y, yc;
+
+ switch (tpg->real_ycbcr_enc) {
+ case V4L2_YCBCR_ENC_601:
+ case V4L2_YCBCR_ENC_XV601:
+ case V4L2_YCBCR_ENC_SYCC:
+ rgb2ycbcr(full ? bt601_full : bt601, r, g, b, 16, y, cb, cr);
+ break;
+ case V4L2_YCBCR_ENC_BT2020:
+ rgb2ycbcr(bt2020, r, g, b, 16, y, cb, cr);
break;
- case V4L2_COLORSPACE_SMPTE240M:
- r = 4769 * y + 7376 * cr;
+ case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+ lin_y = (COEFF(0.2627, 255) * rec709_to_linear(r) +
+ COEFF(0.6780, 255) * rec709_to_linear(g) +
+ COEFF(0.0593, 255) * rec709_to_linear(b)) >> 16;
+ yc = linear_to_rec709(lin_y);
+ *y = (yc * 219) / 255 + (16 << 4);
+ if (b <= yc)
+ *cb = (((b - yc) * COEFF(1.0 / 1.9404, 224)) >> 16) + (128 << 4);
+ else
+ *cb = (((b - yc) * COEFF(1.0 / 1.5816, 224)) >> 16) + (128 << 4);
+ if (r <= yc)
+ *cr = (((r - yc) * COEFF(1.0 / 1.7184, 224)) >> 16) + (128 << 4);
+ else
+ *cr = (((r - yc) * COEFF(1.0 / 0.9936, 224)) >> 16) + (128 << 4);
break;
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_SRGB:
+ case V4L2_YCBCR_ENC_SMPTE240M:
+ rgb2ycbcr(smpte240m, r, g, b, 16, y, cb, cr);
+ break;
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_XV709:
default:
- r = 4769 * y + 7343 * cr;
+ rgb2ycbcr(full ? rec709_full : rec709, r, g, b, 0, y, cb, cr);
break;
}
- return clamp(r >> 12, 0, 0xff0);
}
-static u16 ycbcr_to_g(struct tpg_data *tpg, int y, int cb, int cr)
+static void ycbcr2rgb(const int m[3][3], int y, int cb, int cr,
+ int y_offset, int *r, int *g, int *b)
{
- int g;
-
- y -= 16 << 4;
+ y -= y_offset << 4;
cb -= 128 << 4;
cr -= 128 << 4;
- switch (tpg->colorspace) {
- case V4L2_COLORSPACE_SMPTE170M:
- case V4L2_COLORSPACE_470_SYSTEM_M:
- case V4L2_COLORSPACE_470_SYSTEM_BG:
- g = 4769 * y - 1605 * cb - 3330 * cr;
- break;
- case V4L2_COLORSPACE_SMPTE240M:
- g = 4769 * y - 1055 * cb - 2341 * cr;
- break;
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_SRGB:
- default:
- g = 4769 * y - 873 * cb - 2183 * cr;
- break;
- }
- return clamp(g >> 12, 0, 0xff0);
+ *r = m[0][0] * y + m[0][1] * cb + m[0][2] * cr;
+ *g = m[1][0] * y + m[1][1] * cb + m[1][2] * cr;
+ *b = m[2][0] * y + m[2][1] * cb + m[2][2] * cr;
+ *r = clamp(*r >> 12, 0, 0xff0);
+ *g = clamp(*g >> 12, 0, 0xff0);
+ *b = clamp(*b >> 12, 0, 0xff0);
}
-static u16 ycbcr_to_b(struct tpg_data *tpg, int y, int cb, int cr)
+static void ycbcr_to_color(struct tpg_data *tpg, int y, int cb, int cr,
+ int *r, int *g, int *b)
{
- int b;
+#undef COEFF
+#define COEFF(v, r) ((int)(0.5 + (v) * ((255.0 * 255.0 * 16.0) / (r))))
+ static const int bt601[3][3] = {
+ { COEFF(1, 219), COEFF(0, 224), COEFF(1.4020, 224) },
+ { COEFF(1, 219), COEFF(-0.3441, 224), COEFF(-0.7141, 224) },
+ { COEFF(1, 219), COEFF(1.7720, 224), COEFF(0, 224) },
+ };
+ static const int bt601_full[3][3] = {
+ { COEFF(1, 255), COEFF(0, 255), COEFF(1.4020, 255) },
+ { COEFF(1, 255), COEFF(-0.3441, 255), COEFF(-0.7141, 255) },
+ { COEFF(1, 255), COEFF(1.7720, 255), COEFF(0, 255) },
+ };
+ static const int rec709[3][3] = {
+ { COEFF(1, 219), COEFF(0, 224), COEFF(1.5748, 224) },
+ { COEFF(1, 219), COEFF(-0.1873, 224), COEFF(-0.4681, 224) },
+ { COEFF(1, 219), COEFF(1.8556, 224), COEFF(0, 224) },
+ };
+ static const int rec709_full[3][3] = {
+ { COEFF(1, 255), COEFF(0, 255), COEFF(1.5748, 255) },
+ { COEFF(1, 255), COEFF(-0.1873, 255), COEFF(-0.4681, 255) },
+ { COEFF(1, 255), COEFF(1.8556, 255), COEFF(0, 255) },
+ };
+ static const int smpte240m[3][3] = {
+ { COEFF(1, 219), COEFF(0, 224), COEFF(1.5756, 224) },
+ { COEFF(1, 219), COEFF(-0.2253, 224), COEFF(-0.4767, 224) },
+ { COEFF(1, 219), COEFF(1.8270, 224), COEFF(0, 224) },
+ };
+ static const int bt2020[3][3] = {
+ { COEFF(1, 219), COEFF(0, 224), COEFF(1.4746, 224) },
+ { COEFF(1, 219), COEFF(-0.1646, 224), COEFF(-0.5714, 224) },
+ { COEFF(1, 219), COEFF(1.8814, 224), COEFF(0, 224) },
+ };
+ bool full = tpg->real_quantization == V4L2_QUANTIZATION_FULL_RANGE;
+ int lin_r, lin_g, lin_b, lin_y;
+
+ switch (tpg->real_ycbcr_enc) {
+ case V4L2_YCBCR_ENC_601:
+ case V4L2_YCBCR_ENC_XV601:
+ case V4L2_YCBCR_ENC_SYCC:
+ ycbcr2rgb(full ? bt601_full : bt601, y, cb, cr, 16, r, g, b);
+ break;
+ case V4L2_YCBCR_ENC_BT2020:
+ ycbcr2rgb(bt2020, y, cb, cr, 16, r, g, b);
+ break;
+ case V4L2_YCBCR_ENC_BT2020_CONST_LUM:
+ y -= 16 << 4;
+ cb -= 128 << 4;
+ cr -= 128 << 4;
- y -= 16 << 4;
- cb -= 128 << 4;
- cr -= 128 << 4;
- switch (tpg->colorspace) {
- case V4L2_COLORSPACE_SMPTE170M:
- case V4L2_COLORSPACE_470_SYSTEM_M:
- case V4L2_COLORSPACE_470_SYSTEM_BG:
- b = 4769 * y + 7343 * cb;
+ if (cb <= 0)
+ *b = COEFF(1.0, 219) * y + COEFF(1.9404, 224) * cb;
+ else
+ *b = COEFF(1.0, 219) * y + COEFF(1.5816, 224) * cb;
+ *b = *b >> 12;
+ if (cr <= 0)
+ *r = COEFF(1.0, 219) * y + COEFF(1.7184, 224) * cr;
+ else
+ *r = COEFF(1.0, 219) * y + COEFF(0.9936, 224) * cr;
+ *r = *r >> 12;
+ lin_r = rec709_to_linear(*r);
+ lin_b = rec709_to_linear(*b);
+ lin_y = rec709_to_linear((y * 255) / 219);
+
+ lin_g = COEFF(1.0 / 0.6780, 255) * lin_y -
+ COEFF(0.2627 / 0.6780, 255) * lin_r -
+ COEFF(0.0593 / 0.6780, 255) * lin_b;
+ *g = linear_to_rec709(lin_g >> 12);
break;
- case V4L2_COLORSPACE_SMPTE240M:
- b = 4769 * y + 8552 * cb;
+ case V4L2_YCBCR_ENC_SMPTE240M:
+ ycbcr2rgb(smpte240m, y, cb, cr, 16, r, g, b);
break;
- case V4L2_COLORSPACE_REC709:
- case V4L2_COLORSPACE_SRGB:
+ case V4L2_YCBCR_ENC_709:
+ case V4L2_YCBCR_ENC_XV709:
default:
- b = 4769 * y + 8652 * cb;
+ ycbcr2rgb(full ? rec709_full : rec709, y, cb, cr, 16, r, g, b);
break;
}
- return clamp(b >> 12, 0, 0xff0);
}
/* precalculate color bar values to speed up rendering */
@@ -456,18 +522,17 @@ static void precalculate_color(struct tpg_data *tpg, int k)
g <<= 4;
b <<= 4;
}
- if (tpg->qual == TPG_QUAL_GRAY)
- r = g = b = color_to_y(tpg, r, g, b);
+ if (tpg->qual == TPG_QUAL_GRAY) {
+ /* Rec. 709 Luma function */
+ /* (0.2126, 0.7152, 0.0722) * (255 * 256) */
+ r = g = b = ((13879 * r + 46688 * g + 4713 * b) >> 16) + (16 << 4);
+ }
/*
* The assumption is that the RGB output is always full range,
* so only if the rgb_range overrides the 'real' rgb range do
* we need to convert the RGB values.
*
- * Currently there is no way of signalling to userspace if you
- * are actually giving it limited range RGB (or full range
- * YUV for that matter).
- *
* Remember that r, g and b are still in the 0 - 0xff0 range.
*/
if (tpg->real_rgb_range == V4L2_DV_RGB_RANGE_LIMITED &&
@@ -497,12 +562,12 @@ static void precalculate_color(struct tpg_data *tpg, int k)
if (tpg->brightness != 128 || tpg->contrast != 128 ||
tpg->saturation != 128 || tpg->hue) {
/* Implement these operations */
+ int y, cb, cr;
+ int tmp_cb, tmp_cr;
/* First convert to YCbCr */
- int y = color_to_y(tpg, r, g, b); /* Luma */
- int cb = color_to_cb(tpg, r, g, b); /* Cb */
- int cr = color_to_cr(tpg, r, g, b); /* Cr */
- int tmp_cb, tmp_cr;
+
+ color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
y = (16 << 4) + ((y - (16 << 4)) * tpg->contrast) / 128;
y += (tpg->brightness << 4) - (128 << 4);
@@ -520,21 +585,29 @@ static void precalculate_color(struct tpg_data *tpg, int k)
tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
return;
}
- r = ycbcr_to_r(tpg, y, cb, cr);
- g = ycbcr_to_g(tpg, y, cb, cr);
- b = ycbcr_to_b(tpg, y, cb, cr);
+ ycbcr_to_color(tpg, y, cb, cr, &r, &g, &b);
}
if (tpg->is_yuv) {
/* Convert to YCbCr */
- u16 y = color_to_y(tpg, r, g, b); /* Luma */
- u16 cb = color_to_cb(tpg, r, g, b); /* Cb */
- u16 cr = color_to_cr(tpg, r, g, b); /* Cr */
+ int y, cb, cr;
+
+ color_to_ycbcr(tpg, r, g, b, &y, &cb, &cr);
+ if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
+ y = clamp(y, 16 << 4, 235 << 4);
+ cb = clamp(cb, 16 << 4, 240 << 4);
+ cr = clamp(cr, 16 << 4, 240 << 4);
+ }
tpg->colors[k][0] = clamp(y >> 4, 1, 254);
tpg->colors[k][1] = clamp(cb >> 4, 1, 254);
tpg->colors[k][2] = clamp(cr >> 4, 1, 254);
} else {
+ if (tpg->real_quantization == V4L2_QUANTIZATION_LIM_RANGE) {
+ r = (r * 219) / 255 + (16 << 4);
+ g = (g * 219) / 255 + (16 << 4);
+ b = (b * 219) / 255 + (16 << 4);
+ }
switch (tpg->fourcc) {
case V4L2_PIX_FMT_RGB565:
case V4L2_PIX_FMT_RGB565X:
@@ -1152,6 +1225,46 @@ static void tpg_recalc(struct tpg_data *tpg)
if (tpg->recalc_colors) {
tpg->recalc_colors = false;
tpg->recalc_lines = true;
+ tpg->real_ycbcr_enc = tpg->ycbcr_enc;
+ tpg->real_quantization = tpg->quantization;
+ if (tpg->ycbcr_enc == V4L2_YCBCR_ENC_DEFAULT) {
+ switch (tpg->colorspace) {
+ case V4L2_COLORSPACE_REC709:
+ tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_709;
+ break;
+ case V4L2_COLORSPACE_SRGB:
+ tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SYCC;
+ break;
+ case V4L2_COLORSPACE_BT2020:
+ tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_BT2020;
+ break;
+ case V4L2_COLORSPACE_SMPTE240M:
+ tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_SMPTE240M;
+ break;
+ case V4L2_COLORSPACE_SMPTE170M:
+ case V4L2_COLORSPACE_470_SYSTEM_M:
+ case V4L2_COLORSPACE_470_SYSTEM_BG:
+ case V4L2_COLORSPACE_ADOBERGB:
+ default:
+ tpg->real_ycbcr_enc = V4L2_YCBCR_ENC_601;
+ break;
+ }
+ }
+ if (tpg->quantization == V4L2_QUANTIZATION_DEFAULT) {
+ tpg->real_quantization = V4L2_QUANTIZATION_FULL_RANGE;
+ if (tpg->is_yuv) {
+ switch (tpg->real_ycbcr_enc) {
+ case V4L2_YCBCR_ENC_SYCC:
+ case V4L2_YCBCR_ENC_XV601:
+ case V4L2_YCBCR_ENC_XV709:
+ break;
+ default:
+ tpg->real_quantization =
+ V4L2_QUANTIZATION_LIM_RANGE;
+ break;
+ }
+ }
+ }
tpg_precalculate_colors(tpg);
}
if (tpg->recalc_square_border) {
diff --git a/drivers/media/platform/vivid/vivid-tpg.h b/drivers/media/platform/vivid/vivid-tpg.h
index 8ef3e52..9dc463a4 100644
--- a/drivers/media/platform/vivid/vivid-tpg.h
+++ b/drivers/media/platform/vivid/vivid-tpg.h
@@ -119,6 +119,18 @@ struct tpg_data {
u32 fourcc;
bool is_yuv;
u32 colorspace;
+ u32 ycbcr_enc;
+ /*
+ * Stores the actual Y'CbCr encoding, i.e. will never be
+ * V4L2_YCBCR_ENC_DEFAULT.
+ */
+ u32 real_ycbcr_enc;
+ u32 quantization;
+ /*
+ * Stores the actual quantization, i.e. will never be
+ * V4L2_QUANTIZATION_DEFAULT.
+ */
+ u32 real_quantization;
enum tpg_video_aspect vid_aspect;
enum tpg_pixel_aspect pix_aspect;
unsigned rgb_range;
@@ -286,6 +298,32 @@ static inline u32 tpg_g_colorspace(const struct tpg_data *tpg)
return tpg->colorspace;
}
+static inline void tpg_s_ycbcr_enc(struct tpg_data *tpg, u32 ycbcr_enc)
+{
+ if (tpg->ycbcr_enc == ycbcr_enc)
+ return;
+ tpg->ycbcr_enc = ycbcr_enc;
+ tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_ycbcr_enc(const struct tpg_data *tpg)
+{
+ return tpg->ycbcr_enc;
+}
+
+static inline void tpg_s_quantization(struct tpg_data *tpg, u32 quantization)
+{
+ if (tpg->quantization == quantization)
+ return;
+ tpg->quantization = quantization;
+ tpg->recalc_colors = true;
+}
+
+static inline u32 tpg_g_quantization(const struct tpg_data *tpg)
+{
+ return tpg->quantization;
+}
+
static inline unsigned tpg_g_planes(const struct tpg_data *tpg)
{
return tpg->planes;
diff --git a/drivers/media/platform/vivid/vivid-vbi-cap.c b/drivers/media/platform/vivid/vivid-vbi-cap.c
index 2166d0b..ef81b01 100644
--- a/drivers/media/platform/vivid/vivid-vbi-cap.c
+++ b/drivers/media/platform/vivid/vivid-vbi-cap.c
@@ -236,8 +236,8 @@ const struct vb2_ops vivid_vbi_cap_qops = {
.buf_queue = vbi_cap_buf_queue,
.start_streaming = vbi_cap_start_streaming,
.stop_streaming = vbi_cap_stop_streaming,
- .wait_prepare = vivid_unlock,
- .wait_finish = vivid_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
diff --git a/drivers/media/platform/vivid/vivid-vbi-out.c b/drivers/media/platform/vivid/vivid-vbi-out.c
index 9d00a07..4e4c70e 100644
--- a/drivers/media/platform/vivid/vivid-vbi-out.c
+++ b/drivers/media/platform/vivid/vivid-vbi-out.c
@@ -131,8 +131,8 @@ const struct vb2_ops vivid_vbi_out_qops = {
.buf_queue = vbi_out_buf_queue,
.start_streaming = vbi_out_start_streaming,
.stop_streaming = vbi_out_stop_streaming,
- .wait_prepare = vivid_unlock,
- .wait_finish = vivid_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
int vidioc_g_fmt_vbi_out(struct file *file, void *priv,
diff --git a/drivers/media/platform/vivid/vivid-vid-cap.c b/drivers/media/platform/vivid/vivid-vid-cap.c
index 331c544..867a29a 100644
--- a/drivers/media/platform/vivid/vivid-vid-cap.c
+++ b/drivers/media/platform/vivid/vivid-vid-cap.c
@@ -288,8 +288,8 @@ const struct vb2_ops vivid_vid_cap_qops = {
.buf_queue = vid_cap_buf_queue,
.start_streaming = vid_cap_start_streaming,
.stop_streaming = vid_cap_stop_streaming,
- .wait_prepare = vivid_unlock,
- .wait_finish = vivid_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/*
@@ -443,12 +443,12 @@ void vivid_update_format_cap(struct vivid_dev *dev, bool keep_controls)
break;
if (bt->standards & V4L2_DV_BT_STD_CEA861) {
if (bt->width == 720 && bt->height <= 576)
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
else
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_709);
v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 1);
} else {
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB);
v4l2_ctrl_s_ctrl(dev->real_rgb_range_cap, 0);
}
tpg_s_rgb_range(&dev->tpg, v4l2_ctrl_g_ctrl(dev->rgb_range_cap));
@@ -498,6 +498,20 @@ static unsigned vivid_colorspace_cap(struct vivid_dev *dev)
return dev->colorspace_out;
}
+static unsigned vivid_ycbcr_enc_cap(struct vivid_dev *dev)
+{
+ if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ return tpg_g_ycbcr_enc(&dev->tpg);
+ return dev->ycbcr_enc_out;
+}
+
+static unsigned vivid_quantization_cap(struct vivid_dev *dev)
+{
+ if (!dev->loop_video || vivid_is_webcam(dev) || vivid_is_tv_cap(dev))
+ return tpg_g_quantization(&dev->tpg);
+ return dev->quantization_out;
+}
+
int vivid_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
@@ -510,6 +524,8 @@ int vivid_g_fmt_vid_cap(struct file *file, void *priv,
mp->field = dev->field_cap;
mp->pixelformat = dev->fmt_cap->fourcc;
mp->colorspace = vivid_colorspace_cap(dev);
+ mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
+ mp->quantization = vivid_quantization_cap(dev);
mp->num_planes = dev->fmt_cap->planes;
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = tpg_g_bytesperline(&dev->tpg, p);
@@ -595,6 +611,8 @@ int vivid_try_fmt_vid_cap(struct file *file, void *priv,
memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
}
mp->colorspace = vivid_colorspace_cap(dev);
+ mp->ycbcr_enc = vivid_ycbcr_enc_cap(dev);
+ mp->quantization = vivid_quantization_cap(dev);
memset(mp->reserved, 0, sizeof(mp->reserved));
return 0;
}
@@ -1307,20 +1325,20 @@ int vidioc_s_input(struct file *file, void *priv, unsigned i)
if (dev->colorspace) {
switch (dev->input_type[i]) {
case WEBCAM:
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB);
break;
case TV:
case SVID:
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
break;
case HDMI:
if (bt->standards & V4L2_DV_BT_STD_CEA861) {
if (dev->src_rect.width == 720 && dev->src_rect.height <= 576)
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SMPTE170M);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_170M);
else
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_REC709);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_709);
} else {
- v4l2_ctrl_s_ctrl(dev->colorspace, V4L2_COLORSPACE_SRGB);
+ v4l2_ctrl_s_ctrl(dev->colorspace, VIVID_CS_SRGB);
}
break;
}
diff --git a/drivers/media/platform/vivid/vivid-vid-common.c b/drivers/media/platform/vivid/vivid-vid-common.c
index 16cd6d2..6bef1e6 100644
--- a/drivers/media/platform/vivid/vivid-vid-common.c
+++ b/drivers/media/platform/vivid/vivid-vid-common.c
@@ -259,6 +259,8 @@ void fmt_sp2mp(const struct v4l2_format *sp_fmt, struct v4l2_format *mp_fmt)
mp->pixelformat = pix->pixelformat;
mp->field = pix->field;
mp->colorspace = pix->colorspace;
+ mp->ycbcr_enc = pix->ycbcr_enc;
+ mp->quantization = pix->quantization;
mp->num_planes = 1;
mp->flags = pix->flags;
ppix->sizeimage = pix->sizeimage;
@@ -285,6 +287,8 @@ int fmt_sp2mp_func(struct file *file, void *priv,
pix->pixelformat = mp->pixelformat;
pix->field = mp->field;
pix->colorspace = mp->colorspace;
+ pix->ycbcr_enc = mp->ycbcr_enc;
+ pix->quantization = mp->quantization;
pix->sizeimage = ppix->sizeimage;
pix->bytesperline = ppix->bytesperline;
pix->flags = mp->flags;
diff --git a/drivers/media/platform/vivid/vivid-vid-out.c b/drivers/media/platform/vivid/vivid-vid-out.c
index 69c2dbd..ee5c399 100644
--- a/drivers/media/platform/vivid/vivid-vid-out.c
+++ b/drivers/media/platform/vivid/vivid-vid-out.c
@@ -209,8 +209,8 @@ const struct vb2_ops vivid_vid_out_qops = {
.buf_queue = vid_out_buf_queue,
.start_streaming = vid_out_start_streaming,
.stop_streaming = vid_out_stop_streaming,
- .wait_prepare = vivid_unlock,
- .wait_finish = vivid_lock,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
};
/*
@@ -259,6 +259,8 @@ void vivid_update_format_out(struct vivid_dev *dev)
}
break;
}
+ dev->ycbcr_enc_out = V4L2_YCBCR_ENC_DEFAULT;
+ dev->quantization_out = V4L2_QUANTIZATION_DEFAULT;
dev->compose_out = dev->sink_rect;
dev->compose_bounds_out = dev->sink_rect;
dev->crop_out = dev->compose_out;
@@ -318,6 +320,8 @@ int vivid_g_fmt_vid_out(struct file *file, void *priv,
mp->field = dev->field_out;
mp->pixelformat = dev->fmt_out->fourcc;
mp->colorspace = dev->colorspace_out;
+ mp->ycbcr_enc = dev->ycbcr_enc_out;
+ mp->quantization = dev->quantization_out;
mp->num_planes = dev->fmt_out->planes;
for (p = 0; p < mp->num_planes; p++) {
mp->plane_fmt[p].bytesperline = dev->bytesperline_out[p];
@@ -394,16 +398,23 @@ int vivid_try_fmt_vid_out(struct file *file, void *priv,
pfmt[p].sizeimage = pfmt[p].bytesperline * mp->height;
memset(pfmt[p].reserved, 0, sizeof(pfmt[p].reserved));
}
- if (vivid_is_svid_out(dev))
+ mp->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ mp->quantization = V4L2_QUANTIZATION_DEFAULT;
+ if (vivid_is_svid_out(dev)) {
mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
- else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861))
+ } else if (dev->dvi_d_out || !(bt->standards & V4L2_DV_BT_STD_CEA861)) {
mp->colorspace = V4L2_COLORSPACE_SRGB;
- else if (bt->width == 720 && bt->height <= 576)
+ if (dev->dvi_d_out)
+ mp->quantization = V4L2_QUANTIZATION_LIM_RANGE;
+ } else if (bt->width == 720 && bt->height <= 576) {
mp->colorspace = V4L2_COLORSPACE_SMPTE170M;
- else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
- mp->colorspace != V4L2_COLORSPACE_REC709 &&
- mp->colorspace != V4L2_COLORSPACE_SRGB)
+ } else if (mp->colorspace != V4L2_COLORSPACE_SMPTE170M &&
+ mp->colorspace != V4L2_COLORSPACE_REC709 &&
+ mp->colorspace != V4L2_COLORSPACE_ADOBERGB &&
+ mp->colorspace != V4L2_COLORSPACE_BT2020 &&
+ mp->colorspace != V4L2_COLORSPACE_SRGB) {
mp->colorspace = V4L2_COLORSPACE_REC709;
+ }
memset(mp->reserved, 0, sizeof(mp->reserved));
return 0;
}
@@ -522,6 +533,8 @@ int vivid_s_fmt_vid_out(struct file *file, void *priv,
set_colorspace:
dev->colorspace_out = mp->colorspace;
+ dev->ycbcr_enc_out = mp->ycbcr_enc;
+ dev->quantization_out = mp->quantization;
if (dev->loop_video) {
vivid_send_source_change(dev, SVID);
vivid_send_source_change(dev, HDMI);
diff --git a/drivers/media/platform/vsp1/vsp1_bru.c b/drivers/media/platform/vsp1/vsp1_bru.c
index a0c1984..b21f381 100644
--- a/drivers/media/platform/vsp1/vsp1_bru.c
+++ b/drivers/media/platform/vsp1/vsp1_bru.c
@@ -187,8 +187,8 @@ static int bru_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
- V4L2_MBUS_FMT_ARGB8888_1X32,
- V4L2_MBUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_AYUV8_1X32,
};
struct v4l2_mbus_framefmt *format;
@@ -215,8 +215,8 @@ static int bru_enum_frame_size(struct v4l2_subdev *subdev,
if (fse->index)
return -EINVAL;
- if (fse->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fse->code != V4L2_MBUS_FMT_AYUV8_1X32)
+ if (fse->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fse->code != MEDIA_BUS_FMT_AYUV8_1X32)
return -EINVAL;
fse->min_width = BRU_MIN_SIZE;
@@ -261,9 +261,9 @@ static void bru_try_format(struct vsp1_bru *bru, struct v4l2_subdev_fh *fh,
switch (pad) {
case BRU_PAD_SINK(0):
/* Default to YUV if the requested format is not supported. */
- if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
- fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
+ if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
+ fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
break;
default:
diff --git a/drivers/media/platform/vsp1/vsp1_hsit.c b/drivers/media/platform/vsp1/vsp1_hsit.c
index db2950a..80bedc5 100644
--- a/drivers/media/platform/vsp1/vsp1_hsit.c
+++ b/drivers/media/platform/vsp1/vsp1_hsit.c
@@ -70,9 +70,9 @@ static int hsit_enum_mbus_code(struct v4l2_subdev *subdev,
if ((code->pad == HSIT_PAD_SINK && !hsit->inverse) |
(code->pad == HSIT_PAD_SOURCE && hsit->inverse))
- code->code = V4L2_MBUS_FMT_ARGB8888_1X32;
+ code->code = MEDIA_BUS_FMT_ARGB8888_1X32;
else
- code->code = V4L2_MBUS_FMT_AHSV8888_1X32;
+ code->code = MEDIA_BUS_FMT_AHSV8888_1X32;
return 0;
}
@@ -136,8 +136,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
return 0;
}
- format->code = hsit->inverse ? V4L2_MBUS_FMT_AHSV8888_1X32
- : V4L2_MBUS_FMT_ARGB8888_1X32;
+ format->code = hsit->inverse ? MEDIA_BUS_FMT_AHSV8888_1X32
+ : MEDIA_BUS_FMT_ARGB8888_1X32;
format->width = clamp_t(unsigned int, fmt->format.width,
HSIT_MIN_SIZE, HSIT_MAX_SIZE);
format->height = clamp_t(unsigned int, fmt->format.height,
@@ -151,8 +151,8 @@ static int hsit_set_format(struct v4l2_subdev *subdev,
format = vsp1_entity_get_pad_format(&hsit->entity, fh, HSIT_PAD_SOURCE,
fmt->which);
*format = fmt->format;
- format->code = hsit->inverse ? V4L2_MBUS_FMT_ARGB8888_1X32
- : V4L2_MBUS_FMT_AHSV8888_1X32;
+ format->code = hsit->inverse ? MEDIA_BUS_FMT_ARGB8888_1X32
+ : MEDIA_BUS_FMT_AHSV8888_1X32;
return 0;
}
diff --git a/drivers/media/platform/vsp1/vsp1_lif.c b/drivers/media/platform/vsp1/vsp1_lif.c
index d4fb23e..17a6ca7 100644
--- a/drivers/media/platform/vsp1/vsp1_lif.c
+++ b/drivers/media/platform/vsp1/vsp1_lif.c
@@ -78,8 +78,8 @@ static int lif_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
- V4L2_MBUS_FMT_ARGB8888_1X32,
- V4L2_MBUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_AYUV8_1X32,
};
if (code->pad == LIF_PAD_SINK) {
@@ -147,9 +147,9 @@ static int lif_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
struct v4l2_mbus_framefmt *format;
/* Default to YUV if the requested format is not supported. */
- if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
- fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
+ if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
+ fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
format = vsp1_entity_get_pad_format(&lif->entity, fh, fmt->pad,
fmt->which);
diff --git a/drivers/media/platform/vsp1/vsp1_lut.c b/drivers/media/platform/vsp1/vsp1_lut.c
index fea36eb..6f185c3 100644
--- a/drivers/media/platform/vsp1/vsp1_lut.c
+++ b/drivers/media/platform/vsp1/vsp1_lut.c
@@ -86,9 +86,9 @@ static int lut_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
- V4L2_MBUS_FMT_ARGB8888_1X32,
- V4L2_MBUS_FMT_AHSV8888_1X32,
- V4L2_MBUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_AHSV8888_1X32,
+ MEDIA_BUS_FMT_AYUV8_1X32,
};
struct v4l2_mbus_framefmt *format;
@@ -158,10 +158,10 @@ static int lut_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
struct v4l2_mbus_framefmt *format;
/* Default to YUV if the requested format is not supported. */
- if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fmt->format.code != V4L2_MBUS_FMT_AHSV8888_1X32 &&
- fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
- fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
+ if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fmt->format.code != MEDIA_BUS_FMT_AHSV8888_1X32 &&
+ fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
+ fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
format = vsp1_entity_get_pad_format(&lut->entity, fh, fmt->pad,
fmt->which);
diff --git a/drivers/media/platform/vsp1/vsp1_rwpf.c b/drivers/media/platform/vsp1/vsp1_rwpf.c
index ec3dab6..1f1ba26 100644
--- a/drivers/media/platform/vsp1/vsp1_rwpf.c
+++ b/drivers/media/platform/vsp1/vsp1_rwpf.c
@@ -29,8 +29,8 @@ int vsp1_rwpf_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
- V4L2_MBUS_FMT_ARGB8888_1X32,
- V4L2_MBUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_AYUV8_1X32,
};
if (code->index >= ARRAY_SIZE(codes))
@@ -103,9 +103,9 @@ int vsp1_rwpf_set_format(struct v4l2_subdev *subdev, struct v4l2_subdev_fh *fh,
struct v4l2_rect *crop;
/* Default to YUV if the requested format is not supported. */
- if (fmt->format.code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fmt->format.code != V4L2_MBUS_FMT_AYUV8_1X32)
- fmt->format.code = V4L2_MBUS_FMT_AYUV8_1X32;
+ if (fmt->format.code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fmt->format.code != MEDIA_BUS_FMT_AYUV8_1X32)
+ fmt->format.code = MEDIA_BUS_FMT_AYUV8_1X32;
format = vsp1_entity_get_pad_format(&rwpf->entity, fh, fmt->pad,
fmt->which);
diff --git a/drivers/media/platform/vsp1/vsp1_sru.c b/drivers/media/platform/vsp1/vsp1_sru.c
index b7d3c8b..1129494 100644
--- a/drivers/media/platform/vsp1/vsp1_sru.c
+++ b/drivers/media/platform/vsp1/vsp1_sru.c
@@ -139,7 +139,7 @@ static int sru_s_stream(struct v4l2_subdev *subdev, int enable)
input = &sru->entity.formats[SRU_PAD_SINK];
output = &sru->entity.formats[SRU_PAD_SOURCE];
- if (input->code == V4L2_MBUS_FMT_ARGB8888_1X32)
+ if (input->code == MEDIA_BUS_FMT_ARGB8888_1X32)
ctrl0 = VI6_SRU_CTRL0_PARAM2 | VI6_SRU_CTRL0_PARAM3
| VI6_SRU_CTRL0_PARAM4;
else
@@ -170,8 +170,8 @@ static int sru_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
- V4L2_MBUS_FMT_ARGB8888_1X32,
- V4L2_MBUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_AYUV8_1X32,
};
struct v4l2_mbus_framefmt *format;
@@ -248,9 +248,9 @@ static void sru_try_format(struct vsp1_sru *sru, struct v4l2_subdev_fh *fh,
switch (pad) {
case SRU_PAD_SINK:
/* Default to YUV if the requested format is not supported. */
- if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
- fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
+ if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
+ fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
fmt->width = clamp(fmt->width, SRU_MIN_SIZE, SRU_MAX_SIZE);
fmt->height = clamp(fmt->height, SRU_MIN_SIZE, SRU_MAX_SIZE);
diff --git a/drivers/media/platform/vsp1/vsp1_uds.c b/drivers/media/platform/vsp1/vsp1_uds.c
index de92ef4..a4afec1 100644
--- a/drivers/media/platform/vsp1/vsp1_uds.c
+++ b/drivers/media/platform/vsp1/vsp1_uds.c
@@ -173,8 +173,8 @@ static int uds_enum_mbus_code(struct v4l2_subdev *subdev,
struct v4l2_subdev_mbus_code_enum *code)
{
static const unsigned int codes[] = {
- V4L2_MBUS_FMT_ARGB8888_1X32,
- V4L2_MBUS_FMT_AYUV8_1X32,
+ MEDIA_BUS_FMT_ARGB8888_1X32,
+ MEDIA_BUS_FMT_AYUV8_1X32,
};
if (code->pad == UDS_PAD_SINK) {
@@ -246,9 +246,9 @@ static void uds_try_format(struct vsp1_uds *uds, struct v4l2_subdev_fh *fh,
switch (pad) {
case UDS_PAD_SINK:
/* Default to YUV if the requested format is not supported. */
- if (fmt->code != V4L2_MBUS_FMT_ARGB8888_1X32 &&
- fmt->code != V4L2_MBUS_FMT_AYUV8_1X32)
- fmt->code = V4L2_MBUS_FMT_AYUV8_1X32;
+ if (fmt->code != MEDIA_BUS_FMT_ARGB8888_1X32 &&
+ fmt->code != MEDIA_BUS_FMT_AYUV8_1X32)
+ fmt->code = MEDIA_BUS_FMT_AYUV8_1X32;
fmt->width = clamp(fmt->width, UDS_MIN_SIZE, UDS_MAX_SIZE);
fmt->height = clamp(fmt->height, UDS_MIN_SIZE, UDS_MAX_SIZE);
diff --git a/drivers/media/platform/vsp1/vsp1_video.c b/drivers/media/platform/vsp1/vsp1_video.c
index 915a20e..d91f19a 100644
--- a/drivers/media/platform/vsp1/vsp1_video.c
+++ b/drivers/media/platform/vsp1/vsp1_video.c
@@ -48,85 +48,85 @@
*/
static const struct vsp1_format_info vsp1_video_formats[] = {
- { V4L2_PIX_FMT_RGB332, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_RGB332, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_332, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 8, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_ARGB444, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_ARGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XRGB444, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_XRGB444, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_XRGB_4444, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_ARGB555, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_ARGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XRGB555, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_XRGB555, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_XRGB_1555, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_RGB565, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_RGB565, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_565, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS,
1, { 16, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_BGR24, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_BGR24, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_BGR_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 24, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_RGB24, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_RGB24, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_RGB_888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 24, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_ABGR32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_ABGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XBGR32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_XBGR32, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_ARGB32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_ARGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 32, 0, 0 }, false, false, 1, 1, true },
- { V4L2_PIX_FMT_XRGB32, V4L2_MBUS_FMT_ARGB8888_1X32,
+ { V4L2_PIX_FMT_XRGB32, MEDIA_BUS_FMT_ARGB8888_1X32,
VI6_FMT_ARGB_8888, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 32, 0, 0 }, false, false, 1, 1, false },
- { V4L2_PIX_FMT_UYVY, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_UYVY, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 16, 0, 0 }, false, false, 2, 1, false },
- { V4L2_PIX_FMT_VYUY, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_VYUY, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 16, 0, 0 }, false, true, 2, 1, false },
- { V4L2_PIX_FMT_YUYV, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_YUYV, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 16, 0, 0 }, true, false, 2, 1, false },
- { V4L2_PIX_FMT_YVYU, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_YVYU, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_YUYV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
1, { 16, 0, 0 }, true, true, 2, 1, false },
- { V4L2_PIX_FMT_NV12M, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_NV12M, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
2, { 8, 16, 0 }, false, false, 2, 2, false },
- { V4L2_PIX_FMT_NV21M, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_NV21M, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
2, { 8, 16, 0 }, false, true, 2, 2, false },
- { V4L2_PIX_FMT_NV16M, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_NV16M, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
2, { 8, 16, 0 }, false, false, 2, 1, false },
- { V4L2_PIX_FMT_NV61M, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_NV61M, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_Y_UV_422, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
2, { 8, 16, 0 }, false, true, 2, 1, false },
- { V4L2_PIX_FMT_YUV420M, V4L2_MBUS_FMT_AYUV8_1X32,
+ { V4L2_PIX_FMT_YUV420M, MEDIA_BUS_FMT_AYUV8_1X32,
VI6_FMT_Y_U_V_420, VI6_RPF_DSWAP_P_LLS | VI6_RPF_DSWAP_P_LWS |
VI6_RPF_DSWAP_P_WDS | VI6_RPF_DSWAP_P_BTS,
3, { 8, 8, 8 }, false, false, 2, 2, false },
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
index 9cf6731..284f789 100644
--- a/drivers/media/radio/radio-wl1273.c
+++ b/drivers/media/radio/radio-wl1273.c
@@ -1279,10 +1279,12 @@ static int wl1273_fm_vidioc_querycap(struct file *file, void *priv,
strlcpy(capability->bus_info, radio->bus_type,
sizeof(capability->bus_info));
- capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+ capability->device_caps = V4L2_CAP_HW_FREQ_SEEK |
V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO |
V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR |
V4L2_CAP_RDS_OUTPUT;
+ capability->capabilities = capability->device_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/radio/si4713/radio-platform-si4713.c b/drivers/media/radio/si4713/radio-platform-si4713.c
index a47502a..2de5439 100644
--- a/drivers/media/radio/si4713/radio-platform-si4713.c
+++ b/drivers/media/radio/si4713/radio-platform-si4713.c
@@ -34,7 +34,7 @@
#include <media/v4l2-fh.h>
#include <media/v4l2-ctrls.h>
#include <media/v4l2-event.h>
-#include <media/radio-si4713.h>
+#include "si4713.h"
/* module parameters */
static int radio_nr = -1; /* radio device minor (-1 ==> auto assign) */
@@ -153,7 +153,6 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
{
struct radio_si4713_platform_data *pdata = pdev->dev.platform_data;
struct radio_si4713_device *rsdev;
- struct i2c_adapter *adapter;
struct v4l2_subdev *sd;
int rval = 0;
@@ -177,20 +176,11 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
goto exit;
}
- adapter = i2c_get_adapter(pdata->i2c_bus);
- if (!adapter) {
- dev_err(&pdev->dev, "Cannot get i2c adapter %d\n",
- pdata->i2c_bus);
- rval = -ENODEV;
- goto unregister_v4l2_dev;
- }
-
- sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
- pdata->subdev_board_info, NULL);
- if (!sd) {
+ sd = i2c_get_clientdata(pdata->subdev);
+ rval = v4l2_device_register_subdev(&rsdev->v4l2_dev, sd);
+ if (rval) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
- rval = -ENODEV;
- goto put_adapter;
+ goto unregister_v4l2_dev;
}
rsdev->radio_dev = radio_si4713_vdev_template;
@@ -202,14 +192,12 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
if (video_register_device(&rsdev->radio_dev, VFL_TYPE_RADIO, radio_nr)) {
dev_err(&pdev->dev, "Could not register video device.\n");
rval = -EIO;
- goto put_adapter;
+ goto unregister_v4l2_dev;
}
dev_info(&pdev->dev, "New device successfully probed\n");
goto exit;
-put_adapter:
- i2c_put_adapter(adapter);
unregister_v4l2_dev:
v4l2_device_unregister(&rsdev->v4l2_dev);
exit:
@@ -220,14 +208,10 @@ exit:
static int radio_si4713_pdriver_remove(struct platform_device *pdev)
{
struct v4l2_device *v4l2_dev = platform_get_drvdata(pdev);
- struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
- struct v4l2_subdev, list);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
struct radio_si4713_device *rsdev;
rsdev = container_of(v4l2_dev, struct radio_si4713_device, v4l2_dev);
video_unregister_device(&rsdev->radio_dev);
- i2c_put_adapter(client->adapter);
v4l2_device_unregister(&rsdev->v4l2_dev);
return 0;
diff --git a/drivers/media/radio/si4713/si4713.c b/drivers/media/radio/si4713/si4713.c
index b576555..c90004d 100644
--- a/drivers/media/radio/si4713/si4713.c
+++ b/drivers/media/radio/si4713/si4713.c
@@ -23,6 +23,7 @@
#include <linux/completion.h>
#include <linux/delay.h>
+#include <linux/err.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -366,16 +367,25 @@ static int si4713_powerup(struct si4713_device *sdev)
if (sdev->power_state)
return 0;
- if (sdev->supplies) {
- err = regulator_bulk_enable(sdev->supplies, sdev->supply_data);
+ if (sdev->vdd) {
+ err = regulator_enable(sdev->vdd);
if (err) {
- v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err);
+ v4l2_err(&sdev->sd, "Failed to enable vdd: %d\n", err);
return err;
}
}
- if (gpio_is_valid(sdev->gpio_reset)) {
+
+ if (sdev->vio) {
+ err = regulator_enable(sdev->vio);
+ if (err) {
+ v4l2_err(&sdev->sd, "Failed to enable vio: %d\n", err);
+ return err;
+ }
+ }
+
+ if (!IS_ERR(sdev->gpio_reset)) {
udelay(50);
- gpio_set_value(sdev->gpio_reset, 1);
+ gpiod_set_value(sdev->gpio_reset, 1);
}
if (client->irq)
@@ -397,13 +407,20 @@ static int si4713_powerup(struct si4713_device *sdev)
SI4713_STC_INT | SI4713_CTS);
return err;
}
- if (gpio_is_valid(sdev->gpio_reset))
- gpio_set_value(sdev->gpio_reset, 0);
- if (sdev->supplies) {
- err = regulator_bulk_disable(sdev->supplies, sdev->supply_data);
+ if (!IS_ERR(sdev->gpio_reset))
+ gpiod_set_value(sdev->gpio_reset, 0);
+
+
+ if (sdev->vdd) {
+ err = regulator_disable(sdev->vdd);
if (err)
- v4l2_err(&sdev->sd,
- "Failed to disable supplies: %d\n", err);
+ v4l2_err(&sdev->sd, "Failed to disable vdd: %d\n", err);
+ }
+
+ if (sdev->vio) {
+ err = regulator_disable(sdev->vio);
+ if (err)
+ v4l2_err(&sdev->sd, "Failed to disable vio: %d\n", err);
}
return err;
@@ -430,14 +447,23 @@ static int si4713_powerdown(struct si4713_device *sdev)
v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
resp[0]);
v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
- if (gpio_is_valid(sdev->gpio_reset))
- gpio_set_value(sdev->gpio_reset, 0);
- if (sdev->supplies) {
- err = regulator_bulk_disable(sdev->supplies,
- sdev->supply_data);
- if (err)
+ if (!IS_ERR(sdev->gpio_reset))
+ gpiod_set_value(sdev->gpio_reset, 0);
+
+ if (sdev->vdd) {
+ err = regulator_disable(sdev->vdd);
+ if (err) {
v4l2_err(&sdev->sd,
- "Failed to disable supplies: %d\n", err);
+ "Failed to disable vdd: %d\n", err);
+ }
+ }
+
+ if (sdev->vio) {
+ err = regulator_disable(sdev->vio);
+ if (err) {
+ v4l2_err(&sdev->sd,
+ "Failed to disable vio: %d\n", err);
+ }
}
sdev->power_state = POWER_OFF;
}
@@ -1420,38 +1446,51 @@ static int si4713_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct si4713_device *sdev;
- struct si4713_platform_data *pdata = client->dev.platform_data;
struct v4l2_ctrl_handler *hdl;
- int rval, i;
+ struct si4713_platform_data *pdata = client->dev.platform_data;
+ struct device_node *np = client->dev.of_node;
+ struct radio_si4713_platform_data si4713_pdev_pdata;
+ struct platform_device *si4713_pdev;
+ int rval;
- sdev = kzalloc(sizeof(*sdev), GFP_KERNEL);
+ sdev = devm_kzalloc(&client->dev, sizeof(*sdev), GFP_KERNEL);
if (!sdev) {
dev_err(&client->dev, "Failed to alloc video device.\n");
rval = -ENOMEM;
goto exit;
}
- sdev->gpio_reset = -1;
- if (pdata && gpio_is_valid(pdata->gpio_reset)) {
- rval = gpio_request(pdata->gpio_reset, "si4713 reset");
- if (rval) {
- dev_err(&client->dev,
- "Failed to request gpio: %d\n", rval);
- goto free_sdev;
- }
- sdev->gpio_reset = pdata->gpio_reset;
- gpio_direction_output(sdev->gpio_reset, 0);
- sdev->supplies = pdata->supplies;
+ sdev->gpio_reset = devm_gpiod_get(&client->dev, "reset");
+ if (!IS_ERR(sdev->gpio_reset)) {
+ gpiod_direction_output(sdev->gpio_reset, 0);
+ } else if (PTR_ERR(sdev->gpio_reset) == -ENOENT) {
+ dev_dbg(&client->dev, "No reset GPIO assigned\n");
+ } else if (PTR_ERR(sdev->gpio_reset) == -ENOSYS) {
+ dev_dbg(&client->dev, "No reset GPIO support\n");
+ } else {
+ rval = PTR_ERR(sdev->gpio_reset);
+ dev_err(&client->dev, "Failed to request gpio: %d\n", rval);
+ goto exit;
}
- for (i = 0; i < sdev->supplies; i++)
- sdev->supply_data[i].supply = pdata->supply_names[i];
+ sdev->vdd = devm_regulator_get_optional(&client->dev, "vdd");
+ if (IS_ERR(sdev->vdd)) {
+ rval = PTR_ERR(sdev->vdd);
+ if (rval == -EPROBE_DEFER)
+ goto exit;
- rval = regulator_bulk_get(&client->dev, sdev->supplies,
- sdev->supply_data);
- if (rval) {
- dev_err(&client->dev, "Cannot get regulators: %d\n", rval);
- goto free_gpio;
+ dev_dbg(&client->dev, "no vdd regulator found: %d\n", rval);
+ sdev->vdd = NULL;
+ }
+
+ sdev->vio = devm_regulator_get_optional(&client->dev, "vio");
+ if (IS_ERR(sdev->vio)) {
+ rval = PTR_ERR(sdev->vio);
+ if (rval == -EPROBE_DEFER)
+ goto exit;
+
+ dev_dbg(&client->dev, "no vio regulator found: %d\n", rval);
+ sdev->vio = NULL;
}
v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops);
@@ -1554,12 +1593,12 @@ static int si4713_probe(struct i2c_client *client,
sdev->sd.ctrl_handler = hdl;
if (client->irq) {
- rval = request_irq(client->irq,
+ rval = devm_request_irq(&client->dev, client->irq,
si4713_handler, IRQF_TRIGGER_FALLING,
client->name, sdev);
if (rval < 0) {
v4l2_err(&sdev->sd, "Could not request IRQ\n");
- goto put_reg;
+ goto free_ctrls;
}
v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n");
} else {
@@ -1569,23 +1608,35 @@ static int si4713_probe(struct i2c_client *client,
rval = si4713_initialize(sdev);
if (rval < 0) {
v4l2_err(&sdev->sd, "Failed to probe device information.\n");
- goto free_irq;
+ goto free_ctrls;
}
+ if (!np && (!pdata || !pdata->is_platform_device))
+ return 0;
+
+ si4713_pdev = platform_device_alloc("radio-si4713", -1);
+ if (!si4713_pdev)
+ goto put_main_pdev;
+
+ si4713_pdev_pdata.subdev = client;
+ rval = platform_device_add_data(si4713_pdev, &si4713_pdev_pdata,
+ sizeof(si4713_pdev_pdata));
+ if (rval)
+ goto put_main_pdev;
+
+ rval = platform_device_add(si4713_pdev);
+ if (rval)
+ goto put_main_pdev;
+
+ sdev->pd = si4713_pdev;
+
return 0;
-free_irq:
- if (client->irq)
- free_irq(client->irq, sdev);
+put_main_pdev:
+ platform_device_put(si4713_pdev);
+ v4l2_device_unregister_subdev(&sdev->sd);
free_ctrls:
v4l2_ctrl_handler_free(hdl);
-put_reg:
- regulator_bulk_free(sdev->supplies, sdev->supply_data);
-free_gpio:
- if (gpio_is_valid(sdev->gpio_reset))
- gpio_free(sdev->gpio_reset);
-free_sdev:
- kfree(sdev);
exit:
return rval;
}
@@ -1596,18 +1647,13 @@ static int si4713_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
struct si4713_device *sdev = to_si4713_device(sd);
+ platform_device_unregister(sdev->pd);
+
if (sdev->power_state)
si4713_set_power_state(sdev, POWER_DOWN);
- if (client->irq > 0)
- free_irq(client->irq, sdev);
-
v4l2_device_unregister_subdev(sd);
v4l2_ctrl_handler_free(sd->ctrl_handler);
- regulator_bulk_free(sdev->supplies, sdev->supply_data);
- if (gpio_is_valid(sdev->gpio_reset))
- gpio_free(sdev->gpio_reset);
- kfree(sdev);
return 0;
}
diff --git a/drivers/media/radio/si4713/si4713.h b/drivers/media/radio/si4713/si4713.h
index ed700e3..8a376e1 100644
--- a/drivers/media/radio/si4713/si4713.h
+++ b/drivers/media/radio/si4713/si4713.h
@@ -15,7 +15,9 @@
#ifndef SI4713_I2C_H
#define SI4713_I2C_H
+#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
+#include <linux/gpio/consumer.h>
#include <media/v4l2-subdev.h>
#include <media/v4l2-ctrls.h>
#include <media/si4713.h>
@@ -190,8 +192,6 @@
#define MIN_ACOMP_THRESHOLD (-40)
#define MAX_ACOMP_GAIN 20
-#define SI4713_NUM_SUPPLIES 2
-
/*
* si4713_device - private data
*/
@@ -236,9 +236,10 @@ struct si4713_device {
struct v4l2_ctrl *tune_ant_cap;
};
struct completion work;
- unsigned supplies;
- struct regulator_bulk_data supply_data[SI4713_NUM_SUPPLIES];
- int gpio_reset;
+ struct regulator *vdd;
+ struct regulator *vio;
+ struct gpio_desc *gpio_reset;
+ struct platform_device *pd;
u32 power_state;
u32 rds_enabled;
u32 frequency;
@@ -246,4 +247,8 @@ struct si4713_device {
u32 stereo;
u32 tune_rnl;
};
+
+struct radio_si4713_platform_data {
+ struct i2c_client *subdev;
+};
#endif /* ifndef SI4713_I2C_H */
diff --git a/drivers/media/radio/wl128x/fmdrv_v4l2.c b/drivers/media/radio/wl128x/fmdrv_v4l2.c
index b55012c..a5bd3f6 100644
--- a/drivers/media/radio/wl128x/fmdrv_v4l2.c
+++ b/drivers/media/radio/wl128x/fmdrv_v4l2.c
@@ -198,10 +198,12 @@ static int fm_v4l2_vidioc_querycap(struct file *file, void *priv,
strlcpy(capability->card, FM_DRV_CARD_SHORT_NAME,
sizeof(capability->card));
sprintf(capability->bus_info, "UART");
- capability->capabilities = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
+ capability->device_caps = V4L2_CAP_HW_FREQ_SEEK | V4L2_CAP_TUNER |
V4L2_CAP_RADIO | V4L2_CAP_MODULATOR |
V4L2_CAP_AUDIO | V4L2_CAP_READWRITE |
V4L2_CAP_RDS_CAPTURE;
+ capability->capabilities = capability->device_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
index 8ce0810..ddfab25 100644
--- a/drivers/media/rc/Kconfig
+++ b/drivers/media/rc/Kconfig
@@ -223,6 +223,17 @@ config IR_FINTEK
To compile this driver as a module, choose M here: the
module will be called fintek-cir.
+config IR_MESON
+ tristate "Amlogic Meson IR remote receiver"
+ depends on RC_CORE
+ depends on ARCH_MESON || COMPILE_TEST
+ ---help---
+ Say Y if you want to use the IR remote receiver available
+ on Amlogic Meson SoCs.
+
+ To compile this driver as a module, choose M here: the
+ module will be called meson-ir.
+
config IR_NUVOTON
tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
depends on PNP
@@ -277,6 +288,21 @@ config IR_WINBOND_CIR
To compile this driver as a module, choose M here: the module will
be called winbond_cir.
+config IR_IGORPLUGUSB
+ tristate "IgorPlug-USB IR Receiver"
+ depends on USB_ARCH_HAS_HCD
+ depends on RC_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use the IgorPlug-USB IR Receiver by
+ Igor Cesko. This device is included on the Fit-PC2.
+
+ Note that this device can only record bursts of 36 IR pulses and
+ spaces, which is not enough for the NEC, Sanyo and RC-6 protocol.
+
+ To compile this driver as a module, choose M here: the module will
+ be called igorplugusb.
+
config IR_IGUANA
tristate "IguanaWorks USB IR Transceiver"
depends on USB_ARCH_HAS_HCD
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
index 0989f94..379a5c0 100644
--- a/drivers/media/rc/Makefile
+++ b/drivers/media/rc/Makefile
@@ -22,6 +22,7 @@ obj-$(CONFIG_IR_IMON) += imon.o
obj-$(CONFIG_IR_ITE_CIR) += ite-cir.o
obj-$(CONFIG_IR_MCEUSB) += mceusb.o
obj-$(CONFIG_IR_FINTEK) += fintek-cir.o
+obj-$(CONFIG_IR_MESON) += meson-ir.o
obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
obj-$(CONFIG_IR_ENE) += ene_ir.o
obj-$(CONFIG_IR_REDRAT3) += redrat3.o
@@ -30,6 +31,7 @@ obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
obj-$(CONFIG_IR_GPIO_CIR) += gpio-ir-recv.o
+obj-$(CONFIG_IR_IGORPLUGUSB) += igorplugusb.o
obj-$(CONFIG_IR_IGUANA) += iguanair.o
obj-$(CONFIG_IR_TTUSBIR) += ttusbir.o
obj-$(CONFIG_RC_ST) += st_rc.o
diff --git a/drivers/media/rc/igorplugusb.c b/drivers/media/rc/igorplugusb.c
new file mode 100644
index 0000000..b36e515
--- /dev/null
+++ b/drivers/media/rc/igorplugusb.c
@@ -0,0 +1,261 @@
+/*
+ * IgorPlug-USB IR Receiver
+ *
+ * Copyright (C) 2014 Sean Young <sean@mess.org>
+ *
+ * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
+ * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
+ *
+ * Based on the lirc_igorplugusb.c driver:
+ * Copyright (C) 2004 Jan M. Hochstein
+ * <hochstein@algo.informatik.tu-darmstadt.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/device.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#define DRIVER_DESC "IgorPlug-USB IR Receiver"
+#define DRIVER_NAME "igorplugusb"
+
+#define HEADERLEN 3
+#define BUFLEN 36
+#define MAX_PACKET (HEADERLEN + BUFLEN)
+
+#define SET_INFRABUFFER_EMPTY 1
+#define GET_INFRACODE 2
+
+
+struct igorplugusb {
+ struct rc_dev *rc;
+ struct device *dev;
+
+ struct urb *urb;
+ struct usb_ctrlrequest request;
+
+ struct timer_list timer;
+
+ uint8_t buf_in[MAX_PACKET];
+
+ char phys[64];
+};
+
+static void igorplugusb_cmd(struct igorplugusb *ir, int cmd);
+
+static void igorplugusb_irdata(struct igorplugusb *ir, unsigned len)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ unsigned i, start, overflow;
+
+ dev_dbg(ir->dev, "irdata: %*ph (len=%u)", len, ir->buf_in, len);
+
+ /*
+ * If more than 36 pulses and spaces follow each other, the igorplugusb
+ * overwrites its buffer from the beginning. The overflow value is the
+ * last offset which was not overwritten. Everything from this offset
+ * onwards occurred before everything until this offset.
+ */
+ overflow = ir->buf_in[2];
+ i = start = overflow + HEADERLEN;
+
+ if (start >= len) {
+ dev_err(ir->dev, "receive overflow invalid: %u", overflow);
+ } else {
+ if (overflow > 0)
+ dev_warn(ir->dev, "receive overflow, at least %u lost",
+ overflow);
+
+ do {
+ rawir.duration = ir->buf_in[i] * 85333;
+ rawir.pulse = i & 1;
+
+ ir_raw_event_store_with_filter(ir->rc, &rawir);
+
+ if (++i == len)
+ i = HEADERLEN;
+ } while (i != start);
+
+ /* add a trailing space */
+ rawir.duration = ir->rc->timeout;
+ rawir.pulse = false;
+ ir_raw_event_store_with_filter(ir->rc, &rawir);
+
+ ir_raw_event_handle(ir->rc);
+ }
+
+ igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
+}
+
+static void igorplugusb_callback(struct urb *urb)
+{
+ struct usb_ctrlrequest *req;
+ struct igorplugusb *ir = urb->context;
+
+ req = (struct usb_ctrlrequest *)urb->setup_packet;
+
+ switch (urb->status) {
+ case 0:
+ if (req->bRequest == GET_INFRACODE &&
+ urb->actual_length > HEADERLEN)
+ igorplugusb_irdata(ir, urb->actual_length);
+ else /* request IR */
+ mod_timer(&ir->timer, jiffies + msecs_to_jiffies(50));
+ break;
+ case -EPROTO:
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+ default:
+ dev_warn(ir->dev, "Error: urb status = %d\n", urb->status);
+ igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
+ break;
+ }
+}
+
+static void igorplugusb_cmd(struct igorplugusb *ir, int cmd)
+{
+ int ret;
+
+ ir->request.bRequest = cmd;
+ ir->urb->transfer_flags = 0;
+ ret = usb_submit_urb(ir->urb, GFP_ATOMIC);
+ if (ret)
+ dev_err(ir->dev, "submit urb failed: %d", ret);
+}
+
+static void igorplugusb_timer(unsigned long data)
+{
+ struct igorplugusb *ir = (struct igorplugusb *)data;
+
+ igorplugusb_cmd(ir, GET_INFRACODE);
+}
+
+static int igorplugusb_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev;
+ struct usb_host_interface *idesc;
+ struct usb_endpoint_descriptor *ep;
+ struct igorplugusb *ir;
+ struct rc_dev *rc;
+ int ret;
+
+ udev = interface_to_usbdev(intf);
+ idesc = intf->cur_altsetting;
+
+ if (idesc->desc.bNumEndpoints != 1) {
+ dev_err(&intf->dev, "incorrect number of endpoints");
+ return -ENODEV;
+ }
+
+ ep = &idesc->endpoint[0].desc;
+ if (!usb_endpoint_dir_in(ep) || !usb_endpoint_xfer_control(ep)) {
+ dev_err(&intf->dev, "endpoint incorrect");
+ return -ENODEV;
+ }
+
+ ir = devm_kzalloc(&intf->dev, sizeof(*ir), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
+
+ ir->dev = &intf->dev;
+
+ setup_timer(&ir->timer, igorplugusb_timer, (unsigned long)ir);
+
+ ir->request.bRequest = GET_INFRACODE;
+ ir->request.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN;
+ ir->request.wLength = cpu_to_le16(sizeof(ir->buf_in));
+
+ ir->urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ir->urb)
+ return -ENOMEM;
+
+ usb_fill_control_urb(ir->urb, udev,
+ usb_rcvctrlpipe(udev, 0), (uint8_t *)&ir->request,
+ ir->buf_in, sizeof(ir->buf_in), igorplugusb_callback, ir);
+
+ usb_make_path(udev, ir->phys, sizeof(ir->phys));
+
+ rc = rc_allocate_device();
+ rc->input_name = DRIVER_DESC;
+ rc->input_phys = ir->phys;
+ usb_to_input_id(udev, &rc->input_id);
+ rc->dev.parent = &intf->dev;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ /*
+ * This device can only store 36 pulses + spaces, which is not enough
+ * for the NEC protocol and many others.
+ */
+ rc->allowed_protocols = RC_BIT_ALL & ~(RC_BIT_NEC | RC_BIT_RC6_6A_20 |
+ RC_BIT_RC6_6A_24 | RC_BIT_RC6_6A_32 | RC_BIT_RC6_MCE |
+ RC_BIT_SONY20 | RC_BIT_MCE_KBD | RC_BIT_SANYO);
+
+ rc->priv = ir;
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = RC_MAP_HAUPPAUGE;
+ rc->timeout = MS_TO_NS(100);
+ rc->rx_resolution = 85333;
+
+ ir->rc = rc;
+ ret = rc_register_device(rc);
+ if (ret) {
+ dev_err(&intf->dev, "failed to register rc device: %d", ret);
+ rc_free_device(rc);
+ usb_free_urb(ir->urb);
+ return ret;
+ }
+
+ usb_set_intfdata(intf, ir);
+
+ igorplugusb_cmd(ir, SET_INFRABUFFER_EMPTY);
+
+ return 0;
+}
+
+static void igorplugusb_disconnect(struct usb_interface *intf)
+{
+ struct igorplugusb *ir = usb_get_intfdata(intf);
+
+ rc_unregister_device(ir->rc);
+ del_timer_sync(&ir->timer);
+ usb_set_intfdata(intf, NULL);
+ usb_kill_urb(ir->urb);
+ usb_free_urb(ir->urb);
+}
+
+static struct usb_device_id igorplugusb_table[] = {
+ /* Igor Plug USB (Atmel's Manufact. ID) */
+ { USB_DEVICE(0x03eb, 0x0002) },
+ /* Fit PC2 Infrared Adapter */
+ { USB_DEVICE(0x03eb, 0x21fe) },
+ /* Terminating entry */
+ { }
+};
+
+static struct usb_driver igorplugusb_driver = {
+ .name = DRIVER_NAME,
+ .probe = igorplugusb_probe,
+ .disconnect = igorplugusb_disconnect,
+ .id_table = igorplugusb_table
+};
+
+module_usb_driver(igorplugusb_driver);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR("Sean Young <sean@mess.org>");
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, igorplugusb_table);
diff --git a/drivers/media/rc/img-ir/Kconfig b/drivers/media/rc/img-ir/Kconfig
index 03ba9fc..580715c 100644
--- a/drivers/media/rc/img-ir/Kconfig
+++ b/drivers/media/rc/img-ir/Kconfig
@@ -1,6 +1,7 @@
config IR_IMG
tristate "ImgTec IR Decoder"
depends on RC_CORE
+ depends on METAG || MIPS || COMPILE_TEST
select IR_IMG_HW if !IR_IMG_RAW
help
Say Y or M here if you want to use the ImgTec infrared decoder
diff --git a/drivers/media/rc/img-ir/img-ir-core.c b/drivers/media/rc/img-ir/img-ir-core.c
index a0cac2f..77c78de 100644
--- a/drivers/media/rc/img-ir/img-ir-core.c
+++ b/drivers/media/rc/img-ir/img-ir-core.c
@@ -166,7 +166,6 @@ MODULE_DEVICE_TABLE(of, img_ir_match);
static struct platform_driver img_ir_driver = {
.driver = {
.name = "img-ir",
- .owner = THIS_MODULE,
.of_match_table = img_ir_match,
.pm = &img_ir_pmops,
},
diff --git a/drivers/media/rc/img-ir/img-ir-hw.c b/drivers/media/rc/img-ir/img-ir-hw.c
index ec49f94..2fd47c9 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.c
+++ b/drivers/media/rc/img-ir/img-ir-hw.c
@@ -530,6 +530,22 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
u32 ir_status, irq_en;
spin_lock_irq(&priv->lock);
+ /*
+ * First record that the protocol is being stopped so that the end timer
+ * isn't restarted while we're trying to stop it.
+ */
+ hw->stopping = true;
+
+ /*
+ * Release the lock to stop the end timer, since the end timer handler
+ * acquires the lock and we don't want to deadlock waiting for it.
+ */
+ spin_unlock_irq(&priv->lock);
+ del_timer_sync(&hw->end_timer);
+ spin_lock_irq(&priv->lock);
+
+ hw->stopping = false;
+
/* switch off and disable interrupts */
img_ir_write(priv, IMG_IR_CONTROL, 0);
irq_en = img_ir_read(priv, IMG_IR_IRQ_ENABLE);
@@ -541,12 +557,13 @@ static void img_ir_set_decoder(struct img_ir_priv *priv,
if (ir_status & (IMG_IR_RXDVAL | IMG_IR_RXDVALD2)) {
ir_status &= ~(IMG_IR_RXDVAL | IMG_IR_RXDVALD2);
img_ir_write(priv, IMG_IR_STATUS, ir_status);
- img_ir_read(priv, IMG_IR_DATA_LW);
- img_ir_read(priv, IMG_IR_DATA_UP);
}
- /* stop the end timer and switch back to normal mode */
- del_timer_sync(&hw->end_timer);
+ /* always read data to clear buffer if IR wakes the device */
+ img_ir_read(priv, IMG_IR_DATA_LW);
+ img_ir_read(priv, IMG_IR_DATA_UP);
+
+ /* switch back to normal mode */
hw->mode = IMG_IR_M_NORMAL;
/* clear the wakeup scancode filter */
@@ -817,7 +834,8 @@ static void img_ir_handle_data(struct img_ir_priv *priv, u32 len, u64 raw)
}
- if (dec->repeat) {
+ /* we mustn't update the end timer while trying to stop it */
+ if (dec->repeat && !hw->stopping) {
unsigned long interval;
img_ir_begin_repeat(priv);
diff --git a/drivers/media/rc/img-ir/img-ir-hw.h b/drivers/media/rc/img-ir/img-ir-hw.h
index 8fcc16c..5c2b216 100644
--- a/drivers/media/rc/img-ir/img-ir-hw.h
+++ b/drivers/media/rc/img-ir/img-ir-hw.h
@@ -186,9 +186,6 @@ struct img_ir_reg_timings {
struct img_ir_timing_regvals rtimings;
};
-int img_ir_register_decoder(struct img_ir_decoder *dec);
-void img_ir_unregister_decoder(struct img_ir_decoder *dec);
-
struct img_ir_priv;
#ifdef CONFIG_IR_IMG_HW
@@ -214,6 +211,8 @@ enum img_ir_mode {
* @flags: IMG_IR_F_*.
* @filters: HW filters (derived from scancode filters).
* @mode: Current decode mode.
+ * @stopping: Indicates that decoder is being taken down and timers
+ * should not be restarted.
* @suspend_irqen: Saved IRQ enable mask over suspend.
*/
struct img_ir_priv_hw {
@@ -229,6 +228,7 @@ struct img_ir_priv_hw {
struct img_ir_filter filters[RC_FILTER_MAX];
enum img_ir_mode mode;
+ bool stopping;
u32 suspend_irqen;
};
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
index ed2c8a1..98893a8 100644
--- a/drivers/media/rc/ir-lirc-codec.c
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -42,11 +42,17 @@ static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
return -EINVAL;
/* Packet start */
- if (ev.reset)
- return 0;
+ if (ev.reset) {
+ /* Userspace expects a long space event before the start of
+ * the signal to use as a sync. This may be done with repeat
+ * packets and normal samples. But if a reset has been sent
+ * then we assume that a long time has passed, so we send a
+ * space with the maximum time value. */
+ sample = LIRC_SPACE(LIRC_VALUE_MASK);
+ IR_dprintk(2, "delivering reset sync space to lirc_dev\n");
/* Carrier reports */
- if (ev.carrier_report) {
+ } else if (ev.carrier_report) {
sample = LIRC_FREQUENCY(ev.carrier);
IR_dprintk(2, "carrier report (freq: %d)\n", sample);
diff --git a/drivers/media/rc/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index f1f098e..d16bc67 100644
--- a/drivers/media/rc/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -259,8 +259,8 @@ again:
case 32:
if ((scancode & RC6_6A_LCC_MASK) == RC6_6A_MCE_CC) {
protocol = RC_TYPE_RC6_MCE;
- scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
toggle = !!(scancode & RC6_6A_MCE_TOGGLE_MASK);
+ scancode &= ~RC6_6A_MCE_TOGGLE_MASK;
} else {
protocol = RC_BIT_RC6_6A_32;
toggle = 0;
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
index 249d2fb..1e0545a6 100644
--- a/drivers/media/rc/lirc_dev.c
+++ b/drivers/media/rc/lirc_dev.c
@@ -518,8 +518,7 @@ int lirc_dev_fop_close(struct inode *inode, struct file *file)
WARN_ON(mutex_lock_killable(&lirc_dev_lock));
- if (ir->d.rdev)
- rc_close(ir->d.rdev);
+ rc_close(ir->d.rdev);
ir->open--;
if (ir->attached) {
diff --git a/drivers/media/rc/meson-ir.c b/drivers/media/rc/meson-ir.c
new file mode 100644
index 0000000..fcc3b82
--- /dev/null
+++ b/drivers/media/rc/meson-ir.c
@@ -0,0 +1,216 @@
+/*
+ * Driver for Amlogic Meson IR remote receiver
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@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.
+ *
+ * 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/device.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/spinlock.h>
+
+#include <media/rc-core.h>
+
+#define DRIVER_NAME "meson-ir"
+
+#define IR_DEC_LDR_ACTIVE 0x00
+#define IR_DEC_LDR_IDLE 0x04
+#define IR_DEC_LDR_REPEAT 0x08
+#define IR_DEC_BIT_0 0x0c
+#define IR_DEC_REG0 0x10
+#define IR_DEC_FRAME 0x14
+#define IR_DEC_STATUS 0x18
+#define IR_DEC_REG1 0x1c
+
+#define REG0_RATE_MASK (BIT(11) - 1)
+
+#define REG1_MODE_MASK (BIT(7) | BIT(8))
+#define REG1_MODE_NEC (0 << 7)
+#define REG1_MODE_GENERAL (2 << 7)
+
+#define REG1_TIME_IV_SHIFT 16
+#define REG1_TIME_IV_MASK ((BIT(13) - 1) << REG1_TIME_IV_SHIFT)
+
+#define REG1_IRQSEL_MASK (BIT(2) | BIT(3))
+#define REG1_IRQSEL_NEC_MODE (0 << 2)
+#define REG1_IRQSEL_RISE_FALL (1 << 2)
+#define REG1_IRQSEL_FALL (2 << 2)
+#define REG1_IRQSEL_RISE (3 << 2)
+
+#define REG1_RESET BIT(0)
+#define REG1_ENABLE BIT(15)
+
+#define STATUS_IR_DEC_IN BIT(8)
+
+#define MESON_TRATE 10 /* us */
+
+struct meson_ir {
+ void __iomem *reg;
+ struct rc_dev *rc;
+ int irq;
+ spinlock_t lock;
+};
+
+static void meson_ir_set_mask(struct meson_ir *ir, unsigned int reg,
+ u32 mask, u32 value)
+{
+ u32 data;
+
+ data = readl(ir->reg + reg);
+ data &= ~mask;
+ data |= (value & mask);
+ writel(data, ir->reg + reg);
+}
+
+static irqreturn_t meson_ir_irq(int irqno, void *dev_id)
+{
+ struct meson_ir *ir = dev_id;
+ u32 duration;
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ spin_lock(&ir->lock);
+
+ duration = readl(ir->reg + IR_DEC_REG1);
+ duration = (duration & REG1_TIME_IV_MASK) >> REG1_TIME_IV_SHIFT;
+ rawir.duration = US_TO_NS(duration * MESON_TRATE);
+
+ rawir.pulse = !!(readl(ir->reg + IR_DEC_STATUS) & STATUS_IR_DEC_IN);
+
+ ir_raw_event_store_with_filter(ir->rc, &rawir);
+ ir_raw_event_handle(ir->rc);
+
+ spin_unlock(&ir->lock);
+
+ return IRQ_HANDLED;
+}
+
+static int meson_ir_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *node = dev->of_node;
+ struct resource *res;
+ const char *map_name;
+ struct meson_ir *ir;
+ int ret;
+
+ ir = devm_kzalloc(dev, sizeof(struct meson_ir), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ ir->reg = devm_ioremap_resource(dev, res);
+ if (IS_ERR(ir->reg)) {
+ dev_err(dev, "failed to map registers\n");
+ return PTR_ERR(ir->reg);
+ }
+
+ ir->irq = platform_get_irq(pdev, 0);
+ if (ir->irq < 0) {
+ dev_err(dev, "no irq resource\n");
+ return ir->irq;
+ }
+
+ ir->rc = rc_allocate_device();
+ if (!ir->rc) {
+ dev_err(dev, "failed to allocate rc device\n");
+ return -ENOMEM;
+ }
+
+ ir->rc->priv = ir;
+ ir->rc->input_name = DRIVER_NAME;
+ ir->rc->input_phys = DRIVER_NAME "/input0";
+ ir->rc->input_id.bustype = BUS_HOST;
+ map_name = of_get_property(node, "linux,rc-map-name", NULL);
+ ir->rc->map_name = map_name ? map_name : RC_MAP_EMPTY;
+ ir->rc->dev.parent = dev;
+ ir->rc->driver_type = RC_DRIVER_IR_RAW;
+ ir->rc->allowed_protocols = RC_BIT_ALL;
+ ir->rc->rx_resolution = US_TO_NS(MESON_TRATE);
+ ir->rc->timeout = MS_TO_NS(200);
+ ir->rc->driver_name = DRIVER_NAME;
+
+ spin_lock_init(&ir->lock);
+ platform_set_drvdata(pdev, ir);
+
+ ret = rc_register_device(ir->rc);
+ if (ret) {
+ dev_err(dev, "failed to register rc device\n");
+ goto out_free;
+ }
+
+ ret = devm_request_irq(dev, ir->irq, meson_ir_irq, 0, "ir-meson", ir);
+ if (ret) {
+ dev_err(dev, "failed to request irq\n");
+ goto out_unreg;
+ }
+
+ /* Reset the decoder */
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, REG1_RESET);
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_RESET, 0);
+ /* Set general operation mode */
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_MODE_MASK, REG1_MODE_GENERAL);
+ /* Set rate */
+ meson_ir_set_mask(ir, IR_DEC_REG0, REG0_RATE_MASK, MESON_TRATE - 1);
+ /* IRQ on rising and falling edges */
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_IRQSEL_MASK,
+ REG1_IRQSEL_RISE_FALL);
+ /* Enable the decoder */
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, REG1_ENABLE);
+
+ dev_info(dev, "receiver initialized\n");
+
+ return 0;
+out_unreg:
+ rc_unregister_device(ir->rc);
+ ir->rc = NULL;
+out_free:
+ rc_free_device(ir->rc);
+
+ return ret;
+}
+
+static int meson_ir_remove(struct platform_device *pdev)
+{
+ struct meson_ir *ir = platform_get_drvdata(pdev);
+ unsigned long flags;
+
+ /* Disable the decoder */
+ spin_lock_irqsave(&ir->lock, flags);
+ meson_ir_set_mask(ir, IR_DEC_REG1, REG1_ENABLE, 0);
+ spin_unlock_irqrestore(&ir->lock, flags);
+
+ rc_unregister_device(ir->rc);
+
+ return 0;
+}
+
+static const struct of_device_id meson_ir_match[] = {
+ { .compatible = "amlogic,meson6-ir" },
+ { },
+};
+
+static struct platform_driver meson_ir_driver = {
+ .probe = meson_ir_probe,
+ .remove = meson_ir_remove,
+ .driver = {
+ .name = DRIVER_NAME,
+ .of_match_table = meson_ir_match,
+ },
+};
+
+module_platform_driver(meson_ir_driver);
+
+MODULE_DESCRIPTION("Amlogic Meson IR remote receiver driver");
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
index 8d3b74c..86ffcd5 100644
--- a/drivers/media/rc/rc-main.c
+++ b/drivers/media/rc/rc-main.c
@@ -1298,8 +1298,7 @@ void rc_free_device(struct rc_dev *dev)
if (!dev)
return;
- if (dev->input_dev)
- input_free_device(dev->input_dev);
+ input_free_device(dev->input_dev);
put_device(&dev->dev);
@@ -1414,13 +1413,16 @@ int rc_register_device(struct rc_dev *dev)
ir_raw_init();
raw_init = true;
}
+ /* calls ir_register_device so unlock mutex here*/
+ mutex_unlock(&dev->lock);
rc = ir_raw_event_register(dev);
+ mutex_lock(&dev->lock);
if (rc < 0)
goto out_input;
}
if (dev->change_protocol) {
- u64 rc_type = (1 << rc_map->rc_type);
+ u64 rc_type = (1ll << rc_map->rc_type);
if (dev->driver_type == RC_DRIVER_IR_RAW)
rc_type |= RC_BIT_LIRC;
rc = dev->change_protocol(dev, &rc_type);
diff --git a/drivers/media/rc/redrat3.c b/drivers/media/rc/redrat3.c
index 795b394..c4def66 100644
--- a/drivers/media/rc/redrat3.c
+++ b/drivers/media/rc/redrat3.c
@@ -966,7 +966,7 @@ static int redrat3_dev_probe(struct usb_interface *intf,
rr3->ep_in = ep_in;
rr3->bulk_in_buf = usb_alloc_coherent(udev,
- le16_to_cpu(ep_in->wMaxPacketSize), GFP_ATOMIC, &rr3->dma_in);
+ le16_to_cpu(ep_in->wMaxPacketSize), GFP_KERNEL, &rr3->dma_in);
if (!rr3->bulk_in_buf) {
dev_err(dev, "Read buffer allocation failure\n");
goto error;
@@ -975,6 +975,8 @@ static int redrat3_dev_probe(struct usb_interface *intf,
pipe = usb_rcvbulkpipe(udev, ep_in->bEndpointAddress);
usb_fill_bulk_urb(rr3->read_urb, udev, pipe, rr3->bulk_in_buf,
le16_to_cpu(ep_in->wMaxPacketSize), redrat3_handle_async, rr3);
+ rr3->read_urb->transfer_dma = rr3->dma_in;
+ rr3->read_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
rr3->ep_out = ep_out;
rr3->udev = udev;
diff --git a/drivers/media/tuners/Kconfig b/drivers/media/tuners/Kconfig
index f039dc2..42e5a01 100644
--- a/drivers/media/tuners/Kconfig
+++ b/drivers/media/tuners/Kconfig
@@ -232,6 +232,14 @@ config MEDIA_TUNER_M88TS2022
help
Montage M88TS2022 silicon tuner driver.
+config MEDIA_TUNER_M88RS6000T
+ tristate "Montage M88RS6000 internal tuner"
+ depends on MEDIA_SUPPORT && I2C
+ select REGMAP_I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Montage M88RS6000 internal tuner.
+
config MEDIA_TUNER_TUA9001
tristate "Infineon TUA 9001 silicon tuner"
depends on MEDIA_SUPPORT && I2C
diff --git a/drivers/media/tuners/Makefile b/drivers/media/tuners/Makefile
index 49fcf80..da4fe6e 100644
--- a/drivers/media/tuners/Makefile
+++ b/drivers/media/tuners/Makefile
@@ -41,6 +41,7 @@ obj-$(CONFIG_MEDIA_TUNER_IT913X) += it913x.o
obj-$(CONFIG_MEDIA_TUNER_R820T) += r820t.o
obj-$(CONFIG_MEDIA_TUNER_MXL301RF) += mxl301rf.o
obj-$(CONFIG_MEDIA_TUNER_QM1D1C0042) += qm1d1c0042.o
+obj-$(CONFIG_MEDIA_TUNER_M88RS6000T) += m88rs6000t.o
ccflags-y += -I$(srctree)/drivers/media/dvb-core
ccflags-y += -I$(srctree)/drivers/media/dvb-frontends
diff --git a/drivers/media/tuners/m88rs6000t.c b/drivers/media/tuners/m88rs6000t.c
new file mode 100644
index 0000000..d4c13fe
--- /dev/null
+++ b/drivers/media/tuners/m88rs6000t.c
@@ -0,0 +1,744 @@
+/*
+ * Driver for the internal tuner of Montage M88RS6000
+ *
+ * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include "m88rs6000t.h"
+#include <linux/regmap.h>
+
+struct m88rs6000t_dev {
+ struct m88rs6000t_config cfg;
+ struct i2c_client *client;
+ struct regmap *regmap;
+ u32 frequency_khz;
+};
+
+struct m88rs6000t_reg_val {
+ u8 reg;
+ u8 val;
+};
+
+/* set demod main mclk and ts mclk */
+static int m88rs6000t_set_demod_mclk(struct dvb_frontend *fe)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ u8 reg11, reg15, reg16, reg1D, reg1E, reg1F;
+ u8 N, f0 = 0, f1 = 0, f2 = 0, f3 = 0;
+ u16 pll_div_fb;
+ u32 div, ts_mclk;
+ unsigned int utmp;
+ int ret;
+
+ /* select demod main mclk */
+ ret = regmap_read(dev->regmap, 0x15, &utmp);
+ if (ret)
+ goto err;
+ reg15 = utmp;
+ if (c->symbol_rate > 45010000) {
+ reg11 = 0x0E;
+ reg15 |= 0x02;
+ reg16 = 115; /* mclk = 110.25MHz */
+ } else {
+ reg11 = 0x0A;
+ reg15 &= ~0x02;
+ reg16 = 96; /* mclk = 96MHz */
+ }
+
+ /* set ts mclk */
+ if (c->delivery_system == SYS_DVBS)
+ ts_mclk = 96000;
+ else
+ ts_mclk = 144000;
+
+ pll_div_fb = (reg15 & 0x01) << 8;
+ pll_div_fb += reg16;
+ pll_div_fb += 32;
+
+ div = 36000 * pll_div_fb;
+ div /= ts_mclk;
+
+ if (div <= 32) {
+ N = 2;
+ f0 = 0;
+ f1 = div / 2;
+ f2 = div - f1;
+ f3 = 0;
+ } else if (div <= 48) {
+ N = 3;
+ f0 = div / 3;
+ f1 = (div - f0) / 2;
+ f2 = div - f0 - f1;
+ f3 = 0;
+ } else if (div <= 64) {
+ N = 4;
+ f0 = div / 4;
+ f1 = (div - f0) / 3;
+ f2 = (div - f0 - f1) / 2;
+ f3 = div - f0 - f1 - f2;
+ } else {
+ N = 4;
+ f0 = 16;
+ f1 = 16;
+ f2 = 16;
+ f3 = 16;
+ }
+
+ if (f0 == 16)
+ f0 = 0;
+ if (f1 == 16)
+ f1 = 0;
+ if (f2 == 16)
+ f2 = 0;
+ if (f3 == 16)
+ f3 = 0;
+
+ ret = regmap_read(dev->regmap, 0x1D, &utmp);
+ if (ret)
+ goto err;
+ reg1D = utmp;
+ reg1D &= ~0x03;
+ reg1D |= N - 1;
+ reg1E = ((f3 << 4) + f2) & 0xFF;
+ reg1F = ((f1 << 4) + f0) & 0xFF;
+
+ /* program and recalibrate demod PLL */
+ ret = regmap_write(dev->regmap, 0x05, 0x40);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x11, 0x08);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x15, reg15);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x16, reg16);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x1D, reg1D);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x1E, reg1E);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x1F, reg1F);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x17, 0xc1);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x17, 0x81);
+ if (ret)
+ goto err;
+ usleep_range(5000, 50000);
+ ret = regmap_write(dev->regmap, 0x05, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x11, reg11);
+ if (ret)
+ goto err;
+ usleep_range(5000, 50000);
+err:
+ if (ret)
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int m88rs6000t_set_pll_freq(struct m88rs6000t_dev *dev,
+ u32 tuner_freq_MHz)
+{
+ u32 fcry_KHz, ulNDiv1, ulNDiv2, ulNDiv;
+ u8 refDiv, ucLoDiv1, ucLomod1, ucLoDiv2, ucLomod2, ucLoDiv, ucLomod;
+ u8 reg27, reg29, reg42, reg42buf;
+ unsigned int utmp;
+ int ret;
+
+ fcry_KHz = 27000; /* in kHz */
+ refDiv = 27;
+
+ ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x31, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x2c, 0x02);
+ if (ret)
+ goto err;
+
+ if (tuner_freq_MHz >= 1550) {
+ ucLoDiv1 = 2;
+ ucLomod1 = 0;
+ ucLoDiv2 = 2;
+ ucLomod2 = 0;
+ } else if (tuner_freq_MHz >= 1380) {
+ ucLoDiv1 = 3;
+ ucLomod1 = 16;
+ ucLoDiv2 = 2;
+ ucLomod2 = 0;
+ } else if (tuner_freq_MHz >= 1070) {
+ ucLoDiv1 = 3;
+ ucLomod1 = 16;
+ ucLoDiv2 = 3;
+ ucLomod2 = 16;
+ } else if (tuner_freq_MHz >= 1000) {
+ ucLoDiv1 = 3;
+ ucLomod1 = 16;
+ ucLoDiv2 = 4;
+ ucLomod2 = 64;
+ } else if (tuner_freq_MHz >= 775) {
+ ucLoDiv1 = 4;
+ ucLomod1 = 64;
+ ucLoDiv2 = 4;
+ ucLomod2 = 64;
+ } else if (tuner_freq_MHz >= 700) {
+ ucLoDiv1 = 6;
+ ucLomod1 = 48;
+ ucLoDiv2 = 4;
+ ucLomod2 = 64;
+ } else if (tuner_freq_MHz >= 520) {
+ ucLoDiv1 = 6;
+ ucLomod1 = 48;
+ ucLoDiv2 = 6;
+ ucLomod2 = 48;
+ } else {
+ ucLoDiv1 = 8;
+ ucLomod1 = 96;
+ ucLoDiv2 = 8;
+ ucLomod2 = 96;
+ }
+
+ ulNDiv1 = ((tuner_freq_MHz * ucLoDiv1 * 1000) * refDiv
+ / fcry_KHz - 1024) / 2;
+ ulNDiv2 = ((tuner_freq_MHz * ucLoDiv2 * 1000) * refDiv
+ / fcry_KHz - 1024) / 2;
+
+ reg27 = (((ulNDiv1 >> 8) & 0x0F) + ucLomod1) & 0x7F;
+ ret = regmap_write(dev->regmap, 0x27, reg27);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv1 & 0xFF));
+ if (ret)
+ goto err;
+ reg29 = (((ulNDiv2 >> 8) & 0x0F) + ucLomod2) & 0x7f;
+ ret = regmap_write(dev->regmap, 0x29, reg29);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x2a, (u8)(ulNDiv2 & 0xFF));
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x2F, 0xf5);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x30, 0x05);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x08, 0x1f);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x08, 0x3f);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x09, 0x20);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x09, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x3e, 0x11);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x08, 0x2f);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x08, 0x3f);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x09, 0x10);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x09, 0x00);
+ if (ret)
+ goto err;
+ usleep_range(2000, 50000);
+
+ ret = regmap_read(dev->regmap, 0x42, &utmp);
+ if (ret)
+ goto err;
+ reg42 = utmp;
+
+ ret = regmap_write(dev->regmap, 0x3e, 0x10);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x08, 0x2f);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x08, 0x3f);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x09, 0x10);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x09, 0x00);
+ if (ret)
+ goto err;
+ usleep_range(2000, 50000);
+
+ ret = regmap_read(dev->regmap, 0x42, &utmp);
+ if (ret)
+ goto err;
+ reg42buf = utmp;
+ if (reg42buf < reg42) {
+ ret = regmap_write(dev->regmap, 0x3e, 0x11);
+ if (ret)
+ goto err;
+ }
+ usleep_range(5000, 50000);
+
+ ret = regmap_read(dev->regmap, 0x2d, &utmp);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x2d, utmp);
+ if (ret)
+ goto err;
+ ret = regmap_read(dev->regmap, 0x2e, &utmp);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x2e, utmp);
+ if (ret)
+ goto err;
+
+ ret = regmap_read(dev->regmap, 0x27, &utmp);
+ if (ret)
+ goto err;
+ reg27 = utmp & 0x70;
+ ret = regmap_read(dev->regmap, 0x83, &utmp);
+ if (ret)
+ goto err;
+ if (reg27 == (utmp & 0x70)) {
+ ucLoDiv = ucLoDiv1;
+ ulNDiv = ulNDiv1;
+ ucLomod = ucLomod1 / 16;
+ } else {
+ ucLoDiv = ucLoDiv2;
+ ulNDiv = ulNDiv2;
+ ucLomod = ucLomod2 / 16;
+ }
+
+ if ((ucLoDiv == 3) || (ucLoDiv == 6)) {
+ refDiv = 18;
+ ret = regmap_write(dev->regmap, 0x36, (refDiv - 8));
+ if (ret)
+ goto err;
+ ulNDiv = ((tuner_freq_MHz * ucLoDiv * 1000) * refDiv
+ / fcry_KHz - 1024) / 2;
+ }
+
+ reg27 = (0x80 + ((ucLomod << 4) & 0x70)
+ + ((ulNDiv >> 8) & 0x0F)) & 0xFF;
+ ret = regmap_write(dev->regmap, 0x27, reg27);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x28, (u8)(ulNDiv & 0xFF));
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x29, 0x80);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x31, 0x03);
+ if (ret)
+ goto err;
+
+ if (ucLoDiv == 3)
+ utmp = 0xCE;
+ else
+ utmp = 0x8A;
+ ret = regmap_write(dev->regmap, 0x3b, utmp);
+ if (ret)
+ goto err;
+
+ dev->frequency_khz = fcry_KHz * (ulNDiv * 2 + 1024) / refDiv / ucLoDiv;
+
+ dev_dbg(&dev->client->dev,
+ "actual tune frequency=%d\n", dev->frequency_khz);
+err:
+ if (ret)
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int m88rs6000t_set_bb(struct m88rs6000t_dev *dev,
+ u32 symbol_rate_KSs, s32 lpf_offset_KHz)
+{
+ u32 f3dB;
+ u8 reg40;
+
+ f3dB = symbol_rate_KSs * 9 / 14 + 2000;
+ f3dB += lpf_offset_KHz;
+ f3dB = clamp_val(f3dB, 6000U, 43000U);
+ reg40 = f3dB / 1000;
+ return regmap_write(dev->regmap, 0x40, reg40);
+}
+
+static int m88rs6000t_set_params(struct dvb_frontend *fe)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ s32 lpf_offset_KHz;
+ u32 realFreq, freq_MHz;
+
+ dev_dbg(&dev->client->dev,
+ "frequency=%d symbol_rate=%d\n",
+ c->frequency, c->symbol_rate);
+
+ if (c->symbol_rate < 5000000)
+ lpf_offset_KHz = 3000;
+ else
+ lpf_offset_KHz = 0;
+
+ realFreq = c->frequency + lpf_offset_KHz;
+ /* set tuner pll.*/
+ freq_MHz = (realFreq + 500) / 1000;
+ ret = m88rs6000t_set_pll_freq(dev, freq_MHz);
+ if (ret)
+ goto err;
+ ret = m88rs6000t_set_bb(dev, c->symbol_rate / 1000, lpf_offset_KHz);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x00, 0x01);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x00, 0x00);
+ if (ret)
+ goto err;
+ /* set demod mlck */
+ ret = m88rs6000t_set_demod_mclk(fe);
+err:
+ if (ret)
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int m88rs6000t_init(struct dvb_frontend *fe)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+ int ret;
+
+ dev_dbg(&dev->client->dev, "%s:\n", __func__);
+
+ ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
+ if (ret)
+ goto err;
+ usleep_range(5000, 50000);
+ ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
+ if (ret)
+ goto err;
+ usleep_range(10000, 50000);
+ ret = regmap_write(dev->regmap, 0x07, 0x7d);
+err:
+ if (ret)
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int m88rs6000t_sleep(struct dvb_frontend *fe)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+ int ret;
+
+ dev_dbg(&dev->client->dev, "%s:\n", __func__);
+
+ ret = regmap_write(dev->regmap, 0x07, 0x6d);
+ if (ret)
+ goto err;
+ usleep_range(5000, 10000);
+err:
+ if (ret)
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int m88rs6000t_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+
+ dev_dbg(&dev->client->dev, "\n");
+
+ *frequency = dev->frequency_khz;
+ return 0;
+}
+
+static int m88rs6000t_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+
+ dev_dbg(&dev->client->dev, "\n");
+
+ *frequency = 0; /* Zero-IF */
+ return 0;
+}
+
+
+static int m88rs6000t_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct m88rs6000t_dev *dev = fe->tuner_priv;
+ unsigned int val, i;
+ int ret;
+ u16 gain;
+ u32 PGA2_cri_GS = 46, PGA2_crf_GS = 290, TIA_GS = 290;
+ u32 RF_GC = 1200, IF_GC = 1100, BB_GC = 300;
+ u32 PGA2_GC = 300, TIA_GC = 300, PGA2_cri = 0, PGA2_crf = 0;
+ u32 RFG = 0, IFG = 0, BBG = 0, PGA2G = 0, TIAG = 0;
+ u32 RFGS[13] = {0, 245, 266, 268, 270, 285,
+ 298, 295, 283, 285, 285, 300, 300};
+ u32 IFGS[12] = {0, 300, 230, 270, 270, 285,
+ 295, 285, 290, 295, 295, 310};
+ u32 BBGS[14] = {0, 286, 275, 290, 294, 300, 290,
+ 290, 285, 283, 260, 295, 290, 260};
+
+ ret = regmap_read(dev->regmap, 0x5A, &val);
+ if (ret)
+ goto err;
+ RF_GC = val & 0x0f;
+
+ ret = regmap_read(dev->regmap, 0x5F, &val);
+ if (ret)
+ goto err;
+ IF_GC = val & 0x0f;
+
+ ret = regmap_read(dev->regmap, 0x3F, &val);
+ if (ret)
+ goto err;
+ TIA_GC = (val >> 4) & 0x07;
+
+ ret = regmap_read(dev->regmap, 0x77, &val);
+ if (ret)
+ goto err;
+ BB_GC = (val >> 4) & 0x0f;
+
+ ret = regmap_read(dev->regmap, 0x76, &val);
+ if (ret)
+ goto err;
+ PGA2_GC = val & 0x3f;
+ PGA2_cri = PGA2_GC >> 2;
+ PGA2_crf = PGA2_GC & 0x03;
+
+ for (i = 0; i <= RF_GC; i++)
+ RFG += RFGS[i];
+
+ if (RF_GC == 0)
+ RFG += 400;
+ if (RF_GC == 1)
+ RFG += 300;
+ if (RF_GC == 2)
+ RFG += 200;
+ if (RF_GC == 3)
+ RFG += 100;
+
+ for (i = 0; i <= IF_GC; i++)
+ IFG += IFGS[i];
+
+ TIAG = TIA_GC * TIA_GS;
+
+ for (i = 0; i <= BB_GC; i++)
+ BBG += BBGS[i];
+
+ PGA2G = PGA2_cri * PGA2_cri_GS + PGA2_crf * PGA2_crf_GS;
+
+ gain = RFG + IFG - TIAG + BBG + PGA2G;
+
+ /* scale value to 0x0000-0xffff */
+ gain = clamp_val(gain, 1000U, 10500U);
+ *strength = (10500 - gain) * 0xffff / (10500 - 1000);
+err:
+ if (ret)
+ dev_dbg(&dev->client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static const struct dvb_tuner_ops m88rs6000t_tuner_ops = {
+ .info = {
+ .name = "Montage M88RS6000 Internal Tuner",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ },
+
+ .init = m88rs6000t_init,
+ .sleep = m88rs6000t_sleep,
+ .set_params = m88rs6000t_set_params,
+ .get_frequency = m88rs6000t_get_frequency,
+ .get_if_frequency = m88rs6000t_get_if_frequency,
+ .get_rf_strength = m88rs6000t_get_rf_strength,
+};
+
+static int m88rs6000t_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct m88rs6000t_config *cfg = client->dev.platform_data;
+ struct dvb_frontend *fe = cfg->fe;
+ struct m88rs6000t_dev *dev;
+ int ret, i;
+ unsigned int utmp;
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+ static const struct m88rs6000t_reg_val reg_vals[] = {
+ {0x10, 0xfb},
+ {0x24, 0x38},
+ {0x11, 0x0a},
+ {0x12, 0x00},
+ {0x2b, 0x1c},
+ {0x44, 0x48},
+ {0x54, 0x24},
+ {0x55, 0x06},
+ {0x59, 0x00},
+ {0x5b, 0x4c},
+ {0x60, 0x8b},
+ {0x61, 0xf4},
+ {0x65, 0x07},
+ {0x6d, 0x6f},
+ {0x6e, 0x31},
+ {0x3c, 0xf3},
+ {0x37, 0x0f},
+ {0x48, 0x28},
+ {0x49, 0xd8},
+ {0x70, 0x66},
+ {0x71, 0xCF},
+ {0x72, 0x81},
+ {0x73, 0xA7},
+ {0x74, 0x4F},
+ {0x75, 0xFC},
+ };
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev) {
+ ret = -ENOMEM;
+ dev_err(&client->dev, "kzalloc() failed\n");
+ goto err;
+ }
+
+ memcpy(&dev->cfg, cfg, sizeof(struct m88rs6000t_config));
+ dev->client = client;
+ dev->regmap = devm_regmap_init_i2c(client, &regmap_config);
+ if (IS_ERR(dev->regmap)) {
+ ret = PTR_ERR(dev->regmap);
+ goto err;
+ }
+
+ ret = regmap_update_bits(dev->regmap, 0x11, 0x08, 0x08);
+ if (ret)
+ goto err;
+ usleep_range(5000, 50000);
+ ret = regmap_update_bits(dev->regmap, 0x10, 0x01, 0x01);
+ if (ret)
+ goto err;
+ usleep_range(10000, 50000);
+ ret = regmap_write(dev->regmap, 0x07, 0x7d);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x04, 0x01);
+ if (ret)
+ goto err;
+
+ /* check tuner chip id */
+ ret = regmap_read(dev->regmap, 0x01, &utmp);
+ if (ret)
+ goto err;
+ dev_info(&dev->client->dev, "chip_id=%02x\n", utmp);
+ if (utmp != 0x64) {
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /* tuner init. */
+ ret = regmap_write(dev->regmap, 0x05, 0x40);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x11, 0x08);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x15, 0x6c);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x17, 0xc1);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x17, 0x81);
+ if (ret)
+ goto err;
+ usleep_range(10000, 50000);
+ ret = regmap_write(dev->regmap, 0x05, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap, 0x11, 0x0a);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < ARRAY_SIZE(reg_vals); i++) {
+ ret = regmap_write(dev->regmap,
+ reg_vals[i].reg, reg_vals[i].val);
+ if (ret)
+ goto err;
+ }
+
+ dev_info(&dev->client->dev, "Montage M88RS6000 internal tuner successfully identified\n");
+
+ fe->tuner_priv = dev;
+ memcpy(&fe->ops.tuner_ops, &m88rs6000t_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ i2c_set_clientdata(client, dev);
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ kfree(dev);
+ return ret;
+}
+
+static int m88rs6000t_remove(struct i2c_client *client)
+{
+ struct m88rs6000t_dev *dev = i2c_get_clientdata(client);
+ struct dvb_frontend *fe = dev->cfg.fe;
+
+ dev_dbg(&client->dev, "\n");
+
+ memset(&fe->ops.tuner_ops, 0, sizeof(struct dvb_tuner_ops));
+ fe->tuner_priv = NULL;
+ kfree(dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id m88rs6000t_id[] = {
+ {"m88rs6000t", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, m88rs6000t_id);
+
+static struct i2c_driver m88rs6000t_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "m88rs6000t",
+ },
+ .probe = m88rs6000t_probe,
+ .remove = m88rs6000t_remove,
+ .id_table = m88rs6000t_id,
+};
+
+module_i2c_driver(m88rs6000t_driver);
+
+MODULE_AUTHOR("Max nibble <nibble.max@gmail.com>");
+MODULE_DESCRIPTION("Montage M88RS6000 internal tuner driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/tuners/m88rs6000t.h b/drivers/media/tuners/m88rs6000t.h
new file mode 100644
index 0000000..264c13e
--- /dev/null
+++ b/drivers/media/tuners/m88rs6000t.h
@@ -0,0 +1,29 @@
+/*
+ * Driver for the internal tuner of Montage M88RS6000
+ *
+ * Copyright (C) 2014 Max nibble <nibble.max@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _M88RS6000T_H_
+#define _M88RS6000T_H_
+
+#include "dvb_frontend.h"
+
+struct m88rs6000t_config {
+ /*
+ * pointer to DVB frontend
+ */
+ struct dvb_frontend *fe;
+};
+
+#endif
diff --git a/drivers/media/tuners/m88ts2022.c b/drivers/media/tuners/m88ts2022.c
index caa5423..066e543 100644
--- a/drivers/media/tuners/m88ts2022.c
+++ b/drivers/media/tuners/m88ts2022.c
@@ -488,6 +488,7 @@ static int m88ts2022_probe(struct i2c_client *client,
case 0x83:
break;
default:
+ ret = -ENODEV;
goto err;
}
@@ -505,6 +506,7 @@ static int m88ts2022_probe(struct i2c_client *client,
u8tmp = 0x6c;
break;
default:
+ ret = -EINVAL;
goto err;
}
diff --git a/drivers/media/tuners/mxl5007t.c b/drivers/media/tuners/mxl5007t.c
index 69e453e..1810ad6 100644
--- a/drivers/media/tuners/mxl5007t.c
+++ b/drivers/media/tuners/mxl5007t.c
@@ -374,7 +374,6 @@ static struct reg_pair_t *mxl5007t_calc_init_regs(struct mxl5007t_state *state,
mxl5007t_set_if_freq_bits(state, cfg->if_freq_hz, cfg->invert_if);
mxl5007t_set_xtal_freq_bits(state, cfg->xtal_freq_hz);
- set_reg_bits(state->tab_init, 0x04, 0x01, cfg->loop_thru_enable);
set_reg_bits(state->tab_init, 0x03, 0x08, cfg->clk_out_enable << 3);
set_reg_bits(state->tab_init, 0x03, 0x07, cfg->clk_out_amp);
@@ -531,10 +530,6 @@ static int mxl5007t_tuner_init(struct mxl5007t_state *state,
struct reg_pair_t *init_regs;
int ret;
- ret = mxl5007t_soft_reset(state);
- if (mxl_fail(ret))
- goto fail;
-
/* calculate initialization reg array */
init_regs = mxl5007t_calc_init_regs(state, mode);
@@ -900,7 +895,32 @@ struct dvb_frontend *mxl5007t_attach(struct dvb_frontend *fe,
/* existing tuner instance */
break;
}
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = mxl5007t_soft_reset(state);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (mxl_fail(ret))
+ goto fail;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = mxl5007t_write_reg(state, 0x04,
+ state->config->loop_thru_enable);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (mxl_fail(ret))
+ goto fail;
+
fe->tuner_priv = state;
+
mutex_unlock(&mxl5007t_list_mutex);
memcpy(&fe->ops.tuner_ops, &mxl5007t_tuner_ops,
diff --git a/drivers/media/tuners/r820t.c b/drivers/media/tuners/r820t.c
index a759742..8e040cf 100644
--- a/drivers/media/tuners/r820t.c
+++ b/drivers/media/tuners/r820t.c
@@ -959,6 +959,18 @@ static int r820t_set_tv_standard(struct r820t_priv *priv,
lt_att = 0x00; /* r31[7], lt att enable */
flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
polyfil_cur = 0x60; /* r25[6:5]:min */
+ } else if (delsys == SYS_DVBC_ANNEX_A) {
+ if_khz = 5070;
+ filt_cal_lo = 73500;
+ filt_gain = 0x10; /* +3db, 6mhz on */
+ img_r = 0x00; /* image negative */
+ filt_q = 0x10; /* r10[4]:low q(1'b1) */
+ hp_cor = 0x0b; /* 1.7m disable, +0cap, 1.0mhz */
+ ext_enable = 0x40; /* r30[6]=1 ext enable; r30[5]:1 ext at lna max-1 */
+ loop_through = 0x00; /* r5[7], lt on */
+ lt_att = 0x00; /* r31[7], lt att enable */
+ flt_ext_widest = 0x00; /* r15[7]: flt_ext_wide off */
+ polyfil_cur = 0x60; /* r25[6:5]:min */
} else {
if (bw <= 6) {
if_khz = 3570;
diff --git a/drivers/media/tuners/si2157.c b/drivers/media/tuners/si2157.c
index cf97142..2180de9 100644
--- a/drivers/media/tuners/si2157.c
+++ b/drivers/media/tuners/si2157.c
@@ -1,5 +1,5 @@
/*
- * Silicon Labs Si2147/2157/2158 silicon tuner driver
+ * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
*
* Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
*
@@ -93,8 +93,13 @@ static int si2157_init(struct dvb_frontend *fe)
goto warm;
/* power up */
- memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
- cmd.wlen = 15;
+ if (s->chiptype == SI2157_CHIPTYPE_SI2146) {
+ memcpy(cmd.args, "\xc0\x05\x01\x00\x00\x0b\x00\x00\x01", 9);
+ cmd.wlen = 9;
+ } else {
+ memcpy(cmd.args, "\xc0\x00\x0c\x00\x00\x01\x01\x01\x01\x01\x01\x02\x00\x00\x01", 15);
+ cmd.wlen = 15;
+ }
cmd.rlen = 1;
ret = si2157_cmd_execute(s, &cmd);
if (ret)
@@ -112,17 +117,20 @@ static int si2157_init(struct dvb_frontend *fe)
cmd.args[4] << 0;
#define SI2158_A20 ('A' << 24 | 58 << 16 | '2' << 8 | '0' << 0)
+ #define SI2148_A20 ('A' << 24 | 48 << 16 | '2' << 8 | '0' << 0)
#define SI2157_A30 ('A' << 24 | 57 << 16 | '3' << 8 | '0' << 0)
#define SI2147_A30 ('A' << 24 | 47 << 16 | '3' << 8 | '0' << 0)
+ #define SI2146_A10 ('A' << 24 | 46 << 16 | '1' << 8 | '0' << 0)
switch (chip_id) {
case SI2158_A20:
+ case SI2148_A20:
fw_file = SI2158_A20_FIRMWARE;
break;
case SI2157_A30:
case SI2147_A30:
+ case SI2146_A10:
goto skip_fw_download;
- break;
default:
dev_err(&s->client->dev,
"unknown chip version Si21%d-%c%c%c\n",
@@ -149,7 +157,7 @@ static int si2157_init(struct dvb_frontend *fe)
dev_err(&s->client->dev, "firmware file '%s' is invalid\n",
fw_file);
ret = -EINVAL;
- goto err;
+ goto fw_release_exit;
}
dev_info(&s->client->dev, "downloading firmware from file '%s'\n",
@@ -165,7 +173,7 @@ static int si2157_init(struct dvb_frontend *fe)
dev_err(&s->client->dev,
"firmware download failed=%d\n",
ret);
- goto err;
+ goto fw_release_exit;
}
}
@@ -187,10 +195,9 @@ warm:
s->active = true;
return 0;
+fw_release_exit:
+ release_firmware(fw);
err:
- if (fw)
- release_firmware(fw);
-
dev_dbg(&s->client->dev, "failed=%d\n", ret);
return ret;
}
@@ -250,6 +257,9 @@ static int si2157_set_params(struct dvb_frontend *fe)
case SYS_ATSC:
delivery_system = 0x00;
break;
+ case SYS_DVBC_ANNEX_B:
+ delivery_system = 0x10;
+ break;
case SYS_DVBT:
case SYS_DVBT2: /* it seems DVB-T and DVB-T2 both are 0x20 here */
delivery_system = 0x20;
@@ -272,7 +282,10 @@ static int si2157_set_params(struct dvb_frontend *fe)
if (ret)
goto err;
- memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
+ if (s->chiptype == SI2157_CHIPTYPE_SI2146)
+ memcpy(cmd.args, "\x14\x00\x02\x07\x00\x01", 6);
+ else
+ memcpy(cmd.args, "\x14\x00\x02\x07\x01\x00", 6);
cmd.wlen = 6;
cmd.rlen = 4;
ret = si2157_cmd_execute(s, &cmd);
@@ -305,7 +318,7 @@ static int si2157_get_if_frequency(struct dvb_frontend *fe, u32 *frequency)
static const struct dvb_tuner_ops si2157_ops = {
.info = {
- .name = "Silicon Labs Si2157/Si2158",
+ .name = "Silicon Labs Si2146/2147/2148/2157/2158",
.frequency_min = 110000000,
.frequency_max = 862000000,
},
@@ -336,6 +349,7 @@ static int si2157_probe(struct i2c_client *client,
s->fe = cfg->fe;
s->inversion = cfg->inversion;
s->fw_loaded = false;
+ s->chiptype = (u8)id->driver_data;
mutex_init(&s->i2c_mutex);
/* check if the tuner is there */
@@ -352,7 +366,10 @@ static int si2157_probe(struct i2c_client *client,
i2c_set_clientdata(client, s);
dev_info(&s->client->dev,
- "Silicon Labs Si2157/Si2158 successfully attached\n");
+ "Silicon Labs %s successfully attached\n",
+ s->chiptype == SI2157_CHIPTYPE_SI2146 ?
+ "Si2146" : "Si2147/2148/2157/2158");
+
return 0;
err:
dev_dbg(&client->dev, "failed=%d\n", ret);
@@ -377,6 +394,7 @@ static int si2157_remove(struct i2c_client *client)
static const struct i2c_device_id si2157_id[] = {
{"si2157", 0},
+ {"si2146", 1},
{}
};
MODULE_DEVICE_TABLE(i2c, si2157_id);
@@ -393,7 +411,7 @@ static struct i2c_driver si2157_driver = {
module_i2c_driver(si2157_driver);
-MODULE_DESCRIPTION("Silicon Labs Si2157/Si2158 silicon tuner driver");
+MODULE_DESCRIPTION("Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver");
MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
MODULE_LICENSE("GPL");
MODULE_FIRMWARE(SI2158_A20_FIRMWARE);
diff --git a/drivers/media/tuners/si2157.h b/drivers/media/tuners/si2157.h
index d3b19ca..a564c4a 100644
--- a/drivers/media/tuners/si2157.h
+++ b/drivers/media/tuners/si2157.h
@@ -1,5 +1,5 @@
/*
- * Silicon Labs Si2147/2157/2158 silicon tuner driver
+ * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
*
* Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
*
diff --git a/drivers/media/tuners/si2157_priv.h b/drivers/media/tuners/si2157_priv.h
index e71ffaf..d6e07cd 100644
--- a/drivers/media/tuners/si2157_priv.h
+++ b/drivers/media/tuners/si2157_priv.h
@@ -1,5 +1,5 @@
/*
- * Silicon Labs Si2147/2157/2158 silicon tuner driver
+ * Silicon Labs Si2146/2147/2148/2157/2158 silicon tuner driver
*
* Copyright (C) 2014 Antti Palosaari <crope@iki.fi>
*
@@ -28,9 +28,13 @@ struct si2157 {
bool active;
bool fw_loaded;
bool inversion;
+ u8 chiptype;
};
-/* firmare command struct */
+#define SI2157_CHIPTYPE_SI2157 0
+#define SI2157_CHIPTYPE_SI2146 1
+
+/* firmware command struct */
#define SI2157_ARGLEN 30
struct si2157_cmd {
u8 args[SI2157_ARGLEN];
diff --git a/drivers/media/tuners/tda18271-common.c b/drivers/media/tuners/tda18271-common.c
index 86e5e31..a26bb33 100644
--- a/drivers/media/tuners/tda18271-common.c
+++ b/drivers/media/tuners/tda18271-common.c
@@ -178,7 +178,7 @@ int tda18271_read_extended(struct dvb_frontend *fe)
(i != R_EB17) &&
(i != R_EB19) &&
(i != R_EB20))
- regs[i] = regdump[i];
+ regs[i] = regdump[i];
}
if (tda18271_debug & DBG_REG)
diff --git a/drivers/media/tuners/xc5000.c b/drivers/media/tuners/xc5000.c
index 803a0e6..2a039de 100644
--- a/drivers/media/tuners/xc5000.c
+++ b/drivers/media/tuners/xc5000.c
@@ -62,6 +62,7 @@ struct xc5000_priv {
unsigned int mode;
u8 rf_mode;
u8 radio_input;
+ u16 output_amp;
int chip_id;
u16 pll_register_no;
@@ -744,7 +745,9 @@ static int xc5000_tune_digital(struct dvb_frontend *fe)
return -EIO;
}
- xc_write_reg(priv, XREG_OUTPUT_AMP, 0x8a);
+ dprintk(1, "%s() setting OUTPUT_AMP to 0x%x\n",
+ __func__, priv->output_amp);
+ xc_write_reg(priv, XREG_OUTPUT_AMP, priv->output_amp);
xc_tune_channel(priv, priv->freq_hz, XC_TUNE_DIGITAL);
@@ -1333,8 +1336,7 @@ static int xc5000_release(struct dvb_frontend *fe)
if (priv) {
cancel_delayed_work(&priv->timer_sleep);
- if (priv->firmware)
- release_firmware(priv->firmware);
+ release_firmware(priv->firmware);
hybrid_tuner_release_state(priv);
}
@@ -1358,6 +1360,9 @@ static int xc5000_set_config(struct dvb_frontend *fe, void *priv_cfg)
if (p->radio_input)
priv->radio_input = p->radio_input;
+ if (p->output_amp)
+ priv->output_amp = p->output_amp;
+
return 0;
}
@@ -1438,6 +1443,12 @@ struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
it can be overridden if this is a hybrid driver */
priv->chip_id = (cfg->chip_id) ? cfg->chip_id : 0;
+ /* don't override output_amp if it's already been set
+ unless explicitly specified */
+ if ((priv->output_amp == 0) || (cfg->output_amp))
+ /* use default output_amp value if none specified */
+ priv->output_amp = (cfg->output_amp) ? cfg->output_amp : 0x8a;
+
/* Check if firmware has been loaded. It is possible that another
instance of the driver has loaded the firmware.
*/
diff --git a/drivers/media/tuners/xc5000.h b/drivers/media/tuners/xc5000.h
index 7245cae..6aa534f 100644
--- a/drivers/media/tuners/xc5000.h
+++ b/drivers/media/tuners/xc5000.h
@@ -36,6 +36,7 @@ struct xc5000_config {
u32 if_khz;
u8 radio_input;
u16 xtal_khz;
+ u16 output_amp;
int chip_id;
};
diff --git a/drivers/media/usb/au0828/au0828-cards.c b/drivers/media/usb/au0828/au0828-cards.c
index 9eb77ac..da87f1c 100644
--- a/drivers/media/usb/au0828/au0828-cards.c
+++ b/drivers/media/usb/au0828/au0828-cards.c
@@ -36,6 +36,11 @@ static void hvr950q_cs5340_audio(void *priv, int enable)
au0828_clear(dev, REG_000, 0x10);
}
+/*
+ * WARNING: There's a quirks table at sound/usb/quirks-table.h
+ * that should also be updated every time a new device with V4L2 support
+ * is added here.
+ */
struct au0828_board au0828_boards[] = {
[AU0828_BOARD_UNKNOWN] = {
.name = "Unknown board",
diff --git a/drivers/media/usb/au0828/au0828-core.c b/drivers/media/usb/au0828/au0828-core.c
index bc06480..082ae6b 100644
--- a/drivers/media/usb/au0828/au0828-core.c
+++ b/drivers/media/usb/au0828/au0828-core.c
@@ -153,6 +153,14 @@ static void au0828_usb_disconnect(struct usb_interface *interface)
dprintk(1, "%s()\n", __func__);
+ /* there is a small window after disconnect, before
+ dev->usbdev is NULL, for poll (e.g: IR) try to access
+ the device and fill the dmesg with error messages.
+ Set the status so poll routines can check and avoid
+ access after disconnect.
+ */
+ dev->dev_state = DEV_DISCONNECTED;
+
au0828_rc_unregister(dev);
/* Digital TV */
au0828_dvb_unregister(dev);
diff --git a/drivers/media/usb/au0828/au0828-dvb.c b/drivers/media/usb/au0828/au0828-dvb.c
index 00ab1563..c267d76 100644
--- a/drivers/media/usb/au0828/au0828-dvb.c
+++ b/drivers/media/usb/au0828/au0828-dvb.c
@@ -88,12 +88,14 @@ static struct xc5000_config hauppauge_xc5000a_config = {
.i2c_address = 0x61,
.if_khz = 6000,
.chip_id = XC5000A,
+ .output_amp = 0x8f,
};
static struct xc5000_config hauppauge_xc5000c_config = {
.i2c_address = 0x61,
.if_khz = 6000,
.chip_id = XC5000C,
+ .output_amp = 0x8f,
};
static struct mxl5007t_config mxl5007t_hvr950q_config = {
diff --git a/drivers/media/usb/au0828/au0828-input.c b/drivers/media/usb/au0828/au0828-input.c
index 63995f9..b0f0679 100644
--- a/drivers/media/usb/au0828/au0828-input.c
+++ b/drivers/media/usb/au0828/au0828-input.c
@@ -129,6 +129,10 @@ static int au0828_get_key_au8522(struct au0828_rc *ir)
int prv_bit, bit, width;
bool first = true;
+ /* do nothing if device is disconnected */
+ if (ir->dev->dev_state == DEV_DISCONNECTED)
+ return 0;
+
/* Check IR int */
rc = au8522_rc_read(ir, 0xe1, -1, buf, 1);
if (rc < 0 || !(buf[0] & (1 << 4))) {
@@ -255,8 +259,11 @@ static void au0828_rc_stop(struct rc_dev *rc)
cancel_delayed_work_sync(&ir->work);
- /* Disable IR */
- au8522_rc_clear(ir, 0xe0, 1 << 4);
+ /* do nothing if device is disconnected */
+ if (ir->dev->dev_state != DEV_DISCONNECTED) {
+ /* Disable IR */
+ au8522_rc_clear(ir, 0xe0, 1 << 4);
+ }
}
static int au0828_probe_i2c_ir(struct au0828_dev *dev)
@@ -363,8 +370,7 @@ void au0828_rc_unregister(struct au0828_dev *dev)
if (!ir)
return;
- if (ir->rc)
- rc_unregister_device(ir->rc);
+ rc_unregister_device(ir->rc);
/* done */
kfree(ir);
diff --git a/drivers/media/usb/cx231xx/Kconfig b/drivers/media/usb/cx231xx/Kconfig
index 569aa29..173c0e2 100644
--- a/drivers/media/usb/cx231xx/Kconfig
+++ b/drivers/media/usb/cx231xx/Kconfig
@@ -7,6 +7,7 @@ config VIDEO_CX231XX
select VIDEOBUF_VMALLOC
select VIDEO_CX25840
select VIDEO_CX2341X
+ select I2C_MUX
---help---
This is a video4linux driver for Conexant 231xx USB based TV cards.
diff --git a/drivers/media/usb/cx231xx/cx231xx-417.c b/drivers/media/usb/cx231xx/cx231xx-417.c
index 459bb0e..3f295b4 100644
--- a/drivers/media/usb/cx231xx/cx231xx-417.c
+++ b/drivers/media/usb/cx231xx/cx231xx-417.c
@@ -24,6 +24,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
+
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/init.h>
@@ -37,9 +39,6 @@
#include <media/v4l2-event.h>
#include <media/cx2341x.h>
#include <media/tuner.h>
-#include <linux/usb.h>
-
-#include "cx231xx.h"
#define CX231xx_FIRM_IMAGE_SIZE 376836
#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
@@ -90,10 +89,10 @@ static unsigned int v4l_debug = 1;
module_param(v4l_debug, int, 0644);
MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
-#define dprintk(level, fmt, arg...)\
- do { if (v4l_debug >= level) \
- pr_info("%s: " fmt, \
- (dev) ? dev->name : "cx231xx[?]", ## arg); \
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (v4l_debug >= level) \
+ printk(KERN_DEBUG pr_fmt(fmt), ## arg); \
} while (0)
static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
@@ -988,29 +987,34 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
IVTV_REG_APU, 0);
if (retval != 0) {
- pr_err("%s: Error with mc417_register_write\n", __func__);
+ dev_err(dev->dev,
+ "%s: Error with mc417_register_write\n", __func__);
return -1;
}
retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
- &dev->udev->dev);
+ dev->dev);
if (retval != 0) {
- pr_err("ERROR: Hotplug firmware request failed (%s).\n",
+ dev_err(dev->dev,
+ "ERROR: Hotplug firmware request failed (%s).\n",
CX231xx_FIRM_IMAGE_NAME);
- pr_err("Please fix your hotplug setup, the board will not work without firmware loaded!\n");
+ dev_err(dev->dev,
+ "Please fix your hotplug setup, the board will not work without firmware loaded!\n");
return -1;
}
if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
- pr_err("ERROR: Firmware size mismatch (have %zd, expected %d)\n",
+ dev_err(dev->dev,
+ "ERROR: Firmware size mismatch (have %zd, expected %d)\n",
firmware->size, CX231xx_FIRM_IMAGE_SIZE);
release_firmware(firmware);
return -1;
}
if (0 != memcmp(firmware->data, magic, 8)) {
- pr_err("ERROR: Firmware magic mismatch, wrong file?\n");
+ dev_err(dev->dev,
+ "ERROR: Firmware magic mismatch, wrong file?\n");
release_firmware(firmware);
return -1;
}
@@ -1057,7 +1061,8 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
IVTV_CMD_HW_BLOCKS_RST);
if (retval < 0) {
- pr_err("%s: Error with mc417_register_write\n",
+ dev_err(dev->dev,
+ "%s: Error with mc417_register_write\n",
__func__);
return retval;
}
@@ -1069,7 +1074,8 @@ static int cx231xx_load_firmware(struct cx231xx *dev)
retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
if (retval < 0) {
- pr_err("%s: Error with mc417_register_write\n",
+ dev_err(dev->dev,
+ "%s: Error with mc417_register_write\n",
__func__);
return retval;
}
@@ -1114,28 +1120,31 @@ static int cx231xx_initialize_codec(struct cx231xx *dev)
cx231xx_disable656(dev);
retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
if (retval < 0) {
- dprintk(2, "%s() PING OK\n", __func__);
+ dprintk(2, "%s: PING OK\n", __func__);
retval = cx231xx_load_firmware(dev);
if (retval < 0) {
- pr_err("%s() f/w load failed\n", __func__);
+ dev_err(dev->dev,
+ "%s: f/w load failed\n", __func__);
return retval;
}
retval = cx231xx_find_mailbox(dev);
if (retval < 0) {
- pr_err("%s() mailbox < 0, error\n",
+ dev_err(dev->dev, "%s: mailbox < 0, error\n",
__func__);
return -1;
}
dev->cx23417_mailbox = retval;
retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
if (retval < 0) {
- pr_err("ERROR: cx23417 firmware ping failed!\n");
+ dev_err(dev->dev,
+ "ERROR: cx23417 firmware ping failed!\n");
return -1;
}
retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
&version);
if (retval < 0) {
- pr_err("ERROR: cx23417 firmware get encoder: version failed!\n");
+ dev_err(dev->dev,
+ "ERROR: cx23417 firmware get encoder: version failed!\n");
return -1;
}
dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
@@ -1416,8 +1425,9 @@ static int bb_buf_prepare(struct videobuf_queue *q,
if (!dev->video_mode.bulk_ctl.num_bufs)
urb_init = 1;
}
- /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
- urb_init, dev->video_mode.max_pkt_size);*/
+ dev_dbg(dev->dev,
+ "urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+ urb_init, dev->video_mode.max_pkt_size);
dev->mode_tv = 1;
if (urb_init) {
@@ -1688,7 +1698,7 @@ static int mpeg_open(struct file *file)
sizeof(struct cx231xx_buffer), fh, &dev->lock);
/*
videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
- &dev->udev->dev, &dev->ts1.slock,
+ dev->dev, &dev->ts1.slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx231xx_buffer),
@@ -1798,7 +1808,6 @@ static unsigned int mpeg_poll(struct file *file,
static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
{
struct cx231xx_fh *fh = file->private_data;
- struct cx231xx *dev = fh->dev;
dprintk(2, "%s()\n", __func__);
@@ -1878,7 +1887,7 @@ static int cx231xx_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
/* fix videodecoder resolution */
fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
fmt.height = cxhdl->height;
- fmt.code = V4L2_MBUS_FMT_FIXED;
+ fmt.code = MEDIA_BUS_FMT_FIXED;
v4l2_subdev_call(dev->sd_cx25840, video, s_mbus_fmt, &fmt);
return 0;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-audio.c b/drivers/media/usb/cx231xx/cx231xx-audio.c
index 9b92587..de4ae5e 100644
--- a/drivers/media/usb/cx231xx/cx231xx-audio.c
+++ b/drivers/media/usb/cx231xx/cx231xx-audio.c
@@ -20,8 +20,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/kernel.h>
-#include <linux/usb.h>
#include <linux/init.h>
#include <linux/sound.h>
#include <linux/spinlock.h>
@@ -37,25 +37,18 @@
#include <sound/initval.h>
#include <sound/control.h>
#include <media/v4l2-common.h>
-#include "cx231xx.h"
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "activates debug info");
-#define dprintk(fmt, arg...) do { \
- if (debug) \
- printk(KERN_INFO "cx231xx-audio %s: " fmt, \
- __func__, ##arg); \
- } while (0)
-
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
{
int i;
- dprintk("Stopping isoc\n");
+ dev_dbg(dev->dev, "Stopping isoc\n");
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
if (dev->adev.urb[i]) {
@@ -79,7 +72,7 @@ static int cx231xx_bulk_audio_deinit(struct cx231xx *dev)
{
int i;
- dprintk("Stopping bulk\n");
+ dev_dbg(dev->dev, "Stopping bulk\n");
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
if (dev->adev.urb[i]) {
@@ -123,7 +116,8 @@ static void cx231xx_audio_isocirq(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- dprintk("urb completition error %d.\n", urb->status);
+ dev_dbg(dev->dev, "urb completition error %d.\n",
+ urb->status);
break;
}
@@ -182,8 +176,9 @@ static void cx231xx_audio_isocirq(struct urb *urb)
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
- cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
- status);
+ dev_err(dev->dev,
+ "resubmit of audio urb failed (error=%i)\n",
+ status);
}
return;
}
@@ -211,7 +206,8 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- dprintk("urb completition error %d.\n", urb->status);
+ dev_dbg(dev->dev, "urb completition error %d.\n",
+ urb->status);
break;
}
@@ -266,8 +262,9 @@ static void cx231xx_audio_bulkirq(struct urb *urb)
status = usb_submit_urb(urb, GFP_ATOMIC);
if (status < 0) {
- cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
- status);
+ dev_err(dev->dev,
+ "resubmit of audio urb failed (error=%i)\n",
+ status);
}
return;
}
@@ -277,7 +274,8 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
int i, errCode;
int sb_size;
- cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
+ dev_dbg(dev->dev,
+ "%s: Starting ISO AUDIO transfers\n", __func__);
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
@@ -295,7 +293,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) {
- cx231xx_errdev("usb_alloc_urb failed!\n");
+ dev_err(dev->dev, "usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) {
usb_free_urb(dev->adev.urb[j]);
kfree(dev->adev.transfer_buffer[j]);
@@ -338,7 +336,8 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
int i, errCode;
int sb_size;
- cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
+ dev_dbg(dev->dev,
+ "%s: Starting BULK AUDIO transfers\n", __func__);
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
@@ -356,7 +355,7 @@ static int cx231xx_init_audio_bulk(struct cx231xx *dev)
memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) {
- cx231xx_errdev("usb_alloc_urb failed!\n");
+ dev_err(dev->dev, "usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) {
usb_free_urb(dev->adev.urb[j]);
kfree(dev->adev.transfer_buffer[j]);
@@ -392,8 +391,9 @@ static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
size_t size)
{
struct snd_pcm_runtime *runtime = subs->runtime;
+ struct cx231xx *dev = snd_pcm_substream_chip(subs);
- dprintk("Allocating vbuffer\n");
+ dev_dbg(dev->dev, "Allocating vbuffer\n");
if (runtime->dma_area) {
if (runtime->dma_bytes > size)
return 0;
@@ -436,16 +436,12 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
struct snd_pcm_runtime *runtime = substream->runtime;
int ret = 0;
- dprintk("opening device and trying to acquire exclusive lock\n");
-
- if (!dev) {
- cx231xx_errdev("BUG: cx231xx can't find device struct."
- " Can't proceed with open\n");
- return -ENODEV;
- }
+ dev_dbg(dev->dev,
+ "opening device and trying to acquire exclusive lock\n");
if (dev->state & DEV_DISCONNECTED) {
- cx231xx_errdev("Can't open. the device was removed.\n");
+ dev_err(dev->dev,
+ "Can't open. the device was removed.\n");
return -ENODEV;
}
@@ -458,7 +454,8 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
mutex_unlock(&dev->lock);
if (ret < 0) {
- cx231xx_errdev("failed to set alternate setting !\n");
+ dev_err(dev->dev,
+ "failed to set alternate setting !\n");
return ret;
}
@@ -484,7 +481,7 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
int ret;
struct cx231xx *dev = snd_pcm_substream_chip(substream);
- dprintk("closing device\n");
+ dev_dbg(dev->dev, "closing device\n");
/* inform hardware to stop streaming */
mutex_lock(&dev->lock);
@@ -494,7 +491,8 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
/* 1 - 48000 samples per sec */
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
if (ret < 0) {
- cx231xx_errdev("failed to set alternate setting !\n");
+ dev_err(dev->dev,
+ "failed to set alternate setting !\n");
mutex_unlock(&dev->lock);
return ret;
@@ -504,10 +502,10 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
mutex_unlock(&dev->lock);
if (dev->adev.users == 0 && dev->adev.shutdown == 1) {
- dprintk("audio users: %d\n", dev->adev.users);
- dprintk("disabling audio stream!\n");
+ dev_dbg(dev->dev, "audio users: %d\n", dev->adev.users);
+ dev_dbg(dev->dev, "disabling audio stream!\n");
dev->adev.shutdown = 0;
- dprintk("released lock\n");
+ dev_dbg(dev->dev, "released lock\n");
if (atomic_read(&dev->stream_started) > 0) {
atomic_set(&dev->stream_started, 0);
schedule_work(&dev->wq_trigger);
@@ -519,9 +517,10 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
static int snd_cx231xx_hw_capture_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *hw_params)
{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
int ret;
- dprintk("Setting capture parameters\n");
+ dev_dbg(dev->dev, "Setting capture parameters\n");
ret = snd_pcm_alloc_vmalloc_buffer(substream,
params_buffer_bytes(hw_params));
@@ -543,7 +542,7 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
- dprintk("Stop capture, if needed\n");
+ dev_dbg(dev->dev, "Stop capture, if needed\n");
if (atomic_read(&dev->stream_started) > 0) {
atomic_set(&dev->stream_started, 0);
@@ -568,7 +567,7 @@ static void audio_trigger(struct work_struct *work)
struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger);
if (atomic_read(&dev->stream_started)) {
- dprintk("starting capture");
+ dev_dbg(dev->dev, "starting capture");
if (is_fw_load(dev) == 0)
cx25840_call(dev, core, load_fw);
if (dev->USE_ISO)
@@ -576,7 +575,7 @@ static void audio_trigger(struct work_struct *work)
else
cx231xx_init_audio_bulk(dev);
} else {
- dprintk("stopping capture");
+ dev_dbg(dev->dev, "stopping capture");
cx231xx_isoc_audio_deinit(dev);
}
}
@@ -662,10 +661,10 @@ static int cx231xx_audio_init(struct cx231xx *dev)
return 0;
}
- cx231xx_info("cx231xx-audio.c: probing for cx231xx "
- "non standard usbaudio\n");
+ dev_dbg(dev->dev,
+ "probing for cx231xx non standard usbaudio\n");
- err = snd_card_new(&dev->udev->dev, index[devnr], "Cx231xx Audio",
+ err = snd_card_new(dev->dev, index[devnr], "Cx231xx Audio",
THIS_MODULE, 0, &card);
if (err < 0)
return err;
@@ -707,14 +706,13 @@ static int cx231xx_audio_init(struct cx231xx *dev)
bEndpointAddress;
adev->num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- adev->end_point_addr, adev->num_alt);
+ dev_info(dev->dev,
+ "audio EndPoint Addr 0x%x, Alternate settings: %i\n",
+ adev->end_point_addr, adev->num_alt);
adev->alt_max_pkt_size = kmalloc(32 * adev->num_alt, GFP_KERNEL);
- if (adev->alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
+ if (adev->alt_max_pkt_size == NULL)
return -ENOMEM;
- }
for (i = 0; i < adev->num_alt; i++) {
u16 tmp =
@@ -722,8 +720,9 @@ static int cx231xx_audio_init(struct cx231xx *dev)
wMaxPacketSize);
adev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- adev->alt_max_pkt_size[i]);
+ dev_dbg(dev->dev,
+ "audio alternate setting %i, max size= %i\n", i,
+ adev->alt_max_pkt_size[i]);
}
return 0;
diff --git a/drivers/media/usb/cx231xx/cx231xx-avcore.c b/drivers/media/usb/cx231xx/cx231xx-avcore.c
index 40a6987..39e8879 100644
--- a/drivers/media/usb/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/usb/cx231xx/cx231xx-avcore.c
@@ -22,12 +22,12 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bitmap.h>
-#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/mm.h>
#include <linux/mutex.h>
@@ -36,7 +36,6 @@
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include "cx231xx.h"
#include "cx231xx-dif.h"
#define TUNER_MODE_FM_RADIO 0
@@ -83,10 +82,10 @@ void initGPIO(struct cx231xx *dev)
cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0);
verve_read_byte(dev, 0x07, &val);
- cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+ dev_dbg(dev->dev, "verve_read_byte address0x07=0x%x\n", val);
verve_write_byte(dev, 0x07, 0xF4);
verve_read_byte(dev, 0x07, &val);
- cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+ dev_dbg(dev->dev, "verve_read_byte address0x07=0x%x\n", val);
cx231xx_capture_start(dev, 1, Vbi);
@@ -156,22 +155,25 @@ int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count)
while (afe_power_status != 0x18) {
status = afe_write_byte(dev, SUP_BLK_PWRDN, 0x18);
if (status < 0) {
- cx231xx_info(
- ": Init Super Block failed in send cmd\n");
+ dev_dbg(dev->dev,
+ "%s: Init Super Block failed in send cmd\n",
+ __func__);
break;
}
status = afe_read_byte(dev, SUP_BLK_PWRDN, &afe_power_status);
afe_power_status &= 0xff;
if (status < 0) {
- cx231xx_info(
- ": Init Super Block failed in receive cmd\n");
+ dev_dbg(dev->dev,
+ "%s: Init Super Block failed in receive cmd\n",
+ __func__);
break;
}
i++;
if (i == 10) {
- cx231xx_info(
- ": Init Super Block force break in loop !!!!\n");
+ dev_dbg(dev->dev,
+ "%s: Init Super Block force break in loop !!!!\n",
+ __func__);
status = -1;
break;
}
@@ -410,7 +412,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
0x00);
} else {
- cx231xx_info("Invalid AV mode input\n");
+ dev_dbg(dev->dev, "Invalid AV mode input\n");
status = -1;
}
break;
@@ -467,7 +469,7 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
status |= afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3,
0x40);
} else {
- cx231xx_info("Invalid AV mode input\n");
+ dev_dbg(dev->dev, "Invalid AV mode input\n");
status = -1;
}
} /* switch */
@@ -573,9 +575,9 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
status = cx231xx_set_power_mode(dev,
POLARIS_AVMODE_ENXTERNAL_AV);
if (status < 0) {
- cx231xx_errdev("%s: set_power_mode : Failed to"
- " set Power - errCode [%d]!\n",
- __func__, status);
+ dev_err(dev->dev,
+ "%s: Failed to set Power - errCode [%d]!\n",
+ __func__, status);
return status;
}
}
@@ -591,8 +593,8 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
status = cx231xx_set_power_mode(dev,
POLARIS_AVMODE_ANALOGT_TV);
if (status < 0) {
- cx231xx_errdev("%s: set_power_mode:Failed"
- " to set Power - errCode [%d]!\n",
+ dev_err(dev->dev,
+ "%s: Failed to set Power - errCode [%d]!\n",
__func__, status);
return status;
}
@@ -608,8 +610,8 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
break;
default:
- cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n",
- __func__, INPUT(input)->type);
+ dev_err(dev->dev, "%s: Unknown Input %d !\n",
+ __func__, INPUT(input)->type);
break;
}
@@ -628,8 +630,8 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
if (pin_type != dev->video_input) {
status = cx231xx_afe_adjust_ref_count(dev, pin_type);
if (status < 0) {
- cx231xx_errdev("%s: adjust_ref_count :Failed to set"
- "AFE input mux - errCode [%d]!\n",
+ dev_err(dev->dev,
+ "%s: adjust_ref_count :Failed to set AFE input mux - errCode [%d]!\n",
__func__, status);
return status;
}
@@ -638,9 +640,9 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
/* call afe block to set video inputs */
status = cx231xx_afe_set_input_mux(dev, input);
if (status < 0) {
- cx231xx_errdev("%s: set_input_mux :Failed to set"
- " AFE input mux - errCode [%d]!\n",
- __func__, status);
+ dev_err(dev->dev,
+ "%s: set_input_mux :Failed to set AFE input mux - errCode [%d]!\n",
+ __func__, status);
return status;
}
@@ -670,8 +672,8 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
/* Tell DIF object to go to baseband mode */
status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
if (status < 0) {
- cx231xx_errdev("%s: cx231xx_dif set to By pass"
- " mode- errCode [%d]!\n",
+ dev_err(dev->dev,
+ "%s: cx231xx_dif set to By pass mode- errCode [%d]!\n",
__func__, status);
return status;
}
@@ -715,8 +717,8 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
/* Tell DIF object to go to baseband mode */
status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
if (status < 0) {
- cx231xx_errdev("%s: cx231xx_dif set to By pass"
- " mode- errCode [%d]!\n",
+ dev_err(dev->dev,
+ "%s: cx231xx_dif set to By pass mode- errCode [%d]!\n",
__func__, status);
return status;
}
@@ -790,9 +792,9 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
status = cx231xx_dif_set_standard(dev,
DIF_USE_BASEBAND);
if (status < 0) {
- cx231xx_errdev("%s: cx231xx_dif set to By pass"
- " mode- errCode [%d]!\n",
- __func__, status);
+ dev_err(dev->dev,
+ "%s: cx231xx_dif set to By pass mode- errCode [%d]!\n",
+ __func__, status);
return status;
}
@@ -826,9 +828,9 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
/* Reinitialize the DIF */
status = cx231xx_dif_set_standard(dev, dev->norm);
if (status < 0) {
- cx231xx_errdev("%s: cx231xx_dif set to By pass"
- " mode- errCode [%d]!\n",
- __func__, status);
+ dev_err(dev->dev,
+ "%s: cx231xx_dif set to By pass mode- errCode [%d]!\n",
+ __func__, status);
return status;
}
@@ -970,14 +972,14 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
{
int status = 0;
- cx231xx_info("do_mode_ctrl_overrides : 0x%x\n",
- (unsigned int)dev->norm);
+ dev_dbg(dev->dev, "%s: 0x%x\n",
+ __func__, (unsigned int)dev->norm);
/* Change the DFE_CTRL3 bp_percent to fix flagging */
status = vid_blk_write_word(dev, DFE_CTRL3, 0xCD3F0280);
if (dev->norm & (V4L2_STD_NTSC | V4L2_STD_PAL_M)) {
- cx231xx_info("do_mode_ctrl_overrides NTSC\n");
+ dev_dbg(dev->dev, "%s: NTSC\n", __func__);
/* Move the close caption lines out of active video,
adjust the active video start point */
@@ -1004,7 +1006,7 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
(FLD_HBLANK_CNT, 0x79));
} else if (dev->norm & V4L2_STD_SECAM) {
- cx231xx_info("do_mode_ctrl_overrides SECAM\n");
+ dev_dbg(dev->dev, "%s: SECAM\n", __func__);
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
VERT_TIM_CTRL,
@@ -1031,7 +1033,7 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
cx231xx_set_field
(FLD_HBLANK_CNT, 0x85));
} else {
- cx231xx_info("do_mode_ctrl_overrides PAL\n");
+ dev_dbg(dev->dev, "%s: PAL\n", __func__);
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
VERT_TIM_CTRL,
@@ -1206,7 +1208,8 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
/* This is just a casual suggestion to people adding
new boards in case they use a tuner type we don't
currently know about */
- printk(KERN_INFO "Unknown tuner type configuring SIF");
+ dev_info(dev->dev,
+ "Unknown tuner type configuring SIF");
break;
}
break;
@@ -1270,8 +1273,13 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
int status = 0;
bool current_is_port_3;
- if (dev->board.dont_use_port_3)
- is_port_3 = false;
+ /*
+ * Should this code check dev->port_3_switch_enabled first
+ * to skip unnecessary reading of the register?
+ * If yes, the flag dev->port_3_switch_enabled must be initialized
+ * correctly.
+ */
+
status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
PWR_CTL_EN, value, 4);
if (status < 0)
@@ -1288,12 +1296,13 @@ int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
else
value[0] &= ~I2C_DEMOD_EN;
- cx231xx_info("Changing the i2c master port to %d\n",
- is_port_3 ? 3 : 1);
-
status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
PWR_CTL_EN, value, 4);
+ /* remember status of the switch for usage in is_tuner */
+ if (status >= 0)
+ dev->port_3_switch_enabled = is_port_3;
+
return status;
}
@@ -1325,113 +1334,131 @@ void cx231xx_dump_HH_reg(struct cx231xx *dev)
for (i = 0x100; i < 0x140; i++) {
vid_blk_read_word(dev, i, &value);
- cx231xx_info("reg0x%x=0x%x\n", i, value);
+ dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
i = i+3;
}
for (i = 0x300; i < 0x400; i++) {
vid_blk_read_word(dev, i, &value);
- cx231xx_info("reg0x%x=0x%x\n", i, value);
+ dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
i = i+3;
}
for (i = 0x400; i < 0x440; i++) {
vid_blk_read_word(dev, i, &value);
- cx231xx_info("reg0x%x=0x%x\n", i, value);
+ dev_dbg(dev->dev, "reg0x%x=0x%x\n", i, value);
i = i+3;
}
vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
- cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+ dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
- cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+ dev_dbg(dev->dev, "AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
}
-void cx231xx_dump_SC_reg(struct cx231xx *dev)
+#if 0
+static void cx231xx_dump_SC_reg(struct cx231xx *dev)
{
u8 value[4] = { 0, 0, 0, 0 };
- cx231xx_info("cx231xx_dump_SC_reg!\n");
+ dev_dbg(dev->dev, "%s!\n", __func__);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
- value[1], value[2], value[3]);
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
+ value[1], value[2], value[3]);
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
value, 4);
- cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
- value[1], value[2], value[3]);
-
-
+ dev_dbg(dev->dev,
+ "reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
+ value[1], value[2], value[3]);
}
+#endif
void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
@@ -1497,7 +1524,7 @@ void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
u32 standard = 0;
u8 value[4] = { 0, 0, 0, 0 };
- cx231xx_info("Enter cx231xx_set_Colibri_For_LowIF()\n");
+ dev_dbg(dev->dev, "Enter cx231xx_set_Colibri_For_LowIF()\n");
value[0] = (u8) 0x6F;
value[1] = (u8) 0x6F;
value[2] = (u8) 0x6F;
@@ -1517,7 +1544,7 @@ void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
colibri_carrier_offset = cx231xx_Get_Colibri_CarrierOffset(mode,
standard);
- cx231xx_info("colibri_carrier_offset=%d, standard=0x%x\n",
+ dev_dbg(dev->dev, "colibri_carrier_offset=%d, standard=0x%x\n",
colibri_carrier_offset, standard);
/* Set the band Pass filter for DIF*/
@@ -1551,8 +1578,8 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
u64 pll_freq_u64 = 0;
u32 i = 0;
- cx231xx_info("if_freq=%d;spectral_invert=0x%x;mode=0x%x\n",
- if_freq, spectral_invert, mode);
+ dev_dbg(dev->dev, "if_freq=%d;spectral_invert=0x%x;mode=0x%x\n",
+ if_freq, spectral_invert, mode);
if (mode == TUNER_MODE_FM_RADIO) {
@@ -1595,8 +1622,7 @@ void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
if_freq = 16000000;
}
- cx231xx_info("Enter IF=%zu\n",
- ARRAY_SIZE(Dif_set_array));
+ dev_dbg(dev->dev, "Enter IF=%zu\n", ARRAY_SIZE(Dif_set_array));
for (i = 0; i < ARRAY_SIZE(Dif_set_array); i++) {
if (Dif_set_array[i].if_freq == if_freq) {
vid_blk_write_word(dev,
@@ -1708,7 +1734,7 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
u32 dif_misc_ctrl_value = 0;
u32 func_mode = 0;
- cx231xx_info("%s: setStandard to %x\n", __func__, standard);
+ dev_dbg(dev->dev, "%s: setStandard to %x\n", __func__, standard);
status = vid_blk_read_word(dev, DIF_MISC_CTRL, &dif_misc_ctrl_value);
if (standard != DIF_USE_BASEBAND)
@@ -2111,8 +2137,8 @@ int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
{
int status = 0;
u32 dwval;
- cx231xx_info("cx231xx_tuner_post_channel_change dev->tuner_type =0%d\n",
- dev->tuner_type);
+ dev_dbg(dev->dev, "%s: dev->tuner_type =0%d\n",
+ __func__, dev->tuner_type);
/* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for
* SECAM L/B/D standards */
status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
@@ -2213,8 +2239,8 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
if (dev->power_mode != mode)
dev->power_mode = mode;
else {
- cx231xx_info(" setPowerMode::mode = %d, No Change req.\n",
- mode);
+ dev_dbg(dev->dev, "%s: mode = %d, No Change req.\n",
+ __func__, mode);
return 0;
}
@@ -2264,7 +2290,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
case POLARIS_AVMODE_ANALOGT_TV:
tmp |= PWR_DEMOD_EN;
- tmp |= (I2C_DEMOD_EN);
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
value[2] = (u8) (tmp >> 16);
@@ -2317,9 +2342,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
}
if (dev->board.tuner_type != TUNER_ABSENT) {
- /* Enable tuner */
- cx231xx_enable_i2c_port_3(dev, true);
-
/* reset the Tuner */
if (dev->board.tuner_gpio)
cx231xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -2363,7 +2385,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
}
tmp &= (~PWR_AV_MODE);
- tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN;
+ tmp |= POLARIS_AVMODE_DIGITAL;
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
value[2] = (u8) (tmp >> 16);
@@ -2384,15 +2406,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
}
if (dev->board.tuner_type != TUNER_ABSENT) {
- /*
- * Enable tuner
- * Hauppauge Exeter seems to need to do something different!
- */
- if (dev->model == CX231XX_BOARD_HAUPPAUGE_EXETER)
- cx231xx_enable_i2c_port_3(dev, false);
- else
- cx231xx_enable_i2c_port_3(dev, true);
-
/* reset the Tuner */
if (dev->board.tuner_gpio)
cx231xx_gpio_set(dev, dev->board.tuner_gpio);
@@ -2466,7 +2479,7 @@ int cx231xx_start_stream(struct cx231xx *dev, u32 ep_mask)
u32 tmp = 0;
int status = 0;
- cx231xx_info("cx231xx_start_stream():: ep_mask = %x\n", ep_mask);
+ dev_dbg(dev->dev, "%s: ep_mask = %x\n", __func__, ep_mask);
status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
value, 4);
if (status < 0)
@@ -2491,7 +2504,7 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
u32 tmp = 0;
int status = 0;
- cx231xx_info("cx231xx_stop_stream():: ep_mask = %x\n", ep_mask);
+ dev_dbg(dev->dev, "%s: ep_mask = %x\n", __func__, ep_mask);
status =
cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET, value, 4);
if (status < 0)
@@ -2519,61 +2532,72 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
if (dev->udev->speed == USB_SPEED_HIGH) {
switch (media_type) {
case Audio:
- cx231xx_info("%s: Audio enter HANC\n", __func__);
+ dev_dbg(dev->dev,
+ "%s: Audio enter HANC\n", __func__);
status =
cx231xx_mode_register(dev, TS_MODE_REG, 0x9300);
break;
case Vbi:
- cx231xx_info("%s: set vanc registers\n", __func__);
+ dev_dbg(dev->dev,
+ "%s: set vanc registers\n", __func__);
status = cx231xx_mode_register(dev, TS_MODE_REG, 0x300);
break;
case Sliced_cc:
- cx231xx_info("%s: set hanc registers\n", __func__);
+ dev_dbg(dev->dev,
+ "%s: set hanc registers\n", __func__);
status =
cx231xx_mode_register(dev, TS_MODE_REG, 0x1300);
break;
case Raw_Video:
- cx231xx_info("%s: set video registers\n", __func__);
+ dev_dbg(dev->dev,
+ "%s: set video registers\n", __func__);
status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
break;
case TS1_serial_mode:
- cx231xx_info("%s: set ts1 registers", __func__);
-
- if (dev->board.has_417) {
- cx231xx_info(" MPEG\n");
- value &= 0xFFFFFFFC;
- value |= 0x3;
-
- status = cx231xx_mode_register(dev, TS_MODE_REG, value);
-
- val[0] = 0x04;
- val[1] = 0xA3;
- val[2] = 0x3B;
- val[3] = 0x00;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- TS1_CFG_REG, val, 4);
-
- val[0] = 0x00;
- val[1] = 0x08;
- val[2] = 0x00;
- val[3] = 0x08;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- TS1_LENGTH_REG, val, 4);
-
- } else {
- cx231xx_info(" BDA\n");
- status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
- status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x010);
- }
+ dev_dbg(dev->dev,
+ "%s: set ts1 registers", __func__);
+
+ if (dev->board.has_417) {
+ dev_dbg(dev->dev,
+ "%s: MPEG\n", __func__);
+ value &= 0xFFFFFFFC;
+ value |= 0x3;
+
+ status = cx231xx_mode_register(dev,
+ TS_MODE_REG, value);
+
+ val[0] = 0x04;
+ val[1] = 0xA3;
+ val[2] = 0x3B;
+ val[3] = 0x00;
+ status = cx231xx_write_ctrl_reg(dev,
+ VRT_SET_REGISTER,
+ TS1_CFG_REG, val, 4);
+
+ val[0] = 0x00;
+ val[1] = 0x08;
+ val[2] = 0x00;
+ val[3] = 0x08;
+ status = cx231xx_write_ctrl_reg(dev,
+ VRT_SET_REGISTER,
+ TS1_LENGTH_REG, val, 4);
+ } else {
+ dev_dbg(dev->dev, "%s: BDA\n", __func__);
+ status = cx231xx_mode_register(dev,
+ TS_MODE_REG, 0x101);
+ status = cx231xx_mode_register(dev,
+ TS1_CFG_REG, 0x010);
+ }
break;
case TS1_parallel_mode:
- cx231xx_info("%s: set ts1 parallel mode registers\n",
- __func__);
+ dev_dbg(dev->dev,
+ "%s: set ts1 parallel mode registers\n",
+ __func__);
status = cx231xx_mode_register(dev, TS_MODE_REG, 0x100);
status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
break;
@@ -2926,8 +2950,9 @@ int cx231xx_gpio_i2c_read_ack(struct cx231xx *dev)
(nCnt > 0));
if (nCnt == 0)
- cx231xx_info("No ACK after %d msec -GPIO I2C failed!",
- nInit * 10);
+ dev_dbg(dev->dev,
+ "No ACK after %d msec -GPIO I2C failed!",
+ nInit * 10);
/*
* readAck
diff --git a/drivers/media/usb/cx231xx/cx231xx-cards.c b/drivers/media/usb/cx231xx/cx231xx-cards.c
index 791f00c..ae05d59 100644
--- a/drivers/media/usb/cx231xx/cx231xx-cards.c
+++ b/drivers/media/usb/cx231xx/cx231xx-cards.c
@@ -20,12 +20,12 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/init.h>
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/usb.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
@@ -35,7 +35,6 @@
#include "xc5000.h"
#include "tda18271.h"
-#include "cx231xx.h"
static int tuner = -1;
module_param(tuner, int, 0444);
@@ -104,8 +103,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x02,
.norm = V4L2_STD_PAL,
@@ -144,8 +143,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x32,
.norm = V4L2_STD_NTSC,
@@ -184,8 +183,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x1c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x02,
.norm = V4L2_STD_PAL,
@@ -225,8 +224,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x1c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x02,
.norm = V4L2_STD_PAL,
@@ -262,7 +261,6 @@ struct cx231xx_board cx231xx_boards[] = {
.norm = V4L2_STD_PAL,
.no_alt_vanc = 1,
.external_av = 1,
- .dont_use_port_3 = 1,
/* Actually, it has a 417, but it isn't working correctly.
* So set to 0 for now until someone can manage to get this
* to work reliably. */
@@ -297,8 +295,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x02,
.norm = V4L2_STD_PAL,
@@ -325,8 +323,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x32,
.norm = V4L2_STD_NTSC,
@@ -353,8 +351,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_1,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_NTSC,
@@ -390,7 +388,6 @@ struct cx231xx_board cx231xx_boards[] = {
.norm = V4L2_STD_NTSC,
.no_alt_vanc = 1,
.external_av = 1,
- .dont_use_port_3 = 1,
.input = {{
.type = CX231XX_VMUX_COMPOSITE1,
.vmux = CX231XX_VIN_2_1,
@@ -418,9 +415,9 @@ struct cx231xx_board cx231xx_boards[] = {
.tuner_scl_gpio = -1,
.tuner_sda_gpio = -1,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 2,
- .demod_i2c_master = 1,
- .ir_i2c_master = 2,
+ .tuner_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_3,
+ .ir_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x10,
.norm = V4L2_STD_PAL_M,
@@ -456,9 +453,9 @@ struct cx231xx_board cx231xx_boards[] = {
.tuner_scl_gpio = -1,
.tuner_sda_gpio = -1,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 2,
- .demod_i2c_master = 1,
- .ir_i2c_master = 2,
+ .tuner_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_3,
+ .ir_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x10,
.norm = V4L2_STD_NTSC_M,
@@ -494,9 +491,9 @@ struct cx231xx_board cx231xx_boards[] = {
.tuner_scl_gpio = -1,
.tuner_sda_gpio = -1,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 2,
- .demod_i2c_master = 1,
- .ir_i2c_master = 2,
+ .tuner_i2c_master = I2C_2,
+ .demod_i2c_master = I2C_1_MUX_3,
+ .ir_i2c_master = I2C_2,
.rc_map_name = RC_MAP_PIXELVIEW_002T,
.has_dvb = 1,
.demod_addr = 0x10,
@@ -532,7 +529,6 @@ struct cx231xx_board cx231xx_boards[] = {
.norm = V4L2_STD_NTSC,
.no_alt_vanc = 1,
.external_av = 1,
- .dont_use_port_3 = 1,
.input = {{
.type = CX231XX_VMUX_COMPOSITE1,
@@ -587,7 +583,7 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
+ .tuner_i2c_master = I2C_1_MUX_3,
.norm = V4L2_STD_PAL,
.input = {{
@@ -622,7 +618,7 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
+ .tuner_i2c_master = I2C_1_MUX_3,
.norm = V4L2_STD_NTSC,
.input = {{
@@ -656,7 +652,6 @@ struct cx231xx_board cx231xx_boards[] = {
.norm = V4L2_STD_NTSC,
.no_alt_vanc = 1,
.external_av = 1,
- .dont_use_port_3 = 1,
.input = {{
.type = CX231XX_VMUX_COMPOSITE1,
.vmux = CX231XX_VIN_2_1,
@@ -677,13 +672,12 @@ struct cx231xx_board cx231xx_boards[] = {
.decoder = CX231XX_AVDECODER,
.output_mode = OUT_MODE_VIP11,
.ctl_pin_status_mask = 0xFFFFFFC4,
- .agc_analog_digital_select_gpio = 0x0c,
+ .agc_analog_digital_select_gpio = 0x0c,
/* According with PV CxPlrCAP.inf file */
.gpio_pin_status_mask = 0x4001000,
.norm = V4L2_STD_NTSC,
.no_alt_vanc = 1,
.external_av = 1,
- .dont_use_port_3 = 1,
/*.has_417 = 1, */
/* This board is believed to have a hardware encoding chip
* supporting mpeg1/2/4, but as the 417 is apparently not
@@ -718,8 +712,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_PAL,
@@ -757,8 +751,8 @@ struct cx231xx_board cx231xx_boards[] = {
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
.gpio_pin_status_mask = 0x4001000,
- .tuner_i2c_master = 1,
- .demod_i2c_master = 2,
+ .tuner_i2c_master = I2C_1_MUX_3,
+ .demod_i2c_master = I2C_2,
.has_dvb = 1,
.demod_addr = 0x0e,
.norm = V4L2_STD_PAL,
@@ -861,9 +855,9 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
if (dev->tuner_type == TUNER_XC5000) {
if (command == XC5000_TUNER_RESET) {
- cx231xx_info
- ("Tuner CB: RESET: cmd %d : tuner type %d \n",
- command, dev->tuner_type);
+ dev_dbg(dev->dev,
+ "Tuner CB: RESET: cmd %d : tuner type %d\n",
+ command, dev->tuner_type);
cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit,
1);
msleep(10);
@@ -921,8 +915,8 @@ void cx231xx_pre_card_setup(struct cx231xx *dev)
cx231xx_set_model(dev);
- cx231xx_info("Identified as %s (card=%d)\n",
- dev->board.name, dev->model);
+ dev_info(dev->dev, "Identified as %s (card=%d)\n",
+ dev->board.name, dev->model);
/* set the direction for GPIO pins */
if (dev->board.tuner_gpio) {
@@ -980,25 +974,22 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
}
-static int read_eeprom(struct cx231xx *dev, u8 *eedata, int len)
+static int read_eeprom(struct cx231xx *dev, struct i2c_client *client,
+ u8 *eedata, int len)
{
int ret = 0;
- u8 addr = 0xa0 >> 1;
u8 start_offset = 0;
int len_todo = len;
u8 *eedata_cur = eedata;
int i;
- struct i2c_msg msg_write = { .addr = addr, .flags = 0,
+ struct i2c_msg msg_write = { .addr = client->addr, .flags = 0,
.buf = &start_offset, .len = 1 };
- struct i2c_msg msg_read = { .addr = addr, .flags = I2C_M_RD };
-
- /* mutex_lock(&dev->i2c_lock); */
- cx231xx_enable_i2c_port_3(dev, false);
+ struct i2c_msg msg_read = { .addr = client->addr, .flags = I2C_M_RD };
/* start reading at offset 0 */
- ret = i2c_transfer(&dev->i2c_bus[1].i2c_adap, &msg_write, 1);
+ ret = i2c_transfer(client->adapter, &msg_write, 1);
if (ret < 0) {
- cx231xx_err("Can't read eeprom\n");
+ dev_err(dev->dev, "Can't read eeprom\n");
return ret;
}
@@ -1006,20 +997,18 @@ static int read_eeprom(struct cx231xx *dev, u8 *eedata, int len)
msg_read.len = (len_todo > 64) ? 64 : len_todo;
msg_read.buf = eedata_cur;
- ret = i2c_transfer(&dev->i2c_bus[1].i2c_adap, &msg_read, 1);
+ ret = i2c_transfer(client->adapter, &msg_read, 1);
if (ret < 0) {
- cx231xx_err("Can't read eeprom\n");
+ dev_err(dev->dev, "Can't read eeprom\n");
return ret;
}
eedata_cur += msg_read.len;
len_todo -= msg_read.len;
}
- cx231xx_enable_i2c_port_3(dev, true);
- /* mutex_unlock(&dev->i2c_lock); */
-
for (i = 0; i + 15 < len; i += 16)
- cx231xx_info("i2c eeprom %02x: %*ph\n", i, 16, &eedata[i]);
+ dev_dbg(dev->dev, "i2c eeprom %02x: %*ph\n",
+ i, 16, &eedata[i]);
return 0;
}
@@ -1036,22 +1025,26 @@ void cx231xx_card_setup(struct cx231xx *dev)
/* request some modules */
if (dev->board.decoder == CX231XX_AVDECODER) {
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_bus[0].i2c_adap,
+ cx231xx_get_i2c_adap(dev, I2C_0),
"cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840 == NULL)
- cx231xx_info("cx25840 subdev registration failure\n");
+ dev_err(dev->dev,
+ "cx25840 subdev registration failure\n");
cx25840_call(dev, core, load_fw);
}
/* Initialize the tuner */
if (dev->board.tuner_type != TUNER_ABSENT) {
+ struct i2c_adapter *tuner_i2c = cx231xx_get_i2c_adap(dev,
+ dev->board.tuner_i2c_master);
dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ tuner_i2c,
"tuner",
dev->tuner_addr, NULL);
if (dev->sd_tuner == NULL)
- cx231xx_info("tuner subdev registration failure\n");
+ dev_err(dev->dev,
+ "tuner subdev registration failure\n");
else
cx231xx_config_tuner(dev);
}
@@ -1062,9 +1055,14 @@ void cx231xx_card_setup(struct cx231xx *dev)
{
struct tveeprom tvee;
static u8 eeprom[256];
+ struct i2c_client client;
+
+ memset(&client, 0, sizeof(client));
+ client.adapter = cx231xx_get_i2c_adap(dev, I2C_1_MUX_1);
+ client.addr = 0xa0 >> 1;
- read_eeprom(dev, eeprom, sizeof(eeprom));
- tveeprom_hauppauge_analog(&dev->i2c_bus[1].i2c_client,
+ read_eeprom(dev, &client, eeprom, sizeof(eeprom));
+ tveeprom_hauppauge_analog(&client,
&tvee, eeprom + 0xc0);
break;
}
@@ -1152,7 +1150,7 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
/* Query cx231xx to find what pcb config it is related to */
retval = initialize_cx231xx(dev);
if (retval < 0) {
- cx231xx_errdev("Failed to read PCB config\n");
+ dev_err(dev->dev, "Failed to read PCB config\n");
return retval;
}
@@ -1168,7 +1166,7 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
retval = cx231xx_config(dev);
if (retval) {
- cx231xx_errdev("error configuring device\n");
+ dev_err(dev->dev, "error configuring device\n");
return -ENOMEM;
}
@@ -1178,8 +1176,9 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
/* register i2c bus */
retval = cx231xx_dev_init(dev);
if (retval) {
- cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
- __func__, retval);
+ dev_err(dev->dev,
+ "%s: cx231xx_i2c_register - errCode [%d]!\n",
+ __func__, retval);
goto err_dev_init;
}
@@ -1200,8 +1199,8 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
retval = cx231xx_config(dev);
if (retval) {
- cx231xx_errdev("%s: cx231xx_config - errCode [%d]!\n",
- __func__, retval);
+ dev_err(dev->dev, "%s: cx231xx_config - errCode [%d]!\n",
+ __func__, retval);
goto err_dev_init;
}
@@ -1217,11 +1216,11 @@ static int cx231xx_init_dev(struct cx231xx *dev, struct usb_device *udev,
cx231xx_add_into_devlist(dev);
if (dev->board.has_417) {
- printk(KERN_INFO "attach 417 %d\n", dev->model);
+ dev_info(dev->dev, "attach 417 %d\n", dev->model);
if (cx231xx_417_register(dev) < 0) {
- printk(KERN_ERR
+ dev_err(dev->dev,
"%s() Failed to register 417 on VID_B\n",
- __func__);
+ __func__);
}
}
@@ -1285,7 +1284,8 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
/* compute alternate max packet sizes for video */
idx = dev->current_pcb_config.hs_config_info[0].interface_info.video_index + 1;
if (idx >= dev->max_iad_interface_count) {
- cx231xx_errdev("Video PCB interface #%d doesn't exist\n", idx);
+ dev_err(dev->dev,
+ "Video PCB interface #%d doesn't exist\n", idx);
return -ENODEV;
}
@@ -1294,28 +1294,29 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
dev->video_mode.end_point_addr = uif->altsetting[0].endpoint[isoc_pipe].desc.bEndpointAddress;
dev->video_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->video_mode.end_point_addr,
- dev->video_mode.num_alt);
+ dev_info(dev->dev,
+ "video EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->video_mode.end_point_addr,
+ dev->video_mode.num_alt);
dev->video_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->video_mode.num_alt, GFP_KERNEL);
- if (dev->video_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
+ if (dev->video_mode.alt_max_pkt_size == NULL)
return -ENOMEM;
- }
for (i = 0; i < dev->video_mode.num_alt; i++) {
u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].desc.wMaxPacketSize);
dev->video_mode.alt_max_pkt_size[i] = (tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->video_mode.alt_max_pkt_size[i]);
+ dev_dbg(dev->dev,
+ "Alternate setting %i, max size= %i\n", i,
+ dev->video_mode.alt_max_pkt_size[i]);
}
/* VBI Init */
idx = dev->current_pcb_config.hs_config_info[0].interface_info.vanc_index + 1;
if (idx >= dev->max_iad_interface_count) {
- cx231xx_errdev("VBI PCB interface #%d doesn't exist\n", idx);
+ dev_err(dev->dev,
+ "VBI PCB interface #%d doesn't exist\n", idx);
return -ENODEV;
}
uif = udev->actconfig->interface[idx];
@@ -1325,16 +1326,15 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
bEndpointAddress;
dev->vbi_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->vbi_mode.end_point_addr,
- dev->vbi_mode.num_alt);
+ dev_info(dev->dev,
+ "VBI EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->vbi_mode.end_point_addr,
+ dev->vbi_mode.num_alt);
/* compute alternate max packet sizes for vbi */
dev->vbi_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->vbi_mode.num_alt, GFP_KERNEL);
- if (dev->vbi_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
+ if (dev->vbi_mode.alt_max_pkt_size == NULL)
return -ENOMEM;
- }
for (i = 0; i < dev->vbi_mode.num_alt; i++) {
u16 tmp =
@@ -1342,8 +1342,9 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
desc.wMaxPacketSize);
dev->vbi_mode.alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->vbi_mode.alt_max_pkt_size[i]);
+ dev_dbg(dev->dev,
+ "Alternate setting %i, max size= %i\n", i,
+ dev->vbi_mode.alt_max_pkt_size[i]);
}
/* Sliced CC VBI init */
@@ -1351,7 +1352,8 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
/* compute alternate max packet sizes for sliced CC */
idx = dev->current_pcb_config.hs_config_info[0].interface_info.hanc_index + 1;
if (idx >= dev->max_iad_interface_count) {
- cx231xx_errdev("Sliced CC PCB interface #%d doesn't exist\n", idx);
+ dev_err(dev->dev,
+ "Sliced CC PCB interface #%d doesn't exist\n", idx);
return -ENODEV;
}
uif = udev->actconfig->interface[idx];
@@ -1361,23 +1363,22 @@ static int cx231xx_init_v4l2(struct cx231xx *dev,
bEndpointAddress;
dev->sliced_cc_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->sliced_cc_mode.end_point_addr,
- dev->sliced_cc_mode.num_alt);
+ dev_info(dev->dev,
+ "sliced CC EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->sliced_cc_mode.end_point_addr,
+ dev->sliced_cc_mode.num_alt);
dev->sliced_cc_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->sliced_cc_mode.num_alt, GFP_KERNEL);
-
- if (dev->sliced_cc_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
+ if (dev->sliced_cc_mode.alt_max_pkt_size == NULL)
return -ENOMEM;
- }
for (i = 0; i < dev->sliced_cc_mode.num_alt; i++) {
u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[isoc_pipe].
desc.wMaxPacketSize);
dev->sliced_cc_mode.alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->sliced_cc_mode.alt_max_pkt_size[i]);
+ dev_dbg(dev->dev,
+ "Alternate setting %i, max size= %i\n", i,
+ dev->sliced_cc_mode.alt_max_pkt_size[i]);
}
return 0;
@@ -1391,6 +1392,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
const struct usb_device_id *id)
{
struct usb_device *udev;
+ struct device *d = &interface->dev;
struct usb_interface *uif;
struct cx231xx *dev = NULL;
int retval = -ENODEV;
@@ -1401,6 +1403,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
struct usb_interface_assoc_descriptor *assoc_desc;
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
+ udev = usb_get_dev(interface_to_usbdev(interface));
/*
* Interface number 0 - IR interface (handled by mceusb driver)
@@ -1414,18 +1417,16 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
nr = find_first_zero_bit(&cx231xx_devused, CX231XX_MAXBOARDS);
if (nr >= CX231XX_MAXBOARDS) {
/* No free device slots */
- cx231xx_err(DRIVER_NAME ": Supports only %i devices.\n",
- CX231XX_MAXBOARDS);
+ dev_err(d,
+ "Supports only %i devices.\n",
+ CX231XX_MAXBOARDS);
return -ENOMEM;
}
} while (test_and_set_bit(nr, &cx231xx_devused));
- udev = usb_get_dev(interface_to_usbdev(interface));
-
/* allocate memory for our device state and initialize it */
dev = devm_kzalloc(&udev->dev, sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
- cx231xx_err(DRIVER_NAME ": out of memory!\n");
clear_bit(nr, &cx231xx_devused);
return -ENOMEM;
}
@@ -1434,6 +1435,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
dev->devno = nr;
dev->model = id->driver_info;
dev->video_mode.alt = -1;
+ dev->dev = d;
dev->interface_count++;
/* reset gpio dir and value */
@@ -1472,14 +1474,14 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
speed = "unknown";
}
- cx231xx_info("New device %s %s @ %s Mbps "
- "(%04x:%04x) with %d interfaces\n",
- udev->manufacturer ? udev->manufacturer : "",
- udev->product ? udev->product : "",
- speed,
- le16_to_cpu(udev->descriptor.idVendor),
- le16_to_cpu(udev->descriptor.idProduct),
- dev->max_iad_interface_count);
+ dev_info(d,
+ "New device %s %s @ %s Mbps (%04x:%04x) with %d interfaces\n",
+ udev->manufacturer ? udev->manufacturer : "",
+ udev->product ? udev->product : "",
+ speed,
+ le16_to_cpu(udev->descriptor.idVendor),
+ le16_to_cpu(udev->descriptor.idProduct),
+ dev->max_iad_interface_count);
/* increment interface count */
dev->interface_count++;
@@ -1489,13 +1491,12 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
assoc_desc = udev->actconfig->intf_assoc[0];
if (assoc_desc->bFirstInterface != ifnum) {
- cx231xx_err(DRIVER_NAME ": Not found "
- "matching IAD interface\n");
+ dev_err(d, "Not found matching IAD interface\n");
retval = -ENODEV;
goto err_if;
}
- cx231xx_info("registering interface %d\n", ifnum);
+ dev_dbg(d, "registering interface %d\n", ifnum);
/* save our data pointer in this interface device */
usb_set_intfdata(interface, dev);
@@ -1503,7 +1504,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* Create v4l2 device */
retval = v4l2_device_register(&interface->dev, &dev->v4l2_dev);
if (retval) {
- cx231xx_errdev("v4l2_device_register failed\n");
+ dev_err(d, "v4l2_device_register failed\n");
goto err_v4l2;
}
@@ -1520,7 +1521,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* compute alternate max packet sizes for TS1 */
idx = dev->current_pcb_config.hs_config_info[0].interface_info.ts1_index + 1;
if (idx >= dev->max_iad_interface_count) {
- cx231xx_errdev("TS1 PCB interface #%d doesn't exist\n", idx);
+ dev_err(d, "TS1 PCB interface #%d doesn't exist\n",
+ idx);
retval = -ENODEV;
goto err_video_alt;
}
@@ -1531,13 +1533,13 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
desc.bEndpointAddress;
dev->ts1_mode.num_alt = uif->num_altsetting;
- cx231xx_info("EndPoint Addr 0x%x, Alternate settings: %i\n",
- dev->ts1_mode.end_point_addr,
- dev->ts1_mode.num_alt);
+ dev_info(d,
+ "TS EndPoint Addr 0x%x, Alternate settings: %i\n",
+ dev->ts1_mode.end_point_addr,
+ dev->ts1_mode.num_alt);
dev->ts1_mode.alt_max_pkt_size = devm_kmalloc_array(&udev->dev, 32, dev->ts1_mode.num_alt, GFP_KERNEL);
if (dev->ts1_mode.alt_max_pkt_size == NULL) {
- cx231xx_errdev("out of memory!\n");
retval = -ENOMEM;
goto err_video_alt;
}
@@ -1548,8 +1550,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
wMaxPacketSize);
dev->ts1_mode.alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- cx231xx_info("Alternate setting %i, max size= %i\n", i,
- dev->ts1_mode.alt_max_pkt_size[i]);
+ dev_dbg(d, "Alternate setting %i, max size= %i\n",
+ i, dev->ts1_mode.alt_max_pkt_size[i]);
}
}
@@ -1613,10 +1615,9 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
wake_up_interruptible_all(&dev->open);
if (dev->users) {
- cx231xx_warn
- ("device %s is open! Deregistration and memory "
- "deallocation are deferred on close.\n",
- video_device_node_name(dev->vdev));
+ dev_warn(dev->dev,
+ "device %s is open! Deregistration and memory deallocation are deferred on close.\n",
+ video_device_node_name(dev->vdev));
/* Even having users, it is safe to remove the RC i2c driver */
cx231xx_ir_exit(dev);
diff --git a/drivers/media/usb/cx231xx/cx231xx-core.c b/drivers/media/usb/cx231xx/cx231xx-core.c
index 180103e..4a3f28c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-core.c
+++ b/drivers/media/usb/cx231xx/cx231xx-core.c
@@ -20,16 +20,15 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/slab.h>
-#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
-#include "cx231xx.h"
#include "cx231xx-reg.h"
/* #define ENABLE_DEBUG_ISOC_FRAMES */
@@ -99,10 +98,10 @@ int cx231xx_register_extension(struct cx231xx_ops *ops)
mutex_lock(&cx231xx_devlist_mutex);
list_add_tail(&ops->next, &cx231xx_extension_devlist);
- list_for_each_entry(dev, &cx231xx_devlist, devlist)
+ list_for_each_entry(dev, &cx231xx_devlist, devlist) {
ops->init(dev);
-
- printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name);
+ dev_info(dev->dev, "%s initialized\n", ops->name);
+ }
mutex_unlock(&cx231xx_devlist_mutex);
return 0;
}
@@ -113,11 +112,11 @@ void cx231xx_unregister_extension(struct cx231xx_ops *ops)
struct cx231xx *dev = NULL;
mutex_lock(&cx231xx_devlist_mutex);
- list_for_each_entry(dev, &cx231xx_devlist, devlist)
+ list_for_each_entry(dev, &cx231xx_devlist, devlist) {
ops->fini(dev);
+ dev_info(dev->dev, "%s removed\n", ops->name);
+ }
-
- printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name);
list_del(&ops->next);
mutex_unlock(&cx231xx_devlist_mutex);
}
@@ -227,10 +226,9 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
/* call common vendor command request */
status = cx231xx_send_vendor_cmd(dev, &ven_req);
- if (status < 0) {
- cx231xx_info
- ("UsbInterface::sendCommand, failed with status -%d\n",
- status);
+ if (status < 0 && !dev->i2c_scan_running) {
+ dev_err(dev->dev, "%s: failed with status -%d\n",
+ __func__, status);
}
return status;
@@ -524,9 +522,9 @@ int cx231xx_set_video_alternate(struct cx231xx *dev)
usb_set_interface(dev->udev, usb_interface_index,
dev->video_mode.alt);
if (errCode < 0) {
- cx231xx_errdev
- ("cannot change alt number to %d (error=%i)\n",
- dev->video_mode.alt, errCode);
+ dev_err(dev->dev,
+ "cannot change alt number to %d (error=%i)\n",
+ dev->video_mode.alt, errCode);
return errCode;
}
}
@@ -600,9 +598,9 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
}
if (alt > 0 && max_pkt_size == 0) {
- cx231xx_errdev
- ("can't change interface %d alt no. to %d: Max. Pkt size = 0\n",
- usb_interface_index, alt);
+ dev_err(dev->dev,
+ "can't change interface %d alt no. to %d: Max. Pkt size = 0\n",
+ usb_interface_index, alt);
/*To workaround error number=-71 on EP0 for videograbber,
need add following codes.*/
if (dev->board.no_alt_vanc)
@@ -616,9 +614,9 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
if (usb_interface_index > 0) {
status = usb_set_interface(dev->udev, usb_interface_index, alt);
if (status < 0) {
- cx231xx_errdev
- ("can't change interface %d alt no. to %d (err=%i)\n",
- usb_interface_index, alt, status);
+ dev_err(dev->dev,
+ "can't change interface %d alt no. to %d (err=%i)\n",
+ usb_interface_index, alt, status);
return status;
}
}
@@ -767,18 +765,17 @@ int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size)
u32 *buffer;
buffer = kzalloc(4096, GFP_KERNEL);
- if (buffer == NULL) {
- cx231xx_info("out of mem\n");
+ if (buffer == NULL)
return -ENOMEM;
- }
memcpy(&buffer[0], firmware, 4096);
ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5),
buffer, 4096, &actlen, 2000);
if (ret)
- cx231xx_info("bulk message failed: %d (%d/%d)", ret,
- size, actlen);
+ dev_err(dev->dev,
+ "bulk message failed: %d (%d/%d)", ret,
+ size, actlen);
else {
errCode = actlen != size ? -1 : 0;
}
@@ -987,12 +984,8 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
cx231xx_uninit_isoc(dev);
dma_q->p_left_data = kzalloc(4096, GFP_KERNEL);
- if (dma_q->p_left_data == NULL) {
- cx231xx_info("out of mem\n");
+ if (dma_q->p_left_data == NULL)
return -ENOMEM;
- }
-
-
dev->video_mode.isoc_ctl.isoc_copy = isoc_copy;
dev->video_mode.isoc_ctl.num_bufs = num_bufs;
@@ -1018,14 +1011,16 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
dev->video_mode.isoc_ctl.urb =
kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
if (!dev->video_mode.isoc_ctl.urb) {
- cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ dev_err(dev->dev,
+ "cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
dev->video_mode.isoc_ctl.transfer_buffer =
kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
if (!dev->video_mode.isoc_ctl.transfer_buffer) {
- cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ dev_err(dev->dev,
+ "cannot allocate memory for usbtransfer\n");
kfree(dev->video_mode.isoc_ctl.urb);
return -ENOMEM;
}
@@ -1045,7 +1040,8 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
urb = usb_alloc_urb(max_packets, GFP_KERNEL);
if (!urb) {
- cx231xx_err("cannot alloc isoc_ctl.urb %i\n", i);
+ dev_err(dev->dev,
+ "cannot alloc isoc_ctl.urb %i\n", i);
cx231xx_uninit_isoc(dev);
return -ENOMEM;
}
@@ -1055,10 +1051,10 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
&urb->transfer_dma);
if (!dev->video_mode.isoc_ctl.transfer_buffer[i]) {
- cx231xx_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
+ dev_err(dev->dev,
+ "unable to allocate %i bytes for transfer buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
cx231xx_uninit_isoc(dev);
return -ENOMEM;
}
@@ -1090,8 +1086,9 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
rc = usb_submit_urb(dev->video_mode.isoc_ctl.urb[i],
GFP_ATOMIC);
if (rc) {
- cx231xx_err("submit of urb %i failed (error=%i)\n", i,
- rc);
+ dev_err(dev->dev,
+ "submit of urb %i failed (error=%i)\n", i,
+ rc);
cx231xx_uninit_isoc(dev);
return rc;
}
@@ -1151,14 +1148,16 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
dev->video_mode.bulk_ctl.urb =
kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
if (!dev->video_mode.bulk_ctl.urb) {
- cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ dev_err(dev->dev,
+ "cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
dev->video_mode.bulk_ctl.transfer_buffer =
kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
if (!dev->video_mode.bulk_ctl.transfer_buffer) {
- cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ dev_err(dev->dev,
+ "cannot allocate memory for usbtransfer\n");
kfree(dev->video_mode.bulk_ctl.urb);
return -ENOMEM;
}
@@ -1178,7 +1177,8 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
+ dev_err(dev->dev,
+ "cannot alloc bulk_ctl.urb %i\n", i);
cx231xx_uninit_bulk(dev);
return -ENOMEM;
}
@@ -1189,10 +1189,10 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
&urb->transfer_dma);
if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) {
- cx231xx_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n",
- sb_size, i,
- in_interrupt() ? " while in int" : "");
+ dev_err(dev->dev,
+ "unable to allocate %i bytes for transfer buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
cx231xx_uninit_bulk(dev);
return -ENOMEM;
}
@@ -1212,8 +1212,8 @@ int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
rc = usb_submit_urb(dev->video_mode.bulk_ctl.urb[i],
GFP_ATOMIC);
if (rc) {
- cx231xx_err("submit of urb %i failed (error=%i)\n", i,
- rc);
+ dev_err(dev->dev,
+ "submit of urb %i failed (error=%i)\n", i, rc);
cx231xx_uninit_bulk(dev);
return rc;
}
@@ -1300,6 +1300,15 @@ int cx231xx_dev_init(struct cx231xx *dev)
cx231xx_i2c_register(&dev->i2c_bus[1]);
cx231xx_i2c_register(&dev->i2c_bus[2]);
+ cx231xx_i2c_mux_register(dev, 0);
+ cx231xx_i2c_mux_register(dev, 1);
+
+ /* scan the real bus segments in the order of physical port numbers */
+ cx231xx_do_i2c_scan(dev, I2C_0);
+ cx231xx_do_i2c_scan(dev, I2C_1_MUX_1);
+ cx231xx_do_i2c_scan(dev, I2C_2);
+ cx231xx_do_i2c_scan(dev, I2C_1_MUX_3);
+
/* init hardware */
/* Note : with out calling set power mode function,
afe can not be set up correctly */
@@ -1307,18 +1316,18 @@ int cx231xx_dev_init(struct cx231xx *dev)
errCode = cx231xx_set_power_mode(dev,
POLARIS_AVMODE_ENXTERNAL_AV);
if (errCode < 0) {
- cx231xx_errdev
- ("%s: Failed to set Power - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: Failed to set Power - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
} else {
errCode = cx231xx_set_power_mode(dev,
POLARIS_AVMODE_ANALOGT_TV);
if (errCode < 0) {
- cx231xx_errdev
- ("%s: Failed to set Power - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: Failed to set Power - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
}
@@ -1331,42 +1340,43 @@ int cx231xx_dev_init(struct cx231xx *dev)
/* initialize Colibri block */
errCode = cx231xx_afe_init_super_block(dev, 0x23c);
if (errCode < 0) {
- cx231xx_errdev
- ("%s: cx231xx_afe init super block - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: cx231xx_afe init super block - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
errCode = cx231xx_afe_init_channels(dev);
if (errCode < 0) {
- cx231xx_errdev
- ("%s: cx231xx_afe init channels - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: cx231xx_afe init channels - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
/* Set DIF in By pass mode */
errCode = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
if (errCode < 0) {
- cx231xx_errdev
- ("%s: cx231xx_dif set to By pass mode - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: cx231xx_dif set to By pass mode - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
/* I2S block related functions */
errCode = cx231xx_i2s_blk_initialize(dev);
if (errCode < 0) {
- cx231xx_errdev
- ("%s: cx231xx_i2s block initialize - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: cx231xx_i2s block initialize - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
/* init control pins */
errCode = cx231xx_init_ctrl_pin_status(dev);
if (errCode < 0) {
- cx231xx_errdev("%s: cx231xx_init ctrl pins - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: cx231xx_init ctrl pins - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
@@ -1391,9 +1401,9 @@ int cx231xx_dev_init(struct cx231xx *dev)
break;
}
if (errCode < 0) {
- cx231xx_errdev
- ("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n",
- __func__, errCode);
+ dev_err(dev->dev,
+ "%s: cx231xx_AGC mode to Analog - errCode [%d]!\n",
+ __func__, errCode);
return errCode;
}
@@ -1404,9 +1414,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
if (dev->board.has_dvb)
cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
- /* set the I2C master port to 3 on channel 1 */
- errCode = cx231xx_enable_i2c_port_3(dev, true);
-
+ errCode = 0;
return errCode;
}
EXPORT_SYMBOL_GPL(cx231xx_dev_init);
@@ -1414,6 +1422,8 @@ EXPORT_SYMBOL_GPL(cx231xx_dev_init);
void cx231xx_dev_uninit(struct cx231xx *dev)
{
/* Un Initialize I2C bus */
+ cx231xx_i2c_mux_unregister(dev, 1);
+ cx231xx_i2c_mux_unregister(dev, 0);
cx231xx_i2c_unregister(&dev->i2c_bus[2]);
cx231xx_i2c_unregister(&dev->i2c_bus[1]);
cx231xx_i2c_unregister(&dev->i2c_bus[0]);
@@ -1468,9 +1478,8 @@ int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
/* call common vendor command request */
status = cx231xx_send_vendor_cmd(dev, &ven_req);
if (status < 0) {
- cx231xx_info
- ("UsbInterface::sendCommand, failed with status -%d\n",
- status);
+ dev_err(dev->dev, "%s: failed with status -%d\n",
+ __func__, status);
}
return status;
diff --git a/drivers/media/usb/cx231xx/cx231xx-dvb.c b/drivers/media/usb/cx231xx/cx231xx-dvb.c
index 6c7b5e2..dd600b9 100644
--- a/drivers/media/usb/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/usb/cx231xx/cx231xx-dvb.c
@@ -19,11 +19,10 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/usb.h>
-#include "cx231xx.h"
#include <media/v4l2-common.h>
#include <media/videobuf-vmalloc.h>
@@ -46,11 +45,6 @@ MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define dprintk(level, fmt, arg...) do { \
-if (debug >= level) \
- printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
-} while (0)
-
#define CX231XX_DVB_NUM_BUFS 5
#define CX231XX_DVB_MAX_PACKETSIZE 564
#define CX231XX_DVB_MAX_PACKETS 64
@@ -197,9 +191,11 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
break;
}
if (packet < 0) {
- dprintk(1, "URB status %d [%s].\n", status, errmsg);
+ dev_dbg(dev->dev,
+ "URB status %d [%s].\n", status, errmsg);
} else {
- dprintk(1, "URB packet %d, status %d [%s].\n",
+ dev_dbg(dev->dev,
+ "URB packet %d, status %d [%s].\n",
packet, status, errmsg);
}
}
@@ -265,12 +261,8 @@ static int start_streaming(struct cx231xx_dvb *dvb)
struct cx231xx *dev = dvb->adapter.priv;
if (dev->USE_ISO) {
- cx231xx_info("DVB transfer mode is ISO.\n");
- mutex_lock(&dev->i2c_lock);
- cx231xx_enable_i2c_port_3(dev, false);
+ dev_dbg(dev->dev, "DVB transfer mode is ISO.\n");
cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
- cx231xx_enable_i2c_port_3(dev, true);
- mutex_unlock(&dev->i2c_lock);
rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
if (rc < 0)
return rc;
@@ -280,7 +272,7 @@ static int start_streaming(struct cx231xx_dvb *dvb)
dev->ts1_mode.max_pkt_size,
dvb_isoc_copy);
} else {
- cx231xx_info("DVB transfer mode is BULK.\n");
+ dev_dbg(dev->dev, "DVB transfer mode is BULK.\n");
cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
if (rc < 0)
@@ -378,24 +370,24 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
struct xc5000_config cfg;
memset(&cfg, 0, sizeof(cfg));
- cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap;
+ cfg.i2c_adap = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
cfg.i2c_addr = addr;
if (!dev->dvb->frontend) {
- printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ dev_err(dev->dev, "%s/2: dvb frontend not attached. "
"Can't attach xc5000\n", dev->name);
return -EINVAL;
}
fe = dvb_attach(xc5000_attach, dev->dvb->frontend, &cfg);
if (!fe) {
- printk(KERN_ERR "%s/2: xc5000 attach failed\n", dev->name);
+ dev_err(dev->dev, "%s/2: xc5000 attach failed\n", dev->name);
dvb_frontend_detach(dev->dvb->frontend);
dev->dvb->frontend = NULL;
return -EINVAL;
}
- printk(KERN_INFO "%s/2: xc5000 attached\n", dev->name);
+ dev_info(dev->dev, "%s/2: xc5000 attached\n", dev->name);
return 0;
}
@@ -434,16 +426,17 @@ int cx231xx_reset_analog_tuner(struct cx231xx *dev)
if (dops->init != NULL && !dev->xc_fw_load_done) {
- cx231xx_info("Reloading firmware for XC5000\n");
+ dev_dbg(dev->dev,
+ "Reloading firmware for XC5000\n");
status = dops->init(dev->dvb->frontend);
if (status == 0) {
dev->xc_fw_load_done = 1;
- cx231xx_info
- ("XC5000 firmware download completed\n");
+ dev_dbg(dev->dev,
+ "XC5000 firmware download completed\n");
} else {
dev->xc_fw_load_done = 0;
- cx231xx_info
- ("XC5000 firmware download failed !!!\n");
+ dev_dbg(dev->dev,
+ "XC5000 firmware download failed !!!\n");
}
}
@@ -466,7 +459,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
adapter_nr);
if (result < 0) {
- printk(KERN_WARNING
+ dev_warn(dev->dev,
"%s: dvb_register_adapter failed (errno = %d)\n",
dev->name, result);
goto fail_adapter;
@@ -480,7 +473,7 @@ static int register_dvb(struct cx231xx_dvb *dvb,
/* register frontend */
result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
if (result < 0) {
- printk(KERN_WARNING
+ dev_warn(dev->dev,
"%s: dvb_register_frontend failed (errno = %d)\n",
dev->name, result);
goto fail_frontend;
@@ -498,7 +491,8 @@ static int register_dvb(struct cx231xx_dvb *dvb,
result = dvb_dmx_init(&dvb->demux);
if (result < 0) {
- printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dev_warn(dev->dev,
+ "%s: dvb_dmx_init failed (errno = %d)\n",
dev->name, result);
goto fail_dmx;
}
@@ -508,15 +502,16 @@ static int register_dvb(struct cx231xx_dvb *dvb,
dvb->dmxdev.capabilities = 0;
result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
if (result < 0) {
- printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
- dev->name, result);
+ dev_warn(dev->dev,
+ "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dev->name, result);
goto fail_dmxdev;
}
dvb->fe_hw.source = DMX_FRONTEND_0;
result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
if (result < 0) {
- printk(KERN_WARNING
+ dev_warn(dev->dev,
"%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
dev->name, result);
goto fail_fe_hw;
@@ -525,17 +520,17 @@ static int register_dvb(struct cx231xx_dvb *dvb,
dvb->fe_mem.source = DMX_MEMORY_FE;
result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
if (result < 0) {
- printk(KERN_WARNING
- "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
- dev->name, result);
+ dev_warn(dev->dev,
+ "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dev->name, result);
goto fail_fe_mem;
}
result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
if (result < 0) {
- printk(KERN_WARNING
- "%s: connect_frontend failed (errno = %d)\n", dev->name,
- result);
+ dev_warn(dev->dev,
+ "%s: connect_frontend failed (errno = %d)\n",
+ dev->name, result);
goto fail_fe_conn;
}
@@ -583,6 +578,8 @@ static int dvb_init(struct cx231xx *dev)
{
int result = 0;
struct cx231xx_dvb *dvb;
+ struct i2c_adapter *tuner_i2c;
+ struct i2c_adapter *demod_i2c;
if (!dev->board.has_dvb) {
/* This device does not support the extension */
@@ -592,13 +589,16 @@ static int dvb_init(struct cx231xx *dev)
dvb = kzalloc(sizeof(struct cx231xx_dvb), GFP_KERNEL);
if (dvb == NULL) {
- printk(KERN_INFO "cx231xx_dvb: memory allocation failed\n");
+ dev_info(dev->dev,
+ "cx231xx_dvb: memory allocation failed\n");
return -ENOMEM;
}
dev->dvb = dvb;
dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
+ tuner_i2c = cx231xx_get_i2c_adap(dev, dev->board.tuner_i2c_master);
+ demod_i2c = cx231xx_get_i2c_adap(dev, dev->board.demod_i2c_master);
mutex_lock(&dev->lock);
cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
cx231xx_demod_reset(dev);
@@ -609,11 +609,11 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(s5h1432_attach,
&dvico_s5h1432_config,
- &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+ demod_i2c);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach s5h1432 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach s5h1432 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -622,7 +622,7 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ tuner_i2c,
&cnxt_rde250_tunerconfig)) {
result = -EINVAL;
goto out_free;
@@ -634,11 +634,11 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(s5h1411_attach,
&xc5000_s5h1411_config,
- &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+ demod_i2c);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach s5h1411 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach s5h1411 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -647,7 +647,7 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ tuner_i2c,
&cnxt_rdu250_tunerconfig)) {
result = -EINVAL;
goto out_free;
@@ -657,11 +657,11 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(s5h1432_attach,
&dvico_s5h1432_config,
- &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+ demod_i2c);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach s5h1432 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach s5h1432 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -670,7 +670,7 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
- 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ 0x60, tuner_i2c,
&cnxt_rde253s_tunerconfig)) {
result = -EINVAL;
goto out_free;
@@ -681,11 +681,11 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(s5h1411_attach,
&tda18271_s5h1411_config,
- &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+ demod_i2c);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach s5h1411 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach s5h1411 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -694,7 +694,7 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
- 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ 0x60, tuner_i2c,
&cnxt_rde253s_tunerconfig)) {
result = -EINVAL;
goto out_free;
@@ -702,16 +702,17 @@ static int dvb_init(struct cx231xx *dev)
break;
case CX231XX_BOARD_HAUPPAUGE_EXETER:
- printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n",
- __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+ dev_info(dev->dev,
+ "%s: looking for tuner / demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(tuner_i2c));
dev->dvb->frontend = dvb_attach(lgdt3305_attach,
&hcw_lgdt3305_config,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap);
+ tuner_i2c);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach LG3305 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach LG3305 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -720,7 +721,7 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
dvb_attach(tda18271_attach, dev->dvb->frontend,
- 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ 0x60, tuner_i2c,
&hcw_tda18271_config);
break;
@@ -728,12 +729,12 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(si2165_attach,
&hauppauge_930C_HD_1113xx_si2165_config,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap
+ tuner_i2c
);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach SI2165 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach SI2165 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -745,7 +746,7 @@ static int dvb_init(struct cx231xx *dev)
dvb_attach(tda18271_attach, dev->dvb->frontend,
0x60,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ tuner_i2c,
&hcw_tda18271_config);
dev->cx231xx_reset_analog_tuner = NULL;
@@ -761,12 +762,12 @@ static int dvb_init(struct cx231xx *dev)
dev->dvb->frontend = dvb_attach(si2165_attach,
&pctv_quatro_stick_1114xx_si2165_config,
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap
+ tuner_i2c
);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach SI2165 front end\n");
+ dev_err(dev->dev,
+ "Failed to attach SI2165 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -786,7 +787,7 @@ static int dvb_init(struct cx231xx *dev)
request_module("si2157");
client = i2c_new_device(
- &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ tuner_i2c,
&info);
if (client == NULL || client->dev.driver == NULL) {
dvb_frontend_detach(dev->dvb->frontend);
@@ -810,16 +811,17 @@ static int dvb_init(struct cx231xx *dev)
case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
case CX231XX_BOARD_KWORLD_UB430_USB_HYBRID:
- printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
- __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+ dev_info(dev->dev,
+ "%s: looking for demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(tuner_i2c));
dev->dvb->frontend = dvb_attach(mb86a20s_attach,
&pv_mb86a20s_config,
- &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+ demod_i2c);
if (dev->dvb->frontend == NULL) {
- printk(DRIVER_NAME
- ": Failed to attach mb86a20s demod\n");
+ dev_err(dev->dev,
+ "Failed to attach mb86a20s demod\n");
result = -EINVAL;
goto out_free;
}
@@ -828,30 +830,31 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
dvb_attach(tda18271_attach, dev->dvb->frontend,
- 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ 0x60, tuner_i2c,
&pv_tda18271_config);
break;
default:
- printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
- " isn't supported yet\n", dev->name);
+ dev_err(dev->dev,
+ "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
+ dev->name);
break;
}
if (NULL == dvb->frontend) {
- printk(KERN_ERR
+ dev_err(dev->dev,
"%s/2: frontend initialization failed\n", dev->name);
result = -EINVAL;
goto out_free;
}
/* register everything */
- result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+ result = register_dvb(dvb, THIS_MODULE, dev, dev->dev);
if (result < 0)
goto out_free;
- printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
+ dev_info(dev->dev, "Successfully loaded cx231xx-dvb\n");
ret:
cx231xx_set_mode(dev, CX231XX_SUSPEND);
diff --git a/drivers/media/usb/cx231xx/cx231xx-i2c.c b/drivers/media/usb/cx231xx/cx231xx-i2c.c
index 7c0f797..a29c345 100644
--- a/drivers/media/usb/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/usb/cx231xx/cx231xx-i2c.c
@@ -20,14 +20,14 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/usb.h>
#include <linux/i2c.h>
+#include <linux/i2c-mux.h>
#include <media/v4l2-common.h>
#include <media/tuner.h>
-#include "cx231xx.h"
/* ----------------------------------------------------------- */
@@ -54,10 +54,19 @@ do { \
} \
} while (0)
+static inline int get_real_i2c_port(struct cx231xx *dev, int bus_nr)
+{
+ if (bus_nr == 1)
+ return dev->port_3_switch_enabled ? I2C_1_MUX_3 : I2C_1_MUX_1;
+ return bus_nr;
+}
+
static inline bool is_tuner(struct cx231xx *dev, struct cx231xx_i2c *bus,
const struct i2c_msg *msg, int tuner_type)
{
- if (bus->nr != dev->board.tuner_i2c_master)
+ int i2c_port = get_real_i2c_port(dev, bus->nr);
+
+ if (i2c_port != dev->board.tuner_i2c_master)
return false;
if (msg->addr != dev->board.tuner_addr)
@@ -340,14 +349,15 @@ static int cx231xx_i2c_check_for_device(struct i2c_adapter *i2c_adap,
struct cx231xx *dev = bus->dev;
struct cx231xx_i2c_xfer_data req_data;
int status = 0;
+ u8 buf[1];
/* prepare xfer_data struct */
req_data.dev_addr = msg->addr;
- req_data.direction = msg->flags;
+ req_data.direction = I2C_M_RD;
req_data.saddr_len = 0;
req_data.saddr_dat = 0;
- req_data.buf_size = 0;
- req_data.p_buffer = NULL;
+ req_data.buf_size = 1;
+ req_data.p_buffer = buf;
/* usb send command */
status = dev->cx231xx_send_usb_command(bus, &req_data);
@@ -455,17 +465,14 @@ static struct i2c_adapter cx231xx_adap_template = {
.algo = &cx231xx_algo,
};
-static struct i2c_client cx231xx_client_template = {
- .name = "cx231xx internal",
-};
-
/* ----------------------------------------------------------- */
/*
* i2c_devs
* incomplete list of known devices
*/
-static char *i2c_devs[128] = {
+static const char *i2c_devs[128] = {
+ [0x20 >> 1] = "demod",
[0x60 >> 1] = "colibri",
[0x88 >> 1] = "hammerhead",
[0x8e >> 1] = "CIR",
@@ -480,22 +487,34 @@ static char *i2c_devs[128] = {
* cx231xx_do_i2c_scan()
* check i2c address range for devices
*/
-void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c)
+void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port)
{
unsigned char buf;
int i, rc;
+ struct i2c_client client;
+
+ if (!i2c_scan)
+ return;
+
+ /* Don't generate I2C errors during scan */
+ dev->i2c_scan_running = true;
+
+ memset(&client, 0, sizeof(client));
+ client.adapter = cx231xx_get_i2c_adap(dev, i2c_port);
- cx231xx_info(": Checking for I2C devices ..\n");
for (i = 0; i < 128; i++) {
- c->addr = i;
- rc = i2c_master_recv(c, &buf, 0);
+ client.addr = i;
+ rc = i2c_master_recv(&client, &buf, 0);
if (rc < 0)
continue;
- cx231xx_info("%s: i2c scan: found device @ 0x%x [%s]\n",
- dev->name, i << 1,
- i2c_devs[i] ? i2c_devs[i] : "???");
+ dev_info(dev->dev,
+ "i2c scan: found device @ port %d addr 0x%x [%s]\n",
+ i2c_port,
+ i << 1,
+ i2c_devs[i] ? i2c_devs[i] : "???");
}
- cx231xx_info(": Completed Checking for I2C devices.\n");
+
+ dev->i2c_scan_running = false;
}
/*
@@ -509,23 +528,17 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
BUG_ON(!dev->cx231xx_send_usb_command);
bus->i2c_adap = cx231xx_adap_template;
- bus->i2c_client = cx231xx_client_template;
- bus->i2c_adap.dev.parent = &dev->udev->dev;
+ bus->i2c_adap.dev.parent = dev->dev;
- strlcpy(bus->i2c_adap.name, bus->dev->name, sizeof(bus->i2c_adap.name));
+ snprintf(bus->i2c_adap.name, sizeof(bus->i2c_adap.name), "%s-%d", bus->dev->name, bus->nr);
bus->i2c_adap.algo_data = bus;
i2c_set_adapdata(&bus->i2c_adap, &dev->v4l2_dev);
i2c_add_adapter(&bus->i2c_adap);
- bus->i2c_client.adapter = &bus->i2c_adap;
-
- if (0 == bus->i2c_rc) {
- if (i2c_scan)
- cx231xx_do_i2c_scan(dev, &bus->i2c_client);
- } else
- cx231xx_warn("%s: i2c bus %d register FAILED\n",
- dev->name, bus->nr);
+ if (0 != bus->i2c_rc)
+ dev_warn(dev->dev,
+ "i2c bus %d register FAILED\n", bus->nr);
return bus->i2c_rc;
}
@@ -539,3 +552,62 @@ int cx231xx_i2c_unregister(struct cx231xx_i2c *bus)
i2c_del_adapter(&bus->i2c_adap);
return 0;
}
+
+/*
+ * cx231xx_i2c_mux_select()
+ * switch i2c master number 1 between port1 and port3
+ */
+static int cx231xx_i2c_mux_select(struct i2c_adapter *adap,
+ void *mux_priv, u32 chan_id)
+{
+ struct cx231xx *dev = mux_priv;
+
+ return cx231xx_enable_i2c_port_3(dev, chan_id);
+}
+
+int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no)
+{
+ struct i2c_adapter *i2c_parent = &dev->i2c_bus[1].i2c_adap;
+ /* what is the correct mux_dev? */
+ struct device *mux_dev = dev->dev;
+
+ dev->i2c_mux_adap[mux_no] = i2c_add_mux_adapter(i2c_parent,
+ mux_dev,
+ dev /* mux_priv */,
+ 0,
+ mux_no /* chan_id */,
+ 0 /* class */,
+ &cx231xx_i2c_mux_select,
+ NULL);
+
+ if (!dev->i2c_mux_adap[mux_no])
+ dev_warn(dev->dev,
+ "i2c mux %d register FAILED\n", mux_no);
+
+ return 0;
+}
+
+void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no)
+{
+ i2c_del_mux_adapter(dev->i2c_mux_adap[mux_no]);
+ dev->i2c_mux_adap[mux_no] = NULL;
+}
+
+struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port)
+{
+ switch (i2c_port) {
+ case I2C_0:
+ return &dev->i2c_bus[0].i2c_adap;
+ case I2C_1:
+ return &dev->i2c_bus[1].i2c_adap;
+ case I2C_2:
+ return &dev->i2c_bus[2].i2c_adap;
+ case I2C_1_MUX_1:
+ return dev->i2c_mux_adap[0];
+ case I2C_1_MUX_3:
+ return dev->i2c_mux_adap[1];
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL_GPL(cx231xx_get_i2c_adap);
diff --git a/drivers/media/usb/cx231xx/cx231xx-input.c b/drivers/media/usb/cx231xx/cx231xx-input.c
index 05f0434..15d8d1b 100644
--- a/drivers/media/usb/cx231xx/cx231xx-input.c
+++ b/drivers/media/usb/cx231xx/cx231xx-input.c
@@ -19,7 +19,6 @@
*/
#include "cx231xx.h"
-#include <linux/usb.h>
#include <linux/slab.h>
#include <linux/bitrev.h>
@@ -63,7 +62,7 @@ int cx231xx_ir_init(struct cx231xx *dev)
struct i2c_board_info info;
u8 ir_i2c_bus;
- dev_dbg(&dev->udev->dev, "%s\n", __func__);
+ dev_dbg(dev->dev, "%s\n", __func__);
/* Only initialize if a rc keycode map is defined */
if (!cx231xx_boards[dev->model].rc_map_name)
@@ -98,9 +97,10 @@ int cx231xx_ir_init(struct cx231xx *dev)
/* Load and bind ir-kbd-i2c */
ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
- dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
+ dev_dbg(dev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
ir_i2c_bus, info.addr);
- dev->ir_i2c_client = i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
+ dev->ir_i2c_client = i2c_new_device(
+ cx231xx_get_i2c_adap(dev, ir_i2c_bus), &info);
return 0;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
index 3052c4c..5bc7414 100644
--- a/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
+++ b/drivers/media/usb/cx231xx/cx231xx-pcb-cfg.c
@@ -703,9 +703,9 @@ int initialize_cx231xx(struct cx231xx *dev)
_current_scenario_idx = INDEX_BUSPOWER_DIF_ONLY;
break;
default:
- cx231xx_info("bad config in buspower!!!!\n");
- cx231xx_info("config_info=%x\n",
- (config_info & BUSPOWER_MASK));
+ dev_err(dev->dev,
+ "bad config in buspower!!!!\nconfig_info=%x\n",
+ config_info & BUSPOWER_MASK);
return 1;
}
} else { /* self-power */
@@ -768,9 +768,9 @@ int initialize_cx231xx(struct cx231xx *dev)
_current_scenario_idx = INDEX_SELFPOWER_COMPRESSOR;
break;
default:
- cx231xx_info("bad senario!!!!!\n");
- cx231xx_info("config_info=%x\n",
- (config_info & SELFPOWER_MASK));
+ dev_err(dev->dev,
+ "bad senario!!!!!\nconfig_info=%x\n",
+ config_info & SELFPOWER_MASK);
return -ENODEV;
}
}
@@ -781,18 +781,29 @@ int initialize_cx231xx(struct cx231xx *dev)
sizeof(struct pcb_config));
if (pcb_debug) {
- cx231xx_info("SC(0x00) register = 0x%x\n", config_info);
- cx231xx_info("scenario %d\n",
- (dev->current_pcb_config.index) + 1);
- cx231xx_info("type=%x\n", dev->current_pcb_config.type);
- cx231xx_info("mode=%x\n", dev->current_pcb_config.mode);
- cx231xx_info("speed=%x\n", dev->current_pcb_config.speed);
- cx231xx_info("ts1_source=%x\n",
- dev->current_pcb_config.ts1_source);
- cx231xx_info("ts2_source=%x\n",
- dev->current_pcb_config.ts2_source);
- cx231xx_info("analog_source=%x\n",
- dev->current_pcb_config.analog_source);
+ dev_info(dev->dev,
+ "SC(0x00) register = 0x%x\n", config_info);
+ dev_info(dev->dev,
+ "scenario %d\n",
+ (dev->current_pcb_config.index) + 1);
+ dev_info(dev->dev,
+ "type=%x\n",
+ dev->current_pcb_config.type);
+ dev_info(dev->dev,
+ "mode=%x\n",
+ dev->current_pcb_config.mode);
+ dev_info(dev->dev,
+ "speed=%x\n",
+ dev->current_pcb_config.speed);
+ dev_info(dev->dev,
+ "ts1_source=%x\n",
+ dev->current_pcb_config.ts1_source);
+ dev_info(dev->dev,
+ "ts2_source=%x\n",
+ dev->current_pcb_config.ts2_source);
+ dev_info(dev->dev,
+ "analog_source=%x\n",
+ dev->current_pcb_config.analog_source);
}
return 0;
diff --git a/drivers/media/usb/cx231xx/cx231xx-vbi.c b/drivers/media/usb/cx231xx/cx231xx-vbi.c
index c027942..80261ac 100644
--- a/drivers/media/usb/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/usb/cx231xx/cx231xx-vbi.c
@@ -19,12 +19,12 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bitmap.h>
-#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/mm.h>
#include <linux/mutex.h>
@@ -35,7 +35,6 @@
#include <media/msp3400.h>
#include <media/tuner.h>
-#include "cx231xx.h"
#include "cx231xx-vbi.h"
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
@@ -69,11 +68,12 @@ static inline void print_err_status(struct cx231xx *dev, int packet, int status)
break;
}
if (packet < 0) {
- cx231xx_err("URB status %d [%s].\n", status,
- errmsg);
+ dev_err(dev->dev,
+ "URB status %d [%s].\n", status, errmsg);
} else {
- cx231xx_err("URB packet %d, status %d [%s].\n",
- packet, status, errmsg);
+ dev_err(dev->dev,
+ "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
}
}
@@ -316,8 +316,8 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
case -ESHUTDOWN:
return;
default: /* error */
- cx231xx_err("urb completition error %d.\n",
- urb->status);
+ dev_err(dev->dev,
+ "urb completition error %d.\n", urb->status);
break;
}
@@ -331,8 +331,8 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
urb->status = usb_submit_urb(urb, GFP_ATOMIC);
if (urb->status) {
- cx231xx_err("urb resubmit failed (error=%i)\n",
- urb->status);
+ dev_err(dev->dev, "urb resubmit failed (error=%i)\n",
+ urb->status);
}
}
@@ -344,7 +344,7 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
struct urb *urb;
int i;
- cx231xx_info("called cx231xx_uninit_vbi_isoc\n");
+ dev_dbg(dev->dev, "called cx231xx_uninit_vbi_isoc\n");
dev->vbi_mode.bulk_ctl.nfields = -1;
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
@@ -393,7 +393,7 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
struct urb *urb;
int rc;
- cx231xx_info("called cx231xx_vbi_isoc\n");
+ dev_dbg(dev->dev, "called cx231xx_vbi_isoc\n");
/* De-allocates all pending stuff */
cx231xx_uninit_vbi_isoc(dev);
@@ -419,14 +419,16 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.urb) {
- cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ dev_err(dev->dev,
+ "cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
dev->vbi_mode.bulk_ctl.transfer_buffer =
kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.transfer_buffer) {
- cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ dev_err(dev->dev,
+ "cannot allocate memory for usbtransfer\n");
kfree(dev->vbi_mode.bulk_ctl.urb);
return -ENOMEM;
}
@@ -441,7 +443,8 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
- cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
+ dev_err(dev->dev,
+ "cannot alloc bulk_ctl.urb %i\n", i);
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
@@ -451,9 +454,10 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
- cx231xx_err("unable to allocate %i bytes for transfer"
- " buffer %i%s\n", sb_size, i,
- in_interrupt() ? " while in int" : "");
+ dev_err(dev->dev,
+ "unable to allocate %i bytes for transfer buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
@@ -470,8 +474,8 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
if (rc) {
- cx231xx_err("submit of urb %i failed (error=%i)\n", i,
- rc);
+ dev_err(dev->dev,
+ "submit of urb %i failed (error=%i)\n", i, rc);
cx231xx_uninit_vbi_isoc(dev);
return rc;
}
@@ -522,7 +526,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
struct cx231xx_buffer *buf)
{
/* Advice that buffer was filled */
- /* cx231xx_info("[%p/%d] wakeup\n", buf, buf->vb.i); */
+ /* dev_dbg(dev->dev, "[%p/%d] wakeup\n", buf, buf->vb.i); */
buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
@@ -614,7 +618,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
char *outp;
if (list_empty(&dma_q->active)) {
- cx231xx_err("No active queue to serve\n");
+ dev_err(dev->dev, "No active queue to serve\n");
dev->vbi_mode.bulk_ctl.buf = NULL;
*buf = NULL;
return;
diff --git a/drivers/media/usb/cx231xx/cx231xx-video.c b/drivers/media/usb/cx231xx/cx231xx-video.c
index 3b3ada6..53ca12c 100644
--- a/drivers/media/usb/cx231xx/cx231xx-video.c
+++ b/drivers/media/usb/cx231xx/cx231xx-video.c
@@ -22,12 +22,12 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include "cx231xx.h"
#include <linux/init.h>
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/bitmap.h>
-#include <linux/usb.h>
#include <linux/i2c.h>
#include <linux/mm.h>
#include <linux/mutex.h>
@@ -41,10 +41,9 @@
#include "dvb_frontend.h"
-#include "cx231xx.h"
#include "cx231xx-vbi.h"
-#define CX231XX_VERSION "0.0.2"
+#define CX231XX_VERSION "0.0.3"
#define DRIVER_AUTHOR "Srinivasa Deevi <srinivasa.deevi@conexant.com>"
#define DRIVER_DESC "Conexant cx231xx based USB video device driver"
@@ -737,8 +736,9 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
if (!dev->video_mode.bulk_ctl.num_bufs)
urb_init = 1;
}
- /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
- urb_init, dev->video_mode.max_pkt_size);*/
+ dev_dbg(dev->dev,
+ "urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+ urb_init, dev->video_mode.max_pkt_size);
if (urb_init) {
dev->mode_tv = 0;
if (dev->USE_ISO)
@@ -809,7 +809,7 @@ void video_mux(struct cx231xx *dev, int index)
cx231xx_set_audio_input(dev, dev->ctl_ainput);
- cx231xx_info("video_mux : %d\n", index);
+ dev_dbg(dev->dev, "video_mux : %d\n", index);
/* do mode control overrides if required */
cx231xx_do_mode_ctrl_overrides(dev);
@@ -861,7 +861,7 @@ static void res_free(struct cx231xx_fh *fh)
static int check_dev(struct cx231xx *dev)
{
if (dev->state & DEV_DISCONNECTED) {
- cx231xx_errdev("v4l2 ioctl: device not present\n");
+ dev_err(dev->dev, "v4l2 ioctl: device not present\n");
return -ENODEV;
}
return 0;
@@ -953,12 +953,13 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
- cx231xx_errdev("%s queue busy\n", __func__);
+ dev_err(dev->dev, "%s: queue busy\n", __func__);
return -EBUSY;
}
if (dev->stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
+ dev_err(dev->dev,
+ "%s: device in use by another fh\n", __func__);
return -EBUSY;
}
@@ -967,7 +968,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dev->height = f->fmt.pix.height;
dev->format = fmt;
- v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, MEDIA_BUS_FMT_FIXED);
call_all(dev, video, s_mbus_fmt, &mbus_fmt);
v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
@@ -1012,7 +1013,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
resolution (since a standard change effects things like the number
of lines in VACT, etc) */
memset(&mbus_fmt, 0, sizeof(mbus_fmt));
- mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ mbus_fmt.code = MEDIA_BUS_FMT_FIXED;
mbus_fmt.width = dev->width;
mbus_fmt.height = dev->height;
call_all(dev, video, s_mbus_fmt, &mbus_fmt);
@@ -1176,9 +1177,9 @@ int cx231xx_s_frequency(struct file *file, void *priv,
int rc;
u32 if_frequency = 5400000;
- cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
- f->frequency, f->type);
- /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/
+ dev_dbg(dev->dev,
+ "Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
+ f->frequency, f->type);
rc = check_dev(dev);
if (rc < 0)
@@ -1213,13 +1214,14 @@ int cx231xx_s_frequency(struct file *file, void *priv,
else if (dev->norm & V4L2_STD_SECAM_LC)
if_frequency = 1250000; /*1.25MHz */
- cx231xx_info("if_frequency is set to %d\n", if_frequency);
+ dev_dbg(dev->dev,
+ "if_frequency is set to %d\n", if_frequency);
cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
update_HH_register_after_set_DIF(dev);
}
- cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
+ dev_dbg(dev->dev, "Set New FREQUENCY to %d\n", f->frequency);
return rc;
}
@@ -1523,7 +1525,8 @@ static int vidioc_s_fmt_vbi_cap(struct file *file, void *priv,
struct cx231xx *dev = fh->dev;
if (dev->vbi_stream_on && !fh->stream_on) {
- cx231xx_errdev("%s device in use by another fh\n", __func__);
+ dev_err(dev->dev,
+ "%s device in use by another fh\n", __func__);
return -EBUSY;
}
return vidioc_try_fmt_vbi_cap(file, priv, f);
@@ -1642,17 +1645,15 @@ static int cx231xx_v4l2_open(struct file *filp)
#if 0
errCode = cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
if (errCode < 0) {
- cx231xx_errdev
- ("Device locked on digital mode. Can't open analog\n");
+ dev_err(dev->dev,
+ "Device locked on digital mode. Can't open analog\n");
return -EBUSY;
}
#endif
fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
- if (!fh) {
- cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
+ if (!fh)
return -ENOMEM;
- }
if (mutex_lock_interruptible(&dev->lock)) {
kfree(fh);
return -ERESTARTSYS;
@@ -1736,8 +1737,8 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
dev->radio_dev = NULL;
}
if (dev->vbi_dev) {
- cx231xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vbi_dev));
+ dev_info(dev->dev, "V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vbi_dev));
if (video_is_registered(dev->vbi_dev))
video_unregister_device(dev->vbi_dev);
else
@@ -1745,8 +1746,8 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
dev->vbi_dev = NULL;
}
if (dev->vdev) {
- cx231xx_info("V4L2 device %s deregistered\n",
- video_device_node_name(dev->vdev));
+ dev_info(dev->dev, "V4L2 device %s deregistered\n",
+ video_device_node_name(dev->vdev));
if (dev->board.has_417)
cx231xx_417_unregister(dev);
@@ -2080,8 +2081,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
{
int ret;
- cx231xx_info("%s: v4l2 driver version %s\n",
- dev->name, CX231XX_VERSION);
+ dev_info(dev->dev, "v4l2 driver version %s\n", CX231XX_VERSION);
/* set default norm */
dev->norm = V4L2_STD_PAL;
@@ -2119,7 +2119,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
/* allocate and fill video video_device struct */
dev->vdev = cx231xx_vdev_init(dev, &cx231xx_video_template, "video");
if (!dev->vdev) {
- cx231xx_errdev("cannot allocate video_device.\n");
+ dev_err(dev->dev, "cannot allocate video_device.\n");
return -ENODEV;
}
@@ -2128,13 +2128,14 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
ret = video_register_device(dev->vdev, VFL_TYPE_GRABBER,
video_nr[dev->devno]);
if (ret) {
- cx231xx_errdev("unable to register video device (error=%i).\n",
- ret);
+ dev_err(dev->dev,
+ "unable to register video device (error=%i).\n",
+ ret);
return ret;
}
- cx231xx_info("%s/0: registered device %s [v4l2]\n",
- dev->name, video_device_node_name(dev->vdev));
+ dev_info(dev->dev, "Registered video device %s [v4l2]\n",
+ video_device_node_name(dev->vdev));
/* Initialize VBI template */
cx231xx_vbi_template = cx231xx_video_template;
@@ -2144,7 +2145,7 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev->vbi_dev = cx231xx_vdev_init(dev, &cx231xx_vbi_template, "vbi");
if (!dev->vbi_dev) {
- cx231xx_errdev("cannot allocate video_device.\n");
+ dev_err(dev->dev, "cannot allocate video_device.\n");
return -ENODEV;
}
dev->vbi_dev->ctrl_handler = &dev->ctrl_handler;
@@ -2152,34 +2153,32 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
ret = video_register_device(dev->vbi_dev, VFL_TYPE_VBI,
vbi_nr[dev->devno]);
if (ret < 0) {
- cx231xx_errdev("unable to register vbi device\n");
+ dev_err(dev->dev, "unable to register vbi device\n");
return ret;
}
- cx231xx_info("%s/0: registered device %s\n",
- dev->name, video_device_node_name(dev->vbi_dev));
+ dev_info(dev->dev, "Registered VBI device %s\n",
+ video_device_node_name(dev->vbi_dev));
if (cx231xx_boards[dev->model].radio.type == CX231XX_RADIO) {
dev->radio_dev = cx231xx_vdev_init(dev, &cx231xx_radio_template,
"radio");
if (!dev->radio_dev) {
- cx231xx_errdev("cannot allocate video_device.\n");
+ dev_err(dev->dev,
+ "cannot allocate video_device.\n");
return -ENODEV;
}
dev->radio_dev->ctrl_handler = &dev->radio_ctrl_handler;
ret = video_register_device(dev->radio_dev, VFL_TYPE_RADIO,
radio_nr[dev->devno]);
if (ret < 0) {
- cx231xx_errdev("can't register radio device\n");
+ dev_err(dev->dev,
+ "can't register radio device\n");
return ret;
}
- cx231xx_info("Registered radio device as %s\n",
- video_device_node_name(dev->radio_dev));
+ dev_info(dev->dev, "Registered radio device as %s\n",
+ video_device_node_name(dev->radio_dev));
}
- cx231xx_info("V4L2 device registered as %s and %s\n",
- video_device_node_name(dev->vdev),
- video_device_node_name(dev->vbi_dev));
-
return 0;
}
diff --git a/drivers/media/usb/cx231xx/cx231xx.h b/drivers/media/usb/cx231xx/cx231xx.h
index aeb1bf4..f9e262eb 100644
--- a/drivers/media/usb/cx231xx/cx231xx.h
+++ b/drivers/media/usb/cx231xx/cx231xx.h
@@ -28,6 +28,7 @@
#include <linux/i2c.h>
#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <linux/usb.h>
#include <media/cx2341x.h>
@@ -322,10 +323,11 @@ enum cx231xx_decoder {
};
enum CX231XX_I2C_MASTER_PORT {
- I2C_0 = 0,
- I2C_1 = 1,
- I2C_2 = 2,
- I2C_3 = 3
+ I2C_0 = 0, /* master 0 - internal connection */
+ I2C_1 = 1, /* master 1 - used with mux */
+ I2C_2 = 2, /* master 2 */
+ I2C_1_MUX_1 = 3, /* master 1 - port 1 (I2C_DEMOD_EN = 0) */
+ I2C_1_MUX_3 = 4 /* master 1 - port 3 (I2C_DEMOD_EN = 1) */
};
struct cx231xx_board {
@@ -367,7 +369,6 @@ struct cx231xx_board {
unsigned int valid:1;
unsigned int no_alt_vanc:1;
unsigned int external_av:1;
- unsigned int dont_use_port_3:1;
unsigned char xclk, i2c_speed;
@@ -472,7 +473,6 @@ struct cx231xx_i2c {
/* i2c i/o */
struct i2c_adapter i2c_adap;
- struct i2c_client i2c_client;
u32 i2c_rc;
/* different settings for each bus */
@@ -597,6 +597,7 @@ struct cx231xx {
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
+ struct device *dev; /* pointer to USB interface's dev */
struct cx231xx_board board;
@@ -609,6 +610,8 @@ struct cx231xx {
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
+ unsigned int i2c_scan_running:1; /* true only during i2c_scan */
+
struct cx231xx_fmt *format;
struct v4l2_device v4l2_dev;
@@ -628,7 +631,10 @@ struct cx231xx {
/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
struct cx231xx_i2c i2c_bus[3];
+ struct i2c_adapter *i2c_mux_adap[2];
+
unsigned int xc_fw_load_done:1;
+ unsigned int port_3_switch_enabled:1;
/* locks */
struct mutex gpio_i2c_lock;
struct mutex i2c_lock;
@@ -751,9 +757,12 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq);
int cx231xx_reset_analog_tuner(struct cx231xx *dev);
/* Provided by cx231xx-i2c.c */
-void cx231xx_do_i2c_scan(struct cx231xx *dev, struct i2c_client *c);
+void cx231xx_do_i2c_scan(struct cx231xx *dev, int i2c_port);
int cx231xx_i2c_register(struct cx231xx_i2c *bus);
int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
+int cx231xx_i2c_mux_register(struct cx231xx *dev, int mux_no);
+void cx231xx_i2c_mux_unregister(struct cx231xx *dev, int mux_no);
+struct i2c_adapter *cx231xx_get_i2c_adap(struct cx231xx *dev, int i2c_port);
/* Internal block control functions */
int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
@@ -802,7 +811,6 @@ void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev);
void reset_s5h1432_demod(struct cx231xx *dev);
void cx231xx_dump_HH_reg(struct cx231xx *dev);
void update_HH_register_after_set_DIF(struct cx231xx *dev);
-void cx231xx_dump_SC_reg(struct cx231xx *dev);
@@ -976,23 +984,6 @@ void cx231xx_ir_exit(struct cx231xx *dev);
#define cx231xx_ir_exit(dev) (0)
#endif
-
-/* printk macros */
-
-#define cx231xx_err(fmt, arg...) do {\
- printk(KERN_ERR fmt , ##arg); } while (0)
-
-#define cx231xx_errdev(fmt, arg...) do {\
- printk(KERN_ERR "%s: "fmt,\
- dev->name , ##arg); } while (0)
-
-#define cx231xx_info(fmt, arg...) do {\
- printk(KERN_INFO "%s: "fmt,\
- dev->name , ##arg); } while (0)
-#define cx231xx_warn(fmt, arg...) do {\
- printk(KERN_WARNING "%s: "fmt,\
- dev->name , ##arg); } while (0)
-
static inline unsigned int norm_maxw(struct cx231xx *dev)
{
if (dev->board.max_range_640_480)
diff --git a/drivers/media/usb/dvb-usb-v2/Kconfig b/drivers/media/usb/dvb-usb-v2/Kconfig
index 5b34323..0982e73 100644
--- a/drivers/media/usb/dvb-usb-v2/Kconfig
+++ b/drivers/media/usb/dvb-usb-v2/Kconfig
@@ -145,6 +145,9 @@ config DVB_USB_DVBSKY
tristate "DVBSky USB support"
depends on DVB_USB_V2
select DVB_M88DS3103 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SI2168 if MEDIA_SUBDRV_AUTOSELECT
select MEDIA_TUNER_M88TS2022 if MEDIA_SUBDRV_AUTOSELECT
+ select MEDIA_TUNER_SI2157 if MEDIA_SUBDRV_AUTOSELECT
+ select DVB_SP2 if MEDIA_SUBDRV_AUTOSELECT
help
Say Y here to support the USB receivers from DVBSky.
diff --git a/drivers/media/usb/dvb-usb-v2/af9035.c b/drivers/media/usb/dvb-usb-v2/af9035.c
index 1896ab2..80a29f5 100644
--- a/drivers/media/usb/dvb-usb-v2/af9035.c
+++ b/drivers/media/usb/dvb-usb-v2/af9035.c
@@ -1171,6 +1171,7 @@ static int it930x_frontend_attach(struct dvb_usb_adapter *adap)
dev_dbg(&d->udev->dev, "adap->id=%d\n", adap->id);
+ memset(&si2168_config, 0, sizeof(si2168_config));
si2168_config.i2c_adapter = &adapter;
si2168_config.fe = &adap->fe[0];
si2168_config.ts_mode = SI2168_TS_SERIAL;
diff --git a/drivers/media/usb/dvb-usb-v2/dvbsky.c b/drivers/media/usb/dvb-usb-v2/dvbsky.c
index 34688c8..9b5add4 100644
--- a/drivers/media/usb/dvb-usb-v2/dvbsky.c
+++ b/drivers/media/usb/dvb-usb-v2/dvbsky.c
@@ -21,10 +21,17 @@
#include "dvb_usb.h"
#include "m88ds3103.h"
#include "m88ts2022.h"
+#include "sp2.h"
+#include "si2168.h"
+#include "si2157.h"
#define DVBSKY_MSG_DELAY 0/*2000*/
#define DVBSKY_BUF_LEN 64
+static int dvb_usb_dvbsky_disable_rc;
+module_param_named(disable_rc, dvb_usb_dvbsky_disable_rc, int, 0644);
+MODULE_PARM_DESC(disable_rc, "Disable inbuilt IR receiver.");
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct dvbsky_state {
@@ -32,7 +39,9 @@ struct dvbsky_state {
u8 ibuf[DVBSKY_BUF_LEN];
u8 obuf[DVBSKY_BUF_LEN];
u8 last_lock;
+ struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
+ struct i2c_client *i2c_client_ci;
/* fe hook functions*/
int (*fe_set_voltage)(struct dvb_frontend *fe,
@@ -96,8 +105,7 @@ static int dvbsky_gpio_ctrl(struct dvb_usb_device *d, u8 gport, u8 value)
obuf[2] = value;
ret = dvbsky_usb_generic_rw(d, obuf, 3, ibuf, 1);
if (ret)
- dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
- KBUILD_MODNAME, __func__, ret);
+ dev_err(&d->udev->dev, "failed=%d\n", ret);
return ret;
}
@@ -114,7 +122,7 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if (num > 2) {
dev_err(&d->udev->dev,
- "dvbsky_usb: too many i2c messages[%d] than 2.", num);
+ "too many i2c messages[%d], max 2.", num);
ret = -EOPNOTSUPP;
goto i2c_error;
}
@@ -122,7 +130,7 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
if (num == 1) {
if (msg[0].len > 60) {
dev_err(&d->udev->dev,
- "dvbsky_usb: too many i2c bytes[%d] than 60.",
+ "too many i2c bytes[%d], max 60.",
msg[0].len);
ret = -EOPNOTSUPP;
goto i2c_error;
@@ -136,8 +144,7 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = dvbsky_usb_generic_rw(d, obuf, 4,
ibuf, msg[0].len + 1);
if (ret)
- dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
- KBUILD_MODNAME, __func__, ret);
+ dev_err(&d->udev->dev, "failed=%d\n", ret);
if (!ret)
memcpy(msg[0].buf, &ibuf[1], msg[0].len);
} else {
@@ -149,13 +156,12 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = dvbsky_usb_generic_rw(d, obuf,
msg[0].len + 3, ibuf, 1);
if (ret)
- dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
- KBUILD_MODNAME, __func__, ret);
+ dev_err(&d->udev->dev, "failed=%d\n", ret);
}
} else {
if ((msg[0].len > 60) || (msg[1].len > 60)) {
dev_err(&d->udev->dev,
- "dvbsky_usb: too many i2c bytes[w-%d][r-%d] than 60.",
+ "too many i2c bytes[w-%d][r-%d], max 60.",
msg[0].len, msg[1].len);
ret = -EOPNOTSUPP;
goto i2c_error;
@@ -169,8 +175,7 @@ static int dvbsky_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
ret = dvbsky_usb_generic_rw(d, obuf,
msg[0].len + 4, ibuf, msg[1].len + 1);
if (ret)
- dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
- KBUILD_MODNAME, __func__, ret);
+ dev_err(&d->udev->dev, "failed=%d\n", ret);
if (!ret)
memcpy(msg[1].buf, &ibuf[1], msg[1].len);
@@ -201,8 +206,7 @@ static int dvbsky_rc_query(struct dvb_usb_device *d)
obuf[0] = 0x10;
ret = dvbsky_usb_generic_rw(d, obuf, 1, ibuf, 2);
if (ret)
- dev_err(&d->udev->dev, "%s: %s() failed=%d\n",
- KBUILD_MODNAME, __func__, ret);
+ dev_err(&d->udev->dev, "failed=%d\n", ret);
if (ret == 0)
code = (ibuf[0] << 8) | ibuf[1];
if (code != 0xffff) {
@@ -218,6 +222,11 @@ static int dvbsky_rc_query(struct dvb_usb_device *d)
static int dvbsky_get_rc_config(struct dvb_usb_device *d, struct dvb_usb_rc *rc)
{
+ if (dvb_usb_dvbsky_disable_rc) {
+ rc->map_name = NULL;
+ return 0;
+ }
+
rc->allowed_protos = RC_BIT_RC5;
rc->query = dvbsky_rc_query;
rc->interval = 300;
@@ -265,8 +274,6 @@ static int dvbsky_read_mac_addr(struct dvb_usb_adapter *adap, u8 mac[6])
if (i2c_transfer(&d->i2c_adap, msg, 2) == 2)
memcpy(mac, ibuf, 6);
- dev_info(&d->udev->dev, "dvbsky_usb MAC address=%pM\n", mac);
-
return 0;
}
@@ -362,6 +369,300 @@ fail_attach:
return ret;
}
+static int dvbsky_usb_ci_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ struct dvbsky_state *state = d_to_priv(d);
+ u8 value;
+
+ if (voltage == SEC_VOLTAGE_OFF)
+ value = 0;
+ else
+ value = 1;
+ dvbsky_gpio_ctrl(d, 0x00, value);
+
+ return state->fe_set_voltage(fe, voltage);
+}
+
+static int dvbsky_ci_ctrl(void *priv, u8 read, int addr,
+ u8 data, int *mem)
+{
+ struct dvb_usb_device *d = priv;
+ int ret = 0;
+ u8 command[4], respond[2], command_size, respond_size;
+
+ command[1] = (u8)((addr >> 8) & 0xff); /*high part of address*/
+ command[2] = (u8)(addr & 0xff); /*low part of address*/
+ if (read) {
+ command[0] = 0x71;
+ command_size = 3;
+ respond_size = 2;
+ } else {
+ command[0] = 0x70;
+ command[3] = data;
+ command_size = 4;
+ respond_size = 1;
+ }
+ ret = dvbsky_usb_generic_rw(d, command, command_size,
+ respond, respond_size);
+ if (ret)
+ goto err;
+ if (read)
+ *mem = respond[1];
+ return ret;
+err:
+ dev_err(&d->udev->dev, "ci control failed=%d\n", ret);
+ return ret;
+}
+
+static const struct m88ds3103_config dvbsky_s960c_m88ds3103_config = {
+ .i2c_addr = 0x68,
+ .clock = 27000000,
+ .i2c_wr_max = 33,
+ .clock_out = 0,
+ .ts_mode = M88DS3103_TS_CI,
+ .ts_clk = 10000,
+ .ts_clk_pol = 1,
+ .agc = 0x99,
+ .lnb_hv_pol = 0,
+ .lnb_en_pol = 1,
+};
+
+static int dvbsky_s960c_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvbsky_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret = 0;
+ /* demod I2C adapter */
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_client *client_tuner, *client_ci;
+ struct i2c_board_info info;
+ struct sp2_config sp2_config;
+ struct m88ts2022_config m88ts2022_config = {
+ .clock = 27000000,
+ };
+ memset(&info, 0, sizeof(struct i2c_board_info));
+
+ /* attach demod */
+ adap->fe[0] = dvb_attach(m88ds3103_attach,
+ &dvbsky_s960c_m88ds3103_config,
+ &d->i2c_adap,
+ &i2c_adapter);
+ if (!adap->fe[0]) {
+ dev_err(&d->udev->dev, "dvbsky_s960ci_attach fail.\n");
+ ret = -ENODEV;
+ goto fail_attach;
+ }
+
+ /* attach tuner */
+ m88ts2022_config.fe = adap->fe[0];
+ strlcpy(info.type, "m88ts2022", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &m88ts2022_config;
+ request_module("m88ts2022");
+ client_tuner = i2c_new_device(i2c_adapter, &info);
+ if (client_tuner == NULL || client_tuner->dev.driver == NULL) {
+ ret = -ENODEV;
+ goto fail_tuner_device;
+ }
+
+ if (!try_module_get(client_tuner->dev.driver->owner)) {
+ ret = -ENODEV;
+ goto fail_tuner_module;
+ }
+
+ /* attach ci controller */
+ memset(&sp2_config, 0, sizeof(sp2_config));
+ sp2_config.dvb_adap = &adap->dvb_adap;
+ sp2_config.priv = d;
+ sp2_config.ci_control = dvbsky_ci_ctrl;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+ info.addr = 0x40;
+ info.platform_data = &sp2_config;
+ request_module("sp2");
+ client_ci = i2c_new_device(&d->i2c_adap, &info);
+ if (client_ci == NULL || client_ci->dev.driver == NULL) {
+ ret = -ENODEV;
+ goto fail_ci_device;
+ }
+
+ if (!try_module_get(client_ci->dev.driver->owner)) {
+ ret = -ENODEV;
+ goto fail_ci_module;
+ }
+
+ /* delegate signal strength measurement to tuner */
+ adap->fe[0]->ops.read_signal_strength =
+ adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ /* hook fe: need to resync the slave fifo when signal locks. */
+ state->fe_read_status = adap->fe[0]->ops.read_status;
+ adap->fe[0]->ops.read_status = dvbsky_usb_read_status;
+
+ /* hook fe: LNB off/on is control by Cypress usb chip. */
+ state->fe_set_voltage = adap->fe[0]->ops.set_voltage;
+ adap->fe[0]->ops.set_voltage = dvbsky_usb_ci_set_voltage;
+
+ state->i2c_client_tuner = client_tuner;
+ state->i2c_client_ci = client_ci;
+ return ret;
+fail_ci_module:
+ i2c_unregister_device(client_ci);
+fail_ci_device:
+ module_put(client_tuner->dev.driver->owner);
+fail_tuner_module:
+ i2c_unregister_device(client_tuner);
+fail_tuner_device:
+ dvb_frontend_detach(adap->fe[0]);
+fail_attach:
+ return ret;
+}
+
+static int dvbsky_t680c_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvbsky_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret = 0;
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_client *client_demod, *client_tuner, *client_ci;
+ struct i2c_board_info info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+ struct sp2_config sp2_config;
+
+ /* attach demod */
+ memset(&si2168_config, 0, sizeof(si2168_config));
+ si2168_config.i2c_adapter = &i2c_adapter;
+ si2168_config.fe = &adap->fe[0];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+
+ request_module(info.type);
+ client_demod = i2c_new_device(&d->i2c_adap, &info);
+ if (client_demod == NULL ||
+ client_demod->dev.driver == NULL)
+ goto fail_demod_device;
+ if (!try_module_get(client_demod->dev.driver->owner))
+ goto fail_demod_module;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = adap->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+
+ request_module(info.type);
+ client_tuner = i2c_new_device(i2c_adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL)
+ goto fail_tuner_device;
+ if (!try_module_get(client_tuner->dev.driver->owner))
+ goto fail_tuner_module;
+
+ /* attach ci controller */
+ memset(&sp2_config, 0, sizeof(sp2_config));
+ sp2_config.dvb_adap = &adap->dvb_adap;
+ sp2_config.priv = d;
+ sp2_config.ci_control = dvbsky_ci_ctrl;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "sp2", I2C_NAME_SIZE);
+ info.addr = 0x40;
+ info.platform_data = &sp2_config;
+
+ request_module(info.type);
+ client_ci = i2c_new_device(&d->i2c_adap, &info);
+
+ if (client_ci == NULL || client_ci->dev.driver == NULL)
+ goto fail_ci_device;
+
+ if (!try_module_get(client_ci->dev.driver->owner))
+ goto fail_ci_module;
+
+ state->i2c_client_demod = client_demod;
+ state->i2c_client_tuner = client_tuner;
+ state->i2c_client_ci = client_ci;
+ return ret;
+fail_ci_module:
+ i2c_unregister_device(client_ci);
+fail_ci_device:
+ module_put(client_tuner->dev.driver->owner);
+fail_tuner_module:
+ i2c_unregister_device(client_tuner);
+fail_tuner_device:
+ module_put(client_demod->dev.driver->owner);
+fail_demod_module:
+ i2c_unregister_device(client_demod);
+fail_demod_device:
+ ret = -ENODEV;
+ return ret;
+}
+
+static int dvbsky_t330_attach(struct dvb_usb_adapter *adap)
+{
+ struct dvbsky_state *state = adap_to_priv(adap);
+ struct dvb_usb_device *d = adap_to_d(adap);
+ int ret = 0;
+ struct i2c_adapter *i2c_adapter;
+ struct i2c_client *client_demod, *client_tuner;
+ struct i2c_board_info info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+
+ /* attach demod */
+ memset(&si2168_config, 0, sizeof(si2168_config));
+ si2168_config.i2c_adapter = &i2c_adapter;
+ si2168_config.fe = &adap->fe[0];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL | 0x40;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+
+ request_module(info.type);
+ client_demod = i2c_new_device(&d->i2c_adap, &info);
+ if (client_demod == NULL ||
+ client_demod->dev.driver == NULL)
+ goto fail_demod_device;
+ if (!try_module_get(client_demod->dev.driver->owner))
+ goto fail_demod_module;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = adap->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2157", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+
+ request_module(info.type);
+ client_tuner = i2c_new_device(i2c_adapter, &info);
+ if (client_tuner == NULL ||
+ client_tuner->dev.driver == NULL)
+ goto fail_tuner_device;
+ if (!try_module_get(client_tuner->dev.driver->owner))
+ goto fail_tuner_module;
+
+ state->i2c_client_demod = client_demod;
+ state->i2c_client_tuner = client_tuner;
+ return ret;
+fail_tuner_module:
+ i2c_unregister_device(client_tuner);
+fail_tuner_device:
+ module_put(client_demod->dev.driver->owner);
+fail_demod_module:
+ i2c_unregister_device(client_demod);
+fail_demod_device:
+ ret = -ENODEV;
+ return ret;
+}
+
static int dvbsky_identify_state(struct dvb_usb_device *d, const char **name)
{
dvbsky_gpio_ctrl(d, 0x04, 1);
@@ -404,6 +705,18 @@ static void dvbsky_exit(struct dvb_usb_device *d)
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
}
+ client = state->i2c_client_demod;
+ /* remove I2C demod */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+ client = state->i2c_client_ci;
+ /* remove I2C ci */
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
}
/* DVB USB Driver stuff */
@@ -434,9 +747,104 @@ static struct dvb_usb_device_properties dvbsky_s960_props = {
}
};
+static struct dvb_usb_device_properties dvbsky_s960c_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct dvbsky_state),
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
+
+ .i2c_algo = &dvbsky_i2c_algo,
+ .frontend_attach = dvbsky_s960c_attach,
+ .init = dvbsky_init,
+ .get_rc_config = dvbsky_get_rc_config,
+ .streaming_ctrl = dvbsky_streaming_ctrl,
+ .identify_state = dvbsky_identify_state,
+ .exit = dvbsky_exit,
+ .read_mac_address = dvbsky_read_mac_addr,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
+ }
+ }
+};
+
+static struct dvb_usb_device_properties dvbsky_t680c_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct dvbsky_state),
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
+
+ .i2c_algo = &dvbsky_i2c_algo,
+ .frontend_attach = dvbsky_t680c_attach,
+ .init = dvbsky_init,
+ .get_rc_config = dvbsky_get_rc_config,
+ .streaming_ctrl = dvbsky_streaming_ctrl,
+ .identify_state = dvbsky_identify_state,
+ .exit = dvbsky_exit,
+ .read_mac_address = dvbsky_read_mac_addr,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
+ }
+ }
+};
+
+static struct dvb_usb_device_properties dvbsky_t330_props = {
+ .driver_name = KBUILD_MODNAME,
+ .owner = THIS_MODULE,
+ .adapter_nr = adapter_nr,
+ .size_of_priv = sizeof(struct dvbsky_state),
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+ .generic_bulk_ctrl_endpoint_response = 0x81,
+ .generic_bulk_ctrl_delay = DVBSKY_MSG_DELAY,
+
+ .i2c_algo = &dvbsky_i2c_algo,
+ .frontend_attach = dvbsky_t330_attach,
+ .init = dvbsky_init,
+ .get_rc_config = dvbsky_get_rc_config,
+ .streaming_ctrl = dvbsky_streaming_ctrl,
+ .identify_state = dvbsky_identify_state,
+ .exit = dvbsky_exit,
+ .read_mac_address = dvbsky_read_mac_addr,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .stream = DVB_USB_STREAM_BULK(0x82, 8, 4096),
+ }
+ }
+};
+
static const struct usb_device_id dvbsky_id_table[] = {
{ DVB_USB_DEVICE(0x0572, 0x6831,
&dvbsky_s960_props, "DVBSky S960/S860", RC_MAP_DVBSKY) },
+ { DVB_USB_DEVICE(0x0572, 0x960c,
+ &dvbsky_s960c_props, "DVBSky S960CI", RC_MAP_DVBSKY) },
+ { DVB_USB_DEVICE(0x0572, 0x680c,
+ &dvbsky_t680c_props, "DVBSky T680CI", RC_MAP_DVBSKY) },
+ { DVB_USB_DEVICE(0x0572, 0x0320,
+ &dvbsky_t330_props, "DVBSky T330", RC_MAP_DVBSKY) },
+ { DVB_USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_TVSTICK_CT2_4400,
+ &dvbsky_t330_props, "TechnoTrend TVStick CT2-4400",
+ RC_MAP_TT_1500) },
+ { DVB_USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI,
+ &dvbsky_t680c_props, "TechnoTrend TT-connect CT2-4650 CI",
+ RC_MAP_TT_1500) },
{ }
};
MODULE_DEVICE_TABLE(usb, dvbsky_id_table);
diff --git a/drivers/media/usb/dvb-usb-v2/lmedm04.c b/drivers/media/usb/dvb-usb-v2/lmedm04.c
index 9f2c545..994de53 100644
--- a/drivers/media/usb/dvb-usb-v2/lmedm04.c
+++ b/drivers/media/usb/dvb-usb-v2/lmedm04.c
@@ -817,20 +817,22 @@ static const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
case 0x1122:
switch (st->dvb_usb_lme2510_firmware) {
default:
- st->dvb_usb_lme2510_firmware = TUNER_S0194;
case TUNER_S0194:
fw_lme = fw_s0194;
ret = request_firmware(&fw, fw_lme, &udev->dev);
if (ret == 0) {
+ st->dvb_usb_lme2510_firmware = TUNER_S0194;
cold = 0;
break;
}
- st->dvb_usb_lme2510_firmware = TUNER_LG;
+ /* fall through */
case TUNER_LG:
fw_lme = fw_lg;
ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
+ if (ret == 0) {
+ st->dvb_usb_lme2510_firmware = TUNER_LG;
break;
+ }
st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
break;
}
@@ -838,26 +840,30 @@ static const char *lme_firmware_switch(struct dvb_usb_device *d, int cold)
case 0x1120:
switch (st->dvb_usb_lme2510_firmware) {
default:
- st->dvb_usb_lme2510_firmware = TUNER_S7395;
case TUNER_S7395:
fw_lme = fw_c_s7395;
ret = request_firmware(&fw, fw_lme, &udev->dev);
if (ret == 0) {
+ st->dvb_usb_lme2510_firmware = TUNER_S7395;
cold = 0;
break;
}
- st->dvb_usb_lme2510_firmware = TUNER_LG;
+ /* fall through */
case TUNER_LG:
fw_lme = fw_c_lg;
ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
+ if (ret == 0) {
+ st->dvb_usb_lme2510_firmware = TUNER_LG;
break;
- st->dvb_usb_lme2510_firmware = TUNER_S0194;
+ }
+ /* fall through */
case TUNER_S0194:
fw_lme = fw_c_s0194;
ret = request_firmware(&fw, fw_lme, &udev->dev);
- if (ret == 0)
+ if (ret == 0) {
+ st->dvb_usb_lme2510_firmware = TUNER_S0194;
break;
+ }
st->dvb_usb_lme2510_firmware = TUNER_DEFAULT;
cold = 0;
break;
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
index 27b1e03..896a225 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.c
@@ -24,6 +24,9 @@
#include "rtl2830.h"
#include "rtl2832.h"
+#include "rtl2832_sdr.h"
+#include "mn88472.h"
+#include "mn88473.h"
#include "qt1010.h"
#include "mt2060.h"
@@ -35,25 +38,6 @@
#include "tua9001.h"
#include "r820t.h"
-/*
- * RTL2832_SDR module is in staging. That logic is added in order to avoid any
- * hard dependency to drivers/staging/ directory as we want compile mainline
- * driver even whole staging directory is missing.
- */
-#include <media/v4l2-subdev.h>
-
-#if IS_ENABLED(CONFIG_DVB_RTL2832_SDR)
-struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
- struct v4l2_subdev *sd);
-#else
-static inline struct dvb_frontend *rtl2832_sdr_attach(struct dvb_frontend *fe,
- struct i2c_adapter *i2c, const struct rtl2832_config *cfg,
- struct v4l2_subdev *sd)
-{
- return NULL;
-}
-#endif
#ifdef CONFIG_MEDIA_ATTACH
#define dvb_attach_sdr(FUNCTION, ARGS...) ({ \
@@ -420,6 +404,8 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
struct rtl28xxu_req req_tda18272 = {0x00c0, CMD_I2C_RD, 2, buf};
struct rtl28xxu_req req_r820t = {0x0034, CMD_I2C_RD, 1, buf};
struct rtl28xxu_req req_r828d = {0x0074, CMD_I2C_RD, 1, buf};
+ struct rtl28xxu_req req_mn88472 = {0xff38, CMD_I2C_RD, 1, buf};
+ struct rtl28xxu_req req_mn88473 = {0xff38, CMD_I2C_RD, 1, buf};
dev_dbg(&d->udev->dev, "%s:\n", __func__);
@@ -449,7 +435,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0xa1) {
priv->tuner = TUNER_RTL2832_FC0012;
priv->tuner_name = "FC0012";
- goto found;
+ goto tuner_found;
}
/* check FC0013 ID register; reg=00 val=a3 */
@@ -457,7 +443,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0xa3) {
priv->tuner = TUNER_RTL2832_FC0013;
priv->tuner_name = "FC0013";
- goto found;
+ goto tuner_found;
}
/* check MT2266 ID register; reg=00 val=85 */
@@ -465,7 +451,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x85) {
priv->tuner = TUNER_RTL2832_MT2266;
priv->tuner_name = "MT2266";
- goto found;
+ goto tuner_found;
}
/* check FC2580 ID register; reg=01 val=56 */
@@ -473,7 +459,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x56) {
priv->tuner = TUNER_RTL2832_FC2580;
priv->tuner_name = "FC2580";
- goto found;
+ goto tuner_found;
}
/* check MT2063 ID register; reg=00 val=9e || 9c */
@@ -481,7 +467,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && (buf[0] == 0x9e || buf[0] == 0x9c)) {
priv->tuner = TUNER_RTL2832_MT2063;
priv->tuner_name = "MT2063";
- goto found;
+ goto tuner_found;
}
/* check MAX3543 ID register; reg=00 val=38 */
@@ -489,7 +475,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x38) {
priv->tuner = TUNER_RTL2832_MAX3543;
priv->tuner_name = "MAX3543";
- goto found;
+ goto tuner_found;
}
/* check TUA9001 ID register; reg=7e val=2328 */
@@ -497,7 +483,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x23 && buf[1] == 0x28) {
priv->tuner = TUNER_RTL2832_TUA9001;
priv->tuner_name = "TUA9001";
- goto found;
+ goto tuner_found;
}
/* check MXL5007R ID register; reg=d9 val=14 */
@@ -505,7 +491,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x14) {
priv->tuner = TUNER_RTL2832_MXL5007T;
priv->tuner_name = "MXL5007T";
- goto found;
+ goto tuner_found;
}
/* check E4000 ID register; reg=02 val=40 */
@@ -513,7 +499,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x40) {
priv->tuner = TUNER_RTL2832_E4000;
priv->tuner_name = "E4000";
- goto found;
+ goto tuner_found;
}
/* check TDA18272 ID register; reg=00 val=c760 */
@@ -521,7 +507,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && (buf[0] == 0xc7 || buf[1] == 0x60)) {
priv->tuner = TUNER_RTL2832_TDA18272;
priv->tuner_name = "TDA18272";
- goto found;
+ goto tuner_found;
}
/* check R820T ID register; reg=00 val=69 */
@@ -529,7 +515,7 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x69) {
priv->tuner = TUNER_RTL2832_R820T;
priv->tuner_name = "R820T";
- goto found;
+ goto tuner_found;
}
/* check R828D ID register; reg=00 val=69 */
@@ -537,13 +523,44 @@ static int rtl2832u_read_config(struct dvb_usb_device *d)
if (ret == 0 && buf[0] == 0x69) {
priv->tuner = TUNER_RTL2832_R828D;
priv->tuner_name = "R828D";
- goto found;
+ goto tuner_found;
}
-
-found:
+tuner_found:
dev_dbg(&d->udev->dev, "%s: tuner=%s\n", __func__, priv->tuner_name);
+ /* probe slave demod */
+ if (priv->tuner == TUNER_RTL2832_R828D) {
+ /* power on MN88472 demod on GPIO0 */
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x01, 0x01);
+ if (ret)
+ goto err;
+
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
+ if (ret)
+ goto err;
+
+ ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
+ if (ret)
+ goto err;
+
+ /* check MN88472 answers */
+ ret = rtl28xxu_ctrl_msg(d, &req_mn88472);
+ if (ret == 0 && buf[0] == 0x02) {
+ dev_dbg(&d->udev->dev, "%s: MN88472 found\n", __func__);
+ priv->slave_demod = SLAVE_DEMOD_MN88472;
+ goto demod_found;
+ }
+
+ ret = rtl28xxu_ctrl_msg(d, &req_mn88473);
+ if (ret == 0 && buf[0] == 0x03) {
+ dev_dbg(&d->udev->dev, "%s: MN88473 found\n", __func__);
+ priv->slave_demod = SLAVE_DEMOD_MN88473;
+ goto demod_found;
+ }
+ }
+
+demod_found:
/* close demod I2C gate */
ret = rtl28xxu_ctrl_msg(d, &req_gate_close);
if (ret < 0)
@@ -818,7 +835,66 @@ static int rtl2832u_frontend_attach(struct dvb_usb_adapter *adap)
/* set fe callback */
adap->fe[0]->callback = rtl2832u_frontend_callback;
+ if (priv->slave_demod) {
+ struct i2c_board_info info = {};
+ struct i2c_client *client;
+
+ /*
+ * We continue on reduced mode, without DVB-T2/C, using master
+ * demod, when slave demod fails.
+ */
+ ret = 0;
+
+ /* attach slave demodulator */
+ if (priv->slave_demod == SLAVE_DEMOD_MN88472) {
+ struct mn88472_config mn88472_config = {};
+
+ mn88472_config.fe = &adap->fe[1];
+ mn88472_config.i2c_wr_max = 22,
+ strlcpy(info.type, "mn88472", I2C_NAME_SIZE);
+ info.addr = 0x18;
+ info.platform_data = &mn88472_config;
+ request_module(info.type);
+ client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ priv->slave_demod = SLAVE_DEMOD_NONE;
+ goto err_slave_demod_failed;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ priv->slave_demod = SLAVE_DEMOD_NONE;
+ goto err_slave_demod_failed;
+ }
+
+ priv->i2c_client_slave_demod = client;
+ } else {
+ struct mn88473_config mn88473_config = {};
+
+ mn88473_config.fe = &adap->fe[1];
+ mn88473_config.i2c_wr_max = 22,
+ strlcpy(info.type, "mn88473", I2C_NAME_SIZE);
+ info.addr = 0x18;
+ info.platform_data = &mn88473_config;
+ request_module(info.type);
+ client = i2c_new_device(priv->demod_i2c_adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ priv->slave_demod = SLAVE_DEMOD_NONE;
+ goto err_slave_demod_failed;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ priv->slave_demod = SLAVE_DEMOD_NONE;
+ goto err_slave_demod_failed;
+ }
+
+ priv->i2c_client_slave_demod = client;
+ }
+ }
+
return 0;
+err_slave_demod_failed:
err:
dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
return ret;
@@ -984,7 +1060,7 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
break;
}
- priv->client = client;
+ priv->i2c_client_tuner = client;
sd = i2c_get_clientdata(client);
i2c_set_adapdata(i2c_adap_internal, d);
@@ -1024,32 +1100,30 @@ static int rtl2832u_tuner_attach(struct dvb_usb_adapter *adap)
&rtl28xxu_rtl2832_r820t_config, NULL);
break;
case TUNER_RTL2832_R828D:
- /* power off mn88472 demod on GPIO0 */
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_VAL, 0x00, 0x01);
- if (ret)
- goto err;
-
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_DIR, 0x00, 0x01);
- if (ret)
- goto err;
-
- ret = rtl28xx_wr_reg_mask(d, SYS_GPIO_OUT_EN, 0x01, 0x01);
- if (ret)
- goto err;
-
- fe = dvb_attach(r820t_attach, adap->fe[0], &d->i2c_adap,
+ fe = dvb_attach(r820t_attach, adap->fe[0],
+ priv->demod_i2c_adapter,
&rtl2832u_r828d_config);
-
- /* Use tuner to get the signal strength */
adap->fe[0]->ops.read_signal_strength =
adap->fe[0]->ops.tuner_ops.get_rf_strength;
+
+ if (adap->fe[1]) {
+ fe = dvb_attach(r820t_attach, adap->fe[1],
+ priv->demod_i2c_adapter,
+ &rtl2832u_r828d_config);
+ adap->fe[1]->ops.read_signal_strength =
+ adap->fe[1]->ops.tuner_ops.get_rf_strength;
+ }
+
+ /* attach SDR */
+ dvb_attach_sdr(rtl2832_sdr_attach, adap->fe[0], &d->i2c_adap,
+ &rtl28xxu_rtl2832_r820t_config, NULL);
break;
default:
dev_err(&d->udev->dev, "%s: unknown tuner=%d\n", KBUILD_MODNAME,
priv->tuner);
}
- if (fe == NULL && priv->client == NULL) {
+ if (fe == NULL && priv->i2c_client_tuner == NULL) {
ret = -ENODEV;
goto err;
}
@@ -1097,11 +1171,19 @@ err:
static void rtl28xxu_exit(struct dvb_usb_device *d)
{
struct rtl28xxu_priv *priv = d->priv;
- struct i2c_client *client = priv->client;
+ struct i2c_client *client;
dev_dbg(&d->udev->dev, "%s:\n", __func__);
/* remove I2C tuner */
+ client = priv->i2c_client_tuner;
+ if (client) {
+ module_put(client->dev.driver->owner);
+ i2c_unregister_device(client);
+ }
+
+ /* remove I2C slave demod */
+ client = priv->i2c_client_slave_demod;
if (client) {
module_put(client->dev.driver->owner);
i2c_unregister_device(client);
@@ -1201,13 +1283,6 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
if (ret)
goto err;
- mdelay(5);
-
- /* enable ADC */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x48, 0x48);
- if (ret)
- goto err;
-
/* streaming EP: clear stall & reset */
ret = rtl28xx_wr_regs(d, USB_EPA_CTL, "\x00\x00", 2);
if (ret)
@@ -1222,11 +1297,6 @@ static int rtl2832u_power_ctrl(struct dvb_usb_device *d, int onoff)
if (ret)
goto err;
- /* disable ADC */
- ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x48);
- if (ret)
- goto err;
-
/* disable PLL */
ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, 0x00, 0x80);
if (ret)
@@ -1244,6 +1314,38 @@ err:
return ret;
}
+static int rtl2832u_frontend_ctrl(struct dvb_frontend *fe, int onoff)
+{
+ struct dvb_usb_device *d = fe_to_d(fe);
+ struct dvb_usb_adapter *adap = fe_to_adap(fe);
+ int ret;
+ u8 val;
+
+ dev_dbg(&d->udev->dev, "%s: fe=%d onoff=%d\n", __func__, fe->id, onoff);
+
+ /* control internal demod ADC */
+ if (fe->id == 0 && onoff)
+ val = 0x48; /* enable ADC */
+ else
+ val = 0x00; /* disable ADC */
+
+ ret = rtl28xx_wr_reg_mask(d, SYS_DEMOD_CTL, val, 0x48);
+ if (ret)
+ goto err;
+
+ /* bypass slave demod TS through master demod */
+ if (fe->id == 1 && onoff) {
+ ret = rtl2832_enable_external_ts_if(adap->fe[0]);
+ if (ret)
+ goto err;
+ }
+
+ return 0;
+err:
+ dev_dbg(&d->udev->dev, "%s: failed=%d\n", __func__, ret);
+ return ret;
+}
+
#if IS_ENABLED(CONFIG_RC_CORE)
static int rtl2831u_rc_query(struct dvb_usb_device *d)
{
@@ -1467,6 +1569,7 @@ static const struct dvb_usb_device_properties rtl2832u_props = {
.size_of_priv = sizeof(struct rtl28xxu_priv),
.power_ctrl = rtl2832u_power_ctrl,
+ .frontend_ctrl = rtl2832u_frontend_ctrl,
.i2c_algo = &rtl28xxu_i2c_algo,
.read_config = rtl2832u_read_config,
.frontend_attach = rtl2832u_frontend_attach,
diff --git a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
index a26cab1..3e3ea9d 100644
--- a/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
+++ b/drivers/media/usb/dvb-usb-v2/rtl28xxu.h
@@ -57,7 +57,12 @@ struct rtl28xxu_priv {
u8 page; /* integrated demod active register page */
struct i2c_adapter *demod_i2c_adapter;
bool rc_active;
- struct i2c_client *client;
+ struct i2c_client *i2c_client_tuner;
+ struct i2c_client *i2c_client_slave_demod;
+ #define SLAVE_DEMOD_NONE 0
+ #define SLAVE_DEMOD_MN88472 1
+ #define SLAVE_DEMOD_MN88473 2
+ unsigned int slave_demod:2;
};
enum rtl28xxu_chip_id {
diff --git a/drivers/media/usb/dvb-usb/Kconfig b/drivers/media/usb/dvb-usb/Kconfig
index 41d3eb9..3364200 100644
--- a/drivers/media/usb/dvb-usb/Kconfig
+++ b/drivers/media/usb/dvb-usb/Kconfig
@@ -130,7 +130,6 @@ config DVB_USB_CXUSB
Medion MD95700 hybrid USB2.0 device.
DViCO FusionHDTV (Bluebird) USB2.0 devices
- TechnoTrend TVStick CT2-4400 and CT2-4650 CI devices
config DVB_USB_M920X
tristate "Uli m920x DVB-T USB2.0 support"
diff --git a/drivers/media/usb/dvb-usb/af9005.c b/drivers/media/usb/dvb-usb/af9005.c
index 3f4361e..efa782e 100644
--- a/drivers/media/usb/dvb-usb/af9005.c
+++ b/drivers/media/usb/dvb-usb/af9005.c
@@ -1081,9 +1081,12 @@ static int __init af9005_usb_module_init(void)
err("usb_register failed. (%d)", result);
return result;
}
+#if IS_MODULE(CONFIG_DVB_USB_AF9005) || defined(CONFIG_DVB_USB_AF9005_REMOTE)
+ /* FIXME: convert to todays kernel IR infrastructure */
rc_decode = symbol_request(af9005_rc_decode);
rc_keys = symbol_request(rc_map_af9005_table);
rc_keys_size = symbol_request(rc_map_af9005_table_size);
+#endif
if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
err("af9005_rc_decode function not found, disabling remote");
af9005_properties.rc.legacy.rc_query = NULL;
diff --git a/drivers/media/usb/dvb-usb/cxusb.c b/drivers/media/usb/dvb-usb/cxusb.c
index 356abb3..0f345b1 100644
--- a/drivers/media/usb/dvb-usb/cxusb.c
+++ b/drivers/media/usb/dvb-usb/cxusb.c
@@ -44,7 +44,6 @@
#include "atbm8830.h"
#include "si2168.h"
#include "si2157.h"
-#include "sp2.h"
/* Max transfer size done by I2C transfer functions */
#define MAX_XFER_SIZE 80
@@ -147,22 +146,6 @@ static int cxusb_d680_dmb_gpio_tuner(struct dvb_usb_device *d,
}
}
-static int cxusb_tt_ct2_4400_gpio_tuner(struct dvb_usb_device *d, int onoff)
-{
- u8 o[2], i;
- int rc;
-
- o[0] = 0x83;
- o[1] = onoff;
- rc = cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
-
- if (rc) {
- deb_info("gpio_write failed.\n");
- return -EIO;
- }
- return 0;
-}
-
/* I2C */
static int cxusb_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
int num)
@@ -524,30 +507,6 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
return 0;
}
-static int cxusb_tt_ct2_4400_rc_query(struct dvb_usb_device *d)
-{
- u8 i[2];
- int ret;
- u32 cmd, keycode;
- u8 rc5_cmd, rc5_addr, rc5_toggle;
-
- ret = cxusb_ctrl_msg(d, 0x10, NULL, 0, i, 2);
- if (ret)
- return ret;
-
- cmd = (i[0] << 8) | i[1];
-
- if (cmd != 0xffff) {
- rc5_cmd = cmd & 0x3F; /* bits 1-6 for command */
- rc5_addr = (cmd & 0x07C0) >> 6; /* bits 7-11 for address */
- rc5_toggle = (cmd & 0x0800) >> 11; /* bit 12 for toggle */
- keycode = (rc5_addr << 8) | rc5_cmd;
- rc_keydown(d->rc_dev, RC_BIT_RC5, keycode, rc5_toggle);
- }
-
- return 0;
-}
-
static struct rc_map_table rc_map_dvico_mce_table[] = {
{ 0xfe02, KEY_TV },
{ 0xfe0e, KEY_MP3 },
@@ -673,70 +632,6 @@ static struct rc_map_table rc_map_d680_dmb_table[] = {
{ 0x0025, KEY_POWER },
};
-static int cxusb_tt_ct2_4400_read_mac_address(struct dvb_usb_device *d, u8 mac[6])
-{
- u8 wbuf[2];
- u8 rbuf[6];
- int ret;
- struct i2c_msg msg[] = {
- {
- .addr = 0x51,
- .flags = 0,
- .buf = wbuf,
- .len = 2,
- }, {
- .addr = 0x51,
- .flags = I2C_M_RD,
- .buf = rbuf,
- .len = 6,
- }
- };
-
- wbuf[0] = 0x1e;
- wbuf[1] = 0x00;
- ret = cxusb_i2c_xfer(&d->i2c_adap, msg, 2);
-
- if (ret == 2) {
- memcpy(mac, rbuf, 6);
- return 0;
- } else {
- if (ret < 0)
- return ret;
- return -EIO;
- }
-}
-
-static int cxusb_tt_ct2_4650_ci_ctrl(void *priv, u8 read, int addr,
- u8 data, int *mem)
-{
- struct dvb_usb_device *d = priv;
- u8 wbuf[3];
- u8 rbuf[2];
- int ret;
-
- wbuf[0] = (addr >> 8) & 0xff;
- wbuf[1] = addr & 0xff;
-
- if (read) {
- ret = cxusb_ctrl_msg(d, CMD_SP2_CI_READ, wbuf, 2, rbuf, 2);
- } else {
- wbuf[2] = data;
- ret = cxusb_ctrl_msg(d, CMD_SP2_CI_WRITE, wbuf, 3, rbuf, 1);
- }
-
- if (ret)
- goto err;
-
- if (read)
- *mem = rbuf[1];
-
- return 0;
-err:
- deb_info("%s: ci usb write returned %d\n", __func__, ret);
- return ret;
-
-}
-
static int cxusb_dee1601_demod_init(struct dvb_frontend* fe)
{
static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x28 };
@@ -1408,36 +1303,34 @@ static int cxusb_mygica_d689_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
+static int cxusb_mygica_t230_frontend_attach(struct dvb_usb_adapter *adap)
{
struct dvb_usb_device *d = adap->dev;
struct cxusb_state *st = d->priv;
struct i2c_adapter *adapter;
struct i2c_client *client_demod;
struct i2c_client *client_tuner;
- struct i2c_client *client_ci;
struct i2c_board_info info;
struct si2168_config si2168_config;
struct si2157_config si2157_config;
- struct sp2_config sp2_config;
- u8 o[2], i;
- /* reset the tuner */
- if (cxusb_tt_ct2_4400_gpio_tuner(d, 0) < 0) {
- err("clear tuner gpio failed");
- return -EIO;
- }
- msleep(100);
- if (cxusb_tt_ct2_4400_gpio_tuner(d, 1) < 0) {
- err("set tuner gpio failed");
- return -EIO;
- }
- msleep(100);
+ /* Select required USB configuration */
+ if (usb_set_interface(d->udev, 0, 0) < 0)
+ err("set interface failed");
+
+ /* Unblock all USB pipes */
+ usb_clear_halt(d->udev,
+ usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev,
+ usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev,
+ usb_rcvbulkpipe(d->udev, d->props.adapter[0].fe[0].stream.endpoint));
/* attach frontend */
si2168_config.i2c_adapter = &adapter;
si2168_config.fe = &adap->fe_adap[0].fe;
si2168_config.ts_mode = SI2168_TS_PARALLEL;
+ si2168_config.ts_clock_inv = 1;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "si2168", I2C_NAME_SIZE);
info.addr = 0x64;
@@ -1477,48 +1370,6 @@ static int cxusb_tt_ct2_4400_attach(struct dvb_usb_adapter *adap)
st->i2c_client_tuner = client_tuner;
- /* initialize CI */
- if (d->udev->descriptor.idProduct ==
- USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) {
-
- memcpy(o, "\xc0\x01", 2);
- cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
- msleep(100);
-
- memcpy(o, "\xc0\x00", 2);
- cxusb_ctrl_msg(d, CMD_GPIO_WRITE, o, 2, &i, 1);
- msleep(100);
-
- memset(&sp2_config, 0, sizeof(sp2_config));
- sp2_config.dvb_adap = &adap->dvb_adap;
- sp2_config.priv = d;
- sp2_config.ci_control = cxusb_tt_ct2_4650_ci_ctrl;
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "sp2", I2C_NAME_SIZE);
- info.addr = 0x40;
- info.platform_data = &sp2_config;
- request_module(info.type);
- client_ci = i2c_new_device(&d->i2c_adap, &info);
- if (client_ci == NULL || client_ci->dev.driver == NULL) {
- module_put(client_tuner->dev.driver->owner);
- i2c_unregister_device(client_tuner);
- module_put(client_demod->dev.driver->owner);
- i2c_unregister_device(client_demod);
- return -ENODEV;
- }
- if (!try_module_get(client_ci->dev.driver->owner)) {
- i2c_unregister_device(client_ci);
- module_put(client_tuner->dev.driver->owner);
- i2c_unregister_device(client_tuner);
- module_put(client_demod->dev.driver->owner);
- i2c_unregister_device(client_demod);
- return -ENODEV;
- }
-
- st->i2c_client_ci = client_ci;
-
- }
-
return 0;
}
@@ -1603,7 +1454,7 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
static struct dvb_usb_device_properties cxusb_aver_a868r_properties;
static struct dvb_usb_device_properties cxusb_d680_dmb_properties;
static struct dvb_usb_device_properties cxusb_mygica_d689_properties;
-static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties;
+static struct dvb_usb_device_properties cxusb_mygica_t230_properties;
static int cxusb_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -1634,7 +1485,7 @@ static int cxusb_probe(struct usb_interface *intf,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &cxusb_mygica_d689_properties,
THIS_MODULE, NULL, adapter_nr) ||
- 0 == dvb_usb_device_init(intf, &cxusb_tt_ct2_4400_properties,
+ 0 == dvb_usb_device_init(intf, &cxusb_mygica_t230_properties,
THIS_MODULE, NULL, adapter_nr) ||
0)
return 0;
@@ -1648,13 +1499,6 @@ static void cxusb_disconnect(struct usb_interface *intf)
struct cxusb_state *st = d->priv;
struct i2c_client *client;
- /* remove I2C client for CI */
- client = st->i2c_client_ci;
- if (client) {
- module_put(client->dev.driver->owner);
- i2c_unregister_device(client);
- }
-
/* remove I2C client for tuner */
client = st->i2c_client_tuner;
if (client) {
@@ -1693,8 +1537,7 @@ static struct usb_device_id cxusb_table [] = {
{ USB_DEVICE(USB_VID_DVICO, USB_PID_DVICO_BLUEBIRD_DUAL_4_REV_2) },
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_CONEXANT_D680_DMB) },
{ USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_D689) },
- { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_TVSTICK_CT2_4400) },
- { USB_DEVICE(USB_VID_TECHNOTREND, USB_PID_TECHNOTREND_CONNECT_CT2_4650_CI) },
+ { USB_DEVICE(USB_VID_CONEXANT, USB_PID_MYGICA_T230) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, cxusb_table);
@@ -2341,7 +2184,7 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
}
};
-static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
+static struct dvb_usb_device_properties cxusb_mygica_t230_properties = {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
.usb_ctrl = CYPRESS_FX2,
@@ -2349,25 +2192,21 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
.size_of_priv = sizeof(struct cxusb_state),
.num_adapters = 1,
- .read_mac_address = cxusb_tt_ct2_4400_read_mac_address,
-
.adapter = {
{
.num_frontends = 1,
.fe = {{
.streaming_ctrl = cxusb_streaming_ctrl,
- /* both frontend and tuner attached in the
- same function */
- .frontend_attach = cxusb_tt_ct2_4400_attach,
+ .frontend_attach = cxusb_mygica_t230_frontend_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
.type = USB_BULK,
- .count = 8,
- .endpoint = 0x82,
+ .count = 5,
+ .endpoint = 0x02,
.u = {
.bulk = {
- .buffersize = 4096,
+ .buffersize = 8192,
}
}
},
@@ -2375,28 +2214,25 @@ static struct dvb_usb_device_properties cxusb_tt_ct2_4400_properties = {
},
},
- .i2c_algo = &cxusb_i2c_algo,
+ .power_ctrl = cxusb_d680_dmb_power_ctrl,
+
+ .i2c_algo = &cxusb_i2c_algo,
+
.generic_bulk_ctrl_endpoint = 0x01,
- .generic_bulk_ctrl_endpoint_response = 0x81,
- .rc.core = {
- .rc_codes = RC_MAP_TT_1500,
- .allowed_protos = RC_BIT_RC5,
- .rc_query = cxusb_tt_ct2_4400_rc_query,
- .rc_interval = 150,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_d680_dmb_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table),
+ .rc_query = cxusb_d680_dmb_rc_query,
},
- .num_device_descs = 2,
+ .num_device_descs = 1,
.devices = {
{
- "TechnoTrend TVStick CT2-4400",
- { NULL },
- { &cxusb_table[20], NULL },
- },
- {
- "TechnoTrend TT-connect CT2-4650 CI",
+ "Mygica T230 DVB-T/T2/C",
{ NULL },
- { &cxusb_table[21], NULL },
+ { &cxusb_table[22], NULL },
},
}
};
diff --git a/drivers/media/usb/dvb-usb/cxusb.h b/drivers/media/usb/dvb-usb/cxusb.h
index 29f3e2e..527ff79 100644
--- a/drivers/media/usb/dvb-usb/cxusb.h
+++ b/drivers/media/usb/dvb-usb/cxusb.h
@@ -28,14 +28,10 @@
#define CMD_ANALOG 0x50
#define CMD_DIGITAL 0x51
-#define CMD_SP2_CI_WRITE 0x70
-#define CMD_SP2_CI_READ 0x71
-
struct cxusb_state {
u8 gpio_write_state[3];
struct i2c_client *i2c_client_demod;
struct i2c_client *i2c_client_tuner;
- struct i2c_client *i2c_client_ci;
};
#endif
diff --git a/drivers/media/usb/dvb-usb/technisat-usb2.c b/drivers/media/usb/dvb-usb/technisat-usb2.c
index 6b0b8b6..5801ae7 100644
--- a/drivers/media/usb/dvb-usb/technisat-usb2.c
+++ b/drivers/media/usb/dvb-usb/technisat-usb2.c
@@ -449,6 +449,8 @@ static int technisat_usb2_read_mac_address(struct dvb_usb_device *d,
return 0;
}
+static struct stv090x_config technisat_usb2_stv090x_config;
+
/* frontend attach */
static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
fe_sec_voltage_t voltage)
@@ -472,7 +474,8 @@ static int technisat_usb2_set_voltage(struct dvb_frontend *fe,
}
for (i = 0; i < 3; i++)
- if (stv090x_set_gpio(fe, i+2, 0, gpio[i], 0) != 0)
+ if (technisat_usb2_stv090x_config.set_gpio(fe, i+2, 0,
+ gpio[i], 0) != 0)
return -EREMOTEIO;
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx-audio.c b/drivers/media/usb/em28xx/em28xx-audio.c
index 957c7ae..44ae1e0 100644
--- a/drivers/media/usb/em28xx/em28xx-audio.c
+++ b/drivers/media/usb/em28xx/em28xx-audio.c
@@ -56,7 +56,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "em28xx-audio %s: " fmt, \
- __func__, ##arg); \
+ __func__, ##arg); \
} while (0)
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
@@ -232,7 +232,6 @@ static struct snd_pcm_hardware snd_em28xx_hw_capture = {
.channels_max = 2,
.buffer_bytes_max = 62720 * 8, /* just about the value in usbaudio.c */
-
/*
* The period is 12.288 bytes. Allow a 10% of variation along its
* value, in order to avoid overruns/underruns due to some clock
@@ -361,7 +360,7 @@ static int snd_em28xx_hw_capture_params(struct snd_pcm_substream *substream,
dprintk("Setting capture parameters\n");
ret = snd_pcm_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
+ params_buffer_bytes(hw_params));
if (ret < 0)
return ret;
#if 0
@@ -478,7 +477,7 @@ static struct page *snd_pcm_get_vmalloc_page(struct snd_pcm_substream *subs,
* AC97 volume control support
*/
static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *info)
+ struct snd_ctl_elem_info *info)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
@@ -494,7 +493,7 @@ static int em28xx_vol_info(struct snd_kcontrol *kcontrol,
}
static int em28xx_vol_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
+ struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
@@ -534,7 +533,7 @@ err:
}
static int em28xx_vol_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *value)
+ struct snd_ctl_elem_value *value)
{
struct em28xx *dev = snd_kcontrol_chip(kcontrol);
struct snd_pcm_substream *substream = dev->adev.capture_pcm_substream;
@@ -655,7 +654,7 @@ static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
struct snd_kcontrol *kctl;
struct snd_kcontrol_new tmp;
- memset (&tmp, 0, sizeof(tmp));
+ memset(&tmp, 0, sizeof(tmp));
tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
tmp.private_value = id,
tmp.name = ctl_name,
@@ -672,7 +671,7 @@ static int em28xx_cvol_new(struct snd_card *card, struct em28xx *dev,
dprintk("Added control %s for ac97 volume control 0x%04x\n",
ctl_name, id);
- memset (&tmp, 0, sizeof(tmp));
+ memset(&tmp, 0, sizeof(tmp));
tmp.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
tmp.private_value = id,
tmp.name = ctl_name,
@@ -731,7 +730,7 @@ static void em28xx_audio_free_urb(struct em28xx *dev)
/* high bandwidth multiplier, as encoded in highspeed endpoint descriptors */
static int em28xx_audio_ep_packet_size(struct usb_device *udev,
- struct usb_endpoint_descriptor *e)
+ struct usb_endpoint_descriptor *e)
{
int size = le16_to_cpu(e->wMaxPacketSize);
@@ -781,7 +780,7 @@ static int em28xx_audio_urb_init(struct em28xx *dev)
interval = 1 << (ep->bInterval - 1);
em28xx_info("Endpoint 0x%02x %s on intf %d alt %d interval = %d, size %d\n",
- EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed),
+ EM28XX_EP_AUDIO, usb_speed_string(dev->udev->speed),
dev->ifnum, alt,
interval,
ep_size);
diff --git a/drivers/media/usb/em28xx/em28xx-camera.c b/drivers/media/usb/em28xx/em28xx-camera.c
index 6d2ea9a..7be661f 100644
--- a/drivers/media/usb/em28xx/em28xx-camera.c
+++ b/drivers/media/usb/em28xx/em28xx-camera.c
@@ -27,7 +27,6 @@
#include "em28xx.h"
-
/* Possible i2c addresses of Micron sensors */
static unsigned short micron_sensor_addrs[] = {
0xb8 >> 1, /* MT9V111, MT9V403 */
@@ -43,7 +42,6 @@ static unsigned short omnivision_sensor_addrs[] = {
I2C_CLIENT_END
};
-
static struct soc_camera_link camlink = {
.bus_id = 0,
.flags = 0,
@@ -51,7 +49,6 @@ static struct soc_camera_link camlink = {
.unbalanced_power = true,
};
-
/* FIXME: Should be replaced by a proper mt9m111 driver */
static int em28xx_initialize_mt9m111(struct em28xx *dev)
{
@@ -70,7 +67,6 @@ static int em28xx_initialize_mt9m111(struct em28xx *dev)
return 0;
}
-
/* FIXME: Should be replaced by a proper mt9m001 driver */
static int em28xx_initialize_mt9m001(struct em28xx *dev)
{
@@ -98,7 +94,6 @@ static int em28xx_initialize_mt9m001(struct em28xx *dev)
return 0;
}
-
/*
* Probes Micron sensors with 8 bit address and 16 bit register width
*/
@@ -430,7 +425,7 @@ int em28xx_init_camera(struct em28xx *dev)
break;
}
- fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt.code = MEDIA_BUS_FMT_YUYV8_2X8;
fmt.width = 640;
fmt.height = 480;
v4l2_subdev_call(subdev, video, s_mbus_fmt, &fmt);
diff --git a/drivers/media/usb/em28xx/em28xx-cards.c b/drivers/media/usb/em28xx/em28xx-cards.c
index 71fa51e..d9704e6 100644
--- a/drivers/media/usb/em28xx/em28xx-cards.c
+++ b/drivers/media/usb/em28xx/em28xx-cards.c
@@ -64,7 +64,6 @@ module_param(usb_xfer_mode, int, 0444);
MODULE_PARM_DESC(usb_xfer_mode,
"USB transfer mode for frame data (-1 = auto, 0 = prefer isoc, 1 = prefer bulk)");
-
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS - 1 */
static DECLARE_BITMAP(em28xx_devused, EM28XX_MAXBOARDS);
@@ -190,8 +189,8 @@ static struct em28xx_reg_seq kworld_a340_digital[] = {
};
static struct em28xx_reg_seq kworld_ub435q_v3_digital[] = {
- {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100},
- {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xbe, 0xff, 100},
{EM2874_R80_GPIO_P0_CTRL, 0xfe, 0xff, 100},
{ -1, -1, -1, -1},
@@ -301,7 +300,6 @@ static struct em28xx_reg_seq dikom_dk300_digital[] = {
{ -1, -1, -1, -1},
};
-
/* Reset for the most [digital] boards */
static struct em28xx_reg_seq leadership_digital[] = {
{EM2874_R80_GPIO_P0_CTRL, 0x70, 0xff, 10},
@@ -479,6 +477,20 @@ static struct em28xx_reg_seq pctv_292e[] = {
{-1, -1, -1, -1},
};
+static struct em28xx_reg_seq terratec_t2_stick_hd[] = {
+ {EM2874_R80_GPIO_P0_CTRL, 0xff, 0xff, 0},
+ {0x0d, 0xff, 0xff, 600},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 10},
+ {EM2874_R80_GPIO_P0_CTRL, 0xbc, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0x00, 0xff, 300},
+ {EM2874_R80_GPIO_P0_CTRL, 0xf8, 0xff, 100},
+ {EM2874_R80_GPIO_P0_CTRL, 0xfc, 0xff, 300},
+ {0x0d, 0x42, 0xff, 1000},
+ {EM2874_R5F_TS_ENABLE, 0x85, 0xff, 0},
+ {-1, -1, -1, -1},
+};
+
/*
* Button definitions
*/
@@ -548,7 +560,6 @@ static struct em28xx_led pctv_80e_leds[] = {
{-1, 0, 0, 0},
};
-
/*
* Board definitions
*/
@@ -1514,7 +1525,7 @@ struct em28xx_board em28xx_boards[] = {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
- .aout = EM28XX_AOUT_MONO | /* I2S */
+ .aout = EM28XX_AOUT_MONO | /* I2S */
EM28XX_AOUT_MASTER, /* Line out pin */
}, {
.type = EM28XX_VMUX_COMPOSITE1,
@@ -1536,7 +1547,7 @@ struct em28xx_board em28xx_boards[] = {
.type = EM28XX_VMUX_TELEVISION,
.vmux = SAA7115_COMPOSITE2,
.amux = EM28XX_AMUX_VIDEO,
- .aout = EM28XX_AOUT_MONO | /* I2S */
+ .aout = EM28XX_AOUT_MONO | /* I2S */
EM28XX_AOUT_MASTER, /* Line out pin */
}, {
.type = EM28XX_VMUX_COMPOSITE1,
@@ -2243,6 +2254,31 @@ struct em28xx_board em28xx_boards[] = {
.has_dvb = 1,
.ir_codes = RC_MAP_PINNACLE_PCTV_HD,
},
+ [EM2861_BOARD_LEADTEK_VC100] = {
+ .name = "Leadtek VC100",
+ .tuner_type = TUNER_ABSENT, /* Capture only device */
+ .decoder = EM28XX_TVP5150,
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = TVP5150_COMPOSITE1,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = TVP5150_SVIDEO,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
+ /* eb1a:8179 Terratec Cinergy T2 Stick HD.
+ * Empia EM28178, Silicon Labs Si2168, Silicon Labs Si2146 */
+ [EM28178_BOARD_TERRATEC_T2_STICK_HD] = {
+ .name = "Terratec Cinergy T2 Stick HD",
+ .def_i2c_bus = 1,
+ .i2c_speed = EM28XX_I2C_CLK_WAIT_ENABLE | EM28XX_I2C_FREQ_400_KHZ,
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = terratec_t2_stick_hd,
+ .has_dvb = 1,
+ .ir_codes = RC_MAP_TERRATEC_SLIM_2,
+ },
};
EXPORT_SYMBOL_GPL(em28xx_boards);
@@ -2424,6 +2460,10 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM28178_BOARD_PCTV_461E },
{ USB_DEVICE(0x2013, 0x025f),
.driver_info = EM28178_BOARD_PCTV_292E },
+ { USB_DEVICE(0x0413, 0x6f07),
+ .driver_info = EM2861_BOARD_LEADTEK_VC100 },
+ { USB_DEVICE(0xeb1a, 0x8179),
+ .driver_info = EM28178_BOARD_TERRATEC_T2_STICK_HD },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -2453,6 +2493,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
{0x6b800080, EM2874_BOARD_LEADERSHIP_ISDBT, TUNER_ABSENT},
};
+
/* NOTE: introduce a separate hash table for devices with 16 bit eeproms */
int em28xx_tuner_callback(void *ptr, int component, int command, int arg)
@@ -2695,7 +2736,7 @@ static int em28xx_hint_board(struct em28xx *dev)
" insmod option:\n");
for (i = 0; i < em28xx_bcount; i++) {
em28xx_errdev(" card=%d -> %s\n",
- i, em28xx_boards[i].name);
+ i, em28xx_boards[i].name);
}
return -1;
}
@@ -3051,6 +3092,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (le16_to_cpu(dev->udev->descriptor.idVendor)
== 0xeb1a) {
__le16 idProd = dev->udev->descriptor.idProduct;
+
if (le16_to_cpu(idProd) == 0x2710)
chip_name = "em2710";
else if (le16_to_cpu(idProd) == 0x2820)
@@ -3139,7 +3181,7 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
retval = em28xx_i2c_register(dev, 0, EM28XX_I2C_ALGO_EM28XX);
if (retval < 0) {
em28xx_errdev("%s: em28xx_i2c_register bus 0 - error [%d]!\n",
- __func__, retval);
+ __func__, retval);
return retval;
}
@@ -3147,13 +3189,13 @@ static int em28xx_init_dev(struct em28xx *dev, struct usb_device *udev,
if (dev->def_i2c_bus) {
if (dev->is_em25xx)
retval = em28xx_i2c_register(dev, 1,
- EM28XX_I2C_ALGO_EM25XX_BUS_B);
+ EM28XX_I2C_ALGO_EM25XX_BUS_B);
else
retval = em28xx_i2c_register(dev, 1,
- EM28XX_I2C_ALGO_EM28XX);
+ EM28XX_I2C_ALGO_EM28XX);
if (retval < 0) {
em28xx_errdev("%s: em28xx_i2c_register bus 1 - error [%d]!\n",
- __func__, retval);
+ __func__, retval);
em28xx_i2c_unregister(dev, 0);
@@ -3193,7 +3235,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if (nr >= EM28XX_MAXBOARDS) {
/* No free device slots */
printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
- EM28XX_MAXBOARDS);
+ EM28XX_MAXBOARDS);
retval = -ENOMEM;
goto err_no_slot;
}
@@ -3377,6 +3419,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* Checks if audio is provided by a USB Audio Class interface */
for (i = 0; i < udev->config->desc.bNumInterfaces; i++) {
struct usb_interface *uif = udev->config->interface[i];
+
if (uif->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
if (has_vendor_audio)
em28xx_err("em28xx: device seems to have vendor AND usb audio class interfaces !\n"
@@ -3487,7 +3530,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
}
static int em28xx_usb_suspend(struct usb_interface *interface,
- pm_message_t message)
+ pm_message_t message)
{
struct em28xx *dev;
diff --git a/drivers/media/usb/em28xx/em28xx-core.c b/drivers/media/usb/em28xx/em28xx-core.c
index 901cf2b..86461a7 100644
--- a/drivers/media/usb/em28xx/em28xx-core.c
+++ b/drivers/media/usb/em28xx/em28xx-core.c
@@ -75,7 +75,7 @@ MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
* reads data from the usb device specifying bRequest
*/
int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
- char *buf, int len)
+ char *buf, int len)
{
int ret;
int pipe = usb_rcvctrlpipe(dev->udev, 0);
@@ -151,7 +151,7 @@ EXPORT_SYMBOL_GPL(em28xx_read_reg);
* sends data to the usb device, specifying bRequest
*/
int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
- int len)
+ int len)
{
int ret;
int pipe = usb_sndctrlpipe(dev->udev, 0);
@@ -213,7 +213,7 @@ EXPORT_SYMBOL_GPL(em28xx_write_reg);
* the actual value
*/
int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
- u8 bitmask)
+ u8 bitmask)
{
int oldval;
u8 newval;
@@ -222,7 +222,7 @@ int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
if (oldval < 0)
return oldval;
- newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+ newval = (((u8)oldval) & ~bitmask) | (val & bitmask);
return em28xx_write_regs(dev, reg, &newval, 1);
}
@@ -314,7 +314,7 @@ int em28xx_write_ac97(struct em28xx *dev, u8 reg, u16 val)
if (ret < 0)
return ret;
- ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *) &value, 2);
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, (u8 *)&value, 2);
if (ret < 0)
return ret;
@@ -361,7 +361,7 @@ static int set_ac97_input(struct em28xx *dev)
if (ret < 0)
em28xx_warn("couldn't setup AC97 register %d\n",
- inputs[i].reg);
+ inputs[i].reg);
}
return 0;
}
@@ -445,7 +445,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
ret = em28xx_write_ac97(dev, outputs[i].reg, 0x8000);
if (ret < 0)
em28xx_warn("couldn't setup AC97 register %d\n",
- outputs[i].reg);
+ outputs[i].reg);
}
}
@@ -483,7 +483,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
vol);
if (ret < 0)
em28xx_warn("couldn't setup AC97 register %d\n",
- outputs[i].reg);
+ outputs[i].reg);
}
if (dev->ctl_aoutput & EM28XX_AOUT_PCM_IN) {
@@ -531,7 +531,7 @@ int em28xx_audio_setup(struct em28xx *dev)
} else if ((cfg & EM28XX_CHIPCFG_AUDIOMASK) != EM28XX_CHIPCFG_AC97) {
dev->int_audio_type = EM28XX_INT_AUDIO_I2S;
if (dev->chip_id < CHIP_ID_EM2860 &&
- (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
+ (cfg & EM28XX_CHIPCFG_AUDIOMASK) ==
EM2820_CHIPCFG_I2S_1_SAMPRATE)
i2s_samplerates = 1;
else if (dev->chip_id >= CHIP_ID_EM2860 &&
@@ -541,7 +541,7 @@ int em28xx_audio_setup(struct em28xx *dev)
else
i2s_samplerates = 3;
em28xx_info("I2S Audio (%d sample rate(s))\n",
- i2s_samplerates);
+ i2s_samplerates);
/* Skip the code that does AC97 vendor detection */
dev->audio_mode.ac97 = EM28XX_NO_AC97;
goto init_audio;
@@ -614,8 +614,9 @@ const struct em28xx_led *em28xx_find_led(struct em28xx *dev,
{
if (dev->board.leds) {
u8 k = 0;
+
while (dev->board.leds[k].role >= 0 &&
- dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) {
+ dev->board.leds[k].role < EM28XX_NUM_LED_ROLES) {
if (dev->board.leds[k].role == role)
return &dev->board.leds[k];
k++;
@@ -658,10 +659,12 @@ int em28xx_capture_start(struct em28xx *dev, int start)
if (dev->mode == EM28XX_ANALOG_MODE)
rc = em28xx_write_reg(dev,
- EM28XX_R12_VINENABLE, 0x67);
+ EM28XX_R12_VINENABLE,
+ 0x67);
else
rc = em28xx_write_reg(dev,
- EM28XX_R12_VINENABLE, 0x37);
+ EM28XX_R12_VINENABLE,
+ 0x37);
if (rc < 0)
return rc;
@@ -815,9 +818,9 @@ void em28xx_uninit_usb_xfer(struct em28xx *dev, enum em28xx_mode mode)
if (usb_bufs->transfer_buffer[i]) {
usb_free_coherent(dev->udev,
- urb->transfer_buffer_length,
- usb_bufs->transfer_buffer[i],
- urb->transfer_dma);
+ urb->transfer_buffer_length,
+ usb_bufs->transfer_buffer[i],
+ urb->transfer_dma);
}
usb_free_urb(urb);
usb_bufs->urb[i] = NULL;
@@ -889,7 +892,7 @@ int em28xx_alloc_urbs(struct em28xx *dev, enum em28xx_mode mode, int xfer_bulk,
if ((xfer_bulk && !dev->analog_ep_bulk) ||
(!xfer_bulk && !dev->analog_ep_isoc)) {
em28xx_errdev("no endpoint for analog mode and transfer type %d\n",
- xfer_bulk > 0);
+ xfer_bulk > 0);
return -EINVAL;
}
usb_bufs = &dev->usb_ctl.analog_bufs;
@@ -988,9 +991,9 @@ EXPORT_SYMBOL_GPL(em28xx_alloc_urbs);
* Allocate URBs and start IRQ
*/
int em28xx_init_usb_xfer(struct em28xx *dev, enum em28xx_mode mode,
- int xfer_bulk, int num_bufs, int max_pkt_size,
+ int xfer_bulk, int num_bufs, int max_pkt_size,
int packet_multiplier,
- int (*urb_data_copy) (struct em28xx *dev, struct urb *urb))
+ int (*urb_data_copy)(struct em28xx *dev, struct urb *urb))
{
struct em28xx_dmaqueue *dma_q = &dev->vidq;
struct em28xx_dmaqueue *vbi_dma_q = &dev->vbiq;
diff --git a/drivers/media/usb/em28xx/em28xx-dvb.c b/drivers/media/usb/em28xx/em28xx-dvb.c
index 9682c52..9877b69 100644
--- a/drivers/media/usb/em28xx/em28xx-dvb.c
+++ b/drivers/media/usb/em28xx/em28xx-dvb.c
@@ -63,7 +63,6 @@ MODULE_LICENSE("GPL");
MODULE_DESCRIPTION(DRIVER_DESC " - digital TV interface");
MODULE_VERSION(EM28XX_VERSION);
-
static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
@@ -71,7 +70,7 @@ MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define dprintk(level, fmt, arg...) do { \
-if (debug >= level) \
+if (debug >= level) \
printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
} while (0)
@@ -99,9 +98,8 @@ struct em28xx_dvb {
struct i2c_client *i2c_client_tuner;
};
-
static inline void print_err_status(struct em28xx *dev,
- int packet, int status)
+ int packet, int status)
{
char *errmsg = "Unknown";
@@ -169,7 +167,7 @@ static inline int em28xx_dvb_urb_data_copy(struct em28xx *dev, struct urb *urb)
if (!urb->actual_length)
continue;
dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer,
- urb->actual_length);
+ urb->actual_length);
} else {
if (urb->iso_frame_desc[i].status < 0) {
print_err_status(dev, i,
@@ -280,7 +278,6 @@ static int em28xx_stop_feed(struct dvb_demux_feed *feed)
}
-
/* ------------------------------------------------------------------ */
static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
{
@@ -740,7 +737,7 @@ static int em28xx_pctv_290e_set_lna(struct dvb_frontend *fe)
return ret;
#else
dev_warn(&dev->udev->dev, "%s: LNA control is disabled (lna=%u)\n",
- KBUILD_MODNAME, c->lna);
+ KBUILD_MODNAME, c->lna);
return 0;
#endif
}
@@ -830,6 +827,7 @@ static struct zl10353_config em28xx_zl10353_no_i2c_gate_dev = {
.no_tuner = 1,
.parallel_ts = 1,
};
+
static struct qt1010_config em28xx_qt1010_config = {
.i2c_address = 0x62
};
@@ -861,7 +859,6 @@ static const struct m88ds3103_config pctv_461e_m88ds3103_config = {
.agc = 0x99,
};
-
static struct tda18271_std_map drx_j_std_map = {
.atsc_6 = { .if_freq = 5000, .agc_mode = 3, .std = 0, .if_lvl = 1,
.rfagc_top = 0x37, },
@@ -948,7 +945,7 @@ static int em28xx_register_dvb(struct em28xx_dvb *dvb, struct module *module,
result = dvb_register_frontend(&dvb->adapter, dvb->fe[1]);
if (result < 0) {
printk(KERN_WARNING "%s: 2nd dvb_register_frontend failed (errno = %d)\n",
- dev->name, result);
+ dev->name, result);
goto fail_frontend1;
}
}
@@ -1047,7 +1044,7 @@ static void em28xx_unregister_dvb(struct em28xx_dvb *dvb)
static int em28xx_dvb_init(struct em28xx *dev)
{
- int result = 0, mfe_shared = 0;
+ int result = 0;
struct em28xx_dvb *dvb;
if (dev->is_audio_only) {
@@ -1182,7 +1179,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
&dev->i2c_adap[dev->def_i2c_bus]);
if (dvb->fe[0] != NULL) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
- &dev->i2c_adap[dev->def_i2c_bus], 0x61, TUNER_THOMSON_DTT761X)) {
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x61, TUNER_THOMSON_DTT761X)) {
result = -EINVAL;
goto out_free;
}
@@ -1204,7 +1202,8 @@ static int em28xx_dvb_init(struct em28xx *dev)
&dev->i2c_adap[dev->def_i2c_bus], 0x48);
if (dvb->fe[0]) {
if (!dvb_attach(simple_tuner_attach, dvb->fe[0],
- &dev->i2c_adap[dev->def_i2c_bus], 0x60, TUNER_PHILIPS_CU1216L)) {
+ &dev->i2c_adap[dev->def_i2c_bus],
+ 0x60, TUNER_PHILIPS_CU1216L)) {
result = -EINVAL;
goto out_free;
}
@@ -1219,7 +1218,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
goto out_free;
}
if (!dvb_attach(tda18271_attach, dvb->fe[0], 0x60,
- &dev->i2c_adap[dev->def_i2c_bus],
+ &dev->i2c_adap[dev->def_i2c_bus],
&kworld_a340_config)) {
dvb_frontend_detach(dvb->fe[0]);
result = -EINVAL;
@@ -1250,10 +1249,10 @@ static int em28xx_dvb_init(struct em28xx *dev)
#ifdef CONFIG_GPIOLIB
/* enable LNA for DVB-T, DVB-T2 and DVB-C */
result = gpio_request_one(dvb->lna_gpio,
- GPIOF_OUT_INIT_LOW, NULL);
+ GPIOF_OUT_INIT_LOW, NULL);
if (result)
em28xx_errdev("gpio request failed %d\n",
- result);
+ result);
else
gpio_free(dvb->lna_gpio);
@@ -1266,6 +1265,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
case EM2884_BOARD_HAUPPAUGE_WINTV_HVR_930C:
{
struct xc5000_config cfg;
+
hauppauge_hvr930c_init(dev);
dvb->fe[0] = dvb_attach(drxk_attach,
@@ -1339,7 +1339,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
/* attach SEC */
if (dvb->fe[0])
dvb_attach(a8293_attach, dvb->fe[0], &dev->i2c_adap[dev->def_i2c_bus],
- &em28xx_a8293_config);
+ &em28xx_a8293_config);
break;
case EM2874_BOARD_DELOCK_61959:
case EM2874_BOARD_MAXMEDIA_UB425_TC:
@@ -1553,6 +1553,7 @@ static int em28xx_dvb_init(struct em28xx *dev)
struct si2157_config si2157_config;
/* attach demod */
+ memset(&si2168_config, 0, sizeof(si2168_config));
si2168_config.i2c_adapter = &adapter;
si2168_config.fe = &dvb->fe[0];
si2168_config.ts_mode = SI2168_TS_PARALLEL;
@@ -1603,6 +1604,65 @@ static int em28xx_dvb_init(struct em28xx *dev)
dvb->fe[0]->ops.set_lna = em28xx_pctv_292e_set_lna;
}
break;
+ case EM28178_BOARD_TERRATEC_T2_STICK_HD:
+ {
+ struct i2c_adapter *adapter;
+ struct i2c_client *client;
+ struct i2c_board_info info;
+ struct si2168_config si2168_config;
+ struct si2157_config si2157_config;
+
+ /* attach demod */
+ memset(&si2168_config, 0, sizeof(si2168_config));
+ si2168_config.i2c_adapter = &adapter;
+ si2168_config.fe = &dvb->fe[0];
+ si2168_config.ts_mode = SI2168_TS_PARALLEL;
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2168", I2C_NAME_SIZE);
+ info.addr = 0x64;
+ info.platform_data = &si2168_config;
+ request_module(info.type);
+ client = i2c_new_device(&dev->i2c_adap[dev->def_i2c_bus], &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_demod = client;
+
+ /* attach tuner */
+ memset(&si2157_config, 0, sizeof(si2157_config));
+ si2157_config.fe = dvb->fe[0];
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "si2146", I2C_NAME_SIZE);
+ info.addr = 0x60;
+ info.platform_data = &si2157_config;
+ request_module("si2157");
+ client = i2c_new_device(adapter, &info);
+ if (client == NULL || client->dev.driver == NULL) {
+ module_put(dvb->i2c_client_demod->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ if (!try_module_get(client->dev.driver->owner)) {
+ i2c_unregister_device(client);
+ module_put(dvb->i2c_client_demod->dev.driver->owner);
+ i2c_unregister_device(dvb->i2c_client_demod);
+ result = -ENODEV;
+ goto out_free;
+ }
+
+ dvb->i2c_client_tuner = client;
+ }
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
@@ -1624,9 +1684,6 @@ static int em28xx_dvb_init(struct em28xx *dev)
if (result < 0)
goto out_free;
- /* MFE lock */
- dvb->adapter.mfe_shared = mfe_shared;
-
em28xx_info("DVB extension successfully initialized\n");
kref_get(&dev->ref);
diff --git a/drivers/media/usb/em28xx/em28xx-i2c.c b/drivers/media/usb/em28xx/em28xx-i2c.c
index 1048c1a..a19b5c8 100644
--- a/drivers/media/usb/em28xx/em28xx-i2c.c
+++ b/drivers/media/usb/em28xx/em28xx-i2c.c
@@ -593,6 +593,7 @@ static inline unsigned long em28xx_hash_mem(char *buf, int length, int bits)
unsigned long l = 0;
int len = 0;
unsigned char c;
+
do {
if (len == length) {
c = (char)len;
@@ -877,6 +878,7 @@ static struct i2c_client em28xx_client_template = {
* incomplete list of known devices
*/
static char *i2c_devs[128] = {
+ [0x1c >> 1] = "lgdt330x",
[0x3e >> 1] = "remote IR sensor",
[0x4a >> 1] = "saa7113h",
[0x52 >> 1] = "drxk",
@@ -949,7 +951,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
retval = i2c_add_adapter(&dev->i2c_adap[bus]);
if (retval < 0) {
em28xx_errdev("%s: i2c_add_adapter failed! retval [%d]\n",
- __func__, retval);
+ __func__, retval);
return retval;
}
@@ -961,7 +963,7 @@ int em28xx_i2c_register(struct em28xx *dev, unsigned bus,
retval = em28xx_i2c_eeprom(dev, bus, &dev->eedata, &dev->eedata_len);
if ((retval < 0) && (retval != -ENODEV)) {
em28xx_errdev("%s: em28xx_i2_eeprom failed! retval [%d]\n",
- __func__, retval);
+ __func__, retval);
return retval;
}
diff --git a/drivers/media/usb/em28xx/em28xx-input.c b/drivers/media/usb/em28xx/em28xx-input.c
index 23f8f6a..d8dc03a 100644
--- a/drivers/media/usb/em28xx/em28xx-input.c
+++ b/drivers/media/usb/em28xx/em28xx-input.c
@@ -459,7 +459,7 @@ static int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 *rc_type)
return em2874_ir_change_protocol(rc_dev, rc_type);
default:
printk("Unrecognized em28xx chip id 0x%02x: IR not supported\n",
- dev->chip_id);
+ dev->chip_id);
return -EINVAL;
}
}
@@ -505,7 +505,7 @@ static void em28xx_query_buttons(struct work_struct *work)
/* Check states of the buttons and act */
j = 0;
while (dev->board.buttons[j].role >= 0 &&
- dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
+ dev->board.buttons[j].role < EM28XX_NUM_BUTTON_ROLES) {
struct em28xx_button *button = &dev->board.buttons[j];
/* Check if button uses the current address */
if (button->reg_r != dev->button_polling_addresses[i]) {
@@ -607,7 +607,7 @@ static void em28xx_init_buttons(struct em28xx *dev)
dev->button_polling_interval = EM28XX_BUTTONS_DEBOUNCED_QUERY_INTERVAL;
while (dev->board.buttons[i].role >= 0 &&
- dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
+ dev->board.buttons[i].role < EM28XX_NUM_BUTTON_ROLES) {
struct em28xx_button *button = &dev->board.buttons[i];
/* Check if polling address is already on the list */
addr_new = true;
@@ -653,11 +653,11 @@ next_button:
/* Start polling */
if (dev->num_button_polling_addresses) {
memset(dev->button_polling_last_values, 0,
- EM28XX_NUM_BUTTON_ADDRESSES_MAX);
+ EM28XX_NUM_BUTTON_ADDRESSES_MAX);
INIT_DELAYED_WORK(&dev->buttons_query_work,
- em28xx_query_buttons);
+ em28xx_query_buttons);
schedule_delayed_work(&dev->buttons_query_work,
- msecs_to_jiffies(dev->button_polling_interval));
+ msecs_to_jiffies(dev->button_polling_interval));
}
}
@@ -841,8 +841,7 @@ static int em28xx_ir_fini(struct em28xx *dev)
if (!ir)
goto ref_put;
- if (ir->rc)
- rc_unregister_device(ir->rc);
+ rc_unregister_device(ir->rc);
kfree(ir->i2c_client);
@@ -887,7 +886,7 @@ static int em28xx_ir_resume(struct em28xx *dev)
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
if (dev->num_button_polling_addresses)
schedule_delayed_work(&dev->buttons_query_work,
- msecs_to_jiffies(dev->button_polling_interval));
+ msecs_to_jiffies(dev->button_polling_interval));
return 0;
}
diff --git a/drivers/media/usb/em28xx/em28xx-reg.h b/drivers/media/usb/em28xx/em28xx-reg.h
index 311fb34..13cbb7f 100644
--- a/drivers/media/usb/em28xx/em28xx-reg.h
+++ b/drivers/media/usb/em28xx/em28xx-reg.h
@@ -49,7 +49,6 @@
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_564 0x02
#define EM28XX_CHIPCFG2_TS_PACKETSIZE_752 0x03
-
/* GPIO/GPO registers */
#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
#define EM2820_R08_GPIO_CTRL 0x08 /* em2820-em2873/83 only */
@@ -68,7 +67,6 @@
#define EM28XX_I2C_FREQ_400_KHZ 0x01
#define EM28XX_I2C_FREQ_100_KHZ 0x00
-
#define EM28XX_R0A_CHIPID 0x0a
#define EM28XX_R0C_USBSUSP 0x0c
#define EM28XX_R0C_USBSUSP_SNAPSHOT 0x20 /* 1=button pressed, needs reset */
@@ -157,7 +155,6 @@
#define EM28XX_OUTFMT_YUV422_Y1UY0V 0x15
#define EM28XX_OUTFMT_YUV411 0x18
-
#define EM28XX_R28_XMIN 0x28
#define EM28XX_R29_XMAX 0x29
#define EM28XX_R2A_YMIN 0x2a
diff --git a/drivers/media/usb/em28xx/em28xx-v4l.h b/drivers/media/usb/em28xx/em28xx-v4l.h
index 432862c..8dfcb56 100644
--- a/drivers/media/usb/em28xx/em28xx-v4l.h
+++ b/drivers/media/usb/em28xx/em28xx-v4l.h
@@ -14,7 +14,6 @@
GNU General Public License for more details.
*/
-
int em28xx_start_analog_streaming(struct vb2_queue *vq, unsigned int count);
void em28xx_stop_vbi_streaming(struct vb2_queue *vq);
extern struct vb2_ops em28xx_vbi_qops;
diff --git a/drivers/media/usb/em28xx/em28xx-vbi.c b/drivers/media/usb/em28xx/em28xx-vbi.c
index 34ee1e0..744e7ed 100644
--- a/drivers/media/usb/em28xx/em28xx-vbi.c
+++ b/drivers/media/usb/em28xx/em28xx-vbi.c
@@ -92,7 +92,6 @@ vbi_buffer_queue(struct vb2_buffer *vb)
spin_unlock_irqrestore(&dev->slock, flags);
}
-
struct vb2_ops em28xx_vbi_qops = {
.queue_setup = vbi_queue_setup,
.buf_prepare = vbi_buffer_prepare,
diff --git a/drivers/media/usb/em28xx/em28xx-video.c b/drivers/media/usb/em28xx/em28xx-video.c
index 03d5ece..cf7f58b 100644
--- a/drivers/media/usb/em28xx/em28xx-video.c
+++ b/drivers/media/usb/em28xx/em28xx-video.c
@@ -81,7 +81,6 @@ MODULE_DESCRIPTION(DRIVER_DESC " - v4l2 interface");
MODULE_LICENSE("GPL");
MODULE_VERSION(EM28XX_VERSION);
-
#define EM25XX_FRMDATAHDR_BYTE1 0x02
#define EM25XX_FRMDATAHDR_BYTE2_STILL_IMAGE 0x20
#define EM25XX_FRMDATAHDR_BYTE2_FRAME_END 0x02
@@ -90,7 +89,6 @@ MODULE_VERSION(EM28XX_VERSION);
EM25XX_FRMDATAHDR_BYTE2_FRAME_END | \
EM25XX_FRMDATAHDR_BYTE2_FRAME_ID)
-
static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = -1U };
@@ -194,9 +192,10 @@ static int em28xx_vbi_supported(struct em28xx *dev)
static void em28xx_wake_i2c(struct em28xx *dev)
{
struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
+
v4l2_device_call_all(v4l2_dev, 0, core, reset, 0);
v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
- INPUT(dev->ctl_input)->vmux, 0, 0);
+ INPUT(dev->ctl_input)->vmux, 0, 0);
v4l2_device_call_all(v4l2_dev, 0, video, s_stream, 0);
}
@@ -275,7 +274,7 @@ static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
}
static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
- u16 width, u16 height)
+ u16 width, u16 height)
{
u8 cwidth = width >> 2;
u8 cheight = height >> 2;
@@ -283,7 +282,7 @@ static void em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
/* NOTE: size limit: 2047x1023 = 2MPix */
em28xx_videodbg("capture area set to (%d,%d): %dx%d\n",
- hstart, vstart,
+ hstart, vstart,
((overflow & 2) << 9 | cwidth << 2),
((overflow & 1) << 10 | cheight << 2));
@@ -406,13 +405,13 @@ set_alt:
dev->packet_multiplier = EM28XX_BULK_PACKET_MULTIPLIER;
} else { /* isoc */
em28xx_videodbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
+ min_pkt_size, dev->alt);
dev->max_pkt_size =
dev->alt_max_pkt_size_isoc[dev->alt];
dev->packet_multiplier = EM28XX_NUM_ISOC_PACKETS;
}
em28xx_videodbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
+ dev->alt, dev->max_pkt_size);
errCode = usb_set_interface(dev->udev, dev->ifnum, dev->alt);
if (errCode < 0) {
em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
@@ -482,7 +481,7 @@ static void em28xx_copy_video(struct em28xx *dev,
if ((char *)startwrite + lencopy > (char *)buf->vb_buf + buf->length) {
em28xx_isocdbg("Overflow of %zu bytes past buffer end (1)\n",
- ((char *)startwrite + lencopy) -
+ ((char *)startwrite + lencopy) -
((char *)buf->vb_buf + buf->length));
remain = (char *)buf->vb_buf + buf->length -
(char *)startwrite;
@@ -548,7 +547,7 @@ static void em28xx_copy_vbi(struct em28xx *dev,
}
static inline void print_err_status(struct em28xx *dev,
- int packet, int status)
+ int packet, int status)
{
char *errmsg = "Unknown";
@@ -831,7 +830,6 @@ static inline int em28xx_urb_data_copy(struct em28xx *dev, struct urb *urb)
return 1;
}
-
static int get_ressource(enum v4l2_buf_type f_type)
{
switch (f_type) {
@@ -1003,6 +1001,7 @@ static void em28xx_stop_streaming(struct vb2_queue *vq)
}
while (!list_empty(&vidq->active)) {
struct em28xx_buffer *buf;
+
buf = list_entry(vidq->active.next, struct em28xx_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -1033,6 +1032,7 @@ void em28xx_stop_vbi_streaming(struct vb2_queue *vq)
}
while (!list_empty(&vbiq->active)) {
struct em28xx_buffer *buf;
+
buf = list_entry(vbiq->active.next, struct em28xx_buffer, list);
list_del(&buf->list);
vb2_buffer_done(&buf->vb, VB2_BUF_STATE_ERROR);
@@ -1109,6 +1109,7 @@ static int em28xx_vb2_setup(struct em28xx *dev)
static void video_mux(struct em28xx *dev, int index)
{
struct v4l2_device *v4l2_dev = &dev->v4l2->v4l2_dev;
+
dev->ctl_input = index;
dev->ctl_ainput = INPUT(index)->amux;
dev->ctl_aoutput = INPUT(index)->aout;
@@ -1117,21 +1118,22 @@ static void video_mux(struct em28xx *dev, int index)
dev->ctl_aoutput = EM28XX_AOUT_MASTER;
v4l2_device_call_all(v4l2_dev, 0, video, s_routing,
- INPUT(index)->vmux, 0, 0);
+ INPUT(index)->vmux, 0, 0);
if (dev->board.has_msp34xx) {
if (dev->i2s_speed) {
v4l2_device_call_all(v4l2_dev, 0, audio,
- s_i2s_clock_freq, dev->i2s_speed);
+ s_i2s_clock_freq, dev->i2s_speed);
}
/* Note: this is msp3400 specific */
v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
- dev->ctl_ainput, MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
+ dev->ctl_ainput,
+ MSP_OUTPUT(MSP_SC_IN_DSP_SCART1), 0);
}
if (dev->board.adecoder != EM28XX_NOADECODER) {
v4l2_device_call_all(v4l2_dev, 0, audio, s_routing,
- dev->ctl_ainput, dev->ctl_aoutput, 0);
+ dev->ctl_ainput, dev->ctl_aoutput, 0);
}
em28xx_audio_analog_set(dev);
@@ -1203,7 +1205,7 @@ static const struct v4l2_ctrl_ops em28xx_ctrl_ops = {
};
static void size_to_scale(struct em28xx *dev,
- unsigned int width, unsigned int height,
+ unsigned int width, unsigned int height,
unsigned int *hscale, unsigned int *vscale)
{
unsigned int maxw = norm_maxw(dev);
@@ -1234,7 +1236,7 @@ static void scale_to_size(struct em28xx *dev,
------------------------------------------------------------------*/
static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
@@ -1267,7 +1269,7 @@ static struct em28xx_fmt *format_by_fourcc(unsigned int fourcc)
}
static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
@@ -1338,7 +1340,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
/* set new image size */
size_to_scale(dev, v4l2->width, v4l2->height,
- &v4l2->hscale, &v4l2->vscale);
+ &v4l2->hscale, &v4l2->vscale);
em28xx_resolution_set(dev);
@@ -1346,7 +1348,7 @@ static int em28xx_set_video_format(struct em28xx *dev, unsigned int fourcc,
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_format *f)
+ struct v4l2_format *f)
{
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
@@ -1401,7 +1403,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id norm)
v4l2->width = f.fmt.pix.width;
v4l2->height = f.fmt.pix.height;
size_to_scale(dev, v4l2->width, v4l2->height,
- &v4l2->hscale, &v4l2->vscale);
+ &v4l2->hscale, &v4l2->vscale);
em28xx_resolution_set(dev);
v4l2_device_call_all(&v4l2->v4l2_dev, 0, video, s_std, v4l2->norm);
@@ -1422,7 +1424,7 @@ static int vidioc_g_parm(struct file *file, void *priv,
video, g_parm, p);
else
v4l2_video_std_frame_period(v4l2->norm,
- &p->parm.capture.timeperframe);
+ &p->parm.capture.timeperframe);
return rc;
}
@@ -1450,7 +1452,7 @@ static const char *iname[] = {
};
static int vidioc_enum_input(struct file *file, void *priv,
- struct v4l2_input *i)
+ struct v4l2_input *i)
{
struct em28xx *dev = video_drvdata(file);
unsigned int n;
@@ -1467,7 +1469,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
strcpy(i->name, iname[INPUT(n)->type]);
if ((EM28XX_VMUX_TELEVISION == INPUT(n)->type) ||
- (EM28XX_VMUX_CABLE == INPUT(n)->type))
+ (EM28XX_VMUX_CABLE == INPUT(n)->type))
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = dev->v4l2->vdev->tvnorms;
@@ -1558,7 +1560,7 @@ static int vidioc_s_audio(struct file *file, void *priv, const struct v4l2_audio
}
static int vidioc_g_tuner(struct file *file, void *priv,
- struct v4l2_tuner *t)
+ struct v4l2_tuner *t)
{
struct em28xx *dev = video_drvdata(file);
@@ -1572,7 +1574,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
}
static int vidioc_s_tuner(struct file *file, void *priv,
- const struct v4l2_tuner *t)
+ const struct v4l2_tuner *t)
{
struct em28xx *dev = video_drvdata(file);
@@ -1584,7 +1586,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
}
static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
+ struct v4l2_frequency *f)
{
struct em28xx *dev = video_drvdata(file);
struct em28xx_v4l2 *v4l2 = dev->v4l2;
@@ -1597,7 +1599,7 @@ static int vidioc_g_frequency(struct file *file, void *priv,
}
static int vidioc_s_frequency(struct file *file, void *priv,
- const struct v4l2_frequency *f)
+ const struct v4l2_frequency *f)
{
struct v4l2_frequency new_freq = *f;
struct em28xx *dev = video_drvdata(file);
@@ -1615,7 +1617,7 @@ static int vidioc_s_frequency(struct file *file, void *priv,
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int vidioc_g_chip_info(struct file *file, void *priv,
- struct v4l2_dbg_chip_info *chip)
+ struct v4l2_dbg_chip_info *chip)
{
struct em28xx *dev = video_drvdata(file);
@@ -1670,6 +1672,7 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
__le16 val = 0;
+
ret = dev->em28xx_read_reg_req_len(dev, USB_REQ_GET_STATUS,
reg->reg, (char *)&val, 2);
if (ret < 0)
@@ -1700,9 +1703,8 @@ static int vidioc_s_register(struct file *file, void *priv,
}
#endif
-
static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *cap)
+ struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
struct em28xx *dev = video_drvdata(file);
@@ -1736,7 +1738,7 @@ static int vidioc_querycap(struct file *file, void *priv,
}
static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
- struct v4l2_fmtdesc *f)
+ struct v4l2_fmtdesc *f)
{
if (unlikely(f->index >= ARRAY_SIZE(format)))
return -EINVAL;
@@ -2177,9 +2179,10 @@ static unsigned short msp3400_addrs[] = {
/******************************** usb interface ******************************/
-static struct video_device *em28xx_vdev_init(struct em28xx *dev,
- const struct video_device *template,
- const char *type_name)
+static struct video_device
+*em28xx_vdev_init(struct em28xx *dev,
+ const struct video_device *template,
+ const char *type_name)
{
struct video_device *vfd;
@@ -2344,21 +2347,24 @@ static int em28xx_v4l2_init(struct em28xx *dev)
if (dev->board.radio.type)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus],
- "tuner", dev->board.radio_addr, NULL);
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", dev->board.radio_addr,
+ NULL);
if (has_demod)
v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus], "tuner",
- 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", 0,
+ v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&v4l2->v4l2_dev,
- &dev->i2c_adap[dev->def_i2c_bus], "tuner",
- 0, v4l2_i2c_tuner_addrs(type));
+ &dev->i2c_adap[dev->def_i2c_bus],
+ "tuner", 0,
+ v4l2_i2c_tuner_addrs(type));
if (sd)
tuner_addr = v4l2_i2c_subdev_addr(sd);
@@ -2378,20 +2384,20 @@ static int em28xx_v4l2_init(struct em28xx *dev)
ret = em28xx_audio_setup(dev);
if (ret < 0) {
em28xx_errdev("%s: Error while setting audio - error [%d]!\n",
- __func__, ret);
+ __func__, ret);
goto unregister_dev;
}
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
- V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
v4l2_ctrl_new_std(hdl, &em28xx_ctrl_ops,
- V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
+ V4L2_CID_AUDIO_VOLUME, 0, 0x1f, 1, 0x1f);
} else {
/* install the em28xx notify callback */
v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_MUTE),
- em28xx_ctrl_notify, dev);
+ em28xx_ctrl_notify, dev);
v4l2_ctrl_notify(v4l2_ctrl_find(hdl, V4L2_CID_AUDIO_VOLUME),
- em28xx_ctrl_notify, dev);
+ em28xx_ctrl_notify, dev);
}
/* wake i2c devices */
@@ -2518,7 +2524,7 @@ static int em28xx_v4l2_init(struct em28xx *dev)
/* register v4l2 video video_device */
ret = video_register_device(v4l2->vdev, VFL_TYPE_GRABBER,
- video_nr[dev->devno]);
+ video_nr[dev->devno]);
if (ret) {
em28xx_errdev("unable to register video device (error=%i).\n",
ret);
diff --git a/drivers/media/usb/em28xx/em28xx.h b/drivers/media/usb/em28xx/em28xx.h
index a21a746..9c70753 100644
--- a/drivers/media/usb/em28xx/em28xx.h
+++ b/drivers/media/usb/em28xx/em28xx.h
@@ -141,6 +141,8 @@
#define EM28178_BOARD_PCTV_461E 92
#define EM2874_BOARD_KWORLD_UB435Q_V3 93
#define EM28178_BOARD_PCTV_292E 94
+#define EM2861_BOARD_LEADTEK_VC100 95
+#define EM28178_BOARD_TERRATEC_T2_STICK_HD 96
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -215,7 +217,6 @@ enum em28xx_mode {
EM28XX_DIGITAL_MODE,
};
-
struct em28xx;
struct em28xx_usb_bufs {
@@ -243,11 +244,11 @@ struct em28xx_usb_ctl {
struct em28xx_usb_bufs digital_bufs;
/* Stores already requested buffers */
- struct em28xx_buffer *vid_buf;
- struct em28xx_buffer *vbi_buf;
+ struct em28xx_buffer *vid_buf;
+ struct em28xx_buffer *vbi_buf;
/* copy data from URB */
- int (*urb_data_copy) (struct em28xx *dev, struct urb *urb);
+ int (*urb_data_copy)(struct em28xx *dev, struct urb *urb);
};
@@ -695,14 +696,14 @@ struct em28xx {
char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
/* helper funcs that call usb_control_msg */
- int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
- char *buf, int len);
- int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
- int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
- char *buf, int len);
- int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
- char *buf, int len);
- int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
+ int (*em28xx_write_regs)(struct em28xx *dev, u16 reg,
+ char *buf, int len);
+ int (*em28xx_read_reg)(struct em28xx *dev, u16 reg);
+ int (*em28xx_read_reg_req_len)(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_write_regs_req)(struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_read_reg_req)(struct em28xx *dev, u8 req, u16 reg);
enum em28xx_mode mode;
@@ -745,7 +746,7 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len);
int em28xx_write_reg(struct em28xx *dev, u16 reg, u8 val);
int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
- u8 bitmask);
+ u8 bitmask);
int em28xx_toggle_reg_bits(struct em28xx *dev, u16 reg, u8 bitmask);
int em28xx_read_ac97(struct em28xx *dev, u8 reg);
diff --git a/drivers/media/usb/go7007/go7007-v4l2.c b/drivers/media/usb/go7007/go7007-v4l2.c
index ec799b4..d6bf982 100644
--- a/drivers/media/usb/go7007/go7007-v4l2.c
+++ b/drivers/media/usb/go7007/go7007-v4l2.c
@@ -252,7 +252,7 @@ static int set_capture_size(struct go7007 *go, struct v4l2_format *fmt, int try)
if (go->board_info->sensor_flags & GO7007_SENSOR_SCALING) {
struct v4l2_mbus_framefmt mbus_fmt;
- mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ mbus_fmt.code = MEDIA_BUS_FMT_FIXED;
mbus_fmt.width = fmt ? fmt->fmt.pix.width : width;
mbus_fmt.height = height;
go->encoder_h_halve = 0;
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-context.c b/drivers/media/usb/pvrusb2/pvrusb2-context.c
index 7c19ff7..c8761c7 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-context.c
@@ -80,7 +80,7 @@ static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
static void pvr2_context_destroy(struct pvr2_context *mp)
{
pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
- if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
+ pvr2_hdw_destroy(mp->hdw);
pvr2_context_set_notify(mp, 0);
mutex_lock(&pvr2_context_mutex);
if (mp->exist_next) {
diff --git a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
index 9623b62..2fd9b5e 100644
--- a/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/usb/pvrusb2/pvrusb2-hdw.c
@@ -2966,7 +2966,7 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
memset(&fmt, 0, sizeof(fmt));
fmt.width = hdw->res_hor_val;
fmt.height = hdw->res_ver_val;
- fmt.code = V4L2_MBUS_FMT_FIXED;
+ fmt.code = MEDIA_BUS_FMT_FIXED;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
fmt.width, fmt.height);
v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt);
diff --git a/drivers/media/usb/s2255/s2255drv.c b/drivers/media/usb/s2255/s2255drv.c
index ccc0009..de55e96 100644
--- a/drivers/media/usb/s2255/s2255drv.c
+++ b/drivers/media/usb/s2255/s2255drv.c
@@ -558,27 +558,30 @@ static void s2255_fwchunk_complete(struct urb *urb)
}
-static int s2255_got_frame(struct s2255_vc *vc, int jpgsize)
+static void s2255_got_frame(struct s2255_vc *vc, int jpgsize)
{
struct s2255_buffer *buf;
struct s2255_dev *dev = to_s2255_dev(vc->vdev.v4l2_dev);
unsigned long flags = 0;
- int rc = 0;
+
spin_lock_irqsave(&vc->qlock, flags);
if (list_empty(&vc->buf_list)) {
dprintk(dev, 1, "No active queue to serve\n");
- rc = -1;
- goto unlock;
+ spin_unlock_irqrestore(&vc->qlock, flags);
+ return;
}
buf = list_entry(vc->buf_list.next,
struct s2255_buffer, list);
list_del(&buf->list);
v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
+ buf->vb.v4l2_buf.field = vc->field;
+ buf->vb.v4l2_buf.sequence = vc->frame_count;
+ spin_unlock_irqrestore(&vc->qlock, flags);
+
s2255_fillbuff(vc, buf, jpgsize);
+ /* tell v4l buffer was filled */
+ vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
dprintk(dev, 2, "%s: [buf] [%p]\n", __func__, buf);
-unlock:
- spin_unlock_irqrestore(&vc->qlock, flags);
- return rc;
}
static const struct s2255_fmt *format_by_fourcc(int fourcc)
@@ -632,7 +635,7 @@ static void s2255_fillbuff(struct s2255_vc *vc,
break;
case V4L2_PIX_FMT_JPEG:
case V4L2_PIX_FMT_MJPEG:
- buf->vb.v4l2_buf.length = jpgsize;
+ vb2_set_plane_payload(&buf->vb, 0, jpgsize);
memcpy(vbuf, tmpbuf, jpgsize);
break;
case V4L2_PIX_FMT_YUV422P:
@@ -649,11 +652,6 @@ static void s2255_fillbuff(struct s2255_vc *vc,
}
dprintk(dev, 2, "s2255fill at : Buffer 0x%08lx size= %d\n",
(unsigned long)vbuf, pos);
- /* tell v4l buffer was filled */
- buf->vb.v4l2_buf.field = vc->field;
- buf->vb.v4l2_buf.sequence = vc->frame_count;
- v4l2_get_timestamp(&buf->vb.v4l2_buf.timestamp);
- vb2_buffer_done(&buf->vb, VB2_BUF_STATE_DONE);
}
@@ -1976,8 +1974,7 @@ static int s2255_release_sys_buffers(struct s2255_vc *vc)
{
unsigned long i;
for (i = 0; i < SYS_FRAMES; i++) {
- if (vc->buffer.frame[i].lpvbits)
- vfree(vc->buffer.frame[i].lpvbits);
+ vfree(vc->buffer.frame[i].lpvbits);
vc->buffer.frame[i].lpvbits = NULL;
}
return 0;
diff --git a/drivers/media/usb/stk1160/stk1160-v4l.c b/drivers/media/usb/stk1160/stk1160-v4l.c
index 2330543..a4762910 100644
--- a/drivers/media/usb/stk1160/stk1160-v4l.c
+++ b/drivers/media/usb/stk1160/stk1160-v4l.c
@@ -475,7 +475,7 @@ static int vidioc_s_register(struct file *file, void *priv,
struct stk1160 *dev = video_drvdata(file);
/* Match host */
- return stk1160_write_reg(dev, reg->reg, cpu_to_le16(reg->val));
+ return stk1160_write_reg(dev, reg->reg, reg->val);
}
#endif
diff --git a/drivers/media/usb/usbvision/usbvision-video.c b/drivers/media/usb/usbvision/usbvision-video.c
index 9bfa041..693d5f4 100644
--- a/drivers/media/usb/usbvision/usbvision-video.c
+++ b/drivers/media/usb/usbvision/usbvision-video.c
@@ -509,11 +509,12 @@ static int vidioc_querycap(struct file *file, void *priv,
usbvision_device_data[usbvision->dev_model].model_string,
sizeof(vc->card));
usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
- vc->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ vc->device_caps = V4L2_CAP_VIDEO_CAPTURE |
V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
(usbvision->have_tuner ? V4L2_CAP_TUNER : 0);
+ vc->capabilities = vc->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/media/usb/uvc/uvc_driver.c b/drivers/media/usb/uvc/uvc_driver.c
index 7c8322d..6a4b0b8 100644
--- a/drivers/media/usb/uvc/uvc_driver.c
+++ b/drivers/media/usb/uvc/uvc_driver.c
@@ -331,6 +331,7 @@ static int uvc_parse_format(struct uvc_device *dev,
struct uvc_format_desc *fmtdesc;
struct uvc_frame *frame;
const unsigned char *start = buffer;
+ unsigned int width_multiplier = 1;
unsigned int interval;
unsigned int i, n;
__u8 ftype;
@@ -366,6 +367,20 @@ static int uvc_parse_format(struct uvc_device *dev,
}
format->bpp = buffer[21];
+
+ /* Some devices report a format that doesn't match what they
+ * really send.
+ */
+ if (dev->quirks & UVC_QUIRK_FORCE_Y8) {
+ if (format->fcc == V4L2_PIX_FMT_YUYV) {
+ strlcpy(format->name, "Greyscale 8-bit (Y8 )",
+ sizeof(format->name));
+ format->fcc = V4L2_PIX_FMT_GREY;
+ format->bpp = 8;
+ width_multiplier = 2;
+ }
+ }
+
if (buffer[2] == UVC_VS_FORMAT_UNCOMPRESSED) {
ftype = UVC_VS_FRAME_UNCOMPRESSED;
} else {
@@ -474,7 +489,8 @@ static int uvc_parse_format(struct uvc_device *dev,
frame->bFrameIndex = buffer[3];
frame->bmCapabilities = buffer[4];
- frame->wWidth = get_unaligned_le16(&buffer[5]);
+ frame->wWidth = get_unaligned_le16(&buffer[5])
+ * width_multiplier;
frame->wHeight = get_unaligned_le16(&buffer[7]);
frame->dwMinBitRate = get_unaligned_le32(&buffer[9]);
frame->dwMaxBitRate = get_unaligned_le32(&buffer[13]);
@@ -1623,12 +1639,12 @@ static void uvc_delete(struct uvc_device *dev)
{
struct list_head *p, *n;
- usb_put_intf(dev->intf);
- usb_put_dev(dev->udev);
-
uvc_status_cleanup(dev);
uvc_ctrl_cleanup_device(dev);
+ usb_put_intf(dev->intf);
+ usb_put_dev(dev->udev);
+
if (dev->vdev.dev)
v4l2_device_unregister(&dev->vdev);
#ifdef CONFIG_MEDIA_CONTROLLER
@@ -1718,6 +1734,11 @@ static int uvc_register_video(struct uvc_device *dev,
struct video_device *vdev;
int ret;
+ /* Initialize the video buffers queue. */
+ ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
+ if (ret)
+ return ret;
+
/* Initialize the streaming interface with default streaming
* parameters.
*/
@@ -1744,6 +1765,7 @@ static int uvc_register_video(struct uvc_device *dev,
*/
vdev->v4l2_dev = &dev->vdev;
vdev->fops = &uvc_fops;
+ vdev->ioctl_ops = &uvc_ioctl_ops;
vdev->release = uvc_release;
vdev->prio = &stream->chain->prio;
if (stream->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
@@ -1991,14 +2013,13 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
{
struct uvc_device *dev = usb_get_intfdata(intf);
struct uvc_streaming *stream;
+ int ret = 0;
uvc_trace(UVC_TRACE_SUSPEND, "Resuming interface %u\n",
intf->cur_altsetting->desc.bInterfaceNumber);
if (intf->cur_altsetting->desc.bInterfaceSubClass ==
UVC_SC_VIDEOCONTROL) {
- int ret = 0;
-
if (reset) {
ret = uvc_ctrl_restore_values(dev);
if (ret < 0)
@@ -2014,8 +2035,13 @@ static int __uvc_resume(struct usb_interface *intf, int reset)
}
list_for_each_entry(stream, &dev->streams, list) {
- if (stream->intf == intf)
- return uvc_video_resume(stream, reset);
+ if (stream->intf == intf) {
+ ret = uvc_video_resume(stream, reset);
+ if (ret < 0)
+ uvc_queue_streamoff(&stream->queue,
+ stream->queue.queue.type);
+ return ret;
+ }
}
uvc_trace(UVC_TRACE_SUSPEND, "Resume: video streaming USB interface "
@@ -2504,6 +2530,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_IGNORE_SELECTOR_UNIT },
+ /* Oculus VR Positional Tracker DK2 */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x2833,
+ .idProduct = 0x0201,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_FORCE_Y8 },
/* Generic USB Video Class */
{ USB_INTERFACE_INFO(USB_CLASS_VIDEO, 1, 0) },
{}
diff --git a/drivers/media/usb/uvc/uvc_queue.c b/drivers/media/usb/uvc/uvc_queue.c
index 6e92d20..cc96072 100644
--- a/drivers/media/usb/uvc/uvc_queue.c
+++ b/drivers/media/usb/uvc/uvc_queue.c
@@ -36,6 +36,34 @@
* the driver.
*/
+static inline struct uvc_streaming *
+uvc_queue_to_stream(struct uvc_video_queue *queue)
+{
+ return container_of(queue, struct uvc_streaming, queue);
+}
+
+/*
+ * Return all queued buffers to videobuf2 in the requested state.
+ *
+ * This function must be called with the queue spinlock held.
+ */
+static void uvc_queue_return_buffers(struct uvc_video_queue *queue,
+ enum uvc_buffer_state state)
+{
+ enum vb2_buffer_state vb2_state = state == UVC_BUF_STATE_ERROR
+ ? VB2_BUF_STATE_ERROR
+ : VB2_BUF_STATE_QUEUED;
+
+ while (!list_empty(&queue->irqqueue)) {
+ struct uvc_buffer *buf = list_first_entry(&queue->irqqueue,
+ struct uvc_buffer,
+ queue);
+ list_del(&buf->queue);
+ buf->state = state;
+ vb2_buffer_done(&buf->buf, vb2_state);
+ }
+}
+
/* -----------------------------------------------------------------------------
* videobuf2 queue operations
*/
@@ -45,8 +73,7 @@ static int uvc_queue_setup(struct vb2_queue *vq, const struct v4l2_format *fmt,
unsigned int sizes[], void *alloc_ctxs[])
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
- struct uvc_streaming *stream =
- container_of(queue, struct uvc_streaming, queue);
+ struct uvc_streaming *stream = uvc_queue_to_stream(queue);
/* Make sure the image size is large enough. */
if (fmt && fmt->fmt.pix.sizeimage < stream->ctrl.dwMaxVideoFrameSize)
@@ -109,8 +136,7 @@ static void uvc_buffer_queue(struct vb2_buffer *vb)
static void uvc_buffer_finish(struct vb2_buffer *vb)
{
struct uvc_video_queue *queue = vb2_get_drv_priv(vb->vb2_queue);
- struct uvc_streaming *stream =
- container_of(queue, struct uvc_streaming, queue);
+ struct uvc_streaming *stream = uvc_queue_to_stream(queue);
struct uvc_buffer *buf = container_of(vb, struct uvc_buffer, buf);
if (vb->state == VB2_BUF_STATE_DONE)
@@ -131,6 +157,39 @@ static void uvc_wait_finish(struct vb2_queue *vq)
mutex_lock(&queue->mutex);
}
+static int uvc_start_streaming(struct vb2_queue *vq, unsigned int count)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+ struct uvc_streaming *stream = uvc_queue_to_stream(queue);
+ unsigned long flags;
+ int ret;
+
+ queue->buf_used = 0;
+
+ ret = uvc_video_enable(stream, 1);
+ if (ret == 0)
+ return 0;
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ uvc_queue_return_buffers(queue, UVC_BUF_STATE_QUEUED);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+
+ return ret;
+}
+
+static void uvc_stop_streaming(struct vb2_queue *vq)
+{
+ struct uvc_video_queue *queue = vb2_get_drv_priv(vq);
+ struct uvc_streaming *stream = uvc_queue_to_stream(queue);
+ unsigned long flags;
+
+ uvc_video_enable(stream, 0);
+
+ spin_lock_irqsave(&queue->irqlock, flags);
+ uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
+ spin_unlock_irqrestore(&queue->irqlock, flags);
+}
+
static struct vb2_ops uvc_queue_qops = {
.queue_setup = uvc_queue_setup,
.buf_prepare = uvc_buffer_prepare,
@@ -138,6 +197,8 @@ static struct vb2_ops uvc_queue_qops = {
.buf_finish = uvc_buffer_finish,
.wait_prepare = uvc_wait_prepare,
.wait_finish = uvc_wait_finish,
+ .start_streaming = uvc_start_streaming,
+ .stop_streaming = uvc_stop_streaming,
};
int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
@@ -165,12 +226,19 @@ int uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
return 0;
}
+void uvc_queue_release(struct uvc_video_queue *queue)
+{
+ mutex_lock(&queue->mutex);
+ vb2_queue_release(&queue->queue);
+ mutex_unlock(&queue->mutex);
+}
+
/* -----------------------------------------------------------------------------
* V4L2 queue operations
*/
-int uvc_alloc_buffers(struct uvc_video_queue *queue,
- struct v4l2_requestbuffers *rb)
+int uvc_request_buffers(struct uvc_video_queue *queue,
+ struct v4l2_requestbuffers *rb)
{
int ret;
@@ -181,13 +249,6 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue,
return ret ? ret : rb->count;
}
-void uvc_free_buffers(struct uvc_video_queue *queue)
-{
- mutex_lock(&queue->mutex);
- vb2_queue_release(&queue->queue);
- mutex_unlock(&queue->mutex);
-}
-
int uvc_query_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf)
{
int ret;
@@ -234,6 +295,28 @@ int uvc_dequeue_buffer(struct uvc_video_queue *queue, struct v4l2_buffer *buf,
return ret;
}
+int uvc_queue_streamon(struct uvc_video_queue *queue, enum v4l2_buf_type type)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = vb2_streamon(&queue->queue, type);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
+int uvc_queue_streamoff(struct uvc_video_queue *queue, enum v4l2_buf_type type)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = vb2_streamoff(&queue->queue, type);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
{
int ret;
@@ -289,49 +372,6 @@ int uvc_queue_allocated(struct uvc_video_queue *queue)
}
/*
- * Enable or disable the video buffers queue.
- *
- * The queue must be enabled before starting video acquisition and must be
- * disabled after stopping it. This ensures that the video buffers queue
- * state can be properly initialized before buffers are accessed from the
- * interrupt handler.
- *
- * Enabling the video queue returns -EBUSY if the queue is already enabled.
- *
- * Disabling the video queue cancels the queue and removes all buffers from
- * the main queue.
- *
- * This function can't be called from interrupt context. Use
- * uvc_queue_cancel() instead.
- */
-int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
-{
- unsigned long flags;
- int ret;
-
- mutex_lock(&queue->mutex);
- if (enable) {
- ret = vb2_streamon(&queue->queue, queue->queue.type);
- if (ret < 0)
- goto done;
-
- queue->buf_used = 0;
- } else {
- ret = vb2_streamoff(&queue->queue, queue->queue.type);
- if (ret < 0)
- goto done;
-
- spin_lock_irqsave(&queue->irqlock, flags);
- INIT_LIST_HEAD(&queue->irqqueue);
- spin_unlock_irqrestore(&queue->irqlock, flags);
- }
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
-}
-
-/*
* Cancel the video buffers queue.
*
* Cancelling the queue marks all buffers on the irq queue as erroneous,
@@ -345,17 +385,10 @@ done:
*/
void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect)
{
- struct uvc_buffer *buf;
unsigned long flags;
spin_lock_irqsave(&queue->irqlock, flags);
- while (!list_empty(&queue->irqqueue)) {
- buf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
- queue);
- list_del(&buf->queue);
- buf->state = UVC_BUF_STATE_ERROR;
- vb2_buffer_done(&buf->buf, VB2_BUF_STATE_ERROR);
- }
+ uvc_queue_return_buffers(queue, UVC_BUF_STATE_ERROR);
/* This must be protected by the irqlock spinlock to avoid race
* conditions between uvc_buffer_queue and the disconnection event that
* could result in an interruptible wait in uvc_dequeue_buffer. Do not
diff --git a/drivers/media/usb/uvc/uvc_v4l2.c b/drivers/media/usb/uvc/uvc_v4l2.c
index 378ae02..9c5cbcf 100644
--- a/drivers/media/usb/uvc/uvc_v4l2.c
+++ b/drivers/media/usb/uvc/uvc_v4l2.c
@@ -530,10 +530,8 @@ static int uvc_v4l2_release(struct file *file)
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
/* Only free resources if this is a privileged handle. */
- if (uvc_has_privileges(handle)) {
- uvc_video_enable(stream, 0);
- uvc_free_buffers(&stream->queue);
- }
+ if (uvc_has_privileges(handle))
+ uvc_queue_release(&stream->queue);
/* Release the file handle. */
uvc_dismiss_privileges(handle);
@@ -551,553 +549,628 @@ static int uvc_v4l2_release(struct file *file)
return 0;
}
-static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int uvc_ioctl_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
{
struct video_device *vdev = video_devdata(file);
struct uvc_fh *handle = file->private_data;
struct uvc_video_chain *chain = handle->chain;
struct uvc_streaming *stream = handle->stream;
- long ret = 0;
- switch (cmd) {
- /* Query capabilities */
- case VIDIOC_QUERYCAP:
- {
- struct v4l2_capability *cap = arg;
-
- memset(cap, 0, sizeof *cap);
- strlcpy(cap->driver, "uvcvideo", sizeof cap->driver);
- strlcpy(cap->card, vdev->name, sizeof cap->card);
- usb_make_path(stream->dev->udev,
- cap->bus_info, sizeof(cap->bus_info));
- cap->version = LINUX_VERSION_CODE;
- cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
- | chain->caps;
- if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->device_caps = V4L2_CAP_VIDEO_CAPTURE
- | V4L2_CAP_STREAMING;
- else
- cap->device_caps = V4L2_CAP_VIDEO_OUTPUT
- | V4L2_CAP_STREAMING;
- break;
- }
+ strlcpy(cap->driver, "uvcvideo", sizeof(cap->driver));
+ strlcpy(cap->card, vdev->name, sizeof(cap->card));
+ usb_make_path(stream->dev->udev, cap->bus_info, sizeof(cap->bus_info));
+ cap->capabilities = V4L2_CAP_DEVICE_CAPS | V4L2_CAP_STREAMING
+ | chain->caps;
+ if (stream->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ else
+ cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- /* Priority */
- case VIDIOC_G_PRIORITY:
- *(u32 *)arg = v4l2_prio_max(vdev->prio);
- break;
+ return 0;
+}
- case VIDIOC_S_PRIORITY:
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+static int uvc_ioctl_enum_fmt(struct uvc_streaming *stream,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct uvc_format *format;
+ enum v4l2_buf_type type = fmt->type;
+ __u32 index = fmt->index;
- return v4l2_prio_change(vdev->prio, &handle->vfh.prio,
- *(u32 *)arg);
+ if (fmt->type != stream->type || fmt->index >= stream->nformats)
+ return -EINVAL;
- /* Get, Set & Query control */
- case VIDIOC_QUERYCTRL:
- return uvc_query_v4l2_ctrl(chain, arg);
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->index = index;
+ fmt->type = type;
+
+ format = &stream->format[fmt->index];
+ fmt->flags = 0;
+ if (format->flags & UVC_FMT_FLAG_COMPRESSED)
+ fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
+ strlcpy(fmt->description, format->name, sizeof(fmt->description));
+ fmt->description[sizeof(fmt->description) - 1] = 0;
+ fmt->pixelformat = format->fcc;
+ return 0;
+}
- case VIDIOC_G_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- struct v4l2_ext_control xctrl;
+static int uvc_ioctl_enum_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- memset(&xctrl, 0, sizeof xctrl);
- xctrl.id = ctrl->id;
+ return uvc_ioctl_enum_fmt(stream, fmt);
+}
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
+static int uvc_ioctl_enum_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- ret = uvc_ctrl_get(chain, &xctrl);
- uvc_ctrl_rollback(handle);
- if (ret >= 0)
- ctrl->value = xctrl.value;
- break;
- }
+ return uvc_ioctl_enum_fmt(stream, fmt);
+}
- case VIDIOC_S_CTRL:
- {
- struct v4l2_control *ctrl = arg;
- struct v4l2_ext_control xctrl;
+static int uvc_ioctl_g_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+ return uvc_v4l2_get_format(stream, fmt);
+}
- memset(&xctrl, 0, sizeof xctrl);
- xctrl.id = ctrl->id;
- xctrl.value = ctrl->value;
+static int uvc_ioctl_g_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
+ return uvc_v4l2_get_format(stream, fmt);
+}
- ret = uvc_ctrl_set(chain, &xctrl);
- if (ret < 0) {
- uvc_ctrl_rollback(handle);
- return ret;
- }
- ret = uvc_ctrl_commit(handle, &xctrl, 1);
- if (ret == 0)
- ctrl->value = xctrl.value;
- break;
- }
+static int uvc_ioctl_s_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ int ret;
- case VIDIOC_QUERYMENU:
- return uvc_query_v4l2_menu(chain, arg);
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
- case VIDIOC_G_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctrls = arg;
- struct v4l2_ext_control *ctrl = ctrls->controls;
- unsigned int i;
+ return uvc_v4l2_set_format(stream, fmt);
+}
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
+static int uvc_ioctl_s_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ int ret;
- for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_get(chain, ctrl);
- if (ret < 0) {
- uvc_ctrl_rollback(handle);
- ctrls->error_idx = i;
- return ret;
- }
- }
- ctrls->error_idx = 0;
- ret = uvc_ctrl_rollback(handle);
- break;
- }
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
- case VIDIOC_S_EXT_CTRLS:
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
- /* Fall through */
- case VIDIOC_TRY_EXT_CTRLS:
- {
- struct v4l2_ext_controls *ctrls = arg;
- struct v4l2_ext_control *ctrl = ctrls->controls;
- unsigned int i;
-
- ret = uvc_ctrl_begin(chain);
- if (ret < 0)
- return ret;
+ return uvc_v4l2_set_format(stream, fmt);
+}
- for (i = 0; i < ctrls->count; ++ctrl, ++i) {
- ret = uvc_ctrl_set(chain, ctrl);
- if (ret < 0) {
- uvc_ctrl_rollback(handle);
- ctrls->error_idx = cmd == VIDIOC_S_EXT_CTRLS
- ? ctrls->count : i;
- return ret;
- }
- }
+static int uvc_ioctl_try_fmt_vid_cap(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ struct uvc_streaming_control probe;
- ctrls->error_idx = 0;
+ return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL);
+}
- if (cmd == VIDIOC_S_EXT_CTRLS)
- ret = uvc_ctrl_commit(handle,
- ctrls->controls, ctrls->count);
- else
- ret = uvc_ctrl_rollback(handle);
- break;
- }
+static int uvc_ioctl_try_fmt_vid_out(struct file *file, void *fh,
+ struct v4l2_format *fmt)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ struct uvc_streaming_control probe;
- /* Get, Set & Enum input */
- case VIDIOC_ENUMINPUT:
- {
- const struct uvc_entity *selector = chain->selector;
- struct v4l2_input *input = arg;
- struct uvc_entity *iterm = NULL;
- u32 index = input->index;
- int pin = 0;
-
- if (selector == NULL ||
- (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
- if (index != 0)
- return -EINVAL;
- list_for_each_entry(iterm, &chain->entities, chain) {
- if (UVC_ENTITY_IS_ITERM(iterm))
- break;
- }
- pin = iterm->id;
- } else if (index < selector->bNrInPins) {
- pin = selector->baSourceID[index];
- list_for_each_entry(iterm, &chain->entities, chain) {
- if (!UVC_ENTITY_IS_ITERM(iterm))
- continue;
- if (iterm->id == pin)
- break;
- }
- }
+ return uvc_v4l2_try_format(stream, fmt, &probe, NULL, NULL);
+}
- if (iterm == NULL || iterm->id != pin)
- return -EINVAL;
+static int uvc_ioctl_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *rb)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ int ret;
- memset(input, 0, sizeof *input);
- input->index = index;
- strlcpy(input->name, iterm->name, sizeof input->name);
- if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
- input->type = V4L2_INPUT_TYPE_CAMERA;
- break;
- }
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
- case VIDIOC_G_INPUT:
- {
- u8 input;
+ mutex_lock(&stream->mutex);
+ ret = uvc_request_buffers(&stream->queue, rb);
+ mutex_unlock(&stream->mutex);
+ if (ret < 0)
+ return ret;
- if (chain->selector == NULL ||
- (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
- *(int *)arg = 0;
- break;
- }
+ if (ret == 0)
+ uvc_dismiss_privileges(handle);
- ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
- chain->selector->id, chain->dev->intfnum,
- UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
- if (ret < 0)
- return ret;
+ return 0;
+}
- *(int *)arg = input - 1;
- break;
- }
+static int uvc_ioctl_querybuf(struct file *file, void *fh,
+ struct v4l2_buffer *buf)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- case VIDIOC_S_INPUT:
- {
- u32 input = *(u32 *)arg + 1;
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+ return uvc_query_buffer(&stream->queue, buf);
+}
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
+static int uvc_ioctl_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- if (chain->selector == NULL ||
- (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
- if (input != 1)
- return -EINVAL;
- break;
- }
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
- if (input == 0 || input > chain->selector->bNrInPins)
- return -EINVAL;
+ return uvc_queue_buffer(&stream->queue, buf);
+}
- return uvc_query_ctrl(chain->dev, UVC_SET_CUR,
- chain->selector->id, chain->dev->intfnum,
- UVC_SU_INPUT_SELECT_CONTROL, &input, 1);
- }
+static int uvc_ioctl_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- /* Try, Get, Set & Enum format */
- case VIDIOC_ENUM_FMT:
- {
- struct v4l2_fmtdesc *fmt = arg;
- struct uvc_format *format;
- enum v4l2_buf_type type = fmt->type;
- __u32 index = fmt->index;
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
- if (fmt->type != stream->type ||
- fmt->index >= stream->nformats)
- return -EINVAL;
+ return uvc_dequeue_buffer(&stream->queue, buf,
+ file->f_flags & O_NONBLOCK);
+}
- memset(fmt, 0, sizeof(*fmt));
- fmt->index = index;
- fmt->type = type;
-
- format = &stream->format[fmt->index];
- fmt->flags = 0;
- if (format->flags & UVC_FMT_FLAG_COMPRESSED)
- fmt->flags |= V4L2_FMT_FLAG_COMPRESSED;
- strlcpy(fmt->description, format->name,
- sizeof fmt->description);
- fmt->description[sizeof fmt->description - 1] = 0;
- fmt->pixelformat = format->fcc;
- break;
- }
+static int uvc_ioctl_create_bufs(struct file *file, void *fh,
+ struct v4l2_create_buffers *cb)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ int ret;
- case VIDIOC_TRY_FMT:
- {
- struct uvc_streaming_control probe;
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
- return uvc_v4l2_try_format(stream, arg, &probe, NULL, NULL);
- }
+ return uvc_create_buffers(&stream->queue, cb);
+}
- case VIDIOC_S_FMT:
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+static int uvc_ioctl_streamon(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ int ret;
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
- return uvc_v4l2_set_format(stream, arg);
+ mutex_lock(&stream->mutex);
+ ret = uvc_queue_streamon(&stream->queue, type);
+ mutex_unlock(&stream->mutex);
- case VIDIOC_G_FMT:
- return uvc_v4l2_get_format(stream, arg);
+ return ret;
+}
- /* Frame size enumeration */
- case VIDIOC_ENUM_FRAMESIZES:
- {
- struct v4l2_frmsizeenum *fsize = arg;
- struct uvc_format *format = NULL;
- struct uvc_frame *frame;
- int i;
+static int uvc_ioctl_streamoff(struct file *file, void *fh,
+ enum v4l2_buf_type type)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
- /* Look for the given pixel format */
- for (i = 0; i < stream->nformats; i++) {
- if (stream->format[i].fcc ==
- fsize->pixel_format) {
- format = &stream->format[i];
- break;
- }
- }
- if (format == NULL)
- return -EINVAL;
+ if (!uvc_has_privileges(handle))
+ return -EBUSY;
- if (fsize->index >= format->nframes)
- return -EINVAL;
+ mutex_lock(&stream->mutex);
+ uvc_queue_streamoff(&stream->queue, type);
+ mutex_unlock(&stream->mutex);
- frame = &format->frame[fsize->index];
- fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
- fsize->discrete.width = frame->wWidth;
- fsize->discrete.height = frame->wHeight;
- break;
- }
+ return 0;
+}
- /* Frame interval enumeration */
- case VIDIOC_ENUM_FRAMEINTERVALS:
- {
- struct v4l2_frmivalenum *fival = arg;
- struct uvc_format *format = NULL;
- struct uvc_frame *frame = NULL;
- int i;
-
- /* Look for the given pixel format and frame size */
- for (i = 0; i < stream->nformats; i++) {
- if (stream->format[i].fcc ==
- fival->pixel_format) {
- format = &stream->format[i];
- break;
- }
- }
- if (format == NULL)
+static int uvc_ioctl_enum_input(struct file *file, void *fh,
+ struct v4l2_input *input)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ const struct uvc_entity *selector = chain->selector;
+ struct uvc_entity *iterm = NULL;
+ u32 index = input->index;
+ int pin = 0;
+
+ if (selector == NULL ||
+ (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (index != 0)
return -EINVAL;
-
- for (i = 0; i < format->nframes; i++) {
- if (format->frame[i].wWidth == fival->width &&
- format->frame[i].wHeight == fival->height) {
- frame = &format->frame[i];
+ list_for_each_entry(iterm, &chain->entities, chain) {
+ if (UVC_ENTITY_IS_ITERM(iterm))
break;
- }
}
- if (frame == NULL)
- return -EINVAL;
-
- if (frame->bFrameIntervalType) {
- if (fival->index >= frame->bFrameIntervalType)
- return -EINVAL;
-
- fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
- fival->discrete.numerator =
- frame->dwFrameInterval[fival->index];
- fival->discrete.denominator = 10000000;
- uvc_simplify_fraction(&fival->discrete.numerator,
- &fival->discrete.denominator, 8, 333);
- } else {
- fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
- fival->stepwise.min.numerator =
- frame->dwFrameInterval[0];
- fival->stepwise.min.denominator = 10000000;
- fival->stepwise.max.numerator =
- frame->dwFrameInterval[1];
- fival->stepwise.max.denominator = 10000000;
- fival->stepwise.step.numerator =
- frame->dwFrameInterval[2];
- fival->stepwise.step.denominator = 10000000;
- uvc_simplify_fraction(&fival->stepwise.min.numerator,
- &fival->stepwise.min.denominator, 8, 333);
- uvc_simplify_fraction(&fival->stepwise.max.numerator,
- &fival->stepwise.max.denominator, 8, 333);
- uvc_simplify_fraction(&fival->stepwise.step.numerator,
- &fival->stepwise.step.denominator, 8, 333);
+ pin = iterm->id;
+ } else if (index < selector->bNrInPins) {
+ pin = selector->baSourceID[index];
+ list_for_each_entry(iterm, &chain->entities, chain) {
+ if (!UVC_ENTITY_IS_ITERM(iterm))
+ continue;
+ if (iterm->id == pin)
+ break;
}
- break;
}
- /* Get & Set streaming parameters */
- case VIDIOC_G_PARM:
- return uvc_v4l2_get_streamparm(stream, arg);
+ if (iterm == NULL || iterm->id != pin)
+ return -EINVAL;
- case VIDIOC_S_PARM:
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+ memset(input, 0, sizeof(*input));
+ input->index = index;
+ strlcpy(input->name, iterm->name, sizeof(input->name));
+ if (UVC_ENTITY_TYPE(iterm) == UVC_ITT_CAMERA)
+ input->type = V4L2_INPUT_TYPE_CAMERA;
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
+ return 0;
+}
- return uvc_v4l2_set_streamparm(stream, arg);
+static int uvc_ioctl_g_input(struct file *file, void *fh, unsigned int *input)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ int ret;
+ u8 i;
- /* Cropping and scaling */
- case VIDIOC_CROPCAP:
- {
- struct v4l2_cropcap *ccap = arg;
+ if (chain->selector == NULL ||
+ (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ *input = 0;
+ return 0;
+ }
- if (ccap->type != stream->type)
- return -EINVAL;
+ ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, chain->selector->id,
+ chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL,
+ &i, 1);
+ if (ret < 0)
+ return ret;
- ccap->bounds.left = 0;
- ccap->bounds.top = 0;
+ *input = i - 1;
+ return 0;
+}
- mutex_lock(&stream->mutex);
- ccap->bounds.width = stream->cur_frame->wWidth;
- ccap->bounds.height = stream->cur_frame->wHeight;
- mutex_unlock(&stream->mutex);
+static int uvc_ioctl_s_input(struct file *file, void *fh, unsigned int input)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ int ret;
+ u32 i;
- ccap->defrect = ccap->bounds;
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
- ccap->pixelaspect.numerator = 1;
- ccap->pixelaspect.denominator = 1;
- break;
+ if (chain->selector == NULL ||
+ (chain->dev->quirks & UVC_QUIRK_IGNORE_SELECTOR_UNIT)) {
+ if (input)
+ return -EINVAL;
+ return 0;
}
- case VIDIOC_G_CROP:
- case VIDIOC_S_CROP:
- return -ENOTTY;
+ if (input >= chain->selector->bNrInPins)
+ return -EINVAL;
- /* Buffers & streaming */
- case VIDIOC_REQBUFS:
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+ i = input + 1;
+ return uvc_query_ctrl(chain->dev, UVC_SET_CUR, chain->selector->id,
+ chain->dev->intfnum, UVC_SU_INPUT_SELECT_CONTROL,
+ &i, 1);
+}
- if ((ret = uvc_acquire_privileges(handle)) < 0)
- return ret;
+static int uvc_ioctl_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *qc)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
- mutex_lock(&stream->mutex);
- ret = uvc_alloc_buffers(&stream->queue, arg);
- mutex_unlock(&stream->mutex);
- if (ret < 0)
- return ret;
+ return uvc_query_v4l2_ctrl(chain, qc);
+}
- if (ret == 0)
- uvc_dismiss_privileges(handle);
+static int uvc_ioctl_g_ctrl(struct file *file, void *fh,
+ struct v4l2_control *ctrl)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ struct v4l2_ext_control xctrl;
+ int ret;
- ret = 0;
- break;
+ memset(&xctrl, 0, sizeof(xctrl));
+ xctrl.id = ctrl->id;
+
+ ret = uvc_ctrl_begin(chain);
+ if (ret < 0)
+ return ret;
- case VIDIOC_QUERYBUF:
- {
- struct v4l2_buffer *buf = arg;
+ ret = uvc_ctrl_get(chain, &xctrl);
+ uvc_ctrl_rollback(handle);
+ if (ret < 0)
+ return ret;
- if (!uvc_has_privileges(handle))
- return -EBUSY;
+ ctrl->value = xctrl.value;
+ return 0;
+}
- return uvc_query_buffer(&stream->queue, buf);
- }
+static int uvc_ioctl_s_ctrl(struct file *file, void *fh,
+ struct v4l2_control *ctrl)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ struct v4l2_ext_control xctrl;
+ int ret;
- case VIDIOC_CREATE_BUFS:
- {
- struct v4l2_create_buffers *cb = arg;
+ memset(&xctrl, 0, sizeof(xctrl));
+ xctrl.id = ctrl->id;
+ xctrl.value = ctrl->value;
- ret = uvc_acquire_privileges(handle);
- if (ret < 0)
- return ret;
+ ret = uvc_ctrl_begin(chain);
+ if (ret < 0)
+ return ret;
- return uvc_create_buffers(&stream->queue, cb);
+ ret = uvc_ctrl_set(chain, &xctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(handle);
+ return ret;
}
- case VIDIOC_QBUF:
- if (!uvc_has_privileges(handle))
- return -EBUSY;
+ ret = uvc_ctrl_commit(handle, &xctrl, 1);
+ if (ret < 0)
+ return ret;
- return uvc_queue_buffer(&stream->queue, arg);
+ ctrl->value = xctrl.value;
+ return 0;
+}
+
+static int uvc_ioctl_g_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ struct v4l2_ext_control *ctrl = ctrls->controls;
+ unsigned int i;
+ int ret;
- case VIDIOC_DQBUF:
- if (!uvc_has_privileges(handle))
- return -EBUSY;
+ ret = uvc_ctrl_begin(chain);
+ if (ret < 0)
+ return ret;
- return uvc_dequeue_buffer(&stream->queue, arg,
- file->f_flags & O_NONBLOCK);
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ ret = uvc_ctrl_get(chain, ctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(handle);
+ ctrls->error_idx = i;
+ return ret;
+ }
+ }
- case VIDIOC_STREAMON:
- {
- int *type = arg;
+ ctrls->error_idx = 0;
- if (*type != stream->type)
- return -EINVAL;
+ return uvc_ctrl_rollback(handle);
+}
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+static int uvc_ioctl_s_try_ext_ctrls(struct uvc_fh *handle,
+ struct v4l2_ext_controls *ctrls,
+ bool commit)
+{
+ struct v4l2_ext_control *ctrl = ctrls->controls;
+ struct uvc_video_chain *chain = handle->chain;
+ unsigned int i;
+ int ret;
- if (!uvc_has_privileges(handle))
- return -EBUSY;
+ ret = uvc_ctrl_begin(chain);
+ if (ret < 0)
+ return ret;
- mutex_lock(&stream->mutex);
- ret = uvc_video_enable(stream, 1);
- mutex_unlock(&stream->mutex);
- if (ret < 0)
+ for (i = 0; i < ctrls->count; ++ctrl, ++i) {
+ ret = uvc_ctrl_set(chain, ctrl);
+ if (ret < 0) {
+ uvc_ctrl_rollback(handle);
+ ctrls->error_idx = commit ? ctrls->count : i;
return ret;
- break;
+ }
}
- case VIDIOC_STREAMOFF:
- {
- int *type = arg;
+ ctrls->error_idx = 0;
- if (*type != stream->type)
- return -EINVAL;
+ if (commit)
+ return uvc_ctrl_commit(handle, ctrls->controls, ctrls->count);
+ else
+ return uvc_ctrl_rollback(handle);
+}
- ret = v4l2_prio_check(vdev->prio, handle->vfh.prio);
- if (ret < 0)
- return ret;
+static int uvc_ioctl_s_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct uvc_fh *handle = fh;
+
+ return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, true);
+}
- if (!uvc_has_privileges(handle))
- return -EBUSY;
+static int uvc_ioctl_try_ext_ctrls(struct file *file, void *fh,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct uvc_fh *handle = fh;
- return uvc_video_enable(stream, 0);
+ return uvc_ioctl_s_try_ext_ctrls(handle, ctrls, false);
+}
+
+static int uvc_ioctl_querymenu(struct file *file, void *fh,
+ struct v4l2_querymenu *qm)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+
+ return uvc_query_v4l2_menu(chain, qm);
+}
+
+static int uvc_ioctl_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *ccap)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+
+ if (ccap->type != stream->type)
+ return -EINVAL;
+
+ ccap->bounds.left = 0;
+ ccap->bounds.top = 0;
+ mutex_lock(&stream->mutex);
+ ccap->bounds.width = stream->cur_frame->wWidth;
+ ccap->bounds.height = stream->cur_frame->wHeight;
+ mutex_unlock(&stream->mutex);
+
+ ccap->defrect = ccap->bounds;
+
+ ccap->pixelaspect.numerator = 1;
+ ccap->pixelaspect.denominator = 1;
+ return 0;
+}
+
+static int uvc_ioctl_g_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+
+ return uvc_v4l2_get_streamparm(stream, parm);
+}
+
+static int uvc_ioctl_s_parm(struct file *file, void *fh,
+ struct v4l2_streamparm *parm)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ int ret;
+
+ ret = uvc_acquire_privileges(handle);
+ if (ret < 0)
+ return ret;
+
+ return uvc_v4l2_set_streamparm(stream, parm);
+}
+
+static int uvc_ioctl_enum_framesizes(struct file *file, void *fh,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame;
+ int i;
+
+ /* Look for the given pixel format */
+ for (i = 0; i < stream->nformats; i++) {
+ if (stream->format[i].fcc == fsize->pixel_format) {
+ format = &stream->format[i];
+ break;
+ }
}
+ if (format == NULL)
+ return -EINVAL;
- case VIDIOC_SUBSCRIBE_EVENT:
- {
- struct v4l2_event_subscription *sub = arg;
+ if (fsize->index >= format->nframes)
+ return -EINVAL;
- switch (sub->type) {
- case V4L2_EVENT_CTRL:
- return v4l2_event_subscribe(&handle->vfh, sub, 0,
- &uvc_ctrl_sub_ev_ops);
- default:
- return -EINVAL;
+ frame = &format->frame[fsize->index];
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = frame->wWidth;
+ fsize->discrete.height = frame->wHeight;
+ return 0;
+}
+
+static int uvc_ioctl_enum_frameintervals(struct file *file, void *fh,
+ struct v4l2_frmivalenum *fival)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_streaming *stream = handle->stream;
+ struct uvc_format *format = NULL;
+ struct uvc_frame *frame = NULL;
+ int i;
+
+ /* Look for the given pixel format and frame size */
+ for (i = 0; i < stream->nformats; i++) {
+ if (stream->format[i].fcc == fival->pixel_format) {
+ format = &stream->format[i];
+ break;
}
}
+ if (format == NULL)
+ return -EINVAL;
- case VIDIOC_UNSUBSCRIBE_EVENT:
- return v4l2_event_unsubscribe(&handle->vfh, arg);
+ for (i = 0; i < format->nframes; i++) {
+ if (format->frame[i].wWidth == fival->width &&
+ format->frame[i].wHeight == fival->height) {
+ frame = &format->frame[i];
+ break;
+ }
+ }
+ if (frame == NULL)
+ return -EINVAL;
- case VIDIOC_DQEVENT:
- return v4l2_event_dequeue(&handle->vfh, arg,
- file->f_flags & O_NONBLOCK);
+ if (frame->bFrameIntervalType) {
+ if (fival->index >= frame->bFrameIntervalType)
+ return -EINVAL;
- /* Analog video standards make no sense for digital cameras. */
- case VIDIOC_ENUMSTD:
- case VIDIOC_QUERYSTD:
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
+ fival->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ fival->discrete.numerator =
+ frame->dwFrameInterval[fival->index];
+ fival->discrete.denominator = 10000000;
+ uvc_simplify_fraction(&fival->discrete.numerator,
+ &fival->discrete.denominator, 8, 333);
+ } else {
+ fival->type = V4L2_FRMIVAL_TYPE_STEPWISE;
+ fival->stepwise.min.numerator = frame->dwFrameInterval[0];
+ fival->stepwise.min.denominator = 10000000;
+ fival->stepwise.max.numerator = frame->dwFrameInterval[1];
+ fival->stepwise.max.denominator = 10000000;
+ fival->stepwise.step.numerator = frame->dwFrameInterval[2];
+ fival->stepwise.step.denominator = 10000000;
+ uvc_simplify_fraction(&fival->stepwise.min.numerator,
+ &fival->stepwise.min.denominator, 8, 333);
+ uvc_simplify_fraction(&fival->stepwise.max.numerator,
+ &fival->stepwise.max.denominator, 8, 333);
+ uvc_simplify_fraction(&fival->stepwise.step.numerator,
+ &fival->stepwise.step.denominator, 8, 333);
+ }
- case VIDIOC_OVERLAY:
+ return 0;
+}
- case VIDIOC_ENUMAUDIO:
- case VIDIOC_ENUMAUDOUT:
+static int uvc_ioctl_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_CTRL:
+ return v4l2_event_subscribe(fh, sub, 0, &uvc_ctrl_sub_ev_ops);
+ default:
+ return -EINVAL;
+ }
+}
- case VIDIOC_ENUMOUTPUT:
- uvc_trace(UVC_TRACE_IOCTL, "Unsupported ioctl 0x%08x\n", cmd);
- return -ENOTTY;
+static long uvc_ioctl_default(struct file *file, void *fh, bool valid_prio,
+ unsigned int cmd, void *arg)
+{
+ struct uvc_fh *handle = fh;
+ struct uvc_video_chain *chain = handle->chain;
+ switch (cmd) {
+ /* Dynamic controls. */
case UVCIOC_CTRL_MAP:
return uvc_ioctl_ctrl_map(chain, arg);
@@ -1105,23 +1178,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return uvc_xu_ctrl_query(chain, arg);
default:
- uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
return -ENOTTY;
}
-
- return ret;
-}
-
-static long uvc_v4l2_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- if (uvc_trace_param & UVC_TRACE_IOCTL) {
- uvc_printk(KERN_DEBUG, "uvc_v4l2_ioctl(");
- v4l_printk_ioctl(NULL, cmd);
- printk(")\n");
- }
-
- return video_usercopy(file, cmd, arg, uvc_v4l2_do_ioctl);
}
#ifdef CONFIG_COMPAT
@@ -1304,7 +1362,7 @@ static long uvc_v4l2_compat_ioctl32(struct file *file,
old_fs = get_fs();
set_fs(KERNEL_DS);
- ret = uvc_v4l2_ioctl(file, cmd, (unsigned long)&karg);
+ ret = video_ioctl2(file, cmd, (unsigned long)&karg);
set_fs(old_fs);
if (ret < 0)
@@ -1365,11 +1423,48 @@ static unsigned long uvc_v4l2_get_unmapped_area(struct file *file,
}
#endif
+const struct v4l2_ioctl_ops uvc_ioctl_ops = {
+ .vidioc_querycap = uvc_ioctl_querycap,
+ .vidioc_enum_fmt_vid_cap = uvc_ioctl_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out = uvc_ioctl_enum_fmt_vid_out,
+ .vidioc_g_fmt_vid_cap = uvc_ioctl_g_fmt_vid_cap,
+ .vidioc_g_fmt_vid_out = uvc_ioctl_g_fmt_vid_out,
+ .vidioc_s_fmt_vid_cap = uvc_ioctl_s_fmt_vid_cap,
+ .vidioc_s_fmt_vid_out = uvc_ioctl_s_fmt_vid_out,
+ .vidioc_try_fmt_vid_cap = uvc_ioctl_try_fmt_vid_cap,
+ .vidioc_try_fmt_vid_out = uvc_ioctl_try_fmt_vid_out,
+ .vidioc_reqbufs = uvc_ioctl_reqbufs,
+ .vidioc_querybuf = uvc_ioctl_querybuf,
+ .vidioc_qbuf = uvc_ioctl_qbuf,
+ .vidioc_dqbuf = uvc_ioctl_dqbuf,
+ .vidioc_create_bufs = uvc_ioctl_create_bufs,
+ .vidioc_streamon = uvc_ioctl_streamon,
+ .vidioc_streamoff = uvc_ioctl_streamoff,
+ .vidioc_enum_input = uvc_ioctl_enum_input,
+ .vidioc_g_input = uvc_ioctl_g_input,
+ .vidioc_s_input = uvc_ioctl_s_input,
+ .vidioc_queryctrl = uvc_ioctl_queryctrl,
+ .vidioc_g_ctrl = uvc_ioctl_g_ctrl,
+ .vidioc_s_ctrl = uvc_ioctl_s_ctrl,
+ .vidioc_g_ext_ctrls = uvc_ioctl_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = uvc_ioctl_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = uvc_ioctl_try_ext_ctrls,
+ .vidioc_querymenu = uvc_ioctl_querymenu,
+ .vidioc_cropcap = uvc_ioctl_cropcap,
+ .vidioc_g_parm = uvc_ioctl_g_parm,
+ .vidioc_s_parm = uvc_ioctl_s_parm,
+ .vidioc_enum_framesizes = uvc_ioctl_enum_framesizes,
+ .vidioc_enum_frameintervals = uvc_ioctl_enum_frameintervals,
+ .vidioc_subscribe_event = uvc_ioctl_subscribe_event,
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+ .vidioc_default = uvc_ioctl_default,
+};
+
const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
- .unlocked_ioctl = uvc_v4l2_ioctl,
+ .unlocked_ioctl = video_ioctl2,
#ifdef CONFIG_COMPAT
.compat_ioctl32 = uvc_v4l2_compat_ioctl32,
#endif
diff --git a/drivers/media/usb/uvc/uvc_video.c b/drivers/media/usb/uvc/uvc_video.c
index df81b9c..9637e8b 100644
--- a/drivers/media/usb/uvc/uvc_video.c
+++ b/drivers/media/usb/uvc/uvc_video.c
@@ -1021,6 +1021,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
uvc_video_get_ts(&ts);
+ buf->buf.v4l2_buf.field = V4L2_FIELD_NONE;
buf->buf.v4l2_buf.sequence = stream->sequence;
buf->buf.v4l2_buf.timestamp.tv_sec = ts.tv_sec;
buf->buf.v4l2_buf.timestamp.tv_usec =
@@ -1734,19 +1735,13 @@ int uvc_video_resume(struct uvc_streaming *stream, int reset)
uvc_video_clock_reset(stream);
ret = uvc_commit_video(stream, &stream->ctrl);
- if (ret < 0) {
- uvc_queue_enable(&stream->queue, 0);
+ if (ret < 0)
return ret;
- }
if (!uvc_queue_streaming(&stream->queue))
return 0;
- ret = uvc_init_video(stream, GFP_NOIO);
- if (ret < 0)
- uvc_queue_enable(&stream->queue, 0);
-
- return ret;
+ return uvc_init_video(stream, GFP_NOIO);
}
/* ------------------------------------------------------------------------
@@ -1778,11 +1773,6 @@ int uvc_video_init(struct uvc_streaming *stream)
atomic_set(&stream->active, 0);
- /* Initialize the video buffers queue. */
- ret = uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
- if (ret)
- return ret;
-
/* Alternate setting 0 should be the default, yet the XBox Live Vision
* Cam (and possibly other devices) crash or otherwise misbehave if
* they don't receive a SET_INTERFACE request before any other video
@@ -1889,7 +1879,6 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
usb_clear_halt(stream->dev->udev, pipe);
}
- uvc_queue_enable(&stream->queue, 0);
uvc_video_clock_cleanup(stream);
return 0;
}
@@ -1898,10 +1887,6 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
if (ret < 0)
return ret;
- ret = uvc_queue_enable(&stream->queue, 1);
- if (ret < 0)
- goto error_queue;
-
/* Commit the streaming parameters. */
ret = uvc_commit_video(stream, &stream->ctrl);
if (ret < 0)
@@ -1916,8 +1901,6 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
error_video:
usb_set_interface(stream->dev->udev, stream->intfnum, 0);
error_commit:
- uvc_queue_enable(&stream->queue, 0);
-error_queue:
uvc_video_clock_cleanup(stream);
return ret;
diff --git a/drivers/media/usb/uvc/uvcvideo.h b/drivers/media/usb/uvc/uvcvideo.h
index 864ada7..f0a04b5 100644
--- a/drivers/media/usb/uvc/uvcvideo.h
+++ b/drivers/media/usb/uvc/uvcvideo.h
@@ -148,6 +148,7 @@
#define UVC_QUIRK_PROBE_DEF 0x00000100
#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
#define UVC_QUIRK_RESTORE_CTRLS_ON_INIT 0x00000400
+#define UVC_QUIRK_FORCE_Y8 0x00000800
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -579,7 +580,6 @@ struct uvc_driver {
#define UVC_TRACE_FORMAT (1 << 3)
#define UVC_TRACE_CAPTURE (1 << 4)
#define UVC_TRACE_CALLS (1 << 5)
-#define UVC_TRACE_IOCTL (1 << 6)
#define UVC_TRACE_FRAME (1 << 7)
#define UVC_TRACE_SUSPEND (1 << 8)
#define UVC_TRACE_STATUS (1 << 9)
@@ -623,9 +623,9 @@ extern struct uvc_entity *uvc_entity_by_id(struct uvc_device *dev, int id);
/* Video buffers queue management. */
extern int uvc_queue_init(struct uvc_video_queue *queue,
enum v4l2_buf_type type, int drop_corrupted);
-extern int uvc_alloc_buffers(struct uvc_video_queue *queue,
+extern void uvc_queue_release(struct uvc_video_queue *queue);
+extern int uvc_request_buffers(struct uvc_video_queue *queue,
struct v4l2_requestbuffers *rb);
-extern void uvc_free_buffers(struct uvc_video_queue *queue);
extern int uvc_query_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
extern int uvc_create_buffers(struct uvc_video_queue *queue,
@@ -634,7 +634,10 @@ extern int uvc_queue_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf);
extern int uvc_dequeue_buffer(struct uvc_video_queue *queue,
struct v4l2_buffer *v4l2_buf, int nonblocking);
-extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
+extern int uvc_queue_streamon(struct uvc_video_queue *queue,
+ enum v4l2_buf_type type);
+extern int uvc_queue_streamoff(struct uvc_video_queue *queue,
+ enum v4l2_buf_type type);
extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf);
@@ -653,6 +656,7 @@ static inline int uvc_queue_streaming(struct uvc_video_queue *queue)
}
/* V4L2 interface */
+extern const struct v4l2_ioctl_ops uvc_ioctl_ops;
extern const struct v4l2_file_operations uvc_fops;
/* Media controller */
diff --git a/drivers/media/v4l2-core/v4l2-common.c b/drivers/media/v4l2-core/v4l2-common.c
index 2e9d81f..5b80850 100644
--- a/drivers/media/v4l2-core/v4l2-common.c
+++ b/drivers/media/v4l2-core/v4l2-common.c
@@ -80,36 +80,6 @@ MODULE_LICENSE("GPL");
/* Helper functions for control handling */
-/* Check for correctness of the ctrl's value based on the data from
- struct v4l2_queryctrl and the available menu items. Note that
- menu_items may be NULL, in that case it is ignored. */
-int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
- const char * const *menu_items)
-{
- if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
- if (qctrl->flags & V4L2_CTRL_FLAG_GRABBED)
- return -EBUSY;
- if (qctrl->type == V4L2_CTRL_TYPE_STRING)
- return 0;
- if (qctrl->type == V4L2_CTRL_TYPE_BUTTON ||
- qctrl->type == V4L2_CTRL_TYPE_INTEGER64 ||
- qctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
- return 0;
- if (ctrl->value < qctrl->minimum || ctrl->value > qctrl->maximum)
- return -ERANGE;
- if (qctrl->type == V4L2_CTRL_TYPE_MENU && menu_items != NULL) {
- if (menu_items[ctrl->value] == NULL ||
- menu_items[ctrl->value][0] == '\0')
- return -EINVAL;
- }
- if (qctrl->type == V4L2_CTRL_TYPE_BITMASK &&
- (ctrl->value & ~qctrl->maximum))
- return -ERANGE;
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_check);
-
/* Fill in a struct v4l2_queryctrl */
int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _step, s32 _def)
{
@@ -135,101 +105,6 @@ int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 _min, s32 _max, s32 _
}
EXPORT_SYMBOL(v4l2_ctrl_query_fill);
-/* Fill in a struct v4l2_querymenu based on the struct v4l2_queryctrl and
- the menu. The qctrl pointer may be NULL, in which case it is ignored.
- If menu_items is NULL, then the menu items are retrieved using
- v4l2_ctrl_get_menu. */
-int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
- const char * const *menu_items)
-{
- int i;
-
- qmenu->reserved = 0;
- if (menu_items == NULL)
- menu_items = v4l2_ctrl_get_menu(qmenu->id);
- if (menu_items == NULL ||
- (qctrl && (qmenu->index < qctrl->minimum || qmenu->index > qctrl->maximum)))
- return -EINVAL;
- for (i = 0; i < qmenu->index && menu_items[i]; i++) ;
- if (menu_items[i] == NULL || menu_items[i][0] == '\0')
- return -EINVAL;
- strlcpy(qmenu->name, menu_items[qmenu->index], sizeof(qmenu->name));
- return 0;
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_menu);
-
-/* Fill in a struct v4l2_querymenu based on the specified array of valid
- menu items (terminated by V4L2_CTRL_MENU_IDS_END).
- Use this if there are 'holes' in the list of valid menu items. */
-int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
-{
- const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id);
-
- qmenu->reserved = 0;
- if (menu_items == NULL || ids == NULL)
- return -EINVAL;
- while (*ids != V4L2_CTRL_MENU_IDS_END) {
- if (*ids++ == qmenu->index) {
- strlcpy(qmenu->name, menu_items[qmenu->index],
- sizeof(qmenu->name));
- return 0;
- }
- }
- return -EINVAL;
-}
-EXPORT_SYMBOL(v4l2_ctrl_query_menu_valid_items);
-
-/* ctrl_classes points to an array of u32 pointers, the last element is
- a NULL pointer. Each u32 array is a 0-terminated array of control IDs.
- Each array must be sorted low to high and belong to the same control
- class. The array of u32 pointers must also be sorted, from low class IDs
- to high class IDs.
-
- This function returns the first ID that follows after the given ID.
- When no more controls are available 0 is returned. */
-u32 v4l2_ctrl_next(const u32 * const * ctrl_classes, u32 id)
-{
- u32 ctrl_class = V4L2_CTRL_ID2CLASS(id);
- const u32 *pctrl;
-
- if (ctrl_classes == NULL)
- return 0;
-
- /* if no query is desired, then check if the ID is part of ctrl_classes */
- if ((id & V4L2_CTRL_FLAG_NEXT_CTRL) == 0) {
- /* find class */
- while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) != ctrl_class)
- ctrl_classes++;
- if (*ctrl_classes == NULL)
- return 0;
- pctrl = *ctrl_classes;
- /* find control ID */
- while (*pctrl && *pctrl != id) pctrl++;
- return *pctrl ? id : 0;
- }
- id &= V4L2_CTRL_ID_MASK;
- id++; /* select next control */
- /* find first class that matches (or is greater than) the class of
- the ID */
- while (*ctrl_classes && V4L2_CTRL_ID2CLASS(**ctrl_classes) < ctrl_class)
- ctrl_classes++;
- /* no more classes */
- if (*ctrl_classes == NULL)
- return 0;
- pctrl = *ctrl_classes;
- /* find first ctrl within the class that is >= ID */
- while (*pctrl && *pctrl < id) pctrl++;
- if (*pctrl)
- return *pctrl;
- /* we are at the end of the controls of the current class. */
- /* continue with next class if available */
- ctrl_classes++;
- if (*ctrl_classes == NULL)
- return 0;
- return **ctrl_classes;
-}
-EXPORT_SYMBOL(v4l2_ctrl_next);
-
/* I2C Helper functions */
#if IS_ENABLED(CONFIG_I2C)
diff --git a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
index e502a5f..af63543 100644
--- a/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
+++ b/drivers/media/v4l2-core/v4l2-compat-ioctl32.c
@@ -222,6 +222,9 @@ static int get_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_
static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
+ if (put_user(kp->type, &up->type))
+ return -EFAULT;
+
switch (kp->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT:
@@ -248,8 +251,7 @@ static int __put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __us
static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user *up)
{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)) ||
- put_user(kp->type, &up->type))
+ if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_format32)))
return -EFAULT;
return __put_v4l2_format32(kp, up);
}
@@ -257,8 +259,8 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
static int put_v4l2_create32(struct v4l2_create_buffers *kp, struct v4l2_create_buffers32 __user *up)
{
if (!access_ok(VERIFY_WRITE, up, sizeof(struct v4l2_create_buffers32)) ||
- copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format.fmt)))
- return -EFAULT;
+ copy_to_user(up, kp, offsetof(struct v4l2_create_buffers32, format)))
+ return -EFAULT;
return __put_v4l2_format32(&kp->format, &up->format);
}
diff --git a/drivers/media/v4l2-core/v4l2-ctrls.c b/drivers/media/v4l2-core/v4l2-ctrls.c
index 8601214..45c5b47 100644
--- a/drivers/media/v4l2-core/v4l2-ctrls.c
+++ b/drivers/media/v4l2-core/v4l2-ctrls.c
@@ -1658,10 +1658,8 @@ static int check_range(enum v4l2_ctrl_type type,
}
/* Validate a new control */
-static int validate_new(const struct v4l2_ctrl *ctrl,
- struct v4l2_ext_control *c)
+static int validate_new(const struct v4l2_ctrl *ctrl, union v4l2_ctrl_ptr p_new)
{
- union v4l2_ctrl_ptr ptr;
unsigned idx;
int err = 0;
@@ -1674,19 +1672,14 @@ static int validate_new(const struct v4l2_ctrl *ctrl,
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_BUTTON:
case V4L2_CTRL_TYPE_CTRL_CLASS:
- ptr.p_s32 = &c->value;
- return ctrl->type_ops->validate(ctrl, 0, ptr);
-
case V4L2_CTRL_TYPE_INTEGER64:
- ptr.p_s64 = &c->value64;
- return ctrl->type_ops->validate(ctrl, 0, ptr);
+ return ctrl->type_ops->validate(ctrl, 0, p_new);
default:
break;
}
}
- ptr.p = c->ptr;
- for (idx = 0; !err && idx < c->size / ctrl->elem_size; idx++)
- err = ctrl->type_ops->validate(ctrl, idx, ptr);
+ for (idx = 0; !err && idx < ctrl->elems; idx++)
+ err = ctrl->type_ops->validate(ctrl, idx, p_new);
return err;
}
@@ -3012,6 +3005,7 @@ static int validate_ctrls(struct v4l2_ext_controls *cs,
cs->error_idx = cs->count;
for (i = 0; i < cs->count; i++) {
struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+ union v4l2_ctrl_ptr p_new;
cs->error_idx = i;
@@ -3025,7 +3019,17 @@ static int validate_ctrls(struct v4l2_ext_controls *cs,
best-effort to avoid that. */
if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
return -EBUSY;
- ret = validate_new(ctrl, &cs->controls[i]);
+ /*
+ * Skip validation for now if the payload needs to be copied
+ * from userspace into kernelspace. We'll validate those later.
+ */
+ if (ctrl->is_ptr)
+ continue;
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ p_new.p_s64 = &cs->controls[i].value64;
+ else
+ p_new.p_s32 = &cs->controls[i].value;
+ ret = validate_new(ctrl, p_new);
if (ret)
return ret;
}
@@ -3120,7 +3124,11 @@ static int try_set_ext_ctrls(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
/* Copy the new caller-supplied control values.
user_to_new() sets 'is_new' to 1. */
do {
- ret = user_to_new(cs->controls + idx, helpers[idx].ctrl);
+ struct v4l2_ctrl *ctrl = helpers[idx].ctrl;
+
+ ret = user_to_new(cs->controls + idx, ctrl);
+ if (!ret && ctrl->is_ptr)
+ ret = validate_new(ctrl, ctrl->p_new);
idx = helpers[idx].next;
} while (!ret && idx);
@@ -3170,10 +3178,10 @@ int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs
EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
/* Helper function for VIDIOC_S_CTRL compatibility */
-static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
- struct v4l2_ext_control *c, u32 ch_flags)
+static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl, u32 ch_flags)
{
struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret;
int i;
/* Reset the 'is_new' flags of the cluster */
@@ -3181,8 +3189,9 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
if (master->cluster[i])
master->cluster[i]->is_new = 0;
- if (c)
- user_to_new(c, ctrl);
+ ret = validate_new(ctrl, ctrl->p_new);
+ if (ret)
+ return ret;
/* For autoclusters with volatiles that are switched from auto to
manual mode we have to update the current volatile values since
@@ -3199,15 +3208,14 @@ static int set_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
static int set_ctrl_lock(struct v4l2_fh *fh, struct v4l2_ctrl *ctrl,
struct v4l2_ext_control *c)
{
- int ret = validate_new(ctrl, c);
+ int ret;
- if (!ret) {
- v4l2_ctrl_lock(ctrl);
- ret = set_ctrl(fh, ctrl, c, 0);
- if (!ret)
- cur_to_user(c, ctrl);
- v4l2_ctrl_unlock(ctrl);
- }
+ v4l2_ctrl_lock(ctrl);
+ user_to_new(c, ctrl);
+ ret = set_ctrl(fh, ctrl, 0);
+ if (!ret)
+ cur_to_user(c, ctrl);
+ v4l2_ctrl_unlock(ctrl);
return ret;
}
@@ -3215,7 +3223,7 @@ int v4l2_s_ctrl(struct v4l2_fh *fh, struct v4l2_ctrl_handler *hdl,
struct v4l2_control *control)
{
struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
- struct v4l2_ext_control c;
+ struct v4l2_ext_control c = { control->id };
int ret;
if (ctrl == NULL || !ctrl->is_int)
@@ -3244,7 +3252,7 @@ int __v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
/* It's a driver bug if this happens. */
WARN_ON(!ctrl->is_int);
ctrl->val = val;
- return set_ctrl(NULL, ctrl, NULL, 0);
+ return set_ctrl(NULL, ctrl, 0);
}
EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl);
@@ -3255,7 +3263,7 @@ int __v4l2_ctrl_s_ctrl_int64(struct v4l2_ctrl *ctrl, s64 val)
/* It's a driver bug if this happens. */
WARN_ON(ctrl->is_ptr || ctrl->type != V4L2_CTRL_TYPE_INTEGER64);
*ctrl->p_new.p_s64 = val;
- return set_ctrl(NULL, ctrl, NULL, 0);
+ return set_ctrl(NULL, ctrl, 0);
}
EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_int64);
@@ -3266,7 +3274,7 @@ int __v4l2_ctrl_s_ctrl_string(struct v4l2_ctrl *ctrl, const char *s)
/* It's a driver bug if this happens. */
WARN_ON(ctrl->type != V4L2_CTRL_TYPE_STRING);
strlcpy(ctrl->p_new.p_char, s, ctrl->maximum + 1);
- return set_ctrl(NULL, ctrl, NULL, 0);
+ return set_ctrl(NULL, ctrl, 0);
}
EXPORT_SYMBOL(__v4l2_ctrl_s_ctrl_string);
@@ -3289,8 +3297,8 @@ EXPORT_SYMBOL(v4l2_ctrl_notify);
int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
s64 min, s64 max, u64 step, s64 def)
{
+ bool changed;
int ret;
- struct v4l2_ext_control c;
lockdep_assert_held(ctrl->handler->lock);
@@ -3317,11 +3325,20 @@ int __v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
ctrl->maximum = max;
ctrl->step = step;
ctrl->default_value = def;
- c.value = *ctrl->p_cur.p_s32;
- if (validate_new(ctrl, &c))
- c.value = def;
- if (c.value != *ctrl->p_cur.p_s32)
- ret = set_ctrl(NULL, ctrl, &c, V4L2_EVENT_CTRL_CH_RANGE);
+ cur_to_new(ctrl);
+ if (validate_new(ctrl, ctrl->p_new)) {
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ *ctrl->p_new.p_s64 = def;
+ else
+ *ctrl->p_new.p_s32 = def;
+ }
+
+ if (ctrl->type == V4L2_CTRL_TYPE_INTEGER64)
+ changed = *ctrl->p_new.p_s64 != *ctrl->p_cur.p_s64;
+ else
+ changed = *ctrl->p_new.p_s32 != *ctrl->p_cur.p_s32;
+ if (changed)
+ ret = set_ctrl(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
else
send_event(NULL, ctrl, V4L2_EVENT_CTRL_CH_RANGE);
return ret;
diff --git a/drivers/media/v4l2-core/v4l2-dev.c b/drivers/media/v4l2-core/v4l2-dev.c
index 33617c3..9aa530a 100644
--- a/drivers/media/v4l2-core/v4l2-dev.c
+++ b/drivers/media/v4l2-core/v4l2-dev.c
@@ -194,7 +194,7 @@ static void v4l2_device_release(struct device *cd)
mutex_unlock(&videodev_lock);
#if defined(CONFIG_MEDIA_CONTROLLER)
- if (v4l2_dev && v4l2_dev->mdev &&
+ if (v4l2_dev->mdev &&
vdev->vfl_type != VFL_TYPE_SUBDEV)
media_device_unregister_entity(&vdev->entity);
#endif
@@ -207,7 +207,7 @@ static void v4l2_device_release(struct device *cd)
* TODO: In the long run all drivers that use v4l2_device should use the
* v4l2_device release callback. This check will then be unnecessary.
*/
- if (v4l2_dev && v4l2_dev->release == NULL)
+ if (v4l2_dev->release == NULL)
v4l2_dev = NULL;
/* Release video_device and perform other
@@ -360,27 +360,22 @@ static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
* hack but it will have to do for those drivers that are not
* yet converted to use unlocked_ioctl.
*
- * There are two options: if the driver implements struct
- * v4l2_device, then the lock defined there is used to
- * serialize the ioctls. Otherwise the v4l2 core lock defined
- * below is used. This lock is really bad since it serializes
- * completely independent devices.
+ * All drivers implement struct v4l2_device, so we use the
+ * lock defined there to serialize the ioctls.
*
- * Both variants suffer from the same problem: if the driver
- * sleeps, then it blocks all ioctls since the lock is still
- * held. This is very common for VIDIOC_DQBUF since that
- * normally waits for a frame to arrive. As a result any other
- * ioctl calls will proceed very, very slowly since each call
- * will have to wait for the VIDIOC_QBUF to finish. Things that
- * should take 0.01s may now take 10-20 seconds.
+ * However, if the driver sleeps, then it blocks all ioctls
+ * since the lock is still held. This is very common for
+ * VIDIOC_DQBUF since that normally waits for a frame to arrive.
+ * As a result any other ioctl calls will proceed very, very
+ * slowly since each call will have to wait for the VIDIOC_QBUF
+ * to finish. Things that should take 0.01s may now take 10-20
+ * seconds.
*
* The workaround is to *not* take the lock for VIDIOC_DQBUF.
* This actually works OK for videobuf-based drivers, since
* videobuf will take its own internal lock.
*/
- static DEFINE_MUTEX(v4l2_ioctl_mutex);
- struct mutex *m = vdev->v4l2_dev ?
- &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
+ struct mutex *m = &vdev->v4l2_dev->ioctl_lock;
if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
return -ERESTARTSYS;
@@ -938,12 +933,11 @@ int __video_register_device(struct video_device *vdev, int type, int nr,
name_base, nr, video_device_node_name(vdev));
/* Increase v4l2_device refcount */
- if (vdev->v4l2_dev)
- v4l2_device_get(vdev->v4l2_dev);
+ v4l2_device_get(vdev->v4l2_dev);
#if defined(CONFIG_MEDIA_CONTROLLER)
/* Part 5: Register the entity. */
- if (vdev->v4l2_dev && vdev->v4l2_dev->mdev &&
+ if (vdev->v4l2_dev->mdev &&
vdev->vfl_type != VFL_TYPE_SUBDEV) {
vdev->entity.type = MEDIA_ENT_T_DEVNODE_V4L;
vdev->entity.name = vdev->name;
diff --git a/drivers/media/v4l2-core/v4l2-ioctl.c b/drivers/media/v4l2-core/v4l2-ioctl.c
index 9ccb19a..7565871 100644
--- a/drivers/media/v4l2-core/v4l2-ioctl.c
+++ b/drivers/media/v4l2-core/v4l2-ioctl.c
@@ -257,7 +257,7 @@ static void v4l_print_format(const void *arg, bool write_only)
pr_cont(", width=%u, height=%u, "
"pixelformat=%c%c%c%c, field=%s, "
"bytesperline=%u, sizeimage=%u, colorspace=%d, "
- "flags %u\n",
+ "flags %x, ycbcr_enc=%u, quantization=%u\n",
pix->width, pix->height,
(pix->pixelformat & 0xff),
(pix->pixelformat >> 8) & 0xff,
@@ -265,21 +265,24 @@ static void v4l_print_format(const void *arg, bool write_only)
(pix->pixelformat >> 24) & 0xff,
prt_names(pix->field, v4l2_field_names),
pix->bytesperline, pix->sizeimage,
- pix->colorspace, pix->flags);
+ pix->colorspace, pix->flags, pix->ycbcr_enc,
+ pix->quantization);
break;
case V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE:
case V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE:
mp = &p->fmt.pix_mp;
pr_cont(", width=%u, height=%u, "
"format=%c%c%c%c, field=%s, "
- "colorspace=%d, num_planes=%u\n",
+ "colorspace=%d, num_planes=%u, flags=%x, "
+ "ycbcr_enc=%u, quantization=%u\n",
mp->width, mp->height,
(mp->pixelformat & 0xff),
(mp->pixelformat >> 8) & 0xff,
(mp->pixelformat >> 16) & 0xff,
(mp->pixelformat >> 24) & 0xff,
prt_names(mp->field, v4l2_field_names),
- mp->colorspace, mp->num_planes);
+ mp->colorspace, mp->num_planes, mp->flags,
+ mp->ycbcr_enc, mp->quantization);
for (i = 0; i < mp->num_planes; i++)
printk(KERN_DEBUG "plane %u: bytesperline=%u sizeimage=%u\n", i,
mp->plane_fmt[i].bytesperline,
@@ -1040,7 +1043,7 @@ static int v4l_g_priority(const struct v4l2_ioctl_ops *ops,
if (ops->vidioc_g_priority)
return ops->vidioc_g_priority(file, fh, arg);
vfd = video_devdata(file);
- *p = v4l2_prio_max(&vfd->v4l2_dev->prio);
+ *p = v4l2_prio_max(vfd->prio);
return 0;
}
@@ -1055,7 +1058,7 @@ static int v4l_s_priority(const struct v4l2_ioctl_ops *ops,
return ops->vidioc_s_priority(file, fh, *p);
vfd = video_devdata(file);
vfh = file->private_data;
- return v4l2_prio_change(&vfd->v4l2_dev->prio, &vfh->prio, *p);
+ return v4l2_prio_change(vfd->prio, &vfh->prio, *p);
}
static int v4l_enuminput(const struct v4l2_ioctl_ops *ops,
diff --git a/drivers/media/v4l2-core/videobuf-core.c b/drivers/media/v4l2-core/videobuf-core.c
index b91a266..926836d 100644
--- a/drivers/media/v4l2-core/videobuf-core.c
+++ b/drivers/media/v4l2-core/videobuf-core.c
@@ -51,6 +51,8 @@ MODULE_LICENSE("GPL");
#define CALL(q, f, arg...) \
((q->int_ops->f) ? q->int_ops->f(arg) : 0)
+#define CALLPTR(q, f, arg...) \
+ ((q->int_ops->f) ? q->int_ops->f(arg) : NULL)
struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
{
@@ -831,7 +833,7 @@ static int __videobuf_copy_to_user(struct videobuf_queue *q,
char __user *data, size_t count,
int nonblocking)
{
- void *vaddr = CALL(q, vaddr, buf);
+ void *vaddr = CALLPTR(q, vaddr, buf);
/* copy to userspace */
if (count > buf->size - q->read_off)
@@ -848,7 +850,7 @@ static int __videobuf_copy_stream(struct videobuf_queue *q,
char __user *data, size_t count, size_t pos,
int vbihack, int nonblocking)
{
- unsigned int *fc = CALL(q, vaddr, buf);
+ unsigned int *fc = CALLPTR(q, vaddr, buf);
if (vbihack) {
/* dirty, undocumented hack -- pass the frame counter
diff --git a/drivers/media/v4l2-core/videobuf2-core.c b/drivers/media/v4l2-core/videobuf2-core.c
index f2e43de..d09a891 100644
--- a/drivers/media/v4l2-core/videobuf2-core.c
+++ b/drivers/media/v4l2-core/videobuf2-core.c
@@ -189,6 +189,8 @@ static void __vb2_queue_cancel(struct vb2_queue *q);
static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
{
struct vb2_queue *q = vb->vb2_queue;
+ enum dma_data_direction dma_dir =
+ V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
void *mem_priv;
int plane;
@@ -200,7 +202,7 @@ static int __vb2_buf_mem_alloc(struct vb2_buffer *vb)
unsigned long size = PAGE_ALIGN(q->plane_sizes[plane]);
mem_priv = call_ptr_memop(vb, alloc, q->alloc_ctx[plane],
- size, q->gfp_flags);
+ size, dma_dir, q->gfp_flags);
if (IS_ERR_OR_NULL(mem_priv))
goto free;
@@ -1358,7 +1360,8 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
void *mem_priv;
unsigned int plane;
int ret;
- int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+ enum dma_data_direction dma_dir =
+ V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
bool reacquired = vb->planes[0].mem_priv == NULL;
memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
@@ -1400,7 +1403,7 @@ static int __qbuf_userptr(struct vb2_buffer *vb, const struct v4l2_buffer *b)
/* Acquire each plane's memory */
mem_priv = call_ptr_memop(vb, get_userptr, q->alloc_ctx[plane],
planes[plane].m.userptr,
- planes[plane].length, write);
+ planes[plane].length, dma_dir);
if (IS_ERR_OR_NULL(mem_priv)) {
dprintk(1, "failed acquiring userspace "
"memory for plane %d\n", plane);
@@ -1461,7 +1464,8 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
void *mem_priv;
unsigned int plane;
int ret;
- int write = !V4L2_TYPE_IS_OUTPUT(q->type);
+ enum dma_data_direction dma_dir =
+ V4L2_TYPE_IS_OUTPUT(q->type) ? DMA_TO_DEVICE : DMA_FROM_DEVICE;
bool reacquired = vb->planes[0].mem_priv == NULL;
memset(planes, 0, sizeof(planes[0]) * vb->num_planes);
@@ -1509,7 +1513,7 @@ static int __qbuf_dmabuf(struct vb2_buffer *vb, const struct v4l2_buffer *b)
/* Acquire each plane's memory */
mem_priv = call_ptr_memop(vb, attach_dmabuf, q->alloc_ctx[plane],
- dbuf, planes[plane].length, write);
+ dbuf, planes[plane].length, dma_dir);
if (IS_ERR(mem_priv)) {
dprintk(1, "failed to attach dmabuf\n");
ret = PTR_ERR(mem_priv);
@@ -3385,14 +3389,14 @@ int _vb2_fop_release(struct file *file, struct mutex *lock)
{
struct video_device *vdev = video_devdata(file);
+ if (lock)
+ mutex_lock(lock);
if (file->private_data == vdev->queue->owner) {
- if (lock)
- mutex_lock(lock);
vb2_queue_release(vdev->queue);
vdev->queue->owner = NULL;
- if (lock)
- mutex_unlock(lock);
}
+ if (lock)
+ mutex_unlock(lock);
return v4l2_fh_release(file);
}
EXPORT_SYMBOL_GPL(_vb2_fop_release);
@@ -3455,27 +3459,16 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
struct video_device *vdev = video_devdata(file);
struct vb2_queue *q = vdev->queue;
struct mutex *lock = q->lock ? q->lock : vdev->lock;
- unsigned long req_events = poll_requested_events(wait);
unsigned res;
void *fileio;
- bool must_lock = false;
-
- /* Try to be smart: only lock if polling might start fileio,
- otherwise locking will only introduce unwanted delays. */
- if (q->num_buffers == 0 && !vb2_fileio_is_active(q)) {
- if (!V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_READ) &&
- (req_events & (POLLIN | POLLRDNORM)))
- must_lock = true;
- else if (V4L2_TYPE_IS_OUTPUT(q->type) && (q->io_modes & VB2_WRITE) &&
- (req_events & (POLLOUT | POLLWRNORM)))
- must_lock = true;
- }
- /* If locking is needed, but this helper doesn't know how, then you
- shouldn't be using this helper but you should write your own. */
- WARN_ON(must_lock && !lock);
+ /*
+ * If this helper doesn't know how to lock, then you shouldn't be using
+ * it but you should write your own.
+ */
+ WARN_ON(!lock);
- if (must_lock && lock && mutex_lock_interruptible(lock))
+ if (lock && mutex_lock_interruptible(lock))
return POLLERR;
fileio = q->fileio;
@@ -3483,9 +3476,9 @@ unsigned int vb2_fop_poll(struct file *file, poll_table *wait)
res = vb2_poll(vdev->queue, file, wait);
/* If fileio was started, then we have a new queue owner. */
- if (must_lock && !fileio && q->fileio)
+ if (!fileio && q->fileio)
q->owner = file->private_data;
- if (must_lock && lock)
+ if (lock)
mutex_unlock(lock);
return res;
}
diff --git a/drivers/media/v4l2-core/videobuf2-dma-contig.c b/drivers/media/v4l2-core/videobuf2-dma-contig.c
index 4a02ade..b481d20 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-contig.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-contig.c
@@ -155,7 +155,8 @@ static void vb2_dc_put(void *buf_priv)
kfree(buf);
}
-static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
+static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size,
+ enum dma_data_direction dma_dir, gfp_t gfp_flags)
{
struct vb2_dc_conf *conf = alloc_ctx;
struct device *dev = conf->dev;
@@ -176,6 +177,7 @@ static void *vb2_dc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
/* Prevent the device from being released while the buffer is used */
buf->dev = get_device(dev);
buf->size = size;
+ buf->dma_dir = dma_dir;
buf->handler.refcount = &buf->refcount;
buf->handler.put = vb2_dc_put;
@@ -229,7 +231,7 @@ static int vb2_dc_mmap(void *buf_priv, struct vm_area_struct *vma)
struct vb2_dc_attachment {
struct sg_table sgt;
- enum dma_data_direction dir;
+ enum dma_data_direction dma_dir;
};
static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
@@ -264,7 +266,7 @@ static int vb2_dc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
wr = sg_next(wr);
}
- attach->dir = DMA_NONE;
+ attach->dma_dir = DMA_NONE;
dbuf_attach->priv = attach;
return 0;
@@ -282,16 +284,16 @@ static void vb2_dc_dmabuf_ops_detach(struct dma_buf *dbuf,
sgt = &attach->sgt;
/* release the scatterlist cache */
- if (attach->dir != DMA_NONE)
+ if (attach->dma_dir != DMA_NONE)
dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dir);
+ attach->dma_dir);
sg_free_table(sgt);
kfree(attach);
db_attach->priv = NULL;
}
static struct sg_table *vb2_dc_dmabuf_ops_map(
- struct dma_buf_attachment *db_attach, enum dma_data_direction dir)
+ struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
{
struct vb2_dc_attachment *attach = db_attach->priv;
/* stealing dmabuf mutex to serialize map/unmap operations */
@@ -303,27 +305,27 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
sgt = &attach->sgt;
/* return previously mapped sg table */
- if (attach->dir == dir) {
+ if (attach->dma_dir == dma_dir) {
mutex_unlock(lock);
return sgt;
}
/* release any previous cache */
- if (attach->dir != DMA_NONE) {
+ if (attach->dma_dir != DMA_NONE) {
dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
- attach->dir);
- attach->dir = DMA_NONE;
+ attach->dma_dir);
+ attach->dma_dir = DMA_NONE;
}
/* mapping to the client with new direction */
- ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dir);
+ ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir);
if (ret <= 0) {
pr_err("failed to map scatterlist\n");
mutex_unlock(lock);
return ERR_PTR(-EIO);
}
- attach->dir = dir;
+ attach->dma_dir = dma_dir;
mutex_unlock(lock);
@@ -331,7 +333,7 @@ static struct sg_table *vb2_dc_dmabuf_ops_map(
}
static void vb2_dc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
- struct sg_table *sgt, enum dma_data_direction dir)
+ struct sg_table *sgt, enum dma_data_direction dma_dir)
{
/* nothing to be done here */
}
@@ -460,7 +462,8 @@ static int vb2_dc_get_user_pfn(unsigned long start, int n_pages,
}
static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
- int n_pages, struct vm_area_struct *vma, int write)
+ int n_pages, struct vm_area_struct *vma,
+ enum dma_data_direction dma_dir)
{
if (vma_is_io(vma)) {
unsigned int i;
@@ -482,7 +485,7 @@ static int vb2_dc_get_user_pages(unsigned long start, struct page **pages,
int n;
n = get_user_pages(current, current->mm, start & PAGE_MASK,
- n_pages, write, 1, pages, NULL);
+ n_pages, dma_dir == DMA_FROM_DEVICE, 1, pages, NULL);
/* negative error means that no page was pinned */
n = max(n, 0);
if (n != n_pages) {
@@ -508,7 +511,15 @@ static void vb2_dc_put_userptr(void *buf_priv)
struct sg_table *sgt = buf->dma_sgt;
if (sgt) {
- dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
+ /*
+ * No need to sync to CPU, it's already synced to the CPU
+ * since the finish() memop will have been called before this.
+ */
+ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
+ buf->dma_dir, &attrs);
if (!vma_is_io(buf->vma))
vb2_dc_sgt_foreach_page(sgt, vb2_dc_put_dirty_page);
@@ -551,7 +562,7 @@ static inline dma_addr_t vb2_dc_pfn_to_dma(struct device *dev, unsigned long pfn
#endif
static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
- unsigned long size, int write)
+ unsigned long size, enum dma_data_direction dma_dir)
{
struct vb2_dc_conf *conf = alloc_ctx;
struct vb2_dc_buf *buf;
@@ -565,6 +576,9 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
struct sg_table *sgt;
unsigned long contig_size;
unsigned long dma_align = dma_get_cache_alignment();
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
/* Only cache aligned DMA transfers are reliable */
if (!IS_ALIGNED(vaddr | size, dma_align)) {
@@ -582,7 +596,7 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
return ERR_PTR(-ENOMEM);
buf->dev = conf->dev;
- buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ buf->dma_dir = dma_dir;
start = vaddr & PAGE_MASK;
offset = vaddr & ~PAGE_MASK;
@@ -618,7 +632,8 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
}
/* extract page list from userspace mapping */
- ret = vb2_dc_get_user_pages(start, pages, n_pages, vma, write);
+ ret = vb2_dc_get_user_pages(start, pages, n_pages, vma,
+ dma_dir == DMA_FROM_DEVICE);
if (ret) {
unsigned long pfn;
if (vb2_dc_get_user_pfn(start, n_pages, vma, &pfn) == 0) {
@@ -650,8 +665,12 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
kfree(pages);
pages = NULL;
- sgt->nents = dma_map_sg(buf->dev, sgt->sgl, sgt->orig_nents,
- buf->dma_dir);
+ /*
+ * No need to sync to the device, this will happen later when the
+ * prepare() memop is called.
+ */
+ sgt->nents = dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
+ buf->dma_dir, &attrs);
if (sgt->nents <= 0) {
pr_err("failed to map scatterlist\n");
ret = -EIO;
@@ -673,7 +692,8 @@ static void *vb2_dc_get_userptr(void *alloc_ctx, unsigned long vaddr,
return buf;
fail_map_sg:
- dma_unmap_sg(buf->dev, sgt->sgl, sgt->orig_nents, buf->dma_dir);
+ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->orig_nents,
+ buf->dma_dir, &attrs);
fail_sgt_init:
if (!vma_is_io(buf->vma))
@@ -782,7 +802,7 @@ static void vb2_dc_detach_dmabuf(void *mem_priv)
}
static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
- unsigned long size, int write)
+ unsigned long size, enum dma_data_direction dma_dir)
{
struct vb2_dc_conf *conf = alloc_ctx;
struct vb2_dc_buf *buf;
@@ -804,7 +824,7 @@ static void *vb2_dc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
return dba;
}
- buf->dma_dir = write ? DMA_FROM_DEVICE : DMA_TO_DEVICE;
+ buf->dma_dir = dma_dir;
buf->size = size;
buf->db_attach = dba;
@@ -850,7 +870,8 @@ EXPORT_SYMBOL_GPL(vb2_dma_contig_init_ctx);
void vb2_dma_contig_cleanup_ctx(void *alloc_ctx)
{
- kfree(alloc_ctx);
+ if (!IS_ERR_OR_NULL(alloc_ctx))
+ kfree(alloc_ctx);
}
EXPORT_SYMBOL_GPL(vb2_dma_contig_cleanup_ctx);
diff --git a/drivers/media/v4l2-core/videobuf2-dma-sg.c b/drivers/media/v4l2-core/videobuf2-dma-sg.c
index 9b163a4..b1838ab 100644
--- a/drivers/media/v4l2-core/videobuf2-dma-sg.c
+++ b/drivers/media/v4l2-core/videobuf2-dma-sg.c
@@ -30,17 +30,30 @@ module_param(debug, int, 0644);
printk(KERN_DEBUG "vb2-dma-sg: " fmt, ## arg); \
} while (0)
+struct vb2_dma_sg_conf {
+ struct device *dev;
+};
+
struct vb2_dma_sg_buf {
+ struct device *dev;
void *vaddr;
struct page **pages;
- int write;
int offset;
+ enum dma_data_direction dma_dir;
struct sg_table sg_table;
+ /*
+ * This will point to sg_table when used with the MMAP or USERPTR
+ * memory model, and to the dma_buf sglist when used with the
+ * DMABUF memory model.
+ */
+ struct sg_table *dma_sgt;
size_t size;
unsigned int num_pages;
atomic_t refcount;
struct vb2_vmarea_handler handler;
struct vm_area_struct *vma;
+
+ struct dma_buf_attachment *db_attach;
};
static void vb2_dma_sg_put(void *buf_priv);
@@ -86,22 +99,31 @@ static int vb2_dma_sg_alloc_compacted(struct vb2_dma_sg_buf *buf,
return 0;
}
-static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
+static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size,
+ enum dma_data_direction dma_dir, gfp_t gfp_flags)
{
+ struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
+ struct sg_table *sgt;
int ret;
int num_pages;
+ DEFINE_DMA_ATTRS(attrs);
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
+
+ if (WARN_ON(alloc_ctx == NULL))
+ return NULL;
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
buf->vaddr = NULL;
- buf->write = 0;
+ buf->dma_dir = dma_dir;
buf->offset = 0;
buf->size = size;
/* size is already page aligned */
buf->num_pages = size >> PAGE_SHIFT;
+ buf->dma_sgt = &buf->sg_table;
buf->pages = kzalloc(buf->num_pages * sizeof(struct page *),
GFP_KERNEL);
@@ -112,11 +134,23 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla
if (ret)
goto fail_pages_alloc;
- ret = sg_alloc_table_from_pages(&buf->sg_table, buf->pages,
+ ret = sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
buf->num_pages, 0, size, GFP_KERNEL);
if (ret)
goto fail_table_alloc;
+ /* Prevent the device from being released while the buffer is used */
+ buf->dev = get_device(conf->dev);
+
+ sgt = &buf->sg_table;
+ /*
+ * No need to sync to the device, this will happen later when the
+ * prepare() memop is called.
+ */
+ if (dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->nents,
+ buf->dma_dir, &attrs) == 0)
+ goto fail_map;
+
buf->handler.refcount = &buf->refcount;
buf->handler.put = vb2_dma_sg_put;
buf->handler.arg = buf;
@@ -127,6 +161,9 @@ static void *vb2_dma_sg_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fla
__func__, buf->num_pages);
return buf;
+fail_map:
+ put_device(buf->dev);
+ sg_free_table(buf->dma_sgt);
fail_table_alloc:
num_pages = buf->num_pages;
while (num_pages--)
@@ -141,42 +178,81 @@ fail_pages_array_alloc:
static void vb2_dma_sg_put(void *buf_priv)
{
struct vb2_dma_sg_buf *buf = buf_priv;
+ struct sg_table *sgt = &buf->sg_table;
int i = buf->num_pages;
if (atomic_dec_and_test(&buf->refcount)) {
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
dprintk(1, "%s: Freeing buffer of %d pages\n", __func__,
buf->num_pages);
+ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->nents,
+ buf->dma_dir, &attrs);
if (buf->vaddr)
vm_unmap_ram(buf->vaddr, buf->num_pages);
- sg_free_table(&buf->sg_table);
+ sg_free_table(buf->dma_sgt);
while (--i >= 0)
__free_page(buf->pages[i]);
kfree(buf->pages);
+ put_device(buf->dev);
kfree(buf);
}
}
+static void vb2_dma_sg_prepare(void *buf_priv)
+{
+ struct vb2_dma_sg_buf *buf = buf_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ /* DMABUF exporter will flush the cache for us */
+ if (buf->db_attach)
+ return;
+
+ dma_sync_sg_for_device(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+}
+
+static void vb2_dma_sg_finish(void *buf_priv)
+{
+ struct vb2_dma_sg_buf *buf = buf_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ /* DMABUF exporter will flush the cache for us */
+ if (buf->db_attach)
+ return;
+
+ dma_sync_sg_for_cpu(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir);
+}
+
static inline int vma_is_io(struct vm_area_struct *vma)
{
return !!(vma->vm_flags & (VM_IO | VM_PFNMAP));
}
static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
- unsigned long size, int write)
+ unsigned long size,
+ enum dma_data_direction dma_dir)
{
+ struct vb2_dma_sg_conf *conf = alloc_ctx;
struct vb2_dma_sg_buf *buf;
unsigned long first, last;
int num_pages_from_user;
struct vm_area_struct *vma;
+ struct sg_table *sgt;
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
buf = kzalloc(sizeof *buf, GFP_KERNEL);
if (!buf)
return NULL;
buf->vaddr = NULL;
- buf->write = write;
+ buf->dev = conf->dev;
+ buf->dma_dir = dma_dir;
buf->offset = vaddr & ~PAGE_MASK;
buf->size = size;
+ buf->dma_sgt = &buf->sg_table;
first = (vaddr & PAGE_MASK) >> PAGE_SHIFT;
last = ((vaddr + size - 1) & PAGE_MASK) >> PAGE_SHIFT;
@@ -221,7 +297,7 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
num_pages_from_user = get_user_pages(current, current->mm,
vaddr & PAGE_MASK,
buf->num_pages,
- write,
+ buf->dma_dir == DMA_FROM_DEVICE,
1, /* force */
buf->pages,
NULL);
@@ -229,12 +305,22 @@ static void *vb2_dma_sg_get_userptr(void *alloc_ctx, unsigned long vaddr,
if (num_pages_from_user != buf->num_pages)
goto userptr_fail_get_user_pages;
- if (sg_alloc_table_from_pages(&buf->sg_table, buf->pages,
+ if (sg_alloc_table_from_pages(buf->dma_sgt, buf->pages,
buf->num_pages, buf->offset, size, 0))
goto userptr_fail_alloc_table_from_pages;
+ sgt = &buf->sg_table;
+ /*
+ * No need to sync to the device, this will happen later when the
+ * prepare() memop is called.
+ */
+ if (dma_map_sg_attrs(buf->dev, sgt->sgl, sgt->nents,
+ buf->dma_dir, &attrs) == 0)
+ goto userptr_fail_map;
return buf;
+userptr_fail_map:
+ sg_free_table(&buf->sg_table);
userptr_fail_alloc_table_from_pages:
userptr_fail_get_user_pages:
dprintk(1, "get_user_pages requested/got: %d/%d]\n",
@@ -257,15 +343,20 @@ userptr_fail_alloc_pages:
static void vb2_dma_sg_put_userptr(void *buf_priv)
{
struct vb2_dma_sg_buf *buf = buf_priv;
+ struct sg_table *sgt = &buf->sg_table;
int i = buf->num_pages;
+ DEFINE_DMA_ATTRS(attrs);
+
+ dma_set_attr(DMA_ATTR_SKIP_CPU_SYNC, &attrs);
dprintk(1, "%s: Releasing userspace buffer of %d pages\n",
__func__, buf->num_pages);
+ dma_unmap_sg_attrs(buf->dev, sgt->sgl, sgt->nents, buf->dma_dir, &attrs);
if (buf->vaddr)
vm_unmap_ram(buf->vaddr, buf->num_pages);
- sg_free_table(&buf->sg_table);
+ sg_free_table(buf->dma_sgt);
while (--i >= 0) {
- if (buf->write)
+ if (buf->dma_dir == DMA_FROM_DEVICE)
set_page_dirty_lock(buf->pages[i]);
if (!vma_is_io(buf->vma))
put_page(buf->pages[i]);
@@ -281,14 +372,16 @@ static void *vb2_dma_sg_vaddr(void *buf_priv)
BUG_ON(!buf);
- if (!buf->vaddr)
- buf->vaddr = vm_map_ram(buf->pages,
- buf->num_pages,
- -1,
- PAGE_KERNEL);
+ if (!buf->vaddr) {
+ if (buf->db_attach)
+ buf->vaddr = dma_buf_vmap(buf->db_attach->dmabuf);
+ else
+ buf->vaddr = vm_map_ram(buf->pages,
+ buf->num_pages, -1, PAGE_KERNEL);
+ }
/* add offset in case userptr is not page-aligned */
- return buf->vaddr + buf->offset;
+ return buf->vaddr ? buf->vaddr + buf->offset : NULL;
}
static unsigned int vb2_dma_sg_num_users(void *buf_priv)
@@ -335,11 +428,279 @@ static int vb2_dma_sg_mmap(void *buf_priv, struct vm_area_struct *vma)
return 0;
}
+/*********************************************/
+/* DMABUF ops for exporters */
+/*********************************************/
+
+struct vb2_dma_sg_attachment {
+ struct sg_table sgt;
+ enum dma_data_direction dma_dir;
+};
+
+static int vb2_dma_sg_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
+ struct dma_buf_attachment *dbuf_attach)
+{
+ struct vb2_dma_sg_attachment *attach;
+ unsigned int i;
+ struct scatterlist *rd, *wr;
+ struct sg_table *sgt;
+ struct vb2_dma_sg_buf *buf = dbuf->priv;
+ int ret;
+
+ attach = kzalloc(sizeof(*attach), GFP_KERNEL);
+ if (!attach)
+ return -ENOMEM;
+
+ sgt = &attach->sgt;
+ /* Copy the buf->base_sgt scatter list to the attachment, as we can't
+ * map the same scatter list to multiple attachments at the same time.
+ */
+ ret = sg_alloc_table(sgt, buf->dma_sgt->orig_nents, GFP_KERNEL);
+ if (ret) {
+ kfree(attach);
+ return -ENOMEM;
+ }
+
+ rd = buf->dma_sgt->sgl;
+ wr = sgt->sgl;
+ for (i = 0; i < sgt->orig_nents; ++i) {
+ sg_set_page(wr, sg_page(rd), rd->length, rd->offset);
+ rd = sg_next(rd);
+ wr = sg_next(wr);
+ }
+
+ attach->dma_dir = DMA_NONE;
+ dbuf_attach->priv = attach;
+
+ return 0;
+}
+
+static void vb2_dma_sg_dmabuf_ops_detach(struct dma_buf *dbuf,
+ struct dma_buf_attachment *db_attach)
+{
+ struct vb2_dma_sg_attachment *attach = db_attach->priv;
+ struct sg_table *sgt;
+
+ if (!attach)
+ return;
+
+ sgt = &attach->sgt;
+
+ /* release the scatterlist cache */
+ if (attach->dma_dir != DMA_NONE)
+ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
+ attach->dma_dir);
+ sg_free_table(sgt);
+ kfree(attach);
+ db_attach->priv = NULL;
+}
+
+static struct sg_table *vb2_dma_sg_dmabuf_ops_map(
+ struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
+{
+ struct vb2_dma_sg_attachment *attach = db_attach->priv;
+ /* stealing dmabuf mutex to serialize map/unmap operations */
+ struct mutex *lock = &db_attach->dmabuf->lock;
+ struct sg_table *sgt;
+ int ret;
+
+ mutex_lock(lock);
+
+ sgt = &attach->sgt;
+ /* return previously mapped sg table */
+ if (attach->dma_dir == dma_dir) {
+ mutex_unlock(lock);
+ return sgt;
+ }
+
+ /* release any previous cache */
+ if (attach->dma_dir != DMA_NONE) {
+ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
+ attach->dma_dir);
+ attach->dma_dir = DMA_NONE;
+ }
+
+ /* mapping to the client with new direction */
+ ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir);
+ if (ret <= 0) {
+ pr_err("failed to map scatterlist\n");
+ mutex_unlock(lock);
+ return ERR_PTR(-EIO);
+ }
+
+ attach->dma_dir = dma_dir;
+
+ mutex_unlock(lock);
+
+ return sgt;
+}
+
+static void vb2_dma_sg_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
+ struct sg_table *sgt, enum dma_data_direction dma_dir)
+{
+ /* nothing to be done here */
+}
+
+static void vb2_dma_sg_dmabuf_ops_release(struct dma_buf *dbuf)
+{
+ /* drop reference obtained in vb2_dma_sg_get_dmabuf */
+ vb2_dma_sg_put(dbuf->priv);
+}
+
+static void *vb2_dma_sg_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum)
+{
+ struct vb2_dma_sg_buf *buf = dbuf->priv;
+
+ return buf->vaddr ? buf->vaddr + pgnum * PAGE_SIZE : NULL;
+}
+
+static void *vb2_dma_sg_dmabuf_ops_vmap(struct dma_buf *dbuf)
+{
+ struct vb2_dma_sg_buf *buf = dbuf->priv;
+
+ return vb2_dma_sg_vaddr(buf);
+}
+
+static int vb2_dma_sg_dmabuf_ops_mmap(struct dma_buf *dbuf,
+ struct vm_area_struct *vma)
+{
+ return vb2_dma_sg_mmap(dbuf->priv, vma);
+}
+
+static struct dma_buf_ops vb2_dma_sg_dmabuf_ops = {
+ .attach = vb2_dma_sg_dmabuf_ops_attach,
+ .detach = vb2_dma_sg_dmabuf_ops_detach,
+ .map_dma_buf = vb2_dma_sg_dmabuf_ops_map,
+ .unmap_dma_buf = vb2_dma_sg_dmabuf_ops_unmap,
+ .kmap = vb2_dma_sg_dmabuf_ops_kmap,
+ .kmap_atomic = vb2_dma_sg_dmabuf_ops_kmap,
+ .vmap = vb2_dma_sg_dmabuf_ops_vmap,
+ .mmap = vb2_dma_sg_dmabuf_ops_mmap,
+ .release = vb2_dma_sg_dmabuf_ops_release,
+};
+
+static struct dma_buf *vb2_dma_sg_get_dmabuf(void *buf_priv, unsigned long flags)
+{
+ struct vb2_dma_sg_buf *buf = buf_priv;
+ struct dma_buf *dbuf;
+
+ if (WARN_ON(!buf->dma_sgt))
+ return NULL;
+
+ dbuf = dma_buf_export(buf, &vb2_dma_sg_dmabuf_ops, buf->size, flags, NULL);
+ if (IS_ERR(dbuf))
+ return NULL;
+
+ /* dmabuf keeps reference to vb2 buffer */
+ atomic_inc(&buf->refcount);
+
+ return dbuf;
+}
+
+/*********************************************/
+/* callbacks for DMABUF buffers */
+/*********************************************/
+
+static int vb2_dma_sg_map_dmabuf(void *mem_priv)
+{
+ struct vb2_dma_sg_buf *buf = mem_priv;
+ struct sg_table *sgt;
+
+ if (WARN_ON(!buf->db_attach)) {
+ pr_err("trying to pin a non attached buffer\n");
+ return -EINVAL;
+ }
+
+ if (WARN_ON(buf->dma_sgt)) {
+ pr_err("dmabuf buffer is already pinned\n");
+ return 0;
+ }
+
+ /* get the associated scatterlist for this buffer */
+ sgt = dma_buf_map_attachment(buf->db_attach, buf->dma_dir);
+ if (IS_ERR(sgt)) {
+ pr_err("Error getting dmabuf scatterlist\n");
+ return -EINVAL;
+ }
+
+ buf->dma_sgt = sgt;
+ buf->vaddr = NULL;
+
+ return 0;
+}
+
+static void vb2_dma_sg_unmap_dmabuf(void *mem_priv)
+{
+ struct vb2_dma_sg_buf *buf = mem_priv;
+ struct sg_table *sgt = buf->dma_sgt;
+
+ if (WARN_ON(!buf->db_attach)) {
+ pr_err("trying to unpin a not attached buffer\n");
+ return;
+ }
+
+ if (WARN_ON(!sgt)) {
+ pr_err("dmabuf buffer is already unpinned\n");
+ return;
+ }
+
+ if (buf->vaddr) {
+ dma_buf_vunmap(buf->db_attach->dmabuf, buf->vaddr);
+ buf->vaddr = NULL;
+ }
+ dma_buf_unmap_attachment(buf->db_attach, sgt, buf->dma_dir);
+
+ buf->dma_sgt = NULL;
+}
+
+static void vb2_dma_sg_detach_dmabuf(void *mem_priv)
+{
+ struct vb2_dma_sg_buf *buf = mem_priv;
+
+ /* if vb2 works correctly you should never detach mapped buffer */
+ if (WARN_ON(buf->dma_sgt))
+ vb2_dma_sg_unmap_dmabuf(buf);
+
+ /* detach this attachment */
+ dma_buf_detach(buf->db_attach->dmabuf, buf->db_attach);
+ kfree(buf);
+}
+
+static void *vb2_dma_sg_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
+ unsigned long size, enum dma_data_direction dma_dir)
+{
+ struct vb2_dma_sg_conf *conf = alloc_ctx;
+ struct vb2_dma_sg_buf *buf;
+ struct dma_buf_attachment *dba;
+
+ if (dbuf->size < size)
+ return ERR_PTR(-EFAULT);
+
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
+ if (!buf)
+ return ERR_PTR(-ENOMEM);
+
+ buf->dev = conf->dev;
+ /* create attachment for the dmabuf with the user device */
+ dba = dma_buf_attach(dbuf, buf->dev);
+ if (IS_ERR(dba)) {
+ pr_err("failed to attach dmabuf\n");
+ kfree(buf);
+ return dba;
+ }
+
+ buf->dma_dir = dma_dir;
+ buf->size = size;
+ buf->db_attach = dba;
+
+ return buf;
+}
+
static void *vb2_dma_sg_cookie(void *buf_priv)
{
struct vb2_dma_sg_buf *buf = buf_priv;
- return &buf->sg_table;
+ return buf->dma_sgt;
}
const struct vb2_mem_ops vb2_dma_sg_memops = {
@@ -347,13 +708,41 @@ const struct vb2_mem_ops vb2_dma_sg_memops = {
.put = vb2_dma_sg_put,
.get_userptr = vb2_dma_sg_get_userptr,
.put_userptr = vb2_dma_sg_put_userptr,
+ .prepare = vb2_dma_sg_prepare,
+ .finish = vb2_dma_sg_finish,
.vaddr = vb2_dma_sg_vaddr,
.mmap = vb2_dma_sg_mmap,
.num_users = vb2_dma_sg_num_users,
+ .get_dmabuf = vb2_dma_sg_get_dmabuf,
+ .map_dmabuf = vb2_dma_sg_map_dmabuf,
+ .unmap_dmabuf = vb2_dma_sg_unmap_dmabuf,
+ .attach_dmabuf = vb2_dma_sg_attach_dmabuf,
+ .detach_dmabuf = vb2_dma_sg_detach_dmabuf,
.cookie = vb2_dma_sg_cookie,
};
EXPORT_SYMBOL_GPL(vb2_dma_sg_memops);
+void *vb2_dma_sg_init_ctx(struct device *dev)
+{
+ struct vb2_dma_sg_conf *conf;
+
+ conf = kzalloc(sizeof(*conf), GFP_KERNEL);
+ if (!conf)
+ return ERR_PTR(-ENOMEM);
+
+ conf->dev = dev;
+
+ return conf;
+}
+EXPORT_SYMBOL_GPL(vb2_dma_sg_init_ctx);
+
+void vb2_dma_sg_cleanup_ctx(void *alloc_ctx)
+{
+ if (!IS_ERR_OR_NULL(alloc_ctx))
+ kfree(alloc_ctx);
+}
+EXPORT_SYMBOL_GPL(vb2_dma_sg_cleanup_ctx);
+
MODULE_DESCRIPTION("dma scatter/gather memory handling routines for videobuf2");
MODULE_AUTHOR("Andrzej Pietrasiewicz");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/v4l2-core/videobuf2-vmalloc.c b/drivers/media/v4l2-core/videobuf2-vmalloc.c
index 313d977..fba944e 100644
--- a/drivers/media/v4l2-core/videobuf2-vmalloc.c
+++ b/drivers/media/v4l2-core/videobuf2-vmalloc.c
@@ -25,7 +25,7 @@ struct vb2_vmalloc_buf {
void *vaddr;
struct page **pages;
struct vm_area_struct *vma;
- int write;
+ enum dma_data_direction dma_dir;
unsigned long size;
unsigned int n_pages;
atomic_t refcount;
@@ -35,7 +35,8 @@ struct vb2_vmalloc_buf {
static void vb2_vmalloc_put(void *buf_priv);
-static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_flags)
+static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size,
+ enum dma_data_direction dma_dir, gfp_t gfp_flags)
{
struct vb2_vmalloc_buf *buf;
@@ -45,6 +46,7 @@ static void *vb2_vmalloc_alloc(void *alloc_ctx, unsigned long size, gfp_t gfp_fl
buf->size = size;
buf->vaddr = vmalloc_user(buf->size);
+ buf->dma_dir = dma_dir;
buf->handler.refcount = &buf->refcount;
buf->handler.put = vb2_vmalloc_put;
buf->handler.arg = buf;
@@ -70,7 +72,8 @@ static void vb2_vmalloc_put(void *buf_priv)
}
static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
- unsigned long size, int write)
+ unsigned long size,
+ enum dma_data_direction dma_dir)
{
struct vb2_vmalloc_buf *buf;
unsigned long first, last;
@@ -82,7 +85,7 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
if (!buf)
return NULL;
- buf->write = write;
+ buf->dma_dir = dma_dir;
offset = vaddr & ~PAGE_MASK;
buf->size = size;
@@ -107,7 +110,8 @@ static void *vb2_vmalloc_get_userptr(void *alloc_ctx, unsigned long vaddr,
/* current->mm->mmap_sem is taken by videobuf2 core */
n_pages = get_user_pages(current, current->mm,
vaddr & PAGE_MASK, buf->n_pages,
- write, 1, /* force */
+ dma_dir == DMA_FROM_DEVICE,
+ 1, /* force */
buf->pages, NULL);
if (n_pages != buf->n_pages)
goto fail_get_user_pages;
@@ -144,14 +148,13 @@ static void vb2_vmalloc_put_userptr(void *buf_priv)
if (vaddr)
vm_unmap_ram((void *)vaddr, buf->n_pages);
for (i = 0; i < buf->n_pages; ++i) {
- if (buf->write)
+ if (buf->dma_dir == DMA_FROM_DEVICE)
set_page_dirty_lock(buf->pages[i]);
put_page(buf->pages[i]);
}
kfree(buf->pages);
} else {
- if (buf->vma)
- vb2_put_vma(buf->vma);
+ vb2_put_vma(buf->vma);
iounmap(buf->vaddr);
}
kfree(buf);
@@ -209,6 +212,176 @@ static int vb2_vmalloc_mmap(void *buf_priv, struct vm_area_struct *vma)
}
/*********************************************/
+/* DMABUF ops for exporters */
+/*********************************************/
+
+struct vb2_vmalloc_attachment {
+ struct sg_table sgt;
+ enum dma_data_direction dma_dir;
+};
+
+static int vb2_vmalloc_dmabuf_ops_attach(struct dma_buf *dbuf, struct device *dev,
+ struct dma_buf_attachment *dbuf_attach)
+{
+ struct vb2_vmalloc_attachment *attach;
+ struct vb2_vmalloc_buf *buf = dbuf->priv;
+ int num_pages = PAGE_ALIGN(buf->size) / PAGE_SIZE;
+ struct sg_table *sgt;
+ struct scatterlist *sg;
+ void *vaddr = buf->vaddr;
+ int ret;
+ int i;
+
+ attach = kzalloc(sizeof(*attach), GFP_KERNEL);
+ if (!attach)
+ return -ENOMEM;
+
+ sgt = &attach->sgt;
+ ret = sg_alloc_table(sgt, num_pages, GFP_KERNEL);
+ if (ret) {
+ kfree(attach);
+ return ret;
+ }
+ for_each_sg(sgt->sgl, sg, sgt->nents, i) {
+ struct page *page = vmalloc_to_page(vaddr);
+
+ if (!page) {
+ sg_free_table(sgt);
+ kfree(attach);
+ return -ENOMEM;
+ }
+ sg_set_page(sg, page, PAGE_SIZE, 0);
+ vaddr += PAGE_SIZE;
+ }
+
+ attach->dma_dir = DMA_NONE;
+ dbuf_attach->priv = attach;
+ return 0;
+}
+
+static void vb2_vmalloc_dmabuf_ops_detach(struct dma_buf *dbuf,
+ struct dma_buf_attachment *db_attach)
+{
+ struct vb2_vmalloc_attachment *attach = db_attach->priv;
+ struct sg_table *sgt;
+
+ if (!attach)
+ return;
+
+ sgt = &attach->sgt;
+
+ /* release the scatterlist cache */
+ if (attach->dma_dir != DMA_NONE)
+ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
+ attach->dma_dir);
+ sg_free_table(sgt);
+ kfree(attach);
+ db_attach->priv = NULL;
+}
+
+static struct sg_table *vb2_vmalloc_dmabuf_ops_map(
+ struct dma_buf_attachment *db_attach, enum dma_data_direction dma_dir)
+{
+ struct vb2_vmalloc_attachment *attach = db_attach->priv;
+ /* stealing dmabuf mutex to serialize map/unmap operations */
+ struct mutex *lock = &db_attach->dmabuf->lock;
+ struct sg_table *sgt;
+ int ret;
+
+ mutex_lock(lock);
+
+ sgt = &attach->sgt;
+ /* return previously mapped sg table */
+ if (attach->dma_dir == dma_dir) {
+ mutex_unlock(lock);
+ return sgt;
+ }
+
+ /* release any previous cache */
+ if (attach->dma_dir != DMA_NONE) {
+ dma_unmap_sg(db_attach->dev, sgt->sgl, sgt->orig_nents,
+ attach->dma_dir);
+ attach->dma_dir = DMA_NONE;
+ }
+
+ /* mapping to the client with new direction */
+ ret = dma_map_sg(db_attach->dev, sgt->sgl, sgt->orig_nents, dma_dir);
+ if (ret <= 0) {
+ pr_err("failed to map scatterlist\n");
+ mutex_unlock(lock);
+ return ERR_PTR(-EIO);
+ }
+
+ attach->dma_dir = dma_dir;
+
+ mutex_unlock(lock);
+
+ return sgt;
+}
+
+static void vb2_vmalloc_dmabuf_ops_unmap(struct dma_buf_attachment *db_attach,
+ struct sg_table *sgt, enum dma_data_direction dma_dir)
+{
+ /* nothing to be done here */
+}
+
+static void vb2_vmalloc_dmabuf_ops_release(struct dma_buf *dbuf)
+{
+ /* drop reference obtained in vb2_vmalloc_get_dmabuf */
+ vb2_vmalloc_put(dbuf->priv);
+}
+
+static void *vb2_vmalloc_dmabuf_ops_kmap(struct dma_buf *dbuf, unsigned long pgnum)
+{
+ struct vb2_vmalloc_buf *buf = dbuf->priv;
+
+ return buf->vaddr + pgnum * PAGE_SIZE;
+}
+
+static void *vb2_vmalloc_dmabuf_ops_vmap(struct dma_buf *dbuf)
+{
+ struct vb2_vmalloc_buf *buf = dbuf->priv;
+
+ return buf->vaddr;
+}
+
+static int vb2_vmalloc_dmabuf_ops_mmap(struct dma_buf *dbuf,
+ struct vm_area_struct *vma)
+{
+ return vb2_vmalloc_mmap(dbuf->priv, vma);
+}
+
+static struct dma_buf_ops vb2_vmalloc_dmabuf_ops = {
+ .attach = vb2_vmalloc_dmabuf_ops_attach,
+ .detach = vb2_vmalloc_dmabuf_ops_detach,
+ .map_dma_buf = vb2_vmalloc_dmabuf_ops_map,
+ .unmap_dma_buf = vb2_vmalloc_dmabuf_ops_unmap,
+ .kmap = vb2_vmalloc_dmabuf_ops_kmap,
+ .kmap_atomic = vb2_vmalloc_dmabuf_ops_kmap,
+ .vmap = vb2_vmalloc_dmabuf_ops_vmap,
+ .mmap = vb2_vmalloc_dmabuf_ops_mmap,
+ .release = vb2_vmalloc_dmabuf_ops_release,
+};
+
+static struct dma_buf *vb2_vmalloc_get_dmabuf(void *buf_priv, unsigned long flags)
+{
+ struct vb2_vmalloc_buf *buf = buf_priv;
+ struct dma_buf *dbuf;
+
+ if (WARN_ON(!buf->vaddr))
+ return NULL;
+
+ dbuf = dma_buf_export(buf, &vb2_vmalloc_dmabuf_ops, buf->size, flags, NULL);
+ if (IS_ERR(dbuf))
+ return NULL;
+
+ /* dmabuf keeps reference to vb2 buffer */
+ atomic_inc(&buf->refcount);
+
+ return dbuf;
+}
+
+/*********************************************/
/* callbacks for DMABUF buffers */
/*********************************************/
@@ -240,7 +413,7 @@ static void vb2_vmalloc_detach_dmabuf(void *mem_priv)
}
static void *vb2_vmalloc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
- unsigned long size, int write)
+ unsigned long size, enum dma_data_direction dma_dir)
{
struct vb2_vmalloc_buf *buf;
@@ -252,7 +425,7 @@ static void *vb2_vmalloc_attach_dmabuf(void *alloc_ctx, struct dma_buf *dbuf,
return ERR_PTR(-ENOMEM);
buf->dbuf = dbuf;
- buf->write = write;
+ buf->dma_dir = dma_dir;
buf->size = size;
return buf;
@@ -264,6 +437,7 @@ const struct vb2_mem_ops vb2_vmalloc_memops = {
.put = vb2_vmalloc_put,
.get_userptr = vb2_vmalloc_get_userptr,
.put_userptr = vb2_vmalloc_put_userptr,
+ .get_dmabuf = vb2_vmalloc_get_dmabuf,
.map_dmabuf = vb2_vmalloc_map_dmabuf,
.unmap_dmabuf = vb2_vmalloc_unmap_dmabuf,
.attach_dmabuf = vb2_vmalloc_attach_dmabuf,
diff --git a/drivers/memory/Kconfig b/drivers/memory/Kconfig
index 6d91c27..191383d8 100644
--- a/drivers/memory/Kconfig
+++ b/drivers/memory/Kconfig
@@ -41,6 +41,14 @@ config TI_EMIF
parameters and other settings during frequency, voltage and
temperature changes
+config OMAP_GPMC
+ bool
+ help
+ This driver is for the General Purpose Memory Controller (GPMC)
+ present on Texas Instruments SoCs (e.g. OMAP2+). GPMC allows
+ interfacing to a variety of asynchronous as well as synchronous
+ memory drives like NOR, NAND, OneNAND, SRAM.
+
config MVEBU_DEVBUS
bool "Marvell EBU Device Bus Controller"
default y
@@ -61,16 +69,6 @@ config TEGRA20_MC
analysis, especially for IOMMU/GART(Graphics Address
Relocation Table) module.
-config TEGRA30_MC
- bool "Tegra30 Memory Controller(MC) driver"
- default y
- depends on ARCH_TEGRA_3x_SOC
- help
- This driver is for the Memory Controller(MC) module available
- in Tegra30 SoCs, mainly for a address translation fault
- analysis, especially for IOMMU/SMMU(System Memory Management
- Unit) module.
-
config FSL_CORENET_CF
tristate "Freescale CoreNet Error Reporting"
depends on FSL_SOC_BOOKE
@@ -85,4 +83,6 @@ config FSL_IFC
bool
depends on FSL_SOC
+source "drivers/memory/tegra/Kconfig"
+
endif
diff --git a/drivers/memory/Makefile b/drivers/memory/Makefile
index c32d319..6b65481 100644
--- a/drivers/memory/Makefile
+++ b/drivers/memory/Makefile
@@ -8,8 +8,10 @@ endif
obj-$(CONFIG_ATMEL_SDRAMC) += atmel-sdramc.o
obj-$(CONFIG_TI_AEMIF) += ti-aemif.o
obj-$(CONFIG_TI_EMIF) += emif.o
+obj-$(CONFIG_OMAP_GPMC) += omap-gpmc.o
obj-$(CONFIG_FSL_CORENET_CF) += fsl-corenet-cf.o
obj-$(CONFIG_FSL_IFC) += fsl_ifc.o
obj-$(CONFIG_MVEBU_DEVBUS) += mvebu-devbus.o
obj-$(CONFIG_TEGRA20_MC) += tegra20-mc.o
-obj-$(CONFIG_TEGRA30_MC) += tegra30-mc.o
+
+obj-$(CONFIG_TEGRA_MC) += tegra/
diff --git a/arch/arm/mach-omap2/gpmc.c b/drivers/memory/omap-gpmc.c
index 5fa3755..ffc5e60 100644
--- a/arch/arm/mach-omap2/gpmc.c
+++ b/drivers/memory/omap-gpmc.c
@@ -29,20 +29,15 @@
#include <linux/of_address.h>
#include <linux/of_mtd.h>
#include <linux/of_device.h>
+#include <linux/omap-gpmc.h>
#include <linux/mtd/nand.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/mtd-nand-omap2.h>
+#include <linux/platform_data/mtd-onenand-omap2.h>
#include <asm/mach-types.h>
-#include "soc.h"
-#include "common.h"
-#include "omap_device.h"
-#include "gpmc.h"
-#include "gpmc-nand.h"
-#include "gpmc-onenand.h"
-
#define DEVICE_NAME "omap-gpmc"
/* GPMC register offsets */
@@ -85,6 +80,8 @@
#define GPMC_ECC_CTRL_ECCREG8 0x008
#define GPMC_ECC_CTRL_ECCREG9 0x009
+#define GPMC_CONFIG_LIMITEDADDRESS BIT(1)
+
#define GPMC_CONFIG2_CSEXTRADELAY BIT(7)
#define GPMC_CONFIG3_ADVEXTRADELAY BIT(7)
#define GPMC_CONFIG4_OEEXTRADELAY BIT(7)
@@ -114,10 +111,73 @@
#define GPMC_NR_WAITPINS 4
+#define GPMC_CS_CONFIG1 0x00
+#define GPMC_CS_CONFIG2 0x04
+#define GPMC_CS_CONFIG3 0x08
+#define GPMC_CS_CONFIG4 0x0c
+#define GPMC_CS_CONFIG5 0x10
+#define GPMC_CS_CONFIG6 0x14
+#define GPMC_CS_CONFIG7 0x18
+#define GPMC_CS_NAND_COMMAND 0x1c
+#define GPMC_CS_NAND_ADDRESS 0x20
+#define GPMC_CS_NAND_DATA 0x24
+
+/* Control Commands */
+#define GPMC_CONFIG_RDY_BSY 0x00000001
+#define GPMC_CONFIG_DEV_SIZE 0x00000002
+#define GPMC_CONFIG_DEV_TYPE 0x00000003
+#define GPMC_SET_IRQ_STATUS 0x00000004
+
+#define GPMC_CONFIG1_WRAPBURST_SUPP (1 << 31)
+#define GPMC_CONFIG1_READMULTIPLE_SUPP (1 << 30)
+#define GPMC_CONFIG1_READTYPE_ASYNC (0 << 29)
+#define GPMC_CONFIG1_READTYPE_SYNC (1 << 29)
+#define GPMC_CONFIG1_WRITEMULTIPLE_SUPP (1 << 28)
+#define GPMC_CONFIG1_WRITETYPE_ASYNC (0 << 27)
+#define GPMC_CONFIG1_WRITETYPE_SYNC (1 << 27)
+#define GPMC_CONFIG1_CLKACTIVATIONTIME(val) ((val & 3) << 25)
+#define GPMC_CONFIG1_PAGE_LEN(val) ((val & 3) << 23)
+#define GPMC_CONFIG1_WAIT_READ_MON (1 << 22)
+#define GPMC_CONFIG1_WAIT_WRITE_MON (1 << 21)
+#define GPMC_CONFIG1_WAIT_MON_IIME(val) ((val & 3) << 18)
+#define GPMC_CONFIG1_WAIT_PIN_SEL(val) ((val & 3) << 16)
+#define GPMC_CONFIG1_DEVICESIZE(val) ((val & 3) << 12)
+#define GPMC_CONFIG1_DEVICESIZE_16 GPMC_CONFIG1_DEVICESIZE(1)
+#define GPMC_CONFIG1_DEVICETYPE(val) ((val & 3) << 10)
+#define GPMC_CONFIG1_DEVICETYPE_NOR GPMC_CONFIG1_DEVICETYPE(0)
+#define GPMC_CONFIG1_MUXTYPE(val) ((val & 3) << 8)
+#define GPMC_CONFIG1_TIME_PARA_GRAN (1 << 4)
+#define GPMC_CONFIG1_FCLK_DIV(val) (val & 3)
+#define GPMC_CONFIG1_FCLK_DIV2 (GPMC_CONFIG1_FCLK_DIV(1))
+#define GPMC_CONFIG1_FCLK_DIV3 (GPMC_CONFIG1_FCLK_DIV(2))
+#define GPMC_CONFIG1_FCLK_DIV4 (GPMC_CONFIG1_FCLK_DIV(3))
+#define GPMC_CONFIG7_CSVALID (1 << 6)
+
+#define GPMC_DEVICETYPE_NOR 0
+#define GPMC_DEVICETYPE_NAND 2
+#define GPMC_CONFIG_WRITEPROTECT 0x00000010
+#define WR_RD_PIN_MONITORING 0x00600000
+
+#define GPMC_ENABLE_IRQ 0x0000000d
+
+/* ECC commands */
+#define GPMC_ECC_READ 0 /* Reset Hardware ECC for read */
+#define GPMC_ECC_WRITE 1 /* Reset Hardware ECC for write */
+#define GPMC_ECC_READSYN 2 /* Reset before syndrom is read back */
+
/* XXX: Only NAND irq has been considered,currently these are the only ones used
*/
#define GPMC_NR_IRQ 2
+struct gpmc_cs_data {
+ const char *name;
+
+#define GPMC_CS_RESERVED (1 << 0)
+ u32 flags;
+
+ struct resource mem;
+};
+
struct gpmc_client_irq {
unsigned irq;
u32 bitmask;
@@ -155,10 +215,9 @@ static struct irq_chip gpmc_irq_chip;
static int gpmc_irq_start;
static struct resource gpmc_mem_root;
-static struct resource gpmc_cs_mem[GPMC_CS_NUM];
+static struct gpmc_cs_data gpmc_cs[GPMC_CS_NUM];
static DEFINE_SPINLOCK(gpmc_mem_lock);
/* Define chip-selects as reserved by default until probe completes */
-static unsigned int gpmc_cs_map = ((1 << GPMC_CS_NUM) - 1);
static unsigned int gpmc_cs_num = GPMC_CS_NUM;
static unsigned int gpmc_nr_waitpins;
static struct device *gpmc_dev;
@@ -202,11 +261,6 @@ static unsigned long gpmc_get_fclk_period(void)
{
unsigned long rate = clk_get_rate(gpmc_l3_clk);
- if (rate == 0) {
- printk(KERN_WARNING "gpmc_l3_clk not enabled\n");
- return 0;
- }
-
rate /= 1000;
rate = 1000000000 / rate; /* In picoseconds */
@@ -284,12 +338,130 @@ static void gpmc_cs_bool_timings(int cs, const struct gpmc_bool_timings *p)
}
#ifdef DEBUG
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
- int time, const char *name)
+static int get_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+ bool raw, bool noval, int shift,
+ const char *name)
+{
+ u32 l;
+ int nr_bits, max_value, mask;
+
+ l = gpmc_cs_read_reg(cs, reg);
+ nr_bits = end_bit - st_bit + 1;
+ max_value = (1 << nr_bits) - 1;
+ mask = max_value << st_bit;
+ l = (l & mask) >> st_bit;
+ if (shift)
+ l = (shift << l);
+ if (noval && (l == 0))
+ return 0;
+ if (!raw) {
+ unsigned int time_ns_min, time_ns, time_ns_max;
+
+ time_ns_min = gpmc_ticks_to_ns(l ? l - 1 : 0);
+ time_ns = gpmc_ticks_to_ns(l);
+ time_ns_max = gpmc_ticks_to_ns(l + 1 > max_value ?
+ max_value : l + 1);
+ pr_info("gpmc,%s = <%u> (%u - %u ns, %i ticks)\n",
+ name, time_ns, time_ns_min, time_ns_max, l);
+ } else {
+ pr_info("gpmc,%s = <%u>\n", name, l);
+ }
+
+ return l;
+}
+
+#define GPMC_PRINT_CONFIG(cs, config) \
+ pr_info("cs%i %s: 0x%08x\n", cs, #config, \
+ gpmc_cs_read_reg(cs, config))
+#define GPMC_GET_RAW(reg, st, end, field) \
+ get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 0, 0, field)
+#define GPMC_GET_RAW_BOOL(reg, st, end, field) \
+ get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, 0, field)
+#define GPMC_GET_RAW_SHIFT(reg, st, end, shift, field) \
+ get_gpmc_timing_reg(cs, (reg), (st), (end), 1, 1, (shift), field)
+#define GPMC_GET_TICKS(reg, st, end, field) \
+ get_gpmc_timing_reg(cs, (reg), (st), (end), 0, 0, 0, field)
+
+static void gpmc_show_regs(int cs, const char *desc)
+{
+ pr_info("gpmc cs%i %s:\n", cs, desc);
+ GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG1);
+ GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG2);
+ GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG3);
+ GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG4);
+ GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG5);
+ GPMC_PRINT_CONFIG(cs, GPMC_CS_CONFIG6);
+}
+
+/*
+ * Note that gpmc,wait-pin handing wrongly assumes bit 8 is available,
+ * see commit c9fb809.
+ */
+static void gpmc_cs_show_timings(int cs, const char *desc)
+{
+ gpmc_show_regs(cs, desc);
+
+ pr_info("gpmc cs%i access configuration:\n", cs);
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 4, 4, "time-para-granularity");
+ GPMC_GET_RAW(GPMC_CS_CONFIG1, 8, 9, "mux-add-data");
+ GPMC_GET_RAW(GPMC_CS_CONFIG1, 12, 13, "device-width");
+ GPMC_GET_RAW(GPMC_CS_CONFIG1, 16, 17, "wait-pin");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 21, 21, "wait-on-write");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 22, 22, "wait-on-read");
+ GPMC_GET_RAW_SHIFT(GPMC_CS_CONFIG1, 23, 24, 4, "burst-length");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 27, 27, "sync-write");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 28, 28, "burst-write");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 29, 29, "gpmc,sync-read");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 30, 30, "burst-read");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG1, 31, 31, "burst-wrap");
+
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG2, 7, 7, "cs-extra-delay");
+
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG3, 7, 7, "adv-extra-delay");
+
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 23, 23, "we-extra-delay");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG4, 7, 7, "oe-extra-delay");
+
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6, 7, 7, "cycle2cycle-samecsen");
+ GPMC_GET_RAW_BOOL(GPMC_CS_CONFIG6, 6, 6, "cycle2cycle-diffcsen");
+
+ pr_info("gpmc cs%i timings configuration:\n", cs);
+ GPMC_GET_TICKS(GPMC_CS_CONFIG2, 0, 3, "cs-on-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG2, 8, 12, "cs-rd-off-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG2, 16, 20, "cs-wr-off-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG3, 0, 3, "adv-on-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG3, 8, 12, "adv-rd-off-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG3, 16, 20, "adv-wr-off-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG4, 0, 3, "oe-on-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG4, 8, 12, "oe-off-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG4, 16, 19, "we-on-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG4, 24, 28, "we-off-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG5, 0, 4, "rd-cycle-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG5, 8, 12, "wr-cycle-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG5, 16, 20, "access-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG5, 24, 27, "page-burst-access-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG6, 0, 3, "bus-turnaround-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG6, 8, 11, "cycle2cycle-delay-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG1, 18, 19, "wait-monitoring-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG1, 25, 26, "clk-activation-ns");
+
+ GPMC_GET_TICKS(GPMC_CS_CONFIG6, 16, 19, "wr-data-mux-bus-ns");
+ GPMC_GET_TICKS(GPMC_CS_CONFIG6, 24, 28, "wr-access-ns");
+}
#else
-static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
- int time)
+static inline void gpmc_cs_show_timings(int cs, const char *desc)
+{
+}
#endif
+
+static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
+ int time, const char *name)
{
u32 l;
int ticks, mask, nr_bits;
@@ -299,15 +471,15 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
else
ticks = gpmc_ns_to_ticks(time);
nr_bits = end_bit - st_bit + 1;
- if (ticks >= 1 << nr_bits) {
-#ifdef DEBUG
- printk(KERN_INFO "GPMC CS%d: %-10s* %3d ns, %3d ticks >= %d\n",
- cs, name, time, ticks, 1 << nr_bits);
-#endif
+ mask = (1 << nr_bits) - 1;
+
+ if (ticks > mask) {
+ pr_err("%s: GPMC error! CS%d: %s: %d ns, %d ticks > %d\n",
+ __func__, cs, name, time, ticks, mask);
+
return -1;
}
- mask = (1 << nr_bits) - 1;
l = gpmc_cs_read_reg(cs, reg);
#ifdef DEBUG
printk(KERN_INFO
@@ -322,16 +494,10 @@ static int set_gpmc_timing_reg(int cs, int reg, int st_bit, int end_bit,
return 0;
}
-#ifdef DEBUG
#define GPMC_SET_ONE(reg, st, end, field) \
if (set_gpmc_timing_reg(cs, (reg), (st), (end), \
t->field, #field) < 0) \
return -1
-#else
-#define GPMC_SET_ONE(reg, st, end, field) \
- if (set_gpmc_timing_reg(cs, (reg), (st), (end), t->field) < 0) \
- return -1
-#endif
int gpmc_calc_divider(unsigned int sync_clk)
{
@@ -353,6 +519,7 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
int div;
u32 l;
+ gpmc_cs_show_timings(cs, "before gpmc_cs_set_timings");
div = gpmc_calc_divider(t->sync_clk);
if (div < 0)
return div;
@@ -402,11 +569,12 @@ int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t)
}
gpmc_cs_bool_timings(cs, &t->bool_timings);
+ gpmc_cs_show_timings(cs, "after gpmc_cs_set_timings");
return 0;
}
-static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
+static int gpmc_cs_set_memconf(int cs, u32 base, u32 size)
{
u32 l;
u32 mask;
@@ -430,6 +598,15 @@ static int gpmc_cs_enable_mem(int cs, u32 base, u32 size)
return 0;
}
+static void gpmc_cs_enable_mem(int cs)
+{
+ u32 l;
+
+ l = gpmc_cs_read_reg(cs, GPMC_CS_CONFIG7);
+ l |= GPMC_CONFIG7_CSVALID;
+ gpmc_cs_write_reg(cs, GPMC_CS_CONFIG7, l);
+}
+
static void gpmc_cs_disable_mem(int cs)
{
u32 l;
@@ -460,13 +637,30 @@ static int gpmc_cs_mem_enabled(int cs)
static void gpmc_cs_set_reserved(int cs, int reserved)
{
- gpmc_cs_map &= ~(1 << cs);
- gpmc_cs_map |= (reserved ? 1 : 0) << cs;
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ gpmc->flags |= GPMC_CS_RESERVED;
}
static bool gpmc_cs_reserved(int cs)
{
- return gpmc_cs_map & (1 << cs);
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ return gpmc->flags & GPMC_CS_RESERVED;
+}
+
+static void gpmc_cs_set_name(int cs, const char *name)
+{
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ gpmc->name = name;
+}
+
+const char *gpmc_cs_get_name(int cs)
+{
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+
+ return gpmc->name;
}
static unsigned long gpmc_mem_align(unsigned long size)
@@ -485,7 +679,8 @@ static unsigned long gpmc_mem_align(unsigned long size)
static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
int r;
size = gpmc_mem_align(size);
@@ -500,7 +695,8 @@ static int gpmc_cs_insert_mem(int cs, unsigned long base, unsigned long size)
static int gpmc_cs_delete_mem(int cs)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
int r;
spin_lock(&gpmc_mem_lock);
@@ -541,23 +737,24 @@ static int gpmc_cs_remap(int cs, u32 base)
gpmc_cs_get_memconf(cs, &old_base, &size);
if (base == old_base)
return 0;
- gpmc_cs_disable_mem(cs);
+
ret = gpmc_cs_delete_mem(cs);
if (ret < 0)
return ret;
+
ret = gpmc_cs_insert_mem(cs, base, size);
if (ret < 0)
return ret;
- ret = gpmc_cs_enable_mem(cs, base, size);
- if (ret < 0)
- return ret;
- return 0;
+ ret = gpmc_cs_set_memconf(cs, base, size);
+
+ return ret;
}
int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
int r = -1;
if (cs > gpmc_cs_num) {
@@ -581,12 +778,17 @@ int gpmc_cs_request(int cs, unsigned long size, unsigned long *base)
if (r < 0)
goto out;
- r = gpmc_cs_enable_mem(cs, res->start, resource_size(res));
+ /* Disable CS while changing base address and size mask */
+ gpmc_cs_disable_mem(cs);
+
+ r = gpmc_cs_set_memconf(cs, res->start, resource_size(res));
if (r < 0) {
release_resource(res);
goto out;
}
+ /* Enable CS */
+ gpmc_cs_enable_mem(cs);
*base = res->start;
gpmc_cs_set_reserved(cs, 1);
out:
@@ -597,7 +799,8 @@ EXPORT_SYMBOL(gpmc_cs_request);
void gpmc_cs_free(int cs)
{
- struct resource *res = &gpmc_cs_mem[cs];
+ struct gpmc_cs_data *gpmc = &gpmc_cs[cs];
+ struct resource *res = &gpmc->mem;
spin_lock(&gpmc_mem_lock);
if (cs >= gpmc_cs_num || cs < 0 || !gpmc_cs_reserved(cs)) {
@@ -1394,8 +1597,6 @@ static int gpmc_probe_nand_child(struct platform_device *pdev,
if (gpmc_nand_data->elm_of_node == NULL)
gpmc_nand_data->elm_of_node =
of_parse_phandle(child, "elm_id", 0);
- if (gpmc_nand_data->elm_of_node == NULL)
- pr_warn("%s: ti,elm-id property not found\n", __func__);
/* select ecc-scheme for NAND */
if (of_property_read_string(child, "ti,nand-ecc-opt", &s)) {
@@ -1511,7 +1712,9 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
struct gpmc_timings gpmc_t;
struct resource res;
unsigned long base;
+ const char *name;
int ret, cs;
+ u32 val;
if (of_property_read_u32(child, "reg", &cs) < 0) {
dev_err(&pdev->dev, "%s has no 'reg' property\n",
@@ -1525,28 +1728,41 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
return -ENODEV;
}
+ /*
+ * Check if we have multiple instances of the same device
+ * on a single chip select. If so, use the already initialized
+ * timings.
+ */
+ name = gpmc_cs_get_name(cs);
+ if (name && child->name && of_node_cmp(child->name, name) == 0)
+ goto no_timings;
+
ret = gpmc_cs_request(cs, resource_size(&res), &base);
if (ret < 0) {
dev_err(&pdev->dev, "cannot request GPMC CS %d\n", cs);
return ret;
}
+ gpmc_cs_set_name(cs, child->name);
+
+ gpmc_read_settings_dt(child, &gpmc_s);
+ gpmc_read_timings_dt(child, &gpmc_t);
/*
* For some GPMC devices we still need to rely on the bootloader
- * timings because the devices can be connected via FPGA. So far
- * the list is smc91x on the omap2 SDP boards, and 8250 on zooms.
- * REVISIT: Add timing support from slls644g.pdf and from the
- * lan91c96 manual.
+ * timings because the devices can be connected via FPGA.
+ * REVISIT: Add timing support from slls644g.pdf.
*/
- if (of_device_is_compatible(child, "ns16550a") ||
- of_device_is_compatible(child, "smsc,lan91c94") ||
- of_device_is_compatible(child, "smsc,lan91c111")) {
- dev_warn(&pdev->dev,
- "%s using bootloader timings on CS%d\n",
- child->name, cs);
+ if (!gpmc_t.cs_rd_off) {
+ WARN(1, "enable GPMC debug to configure .dts timings for CS%i\n",
+ cs);
+ gpmc_cs_show_timings(cs,
+ "please add GPMC bootloader timings to .dts");
goto no_timings;
}
+ /* CS must be disabled while making changes to gpmc configuration */
+ gpmc_cs_disable_mem(cs);
+
/*
* FIXME: gpmc_cs_request() will map the CS to an arbitary
* location in the gpmc address space. When booting with
@@ -1562,8 +1778,6 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
goto err;
}
- gpmc_read_settings_dt(child, &gpmc_s);
-
ret = of_property_read_u32(child, "bank-width", &gpmc_s.device_width);
if (ret < 0)
goto err;
@@ -1572,8 +1786,20 @@ static int gpmc_probe_generic_child(struct platform_device *pdev,
if (ret < 0)
goto err;
- gpmc_read_timings_dt(child, &gpmc_t);
- gpmc_cs_set_timings(cs, &gpmc_t);
+ ret = gpmc_cs_set_timings(cs, &gpmc_t);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to set gpmc timings for: %s\n",
+ child->name);
+ goto err;
+ }
+
+ /* Clear limited address i.e. enable A26-A11 */
+ val = gpmc_read_reg(GPMC_CONFIG);
+ val &= ~GPMC_CONFIG_LIMITEDADDRESS;
+ gpmc_write_reg(GPMC_CONFIG, val);
+
+ /* Enable CS region */
+ gpmc_cs_enable_mem(cs);
no_timings:
if (of_platform_device_create(child, NULL, &pdev->dev))
@@ -1670,13 +1896,18 @@ static int gpmc_probe(struct platform_device *pdev)
else
gpmc_irq = res->start;
- gpmc_l3_clk = clk_get(&pdev->dev, "fck");
+ gpmc_l3_clk = devm_clk_get(&pdev->dev, "fck");
if (IS_ERR(gpmc_l3_clk)) {
- dev_err(&pdev->dev, "error: clk_get\n");
+ dev_err(&pdev->dev, "Failed to get GPMC fck\n");
gpmc_irq = 0;
return PTR_ERR(gpmc_l3_clk);
}
+ if (!clk_get_rate(gpmc_l3_clk)) {
+ dev_err(&pdev->dev, "Invalid GPMC fck clock rate\n");
+ return -EINVAL;
+ }
+
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
@@ -1708,9 +1939,6 @@ static int gpmc_probe(struct platform_device *pdev)
if (gpmc_setup_irq() < 0)
dev_warn(gpmc_dev, "gpmc_setup_irq failed\n");
- /* Now the GPMC is initialised, unreserve the chip-selects */
- gpmc_cs_map = 0;
-
if (!pdev->dev.of_node) {
gpmc_cs_num = GPMC_CS_NUM;
gpmc_nr_waitpins = GPMC_NR_WAITPINS;
@@ -1719,7 +1947,6 @@ static int gpmc_probe(struct platform_device *pdev)
rc = gpmc_probe_dt(pdev);
if (rc < 0) {
pm_runtime_put_sync(&pdev->dev);
- clk_put(gpmc_l3_clk);
dev_err(gpmc_dev, "failed to probe DT parameters\n");
return rc;
}
@@ -1777,35 +2004,9 @@ static __exit void gpmc_exit(void)
}
-omap_postcore_initcall(gpmc_init);
+postcore_initcall(gpmc_init);
module_exit(gpmc_exit);
-static int __init omap_gpmc_init(void)
-{
- struct omap_hwmod *oh;
- struct platform_device *pdev;
- char *oh_name = "gpmc";
-
- /*
- * if the board boots up with a populated DT, do not
- * manually add the device from this initcall
- */
- if (of_have_populated_dt())
- return -ENODEV;
-
- oh = omap_hwmod_lookup(oh_name);
- if (!oh) {
- pr_err("Could not look up %s\n", oh_name);
- return -ENODEV;
- }
-
- pdev = omap_device_build(DEVICE_NAME, -1, oh, NULL, 0);
- WARN(IS_ERR(pdev), "could not build omap_device for %s\n", oh_name);
-
- return PTR_RET(pdev);
-}
-omap_postcore_initcall(omap_gpmc_init);
-
static irqreturn_t gpmc_handle_irq(int irq, void *dev)
{
int i;
diff --git a/drivers/memory/tegra/Kconfig b/drivers/memory/tegra/Kconfig
new file mode 100644
index 0000000..5710876
--- /dev/null
+++ b/drivers/memory/tegra/Kconfig
@@ -0,0 +1,7 @@
+config TEGRA_MC
+ bool "NVIDIA Tegra Memory Controller support"
+ default y
+ depends on ARCH_TEGRA
+ help
+ This driver supports the Memory Controller (MC) hardware found on
+ NVIDIA Tegra SoCs.
diff --git a/drivers/memory/tegra/Makefile b/drivers/memory/tegra/Makefile
new file mode 100644
index 0000000..0d9f497
--- /dev/null
+++ b/drivers/memory/tegra/Makefile
@@ -0,0 +1,7 @@
+tegra-mc-y := mc.o
+
+tegra-mc-$(CONFIG_ARCH_TEGRA_3x_SOC) += tegra30.o
+tegra-mc-$(CONFIG_ARCH_TEGRA_114_SOC) += tegra114.o
+tegra-mc-$(CONFIG_ARCH_TEGRA_124_SOC) += tegra124.o
+
+obj-$(CONFIG_TEGRA_MC) += tegra-mc.o
diff --git a/drivers/memory/tegra/mc.c b/drivers/memory/tegra/mc.c
new file mode 100644
index 0000000..fe3c44e
--- /dev/null
+++ b/drivers/memory/tegra/mc.c
@@ -0,0 +1,301 @@
+/*
+ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/clk.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+
+#include "mc.h"
+
+#define MC_INTSTATUS 0x000
+#define MC_INT_DECERR_MTS (1 << 16)
+#define MC_INT_SECERR_SEC (1 << 13)
+#define MC_INT_DECERR_VPR (1 << 12)
+#define MC_INT_INVALID_APB_ASID_UPDATE (1 << 11)
+#define MC_INT_INVALID_SMMU_PAGE (1 << 10)
+#define MC_INT_ARBITRATION_EMEM (1 << 9)
+#define MC_INT_SECURITY_VIOLATION (1 << 8)
+#define MC_INT_DECERR_EMEM (1 << 6)
+
+#define MC_INTMASK 0x004
+
+#define MC_ERR_STATUS 0x08
+#define MC_ERR_STATUS_TYPE_SHIFT 28
+#define MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE (6 << MC_ERR_STATUS_TYPE_SHIFT)
+#define MC_ERR_STATUS_TYPE_MASK (0x7 << MC_ERR_STATUS_TYPE_SHIFT)
+#define MC_ERR_STATUS_READABLE (1 << 27)
+#define MC_ERR_STATUS_WRITABLE (1 << 26)
+#define MC_ERR_STATUS_NONSECURE (1 << 25)
+#define MC_ERR_STATUS_ADR_HI_SHIFT 20
+#define MC_ERR_STATUS_ADR_HI_MASK 0x3
+#define MC_ERR_STATUS_SECURITY (1 << 17)
+#define MC_ERR_STATUS_RW (1 << 16)
+#define MC_ERR_STATUS_CLIENT_MASK 0x7f
+
+#define MC_ERR_ADR 0x0c
+
+#define MC_EMEM_ARB_CFG 0x90
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(x) (((x) & 0x1ff) << 0)
+#define MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK 0x1ff
+#define MC_EMEM_ARB_MISC0 0xd8
+
+static const struct of_device_id tegra_mc_of_match[] = {
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+ { .compatible = "nvidia,tegra30-mc", .data = &tegra30_mc_soc },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+ { .compatible = "nvidia,tegra114-mc", .data = &tegra114_mc_soc },
+#endif
+#ifdef CONFIG_ARCH_TEGRA_124_SOC
+ { .compatible = "nvidia,tegra124-mc", .data = &tegra124_mc_soc },
+#endif
+ { }
+};
+MODULE_DEVICE_TABLE(of, tegra_mc_of_match);
+
+static int tegra_mc_setup_latency_allowance(struct tegra_mc *mc)
+{
+ unsigned long long tick;
+ unsigned int i;
+ u32 value;
+
+ /* compute the number of MC clock cycles per tick */
+ tick = mc->tick * clk_get_rate(mc->clk);
+ do_div(tick, NSEC_PER_SEC);
+
+ value = readl(mc->regs + MC_EMEM_ARB_CFG);
+ value &= ~MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE_MASK;
+ value |= MC_EMEM_ARB_CFG_CYCLES_PER_UPDATE(tick);
+ writel(value, mc->regs + MC_EMEM_ARB_CFG);
+
+ /* write latency allowance defaults */
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ const struct tegra_mc_la *la = &mc->soc->clients[i].la;
+ u32 value;
+
+ value = readl(mc->regs + la->reg);
+ value &= ~(la->mask << la->shift);
+ value |= (la->def & la->mask) << la->shift;
+ writel(value, mc->regs + la->reg);
+ }
+
+ return 0;
+}
+
+static const char *const status_names[32] = {
+ [ 1] = "External interrupt",
+ [ 6] = "EMEM address decode error",
+ [ 8] = "Security violation",
+ [ 9] = "EMEM arbitration error",
+ [10] = "Page fault",
+ [11] = "Invalid APB ASID update",
+ [12] = "VPR violation",
+ [13] = "Secure carveout violation",
+ [16] = "MTS carveout violation",
+};
+
+static const char *const error_names[8] = {
+ [2] = "EMEM decode error",
+ [3] = "TrustZone violation",
+ [4] = "Carveout violation",
+ [6] = "SMMU translation error",
+};
+
+static irqreturn_t tegra_mc_irq(int irq, void *data)
+{
+ struct tegra_mc *mc = data;
+ unsigned long status, mask;
+ unsigned int bit;
+
+ /* mask all interrupts to avoid flooding */
+ status = mc_readl(mc, MC_INTSTATUS);
+ mask = mc_readl(mc, MC_INTMASK);
+
+ for_each_set_bit(bit, &status, 32) {
+ const char *error = status_names[bit] ?: "unknown";
+ const char *client = "unknown", *desc;
+ const char *direction, *secure;
+ phys_addr_t addr = 0;
+ unsigned int i;
+ char perm[7];
+ u8 id, type;
+ u32 value;
+
+ value = mc_readl(mc, MC_ERR_STATUS);
+
+#ifdef CONFIG_PHYS_ADDR_T_64BIT
+ if (mc->soc->num_address_bits > 32) {
+ addr = ((value >> MC_ERR_STATUS_ADR_HI_SHIFT) &
+ MC_ERR_STATUS_ADR_HI_MASK);
+ addr <<= 32;
+ }
+#endif
+
+ if (value & MC_ERR_STATUS_RW)
+ direction = "write";
+ else
+ direction = "read";
+
+ if (value & MC_ERR_STATUS_SECURITY)
+ secure = "secure ";
+ else
+ secure = "";
+
+ id = value & MC_ERR_STATUS_CLIENT_MASK;
+
+ for (i = 0; i < mc->soc->num_clients; i++) {
+ if (mc->soc->clients[i].id == id) {
+ client = mc->soc->clients[i].name;
+ break;
+ }
+ }
+
+ type = (value & MC_ERR_STATUS_TYPE_MASK) >>
+ MC_ERR_STATUS_TYPE_SHIFT;
+ desc = error_names[type];
+
+ switch (value & MC_ERR_STATUS_TYPE_MASK) {
+ case MC_ERR_STATUS_TYPE_INVALID_SMMU_PAGE:
+ perm[0] = ' ';
+ perm[1] = '[';
+
+ if (value & MC_ERR_STATUS_READABLE)
+ perm[2] = 'R';
+ else
+ perm[2] = '-';
+
+ if (value & MC_ERR_STATUS_WRITABLE)
+ perm[3] = 'W';
+ else
+ perm[3] = '-';
+
+ if (value & MC_ERR_STATUS_NONSECURE)
+ perm[4] = '-';
+ else
+ perm[4] = 'S';
+
+ perm[5] = ']';
+ perm[6] = '\0';
+ break;
+
+ default:
+ perm[0] = '\0';
+ break;
+ }
+
+ value = mc_readl(mc, MC_ERR_ADR);
+ addr |= value;
+
+ dev_err_ratelimited(mc->dev, "%s: %s%s @%pa: %s (%s%s)\n",
+ client, secure, direction, &addr, error,
+ desc, perm);
+ }
+
+ /* clear interrupts */
+ mc_writel(mc, status, MC_INTSTATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int tegra_mc_probe(struct platform_device *pdev)
+{
+ const struct of_device_id *match;
+ struct resource *res;
+ struct tegra_mc *mc;
+ u32 value;
+ int err;
+
+ match = of_match_node(tegra_mc_of_match, pdev->dev.of_node);
+ if (!match)
+ return -ENODEV;
+
+ mc = devm_kzalloc(&pdev->dev, sizeof(*mc), GFP_KERNEL);
+ if (!mc)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, mc);
+ mc->soc = match->data;
+ mc->dev = &pdev->dev;
+
+ /* length of MC tick in nanoseconds */
+ mc->tick = 30;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ mc->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(mc->regs))
+ return PTR_ERR(mc->regs);
+
+ mc->clk = devm_clk_get(&pdev->dev, "mc");
+ if (IS_ERR(mc->clk)) {
+ dev_err(&pdev->dev, "failed to get MC clock: %ld\n",
+ PTR_ERR(mc->clk));
+ return PTR_ERR(mc->clk);
+ }
+
+ err = tegra_mc_setup_latency_allowance(mc);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to setup latency allowance: %d\n",
+ err);
+ return err;
+ }
+
+ if (IS_ENABLED(CONFIG_TEGRA_IOMMU_SMMU)) {
+ mc->smmu = tegra_smmu_probe(&pdev->dev, mc->soc->smmu, mc);
+ if (IS_ERR(mc->smmu)) {
+ dev_err(&pdev->dev, "failed to probe SMMU: %ld\n",
+ PTR_ERR(mc->smmu));
+ return PTR_ERR(mc->smmu);
+ }
+ }
+
+ mc->irq = platform_get_irq(pdev, 0);
+ if (mc->irq < 0) {
+ dev_err(&pdev->dev, "interrupt not specified\n");
+ return mc->irq;
+ }
+
+ err = devm_request_irq(&pdev->dev, mc->irq, tegra_mc_irq, IRQF_SHARED,
+ dev_name(&pdev->dev), mc);
+ if (err < 0) {
+ dev_err(&pdev->dev, "failed to request IRQ#%u: %d\n", mc->irq,
+ err);
+ return err;
+ }
+
+ value = MC_INT_DECERR_MTS | MC_INT_SECERR_SEC | MC_INT_DECERR_VPR |
+ MC_INT_INVALID_APB_ASID_UPDATE | MC_INT_INVALID_SMMU_PAGE |
+ MC_INT_ARBITRATION_EMEM | MC_INT_SECURITY_VIOLATION |
+ MC_INT_DECERR_EMEM;
+ mc_writel(mc, value, MC_INTMASK);
+
+ return 0;
+}
+
+static struct platform_driver tegra_mc_driver = {
+ .driver = {
+ .name = "tegra-mc",
+ .of_match_table = tegra_mc_of_match,
+ .suppress_bind_attrs = true,
+ },
+ .prevent_deferred_probe = true,
+ .probe = tegra_mc_probe,
+};
+
+static int tegra_mc_init(void)
+{
+ return platform_driver_register(&tegra_mc_driver);
+}
+arch_initcall(tegra_mc_init);
+
+MODULE_AUTHOR("Thierry Reding <treding@nvidia.com>");
+MODULE_DESCRIPTION("NVIDIA Tegra Memory Controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/memory/tegra/mc.h b/drivers/memory/tegra/mc.h
new file mode 100644
index 0000000..d5d2114
--- /dev/null
+++ b/drivers/memory/tegra/mc.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef MEMORY_TEGRA_MC_H
+#define MEMORY_TEGRA_MC_H
+
+#include <linux/io.h>
+#include <linux/types.h>
+
+#include <soc/tegra/mc.h>
+
+static inline u32 mc_readl(struct tegra_mc *mc, unsigned long offset)
+{
+ return readl(mc->regs + offset);
+}
+
+static inline void mc_writel(struct tegra_mc *mc, u32 value,
+ unsigned long offset)
+{
+ writel(value, mc->regs + offset);
+}
+
+#ifdef CONFIG_ARCH_TEGRA_3x_SOC
+extern const struct tegra_mc_soc tegra30_mc_soc;
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_114_SOC
+extern const struct tegra_mc_soc tegra114_mc_soc;
+#endif
+
+#ifdef CONFIG_ARCH_TEGRA_124_SOC
+extern const struct tegra_mc_soc tegra124_mc_soc;
+#endif
+
+#endif /* MEMORY_TEGRA_MC_H */
diff --git a/drivers/memory/tegra/tegra114.c b/drivers/memory/tegra/tegra114.c
new file mode 100644
index 0000000..511e9a2
--- /dev/null
+++ b/drivers/memory/tegra/tegra114.c
@@ -0,0 +1,948 @@
+/*
+ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/mm.h>
+
+#include <asm/cacheflush.h>
+
+#include <dt-bindings/memory/tegra114-mc.h>
+
+#include "mc.h"
+
+static const struct tegra_mc_client tegra114_mc_clients[] = {
+ {
+ .id = 0x00,
+ .name = "ptcr",
+ .swgroup = TEGRA_SWGROUP_PTC,
+ }, {
+ .id = 0x01,
+ .name = "display0a",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x02,
+ .name = "display0ab",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x03,
+ .name = "display0b",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x04,
+ .name = "display0bb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x05,
+ .name = "display0c",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x06,
+ .name = "display0cb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x09,
+ .name = "eppup",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x33,
+ },
+ }, {
+ .id = 0x0a,
+ .name = "g2pr",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x09,
+ },
+ }, {
+ .id = 0x0b,
+ .name = "g2sr",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x09,
+ },
+ }, {
+ .id = 0x0f,
+ .name = "avpcarm7r",
+ .swgroup = TEGRA_SWGROUP_AVPC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x10,
+ .name = "displayhc",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x68,
+ },
+ }, {
+ .id = 0x11,
+ .name = "displayhcb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x68,
+ },
+ }, {
+ .id = 0x12,
+ .name = "fdcdrd",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
+ }, {
+ .id = 0x13,
+ .name = "fdcdrd2",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x33c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
+ }, {
+ .id = 0x14,
+ .name = "g2dr",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
+ }, {
+ .id = 0x15,
+ .name = "hdar",
+ .swgroup = TEGRA_SWGROUP_HDA,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x16,
+ .name = "host1xdmar",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x17,
+ .name = "host1xr",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x18,
+ .name = "idxsrd",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0b,
+ },
+ }, {
+ .id = 0x1c,
+ .name = "msencsrd",
+ .swgroup = TEGRA_SWGROUP_MSENC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x1d,
+ .name = "ppcsahbdmar",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x1e,
+ .name = "ppcsahbslvr",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xe8,
+ },
+ }, {
+ .id = 0x20,
+ .name = "texl2srd",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
+ }, {
+ .id = 0x22,
+ .name = "vdebsevr",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x23,
+ .name = "vdember",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x24,
+ .name = "vdemcer",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xb8,
+ },
+ }, {
+ .id = 0x25,
+ .name = "vdetper",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xee,
+ },
+ }, {
+ .id = 0x26,
+ .name = "mpcorelpr",
+ .swgroup = TEGRA_SWGROUP_MPCORELP,
+ .la = {
+ .reg = 0x324,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x27,
+ .name = "mpcorer",
+ .swgroup = TEGRA_SWGROUP_MPCORE,
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x28,
+ .name = "eppu",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x33,
+ },
+ }, {
+ .id = 0x29,
+ .name = "eppv",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
+ }, {
+ .id = 0x2a,
+ .name = "eppy",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
+ }, {
+ .id = 0x2b,
+ .name = "msencswr",
+ .swgroup = TEGRA_SWGROUP_MSENC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x2c,
+ .name = "viwsb",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x364,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x47,
+ },
+ }, {
+ .id = 0x2d,
+ .name = "viwu",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x2e,
+ .name = "viwv",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x2f,
+ .name = "viwy",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x36c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x47,
+ },
+ }, {
+ .id = 0x30,
+ .name = "g2dw",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x9,
+ },
+ }, {
+ .id = 0x32,
+ .name = "avpcarm7w",
+ .swgroup = TEGRA_SWGROUP_AVPC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
+ }, {
+ .id = 0x33,
+ .name = "fdcdwr",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x34,
+ .name = "fdcwr2",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x340,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x35,
+ .name = "hdaw",
+ .swgroup = TEGRA_SWGROUP_HDA,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x36,
+ .name = "host1xw",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x25,
+ },
+ }, {
+ .id = 0x37,
+ .name = "ispw",
+ .swgroup = TEGRA_SWGROUP_ISP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x31c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x38,
+ .name = "mpcorelpw",
+ .swgroup = TEGRA_SWGROUP_MPCORELP,
+ .la = {
+ .reg = 0x324,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x39,
+ .name = "mpcorew",
+ .swgroup = TEGRA_SWGROUP_MPCORE,
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
+ }, {
+ .id = 0x3b,
+ .name = "ppcsahbdmaw",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x3c,
+ .name = "ppcsahbslvw",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xe8,
+ },
+ }, {
+ .id = 0x3e,
+ .name = "vdebsevw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x3f,
+ .name = "vdedbgw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x40,
+ .name = "vdembew",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x89,
+ },
+ }, {
+ .id = 0x41,
+ .name = "vdetpmw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x59,
+ },
+ }, {
+ .id = 0x4a,
+ .name = "xusb_hostr",
+ .swgroup = TEGRA_SWGROUP_XUSB_HOST,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x4b,
+ .name = "xusb_hostw",
+ .swgroup = TEGRA_SWGROUP_XUSB_HOST,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x4c,
+ .name = "xusb_devr",
+ .swgroup = TEGRA_SWGROUP_XUSB_DEV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x4d,
+ .name = "xusb_devw",
+ .swgroup = TEGRA_SWGROUP_XUSB_DEV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x4e,
+ .name = "fdcdwr3",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x4f,
+ .name = "fdcdrd3",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
+ }, {
+ .id = 0x50,
+ .name = "fdcwr4",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x51,
+ .name = "fdcrd4",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
+ }, {
+ .id = 0x52,
+ .name = "emucifr",
+ .swgroup = TEGRA_SWGROUP_EMUCIF,
+ .la = {
+ .reg = 0x38c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x53,
+ .name = "emucifw",
+ .swgroup = TEGRA_SWGROUP_EMUCIF,
+ .la = {
+ .reg = 0x38c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
+ }, {
+ .id = 0x54,
+ .name = "tsecsrd",
+ .swgroup = TEGRA_SWGROUP_TSEC,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x55,
+ .name = "tsecswr",
+ .swgroup = TEGRA_SWGROUP_TSEC,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ },
+};
+
+static const struct tegra_smmu_swgroup tegra114_swgroups[] = {
+ { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
+ { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
+ { .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 },
+ { .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c },
+ { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
+ { .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 },
+ { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
+ { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
+ { .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264 },
+ { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
+ { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
+ { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
+ { .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
+ { .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
+ { .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c },
+ { .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
+};
+
+static void tegra114_flush_dcache(struct page *page, unsigned long offset,
+ size_t size)
+{
+ phys_addr_t phys = page_to_phys(page) + offset;
+ void *virt = page_address(page) + offset;
+
+ __cpuc_flush_dcache_area(virt, size);
+ outer_flush_range(phys, phys + size);
+}
+
+static const struct tegra_smmu_ops tegra114_smmu_ops = {
+ .flush_dcache = tegra114_flush_dcache,
+};
+
+static const struct tegra_smmu_soc tegra114_smmu_soc = {
+ .clients = tegra114_mc_clients,
+ .num_clients = ARRAY_SIZE(tegra114_mc_clients),
+ .swgroups = tegra114_swgroups,
+ .num_swgroups = ARRAY_SIZE(tegra114_swgroups),
+ .supports_round_robin_arbitration = false,
+ .supports_request_limit = false,
+ .num_asids = 4,
+ .ops = &tegra114_smmu_ops,
+};
+
+const struct tegra_mc_soc tegra114_mc_soc = {
+ .clients = tegra114_mc_clients,
+ .num_clients = ARRAY_SIZE(tegra114_mc_clients),
+ .num_address_bits = 32,
+ .atom_size = 32,
+ .smmu = &tegra114_smmu_soc,
+};
diff --git a/drivers/memory/tegra/tegra124.c b/drivers/memory/tegra/tegra124.c
new file mode 100644
index 0000000..278d40b
--- /dev/null
+++ b/drivers/memory/tegra/tegra124.c
@@ -0,0 +1,995 @@
+/*
+ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/mm.h>
+
+#include <asm/cacheflush.h>
+
+#include <dt-bindings/memory/tegra124-mc.h>
+
+#include "mc.h"
+
+static const struct tegra_mc_client tegra124_mc_clients[] = {
+ {
+ .id = 0x00,
+ .name = "ptcr",
+ .swgroup = TEGRA_SWGROUP_PTC,
+ }, {
+ .id = 0x01,
+ .name = "display0a",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xc2,
+ },
+ }, {
+ .id = 0x02,
+ .name = "display0ab",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xc6,
+ },
+ }, {
+ .id = 0x03,
+ .name = "display0b",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x04,
+ .name = "display0bb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x05,
+ .name = "display0c",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x06,
+ .name = "display0cb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x0e,
+ .name = "afir",
+ .swgroup = TEGRA_SWGROUP_AFI,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
+ }, {
+ .id = 0x0f,
+ .name = "avpcarm7r",
+ .swgroup = TEGRA_SWGROUP_AVPC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x10,
+ .name = "displayhc",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x11,
+ .name = "displayhcb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x15,
+ .name = "hdar",
+ .swgroup = TEGRA_SWGROUP_HDA,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x24,
+ },
+ }, {
+ .id = 0x16,
+ .name = "host1xdmar",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1e,
+ },
+ }, {
+ .id = 0x17,
+ .name = "host1xr",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x1c,
+ .name = "msencsrd",
+ .swgroup = TEGRA_SWGROUP_MSENC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x23,
+ },
+ }, {
+ .id = 0x1d,
+ .name = "ppcsahbdmar",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
+ }, {
+ .id = 0x1e,
+ .name = "ppcsahbslvr",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
+ }, {
+ .id = 0x1f,
+ .name = "satar",
+ .swgroup = TEGRA_SWGROUP_SATA,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x65,
+ },
+ }, {
+ .id = 0x22,
+ .name = "vdebsevr",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4f,
+ },
+ }, {
+ .id = 0x23,
+ .name = "vdember",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x3d,
+ },
+ }, {
+ .id = 0x24,
+ .name = "vdemcer",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x66,
+ },
+ }, {
+ .id = 0x25,
+ .name = "vdetper",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xa5,
+ },
+ }, {
+ .id = 0x26,
+ .name = "mpcorelpr",
+ .swgroup = TEGRA_SWGROUP_MPCORELP,
+ .la = {
+ .reg = 0x324,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x27,
+ .name = "mpcorer",
+ .swgroup = TEGRA_SWGROUP_MPCORE,
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x2b,
+ .name = "msencswr",
+ .swgroup = TEGRA_SWGROUP_MSENC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x31,
+ .name = "afiw",
+ .swgroup = TEGRA_SWGROUP_AFI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x32,
+ .name = "avpcarm7w",
+ .swgroup = TEGRA_SWGROUP_AVPC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x35,
+ .name = "hdaw",
+ .swgroup = TEGRA_SWGROUP_HDA,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x36,
+ .name = "host1xw",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x38,
+ .name = "mpcorelpw",
+ .swgroup = TEGRA_SWGROUP_MPCORELP,
+ .la = {
+ .reg = 0x324,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x39,
+ .name = "mpcorew",
+ .swgroup = TEGRA_SWGROUP_MPCORE,
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x3b,
+ .name = "ppcsahbdmaw",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x3c,
+ .name = "ppcsahbslvw",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x3d,
+ .name = "sataw",
+ .swgroup = TEGRA_SWGROUP_SATA,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x65,
+ },
+ }, {
+ .id = 0x3e,
+ .name = "vdebsevw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x3f,
+ .name = "vdedbgw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x40,
+ .name = "vdembew",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x41,
+ .name = "vdetpmw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x44,
+ .name = "ispra",
+ .swgroup = TEGRA_SWGROUP_ISP2,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x370,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x18,
+ },
+ }, {
+ .id = 0x46,
+ .name = "ispwa",
+ .swgroup = TEGRA_SWGROUP_ISP2,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x374,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x47,
+ .name = "ispwb",
+ .swgroup = TEGRA_SWGROUP_ISP2,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x374,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x4a,
+ .name = "xusb_hostr",
+ .swgroup = TEGRA_SWGROUP_XUSB_HOST,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x39,
+ },
+ }, {
+ .id = 0x4b,
+ .name = "xusb_hostw",
+ .swgroup = TEGRA_SWGROUP_XUSB_HOST,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x37c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x4c,
+ .name = "xusb_devr",
+ .swgroup = TEGRA_SWGROUP_XUSB_DEV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x39,
+ },
+ }, {
+ .id = 0x4d,
+ .name = "xusb_devw",
+ .swgroup = TEGRA_SWGROUP_XUSB_DEV,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x380,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x4e,
+ .name = "isprab",
+ .swgroup = TEGRA_SWGROUP_ISP2B,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x384,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x18,
+ },
+ }, {
+ .id = 0x50,
+ .name = "ispwab",
+ .swgroup = TEGRA_SWGROUP_ISP2B,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x51,
+ .name = "ispwbb",
+ .swgroup = TEGRA_SWGROUP_ISP2B,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x388,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x54,
+ .name = "tsecsrd",
+ .swgroup = TEGRA_SWGROUP_TSEC,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x9b,
+ },
+ }, {
+ .id = 0x55,
+ .name = "tsecswr",
+ .swgroup = TEGRA_SWGROUP_TSEC,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x390,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x56,
+ .name = "a9avpscr",
+ .swgroup = TEGRA_SWGROUP_A9AVP,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x3a4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x57,
+ .name = "a9avpscw",
+ .swgroup = TEGRA_SWGROUP_A9AVP,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x3a4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x58,
+ .name = "gpusrd",
+ .swgroup = TEGRA_SWGROUP_GPU,
+ .smmu = {
+ /* read-only */
+ .reg = 0x230,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
+ }, {
+ .id = 0x59,
+ .name = "gpuswr",
+ .swgroup = TEGRA_SWGROUP_GPU,
+ .smmu = {
+ /* read-only */
+ .reg = 0x230,
+ .bit = 25,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x5a,
+ .name = "displayt",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x60,
+ .name = "sdmmcra",
+ .swgroup = TEGRA_SWGROUP_SDMMC1A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x3b8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
+ }, {
+ .id = 0x61,
+ .name = "sdmmcraa",
+ .swgroup = TEGRA_SWGROUP_SDMMC2A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x3bc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
+ }, {
+ .id = 0x62,
+ .name = "sdmmcr",
+ .swgroup = TEGRA_SWGROUP_SDMMC3A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x3c0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
+ }, {
+ .id = 0x63,
+ .swgroup = TEGRA_SWGROUP_SDMMC4A,
+ .name = "sdmmcrab",
+ .smmu = {
+ .reg = 0x234,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x3c4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x49,
+ },
+ }, {
+ .id = 0x64,
+ .name = "sdmmcwa",
+ .swgroup = TEGRA_SWGROUP_SDMMC1A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x3b8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x65,
+ .name = "sdmmcwaa",
+ .swgroup = TEGRA_SWGROUP_SDMMC2A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x3bc,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x66,
+ .name = "sdmmcw",
+ .swgroup = TEGRA_SWGROUP_SDMMC3A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x3c0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x67,
+ .name = "sdmmcwab",
+ .swgroup = TEGRA_SWGROUP_SDMMC4A,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x3c4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x6c,
+ .name = "vicsrd",
+ .swgroup = TEGRA_SWGROUP_VIC,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x394,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x1a,
+ },
+ }, {
+ .id = 0x6d,
+ .name = "vicswr",
+ .swgroup = TEGRA_SWGROUP_VIC,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x394,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x72,
+ .name = "viw",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x398,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x73,
+ .name = "displayd",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x234,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x3c8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ },
+};
+
+static const struct tegra_smmu_swgroup tegra124_swgroups[] = {
+ { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
+ { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
+ { .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 },
+ { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
+ { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
+ { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
+ { .swgroup = TEGRA_SWGROUP_MSENC, .reg = 0x264 },
+ { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
+ { .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x274 },
+ { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
+ { .swgroup = TEGRA_SWGROUP_ISP2, .reg = 0x258 },
+ { .swgroup = TEGRA_SWGROUP_XUSB_HOST, .reg = 0x288 },
+ { .swgroup = TEGRA_SWGROUP_XUSB_DEV, .reg = 0x28c },
+ { .swgroup = TEGRA_SWGROUP_ISP2B, .reg = 0xaa4 },
+ { .swgroup = TEGRA_SWGROUP_TSEC, .reg = 0x294 },
+ { .swgroup = TEGRA_SWGROUP_A9AVP, .reg = 0x290 },
+ { .swgroup = TEGRA_SWGROUP_GPU, .reg = 0xaac },
+ { .swgroup = TEGRA_SWGROUP_SDMMC1A, .reg = 0xa94 },
+ { .swgroup = TEGRA_SWGROUP_SDMMC2A, .reg = 0xa98 },
+ { .swgroup = TEGRA_SWGROUP_SDMMC3A, .reg = 0xa9c },
+ { .swgroup = TEGRA_SWGROUP_SDMMC4A, .reg = 0xaa0 },
+ { .swgroup = TEGRA_SWGROUP_VIC, .reg = 0x284 },
+ { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
+};
+
+#ifdef CONFIG_ARCH_TEGRA_124_SOC
+static void tegra124_flush_dcache(struct page *page, unsigned long offset,
+ size_t size)
+{
+ phys_addr_t phys = page_to_phys(page) + offset;
+ void *virt = page_address(page) + offset;
+
+ __cpuc_flush_dcache_area(virt, size);
+ outer_flush_range(phys, phys + size);
+}
+
+static const struct tegra_smmu_ops tegra124_smmu_ops = {
+ .flush_dcache = tegra124_flush_dcache,
+};
+
+static const struct tegra_smmu_soc tegra124_smmu_soc = {
+ .clients = tegra124_mc_clients,
+ .num_clients = ARRAY_SIZE(tegra124_mc_clients),
+ .swgroups = tegra124_swgroups,
+ .num_swgroups = ARRAY_SIZE(tegra124_swgroups),
+ .supports_round_robin_arbitration = true,
+ .supports_request_limit = true,
+ .num_asids = 128,
+ .ops = &tegra124_smmu_ops,
+};
+
+const struct tegra_mc_soc tegra124_mc_soc = {
+ .clients = tegra124_mc_clients,
+ .num_clients = ARRAY_SIZE(tegra124_mc_clients),
+ .num_address_bits = 34,
+ .atom_size = 32,
+ .smmu = &tegra124_smmu_soc,
+};
+#endif /* CONFIG_ARCH_TEGRA_124_SOC */
diff --git a/drivers/memory/tegra/tegra30.c b/drivers/memory/tegra/tegra30.c
new file mode 100644
index 0000000..71fe937
--- /dev/null
+++ b/drivers/memory/tegra/tegra30.c
@@ -0,0 +1,970 @@
+/*
+ * Copyright (C) 2014 NVIDIA CORPORATION. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/of.h>
+#include <linux/mm.h>
+
+#include <asm/cacheflush.h>
+
+#include <dt-bindings/memory/tegra30-mc.h>
+
+#include "mc.h"
+
+static const struct tegra_mc_client tegra30_mc_clients[] = {
+ {
+ .id = 0x00,
+ .name = "ptcr",
+ .swgroup = TEGRA_SWGROUP_PTC,
+ }, {
+ .id = 0x01,
+ .name = "display0a",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x02,
+ .name = "display0ab",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x03,
+ .name = "display0b",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x2e8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x04,
+ .name = "display0bb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x2f4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x05,
+ .name = "display0c",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x06,
+ .name = "display0cb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 6,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x07,
+ .name = "display1b",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 7,
+ },
+ .la = {
+ .reg = 0x2ec,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x08,
+ .name = "display1bb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x2f8,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x4e,
+ },
+ }, {
+ .id = 0x09,
+ .name = "eppup",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x17,
+ },
+ }, {
+ .id = 0x0a,
+ .name = "g2pr",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x09,
+ },
+ }, {
+ .id = 0x0b,
+ .name = "g2sr",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x308,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x09,
+ },
+ }, {
+ .id = 0x0c,
+ .name = "mpeunifbr",
+ .swgroup = TEGRA_SWGROUP_MPE,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x0d,
+ .name = "viruv",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x364,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x2c,
+ },
+ }, {
+ .id = 0x0e,
+ .name = "afir",
+ .swgroup = TEGRA_SWGROUP_AFI,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x0f,
+ .name = "avpcarm7r",
+ .swgroup = TEGRA_SWGROUP_AVPC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x10,
+ .name = "displayhc",
+ .swgroup = TEGRA_SWGROUP_DC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x2f0,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x11,
+ .name = "displayhcb",
+ .swgroup = TEGRA_SWGROUP_DCB,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2fc,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x12,
+ .name = "fdcdrd",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
+ }, {
+ .id = 0x13,
+ .name = "fdcdrd2",
+ .swgroup = TEGRA_SWGROUP_NV2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x33c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
+ }, {
+ .id = 0x14,
+ .name = "g2dr",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
+ }, {
+ .id = 0x15,
+ .name = "hdar",
+ .swgroup = TEGRA_SWGROUP_HDA,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x16,
+ .name = "host1xdmar",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x05,
+ },
+ }, {
+ .id = 0x17,
+ .name = "host1xr",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x310,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x50,
+ },
+ }, {
+ .id = 0x18,
+ .name = "idxsrd",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 24,
+ },
+ .la = {
+ .reg = 0x334,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x13,
+ },
+ }, {
+ .id = 0x19,
+ .name = "idxsrd2",
+ .swgroup = TEGRA_SWGROUP_NV2,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 25,
+ },
+ .la = {
+ .reg = 0x33c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x13,
+ },
+ }, {
+ .id = 0x1a,
+ .name = "mpe_ipred",
+ .swgroup = TEGRA_SWGROUP_MPE,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x328,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x80,
+ },
+ }, {
+ .id = 0x1b,
+ .name = "mpeamemrd",
+ .swgroup = TEGRA_SWGROUP_MPE,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x32c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x42,
+ },
+ }, {
+ .id = 0x1c,
+ .name = "mpecsrd",
+ .swgroup = TEGRA_SWGROUP_MPE,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x32c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x1d,
+ .name = "ppcsahbdmar",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x1e,
+ .name = "ppcsahbslvr",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x344,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x12,
+ },
+ }, {
+ .id = 0x1f,
+ .name = "satar",
+ .swgroup = TEGRA_SWGROUP_SATA,
+ .smmu = {
+ .reg = 0x228,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x33,
+ },
+ }, {
+ .id = 0x20,
+ .name = "texsrd",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
+ }, {
+ .id = 0x21,
+ .name = "texsrd2",
+ .swgroup = TEGRA_SWGROUP_NV2,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x340,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
+ }, {
+ .id = 0x22,
+ .name = "vdebsevr",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 2,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x23,
+ .name = "vdember",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 3,
+ },
+ .la = {
+ .reg = 0x354,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xd0,
+ },
+ }, {
+ .id = 0x24,
+ .name = "vdemcer",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 4,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x2a,
+ },
+ }, {
+ .id = 0x25,
+ .name = "vdetper",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 5,
+ },
+ .la = {
+ .reg = 0x358,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x74,
+ },
+ }, {
+ .id = 0x26,
+ .name = "mpcorelpr",
+ .swgroup = TEGRA_SWGROUP_MPCORELP,
+ .la = {
+ .reg = 0x324,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x27,
+ .name = "mpcorer",
+ .swgroup = TEGRA_SWGROUP_MPCORE,
+ .la = {
+ .reg = 0x320,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x04,
+ },
+ }, {
+ .id = 0x28,
+ .name = "eppu",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 8,
+ },
+ .la = {
+ .reg = 0x300,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
+ }, {
+ .id = 0x29,
+ .name = "eppv",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 9,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
+ }, {
+ .id = 0x2a,
+ .name = "eppy",
+ .swgroup = TEGRA_SWGROUP_EPP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 10,
+ },
+ .la = {
+ .reg = 0x304,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x6c,
+ },
+ }, {
+ .id = 0x2b,
+ .name = "mpeunifbw",
+ .swgroup = TEGRA_SWGROUP_MPE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 11,
+ },
+ .la = {
+ .reg = 0x330,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x13,
+ },
+ }, {
+ .id = 0x2c,
+ .name = "viwsb",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 12,
+ },
+ .la = {
+ .reg = 0x364,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x12,
+ },
+ }, {
+ .id = 0x2d,
+ .name = "viwu",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 13,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xb2,
+ },
+ }, {
+ .id = 0x2e,
+ .name = "viwv",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 14,
+ },
+ .la = {
+ .reg = 0x368,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xb2,
+ },
+ }, {
+ .id = 0x2f,
+ .name = "viwy",
+ .swgroup = TEGRA_SWGROUP_VI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 15,
+ },
+ .la = {
+ .reg = 0x36c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x12,
+ },
+ }, {
+ .id = 0x30,
+ .name = "g2dw",
+ .swgroup = TEGRA_SWGROUP_G2,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 16,
+ },
+ .la = {
+ .reg = 0x30c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x9,
+ },
+ }, {
+ .id = 0x31,
+ .name = "afiw",
+ .swgroup = TEGRA_SWGROUP_AFI,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 17,
+ },
+ .la = {
+ .reg = 0x2e0,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0c,
+ },
+ }, {
+ .id = 0x32,
+ .name = "avpcarm7w",
+ .swgroup = TEGRA_SWGROUP_AVPC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 18,
+ },
+ .la = {
+ .reg = 0x2e4,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
+ }, {
+ .id = 0x33,
+ .name = "fdcdwr",
+ .swgroup = TEGRA_SWGROUP_NV,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 19,
+ },
+ .la = {
+ .reg = 0x338,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
+ }, {
+ .id = 0x34,
+ .name = "fdcwr2",
+ .swgroup = TEGRA_SWGROUP_NV2,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 20,
+ },
+ .la = {
+ .reg = 0x340,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0a,
+ },
+ }, {
+ .id = 0x35,
+ .name = "hdaw",
+ .swgroup = TEGRA_SWGROUP_HDA,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 21,
+ },
+ .la = {
+ .reg = 0x318,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x36,
+ .name = "host1xw",
+ .swgroup = TEGRA_SWGROUP_HC,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 22,
+ },
+ .la = {
+ .reg = 0x314,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x37,
+ .name = "ispw",
+ .swgroup = TEGRA_SWGROUP_ISP,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 23,
+ },
+ .la = {
+ .reg = 0x31c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x38,
+ .name = "mpcorelpw",
+ .swgroup = TEGRA_SWGROUP_MPCORELP,
+ .la = {
+ .reg = 0x324,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
+ }, {
+ .id = 0x39,
+ .name = "mpcorew",
+ .swgroup = TEGRA_SWGROUP_MPCORE,
+ .la = {
+ .reg = 0x320,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x0e,
+ },
+ }, {
+ .id = 0x3a,
+ .name = "mpecswr",
+ .swgroup = TEGRA_SWGROUP_MPE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 26,
+ },
+ .la = {
+ .reg = 0x330,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x3b,
+ .name = "ppcsahbdmaw",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 27,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x10,
+ },
+ }, {
+ .id = 0x3c,
+ .name = "ppcsahbslvw",
+ .swgroup = TEGRA_SWGROUP_PPCS,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 28,
+ },
+ .la = {
+ .reg = 0x348,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x06,
+ },
+ }, {
+ .id = 0x3d,
+ .name = "sataw",
+ .swgroup = TEGRA_SWGROUP_SATA,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 29,
+ },
+ .la = {
+ .reg = 0x350,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x33,
+ },
+ }, {
+ .id = 0x3e,
+ .name = "vdebsevw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 30,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x3f,
+ .name = "vdedbgw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x22c,
+ .bit = 31,
+ },
+ .la = {
+ .reg = 0x35c,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0xff,
+ },
+ }, {
+ .id = 0x40,
+ .name = "vdembew",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 0,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 0,
+ .mask = 0xff,
+ .def = 0x42,
+ },
+ }, {
+ .id = 0x41,
+ .name = "vdetpmw",
+ .swgroup = TEGRA_SWGROUP_VDE,
+ .smmu = {
+ .reg = 0x230,
+ .bit = 1,
+ },
+ .la = {
+ .reg = 0x360,
+ .shift = 16,
+ .mask = 0xff,
+ .def = 0x2a,
+ },
+ },
+};
+
+static const struct tegra_smmu_swgroup tegra30_swgroups[] = {
+ { .swgroup = TEGRA_SWGROUP_DC, .reg = 0x240 },
+ { .swgroup = TEGRA_SWGROUP_DCB, .reg = 0x244 },
+ { .swgroup = TEGRA_SWGROUP_EPP, .reg = 0x248 },
+ { .swgroup = TEGRA_SWGROUP_G2, .reg = 0x24c },
+ { .swgroup = TEGRA_SWGROUP_MPE, .reg = 0x264 },
+ { .swgroup = TEGRA_SWGROUP_VI, .reg = 0x280 },
+ { .swgroup = TEGRA_SWGROUP_AFI, .reg = 0x238 },
+ { .swgroup = TEGRA_SWGROUP_AVPC, .reg = 0x23c },
+ { .swgroup = TEGRA_SWGROUP_NV, .reg = 0x268 },
+ { .swgroup = TEGRA_SWGROUP_NV2, .reg = 0x26c },
+ { .swgroup = TEGRA_SWGROUP_HDA, .reg = 0x254 },
+ { .swgroup = TEGRA_SWGROUP_HC, .reg = 0x250 },
+ { .swgroup = TEGRA_SWGROUP_PPCS, .reg = 0x270 },
+ { .swgroup = TEGRA_SWGROUP_SATA, .reg = 0x278 },
+ { .swgroup = TEGRA_SWGROUP_VDE, .reg = 0x27c },
+ { .swgroup = TEGRA_SWGROUP_ISP, .reg = 0x258 },
+};
+
+static void tegra30_flush_dcache(struct page *page, unsigned long offset,
+ size_t size)
+{
+ phys_addr_t phys = page_to_phys(page) + offset;
+ void *virt = page_address(page) + offset;
+
+ __cpuc_flush_dcache_area(virt, size);
+ outer_flush_range(phys, phys + size);
+}
+
+static const struct tegra_smmu_ops tegra30_smmu_ops = {
+ .flush_dcache = tegra30_flush_dcache,
+};
+
+static const struct tegra_smmu_soc tegra30_smmu_soc = {
+ .clients = tegra30_mc_clients,
+ .num_clients = ARRAY_SIZE(tegra30_mc_clients),
+ .swgroups = tegra30_swgroups,
+ .num_swgroups = ARRAY_SIZE(tegra30_swgroups),
+ .supports_round_robin_arbitration = false,
+ .supports_request_limit = false,
+ .num_asids = 4,
+ .ops = &tegra30_smmu_ops,
+};
+
+const struct tegra_mc_soc tegra30_mc_soc = {
+ .clients = tegra30_mc_clients,
+ .num_clients = ARRAY_SIZE(tegra30_mc_clients),
+ .num_address_bits = 32,
+ .atom_size = 16,
+ .smmu = &tegra30_smmu_soc,
+};
diff --git a/drivers/memory/tegra30-mc.c b/drivers/memory/tegra30-mc.c
deleted file mode 100644
index ef79345..0000000
--- a/drivers/memory/tegra30-mc.c
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * Tegra30 Memory Controller
- *
- * Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms and conditions of the GNU General Public License,
- * version 2, as published by the Free Software Foundation.
- *
- * This program is distributed in the hope it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
- * more details.
- *
- * You should have received a copy of the GNU General Public License along with
- * this program; if not, write to the Free Software Foundation, Inc.,
- * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
- */
-
-#include <linux/err.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/ratelimit.h>
-#include <linux/platform_device.h>
-#include <linux/interrupt.h>
-#include <linux/io.h>
-
-#define DRV_NAME "tegra30-mc"
-
-#define MC_INTSTATUS 0x0
-#define MC_INTMASK 0x4
-
-#define MC_INT_ERR_SHIFT 6
-#define MC_INT_ERR_MASK (0x1f << MC_INT_ERR_SHIFT)
-#define MC_INT_DECERR_EMEM BIT(MC_INT_ERR_SHIFT)
-#define MC_INT_SECURITY_VIOLATION BIT(MC_INT_ERR_SHIFT + 2)
-#define MC_INT_ARBITRATION_EMEM BIT(MC_INT_ERR_SHIFT + 3)
-#define MC_INT_INVALID_SMMU_PAGE BIT(MC_INT_ERR_SHIFT + 4)
-
-#define MC_ERR_STATUS 0x8
-#define MC_ERR_ADR 0xc
-
-#define MC_ERR_TYPE_SHIFT 28
-#define MC_ERR_TYPE_MASK (7 << MC_ERR_TYPE_SHIFT)
-#define MC_ERR_TYPE_DECERR_EMEM 2
-#define MC_ERR_TYPE_SECURITY_TRUSTZONE 3
-#define MC_ERR_TYPE_SECURITY_CARVEOUT 4
-#define MC_ERR_TYPE_INVALID_SMMU_PAGE 6
-
-#define MC_ERR_INVALID_SMMU_PAGE_SHIFT 25
-#define MC_ERR_INVALID_SMMU_PAGE_MASK (7 << MC_ERR_INVALID_SMMU_PAGE_SHIFT)
-#define MC_ERR_RW_SHIFT 16
-#define MC_ERR_RW BIT(MC_ERR_RW_SHIFT)
-#define MC_ERR_SECURITY BIT(MC_ERR_RW_SHIFT + 1)
-
-#define SECURITY_VIOLATION_TYPE BIT(30) /* 0=TRUSTZONE, 1=CARVEOUT */
-
-#define MC_EMEM_ARB_CFG 0x90
-#define MC_EMEM_ARB_OUTSTANDING_REQ 0x94
-#define MC_EMEM_ARB_TIMING_RCD 0x98
-#define MC_EMEM_ARB_TIMING_RP 0x9c
-#define MC_EMEM_ARB_TIMING_RC 0xa0
-#define MC_EMEM_ARB_TIMING_RAS 0xa4
-#define MC_EMEM_ARB_TIMING_FAW 0xa8
-#define MC_EMEM_ARB_TIMING_RRD 0xac
-#define MC_EMEM_ARB_TIMING_RAP2PRE 0xb0
-#define MC_EMEM_ARB_TIMING_WAP2PRE 0xb4
-#define MC_EMEM_ARB_TIMING_R2R 0xb8
-#define MC_EMEM_ARB_TIMING_W2W 0xbc
-#define MC_EMEM_ARB_TIMING_R2W 0xc0
-#define MC_EMEM_ARB_TIMING_W2R 0xc4
-
-#define MC_EMEM_ARB_DA_TURNS 0xd0
-#define MC_EMEM_ARB_DA_COVERS 0xd4
-#define MC_EMEM_ARB_MISC0 0xd8
-#define MC_EMEM_ARB_MISC1 0xdc
-
-#define MC_EMEM_ARB_RING3_THROTTLE 0xe4
-#define MC_EMEM_ARB_OVERRIDE 0xe8
-
-#define MC_TIMING_CONTROL 0xfc
-
-#define MC_CLIENT_ID_MASK 0x7f
-
-#define NUM_MC_REG_BANKS 4
-
-struct tegra30_mc {
- void __iomem *regs[NUM_MC_REG_BANKS];
- struct device *dev;
- u32 ctx[0];
-};
-
-static inline u32 mc_readl(struct tegra30_mc *mc, u32 offs)
-{
- u32 val = 0;
-
- if (offs < 0x10)
- val = readl(mc->regs[0] + offs);
- else if (offs < 0x1f0)
- val = readl(mc->regs[1] + offs - 0x3c);
- else if (offs < 0x228)
- val = readl(mc->regs[2] + offs - 0x200);
- else if (offs < 0x400)
- val = readl(mc->regs[3] + offs - 0x284);
-
- return val;
-}
-
-static inline void mc_writel(struct tegra30_mc *mc, u32 val, u32 offs)
-{
- if (offs < 0x10)
- writel(val, mc->regs[0] + offs);
- else if (offs < 0x1f0)
- writel(val, mc->regs[1] + offs - 0x3c);
- else if (offs < 0x228)
- writel(val, mc->regs[2] + offs - 0x200);
- else if (offs < 0x400)
- writel(val, mc->regs[3] + offs - 0x284);
-}
-
-static const char * const tegra30_mc_client[] = {
- "csr_ptcr",
- "cbr_display0a",
- "cbr_display0ab",
- "cbr_display0b",
- "cbr_display0bb",
- "cbr_display0c",
- "cbr_display0cb",
- "cbr_display1b",
- "cbr_display1bb",
- "cbr_eppup",
- "cbr_g2pr",
- "cbr_g2sr",
- "cbr_mpeunifbr",
- "cbr_viruv",
- "csr_afir",
- "csr_avpcarm7r",
- "csr_displayhc",
- "csr_displayhcb",
- "csr_fdcdrd",
- "csr_fdcdrd2",
- "csr_g2dr",
- "csr_hdar",
- "csr_host1xdmar",
- "csr_host1xr",
- "csr_idxsrd",
- "csr_idxsrd2",
- "csr_mpe_ipred",
- "csr_mpeamemrd",
- "csr_mpecsrd",
- "csr_ppcsahbdmar",
- "csr_ppcsahbslvr",
- "csr_satar",
- "csr_texsrd",
- "csr_texsrd2",
- "csr_vdebsevr",
- "csr_vdember",
- "csr_vdemcer",
- "csr_vdetper",
- "csr_mpcorelpr",
- "csr_mpcorer",
- "cbw_eppu",
- "cbw_eppv",
- "cbw_eppy",
- "cbw_mpeunifbw",
- "cbw_viwsb",
- "cbw_viwu",
- "cbw_viwv",
- "cbw_viwy",
- "ccw_g2dw",
- "csw_afiw",
- "csw_avpcarm7w",
- "csw_fdcdwr",
- "csw_fdcdwr2",
- "csw_hdaw",
- "csw_host1xw",
- "csw_ispw",
- "csw_mpcorelpw",
- "csw_mpcorew",
- "csw_mpecswr",
- "csw_ppcsahbdmaw",
- "csw_ppcsahbslvw",
- "csw_sataw",
- "csw_vdebsevw",
- "csw_vdedbgw",
- "csw_vdembew",
- "csw_vdetpmw",
-};
-
-static void tegra30_mc_decode(struct tegra30_mc *mc, int n)
-{
- u32 err, addr;
- const char * const mc_int_err[] = {
- "MC_DECERR",
- "Unknown",
- "MC_SECURITY_ERR",
- "MC_ARBITRATION_EMEM",
- "MC_SMMU_ERR",
- };
- const char * const err_type[] = {
- "Unknown",
- "Unknown",
- "DECERR_EMEM",
- "SECURITY_TRUSTZONE",
- "SECURITY_CARVEOUT",
- "Unknown",
- "INVALID_SMMU_PAGE",
- "Unknown",
- };
- char attr[6];
- int cid, perm, type, idx;
- const char *client = "Unknown";
-
- idx = n - MC_INT_ERR_SHIFT;
- if ((idx < 0) || (idx >= ARRAY_SIZE(mc_int_err)) || (idx == 1)) {
- dev_err_ratelimited(mc->dev, "Unknown interrupt status %08lx\n",
- BIT(n));
- return;
- }
-
- err = mc_readl(mc, MC_ERR_STATUS);
-
- type = (err & MC_ERR_TYPE_MASK) >> MC_ERR_TYPE_SHIFT;
- perm = (err & MC_ERR_INVALID_SMMU_PAGE_MASK) >>
- MC_ERR_INVALID_SMMU_PAGE_SHIFT;
- if (type == MC_ERR_TYPE_INVALID_SMMU_PAGE)
- sprintf(attr, "%c-%c-%c",
- (perm & BIT(2)) ? 'R' : '-',
- (perm & BIT(1)) ? 'W' : '-',
- (perm & BIT(0)) ? 'S' : '-');
- else
- attr[0] = '\0';
-
- cid = err & MC_CLIENT_ID_MASK;
- if (cid < ARRAY_SIZE(tegra30_mc_client))
- client = tegra30_mc_client[cid];
-
- addr = mc_readl(mc, MC_ERR_ADR);
-
- dev_err_ratelimited(mc->dev, "%s (0x%08x): 0x%08x %s (%s %s %s %s)\n",
- mc_int_err[idx], err, addr, client,
- (err & MC_ERR_SECURITY) ? "secure" : "non-secure",
- (err & MC_ERR_RW) ? "write" : "read",
- err_type[type], attr);
-}
-
-static const u32 tegra30_mc_ctx[] = {
- MC_EMEM_ARB_CFG,
- MC_EMEM_ARB_OUTSTANDING_REQ,
- MC_EMEM_ARB_TIMING_RCD,
- MC_EMEM_ARB_TIMING_RP,
- MC_EMEM_ARB_TIMING_RC,
- MC_EMEM_ARB_TIMING_RAS,
- MC_EMEM_ARB_TIMING_FAW,
- MC_EMEM_ARB_TIMING_RRD,
- MC_EMEM_ARB_TIMING_RAP2PRE,
- MC_EMEM_ARB_TIMING_WAP2PRE,
- MC_EMEM_ARB_TIMING_R2R,
- MC_EMEM_ARB_TIMING_W2W,
- MC_EMEM_ARB_TIMING_R2W,
- MC_EMEM_ARB_TIMING_W2R,
- MC_EMEM_ARB_DA_TURNS,
- MC_EMEM_ARB_DA_COVERS,
- MC_EMEM_ARB_MISC0,
- MC_EMEM_ARB_MISC1,
- MC_EMEM_ARB_RING3_THROTTLE,
- MC_EMEM_ARB_OVERRIDE,
- MC_INTMASK,
-};
-
-#ifdef CONFIG_PM
-static int tegra30_mc_suspend(struct device *dev)
-{
- int i;
- struct tegra30_mc *mc = dev_get_drvdata(dev);
-
- for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
- mc->ctx[i] = mc_readl(mc, tegra30_mc_ctx[i]);
- return 0;
-}
-
-static int tegra30_mc_resume(struct device *dev)
-{
- int i;
- struct tegra30_mc *mc = dev_get_drvdata(dev);
-
- for (i = 0; i < ARRAY_SIZE(tegra30_mc_ctx); i++)
- mc_writel(mc, mc->ctx[i], tegra30_mc_ctx[i]);
-
- mc_writel(mc, 1, MC_TIMING_CONTROL);
- /* Read-back to ensure that write reached */
- mc_readl(mc, MC_TIMING_CONTROL);
- return 0;
-}
-#endif
-
-static UNIVERSAL_DEV_PM_OPS(tegra30_mc_pm,
- tegra30_mc_suspend,
- tegra30_mc_resume, NULL);
-
-static const struct of_device_id tegra30_mc_of_match[] = {
- { .compatible = "nvidia,tegra30-mc", },
- {},
-};
-
-static irqreturn_t tegra30_mc_isr(int irq, void *data)
-{
- u32 stat, mask, bit;
- struct tegra30_mc *mc = data;
-
- stat = mc_readl(mc, MC_INTSTATUS);
- mask = mc_readl(mc, MC_INTMASK);
- mask &= stat;
- if (!mask)
- return IRQ_NONE;
- while ((bit = ffs(mask)) != 0) {
- tegra30_mc_decode(mc, bit - 1);
- mask &= ~BIT(bit - 1);
- }
-
- mc_writel(mc, stat, MC_INTSTATUS);
- return IRQ_HANDLED;
-}
-
-static int tegra30_mc_probe(struct platform_device *pdev)
-{
- struct resource *irq;
- struct tegra30_mc *mc;
- size_t bytes;
- int err, i;
- u32 intmask;
-
- bytes = sizeof(*mc) + sizeof(u32) * ARRAY_SIZE(tegra30_mc_ctx);
- mc = devm_kzalloc(&pdev->dev, bytes, GFP_KERNEL);
- if (!mc)
- return -ENOMEM;
- mc->dev = &pdev->dev;
-
- for (i = 0; i < ARRAY_SIZE(mc->regs); i++) {
- struct resource *res;
-
- res = platform_get_resource(pdev, IORESOURCE_MEM, i);
- mc->regs[i] = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(mc->regs[i]))
- return PTR_ERR(mc->regs[i]);
- }
-
- irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
- if (!irq)
- return -ENODEV;
- err = devm_request_irq(&pdev->dev, irq->start, tegra30_mc_isr,
- IRQF_SHARED, dev_name(&pdev->dev), mc);
- if (err)
- return -ENODEV;
-
- platform_set_drvdata(pdev, mc);
-
- intmask = MC_INT_INVALID_SMMU_PAGE |
- MC_INT_DECERR_EMEM | MC_INT_SECURITY_VIOLATION;
- mc_writel(mc, intmask, MC_INTMASK);
- return 0;
-}
-
-static struct platform_driver tegra30_mc_driver = {
- .probe = tegra30_mc_probe,
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- .of_match_table = tegra30_mc_of_match,
- .pm = &tegra30_mc_pm,
- },
-};
-module_platform_driver(tegra30_mc_driver);
-
-MODULE_AUTHOR("Hiroshi DOYU <hdoyu@nvidia.com>");
-MODULE_DESCRIPTION("Tegra30 MC driver");
-MODULE_LICENSE("GPL v2");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/drivers/message/fusion/mptsas.c b/drivers/message/fusion/mptsas.c
index 0707fa2..5bdaae1 100644
--- a/drivers/message/fusion/mptsas.c
+++ b/drivers/message/fusion/mptsas.c
@@ -1994,6 +1994,7 @@ static struct scsi_host_template mptsas_driver_template = {
.cmd_per_lun = 7,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = mptscsih_host_attrs,
+ .use_blk_tags = 1,
};
static int mptsas_get_linkerrors(struct sas_phy *phy)
diff --git a/drivers/message/fusion/mptscsih.c b/drivers/message/fusion/mptscsih.c
index e7dcb25..6c9fc11 100644
--- a/drivers/message/fusion/mptscsih.c
+++ b/drivers/message/fusion/mptscsih.c
@@ -2311,26 +2311,21 @@ mptscsih_slave_destroy(struct scsi_device *sdev)
* mptscsih_change_queue_depth - This function will set a devices queue depth
* @sdev: per scsi_device pointer
* @qdepth: requested queue depth
- * @reason: calling context
*
* Adding support for new 'change_queue_depth' api.
*/
int
-mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
+mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
MPT_SCSI_HOST *hd = shost_priv(sdev->host);
VirtTarget *vtarget;
struct scsi_target *starget;
int max_depth;
- int tagged;
MPT_ADAPTER *ioc = hd->ioc;
starget = scsi_target(sdev);
vtarget = starget->hostdata;
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (ioc->bus_type == SPI) {
if (!(vtarget->tflags & MPT_TARGET_FLAGS_Q_YES))
max_depth = 1;
@@ -2347,13 +2342,8 @@ mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
if (qdepth > max_depth)
qdepth = max_depth;
- if (qdepth == 1)
- tagged = 0;
- else
- tagged = MSG_SIMPLE_TAG;
- scsi_adjust_queue_depth(sdev, tagged, qdepth);
- return sdev->queue_depth;
+ return scsi_change_queue_depth(sdev, qdepth);
}
/*
@@ -2397,12 +2387,10 @@ mptscsih_slave_configure(struct scsi_device *sdev)
ioc->name, vtarget->negoFlags, vtarget->maxOffset,
vtarget->minSyncFactor));
- mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH,
- SCSI_QDEPTH_DEFAULT);
+ mptscsih_change_queue_depth(sdev, MPT_SCSI_CMD_PER_DEV_HIGH);
dsprintk(ioc, printk(MYIOC_s_DEBUG_FMT
- "tagged %d, simple %d, ordered %d\n",
- ioc->name,sdev->tagged_supported, sdev->simple_tags,
- sdev->ordered_tags));
+ "tagged %d, simple %d\n",
+ ioc->name,sdev->tagged_supported, sdev->simple_tags));
blk_queue_dma_alignment (sdev->request_queue, 512 - 1);
diff --git a/drivers/message/fusion/mptscsih.h b/drivers/message/fusion/mptscsih.h
index e1b1a19..2baeefd 100644
--- a/drivers/message/fusion/mptscsih.h
+++ b/drivers/message/fusion/mptscsih.h
@@ -128,8 +128,7 @@ extern int mptscsih_taskmgmt_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_F
extern int mptscsih_scandv_complete(MPT_ADAPTER *ioc, MPT_FRAME_HDR *mf, MPT_FRAME_HDR *r);
extern int mptscsih_event_process(MPT_ADAPTER *ioc, EventNotificationReply_t *pEvReply);
extern int mptscsih_ioc_reset(MPT_ADAPTER *ioc, int post_reset);
-extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason);
+extern int mptscsih_change_queue_depth(struct scsi_device *sdev, int qdepth);
extern u8 mptscsih_raid_id_to_num(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern int mptscsih_is_phys_disk(MPT_ADAPTER *ioc, u8 channel, u8 id);
extern struct device_attribute *mptscsih_host_attrs[];
diff --git a/drivers/mfd/Kconfig b/drivers/mfd/Kconfig
index 1456ea7..2e6b731 100644
--- a/drivers/mfd/Kconfig
+++ b/drivers/mfd/Kconfig
@@ -59,6 +59,17 @@ config MFD_AAT2870_CORE
additional drivers must be enabled in order to use the
functionality of the device.
+config MFD_ATMEL_HLCDC
+ tristate "Atmel HLCDC (High-end LCD Controller)"
+ select MFD_CORE
+ select REGMAP_MMIO
+ depends on OF
+ help
+ If you say yes here you get support for the HLCDC block.
+ This driver provides common support for accessing the device,
+ additional drivers must be enabled in order to use the
+ functionality of the device.
+
config MFD_BCM590XX
tristate "Broadcom BCM590xx PMUs"
select MFD_CORE
@@ -74,7 +85,8 @@ config MFD_AXP20X
select REGMAP_IRQ
depends on I2C=y
help
- If you say Y here you get support for the X-Powers AXP202 and AXP209.
+ If you say Y here you get support for the X-Powers AXP202, AXP209 and
+ AXP288 power management IC (PMIC).
This driver include only the core APIs. You have to select individual
components like regulators or the PEK (Power Enable Key) under the
corresponding menus.
@@ -183,6 +195,16 @@ config MFD_DA9063
Additional drivers must be enabled in order to use the functionality
of the device.
+config MFD_DLN2
+ tristate "Diolan DLN2 support"
+ select MFD_CORE
+ depends on USB
+ help
+ This adds support for Diolan USB-I2C/SPI/GPIO Master Adapter
+ DLN-2. Additional drivers such as I2C_DLN2, GPIO_DLN2,
+ etc. must be enabled in order to use the functionality of
+ the device.
+
config MFD_MC13XXX
tristate
depends on (SPI_MASTER || I2C)
@@ -655,7 +677,6 @@ config MFD_SEC_CORE
select MFD_CORE
select REGMAP_I2C
select REGMAP_IRQ
- select REGULATOR
help
Support for the Samsung Electronics MFD series.
This driver provides common support for accessing the device,
diff --git a/drivers/mfd/Makefile b/drivers/mfd/Makefile
index 8bd54b1..53467e2 100644
--- a/drivers/mfd/Makefile
+++ b/drivers/mfd/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_MFD_CROS_EC) += cros_ec.o
obj-$(CONFIG_MFD_CROS_EC_I2C) += cros_ec_i2c.o
obj-$(CONFIG_MFD_CROS_EC_SPI) += cros_ec_spi.o
-rtsx_pci-objs := rtsx_pcr.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
+rtsx_pci-objs := rtsx_pcr.o rtsx_gops.o rts5209.o rts5229.o rtl8411.o rts5227.o rts5249.o
obj-$(CONFIG_MFD_RTSX_PCI) += rtsx_pci.o
obj-$(CONFIG_MFD_RTSX_USB) += rtsx_usb.o
@@ -157,6 +157,7 @@ obj-$(CONFIG_MFD_SPMI_PMIC) += qcom-spmi-pmic.o
obj-$(CONFIG_TPS65911_COMPARATOR) += tps65911-comparator.o
obj-$(CONFIG_MFD_TPS65090) += tps65090.o
obj-$(CONFIG_MFD_AAT2870_CORE) += aat2870-core.o
+obj-$(CONFIG_MFD_ATMEL_HLCDC) += atmel-hlcdc.o
obj-$(CONFIG_MFD_INTEL_MSIC) += intel_msic.o
obj-$(CONFIG_MFD_PALMAS) += palmas.o
obj-$(CONFIG_MFD_VIPERBOARD) += viperboard.o
@@ -174,6 +175,7 @@ obj-$(CONFIG_MFD_STW481X) += stw481x.o
obj-$(CONFIG_MFD_IPAQ_MICRO) += ipaq-micro.o
obj-$(CONFIG_MFD_MENF21BMC) += menf21bmc.o
obj-$(CONFIG_MFD_HI6421_PMIC) += hi6421-pmic-core.o
+obj-$(CONFIG_MFD_DLN2) += dln2.o
intel-soc-pmic-objs := intel_soc_pmic_core.o intel_soc_pmic_crc.o
obj-$(CONFIG_INTEL_SOC_PMIC) += intel-soc-pmic.o
diff --git a/drivers/mfd/ab8500-gpadc.c b/drivers/mfd/ab8500-gpadc.c
index 36000f9..8e3168d 100644
--- a/drivers/mfd/ab8500-gpadc.c
+++ b/drivers/mfd/ab8500-gpadc.c
@@ -867,7 +867,7 @@ static void ab8500_gpadc_read_calibration_data(struct ab8500_gpadc *gpadc)
gpadc->cal_data[ADC_INPUT_VBAT].offset);
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int ab8500_gpadc_runtime_suspend(struct device *dev)
{
struct ab8500_gpadc *gpadc = dev_get_drvdata(dev);
diff --git a/drivers/mfd/ab8500-sysctrl.c b/drivers/mfd/ab8500-sysctrl.c
index 8e0dae5..94dbcdd 100644
--- a/drivers/mfd/ab8500-sysctrl.c
+++ b/drivers/mfd/ab8500-sysctrl.c
@@ -85,63 +85,6 @@ shutdown:
}
}
-/*
- * Use the AB WD to reset the platform. It will perform a hard
- * reset instead of a soft reset. Write the reset reason to
- * the AB before reset, which can be read upon restart.
- */
-void ab8500_restart(char mode, const char *cmd)
-{
- struct ab8500_platform_data *plat;
- struct ab8500_sysctrl_platform_data *pdata;
- u16 reason = 0;
- u8 val;
-
- if (sysctrl_dev == NULL) {
- pr_err("%s: sysctrl not initialized\n", __func__);
- return;
- }
-
- plat = dev_get_platdata(sysctrl_dev->parent);
- pdata = plat->sysctrl;
- if (pdata && pdata->reboot_reason_code)
- reason = pdata->reboot_reason_code(cmd);
- else
- pr_warn("[%s] No reboot reason set. Default reason %d\n",
- __func__, reason);
-
- /*
- * Disable RTC alarm, just a precaution so that no alarm
- * is running when WD reset is executed.
- */
- abx500_get_register_interruptible(sysctrl_dev, AB8500_RTC,
- RTC_CTRL , &val);
- abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
- RTC_CTRL , (val & ~RTC_ALARM_ENABLE));
-
- /*
- * Android is not using the RTC alarm registers during reboot
- * so we borrow them for writing the reason of reset
- */
-
- /* reason[8 LSB] */
- val = reason & 0xFF;
- abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
- AB8500_ALARM_MIN_LOW , val);
-
- /* reason[8 MSB] */
- val = (reason>>8) & 0xFF;
- abx500_set_register_interruptible(sysctrl_dev, AB8500_RTC,
- AB8500_ALARM_MIN_MID , val);
-
- /* Setting WD timeout to 0 */
- ab8500_sysctrl_write(AB8500_MAINWDOGTIMER, 0xFF, 0x0);
-
- /* Setting the parameters to AB8500 WD*/
- ab8500_sysctrl_write(AB8500_MAINWDOGCTRL, 0xFF, (AB8500_ENABLE_WD |
- AB8500_WD_RESTART_ON_EXPIRE | AB8500_KICK_WD));
-}
-
static inline bool valid_bank(u8 bank)
{
return ((bank == AB8500_SYS_CTRL1_BLOCK) ||
diff --git a/drivers/mfd/arizona-core.c b/drivers/mfd/arizona-core.c
index bce7c07..09ba8f1 100644
--- a/drivers/mfd/arizona-core.c
+++ b/drivers/mfd/arizona-core.c
@@ -330,7 +330,7 @@ err_fll:
return err;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int arizona_runtime_resume(struct device *dev)
{
struct arizona *arizona = dev_get_drvdata(dev);
@@ -1024,7 +1024,7 @@ int arizona_dev_init(struct arizona *arizona)
goto err_irq;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
regulator_disable(arizona->dcvdd);
#endif
diff --git a/drivers/mfd/arizona-spi.c b/drivers/mfd/arizona-spi.c
index 5145d78..8ef58bc 100644
--- a/drivers/mfd/arizona-spi.c
+++ b/drivers/mfd/arizona-spi.c
@@ -75,7 +75,9 @@ static int arizona_spi_probe(struct spi_device *spi)
static int arizona_spi_remove(struct spi_device *spi)
{
struct arizona *arizona = spi_get_drvdata(spi);
+
arizona_dev_exit(arizona);
+
return 0;
}
diff --git a/drivers/mfd/atmel-hlcdc.c b/drivers/mfd/atmel-hlcdc.c
new file mode 100644
index 0000000..cfd58f4
--- /dev/null
+++ b/drivers/mfd/atmel-hlcdc.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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/clk.h>
+#include <linux/mfd/atmel-hlcdc.h>
+#include <linux/mfd/core.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_REG_MAX (0x4000 - 0x4)
+
+static const struct mfd_cell atmel_hlcdc_cells[] = {
+ {
+ .name = "atmel-hlcdc-pwm",
+ .of_compatible = "atmel,hlcdc-pwm",
+ },
+ {
+ .name = "atmel-hlcdc-dc",
+ .of_compatible = "atmel,hlcdc-display-controller",
+ },
+};
+
+static const struct regmap_config atmel_hlcdc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = ATMEL_HLCDC_REG_MAX,
+};
+
+static int atmel_hlcdc_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct atmel_hlcdc *hlcdc;
+ struct resource *res;
+ void __iomem *regs;
+
+ hlcdc = devm_kzalloc(dev, sizeof(*hlcdc), GFP_KERNEL);
+ if (!hlcdc)
+ return -ENOMEM;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(regs))
+ return PTR_ERR(regs);
+
+ hlcdc->irq = platform_get_irq(pdev, 0);
+ if (hlcdc->irq < 0)
+ return hlcdc->irq;
+
+ hlcdc->periph_clk = devm_clk_get(dev, "periph_clk");
+ if (IS_ERR(hlcdc->periph_clk)) {
+ dev_err(dev, "failed to get peripheral clock\n");
+ return PTR_ERR(hlcdc->periph_clk);
+ }
+
+ hlcdc->sys_clk = devm_clk_get(dev, "sys_clk");
+ if (IS_ERR(hlcdc->sys_clk)) {
+ dev_err(dev, "failed to get system clock\n");
+ return PTR_ERR(hlcdc->sys_clk);
+ }
+
+ hlcdc->slow_clk = devm_clk_get(dev, "slow_clk");
+ if (IS_ERR(hlcdc->slow_clk)) {
+ dev_err(dev, "failed to get slow clock\n");
+ return PTR_ERR(hlcdc->slow_clk);
+ }
+
+ hlcdc->regmap = devm_regmap_init_mmio(dev, regs,
+ &atmel_hlcdc_regmap_config);
+ if (IS_ERR(hlcdc->regmap))
+ return PTR_ERR(hlcdc->regmap);
+
+ dev_set_drvdata(dev, hlcdc);
+
+ return mfd_add_devices(dev, -1, atmel_hlcdc_cells,
+ ARRAY_SIZE(atmel_hlcdc_cells),
+ NULL, 0, NULL);
+}
+
+static int atmel_hlcdc_remove(struct platform_device *pdev)
+{
+ mfd_remove_devices(&pdev->dev);
+
+ return 0;
+}
+
+static const struct of_device_id atmel_hlcdc_match[] = {
+ { .compatible = "atmel,sama5d3-hlcdc" },
+ { /* sentinel */ },
+};
+
+static struct platform_driver atmel_hlcdc_driver = {
+ .probe = atmel_hlcdc_probe,
+ .remove = atmel_hlcdc_remove,
+ .driver = {
+ .name = "atmel-hlcdc",
+ .of_match_table = atmel_hlcdc_match,
+ },
+};
+module_platform_driver(atmel_hlcdc_driver);
+
+MODULE_ALIAS("platform:atmel-hlcdc");
+MODULE_AUTHOR("Boris Brezillon <boris.brezillon@free-electrons.com>");
+MODULE_DESCRIPTION("Atmel HLCDC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/axp20x.c b/drivers/mfd/axp20x.c
index 6231adb..b1b580a 100644
--- a/drivers/mfd/axp20x.c
+++ b/drivers/mfd/axp20x.c
@@ -1,9 +1,9 @@
/*
- * axp20x.c - MFD core driver for the X-Powers AXP202 and AXP209
+ * axp20x.c - MFD core driver for the X-Powers' Power Management ICs
*
- * AXP20x comprises an adaptive USB-Compatible PWM charger, 2 BUCK DC-DC
- * converters, 5 LDOs, multiple 12-bit ADCs of voltage, current and temperature
- * as well as 4 configurable GPIOs.
+ * AXP20x typically comprises an adaptive USB-Compatible PWM charger, BUCK DC-DC
+ * converters, LDOs, multiple 12-bit ADCs of voltage, current and temperature
+ * as well as configurable GPIOs.
*
* Author: Carlo Caione <carlo@caione.org>
*
@@ -25,9 +25,16 @@
#include <linux/mfd/core.h>
#include <linux/of_device.h>
#include <linux/of_irq.h>
+#include <linux/acpi.h>
#define AXP20X_OFF 0x80
+static const char const *axp20x_model_names[] = {
+ "AXP202",
+ "AXP209",
+ "AXP288",
+};
+
static const struct regmap_range axp20x_writeable_ranges[] = {
regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ5_STATE),
regmap_reg_range(AXP20X_DCDC_MODE, AXP20X_FG_RES),
@@ -47,6 +54,25 @@ static const struct regmap_access_table axp20x_volatile_table = {
.n_yes_ranges = ARRAY_SIZE(axp20x_volatile_ranges),
};
+static const struct regmap_range axp288_writeable_ranges[] = {
+ regmap_reg_range(AXP20X_DATACACHE(0), AXP20X_IRQ6_STATE),
+ regmap_reg_range(AXP20X_DCDC_MODE, AXP288_FG_TUNE5),
+};
+
+static const struct regmap_range axp288_volatile_ranges[] = {
+ regmap_reg_range(AXP20X_IRQ1_EN, AXP20X_IPSOUT_V_HIGH_L),
+};
+
+static const struct regmap_access_table axp288_writeable_table = {
+ .yes_ranges = axp288_writeable_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp288_writeable_ranges),
+};
+
+static const struct regmap_access_table axp288_volatile_table = {
+ .yes_ranges = axp288_volatile_ranges,
+ .n_yes_ranges = ARRAY_SIZE(axp288_volatile_ranges),
+};
+
static struct resource axp20x_pek_resources[] = {
{
.name = "PEK_DBR",
@@ -61,6 +87,39 @@ static struct resource axp20x_pek_resources[] = {
},
};
+static struct resource axp288_battery_resources[] = {
+ {
+ .start = AXP288_IRQ_QWBTU,
+ .end = AXP288_IRQ_QWBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WBTU,
+ .end = AXP288_IRQ_WBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_QWBTO,
+ .end = AXP288_IRQ_QWBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WBTO,
+ .end = AXP288_IRQ_WBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WL2,
+ .end = AXP288_IRQ_WL2,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_WL1,
+ .end = AXP288_IRQ_WL1,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
static const struct regmap_config axp20x_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -70,47 +129,96 @@ static const struct regmap_config axp20x_regmap_config = {
.cache_type = REGCACHE_RBTREE,
};
-#define AXP20X_IRQ(_irq, _off, _mask) \
- [AXP20X_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
+static const struct regmap_config axp288_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .wr_table = &axp288_writeable_table,
+ .volatile_table = &axp288_volatile_table,
+ .max_register = AXP288_FG_TUNE5,
+ .cache_type = REGCACHE_RBTREE,
+};
+
+#define INIT_REGMAP_IRQ(_variant, _irq, _off, _mask) \
+ [_variant##_IRQ_##_irq] = { .reg_offset = (_off), .mask = BIT(_mask) }
static const struct regmap_irq axp20x_regmap_irqs[] = {
- AXP20X_IRQ(ACIN_OVER_V, 0, 7),
- AXP20X_IRQ(ACIN_PLUGIN, 0, 6),
- AXP20X_IRQ(ACIN_REMOVAL, 0, 5),
- AXP20X_IRQ(VBUS_OVER_V, 0, 4),
- AXP20X_IRQ(VBUS_PLUGIN, 0, 3),
- AXP20X_IRQ(VBUS_REMOVAL, 0, 2),
- AXP20X_IRQ(VBUS_V_LOW, 0, 1),
- AXP20X_IRQ(BATT_PLUGIN, 1, 7),
- AXP20X_IRQ(BATT_REMOVAL, 1, 6),
- AXP20X_IRQ(BATT_ENT_ACT_MODE, 1, 5),
- AXP20X_IRQ(BATT_EXIT_ACT_MODE, 1, 4),
- AXP20X_IRQ(CHARG, 1, 3),
- AXP20X_IRQ(CHARG_DONE, 1, 2),
- AXP20X_IRQ(BATT_TEMP_HIGH, 1, 1),
- AXP20X_IRQ(BATT_TEMP_LOW, 1, 0),
- AXP20X_IRQ(DIE_TEMP_HIGH, 2, 7),
- AXP20X_IRQ(CHARG_I_LOW, 2, 6),
- AXP20X_IRQ(DCDC1_V_LONG, 2, 5),
- AXP20X_IRQ(DCDC2_V_LONG, 2, 4),
- AXP20X_IRQ(DCDC3_V_LONG, 2, 3),
- AXP20X_IRQ(PEK_SHORT, 2, 1),
- AXP20X_IRQ(PEK_LONG, 2, 0),
- AXP20X_IRQ(N_OE_PWR_ON, 3, 7),
- AXP20X_IRQ(N_OE_PWR_OFF, 3, 6),
- AXP20X_IRQ(VBUS_VALID, 3, 5),
- AXP20X_IRQ(VBUS_NOT_VALID, 3, 4),
- AXP20X_IRQ(VBUS_SESS_VALID, 3, 3),
- AXP20X_IRQ(VBUS_SESS_END, 3, 2),
- AXP20X_IRQ(LOW_PWR_LVL1, 3, 1),
- AXP20X_IRQ(LOW_PWR_LVL2, 3, 0),
- AXP20X_IRQ(TIMER, 4, 7),
- AXP20X_IRQ(PEK_RIS_EDGE, 4, 6),
- AXP20X_IRQ(PEK_FAL_EDGE, 4, 5),
- AXP20X_IRQ(GPIO3_INPUT, 4, 3),
- AXP20X_IRQ(GPIO2_INPUT, 4, 2),
- AXP20X_IRQ(GPIO1_INPUT, 4, 1),
- AXP20X_IRQ(GPIO0_INPUT, 4, 0),
+ INIT_REGMAP_IRQ(AXP20X, ACIN_OVER_V, 0, 7),
+ INIT_REGMAP_IRQ(AXP20X, ACIN_PLUGIN, 0, 6),
+ INIT_REGMAP_IRQ(AXP20X, ACIN_REMOVAL, 0, 5),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_OVER_V, 0, 4),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_PLUGIN, 0, 3),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_REMOVAL, 0, 2),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_V_LOW, 0, 1),
+ INIT_REGMAP_IRQ(AXP20X, BATT_PLUGIN, 1, 7),
+ INIT_REGMAP_IRQ(AXP20X, BATT_REMOVAL, 1, 6),
+ INIT_REGMAP_IRQ(AXP20X, BATT_ENT_ACT_MODE, 1, 5),
+ INIT_REGMAP_IRQ(AXP20X, BATT_EXIT_ACT_MODE, 1, 4),
+ INIT_REGMAP_IRQ(AXP20X, CHARG, 1, 3),
+ INIT_REGMAP_IRQ(AXP20X, CHARG_DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_HIGH, 1, 1),
+ INIT_REGMAP_IRQ(AXP20X, BATT_TEMP_LOW, 1, 0),
+ INIT_REGMAP_IRQ(AXP20X, DIE_TEMP_HIGH, 2, 7),
+ INIT_REGMAP_IRQ(AXP20X, CHARG_I_LOW, 2, 6),
+ INIT_REGMAP_IRQ(AXP20X, DCDC1_V_LONG, 2, 5),
+ INIT_REGMAP_IRQ(AXP20X, DCDC2_V_LONG, 2, 4),
+ INIT_REGMAP_IRQ(AXP20X, DCDC3_V_LONG, 2, 3),
+ INIT_REGMAP_IRQ(AXP20X, PEK_SHORT, 2, 1),
+ INIT_REGMAP_IRQ(AXP20X, PEK_LONG, 2, 0),
+ INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_ON, 3, 7),
+ INIT_REGMAP_IRQ(AXP20X, N_OE_PWR_OFF, 3, 6),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_VALID, 3, 5),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_NOT_VALID, 3, 4),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_VALID, 3, 3),
+ INIT_REGMAP_IRQ(AXP20X, VBUS_SESS_END, 3, 2),
+ INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL1, 3, 1),
+ INIT_REGMAP_IRQ(AXP20X, LOW_PWR_LVL2, 3, 0),
+ INIT_REGMAP_IRQ(AXP20X, TIMER, 4, 7),
+ INIT_REGMAP_IRQ(AXP20X, PEK_RIS_EDGE, 4, 6),
+ INIT_REGMAP_IRQ(AXP20X, PEK_FAL_EDGE, 4, 5),
+ INIT_REGMAP_IRQ(AXP20X, GPIO3_INPUT, 4, 3),
+ INIT_REGMAP_IRQ(AXP20X, GPIO2_INPUT, 4, 2),
+ INIT_REGMAP_IRQ(AXP20X, GPIO1_INPUT, 4, 1),
+ INIT_REGMAP_IRQ(AXP20X, GPIO0_INPUT, 4, 0),
+};
+
+/* some IRQs are compatible with axp20x models */
+static const struct regmap_irq axp288_regmap_irqs[] = {
+ INIT_REGMAP_IRQ(AXP288, VBUS_FALL, 0, 2),
+ INIT_REGMAP_IRQ(AXP288, VBUS_RISE, 0, 3),
+ INIT_REGMAP_IRQ(AXP288, OV, 0, 4),
+
+ INIT_REGMAP_IRQ(AXP288, DONE, 1, 2),
+ INIT_REGMAP_IRQ(AXP288, CHARGING, 1, 3),
+ INIT_REGMAP_IRQ(AXP288, SAFE_QUIT, 1, 4),
+ INIT_REGMAP_IRQ(AXP288, SAFE_ENTER, 1, 5),
+ INIT_REGMAP_IRQ(AXP288, ABSENT, 1, 6),
+ INIT_REGMAP_IRQ(AXP288, APPEND, 1, 7),
+
+ INIT_REGMAP_IRQ(AXP288, QWBTU, 2, 0),
+ INIT_REGMAP_IRQ(AXP288, WBTU, 2, 1),
+ INIT_REGMAP_IRQ(AXP288, QWBTO, 2, 2),
+ INIT_REGMAP_IRQ(AXP288, WBTO, 2, 3),
+ INIT_REGMAP_IRQ(AXP288, QCBTU, 2, 4),
+ INIT_REGMAP_IRQ(AXP288, CBTU, 2, 5),
+ INIT_REGMAP_IRQ(AXP288, QCBTO, 2, 6),
+ INIT_REGMAP_IRQ(AXP288, CBTO, 2, 7),
+
+ INIT_REGMAP_IRQ(AXP288, WL2, 3, 0),
+ INIT_REGMAP_IRQ(AXP288, WL1, 3, 1),
+ INIT_REGMAP_IRQ(AXP288, GPADC, 3, 2),
+ INIT_REGMAP_IRQ(AXP288, OT, 3, 7),
+
+ INIT_REGMAP_IRQ(AXP288, GPIO0, 4, 0),
+ INIT_REGMAP_IRQ(AXP288, GPIO1, 4, 1),
+ INIT_REGMAP_IRQ(AXP288, POKO, 4, 2),
+ INIT_REGMAP_IRQ(AXP288, POKL, 4, 3),
+ INIT_REGMAP_IRQ(AXP288, POKS, 4, 4),
+ INIT_REGMAP_IRQ(AXP288, POKN, 4, 5),
+ INIT_REGMAP_IRQ(AXP288, POKP, 4, 6),
+ INIT_REGMAP_IRQ(AXP288, TIMER, 4, 7),
+
+ INIT_REGMAP_IRQ(AXP288, MV_CHNG, 5, 0),
+ INIT_REGMAP_IRQ(AXP288, BC_USB_CHNG, 5, 1),
};
static const struct of_device_id axp20x_of_match[] = {
@@ -128,16 +236,39 @@ static const struct i2c_device_id axp20x_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, axp20x_i2c_id);
+static const struct acpi_device_id axp20x_acpi_match[] = {
+ {
+ .id = "INT33F4",
+ .driver_data = AXP288_ID,
+ },
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, axp20x_acpi_match);
+
static const struct regmap_irq_chip axp20x_regmap_irq_chip = {
.name = "axp20x_irq_chip",
.status_base = AXP20X_IRQ1_STATE,
.ack_base = AXP20X_IRQ1_STATE,
.mask_base = AXP20X_IRQ1_EN,
- .num_regs = 5,
+ .mask_invert = true,
+ .init_ack_masked = true,
.irqs = axp20x_regmap_irqs,
.num_irqs = ARRAY_SIZE(axp20x_regmap_irqs),
+ .num_regs = 5,
+
+};
+
+static const struct regmap_irq_chip axp288_regmap_irq_chip = {
+ .name = "axp288_irq_chip",
+ .status_base = AXP20X_IRQ1_STATE,
+ .ack_base = AXP20X_IRQ1_STATE,
+ .mask_base = AXP20X_IRQ1_EN,
.mask_invert = true,
.init_ack_masked = true,
+ .irqs = axp288_regmap_irqs,
+ .num_irqs = ARRAY_SIZE(axp288_regmap_irqs),
+ .num_regs = 6,
+
};
static struct mfd_cell axp20x_cells[] = {
@@ -150,36 +281,158 @@ static struct mfd_cell axp20x_cells[] = {
},
};
+static struct resource axp288_adc_resources[] = {
+ {
+ .name = "GPADC",
+ .start = AXP288_IRQ_GPADC,
+ .end = AXP288_IRQ_GPADC,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct resource axp288_charger_resources[] = {
+ {
+ .start = AXP288_IRQ_OV,
+ .end = AXP288_IRQ_OV,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_DONE,
+ .end = AXP288_IRQ_DONE,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_CHARGING,
+ .end = AXP288_IRQ_CHARGING,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_SAFE_QUIT,
+ .end = AXP288_IRQ_SAFE_QUIT,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_SAFE_ENTER,
+ .end = AXP288_IRQ_SAFE_ENTER,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_QCBTU,
+ .end = AXP288_IRQ_QCBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_CBTU,
+ .end = AXP288_IRQ_CBTU,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_QCBTO,
+ .end = AXP288_IRQ_QCBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+ {
+ .start = AXP288_IRQ_CBTO,
+ .end = AXP288_IRQ_CBTO,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static struct mfd_cell axp288_cells[] = {
+ {
+ .name = "axp288_adc",
+ .num_resources = ARRAY_SIZE(axp288_adc_resources),
+ .resources = axp288_adc_resources,
+ },
+ {
+ .name = "axp288_charger",
+ .num_resources = ARRAY_SIZE(axp288_charger_resources),
+ .resources = axp288_charger_resources,
+ },
+ {
+ .name = "axp288_battery",
+ .num_resources = ARRAY_SIZE(axp288_battery_resources),
+ .resources = axp288_battery_resources,
+ },
+ {
+ .name = "axp288_pmic_acpi",
+ },
+};
+
static struct axp20x_dev *axp20x_pm_power_off;
static void axp20x_power_off(void)
{
+ if (axp20x_pm_power_off->variant == AXP288_ID)
+ return;
+
regmap_write(axp20x_pm_power_off->regmap, AXP20X_OFF_CTRL,
AXP20X_OFF);
}
+static int axp20x_match_device(struct axp20x_dev *axp20x, struct device *dev)
+{
+ const struct acpi_device_id *acpi_id;
+ const struct of_device_id *of_id;
+
+ if (dev->of_node) {
+ of_id = of_match_device(axp20x_of_match, dev);
+ if (!of_id) {
+ dev_err(dev, "Unable to match OF ID\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (long) of_id->data;
+ } else {
+ acpi_id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!acpi_id || !acpi_id->driver_data) {
+ dev_err(dev, "Unable to match ACPI ID and data\n");
+ return -ENODEV;
+ }
+ axp20x->variant = (long) acpi_id->driver_data;
+ }
+
+ switch (axp20x->variant) {
+ case AXP202_ID:
+ case AXP209_ID:
+ axp20x->nr_cells = ARRAY_SIZE(axp20x_cells);
+ axp20x->cells = axp20x_cells;
+ axp20x->regmap_cfg = &axp20x_regmap_config;
+ axp20x->regmap_irq_chip = &axp20x_regmap_irq_chip;
+ break;
+ case AXP288_ID:
+ axp20x->cells = axp288_cells;
+ axp20x->nr_cells = ARRAY_SIZE(axp288_cells);
+ axp20x->regmap_cfg = &axp288_regmap_config;
+ axp20x->regmap_irq_chip = &axp288_regmap_irq_chip;
+ break;
+ default:
+ dev_err(dev, "unsupported AXP20X ID %lu\n", axp20x->variant);
+ return -EINVAL;
+ }
+ dev_info(dev, "AXP20x variant %s found\n",
+ axp20x_model_names[axp20x->variant]);
+
+ return 0;
+}
+
static int axp20x_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
struct axp20x_dev *axp20x;
- const struct of_device_id *of_id;
int ret;
axp20x = devm_kzalloc(&i2c->dev, sizeof(*axp20x), GFP_KERNEL);
if (!axp20x)
return -ENOMEM;
- of_id = of_match_device(axp20x_of_match, &i2c->dev);
- if (!of_id) {
- dev_err(&i2c->dev, "Unable to setup AXP20X data\n");
- return -ENODEV;
- }
- axp20x->variant = (long) of_id->data;
+ ret = axp20x_match_device(axp20x, &i2c->dev);
+ if (ret)
+ return ret;
axp20x->i2c_client = i2c;
axp20x->dev = &i2c->dev;
dev_set_drvdata(axp20x->dev, axp20x);
- axp20x->regmap = devm_regmap_init_i2c(i2c, &axp20x_regmap_config);
+ axp20x->regmap = devm_regmap_init_i2c(i2c, axp20x->regmap_cfg);
if (IS_ERR(axp20x->regmap)) {
ret = PTR_ERR(axp20x->regmap);
dev_err(&i2c->dev, "regmap init failed: %d\n", ret);
@@ -188,15 +441,15 @@ static int axp20x_i2c_probe(struct i2c_client *i2c,
ret = regmap_add_irq_chip(axp20x->regmap, i2c->irq,
IRQF_ONESHOT | IRQF_SHARED, -1,
- &axp20x_regmap_irq_chip,
+ axp20x->regmap_irq_chip,
&axp20x->regmap_irqc);
if (ret) {
dev_err(&i2c->dev, "failed to add irq chip: %d\n", ret);
return ret;
}
- ret = mfd_add_devices(axp20x->dev, -1, axp20x_cells,
- ARRAY_SIZE(axp20x_cells), NULL, 0, NULL);
+ ret = mfd_add_devices(axp20x->dev, -1, axp20x->cells,
+ axp20x->nr_cells, NULL, 0, NULL);
if (ret) {
dev_err(&i2c->dev, "failed to add MFD devices: %d\n", ret);
@@ -234,6 +487,7 @@ static struct i2c_driver axp20x_i2c_driver = {
.name = "axp20x",
.owner = THIS_MODULE,
.of_match_table = of_match_ptr(axp20x_of_match),
+ .acpi_match_table = ACPI_PTR(axp20x_acpi_match),
},
.probe = axp20x_i2c_probe,
.remove = axp20x_i2c_remove,
diff --git a/drivers/mfd/da9063-core.c b/drivers/mfd/da9063-core.c
index 93db8bb..f38bc98 100644
--- a/drivers/mfd/da9063-core.c
+++ b/drivers/mfd/da9063-core.c
@@ -118,7 +118,7 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
da9063->irq_base = pdata->irq_base;
} else {
da9063->flags = 0;
- da9063->irq_base = 0;
+ da9063->irq_base = -1;
}
da9063->chip_irq = irq;
@@ -168,6 +168,8 @@ int da9063_device_init(struct da9063 *da9063, unsigned int irq)
return ret;
}
+ da9063->irq_base = regmap_irq_chip_get_base(da9063->regmap_irq);
+
ret = mfd_add_devices(da9063->dev, -1, da9063_devs,
ARRAY_SIZE(da9063_devs), NULL, da9063->irq_base,
NULL);
diff --git a/drivers/mfd/db8500-prcmu.c b/drivers/mfd/db8500-prcmu.c
index 193cf16..a820473 100644
--- a/drivers/mfd/db8500-prcmu.c
+++ b/drivers/mfd/db8500-prcmu.c
@@ -3150,23 +3150,28 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu");
if (!res) {
dev_err(&pdev->dev, "no prcmu memory region provided\n");
- return -ENOENT;
+ return -EINVAL;
}
prcmu_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (!prcmu_base) {
dev_err(&pdev->dev,
"failed to ioremap prcmu register memory\n");
- return -ENOENT;
+ return -ENOMEM;
}
init_prcm_registers();
dbx500_fw_version_init(pdev, pdata->version_offset);
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "prcmu-tcdm");
if (!res) {
dev_err(&pdev->dev, "no prcmu tcdm region provided\n");
- return -ENOENT;
+ return -EINVAL;
}
tcdm_base = devm_ioremap(&pdev->dev, res->start,
resource_size(res));
+ if (!tcdm_base) {
+ dev_err(&pdev->dev,
+ "failed to ioremap prcmu-tcdm register memory\n");
+ return -ENOMEM;
+ }
/* Clean up the mailbox interrupts after pre-kernel code. */
writel(ALL_MBOX_BITS, PRCM_ARM_IT1_CLR);
@@ -3174,15 +3179,14 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
irq = platform_get_irq(pdev, 0);
if (irq <= 0) {
dev_err(&pdev->dev, "no prcmu irq provided\n");
- return -ENOENT;
+ return irq;
}
err = request_threaded_irq(irq, prcmu_irq_handler,
prcmu_irq_thread_fn, IRQF_NO_SUSPEND, "prcmu", NULL);
if (err < 0) {
pr_err("prcmu: Failed to allocate IRQ_DB8500_PRCMU1.\n");
- err = -EBUSY;
- goto no_irq_return;
+ return err;
}
db8500_irq_init(np);
@@ -3206,7 +3210,7 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
if (err) {
mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add subdevices\n");
- goto no_irq_return;
+ return err;
}
}
@@ -3214,12 +3218,10 @@ static int db8500_prcmu_probe(struct platform_device *pdev)
if (err) {
mfd_remove_devices(&pdev->dev);
pr_err("prcmu: Failed to add ab8500 subdevice\n");
- goto no_irq_return;
+ return err;
}
pr_info("DB8500 PRCMU initialized\n");
-
-no_irq_return:
return err;
}
static const struct of_device_id db8500_prcmu_match[] = {
diff --git a/drivers/mfd/dln2.c b/drivers/mfd/dln2.c
new file mode 100644
index 0000000..6d49685
--- /dev/null
+++ b/drivers/mfd/dln2.c
@@ -0,0 +1,781 @@
+/*
+ * Driver for the Diolan DLN-2 USB adapter
+ *
+ * Copyright (c) 2014 Intel Corporation
+ *
+ * Derived from:
+ * i2c-diolan-u2c.c
+ * Copyright (c) 2010-2011 Ericsson AB
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, version 2.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/core.h>
+#include <linux/mfd/dln2.h>
+#include <linux/rculist.h>
+
+struct dln2_header {
+ __le16 size;
+ __le16 id;
+ __le16 echo;
+ __le16 handle;
+};
+
+struct dln2_response {
+ struct dln2_header hdr;
+ __le16 result;
+};
+
+#define DLN2_GENERIC_MODULE_ID 0x00
+#define DLN2_GENERIC_CMD(cmd) DLN2_CMD(cmd, DLN2_GENERIC_MODULE_ID)
+#define CMD_GET_DEVICE_VER DLN2_GENERIC_CMD(0x30)
+#define CMD_GET_DEVICE_SN DLN2_GENERIC_CMD(0x31)
+
+#define DLN2_HW_ID 0x200
+#define DLN2_USB_TIMEOUT 200 /* in ms */
+#define DLN2_MAX_RX_SLOTS 16
+#define DLN2_MAX_URBS 16
+#define DLN2_RX_BUF_SIZE 512
+
+enum dln2_handle {
+ DLN2_HANDLE_EVENT = 0, /* don't change, hardware defined */
+ DLN2_HANDLE_CTRL,
+ DLN2_HANDLE_GPIO,
+ DLN2_HANDLE_I2C,
+ DLN2_HANDLE_SPI,
+ DLN2_HANDLES
+};
+
+/*
+ * Receive context used between the receive demultiplexer and the transfer
+ * routine. While sending a request the transfer routine will look for a free
+ * receive context and use it to wait for a response and to receive the URB and
+ * thus the response data.
+ */
+struct dln2_rx_context {
+ /* completion used to wait for a response */
+ struct completion done;
+
+ /* if non-NULL the URB contains the response */
+ struct urb *urb;
+
+ /* if true then this context is used to wait for a response */
+ bool in_use;
+};
+
+/*
+ * Receive contexts for a particular DLN2 module (i2c, gpio, etc.). We use the
+ * handle header field to identify the module in dln2_dev.mod_rx_slots and then
+ * the echo header field to index the slots field and find the receive context
+ * for a particular request.
+ */
+struct dln2_mod_rx_slots {
+ /* RX slots bitmap */
+ DECLARE_BITMAP(bmap, DLN2_MAX_RX_SLOTS);
+
+ /* used to wait for a free RX slot */
+ wait_queue_head_t wq;
+
+ /* used to wait for an RX operation to complete */
+ struct dln2_rx_context slots[DLN2_MAX_RX_SLOTS];
+
+ /* avoid races between alloc/free_rx_slot and dln2_rx_transfer */
+ spinlock_t lock;
+};
+
+struct dln2_dev {
+ struct usb_device *usb_dev;
+ struct usb_interface *interface;
+ u8 ep_in;
+ u8 ep_out;
+
+ struct urb *rx_urb[DLN2_MAX_URBS];
+ void *rx_buf[DLN2_MAX_URBS];
+
+ struct dln2_mod_rx_slots mod_rx_slots[DLN2_HANDLES];
+
+ struct list_head event_cb_list;
+ spinlock_t event_cb_lock;
+
+ bool disconnect;
+ int active_transfers;
+ wait_queue_head_t disconnect_wq;
+ spinlock_t disconnect_lock;
+};
+
+struct dln2_event_cb_entry {
+ struct list_head list;
+ u16 id;
+ struct platform_device *pdev;
+ dln2_event_cb_t callback;
+};
+
+int dln2_register_event_cb(struct platform_device *pdev, u16 id,
+ dln2_event_cb_t event_cb)
+{
+ struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
+ struct dln2_event_cb_entry *i, *entry;
+ unsigned long flags;
+ int ret = 0;
+
+ entry = kzalloc(sizeof(*entry), GFP_KERNEL);
+ if (!entry)
+ return -ENOMEM;
+
+ entry->id = id;
+ entry->callback = event_cb;
+ entry->pdev = pdev;
+
+ spin_lock_irqsave(&dln2->event_cb_lock, flags);
+
+ list_for_each_entry(i, &dln2->event_cb_list, list) {
+ if (i->id == id) {
+ ret = -EBUSY;
+ break;
+ }
+ }
+
+ if (!ret)
+ list_add_rcu(&entry->list, &dln2->event_cb_list);
+
+ spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
+
+ if (ret)
+ kfree(entry);
+
+ return ret;
+}
+EXPORT_SYMBOL(dln2_register_event_cb);
+
+void dln2_unregister_event_cb(struct platform_device *pdev, u16 id)
+{
+ struct dln2_dev *dln2 = dev_get_drvdata(pdev->dev.parent);
+ struct dln2_event_cb_entry *i;
+ unsigned long flags;
+ bool found = false;
+
+ spin_lock_irqsave(&dln2->event_cb_lock, flags);
+
+ list_for_each_entry(i, &dln2->event_cb_list, list) {
+ if (i->id == id) {
+ list_del_rcu(&i->list);
+ found = true;
+ break;
+ }
+ }
+
+ spin_unlock_irqrestore(&dln2->event_cb_lock, flags);
+
+ if (found) {
+ synchronize_rcu();
+ kfree(i);
+ }
+}
+EXPORT_SYMBOL(dln2_unregister_event_cb);
+
+/*
+ * Returns true if a valid transfer slot is found. In this case the URB must not
+ * be resubmitted immediately in dln2_rx as we need the data when dln2_transfer
+ * is woke up. It will be resubmitted there.
+ */
+static bool dln2_transfer_complete(struct dln2_dev *dln2, struct urb *urb,
+ u16 handle, u16 rx_slot)
+{
+ struct device *dev = &dln2->interface->dev;
+ struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
+ struct dln2_rx_context *rxc;
+ bool valid_slot = false;
+
+ if (rx_slot >= DLN2_MAX_RX_SLOTS)
+ goto out;
+
+ rxc = &rxs->slots[rx_slot];
+
+ /*
+ * No need to disable interrupts as this lock is not taken in interrupt
+ * context elsewhere in this driver. This function (or its callers) are
+ * also not exported to other modules.
+ */
+ spin_lock(&rxs->lock);
+ if (rxc->in_use && !rxc->urb) {
+ rxc->urb = urb;
+ complete(&rxc->done);
+ valid_slot = true;
+ }
+ spin_unlock(&rxs->lock);
+
+out:
+ if (!valid_slot)
+ dev_warn(dev, "bad/late response %d/%d\n", handle, rx_slot);
+
+ return valid_slot;
+}
+
+static void dln2_run_event_callbacks(struct dln2_dev *dln2, u16 id, u16 echo,
+ void *data, int len)
+{
+ struct dln2_event_cb_entry *i;
+
+ rcu_read_lock();
+
+ list_for_each_entry_rcu(i, &dln2->event_cb_list, list) {
+ if (i->id == id) {
+ i->callback(i->pdev, echo, data, len);
+ break;
+ }
+ }
+
+ rcu_read_unlock();
+}
+
+static void dln2_rx(struct urb *urb)
+{
+ struct dln2_dev *dln2 = urb->context;
+ struct dln2_header *hdr = urb->transfer_buffer;
+ struct device *dev = &dln2->interface->dev;
+ u16 id, echo, handle, size;
+ u8 *data;
+ int len;
+ int err;
+
+ switch (urb->status) {
+ case 0:
+ /* success */
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ case -EPIPE:
+ /* this urb is terminated, clean up */
+ dev_dbg(dev, "urb shutting down with status %d\n", urb->status);
+ return;
+ default:
+ dev_dbg(dev, "nonzero urb status received %d\n", urb->status);
+ goto out;
+ }
+
+ if (urb->actual_length < sizeof(struct dln2_header)) {
+ dev_err(dev, "short response: %d\n", urb->actual_length);
+ goto out;
+ }
+
+ handle = le16_to_cpu(hdr->handle);
+ id = le16_to_cpu(hdr->id);
+ echo = le16_to_cpu(hdr->echo);
+ size = le16_to_cpu(hdr->size);
+
+ if (size != urb->actual_length) {
+ dev_err(dev, "size mismatch: handle %x cmd %x echo %x size %d actual %d\n",
+ handle, id, echo, size, urb->actual_length);
+ goto out;
+ }
+
+ if (handle >= DLN2_HANDLES) {
+ dev_warn(dev, "invalid handle %d\n", handle);
+ goto out;
+ }
+
+ data = urb->transfer_buffer + sizeof(struct dln2_header);
+ len = urb->actual_length - sizeof(struct dln2_header);
+
+ if (handle == DLN2_HANDLE_EVENT) {
+ dln2_run_event_callbacks(dln2, id, echo, data, len);
+ } else {
+ /* URB will be re-submitted in _dln2_transfer (free_rx_slot) */
+ if (dln2_transfer_complete(dln2, urb, handle, echo))
+ return;
+ }
+
+out:
+ err = usb_submit_urb(urb, GFP_ATOMIC);
+ if (err < 0)
+ dev_err(dev, "failed to resubmit RX URB: %d\n", err);
+}
+
+static void *dln2_prep_buf(u16 handle, u16 cmd, u16 echo, const void *obuf,
+ int *obuf_len, gfp_t gfp)
+{
+ int len;
+ void *buf;
+ struct dln2_header *hdr;
+
+ len = *obuf_len + sizeof(*hdr);
+ buf = kmalloc(len, gfp);
+ if (!buf)
+ return NULL;
+
+ hdr = (struct dln2_header *)buf;
+ hdr->id = cpu_to_le16(cmd);
+ hdr->size = cpu_to_le16(len);
+ hdr->echo = cpu_to_le16(echo);
+ hdr->handle = cpu_to_le16(handle);
+
+ memcpy(buf + sizeof(*hdr), obuf, *obuf_len);
+
+ *obuf_len = len;
+
+ return buf;
+}
+
+static int dln2_send_wait(struct dln2_dev *dln2, u16 handle, u16 cmd, u16 echo,
+ const void *obuf, int obuf_len)
+{
+ int ret = 0;
+ int len = obuf_len;
+ void *buf;
+ int actual;
+
+ buf = dln2_prep_buf(handle, cmd, echo, obuf, &len, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ ret = usb_bulk_msg(dln2->usb_dev,
+ usb_sndbulkpipe(dln2->usb_dev, dln2->ep_out),
+ buf, len, &actual, DLN2_USB_TIMEOUT);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static bool find_free_slot(struct dln2_dev *dln2, u16 handle, int *slot)
+{
+ struct dln2_mod_rx_slots *rxs;
+ unsigned long flags;
+
+ if (dln2->disconnect) {
+ *slot = -ENODEV;
+ return true;
+ }
+
+ rxs = &dln2->mod_rx_slots[handle];
+
+ spin_lock_irqsave(&rxs->lock, flags);
+
+ *slot = find_first_zero_bit(rxs->bmap, DLN2_MAX_RX_SLOTS);
+
+ if (*slot < DLN2_MAX_RX_SLOTS) {
+ struct dln2_rx_context *rxc = &rxs->slots[*slot];
+
+ set_bit(*slot, rxs->bmap);
+ rxc->in_use = true;
+ }
+
+ spin_unlock_irqrestore(&rxs->lock, flags);
+
+ return *slot < DLN2_MAX_RX_SLOTS;
+}
+
+static int alloc_rx_slot(struct dln2_dev *dln2, u16 handle)
+{
+ int ret;
+ int slot;
+
+ /*
+ * No need to timeout here, the wait is bounded by the timeout in
+ * _dln2_transfer.
+ */
+ ret = wait_event_interruptible(dln2->mod_rx_slots[handle].wq,
+ find_free_slot(dln2, handle, &slot));
+ if (ret < 0)
+ return ret;
+
+ return slot;
+}
+
+static void free_rx_slot(struct dln2_dev *dln2, u16 handle, int slot)
+{
+ struct dln2_mod_rx_slots *rxs;
+ struct urb *urb = NULL;
+ unsigned long flags;
+ struct dln2_rx_context *rxc;
+
+ rxs = &dln2->mod_rx_slots[handle];
+
+ spin_lock_irqsave(&rxs->lock, flags);
+
+ clear_bit(slot, rxs->bmap);
+
+ rxc = &rxs->slots[slot];
+ rxc->in_use = false;
+ urb = rxc->urb;
+ rxc->urb = NULL;
+ reinit_completion(&rxc->done);
+
+ spin_unlock_irqrestore(&rxs->lock, flags);
+
+ if (urb) {
+ int err;
+ struct device *dev = &dln2->interface->dev;
+
+ err = usb_submit_urb(urb, GFP_KERNEL);
+ if (err < 0)
+ dev_err(dev, "failed to resubmit RX URB: %d\n", err);
+ }
+
+ wake_up_interruptible(&rxs->wq);
+}
+
+static int _dln2_transfer(struct dln2_dev *dln2, u16 handle, u16 cmd,
+ const void *obuf, unsigned obuf_len,
+ void *ibuf, unsigned *ibuf_len)
+{
+ int ret = 0;
+ int rx_slot;
+ struct dln2_response *rsp;
+ struct dln2_rx_context *rxc;
+ struct device *dev = &dln2->interface->dev;
+ const unsigned long timeout = DLN2_USB_TIMEOUT * HZ / 1000;
+ struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[handle];
+ int size;
+
+ spin_lock(&dln2->disconnect_lock);
+ if (!dln2->disconnect)
+ dln2->active_transfers++;
+ else
+ ret = -ENODEV;
+ spin_unlock(&dln2->disconnect_lock);
+
+ if (ret)
+ return ret;
+
+ rx_slot = alloc_rx_slot(dln2, handle);
+ if (rx_slot < 0) {
+ ret = rx_slot;
+ goto out_decr;
+ }
+
+ ret = dln2_send_wait(dln2, handle, cmd, rx_slot, obuf, obuf_len);
+ if (ret < 0) {
+ dev_err(dev, "USB write failed: %d\n", ret);
+ goto out_free_rx_slot;
+ }
+
+ rxc = &rxs->slots[rx_slot];
+
+ ret = wait_for_completion_interruptible_timeout(&rxc->done, timeout);
+ if (ret <= 0) {
+ if (!ret)
+ ret = -ETIMEDOUT;
+ goto out_free_rx_slot;
+ } else {
+ ret = 0;
+ }
+
+ if (dln2->disconnect) {
+ ret = -ENODEV;
+ goto out_free_rx_slot;
+ }
+
+ /* if we got here we know that the response header has been checked */
+ rsp = rxc->urb->transfer_buffer;
+ size = le16_to_cpu(rsp->hdr.size);
+
+ if (size < sizeof(*rsp)) {
+ ret = -EPROTO;
+ goto out_free_rx_slot;
+ }
+
+ if (le16_to_cpu(rsp->result) > 0x80) {
+ dev_dbg(dev, "%d received response with error %d\n",
+ handle, le16_to_cpu(rsp->result));
+ ret = -EREMOTEIO;
+ goto out_free_rx_slot;
+ }
+
+ if (!ibuf)
+ goto out_free_rx_slot;
+
+ if (*ibuf_len > size - sizeof(*rsp))
+ *ibuf_len = size - sizeof(*rsp);
+
+ memcpy(ibuf, rsp + 1, *ibuf_len);
+
+out_free_rx_slot:
+ free_rx_slot(dln2, handle, rx_slot);
+out_decr:
+ spin_lock(&dln2->disconnect_lock);
+ dln2->active_transfers--;
+ spin_unlock(&dln2->disconnect_lock);
+ if (dln2->disconnect)
+ wake_up(&dln2->disconnect_wq);
+
+ return ret;
+}
+
+int dln2_transfer(struct platform_device *pdev, u16 cmd,
+ const void *obuf, unsigned obuf_len,
+ void *ibuf, unsigned *ibuf_len)
+{
+ struct dln2_platform_data *dln2_pdata;
+ struct dln2_dev *dln2;
+ u16 handle;
+
+ dln2 = dev_get_drvdata(pdev->dev.parent);
+ dln2_pdata = dev_get_platdata(&pdev->dev);
+ handle = dln2_pdata->handle;
+
+ return _dln2_transfer(dln2, handle, cmd, obuf, obuf_len, ibuf,
+ ibuf_len);
+}
+EXPORT_SYMBOL(dln2_transfer);
+
+static int dln2_check_hw(struct dln2_dev *dln2)
+{
+ int ret;
+ __le32 hw_type;
+ int len = sizeof(hw_type);
+
+ ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_VER,
+ NULL, 0, &hw_type, &len);
+ if (ret < 0)
+ return ret;
+ if (len < sizeof(hw_type))
+ return -EREMOTEIO;
+
+ if (le32_to_cpu(hw_type) != DLN2_HW_ID) {
+ dev_err(&dln2->interface->dev, "Device ID 0x%x not supported\n",
+ le32_to_cpu(hw_type));
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static int dln2_print_serialno(struct dln2_dev *dln2)
+{
+ int ret;
+ __le32 serial_no;
+ int len = sizeof(serial_no);
+ struct device *dev = &dln2->interface->dev;
+
+ ret = _dln2_transfer(dln2, DLN2_HANDLE_CTRL, CMD_GET_DEVICE_SN, NULL, 0,
+ &serial_no, &len);
+ if (ret < 0)
+ return ret;
+ if (len < sizeof(serial_no))
+ return -EREMOTEIO;
+
+ dev_info(dev, "Diolan DLN2 serial %u\n", le32_to_cpu(serial_no));
+
+ return 0;
+}
+
+static int dln2_hw_init(struct dln2_dev *dln2)
+{
+ int ret;
+
+ ret = dln2_check_hw(dln2);
+ if (ret < 0)
+ return ret;
+
+ return dln2_print_serialno(dln2);
+}
+
+static void dln2_free_rx_urbs(struct dln2_dev *dln2)
+{
+ int i;
+
+ for (i = 0; i < DLN2_MAX_URBS; i++) {
+ usb_kill_urb(dln2->rx_urb[i]);
+ usb_free_urb(dln2->rx_urb[i]);
+ kfree(dln2->rx_buf[i]);
+ }
+}
+
+static void dln2_free(struct dln2_dev *dln2)
+{
+ dln2_free_rx_urbs(dln2);
+ usb_put_dev(dln2->usb_dev);
+ kfree(dln2);
+}
+
+static int dln2_setup_rx_urbs(struct dln2_dev *dln2,
+ struct usb_host_interface *hostif)
+{
+ int i;
+ int ret;
+ const int rx_max_size = DLN2_RX_BUF_SIZE;
+ struct device *dev = &dln2->interface->dev;
+
+ for (i = 0; i < DLN2_MAX_URBS; i++) {
+ dln2->rx_buf[i] = kmalloc(rx_max_size, GFP_KERNEL);
+ if (!dln2->rx_buf[i])
+ return -ENOMEM;
+
+ dln2->rx_urb[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dln2->rx_urb[i])
+ return -ENOMEM;
+
+ usb_fill_bulk_urb(dln2->rx_urb[i], dln2->usb_dev,
+ usb_rcvbulkpipe(dln2->usb_dev, dln2->ep_in),
+ dln2->rx_buf[i], rx_max_size, dln2_rx, dln2);
+
+ ret = usb_submit_urb(dln2->rx_urb[i], GFP_KERNEL);
+ if (ret < 0) {
+ dev_err(dev, "failed to submit RX URB: %d\n", ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static struct dln2_platform_data dln2_pdata_gpio = {
+ .handle = DLN2_HANDLE_GPIO,
+};
+
+/* Only one I2C port seems to be supported on current hardware */
+static struct dln2_platform_data dln2_pdata_i2c = {
+ .handle = DLN2_HANDLE_I2C,
+ .port = 0,
+};
+
+/* Only one SPI port supported */
+static struct dln2_platform_data dln2_pdata_spi = {
+ .handle = DLN2_HANDLE_SPI,
+ .port = 0,
+};
+
+static const struct mfd_cell dln2_devs[] = {
+ {
+ .name = "dln2-gpio",
+ .platform_data = &dln2_pdata_gpio,
+ .pdata_size = sizeof(struct dln2_platform_data),
+ },
+ {
+ .name = "dln2-i2c",
+ .platform_data = &dln2_pdata_i2c,
+ .pdata_size = sizeof(struct dln2_platform_data),
+ },
+ {
+ .name = "dln2-spi",
+ .platform_data = &dln2_pdata_spi,
+ .pdata_size = sizeof(struct dln2_platform_data),
+ },
+};
+
+static void dln2_disconnect(struct usb_interface *interface)
+{
+ struct dln2_dev *dln2 = usb_get_intfdata(interface);
+ int i, j;
+
+ /* don't allow starting new transfers */
+ spin_lock(&dln2->disconnect_lock);
+ dln2->disconnect = true;
+ spin_unlock(&dln2->disconnect_lock);
+
+ /* cancel in progress transfers */
+ for (i = 0; i < DLN2_HANDLES; i++) {
+ struct dln2_mod_rx_slots *rxs = &dln2->mod_rx_slots[i];
+ unsigned long flags;
+
+ spin_lock_irqsave(&rxs->lock, flags);
+
+ /* cancel all response waiters */
+ for (j = 0; j < DLN2_MAX_RX_SLOTS; j++) {
+ struct dln2_rx_context *rxc = &rxs->slots[j];
+
+ if (rxc->in_use)
+ complete(&rxc->done);
+ }
+
+ spin_unlock_irqrestore(&rxs->lock, flags);
+ }
+
+ /* wait for transfers to end */
+ wait_event(dln2->disconnect_wq, !dln2->active_transfers);
+
+ mfd_remove_devices(&interface->dev);
+
+ dln2_free(dln2);
+}
+
+static int dln2_probe(struct usb_interface *interface,
+ const struct usb_device_id *usb_id)
+{
+ struct usb_host_interface *hostif = interface->cur_altsetting;
+ struct device *dev = &interface->dev;
+ struct dln2_dev *dln2;
+ int ret;
+ int i, j;
+
+ if (hostif->desc.bInterfaceNumber != 0 ||
+ hostif->desc.bNumEndpoints < 2)
+ return -ENODEV;
+
+ dln2 = kzalloc(sizeof(*dln2), GFP_KERNEL);
+ if (!dln2)
+ return -ENOMEM;
+
+ dln2->ep_out = hostif->endpoint[0].desc.bEndpointAddress;
+ dln2->ep_in = hostif->endpoint[1].desc.bEndpointAddress;
+ dln2->usb_dev = usb_get_dev(interface_to_usbdev(interface));
+ dln2->interface = interface;
+ usb_set_intfdata(interface, dln2);
+ init_waitqueue_head(&dln2->disconnect_wq);
+
+ for (i = 0; i < DLN2_HANDLES; i++) {
+ init_waitqueue_head(&dln2->mod_rx_slots[i].wq);
+ spin_lock_init(&dln2->mod_rx_slots[i].lock);
+ for (j = 0; j < DLN2_MAX_RX_SLOTS; j++)
+ init_completion(&dln2->mod_rx_slots[i].slots[j].done);
+ }
+
+ spin_lock_init(&dln2->event_cb_lock);
+ spin_lock_init(&dln2->disconnect_lock);
+ INIT_LIST_HEAD(&dln2->event_cb_list);
+
+ ret = dln2_setup_rx_urbs(dln2, hostif);
+ if (ret)
+ goto out_cleanup;
+
+ ret = dln2_hw_init(dln2);
+ if (ret < 0) {
+ dev_err(dev, "failed to initialize hardware\n");
+ goto out_cleanup;
+ }
+
+ ret = mfd_add_hotplug_devices(dev, dln2_devs, ARRAY_SIZE(dln2_devs));
+ if (ret != 0) {
+ dev_err(dev, "failed to add mfd devices to core\n");
+ goto out_cleanup;
+ }
+
+ return 0;
+
+out_cleanup:
+ dln2_free(dln2);
+
+ return ret;
+}
+
+static const struct usb_device_id dln2_table[] = {
+ { USB_DEVICE(0xa257, 0x2013) },
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, dln2_table);
+
+static struct usb_driver dln2_driver = {
+ .name = "dln2",
+ .probe = dln2_probe,
+ .disconnect = dln2_disconnect,
+ .id_table = dln2_table,
+};
+
+module_usb_driver(dln2_driver);
+
+MODULE_AUTHOR("Octavian Purdila <octavian.purdila@intel.com>");
+MODULE_DESCRIPTION("Core driver for the Diolan DLN2 interface adapter");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/mfd/intel_soc_pmic_crc.c b/drivers/mfd/intel_soc_pmic_crc.c
index 7107cab..c85e2ec 100644
--- a/drivers/mfd/intel_soc_pmic_crc.c
+++ b/drivers/mfd/intel_soc_pmic_crc.c
@@ -106,6 +106,9 @@ static struct mfd_cell crystal_cove_dev[] = {
.num_resources = ARRAY_SIZE(gpio_resources),
.resources = gpio_resources,
},
+ {
+ .name = "crystal_cove_pmic",
+ },
};
static struct regmap_config crystal_cove_regmap_config = {
diff --git a/drivers/mfd/lpc_sch.c b/drivers/mfd/lpc_sch.c
index c980da4..5c38df3 100644
--- a/drivers/mfd/lpc_sch.c
+++ b/drivers/mfd/lpc_sch.c
@@ -193,11 +193,7 @@ static int lpc_sch_probe(struct pci_dev *dev, const struct pci_device_id *id)
return -ENODEV;
}
- ret = mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
- if (ret)
- mfd_remove_devices(&dev->dev);
-
- return ret;
+ return mfd_add_devices(&dev->dev, 0, lpc_sch_cells, cells, NULL, 0, NULL);
}
static void lpc_sch_remove(struct pci_dev *dev)
diff --git a/drivers/mfd/max14577.c b/drivers/mfd/max14577.c
index de96b7f..3bf8def 100644
--- a/drivers/mfd/max14577.c
+++ b/drivers/mfd/max14577.c
@@ -1,7 +1,7 @@
/*
* max14577.c - mfd core driver for the Maxim 14577/77836
*
- * Copyright (C) 2014 Samsung Electrnoics
+ * Copyright (C) 2014 Samsung Electronics
* Chanwoo Choi <cw00.choi@samsung.com>
* Krzysztof Kozlowski <k.kozlowski@samsung.com>
*
diff --git a/drivers/mfd/max77693.c b/drivers/mfd/max77693.c
index 711773e..a159593 100644
--- a/drivers/mfd/max77693.c
+++ b/drivers/mfd/max77693.c
@@ -43,9 +43,15 @@
static const struct mfd_cell max77693_devs[] = {
{ .name = "max77693-pmic", },
- { .name = "max77693-charger", },
+ {
+ .name = "max77693-charger",
+ .of_compatible = "maxim,max77693-charger",
+ },
{ .name = "max77693-muic", },
- { .name = "max77693-haptic", },
+ {
+ .name = "max77693-haptic",
+ .of_compatible = "maxim,max77693-haptic",
+ },
{
.name = "max77693-flash",
.of_compatible = "maxim,max77693-flash",
@@ -147,6 +153,12 @@ static const struct regmap_irq_chip max77693_muic_irq_chip = {
.num_irqs = ARRAY_SIZE(max77693_muic_irqs),
};
+static const struct regmap_config max77693_regmap_haptic_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ .max_register = MAX77693_HAPTIC_REG_END,
+};
+
static int max77693_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -196,6 +208,15 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
}
i2c_set_clientdata(max77693->haptic, max77693);
+ max77693->regmap_haptic = devm_regmap_init_i2c(max77693->haptic,
+ &max77693_regmap_haptic_config);
+ if (IS_ERR(max77693->regmap_haptic)) {
+ ret = PTR_ERR(max77693->regmap_haptic);
+ dev_err(max77693->dev,
+ "failed to initialize haptic register map: %d\n", ret);
+ goto err_regmap;
+ }
+
/*
* Initialize register map for MUIC device because use regmap-muic
* instance of MUIC device when irq of max77693 is initialized
@@ -207,7 +228,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
ret = PTR_ERR(max77693->regmap_muic);
dev_err(max77693->dev,
"failed to allocate register map: %d\n", ret);
- goto err_regmap_muic;
+ goto err_regmap;
}
ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
@@ -217,7 +238,7 @@ static int max77693_i2c_probe(struct i2c_client *i2c,
&max77693->irq_data_led);
if (ret) {
dev_err(max77693->dev, "failed to add irq chip: %d\n", ret);
- goto err_regmap_muic;
+ goto err_regmap;
}
ret = regmap_add_irq_chip(max77693->regmap, max77693->irq,
@@ -280,7 +301,7 @@ err_irq_charger:
regmap_del_irq_chip(max77693->irq, max77693->irq_data_topsys);
err_irq_topsys:
regmap_del_irq_chip(max77693->irq, max77693->irq_data_led);
-err_regmap_muic:
+err_regmap:
i2c_unregister_device(max77693->haptic);
err_i2c_haptic:
i2c_unregister_device(max77693->muic);
diff --git a/drivers/mfd/mfd-core.c b/drivers/mfd/mfd-core.c
index f3338fe..2a87f69 100644
--- a/drivers/mfd/mfd-core.c
+++ b/drivers/mfd/mfd-core.c
@@ -125,9 +125,15 @@ static int mfd_add_device(struct device *parent, int id,
struct platform_device *pdev;
struct device_node *np = NULL;
int ret = -ENOMEM;
+ int platform_id;
int r;
- pdev = platform_device_alloc(cell->name, id + cell->id);
+ if (id < 0)
+ platform_id = id;
+ else
+ platform_id = id + cell->id;
+
+ pdev = platform_device_alloc(cell->name, platform_id);
if (!pdev)
goto fail_alloc;
diff --git a/drivers/mfd/rts5227.c b/drivers/mfd/rts5227.c
index 9c8eec8..3240740 100644
--- a/drivers/mfd/rts5227.c
+++ b/drivers/mfd/rts5227.c
@@ -130,6 +130,12 @@ static int rts5227_extra_init_hw(struct rtsx_pcr *pcr)
static int rts5227_optimize_phy(struct rtsx_pcr *pcr)
{
+ int err;
+
+ err = rtsx_gops_pm_reset(pcr);
+ if (err < 0)
+ return err;
+
/* Optimize RX sensitivity */
return rtsx_pci_write_phy_register(pcr, 0x00, 0xBA42);
}
diff --git a/drivers/mfd/rts5249.c b/drivers/mfd/rts5249.c
index 573de7b..cf425cc 100644
--- a/drivers/mfd/rts5249.c
+++ b/drivers/mfd/rts5249.c
@@ -130,6 +130,10 @@ static int rts5249_optimize_phy(struct rtsx_pcr *pcr)
{
int err;
+ err = rtsx_gops_pm_reset(pcr);
+ if (err < 0)
+ return err;
+
err = rtsx_pci_write_phy_register(pcr, PHY_REG_REV,
PHY_REG_REV_RESV | PHY_REG_REV_RXIDLE_LATCHED |
PHY_REG_REV_P1_EN | PHY_REG_REV_RXIDLE_EN |
diff --git a/drivers/mfd/rtsx_gops.c b/drivers/mfd/rtsx_gops.c
new file mode 100644
index 0000000..b1a98c6
--- /dev/null
+++ b/drivers/mfd/rtsx_gops.c
@@ -0,0 +1,37 @@
+/* Driver for Realtek PCI-Express card reader
+ *
+ * Copyright(c) 2009-2013 Realtek Semiconductor Corp. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, see <http://www.gnu.org/licenses/>.
+ *
+ * Author:
+ * Micky Ching <micky_ching@realsil.com.cn>
+ */
+
+#include <linux/mfd/rtsx_pci.h>
+#include "rtsx_pcr.h"
+
+int rtsx_gops_pm_reset(struct rtsx_pcr *pcr)
+{
+ int err;
+
+ /* init aspm */
+ rtsx_pci_write_register(pcr, ASPM_FORCE_CTL, 0xFF, 0x00);
+ err = rtsx_pci_update_cfg_byte(pcr, LCTLR, ~LCTLR_ASPM_CTL_MASK, 0x00);
+ if (err < 0)
+ return err;
+
+ /* reset PM_CTRL3 before send buffer cmd */
+ return rtsx_pci_write_register(pcr, PM_CTRL3, D3_DELINK_MODE_EN, 0x00);
+}
diff --git a/drivers/mfd/rtsx_pcr.h b/drivers/mfd/rtsx_pcr.h
index 07e4c2e..fe2bbb6 100644
--- a/drivers/mfd/rtsx_pcr.h
+++ b/drivers/mfd/rtsx_pcr.h
@@ -72,4 +72,7 @@ do { \
pcr->ms_pull_ctl_disable_tbl = __device##_ms_pull_ctl_disable_tbl; \
} while (0)
+/* generic operations */
+int rtsx_gops_pm_reset(struct rtsx_pcr *pcr);
+
#endif
diff --git a/drivers/mfd/rtsx_usb.c b/drivers/mfd/rtsx_usb.c
index 9cf98d1..dbdd0fa 100644
--- a/drivers/mfd/rtsx_usb.c
+++ b/drivers/mfd/rtsx_usb.c
@@ -647,8 +647,8 @@ static int rtsx_usb_probe(struct usb_interface *intf,
/* initialize USB SG transfer timer */
setup_timer(&ucr->sg_timer, rtsx_usb_sg_timed_out, (unsigned long) ucr);
- ret = mfd_add_devices(&intf->dev, usb_dev->devnum, rtsx_usb_cells,
- ARRAY_SIZE(rtsx_usb_cells), NULL, 0, NULL);
+ ret = mfd_add_hotplug_devices(&intf->dev, rtsx_usb_cells,
+ ARRAY_SIZE(rtsx_usb_cells));
if (ret)
goto out_init_fail;
diff --git a/drivers/mfd/sec-core.c b/drivers/mfd/sec-core.c
index dba7e2b..0a7bc43 100644
--- a/drivers/mfd/sec-core.c
+++ b/drivers/mfd/sec-core.c
@@ -27,11 +27,11 @@
#include <linux/mfd/samsung/irq.h>
#include <linux/mfd/samsung/s2mpa01.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s2mpu02.h>
#include <linux/mfd/samsung/s5m8763.h>
#include <linux/mfd/samsung/s5m8767.h>
-#include <linux/regulator/machine.h>
#include <linux/regmap.h>
static const struct mfd_cell s5m8751_devs[] = {
@@ -74,6 +74,15 @@ static const struct mfd_cell s2mps11_devs[] = {
}
};
+static const struct mfd_cell s2mps13_devs[] = {
+ { .name = "s2mps13-pmic", },
+ { .name = "s2mps13-rtc", },
+ {
+ .name = "s2mps13-clk",
+ .of_compatible = "samsung,s2mps13-clk",
+ },
+};
+
static const struct mfd_cell s2mps14_devs[] = {
{
.name = "s2mps14-pmic",
@@ -108,6 +117,9 @@ static const struct of_device_id sec_dt_match[] = {
.compatible = "samsung,s2mps11-pmic",
.data = (void *)S2MPS11X,
}, {
+ .compatible = "samsung,s2mps13-pmic",
+ .data = (void *)S2MPS13X,
+ }, {
.compatible = "samsung,s2mps14-pmic",
.data = (void *)S2MPS14X,
}, {
@@ -194,6 +206,15 @@ static const struct regmap_config s2mps11_regmap_config = {
.cache_type = REGCACHE_FLAT,
};
+static const struct regmap_config s2mps13_regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+
+ .max_register = S2MPS13_REG_LDODSCH5,
+ .volatile_reg = s2mps11_volatile,
+ .cache_type = REGCACHE_FLAT,
+};
+
static const struct regmap_config s2mps14_regmap_config = {
.reg_bits = 8,
.val_bits = 8,
@@ -325,6 +346,9 @@ static int sec_pmic_probe(struct i2c_client *i2c,
case S2MPS11X:
regmap = &s2mps11_regmap_config;
break;
+ case S2MPS13X:
+ regmap = &s2mps13_regmap_config;
+ break;
case S2MPS14X:
regmap = &s2mps14_regmap_config;
break;
@@ -378,6 +402,10 @@ static int sec_pmic_probe(struct i2c_client *i2c,
sec_devs = s2mps11_devs;
num_sec_devs = ARRAY_SIZE(s2mps11_devs);
break;
+ case S2MPS13X:
+ sec_devs = s2mps13_devs;
+ num_sec_devs = ARRAY_SIZE(s2mps13_devs);
+ break;
case S2MPS14X:
sec_devs = s2mps14_devs;
num_sec_devs = ARRAY_SIZE(s2mps14_devs);
@@ -432,15 +460,6 @@ static int sec_pmic_suspend(struct device *dev)
*/
disable_irq(sec_pmic->irq);
- switch (sec_pmic->device_type) {
- case S2MPS14X:
- case S2MPU02:
- regulator_suspend_prepare(PM_SUSPEND_MEM);
- break;
- default:
- break;
- }
-
return 0;
}
diff --git a/drivers/mfd/sec-irq.c b/drivers/mfd/sec-irq.c
index f9a5786..ba86a91 100644
--- a/drivers/mfd/sec-irq.c
+++ b/drivers/mfd/sec-irq.c
@@ -389,14 +389,22 @@ static const struct regmap_irq_chip s2mps11_irq_chip = {
.ack_base = S2MPS11_REG_INT1,
};
+#define S2MPS1X_IRQ_CHIP_COMMON_DATA \
+ .irqs = s2mps14_irqs, \
+ .num_irqs = ARRAY_SIZE(s2mps14_irqs), \
+ .num_regs = 3, \
+ .status_base = S2MPS14_REG_INT1, \
+ .mask_base = S2MPS14_REG_INT1M, \
+ .ack_base = S2MPS14_REG_INT1 \
+
+static const struct regmap_irq_chip s2mps13_irq_chip = {
+ .name = "s2mps13",
+ S2MPS1X_IRQ_CHIP_COMMON_DATA,
+};
+
static const struct regmap_irq_chip s2mps14_irq_chip = {
.name = "s2mps14",
- .irqs = s2mps14_irqs,
- .num_irqs = ARRAY_SIZE(s2mps14_irqs),
- .num_regs = 3,
- .status_base = S2MPS14_REG_INT1,
- .mask_base = S2MPS14_REG_INT1M,
- .ack_base = S2MPS14_REG_INT1,
+ S2MPS1X_IRQ_CHIP_COMMON_DATA,
};
static const struct regmap_irq_chip s2mpu02_irq_chip = {
@@ -452,6 +460,9 @@ int sec_irq_init(struct sec_pmic_dev *sec_pmic)
case S2MPS11X:
sec_irq_chip = &s2mps11_irq_chip;
break;
+ case S2MPS13X:
+ sec_irq_chip = &s2mps13_irq_chip;
+ break;
case S2MPS14X:
sec_irq_chip = &s2mps14_irq_chip;
break;
diff --git a/drivers/mfd/syscon.c b/drivers/mfd/syscon.c
index ca15878..72373b1 100644
--- a/drivers/mfd/syscon.c
+++ b/drivers/mfd/syscon.c
@@ -15,6 +15,7 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/module.h>
+#include <linux/list.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_platform.h>
@@ -22,31 +23,94 @@
#include <linux/platform_device.h>
#include <linux/regmap.h>
#include <linux/mfd/syscon.h>
+#include <linux/slab.h>
static struct platform_driver syscon_driver;
+static DEFINE_SPINLOCK(syscon_list_slock);
+static LIST_HEAD(syscon_list);
+
struct syscon {
+ struct device_node *np;
struct regmap *regmap;
+ struct list_head list;
+};
+
+static struct regmap_config syscon_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
};
-static int syscon_match_node(struct device *dev, void *data)
+static struct syscon *of_syscon_register(struct device_node *np)
{
- struct device_node *dn = data;
+ struct syscon *syscon;
+ struct regmap *regmap;
+ void __iomem *base;
+ int ret;
+ struct regmap_config syscon_config = syscon_regmap_config;
+
+ if (!of_device_is_compatible(np, "syscon"))
+ return ERR_PTR(-EINVAL);
+
+ syscon = kzalloc(sizeof(*syscon), GFP_KERNEL);
+ if (!syscon)
+ return ERR_PTR(-ENOMEM);
+
+ base = of_iomap(np, 0);
+ if (!base) {
+ ret = -ENOMEM;
+ goto err_map;
+ }
+
+ /* Parse the device's DT node for an endianness specification */
+ if (of_property_read_bool(np, "big-endian"))
+ syscon_config.val_format_endian = REGMAP_ENDIAN_BIG;
+ else if (of_property_read_bool(np, "little-endian"))
+ syscon_config.val_format_endian = REGMAP_ENDIAN_LITTLE;
+
+ regmap = regmap_init_mmio(NULL, base, &syscon_config);
+ if (IS_ERR(regmap)) {
+ pr_err("regmap init failed\n");
+ ret = PTR_ERR(regmap);
+ goto err_regmap;
+ }
+
+ syscon->regmap = regmap;
+ syscon->np = np;
+
+ spin_lock(&syscon_list_slock);
+ list_add_tail(&syscon->list, &syscon_list);
+ spin_unlock(&syscon_list_slock);
- return (dev->of_node == dn) ? 1 : 0;
+ return syscon;
+
+err_regmap:
+ iounmap(base);
+err_map:
+ kfree(syscon);
+ return ERR_PTR(ret);
}
struct regmap *syscon_node_to_regmap(struct device_node *np)
{
- struct syscon *syscon;
- struct device *dev;
+ struct syscon *entry, *syscon = NULL;
- dev = driver_find_device(&syscon_driver.driver, NULL, np,
- syscon_match_node);
- if (!dev)
- return ERR_PTR(-EPROBE_DEFER);
+ spin_lock(&syscon_list_slock);
- syscon = dev_get_drvdata(dev);
+ list_for_each_entry(entry, &syscon_list, list)
+ if (entry->np == np) {
+ syscon = entry;
+ break;
+ }
+
+ spin_unlock(&syscon_list_slock);
+
+ if (!syscon)
+ syscon = of_syscon_register(np);
+
+ if (IS_ERR(syscon))
+ return ERR_CAST(syscon);
return syscon->regmap;
}
@@ -110,17 +174,6 @@ struct regmap *syscon_regmap_lookup_by_phandle(struct device_node *np,
}
EXPORT_SYMBOL_GPL(syscon_regmap_lookup_by_phandle);
-static const struct of_device_id of_syscon_match[] = {
- { .compatible = "syscon", },
- { },
-};
-
-static struct regmap_config syscon_regmap_config = {
- .reg_bits = 32,
- .val_bits = 32,
- .reg_stride = 4,
-};
-
static int syscon_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -167,7 +220,6 @@ static struct platform_driver syscon_driver = {
.driver = {
.name = "syscon",
.owner = THIS_MODULE,
- .of_match_table = of_syscon_match,
},
.probe = syscon_probe,
.id_table = syscon_ids,
diff --git a/drivers/mfd/t7l66xb.c b/drivers/mfd/t7l66xb.c
index 9e04a74..439d905 100644
--- a/drivers/mfd/t7l66xb.c
+++ b/drivers/mfd/t7l66xb.c
@@ -87,7 +87,7 @@ static int t7l66xb_mmc_enable(struct platform_device *mmc)
unsigned long flags;
u8 dev_ctl;
- clk_enable(t7l66xb->clk32k);
+ clk_prepare_enable(t7l66xb->clk32k);
spin_lock_irqsave(&t7l66xb->lock, flags);
@@ -118,7 +118,7 @@ static int t7l66xb_mmc_disable(struct platform_device *mmc)
spin_unlock_irqrestore(&t7l66xb->lock, flags);
- clk_disable(t7l66xb->clk32k);
+ clk_disable_unprepare(t7l66xb->clk32k);
return 0;
}
@@ -285,7 +285,7 @@ static int t7l66xb_suspend(struct platform_device *dev, pm_message_t state)
if (pdata && pdata->suspend)
pdata->suspend(dev);
- clk_disable(t7l66xb->clk48m);
+ clk_disable_unprepare(t7l66xb->clk48m);
return 0;
}
@@ -295,7 +295,7 @@ static int t7l66xb_resume(struct platform_device *dev)
struct t7l66xb *t7l66xb = platform_get_drvdata(dev);
struct t7l66xb_platform_data *pdata = dev_get_platdata(&dev->dev);
- clk_enable(t7l66xb->clk48m);
+ clk_prepare_enable(t7l66xb->clk48m);
if (pdata && pdata->resume)
pdata->resume(dev);
@@ -369,7 +369,7 @@ static int t7l66xb_probe(struct platform_device *dev)
goto err_ioremap;
}
- clk_enable(t7l66xb->clk48m);
+ clk_prepare_enable(t7l66xb->clk48m);
if (pdata && pdata->enable)
pdata->enable(dev);
@@ -414,9 +414,9 @@ static int t7l66xb_remove(struct platform_device *dev)
int ret;
ret = pdata->disable(dev);
- clk_disable(t7l66xb->clk48m);
+ clk_disable_unprepare(t7l66xb->clk48m);
clk_put(t7l66xb->clk48m);
- clk_disable(t7l66xb->clk32k);
+ clk_disable_unprepare(t7l66xb->clk32k);
clk_put(t7l66xb->clk32k);
t7l66xb_detach_irq(dev);
iounmap(t7l66xb->scr);
diff --git a/drivers/mfd/tc3589x.c b/drivers/mfd/tc3589x.c
index 0072e66..aacb372 100644
--- a/drivers/mfd/tc3589x.c
+++ b/drivers/mfd/tc3589x.c
@@ -241,10 +241,8 @@ static struct irq_domain_ops tc3589x_irq_ops = {
static int tc3589x_irq_init(struct tc3589x *tc3589x, struct device_node *np)
{
- int base = tc3589x->irq_base;
-
tc3589x->domain = irq_domain_add_simple(
- np, TC3589x_NR_INTERNAL_IRQS, base,
+ np, TC3589x_NR_INTERNAL_IRQS, 0,
&tc3589x_irq_ops, tc3589x);
if (!tc3589x->domain) {
@@ -298,7 +296,7 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
if (blocks & TC3589x_BLOCK_GPIO) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_gpio,
ARRAY_SIZE(tc3589x_dev_gpio), NULL,
- tc3589x->irq_base, tc3589x->domain);
+ 0, tc3589x->domain);
if (ret) {
dev_err(tc3589x->dev, "failed to add gpio child\n");
return ret;
@@ -309,7 +307,7 @@ static int tc3589x_device_init(struct tc3589x *tc3589x)
if (blocks & TC3589x_BLOCK_KEYPAD) {
ret = mfd_add_devices(tc3589x->dev, -1, tc3589x_dev_keypad,
ARRAY_SIZE(tc3589x_dev_keypad), NULL,
- tc3589x->irq_base, tc3589x->domain);
+ 0, tc3589x->domain);
if (ret) {
dev_err(tc3589x->dev, "failed to keypad child\n");
return ret;
@@ -404,7 +402,6 @@ static int tc3589x_probe(struct i2c_client *i2c,
tc3589x->dev = &i2c->dev;
tc3589x->i2c = i2c;
tc3589x->pdata = pdata;
- tc3589x->irq_base = pdata->irq_base;
switch (version) {
case TC3589X_TC35893:
diff --git a/drivers/mfd/tc6387xb.c b/drivers/mfd/tc6387xb.c
index e71f880..85fab37 100644
--- a/drivers/mfd/tc6387xb.c
+++ b/drivers/mfd/tc6387xb.c
@@ -52,7 +52,7 @@ static int tc6387xb_suspend(struct platform_device *dev, pm_message_t state)
if (pdata && pdata->suspend)
pdata->suspend(dev);
- clk_disable(tc6387xb->clk32k);
+ clk_disable_unprepare(tc6387xb->clk32k);
return 0;
}
@@ -62,7 +62,7 @@ static int tc6387xb_resume(struct platform_device *dev)
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
struct tc6387xb_platform_data *pdata = dev_get_platdata(&dev->dev);
- clk_enable(tc6387xb->clk32k);
+ clk_prepare_enable(tc6387xb->clk32k);
if (pdata && pdata->resume)
pdata->resume(dev);
@@ -100,7 +100,7 @@ static int tc6387xb_mmc_enable(struct platform_device *mmc)
struct platform_device *dev = to_platform_device(mmc->dev.parent);
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_enable(tc6387xb->clk32k);
+ clk_prepare_enable(tc6387xb->clk32k);
tmio_core_mmc_enable(tc6387xb->scr + 0x200, 0,
tc6387xb_mmc_resources[0].start & 0xfffe);
@@ -113,7 +113,7 @@ static int tc6387xb_mmc_disable(struct platform_device *mmc)
struct platform_device *dev = to_platform_device(mmc->dev.parent);
struct tc6387xb *tc6387xb = platform_get_drvdata(dev);
- clk_disable(tc6387xb->clk32k);
+ clk_disable_unprepare(tc6387xb->clk32k);
return 0;
}
@@ -214,7 +214,7 @@ static int tc6387xb_remove(struct platform_device *dev)
mfd_remove_devices(&dev->dev);
iounmap(tc6387xb->scr);
release_resource(&tc6387xb->rscr);
- clk_disable(tc6387xb->clk32k);
+ clk_disable_unprepare(tc6387xb->clk32k);
clk_put(tc6387xb->clk32k);
kfree(tc6387xb);
diff --git a/drivers/mfd/tc6393xb.c b/drivers/mfd/tc6393xb.c
index 4fac16b..d35f11f 100644
--- a/drivers/mfd/tc6393xb.c
+++ b/drivers/mfd/tc6393xb.c
@@ -263,6 +263,17 @@ static int tc6393xb_ohci_disable(struct platform_device *dev)
return 0;
}
+static int tc6393xb_ohci_suspend(struct platform_device *dev)
+{
+ struct tc6393xb_platform_data *tcpd = dev_get_platdata(dev->dev.parent);
+
+ /* We can't properly store/restore OHCI state, so fail here */
+ if (tcpd->resume_restore)
+ return -EBUSY;
+
+ return tc6393xb_ohci_disable(dev);
+}
+
static int tc6393xb_fb_enable(struct platform_device *dev)
{
struct tc6393xb *tc6393xb = dev_get_drvdata(dev->dev.parent);
@@ -403,7 +414,7 @@ static struct mfd_cell tc6393xb_cells[] = {
.num_resources = ARRAY_SIZE(tc6393xb_ohci_resources),
.resources = tc6393xb_ohci_resources,
.enable = tc6393xb_ohci_enable,
- .suspend = tc6393xb_ohci_disable,
+ .suspend = tc6393xb_ohci_suspend,
.resume = tc6393xb_ohci_enable,
.disable = tc6393xb_ohci_disable,
},
@@ -654,7 +665,7 @@ static int tc6393xb_probe(struct platform_device *dev)
goto err_ioremap;
}
- ret = clk_enable(tc6393xb->clk);
+ ret = clk_prepare_enable(tc6393xb->clk);
if (ret)
goto err_clk_enable;
@@ -717,7 +728,7 @@ err_gpio_add:
gpiochip_remove(&tc6393xb->gpio);
tcpd->disable(dev);
err_enable:
- clk_disable(tc6393xb->clk);
+ clk_disable_unprepare(tc6393xb->clk);
err_clk_enable:
iounmap(tc6393xb->scr);
err_ioremap:
@@ -748,7 +759,7 @@ static int tc6393xb_remove(struct platform_device *dev)
gpiochip_remove(&tc6393xb->gpio);
ret = tcpd->disable(dev);
- clk_disable(tc6393xb->clk);
+ clk_disable_unprepare(tc6393xb->clk);
iounmap(tc6393xb->scr);
release_resource(&tc6393xb->rscr);
clk_put(tc6393xb->clk);
@@ -776,7 +787,7 @@ static int tc6393xb_suspend(struct platform_device *dev, pm_message_t state)
ioread8(tc6393xb->scr + SCR_GPI_BCR(i));
}
ret = tcpd->suspend(dev);
- clk_disable(tc6393xb->clk);
+ clk_disable_unprepare(tc6393xb->clk);
return ret;
}
@@ -788,7 +799,7 @@ static int tc6393xb_resume(struct platform_device *dev)
int ret;
int i;
- clk_enable(tc6393xb->clk);
+ clk_prepare_enable(tc6393xb->clk);
ret = tcpd->resume(dev);
if (ret)
diff --git a/drivers/mfd/tps65090.c b/drivers/mfd/tps65090.c
index 1c3e6e2..14b62e1 100644
--- a/drivers/mfd/tps65090.c
+++ b/drivers/mfd/tps65090.c
@@ -76,58 +76,58 @@ static struct mfd_cell tps65090s[] = {
static const struct regmap_irq tps65090_irqs[] = {
/* INT1 IRQs*/
[TPS65090_IRQ_VAC_STATUS_CHANGE] = {
- .mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
+ .mask = TPS65090_INT1_MASK_VAC_STATUS_CHANGE,
},
[TPS65090_IRQ_VSYS_STATUS_CHANGE] = {
- .mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
+ .mask = TPS65090_INT1_MASK_VSYS_STATUS_CHANGE,
},
[TPS65090_IRQ_BAT_STATUS_CHANGE] = {
- .mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
+ .mask = TPS65090_INT1_MASK_BAT_STATUS_CHANGE,
},
[TPS65090_IRQ_CHARGING_STATUS_CHANGE] = {
- .mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
+ .mask = TPS65090_INT1_MASK_CHARGING_STATUS_CHANGE,
},
[TPS65090_IRQ_CHARGING_COMPLETE] = {
- .mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
+ .mask = TPS65090_INT1_MASK_CHARGING_COMPLETE,
},
[TPS65090_IRQ_OVERLOAD_DCDC1] = {
- .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
+ .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC1,
},
[TPS65090_IRQ_OVERLOAD_DCDC2] = {
- .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
+ .mask = TPS65090_INT1_MASK_OVERLOAD_DCDC2,
},
/* INT2 IRQs*/
[TPS65090_IRQ_OVERLOAD_DCDC3] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_DCDC3,
},
[TPS65090_IRQ_OVERLOAD_FET1] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET1,
},
[TPS65090_IRQ_OVERLOAD_FET2] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET2,
},
[TPS65090_IRQ_OVERLOAD_FET3] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET3,
},
[TPS65090_IRQ_OVERLOAD_FET4] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET4,
},
[TPS65090_IRQ_OVERLOAD_FET5] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET5,
},
[TPS65090_IRQ_OVERLOAD_FET6] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET6,
},
[TPS65090_IRQ_OVERLOAD_FET7] = {
- .reg_offset = 1,
- .mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
+ .reg_offset = 1,
+ .mask = TPS65090_INT2_MASK_OVERLOAD_FET7,
},
};
@@ -176,7 +176,7 @@ MODULE_DEVICE_TABLE(of, tps65090_of_match);
#endif
static int tps65090_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
+ const struct i2c_device_id *id)
{
struct tps65090_platform_data *pdata = dev_get_platdata(&client->dev);
int irq_base = 0;
@@ -210,11 +210,11 @@ static int tps65090_i2c_probe(struct i2c_client *client,
if (client->irq) {
ret = regmap_add_irq_chip(tps65090->rmap, client->irq,
- IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
- &tps65090_irq_chip, &tps65090->irq_data);
- if (ret) {
- dev_err(&client->dev,
- "IRQ init failed with err: %d\n", ret);
+ IRQF_ONESHOT | IRQF_TRIGGER_LOW, irq_base,
+ &tps65090_irq_chip, &tps65090->irq_data);
+ if (ret) {
+ dev_err(&client->dev,
+ "IRQ init failed with err: %d\n", ret);
return ret;
}
} else {
@@ -223,8 +223,8 @@ static int tps65090_i2c_probe(struct i2c_client *client,
}
ret = mfd_add_devices(tps65090->dev, -1, tps65090s,
- ARRAY_SIZE(tps65090s), NULL,
- 0, regmap_irq_get_domain(tps65090->irq_data));
+ ARRAY_SIZE(tps65090s), NULL,
+ 0, regmap_irq_get_domain(tps65090->irq_data));
if (ret) {
dev_err(&client->dev, "add mfd devices failed with err: %d\n",
ret);
diff --git a/drivers/mfd/tps65217.c b/drivers/mfd/tps65217.c
index a8ee52c..80a919a 100644
--- a/drivers/mfd/tps65217.c
+++ b/drivers/mfd/tps65217.c
@@ -33,9 +33,11 @@
static const struct mfd_cell tps65217s[] = {
{
.name = "tps65217-pmic",
+ .of_compatible = "ti,tps65217-pmic",
},
{
.name = "tps65217-bl",
+ .of_compatible = "ti,tps65217-bl",
},
};
diff --git a/drivers/mfd/twl4030-power.c b/drivers/mfd/twl4030-power.c
index 50f9091..7d63e32 100644
--- a/drivers/mfd/twl4030-power.c
+++ b/drivers/mfd/twl4030-power.c
@@ -831,6 +831,9 @@ static struct twl4030_power_data osc_off_idle = {
static struct of_device_id twl4030_power_of_match[] = {
{
+ .compatible = "ti,twl4030-power",
+ },
+ {
.compatible = "ti,twl4030-power-reset",
.data = &omap3_reset,
},
diff --git a/drivers/mfd/vexpress-sysreg.c b/drivers/mfd/vexpress-sysreg.c
index 9e21e4f..8f43ab8 100644
--- a/drivers/mfd/vexpress-sysreg.c
+++ b/drivers/mfd/vexpress-sysreg.c
@@ -223,7 +223,7 @@ static int vexpress_sysreg_probe(struct platform_device *pdev)
vexpress_config_set_master(vexpress_sysreg_get_master());
/* Confirm board type against DT property, if available */
- if (of_property_read_u32(of_allnodes, "arm,hbi", &dt_hbi) == 0) {
+ if (of_property_read_u32(of_root, "arm,hbi", &dt_hbi) == 0) {
u32 id = vexpress_get_procid(VEXPRESS_SITE_MASTER);
u32 hbi = (id >> SYS_PROCIDx_HBI_SHIFT) & SYS_HBI_MASK;
diff --git a/drivers/mfd/viperboard.c b/drivers/mfd/viperboard.c
index 3c2b8f9..e6b3c70 100644
--- a/drivers/mfd/viperboard.c
+++ b/drivers/mfd/viperboard.c
@@ -93,9 +93,8 @@ static int vprbrd_probe(struct usb_interface *interface,
version >> 8, version & 0xff,
vb->usb_dev->bus->busnum, vb->usb_dev->devnum);
- ret = mfd_add_devices(&interface->dev, PLATFORM_DEVID_AUTO,
- vprbrd_devs, ARRAY_SIZE(vprbrd_devs), NULL, 0,
- NULL);
+ ret = mfd_add_hotplug_devices(&interface->dev, vprbrd_devs,
+ ARRAY_SIZE(vprbrd_devs));
if (ret != 0) {
dev_err(&interface->dev, "Failed to add mfd devices to core.");
goto error;
diff --git a/drivers/mfd/wm5102-tables.c b/drivers/mfd/wm5102-tables.c
index d6f35bb..b326a82 100644
--- a/drivers/mfd/wm5102-tables.c
+++ b/drivers/mfd/wm5102-tables.c
@@ -336,8 +336,6 @@ static const struct reg_default wm5102_reg_default[] = {
{ 0x00000218, 0x01A6 }, /* R536 - Mic Bias Ctrl 1 */
{ 0x00000219, 0x01A6 }, /* R537 - Mic Bias Ctrl 2 */
{ 0x0000021A, 0x01A6 }, /* R538 - Mic Bias Ctrl 3 */
- { 0x00000225, 0x0400 }, /* R549 - HP Ctrl 1L */
- { 0x00000226, 0x0400 }, /* R550 - HP Ctrl 1R */
{ 0x00000293, 0x0000 }, /* R659 - Accessory Detect Mode 1 */
{ 0x0000029B, 0x0020 }, /* R667 - Headphone Detect 1 */
{ 0x0000029C, 0x0000 }, /* R668 - Headphone Detect 2 */
@@ -1112,6 +1110,8 @@ static bool wm5102_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_BIAS_CTRL_1:
case ARIZONA_MIC_BIAS_CTRL_2:
case ARIZONA_MIC_BIAS_CTRL_3:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
@@ -1949,6 +1949,8 @@ static bool wm5102_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_DSP1_SCRATCH_1:
case ARIZONA_DSP1_SCRATCH_2:
case ARIZONA_DSP1_SCRATCH_3:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
case ARIZONA_HEADPHONE_DETECT_2:
case ARIZONA_HP_DACVAL:
case ARIZONA_MIC_DETECT_3:
diff --git a/drivers/mfd/wm5110-tables.c b/drivers/mfd/wm5110-tables.c
index 4642b5b..12cad94 100644
--- a/drivers/mfd/wm5110-tables.c
+++ b/drivers/mfd/wm5110-tables.c
@@ -895,8 +895,16 @@ static const struct reg_default wm5110_reg_default[] = {
{ 0x00000548, 0x1818 }, /* R1352 - AIF2 Frame Ctrl 2 */
{ 0x00000549, 0x0000 }, /* R1353 - AIF2 Frame Ctrl 3 */
{ 0x0000054A, 0x0001 }, /* R1354 - AIF2 Frame Ctrl 4 */
+ { 0x0000054B, 0x0002 }, /* R1355 - AIF2 Frame Ctrl 5 */
+ { 0x0000054C, 0x0003 }, /* R1356 - AIF2 Frame Ctrl 6 */
+ { 0x0000054D, 0x0004 }, /* R1357 - AIF2 Frame Ctrl 7 */
+ { 0x0000054E, 0x0005 }, /* R1358 - AIF2 Frame Ctrl 8 */
{ 0x00000551, 0x0000 }, /* R1361 - AIF2 Frame Ctrl 11 */
{ 0x00000552, 0x0001 }, /* R1362 - AIF2 Frame Ctrl 12 */
+ { 0x00000553, 0x0002 }, /* R1363 - AIF2 Frame Ctrl 13 */
+ { 0x00000554, 0x0003 }, /* R1364 - AIF2 Frame Ctrl 14 */
+ { 0x00000555, 0x0004 }, /* R1365 - AIF2 Frame Ctrl 15 */
+ { 0x00000556, 0x0005 }, /* R1366 - AIF2 Frame Ctrl 16 */
{ 0x00000559, 0x0000 }, /* R1369 - AIF2 Tx Enables */
{ 0x0000055A, 0x0000 }, /* R1370 - AIF2 Rx Enables */
{ 0x00000580, 0x000C }, /* R1408 - AIF3 BCLK Ctrl */
@@ -1790,6 +1798,8 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_BIAS_CTRL_1:
case ARIZONA_MIC_BIAS_CTRL_2:
case ARIZONA_MIC_BIAS_CTRL_3:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
@@ -1934,8 +1944,16 @@ static bool wm5110_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_AIF2_FRAME_CTRL_2:
case ARIZONA_AIF2_FRAME_CTRL_3:
case ARIZONA_AIF2_FRAME_CTRL_4:
+ case ARIZONA_AIF2_FRAME_CTRL_5:
+ case ARIZONA_AIF2_FRAME_CTRL_6:
+ case ARIZONA_AIF2_FRAME_CTRL_7:
+ case ARIZONA_AIF2_FRAME_CTRL_8:
case ARIZONA_AIF2_FRAME_CTRL_11:
case ARIZONA_AIF2_FRAME_CTRL_12:
+ case ARIZONA_AIF2_FRAME_CTRL_13:
+ case ARIZONA_AIF2_FRAME_CTRL_14:
+ case ARIZONA_AIF2_FRAME_CTRL_15:
+ case ARIZONA_AIF2_FRAME_CTRL_16:
case ARIZONA_AIF2_TX_ENABLES:
case ARIZONA_AIF2_RX_ENABLES:
case ARIZONA_AIF3_BCLK_CTRL:
@@ -2825,6 +2843,8 @@ static bool wm5110_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
case ARIZONA_ASYNC_SAMPLE_RATE_2_STATUS:
case ARIZONA_MIC_DETECT_3:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
case ARIZONA_HEADPHONE_DETECT_2:
case ARIZONA_INPUT_ENABLES_STATUS:
case ARIZONA_OUTPUT_STATUS_1:
diff --git a/drivers/mfd/wm8350-core.c b/drivers/mfd/wm8350-core.c
index 4ab527f..f5124a8 100644
--- a/drivers/mfd/wm8350-core.c
+++ b/drivers/mfd/wm8350-core.c
@@ -308,7 +308,7 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
goto err;
}
- mode = id2 & WM8350_CONF_STS_MASK >> 10;
+ mode = (id2 & WM8350_CONF_STS_MASK) >> 10;
cust_id = id2 & WM8350_CUST_ID_MASK;
chip_rev = (id2 & WM8350_CHIP_REV_MASK) >> 12;
dev_info(wm8350->dev,
diff --git a/drivers/mfd/wm8994-core.c b/drivers/mfd/wm8994-core.c
index e6fab94..6ca9d25 100644
--- a/drivers/mfd/wm8994-core.c
+++ b/drivers/mfd/wm8994-core.c
@@ -116,7 +116,7 @@ static const char *wm8958_main_supplies[] = {
"SPKVDD2",
};
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int wm8994_suspend(struct device *dev)
{
struct wm8994 *wm8994 = dev_get_drvdata(dev);
diff --git a/drivers/mfd/wm8997-tables.c b/drivers/mfd/wm8997-tables.c
index 510da3b..c0c25d75 100644
--- a/drivers/mfd/wm8997-tables.c
+++ b/drivers/mfd/wm8997-tables.c
@@ -670,6 +670,7 @@ static const struct reg_default wm8997_reg_default[] = {
{ 0x00000C23, 0x0000 }, /* R3107 - Misc Pad Ctrl 4 */
{ 0x00000C24, 0x0000 }, /* R3108 - Misc Pad Ctrl 5 */
{ 0x00000D08, 0xFFFF }, /* R3336 - Interrupt Status 1 Mask */
+ { 0x00000D09, 0xFFFF }, /* R3337 - Interrupt Status 2 Mask */
{ 0x00000D0A, 0xFFFF }, /* R3338 - Interrupt Status 3 Mask */
{ 0x00000D0B, 0xFFFF }, /* R3339 - Interrupt Status 4 Mask */
{ 0x00000D0C, 0xFEFF }, /* R3340 - Interrupt Status 5 Mask */
@@ -886,6 +887,8 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_MIC_BIAS_CTRL_1:
case ARIZONA_MIC_BIAS_CTRL_2:
case ARIZONA_MIC_BIAS_CTRL_3:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
case ARIZONA_ACCESSORY_DETECT_MODE_1:
case ARIZONA_HEADPHONE_DETECT_1:
case ARIZONA_HEADPHONE_DETECT_2:
@@ -1328,6 +1331,7 @@ static bool wm8997_readable_register(struct device *dev, unsigned int reg)
case ARIZONA_INTERRUPT_STATUS_4:
case ARIZONA_INTERRUPT_STATUS_5:
case ARIZONA_INTERRUPT_STATUS_1_MASK:
+ case ARIZONA_INTERRUPT_STATUS_2_MASK:
case ARIZONA_INTERRUPT_STATUS_3_MASK:
case ARIZONA_INTERRUPT_STATUS_4_MASK:
case ARIZONA_INTERRUPT_STATUS_5_MASK:
@@ -1477,6 +1481,8 @@ static bool wm8997_volatile_register(struct device *dev, unsigned int reg)
case ARIZONA_SAMPLE_RATE_3_STATUS:
case ARIZONA_ASYNC_SAMPLE_RATE_1_STATUS:
case ARIZONA_MIC_DETECT_3:
+ case ARIZONA_HP_CTRL_1L:
+ case ARIZONA_HP_CTRL_1R:
case ARIZONA_HEADPHONE_DETECT_2:
case ARIZONA_INPUT_ENABLES_STATUS:
case ARIZONA_OUTPUT_STATUS_1:
diff --git a/drivers/misc/Kconfig b/drivers/misc/Kconfig
index bbeb451..006242c 100644
--- a/drivers/misc/Kconfig
+++ b/drivers/misc/Kconfig
@@ -75,7 +75,7 @@ config ATMEL_TCB_CLKSRC
config ATMEL_TCB_CLKSRC_BLOCK
int
depends on ATMEL_TCB_CLKSRC
- prompt "TC Block" if ARCH_AT91RM9200 || ARCH_AT91SAM9260 || CPU_AT32AP700X
+ prompt "TC Block" if CPU_AT32AP700X
default 0
range 0 1
help
diff --git a/drivers/misc/apds990x.c b/drivers/misc/apds990x.c
index 868a30a..3739ffa 100644
--- a/drivers/misc/apds990x.c
+++ b/drivers/misc/apds990x.c
@@ -609,7 +609,7 @@ static int apds990x_detect(struct apds990x_chip *chip)
return ret;
}
-#if defined(CONFIG_PM) || defined(CONFIG_PM_RUNTIME)
+#ifdef CONFIG_PM
static int apds990x_chip_on(struct apds990x_chip *chip)
{
int err = regulator_bulk_enable(ARRAY_SIZE(chip->regs),
@@ -1237,7 +1237,7 @@ static int apds990x_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int apds990x_runtime_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
diff --git a/drivers/misc/bh1770glc.c b/drivers/misc/bh1770glc.c
index 7b55f8a..b756381 100644
--- a/drivers/misc/bh1770glc.c
+++ b/drivers/misc/bh1770glc.c
@@ -1358,7 +1358,7 @@ static int bh1770_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int bh1770_runtime_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
diff --git a/drivers/misc/eeprom/at25.c b/drivers/misc/eeprom/at25.c
index 634f729..0a1af93 100644
--- a/drivers/misc/eeprom/at25.c
+++ b/drivers/misc/eeprom/at25.c
@@ -18,7 +18,7 @@
#include <linux/spi/spi.h>
#include <linux/spi/eeprom.h>
-#include <linux/of.h>
+#include <linux/property.h>
/*
* NOTE: this is an *EEPROM* driver. The vagaries of product naming
@@ -301,35 +301,33 @@ static ssize_t at25_mem_write(struct memory_accessor *mem, const char *buf,
/*-------------------------------------------------------------------------*/
-static int at25_np_to_chip(struct device *dev,
- struct device_node *np,
- struct spi_eeprom *chip)
+static int at25_fw_to_chip(struct device *dev, struct spi_eeprom *chip)
{
u32 val;
memset(chip, 0, sizeof(*chip));
- strncpy(chip->name, np->name, sizeof(chip->name));
+ strncpy(chip->name, "at25", sizeof(chip->name));
- if (of_property_read_u32(np, "size", &val) == 0 ||
- of_property_read_u32(np, "at25,byte-len", &val) == 0) {
+ if (device_property_read_u32(dev, "size", &val) == 0 ||
+ device_property_read_u32(dev, "at25,byte-len", &val) == 0) {
chip->byte_len = val;
} else {
dev_err(dev, "Error: missing \"size\" property\n");
return -ENODEV;
}
- if (of_property_read_u32(np, "pagesize", &val) == 0 ||
- of_property_read_u32(np, "at25,page-size", &val) == 0) {
+ if (device_property_read_u32(dev, "pagesize", &val) == 0 ||
+ device_property_read_u32(dev, "at25,page-size", &val) == 0) {
chip->page_size = (u16)val;
} else {
dev_err(dev, "Error: missing \"pagesize\" property\n");
return -ENODEV;
}
- if (of_property_read_u32(np, "at25,addr-mode", &val) == 0) {
+ if (device_property_read_u32(dev, "at25,addr-mode", &val) == 0) {
chip->flags = (u16)val;
} else {
- if (of_property_read_u32(np, "address-width", &val)) {
+ if (device_property_read_u32(dev, "address-width", &val)) {
dev_err(dev,
"Error: missing \"address-width\" property\n");
return -ENODEV;
@@ -350,7 +348,7 @@ static int at25_np_to_chip(struct device *dev,
val);
return -ENODEV;
}
- if (of_find_property(np, "read-only", NULL))
+ if (device_property_present(dev, "read-only"))
chip->flags |= EE_READONLY;
}
return 0;
@@ -360,21 +358,15 @@ static int at25_probe(struct spi_device *spi)
{
struct at25_data *at25 = NULL;
struct spi_eeprom chip;
- struct device_node *np = spi->dev.of_node;
int err;
int sr;
int addrlen;
/* Chip description */
if (!spi->dev.platform_data) {
- if (np) {
- err = at25_np_to_chip(&spi->dev, np, &chip);
- if (err)
- return err;
- } else {
- dev_err(&spi->dev, "Error: no chip description\n");
- return -ENODEV;
- }
+ err = at25_fw_to_chip(&spi->dev, &chip);
+ if (err)
+ return err;
} else
chip = *(struct spi_eeprom *)spi->dev.platform_data;
diff --git a/drivers/misc/eeprom/eeprom_93cx6.c b/drivers/misc/eeprom/eeprom_93cx6.c
index 0ff4b02..0cf2c9d 100644
--- a/drivers/misc/eeprom/eeprom_93cx6.c
+++ b/drivers/misc/eeprom/eeprom_93cx6.c
@@ -170,7 +170,7 @@ static void eeprom_93cx6_read_bits(struct eeprom_93cx6 *eeprom,
}
/**
- * eeprom_93cx6_read - Read multiple words from eeprom
+ * eeprom_93cx6_read - Read a word from eeprom
* @eeprom: Pointer to eeprom structure
* @word: Word index from where we should start reading
* @data: target pointer where the information will have to be stored
@@ -235,6 +235,66 @@ void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom, const u8 word,
EXPORT_SYMBOL_GPL(eeprom_93cx6_multiread);
/**
+ * eeprom_93cx6_readb - Read a byte from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @word: Byte index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ *
+ * This function will read a byte of the eeprom data
+ * into the given data pointer.
+ */
+void eeprom_93cx6_readb(struct eeprom_93cx6 *eeprom, const u8 byte,
+ u8 *data)
+{
+ u16 command;
+ u16 tmp;
+
+ /*
+ * Initialize the eeprom register
+ */
+ eeprom_93cx6_startup(eeprom);
+
+ /*
+ * Select the read opcode and the byte to be read.
+ */
+ command = (PCI_EEPROM_READ_OPCODE << (eeprom->width + 1)) | byte;
+ eeprom_93cx6_write_bits(eeprom, command,
+ PCI_EEPROM_WIDTH_OPCODE + eeprom->width + 1);
+
+ /*
+ * Read the requested 8 bits.
+ */
+ eeprom_93cx6_read_bits(eeprom, &tmp, 8);
+ *data = tmp & 0xff;
+
+ /*
+ * Cleanup eeprom register.
+ */
+ eeprom_93cx6_cleanup(eeprom);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_readb);
+
+/**
+ * eeprom_93cx6_multireadb - Read multiple bytes from eeprom
+ * @eeprom: Pointer to eeprom structure
+ * @byte: Index from where we should start reading
+ * @data: target pointer where the information will have to be stored
+ * @words: Number of bytes that should be read.
+ *
+ * This function will read all requested bytes from the eeprom,
+ * this is done by calling eeprom_93cx6_readb() multiple times.
+ */
+void eeprom_93cx6_multireadb(struct eeprom_93cx6 *eeprom, const u8 byte,
+ u8 *data, const u16 bytes)
+{
+ unsigned int i;
+
+ for (i = 0; i < bytes; i++)
+ eeprom_93cx6_readb(eeprom, byte + i, &data[i]);
+}
+EXPORT_SYMBOL_GPL(eeprom_93cx6_multireadb);
+
+/**
* eeprom_93cx6_wren - set the write enable state
* @eeprom: Pointer to eeprom structure
* @enable: true to enable writes, otherwise disable writes
diff --git a/drivers/misc/enclosure.c b/drivers/misc/enclosure.c
index 2cf2bbc..180a544 100644
--- a/drivers/misc/enclosure.c
+++ b/drivers/misc/enclosure.c
@@ -187,6 +187,7 @@ void enclosure_unregister(struct enclosure_device *edev)
EXPORT_SYMBOL_GPL(enclosure_unregister);
#define ENCLOSURE_NAME_SIZE 64
+#define COMPONENT_NAME_SIZE 64
static void enclosure_link_name(struct enclosure_component *cdev, char *name)
{
@@ -246,6 +247,29 @@ static void enclosure_component_release(struct device *dev)
put_device(dev->parent);
}
+static struct enclosure_component *
+enclosure_component_find_by_name(struct enclosure_device *edev,
+ const char *name)
+{
+ int i;
+ const char *cname;
+ struct enclosure_component *ecomp;
+
+ if (!edev || !name || !name[0])
+ return NULL;
+
+ for (i = 0; i < edev->components; i++) {
+ ecomp = &edev->component[i];
+ cname = dev_name(&ecomp->cdev);
+ if (ecomp->number != -1 &&
+ cname && cname[0] &&
+ !strcmp(cname, name))
+ return ecomp;
+ }
+
+ return NULL;
+}
+
static const struct attribute_group *enclosure_component_groups[];
/**
@@ -269,7 +293,8 @@ enclosure_component_register(struct enclosure_device *edev,
{
struct enclosure_component *ecomp;
struct device *cdev;
- int err;
+ int err, i;
+ char newname[COMPONENT_NAME_SIZE];
if (number >= edev->components)
return ERR_PTR(-EINVAL);
@@ -283,9 +308,20 @@ enclosure_component_register(struct enclosure_device *edev,
ecomp->number = number;
cdev = &ecomp->cdev;
cdev->parent = get_device(&edev->edev);
- if (name && name[0])
- dev_set_name(cdev, "%s", name);
- else
+
+ if (name && name[0]) {
+ /* Some hardware (e.g. enclosure in RX300 S6) has components
+ * with non unique names. Registering duplicates in sysfs
+ * will lead to warnings during bootup. So make the names
+ * unique by appending consecutive numbers -1, -2, ... */
+ i = 1;
+ snprintf(newname, COMPONENT_NAME_SIZE,
+ "%s", name);
+ while (enclosure_component_find_by_name(edev, newname))
+ snprintf(newname, COMPONENT_NAME_SIZE,
+ "%s-%i", name, i++);
+ dev_set_name(cdev, "%s", newname);
+ } else
dev_set_name(cdev, "%u", number);
cdev->release = enclosure_component_release;
diff --git a/drivers/misc/genwqe/card_dev.c b/drivers/misc/genwqe/card_dev.c
index 5918586..c49d244 100644
--- a/drivers/misc/genwqe/card_dev.c
+++ b/drivers/misc/genwqe/card_dev.c
@@ -395,7 +395,7 @@ static void genwqe_vma_open(struct vm_area_struct *vma)
static void genwqe_vma_close(struct vm_area_struct *vma)
{
unsigned long vsize = vma->vm_end - vma->vm_start;
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = file_inode(vma->vm_file);
struct dma_mapping *dma_map;
struct genwqe_dev *cd = container_of(inode->i_cdev, struct genwqe_dev,
cdev_genwqe);
diff --git a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
index d324f8a..63fe096 100644
--- a/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
+++ b/drivers/misc/lis3lv02d/lis3lv02d_i2c.c
@@ -235,7 +235,7 @@ static int lis3lv02d_i2c_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int lis3_i2c_runtime_suspend(struct device *dev)
{
struct i2c_client *client = container_of(dev, struct i2c_client, dev);
@@ -253,7 +253,7 @@ static int lis3_i2c_runtime_resume(struct device *dev)
lis3lv02d_poweron(lis3);
return 0;
}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
static const struct i2c_device_id lis3lv02d_id[] = {
{"lis3lv02d", LIS3LV02D},
diff --git a/drivers/misc/mei/mei_dev.h b/drivers/misc/mei/mei_dev.h
index 71744b1..61b04d7 100644
--- a/drivers/misc/mei/mei_dev.h
+++ b/drivers/misc/mei/mei_dev.h
@@ -530,9 +530,9 @@ struct mei_device {
* Power Gating support
*/
enum mei_pg_event pg_event;
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
struct dev_pm_domain pg_domain;
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
unsigned char rd_msg_buf[MEI_RD_MSG_BUF_SIZE];
u32 rd_msg_hdr;
diff --git a/drivers/misc/mei/pci-me.c b/drivers/misc/mei/pci-me.c
index f3225b1..cf20d39 100644
--- a/drivers/misc/mei/pci-me.c
+++ b/drivers/misc/mei/pci-me.c
@@ -89,13 +89,13 @@ static const struct pci_device_id mei_me_pci_tbl[] = {
MODULE_DEVICE_TABLE(pci, mei_me_pci_tbl);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static inline void mei_me_set_pm_domain(struct mei_device *dev);
static inline void mei_me_unset_pm_domain(struct mei_device *dev);
#else
static inline void mei_me_set_pm_domain(struct mei_device *dev) {}
static inline void mei_me_unset_pm_domain(struct mei_device *dev) {}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
/**
* mei_me_quirk_probe - probe for devices that doesn't valid ME interface
@@ -357,7 +357,7 @@ static int mei_me_pci_resume(struct device *device)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int mei_me_pm_runtime_idle(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
@@ -453,9 +453,7 @@ static inline void mei_me_unset_pm_domain(struct mei_device *dev)
/* stop using pm callbacks if any */
dev->dev->pm_domain = NULL;
}
-#endif /* CONFIG_PM_RUNTIME */
-#ifdef CONFIG_PM
static const struct dev_pm_ops mei_me_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mei_me_pci_suspend,
mei_me_pci_resume)
diff --git a/drivers/misc/mei/pci-txe.c b/drivers/misc/mei/pci-txe.c
index bee1c6fb..1f572de 100644
--- a/drivers/misc/mei/pci-txe.c
+++ b/drivers/misc/mei/pci-txe.c
@@ -42,13 +42,13 @@ static const struct pci_device_id mei_txe_pci_tbl[] = {
};
MODULE_DEVICE_TABLE(pci, mei_txe_pci_tbl);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static inline void mei_txe_set_pm_domain(struct mei_device *dev);
static inline void mei_txe_unset_pm_domain(struct mei_device *dev);
#else
static inline void mei_txe_set_pm_domain(struct mei_device *dev) {}
static inline void mei_txe_unset_pm_domain(struct mei_device *dev) {}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
static void mei_txe_pci_iounmap(struct pci_dev *pdev, struct mei_txe_hw *hw)
{
@@ -295,7 +295,7 @@ static int mei_txe_pci_resume(struct device *device)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int mei_txe_pm_runtime_idle(struct device *device)
{
struct pci_dev *pdev = to_pci_dev(device);
@@ -401,9 +401,7 @@ static inline void mei_txe_unset_pm_domain(struct mei_device *dev)
/* stop using pm callbacks if any */
dev->dev->pm_domain = NULL;
}
-#endif /* CONFIG_PM_RUNTIME */
-#ifdef CONFIG_PM
static const struct dev_pm_ops mei_txe_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(mei_txe_pci_suspend,
mei_txe_pci_resume)
diff --git a/drivers/misc/mic/card/mic_virtio.c b/drivers/misc/mic/card/mic_virtio.c
index e647947..e486a0c 100644
--- a/drivers/misc/mic/card/mic_virtio.c
+++ b/drivers/misc/mic/card/mic_virtio.c
@@ -68,7 +68,7 @@ static inline struct device *mic_dev(struct mic_vdev *mvdev)
}
/* This gets the device's feature bits. */
-static u32 mic_get_features(struct virtio_device *vdev)
+static u64 mic_get_features(struct virtio_device *vdev)
{
unsigned int i, bits;
u32 features = 0;
@@ -76,8 +76,7 @@ static u32 mic_get_features(struct virtio_device *vdev)
u8 __iomem *in_features = mic_vq_features(desc);
int feature_len = ioread8(&desc->feature_len);
- bits = min_t(unsigned, feature_len,
- sizeof(vdev->features)) * 8;
+ bits = min_t(unsigned, feature_len, sizeof(features)) * 8;
for (i = 0; i < bits; i++)
if (ioread8(&in_features[i / 8]) & (BIT(i % 8)))
features |= BIT(i);
@@ -85,7 +84,7 @@ static u32 mic_get_features(struct virtio_device *vdev)
return features;
}
-static void mic_finalize_features(struct virtio_device *vdev)
+static int mic_finalize_features(struct virtio_device *vdev)
{
unsigned int i, bits;
struct mic_device_desc __iomem *desc = to_micvdev(vdev)->desc;
@@ -97,14 +96,19 @@ static void mic_finalize_features(struct virtio_device *vdev)
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
+ /* Make sure we don't have any features > 32 bits! */
+ BUG_ON((u32)vdev->features != vdev->features);
+
memset_io(out_features, 0, feature_len);
bits = min_t(unsigned, feature_len,
sizeof(vdev->features)) * 8;
for (i = 0; i < bits; i++) {
- if (test_bit(i, vdev->features))
+ if (__virtio_test_bit(vdev, i))
iowrite8(ioread8(&out_features[i / 8]) | (1 << (i % 8)),
&out_features[i / 8]);
}
+
+ return 0;
}
/*
diff --git a/drivers/misc/vexpress-syscfg.c b/drivers/misc/vexpress-syscfg.c
index b3a8123..c344483 100644
--- a/drivers/misc/vexpress-syscfg.c
+++ b/drivers/misc/vexpress-syscfg.c
@@ -145,7 +145,7 @@ static struct regmap_config vexpress_syscfg_regmap_config = {
static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
void *context)
{
- struct platform_device *pdev = to_platform_device(dev);
+ int err;
struct vexpress_syscfg *syscfg = context;
struct vexpress_syscfg_func *func;
struct property *prop;
@@ -155,32 +155,18 @@ static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
u32 site, position, dcc;
int i;
- if (dev->of_node) {
- int err = vexpress_config_get_topo(dev->of_node, &site,
+ err = vexpress_config_get_topo(dev->of_node, &site,
&position, &dcc);
+ if (err)
+ return ERR_PTR(err);
- if (err)
- return ERR_PTR(err);
-
- prop = of_find_property(dev->of_node,
- "arm,vexpress-sysreg,func", NULL);
- if (!prop)
- return ERR_PTR(-EINVAL);
-
- num = prop->length / sizeof(u32) / 2;
- val = prop->value;
- } else {
- if (pdev->num_resources != 1 ||
- pdev->resource[0].flags != IORESOURCE_BUS)
- return ERR_PTR(-EFAULT);
-
- site = pdev->resource[0].start;
- if (site == VEXPRESS_SITE_MASTER)
- site = vexpress_config_get_master();
- position = 0;
- dcc = 0;
- num = 1;
- }
+ prop = of_find_property(dev->of_node,
+ "arm,vexpress-sysreg,func", NULL);
+ if (!prop)
+ return ERR_PTR(-EINVAL);
+
+ num = prop->length / sizeof(u32) / 2;
+ val = prop->value;
/*
* "arm,vexpress-energy" function used to be described
@@ -207,13 +193,8 @@ static struct regmap *vexpress_syscfg_regmap_init(struct device *dev,
for (i = 0; i < num; i++) {
u32 function, device;
- if (dev->of_node) {
- function = be32_to_cpup(val++);
- device = be32_to_cpup(val++);
- } else {
- function = pdev->resource[0].end;
- device = pdev->id;
- }
+ function = be32_to_cpup(val++);
+ device = be32_to_cpup(val++);
dev_dbg(dev, "func %p: %u/%u/%u/%u/%u\n",
func, site, position, dcc,
@@ -265,17 +246,6 @@ static struct vexpress_config_bridge_ops vexpress_syscfg_bridge_ops = {
};
-/* Non-DT hack, to be gone... */
-static struct device *vexpress_syscfg_bridge;
-
-int vexpress_syscfg_device_register(struct platform_device *pdev)
-{
- pdev->dev.parent = vexpress_syscfg_bridge;
-
- return platform_device_register(pdev);
-}
-
-
static int vexpress_syscfg_probe(struct platform_device *pdev)
{
struct vexpress_syscfg *syscfg;
@@ -303,10 +273,6 @@ static int vexpress_syscfg_probe(struct platform_device *pdev)
if (IS_ERR(bridge))
return PTR_ERR(bridge);
- /* Non-DT case */
- if (!pdev->dev.of_node)
- vexpress_syscfg_bridge = bridge;
-
return 0;
}
diff --git a/drivers/mmc/card/block.c b/drivers/mmc/card/block.c
index 1fa4c80..4409d79 100644
--- a/drivers/mmc/card/block.c
+++ b/drivers/mmc/card/block.c
@@ -78,13 +78,16 @@ static int perdev_minors = CONFIG_MMC_BLOCK_MINORS;
/*
* We've only got one major, so number of mmcblk devices is
- * limited to 256 / number of minors per device.
+ * limited to (1 << 20) / number of minors per device. It is also
+ * currently limited by the size of the static bitmaps below.
*/
static int max_devices;
-/* 256 minors, so at most 256 separate devices */
-static DECLARE_BITMAP(dev_use, 256);
-static DECLARE_BITMAP(name_use, 256);
+#define MAX_DEVICES 256
+
+/* TODO: Replace these with struct ida */
+static DECLARE_BITMAP(dev_use, MAX_DEVICES);
+static DECLARE_BITMAP(name_use, MAX_DEVICES);
/*
* There is one mmc_blk_data per slot.
@@ -112,7 +115,7 @@ struct mmc_blk_data {
/*
* Only set in main mmc_blk_data associated
- * with mmc_card with mmc_set_drvdata, and keeps
+ * with mmc_card with dev_set_drvdata, and keeps
* track of the current selected device partition.
*/
unsigned int part_curr;
@@ -260,7 +263,7 @@ static ssize_t force_ro_show(struct device *dev, struct device_attribute *attr,
int ret;
struct mmc_blk_data *md = mmc_blk_get(dev_to_disk(dev));
- ret = snprintf(buf, PAGE_SIZE, "%d",
+ ret = snprintf(buf, PAGE_SIZE, "%d\n",
get_disk_ro(dev_to_disk(dev)) ^
md->read_only);
mmc_blk_put(md);
@@ -642,7 +645,7 @@ static inline int mmc_blk_part_switch(struct mmc_card *card,
struct mmc_blk_data *md)
{
int ret;
- struct mmc_blk_data *main_md = mmc_get_drvdata(card);
+ struct mmc_blk_data *main_md = dev_get_drvdata(&card->dev);
if (main_md->part_curr == md->part_type)
return 0;
@@ -1004,7 +1007,8 @@ static int mmc_blk_reset(struct mmc_blk_data *md, struct mmc_host *host,
err = mmc_hw_reset(host);
/* Ensure we switch back to the correct partition */
if (err != -EOPNOTSUPP) {
- struct mmc_blk_data *main_md = mmc_get_drvdata(host->card);
+ struct mmc_blk_data *main_md =
+ dev_get_drvdata(&host->card->dev);
int part_err;
main_md->part_curr = main_md->part_type;
@@ -1308,19 +1312,11 @@ static int mmc_blk_packed_err_check(struct mmc_card *card,
}
if (status & R1_EXCEPTION_EVENT) {
- ext_csd = kzalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: unable to allocate buffer for ext_csd\n",
- req->rq_disk->disk_name);
- return -ENOMEM;
- }
-
- err = mmc_send_ext_csd(card, ext_csd);
+ err = mmc_get_ext_csd(card, &ext_csd);
if (err) {
pr_err("%s: error %d sending ext_csd\n",
req->rq_disk->disk_name, err);
- check = MMC_BLK_ABORT;
- goto free;
+ return MMC_BLK_ABORT;
}
if ((ext_csd[EXT_CSD_EXP_EVENTS_STATUS] &
@@ -1338,7 +1334,6 @@ static int mmc_blk_packed_err_check(struct mmc_card *card,
req->rq_disk->disk_name, packed->nr_entries,
packed->blocks, packed->idx_failure);
}
-free:
kfree(ext_csd);
}
@@ -2093,7 +2088,7 @@ static struct mmc_blk_data *mmc_blk_alloc_req(struct mmc_card *card,
/*
* !subname implies we are creating main mmc_blk_data that will be
- * associated with mmc_card with mmc_set_drvdata. Due to device
+ * associated with mmc_card with dev_set_drvdata. Due to device
* partitions, devidx will not coincide with a per-physical card
* index anymore so we keep track of a name index.
*/
@@ -2425,8 +2420,9 @@ static const struct mmc_fixup blk_fixups[] =
END_FIXUP
};
-static int mmc_blk_probe(struct mmc_card *card)
+static int mmc_blk_probe(struct device *dev)
{
+ struct mmc_card *card = mmc_dev_to_card(dev);
struct mmc_blk_data *md, *part_md;
char cap_str[10];
@@ -2451,7 +2447,7 @@ static int mmc_blk_probe(struct mmc_card *card)
if (mmc_blk_alloc_parts(card, md))
goto out;
- mmc_set_drvdata(card, md);
+ dev_set_drvdata(dev, md);
if (mmc_add_disk(md))
goto out;
@@ -2481,9 +2477,10 @@ static int mmc_blk_probe(struct mmc_card *card)
return 0;
}
-static void mmc_blk_remove(struct mmc_card *card)
+static int mmc_blk_remove(struct device *dev)
{
- struct mmc_blk_data *md = mmc_get_drvdata(card);
+ struct mmc_card *card = mmc_dev_to_card(dev);
+ struct mmc_blk_data *md = dev_get_drvdata(dev);
mmc_blk_remove_parts(card, md);
pm_runtime_get_sync(&card->dev);
@@ -2494,13 +2491,15 @@ static void mmc_blk_remove(struct mmc_card *card)
pm_runtime_disable(&card->dev);
pm_runtime_put_noidle(&card->dev);
mmc_blk_remove_req(md);
- mmc_set_drvdata(card, NULL);
+ dev_set_drvdata(dev, NULL);
+
+ return 0;
}
-static int _mmc_blk_suspend(struct mmc_card *card)
+static int _mmc_blk_suspend(struct device *dev)
{
struct mmc_blk_data *part_md;
- struct mmc_blk_data *md = mmc_get_drvdata(card);
+ struct mmc_blk_data *md = dev_get_drvdata(dev);
if (md) {
mmc_queue_suspend(&md->queue);
@@ -2511,21 +2510,21 @@ static int _mmc_blk_suspend(struct mmc_card *card)
return 0;
}
-static void mmc_blk_shutdown(struct mmc_card *card)
+static void mmc_blk_shutdown(struct device *dev)
{
- _mmc_blk_suspend(card);
+ _mmc_blk_suspend(dev);
}
-#ifdef CONFIG_PM
-static int mmc_blk_suspend(struct mmc_card *card)
+#ifdef CONFIG_PM_SLEEP
+static int mmc_blk_suspend(struct device *dev)
{
- return _mmc_blk_suspend(card);
+ return _mmc_blk_suspend(dev);
}
-static int mmc_blk_resume(struct mmc_card *card)
+static int mmc_blk_resume(struct device *dev)
{
struct mmc_blk_data *part_md;
- struct mmc_blk_data *md = mmc_get_drvdata(card);
+ struct mmc_blk_data *md = dev_get_drvdata(dev);
if (md) {
/*
@@ -2540,19 +2539,15 @@ static int mmc_blk_resume(struct mmc_card *card)
}
return 0;
}
-#else
-#define mmc_blk_suspend NULL
-#define mmc_blk_resume NULL
#endif
-static struct mmc_driver mmc_driver = {
- .drv = {
- .name = "mmcblk",
- },
+static SIMPLE_DEV_PM_OPS(mmc_blk_pm_ops, mmc_blk_suspend, mmc_blk_resume);
+
+static struct device_driver mmc_driver = {
+ .name = "mmcblk",
+ .pm = &mmc_blk_pm_ops,
.probe = mmc_blk_probe,
.remove = mmc_blk_remove,
- .suspend = mmc_blk_suspend,
- .resume = mmc_blk_resume,
.shutdown = mmc_blk_shutdown,
};
@@ -2563,7 +2558,7 @@ static int __init mmc_blk_init(void)
if (perdev_minors != CONFIG_MMC_BLOCK_MINORS)
pr_info("mmcblk: using %d minors per device\n", perdev_minors);
- max_devices = 256 / perdev_minors;
+ max_devices = min(MAX_DEVICES, (1 << MINORBITS) / perdev_minors);
res = register_blkdev(MMC_BLOCK_MAJOR, "mmc");
if (res)
diff --git a/drivers/mmc/card/mmc_test.c b/drivers/mmc/card/mmc_test.c
index 0c0fc52..0a7430f 100644
--- a/drivers/mmc/card/mmc_test.c
+++ b/drivers/mmc/card/mmc_test.c
@@ -14,6 +14,7 @@
#include <linux/mmc/host.h>
#include <linux/mmc/mmc.h>
#include <linux/slab.h>
+#include <linux/device.h>
#include <linux/scatterlist.h>
#include <linux/swap.h> /* For nr_free_buffer_pages() */
@@ -32,6 +33,8 @@
#define BUFFER_ORDER 2
#define BUFFER_SIZE (PAGE_SIZE << BUFFER_ORDER)
+#define TEST_ALIGN_END 8
+
/*
* Limit the test area size to the maximum MMC HC erase group size. Note that
* the maximum SD allocation unit size is just 4MiB.
@@ -1174,7 +1177,7 @@ static int mmc_test_align_write(struct mmc_test_card *test)
int ret, i;
struct scatterlist sg;
- for (i = 1;i < 4;i++) {
+ for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, 512);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 1);
if (ret)
@@ -1189,7 +1192,7 @@ static int mmc_test_align_read(struct mmc_test_card *test)
int ret, i;
struct scatterlist sg;
- for (i = 1;i < 4;i++) {
+ for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, 512);
ret = mmc_test_transfer(test, &sg, 1, 0, 1, 512, 0);
if (ret)
@@ -1216,7 +1219,7 @@ static int mmc_test_align_multi_write(struct mmc_test_card *test)
if (size < 1024)
return RESULT_UNSUP_HOST;
- for (i = 1;i < 4;i++) {
+ for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, size);
ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 1);
if (ret)
@@ -1243,7 +1246,7 @@ static int mmc_test_align_multi_read(struct mmc_test_card *test)
if (size < 1024)
return RESULT_UNSUP_HOST;
- for (i = 1;i < 4;i++) {
+ for (i = 1; i < TEST_ALIGN_END; i++) {
sg_init_one(&sg, test->buffer + i, size);
ret = mmc_test_transfer(test, &sg, 1, 0, size/512, 512, 0);
if (ret)
@@ -2997,8 +3000,9 @@ err:
return ret;
}
-static int mmc_test_probe(struct mmc_card *card)
+static int mmc_test_probe(struct device *dev)
{
+ struct mmc_card *card = mmc_dev_to_card(dev);
int ret;
if (!mmc_card_mmc(card) && !mmc_card_sd(card))
@@ -3013,20 +3017,22 @@ static int mmc_test_probe(struct mmc_card *card)
return 0;
}
-static void mmc_test_remove(struct mmc_card *card)
+static int mmc_test_remove(struct device *dev)
{
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
mmc_test_free_result(card);
mmc_test_free_dbgfs_file(card);
+
+ return 0;
}
-static void mmc_test_shutdown(struct mmc_card *card)
+static void mmc_test_shutdown(struct device *dev)
{
}
-static struct mmc_driver mmc_driver = {
- .drv = {
- .name = "mmc_test",
- },
+static struct device_driver mmc_driver = {
+ .name = "mmc_test",
.probe = mmc_test_probe,
.remove = mmc_test_remove,
.shutdown = mmc_test_shutdown,
diff --git a/drivers/mmc/card/queue.c b/drivers/mmc/card/queue.c
index cfa6110..236d194 100644
--- a/drivers/mmc/card/queue.c
+++ b/drivers/mmc/card/queue.c
@@ -232,13 +232,15 @@ int mmc_init_queue(struct mmc_queue *mq, struct mmc_card *card,
if (!mqrq_cur->bounce_buf) {
pr_warn("%s: unable to allocate bounce cur buffer\n",
mmc_card_name(card));
- }
- mqrq_prev->bounce_buf = kmalloc(bouncesz, GFP_KERNEL);
- if (!mqrq_prev->bounce_buf) {
- pr_warn("%s: unable to allocate bounce prev buffer\n",
- mmc_card_name(card));
- kfree(mqrq_cur->bounce_buf);
- mqrq_cur->bounce_buf = NULL;
+ } else {
+ mqrq_prev->bounce_buf =
+ kmalloc(bouncesz, GFP_KERNEL);
+ if (!mqrq_prev->bounce_buf) {
+ pr_warn("%s: unable to allocate bounce prev buffer\n",
+ mmc_card_name(card));
+ kfree(mqrq_cur->bounce_buf);
+ mqrq_cur->bounce_buf = NULL;
+ }
}
}
diff --git a/drivers/mmc/core/bus.c b/drivers/mmc/core/bus.c
index 8a1f124..86d2711 100644
--- a/drivers/mmc/core/bus.c
+++ b/drivers/mmc/core/bus.c
@@ -25,8 +25,6 @@
#include "sdio_cis.h"
#include "bus.h"
-#define to_mmc_driver(d) container_of(d, struct mmc_driver, drv)
-
static ssize_t type_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
@@ -106,33 +104,14 @@ mmc_bus_uevent(struct device *dev, struct kobj_uevent_env *env)
return retval;
}
-static int mmc_bus_probe(struct device *dev)
-{
- struct mmc_driver *drv = to_mmc_driver(dev->driver);
- struct mmc_card *card = mmc_dev_to_card(dev);
-
- return drv->probe(card);
-}
-
-static int mmc_bus_remove(struct device *dev)
-{
- struct mmc_driver *drv = to_mmc_driver(dev->driver);
- struct mmc_card *card = mmc_dev_to_card(dev);
-
- drv->remove(card);
-
- 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 (dev->driver && dev->driver->shutdown)
+ dev->driver->shutdown(dev);
if (host->bus_ops->shutdown) {
ret = host->bus_ops->shutdown(host);
@@ -145,16 +124,13 @@ static void mmc_bus_shutdown(struct device *dev)
#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);
struct mmc_host *host = card->host;
int ret;
- if (dev->driver && drv->suspend) {
- ret = drv->suspend(card);
- if (ret)
- return ret;
- }
+ ret = pm_generic_suspend(dev);
+ if (ret)
+ return ret;
ret = host->bus_ops->suspend(host);
return ret;
@@ -162,7 +138,6 @@ static int mmc_bus_suspend(struct device *dev)
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);
struct mmc_host *host = card->host;
int ret;
@@ -172,14 +147,12 @@ static int mmc_bus_resume(struct device *dev)
pr_warn("%s: error %d during resume (card was removed?)\n",
mmc_hostname(host), ret);
- if (dev->driver && drv->resume)
- ret = drv->resume(card);
-
+ ret = pm_generic_resume(dev);
return ret;
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int mmc_runtime_suspend(struct device *dev)
{
struct mmc_card *card = mmc_dev_to_card(dev);
@@ -195,7 +168,7 @@ static int mmc_runtime_resume(struct device *dev)
return host->bus_ops->runtime_resume(host);
}
-#endif /* !CONFIG_PM_RUNTIME */
+#endif /* !CONFIG_PM */
static const struct dev_pm_ops mmc_bus_pm_ops = {
SET_RUNTIME_PM_OPS(mmc_runtime_suspend, mmc_runtime_resume, NULL)
@@ -207,8 +180,6 @@ static struct bus_type mmc_bus_type = {
.dev_groups = mmc_dev_groups,
.match = mmc_bus_match,
.uevent = mmc_bus_uevent,
- .probe = mmc_bus_probe,
- .remove = mmc_bus_remove,
.shutdown = mmc_bus_shutdown,
.pm = &mmc_bus_pm_ops,
};
@@ -227,24 +198,22 @@ void mmc_unregister_bus(void)
* mmc_register_driver - register a media driver
* @drv: MMC media driver
*/
-int mmc_register_driver(struct mmc_driver *drv)
+int mmc_register_driver(struct device_driver *drv)
{
- drv->drv.bus = &mmc_bus_type;
- return driver_register(&drv->drv);
+ drv->bus = &mmc_bus_type;
+ return driver_register(drv);
}
-
EXPORT_SYMBOL(mmc_register_driver);
/**
* mmc_unregister_driver - unregister a media driver
* @drv: MMC media driver
*/
-void mmc_unregister_driver(struct mmc_driver *drv)
+void mmc_unregister_driver(struct device_driver *drv)
{
- drv->drv.bus = &mmc_bus_type;
- driver_unregister(&drv->drv);
+ drv->bus = &mmc_bus_type;
+ driver_unregister(drv);
}
-
EXPORT_SYMBOL(mmc_unregister_driver);
static void mmc_release_card(struct device *dev)
diff --git a/drivers/mmc/core/core.c b/drivers/mmc/core/core.c
index f26a5f1..9584bff 100644
--- a/drivers/mmc/core/core.c
+++ b/drivers/mmc/core/core.c
@@ -149,6 +149,14 @@ void mmc_request_done(struct mmc_host *host, struct mmc_request *mrq)
led_trigger_event(host->led, LED_OFF);
+ if (mrq->sbc) {
+ pr_debug("%s: req done <CMD%u>: %d: %08x %08x %08x %08x\n",
+ mmc_hostname(host), mrq->sbc->opcode,
+ mrq->sbc->error,
+ mrq->sbc->resp[0], mrq->sbc->resp[1],
+ mrq->sbc->resp[2], mrq->sbc->resp[3]);
+ }
+
pr_debug("%s: req done (CMD%u): %d: %08x %08x %08x %08x\n",
mmc_hostname(host), cmd->opcode, err,
cmd->resp[0], cmd->resp[1],
@@ -214,6 +222,10 @@ mmc_start_request(struct mmc_host *host, struct mmc_request *mrq)
mrq->cmd->error = 0;
mrq->cmd->mrq = mrq;
+ if (mrq->sbc) {
+ mrq->sbc->error = 0;
+ mrq->sbc->mrq = mrq;
+ }
if (mrq->data) {
BUG_ON(mrq->data->blksz > host->max_blk_size);
BUG_ON(mrq->data->blocks > host->max_blk_count);
@@ -538,8 +550,18 @@ struct mmc_async_req *mmc_start_req(struct mmc_host *host,
if (host->card && mmc_card_mmc(host->card) &&
((mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1) ||
(mmc_resp_type(host->areq->mrq->cmd) == MMC_RSP_R1B)) &&
- (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT))
+ (host->areq->mrq->cmd->resp[0] & R1_EXCEPTION_EVENT)) {
+
+ /* Cancel the prepared request */
+ if (areq)
+ mmc_post_req(host, areq->mrq, -EINVAL);
+
mmc_start_bkops(host->card, true);
+
+ /* prepare the request again */
+ if (areq)
+ mmc_pre_req(host, areq->mrq, !host->areq);
+ }
}
if (!err && areq)
@@ -709,27 +731,16 @@ int mmc_read_bkops_status(struct mmc_card *card)
int err;
u8 *ext_csd;
- /*
- * In future work, we should consider storing the entire ext_csd.
- */
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: could not allocate buffer to receive the ext_csd.\n",
- mmc_hostname(card->host));
- return -ENOMEM;
- }
-
mmc_claim_host(card->host);
- err = mmc_send_ext_csd(card, ext_csd);
+ err = mmc_get_ext_csd(card, &ext_csd);
mmc_release_host(card->host);
if (err)
- goto out;
+ return err;
card->ext_csd.raw_bkops_status = ext_csd[EXT_CSD_BKOPS_STATUS];
card->ext_csd.raw_exception_status = ext_csd[EXT_CSD_EXP_EVENTS_STATUS];
-out:
kfree(ext_csd);
- return err;
+ return 0;
}
EXPORT_SYMBOL(mmc_read_bkops_status);
@@ -1088,6 +1099,22 @@ void mmc_set_bus_width(struct mmc_host *host, unsigned int width)
mmc_host_clk_release(host);
}
+/*
+ * Set initial state after a power cycle or a hw_reset.
+ */
+void mmc_set_initial_state(struct mmc_host *host)
+{
+ if (mmc_host_is_spi(host))
+ host->ios.chip_select = MMC_CS_HIGH;
+ else
+ host->ios.chip_select = MMC_CS_DONTCARE;
+ host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
+ host->ios.bus_width = MMC_BUS_WIDTH_1;
+ host->ios.timing = MMC_TIMING_LEGACY;
+
+ mmc_set_ios(host);
+}
+
/**
* mmc_vdd_to_ocrbitnum - Convert a voltage to the OCR bit number
* @vdd: voltage (mV)
@@ -1420,18 +1447,20 @@ int mmc_set_signal_voltage(struct mmc_host *host, int signal_voltage, u32 ocr)
pr_warn("%s: cannot verify signal voltage switch\n",
mmc_hostname(host));
+ mmc_host_clk_hold(host);
+
cmd.opcode = SD_SWITCH_VOLTAGE;
cmd.arg = 0;
cmd.flags = MMC_RSP_R1 | MMC_CMD_AC;
err = mmc_wait_for_cmd(host, &cmd, 0);
if (err)
- return err;
+ goto err_command;
- if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR))
- return -EIO;
-
- mmc_host_clk_hold(host);
+ if (!mmc_host_is_spi(host) && (cmd.resp[0] & R1_ERROR)) {
+ err = -EIO;
+ goto err_command;
+ }
/*
* The card should drive cmd and dat[0:3] low immediately
* after the response of cmd11, but wait 1 ms to be sure
@@ -1480,6 +1509,7 @@ power_cycle:
mmc_power_cycle(host, ocr);
}
+err_command:
mmc_host_clk_release(host);
return err;
@@ -1526,15 +1556,9 @@ void mmc_power_up(struct mmc_host *host, u32 ocr)
mmc_host_clk_hold(host);
host->ios.vdd = fls(ocr) - 1;
- if (mmc_host_is_spi(host))
- host->ios.chip_select = MMC_CS_HIGH;
- else
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
host->ios.power_mode = MMC_POWER_UP;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
/* Try to set signal voltage to 3.3V but fall back to 1.8v or 1.2v */
if (__mmc_set_signal_voltage(host, MMC_SIGNAL_VOLTAGE_330) == 0)
@@ -1574,14 +1598,9 @@ void mmc_power_off(struct mmc_host *host)
host->ios.clock = 0;
host->ios.vdd = 0;
- if (!mmc_host_is_spi(host)) {
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- host->ios.chip_select = MMC_CS_DONTCARE;
- }
host->ios.power_mode = MMC_POWER_OFF;
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
/*
* Some configurations, such as the 802.11 SDIO card in the OLPC
@@ -2259,30 +2278,16 @@ static int mmc_do_hw_reset(struct mmc_host *host, int check)
/* If the reset has happened, then a status command will fail */
if (check) {
- struct mmc_command cmd = {0};
- int err;
+ u32 status;
- cmd.opcode = MMC_SEND_STATUS;
- if (!mmc_host_is_spi(card->host))
- cmd.arg = card->rca << 16;
- cmd.flags = MMC_RSP_SPI_R2 | MMC_RSP_R1 | MMC_CMD_AC;
- err = mmc_wait_for_cmd(card->host, &cmd, 0);
- if (!err) {
+ if (!mmc_send_status(card, &status)) {
mmc_host_clk_release(host);
return -ENOSYS;
}
}
- if (mmc_host_is_spi(host)) {
- host->ios.chip_select = MMC_CS_HIGH;
- host->ios.bus_mode = MMC_BUSMODE_PUSHPULL;
- } else {
- host->ios.chip_select = MMC_CS_DONTCARE;
- host->ios.bus_mode = MMC_BUSMODE_OPENDRAIN;
- }
- host->ios.bus_width = MMC_BUS_WIDTH_1;
- host->ios.timing = MMC_TIMING_LEGACY;
- mmc_set_ios(host);
+ /* Set initial state and call mmc_set_ios */
+ mmc_set_initial_state(host);
mmc_host_clk_release(host);
diff --git a/drivers/mmc/core/core.h b/drivers/mmc/core/core.h
index 443a584..d76597c 100644
--- a/drivers/mmc/core/core.h
+++ b/drivers/mmc/core/core.h
@@ -49,6 +49,7 @@ void mmc_set_driver_type(struct mmc_host *host, unsigned int drv_type);
void mmc_power_up(struct mmc_host *host, u32 ocr);
void mmc_power_off(struct mmc_host *host);
void mmc_power_cycle(struct mmc_host *host, u32 ocr);
+void mmc_set_initial_state(struct mmc_host *host);
static inline void mmc_delay(unsigned int ms)
{
diff --git a/drivers/mmc/core/debugfs.c b/drivers/mmc/core/debugfs.c
index 91eb162..e914210 100644
--- a/drivers/mmc/core/debugfs.c
+++ b/drivers/mmc/core/debugfs.c
@@ -291,14 +291,8 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
if (!buf)
return -ENOMEM;
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- err = -ENOMEM;
- goto out_free;
- }
-
mmc_get_card(card);
- err = mmc_send_ext_csd(card, ext_csd);
+ err = mmc_get_ext_csd(card, &ext_csd);
mmc_put_card(card);
if (err)
goto out_free;
@@ -314,7 +308,6 @@ static int mmc_ext_csd_open(struct inode *inode, struct file *filp)
out_free:
kfree(buf);
- kfree(ext_csd);
return err;
}
diff --git a/drivers/mmc/core/mmc.c b/drivers/mmc/core/mmc.c
index a301a78..02ad792 100644
--- a/drivers/mmc/core/mmc.c
+++ b/drivers/mmc/core/mmc.c
@@ -177,65 +177,6 @@ static int mmc_decode_csd(struct mmc_card *card)
return 0;
}
-/*
- * Read extended CSD.
- */
-static int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
-{
- int err;
- u8 *ext_csd;
-
- BUG_ON(!card);
- BUG_ON(!new_ext_csd);
-
- *new_ext_csd = NULL;
-
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return 0;
-
- /*
- * As the ext_csd is so large and mostly unused, we don't store the
- * raw block in mmc_card.
- */
- ext_csd = kmalloc(512, GFP_KERNEL);
- if (!ext_csd) {
- pr_err("%s: could not allocate a buffer to "
- "receive the ext_csd.\n", mmc_hostname(card->host));
- return -ENOMEM;
- }
-
- err = mmc_send_ext_csd(card, ext_csd);
- if (err) {
- kfree(ext_csd);
- *new_ext_csd = NULL;
-
- /* If the host or the card can't do the switch,
- * fail more gracefully. */
- if ((err != -EINVAL)
- && (err != -ENOSYS)
- && (err != -EFAULT))
- return err;
-
- /*
- * High capacity cards should have this "magic" size
- * stored in their CSD.
- */
- if (card->csd.capacity == (4096 * 512)) {
- pr_err("%s: unable to read EXT_CSD "
- "on a possible high capacity card. "
- "Card will be ignored.\n",
- mmc_hostname(card->host));
- } else {
- pr_warn("%s: unable to read EXT_CSD, performance might suffer\n",
- mmc_hostname(card->host));
- err = 0;
- }
- } else
- *new_ext_csd = ext_csd;
-
- return err;
-}
-
static void mmc_select_card_type(struct mmc_card *card)
{
struct mmc_host *host = card->host;
@@ -391,16 +332,11 @@ static void mmc_manage_gp_partitions(struct mmc_card *card, u8 *ext_csd)
/*
* Decode extended CSD.
*/
-static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
+static int mmc_decode_ext_csd(struct mmc_card *card, u8 *ext_csd)
{
int err = 0, idx;
unsigned int part_size;
- BUG_ON(!card);
-
- if (!ext_csd)
- return 0;
-
/* Version is coded in the CSD_STRUCTURE byte in the EXT_CSD register */
card->ext_csd.raw_ext_csd_structure = ext_csd[EXT_CSD_STRUCTURE];
if (card->csd.structure == 3) {
@@ -628,16 +564,56 @@ static int mmc_read_ext_csd(struct mmc_card *card, u8 *ext_csd)
card->ext_csd.data_sector_size = 512;
}
+ /* eMMC v5 or later */
+ if (card->ext_csd.rev >= 7) {
+ memcpy(card->ext_csd.fwrev, &ext_csd[EXT_CSD_FIRMWARE_VERSION],
+ MMC_FIRMWARE_LEN);
+ card->ext_csd.ffu_capable =
+ (ext_csd[EXT_CSD_SUPPORTED_MODE] & 0x1) &&
+ !(ext_csd[EXT_CSD_FW_CONFIG] & 0x1);
+ }
out:
return err;
}
-static inline void mmc_free_ext_csd(u8 *ext_csd)
+static int mmc_read_ext_csd(struct mmc_card *card)
{
+ u8 *ext_csd;
+ int err;
+
+ if (!mmc_can_ext_csd(card))
+ return 0;
+
+ err = mmc_get_ext_csd(card, &ext_csd);
+ if (err) {
+ /* If the host or the card can't do the switch,
+ * fail more gracefully. */
+ if ((err != -EINVAL)
+ && (err != -ENOSYS)
+ && (err != -EFAULT))
+ return err;
+
+ /*
+ * High capacity cards should have this "magic" size
+ * stored in their CSD.
+ */
+ if (card->csd.capacity == (4096 * 512)) {
+ pr_err("%s: unable to read EXT_CSD on a possible high capacity card. Card will be ignored.\n",
+ mmc_hostname(card->host));
+ } else {
+ pr_warn("%s: unable to read EXT_CSD, performance might suffer\n",
+ mmc_hostname(card->host));
+ err = 0;
+ }
+
+ return err;
+ }
+
+ err = mmc_decode_ext_csd(card, ext_csd);
kfree(ext_csd);
+ return err;
}
-
static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
{
u8 *bw_ext_csd;
@@ -647,11 +623,8 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
return 0;
err = mmc_get_ext_csd(card, &bw_ext_csd);
-
- if (err || bw_ext_csd == NULL) {
- err = -EINVAL;
- goto out;
- }
+ if (err)
+ return err;
/* only compare read only fields */
err = !((card->ext_csd.raw_partition_support ==
@@ -710,8 +683,7 @@ static int mmc_compare_ext_csds(struct mmc_card *card, unsigned bus_width)
if (err)
err = -EINVAL;
-out:
- mmc_free_ext_csd(bw_ext_csd);
+ kfree(bw_ext_csd);
return err;
}
@@ -722,7 +694,7 @@ MMC_DEV_ATTR(csd, "%08x%08x%08x%08x\n", card->raw_csd[0], card->raw_csd[1],
MMC_DEV_ATTR(date, "%02d/%04d\n", card->cid.month, card->cid.year);
MMC_DEV_ATTR(erase_size, "%u\n", card->erase_size << 9);
MMC_DEV_ATTR(preferred_erase_size, "%u\n", card->pref_erase << 9);
-MMC_DEV_ATTR(fwrev, "0x%x\n", card->cid.fwrev);
+MMC_DEV_ATTR(ffu_capable, "%d\n", card->ext_csd.ffu_capable);
MMC_DEV_ATTR(hwrev, "0x%x\n", card->cid.hwrev);
MMC_DEV_ATTR(manfid, "0x%06x\n", card->cid.manfid);
MMC_DEV_ATTR(name, "%s\n", card->cid.prod_name);
@@ -735,6 +707,22 @@ MMC_DEV_ATTR(enhanced_area_size, "%u\n", card->ext_csd.enhanced_area_size);
MMC_DEV_ATTR(raw_rpmb_size_mult, "%#x\n", card->ext_csd.raw_rpmb_size_mult);
MMC_DEV_ATTR(rel_sectors, "%#x\n", card->ext_csd.rel_sectors);
+static ssize_t mmc_fwrev_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct mmc_card *card = mmc_dev_to_card(dev);
+
+ if (card->ext_csd.rev < 7) {
+ return sprintf(buf, "0x%x\n", card->cid.fwrev);
+ } else {
+ return sprintf(buf, "0x%*phN\n", MMC_FIRMWARE_LEN,
+ card->ext_csd.fwrev);
+ }
+}
+
+static DEVICE_ATTR(fwrev, S_IRUGO, mmc_fwrev_show, NULL);
+
static struct attribute *mmc_std_attrs[] = {
&dev_attr_cid.attr,
&dev_attr_csd.attr,
@@ -742,6 +730,7 @@ static struct attribute *mmc_std_attrs[] = {
&dev_attr_erase_size.attr,
&dev_attr_preferred_erase_size.attr,
&dev_attr_fwrev.attr,
+ &dev_attr_ffu_capable.attr,
&dev_attr_hwrev.attr,
&dev_attr_manfid.attr,
&dev_attr_name.attr,
@@ -774,14 +763,6 @@ static int __mmc_select_powerclass(struct mmc_card *card,
unsigned int pwrclass_val = 0;
int err = 0;
- /* Power class selection is supported for versions >= 4.0 */
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
- return 0;
-
- /* Power class values are defined only for 4/8 bit bus */
- if (bus_width == EXT_CSD_BUS_WIDTH_1)
- return 0;
-
switch (1 << host->ios.vdd) {
case MMC_VDD_165_195:
if (host->ios.clock <= MMC_HIGH_26_MAX_DTR)
@@ -844,7 +825,7 @@ static int mmc_select_powerclass(struct mmc_card *card)
int err, ddr;
/* Power class selection is supported for versions >= 4.0 */
- if (card->csd.mmca_vsn < CSD_SPEC_VER_4)
+ if (!mmc_can_ext_csd(card))
return 0;
bus_width = host->ios.bus_width;
@@ -905,7 +886,7 @@ static int mmc_select_bus_width(struct mmc_card *card)
unsigned idx, bus_width = 0;
int err = 0;
- if ((card->csd.mmca_vsn < CSD_SPEC_VER_4) &&
+ if (!mmc_can_ext_csd(card) &&
!(host->caps & (MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA)))
return 0;
@@ -998,7 +979,7 @@ static int mmc_select_hs_ddr(struct mmc_card *card)
ext_csd_bits,
card->ext_csd.generic_cmd6_time);
if (err) {
- pr_warn("%s: switch to bus width %d ddr failed\n",
+ pr_err("%s: switch to bus width %d ddr failed\n",
mmc_hostname(host), 1 << bus_width);
return err;
}
@@ -1069,7 +1050,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err) {
- pr_warn("%s: switch to high-speed from hs200 failed, err:%d\n",
+ pr_err("%s: switch to high-speed from hs200 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
@@ -1079,7 +1060,7 @@ static int mmc_select_hs400(struct mmc_card *card)
EXT_CSD_DDR_BUS_WIDTH_8,
card->ext_csd.generic_cmd6_time);
if (err) {
- pr_warn("%s: switch to bus width for hs400 failed, err:%d\n",
+ pr_err("%s: switch to bus width for hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
@@ -1089,7 +1070,7 @@ static int mmc_select_hs400(struct mmc_card *card)
card->ext_csd.generic_cmd6_time,
true, true, true);
if (err) {
- pr_warn("%s: switch to hs400 failed, err:%d\n",
+ pr_err("%s: switch to hs400 failed, err:%d\n",
mmc_hostname(host), err);
return err;
}
@@ -1146,8 +1127,7 @@ static int mmc_select_timing(struct mmc_card *card)
{
int err = 0;
- if ((card->csd.mmca_vsn < CSD_SPEC_VER_4 &&
- card->ext_csd.hs_max_dtr == 0))
+ if (!mmc_can_ext_csd(card))
goto bus_speed;
if (card->mmc_avail_type & EXT_CSD_CARD_TYPE_HS200)
@@ -1232,7 +1212,7 @@ static int mmc_hs200_tuning(struct mmc_card *card)
mmc_host_clk_release(host);
if (err)
- pr_warn("%s: tuning execution failed\n",
+ pr_err("%s: tuning execution failed\n",
mmc_hostname(host));
}
@@ -1252,7 +1232,6 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
int err;
u32 cid[4];
u32 rocr;
- u8 *ext_csd = NULL;
BUG_ON(!host);
WARN_ON(!host->claimed);
@@ -1361,14 +1340,8 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
}
if (!oldcard) {
- /*
- * Fetch and process extended CSD.
- */
-
- err = mmc_get_ext_csd(card, &ext_csd);
- if (err)
- goto free_card;
- err = mmc_read_ext_csd(card, ext_csd);
+ /* Read extended CSD. */
+ err = mmc_read_ext_csd(card);
if (err)
goto free_card;
@@ -1458,18 +1431,18 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (mmc_card_hs200(card)) {
err = mmc_hs200_tuning(card);
if (err)
- goto err;
+ goto free_card;
err = mmc_select_hs400(card);
if (err)
- goto err;
+ goto free_card;
} else if (mmc_card_hs(card)) {
/* Select the desired bus width optionally */
err = mmc_select_bus_width(card);
if (!IS_ERR_VALUE(err)) {
err = mmc_select_hs_ddr(card);
if (err)
- goto err;
+ goto free_card;
}
}
@@ -1545,15 +1518,12 @@ static int mmc_init_card(struct mmc_host *host, u32 ocr,
if (!oldcard)
host->card = card;
- mmc_free_ext_csd(ext_csd);
return 0;
free_card:
if (!oldcard)
mmc_remove_card(card);
err:
- mmc_free_ext_csd(ext_csd);
-
return err;
}
diff --git a/drivers/mmc/core/mmc_ops.c b/drivers/mmc/core/mmc_ops.c
index 7911e05..3b044c5 100644
--- a/drivers/mmc/core/mmc_ops.c
+++ b/drivers/mmc/core/mmc_ops.c
@@ -264,20 +264,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
struct mmc_command cmd = {0};
struct mmc_data data = {0};
struct scatterlist sg;
- void *data_buf;
- int is_on_stack;
-
- is_on_stack = object_is_on_stack(buf);
- if (is_on_stack) {
- /*
- * dma onto stack is unsafe/nonportable, but callers to this
- * routine normally provide temporary on-stack buffers ...
- */
- data_buf = kmalloc(len, GFP_KERNEL);
- if (!data_buf)
- return -ENOMEM;
- } else
- data_buf = buf;
mrq.cmd = &cmd;
mrq.data = &data;
@@ -298,7 +284,7 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
data.sg = &sg;
data.sg_len = 1;
- sg_init_one(&sg, data_buf, len);
+ sg_init_one(&sg, buf, len);
if (opcode == MMC_SEND_CSD || opcode == MMC_SEND_CID) {
/*
@@ -312,11 +298,6 @@ mmc_send_cxd_data(struct mmc_card *card, struct mmc_host *host,
mmc_wait_for_req(host, &mrq);
- if (is_on_stack) {
- memcpy(buf, data_buf, len);
- kfree(data_buf);
- }
-
if (cmd.error)
return cmd.error;
if (data.error)
@@ -334,7 +315,7 @@ int mmc_send_csd(struct mmc_card *card, u32 *csd)
return mmc_send_cxd_native(card->host, card->rca << 16,
csd, MMC_SEND_CSD);
- csd_tmp = kmalloc(16, GFP_KERNEL);
+ csd_tmp = kzalloc(16, GFP_KERNEL);
if (!csd_tmp)
return -ENOMEM;
@@ -362,7 +343,7 @@ int mmc_send_cid(struct mmc_host *host, u32 *cid)
cid, MMC_SEND_CID);
}
- cid_tmp = kmalloc(16, GFP_KERNEL);
+ cid_tmp = kzalloc(16, GFP_KERNEL);
if (!cid_tmp)
return -ENOMEM;
@@ -378,12 +359,35 @@ err:
return ret;
}
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd)
+int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd)
{
- return mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD,
- ext_csd, 512);
+ int err;
+ u8 *ext_csd;
+
+ if (!card || !new_ext_csd)
+ return -EINVAL;
+
+ if (!mmc_can_ext_csd(card))
+ return -EOPNOTSUPP;
+
+ /*
+ * As the ext_csd is so large and mostly unused, we don't store the
+ * raw block in mmc_card.
+ */
+ ext_csd = kzalloc(512, GFP_KERNEL);
+ if (!ext_csd)
+ return -ENOMEM;
+
+ err = mmc_send_cxd_data(card, card->host, MMC_SEND_EXT_CSD, ext_csd,
+ 512);
+ if (err)
+ kfree(ext_csd);
+ else
+ *new_ext_csd = ext_csd;
+
+ return err;
}
-EXPORT_SYMBOL_GPL(mmc_send_ext_csd);
+EXPORT_SYMBOL_GPL(mmc_get_ext_csd);
int mmc_spi_read_ocr(struct mmc_host *host, int highcap, u32 *ocrp)
{
@@ -543,6 +547,75 @@ int mmc_switch(struct mmc_card *card, u8 set, u8 index, u8 value,
}
EXPORT_SYMBOL_GPL(mmc_switch);
+int mmc_send_tuning(struct mmc_host *host)
+{
+ struct mmc_request mrq = {NULL};
+ struct mmc_command cmd = {0};
+ struct mmc_data data = {0};
+ struct scatterlist sg;
+ struct mmc_ios *ios = &host->ios;
+ const u8 *tuning_block_pattern;
+ int size, err = 0;
+ u8 *data_buf;
+ u32 opcode;
+
+ if (ios->bus_width == MMC_BUS_WIDTH_8) {
+ tuning_block_pattern = tuning_blk_pattern_8bit;
+ size = sizeof(tuning_blk_pattern_8bit);
+ opcode = MMC_SEND_TUNING_BLOCK_HS200;
+ } else if (ios->bus_width == MMC_BUS_WIDTH_4) {
+ tuning_block_pattern = tuning_blk_pattern_4bit;
+ size = sizeof(tuning_blk_pattern_4bit);
+ opcode = MMC_SEND_TUNING_BLOCK;
+ } else
+ return -EINVAL;
+
+ data_buf = kzalloc(size, GFP_KERNEL);
+ if (!data_buf)
+ return -ENOMEM;
+
+ mrq.cmd = &cmd;
+ mrq.data = &data;
+
+ cmd.opcode = opcode;
+ cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
+
+ data.blksz = size;
+ data.blocks = 1;
+ data.flags = MMC_DATA_READ;
+
+ /*
+ * According to the tuning specs, Tuning process
+ * is normally shorter 40 executions of CMD19,
+ * and timeout value should be shorter than 150 ms
+ */
+ data.timeout_ns = 150 * NSEC_PER_MSEC;
+
+ data.sg = &sg;
+ data.sg_len = 1;
+ sg_init_one(&sg, data_buf, size);
+
+ mmc_wait_for_req(host, &mrq);
+
+ if (cmd.error) {
+ err = cmd.error;
+ goto out;
+ }
+
+ if (data.error) {
+ err = data.error;
+ goto out;
+ }
+
+ if (memcmp(data_buf, tuning_block_pattern, size))
+ err = -EIO;
+
+out:
+ kfree(data_buf);
+ return err;
+}
+EXPORT_SYMBOL_GPL(mmc_send_tuning);
+
static int
mmc_send_bus_test(struct mmc_card *card, struct mmc_host *host, u8 opcode,
u8 len)
@@ -675,3 +748,8 @@ int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status)
return 0;
}
+
+int mmc_can_ext_csd(struct mmc_card *card)
+{
+ return (card && card->csd.mmca_vsn > CSD_SPEC_VER_3);
+}
diff --git a/drivers/mmc/core/mmc_ops.h b/drivers/mmc/core/mmc_ops.h
index 390dac6..6f4b00e 100644
--- a/drivers/mmc/core/mmc_ops.h
+++ b/drivers/mmc/core/mmc_ops.h
@@ -20,13 +20,13 @@ int mmc_send_op_cond(struct mmc_host *host, u32 ocr, u32 *rocr);
int mmc_all_send_cid(struct mmc_host *host, u32 *cid);
int mmc_set_relative_addr(struct mmc_card *card);
int mmc_send_csd(struct mmc_card *card, u32 *csd);
-int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
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_bus_test(struct mmc_card *card, u8 bus_width);
int mmc_send_hpi_cmd(struct mmc_card *card, u32 *status);
+int mmc_can_ext_csd(struct mmc_card *card);
#endif
diff --git a/drivers/mmc/core/sdio.c b/drivers/mmc/core/sdio.c
index 2439e71..fd0750b 100644
--- a/drivers/mmc/core/sdio.c
+++ b/drivers/mmc/core/sdio.c
@@ -980,8 +980,12 @@ static int mmc_sdio_resume(struct mmc_host *host)
if (mmc_card_is_removable(host) || !mmc_card_keep_power(host)) {
sdio_reset(host);
mmc_go_idle(host);
- err = mmc_sdio_init_card(host, host->card->ocr, host->card,
- mmc_card_keep_power(host));
+ mmc_send_if_cond(host, host->card->ocr);
+ err = mmc_send_io_op_cond(host, 0, NULL);
+ if (!err)
+ err = mmc_sdio_init_card(host, host->card->ocr,
+ host->card,
+ mmc_card_keep_power(host));
} else if (mmc_card_keep_power(host) && mmc_card_wake_sdio_irq(host)) {
/* We may have switched to 1-bit mode during suspend */
err = sdio_enable_4bit_bus(host->card);
@@ -1035,7 +1039,7 @@ static int mmc_sdio_power_restore(struct mmc_host *host)
sdio_reset(host);
mmc_go_idle(host);
- mmc_send_if_cond(host, host->ocr_avail);
+ mmc_send_if_cond(host, host->card->ocr);
ret = mmc_send_io_op_cond(host, 0, NULL);
if (ret)
diff --git a/drivers/mmc/core/sdio_bus.c b/drivers/mmc/core/sdio_bus.c
index 6da97b1..6088531 100644
--- a/drivers/mmc/core/sdio_bus.c
+++ b/drivers/mmc/core/sdio_bus.c
@@ -26,6 +26,8 @@
#include "sdio_cis.h"
#include "sdio_bus.h"
+#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
+
/* show configuration fields */
#define sdio_config_attr(field, format_string) \
static ssize_t \
@@ -196,8 +198,6 @@ static int sdio_bus_remove(struct device *dev)
return ret;
}
-#ifdef CONFIG_PM
-
static const struct dev_pm_ops sdio_bus_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume)
SET_RUNTIME_PM_OPS(
@@ -207,14 +207,6 @@ static const struct dev_pm_ops sdio_bus_pm_ops = {
)
};
-#define SDIO_PM_OPS_PTR (&sdio_bus_pm_ops)
-
-#else /* !CONFIG_PM */
-
-#define SDIO_PM_OPS_PTR NULL
-
-#endif /* !CONFIG_PM */
-
static struct bus_type sdio_bus_type = {
.name = "sdio",
.dev_groups = sdio_dev_groups,
@@ -222,7 +214,7 @@ static struct bus_type sdio_bus_type = {
.uevent = sdio_bus_uevent,
.probe = sdio_bus_probe,
.remove = sdio_bus_remove,
- .pm = SDIO_PM_OPS_PTR,
+ .pm = &sdio_bus_pm_ops,
};
int sdio_register_bus(void)
@@ -295,7 +287,7 @@ struct sdio_func *sdio_alloc_func(struct mmc_card *card)
static void sdio_acpi_set_handle(struct sdio_func *func)
{
struct mmc_host *host = func->card->host;
- u64 addr = (host->slotno << 16) | func->num;
+ u64 addr = ((u64)host->slotno << 16) | func->num;
acpi_preset_companion(&func->dev, ACPI_COMPANION(host->parent), addr);
}
diff --git a/drivers/mmc/host/Kconfig b/drivers/mmc/host/Kconfig
index 1386065..2d6fbdd 100644
--- a/drivers/mmc/host/Kconfig
+++ b/drivers/mmc/host/Kconfig
@@ -580,7 +580,7 @@ config SDH_BFIN_MISSING_CMD_PULLUP_WORKAROUND
config MMC_DW
tristate "Synopsys DesignWare Memory Card Interface"
depends on HAS_DMA
- depends on ARC || ARM || MIPS || COMPILE_TEST
+ depends on ARC || ARM || ARM64 || MIPS || COMPILE_TEST
help
This selects support for the Synopsys DesignWare Mobile Storage IP
block, this provides host support for SD and MMC interfaces, in both
@@ -748,3 +748,8 @@ config MMC_SUNXI
help
This selects support for the SD/MMC Host Controller on
Allwinner sunxi SoCs.
+
+config MMC_TOSHIBA_PCI
+ tristate "Toshiba Type A SD/MMC Card Interface Driver"
+ depends on PCI
+ help
diff --git a/drivers/mmc/host/Makefile b/drivers/mmc/host/Makefile
index b09ecfb..f7b0a77 100644
--- a/drivers/mmc/host/Makefile
+++ b/drivers/mmc/host/Makefile
@@ -55,6 +55,7 @@ obj-$(CONFIG_MMC_WMT) += wmt-sdmmc.o
obj-$(CONFIG_MMC_MOXART) += moxart-mmc.o
obj-$(CONFIG_MMC_SUNXI) += sunxi-mmc.o
obj-$(CONFIG_MMC_USDHI6ROL0) += usdhi6rol0.o
+obj-$(CONFIG_MMC_TOSHIBA_PCI) += toshsd.o
obj-$(CONFIG_MMC_REALTEK_PCI) += rtsx_pci_sdmmc.o
obj-$(CONFIG_MMC_REALTEK_USB) += rtsx_usb_sdmmc.o
diff --git a/drivers/mmc/host/atmel-mci.c b/drivers/mmc/host/atmel-mci.c
index 77250d4..62aba9a 100644
--- a/drivers/mmc/host/atmel-mci.c
+++ b/drivers/mmc/host/atmel-mci.c
@@ -30,13 +30,16 @@
#include <linux/stat.h>
#include <linux/types.h>
#include <linux/platform_data/atmel.h>
+#include <linux/platform_data/mmc-atmel-mci.h>
#include <linux/mmc/host.h>
#include <linux/mmc/sdio.h>
-#include <mach/atmel-mci.h>
#include <linux/atmel-mci.h>
#include <linux/atmel_pdc.h>
+#include <linux/pm.h>
+#include <linux/pm_runtime.h>
+#include <linux/pinctrl/consumer.h>
#include <asm/cacheflush.h>
#include <asm/io.h>
@@ -44,6 +47,8 @@
#include "atmel-mci-regs.h"
+#define AUTOSUSPEND_DELAY 50
+
#define ATMCI_DATA_ERROR_FLAGS (ATMCI_DCRCE | ATMCI_DTOE | ATMCI_OVRE | ATMCI_UNRE)
#define ATMCI_DMA_THRESHOLD 16
@@ -386,20 +391,19 @@ static int atmci_regs_show(struct seq_file *s, void *v)
if (!buf)
return -ENOMEM;
+ pm_runtime_get_sync(&host->pdev->dev);
+
/*
* Grab a more or less consistent snapshot. Note that we're
* not disabling interrupts, so IMR and SR may not be
* consistent.
*/
- ret = clk_prepare_enable(host->mck);
- if (ret)
- goto out;
-
spin_lock_bh(&host->lock);
memcpy_fromio(buf, host->regs, ATMCI_REGS_SIZE);
spin_unlock_bh(&host->lock);
- clk_disable_unprepare(host->mck);
+ pm_runtime_mark_last_busy(&host->pdev->dev);
+ pm_runtime_put_autosuspend(&host->pdev->dev);
seq_printf(s, "MR:\t0x%08x%s%s ",
buf[ATMCI_MR / 4],
@@ -449,7 +453,6 @@ static int atmci_regs_show(struct seq_file *s, void *v)
val & ATMCI_CFG_LSYNC ? " LSYNC" : "");
}
-out:
kfree(buf);
return ret;
@@ -560,6 +563,9 @@ atmci_of_init(struct platform_device *pdev)
pdata->slot[slot_id].detect_is_active_high =
of_property_read_bool(cnp, "cd-inverted");
+ pdata->slot[slot_id].non_removable =
+ of_property_read_bool(cnp, "non-removable");
+
pdata->slot[slot_id].wp_pin =
of_get_named_gpio(cnp, "wp-gpios", 0);
}
@@ -1252,6 +1258,8 @@ static void atmci_request(struct mmc_host *mmc, struct mmc_request *mrq)
WARN_ON(slot->mrq);
dev_dbg(&host->pdev->dev, "MRQ: cmd %u\n", mrq->cmd->opcode);
+ pm_runtime_get_sync(&host->pdev->dev);
+
/*
* We may "know" the card is gone even though there's still an
* electrical connection. If so, we really need to communicate
@@ -1281,7 +1289,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
struct atmel_mci_slot *slot = mmc_priv(mmc);
struct atmel_mci *host = slot->host;
unsigned int i;
- bool unprepare_clk;
+
+ pm_runtime_get_sync(&host->pdev->dev);
slot->sdc_reg &= ~ATMCI_SDCBUS_MASK;
switch (ios->bus_width) {
@@ -1297,13 +1306,8 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
unsigned int clock_min = ~0U;
u32 clkdiv;
- clk_prepare(host->mck);
- unprepare_clk = true;
-
spin_lock_bh(&host->lock);
if (!host->mode_reg) {
- clk_enable(host->mck);
- unprepare_clk = false;
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIEN);
if (host->caps.has_cfg_reg)
@@ -1371,8 +1375,6 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
} else {
bool any_slot_active = false;
- unprepare_clk = false;
-
spin_lock_bh(&host->lock);
slot->clock = 0;
for (i = 0; i < ATMCI_MAX_NR_SLOTS; i++) {
@@ -1385,17 +1387,12 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
if (host->mode_reg) {
atmci_readl(host, ATMCI_MR);
- clk_disable(host->mck);
- unprepare_clk = true;
}
host->mode_reg = 0;
}
spin_unlock_bh(&host->lock);
}
- if (unprepare_clk)
- clk_unprepare(host->mck);
-
switch (ios->power_mode) {
case MMC_POWER_OFF:
if (!IS_ERR(mmc->supply.vmmc))
@@ -1421,6 +1418,9 @@ static void atmci_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
*/
break;
}
+
+ pm_runtime_mark_last_busy(&host->pdev->dev);
+ pm_runtime_put_autosuspend(&host->pdev->dev);
}
static int atmci_get_ro(struct mmc_host *mmc)
@@ -1512,6 +1512,9 @@ static void atmci_request_end(struct atmel_mci *host, struct mmc_request *mrq)
spin_unlock(&host->lock);
mmc_request_done(prev_mmc, mrq);
spin_lock(&host->lock);
+
+ pm_runtime_mark_last_busy(&host->pdev->dev);
+ pm_runtime_put_autosuspend(&host->pdev->dev);
}
static void atmci_command_complete(struct atmel_mci *host,
@@ -2137,7 +2140,7 @@ static irqreturn_t atmci_detect_interrupt(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int __init atmci_init_slot(struct atmel_mci *host,
+static int atmci_init_slot(struct atmel_mci *host,
struct mci_slot_pdata *slot_data, unsigned int id,
u32 sdc_reg, u32 sdio_irq)
{
@@ -2206,8 +2209,12 @@ static int __init atmci_init_slot(struct atmel_mci *host,
}
}
- if (!gpio_is_valid(slot->detect_pin))
- mmc->caps |= MMC_CAP_NEEDS_POLL;
+ if (!gpio_is_valid(slot->detect_pin)) {
+ if (slot_data->non_removable)
+ mmc->caps |= MMC_CAP_NONREMOVABLE;
+ else
+ mmc->caps |= MMC_CAP_NEEDS_POLL;
+ }
if (gpio_is_valid(slot->wp_pin)) {
if (devm_gpio_request(&host->pdev->dev, slot->wp_pin,
@@ -2265,55 +2272,25 @@ static void atmci_cleanup_slot(struct atmel_mci_slot *slot,
mmc_free_host(slot->mmc);
}
-static bool atmci_filter(struct dma_chan *chan, void *pdata)
+static int atmci_configure_dma(struct atmel_mci *host)
{
- struct mci_platform_data *sl_pdata = pdata;
- struct mci_dma_data *sl;
-
- if (!sl_pdata)
- return false;
+ host->dma.chan = dma_request_slave_channel_reason(&host->pdev->dev,
+ "rxtx");
+ if (IS_ERR(host->dma.chan))
+ return PTR_ERR(host->dma.chan);
+
+ dev_info(&host->pdev->dev, "using %s for DMA transfers\n",
+ dma_chan_name(host->dma.chan));
+
+ host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
+ host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_conf.src_maxburst = 1;
+ host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
+ host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ host->dma_conf.dst_maxburst = 1;
+ host->dma_conf.device_fc = false;
- sl = sl_pdata->dma_slave;
- if (sl && find_slave_dev(sl) == chan->device->dev) {
- chan->private = slave_data_ptr(sl);
- return true;
- } else {
- return false;
- }
-}
-
-static bool atmci_configure_dma(struct atmel_mci *host)
-{
- struct mci_platform_data *pdata;
- dma_cap_mask_t mask;
-
- if (host == NULL)
- return false;
-
- pdata = host->pdev->dev.platform_data;
-
- dma_cap_zero(mask);
- dma_cap_set(DMA_SLAVE, mask);
-
- host->dma.chan = dma_request_slave_channel_compat(mask, atmci_filter, pdata,
- &host->pdev->dev, "rxtx");
- if (!host->dma.chan) {
- dev_warn(&host->pdev->dev, "no DMA channel available\n");
- return false;
- } else {
- dev_info(&host->pdev->dev,
- "using %s for DMA transfers\n",
- dma_chan_name(host->dma.chan));
-
- host->dma_conf.src_addr = host->mapbase + ATMCI_RDR;
- host->dma_conf.src_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_conf.src_maxburst = 1;
- host->dma_conf.dst_addr = host->mapbase + ATMCI_TDR;
- host->dma_conf.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
- host->dma_conf.dst_maxburst = 1;
- host->dma_conf.device_fc = false;
- return true;
- }
+ return 0;
}
/*
@@ -2321,7 +2298,7 @@ static bool atmci_configure_dma(struct atmel_mci *host)
* HSMCI provides DMA support and a new config register but no more supports
* PDC.
*/
-static void __init atmci_get_cap(struct atmel_mci *host)
+static void atmci_get_cap(struct atmel_mci *host)
{
unsigned int version;
@@ -2370,7 +2347,7 @@ static void __init atmci_get_cap(struct atmel_mci *host)
}
}
-static int __init atmci_probe(struct platform_device *pdev)
+static int atmci_probe(struct platform_device *pdev)
{
struct mci_platform_data *pdata;
struct atmel_mci *host;
@@ -2417,19 +2394,23 @@ static int __init atmci_probe(struct platform_device *pdev)
atmci_writel(host, ATMCI_CR, ATMCI_CR_SWRST);
host->bus_hz = clk_get_rate(host->mck);
- clk_disable_unprepare(host->mck);
host->mapbase = regs->start;
tasklet_init(&host->tasklet, atmci_tasklet_func, (unsigned long)host);
ret = request_irq(irq, atmci_interrupt, 0, dev_name(&pdev->dev), host);
- if (ret)
+ if (ret) {
+ clk_disable_unprepare(host->mck);
return ret;
+ }
/* Get MCI capabilities and set operations according to it */
atmci_get_cap(host);
- if (atmci_configure_dma(host)) {
+ ret = atmci_configure_dma(host);
+ if (ret == -EPROBE_DEFER)
+ goto err_dma_probe_defer;
+ if (ret == 0) {
host->prepare_data = &atmci_prepare_data_dma;
host->submit_data = &atmci_submit_data_dma;
host->stop_transfer = &atmci_stop_transfer_dma;
@@ -2449,6 +2430,12 @@ static int __init atmci_probe(struct platform_device *pdev)
setup_timer(&host->timer, atmci_timeout_timer, (unsigned long)host);
+ pm_runtime_get_noresume(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_DELAY);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
/* We need at least one slot to succeed */
nr_slots = 0;
ret = -ENODEV;
@@ -2491,6 +2478,9 @@ static int __init atmci_probe(struct platform_device *pdev)
"Atmel MCI controller at 0x%08lx irq %d, %u slots\n",
host->mapbase, irq, nr_slots);
+ pm_runtime_mark_last_busy(&host->pdev->dev);
+ pm_runtime_put_autosuspend(&pdev->dev);
+
return 0;
err_dma_alloc:
@@ -2499,18 +2489,26 @@ err_dma_alloc:
atmci_cleanup_slot(host->slot[i], i);
}
err_init_slot:
+ clk_disable_unprepare(host->mck);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
del_timer_sync(&host->timer);
- if (host->dma.chan)
+ if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan);
+err_dma_probe_defer:
free_irq(irq, host);
return ret;
}
-static int __exit atmci_remove(struct platform_device *pdev)
+static int atmci_remove(struct platform_device *pdev)
{
struct atmel_mci *host = platform_get_drvdata(pdev);
unsigned int i;
+ pm_runtime_get_sync(&pdev->dev);
+
if (host->buffer)
dma_free_coherent(&pdev->dev, host->buf_size,
host->buffer, host->buf_phys_addr);
@@ -2520,41 +2518,62 @@ static int __exit atmci_remove(struct platform_device *pdev)
atmci_cleanup_slot(host->slot[i], i);
}
- clk_prepare_enable(host->mck);
atmci_writel(host, ATMCI_IDR, ~0UL);
atmci_writel(host, ATMCI_CR, ATMCI_CR_MCIDIS);
atmci_readl(host, ATMCI_SR);
- clk_disable_unprepare(host->mck);
del_timer_sync(&host->timer);
- if (host->dma.chan)
+ if (!IS_ERR(host->dma.chan))
dma_release_channel(host->dma.chan);
free_irq(platform_get_irq(pdev, 0), host);
+ clk_disable_unprepare(host->mck);
+
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_put_noidle(&pdev->dev);
+
return 0;
}
-static struct platform_driver atmci_driver = {
- .remove = __exit_p(atmci_remove),
- .driver = {
- .name = "atmel_mci",
- .of_match_table = of_match_ptr(atmci_dt_ids),
- },
-};
-
-static int __init atmci_init(void)
+#ifdef CONFIG_PM
+static int atmci_runtime_suspend(struct device *dev)
{
- return platform_driver_probe(&atmci_driver, atmci_probe);
+ struct atmel_mci *host = dev_get_drvdata(dev);
+
+ clk_disable_unprepare(host->mck);
+
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
}
-static void __exit atmci_exit(void)
+static int atmci_runtime_resume(struct device *dev)
{
- platform_driver_unregister(&atmci_driver);
+ struct atmel_mci *host = dev_get_drvdata(dev);
+
+ pinctrl_pm_select_default_state(dev);
+
+ return clk_prepare_enable(host->mck);
}
+#endif
-late_initcall(atmci_init); /* try to load after dma driver when built-in */
-module_exit(atmci_exit);
+static const struct dev_pm_ops atmci_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
+ pm_runtime_force_resume)
+ SET_PM_RUNTIME_PM_OPS(atmci_runtime_suspend, atmci_runtime_resume, NULL)
+};
+
+static struct platform_driver atmci_driver = {
+ .probe = atmci_probe,
+ .remove = atmci_remove,
+ .driver = {
+ .name = "atmel_mci",
+ .of_match_table = of_match_ptr(atmci_dt_ids),
+ .pm = &atmci_dev_pm_ops,
+ },
+};
+module_platform_driver(atmci_driver);
MODULE_DESCRIPTION("Atmel Multimedia Card Interface driver");
MODULE_AUTHOR("Haavard Skinnemoen (Atmel)");
diff --git a/drivers/mmc/host/dw_mmc-exynos.c b/drivers/mmc/host/dw_mmc-exynos.c
index 0fbc53a..509365c 100644
--- a/drivers/mmc/host/dw_mmc-exynos.c
+++ b/drivers/mmc/host/dw_mmc-exynos.c
@@ -25,6 +25,7 @@
#define NUM_PINS(x) (x + 2)
#define SDMMC_CLKSEL 0x09C
+#define SDMMC_CLKSEL64 0x0A8
#define SDMMC_CLKSEL_CCLK_SAMPLE(x) (((x) & 7) << 0)
#define SDMMC_CLKSEL_CCLK_DRIVE(x) (((x) & 7) << 16)
#define SDMMC_CLKSEL_CCLK_DIVIDER(x) (((x) & 7) << 24)
@@ -65,6 +66,8 @@ enum dw_mci_exynos_type {
DW_MCI_TYPE_EXYNOS5250,
DW_MCI_TYPE_EXYNOS5420,
DW_MCI_TYPE_EXYNOS5420_SMU,
+ DW_MCI_TYPE_EXYNOS7,
+ DW_MCI_TYPE_EXYNOS7_SMU,
};
/* Exynos implementation specific driver private data */
@@ -95,6 +98,12 @@ static struct dw_mci_exynos_compatible {
}, {
.compatible = "samsung,exynos5420-dw-mshc-smu",
.ctrl_type = DW_MCI_TYPE_EXYNOS5420_SMU,
+ }, {
+ .compatible = "samsung,exynos7-dw-mshc",
+ .ctrl_type = DW_MCI_TYPE_EXYNOS7,
+ }, {
+ .compatible = "samsung,exynos7-dw-mshc-smu",
+ .ctrl_type = DW_MCI_TYPE_EXYNOS7_SMU,
},
};
@@ -102,7 +111,8 @@ static int dw_mci_exynos_priv_init(struct dw_mci *host)
{
struct dw_mci_exynos_priv_data *priv = host->priv;
- if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU) {
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS5420_SMU ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
mci_writel(host, MPSBEGIN0, 0);
mci_writel(host, MPSEND0, DWMCI_BLOCK_NUM);
mci_writel(host, MPSCTRL0, DWMCI_MPSCTRL_SECURE_WRITE_BIT |
@@ -153,11 +163,22 @@ static int dw_mci_exynos_resume(struct device *dev)
static int dw_mci_exynos_resume_noirq(struct device *dev)
{
struct dw_mci *host = dev_get_drvdata(dev);
+ struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel;
- clksel = mci_readl(host, CLKSEL);
- if (clksel & SDMMC_CLKSEL_WAKEUP_INT)
- mci_writel(host, CLKSEL, clksel);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+ clksel = mci_readl(host, CLKSEL);
+
+ if (clksel & SDMMC_CLKSEL_WAKEUP_INT) {
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+ mci_writel(host, CLKSEL, clksel);
+ }
return 0;
}
@@ -169,6 +190,7 @@ static int dw_mci_exynos_resume_noirq(struct device *dev)
static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
/*
* Exynos4412 and Exynos5250 extends the use of CMD register with the
* use of bit 29 (which is reserved on standard MSHC controllers) for
@@ -176,8 +198,14 @@ static void dw_mci_exynos_prepare_command(struct dw_mci *host, u32 *cmdr)
* HOLD register should be bypassed in case there is no phase shift
* applied on CMD/DATA that is sent to the card.
*/
- if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
- *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU) {
+ if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL64)))
+ *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+ } else {
+ if (SDMMC_CLKSEL_GET_DRV_WD3(mci_readl(host, CLKSEL)))
+ *cmdr |= SDMMC_CMD_USE_HOLD_REG;
+ }
}
static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
@@ -188,12 +216,20 @@ static void dw_mci_exynos_set_ios(struct dw_mci *host, struct mmc_ios *ios)
u8 div = priv->ciu_div + 1;
if (ios->timing == MMC_TIMING_MMC_DDR52) {
- mci_writel(host, CLKSEL, priv->ddr_timing);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, priv->ddr_timing);
+ else
+ mci_writel(host, CLKSEL, priv->ddr_timing);
/* Should be double rate for DDR mode */
if (ios->bus_width == MMC_BUS_WIDTH_8)
wanted <<= 1;
} else {
- mci_writel(host, CLKSEL, priv->sdr_timing);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, priv->sdr_timing);
+ else
+ mci_writel(host, CLKSEL, priv->sdr_timing);
}
/* Don't care if wanted clock is zero */
@@ -265,26 +301,51 @@ static int dw_mci_exynos_parse_dt(struct dw_mci *host)
static inline u8 dw_mci_exynos_get_clksmpl(struct dw_mci *host)
{
- return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL64));
+ else
+ return SDMMC_CLKSEL_CCLK_SAMPLE(mci_readl(host, CLKSEL));
}
static inline void dw_mci_exynos_set_clksmpl(struct dw_mci *host, u8 sample)
{
u32 clksel;
- clksel = mci_readl(host, CLKSEL);
+ struct dw_mci_exynos_priv_data *priv = host->priv;
+
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+ clksel = mci_readl(host, CLKSEL);
clksel = (clksel & ~0x7) | SDMMC_CLKSEL_CCLK_SAMPLE(sample);
- mci_writel(host, CLKSEL, clksel);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+ mci_writel(host, CLKSEL, clksel);
}
static inline u8 dw_mci_exynos_move_next_clksmpl(struct dw_mci *host)
{
+ struct dw_mci_exynos_priv_data *priv = host->priv;
u32 clksel;
u8 sample;
- clksel = mci_readl(host, CLKSEL);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ clksel = mci_readl(host, CLKSEL64);
+ else
+ clksel = mci_readl(host, CLKSEL);
sample = (clksel + 1) & 0x7;
clksel = (clksel & ~0x7) | sample;
- mci_writel(host, CLKSEL, clksel);
+ if (priv->ctrl_type == DW_MCI_TYPE_EXYNOS7 ||
+ priv->ctrl_type == DW_MCI_TYPE_EXYNOS7_SMU)
+ mci_writel(host, CLKSEL64, clksel);
+ else
+ mci_writel(host, CLKSEL, clksel);
return sample;
}
@@ -411,6 +472,10 @@ static const struct of_device_id dw_mci_exynos_match[] = {
.data = &exynos_drv_data, },
{ .compatible = "samsung,exynos5420-dw-mshc-smu",
.data = &exynos_drv_data, },
+ { .compatible = "samsung,exynos7-dw-mshc",
+ .data = &exynos_drv_data, },
+ { .compatible = "samsung,exynos7-dw-mshc-smu",
+ .data = &exynos_drv_data, },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_exynos_match);
diff --git a/drivers/mmc/host/dw_mmc-pltfm.c b/drivers/mmc/host/dw_mmc-pltfm.c
index 8b65721..ec6dbcd 100644
--- a/drivers/mmc/host/dw_mmc-pltfm.c
+++ b/drivers/mmc/host/dw_mmc-pltfm.c
@@ -35,6 +35,10 @@ static const struct dw_mci_drv_data socfpga_drv_data = {
.prepare_command = dw_mci_pltfm_prepare_command,
};
+static const struct dw_mci_drv_data pistachio_drv_data = {
+ .prepare_command = dw_mci_pltfm_prepare_command,
+};
+
int dw_mci_pltfm_register(struct platform_device *pdev,
const struct dw_mci_drv_data *drv_data)
{
@@ -90,6 +94,8 @@ static const struct of_device_id dw_mci_pltfm_match[] = {
{ .compatible = "snps,dw-mshc", },
{ .compatible = "altr,socfpga-dw-mshc",
.data = &socfpga_drv_data },
+ { .compatible = "img,pistachio-dw-mshc",
+ .data = &pistachio_drv_data },
{},
};
MODULE_DEVICE_TABLE(of, dw_mci_pltfm_match);
diff --git a/drivers/mmc/host/dw_mmc-rockchip.c b/drivers/mmc/host/dw_mmc-rockchip.c
index f0c2cb1..5650ac4 100644
--- a/drivers/mmc/host/dw_mmc-rockchip.c
+++ b/drivers/mmc/host/dw_mmc-rockchip.c
@@ -37,6 +37,9 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
unsigned int cclkin;
u32 bus_hz;
+ if (ios->clock == 0)
+ return;
+
/*
* cclkin: source clock of mmc controller
* bus_hz: card interface clock generated by CLKGEN
@@ -65,14 +68,24 @@ static void dw_mci_rk3288_set_ios(struct dw_mci *host, struct mmc_ios *ios)
}
}
+static int dw_mci_rockchip_init(struct dw_mci *host)
+{
+ /* It is slot 8 on Rockchip SoCs */
+ host->sdio_id0 = 8;
+
+ return 0;
+}
+
static const struct dw_mci_drv_data rk2928_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command,
+ .init = dw_mci_rockchip_init,
};
static const struct dw_mci_drv_data rk3288_drv_data = {
.prepare_command = dw_mci_rockchip_prepare_command,
.set_ios = dw_mci_rk3288_set_ios,
.setup_clock = dw_mci_rk3288_setup_clock,
+ .init = dw_mci_rockchip_init,
};
static const struct of_device_id dw_mci_rockchip_match[] = {
diff --git a/drivers/mmc/host/dw_mmc.c b/drivers/mmc/host/dw_mmc.c
index 69f0cc6..67c0451 100644
--- a/drivers/mmc/host/dw_mmc.c
+++ b/drivers/mmc/host/dw_mmc.c
@@ -34,7 +34,6 @@
#include <linux/mmc/dw_mmc.h>
#include <linux/bitops.h>
#include <linux/regulator/consumer.h>
-#include <linux/workqueue.h>
#include <linux/of.h>
#include <linux/of_gpio.h>
#include <linux/mmc/slot-gpio.h>
@@ -62,6 +61,24 @@
SDMMC_IDMAC_INT_FBE | SDMMC_IDMAC_INT_RI | \
SDMMC_IDMAC_INT_TI)
+struct idmac_desc_64addr {
+ u32 des0; /* Control Descriptor */
+
+ u32 des1; /* Reserved */
+
+ u32 des2; /*Buffer sizes */
+#define IDMAC_64ADDR_SET_BUFFER1_SIZE(d, s) \
+ ((d)->des2 = ((d)->des2 & 0x03ffe000) | ((s) & 0x1fff))
+
+ u32 des3; /* Reserved */
+
+ u32 des4; /* Lower 32-bits of Buffer Address Pointer 1*/
+ u32 des5; /* Upper 32-bits of Buffer Address Pointer 1*/
+
+ u32 des6; /* Lower 32-bits of Next Descriptor Address */
+ u32 des7; /* Upper 32-bits of Next Descriptor Address */
+};
+
struct idmac_desc {
u32 des0; /* Control Descriptor */
#define IDMAC_DES0_DIC BIT(1)
@@ -83,6 +100,7 @@ struct idmac_desc {
#endif /* CONFIG_MMC_DW_IDMAC */
static bool dw_mci_reset(struct dw_mci *host);
+static bool dw_mci_ctrl_reset(struct dw_mci *host, u32 reset);
#if defined(CONFIG_DEBUG_FS)
static int dw_mci_req_show(struct seq_file *s, void *v)
@@ -414,30 +432,66 @@ static void dw_mci_translate_sglist(struct dw_mci *host, struct mmc_data *data,
unsigned int sg_len)
{
int i;
- struct idmac_desc *desc = host->sg_cpu;
+ if (host->dma_64bit_address == 1) {
+ struct idmac_desc_64addr *desc = host->sg_cpu;
- for (i = 0; i < sg_len; i++, desc++) {
- unsigned int length = sg_dma_len(&data->sg[i]);
- u32 mem_addr = sg_dma_address(&data->sg[i]);
+ for (i = 0; i < sg_len; i++, desc++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ u64 mem_addr = sg_dma_address(&data->sg[i]);
- /* Set the OWN bit and disable interrupts for this descriptor */
- desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC | IDMAC_DES0_CH;
+ /*
+ * Set the OWN bit and disable interrupts for this
+ * descriptor
+ */
+ desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
+ IDMAC_DES0_CH;
+ /* Buffer length */
+ IDMAC_64ADDR_SET_BUFFER1_SIZE(desc, length);
+
+ /* Physical address to DMA to/from */
+ desc->des4 = mem_addr & 0xffffffff;
+ desc->des5 = mem_addr >> 32;
+ }
- /* Buffer length */
- IDMAC_SET_BUFFER1_SIZE(desc, length);
+ /* Set first descriptor */
+ desc = host->sg_cpu;
+ desc->des0 |= IDMAC_DES0_FD;
- /* Physical address to DMA to/from */
- desc->des2 = mem_addr;
- }
+ /* Set last descriptor */
+ desc = host->sg_cpu + (i - 1) *
+ sizeof(struct idmac_desc_64addr);
+ desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+ desc->des0 |= IDMAC_DES0_LD;
- /* Set first descriptor */
- desc = host->sg_cpu;
- desc->des0 |= IDMAC_DES0_FD;
+ } else {
+ struct idmac_desc *desc = host->sg_cpu;
+
+ for (i = 0; i < sg_len; i++, desc++) {
+ unsigned int length = sg_dma_len(&data->sg[i]);
+ u32 mem_addr = sg_dma_address(&data->sg[i]);
+
+ /*
+ * Set the OWN bit and disable interrupts for this
+ * descriptor
+ */
+ desc->des0 = IDMAC_DES0_OWN | IDMAC_DES0_DIC |
+ IDMAC_DES0_CH;
+ /* Buffer length */
+ IDMAC_SET_BUFFER1_SIZE(desc, length);
- /* Set last descriptor */
- desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
- desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
- desc->des0 |= IDMAC_DES0_LD;
+ /* Physical address to DMA to/from */
+ desc->des2 = mem_addr;
+ }
+
+ /* Set first descriptor */
+ desc = host->sg_cpu;
+ desc->des0 |= IDMAC_DES0_FD;
+
+ /* Set last descriptor */
+ desc = host->sg_cpu + (i - 1) * sizeof(struct idmac_desc);
+ desc->des0 &= ~(IDMAC_DES0_CH | IDMAC_DES0_DIC);
+ desc->des0 |= IDMAC_DES0_LD;
+ }
wmb();
}
@@ -448,6 +502,10 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
dw_mci_translate_sglist(host, host->data, sg_len);
+ /* Make sure to reset DMA in case we did PIO before this */
+ dw_mci_ctrl_reset(host, SDMMC_CTRL_DMA_RESET);
+ dw_mci_idmac_reset(host);
+
/* Select IDMAC interface */
temp = mci_readl(host, CTRL);
temp |= SDMMC_CTRL_USE_IDMAC;
@@ -466,29 +524,71 @@ static void dw_mci_idmac_start_dma(struct dw_mci *host, unsigned int sg_len)
static int dw_mci_idmac_init(struct dw_mci *host)
{
- struct idmac_desc *p;
int i;
- /* Number of descriptors in the ring buffer */
- host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
+ if (host->dma_64bit_address == 1) {
+ struct idmac_desc_64addr *p;
+ /* Number of descriptors in the ring buffer */
+ host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc_64addr);
+
+ /* Forward link the descriptor list */
+ for (i = 0, p = host->sg_cpu; i < host->ring_size - 1;
+ i++, p++) {
+ p->des6 = (host->sg_dma +
+ (sizeof(struct idmac_desc_64addr) *
+ (i + 1))) & 0xffffffff;
+
+ p->des7 = (u64)(host->sg_dma +
+ (sizeof(struct idmac_desc_64addr) *
+ (i + 1))) >> 32;
+ /* Initialize reserved and buffer size fields to "0" */
+ p->des1 = 0;
+ p->des2 = 0;
+ p->des3 = 0;
+ }
+
+ /* Set the last descriptor as the end-of-ring descriptor */
+ p->des6 = host->sg_dma & 0xffffffff;
+ p->des7 = (u64)host->sg_dma >> 32;
+ p->des0 = IDMAC_DES0_ER;
+
+ } else {
+ struct idmac_desc *p;
+ /* Number of descriptors in the ring buffer */
+ host->ring_size = PAGE_SIZE / sizeof(struct idmac_desc);
- /* Forward link the descriptor list */
- for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
- p->des3 = host->sg_dma + (sizeof(struct idmac_desc) * (i + 1));
+ /* Forward link the descriptor list */
+ for (i = 0, p = host->sg_cpu; i < host->ring_size - 1; i++, p++)
+ p->des3 = host->sg_dma + (sizeof(struct idmac_desc) *
+ (i + 1));
- /* Set the last descriptor as the end-of-ring descriptor */
- p->des3 = host->sg_dma;
- p->des0 = IDMAC_DES0_ER;
+ /* Set the last descriptor as the end-of-ring descriptor */
+ p->des3 = host->sg_dma;
+ p->des0 = IDMAC_DES0_ER;
+ }
dw_mci_idmac_reset(host);
- /* Mask out interrupts - get Tx & Rx complete only */
- mci_writel(host, IDSTS, IDMAC_INT_CLR);
- mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI | SDMMC_IDMAC_INT_RI |
- SDMMC_IDMAC_INT_TI);
+ if (host->dma_64bit_address == 1) {
+ /* Mask out interrupts - get Tx & Rx complete only */
+ mci_writel(host, IDSTS64, IDMAC_INT_CLR);
+ mci_writel(host, IDINTEN64, SDMMC_IDMAC_INT_NI |
+ SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
+
+ /* Set the descriptor base address */
+ mci_writel(host, DBADDRL, host->sg_dma & 0xffffffff);
+ mci_writel(host, DBADDRU, (u64)host->sg_dma >> 32);
+
+ } else {
+ /* Mask out interrupts - get Tx & Rx complete only */
+ mci_writel(host, IDSTS, IDMAC_INT_CLR);
+ mci_writel(host, IDINTEN, SDMMC_IDMAC_INT_NI |
+ SDMMC_IDMAC_INT_RI | SDMMC_IDMAC_INT_TI);
+
+ /* Set the descriptor base address */
+ mci_writel(host, DBADDR, host->sg_dma);
+ }
- /* Set the descriptor base address */
- mci_writel(host, DBADDR, host->sg_dma);
return 0;
}
@@ -626,6 +726,13 @@ static void dw_mci_ctrl_rd_thld(struct dw_mci *host, struct mmc_data *data)
WARN_ON(!(data->flags & MMC_DATA_READ));
+ /*
+ * CDTHRCTL doesn't exist prior to 240A (in fact that register offset is
+ * in the FIFO region, so we really shouldn't access it).
+ */
+ if (host->verid < DW_MMC_240A)
+ return;
+
if (host->timing != MMC_TIMING_MMC_HS200 &&
host->timing != MMC_TIMING_UHS_SDR104)
goto disable;
@@ -819,7 +926,7 @@ static void dw_mci_setup_bus(struct dw_mci_slot *slot, bool force_clkinit)
/* enable clock; only low power if no SDIO */
clk_en_a = SDMMC_CLKEN_ENABLE << slot->id;
- if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->id)))
+ if (!(mci_readl(host, INTMASK) & SDMMC_INT_SDIO(slot->sdio_id)))
clk_en_a |= SDMMC_CLKEN_LOW_PWR << slot->id;
mci_writel(host, CLKENA, clk_en_a);
@@ -1075,7 +1182,7 @@ static int dw_mci_switch_voltage(struct mmc_host *mmc, struct mmc_ios *ios)
ret = regulator_set_voltage(mmc->supply.vqmmc, min_uv, max_uv);
if (ret) {
- dev_err(&mmc->class_dev,
+ dev_dbg(&mmc->class_dev,
"Regulator set error %d: %d - %d\n",
ret, min_uv, max_uv);
return ret;
@@ -1180,10 +1287,10 @@ static void dw_mci_enable_sdio_irq(struct mmc_host *mmc, int enb)
dw_mci_disable_low_power(slot);
mci_writel(host, INTMASK,
- (int_mask | SDMMC_INT_SDIO(slot->id)));
+ (int_mask | SDMMC_INT_SDIO(slot->sdio_id)));
} else {
mci_writel(host, INTMASK,
- (int_mask & ~SDMMC_INT_SDIO(slot->id)));
+ (int_mask & ~SDMMC_INT_SDIO(slot->sdio_id)));
}
}
@@ -1954,6 +2061,23 @@ static void dw_mci_cmd_interrupt(struct dw_mci *host, u32 status)
tasklet_schedule(&host->tasklet);
}
+static void dw_mci_handle_cd(struct dw_mci *host)
+{
+ int i;
+
+ for (i = 0; i < host->num_slots; i++) {
+ struct dw_mci_slot *slot = host->slot[i];
+
+ if (!slot)
+ continue;
+
+ if (slot->mmc->ops->card_event)
+ slot->mmc->ops->card_event(slot->mmc);
+ mmc_detect_change(slot->mmc,
+ msecs_to_jiffies(host->pdata->detect_delay_ms));
+ }
+}
+
static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
{
struct dw_mci *host = dev_id;
@@ -2029,14 +2153,15 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
if (pending & SDMMC_INT_CD) {
mci_writel(host, RINTSTS, SDMMC_INT_CD);
- queue_work(host->card_workqueue, &host->card_work);
+ dw_mci_handle_cd(host);
}
/* Handle SDIO Interrupts */
for (i = 0; i < host->num_slots; i++) {
struct dw_mci_slot *slot = host->slot[i];
- if (pending & SDMMC_INT_SDIO(i)) {
- mci_writel(host, RINTSTS, SDMMC_INT_SDIO(i));
+ if (pending & SDMMC_INT_SDIO(slot->sdio_id)) {
+ mci_writel(host, RINTSTS,
+ SDMMC_INT_SDIO(slot->sdio_id));
mmc_signal_sdio_irq(slot->mmc);
}
}
@@ -2045,99 +2170,28 @@ static irqreturn_t dw_mci_interrupt(int irq, void *dev_id)
#ifdef CONFIG_MMC_DW_IDMAC
/* Handle DMA interrupts */
- pending = mci_readl(host, IDSTS);
- if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
- mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI);
- mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
- host->dma_ops->complete(host);
+ if (host->dma_64bit_address == 1) {
+ pending = mci_readl(host, IDSTS64);
+ if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
+ mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_TI |
+ SDMMC_IDMAC_INT_RI);
+ mci_writel(host, IDSTS64, SDMMC_IDMAC_INT_NI);
+ host->dma_ops->complete(host);
+ }
+ } else {
+ pending = mci_readl(host, IDSTS);
+ if (pending & (SDMMC_IDMAC_INT_TI | SDMMC_IDMAC_INT_RI)) {
+ mci_writel(host, IDSTS, SDMMC_IDMAC_INT_TI |
+ SDMMC_IDMAC_INT_RI);
+ mci_writel(host, IDSTS, SDMMC_IDMAC_INT_NI);
+ host->dma_ops->complete(host);
+ }
}
#endif
return IRQ_HANDLED;
}
-static void dw_mci_work_routine_card(struct work_struct *work)
-{
- struct dw_mci *host = container_of(work, struct dw_mci, card_work);
- int i;
-
- for (i = 0; i < host->num_slots; i++) {
- struct dw_mci_slot *slot = host->slot[i];
- struct mmc_host *mmc = slot->mmc;
- struct mmc_request *mrq;
- int present;
-
- present = dw_mci_get_cd(mmc);
- while (present != slot->last_detect_state) {
- dev_dbg(&slot->mmc->class_dev, "card %s\n",
- present ? "inserted" : "removed");
-
- spin_lock_bh(&host->lock);
-
- /* Card change detected */
- slot->last_detect_state = present;
-
- /* Clean up queue if present */
- mrq = slot->mrq;
- if (mrq) {
- if (mrq == host->mrq) {
- host->data = NULL;
- host->cmd = NULL;
-
- switch (host->state) {
- case STATE_IDLE:
- case STATE_WAITING_CMD11_DONE:
- break;
- case STATE_SENDING_CMD11:
- case STATE_SENDING_CMD:
- mrq->cmd->error = -ENOMEDIUM;
- if (!mrq->data)
- break;
- /* fall through */
- case STATE_SENDING_DATA:
- mrq->data->error = -ENOMEDIUM;
- dw_mci_stop_dma(host);
- break;
- case STATE_DATA_BUSY:
- case STATE_DATA_ERROR:
- if (mrq->data->error == -EINPROGRESS)
- mrq->data->error = -ENOMEDIUM;
- /* fall through */
- case STATE_SENDING_STOP:
- if (mrq->stop)
- mrq->stop->error = -ENOMEDIUM;
- break;
- }
-
- dw_mci_request_end(host, mrq);
- } else {
- list_del(&slot->queue_node);
- mrq->cmd->error = -ENOMEDIUM;
- if (mrq->data)
- mrq->data->error = -ENOMEDIUM;
- if (mrq->stop)
- mrq->stop->error = -ENOMEDIUM;
-
- spin_unlock(&host->lock);
- mmc_request_done(slot->mmc, mrq);
- spin_lock(&host->lock);
- }
- }
-
- /* Power down slot */
- if (present == 0)
- dw_mci_reset(host);
-
- spin_unlock_bh(&host->lock);
-
- present = dw_mci_get_cd(mmc);
- }
-
- mmc_detect_change(slot->mmc,
- msecs_to_jiffies(host->pdata->detect_delay_ms));
- }
-}
-
#ifdef CONFIG_OF
/* given a slot id, find out the device node representing that slot */
static struct device_node *dw_mci_of_find_slot_node(struct device *dev, u8 slot)
@@ -2206,6 +2260,7 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
slot = mmc_priv(mmc);
slot->id = id;
+ slot->sdio_id = host->sdio_id0 + id;
slot->mmc = mmc;
slot->host = host;
host->slot[id] = slot;
@@ -2289,9 +2344,6 @@ static int dw_mci_init_slot(struct dw_mci *host, unsigned int id)
dw_mci_init_debugfs(slot);
#endif
- /* Card initially undetected */
- slot->last_detect_state = 0;
-
return 0;
err_host_allocated:
@@ -2309,6 +2361,22 @@ static void dw_mci_cleanup_slot(struct dw_mci_slot *slot, unsigned int id)
static void dw_mci_init_dma(struct dw_mci *host)
{
+ int addr_config;
+ /* Check ADDR_CONFIG bit in HCON to find IDMAC address bus width */
+ addr_config = (mci_readl(host, HCON) >> 27) & 0x01;
+
+ if (addr_config == 1) {
+ /* host supports IDMAC in 64-bit address mode */
+ host->dma_64bit_address = 1;
+ dev_info(host->dev, "IDMAC supports 64-bit address mode.\n");
+ if (!dma_set_mask(host->dev, DMA_BIT_MASK(64)))
+ dma_set_coherent_mask(host->dev, DMA_BIT_MASK(64));
+ } else {
+ /* host supports IDMAC in 32-bit address mode */
+ host->dma_64bit_address = 0;
+ dev_info(host->dev, "IDMAC supports 32-bit address mode.\n");
+ }
+
/* Alloc memory for sg translation */
host->sg_cpu = dmam_alloc_coherent(host->dev, PAGE_SIZE,
&host->sg_dma, GFP_KERNEL);
@@ -2672,17 +2740,10 @@ int dw_mci_probe(struct dw_mci *host)
host->data_offset = DATA_240A_OFFSET;
tasklet_init(&host->tasklet, dw_mci_tasklet_func, (unsigned long)host);
- host->card_workqueue = alloc_workqueue("dw-mci-card",
- WQ_MEM_RECLAIM, 1);
- if (!host->card_workqueue) {
- ret = -ENOMEM;
- goto err_dmaunmap;
- }
- INIT_WORK(&host->card_work, dw_mci_work_routine_card);
ret = devm_request_irq(host->dev, host->irq, dw_mci_interrupt,
host->irq_flags, "dw-mci", host);
if (ret)
- goto err_workqueue;
+ goto err_dmaunmap;
if (host->pdata->num_slots)
host->num_slots = host->pdata->num_slots;
@@ -2718,7 +2779,7 @@ int dw_mci_probe(struct dw_mci *host)
} else {
dev_dbg(host->dev, "attempted to initialize %d slots, "
"but failed on all\n", host->num_slots);
- goto err_workqueue;
+ goto err_dmaunmap;
}
if (host->quirks & DW_MCI_QUIRK_IDMAC_DTO)
@@ -2726,9 +2787,6 @@ int dw_mci_probe(struct dw_mci *host)
return 0;
-err_workqueue:
- destroy_workqueue(host->card_workqueue);
-
err_dmaunmap:
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
@@ -2762,8 +2820,6 @@ void dw_mci_remove(struct dw_mci *host)
mci_writel(host, CLKENA, 0);
mci_writel(host, CLKSRC, 0);
- destroy_workqueue(host->card_workqueue);
-
if (host->use_dma && host->dma_ops->exit)
host->dma_ops->exit(host);
diff --git a/drivers/mmc/host/dw_mmc.h b/drivers/mmc/host/dw_mmc.h
index 01b99e8..0d0f7a2 100644
--- a/drivers/mmc/host/dw_mmc.h
+++ b/drivers/mmc/host/dw_mmc.h
@@ -55,6 +55,17 @@
#define SDMMC_BUFADDR 0x098
#define SDMMC_CDTHRCTL 0x100
#define SDMMC_DATA(x) (x)
+/*
+* Registers to support idmac 64-bit address mode
+*/
+#define SDMMC_DBADDRL 0x088
+#define SDMMC_DBADDRU 0x08c
+#define SDMMC_IDSTS64 0x090
+#define SDMMC_IDINTEN64 0x094
+#define SDMMC_DSCADDRL 0x098
+#define SDMMC_DSCADDRU 0x09c
+#define SDMMC_BUFADDRL 0x0A0
+#define SDMMC_BUFADDRU 0x0A4
/*
* Data offset is difference according to Version
@@ -214,7 +225,7 @@ extern int dw_mci_resume(struct dw_mci *host);
* with CONFIG_MMC_CLKGATE.
* @flags: Random state bits associated with the slot.
* @id: Number of this slot.
- * @last_detect_state: Most recently observed card detect state.
+ * @sdio_id: Number of this slot in the SDIO interrupt registers.
*/
struct dw_mci_slot {
struct mmc_host *mmc;
@@ -234,7 +245,7 @@ struct dw_mci_slot {
#define DW_MMC_CARD_PRESENT 0
#define DW_MMC_CARD_NEED_INIT 1
int id;
- int last_detect_state;
+ int sdio_id;
};
struct dw_mci_tuning_data {
diff --git a/drivers/mmc/host/mmci.c b/drivers/mmc/host/mmci.c
index 43af791..8232e9a 100644
--- a/drivers/mmc/host/mmci.c
+++ b/drivers/mmc/host/mmci.c
@@ -736,8 +736,15 @@ static void mmci_post_request(struct mmc_host *mmc, struct mmc_request *mrq,
chan = host->dma_tx_channel;
dmaengine_terminate_all(chan);
+ if (host->dma_desc_current == next->dma_desc)
+ host->dma_desc_current = NULL;
+
+ if (host->dma_current == next->dma_chan)
+ host->dma_current = NULL;
+
next->dma_desc = NULL;
next->dma_chan = NULL;
+ data->host_cookie = 0;
}
}
@@ -1843,7 +1850,7 @@ static int mmci_runtime_resume(struct device *dev)
static const struct dev_pm_ops mmci_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
- SET_PM_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
+ SET_RUNTIME_PM_OPS(mmci_runtime_suspend, mmci_runtime_resume, NULL)
};
static struct amba_id mmci_ids[] = {
diff --git a/drivers/mmc/host/msm_sdcc.c b/drivers/mmc/host/msm_sdcc.c
index 9405ecd..90c60fd 100644
--- a/drivers/mmc/host/msm_sdcc.c
+++ b/drivers/mmc/host/msm_sdcc.c
@@ -1360,7 +1360,7 @@ msmsdcc_probe(struct platform_device *pdev)
if (ret)
goto cmd_irq_free;
- mmc_set_drvdata(pdev, mmc);
+ platform_set_drvdata(pdev, mmc);
mmc_add_host(mmc);
pr_info("%s: Qualcomm MSM SDCC at 0x%016llx irq %d,%d dma %d\n",
@@ -1419,7 +1419,7 @@ ioremap_free:
static int
msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
{
- struct mmc_host *mmc = mmc_get_drvdata(dev);
+ struct mmc_host *mmc = platform_get_drvdata(dev);
if (mmc) {
struct msmsdcc_host *host = mmc_priv(mmc);
@@ -1437,7 +1437,7 @@ msmsdcc_suspend(struct platform_device *dev, pm_message_t state)
static int
msmsdcc_resume(struct platform_device *dev)
{
- struct mmc_host *mmc = mmc_get_drvdata(dev);
+ struct mmc_host *mmc = platform_get_drvdata(dev);
if (mmc) {
struct msmsdcc_host *host = mmc_priv(mmc);
diff --git a/drivers/mmc/host/mvsdio.c b/drivers/mmc/host/mvsdio.c
index 6b4c5ad3..4f8618f 100644
--- a/drivers/mmc/host/mvsdio.c
+++ b/drivers/mmc/host/mvsdio.c
@@ -111,10 +111,15 @@ static int mvsd_setup_data(struct mvsd_host *host, struct mmc_data *data)
mvsd_write(MVSD_BLK_COUNT, data->blocks);
mvsd_write(MVSD_BLK_SIZE, data->blksz);
- if (nodma || (data->blksz | data->sg->offset) & 3) {
+ if (nodma || (data->blksz | data->sg->offset) & 3 ||
+ ((!(data->flags & MMC_DATA_READ) && data->sg->offset & 0x3f))) {
/*
* We cannot do DMA on a buffer which offset or size
* is not aligned on a 4-byte boundary.
+ *
+ * It also appears the host to card DMA can corrupt
+ * data when the buffer is not aligned on a 64 byte
+ * boundary.
*/
host->pio_size = data->blocks * data->blksz;
host->pio_ptr = sg_virt(data->sg);
diff --git a/drivers/mmc/host/mxcmmc.c b/drivers/mmc/host/mxcmmc.c
index ad11142..5316d9b 100644
--- a/drivers/mmc/host/mxcmmc.c
+++ b/drivers/mmc/host/mxcmmc.c
@@ -373,13 +373,9 @@ static void mxcmci_dma_callback(void *data)
del_timer(&host->watchdog);
stat = mxcmci_readl(host, MMC_REG_STATUS);
- mxcmci_writel(host, stat & ~STATUS_DATA_TRANS_DONE, MMC_REG_STATUS);
dev_dbg(mmc_dev(host->mmc), "%s: 0x%08x\n", __func__, stat);
- if (stat & STATUS_READ_OP_DONE)
- mxcmci_writel(host, STATUS_READ_OP_DONE, MMC_REG_STATUS);
-
mxcmci_data_done(host, stat);
}
@@ -743,10 +739,8 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
sdio_irq = (stat & STATUS_SDIO_INT_ACTIVE) && host->use_sdio;
spin_unlock_irqrestore(&host->lock, flags);
- if (mxcmci_use_dma(host) &&
- (stat & (STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE)))
- mxcmci_writel(host, STATUS_READ_OP_DONE | STATUS_WRITE_OP_DONE,
- MMC_REG_STATUS);
+ if (mxcmci_use_dma(host) && (stat & (STATUS_WRITE_OP_DONE)))
+ mxcmci_writel(host, STATUS_WRITE_OP_DONE, MMC_REG_STATUS);
if (sdio_irq) {
mxcmci_writel(host, STATUS_SDIO_INT_ACTIVE, MMC_REG_STATUS);
@@ -756,8 +750,7 @@ static irqreturn_t mxcmci_irq(int irq, void *devid)
if (stat & STATUS_END_CMD_RESP)
mxcmci_cmd_done(host, stat);
- if (mxcmci_use_dma(host) &&
- (stat & (STATUS_DATA_TRANS_DONE | STATUS_WRITE_OP_DONE))) {
+ if (mxcmci_use_dma(host) && (stat & STATUS_WRITE_OP_DONE)) {
del_timer(&host->watchdog);
mxcmci_data_done(host, stat);
}
@@ -1084,12 +1077,14 @@ static int mxcmci_probe(struct platform_device *pdev)
dat3_card_detect = true;
ret = mmc_regulator_get_supply(mmc);
- if (ret) {
- if (pdata && ret != -EPROBE_DEFER)
- mmc->ocr_avail = pdata->ocr_avail ? :
- MMC_VDD_32_33 | MMC_VDD_33_34;
+ if (ret == -EPROBE_DEFER)
+ goto out_free;
+
+ if (!mmc->ocr_avail) {
+ if (pdata && pdata->ocr_avail)
+ mmc->ocr_avail = pdata->ocr_avail;
else
- goto out_free;
+ mmc->ocr_avail = MMC_VDD_32_33 | MMC_VDD_33_34;
}
if (dat3_card_detect)
diff --git a/drivers/mmc/host/mxs-mmc.c b/drivers/mmc/host/mxs-mmc.c
index cd74e51..60c4ca9 100644
--- a/drivers/mmc/host/mxs-mmc.c
+++ b/drivers/mmc/host/mxs-mmc.c
@@ -581,10 +581,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
struct regulator *reg_vmmc;
struct mxs_ssp *ssp;
- iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq_err = platform_get_irq(pdev, 0);
- if (!iores || irq_err < 0)
- return -EINVAL;
+ if (irq_err < 0)
+ return irq_err;
mmc = mmc_alloc_host(sizeof(struct mxs_mmc_host), &pdev->dev);
if (!mmc)
@@ -593,6 +592,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
host = mmc_priv(mmc);
ssp = &host->ssp;
ssp->dev = &pdev->dev;
+ iores = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ssp->base = devm_ioremap_resource(&pdev->dev, iores);
if (IS_ERR(ssp->base)) {
ret = PTR_ERR(ssp->base);
@@ -619,7 +619,9 @@ static int mxs_mmc_probe(struct platform_device *pdev)
ret = PTR_ERR(ssp->clk);
goto out_mmc_free;
}
- clk_prepare_enable(ssp->clk);
+ ret = clk_prepare_enable(ssp->clk);
+ if (ret)
+ goto out_mmc_free;
ret = mxs_mmc_reset(host);
if (ret) {
@@ -660,7 +662,7 @@ static int mxs_mmc_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, mmc);
ret = devm_request_irq(&pdev->dev, irq_err, mxs_mmc_irq_handler, 0,
- DRIVER_NAME, host);
+ dev_name(&pdev->dev), host);
if (ret)
goto out_free_dma;
@@ -702,7 +704,7 @@ static int mxs_mmc_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM
+#ifdef CONFIG_PM_SLEEP
static int mxs_mmc_suspend(struct device *dev)
{
struct mmc_host *mmc = dev_get_drvdata(dev);
@@ -719,25 +721,19 @@ static int mxs_mmc_resume(struct device *dev)
struct mxs_mmc_host *host = mmc_priv(mmc);
struct mxs_ssp *ssp = &host->ssp;
- clk_prepare_enable(ssp->clk);
- return 0;
+ return clk_prepare_enable(ssp->clk);
}
-
-static const struct dev_pm_ops mxs_mmc_pm_ops = {
- .suspend = mxs_mmc_suspend,
- .resume = mxs_mmc_resume,
-};
#endif
+static SIMPLE_DEV_PM_OPS(mxs_mmc_pm_ops, mxs_mmc_suspend, mxs_mmc_resume);
+
static struct platform_driver mxs_mmc_driver = {
.probe = mxs_mmc_probe,
.remove = mxs_mmc_remove,
.id_table = mxs_ssp_ids,
.driver = {
.name = DRIVER_NAME,
-#ifdef CONFIG_PM
.pm = &mxs_mmc_pm_ops,
-#endif
.of_match_table = mxs_mmc_dt_ids,
},
};
diff --git a/drivers/mmc/host/omap_hsmmc.c b/drivers/mmc/host/omap_hsmmc.c
index df27bb4..7c71dcd 100644
--- a/drivers/mmc/host/omap_hsmmc.c
+++ b/drivers/mmc/host/omap_hsmmc.c
@@ -42,7 +42,7 @@
#include <linux/regulator/consumer.h>
#include <linux/pinctrl/consumer.h>
#include <linux/pm_runtime.h>
-#include <linux/platform_data/mmc-omap.h>
+#include <linux/platform_data/hsmmc-omap.h>
/* OMAP HSMMC Host Controller Registers */
#define OMAP_HSMMC_SYSSTATUS 0x0014
@@ -155,7 +155,7 @@
* omap.c controller driver. Luckily this is not currently done on any known
* omap_hsmmc.c device.
*/
-#define mmc_slot(host) (host->pdata->slots[host->slot_id])
+#define mmc_pdata(host) host->pdata
/*
* MMC Host controller read/write API's
@@ -207,7 +207,6 @@ struct omap_hsmmc_host {
int use_dma, dma_ch;
struct dma_chan *tx_chan;
struct dma_chan *rx_chan;
- int slot_id;
int response_busy;
int context_loss;
int protect_card;
@@ -220,7 +219,26 @@ struct omap_hsmmc_host {
#define HSMMC_SDIO_IRQ_ENABLED (1 << 1) /* SDIO irq enabled */
#define HSMMC_WAKE_IRQ_ENABLED (1 << 2)
struct omap_hsmmc_next next_data;
- struct omap_mmc_platform_data *pdata;
+ struct omap_hsmmc_platform_data *pdata;
+
+ /* To handle board related suspend/resume functionality for MMC */
+ int (*suspend)(struct device *dev);
+ int (*resume)(struct device *dev);
+
+ /* return MMC cover switch state, can be NULL if not supported.
+ *
+ * possible return values:
+ * 0 - closed
+ * 1 - open
+ */
+ int (*get_cover_state)(struct device *dev);
+
+ /* Card detection IRQs */
+ int card_detect_irq;
+
+ int (*card_detect)(struct device *dev);
+ int (*get_ro)(struct device *dev);
+
};
struct omap_mmc_of_data {
@@ -230,50 +248,48 @@ struct omap_mmc_of_data {
static void omap_hsmmc_start_dma_transfer(struct omap_hsmmc_host *host);
-static int omap_hsmmc_card_detect(struct device *dev, int slot)
+static int omap_hsmmc_card_detect(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_mmc_platform_data *mmc = host->pdata;
+ struct omap_hsmmc_platform_data *mmc = host->pdata;
/* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
+ return !gpio_get_value_cansleep(mmc->switch_pin);
}
-static int omap_hsmmc_get_wp(struct device *dev, int slot)
+static int omap_hsmmc_get_wp(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_mmc_platform_data *mmc = host->pdata;
+ struct omap_hsmmc_platform_data *mmc = host->pdata;
/* NOTE: assumes write protect signal is active-high */
- return gpio_get_value_cansleep(mmc->slots[0].gpio_wp);
+ return gpio_get_value_cansleep(mmc->gpio_wp);
}
-static int omap_hsmmc_get_cover_state(struct device *dev, int slot)
+static int omap_hsmmc_get_cover_state(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_mmc_platform_data *mmc = host->pdata;
+ struct omap_hsmmc_platform_data *mmc = host->pdata;
/* NOTE: assumes card detect signal is active-low */
- return !gpio_get_value_cansleep(mmc->slots[0].switch_pin);
+ return !gpio_get_value_cansleep(mmc->switch_pin);
}
#ifdef CONFIG_PM
-static int omap_hsmmc_suspend_cdirq(struct device *dev, int slot)
+static int omap_hsmmc_suspend_cdirq(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_mmc_platform_data *mmc = host->pdata;
- disable_irq(mmc->slots[0].card_detect_irq);
+ disable_irq(host->card_detect_irq);
return 0;
}
-static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
+static int omap_hsmmc_resume_cdirq(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- struct omap_mmc_platform_data *mmc = host->pdata;
- enable_irq(mmc->slots[0].card_detect_irq);
+ enable_irq(host->card_detect_irq);
return 0;
}
@@ -286,8 +302,7 @@ static int omap_hsmmc_resume_cdirq(struct device *dev, int slot)
#ifdef CONFIG_REGULATOR
-static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
- int vdd)
+static int omap_hsmmc_set_power(struct device *dev, int power_on, int vdd)
{
struct omap_hsmmc_host *host =
platform_get_drvdata(to_platform_device(dev));
@@ -300,8 +315,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
if (!host->vcc)
return 0;
- if (mmc_slot(host).before_set_reg)
- mmc_slot(host).before_set_reg(dev, slot, power_on, vdd);
+ if (mmc_pdata(host)->before_set_reg)
+ mmc_pdata(host)->before_set_reg(dev, power_on, vdd);
if (host->pbias) {
if (host->pbias_enabled == 1) {
@@ -363,8 +378,8 @@ static int omap_hsmmc_set_power(struct device *dev, int slot, int power_on,
}
}
- if (mmc_slot(host).after_set_reg)
- mmc_slot(host).after_set_reg(dev, slot, power_on, vdd);
+ if (mmc_pdata(host)->after_set_reg)
+ mmc_pdata(host)->after_set_reg(dev, power_on, vdd);
error_set_power:
return ret;
@@ -383,18 +398,18 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
} else {
host->vcc = reg;
ocr_value = mmc_regulator_get_ocrmask(reg);
- if (!mmc_slot(host).ocr_mask) {
- mmc_slot(host).ocr_mask = ocr_value;
+ if (!mmc_pdata(host)->ocr_mask) {
+ mmc_pdata(host)->ocr_mask = ocr_value;
} else {
- if (!(mmc_slot(host).ocr_mask & ocr_value)) {
+ if (!(mmc_pdata(host)->ocr_mask & ocr_value)) {
dev_err(host->dev, "ocrmask %x is not supported\n",
- mmc_slot(host).ocr_mask);
- mmc_slot(host).ocr_mask = 0;
+ mmc_pdata(host)->ocr_mask);
+ mmc_pdata(host)->ocr_mask = 0;
return -EINVAL;
}
}
}
- mmc_slot(host).set_power = omap_hsmmc_set_power;
+ mmc_pdata(host)->set_power = omap_hsmmc_set_power;
/* Allow an aux regulator */
reg = devm_regulator_get_optional(host->dev, "vmmc_aux");
@@ -404,7 +419,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
host->pbias = IS_ERR(reg) ? NULL : reg;
/* For eMMC do not power off when not in sleep state */
- if (mmc_slot(host).no_regulator_off_init)
+ if (mmc_pdata(host)->no_regulator_off_init)
return 0;
/*
* To disable boot_on regulator, enable regulator
@@ -412,10 +427,10 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
*/
if ((host->vcc && regulator_is_enabled(host->vcc) > 0) ||
(host->vcc_aux && regulator_is_enabled(host->vcc_aux))) {
- int vdd = ffs(mmc_slot(host).ocr_mask) - 1;
+ int vdd = ffs(mmc_pdata(host)->ocr_mask) - 1;
- mmc_slot(host).set_power(host->dev, host->slot_id, 1, vdd);
- mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+ mmc_pdata(host)->set_power(host->dev, 1, vdd);
+ mmc_pdata(host)->set_power(host->dev, 0, 0);
}
return 0;
@@ -423,7 +438,7 @@ static int omap_hsmmc_reg_get(struct omap_hsmmc_host *host)
static void omap_hsmmc_reg_put(struct omap_hsmmc_host *host)
{
- mmc_slot(host).set_power = NULL;
+ mmc_pdata(host)->set_power = NULL;
}
static inline int omap_hsmmc_have_reg(void)
@@ -449,55 +464,59 @@ static inline int omap_hsmmc_have_reg(void)
#endif
-static int omap_hsmmc_gpio_init(struct omap_mmc_platform_data *pdata)
+static int omap_hsmmc_gpio_init(struct omap_hsmmc_host *host,
+ struct omap_hsmmc_platform_data *pdata)
{
int ret;
- if (gpio_is_valid(pdata->slots[0].switch_pin)) {
- if (pdata->slots[0].cover)
- pdata->slots[0].get_cover_state =
- omap_hsmmc_get_cover_state;
+ if (gpio_is_valid(pdata->switch_pin)) {
+ if (pdata->cover)
+ host->get_cover_state =
+ omap_hsmmc_get_cover_state;
else
- pdata->slots[0].card_detect = omap_hsmmc_card_detect;
- pdata->slots[0].card_detect_irq =
- gpio_to_irq(pdata->slots[0].switch_pin);
- ret = gpio_request(pdata->slots[0].switch_pin, "mmc_cd");
+ host->card_detect = omap_hsmmc_card_detect;
+ host->card_detect_irq =
+ gpio_to_irq(pdata->switch_pin);
+ ret = gpio_request(pdata->switch_pin, "mmc_cd");
if (ret)
return ret;
- ret = gpio_direction_input(pdata->slots[0].switch_pin);
+ ret = gpio_direction_input(pdata->switch_pin);
if (ret)
goto err_free_sp;
- } else
- pdata->slots[0].switch_pin = -EINVAL;
+ } else {
+ pdata->switch_pin = -EINVAL;
+ }
- if (gpio_is_valid(pdata->slots[0].gpio_wp)) {
- pdata->slots[0].get_ro = omap_hsmmc_get_wp;
- ret = gpio_request(pdata->slots[0].gpio_wp, "mmc_wp");
+ if (gpio_is_valid(pdata->gpio_wp)) {
+ host->get_ro = omap_hsmmc_get_wp;
+ ret = gpio_request(pdata->gpio_wp, "mmc_wp");
if (ret)
goto err_free_cd;
- ret = gpio_direction_input(pdata->slots[0].gpio_wp);
+ ret = gpio_direction_input(pdata->gpio_wp);
if (ret)
goto err_free_wp;
- } else
- pdata->slots[0].gpio_wp = -EINVAL;
+ } else {
+ pdata->gpio_wp = -EINVAL;
+ }
return 0;
err_free_wp:
- gpio_free(pdata->slots[0].gpio_wp);
+ gpio_free(pdata->gpio_wp);
err_free_cd:
- if (gpio_is_valid(pdata->slots[0].switch_pin))
+ if (gpio_is_valid(pdata->switch_pin))
err_free_sp:
- gpio_free(pdata->slots[0].switch_pin);
+ gpio_free(pdata->switch_pin);
return ret;
}
-static void omap_hsmmc_gpio_free(struct omap_mmc_platform_data *pdata)
+static void omap_hsmmc_gpio_free(struct omap_hsmmc_host *host,
+ struct omap_hsmmc_platform_data *pdata)
{
- if (gpio_is_valid(pdata->slots[0].gpio_wp))
- gpio_free(pdata->slots[0].gpio_wp);
- if (gpio_is_valid(pdata->slots[0].switch_pin))
- gpio_free(pdata->slots[0].switch_pin);
+ if (gpio_is_valid(pdata->gpio_wp))
+ gpio_free(pdata->gpio_wp);
+ if (gpio_is_valid(pdata->switch_pin))
+ gpio_free(pdata->switch_pin);
}
/*
@@ -607,8 +626,9 @@ static void omap_hsmmc_set_clock(struct omap_hsmmc_host *host)
* in capabilities register
* - MMC/SD clock coming out of controller > 25MHz
*/
- if ((mmc_slot(host).features & HSMMC_HAS_HSPE_SUPPORT) &&
+ if ((mmc_pdata(host)->features & HSMMC_HAS_HSPE_SUPPORT) &&
(ios->timing != MMC_TIMING_MMC_DDR52) &&
+ (ios->timing != MMC_TIMING_UHS_DDR50) &&
((OMAP_HSMMC_READ(host->base, CAPA) & HSS) == HSS)) {
regval = OMAP_HSMMC_READ(host->base, HCTL);
if (clkdiv && (clk_get_rate(host->fclk)/clkdiv) > 25000000)
@@ -628,7 +648,8 @@ static void omap_hsmmc_set_bus_width(struct omap_hsmmc_host *host)
u32 con;
con = OMAP_HSMMC_READ(host->base, CON);
- if (ios->timing == MMC_TIMING_MMC_DDR52)
+ if (ios->timing == MMC_TIMING_MMC_DDR52 ||
+ ios->timing == MMC_TIMING_UHS_DDR50)
con |= DDR; /* configure in DDR mode */
else
con &= ~DDR;
@@ -791,8 +812,8 @@ int omap_hsmmc_cover_is_closed(struct omap_hsmmc_host *host)
{
int r = 1;
- if (mmc_slot(host).get_cover_state)
- r = mmc_slot(host).get_cover_state(host->dev, host->slot_id);
+ if (host->get_cover_state)
+ r = host->get_cover_state(host->dev);
return r;
}
@@ -816,7 +837,7 @@ omap_hsmmc_show_slot_name(struct device *dev, struct device_attribute *attr,
struct mmc_host *mmc = container_of(dev, struct mmc_host, class_dev);
struct omap_hsmmc_host *host = mmc_priv(mmc);
- return sprintf(buf, "%s\n", mmc_slot(host).name);
+ return sprintf(buf, "%s\n", mmc_pdata(host)->name);
}
static DEVICE_ATTR(slot_name, S_IRUGO, omap_hsmmc_show_slot_name, NULL);
@@ -1061,7 +1082,7 @@ static inline void omap_hsmmc_reset_controller_fsm(struct omap_hsmmc_host *host,
* OMAP4 ES2 and greater has an updated reset logic.
* Monitor a 0->1 transition first
*/
- if (mmc_slot(host).features & HSMMC_HAS_UPDATED_RESET) {
+ if (mmc_pdata(host)->features & HSMMC_HAS_UPDATED_RESET) {
while ((!(OMAP_HSMMC_READ(host->base, SYSCTL) & bit))
&& (i++ < limit))
udelay(1);
@@ -1210,12 +1231,11 @@ static int omap_hsmmc_switch_opcond(struct omap_hsmmc_host *host, int vdd)
clk_disable_unprepare(host->dbclk);
/* Turn the power off */
- ret = mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
+ ret = mmc_pdata(host)->set_power(host->dev, 0, 0);
/* Turn the power ON with given VDD 1.8 or 3.0v */
if (!ret)
- ret = mmc_slot(host).set_power(host->dev, host->slot_id, 1,
- vdd);
+ ret = mmc_pdata(host)->set_power(host->dev, 1, vdd);
pm_runtime_get_sync(host->dev);
if (host->dbclk)
clk_prepare_enable(host->dbclk);
@@ -1259,11 +1279,11 @@ err:
/* Protect the card while the cover is open */
static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
{
- if (!mmc_slot(host).get_cover_state)
+ if (!host->get_cover_state)
return;
host->reqs_blocked = 0;
- if (mmc_slot(host).get_cover_state(host->dev, host->slot_id)) {
+ if (host->get_cover_state(host->dev)) {
if (host->protect_card) {
dev_info(host->dev, "%s: cover is closed, "
"card is now accessible\n",
@@ -1286,13 +1306,12 @@ static void omap_hsmmc_protect_card(struct omap_hsmmc_host *host)
static irqreturn_t omap_hsmmc_detect(int irq, void *dev_id)
{
struct omap_hsmmc_host *host = dev_id;
- struct omap_mmc_slot_data *slot = &mmc_slot(host);
int carddetect;
sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
- if (slot->card_detect)
- carddetect = slot->card_detect(host->dev, host->slot_id);
+ if (host->card_detect)
+ carddetect = host->card_detect(host->dev);
else {
omap_hsmmc_protect_card(host);
carddetect = -ENOSYS;
@@ -1618,12 +1637,10 @@ static void omap_hsmmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
if (ios->power_mode != host->power_mode) {
switch (ios->power_mode) {
case MMC_POWER_OFF:
- mmc_slot(host).set_power(host->dev, host->slot_id,
- 0, 0);
+ mmc_pdata(host)->set_power(host->dev, 0, 0);
break;
case MMC_POWER_UP:
- mmc_slot(host).set_power(host->dev, host->slot_id,
- 1, ios->vdd);
+ mmc_pdata(host)->set_power(host->dev, 1, ios->vdd);
break;
case MMC_POWER_ON:
do_send_init_stream = 1;
@@ -1668,26 +1685,26 @@ static int omap_hsmmc_get_cd(struct mmc_host *mmc)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
- if (!mmc_slot(host).card_detect)
+ if (!host->card_detect)
return -ENOSYS;
- return mmc_slot(host).card_detect(host->dev, host->slot_id);
+ return host->card_detect(host->dev);
}
static int omap_hsmmc_get_ro(struct mmc_host *mmc)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
- if (!mmc_slot(host).get_ro)
+ if (!host->get_ro)
return -ENOSYS;
- return mmc_slot(host).get_ro(host->dev, 0);
+ return host->get_ro(host->dev);
}
static void omap_hsmmc_init_card(struct mmc_host *mmc, struct mmc_card *card)
{
struct omap_hsmmc_host *host = mmc_priv(mmc);
- if (mmc_slot(host).init_card)
- mmc_slot(host).init_card(card);
+ if (mmc_pdata(host)->init_card)
+ mmc_pdata(host)->init_card(card);
}
static void omap_hsmmc_enable_sdio_irq(struct mmc_host *mmc, int enable)
@@ -1957,9 +1974,9 @@ static const struct of_device_id omap_mmc_of_match[] = {
};
MODULE_DEVICE_TABLE(of, omap_mmc_of_match);
-static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
+static struct omap_hsmmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
{
- struct omap_mmc_platform_data *pdata;
+ struct omap_hsmmc_platform_data *pdata;
struct device_node *np = dev->of_node;
u32 bus_width, max_freq;
int cd_gpio, wp_gpio;
@@ -1976,40 +1993,38 @@ static struct omap_mmc_platform_data *of_get_hsmmc_pdata(struct device *dev)
if (of_find_property(np, "ti,dual-volt", NULL))
pdata->controller_flags |= OMAP_HSMMC_SUPPORTS_DUAL_VOLT;
- /* This driver only supports 1 slot */
- pdata->nr_slots = 1;
- pdata->slots[0].switch_pin = cd_gpio;
- pdata->slots[0].gpio_wp = wp_gpio;
+ pdata->switch_pin = cd_gpio;
+ pdata->gpio_wp = wp_gpio;
if (of_find_property(np, "ti,non-removable", NULL)) {
- pdata->slots[0].nonremovable = true;
- pdata->slots[0].no_regulator_off_init = true;
+ pdata->nonremovable = true;
+ pdata->no_regulator_off_init = true;
}
of_property_read_u32(np, "bus-width", &bus_width);
if (bus_width == 4)
- pdata->slots[0].caps |= MMC_CAP_4_BIT_DATA;
+ pdata->caps |= MMC_CAP_4_BIT_DATA;
else if (bus_width == 8)
- pdata->slots[0].caps |= MMC_CAP_8_BIT_DATA;
+ pdata->caps |= MMC_CAP_8_BIT_DATA;
if (of_find_property(np, "ti,needs-special-reset", NULL))
- pdata->slots[0].features |= HSMMC_HAS_UPDATED_RESET;
+ pdata->features |= HSMMC_HAS_UPDATED_RESET;
if (!of_property_read_u32(np, "max-frequency", &max_freq))
pdata->max_freq = max_freq;
if (of_find_property(np, "ti,needs-special-hs-handling", NULL))
- pdata->slots[0].features |= HSMMC_HAS_HSPE_SUPPORT;
+ pdata->features |= HSMMC_HAS_HSPE_SUPPORT;
if (of_find_property(np, "keep-power-in-suspend", NULL))
- pdata->slots[0].pm_caps |= MMC_PM_KEEP_POWER;
+ pdata->pm_caps |= MMC_PM_KEEP_POWER;
if (of_find_property(np, "enable-sdio-wakeup", NULL))
- pdata->slots[0].pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
+ pdata->pm_caps |= MMC_PM_WAKE_SDIO_IRQ;
return pdata;
}
#else
-static inline struct omap_mmc_platform_data
+static inline struct omap_hsmmc_platform_data
*of_get_hsmmc_pdata(struct device *dev)
{
return ERR_PTR(-EINVAL);
@@ -2018,7 +2033,7 @@ static inline struct omap_mmc_platform_data
static int omap_hsmmc_probe(struct platform_device *pdev)
{
- struct omap_mmc_platform_data *pdata = pdev->dev.platform_data;
+ struct omap_hsmmc_platform_data *pdata = pdev->dev.platform_data;
struct mmc_host *mmc;
struct omap_hsmmc_host *host = NULL;
struct resource *res;
@@ -2048,11 +2063,6 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
return -ENXIO;
}
- if (pdata->nr_slots == 0) {
- dev_err(&pdev->dev, "No Slots\n");
- return -ENXIO;
- }
-
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
if (res == NULL || irq < 0)
@@ -2062,14 +2072,10 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
if (IS_ERR(base))
return PTR_ERR(base);
- ret = omap_hsmmc_gpio_init(pdata);
- if (ret)
- goto err;
-
mmc = mmc_alloc_host(sizeof(struct omap_hsmmc_host), &pdev->dev);
if (!mmc) {
ret = -ENOMEM;
- goto err_alloc;
+ goto err;
}
host = mmc_priv(mmc);
@@ -2079,13 +2085,16 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
host->use_dma = 1;
host->dma_ch = -1;
host->irq = irq;
- host->slot_id = 0;
host->mapbase = res->start + pdata->reg_offset;
host->base = base + pdata->reg_offset;
host->power_mode = MMC_POWER_OFF;
host->next_data.cookie = 1;
host->pbias_enabled = 0;
+ ret = omap_hsmmc_gpio_init(host, pdata);
+ if (ret)
+ goto err_gpio;
+
platform_set_drvdata(pdev, host);
if (pdev->dev.of_node)
@@ -2144,14 +2153,14 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc->caps |= MMC_CAP_MMC_HIGHSPEED | MMC_CAP_SD_HIGHSPEED |
MMC_CAP_WAIT_WHILE_BUSY | MMC_CAP_ERASE;
- mmc->caps |= mmc_slot(host).caps;
+ mmc->caps |= mmc_pdata(host)->caps;
if (mmc->caps & MMC_CAP_8_BIT_DATA)
mmc->caps |= MMC_CAP_4_BIT_DATA;
- if (mmc_slot(host).nonremovable)
+ if (mmc_pdata(host)->nonremovable)
mmc->caps |= MMC_CAP_NONREMOVABLE;
- mmc->pm_caps = mmc_slot(host).pm_caps;
+ mmc->pm_caps = mmc_pdata(host)->pm_caps;
omap_hsmmc_conf_bus_power(host);
@@ -2204,27 +2213,19 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
goto err_irq;
}
- if (pdata->init != NULL) {
- if (pdata->init(&pdev->dev) != 0) {
- dev_err(mmc_dev(host->mmc),
- "Unable to configure MMC IRQs\n");
- goto err_irq;
- }
- }
-
- if (omap_hsmmc_have_reg() && !mmc_slot(host).set_power) {
+ if (omap_hsmmc_have_reg() && !mmc_pdata(host)->set_power) {
ret = omap_hsmmc_reg_get(host);
if (ret)
- goto err_reg;
+ goto err_irq;
host->use_reg = 1;
}
- mmc->ocr_avail = mmc_slot(host).ocr_mask;
+ mmc->ocr_avail = mmc_pdata(host)->ocr_mask;
/* Request IRQ for card detect */
- if ((mmc_slot(host).card_detect_irq)) {
+ if (host->card_detect_irq) {
ret = devm_request_threaded_irq(&pdev->dev,
- mmc_slot(host).card_detect_irq,
+ host->card_detect_irq,
NULL, omap_hsmmc_detect,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
mmc_hostname(mmc), host);
@@ -2233,8 +2234,8 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
"Unable to grab MMC CD IRQ\n");
goto err_irq_cd;
}
- pdata->suspend = omap_hsmmc_suspend_cdirq;
- pdata->resume = omap_hsmmc_resume_cdirq;
+ host->suspend = omap_hsmmc_suspend_cdirq;
+ host->resume = omap_hsmmc_resume_cdirq;
}
omap_hsmmc_disable_irq(host);
@@ -2255,12 +2256,12 @@ static int omap_hsmmc_probe(struct platform_device *pdev)
mmc_add_host(mmc);
- if (mmc_slot(host).name != NULL) {
+ if (mmc_pdata(host)->name != NULL) {
ret = device_create_file(&mmc->class_dev, &dev_attr_slot_name);
if (ret < 0)
goto err_slot_name;
}
- if (mmc_slot(host).card_detect_irq && mmc_slot(host).get_cover_state) {
+ if (host->card_detect_irq && host->get_cover_state) {
ret = device_create_file(&mmc->class_dev,
&dev_attr_cover_switch);
if (ret < 0)
@@ -2278,9 +2279,6 @@ err_slot_name:
err_irq_cd:
if (host->use_reg)
omap_hsmmc_reg_put(host);
-err_reg:
- if (host->pdata->cleanup)
- host->pdata->cleanup(&pdev->dev);
err_irq:
if (host->tx_chan)
dma_release_channel(host->tx_chan);
@@ -2291,9 +2289,9 @@ err_irq:
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
err1:
+ omap_hsmmc_gpio_free(host, pdata);
+err_gpio:
mmc_free_host(mmc);
-err_alloc:
- omap_hsmmc_gpio_free(pdata);
err:
return ret;
}
@@ -2306,8 +2304,6 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
mmc_remove_host(host->mmc);
if (host->use_reg)
omap_hsmmc_reg_put(host);
- if (host->pdata->cleanup)
- host->pdata->cleanup(&pdev->dev);
if (host->tx_chan)
dma_release_channel(host->tx_chan);
@@ -2319,7 +2315,7 @@ static int omap_hsmmc_remove(struct platform_device *pdev)
if (host->dbclk)
clk_disable_unprepare(host->dbclk);
- omap_hsmmc_gpio_free(host->pdata);
+ omap_hsmmc_gpio_free(host, host->pdata);
mmc_free_host(host->mmc);
return 0;
@@ -2330,8 +2326,8 @@ static int omap_hsmmc_prepare(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- if (host->pdata->suspend)
- return host->pdata->suspend(dev, host->slot_id);
+ if (host->suspend)
+ return host->suspend(dev);
return 0;
}
@@ -2340,8 +2336,8 @@ static void omap_hsmmc_complete(struct device *dev)
{
struct omap_hsmmc_host *host = dev_get_drvdata(dev);
- if (host->pdata->resume)
- host->pdata->resume(dev, host->slot_id);
+ if (host->resume)
+ host->resume(dev);
}
diff --git a/drivers/mmc/host/sdhci-acpi.c b/drivers/mmc/host/sdhci-acpi.c
index 9cccc0e..c01eac7 100644
--- a/drivers/mmc/host/sdhci-acpi.c
+++ b/drivers/mmc/host/sdhci-acpi.c
@@ -76,6 +76,7 @@ struct sdhci_acpi_host {
const struct sdhci_acpi_slot *slot;
struct platform_device *pdev;
bool use_runtime_pm;
+ bool dma_setup;
};
static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
@@ -85,7 +86,29 @@ static inline bool sdhci_acpi_flag(struct sdhci_acpi_host *c, unsigned int flag)
static int sdhci_acpi_enable_dma(struct sdhci_host *host)
{
- return 0;
+ struct sdhci_acpi_host *c = sdhci_priv(host);
+ struct device *dev = &c->pdev->dev;
+ int err = -1;
+
+ if (c->dma_setup)
+ return 0;
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) {
+ host->flags &= ~SDHCI_USE_64_BIT_DMA;
+ } else {
+ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(64));
+ if (err)
+ dev_warn(dev, "Failed to set 64-bit DMA mask\n");
+ }
+ }
+
+ if (err)
+ err = dma_set_mask_and_coherent(dev, DMA_BIT_MASK(32));
+
+ c->dma_setup = !err;
+
+ return err;
}
static void sdhci_acpi_int_hw_reset(struct sdhci_host *host)
@@ -180,17 +203,21 @@ static int sdhci_acpi_sd_probe_slot(struct platform_device *pdev,
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_emmc = {
.chip = &sdhci_acpi_chip_int,
.caps = MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
- MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR,
+ MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
+ MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.caps2 = MMC_CAP2_HC_ERASE_SZ,
.flags = SDHCI_ACPI_RUNTIME_PM,
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN | SDHCI_QUIRK2_STOP_WITH_TC,
.probe_slot = sdhci_acpi_emmc_probe_slot,
};
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
- .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION,
+ .quirks = SDHCI_QUIRK_BROKEN_CARD_DETECTION |
+ SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON,
- .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD,
+ .caps = MMC_CAP_NONREMOVABLE | MMC_CAP_POWER_OFF_CARD |
+ MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.flags = SDHCI_ACPI_RUNTIME_PM,
.pm_caps = MMC_PM_KEEP_POWER,
.probe_slot = sdhci_acpi_sdio_probe_slot,
@@ -199,8 +226,10 @@ static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sdio = {
static const struct sdhci_acpi_slot sdhci_acpi_slot_int_sd = {
.flags = SDHCI_ACPI_SD_CD | SDHCI_ACPI_SD_CD_OVERRIDE_LEVEL |
SDHCI_ACPI_RUNTIME_PM,
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_STOP_WITH_TC,
+ .caps = MMC_CAP_BUS_WIDTH_TEST | MMC_CAP_WAIT_WHILE_BUSY,
.probe_slot = sdhci_acpi_sd_probe_slot,
};
@@ -305,21 +334,6 @@ static int sdhci_acpi_probe(struct platform_device *pdev)
goto err_free;
}
- if (!dev->dma_mask) {
- u64 dma_mask;
-
- if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT) {
- /* 64-bit DMA is not supported at present */
- dma_mask = DMA_BIT_MASK(32);
- } else {
- dma_mask = DMA_BIT_MASK(32);
- }
-
- err = dma_coerce_mask_and_coherent(dev, dma_mask);
- if (err)
- goto err_free;
- }
-
if (c->slot) {
if (c->slot->probe_slot) {
err = c->slot->probe_slot(pdev, hid, uid);
@@ -416,7 +430,7 @@ static int sdhci_acpi_resume(struct device *dev)
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sdhci_acpi_runtime_suspend(struct device *dev)
{
diff --git a/drivers/mmc/host/sdhci-esdhc-imx.c b/drivers/mmc/host/sdhci-esdhc-imx.c
index 587ee0e..af1f7c0 100644
--- a/drivers/mmc/host/sdhci-esdhc-imx.c
+++ b/drivers/mmc/host/sdhci-esdhc-imx.c
@@ -65,8 +65,6 @@
/* NOTE: the minimum valid tuning start tap for mx6sl is 1 */
#define ESDHC_TUNING_START_TAP 0x1
-#define ESDHC_TUNING_BLOCK_PATTERN_LEN 64
-
/* pinctrl state */
#define ESDHC_PINCTRL_STATE_100MHZ "state_100mhz"
#define ESDHC_PINCTRL_STATE_200MHZ "state_200mhz"
@@ -692,8 +690,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
/* FIXME: delay a bit for card to be ready for next tuning due to errors */
mdelay(1);
- /* This is balanced by the runtime put in sdhci_tasklet_finish */
- pm_runtime_get_sync(host->mmc->parent);
reg = readl(host->ioaddr + ESDHC_MIX_CTRL);
reg |= ESDHC_MIX_CTRL_EXE_TUNE | ESDHC_MIX_CTRL_SMPCLK_SEL |
ESDHC_MIX_CTRL_FBCLK_SEL;
@@ -704,54 +700,6 @@ static void esdhc_prepare_tuning(struct sdhci_host *host, u32 val)
val, readl(host->ioaddr + ESDHC_TUNE_CTRL_STATUS));
}
-static void esdhc_request_done(struct mmc_request *mrq)
-{
- complete(&mrq->completion);
-}
-
-static int esdhc_send_tuning_cmd(struct sdhci_host *host, u32 opcode,
- struct scatterlist *sg)
-{
- struct mmc_command cmd = {0};
- struct mmc_request mrq = {NULL};
- struct mmc_data data = {0};
-
- cmd.opcode = opcode;
- cmd.arg = 0;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = ESDHC_TUNING_BLOCK_PATTERN_LEN;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.sg = sg;
- data.sg_len = 1;
-
- mrq.cmd = &cmd;
- mrq.cmd->mrq = &mrq;
- mrq.data = &data;
- mrq.data->mrq = &mrq;
- mrq.cmd->data = mrq.data;
-
- mrq.done = esdhc_request_done;
- init_completion(&(mrq.completion));
-
- spin_lock_irq(&host->lock);
- host->mrq = &mrq;
-
- sdhci_send_command(host, mrq.cmd);
-
- spin_unlock_irq(&host->lock);
-
- wait_for_completion(&mrq.completion);
-
- if (cmd.error)
- return cmd.error;
- if (data.error)
- return data.error;
-
- return 0;
-}
-
static void esdhc_post_tuning(struct sdhci_host *host)
{
u32 reg;
@@ -763,21 +711,13 @@ static void esdhc_post_tuning(struct sdhci_host *host)
static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
{
- struct scatterlist sg;
- char *tuning_pattern;
int min, max, avg, ret;
- tuning_pattern = kmalloc(ESDHC_TUNING_BLOCK_PATTERN_LEN, GFP_KERNEL);
- if (!tuning_pattern)
- return -ENOMEM;
-
- sg_init_one(&sg, tuning_pattern, ESDHC_TUNING_BLOCK_PATTERN_LEN);
-
/* find the mininum delay first which can pass tuning */
min = ESDHC_TUNE_CTRL_MIN;
while (min < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, min);
- if (!esdhc_send_tuning_cmd(host, opcode, &sg))
+ if (!mmc_send_tuning(host->mmc))
break;
min += ESDHC_TUNE_CTRL_STEP;
}
@@ -786,7 +726,7 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
max = min + ESDHC_TUNE_CTRL_STEP;
while (max < ESDHC_TUNE_CTRL_MAX) {
esdhc_prepare_tuning(host, max);
- if (esdhc_send_tuning_cmd(host, opcode, &sg)) {
+ if (mmc_send_tuning(host->mmc)) {
max -= ESDHC_TUNE_CTRL_STEP;
break;
}
@@ -796,11 +736,9 @@ static int esdhc_executing_tuning(struct sdhci_host *host, u32 opcode)
/* use average delay to get the best timing */
avg = (min + max) / 2;
esdhc_prepare_tuning(host, avg);
- ret = esdhc_send_tuning_cmd(host, opcode, &sg);
+ ret = mmc_send_tuning(host->mmc);
esdhc_post_tuning(host);
- kfree(tuning_pattern);
-
dev_dbg(mmc_dev(host->mmc), "tunning %s at 0x%x ret %d\n",
ret ? "failed" : "passed", avg, ret);
@@ -1031,11 +969,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
imx_data->pins_default = pinctrl_lookup_state(imx_data->pinctrl,
PINCTRL_STATE_DEFAULT);
- if (IS_ERR(imx_data->pins_default)) {
- err = PTR_ERR(imx_data->pins_default);
- dev_err(mmc_dev(host->mmc), "could not get default state\n");
- goto disable_clk;
- }
+ if (IS_ERR(imx_data->pins_default))
+ dev_warn(mmc_dev(host->mmc), "could not get default state\n");
host->quirks |= SDHCI_QUIRK_BROKEN_TIMEOUT_VAL;
@@ -1123,7 +1058,8 @@ static int sdhci_esdhc_imx_probe(struct platform_device *pdev)
}
/* sdr50 and sdr104 needs work on 1.8v signal voltage */
- if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data)) {
+ if ((boarddata->support_vsel) && esdhc_is_usdhc(imx_data) &&
+ !IS_ERR(imx_data->pins_default)) {
imx_data->pins_100mhz = pinctrl_lookup_state(imx_data->pinctrl,
ESDHC_PINCTRL_STATE_100MHZ);
imx_data->pins_200mhz = pinctrl_lookup_state(imx_data->pinctrl,
@@ -1172,7 +1108,7 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
pm_runtime_dont_use_autosuspend(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- if (!IS_ENABLED(CONFIG_PM_RUNTIME)) {
+ if (!IS_ENABLED(CONFIG_PM)) {
clk_disable_unprepare(imx_data->clk_per);
clk_disable_unprepare(imx_data->clk_ipg);
clk_disable_unprepare(imx_data->clk_ahb);
@@ -1183,7 +1119,7 @@ static int sdhci_esdhc_imx_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sdhci_esdhc_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
diff --git a/drivers/mmc/host/sdhci-msm.c b/drivers/mmc/host/sdhci-msm.c
index 30804385..3d32ce8 100644
--- a/drivers/mmc/host/sdhci-msm.c
+++ b/drivers/mmc/host/sdhci-msm.c
@@ -339,9 +339,7 @@ static int msm_init_cm_dll(struct sdhci_host *host)
static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
{
int tuning_seq_cnt = 3;
- u8 phase, *data_buf, tuned_phases[16], tuned_phase_cnt = 0;
- const u8 *tuning_block_pattern = tuning_blk_pattern_4bit;
- int size = sizeof(tuning_blk_pattern_4bit);
+ u8 phase, tuned_phases[16], tuned_phase_cnt = 0;
int rc;
struct mmc_host *mmc = host->mmc;
struct mmc_ios ios = host->mmc->ios;
@@ -355,53 +353,21 @@ static int sdhci_msm_execute_tuning(struct sdhci_host *host, u32 opcode)
(ios.timing == MMC_TIMING_UHS_SDR104)))
return 0;
- if ((opcode == MMC_SEND_TUNING_BLOCK_HS200) &&
- (mmc->ios.bus_width == MMC_BUS_WIDTH_8)) {
- tuning_block_pattern = tuning_blk_pattern_8bit;
- size = sizeof(tuning_blk_pattern_8bit);
- }
-
- data_buf = kmalloc(size, GFP_KERNEL);
- if (!data_buf)
- return -ENOMEM;
-
retry:
/* First of all reset the tuning block */
rc = msm_init_cm_dll(host);
if (rc)
- goto out;
+ return rc;
phase = 0;
do {
- struct mmc_command cmd = { 0 };
- struct mmc_data data = { 0 };
- struct mmc_request mrq = {
- .cmd = &cmd,
- .data = &data
- };
- struct scatterlist sg;
-
/* Set the phase in delay line hw block */
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
- goto out;
+ return rc;
- cmd.opcode = opcode;
- cmd.flags = MMC_RSP_R1 | MMC_CMD_ADTC;
-
- data.blksz = size;
- data.blocks = 1;
- data.flags = MMC_DATA_READ;
- data.timeout_ns = NSEC_PER_SEC; /* 1 second */
-
- data.sg = &sg;
- data.sg_len = 1;
- sg_init_one(&sg, data_buf, size);
- memset(data_buf, 0, size);
- mmc_wait_for_req(mmc, &mrq);
-
- if (!cmd.error && !data.error &&
- !memcmp(data_buf, tuning_block_pattern, size)) {
+ rc = mmc_send_tuning(mmc);
+ if (!rc) {
/* Tuning is successful at this tuning point */
tuned_phases[tuned_phase_cnt++] = phase;
dev_dbg(mmc_dev(mmc), "%s: Found good phase = %d\n",
@@ -413,7 +379,7 @@ retry:
rc = msm_find_most_appropriate_phase(host, tuned_phases,
tuned_phase_cnt);
if (rc < 0)
- goto out;
+ return rc;
else
phase = rc;
@@ -423,7 +389,7 @@ retry:
*/
rc = msm_config_cm_dll_phase(host, phase);
if (rc)
- goto out;
+ return rc;
dev_dbg(mmc_dev(mmc), "%s: Setting the tuning phase to %d\n",
mmc_hostname(mmc), phase);
} else {
@@ -435,8 +401,6 @@ retry:
rc = -EIO;
}
-out:
- kfree(data_buf);
return rc;
}
diff --git a/drivers/mmc/host/sdhci-of-arasan.c b/drivers/mmc/host/sdhci-of-arasan.c
index 981d66e..bcb51e9 100644
--- a/drivers/mmc/host/sdhci-of-arasan.c
+++ b/drivers/mmc/host/sdhci-of-arasan.c
@@ -165,7 +165,6 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
host = sdhci_pltfm_init(pdev, &sdhci_arasan_pdata, 0);
if (IS_ERR(host)) {
ret = PTR_ERR(host);
- dev_err(&pdev->dev, "platform init failed (%u)\n", ret);
goto clk_disable_all;
}
@@ -175,10 +174,8 @@ static int sdhci_arasan_probe(struct platform_device *pdev)
pltfm_host->clk = clk_xin;
ret = sdhci_add_host(host);
- if (ret) {
- dev_err(&pdev->dev, "platform register failed (%u)\n", ret);
+ if (ret)
goto err_pltfm_free;
- }
return 0;
diff --git a/drivers/mmc/host/sdhci-pci-o2micro.c b/drivers/mmc/host/sdhci-pci-o2micro.c
index 5670e38..e2ec108d 100644
--- a/drivers/mmc/host/sdhci-pci-o2micro.c
+++ b/drivers/mmc/host/sdhci-pci-o2micro.c
@@ -127,8 +127,6 @@ void sdhci_pci_o2_fujin2_pci_init(struct sdhci_pci_chip *chip)
return;
scratch_32 &= ~((1 << 21) | (1 << 30));
- /* Set RTD3 function disabled */
- scratch_32 |= ((1 << 29) | (1 << 28));
pci_write_config_dword(chip->pdev, O2_SD_FUNC_REG3, scratch_32);
/* Set L1 Entrance Timer */
diff --git a/drivers/mmc/host/sdhci-pci.c b/drivers/mmc/host/sdhci-pci.c
index 6119297..0342775 100644
--- a/drivers/mmc/host/sdhci-pci.c
+++ b/drivers/mmc/host/sdhci-pci.c
@@ -134,7 +134,7 @@ static int pch_hc_probe_slot(struct sdhci_pci_slot *slot)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static irqreturn_t sdhci_pci_sd_cd(int irq, void *dev_id)
{
@@ -269,7 +269,9 @@ static void sdhci_pci_int_hw_reset(struct sdhci_host *host)
static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
{
slot->host->mmc->caps |= MMC_CAP_8_BIT_DATA | MMC_CAP_NONREMOVABLE |
- MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR;
+ MMC_CAP_HW_RESET | MMC_CAP_1_8V_DDR |
+ MMC_CAP_BUS_WIDTH_TEST |
+ MMC_CAP_WAIT_WHILE_BUSY;
slot->host->mmc->caps2 |= MMC_CAP2_HC_ERASE_SZ;
slot->hw_reset = sdhci_pci_int_hw_reset;
if (slot->chip->pdev->device == PCI_DEVICE_ID_INTEL_BSW_EMMC)
@@ -279,12 +281,16 @@ static int byt_emmc_probe_slot(struct sdhci_pci_slot *slot)
static int byt_sdio_probe_slot(struct sdhci_pci_slot *slot)
{
- slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE;
+ slot->host->mmc->caps |= MMC_CAP_POWER_OFF_CARD | MMC_CAP_NONREMOVABLE |
+ MMC_CAP_BUS_WIDTH_TEST |
+ MMC_CAP_WAIT_WHILE_BUSY;
return 0;
}
static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
{
+ slot->host->mmc->caps |= MMC_CAP_BUS_WIDTH_TEST |
+ MMC_CAP_WAIT_WHILE_BUSY;
slot->cd_con_id = NULL;
slot->cd_idx = 0;
slot->cd_override_level = true;
@@ -294,11 +300,13 @@ static int byt_sd_probe_slot(struct sdhci_pci_slot *slot)
static const struct sdhci_pci_fixes sdhci_intel_byt_emmc = {
.allow_runtime_pm = true,
.probe_slot = byt_emmc_probe_slot,
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC,
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_HOST_OFF_CARD_ON |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN,
.allow_runtime_pm = true,
@@ -306,6 +314,7 @@ static const struct sdhci_pci_fixes sdhci_intel_byt_sdio = {
};
static const struct sdhci_pci_fixes sdhci_intel_byt_sd = {
+ .quirks = SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC,
.quirks2 = SDHCI_QUIRK2_CARD_ON_NEEDS_BUS_ON |
SDHCI_QUIRK2_PRESET_VALUE_BROKEN |
SDHCI_QUIRK2_STOP_WITH_TC,
@@ -645,6 +654,25 @@ static const struct sdhci_pci_fixes sdhci_rtsx = {
.probe_slot = rtsx_probe_slot,
};
+static int amd_probe(struct sdhci_pci_chip *chip)
+{
+ struct pci_dev *smbus_dev;
+
+ smbus_dev = pci_get_device(PCI_VENDOR_ID_AMD,
+ PCI_DEVICE_ID_AMD_HUDSON2_SMBUS, NULL);
+
+ if (smbus_dev && (smbus_dev->revision < 0x51)) {
+ chip->quirks2 |= SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD;
+ chip->quirks2 |= SDHCI_QUIRK2_BROKEN_HS200;
+ }
+
+ return 0;
+}
+
+static const struct sdhci_pci_fixes sdhci_amd = {
+ .probe = amd_probe,
+};
+
static const struct pci_device_id pci_ids[] = {
{
.vendor = PCI_VENDOR_ID_RICOH,
@@ -1044,7 +1072,15 @@ static const struct pci_device_id pci_ids[] = {
.subdevice = PCI_ANY_ID,
.driver_data = (kernel_ulong_t)&sdhci_o2,
},
-
+ {
+ .vendor = PCI_VENDOR_ID_AMD,
+ .device = PCI_ANY_ID,
+ .class = PCI_CLASS_SYSTEM_SDHCI << 8,
+ .class_mask = 0xFFFF00,
+ .subvendor = PCI_ANY_ID,
+ .subdevice = PCI_ANY_ID,
+ .driver_data = (kernel_ulong_t)&sdhci_amd,
+ },
{ /* Generic SD host controller */
PCI_DEVICE_CLASS((PCI_CLASS_SYSTEM_SDHCI << 8), 0xFFFF00)
},
@@ -1064,7 +1100,7 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
{
struct sdhci_pci_slot *slot;
struct pci_dev *pdev;
- int ret;
+ int ret = -1;
slot = sdhci_priv(host);
pdev = slot->chip->pdev;
@@ -1076,7 +1112,17 @@ static int sdhci_pci_enable_dma(struct sdhci_host *host)
"doesn't fully claim to support it.\n");
}
- ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ if (host->quirks2 & SDHCI_QUIRK2_BROKEN_64_BIT_DMA) {
+ host->flags &= ~SDHCI_USE_64_BIT_DMA;
+ } else {
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ if (ret)
+ dev_warn(&pdev->dev, "Failed to set 64-bit DMA mask\n");
+ }
+ }
+ if (ret)
+ ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
if (ret)
return ret;
@@ -1230,15 +1276,6 @@ static int sdhci_pci_resume(struct device *dev)
return 0;
}
-#else /* CONFIG_PM */
-
-#define sdhci_pci_suspend NULL
-#define sdhci_pci_resume NULL
-
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
-
static int sdhci_pci_runtime_suspend(struct device *dev)
{
struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
@@ -1310,7 +1347,12 @@ static int sdhci_pci_runtime_idle(struct device *dev)
return 0;
}
-#endif
+#else /* CONFIG_PM */
+
+#define sdhci_pci_suspend NULL
+#define sdhci_pci_resume NULL
+
+#endif /* CONFIG_PM */
static const struct dev_pm_ops sdhci_pci_pm_ops = {
.suspend = sdhci_pci_suspend,
diff --git a/drivers/mmc/host/sdhci-pxav2.c b/drivers/mmc/host/sdhci-pxav2.c
index b4c23e9..f98008b 100644
--- a/drivers/mmc/host/sdhci-pxav2.c
+++ b/drivers/mmc/host/sdhci-pxav2.c
@@ -167,23 +167,17 @@ static int sdhci_pxav2_probe(struct platform_device *pdev)
struct sdhci_pxa_platdata *pdata = pdev->dev.platform_data;
struct device *dev = &pdev->dev;
struct sdhci_host *host = NULL;
- struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
int ret;
struct clk *clk;
- pxa = kzalloc(sizeof(struct sdhci_pxa), GFP_KERNEL);
- if (!pxa)
- return -ENOMEM;
-
host = sdhci_pltfm_init(pdev, NULL, 0);
- if (IS_ERR(host)) {
- kfree(pxa);
+ if (IS_ERR(host))
return PTR_ERR(host);
- }
+
pltfm_host = sdhci_priv(host);
- pltfm_host->priv = pxa;
+ pltfm_host->priv = NULL;
clk = clk_get(dev, "PXA-SDHCLK");
if (IS_ERR(clk)) {
@@ -238,7 +232,6 @@ err_add_host:
clk_put(clk);
err_clk_get:
sdhci_pltfm_free(pdev);
- kfree(pxa);
return ret;
}
@@ -246,14 +239,12 @@ static int sdhci_pxav2_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
- struct sdhci_pxa *pxa = pltfm_host->priv;
sdhci_remove_host(host, 1);
clk_disable_unprepare(pltfm_host->clk);
clk_put(pltfm_host->clk);
sdhci_pltfm_free(pdev);
- kfree(pxa);
return 0;
}
diff --git a/drivers/mmc/host/sdhci-pxav3.c b/drivers/mmc/host/sdhci-pxav3.c
index 5036d7d..4523887 100644
--- a/drivers/mmc/host/sdhci-pxav3.c
+++ b/drivers/mmc/host/sdhci-pxav3.c
@@ -58,6 +58,12 @@
#define SDCE_MISC_INT (1<<2)
#define SDCE_MISC_INT_EN (1<<1)
+struct sdhci_pxa {
+ struct clk *clk_core;
+ struct clk *clk_io;
+ u8 power_mode;
+};
+
/*
* These registers are relative to the second register region, for the
* MBus bridge.
@@ -211,6 +217,7 @@ static void pxav3_set_uhs_signaling(struct sdhci_host *host, unsigned int uhs)
case MMC_TIMING_UHS_SDR104:
ctrl_2 |= SDHCI_CTRL_UHS_SDR104 | SDHCI_CTRL_VDD_180;
break;
+ case MMC_TIMING_MMC_DDR52:
case MMC_TIMING_UHS_DDR50:
ctrl_2 |= SDHCI_CTRL_UHS_DDR50 | SDHCI_CTRL_VDD_180;
break;
@@ -283,9 +290,7 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
struct sdhci_host *host = NULL;
struct sdhci_pxa *pxa = NULL;
const struct of_device_id *match;
-
int ret;
- struct clk *clk;
pxa = devm_kzalloc(&pdev->dev, sizeof(struct sdhci_pxa), GFP_KERNEL);
if (!pxa)
@@ -305,14 +310,20 @@ static int sdhci_pxav3_probe(struct platform_device *pdev)
pltfm_host = sdhci_priv(host);
pltfm_host->priv = pxa;
- clk = devm_clk_get(dev, NULL);
- if (IS_ERR(clk)) {
+ pxa->clk_io = devm_clk_get(dev, "io");
+ if (IS_ERR(pxa->clk_io))
+ pxa->clk_io = devm_clk_get(dev, NULL);
+ if (IS_ERR(pxa->clk_io)) {
dev_err(dev, "failed to get io clock\n");
- ret = PTR_ERR(clk);
+ ret = PTR_ERR(pxa->clk_io);
goto err_clk_get;
}
- pltfm_host->clk = clk;
- clk_prepare_enable(clk);
+ pltfm_host->clk = pxa->clk_io;
+ clk_prepare_enable(pxa->clk_io);
+
+ pxa->clk_core = devm_clk_get(dev, "core");
+ if (!IS_ERR(pxa->clk_core))
+ clk_prepare_enable(pxa->clk_core);
/* enable 1/8V DDR capable */
host->mmc->caps |= MMC_CAP_1_8V_DDR;
@@ -385,7 +396,9 @@ err_add_host:
pm_runtime_disable(&pdev->dev);
err_of_parse:
err_cd_req:
- clk_disable_unprepare(clk);
+ clk_disable_unprepare(pxa->clk_io);
+ if (!IS_ERR(pxa->clk_core))
+ clk_disable_unprepare(pxa->clk_core);
err_clk_get:
err_mbus_win:
sdhci_pltfm_free(pdev);
@@ -396,12 +409,15 @@ static int sdhci_pxav3_remove(struct platform_device *pdev)
{
struct sdhci_host *host = platform_get_drvdata(pdev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_pxa *pxa = pltfm_host->priv;
pm_runtime_get_sync(&pdev->dev);
sdhci_remove_host(host, 1);
pm_runtime_disable(&pdev->dev);
- clk_disable_unprepare(pltfm_host->clk);
+ clk_disable_unprepare(pxa->clk_io);
+ if (!IS_ERR(pxa->clk_core))
+ clk_disable_unprepare(pxa->clk_core);
sdhci_pltfm_free(pdev);
@@ -436,20 +452,21 @@ static int sdhci_pxav3_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sdhci_pxav3_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_pxa *pxa = pltfm_host->priv;
unsigned long flags;
- if (pltfm_host->clk) {
- spin_lock_irqsave(&host->lock, flags);
- host->runtime_suspended = true;
- spin_unlock_irqrestore(&host->lock, flags);
+ spin_lock_irqsave(&host->lock, flags);
+ host->runtime_suspended = true;
+ spin_unlock_irqrestore(&host->lock, flags);
- clk_disable_unprepare(pltfm_host->clk);
- }
+ clk_disable_unprepare(pxa->clk_io);
+ if (!IS_ERR(pxa->clk_core))
+ clk_disable_unprepare(pxa->clk_core);
return 0;
}
@@ -458,15 +475,16 @@ static int sdhci_pxav3_runtime_resume(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
struct sdhci_pltfm_host *pltfm_host = sdhci_priv(host);
+ struct sdhci_pxa *pxa = pltfm_host->priv;
unsigned long flags;
- if (pltfm_host->clk) {
- clk_prepare_enable(pltfm_host->clk);
+ clk_prepare_enable(pxa->clk_io);
+ if (!IS_ERR(pxa->clk_core))
+ clk_prepare_enable(pxa->clk_core);
- spin_lock_irqsave(&host->lock, flags);
- host->runtime_suspended = false;
- spin_unlock_irqrestore(&host->lock, flags);
- }
+ spin_lock_irqsave(&host->lock, flags);
+ host->runtime_suspended = false;
+ spin_unlock_irqrestore(&host->lock, flags);
return 0;
}
diff --git a/drivers/mmc/host/sdhci-s3c.c b/drivers/mmc/host/sdhci-s3c.c
index 0ce6eb17..c45b893 100644
--- a/drivers/mmc/host/sdhci-s3c.c
+++ b/drivers/mmc/host/sdhci-s3c.c
@@ -300,6 +300,7 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
struct device *dev = &ourhost->pdev->dev;
unsigned long timeout;
u16 clk = 0;
+ int ret;
host->mmc->actual_clock = 0;
@@ -311,7 +312,12 @@ static void sdhci_cmu_set_clock(struct sdhci_host *host, unsigned int clock)
sdhci_s3c_set_clock(host, clock);
- clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
+ ret = clk_set_rate(ourhost->clk_bus[ourhost->cur_clk], clock);
+ if (ret != 0) {
+ dev_err(dev, "%s: failed to set clock rate %uHz\n",
+ mmc_hostname(host->mmc), clock);
+ return;
+ }
clk = SDHCI_CLOCK_INT_EN;
sdhci_writew(host, clk, SDHCI_CLOCK_CONTROL);
@@ -609,7 +615,7 @@ static int sdhci_s3c_probe(struct platform_device *pdev)
goto err_req_regs;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
if (pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_disable_unprepare(sc->clk_io);
#endif
@@ -635,7 +641,7 @@ static int sdhci_s3c_remove(struct platform_device *pdev)
if (sc->ext_cd_irq)
free_irq(sc->ext_cd_irq, sc);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
if (sc->pdata->cd_type != S3C_SDHCI_CD_INTERNAL)
clk_prepare_enable(sc->clk_io);
#endif
@@ -667,7 +673,7 @@ static int sdhci_s3c_resume(struct device *dev)
}
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sdhci_s3c_runtime_suspend(struct device *dev)
{
struct sdhci_host *host = dev_get_drvdata(dev);
diff --git a/drivers/mmc/host/sdhci.c b/drivers/mmc/host/sdhci.c
index ada1a3e..cbb245b 100644
--- a/drivers/mmc/host/sdhci.c
+++ b/drivers/mmc/host/sdhci.c
@@ -44,8 +44,6 @@
#define MAX_TUNING_LOOP 40
-#define ADMA_SIZE ((128 * 2 + 1) * 4)
-
static unsigned int debug_quirks = 0;
static unsigned int debug_quirks2;
@@ -56,7 +54,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode);
static void sdhci_tuning_timer(unsigned long data);
static void sdhci_enable_preset_value(struct sdhci_host *host, bool enable);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sdhci_runtime_pm_get(struct sdhci_host *host);
static int sdhci_runtime_pm_put(struct sdhci_host *host);
static void sdhci_runtime_pm_bus_on(struct sdhci_host *host);
@@ -119,10 +117,17 @@ static void sdhci_dumpregs(struct sdhci_host *host)
pr_debug(DRIVER_NAME ": Host ctl2: 0x%08x\n",
sdhci_readw(host, SDHCI_HOST_CONTROL2));
- if (host->flags & SDHCI_USE_ADMA)
- pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
- readl(host->ioaddr + SDHCI_ADMA_ERROR),
- readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+ if (host->flags & SDHCI_USE_ADMA) {
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x%08x\n",
+ readl(host->ioaddr + SDHCI_ADMA_ERROR),
+ readl(host->ioaddr + SDHCI_ADMA_ADDRESS_HI),
+ readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+ else
+ pr_debug(DRIVER_NAME ": ADMA Err: 0x%08x | ADMA Ptr: 0x%08x\n",
+ readl(host->ioaddr + SDHCI_ADMA_ERROR),
+ readl(host->ioaddr + SDHCI_ADMA_ADDRESS));
+ }
pr_debug(DRIVER_NAME ": ===========================================\n");
}
@@ -448,18 +453,26 @@ static void sdhci_kunmap_atomic(void *buffer, unsigned long *flags)
local_irq_restore(*flags);
}
-static void sdhci_set_adma_desc(u8 *desc, u32 addr, int len, unsigned cmd)
+static void sdhci_adma_write_desc(struct sdhci_host *host, void *desc,
+ dma_addr_t addr, int len, unsigned cmd)
{
- __le32 *dataddr = (__le32 __force *)(desc + 4);
- __le16 *cmdlen = (__le16 __force *)desc;
+ struct sdhci_adma2_64_desc *dma_desc = desc;
+
+ /* 32-bit and 64-bit descriptors have these members in same position */
+ dma_desc->cmd = cpu_to_le16(cmd);
+ dma_desc->len = cpu_to_le16(len);
+ dma_desc->addr_lo = cpu_to_le32((u32)addr);
- /* SDHCI specification says ADMA descriptors should be 4 byte
- * aligned, so using 16 or 32bit operations should be safe. */
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ dma_desc->addr_hi = cpu_to_le32((u64)addr >> 32);
+}
- cmdlen[0] = cpu_to_le16(cmd);
- cmdlen[1] = cpu_to_le16(len);
+static void sdhci_adma_mark_end(void *desc)
+{
+ struct sdhci_adma2_64_desc *dma_desc = desc;
- dataddr[0] = cpu_to_le32(addr);
+ /* 32-bit and 64-bit descriptors have 'cmd' in same position */
+ dma_desc->cmd |= cpu_to_le16(ADMA2_END);
}
static int sdhci_adma_table_pre(struct sdhci_host *host,
@@ -467,8 +480,8 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
{
int direction;
- u8 *desc;
- u8 *align;
+ void *desc;
+ void *align;
dma_addr_t addr;
dma_addr_t align_addr;
int len, offset;
@@ -489,17 +502,17 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
direction = DMA_TO_DEVICE;
host->align_addr = dma_map_single(mmc_dev(host->mmc),
- host->align_buffer, 128 * 4, direction);
+ host->align_buffer, host->align_buffer_sz, direction);
if (dma_mapping_error(mmc_dev(host->mmc), host->align_addr))
goto fail;
- BUG_ON(host->align_addr & 0x3);
+ BUG_ON(host->align_addr & host->align_mask);
host->sg_count = dma_map_sg(mmc_dev(host->mmc),
data->sg, data->sg_len, direction);
if (host->sg_count == 0)
goto unmap_align;
- desc = host->adma_desc;
+ desc = host->adma_table;
align = host->align_buffer;
align_addr = host->align_addr;
@@ -515,24 +528,27 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
* the (up to three) bytes that screw up the
* alignment.
*/
- offset = (4 - (addr & 0x3)) & 0x3;
+ offset = (host->align_sz - (addr & host->align_mask)) &
+ host->align_mask;
if (offset) {
if (data->flags & MMC_DATA_WRITE) {
buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
+ WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
+ (PAGE_SIZE - offset));
memcpy(align, buffer, offset);
sdhci_kunmap_atomic(buffer, &flags);
}
/* tran, valid */
- sdhci_set_adma_desc(desc, align_addr, offset, 0x21);
+ sdhci_adma_write_desc(host, desc, align_addr, offset,
+ ADMA2_TRAN_VALID);
BUG_ON(offset > 65536);
- align += 4;
- align_addr += 4;
+ align += host->align_sz;
+ align_addr += host->align_sz;
- desc += 8;
+ desc += host->desc_sz;
addr += offset;
len -= offset;
@@ -541,23 +557,23 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
BUG_ON(len > 65536);
/* tran, valid */
- sdhci_set_adma_desc(desc, addr, len, 0x21);
- desc += 8;
+ sdhci_adma_write_desc(host, desc, addr, len, ADMA2_TRAN_VALID);
+ desc += host->desc_sz;
/*
* If this triggers then we have a calculation bug
* somewhere. :/
*/
- WARN_ON((desc - host->adma_desc) > ADMA_SIZE);
+ WARN_ON((desc - host->adma_table) >= host->adma_table_sz);
}
if (host->quirks & SDHCI_QUIRK_NO_ENDATTR_IN_NOPDESC) {
/*
* Mark the last descriptor as the terminating descriptor
*/
- if (desc != host->adma_desc) {
- desc -= 8;
- desc[0] |= 0x2; /* end */
+ if (desc != host->adma_table) {
+ desc -= host->desc_sz;
+ sdhci_adma_mark_end(desc);
}
} else {
/*
@@ -565,7 +581,7 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/
/* nop, end, valid */
- sdhci_set_adma_desc(desc, 0, 0, 0x3);
+ sdhci_adma_write_desc(host, desc, 0, 0, ADMA2_NOP_END_VALID);
}
/*
@@ -573,14 +589,14 @@ static int sdhci_adma_table_pre(struct sdhci_host *host,
*/
if (data->flags & MMC_DATA_WRITE) {
dma_sync_single_for_device(mmc_dev(host->mmc),
- host->align_addr, 128 * 4, direction);
+ host->align_addr, host->align_buffer_sz, direction);
}
return 0;
unmap_align:
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ host->align_buffer_sz, direction);
fail:
return -EINVAL;
}
@@ -592,7 +608,7 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
struct scatterlist *sg;
int i, size;
- u8 *align;
+ void *align;
char *buffer;
unsigned long flags;
bool has_unaligned;
@@ -603,12 +619,12 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
direction = DMA_TO_DEVICE;
dma_unmap_single(mmc_dev(host->mmc), host->align_addr,
- 128 * 4, direction);
+ host->align_buffer_sz, direction);
/* Do a quick scan of the SG list for any unaligned mappings */
has_unaligned = false;
for_each_sg(data->sg, sg, host->sg_count, i)
- if (sg_dma_address(sg) & 3) {
+ if (sg_dma_address(sg) & host->align_mask) {
has_unaligned = true;
break;
}
@@ -620,15 +636,17 @@ static void sdhci_adma_table_post(struct sdhci_host *host,
align = host->align_buffer;
for_each_sg(data->sg, sg, host->sg_count, i) {
- if (sg_dma_address(sg) & 0x3) {
- size = 4 - (sg_dma_address(sg) & 0x3);
+ if (sg_dma_address(sg) & host->align_mask) {
+ size = host->align_sz -
+ (sg_dma_address(sg) & host->align_mask);
buffer = sdhci_kmap_atomic(sg, &flags);
- WARN_ON(((long)buffer & PAGE_MASK) > (PAGE_SIZE - 3));
+ WARN_ON(((long)buffer & (PAGE_SIZE - 1)) >
+ (PAGE_SIZE - size));
memcpy(buffer, align, size);
sdhci_kunmap_atomic(buffer, &flags);
- align += 4;
+ align += host->align_sz;
}
}
}
@@ -822,6 +840,10 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
} else {
sdhci_writel(host, host->adma_addr,
SDHCI_ADMA_ADDRESS);
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ sdhci_writel(host,
+ (u64)host->adma_addr >> 32,
+ SDHCI_ADMA_ADDRESS_HI);
}
} else {
int sg_cnt;
@@ -855,10 +877,14 @@ static void sdhci_prepare_data(struct sdhci_host *host, struct mmc_command *cmd)
ctrl = sdhci_readb(host, SDHCI_HOST_CONTROL);
ctrl &= ~SDHCI_CTRL_DMA_MASK;
if ((host->flags & SDHCI_REQ_USE_DMA) &&
- (host->flags & SDHCI_USE_ADMA))
- ctrl |= SDHCI_CTRL_ADMA32;
- else
+ (host->flags & SDHCI_USE_ADMA)) {
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ ctrl |= SDHCI_CTRL_ADMA64;
+ else
+ ctrl |= SDHCI_CTRL_ADMA32;
+ } else {
ctrl |= SDHCI_CTRL_SDMA;
+ }
sdhci_writeb(host, ctrl, SDHCI_HOST_CONTROL);
}
@@ -889,10 +915,15 @@ static void sdhci_set_transfer_mode(struct sdhci_host *host,
struct mmc_data *data = cmd->data;
if (data == NULL) {
+ if (host->quirks2 &
+ SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD) {
+ sdhci_writew(host, 0x0, SDHCI_TRANSFER_MODE);
+ } else {
/* clear Auto CMD settings for no data CMDs */
- mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
- sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
+ mode = sdhci_readw(host, SDHCI_TRANSFER_MODE);
+ sdhci_writew(host, mode & ~(SDHCI_TRNS_AUTO_CMD12 |
SDHCI_TRNS_AUTO_CMD23), SDHCI_TRANSFER_MODE);
+ }
return;
}
@@ -1117,6 +1148,9 @@ static u16 sdhci_get_preset_value(struct sdhci_host *host)
case MMC_TIMING_UHS_DDR50:
preset = sdhci_readw(host, SDHCI_PRESET_FOR_DDR50);
break;
+ case MMC_TIMING_MMC_HS400:
+ preset = sdhci_readw(host, SDHCI_PRESET_FOR_HS400);
+ break;
default:
pr_warn("%s: Invalid UHS-I mode selected\n",
mmc_hostname(host->mmc));
@@ -1444,6 +1478,8 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing)
else if ((timing == MMC_TIMING_UHS_DDR50) ||
(timing == MMC_TIMING_MMC_DDR52))
ctrl_2 |= SDHCI_CTRL_UHS_DDR50;
+ else if (timing == MMC_TIMING_MMC_HS400)
+ ctrl_2 |= SDHCI_CTRL_HS400; /* Non-standard */
sdhci_writew(host, ctrl_2, SDHCI_HOST_CONTROL2);
}
EXPORT_SYMBOL_GPL(sdhci_set_uhs_signaling);
@@ -1515,7 +1551,8 @@ static void sdhci_do_set_ios(struct sdhci_host *host, struct mmc_ios *ios)
u16 clk, ctrl_2;
/* In case of UHS-I modes, set High Speed Enable */
- if ((ios->timing == MMC_TIMING_MMC_HS200) ||
+ if ((ios->timing == MMC_TIMING_MMC_HS400) ||
+ (ios->timing == MMC_TIMING_MMC_HS200) ||
(ios->timing == MMC_TIMING_MMC_DDR52) ||
(ios->timing == MMC_TIMING_UHS_SDR50) ||
(ios->timing == MMC_TIMING_UHS_SDR104) ||
@@ -1862,6 +1899,7 @@ static int sdhci_execute_tuning(struct mmc_host *mmc, u32 opcode)
* tuning function has to be executed.
*/
switch (host->timing) {
+ case MMC_TIMING_MMC_HS400:
case MMC_TIMING_MMC_HS200:
case MMC_TIMING_UHS_SDR104:
break;
@@ -2144,9 +2182,10 @@ static void sdhci_tasklet_finish(unsigned long param)
*/
if (!(host->flags & SDHCI_DEVICE_DEAD) &&
((mrq->cmd && mrq->cmd->error) ||
- (mrq->data && (mrq->data->error ||
- (mrq->data->stop && mrq->data->stop->error))) ||
- (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
+ (mrq->sbc && mrq->sbc->error) ||
+ (mrq->data && ((mrq->data->error && !mrq->data->stop) ||
+ (mrq->data->stop && mrq->data->stop->error))) ||
+ (host->quirks & SDHCI_QUIRK_RESET_AFTER_REQUEST))) {
/* Some controllers need this kick or reset won't work here */
if (host->quirks & SDHCI_QUIRK_CLOCK_BEFORE_RESET)
@@ -2282,32 +2321,36 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask, u32 *mask)
}
#ifdef CONFIG_MMC_DEBUG
-static void sdhci_show_adma_error(struct sdhci_host *host)
+static void sdhci_adma_show_error(struct sdhci_host *host)
{
const char *name = mmc_hostname(host->mmc);
- u8 *desc = host->adma_desc;
- __le32 *dma;
- __le16 *len;
- u8 attr;
+ void *desc = host->adma_table;
sdhci_dumpregs(host);
while (true) {
- dma = (__le32 *)(desc + 4);
- len = (__le16 *)(desc + 2);
- attr = *desc;
-
- DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
- name, desc, le32_to_cpu(*dma), le16_to_cpu(*len), attr);
+ struct sdhci_adma2_64_desc *dma_desc = desc;
+
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ DBG("%s: %p: DMA 0x%08x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ name, desc, le32_to_cpu(dma_desc->addr_hi),
+ le32_to_cpu(dma_desc->addr_lo),
+ le16_to_cpu(dma_desc->len),
+ le16_to_cpu(dma_desc->cmd));
+ else
+ DBG("%s: %p: DMA 0x%08x, LEN 0x%04x, Attr=0x%02x\n",
+ name, desc, le32_to_cpu(dma_desc->addr_lo),
+ le16_to_cpu(dma_desc->len),
+ le16_to_cpu(dma_desc->cmd));
- desc += 8;
+ desc += host->desc_sz;
- if (attr & 2)
+ if (dma_desc->cmd & cpu_to_le16(ADMA2_END))
break;
}
}
#else
-static void sdhci_show_adma_error(struct sdhci_host *host) { }
+static void sdhci_adma_show_error(struct sdhci_host *host) { }
#endif
static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
@@ -2370,7 +2413,7 @@ static void sdhci_data_irq(struct sdhci_host *host, u32 intmask)
host->data->error = -EILSEQ;
else if (intmask & SDHCI_INT_ADMA_ERROR) {
pr_err("%s: ADMA error\n", mmc_hostname(host->mmc));
- sdhci_show_adma_error(host);
+ sdhci_adma_show_error(host);
host->data->error = -EIO;
if (host->ops->adma_workaround)
host->ops->adma_workaround(host, intmask);
@@ -2654,9 +2697,6 @@ int sdhci_resume_host(struct sdhci_host *host)
}
EXPORT_SYMBOL_GPL(sdhci_resume_host);
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
static int sdhci_runtime_pm_get(struct sdhci_host *host)
{
@@ -2757,7 +2797,7 @@ int sdhci_runtime_resume_host(struct sdhci_host *host)
}
EXPORT_SYMBOL_GPL(sdhci_runtime_resume_host);
-#endif
+#endif /* CONFIG_PM */
/*****************************************************************************\
* *
@@ -2849,6 +2889,16 @@ int sdhci_add_host(struct sdhci_host *host)
host->flags &= ~SDHCI_USE_ADMA;
}
+ /*
+ * It is assumed that a 64-bit capable device has set a 64-bit DMA mask
+ * and *must* do 64-bit DMA. A driver has the opportunity to change
+ * that during the first call to ->enable_dma(). Similarly
+ * SDHCI_QUIRK2_BROKEN_64_BIT_DMA must be left to the drivers to
+ * implement.
+ */
+ if (sdhci_readl(host, SDHCI_CAPABILITIES) & SDHCI_CAN_64BIT)
+ host->flags |= SDHCI_USE_64_BIT_DMA;
+
if (host->flags & (SDHCI_USE_SDMA | SDHCI_USE_ADMA)) {
if (host->ops->enable_dma) {
if (host->ops->enable_dma(host)) {
@@ -2860,33 +2910,56 @@ int sdhci_add_host(struct sdhci_host *host)
}
}
+ /* SDMA does not support 64-bit DMA */
+ if (host->flags & SDHCI_USE_64_BIT_DMA)
+ host->flags &= ~SDHCI_USE_SDMA;
+
if (host->flags & SDHCI_USE_ADMA) {
/*
- * We need to allocate descriptors for all sg entries
- * (128) and potentially one alignment transfer for
- * each of those entries.
+ * The DMA descriptor table size is calculated as the maximum
+ * number of segments times 2, to allow for an alignment
+ * descriptor for each segment, plus 1 for a nop end descriptor,
+ * all multipled by the descriptor size.
*/
- host->adma_desc = dma_alloc_coherent(mmc_dev(mmc),
- ADMA_SIZE, &host->adma_addr,
- GFP_KERNEL);
- host->align_buffer = kmalloc(128 * 4, GFP_KERNEL);
- if (!host->adma_desc || !host->align_buffer) {
- dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
- host->adma_desc, host->adma_addr);
+ if (host->flags & SDHCI_USE_64_BIT_DMA) {
+ host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
+ SDHCI_ADMA2_64_DESC_SZ;
+ host->align_buffer_sz = SDHCI_MAX_SEGS *
+ SDHCI_ADMA2_64_ALIGN;
+ host->desc_sz = SDHCI_ADMA2_64_DESC_SZ;
+ host->align_sz = SDHCI_ADMA2_64_ALIGN;
+ host->align_mask = SDHCI_ADMA2_64_ALIGN - 1;
+ } else {
+ host->adma_table_sz = (SDHCI_MAX_SEGS * 2 + 1) *
+ SDHCI_ADMA2_32_DESC_SZ;
+ host->align_buffer_sz = SDHCI_MAX_SEGS *
+ SDHCI_ADMA2_32_ALIGN;
+ host->desc_sz = SDHCI_ADMA2_32_DESC_SZ;
+ host->align_sz = SDHCI_ADMA2_32_ALIGN;
+ host->align_mask = SDHCI_ADMA2_32_ALIGN - 1;
+ }
+ host->adma_table = dma_alloc_coherent(mmc_dev(mmc),
+ host->adma_table_sz,
+ &host->adma_addr,
+ GFP_KERNEL);
+ host->align_buffer = kmalloc(host->align_buffer_sz, GFP_KERNEL);
+ if (!host->adma_table || !host->align_buffer) {
+ dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
+ host->adma_table, host->adma_addr);
kfree(host->align_buffer);
pr_warn("%s: Unable to allocate ADMA buffers - falling back to standard DMA\n",
mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA;
- host->adma_desc = NULL;
+ host->adma_table = NULL;
host->align_buffer = NULL;
- } else if (host->adma_addr & 3) {
+ } else if (host->adma_addr & host->align_mask) {
pr_warn("%s: unable to allocate aligned ADMA descriptor\n",
mmc_hostname(mmc));
host->flags &= ~SDHCI_USE_ADMA;
- dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
- host->adma_desc, host->adma_addr);
+ dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
+ host->adma_table, host->adma_addr);
kfree(host->align_buffer);
- host->adma_desc = NULL;
+ host->adma_table = NULL;
host->align_buffer = NULL;
}
}
@@ -3027,7 +3100,7 @@ int sdhci_add_host(struct sdhci_host *host)
if (ret) {
pr_warn("%s: Failed to enable vqmmc regulator: %d\n",
mmc_hostname(mmc), ret);
- mmc->supply.vqmmc = NULL;
+ mmc->supply.vqmmc = ERR_PTR(-EINVAL);
}
}
@@ -3046,16 +3119,21 @@ int sdhci_add_host(struct sdhci_host *host)
/* SD3.0: SDR104 is supported so (for eMMC) the caps2
* field can be promoted to support HS200.
*/
- if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200)) {
+ if (!(host->quirks2 & SDHCI_QUIRK2_BROKEN_HS200))
mmc->caps2 |= MMC_CAP2_HS200;
- if (IS_ERR(mmc->supply.vqmmc) ||
- !regulator_is_supported_voltage
- (mmc->supply.vqmmc, 1100000, 1300000))
- mmc->caps2 &= ~MMC_CAP2_HS200_1_2V_SDR;
- }
} else if (caps[1] & SDHCI_SUPPORT_SDR50)
mmc->caps |= MMC_CAP_UHS_SDR50;
+ if (host->quirks2 & SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 &&
+ (caps[1] & SDHCI_SUPPORT_HS400))
+ mmc->caps2 |= MMC_CAP2_HS400;
+
+ if ((mmc->caps2 & MMC_CAP2_HSX00_1_2V) &&
+ (IS_ERR(mmc->supply.vqmmc) ||
+ !regulator_is_supported_voltage(mmc->supply.vqmmc, 1100000,
+ 1300000)))
+ mmc->caps2 &= ~MMC_CAP2_HSX00_1_2V;
+
if ((caps[1] & SDHCI_SUPPORT_DDR50) &&
!(host->quirks2 & SDHCI_QUIRK2_BROKEN_DDR50))
mmc->caps |= MMC_CAP_UHS_DDR50;
@@ -3175,11 +3253,11 @@ int sdhci_add_host(struct sdhci_host *host)
* can do scatter/gather or not.
*/
if (host->flags & SDHCI_USE_ADMA)
- mmc->max_segs = 128;
+ mmc->max_segs = SDHCI_MAX_SEGS;
else if (host->flags & SDHCI_USE_SDMA)
mmc->max_segs = 1;
else /* PIO */
- mmc->max_segs = 128;
+ mmc->max_segs = SDHCI_MAX_SEGS;
/*
* Maximum number of sectors in one transfer. Limited by DMA boundary
@@ -3277,7 +3355,8 @@ int sdhci_add_host(struct sdhci_host *host)
pr_info("%s: SDHCI controller on %s [%s] using %s\n",
mmc_hostname(mmc), host->hw_name, dev_name(mmc_dev(mmc)),
- (host->flags & SDHCI_USE_ADMA) ? "ADMA" :
+ (host->flags & SDHCI_USE_ADMA) ?
+ (host->flags & SDHCI_USE_64_BIT_DMA) ? "ADMA 64-bit" : "ADMA" :
(host->flags & SDHCI_USE_SDMA) ? "DMA" : "PIO");
sdhci_enable_card_detection(host);
@@ -3339,18 +3418,15 @@ void sdhci_remove_host(struct sdhci_host *host, int dead)
tasklet_kill(&host->finish_tasklet);
- if (!IS_ERR(mmc->supply.vmmc))
- regulator_disable(mmc->supply.vmmc);
-
if (!IS_ERR(mmc->supply.vqmmc))
regulator_disable(mmc->supply.vqmmc);
- if (host->adma_desc)
- dma_free_coherent(mmc_dev(mmc), ADMA_SIZE,
- host->adma_desc, host->adma_addr);
+ if (host->adma_table)
+ dma_free_coherent(mmc_dev(mmc), host->adma_table_sz,
+ host->adma_table, host->adma_addr);
kfree(host->align_buffer);
- host->adma_desc = NULL;
+ host->adma_table = NULL;
host->align_buffer = NULL;
}
diff --git a/drivers/mmc/host/sdhci.h b/drivers/mmc/host/sdhci.h
index 31896a7..41a2c34 100644
--- a/drivers/mmc/host/sdhci.h
+++ b/drivers/mmc/host/sdhci.h
@@ -161,7 +161,7 @@
#define SDHCI_CTRL_UHS_SDR50 0x0002
#define SDHCI_CTRL_UHS_SDR104 0x0003
#define SDHCI_CTRL_UHS_DDR50 0x0004
-#define SDHCI_CTRL_HS_SDR200 0x0005 /* reserved value in SDIO spec */
+#define SDHCI_CTRL_HS400 0x0005 /* Non-standard */
#define SDHCI_CTRL_VDD_180 0x0008
#define SDHCI_CTRL_DRV_TYPE_MASK 0x0030
#define SDHCI_CTRL_DRV_TYPE_B 0x0000
@@ -204,6 +204,7 @@
#define SDHCI_RETUNING_MODE_SHIFT 14
#define SDHCI_CLOCK_MUL_MASK 0x00FF0000
#define SDHCI_CLOCK_MUL_SHIFT 16
+#define SDHCI_SUPPORT_HS400 0x80000000 /* Non-standard */
#define SDHCI_CAPABILITIES_1 0x44
@@ -227,6 +228,7 @@
/* 55-57 reserved */
#define SDHCI_ADMA_ADDRESS 0x58
+#define SDHCI_ADMA_ADDRESS_HI 0x5C
/* 60-FB reserved */
@@ -235,6 +237,7 @@
#define SDHCI_PRESET_FOR_SDR50 0x6A
#define SDHCI_PRESET_FOR_SDR104 0x6C
#define SDHCI_PRESET_FOR_DDR50 0x6E
+#define SDHCI_PRESET_FOR_HS400 0x74 /* Non-standard */
#define SDHCI_PRESET_DRV_MASK 0xC000
#define SDHCI_PRESET_DRV_SHIFT 14
#define SDHCI_PRESET_CLKGEN_SEL_MASK 0x400
@@ -266,6 +269,46 @@
#define SDHCI_DEFAULT_BOUNDARY_SIZE (512 * 1024)
#define SDHCI_DEFAULT_BOUNDARY_ARG (ilog2(SDHCI_DEFAULT_BOUNDARY_SIZE) - 12)
+/* ADMA2 32-bit DMA descriptor size */
+#define SDHCI_ADMA2_32_DESC_SZ 8
+
+/* ADMA2 32-bit DMA alignment */
+#define SDHCI_ADMA2_32_ALIGN 4
+
+/* ADMA2 32-bit descriptor */
+struct sdhci_adma2_32_desc {
+ __le16 cmd;
+ __le16 len;
+ __le32 addr;
+} __packed __aligned(SDHCI_ADMA2_32_ALIGN);
+
+/* ADMA2 64-bit DMA descriptor size */
+#define SDHCI_ADMA2_64_DESC_SZ 12
+
+/* ADMA2 64-bit DMA alignment */
+#define SDHCI_ADMA2_64_ALIGN 8
+
+/*
+ * ADMA2 64-bit descriptor. Note 12-byte descriptor can't always be 8-byte
+ * aligned.
+ */
+struct sdhci_adma2_64_desc {
+ __le16 cmd;
+ __le16 len;
+ __le32 addr_lo;
+ __le32 addr_hi;
+} __packed __aligned(4);
+
+#define ADMA2_TRAN_VALID 0x21
+#define ADMA2_NOP_END_VALID 0x3
+#define ADMA2_END 0x2
+
+/*
+ * Maximum segments assuming a 512KiB maximum requisition size and a minimum
+ * 4KiB page size.
+ */
+#define SDHCI_MAX_SEGS 128
+
struct sdhci_ops {
#ifdef CONFIG_MMC_SDHCI_IO_ACCESSORS
u32 (*read_l)(struct sdhci_host *host, int reg);
@@ -411,9 +454,6 @@ void sdhci_set_uhs_signaling(struct sdhci_host *host, unsigned timing);
extern int sdhci_suspend_host(struct sdhci_host *host);
extern int sdhci_resume_host(struct sdhci_host *host);
extern void sdhci_enable_irq_wakeups(struct sdhci_host *host);
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
extern int sdhci_runtime_suspend_host(struct sdhci_host *host);
extern int sdhci_runtime_resume_host(struct sdhci_host *host);
#endif
diff --git a/drivers/mmc/host/sh_mobile_sdhi.c b/drivers/mmc/host/sh_mobile_sdhi.c
index a2e81a1..00c8ebd 100644
--- a/drivers/mmc/host/sh_mobile_sdhi.c
+++ b/drivers/mmc/host/sh_mobile_sdhi.c
@@ -375,7 +375,7 @@ static int sh_mobile_sdhi_remove(struct platform_device *pdev)
static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pm_runtime_force_suspend,
pm_runtime_force_resume)
- SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
tmio_mmc_host_runtime_resume,
NULL)
};
diff --git a/drivers/mmc/host/sunxi-mmc.c b/drivers/mmc/host/sunxi-mmc.c
index d1663b3..15cb8b7 100644
--- a/drivers/mmc/host/sunxi-mmc.c
+++ b/drivers/mmc/host/sunxi-mmc.c
@@ -21,7 +21,6 @@
#include <linux/err.h>
#include <linux/clk.h>
-#include <linux/clk-private.h>
#include <linux/clk/sunxi.h>
#include <linux/gpio.h>
diff --git a/drivers/mmc/host/tmio_mmc.c b/drivers/mmc/host/tmio_mmc.c
index 659028d..2616fdf 100644
--- a/drivers/mmc/host/tmio_mmc.c
+++ b/drivers/mmc/host/tmio_mmc.c
@@ -135,7 +135,7 @@ static int tmio_mmc_remove(struct platform_device *pdev)
static const struct dev_pm_ops tmio_mmc_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(tmio_mmc_suspend, tmio_mmc_resume)
- SET_PM_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
+ SET_RUNTIME_PM_OPS(tmio_mmc_host_runtime_suspend,
tmio_mmc_host_runtime_resume,
NULL)
};
diff --git a/drivers/mmc/host/toshsd.c b/drivers/mmc/host/toshsd.c
new file mode 100644
index 0000000..4666262
--- /dev/null
+++ b/drivers/mmc/host/toshsd.c
@@ -0,0 +1,717 @@
+/*
+ * Toshiba PCI Secure Digital Host Controller Interface driver
+ *
+ * Copyright (C) 2014 Ondrej Zary
+ * Copyright (C) 2007 Richard Betts, All Rights Reserved.
+ *
+ * Based on asic3_mmc.c, copyright (c) 2005 SDG Systems, LLC and,
+ * sdhci.c, copyright (C) 2005-2006 Pierre Ossman
+ *
+ * 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/delay.h>
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/pm.h>
+#include <linux/mmc/host.h>
+#include <linux/mmc/mmc.h>
+
+#include "toshsd.h"
+
+#define DRIVER_NAME "toshsd"
+
+static const struct pci_device_id pci_ids[] = {
+ { PCI_DEVICE(PCI_VENDOR_ID_TOSHIBA, 0x0805) },
+ { /* end: all zeroes */ },
+};
+
+MODULE_DEVICE_TABLE(pci, pci_ids);
+
+static void toshsd_init(struct toshsd_host *host)
+{
+ /* enable clock */
+ pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP,
+ SD_PCICFG_CLKSTOP_ENABLE_ALL);
+ pci_write_config_byte(host->pdev, SD_PCICFG_CARDDETECT, 2);
+
+ /* reset */
+ iowrite16(0, host->ioaddr + SD_SOFTWARERESET); /* assert */
+ mdelay(2);
+ iowrite16(1, host->ioaddr + SD_SOFTWARERESET); /* deassert */
+ mdelay(2);
+
+ /* Clear card registers */
+ iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL);
+ iowrite32(0, host->ioaddr + SD_CARDSTATUS);
+ iowrite32(0, host->ioaddr + SD_ERRORSTATUS0);
+ iowrite16(0, host->ioaddr + SD_STOPINTERNAL);
+
+ /* SDIO clock? */
+ iowrite16(0x100, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL);
+
+ /* enable LED */
+ pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE1,
+ SD_PCICFG_LED_ENABLE1_START);
+ pci_write_config_byte(host->pdev, SD_PCICFG_SDLED_ENABLE2,
+ SD_PCICFG_LED_ENABLE2_START);
+
+ /* set interrupt masks */
+ iowrite32(~(u32)(SD_CARD_RESP_END | SD_CARD_RW_END
+ | SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0
+ | SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE
+ | SD_BUF_CMD_TIMEOUT),
+ host->ioaddr + SD_INTMASKCARD);
+
+ iowrite16(0x1000, host->ioaddr + SD_TRANSACTIONCTRL);
+}
+
+/* Set MMC clock / power.
+ * Note: This controller uses a simple divider scheme therefore it cannot run
+ * SD/MMC cards at full speed (24/20MHz). HCLK (=33MHz PCI clock?) is too high
+ * and the next slowest is 16MHz (div=2).
+ */
+static void __toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct toshsd_host *host = mmc_priv(mmc);
+
+ if (ios->clock) {
+ u16 clk;
+ int div = 1;
+
+ while (ios->clock < HCLK / div)
+ div *= 2;
+
+ clk = div >> 2;
+
+ if (div == 1) { /* disable the divider */
+ pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE,
+ SD_PCICFG_CLKMODE_DIV_DISABLE);
+ clk |= SD_CARDCLK_DIV_DISABLE;
+ } else
+ pci_write_config_byte(host->pdev, SD_PCICFG_CLKMODE, 0);
+
+ clk |= SD_CARDCLK_ENABLE_CLOCK;
+ iowrite16(clk, host->ioaddr + SD_CARDCLOCKCTRL);
+
+ mdelay(10);
+ } else
+ iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL);
+
+ switch (ios->power_mode) {
+ case MMC_POWER_OFF:
+ pci_write_config_byte(host->pdev, SD_PCICFG_POWER1,
+ SD_PCICFG_PWR1_OFF);
+ mdelay(1);
+ break;
+ case MMC_POWER_UP:
+ break;
+ case MMC_POWER_ON:
+ pci_write_config_byte(host->pdev, SD_PCICFG_POWER1,
+ SD_PCICFG_PWR1_33V);
+ pci_write_config_byte(host->pdev, SD_PCICFG_POWER2,
+ SD_PCICFG_PWR2_AUTO);
+ mdelay(20);
+ break;
+ }
+
+ switch (ios->bus_width) {
+ case MMC_BUS_WIDTH_1:
+ iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14)
+ | SD_CARDOPT_C2_MODULE_ABSENT
+ | SD_CARDOPT_DATA_XFR_WIDTH_1,
+ host->ioaddr + SD_CARDOPTIONSETUP);
+ break;
+ case MMC_BUS_WIDTH_4:
+ iowrite16(SD_CARDOPT_REQUIRED | SD_CARDOPT_DATA_RESP_TIMEOUT(14)
+ | SD_CARDOPT_C2_MODULE_ABSENT
+ | SD_CARDOPT_DATA_XFR_WIDTH_4,
+ host->ioaddr + SD_CARDOPTIONSETUP);
+ break;
+ }
+}
+
+static void toshsd_set_led(struct toshsd_host *host, unsigned char state)
+{
+ iowrite16(state, host->ioaddr + SDIO_BASE + SDIO_LEDCTRL);
+}
+
+static void toshsd_finish_request(struct toshsd_host *host)
+{
+ struct mmc_request *mrq = host->mrq;
+
+ /* Write something to end the command */
+ host->mrq = NULL;
+ host->cmd = NULL;
+ host->data = NULL;
+
+ toshsd_set_led(host, 0);
+ mmc_request_done(host->mmc, mrq);
+}
+
+static irqreturn_t toshsd_thread_irq(int irq, void *dev_id)
+{
+ struct toshsd_host *host = dev_id;
+ struct mmc_data *data = host->data;
+ struct sg_mapping_iter *sg_miter = &host->sg_miter;
+ unsigned short *buf;
+ int count;
+ unsigned long flags;
+
+ if (!data) {
+ dev_warn(&host->pdev->dev, "Spurious Data IRQ\n");
+ if (host->cmd) {
+ host->cmd->error = -EIO;
+ toshsd_finish_request(host);
+ }
+ return IRQ_NONE;
+ }
+ spin_lock_irqsave(&host->lock, flags);
+
+ if (!sg_miter_next(sg_miter))
+ return IRQ_HANDLED;
+ buf = sg_miter->addr;
+
+ /* Ensure we dont read more than one block. The chip will interrupt us
+ * When the next block is available.
+ */
+ count = sg_miter->length;
+ if (count > data->blksz)
+ count = data->blksz;
+
+ dev_dbg(&host->pdev->dev, "count: %08x, flags %08x\n", count,
+ data->flags);
+
+ /* Transfer the data */
+ if (data->flags & MMC_DATA_READ)
+ ioread32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2);
+ else
+ iowrite32_rep(host->ioaddr + SD_DATAPORT, buf, count >> 2);
+
+ sg_miter->consumed = count;
+ sg_miter_stop(sg_miter);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void toshsd_cmd_irq(struct toshsd_host *host)
+{
+ struct mmc_command *cmd = host->cmd;
+ u8 *buf;
+ u16 data;
+
+ if (!host->cmd) {
+ dev_warn(&host->pdev->dev, "Spurious CMD irq\n");
+ return;
+ }
+ buf = (u8 *)cmd->resp;
+ host->cmd = NULL;
+
+ if (cmd->flags & MMC_RSP_PRESENT && cmd->flags & MMC_RSP_136) {
+ /* R2 */
+ buf[12] = 0xff;
+ data = ioread16(host->ioaddr + SD_RESPONSE0);
+ buf[13] = data & 0xff;
+ buf[14] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE1);
+ buf[15] = data & 0xff;
+ buf[8] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE2);
+ buf[9] = data & 0xff;
+ buf[10] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE3);
+ buf[11] = data & 0xff;
+ buf[4] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE4);
+ buf[5] = data & 0xff;
+ buf[6] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE5);
+ buf[7] = data & 0xff;
+ buf[0] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE6);
+ buf[1] = data & 0xff;
+ buf[2] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE7);
+ buf[3] = data & 0xff;
+ } else if (cmd->flags & MMC_RSP_PRESENT) {
+ /* R1, R1B, R3, R6, R7 */
+ data = ioread16(host->ioaddr + SD_RESPONSE0);
+ buf[0] = data & 0xff;
+ buf[1] = data >> 8;
+ data = ioread16(host->ioaddr + SD_RESPONSE1);
+ buf[2] = data & 0xff;
+ buf[3] = data >> 8;
+ }
+
+ dev_dbg(&host->pdev->dev, "Command IRQ complete %d %d %x\n",
+ cmd->opcode, cmd->error, cmd->flags);
+
+ /* If there is data to handle we will
+ * finish the request in the mmc_data_end_irq handler.*/
+ if (host->data)
+ return;
+
+ toshsd_finish_request(host);
+}
+
+static void toshsd_data_end_irq(struct toshsd_host *host)
+{
+ struct mmc_data *data = host->data;
+
+ host->data = NULL;
+
+ if (!data) {
+ dev_warn(&host->pdev->dev, "Spurious data end IRQ\n");
+ return;
+ }
+
+ if (data->error == 0)
+ data->bytes_xfered = data->blocks * data->blksz;
+ else
+ data->bytes_xfered = 0;
+
+ dev_dbg(&host->pdev->dev, "Completed data request xfr=%d\n",
+ data->bytes_xfered);
+
+ iowrite16(0, host->ioaddr + SD_STOPINTERNAL);
+
+ toshsd_finish_request(host);
+}
+
+static irqreturn_t toshsd_irq(int irq, void *dev_id)
+{
+ struct toshsd_host *host = dev_id;
+ u32 int_reg, int_mask, int_status, detail;
+ int error = 0, ret = IRQ_HANDLED;
+
+ spin_lock(&host->lock);
+ int_status = ioread32(host->ioaddr + SD_CARDSTATUS);
+ int_mask = ioread32(host->ioaddr + SD_INTMASKCARD);
+ int_reg = int_status & ~int_mask & ~IRQ_DONT_CARE_BITS;
+
+ dev_dbg(&host->pdev->dev, "IRQ status:%x mask:%x\n",
+ int_status, int_mask);
+
+ /* nothing to do: it's not our IRQ */
+ if (!int_reg) {
+ ret = IRQ_NONE;
+ goto irq_end;
+ }
+
+ if (int_reg & SD_BUF_CMD_TIMEOUT) {
+ error = -ETIMEDOUT;
+ dev_dbg(&host->pdev->dev, "Timeout\n");
+ } else if (int_reg & SD_BUF_CRC_ERR) {
+ error = -EILSEQ;
+ dev_err(&host->pdev->dev, "BadCRC\n");
+ } else if (int_reg & (SD_BUF_ILLEGAL_ACCESS
+ | SD_BUF_CMD_INDEX_ERR
+ | SD_BUF_STOP_BIT_END_ERR
+ | SD_BUF_OVERFLOW
+ | SD_BUF_UNDERFLOW
+ | SD_BUF_DATA_TIMEOUT)) {
+ dev_err(&host->pdev->dev, "Buffer status error: { %s%s%s%s%s%s}\n",
+ int_reg & SD_BUF_ILLEGAL_ACCESS ? "ILLEGAL_ACC " : "",
+ int_reg & SD_BUF_CMD_INDEX_ERR ? "CMD_INDEX " : "",
+ int_reg & SD_BUF_STOP_BIT_END_ERR ? "STOPBIT_END " : "",
+ int_reg & SD_BUF_OVERFLOW ? "OVERFLOW " : "",
+ int_reg & SD_BUF_UNDERFLOW ? "UNDERFLOW " : "",
+ int_reg & SD_BUF_DATA_TIMEOUT ? "DATA_TIMEOUT " : "");
+
+ detail = ioread32(host->ioaddr + SD_ERRORSTATUS0);
+ dev_err(&host->pdev->dev, "detail error status { %s%s%s%s%s%s%s%s%s%s%s%s%s}\n",
+ detail & SD_ERR0_RESP_CMD_ERR ? "RESP_CMD " : "",
+ detail & SD_ERR0_RESP_NON_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "",
+ detail & SD_ERR0_RESP_CMD12_END_BIT_ERR ? "RESP_END_BIT " : "",
+ detail & SD_ERR0_READ_DATA_END_BIT_ERR ? "READ_DATA_END_BIT " : "",
+ detail & SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR ? "WRITE_CMD_END_BIT " : "",
+ detail & SD_ERR0_RESP_NON_CMD12_CRC_ERR ? "RESP_CRC " : "",
+ detail & SD_ERR0_RESP_CMD12_CRC_ERR ? "RESP_CRC " : "",
+ detail & SD_ERR0_READ_DATA_CRC_ERR ? "READ_DATA_CRC " : "",
+ detail & SD_ERR0_WRITE_CMD_CRC_ERR ? "WRITE_CMD_CRC " : "",
+ detail & SD_ERR1_NO_CMD_RESP ? "NO_CMD_RESP " : "",
+ detail & SD_ERR1_TIMEOUT_READ_DATA ? "READ_DATA_TIMEOUT " : "",
+ detail & SD_ERR1_TIMEOUT_CRS_STATUS ? "CRS_STATUS_TIMEOUT " : "",
+ detail & SD_ERR1_TIMEOUT_CRC_BUSY ? "CRC_BUSY_TIMEOUT " : "");
+ error = -EIO;
+ }
+
+ if (error) {
+ if (host->cmd)
+ host->cmd->error = error;
+
+ if (error == -ETIMEDOUT) {
+ iowrite32(int_status &
+ ~(SD_BUF_CMD_TIMEOUT | SD_CARD_RESP_END),
+ host->ioaddr + SD_CARDSTATUS);
+ } else {
+ toshsd_init(host);
+ __toshsd_set_ios(host->mmc, &host->mmc->ios);
+ goto irq_end;
+ }
+ }
+
+ /* Card insert/remove. The mmc controlling code is stateless. */
+ if (int_reg & (SD_CARD_CARD_INSERTED_0 | SD_CARD_CARD_REMOVED_0)) {
+ iowrite32(int_status &
+ ~(SD_CARD_CARD_REMOVED_0 | SD_CARD_CARD_INSERTED_0),
+ host->ioaddr + SD_CARDSTATUS);
+
+ if (int_reg & SD_CARD_CARD_INSERTED_0)
+ toshsd_init(host);
+
+ mmc_detect_change(host->mmc, 1);
+ }
+
+ /* Data transfer */
+ if (int_reg & (SD_BUF_READ_ENABLE | SD_BUF_WRITE_ENABLE)) {
+ iowrite32(int_status &
+ ~(SD_BUF_WRITE_ENABLE | SD_BUF_READ_ENABLE),
+ host->ioaddr + SD_CARDSTATUS);
+
+ ret = IRQ_WAKE_THREAD;
+ goto irq_end;
+ }
+
+ /* Command completion */
+ if (int_reg & SD_CARD_RESP_END) {
+ iowrite32(int_status & ~(SD_CARD_RESP_END),
+ host->ioaddr + SD_CARDSTATUS);
+ toshsd_cmd_irq(host);
+ }
+
+ /* Data transfer completion */
+ if (int_reg & SD_CARD_RW_END) {
+ iowrite32(int_status & ~(SD_CARD_RW_END),
+ host->ioaddr + SD_CARDSTATUS);
+ toshsd_data_end_irq(host);
+ }
+irq_end:
+ spin_unlock(&host->lock);
+ return ret;
+}
+
+static void toshsd_start_cmd(struct toshsd_host *host, struct mmc_command *cmd)
+{
+ struct mmc_data *data = host->data;
+ int c = cmd->opcode;
+
+ dev_dbg(&host->pdev->dev, "Command opcode: %d\n", cmd->opcode);
+
+ if (cmd->opcode == MMC_STOP_TRANSMISSION) {
+ iowrite16(SD_STOPINT_ISSUE_CMD12,
+ host->ioaddr + SD_STOPINTERNAL);
+
+ cmd->resp[0] = cmd->opcode;
+ cmd->resp[1] = 0;
+ cmd->resp[2] = 0;
+ cmd->resp[3] = 0;
+
+ toshsd_finish_request(host);
+ return;
+ }
+
+ switch (mmc_resp_type(cmd)) {
+ case MMC_RSP_NONE:
+ c |= SD_CMD_RESP_TYPE_NONE;
+ break;
+
+ case MMC_RSP_R1:
+ c |= SD_CMD_RESP_TYPE_EXT_R1;
+ break;
+ case MMC_RSP_R1B:
+ c |= SD_CMD_RESP_TYPE_EXT_R1B;
+ break;
+ case MMC_RSP_R2:
+ c |= SD_CMD_RESP_TYPE_EXT_R2;
+ break;
+ case MMC_RSP_R3:
+ c |= SD_CMD_RESP_TYPE_EXT_R3;
+ break;
+
+ default:
+ dev_err(&host->pdev->dev, "Unknown response type %d\n",
+ mmc_resp_type(cmd));
+ break;
+ }
+
+ host->cmd = cmd;
+
+ if (cmd->opcode == MMC_APP_CMD)
+ c |= SD_CMD_TYPE_ACMD;
+
+ if (cmd->opcode == MMC_GO_IDLE_STATE)
+ c |= (3 << 8); /* removed from ipaq-asic3.h for some reason */
+
+ if (data) {
+ c |= SD_CMD_DATA_PRESENT;
+
+ if (data->blocks > 1) {
+ iowrite16(SD_STOPINT_AUTO_ISSUE_CMD12,
+ host->ioaddr + SD_STOPINTERNAL);
+ c |= SD_CMD_MULTI_BLOCK;
+ }
+
+ if (data->flags & MMC_DATA_READ)
+ c |= SD_CMD_TRANSFER_READ;
+
+ /* MMC_DATA_WRITE does not require a bit to be set */
+ }
+
+ /* Send the command */
+ iowrite32(cmd->arg, host->ioaddr + SD_ARG0);
+ iowrite16(c, host->ioaddr + SD_CMD);
+}
+
+static void toshsd_start_data(struct toshsd_host *host, struct mmc_data *data)
+{
+ unsigned int flags = SG_MITER_ATOMIC;
+
+ dev_dbg(&host->pdev->dev, "setup data transfer: blocksize %08x nr_blocks %d, offset: %08x\n",
+ data->blksz, data->blocks, data->sg->offset);
+
+ host->data = data;
+
+ if (data->flags & MMC_DATA_READ)
+ flags |= SG_MITER_TO_SG;
+ else
+ flags |= SG_MITER_FROM_SG;
+
+ sg_miter_start(&host->sg_miter, data->sg, data->sg_len, flags);
+
+ /* Set transfer length and blocksize */
+ iowrite16(data->blocks, host->ioaddr + SD_BLOCKCOUNT);
+ iowrite16(data->blksz, host->ioaddr + SD_CARDXFERDATALEN);
+}
+
+/* Process requests from the MMC layer */
+static void toshsd_request(struct mmc_host *mmc, struct mmc_request *mrq)
+{
+ struct toshsd_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ /* abort if card not present */
+ if (!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0)) {
+ mrq->cmd->error = -ENOMEDIUM;
+ mmc_request_done(mmc, mrq);
+ return;
+ }
+
+ spin_lock_irqsave(&host->lock, flags);
+
+ WARN_ON(host->mrq != NULL);
+
+ host->mrq = mrq;
+
+ if (mrq->data)
+ toshsd_start_data(host, mrq->data);
+
+ toshsd_set_led(host, 1);
+
+ toshsd_start_cmd(host, mrq->cmd);
+
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static void toshsd_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
+{
+ struct toshsd_host *host = mmc_priv(mmc);
+ unsigned long flags;
+
+ spin_lock_irqsave(&host->lock, flags);
+ __toshsd_set_ios(mmc, ios);
+ spin_unlock_irqrestore(&host->lock, flags);
+}
+
+static int toshsd_get_ro(struct mmc_host *mmc)
+{
+ struct toshsd_host *host = mmc_priv(mmc);
+
+ /* active low */
+ return !(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_WRITE_PROTECT);
+}
+
+static int toshsd_get_cd(struct mmc_host *mmc)
+{
+ struct toshsd_host *host = mmc_priv(mmc);
+
+ return !!(ioread16(host->ioaddr + SD_CARDSTATUS) & SD_CARD_PRESENT_0);
+}
+
+static struct mmc_host_ops toshsd_ops = {
+ .request = toshsd_request,
+ .set_ios = toshsd_set_ios,
+ .get_ro = toshsd_get_ro,
+ .get_cd = toshsd_get_cd,
+};
+
+
+static void toshsd_powerdown(struct toshsd_host *host)
+{
+ /* mask all interrupts */
+ iowrite32(0xffffffff, host->ioaddr + SD_INTMASKCARD);
+ /* disable card clock */
+ iowrite16(0x000, host->ioaddr + SDIO_BASE + SDIO_CLOCKNWAITCTRL);
+ iowrite16(0, host->ioaddr + SD_CARDCLOCKCTRL);
+ /* power down card */
+ pci_write_config_byte(host->pdev, SD_PCICFG_POWER1, SD_PCICFG_PWR1_OFF);
+ /* disable clock */
+ pci_write_config_byte(host->pdev, SD_PCICFG_CLKSTOP, 0);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int toshsd_pm_suspend(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct toshsd_host *host = pci_get_drvdata(pdev);
+
+ toshsd_powerdown(host);
+
+ pci_save_state(pdev);
+ pci_enable_wake(pdev, PCI_D3hot, 0);
+ pci_disable_device(pdev);
+ pci_set_power_state(pdev, PCI_D3hot);
+
+ return 0;
+}
+
+static int toshsd_pm_resume(struct device *dev)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ struct toshsd_host *host = pci_get_drvdata(pdev);
+ int ret;
+
+ pci_set_power_state(pdev, PCI_D0);
+ pci_restore_state(pdev);
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ toshsd_init(host);
+
+ return 0;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static int toshsd_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ret;
+ struct toshsd_host *host;
+ struct mmc_host *mmc;
+ resource_size_t base;
+
+ ret = pci_enable_device(pdev);
+ if (ret)
+ return ret;
+
+ mmc = mmc_alloc_host(sizeof(struct toshsd_host), &pdev->dev);
+ if (!mmc) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ host = mmc_priv(mmc);
+ host->mmc = mmc;
+
+ host->pdev = pdev;
+ pci_set_drvdata(pdev, host);
+
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret)
+ goto free;
+
+ host->ioaddr = pci_iomap(pdev, 0, 0);
+ if (!host->ioaddr) {
+ ret = -ENOMEM;
+ goto release;
+ }
+
+ /* Set MMC host parameters */
+ mmc->ops = &toshsd_ops;
+ mmc->caps = MMC_CAP_4_BIT_DATA;
+ mmc->ocr_avail = MMC_VDD_32_33;
+
+ mmc->f_min = HCLK / 512;
+ mmc->f_max = HCLK;
+
+ spin_lock_init(&host->lock);
+
+ toshsd_init(host);
+
+ ret = request_threaded_irq(pdev->irq, toshsd_irq, toshsd_thread_irq,
+ IRQF_SHARED, DRIVER_NAME, host);
+ if (ret)
+ goto unmap;
+
+ mmc_add_host(mmc);
+
+ base = pci_resource_start(pdev, 0);
+ dev_dbg(&pdev->dev, "MMIO %pa, IRQ %d\n", &base, pdev->irq);
+
+ pm_suspend_ignore_children(&pdev->dev, 1);
+
+ return 0;
+
+unmap:
+ pci_iounmap(pdev, host->ioaddr);
+release:
+ pci_release_regions(pdev);
+free:
+ mmc_free_host(mmc);
+ pci_set_drvdata(pdev, NULL);
+err:
+ pci_disable_device(pdev);
+ return ret;
+}
+
+static void toshsd_remove(struct pci_dev *pdev)
+{
+ struct toshsd_host *host = pci_get_drvdata(pdev);
+
+ mmc_remove_host(host->mmc);
+ toshsd_powerdown(host);
+ free_irq(pdev->irq, host);
+ pci_iounmap(pdev, host->ioaddr);
+ pci_release_regions(pdev);
+ mmc_free_host(host->mmc);
+ pci_set_drvdata(pdev, NULL);
+ pci_disable_device(pdev);
+}
+
+static const struct dev_pm_ops toshsd_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(toshsd_pm_suspend, toshsd_pm_resume)
+};
+
+static struct pci_driver toshsd_driver = {
+ .name = DRIVER_NAME,
+ .id_table = pci_ids,
+ .probe = toshsd_probe,
+ .remove = toshsd_remove,
+ .driver.pm = &toshsd_pm_ops,
+};
+
+static int __init toshsd_drv_init(void)
+{
+ return pci_register_driver(&toshsd_driver);
+}
+
+static void __exit toshsd_drv_exit(void)
+{
+ pci_unregister_driver(&toshsd_driver);
+}
+
+module_init(toshsd_drv_init);
+module_exit(toshsd_drv_exit);
+
+MODULE_AUTHOR("Ondrej Zary, Richard Betts");
+MODULE_DESCRIPTION("Toshiba PCI Secure Digital Host Controller Interface driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/mmc/host/toshsd.h b/drivers/mmc/host/toshsd.h
new file mode 100644
index 0000000..b6c0d89
--- /dev/null
+++ b/drivers/mmc/host/toshsd.h
@@ -0,0 +1,176 @@
+/*
+ * Toshiba PCI Secure Digital Host Controller Interface driver
+ *
+ * Copyright (C) 2014 Ondrej Zary
+ * Copyright (C) 2007 Richard Betts, All Rights Reserved.
+ *
+ * Based on asic3_mmc.c Copyright (c) 2005 SDG Systems, LLC
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or (at
+ * your option) any later version.
+ */
+
+#define HCLK 33000000 /* 33 MHz (PCI clock) */
+
+#define SD_PCICFG_CLKSTOP 0x40 /* 0x1f = clock controller, 0 = stop */
+#define SD_PCICFG_GATEDCLK 0x41 /* Gated clock */
+#define SD_PCICFG_CLKMODE 0x42 /* Control clock of SD controller */
+#define SD_PCICFG_PINSTATUS 0x44 /* R/O: read status of SD pins */
+#define SD_PCICFG_POWER1 0x48
+#define SD_PCICFG_POWER2 0x49
+#define SD_PCICFG_POWER3 0x4a
+#define SD_PCICFG_CARDDETECT 0x4c
+#define SD_PCICFG_SLOTS 0x50 /* R/O: define support slot number */
+#define SD_PCICFG_EXTGATECLK1 0xf0 /* Could be used for gated clock */
+#define SD_PCICFG_EXTGATECLK2 0xf1 /* Could be used for gated clock */
+#define SD_PCICFG_EXTGATECLK3 0xf9 /* Bit 1: double buffer/single buffer */
+#define SD_PCICFG_SDLED_ENABLE1 0xfa
+#define SD_PCICFG_SDLED_ENABLE2 0xfe
+
+#define SD_PCICFG_CLKMODE_DIV_DISABLE BIT(0)
+#define SD_PCICFG_CLKSTOP_ENABLE_ALL 0x1f
+#define SD_PCICFG_LED_ENABLE1_START 0x12
+#define SD_PCICFG_LED_ENABLE2_START 0x80
+
+#define SD_PCICFG_PWR1_33V 0x08 /* Set for 3.3 volts */
+#define SD_PCICFG_PWR1_OFF 0x00 /* Turn off power */
+#define SD_PCICFG_PWR2_AUTO 0x02
+
+#define SD_CMD 0x00 /* also for SDIO */
+#define SD_ARG0 0x04 /* also for SDIO */
+#define SD_ARG1 0x06 /* also for SDIO */
+#define SD_STOPINTERNAL 0x08
+#define SD_BLOCKCOUNT 0x0a /* also for SDIO */
+#define SD_RESPONSE0 0x0c /* also for SDIO */
+#define SD_RESPONSE1 0x0e /* also for SDIO */
+#define SD_RESPONSE2 0x10 /* also for SDIO */
+#define SD_RESPONSE3 0x12 /* also for SDIO */
+#define SD_RESPONSE4 0x14 /* also for SDIO */
+#define SD_RESPONSE5 0x16 /* also for SDIO */
+#define SD_RESPONSE6 0x18 /* also for SDIO */
+#define SD_RESPONSE7 0x1a /* also for SDIO */
+#define SD_CARDSTATUS 0x1c /* also for SDIO */
+#define SD_BUFFERCTRL 0x1e /* also for SDIO */
+#define SD_INTMASKCARD 0x20 /* also for SDIO */
+#define SD_INTMASKBUFFER 0x22 /* also for SDIO */
+#define SD_CARDCLOCKCTRL 0x24
+#define SD_CARDXFERDATALEN 0x26 /* also for SDIO */
+#define SD_CARDOPTIONSETUP 0x28 /* also for SDIO */
+#define SD_ERRORSTATUS0 0x2c /* also for SDIO */
+#define SD_ERRORSTATUS1 0x2e /* also for SDIO */
+#define SD_DATAPORT 0x30 /* also for SDIO */
+#define SD_TRANSACTIONCTRL 0x34 /* also for SDIO */
+#define SD_SOFTWARERESET 0xe0 /* also for SDIO */
+
+/* registers above marked "also for SDIO" and all SDIO registers below can be
+ * accessed at SDIO_BASE + reg address */
+#define SDIO_BASE 0x100
+
+#define SDIO_CARDPORTSEL 0x02
+#define SDIO_CARDINTCTRL 0x36
+#define SDIO_CLOCKNWAITCTRL 0x38
+#define SDIO_HOSTINFORMATION 0x3a
+#define SDIO_ERRORCTRL 0x3c
+#define SDIO_LEDCTRL 0x3e
+
+#define SD_TRANSCTL_SET BIT(8)
+
+#define SD_CARDCLK_DIV_DISABLE BIT(15)
+#define SD_CARDCLK_ENABLE_CLOCK BIT(8)
+#define SD_CARDCLK_CLK_DIV_512 BIT(7)
+#define SD_CARDCLK_CLK_DIV_256 BIT(6)
+#define SD_CARDCLK_CLK_DIV_128 BIT(5)
+#define SD_CARDCLK_CLK_DIV_64 BIT(4)
+#define SD_CARDCLK_CLK_DIV_32 BIT(3)
+#define SD_CARDCLK_CLK_DIV_16 BIT(2)
+#define SD_CARDCLK_CLK_DIV_8 BIT(1)
+#define SD_CARDCLK_CLK_DIV_4 BIT(0)
+#define SD_CARDCLK_CLK_DIV_2 0
+
+#define SD_CARDOPT_REQUIRED 0x000e
+#define SD_CARDOPT_DATA_RESP_TIMEOUT(x) (((x) & 0x0f) << 4) /* 4 bits */
+#define SD_CARDOPT_C2_MODULE_ABSENT BIT(14)
+#define SD_CARDOPT_DATA_XFR_WIDTH_1 (1 << 15)
+#define SD_CARDOPT_DATA_XFR_WIDTH_4 (0 << 15)
+
+#define SD_CMD_TYPE_CMD (0 << 6)
+#define SD_CMD_TYPE_ACMD (1 << 6)
+#define SD_CMD_TYPE_AUTHEN (2 << 6)
+#define SD_CMD_RESP_TYPE_NONE (3 << 8)
+#define SD_CMD_RESP_TYPE_EXT_R1 (4 << 8)
+#define SD_CMD_RESP_TYPE_EXT_R1B (5 << 8)
+#define SD_CMD_RESP_TYPE_EXT_R2 (6 << 8)
+#define SD_CMD_RESP_TYPE_EXT_R3 (7 << 8)
+#define SD_CMD_RESP_TYPE_EXT_R6 (4 << 8)
+#define SD_CMD_RESP_TYPE_EXT_R7 (4 << 8)
+#define SD_CMD_DATA_PRESENT BIT(11)
+#define SD_CMD_TRANSFER_READ BIT(12)
+#define SD_CMD_MULTI_BLOCK BIT(13)
+#define SD_CMD_SECURITY_CMD BIT(14)
+
+#define SD_STOPINT_ISSUE_CMD12 BIT(0)
+#define SD_STOPINT_AUTO_ISSUE_CMD12 BIT(8)
+
+#define SD_CARD_RESP_END BIT(0)
+#define SD_CARD_RW_END BIT(2)
+#define SD_CARD_CARD_REMOVED_0 BIT(3)
+#define SD_CARD_CARD_INSERTED_0 BIT(4)
+#define SD_CARD_PRESENT_0 BIT(5)
+#define SD_CARD_UNK6 BIT(6)
+#define SD_CARD_WRITE_PROTECT BIT(7)
+#define SD_CARD_CARD_REMOVED_3 BIT(8)
+#define SD_CARD_CARD_INSERTED_3 BIT(9)
+#define SD_CARD_PRESENT_3 BIT(10)
+
+#define SD_BUF_CMD_INDEX_ERR BIT(16)
+#define SD_BUF_CRC_ERR BIT(17)
+#define SD_BUF_STOP_BIT_END_ERR BIT(18)
+#define SD_BUF_DATA_TIMEOUT BIT(19)
+#define SD_BUF_OVERFLOW BIT(20)
+#define SD_BUF_UNDERFLOW BIT(21)
+#define SD_BUF_CMD_TIMEOUT BIT(22)
+#define SD_BUF_UNK7 BIT(23)
+#define SD_BUF_READ_ENABLE BIT(24)
+#define SD_BUF_WRITE_ENABLE BIT(25)
+#define SD_BUF_ILLEGAL_FUNCTION BIT(29)
+#define SD_BUF_CMD_BUSY BIT(30)
+#define SD_BUF_ILLEGAL_ACCESS BIT(31)
+
+#define SD_ERR0_RESP_CMD_ERR BIT(0)
+#define SD_ERR0_RESP_NON_CMD12_END_BIT_ERR BIT(2)
+#define SD_ERR0_RESP_CMD12_END_BIT_ERR BIT(3)
+#define SD_ERR0_READ_DATA_END_BIT_ERR BIT(4)
+#define SD_ERR0_WRITE_CRC_STATUS_END_BIT_ERR BIT(5)
+#define SD_ERR0_RESP_NON_CMD12_CRC_ERR BIT(8)
+#define SD_ERR0_RESP_CMD12_CRC_ERR BIT(9)
+#define SD_ERR0_READ_DATA_CRC_ERR BIT(10)
+#define SD_ERR0_WRITE_CMD_CRC_ERR BIT(11)
+
+#define SD_ERR1_NO_CMD_RESP BIT(16)
+#define SD_ERR1_TIMEOUT_READ_DATA BIT(20)
+#define SD_ERR1_TIMEOUT_CRS_STATUS BIT(21)
+#define SD_ERR1_TIMEOUT_CRC_BUSY BIT(22)
+
+#define IRQ_DONT_CARE_BITS (SD_CARD_PRESENT_3 \
+ | SD_CARD_WRITE_PROTECT \
+ | SD_CARD_UNK6 \
+ | SD_CARD_PRESENT_0 \
+ | SD_BUF_UNK7 \
+ | SD_BUF_CMD_BUSY)
+
+struct toshsd_host {
+ struct pci_dev *pdev;
+ struct mmc_host *mmc;
+
+ spinlock_t lock;
+
+ struct mmc_request *mrq;/* Current request */
+ struct mmc_command *cmd;/* Current command */
+ struct mmc_data *data; /* Current data request */
+
+ struct sg_mapping_iter sg_miter; /* for PIO */
+
+ void __iomem *ioaddr; /* mapped address */
+};
diff --git a/drivers/net/ethernet/cadence/Kconfig b/drivers/net/ethernet/cadence/Kconfig
index 6932be0..321d2ad 100644
--- a/drivers/net/ethernet/cadence/Kconfig
+++ b/drivers/net/ethernet/cadence/Kconfig
@@ -22,7 +22,7 @@ if NET_CADENCE
config ARM_AT91_ETHER
tristate "AT91RM9200 Ethernet support"
- depends on HAS_DMA && (ARCH_AT91RM9200 || COMPILE_TEST)
+ depends on HAS_DMA && (ARCH_AT91 || COMPILE_TEST)
select MACB
---help---
If you wish to compile a kernel for the AT91RM9200 and enable
diff --git a/drivers/net/ethernet/intel/e1000e/netdev.c b/drivers/net/ethernet/intel/e1000e/netdev.c
index 5c82c80..e14fd85 100644
--- a/drivers/net/ethernet/intel/e1000e/netdev.c
+++ b/drivers/net/ethernet/intel/e1000e/netdev.c
@@ -6365,7 +6365,6 @@ static int e1000e_pm_resume(struct device *dev)
}
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
static int e1000e_pm_runtime_idle(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -6425,7 +6424,6 @@ static int e1000e_pm_runtime_suspend(struct device *dev)
return 0;
}
-#endif /* CONFIG_PM_RUNTIME */
#endif /* CONFIG_PM */
static void e1000_shutdown(struct pci_dev *pdev)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 485d2c6..2e526d4 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -186,11 +186,9 @@ static int igb_pci_enable_sriov(struct pci_dev *dev, int num_vfs);
static int igb_suspend(struct device *);
#endif
static int igb_resume(struct device *);
-#ifdef CONFIG_PM_RUNTIME
static int igb_runtime_suspend(struct device *dev);
static int igb_runtime_resume(struct device *dev);
static int igb_runtime_idle(struct device *dev);
-#endif
static const struct dev_pm_ops igb_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(igb_suspend, igb_resume)
SET_RUNTIME_PM_OPS(igb_runtime_suspend, igb_runtime_resume,
@@ -7437,7 +7435,6 @@ static int igb_resume(struct device *dev)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
static int igb_runtime_idle(struct device *dev)
{
struct pci_dev *pdev = to_pci_dev(dev);
@@ -7474,8 +7471,7 @@ static int igb_runtime_resume(struct device *dev)
{
return igb_resume(dev);
}
-#endif /* CONFIG_PM_RUNTIME */
-#endif
+#endif /* CONFIG_PM */
static void igb_shutdown(struct pci_dev *pdev)
{
diff --git a/drivers/net/macvtap.c b/drivers/net/macvtap.c
index 2c157cc..60f7ee5 100644
--- a/drivers/net/macvtap.c
+++ b/drivers/net/macvtap.c
@@ -46,6 +46,18 @@ struct macvtap_queue {
struct list_head next;
};
+#define MACVTAP_FEATURES (IFF_VNET_HDR | IFF_VNET_LE | IFF_MULTI_QUEUE)
+
+static inline u16 macvtap16_to_cpu(struct macvtap_queue *q, __virtio16 val)
+{
+ return __virtio16_to_cpu(q->flags & IFF_VNET_LE, val);
+}
+
+static inline __virtio16 cpu_to_macvtap16(struct macvtap_queue *q, u16 val)
+{
+ return __cpu_to_virtio16(q->flags & IFF_VNET_LE, val);
+}
+
static struct proto macvtap_proto = {
.name = "macvtap",
.owner = THIS_MODULE,
@@ -558,7 +570,8 @@ static inline struct sk_buff *macvtap_alloc_skb(struct sock *sk, size_t prepad,
* macvtap_skb_from_vnet_hdr and macvtap_skb_to_vnet_hdr should
* be shared with the tun/tap driver.
*/
-static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
+static int macvtap_skb_from_vnet_hdr(struct macvtap_queue *q,
+ struct sk_buff *skb,
struct virtio_net_hdr *vnet_hdr)
{
unsigned short gso_type = 0;
@@ -589,13 +602,13 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
}
if (vnet_hdr->flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
- if (!skb_partial_csum_set(skb, vnet_hdr->csum_start,
- vnet_hdr->csum_offset))
+ if (!skb_partial_csum_set(skb, macvtap16_to_cpu(q, vnet_hdr->csum_start),
+ macvtap16_to_cpu(q, vnet_hdr->csum_offset)))
return -EINVAL;
}
if (vnet_hdr->gso_type != VIRTIO_NET_HDR_GSO_NONE) {
- skb_shinfo(skb)->gso_size = vnet_hdr->gso_size;
+ skb_shinfo(skb)->gso_size = macvtap16_to_cpu(q, vnet_hdr->gso_size);
skb_shinfo(skb)->gso_type = gso_type;
/* Header must be checked, and gso_segs computed. */
@@ -605,8 +618,9 @@ static int macvtap_skb_from_vnet_hdr(struct sk_buff *skb,
return 0;
}
-static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
- struct virtio_net_hdr *vnet_hdr)
+static void macvtap_skb_to_vnet_hdr(struct macvtap_queue *q,
+ const struct sk_buff *skb,
+ struct virtio_net_hdr *vnet_hdr)
{
memset(vnet_hdr, 0, sizeof(*vnet_hdr));
@@ -614,8 +628,8 @@ static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
struct skb_shared_info *sinfo = skb_shinfo(skb);
/* This is a hint as to how much should be linear. */
- vnet_hdr->hdr_len = skb_headlen(skb);
- vnet_hdr->gso_size = sinfo->gso_size;
+ vnet_hdr->hdr_len = cpu_to_macvtap16(q, skb_headlen(skb));
+ vnet_hdr->gso_size = cpu_to_macvtap16(q, sinfo->gso_size);
if (sinfo->gso_type & SKB_GSO_TCPV4)
vnet_hdr->gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
@@ -629,10 +643,13 @@ static void macvtap_skb_to_vnet_hdr(const struct sk_buff *skb,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
vnet_hdr->flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- vnet_hdr->csum_start = skb_checksum_start_offset(skb);
if (vlan_tx_tag_present(skb))
- vnet_hdr->csum_start += VLAN_HLEN;
- vnet_hdr->csum_offset = skb->csum_offset;
+ vnet_hdr->csum_start = cpu_to_macvtap16(q,
+ skb_checksum_start_offset(skb) + VLAN_HLEN);
+ else
+ vnet_hdr->csum_start = cpu_to_macvtap16(q,
+ skb_checksum_start_offset(skb));
+ vnet_hdr->csum_offset = cpu_to_macvtap16(q, skb->csum_offset);
} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
vnet_hdr->flags = VIRTIO_NET_HDR_F_DATA_VALID;
} /* else everything is zero */
@@ -669,12 +686,14 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
goto err;
iov_iter_advance(from, vnet_hdr_len - sizeof(vnet_hdr));
if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
- vnet_hdr.csum_start + vnet_hdr.csum_offset + 2 >
- vnet_hdr.hdr_len)
- vnet_hdr.hdr_len = vnet_hdr.csum_start +
- vnet_hdr.csum_offset + 2;
+ macvtap16_to_cpu(q, vnet_hdr.csum_start) +
+ macvtap16_to_cpu(q, vnet_hdr.csum_offset) + 2 >
+ macvtap16_to_cpu(q, vnet_hdr.hdr_len))
+ vnet_hdr.hdr_len = cpu_to_macvtap16(q,
+ macvtap16_to_cpu(q, vnet_hdr.csum_start) +
+ macvtap16_to_cpu(q, vnet_hdr.csum_offset) + 2);
err = -EINVAL;
- if (vnet_hdr.hdr_len > len)
+ if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > len)
goto err;
}
@@ -685,7 +704,8 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
if (m && m->msg_control && sock_flag(&q->sk, SOCK_ZEROCOPY)) {
struct iov_iter i;
- copylen = vnet_hdr.hdr_len ? vnet_hdr.hdr_len : GOODCOPY_LEN;
+ copylen = vnet_hdr.hdr_len ?
+ macvtap16_to_cpu(q, vnet_hdr.hdr_len) : GOODCOPY_LEN;
if (copylen > good_linear)
copylen = good_linear;
linear = copylen;
@@ -697,10 +717,10 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
if (!zerocopy) {
copylen = len;
- if (vnet_hdr.hdr_len > good_linear)
+ if (macvtap16_to_cpu(q, vnet_hdr.hdr_len) > good_linear)
linear = good_linear;
else
- linear = vnet_hdr.hdr_len;
+ linear = macvtap16_to_cpu(q, vnet_hdr.hdr_len);
}
skb = macvtap_alloc_skb(&q->sk, NET_IP_ALIGN, copylen,
@@ -726,7 +746,7 @@ static ssize_t macvtap_get_user(struct macvtap_queue *q, struct msghdr *m,
skb->protocol = eth_hdr(skb)->h_proto;
if (vnet_hdr_len) {
- err = macvtap_skb_from_vnet_hdr(skb, &vnet_hdr);
+ err = macvtap_skb_from_vnet_hdr(q, skb, &vnet_hdr);
if (err)
goto err_kfree;
}
@@ -788,7 +808,7 @@ static ssize_t macvtap_put_user(struct macvtap_queue *q,
if (iov_iter_count(iter) < vnet_hdr_len)
return -EINVAL;
- macvtap_skb_to_vnet_hdr(skb, &vnet_hdr);
+ macvtap_skb_to_vnet_hdr(q, skb, &vnet_hdr);
if (copy_to_iter(&vnet_hdr, sizeof(vnet_hdr), iter) !=
sizeof(vnet_hdr))
@@ -991,8 +1011,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
return -EFAULT;
ret = 0;
- if ((u & ~(IFF_VNET_HDR | IFF_MULTI_QUEUE)) !=
- (IFF_NO_PI | IFF_TAP))
+ if ((u & ~MACVTAP_FEATURES) != (IFF_NO_PI | IFF_TAP))
ret = -EINVAL;
else
q->flags = u;
@@ -1024,8 +1043,7 @@ static long macvtap_ioctl(struct file *file, unsigned int cmd,
return ret;
case TUNGETFEATURES:
- if (put_user(IFF_TAP | IFF_NO_PI | IFF_VNET_HDR |
- IFF_MULTI_QUEUE, up))
+ if (put_user(IFF_TAP | IFF_NO_PI | MACVTAP_FEATURES, up))
return -EFAULT;
return 0;
diff --git a/drivers/net/tun.c b/drivers/net/tun.c
index f3e992e..a5cbf67 100644
--- a/drivers/net/tun.c
+++ b/drivers/net/tun.c
@@ -104,6 +104,15 @@ do { \
} while (0)
#endif
+/* TUN device flags */
+
+/* IFF_ATTACH_QUEUE is never stored in device flags,
+ * overload it to mean fasync when stored there.
+ */
+#define TUN_FASYNC IFF_ATTACH_QUEUE
+
+#define TUN_FEATURES (IFF_NO_PI | IFF_ONE_QUEUE | IFF_VNET_HDR | \
+ IFF_VNET_LE | IFF_MULTI_QUEUE)
#define GOODCOPY_LEN 128
#define FLT_EXACT_COUNT 8
@@ -197,6 +206,16 @@ struct tun_struct {
u32 flow_count;
};
+static inline u16 tun16_to_cpu(struct tun_struct *tun, __virtio16 val)
+{
+ return __virtio16_to_cpu(tun->flags & IFF_VNET_LE, val);
+}
+
+static inline __virtio16 cpu_to_tun16(struct tun_struct *tun, u16 val)
+{
+ return __cpu_to_virtio16(tun->flags & IFF_VNET_LE, val);
+}
+
static inline u32 tun_hashfn(u32 rxhash)
{
return rxhash & 0x3ff;
@@ -473,7 +492,7 @@ static void __tun_detach(struct tun_file *tfile, bool clean)
if (tun && tun->numqueues == 0 && tun->numdisabled == 0) {
netif_carrier_off(tun->dev);
- if (!(tun->flags & TUN_PERSIST) &&
+ if (!(tun->flags & IFF_PERSIST) &&
tun->dev->reg_state == NETREG_REGISTERED)
unregister_netdevice(tun->dev);
}
@@ -524,7 +543,7 @@ static void tun_detach_all(struct net_device *dev)
}
BUG_ON(tun->numdisabled != 0);
- if (tun->flags & TUN_PERSIST)
+ if (tun->flags & IFF_PERSIST)
module_put(THIS_MODULE);
}
@@ -542,7 +561,7 @@ static int tun_attach(struct tun_struct *tun, struct file *file, bool skip_filte
goto out;
err = -EBUSY;
- if (!(tun->flags & TUN_TAP_MQ) && tun->numqueues == 1)
+ if (!(tun->flags & IFF_MULTI_QUEUE) && tun->numqueues == 1)
goto out;
err = -E2BIG;
@@ -921,7 +940,7 @@ static void tun_net_init(struct net_device *dev)
struct tun_struct *tun = netdev_priv(dev);
switch (tun->flags & TUN_TYPE_MASK) {
- case TUN_TUN_DEV:
+ case IFF_TUN:
dev->netdev_ops = &tun_netdev_ops;
/* Point-to-Point TUN Device */
@@ -935,7 +954,7 @@ static void tun_net_init(struct net_device *dev)
dev->tx_queue_len = TUN_READQ_SIZE; /* We prefer our own queue length */
break;
- case TUN_TAP_DEV:
+ case IFF_TAP:
dev->netdev_ops = &tap_netdev_ops;
/* Ethernet TAP Device */
ether_setup(dev);
@@ -1027,7 +1046,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
u32 rxhash;
ssize_t n;
- if (!(tun->flags & TUN_NO_PI)) {
+ if (!(tun->flags & IFF_NO_PI)) {
if (len < sizeof(pi))
return -EINVAL;
len -= sizeof(pi);
@@ -1037,7 +1056,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
return -EFAULT;
}
- if (tun->flags & TUN_VNET_HDR) {
+ if (tun->flags & IFF_VNET_HDR) {
if (len < tun->vnet_hdr_sz)
return -EINVAL;
len -= tun->vnet_hdr_sz;
@@ -1047,18 +1066,18 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
return -EFAULT;
if ((gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
- gso.csum_start + gso.csum_offset + 2 > gso.hdr_len)
- gso.hdr_len = gso.csum_start + gso.csum_offset + 2;
+ tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2 > tun16_to_cpu(tun, gso.hdr_len))
+ gso.hdr_len = cpu_to_tun16(tun, tun16_to_cpu(tun, gso.csum_start) + tun16_to_cpu(tun, gso.csum_offset) + 2);
- if (gso.hdr_len > len)
+ if (tun16_to_cpu(tun, gso.hdr_len) > len)
return -EINVAL;
iov_iter_advance(from, tun->vnet_hdr_sz - sizeof(gso));
}
- if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
+ if ((tun->flags & TUN_TYPE_MASK) == IFF_TAP) {
align += NET_IP_ALIGN;
if (unlikely(len < ETH_HLEN ||
- (gso.hdr_len && gso.hdr_len < ETH_HLEN)))
+ (gso.hdr_len && tun16_to_cpu(tun, gso.hdr_len) < ETH_HLEN)))
return -EINVAL;
}
@@ -1071,7 +1090,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
* enough room for skb expand head in case it is used.
* The rest of the buffer is mapped from userspace.
*/
- copylen = gso.hdr_len ? gso.hdr_len : GOODCOPY_LEN;
+ copylen = gso.hdr_len ? tun16_to_cpu(tun, gso.hdr_len) : GOODCOPY_LEN;
if (copylen > good_linear)
copylen = good_linear;
linear = copylen;
@@ -1082,10 +1101,10 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
if (!zerocopy) {
copylen = len;
- if (gso.hdr_len > good_linear)
+ if (tun16_to_cpu(tun, gso.hdr_len) > good_linear)
linear = good_linear;
else
- linear = gso.hdr_len;
+ linear = tun16_to_cpu(tun, gso.hdr_len);
}
skb = tun_alloc_skb(tfile, align, copylen, linear, noblock);
@@ -1112,8 +1131,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
if (gso.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
- if (!skb_partial_csum_set(skb, gso.csum_start,
- gso.csum_offset)) {
+ if (!skb_partial_csum_set(skb, tun16_to_cpu(tun, gso.csum_start),
+ tun16_to_cpu(tun, gso.csum_offset))) {
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
return -EINVAL;
@@ -1121,8 +1140,8 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
}
switch (tun->flags & TUN_TYPE_MASK) {
- case TUN_TUN_DEV:
- if (tun->flags & TUN_NO_PI) {
+ case IFF_TUN:
+ if (tun->flags & IFF_NO_PI) {
switch (skb->data[0] & 0xf0) {
case 0x40:
pi.proto = htons(ETH_P_IP);
@@ -1141,7 +1160,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
skb->protocol = pi.proto;
skb->dev = tun->dev;
break;
- case TUN_TAP_DEV:
+ case IFF_TAP:
skb->protocol = eth_type_trans(skb, tun->dev);
break;
}
@@ -1181,7 +1200,7 @@ static ssize_t tun_get_user(struct tun_struct *tun, struct tun_file *tfile,
if (gso.gso_type & VIRTIO_NET_HDR_GSO_ECN)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
- skb_shinfo(skb)->gso_size = gso.gso_size;
+ skb_shinfo(skb)->gso_size = tun16_to_cpu(tun, gso.gso_size);
if (skb_shinfo(skb)->gso_size == 0) {
tun->dev->stats.rx_frame_errors++;
kfree_skb(skb);
@@ -1243,12 +1262,12 @@ static ssize_t tun_put_user(struct tun_struct *tun,
if (vlan_tx_tag_present(skb))
vlan_hlen = VLAN_HLEN;
- if (tun->flags & TUN_VNET_HDR)
+ if (tun->flags & IFF_VNET_HDR)
vnet_hdr_sz = tun->vnet_hdr_sz;
total = skb->len + vlan_hlen + vnet_hdr_sz;
- if (!(tun->flags & TUN_NO_PI)) {
+ if (!(tun->flags & IFF_NO_PI)) {
if (iov_iter_count(iter) < sizeof(pi))
return -EINVAL;
@@ -1271,8 +1290,8 @@ static ssize_t tun_put_user(struct tun_struct *tun,
struct skb_shared_info *sinfo = skb_shinfo(skb);
/* This is a hint as to how much should be linear. */
- gso.hdr_len = skb_headlen(skb);
- gso.gso_size = sinfo->gso_size;
+ gso.hdr_len = cpu_to_tun16(tun, skb_headlen(skb));
+ gso.gso_size = cpu_to_tun16(tun, sinfo->gso_size);
if (sinfo->gso_type & SKB_GSO_TCPV4)
gso.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
@@ -1280,12 +1299,12 @@ static ssize_t tun_put_user(struct tun_struct *tun,
else {
pr_err("unexpected GSO type: "
"0x%x, gso_size %d, hdr_len %d\n",
- sinfo->gso_type, gso.gso_size,
- gso.hdr_len);
+ sinfo->gso_type, tun16_to_cpu(tun, gso.gso_size),
+ tun16_to_cpu(tun, gso.hdr_len));
print_hex_dump(KERN_ERR, "tun: ",
DUMP_PREFIX_NONE,
16, 1, skb->head,
- min((int)gso.hdr_len, 64), true);
+ min((int)tun16_to_cpu(tun, gso.hdr_len), 64), true);
WARN_ON_ONCE(1);
return -EINVAL;
}
@@ -1296,9 +1315,9 @@ static ssize_t tun_put_user(struct tun_struct *tun,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
gso.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- gso.csum_start = skb_checksum_start_offset(skb) +
- vlan_hlen;
- gso.csum_offset = skb->csum_offset;
+ gso.csum_start = cpu_to_tun16(tun, skb_checksum_start_offset(skb) +
+ vlan_hlen);
+ gso.csum_offset = cpu_to_tun16(tun, skb->csum_offset);
} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
gso.flags = VIRTIO_NET_HDR_F_DATA_VALID;
} /* else everything is zero */
@@ -1511,32 +1530,7 @@ static struct proto tun_proto = {
static int tun_flags(struct tun_struct *tun)
{
- int flags = 0;
-
- if (tun->flags & TUN_TUN_DEV)
- flags |= IFF_TUN;
- else
- flags |= IFF_TAP;
-
- if (tun->flags & TUN_NO_PI)
- flags |= IFF_NO_PI;
-
- /* This flag has no real effect. We track the value for backwards
- * compatibility.
- */
- if (tun->flags & TUN_ONE_QUEUE)
- flags |= IFF_ONE_QUEUE;
-
- if (tun->flags & TUN_VNET_HDR)
- flags |= IFF_VNET_HDR;
-
- if (tun->flags & TUN_TAP_MQ)
- flags |= IFF_MULTI_QUEUE;
-
- if (tun->flags & TUN_PERSIST)
- flags |= IFF_PERSIST;
-
- return flags;
+ return tun->flags & (TUN_FEATURES | IFF_PERSIST | IFF_TUN | IFF_TAP);
}
static ssize_t tun_show_flags(struct device *dev, struct device_attribute *attr,
@@ -1592,7 +1586,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
return -EINVAL;
if (!!(ifr->ifr_flags & IFF_MULTI_QUEUE) !=
- !!(tun->flags & TUN_TAP_MQ))
+ !!(tun->flags & IFF_MULTI_QUEUE))
return -EINVAL;
if (tun_not_capable(tun))
@@ -1605,7 +1599,7 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
if (err < 0)
return err;
- if (tun->flags & TUN_TAP_MQ &&
+ if (tun->flags & IFF_MULTI_QUEUE &&
(tun->numqueues + tun->numdisabled > 1)) {
/* One or more queue has already been attached, no need
* to initialize the device again.
@@ -1628,11 +1622,11 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
/* Set dev type */
if (ifr->ifr_flags & IFF_TUN) {
/* TUN device */
- flags |= TUN_TUN_DEV;
+ flags |= IFF_TUN;
name = "tun%d";
} else if (ifr->ifr_flags & IFF_TAP) {
/* TAP device */
- flags |= TUN_TAP_DEV;
+ flags |= IFF_TAP;
name = "tap%d";
} else
return -EINVAL;
@@ -1696,28 +1690,8 @@ static int tun_set_iff(struct net *net, struct file *file, struct ifreq *ifr)
tun_debug(KERN_INFO, tun, "tun_set_iff\n");
- if (ifr->ifr_flags & IFF_NO_PI)
- tun->flags |= TUN_NO_PI;
- else
- tun->flags &= ~TUN_NO_PI;
-
- /* This flag has no real effect. We track the value for backwards
- * compatibility.
- */
- if (ifr->ifr_flags & IFF_ONE_QUEUE)
- tun->flags |= TUN_ONE_QUEUE;
- else
- tun->flags &= ~TUN_ONE_QUEUE;
-
- if (ifr->ifr_flags & IFF_VNET_HDR)
- tun->flags |= TUN_VNET_HDR;
- else
- tun->flags &= ~TUN_VNET_HDR;
-
- if (ifr->ifr_flags & IFF_MULTI_QUEUE)
- tun->flags |= TUN_TAP_MQ;
- else
- tun->flags &= ~TUN_TAP_MQ;
+ tun->flags = (tun->flags & ~TUN_FEATURES) |
+ (ifr->ifr_flags & TUN_FEATURES);
/* Make sure persistent devices do not get stuck in
* xoff state.
@@ -1845,7 +1819,7 @@ static int tun_set_queue(struct file *file, struct ifreq *ifr)
ret = tun_attach(tun, file, false);
} else if (ifr->ifr_flags & IFF_DETACH_QUEUE) {
tun = rtnl_dereference(tfile->tun);
- if (!tun || !(tun->flags & TUN_TAP_MQ) || tfile->detached)
+ if (!tun || !(tun->flags & IFF_MULTI_QUEUE) || tfile->detached)
ret = -EINVAL;
else
__tun_detach(tfile, false);
@@ -1880,9 +1854,9 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
if (cmd == TUNGETFEATURES) {
/* Currently this just means: "what IFF flags are valid?".
* This is needed because we never checked for invalid flags on
- * TUNSETIFF. */
- return put_user(IFF_TUN | IFF_TAP | IFF_NO_PI | IFF_ONE_QUEUE |
- IFF_VNET_HDR | IFF_MULTI_QUEUE,
+ * TUNSETIFF.
+ */
+ return put_user(IFF_TUN | IFF_TAP | TUN_FEATURES,
(unsigned int __user*)argp);
} else if (cmd == TUNSETQUEUE)
return tun_set_queue(file, &ifr);
@@ -1949,12 +1923,12 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
/* Disable/Enable persist mode. Keep an extra reference to the
* module to prevent the module being unprobed.
*/
- if (arg && !(tun->flags & TUN_PERSIST)) {
- tun->flags |= TUN_PERSIST;
+ if (arg && !(tun->flags & IFF_PERSIST)) {
+ tun->flags |= IFF_PERSIST;
__module_get(THIS_MODULE);
}
- if (!arg && (tun->flags & TUN_PERSIST)) {
- tun->flags &= ~TUN_PERSIST;
+ if (!arg && (tun->flags & IFF_PERSIST)) {
+ tun->flags &= ~IFF_PERSIST;
module_put(THIS_MODULE);
}
@@ -2012,7 +1986,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case TUNSETTXFILTER:
/* Can be set only for TAPs */
ret = -EINVAL;
- if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP)
break;
ret = update_filter(&tun->txflt, (void __user *)arg);
break;
@@ -2071,7 +2045,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case TUNATTACHFILTER:
/* Can be set only for TAPs */
ret = -EINVAL;
- if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP)
break;
ret = -EFAULT;
if (copy_from_user(&tun->fprog, argp, sizeof(tun->fprog)))
@@ -2083,7 +2057,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case TUNDETACHFILTER:
/* Can be set only for TAPs */
ret = -EINVAL;
- if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP)
break;
ret = 0;
tun_detach_filter(tun, tun->numqueues);
@@ -2091,7 +2065,7 @@ static long __tun_chr_ioctl(struct file *file, unsigned int cmd,
case TUNGETFILTER:
ret = -EINVAL;
- if ((tun->flags & TUN_TYPE_MASK) != TUN_TAP_DEV)
+ if ((tun->flags & TUN_TYPE_MASK) != IFF_TAP)
break;
ret = -EFAULT;
if (copy_to_user(argp, &tun->fprog, sizeof(tun->fprog)))
@@ -2212,7 +2186,7 @@ static int tun_chr_close(struct inode *inode, struct file *file)
}
#ifdef CONFIG_PROC_FS
-static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f)
+static void tun_chr_show_fdinfo(struct seq_file *m, struct file *f)
{
struct tun_struct *tun;
struct ifreq ifr;
@@ -2228,7 +2202,7 @@ static int tun_chr_show_fdinfo(struct seq_file *m, struct file *f)
if (tun)
tun_put(tun);
- return seq_printf(m, "iff:\t%s\n", ifr.ifr_name);
+ seq_printf(m, "iff:\t%s\n", ifr.ifr_name);
}
#endif
@@ -2284,10 +2258,10 @@ static void tun_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info
strlcpy(info->version, DRV_VERSION, sizeof(info->version));
switch (tun->flags & TUN_TYPE_MASK) {
- case TUN_TUN_DEV:
+ case IFF_TUN:
strlcpy(info->bus_info, "tun", sizeof(info->bus_info));
break;
- case TUN_TAP_DEV:
+ case IFF_TAP:
strlcpy(info->bus_info, "tap", sizeof(info->bus_info));
break;
}
diff --git a/drivers/net/virtio_net.c b/drivers/net/virtio_net.c
index b0bc8ea..b8bd719 100644
--- a/drivers/net/virtio_net.c
+++ b/drivers/net/virtio_net.c
@@ -123,6 +123,9 @@ struct virtnet_info {
/* Host can handle any s/g split between our header and packet data */
bool any_header_sg;
+ /* Packet virtio header size */
+ u8 hdr_len;
+
/* Active statistics */
struct virtnet_stats __percpu *stats;
@@ -139,21 +142,14 @@ struct virtnet_info {
struct notifier_block nb;
};
-struct skb_vnet_hdr {
- union {
- struct virtio_net_hdr hdr;
- struct virtio_net_hdr_mrg_rxbuf mhdr;
- };
-};
-
struct padded_vnet_hdr {
- struct virtio_net_hdr hdr;
+ struct virtio_net_hdr_mrg_rxbuf hdr;
/*
- * virtio_net_hdr should be in a separated sg buffer because of a
- * QEMU bug, and data sg buffer shares same page with this header sg.
- * This padding makes next sg 16 byte aligned after virtio_net_hdr.
+ * hdr is in a separate sg buffer, and data sg buffer shares same page
+ * with this header sg. This padding makes next sg 16 byte aligned
+ * after the header.
*/
- char padding[6];
+ char padding[4];
};
/* Converting between virtqueue no. and kernel tx/rx queue no.
@@ -179,9 +175,9 @@ static int rxq2vq(int rxq)
return rxq * 2;
}
-static inline struct skb_vnet_hdr *skb_vnet_hdr(struct sk_buff *skb)
+static inline struct virtio_net_hdr_mrg_rxbuf *skb_vnet_hdr(struct sk_buff *skb)
{
- return (struct skb_vnet_hdr *)skb->cb;
+ return (struct virtio_net_hdr_mrg_rxbuf *)skb->cb;
}
/*
@@ -241,13 +237,13 @@ static unsigned long mergeable_buf_to_ctx(void *buf, unsigned int truesize)
}
/* Called from bottom half context */
-static struct sk_buff *page_to_skb(struct receive_queue *rq,
+static struct sk_buff *page_to_skb(struct virtnet_info *vi,
+ struct receive_queue *rq,
struct page *page, unsigned int offset,
unsigned int len, unsigned int truesize)
{
- struct virtnet_info *vi = rq->vq->vdev->priv;
struct sk_buff *skb;
- struct skb_vnet_hdr *hdr;
+ struct virtio_net_hdr_mrg_rxbuf *hdr;
unsigned int copy, hdr_len, hdr_padded_len;
char *p;
@@ -260,13 +256,11 @@ static struct sk_buff *page_to_skb(struct receive_queue *rq,
hdr = skb_vnet_hdr(skb);
- if (vi->mergeable_rx_bufs) {
- hdr_len = sizeof hdr->mhdr;
- hdr_padded_len = sizeof hdr->mhdr;
- } else {
- hdr_len = sizeof hdr->hdr;
+ hdr_len = vi->hdr_len;
+ if (vi->mergeable_rx_bufs)
+ hdr_padded_len = sizeof *hdr;
+ else
hdr_padded_len = sizeof(struct padded_vnet_hdr);
- }
memcpy(hdr, p, hdr_len);
@@ -317,23 +311,24 @@ static struct sk_buff *page_to_skb(struct receive_queue *rq,
return skb;
}
-static struct sk_buff *receive_small(void *buf, unsigned int len)
+static struct sk_buff *receive_small(struct virtnet_info *vi, void *buf, unsigned int len)
{
struct sk_buff * skb = buf;
- len -= sizeof(struct virtio_net_hdr);
+ len -= vi->hdr_len;
skb_trim(skb, len);
return skb;
}
static struct sk_buff *receive_big(struct net_device *dev,
+ struct virtnet_info *vi,
struct receive_queue *rq,
void *buf,
unsigned int len)
{
struct page *page = buf;
- struct sk_buff *skb = page_to_skb(rq, page, 0, len, PAGE_SIZE);
+ struct sk_buff *skb = page_to_skb(vi, rq, page, 0, len, PAGE_SIZE);
if (unlikely(!skb))
goto err;
@@ -347,18 +342,20 @@ err:
}
static struct sk_buff *receive_mergeable(struct net_device *dev,
+ struct virtnet_info *vi,
struct receive_queue *rq,
unsigned long ctx,
unsigned int len)
{
void *buf = mergeable_ctx_to_buf_address(ctx);
- struct skb_vnet_hdr *hdr = buf;
- int num_buf = hdr->mhdr.num_buffers;
+ struct virtio_net_hdr_mrg_rxbuf *hdr = buf;
+ u16 num_buf = virtio16_to_cpu(vi->vdev, hdr->num_buffers);
struct page *page = virt_to_head_page(buf);
int offset = buf - page_address(page);
unsigned int truesize = max(len, mergeable_ctx_to_buf_truesize(ctx));
- struct sk_buff *head_skb = page_to_skb(rq, page, offset, len, truesize);
+ struct sk_buff *head_skb = page_to_skb(vi, rq, page, offset, len,
+ truesize);
struct sk_buff *curr_skb = head_skb;
if (unlikely(!curr_skb))
@@ -369,7 +366,9 @@ static struct sk_buff *receive_mergeable(struct net_device *dev,
ctx = (unsigned long)virtqueue_get_buf(rq->vq, &len);
if (unlikely(!ctx)) {
pr_debug("%s: rx error: %d buffers out of %d missing\n",
- dev->name, num_buf, hdr->mhdr.num_buffers);
+ dev->name, num_buf,
+ virtio16_to_cpu(vi->vdev,
+ hdr->num_buffers));
dev->stats.rx_length_errors++;
goto err_buf;
}
@@ -430,15 +429,15 @@ err_buf:
return NULL;
}
-static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
+static void receive_buf(struct virtnet_info *vi, struct receive_queue *rq,
+ void *buf, unsigned int len)
{
- struct virtnet_info *vi = rq->vq->vdev->priv;
struct net_device *dev = vi->dev;
struct virtnet_stats *stats = this_cpu_ptr(vi->stats);
struct sk_buff *skb;
- struct skb_vnet_hdr *hdr;
+ struct virtio_net_hdr_mrg_rxbuf *hdr;
- if (unlikely(len < sizeof(struct virtio_net_hdr) + ETH_HLEN)) {
+ if (unlikely(len < vi->hdr_len + ETH_HLEN)) {
pr_debug("%s: short packet %i\n", dev->name, len);
dev->stats.rx_length_errors++;
if (vi->mergeable_rx_bufs) {
@@ -454,11 +453,11 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
}
if (vi->mergeable_rx_bufs)
- skb = receive_mergeable(dev, rq, (unsigned long)buf, len);
+ skb = receive_mergeable(dev, vi, rq, (unsigned long)buf, len);
else if (vi->big_packets)
- skb = receive_big(dev, rq, buf, len);
+ skb = receive_big(dev, vi, rq, buf, len);
else
- skb = receive_small(buf, len);
+ skb = receive_small(vi, buf, len);
if (unlikely(!skb))
return;
@@ -473,8 +472,8 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
if (hdr->hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
pr_debug("Needs csum!\n");
if (!skb_partial_csum_set(skb,
- hdr->hdr.csum_start,
- hdr->hdr.csum_offset))
+ virtio16_to_cpu(vi->vdev, hdr->hdr.csum_start),
+ virtio16_to_cpu(vi->vdev, hdr->hdr.csum_offset)))
goto frame_err;
} else if (hdr->hdr.flags & VIRTIO_NET_HDR_F_DATA_VALID) {
skb->ip_summed = CHECKSUM_UNNECESSARY;
@@ -514,7 +513,8 @@ static void receive_buf(struct receive_queue *rq, void *buf, unsigned int len)
if (hdr->hdr.gso_type & VIRTIO_NET_HDR_GSO_ECN)
skb_shinfo(skb)->gso_type |= SKB_GSO_TCP_ECN;
- skb_shinfo(skb)->gso_size = hdr->hdr.gso_size;
+ skb_shinfo(skb)->gso_size = virtio16_to_cpu(vi->vdev,
+ hdr->hdr.gso_size);
if (skb_shinfo(skb)->gso_size == 0) {
net_warn_ratelimited("%s: zero gso size.\n", dev->name);
goto frame_err;
@@ -535,11 +535,11 @@ frame_err:
dev_kfree_skb(skb);
}
-static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp)
+static int add_recvbuf_small(struct virtnet_info *vi, struct receive_queue *rq,
+ gfp_t gfp)
{
- struct virtnet_info *vi = rq->vq->vdev->priv;
struct sk_buff *skb;
- struct skb_vnet_hdr *hdr;
+ struct virtio_net_hdr_mrg_rxbuf *hdr;
int err;
skb = __netdev_alloc_skb_ip_align(vi->dev, GOOD_PACKET_LEN, gfp);
@@ -550,7 +550,7 @@ static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp)
hdr = skb_vnet_hdr(skb);
sg_init_table(rq->sg, MAX_SKB_FRAGS + 2);
- sg_set_buf(rq->sg, &hdr->hdr, sizeof hdr->hdr);
+ sg_set_buf(rq->sg, hdr, vi->hdr_len);
skb_to_sgvec(skb, rq->sg + 1, 0, skb->len);
err = virtqueue_add_inbuf(rq->vq, rq->sg, 2, skb, gfp);
@@ -560,7 +560,8 @@ static int add_recvbuf_small(struct receive_queue *rq, gfp_t gfp)
return err;
}
-static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp)
+static int add_recvbuf_big(struct virtnet_info *vi, struct receive_queue *rq,
+ gfp_t gfp)
{
struct page *first, *list = NULL;
char *p;
@@ -591,8 +592,8 @@ static int add_recvbuf_big(struct receive_queue *rq, gfp_t gfp)
p = page_address(first);
/* rq->sg[0], rq->sg[1] share the same page */
- /* a separated rq->sg[0] for virtio_net_hdr only due to QEMU bug */
- sg_set_buf(&rq->sg[0], p, sizeof(struct virtio_net_hdr));
+ /* a separated rq->sg[0] for header - required in case !any_header_sg */
+ sg_set_buf(&rq->sg[0], p, vi->hdr_len);
/* rq->sg[1] for data packet, from offset */
offset = sizeof(struct padded_vnet_hdr);
@@ -660,9 +661,9 @@ static int add_recvbuf_mergeable(struct receive_queue *rq, gfp_t gfp)
* before we're receiving packets, or from refill_work which is
* careful to disable receiving (using napi_disable).
*/
-static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
+static bool try_fill_recv(struct virtnet_info *vi, struct receive_queue *rq,
+ gfp_t gfp)
{
- struct virtnet_info *vi = rq->vq->vdev->priv;
int err;
bool oom;
@@ -671,9 +672,9 @@ static bool try_fill_recv(struct receive_queue *rq, gfp_t gfp)
if (vi->mergeable_rx_bufs)
err = add_recvbuf_mergeable(rq, gfp);
else if (vi->big_packets)
- err = add_recvbuf_big(rq, gfp);
+ err = add_recvbuf_big(vi, rq, gfp);
else
- err = add_recvbuf_small(rq, gfp);
+ err = add_recvbuf_small(vi, rq, gfp);
oom = err == -ENOMEM;
if (err)
@@ -722,7 +723,7 @@ static void refill_work(struct work_struct *work)
struct receive_queue *rq = &vi->rq[i];
napi_disable(&rq->napi);
- still_empty = !try_fill_recv(rq, GFP_KERNEL);
+ still_empty = !try_fill_recv(vi, rq, GFP_KERNEL);
virtnet_napi_enable(rq);
/* In theory, this can happen: if we don't get any buffers in
@@ -741,12 +742,12 @@ static int virtnet_receive(struct receive_queue *rq, int budget)
while (received < budget &&
(buf = virtqueue_get_buf(rq->vq, &len)) != NULL) {
- receive_buf(rq, buf, len);
+ receive_buf(vi, rq, buf, len);
received++;
}
if (rq->vq->num_free > virtqueue_get_vring_size(rq->vq) / 2) {
- if (!try_fill_recv(rq, GFP_ATOMIC))
+ if (!try_fill_recv(vi, rq, GFP_ATOMIC))
schedule_delayed_work(&vi->refill, 0);
}
@@ -822,7 +823,7 @@ static int virtnet_open(struct net_device *dev)
for (i = 0; i < vi->max_queue_pairs; i++) {
if (i < vi->curr_queue_pairs)
/* Make sure we have some buffers: if oom use wq. */
- if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+ if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
schedule_delayed_work(&vi->refill, 0);
virtnet_napi_enable(&vi->rq[i]);
}
@@ -851,18 +852,14 @@ static void free_old_xmit_skbs(struct send_queue *sq)
static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
{
- struct skb_vnet_hdr *hdr;
+ struct virtio_net_hdr_mrg_rxbuf *hdr;
const unsigned char *dest = ((struct ethhdr *)skb->data)->h_dest;
struct virtnet_info *vi = sq->vq->vdev->priv;
unsigned num_sg;
- unsigned hdr_len;
+ unsigned hdr_len = vi->hdr_len;
bool can_push;
pr_debug("%s: xmit %p %pM\n", vi->dev->name, skb, dest);
- if (vi->mergeable_rx_bufs)
- hdr_len = sizeof hdr->mhdr;
- else
- hdr_len = sizeof hdr->hdr;
can_push = vi->any_header_sg &&
!((unsigned long)skb->data & (__alignof__(*hdr) - 1)) &&
@@ -870,22 +867,25 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
/* Even if we can, don't push here yet as this would skew
* csum_start offset below. */
if (can_push)
- hdr = (struct skb_vnet_hdr *)(skb->data - hdr_len);
+ hdr = (struct virtio_net_hdr_mrg_rxbuf *)(skb->data - hdr_len);
else
hdr = skb_vnet_hdr(skb);
if (skb->ip_summed == CHECKSUM_PARTIAL) {
hdr->hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- hdr->hdr.csum_start = skb_checksum_start_offset(skb);
- hdr->hdr.csum_offset = skb->csum_offset;
+ hdr->hdr.csum_start = cpu_to_virtio16(vi->vdev,
+ skb_checksum_start_offset(skb));
+ hdr->hdr.csum_offset = cpu_to_virtio16(vi->vdev,
+ skb->csum_offset);
} else {
hdr->hdr.flags = 0;
hdr->hdr.csum_offset = hdr->hdr.csum_start = 0;
}
if (skb_is_gso(skb)) {
- hdr->hdr.hdr_len = skb_headlen(skb);
- hdr->hdr.gso_size = skb_shinfo(skb)->gso_size;
+ hdr->hdr.hdr_len = cpu_to_virtio16(vi->vdev, skb_headlen(skb));
+ hdr->hdr.gso_size = cpu_to_virtio16(vi->vdev,
+ skb_shinfo(skb)->gso_size);
if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV4)
hdr->hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
@@ -900,7 +900,7 @@ static int xmit_skb(struct send_queue *sq, struct sk_buff *skb)
}
if (vi->mergeable_rx_bufs)
- hdr->mhdr.num_buffers = 0;
+ hdr->num_buffers = 0;
sg_init_table(sq->sg, MAX_SKB_FRAGS + 2);
if (can_push) {
@@ -1030,7 +1030,8 @@ static int virtnet_set_mac_address(struct net_device *dev, void *p)
"Failed to set mac address by vq command.\n");
return -EINVAL;
}
- } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC)) {
+ } else if (virtio_has_feature(vdev, VIRTIO_NET_F_MAC) &&
+ !virtio_has_feature(vdev, VIRTIO_F_VERSION_1)) {
unsigned int i;
/* Naturally, this has an atomicity problem. */
@@ -1112,7 +1113,7 @@ static int virtnet_set_queues(struct virtnet_info *vi, u16 queue_pairs)
if (!vi->has_cvq || !virtio_has_feature(vi->vdev, VIRTIO_NET_F_MQ))
return 0;
- s.virtqueue_pairs = queue_pairs;
+ s.virtqueue_pairs = cpu_to_virtio16(vi->vdev, queue_pairs);
sg_init_one(&sg, &s, sizeof(s));
if (!virtnet_send_command(vi, VIRTIO_NET_CTRL_MQ,
@@ -1189,7 +1190,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
sg_init_table(sg, 2);
/* Store the unicast list and count in the front of the buffer */
- mac_data->entries = uc_count;
+ mac_data->entries = cpu_to_virtio32(vi->vdev, uc_count);
i = 0;
netdev_for_each_uc_addr(ha, dev)
memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
@@ -1200,7 +1201,7 @@ static void virtnet_set_rx_mode(struct net_device *dev)
/* multicast list and count fill the end */
mac_data = (void *)&mac_data->macs[uc_count][0];
- mac_data->entries = mc_count;
+ mac_data->entries = cpu_to_virtio32(vi->vdev, mc_count);
i = 0;
netdev_for_each_mc_addr(ha, dev)
memcpy(&mac_data->macs[i++][0], ha->addr, ETH_ALEN);
@@ -1805,18 +1806,20 @@ static int virtnet_probe(struct virtio_device *vdev)
if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF))
vi->mergeable_rx_bufs = true;
+ if (virtio_has_feature(vdev, VIRTIO_NET_F_MRG_RXBUF) ||
+ virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
+ vi->hdr_len = sizeof(struct virtio_net_hdr_mrg_rxbuf);
+ else
+ vi->hdr_len = sizeof(struct virtio_net_hdr);
+
if (virtio_has_feature(vdev, VIRTIO_F_ANY_LAYOUT))
vi->any_header_sg = true;
if (virtio_has_feature(vdev, VIRTIO_NET_F_CTRL_VQ))
vi->has_cvq = true;
- if (vi->any_header_sg) {
- if (vi->mergeable_rx_bufs)
- dev->needed_headroom = sizeof(struct virtio_net_hdr_mrg_rxbuf);
- else
- dev->needed_headroom = sizeof(struct virtio_net_hdr);
- }
+ if (vi->any_header_sg)
+ dev->needed_headroom = vi->hdr_len;
/* Use single tx/rx queue pair as default */
vi->curr_queue_pairs = 1;
@@ -1844,7 +1847,7 @@ static int virtnet_probe(struct virtio_device *vdev)
/* Last of all, set up some receive buffers. */
for (i = 0; i < vi->curr_queue_pairs; i++) {
- try_fill_recv(&vi->rq[i], GFP_KERNEL);
+ try_fill_recv(vi, &vi->rq[i], GFP_KERNEL);
/* If we didn't even get one input buffer, we're useless. */
if (vi->rq[i].vq->num_free ==
@@ -1964,7 +1967,7 @@ static int virtnet_restore(struct virtio_device *vdev)
if (netif_running(vi->dev)) {
for (i = 0; i < vi->curr_queue_pairs; i++)
- if (!try_fill_recv(&vi->rq[i], GFP_KERNEL))
+ if (!try_fill_recv(vi, &vi->rq[i], GFP_KERNEL))
schedule_delayed_work(&vi->refill, 0);
for (i = 0; i < vi->max_queue_pairs; i++)
diff --git a/drivers/nubus/nubus.c b/drivers/nubus/nubus.c
index 5066a7e..3319cf1 100644
--- a/drivers/nubus/nubus.c
+++ b/drivers/nubus/nubus.c
@@ -920,14 +920,10 @@ void __init nubus_probe_slot(int slot)
rp = nubus_rom_addr(slot);
for(i = 4; i; i--)
{
- unsigned long flags;
int card_present;
rp--;
- local_irq_save(flags);
card_present = hwreg_present(rp);
- local_irq_restore(flags);
-
if (!card_present)
continue;
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index 1a13f5b..b5e0c87 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -7,8 +7,8 @@ config OF
menu "Device Tree and Open Firmware support"
depends on OF
-config OF_SELFTEST
- bool "Device Tree Runtime self tests"
+config OF_UNITTEST
+ bool "Device Tree runtime unit tests"
depends on OF_IRQ && OF_EARLY_FLATTREE
select OF_DYNAMIC
select OF_RESOLVE
@@ -23,6 +23,7 @@ config OF_FLATTREE
bool
select DTC
select LIBFDT
+ select CRC32
config OF_EARLY_FLATTREE
bool
@@ -83,4 +84,10 @@ config OF_RESERVED_MEM
config OF_RESOLVE
bool
+config OF_OVERLAY
+ bool
+ depends on OF
+ select OF_DYNAMIC
+ select OF_RESOLVE
+
endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index ca9209c..7563f36 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -6,14 +6,15 @@ obj-$(CONFIG_OF_PROMTREE) += pdt.o
obj-$(CONFIG_OF_ADDRESS) += address.o
obj-$(CONFIG_OF_IRQ) += irq.o
obj-$(CONFIG_OF_NET) += of_net.o
-obj-$(CONFIG_OF_SELFTEST) += of_selftest.o
-of_selftest-objs := selftest.o testcase-data/testcases.dtb.o
+obj-$(CONFIG_OF_UNITTEST) += of_unittest.o
+of_unittest-objs := unittest.o unittest-data/testcases.dtb.o
obj-$(CONFIG_OF_MDIO) += of_mdio.o
obj-$(CONFIG_OF_PCI) += of_pci.o
obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
obj-$(CONFIG_OF_MTD) += of_mtd.o
obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
obj-$(CONFIG_OF_RESOLVE) += resolver.o
+obj-$(CONFIG_OF_OVERLAY) += overlay.o
CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
diff --git a/drivers/of/address.c b/drivers/of/address.c
index 06af494..ad29069 100644
--- a/drivers/of/address.c
+++ b/drivers/of/address.c
@@ -491,7 +491,7 @@ static int of_translate_one(struct device_node *parent, struct of_bus *bus,
*/
ranges = of_get_property(parent, rprop, &rlen);
if (ranges == NULL && !of_empty_ranges_quirk()) {
- pr_err("OF: no ranges; cannot translate\n");
+ pr_debug("OF: no ranges; cannot translate\n");
return 1;
}
if (ranges == NULL || rlen == 0) {
@@ -884,7 +884,7 @@ EXPORT_SYMBOL(of_iomap);
* return PTR_ERR(base);
*/
void __iomem *of_io_request_and_map(struct device_node *np, int index,
- char *name)
+ const char *name)
{
struct resource res;
void __iomem *mem;
diff --git a/drivers/of/base.c b/drivers/of/base.c
index 3823edf..36536b6 100644
--- a/drivers/of/base.c
+++ b/drivers/of/base.c
@@ -32,11 +32,12 @@
LIST_HEAD(aliases_lookup);
-struct device_node *of_allnodes;
-EXPORT_SYMBOL(of_allnodes);
+struct device_node *of_root;
+EXPORT_SYMBOL(of_root);
struct device_node *of_chosen;
struct device_node *of_aliases;
struct device_node *of_stdout;
+static const char *of_stdout_options;
struct kset *of_kset;
@@ -48,7 +49,7 @@ struct kset *of_kset;
*/
DEFINE_MUTEX(of_mutex);
-/* use when traversing tree through the allnext, child, sibling,
+/* use when traversing tree through the child, sibling,
* or parent members of struct device_node.
*/
DEFINE_RAW_SPINLOCK(devtree_lock);
@@ -204,7 +205,7 @@ static int __init of_init(void)
mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */
- if (of_allnodes)
+ if (of_root)
proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base");
return 0;
@@ -245,6 +246,23 @@ struct property *of_find_property(const struct device_node *np,
}
EXPORT_SYMBOL(of_find_property);
+struct device_node *__of_find_all_nodes(struct device_node *prev)
+{
+ struct device_node *np;
+ if (!prev) {
+ np = of_root;
+ } else if (prev->child) {
+ np = prev->child;
+ } else {
+ /* Walk back up looking for a sibling, or the end of the structure */
+ np = prev;
+ while (np->parent && !np->sibling)
+ np = np->parent;
+ np = np->sibling; /* Might be null at the end of the tree */
+ }
+ return np;
+}
+
/**
* of_find_all_nodes - Get next node in global list
* @prev: Previous node or NULL to start iteration
@@ -259,10 +277,8 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np = prev ? prev->allnext : of_allnodes;
- for (; np != NULL; np = np->allnext)
- if (of_node_get(np))
- break;
+ np = __of_find_all_nodes(prev);
+ of_node_get(np);
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
@@ -485,7 +501,7 @@ EXPORT_SYMBOL(of_device_is_compatible);
* of_machine_is_compatible - Test root of device tree for a given compatible value
* @compat: compatible string to look for in root node's compatible property.
*
- * Returns true if the root node has the given value in its
+ * Returns a positive integer if the root node has the given value in its
* compatible property.
*/
int of_machine_is_compatible(const char *compat)
@@ -507,27 +523,27 @@ EXPORT_SYMBOL(of_machine_is_compatible);
*
* @device: Node to check for availability, with locks already held
*
- * Returns 1 if the status property is absent or set to "okay" or "ok",
- * 0 otherwise
+ * Returns true if the status property is absent or set to "okay" or "ok",
+ * false otherwise
*/
-static int __of_device_is_available(const struct device_node *device)
+static bool __of_device_is_available(const struct device_node *device)
{
const char *status;
int statlen;
if (!device)
- return 0;
+ return false;
status = __of_get_property(device, "status", &statlen);
if (status == NULL)
- return 1;
+ return true;
if (statlen > 0) {
if (!strcmp(status, "okay") || !strcmp(status, "ok"))
- return 1;
+ return true;
}
- return 0;
+ return false;
}
/**
@@ -535,13 +551,13 @@ static int __of_device_is_available(const struct device_node *device)
*
* @device: Node to check for availability
*
- * Returns 1 if the status property is absent or set to "okay" or "ok",
- * 0 otherwise
+ * Returns true if the status property is absent or set to "okay" or "ok",
+ * false otherwise
*/
-int of_device_is_available(const struct device_node *device)
+bool of_device_is_available(const struct device_node *device)
{
unsigned long flags;
- int res;
+ bool res;
raw_spin_lock_irqsave(&devtree_lock, flags);
res = __of_device_is_available(device);
@@ -577,9 +593,9 @@ EXPORT_SYMBOL(of_get_parent);
* of_get_next_parent - Iterate to a node's parent
* @node: Node to get parent of
*
- * This is like of_get_parent() except that it drops the
- * refcount on the passed node, making it suitable for iterating
- * through a node's parents.
+ * This is like of_get_parent() except that it drops the
+ * refcount on the passed node, making it suitable for iterating
+ * through a node's parents.
*
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
@@ -699,10 +715,15 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
{
struct device_node *child;
int len = strchrnul(path, '/') - path;
+ int term;
if (!len)
return NULL;
+ term = strchrnul(path, ':') - path;
+ if (term < len)
+ len = term;
+
__for_each_child_of_node(parent, child) {
const char *name = strrchr(child->full_name, '/');
if (WARN(!name, "malformed device_node %s\n", child->full_name))
@@ -715,11 +736,14 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
}
/**
- * of_find_node_by_path - Find a node matching a full OF path
+ * of_find_node_opts_by_path - Find a node matching a full OF path
* @path: Either the full path to match, or if the path does not
* start with '/', the name of a property of the /aliases
* node (an alias). In the case of an alias, the node
* matching the alias' value will be returned.
+ * @opts: Address of a pointer into which to store the start of
+ * an options string appended to the end of the path with
+ * a ':' separator.
*
* Valid paths:
* /foo/bar Full path
@@ -729,19 +753,23 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
* Returns a node pointer with refcount incremented, use
* of_node_put() on it when done.
*/
-struct device_node *of_find_node_by_path(const char *path)
+struct device_node *of_find_node_opts_by_path(const char *path, const char **opts)
{
struct device_node *np = NULL;
struct property *pp;
unsigned long flags;
+ const char *separator = strchr(path, ':');
+
+ if (opts)
+ *opts = separator ? separator + 1 : NULL;
if (strcmp(path, "/") == 0)
- return of_node_get(of_allnodes);
+ return of_node_get(of_root);
/* The path could begin with an alias */
if (*path != '/') {
char *p = strchrnul(path, '/');
- int len = p - path;
+ int len = separator ? separator - path : p - path;
/* of_aliases must not be NULL */
if (!of_aliases)
@@ -761,7 +789,7 @@ struct device_node *of_find_node_by_path(const char *path)
/* Step down the tree matching path components */
raw_spin_lock_irqsave(&devtree_lock, flags);
if (!np)
- np = of_node_get(of_allnodes);
+ np = of_node_get(of_root);
while (np && *path == '/') {
path++; /* Increment past '/' delimiter */
np = __of_find_node_by_path(np, path);
@@ -770,7 +798,7 @@ struct device_node *of_find_node_by_path(const char *path)
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
}
-EXPORT_SYMBOL(of_find_node_by_path);
+EXPORT_SYMBOL(of_find_node_opts_by_path);
/**
* of_find_node_by_name - Find a node by its "name" property
@@ -790,8 +818,7 @@ struct device_node *of_find_node_by_name(struct device_node *from,
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np = from ? from->allnext : of_allnodes;
- for (; np; np = np->allnext)
+ for_each_of_allnodes_from(from, np)
if (np->name && (of_node_cmp(np->name, name) == 0)
&& of_node_get(np))
break;
@@ -820,8 +847,7 @@ struct device_node *of_find_node_by_type(struct device_node *from,
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np = from ? from->allnext : of_allnodes;
- for (; np; np = np->allnext)
+ for_each_of_allnodes_from(from, np)
if (np->type && (of_node_cmp(np->type, type) == 0)
&& of_node_get(np))
break;
@@ -852,12 +878,10 @@ struct device_node *of_find_compatible_node(struct device_node *from,
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np = from ? from->allnext : of_allnodes;
- for (; np; np = np->allnext) {
+ for_each_of_allnodes_from(from, np)
if (__of_device_is_compatible(np, compatible, type, NULL) &&
of_node_get(np))
break;
- }
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return np;
@@ -884,8 +908,7 @@ struct device_node *of_find_node_with_property(struct device_node *from,
unsigned long flags;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np = from ? from->allnext : of_allnodes;
- for (; np; np = np->allnext) {
+ for_each_of_allnodes_from(from, np) {
for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, prop_name) == 0) {
of_node_get(np);
@@ -923,7 +946,7 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches,
}
/**
- * of_match_node - Tell if an device_node has a matching of_match structure
+ * of_match_node - Tell if a device_node has a matching of_match structure
* @matches: array of of device match structures to search in
* @node: the of device structure to match against
*
@@ -967,8 +990,7 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
*match = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
- np = from ? from->allnext : of_allnodes;
- for (; np; np = np->allnext) {
+ for_each_of_allnodes_from(from, np) {
m = __of_match_node(matches, np);
if (m && of_node_get(np)) {
if (match)
@@ -1025,7 +1047,7 @@ struct device_node *of_find_node_by_phandle(phandle handle)
return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
- for (np = of_allnodes; np; np = np->allnext)
+ for_each_of_allnodes(np)
if (np->phandle == handle)
break;
of_node_get(np);
@@ -1250,6 +1272,39 @@ int of_property_read_u64(const struct device_node *np, const char *propname,
EXPORT_SYMBOL_GPL(of_property_read_u64);
/**
+ * of_property_read_u64_array - Find and read an array of 64 bit integers
+ * from a property.
+ *
+ * @np: device node from which the property value is to be read.
+ * @propname: name of the property to be searched.
+ * @out_values: pointer to return value, modified only if return value is 0.
+ * @sz: number of array elements to read
+ *
+ * Search for a property in a device node and read 64-bit value(s) from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_values is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_array(const struct device_node *np,
+ const char *propname, u64 *out_values,
+ size_t sz)
+{
+ const __be32 *val = of_find_property_value_of_size(np, propname,
+ (sz * sizeof(*out_values)));
+
+ if (IS_ERR(val))
+ return PTR_ERR(val);
+
+ while (sz--) {
+ *out_values++ = of_read_number(val, 2);
+ val += 2;
+ }
+ return 0;
+}
+
+/**
* of_property_read_string - Find and read a string from a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
@@ -1317,7 +1372,7 @@ int of_property_match_string(struct device_node *np, const char *propname,
EXPORT_SYMBOL_GPL(of_property_match_string);
/**
- * of_property_read_string_util() - Utility helper for parsing string properties
+ * of_property_read_string_helper() - Utility helper for parsing string properties
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
* @out_strs: output array of string pointers.
@@ -1516,21 +1571,21 @@ EXPORT_SYMBOL(of_parse_phandle);
* Returns 0 on success and fills out_args, on error returns appropriate
* errno value.
*
- * Caller is responsible to call of_node_put() on the returned out_args->node
+ * Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
* Example:
*
* phandle1: node1 {
- * #list-cells = <2>;
+ * #list-cells = <2>;
* }
*
* phandle2: node2 {
- * #list-cells = <1>;
+ * #list-cells = <1>;
* }
*
* node3 {
- * list = <&phandle1 1 2 &phandle2 3>;
+ * list = <&phandle1 1 2 &phandle2 3>;
* }
*
* To get a device_node of the `node2' node you may call this:
@@ -1559,7 +1614,7 @@ EXPORT_SYMBOL(of_parse_phandle_with_args);
* Returns 0 on success and fills out_args, on error returns appropriate
* errno value.
*
- * Caller is responsible to call of_node_put() on the returned out_args->node
+ * Caller is responsible to call of_node_put() on the returned out_args->np
* pointer.
*
* Example:
@@ -1571,7 +1626,7 @@ EXPORT_SYMBOL(of_parse_phandle_with_args);
* }
*
* node3 {
- * list = <&phandle1 0 2 &phandle2 2 3>;
+ * list = <&phandle1 0 2 &phandle2 2 3>;
* }
*
* To get a device_node of the `node2' node you may call this:
@@ -1805,14 +1860,14 @@ static void of_alias_add(struct alias_prop *ap, struct device_node *np,
}
/**
- * of_alias_scan - Scan all properties of 'aliases' node
+ * of_alias_scan - Scan all properties of the 'aliases' node
*
- * The function scans all the properties of 'aliases' node and populate
- * the the global lookup table with the properties. It returns the
- * number of alias_prop found, or error code in error case.
+ * The function scans all the properties of the 'aliases' node and populates
+ * the global lookup table with the properties. It returns the
+ * number of alias properties found, or an error code in case of failure.
*
* @dt_alloc: An allocator that provides a virtual address to memory
- * for the resulting tree
+ * for storing the resulting tree
*/
void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
{
@@ -1831,7 +1886,7 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
if (IS_ENABLED(CONFIG_PPC) && !name)
name = of_get_property(of_aliases, "stdout", NULL);
if (name)
- of_stdout = of_find_node_by_path(name);
+ of_stdout = of_find_node_opts_by_path(name, &of_stdout_options);
}
if (!of_aliases)
@@ -1957,7 +2012,8 @@ bool of_console_check(struct device_node *dn, char *name, int index)
{
if (!dn || dn != of_stdout || console_set_on_cmdline)
return false;
- return !add_preferred_console(name, index, NULL);
+ return !add_preferred_console(name, index,
+ kstrdup(of_stdout_options, GFP_KERNEL));
}
EXPORT_SYMBOL_GPL(of_console_check);
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index d4994177..3351ef4 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -77,18 +77,132 @@ int of_reconfig_notifier_unregister(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister);
-int of_reconfig_notify(unsigned long action, void *p)
+#ifdef DEBUG
+const char *action_names[] = {
+ [OF_RECONFIG_ATTACH_NODE] = "ATTACH_NODE",
+ [OF_RECONFIG_DETACH_NODE] = "DETACH_NODE",
+ [OF_RECONFIG_ADD_PROPERTY] = "ADD_PROPERTY",
+ [OF_RECONFIG_REMOVE_PROPERTY] = "REMOVE_PROPERTY",
+ [OF_RECONFIG_UPDATE_PROPERTY] = "UPDATE_PROPERTY",
+};
+#endif
+
+int of_reconfig_notify(unsigned long action, struct of_reconfig_data *p)
{
int rc;
+#ifdef DEBUG
+ struct of_reconfig_data *pr = p;
+
+ switch (action) {
+ case OF_RECONFIG_ATTACH_NODE:
+ case OF_RECONFIG_DETACH_NODE:
+ pr_debug("of/notify %-15s %s\n", action_names[action],
+ pr->dn->full_name);
+ break;
+ case OF_RECONFIG_ADD_PROPERTY:
+ case OF_RECONFIG_REMOVE_PROPERTY:
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ pr_debug("of/notify %-15s %s:%s\n", action_names[action],
+ pr->dn->full_name, pr->prop->name);
+ break;
+ }
+#endif
rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p);
return notifier_to_errno(rc);
}
+/*
+ * of_reconfig_get_state_change() - Returns new state of device
+ * @action - action of the of notifier
+ * @arg - argument of the of notifier
+ *
+ * Returns the new state of a device based on the notifier used.
+ * Returns 0 on device going from enabled to disabled, 1 on device
+ * going from disabled to enabled and -1 on no change.
+ */
+int of_reconfig_get_state_change(unsigned long action, struct of_reconfig_data *pr)
+{
+ struct property *prop, *old_prop = NULL;
+ int is_status, status_state, old_status_state, prev_state, new_state;
+
+ /* figure out if a device should be created or destroyed */
+ switch (action) {
+ case OF_RECONFIG_ATTACH_NODE:
+ case OF_RECONFIG_DETACH_NODE:
+ prop = of_find_property(pr->dn, "status", NULL);
+ break;
+ case OF_RECONFIG_ADD_PROPERTY:
+ case OF_RECONFIG_REMOVE_PROPERTY:
+ prop = pr->prop;
+ break;
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ prop = pr->prop;
+ old_prop = pr->old_prop;
+ break;
+ default:
+ return OF_RECONFIG_NO_CHANGE;
+ }
+
+ is_status = 0;
+ status_state = -1;
+ old_status_state = -1;
+ prev_state = -1;
+ new_state = -1;
+
+ if (prop && !strcmp(prop->name, "status")) {
+ is_status = 1;
+ status_state = !strcmp(prop->value, "okay") ||
+ !strcmp(prop->value, "ok");
+ if (old_prop)
+ old_status_state = !strcmp(old_prop->value, "okay") ||
+ !strcmp(old_prop->value, "ok");
+ }
+
+ switch (action) {
+ case OF_RECONFIG_ATTACH_NODE:
+ prev_state = 0;
+ /* -1 & 0 status either missing or okay */
+ new_state = status_state != 0;
+ break;
+ case OF_RECONFIG_DETACH_NODE:
+ /* -1 & 0 status either missing or okay */
+ prev_state = status_state != 0;
+ new_state = 0;
+ break;
+ case OF_RECONFIG_ADD_PROPERTY:
+ if (is_status) {
+ /* no status property -> enabled (legacy) */
+ prev_state = 1;
+ new_state = status_state;
+ }
+ break;
+ case OF_RECONFIG_REMOVE_PROPERTY:
+ if (is_status) {
+ prev_state = status_state;
+ /* no status property -> enabled (legacy) */
+ new_state = 1;
+ }
+ break;
+ case OF_RECONFIG_UPDATE_PROPERTY:
+ if (is_status) {
+ prev_state = old_status_state != 0;
+ new_state = status_state != 0;
+ }
+ break;
+ }
+
+ if (prev_state == new_state)
+ return OF_RECONFIG_NO_CHANGE;
+
+ return new_state ? OF_RECONFIG_CHANGE_ADD : OF_RECONFIG_CHANGE_REMOVE;
+}
+EXPORT_SYMBOL_GPL(of_reconfig_get_state_change);
+
int of_property_notify(int action, struct device_node *np,
struct property *prop, struct property *oldprop)
{
- struct of_prop_reconfig pr;
+ struct of_reconfig_data pr;
/* only call notifiers if the node is attached */
if (!of_node_is_attached(np))
@@ -117,8 +231,6 @@ void __of_attach_node(struct device_node *np)
np->child = NULL;
np->sibling = np->parent->child;
- np->allnext = np->parent->allnext;
- np->parent->allnext = np;
np->parent->child = np;
of_node_clear_flag(np, OF_DETACHED);
}
@@ -128,8 +240,12 @@ void __of_attach_node(struct device_node *np)
*/
int of_attach_node(struct device_node *np)
{
+ struct of_reconfig_data rd;
unsigned long flags;
+ memset(&rd, 0, sizeof(rd));
+ rd.dn = np;
+
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
__of_attach_node(np);
@@ -138,7 +254,7 @@ int of_attach_node(struct device_node *np)
__of_attach_node_sysfs(np);
mutex_unlock(&of_mutex);
- of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np);
+ of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, &rd);
return 0;
}
@@ -154,17 +270,6 @@ void __of_detach_node(struct device_node *np)
if (WARN_ON(!parent))
return;
- if (of_allnodes == np)
- of_allnodes = np->allnext;
- else {
- struct device_node *prev;
- for (prev = of_allnodes;
- prev->allnext != np;
- prev = prev->allnext)
- ;
- prev->allnext = np->allnext;
- }
-
if (parent->child == np)
parent->child = np->sibling;
else {
@@ -187,9 +292,13 @@ void __of_detach_node(struct device_node *np)
*/
int of_detach_node(struct device_node *np)
{
+ struct of_reconfig_data rd;
unsigned long flags;
int rc = 0;
+ memset(&rd, 0, sizeof(rd));
+ rd.dn = np;
+
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
__of_detach_node(np);
@@ -198,7 +307,7 @@ int of_detach_node(struct device_node *np)
__of_detach_node_sysfs(np);
mutex_unlock(&of_mutex);
- of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
+ of_reconfig_notify(OF_RECONFIG_DETACH_NODE, &rd);
return rc;
}
@@ -285,36 +394,54 @@ struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags)
}
/**
- * __of_node_alloc() - Create an empty device node dynamically.
- * @full_name: Full name of the new device node
- * @allocflags: Allocation flags (typically pass GFP_KERNEL)
+ * __of_node_dup() - Duplicate or create an empty device node dynamically.
+ * @fmt: Format string (plus vargs) for new full name of the device node
*
- * Create an empty device tree node, suitable for further modification.
- * The node data are dynamically allocated and all the node flags
- * have the OF_DYNAMIC & OF_DETACHED bits set.
- * Returns the newly allocated node or NULL on out of memory error.
+ * Create an device tree node, either by duplicating an empty node or by allocating
+ * an empty one suitable for further modification. The node data are
+ * dynamically allocated and all the node flags have the OF_DYNAMIC &
+ * OF_DETACHED bits set. Returns the newly allocated node or NULL on out of
+ * memory error.
*/
-struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags)
+struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...)
{
+ va_list vargs;
struct device_node *node;
- node = kzalloc(sizeof(*node), allocflags);
+ node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node)
return NULL;
+ va_start(vargs, fmt);
+ node->full_name = kvasprintf(GFP_KERNEL, fmt, vargs);
+ va_end(vargs);
+ if (!node->full_name) {
+ kfree(node);
+ return NULL;
+ }
- node->full_name = kstrdup(full_name, allocflags);
of_node_set_flag(node, OF_DYNAMIC);
of_node_set_flag(node, OF_DETACHED);
- if (!node->full_name)
- goto err_free;
-
of_node_init(node);
+ /* Iterate over and duplicate all properties */
+ if (np) {
+ struct property *pp, *new_pp;
+ for_each_property_of_node(np, pp) {
+ new_pp = __of_prop_dup(pp, GFP_KERNEL);
+ if (!new_pp)
+ goto err_prop;
+ if (__of_add_property(node, new_pp)) {
+ kfree(new_pp->name);
+ kfree(new_pp->value);
+ kfree(new_pp);
+ goto err_prop;
+ }
+ }
+ }
return node;
- err_free:
- kfree(node->full_name);
- kfree(node);
+ err_prop:
+ of_node_put(node); /* Frees the node and properties */
return NULL;
}
@@ -330,27 +457,15 @@ static void __of_changeset_entry_dump(struct of_changeset_entry *ce)
{
switch (ce->action) {
case OF_RECONFIG_ADD_PROPERTY:
- pr_debug("%p: %s %s/%s\n",
- ce, "ADD_PROPERTY ", ce->np->full_name,
- ce->prop->name);
- break;
case OF_RECONFIG_REMOVE_PROPERTY:
- pr_debug("%p: %s %s/%s\n",
- ce, "REMOVE_PROPERTY", ce->np->full_name,
- ce->prop->name);
- break;
case OF_RECONFIG_UPDATE_PROPERTY:
- pr_debug("%p: %s %s/%s\n",
- ce, "UPDATE_PROPERTY", ce->np->full_name,
- ce->prop->name);
+ pr_debug("of/cset<%p> %-15s %s/%s\n", ce, action_names[ce->action],
+ ce->np->full_name, ce->prop->name);
break;
case OF_RECONFIG_ATTACH_NODE:
- pr_debug("%p: %s %s\n",
- ce, "ATTACH_NODE ", ce->np->full_name);
- break;
case OF_RECONFIG_DETACH_NODE:
- pr_debug("%p: %s %s\n",
- ce, "DETACH_NODE ", ce->np->full_name);
+ pr_debug("of/cset<%p> %-15s %s\n", ce, action_names[ce->action],
+ ce->np->full_name);
break;
}
}
@@ -388,6 +503,7 @@ static void __of_changeset_entry_invert(struct of_changeset_entry *ce,
static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert)
{
+ struct of_reconfig_data rd;
struct of_changeset_entry ce_inverted;
int ret;
@@ -399,7 +515,9 @@ static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool reve
switch (ce->action) {
case OF_RECONFIG_ATTACH_NODE:
case OF_RECONFIG_DETACH_NODE:
- ret = of_reconfig_notify(ce->action, ce->np);
+ memset(&rd, 0, sizeof(rd));
+ rd.dn = ce->np;
+ ret = of_reconfig_notify(ce->action, &rd);
break;
case OF_RECONFIG_ADD_PROPERTY:
case OF_RECONFIG_REMOVE_PROPERTY:
diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
index d134710..5100742 100644
--- a/drivers/of/fdt.c
+++ b/drivers/of/fdt.c
@@ -9,6 +9,7 @@
* version 2 as published by the Free Software Foundation.
*/
+#include <linux/crc32.h>
#include <linux/kernel.h>
#include <linux/initrd.h>
#include <linux/memblock.h>
@@ -22,6 +23,7 @@
#include <linux/libfdt.h>
#include <linux/debugfs.h>
#include <linux/serial_core.h>
+#include <linux/sysfs.h>
#include <asm/setup.h> /* for COMMAND_LINE_SIZE */
#include <asm/page.h>
@@ -145,15 +147,15 @@ static void *unflatten_dt_alloc(void **mem, unsigned long size,
* @mem: Memory chunk to use for allocating device nodes and properties
* @p: pointer to node in flat tree
* @dad: Parent struct device_node
- * @allnextpp: pointer to ->allnext from last allocated device_node
* @fpsize: Size of the node path up at the current depth.
*/
static void * unflatten_dt_node(void *blob,
void *mem,
int *poffset,
struct device_node *dad,
- struct device_node ***allnextpp,
- unsigned long fpsize)
+ struct device_node **nodepp,
+ unsigned long fpsize,
+ bool dryrun)
{
const __be32 *p;
struct device_node *np;
@@ -200,7 +202,7 @@ static void * unflatten_dt_node(void *blob,
np = unflatten_dt_alloc(&mem, sizeof(struct device_node) + allocl,
__alignof__(struct device_node));
- if (allnextpp) {
+ if (!dryrun) {
char *fn;
of_node_init(np);
np->full_name = fn = ((char *)np) + sizeof(*np);
@@ -222,16 +224,10 @@ static void * unflatten_dt_node(void *blob,
memcpy(fn, pathp, l);
prev_pp = &np->properties;
- **allnextpp = np;
- *allnextpp = &np->allnext;
if (dad != NULL) {
np->parent = dad;
- /* we temporarily use the next field as `last_child'*/
- if (dad->next == NULL)
- dad->child = np;
- else
- dad->next->sibling = np;
- dad->next = np;
+ np->sibling = dad->child;
+ dad->child = np;
}
}
/* process properties */
@@ -254,7 +250,7 @@ static void * unflatten_dt_node(void *blob,
has_name = 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property),
__alignof__(struct property));
- if (allnextpp) {
+ if (!dryrun) {
/* We accept flattened tree phandles either in
* ePAPR-style "phandle" properties, or the
* legacy "linux,phandle" properties. If both
@@ -296,7 +292,7 @@ static void * unflatten_dt_node(void *blob,
sz = (pa - ps) + 1;
pp = unflatten_dt_alloc(&mem, sizeof(struct property) + sz,
__alignof__(struct property));
- if (allnextpp) {
+ if (!dryrun) {
pp->name = "name";
pp->length = sz;
pp->value = pp + 1;
@@ -308,7 +304,7 @@ static void * unflatten_dt_node(void *blob,
(char *)pp->value);
}
}
- if (allnextpp) {
+ if (!dryrun) {
*prev_pp = NULL;
np->name = of_get_property(np, "name", NULL);
np->type = of_get_property(np, "device_type", NULL);
@@ -324,12 +320,30 @@ static void * unflatten_dt_node(void *blob,
if (depth < 0)
depth = 0;
while (*poffset > 0 && depth > old_depth)
- mem = unflatten_dt_node(blob, mem, poffset, np, allnextpp,
- fpsize);
+ mem = unflatten_dt_node(blob, mem, poffset, np, NULL,
+ fpsize, dryrun);
if (*poffset < 0 && *poffset != -FDT_ERR_NOTFOUND)
pr_err("unflatten: error %d processing FDT\n", *poffset);
+ /*
+ * Reverse the child list. Some drivers assumes node order matches .dts
+ * node order
+ */
+ if (!dryrun && np->child) {
+ struct device_node *child = np->child;
+ np->child = NULL;
+ while (child) {
+ struct device_node *next = child->sibling;
+ child->sibling = np->child;
+ np->child = child;
+ child = next;
+ }
+ }
+
+ if (nodepp)
+ *nodepp = np;
+
return mem;
}
@@ -352,7 +366,6 @@ static void __unflatten_device_tree(void *blob,
unsigned long size;
int start;
void *mem;
- struct device_node **allnextp = mynodes;
pr_debug(" -> unflatten_device_tree()\n");
@@ -373,7 +386,7 @@ static void __unflatten_device_tree(void *blob,
/* First pass, scan for size */
start = 0;
- size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0);
+ size = (unsigned long)unflatten_dt_node(blob, NULL, &start, NULL, NULL, 0, true);
size = ALIGN(size, 4);
pr_debug(" size is %lx, allocating...\n", size);
@@ -388,11 +401,10 @@ static void __unflatten_device_tree(void *blob,
/* Second pass, do actual unflattening */
start = 0;
- unflatten_dt_node(blob, mem, &start, NULL, &allnextp, 0);
+ unflatten_dt_node(blob, mem, &start, NULL, mynodes, 0, false);
if (be32_to_cpup(mem + size) != 0xdeadbeef)
pr_warning("End of tree marker overwritten: %08x\n",
be32_to_cpup(mem + size));
- *allnextp = NULL;
pr_debug(" <- unflatten_device_tree()\n");
}
@@ -425,6 +437,8 @@ void *initial_boot_params;
#ifdef CONFIG_OF_EARLY_FLATTREE
+static u32 of_fdt_crc32;
+
/**
* res_mem_reserve_reg() - reserve all memory described in 'reg' property
*/
@@ -930,6 +944,11 @@ void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size)
const u64 phys_offset = __pa(PAGE_OFFSET);
if (!PAGE_ALIGNED(base)) {
+ if (size < PAGE_SIZE - (base & ~PAGE_MASK)) {
+ pr_warn("Ignoring memory block 0x%llx - 0x%llx\n",
+ base, base + size);
+ return;
+ }
size -= PAGE_SIZE - (base & ~PAGE_MASK);
base = PAGE_ALIGN(base);
}
@@ -992,15 +1011,14 @@ bool __init early_init_dt_verify(void *params)
if (!params)
return false;
- /* Setup flat device-tree pointer */
- initial_boot_params = params;
-
/* check device tree validity */
- if (fdt_check_header(params)) {
- initial_boot_params = NULL;
+ if (fdt_check_header(params))
return false;
- }
+ /* Setup flat device-tree pointer */
+ initial_boot_params = params;
+ of_fdt_crc32 = crc32_be(~0, initial_boot_params,
+ fdt_totalsize(initial_boot_params));
return true;
}
@@ -1039,7 +1057,7 @@ bool __init early_init_dt_scan(void *params)
*/
void __init unflatten_device_tree(void)
{
- __unflatten_device_tree(initial_boot_params, &of_allnodes,
+ __unflatten_device_tree(initial_boot_params, &of_root,
early_init_dt_alloc_memory_arch);
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
@@ -1078,27 +1096,32 @@ void __init unflatten_and_copy_device_tree(void)
unflatten_device_tree();
}
-#if defined(CONFIG_DEBUG_FS) && defined(DEBUG)
-static struct debugfs_blob_wrapper flat_dt_blob;
-
-static int __init of_flat_dt_debugfs_export_fdt(void)
+#ifdef CONFIG_SYSFS
+static ssize_t of_fdt_raw_read(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *bin_attr,
+ char *buf, loff_t off, size_t count)
{
- struct dentry *d = debugfs_create_dir("device-tree", NULL);
-
- if (!d)
- return -ENOENT;
+ memcpy(buf, initial_boot_params + off, count);
+ return count;
+}
- flat_dt_blob.data = initial_boot_params;
- flat_dt_blob.size = fdt_totalsize(initial_boot_params);
+static int __init of_fdt_raw_init(void)
+{
+ static struct bin_attribute of_fdt_raw_attr =
+ __BIN_ATTR(fdt, S_IRUSR, of_fdt_raw_read, NULL, 0);
- d = debugfs_create_blob("flat-device-tree", S_IFREG | S_IRUSR,
- d, &flat_dt_blob);
- if (!d)
- return -ENOENT;
+ if (!initial_boot_params)
+ return 0;
- return 0;
+ if (of_fdt_crc32 != crc32_be(~0, initial_boot_params,
+ fdt_totalsize(initial_boot_params))) {
+ pr_warn("fdt: not creating '/sys/firmware/fdt': CRC check failed\n");
+ return 0;
+ }
+ of_fdt_raw_attr.size = fdt_totalsize(initial_boot_params);
+ return sysfs_create_bin_file(firmware_kobj, &of_fdt_raw_attr);
}
-module_init(of_flat_dt_debugfs_export_fdt);
+late_initcall(of_fdt_raw_init);
#endif
#endif /* CONFIG_OF_EARLY_FLATTREE */
diff --git a/drivers/of/of_pci.c b/drivers/of/of_pci.c
index 8882b46..88471d3 100644
--- a/drivers/of/of_pci.c
+++ b/drivers/of/of_pci.c
@@ -236,7 +236,7 @@ EXPORT_SYMBOL_GPL(of_pci_get_host_bridge_resources);
static LIST_HEAD(of_pci_msi_chip_list);
static DEFINE_MUTEX(of_pci_msi_chip_mutex);
-int of_pci_msi_chip_add(struct msi_chip *chip)
+int of_pci_msi_chip_add(struct msi_controller *chip)
{
if (!of_property_read_bool(chip->of_node, "msi-controller"))
return -EINVAL;
@@ -249,7 +249,7 @@ int of_pci_msi_chip_add(struct msi_chip *chip)
}
EXPORT_SYMBOL_GPL(of_pci_msi_chip_add);
-void of_pci_msi_chip_remove(struct msi_chip *chip)
+void of_pci_msi_chip_remove(struct msi_controller *chip)
{
mutex_lock(&of_pci_msi_chip_mutex);
list_del(&chip->list);
@@ -257,9 +257,9 @@ void of_pci_msi_chip_remove(struct msi_chip *chip)
}
EXPORT_SYMBOL_GPL(of_pci_msi_chip_remove);
-struct msi_chip *of_pci_find_msi_chip_by_node(struct device_node *of_node)
+struct msi_controller *of_pci_find_msi_chip_by_node(struct device_node *of_node)
{
- struct msi_chip *c;
+ struct msi_controller *c;
mutex_lock(&of_pci_msi_chip_mutex);
list_for_each_entry(c, &of_pci_msi_chip_list, list) {
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index 858e0a5..8e882e7 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -61,7 +61,7 @@ static inline int of_property_notify(int action, struct device_node *np,
* own the devtree lock or work on detached trees only.
*/
struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags);
-struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags);
+__printf(2, 3) struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...);
extern const void *__of_get_property(const struct device_node *np,
const char *name, int *lenp);
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
new file mode 100644
index 0000000..ea63fbd2
--- /dev/null
+++ b/drivers/of/overlay.c
@@ -0,0 +1,562 @@
+/*
+ * Functions for working with device tree overlays
+ *
+ * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
+ * Copyright (C) 2012 Texas Instruments Inc.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ */
+#undef DEBUG
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/string.h>
+#include <linux/ctype.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/err.h>
+
+#include "of_private.h"
+
+/**
+ * struct of_overlay_info - Holds a single overlay info
+ * @target: target of the overlay operation
+ * @overlay: pointer to the overlay contents node
+ *
+ * Holds a single overlay state, including all the overlay logs &
+ * records.
+ */
+struct of_overlay_info {
+ struct device_node *target;
+ struct device_node *overlay;
+};
+
+/**
+ * struct of_overlay - Holds a complete overlay transaction
+ * @node: List on which we are located
+ * @count: Count of ovinfo structures
+ * @ovinfo_tab: Overlay info table (count sized)
+ * @cset: Changeset to be used
+ *
+ * Holds a complete overlay transaction
+ */
+struct of_overlay {
+ int id;
+ struct list_head node;
+ int count;
+ struct of_overlay_info *ovinfo_tab;
+ struct of_changeset cset;
+};
+
+static int of_overlay_apply_one(struct of_overlay *ov,
+ struct device_node *target, const struct device_node *overlay);
+
+static int of_overlay_apply_single_property(struct of_overlay *ov,
+ struct device_node *target, struct property *prop)
+{
+ struct property *propn, *tprop;
+
+ /* NOTE: Multiple changes of single properties not supported */
+ tprop = of_find_property(target, prop->name, NULL);
+
+ /* special properties are not meant to be updated (silent NOP) */
+ if (of_prop_cmp(prop->name, "name") == 0 ||
+ of_prop_cmp(prop->name, "phandle") == 0 ||
+ of_prop_cmp(prop->name, "linux,phandle") == 0)
+ return 0;
+
+ propn = __of_prop_dup(prop, GFP_KERNEL);
+ if (propn == NULL)
+ return -ENOMEM;
+
+ /* not found? add */
+ if (tprop == NULL)
+ return of_changeset_add_property(&ov->cset, target, propn);
+
+ /* found? update */
+ return of_changeset_update_property(&ov->cset, target, propn);
+}
+
+static int of_overlay_apply_single_device_node(struct of_overlay *ov,
+ struct device_node *target, struct device_node *child)
+{
+ const char *cname;
+ struct device_node *tchild, *grandchild;
+ int ret = 0;
+
+ cname = kbasename(child->full_name);
+ if (cname == NULL)
+ return -ENOMEM;
+
+ /* NOTE: Multiple mods of created nodes not supported */
+ tchild = of_get_child_by_name(target, cname);
+ if (tchild != NULL) {
+ /* apply overlay recursively */
+ ret = of_overlay_apply_one(ov, tchild, child);
+ of_node_put(tchild);
+ } else {
+ /* create empty tree as a target */
+ tchild = __of_node_dup(child, "%s/%s", target->full_name, cname);
+ if (!tchild)
+ return -ENOMEM;
+
+ /* point to parent */
+ tchild->parent = target;
+
+ ret = of_changeset_attach_node(&ov->cset, tchild);
+ if (ret)
+ return ret;
+
+ ret = of_overlay_apply_one(ov, tchild, child);
+ if (ret)
+ return ret;
+
+ /* The properties are already copied, now do the child nodes */
+ for_each_child_of_node(child, grandchild) {
+ ret = of_overlay_apply_single_device_node(ov, tchild, grandchild);
+ if (ret) {
+ pr_err("%s: Failed to apply single node @%s/%s\n",
+ __func__, tchild->full_name,
+ grandchild->name);
+ return ret;
+ }
+ }
+ }
+
+ return ret;
+}
+
+/*
+ * Apply a single overlay node recursively.
+ *
+ * Note that the in case of an error the target node is left
+ * in a inconsistent state. Error recovery should be performed
+ * by using the changeset.
+ */
+static int of_overlay_apply_one(struct of_overlay *ov,
+ struct device_node *target, const struct device_node *overlay)
+{
+ struct device_node *child;
+ struct property *prop;
+ int ret;
+
+ for_each_property_of_node(overlay, prop) {
+ ret = of_overlay_apply_single_property(ov, target, prop);
+ if (ret) {
+ pr_err("%s: Failed to apply prop @%s/%s\n",
+ __func__, target->full_name, prop->name);
+ return ret;
+ }
+ }
+
+ for_each_child_of_node(overlay, child) {
+ ret = of_overlay_apply_single_device_node(ov, target, child);
+ if (ret != 0) {
+ pr_err("%s: Failed to apply single node @%s/%s\n",
+ __func__, target->full_name,
+ child->name);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * of_overlay_apply() - Apply @count overlays pointed at by @ovinfo_tab
+ * @ov: Overlay to apply
+ *
+ * Applies the overlays given, while handling all error conditions
+ * appropriately. Either the operation succeeds, or if it fails the
+ * live tree is reverted to the state before the attempt.
+ * Returns 0, or an error if the overlay attempt failed.
+ */
+static int of_overlay_apply(struct of_overlay *ov)
+{
+ int i, err;
+
+ /* first we apply the overlays atomically */
+ for (i = 0; i < ov->count; i++) {
+ struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
+
+ err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay);
+ if (err != 0) {
+ pr_err("%s: overlay failed '%s'\n",
+ __func__, ovinfo->target->full_name);
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Find the target node using a number of different strategies
+ * in order of preference
+ *
+ * "target" property containing the phandle of the target
+ * "target-path" property containing the path of the target
+ */
+static struct device_node *find_target_node(struct device_node *info_node)
+{
+ const char *path;
+ u32 val;
+ int ret;
+
+ /* first try to go by using the target as a phandle */
+ ret = of_property_read_u32(info_node, "target", &val);
+ if (ret == 0)
+ return of_find_node_by_phandle(val);
+
+ /* now try to locate by path */
+ ret = of_property_read_string(info_node, "target-path", &path);
+ if (ret == 0)
+ return of_find_node_by_path(path);
+
+ pr_err("%s: Failed to find target for node %p (%s)\n", __func__,
+ info_node, info_node->name);
+
+ return NULL;
+}
+
+/**
+ * of_fill_overlay_info() - Fill an overlay info structure
+ * @ov Overlay to fill
+ * @info_node: Device node containing the overlay
+ * @ovinfo: Pointer to the overlay info structure to fill
+ *
+ * Fills an overlay info structure with the overlay information
+ * from a device node. This device node must have a target property
+ * which contains a phandle of the overlay target node, and an
+ * __overlay__ child node which has the overlay contents.
+ * Both ovinfo->target & ovinfo->overlay have their references taken.
+ *
+ * Returns 0 on success, or a negative error value.
+ */
+static int of_fill_overlay_info(struct of_overlay *ov,
+ struct device_node *info_node, struct of_overlay_info *ovinfo)
+{
+ ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__");
+ if (ovinfo->overlay == NULL)
+ goto err_fail;
+
+ ovinfo->target = find_target_node(info_node);
+ if (ovinfo->target == NULL)
+ goto err_fail;
+
+ return 0;
+
+err_fail:
+ of_node_put(ovinfo->target);
+ of_node_put(ovinfo->overlay);
+
+ memset(ovinfo, 0, sizeof(*ovinfo));
+ return -EINVAL;
+}
+
+/**
+ * of_build_overlay_info() - Build an overlay info array
+ * @ov Overlay to build
+ * @tree: Device node containing all the overlays
+ *
+ * Helper function that given a tree containing overlay information,
+ * allocates and builds an overlay info array containing it, ready
+ * for use using of_overlay_apply.
+ *
+ * Returns 0 on success with the @cntp @ovinfop pointers valid,
+ * while on error a negative error value is returned.
+ */
+static int of_build_overlay_info(struct of_overlay *ov,
+ struct device_node *tree)
+{
+ struct device_node *node;
+ struct of_overlay_info *ovinfo;
+ int cnt, err;
+
+ /* worst case; every child is a node */
+ cnt = 0;
+ for_each_child_of_node(tree, node)
+ cnt++;
+
+ ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
+ if (ovinfo == NULL)
+ return -ENOMEM;
+
+ cnt = 0;
+ for_each_child_of_node(tree, node) {
+ memset(&ovinfo[cnt], 0, sizeof(*ovinfo));
+ err = of_fill_overlay_info(ov, node, &ovinfo[cnt]);
+ if (err == 0)
+ cnt++;
+ }
+
+ /* if nothing filled, return error */
+ if (cnt == 0) {
+ kfree(ovinfo);
+ return -ENODEV;
+ }
+
+ ov->count = cnt;
+ ov->ovinfo_tab = ovinfo;
+
+ return 0;
+}
+
+/**
+ * of_free_overlay_info() - Free an overlay info array
+ * @ov Overlay to free the overlay info from
+ * @ovinfo_tab: Array of overlay_info's to free
+ *
+ * Releases the memory of a previously allocated ovinfo array
+ * by of_build_overlay_info.
+ * Returns 0, or an error if the arguments are bogus.
+ */
+static int of_free_overlay_info(struct of_overlay *ov)
+{
+ struct of_overlay_info *ovinfo;
+ int i;
+
+ /* do it in reverse */
+ for (i = ov->count - 1; i >= 0; i--) {
+ ovinfo = &ov->ovinfo_tab[i];
+
+ of_node_put(ovinfo->target);
+ of_node_put(ovinfo->overlay);
+ }
+ kfree(ov->ovinfo_tab);
+
+ return 0;
+}
+
+static LIST_HEAD(ov_list);
+static DEFINE_IDR(ov_idr);
+
+/**
+ * of_overlay_create() - Create and apply an overlay
+ * @tree: Device node containing all the overlays
+ *
+ * Creates and applies an overlay while also keeping track
+ * of the overlay in a list. This list can be used to prevent
+ * illegal overlay removals.
+ *
+ * Returns the id of the created overlay, or an negative error number
+ */
+int of_overlay_create(struct device_node *tree)
+{
+ struct of_overlay *ov;
+ int err, id;
+
+ /* allocate the overlay structure */
+ ov = kzalloc(sizeof(*ov), GFP_KERNEL);
+ if (ov == NULL)
+ return -ENOMEM;
+ ov->id = -1;
+
+ INIT_LIST_HEAD(&ov->node);
+
+ of_changeset_init(&ov->cset);
+
+ mutex_lock(&of_mutex);
+
+ id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
+ if (id < 0) {
+ pr_err("%s: idr_alloc() failed for tree@%s\n",
+ __func__, tree->full_name);
+ err = id;
+ goto err_destroy_trans;
+ }
+ ov->id = id;
+
+ /* build the overlay info structures */
+ err = of_build_overlay_info(ov, tree);
+ if (err) {
+ pr_err("%s: of_build_overlay_info() failed for tree@%s\n",
+ __func__, tree->full_name);
+ goto err_free_idr;
+ }
+
+ /* apply the overlay */
+ err = of_overlay_apply(ov);
+ if (err) {
+ pr_err("%s: of_overlay_apply() failed for tree@%s\n",
+ __func__, tree->full_name);
+ goto err_abort_trans;
+ }
+
+ /* apply the changeset */
+ err = of_changeset_apply(&ov->cset);
+ if (err) {
+ pr_err("%s: of_changeset_apply() failed for tree@%s\n",
+ __func__, tree->full_name);
+ goto err_revert_overlay;
+ }
+
+ /* add to the tail of the overlay list */
+ list_add_tail(&ov->node, &ov_list);
+
+ mutex_unlock(&of_mutex);
+
+ return id;
+
+err_revert_overlay:
+err_abort_trans:
+ of_free_overlay_info(ov);
+err_free_idr:
+ idr_remove(&ov_idr, ov->id);
+err_destroy_trans:
+ of_changeset_destroy(&ov->cset);
+ kfree(ov);
+ mutex_unlock(&of_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(of_overlay_create);
+
+/* check whether the given node, lies under the given tree */
+static int overlay_subtree_check(struct device_node *tree,
+ struct device_node *dn)
+{
+ struct device_node *child;
+
+ /* match? */
+ if (tree == dn)
+ return 1;
+
+ for_each_child_of_node(tree, child) {
+ if (overlay_subtree_check(child, dn))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* check whether this overlay is the topmost */
+static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn)
+{
+ struct of_overlay *ovt;
+ struct of_changeset_entry *ce;
+
+ list_for_each_entry_reverse(ovt, &ov_list, node) {
+ /* if we hit ourselves, we're done */
+ if (ovt == ov)
+ break;
+
+ /* check against each subtree affected by this overlay */
+ list_for_each_entry(ce, &ovt->cset.entries, node) {
+ if (overlay_subtree_check(ce->np, dn)) {
+ pr_err("%s: #%d clashes #%d @%s\n",
+ __func__, ov->id, ovt->id,
+ dn->full_name);
+ return 0;
+ }
+ }
+ }
+
+ /* overlay is topmost */
+ return 1;
+}
+
+/*
+ * We can safely remove the overlay only if it's the top-most one.
+ * Newly applied overlays are inserted at the tail of the overlay list,
+ * so a top most overlay is the one that is closest to the tail.
+ *
+ * The topmost check is done by exploiting this property. For each
+ * affected device node in the log list we check if this overlay is
+ * the one closest to the tail. If another overlay has affected this
+ * device node and is closest to the tail, then removal is not permited.
+ */
+static int overlay_removal_is_ok(struct of_overlay *ov)
+{
+ struct of_changeset_entry *ce;
+
+ list_for_each_entry(ce, &ov->cset.entries, node) {
+ if (!overlay_is_topmost(ov, ce->np)) {
+ pr_err("%s: overlay #%d is not topmost\n",
+ __func__, ov->id);
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/**
+ * of_overlay_destroy() - Removes an overlay
+ * @id: Overlay id number returned by a previous call to of_overlay_create
+ *
+ * Removes an overlay if it is permissible.
+ *
+ * Returns 0 on success, or an negative error number
+ */
+int of_overlay_destroy(int id)
+{
+ struct of_overlay *ov;
+ int err;
+
+ mutex_lock(&of_mutex);
+
+ ov = idr_find(&ov_idr, id);
+ if (ov == NULL) {
+ err = -ENODEV;
+ pr_err("%s: Could not find overlay #%d\n",
+ __func__, id);
+ goto out;
+ }
+
+ /* check whether the overlay is safe to remove */
+ if (!overlay_removal_is_ok(ov)) {
+ err = -EBUSY;
+ pr_err("%s: removal check failed for overlay #%d\n",
+ __func__, id);
+ goto out;
+ }
+
+
+ list_del(&ov->node);
+ of_changeset_revert(&ov->cset);
+ of_free_overlay_info(ov);
+ idr_remove(&ov_idr, id);
+ of_changeset_destroy(&ov->cset);
+ kfree(ov);
+
+ err = 0;
+
+out:
+ mutex_unlock(&of_mutex);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(of_overlay_destroy);
+
+/**
+ * of_overlay_destroy_all() - Removes all overlays from the system
+ *
+ * Removes all overlays from the system in the correct order.
+ *
+ * Returns 0 on success, or an negative error number
+ */
+int of_overlay_destroy_all(void)
+{
+ struct of_overlay *ov, *ovn;
+
+ mutex_lock(&of_mutex);
+
+ /* the tail of list is guaranteed to be safe to remove */
+ list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
+ list_del(&ov->node);
+ of_changeset_revert(&ov->cset);
+ of_free_overlay_info(ov);
+ idr_remove(&ov_idr, ov->id);
+ kfree(ov);
+ }
+
+ mutex_unlock(&of_mutex);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
diff --git a/drivers/of/pdt.c b/drivers/of/pdt.c
index 36b4035..d2acae8 100644
--- a/drivers/of/pdt.c
+++ b/drivers/of/pdt.c
@@ -25,8 +25,7 @@
static struct of_pdt_ops *of_pdt_prom_ops __initdata;
-void __initdata (*of_pdt_build_more)(struct device_node *dp,
- struct device_node ***nextp);
+void __initdata (*of_pdt_build_more)(struct device_node *dp);
#if defined(CONFIG_SPARC)
unsigned int of_pdt_unique_id __initdata;
@@ -192,8 +191,7 @@ static struct device_node * __init of_pdt_create_node(phandle node,
}
static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
- phandle node,
- struct device_node ***nextp)
+ phandle node)
{
struct device_node *ret = NULL, *prev_sibling = NULL;
struct device_node *dp;
@@ -210,16 +208,12 @@ static struct device_node * __init of_pdt_build_tree(struct device_node *parent,
ret = dp;
prev_sibling = dp;
- *(*nextp) = dp;
- *nextp = &dp->allnext;
-
dp->full_name = of_pdt_build_full_name(dp);
- dp->child = of_pdt_build_tree(dp,
- of_pdt_prom_ops->getchild(node), nextp);
+ dp->child = of_pdt_build_tree(dp, of_pdt_prom_ops->getchild(node));
if (of_pdt_build_more)
- of_pdt_build_more(dp, nextp);
+ of_pdt_build_more(dp);
node = of_pdt_prom_ops->getsibling(node);
}
@@ -234,20 +228,17 @@ static void * __init kernel_tree_alloc(u64 size, u64 align)
void __init of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops)
{
- struct device_node **nextp;
-
BUG_ON(!ops);
of_pdt_prom_ops = ops;
- of_allnodes = of_pdt_create_node(root_node, NULL);
+ of_root = of_pdt_create_node(root_node, NULL);
#if defined(CONFIG_SPARC)
- of_allnodes->path_component_name = "";
+ of_root->path_component_name = "";
#endif
- of_allnodes->full_name = "/";
+ of_root->full_name = "/";
- nextp = &of_allnodes->allnext;
- of_allnodes->child = of_pdt_build_tree(of_allnodes,
- of_pdt_prom_ops->getchild(of_allnodes->phandle), &nextp);
+ of_root->child = of_pdt_build_tree(of_root,
+ of_pdt_prom_ops->getchild(of_root->phandle));
/* Get pointer to "/chosen" and "/aliases" nodes for use everywhere */
of_alias_scan(kernel_tree_alloc);
diff --git a/drivers/of/platform.c b/drivers/of/platform.c
index 3b64d0b..cd87a36 100644
--- a/drivers/of/platform.c
+++ b/drivers/of/platform.c
@@ -138,7 +138,7 @@ struct platform_device *of_device_alloc(struct device_node *np,
}
dev->dev.of_node = of_node_get(np);
- dev->dev.parent = parent;
+ dev->dev.parent = parent ? : &platform_bus;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
@@ -291,7 +291,7 @@ static struct amba_device *of_amba_device_create(struct device_node *node,
/* setup generic device info */
dev->dev.of_node = of_node_get(node);
- dev->dev.parent = parent;
+ dev->dev.parent = parent ? : &platform_bus;
dev->dev.platform_data = platform_data;
if (bus_id)
dev_set_name(&dev->dev, "%s", bus_id);
@@ -500,6 +500,7 @@ int of_platform_populate(struct device_node *root,
if (rc)
break;
}
+ of_node_set_flag(root, OF_POPULATED_BUS);
of_node_put(root);
return rc;
@@ -542,8 +543,66 @@ static int of_platform_device_destroy(struct device *dev, void *data)
*/
void of_platform_depopulate(struct device *parent)
{
- device_for_each_child(parent, NULL, of_platform_device_destroy);
+ if (parent->of_node && of_node_check_flag(parent->of_node, OF_POPULATED_BUS)) {
+ device_for_each_child(parent, NULL, of_platform_device_destroy);
+ of_node_clear_flag(parent->of_node, OF_POPULATED_BUS);
+ }
}
EXPORT_SYMBOL_GPL(of_platform_depopulate);
+#ifdef CONFIG_OF_DYNAMIC
+static int of_platform_notify(struct notifier_block *nb,
+ unsigned long action, void *arg)
+{
+ struct of_reconfig_data *rd = arg;
+ struct platform_device *pdev_parent, *pdev;
+ bool children_left;
+
+ switch (of_reconfig_get_state_change(action, rd)) {
+ case OF_RECONFIG_CHANGE_ADD:
+ /* verify that the parent is a bus */
+ if (!of_node_check_flag(rd->dn->parent, OF_POPULATED_BUS))
+ return NOTIFY_OK; /* not for us */
+
+ /* pdev_parent may be NULL when no bus platform device */
+ pdev_parent = of_find_device_by_node(rd->dn->parent);
+ pdev = of_platform_device_create(rd->dn, NULL,
+ pdev_parent ? &pdev_parent->dev : NULL);
+ of_dev_put(pdev_parent);
+
+ if (pdev == NULL) {
+ pr_err("%s: failed to create for '%s'\n",
+ __func__, rd->dn->full_name);
+ /* of_platform_device_create tosses the error code */
+ return notifier_from_errno(-EINVAL);
+ }
+ break;
+
+ case OF_RECONFIG_CHANGE_REMOVE:
+ /* find our device by node */
+ pdev = of_find_device_by_node(rd->dn);
+ if (pdev == NULL)
+ return NOTIFY_OK; /* no? not meant for us */
+
+ /* unregister takes one ref away */
+ of_platform_device_destroy(&pdev->dev, &children_left);
+
+ /* and put the reference of the find */
+ of_dev_put(pdev);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block platform_of_notifier = {
+ .notifier_call = of_platform_notify,
+};
+
+void of_platform_register_reconfig_notifier(void)
+{
+ WARN_ON(of_reconfig_notifier_register(&platform_of_notifier));
+}
+#endif /* CONFIG_OF_DYNAMIC */
+
#endif /* CONFIG_OF_ADDRESS */
diff --git a/drivers/of/resolver.c b/drivers/of/resolver.c
index aed7959..640eb4c 100644
--- a/drivers/of/resolver.c
+++ b/drivers/of/resolver.c
@@ -111,7 +111,8 @@ static void __of_adjust_tree_phandles(struct device_node *node,
__of_adjust_tree_phandles(child, phandle_delta);
}
-static int __of_adjust_phandle_ref(struct device_node *node, struct property *rprop, int value, bool is_delta)
+static int __of_adjust_phandle_ref(struct device_node *node,
+ struct property *rprop, int value)
{
phandle phandle;
struct device_node *refnode;
@@ -181,7 +182,7 @@ static int __of_adjust_phandle_ref(struct device_node *node, struct property *rp
goto err_fail;
}
- phandle = is_delta ? be32_to_cpup(sprop->value + offset) + value : value;
+ phandle = value;
*(__be32 *)(sprop->value + offset) = cpu_to_be32(phandle);
}
@@ -190,36 +191,97 @@ err_fail:
return err;
}
+/* compare nodes taking into account that 'name' strips out the @ part */
+static int __of_node_name_cmp(const struct device_node *dn1,
+ const struct device_node *dn2)
+{
+ const char *n1 = strrchr(dn1->full_name, '/') ? : "/";
+ const char *n2 = strrchr(dn2->full_name, '/') ? : "/";
+
+ return of_node_cmp(n1, n2);
+}
+
/*
* Adjust the local phandle references by the given phandle delta.
- * Assumes the existances of a __local_fixups__ node at the root
- * of the tree. Does not take any devtree locks so make sure you
- * call this on a tree which is at the detached state.
+ * Assumes the existances of a __local_fixups__ node at the root.
+ * Assumes that __of_verify_tree_phandle_references has been called.
+ * Does not take any devtree locks so make sure you call this on a tree
+ * which is at the detached state.
*/
static int __of_adjust_tree_phandle_references(struct device_node *node,
- int phandle_delta)
+ struct device_node *target, int phandle_delta)
{
- struct device_node *child;
- struct property *rprop;
- int err;
-
- /* locate the symbols & fixups nodes on resolve */
- for_each_child_of_node(node, child)
- if (of_node_cmp(child->name, "__local_fixups__") == 0)
- break;
+ struct device_node *child, *childtarget;
+ struct property *rprop, *sprop;
+ int err, i, count;
+ unsigned int off;
+ phandle phandle;
- /* no local fixups */
- if (!child)
+ if (node == NULL)
return 0;
- /* find the local fixups property */
- for_each_property_of_node(child, rprop) {
+ for_each_property_of_node(node, rprop) {
+
/* skip properties added automatically */
- if (of_prop_cmp(rprop->name, "name") == 0)
+ if (of_prop_cmp(rprop->name, "name") == 0 ||
+ of_prop_cmp(rprop->name, "phandle") == 0 ||
+ of_prop_cmp(rprop->name, "linux,phandle") == 0)
continue;
- err = __of_adjust_phandle_ref(node, rprop, phandle_delta, true);
- if (err)
+ if ((rprop->length % 4) != 0 || rprop->length == 0) {
+ pr_err("%s: Illegal property (size) '%s' @%s\n",
+ __func__, rprop->name, node->full_name);
+ return -EINVAL;
+ }
+ count = rprop->length / sizeof(__be32);
+
+ /* now find the target property */
+ for_each_property_of_node(target, sprop) {
+ if (of_prop_cmp(sprop->name, rprop->name) == 0)
+ break;
+ }
+
+ if (sprop == NULL) {
+ pr_err("%s: Could not find target property '%s' @%s\n",
+ __func__, rprop->name, node->full_name);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < count; i++) {
+ off = be32_to_cpu(((__be32 *)rprop->value)[i]);
+ /* make sure the offset doesn't overstep (even wrap) */
+ if (off >= sprop->length ||
+ (off + 4) > sprop->length) {
+ pr_err("%s: Illegal property '%s' @%s\n",
+ __func__, rprop->name,
+ node->full_name);
+ return -EINVAL;
+ }
+
+ if (phandle_delta) {
+ /* adjust */
+ phandle = be32_to_cpu(*(__be32 *)(sprop->value + off));
+ phandle += phandle_delta;
+ *(__be32 *)(sprop->value + off) = cpu_to_be32(phandle);
+ }
+ }
+ }
+
+ for_each_child_of_node(node, child) {
+
+ for_each_child_of_node(target, childtarget)
+ if (__of_node_name_cmp(child, childtarget) == 0)
+ break;
+
+ if (!childtarget) {
+ pr_err("%s: Could not find target child '%s' @%s\n",
+ __func__, child->name, node->full_name);
+ return -EINVAL;
+ }
+
+ err = __of_adjust_tree_phandle_references(child, childtarget,
+ phandle_delta);
+ if (err != 0)
return err;
}
@@ -241,7 +303,7 @@ static int __of_adjust_tree_phandle_references(struct device_node *node,
*/
int of_resolve_phandles(struct device_node *resolve)
{
- struct device_node *child, *refnode;
+ struct device_node *child, *childroot, *refnode;
struct device_node *root_sym, *resolve_sym, *resolve_fix;
struct property *rprop;
const char *refpath;
@@ -255,9 +317,23 @@ int of_resolve_phandles(struct device_node *resolve)
/* first we need to adjust the phandles */
phandle_delta = of_get_tree_max_phandle() + 1;
__of_adjust_tree_phandles(resolve, phandle_delta);
- err = __of_adjust_tree_phandle_references(resolve, phandle_delta);
- if (err != 0)
- return err;
+
+ /* locate the local fixups */
+ childroot = NULL;
+ for_each_child_of_node(resolve, childroot)
+ if (of_node_cmp(childroot->name, "__local_fixups__") == 0)
+ break;
+
+ if (childroot != NULL) {
+ /* resolve root is guaranteed to be the '/' */
+ err = __of_adjust_tree_phandle_references(childroot,
+ resolve, 0);
+ if (err != 0)
+ return err;
+
+ BUG_ON(__of_adjust_tree_phandle_references(childroot,
+ resolve, phandle_delta));
+ }
root_sym = NULL;
resolve_sym = NULL;
@@ -322,7 +398,7 @@ int of_resolve_phandles(struct device_node *resolve)
pr_debug("%s: %s phandle is 0x%08x\n",
__func__, rprop->name, phandle);
- err = __of_adjust_phandle_ref(resolve, rprop, phandle, false);
+ err = __of_adjust_phandle_ref(resolve, rprop, phandle);
if (err)
break;
}
diff --git a/drivers/of/testcase-data/testcases.dts b/drivers/of/testcase-data/testcases.dts
deleted file mode 100644
index 6994e15..0000000
--- a/drivers/of/testcase-data/testcases.dts
+++ /dev/null
@@ -1,50 +0,0 @@
-/dts-v1/;
-/ {
- testcase-data {
- changeset {
- prop-update = "hello";
- prop-remove = "world";
- node-remove {
- };
- };
- };
-};
-#include "tests-phandle.dtsi"
-#include "tests-interrupts.dtsi"
-#include "tests-match.dtsi"
-#include "tests-platform.dtsi"
-
-/*
- * phandle fixup data - generated by dtc patches that aren't upstream.
- * This data must be regenerated whenever phandle references are modified in
- * the testdata tree.
- *
- * The format of this data may be subject to change. For the time being consider
- * this a kernel-internal data format.
- */
-/ { __local_fixups__ {
- fixup = "/testcase-data/testcase-device2:interrupt-parent:0",
- "/testcase-data/testcase-device1:interrupt-parent:0",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:60",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:52",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:44",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:36",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:24",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:8",
- "/testcase-data/interrupts/interrupts-extended0:interrupts-extended:0",
- "/testcase-data/interrupts/interrupts1:interrupt-parent:0",
- "/testcase-data/interrupts/interrupts0:interrupt-parent:0",
- "/testcase-data/interrupts/intmap1:interrupt-map:12",
- "/testcase-data/interrupts/intmap0:interrupt-map:52",
- "/testcase-data/interrupts/intmap0:interrupt-map:36",
- "/testcase-data/interrupts/intmap0:interrupt-map:16",
- "/testcase-data/interrupts/intmap0:interrupt-map:4",
- "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:12",
- "/testcase-data/phandle-tests/consumer-a:phandle-list-bad-args:0",
- "/testcase-data/phandle-tests/consumer-a:phandle-list:56",
- "/testcase-data/phandle-tests/consumer-a:phandle-list:52",
- "/testcase-data/phandle-tests/consumer-a:phandle-list:40",
- "/testcase-data/phandle-tests/consumer-a:phandle-list:24",
- "/testcase-data/phandle-tests/consumer-a:phandle-list:8",
- "/testcase-data/phandle-tests/consumer-a:phandle-list:0";
-}; };
diff --git a/drivers/of/unittest-data/testcases.dts b/drivers/of/unittest-data/testcases.dts
new file mode 100644
index 0000000..12f7c3d
--- /dev/null
+++ b/drivers/of/unittest-data/testcases.dts
@@ -0,0 +1,79 @@
+/dts-v1/;
+/ {
+ testcase-data {
+ changeset {
+ prop-update = "hello";
+ prop-remove = "world";
+ node-remove {
+ };
+ };
+ };
+};
+#include "tests-phandle.dtsi"
+#include "tests-interrupts.dtsi"
+#include "tests-match.dtsi"
+#include "tests-platform.dtsi"
+#include "tests-overlay.dtsi"
+
+/*
+ * phandle fixup data - generated by dtc patches that aren't upstream.
+ * This data must be regenerated whenever phandle references are modified in
+ * the testdata tree.
+ *
+ * The format of this data may be subject to change. For the time being consider
+ * this a kernel-internal data format.
+ */
+/ { __local_fixups__ {
+ testcase-data {
+ phandle-tests {
+ consumer-a {
+ phandle-list = <0x00000000 0x00000008
+ 0x00000018 0x00000028
+ 0x00000034 0x00000038>;
+ phandle-list-bad-args = <0x00000000 0x0000000c>;
+ };
+ };
+ interrupts {
+ intmap0 {
+ interrupt-map = <0x00000004 0x00000010
+ 0x00000024 0x00000034>;
+ };
+ intmap1 {
+ interrupt-map = <0x0000000c>;
+ };
+ interrupts0 {
+ interrupt-parent = <0x00000000>;
+ };
+ interrupts1 {
+ interrupt-parent = <0x00000000>;
+ };
+ interrupts-extended0 {
+ interrupts-extended = <0x00000000 0x00000008
+ 0x00000018 0x00000024
+ 0x0000002c 0x00000034
+ 0x0000003c>;
+ };
+ };
+ testcase-device1 {
+ interrupt-parent = <0x00000000>;
+ };
+ testcase-device2 {
+ interrupt-parent = <0x00000000>;
+ };
+ overlay2 {
+ fragment@0 {
+ target = <0x00000000>;
+ };
+ };
+ overlay3 {
+ fragment@0 {
+ target = <0x00000000>;
+ };
+ };
+ overlay4 {
+ fragment@0 {
+ target = <0x00000000>;
+ };
+ };
+ };
+}; };
diff --git a/drivers/of/testcase-data/tests-interrupts.dtsi b/drivers/of/unittest-data/tests-interrupts.dtsi
index da4695f..da4695f 100644
--- a/drivers/of/testcase-data/tests-interrupts.dtsi
+++ b/drivers/of/unittest-data/tests-interrupts.dtsi
diff --git a/drivers/of/testcase-data/tests-match.dtsi b/drivers/of/unittest-data/tests-match.dtsi
index c9e5411..c9e5411 100644
--- a/drivers/of/testcase-data/tests-match.dtsi
+++ b/drivers/of/unittest-data/tests-match.dtsi
diff --git a/drivers/of/unittest-data/tests-overlay.dtsi b/drivers/of/unittest-data/tests-overlay.dtsi
new file mode 100644
index 0000000..75976da
--- /dev/null
+++ b/drivers/of/unittest-data/tests-overlay.dtsi
@@ -0,0 +1,180 @@
+
+/ {
+ testcase-data {
+ overlay-node {
+
+ /* test bus */
+ selftestbus: test-bus {
+ compatible = "simple-bus";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ selftest100: test-selftest100 {
+ compatible = "selftest";
+ status = "okay";
+ reg = <100>;
+ };
+
+ selftest101: test-selftest101 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <101>;
+ };
+
+ selftest0: test-selftest0 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <0>;
+ };
+
+ selftest1: test-selftest1 {
+ compatible = "selftest";
+ status = "okay";
+ reg = <1>;
+ };
+
+ selftest2: test-selftest2 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <2>;
+ };
+
+ selftest3: test-selftest3 {
+ compatible = "selftest";
+ status = "okay";
+ reg = <3>;
+ };
+
+ selftest5: test-selftest5 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <5>;
+ };
+
+ selftest6: test-selftest6 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <6>;
+ };
+
+ selftest7: test-selftest7 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <7>;
+ };
+
+ selftest8: test-selftest8 {
+ compatible = "selftest";
+ status = "disabled";
+ reg = <8>;
+ };
+ };
+ };
+
+ /* test enable using absolute target path */
+ overlay0 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest0";
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+
+ /* test disable using absolute target path */
+ overlay1 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest1";
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+ };
+
+ /* test enable using label */
+ overlay2 {
+ fragment@0 {
+ target = <&selftest2>;
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+
+ /* test disable using label */
+ overlay3 {
+ fragment@0 {
+ target = <&selftest3>;
+ __overlay__ {
+ status = "disabled";
+ };
+ };
+ };
+
+ /* test insertion of a full node */
+ overlay4 {
+ fragment@0 {
+ target = <&selftestbus>;
+ __overlay__ {
+
+ /* suppress DTC warning */
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ test-selftest4 {
+ compatible = "selftest";
+ status = "okay";
+ reg = <4>;
+ };
+ };
+ };
+ };
+
+ /* test overlay apply revert */
+ overlay5 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest5";
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+
+ /* test overlays application and removal in sequence */
+ overlay6 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest6";
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+ overlay7 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest7";
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+
+ /* test overlays application and removal in bad sequence */
+ overlay8 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
+ __overlay__ {
+ status = "okay";
+ };
+ };
+ };
+ overlay9 {
+ fragment@0 {
+ target-path = "/testcase-data/overlay-node/test-bus/test-selftest8";
+ __overlay__ {
+ property-foo = "bar";
+ };
+ };
+ };
+
+ };
+};
diff --git a/drivers/of/testcase-data/tests-phandle.dtsi b/drivers/of/unittest-data/tests-phandle.dtsi
index 5b1527e..5b1527e 100644
--- a/drivers/of/testcase-data/tests-phandle.dtsi
+++ b/drivers/of/unittest-data/tests-phandle.dtsi
diff --git a/drivers/of/testcase-data/tests-platform.dtsi b/drivers/of/unittest-data/tests-platform.dtsi
index eb20eeb..eb20eeb 100644
--- a/drivers/of/testcase-data/tests-platform.dtsi
+++ b/drivers/of/unittest-data/tests-platform.dtsi
diff --git a/drivers/of/selftest.c b/drivers/of/unittest.c
index e2d79af..844838e 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/unittest.c
@@ -17,6 +17,8 @@
#include <linux/mutex.h>
#include <linux/slab.h>
#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/of_platform.h>
#include "of_private.h"
@@ -30,19 +32,22 @@ static struct device_node *nodes[NO_OF_NODES];
static int last_node_index;
static bool selftest_live_tree;
-#define selftest(result, fmt, ...) { \
- if (!(result)) { \
+#define selftest(result, fmt, ...) ({ \
+ bool failed = !(result); \
+ if (failed) { \
selftest_results.failed++; \
pr_err("FAIL %s():%i " fmt, __func__, __LINE__, ##__VA_ARGS__); \
} else { \
selftest_results.passed++; \
pr_debug("pass %s():%i\n", __func__, __LINE__); \
} \
-}
+ failed; \
+})
static void __init of_selftest_find_node_by_name(void)
{
struct device_node *np;
+ const char *options;
np = of_find_node_by_path("/testcase-data");
selftest(np && !strcmp("/testcase-data", np->full_name),
@@ -83,6 +88,35 @@ static void __init of_selftest_find_node_by_name(void)
np = of_find_node_by_path("testcase-alias/missing-path");
selftest(!np, "non-existent alias with relative path returned node %s\n", np->full_name);
of_node_put(np);
+
+ np = of_find_node_opts_by_path("/testcase-data:testoption", &options);
+ selftest(np && !strcmp("testoption", options),
+ "option path test failed\n");
+ of_node_put(np);
+
+ np = of_find_node_opts_by_path("/testcase-data:testoption", NULL);
+ selftest(np, "NULL option path test failed\n");
+ of_node_put(np);
+
+ np = of_find_node_opts_by_path("testcase-alias:testaliasoption",
+ &options);
+ selftest(np && !strcmp("testaliasoption", options),
+ "option alias path test failed\n");
+ of_node_put(np);
+
+ np = of_find_node_opts_by_path("testcase-alias:testaliasoption", NULL);
+ selftest(np, "NULL option alias path test failed\n");
+ of_node_put(np);
+
+ options = "testoption";
+ np = of_find_node_opts_by_path("testcase-alias", &options);
+ selftest(np && !options, "option clearing test failed\n");
+ of_node_put(np);
+
+ options = "testoption";
+ np = of_find_node_opts_by_path("/", &options);
+ selftest(np && !options, "option clearing root node test failed\n");
+ of_node_put(np);
}
static void __init of_selftest_dynamic(void)
@@ -148,7 +182,7 @@ static void __init of_selftest_dynamic(void)
static int __init of_selftest_check_node_linkage(struct device_node *np)
{
- struct device_node *child, *allnext_index = np;
+ struct device_node *child;
int count = 0, rc;
for_each_child_of_node(np, child) {
@@ -158,14 +192,6 @@ static int __init of_selftest_check_node_linkage(struct device_node *np)
return -EINVAL;
}
- while (allnext_index && allnext_index != child)
- allnext_index = allnext_index->allnext;
- if (allnext_index != child) {
- pr_err("Node %s is ordered differently in sibling and allnode lists\n",
- child->name);
- return -EINVAL;
- }
-
rc = of_selftest_check_node_linkage(child);
if (rc < 0)
return rc;
@@ -180,12 +206,12 @@ static void __init of_selftest_check_tree_linkage(void)
struct device_node *np;
int allnode_count = 0, child_count;
- if (!of_allnodes)
+ if (!of_root)
return;
for_each_of_allnodes(np)
allnode_count++;
- child_count = of_selftest_check_node_linkage(of_allnodes);
+ child_count = of_selftest_check_node_linkage(of_root);
selftest(child_count > 0, "Device node data structure is corrupted\n");
selftest(child_count == allnode_count, "allnodes list size (%i) doesn't match"
@@ -451,15 +477,15 @@ static void __init of_selftest_changeset(void)
struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" };
struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
struct property *ppremove;
- struct device_node *n1, *n2, *n21, *nremove, *parent;
+ struct device_node *n1, *n2, *n21, *nremove, *parent, *np;
struct of_changeset chgset;
of_changeset_init(&chgset);
- n1 = __of_node_alloc("/testcase-data/changeset/n1", GFP_KERNEL);
+ n1 = __of_node_dup(NULL, "/testcase-data/changeset/n1");
selftest(n1, "testcase setup failure\n");
- n2 = __of_node_alloc("/testcase-data/changeset/n2", GFP_KERNEL);
+ n2 = __of_node_dup(NULL, "/testcase-data/changeset/n2");
selftest(n2, "testcase setup failure\n");
- n21 = __of_node_alloc("/testcase-data/changeset/n2/n21", GFP_KERNEL);
+ n21 = __of_node_dup(NULL, "%s/%s", "/testcase-data/changeset/n2", "n21");
selftest(n21, "testcase setup failure %p\n", n21);
nremove = of_find_node_by_path("/testcase-data/changeset/node-remove");
selftest(nremove, "testcase setup failure\n");
@@ -487,6 +513,11 @@ static void __init of_selftest_changeset(void)
selftest(!of_changeset_apply(&chgset), "apply failed\n");
mutex_unlock(&of_mutex);
+ /* Make sure node names are constructed correctly */
+ selftest((np = of_find_node_by_path("/testcase-data/changeset/n2/n21")),
+ "'%s' not added\n", n21->full_name);
+ of_node_put(np);
+
mutex_lock(&of_mutex);
selftest(!of_changeset_revert(&chgset), "revert failed\n");
mutex_unlock(&of_mutex);
@@ -702,10 +733,13 @@ static void __init of_selftest_match_node(void)
}
}
+struct device test_bus = {
+ .init_name = "unittest-bus",
+};
static void __init of_selftest_platform_populate(void)
{
- int irq;
- struct device_node *np, *child;
+ int irq, rc;
+ struct device_node *np, *child, *grandchild;
struct platform_device *pdev;
struct of_device_id match[] = {
{ .compatible = "test-device", },
@@ -730,20 +764,32 @@ static void __init of_selftest_platform_populate(void)
irq = platform_get_irq(pdev, 0);
selftest(irq < 0 && irq != -EPROBE_DEFER, "device parsing error failed - %d\n", irq);
- np = of_find_node_by_path("/testcase-data/platform-tests");
- if (!np) {
- pr_err("No testcase data in device tree\n");
+ if (selftest(np = of_find_node_by_path("/testcase-data/platform-tests"),
+ "No testcase data in device tree\n"));
+ return;
+
+ if (selftest(!(rc = device_register(&test_bus)),
+ "testbus registration failed; rc=%i\n", rc));
return;
- }
for_each_child_of_node(np, child) {
- struct device_node *grandchild;
- of_platform_populate(child, match, NULL, NULL);
+ of_platform_populate(child, match, NULL, &test_bus);
for_each_child_of_node(child, grandchild)
selftest(of_find_device_by_node(grandchild),
"Could not create device for node '%s'\n",
grandchild->name);
}
+
+ of_platform_depopulate(&test_bus);
+ for_each_child_of_node(np, child) {
+ for_each_child_of_node(child, grandchild)
+ selftest(!of_find_device_by_node(grandchild),
+ "device didn't get destroyed '%s'\n",
+ grandchild->name);
+ }
+
+ device_unregister(&test_bus);
+ of_node_put(np);
}
/**
@@ -775,33 +821,29 @@ static void update_node_properties(struct device_node *np,
*/
static int attach_node_and_children(struct device_node *np)
{
- struct device_node *next, *root = np, *dup;
+ struct device_node *next, *dup, *child;
- /* skip root node */
- np = np->child;
- /* storing a copy in temporary node */
- dup = np;
+ dup = of_find_node_by_path(np->full_name);
+ if (dup) {
+ update_node_properties(np, dup);
+ return 0;
+ }
- while (dup) {
+ /* Children of the root need to be remembered for removal */
+ if (np->parent == of_root) {
if (WARN_ON(last_node_index >= NO_OF_NODES))
return -EINVAL;
- nodes[last_node_index++] = dup;
- dup = dup->sibling;
+ nodes[last_node_index++] = np;
}
- dup = NULL;
- while (np) {
- next = np->allnext;
- dup = of_find_node_by_path(np->full_name);
- if (dup)
- update_node_properties(np, dup);
- else {
- np->child = NULL;
- if (np->parent == root)
- np->parent = of_allnodes;
- of_attach_node(np);
- }
- np = next;
+ child = np->child;
+ np->child = NULL;
+ np->sibling = NULL;
+ of_attach_node(np);
+ while (child) {
+ next = child->sibling;
+ attach_node_and_children(child);
+ child = next;
}
return 0;
@@ -846,10 +888,10 @@ static int __init selftest_data_add(void)
return -EINVAL;
}
- if (!of_allnodes) {
+ if (!of_root) {
/* enabling flag for removing nodes */
selftest_live_tree = true;
- of_allnodes = selftest_data_node;
+ of_root = selftest_data_node;
for_each_of_allnodes(np)
__of_attach_node_sysfs(np);
@@ -859,7 +901,14 @@ static int __init selftest_data_add(void)
}
/* attach the sub-tree to live tree */
- return attach_node_and_children(selftest_data_node);
+ np = selftest_data_node->child;
+ while (np) {
+ struct device_node *next = np->sibling;
+ np->parent = of_root;
+ attach_node_and_children(np);
+ np = next;
+ }
+ return 0;
}
/**
@@ -889,10 +938,10 @@ static void selftest_data_remove(void)
of_node_put(of_chosen);
of_aliases = NULL;
of_chosen = NULL;
- for_each_child_of_node(of_allnodes, np)
+ for_each_child_of_node(of_root, np)
detach_node_and_children(np);
- __of_detach_node_sysfs(of_allnodes);
- of_allnodes = NULL;
+ __of_detach_node_sysfs(of_root);
+ of_root = NULL;
return;
}
@@ -915,6 +964,483 @@ static void selftest_data_remove(void)
}
}
+#ifdef CONFIG_OF_OVERLAY
+
+static int selftest_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ if (np == NULL) {
+ dev_err(dev, "No OF data for device\n");
+ return -EINVAL;
+
+ }
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+ return 0;
+}
+
+static int selftest_remove(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *np = dev->of_node;
+
+ dev_dbg(dev, "%s for node @%s\n", __func__, np->full_name);
+ return 0;
+}
+
+static struct of_device_id selftest_match[] = {
+ { .compatible = "selftest", },
+ {},
+};
+
+static struct platform_driver selftest_driver = {
+ .probe = selftest_probe,
+ .remove = selftest_remove,
+ .driver = {
+ .name = "selftest",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(selftest_match),
+ },
+};
+
+/* get the platform device instantiated at the path */
+static struct platform_device *of_path_to_platform_device(const char *path)
+{
+ struct device_node *np;
+ struct platform_device *pdev;
+
+ np = of_find_node_by_path(path);
+ if (np == NULL)
+ return NULL;
+
+ pdev = of_find_device_by_node(np);
+ of_node_put(np);
+
+ return pdev;
+}
+
+/* find out if a platform device exists at that path */
+static int of_path_platform_device_exists(const char *path)
+{
+ struct platform_device *pdev;
+
+ pdev = of_path_to_platform_device(path);
+ platform_device_put(pdev);
+ return pdev != NULL;
+}
+
+static const char *selftest_path(int nr)
+{
+ static char buf[256];
+
+ snprintf(buf, sizeof(buf) - 1,
+ "/testcase-data/overlay-node/test-bus/test-selftest%d", nr);
+ buf[sizeof(buf) - 1] = '\0';
+
+ return buf;
+}
+
+static const char *overlay_path(int nr)
+{
+ static char buf[256];
+
+ snprintf(buf, sizeof(buf) - 1,
+ "/testcase-data/overlay%d", nr);
+ buf[sizeof(buf) - 1] = '\0';
+
+ return buf;
+}
+
+static const char *bus_path = "/testcase-data/overlay-node/test-bus";
+
+static int of_selftest_apply_overlay(int selftest_nr, int overlay_nr,
+ int *overlay_id)
+{
+ struct device_node *np = NULL;
+ int ret, id = -1;
+
+ np = of_find_node_by_path(overlay_path(overlay_nr));
+ if (np == NULL) {
+ selftest(0, "could not find overlay node @\"%s\"\n",
+ overlay_path(overlay_nr));
+ ret = -EINVAL;
+ goto out;
+ }
+
+ ret = of_overlay_create(np);
+ if (ret < 0) {
+ selftest(0, "could not create overlay from \"%s\"\n",
+ overlay_path(overlay_nr));
+ goto out;
+ }
+ id = ret;
+
+ ret = 0;
+
+out:
+ of_node_put(np);
+
+ if (overlay_id)
+ *overlay_id = id;
+
+ return ret;
+}
+
+/* apply an overlay while checking before and after states */
+static int of_selftest_apply_overlay_check(int overlay_nr, int selftest_nr,
+ int before, int after)
+{
+ int ret;
+
+ /* selftest device must not be in before state */
+ if (of_path_platform_device_exists(selftest_path(selftest_nr))
+ != before) {
+ selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+ overlay_path(overlay_nr),
+ selftest_path(selftest_nr),
+ !before ? "enabled" : "disabled");
+ return -EINVAL;
+ }
+
+ ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, NULL);
+ if (ret != 0) {
+ /* of_selftest_apply_overlay already called selftest() */
+ return ret;
+ }
+
+ /* selftest device must be to set to after state */
+ if (of_path_platform_device_exists(selftest_path(selftest_nr))
+ != after) {
+ selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+ overlay_path(overlay_nr),
+ selftest_path(selftest_nr),
+ !after ? "enabled" : "disabled");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* apply an overlay and then revert it while checking before, after states */
+static int of_selftest_apply_revert_overlay_check(int overlay_nr,
+ int selftest_nr, int before, int after)
+{
+ int ret, ov_id;
+
+ /* selftest device must be in before state */
+ if (of_path_platform_device_exists(selftest_path(selftest_nr))
+ != before) {
+ selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+ overlay_path(overlay_nr),
+ selftest_path(selftest_nr),
+ !before ? "enabled" : "disabled");
+ return -EINVAL;
+ }
+
+ /* apply the overlay */
+ ret = of_selftest_apply_overlay(overlay_nr, selftest_nr, &ov_id);
+ if (ret != 0) {
+ /* of_selftest_apply_overlay already called selftest() */
+ return ret;
+ }
+
+ /* selftest device must be in after state */
+ if (of_path_platform_device_exists(selftest_path(selftest_nr))
+ != after) {
+ selftest(0, "overlay @\"%s\" failed to create @\"%s\" %s\n",
+ overlay_path(overlay_nr),
+ selftest_path(selftest_nr),
+ !after ? "enabled" : "disabled");
+ return -EINVAL;
+ }
+
+ ret = of_overlay_destroy(ov_id);
+ if (ret != 0) {
+ selftest(0, "overlay @\"%s\" failed to be destroyed @\"%s\"\n",
+ overlay_path(overlay_nr),
+ selftest_path(selftest_nr));
+ return ret;
+ }
+
+ /* selftest device must be again in before state */
+ if (of_path_platform_device_exists(selftest_path(selftest_nr))
+ != before) {
+ selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+ overlay_path(overlay_nr),
+ selftest_path(selftest_nr),
+ !before ? "enabled" : "disabled");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* test activation of device */
+static void of_selftest_overlay_0(void)
+{
+ int ret;
+
+ /* device should enable */
+ ret = of_selftest_apply_overlay_check(0, 0, 0, 1);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 0);
+}
+
+/* test deactivation of device */
+static void of_selftest_overlay_1(void)
+{
+ int ret;
+
+ /* device should disable */
+ ret = of_selftest_apply_overlay_check(1, 1, 1, 0);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 1);
+}
+
+/* test activation of device */
+static void of_selftest_overlay_2(void)
+{
+ int ret;
+
+ /* device should enable */
+ ret = of_selftest_apply_overlay_check(2, 2, 0, 1);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 2);
+}
+
+/* test deactivation of device */
+static void of_selftest_overlay_3(void)
+{
+ int ret;
+
+ /* device should disable */
+ ret = of_selftest_apply_overlay_check(3, 3, 1, 0);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 3);
+}
+
+/* test activation of a full device node */
+static void of_selftest_overlay_4(void)
+{
+ int ret;
+
+ /* device should disable */
+ ret = of_selftest_apply_overlay_check(4, 4, 0, 1);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 4);
+}
+
+/* test overlay apply/revert sequence */
+static void of_selftest_overlay_5(void)
+{
+ int ret;
+
+ /* device should disable */
+ ret = of_selftest_apply_revert_overlay_check(5, 5, 0, 1);
+ if (ret != 0)
+ return;
+
+ selftest(1, "overlay test %d passed\n", 5);
+}
+
+/* test overlay application in sequence */
+static void of_selftest_overlay_6(void)
+{
+ struct device_node *np;
+ int ret, i, ov_id[2];
+ int overlay_nr = 6, selftest_nr = 6;
+ int before = 0, after = 1;
+
+ /* selftest device must be in before state */
+ for (i = 0; i < 2; i++) {
+ if (of_path_platform_device_exists(
+ selftest_path(selftest_nr + i))
+ != before) {
+ selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+ overlay_path(overlay_nr + i),
+ selftest_path(selftest_nr + i),
+ !before ? "enabled" : "disabled");
+ return;
+ }
+ }
+
+ /* apply the overlays */
+ for (i = 0; i < 2; i++) {
+
+ np = of_find_node_by_path(overlay_path(overlay_nr + i));
+ if (np == NULL) {
+ selftest(0, "could not find overlay node @\"%s\"\n",
+ overlay_path(overlay_nr + i));
+ return;
+ }
+
+ ret = of_overlay_create(np);
+ if (ret < 0) {
+ selftest(0, "could not create overlay from \"%s\"\n",
+ overlay_path(overlay_nr + i));
+ return;
+ }
+ ov_id[i] = ret;
+ }
+
+ for (i = 0; i < 2; i++) {
+ /* selftest device must be in after state */
+ if (of_path_platform_device_exists(
+ selftest_path(selftest_nr + i))
+ != after) {
+ selftest(0, "overlay @\"%s\" failed @\"%s\" %s\n",
+ overlay_path(overlay_nr + i),
+ selftest_path(selftest_nr + i),
+ !after ? "enabled" : "disabled");
+ return;
+ }
+ }
+
+ for (i = 1; i >= 0; i--) {
+ ret = of_overlay_destroy(ov_id[i]);
+ if (ret != 0) {
+ selftest(0, "overlay @\"%s\" failed destroy @\"%s\"\n",
+ overlay_path(overlay_nr + i),
+ selftest_path(selftest_nr + i));
+ return;
+ }
+ }
+
+ for (i = 0; i < 2; i++) {
+ /* selftest device must be again in before state */
+ if (of_path_platform_device_exists(
+ selftest_path(selftest_nr + i))
+ != before) {
+ selftest(0, "overlay @\"%s\" with device @\"%s\" %s\n",
+ overlay_path(overlay_nr + i),
+ selftest_path(selftest_nr + i),
+ !before ? "enabled" : "disabled");
+ return;
+ }
+ }
+
+ selftest(1, "overlay test %d passed\n", 6);
+}
+
+/* test overlay application in sequence */
+static void of_selftest_overlay_8(void)
+{
+ struct device_node *np;
+ int ret, i, ov_id[2];
+ int overlay_nr = 8, selftest_nr = 8;
+
+ /* we don't care about device state in this test */
+
+ /* apply the overlays */
+ for (i = 0; i < 2; i++) {
+
+ np = of_find_node_by_path(overlay_path(overlay_nr + i));
+ if (np == NULL) {
+ selftest(0, "could not find overlay node @\"%s\"\n",
+ overlay_path(overlay_nr + i));
+ return;
+ }
+
+ ret = of_overlay_create(np);
+ if (ret < 0) {
+ selftest(0, "could not create overlay from \"%s\"\n",
+ overlay_path(overlay_nr + i));
+ return;
+ }
+ ov_id[i] = ret;
+ }
+
+ /* now try to remove first overlay (it should fail) */
+ ret = of_overlay_destroy(ov_id[0]);
+ if (ret == 0) {
+ selftest(0, "overlay @\"%s\" was destroyed @\"%s\"\n",
+ overlay_path(overlay_nr + 0),
+ selftest_path(selftest_nr));
+ return;
+ }
+
+ /* removing them in order should work */
+ for (i = 1; i >= 0; i--) {
+ ret = of_overlay_destroy(ov_id[i]);
+ if (ret != 0) {
+ selftest(0, "overlay @\"%s\" not destroyed @\"%s\"\n",
+ overlay_path(overlay_nr + i),
+ selftest_path(selftest_nr));
+ return;
+ }
+ }
+
+ selftest(1, "overlay test %d passed\n", 8);
+}
+
+static void __init of_selftest_overlay(void)
+{
+ struct device_node *bus_np = NULL;
+ int ret;
+
+ ret = platform_driver_register(&selftest_driver);
+ if (ret != 0) {
+ selftest(0, "could not register selftest driver\n");
+ goto out;
+ }
+
+ bus_np = of_find_node_by_path(bus_path);
+ if (bus_np == NULL) {
+ selftest(0, "could not find bus_path \"%s\"\n", bus_path);
+ goto out;
+ }
+
+ ret = of_platform_populate(bus_np, of_default_bus_match_table,
+ NULL, NULL);
+ if (ret != 0) {
+ selftest(0, "could not populate bus @ \"%s\"\n", bus_path);
+ goto out;
+ }
+
+ if (!of_path_platform_device_exists(selftest_path(100))) {
+ selftest(0, "could not find selftest0 @ \"%s\"\n",
+ selftest_path(100));
+ goto out;
+ }
+
+ if (of_path_platform_device_exists(selftest_path(101))) {
+ selftest(0, "selftest1 @ \"%s\" should not exist\n",
+ selftest_path(101));
+ goto out;
+ }
+
+ selftest(1, "basic infrastructure of overlays passed");
+
+ /* tests in sequence */
+ of_selftest_overlay_0();
+ of_selftest_overlay_1();
+ of_selftest_overlay_2();
+ of_selftest_overlay_3();
+ of_selftest_overlay_4();
+ of_selftest_overlay_5();
+ of_selftest_overlay_6();
+ of_selftest_overlay_8();
+
+out:
+ of_node_put(bus_np);
+}
+
+#else
+static inline void __init of_selftest_overlay(void) { }
+#endif
+
static int __init of_selftest(void)
{
struct device_node *np;
@@ -947,6 +1473,7 @@ static int __init of_selftest(void)
of_selftest_parse_interrupts_extended();
of_selftest_match_node();
of_selftest_platform_populate();
+ of_selftest_overlay();
/* removing selftest data from live tree */
selftest_data_remove();
diff --git a/drivers/pci/Kconfig b/drivers/pci/Kconfig
index 893503f..cced842 100644
--- a/drivers/pci/Kconfig
+++ b/drivers/pci/Kconfig
@@ -4,6 +4,7 @@
config PCI_MSI
bool "Message Signaled Interrupts (MSI and MSI-X)"
depends on PCI
+ select GENERIC_MSI_IRQ
help
This allows device drivers to enable MSI (Message Signaled
Interrupts). Message Signaled Interrupts enable a device to
@@ -16,6 +17,11 @@ config PCI_MSI
If you don't know what to do here, say Y.
+config PCI_MSI_IRQ_DOMAIN
+ bool
+ depends on PCI_MSI
+ select GENERIC_MSI_IRQ_DOMAIN
+
config PCI_DEBUG
bool "PCI Debugging"
depends on PCI && DEBUG_KERNEL
diff --git a/drivers/pci/host/Kconfig b/drivers/pci/host/Kconfig
index 3dc25fa..c4b6568 100644
--- a/drivers/pci/host/Kconfig
+++ b/drivers/pci/host/Kconfig
@@ -32,7 +32,10 @@ config PCI_IMX6
config PCI_TEGRA
bool "NVIDIA Tegra PCIe controller"
- depends on ARCH_TEGRA
+ depends on ARCH_TEGRA && !ARM64
+ help
+ Say Y here if you want support for the PCIe host controller found
+ on NVIDIA Tegra SoCs.
config PCI_RCAR_GEN2
bool "Renesas R-Car Gen2 Internal PCI controller"
@@ -91,4 +94,12 @@ config PCI_XGENE
There are 5 internal PCIe ports available. Each port is GEN3 capable
and have varied lanes from x1 to x8.
+config PCI_LAYERSCAPE
+ bool "Freescale Layerscape PCIe controller"
+ depends on OF && ARM
+ select PCIE_DW
+ select MFD_SYSCON
+ help
+ Say Y here if you want PCIe controller support on Layerscape SoCs.
+
endmenu
diff --git a/drivers/pci/host/Makefile b/drivers/pci/host/Makefile
index 26b3461..44c2699 100644
--- a/drivers/pci/host/Makefile
+++ b/drivers/pci/host/Makefile
@@ -11,3 +11,4 @@ obj-$(CONFIG_PCIE_SPEAR13XX) += pcie-spear13xx.o
obj-$(CONFIG_PCI_KEYSTONE) += pci-keystone-dw.o pci-keystone.o
obj-$(CONFIG_PCIE_XILINX) += pcie-xilinx.o
obj-$(CONFIG_PCI_XGENE) += pci-xgene.o
+obj-$(CONFIG_PCI_LAYERSCAPE) += pci-layerscape.o
diff --git a/drivers/pci/host/pci-dra7xx.c b/drivers/pci/host/pci-dra7xx.c
index 52b34fe..8c69697 100644
--- a/drivers/pci/host/pci-dra7xx.c
+++ b/drivers/pci/host/pci-dra7xx.c
@@ -270,8 +270,8 @@ static irqreturn_t dra7xx_pcie_irq_handler(int irq, void *arg)
return IRQ_HANDLED;
}
-static int add_pcie_port(struct dra7xx_pcie *dra7xx,
- struct platform_device *pdev)
+static int __init dra7xx_add_pcie_port(struct dra7xx_pcie *dra7xx,
+ struct platform_device *pdev)
{
int ret;
struct pcie_port *pp;
@@ -398,7 +398,7 @@ static int __init dra7xx_pcie_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, dra7xx);
- ret = add_pcie_port(dra7xx, pdev);
+ ret = dra7xx_add_pcie_port(dra7xx, pdev);
if (ret < 0)
goto err_add_port;
diff --git a/drivers/pci/host/pci-exynos.c b/drivers/pci/host/pci-exynos.c
index c5d0ca3..850c9f9 100644
--- a/drivers/pci/host/pci-exynos.c
+++ b/drivers/pci/host/pci-exynos.c
@@ -312,7 +312,6 @@ static void exynos_pcie_assert_reset(struct pcie_port *pp)
if (exynos_pcie->reset_gpio >= 0)
devm_gpio_request_one(pp->dev, exynos_pcie->reset_gpio,
GPIOF_OUT_INIT_HIGH, "RESET");
- return;
}
static int exynos_pcie_establish_link(struct pcie_port *pp)
@@ -388,7 +387,6 @@ static void exynos_pcie_clear_irq_pulse(struct pcie_port *pp)
val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_PULSE);
exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_PULSE);
- return;
}
static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp)
@@ -400,7 +398,6 @@ static void exynos_pcie_enable_irq_pulse(struct pcie_port *pp)
val = IRQ_INTA_ASSERT | IRQ_INTB_ASSERT |
IRQ_INTC_ASSERT | IRQ_INTD_ASSERT,
exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_PULSE);
- return;
}
static irqreturn_t exynos_pcie_irq_handler(int irq, void *arg)
@@ -429,7 +426,6 @@ static void exynos_pcie_msi_init(struct pcie_port *pp)
val = exynos_elb_readl(exynos_pcie, PCIE_IRQ_EN_LEVEL);
val |= IRQ_MSI_ENABLE;
exynos_elb_writel(exynos_pcie, val, PCIE_IRQ_EN_LEVEL);
- return;
}
static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
@@ -438,8 +434,6 @@ static void exynos_pcie_enable_interrupts(struct pcie_port *pp)
if (IS_ENABLED(CONFIG_PCI_MSI))
exynos_pcie_msi_init(pp);
-
- return;
}
static inline void exynos_pcie_readl_rc(struct pcie_port *pp,
@@ -448,7 +442,6 @@ static inline void exynos_pcie_readl_rc(struct pcie_port *pp,
exynos_pcie_sideband_dbi_r_mode(pp, true);
*val = readl(dbi_base);
exynos_pcie_sideband_dbi_r_mode(pp, false);
- return;
}
static inline void exynos_pcie_writel_rc(struct pcie_port *pp,
@@ -457,7 +450,6 @@ static inline void exynos_pcie_writel_rc(struct pcie_port *pp,
exynos_pcie_sideband_dbi_w_mode(pp, true);
writel(val, dbi_base);
exynos_pcie_sideband_dbi_w_mode(pp, false);
- return;
}
static int exynos_pcie_rd_own_conf(struct pcie_port *pp, int where, int size,
@@ -509,8 +501,8 @@ static struct pcie_host_ops exynos_pcie_host_ops = {
.host_init = exynos_pcie_host_init,
};
-static int __init add_pcie_port(struct pcie_port *pp,
- struct platform_device *pdev)
+static int __init exynos_add_pcie_port(struct pcie_port *pp,
+ struct platform_device *pdev)
{
int ret;
@@ -615,7 +607,7 @@ static int __init exynos_pcie_probe(struct platform_device *pdev)
goto fail_bus_clk;
}
- ret = add_pcie_port(pp, pdev);
+ ret = exynos_add_pcie_port(pp, pdev);
if (ret < 0)
goto fail_bus_clk;
@@ -656,11 +648,11 @@ static struct platform_driver exynos_pcie_driver = {
/* Exynos PCIe driver does not allow module unload */
-static int __init pcie_init(void)
+static int __init exynos_pcie_init(void)
{
return platform_driver_probe(&exynos_pcie_driver, exynos_pcie_probe);
}
-subsys_initcall(pcie_init);
+subsys_initcall(exynos_pcie_init);
MODULE_AUTHOR("Jingoo Han <jg1.han@samsung.com>");
MODULE_DESCRIPTION("Samsung PCIe host controller driver");
diff --git a/drivers/pci/host/pci-host-generic.c b/drivers/pci/host/pci-host-generic.c
index 3d2076f..1895907 100644
--- a/drivers/pci/host/pci-host-generic.c
+++ b/drivers/pci/host/pci-host-generic.c
@@ -32,7 +32,7 @@ struct gen_pci_cfg_bus_ops {
struct gen_pci_cfg_windows {
struct resource res;
- struct resource bus_range;
+ struct resource *bus_range;
void __iomem **win;
const struct gen_pci_cfg_bus_ops *ops;
@@ -50,7 +50,7 @@ static void __iomem *gen_pci_map_cfg_bus_cam(struct pci_bus *bus,
{
struct pci_sys_data *sys = bus->sysdata;
struct gen_pci *pci = sys->private_data;
- resource_size_t idx = bus->number - pci->cfg.bus_range.start;
+ resource_size_t idx = bus->number - pci->cfg.bus_range->start;
return pci->cfg.win[idx] + ((devfn << 8) | where);
}
@@ -66,7 +66,7 @@ static void __iomem *gen_pci_map_cfg_bus_ecam(struct pci_bus *bus,
{
struct pci_sys_data *sys = bus->sysdata;
struct gen_pci *pci = sys->private_data;
- resource_size_t idx = bus->number - pci->cfg.bus_range.start;
+ resource_size_t idx = bus->number - pci->cfg.bus_range->start;
return pci->cfg.win[idx] + ((devfn << 12) | where);
}
@@ -138,106 +138,50 @@ static const struct of_device_id gen_pci_of_match[] = {
};
MODULE_DEVICE_TABLE(of, gen_pci_of_match);
-static int gen_pci_calc_io_offset(struct device *dev,
- struct of_pci_range *range,
- struct resource *res,
- resource_size_t *offset)
-{
- static atomic_t wins = ATOMIC_INIT(0);
- int err, idx, max_win;
- unsigned int window;
-
- if (!PAGE_ALIGNED(range->cpu_addr))
- return -EINVAL;
-
- max_win = (IO_SPACE_LIMIT + 1) / SZ_64K;
- idx = atomic_inc_return(&wins);
- if (idx > max_win)
- return -ENOSPC;
-
- window = (idx - 1) * SZ_64K;
- err = pci_ioremap_io(window, range->cpu_addr);
- if (err)
- return err;
-
- of_pci_range_to_resource(range, dev->of_node, res);
- res->start = window;
- res->end = res->start + range->size - 1;
- *offset = window - range->pci_addr;
- return 0;
-}
-
-static int gen_pci_calc_mem_offset(struct device *dev,
- struct of_pci_range *range,
- struct resource *res,
- resource_size_t *offset)
-{
- of_pci_range_to_resource(range, dev->of_node, res);
- *offset = range->cpu_addr - range->pci_addr;
- return 0;
-}
-
static void gen_pci_release_of_pci_ranges(struct gen_pci *pci)
{
- struct pci_host_bridge_window *win;
-
- list_for_each_entry(win, &pci->resources, list)
- release_resource(win->res);
-
pci_free_resource_list(&pci->resources);
}
static int gen_pci_parse_request_of_pci_ranges(struct gen_pci *pci)
{
- struct of_pci_range range;
- struct of_pci_range_parser parser;
int err, res_valid = 0;
struct device *dev = pci->host.dev.parent;
struct device_node *np = dev->of_node;
+ resource_size_t iobase;
+ struct pci_host_bridge_window *win;
- if (of_pci_range_parser_init(&parser, np)) {
- dev_err(dev, "missing \"ranges\" property\n");
- return -EINVAL;
- }
-
- for_each_of_pci_range(&parser, &range) {
- struct resource *parent, *res;
- resource_size_t offset;
- u32 restype = range.flags & IORESOURCE_TYPE_BITS;
+ err = of_pci_get_host_bridge_resources(np, 0, 0xff, &pci->resources,
+ &iobase);
+ if (err)
+ return err;
- res = devm_kmalloc(dev, sizeof(*res), GFP_KERNEL);
- if (!res) {
- err = -ENOMEM;
- goto out_release_res;
- }
+ list_for_each_entry(win, &pci->resources, list) {
+ struct resource *parent, *res = win->res;
- switch (restype) {
+ switch (resource_type(res)) {
case IORESOURCE_IO:
parent = &ioport_resource;
- err = gen_pci_calc_io_offset(dev, &range, res, &offset);
+ err = pci_remap_iospace(res, iobase);
+ if (err) {
+ dev_warn(dev, "error %d: failed to map resource %pR\n",
+ err, res);
+ continue;
+ }
break;
case IORESOURCE_MEM:
parent = &iomem_resource;
- err = gen_pci_calc_mem_offset(dev, &range, res, &offset);
- res_valid |= !(res->flags & IORESOURCE_PREFETCH || err);
+ res_valid |= !(res->flags & IORESOURCE_PREFETCH);
break;
+ case IORESOURCE_BUS:
+ pci->cfg.bus_range = res;
default:
- err = -EINVAL;
- continue;
- }
-
- if (err) {
- dev_warn(dev,
- "error %d: failed to add resource [type 0x%x, %lld bytes]\n",
- err, restype, range.size);
continue;
}
- err = request_resource(parent, res);
+ err = devm_request_resource(dev, parent, res);
if (err)
goto out_release_res;
-
- pci_add_resource_offset(&pci->resources, res, offset);
}
if (!res_valid) {
@@ -262,38 +206,30 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
struct device *dev = pci->host.dev.parent;
struct device_node *np = dev->of_node;
- if (of_pci_parse_bus_range(np, &pci->cfg.bus_range))
- pci->cfg.bus_range = (struct resource) {
- .name = np->name,
- .start = 0,
- .end = 0xff,
- .flags = IORESOURCE_BUS,
- };
-
err = of_address_to_resource(np, 0, &pci->cfg.res);
if (err) {
dev_err(dev, "missing \"reg\" property\n");
return err;
}
- pci->cfg.win = devm_kcalloc(dev, resource_size(&pci->cfg.bus_range),
+ /* Limit the bus-range to fit within reg */
+ bus_max = pci->cfg.bus_range->start +
+ (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
+ pci->cfg.bus_range->end = min_t(resource_size_t,
+ pci->cfg.bus_range->end, bus_max);
+
+ pci->cfg.win = devm_kcalloc(dev, resource_size(pci->cfg.bus_range),
sizeof(*pci->cfg.win), GFP_KERNEL);
if (!pci->cfg.win)
return -ENOMEM;
- /* Limit the bus-range to fit within reg */
- bus_max = pci->cfg.bus_range.start +
- (resource_size(&pci->cfg.res) >> pci->cfg.ops->bus_shift) - 1;
- pci->cfg.bus_range.end = min_t(resource_size_t, pci->cfg.bus_range.end,
- bus_max);
-
/* Map our Configuration Space windows */
if (!devm_request_mem_region(dev, pci->cfg.res.start,
resource_size(&pci->cfg.res),
"Configuration Space"))
return -ENOMEM;
- bus_range = &pci->cfg.bus_range;
+ bus_range = pci->cfg.bus_range;
for (busn = bus_range->start; busn <= bus_range->end; ++busn) {
u32 idx = busn - bus_range->start;
u32 sz = 1 << pci->cfg.ops->bus_shift;
@@ -305,8 +241,6 @@ static int gen_pci_parse_map_cfg_windows(struct gen_pci *pci)
return -ENOMEM;
}
- /* Register bus resource */
- pci_add_resource(&pci->resources, bus_range);
return 0;
}
diff --git a/drivers/pci/host/pci-imx6.c b/drivers/pci/host/pci-imx6.c
index 69202d1..d1a26d1 100644
--- a/drivers/pci/host/pci-imx6.c
+++ b/drivers/pci/host/pci-imx6.c
@@ -533,8 +533,8 @@ static int __init imx6_add_pcie_port(struct pcie_port *pp,
}
ret = devm_request_irq(&pdev->dev, pp->msi_irq,
- imx6_pcie_msi_handler,
- IRQF_SHARED, "mx6-pcie-msi", pp);
+ imx6_pcie_msi_handler,
+ IRQF_SHARED, "mx6-pcie-msi", pp);
if (ret) {
dev_err(&pdev->dev, "failed to request MSI irq\n");
return -ENODEV;
diff --git a/drivers/pci/host/pci-keystone-dw.c b/drivers/pci/host/pci-keystone-dw.c
index 34086ce..66d8ea4 100644
--- a/drivers/pci/host/pci-keystone-dw.c
+++ b/drivers/pci/host/pci-keystone-dw.c
@@ -155,7 +155,7 @@ static void ks_dw_pcie_msi_irq_mask(struct irq_data *d)
/* Mask the end point if PVM implemented */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (msi->msi_attrib.maskbit)
- mask_msi_irq(d);
+ pci_msi_mask_irq(d);
}
ks_dw_pcie_msi_clear_irq(pp, offset);
@@ -177,7 +177,7 @@ static void ks_dw_pcie_msi_irq_unmask(struct irq_data *d)
/* Mask the end point if PVM implemented */
if (IS_ENABLED(CONFIG_PCI_MSI)) {
if (msi->msi_attrib.maskbit)
- unmask_msi_irq(d);
+ pci_msi_unmask_irq(d);
}
ks_dw_pcie_msi_set_irq(pp, offset);
@@ -201,11 +201,11 @@ static int ks_dw_pcie_msi_map(struct irq_domain *domain, unsigned int irq,
return 0;
}
-const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
+static const struct irq_domain_ops ks_dw_pcie_msi_domain_ops = {
.map = ks_dw_pcie_msi_map,
};
-int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_chip *chip)
+int ks_dw_pcie_msi_host_init(struct pcie_port *pp, struct msi_controller *chip)
{
struct keystone_pcie *ks_pcie = to_keystone_pcie(pp);
int i;
diff --git a/drivers/pci/host/pci-keystone.c b/drivers/pci/host/pci-keystone.c
index 1b893bc..62b9454 100644
--- a/drivers/pci/host/pci-keystone.c
+++ b/drivers/pci/host/pci-keystone.c
@@ -353,10 +353,9 @@ static int __init ks_pcie_probe(struct platform_device *pdev)
ks_pcie = devm_kzalloc(&pdev->dev, sizeof(*ks_pcie),
GFP_KERNEL);
- if (!ks_pcie) {
- dev_err(dev, "no memory for keystone pcie\n");
+ if (!ks_pcie)
return -ENOMEM;
- }
+
pp = &ks_pcie->pp;
/* initialize SerDes Phy if present */
diff --git a/drivers/pci/host/pci-keystone.h b/drivers/pci/host/pci-keystone.h
index 1fc1fce..478d932 100644
--- a/drivers/pci/host/pci-keystone.h
+++ b/drivers/pci/host/pci-keystone.h
@@ -55,4 +55,4 @@ void ks_dw_pcie_msi_set_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_msi_clear_irq(struct pcie_port *pp, int irq);
void ks_dw_pcie_v3_65_scan_bus(struct pcie_port *pp);
int ks_dw_pcie_msi_host_init(struct pcie_port *pp,
- struct msi_chip *chip);
+ struct msi_controller *chip);
diff --git a/drivers/pci/host/pci-layerscape.c b/drivers/pci/host/pci-layerscape.c
new file mode 100644
index 0000000..6697b1a
--- /dev/null
+++ b/drivers/pci/host/pci-layerscape.c
@@ -0,0 +1,179 @@
+/*
+ * PCIe host controller driver for Freescale Layerscape SoCs
+ *
+ * Copyright (C) 2014 Freescale Semiconductor.
+ *
+ * Author: Minghuan Lian <Minghuan.Lian@freescale.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/kernel.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/of_pci.h>
+#include <linux/of_platform.h>
+#include <linux/of_irq.h>
+#include <linux/of_address.h>
+#include <linux/pci.h>
+#include <linux/platform_device.h>
+#include <linux/resource.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+
+#include "pcie-designware.h"
+
+/* PEX1/2 Misc Ports Status Register */
+#define SCFG_PEXMSCPORTSR(pex_idx) (0x94 + (pex_idx) * 4)
+#define LTSSM_STATE_SHIFT 20
+#define LTSSM_STATE_MASK 0x3f
+#define LTSSM_PCIE_L0 0x11 /* L0 state */
+
+/* Symbol Timer Register and Filter Mask Register 1 */
+#define PCIE_STRFMR1 0x71c
+
+struct ls_pcie {
+ struct list_head node;
+ struct device *dev;
+ struct pci_bus *bus;
+ void __iomem *dbi;
+ struct regmap *scfg;
+ struct pcie_port pp;
+ int index;
+ int msi_irq;
+};
+
+#define to_ls_pcie(x) container_of(x, struct ls_pcie, pp)
+
+static int ls_pcie_link_up(struct pcie_port *pp)
+{
+ u32 state;
+ struct ls_pcie *pcie = to_ls_pcie(pp);
+
+ regmap_read(pcie->scfg, SCFG_PEXMSCPORTSR(pcie->index), &state);
+ state = (state >> LTSSM_STATE_SHIFT) & LTSSM_STATE_MASK;
+
+ if (state < LTSSM_PCIE_L0)
+ return 0;
+
+ return 1;
+}
+
+static void ls_pcie_host_init(struct pcie_port *pp)
+{
+ struct ls_pcie *pcie = to_ls_pcie(pp);
+ int count = 0;
+ u32 val;
+
+ dw_pcie_setup_rc(pp);
+
+ while (!ls_pcie_link_up(pp)) {
+ usleep_range(100, 1000);
+ count++;
+ if (count >= 200) {
+ dev_err(pp->dev, "phy link never came up\n");
+ return;
+ }
+ }
+
+ /*
+ * LS1021A Workaround for internal TKT228622
+ * to fix the INTx hang issue
+ */
+ val = ioread32(pcie->dbi + PCIE_STRFMR1);
+ val &= 0xffff;
+ iowrite32(val, pcie->dbi + PCIE_STRFMR1);
+}
+
+static struct pcie_host_ops ls_pcie_host_ops = {
+ .link_up = ls_pcie_link_up,
+ .host_init = ls_pcie_host_init,
+};
+
+static int ls_add_pcie_port(struct ls_pcie *pcie)
+{
+ struct pcie_port *pp;
+ int ret;
+
+ pp = &pcie->pp;
+ pp->dev = pcie->dev;
+ pp->dbi_base = pcie->dbi;
+ pp->root_bus_nr = -1;
+ pp->ops = &ls_pcie_host_ops;
+
+ ret = dw_pcie_host_init(pp);
+ if (ret) {
+ dev_err(pp->dev, "failed to initialize host\n");
+ return ret;
+ }
+
+ return 0;
+}
+
+static int __init ls_pcie_probe(struct platform_device *pdev)
+{
+ struct ls_pcie *pcie;
+ struct resource *dbi_base;
+ u32 index[2];
+ int ret;
+
+ pcie = devm_kzalloc(&pdev->dev, sizeof(*pcie), GFP_KERNEL);
+ if (!pcie)
+ return -ENOMEM;
+
+ pcie->dev = &pdev->dev;
+
+ dbi_base = platform_get_resource_byname(pdev, IORESOURCE_MEM, "regs");
+ if (!dbi_base) {
+ dev_err(&pdev->dev, "missing *regs* space\n");
+ return -ENODEV;
+ }
+
+ pcie->dbi = devm_ioremap_resource(&pdev->dev, dbi_base);
+ if (IS_ERR(pcie->dbi))
+ return PTR_ERR(pcie->dbi);
+
+ pcie->scfg = syscon_regmap_lookup_by_phandle(pdev->dev.of_node,
+ "fsl,pcie-scfg");
+ if (IS_ERR(pcie->scfg)) {
+ dev_err(&pdev->dev, "No syscfg phandle specified\n");
+ return PTR_ERR(pcie->scfg);
+ }
+
+ ret = of_property_read_u32_array(pdev->dev.of_node,
+ "fsl,pcie-scfg", index, 2);
+ if (ret)
+ return ret;
+ pcie->index = index[1];
+
+ ret = ls_add_pcie_port(pcie);
+ if (ret < 0)
+ return ret;
+
+ platform_set_drvdata(pdev, pcie);
+
+ return 0;
+}
+
+static const struct of_device_id ls_pcie_of_match[] = {
+ { .compatible = "fsl,ls1021a-pcie" },
+ { },
+};
+MODULE_DEVICE_TABLE(of, ls_pcie_of_match);
+
+static struct platform_driver ls_pcie_driver = {
+ .driver = {
+ .name = "layerscape-pcie",
+ .owner = THIS_MODULE,
+ .of_match_table = ls_pcie_of_match,
+ },
+};
+
+module_platform_driver_probe(ls_pcie_driver, ls_pcie_probe);
+
+MODULE_AUTHOR("Minghuan Lian <Minghuan.Lian@freescale.com>");
+MODULE_DESCRIPTION("Freescale Layerscape PCIe host controller driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pci/host/pci-mvebu.c b/drivers/pci/host/pci-mvebu.c
index b1315e1..fed3fab 100644
--- a/drivers/pci/host/pci-mvebu.c
+++ b/drivers/pci/host/pci-mvebu.c
@@ -99,7 +99,7 @@ struct mvebu_pcie_port;
struct mvebu_pcie {
struct platform_device *pdev;
struct mvebu_pcie_port *ports;
- struct msi_chip *msi;
+ struct msi_controller *msi;
struct resource io;
char io_name[30];
struct resource realio;
@@ -622,6 +622,7 @@ static struct mvebu_pcie_port *mvebu_pcie_find_port(struct mvebu_pcie *pcie,
for (i = 0; i < pcie->nports; i++) {
struct mvebu_pcie_port *port = &pcie->ports[i];
+
if (bus->number == 0 && port->devfn == devfn)
return port;
if (bus->number != 0 &&
@@ -751,6 +752,7 @@ static int mvebu_pcie_setup(int nr, struct pci_sys_data *sys)
for (i = 0; i < pcie->nports; i++) {
struct mvebu_pcie_port *port = &pcie->ports[i];
+
if (!port->base)
continue;
mvebu_pcie_setup_hw(port);
@@ -774,12 +776,6 @@ static struct pci_bus *mvebu_pcie_scan_bus(int nr, struct pci_sys_data *sys)
return bus;
}
-static void mvebu_pcie_add_bus(struct pci_bus *bus)
-{
- struct mvebu_pcie *pcie = sys_to_pcie(bus->sysdata);
- bus->msi = pcie->msi;
-}
-
static resource_size_t mvebu_pcie_align_resource(struct pci_dev *dev,
const struct resource *res,
resource_size_t start,
@@ -816,6 +812,10 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
memset(&hw, 0, sizeof(hw));
+#ifdef CONFIG_PCI_MSI
+ hw.msi_ctrl = pcie->msi;
+#endif
+
hw.nr_controllers = 1;
hw.private_data = (void **)&pcie;
hw.setup = mvebu_pcie_setup;
@@ -823,7 +823,6 @@ static void mvebu_pcie_enable(struct mvebu_pcie *pcie)
hw.map_irq = of_irq_parse_and_map_pci;
hw.ops = &mvebu_pcie_ops;
hw.align_resource = mvebu_pcie_align_resource;
- hw.add_bus = mvebu_pcie_add_bus;
pci_common_init(&hw);
}
diff --git a/drivers/pci/host/pci-tegra.c b/drivers/pci/host/pci-tegra.c
index 19bb19c..feccfa6 100644
--- a/drivers/pci/host/pci-tegra.c
+++ b/drivers/pci/host/pci-tegra.c
@@ -238,7 +238,7 @@
)
struct tegra_msi {
- struct msi_chip chip;
+ struct msi_controller chip;
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
struct irq_domain *domain;
unsigned long pages;
@@ -259,7 +259,7 @@ struct tegra_pcie_soc_data {
bool has_gen2;
};
-static inline struct tegra_msi *to_tegra_msi(struct msi_chip *chip)
+static inline struct tegra_msi *to_tegra_msi(struct msi_controller *chip)
{
return container_of(chip, struct tegra_msi, chip);
}
@@ -692,15 +692,6 @@ static int tegra_pcie_map_irq(const struct pci_dev *pdev, u8 slot, u8 pin)
return irq;
}
-static void tegra_pcie_add_bus(struct pci_bus *bus)
-{
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- struct tegra_pcie *pcie = sys_to_pcie(bus->sysdata);
-
- bus->msi = &pcie->msi.chip;
- }
-}
-
static struct pci_bus *tegra_pcie_scan_bus(int nr, struct pci_sys_data *sys)
{
struct tegra_pcie *pcie = sys_to_pcie(sys);
@@ -1280,8 +1271,8 @@ static irqreturn_t tegra_pcie_msi_irq(int irq, void *data)
return processed > 0 ? IRQ_HANDLED : IRQ_NONE;
}
-static int tegra_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
- struct msi_desc *desc)
+static int tegra_msi_setup_irq(struct msi_controller *chip,
+ struct pci_dev *pdev, struct msi_desc *desc)
{
struct tegra_msi *msi = to_tegra_msi(chip);
struct msi_msg msg;
@@ -1305,12 +1296,13 @@ static int tegra_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
msg.address_hi = 0;
msg.data = hwirq;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
return 0;
}
-static void tegra_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+static void tegra_msi_teardown_irq(struct msi_controller *chip,
+ unsigned int irq)
{
struct tegra_msi *msi = to_tegra_msi(chip);
struct irq_data *d = irq_get_irq_data(irq);
@@ -1322,10 +1314,10 @@ static void tegra_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
static struct irq_chip tegra_msi_irq_chip = {
.name = "Tegra PCIe MSI",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
static int tegra_msi_map(struct irq_domain *domain, unsigned int irq,
@@ -1893,11 +1885,14 @@ static int tegra_pcie_enable(struct tegra_pcie *pcie)
memset(&hw, 0, sizeof(hw));
+#ifdef CONFIG_PCI_MSI
+ hw.msi_ctrl = &pcie->msi.chip;
+#endif
+
hw.nr_controllers = 1;
hw.private_data = (void **)&pcie;
hw.setup = tegra_pcie_setup;
hw.map_irq = tegra_pcie_map_irq;
- hw.add_bus = tegra_pcie_add_bus;
hw.scan = tegra_pcie_scan_bus;
hw.ops = &tegra_pcie_ops;
diff --git a/drivers/pci/host/pcie-designware.c b/drivers/pci/host/pcie-designware.c
index dfed00a..df781cd 100644
--- a/drivers/pci/host/pcie-designware.c
+++ b/drivers/pci/host/pcie-designware.c
@@ -152,10 +152,10 @@ static int dw_pcie_wr_own_conf(struct pcie_port *pp, int where, int size,
static struct irq_chip dw_msi_irq_chip = {
.name = "PCI-MSI",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
/* MSI int handler */
@@ -276,7 +276,7 @@ no_valid_irq:
return -ENOSPC;
}
-static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
+static int dw_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_desc *desc)
{
int irq, pos;
@@ -298,12 +298,12 @@ static int dw_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
else
msg.data = pos;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
return 0;
}
-static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+static void dw_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
{
struct irq_data *data = irq_get_irq_data(irq);
struct msi_desc *msi = irq_data_get_msi(data);
@@ -312,7 +312,7 @@ static void dw_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
clear_irq_range(pp, irq, 1, data->hwirq);
}
-static struct msi_chip dw_pcie_msi_chip = {
+static struct msi_controller dw_pcie_msi_chip = {
.setup_irq = dw_msi_setup_irq,
.teardown_irq = dw_msi_teardown_irq,
};
@@ -380,6 +380,7 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
/* Get the I/O and memory ranges from DT */
for_each_of_pci_range(&parser, &range) {
unsigned long restype = range.flags & IORESOURCE_TYPE_BITS;
+
if (restype == IORESOURCE_IO) {
of_pci_range_to_resource(&range, np, &pp->io);
pp->io.name = "I/O";
@@ -498,6 +499,11 @@ int __init dw_pcie_host_init(struct pcie_port *pp)
val |= PORT_LOGIC_SPEED_CHANGE;
dw_pcie_wr_own_conf(pp, PCIE_LINK_WIDTH_SPEED_CONTROL, 4, val);
+#ifdef CONFIG_PCI_MSI
+ dw_pcie_msi_chip.dev = pp->dev;
+ dw_pci.msi_ctrl = &dw_pcie_msi_chip;
+#endif
+
dw_pci.nr_controllers = 1;
dw_pci.private_data = (void **)&pp;
@@ -747,21 +753,10 @@ static int dw_pcie_map_irq(const struct pci_dev *dev, u8 slot, u8 pin)
return irq;
}
-static void dw_pcie_add_bus(struct pci_bus *bus)
-{
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- struct pcie_port *pp = sys_to_pcie(bus->sysdata);
-
- dw_pcie_msi_chip.dev = pp->dev;
- bus->msi = &dw_pcie_msi_chip;
- }
-}
-
static struct hw_pci dw_pci = {
.setup = dw_pcie_setup,
.scan = dw_pcie_scan_bus,
.map_irq = dw_pcie_map_irq,
- .add_bus = dw_pcie_add_bus,
};
void dw_pcie_setup_rc(struct pcie_port *pp)
diff --git a/drivers/pci/host/pcie-designware.h b/drivers/pci/host/pcie-designware.h
index c625675..d0bbd27 100644
--- a/drivers/pci/host/pcie-designware.h
+++ b/drivers/pci/host/pcie-designware.h
@@ -73,7 +73,7 @@ struct pcie_host_ops {
u32 (*get_msi_addr)(struct pcie_port *pp);
u32 (*get_msi_data)(struct pcie_port *pp, int pos);
void (*scan_bus)(struct pcie_port *pp);
- int (*msi_host_init)(struct pcie_port *pp, struct msi_chip *chip);
+ int (*msi_host_init)(struct pcie_port *pp, struct msi_controller *chip);
};
int dw_pcie_cfg_read(void __iomem *addr, int where, int size, u32 *val);
diff --git a/drivers/pci/host/pcie-rcar.c b/drivers/pci/host/pcie-rcar.c
index 61158e0..5519e93 100644
--- a/drivers/pci/host/pcie-rcar.c
+++ b/drivers/pci/host/pcie-rcar.c
@@ -111,14 +111,14 @@
struct rcar_msi {
DECLARE_BITMAP(used, INT_PCI_MSI_NR);
struct irq_domain *domain;
- struct msi_chip chip;
+ struct msi_controller chip;
unsigned long pages;
struct mutex lock;
int irq1;
int irq2;
};
-static inline struct rcar_msi *to_rcar_msi(struct msi_chip *chip)
+static inline struct rcar_msi *to_rcar_msi(struct msi_controller *chip)
{
return container_of(chip, struct rcar_msi, chip);
}
@@ -380,20 +380,10 @@ static int rcar_pcie_setup(int nr, struct pci_sys_data *sys)
return 1;
}
-static void rcar_pcie_add_bus(struct pci_bus *bus)
-{
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- struct rcar_pcie *pcie = sys_to_pcie(bus->sysdata);
-
- bus->msi = &pcie->msi.chip;
- }
-}
-
-struct hw_pci rcar_pci = {
+static struct hw_pci rcar_pci = {
.setup = rcar_pcie_setup,
.map_irq = of_irq_parse_and_map_pci,
.ops = &rcar_pcie_ops,
- .add_bus = rcar_pcie_add_bus,
};
static void rcar_pcie_enable(struct rcar_pcie *pcie)
@@ -402,6 +392,9 @@ static void rcar_pcie_enable(struct rcar_pcie *pcie)
rcar_pci.nr_controllers = 1;
rcar_pci.private_data = (void **)&pcie;
+#ifdef CONFIG_PCI_MSI
+ rcar_pci.msi_ctrl = &pcie->msi.chip;
+#endif
pci_common_init_dev(&pdev->dev, &rcar_pci);
#ifdef CONFIG_PCI_DOMAINS
@@ -622,7 +615,7 @@ static irqreturn_t rcar_pcie_msi_irq(int irq, void *data)
return IRQ_HANDLED;
}
-static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
+static int rcar_msi_setup_irq(struct msi_controller *chip, struct pci_dev *pdev,
struct msi_desc *desc)
{
struct rcar_msi *msi = to_rcar_msi(chip);
@@ -647,12 +640,12 @@ static int rcar_msi_setup_irq(struct msi_chip *chip, struct pci_dev *pdev,
msg.address_hi = rcar_pci_read_reg(pcie, PCIEMSIAUR);
msg.data = hwirq;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
return 0;
}
-static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+static void rcar_msi_teardown_irq(struct msi_controller *chip, unsigned int irq)
{
struct rcar_msi *msi = to_rcar_msi(chip);
struct irq_data *d = irq_get_irq_data(irq);
@@ -662,10 +655,10 @@ static void rcar_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
static struct irq_chip rcar_msi_irq_chip = {
.name = "R-Car PCIe MSI",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
static int rcar_msi_map(struct irq_domain *domain, unsigned int irq,
diff --git a/drivers/pci/host/pcie-spear13xx.c b/drivers/pci/host/pcie-spear13xx.c
index 85f594e..2ca10cc 100644
--- a/drivers/pci/host/pcie-spear13xx.c
+++ b/drivers/pci/host/pcie-spear13xx.c
@@ -269,7 +269,8 @@ static struct pcie_host_ops spear13xx_pcie_host_ops = {
.host_init = spear13xx_pcie_host_init,
};
-static int add_pcie_port(struct pcie_port *pp, struct platform_device *pdev)
+static int __init spear13xx_add_pcie_port(struct pcie_port *pp,
+ struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
int ret;
@@ -308,10 +309,8 @@ static int __init spear13xx_pcie_probe(struct platform_device *pdev)
int ret;
spear13xx_pcie = devm_kzalloc(dev, sizeof(*spear13xx_pcie), GFP_KERNEL);
- if (!spear13xx_pcie) {
- dev_err(dev, "no memory for SPEAr13xx pcie\n");
+ if (!spear13xx_pcie)
return -ENOMEM;
- }
spear13xx_pcie->phy = devm_phy_get(dev, "pcie-phy");
if (IS_ERR(spear13xx_pcie->phy)) {
@@ -352,7 +351,7 @@ static int __init spear13xx_pcie_probe(struct platform_device *pdev)
if (of_property_read_bool(np, "st,pcie-is-gen1"))
spear13xx_pcie->is_gen1 = true;
- ret = add_pcie_port(pp, pdev);
+ ret = spear13xx_add_pcie_port(pp, pdev);
if (ret < 0)
goto fail_clk;
@@ -382,11 +381,11 @@ static struct platform_driver spear13xx_pcie_driver __initdata = {
/* SPEAr13xx PCIe driver does not allow module unload */
-static int __init pcie_init(void)
+static int __init spear13xx_pcie_init(void)
{
return platform_driver_register(&spear13xx_pcie_driver);
}
-module_init(pcie_init);
+module_init(spear13xx_pcie_init);
MODULE_DESCRIPTION("ST Microelectronics SPEAr13xx PCIe host controller driver");
MODULE_AUTHOR("Pratyush Anand <pratyush.anand@st.com>");
diff --git a/drivers/pci/host/pcie-xilinx.c b/drivers/pci/host/pcie-xilinx.c
index ccc496b..2f50fa5 100644
--- a/drivers/pci/host/pcie-xilinx.c
+++ b/drivers/pci/host/pcie-xilinx.c
@@ -335,7 +335,8 @@ static int xilinx_pcie_assign_msi(struct xilinx_pcie_port *port)
* @chip: MSI Chip descriptor
* @irq: MSI IRQ to destroy
*/
-static void xilinx_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
+static void xilinx_msi_teardown_irq(struct msi_controller *chip,
+ unsigned int irq)
{
xilinx_pcie_destroy_msi(irq);
}
@@ -348,7 +349,7 @@ static void xilinx_msi_teardown_irq(struct msi_chip *chip, unsigned int irq)
*
* Return: '0' on success and error value on failure
*/
-static int xilinx_pcie_msi_setup_irq(struct msi_chip *chip,
+static int xilinx_pcie_msi_setup_irq(struct msi_controller *chip,
struct pci_dev *pdev,
struct msi_desc *desc)
{
@@ -374,13 +375,13 @@ static int xilinx_pcie_msi_setup_irq(struct msi_chip *chip,
msg.address_lo = msg_addr;
msg.data = irq;
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
return 0;
}
/* MSI Chip Descriptor */
-static struct msi_chip xilinx_pcie_msi_chip = {
+static struct msi_controller xilinx_pcie_msi_chip = {
.setup_irq = xilinx_pcie_msi_setup_irq,
.teardown_irq = xilinx_msi_teardown_irq,
};
@@ -388,10 +389,10 @@ static struct msi_chip xilinx_pcie_msi_chip = {
/* HW Interrupt Chip Descriptor */
static struct irq_chip xilinx_msi_irq_chip = {
.name = "Xilinx PCIe MSI",
- .irq_enable = unmask_msi_irq,
- .irq_disable = mask_msi_irq,
- .irq_mask = mask_msi_irq,
- .irq_unmask = unmask_msi_irq,
+ .irq_enable = pci_msi_unmask_irq,
+ .irq_disable = pci_msi_mask_irq,
+ .irq_mask = pci_msi_mask_irq,
+ .irq_unmask = pci_msi_unmask_irq,
};
/**
@@ -431,20 +432,6 @@ static void xilinx_pcie_enable_msi(struct xilinx_pcie_port *port)
pcie_write(port, msg_addr, XILINX_PCIE_REG_MSIBASE2);
}
-/**
- * xilinx_pcie_add_bus - Add MSI chip info to PCIe bus
- * @bus: PCIe bus
- */
-static void xilinx_pcie_add_bus(struct pci_bus *bus)
-{
- if (IS_ENABLED(CONFIG_PCI_MSI)) {
- struct xilinx_pcie_port *port = sys_to_pcie(bus->sysdata);
-
- xilinx_pcie_msi_chip.dev = port->dev;
- bus->msi = &xilinx_pcie_msi_chip;
- }
-}
-
/* INTx Functions */
/**
@@ -924,10 +911,14 @@ static int xilinx_pcie_probe(struct platform_device *pdev)
.private_data = (void **)&port,
.setup = xilinx_pcie_setup,
.map_irq = of_irq_parse_and_map_pci,
- .add_bus = xilinx_pcie_add_bus,
.scan = xilinx_pcie_scan_bus,
.ops = &xilinx_pcie_ops,
};
+
+#ifdef CONFIG_PCI_MSI
+ xilinx_pcie_msi_chip.dev = port->dev;
+ hw.msi_ctrl = &xilinx_pcie_msi_chip;
+#endif
pci_common_init_dev(dev, &hw);
return 0;
diff --git a/drivers/pci/hotplug/ibmphp_res.c b/drivers/pci/hotplug/ibmphp_res.c
index 219ba80..f279060 100644
--- a/drivers/pci/hotplug/ibmphp_res.c
+++ b/drivers/pci/hotplug/ibmphp_res.c
@@ -376,10 +376,7 @@ int __init ibmphp_rsrc_init (void)
if (rc)
return rc;
}
- rc = once_over (); /* This is to align ranges (so no -1) */
- if (rc)
- return rc;
- return 0;
+ return once_over (); /* This is to align ranges (so no -1) */
}
/********************************************************************************
diff --git a/drivers/pci/iov.c b/drivers/pci/iov.c
index 4d109c0..4b3a4ea 100644
--- a/drivers/pci/iov.c
+++ b/drivers/pci/iov.c
@@ -479,20 +479,16 @@ void pci_iov_release(struct pci_dev *dev)
* pci_iov_resource_bar - get position of the SR-IOV BAR
* @dev: the PCI device
* @resno: the resource number
- * @type: the BAR type to be filled in
*
* Returns position of the BAR encapsulated in the SR-IOV capability.
*/
-int pci_iov_resource_bar(struct pci_dev *dev, int resno,
- enum pci_bar_type *type)
+int pci_iov_resource_bar(struct pci_dev *dev, int resno)
{
if (resno < PCI_IOV_RESOURCES || resno > PCI_IOV_RESOURCE_END)
return 0;
BUG_ON(!dev->is_physfn);
- *type = pci_bar_unknown;
-
return dev->sriov->pos + PCI_SRIOV_BAR +
4 * (resno - PCI_IOV_RESOURCES);
}
@@ -510,13 +506,12 @@ int pci_iov_resource_bar(struct pci_dev *dev, int resno,
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno)
{
struct resource tmp;
- enum pci_bar_type type;
- int reg = pci_iov_resource_bar(dev, resno, &type);
+ int reg = pci_iov_resource_bar(dev, resno);
if (!reg)
return 0;
- __pci_read_base(dev, type, &tmp, reg);
+ __pci_read_base(dev, pci_bar_unknown, &tmp, reg);
return resource_alignment(&tmp);
}
diff --git a/drivers/pci/msi.c b/drivers/pci/msi.c
index 084587d..fd60806 100644
--- a/drivers/pci/msi.c
+++ b/drivers/pci/msi.c
@@ -19,19 +19,82 @@
#include <linux/errno.h>
#include <linux/io.h>
#include <linux/slab.h>
+#include <linux/irqdomain.h>
#include "pci.h"
static int pci_msi_enable = 1;
+int pci_msi_ignore_mask;
#define msix_table_size(flags) ((flags & PCI_MSIX_FLAGS_QSIZE) + 1)
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+static struct irq_domain *pci_msi_default_domain;
+static DEFINE_MUTEX(pci_msi_domain_lock);
+
+struct irq_domain * __weak arch_get_pci_msi_domain(struct pci_dev *dev)
+{
+ return pci_msi_default_domain;
+}
+
+static struct irq_domain *pci_msi_get_domain(struct pci_dev *dev)
+{
+ struct irq_domain *domain = NULL;
+
+ if (dev->bus->msi)
+ domain = dev->bus->msi->domain;
+ if (!domain)
+ domain = arch_get_pci_msi_domain(dev);
+
+ return domain;
+}
+
+static int pci_msi_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
+{
+ struct irq_domain *domain;
+
+ domain = pci_msi_get_domain(dev);
+ if (domain)
+ return pci_msi_domain_alloc_irqs(domain, dev, nvec, type);
+
+ return arch_setup_msi_irqs(dev, nvec, type);
+}
+
+static void pci_msi_teardown_msi_irqs(struct pci_dev *dev)
+{
+ struct irq_domain *domain;
+
+ domain = pci_msi_get_domain(dev);
+ if (domain)
+ pci_msi_domain_free_irqs(domain, dev);
+ else
+ arch_teardown_msi_irqs(dev);
+}
+#else
+#define pci_msi_setup_msi_irqs arch_setup_msi_irqs
+#define pci_msi_teardown_msi_irqs arch_teardown_msi_irqs
+#endif
/* Arch hooks */
+struct msi_controller * __weak pcibios_msi_controller(struct pci_dev *dev)
+{
+ return NULL;
+}
+
+static struct msi_controller *pci_msi_controller(struct pci_dev *dev)
+{
+ struct msi_controller *msi_ctrl = dev->bus->msi;
+
+ if (msi_ctrl)
+ return msi_ctrl;
+
+ return pcibios_msi_controller(dev);
+}
+
int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
{
- struct msi_chip *chip = dev->bus->msi;
+ struct msi_controller *chip = pci_msi_controller(dev);
int err;
if (!chip || !chip->setup_irq)
@@ -48,7 +111,7 @@ int __weak arch_setup_msi_irq(struct pci_dev *dev, struct msi_desc *desc)
void __weak arch_teardown_msi_irq(unsigned int irq)
{
- struct msi_chip *chip = irq_get_chip_data(irq);
+ struct msi_controller *chip = irq_get_chip_data(irq);
if (!chip || !chip->teardown_irq)
return;
@@ -85,19 +148,13 @@ int __weak arch_setup_msi_irqs(struct pci_dev *dev, int nvec, int type)
*/
void default_teardown_msi_irqs(struct pci_dev *dev)
{
+ int i;
struct msi_desc *entry;
- list_for_each_entry(entry, &dev->msi_list, list) {
- int i, nvec;
- if (entry->irq == 0)
- continue;
- if (entry->nvec_used)
- nvec = entry->nvec_used;
- else
- nvec = 1 << entry->msi_attrib.multiple;
- for (i = 0; i < nvec; i++)
- arch_teardown_msi_irq(entry->irq + i);
- }
+ list_for_each_entry(entry, &dev->msi_list, list)
+ if (entry->irq)
+ for (i = 0; i < entry->nvec_used; i++)
+ arch_teardown_msi_irq(entry->irq + i);
}
void __weak arch_teardown_msi_irqs(struct pci_dev *dev)
@@ -120,7 +177,7 @@ static void default_restore_msi_irq(struct pci_dev *dev, int irq)
}
if (entry)
- __write_msi_msg(entry, &entry->msg);
+ __pci_write_msi_msg(entry, &entry->msg);
}
void __weak arch_restore_msi_irqs(struct pci_dev *dev)
@@ -163,11 +220,11 @@ static inline __attribute_const__ u32 msi_mask(unsigned x)
* reliably as devices without an INTx disable bit will then generate a
* level IRQ which will never be cleared.
*/
-u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
+u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{
u32 mask_bits = desc->masked;
- if (!desc->msi_attrib.maskbit)
+ if (pci_msi_ignore_mask || !desc->msi_attrib.maskbit)
return 0;
mask_bits &= ~mask;
@@ -177,14 +234,9 @@ u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
return mask_bits;
}
-__weak u32 arch_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
-{
- return default_msi_mask_irq(desc, mask, flag);
-}
-
static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
{
- desc->masked = arch_msi_mask_irq(desc, mask, flag);
+ desc->masked = __pci_msi_desc_mask_irq(desc, mask, flag);
}
/*
@@ -194,11 +246,15 @@ static void msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag)
* file. This saves a few milliseconds when initialising devices with lots
* of MSI-X interrupts.
*/
-u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag)
+u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag)
{
u32 mask_bits = desc->masked;
unsigned offset = desc->msi_attrib.entry_nr * PCI_MSIX_ENTRY_SIZE +
PCI_MSIX_ENTRY_VECTOR_CTRL;
+
+ if (pci_msi_ignore_mask)
+ return 0;
+
mask_bits &= ~PCI_MSIX_ENTRY_CTRL_MASKBIT;
if (flag)
mask_bits |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
@@ -207,14 +263,9 @@ u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag)
return mask_bits;
}
-__weak u32 arch_msix_mask_irq(struct msi_desc *desc, u32 flag)
-{
- return default_msix_mask_irq(desc, flag);
-}
-
static void msix_mask_irq(struct msi_desc *desc, u32 flag)
{
- desc->masked = arch_msix_mask_irq(desc, flag);
+ desc->masked = __pci_msix_desc_mask_irq(desc, flag);
}
static void msi_set_mask_bit(struct irq_data *data, u32 flag)
@@ -230,12 +281,20 @@ static void msi_set_mask_bit(struct irq_data *data, u32 flag)
}
}
-void mask_msi_irq(struct irq_data *data)
+/**
+ * pci_msi_mask_irq - Generic irq chip callback to mask PCI/MSI interrupts
+ * @data: pointer to irqdata associated to that interrupt
+ */
+void pci_msi_mask_irq(struct irq_data *data)
{
msi_set_mask_bit(data, 1);
}
-void unmask_msi_irq(struct irq_data *data)
+/**
+ * pci_msi_unmask_irq - Generic irq chip callback to unmask PCI/MSI interrupts
+ * @data: pointer to irqdata associated to that interrupt
+ */
+void pci_msi_unmask_irq(struct irq_data *data)
{
msi_set_mask_bit(data, 0);
}
@@ -244,12 +303,11 @@ void default_restore_msi_irqs(struct pci_dev *dev)
{
struct msi_desc *entry;
- list_for_each_entry(entry, &dev->msi_list, list) {
+ list_for_each_entry(entry, &dev->msi_list, list)
default_restore_msi_irq(dev, entry->irq);
- }
}
-void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
BUG_ON(entry->dev->current_state != PCI_D0);
@@ -279,32 +337,7 @@ void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
}
}
-void read_msi_msg(unsigned int irq, struct msi_msg *msg)
-{
- struct msi_desc *entry = irq_get_msi_desc(irq);
-
- __read_msi_msg(entry, msg);
-}
-
-void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
-{
- /* Assert that the cache is valid, assuming that
- * valid messages are not all-zeroes. */
- BUG_ON(!(entry->msg.address_hi | entry->msg.address_lo |
- entry->msg.data));
-
- *msg = entry->msg;
-}
-
-void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
-{
- struct msi_desc *entry = irq_get_msi_desc(irq);
-
- __get_cached_msi_msg(entry, msg);
-}
-EXPORT_SYMBOL_GPL(get_cached_msi_msg);
-
-void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
{
if (entry->dev->current_state != PCI_D0) {
/* Don't touch the hardware now */
@@ -341,34 +374,27 @@ void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
entry->msg = *msg;
}
-void write_msi_msg(unsigned int irq, struct msi_msg *msg)
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg)
{
struct msi_desc *entry = irq_get_msi_desc(irq);
- __write_msi_msg(entry, msg);
+ __pci_write_msi_msg(entry, msg);
}
-EXPORT_SYMBOL_GPL(write_msi_msg);
+EXPORT_SYMBOL_GPL(pci_write_msi_msg);
static void free_msi_irqs(struct pci_dev *dev)
{
struct msi_desc *entry, *tmp;
struct attribute **msi_attrs;
struct device_attribute *dev_attr;
- int count = 0;
+ int i, count = 0;
- list_for_each_entry(entry, &dev->msi_list, list) {
- int i, nvec;
- if (!entry->irq)
- continue;
- if (entry->nvec_used)
- nvec = entry->nvec_used;
- else
- nvec = 1 << entry->msi_attrib.multiple;
- for (i = 0; i < nvec; i++)
- BUG_ON(irq_has_action(entry->irq + i));
- }
+ list_for_each_entry(entry, &dev->msi_list, list)
+ if (entry->irq)
+ for (i = 0; i < entry->nvec_used; i++)
+ BUG_ON(irq_has_action(entry->irq + i));
- arch_teardown_msi_irqs(dev);
+ pci_msi_teardown_msi_irqs(dev);
list_for_each_entry_safe(entry, tmp, &dev->msi_list, list) {
if (entry->msi_attrib.is_msix) {
@@ -451,9 +477,8 @@ static void __pci_restore_msix_state(struct pci_dev *dev)
PCI_MSIX_FLAGS_ENABLE | PCI_MSIX_FLAGS_MASKALL);
arch_restore_msi_irqs(dev);
- list_for_each_entry(entry, &dev->msi_list, list) {
+ list_for_each_entry(entry, &dev->msi_list, list)
msix_mask_irq(entry, entry->masked);
- }
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_MASKALL, 0);
}
@@ -497,9 +522,8 @@ static int populate_msi_sysfs(struct pci_dev *pdev)
int count = 0;
/* Determine how many msi entries we have */
- list_for_each_entry(entry, &pdev->msi_list, list) {
+ list_for_each_entry(entry, &pdev->msi_list, list)
++num_msi;
- }
if (!num_msi)
return 0;
@@ -559,7 +583,7 @@ error_attrs:
return ret;
}
-static struct msi_desc *msi_setup_entry(struct pci_dev *dev)
+static struct msi_desc *msi_setup_entry(struct pci_dev *dev, int nvec)
{
u16 control;
struct msi_desc *entry;
@@ -577,6 +601,8 @@ static struct msi_desc *msi_setup_entry(struct pci_dev *dev)
entry->msi_attrib.maskbit = !!(control & PCI_MSI_FLAGS_MASKBIT);
entry->msi_attrib.default_irq = dev->irq; /* Save IOAPIC IRQ */
entry->msi_attrib.multi_cap = (control & PCI_MSI_FLAGS_QMASK) >> 1;
+ entry->msi_attrib.multiple = ilog2(__roundup_pow_of_two(nvec));
+ entry->nvec_used = nvec;
if (control & PCI_MSI_FLAGS_64BIT)
entry->mask_pos = dev->msi_cap + PCI_MSI_MASK_64;
@@ -623,7 +649,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
msi_set_enable(dev, 0); /* Disable MSI during set up */
- entry = msi_setup_entry(dev);
+ entry = msi_setup_entry(dev, nvec);
if (!entry)
return -ENOMEM;
@@ -634,7 +660,7 @@ static int msi_capability_init(struct pci_dev *dev, int nvec)
list_add_tail(&entry->list, &dev->msi_list);
/* Configure MSI capability structure */
- ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
+ ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSI);
if (ret) {
msi_mask_irq(entry, mask, ~mask);
free_msi_irqs(dev);
@@ -701,6 +727,7 @@ static int msix_setup_entries(struct pci_dev *dev, void __iomem *base,
entry->msi_attrib.entry_nr = entries[i].entry;
entry->msi_attrib.default_irq = dev->irq;
entry->mask_base = base;
+ entry->nvec_used = 1;
list_add_tail(&entry->list, &dev->msi_list);
}
@@ -719,7 +746,6 @@ static void msix_program_entries(struct pci_dev *dev,
PCI_MSIX_ENTRY_VECTOR_CTRL;
entries[i].vector = entry->irq;
- irq_set_msi_desc(entry->irq, entry);
entry->masked = readl(entry->mask_base + offset);
msix_mask_irq(entry, 1);
i++;
@@ -756,7 +782,7 @@ static int msix_capability_init(struct pci_dev *dev,
if (ret)
return ret;
- ret = arch_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
+ ret = pci_msi_setup_msi_irqs(dev, nvec, PCI_CAP_ID_MSIX);
if (ret)
goto out_avail;
@@ -895,7 +921,7 @@ void pci_msi_shutdown(struct pci_dev *dev)
/* Return the device with MSI unmasked as initial states */
mask = msi_mask(desc->msi_attrib.multi_cap);
/* Keep cached state to be restored */
- arch_msi_mask_irq(desc, mask, ~mask);
+ __pci_msi_desc_mask_irq(desc, mask, ~mask);
/* Restore dev->irq to its default pin-assertion irq */
dev->irq = desc->msi_attrib.default_irq;
@@ -993,7 +1019,7 @@ void pci_msix_shutdown(struct pci_dev *dev)
/* Return the device with MSI-X masked as initial states */
list_for_each_entry(entry, &dev->msi_list, list) {
/* Keep cached states to be restored */
- arch_msix_mask_irq(entry, 1);
+ __pci_msix_desc_mask_irq(entry, 1);
}
msix_clear_and_set_ctrl(dev, PCI_MSIX_FLAGS_ENABLE, 0);
@@ -1138,3 +1164,197 @@ int pci_enable_msix_range(struct pci_dev *dev, struct msix_entry *entries,
return nvec;
}
EXPORT_SYMBOL(pci_enable_msix_range);
+
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+/**
+ * pci_msi_domain_write_msg - Helper to write MSI message to PCI config space
+ * @irq_data: Pointer to interrupt data of the MSI interrupt
+ * @msg: Pointer to the message
+ */
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg)
+{
+ struct msi_desc *desc = irq_data->msi_desc;
+
+ /*
+ * For MSI-X desc->irq is always equal to irq_data->irq. For
+ * MSI only the first interrupt of MULTI MSI passes the test.
+ */
+ if (desc->irq == irq_data->irq)
+ __pci_write_msi_msg(desc, msg);
+}
+
+/**
+ * pci_msi_domain_calc_hwirq - Generate a unique ID for an MSI source
+ * @dev: Pointer to the PCI device
+ * @desc: Pointer to the msi descriptor
+ *
+ * The ID number is only used within the irqdomain.
+ */
+irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
+ struct msi_desc *desc)
+{
+ return (irq_hw_number_t)desc->msi_attrib.entry_nr |
+ PCI_DEVID(dev->bus->number, dev->devfn) << 11 |
+ (pci_domain_nr(dev->bus) & 0xFFFFFFFF) << 27;
+}
+
+static inline bool pci_msi_desc_is_multi_msi(struct msi_desc *desc)
+{
+ return !desc->msi_attrib.is_msix && desc->nvec_used > 1;
+}
+
+/**
+ * pci_msi_domain_check_cap - Verify that @domain supports the capabilities for @dev
+ * @domain: The interrupt domain to check
+ * @info: The domain info for verification
+ * @dev: The device to check
+ *
+ * Returns:
+ * 0 if the functionality is supported
+ * 1 if Multi MSI is requested, but the domain does not support it
+ * -ENOTSUPP otherwise
+ */
+int pci_msi_domain_check_cap(struct irq_domain *domain,
+ struct msi_domain_info *info, struct device *dev)
+{
+ struct msi_desc *desc = first_pci_msi_entry(to_pci_dev(dev));
+
+ /* Special handling to support pci_enable_msi_range() */
+ if (pci_msi_desc_is_multi_msi(desc) &&
+ !(info->flags & MSI_FLAG_MULTI_PCI_MSI))
+ return 1;
+ else if (desc->msi_attrib.is_msix && !(info->flags & MSI_FLAG_PCI_MSIX))
+ return -ENOTSUPP;
+
+ return 0;
+}
+
+static int pci_msi_domain_handle_error(struct irq_domain *domain,
+ struct msi_desc *desc, int error)
+{
+ /* Special handling to support pci_enable_msi_range() */
+ if (pci_msi_desc_is_multi_msi(desc) && error == -ENOSPC)
+ return 1;
+
+ return error;
+}
+
+#ifdef GENERIC_MSI_DOMAIN_OPS
+static void pci_msi_domain_set_desc(msi_alloc_info_t *arg,
+ struct msi_desc *desc)
+{
+ arg->desc = desc;
+ arg->hwirq = pci_msi_domain_calc_hwirq(msi_desc_to_pci_dev(desc),
+ desc);
+}
+#else
+#define pci_msi_domain_set_desc NULL
+#endif
+
+static struct msi_domain_ops pci_msi_domain_ops_default = {
+ .set_desc = pci_msi_domain_set_desc,
+ .msi_check = pci_msi_domain_check_cap,
+ .handle_error = pci_msi_domain_handle_error,
+};
+
+static void pci_msi_domain_update_dom_ops(struct msi_domain_info *info)
+{
+ struct msi_domain_ops *ops = info->ops;
+
+ if (ops == NULL) {
+ info->ops = &pci_msi_domain_ops_default;
+ } else {
+ if (ops->set_desc == NULL)
+ ops->set_desc = pci_msi_domain_set_desc;
+ if (ops->msi_check == NULL)
+ ops->msi_check = pci_msi_domain_check_cap;
+ if (ops->handle_error == NULL)
+ ops->handle_error = pci_msi_domain_handle_error;
+ }
+}
+
+static void pci_msi_domain_update_chip_ops(struct msi_domain_info *info)
+{
+ struct irq_chip *chip = info->chip;
+
+ BUG_ON(!chip);
+ if (!chip->irq_write_msi_msg)
+ chip->irq_write_msi_msg = pci_msi_domain_write_msg;
+}
+
+/**
+ * pci_msi_create_irq_domain - Creat a MSI interrupt domain
+ * @node: Optional device-tree node of the interrupt controller
+ * @info: MSI domain info
+ * @parent: Parent irq domain
+ *
+ * Updates the domain and chip ops and creates a MSI interrupt domain.
+ *
+ * Returns:
+ * A domain pointer or NULL in case of failure.
+ */
+struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent)
+{
+ if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
+ pci_msi_domain_update_dom_ops(info);
+ if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
+ pci_msi_domain_update_chip_ops(info);
+
+ return msi_create_irq_domain(node, info, parent);
+}
+
+/**
+ * pci_msi_domain_alloc_irqs - Allocate interrupts for @dev in @domain
+ * @domain: The interrupt domain to allocate from
+ * @dev: The device for which to allocate
+ * @nvec: The number of interrupts to allocate
+ * @type: Unused to allow simpler migration from the arch_XXX interfaces
+ *
+ * Returns:
+ * A virtual interrupt number or an error code in case of failure
+ */
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev,
+ int nvec, int type)
+{
+ return msi_domain_alloc_irqs(domain, &dev->dev, nvec);
+}
+
+/**
+ * pci_msi_domain_free_irqs - Free interrupts for @dev in @domain
+ * @domain: The interrupt domain
+ * @dev: The device for which to free interrupts
+ */
+void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev)
+{
+ msi_domain_free_irqs(domain, &dev->dev);
+}
+
+/**
+ * pci_msi_create_default_irq_domain - Create a default MSI interrupt domain
+ * @node: Optional device-tree node of the interrupt controller
+ * @info: MSI domain info
+ * @parent: Parent irq domain
+ *
+ * Returns: A domain pointer or NULL in case of failure. If successful
+ * the default PCI/MSI irqdomain pointer is updated.
+ */
+struct irq_domain *pci_msi_create_default_irq_domain(struct device_node *node,
+ struct msi_domain_info *info, struct irq_domain *parent)
+{
+ struct irq_domain *domain;
+
+ mutex_lock(&pci_msi_domain_lock);
+ if (pci_msi_default_domain) {
+ pr_err("PCI: default irq domain for PCI MSI has already been created.\n");
+ domain = NULL;
+ } else {
+ domain = pci_msi_create_irq_domain(node, info, parent);
+ pci_msi_default_domain = domain;
+ }
+ mutex_unlock(&pci_msi_domain_lock);
+
+ return domain;
+}
+#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index 6ebf8ed..3542150 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -322,8 +322,7 @@ static void pci_acpi_wake_dev(struct work_struct *work)
pci_wakeup_event(pci_dev);
pm_runtime_resume(&pci_dev->dev);
- if (pci_dev->subordinate)
- pci_pme_wakeup_bus(pci_dev->subordinate);
+ pci_pme_wakeup_bus(pci_dev->subordinate);
}
/**
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index 2b3c894..887e6bd 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -1104,7 +1104,7 @@ static int pci_pm_restore(struct device *dev)
#endif /* !CONFIG_HIBERNATE_CALLBACKS */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int pci_pm_runtime_suspend(struct device *dev)
{
@@ -1200,16 +1200,6 @@ static int pci_pm_runtime_idle(struct device *dev)
return ret;
}
-#else /* !CONFIG_PM_RUNTIME */
-
-#define pci_pm_runtime_suspend NULL
-#define pci_pm_runtime_resume NULL
-#define pci_pm_runtime_idle NULL
-
-#endif /* !CONFIG_PM_RUNTIME */
-
-#ifdef CONFIG_PM
-
static const struct dev_pm_ops pci_dev_pm_ops = {
.prepare = pci_pm_prepare,
.suspend = pci_pm_suspend,
@@ -1231,11 +1221,15 @@ static const struct dev_pm_ops pci_dev_pm_ops = {
#define PCI_PM_OPS_PTR (&pci_dev_pm_ops)
-#else /* !COMFIG_PM_OPS */
+#else /* !CONFIG_PM */
+
+#define pci_pm_runtime_suspend NULL
+#define pci_pm_runtime_resume NULL
+#define pci_pm_runtime_idle NULL
#define PCI_PM_OPS_PTR NULL
-#endif /* !COMFIG_PM_OPS */
+#endif /* !CONFIG_PM */
/**
* __pci_register_driver - register a new pci driver
diff --git a/drivers/pci/pci-sysfs.c b/drivers/pci/pci-sysfs.c
index 2c6643f..a62acc4 100644
--- a/drivers/pci/pci-sysfs.c
+++ b/drivers/pci/pci-sysfs.c
@@ -221,12 +221,37 @@ static ssize_t enable_show(struct device *dev, struct device_attribute *attr,
static DEVICE_ATTR_RW(enable);
#ifdef CONFIG_NUMA
+static ssize_t numa_node_store(struct device *dev,
+ struct device_attribute *attr, const char *buf,
+ size_t count)
+{
+ struct pci_dev *pdev = to_pci_dev(dev);
+ int node, ret;
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ ret = kstrtoint(buf, 0, &node);
+ if (ret)
+ return ret;
+
+ if (!node_online(node))
+ return -EINVAL;
+
+ add_taint(TAINT_FIRMWARE_WORKAROUND, LOCKDEP_STILL_OK);
+ dev_alert(&pdev->dev, FW_BUG "Overriding NUMA node to %d. Contact your vendor for updates.",
+ node);
+
+ dev->numa_node = node;
+ return count;
+}
+
static ssize_t numa_node_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
return sprintf(buf, "%d\n", dev->numa_node);
}
-static DEVICE_ATTR_RO(numa_node);
+static DEVICE_ATTR_RW(numa_node);
#endif
static ssize_t dma_mask_bits_show(struct device *dev,
@@ -385,7 +410,7 @@ static ssize_t dev_bus_rescan_store(struct device *dev,
}
static DEVICE_ATTR(rescan, (S_IWUSR|S_IWGRP), NULL, dev_bus_rescan_store);
-#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
+#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
static ssize_t d3cold_allowed_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
@@ -566,7 +591,7 @@ static struct attribute *pci_dev_attrs[] = {
&dev_attr_enable.attr,
&dev_attr_broken_parity_status.attr,
&dev_attr_msi_bus.attr,
-#if defined(CONFIG_PM_RUNTIME) && defined(CONFIG_ACPI)
+#if defined(CONFIG_PM) && defined(CONFIG_ACPI)
&dev_attr_d3cold_allowed.attr,
#endif
#ifdef CONFIG_OF
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 625a4ac..a7ac726 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1012,11 +1012,7 @@ int pci_save_state(struct pci_dev *dev)
if (i != 0)
return i;
- i = pci_save_vc_state(dev);
- if (i != 0)
- return i;
-
- return 0;
+ return pci_save_vc_state(dev);
}
EXPORT_SYMBOL(pci_save_state);
@@ -3144,12 +3140,10 @@ static int pcie_flr(struct pci_dev *dev, int probe)
return 0;
if (!pci_wait_for_pending_transaction(dev))
- dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
+ dev_err(&dev->dev, "timed out waiting for pending transaction; performing function level reset anyway\n");
pcie_capability_set_word(dev, PCI_EXP_DEVCTL, PCI_EXP_DEVCTL_BCR_FLR);
-
msleep(100);
-
return 0;
}
@@ -3174,16 +3168,12 @@ static int pci_af_flr(struct pci_dev *dev, int probe)
* is used, so we use the conrol offset rather than status and shift
* the test bit to match.
*/
- if (pci_wait_for_pending(dev, pos + PCI_AF_CTRL,
+ if (!pci_wait_for_pending(dev, pos + PCI_AF_CTRL,
PCI_AF_STATUS_TP << 8))
- goto clear;
-
- dev_err(&dev->dev, "transaction is not cleared; proceeding with reset anyway\n");
+ dev_err(&dev->dev, "timed out waiting for pending transaction; performing AF function level reset anyway\n");
-clear:
pci_write_config_byte(dev, pos + PCI_AF_CTRL, PCI_AF_CTRL_FLR);
msleep(100);
-
return 0;
}
@@ -4180,7 +4170,8 @@ int pci_resource_bar(struct pci_dev *dev, int resno, enum pci_bar_type *type)
return dev->rom_base_reg;
} else if (resno < PCI_BRIDGE_RESOURCES) {
/* device specific resource */
- reg = pci_iov_resource_bar(dev, resno, type);
+ *type = pci_bar_unknown;
+ reg = pci_iov_resource_bar(dev, resno);
if (reg)
return reg;
}
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 4a3902d..8aff29a 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -253,8 +253,7 @@ static inline void pci_restore_ats_state(struct pci_dev *dev)
#ifdef CONFIG_PCI_IOV
int pci_iov_init(struct pci_dev *dev);
void pci_iov_release(struct pci_dev *dev);
-int pci_iov_resource_bar(struct pci_dev *dev, int resno,
- enum pci_bar_type *type);
+int pci_iov_resource_bar(struct pci_dev *dev, int resno);
resource_size_t pci_sriov_resource_alignment(struct pci_dev *dev, int resno);
void pci_restore_iov_state(struct pci_dev *dev);
int pci_iov_bus_range(struct pci_bus *bus);
@@ -268,8 +267,7 @@ static inline void pci_iov_release(struct pci_dev *dev)
{
}
-static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno,
- enum pci_bar_type *type)
+static inline int pci_iov_resource_bar(struct pci_dev *dev, int resno)
{
return 0;
}
diff --git a/drivers/pci/pcie/Kconfig b/drivers/pci/pcie/Kconfig
index 7958e59..e294713 100644
--- a/drivers/pci/pcie/Kconfig
+++ b/drivers/pci/pcie/Kconfig
@@ -79,4 +79,4 @@ endchoice
config PCIE_PME
def_bool y
- depends on PCIEPORTBUS && PM_RUNTIME
+ depends on PCIEPORTBUS && PM
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index c8ca98c..23212f8 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -87,8 +87,7 @@ static void release_pcibus_dev(struct device *dev)
{
struct pci_bus *pci_bus = to_pci_bus(dev);
- if (pci_bus->bridge)
- put_device(pci_bus->bridge);
+ put_device(pci_bus->bridge);
pci_bus_remove_resources(pci_bus);
pci_release_bus_of_node(pci_bus);
kfree(pci_bus);
@@ -175,7 +174,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
u64 l64, sz64, mask64;
u16 orig_cmd;
struct pci_bus_region region, inverted_region;
- bool bar_too_big = false, bar_too_high = false, bar_invalid = false;
mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -201,8 +199,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
* memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit
* 1 must be clear.
*/
- if (!sz || sz == 0xffffffff)
- goto fail;
+ if (sz == 0xffffffff)
+ sz = 0;
/*
* I don't know how l can have all bits set. Copied from old code.
@@ -215,23 +213,22 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->flags = decode_bar(dev, l);
res->flags |= IORESOURCE_SIZEALIGN;
if (res->flags & IORESOURCE_IO) {
- l &= PCI_BASE_ADDRESS_IO_MASK;
- mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT;
+ l64 = l & PCI_BASE_ADDRESS_IO_MASK;
+ sz64 = sz & PCI_BASE_ADDRESS_IO_MASK;
+ mask64 = PCI_BASE_ADDRESS_IO_MASK & (u32)IO_SPACE_LIMIT;
} else {
- l &= PCI_BASE_ADDRESS_MEM_MASK;
- mask = (u32)PCI_BASE_ADDRESS_MEM_MASK;
+ l64 = l & PCI_BASE_ADDRESS_MEM_MASK;
+ sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK;
+ mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK;
}
} else {
res->flags |= (l & IORESOURCE_ROM_ENABLE);
- l &= PCI_ROM_ADDRESS_MASK;
- mask = (u32)PCI_ROM_ADDRESS_MASK;
+ l64 = l & PCI_ROM_ADDRESS_MASK;
+ sz64 = sz & PCI_ROM_ADDRESS_MASK;
+ mask64 = (u32)PCI_ROM_ADDRESS_MASK;
}
if (res->flags & IORESOURCE_MEM_64) {
- l64 = l;
- sz64 = sz;
- mask64 = mask | (u64)~0 << 32;
-
pci_read_config_dword(dev, pos + 4, &l);
pci_write_config_dword(dev, pos + 4, ~0);
pci_read_config_dword(dev, pos + 4, &sz);
@@ -239,18 +236,30 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
l64 |= ((u64)l << 32);
sz64 |= ((u64)sz << 32);
+ mask64 |= ((u64)~0 << 32);
+ }
- sz64 = pci_size(l64, sz64, mask64);
+ if (!dev->mmio_always_on && (orig_cmd & PCI_COMMAND_DECODE_ENABLE))
+ pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
- if (!sz64)
- goto fail;
+ if (!sz64)
+ goto fail;
+ sz64 = pci_size(l64, sz64, mask64);
+ if (!sz64) {
+ dev_info(&dev->dev, FW_BUG "reg 0x%x: invalid BAR (can't size)\n",
+ pos);
+ goto fail;
+ }
+
+ if (res->flags & IORESOURCE_MEM_64) {
if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) &&
sz64 > 0x100000000ULL) {
res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED;
res->start = 0;
res->end = 0;
- bar_too_big = true;
+ dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n",
+ pos, (unsigned long long)sz64);
goto out;
}
@@ -259,22 +268,15 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->flags |= IORESOURCE_UNSET;
res->start = 0;
res->end = sz64;
- bar_too_high = true;
+ dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4GB (bus address %#010llx)\n",
+ pos, (unsigned long long)l64);
goto out;
- } else {
- region.start = l64;
- region.end = l64 + sz64;
}
- } else {
- sz = pci_size(l, sz, mask);
-
- if (!sz)
- goto fail;
-
- region.start = l;
- region.end = l + sz;
}
+ region.start = l64;
+ region.end = l64 + sz64;
+
pcibios_bus_to_resource(dev->bus, res, &region);
pcibios_resource_to_bus(dev->bus, &inverted_region, res);
@@ -293,7 +295,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
res->flags |= IORESOURCE_UNSET;
res->start = 0;
res->end = region.end - region.start;
- bar_invalid = true;
+ dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n",
+ pos, (unsigned long long)region.start);
}
goto out;
@@ -302,19 +305,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
fail:
res->flags = 0;
out:
- if (!dev->mmio_always_on &&
- (orig_cmd & PCI_COMMAND_DECODE_ENABLE))
- pci_write_config_word(dev, PCI_COMMAND, orig_cmd);
-
- if (bar_too_big)
- dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n",
- pos, (unsigned long long) sz64);
- if (bar_too_high)
- dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4G (bus address %#010llx)\n",
- pos, (unsigned long long) l64);
- if (bar_invalid)
- dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n",
- pos, (unsigned long long) region.start);
if (res->flags)
dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res);
diff --git a/drivers/pci/search.c b/drivers/pci/search.c
index a81f413..a20ce7d 100644
--- a/drivers/pci/search.c
+++ b/drivers/pci/search.c
@@ -271,8 +271,7 @@ static struct pci_dev *pci_get_dev_by_id(const struct pci_device_id *id,
match_pci_dev_by_id);
if (dev)
pdev = to_pci_dev(dev);
- if (from)
- pci_dev_put(from);
+ pci_dev_put(from);
return pdev;
}
diff --git a/drivers/pci/xen-pcifront.c b/drivers/pci/xen-pcifront.c
index 116ca37..b1ffebe 100644
--- a/drivers/pci/xen-pcifront.c
+++ b/drivers/pci/xen-pcifront.c
@@ -596,8 +596,7 @@ static pci_ers_result_t pcifront_common_process(int cmd,
pcidev = pci_get_bus_and_slot(bus, devfn);
if (!pcidev || !pcidev->driver) {
dev_err(&pdev->xdev->dev, "device or AER driver is NULL\n");
- if (pcidev)
- pci_dev_put(pcidev);
+ pci_dev_put(pcidev);
return result;
}
pdrv = pcidev->driver;
@@ -866,6 +865,11 @@ static int pcifront_try_connect(struct pcifront_device *pdev)
xenbus_dev_error(pdev->xdev, err,
"No PCI Roots found, trying 0000:00");
err = pcifront_scan_root(pdev, 0, 0);
+ if (err) {
+ xenbus_dev_fatal(pdev->xdev, err,
+ "Error scanning PCI root 0000:00");
+ goto out;
+ }
num_roots = 0;
} else if (err != 1) {
if (err == 0)
@@ -947,6 +951,11 @@ static int pcifront_attach_devices(struct pcifront_device *pdev)
xenbus_dev_error(pdev->xdev, err,
"No PCI Roots found, trying 0000:00");
err = pcifront_rescan_root(pdev, 0, 0);
+ if (err) {
+ xenbus_dev_fatal(pdev->xdev, err,
+ "Error scanning PCI root 0000:00");
+ goto out;
+ }
num_roots = 0;
} else if (err != 1) {
if (err == 0)
diff --git a/drivers/pinctrl/Kconfig b/drivers/pinctrl/Kconfig
index c6a66de..d014f22 100644
--- a/drivers/pinctrl/Kconfig
+++ b/drivers/pinctrl/Kconfig
@@ -67,18 +67,6 @@ config PINCTRL_AT91
help
Say Y here to enable the at91 pinctrl driver
-config PINCTRL_BAYTRAIL
- bool "Intel Baytrail GPIO pin control"
- depends on GPIOLIB && ACPI && X86
- select GPIOLIB_IRQCHIP
- help
- driver for memory mapped GPIO functionality on Intel Baytrail
- platforms. Supports 3 banks with 102, 28 and 44 gpios.
- Most pins are usually muxed to some other functionality by firmware,
- so only a small amount is available for gpio use.
-
- Requires ACPI device enumeration code to set up a platform device.
-
config PINCTRL_BCM2835
bool
select PINMUX
@@ -205,6 +193,7 @@ config PINCTRL_PALMAS
source "drivers/pinctrl/berlin/Kconfig"
source "drivers/pinctrl/freescale/Kconfig"
+source "drivers/pinctrl/intel/Kconfig"
source "drivers/pinctrl/mvebu/Kconfig"
source "drivers/pinctrl/nomadik/Kconfig"
source "drivers/pinctrl/qcom/Kconfig"
diff --git a/drivers/pinctrl/Makefile b/drivers/pinctrl/Makefile
index 51f52d3..c030b3d 100644
--- a/drivers/pinctrl/Makefile
+++ b/drivers/pinctrl/Makefile
@@ -15,7 +15,6 @@ obj-$(CONFIG_PINCTRL_BF54x) += pinctrl-adi2-bf54x.o
obj-$(CONFIG_PINCTRL_BF60x) += pinctrl-adi2-bf60x.o
obj-$(CONFIG_PINCTRL_AT91) += pinctrl-at91.o
obj-$(CONFIG_PINCTRL_BCM2835) += pinctrl-bcm2835.o
-obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
obj-$(CONFIG_PINCTRL_BCM281XX) += pinctrl-bcm281xx.o
obj-$(CONFIG_PINCTRL_FALCON) += pinctrl-falcon.o
obj-$(CONFIG_PINCTRL_PALMAS) += pinctrl-palmas.o
@@ -39,6 +38,7 @@ obj-$(CONFIG_PINCTRL_ST) += pinctrl-st.o
obj-$(CONFIG_ARCH_BERLIN) += berlin/
obj-y += freescale/
+obj-$(CONFIG_X86) += intel/
obj-$(CONFIG_PLAT_ORION) += mvebu/
obj-y += nomadik/
obj-$(CONFIG_ARCH_QCOM) += qcom/
diff --git a/drivers/pinctrl/freescale/pinctrl-imx.c b/drivers/pinctrl/freescale/pinctrl-imx.c
index f244676..52f2b94 100644
--- a/drivers/pinctrl/freescale/pinctrl-imx.c
+++ b/drivers/pinctrl/freescale/pinctrl-imx.c
@@ -294,11 +294,83 @@ static int imx_pmx_get_groups(struct pinctrl_dev *pctldev, unsigned selector,
return 0;
}
+static int imx_pmx_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+ struct imx_pin_group *grp;
+ struct imx_pin *imx_pin;
+ unsigned int pin, group;
+ u32 reg;
+
+ /* Currently implementation only for shared mux/conf register */
+ if (!(info->flags & SHARE_MUX_CONF_REG))
+ return -EINVAL;
+
+ pin_reg = &info->pin_regs[offset];
+ if (pin_reg->mux_reg == -1)
+ return -EINVAL;
+
+ /* Find the pinctrl config with GPIO mux mode for the requested pin */
+ for (group = 0; group < info->ngroups; group++) {
+ grp = &info->groups[group];
+ for (pin = 0; pin < grp->npins; pin++) {
+ imx_pin = &grp->pins[pin];
+ if (imx_pin->pin == offset && !imx_pin->mux_mode)
+ goto mux_pin;
+ }
+ }
+
+ return -EINVAL;
+
+mux_pin:
+ reg = readl(ipctl->base + pin_reg->mux_reg);
+ reg &= ~(0x7 << 20);
+ reg |= imx_pin->config;
+ writel(reg, ipctl->base + pin_reg->mux_reg);
+
+ return 0;
+}
+
+static int imx_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range, unsigned offset, bool input)
+{
+ struct imx_pinctrl *ipctl = pinctrl_dev_get_drvdata(pctldev);
+ const struct imx_pinctrl_soc_info *info = ipctl->info;
+ const struct imx_pin_reg *pin_reg;
+ u32 reg;
+
+ /*
+ * Only Vybrid has the input/output buffer enable flags (IBE/OBE)
+ * They are part of the shared mux/conf register.
+ */
+ if (!(info->flags & SHARE_MUX_CONF_REG))
+ return -EINVAL;
+
+ pin_reg = &info->pin_regs[offset];
+ if (pin_reg->mux_reg == -1)
+ return -EINVAL;
+
+ /* IBE always enabled allows us to read the value "on the wire" */
+ reg = readl(ipctl->base + pin_reg->mux_reg);
+ if (input)
+ reg &= ~0x2;
+ else
+ reg |= 0x2;
+ writel(reg, ipctl->base + pin_reg->mux_reg);
+
+ return 0;
+}
+
static const struct pinmux_ops imx_pmx_ops = {
.get_functions_count = imx_pmx_get_funcs_count,
.get_function_name = imx_pmx_get_func_name,
.get_function_groups = imx_pmx_get_groups,
.set_mux = imx_pmx_set,
+ .gpio_request_enable = imx_pmx_gpio_request_enable,
+ .gpio_set_direction = imx_pmx_gpio_set_direction,
};
static int imx_pinconf_get(struct pinctrl_dev *pctldev,
diff --git a/drivers/pinctrl/freescale/pinctrl-mxs.c b/drivers/pinctrl/freescale/pinctrl-mxs.c
index f98c6bb..646d5c2 100644
--- a/drivers/pinctrl/freescale/pinctrl-mxs.c
+++ b/drivers/pinctrl/freescale/pinctrl-mxs.c
@@ -445,6 +445,31 @@ static int mxs_pinctrl_probe_dt(struct platform_device *pdev,
if (of_property_read_u32(child, "reg", &val))
continue;
if (strcmp(fn, child->name)) {
+ struct device_node *child2;
+
+ /*
+ * This reference is dropped by
+ * of_get_next_child(np, * child)
+ */
+ of_node_get(child);
+
+ /*
+ * The logic parsing the functions from dt currently
+ * doesn't handle if functions with the same name are
+ * not grouped together. Only the first contiguous
+ * cluster is usable for each function name. This is a
+ * bug that is not trivial to fix, but at least warn
+ * about it.
+ */
+ for (child2 = of_get_next_child(np, child);
+ child2 != NULL;
+ child2 = of_get_next_child(np, child2)) {
+ if (!strcmp(child2->name, fn))
+ dev_warn(&pdev->dev,
+ "function nodes must be grouped by name (failed for: %s)",
+ fn);
+ }
+
f = &soc->functions[idxf++];
f->name = fn = child->name;
}
diff --git a/drivers/pinctrl/intel/Kconfig b/drivers/pinctrl/intel/Kconfig
new file mode 100644
index 0000000..b801d86
--- /dev/null
+++ b/drivers/pinctrl/intel/Kconfig
@@ -0,0 +1,27 @@
+#
+# Intel pin control drivers
+#
+
+config PINCTRL_BAYTRAIL
+ bool "Intel Baytrail GPIO pin control"
+ depends on GPIOLIB && ACPI
+ select GPIOLIB_IRQCHIP
+ help
+ driver for memory mapped GPIO functionality on Intel Baytrail
+ platforms. Supports 3 banks with 102, 28 and 44 gpios.
+ Most pins are usually muxed to some other functionality by firmware,
+ so only a small amount is available for gpio use.
+
+ Requires ACPI device enumeration code to set up a platform device.
+
+config PINCTRL_CHERRYVIEW
+ tristate "Intel Cherryview/Braswell pinctrl and GPIO driver"
+ depends on ACPI
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ select GPIOLIB
+ select GPIOLIB_IRQCHIP
+ help
+ Cherryview/Braswell pinctrl driver provides an interface that
+ allows configuring of SoC pins and using them as GPIOs.
diff --git a/drivers/pinctrl/intel/Makefile b/drivers/pinctrl/intel/Makefile
new file mode 100644
index 0000000..4c210e4
--- /dev/null
+++ b/drivers/pinctrl/intel/Makefile
@@ -0,0 +1,4 @@
+# Intel pin control drivers
+
+obj-$(CONFIG_PINCTRL_BAYTRAIL) += pinctrl-baytrail.o
+obj-$(CONFIG_PINCTRL_CHERRYVIEW) += pinctrl-cherryview.o
diff --git a/drivers/pinctrl/pinctrl-baytrail.c b/drivers/pinctrl/intel/pinctrl-baytrail.c
index 9dc3814..7db0004 100644
--- a/drivers/pinctrl/pinctrl-baytrail.c
+++ b/drivers/pinctrl/intel/pinctrl-baytrail.c
@@ -616,5 +616,10 @@ static int __init byt_gpio_init(void)
{
return platform_driver_register(&byt_gpio_driver);
}
-
subsys_initcall(byt_gpio_init);
+
+static void __exit byt_gpio_exit(void)
+{
+ platform_driver_unregister(&byt_gpio_driver);
+}
+module_exit(byt_gpio_exit);
diff --git a/drivers/pinctrl/intel/pinctrl-cherryview.c b/drivers/pinctrl/intel/pinctrl-cherryview.c
new file mode 100644
index 0000000..e9f8b39
--- /dev/null
+++ b/drivers/pinctrl/intel/pinctrl-cherryview.c
@@ -0,0 +1,1519 @@
+/*
+ * Cherryview/Braswell pinctrl driver
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Author: Mika Westerberg <mika.westerberg@linux.intel.com>
+ *
+ * This driver is based on the original Cherryview GPIO driver by
+ * Ning Li <ning.li@intel.com>
+ * Alan Cox <alan@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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/gpio.h>
+#include <linux/gpio/driver.h>
+#include <linux/acpi.h>
+#include <linux/pinctrl/pinctrl.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/platform_device.h>
+
+#define CHV_INTSTAT 0x300
+#define CHV_INTMASK 0x380
+
+#define FAMILY_PAD_REGS_OFF 0x4400
+#define FAMILY_PAD_REGS_SIZE 0x400
+#define MAX_FAMILY_PAD_GPIO_NO 15
+#define GPIO_REGS_SIZE 8
+
+#define CHV_PADCTRL0 0x000
+#define CHV_PADCTRL0_INTSEL_SHIFT 28
+#define CHV_PADCTRL0_INTSEL_MASK (0xf << CHV_PADCTRL0_INTSEL_SHIFT)
+#define CHV_PADCTRL0_TERM_UP BIT(23)
+#define CHV_PADCTRL0_TERM_SHIFT 20
+#define CHV_PADCTRL0_TERM_MASK (7 << CHV_PADCTRL0_TERM_SHIFT)
+#define CHV_PADCTRL0_TERM_20K 1
+#define CHV_PADCTRL0_TERM_5K 2
+#define CHV_PADCTRL0_TERM_1K 4
+#define CHV_PADCTRL0_PMODE_SHIFT 16
+#define CHV_PADCTRL0_PMODE_MASK (0xf << CHV_PADCTRL0_PMODE_SHIFT)
+#define CHV_PADCTRL0_GPIOEN BIT(15)
+#define CHV_PADCTRL0_GPIOCFG_SHIFT 8
+#define CHV_PADCTRL0_GPIOCFG_MASK (7 << CHV_PADCTRL0_GPIOCFG_SHIFT)
+#define CHV_PADCTRL0_GPIOCFG_GPIO 0
+#define CHV_PADCTRL0_GPIOCFG_GPO 1
+#define CHV_PADCTRL0_GPIOCFG_GPI 2
+#define CHV_PADCTRL0_GPIOCFG_HIZ 3
+#define CHV_PADCTRL0_GPIOTXSTATE BIT(1)
+#define CHV_PADCTRL0_GPIORXSTATE BIT(0)
+
+#define CHV_PADCTRL1 0x004
+#define CHV_PADCTRL1_CFGLOCK BIT(31)
+#define CHV_PADCTRL1_INVRXTX_SHIFT 4
+#define CHV_PADCTRL1_INVRXTX_MASK (0xf << CHV_PADCTRL1_INVRXTX_SHIFT)
+#define CHV_PADCTRL1_INVRXTX_TXENABLE (2 << CHV_PADCTRL1_INVRXTX_SHIFT)
+#define CHV_PADCTRL1_ODEN BIT(3)
+#define CHV_PADCTRL1_INVRXTX_RXDATA (4 << CHV_PADCTRL1_INVRXTX_SHIFT)
+#define CHV_PADCTRL1_INTWAKECFG_MASK 7
+#define CHV_PADCTRL1_INTWAKECFG_FALLING 1
+#define CHV_PADCTRL1_INTWAKECFG_RISING 2
+#define CHV_PADCTRL1_INTWAKECFG_BOTH 3
+#define CHV_PADCTRL1_INTWAKECFG_LEVEL 4
+
+/**
+ * struct chv_alternate_function - A per group or per pin alternate function
+ * @pin: Pin number (only used in per pin configs)
+ * @mode: Mode the pin should be set in
+ * @invert_oe: Invert OE for this pin
+ */
+struct chv_alternate_function {
+ unsigned pin;
+ u8 mode;
+ bool invert_oe;
+};
+
+/**
+ * struct chv_pincgroup - describes a CHV pin group
+ * @name: Name of the group
+ * @pins: An array of pins in this group
+ * @npins: Number of pins in this group
+ * @altfunc: Alternate function applied to all pins in this group
+ * @overrides: Alternate function override per pin or %NULL if not used
+ * @noverrides: Number of per pin alternate function overrides if
+ * @overrides != NULL.
+ */
+struct chv_pingroup {
+ const char *name;
+ const unsigned *pins;
+ size_t npins;
+ struct chv_alternate_function altfunc;
+ const struct chv_alternate_function *overrides;
+ size_t noverrides;
+};
+
+/**
+ * struct chv_function - A CHV pinmux function
+ * @name: Name of the function
+ * @groups: An array of groups for this function
+ * @ngroups: Number of groups in @groups
+ */
+struct chv_function {
+ const char *name;
+ const char * const *groups;
+ size_t ngroups;
+};
+
+/**
+ * struct chv_gpio_pinrange - A range of pins that can be used as GPIOs
+ * @base: Start pin number
+ * @npins: Number of pins in this range
+ */
+struct chv_gpio_pinrange {
+ unsigned base;
+ unsigned npins;
+};
+
+/**
+ * struct chv_community - A community specific configuration
+ * @uid: ACPI _UID used to match the community
+ * @pins: All pins in this community
+ * @npins: Number of pins
+ * @groups: All groups in this community
+ * @ngroups: Number of groups
+ * @functions: All functions in this community
+ * @nfunctions: Number of functions
+ * @ngpios: Number of GPIOs in this community
+ * @gpio_ranges: An array of GPIO ranges in this community
+ * @ngpio_ranges: Number of GPIO ranges
+ * @ngpios: Total number of GPIOs in this community
+ */
+struct chv_community {
+ const char *uid;
+ const struct pinctrl_pin_desc *pins;
+ size_t npins;
+ const struct chv_pingroup *groups;
+ size_t ngroups;
+ const struct chv_function *functions;
+ size_t nfunctions;
+ const struct chv_gpio_pinrange *gpio_ranges;
+ size_t ngpio_ranges;
+ size_t ngpios;
+};
+
+/**
+ * struct chv_pinctrl - CHV pinctrl private structure
+ * @dev: Pointer to the parent device
+ * @pctldesc: Pin controller description
+ * @pctldev: Pointer to the pin controller device
+ * @chip: GPIO chip in this pin controller
+ * @regs: MMIO registers
+ * @lock: Lock to serialize register accesses
+ * @intr_lines: Stores mapping between 16 HW interrupt wires and GPIO
+ * offset (in GPIO number space)
+ * @community: Community this pinctrl instance represents
+ *
+ * The first group in @groups is expected to contain all pins that can be
+ * used as GPIOs.
+ */
+struct chv_pinctrl {
+ struct device *dev;
+ struct pinctrl_desc pctldesc;
+ struct pinctrl_dev *pctldev;
+ struct gpio_chip chip;
+ void __iomem *regs;
+ spinlock_t lock;
+ unsigned intr_lines[16];
+ const struct chv_community *community;
+};
+
+#define gpiochip_to_pinctrl(c) container_of(c, struct chv_pinctrl, chip)
+
+#define ALTERNATE_FUNCTION(p, m, i) \
+ { \
+ .pin = (p), \
+ .mode = (m), \
+ .invert_oe = (i), \
+ }
+
+#define PIN_GROUP(n, p, m, i) \
+ { \
+ .name = (n), \
+ .pins = (p), \
+ .npins = ARRAY_SIZE((p)), \
+ .altfunc.mode = (m), \
+ .altfunc.invert_oe = (i), \
+ }
+
+#define PIN_GROUP_WITH_OVERRIDE(n, p, m, i, o) \
+ { \
+ .name = (n), \
+ .pins = (p), \
+ .npins = ARRAY_SIZE((p)), \
+ .altfunc.mode = (m), \
+ .altfunc.invert_oe = (i), \
+ .overrides = (o), \
+ .noverrides = ARRAY_SIZE((o)), \
+ }
+
+#define FUNCTION(n, g) \
+ { \
+ .name = (n), \
+ .groups = (g), \
+ .ngroups = ARRAY_SIZE((g)), \
+ }
+
+#define GPIO_PINRANGE(start, end) \
+ { \
+ .base = (start), \
+ .npins = (end) - (start) + 1, \
+ }
+
+static const struct pinctrl_pin_desc southwest_pins[] = {
+ PINCTRL_PIN(0, "FST_SPI_D2"),
+ PINCTRL_PIN(1, "FST_SPI_D0"),
+ PINCTRL_PIN(2, "FST_SPI_CLK"),
+ PINCTRL_PIN(3, "FST_SPI_D3"),
+ PINCTRL_PIN(4, "FST_SPI_CS1_B"),
+ PINCTRL_PIN(5, "FST_SPI_D1"),
+ PINCTRL_PIN(6, "FST_SPI_CS0_B"),
+ PINCTRL_PIN(7, "FST_SPI_CS2_B"),
+
+ PINCTRL_PIN(15, "UART1_RTS_B"),
+ PINCTRL_PIN(16, "UART1_RXD"),
+ PINCTRL_PIN(17, "UART2_RXD"),
+ PINCTRL_PIN(18, "UART1_CTS_B"),
+ PINCTRL_PIN(19, "UART2_RTS_B"),
+ PINCTRL_PIN(20, "UART1_TXD"),
+ PINCTRL_PIN(21, "UART2_TXD"),
+ PINCTRL_PIN(22, "UART2_CTS_B"),
+
+ PINCTRL_PIN(30, "MF_HDA_CLK"),
+ PINCTRL_PIN(31, "MF_HDA_RSTB"),
+ PINCTRL_PIN(32, "MF_HDA_SDIO"),
+ PINCTRL_PIN(33, "MF_HDA_SDO"),
+ PINCTRL_PIN(34, "MF_HDA_DOCKRSTB"),
+ PINCTRL_PIN(35, "MF_HDA_SYNC"),
+ PINCTRL_PIN(36, "MF_HDA_SDI1"),
+ PINCTRL_PIN(37, "MF_HDA_DOCKENB"),
+
+ PINCTRL_PIN(45, "I2C5_SDA"),
+ PINCTRL_PIN(46, "I2C4_SDA"),
+ PINCTRL_PIN(47, "I2C6_SDA"),
+ PINCTRL_PIN(48, "I2C5_SCL"),
+ PINCTRL_PIN(49, "I2C_NFC_SDA"),
+ PINCTRL_PIN(50, "I2C4_SCL"),
+ PINCTRL_PIN(51, "I2C6_SCL"),
+ PINCTRL_PIN(52, "I2C_NFC_SCL"),
+
+ PINCTRL_PIN(60, "I2C1_SDA"),
+ PINCTRL_PIN(61, "I2C0_SDA"),
+ PINCTRL_PIN(62, "I2C2_SDA"),
+ PINCTRL_PIN(63, "I2C1_SCL"),
+ PINCTRL_PIN(64, "I2C3_SDA"),
+ PINCTRL_PIN(65, "I2C0_SCL"),
+ PINCTRL_PIN(66, "I2C2_SCL"),
+ PINCTRL_PIN(67, "I2C3_SCL"),
+
+ PINCTRL_PIN(75, "SATA_GP0"),
+ PINCTRL_PIN(76, "SATA_GP1"),
+ PINCTRL_PIN(77, "SATA_LEDN"),
+ PINCTRL_PIN(78, "SATA_GP2"),
+ PINCTRL_PIN(79, "MF_SMB_ALERTB"),
+ PINCTRL_PIN(80, "SATA_GP3"),
+ PINCTRL_PIN(81, "MF_SMB_CLK"),
+ PINCTRL_PIN(82, "MF_SMB_DATA"),
+
+ PINCTRL_PIN(90, "PCIE_CLKREQ0B"),
+ PINCTRL_PIN(91, "PCIE_CLKREQ1B"),
+ PINCTRL_PIN(92, "GP_SSP_2_CLK"),
+ PINCTRL_PIN(93, "PCIE_CLKREQ2B"),
+ PINCTRL_PIN(94, "GP_SSP_2_RXD"),
+ PINCTRL_PIN(95, "PCIE_CLKREQ3B"),
+ PINCTRL_PIN(96, "GP_SSP_2_FS"),
+ PINCTRL_PIN(97, "GP_SSP_2_TXD"),
+};
+
+static const unsigned southwest_fspi_pins[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
+static const unsigned southwest_uart0_pins[] = { 16, 20 };
+static const unsigned southwest_uart1_pins[] = { 15, 16, 18, 20 };
+static const unsigned southwest_uart2_pins[] = { 17, 19, 21, 22 };
+static const unsigned southwest_i2c0_pins[] = { 61, 65 };
+static const unsigned southwest_hda_pins[] = { 30, 31, 32, 33, 34, 35, 36, 37 };
+static const unsigned southwest_lpe_pins[] = {
+ 30, 31, 32, 33, 34, 35, 36, 37, 92, 94, 96, 97,
+};
+static const unsigned southwest_i2c1_pins[] = { 60, 63 };
+static const unsigned southwest_i2c2_pins[] = { 62, 66 };
+static const unsigned southwest_i2c3_pins[] = { 64, 67 };
+static const unsigned southwest_i2c4_pins[] = { 46, 50 };
+static const unsigned southwest_i2c5_pins[] = { 45, 48 };
+static const unsigned southwest_i2c6_pins[] = { 47, 51 };
+static const unsigned southwest_i2c_nfc_pins[] = { 49, 52 };
+static const unsigned southwest_smbus_pins[] = { 79, 81, 82 };
+static const unsigned southwest_spi3_pins[] = { 76, 79, 80, 81, 82 };
+
+/* LPE I2S TXD pins need to have invert_oe set */
+static const struct chv_alternate_function southwest_lpe_altfuncs[] = {
+ ALTERNATE_FUNCTION(30, 1, true),
+ ALTERNATE_FUNCTION(34, 1, true),
+ ALTERNATE_FUNCTION(97, 1, true),
+};
+
+/*
+ * Two spi3 chipselects are available in different mode than the main spi3
+ * functionality, which is using mode 1.
+ */
+static const struct chv_alternate_function southwest_spi3_altfuncs[] = {
+ ALTERNATE_FUNCTION(76, 3, false),
+ ALTERNATE_FUNCTION(80, 3, false),
+};
+
+static const struct chv_pingroup southwest_groups[] = {
+ PIN_GROUP("uart0_grp", southwest_uart0_pins, 2, false),
+ PIN_GROUP("uart1_grp", southwest_uart1_pins, 1, false),
+ PIN_GROUP("uart2_grp", southwest_uart2_pins, 1, false),
+ PIN_GROUP("hda_grp", southwest_hda_pins, 2, false),
+ PIN_GROUP("i2c0_grp", southwest_i2c0_pins, 1, true),
+ PIN_GROUP("i2c1_grp", southwest_i2c1_pins, 1, true),
+ PIN_GROUP("i2c2_grp", southwest_i2c2_pins, 1, true),
+ PIN_GROUP("i2c3_grp", southwest_i2c3_pins, 1, true),
+ PIN_GROUP("i2c4_grp", southwest_i2c4_pins, 1, true),
+ PIN_GROUP("i2c5_grp", southwest_i2c5_pins, 1, true),
+ PIN_GROUP("i2c6_grp", southwest_i2c6_pins, 1, true),
+ PIN_GROUP("i2c_nfc_grp", southwest_i2c_nfc_pins, 2, true),
+
+ PIN_GROUP_WITH_OVERRIDE("lpe_grp", southwest_lpe_pins, 1, false,
+ southwest_lpe_altfuncs),
+ PIN_GROUP_WITH_OVERRIDE("spi3_grp", southwest_spi3_pins, 2, false,
+ southwest_spi3_altfuncs),
+};
+
+static const char * const southwest_uart0_groups[] = { "uart0_grp" };
+static const char * const southwest_uart1_groups[] = { "uart1_grp" };
+static const char * const southwest_uart2_groups[] = { "uart2_grp" };
+static const char * const southwest_hda_groups[] = { "hda_grp" };
+static const char * const southwest_lpe_groups[] = { "lpe_grp" };
+static const char * const southwest_i2c0_groups[] = { "i2c0_grp" };
+static const char * const southwest_i2c1_groups[] = { "i2c1_grp" };
+static const char * const southwest_i2c2_groups[] = { "i2c2_grp" };
+static const char * const southwest_i2c3_groups[] = { "i2c3_grp" };
+static const char * const southwest_i2c4_groups[] = { "i2c4_grp" };
+static const char * const southwest_i2c5_groups[] = { "i2c5_grp" };
+static const char * const southwest_i2c6_groups[] = { "i2c6_grp" };
+static const char * const southwest_i2c_nfc_groups[] = { "i2c_nfc_grp" };
+static const char * const southwest_spi3_groups[] = { "spi3_grp" };
+
+/*
+ * Only do pinmuxing for certain LPSS devices for now. Rest of the pins are
+ * enabled only as GPIOs.
+ */
+static const struct chv_function southwest_functions[] = {
+ FUNCTION("uart0", southwest_uart0_groups),
+ FUNCTION("uart1", southwest_uart1_groups),
+ FUNCTION("uart2", southwest_uart2_groups),
+ FUNCTION("hda", southwest_hda_groups),
+ FUNCTION("lpe", southwest_lpe_groups),
+ FUNCTION("i2c0", southwest_i2c0_groups),
+ FUNCTION("i2c1", southwest_i2c1_groups),
+ FUNCTION("i2c2", southwest_i2c2_groups),
+ FUNCTION("i2c3", southwest_i2c3_groups),
+ FUNCTION("i2c4", southwest_i2c4_groups),
+ FUNCTION("i2c5", southwest_i2c5_groups),
+ FUNCTION("i2c6", southwest_i2c6_groups),
+ FUNCTION("i2c_nfc", southwest_i2c_nfc_groups),
+ FUNCTION("spi3", southwest_spi3_groups),
+};
+
+static const struct chv_gpio_pinrange southwest_gpio_ranges[] = {
+ GPIO_PINRANGE(0, 7),
+ GPIO_PINRANGE(15, 22),
+ GPIO_PINRANGE(30, 37),
+ GPIO_PINRANGE(45, 52),
+ GPIO_PINRANGE(60, 67),
+ GPIO_PINRANGE(75, 82),
+ GPIO_PINRANGE(90, 97),
+};
+
+static const struct chv_community southwest_community = {
+ .uid = "1",
+ .pins = southwest_pins,
+ .npins = ARRAY_SIZE(southwest_pins),
+ .groups = southwest_groups,
+ .ngroups = ARRAY_SIZE(southwest_groups),
+ .functions = southwest_functions,
+ .nfunctions = ARRAY_SIZE(southwest_functions),
+ .gpio_ranges = southwest_gpio_ranges,
+ .ngpio_ranges = ARRAY_SIZE(southwest_gpio_ranges),
+ .ngpios = ARRAY_SIZE(southwest_pins),
+};
+
+static const struct pinctrl_pin_desc north_pins[] = {
+ PINCTRL_PIN(0, "GPIO_DFX_0"),
+ PINCTRL_PIN(1, "GPIO_DFX_3"),
+ PINCTRL_PIN(2, "GPIO_DFX_7"),
+ PINCTRL_PIN(3, "GPIO_DFX_1"),
+ PINCTRL_PIN(4, "GPIO_DFX_5"),
+ PINCTRL_PIN(5, "GPIO_DFX_4"),
+ PINCTRL_PIN(6, "GPIO_DFX_8"),
+ PINCTRL_PIN(7, "GPIO_DFX_2"),
+ PINCTRL_PIN(8, "GPIO_DFX_6"),
+
+ PINCTRL_PIN(15, "GPIO_SUS0"),
+ PINCTRL_PIN(16, "SEC_GPIO_SUS10"),
+ PINCTRL_PIN(17, "GPIO_SUS3"),
+ PINCTRL_PIN(18, "GPIO_SUS7"),
+ PINCTRL_PIN(19, "GPIO_SUS1"),
+ PINCTRL_PIN(20, "GPIO_SUS5"),
+ PINCTRL_PIN(21, "SEC_GPIO_SUS11"),
+ PINCTRL_PIN(22, "GPIO_SUS4"),
+ PINCTRL_PIN(23, "SEC_GPIO_SUS8"),
+ PINCTRL_PIN(24, "GPIO_SUS2"),
+ PINCTRL_PIN(25, "GPIO_SUS6"),
+ PINCTRL_PIN(26, "CX_PREQ_B"),
+ PINCTRL_PIN(27, "SEC_GPIO_SUS9"),
+
+ PINCTRL_PIN(30, "TRST_B"),
+ PINCTRL_PIN(31, "TCK"),
+ PINCTRL_PIN(32, "PROCHOT_B"),
+ PINCTRL_PIN(33, "SVIDO_DATA"),
+ PINCTRL_PIN(34, "TMS"),
+ PINCTRL_PIN(35, "CX_PRDY_B_2"),
+ PINCTRL_PIN(36, "TDO_2"),
+ PINCTRL_PIN(37, "CX_PRDY_B"),
+ PINCTRL_PIN(38, "SVIDO_ALERT_B"),
+ PINCTRL_PIN(39, "TDO"),
+ PINCTRL_PIN(40, "SVIDO_CLK"),
+ PINCTRL_PIN(41, "TDI"),
+
+ PINCTRL_PIN(45, "GP_CAMERASB_05"),
+ PINCTRL_PIN(46, "GP_CAMERASB_02"),
+ PINCTRL_PIN(47, "GP_CAMERASB_08"),
+ PINCTRL_PIN(48, "GP_CAMERASB_00"),
+ PINCTRL_PIN(49, "GP_CAMERASB_06"),
+ PINCTRL_PIN(50, "GP_CAMERASB_10"),
+ PINCTRL_PIN(51, "GP_CAMERASB_03"),
+ PINCTRL_PIN(52, "GP_CAMERASB_09"),
+ PINCTRL_PIN(53, "GP_CAMERASB_01"),
+ PINCTRL_PIN(54, "GP_CAMERASB_07"),
+ PINCTRL_PIN(55, "GP_CAMERASB_11"),
+ PINCTRL_PIN(56, "GP_CAMERASB_04"),
+
+ PINCTRL_PIN(60, "PANEL0_BKLTEN"),
+ PINCTRL_PIN(61, "HV_DDI0_HPD"),
+ PINCTRL_PIN(62, "HV_DDI2_DDC_SDA"),
+ PINCTRL_PIN(63, "PANEL1_BKLTCTL"),
+ PINCTRL_PIN(64, "HV_DDI1_HPD"),
+ PINCTRL_PIN(65, "PANEL0_BKLTCTL"),
+ PINCTRL_PIN(66, "HV_DDI0_DDC_SDA"),
+ PINCTRL_PIN(67, "HV_DDI2_DDC_SCL"),
+ PINCTRL_PIN(68, "HV_DDI2_HPD"),
+ PINCTRL_PIN(69, "PANEL1_VDDEN"),
+ PINCTRL_PIN(70, "PANEL1_BKLTEN"),
+ PINCTRL_PIN(71, "HV_DDI0_DDC_SCL"),
+ PINCTRL_PIN(72, "PANEL0_VDDEN"),
+};
+
+static const struct chv_gpio_pinrange north_gpio_ranges[] = {
+ GPIO_PINRANGE(0, 8),
+ GPIO_PINRANGE(15, 27),
+ GPIO_PINRANGE(30, 41),
+ GPIO_PINRANGE(45, 56),
+ GPIO_PINRANGE(60, 72),
+};
+
+static const struct chv_community north_community = {
+ .uid = "2",
+ .pins = north_pins,
+ .npins = ARRAY_SIZE(north_pins),
+ .gpio_ranges = north_gpio_ranges,
+ .ngpio_ranges = ARRAY_SIZE(north_gpio_ranges),
+ .ngpios = ARRAY_SIZE(north_pins),
+};
+
+static const struct pinctrl_pin_desc east_pins[] = {
+ PINCTRL_PIN(0, "PMU_SLP_S3_B"),
+ PINCTRL_PIN(1, "PMU_BATLOW_B"),
+ PINCTRL_PIN(2, "SUS_STAT_B"),
+ PINCTRL_PIN(3, "PMU_SLP_S0IX_B"),
+ PINCTRL_PIN(4, "PMU_AC_PRESENT"),
+ PINCTRL_PIN(5, "PMU_PLTRST_B"),
+ PINCTRL_PIN(6, "PMU_SUSCLK"),
+ PINCTRL_PIN(7, "PMU_SLP_LAN_B"),
+ PINCTRL_PIN(8, "PMU_PWRBTN_B"),
+ PINCTRL_PIN(9, "PMU_SLP_S4_B"),
+ PINCTRL_PIN(10, "PMU_WAKE_B"),
+ PINCTRL_PIN(11, "PMU_WAKE_LAN_B"),
+
+ PINCTRL_PIN(15, "MF_ISH_GPIO_3"),
+ PINCTRL_PIN(16, "MF_ISH_GPIO_7"),
+ PINCTRL_PIN(17, "MF_ISH_I2C1_SCL"),
+ PINCTRL_PIN(18, "MF_ISH_GPIO_1"),
+ PINCTRL_PIN(19, "MF_ISH_GPIO_5"),
+ PINCTRL_PIN(20, "MF_ISH_GPIO_9"),
+ PINCTRL_PIN(21, "MF_ISH_GPIO_0"),
+ PINCTRL_PIN(22, "MF_ISH_GPIO_4"),
+ PINCTRL_PIN(23, "MF_ISH_GPIO_8"),
+ PINCTRL_PIN(24, "MF_ISH_GPIO_2"),
+ PINCTRL_PIN(25, "MF_ISH_GPIO_6"),
+ PINCTRL_PIN(26, "MF_ISH_I2C1_SDA"),
+};
+
+static const struct chv_gpio_pinrange east_gpio_ranges[] = {
+ GPIO_PINRANGE(0, 11),
+ GPIO_PINRANGE(15, 26),
+};
+
+static const struct chv_community east_community = {
+ .uid = "3",
+ .pins = east_pins,
+ .npins = ARRAY_SIZE(east_pins),
+ .gpio_ranges = east_gpio_ranges,
+ .ngpio_ranges = ARRAY_SIZE(east_gpio_ranges),
+ .ngpios = ARRAY_SIZE(east_pins),
+};
+
+static const struct pinctrl_pin_desc southeast_pins[] = {
+ PINCTRL_PIN(0, "MF_PLT_CLK0"),
+ PINCTRL_PIN(1, "PWM1"),
+ PINCTRL_PIN(2, "MF_PLT_CLK1"),
+ PINCTRL_PIN(3, "MF_PLT_CLK4"),
+ PINCTRL_PIN(4, "MF_PLT_CLK3"),
+ PINCTRL_PIN(5, "PWM0"),
+ PINCTRL_PIN(6, "MF_PLT_CLK5"),
+ PINCTRL_PIN(7, "MF_PLT_CLK2"),
+
+ PINCTRL_PIN(15, "SDMMC2_D3_CD_B"),
+ PINCTRL_PIN(16, "SDMMC1_CLK"),
+ PINCTRL_PIN(17, "SDMMC1_D0"),
+ PINCTRL_PIN(18, "SDMMC2_D1"),
+ PINCTRL_PIN(19, "SDMMC2_CLK"),
+ PINCTRL_PIN(20, "SDMMC1_D2"),
+ PINCTRL_PIN(21, "SDMMC2_D2"),
+ PINCTRL_PIN(22, "SDMMC2_CMD"),
+ PINCTRL_PIN(23, "SDMMC1_CMD"),
+ PINCTRL_PIN(24, "SDMMC1_D1"),
+ PINCTRL_PIN(25, "SDMMC2_D0"),
+ PINCTRL_PIN(26, "SDMMC1_D3_CD_B"),
+
+ PINCTRL_PIN(30, "SDMMC3_D1"),
+ PINCTRL_PIN(31, "SDMMC3_CLK"),
+ PINCTRL_PIN(32, "SDMMC3_D3"),
+ PINCTRL_PIN(33, "SDMMC3_D2"),
+ PINCTRL_PIN(34, "SDMMC3_CMD"),
+ PINCTRL_PIN(35, "SDMMC3_D0"),
+
+ PINCTRL_PIN(45, "MF_LPC_AD2"),
+ PINCTRL_PIN(46, "LPC_CLKRUNB"),
+ PINCTRL_PIN(47, "MF_LPC_AD0"),
+ PINCTRL_PIN(48, "LPC_FRAMEB"),
+ PINCTRL_PIN(49, "MF_LPC_CLKOUT1"),
+ PINCTRL_PIN(50, "MF_LPC_AD3"),
+ PINCTRL_PIN(51, "MF_LPC_CLKOUT0"),
+ PINCTRL_PIN(52, "MF_LPC_AD1"),
+
+ PINCTRL_PIN(60, "SPI1_MISO"),
+ PINCTRL_PIN(61, "SPI1_CSO_B"),
+ PINCTRL_PIN(62, "SPI1_CLK"),
+ PINCTRL_PIN(63, "MMC1_D6"),
+ PINCTRL_PIN(64, "SPI1_MOSI"),
+ PINCTRL_PIN(65, "MMC1_D5"),
+ PINCTRL_PIN(66, "SPI1_CS1_B"),
+ PINCTRL_PIN(67, "MMC1_D4_SD_WE"),
+ PINCTRL_PIN(68, "MMC1_D7"),
+ PINCTRL_PIN(69, "MMC1_RCLK"),
+
+ PINCTRL_PIN(75, "USB_OC1_B"),
+ PINCTRL_PIN(76, "PMU_RESETBUTTON_B"),
+ PINCTRL_PIN(77, "GPIO_ALERT"),
+ PINCTRL_PIN(78, "SDMMC3_PWR_EN_B"),
+ PINCTRL_PIN(79, "ILB_SERIRQ"),
+ PINCTRL_PIN(80, "USB_OC0_B"),
+ PINCTRL_PIN(81, "SDMMC3_CD_B"),
+ PINCTRL_PIN(82, "SPKR"),
+ PINCTRL_PIN(83, "SUSPWRDNACK"),
+ PINCTRL_PIN(84, "SPARE_PIN"),
+ PINCTRL_PIN(85, "SDMMC3_1P8_EN"),
+};
+
+static const unsigned southeast_pwm0_pins[] = { 5 };
+static const unsigned southeast_pwm1_pins[] = { 1 };
+static const unsigned southeast_sdmmc1_pins[] = {
+ 16, 17, 20, 23, 24, 26, 63, 65, 67, 68, 69,
+};
+static const unsigned southeast_sdmmc2_pins[] = { 15, 18, 19, 21, 22, 25 };
+static const unsigned southeast_sdmmc3_pins[] = {
+ 30, 31, 32, 33, 34, 35, 78, 81, 85,
+};
+static const unsigned southeast_spi1_pins[] = { 60, 61, 62, 64, 66 };
+static const unsigned southeast_spi2_pins[] = { 2, 3, 4, 6, 7 };
+
+static const struct chv_pingroup southeast_groups[] = {
+ PIN_GROUP("pwm0_grp", southeast_pwm0_pins, 1, false),
+ PIN_GROUP("pwm1_grp", southeast_pwm1_pins, 1, false),
+ PIN_GROUP("sdmmc1_grp", southeast_sdmmc1_pins, 1, false),
+ PIN_GROUP("sdmmc2_grp", southeast_sdmmc2_pins, 1, false),
+ PIN_GROUP("sdmmc3_grp", southeast_sdmmc3_pins, 1, false),
+ PIN_GROUP("spi1_grp", southeast_spi1_pins, 1, false),
+ PIN_GROUP("spi2_grp", southeast_spi2_pins, 4, false),
+};
+
+static const char * const southeast_pwm0_groups[] = { "pwm0_grp" };
+static const char * const southeast_pwm1_groups[] = { "pwm1_grp" };
+static const char * const southeast_sdmmc1_groups[] = { "sdmmc1_grp" };
+static const char * const southeast_sdmmc2_groups[] = { "sdmmc2_grp" };
+static const char * const southeast_sdmmc3_groups[] = { "sdmmc3_grp" };
+static const char * const southeast_spi1_groups[] = { "spi1_grp" };
+static const char * const southeast_spi2_groups[] = { "spi2_grp" };
+
+static const struct chv_function southeast_functions[] = {
+ FUNCTION("pwm0", southeast_pwm0_groups),
+ FUNCTION("pwm1", southeast_pwm1_groups),
+ FUNCTION("sdmmc1", southeast_sdmmc1_groups),
+ FUNCTION("sdmmc2", southeast_sdmmc2_groups),
+ FUNCTION("sdmmc3", southeast_sdmmc3_groups),
+ FUNCTION("spi1", southeast_spi1_groups),
+ FUNCTION("spi2", southeast_spi2_groups),
+};
+
+static const struct chv_gpio_pinrange southeast_gpio_ranges[] = {
+ GPIO_PINRANGE(0, 7),
+ GPIO_PINRANGE(15, 26),
+ GPIO_PINRANGE(30, 35),
+ GPIO_PINRANGE(45, 52),
+ GPIO_PINRANGE(60, 69),
+ GPIO_PINRANGE(75, 85),
+};
+
+static const struct chv_community southeast_community = {
+ .uid = "4",
+ .pins = southeast_pins,
+ .npins = ARRAY_SIZE(southeast_pins),
+ .groups = southeast_groups,
+ .ngroups = ARRAY_SIZE(southeast_groups),
+ .functions = southeast_functions,
+ .nfunctions = ARRAY_SIZE(southeast_functions),
+ .gpio_ranges = southeast_gpio_ranges,
+ .ngpio_ranges = ARRAY_SIZE(southeast_gpio_ranges),
+ .ngpios = ARRAY_SIZE(southeast_pins),
+};
+
+static const struct chv_community *chv_communities[] = {
+ &southwest_community,
+ &north_community,
+ &east_community,
+ &southeast_community,
+};
+
+static void __iomem *chv_padreg(struct chv_pinctrl *pctrl, unsigned offset,
+ unsigned reg)
+{
+ unsigned family_no = offset / MAX_FAMILY_PAD_GPIO_NO;
+ unsigned pad_no = offset % MAX_FAMILY_PAD_GPIO_NO;
+
+ offset = FAMILY_PAD_REGS_OFF + FAMILY_PAD_REGS_SIZE * family_no +
+ GPIO_REGS_SIZE * pad_no;
+
+ return pctrl->regs + offset + reg;
+}
+
+static void chv_writel(u32 value, void __iomem *reg)
+{
+ writel(value, reg);
+ /* simple readback to confirm the bus transferring done */
+ readl(reg);
+}
+
+/* When Pad Cfg is locked, driver can only change GPIOTXState or GPIORXState */
+static bool chv_pad_locked(struct chv_pinctrl *pctrl, unsigned offset)
+{
+ void __iomem *reg;
+
+ reg = chv_padreg(pctrl, offset, CHV_PADCTRL1);
+ return readl(reg) & CHV_PADCTRL1_CFGLOCK;
+}
+
+static int chv_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->community->ngroups;
+}
+
+static const char *chv_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned group)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->community->groups[group].name;
+}
+
+static int chv_get_group_pins(struct pinctrl_dev *pctldev, unsigned group,
+ const unsigned **pins, unsigned *npins)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *pins = pctrl->community->groups[group].pins;
+ *npins = pctrl->community->groups[group].npins;
+ return 0;
+}
+
+static void chv_pin_dbg_show(struct pinctrl_dev *pctldev, struct seq_file *s,
+ unsigned offset)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long flags;
+ u32 ctrl0, ctrl1;
+ bool locked;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ ctrl0 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
+ ctrl1 = readl(chv_padreg(pctrl, offset, CHV_PADCTRL1));
+ locked = chv_pad_locked(pctrl, offset);
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ if (ctrl0 & CHV_PADCTRL0_GPIOEN) {
+ seq_puts(s, "GPIO ");
+ } else {
+ u32 mode;
+
+ mode = ctrl0 & CHV_PADCTRL0_PMODE_MASK;
+ mode >>= CHV_PADCTRL0_PMODE_SHIFT;
+
+ seq_printf(s, "mode %d ", mode);
+ }
+
+ seq_printf(s, "ctrl0 0x%08x ctrl1 0x%08x", ctrl0, ctrl1);
+
+ if (locked)
+ seq_puts(s, " [LOCKED]");
+}
+
+static const struct pinctrl_ops chv_pinctrl_ops = {
+ .get_groups_count = chv_get_groups_count,
+ .get_group_name = chv_get_group_name,
+ .get_group_pins = chv_get_group_pins,
+ .pin_dbg_show = chv_pin_dbg_show,
+};
+
+static int chv_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->community->nfunctions;
+}
+
+static const char *chv_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ return pctrl->community->functions[function].name;
+}
+
+static int chv_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char * const **groups,
+ unsigned * const ngroups)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+
+ *groups = pctrl->community->functions[function].groups;
+ *ngroups = pctrl->community->functions[function].ngroups;
+ return 0;
+}
+
+static int chv_pinmux_set_mux(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned group)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ const struct chv_pingroup *grp;
+ unsigned long flags;
+ int i;
+
+ grp = &pctrl->community->groups[group];
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ /* Check first that the pad is not locked */
+ for (i = 0; i < grp->npins; i++) {
+ if (chv_pad_locked(pctrl, grp->pins[i])) {
+ dev_warn(pctrl->dev, "unable to set mode for locked pin %u\n",
+ grp->pins[i]);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+ return -EBUSY;
+ }
+ }
+
+ for (i = 0; i < grp->npins; i++) {
+ const struct chv_alternate_function *altfunc = &grp->altfunc;
+ int pin = grp->pins[i];
+ void __iomem *reg;
+ u32 value;
+
+ /* Check if there is pin-specific config */
+ if (grp->overrides) {
+ int j;
+
+ for (j = 0; j < grp->noverrides; j++) {
+ if (grp->overrides[j].pin == pin) {
+ altfunc = &grp->overrides[j];
+ break;
+ }
+ }
+ }
+
+ reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
+ value = readl(reg);
+ /* Disable GPIO mode */
+ value &= ~CHV_PADCTRL0_GPIOEN;
+ /* Set to desired mode */
+ value &= ~CHV_PADCTRL0_PMODE_MASK;
+ value |= altfunc->mode << CHV_PADCTRL0_PMODE_SHIFT;
+ chv_writel(value, reg);
+
+ /* Update for invert_oe */
+ reg = chv_padreg(pctrl, pin, CHV_PADCTRL1);
+ value = readl(reg) & ~CHV_PADCTRL1_INVRXTX_MASK;
+ if (altfunc->invert_oe)
+ value |= CHV_PADCTRL1_INVRXTX_TXENABLE;
+ chv_writel(value, reg);
+
+ dev_dbg(pctrl->dev, "configured pin %u mode %u OE %sinverted\n",
+ pin, altfunc->mode, altfunc->invert_oe ? "" : "not ");
+ }
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static int chv_gpio_request_enable(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long flags;
+ void __iomem *reg;
+ u32 value;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ if (chv_pad_locked(pctrl, offset)) {
+ value = readl(chv_padreg(pctrl, offset, CHV_PADCTRL0));
+ if (!(value & CHV_PADCTRL0_GPIOEN)) {
+ /* Locked so cannot enable */
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+ return -EBUSY;
+ }
+ } else {
+ int i;
+
+ /* Reset the interrupt mapping */
+ for (i = 0; i < ARRAY_SIZE(pctrl->intr_lines); i++) {
+ if (pctrl->intr_lines[i] == offset) {
+ pctrl->intr_lines[i] = 0;
+ break;
+ }
+ }
+
+ /* Disable interrupt generation */
+ reg = chv_padreg(pctrl, offset, CHV_PADCTRL1);
+ value = readl(reg);
+ value &= ~CHV_PADCTRL1_INTWAKECFG_MASK;
+ value &= ~CHV_PADCTRL1_INVRXTX_MASK;
+ chv_writel(value, reg);
+
+ /* Switch to a GPIO mode */
+ reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
+ value = readl(reg) | CHV_PADCTRL0_GPIOEN;
+ chv_writel(value, reg);
+ }
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static void chv_gpio_disable_free(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ unsigned long flags;
+ void __iomem *reg;
+ u32 value;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
+ value = readl(reg) & ~CHV_PADCTRL0_GPIOEN;
+ chv_writel(value, reg);
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static int chv_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset, bool input)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ void __iomem *reg = chv_padreg(pctrl, offset, CHV_PADCTRL0);
+ unsigned long flags;
+ u32 ctrl0;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ ctrl0 = readl(reg) & ~CHV_PADCTRL0_GPIOCFG_MASK;
+ if (input)
+ ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPI << CHV_PADCTRL0_GPIOCFG_SHIFT;
+ else
+ ctrl0 |= CHV_PADCTRL0_GPIOCFG_GPO << CHV_PADCTRL0_GPIOCFG_SHIFT;
+ chv_writel(ctrl0, reg);
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static const struct pinmux_ops chv_pinmux_ops = {
+ .get_functions_count = chv_get_functions_count,
+ .get_function_name = chv_get_function_name,
+ .get_function_groups = chv_get_function_groups,
+ .set_mux = chv_pinmux_set_mux,
+ .gpio_request_enable = chv_gpio_request_enable,
+ .gpio_disable_free = chv_gpio_disable_free,
+ .gpio_set_direction = chv_gpio_set_direction,
+};
+
+static int chv_config_get(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *config)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param = pinconf_to_config_param(*config);
+ unsigned long flags;
+ u32 ctrl0, ctrl1;
+ u16 arg = 0;
+ u32 term;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+ ctrl1 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL1));
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ term = (ctrl0 & CHV_PADCTRL0_TERM_MASK) >> CHV_PADCTRL0_TERM_SHIFT;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ if (term)
+ return -EINVAL;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ if (!(ctrl0 & CHV_PADCTRL0_TERM_UP))
+ return -EINVAL;
+
+ switch (term) {
+ case CHV_PADCTRL0_TERM_20K:
+ arg = 20000;
+ break;
+ case CHV_PADCTRL0_TERM_5K:
+ arg = 5000;
+ break;
+ case CHV_PADCTRL0_TERM_1K:
+ arg = 1000;
+ break;
+ }
+
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (!term || (ctrl0 & CHV_PADCTRL0_TERM_UP))
+ return -EINVAL;
+
+ switch (term) {
+ case CHV_PADCTRL0_TERM_20K:
+ arg = 20000;
+ break;
+ case CHV_PADCTRL0_TERM_5K:
+ arg = 5000;
+ break;
+ }
+
+ break;
+
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ if (!(ctrl1 & CHV_PADCTRL1_ODEN))
+ return -EINVAL;
+ break;
+
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE: {
+ u32 cfg;
+
+ cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
+ cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
+ if (cfg != CHV_PADCTRL0_GPIOCFG_HIZ)
+ return -EINVAL;
+
+ break;
+ }
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static int chv_config_set_pull(struct chv_pinctrl *pctrl, unsigned pin,
+ enum pin_config_param param, u16 arg)
+{
+ void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
+ unsigned long flags;
+ u32 ctrl0, pull;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+ ctrl0 = readl(reg);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP);
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_UP:
+ ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP);
+
+ switch (arg) {
+ case 1000:
+ /* For 1k there is only pull up */
+ pull = CHV_PADCTRL0_TERM_1K << CHV_PADCTRL0_TERM_SHIFT;
+ break;
+ case 5000:
+ pull = CHV_PADCTRL0_TERM_5K << CHV_PADCTRL0_TERM_SHIFT;
+ break;
+ case 20000:
+ pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
+ break;
+ default:
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+ return -EINVAL;
+ }
+
+ ctrl0 |= CHV_PADCTRL0_TERM_UP | pull;
+ break;
+
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ ctrl0 &= ~(CHV_PADCTRL0_TERM_MASK | CHV_PADCTRL0_TERM_UP);
+
+ switch (arg) {
+ case 5000:
+ pull = CHV_PADCTRL0_TERM_5K << CHV_PADCTRL0_TERM_SHIFT;
+ break;
+ case 20000:
+ pull = CHV_PADCTRL0_TERM_20K << CHV_PADCTRL0_TERM_SHIFT;
+ break;
+ default:
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+ return -EINVAL;
+ }
+
+ ctrl0 |= pull;
+ break;
+
+ default:
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+ return -EINVAL;
+ }
+
+ chv_writel(ctrl0, reg);
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static int chv_config_set(struct pinctrl_dev *pctldev, unsigned pin,
+ unsigned long *configs, unsigned nconfigs)
+{
+ struct chv_pinctrl *pctrl = pinctrl_dev_get_drvdata(pctldev);
+ enum pin_config_param param;
+ int i, ret;
+ u16 arg;
+
+ if (chv_pad_locked(pctrl, pin))
+ return -EBUSY;
+
+ for (i = 0; i < nconfigs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ case PIN_CONFIG_BIAS_PULL_UP:
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ ret = chv_config_set_pull(pctrl, pin, param, arg);
+ if (ret)
+ return ret;
+ break;
+
+ default:
+ return -ENOTSUPP;
+ }
+
+ dev_dbg(pctrl->dev, "pin %d set config %d arg %u\n", pin,
+ param, arg);
+ }
+
+ return 0;
+}
+
+static const struct pinconf_ops chv_pinconf_ops = {
+ .is_generic = true,
+ .pin_config_set = chv_config_set,
+ .pin_config_get = chv_config_get,
+};
+
+static struct pinctrl_desc chv_pinctrl_desc = {
+ .pctlops = &chv_pinctrl_ops,
+ .pmxops = &chv_pinmux_ops,
+ .confops = &chv_pinconf_ops,
+ .owner = THIS_MODULE,
+};
+
+static int chv_gpio_request(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_request_gpio(chip->base + offset);
+}
+
+static void chv_gpio_free(struct gpio_chip *chip, unsigned offset)
+{
+ pinctrl_free_gpio(chip->base + offset);
+}
+
+static unsigned chv_gpio_offset_to_pin(struct chv_pinctrl *pctrl,
+ unsigned offset)
+{
+ return pctrl->community->pins[offset].number;
+}
+
+static int chv_gpio_get(struct gpio_chip *chip, unsigned offset)
+{
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ int pin = chv_gpio_offset_to_pin(pctrl, offset);
+ u32 ctrl0, cfg;
+
+ ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+
+ cfg = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
+ cfg >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
+
+ if (cfg == CHV_PADCTRL0_GPIOCFG_GPO)
+ return !!(ctrl0 & CHV_PADCTRL0_GPIOTXSTATE);
+ return !!(ctrl0 & CHV_PADCTRL0_GPIORXSTATE);
+}
+
+static void chv_gpio_set(struct gpio_chip *chip, unsigned offset, int value)
+{
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ unsigned pin = chv_gpio_offset_to_pin(pctrl, offset);
+ unsigned long flags;
+ void __iomem *reg;
+ u32 ctrl0;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ reg = chv_padreg(pctrl, pin, CHV_PADCTRL0);
+ ctrl0 = readl(reg);
+
+ if (value)
+ ctrl0 |= CHV_PADCTRL0_GPIOTXSTATE;
+ else
+ ctrl0 &= ~CHV_PADCTRL0_GPIOTXSTATE;
+
+ chv_writel(ctrl0, reg);
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static int chv_gpio_get_direction(struct gpio_chip *chip, unsigned offset)
+{
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(chip);
+ unsigned pin = chv_gpio_offset_to_pin(pctrl, offset);
+ u32 ctrl0, direction;
+
+ ctrl0 = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+
+ direction = ctrl0 & CHV_PADCTRL0_GPIOCFG_MASK;
+ direction >>= CHV_PADCTRL0_GPIOCFG_SHIFT;
+
+ return direction != CHV_PADCTRL0_GPIOCFG_GPO;
+}
+
+static int chv_gpio_direction_input(struct gpio_chip *chip, unsigned offset)
+{
+ return pinctrl_gpio_direction_input(chip->base + offset);
+}
+
+static int chv_gpio_direction_output(struct gpio_chip *chip, unsigned offset,
+ int value)
+{
+ return pinctrl_gpio_direction_output(chip->base + offset);
+}
+
+static const struct gpio_chip chv_gpio_chip = {
+ .owner = THIS_MODULE,
+ .request = chv_gpio_request,
+ .free = chv_gpio_free,
+ .get_direction = chv_gpio_get_direction,
+ .direction_input = chv_gpio_direction_input,
+ .direction_output = chv_gpio_direction_output,
+ .get = chv_gpio_get,
+ .set = chv_gpio_set,
+};
+
+static void chv_gpio_irq_ack(struct irq_data *d)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
+ u32 intr_line;
+
+ spin_lock(&pctrl->lock);
+
+ intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+ intr_line &= CHV_PADCTRL0_INTSEL_MASK;
+ intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT;
+ chv_writel(BIT(intr_line), pctrl->regs + CHV_INTSTAT);
+
+ spin_unlock(&pctrl->lock);
+}
+
+static void chv_gpio_irq_mask_unmask(struct irq_data *d, bool mask)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ int pin = chv_gpio_offset_to_pin(pctrl, irqd_to_hwirq(d));
+ u32 value, intr_line;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ intr_line = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+ intr_line &= CHV_PADCTRL0_INTSEL_MASK;
+ intr_line >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+ value = readl(pctrl->regs + CHV_INTMASK);
+ if (mask)
+ value &= ~BIT(intr_line);
+ else
+ value |= BIT(intr_line);
+ chv_writel(value, pctrl->regs + CHV_INTMASK);
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+}
+
+static void chv_gpio_irq_mask(struct irq_data *d)
+{
+ chv_gpio_irq_mask_unmask(d, true);
+}
+
+static void chv_gpio_irq_unmask(struct irq_data *d)
+{
+ chv_gpio_irq_mask_unmask(d, false);
+}
+
+static int chv_gpio_irq_type(struct irq_data *d, unsigned type)
+{
+ struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ unsigned offset = irqd_to_hwirq(d);
+ int pin = chv_gpio_offset_to_pin(pctrl, offset);
+ unsigned long flags;
+ u32 value;
+
+ spin_lock_irqsave(&pctrl->lock, flags);
+
+ /*
+ * Pins which can be used as shared interrupt are configured in
+ * BIOS. Driver trusts BIOS configurations and assigns different
+ * handler according to the irq type.
+ *
+ * Driver needs to save the mapping between each pin and
+ * its interrupt line.
+ * 1. If the pin cfg is locked in BIOS:
+ * Trust BIOS has programmed IntWakeCfg bits correctly,
+ * driver just needs to save the mapping.
+ * 2. If the pin cfg is not locked in BIOS:
+ * Driver programs the IntWakeCfg bits and save the mapping.
+ */
+ if (!chv_pad_locked(pctrl, pin)) {
+ void __iomem *reg = chv_padreg(pctrl, pin, CHV_PADCTRL1);
+
+ value = readl(reg);
+ value &= ~CHV_PADCTRL1_INTWAKECFG_MASK;
+ value &= ~CHV_PADCTRL1_INVRXTX_MASK;
+
+ if (type & IRQ_TYPE_EDGE_BOTH) {
+ if ((type & IRQ_TYPE_EDGE_BOTH) == IRQ_TYPE_EDGE_BOTH)
+ value |= CHV_PADCTRL1_INTWAKECFG_BOTH;
+ else if (type & IRQ_TYPE_EDGE_RISING)
+ value |= CHV_PADCTRL1_INTWAKECFG_RISING;
+ else if (type & IRQ_TYPE_EDGE_FALLING)
+ value |= CHV_PADCTRL1_INTWAKECFG_FALLING;
+ } else if (type & IRQ_TYPE_LEVEL_MASK) {
+ value |= CHV_PADCTRL1_INTWAKECFG_LEVEL;
+ if (type & IRQ_TYPE_LEVEL_LOW)
+ value |= CHV_PADCTRL1_INVRXTX_RXDATA;
+ }
+
+ chv_writel(value, reg);
+ }
+
+ value = readl(chv_padreg(pctrl, pin, CHV_PADCTRL0));
+ value &= CHV_PADCTRL0_INTSEL_MASK;
+ value >>= CHV_PADCTRL0_INTSEL_SHIFT;
+
+ pctrl->intr_lines[value] = offset;
+
+ if (type & IRQ_TYPE_EDGE_BOTH)
+ __irq_set_handler_locked(d->irq, handle_edge_irq);
+ else if (type & IRQ_TYPE_LEVEL_MASK)
+ __irq_set_handler_locked(d->irq, handle_level_irq);
+
+ spin_unlock_irqrestore(&pctrl->lock, flags);
+
+ return 0;
+}
+
+static struct irq_chip chv_gpio_irqchip = {
+ .name = "chv-gpio",
+ .irq_ack = chv_gpio_irq_ack,
+ .irq_mask = chv_gpio_irq_mask,
+ .irq_unmask = chv_gpio_irq_unmask,
+ .irq_set_type = chv_gpio_irq_type,
+ .flags = IRQCHIP_SKIP_SET_WAKE,
+};
+
+static void chv_gpio_irq_handler(unsigned irq, struct irq_desc *desc)
+{
+ struct gpio_chip *gc = irq_desc_get_handler_data(desc);
+ struct chv_pinctrl *pctrl = gpiochip_to_pinctrl(gc);
+ struct irq_chip *chip = irq_get_chip(irq);
+ unsigned long pending;
+ u32 intr_line;
+
+ chained_irq_enter(chip, desc);
+
+ pending = readl(pctrl->regs + CHV_INTSTAT);
+ for_each_set_bit(intr_line, &pending, 16) {
+ unsigned irq, offset;
+
+ offset = pctrl->intr_lines[intr_line];
+ irq = irq_find_mapping(gc->irqdomain, offset);
+ generic_handle_irq(irq);
+ }
+
+ chained_irq_exit(chip, desc);
+}
+
+static int chv_gpio_probe(struct chv_pinctrl *pctrl, int irq)
+{
+ const struct chv_gpio_pinrange *range;
+ struct gpio_chip *chip = &pctrl->chip;
+ int ret, i, offset;
+
+ *chip = chv_gpio_chip;
+
+ chip->ngpio = pctrl->community->ngpios;
+ chip->label = dev_name(pctrl->dev);
+ chip->dev = pctrl->dev;
+ chip->base = -1;
+
+ ret = gpiochip_add(chip);
+ if (ret) {
+ dev_err(pctrl->dev, "Failed to register gpiochip\n");
+ return ret;
+ }
+
+ for (i = 0, offset = 0; i < pctrl->community->ngpio_ranges; i++) {
+ range = &pctrl->community->gpio_ranges[i];
+ ret = gpiochip_add_pin_range(chip, dev_name(pctrl->dev), offset,
+ range->base, range->npins);
+ if (ret) {
+ dev_err(pctrl->dev, "failed to add GPIO pin range\n");
+ goto fail;
+ }
+
+ offset += range->npins;
+ }
+
+ /* Mask and clear all interrupts */
+ chv_writel(0, pctrl->regs + CHV_INTMASK);
+ chv_writel(0xffff, pctrl->regs + CHV_INTSTAT);
+
+ ret = gpiochip_irqchip_add(chip, &chv_gpio_irqchip, 0,
+ handle_simple_irq, IRQ_TYPE_NONE);
+ if (ret) {
+ dev_err(pctrl->dev, "failed to add IRQ chip\n");
+ goto fail;
+ }
+
+ gpiochip_set_chained_irqchip(chip, &chv_gpio_irqchip, irq,
+ chv_gpio_irq_handler);
+ return 0;
+
+fail:
+ gpiochip_remove(chip);
+
+ return ret;
+}
+
+static int chv_pinctrl_probe(struct platform_device *pdev)
+{
+ struct chv_pinctrl *pctrl;
+ struct acpi_device *adev;
+ struct resource *res;
+ int ret, irq, i;
+
+ adev = ACPI_COMPANION(&pdev->dev);
+ if (!adev)
+ return -ENODEV;
+
+ pctrl = devm_kzalloc(&pdev->dev, sizeof(*pctrl), GFP_KERNEL);
+ if (!pctrl)
+ return -ENOMEM;
+
+ for (i = 0; i < ARRAY_SIZE(chv_communities); i++)
+ if (!strcmp(adev->pnp.unique_id, chv_communities[i]->uid)) {
+ pctrl->community = chv_communities[i];
+ break;
+ }
+ if (i == ARRAY_SIZE(chv_communities))
+ return -ENODEV;
+
+ spin_lock_init(&pctrl->lock);
+ pctrl->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ pctrl->regs = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(pctrl->regs))
+ return PTR_ERR(pctrl->regs);
+
+ irq = platform_get_irq(pdev, 0);
+ if (irq < 0) {
+ dev_err(&pdev->dev, "failed to get interrupt number\n");
+ return irq;
+ }
+
+ pctrl->pctldesc = chv_pinctrl_desc;
+ pctrl->pctldesc.name = dev_name(&pdev->dev);
+ pctrl->pctldesc.pins = pctrl->community->pins;
+ pctrl->pctldesc.npins = pctrl->community->npins;
+
+ pctrl->pctldev = pinctrl_register(&pctrl->pctldesc, &pdev->dev, pctrl);
+ if (!pctrl->pctldev) {
+ dev_err(&pdev->dev, "failed to register pinctrl driver\n");
+ return -ENODEV;
+ }
+
+ ret = chv_gpio_probe(pctrl, irq);
+ if (ret) {
+ pinctrl_unregister(pctrl->pctldev);
+ return ret;
+ }
+
+ platform_set_drvdata(pdev, pctrl);
+
+ return 0;
+}
+
+static int chv_pinctrl_remove(struct platform_device *pdev)
+{
+ struct chv_pinctrl *pctrl = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&pctrl->chip);
+ pinctrl_unregister(pctrl->pctldev);
+
+ return 0;
+}
+
+static const struct acpi_device_id chv_pinctrl_acpi_match[] = {
+ { "INT33FF" },
+ { }
+};
+MODULE_DEVICE_TABLE(acpi, chv_pinctrl_acpi_match);
+
+static struct platform_driver chv_pinctrl_driver = {
+ .probe = chv_pinctrl_probe,
+ .remove = chv_pinctrl_remove,
+ .driver = {
+ .name = "cherryview-pinctrl",
+ .owner = THIS_MODULE,
+ .acpi_match_table = chv_pinctrl_acpi_match,
+ },
+};
+
+static int __init chv_pinctrl_init(void)
+{
+ return platform_driver_register(&chv_pinctrl_driver);
+}
+subsys_initcall(chv_pinctrl_init);
+
+static void __exit chv_pinctrl_exit(void)
+{
+ platform_driver_unregister(&chv_pinctrl_driver);
+}
+module_exit(chv_pinctrl_exit);
+
+MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>");
+MODULE_DESCRIPTION("Intel Cherryview/Braswell pinctrl driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/nomadik/pinctrl-abx500.c b/drivers/pinctrl/nomadik/pinctrl-abx500.c
index 2289728..e1087c7 100644
--- a/drivers/pinctrl/nomadik/pinctrl-abx500.c
+++ b/drivers/pinctrl/nomadik/pinctrl-abx500.c
@@ -891,14 +891,13 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
const char *function = NULL;
unsigned long *configs;
unsigned int nconfigs = 0;
- bool has_config = 0;
struct property *prop;
- const char *group, *gpio_name;
- struct device_node *np_config;
- ret = of_property_read_string(np, "ste,function", &function);
+ ret = of_property_read_string(np, "function", &function);
if (ret >= 0) {
- ret = of_property_count_strings(np, "ste,pins");
+ const char *group;
+
+ ret = of_property_count_strings(np, "groups");
if (ret < 0)
goto exit;
@@ -907,7 +906,7 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (ret < 0)
goto exit;
- of_property_for_each_string(np, "ste,pins", prop, group) {
+ of_property_for_each_string(np, "groups", prop, group) {
ret = abx500_dt_add_map_mux(map, reserved_maps,
num_maps, group, function);
if (ret < 0)
@@ -916,18 +915,11 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
}
ret = pinconf_generic_parse_dt_config(np, &configs, &nconfigs);
- if (nconfigs)
- has_config = 1;
- np_config = of_parse_phandle(np, "ste,config", 0);
- if (np_config) {
- ret = pinconf_generic_parse_dt_config(np_config, &configs,
- &nconfigs);
- if (ret)
- goto exit;
- has_config |= nconfigs;
- }
- if (has_config) {
- ret = of_property_count_strings(np, "ste,pins");
+ if (nconfigs) {
+ const char *gpio_name;
+ const char *pin;
+
+ ret = of_property_count_strings(np, "pins");
if (ret < 0)
goto exit;
@@ -937,8 +929,8 @@ static int abx500_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (ret < 0)
goto exit;
- of_property_for_each_string(np, "ste,pins", prop, group) {
- gpio_name = abx500_find_pin_name(pctldev, group);
+ of_property_for_each_string(np, "pins", prop, pin) {
+ gpio_name = abx500_find_pin_name(pctldev, pin);
ret = abx500_dt_add_map_configs(map, reserved_maps,
num_maps, gpio_name, configs, 1);
@@ -1112,6 +1104,7 @@ out:
static const struct pinconf_ops abx500_pinconf_ops = {
.pin_config_get = abx500_pin_config_get,
.pin_config_set = abx500_pin_config_set,
+ .is_generic = true,
};
static struct pinctrl_desc abx500_pinctrl_desc = {
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
index ed39dca..2cd7147 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik-stn8815.c
@@ -291,6 +291,7 @@ static const unsigned u0_a_1_pins[] = { STN8815_PIN_B4, STN8815_PIN_D5,
static const unsigned mmcsd_a_1_pins[] = { STN8815_PIN_B10, STN8815_PIN_A10,
STN8815_PIN_C11, STN8815_PIN_B11, STN8815_PIN_A11, STN8815_PIN_C12,
STN8815_PIN_B12, STN8815_PIN_A12, STN8815_PIN_C13, STN8815_PIN_C15 };
+static const unsigned mmcsd_b_1_pins[] = { STN8815_PIN_D15 };
static const unsigned u1_a_1_pins[] = { STN8815_PIN_M2, STN8815_PIN_L1,
STN8815_PIN_F3, STN8815_PIN_F2 };
static const unsigned i2c1_a_1_pins[] = { STN8815_PIN_L4, STN8815_PIN_L3 };
@@ -305,6 +306,7 @@ static const unsigned i2cusb_b_1_pins[] = { STN8815_PIN_C21, STN8815_PIN_C20 };
static const struct nmk_pingroup nmk_stn8815_groups[] = {
STN8815_PIN_GROUP(u0_a_1, NMK_GPIO_ALT_A),
STN8815_PIN_GROUP(mmcsd_a_1, NMK_GPIO_ALT_A),
+ STN8815_PIN_GROUP(mmcsd_b_1, NMK_GPIO_ALT_B),
STN8815_PIN_GROUP(u1_a_1, NMK_GPIO_ALT_A),
STN8815_PIN_GROUP(i2c1_a_1, NMK_GPIO_ALT_A),
STN8815_PIN_GROUP(i2c0_a_1, NMK_GPIO_ALT_A),
@@ -317,7 +319,7 @@ static const struct nmk_pingroup nmk_stn8815_groups[] = {
static const char * const a##_groups[] = { b };
STN8815_FUNC_GROUPS(u0, "u0_a_1");
-STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1");
+STN8815_FUNC_GROUPS(mmcsd, "mmcsd_a_1", "mmcsd_b_1");
STN8815_FUNC_GROUPS(u1, "u1_a_1", "u1_b_1");
STN8815_FUNC_GROUPS(i2c1, "i2c1_a_1");
STN8815_FUNC_GROUPS(i2c0, "i2c0_a_1");
diff --git a/drivers/pinctrl/nomadik/pinctrl-nomadik.c b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
index 746db6a..ad99ba8 100644
--- a/drivers/pinctrl/nomadik/pinctrl-nomadik.c
+++ b/drivers/pinctrl/nomadik/pinctrl-nomadik.c
@@ -1520,12 +1520,13 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
unsigned long configs = 0;
bool has_config = 0;
struct property *prop;
- const char *group, *gpio_name;
struct device_node *np_config;
- ret = of_property_read_string(np, "ste,function", &function);
+ ret = of_property_read_string(np, "function", &function);
if (ret >= 0) {
- ret = of_property_count_strings(np, "ste,pins");
+ const char *group;
+
+ ret = of_property_count_strings(np, "groups");
if (ret < 0)
goto exit;
@@ -1535,7 +1536,7 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (ret < 0)
goto exit;
- of_property_for_each_string(np, "ste,pins", prop, group) {
+ of_property_for_each_string(np, "groups", prop, group) {
ret = nmk_dt_add_map_mux(map, reserved_maps, num_maps,
group, function);
if (ret < 0)
@@ -1548,7 +1549,10 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (np_config)
has_config |= nmk_pinctrl_dt_get_config(np_config, &configs);
if (has_config) {
- ret = of_property_count_strings(np, "ste,pins");
+ const char *gpio_name;
+ const char *pin;
+
+ ret = of_property_count_strings(np, "pins");
if (ret < 0)
goto exit;
ret = pinctrl_utils_reserve_map(pctldev, map,
@@ -1557,8 +1561,8 @@ static int nmk_pinctrl_dt_subnode_to_map(struct pinctrl_dev *pctldev,
if (ret < 0)
goto exit;
- of_property_for_each_string(np, "ste,pins", prop, group) {
- gpio_name = nmk_find_pin_name(pctldev, group);
+ of_property_for_each_string(np, "pins", prop, pin) {
+ gpio_name = nmk_find_pin_name(pctldev, pin);
ret = nmk_dt_add_map_configs(map, reserved_maps,
num_maps,
diff --git a/drivers/pinctrl/pinconf-generic.c b/drivers/pinctrl/pinconf-generic.c
index 29ff77f..f78b416 100644
--- a/drivers/pinctrl/pinconf-generic.c
+++ b/drivers/pinctrl/pinconf-generic.c
@@ -32,30 +32,32 @@ struct pin_config_item {
const enum pin_config_param param;
const char * const display;
const char * const format;
+ bool has_arg;
};
-#define PCONFDUMP(a, b, c) { .param = a, .display = b, .format = c }
+#define PCONFDUMP(a, b, c, d) { .param = a, .display = b, .format = c, \
+ .has_arg = d }
-static struct pin_config_item conf_items[] = {
- PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL),
- PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL),
- PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL),
- PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL),
- PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL),
+static const struct pin_config_item conf_items[] = {
+ PCONFDUMP(PIN_CONFIG_BIAS_DISABLE, "input bias disabled", NULL, false),
+ PCONFDUMP(PIN_CONFIG_BIAS_HIGH_IMPEDANCE, "input bias high impedance", NULL, false),
+ PCONFDUMP(PIN_CONFIG_BIAS_BUS_HOLD, "input bias bus hold", NULL, false),
+ PCONFDUMP(PIN_CONFIG_BIAS_PULL_UP, "input bias pull up", NULL, false),
+ PCONFDUMP(PIN_CONFIG_BIAS_PULL_DOWN, "input bias pull down", NULL, false),
PCONFDUMP(PIN_CONFIG_BIAS_PULL_PIN_DEFAULT,
- "input bias pull to pin specific state", NULL),
- PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL),
- PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL),
- PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL),
- PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA"),
- PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL),
- PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL),
- PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL),
- PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec"),
- PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector"),
- PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL),
- PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode"),
- PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level"),
+ "input bias pull to pin specific state", NULL, false),
+ PCONFDUMP(PIN_CONFIG_DRIVE_PUSH_PULL, "output drive push pull", NULL, false),
+ PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_DRAIN, "output drive open drain", NULL, false),
+ PCONFDUMP(PIN_CONFIG_DRIVE_OPEN_SOURCE, "output drive open source", NULL, false),
+ PCONFDUMP(PIN_CONFIG_DRIVE_STRENGTH, "output drive strength", "mA", true),
+ PCONFDUMP(PIN_CONFIG_INPUT_ENABLE, "input enabled", NULL, false),
+ PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT_ENABLE, "input schmitt enabled", NULL, false),
+ PCONFDUMP(PIN_CONFIG_INPUT_SCHMITT, "input schmitt trigger", NULL, false),
+ PCONFDUMP(PIN_CONFIG_INPUT_DEBOUNCE, "input debounce", "usec", true),
+ PCONFDUMP(PIN_CONFIG_POWER_SOURCE, "pin power source", "selector", true),
+ PCONFDUMP(PIN_CONFIG_SLEW_RATE, "slew rate", NULL, true),
+ PCONFDUMP(PIN_CONFIG_LOW_POWER_MODE, "pin low power", "mode", true),
+ PCONFDUMP(PIN_CONFIG_OUTPUT, "pin output", "level", true),
};
void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
@@ -85,11 +87,14 @@ void pinconf_generic_dump_pin(struct pinctrl_dev *pctldev,
seq_puts(s, " ");
seq_puts(s, conf_items[i].display);
/* Print unit if available */
- if (conf_items[i].format &&
- pinconf_to_config_argument(config) != 0)
- seq_printf(s, " (%u %s)",
- pinconf_to_config_argument(config),
- conf_items[i].format);
+ if (conf_items[i].has_arg) {
+ seq_printf(s, " (%u",
+ pinconf_to_config_argument(config));
+ if (conf_items[i].format)
+ seq_printf(s, " %s)", conf_items[i].format);
+ else
+ seq_puts(s, ")");
+ }
}
}
@@ -121,10 +126,14 @@ void pinconf_generic_dump_group(struct pinctrl_dev *pctldev,
seq_puts(s, " ");
seq_puts(s, conf_items[i].display);
/* Print unit if available */
- if (conf_items[i].format && config != 0)
- seq_printf(s, " (%u %s)",
- pinconf_to_config_argument(config),
- conf_items[i].format);
+ if (conf_items[i].has_arg) {
+ seq_printf(s, " (%u",
+ pinconf_to_config_argument(config));
+ if (conf_items[i].format)
+ seq_printf(s, " %s)", conf_items[i].format);
+ else
+ seq_puts(s, ")");
+ }
}
}
@@ -150,7 +159,7 @@ struct pinconf_generic_dt_params {
u32 default_value;
};
-static struct pinconf_generic_dt_params dt_params[] = {
+static const struct pinconf_generic_dt_params dt_params[] = {
{ "bias-disable", PIN_CONFIG_BIAS_DISABLE, 0 },
{ "bias-high-impedance", PIN_CONFIG_BIAS_HIGH_IMPEDANCE, 0 },
{ "bias-bus-hold", PIN_CONFIG_BIAS_BUS_HOLD, 0 },
@@ -200,7 +209,7 @@ int pinconf_generic_parse_dt_config(struct device_node *np,
return -ENOMEM;
for (i = 0; i < ARRAY_SIZE(dt_params); i++) {
- struct pinconf_generic_dt_params *par = &dt_params[i];
+ const struct pinconf_generic_dt_params *par = &dt_params[i];
ret = of_property_read_u32(np, par->property, &val);
/* property not found */
diff --git a/drivers/pinctrl/pinctrl-at91.c b/drivers/pinctrl/pinctrl-at91.c
index 354a81d..66db984 100644
--- a/drivers/pinctrl/pinctrl-at91.c
+++ b/drivers/pinctrl/pinctrl-at91.c
@@ -25,9 +25,7 @@
/* Since we request GPIOs from ourself */
#include <linux/pinctrl/consumer.h>
-#include <mach/hardware.h>
-#include <mach/at91_pio.h>
-
+#include "pinctrl-at91.h"
#include "core.h"
#define MAX_GPIO_BANKS 5
@@ -1344,7 +1342,6 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
for (i = 0; i < chip->ngpio; i++) {
unsigned mask = pin_to_mask(i);
const char *gpio_label;
- u32 pdsr;
gpio_label = gpiochip_is_requested(chip, i);
if (!gpio_label)
@@ -1353,11 +1350,13 @@ static void at91_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
seq_printf(s, "[%s] GPIO%s%d: ",
gpio_label, chip->label, i);
if (mode == AT91_MUX_GPIO) {
- pdsr = readl_relaxed(pio + PIO_PDSR);
-
- seq_printf(s, "[gpio] %s\n",
- pdsr & mask ?
- "set" : "clear");
+ seq_printf(s, "[gpio] ");
+ seq_printf(s, "%s ",
+ readl_relaxed(pio + PIO_OSR) & mask ?
+ "output" : "input");
+ seq_printf(s, "%s\n",
+ readl_relaxed(pio + PIO_PDSR) & mask ?
+ "set" : "clear");
} else {
seq_printf(s, "[periph %c]\n",
mode + 'A' - 1);
diff --git a/drivers/pinctrl/pinctrl-at91.h b/drivers/pinctrl/pinctrl-at91.h
new file mode 100644
index 0000000..79b957f
--- /dev/null
+++ b/drivers/pinctrl/pinctrl-at91.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2005 Ivan Kokshaysky
+ * Copyright (C) SAN People
+ *
+ * Parallel I/O Controller (PIO) - System peripherals registers.
+ *
+ * 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 __PINCTRL_AT91_H
+#define __PINCTRL_AT91_H
+
+#define PIO_PER 0x00 /* Enable Register */
+#define PIO_PDR 0x04 /* Disable Register */
+#define PIO_PSR 0x08 /* Status Register */
+#define PIO_OER 0x10 /* Output Enable Register */
+#define PIO_ODR 0x14 /* Output Disable Register */
+#define PIO_OSR 0x18 /* Output Status Register */
+#define PIO_IFER 0x20 /* Glitch Input Filter Enable */
+#define PIO_IFDR 0x24 /* Glitch Input Filter Disable */
+#define PIO_IFSR 0x28 /* Glitch Input Filter Status */
+#define PIO_SODR 0x30 /* Set Output Data Register */
+#define PIO_CODR 0x34 /* Clear Output Data Register */
+#define PIO_ODSR 0x38 /* Output Data Status Register */
+#define PIO_PDSR 0x3c /* Pin Data Status Register */
+#define PIO_IER 0x40 /* Interrupt Enable Register */
+#define PIO_IDR 0x44 /* Interrupt Disable Register */
+#define PIO_IMR 0x48 /* Interrupt Mask Register */
+#define PIO_ISR 0x4c /* Interrupt Status Register */
+#define PIO_MDER 0x50 /* Multi-driver Enable Register */
+#define PIO_MDDR 0x54 /* Multi-driver Disable Register */
+#define PIO_MDSR 0x58 /* Multi-driver Status Register */
+#define PIO_PUDR 0x60 /* Pull-up Disable Register */
+#define PIO_PUER 0x64 /* Pull-up Enable Register */
+#define PIO_PUSR 0x68 /* Pull-up Status Register */
+#define PIO_ASR 0x70 /* Peripheral A Select Register */
+#define PIO_ABCDSR1 0x70 /* Peripheral ABCD Select Register 1 [some sam9 only] */
+#define PIO_BSR 0x74 /* Peripheral B Select Register */
+#define PIO_ABCDSR2 0x74 /* Peripheral ABCD Select Register 2 [some sam9 only] */
+#define PIO_ABSR 0x78 /* AB Status Register */
+#define PIO_IFSCDR 0x80 /* Input Filter Slow Clock Disable Register */
+#define PIO_IFSCER 0x84 /* Input Filter Slow Clock Enable Register */
+#define PIO_IFSCSR 0x88 /* Input Filter Slow Clock Status Register */
+#define PIO_SCDR 0x8c /* Slow Clock Divider Debouncing Register */
+#define PIO_SCDR_DIV (0x3fff << 0) /* Slow Clock Divider Mask */
+#define PIO_PPDDR 0x90 /* Pad Pull-down Disable Register */
+#define PIO_PPDER 0x94 /* Pad Pull-down Enable Register */
+#define PIO_PPDSR 0x98 /* Pad Pull-down Status Register */
+#define PIO_OWER 0xa0 /* Output Write Enable Register */
+#define PIO_OWDR 0xa4 /* Output Write Disable Register */
+#define PIO_OWSR 0xa8 /* Output Write Status Register */
+#define PIO_AIMER 0xb0 /* Additional Interrupt Modes Enable Register */
+#define PIO_AIMDR 0xb4 /* Additional Interrupt Modes Disable Register */
+#define PIO_AIMMR 0xb8 /* Additional Interrupt Modes Mask Register */
+#define PIO_ESR 0xc0 /* Edge Select Register */
+#define PIO_LSR 0xc4 /* Level Select Register */
+#define PIO_ELSR 0xc8 /* Edge/Level Status Register */
+#define PIO_FELLSR 0xd0 /* Falling Edge/Low Level Select Register */
+#define PIO_REHLSR 0xd4 /* Rising Edge/ High Level Select Register */
+#define PIO_FRLHSR 0xd8 /* Fall/Rise - Low/High Status Register */
+#define PIO_SCHMITT 0x100 /* Schmitt Trigger Register */
+
+#define SAMA5D3_PIO_DRIVER1 0x118 /*PIO Driver 1 register offset*/
+#define SAMA5D3_PIO_DRIVER2 0x11C /*PIO Driver 2 register offset*/
+
+#define AT91SAM9X5_PIO_DRIVER1 0x114 /*PIO Driver 1 register offset*/
+#define AT91SAM9X5_PIO_DRIVER2 0x118 /*PIO Driver 2 register offset*/
+
+#endif
diff --git a/drivers/pinctrl/pinctrl-bcm281xx.c b/drivers/pinctrl/pinctrl-bcm281xx.c
index a26e0c2..2b25047 100644
--- a/drivers/pinctrl/pinctrl-bcm281xx.c
+++ b/drivers/pinctrl/pinctrl-bcm281xx.c
@@ -1404,11 +1404,6 @@ static int __init bcm281xx_pinctrl_probe(struct platform_device *pdev)
/* So far We can assume there is only 1 bank of registers */
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "Missing MEM resource\n");
- return -ENODEV;
- }
-
pdata->reg_base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(pdata->reg_base)) {
dev_err(&pdev->dev, "Failed to ioremap MEM resource\n");
diff --git a/drivers/pinctrl/pinctrl-rockchip.c b/drivers/pinctrl/pinctrl-rockchip.c
index 016f457..40970c3 100644
--- a/drivers/pinctrl/pinctrl-rockchip.c
+++ b/drivers/pinctrl/pinctrl-rockchip.c
@@ -856,27 +856,22 @@ static int rockchip_pmx_set(struct pinctrl_dev *pctldev, unsigned selector,
* leads to this function call (via the pinctrl_gpio_direction_{input|output}()
* function called from the gpiolib interface).
*/
-static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
- struct pinctrl_gpio_range *range,
- unsigned offset, bool input)
+static int _rockchip_pmx_gpio_set_direction(struct gpio_chip *chip,
+ int pin, bool input)
{
- struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
struct rockchip_pin_bank *bank;
- struct gpio_chip *chip;
- int pin, ret;
+ int ret;
+ unsigned long flags;
u32 data;
- chip = range->gc;
bank = gc_to_pin_bank(chip);
- pin = offset - chip->base;
-
- dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
- offset, range->name, pin, input ? "input" : "output");
ret = rockchip_set_mux(bank, pin, RK_FUNC_GPIO);
if (ret < 0)
return ret;
+ spin_lock_irqsave(&bank->slock, flags);
+
data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
/* set bit to 1 for output, 0 for input */
if (!input)
@@ -885,9 +880,28 @@ static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
data &= ~BIT(pin);
writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+ spin_unlock_irqrestore(&bank->slock, flags);
+
return 0;
}
+static int rockchip_pmx_gpio_set_direction(struct pinctrl_dev *pctldev,
+ struct pinctrl_gpio_range *range,
+ unsigned offset, bool input)
+{
+ struct rockchip_pinctrl *info = pinctrl_dev_get_drvdata(pctldev);
+ struct gpio_chip *chip;
+ int pin;
+
+ chip = range->gc;
+ pin = offset - chip->base;
+ dev_dbg(info->dev, "gpio_direction for pin %u as %s-%d to %s\n",
+ offset, range->name, pin, input ? "input" : "output");
+
+ return _rockchip_pmx_gpio_set_direction(chip, offset - chip->base,
+ input);
+}
+
static const struct pinmux_ops rockchip_pmx_ops = {
.get_functions_count = rockchip_pmx_get_funcs_count,
.get_function_name = rockchip_pmx_get_func_name,
@@ -917,8 +931,7 @@ static bool rockchip_pinconf_pull_valid(struct rockchip_pin_ctrl *ctrl,
return false;
}
-static int rockchip_gpio_direction_output(struct gpio_chip *gc,
- unsigned offset, int value);
+static void rockchip_gpio_set(struct gpio_chip *gc, unsigned offset, int value);
static int rockchip_gpio_get(struct gpio_chip *gc, unsigned offset);
/* set the pin config settings for a specified pin */
@@ -959,9 +972,10 @@ static int rockchip_pinconf_set(struct pinctrl_dev *pctldev, unsigned int pin,
return rc;
break;
case PIN_CONFIG_OUTPUT:
- rc = rockchip_gpio_direction_output(&bank->gpio_chip,
- pin - bank->pin_base,
- arg);
+ rockchip_gpio_set(&bank->gpio_chip,
+ pin - bank->pin_base, arg);
+ rc = _rockchip_pmx_gpio_set_direction(&bank->gpio_chip,
+ pin - bank->pin_base, false);
if (rc)
return rc;
break;
@@ -1253,6 +1267,10 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
}
}
+ ret = rockchip_pinctrl_parse_dt(pdev, info);
+ if (ret)
+ return ret;
+
info->pctl_dev = pinctrl_register(ctrldesc, &pdev->dev, info);
if (!info->pctl_dev) {
dev_err(&pdev->dev, "could not register pinctrl driver\n");
@@ -1270,12 +1288,6 @@ static int rockchip_pinctrl_register(struct platform_device *pdev,
pinctrl_add_gpio_range(info->pctl_dev, &pin_bank->grange);
}
- ret = rockchip_pinctrl_parse_dt(pdev, info);
- if (ret) {
- pinctrl_unregister(info->pctl_dev);
- return ret;
- }
-
return 0;
}
@@ -1387,6 +1399,7 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
u32 polarity = 0, data = 0;
u32 pend;
bool edge_changed = false;
+ unsigned long flags;
dev_dbg(bank->drvdata->dev, "got irq for bank %s\n", bank->name);
@@ -1432,10 +1445,14 @@ static void rockchip_irq_demux(unsigned int irq, struct irq_desc *desc)
if (bank->toggle_edge_mode && edge_changed) {
/* Interrupt params should only be set with ints disabled */
+ spin_lock_irqsave(&bank->slock, flags);
+
data = readl_relaxed(bank->reg_base + GPIO_INTEN);
writel_relaxed(0, bank->reg_base + GPIO_INTEN);
writel(polarity, bank->reg_base + GPIO_INT_POLARITY);
writel(data, bank->reg_base + GPIO_INTEN);
+
+ spin_unlock_irqrestore(&bank->slock, flags);
}
chained_irq_exit(chip, desc);
@@ -1449,6 +1466,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
u32 polarity;
u32 level;
u32 data;
+ unsigned long flags;
int ret;
/* make sure the pin is configured as gpio input */
@@ -1456,15 +1474,20 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
if (ret < 0)
return ret;
+ spin_lock_irqsave(&bank->slock, flags);
+
data = readl_relaxed(bank->reg_base + GPIO_SWPORT_DDR);
data &= ~mask;
writel_relaxed(data, bank->reg_base + GPIO_SWPORT_DDR);
+ spin_unlock_irqrestore(&bank->slock, flags);
+
if (type & IRQ_TYPE_EDGE_BOTH)
__irq_set_handler_locked(d->irq, handle_edge_irq);
else
__irq_set_handler_locked(d->irq, handle_level_irq);
+ spin_lock_irqsave(&bank->slock, flags);
irq_gc_lock(gc);
level = readl_relaxed(gc->reg_base + GPIO_INTTYPE_LEVEL);
@@ -1507,6 +1530,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
break;
default:
irq_gc_unlock(gc);
+ spin_unlock_irqrestore(&bank->slock, flags);
return -EINVAL;
}
@@ -1514,6 +1538,7 @@ static int rockchip_irq_set_type(struct irq_data *d, unsigned int type)
writel_relaxed(polarity, gc->reg_base + GPIO_INT_POLARITY);
irq_gc_unlock(gc);
+ spin_unlock_irqrestore(&bank->slock, flags);
return 0;
}
@@ -1563,6 +1588,7 @@ static int rockchip_interrupts_register(struct platform_device *pdev,
gc->chip_types[0].chip.irq_unmask = irq_gc_mask_set_bit;
gc->chip_types[0].chip.irq_set_wake = irq_gc_set_wake;
gc->chip_types[0].chip.irq_set_type = rockchip_irq_set_type;
+ gc->wake_enabled = IRQ_MSK(bank->nr_pins);
irq_set_handler_data(bank->irq, bank);
irq_set_chained_handler(bank->irq, rockchip_irq_demux);
@@ -1770,6 +1796,51 @@ static struct rockchip_pin_ctrl *rockchip_pinctrl_get_soc_data(
return ctrl;
}
+#define RK3288_GRF_GPIO6C_IOMUX 0x64
+#define GPIO6C6_SEL_WRITE_ENABLE BIT(28)
+
+static u32 rk3288_grf_gpio6c_iomux;
+
+static int __maybe_unused rockchip_pinctrl_suspend(struct device *dev)
+{
+ struct rockchip_pinctrl *info = dev_get_drvdata(dev);
+ int ret = pinctrl_force_sleep(info->pctl_dev);
+
+ if (ret)
+ return ret;
+
+ /*
+ * RK3288 GPIO6_C6 mux would be modified by Maskrom when resume, so save
+ * the setting here, and restore it at resume.
+ */
+ if (info->ctrl->type == RK3288) {
+ ret = regmap_read(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
+ &rk3288_grf_gpio6c_iomux);
+ if (ret) {
+ pinctrl_force_default(info->pctl_dev);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static int __maybe_unused rockchip_pinctrl_resume(struct device *dev)
+{
+ struct rockchip_pinctrl *info = dev_get_drvdata(dev);
+ int ret = regmap_write(info->regmap_base, RK3288_GRF_GPIO6C_IOMUX,
+ rk3288_grf_gpio6c_iomux |
+ GPIO6C6_SEL_WRITE_ENABLE);
+
+ if (ret)
+ return ret;
+
+ return pinctrl_force_default(info->pctl_dev);
+}
+
+static SIMPLE_DEV_PM_OPS(rockchip_pinctrl_dev_pm_ops, rockchip_pinctrl_suspend,
+ rockchip_pinctrl_resume);
+
static int rockchip_pinctrl_probe(struct platform_device *pdev)
{
struct rockchip_pinctrl *info;
@@ -1983,6 +2054,7 @@ static struct platform_driver rockchip_pinctrl_driver = {
.driver = {
.name = "rockchip-pinctrl",
.owner = THIS_MODULE,
+ .pm = &rockchip_pinctrl_dev_pm_ops,
.of_match_table = rockchip_pinctrl_dt_match,
},
};
diff --git a/drivers/pinctrl/pinctrl-st.c b/drivers/pinctrl/pinctrl-st.c
index 4b1792a..caeeb1c 100644
--- a/drivers/pinctrl/pinctrl-st.c
+++ b/drivers/pinctrl/pinctrl-st.c
@@ -1512,7 +1512,7 @@ static int st_gpiolib_register_bank(struct st_pinctrl *info,
gpio_irq, st_gpio_irq_handler);
}
- if (info->irqmux_base > 0 || gpio_irq > 0) {
+ if (info->irqmux_base || gpio_irq > 0) {
err = gpiochip_irqchip_add(&bank->gpio_chip, &st_gpio_irqchip,
0, handle_simple_irq,
IRQ_TYPE_LEVEL_LOW);
diff --git a/drivers/pinctrl/pinctrl-tb10x.c b/drivers/pinctrl/pinctrl-tb10x.c
index 3b9bfcf..9363563 100644
--- a/drivers/pinctrl/pinctrl-tb10x.c
+++ b/drivers/pinctrl/pinctrl-tb10x.c
@@ -759,7 +759,7 @@ static struct pinctrl_desc tb10x_pindesc = {
static int tb10x_pinctrl_probe(struct platform_device *pdev)
{
int ret = -EINVAL;
- struct resource *mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ struct resource *mem;
struct device *dev = &pdev->dev;
struct device_node *of_node = dev->of_node;
struct device_node *child;
@@ -771,11 +771,6 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev)
return -EINVAL;
}
- if (!mem) {
- dev_err(dev, "No memory resource defined.\n");
- return -EINVAL;
- }
-
state = devm_kzalloc(dev, sizeof(struct tb10x_pinctrl) +
of_get_child_count(of_node)
* sizeof(struct tb10x_of_pinfunc),
@@ -787,6 +782,7 @@ static int tb10x_pinctrl_probe(struct platform_device *pdev)
state->pinfuncs = (struct tb10x_of_pinfunc *)(state + 1);
mutex_init(&state->mutex);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
state->base = devm_ioremap_resource(dev, mem);
if (IS_ERR(state->base)) {
ret = PTR_ERR(state->base);
diff --git a/drivers/pinctrl/pinctrl-tegra-xusb.c b/drivers/pinctrl/pinctrl-tegra-xusb.c
index 1631ec9..080ec77 100644
--- a/drivers/pinctrl/pinctrl-tegra-xusb.c
+++ b/drivers/pinctrl/pinctrl-tegra-xusb.c
@@ -20,6 +20,7 @@
#include <linux/pinctrl/pinmux.h>
#include <linux/platform_device.h>
#include <linux/reset.h>
+#include <linux/slab.h>
#include <dt-bindings/pinctrl/pinctrl-tegra-xusb.h>
@@ -171,7 +172,7 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
if (err == -EINVAL)
continue;
- return err;
+ goto out;
}
config = TEGRA_XUSB_PADCTL_PACK(properties[i].param, value);
@@ -179,7 +180,7 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
err = pinctrl_utils_add_config(padctl->pinctrl, &configs,
&num_configs, config);
if (err < 0)
- return err;
+ goto out;
}
if (function)
@@ -190,14 +191,14 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
err = of_property_count_strings(np, "nvidia,lanes");
if (err < 0)
- return err;
+ goto out;
reserve *= err;
err = pinctrl_utils_reserve_map(padctl->pinctrl, maps, reserved_maps,
num_maps, reserve);
if (err < 0)
- return err;
+ goto out;
of_property_for_each_string(np, "nvidia,lanes", prop, group) {
if (function) {
@@ -205,7 +206,7 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
reserved_maps, num_maps, group,
function);
if (err < 0)
- return err;
+ goto out;
}
if (num_configs) {
@@ -214,11 +215,15 @@ static int tegra_xusb_padctl_parse_subnode(struct tegra_xusb_padctl *padctl,
configs, num_configs,
PIN_MAP_TYPE_CONFIGS_GROUP);
if (err < 0)
- return err;
+ goto out;
}
}
- return 0;
+ err = 0;
+
+out:
+ kfree(configs);
+ return err;
}
static int tegra_xusb_padctl_dt_node_to_map(struct pinctrl_dev *pinctrl,
diff --git a/drivers/pinctrl/qcom/Kconfig b/drivers/pinctrl/qcom/Kconfig
index 81275af..3cd243c 100644
--- a/drivers/pinctrl/qcom/Kconfig
+++ b/drivers/pinctrl/qcom/Kconfig
@@ -47,4 +47,17 @@ config PINCTRL_MSM8X74
This is the pinctrl, pinmux, pinconf and gpiolib driver for the
Qualcomm TLMM block found in the Qualcomm 8974 platform.
+config PINCTRL_QCOM_SPMI_PMIC
+ tristate "Qualcomm SPMI PMIC pin controller driver"
+ depends on GPIOLIB && OF && SPMI
+ select REGMAP_SPMI
+ select PINMUX
+ select PINCONF
+ select GENERIC_PINCONF
+ help
+ This is the pinctrl, pinmux, pinconf and gpiolib driver for the
+ Qualcomm GPIO and MPP blocks found in the Qualcomm PMIC's chips,
+ which are using SPMI for communication with SoC. Example PMIC's
+ devices are pm8841, pm8941 and pma8084.
+
endif
diff --git a/drivers/pinctrl/qcom/Makefile b/drivers/pinctrl/qcom/Makefile
index ba8519f..bfd79af 100644
--- a/drivers/pinctrl/qcom/Makefile
+++ b/drivers/pinctrl/qcom/Makefile
@@ -5,3 +5,5 @@ obj-$(CONFIG_PINCTRL_APQ8084) += pinctrl-apq8084.o
obj-$(CONFIG_PINCTRL_IPQ8064) += pinctrl-ipq8064.o
obj-$(CONFIG_PINCTRL_MSM8960) += pinctrl-msm8960.o
obj-$(CONFIG_PINCTRL_MSM8X74) += pinctrl-msm8x74.o
+obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-gpio.o
+obj-$(CONFIG_PINCTRL_QCOM_SPMI_PMIC) += pinctrl-spmi-mpp.o
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
new file mode 100644
index 0000000..b863b50
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-gpio.c
@@ -0,0 +1,933 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <dt-bindings/pinctrl/qcom,pmic-gpio.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define PMIC_GPIO_ADDRESS_RANGE 0x100
+
+/* type and subtype registers base address offsets */
+#define PMIC_GPIO_REG_TYPE 0x4
+#define PMIC_GPIO_REG_SUBTYPE 0x5
+
+/* GPIO peripheral type and subtype out_values */
+#define PMIC_GPIO_TYPE 0x10
+#define PMIC_GPIO_SUBTYPE_GPIO_4CH 0x1
+#define PMIC_GPIO_SUBTYPE_GPIOC_4CH 0x5
+#define PMIC_GPIO_SUBTYPE_GPIO_8CH 0x9
+#define PMIC_GPIO_SUBTYPE_GPIOC_8CH 0xd
+
+#define PMIC_MPP_REG_RT_STS 0x10
+#define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1
+
+/* control register base address offsets */
+#define PMIC_GPIO_REG_MODE_CTL 0x40
+#define PMIC_GPIO_REG_DIG_VIN_CTL 0x41
+#define PMIC_GPIO_REG_DIG_PULL_CTL 0x42
+#define PMIC_GPIO_REG_DIG_OUT_CTL 0x45
+#define PMIC_GPIO_REG_EN_CTL 0x46
+
+/* PMIC_GPIO_REG_MODE_CTL */
+#define PMIC_GPIO_REG_MODE_VALUE_SHIFT 0x1
+#define PMIC_GPIO_REG_MODE_FUNCTION_SHIFT 1
+#define PMIC_GPIO_REG_MODE_FUNCTION_MASK 0x7
+#define PMIC_GPIO_REG_MODE_DIR_SHIFT 4
+#define PMIC_GPIO_REG_MODE_DIR_MASK 0x7
+
+/* PMIC_GPIO_REG_DIG_VIN_CTL */
+#define PMIC_GPIO_REG_VIN_SHIFT 0
+#define PMIC_GPIO_REG_VIN_MASK 0x7
+
+/* PMIC_GPIO_REG_DIG_PULL_CTL */
+#define PMIC_GPIO_REG_PULL_SHIFT 0
+#define PMIC_GPIO_REG_PULL_MASK 0x7
+
+#define PMIC_GPIO_PULL_DOWN 4
+#define PMIC_GPIO_PULL_DISABLE 5
+
+/* PMIC_GPIO_REG_DIG_OUT_CTL */
+#define PMIC_GPIO_REG_OUT_STRENGTH_SHIFT 0
+#define PMIC_GPIO_REG_OUT_STRENGTH_MASK 0x3
+#define PMIC_GPIO_REG_OUT_TYPE_SHIFT 4
+#define PMIC_GPIO_REG_OUT_TYPE_MASK 0x3
+
+/*
+ * Output type - indicates pin should be configured as push-pull,
+ * open drain or open source.
+ */
+#define PMIC_GPIO_OUT_BUF_CMOS 0
+#define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS 1
+#define PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS 2
+
+/* PMIC_GPIO_REG_EN_CTL */
+#define PMIC_GPIO_REG_MASTER_EN_SHIFT 7
+
+#define PMIC_GPIO_PHYSICAL_OFFSET 1
+
+/* Qualcomm specific pin configurations */
+#define PMIC_GPIO_CONF_PULL_UP (PIN_CONFIG_END + 1)
+#define PMIC_GPIO_CONF_STRENGTH (PIN_CONFIG_END + 2)
+
+/**
+ * struct pmic_gpio_pad - keep current GPIO settings
+ * @base: Address base in SPMI device.
+ * @irq: IRQ number which this GPIO generate.
+ * @is_enabled: Set to false when GPIO should be put in high Z state.
+ * @out_value: Cached pin output value
+ * @have_buffer: Set to true if GPIO output could be configured in push-pull,
+ * open-drain or open-source mode.
+ * @output_enabled: Set to true if GPIO output logic is enabled.
+ * @input_enabled: Set to true if GPIO input buffer logic is enabled.
+ * @num_sources: Number of power-sources supported by this GPIO.
+ * @power_source: Current power-source used.
+ * @buffer_type: Push-pull, open-drain or open-source.
+ * @pullup: Constant current which flow trough GPIO output buffer.
+ * @strength: No, Low, Medium, High
+ * @function: See pmic_gpio_functions[]
+ */
+struct pmic_gpio_pad {
+ u16 base;
+ int irq;
+ bool is_enabled;
+ bool out_value;
+ bool have_buffer;
+ bool output_enabled;
+ bool input_enabled;
+ unsigned int num_sources;
+ unsigned int power_source;
+ unsigned int buffer_type;
+ unsigned int pullup;
+ unsigned int strength;
+ unsigned int function;
+};
+
+struct pmic_gpio_state {
+ struct device *dev;
+ struct regmap *map;
+ struct pinctrl_dev *ctrl;
+ struct gpio_chip chip;
+};
+
+struct pmic_gpio_bindings {
+ const char *property;
+ unsigned param;
+};
+
+static struct pmic_gpio_bindings pmic_gpio_bindings[] = {
+ {"qcom,pull-up-strength", PMIC_GPIO_CONF_PULL_UP},
+ {"qcom,drive-strength", PMIC_GPIO_CONF_STRENGTH},
+};
+
+static const char *const pmic_gpio_groups[] = {
+ "gpio1", "gpio2", "gpio3", "gpio4", "gpio5", "gpio6", "gpio7", "gpio8",
+ "gpio9", "gpio10", "gpio11", "gpio12", "gpio13", "gpio14", "gpio15",
+ "gpio16", "gpio17", "gpio18", "gpio19", "gpio20", "gpio21", "gpio22",
+ "gpio23", "gpio24", "gpio25", "gpio26", "gpio27", "gpio28", "gpio29",
+ "gpio30", "gpio31", "gpio32", "gpio33", "gpio34", "gpio35", "gpio36",
+};
+
+static const char *const pmic_gpio_functions[] = {
+ PMIC_GPIO_FUNC_NORMAL, PMIC_GPIO_FUNC_PAIRED,
+ PMIC_GPIO_FUNC_FUNC1, PMIC_GPIO_FUNC_FUNC2,
+ PMIC_GPIO_FUNC_DTEST1, PMIC_GPIO_FUNC_DTEST2,
+ PMIC_GPIO_FUNC_DTEST3, PMIC_GPIO_FUNC_DTEST4,
+};
+
+static inline struct pmic_gpio_state *to_gpio_state(struct gpio_chip *chip)
+{
+ return container_of(chip, struct pmic_gpio_state, chip);
+};
+
+static int pmic_gpio_read(struct pmic_gpio_state *state,
+ struct pmic_gpio_pad *pad, unsigned int addr)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(state->map, pad->base + addr, &val);
+ if (ret < 0)
+ dev_err(state->dev, "read 0x%x failed\n", addr);
+ else
+ ret = val;
+
+ return ret;
+}
+
+static int pmic_gpio_write(struct pmic_gpio_state *state,
+ struct pmic_gpio_pad *pad, unsigned int addr,
+ unsigned int val)
+{
+ int ret;
+
+ ret = regmap_write(state->map, pad->base + addr, val);
+ if (ret < 0)
+ dev_err(state->dev, "write 0x%x failed\n", addr);
+
+ return ret;
+}
+
+static int pmic_gpio_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ /* Every PIN is a group */
+ return pctldev->desc->npins;
+}
+
+static const char *pmic_gpio_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned pin)
+{
+ return pctldev->desc->pins[pin].name;
+}
+
+static int pmic_gpio_get_group_pins(struct pinctrl_dev *pctldev, unsigned pin,
+ const unsigned **pins, unsigned *num_pins)
+{
+ *pins = &pctldev->desc->pins[pin].number;
+ *num_pins = 1;
+ return 0;
+}
+
+static int pmic_gpio_parse_dt_config(struct device_node *np,
+ struct pinctrl_dev *pctldev,
+ unsigned long **configs,
+ unsigned int *nconfs)
+{
+ struct pmic_gpio_bindings *par;
+ unsigned long cfg;
+ int ret, i;
+ u32 val;
+
+ for (i = 0; i < ARRAY_SIZE(pmic_gpio_bindings); i++) {
+ par = &pmic_gpio_bindings[i];
+ ret = of_property_read_u32(np, par->property, &val);
+
+ /* property not found */
+ if (ret == -EINVAL)
+ continue;
+
+ /* use zero as default value */
+ if (ret)
+ val = 0;
+
+ dev_dbg(pctldev->dev, "found %s with value %u\n",
+ par->property, val);
+
+ cfg = pinconf_to_config_packed(par->param, val);
+
+ ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pmic_gpio_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserv, unsigned *nmaps,
+ enum pinctrl_map_type type)
+{
+ unsigned long *configs = NULL;
+ unsigned nconfs = 0;
+ struct property *prop;
+ const char *group;
+ int ret;
+
+ ret = pmic_gpio_parse_dt_config(np, pctldev, &configs, &nconfs);
+ if (ret < 0)
+ return ret;
+
+ if (!nconfs)
+ return 0;
+
+ ret = of_property_count_strings(np, "pins");
+ if (ret < 0)
+ goto exit;
+
+ ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret);
+ if (ret < 0)
+ goto exit;
+
+ of_property_for_each_string(np, "pins", prop, group) {
+ ret = pinctrl_utils_add_map_configs(pctldev, map,
+ reserv, nmaps, group,
+ configs, nconfs, type);
+ if (ret < 0)
+ break;
+ }
+exit:
+ kfree(configs);
+ return ret;
+}
+
+static int pmic_gpio_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *nmaps)
+{
+ enum pinctrl_map_type type;
+ struct device_node *np;
+ unsigned reserv;
+ int ret;
+
+ ret = 0;
+ *map = NULL;
+ *nmaps = 0;
+ reserv = 0;
+ type = PIN_MAP_TYPE_CONFIGS_GROUP;
+
+ for_each_child_of_node(np_config, np) {
+ ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
+ &reserv, nmaps, type);
+ if (ret)
+ break;
+
+ ret = pmic_gpio_dt_subnode_to_map(pctldev, np, map, &reserv,
+ nmaps, type);
+ if (ret)
+ break;
+ }
+
+ if (ret < 0)
+ pinctrl_utils_dt_free_map(pctldev, *map, *nmaps);
+
+ return ret;
+}
+
+static const struct pinctrl_ops pmic_gpio_pinctrl_ops = {
+ .get_groups_count = pmic_gpio_get_groups_count,
+ .get_group_name = pmic_gpio_get_group_name,
+ .get_group_pins = pmic_gpio_get_group_pins,
+ .dt_node_to_map = pmic_gpio_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int pmic_gpio_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(pmic_gpio_functions);
+}
+
+static const char *pmic_gpio_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ return pmic_gpio_functions[function];
+}
+
+static int pmic_gpio_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char *const **groups,
+ unsigned *const num_qgroups)
+{
+ *groups = pmic_gpio_groups;
+ *num_qgroups = pctldev->desc->npins;
+ return 0;
+}
+
+static int pmic_gpio_set_mux(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned pin)
+{
+ struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
+ struct pmic_gpio_pad *pad;
+ unsigned int val;
+ int ret;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ pad->function = function;
+
+ val = 0;
+ if (pad->output_enabled) {
+ if (pad->input_enabled)
+ val = 2;
+ else
+ val = 1;
+ }
+
+ val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
+ val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
+
+ ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = pad->is_enabled << PMIC_GPIO_REG_MASTER_EN_SHIFT;
+
+ return pmic_gpio_write(state, pad, PMIC_GPIO_REG_EN_CTL, val);
+}
+
+static const struct pinmux_ops pmic_gpio_pinmux_ops = {
+ .get_functions_count = pmic_gpio_get_functions_count,
+ .get_function_name = pmic_gpio_get_function_name,
+ .get_function_groups = pmic_gpio_get_function_groups,
+ .set_mux = pmic_gpio_set_mux,
+};
+
+static int pmic_gpio_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ unsigned param = pinconf_to_config_param(*config);
+ struct pmic_gpio_pad *pad;
+ unsigned arg;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_CMOS;
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_SOURCE:
+ arg = pad->buffer_type == PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ arg = pad->pullup == PMIC_GPIO_PULL_DOWN;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ arg = pad->pullup = PMIC_GPIO_PULL_DISABLE;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ arg = pad->pullup == PMIC_GPIO_PULL_UP_30;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ arg = !pad->is_enabled;
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ arg = pad->power_source;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ arg = pad->input_enabled;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ arg = pad->out_value;
+ break;
+ case PMIC_GPIO_CONF_PULL_UP:
+ arg = pad->pullup;
+ break;
+ case PMIC_GPIO_CONF_STRENGTH:
+ arg = pad->strength;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static int pmic_gpio_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned nconfs)
+{
+ struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
+ struct pmic_gpio_pad *pad;
+ unsigned param, arg;
+ unsigned int val;
+ int i, ret;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ for (i = 0; i < nconfs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_DRIVE_PUSH_PULL:
+ pad->buffer_type = PMIC_GPIO_OUT_BUF_CMOS;
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_DRAIN:
+ if (!pad->have_buffer)
+ return -EINVAL;
+ pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_NMOS;
+ break;
+ case PIN_CONFIG_DRIVE_OPEN_SOURCE:
+ if (!pad->have_buffer)
+ return -EINVAL;
+ pad->buffer_type = PMIC_GPIO_OUT_BUF_OPEN_DRAIN_PMOS;
+ break;
+ case PIN_CONFIG_BIAS_DISABLE:
+ pad->pullup = PMIC_GPIO_PULL_DISABLE;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ pad->pullup = PMIC_GPIO_PULL_UP_30;
+ break;
+ case PIN_CONFIG_BIAS_PULL_DOWN:
+ if (arg)
+ pad->pullup = PMIC_GPIO_PULL_DOWN;
+ else
+ pad->pullup = PMIC_GPIO_PULL_DISABLE;
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ pad->is_enabled = false;
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ if (arg > pad->num_sources)
+ return -EINVAL;
+ pad->power_source = arg;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ pad->input_enabled = arg ? true : false;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ pad->output_enabled = true;
+ pad->out_value = arg;
+ break;
+ case PMIC_GPIO_CONF_PULL_UP:
+ if (arg > PMIC_GPIO_PULL_UP_1P5_30)
+ return -EINVAL;
+ pad->pullup = arg;
+ break;
+ case PMIC_GPIO_CONF_STRENGTH:
+ if (arg > PMIC_GPIO_STRENGTH_LOW)
+ return -EINVAL;
+ pad->strength = arg;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ val = pad->power_source << PMIC_GPIO_REG_VIN_SHIFT;
+
+ ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = pad->pullup << PMIC_GPIO_REG_PULL_SHIFT;
+
+ ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = pad->buffer_type << PMIC_GPIO_REG_OUT_TYPE_SHIFT;
+ val = pad->strength << PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
+
+ ret = pmic_gpio_write(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = 0;
+ if (pad->output_enabled) {
+ if (pad->input_enabled)
+ val = 2;
+ else
+ val = 1;
+ }
+
+ val = val << PMIC_GPIO_REG_MODE_DIR_SHIFT;
+ val |= pad->function << PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
+ val |= pad->out_value & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
+
+ return pmic_gpio_write(state, pad, PMIC_GPIO_REG_MODE_CTL, val);
+}
+
+static void pmic_gpio_config_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin)
+{
+ struct pmic_gpio_state *state = pinctrl_dev_get_drvdata(pctldev);
+ struct pmic_gpio_pad *pad;
+ int ret, val;
+
+ static const char *const biases[] = {
+ "pull-up 30uA", "pull-up 1.5uA", "pull-up 31.5uA",
+ "pull-up 1.5uA + 30uA boost", "pull-down 10uA", "no pull"
+ };
+ static const char *const buffer_types[] = {
+ "push-pull", "open-drain", "open-source"
+ };
+ static const char *const strengths[] = {
+ "no", "high", "medium", "low"
+ };
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ seq_printf(s, " gpio%-2d:", pin + PMIC_GPIO_PHYSICAL_OFFSET);
+
+ val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_EN_CTL);
+
+ if (val < 0 || !(val >> PMIC_GPIO_REG_MASTER_EN_SHIFT)) {
+ seq_puts(s, " ---");
+ } else {
+
+ if (!pad->input_enabled) {
+ ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
+ if (!ret) {
+ ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
+ pad->out_value = ret;
+ }
+ }
+
+ seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
+ seq_printf(s, " %-7s", pmic_gpio_functions[pad->function]);
+ seq_printf(s, " vin-%d", pad->power_source);
+ seq_printf(s, " %-27s", biases[pad->pullup]);
+ seq_printf(s, " %-10s", buffer_types[pad->buffer_type]);
+ seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
+ seq_printf(s, " %-7s", strengths[pad->strength]);
+ }
+}
+
+static const struct pinconf_ops pmic_gpio_pinconf_ops = {
+ .pin_config_group_get = pmic_gpio_config_get,
+ .pin_config_group_set = pmic_gpio_config_set,
+ .pin_config_group_dbg_show = pmic_gpio_config_dbg_show,
+};
+
+static int pmic_gpio_direction_input(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_gpio_state *state = to_gpio_state(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+ return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int pmic_gpio_direction_output(struct gpio_chip *chip,
+ unsigned pin, int val)
+{
+ struct pmic_gpio_state *state = to_gpio_state(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+ return pmic_gpio_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int pmic_gpio_get(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_pad *pad;
+ int ret;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ if (!pad->is_enabled)
+ return -EINVAL;
+
+ if (pad->input_enabled) {
+ ret = pmic_gpio_read(state, pad, PMIC_MPP_REG_RT_STS);
+ if (ret < 0)
+ return ret;
+
+ pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
+ }
+
+ return pad->out_value;
+}
+
+static void pmic_gpio_set(struct gpio_chip *chip, unsigned pin, int value)
+{
+ struct pmic_gpio_state *state = to_gpio_state(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+ pmic_gpio_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int pmic_gpio_request(struct gpio_chip *chip, unsigned base)
+{
+ return pinctrl_request_gpio(chip->base + base);
+}
+
+static void pmic_gpio_free(struct gpio_chip *chip, unsigned base)
+{
+ pinctrl_free_gpio(chip->base + base);
+}
+
+static int pmic_gpio_of_xlate(struct gpio_chip *chip,
+ const struct of_phandle_args *gpio_desc,
+ u32 *flags)
+{
+ if (chip->of_gpio_n_cells < 2)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpio_desc->args[1];
+
+ return gpio_desc->args[0] - PMIC_GPIO_PHYSICAL_OFFSET;
+}
+
+static int pmic_gpio_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_gpio_state *state = to_gpio_state(chip);
+ struct pmic_gpio_pad *pad;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ return pad->irq;
+}
+
+static void pmic_gpio_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct pmic_gpio_state *state = to_gpio_state(chip);
+ unsigned i;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ pmic_gpio_config_dbg_show(state->ctrl, s, i);
+ seq_puts(s, "\n");
+ }
+}
+
+static const struct gpio_chip pmic_gpio_gpio_template = {
+ .direction_input = pmic_gpio_direction_input,
+ .direction_output = pmic_gpio_direction_output,
+ .get = pmic_gpio_get,
+ .set = pmic_gpio_set,
+ .request = pmic_gpio_request,
+ .free = pmic_gpio_free,
+ .of_xlate = pmic_gpio_of_xlate,
+ .to_irq = pmic_gpio_to_irq,
+ .dbg_show = pmic_gpio_dbg_show,
+};
+
+static int pmic_gpio_populate(struct pmic_gpio_state *state,
+ struct pmic_gpio_pad *pad)
+{
+ int type, subtype, val, dir;
+
+ type = pmic_gpio_read(state, pad, PMIC_GPIO_REG_TYPE);
+ if (type < 0)
+ return type;
+
+ if (type != PMIC_GPIO_TYPE) {
+ dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
+ type, pad->base);
+ return -ENODEV;
+ }
+
+ subtype = pmic_gpio_read(state, pad, PMIC_GPIO_REG_SUBTYPE);
+ if (subtype < 0)
+ return subtype;
+
+ switch (subtype) {
+ case PMIC_GPIO_SUBTYPE_GPIO_4CH:
+ pad->have_buffer = true;
+ case PMIC_GPIO_SUBTYPE_GPIOC_4CH:
+ pad->num_sources = 4;
+ break;
+ case PMIC_GPIO_SUBTYPE_GPIO_8CH:
+ pad->have_buffer = true;
+ case PMIC_GPIO_SUBTYPE_GPIOC_8CH:
+ pad->num_sources = 8;
+ break;
+ default:
+ dev_err(state->dev, "unknown GPIO type 0x%x\n", subtype);
+ return -ENODEV;
+ }
+
+ val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_MODE_CTL);
+ if (val < 0)
+ return val;
+
+ pad->out_value = val & PMIC_GPIO_REG_MODE_VALUE_SHIFT;
+
+ dir = val >> PMIC_GPIO_REG_MODE_DIR_SHIFT;
+ dir &= PMIC_GPIO_REG_MODE_DIR_MASK;
+ switch (dir) {
+ case 0:
+ pad->input_enabled = true;
+ pad->output_enabled = false;
+ break;
+ case 1:
+ pad->input_enabled = false;
+ pad->output_enabled = true;
+ break;
+ case 2:
+ pad->input_enabled = true;
+ pad->output_enabled = true;
+ break;
+ default:
+ dev_err(state->dev, "unknown GPIO direction\n");
+ return -ENODEV;
+ }
+
+ pad->function = val >> PMIC_GPIO_REG_MODE_FUNCTION_SHIFT;
+ pad->function &= PMIC_GPIO_REG_MODE_FUNCTION_MASK;
+
+ val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_VIN_CTL);
+ if (val < 0)
+ return val;
+
+ pad->power_source = val >> PMIC_GPIO_REG_VIN_SHIFT;
+ pad->power_source &= PMIC_GPIO_REG_VIN_MASK;
+
+ val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_PULL_CTL);
+ if (val < 0)
+ return val;
+
+ pad->pullup = val >> PMIC_GPIO_REG_PULL_SHIFT;
+ pad->pullup &= PMIC_GPIO_REG_PULL_MASK;
+
+ val = pmic_gpio_read(state, pad, PMIC_GPIO_REG_DIG_OUT_CTL);
+ if (val < 0)
+ return val;
+
+ pad->strength = val >> PMIC_GPIO_REG_OUT_STRENGTH_SHIFT;
+ pad->strength &= PMIC_GPIO_REG_OUT_STRENGTH_MASK;
+
+ pad->buffer_type = val >> PMIC_GPIO_REG_OUT_TYPE_SHIFT;
+ pad->buffer_type &= PMIC_GPIO_REG_OUT_TYPE_MASK;
+
+ /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
+ pad->is_enabled = true;
+ return 0;
+}
+
+static int pmic_gpio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pinctrl_pin_desc *pindesc;
+ struct pinctrl_desc *pctrldesc;
+ struct pmic_gpio_pad *pad, *pads;
+ struct pmic_gpio_state *state;
+ int ret, npins, i;
+ u32 res[2];
+
+ ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
+ if (ret < 0) {
+ dev_err(dev, "missing base address and/or range");
+ return ret;
+ }
+
+ npins = res[1] / PMIC_GPIO_ADDRESS_RANGE;
+
+ if (!npins)
+ return -EINVAL;
+
+ BUG_ON(npins > ARRAY_SIZE(pmic_gpio_groups));
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, state);
+
+ state->dev = &pdev->dev;
+ state->map = dev_get_regmap(dev->parent, NULL);
+
+ pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
+ if (!pindesc)
+ return -ENOMEM;
+
+ pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
+ if (!pads)
+ return -ENOMEM;
+
+ pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
+ if (!pctrldesc)
+ return -ENOMEM;
+
+ pctrldesc->pctlops = &pmic_gpio_pinctrl_ops;
+ pctrldesc->pmxops = &pmic_gpio_pinmux_ops;
+ pctrldesc->confops = &pmic_gpio_pinconf_ops;
+ pctrldesc->owner = THIS_MODULE;
+ pctrldesc->name = dev_name(dev);
+ pctrldesc->pins = pindesc;
+ pctrldesc->npins = npins;
+
+ for (i = 0; i < npins; i++, pindesc++) {
+ pad = &pads[i];
+ pindesc->drv_data = pad;
+ pindesc->number = i;
+ pindesc->name = pmic_gpio_groups[i];
+
+ pad->irq = platform_get_irq(pdev, i);
+ if (pad->irq < 0)
+ return pad->irq;
+
+ pad->base = res[0] + i * PMIC_GPIO_ADDRESS_RANGE;
+
+ ret = pmic_gpio_populate(state, pad);
+ if (ret < 0)
+ return ret;
+ }
+
+ state->chip = pmic_gpio_gpio_template;
+ state->chip.dev = dev;
+ state->chip.base = -1;
+ state->chip.ngpio = npins;
+ state->chip.label = dev_name(dev);
+ state->chip.of_gpio_n_cells = 2;
+ state->chip.can_sleep = false;
+
+ state->ctrl = pinctrl_register(pctrldesc, dev, state);
+ if (!state->ctrl)
+ return -ENODEV;
+
+ ret = gpiochip_add(&state->chip);
+ if (ret) {
+ dev_err(state->dev, "can't add gpio chip\n");
+ goto err_chip;
+ }
+
+ ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
+ if (ret) {
+ dev_err(dev, "failed to add pin range\n");
+ goto err_range;
+ }
+
+ return 0;
+
+err_range:
+ gpiochip_remove(&state->chip);
+err_chip:
+ pinctrl_unregister(state->ctrl);
+ return ret;
+}
+
+static int pmic_gpio_remove(struct platform_device *pdev)
+{
+ struct pmic_gpio_state *state = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&state->chip);
+ pinctrl_unregister(state->ctrl);
+ return 0;
+}
+
+static const struct of_device_id pmic_gpio_of_match[] = {
+ { .compatible = "qcom,pm8941-gpio" }, /* 36 GPIO's */
+ { .compatible = "qcom,pma8084-gpio" }, /* 22 GPIO's */
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, pmic_gpio_of_match);
+
+static struct platform_driver pmic_gpio_driver = {
+ .driver = {
+ .name = "qcom-spmi-gpio",
+ .of_match_table = pmic_gpio_of_match,
+ },
+ .probe = pmic_gpio_probe,
+ .remove = pmic_gpio_remove,
+};
+
+module_platform_driver(pmic_gpio_driver);
+
+MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
+MODULE_DESCRIPTION("Qualcomm SPMI PMIC GPIO pin control driver");
+MODULE_ALIAS("platform:qcom-spmi-gpio");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
new file mode 100644
index 0000000..a8924db
--- /dev/null
+++ b/drivers/pinctrl/qcom/pinctrl-spmi-mpp.c
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2012-2014, The Linux Foundation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/gpio.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/pinctrl/pinconf-generic.h>
+#include <linux/pinctrl/pinconf.h>
+#include <linux/pinctrl/pinmux.h>
+#include <linux/platform_device.h>
+#include <linux/regmap.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include <dt-bindings/pinctrl/qcom,pmic-mpp.h>
+
+#include "../core.h"
+#include "../pinctrl-utils.h"
+
+#define PMIC_MPP_ADDRESS_RANGE 0x100
+
+/*
+ * Pull Up Values - it indicates whether a pull-up should be
+ * applied for bidirectional mode only. The hardware ignores the
+ * configuration when operating in other modes.
+ */
+#define PMIC_MPP_PULL_UP_0P6KOHM 0
+#define PMIC_MPP_PULL_UP_10KOHM 1
+#define PMIC_MPP_PULL_UP_30KOHM 2
+#define PMIC_MPP_PULL_UP_OPEN 3
+
+/* type registers base address bases */
+#define PMIC_MPP_REG_TYPE 0x4
+#define PMIC_MPP_REG_SUBTYPE 0x5
+
+/* mpp peripheral type and subtype values */
+#define PMIC_MPP_TYPE 0x11
+#define PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT 0x3
+#define PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT 0x4
+#define PMIC_MPP_SUBTYPE_4CH_NO_SINK 0x5
+#define PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK 0x6
+#define PMIC_MPP_SUBTYPE_4CH_FULL_FUNC 0x7
+#define PMIC_MPP_SUBTYPE_8CH_FULL_FUNC 0xf
+
+#define PMIC_MPP_REG_RT_STS 0x10
+#define PMIC_MPP_REG_RT_STS_VAL_MASK 0x1
+
+/* control register base address bases */
+#define PMIC_MPP_REG_MODE_CTL 0x40
+#define PMIC_MPP_REG_DIG_VIN_CTL 0x41
+#define PMIC_MPP_REG_DIG_PULL_CTL 0x42
+#define PMIC_MPP_REG_DIG_IN_CTL 0x43
+#define PMIC_MPP_REG_EN_CTL 0x46
+#define PMIC_MPP_REG_AIN_CTL 0x4a
+
+/* PMIC_MPP_REG_MODE_CTL */
+#define PMIC_MPP_REG_MODE_VALUE_MASK 0x1
+#define PMIC_MPP_REG_MODE_FUNCTION_SHIFT 1
+#define PMIC_MPP_REG_MODE_FUNCTION_MASK 0x7
+#define PMIC_MPP_REG_MODE_DIR_SHIFT 4
+#define PMIC_MPP_REG_MODE_DIR_MASK 0x7
+
+/* PMIC_MPP_REG_DIG_VIN_CTL */
+#define PMIC_MPP_REG_VIN_SHIFT 0
+#define PMIC_MPP_REG_VIN_MASK 0x7
+
+/* PMIC_MPP_REG_DIG_PULL_CTL */
+#define PMIC_MPP_REG_PULL_SHIFT 0
+#define PMIC_MPP_REG_PULL_MASK 0x7
+
+/* PMIC_MPP_REG_EN_CTL */
+#define PMIC_MPP_REG_MASTER_EN_SHIFT 7
+
+/* PMIC_MPP_REG_AIN_CTL */
+#define PMIC_MPP_REG_AIN_ROUTE_SHIFT 0
+#define PMIC_MPP_REG_AIN_ROUTE_MASK 0x7
+
+#define PMIC_MPP_PHYSICAL_OFFSET 1
+
+/* Qualcomm specific pin configurations */
+#define PMIC_MPP_CONF_AMUX_ROUTE (PIN_CONFIG_END + 1)
+#define PMIC_MPP_CONF_ANALOG_MODE (PIN_CONFIG_END + 2)
+
+/**
+ * struct pmic_mpp_pad - keep current MPP settings
+ * @base: Address base in SPMI device.
+ * @irq: IRQ number which this MPP generate.
+ * @is_enabled: Set to false when MPP should be put in high Z state.
+ * @out_value: Cached pin output value.
+ * @output_enabled: Set to true if MPP output logic is enabled.
+ * @input_enabled: Set to true if MPP input buffer logic is enabled.
+ * @analog_mode: Set to true when MPP should operate in Analog Input, Analog
+ * Output or Bidirectional Analog mode.
+ * @num_sources: Number of power-sources supported by this MPP.
+ * @power_source: Current power-source used.
+ * @amux_input: Set the source for analog input.
+ * @pullup: Pullup resistor value. Valid in Bidirectional mode only.
+ * @function: See pmic_mpp_functions[].
+ */
+struct pmic_mpp_pad {
+ u16 base;
+ int irq;
+ bool is_enabled;
+ bool out_value;
+ bool output_enabled;
+ bool input_enabled;
+ bool analog_mode;
+ unsigned int num_sources;
+ unsigned int power_source;
+ unsigned int amux_input;
+ unsigned int pullup;
+ unsigned int function;
+};
+
+struct pmic_mpp_state {
+ struct device *dev;
+ struct regmap *map;
+ struct pinctrl_dev *ctrl;
+ struct gpio_chip chip;
+};
+
+struct pmic_mpp_bindings {
+ const char *property;
+ unsigned param;
+};
+
+static struct pmic_mpp_bindings pmic_mpp_bindings[] = {
+ {"qcom,amux-route", PMIC_MPP_CONF_AMUX_ROUTE},
+ {"qcom,analog-mode", PMIC_MPP_CONF_ANALOG_MODE},
+};
+
+static const char *const pmic_mpp_groups[] = {
+ "mpp1", "mpp2", "mpp3", "mpp4", "mpp5", "mpp6", "mpp7", "mpp8",
+};
+
+static const char *const pmic_mpp_functions[] = {
+ PMIC_MPP_FUNC_NORMAL, PMIC_MPP_FUNC_PAIRED,
+ "reserved1", "reserved2",
+ PMIC_MPP_FUNC_DTEST1, PMIC_MPP_FUNC_DTEST2,
+ PMIC_MPP_FUNC_DTEST3, PMIC_MPP_FUNC_DTEST4,
+};
+
+static inline struct pmic_mpp_state *to_mpp_state(struct gpio_chip *chip)
+{
+ return container_of(chip, struct pmic_mpp_state, chip);
+};
+
+static int pmic_mpp_read(struct pmic_mpp_state *state,
+ struct pmic_mpp_pad *pad, unsigned int addr)
+{
+ unsigned int val;
+ int ret;
+
+ ret = regmap_read(state->map, pad->base + addr, &val);
+ if (ret < 0)
+ dev_err(state->dev, "read 0x%x failed\n", addr);
+ else
+ ret = val;
+
+ return ret;
+}
+
+static int pmic_mpp_write(struct pmic_mpp_state *state,
+ struct pmic_mpp_pad *pad, unsigned int addr,
+ unsigned int val)
+{
+ int ret;
+
+ ret = regmap_write(state->map, pad->base + addr, val);
+ if (ret < 0)
+ dev_err(state->dev, "write 0x%x failed\n", addr);
+
+ return ret;
+}
+
+static int pmic_mpp_get_groups_count(struct pinctrl_dev *pctldev)
+{
+ /* Every PIN is a group */
+ return pctldev->desc->npins;
+}
+
+static const char *pmic_mpp_get_group_name(struct pinctrl_dev *pctldev,
+ unsigned pin)
+{
+ return pctldev->desc->pins[pin].name;
+}
+
+static int pmic_mpp_get_group_pins(struct pinctrl_dev *pctldev,
+ unsigned pin,
+ const unsigned **pins, unsigned *num_pins)
+{
+ *pins = &pctldev->desc->pins[pin].number;
+ *num_pins = 1;
+ return 0;
+}
+
+static int pmic_mpp_parse_dt_config(struct device_node *np,
+ struct pinctrl_dev *pctldev,
+ unsigned long **configs,
+ unsigned int *nconfs)
+{
+ struct pmic_mpp_bindings *par;
+ unsigned long cfg;
+ int ret, i;
+ u32 val;
+
+ for (i = 0; i < ARRAY_SIZE(pmic_mpp_bindings); i++) {
+ par = &pmic_mpp_bindings[i];
+ ret = of_property_read_u32(np, par->property, &val);
+
+ /* property not found */
+ if (ret == -EINVAL)
+ continue;
+
+ /* use zero as default value, when no value is specified */
+ if (ret)
+ val = 0;
+
+ dev_dbg(pctldev->dev, "found %s with value %u\n",
+ par->property, val);
+
+ cfg = pinconf_to_config_packed(par->param, val);
+
+ ret = pinctrl_utils_add_config(pctldev, configs, nconfs, cfg);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+
+static int pmic_mpp_dt_subnode_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np,
+ struct pinctrl_map **map,
+ unsigned *reserv, unsigned *nmaps,
+ enum pinctrl_map_type type)
+{
+ unsigned long *configs = NULL;
+ unsigned nconfs = 0;
+ struct property *prop;
+ const char *group;
+ int ret;
+
+ ret = pmic_mpp_parse_dt_config(np, pctldev, &configs, &nconfs);
+ if (ret < 0)
+ return ret;
+
+ if (!nconfs)
+ return 0;
+
+ ret = of_property_count_strings(np, "pins");
+ if (ret < 0)
+ goto exit;
+
+ ret = pinctrl_utils_reserve_map(pctldev, map, reserv, nmaps, ret);
+ if (ret < 0)
+ goto exit;
+
+ of_property_for_each_string(np, "pins", prop, group) {
+ ret = pinctrl_utils_add_map_configs(pctldev, map,
+ reserv, nmaps, group,
+ configs, nconfs, type);
+ if (ret < 0)
+ break;
+ }
+exit:
+ kfree(configs);
+ return ret;
+}
+
+static int pmic_mpp_dt_node_to_map(struct pinctrl_dev *pctldev,
+ struct device_node *np_config,
+ struct pinctrl_map **map, unsigned *nmaps)
+{
+ struct device_node *np;
+ enum pinctrl_map_type type;
+ unsigned reserv;
+ int ret;
+
+ ret = 0;
+ *map = NULL;
+ *nmaps = 0;
+ reserv = 0;
+ type = PIN_MAP_TYPE_CONFIGS_GROUP;
+
+ for_each_child_of_node(np_config, np) {
+ ret = pinconf_generic_dt_subnode_to_map(pctldev, np, map,
+ &reserv, nmaps, type);
+ if (ret)
+ break;
+
+ ret = pmic_mpp_dt_subnode_to_map(pctldev, np, map, &reserv,
+ nmaps, type);
+ if (ret)
+ break;
+ }
+
+ if (ret < 0)
+ pinctrl_utils_dt_free_map(pctldev, *map, *nmaps);
+
+ return ret;
+}
+
+static const struct pinctrl_ops pmic_mpp_pinctrl_ops = {
+ .get_groups_count = pmic_mpp_get_groups_count,
+ .get_group_name = pmic_mpp_get_group_name,
+ .get_group_pins = pmic_mpp_get_group_pins,
+ .dt_node_to_map = pmic_mpp_dt_node_to_map,
+ .dt_free_map = pinctrl_utils_dt_free_map,
+};
+
+static int pmic_mpp_get_functions_count(struct pinctrl_dev *pctldev)
+{
+ return ARRAY_SIZE(pmic_mpp_functions);
+}
+
+static const char *pmic_mpp_get_function_name(struct pinctrl_dev *pctldev,
+ unsigned function)
+{
+ return pmic_mpp_functions[function];
+}
+
+static int pmic_mpp_get_function_groups(struct pinctrl_dev *pctldev,
+ unsigned function,
+ const char *const **groups,
+ unsigned *const num_qgroups)
+{
+ *groups = pmic_mpp_groups;
+ *num_qgroups = pctldev->desc->npins;
+ return 0;
+}
+
+static int pmic_mpp_set_mux(struct pinctrl_dev *pctldev, unsigned function,
+ unsigned pin)
+{
+ struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev);
+ struct pmic_mpp_pad *pad;
+ unsigned int val;
+ int ret;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ pad->function = function;
+
+ if (!pad->analog_mode) {
+ val = 0; /* just digital input */
+ if (pad->output_enabled) {
+ if (pad->input_enabled)
+ val = 2; /* digital input and output */
+ else
+ val = 1; /* just digital output */
+ }
+ } else {
+ val = 4; /* just analog input */
+ if (pad->output_enabled) {
+ if (pad->input_enabled)
+ val = 3; /* analog input and output */
+ else
+ val = 5; /* just analog output */
+ }
+ }
+
+ val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
+ val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK;
+
+ ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = pad->is_enabled << PMIC_MPP_REG_MASTER_EN_SHIFT;
+
+ return pmic_mpp_write(state, pad, PMIC_MPP_REG_EN_CTL, val);
+}
+
+static const struct pinmux_ops pmic_mpp_pinmux_ops = {
+ .get_functions_count = pmic_mpp_get_functions_count,
+ .get_function_name = pmic_mpp_get_function_name,
+ .get_function_groups = pmic_mpp_get_function_groups,
+ .set_mux = pmic_mpp_set_mux,
+};
+
+static int pmic_mpp_config_get(struct pinctrl_dev *pctldev,
+ unsigned int pin, unsigned long *config)
+{
+ unsigned param = pinconf_to_config_param(*config);
+ struct pmic_mpp_pad *pad;
+ unsigned arg = 0;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ arg = pad->pullup == PMIC_MPP_PULL_UP_OPEN;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ switch (pad->pullup) {
+ case PMIC_MPP_PULL_UP_OPEN:
+ arg = 0;
+ break;
+ case PMIC_MPP_PULL_UP_0P6KOHM:
+ arg = 600;
+ break;
+ case PMIC_MPP_PULL_UP_10KOHM:
+ arg = 10000;
+ break;
+ case PMIC_MPP_PULL_UP_30KOHM:
+ arg = 30000;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ arg = !pad->is_enabled;
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ arg = pad->power_source;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ arg = pad->input_enabled;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ arg = pad->out_value;
+ break;
+ case PMIC_MPP_CONF_AMUX_ROUTE:
+ arg = pad->amux_input;
+ break;
+ case PMIC_MPP_CONF_ANALOG_MODE:
+ arg = pad->analog_mode;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Convert register value to pinconf value */
+ *config = pinconf_to_config_packed(param, arg);
+ return 0;
+}
+
+static int pmic_mpp_config_set(struct pinctrl_dev *pctldev, unsigned int pin,
+ unsigned long *configs, unsigned nconfs)
+{
+ struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev);
+ struct pmic_mpp_pad *pad;
+ unsigned param, arg;
+ unsigned int val;
+ int i, ret;
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ for (i = 0; i < nconfs; i++) {
+ param = pinconf_to_config_param(configs[i]);
+ arg = pinconf_to_config_argument(configs[i]);
+
+ switch (param) {
+ case PIN_CONFIG_BIAS_DISABLE:
+ pad->pullup = PMIC_MPP_PULL_UP_OPEN;
+ break;
+ case PIN_CONFIG_BIAS_PULL_UP:
+ switch (arg) {
+ case 600:
+ pad->pullup = PMIC_MPP_PULL_UP_0P6KOHM;
+ break;
+ case 10000:
+ pad->pullup = PMIC_MPP_PULL_UP_10KOHM;
+ break;
+ case 30000:
+ pad->pullup = PMIC_MPP_PULL_UP_30KOHM;
+ break;
+ default:
+ return -EINVAL;
+ }
+ break;
+ case PIN_CONFIG_BIAS_HIGH_IMPEDANCE:
+ pad->is_enabled = false;
+ break;
+ case PIN_CONFIG_POWER_SOURCE:
+ if (arg >= pad->num_sources)
+ return -EINVAL;
+ pad->power_source = arg;
+ break;
+ case PIN_CONFIG_INPUT_ENABLE:
+ pad->input_enabled = arg ? true : false;
+ break;
+ case PIN_CONFIG_OUTPUT:
+ pad->output_enabled = true;
+ pad->out_value = arg;
+ break;
+ case PMIC_MPP_CONF_AMUX_ROUTE:
+ if (arg >= PMIC_MPP_AMUX_ROUTE_ABUS4)
+ return -EINVAL;
+ pad->amux_input = arg;
+ break;
+ case PMIC_MPP_CONF_ANALOG_MODE:
+ pad->analog_mode = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ val = pad->power_source << PMIC_MPP_REG_VIN_SHIFT;
+
+ ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_VIN_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = pad->pullup << PMIC_MPP_REG_PULL_SHIFT;
+
+ ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_DIG_PULL_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ val = pad->amux_input & PMIC_MPP_REG_AIN_ROUTE_MASK;
+
+ ret = pmic_mpp_write(state, pad, PMIC_MPP_REG_AIN_CTL, val);
+ if (ret < 0)
+ return ret;
+
+ if (!pad->analog_mode) {
+ val = 0; /* just digital input */
+ if (pad->output_enabled) {
+ if (pad->input_enabled)
+ val = 2; /* digital input and output */
+ else
+ val = 1; /* just digital output */
+ }
+ } else {
+ val = 4; /* just analog input */
+ if (pad->output_enabled) {
+ if (pad->input_enabled)
+ val = 3; /* analog input and output */
+ else
+ val = 5; /* just analog output */
+ }
+ }
+
+ val = val << PMIC_MPP_REG_MODE_DIR_SHIFT;
+ val |= pad->function << PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
+ val |= pad->out_value & PMIC_MPP_REG_MODE_VALUE_MASK;
+
+ return pmic_mpp_write(state, pad, PMIC_MPP_REG_MODE_CTL, val);
+}
+
+static void pmic_mpp_config_dbg_show(struct pinctrl_dev *pctldev,
+ struct seq_file *s, unsigned pin)
+{
+ struct pmic_mpp_state *state = pinctrl_dev_get_drvdata(pctldev);
+ struct pmic_mpp_pad *pad;
+ int ret, val;
+
+ static const char *const biases[] = {
+ "0.6kOhm", "10kOhm", "30kOhm", "Disabled"
+ };
+
+
+ pad = pctldev->desc->pins[pin].drv_data;
+
+ seq_printf(s, " mpp%-2d:", pin + PMIC_MPP_PHYSICAL_OFFSET);
+
+ val = pmic_mpp_read(state, pad, PMIC_MPP_REG_EN_CTL);
+
+ if (val < 0 || !(val >> PMIC_MPP_REG_MASTER_EN_SHIFT)) {
+ seq_puts(s, " ---");
+ } else {
+
+ if (pad->input_enabled) {
+ ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS);
+ if (!ret) {
+ ret &= PMIC_MPP_REG_RT_STS_VAL_MASK;
+ pad->out_value = ret;
+ }
+ }
+
+ seq_printf(s, " %-4s", pad->output_enabled ? "out" : "in");
+ seq_printf(s, " %-4s", pad->analog_mode ? "ana" : "dig");
+ seq_printf(s, " %-7s", pmic_mpp_functions[pad->function]);
+ seq_printf(s, " vin-%d", pad->power_source);
+ seq_printf(s, " %-8s", biases[pad->pullup]);
+ seq_printf(s, " %-4s", pad->out_value ? "high" : "low");
+ }
+}
+
+static const struct pinconf_ops pmic_mpp_pinconf_ops = {
+ .pin_config_group_get = pmic_mpp_config_get,
+ .pin_config_group_set = pmic_mpp_config_set,
+ .pin_config_group_dbg_show = pmic_mpp_config_dbg_show,
+};
+
+static int pmic_mpp_direction_input(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_mpp_state *state = to_mpp_state(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_INPUT_ENABLE, 1);
+
+ return pmic_mpp_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int pmic_mpp_direction_output(struct gpio_chip *chip,
+ unsigned pin, int val)
+{
+ struct pmic_mpp_state *state = to_mpp_state(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, val);
+
+ return pmic_mpp_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int pmic_mpp_get(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_pad *pad;
+ int ret;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ if (pad->input_enabled) {
+ ret = pmic_mpp_read(state, pad, PMIC_MPP_REG_RT_STS);
+ if (ret < 0)
+ return ret;
+
+ pad->out_value = ret & PMIC_MPP_REG_RT_STS_VAL_MASK;
+ }
+
+ return pad->out_value;
+}
+
+static void pmic_mpp_set(struct gpio_chip *chip, unsigned pin, int value)
+{
+ struct pmic_mpp_state *state = to_mpp_state(chip);
+ unsigned long config;
+
+ config = pinconf_to_config_packed(PIN_CONFIG_OUTPUT, value);
+
+ pmic_mpp_config_set(state->ctrl, pin, &config, 1);
+}
+
+static int pmic_mpp_request(struct gpio_chip *chip, unsigned base)
+{
+ return pinctrl_request_gpio(chip->base + base);
+}
+
+static void pmic_mpp_free(struct gpio_chip *chip, unsigned base)
+{
+ pinctrl_free_gpio(chip->base + base);
+}
+
+static int pmic_mpp_of_xlate(struct gpio_chip *chip,
+ const struct of_phandle_args *gpio_desc,
+ u32 *flags)
+{
+ if (chip->of_gpio_n_cells < 2)
+ return -EINVAL;
+
+ if (flags)
+ *flags = gpio_desc->args[1];
+
+ return gpio_desc->args[0] - PMIC_MPP_PHYSICAL_OFFSET;
+}
+
+static int pmic_mpp_to_irq(struct gpio_chip *chip, unsigned pin)
+{
+ struct pmic_mpp_state *state = to_mpp_state(chip);
+ struct pmic_mpp_pad *pad;
+
+ pad = state->ctrl->desc->pins[pin].drv_data;
+
+ return pad->irq;
+}
+
+static void pmic_mpp_dbg_show(struct seq_file *s, struct gpio_chip *chip)
+{
+ struct pmic_mpp_state *state = to_mpp_state(chip);
+ unsigned i;
+
+ for (i = 0; i < chip->ngpio; i++) {
+ pmic_mpp_config_dbg_show(state->ctrl, s, i);
+ seq_puts(s, "\n");
+ }
+}
+
+static const struct gpio_chip pmic_mpp_gpio_template = {
+ .direction_input = pmic_mpp_direction_input,
+ .direction_output = pmic_mpp_direction_output,
+ .get = pmic_mpp_get,
+ .set = pmic_mpp_set,
+ .request = pmic_mpp_request,
+ .free = pmic_mpp_free,
+ .of_xlate = pmic_mpp_of_xlate,
+ .to_irq = pmic_mpp_to_irq,
+ .dbg_show = pmic_mpp_dbg_show,
+};
+
+static int pmic_mpp_populate(struct pmic_mpp_state *state,
+ struct pmic_mpp_pad *pad)
+{
+ int type, subtype, val, dir;
+
+ type = pmic_mpp_read(state, pad, PMIC_MPP_REG_TYPE);
+ if (type < 0)
+ return type;
+
+ if (type != PMIC_MPP_TYPE) {
+ dev_err(state->dev, "incorrect block type 0x%x at 0x%x\n",
+ type, pad->base);
+ return -ENODEV;
+ }
+
+ subtype = pmic_mpp_read(state, pad, PMIC_MPP_REG_SUBTYPE);
+ if (subtype < 0)
+ return subtype;
+
+ switch (subtype) {
+ case PMIC_MPP_SUBTYPE_4CH_NO_ANA_OUT:
+ case PMIC_MPP_SUBTYPE_ULT_4CH_NO_ANA_OUT:
+ case PMIC_MPP_SUBTYPE_4CH_NO_SINK:
+ case PMIC_MPP_SUBTYPE_ULT_4CH_NO_SINK:
+ case PMIC_MPP_SUBTYPE_4CH_FULL_FUNC:
+ pad->num_sources = 4;
+ break;
+ case PMIC_MPP_SUBTYPE_8CH_FULL_FUNC:
+ pad->num_sources = 8;
+ break;
+ default:
+ dev_err(state->dev, "unknown MPP type 0x%x at 0x%x\n",
+ subtype, pad->base);
+ return -ENODEV;
+ }
+
+ val = pmic_mpp_read(state, pad, PMIC_MPP_REG_MODE_CTL);
+ if (val < 0)
+ return val;
+
+ pad->out_value = val & PMIC_MPP_REG_MODE_VALUE_MASK;
+
+ dir = val >> PMIC_MPP_REG_MODE_DIR_SHIFT;
+ dir &= PMIC_MPP_REG_MODE_DIR_MASK;
+
+ switch (dir) {
+ case 0:
+ pad->input_enabled = true;
+ pad->output_enabled = false;
+ pad->analog_mode = false;
+ break;
+ case 1:
+ pad->input_enabled = false;
+ pad->output_enabled = true;
+ pad->analog_mode = false;
+ break;
+ case 2:
+ pad->input_enabled = true;
+ pad->output_enabled = true;
+ pad->analog_mode = false;
+ break;
+ case 3:
+ pad->input_enabled = true;
+ pad->output_enabled = true;
+ pad->analog_mode = true;
+ break;
+ case 4:
+ pad->input_enabled = true;
+ pad->output_enabled = false;
+ pad->analog_mode = true;
+ break;
+ case 5:
+ pad->input_enabled = false;
+ pad->output_enabled = true;
+ pad->analog_mode = true;
+ break;
+ default:
+ dev_err(state->dev, "unknown MPP direction\n");
+ return -ENODEV;
+ }
+
+ pad->function = val >> PMIC_MPP_REG_MODE_FUNCTION_SHIFT;
+ pad->function &= PMIC_MPP_REG_MODE_FUNCTION_MASK;
+
+ val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_VIN_CTL);
+ if (val < 0)
+ return val;
+
+ pad->power_source = val >> PMIC_MPP_REG_VIN_SHIFT;
+ pad->power_source &= PMIC_MPP_REG_VIN_MASK;
+
+ val = pmic_mpp_read(state, pad, PMIC_MPP_REG_DIG_PULL_CTL);
+ if (val < 0)
+ return val;
+
+ pad->pullup = val >> PMIC_MPP_REG_PULL_SHIFT;
+ pad->pullup &= PMIC_MPP_REG_PULL_MASK;
+
+ val = pmic_mpp_read(state, pad, PMIC_MPP_REG_AIN_CTL);
+ if (val < 0)
+ return val;
+
+ pad->amux_input = val >> PMIC_MPP_REG_AIN_ROUTE_SHIFT;
+ pad->amux_input &= PMIC_MPP_REG_AIN_ROUTE_MASK;
+
+ /* Pin could be disabled with PIN_CONFIG_BIAS_HIGH_IMPEDANCE */
+ pad->is_enabled = true;
+ return 0;
+}
+
+static int pmic_mpp_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct pinctrl_pin_desc *pindesc;
+ struct pinctrl_desc *pctrldesc;
+ struct pmic_mpp_pad *pad, *pads;
+ struct pmic_mpp_state *state;
+ int ret, npins, i;
+ u32 res[2];
+
+ ret = of_property_read_u32_array(dev->of_node, "reg", res, 2);
+ if (ret < 0) {
+ dev_err(dev, "missing base address and/or range");
+ return ret;
+ }
+
+ npins = res[1] / PMIC_MPP_ADDRESS_RANGE;
+ if (!npins)
+ return -EINVAL;
+
+ BUG_ON(npins > ARRAY_SIZE(pmic_mpp_groups));
+
+ state = devm_kzalloc(dev, sizeof(*state), GFP_KERNEL);
+ if (!state)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, state);
+
+ state->dev = &pdev->dev;
+ state->map = dev_get_regmap(dev->parent, NULL);
+
+ pindesc = devm_kcalloc(dev, npins, sizeof(*pindesc), GFP_KERNEL);
+ if (!pindesc)
+ return -ENOMEM;
+
+ pads = devm_kcalloc(dev, npins, sizeof(*pads), GFP_KERNEL);
+ if (!pads)
+ return -ENOMEM;
+
+ pctrldesc = devm_kzalloc(dev, sizeof(*pctrldesc), GFP_KERNEL);
+ if (!pctrldesc)
+ return -ENOMEM;
+
+ pctrldesc->pctlops = &pmic_mpp_pinctrl_ops;
+ pctrldesc->pmxops = &pmic_mpp_pinmux_ops;
+ pctrldesc->confops = &pmic_mpp_pinconf_ops;
+ pctrldesc->owner = THIS_MODULE;
+ pctrldesc->name = dev_name(dev);
+ pctrldesc->pins = pindesc;
+ pctrldesc->npins = npins;
+
+ for (i = 0; i < npins; i++, pindesc++) {
+ pad = &pads[i];
+ pindesc->drv_data = pad;
+ pindesc->number = i;
+ pindesc->name = pmic_mpp_groups[i];
+
+ pad->irq = platform_get_irq(pdev, i);
+ if (pad->irq < 0)
+ return pad->irq;
+
+ pad->base = res[0] + i * PMIC_MPP_ADDRESS_RANGE;
+
+ ret = pmic_mpp_populate(state, pad);
+ if (ret < 0)
+ return ret;
+ }
+
+ state->chip = pmic_mpp_gpio_template;
+ state->chip.dev = dev;
+ state->chip.base = -1;
+ state->chip.ngpio = npins;
+ state->chip.label = dev_name(dev);
+ state->chip.of_gpio_n_cells = 2;
+ state->chip.can_sleep = false;
+
+ state->ctrl = pinctrl_register(pctrldesc, dev, state);
+ if (!state->ctrl)
+ return -ENODEV;
+
+ ret = gpiochip_add(&state->chip);
+ if (ret) {
+ dev_err(state->dev, "can't add gpio chip\n");
+ goto err_chip;
+ }
+
+ ret = gpiochip_add_pin_range(&state->chip, dev_name(dev), 0, 0, npins);
+ if (ret) {
+ dev_err(dev, "failed to add pin range\n");
+ goto err_range;
+ }
+
+ return 0;
+
+err_range:
+ gpiochip_remove(&state->chip);
+err_chip:
+ pinctrl_unregister(state->ctrl);
+ return ret;
+}
+
+static int pmic_mpp_remove(struct platform_device *pdev)
+{
+ struct pmic_mpp_state *state = platform_get_drvdata(pdev);
+
+ gpiochip_remove(&state->chip);
+ pinctrl_unregister(state->ctrl);
+ return 0;
+}
+
+static const struct of_device_id pmic_mpp_of_match[] = {
+ { .compatible = "qcom,pm8841-mpp" }, /* 4 MPP's */
+ { .compatible = "qcom,pm8941-mpp" }, /* 8 MPP's */
+ { .compatible = "qcom,pma8084-mpp" }, /* 8 MPP's */
+ { },
+};
+
+MODULE_DEVICE_TABLE(of, pmic_mpp_of_match);
+
+static struct platform_driver pmic_mpp_driver = {
+ .driver = {
+ .name = "qcom-spmi-mpp",
+ .of_match_table = pmic_mpp_of_match,
+ },
+ .probe = pmic_mpp_probe,
+ .remove = pmic_mpp_remove,
+};
+
+module_platform_driver(pmic_mpp_driver);
+
+MODULE_AUTHOR("Ivan T. Ivanov <iivanov@mm-sol.com>");
+MODULE_DESCRIPTION("Qualcomm SPMI PMIC MPP pin control driver");
+MODULE_ALIAS("platform:qcom-spmi-mpp");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.c b/drivers/pinctrl/samsung/pinctrl-exynos.c
index d7154ed..d5d4cfc 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.c
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.c
@@ -46,22 +46,16 @@ static inline struct exynos_irq_chip *to_exynos_irq_chip(struct irq_chip *chip)
return container_of(chip, struct exynos_irq_chip, chip);
}
-static struct samsung_pin_bank_type bank_type_off = {
+static const struct samsung_pin_bank_type bank_type_off = {
.fld_width = { 4, 1, 2, 2, 2, 2, },
.reg_offset = { 0x00, 0x04, 0x08, 0x0c, 0x10, 0x14, },
};
-static struct samsung_pin_bank_type bank_type_alive = {
+static const struct samsung_pin_bank_type bank_type_alive = {
.fld_width = { 4, 1, 2, 2, },
.reg_offset = { 0x00, 0x04, 0x08, 0x0c, },
};
-/* list of external wakeup controllers supported */
-static const struct of_device_id exynos_wkup_irq_ids[] = {
- { .compatible = "samsung,exynos4210-wakeup-eint", },
- { }
-};
-
static void exynos_irq_mask(struct irq_data *irqd)
{
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
@@ -171,7 +165,7 @@ static int exynos_irq_request_resources(struct irq_data *irqd)
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
- struct samsung_pin_bank_type *bank_type = bank->type;
+ const struct samsung_pin_bank_type *bank_type = bank->type;
struct samsung_pinctrl_drv_data *d = bank->drvdata;
unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
@@ -210,7 +204,7 @@ static void exynos_irq_release_resources(struct irq_data *irqd)
struct irq_chip *chip = irq_data_get_irq_chip(irqd);
struct exynos_irq_chip *our_chip = to_exynos_irq_chip(chip);
struct samsung_pin_bank *bank = irq_data_get_irq_chip_data(irqd);
- struct samsung_pin_bank_type *bank_type = bank->type;
+ const struct samsung_pin_bank_type *bank_type = bank->type;
struct samsung_pinctrl_drv_data *d = bank->drvdata;
unsigned int shift = EXYNOS_EINT_CON_LEN * irqd->hwirq;
unsigned long reg_con = our_chip->eint_con + bank->eint_offset;
@@ -254,31 +248,30 @@ static struct exynos_irq_chip exynos_gpio_irq_chip = {
.eint_pend = EXYNOS_GPIO_EPEND_OFFSET,
};
-static int exynos_gpio_irq_map(struct irq_domain *h, unsigned int virq,
+static int exynos_eint_irq_map(struct irq_domain *h, unsigned int virq,
irq_hw_number_t hw)
{
struct samsung_pin_bank *b = h->host_data;
irq_set_chip_data(virq, b);
- irq_set_chip_and_handler(virq, &exynos_gpio_irq_chip.chip,
+ irq_set_chip_and_handler(virq, &b->irq_chip->chip,
handle_level_irq);
set_irq_flags(virq, IRQF_VALID);
return 0;
}
/*
- * irq domain callbacks for external gpio interrupt controller.
+ * irq domain callbacks for external gpio and wakeup interrupt controllers.
*/
-static const struct irq_domain_ops exynos_gpio_irqd_ops = {
- .map = exynos_gpio_irq_map,
+static const struct irq_domain_ops exynos_eint_irqd_ops = {
+ .map = exynos_eint_irq_map,
.xlate = irq_domain_xlate_twocell,
};
static irqreturn_t exynos_eint_gpio_irq(int irq, void *data)
{
struct samsung_pinctrl_drv_data *d = data;
- struct samsung_pin_ctrl *ctrl = d->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
+ struct samsung_pin_bank *bank = d->pin_banks;
unsigned int svc, group, pin, virq;
svc = readl(d->virt_base + EXYNOS_SVC_OFFSET);
@@ -325,12 +318,12 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
return -ENXIO;
}
- bank = d->ctrl->pin_banks;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ bank = d->pin_banks;
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
if (bank->eint_type != EINT_TYPE_GPIO)
continue;
bank->irq_domain = irq_domain_add_linear(bank->of_node,
- bank->nr_pins, &exynos_gpio_irqd_ops, bank);
+ bank->nr_pins, &exynos_eint_irqd_ops, bank);
if (!bank->irq_domain) {
dev_err(dev, "gpio irq domain add failed\n");
ret = -ENXIO;
@@ -344,6 +337,8 @@ static int exynos_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
ret = -ENOMEM;
goto err_domains;
}
+
+ bank->irq_chip = &exynos_gpio_irq_chip;
}
return 0;
@@ -383,9 +378,9 @@ static int exynos_wkup_irq_set_wake(struct irq_data *irqd, unsigned int on)
/*
* irq_chip for wakeup interrupts
*/
-static struct exynos_irq_chip exynos_wkup_irq_chip = {
+static struct exynos_irq_chip exynos4210_wkup_irq_chip __initdata = {
.chip = {
- .name = "exynos_wkup_irq_chip",
+ .name = "exynos4210_wkup_irq_chip",
.irq_unmask = exynos_irq_unmask,
.irq_mask = exynos_irq_mask,
.irq_ack = exynos_irq_ack,
@@ -399,6 +394,31 @@ static struct exynos_irq_chip exynos_wkup_irq_chip = {
.eint_pend = EXYNOS_WKUP_EPEND_OFFSET,
};
+static struct exynos_irq_chip exynos7_wkup_irq_chip __initdata = {
+ .chip = {
+ .name = "exynos7_wkup_irq_chip",
+ .irq_unmask = exynos_irq_unmask,
+ .irq_mask = exynos_irq_mask,
+ .irq_ack = exynos_irq_ack,
+ .irq_set_type = exynos_irq_set_type,
+ .irq_set_wake = exynos_wkup_irq_set_wake,
+ .irq_request_resources = exynos_irq_request_resources,
+ .irq_release_resources = exynos_irq_release_resources,
+ },
+ .eint_con = EXYNOS7_WKUP_ECON_OFFSET,
+ .eint_mask = EXYNOS7_WKUP_EMASK_OFFSET,
+ .eint_pend = EXYNOS7_WKUP_EPEND_OFFSET,
+};
+
+/* list of external wakeup controllers supported */
+static const struct of_device_id exynos_wkup_irq_ids[] = {
+ { .compatible = "samsung,exynos4210-wakeup-eint",
+ .data = &exynos4210_wkup_irq_chip },
+ { .compatible = "samsung,exynos7-wakeup-eint",
+ .data = &exynos7_wkup_irq_chip },
+ { }
+};
+
/* interrupt handler for wakeup interrupts 0..15 */
static void exynos_irq_eint0_15(unsigned int irq, struct irq_desc *desc)
{
@@ -445,9 +465,9 @@ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
for (i = 0; i < eintd->nr_banks; ++i) {
struct samsung_pin_bank *b = eintd->banks[i];
- pend = readl(d->virt_base + EXYNOS_WKUP_EPEND_OFFSET
+ pend = readl(d->virt_base + b->irq_chip->eint_pend
+ b->eint_offset);
- mask = readl(d->virt_base + EXYNOS_WKUP_EMASK_OFFSET
+ mask = readl(d->virt_base + b->irq_chip->eint_mask
+ b->eint_offset);
exynos_irq_demux_eint(pend & ~mask, b->irq_domain);
}
@@ -455,24 +475,6 @@ static void exynos_irq_demux_eint16_31(unsigned int irq, struct irq_desc *desc)
chained_irq_exit(chip, desc);
}
-static int exynos_wkup_irq_map(struct irq_domain *h, unsigned int virq,
- irq_hw_number_t hw)
-{
- irq_set_chip_and_handler(virq, &exynos_wkup_irq_chip.chip,
- handle_level_irq);
- irq_set_chip_data(virq, h->host_data);
- set_irq_flags(virq, IRQF_VALID);
- return 0;
-}
-
-/*
- * irq domain callbacks for external wakeup interrupt controller.
- */
-static const struct irq_domain_ops exynos_wkup_irqd_ops = {
- .map = exynos_wkup_irq_map,
- .xlate = irq_domain_xlate_twocell,
-};
-
/*
* exynos_eint_wkup_init() - setup handling of external wakeup interrupts.
* @d: driver data of samsung pinctrl driver.
@@ -485,12 +487,18 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
struct samsung_pin_bank *bank;
struct exynos_weint_data *weint_data;
struct exynos_muxed_weint_data *muxed_data;
+ struct exynos_irq_chip *irq_chip;
unsigned int muxed_banks = 0;
unsigned int i;
int idx, irq;
for_each_child_of_node(dev->of_node, np) {
- if (of_match_node(exynos_wkup_irq_ids, np)) {
+ const struct of_device_id *match;
+
+ match = of_match_node(exynos_wkup_irq_ids, np);
+ if (match) {
+ irq_chip = kmemdup(match->data,
+ sizeof(*irq_chip), GFP_KERNEL);
wkup_np = np;
break;
}
@@ -498,18 +506,20 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
if (!wkup_np)
return -ENODEV;
- bank = d->ctrl->pin_banks;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ bank = d->pin_banks;
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
if (bank->eint_type != EINT_TYPE_WKUP)
continue;
bank->irq_domain = irq_domain_add_linear(bank->of_node,
- bank->nr_pins, &exynos_wkup_irqd_ops, bank);
+ bank->nr_pins, &exynos_eint_irqd_ops, bank);
if (!bank->irq_domain) {
dev_err(dev, "wkup irq domain add failed\n");
return -ENXIO;
}
+ bank->irq_chip = irq_chip;
+
if (!of_find_property(bank->of_node, "interrupts", NULL)) {
bank->eint_type = EINT_TYPE_WKUP_MUX;
++muxed_banks;
@@ -556,9 +566,9 @@ static int exynos_eint_wkup_init(struct samsung_pinctrl_drv_data *d)
irq_set_chained_handler(irq, exynos_irq_demux_eint16_31);
irq_set_handler_data(irq, muxed_data);
- bank = d->ctrl->pin_banks;
+ bank = d->pin_banks;
idx = 0;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
if (bank->eint_type != EINT_TYPE_WKUP_MUX)
continue;
@@ -590,11 +600,10 @@ static void exynos_pinctrl_suspend_bank(
static void exynos_pinctrl_suspend(struct samsung_pinctrl_drv_data *drvdata)
{
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
+ struct samsung_pin_bank *bank = drvdata->pin_banks;
int i;
- for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+ for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
if (bank->eint_type == EINT_TYPE_GPIO)
exynos_pinctrl_suspend_bank(drvdata, bank);
}
@@ -626,17 +635,16 @@ static void exynos_pinctrl_resume_bank(
static void exynos_pinctrl_resume(struct samsung_pinctrl_drv_data *drvdata)
{
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
+ struct samsung_pin_bank *bank = drvdata->pin_banks;
int i;
- for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+ for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
if (bank->eint_type == EINT_TYPE_GPIO)
exynos_pinctrl_resume_bank(drvdata, bank);
}
/* pin banks of s5pv210 pin-controller */
-static struct samsung_pin_bank s5pv210_pin_bank[] = {
+static const struct samsung_pin_bank_data s5pv210_pin_bank[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
@@ -673,7 +681,7 @@ static struct samsung_pin_bank s5pv210_pin_bank[] = {
EXYNOS_PIN_BANK_EINTW(8, 0xc60, "gph3", 0x0c),
};
-struct samsung_pin_ctrl s5pv210_pin_ctrl[] = {
+const struct samsung_pin_ctrl s5pv210_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = s5pv210_pin_bank,
@@ -682,12 +690,11 @@ struct samsung_pin_ctrl s5pv210_pin_ctrl[] = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "s5pv210-gpio-ctrl0",
},
};
/* pin banks of exynos3250 pin-controller 0 */
-static struct samsung_pin_bank exynos3250_pin_banks0[] = {
+static const struct samsung_pin_bank_data exynos3250_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
@@ -698,7 +705,7 @@ static struct samsung_pin_bank exynos3250_pin_banks0[] = {
};
/* pin banks of exynos3250 pin-controller 1 */
-static struct samsung_pin_bank exynos3250_pin_banks1[] = {
+static const struct samsung_pin_bank_data exynos3250_pin_banks1[] __initconst = {
EXYNOS_PIN_BANK_EINTN(8, 0x120, "gpe0"),
EXYNOS_PIN_BANK_EINTN(8, 0x140, "gpe1"),
EXYNOS_PIN_BANK_EINTN(3, 0x180, "gpe2"),
@@ -721,7 +728,7 @@ static struct samsung_pin_bank exynos3250_pin_banks1[] = {
* Samsung pinctrl driver data for Exynos3250 SoC. Exynos3250 SoC includes
* two gpio/pin-mux/pinconfig controllers.
*/
-struct samsung_pin_ctrl exynos3250_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos3250_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = exynos3250_pin_banks0,
@@ -729,7 +736,6 @@ struct samsung_pin_ctrl exynos3250_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos3250-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos3250_pin_banks1,
@@ -738,12 +744,11 @@ struct samsung_pin_ctrl exynos3250_pin_ctrl[] = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos3250-gpio-ctrl1",
},
};
/* pin banks of exynos4210 pin-controller 0 */
-static struct samsung_pin_bank exynos4210_pin_banks0[] = {
+static const struct samsung_pin_bank_data exynos4210_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
@@ -763,7 +768,7 @@ static struct samsung_pin_bank exynos4210_pin_banks0[] = {
};
/* pin banks of exynos4210 pin-controller 1 */
-static struct samsung_pin_bank exynos4210_pin_banks1[] = {
+static const struct samsung_pin_bank_data exynos4210_pin_banks1[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpj0", 0x00),
EXYNOS_PIN_BANK_EINTG(5, 0x020, "gpj1", 0x04),
EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08),
@@ -787,7 +792,7 @@ static struct samsung_pin_bank exynos4210_pin_banks1[] = {
};
/* pin banks of exynos4210 pin-controller 2 */
-static struct samsung_pin_bank exynos4210_pin_banks2[] = {
+static const struct samsung_pin_bank_data exynos4210_pin_banks2[] __initconst = {
EXYNOS_PIN_BANK_EINTN(7, 0x000, "gpz"),
};
@@ -795,7 +800,7 @@ static struct samsung_pin_bank exynos4210_pin_banks2[] = {
* Samsung pinctrl driver data for Exynos4210 SoC. Exynos4210 SoC includes
* three gpio/pin-mux/pinconfig controllers.
*/
-struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos4210_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = exynos4210_pin_banks0,
@@ -803,7 +808,6 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos4210-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos4210_pin_banks1,
@@ -812,17 +816,15 @@ struct samsung_pin_ctrl exynos4210_pin_ctrl[] = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos4210-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos4210_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos4210_pin_banks2),
- .label = "exynos4210-gpio-ctrl2",
},
};
/* pin banks of exynos4x12 pin-controller 0 */
-static struct samsung_pin_bank exynos4x12_pin_banks0[] = {
+static const struct samsung_pin_bank_data exynos4x12_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
@@ -839,7 +841,7 @@ static struct samsung_pin_bank exynos4x12_pin_banks0[] = {
};
/* pin banks of exynos4x12 pin-controller 1 */
-static struct samsung_pin_bank exynos4x12_pin_banks1[] = {
+static const struct samsung_pin_bank_data exynos4x12_pin_banks1[] __initconst = {
EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpk0", 0x08),
EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
@@ -866,12 +868,12 @@ static struct samsung_pin_bank exynos4x12_pin_banks1[] = {
};
/* pin banks of exynos4x12 pin-controller 2 */
-static struct samsung_pin_bank exynos4x12_pin_banks2[] = {
+static const struct samsung_pin_bank_data exynos4x12_pin_banks2[] __initconst = {
EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
};
/* pin banks of exynos4x12 pin-controller 3 */
-static struct samsung_pin_bank exynos4x12_pin_banks3[] = {
+static const struct samsung_pin_bank_data exynos4x12_pin_banks3[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpv2", 0x08),
@@ -883,7 +885,7 @@ static struct samsung_pin_bank exynos4x12_pin_banks3[] = {
* Samsung pinctrl driver data for Exynos4x12 SoC. Exynos4x12 SoC includes
* four gpio/pin-mux/pinconfig controllers.
*/
-struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos4x12_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = exynos4x12_pin_banks0,
@@ -891,7 +893,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos4x12-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos4x12_pin_banks1,
@@ -900,7 +901,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos4x12-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos4x12_pin_banks2,
@@ -908,7 +908,6 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos4x12-gpio-ctrl2",
}, {
/* pin-controller instance 3 data */
.pin_banks = exynos4x12_pin_banks3,
@@ -916,12 +915,86 @@ struct samsung_pin_ctrl exynos4x12_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos4x12-gpio-ctrl3",
+ },
+};
+
+/* pin banks of exynos4415 pin-controller 0 */
+static const struct samsung_pin_bank_data exynos4415_pin_banks0[] = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpb", 0x08),
+ EXYNOS_PIN_BANK_EINTG(5, 0x060, "gpc0", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(5, 0x080, "gpc1", 0x10),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0A0, "gpd0", 0x14),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpd1", 0x18),
+ EXYNOS_PIN_BANK_EINTG(8, 0x180, "gpf0", 0x30),
+ EXYNOS_PIN_BANK_EINTG(8, 0x1A0, "gpf1", 0x34),
+ EXYNOS_PIN_BANK_EINTG(1, 0x1C0, "gpf2", 0x38),
+};
+
+/* pin banks of exynos4415 pin-controller 1 */
+static const struct samsung_pin_bank_data exynos4415_pin_banks1[] = {
+ EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpk0", 0x08),
+ EXYNOS_PIN_BANK_EINTG(7, 0x060, "gpk1", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(7, 0x080, "gpk2", 0x10),
+ EXYNOS_PIN_BANK_EINTG(7, 0x0A0, "gpk3", 0x14),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0C0, "gpl0", 0x18),
+ EXYNOS_PIN_BANK_EINTN(6, 0x120, "mp00"),
+ EXYNOS_PIN_BANK_EINTN(4, 0x140, "mp01"),
+ EXYNOS_PIN_BANK_EINTN(6, 0x160, "mp02"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x180, "mp03"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x1A0, "mp04"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x1C0, "mp05"),
+ EXYNOS_PIN_BANK_EINTN(8, 0x1E0, "mp06"),
+ EXYNOS_PIN_BANK_EINTG(8, 0x260, "gpm0", 0x24),
+ EXYNOS_PIN_BANK_EINTG(7, 0x280, "gpm1", 0x28),
+ EXYNOS_PIN_BANK_EINTG(5, 0x2A0, "gpm2", 0x2c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x2C0, "gpm3", 0x30),
+ EXYNOS_PIN_BANK_EINTG(8, 0x2E0, "gpm4", 0x34),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC40, "gpx2", 0x08),
+ EXYNOS_PIN_BANK_EINTW(8, 0xC60, "gpx3", 0x0c),
+};
+
+/* pin banks of exynos4415 pin-controller 2 */
+static const struct samsung_pin_bank_data exynos4415_pin_banks2[] = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
+ EXYNOS_PIN_BANK_EINTN(2, 0x000, "etc1"),
+};
+
+/*
+ * Samsung pinctrl driver data for Exynos4415 SoC. Exynos4415 SoC includes
+ * three gpio/pin-mux/pinconfig controllers.
+ */
+const struct samsung_pin_ctrl exynos4415_pin_ctrl[] = {
+ {
+ /* pin-controller instance 0 data */
+ .pin_banks = exynos4415_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos4415_pin_banks0),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 1 data */
+ .pin_banks = exynos4415_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos4415_pin_banks1),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
+ }, {
+ /* pin-controller instance 2 data */
+ .pin_banks = exynos4415_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos4415_pin_banks2),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .suspend = exynos_pinctrl_suspend,
+ .resume = exynos_pinctrl_resume,
},
};
/* pin banks of exynos5250 pin-controller 0 */
-static struct samsung_pin_bank exynos5250_pin_banks0[] = {
+static const struct samsung_pin_bank_data exynos5250_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
@@ -950,7 +1023,7 @@ static struct samsung_pin_bank exynos5250_pin_banks0[] = {
};
/* pin banks of exynos5250 pin-controller 1 */
-static struct samsung_pin_bank exynos5250_pin_banks1[] = {
+static const struct samsung_pin_bank_data exynos5250_pin_banks1[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
EXYNOS_PIN_BANK_EINTG(4, 0x040, "gpf0", 0x08),
@@ -963,7 +1036,7 @@ static struct samsung_pin_bank exynos5250_pin_banks1[] = {
};
/* pin banks of exynos5250 pin-controller 2 */
-static struct samsung_pin_bank exynos5250_pin_banks2[] = {
+static const struct samsung_pin_bank_data exynos5250_pin_banks2[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpv0", 0x00),
EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpv1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpv2", 0x08),
@@ -972,7 +1045,7 @@ static struct samsung_pin_bank exynos5250_pin_banks2[] = {
};
/* pin banks of exynos5250 pin-controller 3 */
-static struct samsung_pin_bank exynos5250_pin_banks3[] = {
+static const struct samsung_pin_bank_data exynos5250_pin_banks3[] __initconst = {
EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
};
@@ -980,7 +1053,7 @@ static struct samsung_pin_bank exynos5250_pin_banks3[] = {
* Samsung pinctrl driver data for Exynos5250 SoC. Exynos5250 SoC includes
* four gpio/pin-mux/pinconfig controllers.
*/
-struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos5250_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = exynos5250_pin_banks0,
@@ -989,7 +1062,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.eint_wkup_init = exynos_eint_wkup_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos5250-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos5250_pin_banks1,
@@ -997,7 +1069,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos5250-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos5250_pin_banks2,
@@ -1005,7 +1076,6 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos5250-gpio-ctrl2",
}, {
/* pin-controller instance 3 data */
.pin_banks = exynos5250_pin_banks3,
@@ -1013,12 +1083,11 @@ struct samsung_pin_ctrl exynos5250_pin_ctrl[] = {
.eint_gpio_init = exynos_eint_gpio_init,
.suspend = exynos_pinctrl_suspend,
.resume = exynos_pinctrl_resume,
- .label = "exynos5250-gpio-ctrl3",
},
};
/* pin banks of exynos5260 pin-controller 0 */
-static struct samsung_pin_bank exynos5260_pin_banks0[] = {
+static const struct samsung_pin_bank_data exynos5260_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(7, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
@@ -1043,7 +1112,7 @@ static struct samsung_pin_bank exynos5260_pin_banks0[] = {
};
/* pin banks of exynos5260 pin-controller 1 */
-static struct samsung_pin_bank exynos5260_pin_banks1[] = {
+static const struct samsung_pin_bank_data exynos5260_pin_banks1[] __initconst = {
EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpc0", 0x00),
EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpc1", 0x04),
EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
@@ -1052,7 +1121,7 @@ static struct samsung_pin_bank exynos5260_pin_banks1[] = {
};
/* pin banks of exynos5260 pin-controller 2 */
-static struct samsung_pin_bank exynos5260_pin_banks2[] = {
+static const struct samsung_pin_bank_data exynos5260_pin_banks2[] __initconst = {
EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz0", 0x00),
EXYNOS_PIN_BANK_EINTG(4, 0x020, "gpz1", 0x04),
};
@@ -1061,31 +1130,28 @@ static struct samsung_pin_bank exynos5260_pin_banks2[] = {
* Samsung pinctrl driver data for Exynos5260 SoC. Exynos5260 SoC includes
* three gpio/pin-mux/pinconfig controllers.
*/
-struct samsung_pin_ctrl exynos5260_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos5260_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = exynos5260_pin_banks0,
.nr_banks = ARRAY_SIZE(exynos5260_pin_banks0),
.eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init,
- .label = "exynos5260-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos5260_pin_banks1,
.nr_banks = ARRAY_SIZE(exynos5260_pin_banks1),
.eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos5260-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos5260_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos5260_pin_banks2),
.eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos5260-gpio-ctrl2",
},
};
/* pin banks of exynos5420 pin-controller 0 */
-static struct samsung_pin_bank exynos5420_pin_banks0[] = {
+static const struct samsung_pin_bank_data exynos5420_pin_banks0[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpy7", 0x00),
EXYNOS_PIN_BANK_EINTW(8, 0xC00, "gpx0", 0x00),
EXYNOS_PIN_BANK_EINTW(8, 0xC20, "gpx1", 0x04),
@@ -1094,7 +1160,7 @@ static struct samsung_pin_bank exynos5420_pin_banks0[] = {
};
/* pin banks of exynos5420 pin-controller 1 */
-static struct samsung_pin_bank exynos5420_pin_banks1[] = {
+static const struct samsung_pin_bank_data exynos5420_pin_banks1[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpc0", 0x00),
EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc1", 0x04),
EXYNOS_PIN_BANK_EINTG(7, 0x040, "gpc2", 0x08),
@@ -1111,7 +1177,7 @@ static struct samsung_pin_bank exynos5420_pin_banks1[] = {
};
/* pin banks of exynos5420 pin-controller 2 */
-static struct samsung_pin_bank exynos5420_pin_banks2[] = {
+static const struct samsung_pin_bank_data exynos5420_pin_banks2[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpe0", 0x00),
EXYNOS_PIN_BANK_EINTG(2, 0x020, "gpe1", 0x04),
EXYNOS_PIN_BANK_EINTG(6, 0x040, "gpf0", 0x08),
@@ -1123,7 +1189,7 @@ static struct samsung_pin_bank exynos5420_pin_banks2[] = {
};
/* pin banks of exynos5420 pin-controller 3 */
-static struct samsung_pin_bank exynos5420_pin_banks3[] = {
+static const struct samsung_pin_bank_data exynos5420_pin_banks3[] __initconst = {
EXYNOS_PIN_BANK_EINTG(8, 0x000, "gpa0", 0x00),
EXYNOS_PIN_BANK_EINTG(6, 0x020, "gpa1", 0x04),
EXYNOS_PIN_BANK_EINTG(8, 0x040, "gpa2", 0x08),
@@ -1136,7 +1202,7 @@ static struct samsung_pin_bank exynos5420_pin_banks3[] = {
};
/* pin banks of exynos5420 pin-controller 4 */
-static struct samsung_pin_bank exynos5420_pin_banks4[] = {
+static const struct samsung_pin_bank_data exynos5420_pin_banks4[] __initconst = {
EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpz", 0x00),
};
@@ -1144,37 +1210,137 @@ static struct samsung_pin_bank exynos5420_pin_banks4[] = {
* Samsung pinctrl driver data for Exynos5420 SoC. Exynos5420 SoC includes
* four gpio/pin-mux/pinconfig controllers.
*/
-struct samsung_pin_ctrl exynos5420_pin_ctrl[] = {
+const struct samsung_pin_ctrl exynos5420_pin_ctrl[] __initconst = {
{
/* pin-controller instance 0 data */
.pin_banks = exynos5420_pin_banks0,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks0),
.eint_gpio_init = exynos_eint_gpio_init,
.eint_wkup_init = exynos_eint_wkup_init,
- .label = "exynos5420-gpio-ctrl0",
}, {
/* pin-controller instance 1 data */
.pin_banks = exynos5420_pin_banks1,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks1),
.eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos5420-gpio-ctrl1",
}, {
/* pin-controller instance 2 data */
.pin_banks = exynos5420_pin_banks2,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks2),
.eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos5420-gpio-ctrl2",
}, {
/* pin-controller instance 3 data */
.pin_banks = exynos5420_pin_banks3,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks3),
.eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos5420-gpio-ctrl3",
}, {
/* pin-controller instance 4 data */
.pin_banks = exynos5420_pin_banks4,
.nr_banks = ARRAY_SIZE(exynos5420_pin_banks4),
.eint_gpio_init = exynos_eint_gpio_init,
- .label = "exynos5420-gpio-ctrl4",
+ },
+};
+
+/* pin banks of exynos7 pin-controller - ALIVE */
+static const struct samsung_pin_bank_data exynos7_pin_banks0[] __initconst = {
+ EXYNOS_PIN_BANK_EINTW(8, 0x000, "gpa0", 0x00),
+ EXYNOS_PIN_BANK_EINTW(8, 0x020, "gpa1", 0x04),
+ EXYNOS_PIN_BANK_EINTW(8, 0x040, "gpa2", 0x08),
+ EXYNOS_PIN_BANK_EINTW(8, 0x060, "gpa3", 0x0c),
+};
+
+/* pin banks of exynos7 pin-controller - BUS0 */
+static const struct samsung_pin_bank_data exynos7_pin_banks1[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpb0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpc0", 0x04),
+ EXYNOS_PIN_BANK_EINTG(2, 0x040, "gpc1", 0x08),
+ EXYNOS_PIN_BANK_EINTG(6, 0x060, "gpc2", 0x0c),
+ EXYNOS_PIN_BANK_EINTG(8, 0x080, "gpc3", 0x10),
+ EXYNOS_PIN_BANK_EINTG(4, 0x0a0, "gpd0", 0x14),
+ EXYNOS_PIN_BANK_EINTG(6, 0x0c0, "gpd1", 0x18),
+ EXYNOS_PIN_BANK_EINTG(8, 0x0e0, "gpd2", 0x1c),
+ EXYNOS_PIN_BANK_EINTG(5, 0x100, "gpd4", 0x20),
+ EXYNOS_PIN_BANK_EINTG(4, 0x120, "gpd5", 0x24),
+ EXYNOS_PIN_BANK_EINTG(6, 0x140, "gpd6", 0x28),
+ EXYNOS_PIN_BANK_EINTG(3, 0x160, "gpd7", 0x2c),
+ EXYNOS_PIN_BANK_EINTG(2, 0x180, "gpd8", 0x30),
+ EXYNOS_PIN_BANK_EINTG(2, 0x1a0, "gpg0", 0x34),
+ EXYNOS_PIN_BANK_EINTG(4, 0x1c0, "gpg3", 0x38),
+};
+
+/* pin banks of exynos7 pin-controller - NFC */
+static const struct samsung_pin_bank_data exynos7_pin_banks2[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj0", 0x00),
+};
+
+/* pin banks of exynos7 pin-controller - TOUCH */
+static const struct samsung_pin_bank_data exynos7_pin_banks3[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(3, 0x000, "gpj1", 0x00),
+};
+
+/* pin banks of exynos7 pin-controller - FF */
+static const struct samsung_pin_bank_data exynos7_pin_banks4[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpg4", 0x00),
+};
+
+/* pin banks of exynos7 pin-controller - ESE */
+static const struct samsung_pin_bank_data exynos7_pin_banks5[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(5, 0x000, "gpv7", 0x00),
+};
+
+/* pin banks of exynos7 pin-controller - FSYS0 */
+static const struct samsung_pin_bank_data exynos7_pin_banks6[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(7, 0x000, "gpr4", 0x00),
+};
+
+/* pin banks of exynos7 pin-controller - FSYS1 */
+static const struct samsung_pin_bank_data exynos7_pin_banks7[] __initconst = {
+ EXYNOS_PIN_BANK_EINTG(4, 0x000, "gpr0", 0x00),
+ EXYNOS_PIN_BANK_EINTG(8, 0x020, "gpr1", 0x04),
+ EXYNOS_PIN_BANK_EINTG(5, 0x040, "gpr2", 0x08),
+ EXYNOS_PIN_BANK_EINTG(8, 0x060, "gpr3", 0x0c),
+};
+
+const struct samsung_pin_ctrl exynos7_pin_ctrl[] __initconst = {
+ {
+ /* pin-controller instance 0 Alive data */
+ .pin_banks = exynos7_pin_banks0,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks0),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ .eint_wkup_init = exynos_eint_wkup_init,
+ }, {
+ /* pin-controller instance 1 BUS0 data */
+ .pin_banks = exynos7_pin_banks1,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks1),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 2 NFC data */
+ .pin_banks = exynos7_pin_banks2,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks2),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 3 TOUCH data */
+ .pin_banks = exynos7_pin_banks3,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks3),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 4 FF data */
+ .pin_banks = exynos7_pin_banks4,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks4),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 5 ESE data */
+ .pin_banks = exynos7_pin_banks5,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks5),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 6 FSYS0 data */
+ .pin_banks = exynos7_pin_banks6,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks6),
+ .eint_gpio_init = exynos_eint_gpio_init,
+ }, {
+ /* pin-controller instance 7 FSYS1 data */
+ .pin_banks = exynos7_pin_banks7,
+ .nr_banks = ARRAY_SIZE(exynos7_pin_banks7),
+ .eint_gpio_init = exynos_eint_gpio_init,
},
};
diff --git a/drivers/pinctrl/samsung/pinctrl-exynos.h b/drivers/pinctrl/samsung/pinctrl-exynos.h
index 3c91c35..0f0f7ce 100644
--- a/drivers/pinctrl/samsung/pinctrl-exynos.h
+++ b/drivers/pinctrl/samsung/pinctrl-exynos.h
@@ -25,6 +25,9 @@
#define EXYNOS_WKUP_ECON_OFFSET 0xE00
#define EXYNOS_WKUP_EMASK_OFFSET 0xF00
#define EXYNOS_WKUP_EPEND_OFFSET 0xF40
+#define EXYNOS7_WKUP_ECON_OFFSET 0x700
+#define EXYNOS7_WKUP_EMASK_OFFSET 0x900
+#define EXYNOS7_WKUP_EPEND_OFFSET 0xA00
#define EXYNOS_SVC_OFFSET 0xB08
#define EXYNOS_EINT_FUNC 0xF
diff --git a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c
index ad3eaad..f1993f42 100644
--- a/drivers/pinctrl/samsung/pinctrl-s3c24xx.c
+++ b/drivers/pinctrl/samsung/pinctrl-s3c24xx.c
@@ -44,12 +44,12 @@
#define EINT_EDGE_BOTH 6
#define EINT_MASK 0xf
-static struct samsung_pin_bank_type bank_type_1bit = {
+static const struct samsung_pin_bank_type bank_type_1bit = {
.fld_width = { 1, 1, },
.reg_offset = { 0x00, 0x04, },
};
-static struct samsung_pin_bank_type bank_type_2bit = {
+static const struct samsung_pin_bank_type bank_type_2bit = {
.fld_width = { 2, 1, 2, },
.reg_offset = { 0x00, 0x04, 0x08, },
};
@@ -143,7 +143,7 @@ static void s3c24xx_eint_set_handler(unsigned int irq, unsigned int type)
static void s3c24xx_eint_set_function(struct samsung_pinctrl_drv_data *d,
struct samsung_pin_bank *bank, int pin)
{
- struct samsung_pin_bank_type *bank_type = bank->type;
+ const struct samsung_pin_bank_type *bank_type = bank->type;
unsigned long flags;
void __iomem *reg;
u8 shift;
@@ -518,8 +518,8 @@ static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d)
irq_set_handler_data(irq, eint_data);
}
- bank = d->ctrl->pin_banks;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ bank = d->pin_banks;
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
struct s3c24xx_eint_domain_data *ddata;
unsigned int mask;
unsigned int irq;
@@ -561,7 +561,7 @@ static int s3c24xx_eint_init(struct samsung_pinctrl_drv_data *d)
return 0;
}
-static struct samsung_pin_bank s3c2412_pin_banks[] = {
+static const struct samsung_pin_bank_data s3c2412_pin_banks[] __initconst = {
PIN_BANK_A(23, 0x000, "gpa"),
PIN_BANK_2BIT(11, 0x010, "gpb"),
PIN_BANK_2BIT(16, 0x020, "gpc"),
@@ -573,16 +573,15 @@ static struct samsung_pin_bank s3c2412_pin_banks[] = {
PIN_BANK_2BIT(13, 0x080, "gpj"),
};
-struct samsung_pin_ctrl s3c2412_pin_ctrl[] = {
+const struct samsung_pin_ctrl s3c2412_pin_ctrl[] __initconst = {
{
.pin_banks = s3c2412_pin_banks,
.nr_banks = ARRAY_SIZE(s3c2412_pin_banks),
.eint_wkup_init = s3c24xx_eint_init,
- .label = "S3C2412-GPIO",
},
};
-static struct samsung_pin_bank s3c2416_pin_banks[] = {
+static const struct samsung_pin_bank_data s3c2416_pin_banks[] __initconst = {
PIN_BANK_A(27, 0x000, "gpa"),
PIN_BANK_2BIT(11, 0x010, "gpb"),
PIN_BANK_2BIT(16, 0x020, "gpc"),
@@ -596,16 +595,15 @@ static struct samsung_pin_bank s3c2416_pin_banks[] = {
PIN_BANK_2BIT(2, 0x100, "gpm"),
};
-struct samsung_pin_ctrl s3c2416_pin_ctrl[] = {
+const struct samsung_pin_ctrl s3c2416_pin_ctrl[] __initconst = {
{
.pin_banks = s3c2416_pin_banks,
.nr_banks = ARRAY_SIZE(s3c2416_pin_banks),
.eint_wkup_init = s3c24xx_eint_init,
- .label = "S3C2416-GPIO",
},
};
-static struct samsung_pin_bank s3c2440_pin_banks[] = {
+static const struct samsung_pin_bank_data s3c2440_pin_banks[] __initconst = {
PIN_BANK_A(25, 0x000, "gpa"),
PIN_BANK_2BIT(11, 0x010, "gpb"),
PIN_BANK_2BIT(16, 0x020, "gpc"),
@@ -617,16 +615,15 @@ static struct samsung_pin_bank s3c2440_pin_banks[] = {
PIN_BANK_2BIT(13, 0x0d0, "gpj"),
};
-struct samsung_pin_ctrl s3c2440_pin_ctrl[] = {
+const struct samsung_pin_ctrl s3c2440_pin_ctrl[] __initconst = {
{
.pin_banks = s3c2440_pin_banks,
.nr_banks = ARRAY_SIZE(s3c2440_pin_banks),
.eint_wkup_init = s3c24xx_eint_init,
- .label = "S3C2440-GPIO",
},
};
-static struct samsung_pin_bank s3c2450_pin_banks[] = {
+static const struct samsung_pin_bank_data s3c2450_pin_banks[] __initconst = {
PIN_BANK_A(28, 0x000, "gpa"),
PIN_BANK_2BIT(11, 0x010, "gpb"),
PIN_BANK_2BIT(16, 0x020, "gpc"),
@@ -641,11 +638,10 @@ static struct samsung_pin_bank s3c2450_pin_banks[] = {
PIN_BANK_2BIT(2, 0x100, "gpm"),
};
-struct samsung_pin_ctrl s3c2450_pin_ctrl[] = {
+const struct samsung_pin_ctrl s3c2450_pin_ctrl[] __initconst = {
{
.pin_banks = s3c2450_pin_banks,
.nr_banks = ARRAY_SIZE(s3c2450_pin_banks),
.eint_wkup_init = s3c24xx_eint_init,
- .label = "S3C2450-GPIO",
},
};
diff --git a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c
index 89143c9..7756c1e 100644
--- a/drivers/pinctrl/samsung/pinctrl-s3c64xx.c
+++ b/drivers/pinctrl/samsung/pinctrl-s3c64xx.c
@@ -68,32 +68,32 @@
#define EINT_CON_MASK 0xF
#define EINT_CON_LEN 4
-static struct samsung_pin_bank_type bank_type_4bit_off = {
+static const struct samsung_pin_bank_type bank_type_4bit_off = {
.fld_width = { 4, 1, 2, 0, 2, 2, },
.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
};
-static struct samsung_pin_bank_type bank_type_4bit_alive = {
+static const struct samsung_pin_bank_type bank_type_4bit_alive = {
.fld_width = { 4, 1, 2, },
.reg_offset = { 0x00, 0x04, 0x08, },
};
-static struct samsung_pin_bank_type bank_type_4bit2_off = {
+static const struct samsung_pin_bank_type bank_type_4bit2_off = {
.fld_width = { 4, 1, 2, 0, 2, 2, },
.reg_offset = { 0x00, 0x08, 0x0c, 0, 0x10, 0x14, },
};
-static struct samsung_pin_bank_type bank_type_4bit2_alive = {
+static const struct samsung_pin_bank_type bank_type_4bit2_alive = {
.fld_width = { 4, 1, 2, },
.reg_offset = { 0x00, 0x08, 0x0c, },
};
-static struct samsung_pin_bank_type bank_type_2bit_off = {
+static const struct samsung_pin_bank_type bank_type_2bit_off = {
.fld_width = { 2, 1, 2, 0, 2, 2, },
.reg_offset = { 0x00, 0x04, 0x08, 0, 0x0c, 0x10, },
};
-static struct samsung_pin_bank_type bank_type_2bit_alive = {
+static const struct samsung_pin_bank_type bank_type_2bit_alive = {
.fld_width = { 2, 1, 2, },
.reg_offset = { 0x00, 0x04, 0x08, },
};
@@ -272,7 +272,7 @@ static void s3c64xx_irq_set_handler(unsigned int irq, unsigned int type)
static void s3c64xx_irq_set_function(struct samsung_pinctrl_drv_data *d,
struct samsung_pin_bank *bank, int pin)
{
- struct samsung_pin_bank_type *bank_type = bank->type;
+ const struct samsung_pin_bank_type *bank_type = bank->type;
unsigned long flags;
void __iomem *reg;
u8 shift;
@@ -468,8 +468,8 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
}
nr_domains = 0;
- bank = d->ctrl->pin_banks;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ bank = d->pin_banks;
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
unsigned int nr_eints;
unsigned int mask;
@@ -497,9 +497,9 @@ static int s3c64xx_eint_gpio_init(struct samsung_pinctrl_drv_data *d)
}
data->drvdata = d;
- bank = d->ctrl->pin_banks;
+ bank = d->pin_banks;
nr_domains = 0;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
if (bank->eint_type != EINT_TYPE_GPIO)
continue;
@@ -735,8 +735,8 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
irq_set_handler_data(irq, data);
}
- bank = d->ctrl->pin_banks;
- for (i = 0; i < d->ctrl->nr_banks; ++i, ++bank) {
+ bank = d->pin_banks;
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
struct s3c64xx_eint0_domain_data *ddata;
unsigned int nr_eints;
unsigned int mask;
@@ -780,7 +780,7 @@ static int s3c64xx_eint_eint0_init(struct samsung_pinctrl_drv_data *d)
}
/* pin banks of s3c64xx pin-controller 0 */
-static struct samsung_pin_bank s3c64xx_pin_banks0[] = {
+static const struct samsung_pin_bank_data s3c64xx_pin_banks0[] __initconst = {
PIN_BANK_4BIT_EINTG(8, 0x000, "gpa", 0),
PIN_BANK_4BIT_EINTG(7, 0x020, "gpb", 8),
PIN_BANK_4BIT_EINTG(8, 0x040, "gpc", 16),
@@ -804,13 +804,12 @@ static struct samsung_pin_bank s3c64xx_pin_banks0[] = {
* Samsung pinctrl driver data for S3C64xx SoC. S3C64xx SoC includes
* one gpio/pin-mux/pinconfig controller.
*/
-struct samsung_pin_ctrl s3c64xx_pin_ctrl[] = {
+const struct samsung_pin_ctrl s3c64xx_pin_ctrl[] __initconst = {
{
/* pin-controller instance 1 data */
.pin_banks = s3c64xx_pin_banks0,
.nr_banks = ARRAY_SIZE(s3c64xx_pin_banks0),
.eint_gpio_init = s3c64xx_eint_gpio_init,
.eint_wkup_init = s3c64xx_eint_eint0_init,
- .label = "S3C64xx-GPIO",
},
};
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.c b/drivers/pinctrl/samsung/pinctrl-samsung.c
index 2d37c8f..32940a0 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.c
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.c
@@ -349,7 +349,7 @@ static void pin_to_reg_bank(struct samsung_pinctrl_drv_data *drvdata,
{
struct samsung_pin_bank *b;
- b = drvdata->ctrl->pin_banks;
+ b = drvdata->pin_banks;
while ((pin >= b->pin_base) &&
((b->pin_base + b->nr_pins - 1) < pin))
@@ -366,7 +366,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
unsigned group, bool enable)
{
struct samsung_pinctrl_drv_data *drvdata;
- struct samsung_pin_bank_type *type;
+ const struct samsung_pin_bank_type *type;
struct samsung_pin_bank *bank;
void __iomem *reg;
u32 mask, shift, data, pin_offset;
@@ -378,7 +378,7 @@ static void samsung_pinmux_setup(struct pinctrl_dev *pctldev, unsigned selector,
func = &drvdata->pmx_functions[selector];
grp = &drvdata->pin_groups[group];
- pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->ctrl->base,
+ pin_to_reg_bank(drvdata, grp->pins[0] - drvdata->pin_base,
&reg, &pin_offset, &bank);
type = bank->type;
mask = (1 << type->fld_width[PINCFG_TYPE_FUNC]) - 1;
@@ -422,7 +422,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long *config, bool set)
{
struct samsung_pinctrl_drv_data *drvdata;
- struct samsung_pin_bank_type *type;
+ const struct samsung_pin_bank_type *type;
struct samsung_pin_bank *bank;
void __iomem *reg_base;
enum pincfg_type cfg_type = PINCFG_UNPACK_TYPE(*config);
@@ -431,7 +431,7 @@ static int samsung_pinconf_rw(struct pinctrl_dev *pctldev, unsigned int pin,
unsigned long flags;
drvdata = pinctrl_dev_get_drvdata(pctldev);
- pin_to_reg_bank(drvdata, pin - drvdata->ctrl->base, &reg_base,
+ pin_to_reg_bank(drvdata, pin - drvdata->pin_base, &reg_base,
&pin_offset, &bank);
type = bank->type;
@@ -528,7 +528,7 @@ static const struct pinconf_ops samsung_pinconf_ops = {
static void samsung_gpio_set(struct gpio_chip *gc, unsigned offset, int value)
{
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
- struct samsung_pin_bank_type *type = bank->type;
+ const struct samsung_pin_bank_type *type = bank->type;
unsigned long flags;
void __iomem *reg;
u32 data;
@@ -552,7 +552,7 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
void __iomem *reg;
u32 data;
struct samsung_pin_bank *bank = gc_to_pin_bank(gc);
- struct samsung_pin_bank_type *type = bank->type;
+ const struct samsung_pin_bank_type *type = bank->type;
reg = bank->drvdata->virt_base + bank->pctl_offset;
@@ -569,7 +569,7 @@ static int samsung_gpio_get(struct gpio_chip *gc, unsigned offset)
static int samsung_gpio_set_direction(struct gpio_chip *gc,
unsigned offset, bool input)
{
- struct samsung_pin_bank_type *type;
+ const struct samsung_pin_bank_type *type;
struct samsung_pin_bank *bank;
struct samsung_pinctrl_drv_data *drvdata;
void __iomem *reg;
@@ -834,32 +834,32 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
ctrldesc->confops = &samsung_pinconf_ops;
pindesc = devm_kzalloc(&pdev->dev, sizeof(*pindesc) *
- drvdata->ctrl->nr_pins, GFP_KERNEL);
+ drvdata->nr_pins, GFP_KERNEL);
if (!pindesc) {
dev_err(&pdev->dev, "mem alloc for pin descriptors failed\n");
return -ENOMEM;
}
ctrldesc->pins = pindesc;
- ctrldesc->npins = drvdata->ctrl->nr_pins;
+ ctrldesc->npins = drvdata->nr_pins;
/* dynamically populate the pin number and pin name for pindesc */
for (pin = 0, pdesc = pindesc; pin < ctrldesc->npins; pin++, pdesc++)
- pdesc->number = pin + drvdata->ctrl->base;
+ pdesc->number = pin + drvdata->pin_base;
/*
* allocate space for storing the dynamically generated names for all
* the pins which belong to this pin-controller.
*/
pin_names = devm_kzalloc(&pdev->dev, sizeof(char) * PIN_NAME_LENGTH *
- drvdata->ctrl->nr_pins, GFP_KERNEL);
+ drvdata->nr_pins, GFP_KERNEL);
if (!pin_names) {
dev_err(&pdev->dev, "mem alloc for pin names failed\n");
return -ENOMEM;
}
/* for each pin, the name of the pin is pin-bank name + pin number */
- for (bank = 0; bank < drvdata->ctrl->nr_banks; bank++) {
- pin_bank = &drvdata->ctrl->pin_banks[bank];
+ for (bank = 0; bank < drvdata->nr_banks; bank++) {
+ pin_bank = &drvdata->pin_banks[bank];
for (pin = 0; pin < pin_bank->nr_pins; pin++) {
sprintf(pin_names, "%s-%d", pin_bank->name, pin);
pdesc = pindesc + pin_bank->pin_base + pin;
@@ -878,11 +878,11 @@ static int samsung_pinctrl_register(struct platform_device *pdev,
return -EINVAL;
}
- for (bank = 0; bank < drvdata->ctrl->nr_banks; ++bank) {
- pin_bank = &drvdata->ctrl->pin_banks[bank];
+ for (bank = 0; bank < drvdata->nr_banks; ++bank) {
+ pin_bank = &drvdata->pin_banks[bank];
pin_bank->grange.name = pin_bank->name;
pin_bank->grange.id = bank;
- pin_bank->grange.pin_base = drvdata->ctrl->base
+ pin_bank->grange.pin_base = drvdata->pin_base
+ pin_bank->pin_base;
pin_bank->grange.base = pin_bank->gpio_chip.base;
pin_bank->grange.npins = pin_bank->gpio_chip.ngpio;
@@ -918,17 +918,16 @@ static const struct gpio_chip samsung_gpiolib_chip = {
static int samsung_gpiolib_register(struct platform_device *pdev,
struct samsung_pinctrl_drv_data *drvdata)
{
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
+ struct samsung_pin_bank *bank = drvdata->pin_banks;
struct gpio_chip *gc;
int ret;
int i;
- for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+ for (i = 0; i < drvdata->nr_banks; ++i, ++bank) {
bank->gpio_chip = samsung_gpiolib_chip;
gc = &bank->gpio_chip;
- gc->base = ctrl->base + bank->pin_base;
+ gc->base = drvdata->pin_base + bank->pin_base;
gc->ngpio = bank->nr_pins;
gc->dev = &pdev->dev;
gc->of_node = bank->of_node;
@@ -954,51 +953,70 @@ fail:
static int samsung_gpiolib_unregister(struct platform_device *pdev,
struct samsung_pinctrl_drv_data *drvdata)
{
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
- struct samsung_pin_bank *bank = ctrl->pin_banks;
+ struct samsung_pin_bank *bank = drvdata->pin_banks;
int i;
- for (i = 0; i < ctrl->nr_banks; ++i, ++bank)
+ for (i = 0; i < drvdata->nr_banks; ++i, ++bank)
gpiochip_remove(&bank->gpio_chip);
+
return 0;
}
static const struct of_device_id samsung_pinctrl_dt_match[];
/* retrieve the soc specific data */
-static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
- struct samsung_pinctrl_drv_data *d,
- struct platform_device *pdev)
+static const struct samsung_pin_ctrl *
+samsung_pinctrl_get_soc_data(struct samsung_pinctrl_drv_data *d,
+ struct platform_device *pdev)
{
int id;
const struct of_device_id *match;
struct device_node *node = pdev->dev.of_node;
struct device_node *np;
- struct samsung_pin_ctrl *ctrl;
+ const struct samsung_pin_bank_data *bdata;
+ const struct samsung_pin_ctrl *ctrl;
struct samsung_pin_bank *bank;
int i;
id = of_alias_get_id(node, "pinctrl");
if (id < 0) {
dev_err(&pdev->dev, "failed to get alias id\n");
- return NULL;
+ return ERR_PTR(-ENOENT);
}
match = of_match_node(samsung_pinctrl_dt_match, node);
ctrl = (struct samsung_pin_ctrl *)match->data + id;
- bank = ctrl->pin_banks;
- for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+ d->suspend = ctrl->suspend;
+ d->resume = ctrl->resume;
+ d->nr_banks = ctrl->nr_banks;
+ d->pin_banks = devm_kcalloc(&pdev->dev, d->nr_banks,
+ sizeof(*d->pin_banks), GFP_KERNEL);
+ if (!d->pin_banks)
+ return ERR_PTR(-ENOMEM);
+
+ bank = d->pin_banks;
+ bdata = ctrl->pin_banks;
+ for (i = 0; i < ctrl->nr_banks; ++i, ++bdata, ++bank) {
+ bank->type = bdata->type;
+ bank->pctl_offset = bdata->pctl_offset;
+ bank->nr_pins = bdata->nr_pins;
+ bank->eint_func = bdata->eint_func;
+ bank->eint_type = bdata->eint_type;
+ bank->eint_mask = bdata->eint_mask;
+ bank->eint_offset = bdata->eint_offset;
+ bank->name = bdata->name;
+
spin_lock_init(&bank->slock);
bank->drvdata = d;
- bank->pin_base = ctrl->nr_pins;
- ctrl->nr_pins += bank->nr_pins;
+ bank->pin_base = d->nr_pins;
+ d->nr_pins += bank->nr_pins;
}
for_each_child_of_node(node, np) {
if (!of_find_property(np, "gpio-controller", NULL))
continue;
- bank = ctrl->pin_banks;
- for (i = 0; i < ctrl->nr_banks; ++i, ++bank) {
+ bank = d->pin_banks;
+ for (i = 0; i < d->nr_banks; ++i, ++bank) {
if (!strcmp(bank->name, np->name)) {
bank->of_node = np;
break;
@@ -1006,8 +1024,8 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
}
}
- ctrl->base = pin_base;
- pin_base += ctrl->nr_pins;
+ d->pin_base = pin_base;
+ pin_base += d->nr_pins;
return ctrl;
}
@@ -1015,8 +1033,8 @@ static struct samsung_pin_ctrl *samsung_pinctrl_get_soc_data(
static int samsung_pinctrl_probe(struct platform_device *pdev)
{
struct samsung_pinctrl_drv_data *drvdata;
+ const struct samsung_pin_ctrl *ctrl;
struct device *dev = &pdev->dev;
- struct samsung_pin_ctrl *ctrl;
struct resource *res;
int ret;
@@ -1033,11 +1051,10 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
}
ctrl = samsung_pinctrl_get_soc_data(drvdata, pdev);
- if (!ctrl) {
+ if (IS_ERR(ctrl)) {
dev_err(&pdev->dev, "driver data not available\n");
- return -EINVAL;
+ return PTR_ERR(ctrl);
}
- drvdata->ctrl = ctrl;
drvdata->dev = dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
@@ -1082,16 +1099,14 @@ static int samsung_pinctrl_probe(struct platform_device *pdev)
static void samsung_pinctrl_suspend_dev(
struct samsung_pinctrl_drv_data *drvdata)
{
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
void __iomem *virt_base = drvdata->virt_base;
int i;
- for (i = 0; i < ctrl->nr_banks; i++) {
- struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
+ for (i = 0; i < drvdata->nr_banks; i++) {
+ struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
void __iomem *reg = virt_base + bank->pctl_offset;
-
- u8 *offs = bank->type->reg_offset;
- u8 *widths = bank->type->fld_width;
+ const u8 *offs = bank->type->reg_offset;
+ const u8 *widths = bank->type->fld_width;
enum pincfg_type type;
/* Registers without a powerdown config aren't lost */
@@ -1116,8 +1131,8 @@ static void samsung_pinctrl_suspend_dev(
}
}
- if (ctrl->suspend)
- ctrl->suspend(drvdata);
+ if (drvdata->suspend)
+ drvdata->suspend(drvdata);
}
/**
@@ -1130,19 +1145,17 @@ static void samsung_pinctrl_suspend_dev(
*/
static void samsung_pinctrl_resume_dev(struct samsung_pinctrl_drv_data *drvdata)
{
- struct samsung_pin_ctrl *ctrl = drvdata->ctrl;
void __iomem *virt_base = drvdata->virt_base;
int i;
- if (ctrl->resume)
- ctrl->resume(drvdata);
+ if (drvdata->resume)
+ drvdata->resume(drvdata);
- for (i = 0; i < ctrl->nr_banks; i++) {
- struct samsung_pin_bank *bank = &ctrl->pin_banks[i];
+ for (i = 0; i < drvdata->nr_banks; i++) {
+ struct samsung_pin_bank *bank = &drvdata->pin_banks[i];
void __iomem *reg = virt_base + bank->pctl_offset;
-
- u8 *offs = bank->type->reg_offset;
- u8 *widths = bank->type->fld_width;
+ const u8 *offs = bank->type->reg_offset;
+ const u8 *widths = bank->type->fld_width;
enum pincfg_type type;
/* Registers without a powerdown config aren't lost */
@@ -1218,6 +1231,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = (void *)exynos4210_pin_ctrl },
{ .compatible = "samsung,exynos4x12-pinctrl",
.data = (void *)exynos4x12_pin_ctrl },
+ { .compatible = "samsung,exynos4415-pinctrl",
+ .data = (void *)exynos4415_pin_ctrl },
{ .compatible = "samsung,exynos5250-pinctrl",
.data = (void *)exynos5250_pin_ctrl },
{ .compatible = "samsung,exynos5260-pinctrl",
@@ -1226,6 +1241,8 @@ static const struct of_device_id samsung_pinctrl_dt_match[] = {
.data = (void *)exynos5420_pin_ctrl },
{ .compatible = "samsung,s5pv210-pinctrl",
.data = (void *)s5pv210_pin_ctrl },
+ { .compatible = "samsung,exynos7-pinctrl",
+ .data = (void *)exynos7_pin_ctrl },
#endif
#ifdef CONFIG_PINCTRL_S3C64XX
{ .compatible = "samsung,s3c64xx-pinctrl",
diff --git a/drivers/pinctrl/samsung/pinctrl-samsung.h b/drivers/pinctrl/samsung/pinctrl-samsung.h
index 5cedc9d..1b8c013 100644
--- a/drivers/pinctrl/samsung/pinctrl-samsung.h
+++ b/drivers/pinctrl/samsung/pinctrl-samsung.h
@@ -113,39 +113,66 @@ struct samsung_pin_bank_type {
};
/**
+ * struct samsung_pin_bank_data: represent a controller pin-bank (init data).
+ * @type: type of the bank (register offsets and bitfield widths)
+ * @pctl_offset: starting offset of the pin-bank registers.
+ * @nr_pins: number of pins included in this bank.
+ * @eint_func: function to set in CON register to configure pin as EINT.
+ * @eint_type: type of the external interrupt supported by the bank.
+ * @eint_mask: bit mask of pins which support EINT function.
+ * @eint_offset: SoC-specific EINT register or interrupt offset of bank.
+ * @name: name to be prefixed for each pin in this pin bank.
+ */
+struct samsung_pin_bank_data {
+ const struct samsung_pin_bank_type *type;
+ u32 pctl_offset;
+ u8 nr_pins;
+ u8 eint_func;
+ enum eint_type eint_type;
+ u32 eint_mask;
+ u32 eint_offset;
+ const char *name;
+};
+
+/**
* struct samsung_pin_bank: represent a controller pin-bank.
* @type: type of the bank (register offsets and bitfield widths)
* @pctl_offset: starting offset of the pin-bank registers.
- * @pin_base: starting pin number of the bank.
* @nr_pins: number of pins included in this bank.
* @eint_func: function to set in CON register to configure pin as EINT.
* @eint_type: type of the external interrupt supported by the bank.
* @eint_mask: bit mask of pins which support EINT function.
+ * @eint_offset: SoC-specific EINT register or interrupt offset of bank.
* @name: name to be prefixed for each pin in this pin bank.
+ * @pin_base: starting pin number of the bank.
+ * @soc_priv: per-bank private data for SoC-specific code.
* @of_node: OF node of the bank.
* @drvdata: link to controller driver data
* @irq_domain: IRQ domain of the bank.
* @gpio_chip: GPIO chip of the bank.
* @grange: linux gpio pin range supported by this bank.
+ * @irq_chip: link to irq chip for external gpio and wakeup interrupts.
* @slock: spinlock protecting bank registers
* @pm_save: saved register values during suspend
*/
struct samsung_pin_bank {
- struct samsung_pin_bank_type *type;
+ const struct samsung_pin_bank_type *type;
u32 pctl_offset;
- u32 pin_base;
u8 nr_pins;
u8 eint_func;
enum eint_type eint_type;
u32 eint_mask;
u32 eint_offset;
- char *name;
+ const char *name;
+
+ u32 pin_base;
void *soc_priv;
struct device_node *of_node;
struct samsung_pinctrl_drv_data *drvdata;
struct irq_domain *irq_domain;
struct gpio_chip gpio_chip;
struct pinctrl_gpio_range grange;
+ struct exynos_irq_chip *irq_chip;
spinlock_t slock;
u32 pm_save[PINCFG_TYPE_NUM + 1]; /* +1 to handle double CON registers*/
@@ -155,27 +182,19 @@ struct samsung_pin_bank {
* struct samsung_pin_ctrl: represent a pin controller.
* @pin_banks: list of pin banks included in this controller.
* @nr_banks: number of pin banks.
- * @base: starting system wide pin number.
- * @nr_pins: number of pins supported by the controller.
* @eint_gpio_init: platform specific callback to setup the external gpio
* interrupts for the controller.
* @eint_wkup_init: platform specific callback to setup the external wakeup
* interrupts for the controller.
- * @label: for debug information.
*/
struct samsung_pin_ctrl {
- struct samsung_pin_bank *pin_banks;
+ const struct samsung_pin_bank_data *pin_banks;
u32 nr_banks;
- u32 base;
- u32 nr_pins;
-
int (*eint_gpio_init)(struct samsung_pinctrl_drv_data *);
int (*eint_wkup_init)(struct samsung_pinctrl_drv_data *);
void (*suspend)(struct samsung_pinctrl_drv_data *);
void (*resume)(struct samsung_pinctrl_drv_data *);
-
- char *label;
};
/**
@@ -191,6 +210,8 @@ struct samsung_pin_ctrl {
* @nr_groups: number of such pin groups.
* @pmx_functions: list of pin functions available to the driver.
* @nr_function: number of such pin functions.
+ * @pin_base: starting system wide pin number.
+ * @nr_pins: number of pins supported by the controller.
*/
struct samsung_pinctrl_drv_data {
struct list_head node;
@@ -198,7 +219,6 @@ struct samsung_pinctrl_drv_data {
struct device *dev;
int irq;
- struct samsung_pin_ctrl *ctrl;
struct pinctrl_desc pctl;
struct pinctrl_dev *pctl_dev;
@@ -206,6 +226,14 @@ struct samsung_pinctrl_drv_data {
unsigned int nr_groups;
const struct samsung_pmx_func *pmx_functions;
unsigned int nr_functions;
+
+ struct samsung_pin_bank *pin_banks;
+ u32 nr_banks;
+ unsigned int pin_base;
+ unsigned int nr_pins;
+
+ void (*suspend)(struct samsung_pinctrl_drv_data *);
+ void (*resume)(struct samsung_pinctrl_drv_data *);
};
/**
@@ -236,17 +264,19 @@ struct samsung_pmx_func {
};
/* list of all exported SoC specific data */
-extern struct samsung_pin_ctrl exynos3250_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos4210_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos5250_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos5260_pin_ctrl[];
-extern struct samsung_pin_ctrl exynos5420_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2412_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2416_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2440_pin_ctrl[];
-extern struct samsung_pin_ctrl s3c2450_pin_ctrl[];
-extern struct samsung_pin_ctrl s5pv210_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos3250_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos4210_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos4x12_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos4415_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos5250_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos5260_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos5420_pin_ctrl[];
+extern const struct samsung_pin_ctrl exynos7_pin_ctrl[];
+extern const struct samsung_pin_ctrl s3c64xx_pin_ctrl[];
+extern const struct samsung_pin_ctrl s3c2412_pin_ctrl[];
+extern const struct samsung_pin_ctrl s3c2416_pin_ctrl[];
+extern const struct samsung_pin_ctrl s3c2440_pin_ctrl[];
+extern const struct samsung_pin_ctrl s3c2450_pin_ctrl[];
+extern const struct samsung_pin_ctrl s5pv210_pin_ctrl[];
#endif /* __PINCTRL_SAMSUNG_H */
diff --git a/drivers/pinctrl/sunxi/Kconfig b/drivers/pinctrl/sunxi/Kconfig
index a5e10f7..230a952 100644
--- a/drivers/pinctrl/sunxi/Kconfig
+++ b/drivers/pinctrl/sunxi/Kconfig
@@ -39,4 +39,8 @@ config PINCTRL_SUN8I_A23_R
depends on RESET_CONTROLLER
select PINCTRL_SUNXI_COMMON
+config PINCTRL_SUN9I_A80
+ def_bool MACH_SUN9I
+ select PINCTRL_SUNXI_COMMON
+
endif
diff --git a/drivers/pinctrl/sunxi/Makefile b/drivers/pinctrl/sunxi/Makefile
index e797efb..c7d92e4 100644
--- a/drivers/pinctrl/sunxi/Makefile
+++ b/drivers/pinctrl/sunxi/Makefile
@@ -10,3 +10,4 @@ obj-$(CONFIG_PINCTRL_SUN6I_A31_R) += pinctrl-sun6i-a31-r.o
obj-$(CONFIG_PINCTRL_SUN7I_A20) += pinctrl-sun7i-a20.o
obj-$(CONFIG_PINCTRL_SUN8I_A23) += pinctrl-sun8i-a23.o
obj-$(CONFIG_PINCTRL_SUN8I_A23_R) += pinctrl-sun8i-a23-r.o
+obj-$(CONFIG_PINCTRL_SUN9I_A80) += pinctrl-sun9i-a80.o
diff --git a/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
new file mode 100644
index 0000000..adb2942
--- /dev/null
+++ b/drivers/pinctrl/sunxi/pinctrl-sun9i-a80.c
@@ -0,0 +1,749 @@
+/*
+ * Allwinner A80 SoCs pinctrl driver.
+ *
+ * Copyright (C) 2014 Maxime Ripard
+ *
+ * Maxime Ripard <maxime.ripard@free-electrons.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/of.h>
+#include <linux/of_device.h>
+#include <linux/pinctrl/pinctrl.h>
+
+#include "pinctrl-sunxi.h"
+
+static const struct sunxi_desc_pin sun9i_a80_pins[] = {
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXD3 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 0)), /* PA_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXD2 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 1)), /* PA_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXD1 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 2)), /* PA_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXD0 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 3)), /* PA_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXCK */
+ SUNXI_FUNCTION(0x4, "uart1"), /* DTR */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 4)), /* PA_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXCTL */
+ SUNXI_FUNCTION(0x4, "uart1"), /* DSR */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 5)), /* PA_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RXERR */
+ SUNXI_FUNCTION(0x4, "uart1"), /* DCD */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 6)), /* PA_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXD3 */
+ SUNXI_FUNCTION(0x4, "uart1"), /* RING */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 7)), /* PA_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXD2 */
+ SUNXI_FUNCTION(0x4, "eclk"), /* IN0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 8)), /* PA_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXEN */
+ SUNXI_FUNCTION(0x4, "eclk"), /* IN1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 9)), /* PA_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXD0 */
+ SUNXI_FUNCTION(0x4, "clk_out_a"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 10)), /* PA_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* MII-CRS */
+ SUNXI_FUNCTION(0x4, "clk_out_b"),
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 11)), /* PA_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* TXCK */
+ SUNXI_FUNCTION(0x4, "pwm3"), /* PWM_P */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 12)), /* PA_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RGMII-TXCK / GMII-TXEN */
+ SUNXI_FUNCTION(0x4, "pwm3"), /* PWM_N */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 13)), /* PA_EINT13 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* MII-TXERR */
+ SUNXI_FUNCTION(0x4, "spi1"), /* CS0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PA_EINT14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* RGMII-CLKIN / MII-COL */
+ SUNXI_FUNCTION(0x4, "spi1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PA_EINT15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* EMDC */
+ SUNXI_FUNCTION(0x4, "spi1"), /* MOSI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PA_EINT16 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(A, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "gmac"), /* EMDIO */
+ SUNXI_FUNCTION(0x4, "spi1"), /* MISO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 17)), /* PA_EINT17 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "uart3"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 5)), /* PB_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "uart3"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 1, 6)), /* PB_EINT6 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "mcsi"), /* MCLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 14)), /* PB_EINT14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "mcsi"), /* SCK */
+ SUNXI_FUNCTION(0x4, "i2c4"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 15)), /* PB_EINT15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(B, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "mcsi"), /* SDA */
+ SUNXI_FUNCTION(0x4, "i2c4"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 0, 16)), /* PB_EINT16 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* WE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MOSI */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* ALE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* MISO */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CLE */
+ SUNXI_FUNCTION(0x3, "spi0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* CE0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0")), /* RE */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RB0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* RB1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ0 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ1 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ2 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ3 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ4 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ5 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ6 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQ7 */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* D7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* DQS */
+ SUNXI_FUNCTION(0x3, "mmc2")), /* RST */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CE2 */
+ SUNXI_FUNCTION(0x3, "nand0_b")), /* RE */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "nand0"), /* CE3 */
+ SUNXI_FUNCTION(0x3, "nand0_b")), /* DQS */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(C, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "spi0")), /* CS0 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D0 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D1 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D2 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D3 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D4 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D5 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D6 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VPC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D7 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D8 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VP3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D9 */
+ SUNXI_FUNCTION(0x3, "lvds0")), /* VN3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D10 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D11 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D12 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D13 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D14 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D15 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D16 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VPC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D17 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D18 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VP3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0"), /* D19 */
+ SUNXI_FUNCTION(0x3, "lvds1")), /* VN3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D20 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D21 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 22),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D22 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 23),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* D23 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 24),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* CLK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 25),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* DE */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 26),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* HSYNC */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(D, 27),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "lcd0")), /* VSYNC */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* PCLK */
+ SUNXI_FUNCTION(0x3, "ts"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 0)), /* PE_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* MCLK */
+ SUNXI_FUNCTION(0x3, "ts"), /* ERR */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 1)), /* PE_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* HSYNC */
+ SUNXI_FUNCTION(0x3, "ts"), /* SYNC */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 2)), /* PE_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* VSYNC */
+ SUNXI_FUNCTION(0x3, "ts"), /* DVLD */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 3)), /* PE_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D0 */
+ SUNXI_FUNCTION(0x3, "spi2"), /* CS0 */
+ SUNXI_FUNCTION(0x4, "uart5"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 4)), /* PE_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D1 */
+ SUNXI_FUNCTION(0x3, "spi2"), /* CLK */
+ SUNXI_FUNCTION(0x4, "uart5"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 5)), /* PE_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D2 */
+ SUNXI_FUNCTION(0x3, "spi2"), /* MOSI */
+ SUNXI_FUNCTION(0x4, "uart5"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 6)), /* PE_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D3 */
+ SUNXI_FUNCTION(0x3, "spi2"), /* MISO */
+ SUNXI_FUNCTION(0x4, "uart5"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 7)), /* PE_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D4 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 8)), /* PE_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D5 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 9)), /* PE_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D6 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 10)), /* PE_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D7 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D3 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 11)), /* PE_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D8 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D4 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 12)), /* PE_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D9 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D5 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 13)), /* PE_EINT13 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D10 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D6 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 14)), /* PE_EINT14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* D11 */
+ SUNXI_FUNCTION(0x3, "ts"), /* D7 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 15)), /* PE_EINT15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SCK */
+ SUNXI_FUNCTION(0x3, "i2c4"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 16)), /* PE_EINT16 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(E, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "csi"), /* SDA */
+ SUNXI_FUNCTION(0x3, "i2c4"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 2, 17)), /* PE_EINT17 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* CLK */
+ SUNXI_FUNCTION(0x4, "uart0")), /* TX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0")), /* CMD */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0"), /* D3 */
+ SUNXI_FUNCTION(0x4, "uart0")), /* RX */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(F, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc0")), /* D2 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 0)), /* PG_EINT0 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* CMD */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 1)), /* PG_EINT1 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 2)), /* PG_EINT2 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 3)), /* PG_EINT3 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 4)), /* PG_EINT4 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "mmc1"), /* D3 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 5)), /* PG_EINT5 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 6)), /* PG_EINT6 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 7),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 7)), /* PG_EINT7 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 8)), /* PG_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart2"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 9)), /* PG_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c3"), /* SCK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 10)), /* PG_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c3"), /* SDA */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 11)), /* PG_EINT11 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* TX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 12)), /* PG_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* RX */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 13)), /* PG_EINT13 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* RTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 14)), /* PG_EINT14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(G, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart4"), /* CTS */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 3, 15)), /* PG_EINT15 */
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 0),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 1),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c0")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 2),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 3),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c1")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 4),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SCK */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 5),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "i2c2")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 6),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "pwm0")),
+
+ /* Hole */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 8),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "pwm1"), /* Positive */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 8)), /* PH_EINT8 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 9),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "pwm1"), /* Negative */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 9)), /* PH_EINT9 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 10),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "pwm2"), /* Positive */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 10)), /* PH_EINT10 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 11),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x3, "pwm2"), /* Negative */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 11)), /* PH_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 12),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0"), /* TX */
+ SUNXI_FUNCTION(0x3, "spi3"), /* CS2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 12)), /* PH_EINT12 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 13),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "uart0"), /* RX */
+ SUNXI_FUNCTION(0x3, "spi3"), /* CS2 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 13)), /* PH_EINT13 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 14),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi3"), /* CLK */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 14)), /* PH_EINT14 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 15),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi3"), /* MOSI */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 15)), /* PH_EINT15 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 16),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi3"), /* MISO */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 16)), /* PH_EINT16 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 17),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi3"), /* CS0 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 17)), /* PH_EINT17 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 18),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "spi3"), /* CS1 */
+ SUNXI_FUNCTION_IRQ_BANK(0x6, 4, 18)), /* PH_EINT18 */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 19),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "hdmi")), /* SCL */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 20),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "hdmi")), /* SDA */
+ SUNXI_PIN(SUNXI_PINCTRL_PIN(H, 21),
+ SUNXI_FUNCTION(0x0, "gpio_in"),
+ SUNXI_FUNCTION(0x1, "gpio_out"),
+ SUNXI_FUNCTION(0x2, "hdmi")), /* CEC */
+};
+
+static const struct sunxi_pinctrl_desc sun9i_a80_pinctrl_data = {
+ .pins = sun9i_a80_pins,
+ .npins = ARRAY_SIZE(sun9i_a80_pins),
+ .irq_banks = 5,
+};
+
+static int sun9i_a80_pinctrl_probe(struct platform_device *pdev)
+{
+ return sunxi_pinctrl_init(pdev,
+ &sun9i_a80_pinctrl_data);
+}
+
+static struct of_device_id sun9i_a80_pinctrl_match[] = {
+ { .compatible = "allwinner,sun9i-a80-pinctrl", },
+ {}
+};
+MODULE_DEVICE_TABLE(of, sun9i_a80_pinctrl_match);
+
+static struct platform_driver sun9i_a80_pinctrl_driver = {
+ .probe = sun9i_a80_pinctrl_probe,
+ .driver = {
+ .name = "sun9i-a80-pinctrl",
+ .of_match_table = sun9i_a80_pinctrl_match,
+ },
+};
+module_platform_driver(sun9i_a80_pinctrl_driver);
+
+MODULE_AUTHOR("Maxime Ripard <maxime.ripard@free-electrons.com>");
+MODULE_DESCRIPTION("Allwinner A80 pinctrl driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/pinctrl/sunxi/pinctrl-sunxi.h b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
index 4245b96..5a51523 100644
--- a/drivers/pinctrl/sunxi/pinctrl-sunxi.h
+++ b/drivers/pinctrl/sunxi/pinctrl-sunxi.h
@@ -27,6 +27,7 @@
#define PI_BASE 256
#define PL_BASE 352
#define PM_BASE 384
+#define PN_BASE 416
#define SUNXI_PINCTRL_PIN(bank, pin) \
PINCTRL_PIN(P ## bank ## _BASE + (pin), "P" #bank #pin)
diff --git a/drivers/power/reset/Kconfig b/drivers/power/reset/Kconfig
index f65ff49..028e765 100644
--- a/drivers/power/reset/Kconfig
+++ b/drivers/power/reset/Kconfig
@@ -71,6 +71,15 @@ config POWER_RESET_HISI
help
Reboot support for Hisilicon boards.
+config POWER_RESET_IMX
+ bool "IMX6 power-off driver"
+ depends on POWER_RESET && SOC_IMX6
+ help
+ This driver support power off external PMIC by PMIC_ON_REQ on i.mx6
+ boards.If you want to use other pin to control external power,please
+ say N here or disable in dts to make sure pm_power_off never be
+ overwrote wrongly by this driver.
+
config POWER_RESET_MSM
bool "Qualcomm MSM power-off driver"
depends on ARCH_QCOM
diff --git a/drivers/power/reset/Makefile b/drivers/power/reset/Makefile
index 76ce1c5..1d4804d 100644
--- a/drivers/power/reset/Makefile
+++ b/drivers/power/reset/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_POWER_RESET_BRCMSTB) += brcmstb-reboot.o
obj-$(CONFIG_POWER_RESET_GPIO) += gpio-poweroff.o
obj-$(CONFIG_POWER_RESET_GPIO_RESTART) += gpio-restart.o
obj-$(CONFIG_POWER_RESET_HISI) += hisi-reboot.o
+obj-$(CONFIG_POWER_RESET_IMX) += imx-snvs-poweroff.o
obj-$(CONFIG_POWER_RESET_MSM) += msm-poweroff.o
obj-$(CONFIG_POWER_RESET_LTC2952) += ltc2952-poweroff.o
obj-$(CONFIG_POWER_RESET_QNAP) += qnap-poweroff.o
diff --git a/drivers/power/reset/at91-reset.c b/drivers/power/reset/at91-reset.c
index 3cb3669..69a75d99 100644
--- a/drivers/power/reset/at91-reset.c
+++ b/drivers/power/reset/at91-reset.c
@@ -19,8 +19,8 @@
#include <asm/system_misc.h>
-#include <mach/at91sam9_ddrsdr.h>
-#include <mach/at91sam9_sdramc.h>
+#include <soc/at91/at91sam9_ddrsdr.h>
+#include <soc/at91/at91sam9_sdramc.h>
#define AT91_RSTC_CR 0x00 /* Reset Controller Control Register */
#define AT91_RSTC_PROCRST BIT(0) /* Processor Reset */
diff --git a/drivers/power/reset/imx-snvs-poweroff.c b/drivers/power/reset/imx-snvs-poweroff.c
new file mode 100644
index 0000000..ad6ce50
--- /dev/null
+++ b/drivers/power/reset/imx-snvs-poweroff.c
@@ -0,0 +1,66 @@
+/* Power off driver for i.mx6
+ * Copyright (c) 2014, FREESCALE CORPORATION. All rights reserved.
+ *
+ * based on msm-poweroff.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 and
+ * only version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#include <linux/err.h>
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+
+static void __iomem *snvs_base;
+
+static void do_imx_poweroff(void)
+{
+ u32 value = readl(snvs_base);
+
+ /* set TOP and DP_EN bit */
+ writel(value | 0x60, snvs_base);
+}
+
+static int imx_poweroff_probe(struct platform_device *pdev)
+{
+ snvs_base = of_iomap(pdev->dev.of_node, 0);
+ if (!snvs_base) {
+ dev_err(&pdev->dev, "failed to get memory\n");
+ return -ENODEV;
+ }
+
+ pm_power_off = do_imx_poweroff;
+ return 0;
+}
+
+static const struct of_device_id of_imx_poweroff_match[] = {
+ { .compatible = "fsl,sec-v4.0-poweroff", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, of_imx_poweroff_match);
+
+static struct platform_driver imx_poweroff_driver = {
+ .probe = imx_poweroff_probe,
+ .driver = {
+ .name = "imx-snvs-poweroff",
+ .of_match_table = of_match_ptr(of_imx_poweroff_match),
+ },
+};
+
+static int __init imx_poweroff_init(void)
+{
+ return platform_driver_register(&imx_poweroff_driver);
+}
+device_initcall(imx_poweroff_init);
diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig
index a7c81b5..85727ef 100644
--- a/drivers/powercap/Kconfig
+++ b/drivers/powercap/Kconfig
@@ -17,7 +17,7 @@ if POWERCAP
# Client driver configurations go here.
config INTEL_RAPL
tristate "Intel RAPL Support"
- depends on X86
+ depends on X86 && IOSF_MBI
default n
---help---
This enables support for the Intel Running Average Power Limit (RAPL)
diff --git a/drivers/powercap/intel_rapl.c b/drivers/powercap/intel_rapl.c
index 45e05b3..c71443c 100644
--- a/drivers/powercap/intel_rapl.c
+++ b/drivers/powercap/intel_rapl.c
@@ -29,6 +29,7 @@
#include <linux/sysfs.h>
#include <linux/cpu.h>
#include <linux/powercap.h>
+#include <asm/iosf_mbi.h>
#include <asm/processor.h>
#include <asm/cpu_device_id.h>
@@ -70,11 +71,6 @@
#define RAPL_PRIMITIVE_DERIVED BIT(1) /* not from raw data */
#define RAPL_PRIMITIVE_DUMMY BIT(2)
-/* scale RAPL units to avoid floating point math inside kernel */
-#define POWER_UNIT_SCALE (1000000)
-#define ENERGY_UNIT_SCALE (1000000)
-#define TIME_UNIT_SCALE (1000000)
-
#define TIME_WINDOW_MAX_MSEC 40000
#define TIME_WINDOW_MIN_MSEC 250
@@ -175,9 +171,9 @@ struct rapl_package {
unsigned int id; /* physical package/socket id */
unsigned int nr_domains;
unsigned long domain_map; /* bit map of active domains */
- unsigned int power_unit_divisor;
- unsigned int energy_unit_divisor;
- unsigned int time_unit_divisor;
+ unsigned int power_unit;
+ unsigned int energy_unit;
+ unsigned int time_unit;
struct rapl_domain *domains; /* array of domains, sized at runtime */
struct powercap_zone *power_zone; /* keep track of parent zone */
int nr_cpus; /* active cpus on the package, topology info is lost during
@@ -188,6 +184,18 @@ struct rapl_package {
*/
struct list_head plist;
};
+
+struct rapl_defaults {
+ int (*check_unit)(struct rapl_package *rp, int cpu);
+ void (*set_floor_freq)(struct rapl_domain *rd, bool mode);
+ u64 (*compute_time_window)(struct rapl_package *rp, u64 val,
+ bool to_raw);
+};
+static struct rapl_defaults *rapl_defaults;
+
+/* Sideband MBI registers */
+#define IOSF_CPU_POWER_BUDGET_CTL (0x2)
+
#define PACKAGE_PLN_INT_SAVED BIT(0)
#define MAX_PRIM_NAME (32)
@@ -339,23 +347,13 @@ static int find_nr_power_limit(struct rapl_domain *rd)
static int set_domain_enable(struct powercap_zone *power_zone, bool mode)
{
struct rapl_domain *rd = power_zone_to_rapl_domain(power_zone);
- int nr_powerlimit;
if (rd->state & DOMAIN_STATE_BIOS_LOCKED)
return -EACCES;
+
get_online_cpus();
- nr_powerlimit = find_nr_power_limit(rd);
- /* here we activate/deactivate the hardware for power limiting */
rapl_write_data_raw(rd, PL1_ENABLE, mode);
- /* always enable clamp such that p-state can go below OS requested
- * range. power capping priority over guranteed frequency.
- */
- rapl_write_data_raw(rd, PL1_CLAMP, mode);
- /* some domains have pl2 */
- if (nr_powerlimit > 1) {
- rapl_write_data_raw(rd, PL2_ENABLE, mode);
- rapl_write_data_raw(rd, PL2_CLAMP, mode);
- }
+ rapl_defaults->set_floor_freq(rd, mode);
put_online_cpus();
return 0;
@@ -653,9 +651,7 @@ static void rapl_init_domains(struct rapl_package *rp)
static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
int to_raw)
{
- u64 divisor = 1;
- int scale = 1; /* scale to user friendly data without floating point */
- u64 f, y; /* fraction and exp. used for time unit */
+ u64 units = 1;
struct rapl_package *rp;
rp = find_package_by_id(package);
@@ -664,42 +660,24 @@ static u64 rapl_unit_xlate(int package, enum unit_type type, u64 value,
switch (type) {
case POWER_UNIT:
- divisor = rp->power_unit_divisor;
- scale = POWER_UNIT_SCALE;
+ units = rp->power_unit;
break;
case ENERGY_UNIT:
- scale = ENERGY_UNIT_SCALE;
- divisor = rp->energy_unit_divisor;
+ units = rp->energy_unit;
break;
case TIME_UNIT:
- divisor = rp->time_unit_divisor;
- scale = TIME_UNIT_SCALE;
- /* special processing based on 2^Y*(1+F)/4 = val/divisor, refer
- * to Intel Software Developer's manual Vol. 3a, CH 14.7.4.
- */
- if (!to_raw) {
- f = (value & 0x60) >> 5;
- y = value & 0x1f;
- value = (1 << y) * (4 + f) * scale / 4;
- return div64_u64(value, divisor);
- } else {
- do_div(value, scale);
- value *= divisor;
- y = ilog2(value);
- f = div64_u64(4 * (value - (1 << y)), 1 << y);
- value = (y & 0x1f) | ((f & 0x3) << 5);
- return value;
- }
- break;
+ return rapl_defaults->compute_time_window(rp, value, to_raw);
case ARBITRARY_UNIT:
default:
return value;
};
if (to_raw)
- return div64_u64(value * divisor, scale);
- else
- return div64_u64(value * scale, divisor);
+ return div64_u64(value, units);
+
+ value *= units;
+
+ return value;
}
/* in the order of enum rapl_primitives */
@@ -833,12 +811,18 @@ static int rapl_write_data_raw(struct rapl_domain *rd,
return 0;
}
-static const struct x86_cpu_id energy_unit_quirk_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
- {}
-};
-
-static int rapl_check_unit(struct rapl_package *rp, int cpu)
+/*
+ * Raw RAPL data stored in MSRs are in certain scales. We need to
+ * convert them into standard units based on the units reported in
+ * the RAPL unit MSRs. This is specific to CPUs as the method to
+ * calculate units differ on different CPUs.
+ * We convert the units to below format based on CPUs.
+ * i.e.
+ * energy unit: microJoules : Represented in microJoules by default
+ * power unit : microWatts : Represented in milliWatts by default
+ * time unit : microseconds: Represented in seconds by default
+ */
+static int rapl_check_unit_core(struct rapl_package *rp, int cpu)
{
u64 msr_val;
u32 value;
@@ -849,36 +833,47 @@ static int rapl_check_unit(struct rapl_package *rp, int cpu)
return -ENODEV;
}
- /* Raw RAPL data stored in MSRs are in certain scales. We need to
- * convert them into standard units based on the divisors reported in
- * the RAPL unit MSRs.
- * i.e.
- * energy unit: 1/enery_unit_divisor Joules
- * power unit: 1/power_unit_divisor Watts
- * time unit: 1/time_unit_divisor Seconds
- */
value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
- /* some CPUs have different way to calculate energy unit */
- if (x86_match_cpu(energy_unit_quirk_ids))
- rp->energy_unit_divisor = 1000000 / (1 << value);
- else
- rp->energy_unit_divisor = 1 << value;
+ rp->energy_unit = 1000000 / (1 << value);
value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
- rp->power_unit_divisor = 1 << value;
+ rp->power_unit = 1000000 / (1 << value);
value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
- rp->time_unit_divisor = 1 << value;
+ rp->time_unit = 1000000 / (1 << value);
- pr_debug("Physical package %d units: energy=%d, time=%d, power=%d\n",
- rp->id,
- rp->energy_unit_divisor,
- rp->time_unit_divisor,
- rp->power_unit_divisor);
+ pr_debug("Core CPU package %d energy=%duJ, time=%dus, power=%duW\n",
+ rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
return 0;
}
+static int rapl_check_unit_atom(struct rapl_package *rp, int cpu)
+{
+ u64 msr_val;
+ u32 value;
+
+ if (rdmsrl_safe_on_cpu(cpu, MSR_RAPL_POWER_UNIT, &msr_val)) {
+ pr_err("Failed to read power unit MSR 0x%x on CPU %d, exit.\n",
+ MSR_RAPL_POWER_UNIT, cpu);
+ return -ENODEV;
+ }
+ value = (msr_val & ENERGY_UNIT_MASK) >> ENERGY_UNIT_OFFSET;
+ rp->energy_unit = 1 << value;
+
+ value = (msr_val & POWER_UNIT_MASK) >> POWER_UNIT_OFFSET;
+ rp->power_unit = (1 << value) * 1000;
+
+ value = (msr_val & TIME_UNIT_MASK) >> TIME_UNIT_OFFSET;
+ rp->time_unit = 1000000 / (1 << value);
+
+ pr_debug("Atom package %d energy=%duJ, time=%dus, power=%duW\n",
+ rp->id, rp->energy_unit, rp->time_unit, rp->power_unit);
+
+ return 0;
+}
+
+
/* REVISIT:
* When package power limit is set artificially low by RAPL, LVT
* thermal interrupt for package power limit should be ignored
@@ -946,16 +941,107 @@ static void package_power_limit_irq_restore(int package_id)
wrmsr_on_cpu(cpu, MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
}
+static void set_floor_freq_default(struct rapl_domain *rd, bool mode)
+{
+ int nr_powerlimit = find_nr_power_limit(rd);
+
+ /* always enable clamp such that p-state can go below OS requested
+ * range. power capping priority over guranteed frequency.
+ */
+ rapl_write_data_raw(rd, PL1_CLAMP, mode);
+
+ /* some domains have pl2 */
+ if (nr_powerlimit > 1) {
+ rapl_write_data_raw(rd, PL2_ENABLE, mode);
+ rapl_write_data_raw(rd, PL2_CLAMP, mode);
+ }
+}
+
+static void set_floor_freq_atom(struct rapl_domain *rd, bool enable)
+{
+ static u32 power_ctrl_orig_val;
+ u32 mdata;
+
+ if (!power_ctrl_orig_val)
+ iosf_mbi_read(BT_MBI_UNIT_PMC, BT_MBI_PMC_READ,
+ IOSF_CPU_POWER_BUDGET_CTL, &power_ctrl_orig_val);
+ mdata = power_ctrl_orig_val;
+ if (enable) {
+ mdata &= ~(0x7f << 8);
+ mdata |= 1 << 8;
+ }
+ iosf_mbi_write(BT_MBI_UNIT_PMC, BT_MBI_PMC_WRITE,
+ IOSF_CPU_POWER_BUDGET_CTL, mdata);
+}
+
+static u64 rapl_compute_time_window_core(struct rapl_package *rp, u64 value,
+ bool to_raw)
+{
+ u64 f, y; /* fraction and exp. used for time unit */
+
+ /*
+ * Special processing based on 2^Y*(1+F/4), refer
+ * to Intel Software Developer's manual Vol.3B: CH 14.9.3.
+ */
+ if (!to_raw) {
+ f = (value & 0x60) >> 5;
+ y = value & 0x1f;
+ value = (1 << y) * (4 + f) * rp->time_unit / 4;
+ } else {
+ do_div(value, rp->time_unit);
+ y = ilog2(value);
+ f = div64_u64(4 * (value - (1 << y)), 1 << y);
+ value = (y & 0x1f) | ((f & 0x3) << 5);
+ }
+ return value;
+}
+
+static u64 rapl_compute_time_window_atom(struct rapl_package *rp, u64 value,
+ bool to_raw)
+{
+ /*
+ * Atom time unit encoding is straight forward val * time_unit,
+ * where time_unit is default to 1 sec. Never 0.
+ */
+ if (!to_raw)
+ return (value) ? value *= rp->time_unit : rp->time_unit;
+ else
+ value = div64_u64(value, rp->time_unit);
+
+ return value;
+}
+
+static const struct rapl_defaults rapl_defaults_core = {
+ .check_unit = rapl_check_unit_core,
+ .set_floor_freq = set_floor_freq_default,
+ .compute_time_window = rapl_compute_time_window_core,
+};
+
+static const struct rapl_defaults rapl_defaults_atom = {
+ .check_unit = rapl_check_unit_atom,
+ .set_floor_freq = set_floor_freq_atom,
+ .compute_time_window = rapl_compute_time_window_atom,
+};
+
+#define RAPL_CPU(_model, _ops) { \
+ .vendor = X86_VENDOR_INTEL, \
+ .family = 6, \
+ .model = _model, \
+ .driver_data = (kernel_ulong_t)&_ops, \
+ }
+
static const struct x86_cpu_id rapl_ids[] = {
- { X86_VENDOR_INTEL, 6, 0x2a},/* Sandy Bridge */
- { X86_VENDOR_INTEL, 6, 0x2d},/* Sandy Bridge EP */
- { X86_VENDOR_INTEL, 6, 0x37},/* Valleyview */
- { X86_VENDOR_INTEL, 6, 0x3a},/* Ivy Bridge */
- { X86_VENDOR_INTEL, 6, 0x3c},/* Haswell */
- { X86_VENDOR_INTEL, 6, 0x3d},/* Broadwell */
- { X86_VENDOR_INTEL, 6, 0x3f},/* Haswell */
- { X86_VENDOR_INTEL, 6, 0x45},/* Haswell ULT */
- /* TODO: Add more CPU IDs after testing */
+ RAPL_CPU(0x2a, rapl_defaults_core),/* Sandy Bridge */
+ RAPL_CPU(0x2d, rapl_defaults_core),/* Sandy Bridge EP */
+ RAPL_CPU(0x37, rapl_defaults_atom),/* Valleyview */
+ RAPL_CPU(0x3a, rapl_defaults_core),/* Ivy Bridge */
+ RAPL_CPU(0x3c, rapl_defaults_core),/* Haswell */
+ RAPL_CPU(0x3d, rapl_defaults_core),/* Broadwell */
+ RAPL_CPU(0x3f, rapl_defaults_core),/* Haswell */
+ RAPL_CPU(0x45, rapl_defaults_core),/* Haswell ULT */
+ RAPL_CPU(0x4C, rapl_defaults_atom),/* Braswell */
+ RAPL_CPU(0x4A, rapl_defaults_atom),/* Tangier */
+ RAPL_CPU(0x5A, rapl_defaults_atom),/* Annidale */
{}
};
MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
@@ -1241,7 +1327,7 @@ static int rapl_detect_topology(void)
/* check if the package contains valid domains */
if (rapl_detect_domains(new_package, i) ||
- rapl_check_unit(new_package, i)) {
+ rapl_defaults->check_unit(new_package, i)) {
kfree(new_package->domains);
kfree(new_package);
/* free up the packages already initialized */
@@ -1296,7 +1382,7 @@ static int rapl_add_package(int cpu)
rp->nr_cpus = 1;
/* check if the package contains valid domains */
if (rapl_detect_domains(rp, cpu) ||
- rapl_check_unit(rp, cpu)) {
+ rapl_defaults->check_unit(rp, cpu)) {
ret = -ENODEV;
goto err_free_package;
}
@@ -1358,14 +1444,18 @@ static struct notifier_block rapl_cpu_notifier = {
static int __init rapl_init(void)
{
int ret = 0;
+ const struct x86_cpu_id *id;
- if (!x86_match_cpu(rapl_ids)) {
+ id = x86_match_cpu(rapl_ids);
+ if (!id) {
pr_err("driver does not support CPU family %d model %d\n",
boot_cpu_data.x86, boot_cpu_data.x86_model);
return -ENODEV;
}
+ rapl_defaults = (struct rapl_defaults *)id->driver_data;
+
cpu_notifier_register_begin();
/* prevent CPU hotplug during detection */
diff --git a/drivers/regulator/88pm8607.c b/drivers/regulator/88pm8607.c
index 6d77dcd..3fe47bd 100644
--- a/drivers/regulator/88pm8607.c
+++ b/drivers/regulator/88pm8607.c
@@ -330,7 +330,8 @@ static int pm8607_regulator_dt_init(struct platform_device *pdev,
for_each_child_of_node(nproot, np) {
if (!of_node_cmp(np->name, info->desc.name)) {
config->init_data =
- of_get_regulator_init_data(&pdev->dev, np);
+ of_get_regulator_init_data(&pdev->dev, np,
+ &info->desc);
config->of_node = np;
break;
}
diff --git a/drivers/regulator/Kconfig b/drivers/regulator/Kconfig
index 55d7b7b..c3a60b5 100644
--- a/drivers/regulator/Kconfig
+++ b/drivers/regulator/Kconfig
@@ -521,6 +521,14 @@ config REGULATOR_RN5T618
help
Say y here to support the regulators found on Ricoh RN5T618 PMIC.
+config REGULATOR_RT5033
+ tristate "Richtek RT5033 Regulators"
+ depends on MFD_RT5033
+ help
+ This adds support for voltage and current regulators in Richtek
+ RT5033 PMIC. The device supports multiple regulators like
+ current source, LDO and Buck.
+
config REGULATOR_S2MPA01
tristate "Samsung S2MPA01 voltage regulator"
depends on MFD_SEC_CORE
@@ -529,13 +537,13 @@ config REGULATOR_S2MPA01
via I2C bus. S2MPA01 has 10 Bucks and 26 LDO outputs.
config REGULATOR_S2MPS11
- tristate "Samsung S2MPS11/S2MPS14/S2MPU02 voltage regulator"
+ tristate "Samsung S2MPS11/S2MPS13/S2MPS14/S2MPU02 voltage regulator"
depends on MFD_SEC_CORE
help
- This driver supports a Samsung S2MPS11/S2MPS14/S2MPU02 voltage output
- regulator via I2C bus. The chip is comprised of high efficient Buck
- converters including Dual-Phase Buck converter, Buck-Boost converter,
- various LDOs.
+ This driver supports a Samsung S2MPS11/S2MPS13/S2MPS14/S2MPU02 voltage
+ output regulator via I2C bus. The chip is comprised of high efficient
+ Buck converters including Dual-Phase Buck converter, Buck-Boost
+ converter, various LDOs.
config REGULATOR_S5M8767
tristate "Samsung S5M8767A voltage regulator"
@@ -547,7 +555,7 @@ config REGULATOR_S5M8767
config REGULATOR_SKY81452
tristate "Skyworks Solutions SKY81452 voltage regulator"
- depends on SKY81452
+ depends on MFD_SKY81452
help
This driver supports Skyworks SKY81452 voltage output regulator
via I2C bus. SKY81452 has one voltage linear regulator can be
diff --git a/drivers/regulator/Makefile b/drivers/regulator/Makefile
index 1029ed3..1f28ebf 100644
--- a/drivers/regulator/Makefile
+++ b/drivers/regulator/Makefile
@@ -69,6 +69,7 @@ obj-$(CONFIG_REGULATOR_PCF50633) += pcf50633-regulator.o
obj-$(CONFIG_REGULATOR_RC5T583) += rc5t583-regulator.o
obj-$(CONFIG_REGULATOR_RK808) += rk808-regulator.o
obj-$(CONFIG_REGULATOR_RN5T618) += rn5t618-regulator.o
+obj-$(CONFIG_REGULATOR_RT5033) += rt5033-regulator.o
obj-$(CONFIG_REGULATOR_S2MPA01) += s2mpa01.o
obj-$(CONFIG_REGULATOR_S2MPS11) += s2mps11.o
obj-$(CONFIG_REGULATOR_S5M8767) += s5m8767.o
diff --git a/drivers/regulator/act8865-regulator.c b/drivers/regulator/act8865-regulator.c
index afd06f9..9eec453 100644
--- a/drivers/regulator/act8865-regulator.c
+++ b/drivers/regulator/act8865-regulator.c
@@ -61,6 +61,8 @@
#define ACT8846_REG12_VSET 0xa0
#define ACT8846_REG12_CTRL 0xa1
#define ACT8846_REG13_CTRL 0xb1
+#define ACT8846_GLB_OFF_CTRL 0xc3
+#define ACT8846_OFF_SYSMASK 0x18
/*
* ACT8865 Global Register Map.
@@ -84,6 +86,7 @@
#define ACT8865_LDO3_CTRL 0x61
#define ACT8865_LDO4_VSET 0x64
#define ACT8865_LDO4_CTRL 0x65
+#define ACT8865_MSTROFF 0x20
/*
* Field Definitions.
@@ -98,6 +101,8 @@
struct act8865 {
struct regmap *regmap;
+ int off_reg;
+ int off_mask;
};
static const struct regmap_config act8865_regmap_config = {
@@ -275,6 +280,16 @@ static struct regulator_init_data
return NULL;
}
+static struct i2c_client *act8865_i2c_client;
+static void act8865_power_off(void)
+{
+ struct act8865 *act8865;
+
+ act8865 = i2c_get_clientdata(act8865_i2c_client);
+ regmap_write(act8865->regmap, act8865->off_reg, act8865->off_mask);
+ while (1);
+}
+
static int act8865_pmic_probe(struct i2c_client *client,
const struct i2c_device_id *i2c_id)
{
@@ -285,6 +300,7 @@ static int act8865_pmic_probe(struct i2c_client *client,
int i, ret, num_regulators;
struct act8865 *act8865;
unsigned long type;
+ int off_reg, off_mask;
pdata = dev_get_platdata(dev);
@@ -304,10 +320,14 @@ static int act8865_pmic_probe(struct i2c_client *client,
case ACT8846:
regulators = act8846_regulators;
num_regulators = ARRAY_SIZE(act8846_regulators);
+ off_reg = ACT8846_GLB_OFF_CTRL;
+ off_mask = ACT8846_OFF_SYSMASK;
break;
case ACT8865:
regulators = act8865_regulators;
num_regulators = ARRAY_SIZE(act8865_regulators);
+ off_reg = ACT8865_SYS_CTRL;
+ off_mask = ACT8865_MSTROFF;
break;
default:
dev_err(dev, "invalid device id %lu\n", type);
@@ -345,6 +365,17 @@ static int act8865_pmic_probe(struct i2c_client *client,
return ret;
}
+ if (of_device_is_system_power_controller(dev->of_node)) {
+ if (!pm_power_off) {
+ act8865_i2c_client = client;
+ act8865->off_reg = off_reg;
+ act8865->off_mask = off_mask;
+ pm_power_off = act8865_power_off;
+ } else {
+ dev_err(dev, "Failed to set poweroff capability, already defined\n");
+ }
+ }
+
/* Finally register devices */
for (i = 0; i < num_regulators; i++) {
const struct regulator_desc *desc = &regulators[i];
diff --git a/drivers/regulator/anatop-regulator.c b/drivers/regulator/anatop-regulator.c
index 4f730af..3586571 100644
--- a/drivers/regulator/anatop-regulator.c
+++ b/drivers/regulator/anatop-regulator.c
@@ -189,17 +189,18 @@ static int anatop_regulator_probe(struct platform_device *pdev)
int ret = 0;
u32 val;
- initdata = of_get_regulator_init_data(dev, np);
sreg = devm_kzalloc(dev, sizeof(*sreg), GFP_KERNEL);
if (!sreg)
return -ENOMEM;
- sreg->initdata = initdata;
sreg->name = of_get_property(np, "regulator-name", NULL);
rdesc = &sreg->rdesc;
rdesc->name = sreg->name;
rdesc->type = REGULATOR_VOLTAGE;
rdesc->owner = THIS_MODULE;
+ initdata = of_get_regulator_init_data(dev, np, rdesc);
+ sreg->initdata = initdata;
+
anatop_np = of_get_parent(np);
if (!anatop_np)
return -ENODEV;
@@ -283,6 +284,19 @@ static int anatop_regulator_probe(struct platform_device *pdev)
sreg->sel = 0;
sreg->bypass = true;
}
+
+ /*
+ * In case vddpu was disabled by the bootloader, we need to set
+ * a sane default until imx6-cpufreq was probed and changes the
+ * voltage to the correct value. In this case we set 1.25V.
+ */
+ if (!sreg->sel && !strcmp(sreg->name, "vddpu"))
+ sreg->sel = 22;
+
+ if (!sreg->sel) {
+ dev_err(&pdev->dev, "Failed to read a valid default voltage selector.\n");
+ return -EINVAL;
+ }
} else {
rdesc->ops = &anatop_rops;
}
diff --git a/drivers/regulator/arizona-ldo1.c b/drivers/regulator/arizona-ldo1.c
index 4c9db58..d071b21 100644
--- a/drivers/regulator/arizona-ldo1.c
+++ b/drivers/regulator/arizona-ldo1.c
@@ -179,7 +179,8 @@ static const struct regulator_init_data arizona_ldo1_default = {
};
static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
- struct regulator_config *config)
+ struct regulator_config *config,
+ const struct regulator_desc *desc)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_ldo1 *ldo1 = config->driver_data;
@@ -194,7 +195,8 @@ static int arizona_ldo1_of_get_pdata(struct arizona *arizona,
if (init_node) {
config->of_node = init_node;
- init_data = of_get_regulator_init_data(arizona->dev, init_node);
+ init_data = of_get_regulator_init_data(arizona->dev, init_node,
+ desc);
if (init_data) {
init_data->consumer_supplies = &ldo1->supply;
@@ -257,9 +259,11 @@ static int arizona_ldo1_probe(struct platform_device *pdev)
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
- ret = arizona_ldo1_of_get_pdata(arizona, &config);
+ ret = arizona_ldo1_of_get_pdata(arizona, &config, desc);
if (ret < 0)
return ret;
+
+ config.ena_gpio_initialized = true;
}
}
diff --git a/drivers/regulator/arizona-micsupp.c b/drivers/regulator/arizona-micsupp.c
index ce9aca5..c313ef4 100644
--- a/drivers/regulator/arizona-micsupp.c
+++ b/drivers/regulator/arizona-micsupp.c
@@ -198,7 +198,8 @@ static const struct regulator_init_data arizona_micsupp_ext_default = {
};
static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
- struct regulator_config *config)
+ struct regulator_config *config,
+ const struct regulator_desc *desc)
{
struct arizona_pdata *pdata = &arizona->pdata;
struct arizona_micsupp *micsupp = config->driver_data;
@@ -210,7 +211,7 @@ static int arizona_micsupp_of_get_pdata(struct arizona *arizona,
if (np) {
config->of_node = np;
- init_data = of_get_regulator_init_data(arizona->dev, np);
+ init_data = of_get_regulator_init_data(arizona->dev, np, desc);
if (init_data) {
init_data->consumer_supplies = &micsupp->supply;
@@ -264,7 +265,8 @@ static int arizona_micsupp_probe(struct platform_device *pdev)
if (IS_ENABLED(CONFIG_OF)) {
if (!dev_get_platdata(arizona->dev)) {
- ret = arizona_micsupp_of_get_pdata(arizona, &config);
+ ret = arizona_micsupp_of_get_pdata(arizona, &config,
+ desc);
if (ret < 0)
return ret;
}
diff --git a/drivers/regulator/core.c b/drivers/regulator/core.c
index cd87c0c..e225711 100644
--- a/drivers/regulator/core.c
+++ b/drivers/regulator/core.c
@@ -828,7 +828,7 @@ static void print_constraints(struct regulator_dev *rdev)
if (!count)
sprintf(buf, "no parameters");
- rdev_info(rdev, "%s\n", buf);
+ rdev_dbg(rdev, "%s\n", buf);
if ((constraints->min_uV != constraints->max_uV) &&
!(constraints->valid_ops_mask & REGULATOR_CHANGE_VOLTAGE))
@@ -1713,6 +1713,8 @@ static void regulator_ena_gpio_free(struct regulator_dev *rdev)
gpiod_put(pin->gpiod);
list_del(&pin->list);
kfree(pin);
+ rdev->ena_pin = NULL;
+ return;
} else {
pin->request_count--;
}
@@ -1976,9 +1978,18 @@ static int _regulator_disable(struct regulator_dev *rdev)
/* we are last user */
if (_regulator_can_change_status(rdev)) {
+ ret = _notifier_call_chain(rdev,
+ REGULATOR_EVENT_PRE_DISABLE,
+ NULL);
+ if (ret & NOTIFY_STOP_MASK)
+ return -EINVAL;
+
ret = _regulator_do_disable(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to disable\n");
+ _notifier_call_chain(rdev,
+ REGULATOR_EVENT_ABORT_DISABLE,
+ NULL);
return ret;
}
_notifier_call_chain(rdev, REGULATOR_EVENT_DISABLE,
@@ -2035,9 +2046,16 @@ static int _regulator_force_disable(struct regulator_dev *rdev)
{
int ret = 0;
+ ret = _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+ REGULATOR_EVENT_PRE_DISABLE, NULL);
+ if (ret & NOTIFY_STOP_MASK)
+ return -EINVAL;
+
ret = _regulator_do_disable(rdev);
if (ret < 0) {
rdev_err(rdev, "failed to force disable\n");
+ _notifier_call_chain(rdev, REGULATOR_EVENT_FORCE_DISABLE |
+ REGULATOR_EVENT_ABORT_DISABLE, NULL);
return ret;
}
@@ -3650,7 +3668,8 @@ regulator_register(const struct regulator_desc *regulator_desc,
dev_set_drvdata(&rdev->dev, rdev);
- if (config->ena_gpio && gpio_is_valid(config->ena_gpio)) {
+ if ((config->ena_gpio || config->ena_gpio_initialized) &&
+ gpio_is_valid(config->ena_gpio)) {
ret = regulator_ena_gpio_request(rdev, config);
if (ret != 0) {
rdev_err(rdev, "Failed to request enable GPIO%d: %d\n",
diff --git a/drivers/regulator/da9052-regulator.c b/drivers/regulator/da9052-regulator.c
index 0003362..3945f10 100644
--- a/drivers/regulator/da9052-regulator.c
+++ b/drivers/regulator/da9052-regulator.c
@@ -436,7 +436,8 @@ static int da9052_regulator_probe(struct platform_device *pdev)
if (!of_node_cmp(np->name,
regulator->info->reg_desc.name)) {
config.init_data = of_get_regulator_init_data(
- &pdev->dev, np);
+ &pdev->dev, np,
+ &regulator->info->reg_desc);
config.of_node = np;
break;
}
diff --git a/drivers/regulator/da9063-regulator.c b/drivers/regulator/da9063-regulator.c
index 7c9461d..37dd427 100644
--- a/drivers/regulator/da9063-regulator.c
+++ b/drivers/regulator/da9063-regulator.c
@@ -867,17 +867,14 @@ static int da9063_regulator_probe(struct platform_device *pdev)
return irq;
}
- regulators->irq_ldo_lim = regmap_irq_get_virq(da9063->regmap_irq, irq);
- if (regulators->irq_ldo_lim >= 0) {
- ret = request_threaded_irq(regulators->irq_ldo_lim,
- NULL, da9063_ldo_lim_event,
- IRQF_TRIGGER_LOW | IRQF_ONESHOT,
- "LDO_LIM", regulators);
- if (ret) {
- dev_err(&pdev->dev,
- "Failed to request LDO_LIM IRQ.\n");
- regulators->irq_ldo_lim = -ENXIO;
- }
+ ret = request_threaded_irq(irq,
+ NULL, da9063_ldo_lim_event,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "LDO_LIM", regulators);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Failed to request LDO_LIM IRQ.\n");
+ regulators->irq_ldo_lim = -ENXIO;
}
return 0;
diff --git a/drivers/regulator/da9210-regulator.c b/drivers/regulator/da9210-regulator.c
index 7a320dd..bc61001 100644
--- a/drivers/regulator/da9210-regulator.c
+++ b/drivers/regulator/da9210-regulator.c
@@ -147,7 +147,7 @@ static int da9210_i2c_probe(struct i2c_client *i2c,
config.dev = &i2c->dev;
config.init_data = pdata ? &pdata->da9210_constraints :
- of_get_regulator_init_data(dev, dev->of_node);
+ of_get_regulator_init_data(dev, dev->of_node, &da9210_reg);
config.driver_data = chip;
config.regmap = chip->regmap;
config.of_node = dev->of_node;
diff --git a/drivers/regulator/dummy.c b/drivers/regulator/dummy.c
index 2436db9..7aef9e4 100644
--- a/drivers/regulator/dummy.c
+++ b/drivers/regulator/dummy.c
@@ -33,7 +33,7 @@ static struct regulator_init_data dummy_initdata = {
static struct regulator_ops dummy_ops;
-static struct regulator_desc dummy_desc = {
+static const struct regulator_desc dummy_desc = {
.name = "regulator-dummy",
.id = -1,
.type = REGULATOR_VOLTAGE,
diff --git a/drivers/regulator/fan53555.c b/drivers/regulator/fan53555.c
index f8e4257..6c43ab2 100644
--- a/drivers/regulator/fan53555.c
+++ b/drivers/regulator/fan53555.c
@@ -302,7 +302,8 @@ static struct regmap_config fan53555_regmap_config = {
};
static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev,
- struct device_node *np)
+ struct device_node *np,
+ const struct regulator_desc *desc)
{
struct fan53555_platform_data *pdata;
int ret;
@@ -312,7 +313,7 @@ static struct fan53555_platform_data *fan53555_parse_dt(struct device *dev,
if (!pdata)
return NULL;
- pdata->regulator = of_get_regulator_init_data(dev, np);
+ pdata->regulator = of_get_regulator_init_data(dev, np, desc);
ret = of_property_read_u32(np, "fcs,suspend-voltage-selector",
&tmp);
@@ -347,20 +348,20 @@ static int fan53555_regulator_probe(struct i2c_client *client,
unsigned int val;
int ret;
+ di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
+ GFP_KERNEL);
+ if (!di)
+ return -ENOMEM;
+
pdata = dev_get_platdata(&client->dev);
if (!pdata)
- pdata = fan53555_parse_dt(&client->dev, np);
+ pdata = fan53555_parse_dt(&client->dev, np, &di->desc);
if (!pdata || !pdata->regulator) {
dev_err(&client->dev, "Platform data not found!\n");
return -ENODEV;
}
- di = devm_kzalloc(&client->dev, sizeof(struct fan53555_device_info),
- GFP_KERNEL);
- if (!di)
- return -ENOMEM;
-
di->regulator = pdata->regulator;
if (client->dev.of_node) {
const struct of_device_id *match;
diff --git a/drivers/regulator/fixed.c b/drivers/regulator/fixed.c
index 354105e..d21da27 100644
--- a/drivers/regulator/fixed.c
+++ b/drivers/regulator/fixed.c
@@ -40,13 +40,15 @@ struct fixed_voltage_data {
/**
* of_get_fixed_voltage_config - extract fixed_voltage_config structure info
* @dev: device requesting for fixed_voltage_config
+ * @desc: regulator description
*
* Populates fixed_voltage_config structure by extracting data from device
* tree node, returns a pointer to the populated structure of NULL if memory
* alloc fails.
*/
static struct fixed_voltage_config *
-of_get_fixed_voltage_config(struct device *dev)
+of_get_fixed_voltage_config(struct device *dev,
+ const struct regulator_desc *desc)
{
struct fixed_voltage_config *config;
struct device_node *np = dev->of_node;
@@ -57,7 +59,7 @@ of_get_fixed_voltage_config(struct device *dev)
if (!config)
return ERR_PTR(-ENOMEM);
- config->init_data = of_get_regulator_init_data(dev, dev->of_node);
+ config->init_data = of_get_regulator_init_data(dev, dev->of_node, desc);
if (!config->init_data)
return ERR_PTR(-EINVAL);
@@ -112,8 +114,14 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
struct regulator_config cfg = { };
int ret;
+ drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
+ GFP_KERNEL);
+ if (!drvdata)
+ return -ENOMEM;
+
if (pdev->dev.of_node) {
- config = of_get_fixed_voltage_config(&pdev->dev);
+ config = of_get_fixed_voltage_config(&pdev->dev,
+ &drvdata->desc);
if (IS_ERR(config))
return PTR_ERR(config);
} else {
@@ -123,11 +131,6 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
if (!config)
return -ENOMEM;
- drvdata = devm_kzalloc(&pdev->dev, sizeof(struct fixed_voltage_data),
- GFP_KERNEL);
- if (!drvdata)
- return -ENOMEM;
-
drvdata->desc.name = devm_kstrdup(&pdev->dev,
config->supply_name,
GFP_KERNEL);
@@ -157,8 +160,11 @@ static int reg_fixed_voltage_probe(struct platform_device *pdev)
drvdata->desc.fixed_uV = config->microvolts;
- if (config->gpio >= 0)
+ if (gpio_is_valid(config->gpio)) {
cfg.ena_gpio = config->gpio;
+ if (pdev->dev.of_node)
+ cfg.ena_gpio_initialized = true;
+ }
cfg.ena_gpio_invert = !config->enable_high;
if (config->enabled_at_boot) {
if (config->enable_high)
diff --git a/drivers/regulator/gpio-regulator.c b/drivers/regulator/gpio-regulator.c
index 989b23b..c888a9a 100644
--- a/drivers/regulator/gpio-regulator.c
+++ b/drivers/regulator/gpio-regulator.c
@@ -133,7 +133,8 @@ static struct regulator_ops gpio_regulator_voltage_ops = {
};
static struct gpio_regulator_config *
-of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
+of_get_gpio_regulator_config(struct device *dev, struct device_node *np,
+ const struct regulator_desc *desc)
{
struct gpio_regulator_config *config;
const char *regtype;
@@ -146,7 +147,7 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
if (!config)
return ERR_PTR(-ENOMEM);
- config->init_data = of_get_regulator_init_data(dev, np);
+ config->init_data = of_get_regulator_init_data(dev, np, desc);
if (!config->init_data)
return ERR_PTR(-EINVAL);
@@ -162,34 +163,41 @@ of_get_gpio_regulator_config(struct device *dev, struct device_node *np)
config->enable_gpio = of_get_named_gpio(np, "enable-gpio", 0);
- /* Fetch GPIOs. */
- config->nr_gpios = of_gpio_count(np);
-
- config->gpios = devm_kzalloc(dev,
- sizeof(struct gpio) * config->nr_gpios,
- GFP_KERNEL);
- if (!config->gpios)
- return ERR_PTR(-ENOMEM);
-
- proplen = of_property_count_u32_elems(np, "gpios-states");
- /* optional property */
- if (proplen < 0)
- proplen = 0;
-
- if (proplen > 0 && proplen != config->nr_gpios) {
- dev_warn(dev, "gpios <-> gpios-states mismatch\n");
- proplen = 0;
- }
+ /* Fetch GPIOs. - optional property*/
+ ret = of_gpio_count(np);
+ if ((ret < 0) && (ret != -ENOENT))
+ return ERR_PTR(ret);
+
+ if (ret > 0) {
+ config->nr_gpios = ret;
+ config->gpios = devm_kzalloc(dev,
+ sizeof(struct gpio) * config->nr_gpios,
+ GFP_KERNEL);
+ if (!config->gpios)
+ return ERR_PTR(-ENOMEM);
+
+ proplen = of_property_count_u32_elems(np, "gpios-states");
+ /* optional property */
+ if (proplen < 0)
+ proplen = 0;
+
+ if (proplen > 0 && proplen != config->nr_gpios) {
+ dev_warn(dev, "gpios <-> gpios-states mismatch\n");
+ proplen = 0;
+ }
- for (i = 0; i < config->nr_gpios; i++) {
- gpio = of_get_named_gpio(np, "gpios", i);
- if (gpio < 0)
- break;
- config->gpios[i].gpio = gpio;
- if (proplen > 0) {
- of_property_read_u32_index(np, "gpios-states", i, &ret);
- if (ret)
- config->gpios[i].flags = GPIOF_OUT_INIT_HIGH;
+ for (i = 0; i < config->nr_gpios; i++) {
+ gpio = of_get_named_gpio(np, "gpios", i);
+ if (gpio < 0)
+ break;
+ config->gpios[i].gpio = gpio;
+ if (proplen > 0) {
+ of_property_read_u32_index(np, "gpios-states",
+ i, &ret);
+ if (ret)
+ config->gpios[i].flags =
+ GPIOF_OUT_INIT_HIGH;
+ }
}
}
@@ -243,17 +251,18 @@ static int gpio_regulator_probe(struct platform_device *pdev)
struct regulator_config cfg = { };
int ptr, ret, state;
- if (np) {
- config = of_get_gpio_regulator_config(&pdev->dev, np);
- if (IS_ERR(config))
- return PTR_ERR(config);
- }
-
drvdata = devm_kzalloc(&pdev->dev, sizeof(struct gpio_regulator_data),
GFP_KERNEL);
if (drvdata == NULL)
return -ENOMEM;
+ if (np) {
+ config = of_get_gpio_regulator_config(&pdev->dev, np,
+ &drvdata->desc);
+ if (IS_ERR(config))
+ return PTR_ERR(config);
+ }
+
drvdata->desc.name = kstrdup(config->supply_name, GFP_KERNEL);
if (drvdata->desc.name == NULL) {
dev_err(&pdev->dev, "Failed to allocate supply name\n");
@@ -261,13 +270,23 @@ static int gpio_regulator_probe(struct platform_device *pdev)
goto err;
}
- drvdata->gpios = kmemdup(config->gpios,
- config->nr_gpios * sizeof(struct gpio),
- GFP_KERNEL);
- if (drvdata->gpios == NULL) {
- dev_err(&pdev->dev, "Failed to allocate gpio data\n");
- ret = -ENOMEM;
- goto err_name;
+ if (config->nr_gpios != 0) {
+ drvdata->gpios = kmemdup(config->gpios,
+ config->nr_gpios * sizeof(struct gpio),
+ GFP_KERNEL);
+ if (drvdata->gpios == NULL) {
+ dev_err(&pdev->dev, "Failed to allocate gpio data\n");
+ ret = -ENOMEM;
+ goto err_name;
+ }
+
+ drvdata->nr_gpios = config->nr_gpios;
+ ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not obtain regulator setting GPIOs: %d\n", ret);
+ goto err_memstate;
+ }
}
drvdata->states = kmemdup(config->states,
@@ -301,14 +320,6 @@ static int gpio_regulator_probe(struct platform_device *pdev)
goto err_memgpio;
}
- drvdata->nr_gpios = config->nr_gpios;
- ret = gpio_request_array(drvdata->gpios, drvdata->nr_gpios);
- if (ret) {
- dev_err(&pdev->dev,
- "Could not obtain regulator setting GPIOs: %d\n", ret);
- goto err_memstate;
- }
-
/* build initial state from gpio init data. */
state = 0;
for (ptr = 0; ptr < drvdata->nr_gpios; ptr++) {
@@ -322,8 +333,10 @@ static int gpio_regulator_probe(struct platform_device *pdev)
cfg.driver_data = drvdata;
cfg.of_node = np;
- if (config->enable_gpio >= 0)
+ if (gpio_is_valid(config->enable_gpio)) {
cfg.ena_gpio = config->enable_gpio;
+ cfg.ena_gpio_initialized = true;
+ }
cfg.ena_gpio_invert = !config->enable_high;
if (config->enabled_at_boot) {
if (config->enable_high)
diff --git a/drivers/regulator/max77686.c b/drivers/regulator/max77686.c
index f69320e..871b96b 100644
--- a/drivers/regulator/max77686.c
+++ b/drivers/regulator/max77686.c
@@ -45,6 +45,23 @@
#define MAX77686_DVS_MINUV 600000
#define MAX77686_DVS_UVSTEP 12500
+/*
+ * Values used for configuring LDOs and bucks.
+ * Forcing low power mode: LDO1, 3-5, 9, 13, 17-26
+ */
+#define MAX77686_LDO_LOWPOWER 0x1
+/*
+ * On/off controlled by PWRREQ:
+ * - LDO2, 6-8, 10-12, 14-16
+ * - buck[1234]
+ */
+#define MAX77686_OFF_PWRREQ 0x1
+/* Low power mode controlled by PWRREQ: All LDOs */
+#define MAX77686_LDO_LOWPOWER_PWRREQ 0x2
+/* Forcing low power mode: buck[234] */
+#define MAX77686_BUCK_LOWPOWER 0x2
+#define MAX77686_NORMAL 0x3
+
#define MAX77686_OPMODE_SHIFT 6
#define MAX77686_OPMODE_BUCK234_SHIFT 4
#define MAX77686_OPMODE_MASK 0x3
@@ -65,23 +82,36 @@ enum max77686_ramp_rate {
};
struct max77686_data {
+ /* Array indexed by regulator id */
unsigned int opmode[MAX77686_REGULATORS];
};
-/* Some BUCKS supports Normal[ON/OFF] mode during suspend */
-static int max77686_buck_set_suspend_disable(struct regulator_dev *rdev)
+static unsigned int max77686_get_opmode_shift(int id)
{
- unsigned int val;
+ switch (id) {
+ case MAX77686_BUCK1:
+ case MAX77686_BUCK5 ... MAX77686_BUCK9:
+ return 0;
+ case MAX77686_BUCK2 ... MAX77686_BUCK4:
+ return MAX77686_OPMODE_BUCK234_SHIFT;
+ default:
+ /* all LDOs */
+ return MAX77686_OPMODE_SHIFT;
+ }
+}
+
+/* Some BUCKs and LDOs supports Normal[ON/OFF] mode during suspend */
+static int max77686_set_suspend_disable(struct regulator_dev *rdev)
+{
+ unsigned int val, shift;
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
int ret, id = rdev_get_id(rdev);
- if (id == MAX77686_BUCK1)
- val = 0x1;
- else
- val = 0x1 << MAX77686_OPMODE_BUCK234_SHIFT;
+ shift = max77686_get_opmode_shift(id);
+ val = MAX77686_OFF_PWRREQ;
ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, val);
+ rdev->desc->enable_mask, val << shift);
if (ret)
return ret;
@@ -103,10 +133,10 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
switch (mode) {
case REGULATOR_MODE_IDLE: /* ON in LP Mode */
- val = 0x2 << MAX77686_OPMODE_SHIFT;
+ val = MAX77686_LDO_LOWPOWER_PWRREQ;
break;
case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
- val = 0x3 << MAX77686_OPMODE_SHIFT;
+ val = MAX77686_NORMAL;
break;
default:
pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n",
@@ -115,7 +145,8 @@ static int max77686_set_suspend_mode(struct regulator_dev *rdev,
}
ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, val);
+ rdev->desc->enable_mask,
+ val << MAX77686_OPMODE_SHIFT);
if (ret)
return ret;
@@ -133,13 +164,13 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
switch (mode) {
case REGULATOR_MODE_STANDBY: /* switch off */
- val = 0x1 << MAX77686_OPMODE_SHIFT;
+ val = MAX77686_OFF_PWRREQ;
break;
case REGULATOR_MODE_IDLE: /* ON in LP Mode */
- val = 0x2 << MAX77686_OPMODE_SHIFT;
+ val = MAX77686_LDO_LOWPOWER_PWRREQ;
break;
case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
- val = 0x3 << MAX77686_OPMODE_SHIFT;
+ val = MAX77686_NORMAL;
break;
default:
pr_warn("%s: regulator_suspend_mode : 0x%x not supported\n",
@@ -148,7 +179,8 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
}
ret = regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
- rdev->desc->enable_mask, val);
+ rdev->desc->enable_mask,
+ val << MAX77686_OPMODE_SHIFT);
if (ret)
return ret;
@@ -159,10 +191,17 @@ static int max77686_ldo_set_suspend_mode(struct regulator_dev *rdev,
static int max77686_enable(struct regulator_dev *rdev)
{
struct max77686_data *max77686 = rdev_get_drvdata(rdev);
+ unsigned int shift;
+ int id = rdev_get_id(rdev);
+
+ shift = max77686_get_opmode_shift(id);
+
+ if (max77686->opmode[id] == MAX77686_OFF_PWRREQ)
+ max77686->opmode[id] = MAX77686_NORMAL;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
- max77686->opmode[rdev_get_id(rdev)]);
+ max77686->opmode[id] << shift);
}
static int max77686_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
@@ -212,6 +251,7 @@ static struct regulator_ops max77686_ldo_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_suspend_mode = max77686_ldo_set_suspend_mode,
+ .set_suspend_disable = max77686_set_suspend_disable,
};
static struct regulator_ops max77686_buck1_ops = {
@@ -223,7 +263,7 @@ static struct regulator_ops max77686_buck1_ops = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_suspend_disable = max77686_buck_set_suspend_disable,
+ .set_suspend_disable = max77686_set_suspend_disable,
};
static struct regulator_ops max77686_buck_dvs_ops = {
@@ -236,11 +276,13 @@ static struct regulator_ops max77686_buck_dvs_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = max77686_set_ramp_delay,
- .set_suspend_disable = max77686_buck_set_suspend_disable,
+ .set_suspend_disable = max77686_set_suspend_disable,
};
#define regulator_desc_ldo(num) { \
.name = "LDO"#num, \
+ .of_match = of_match_ptr("LDO"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_LDO##num, \
.ops = &max77686_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -257,6 +299,8 @@ static struct regulator_ops max77686_buck_dvs_ops = {
}
#define regulator_desc_lpm_ldo(num) { \
.name = "LDO"#num, \
+ .of_match = of_match_ptr("LDO"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_LDO##num, \
.ops = &max77686_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -273,6 +317,8 @@ static struct regulator_ops max77686_buck_dvs_ops = {
}
#define regulator_desc_ldo_low(num) { \
.name = "LDO"#num, \
+ .of_match = of_match_ptr("LDO"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_LDO##num, \
.ops = &max77686_ldo_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -289,6 +335,8 @@ static struct regulator_ops max77686_buck_dvs_ops = {
}
#define regulator_desc_ldo1_low(num) { \
.name = "LDO"#num, \
+ .of_match = of_match_ptr("LDO"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_LDO##num, \
.ops = &max77686_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -305,6 +353,8 @@ static struct regulator_ops max77686_buck_dvs_ops = {
}
#define regulator_desc_buck(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_BUCK##num, \
.ops = &max77686_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -320,6 +370,8 @@ static struct regulator_ops max77686_buck_dvs_ops = {
}
#define regulator_desc_buck1(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_BUCK##num, \
.ops = &max77686_buck1_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -335,6 +387,8 @@ static struct regulator_ops max77686_buck_dvs_ops = {
}
#define regulator_desc_buck_dvs(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("voltage-regulators"), \
.id = MAX77686_BUCK##num, \
.ops = &max77686_buck_dvs_ops, \
.type = REGULATOR_VOLTAGE, \
@@ -350,7 +404,7 @@ static struct regulator_ops max77686_buck_dvs_ops = {
<< MAX77686_OPMODE_BUCK234_SHIFT, \
}
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
regulator_desc_ldo1_low(1),
regulator_desc_ldo_low(2),
regulator_desc_ldo(3),
@@ -388,103 +442,37 @@ static struct regulator_desc regulators[] = {
regulator_desc_buck(9),
};
-#ifdef CONFIG_OF
-static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
- struct max77686_platform_data *pdata)
-{
- struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct device_node *pmic_np, *regulators_np;
- struct max77686_regulator_data *rdata;
- struct of_regulator_match rmatch = { };
- unsigned int i;
-
- pmic_np = iodev->dev->of_node;
- regulators_np = of_get_child_by_name(pmic_np, "voltage-regulators");
- if (!regulators_np) {
- dev_err(&pdev->dev, "could not find regulators sub-node\n");
- return -EINVAL;
- }
-
- pdata->num_regulators = ARRAY_SIZE(regulators);
- rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
- pdata->num_regulators, GFP_KERNEL);
- if (!rdata) {
- of_node_put(regulators_np);
- return -ENOMEM;
- }
-
- for (i = 0; i < pdata->num_regulators; i++) {
- rmatch.name = regulators[i].name;
- rmatch.init_data = NULL;
- rmatch.of_node = NULL;
- of_regulator_match(&pdev->dev, regulators_np, &rmatch, 1);
- rdata[i].initdata = rmatch.init_data;
- rdata[i].of_node = rmatch.of_node;
- }
-
- pdata->regulators = rdata;
- of_node_put(regulators_np);
-
- return 0;
-}
-#else
-static int max77686_pmic_dt_parse_pdata(struct platform_device *pdev,
- struct max77686_platform_data *pdata)
-{
- return 0;
-}
-#endif /* CONFIG_OF */
-
static int max77686_pmic_probe(struct platform_device *pdev)
{
struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
struct max77686_data *max77686;
- int i, ret = 0;
+ int i;
struct regulator_config config = { };
dev_dbg(&pdev->dev, "%s\n", __func__);
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data found for regulator\n");
- return -ENODEV;
- }
-
- if (iodev->dev->of_node) {
- ret = max77686_pmic_dt_parse_pdata(pdev, pdata);
- if (ret)
- return ret;
- }
-
- if (pdata->num_regulators != MAX77686_REGULATORS) {
- dev_err(&pdev->dev,
- "Invalid initial data for regulator's initialiation\n");
- return -EINVAL;
- }
-
max77686 = devm_kzalloc(&pdev->dev, sizeof(struct max77686_data),
GFP_KERNEL);
if (!max77686)
return -ENOMEM;
- config.dev = &pdev->dev;
+ config.dev = iodev->dev;
config.regmap = iodev->regmap;
config.driver_data = max77686;
platform_set_drvdata(pdev, max77686);
for (i = 0; i < MAX77686_REGULATORS; i++) {
struct regulator_dev *rdev;
+ int id = regulators[i].id;
- config.init_data = pdata->regulators[i].initdata;
- config.of_node = pdata->regulators[i].of_node;
-
- max77686->opmode[i] = regulators[i].enable_mask;
+ max77686->opmode[id] = MAX77686_NORMAL;
rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
if (IS_ERR(rdev)) {
+ int ret = PTR_ERR(rdev);
dev_err(&pdev->dev,
- "regulator init failed for %d\n", i);
- return PTR_ERR(rdev);
+ "regulator init failed for %d: %d\n", i, ret);
+ return ret;
}
}
diff --git a/drivers/regulator/max77693.c b/drivers/regulator/max77693.c
index d158f71..7b9755a 100644
--- a/drivers/regulator/max77693.c
+++ b/drivers/regulator/max77693.c
@@ -139,7 +139,7 @@ static struct regulator_ops max77693_charger_ops = {
.enable_mask = SAFEOUT_CTRL_ENSAFEOUT##_num##_MASK , \
}
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
regulator_desc_esafeout(1),
regulator_desc_esafeout(2),
{
diff --git a/drivers/regulator/max77802.c b/drivers/regulator/max77802.c
index 45fa240..0766615 100644
--- a/drivers/regulator/max77802.c
+++ b/drivers/regulator/max77802.c
@@ -33,6 +33,7 @@
#include <linux/regulator/of_regulator.h>
#include <linux/mfd/max77686.h>
#include <linux/mfd/max77686-private.h>
+#include <dt-bindings/regulator/maxim,max77802.h>
/* Default ramp delay in case it is not manually set */
#define MAX77802_RAMP_DELAY 100000 /* uV/us */
@@ -49,6 +50,10 @@
#define MAX77802_RAMP_RATE_MASK_4BIT 0xF0
#define MAX77802_RAMP_RATE_SHIFT_4BIT 4
+#define MAX77802_STATUS_OFF 0x0
+#define MAX77802_OFF_PWRREQ 0x1
+#define MAX77802_LP_PWRREQ 0x2
+
/* MAX77802 has two register formats: 2-bit and 4-bit */
static const unsigned int ramp_table_77802_2bit[] = {
12500,
@@ -65,9 +70,16 @@ static unsigned int ramp_table_77802_4bit[] = {
};
struct max77802_regulator_prv {
+ /* Array indexed by regulator id */
unsigned int opmode[MAX77802_REG_MAX];
};
+static inline unsigned int max77802_map_mode(unsigned int mode)
+{
+ return mode == MAX77802_OPMODE_NORMAL ?
+ REGULATOR_MODE_NORMAL : REGULATOR_MODE_STANDBY;
+}
+
static int max77802_get_opmode_shift(int id)
{
if (id == MAX77802_BUCK1 || (id >= MAX77802_BUCK5 &&
@@ -83,17 +95,16 @@ static int max77802_get_opmode_shift(int id)
return -EINVAL;
}
-/*
- * Some BUCKS supports Normal[ON/OFF] mode during suspend
+/**
+ * max77802_set_suspend_disable - Disable the regulator during system suspend
+ * @rdev: regulator to mark as disabled
*
- * BUCK 1, 6, 2-4, 5, 7-10 (all)
- *
- * The other mode (0x02) will make PWRREQ switch between normal
- * and low power.
+ * All regulators expect LDO 1, 3, 20 and 21 support OFF by PWRREQ.
+ * Configure the regulator so the PMIC will turn it OFF during system suspend.
*/
-static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev)
+static int max77802_set_suspend_disable(struct regulator_dev *rdev)
{
- unsigned int val = MAX77802_OPMODE_STANDBY;
+ unsigned int val = MAX77802_OFF_PWRREQ;
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
int shift = max77802_get_opmode_shift(id);
@@ -104,14 +115,11 @@ static int max77802_buck_set_suspend_disable(struct regulator_dev *rdev)
}
/*
- * Some LDOs supports LPM-ON/OFF/Normal-ON mode during suspend state
- * (Enable Control Logic1 by PWRREQ)
- *
- * LDOs 2, 4-19, 22-35.
+ * Some LDOs support Low Power Mode while the system is running.
*
+ * LDOs 1, 3, 20, 21.
*/
-static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev,
- unsigned int mode)
+static int max77802_set_mode(struct regulator_dev *rdev, unsigned int mode)
{
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
@@ -119,14 +127,11 @@ static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev,
int shift = max77802_get_opmode_shift(id);
switch (mode) {
- case REGULATOR_MODE_IDLE: /* ON in LP Mode */
- val = MAX77802_OPMODE_LP;
+ case REGULATOR_MODE_STANDBY:
+ val = MAX77802_OPMODE_LP; /* ON in Low Power Mode */
break;
- case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
- val = MAX77802_OPMODE_NORMAL;
- break;
- case REGULATOR_MODE_STANDBY: /* ON/OFF by PWRREQ */
- val = MAX77802_OPMODE_STANDBY;
+ case REGULATOR_MODE_NORMAL:
+ val = MAX77802_OPMODE_NORMAL; /* ON in Normal Mode */
break;
default:
dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
@@ -139,35 +144,76 @@ static int max77802_ldo_set_suspend_mode_logic1(struct regulator_dev *rdev,
rdev->desc->enable_mask, val << shift);
}
-/*
- * Mode 1 (Output[ON/OFF] by PWRREQ) is not supported on some LDOs
- * (Enable Control Logic2 by PWRREQ)
+static unsigned max77802_get_mode(struct regulator_dev *rdev)
+{
+ struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
+ int id = rdev_get_id(rdev);
+
+ return max77802_map_mode(max77802->opmode[id]);
+}
+
+/**
+ * max77802_set_suspend_mode - set regulator opmode when the system is suspended
+ * @rdev: regulator to change mode
+ * @mode: operating mode to be set
*
- * LDOs 1, 20, 21, and 3,
+ * Will set the operating mode for the regulators during system suspend.
+ * This function is valid for the three different enable control logics:
*
+ * Enable Control Logic1 by PWRREQ (BUCK 2-4 and LDOs 2, 4-19, 22-35)
+ * Enable Control Logic2 by PWRREQ (LDOs 1, 20, 21)
+ * Enable Control Logic3 by PWRREQ (LDO 3)
+ *
+ * If setting the regulator mode fails, the function only warns but does
+ * not return an error code to avoid the regulator core to stop setting
+ * the operating mode for the remaining regulators.
*/
-static int max77802_ldo_set_suspend_mode_logic2(struct regulator_dev *rdev,
- unsigned int mode)
+static int max77802_set_suspend_mode(struct regulator_dev *rdev,
+ unsigned int mode)
{
struct max77802_regulator_prv *max77802 = rdev_get_drvdata(rdev);
int id = rdev_get_id(rdev);
unsigned int val;
int shift = max77802_get_opmode_shift(id);
+ /*
+ * If the regulator has been disabled for suspend
+ * then is invalid to try setting a suspend mode.
+ */
+ if (max77802->opmode[id] == MAX77802_OFF_PWRREQ) {
+ dev_warn(&rdev->dev, "%s: is disabled, mode: 0x%x not set\n",
+ rdev->desc->name, mode);
+ return 0;
+ }
+
switch (mode) {
- case REGULATOR_MODE_IDLE: /* ON in LP Mode */
- val = MAX77802_OPMODE_LP;
- break;
- case REGULATOR_MODE_NORMAL: /* ON in Normal Mode */
- val = MAX77802_OPMODE_NORMAL;
+ case REGULATOR_MODE_STANDBY:
+ /*
+ * If the regulator opmode is normal then enable
+ * ON in Low Power Mode by PWRREQ. If the mode is
+ * already Low Power then no action is required.
+ */
+ if (max77802->opmode[id] == MAX77802_OPMODE_NORMAL)
+ val = MAX77802_LP_PWRREQ;
+ else
+ return 0;
break;
+ case REGULATOR_MODE_NORMAL:
+ /*
+ * If the regulator operating mode is Low Power then
+ * normal is not a valid opmode in suspend. If the
+ * mode is already normal then no action is required.
+ */
+ if (max77802->opmode[id] == MAX77802_OPMODE_LP)
+ dev_warn(&rdev->dev, "%s: in Low Power: 0x%x invalid\n",
+ rdev->desc->name, mode);
+ return 0;
default:
dev_warn(&rdev->dev, "%s: regulator mode: 0x%x not supported\n",
rdev->desc->name, mode);
return -EINVAL;
}
- max77802->opmode[id] = val;
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask, val << shift);
}
@@ -178,6 +224,9 @@ static int max77802_enable(struct regulator_dev *rdev)
int id = rdev_get_id(rdev);
int shift = max77802_get_opmode_shift(id);
+ if (max77802->opmode[id] == MAX77802_OFF_PWRREQ)
+ max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
+
return regmap_update_bits(rdev->regmap, rdev->desc->enable_reg,
rdev->desc->enable_mask,
max77802->opmode[id] << shift);
@@ -247,7 +296,8 @@ static struct regulator_ops max77802_ldo_ops_logic1 = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_suspend_mode = max77802_ldo_set_suspend_mode_logic1,
+ .set_suspend_disable = max77802_set_suspend_disable,
+ .set_suspend_mode = max77802_set_suspend_mode,
};
/*
@@ -262,7 +312,9 @@ static struct regulator_ops max77802_ldo_ops_logic2 = {
.get_voltage_sel = regulator_get_voltage_sel_regmap,
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
- .set_suspend_mode = max77802_ldo_set_suspend_mode_logic2,
+ .set_mode = max77802_set_mode,
+ .get_mode = max77802_get_mode,
+ .set_suspend_mode = max77802_set_suspend_mode,
};
/* BUCKS 1, 6 */
@@ -276,10 +328,25 @@ static struct regulator_ops max77802_buck_16_dvs_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = max77802_set_ramp_delay_4bit,
- .set_suspend_disable = max77802_buck_set_suspend_disable,
+ .set_suspend_disable = max77802_set_suspend_disable,
};
-/* BUCKs 2-4, 5, 7-10 */
+/* BUCKs 2-4 */
+static struct regulator_ops max77802_buck_234_ops = {
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = max77802_enable,
+ .disable = regulator_disable_regmap,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+ .set_voltage_time_sel = regulator_set_voltage_time_sel,
+ .set_ramp_delay = max77802_set_ramp_delay_2bit,
+ .set_suspend_disable = max77802_set_suspend_disable,
+ .set_suspend_mode = max77802_set_suspend_mode,
+};
+
+/* BUCKs 5, 7-10 */
static struct regulator_ops max77802_buck_dvs_ops = {
.list_voltage = regulator_list_voltage_linear,
.map_voltage = regulator_map_voltage_linear,
@@ -290,12 +357,14 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.set_voltage_sel = regulator_set_voltage_sel_regmap,
.set_voltage_time_sel = regulator_set_voltage_time_sel,
.set_ramp_delay = max77802_set_ramp_delay_2bit,
- .set_suspend_disable = max77802_buck_set_suspend_disable,
+ .set_suspend_disable = max77802_set_suspend_disable,
};
/* LDOs 3-7, 9-14, 18-26, 28, 29, 32-34 */
#define regulator_77802_desc_p_ldo(num, supply, log) { \
.name = "LDO"#num, \
+ .of_match = of_match_ptr("LDO"#num), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = MAX77802_LDO##num, \
.supply_name = "inl"#supply, \
.ops = &max77802_ldo_ops_logic##log, \
@@ -309,11 +378,14 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.vsel_mask = MAX77802_VSEL_MASK, \
.enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \
.enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+ .of_map_mode = max77802_map_mode, \
}
/* LDOs 1, 2, 8, 15, 17, 27, 30, 35 */
#define regulator_77802_desc_n_ldo(num, supply, log) { \
.name = "LDO"#num, \
+ .of_match = of_match_ptr("LDO"#num), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = MAX77802_LDO##num, \
.supply_name = "inl"#supply, \
.ops = &max77802_ldo_ops_logic##log, \
@@ -327,11 +399,14 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.vsel_mask = MAX77802_VSEL_MASK, \
.enable_reg = MAX77802_REG_LDO1CTRL1 + num - 1, \
.enable_mask = MAX77802_OPMODE_MASK << MAX77802_OPMODE_SHIFT_LDO, \
+ .of_map_mode = max77802_map_mode, \
}
/* BUCKs 1, 6 */
#define regulator_77802_desc_16_buck(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = MAX77802_BUCK##num, \
.supply_name = "inb"#num, \
.ops = &max77802_buck_16_dvs_ops, \
@@ -345,14 +420,17 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.vsel_mask = MAX77802_DVS_VSEL_MASK, \
.enable_reg = MAX77802_REG_BUCK ## num ## CTRL, \
.enable_mask = MAX77802_OPMODE_MASK, \
+ .of_map_mode = max77802_map_mode, \
}
/* BUCKS 2-4 */
#define regulator_77802_desc_234_buck(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = MAX77802_BUCK##num, \
.supply_name = "inb"#num, \
- .ops = &max77802_buck_dvs_ops, \
+ .ops = &max77802_buck_234_ops, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
.min_uV = 600000, \
@@ -364,11 +442,14 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.enable_reg = MAX77802_REG_BUCK ## num ## CTRL1, \
.enable_mask = MAX77802_OPMODE_MASK << \
MAX77802_OPMODE_BUCK234_SHIFT, \
+ .of_map_mode = max77802_map_mode, \
}
/* BUCK 5 */
#define regulator_77802_desc_buck5(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = MAX77802_BUCK##num, \
.supply_name = "inb"#num, \
.ops = &max77802_buck_dvs_ops, \
@@ -382,11 +463,14 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.vsel_mask = MAX77802_VSEL_MASK, \
.enable_reg = MAX77802_REG_BUCK5CTRL, \
.enable_mask = MAX77802_OPMODE_MASK, \
+ .of_map_mode = max77802_map_mode, \
}
/* BUCKs 7-10 */
#define regulator_77802_desc_buck7_10(num) { \
.name = "BUCK"#num, \
+ .of_match = of_match_ptr("BUCK"#num), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = MAX77802_BUCK##num, \
.supply_name = "inb"#num, \
.ops = &max77802_buck_dvs_ops, \
@@ -400,9 +484,10 @@ static struct regulator_ops max77802_buck_dvs_ops = {
.vsel_mask = MAX77802_VSEL_MASK, \
.enable_reg = MAX77802_REG_BUCK7CTRL + (num - 7) * 3, \
.enable_mask = MAX77802_OPMODE_MASK, \
+ .of_map_mode = max77802_map_mode, \
}
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
regulator_77802_desc_16_buck(1),
regulator_77802_desc_234_buck(2),
regulator_77802_desc_234_buck(3),
@@ -447,85 +532,19 @@ static struct regulator_desc regulators[] = {
regulator_77802_desc_n_ldo(35, 2, 1),
};
-#ifdef CONFIG_OF
-static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
- struct max77686_platform_data *pdata)
-{
- struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct device_node *pmic_np, *regulators_np;
- struct max77686_regulator_data *rdata;
- struct of_regulator_match rmatch = { };
- unsigned int i;
-
- pmic_np = iodev->dev->of_node;
- regulators_np = of_get_child_by_name(pmic_np, "regulators");
- if (!regulators_np) {
- dev_err(&pdev->dev, "could not find regulators sub-node\n");
- return -EINVAL;
- }
-
- pdata->num_regulators = ARRAY_SIZE(regulators);
- rdata = devm_kzalloc(&pdev->dev, sizeof(*rdata) *
- pdata->num_regulators, GFP_KERNEL);
- if (!rdata) {
- of_node_put(regulators_np);
- return -ENOMEM;
- }
-
- for (i = 0; i < pdata->num_regulators; i++) {
- rmatch.name = regulators[i].name;
- rmatch.init_data = NULL;
- rmatch.of_node = NULL;
- if (of_regulator_match(&pdev->dev, regulators_np, &rmatch,
- 1) != 1) {
- dev_warn(&pdev->dev, "No matching regulator for '%s'\n",
- rmatch.name);
- continue;
- }
- rdata[i].initdata = rmatch.init_data;
- rdata[i].of_node = rmatch.of_node;
- rdata[i].id = regulators[i].id;
- }
-
- pdata->regulators = rdata;
- of_node_put(regulators_np);
-
- return 0;
-}
-#else
-static int max77802_pmic_dt_parse_pdata(struct platform_device *pdev,
- struct max77686_platform_data *pdata)
-{
- return 0;
-}
-#endif /* CONFIG_OF */
-
static int max77802_pmic_probe(struct platform_device *pdev)
{
struct max77686_dev *iodev = dev_get_drvdata(pdev->dev.parent);
- struct max77686_platform_data *pdata = dev_get_platdata(iodev->dev);
struct max77802_regulator_prv *max77802;
- int i, ret = 0, val;
+ int i, val;
struct regulator_config config = { };
- /* This is allocated by the MFD driver */
- if (!pdata) {
- dev_err(&pdev->dev, "no platform data found for regulator\n");
- return -ENODEV;
- }
-
max77802 = devm_kzalloc(&pdev->dev,
sizeof(struct max77802_regulator_prv),
GFP_KERNEL);
if (!max77802)
return -ENOMEM;
- if (iodev->dev->of_node) {
- ret = max77802_pmic_dt_parse_pdata(pdev, pdata);
- if (ret)
- return ret;
- }
-
config.dev = iodev->dev;
config.regmap = iodev->regmap;
config.driver_data = max77802;
@@ -533,21 +552,25 @@ static int max77802_pmic_probe(struct platform_device *pdev)
for (i = 0; i < MAX77802_REG_MAX; i++) {
struct regulator_dev *rdev;
- int id = pdata->regulators[i].id;
+ int id = regulators[i].id;
int shift = max77802_get_opmode_shift(id);
-
- config.init_data = pdata->regulators[i].initdata;
- config.of_node = pdata->regulators[i].of_node;
+ int ret;
ret = regmap_read(iodev->regmap, regulators[i].enable_reg, &val);
- val = val >> shift & MAX77802_OPMODE_MASK;
+ if (ret < 0) {
+ dev_warn(&pdev->dev,
+ "cannot read current mode for %d\n", i);
+ val = MAX77802_OPMODE_NORMAL;
+ } else {
+ val = val >> shift & MAX77802_OPMODE_MASK;
+ }
/*
* If the regulator is disabled and the system warm rebooted,
* the hardware reports OFF as the regulator operating mode.
* Default to operating mode NORMAL in that case.
*/
- if (val == MAX77802_OPMODE_OFF)
+ if (val == MAX77802_STATUS_OFF)
max77802->opmode[id] = MAX77802_OPMODE_NORMAL;
else
max77802->opmode[id] = val;
@@ -555,9 +578,10 @@ static int max77802_pmic_probe(struct platform_device *pdev)
rdev = devm_regulator_register(&pdev->dev,
&regulators[i], &config);
if (IS_ERR(rdev)) {
+ ret = PTR_ERR(rdev);
dev_err(&pdev->dev,
- "regulator init failed for %d\n", i);
- return PTR_ERR(rdev);
+ "regulator init failed for %d: %d\n", i, ret);
+ return ret;
}
}
diff --git a/drivers/regulator/max8952.c b/drivers/regulator/max8952.c
index f7f9efc..1af8f4a 100644
--- a/drivers/regulator/max8952.c
+++ b/drivers/regulator/max8952.c
@@ -174,7 +174,7 @@ static struct max8952_platform_data *max8952_parse_dt(struct device *dev)
if (of_property_read_u32(np, "max8952,ramp-speed", &pd->ramp_speed))
dev_warn(dev, "max8952,ramp-speed property not specified, defaulting to 32mV/us\n");
- pd->reg_data = of_get_regulator_init_data(dev, np);
+ pd->reg_data = of_get_regulator_init_data(dev, np, &regulator);
if (!pd->reg_data) {
dev_err(dev, "Failed to parse regulator init data\n");
return NULL;
@@ -225,6 +225,8 @@ static int max8952_pmic_probe(struct i2c_client *client,
config.of_node = client->dev.of_node;
config.ena_gpio = pdata->gpio_en;
+ if (client->dev.of_node)
+ config.ena_gpio_initialized = true;
if (pdata->reg_data->constraints.boot_on)
config.ena_gpio_flags |= GPIOF_OUT_INIT_HIGH;
diff --git a/drivers/regulator/max8973-regulator.c b/drivers/regulator/max8973-regulator.c
index dbedf17..c3d55c2 100644
--- a/drivers/regulator/max8973-regulator.c
+++ b/drivers/regulator/max8973-regulator.c
@@ -458,7 +458,8 @@ static int max8973_probe(struct i2c_client *client,
config.dev = &client->dev;
config.init_data = pdata ? pdata->reg_init_data :
- of_get_regulator_init_data(&client->dev, client->dev.of_node);
+ of_get_regulator_init_data(&client->dev, client->dev.of_node,
+ &max->desc);
config.driver_data = max;
config.of_node = client->dev.of_node;
config.regmap = max->regmap;
diff --git a/drivers/regulator/max8997.c b/drivers/regulator/max8997.c
index 9c31e21..726fde1 100644
--- a/drivers/regulator/max8997.c
+++ b/drivers/regulator/max8997.c
@@ -953,7 +953,8 @@ static int max8997_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata->id = i;
rdata->initdata = of_get_regulator_init_data(&pdev->dev,
- reg_np);
+ reg_np,
+ &regulators[i]);
rdata->reg_node = reg_np;
rdata++;
}
diff --git a/drivers/regulator/max8998.c b/drivers/regulator/max8998.c
index 961091b..59e34a0 100644
--- a/drivers/regulator/max8998.c
+++ b/drivers/regulator/max8998.c
@@ -686,8 +686,9 @@ static int max8998_pmic_dt_parse_pdata(struct max8998_dev *iodev,
continue;
rdata->id = regulators[i].id;
- rdata->initdata = of_get_regulator_init_data(
- iodev->dev, reg_np);
+ rdata->initdata = of_get_regulator_init_data(iodev->dev,
+ reg_np,
+ &regulators[i]);
rdata->reg_node = reg_np;
++rdata;
}
diff --git a/drivers/regulator/mc13xxx-regulator-core.c b/drivers/regulator/mc13xxx-regulator-core.c
index afba024..0281c31 100644
--- a/drivers/regulator/mc13xxx-regulator-core.c
+++ b/drivers/regulator/mc13xxx-regulator-core.c
@@ -194,7 +194,8 @@ struct mc13xxx_regulator_init_data *mc13xxx_parse_regulators_dt(
regulators[i].desc.name)) {
p->id = i;
p->init_data = of_get_regulator_init_data(
- &pdev->dev, child);
+ &pdev->dev, child,
+ &regulators[i].desc);
p->node = child;
p++;
diff --git a/drivers/regulator/of_regulator.c b/drivers/regulator/of_regulator.c
index 5a1d4af..91eaaf0 100644
--- a/drivers/regulator/of_regulator.c
+++ b/drivers/regulator/of_regulator.c
@@ -19,12 +19,20 @@
#include "internal.h"
+static const char *const regulator_states[PM_SUSPEND_MAX + 1] = {
+ [PM_SUSPEND_MEM] = "regulator-state-mem",
+ [PM_SUSPEND_MAX] = "regulator-state-disk",
+};
+
static void of_get_regulation_constraints(struct device_node *np,
- struct regulator_init_data **init_data)
+ struct regulator_init_data **init_data,
+ const struct regulator_desc *desc)
{
const __be32 *min_uV, *max_uV;
struct regulation_constraints *constraints = &(*init_data)->constraints;
- int ret;
+ struct regulator_state *suspend_state;
+ struct device_node *suspend_np;
+ int ret, i;
u32 pval;
constraints->name = of_get_property(np, "regulator-name", NULL);
@@ -73,18 +81,84 @@ static void of_get_regulation_constraints(struct device_node *np,
ret = of_property_read_u32(np, "regulator-enable-ramp-delay", &pval);
if (!ret)
constraints->enable_time = pval;
+
+ if (!of_property_read_u32(np, "regulator-initial-mode", &pval)) {
+ if (desc && desc->of_map_mode) {
+ ret = desc->of_map_mode(pval);
+ if (ret == -EINVAL)
+ pr_err("%s: invalid mode %u\n", np->name, pval);
+ else
+ constraints->initial_mode = ret;
+ } else {
+ pr_warn("%s: mapping for mode %d not defined\n",
+ np->name, pval);
+ }
+ }
+
+ for (i = 0; i < ARRAY_SIZE(regulator_states); i++) {
+ switch (i) {
+ case PM_SUSPEND_MEM:
+ suspend_state = &constraints->state_mem;
+ break;
+ case PM_SUSPEND_MAX:
+ suspend_state = &constraints->state_disk;
+ break;
+ case PM_SUSPEND_ON:
+ case PM_SUSPEND_FREEZE:
+ case PM_SUSPEND_STANDBY:
+ default:
+ continue;
+ };
+
+ suspend_np = of_get_child_by_name(np, regulator_states[i]);
+ if (!suspend_np || !suspend_state)
+ continue;
+
+ if (!of_property_read_u32(suspend_np, "regulator-mode",
+ &pval)) {
+ if (desc && desc->of_map_mode) {
+ ret = desc->of_map_mode(pval);
+ if (ret == -EINVAL)
+ pr_err("%s: invalid mode %u\n",
+ np->name, pval);
+ else
+ suspend_state->mode = ret;
+ } else {
+ pr_warn("%s: mapping for mode %d not defined\n",
+ np->name, pval);
+ }
+ }
+
+ if (of_property_read_bool(suspend_np,
+ "regulator-on-in-suspend"))
+ suspend_state->enabled = true;
+ else if (of_property_read_bool(suspend_np,
+ "regulator-off-in-suspend"))
+ suspend_state->disabled = true;
+
+ if (!of_property_read_u32(suspend_np,
+ "regulator-suspend-microvolt", &pval))
+ suspend_state->uV = pval;
+
+ of_node_put(suspend_np);
+ suspend_state = NULL;
+ suspend_np = NULL;
+ }
}
/**
* of_get_regulator_init_data - extract regulator_init_data structure info
* @dev: device requesting for regulator_init_data
+ * @node: regulator device node
+ * @desc: regulator description
*
* Populates regulator_init_data structure by extracting data from device
* tree node, returns a pointer to the populated struture or NULL if memory
* alloc fails.
*/
struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
- struct device_node *node)
+ struct device_node *node,
+ const struct regulator_desc *desc)
{
struct regulator_init_data *init_data;
@@ -95,7 +169,7 @@ struct regulator_init_data *of_get_regulator_init_data(struct device *dev,
if (!init_data)
return NULL; /* Out of memory? */
- of_get_regulation_constraints(node, &init_data);
+ of_get_regulation_constraints(node, &init_data, desc);
return init_data;
}
EXPORT_SYMBOL_GPL(of_get_regulator_init_data);
@@ -176,7 +250,8 @@ int of_regulator_match(struct device *dev, struct device_node *node,
continue;
match->init_data =
- of_get_regulator_init_data(dev, child);
+ of_get_regulator_init_data(dev, child,
+ match->desc);
if (!match->init_data) {
dev_err(dev,
"failed to parse DT for regulator %s\n",
@@ -224,7 +299,7 @@ struct regulator_init_data *regulator_of_get_init_data(struct device *dev,
if (strcmp(desc->of_match, name))
continue;
- init_data = of_get_regulator_init_data(dev, child);
+ init_data = of_get_regulator_init_data(dev, child, desc);
if (!init_data) {
dev_err(dev,
"failed to parse DT for regulator %s\n",
diff --git a/drivers/regulator/pwm-regulator.c b/drivers/regulator/pwm-regulator.c
index d3f55ea..91f34ca 100644
--- a/drivers/regulator/pwm-regulator.c
+++ b/drivers/regulator/pwm-regulator.c
@@ -149,7 +149,8 @@ static int pwm_regulator_probe(struct platform_device *pdev)
return ret;
}
- config.init_data = of_get_regulator_init_data(&pdev->dev, np);
+ config.init_data = of_get_regulator_init_data(&pdev->dev, np,
+ &drvdata->desc);
if (!config.init_data)
return -ENOMEM;
diff --git a/drivers/regulator/qcom_rpm-regulator.c b/drivers/regulator/qcom_rpm-regulator.c
index b55cd5b..183598b 100644
--- a/drivers/regulator/qcom_rpm-regulator.c
+++ b/drivers/regulator/qcom_rpm-regulator.c
@@ -183,6 +183,13 @@ static const struct regulator_linear_range ftsmps_ranges[] = {
REGULATOR_LINEAR_RANGE(1500000, 64, 100, 50000),
};
+static const struct regulator_linear_range smb208_ranges[] = {
+ REGULATOR_LINEAR_RANGE( 375000, 0, 29, 12500),
+ REGULATOR_LINEAR_RANGE( 750000, 30, 89, 12500),
+ REGULATOR_LINEAR_RANGE(1500000, 90, 153, 25000),
+ REGULATOR_LINEAR_RANGE(3100000, 154, 234, 25000),
+};
+
static const struct regulator_linear_range ncp_ranges[] = {
REGULATOR_LINEAR_RANGE(1500000, 0, 31, 50000),
};
@@ -559,6 +566,16 @@ static const struct qcom_rpm_reg pm8921_switch = {
.parts = &rpm8960_switch_parts,
};
+static const struct qcom_rpm_reg smb208_smps = {
+ .desc.linear_ranges = smb208_ranges,
+ .desc.n_linear_ranges = ARRAY_SIZE(smb208_ranges),
+ .desc.n_voltages = 235,
+ .desc.ops = &uV_ops,
+ .parts = &rpm8960_smps_parts,
+ .supports_force_mode_auto = false,
+ .supports_force_mode_bypass = false,
+};
+
static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8058-pldo", .data = &pm8058_pldo },
{ .compatible = "qcom,rpm-pm8058-nldo", .data = &pm8058_nldo },
@@ -578,6 +595,8 @@ static const struct of_device_id rpm_of_match[] = {
{ .compatible = "qcom,rpm-pm8921-ftsmps", .data = &pm8921_ftsmps },
{ .compatible = "qcom,rpm-pm8921-ncp", .data = &pm8921_ncp },
{ .compatible = "qcom,rpm-pm8921-switch", .data = &pm8921_switch },
+
+ { .compatible = "qcom,rpm-smb208", .data = &smb208_smps },
{ }
};
MODULE_DEVICE_TABLE(of, rpm_of_match);
@@ -643,10 +662,6 @@ static int rpm_reg_probe(struct platform_device *pdev)
match = of_match_device(rpm_of_match, &pdev->dev);
template = match->data;
- initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
- if (!initdata)
- return -EINVAL;
-
vreg = devm_kmalloc(&pdev->dev, sizeof(*vreg), GFP_KERNEL);
if (!vreg) {
dev_err(&pdev->dev, "failed to allocate vreg\n");
@@ -666,6 +681,11 @@ static int rpm_reg_probe(struct platform_device *pdev)
return -ENODEV;
}
+ initdata = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
+ &vreg->desc);
+ if (!initdata)
+ return -EINVAL;
+
key = "reg";
ret = of_property_read_u32(pdev->dev.of_node, key, &val);
if (ret) {
diff --git a/drivers/regulator/rk808-regulator.c b/drivers/regulator/rk808-regulator.c
index 196a5c8..ea9d05e 100644
--- a/drivers/regulator/rk808-regulator.c
+++ b/drivers/regulator/rk808-regulator.c
@@ -36,6 +36,12 @@
#define RK808_RAMP_RATE_6MV_PER_US (2 << RK808_RAMP_RATE_OFFSET)
#define RK808_RAMP_RATE_10MV_PER_US (3 << RK808_RAMP_RATE_OFFSET)
+/* Offset from XXX_ON_VSEL to XXX_SLP_VSEL */
+#define RK808_SLP_REG_OFFSET 1
+
+/* Offset from XXX_EN_REG to SLEEP_SET_OFF_XXX */
+#define RK808_SLP_SET_OFF_REG_OFFSET 2
+
static const int rk808_buck_config_regs[] = {
RK808_BUCK1_CONFIG_REG,
RK808_BUCK2_CONFIG_REG,
@@ -91,6 +97,43 @@ static int rk808_set_ramp_delay(struct regulator_dev *rdev, int ramp_delay)
RK808_RAMP_RATE_MASK, ramp_value);
}
+int rk808_set_suspend_voltage(struct regulator_dev *rdev, int uv)
+{
+ unsigned int reg;
+ int sel = regulator_map_voltage_linear_range(rdev, uv, uv);
+
+ if (sel < 0)
+ return -EINVAL;
+
+ reg = rdev->desc->vsel_reg + RK808_SLP_REG_OFFSET;
+
+ return regmap_update_bits(rdev->regmap, reg,
+ rdev->desc->vsel_mask,
+ sel);
+}
+
+int rk808_set_suspend_enable(struct regulator_dev *rdev)
+{
+ unsigned int reg;
+
+ reg = rdev->desc->enable_reg + RK808_SLP_SET_OFF_REG_OFFSET;
+
+ return regmap_update_bits(rdev->regmap, reg,
+ rdev->desc->enable_mask,
+ 0);
+}
+
+int rk808_set_suspend_disable(struct regulator_dev *rdev)
+{
+ unsigned int reg;
+
+ reg = rdev->desc->enable_reg + RK808_SLP_SET_OFF_REG_OFFSET;
+
+ return regmap_update_bits(rdev->regmap, reg,
+ rdev->desc->enable_mask,
+ rdev->desc->enable_mask);
+}
+
static struct regulator_ops rk808_buck1_2_ops = {
.list_voltage = regulator_list_voltage_linear_range,
.map_voltage = regulator_map_voltage_linear_range,
@@ -100,6 +143,9 @@ static struct regulator_ops rk808_buck1_2_ops = {
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
.set_ramp_delay = rk808_set_ramp_delay,
+ .set_suspend_voltage = rk808_set_suspend_voltage,
+ .set_suspend_enable = rk808_set_suspend_enable,
+ .set_suspend_disable = rk808_set_suspend_disable,
};
static struct regulator_ops rk808_reg_ops = {
@@ -110,12 +156,17 @@ static struct regulator_ops rk808_reg_ops = {
.enable = regulator_enable_regmap,
.disable = regulator_disable_regmap,
.is_enabled = regulator_is_enabled_regmap,
+ .set_suspend_voltage = rk808_set_suspend_voltage,
+ .set_suspend_enable = rk808_set_suspend_enable,
+ .set_suspend_disable = rk808_set_suspend_disable,
};
static struct regulator_ops rk808_switch_ops = {
- .enable = regulator_enable_regmap,
- .disable = regulator_disable_regmap,
- .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .is_enabled = regulator_is_enabled_regmap,
+ .set_suspend_enable = rk808_set_suspend_enable,
+ .set_suspend_disable = rk808_set_suspend_disable,
};
static const struct regulator_desc rk808_reg[] = {
diff --git a/drivers/regulator/rn5t618-regulator.c b/drivers/regulator/rn5t618-regulator.c
index e58d79a..b85ceb8 100644
--- a/drivers/regulator/rn5t618-regulator.c
+++ b/drivers/regulator/rn5t618-regulator.c
@@ -31,6 +31,8 @@ static struct regulator_ops rn5t618_reg_ops = {
#define REG(rid, ereg, emask, vreg, vmask, min, max, step) \
[RN5T618_##rid] = { \
.name = #rid, \
+ .of_match = of_match_ptr(#rid), \
+ .regulators_node = of_match_ptr("regulators"), \
.id = RN5T618_##rid, \
.type = REGULATOR_VOLTAGE, \
.owner = THIS_MODULE, \
@@ -60,60 +62,15 @@ static struct regulator_desc rn5t618_regulators[] = {
REG(LDORTC2, LDOEN2, BIT(5), LDORTC2DAC, 0x7f, 900000, 3500000, 25000),
};
-static struct of_regulator_match rn5t618_matches[] = {
- [RN5T618_DCDC1] = { .name = "DCDC1" },
- [RN5T618_DCDC2] = { .name = "DCDC2" },
- [RN5T618_DCDC3] = { .name = "DCDC3" },
- [RN5T618_LDO1] = { .name = "LDO1" },
- [RN5T618_LDO2] = { .name = "LDO2" },
- [RN5T618_LDO3] = { .name = "LDO3" },
- [RN5T618_LDO4] = { .name = "LDO4" },
- [RN5T618_LDO5] = { .name = "LDO5" },
- [RN5T618_LDORTC1] = { .name = "LDORTC1" },
- [RN5T618_LDORTC2] = { .name = "LDORTC2" },
-};
-
-static int rn5t618_regulator_parse_dt(struct platform_device *pdev)
-{
- struct device_node *np, *regulators;
- int ret;
-
- np = of_node_get(pdev->dev.parent->of_node);
- if (!np)
- return 0;
-
- regulators = of_get_child_by_name(np, "regulators");
- if (!regulators) {
- dev_err(&pdev->dev, "regulators node not found\n");
- return -EINVAL;
- }
-
- ret = of_regulator_match(&pdev->dev, regulators, rn5t618_matches,
- ARRAY_SIZE(rn5t618_matches));
- of_node_put(regulators);
- if (ret < 0) {
- dev_err(&pdev->dev, "error parsing regulator init data: %d\n",
- ret);
- }
-
- return 0;
-}
-
static int rn5t618_regulator_probe(struct platform_device *pdev)
{
struct rn5t618 *rn5t618 = dev_get_drvdata(pdev->dev.parent);
struct regulator_config config = { };
struct regulator_dev *rdev;
- int ret, i;
-
- ret = rn5t618_regulator_parse_dt(pdev);
- if (ret)
- return ret;
+ int i;
for (i = 0; i < RN5T618_REG_NUM; i++) {
- config.dev = &pdev->dev;
- config.init_data = rn5t618_matches[i].init_data;
- config.of_node = rn5t618_matches[i].of_node;
+ config.dev = pdev->dev.parent;
config.regmap = rn5t618->regmap;
rdev = devm_regulator_register(&pdev->dev,
diff --git a/drivers/regulator/rt5033-regulator.c b/drivers/regulator/rt5033-regulator.c
new file mode 100644
index 0000000..870cc49
--- /dev/null
+++ b/drivers/regulator/rt5033-regulator.c
@@ -0,0 +1,123 @@
+/*
+ * Regulator driver for the Richtek RT5033
+ *
+ * Copyright (C) 2014 Samsung Electronics, Co., Ltd.
+ * Author: Beomho Seo <beomho.seo@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published bythe Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/regulator/driver.h>
+#include <linux/mfd/rt5033.h>
+#include <linux/mfd/rt5033-private.h>
+#include <linux/regulator/of_regulator.h>
+
+static struct regulator_ops rt5033_safe_ldo_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+};
+
+static struct regulator_ops rt5033_buck_ops = {
+ .is_enabled = regulator_is_enabled_regmap,
+ .enable = regulator_enable_regmap,
+ .disable = regulator_disable_regmap,
+ .list_voltage = regulator_list_voltage_linear,
+ .map_voltage = regulator_map_voltage_linear,
+ .get_voltage_sel = regulator_get_voltage_sel_regmap,
+ .set_voltage_sel = regulator_set_voltage_sel_regmap,
+};
+
+static const struct regulator_desc rt5033_supported_regulators[] = {
+ [RT5033_BUCK] = {
+ .name = "BUCK",
+ .id = RT5033_BUCK,
+ .ops = &rt5033_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = RT5033_REGULATOR_BUCK_VOLTAGE_STEP_NUM,
+ .min_uV = RT5033_REGULATOR_BUCK_VOLTAGE_MIN,
+ .uV_step = RT5033_REGULATOR_BUCK_VOLTAGE_STEP,
+ .enable_reg = RT5033_REG_CTRL,
+ .enable_mask = RT5033_CTRL_EN_BUCK_MASK,
+ .vsel_reg = RT5033_REG_BUCK_CTRL,
+ .vsel_mask = RT5033_BUCK_CTRL_MASK,
+ },
+ [RT5033_LDO] = {
+ .name = "LDO",
+ .id = RT5033_LDO,
+ .ops = &rt5033_buck_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = RT5033_REGULATOR_LDO_VOLTAGE_STEP_NUM,
+ .min_uV = RT5033_REGULATOR_LDO_VOLTAGE_MIN,
+ .uV_step = RT5033_REGULATOR_LDO_VOLTAGE_STEP,
+ .enable_reg = RT5033_REG_CTRL,
+ .enable_mask = RT5033_CTRL_EN_LDO_MASK,
+ .vsel_reg = RT5033_REG_LDO_CTRL,
+ .vsel_mask = RT5033_LDO_CTRL_MASK,
+ },
+ [RT5033_SAFE_LDO] = {
+ .name = "SAFE_LDO",
+ .id = RT5033_SAFE_LDO,
+ .ops = &rt5033_safe_ldo_ops,
+ .type = REGULATOR_VOLTAGE,
+ .owner = THIS_MODULE,
+ .n_voltages = 1,
+ .min_uV = RT5033_REGULATOR_SAFE_LDO_VOLTAGE,
+ .enable_reg = RT5033_REG_CTRL,
+ .enable_mask = RT5033_CTRL_EN_SAFE_LDO_MASK,
+ },
+};
+
+static int rt5033_regulator_probe(struct platform_device *pdev)
+{
+ struct rt5033_dev *rt5033 = dev_get_drvdata(pdev->dev.parent);
+ int ret, i;
+ struct regulator_config config = {};
+
+ config.dev = &pdev->dev;
+ config.driver_data = rt5033;
+
+ for (i = 0; i < ARRAY_SIZE(rt5033_supported_regulators); i++) {
+ struct regulator_dev *regulator;
+
+ config.regmap = rt5033->regmap;
+
+ regulator = devm_regulator_register(&pdev->dev,
+ &rt5033_supported_regulators[i], &config);
+ if (IS_ERR(regulator)) {
+ ret = PTR_ERR(regulator);
+ dev_err(&pdev->dev,
+ "Regulator init failed %d: with error: %d\n",
+ i, ret);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static const struct platform_device_id rt5033_regulator_id[] = {
+ { "rt5033-regulator", },
+ { }
+};
+MODULE_DEVICE_TABLE(platform, rt5033_regulator_id);
+
+static struct platform_driver rt5033_regulator_driver = {
+ .driver = {
+ .name = "rt5033-regulator",
+ },
+ .probe = rt5033_regulator_probe,
+ .id_table = rt5033_regulator_id,
+};
+module_platform_driver(rt5033_regulator_driver);
+
+MODULE_DESCRIPTION("Richtek RT5033 Regulator driver");
+MODULE_AUTHOR("Beomho Seo <beomho.seo@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/regulator/s2mpa01.c b/drivers/regulator/s2mpa01.c
index 7633b9b..5db4e12 100644
--- a/drivers/regulator/s2mpa01.c
+++ b/drivers/regulator/s2mpa01.c
@@ -298,7 +298,7 @@ static struct regulator_ops s2mpa01_buck_ops = {
.enable_mask = S2MPA01_ENABLE_MASK \
}
-static struct regulator_desc regulators[] = {
+static const struct regulator_desc regulators[] = {
regulator_desc_ldo(1, STEP_25_MV),
regulator_desc_ldo(2, STEP_50_MV),
regulator_desc_ldo(3, STEP_50_MV),
diff --git a/drivers/regulator/s2mps11.c b/drivers/regulator/s2mps11.c
index adab82d..b345cf5 100644
--- a/drivers/regulator/s2mps11.c
+++ b/drivers/regulator/s2mps11.c
@@ -30,6 +30,7 @@
#include <linux/of_gpio.h>
#include <linux/mfd/samsung/core.h>
#include <linux/mfd/samsung/s2mps11.h>
+#include <linux/mfd/samsung/s2mps13.h>
#include <linux/mfd/samsung/s2mps14.h>
#include <linux/mfd/samsung/s2mpu02.h>
@@ -45,10 +46,10 @@ struct s2mps11_info {
enum sec_device_type dev_type;
/*
- * One bit for each S2MPS14/S2MPU02 regulator whether the suspend mode
- * was enabled.
+ * One bit for each S2MPS13/S2MPS14/S2MPU02 regulator whether
+ * the suspend mode was enabled.
*/
- unsigned long long s2mps14_suspend_state:35;
+ unsigned long long s2mps14_suspend_state:50;
/* Array of size rdev_num with GPIO-s for external sleep control */
int *ext_control_gpio;
@@ -369,12 +370,101 @@ static const struct regulator_desc s2mps11_regulators[] = {
regulator_desc_s2mps11_buck6_10(10, MIN_750_MV, STEP_12_5_MV),
};
+static struct regulator_ops s2mps14_reg_ops;
+
+#define regulator_desc_s2mps13_ldo(num, min, step, min_sel) { \
+ .name = "LDO"#num, \
+ .id = S2MPS13_LDO##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .linear_min_sel = min_sel, \
+ .n_voltages = S2MPS14_LDO_N_VOLTAGES, \
+ .vsel_reg = S2MPS13_REG_L1CTRL + num - 1, \
+ .vsel_mask = S2MPS14_LDO_VSEL_MASK, \
+ .enable_reg = S2MPS13_REG_L1CTRL + num - 1, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+
+#define regulator_desc_s2mps13_buck(num, min, step, min_sel) { \
+ .name = "BUCK"#num, \
+ .id = S2MPS13_BUCK##num, \
+ .ops = &s2mps14_reg_ops, \
+ .type = REGULATOR_VOLTAGE, \
+ .owner = THIS_MODULE, \
+ .min_uV = min, \
+ .uV_step = step, \
+ .linear_min_sel = min_sel, \
+ .n_voltages = S2MPS14_BUCK_N_VOLTAGES, \
+ .ramp_delay = S2MPS13_BUCK_RAMP_DELAY, \
+ .vsel_reg = S2MPS13_REG_B1OUT + (num - 1) * 2, \
+ .vsel_mask = S2MPS14_BUCK_VSEL_MASK, \
+ .enable_reg = S2MPS13_REG_B1CTRL + (num - 1) * 2, \
+ .enable_mask = S2MPS14_ENABLE_MASK \
+}
+
+static const struct regulator_desc s2mps13_regulators[] = {
+ regulator_desc_s2mps13_ldo(1, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(2, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(3, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(4, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(5, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(6, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(7, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(8, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(9, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(10, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(11, MIN_800_MV, STEP_25_MV, 0x10),
+ regulator_desc_s2mps13_ldo(12, MIN_800_MV, STEP_25_MV, 0x10),
+ regulator_desc_s2mps13_ldo(13, MIN_800_MV, STEP_25_MV, 0x10),
+ regulator_desc_s2mps13_ldo(14, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(15, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(16, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(17, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(18, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(19, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(20, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(21, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(22, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(23, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(24, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(25, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(26, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(27, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(28, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(29, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(30, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(31, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(32, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(33, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(34, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(35, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(36, MIN_800_MV, STEP_12_5_MV, 0x00),
+ regulator_desc_s2mps13_ldo(37, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(38, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_ldo(39, MIN_1000_MV, STEP_25_MV, 0x08),
+ regulator_desc_s2mps13_ldo(40, MIN_1400_MV, STEP_50_MV, 0x0C),
+ regulator_desc_s2mps13_buck(1, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(2, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(3, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(4, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(5, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(6, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(7, MIN_500_MV, STEP_6_25_MV, 0x10),
+ regulator_desc_s2mps13_buck(8, MIN_1000_MV, STEP_12_5_MV, 0x20),
+ regulator_desc_s2mps13_buck(9, MIN_1000_MV, STEP_12_5_MV, 0x20),
+ regulator_desc_s2mps13_buck(10, MIN_500_MV, STEP_6_25_MV, 0x10),
+};
+
static int s2mps14_regulator_enable(struct regulator_dev *rdev)
{
struct s2mps11_info *s2mps11 = rdev_get_drvdata(rdev);
unsigned int val;
switch (s2mps11->dev_type) {
+ case S2MPS13X:
case S2MPS14X:
if (s2mps11->s2mps14_suspend_state & (1 << rdev_get_id(rdev)))
val = S2MPS14_ENABLE_SUSPEND;
@@ -406,6 +496,7 @@ static int s2mps14_regulator_set_suspend_disable(struct regulator_dev *rdev)
/* Below LDO should be always on or does not support suspend mode. */
switch (s2mps11->dev_type) {
+ case S2MPS13X:
case S2MPS14X:
switch (rdev_id) {
case S2MPS14_LDO3:
@@ -831,6 +922,10 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
s2mps11->rdev_num = ARRAY_SIZE(s2mps11_regulators);
regulators = s2mps11_regulators;
break;
+ case S2MPS13X:
+ s2mps11->rdev_num = ARRAY_SIZE(s2mps13_regulators);
+ regulators = s2mps13_regulators;
+ break;
case S2MPS14X:
s2mps11->rdev_num = ARRAY_SIZE(s2mps14_regulators);
regulators = s2mps14_regulators;
@@ -845,7 +940,7 @@ static int s2mps11_pmic_probe(struct platform_device *pdev)
return -EINVAL;
};
- s2mps11->ext_control_gpio = devm_kzalloc(&pdev->dev,
+ s2mps11->ext_control_gpio = devm_kmalloc(&pdev->dev,
sizeof(*s2mps11->ext_control_gpio) * s2mps11->rdev_num,
GFP_KERNEL);
if (!s2mps11->ext_control_gpio)
@@ -886,6 +981,7 @@ common_reg:
config.regmap = iodev->regmap_pmic;
config.driver_data = s2mps11;
config.ena_gpio_flags = GPIOF_OUT_INIT_HIGH;
+ config.ena_gpio_initialized = true;
for (i = 0; i < s2mps11->rdev_num; i++) {
struct regulator_dev *regulator;
@@ -927,6 +1023,7 @@ out:
static const struct platform_device_id s2mps11_pmic_id[] = {
{ "s2mps11-pmic", S2MPS11X},
+ { "s2mps13-pmic", S2MPS13X},
{ "s2mps14-pmic", S2MPS14X},
{ "s2mpu02-pmic", S2MPU02},
{ },
diff --git a/drivers/regulator/s5m8767.c b/drivers/regulator/s5m8767.c
index 0ab5cbe..dc1328c 100644
--- a/drivers/regulator/s5m8767.c
+++ b/drivers/regulator/s5m8767.c
@@ -581,7 +581,8 @@ static int s5m8767_pmic_dt_parse_pdata(struct platform_device *pdev,
rdata->id = i;
rdata->initdata = of_get_regulator_init_data(
- &pdev->dev, reg_np);
+ &pdev->dev, reg_np,
+ &regulators[i]);
rdata->reg_node = reg_np;
rdata++;
rmode->id = i;
@@ -950,6 +951,7 @@ static int s5m8767_pmic_probe(struct platform_device *pdev)
config.of_node = pdata->regulators[i].reg_node;
config.ena_gpio = -EINVAL;
config.ena_gpio_flags = 0;
+ config.ena_gpio_initialized = true;
if (gpio_is_valid(pdata->regulators[i].ext_control_gpio))
s5m8767_regulator_config_ext_control(s5m8767,
&pdata->regulators[i], &config);
diff --git a/drivers/regulator/sky81452-regulator.c b/drivers/regulator/sky81452-regulator.c
index 97aff0c..6478606 100644
--- a/drivers/regulator/sky81452-regulator.c
+++ b/drivers/regulator/sky81452-regulator.c
@@ -5,9 +5,8 @@
* Author : Gyungoh Yoo <jack.yoo@skyworksinc.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, or (at your option) any
- * later version.
+ * 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
@@ -52,6 +51,8 @@ static const struct regulator_linear_range sky81452_reg_ranges[] = {
static const struct regulator_desc sky81452_reg = {
.name = "LOUT",
+ .of_match = of_match_ptr("lout"),
+ .regulators_node = of_match_ptr("regulator"),
.ops = &sky81452_reg_ops,
.type = REGULATOR_VOLTAGE,
.owner = THIS_MODULE,
@@ -64,30 +65,6 @@ static const struct regulator_desc sky81452_reg = {
.enable_mask = SKY81452_LEN,
};
-#ifdef CONFIG_OF
-static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev)
-{
- struct regulator_init_data *init_data;
- struct device_node *np;
-
- np = of_get_child_by_name(dev->parent->of_node, "regulator");
- if (unlikely(!np)) {
- dev_err(dev, "regulator node not found");
- return NULL;
- }
-
- init_data = of_get_regulator_init_data(dev, np);
-
- of_node_put(np);
- return init_data;
-}
-#else
-static struct regulator_init_data *sky81452_reg_parse_dt(struct device *dev)
-{
- return ERR_PTR(-EINVAL);
-}
-#endif
-
static int sky81452_reg_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
@@ -95,20 +72,16 @@ static int sky81452_reg_probe(struct platform_device *pdev)
struct regulator_config config = { };
struct regulator_dev *rdev;
- if (!init_data) {
- init_data = sky81452_reg_parse_dt(dev);
- if (IS_ERR(init_data))
- return PTR_ERR(init_data);
- }
-
- config.dev = dev;
+ config.dev = dev->parent;
config.init_data = init_data;
config.of_node = dev->of_node;
config.regmap = dev_get_drvdata(dev->parent);
rdev = devm_regulator_register(dev, &sky81452_reg, &config);
- if (IS_ERR(rdev))
+ if (IS_ERR(rdev)) {
+ dev_err(dev, "failed to register. err=%ld\n", PTR_ERR(rdev));
return PTR_ERR(rdev);
+ }
platform_set_drvdata(pdev, rdev);
@@ -126,5 +99,4 @@ module_platform_driver(sky81452_reg_driver);
MODULE_DESCRIPTION("Skyworks SKY81452 Regulator driver");
MODULE_AUTHOR("Gyungoh Yoo <jack.yoo@skyworksinc.com>");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("1.0");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/regulator/stw481x-vmmc.c b/drivers/regulator/stw481x-vmmc.c
index a7e1526..b4f1696 100644
--- a/drivers/regulator/stw481x-vmmc.c
+++ b/drivers/regulator/stw481x-vmmc.c
@@ -72,7 +72,8 @@ static int stw481x_vmmc_regulator_probe(struct platform_device *pdev)
config.regmap = stw481x->map;
config.of_node = pdev->dev.of_node;
config.init_data = of_get_regulator_init_data(&pdev->dev,
- pdev->dev.of_node);
+ pdev->dev.of_node,
+ &vmmc_regulator);
stw481x->vmmc_regulator = devm_regulator_register(&pdev->dev,
&vmmc_regulator, &config);
diff --git a/drivers/regulator/ti-abb-regulator.c b/drivers/regulator/ti-abb-regulator.c
index a2dabb5..1ef5aba 100644
--- a/drivers/regulator/ti-abb-regulator.c
+++ b/drivers/regulator/ti-abb-regulator.c
@@ -837,7 +837,8 @@ skip_opt:
return -EINVAL;
}
- initdata = of_get_regulator_init_data(dev, pdev->dev.of_node);
+ initdata = of_get_regulator_init_data(dev, pdev->dev.of_node,
+ &abb->rdesc);
if (!initdata) {
dev_err(dev, "%s: Unable to alloc regulator init data\n",
__func__);
diff --git a/drivers/regulator/tps51632-regulator.c b/drivers/regulator/tps51632-regulator.c
index f31f22e..c213e37 100644
--- a/drivers/regulator/tps51632-regulator.c
+++ b/drivers/regulator/tps51632-regulator.c
@@ -221,7 +221,8 @@ static const struct of_device_id tps51632_of_match[] = {
MODULE_DEVICE_TABLE(of, tps51632_of_match);
static struct tps51632_regulator_platform_data *
- of_get_tps51632_platform_data(struct device *dev)
+ of_get_tps51632_platform_data(struct device *dev,
+ const struct regulator_desc *desc)
{
struct tps51632_regulator_platform_data *pdata;
struct device_node *np = dev->of_node;
@@ -230,7 +231,8 @@ static struct tps51632_regulator_platform_data *
if (!pdata)
return NULL;
- pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
+ pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node,
+ desc);
if (!pdata->reg_init_data) {
dev_err(dev, "Not able to get OF regulator init data\n");
return NULL;
@@ -248,7 +250,8 @@ static struct tps51632_regulator_platform_data *
}
#else
static struct tps51632_regulator_platform_data *
- of_get_tps51632_platform_data(struct device *dev)
+ of_get_tps51632_platform_data(struct device *dev,
+ const struct regulator_desc *desc)
{
return NULL;
}
@@ -273,9 +276,25 @@ static int tps51632_probe(struct i2c_client *client,
}
}
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps)
+ return -ENOMEM;
+
+ tps->dev = &client->dev;
+ tps->desc.name = client->name;
+ tps->desc.id = 0;
+ tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY;
+ tps->desc.min_uV = TPS51632_MIN_VOLTAGE;
+ tps->desc.uV_step = TPS51632_VOLTAGE_STEP_10mV;
+ tps->desc.linear_min_sel = TPS51632_MIN_VSEL;
+ tps->desc.n_voltages = TPS51632_MAX_VSEL + 1;
+ tps->desc.ops = &tps51632_dcdc_ops;
+ tps->desc.type = REGULATOR_VOLTAGE;
+ tps->desc.owner = THIS_MODULE;
+
pdata = dev_get_platdata(&client->dev);
if (!pdata && client->dev.of_node)
- pdata = of_get_tps51632_platform_data(&client->dev);
+ pdata = of_get_tps51632_platform_data(&client->dev, &tps->desc);
if (!pdata) {
dev_err(&client->dev, "No Platform data\n");
return -EINVAL;
@@ -296,22 +315,6 @@ static int tps51632_probe(struct i2c_client *client,
}
}
- tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
- if (!tps)
- return -ENOMEM;
-
- tps->dev = &client->dev;
- tps->desc.name = client->name;
- tps->desc.id = 0;
- tps->desc.ramp_delay = TPS51632_DEFAULT_RAMP_DELAY;
- tps->desc.min_uV = TPS51632_MIN_VOLTAGE;
- tps->desc.uV_step = TPS51632_VOLTAGE_STEP_10mV;
- tps->desc.linear_min_sel = TPS51632_MIN_VSEL;
- tps->desc.n_voltages = TPS51632_MAX_VSEL + 1;
- tps->desc.ops = &tps51632_dcdc_ops;
- tps->desc.type = REGULATOR_VOLTAGE;
- tps->desc.owner = THIS_MODULE;
-
if (pdata->enable_pwm_dvfs)
tps->desc.vsel_reg = TPS51632_VOLTAGE_BASE_REG;
else
diff --git a/drivers/regulator/tps62360-regulator.c b/drivers/regulator/tps62360-regulator.c
index a167204..a1fd626 100644
--- a/drivers/regulator/tps62360-regulator.c
+++ b/drivers/regulator/tps62360-regulator.c
@@ -293,7 +293,8 @@ static const struct regmap_config tps62360_regmap_config = {
};
static struct tps62360_regulator_platform_data *
- of_get_tps62360_platform_data(struct device *dev)
+ of_get_tps62360_platform_data(struct device *dev,
+ const struct regulator_desc *desc)
{
struct tps62360_regulator_platform_data *pdata;
struct device_node *np = dev->of_node;
@@ -302,7 +303,8 @@ static struct tps62360_regulator_platform_data *
if (!pdata)
return NULL;
- pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node);
+ pdata->reg_init_data = of_get_regulator_init_data(dev, dev->of_node,
+ desc);
if (!pdata->reg_init_data) {
dev_err(dev, "Not able to get OF regulator init data\n");
return NULL;
@@ -350,6 +352,17 @@ static int tps62360_probe(struct i2c_client *client,
pdata = dev_get_platdata(&client->dev);
+ tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
+ if (!tps)
+ return -ENOMEM;
+
+ tps->desc.name = client->name;
+ tps->desc.id = 0;
+ tps->desc.ops = &tps62360_dcdc_ops;
+ tps->desc.type = REGULATOR_VOLTAGE;
+ tps->desc.owner = THIS_MODULE;
+ tps->desc.uV_step = 10000;
+
if (client->dev.of_node) {
const struct of_device_id *match;
match = of_match_device(of_match_ptr(tps62360_of_match),
@@ -360,7 +373,8 @@ static int tps62360_probe(struct i2c_client *client,
}
chip_id = (int)(long)match->data;
if (!pdata)
- pdata = of_get_tps62360_platform_data(&client->dev);
+ pdata = of_get_tps62360_platform_data(&client->dev,
+ &tps->desc);
} else if (id) {
chip_id = id->driver_data;
} else {
@@ -374,10 +388,6 @@ static int tps62360_probe(struct i2c_client *client,
return -EIO;
}
- tps = devm_kzalloc(&client->dev, sizeof(*tps), GFP_KERNEL);
- if (!tps)
- return -ENOMEM;
-
tps->en_discharge = pdata->en_discharge;
tps->en_internal_pulldn = pdata->en_internal_pulldn;
tps->vsel0_gpio = pdata->vsel0_gpio;
@@ -401,13 +411,6 @@ static int tps62360_probe(struct i2c_client *client,
return -ENODEV;
}
- tps->desc.name = client->name;
- tps->desc.id = 0;
- tps->desc.ops = &tps62360_dcdc_ops;
- tps->desc.type = REGULATOR_VOLTAGE;
- tps->desc.owner = THIS_MODULE;
- tps->desc.uV_step = 10000;
-
tps->regmap = devm_regmap_init_i2c(client, &tps62360_regmap_config);
if (IS_ERR(tps->regmap)) {
ret = PTR_ERR(tps->regmap);
diff --git a/drivers/regulator/tps65090-regulator.c b/drivers/regulator/tps65090-regulator.c
index d5df1e9..f1df442 100644
--- a/drivers/regulator/tps65090-regulator.c
+++ b/drivers/regulator/tps65090-regulator.c
@@ -312,7 +312,11 @@ static void tps65090_configure_regulator_config(
gpio_flag = GPIOF_OUT_INIT_HIGH;
config->ena_gpio = tps_pdata->gpio;
+ config->ena_gpio_initialized = true;
config->ena_gpio_flags = gpio_flag;
+ } else {
+ config->ena_gpio = -EINVAL;
+ config->ena_gpio_initialized = false;
}
}
diff --git a/drivers/regulator/tps65218-regulator.c b/drivers/regulator/tps65218-regulator.c
index f0a4028..263cc85 100644
--- a/drivers/regulator/tps65218-regulator.c
+++ b/drivers/regulator/tps65218-regulator.c
@@ -231,7 +231,8 @@ static int tps65218_regulator_probe(struct platform_device *pdev)
template = match->data;
id = template->id;
- init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+ init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
+ &regulators[id]);
platform_set_drvdata(pdev, tps);
diff --git a/drivers/regulator/twl-regulator.c b/drivers/regulator/twl-regulator.c
index 0b4f866..dd727bc 100644
--- a/drivers/regulator/twl-regulator.c
+++ b/drivers/regulator/twl-regulator.c
@@ -1104,7 +1104,8 @@ static int twlreg_probe(struct platform_device *pdev)
template = match->data;
id = template->desc.id;
initdata = of_get_regulator_init_data(&pdev->dev,
- pdev->dev.of_node);
+ pdev->dev.of_node,
+ &template->desc);
drvdata = NULL;
} else {
id = pdev->id;
diff --git a/drivers/regulator/vexpress.c b/drivers/regulator/vexpress.c
index 02e7267..5e7c789 100644
--- a/drivers/regulator/vexpress.c
+++ b/drivers/regulator/vexpress.c
@@ -74,7 +74,8 @@ static int vexpress_regulator_probe(struct platform_device *pdev)
reg->desc.owner = THIS_MODULE;
reg->desc.continuous_voltage_range = true;
- init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node);
+ init_data = of_get_regulator_init_data(&pdev->dev, pdev->dev.of_node,
+ &reg->desc);
if (!init_data)
return -EINVAL;
diff --git a/drivers/regulator/wm8994-regulator.c b/drivers/regulator/wm8994-regulator.c
index c24346d..88f5064 100644
--- a/drivers/regulator/wm8994-regulator.c
+++ b/drivers/regulator/wm8994-regulator.c
@@ -145,10 +145,12 @@ static int wm8994_ldo_probe(struct platform_device *pdev)
config.driver_data = ldo;
config.regmap = wm8994->regmap;
config.init_data = &ldo->init_data;
- if (pdata)
+ if (pdata) {
config.ena_gpio = pdata->ldo[id].enable;
- else if (wm8994->dev->of_node)
+ } else if (wm8994->dev->of_node) {
config.ena_gpio = wm8994->pdata.ldo[id].enable;
+ config.ena_gpio_initialized = true;
+ }
/* Use default constraints if none set up */
if (!pdata || !pdata->ldo[id].init_data || wm8994->dev->of_node) {
diff --git a/drivers/remoteproc/omap_remoteproc.c b/drivers/remoteproc/omap_remoteproc.c
index 5168972..cf92f6e 100644
--- a/drivers/remoteproc/omap_remoteproc.c
+++ b/drivers/remoteproc/omap_remoteproc.c
@@ -27,6 +27,7 @@
#include <linux/platform_device.h>
#include <linux/dma-mapping.h>
#include <linux/remoteproc.h>
+#include <linux/mailbox_client.h>
#include <linux/omap-mailbox.h>
#include <linux/platform_data/remoteproc-omap.h>
@@ -36,20 +37,19 @@
/**
* struct omap_rproc - omap remote processor state
- * @mbox: omap mailbox handle
- * @nb: notifier block that will be invoked on inbound mailbox messages
+ * @mbox: mailbox channel handle
+ * @client: mailbox client to request the mailbox channel
* @rproc: rproc handle
*/
struct omap_rproc {
- struct omap_mbox *mbox;
- struct notifier_block nb;
+ struct mbox_chan *mbox;
+ struct mbox_client client;
struct rproc *rproc;
};
/**
* omap_rproc_mbox_callback() - inbound mailbox message handler
- * @this: notifier block
- * @index: unused
+ * @client: mailbox client pointer used for requesting the mailbox channel
* @data: mailbox payload
*
* This handler is invoked by omap's mailbox driver whenever a mailbox
@@ -61,13 +61,13 @@ struct omap_rproc {
* that indicates different events. Those values are deliberately very
* big so they don't coincide with virtqueue indices.
*/
-static int omap_rproc_mbox_callback(struct notifier_block *this,
- unsigned long index, void *data)
+static void omap_rproc_mbox_callback(struct mbox_client *client, void *data)
{
- mbox_msg_t msg = (mbox_msg_t) data;
- struct omap_rproc *oproc = container_of(this, struct omap_rproc, nb);
+ struct omap_rproc *oproc = container_of(client, struct omap_rproc,
+ client);
struct device *dev = oproc->rproc->dev.parent;
const char *name = oproc->rproc->name;
+ u32 msg = (u32)data;
dev_dbg(dev, "mbox msg: 0x%x\n", msg);
@@ -84,8 +84,6 @@ static int omap_rproc_mbox_callback(struct notifier_block *this,
if (rproc_vq_interrupt(oproc->rproc, msg) == IRQ_NONE)
dev_dbg(dev, "no message was found in vqid %d\n", msg);
}
-
- return NOTIFY_DONE;
}
/* kick a virtqueue */
@@ -96,8 +94,8 @@ static void omap_rproc_kick(struct rproc *rproc, int vqid)
int ret;
/* send the index of the triggered virtqueue in the mailbox payload */
- ret = omap_mbox_msg_send(oproc->mbox, vqid);
- if (ret)
+ ret = mbox_send_message(oproc->mbox, (void *)vqid);
+ if (ret < 0)
dev_err(dev, "omap_mbox_msg_send failed: %d\n", ret);
}
@@ -115,17 +113,22 @@ static int omap_rproc_start(struct rproc *rproc)
struct platform_device *pdev = to_platform_device(dev);
struct omap_rproc_pdata *pdata = pdev->dev.platform_data;
int ret;
+ struct mbox_client *client = &oproc->client;
if (pdata->set_bootaddr)
pdata->set_bootaddr(rproc->bootaddr);
- oproc->nb.notifier_call = omap_rproc_mbox_callback;
+ client->dev = dev;
+ client->tx_done = NULL;
+ client->rx_callback = omap_rproc_mbox_callback;
+ client->tx_block = false;
+ client->knows_txdone = false;
- /* every omap rproc is assigned a mailbox instance for messaging */
- oproc->mbox = omap_mbox_get(pdata->mbox_name, &oproc->nb);
+ oproc->mbox = omap_mbox_request_channel(client, pdata->mbox_name);
if (IS_ERR(oproc->mbox)) {
- ret = PTR_ERR(oproc->mbox);
- dev_err(dev, "omap_mbox_get failed: %d\n", ret);
+ ret = -EBUSY;
+ dev_err(dev, "mbox_request_channel failed: %ld\n",
+ PTR_ERR(oproc->mbox));
return ret;
}
@@ -136,9 +139,9 @@ static int omap_rproc_start(struct rproc *rproc)
* Note that the reply will _not_ arrive immediately: this message
* will wait in the mailbox fifo until the remote processor is booted.
*/
- ret = omap_mbox_msg_send(oproc->mbox, RP_MBOX_ECHO_REQUEST);
- if (ret) {
- dev_err(dev, "omap_mbox_get failed: %d\n", ret);
+ ret = mbox_send_message(oproc->mbox, (void *)RP_MBOX_ECHO_REQUEST);
+ if (ret < 0) {
+ dev_err(dev, "mbox_send_message failed: %d\n", ret);
goto put_mbox;
}
@@ -151,7 +154,7 @@ static int omap_rproc_start(struct rproc *rproc)
return 0;
put_mbox:
- omap_mbox_put(oproc->mbox, &oproc->nb);
+ mbox_free_channel(oproc->mbox);
return ret;
}
@@ -168,7 +171,7 @@ static int omap_rproc_stop(struct rproc *rproc)
if (ret)
return ret;
- omap_mbox_put(oproc->mbox, &oproc->nb);
+ mbox_free_channel(oproc->mbox);
return 0;
}
diff --git a/drivers/remoteproc/remoteproc_virtio.c b/drivers/remoteproc/remoteproc_virtio.c
index a34b506..e1a1023 100644
--- a/drivers/remoteproc/remoteproc_virtio.c
+++ b/drivers/remoteproc/remoteproc_virtio.c
@@ -207,7 +207,7 @@ static void rproc_virtio_reset(struct virtio_device *vdev)
}
/* provide the vdev features as retrieved from the firmware */
-static u32 rproc_virtio_get_features(struct virtio_device *vdev)
+static u64 rproc_virtio_get_features(struct virtio_device *vdev)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
@@ -217,7 +217,7 @@ static u32 rproc_virtio_get_features(struct virtio_device *vdev)
return rsc->dfeatures;
}
-static void rproc_virtio_finalize_features(struct virtio_device *vdev)
+static int rproc_virtio_finalize_features(struct virtio_device *vdev)
{
struct rproc_vdev *rvdev = vdev_to_rvdev(vdev);
struct fw_rsc_vdev *rsc;
@@ -227,11 +227,16 @@ static void rproc_virtio_finalize_features(struct virtio_device *vdev)
/* Give virtio_ring a chance to accept features */
vring_transport_features(vdev);
+ /* Make sure we don't have any features > 32 bits! */
+ BUG_ON((u32)vdev->features != vdev->features);
+
/*
* Remember the finalized features of our vdev, and provide it
* to the remote processor once it is powered on.
*/
- rsc->gfeatures = vdev->features[0];
+ rsc->gfeatures = vdev->features;
+
+ return 0;
}
static void rproc_virtio_get(struct virtio_device *vdev, unsigned offset,
diff --git a/drivers/reset/Makefile b/drivers/reset/Makefile
index 60fed3d..157d421 100644
--- a/drivers/reset/Makefile
+++ b/drivers/reset/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_RESET_CONTROLLER) += core.o
obj-$(CONFIG_ARCH_SOCFPGA) += reset-socfpga.o
+obj-$(CONFIG_ARCH_BERLIN) += reset-berlin.o
obj-$(CONFIG_ARCH_SUNXI) += reset-sunxi.o
obj-$(CONFIG_ARCH_STI) += sti/
diff --git a/drivers/reset/core.c b/drivers/reset/core.c
index baeaf82..7955e00 100644
--- a/drivers/reset/core.c
+++ b/drivers/reset/core.c
@@ -126,6 +126,21 @@ int reset_control_deassert(struct reset_control *rstc)
EXPORT_SYMBOL_GPL(reset_control_deassert);
/**
+ * reset_control_status - returns a negative errno if not supported, a
+ * positive value if the reset line is asserted, or zero if the reset
+ * line is not asserted.
+ * @rstc: reset controller
+ */
+int reset_control_status(struct reset_control *rstc)
+{
+ if (rstc->rcdev->ops->status)
+ return rstc->rcdev->ops->status(rstc->rcdev, rstc->id);
+
+ return -ENOSYS;
+}
+EXPORT_SYMBOL_GPL(reset_control_status);
+
+/**
* of_reset_control_get - Lookup and obtain a reference to a reset controller.
* @node: device to be reset by the controller
* @id: reset line name
diff --git a/drivers/reset/reset-berlin.c b/drivers/reset/reset-berlin.c
new file mode 100644
index 0000000..f8b48a1
--- /dev/null
+++ b/drivers/reset/reset-berlin.c
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2014 Marvell Technology Group Ltd.
+ *
+ * Antoine Tenart <antoine.tenart@free-electrons.com>
+ * Sebastian Hesselbarth <sebastian.hesselbarth@gmail.com>
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2. This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/delay.h>
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_address.h>
+#include <linux/platform_device.h>
+#include <linux/reset-controller.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#define BERLIN_MAX_RESETS 32
+
+#define to_berlin_reset_priv(p) \
+ container_of((p), struct berlin_reset_priv, rcdev)
+
+struct berlin_reset_priv {
+ void __iomem *base;
+ unsigned int size;
+ struct reset_controller_dev rcdev;
+};
+
+static int berlin_reset_reset(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev);
+ int offset = id >> 8;
+ int mask = BIT(id & 0x1f);
+
+ writel(mask, priv->base + offset);
+
+ /* let the reset be effective */
+ udelay(10);
+
+ return 0;
+}
+
+static struct reset_control_ops berlin_reset_ops = {
+ .reset = berlin_reset_reset,
+};
+
+static int berlin_reset_xlate(struct reset_controller_dev *rcdev,
+ const struct of_phandle_args *reset_spec)
+{
+ struct berlin_reset_priv *priv = to_berlin_reset_priv(rcdev);
+ unsigned offset, bit;
+
+ if (WARN_ON(reset_spec->args_count != rcdev->of_reset_n_cells))
+ return -EINVAL;
+
+ offset = reset_spec->args[0];
+ bit = reset_spec->args[1];
+
+ if (offset >= priv->size)
+ return -EINVAL;
+
+ if (bit >= BERLIN_MAX_RESETS)
+ return -EINVAL;
+
+ return (offset << 8) | bit;
+}
+
+static int __berlin_reset_init(struct device_node *np)
+{
+ struct berlin_reset_priv *priv;
+ struct resource res;
+ resource_size_t size;
+ int ret;
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ ret = of_address_to_resource(np, 0, &res);
+ if (ret)
+ goto err;
+
+ size = resource_size(&res);
+ priv->base = ioremap(res.start, size);
+ if (!priv->base) {
+ ret = -ENOMEM;
+ goto err;
+ }
+ priv->size = size;
+
+ priv->rcdev.owner = THIS_MODULE;
+ priv->rcdev.ops = &berlin_reset_ops;
+ priv->rcdev.of_node = np;
+ priv->rcdev.of_reset_n_cells = 2;
+ priv->rcdev.of_xlate = berlin_reset_xlate;
+
+ reset_controller_register(&priv->rcdev);
+
+ return 0;
+
+err:
+ kfree(priv);
+ return ret;
+}
+
+static const struct of_device_id berlin_reset_of_match[] __initconst = {
+ { .compatible = "marvell,berlin2-chip-ctrl" },
+ { .compatible = "marvell,berlin2cd-chip-ctrl" },
+ { .compatible = "marvell,berlin2q-chip-ctrl" },
+ { },
+};
+
+static int __init berlin_reset_init(void)
+{
+ struct device_node *np;
+ int ret;
+
+ for_each_matching_node(np, berlin_reset_of_match) {
+ ret = __berlin_reset_init(np);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+arch_initcall(berlin_reset_init);
diff --git a/drivers/reset/reset-socfpga.c b/drivers/reset/reset-socfpga.c
index 79c32ca..4058208 100644
--- a/drivers/reset/reset-socfpga.c
+++ b/drivers/reset/reset-socfpga.c
@@ -76,9 +76,24 @@ static int socfpga_reset_deassert(struct reset_controller_dev *rcdev,
return 0;
}
+static int socfpga_reset_status(struct reset_controller_dev *rcdev,
+ unsigned long id)
+{
+ struct socfpga_reset_data *data = container_of(rcdev,
+ struct socfpga_reset_data, rcdev);
+ int bank = id / BITS_PER_LONG;
+ int offset = id % BITS_PER_LONG;
+ u32 reg;
+
+ reg = readl(data->membase + OFFSET_MODRST + (bank * NR_BANKS));
+
+ return !(reg & BIT(offset));
+}
+
static struct reset_control_ops socfpga_reset_ops = {
.assert = socfpga_reset_assert,
.deassert = socfpga_reset_deassert,
+ .status = socfpga_reset_status,
};
static int socfpga_reset_probe(struct platform_device *pdev)
diff --git a/drivers/reset/sti/Kconfig b/drivers/reset/sti/Kconfig
index 88d2d03..f8c15a3 100644
--- a/drivers/reset/sti/Kconfig
+++ b/drivers/reset/sti/Kconfig
@@ -12,4 +12,8 @@ config STIH416_RESET
bool
select STI_RESET_SYSCFG
+config STIH407_RESET
+ bool
+ select STI_RESET_SYSCFG
+
endif
diff --git a/drivers/reset/sti/Makefile b/drivers/reset/sti/Makefile
index be1c976..dc85dfb 100644
--- a/drivers/reset/sti/Makefile
+++ b/drivers/reset/sti/Makefile
@@ -2,3 +2,4 @@ obj-$(CONFIG_STI_RESET_SYSCFG) += reset-syscfg.o
obj-$(CONFIG_STIH415_RESET) += reset-stih415.o
obj-$(CONFIG_STIH416_RESET) += reset-stih416.o
+obj-$(CONFIG_STIH407_RESET) += reset-stih407.o
diff --git a/drivers/reset/sti/reset-stih407.c b/drivers/reset/sti/reset-stih407.c
new file mode 100644
index 0000000..d83db5d7
--- /dev/null
+++ b/drivers/reset/sti/reset-stih407.c
@@ -0,0 +1,158 @@
+/*
+ * Copyright (C) 2014 STMicroelectronics (R&D) Limited
+ * Author: Giuseppe Cavallaro <peppe.cavallaro@st.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <dt-bindings/reset-controller/stih407-resets.h>
+#include "reset-syscfg.h"
+
+/* STiH407 Peripheral powerdown definitions. */
+static const char stih407_core[] = "st,stih407-core-syscfg";
+static const char stih407_sbc_reg[] = "st,stih407-sbc-reg-syscfg";
+static const char stih407_lpm[] = "st,stih407-lpm-syscfg";
+
+#define STIH407_PDN_0(_bit) \
+ _SYSCFG_RST_CH(stih407_core, SYSCFG_5000, _bit, SYSSTAT_5500, _bit)
+#define STIH407_PDN_1(_bit) \
+ _SYSCFG_RST_CH(stih407_core, SYSCFG_5001, _bit, SYSSTAT_5501, _bit)
+#define STIH407_PDN_ETH(_bit, _stat) \
+ _SYSCFG_RST_CH(stih407_sbc_reg, SYSCFG_4032, _bit, SYSSTAT_4520, _stat)
+
+/* Powerdown requests control 0 */
+#define SYSCFG_5000 0x0
+#define SYSSTAT_5500 0x7d0
+/* Powerdown requests control 1 (High Speed Links) */
+#define SYSCFG_5001 0x4
+#define SYSSTAT_5501 0x7d4
+
+/* Ethernet powerdown/status/reset */
+#define SYSCFG_4032 0x80
+#define SYSSTAT_4520 0x820
+#define SYSCFG_4002 0x8
+
+static const struct syscfg_reset_channel_data stih407_powerdowns[] = {
+ [STIH407_EMISS_POWERDOWN] = STIH407_PDN_0(1),
+ [STIH407_NAND_POWERDOWN] = STIH407_PDN_0(0),
+ [STIH407_USB3_POWERDOWN] = STIH407_PDN_1(6),
+ [STIH407_USB2_PORT1_POWERDOWN] = STIH407_PDN_1(5),
+ [STIH407_USB2_PORT0_POWERDOWN] = STIH407_PDN_1(4),
+ [STIH407_PCIE1_POWERDOWN] = STIH407_PDN_1(3),
+ [STIH407_PCIE0_POWERDOWN] = STIH407_PDN_1(2),
+ [STIH407_SATA1_POWERDOWN] = STIH407_PDN_1(1),
+ [STIH407_SATA0_POWERDOWN] = STIH407_PDN_1(0),
+ [STIH407_ETH1_POWERDOWN] = STIH407_PDN_ETH(0, 2),
+};
+
+/* Reset Generator control 0/1 */
+#define SYSCFG_5131 0x20c
+#define SYSCFG_5132 0x210
+
+#define LPM_SYSCFG_1 0x4 /* Softreset IRB & SBC UART */
+
+#define STIH407_SRST_CORE(_reg, _bit) \
+ _SYSCFG_RST_CH_NO_ACK(stih407_core, _reg, _bit)
+
+#define STIH407_SRST_SBC(_reg, _bit) \
+ _SYSCFG_RST_CH_NO_ACK(stih407_sbc_reg, _reg, _bit)
+
+#define STIH407_SRST_LPM(_reg, _bit) \
+ _SYSCFG_RST_CH_NO_ACK(stih407_lpm, _reg, _bit)
+
+static const struct syscfg_reset_channel_data stih407_softresets[] = {
+ [STIH407_ETH1_SOFTRESET] = STIH407_SRST_SBC(SYSCFG_4002, 4),
+ [STIH407_MMC1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 3),
+ [STIH407_USB2_PORT0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 28),
+ [STIH407_USB2_PORT1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 29),
+ [STIH407_PICOPHY_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 30),
+ [STIH407_IRB_SOFTRESET] = STIH407_SRST_LPM(LPM_SYSCFG_1, 6),
+ [STIH407_PCIE0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 6),
+ [STIH407_PCIE1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 15),
+ [STIH407_SATA0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 7),
+ [STIH407_SATA1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 16),
+ [STIH407_MIPHY0_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 4),
+ [STIH407_MIPHY1_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 13),
+ [STIH407_MIPHY2_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 22),
+ [STIH407_SATA0_PWR_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 5),
+ [STIH407_SATA1_PWR_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 14),
+ [STIH407_DELTA_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 3),
+ [STIH407_BLITTER_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 10),
+ [STIH407_HDTVOUT_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 11),
+ [STIH407_HDQVDP_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 12),
+ [STIH407_VDP_AUX_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 14),
+ [STIH407_COMPO_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 15),
+ [STIH407_HDMI_TX_PHY_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 21),
+ [STIH407_JPEG_DEC_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 23),
+ [STIH407_VP8_DEC_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 24),
+ [STIH407_GPU_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5131, 30),
+ [STIH407_HVA_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 0),
+ [STIH407_ERAM_HVA_SOFTRESET] = STIH407_SRST_CORE(SYSCFG_5132, 1),
+ [STIH407_LPM_SOFTRESET] = STIH407_SRST_SBC(SYSCFG_4002, 2),
+ [STIH407_KEYSCAN_SOFTRESET] = STIH407_SRST_LPM(LPM_SYSCFG_1, 8),
+};
+
+/* PicoPHY reset/control */
+#define SYSCFG_5061 0x0f4
+
+static const struct syscfg_reset_channel_data stih407_picophyresets[] = {
+ [STIH407_PICOPHY0_RESET] = STIH407_SRST_CORE(SYSCFG_5061, 5),
+ [STIH407_PICOPHY1_RESET] = STIH407_SRST_CORE(SYSCFG_5061, 6),
+ [STIH407_PICOPHY2_RESET] = STIH407_SRST_CORE(SYSCFG_5061, 7),
+};
+
+static const struct syscfg_reset_controller_data stih407_powerdown_controller = {
+ .wait_for_ack = true,
+ .nr_channels = ARRAY_SIZE(stih407_powerdowns),
+ .channels = stih407_powerdowns,
+};
+
+static const struct syscfg_reset_controller_data stih407_softreset_controller = {
+ .wait_for_ack = false,
+ .active_low = true,
+ .nr_channels = ARRAY_SIZE(stih407_softresets),
+ .channels = stih407_softresets,
+};
+
+static const struct syscfg_reset_controller_data stih407_picophyreset_controller = {
+ .wait_for_ack = false,
+ .nr_channels = ARRAY_SIZE(stih407_picophyresets),
+ .channels = stih407_picophyresets,
+};
+
+static struct of_device_id stih407_reset_match[] = {
+ {
+ .compatible = "st,stih407-powerdown",
+ .data = &stih407_powerdown_controller,
+ },
+ {
+ .compatible = "st,stih407-softreset",
+ .data = &stih407_softreset_controller,
+ },
+ {
+ .compatible = "st,stih407-picophyreset",
+ .data = &stih407_picophyreset_controller,
+ },
+ { /* sentinel */ },
+};
+
+static struct platform_driver stih407_reset_driver = {
+ .probe = syscfg_reset_probe,
+ .driver = {
+ .name = "reset-stih407",
+ .of_match_table = stih407_reset_match,
+ },
+};
+
+static int __init stih407_reset_init(void)
+{
+ return platform_driver_register(&stih407_reset_driver);
+}
+
+arch_initcall(stih407_reset_init);
diff --git a/drivers/rtc/Kconfig b/drivers/rtc/Kconfig
index 6dd12dd..4511ddc 100644
--- a/drivers/rtc/Kconfig
+++ b/drivers/rtc/Kconfig
@@ -192,6 +192,14 @@ config RTC_DRV_DS1374
This driver can also be built as a module. If so, the module
will be called rtc-ds1374.
+config RTC_DRV_DS1374_WDT
+ bool "Dallas/Maxim DS1374 watchdog timer"
+ depends on RTC_DRV_DS1374
+ help
+ If you say Y here you will get support for the
+ watchdog timer in the Dallas Semiconductor DS1374
+ real-time clock chips.
+
config RTC_DRV_DS1672
tristate "Dallas/Maxim DS1672"
help
@@ -1109,36 +1117,42 @@ config RTC_DRV_AT91RM9200
this is powered by the backup power supply.
config RTC_DRV_AT91SAM9
- tristate "AT91SAM9x/AT91CAP9 RTT as RTC"
- depends on ARCH_AT91 && !(ARCH_AT91RM9200 || ARCH_AT91X40)
+ tristate "AT91SAM9 RTT as RTC"
+ depends on ARCH_AT91
+ select MFD_SYSCON
help
- RTC driver for the Atmel AT91SAM9x and AT91CAP9 internal RTT
- (Real Time Timer). These timers are powered by the backup power
- supply (such as a small coin cell battery), but do not need to
- be used as RTCs.
-
- (On AT91SAM9rl and AT91SAM9G45 chips you probably want to use the
- dedicated RTC module and leave the RTT available for other uses.)
+ Some AT91SAM9 SoCs provide an RTT (Real Time Timer) block which
+ can be used as an RTC thanks to the backup power supply (e.g. a
+ small coin cell battery) which keeps this block and the GPBR
+ (General Purpose Backup Registers) block powered when the device
+ is shutdown.
+ Some AT91SAM9 SoCs provide a real RTC block, on those ones you'd
+ probably want to use the real RTC block instead of the "RTT as an
+ RTC" driver.
config RTC_DRV_AT91SAM9_RTT
int
range 0 1
default 0
- prompt "RTT module Number" if ARCH_AT91SAM9263
depends on RTC_DRV_AT91SAM9
help
+ This option is only relevant for legacy board support and
+ won't be used when booting a DT board.
+
More than one RTT module is available. You can choose which
one will be used as an RTC. The default of zero is normally
OK to use, though some systems use that for non-RTC purposes.
config RTC_DRV_AT91SAM9_GPBR
int
- range 0 3 if !ARCH_AT91SAM9263
- range 0 15 if ARCH_AT91SAM9263
+ range 0 3
default 0
prompt "Backup Register Number"
depends on RTC_DRV_AT91SAM9
help
+ This option is only relevant for legacy board support and
+ won't be used when booting a DT board.
+
The RTC driver needs to use one of the General Purpose Backup
Registers (GPBRs) as well as the RTT. You can choose which one
will be used. The default of zero is normally OK to use, but
diff --git a/drivers/rtc/class.c b/drivers/rtc/class.c
index 38e26be..472a5ad 100644
--- a/drivers/rtc/class.c
+++ b/drivers/rtc/class.c
@@ -45,14 +45,14 @@ int rtc_hctosys_ret = -ENODEV;
* system's wall clock; restore it on resume().
*/
-static struct timespec old_rtc, old_system, old_delta;
+static struct timespec64 old_rtc, old_system, old_delta;
static int rtc_suspend(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec delta, delta_delta;
+ struct timespec64 delta, delta_delta;
int err;
if (has_persistent_clock())
@@ -68,8 +68,8 @@ static int rtc_suspend(struct device *dev)
return 0;
}
- getnstimeofday(&old_system);
- rtc_tm_to_time(&tm, &old_rtc.tv_sec);
+ getnstimeofday64(&old_system);
+ old_rtc.tv_sec = rtc_tm_to_time64(&tm);
/*
@@ -78,8 +78,8 @@ static int rtc_suspend(struct device *dev)
* try to compensate so the difference in system time
* and rtc time stays close to constant.
*/
- delta = timespec_sub(old_system, old_rtc);
- delta_delta = timespec_sub(delta, old_delta);
+ delta = timespec64_sub(old_system, old_rtc);
+ delta_delta = timespec64_sub(delta, old_delta);
if (delta_delta.tv_sec < -2 || delta_delta.tv_sec >= 2) {
/*
* if delta_delta is too large, assume time correction
@@ -88,7 +88,7 @@ static int rtc_suspend(struct device *dev)
old_delta = delta;
} else {
/* Otherwise try to adjust old_system to compensate */
- old_system = timespec_sub(old_system, delta_delta);
+ old_system = timespec64_sub(old_system, delta_delta);
}
return 0;
@@ -98,8 +98,8 @@ static int rtc_resume(struct device *dev)
{
struct rtc_device *rtc = to_rtc_device(dev);
struct rtc_time tm;
- struct timespec new_system, new_rtc;
- struct timespec sleep_time;
+ struct timespec64 new_system, new_rtc;
+ struct timespec64 sleep_time;
int err;
if (has_persistent_clock())
@@ -110,7 +110,7 @@ static int rtc_resume(struct device *dev)
return 0;
/* snapshot the current rtc and system time at resume */
- getnstimeofday(&new_system);
+ getnstimeofday64(&new_system);
err = rtc_read_time(rtc, &tm);
if (err < 0) {
pr_debug("%s: fail to read rtc time\n", dev_name(&rtc->dev));
@@ -121,7 +121,7 @@ static int rtc_resume(struct device *dev)
pr_debug("%s: bogus resume time\n", dev_name(&rtc->dev));
return 0;
}
- rtc_tm_to_time(&tm, &new_rtc.tv_sec);
+ new_rtc.tv_sec = rtc_tm_to_time64(&tm);
new_rtc.tv_nsec = 0;
if (new_rtc.tv_sec < old_rtc.tv_sec) {
@@ -130,7 +130,7 @@ static int rtc_resume(struct device *dev)
}
/* calculate the RTC time delta (sleep time)*/
- sleep_time = timespec_sub(new_rtc, old_rtc);
+ sleep_time = timespec64_sub(new_rtc, old_rtc);
/*
* Since these RTC suspend/resume handlers are not called
@@ -139,11 +139,11 @@ static int rtc_resume(struct device *dev)
* so subtract kernel run-time between rtc_suspend to rtc_resume
* to keep things accurate.
*/
- sleep_time = timespec_sub(sleep_time,
- timespec_sub(new_system, old_system));
+ sleep_time = timespec64_sub(sleep_time,
+ timespec64_sub(new_system, old_system));
if (sleep_time.tv_sec >= 0)
- timekeeping_inject_sleeptime(&sleep_time);
+ timekeeping_inject_sleeptime64(&sleep_time);
rtc_hctosys_ret = 0;
return 0;
}
diff --git a/drivers/rtc/interface.c b/drivers/rtc/interface.c
index 5b2717f..45bfc28ee 100644
--- a/drivers/rtc/interface.c
+++ b/drivers/rtc/interface.c
@@ -30,6 +30,14 @@ static int __rtc_read_time(struct rtc_device *rtc, struct rtc_time *tm)
else {
memset(tm, 0, sizeof(struct rtc_time));
err = rtc->ops->read_time(rtc->dev.parent, tm);
+ if (err < 0) {
+ dev_err(&rtc->dev, "read_time: fail to read\n");
+ return err;
+ }
+
+ err = rtc_valid_tm(tm);
+ if (err < 0)
+ dev_err(&rtc->dev, "read_time: rtc_time isn't valid\n");
}
return err;
}
@@ -891,11 +899,24 @@ again:
if (next) {
struct rtc_wkalrm alarm;
int err;
+ int retry = 3;
+
alarm.time = rtc_ktime_to_tm(next->expires);
alarm.enabled = 1;
+reprogram:
err = __rtc_set_alarm(rtc, &alarm);
if (err == -ETIME)
goto again;
+ else if (err) {
+ if (retry-- > 0)
+ goto reprogram;
+
+ timer = container_of(next, struct rtc_timer, node);
+ timerqueue_del(&rtc->timerqueue, &timer->node);
+ timer->enabled = 0;
+ dev_err(&rtc->dev, "__rtc_set_alarm: err=%d\n", err);
+ goto again;
+ }
} else
rtc_alarm_disable(rtc);
diff --git a/drivers/rtc/rtc-ab8500.c b/drivers/rtc/rtc-ab8500.c
index 727e2f5..866e0ef 100644
--- a/drivers/rtc/rtc-ab8500.c
+++ b/drivers/rtc/rtc-ab8500.c
@@ -504,6 +504,8 @@ static int ab8500_rtc_probe(struct platform_device *pdev)
return err;
}
+ rtc->uie_unsupported = 1;
+
return 0;
}
diff --git a/drivers/rtc/rtc-at91sam9.c b/drivers/rtc/rtc-at91sam9.c
index 5963743..abac38a 100644
--- a/drivers/rtc/rtc-at91sam9.c
+++ b/drivers/rtc/rtc-at91sam9.c
@@ -21,10 +21,9 @@
#include <linux/slab.h>
#include <linux/platform_data/atmel.h>
#include <linux/io.h>
-
-#include <mach/at91_rtt.h>
-#include <mach/cpu.h>
-#include <mach/hardware.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/clk.h>
/*
* This driver uses two configurable hardware resources that live in the
@@ -47,6 +46,22 @@
* registers available, likewise usable for more than "RTC" support.
*/
+#define AT91_RTT_MR 0x00 /* Real-time Mode Register */
+#define AT91_RTT_RTPRES (0xffff << 0) /* Real-time Timer Prescaler Value */
+#define AT91_RTT_ALMIEN (1 << 16) /* Alarm Interrupt Enable */
+#define AT91_RTT_RTTINCIEN (1 << 17) /* Real Time Timer Increment Interrupt Enable */
+#define AT91_RTT_RTTRST (1 << 18) /* Real Time Timer Restart */
+
+#define AT91_RTT_AR 0x04 /* Real-time Alarm Register */
+#define AT91_RTT_ALMV (0xffffffff) /* Alarm Value */
+
+#define AT91_RTT_VR 0x08 /* Real-time Value Register */
+#define AT91_RTT_CRTV (0xffffffff) /* Current Real-time Value */
+
+#define AT91_RTT_SR 0x0c /* Real-time Status Register */
+#define AT91_RTT_ALMS (1 << 0) /* Real-time Alarm Status */
+#define AT91_RTT_RTTINC (1 << 1) /* Real-time Timer Increment */
+
/*
* We store ALARM_DISABLED in ALMV to record that no alarm is set.
* It's also the reset value for that field.
@@ -58,19 +73,30 @@ struct sam9_rtc {
void __iomem *rtt;
struct rtc_device *rtcdev;
u32 imr;
- void __iomem *gpbr;
+ struct regmap *gpbr;
+ unsigned int gpbr_offset;
int irq;
+ struct clk *sclk;
};
#define rtt_readl(rtc, field) \
- __raw_readl((rtc)->rtt + AT91_RTT_ ## field)
+ readl((rtc)->rtt + AT91_RTT_ ## field)
#define rtt_writel(rtc, field, val) \
- __raw_writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+ writel((val), (rtc)->rtt + AT91_RTT_ ## field)
+
+static inline unsigned int gpbr_readl(struct sam9_rtc *rtc)
+{
+ unsigned int val;
+
+ regmap_read(rtc->gpbr, rtc->gpbr_offset, &val);
-#define gpbr_readl(rtc) \
- __raw_readl((rtc)->gpbr)
-#define gpbr_writel(rtc, val) \
- __raw_writel((val), (rtc)->gpbr)
+ return val;
+}
+
+static inline void gpbr_writel(struct sam9_rtc *rtc, unsigned int val)
+{
+ regmap_write(rtc->gpbr, rtc->gpbr_offset, val);
+}
/*
* Read current time and date in RTC
@@ -287,22 +313,22 @@ static const struct rtc_class_ops at91_rtc_ops = {
.alarm_irq_enable = at91_rtc_alarm_irq_enable,
};
+static struct regmap_config gpbr_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+};
+
/*
* Initialize and install RTC driver
*/
static int at91_rtc_probe(struct platform_device *pdev)
{
- struct resource *r, *r_gpbr;
+ struct resource *r;
struct sam9_rtc *rtc;
int ret, irq;
u32 mr;
-
- r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- r_gpbr = platform_get_resource(pdev, IORESOURCE_MEM, 1);
- if (!r || !r_gpbr) {
- dev_err(&pdev->dev, "need 2 ressources\n");
- return -ENODEV;
- }
+ unsigned int sclk_rate;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
@@ -321,24 +347,66 @@ static int at91_rtc_probe(struct platform_device *pdev)
device_init_wakeup(&pdev->dev, 1);
platform_set_drvdata(pdev, rtc);
- rtc->rtt = devm_ioremap(&pdev->dev, r->start, resource_size(r));
- if (!rtc->rtt) {
- dev_err(&pdev->dev, "failed to map registers, aborting.\n");
- return -ENOMEM;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ rtc->rtt = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(rtc->rtt))
+ return PTR_ERR(rtc->rtt);
+
+ if (!pdev->dev.of_node) {
+ /*
+ * TODO: Remove this code chunk when removing non DT board
+ * support. Remember to remove the gpbr_regmap_config
+ * variable too.
+ */
+ void __iomem *gpbr;
+
+ r = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ gpbr = devm_ioremap_resource(&pdev->dev, r);
+ if (IS_ERR(gpbr))
+ return PTR_ERR(gpbr);
+
+ rtc->gpbr = regmap_init_mmio(NULL, gpbr,
+ &gpbr_regmap_config);
+ } else {
+ struct of_phandle_args args;
+
+ ret = of_parse_phandle_with_fixed_args(pdev->dev.of_node,
+ "atmel,rtt-rtc-time-reg", 1, 0,
+ &args);
+ if (ret)
+ return ret;
+
+ rtc->gpbr = syscon_node_to_regmap(args.np);
+ rtc->gpbr_offset = args.args[0];
}
- rtc->gpbr = devm_ioremap(&pdev->dev, r_gpbr->start,
- resource_size(r_gpbr));
- if (!rtc->gpbr) {
- dev_err(&pdev->dev, "failed to map gpbr registers, aborting.\n");
+ if (IS_ERR(rtc->gpbr)) {
+ dev_err(&pdev->dev, "failed to retrieve gpbr regmap, aborting.\n");
return -ENOMEM;
}
+ rtc->sclk = devm_clk_get(&pdev->dev, NULL);
+ if (IS_ERR(rtc->sclk))
+ return PTR_ERR(rtc->sclk);
+
+ sclk_rate = clk_get_rate(rtc->sclk);
+ if (!sclk_rate || sclk_rate > AT91_RTT_RTPRES) {
+ dev_err(&pdev->dev, "Invalid slow clock rate\n");
+ return -EINVAL;
+ }
+
+ ret = clk_prepare_enable(rtc->sclk);
+ if (ret) {
+ dev_err(&pdev->dev, "Could not enable slow clock\n");
+ return ret;
+ }
+
mr = rtt_readl(rtc, MR);
/* unless RTT is counting at 1 Hz, re-initialize it */
- if ((mr & AT91_RTT_RTPRES) != AT91_SLOW_CLOCK) {
- mr = AT91_RTT_RTTRST | (AT91_SLOW_CLOCK & AT91_RTT_RTPRES);
+ if ((mr & AT91_RTT_RTPRES) != sclk_rate) {
+ mr = AT91_RTT_RTTRST | (sclk_rate & AT91_RTT_RTPRES);
gpbr_writel(rtc, 0);
}
@@ -383,6 +451,9 @@ static int at91_rtc_remove(struct platform_device *pdev)
/* disable all interrupts */
rtt_writel(rtc, MR, mr & ~(AT91_RTT_ALMIEN | AT91_RTT_RTTINCIEN));
+ if (!IS_ERR(rtc->sclk))
+ clk_disable_unprepare(rtc->sclk);
+
return 0;
}
@@ -440,6 +511,14 @@ static int at91_rtc_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(at91_rtc_pm_ops, at91_rtc_suspend, at91_rtc_resume);
+#ifdef CONFIG_OF
+static const struct of_device_id at91_rtc_dt_ids[] = {
+ { .compatible = "atmel,at91sam9260-rtt" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, at91_rtc_dt_ids);
+#endif
+
static struct platform_driver at91_rtc_driver = {
.probe = at91_rtc_probe,
.remove = at91_rtc_remove,
@@ -448,6 +527,7 @@ static struct platform_driver at91_rtc_driver = {
.name = "rtc-at91sam9",
.owner = THIS_MODULE,
.pm = &at91_rtc_pm_ops,
+ .of_match_table = of_match_ptr(at91_rtc_dt_ids),
},
};
diff --git a/drivers/rtc/rtc-ds1307.c b/drivers/rtc/rtc-ds1307.c
index bb43cf7..4ffabb3 100644
--- a/drivers/rtc/rtc-ds1307.c
+++ b/drivers/rtc/rtc-ds1307.c
@@ -35,7 +35,7 @@ enum ds_type {
ds_1388,
ds_3231,
m41t00,
- mcp7941x,
+ mcp794xx,
rx_8025,
last_ds_type /* always last */
/* rs5c372 too? different address... */
@@ -46,7 +46,7 @@ enum ds_type {
#define DS1307_REG_SECS 0x00 /* 00-59 */
# define DS1307_BIT_CH 0x80
# define DS1340_BIT_nEOSC 0x80
-# define MCP7941X_BIT_ST 0x80
+# define MCP794XX_BIT_ST 0x80
#define DS1307_REG_MIN 0x01 /* 00-59 */
#define DS1307_REG_HOUR 0x02 /* 00-23, or 1-12{am,pm} */
# define DS1307_BIT_12HR 0x40 /* in REG_HOUR */
@@ -54,7 +54,7 @@ enum ds_type {
# define DS1340_BIT_CENTURY_EN 0x80 /* in REG_HOUR */
# define DS1340_BIT_CENTURY 0x40 /* in REG_HOUR */
#define DS1307_REG_WDAY 0x03 /* 01-07 */
-# define MCP7941X_BIT_VBATEN 0x08
+# define MCP794XX_BIT_VBATEN 0x08
#define DS1307_REG_MDAY 0x04 /* 01-31 */
#define DS1307_REG_MONTH 0x05 /* 01-12 */
# define DS1337_BIT_CENTURY 0x80 /* in REG_MONTH */
@@ -159,7 +159,7 @@ static struct chip_desc chips[last_ds_type] = {
[ds_3231] = {
.alarm = 1,
},
- [mcp7941x] = {
+ [mcp794xx] = {
.alarm = 1,
/* this is battery backed SRAM */
.nvram_offset = 0x20,
@@ -176,7 +176,8 @@ static const struct i2c_device_id ds1307_id[] = {
{ "ds1340", ds_1340 },
{ "ds3231", ds_3231 },
{ "m41t00", m41t00 },
- { "mcp7941x", mcp7941x },
+ { "mcp7940x", mcp794xx },
+ { "mcp7941x", mcp794xx },
{ "pt7c4338", ds_1307 },
{ "rx8025", rx_8025 },
{ }
@@ -439,14 +440,14 @@ static int ds1307_set_time(struct device *dev, struct rtc_time *t)
buf[DS1307_REG_HOUR] |= DS1340_BIT_CENTURY_EN
| DS1340_BIT_CENTURY;
break;
- case mcp7941x:
+ case mcp794xx:
/*
* these bits were cleared when preparing the date/time
* values and need to be set again before writing the
* buffer out to the device.
*/
- buf[DS1307_REG_SECS] |= MCP7941X_BIT_ST;
- buf[DS1307_REG_WDAY] |= MCP7941X_BIT_VBATEN;
+ buf[DS1307_REG_SECS] |= MCP794XX_BIT_ST;
+ buf[DS1307_REG_WDAY] |= MCP794XX_BIT_VBATEN;
break;
default:
break;
@@ -614,26 +615,26 @@ static const struct rtc_class_ops ds13xx_rtc_ops = {
/*----------------------------------------------------------------------*/
/*
- * Alarm support for mcp7941x devices.
+ * Alarm support for mcp794xx devices.
*/
-#define MCP7941X_REG_CONTROL 0x07
-# define MCP7941X_BIT_ALM0_EN 0x10
-# define MCP7941X_BIT_ALM1_EN 0x20
-#define MCP7941X_REG_ALARM0_BASE 0x0a
-#define MCP7941X_REG_ALARM0_CTRL 0x0d
-#define MCP7941X_REG_ALARM1_BASE 0x11
-#define MCP7941X_REG_ALARM1_CTRL 0x14
-# define MCP7941X_BIT_ALMX_IF (1 << 3)
-# define MCP7941X_BIT_ALMX_C0 (1 << 4)
-# define MCP7941X_BIT_ALMX_C1 (1 << 5)
-# define MCP7941X_BIT_ALMX_C2 (1 << 6)
-# define MCP7941X_BIT_ALMX_POL (1 << 7)
-# define MCP7941X_MSK_ALMX_MATCH (MCP7941X_BIT_ALMX_C0 | \
- MCP7941X_BIT_ALMX_C1 | \
- MCP7941X_BIT_ALMX_C2)
-
-static void mcp7941x_work(struct work_struct *work)
+#define MCP794XX_REG_CONTROL 0x07
+# define MCP794XX_BIT_ALM0_EN 0x10
+# define MCP794XX_BIT_ALM1_EN 0x20
+#define MCP794XX_REG_ALARM0_BASE 0x0a
+#define MCP794XX_REG_ALARM0_CTRL 0x0d
+#define MCP794XX_REG_ALARM1_BASE 0x11
+#define MCP794XX_REG_ALARM1_CTRL 0x14
+# define MCP794XX_BIT_ALMX_IF (1 << 3)
+# define MCP794XX_BIT_ALMX_C0 (1 << 4)
+# define MCP794XX_BIT_ALMX_C1 (1 << 5)
+# define MCP794XX_BIT_ALMX_C2 (1 << 6)
+# define MCP794XX_BIT_ALMX_POL (1 << 7)
+# define MCP794XX_MSK_ALMX_MATCH (MCP794XX_BIT_ALMX_C0 | \
+ MCP794XX_BIT_ALMX_C1 | \
+ MCP794XX_BIT_ALMX_C2)
+
+static void mcp794xx_work(struct work_struct *work)
{
struct ds1307 *ds1307 = container_of(work, struct ds1307, work);
struct i2c_client *client = ds1307->client;
@@ -642,22 +643,22 @@ static void mcp7941x_work(struct work_struct *work)
mutex_lock(&ds1307->rtc->ops_lock);
/* Check and clear alarm 0 interrupt flag. */
- reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_ALARM0_CTRL);
+ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_ALARM0_CTRL);
if (reg < 0)
goto out;
- if (!(reg & MCP7941X_BIT_ALMX_IF))
+ if (!(reg & MCP794XX_BIT_ALMX_IF))
goto out;
- reg &= ~MCP7941X_BIT_ALMX_IF;
- ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_ALARM0_CTRL, reg);
+ reg &= ~MCP794XX_BIT_ALMX_IF;
+ ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_ALARM0_CTRL, reg);
if (ret < 0)
goto out;
/* Disable alarm 0. */
- reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
if (reg < 0)
goto out;
- reg &= ~MCP7941X_BIT_ALM0_EN;
- ret = i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ reg &= ~MCP794XX_BIT_ALM0_EN;
+ ret = i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
if (ret < 0)
goto out;
@@ -669,7 +670,7 @@ out:
mutex_unlock(&ds1307->rtc->ops_lock);
}
-static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
+static int mcp794xx_read_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -680,11 +681,11 @@ static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
return -EINVAL;
/* Read control and alarm 0 registers. */
- ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0)
return ret;
- t->enabled = !!(regs[0] & MCP7941X_BIT_ALM0_EN);
+ t->enabled = !!(regs[0] & MCP794XX_BIT_ALM0_EN);
/* Report alarm 0 time assuming 24-hour and day-of-month modes. */
t->time.tm_sec = bcd2bin(ds1307->regs[3] & 0x7f);
@@ -701,14 +702,14 @@ static int mcp7941x_read_alarm(struct device *dev, struct rtc_wkalrm *t)
"enabled=%d polarity=%d irq=%d match=%d\n", __func__,
t->time.tm_sec, t->time.tm_min, t->time.tm_hour,
t->time.tm_wday, t->time.tm_mday, t->time.tm_mon, t->enabled,
- !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_POL),
- !!(ds1307->regs[6] & MCP7941X_BIT_ALMX_IF),
- (ds1307->regs[6] & MCP7941X_MSK_ALMX_MATCH) >> 4);
+ !!(ds1307->regs[6] & MCP794XX_BIT_ALMX_POL),
+ !!(ds1307->regs[6] & MCP794XX_BIT_ALMX_IF),
+ (ds1307->regs[6] & MCP794XX_MSK_ALMX_MATCH) >> 4);
return 0;
}
-static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
+static int mcp794xx_set_alarm(struct device *dev, struct rtc_wkalrm *t)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -725,7 +726,7 @@ static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
t->enabled, t->pending);
/* Read control and alarm 0 registers. */
- ret = ds1307->read_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ ret = ds1307->read_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0)
return ret;
@@ -738,23 +739,23 @@ static int mcp7941x_set_alarm(struct device *dev, struct rtc_wkalrm *t)
regs[8] = bin2bcd(t->time.tm_mon) + 1;
/* Clear the alarm 0 interrupt flag. */
- regs[6] &= ~MCP7941X_BIT_ALMX_IF;
+ regs[6] &= ~MCP794XX_BIT_ALMX_IF;
/* Set alarm match: second, minute, hour, day, date, month. */
- regs[6] |= MCP7941X_MSK_ALMX_MATCH;
+ regs[6] |= MCP794XX_MSK_ALMX_MATCH;
if (t->enabled)
- regs[0] |= MCP7941X_BIT_ALM0_EN;
+ regs[0] |= MCP794XX_BIT_ALM0_EN;
else
- regs[0] &= ~MCP7941X_BIT_ALM0_EN;
+ regs[0] &= ~MCP794XX_BIT_ALM0_EN;
- ret = ds1307->write_block_data(client, MCP7941X_REG_CONTROL, 10, regs);
+ ret = ds1307->write_block_data(client, MCP794XX_REG_CONTROL, 10, regs);
if (ret < 0)
return ret;
return 0;
}
-static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
+static int mcp794xx_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
struct ds1307 *ds1307 = i2c_get_clientdata(client);
@@ -763,24 +764,24 @@ static int mcp7941x_alarm_irq_enable(struct device *dev, unsigned int enabled)
if (!test_bit(HAS_ALARM, &ds1307->flags))
return -EINVAL;
- reg = i2c_smbus_read_byte_data(client, MCP7941X_REG_CONTROL);
+ reg = i2c_smbus_read_byte_data(client, MCP794XX_REG_CONTROL);
if (reg < 0)
return reg;
if (enabled)
- reg |= MCP7941X_BIT_ALM0_EN;
+ reg |= MCP794XX_BIT_ALM0_EN;
else
- reg &= ~MCP7941X_BIT_ALM0_EN;
+ reg &= ~MCP794XX_BIT_ALM0_EN;
- return i2c_smbus_write_byte_data(client, MCP7941X_REG_CONTROL, reg);
+ return i2c_smbus_write_byte_data(client, MCP794XX_REG_CONTROL, reg);
}
-static const struct rtc_class_ops mcp7941x_rtc_ops = {
+static const struct rtc_class_ops mcp794xx_rtc_ops = {
.read_time = ds1307_get_time,
.set_time = ds1307_set_time,
- .read_alarm = mcp7941x_read_alarm,
- .set_alarm = mcp7941x_set_alarm,
- .alarm_irq_enable = mcp7941x_alarm_irq_enable,
+ .read_alarm = mcp794xx_read_alarm,
+ .set_alarm = mcp794xx_set_alarm,
+ .alarm_irq_enable = mcp794xx_alarm_irq_enable,
};
/*----------------------------------------------------------------------*/
@@ -1049,10 +1050,10 @@ static int ds1307_probe(struct i2c_client *client,
case ds_1388:
ds1307->offset = 1; /* Seconds starts at 1 */
break;
- case mcp7941x:
- rtc_ops = &mcp7941x_rtc_ops;
+ case mcp794xx:
+ rtc_ops = &mcp794xx_rtc_ops;
if (ds1307->client->irq > 0 && chip->alarm) {
- INIT_WORK(&ds1307->work, mcp7941x_work);
+ INIT_WORK(&ds1307->work, mcp794xx_work);
want_irq = true;
}
break;
@@ -1117,18 +1118,18 @@ read_rtc:
dev_warn(&client->dev, "SET TIME!\n");
}
break;
- case mcp7941x:
+ case mcp794xx:
/* make sure that the backup battery is enabled */
- if (!(ds1307->regs[DS1307_REG_WDAY] & MCP7941X_BIT_VBATEN)) {
+ if (!(ds1307->regs[DS1307_REG_WDAY] & MCP794XX_BIT_VBATEN)) {
i2c_smbus_write_byte_data(client, DS1307_REG_WDAY,
ds1307->regs[DS1307_REG_WDAY]
- | MCP7941X_BIT_VBATEN);
+ | MCP794XX_BIT_VBATEN);
}
/* clock halted? turn it on, so clock can tick. */
- if (!(tmp & MCP7941X_BIT_ST)) {
+ if (!(tmp & MCP794XX_BIT_ST)) {
i2c_smbus_write_byte_data(client, DS1307_REG_SECS,
- MCP7941X_BIT_ST);
+ MCP794XX_BIT_ST);
dev_warn(&client->dev, "SET TIME!\n");
goto read_rtc;
}
diff --git a/drivers/rtc/rtc-ds1374.c b/drivers/rtc/rtc-ds1374.c
index 9e6e14f..8605fde 100644
--- a/drivers/rtc/rtc-ds1374.c
+++ b/drivers/rtc/rtc-ds1374.c
@@ -4,6 +4,7 @@
* Based on code by Randy Vinson <rvinson@mvista.com>,
* which was based on the m41t00.c by Mark Greer <mgreer@mvista.com>.
*
+ * Copyright (C) 2014 Rose Technology
* Copyright (C) 2006-2007 Freescale Semiconductor
*
* 2005 (c) MontaVista Software, Inc. This file is licensed under
@@ -26,6 +27,13 @@
#include <linux/workqueue.h>
#include <linux/slab.h>
#include <linux/pm.h>
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+#include <linux/fs.h>
+#include <linux/ioctl.h>
+#include <linux/miscdevice.h>
+#include <linux/reboot.h>
+#include <linux/watchdog.h>
+#endif
#define DS1374_REG_TOD0 0x00 /* Time of Day */
#define DS1374_REG_TOD1 0x01
@@ -49,6 +57,14 @@ static const struct i2c_device_id ds1374_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ds1374_id);
+#ifdef CONFIG_OF
+static const struct of_device_id ds1374_of_match[] = {
+ { .compatible = "dallas,ds1374" },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ds1374_of_match);
+#endif
+
struct ds1374 {
struct i2c_client *client;
struct rtc_device *rtc;
@@ -162,6 +178,7 @@ static int ds1374_set_time(struct device *dev, struct rtc_time *time)
return ds1374_write_rtc(client, itime, DS1374_REG_TOD0, 4);
}
+#ifndef CONFIG_RTC_DRV_DS1374_WDT
/* The ds1374 has a decrementer for an alarm, rather than a comparator.
* If the time of day is changed, then the alarm will need to be
* reset.
@@ -263,6 +280,7 @@ out:
mutex_unlock(&ds1374->mutex);
return ret;
}
+#endif
static irqreturn_t ds1374_irq(int irq, void *dev_id)
{
@@ -307,6 +325,7 @@ unlock:
mutex_unlock(&ds1374->mutex);
}
+#ifndef CONFIG_RTC_DRV_DS1374_WDT
static int ds1374_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
struct i2c_client *client = to_i2c_client(dev);
@@ -331,15 +350,260 @@ out:
mutex_unlock(&ds1374->mutex);
return ret;
}
+#endif
static const struct rtc_class_ops ds1374_rtc_ops = {
.read_time = ds1374_read_time,
.set_time = ds1374_set_time,
+#ifndef CONFIG_RTC_DRV_DS1374_WDT
.read_alarm = ds1374_read_alarm,
.set_alarm = ds1374_set_alarm,
.alarm_irq_enable = ds1374_alarm_irq_enable,
+#endif
+};
+
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+/*
+ *****************************************************************************
+ *
+ * Watchdog Driver
+ *
+ *****************************************************************************
+ */
+static struct i2c_client *save_client;
+/* Default margin */
+#define WD_TIMO 131762
+
+#define DRV_NAME "DS1374 Watchdog"
+
+static int wdt_margin = WD_TIMO;
+static unsigned long wdt_is_open;
+module_param(wdt_margin, int, 0);
+MODULE_PARM_DESC(wdt_margin, "Watchdog timeout in seconds (default 32s)");
+
+static const struct watchdog_info ds1374_wdt_info = {
+ .identity = "DS1374 WTD",
+ .options = WDIOF_SETTIMEOUT | WDIOF_KEEPALIVEPING |
+ WDIOF_MAGICCLOSE,
};
+static int ds1374_wdt_settimeout(unsigned int timeout)
+{
+ int ret = -ENOIOCTLCMD;
+ int cr;
+
+ ret = cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR);
+ if (ret < 0)
+ goto out;
+
+ /* Disable any existing watchdog/alarm before setting the new one */
+ cr &= ~DS1374_REG_CR_WACE;
+
+ ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+ if (ret < 0)
+ goto out;
+
+ /* Set new watchdog time */
+ ret = ds1374_write_rtc(save_client, timeout, DS1374_REG_WDALM0, 3);
+ if (ret) {
+ pr_info("rtc-ds1374 - couldn't set new watchdog time\n");
+ goto out;
+ }
+
+ /* Enable watchdog timer */
+ cr |= DS1374_REG_CR_WACE | DS1374_REG_CR_WDALM;
+ cr &= ~DS1374_REG_CR_AIE;
+
+ ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+ if (ret < 0)
+ goto out;
+
+ return 0;
+out:
+ return ret;
+}
+
+
+/*
+ * Reload the watchdog timer. (ie, pat the watchdog)
+ */
+static void ds1374_wdt_ping(void)
+{
+ u32 val;
+ int ret = 0;
+
+ ret = ds1374_read_rtc(save_client, &val, DS1374_REG_WDALM0, 3);
+ if (ret)
+ pr_info("WD TICK FAIL!!!!!!!!!! %i\n", ret);
+}
+
+static void ds1374_wdt_disable(void)
+{
+ int ret = -ENOIOCTLCMD;
+ int cr;
+
+ cr = i2c_smbus_read_byte_data(save_client, DS1374_REG_CR);
+ /* Disable watchdog timer */
+ cr &= ~DS1374_REG_CR_WACE;
+
+ ret = i2c_smbus_write_byte_data(save_client, DS1374_REG_CR, cr);
+}
+
+/*
+ * Watchdog device is opened, and watchdog starts running.
+ */
+static int ds1374_wdt_open(struct inode *inode, struct file *file)
+{
+ struct ds1374 *ds1374 = i2c_get_clientdata(save_client);
+
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR) {
+ mutex_lock(&ds1374->mutex);
+ if (test_and_set_bit(0, &wdt_is_open)) {
+ mutex_unlock(&ds1374->mutex);
+ return -EBUSY;
+ }
+ /*
+ * Activate
+ */
+ wdt_is_open = 1;
+ mutex_unlock(&ds1374->mutex);
+ return nonseekable_open(inode, file);
+ }
+ return -ENODEV;
+}
+
+/*
+ * Close the watchdog device.
+ */
+static int ds1374_wdt_release(struct inode *inode, struct file *file)
+{
+ if (MINOR(inode->i_rdev) == WATCHDOG_MINOR)
+ clear_bit(0, &wdt_is_open);
+
+ return 0;
+}
+
+/*
+ * Pat the watchdog whenever device is written to.
+ */
+static ssize_t ds1374_wdt_write(struct file *file, const char __user *data,
+ size_t len, loff_t *ppos)
+{
+ if (len) {
+ ds1374_wdt_ping();
+ return 1;
+ }
+ return 0;
+}
+
+static ssize_t ds1374_wdt_read(struct file *file, char __user *data,
+ size_t len, loff_t *ppos)
+{
+ return 0;
+}
+
+/*
+ * Handle commands from user-space.
+ */
+static long ds1374_wdt_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int new_margin, options;
+
+ switch (cmd) {
+ case WDIOC_GETSUPPORT:
+ return copy_to_user((struct watchdog_info __user *)arg,
+ &ds1374_wdt_info, sizeof(ds1374_wdt_info)) ? -EFAULT : 0;
+
+ case WDIOC_GETSTATUS:
+ case WDIOC_GETBOOTSTATUS:
+ return put_user(0, (int __user *)arg);
+ case WDIOC_KEEPALIVE:
+ ds1374_wdt_ping();
+ return 0;
+ case WDIOC_SETTIMEOUT:
+ if (get_user(new_margin, (int __user *)arg))
+ return -EFAULT;
+
+ if (new_margin < 1 || new_margin > 16777216)
+ return -EINVAL;
+
+ wdt_margin = new_margin;
+ ds1374_wdt_settimeout(new_margin);
+ ds1374_wdt_ping();
+ /* fallthrough */
+ case WDIOC_GETTIMEOUT:
+ return put_user(wdt_margin, (int __user *)arg);
+ case WDIOC_SETOPTIONS:
+ if (copy_from_user(&options, (int __user *)arg, sizeof(int)))
+ return -EFAULT;
+
+ if (options & WDIOS_DISABLECARD) {
+ pr_info("rtc-ds1374: disable watchdog\n");
+ ds1374_wdt_disable();
+ }
+
+ if (options & WDIOS_ENABLECARD) {
+ pr_info("rtc-ds1374: enable watchdog\n");
+ ds1374_wdt_settimeout(wdt_margin);
+ ds1374_wdt_ping();
+ }
+
+ return -EINVAL;
+ }
+ return -ENOTTY;
+}
+
+static long ds1374_wdt_unlocked_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ int ret;
+ struct ds1374 *ds1374 = i2c_get_clientdata(save_client);
+
+ mutex_lock(&ds1374->mutex);
+ ret = ds1374_wdt_ioctl(file, cmd, arg);
+ mutex_unlock(&ds1374->mutex);
+
+ return ret;
+}
+
+static int ds1374_wdt_notify_sys(struct notifier_block *this,
+ unsigned long code, void *unused)
+{
+ if (code == SYS_DOWN || code == SYS_HALT)
+ /* Disable Watchdog */
+ ds1374_wdt_disable();
+ return NOTIFY_DONE;
+}
+
+static const struct file_operations ds1374_wdt_fops = {
+ .owner = THIS_MODULE,
+ .read = ds1374_wdt_read,
+ .unlocked_ioctl = ds1374_wdt_unlocked_ioctl,
+ .write = ds1374_wdt_write,
+ .open = ds1374_wdt_open,
+ .release = ds1374_wdt_release,
+ .llseek = no_llseek,
+};
+
+static struct miscdevice ds1374_miscdev = {
+ .minor = WATCHDOG_MINOR,
+ .name = "watchdog",
+ .fops = &ds1374_wdt_fops,
+};
+
+static struct notifier_block ds1374_wdt_notifier = {
+ .notifier_call = ds1374_wdt_notify_sys,
+};
+
+#endif /*CONFIG_RTC_DRV_DS1374_WDT*/
+/*
+ *****************************************************************************
+ *
+ * Driver Interface
+ *
+ *****************************************************************************
+ */
static int ds1374_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
@@ -378,12 +642,33 @@ static int ds1374_probe(struct i2c_client *client,
return PTR_ERR(ds1374->rtc);
}
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+ save_client = client;
+ ret = misc_register(&ds1374_miscdev);
+ if (ret)
+ return ret;
+ ret = register_reboot_notifier(&ds1374_wdt_notifier);
+ if (ret) {
+ misc_deregister(&ds1374_miscdev);
+ return ret;
+ }
+ ds1374_wdt_settimeout(131072);
+#endif
+
return 0;
}
static int ds1374_remove(struct i2c_client *client)
{
struct ds1374 *ds1374 = i2c_get_clientdata(client);
+#ifdef CONFIG_RTC_DRV_DS1374_WDT
+ int res;
+
+ res = misc_deregister(&ds1374_miscdev);
+ if (!res)
+ ds1374_miscdev.parent = NULL;
+ unregister_reboot_notifier(&ds1374_wdt_notifier);
+#endif
if (client->irq > 0) {
mutex_lock(&ds1374->mutex);
diff --git a/drivers/rtc/rtc-isl12057.c b/drivers/rtc/rtc-isl12057.c
index 455b601..6e1fcfb 100644
--- a/drivers/rtc/rtc-isl12057.c
+++ b/drivers/rtc/rtc-isl12057.c
@@ -41,6 +41,7 @@
#define ISL12057_REG_RTC_DW 0x03 /* Day of the Week */
#define ISL12057_REG_RTC_DT 0x04 /* Date */
#define ISL12057_REG_RTC_MO 0x05 /* Month */
+#define ISL12057_REG_RTC_MO_CEN BIT(7) /* Century bit */
#define ISL12057_REG_RTC_YR 0x06 /* Year */
#define ISL12057_RTC_SEC_LEN 7
@@ -88,7 +89,7 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
tm->tm_min = bcd2bin(regs[ISL12057_REG_RTC_MN]);
if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_MIL) { /* AM/PM */
- tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x0f);
+ tm->tm_hour = bcd2bin(regs[ISL12057_REG_RTC_HR] & 0x1f);
if (regs[ISL12057_REG_RTC_HR] & ISL12057_REG_RTC_HR_PM)
tm->tm_hour += 12;
} else { /* 24 hour mode */
@@ -97,26 +98,37 @@ static void isl12057_rtc_regs_to_tm(struct rtc_time *tm, u8 *regs)
tm->tm_mday = bcd2bin(regs[ISL12057_REG_RTC_DT]);
tm->tm_wday = bcd2bin(regs[ISL12057_REG_RTC_DW]) - 1; /* starts at 1 */
- tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO]) - 1; /* starts at 1 */
+ tm->tm_mon = bcd2bin(regs[ISL12057_REG_RTC_MO] & 0x1f) - 1; /* ditto */
tm->tm_year = bcd2bin(regs[ISL12057_REG_RTC_YR]) + 100;
+
+ /* Check if years register has overflown from 99 to 00 */
+ if (regs[ISL12057_REG_RTC_MO] & ISL12057_REG_RTC_MO_CEN)
+ tm->tm_year += 100;
}
static int isl12057_rtc_tm_to_regs(u8 *regs, struct rtc_time *tm)
{
+ u8 century_bit;
+
/*
* The clock has an 8 bit wide bcd-coded register for the year.
+ * It also has a century bit encoded in MO flag which provides
+ * information about overflow of year register from 99 to 00.
* tm_year is an offset from 1900 and we are interested in the
- * 2000-2099 range, so any value less than 100 is invalid.
+ * 2000-2199 range, so any value less than 100 or larger than
+ * 299 is invalid.
*/
- if (tm->tm_year < 100)
+ if (tm->tm_year < 100 || tm->tm_year > 299)
return -EINVAL;
+ century_bit = (tm->tm_year > 199) ? ISL12057_REG_RTC_MO_CEN : 0;
+
regs[ISL12057_REG_RTC_SC] = bin2bcd(tm->tm_sec);
regs[ISL12057_REG_RTC_MN] = bin2bcd(tm->tm_min);
regs[ISL12057_REG_RTC_HR] = bin2bcd(tm->tm_hour); /* 24-hour format */
regs[ISL12057_REG_RTC_DT] = bin2bcd(tm->tm_mday);
- regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1);
- regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year - 100);
+ regs[ISL12057_REG_RTC_MO] = bin2bcd(tm->tm_mon + 1) | century_bit;
+ regs[ISL12057_REG_RTC_YR] = bin2bcd(tm->tm_year % 100);
regs[ISL12057_REG_RTC_DW] = bin2bcd(tm->tm_wday + 1);
return 0;
@@ -152,17 +164,33 @@ static int isl12057_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
struct isl12057_rtc_data *data = dev_get_drvdata(dev);
u8 regs[ISL12057_RTC_SEC_LEN];
+ unsigned int sr;
int ret;
mutex_lock(&data->lock);
+ ret = regmap_read(data->regmap, ISL12057_REG_SR, &sr);
+ if (ret) {
+ dev_err(dev, "%s: unable to read oscillator status flag (%d)\n",
+ __func__, ret);
+ goto out;
+ } else {
+ if (sr & ISL12057_REG_SR_OSF) {
+ ret = -ENODATA;
+ goto out;
+ }
+ }
+
ret = regmap_bulk_read(data->regmap, ISL12057_REG_RTC_SC, regs,
ISL12057_RTC_SEC_LEN);
+ if (ret)
+ dev_err(dev, "%s: unable to read RTC time section (%d)\n",
+ __func__, ret);
+
+out:
mutex_unlock(&data->lock);
- if (ret) {
- dev_err(dev, "%s: RTC read failed\n", __func__);
+ if (ret)
return ret;
- }
isl12057_rtc_regs_to_tm(tm, regs);
@@ -182,10 +210,24 @@ static int isl12057_rtc_set_time(struct device *dev, struct rtc_time *tm)
mutex_lock(&data->lock);
ret = regmap_bulk_write(data->regmap, ISL12057_REG_RTC_SC, regs,
ISL12057_RTC_SEC_LEN);
- mutex_unlock(&data->lock);
+ if (ret) {
+ dev_err(dev, "%s: unable to write RTC time section (%d)\n",
+ __func__, ret);
+ goto out;
+ }
- if (ret)
- dev_err(dev, "%s: RTC write failed\n", __func__);
+ /*
+ * Now that RTC time has been updated, let's clear oscillator
+ * failure flag, if needed.
+ */
+ ret = regmap_update_bits(data->regmap, ISL12057_REG_SR,
+ ISL12057_REG_SR_OSF, 0);
+ if (ret < 0)
+ dev_err(dev, "%s: unable to clear osc. failure bit (%d)\n",
+ __func__, ret);
+
+out:
+ mutex_unlock(&data->lock);
return ret;
}
@@ -203,15 +245,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap)
ret = regmap_update_bits(regmap, ISL12057_REG_INT,
ISL12057_REG_INT_EOSC, 0);
if (ret < 0) {
- dev_err(dev, "Unable to enable oscillator\n");
- return ret;
- }
-
- /* Clear oscillator failure bit if needed */
- ret = regmap_update_bits(regmap, ISL12057_REG_SR,
- ISL12057_REG_SR_OSF, 0);
- if (ret < 0) {
- dev_err(dev, "Unable to clear oscillator failure bit\n");
+ dev_err(dev, "%s: unable to enable oscillator (%d)\n",
+ __func__, ret);
return ret;
}
@@ -219,7 +254,8 @@ static int isl12057_check_rtc_status(struct device *dev, struct regmap *regmap)
ret = regmap_update_bits(regmap, ISL12057_REG_SR,
ISL12057_REG_SR_A1F, 0);
if (ret < 0) {
- dev_err(dev, "Unable to clear alarm bit\n");
+ dev_err(dev, "%s: unable to clear alarm bit (%d)\n",
+ __func__, ret);
return ret;
}
@@ -253,7 +289,8 @@ static int isl12057_probe(struct i2c_client *client,
regmap = devm_regmap_init_i2c(client, &isl12057_rtc_regmap_config);
if (IS_ERR(regmap)) {
ret = PTR_ERR(regmap);
- dev_err(dev, "regmap allocation failed: %d\n", ret);
+ dev_err(dev, "%s: regmap allocation failed (%d)\n",
+ __func__, ret);
return ret;
}
diff --git a/drivers/rtc/rtc-lib.c b/drivers/rtc/rtc-lib.c
index c4cf057..e6bfb9c 100644
--- a/drivers/rtc/rtc-lib.c
+++ b/drivers/rtc/rtc-lib.c
@@ -45,16 +45,20 @@ int rtc_year_days(unsigned int day, unsigned int month, unsigned int year)
}
EXPORT_SYMBOL(rtc_year_days);
+
/*
+ * rtc_time_to_tm64 - Converts time64_t to rtc_time.
* Convert seconds since 01-01-1970 00:00:00 to Gregorian date.
*/
-void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+void rtc_time64_to_tm(time64_t time, struct rtc_time *tm)
{
unsigned int month, year;
+ unsigned long secs;
int days;
- days = time / 86400;
- time -= (unsigned int) days * 86400;
+ /* time must be positive */
+ days = div_s64(time, 86400);
+ secs = time - (unsigned int) days * 86400;
/* day of the week, 1970-01-01 was a Thursday */
tm->tm_wday = (days + 4) % 7;
@@ -81,14 +85,14 @@ void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
tm->tm_mon = month;
tm->tm_mday = days + 1;
- tm->tm_hour = time / 3600;
- time -= tm->tm_hour * 3600;
- tm->tm_min = time / 60;
- tm->tm_sec = time - tm->tm_min * 60;
+ tm->tm_hour = secs / 3600;
+ secs -= tm->tm_hour * 3600;
+ tm->tm_min = secs / 60;
+ tm->tm_sec = secs - tm->tm_min * 60;
tm->tm_isdst = 0;
}
-EXPORT_SYMBOL(rtc_time_to_tm);
+EXPORT_SYMBOL(rtc_time64_to_tm);
/*
* Does the rtc_time represent a valid date/time?
@@ -109,24 +113,22 @@ int rtc_valid_tm(struct rtc_time *tm)
EXPORT_SYMBOL(rtc_valid_tm);
/*
+ * rtc_tm_to_time64 - Converts rtc_time to time64_t.
* Convert Gregorian date to seconds since 01-01-1970 00:00:00.
*/
-int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+time64_t rtc_tm_to_time64(struct rtc_time *tm)
{
- *time = mktime(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
+ return mktime64(tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday,
tm->tm_hour, tm->tm_min, tm->tm_sec);
- return 0;
}
-EXPORT_SYMBOL(rtc_tm_to_time);
+EXPORT_SYMBOL(rtc_tm_to_time64);
/*
* Convert rtc_time to ktime
*/
ktime_t rtc_tm_to_ktime(struct rtc_time tm)
{
- time_t time;
- rtc_tm_to_time(&tm, &time);
- return ktime_set(time, 0);
+ return ktime_set(rtc_tm_to_time64(&tm), 0);
}
EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
@@ -135,14 +137,14 @@ EXPORT_SYMBOL_GPL(rtc_tm_to_ktime);
*/
struct rtc_time rtc_ktime_to_tm(ktime_t kt)
{
- struct timespec ts;
+ struct timespec64 ts;
struct rtc_time ret;
- ts = ktime_to_timespec(kt);
+ ts = ktime_to_timespec64(kt);
/* Round up any ns */
if (ts.tv_nsec)
ts.tv_sec++;
- rtc_time_to_tm(ts.tv_sec, &ret);
+ rtc_time64_to_tm(ts.tv_sec, &ret);
return ret;
}
EXPORT_SYMBOL_GPL(rtc_ktime_to_tm);
diff --git a/drivers/rtc/rtc-omap.c b/drivers/rtc/rtc-omap.c
index 21142e6..4f1c6ca 100644
--- a/drivers/rtc/rtc-omap.c
+++ b/drivers/rtc/rtc-omap.c
@@ -1,10 +1,11 @@
/*
- * TI OMAP1 Real Time Clock interface for Linux
+ * TI OMAP Real Time Clock interface for Linux
*
* Copyright (C) 2003 MontaVista Software, Inc.
* Author: George G. Davis <gdavis@mvista.com> or <source@mvista.com>
*
* Copyright (C) 2006 David Brownell (new RTC framework)
+ * Copyright (C) 2014 Johan Hovold <johan@kernel.org>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -25,7 +26,8 @@
#include <linux/pm_runtime.h>
#include <linux/io.h>
-/* The OMAP1 RTC is a year/month/day/hours/minutes/seconds BCD clock
+/*
+ * The OMAP RTC is a year/month/day/hours/minutes/seconds BCD clock
* with century-range alarm matching, driven by the 32kHz clock.
*
* The main user-visible ways it differs from PC RTCs are by omitting
@@ -39,10 +41,6 @@
* the SoC). See the BOARD-SPECIFIC CUSTOMIZATION comment.
*/
-#define DRIVER_NAME "omap_rtc"
-
-#define OMAP_RTC_BASE 0xfffb4800
-
/* RTC registers */
#define OMAP_RTC_SECONDS_REG 0x00
#define OMAP_RTC_MINUTES_REG 0x04
@@ -72,6 +70,15 @@
#define OMAP_RTC_IRQWAKEEN 0x7c
+#define OMAP_RTC_ALARM2_SECONDS_REG 0x80
+#define OMAP_RTC_ALARM2_MINUTES_REG 0x84
+#define OMAP_RTC_ALARM2_HOURS_REG 0x88
+#define OMAP_RTC_ALARM2_DAYS_REG 0x8c
+#define OMAP_RTC_ALARM2_MONTHS_REG 0x90
+#define OMAP_RTC_ALARM2_YEARS_REG 0x94
+
+#define OMAP_RTC_PMIC_REG 0x98
+
/* OMAP_RTC_CTRL_REG bit fields: */
#define OMAP_RTC_CTRL_SPLIT BIT(7)
#define OMAP_RTC_CTRL_DISABLE BIT(6)
@@ -84,6 +91,7 @@
/* OMAP_RTC_STATUS_REG bit fields: */
#define OMAP_RTC_STATUS_POWER_UP BIT(7)
+#define OMAP_RTC_STATUS_ALARM2 BIT(7)
#define OMAP_RTC_STATUS_ALARM BIT(6)
#define OMAP_RTC_STATUS_1D_EVENT BIT(5)
#define OMAP_RTC_STATUS_1H_EVENT BIT(4)
@@ -93,6 +101,7 @@
#define OMAP_RTC_STATUS_BUSY BIT(0)
/* OMAP_RTC_INTERRUPTS_REG bit fields: */
+#define OMAP_RTC_INTERRUPTS_IT_ALARM2 BIT(4)
#define OMAP_RTC_INTERRUPTS_IT_ALARM BIT(3)
#define OMAP_RTC_INTERRUPTS_IT_TIMER BIT(2)
@@ -102,61 +111,82 @@
/* OMAP_RTC_IRQWAKEEN bit fields: */
#define OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN BIT(1)
+/* OMAP_RTC_PMIC bit fields: */
+#define OMAP_RTC_PMIC_POWER_EN_EN BIT(16)
+
/* OMAP_RTC_KICKER values */
#define KICK0_VALUE 0x83e70b13
#define KICK1_VALUE 0x95a4f1e0
-#define OMAP_RTC_HAS_KICKER BIT(0)
-
-/*
- * Few RTC IP revisions has special WAKE-EN Register to enable Wakeup
- * generation for event Alarm.
- */
-#define OMAP_RTC_HAS_IRQWAKEEN BIT(1)
+struct omap_rtc_device_type {
+ bool has_32kclk_en;
+ bool has_kicker;
+ bool has_irqwakeen;
+ bool has_pmic_mode;
+ bool has_power_up_reset;
+};
-/*
- * Some RTC IP revisions (like those in AM335x and DRA7x) need
- * the 32KHz clock to be explicitly enabled.
- */
-#define OMAP_RTC_HAS_32KCLK_EN BIT(2)
+struct omap_rtc {
+ struct rtc_device *rtc;
+ void __iomem *base;
+ int irq_alarm;
+ int irq_timer;
+ u8 interrupts_reg;
+ bool is_pmic_controller;
+ const struct omap_rtc_device_type *type;
+};
-static void __iomem *rtc_base;
+static inline u8 rtc_read(struct omap_rtc *rtc, unsigned int reg)
+{
+ return readb(rtc->base + reg);
+}
-#define rtc_read(addr) readb(rtc_base + (addr))
-#define rtc_write(val, addr) writeb(val, rtc_base + (addr))
+static inline u32 rtc_readl(struct omap_rtc *rtc, unsigned int reg)
+{
+ return readl(rtc->base + reg);
+}
-#define rtc_writel(val, addr) writel(val, rtc_base + (addr))
+static inline void rtc_write(struct omap_rtc *rtc, unsigned int reg, u8 val)
+{
+ writeb(val, rtc->base + reg);
+}
+static inline void rtc_writel(struct omap_rtc *rtc, unsigned int reg, u32 val)
+{
+ writel(val, rtc->base + reg);
+}
-/* we rely on the rtc framework to handle locking (rtc->ops_lock),
+/*
+ * We rely on the rtc framework to handle locking (rtc->ops_lock),
* so the only other requirement is that register accesses which
* require BUSY to be clear are made with IRQs locally disabled
*/
-static void rtc_wait_not_busy(void)
+static void rtc_wait_not_busy(struct omap_rtc *rtc)
{
- int count = 0;
- u8 status;
+ int count;
+ u8 status;
/* BUSY may stay active for 1/32768 second (~30 usec) */
for (count = 0; count < 50; count++) {
- status = rtc_read(OMAP_RTC_STATUS_REG);
- if ((status & (u8)OMAP_RTC_STATUS_BUSY) == 0)
+ status = rtc_read(rtc, OMAP_RTC_STATUS_REG);
+ if (!(status & OMAP_RTC_STATUS_BUSY))
break;
udelay(1);
}
/* now we have ~15 usec to read/write various registers */
}
-static irqreturn_t rtc_irq(int irq, void *rtc)
+static irqreturn_t rtc_irq(int irq, void *dev_id)
{
- unsigned long events = 0;
- u8 irq_data;
+ struct omap_rtc *rtc = dev_id;
+ unsigned long events = 0;
+ u8 irq_data;
- irq_data = rtc_read(OMAP_RTC_STATUS_REG);
+ irq_data = rtc_read(rtc, OMAP_RTC_STATUS_REG);
/* alarm irq? */
if (irq_data & OMAP_RTC_STATUS_ALARM) {
- rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+ rtc_write(rtc, OMAP_RTC_STATUS_REG, OMAP_RTC_STATUS_ALARM);
events |= RTC_IRQF | RTC_AF;
}
@@ -164,23 +194,21 @@ static irqreturn_t rtc_irq(int irq, void *rtc)
if (irq_data & OMAP_RTC_STATUS_1S_EVENT)
events |= RTC_IRQF | RTC_UF;
- rtc_update_irq(rtc, 1, events);
+ rtc_update_irq(rtc->rtc, 1, events);
return IRQ_HANDLED;
}
static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
u8 reg, irqwake_reg = 0;
- struct platform_device *pdev = to_platform_device(dev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(pdev);
local_irq_disable();
- rtc_wait_not_busy();
- reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
+ rtc_wait_not_busy(rtc);
+ reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ if (rtc->type->has_irqwakeen)
+ irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
if (enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
@@ -189,10 +217,10 @@ static int omap_rtc_alarm_irq_enable(struct device *dev, unsigned int enabled)
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
}
- rtc_wait_not_busy();
- rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
+ rtc_wait_not_busy(rtc);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
+ if (rtc->type->has_irqwakeen)
+ rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
local_irq_enable();
return 0;
@@ -230,39 +258,47 @@ static void bcd2tm(struct rtc_time *tm)
tm->tm_year = bcd2bin(tm->tm_year) + 100;
}
+static void omap_rtc_read_time_raw(struct omap_rtc *rtc, struct rtc_time *tm)
+{
+ tm->tm_sec = rtc_read(rtc, OMAP_RTC_SECONDS_REG);
+ tm->tm_min = rtc_read(rtc, OMAP_RTC_MINUTES_REG);
+ tm->tm_hour = rtc_read(rtc, OMAP_RTC_HOURS_REG);
+ tm->tm_mday = rtc_read(rtc, OMAP_RTC_DAYS_REG);
+ tm->tm_mon = rtc_read(rtc, OMAP_RTC_MONTHS_REG);
+ tm->tm_year = rtc_read(rtc, OMAP_RTC_YEARS_REG);
+}
static int omap_rtc_read_time(struct device *dev, struct rtc_time *tm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+
/* we don't report wday/yday/isdst ... */
local_irq_disable();
- rtc_wait_not_busy();
-
- tm->tm_sec = rtc_read(OMAP_RTC_SECONDS_REG);
- tm->tm_min = rtc_read(OMAP_RTC_MINUTES_REG);
- tm->tm_hour = rtc_read(OMAP_RTC_HOURS_REG);
- tm->tm_mday = rtc_read(OMAP_RTC_DAYS_REG);
- tm->tm_mon = rtc_read(OMAP_RTC_MONTHS_REG);
- tm->tm_year = rtc_read(OMAP_RTC_YEARS_REG);
-
+ rtc_wait_not_busy(rtc);
+ omap_rtc_read_time_raw(rtc, tm);
local_irq_enable();
bcd2tm(tm);
+
return 0;
}
static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+
if (tm2bcd(tm) < 0)
return -EINVAL;
+
local_irq_disable();
- rtc_wait_not_busy();
+ rtc_wait_not_busy(rtc);
- rtc_write(tm->tm_year, OMAP_RTC_YEARS_REG);
- rtc_write(tm->tm_mon, OMAP_RTC_MONTHS_REG);
- rtc_write(tm->tm_mday, OMAP_RTC_DAYS_REG);
- rtc_write(tm->tm_hour, OMAP_RTC_HOURS_REG);
- rtc_write(tm->tm_min, OMAP_RTC_MINUTES_REG);
- rtc_write(tm->tm_sec, OMAP_RTC_SECONDS_REG);
+ rtc_write(rtc, OMAP_RTC_YEARS_REG, tm->tm_year);
+ rtc_write(rtc, OMAP_RTC_MONTHS_REG, tm->tm_mon);
+ rtc_write(rtc, OMAP_RTC_DAYS_REG, tm->tm_mday);
+ rtc_write(rtc, OMAP_RTC_HOURS_REG, tm->tm_hour);
+ rtc_write(rtc, OMAP_RTC_MINUTES_REG, tm->tm_min);
+ rtc_write(rtc, OMAP_RTC_SECONDS_REG, tm->tm_sec);
local_irq_enable();
@@ -271,48 +307,50 @@ static int omap_rtc_set_time(struct device *dev, struct rtc_time *tm)
static int omap_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+ u8 interrupts;
+
local_irq_disable();
- rtc_wait_not_busy();
+ rtc_wait_not_busy(rtc);
- alm->time.tm_sec = rtc_read(OMAP_RTC_ALARM_SECONDS_REG);
- alm->time.tm_min = rtc_read(OMAP_RTC_ALARM_MINUTES_REG);
- alm->time.tm_hour = rtc_read(OMAP_RTC_ALARM_HOURS_REG);
- alm->time.tm_mday = rtc_read(OMAP_RTC_ALARM_DAYS_REG);
- alm->time.tm_mon = rtc_read(OMAP_RTC_ALARM_MONTHS_REG);
- alm->time.tm_year = rtc_read(OMAP_RTC_ALARM_YEARS_REG);
+ alm->time.tm_sec = rtc_read(rtc, OMAP_RTC_ALARM_SECONDS_REG);
+ alm->time.tm_min = rtc_read(rtc, OMAP_RTC_ALARM_MINUTES_REG);
+ alm->time.tm_hour = rtc_read(rtc, OMAP_RTC_ALARM_HOURS_REG);
+ alm->time.tm_mday = rtc_read(rtc, OMAP_RTC_ALARM_DAYS_REG);
+ alm->time.tm_mon = rtc_read(rtc, OMAP_RTC_ALARM_MONTHS_REG);
+ alm->time.tm_year = rtc_read(rtc, OMAP_RTC_ALARM_YEARS_REG);
local_irq_enable();
bcd2tm(&alm->time);
- alm->enabled = !!(rtc_read(OMAP_RTC_INTERRUPTS_REG)
- & OMAP_RTC_INTERRUPTS_IT_ALARM);
+
+ interrupts = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ alm->enabled = !!(interrupts & OMAP_RTC_INTERRUPTS_IT_ALARM);
return 0;
}
static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
u8 reg, irqwake_reg = 0;
- struct platform_device *pdev = to_platform_device(dev);
- const struct platform_device_id *id_entry =
- platform_get_device_id(pdev);
if (tm2bcd(&alm->time) < 0)
return -EINVAL;
local_irq_disable();
- rtc_wait_not_busy();
+ rtc_wait_not_busy(rtc);
- rtc_write(alm->time.tm_year, OMAP_RTC_ALARM_YEARS_REG);
- rtc_write(alm->time.tm_mon, OMAP_RTC_ALARM_MONTHS_REG);
- rtc_write(alm->time.tm_mday, OMAP_RTC_ALARM_DAYS_REG);
- rtc_write(alm->time.tm_hour, OMAP_RTC_ALARM_HOURS_REG);
- rtc_write(alm->time.tm_min, OMAP_RTC_ALARM_MINUTES_REG);
- rtc_write(alm->time.tm_sec, OMAP_RTC_ALARM_SECONDS_REG);
+ rtc_write(rtc, OMAP_RTC_ALARM_YEARS_REG, alm->time.tm_year);
+ rtc_write(rtc, OMAP_RTC_ALARM_MONTHS_REG, alm->time.tm_mon);
+ rtc_write(rtc, OMAP_RTC_ALARM_DAYS_REG, alm->time.tm_mday);
+ rtc_write(rtc, OMAP_RTC_ALARM_HOURS_REG, alm->time.tm_hour);
+ rtc_write(rtc, OMAP_RTC_ALARM_MINUTES_REG, alm->time.tm_min);
+ rtc_write(rtc, OMAP_RTC_ALARM_SECONDS_REG, alm->time.tm_sec);
- reg = rtc_read(OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- irqwake_reg = rtc_read(OMAP_RTC_IRQWAKEEN);
+ reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ if (rtc->type->has_irqwakeen)
+ irqwake_reg = rtc_read(rtc, OMAP_RTC_IRQWAKEEN);
if (alm->enabled) {
reg |= OMAP_RTC_INTERRUPTS_IT_ALARM;
@@ -321,15 +359,79 @@ static int omap_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *alm)
reg &= ~OMAP_RTC_INTERRUPTS_IT_ALARM;
irqwake_reg &= ~OMAP_RTC_IRQWAKEEN_ALARM_WAKEEN;
}
- rtc_write(reg, OMAP_RTC_INTERRUPTS_REG);
- if (id_entry->driver_data & OMAP_RTC_HAS_IRQWAKEEN)
- rtc_write(irqwake_reg, OMAP_RTC_IRQWAKEEN);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, reg);
+ if (rtc->type->has_irqwakeen)
+ rtc_write(rtc, OMAP_RTC_IRQWAKEEN, irqwake_reg);
local_irq_enable();
return 0;
}
+static struct omap_rtc *omap_rtc_power_off_rtc;
+
+/*
+ * omap_rtc_poweroff: RTC-controlled power off
+ *
+ * The RTC can be used to control an external PMIC via the pmic_power_en pin,
+ * which can be configured to transition to OFF on ALARM2 events.
+ *
+ * Notes:
+ * The two-second alarm offset is the shortest offset possible as the alarm
+ * registers must be set before the next timer update and the offset
+ * calculation is too heavy for everything to be done within a single access
+ * period (~15 us).
+ *
+ * Called with local interrupts disabled.
+ */
+static void omap_rtc_power_off(void)
+{
+ struct omap_rtc *rtc = omap_rtc_power_off_rtc;
+ struct rtc_time tm;
+ unsigned long now;
+ u32 val;
+
+ /* enable pmic_power_en control */
+ val = rtc_readl(rtc, OMAP_RTC_PMIC_REG);
+ rtc_writel(rtc, OMAP_RTC_PMIC_REG, val | OMAP_RTC_PMIC_POWER_EN_EN);
+
+ /* set alarm two seconds from now */
+ omap_rtc_read_time_raw(rtc, &tm);
+ bcd2tm(&tm);
+ rtc_tm_to_time(&tm, &now);
+ rtc_time_to_tm(now + 2, &tm);
+
+ if (tm2bcd(&tm) < 0) {
+ dev_err(&rtc->rtc->dev, "power off failed\n");
+ return;
+ }
+
+ rtc_wait_not_busy(rtc);
+
+ rtc_write(rtc, OMAP_RTC_ALARM2_SECONDS_REG, tm.tm_sec);
+ rtc_write(rtc, OMAP_RTC_ALARM2_MINUTES_REG, tm.tm_min);
+ rtc_write(rtc, OMAP_RTC_ALARM2_HOURS_REG, tm.tm_hour);
+ rtc_write(rtc, OMAP_RTC_ALARM2_DAYS_REG, tm.tm_mday);
+ rtc_write(rtc, OMAP_RTC_ALARM2_MONTHS_REG, tm.tm_mon);
+ rtc_write(rtc, OMAP_RTC_ALARM2_YEARS_REG, tm.tm_year);
+
+ /*
+ * enable ALARM2 interrupt
+ *
+ * NOTE: this fails on AM3352 if rtc_write (writeb) is used
+ */
+ val = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG,
+ val | OMAP_RTC_INTERRUPTS_IT_ALARM2);
+
+ /*
+ * Wait for alarm to trigger (within two seconds) and external PMIC to
+ * power off the system. Add a 500 ms margin for external latencies
+ * (e.g. debounce circuits).
+ */
+ mdelay(2500);
+}
+
static struct rtc_class_ops omap_rtc_ops = {
.read_time = omap_rtc_read_time,
.set_time = omap_rtc_set_time,
@@ -338,137 +440,140 @@ static struct rtc_class_ops omap_rtc_ops = {
.alarm_irq_enable = omap_rtc_alarm_irq_enable,
};
-static int omap_rtc_alarm;
-static int omap_rtc_timer;
+static const struct omap_rtc_device_type omap_rtc_default_type = {
+ .has_power_up_reset = true,
+};
-#define OMAP_RTC_DATA_AM3352_IDX 1
-#define OMAP_RTC_DATA_DA830_IDX 2
+static const struct omap_rtc_device_type omap_rtc_am3352_type = {
+ .has_32kclk_en = true,
+ .has_kicker = true,
+ .has_irqwakeen = true,
+ .has_pmic_mode = true,
+};
-static struct platform_device_id omap_rtc_devtype[] = {
+static const struct omap_rtc_device_type omap_rtc_da830_type = {
+ .has_kicker = true,
+};
+
+static const struct platform_device_id omap_rtc_id_table[] = {
{
- .name = DRIVER_NAME,
- },
- [OMAP_RTC_DATA_AM3352_IDX] = {
+ .name = "omap_rtc",
+ .driver_data = (kernel_ulong_t)&omap_rtc_default_type,
+ }, {
.name = "am3352-rtc",
- .driver_data = OMAP_RTC_HAS_KICKER | OMAP_RTC_HAS_IRQWAKEEN |
- OMAP_RTC_HAS_32KCLK_EN,
- },
- [OMAP_RTC_DATA_DA830_IDX] = {
+ .driver_data = (kernel_ulong_t)&omap_rtc_am3352_type,
+ }, {
.name = "da830-rtc",
- .driver_data = OMAP_RTC_HAS_KICKER,
- },
- {},
+ .driver_data = (kernel_ulong_t)&omap_rtc_da830_type,
+ }, {
+ /* sentinel */
+ }
};
-MODULE_DEVICE_TABLE(platform, omap_rtc_devtype);
+MODULE_DEVICE_TABLE(platform, omap_rtc_id_table);
static const struct of_device_id omap_rtc_of_match[] = {
- { .compatible = "ti,da830-rtc",
- .data = &omap_rtc_devtype[OMAP_RTC_DATA_DA830_IDX],
- },
- { .compatible = "ti,am3352-rtc",
- .data = &omap_rtc_devtype[OMAP_RTC_DATA_AM3352_IDX],
- },
- {},
+ {
+ .compatible = "ti,am3352-rtc",
+ .data = &omap_rtc_am3352_type,
+ }, {
+ .compatible = "ti,da830-rtc",
+ .data = &omap_rtc_da830_type,
+ }, {
+ /* sentinel */
+ }
};
MODULE_DEVICE_TABLE(of, omap_rtc_of_match);
static int __init omap_rtc_probe(struct platform_device *pdev)
{
- struct resource *res;
- struct rtc_device *rtc;
- u8 reg, new_ctrl;
+ struct omap_rtc *rtc;
+ struct resource *res;
+ u8 reg, mask, new_ctrl;
const struct platform_device_id *id_entry;
const struct of_device_id *of_id;
+ int ret;
- of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
- if (of_id)
- pdev->id_entry = of_id->data;
+ rtc = devm_kzalloc(&pdev->dev, sizeof(*rtc), GFP_KERNEL);
+ if (!rtc)
+ return -ENOMEM;
- id_entry = platform_get_device_id(pdev);
- if (!id_entry) {
- dev_err(&pdev->dev, "no matching device entry\n");
- return -ENODEV;
+ of_id = of_match_device(omap_rtc_of_match, &pdev->dev);
+ if (of_id) {
+ rtc->type = of_id->data;
+ rtc->is_pmic_controller = rtc->type->has_pmic_mode &&
+ of_property_read_bool(pdev->dev.of_node,
+ "system-power-controller");
+ } else {
+ id_entry = platform_get_device_id(pdev);
+ rtc->type = (void *)id_entry->driver_data;
}
- omap_rtc_timer = platform_get_irq(pdev, 0);
- if (omap_rtc_timer <= 0) {
- pr_debug("%s: no update irq?\n", pdev->name);
+ rtc->irq_timer = platform_get_irq(pdev, 0);
+ if (rtc->irq_timer <= 0)
return -ENOENT;
- }
- omap_rtc_alarm = platform_get_irq(pdev, 1);
- if (omap_rtc_alarm <= 0) {
- pr_debug("%s: no alarm irq?\n", pdev->name);
+ rtc->irq_alarm = platform_get_irq(pdev, 1);
+ if (rtc->irq_alarm <= 0)
return -ENOENT;
- }
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- rtc_base = devm_ioremap_resource(&pdev->dev, res);
- if (IS_ERR(rtc_base))
- return PTR_ERR(rtc_base);
+ rtc->base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(rtc->base))
+ return PTR_ERR(rtc->base);
+
+ platform_set_drvdata(pdev, rtc);
/* Enable the clock/module so that we can access the registers */
pm_runtime_enable(&pdev->dev);
pm_runtime_get_sync(&pdev->dev);
- if (id_entry->driver_data & OMAP_RTC_HAS_KICKER) {
- rtc_writel(KICK0_VALUE, OMAP_RTC_KICK0_REG);
- rtc_writel(KICK1_VALUE, OMAP_RTC_KICK1_REG);
- }
-
- rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
- &omap_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtc)) {
- pr_debug("%s: can't register RTC device, err %ld\n",
- pdev->name, PTR_ERR(rtc));
- goto fail0;
+ if (rtc->type->has_kicker) {
+ rtc_writel(rtc, OMAP_RTC_KICK0_REG, KICK0_VALUE);
+ rtc_writel(rtc, OMAP_RTC_KICK1_REG, KICK1_VALUE);
}
- platform_set_drvdata(pdev, rtc);
- /* clear pending irqs, and set 1/second periodic,
- * which we'll use instead of update irqs
+ /*
+ * disable interrupts
+ *
+ * NOTE: ALARM2 is not cleared on AM3352 if rtc_write (writeb) is used
*/
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ rtc_writel(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
/* enable RTC functional clock */
- if (id_entry->driver_data & OMAP_RTC_HAS_32KCLK_EN)
- rtc_writel(OMAP_RTC_OSC_32KCLK_EN, OMAP_RTC_OSC_REG);
+ if (rtc->type->has_32kclk_en) {
+ reg = rtc_read(rtc, OMAP_RTC_OSC_REG);
+ rtc_writel(rtc, OMAP_RTC_OSC_REG,
+ reg | OMAP_RTC_OSC_32KCLK_EN);
+ }
/* clear old status */
- reg = rtc_read(OMAP_RTC_STATUS_REG);
- if (reg & (u8) OMAP_RTC_STATUS_POWER_UP) {
- pr_info("%s: RTC power up reset detected\n",
- pdev->name);
- rtc_write(OMAP_RTC_STATUS_POWER_UP, OMAP_RTC_STATUS_REG);
- }
- if (reg & (u8) OMAP_RTC_STATUS_ALARM)
- rtc_write(OMAP_RTC_STATUS_ALARM, OMAP_RTC_STATUS_REG);
+ reg = rtc_read(rtc, OMAP_RTC_STATUS_REG);
- /* handle periodic and alarm irqs */
- if (devm_request_irq(&pdev->dev, omap_rtc_timer, rtc_irq, 0,
- dev_name(&rtc->dev), rtc)) {
- pr_debug("%s: RTC timer interrupt IRQ%d already claimed\n",
- pdev->name, omap_rtc_timer);
- goto fail0;
- }
- if ((omap_rtc_timer != omap_rtc_alarm) &&
- (devm_request_irq(&pdev->dev, omap_rtc_alarm, rtc_irq, 0,
- dev_name(&rtc->dev), rtc))) {
- pr_debug("%s: RTC alarm interrupt IRQ%d already claimed\n",
- pdev->name, omap_rtc_alarm);
- goto fail0;
+ mask = OMAP_RTC_STATUS_ALARM;
+
+ if (rtc->type->has_pmic_mode)
+ mask |= OMAP_RTC_STATUS_ALARM2;
+
+ if (rtc->type->has_power_up_reset) {
+ mask |= OMAP_RTC_STATUS_POWER_UP;
+ if (reg & OMAP_RTC_STATUS_POWER_UP)
+ dev_info(&pdev->dev, "RTC power up reset detected\n");
}
+ if (reg & mask)
+ rtc_write(rtc, OMAP_RTC_STATUS_REG, reg & mask);
+
/* On boards with split power, RTC_ON_NOFF won't reset the RTC */
- reg = rtc_read(OMAP_RTC_CTRL_REG);
- if (reg & (u8) OMAP_RTC_CTRL_STOP)
- pr_info("%s: already running\n", pdev->name);
+ reg = rtc_read(rtc, OMAP_RTC_CTRL_REG);
+ if (reg & OMAP_RTC_CTRL_STOP)
+ dev_info(&pdev->dev, "already running\n");
/* force to 24 hour mode */
- new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT|OMAP_RTC_CTRL_AUTO_COMP);
+ new_ctrl = reg & (OMAP_RTC_CTRL_SPLIT | OMAP_RTC_CTRL_AUTO_COMP);
new_ctrl |= OMAP_RTC_CTRL_STOP;
- /* BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
+ /*
+ * BOARD-SPECIFIC CUSTOMIZATION CAN GO HERE:
*
* - Device wake-up capability setting should come through chip
* init logic. OMAP1 boards should initialize the "wakeup capable"
@@ -482,36 +587,70 @@ static int __init omap_rtc_probe(struct platform_device *pdev)
* is write-only, and always reads as zero...)
*/
+ if (new_ctrl & OMAP_RTC_CTRL_SPLIT)
+ dev_info(&pdev->dev, "split power mode\n");
+
+ if (reg != new_ctrl)
+ rtc_write(rtc, OMAP_RTC_CTRL_REG, new_ctrl);
+
device_init_wakeup(&pdev->dev, true);
- if (new_ctrl & (u8) OMAP_RTC_CTRL_SPLIT)
- pr_info("%s: split power mode\n", pdev->name);
+ rtc->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &omap_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtc->rtc)) {
+ ret = PTR_ERR(rtc->rtc);
+ goto err;
+ }
- if (reg != new_ctrl)
- rtc_write(new_ctrl, OMAP_RTC_CTRL_REG);
+ /* handle periodic and alarm irqs */
+ ret = devm_request_irq(&pdev->dev, rtc->irq_timer, rtc_irq, 0,
+ dev_name(&rtc->rtc->dev), rtc);
+ if (ret)
+ goto err;
+
+ if (rtc->irq_timer != rtc->irq_alarm) {
+ ret = devm_request_irq(&pdev->dev, rtc->irq_alarm, rtc_irq, 0,
+ dev_name(&rtc->rtc->dev), rtc);
+ if (ret)
+ goto err;
+ }
+
+ if (rtc->is_pmic_controller) {
+ if (!pm_power_off) {
+ omap_rtc_power_off_rtc = rtc;
+ pm_power_off = omap_rtc_power_off;
+ }
+ }
return 0;
-fail0:
- if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
- rtc_writel(0, OMAP_RTC_KICK0_REG);
+err:
+ device_init_wakeup(&pdev->dev, false);
+ if (rtc->type->has_kicker)
+ rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);
pm_runtime_put_sync(&pdev->dev);
pm_runtime_disable(&pdev->dev);
- return -EIO;
+
+ return ret;
}
static int __exit omap_rtc_remove(struct platform_device *pdev)
{
- const struct platform_device_id *id_entry =
- platform_get_device_id(pdev);
+ struct omap_rtc *rtc = platform_get_drvdata(pdev);
+
+ if (pm_power_off == omap_rtc_power_off &&
+ omap_rtc_power_off_rtc == rtc) {
+ pm_power_off = NULL;
+ omap_rtc_power_off_rtc = NULL;
+ }
device_init_wakeup(&pdev->dev, 0);
/* leave rtc running, but disable irqs */
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
- if (id_entry->driver_data & OMAP_RTC_HAS_KICKER)
- rtc_writel(0, OMAP_RTC_KICK0_REG);
+ if (rtc->type->has_kicker)
+ rtc_writel(rtc, OMAP_RTC_KICK0_REG, 0);
/* Disable the clock/module */
pm_runtime_put_sync(&pdev->dev);
@@ -521,20 +660,21 @@ static int __exit omap_rtc_remove(struct platform_device *pdev)
}
#ifdef CONFIG_PM_SLEEP
-static u8 irqstat;
-
static int omap_rtc_suspend(struct device *dev)
{
- irqstat = rtc_read(OMAP_RTC_INTERRUPTS_REG);
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
- /* FIXME the RTC alarm is not currently acting as a wakeup event
+ rtc->interrupts_reg = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+
+ /*
+ * FIXME: the RTC alarm is not currently acting as a wakeup event
* source on some platforms, and in fact this enable() call is just
* saving a flag that's never used...
*/
if (device_may_wakeup(dev))
- enable_irq_wake(omap_rtc_alarm);
+ enable_irq_wake(rtc->irq_alarm);
else
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, 0);
/* Disable the clock/module */
pm_runtime_put_sync(dev);
@@ -544,13 +684,15 @@ static int omap_rtc_suspend(struct device *dev)
static int omap_rtc_resume(struct device *dev)
{
+ struct omap_rtc *rtc = dev_get_drvdata(dev);
+
/* Enable the clock/module so that we can access the registers */
pm_runtime_get_sync(dev);
if (device_may_wakeup(dev))
- disable_irq_wake(omap_rtc_alarm);
+ disable_irq_wake(rtc->irq_alarm);
else
- rtc_write(irqstat, OMAP_RTC_INTERRUPTS_REG);
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, rtc->interrupts_reg);
return 0;
}
@@ -560,23 +702,32 @@ static SIMPLE_DEV_PM_OPS(omap_rtc_pm_ops, omap_rtc_suspend, omap_rtc_resume);
static void omap_rtc_shutdown(struct platform_device *pdev)
{
- rtc_write(0, OMAP_RTC_INTERRUPTS_REG);
+ struct omap_rtc *rtc = platform_get_drvdata(pdev);
+ u8 mask;
+
+ /*
+ * Keep the ALARM interrupt enabled to allow the system to power up on
+ * alarm events.
+ */
+ mask = rtc_read(rtc, OMAP_RTC_INTERRUPTS_REG);
+ mask &= OMAP_RTC_INTERRUPTS_IT_ALARM;
+ rtc_write(rtc, OMAP_RTC_INTERRUPTS_REG, mask);
}
-MODULE_ALIAS("platform:omap_rtc");
static struct platform_driver omap_rtc_driver = {
.remove = __exit_p(omap_rtc_remove),
.shutdown = omap_rtc_shutdown,
.driver = {
- .name = DRIVER_NAME,
+ .name = "omap_rtc",
.owner = THIS_MODULE,
.pm = &omap_rtc_pm_ops,
.of_match_table = omap_rtc_of_match,
},
- .id_table = omap_rtc_devtype,
+ .id_table = omap_rtc_id_table,
};
module_platform_driver_probe(omap_rtc_driver, omap_rtc_probe);
+MODULE_ALIAS("platform:omap_rtc");
MODULE_AUTHOR("George G. Davis (and others)");
MODULE_LICENSE("GPL");
diff --git a/drivers/rtc/rtc-pcf8563.c b/drivers/rtc/rtc-pcf8563.c
index c2ef0a2..96fb32e 100644
--- a/drivers/rtc/rtc-pcf8563.c
+++ b/drivers/rtc/rtc-pcf8563.c
@@ -28,6 +28,7 @@
#define PCF8563_REG_ST2 0x01
#define PCF8563_BIT_AIE (1 << 1)
#define PCF8563_BIT_AF (1 << 3)
+#define PCF8563_BITS_ST2_N (7 << 5)
#define PCF8563_REG_SC 0x02 /* datetime */
#define PCF8563_REG_MN 0x03
@@ -41,6 +42,13 @@
#define PCF8563_REG_CLKO 0x0D /* clock out */
#define PCF8563_REG_TMRC 0x0E /* timer control */
+#define PCF8563_TMRC_ENABLE BIT(7)
+#define PCF8563_TMRC_4096 0
+#define PCF8563_TMRC_64 1
+#define PCF8563_TMRC_1 2
+#define PCF8563_TMRC_1_60 3
+#define PCF8563_TMRC_MASK 3
+
#define PCF8563_REG_TMR 0x0F /* timer */
#define PCF8563_SC_LV 0x80 /* low voltage */
@@ -118,22 +126,21 @@ static int pcf8563_write_block_data(struct i2c_client *client,
static int pcf8563_set_alarm_mode(struct i2c_client *client, bool on)
{
- unsigned char buf[2];
+ unsigned char buf;
int err;
- err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, buf + 1);
+ err = pcf8563_read_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err < 0)
return err;
if (on)
- buf[1] |= PCF8563_BIT_AIE;
+ buf |= PCF8563_BIT_AIE;
else
- buf[1] &= ~PCF8563_BIT_AIE;
+ buf &= ~PCF8563_BIT_AIE;
- buf[1] &= ~PCF8563_BIT_AF;
- buf[0] = PCF8563_REG_ST2;
+ buf &= ~(PCF8563_BIT_AF | PCF8563_BITS_ST2_N);
- err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, buf + 1);
+ err = pcf8563_write_block_data(client, PCF8563_REG_ST2, 1, &buf);
if (err < 0) {
dev_err(&client->dev, "%s: write error\n", __func__);
return -EIO;
@@ -336,8 +343,8 @@ static int pcf8563_rtc_read_alarm(struct device *dev, struct rtc_wkalrm *tm)
__func__, buf[0], buf[1], buf[2], buf[3]);
tm->time.tm_min = bcd2bin(buf[0] & 0x7F);
- tm->time.tm_hour = bcd2bin(buf[1] & 0x7F);
- tm->time.tm_mday = bcd2bin(buf[2] & 0x1F);
+ tm->time.tm_hour = bcd2bin(buf[1] & 0x3F);
+ tm->time.tm_mday = bcd2bin(buf[2] & 0x3F);
tm->time.tm_wday = bcd2bin(buf[3] & 0x7);
tm->time.tm_mon = -1;
tm->time.tm_year = -1;
@@ -361,6 +368,14 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
struct i2c_client *client = to_i2c_client(dev);
unsigned char buf[4];
int err;
+ unsigned long alarm_time;
+
+ /* The alarm has no seconds, round up to nearest minute */
+ if (tm->time.tm_sec) {
+ rtc_tm_to_time(&tm->time, &alarm_time);
+ alarm_time += 60-tm->time.tm_sec;
+ rtc_time_to_tm(alarm_time, &tm->time);
+ }
dev_dbg(dev, "%s, min=%d hour=%d wday=%d mday=%d "
"enabled=%d pending=%d\n", __func__,
@@ -381,6 +396,7 @@ static int pcf8563_rtc_set_alarm(struct device *dev, struct rtc_wkalrm *tm)
static int pcf8563_irq_enable(struct device *dev, unsigned int enabled)
{
+ dev_dbg(dev, "%s: en=%d\n", __func__, enabled);
return pcf8563_set_alarm_mode(to_i2c_client(dev), !!enabled);
}
@@ -398,6 +414,8 @@ static int pcf8563_probe(struct i2c_client *client,
{
struct pcf8563 *pcf8563;
int err;
+ unsigned char buf;
+ unsigned char alm_pending;
dev_dbg(&client->dev, "%s\n", __func__);
@@ -415,6 +433,22 @@ static int pcf8563_probe(struct i2c_client *client,
pcf8563->client = client;
device_set_wakeup_capable(&client->dev, 1);
+ /* Set timer to lowest frequency to save power (ref Haoyu datasheet) */
+ buf = PCF8563_TMRC_1_60;
+ err = pcf8563_write_block_data(client, PCF8563_REG_TMRC, 1, &buf);
+ if (err < 0) {
+ dev_err(&client->dev, "%s: write error\n", __func__);
+ return err;
+ }
+
+ err = pcf8563_get_alarm_mode(client, NULL, &alm_pending);
+ if (err < 0) {
+ dev_err(&client->dev, "%s: read error\n", __func__);
+ return err;
+ }
+ if (alm_pending)
+ pcf8563_set_alarm_mode(client, 0);
+
pcf8563->rtc = devm_rtc_device_register(&client->dev,
pcf8563_driver.driver.name,
&pcf8563_rtc_ops, THIS_MODULE);
@@ -435,6 +469,9 @@ static int pcf8563_probe(struct i2c_client *client,
}
+ /* the pcf8563 alarm only supports a minute accuracy */
+ pcf8563->rtc->uie_unsupported = 1;
+
return 0;
}
diff --git a/drivers/rtc/rtc-sirfsoc.c b/drivers/rtc/rtc-sirfsoc.c
index 76e38007b..d2ac668 100644
--- a/drivers/rtc/rtc-sirfsoc.c
+++ b/drivers/rtc/rtc-sirfsoc.c
@@ -47,6 +47,7 @@ struct sirfsoc_rtc_drv {
unsigned irq_wake;
/* Overflow for every 8 years extra time */
u32 overflow_rtc;
+ spinlock_t lock;
#ifdef CONFIG_PM
u32 saved_counter;
u32 saved_overflow_rtc;
@@ -61,7 +62,7 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,
rtcdrv = dev_get_drvdata(dev);
- local_irq_disable();
+ spin_lock_irq(&rtcdrv->lock);
rtc_count = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_CN);
@@ -84,7 +85,8 @@ static int sirfsoc_rtc_read_alarm(struct device *dev,
if (sirfsoc_rtc_iobrg_readl(
rtcdrv->rtc_base + RTC_STATUS) & SIRFSOC_RTC_AL0E)
alrm->enabled = 1;
- local_irq_enable();
+
+ spin_unlock_irq(&rtcdrv->lock);
return 0;
}
@@ -99,7 +101,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
if (alrm->enabled) {
rtc_tm_to_time(&(alrm->time), &rtc_alarm);
- local_irq_disable();
+ spin_lock_irq(&rtcdrv->lock);
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
rtcdrv->rtc_base + RTC_STATUS);
@@ -123,14 +125,15 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
rtc_status_reg |= SIRFSOC_RTC_AL0E;
sirfsoc_rtc_iobrg_writel(
rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
- local_irq_enable();
+
+ spin_unlock_irq(&rtcdrv->lock);
} else {
/*
* if this function was called with enabled=0
* then it could mean that the application is
* trying to cancel an ongoing alarm
*/
- local_irq_disable();
+ spin_lock_irq(&rtcdrv->lock);
rtc_status_reg = sirfsoc_rtc_iobrg_readl(
rtcdrv->rtc_base + RTC_STATUS);
@@ -146,7 +149,7 @@ static int sirfsoc_rtc_set_alarm(struct device *dev,
rtcdrv->rtc_base + RTC_STATUS);
}
- local_irq_enable();
+ spin_unlock_irq(&rtcdrv->lock);
}
return 0;
@@ -209,12 +212,38 @@ static int sirfsoc_rtc_ioctl(struct device *dev, unsigned int cmd,
}
}
+static int sirfsoc_rtc_alarm_irq_enable(struct device *dev,
+ unsigned int enabled)
+{
+ unsigned long rtc_status_reg = 0x0;
+ struct sirfsoc_rtc_drv *rtcdrv;
+
+ rtcdrv = dev_get_drvdata(dev);
+
+ spin_lock_irq(&rtcdrv->lock);
+
+ rtc_status_reg = sirfsoc_rtc_iobrg_readl(
+ rtcdrv->rtc_base + RTC_STATUS);
+ if (enabled)
+ rtc_status_reg |= SIRFSOC_RTC_AL0E;
+ else
+ rtc_status_reg &= ~SIRFSOC_RTC_AL0E;
+
+ sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
+
+ spin_unlock_irq(&rtcdrv->lock);
+
+ return 0;
+
+}
+
static const struct rtc_class_ops sirfsoc_rtc_ops = {
.read_time = sirfsoc_rtc_read_time,
.set_time = sirfsoc_rtc_set_time,
.read_alarm = sirfsoc_rtc_read_alarm,
.set_alarm = sirfsoc_rtc_set_alarm,
- .ioctl = sirfsoc_rtc_ioctl
+ .ioctl = sirfsoc_rtc_ioctl,
+ .alarm_irq_enable = sirfsoc_rtc_alarm_irq_enable
};
static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
@@ -223,6 +252,8 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
unsigned long rtc_status_reg = 0x0;
unsigned long events = 0x0;
+ spin_lock(&rtcdrv->lock);
+
rtc_status_reg = sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_STATUS);
/* this bit will be set ONLY if an alarm was active
* and it expired NOW
@@ -240,6 +271,9 @@ static irqreturn_t sirfsoc_rtc_irq_handler(int irq, void *pdata)
rtc_status_reg &= ~(SIRFSOC_RTC_AL0E);
}
sirfsoc_rtc_iobrg_writel(rtc_status_reg, rtcdrv->rtc_base + RTC_STATUS);
+
+ spin_unlock(&rtcdrv->lock);
+
/* this should wake up any apps polling/waiting on the read
* after setting the alarm
*/
@@ -267,6 +301,8 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
if (rtcdrv == NULL)
return -ENOMEM;
+ spin_lock_init(&rtcdrv->lock);
+
err = of_property_read_u32(np, "reg", &rtcdrv->rtc_base);
if (err) {
dev_err(&pdev->dev, "unable to find base address of rtc node in dtb\n");
@@ -286,14 +322,6 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
rtc_div = ((32768 / RTC_HZ) / 2) - 1;
sirfsoc_rtc_iobrg_writel(rtc_div, rtcdrv->rtc_base + RTC_DIV);
- rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
- &sirfsoc_rtc_ops, THIS_MODULE);
- if (IS_ERR(rtcdrv->rtc)) {
- err = PTR_ERR(rtcdrv->rtc);
- dev_err(&pdev->dev, "can't register RTC device\n");
- return err;
- }
-
/* 0x3 -> RTC_CLK */
sirfsoc_rtc_iobrg_writel(SIRFSOC_RTC_CLK,
rtcdrv->rtc_base + RTC_CLOCK_SWITCH);
@@ -308,6 +336,14 @@ static int sirfsoc_rtc_probe(struct platform_device *pdev)
rtcdrv->overflow_rtc =
sirfsoc_rtc_iobrg_readl(rtcdrv->rtc_base + RTC_SW_VALUE);
+ rtcdrv->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
+ &sirfsoc_rtc_ops, THIS_MODULE);
+ if (IS_ERR(rtcdrv->rtc)) {
+ err = PTR_ERR(rtcdrv->rtc);
+ dev_err(&pdev->dev, "can't register RTC device\n");
+ return err;
+ }
+
rtcdrv->irq = platform_get_irq(pdev, 0);
err = devm_request_irq(
&pdev->dev,
diff --git a/drivers/rtc/rtc-snvs.c b/drivers/rtc/rtc-snvs.c
index fa384fe..2cd8ffe 100644
--- a/drivers/rtc/rtc-snvs.c
+++ b/drivers/rtc/rtc-snvs.c
@@ -17,6 +17,7 @@
#include <linux/of_device.h>
#include <linux/platform_device.h>
#include <linux/rtc.h>
+#include <linux/clk.h>
/* These register offsets are relative to LP (Low Power) range */
#define SNVS_LPCR 0x04
@@ -39,6 +40,7 @@ struct snvs_rtc_data {
void __iomem *ioaddr;
int irq;
spinlock_t lock;
+ struct clk *clk;
};
static u32 rtc_read_lp_counter(void __iomem *ioaddr)
@@ -260,6 +262,18 @@ static int snvs_rtc_probe(struct platform_device *pdev)
if (data->irq < 0)
return data->irq;
+ data->clk = devm_clk_get(&pdev->dev, "snvs-rtc");
+ if (IS_ERR(data->clk)) {
+ data->clk = NULL;
+ } else {
+ ret = clk_prepare_enable(data->clk);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "Could not prepare or enable the snvs clock\n");
+ return ret;
+ }
+ }
+
platform_set_drvdata(pdev, data);
spin_lock_init(&data->lock);
@@ -280,7 +294,7 @@ static int snvs_rtc_probe(struct platform_device *pdev)
if (ret) {
dev_err(&pdev->dev, "failed to request irq %d: %d\n",
data->irq, ret);
- return ret;
+ goto error_rtc_device_register;
}
data->rtc = devm_rtc_device_register(&pdev->dev, pdev->name,
@@ -288,10 +302,16 @@ static int snvs_rtc_probe(struct platform_device *pdev)
if (IS_ERR(data->rtc)) {
ret = PTR_ERR(data->rtc);
dev_err(&pdev->dev, "failed to register rtc: %d\n", ret);
- return ret;
+ goto error_rtc_device_register;
}
return 0;
+
+error_rtc_device_register:
+ if (data->clk)
+ clk_disable_unprepare(data->clk);
+
+ return ret;
}
#ifdef CONFIG_PM_SLEEP
@@ -302,21 +322,34 @@ static int snvs_rtc_suspend(struct device *dev)
if (device_may_wakeup(dev))
enable_irq_wake(data->irq);
+ if (data->clk)
+ clk_disable_unprepare(data->clk);
+
return 0;
}
static int snvs_rtc_resume(struct device *dev)
{
struct snvs_rtc_data *data = dev_get_drvdata(dev);
+ int ret;
if (device_may_wakeup(dev))
disable_irq_wake(data->irq);
+ if (data->clk) {
+ ret = clk_prepare_enable(data->clk);
+ if (ret)
+ return ret;
+ }
+
return 0;
}
#endif
-static SIMPLE_DEV_PM_OPS(snvs_rtc_pm_ops, snvs_rtc_suspend, snvs_rtc_resume);
+static const struct dev_pm_ops snvs_rtc_pm_ops = {
+ .suspend_noirq = snvs_rtc_suspend,
+ .resume_noirq = snvs_rtc_resume,
+};
static const struct of_device_id snvs_dt_ids[] = {
{ .compatible = "fsl,sec-v4.0-mon-rtc-lp", },
diff --git a/drivers/s390/char/hmcdrv_dev.c b/drivers/s390/char/hmcdrv_dev.c
index 0c51761..43cee7f 100644
--- a/drivers/s390/char/hmcdrv_dev.c
+++ b/drivers/s390/char/hmcdrv_dev.c
@@ -136,8 +136,7 @@ static int hmcdrv_dev_open(struct inode *inode, struct file *fp)
if (rc)
module_put(THIS_MODULE);
- pr_debug("open file '/dev/%s' with return code %d\n",
- fp->f_dentry->d_name.name, rc);
+ pr_debug("open file '/dev/%pD' with return code %d\n", fp, rc);
return rc;
}
@@ -146,7 +145,7 @@ static int hmcdrv_dev_open(struct inode *inode, struct file *fp)
*/
static int hmcdrv_dev_release(struct inode *inode, struct file *fp)
{
- pr_debug("closing file '/dev/%s'\n", fp->f_dentry->d_name.name);
+ pr_debug("closing file '/dev/%pD'\n", fp);
kfree(fp->private_data);
fp->private_data = NULL;
hmcdrv_ftp_shutdown();
@@ -231,8 +230,8 @@ static ssize_t hmcdrv_dev_read(struct file *fp, char __user *ubuf,
retlen = hmcdrv_dev_transfer((char *) fp->private_data,
*pos, ubuf, len);
- pr_debug("read from file '/dev/%s' at %lld returns %zd/%zu\n",
- fp->f_dentry->d_name.name, (long long) *pos, retlen, len);
+ pr_debug("read from file '/dev/%pD' at %lld returns %zd/%zu\n",
+ fp, (long long) *pos, retlen, len);
if (retlen > 0)
*pos += retlen;
@@ -248,8 +247,8 @@ static ssize_t hmcdrv_dev_write(struct file *fp, const char __user *ubuf,
{
ssize_t retlen;
- pr_debug("writing file '/dev/%s' at pos. %lld with length %zd\n",
- fp->f_dentry->d_name.name, (long long) *pos, len);
+ pr_debug("writing file '/dev/%pD' at pos. %lld with length %zd\n",
+ fp, (long long) *pos, len);
if (!fp->private_data) { /* first expect a cmd write */
fp->private_data = kmalloc(len + 1, GFP_KERNEL);
@@ -272,8 +271,7 @@ static ssize_t hmcdrv_dev_write(struct file *fp, const char __user *ubuf,
if (retlen > 0)
*pos += retlen;
- pr_debug("write to file '/dev/%s' returned %zd\n",
- fp->f_dentry->d_name.name, retlen);
+ pr_debug("write to file '/dev/%pD' returned %zd\n", fp, retlen);
return retlen;
}
diff --git a/drivers/s390/kvm/kvm_virtio.c b/drivers/s390/kvm/kvm_virtio.c
index 6431290..dd65c8b 100644
--- a/drivers/s390/kvm/kvm_virtio.c
+++ b/drivers/s390/kvm/kvm_virtio.c
@@ -80,7 +80,7 @@ static unsigned desc_size(const struct kvm_device_desc *desc)
}
/* This gets the device's feature bits. */
-static u32 kvm_get_features(struct virtio_device *vdev)
+static u64 kvm_get_features(struct virtio_device *vdev)
{
unsigned int i;
u32 features = 0;
@@ -93,7 +93,7 @@ static u32 kvm_get_features(struct virtio_device *vdev)
return features;
}
-static void kvm_finalize_features(struct virtio_device *vdev)
+static int kvm_finalize_features(struct virtio_device *vdev)
{
unsigned int i, bits;
struct kvm_device_desc *desc = to_kvmdev(vdev)->desc;
@@ -103,12 +103,17 @@ static void kvm_finalize_features(struct virtio_device *vdev)
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
+ /* Make sure we don't have any features > 32 bits! */
+ BUG_ON((u32)vdev->features != vdev->features);
+
memset(out_features, 0, desc->feature_len);
bits = min_t(unsigned, desc->feature_len, sizeof(vdev->features)) * 8;
for (i = 0; i < bits; i++) {
- if (test_bit(i, vdev->features))
+ if (__virtio_test_bit(vdev, i))
out_features[i / 8] |= (1 << (i % 8));
}
+
+ return 0;
}
/*
diff --git a/drivers/s390/kvm/virtio_ccw.c b/drivers/s390/kvm/virtio_ccw.c
index bda52f1..71d7802 100644
--- a/drivers/s390/kvm/virtio_ccw.c
+++ b/drivers/s390/kvm/virtio_ccw.c
@@ -55,6 +55,7 @@ struct virtio_ccw_device {
struct ccw_device *cdev;
__u32 curr_io;
int err;
+ unsigned int revision; /* Transport revision */
wait_queue_head_t wait_q;
spinlock_t lock;
struct list_head virtqueues;
@@ -67,13 +68,22 @@ struct virtio_ccw_device {
void *airq_info;
};
-struct vq_info_block {
+struct vq_info_block_legacy {
__u64 queue;
__u32 align;
__u16 index;
__u16 num;
} __packed;
+struct vq_info_block {
+ __u64 desc;
+ __u32 res0;
+ __u16 index;
+ __u16 num;
+ __u64 avail;
+ __u64 used;
+} __packed;
+
struct virtio_feature_desc {
__u32 features;
__u8 index;
@@ -86,11 +96,23 @@ struct virtio_thinint_area {
u8 isc;
} __packed;
+struct virtio_rev_info {
+ __u16 revision;
+ __u16 length;
+ __u8 data[];
+};
+
+/* the highest virtio-ccw revision we support */
+#define VIRTIO_CCW_REV_MAX 1
+
struct virtio_ccw_vq_info {
struct virtqueue *vq;
int num;
void *queue;
- struct vq_info_block *info_block;
+ union {
+ struct vq_info_block s;
+ struct vq_info_block_legacy l;
+ } *info_block;
int bit_nr;
struct list_head node;
long cookie;
@@ -122,6 +144,7 @@ static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
#define CCW_CMD_WRITE_STATUS 0x31
#define CCW_CMD_READ_VQ_CONF 0x32
#define CCW_CMD_SET_IND_ADAPTER 0x73
+#define CCW_CMD_SET_VIRTIO_REV 0x83
#define VIRTIO_CCW_DOING_SET_VQ 0x00010000
#define VIRTIO_CCW_DOING_RESET 0x00040000
@@ -134,6 +157,7 @@ static struct airq_info *airq_areas[MAX_AIRQ_AREAS];
#define VIRTIO_CCW_DOING_READ_VQ_CONF 0x02000000
#define VIRTIO_CCW_DOING_SET_CONF_IND 0x04000000
#define VIRTIO_CCW_DOING_SET_IND_ADAPTER 0x08000000
+#define VIRTIO_CCW_DOING_SET_VIRTIO_REV 0x10000000
#define VIRTIO_CCW_INTPARM_MASK 0xffff0000
static struct virtio_ccw_device *to_vc_device(struct virtio_device *vdev)
@@ -399,13 +423,22 @@ static void virtio_ccw_del_vq(struct virtqueue *vq, struct ccw1 *ccw)
spin_unlock_irqrestore(&vcdev->lock, flags);
/* Release from host. */
- info->info_block->queue = 0;
- info->info_block->align = 0;
- info->info_block->index = index;
- info->info_block->num = 0;
+ if (vcdev->revision == 0) {
+ info->info_block->l.queue = 0;
+ info->info_block->l.align = 0;
+ info->info_block->l.index = index;
+ info->info_block->l.num = 0;
+ ccw->count = sizeof(info->info_block->l);
+ } else {
+ info->info_block->s.desc = 0;
+ info->info_block->s.index = index;
+ info->info_block->s.num = 0;
+ info->info_block->s.avail = 0;
+ info->info_block->s.used = 0;
+ ccw->count = sizeof(info->info_block->s);
+ }
ccw->cmd_code = CCW_CMD_SET_VQ;
ccw->flags = 0;
- ccw->count = sizeof(*info->info_block);
ccw->cda = (__u32)(unsigned long)(info->info_block);
ret = ccw_io_helper(vcdev, ccw,
VIRTIO_CCW_DOING_SET_VQ | index);
@@ -488,13 +521,22 @@ static struct virtqueue *virtio_ccw_setup_vq(struct virtio_device *vdev,
}
/* Register it with the host. */
- info->info_block->queue = (__u64)info->queue;
- info->info_block->align = KVM_VIRTIO_CCW_RING_ALIGN;
- info->info_block->index = i;
- info->info_block->num = info->num;
+ if (vcdev->revision == 0) {
+ info->info_block->l.queue = (__u64)info->queue;
+ info->info_block->l.align = KVM_VIRTIO_CCW_RING_ALIGN;
+ info->info_block->l.index = i;
+ info->info_block->l.num = info->num;
+ ccw->count = sizeof(info->info_block->l);
+ } else {
+ info->info_block->s.desc = (__u64)info->queue;
+ info->info_block->s.index = i;
+ info->info_block->s.num = info->num;
+ info->info_block->s.avail = (__u64)virtqueue_get_avail(vq);
+ info->info_block->s.used = (__u64)virtqueue_get_used(vq);
+ ccw->count = sizeof(info->info_block->s);
+ }
ccw->cmd_code = CCW_CMD_SET_VQ;
ccw->flags = 0;
- ccw->count = sizeof(*info->info_block);
ccw->cda = (__u32)(unsigned long)(info->info_block);
err = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_SET_VQ | i);
if (err) {
@@ -660,11 +702,12 @@ static void virtio_ccw_reset(struct virtio_device *vdev)
kfree(ccw);
}
-static u32 virtio_ccw_get_features(struct virtio_device *vdev)
+static u64 virtio_ccw_get_features(struct virtio_device *vdev)
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct virtio_feature_desc *features;
- int ret, rc;
+ int ret;
+ u64 rc;
struct ccw1 *ccw;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
@@ -677,7 +720,6 @@ static u32 virtio_ccw_get_features(struct virtio_device *vdev)
goto out_free;
}
/* Read the feature bits from the host. */
- /* TODO: Features > 32 bits */
features->index = 0;
ccw->cmd_code = CCW_CMD_READ_FEAT;
ccw->flags = 0;
@@ -691,46 +733,79 @@ static u32 virtio_ccw_get_features(struct virtio_device *vdev)
rc = le32_to_cpu(features->features);
+ if (vcdev->revision == 0)
+ goto out_free;
+
+ /* Read second half of the feature bits from the host. */
+ features->index = 1;
+ ccw->cmd_code = CCW_CMD_READ_FEAT;
+ ccw->flags = 0;
+ ccw->count = sizeof(*features);
+ ccw->cda = (__u32)(unsigned long)features;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_READ_FEAT);
+ if (ret == 0)
+ rc |= (u64)le32_to_cpu(features->features) << 32;
+
out_free:
kfree(features);
kfree(ccw);
return rc;
}
-static void virtio_ccw_finalize_features(struct virtio_device *vdev)
+static int virtio_ccw_finalize_features(struct virtio_device *vdev)
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
struct virtio_feature_desc *features;
- int i;
struct ccw1 *ccw;
+ int ret;
+
+ if (vcdev->revision >= 1 &&
+ !__virtio_test_bit(vdev, VIRTIO_F_VERSION_1)) {
+ dev_err(&vdev->dev, "virtio: device uses revision 1 "
+ "but does not have VIRTIO_F_VERSION_1\n");
+ return -EINVAL;
+ }
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
- return;
+ return -ENOMEM;
features = kzalloc(sizeof(*features), GFP_DMA | GFP_KERNEL);
- if (!features)
+ if (!features) {
+ ret = -ENOMEM;
goto out_free;
-
+ }
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
- for (i = 0; i < sizeof(*vdev->features) / sizeof(features->features);
- i++) {
- int highbits = i % 2 ? 32 : 0;
- features->index = i;
- features->features = cpu_to_le32(vdev->features[i / 2]
- >> highbits);
- /* Write the feature bits to the host. */
- ccw->cmd_code = CCW_CMD_WRITE_FEAT;
- ccw->flags = 0;
- ccw->count = sizeof(*features);
- ccw->cda = (__u32)(unsigned long)features;
- ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
- }
+ features->index = 0;
+ features->features = cpu_to_le32((u32)vdev->features);
+ /* Write the first half of the feature bits to the host. */
+ ccw->cmd_code = CCW_CMD_WRITE_FEAT;
+ ccw->flags = 0;
+ ccw->count = sizeof(*features);
+ ccw->cda = (__u32)(unsigned long)features;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
+ if (ret)
+ goto out_free;
+
+ if (vcdev->revision == 0)
+ goto out_free;
+
+ features->index = 1;
+ features->features = cpu_to_le32(vdev->features >> 32);
+ /* Write the second half of the feature bits to the host. */
+ ccw->cmd_code = CCW_CMD_WRITE_FEAT;
+ ccw->flags = 0;
+ ccw->count = sizeof(*features);
+ ccw->cda = (__u32)(unsigned long)features;
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_FEAT);
+
out_free:
kfree(features);
kfree(ccw);
+
+ return ret;
}
static void virtio_ccw_get_config(struct virtio_device *vdev,
@@ -806,7 +881,9 @@ static u8 virtio_ccw_get_status(struct virtio_device *vdev)
static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
{
struct virtio_ccw_device *vcdev = to_vc_device(vdev);
+ u8 old_status = *vcdev->status;
struct ccw1 *ccw;
+ int ret;
ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
if (!ccw)
@@ -818,7 +895,10 @@ static void virtio_ccw_set_status(struct virtio_device *vdev, u8 status)
ccw->flags = 0;
ccw->count = sizeof(status);
ccw->cda = (__u32)(unsigned long)vcdev->status;
- ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
+ ret = ccw_io_helper(vcdev, ccw, VIRTIO_CCW_DOING_WRITE_STATUS);
+ /* Write failed? We assume status is unchanged. */
+ if (ret)
+ *vcdev->status = old_status;
kfree(ccw);
}
@@ -919,6 +999,7 @@ static void virtio_ccw_int_handler(struct ccw_device *cdev,
case VIRTIO_CCW_DOING_RESET:
case VIRTIO_CCW_DOING_READ_VQ_CONF:
case VIRTIO_CCW_DOING_SET_IND_ADAPTER:
+ case VIRTIO_CCW_DOING_SET_VIRTIO_REV:
vcdev->curr_io &= ~activity;
wake_up(&vcdev->wait_q);
break;
@@ -1034,6 +1115,51 @@ static int virtio_ccw_offline(struct ccw_device *cdev)
return 0;
}
+static int virtio_ccw_set_transport_rev(struct virtio_ccw_device *vcdev)
+{
+ struct virtio_rev_info *rev;
+ struct ccw1 *ccw;
+ int ret;
+
+ ccw = kzalloc(sizeof(*ccw), GFP_DMA | GFP_KERNEL);
+ if (!ccw)
+ return -ENOMEM;
+ rev = kzalloc(sizeof(*rev), GFP_DMA | GFP_KERNEL);
+ if (!rev) {
+ kfree(ccw);
+ return -ENOMEM;
+ }
+
+ /* Set transport revision */
+ ccw->cmd_code = CCW_CMD_SET_VIRTIO_REV;
+ ccw->flags = 0;
+ ccw->count = sizeof(*rev);
+ ccw->cda = (__u32)(unsigned long)rev;
+
+ vcdev->revision = VIRTIO_CCW_REV_MAX;
+ do {
+ rev->revision = vcdev->revision;
+ /* none of our supported revisions carry payload */
+ rev->length = 0;
+ ret = ccw_io_helper(vcdev, ccw,
+ VIRTIO_CCW_DOING_SET_VIRTIO_REV);
+ if (ret == -EOPNOTSUPP) {
+ if (vcdev->revision == 0)
+ /*
+ * The host device does not support setting
+ * the revision: let's operate it in legacy
+ * mode.
+ */
+ ret = 0;
+ else
+ vcdev->revision--;
+ }
+ } while (ret == -EOPNOTSUPP);
+
+ kfree(ccw);
+ kfree(rev);
+ return ret;
+}
static int virtio_ccw_online(struct ccw_device *cdev)
{
@@ -1074,6 +1200,15 @@ static int virtio_ccw_online(struct ccw_device *cdev)
spin_unlock_irqrestore(get_ccwdev_lock(cdev), flags);
vcdev->vdev.id.vendor = cdev->id.cu_type;
vcdev->vdev.id.device = cdev->id.cu_model;
+
+ if (virtio_device_is_legacy_only(vcdev->vdev.id)) {
+ vcdev->revision = 0;
+ } else {
+ ret = virtio_ccw_set_transport_rev(vcdev);
+ if (ret)
+ goto out_free;
+ }
+
ret = register_virtio_device(&vcdev->vdev);
if (ret) {
dev_warn(&cdev->dev, "Failed to register virtio device: %d\n",
diff --git a/drivers/s390/scsi/zfcp_aux.c b/drivers/s390/scsi/zfcp_aux.c
index 8004b07..01a7339 100644
--- a/drivers/s390/scsi/zfcp_aux.c
+++ b/drivers/s390/scsi/zfcp_aux.c
@@ -353,9 +353,11 @@ struct zfcp_adapter *zfcp_adapter_enqueue(struct ccw_device *ccw_device)
adapter->ccw_device = ccw_device;
INIT_WORK(&adapter->stat_work, _zfcp_status_read_scheduler);
- INIT_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
+ INIT_DELAYED_WORK(&adapter->scan_work, zfcp_fc_scan_ports);
INIT_WORK(&adapter->ns_up_work, zfcp_fc_sym_name_update);
+ adapter->next_port_scan = jiffies;
+
if (zfcp_qdio_setup(adapter))
goto failed;
@@ -420,7 +422,7 @@ void zfcp_adapter_unregister(struct zfcp_adapter *adapter)
{
struct ccw_device *cdev = adapter->ccw_device;
- cancel_work_sync(&adapter->scan_work);
+ cancel_delayed_work_sync(&adapter->scan_work);
cancel_work_sync(&adapter->stat_work);
cancel_work_sync(&adapter->ns_up_work);
zfcp_destroy_adapter_work_queue(adapter);
diff --git a/drivers/s390/scsi/zfcp_ccw.c b/drivers/s390/scsi/zfcp_ccw.c
index f9879d4..54c7b48 100644
--- a/drivers/s390/scsi/zfcp_ccw.c
+++ b/drivers/s390/scsi/zfcp_ccw.c
@@ -56,8 +56,22 @@ static int zfcp_ccw_activate(struct ccw_device *cdev, int clear, char *tag)
zfcp_erp_set_adapter_status(adapter, ZFCP_STATUS_COMMON_RUNNING);
zfcp_erp_adapter_reopen(adapter, ZFCP_STATUS_COMMON_ERP_FAILED,
tag);
+
+ /*
+ * We want to scan ports here, with some random backoff and without
+ * rate limit. Recovery has already scheduled a port scan for us,
+ * but with both random delay and rate limit. Nevertheless we get
+ * what we want here by flushing the scheduled work after sleeping
+ * an equivalent random time.
+ * Let the port scan random delay elapse first. If recovery finishes
+ * up to that point in time, that would be perfect for both recovery
+ * and port scan. If not, i.e. recovery takes ages, there was no
+ * point in waiting a random delay on top of the time consumed by
+ * recovery.
+ */
+ msleep(zfcp_fc_port_scan_backoff());
zfcp_erp_wait(adapter);
- flush_work(&adapter->scan_work); /* ok to call even if nothing queued */
+ flush_delayed_work(&adapter->scan_work);
zfcp_ccw_adapter_put(adapter);
@@ -162,11 +176,19 @@ static int zfcp_ccw_set_online(struct ccw_device *cdev)
adapter->req_no = 0;
zfcp_ccw_activate(cdev, 0, "ccsonl1");
- /* scan for remote ports
- either at the end of any successful adapter recovery
- or only after the adapter recovery for setting a device online */
+
+ /*
+ * We want to scan ports here, always, with some random delay and
+ * without rate limit - basically what zfcp_ccw_activate() has
+ * achieved for us. Not quite! That port scan depended on
+ * !no_auto_port_rescan. So let's cover the no_auto_port_rescan
+ * case here to make sure a port scan is done unconditionally.
+ * Since zfcp_ccw_activate() has waited the desired random time,
+ * we can immediately schedule and flush a port scan for the
+ * remaining cases.
+ */
zfcp_fc_inverse_conditional_port_scan(adapter);
- flush_work(&adapter->scan_work); /* ok to call even if nothing queued */
+ flush_delayed_work(&adapter->scan_work);
zfcp_ccw_adapter_put(adapter);
return 0;
}
diff --git a/drivers/s390/scsi/zfcp_def.h b/drivers/s390/scsi/zfcp_def.h
index d91173f..b8e853e 100644
--- a/drivers/s390/scsi/zfcp_def.h
+++ b/drivers/s390/scsi/zfcp_def.h
@@ -186,12 +186,13 @@ struct zfcp_adapter {
struct fc_host_statistics *fc_stats;
struct fsf_qtcb_bottom_port *stats_reset_data;
unsigned long stats_reset;
- struct work_struct scan_work;
+ struct delayed_work scan_work;
struct work_struct ns_up_work;
struct service_level service_level;
struct workqueue_struct *work_queue;
struct device_dma_parameters dma_parms;
struct zfcp_fc_events events;
+ unsigned long next_port_scan;
};
struct zfcp_port {
diff --git a/drivers/s390/scsi/zfcp_erp.c b/drivers/s390/scsi/zfcp_erp.c
index c82fe65..2c5d456 100644
--- a/drivers/s390/scsi/zfcp_erp.c
+++ b/drivers/s390/scsi/zfcp_erp.c
@@ -821,11 +821,6 @@ static int zfcp_erp_port_forced_strategy_close(struct zfcp_erp_action *act)
return ZFCP_ERP_CONTINUES;
}
-static void zfcp_erp_port_strategy_clearstati(struct zfcp_port *port)
-{
- atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED, &port->status);
-}
-
static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
{
struct zfcp_port *port = erp_action->port;
@@ -833,7 +828,6 @@ static int zfcp_erp_port_forced_strategy(struct zfcp_erp_action *erp_action)
switch (erp_action->step) {
case ZFCP_ERP_STEP_UNINITIALIZED:
- zfcp_erp_port_strategy_clearstati(port);
if ((status & ZFCP_STATUS_PORT_PHYS_OPEN) &&
(status & ZFCP_STATUS_COMMON_OPEN))
return zfcp_erp_port_forced_strategy_close(erp_action);
@@ -933,7 +927,6 @@ static int zfcp_erp_port_strategy(struct zfcp_erp_action *erp_action)
switch (erp_action->step) {
case ZFCP_ERP_STEP_UNINITIALIZED:
- zfcp_erp_port_strategy_clearstati(port);
if (p_status & ZFCP_STATUS_COMMON_OPEN)
return zfcp_erp_port_strategy_close(erp_action);
break;
diff --git a/drivers/s390/scsi/zfcp_ext.h b/drivers/s390/scsi/zfcp_ext.h
index a9c570a..5b50065 100644
--- a/drivers/s390/scsi/zfcp_ext.h
+++ b/drivers/s390/scsi/zfcp_ext.h
@@ -85,6 +85,7 @@ extern void zfcp_fc_gs_destroy(struct zfcp_adapter *);
extern int zfcp_fc_exec_bsg_job(struct fc_bsg_job *);
extern int zfcp_fc_timeout_bsg_job(struct fc_bsg_job *);
extern void zfcp_fc_sym_name_update(struct work_struct *);
+extern unsigned int zfcp_fc_port_scan_backoff(void);
extern void zfcp_fc_conditional_port_scan(struct zfcp_adapter *);
extern void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *);
diff --git a/drivers/s390/scsi/zfcp_fc.c b/drivers/s390/scsi/zfcp_fc.c
index ca28e1c..25d49f3 100644
--- a/drivers/s390/scsi/zfcp_fc.c
+++ b/drivers/s390/scsi/zfcp_fc.c
@@ -12,6 +12,7 @@
#include <linux/types.h>
#include <linux/slab.h>
#include <linux/utsname.h>
+#include <linux/random.h>
#include <scsi/fc/fc_els.h>
#include <scsi/libfc.h>
#include "zfcp_ext.h"
@@ -31,12 +32,54 @@ module_param_named(no_auto_port_rescan, no_auto_port_rescan, bool, 0600);
MODULE_PARM_DESC(no_auto_port_rescan,
"no automatic port_rescan (default off)");
+static unsigned int port_scan_backoff = 500;
+module_param(port_scan_backoff, uint, 0600);
+MODULE_PARM_DESC(port_scan_backoff,
+ "upper limit of port scan random backoff in msecs (default 500)");
+
+static unsigned int port_scan_ratelimit = 60000;
+module_param(port_scan_ratelimit, uint, 0600);
+MODULE_PARM_DESC(port_scan_ratelimit,
+ "minimum interval between port scans in msecs (default 60000)");
+
+unsigned int zfcp_fc_port_scan_backoff(void)
+{
+ if (!port_scan_backoff)
+ return 0;
+ return get_random_int() % port_scan_backoff;
+}
+
+static void zfcp_fc_port_scan_time(struct zfcp_adapter *adapter)
+{
+ unsigned long interval = msecs_to_jiffies(port_scan_ratelimit);
+ unsigned long backoff = msecs_to_jiffies(zfcp_fc_port_scan_backoff());
+
+ adapter->next_port_scan = jiffies + interval + backoff;
+}
+
+static void zfcp_fc_port_scan(struct zfcp_adapter *adapter)
+{
+ unsigned long now = jiffies;
+ unsigned long next = adapter->next_port_scan;
+ unsigned long delay = 0, max;
+
+ /* delay only needed within waiting period */
+ if (time_before(now, next)) {
+ delay = next - now;
+ /* paranoia: never ever delay scans longer than specified */
+ max = msecs_to_jiffies(port_scan_ratelimit + port_scan_backoff);
+ delay = min(delay, max);
+ }
+
+ queue_delayed_work(adapter->work_queue, &adapter->scan_work, delay);
+}
+
void zfcp_fc_conditional_port_scan(struct zfcp_adapter *adapter)
{
if (no_auto_port_rescan)
return;
- queue_work(adapter->work_queue, &adapter->scan_work);
+ zfcp_fc_port_scan(adapter);
}
void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter)
@@ -44,7 +87,7 @@ void zfcp_fc_inverse_conditional_port_scan(struct zfcp_adapter *adapter)
if (!no_auto_port_rescan)
return;
- queue_work(adapter->work_queue, &adapter->scan_work);
+ zfcp_fc_port_scan(adapter);
}
/**
@@ -680,12 +723,15 @@ static int zfcp_fc_eval_gpn_ft(struct zfcp_fc_req *fc_req,
*/
void zfcp_fc_scan_ports(struct work_struct *work)
{
- struct zfcp_adapter *adapter = container_of(work, struct zfcp_adapter,
+ struct delayed_work *dw = to_delayed_work(work);
+ struct zfcp_adapter *adapter = container_of(dw, struct zfcp_adapter,
scan_work);
int ret, i;
struct zfcp_fc_req *fc_req;
int chain, max_entries, buf_num, max_bytes;
+ zfcp_fc_port_scan_time(adapter);
+
chain = adapter->adapter_features & FSF_FEATURE_ELS_CT_CHAINED_SBALS;
buf_num = chain ? ZFCP_FC_GPN_FT_NUM_BUFS : 1;
max_entries = chain ? ZFCP_FC_GPN_FT_MAX_ENT : ZFCP_FC_GPN_FT_ENT_PAGE;
diff --git a/drivers/s390/scsi/zfcp_fc.h b/drivers/s390/scsi/zfcp_fc.h
index b1d2024..df2b541 100644
--- a/drivers/s390/scsi/zfcp_fc.h
+++ b/drivers/s390/scsi/zfcp_fc.h
@@ -212,8 +212,6 @@ static inline
void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi,
u8 tm_flags)
{
- char tag[2];
-
int_to_scsilun(scsi->device->lun, (struct scsi_lun *) &fcp->fc_lun);
if (unlikely(tm_flags)) {
@@ -221,17 +219,7 @@ void zfcp_fc_scsi_to_fcp(struct fcp_cmnd *fcp, struct scsi_cmnd *scsi,
return;
}
- if (scsi_populate_tag_msg(scsi, tag)) {
- switch (tag[0]) {
- case MSG_ORDERED_TAG:
- fcp->fc_pri_ta |= FCP_PTA_ORDERED;
- break;
- case MSG_SIMPLE_TAG:
- fcp->fc_pri_ta |= FCP_PTA_SIMPLE;
- break;
- };
- } else
- fcp->fc_pri_ta = FCP_PTA_SIMPLE;
+ fcp->fc_pri_ta = FCP_PTA_SIMPLE;
if (scsi->sc_data_direction == DMA_FROM_DEVICE)
fcp->fc_flags |= FCP_CFL_RDDATA;
diff --git a/drivers/s390/scsi/zfcp_fsf.c b/drivers/s390/scsi/zfcp_fsf.c
index 0fe8d5d..21ec5e2 100644
--- a/drivers/s390/scsi/zfcp_fsf.c
+++ b/drivers/s390/scsi/zfcp_fsf.c
@@ -1396,8 +1396,7 @@ static void zfcp_fsf_open_port_handler(struct zfcp_fsf_req *req)
port->handle = header->port_handle;
atomic_set_mask(ZFCP_STATUS_COMMON_OPEN |
ZFCP_STATUS_PORT_PHYS_OPEN, &port->status);
- atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_DENIED |
- ZFCP_STATUS_COMMON_ACCESS_BOXED,
+ atomic_clear_mask(ZFCP_STATUS_COMMON_ACCESS_BOXED,
&port->status);
/* check whether D_ID has changed during open */
/*
diff --git a/drivers/s390/scsi/zfcp_scsi.c b/drivers/s390/scsi/zfcp_scsi.c
index 7b35364..75f4bfc 100644
--- a/drivers/s390/scsi/zfcp_scsi.c
+++ b/drivers/s390/scsi/zfcp_scsi.c
@@ -32,25 +32,6 @@ static bool allow_lun_scan = 1;
module_param(allow_lun_scan, bool, 0600);
MODULE_PARM_DESC(allow_lun_scan, "For NPIV, scan and attach all storage LUNs");
-static int zfcp_scsi_change_queue_depth(struct scsi_device *sdev, int depth,
- int reason)
-{
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, depth);
- break;
- case SCSI_QDEPTH_RAMP_UP:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
- return sdev->queue_depth;
-}
-
static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)
{
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev);
@@ -66,9 +47,7 @@ static void zfcp_scsi_slave_destroy(struct scsi_device *sdev)
static int zfcp_scsi_slave_configure(struct scsi_device *sdp)
{
if (sdp->tagged_supported)
- scsi_adjust_queue_depth(sdp, MSG_SIMPLE_TAG, default_depth);
- else
- scsi_adjust_queue_depth(sdp, 0, 1);
+ scsi_change_queue_depth(sdp, default_depth);
return 0;
}
@@ -307,7 +286,7 @@ static struct scsi_host_template zfcp_scsi_host_template = {
.slave_alloc = zfcp_scsi_slave_alloc,
.slave_configure = zfcp_scsi_slave_configure,
.slave_destroy = zfcp_scsi_slave_destroy,
- .change_queue_depth = zfcp_scsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.proc_name = "zfcp",
.can_queue = 4096,
.this_id = -1,
@@ -322,6 +301,7 @@ static struct scsi_host_template zfcp_scsi_host_template = {
.use_clustering = 1,
.shost_attrs = zfcp_sysfs_shost_attrs,
.sdev_attrs = zfcp_sysfs_sdev_attrs,
+ .track_queue_depth = 1,
};
/**
diff --git a/drivers/s390/scsi/zfcp_sysfs.c b/drivers/s390/scsi/zfcp_sysfs.c
index 672b572..96a0be1 100644
--- a/drivers/s390/scsi/zfcp_sysfs.c
+++ b/drivers/s390/scsi/zfcp_sysfs.c
@@ -73,9 +73,7 @@ ZFCP_DEFINE_ATTR(zfcp_port, port, status, "0x%08x\n",
ZFCP_DEFINE_ATTR(zfcp_port, port, in_recovery, "%d\n",
(atomic_read(&port->status) &
ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
-ZFCP_DEFINE_ATTR(zfcp_port, port, access_denied, "%d\n",
- (atomic_read(&port->status) &
- ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
+ZFCP_DEFINE_ATTR_CONST(port, access_denied, "%d\n", 0);
ZFCP_DEFINE_ATTR(zfcp_unit, unit, status, "0x%08x\n",
zfcp_unit_sdev_status(unit));
@@ -223,9 +221,13 @@ static ssize_t zfcp_sysfs_port_rescan_store(struct device *dev,
if (!adapter)
return -ENODEV;
- /* sync the user-space- with the kernel-invocation of scan_work */
- queue_work(adapter->work_queue, &adapter->scan_work);
- flush_work(&adapter->scan_work);
+ /*
+ * Users wish is our command: immediately schedule and flush a
+ * worker to conduct a synchronous port scan, that is, neither
+ * a random delay nor a rate limit is applied here.
+ */
+ queue_delayed_work(adapter->work_queue, &adapter->scan_work, 0);
+ flush_delayed_work(&adapter->scan_work);
zfcp_ccw_adapter_put(adapter);
return (ssize_t) count;
@@ -439,16 +441,15 @@ static ssize_t zfcp_sysfs_scsi_##_name##_show(struct device *dev, \
{ \
struct scsi_device *sdev = to_scsi_device(dev); \
struct zfcp_scsi_dev *zfcp_sdev = sdev_to_zfcp(sdev); \
- struct zfcp_port *port = zfcp_sdev->port; \
\
return sprintf(buf, _format, _value); \
} \
static DEVICE_ATTR(_name, S_IRUGO, zfcp_sysfs_scsi_##_name##_show, NULL);
ZFCP_DEFINE_SCSI_ATTR(hba_id, "%s\n",
- dev_name(&port->adapter->ccw_device->dev));
+ dev_name(&zfcp_sdev->port->adapter->ccw_device->dev));
ZFCP_DEFINE_SCSI_ATTR(wwpn, "0x%016llx\n",
- (unsigned long long) port->wwpn);
+ (unsigned long long) zfcp_sdev->port->wwpn);
static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev,
struct device_attribute *attr,
@@ -460,6 +461,49 @@ static ssize_t zfcp_sysfs_scsi_fcp_lun_show(struct device *dev,
}
static DEVICE_ATTR(fcp_lun, S_IRUGO, zfcp_sysfs_scsi_fcp_lun_show, NULL);
+ZFCP_DEFINE_SCSI_ATTR(zfcp_access_denied, "%d\n",
+ (atomic_read(&zfcp_sdev->status) &
+ ZFCP_STATUS_COMMON_ACCESS_DENIED) != 0);
+
+static ssize_t zfcp_sysfs_scsi_zfcp_failed_show(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned int status = atomic_read(&sdev_to_zfcp(sdev)->status);
+ unsigned int failed = status & ZFCP_STATUS_COMMON_ERP_FAILED ? 1 : 0;
+
+ return sprintf(buf, "%d\n", failed);
+}
+
+static ssize_t zfcp_sysfs_scsi_zfcp_failed_store(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t count)
+{
+ struct scsi_device *sdev = to_scsi_device(dev);
+ unsigned long val;
+
+ if (kstrtoul(buf, 0, &val) || val != 0)
+ return -EINVAL;
+
+ zfcp_erp_set_lun_status(sdev, ZFCP_STATUS_COMMON_RUNNING);
+ zfcp_erp_lun_reopen(sdev, ZFCP_STATUS_COMMON_ERP_FAILED,
+ "syufai3");
+ zfcp_erp_wait(sdev_to_zfcp(sdev)->port->adapter);
+
+ return count;
+}
+static DEVICE_ATTR(zfcp_failed, S_IWUSR | S_IRUGO,
+ zfcp_sysfs_scsi_zfcp_failed_show,
+ zfcp_sysfs_scsi_zfcp_failed_store);
+
+ZFCP_DEFINE_SCSI_ATTR(zfcp_in_recovery, "%d\n",
+ (atomic_read(&zfcp_sdev->status) &
+ ZFCP_STATUS_COMMON_ERP_INUSE) != 0);
+
+ZFCP_DEFINE_SCSI_ATTR(zfcp_status, "0x%08x\n",
+ atomic_read(&zfcp_sdev->status));
+
struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
&dev_attr_fcp_lun,
&dev_attr_wwpn,
@@ -467,6 +511,10 @@ struct device_attribute *zfcp_sysfs_sdev_attrs[] = {
&dev_attr_read_latency,
&dev_attr_write_latency,
&dev_attr_cmd_latency,
+ &dev_attr_zfcp_access_denied,
+ &dev_attr_zfcp_failed,
+ &dev_attr_zfcp_in_recovery,
+ &dev_attr_zfcp_status,
NULL
};
diff --git a/drivers/scsi/3w-9xxx.c b/drivers/scsi/3w-9xxx.c
index 0a73253..cd4129f 100644
--- a/drivers/scsi/3w-9xxx.c
+++ b/drivers/scsi/3w-9xxx.c
@@ -189,19 +189,6 @@ static ssize_t twa_show_stats(struct device *dev,
return len;
} /* End twa_show_stats() */
-/* This function will set a devices queue depth */
-static int twa_change_queue_depth(struct scsi_device *sdev, int queue_depth,
- int reason)
-{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
- if (queue_depth > TW_Q_LENGTH-2)
- queue_depth = TW_Q_LENGTH-2;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
- return queue_depth;
-} /* End twa_change_queue_depth() */
-
/* Create sysfs 'stats' entry */
static struct device_attribute twa_host_stats_attr = {
.attr = {
@@ -2016,7 +2003,7 @@ static struct scsi_host_template driver_template = {
.queuecommand = twa_scsi_queue,
.eh_host_reset_handler = twa_scsi_eh_reset,
.bios_param = twa_scsi_biosparam,
- .change_queue_depth = twa_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.can_queue = TW_Q_LENGTH-2,
.slave_configure = twa_slave_configure,
.this_id = -1,
diff --git a/drivers/scsi/3w-sas.c b/drivers/scsi/3w-sas.c
index 6da6cec..2361772 100644
--- a/drivers/scsi/3w-sas.c
+++ b/drivers/scsi/3w-sas.c
@@ -191,19 +191,6 @@ static ssize_t twl_show_stats(struct device *dev,
return len;
} /* End twl_show_stats() */
-/* This function will set a devices queue depth */
-static int twl_change_queue_depth(struct scsi_device *sdev, int queue_depth,
- int reason)
-{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
- if (queue_depth > TW_Q_LENGTH-2)
- queue_depth = TW_Q_LENGTH-2;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
- return queue_depth;
-} /* End twl_change_queue_depth() */
-
/* stats sysfs attribute initializer */
static struct device_attribute twl_host_stats_attr = {
.attr = {
@@ -1590,7 +1577,7 @@ static struct scsi_host_template driver_template = {
.queuecommand = twl_scsi_queue,
.eh_host_reset_handler = twl_scsi_eh_reset,
.bios_param = twl_scsi_biosparam,
- .change_queue_depth = twl_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.can_queue = TW_Q_LENGTH-2,
.slave_configure = twl_slave_configure,
.this_id = -1,
diff --git a/drivers/scsi/3w-xxxx.c b/drivers/scsi/3w-xxxx.c
index 752624e..c75f204 100644
--- a/drivers/scsi/3w-xxxx.c
+++ b/drivers/scsi/3w-xxxx.c
@@ -523,19 +523,6 @@ static ssize_t tw_show_stats(struct device *dev, struct device_attribute *attr,
return len;
} /* End tw_show_stats() */
-/* This function will set a devices queue depth */
-static int tw_change_queue_depth(struct scsi_device *sdev, int queue_depth,
- int reason)
-{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
- if (queue_depth > TW_Q_LENGTH-2)
- queue_depth = TW_Q_LENGTH-2;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
- return queue_depth;
-} /* End tw_change_queue_depth() */
-
/* Create sysfs 'stats' entry */
static struct device_attribute tw_host_stats_attr = {
.attr = {
@@ -2270,7 +2257,7 @@ static struct scsi_host_template driver_template = {
.queuecommand = tw_scsi_queue,
.eh_host_reset_handler = tw_scsi_eh_reset,
.bios_param = tw_scsi_biosparam,
- .change_queue_depth = tw_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.can_queue = TW_Q_LENGTH-2,
.slave_configure = tw_slave_configure,
.this_id = -1,
diff --git a/drivers/scsi/53c700.c b/drivers/scsi/53c700.c
index fabd4be..aa915da 100644
--- a/drivers/scsi/53c700.c
+++ b/drivers/scsi/53c700.c
@@ -175,7 +175,7 @@ STATIC void NCR_700_chip_reset(struct Scsi_Host *host);
STATIC int NCR_700_slave_alloc(struct scsi_device *SDpnt);
STATIC int NCR_700_slave_configure(struct scsi_device *SDpnt);
STATIC void NCR_700_slave_destroy(struct scsi_device *SDpnt);
-static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth, int reason);
+static int NCR_700_change_queue_depth(struct scsi_device *SDpnt, int depth);
static int NCR_700_change_queue_type(struct scsi_device *SDpnt, int depth);
STATIC struct device_attribute *NCR_700_dev_attrs[];
@@ -327,6 +327,7 @@ NCR_700_detect(struct scsi_host_template *tpnt,
tpnt->slave_alloc = NCR_700_slave_alloc;
tpnt->change_queue_depth = NCR_700_change_queue_depth;
tpnt->change_queue_type = NCR_700_change_queue_type;
+ tpnt->use_blk_tags = 1;
if(tpnt->name == NULL)
tpnt->name = "53c700";
@@ -592,19 +593,14 @@ NCR_700_scsi_done(struct NCR_700_Host_Parameters *hostdata,
hostdata->cmd = NULL;
if(SCp != NULL) {
- struct NCR_700_command_slot *slot =
+ struct NCR_700_command_slot *slot =
(struct NCR_700_command_slot *)SCp->host_scribble;
-
+
dma_unmap_single(hostdata->dev, slot->pCmd,
MAX_COMMAND_SIZE, DMA_TO_DEVICE);
if (slot->flags == NCR_700_FLAG_AUTOSENSE) {
char *cmnd = NCR_700_get_sense_cmnd(SCp->device);
-#ifdef NCR_700_DEBUG
- printk(" ORIGINAL CMD %p RETURNED %d, new return is %d sense is\n",
- SCp, SCp->cmnd[7], result);
- scsi_print_sense("53c700", SCp);
-#endif
dma_unmap_single(hostdata->dev, slot->dma_handle,
SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
/* restore the old result if the request sense was
@@ -906,8 +902,10 @@ process_message(struct Scsi_Host *host, struct NCR_700_Host_Parameters *hostdata
/* we're done negotiating */
NCR_700_set_tag_neg_state(SCp->device, NCR_700_FINISHED_TAG_NEGOTIATION);
hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
+
SCp->device->tagged_supported = 0;
- scsi_deactivate_tcq(SCp->device, host->cmd_per_lun);
+ scsi_change_queue_depth(SCp->device, host->cmd_per_lun);
+ scsi_set_tag_type(SCp->device, 0);
} else {
shost_printk(KERN_WARNING, host,
"(%d:%d) Unexpected REJECT Message %s\n",
@@ -1432,7 +1430,7 @@ NCR_700_start_command(struct scsi_cmnd *SCp)
if((hostdata->tag_negotiated & (1<<scmd_id(SCp)))
&& (slot->tag != SCSI_NO_TAG && SCp->cmnd[0] != REQUEST_SENSE &&
slot->flags != NCR_700_FLAG_AUTOSENSE)) {
- count += scsi_populate_tag_msg(SCp, &hostdata->msgout[count]);
+ count += spi_populate_tag_msg(&hostdata->msgout[count], SCp);
}
if(hostdata->fast &&
@@ -1772,7 +1770,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
*/
if(NCR_700_get_depth(SCp->device) != 0
&& (!(hostdata->tag_negotiated & (1<<scmd_id(SCp)))
- || !blk_rq_tagged(SCp->request))) {
+ || !(SCp->flags & SCMD_TAGGED))) {
CDEBUG(KERN_ERR, SCp, "has non zero depth %d\n",
NCR_700_get_depth(SCp->device));
return SCSI_MLQUEUE_DEVICE_BUSY;
@@ -1800,7 +1798,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
printk("53c700: scsi%d, command ", SCp->device->host->host_no);
scsi_print_command(SCp);
#endif
- if(blk_rq_tagged(SCp->request)
+ if ((SCp->flags & SCMD_TAGGED)
&& (hostdata->tag_negotiated &(1<<scmd_id(SCp))) == 0
&& NCR_700_get_tag_neg_state(SCp->device) == NCR_700_START_TAG_NEGOTIATION) {
scmd_printk(KERN_ERR, SCp, "Enabling Tag Command Queuing\n");
@@ -1814,7 +1812,7 @@ NCR_700_queuecommand_lck(struct scsi_cmnd *SCp, void (*done)(struct scsi_cmnd *)
*
* FIXME: This will royally screw up on multiple LUN devices
* */
- if(!blk_rq_tagged(SCp->request)
+ if (!(SCp->flags & SCMD_TAGGED)
&& (hostdata->tag_negotiated &(1<<scmd_id(SCp)))) {
scmd_printk(KERN_INFO, SCp, "Disabling Tag Command Queuing\n");
hostdata->tag_negotiated &= ~(1<<scmd_id(SCp));
@@ -1911,9 +1909,7 @@ NCR_700_abort(struct scsi_cmnd * SCp)
{
struct NCR_700_command_slot *slot;
- scmd_printk(KERN_INFO, SCp,
- "New error handler wants to abort command\n\t");
- scsi_print_command(SCp);
+ scmd_printk(KERN_INFO, SCp, "abort command\n");
slot = (struct NCR_700_command_slot *)SCp->host_scribble;
@@ -2056,13 +2052,10 @@ NCR_700_slave_configure(struct scsi_device *SDp)
/* to do here: allocate memory; build a queue_full list */
if(SDp->tagged_supported) {
- scsi_set_tag_type(SDp, MSG_ORDERED_TAG);
- scsi_activate_tcq(SDp, NCR_700_DEFAULT_TAGS);
+ scsi_change_queue_depth(SDp, NCR_700_DEFAULT_TAGS);
NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
- } else {
- /* initialise to default depth */
- scsi_adjust_queue_depth(SDp, 0, SDp->host->cmd_per_lun);
}
+
if(hostdata->fast) {
/* Find the correct offset and period via domain validation */
if (!spi_initial_dv(SDp->sdev_target))
@@ -2082,16 +2075,11 @@ NCR_700_slave_destroy(struct scsi_device *SDp)
}
static int
-NCR_700_change_queue_depth(struct scsi_device *SDp, int depth, int reason)
+NCR_700_change_queue_depth(struct scsi_device *SDp, int depth)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (depth > NCR_700_MAX_TAGS)
depth = NCR_700_MAX_TAGS;
-
- scsi_adjust_queue_depth(SDp, scsi_get_tag_type(SDp), depth);
- return depth;
+ return scsi_change_queue_depth(SDp, depth);
}
static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
@@ -2101,8 +2089,6 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
struct NCR_700_Host_Parameters *hostdata =
(struct NCR_700_Host_Parameters *)SDp->host->hostdata[0];
- scsi_set_tag_type(SDp, tag_type);
-
/* We have a global (per target) flag to track whether TCQ is
* enabled, so we'll be turning it off for the entire target here.
* our tag algorithm will fail if we mix tagged and untagged commands,
@@ -2110,15 +2096,16 @@ static int NCR_700_change_queue_type(struct scsi_device *SDp, int tag_type)
if (change_tag)
scsi_target_quiesce(SDp->sdev_target);
+ scsi_set_tag_type(SDp, tag_type);
if (!tag_type) {
/* shift back to the default unqueued number of commands
* (the user can still raise this) */
- scsi_deactivate_tcq(SDp, SDp->host->cmd_per_lun);
+ scsi_change_queue_depth(SDp, SDp->host->cmd_per_lun);
hostdata->tag_negotiated &= ~(1 << sdev_id(SDp));
} else {
/* Here, we cleared the negotiation flag above, so this
* will force the driver to renegotiate */
- scsi_activate_tcq(SDp, SDp->queue_depth);
+ scsi_change_queue_depth(SDp, SDp->queue_depth);
if (change_tag)
NCR_700_set_tag_neg_state(SDp, NCR_700_START_TAG_NEGOTIATION);
}
diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c
index 64c7514..8d66a64 100644
--- a/drivers/scsi/BusLogic.c
+++ b/drivers/scsi/BusLogic.c
@@ -2327,12 +2327,12 @@ static int blogic_slaveconfig(struct scsi_device *dev)
if (qdepth == 0)
qdepth = BLOGIC_MAX_AUTO_TAG_DEPTH;
adapter->qdepth[tgt_id] = qdepth;
- scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, qdepth);
+ scsi_change_queue_depth(dev, qdepth);
} else {
adapter->tagq_ok &= ~(1 << tgt_id);
qdepth = adapter->untag_qdepth;
adapter->qdepth[tgt_id] = qdepth;
- scsi_adjust_queue_depth(dev, 0, qdepth);
+ scsi_change_queue_depth(dev, qdepth);
}
qdepth = 0;
for (tgt_id = 0; tgt_id < adapter->maxdev; tgt_id++)
diff --git a/drivers/scsi/Kconfig b/drivers/scsi/Kconfig
index 3a820f6..86cf3d6 100644
--- a/drivers/scsi/Kconfig
+++ b/drivers/scsi/Kconfig
@@ -1341,13 +1341,15 @@ config SCSI_DC395x
To compile this driver as a module, choose M here: the
module will be called dc395x.
-config SCSI_DC390T
- tristate "Tekram DC390(T) and Am53/79C974 SCSI support"
+config SCSI_AM53C974
+ tristate "Tekram DC390(T) and Am53/79C974 SCSI support (new driver)"
depends on PCI && SCSI
+ select SCSI_SPI_ATTRS
---help---
This driver supports PCI SCSI host adapters based on the Am53C974A
chip, e.g. Tekram DC390(T), DawiControl 2974 and some onboard
PCscsi/PCnet (Am53/79C974) solutions.
+ This is a new implementation base on the generic esp_scsi driver.
Documentation can be found in <file:Documentation/scsi/tmscsim.txt>.
@@ -1355,7 +1357,7 @@ config SCSI_DC390T
based on NCR/Symbios chips. Use "NCR53C8XX SCSI support" for those.
To compile this driver as a module, choose M here: the
- module will be called tmscsim.
+ module will be called am53c974.
config SCSI_T128
tristate "Trantor T128/T128F/T228 SCSI support"
@@ -1451,6 +1453,14 @@ config SCSI_NSP32
To compile this driver as a module, choose M here: the
module will be called nsp32.
+config SCSI_WD719X
+ tristate "Western Digital WD7193/7197/7296 support"
+ depends on PCI && SCSI
+ select EEPROM_93CX6
+ ---help---
+ This is a driver for Western Digital WD7193, WD7197 and WD7296 PCI
+ SCSI controllers (based on WD33C296A chip).
+
config SCSI_DEBUG
tristate "SCSI debugging host simulator"
depends on SCSI
@@ -1615,7 +1625,7 @@ config ATARI_SCSI_RESET_BOOT
that leave the devices with SCSI operations partway completed.
config MAC_SCSI
- bool "Macintosh NCR5380 SCSI"
+ tristate "Macintosh NCR5380 SCSI"
depends on MAC && SCSI=y
select SCSI_SPI_ATTRS
help
diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile
index 59f1ce6..58158f1 100644
--- a/drivers/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -100,7 +100,7 @@ obj-$(CONFIG_SCSI_EATA_PIO) += eata_pio.o
obj-$(CONFIG_SCSI_7000FASST) += wd7000.o
obj-$(CONFIG_SCSI_EATA) += eata.o
obj-$(CONFIG_SCSI_DC395x) += dc395x.o
-obj-$(CONFIG_SCSI_DC390T) += tmscsim.o
+obj-$(CONFIG_SCSI_AM53C974) += esp_scsi.o am53c974.o
obj-$(CONFIG_MEGARAID_LEGACY) += megaraid.o
obj-$(CONFIG_MEGARAID_NEWGEN) += megaraid/
obj-$(CONFIG_MEGARAID_SAS) += megaraid/
@@ -143,6 +143,7 @@ obj-$(CONFIG_SCSI_VIRTIO) += virtio_scsi.o
obj-$(CONFIG_VMWARE_PVSCSI) += vmw_pvscsi.o
obj-$(CONFIG_XEN_SCSI_FRONTEND) += xen-scsifront.o
obj-$(CONFIG_HYPERV_STORAGE) += hv_storvsc.o
+obj-$(CONFIG_SCSI_WD719X) += wd719x.o
obj-$(CONFIG_ARM) += arm/
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
index 45da3c8..36244d6 100644
--- a/drivers/scsi/NCR5380.c
+++ b/drivers/scsi/NCR5380.c
@@ -11,8 +11,6 @@
* drew@colorado.edu
* +1 (303) 666-5836
*
- * DISTRIBUTION RELEASE 6.
- *
* For more information, please consult
*
* NCR 5380 Family
@@ -279,7 +277,7 @@ static void do_reset(struct Scsi_Host *host);
* Set up the internal fields in the SCSI command.
*/
-static __inline__ void initialize_SCp(Scsi_Cmnd * cmd)
+static inline void initialize_SCp(struct scsi_cmnd *cmd)
{
/*
* Initialize the Scsi Pointer field so that all of the commands in the
@@ -574,12 +572,12 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
int trying_irqs, i, mask;
NCR5380_setup(instance);
- for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
+ for (trying_irqs = 0, i = 1, mask = 2; i < 16; ++i, mask <<= 1)
if ((mask & possible) && (request_irq(i, &probe_intr, 0, "NCR-probe", NULL) == 0))
trying_irqs |= mask;
timeout = jiffies + (250 * HZ / 1000);
- probe_irq = SCSI_IRQ_NONE;
+ probe_irq = NO_IRQ;
/*
* A interrupt is triggered whenever BSY = false, SEL = true
@@ -596,13 +594,13 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA | ICR_ASSERT_SEL);
- while (probe_irq == SCSI_IRQ_NONE && time_before(jiffies, timeout))
+ while (probe_irq == NO_IRQ && time_before(jiffies, timeout))
schedule_timeout_uninterruptible(1);
NCR5380_write(SELECT_ENABLE_REG, 0);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)
+ for (i = 1, mask = 2; i < 16; ++i, mask <<= 1)
if (trying_irqs & mask)
free_irq(i, NULL);
@@ -610,50 +608,70 @@ static int __init __maybe_unused NCR5380_probe_irq(struct Scsi_Host *instance,
}
/**
- * NCR58380_print_options - show options
- * @instance: unused for now
+ * NCR58380_info - report driver and host information
+ * @instance: relevant scsi host instance
*
- * Called by probe code indicating the NCR5380 driver options that
- * were selected. At some point this will switch to runtime options
- * read from the adapter in question
+ * For use as the host template info() handler.
*
* Locks: none
*/
-static void __init __maybe_unused
-NCR5380_print_options(struct Scsi_Host *instance)
+static const char *NCR5380_info(struct Scsi_Host *instance)
{
- printk(" generic options"
-#ifdef AUTOPROBE_IRQ
- " AUTOPROBE_IRQ"
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ return hostdata->info;
+}
+
+static void prepare_info(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ snprintf(hostdata->info, sizeof(hostdata->info),
+ "%s, io_port 0x%lx, n_io_port %d, "
+ "base 0x%lx, irq %d, "
+ "can_queue %d, cmd_per_lun %d, "
+ "sg_tablesize %d, this_id %d, "
+ "flags { %s%s%s}, "
+#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
+ "USLEEP_POLL %d, USLEEP_WAITLONG %d, "
#endif
-#ifdef AUTOSENSE
- " AUTOSENSE"
+ "options { %s} ",
+ instance->hostt->name, instance->io_port, instance->n_io_port,
+ instance->base, instance->irq,
+ instance->can_queue, instance->cmd_per_lun,
+ instance->sg_tablesize, instance->this_id,
+ hostdata->flags & FLAG_NCR53C400 ? "NCR53C400 " : "",
+ hostdata->flags & FLAG_DTC3181E ? "DTC3181E " : "",
+ hostdata->flags & FLAG_NO_PSEUDO_DMA ? "NO_PSEUDO_DMA " : "",
+#if defined(USLEEP_POLL) && defined(USLEEP_WAITLONG)
+ USLEEP_POLL, USLEEP_WAITLONG,
+#endif
+#ifdef AUTOPROBE_IRQ
+ "AUTOPROBE_IRQ "
#endif
#ifdef DIFFERENTIAL
- " DIFFERENTIAL"
+ "DIFFERENTIAL "
#endif
#ifdef REAL_DMA
- " REAL DMA"
+ "REAL_DMA "
#endif
#ifdef REAL_DMA_POLL
- " REAL DMA POLL"
+ "REAL_DMA_POLL "
#endif
#ifdef PARITY
- " PARITY"
+ "PARITY "
#endif
#ifdef PSEUDO_DMA
- " PSEUDO DMA"
+ "PSEUDO_DMA "
#endif
#ifdef UNSAFE
- " UNSAFE "
+ "UNSAFE "
#endif
- );
- printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);
- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
- if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400) {
- printk(" ncr53c400 release=%d", NCR53C400_PUBLIC_RELEASE);
- }
+#ifdef NCR53C400
+ "NCR53C400 "
+#endif
+ "");
}
/**
@@ -672,6 +690,7 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
NCR5380_dprint_phase(NDEBUG_ANY, instance);
}
+#ifdef PSEUDO_DMA
/******************************************/
/*
* /proc/scsi/[dtc pas16 t128 generic]/[0-ASC_NUM_BOARD_SUPPORTED]
@@ -689,19 +708,18 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
char *buffer, int length)
{
-#ifdef DTC_PUBLIC_RELEASE
- dtc_wmaxi = dtc_maxi = 0;
-#endif
-#ifdef PAS16_PUBLIC_RELEASE
- pas_wmaxi = pas_maxi = 0;
-#endif
- return (-ENOSYS); /* Currently this is a no-op */
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ hostdata->spin_max_r = 0;
+ hostdata->spin_max_w = 0;
+ return 0;
}
+#endif
#undef SPRINTF
#define SPRINTF(args...) seq_printf(m, ## args)
static
-void lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, struct seq_file *m);
+void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m);
static
void lprint_command(unsigned char *cmd, struct seq_file *m);
static
@@ -711,56 +729,31 @@ static int __maybe_unused NCR5380_show_info(struct seq_file *m,
struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
+ struct scsi_cmnd *ptr;
hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- SPRINTF("NCR5380 core release=%d. ", NCR5380_PUBLIC_RELEASE);
- if (((struct NCR5380_hostdata *) instance->hostdata)->flags & FLAG_NCR53C400)
- SPRINTF("ncr53c400 release=%d. ", NCR53C400_PUBLIC_RELEASE);
-#ifdef DTC_PUBLIC_RELEASE
- SPRINTF("DTC 3180/3280 release %d", DTC_PUBLIC_RELEASE);
-#endif
-#ifdef T128_PUBLIC_RELEASE
- SPRINTF("T128 release %d", T128_PUBLIC_RELEASE);
-#endif
-#ifdef GENERIC_NCR5380_PUBLIC_RELEASE
- SPRINTF("Generic5380 release %d", GENERIC_NCR5380_PUBLIC_RELEASE);
-#endif
-#ifdef PAS16_PUBLIC_RELEASE
- SPRINTF("PAS16 release=%d", PAS16_PUBLIC_RELEASE);
-#endif
-
- SPRINTF("\nBase Addr: 0x%05lX ", (long) instance->base);
- SPRINTF("io_port: %04x ", (int) instance->io_port);
- if (instance->irq == SCSI_IRQ_NONE)
- SPRINTF("IRQ: None.\n");
- else
- SPRINTF("IRQ: %d.\n", instance->irq);
-
-#ifdef DTC_PUBLIC_RELEASE
- SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", dtc_wmaxi, dtc_maxi);
-#endif
-#ifdef PAS16_PUBLIC_RELEASE
- SPRINTF("Highwater I/O busy_spin_counts -- write: %d read: %d\n", pas_wmaxi, pas_maxi);
+#ifdef PSEUDO_DMA
+ SPRINTF("Highwater I/O busy spin counts: write %d, read %d\n",
+ hostdata->spin_max_w, hostdata->spin_max_r);
#endif
spin_lock_irq(instance->host_lock);
if (!hostdata->connected)
SPRINTF("scsi%d: no currently connected command\n", instance->host_no);
else
- lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
+ lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
SPRINTF("scsi%d: issue_queue\n", instance->host_no);
- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ for (ptr = (struct scsi_cmnd *) hostdata->issue_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
lprint_Scsi_Cmnd(ptr, m);
SPRINTF("scsi%d: disconnected_queue\n", instance->host_no);
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
+ for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr; ptr = (struct scsi_cmnd *) ptr->host_scribble)
lprint_Scsi_Cmnd(ptr, m);
spin_unlock_irq(instance->host_lock);
return 0;
}
-static void lprint_Scsi_Cmnd(Scsi_Cmnd * cmd, struct seq_file *m)
+static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
{
SPRINTF("scsi%d : destination target %d, lun %llu\n", cmd->device->host->host_no, cmd->device->id, cmd->device->lun);
SPRINTF(" command = ");
@@ -836,18 +829,6 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
INIT_DELAYED_WORK(&hostdata->coroutine, NCR5380_main);
-#ifdef NCR5380_STATS
- for (i = 0; i < 8; ++i) {
- hostdata->time_read[i] = 0;
- hostdata->time_write[i] = 0;
- hostdata->bytes_read[i] = 0;
- hostdata->bytes_write[i] = 0;
- }
- hostdata->timebase = 0;
- hostdata->pendingw = 0;
- hostdata->pendingr = 0;
-#endif
-
/* The CHECK code seems to break the 53C400. Will check it later maybe */
if (flags & FLAG_NCR53C400)
hostdata->flags = FLAG_HAS_LAST_BYTE_SENT | flags;
@@ -857,11 +838,7 @@ static int NCR5380_init(struct Scsi_Host *instance, int flags)
hostdata->host = instance;
hostdata->time_expires = 0;
-#ifndef AUTOSENSE
- if ((instance->cmd_per_lun > 1) || instance->can_queue > 1)
- printk(KERN_WARNING "scsi%d : WARNING : support for multiple outstanding commands enabled\n" " without AUTOSENSE option, contingent allegiance conditions may\n"
- " be incorrectly cleared.\n", instance->host_no);
-#endif /* def AUTOSENSE */
+ prepare_info(instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
@@ -935,11 +912,11 @@ static void NCR5380_exit(struct Scsi_Host *instance)
* Locks: host lock taken by caller
*/
-static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd, void (*done) (struct scsi_cmnd *))
{
struct Scsi_Host *instance = cmd->device->host;
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- Scsi_Cmnd *tmp;
+ struct scsi_cmnd *tmp;
#if (NDEBUG & NDEBUG_NO_WRITE)
switch (cmd->cmnd[0]) {
@@ -952,25 +929,6 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)
}
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-#ifdef NCR5380_STATS
- switch (cmd->cmnd[0]) {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
- hostdata->pendingw++;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
- hostdata->pendingr++;
- break;
- }
-#endif
-
/*
* We use the host_scribble field as a pointer to the next command
* in a queue
@@ -992,7 +950,7 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *)
cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
hostdata->issue_queue = cmd;
} else {
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (Scsi_Cmnd *) tmp->host_scribble);
+ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp->host_scribble; tmp = (struct scsi_cmnd *) tmp->host_scribble);
LIST(cmd, tmp);
tmp->host_scribble = (unsigned char *) cmd;
}
@@ -1023,7 +981,7 @@ static void NCR5380_main(struct work_struct *work)
struct NCR5380_hostdata *hostdata =
container_of(work, struct NCR5380_hostdata, coroutine.work);
struct Scsi_Host *instance = hostdata->host;
- Scsi_Cmnd *tmp, *prev;
+ struct scsi_cmnd *tmp, *prev;
int done;
spin_lock_irq(instance->host_lock);
@@ -1036,7 +994,7 @@ static void NCR5380_main(struct work_struct *work)
* Search through the issue_queue for a command destined
* for a target that's not busy.
*/
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
{
if (prev != tmp)
dprintk(NDEBUG_LISTS, "MAIN tmp=%p target=%d busy=%d lun=%llu\n", tmp, tmp->device->id, hostdata->busy[tmp->device->id], tmp->device->lun);
@@ -1048,7 +1006,7 @@ static void NCR5380_main(struct work_struct *work)
prev->host_scribble = tmp->host_scribble;
} else {
REMOVE(-1, hostdata->issue_queue, tmp, tmp->host_scribble);
- hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
+ hostdata->issue_queue = (struct scsi_cmnd *) tmp->host_scribble;
}
tmp->host_scribble = NULL;
@@ -1073,14 +1031,14 @@ static void NCR5380_main(struct work_struct *work)
hostdata->selecting = NULL;
/* RvC: have to preset this to indicate a new command is being performed */
- if (!NCR5380_select(instance, tmp,
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent allegiance condition exists for the
+ * entire unit.
+ */
+
+ if (!NCR5380_select(instance, tmp)) {
break;
} else {
LIST(tmp, hostdata->issue_queue);
@@ -1095,9 +1053,9 @@ static void NCR5380_main(struct work_struct *work)
/* exited locked */
} /* if (!hostdata->connected) */
if (hostdata->selecting) {
- tmp = (Scsi_Cmnd *) hostdata->selecting;
+ tmp = (struct scsi_cmnd *) hostdata->selecting;
/* Selection will drop and retake the lock */
- if (!NCR5380_select(instance, tmp, (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE : TAG_NEXT)) {
+ if (!NCR5380_select(instance, tmp)) {
/* Ok ?? */
} else {
/* RvC: device failed, so we wait a long time
@@ -1216,47 +1174,16 @@ static irqreturn_t NCR5380_intr(int dummy, void *dev_id)
#endif
-/**
- * collect_stats - collect stats on a scsi command
- * @hostdata: adapter
- * @cmd: command being issued
- *
- * Update the statistical data by parsing the command in question
- */
-
-static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd)
-{
-#ifdef NCR5380_STATS
- switch (cmd->cmnd[0]) {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[scmd_id(cmd)] += (jiffies - hostdata->timebase);
- hostdata->pendingw--;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[scmd_id(cmd)] += (jiffies - hostdata->timebase);
- hostdata->pendingr--;
- break;
- }
-#endif
-}
-
-
/*
- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
- * int tag);
+ * Function : int NCR5380_select(struct Scsi_Host *instance,
+ * struct scsi_cmnd *cmd)
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
* including ARBITRATION, SELECTION, and initial message out for
* IDENTIFY and queue messages.
*
* Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
- * the command that is presently connected.
+ * target lives, cmd - SCSI command to execute.
*
* Returns : -1 if selection could not execute for some reason,
* 0 if selection succeeded or failed because the target
@@ -1278,7 +1205,7 @@ static void collect_stats(struct NCR5380_hostdata *hostdata, Scsi_Cmnd * cmd)
* Locks: caller holds hostdata lock in IRQ mode
*/
-static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag)
+static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
{
NCR5380_local_declare();
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
@@ -1476,7 +1403,6 @@ part2:
return -1;
}
cmd->result = DID_BAD_TARGET << 16;
- collect_stats(hostdata, cmd);
cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
dprintk(NDEBUG_SELECTION, "scsi%d : target did not respond within 250ms\n", instance->host_no);
@@ -1513,7 +1439,7 @@ part2:
}
dprintk(NDEBUG_SELECTION, "scsi%d : target %d selected, going into MESSAGE OUT phase.\n", instance->host_no, cmd->device->id);
- tmp[0] = IDENTIFY(((instance->irq == SCSI_IRQ_NONE) ? 0 : 1), cmd->device->lun);
+ tmp[0] = IDENTIFY(((instance->irq == NO_IRQ) ? 0 : 1), cmd->device->lun);
len = 1;
cmd->tag = 0;
@@ -2086,7 +2012,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+ struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
/* RvC: we need to set the end of the polling time */
unsigned long poll_time = jiffies + USLEEP_POLL;
@@ -2228,7 +2154,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
cmd->next_link->tag = cmd->tag;
cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
dprintk(NDEBUG_LINKED, "scsi%d : target %d lun %llu linked request done, calling scsi_done().\n", instance->host_no, cmd->device->id, cmd->device->lun);
- collect_stats(hostdata, cmd);
cmd->scsi_done(cmd);
cmd = hostdata->connected;
break;
@@ -2263,7 +2188,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
else if (status_byte(cmd->SCp.Status) != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-#ifdef AUTOSENSE
if ((cmd->cmnd[0] == REQUEST_SENSE) &&
hostdata->ses.cmd_len) {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
@@ -2278,12 +2202,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
LIST(cmd, hostdata->issue_queue);
cmd->host_scribble = (unsigned char *)
hostdata->issue_queue;
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ hostdata->issue_queue = (struct scsi_cmnd *) cmd;
dprintk(NDEBUG_QUEUES, "scsi%d : REQUEST SENSE added to head of issue queue\n", instance->host_no);
- } else
-#endif /* def AUTOSENSE */
- {
- collect_stats(hostdata, cmd);
+ } else {
cmd->scsi_done(cmd);
}
@@ -2430,7 +2351,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
hostdata->busy[cmd->device->id] &= ~(1 << (cmd->device->lun & 0xFF));
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
- collect_stats(hostdata, cmd);
cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
return;
@@ -2479,7 +2399,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance) {
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : does reselection, initializing the instance->connected
- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
* nexus has been reestablished,
*
* Inputs : instance - this instance of the NCR5380.
@@ -2496,7 +2416,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
int len;
unsigned char msg[3];
unsigned char *data;
- Scsi_Cmnd *tmp = NULL, *prev;
+ struct scsi_cmnd *tmp = NULL, *prev;
int abort = 0;
NCR5380_setup(instance);
@@ -2562,7 +2482,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
*/
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL; tmp; prev = tmp, tmp = (struct scsi_cmnd *) tmp->host_scribble)
if ((target_mask == (1 << tmp->device->id)) && (lun == (u8)tmp->device->lun)
) {
if (prev) {
@@ -2570,7 +2490,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
prev->host_scribble = tmp->host_scribble;
} else {
REMOVE(-1, hostdata->disconnected_queue, tmp, tmp->host_scribble);
- hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble;
+ hostdata->disconnected_queue = (struct scsi_cmnd *) tmp->host_scribble;
}
tmp->host_scribble = NULL;
break;
@@ -2601,7 +2521,7 @@ static void NCR5380_reselect(struct Scsi_Host *instance) {
*
* Inputs : instance - this instance of the NCR5380.
*
- * Returns : pointer to the Scsi_Cmnd structure for which the I_T_L
+ * Returns : pointer to the scsi_cmnd structure for which the I_T_L
* nexus has been reestablished, on failure NULL is returned.
*/
@@ -2643,32 +2563,32 @@ static void NCR5380_dma_complete(NCR5380_instance * instance) {
#endif /* def REAL_DMA */
/*
- * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
*
* Purpose : abort a command
*
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
+ * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
* used.
*
- * Returns : 0 - success, -1 on failure.
+ * Returns : SUCCESS - success, FAILED on failure.
*
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
+ * XXX - there is no way to abort the command that is currently
+ * connected, you have to wait for it to complete. If this is
* a problem, we could implement longjmp() / setjmp(), setjmp()
* called where the loop started in NCR5380_main().
*
* Locks: host lock taken by caller
*/
-static int NCR5380_abort(Scsi_Cmnd * cmd) {
+static int NCR5380_abort(struct scsi_cmnd *cmd)
+{
NCR5380_local_declare();
struct Scsi_Host *instance = cmd->device->host;
struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) instance->hostdata;
- Scsi_Cmnd *tmp, **prev;
-
- printk(KERN_WARNING "scsi%d : aborting command\n", instance->host_no);
- scsi_print_command(cmd);
+ struct scsi_cmnd *tmp, **prev;
+
+ scmd_printk(KERN_WARNING, cmd, "aborting command\n");
NCR5380_print_status(instance);
@@ -2704,7 +2624,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
* aborted flag and get back into our main loop.
*/
- return 0;
+ return SUCCESS;
}
#endif
@@ -2714,10 +2634,10 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
*/
dprintk(NDEBUG_ABORT, "scsi%d : abort going into loop.\n", instance->host_no);
- for (prev = (Scsi_Cmnd **) & (hostdata->issue_queue), tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue), tmp = (struct scsi_cmnd *) hostdata->issue_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
if (cmd == tmp) {
REMOVE(5, *prev, tmp, tmp->host_scribble);
- (*prev) = (Scsi_Cmnd *) tmp->host_scribble;
+ (*prev) = (struct scsi_cmnd *) tmp->host_scribble;
tmp->host_scribble = NULL;
tmp->result = DID_ABORT << 16;
dprintk(NDEBUG_ABORT, "scsi%d : abort removed command from issue queue.\n", instance->host_no);
@@ -2770,20 +2690,20 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
* it from the disconnected queue.
*/
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; tmp = (struct scsi_cmnd *) tmp->host_scribble)
if (cmd == tmp) {
dprintk(NDEBUG_ABORT, "scsi%d : aborting disconnected command.\n", instance->host_no);
- if (NCR5380_select(instance, cmd, (int) cmd->tag))
+ if (NCR5380_select(instance, cmd))
return FAILED;
dprintk(NDEBUG_ABORT, "scsi%d : nexus reestablished.\n", instance->host_no);
do_abort(instance);
- for (prev = (Scsi_Cmnd **) & (hostdata->disconnected_queue), tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp; prev = (Scsi_Cmnd **) & (tmp->host_scribble), tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue), tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp; prev = (struct scsi_cmnd **) &(tmp->host_scribble), tmp = (struct scsi_cmnd *) tmp->host_scribble)
if (cmd == tmp) {
REMOVE(5, *prev, tmp, tmp->host_scribble);
- *prev = (Scsi_Cmnd *) tmp->host_scribble;
+ *prev = (struct scsi_cmnd *) tmp->host_scribble;
tmp->host_scribble = NULL;
tmp->result = DID_ABORT << 16;
tmp->scsi_done(tmp);
@@ -2806,7 +2726,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
/*
- * Function : int NCR5380_bus_reset (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_bus_reset (struct scsi_cmnd *cmd)
*
* Purpose : reset the SCSI bus.
*
@@ -2815,7 +2735,7 @@ static int NCR5380_abort(Scsi_Cmnd * cmd) {
* Locks: host lock taken by caller
*/
-static int NCR5380_bus_reset(Scsi_Cmnd * cmd)
+static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
{
struct Scsi_Host *instance = cmd->device->host;
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
index c79ddfa..162112d 100644
--- a/drivers/scsi/NCR5380.h
+++ b/drivers/scsi/NCR5380.h
@@ -7,8 +7,6 @@
* drew@colorado.edu
* +1 (303) 666-5836
*
- * DISTRIBUTION RELEASE 7
- *
* For more information, please consult
*
* NCR 5380 Family
@@ -25,13 +23,7 @@
#define NCR5380_H
#include <linux/interrupt.h>
-
-#ifdef AUTOSENSE
#include <scsi/scsi_eh.h>
-#endif
-
-#define NCR5380_PUBLIC_RELEASE 7
-#define NCR53C400_PUBLIC_RELEASE 2
#define NDEBUG_ARBITRATION 0x1
#define NDEBUG_AUTOSENSE 0x2
@@ -224,33 +216,44 @@
#define DISCONNECT_LONG 2
/*
- * These are "special" values for the tag parameter passed to NCR5380_select.
+ * "Special" value for the (unsigned char) command tag, to indicate
+ * I_T_L nexus instead of I_T_L_Q.
*/
-#define TAG_NEXT -1 /* Use next free tag */
-#define TAG_NONE -2 /*
- * Establish I_T_L nexus instead of I_T_L_Q
- * even on SCSI-II devices.
- */
+#define TAG_NONE 0xff
/*
* These are "special" values for the irq and dma_channel fields of the
* Scsi_Host structure
*/
-#define SCSI_IRQ_NONE 255
#define DMA_NONE 255
#define IRQ_AUTO 254
#define DMA_AUTO 254
#define PORT_AUTO 0xffff /* autoprobe io port for 53c400a */
+#ifndef NO_IRQ
+#define NO_IRQ 0
+#endif
+
#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */
#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */
#define FLAG_NCR53C400 4 /* NCR53c400 */
#define FLAG_NO_PSEUDO_DMA 8 /* Inhibit DMA */
#define FLAG_DTC3181E 16 /* DTC3181E */
+#define FLAG_LATE_DMA_SETUP 32 /* Setup NCR before DMA H/W */
+#define FLAG_TAGGED_QUEUING 64 /* as X3T9.2 spelled it */
#ifndef ASM
+
+#ifdef SUPPORT_TAGS
+struct tag_alloc {
+ DECLARE_BITMAP(allocated, MAX_TAGS);
+ int nr_allocated;
+ int queue_size;
+};
+#endif
+
struct NCR5380_hostdata {
NCR5380_implementation_fields; /* implementation specific */
struct Scsi_Host *host; /* Host backpointer */
@@ -263,9 +266,9 @@ struct NCR5380_hostdata {
volatile int dma_len; /* requested length of DMA */
#endif
volatile unsigned char last_message; /* last message OUT */
- volatile Scsi_Cmnd *connected; /* currently connected command */
- volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */
- volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */
+ volatile struct scsi_cmnd *connected; /* currently connected command */
+ volatile struct scsi_cmnd *issue_queue; /* waiting to be issued */
+ volatile struct scsi_cmnd *disconnected_queue; /* waiting for reconnect */
volatile int restart_select; /* we have disconnected,
used to restart
NCR5380_select() */
@@ -273,19 +276,21 @@ struct NCR5380_hostdata {
int flags;
unsigned long time_expires; /* in jiffies, set prior to sleeping */
int select_time; /* timer in select for target response */
- volatile Scsi_Cmnd *selecting;
+ volatile struct scsi_cmnd *selecting;
struct delayed_work coroutine; /* our co-routine */
-#ifdef NCR5380_STATS
- unsigned timebase; /* Base for time calcs */
- long time_read[8]; /* time to do reads */
- long time_write[8]; /* time to do writes */
- unsigned long bytes_read[8]; /* bytes read */
- unsigned long bytes_write[8]; /* bytes written */
- unsigned pendingr;
- unsigned pendingw;
-#endif
-#ifdef AUTOSENSE
struct scsi_eh_save ses;
+ char info[256];
+ int read_overruns; /* number of bytes to cut from a
+ * transfer to handle chip overruns */
+ int retain_dma_intr;
+ struct work_struct main_task;
+ volatile int main_running;
+#ifdef SUPPORT_TAGS
+ struct tag_alloc TagAlloc[8][8]; /* 8 targets and 8 LUNs */
+#endif
+#ifdef PSEUDO_DMA
+ unsigned spin_max_r;
+ unsigned spin_max_w;
#endif
};
@@ -296,7 +301,8 @@ struct NCR5380_hostdata {
#endif
#define dprintk(flg, fmt, ...) \
- do { if ((NDEBUG) & (flg)) pr_debug(fmt, ## __VA_ARGS__); } while (0)
+ do { if ((NDEBUG) & (flg)) \
+ printk(KERN_DEBUG fmt, ## __VA_ARGS__); } while (0)
#if NDEBUG
#define NCR5380_dprint(flg, arg) \
@@ -320,17 +326,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance);
static irqreturn_t NCR5380_intr(int irq, void *dev_id);
#endif
static void NCR5380_main(struct work_struct *work);
-static void __maybe_unused NCR5380_print_options(struct Scsi_Host *instance);
-static int NCR5380_abort(Scsi_Cmnd * cmd);
-static int NCR5380_bus_reset(Scsi_Cmnd * cmd);
-static int NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int __maybe_unused NCR5380_show_info(struct seq_file *,
- struct Scsi_Host *);
-static int __maybe_unused NCR5380_write_info(struct Scsi_Host *instance,
- char *buffer, int length);
-
+static const char *NCR5380_info(struct Scsi_Host *instance);
static void NCR5380_reselect(struct Scsi_Host *instance);
-static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd * cmd, int tag);
+static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd);
#if defined(PSEUDO_DMA) || defined(REAL_DMA) || defined(REAL_DMA_POLL)
static int NCR5380_transfer_dma(struct Scsi_Host *instance, unsigned char *phase, int *count, unsigned char **data);
#endif
diff --git a/drivers/scsi/aacraid/aachba.c b/drivers/scsi/aacraid/aachba.c
index 681434e..b32e77d 100644
--- a/drivers/scsi/aacraid/aachba.c
+++ b/drivers/scsi/aacraid/aachba.c
@@ -2181,7 +2181,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
(fsa_dev_ptr[cid].sense_data.sense_key ==
NOT_READY)) {
switch (scsicmd->cmnd[0]) {
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
if (!(dev->raw_io_interface) ||
!(dev->raw_io_64) ||
((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
@@ -2309,7 +2309,7 @@ int aac_scsi_cmd(struct scsi_cmnd * scsicmd)
scsi_sg_copy_from_buffer(scsicmd, &inq_data, sizeof(inq_data));
return aac_get_container_name(scsicmd);
}
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
if (!(dev->raw_io_interface) ||
!(dev->raw_io_64) ||
((scsicmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
diff --git a/drivers/scsi/aacraid/linit.c b/drivers/scsi/aacraid/linit.c
index a759cb2..fdcdf9f 100644
--- a/drivers/scsi/aacraid/linit.c
+++ b/drivers/scsi/aacraid/linit.c
@@ -462,9 +462,9 @@ static int aac_slave_configure(struct scsi_device *sdev)
depth = 256;
else if (depth < 2)
depth = 2;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
+ scsi_change_queue_depth(sdev, depth);
} else
- scsi_adjust_queue_depth(sdev, 0, 1);
+ scsi_change_queue_depth(sdev, 1);
return 0;
}
@@ -478,12 +478,8 @@ static int aac_slave_configure(struct scsi_device *sdev)
* total capacity and the queue depth supported by the target device.
*/
-static int aac_change_queue_depth(struct scsi_device *sdev, int depth,
- int reason)
+static int aac_change_queue_depth(struct scsi_device *sdev, int depth)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (sdev->tagged_supported && (sdev->type == TYPE_DISK) &&
(sdev_channel(sdev) == CONTAINER_CHANNEL)) {
struct scsi_device * dev;
@@ -504,10 +500,10 @@ static int aac_change_queue_depth(struct scsi_device *sdev, int depth,
depth = 256;
else if (depth < 2)
depth = 2;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
- } else
- scsi_adjust_queue_depth(sdev, 0, 1);
- return sdev->queue_depth;
+ return scsi_change_queue_depth(sdev, depth);
+ }
+
+ return scsi_change_queue_depth(sdev, 1);
}
static ssize_t aac_show_raid_level(struct device *dev, struct device_attribute *attr, char *buf)
@@ -555,7 +551,7 @@ static int aac_eh_abort(struct scsi_cmnd* cmd)
AAC_DRIVERNAME,
host->host_no, sdev_channel(dev), sdev_id(dev), dev->lun);
switch (cmd->cmnd[0]) {
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
if (!(aac->raw_io_interface) ||
!(aac->raw_io_64) ||
((cmd->cmnd[1] & 0x1f) != SAI_READ_CAPACITY_16))
diff --git a/drivers/scsi/advansys.c b/drivers/scsi/advansys.c
index 43761c1..6719a33 100644
--- a/drivers/scsi/advansys.c
+++ b/drivers/scsi/advansys.c
@@ -7706,7 +7706,7 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
asc_dvc->cfg->can_tagged_qng |= tid_bit;
asc_dvc->use_tagged_qng |= tid_bit;
}
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
+ scsi_change_queue_depth(sdev,
asc_dvc->max_dvc_qng[sdev->id]);
}
} else {
@@ -7714,7 +7714,6 @@ advansys_narrow_slave_configure(struct scsi_device *sdev, ASC_DVC_VAR *asc_dvc)
asc_dvc->cfg->can_tagged_qng &= ~tid_bit;
asc_dvc->use_tagged_qng &= ~tid_bit;
}
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
}
if ((sdev->lun == 0) &&
@@ -7848,12 +7847,8 @@ advansys_wide_slave_configure(struct scsi_device *sdev, ADV_DVC_VAR *adv_dvc)
}
}
- if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported) {
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG,
- adv_dvc->max_dvc_qng);
- } else {
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
- }
+ if ((adv_dvc->tagqng_able & tidmask) && sdev->tagged_supported)
+ scsi_change_queue_depth(sdev, adv_dvc->max_dvc_qng);
}
/*
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
index e77b72f..2b960b3 100644
--- a/drivers/scsi/aha152x.c
+++ b/drivers/scsi/aha152x.c
@@ -230,7 +230,7 @@
*
*
**************************************************************************
-
+
see Documentation/scsi/aha152x.txt for configuration details
**************************************************************************/
@@ -279,45 +279,11 @@ static LIST_HEAD(aha152x_host_list);
#error define AUTOCONF or SETUP0
#endif
-#if defined(AHA152X_DEBUG)
-#define DEBUG_DEFAULT debug_eh
-
-#define DPRINTK(when,msgs...) \
- do { if(HOSTDATA(shpnt)->debug & (when)) printk(msgs); } while(0)
-
-#define DO_LOCK(flags) \
- do { \
- if(spin_is_locked(&QLOCK)) { \
- DPRINTK(debug_intr, DEBUG_LEAD "(%s:%d) already locked at %s:%d\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
- } \
- DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locking\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
- spin_lock_irqsave(&QLOCK,flags); \
- DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) locked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
- QLOCKER=__func__; \
- QLOCKERL=__LINE__; \
- } while(0)
-
-#define DO_UNLOCK(flags) \
- do { \
- DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocking (locked at %s:%d)\n", CMDINFO(CURRENT_SC), __func__, __LINE__, QLOCKER, QLOCKERL); \
- spin_unlock_irqrestore(&QLOCK,flags); \
- DPRINTK(debug_locking, DEBUG_LEAD "(%s:%d) unlocked\n", CMDINFO(CURRENT_SC), __func__, __LINE__); \
- QLOCKER="(not locked)"; \
- QLOCKERL=0; \
- } while(0)
-
-#else
-#define DPRINTK(when,msgs...)
#define DO_LOCK(flags) spin_lock_irqsave(&QLOCK,flags)
#define DO_UNLOCK(flags) spin_unlock_irqrestore(&QLOCK,flags)
-#endif
#define LEAD "(scsi%d:%d:%d) "
-#define WARN_LEAD KERN_WARNING LEAD
#define INFO_LEAD KERN_INFO LEAD
-#define NOTE_LEAD KERN_NOTICE LEAD
-#define ERR_LEAD KERN_ERR LEAD
-#define DEBUG_LEAD KERN_DEBUG LEAD
#define CMDINFO(cmd) \
(cmd) ? ((cmd)->device->host->host_no) : -1, \
(cmd) ? ((cmd)->device->id & 0x0f) : -1, \
@@ -345,10 +311,10 @@ CMD_INC_RESID(struct scsi_cmnd *cmd, int inc)
enum {
not_issued = 0x0001, /* command not yet issued */
- selecting = 0x0002, /* target is beeing selected */
+ selecting = 0x0002, /* target is being selected */
identified = 0x0004, /* IDENTIFY was sent */
disconnected = 0x0008, /* target disconnected */
- completed = 0x0010, /* target sent COMMAND COMPLETE */
+ completed = 0x0010, /* target sent COMMAND COMPLETE */
aborted = 0x0020, /* ABORT was sent */
resetted = 0x0040, /* BUS DEVICE RESET was sent */
spiordy = 0x0080, /* waiting for SPIORDY to raise */
@@ -396,7 +362,6 @@ static int exttrans[] = {0, 0};
module_param_array(exttrans, int, NULL, 0);
MODULE_PARM_DESC(exttrans,"use extended translation");
-#if !defined(AHA152X_DEBUG)
static int aha152x[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
module_param_array(aha152x, int, NULL, 0);
MODULE_PARM_DESC(aha152x, "parameters for first controller");
@@ -404,19 +369,6 @@ MODULE_PARM_DESC(aha152x, "parameters for first controller");
static int aha152x1[] = {0, 11, 7, 1, 1, 0, DELAY_DEFAULT, 0};
module_param_array(aha152x1, int, NULL, 0);
MODULE_PARM_DESC(aha152x1, "parameters for second controller");
-#else
-static int debug[] = {DEBUG_DEFAULT, DEBUG_DEFAULT};
-module_param_array(debug, int, NULL, 0);
-MODULE_PARM_DESC(debug, "flags for driver debugging");
-
-static int aha152x[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-module_param_array(aha152x, int, NULL, 0);
-MODULE_PARM_DESC(aha152x, "parameters for first controller");
-
-static int aha152x1[] = {0, 11, 7, 1, 1, 1, DELAY_DEFAULT, 0, DEBUG_DEFAULT};
-module_param_array(aha152x1, int, NULL, 0);
-MODULE_PARM_DESC(aha152x1, "parameters for second controller");
-#endif /* !defined(AHA152X_DEBUG) */
#endif /* MODULE */
#ifdef __ISAPNP__
@@ -446,7 +398,7 @@ static struct scsi_host_template aha152x_driver_template;
/*
* internal states of the host
*
- */
+ */
enum aha152x_state {
idle=0,
unknown,
@@ -485,24 +437,16 @@ struct aha152x_hostdata {
spinlock_t lock;
/* host lock */
-#if defined(AHA152X_DEBUG)
- const char *locker;
- /* which function has the lock */
- int lockerl; /* where did it get it */
-
- int debug; /* current debugging setting */
-#endif
-
#if defined(AHA152X_STAT)
- int total_commands;
+ int total_commands;
int disconnections;
int busfree_without_any_action;
int busfree_without_old_command;
int busfree_without_new_command;
int busfree_without_done_command;
int busfree_with_check_condition;
- int count[maxstate];
- int count_trans[maxstate];
+ int count[maxstate];
+ int count_trans[maxstate];
unsigned long time[maxstate];
#endif
@@ -514,7 +458,7 @@ struct aha152x_hostdata {
int delay; /* reset out delay */
int ext_trans; /* extended translation enabled */
- int swint; /* software-interrupt was fired during detect() */
+ int swint; /* software-interrupt was fired during detect() */
int service; /* bh needs to be run */
int in_intr; /* bh is running */
@@ -543,7 +487,7 @@ struct aha152x_hostdata {
unsigned char msgi[256];
/* received message bytes */
- int msgo_i, msgo_len;
+ int msgo_i, msgo_len;
/* number of sent bytes and length of current messages */
unsigned char msgo[256];
/* pending messages */
@@ -689,7 +633,6 @@ static void aha152x_error(struct Scsi_Host *shpnt, char *msg);
static void done(struct Scsi_Host *shpnt, int error);
/* diagnostics */
-static void disp_ports(struct Scsi_Host *shpnt);
static void show_command(Scsi_Cmnd * ptr);
static void show_queues(struct Scsi_Host *shpnt);
static void disp_enintr(struct Scsi_Host *shpnt);
@@ -812,10 +755,6 @@ struct Scsi_Host *aha152x_probe_one(struct aha152x_setup *setup)
DELAY = setup->delay;
EXT_TRANS = setup->ext_trans;
-#if defined(AHA152X_DEBUG)
- HOSTDATA(shpnt)->debug = setup->debug;
-#endif
-
SETPORT(SCSIID, setup->scsiid << 4);
shpnt->this_id = setup->scsiid;
@@ -941,31 +880,24 @@ void aha152x_release(struct Scsi_Host *shpnt)
* setup controller to generate interrupts depending
* on current state (lock has to be acquired)
*
- */
+ */
static int setup_expected_interrupts(struct Scsi_Host *shpnt)
{
if(CURRENT_SC) {
CURRENT_SC->SCp.phase |= 1 << 16;
-
+
if(CURRENT_SC->SCp.phase & selecting) {
- DPRINTK(debug_intr, DEBUG_LEAD "expecting: (seldo) (seltimo) (seldi)\n", CMDINFO(CURRENT_SC));
SETPORT(SSTAT1, SELTO);
SETPORT(SIMODE0, ENSELDO | (DISCONNECTED_SC ? ENSELDI : 0));
SETPORT(SIMODE1, ENSELTIMO);
} else {
- DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (busfree) %s\n", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.phase & spiordy ? "(spiordy)" : "");
SETPORT(SIMODE0, (CURRENT_SC->SCp.phase & spiordy) ? ENSPIORDY : 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
+ SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
}
} else if(STATE==seldi) {
- DPRINTK(debug_intr, DEBUG_LEAD "expecting: (phase change) (identify)\n", CMDINFO(CURRENT_SC));
SETPORT(SIMODE0, 0);
- SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
+ SETPORT(SIMODE1, ENPHASEMIS | ENSCSIRST | ENSCSIPERR | ENBUSFREE);
} else {
- DPRINTK(debug_intr, DEBUG_LEAD "expecting: %s %s\n",
- CMDINFO(CURRENT_SC),
- DISCONNECTED_SC ? "(reselection)" : "",
- ISSUE_SC ? "(busfree)" : "");
SETPORT(SIMODE0, DISCONNECTED_SC ? ENSELDI : 0);
SETPORT(SIMODE1, ENSCSIRST | ( (ISSUE_SC||DONE_SC) ? ENBUSFREE : 0));
}
@@ -977,7 +909,7 @@ static int setup_expected_interrupts(struct Scsi_Host *shpnt)
}
-/*
+/*
* Queue a command and setup interrupts for a free bus.
*/
static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
@@ -986,15 +918,6 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
struct Scsi_Host *shpnt = SCpnt->device->host;
unsigned long flags;
-#if defined(AHA152X_DEBUG)
- if (HOSTDATA(shpnt)->debug & debug_queue) {
- printk(INFO_LEAD "queue: %p; cmd_len=%d pieces=%d size=%u cmnd=",
- CMDINFO(SCpnt), SCpnt, SCpnt->cmd_len,
- scsi_sg_count(SCpnt), scsi_bufflen(SCpnt));
- __scsi_print_command(SCpnt->cmnd);
- }
-#endif
-
SCpnt->scsi_done = done;
SCpnt->SCp.phase = not_issued | phase;
SCpnt->SCp.Status = 0x1; /* Ilegal status by SCSI standard */
@@ -1004,13 +927,13 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
if(SCpnt->SCp.phase & (resetting|check_condition)) {
if (!SCpnt->host_scribble || SCSEM(SCpnt) || SCNEXT(SCpnt)) {
- printk(ERR_LEAD "cannot reuse command\n", CMDINFO(SCpnt));
+ scmd_printk(KERN_ERR, SCpnt, "cannot reuse command\n");
return FAILED;
}
} else {
SCpnt->host_scribble = kmalloc(sizeof(struct aha152x_scdata), GFP_ATOMIC);
if(!SCpnt->host_scribble) {
- printk(ERR_LEAD "allocation failed\n", CMDINFO(SCpnt));
+ scmd_printk(KERN_ERR, SCpnt, "allocation failed\n");
return FAILED;
}
}
@@ -1066,15 +989,6 @@ static int aha152x_internal_queue(Scsi_Cmnd *SCpnt, struct completion *complete,
*/
static int aha152x_queue_lck(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
{
-#if 0
- if(*SCpnt->cmnd == REQUEST_SENSE) {
- SCpnt->result = 0;
- done(SCpnt);
-
- return 0;
- }
-#endif
-
return aha152x_internal_queue(SCpnt, NULL, 0, done);
}
@@ -1082,15 +996,10 @@ static DEF_SCSI_QCMD(aha152x_queue)
/*
- *
*
*/
static void reset_done(Scsi_Cmnd *SCpnt)
{
-#if 0
- struct Scsi_Host *shpnt = SCpnt->host;
- DPRINTK(debug_eh, INFO_LEAD "reset_done called\n", CMDINFO(SCpnt));
-#endif
if(SCSEM(SCpnt)) {
complete(SCSEM(SCpnt));
} else {
@@ -1108,20 +1017,11 @@ static int aha152x_abort(Scsi_Cmnd *SCpnt)
Scsi_Cmnd *ptr;
unsigned long flags;
-#if defined(AHA152X_DEBUG)
- if(HOSTDATA(shpnt)->debug & debug_eh) {
- printk(DEBUG_LEAD "abort(%p)", CMDINFO(SCpnt), SCpnt);
- show_queues(shpnt);
- }
-#endif
-
DO_LOCK(flags);
ptr=remove_SC(&ISSUE_SC, SCpnt);
if(ptr) {
- DPRINTK(debug_eh, DEBUG_LEAD "not yet issued - SUCCESS\n", CMDINFO(SCpnt));
-
HOSTDATA(shpnt)->commands--;
if (!HOSTDATA(shpnt)->commands)
SETPORT(PORTA, 0);
@@ -1131,7 +1031,7 @@ static int aha152x_abort(Scsi_Cmnd *SCpnt)
SCpnt->host_scribble=NULL;
return SUCCESS;
- }
+ }
DO_UNLOCK(flags);
@@ -1142,7 +1042,8 @@ static int aha152x_abort(Scsi_Cmnd *SCpnt)
*
*/
- printk(ERR_LEAD "cannot abort running or disconnected command\n", CMDINFO(SCpnt));
+ scmd_printk(KERN_ERR, SCpnt,
+ "cannot abort running or disconnected command\n");
return FAILED;
}
@@ -1160,15 +1061,8 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
unsigned long flags;
unsigned long timeleft;
-#if defined(AHA152X_DEBUG)
- if(HOSTDATA(shpnt)->debug & debug_eh) {
- printk(INFO_LEAD "aha152x_device_reset(%p)", CMDINFO(SCpnt), SCpnt);
- show_queues(shpnt);
- }
-#endif
-
if(CURRENT_SC==SCpnt) {
- printk(ERR_LEAD "cannot reset current device\n", CMDINFO(SCpnt));
+ scmd_printk(KERN_ERR, SCpnt, "cannot reset current device\n");
return FAILED;
}
@@ -1208,7 +1102,7 @@ static int aha152x_device_reset(Scsi_Cmnd * SCpnt)
} else if(disconnected) {
append_SC(&DISCONNECTED_SC, SCpnt);
}
-
+
ret = FAILED;
}
@@ -1227,12 +1121,12 @@ static void free_hard_reset_SCs(struct Scsi_Host *shpnt, Scsi_Cmnd **SCs)
if(SCDATA(ptr)) {
next = SCNEXT(ptr);
} else {
- printk(DEBUG_LEAD "queue corrupted at %p\n", CMDINFO(ptr), ptr);
+ scmd_printk(KERN_DEBUG, ptr,
+ "queue corrupted at %p\n", ptr);
next = NULL;
}
if (!ptr->device->soft_reset) {
- DPRINTK(debug_eh, DEBUG_LEAD "disconnected command %p removed\n", CMDINFO(ptr), ptr);
remove_SC(SCs, ptr);
HOSTDATA(shpnt)->commands--;
kfree(ptr->host_scribble);
@@ -1253,25 +1147,14 @@ static int aha152x_bus_reset_host(struct Scsi_Host *shpnt)
DO_LOCK(flags);
-#if defined(AHA152X_DEBUG)
- if(HOSTDATA(shpnt)->debug & debug_eh) {
- printk(KERN_DEBUG "scsi%d: bus reset", shpnt->host_no);
- show_queues(shpnt);
- }
-#endif
-
free_hard_reset_SCs(shpnt, &ISSUE_SC);
free_hard_reset_SCs(shpnt, &DISCONNECTED_SC);
- DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting bus\n", shpnt->host_no);
-
SETPORT(SCSISEQ, SCSIRSTO);
mdelay(256);
SETPORT(SCSISEQ, 0);
mdelay(DELAY);
- DPRINTK(debug_eh, KERN_DEBUG "scsi%d: bus resetted\n", shpnt->host_no);
-
setup_expected_interrupts(shpnt);
if(HOSTDATA(shpnt)->commands==0)
SETPORT(PORTA, 0);
@@ -1333,11 +1216,7 @@ static void reset_ports(struct Scsi_Host *shpnt)
*/
int aha152x_host_reset_host(struct Scsi_Host *shpnt)
{
- DPRINTK(debug_eh, KERN_DEBUG "scsi%d: host reset\n", shpnt->host_no);
-
aha152x_bus_reset_host(shpnt);
-
- DPRINTK(debug_eh, KERN_DEBUG "scsi%d: resetting ports\n", shpnt->host_no);
reset_ports(shpnt);
return SUCCESS;
@@ -1345,7 +1224,7 @@ int aha152x_host_reset_host(struct Scsi_Host *shpnt)
/*
* Reset the host (bus and controller)
- *
+ *
*/
static int aha152x_host_reset(Scsi_Cmnd *SCpnt)
{
@@ -1411,7 +1290,9 @@ static void done(struct Scsi_Host *shpnt, int error)
{
if (CURRENT_SC) {
if(DONE_SC)
- printk(ERR_LEAD "there's already a completed command %p - will cause abort\n", CMDINFO(CURRENT_SC), DONE_SC);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "there's already a completed command %p "
+ "- will cause abort\n", DONE_SC);
DONE_SC = CURRENT_SC;
CURRENT_SC = NULL;
@@ -1466,7 +1347,7 @@ static irqreturn_t intr(int irqno, void *dev_id)
return IRQ_NONE;
if( TESTLO(DMASTAT, INTSTAT) )
- return IRQ_NONE;
+ return IRQ_NONE;
/* no more interrupts from the controller, while we're busy.
INTEN is restored by the BH handler */
@@ -1501,7 +1382,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
SETPORT(SXFRCTL0, CH1);
SETPORT(SSTAT1, CLRBUSFREE);
-
+
if(CURRENT_SC) {
#if defined(AHA152X_STAT)
action++;
@@ -1513,19 +1394,13 @@ static void busfree_run(struct Scsi_Host *shpnt)
done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16));
} else if(CURRENT_SC->SCp.phase & aborted) {
- DPRINTK(debug_eh, DEBUG_LEAD "ABORT sent\n", CMDINFO(CURRENT_SC));
done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_ABORT << 16));
} else if(CURRENT_SC->SCp.phase & resetted) {
- DPRINTK(debug_eh, DEBUG_LEAD "BUS DEVICE RESET sent\n", CMDINFO(CURRENT_SC));
done(shpnt, (CURRENT_SC->SCp.Status & 0xff) | ((CURRENT_SC->SCp.Message & 0xff) << 8) | (DID_RESET << 16));
} else if(CURRENT_SC->SCp.phase & disconnected) {
/* target sent DISCONNECT */
- DPRINTK(debug_selection, DEBUG_LEAD "target disconnected at %d/%d\n",
- CMDINFO(CURRENT_SC),
- scsi_get_resid(CURRENT_SC),
- scsi_bufflen(CURRENT_SC));
#if defined(AHA152X_STAT)
HOSTDATA(shpnt)->disconnections++;
#endif
@@ -1553,13 +1428,6 @@ static void busfree_run(struct Scsi_Host *shpnt)
struct scsi_cmnd *cmd = HOSTDATA(shpnt)->done_SC;
struct aha152x_scdata *sc = SCDATA(cmd);
-#if 0
- if(HOSTDATA(shpnt)->debug & debug_eh) {
- printk(ERR_LEAD "received sense: ", CMDINFO(DONE_SC));
- scsi_print_sense("bh", DONE_SC);
- }
-#endif
-
scsi_eh_restore_cmnd(cmd, &sc->ses);
cmd->SCp.Status = SAM_STAT_CHECK_CONDITION;
@@ -1571,17 +1439,11 @@ static void busfree_run(struct Scsi_Host *shpnt)
#if defined(AHA152X_STAT)
HOSTDATA(shpnt)->busfree_with_check_condition++;
#endif
-#if 0
- DPRINTK(debug_eh, ERR_LEAD "CHECK CONDITION found\n", CMDINFO(DONE_SC));
-#endif
if(!(DONE_SC->SCp.phase & not_issued)) {
struct aha152x_scdata *sc;
Scsi_Cmnd *ptr = DONE_SC;
DONE_SC=NULL;
-#if 0
- DPRINTK(debug_eh, ERR_LEAD "requesting sense\n", CMDINFO(ptr));
-#endif
sc = SCDATA(ptr);
/* It was allocated in aha152x_internal_queue? */
@@ -1591,19 +1453,10 @@ static void busfree_run(struct Scsi_Host *shpnt)
DO_UNLOCK(flags);
aha152x_internal_queue(ptr, NULL, check_condition, ptr->scsi_done);
DO_LOCK(flags);
-#if 0
- } else {
- DPRINTK(debug_eh, ERR_LEAD "command not issued - CHECK CONDITION ignored\n", CMDINFO(DONE_SC));
-#endif
}
}
if(DONE_SC && DONE_SC->scsi_done) {
-#if defined(AHA152X_DEBUG)
- int hostno=DONE_SC->device->host->host_no;
- int id=DONE_SC->device->id & 0xf;
- int lun=((u8)DONE_SC->device->lun) & 0x7;
-#endif
Scsi_Cmnd *ptr = DONE_SC;
DONE_SC=NULL;
@@ -1618,9 +1471,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
}
DO_UNLOCK(flags);
- DPRINTK(debug_done, DEBUG_LEAD "calling scsi_done(%p)\n", hostno, id, lun, ptr);
- ptr->scsi_done(ptr);
- DPRINTK(debug_done, DEBUG_LEAD "scsi_done(%p) returned\n", hostno, id, lun, ptr);
+ ptr->scsi_done(ptr);
DO_LOCK(flags);
}
@@ -1640,9 +1491,7 @@ static void busfree_run(struct Scsi_Host *shpnt)
#if defined(AHA152X_STAT)
action++;
#endif
- CURRENT_SC->SCp.phase |= selecting;
-
- DPRINTK(debug_selection, DEBUG_LEAD "selecting target\n", CMDINFO(CURRENT_SC));
+ CURRENT_SC->SCp.phase |= selecting;
/* clear selection timeout */
SETPORT(SSTAT1, SELTO);
@@ -1674,18 +1523,19 @@ static void seldo_run(struct Scsi_Host *shpnt)
SETPORT(SSTAT1, CLRBUSFREE);
SETPORT(SSTAT1, CLRPHASECHG);
- CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
+ CURRENT_SC->SCp.phase &= ~(selecting|not_issued);
SETPORT(SCSISEQ, 0);
if (TESTLO(SSTAT0, SELDO)) {
- printk(ERR_LEAD "aha152x: passing bus free condition\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "aha152x: passing bus free condition\n");
done(shpnt, DID_NO_CONNECT << 16);
return;
}
SETPORT(SSTAT0, CLRSELDO);
-
+
ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
if (CURRENT_SC->SCp.phase & aborting) {
@@ -1693,7 +1543,7 @@ static void seldo_run(struct Scsi_Host *shpnt)
} else if (CURRENT_SC->SCp.phase & resetting) {
ADDMSGO(BUS_DEVICE_RESET);
} else if (SYNCNEG==0 && SYNCHRONOUS) {
- CURRENT_SC->SCp.phase |= syncneg;
+ CURRENT_SC->SCp.phase |= syncneg;
MSGOLEN += spi_populate_sync_msg(&MSGO(MSGOLEN), 50, 8);
SYNCNEG=1; /* negotiation in progress */
}
@@ -1708,29 +1558,21 @@ static void seldo_run(struct Scsi_Host *shpnt)
*/
static void selto_run(struct Scsi_Host *shpnt)
{
- SETPORT(SCSISEQ, 0);
+ SETPORT(SCSISEQ, 0);
SETPORT(SSTAT1, CLRSELTIMO);
- DPRINTK(debug_selection, DEBUG_LEAD "selection timeout\n", CMDINFO(CURRENT_SC));
-
- if(!CURRENT_SC) {
- DPRINTK(debug_selection, DEBUG_LEAD "!CURRENT_SC\n", CMDINFO(CURRENT_SC));
+ if (!CURRENT_SC)
return;
- }
- CURRENT_SC->SCp.phase &= ~selecting;
+ CURRENT_SC->SCp.phase &= ~selecting;
- if (CURRENT_SC->SCp.phase & aborted) {
- DPRINTK(debug_selection, DEBUG_LEAD "aborted\n", CMDINFO(CURRENT_SC));
+ if (CURRENT_SC->SCp.phase & aborted)
done(shpnt, DID_ABORT << 16);
- } else if (TESTLO(SSTAT0, SELINGO)) {
- DPRINTK(debug_selection, DEBUG_LEAD "arbitration not won\n", CMDINFO(CURRENT_SC));
+ else if (TESTLO(SSTAT0, SELINGO))
done(shpnt, DID_BUS_BUSY << 16);
- } else {
+ else
/* ARBITRATION won, but SELECTION failed */
- DPRINTK(debug_selection, DEBUG_LEAD "selection failed\n", CMDINFO(CURRENT_SC));
done(shpnt, DID_NO_CONNECT << 16);
- }
}
/*
@@ -1753,9 +1595,8 @@ static void seldi_run(struct Scsi_Host *shpnt)
if(CURRENT_SC) {
if(!(CURRENT_SC->SCp.phase & not_issued))
- printk(ERR_LEAD "command should not have been issued yet\n", CMDINFO(CURRENT_SC));
-
- DPRINTK(debug_selection, ERR_LEAD "command requeued - reselection\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "command should not have been issued yet\n");
DO_LOCK(flags);
append_SC(&ISSUE_SC, CURRENT_SC);
@@ -1764,17 +1605,16 @@ static void seldi_run(struct Scsi_Host *shpnt)
CURRENT_SC = NULL;
}
- if(!DISCONNECTED_SC) {
- DPRINTK(debug_selection, DEBUG_LEAD "unexpected SELDI ", CMDINFO(CURRENT_SC));
+ if (!DISCONNECTED_SC)
return;
- }
RECONN_TARGET=-1;
selid = GETPORT(SELID) & ~(1 << shpnt->this_id);
if (selid==0) {
- printk("aha152x%d: target id unknown (%02x)\n", HOSTNO, selid);
+ shost_printk(KERN_INFO, shpnt,
+ "target id unknown (%02x)\n", selid);
return;
}
@@ -1782,8 +1622,8 @@ static void seldi_run(struct Scsi_Host *shpnt)
;
if(selid & ~(1 << target)) {
- printk("aha152x%d: multiple targets reconnected (%02x)\n",
- HOSTNO, selid);
+ shost_printk(KERN_INFO, shpnt,
+ "multiple targets reconnected (%02x)\n", selid);
}
@@ -1793,7 +1633,6 @@ static void seldi_run(struct Scsi_Host *shpnt)
SETRATE(HOSTDATA(shpnt)->syncrate[target]);
RECONN_TARGET=target;
- DPRINTK(debug_selection, DEBUG_LEAD "target %d reselected (%02x).\n", CMDINFO(CURRENT_SC), target, selid);
}
/*
@@ -1817,31 +1656,24 @@ static void msgi_run(struct Scsi_Host *shpnt)
if(sstat1 & (PHASECHG|PHASEMIS|BUSFREE) || !(sstat1 & REQINIT))
return;
- if(TESTLO(SSTAT0,SPIORDY)) {
- DPRINTK(debug_msgi, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ if (TESTLO(SSTAT0, SPIORDY))
return;
- }
ADDMSGI(GETPORT(SCSIDAT));
-#if defined(AHA152X_DEBUG)
- if (HOSTDATA(shpnt)->debug & debug_msgi) {
- printk(INFO_LEAD "inbound message %02x ", CMDINFO(CURRENT_SC), MSGI(0));
- spi_print_msg(&MSGI(0));
- printk("\n");
- }
-#endif
-
if(!CURRENT_SC) {
if(LASTSTATE!=seldi) {
- printk(KERN_ERR "aha152x%d: message in w/o current command not after reselection\n", HOSTNO);
+ shost_printk(KERN_ERR, shpnt,
+ "message in w/o current command"
+ " not after reselection\n");
}
/*
- * Handle reselection
- */
+ * Handle reselection
+ */
if(!(MSGI(0) & IDENTIFY_BASE)) {
- printk(KERN_ERR "aha152x%d: target didn't identify after reselection\n", HOSTNO);
+ shost_printk(KERN_ERR, shpnt,
+ "target didn't identify after reselection\n");
continue;
}
@@ -1849,12 +1681,13 @@ static void msgi_run(struct Scsi_Host *shpnt)
if (!CURRENT_SC) {
show_queues(shpnt);
- printk(KERN_ERR "aha152x%d: no disconnected command for target %d/%d\n", HOSTNO, RECONN_TARGET, MSGI(0) & 0x3f);
+ shost_printk(KERN_ERR, shpnt,
+ "no disconnected command"
+ " for target %d/%d\n",
+ RECONN_TARGET, MSGI(0) & 0x3f);
continue;
}
- DPRINTK(debug_msgi, DEBUG_LEAD "target reconnected\n", CMDINFO(CURRENT_SC));
-
CURRENT_SC->SCp.Message = MSGI(0);
CURRENT_SC->SCp.phase &= ~disconnected;
@@ -1862,31 +1695,32 @@ static void msgi_run(struct Scsi_Host *shpnt)
/* next message if any */
continue;
- }
+ }
CURRENT_SC->SCp.Message = MSGI(0);
switch (MSGI(0)) {
case DISCONNECT:
if (!RECONNECT)
- printk(WARN_LEAD "target was not allowed to disconnect\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_WARNING, CURRENT_SC,
+ "target was not allowed to disconnect\n");
CURRENT_SC->SCp.phase |= disconnected;
break;
case COMMAND_COMPLETE:
- if(CURRENT_SC->SCp.phase & completed)
- DPRINTK(debug_msgi, DEBUG_LEAD "again COMMAND COMPLETE\n", CMDINFO(CURRENT_SC));
-
CURRENT_SC->SCp.phase |= completed;
break;
case MESSAGE_REJECT:
if (SYNCNEG==1) {
- printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_INFO, CURRENT_SC,
+ "Synchronous Data Transfer Request"
+ " was rejected\n");
SYNCNEG=2; /* negotiation completed */
} else
- printk(INFO_LEAD "inbound message (MESSAGE REJECT)\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_INFO, CURRENT_SC,
+ "inbound message (MESSAGE REJECT)\n");
break;
case SAVE_POINTERS:
@@ -1907,7 +1741,8 @@ static void msgi_run(struct Scsi_Host *shpnt)
long ticks;
if (MSGI(1) != 3) {
- printk(ERR_LEAD "SDTR message length!=3\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "SDTR message length!=3\n");
break;
}
@@ -1924,10 +1759,12 @@ static void msgi_run(struct Scsi_Host *shpnt)
/* negotiation in progress */
if (ticks > 9 || MSGI(4) < 1 || MSGI(4) > 8) {
ADDMSGO(MESSAGE_REJECT);
- printk(INFO_LEAD "received Synchronous Data Transfer Request invalid - rejected\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_INFO,
+ CURRENT_SC,
+ "received Synchronous Data Transfer Request invalid - rejected\n");
break;
}
-
+
SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
} else if (ticks <= 9 && MSGI(4) >= 1) {
ADDMSGO(EXTENDED_MESSAGE);
@@ -1947,11 +1784,14 @@ static void msgi_run(struct Scsi_Host *shpnt)
SYNCRATE |= ((ticks - 2) << 4) + MSGI(4);
} else {
/* requested SDTR is too slow, do it asynchronously */
- printk(INFO_LEAD "Synchronous Data Transfer Request too slow - Rejecting\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_INFO,
+ CURRENT_SC,
+ "Synchronous Data Transfer Request too slow - Rejecting\n");
ADDMSGO(MESSAGE_REJECT);
}
- SYNCNEG=2; /* negotiation completed */
+ /* negotiation completed */
+ SYNCNEG=2;
SETRATE(SYNCRATE);
}
break;
@@ -1985,12 +1825,12 @@ static void msgi_run(struct Scsi_Host *shpnt)
static void msgi_end(struct Scsi_Host *shpnt)
{
if(MSGILEN>0)
- printk(WARN_LEAD "target left before message completed (%d)\n", CMDINFO(CURRENT_SC), MSGILEN);
+ scmd_printk(KERN_WARNING, CURRENT_SC,
+ "target left before message completed (%d)\n",
+ MSGILEN);
- if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE)) {
- DPRINTK(debug_msgi, DEBUG_LEAD "msgo pending\n", CMDINFO(CURRENT_SC));
+ if (MSGOLEN > 0 && !(GETPORT(SSTAT1) & BUSFREE))
SETPORT(SCSISIG, P_MSGI | SIG_ATNO);
- }
}
/*
@@ -2003,21 +1843,12 @@ static void msgo_init(struct Scsi_Host *shpnt)
if((CURRENT_SC->SCp.phase & syncneg) && SYNCNEG==2 && SYNCRATE==0) {
ADDMSGO(IDENTIFY(RECONNECT, CURRENT_SC->device->lun));
} else {
- printk(INFO_LEAD "unexpected MESSAGE OUT phase; rejecting\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_INFO, CURRENT_SC,
+ "unexpected MESSAGE OUT phase; rejecting\n");
ADDMSGO(MESSAGE_REJECT);
}
}
-#if defined(AHA152X_DEBUG)
- if(HOSTDATA(shpnt)->debug & debug_msgo) {
- int i;
-
- printk(DEBUG_LEAD "messages( ", CMDINFO(CURRENT_SC));
- for (i=0; i<MSGOLEN; i+=spi_print_msg(&MSGO(i)), printk(" "))
- ;
- printk(")\n");
- }
-#endif
}
/*
@@ -2026,16 +1857,9 @@ static void msgo_init(struct Scsi_Host *shpnt)
*/
static void msgo_run(struct Scsi_Host *shpnt)
{
- if(MSGO_I==MSGOLEN)
- DPRINTK(debug_msgo, DEBUG_LEAD "messages all sent (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
-
while(MSGO_I<MSGOLEN) {
- DPRINTK(debug_msgo, DEBUG_LEAD "message byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO(MSGO_I), MSGO_I, MSGOLEN);
-
- if(TESTLO(SSTAT0, SPIORDY)) {
- DPRINTK(debug_msgo, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ if (TESTLO(SSTAT0, SPIORDY))
return;
- }
if (MSGO_I==MSGOLEN-1) {
/* Leave MESSAGE OUT after transfer */
@@ -2059,36 +1883,33 @@ static void msgo_run(struct Scsi_Host *shpnt)
static void msgo_end(struct Scsi_Host *shpnt)
{
if(MSGO_I<MSGOLEN) {
- printk(ERR_LEAD "message sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), MSGO_I, MSGOLEN);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "message sent incompletely (%d/%d)\n",
+ MSGO_I, MSGOLEN);
if(SYNCNEG==1) {
- printk(INFO_LEAD "Synchronous Data Transfer Request was rejected\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_INFO, CURRENT_SC,
+ "Synchronous Data Transfer Request was rejected\n");
SYNCNEG=2;
}
}
-
+
MSGO_I = 0;
MSGOLEN = 0;
}
-/*
+/*
* command phase
*
*/
static void cmd_init(struct Scsi_Host *shpnt)
{
if (CURRENT_SC->SCp.sent_command) {
- printk(ERR_LEAD "command already sent\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "command already sent\n");
done(shpnt, DID_ERROR << 16);
return;
}
-#if defined(AHA152X_DEBUG)
- if (HOSTDATA(shpnt)->debug & debug_cmd) {
- printk(DEBUG_LEAD "cmd_init: ", CMDINFO(CURRENT_SC));
- __scsi_print_command(CURRENT_SC->cmnd);
- }
-#endif
-
CMD_I=0;
}
@@ -2098,18 +1919,9 @@ static void cmd_init(struct Scsi_Host *shpnt)
*/
static void cmd_run(struct Scsi_Host *shpnt)
{
- if(CMD_I==CURRENT_SC->cmd_len) {
- DPRINTK(debug_cmd, DEBUG_LEAD "command already completely sent (%d/%d)", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
- disp_ports(shpnt);
- }
-
while(CMD_I<CURRENT_SC->cmd_len) {
- DPRINTK(debug_cmd, DEBUG_LEAD "command byte %02x (%d/%d)\n", CMDINFO(CURRENT_SC), CURRENT_SC->cmnd[CMD_I], CMD_I, CURRENT_SC->cmd_len);
-
- if(TESTLO(SSTAT0, SPIORDY)) {
- DPRINTK(debug_cmd, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ if (TESTLO(SSTAT0, SPIORDY))
return;
- }
SETPORT(SCSIDAT, CURRENT_SC->cmnd[CMD_I++]);
}
@@ -2118,7 +1930,9 @@ static void cmd_run(struct Scsi_Host *shpnt)
static void cmd_end(struct Scsi_Host *shpnt)
{
if(CMD_I<CURRENT_SC->cmd_len)
- printk(ERR_LEAD "command sent incompletely (%d/%d)\n", CMDINFO(CURRENT_SC), CMD_I, CURRENT_SC->cmd_len);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "command sent incompletely (%d/%d)\n",
+ CMD_I, CURRENT_SC->cmd_len);
else
CURRENT_SC->SCp.sent_command++;
}
@@ -2129,20 +1943,11 @@ static void cmd_end(struct Scsi_Host *shpnt)
*/
static void status_run(struct Scsi_Host *shpnt)
{
- if(TESTLO(SSTAT0,SPIORDY)) {
- DPRINTK(debug_status, DEBUG_LEAD "!SPIORDY\n", CMDINFO(CURRENT_SC));
+ if (TESTLO(SSTAT0, SPIORDY))
return;
- }
CURRENT_SC->SCp.Status = GETPORT(SCSIDAT);
-#if defined(AHA152X_DEBUG)
- if (HOSTDATA(shpnt)->debug & debug_status) {
- printk(DEBUG_LEAD "inbound status %02x ", CMDINFO(CURRENT_SC), CURRENT_SC->SCp.Status);
- scsi_print_status(CURRENT_SC->SCp.Status);
- printk("\n");
- }
-#endif
}
/*
@@ -2161,10 +1966,6 @@ static void datai_init(struct Scsi_Host *shpnt)
SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE);
DATA_LEN=0;
- DPRINTK(debug_datai,
- DEBUG_LEAD "datai_init: request_bufflen=%d resid=%d\n",
- CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
- scsi_get_resid(CURRENT_SC));
}
static void datai_run(struct Scsi_Host *shpnt)
@@ -2186,8 +1987,7 @@ static void datai_run(struct Scsi_Host *shpnt)
barrier();
if(TESTLO(DMASTAT, DFIFOFULL|INTSTAT)) {
- printk(ERR_LEAD "datai timeout", CMDINFO(CURRENT_SC));
- disp_ports(shpnt);
+ scmd_printk(KERN_ERR, CURRENT_SC, "datai timeout\n");
break;
}
@@ -2199,8 +1999,8 @@ static void datai_run(struct Scsi_Host *shpnt)
barrier();
if(TESTLO(SSTAT2, SEMPTY)) {
- printk(ERR_LEAD "datai sempty timeout", CMDINFO(CURRENT_SC));
- disp_ports(shpnt);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "datai sempty timeout");
break;
}
@@ -2209,48 +2009,49 @@ static void datai_run(struct Scsi_Host *shpnt)
if(CURRENT_SC->SCp.this_residual>0) {
while(fifodata>0 && CURRENT_SC->SCp.this_residual>0) {
- data_count = fifodata>CURRENT_SC->SCp.this_residual ?
+ data_count = fifodata > CURRENT_SC->SCp.this_residual ?
CURRENT_SC->SCp.this_residual :
fifodata;
fifodata -= data_count;
- if(data_count & 1) {
- DPRINTK(debug_datai, DEBUG_LEAD "8bit\n", CMDINFO(CURRENT_SC));
- SETPORT(DMACNTRL0, ENDMA|_8BIT);
- *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
- CURRENT_SC->SCp.this_residual--;
- DATA_LEN++;
- SETPORT(DMACNTRL0, ENDMA);
- }
-
- if(data_count > 1) {
- DPRINTK(debug_datai, DEBUG_LEAD "16bit(%d)\n", CMDINFO(CURRENT_SC), data_count);
- data_count >>= 1;
- insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
- CURRENT_SC->SCp.ptr += 2 * data_count;
- CURRENT_SC->SCp.this_residual -= 2 * data_count;
- DATA_LEN += 2 * data_count;
- }
-
- if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
- /* advance to next buffer */
- CURRENT_SC->SCp.buffers_residual--;
- CURRENT_SC->SCp.buffer++;
- CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
- CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
- }
- }
- } else if(fifodata>0) {
- printk(ERR_LEAD "no buffers left for %d(%d) bytes (data overrun!?)\n", CMDINFO(CURRENT_SC), fifodata, GETPORT(FIFOSTAT));
- SETPORT(DMACNTRL0, ENDMA|_8BIT);
+ if (data_count & 1) {
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
+ *CURRENT_SC->SCp.ptr++ = GETPORT(DATAPORT);
+ CURRENT_SC->SCp.this_residual--;
+ DATA_LEN++;
+ SETPORT(DMACNTRL0, ENDMA);
+ }
+
+ if (data_count > 1) {
+ data_count >>= 1;
+ insw(DATAPORT, CURRENT_SC->SCp.ptr, data_count);
+ CURRENT_SC->SCp.ptr += 2 * data_count;
+ CURRENT_SC->SCp.this_residual -= 2 * data_count;
+ DATA_LEN += 2 * data_count;
+ }
+
+ if (CURRENT_SC->SCp.this_residual == 0 &&
+ CURRENT_SC->SCp.buffers_residual > 0) {
+ /* advance to next buffer */
+ CURRENT_SC->SCp.buffers_residual--;
+ CURRENT_SC->SCp.buffer++;
+ CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer);
+ CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length;
+ }
+ }
+ } else if (fifodata > 0) {
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "no buffers left for %d(%d) bytes"
+ " (data overrun!?)\n",
+ fifodata, GETPORT(FIFOSTAT));
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
while(fifodata>0) {
int data;
data=GETPORT(DATAPORT);
- DPRINTK(debug_datai, DEBUG_LEAD "data=%02x\n", CMDINFO(CURRENT_SC), data);
fifodata--;
DATA_LEN++;
}
- SETPORT(DMACNTRL0, ENDMA|_8BIT);
+ SETPORT(DMACNTRL0, ENDMA|_8BIT);
}
}
@@ -2258,19 +2059,20 @@ static void datai_run(struct Scsi_Host *shpnt)
TESTLO(DMASTAT, DFIFOEMP) ||
TESTLO(SSTAT2, SEMPTY) ||
GETPORT(FIFOSTAT)>0) {
- /*
+ /*
* something went wrong, if there's something left in the fifos
* or the phase didn't change
*/
- printk(ERR_LEAD "fifos should be empty and phase should have changed\n", CMDINFO(CURRENT_SC));
- disp_ports(shpnt);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "fifos should be empty and phase should have changed\n");
}
if(DATA_LEN!=GETSTCNT()) {
- printk(ERR_LEAD
- "manual transfer count differs from automatic (count=%d;stcnt=%d;diff=%d;fifostat=%d)",
- CMDINFO(CURRENT_SC), DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN, GETPORT(FIFOSTAT));
- disp_ports(shpnt);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "manual transfer count differs from automatic "
+ "(count=%d;stcnt=%d;diff=%d;fifostat=%d)",
+ DATA_LEN, GETSTCNT(), GETSTCNT()-DATA_LEN,
+ GETPORT(FIFOSTAT));
mdelay(10000);
}
}
@@ -2279,11 +2081,6 @@ static void datai_end(struct Scsi_Host *shpnt)
{
CMD_INC_RESID(CURRENT_SC, -GETSTCNT());
- DPRINTK(debug_datai,
- DEBUG_LEAD "datai_end: request_bufflen=%d resid=%d stcnt=%d\n",
- CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
- scsi_get_resid(CURRENT_SC), GETSTCNT());
-
SETPORT(SXFRCTL0, CH1|CLRSTCNT);
SETPORT(DMACNTRL0, 0);
}
@@ -2304,11 +2101,6 @@ static void datao_init(struct Scsi_Host *shpnt)
SETPORT(SIMODE1, ENSCSIPERR | ENSCSIRST | ENPHASEMIS | ENBUSFREE );
DATA_LEN = scsi_get_resid(CURRENT_SC);
-
- DPRINTK(debug_datao,
- DEBUG_LEAD "datao_init: request_bufflen=%d; resid=%d\n",
- CMDINFO(CURRENT_SC), scsi_bufflen(CURRENT_SC),
- scsi_get_resid(CURRENT_SC));
}
static void datao_run(struct Scsi_Host *shpnt)
@@ -2323,8 +2115,9 @@ static void datao_run(struct Scsi_Host *shpnt)
data_count=CURRENT_SC->SCp.this_residual;
if(TESTLO(DMASTAT, DFIFOEMP)) {
- printk(ERR_LEAD "datao fifo not empty (%d)", CMDINFO(CURRENT_SC), GETPORT(FIFOSTAT));
- disp_ports(shpnt);
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "datao fifo not empty (%d)",
+ GETPORT(FIFOSTAT));
break;
}
@@ -2342,7 +2135,7 @@ static void datao_run(struct Scsi_Host *shpnt)
CURRENT_SC->SCp.ptr += 2 * data_count;
CURRENT_SC->SCp.this_residual -= 2 * data_count;
CMD_INC_RESID(CURRENT_SC, -2 * data_count);
- }
+ }
if(CURRENT_SC->SCp.this_residual==0 && CURRENT_SC->SCp.buffers_residual>0) {
/* advance to next buffer */
@@ -2357,8 +2150,7 @@ static void datao_run(struct Scsi_Host *shpnt)
barrier();
if(TESTLO(DMASTAT, DFIFOEMP|INTSTAT)) {
- printk(ERR_LEAD "dataout timeout", CMDINFO(CURRENT_SC));
- disp_ports(shpnt);
+ scmd_printk(KERN_ERR, CURRENT_SC, "dataout timeout\n");
break;
}
}
@@ -2368,35 +2160,23 @@ static void datao_end(struct Scsi_Host *shpnt)
{
if(TESTLO(DMASTAT, DFIFOEMP)) {
int data_count = (DATA_LEN - scsi_get_resid(CURRENT_SC)) -
- GETSTCNT();
-
- DPRINTK(debug_datao, DEBUG_LEAD "datao: %d bytes to resend (%d written, %d transferred)\n",
- CMDINFO(CURRENT_SC),
- data_count,
- DATA_LEN - scsi_get_resid(CURRENT_SC),
- GETSTCNT());
+ GETSTCNT();
CMD_INC_RESID(CURRENT_SC, data_count);
data_count -= CURRENT_SC->SCp.ptr -
- SG_ADDRESS(CURRENT_SC->SCp.buffer);
+ SG_ADDRESS(CURRENT_SC->SCp.buffer);
while(data_count>0) {
CURRENT_SC->SCp.buffer--;
CURRENT_SC->SCp.buffers_residual++;
data_count -= CURRENT_SC->SCp.buffer->length;
}
CURRENT_SC->SCp.ptr = SG_ADDRESS(CURRENT_SC->SCp.buffer) -
- data_count;
+ data_count;
CURRENT_SC->SCp.this_residual = CURRENT_SC->SCp.buffer->length +
- data_count;
+ data_count;
}
- DPRINTK(debug_datao, DEBUG_LEAD "datao_end: request_bufflen=%d; resid=%d; stcnt=%d\n",
- CMDINFO(CURRENT_SC),
- scsi_bufflen(CURRENT_SC),
- scsi_get_resid(CURRENT_SC),
- GETSTCNT());
-
SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
SETPORT(SXFRCTL0, CH1);
@@ -2420,7 +2200,7 @@ static int update_state(struct Scsi_Host *shpnt)
STATE=rsti;
SETPORT(SCSISEQ,0);
SETPORT(SSTAT1,SCSIRSTI);
- } else if(stat0 & SELDI && PREVSTATE==busfree) {
+ } else if (stat0 & SELDI && PREVSTATE == busfree) {
STATE=seldi;
} else if(stat0 & SELDO && CURRENT_SC && (CURRENT_SC->SCp.phase & selecting)) {
STATE=seldo;
@@ -2445,8 +2225,7 @@ static int update_state(struct Scsi_Host *shpnt)
}
if((stat0 & SELDI) && STATE!=seldi && !dataphase) {
- printk(INFO_LEAD "reselection missed?", CMDINFO(CURRENT_SC));
- disp_ports(shpnt);
+ scmd_printk(KERN_INFO, CURRENT_SC, "reselection missed?");
}
if(STATE!=PREVSTATE) {
@@ -2464,7 +2243,7 @@ static int update_state(struct Scsi_Host *shpnt)
*/
static void parerr_run(struct Scsi_Host *shpnt)
{
- printk(ERR_LEAD "parity error\n", CMDINFO(CURRENT_SC));
+ scmd_printk(KERN_ERR, CURRENT_SC, "parity error\n");
done(shpnt, DID_PARITY << 16);
}
@@ -2476,8 +2255,8 @@ static void rsti_run(struct Scsi_Host *shpnt)
{
Scsi_Cmnd *ptr;
- printk(KERN_NOTICE "aha152x%d: scsi reset in\n", HOSTNO);
-
+ shost_printk(KERN_NOTICE, shpnt, "scsi reset in\n");
+
ptr=DISCONNECTED_SC;
while(ptr) {
Scsi_Cmnd *next = SCNEXT(ptr);
@@ -2539,8 +2318,6 @@ static void is_complete(struct Scsi_Host *shpnt)
dataphase=update_state(shpnt);
- DPRINTK(debug_phases, LEAD "start %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
-
/*
* end previous state
*
@@ -2567,9 +2344,9 @@ static void is_complete(struct Scsi_Host *shpnt)
if(dataphase) {
SETPORT(SSTAT0, REQINIT);
SETPORT(SCSISIG, GETPORT(SCSISIG) & P_MASK);
- SETPORT(SSTAT1, PHASECHG);
+ SETPORT(SSTAT1, PHASECHG);
}
-
+
/*
* enable SPIO mode if previous didn't use it
* and this one does
@@ -2581,14 +2358,14 @@ static void is_complete(struct Scsi_Host *shpnt)
if(CURRENT_SC)
CURRENT_SC->SCp.phase |= spiordy;
}
-
+
/*
* initialize for new state
*
*/
if(PREVSTATE!=STATE && states[STATE].init)
states[STATE].init(shpnt);
-
+
/*
* handle current state
*
@@ -2596,8 +2373,9 @@ static void is_complete(struct Scsi_Host *shpnt)
if(states[STATE].run)
states[STATE].run(shpnt);
else
- printk(ERR_LEAD "unexpected state (%x)\n", CMDINFO(CURRENT_SC), STATE);
-
+ scmd_printk(KERN_ERR, CURRENT_SC,
+ "unexpected state (%x)\n", STATE);
+
/*
* setup controller to interrupt on
* the next expected condition and
@@ -2613,7 +2391,6 @@ static void is_complete(struct Scsi_Host *shpnt)
HOSTDATA(shpnt)->time[STATE] += jiffies-start;
#endif
- DPRINTK(debug_phases, LEAD "end %s %s(%s)\n", CMDINFO(CURRENT_SC), states[STATE].name, states[PREVSTATE].name, states[LASTSTATE].name);
} while(pending);
/*
@@ -2626,289 +2403,42 @@ static void is_complete(struct Scsi_Host *shpnt)
}
-/*
+/*
* Dump the current driver status and panic
*/
static void aha152x_error(struct Scsi_Host *shpnt, char *msg)
{
- printk(KERN_EMERG "\naha152x%d: %s\n", HOSTNO, msg);
+ shost_printk(KERN_EMERG, shpnt, "%s\n", msg);
show_queues(shpnt);
panic("aha152x panic\n");
}
/*
- * Display registers of AIC-6260
- */
-static void disp_ports(struct Scsi_Host *shpnt)
-{
-#if defined(AHA152X_DEBUG)
- int s;
-
- printk("\n%s: %s(%s) ",
- CURRENT_SC ? "busy" : "waiting",
- states[STATE].name,
- states[PREVSTATE].name);
-
- s = GETPORT(SCSISEQ);
- printk("SCSISEQ( ");
- if (s & TEMODEO)
- printk("TARGET MODE ");
- if (s & ENSELO)
- printk("SELO ");
- if (s & ENSELI)
- printk("SELI ");
- if (s & ENRESELI)
- printk("RESELI ");
- if (s & ENAUTOATNO)
- printk("AUTOATNO ");
- if (s & ENAUTOATNI)
- printk("AUTOATNI ");
- if (s & ENAUTOATNP)
- printk("AUTOATNP ");
- if (s & SCSIRSTO)
- printk("SCSIRSTO ");
- printk(");");
-
- printk(" SCSISIG(");
- s = GETPORT(SCSISIG);
- switch (s & P_MASK) {
- case P_DATAO:
- printk("DATA OUT");
- break;
- case P_DATAI:
- printk("DATA IN");
- break;
- case P_CMD:
- printk("COMMAND");
- break;
- case P_STATUS:
- printk("STATUS");
- break;
- case P_MSGO:
- printk("MESSAGE OUT");
- break;
- case P_MSGI:
- printk("MESSAGE IN");
- break;
- default:
- printk("*invalid*");
- break;
- }
-
- printk("); ");
-
- printk("INTSTAT (%s); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
-
- printk("SSTAT( ");
- s = GETPORT(SSTAT0);
- if (s & TARGET)
- printk("TARGET ");
- if (s & SELDO)
- printk("SELDO ");
- if (s & SELDI)
- printk("SELDI ");
- if (s & SELINGO)
- printk("SELINGO ");
- if (s & SWRAP)
- printk("SWRAP ");
- if (s & SDONE)
- printk("SDONE ");
- if (s & SPIORDY)
- printk("SPIORDY ");
- if (s & DMADONE)
- printk("DMADONE ");
-
- s = GETPORT(SSTAT1);
- if (s & SELTO)
- printk("SELTO ");
- if (s & ATNTARG)
- printk("ATNTARG ");
- if (s & SCSIRSTI)
- printk("SCSIRSTI ");
- if (s & PHASEMIS)
- printk("PHASEMIS ");
- if (s & BUSFREE)
- printk("BUSFREE ");
- if (s & SCSIPERR)
- printk("SCSIPERR ");
- if (s & PHASECHG)
- printk("PHASECHG ");
- if (s & REQINIT)
- printk("REQINIT ");
- printk("); ");
-
-
- printk("SSTAT( ");
-
- s = GETPORT(SSTAT0) & GETPORT(SIMODE0);
-
- if (s & TARGET)
- printk("TARGET ");
- if (s & SELDO)
- printk("SELDO ");
- if (s & SELDI)
- printk("SELDI ");
- if (s & SELINGO)
- printk("SELINGO ");
- if (s & SWRAP)
- printk("SWRAP ");
- if (s & SDONE)
- printk("SDONE ");
- if (s & SPIORDY)
- printk("SPIORDY ");
- if (s & DMADONE)
- printk("DMADONE ");
-
- s = GETPORT(SSTAT1) & GETPORT(SIMODE1);
-
- if (s & SELTO)
- printk("SELTO ");
- if (s & ATNTARG)
- printk("ATNTARG ");
- if (s & SCSIRSTI)
- printk("SCSIRSTI ");
- if (s & PHASEMIS)
- printk("PHASEMIS ");
- if (s & BUSFREE)
- printk("BUSFREE ");
- if (s & SCSIPERR)
- printk("SCSIPERR ");
- if (s & PHASECHG)
- printk("PHASECHG ");
- if (s & REQINIT)
- printk("REQINIT ");
- printk("); ");
-
- printk("SXFRCTL0( ");
-
- s = GETPORT(SXFRCTL0);
- if (s & SCSIEN)
- printk("SCSIEN ");
- if (s & DMAEN)
- printk("DMAEN ");
- if (s & CH1)
- printk("CH1 ");
- if (s & CLRSTCNT)
- printk("CLRSTCNT ");
- if (s & SPIOEN)
- printk("SPIOEN ");
- if (s & CLRCH1)
- printk("CLRCH1 ");
- printk("); ");
-
- printk("SIGNAL( ");
-
- s = GETPORT(SCSISIG);
- if (s & SIG_ATNI)
- printk("ATNI ");
- if (s & SIG_SELI)
- printk("SELI ");
- if (s & SIG_BSYI)
- printk("BSYI ");
- if (s & SIG_REQI)
- printk("REQI ");
- if (s & SIG_ACKI)
- printk("ACKI ");
- printk("); ");
-
- printk("SELID (%02x), ", GETPORT(SELID));
-
- printk("STCNT (%d), ", GETSTCNT());
-
- printk("SSTAT2( ");
-
- s = GETPORT(SSTAT2);
- if (s & SOFFSET)
- printk("SOFFSET ");
- if (s & SEMPTY)
- printk("SEMPTY ");
- if (s & SFULL)
- printk("SFULL ");
- printk("); SFCNT (%d); ", s & (SFULL | SFCNT));
-
- s = GETPORT(SSTAT3);
- printk("SCSICNT (%d), OFFCNT(%d), ", (s & 0xf0) >> 4, s & 0x0f);
-
- printk("SSTAT4( ");
- s = GETPORT(SSTAT4);
- if (s & SYNCERR)
- printk("SYNCERR ");
- if (s & FWERR)
- printk("FWERR ");
- if (s & FRERR)
- printk("FRERR ");
- printk("); ");
-
- printk("DMACNTRL0( ");
- s = GETPORT(DMACNTRL0);
- printk("%s ", s & _8BIT ? "8BIT" : "16BIT");
- printk("%s ", s & DMA ? "DMA" : "PIO");
- printk("%s ", s & WRITE_READ ? "WRITE" : "READ");
- if (s & ENDMA)
- printk("ENDMA ");
- if (s & INTEN)
- printk("INTEN ");
- if (s & RSTFIFO)
- printk("RSTFIFO ");
- if (s & SWINT)
- printk("SWINT ");
- printk("); ");
-
- printk("DMASTAT( ");
- s = GETPORT(DMASTAT);
- if (s & ATDONE)
- printk("ATDONE ");
- if (s & WORDRDY)
- printk("WORDRDY ");
- if (s & DFIFOFULL)
- printk("DFIFOFULL ");
- if (s & DFIFOEMP)
- printk("DFIFOEMP ");
- printk(")\n");
-#endif
-}
-
-/*
* display enabled interrupts
*/
static void disp_enintr(struct Scsi_Host *shpnt)
{
- int s;
-
- printk(KERN_DEBUG "enabled interrupts ( ");
-
- s = GETPORT(SIMODE0);
- if (s & ENSELDO)
- printk("ENSELDO ");
- if (s & ENSELDI)
- printk("ENSELDI ");
- if (s & ENSELINGO)
- printk("ENSELINGO ");
- if (s & ENSWRAP)
- printk("ENSWRAP ");
- if (s & ENSDONE)
- printk("ENSDONE ");
- if (s & ENSPIORDY)
- printk("ENSPIORDY ");
- if (s & ENDMADONE)
- printk("ENDMADONE ");
-
- s = GETPORT(SIMODE1);
- if (s & ENSELTIMO)
- printk("ENSELTIMO ");
- if (s & ENATNTARG)
- printk("ENATNTARG ");
- if (s & ENPHASEMIS)
- printk("ENPHASEMIS ");
- if (s & ENBUSFREE)
- printk("ENBUSFREE ");
- if (s & ENSCSIPERR)
- printk("ENSCSIPERR ");
- if (s & ENPHASECHG)
- printk("ENPHASECHG ");
- if (s & ENREQINIT)
- printk("ENREQINIT ");
- printk(")\n");
+ int s0, s1;
+
+ s0 = GETPORT(SIMODE0);
+ s1 = GETPORT(SIMODE1);
+
+ shost_printk(KERN_DEBUG, shpnt,
+ "enabled interrupts (%s%s%s%s%s%s%s%s%s%s%s%s%s%s)\n",
+ (s0 & ENSELDO) ? "ENSELDO " : "",
+ (s0 & ENSELDI) ? "ENSELDI " : "",
+ (s0 & ENSELINGO) ? "ENSELINGO " : "",
+ (s0 & ENSWRAP) ? "ENSWRAP " : "",
+ (s0 & ENSDONE) ? "ENSDONE " : "",
+ (s0 & ENSPIORDY) ? "ENSPIORDY " : "",
+ (s0 & ENDMADONE) ? "ENDMADONE " : "",
+ (s1 & ENSELTIMO) ? "ENSELTIMO " : "",
+ (s1 & ENATNTARG) ? "ENATNTARG " : "",
+ (s1 & ENPHASEMIS) ? "ENPHASEMIS " : "",
+ (s1 & ENBUSFREE) ? "ENBUSFREE " : "",
+ (s1 & ENSCSIPERR) ? "ENSCSIPERR " : "",
+ (s1 & ENPHASECHG) ? "ENPHASECHG " : "",
+ (s1 & ENREQINIT) ? "ENREQINIT " : "");
}
/*
@@ -2916,36 +2446,21 @@ static void disp_enintr(struct Scsi_Host *shpnt)
*/
static void show_command(Scsi_Cmnd *ptr)
{
- scmd_printk(KERN_DEBUG, ptr, "%p: cmnd=(", ptr);
-
- __scsi_print_command(ptr->cmnd);
-
- printk(KERN_DEBUG "); request_bufflen=%d; resid=%d; phase |",
- scsi_bufflen(ptr), scsi_get_resid(ptr));
-
- if (ptr->SCp.phase & not_issued)
- printk("not issued|");
- if (ptr->SCp.phase & selecting)
- printk("selecting|");
- if (ptr->SCp.phase & identified)
- printk("identified|");
- if (ptr->SCp.phase & disconnected)
- printk("disconnected|");
- if (ptr->SCp.phase & completed)
- printk("completed|");
- if (ptr->SCp.phase & spiordy)
- printk("spiordy|");
- if (ptr->SCp.phase & syncneg)
- printk("syncneg|");
- if (ptr->SCp.phase & aborted)
- printk("aborted|");
- if (ptr->SCp.phase & resetted)
- printk("resetted|");
- if( SCDATA(ptr) ) {
- printk("; next=0x%p\n", SCNEXT(ptr));
- } else {
- printk("; next=(host scribble NULL)\n");
- }
+ scsi_print_command(ptr);
+ scmd_printk(KERN_DEBUG, ptr,
+ "request_bufflen=%d; resid=%d; "
+ "phase |%s%s%s%s%s%s%s%s%s; next=0x%p",
+ scsi_bufflen(ptr), scsi_get_resid(ptr),
+ (ptr->SCp.phase & not_issued) ? "not issued|" : "",
+ (ptr->SCp.phase & selecting) ? "selecting|" : "",
+ (ptr->SCp.phase & identified) ? "identified|" : "",
+ (ptr->SCp.phase & disconnected) ? "disconnected|" : "",
+ (ptr->SCp.phase & completed) ? "completed|" : "",
+ (ptr->SCp.phase & spiordy) ? "spiordy|" : "",
+ (ptr->SCp.phase & syncneg) ? "syncneg|" : "",
+ (ptr->SCp.phase & aborted) ? "aborted|" : "",
+ (ptr->SCp.phase & resetted) ? "resetted|" : "",
+ (SCDATA(ptr)) ? SCNEXT(ptr) : NULL);
}
/*
@@ -2972,7 +2487,6 @@ static void show_queues(struct Scsi_Host *shpnt)
for (ptr = DISCONNECTED_SC; ptr; ptr = SCDATA(ptr) ? SCNEXT(ptr) : NULL)
show_command(ptr);
- disp_ports(shpnt);
disp_enintr(shpnt);
}
@@ -3276,15 +2790,6 @@ static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
if(!shpnt || !buffer || length<8 || strncmp("aha152x ", buffer, 8)!=0)
return -EINVAL;
-#if defined(AHA152X_DEBUG)
- if(length>14 && strncmp("debug ", buffer+8, 6)==0) {
- int debug = HOSTDATA(shpnt)->debug;
-
- HOSTDATA(shpnt)->debug = simple_strtoul(buffer+14, NULL, 0);
-
- printk(KERN_INFO "aha152x%d: debugging options set to 0x%04x (were 0x%04x)\n", HOSTNO, HOSTDATA(shpnt)->debug, debug);
- } else
-#endif
#if defined(AHA152X_STAT)
if(length>13 && strncmp("reset", buffer+8, 5)==0) {
int i;
@@ -3302,7 +2807,7 @@ static int aha152x_set_info(struct Scsi_Host *shpnt, char *buffer, int length)
HOSTDATA(shpnt)->time[i]=0;
}
- printk(KERN_INFO "aha152x%d: stats reseted.\n", HOSTNO);
+ shost_printk(KERN_INFO, shpnt, "aha152x: stats reset.\n");
} else
#endif
@@ -3343,29 +2848,6 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
(((HOSTDATA(shpnt)->syncrate[i] & 0x70) >> 4) + 2) * 50,
HOSTDATA(shpnt)->syncrate[i] & 0x0f);
}
-#if defined(AHA152X_DEBUG)
-#define PDEBUG(flags,txt) \
- if(HOSTDATA(shpnt)->debug & flags) SPRINTF("(%s) ", txt);
-
- SPRINTF("enabled debugging options: ");
-
- PDEBUG(debug_procinfo, "procinfo");
- PDEBUG(debug_queue, "queue");
- PDEBUG(debug_intr, "interrupt");
- PDEBUG(debug_selection, "selection");
- PDEBUG(debug_msgo, "message out");
- PDEBUG(debug_msgi, "message in");
- PDEBUG(debug_status, "status");
- PDEBUG(debug_cmd, "command");
- PDEBUG(debug_datai, "data in");
- PDEBUG(debug_datao, "data out");
- PDEBUG(debug_eh, "eh");
- PDEBUG(debug_locking, "locks");
- PDEBUG(debug_phases, "phases");
-
- SPRINTF("\n");
-#endif
-
SPRINTF("\nqueue status:\n");
DO_LOCK(flags);
if (ISSUE_SC) {
@@ -3393,8 +2875,8 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
#if defined(AHA152X_STAT)
SPRINTF("statistics:\n"
- "total commands: %d\n"
- "disconnections: %d\n"
+ "total commands: %d\n"
+ "disconnections: %d\n"
"busfree with check condition: %d\n"
"busfree without old command: %d\n"
"busfree without new command: %d\n"
@@ -3413,7 +2895,7 @@ static int aha152x_show_info(struct seq_file *m, struct Scsi_Host *shpnt)
HOSTDATA(shpnt)->busfree_without_any_action);
for(i=0; i<maxstate; i++) {
SPRINTF("%-10s %-12d %-12d %-12ld\n",
- states[i].name,
+ states[i].name,
HOSTDATA(shpnt)->count_trans[i],
HOSTDATA(shpnt)->count[i],
HOSTDATA(shpnt)->time[i]);
@@ -3671,25 +3153,19 @@ static int __init aha152x_init(void)
setup[setup_count].synchronous = aha152x[5];
setup[setup_count].delay = aha152x[6];
setup[setup_count].ext_trans = aha152x[7];
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = aha152x[8];
-#endif
- } else if(io[0]!=0 || irq[0]!=0) {
+ } else if (io[0] != 0 || irq[0] != 0) {
if(io[0]!=0) setup[setup_count].io_port = io[0];
if(irq[0]!=0) setup[setup_count].irq = irq[0];
- setup[setup_count].scsiid = scsiid[0];
- setup[setup_count].reconnect = reconnect[0];
- setup[setup_count].parity = parity[0];
- setup[setup_count].synchronous = sync[0];
- setup[setup_count].delay = delay[0];
- setup[setup_count].ext_trans = exttrans[0];
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = debug[0];
-#endif
+ setup[setup_count].scsiid = scsiid[0];
+ setup[setup_count].reconnect = reconnect[0];
+ setup[setup_count].parity = parity[0];
+ setup[setup_count].synchronous = sync[0];
+ setup[setup_count].delay = delay[0];
+ setup[setup_count].ext_trans = exttrans[0];
}
- if (checksetup(&setup[setup_count]))
+ if (checksetup(&setup[setup_count]))
setup_count++;
else
printk(KERN_ERR "aha152x: invalid module params io=0x%x, irq=%d,scsiid=%d,reconnect=%d,parity=%d,sync=%d,delay=%d,exttrans=%d\n",
@@ -3714,22 +3190,16 @@ static int __init aha152x_init(void)
setup[setup_count].synchronous = aha152x1[5];
setup[setup_count].delay = aha152x1[6];
setup[setup_count].ext_trans = aha152x1[7];
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = aha152x1[8];
-#endif
- } else if(io[1]!=0 || irq[1]!=0) {
+ } else if (io[1] != 0 || irq[1] != 0) {
if(io[1]!=0) setup[setup_count].io_port = io[1];
if(irq[1]!=0) setup[setup_count].irq = irq[1];
- setup[setup_count].scsiid = scsiid[1];
- setup[setup_count].reconnect = reconnect[1];
- setup[setup_count].parity = parity[1];
- setup[setup_count].synchronous = sync[1];
- setup[setup_count].delay = delay[1];
- setup[setup_count].ext_trans = exttrans[1];
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = debug[1];
-#endif
+ setup[setup_count].scsiid = scsiid[1];
+ setup[setup_count].reconnect = reconnect[1];
+ setup[setup_count].parity = parity[1];
+ setup[setup_count].synchronous = sync[1];
+ setup[setup_count].delay = delay[1];
+ setup[setup_count].ext_trans = exttrans[1];
}
if (checksetup(&setup[setup_count]))
setup_count++;
@@ -3776,9 +3246,6 @@ static int __init aha152x_init(void)
setup[setup_count].synchronous = 1;
setup[setup_count].delay = DELAY_DEFAULT;
setup[setup_count].ext_trans = 0;
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = DEBUG_DEFAULT;
-#endif
#if defined(__ISAPNP__)
pnpdev[setup_count] = dev;
#endif
@@ -3847,9 +3314,6 @@ static int __init aha152x_init(void)
setup[setup_count].synchronous = conf.cf_syncneg;
setup[setup_count].delay = DELAY_DEFAULT;
setup[setup_count].ext_trans = 0;
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = DEBUG_DEFAULT;
-#endif
setup_count++;
}
@@ -3903,11 +3367,8 @@ module_exit(aha152x_exit);
#if !defined(MODULE)
static int __init aha152x_setup(char *str)
{
-#if defined(AHA152X_DEBUG)
- int ints[11];
-#else
int ints[10];
-#endif
+
get_options(str, ARRAY_SIZE(ints), ints);
if(setup_count>=ARRAY_SIZE(setup)) {
@@ -3924,16 +3385,9 @@ static int __init aha152x_setup(char *str)
setup[setup_count].synchronous = ints[0] >= 6 ? ints[6] : 1;
setup[setup_count].delay = ints[0] >= 7 ? ints[7] : DELAY_DEFAULT;
setup[setup_count].ext_trans = ints[0] >= 8 ? ints[8] : 0;
-#if defined(AHA152X_DEBUG)
- setup[setup_count].debug = ints[0] >= 9 ? ints[9] : DEBUG_DEFAULT;
- if (ints[0] > 9) {
- printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
- "[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>[,<DEBUG>]]]]]]]]\n");
-#else
if (ints[0] > 8) { /*}*/
printk(KERN_NOTICE "aha152x: usage: aha152x=<IOBASE>[,<IRQ>[,<SCSI ID>"
"[,<RECONNECT>[,<PARITY>[,<SYNCHRONOUS>[,<DELAY>[,<EXT_TRANS>]]]]]]]\n");
-#endif
} else {
setup_count++;
return 0;
diff --git a/drivers/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 5f31017..31ace4b 100644
--- a/drivers/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -531,7 +531,7 @@ static int aha1740_eh_abort_handler (Scsi_Cmnd *dummy)
* quiet as possible...
*/
- return 0;
+ return SUCCESS;
}
static struct scsi_host_template aha1740_template = {
diff --git a/drivers/scsi/aic7xxx/aic79xx_osm.c b/drivers/scsi/aic7xxx/aic79xx_osm.c
index ed333669..d5c7b19 100644
--- a/drivers/scsi/aic7xxx/aic79xx_osm.c
+++ b/drivers/scsi/aic7xxx/aic79xx_osm.c
@@ -925,6 +925,7 @@ struct scsi_host_template aic79xx_driver_template = {
.slave_configure = ahd_linux_slave_configure,
.target_alloc = ahd_linux_target_alloc,
.target_destroy = ahd_linux_target_destroy,
+ .use_blk_tags = 1,
};
/******************************** Bus DMA *************************************/
@@ -1468,12 +1469,9 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
switch ((dev->flags & (AHD_DEV_Q_BASIC|AHD_DEV_Q_TAGGED))) {
case AHD_DEV_Q_BASIC:
- scsi_set_tag_type(sdev, MSG_SIMPLE_TASK);
- scsi_activate_tcq(sdev, dev->openings + dev->active);
- break;
case AHD_DEV_Q_TAGGED:
- scsi_set_tag_type(sdev, MSG_ORDERED_TASK);
- scsi_activate_tcq(sdev, dev->openings + dev->active);
+ scsi_change_queue_depth(sdev,
+ dev->openings + dev->active);
break;
default:
/*
@@ -1482,7 +1480,7 @@ ahd_platform_set_tags(struct ahd_softc *ahd, struct scsi_device *sdev,
* serially on the controller/device. This should
* remove some latency.
*/
- scsi_deactivate_tcq(sdev, 1);
+ scsi_change_queue_depth(sdev, 1);
break;
}
}
@@ -1619,15 +1617,6 @@ ahd_linux_run_command(struct ahd_softc *ahd, struct ahd_linux_device *dev,
}
if ((dev->flags & (AHD_DEV_Q_TAGGED|AHD_DEV_Q_BASIC)) != 0) {
- int msg_bytes;
- uint8_t tag_msgs[2];
-
- msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
- if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
- hscb->control |= tag_msgs[0];
- if (tag_msgs[0] == MSG_ORDERED_TASK)
- dev->commands_since_idle_or_otag = 0;
- } else
if (dev->commands_since_idle_or_otag == AHD_OTAG_THRESH
&& (dev->flags & AHD_DEV_Q_TAGGED) != 0) {
hscb->control |= MSG_ORDERED_TASK;
diff --git a/drivers/scsi/aic7xxx/aic7xxx_osm.c b/drivers/scsi/aic7xxx/aic7xxx_osm.c
index d2c9bf3..8836011 100644
--- a/drivers/scsi/aic7xxx/aic7xxx_osm.c
+++ b/drivers/scsi/aic7xxx/aic7xxx_osm.c
@@ -812,6 +812,7 @@ struct scsi_host_template aic7xxx_driver_template = {
.slave_configure = ahc_linux_slave_configure,
.target_alloc = ahc_linux_target_alloc,
.target_destroy = ahc_linux_target_destroy,
+ .use_blk_tags = 1,
};
/**************************** Tasklet Handler *********************************/
@@ -1334,13 +1335,9 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
}
switch ((dev->flags & (AHC_DEV_Q_BASIC|AHC_DEV_Q_TAGGED))) {
case AHC_DEV_Q_BASIC:
- scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);
- scsi_activate_tcq(sdev, dev->openings + dev->active);
- break;
case AHC_DEV_Q_TAGGED:
- scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
- scsi_activate_tcq(sdev, dev->openings + dev->active);
- break;
+ scsi_change_queue_depth(sdev,
+ dev->openings + dev->active);
default:
/*
* We allow the OS to queue 2 untagged transactions to
@@ -1348,7 +1345,7 @@ ahc_platform_set_tags(struct ahc_softc *ahc, struct scsi_device *sdev,
* serially on the controller/device. This should
* remove some latency.
*/
- scsi_deactivate_tcq(sdev, 2);
+ scsi_change_queue_depth(sdev, 2);
break;
}
}
@@ -1447,7 +1444,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
* we are storing a full busy target *lun*
* table in SCB space.
*/
- if (!blk_rq_tagged(cmd->request)
+ if (!(cmd->flags & SCMD_TAGGED)
&& (ahc->features & AHC_SCB_BTT) == 0) {
int target_offset;
@@ -1501,15 +1498,7 @@ ahc_linux_run_command(struct ahc_softc *ahc, struct ahc_linux_device *dev,
}
if ((dev->flags & (AHC_DEV_Q_TAGGED|AHC_DEV_Q_BASIC)) != 0) {
- int msg_bytes;
- uint8_t tag_msgs[2];
-
- msg_bytes = scsi_populate_tag_msg(cmd, tag_msgs);
- if (msg_bytes && tag_msgs[0] != MSG_SIMPLE_TASK) {
- hscb->control |= tag_msgs[0];
- if (tag_msgs[0] == MSG_ORDERED_TASK)
- dev->commands_since_idle_or_otag = 0;
- } else if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
+ if (dev->commands_since_idle_or_otag == AHC_OTAG_THRESH
&& (dev->flags & AHC_DEV_Q_TAGGED) != 0) {
hscb->control |= MSG_ORDERED_TASK;
dev->commands_since_idle_or_otag = 0;
diff --git a/drivers/scsi/aic94xx/aic94xx.h b/drivers/scsi/aic94xx/aic94xx.h
index 66cda66..26d4ad9 100644
--- a/drivers/scsi/aic94xx/aic94xx.h
+++ b/drivers/scsi/aic94xx/aic94xx.h
@@ -78,7 +78,7 @@ void asd_dev_gone(struct domain_device *dev);
void asd_invalidate_edb(struct asd_ascb *ascb, int edb_id);
-int asd_execute_task(struct sas_task *, int num, gfp_t gfp_flags);
+int asd_execute_task(struct sas_task *task, gfp_t gfp_flags);
void asd_set_dmamode(struct domain_device *dev);
diff --git a/drivers/scsi/aic94xx/aic94xx_hwi.c b/drivers/scsi/aic94xx/aic94xx_hwi.c
index 4df867e..9f636a3 100644
--- a/drivers/scsi/aic94xx/aic94xx_hwi.c
+++ b/drivers/scsi/aic94xx/aic94xx_hwi.c
@@ -1200,8 +1200,7 @@ static void asd_start_scb_timers(struct list_head *list)
* Case A: we can send the whole batch at once. Increment "pending"
* in the beginning of this function, when it is checked, in order to
* eliminate races when this function is called by multiple processes.
- * Case B: should never happen if the managing layer considers
- * lldd_queue_size.
+ * Case B: should never happen.
*/
int asd_post_ascb_list(struct asd_ha_struct *asd_ha, struct asd_ascb *ascb,
int num)
diff --git a/drivers/scsi/aic94xx/aic94xx_init.c b/drivers/scsi/aic94xx/aic94xx_init.c
index c56741f..14fc018 100644
--- a/drivers/scsi/aic94xx/aic94xx_init.c
+++ b/drivers/scsi/aic94xx/aic94xx_init.c
@@ -49,14 +49,6 @@ MODULE_PARM_DESC(use_msi, "\n"
"\tEnable(1) or disable(0) using PCI MSI.\n"
"\tDefault: 0");
-static int lldd_max_execute_num = 0;
-module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
-MODULE_PARM_DESC(collector, "\n"
- "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
- "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
- "\tThe aic94xx SAS LLDD supports both modes.\n"
- "\tDefault: 0 (Direct Mode).\n");
-
static struct scsi_transport_template *aic94xx_transport_template;
static int asd_scan_finished(struct Scsi_Host *, unsigned long);
static void asd_scan_start(struct Scsi_Host *);
@@ -83,6 +75,8 @@ static struct scsi_host_template aic94xx_sht = {
.eh_bus_reset_handler = sas_eh_bus_reset_handler,
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static int asd_map_memio(struct asd_ha_struct *asd_ha)
@@ -709,9 +703,6 @@ static int asd_register_sas_ha(struct asd_ha_struct *asd_ha)
asd_ha->sas_ha.sas_port= sas_ports;
asd_ha->sas_ha.num_phys= ASD_MAX_PHYS;
- asd_ha->sas_ha.lldd_queue_size = asd_ha->seq.can_queue;
- asd_ha->sas_ha.lldd_max_execute_num = lldd_max_execute_num;
-
return sas_register_ha(&asd_ha->sas_ha);
}
diff --git a/drivers/scsi/aic94xx/aic94xx_task.c b/drivers/scsi/aic94xx/aic94xx_task.c
index 59b86e2..5ff1ce7 100644
--- a/drivers/scsi/aic94xx/aic94xx_task.c
+++ b/drivers/scsi/aic94xx/aic94xx_task.c
@@ -543,8 +543,7 @@ static int asd_can_queue(struct asd_ha_struct *asd_ha, int num)
return res;
}
-int asd_execute_task(struct sas_task *task, const int num,
- gfp_t gfp_flags)
+int asd_execute_task(struct sas_task *task, gfp_t gfp_flags)
{
int res = 0;
LIST_HEAD(alist);
@@ -553,11 +552,11 @@ int asd_execute_task(struct sas_task *task, const int num,
struct asd_ha_struct *asd_ha = task->dev->port->ha->lldd_ha;
unsigned long flags;
- res = asd_can_queue(asd_ha, num);
+ res = asd_can_queue(asd_ha, 1);
if (res)
return res;
- res = num;
+ res = 1;
ascb = asd_ascb_alloc_list(asd_ha, &res, gfp_flags);
if (res) {
res = -ENOMEM;
@@ -568,7 +567,7 @@ int asd_execute_task(struct sas_task *task, const int num,
list_for_each_entry(a, &alist, list) {
a->uldd_task = t;
t->lldd_task = a;
- t = list_entry(t->list.next, struct sas_task, list);
+ break;
}
list_for_each_entry(a, &alist, list) {
t = a->uldd_task;
@@ -601,7 +600,7 @@ int asd_execute_task(struct sas_task *task, const int num,
}
list_del_init(&alist);
- res = asd_post_ascb_list(asd_ha, ascb, num);
+ res = asd_post_ascb_list(asd_ha, ascb, 1);
if (unlikely(res)) {
a = NULL;
__list_add(&alist, ascb->list.prev, &ascb->list);
@@ -639,6 +638,6 @@ out_err_unmap:
out_err:
if (ascb)
asd_ascb_free_list(ascb);
- asd_can_dequeue(asd_ha, num);
+ asd_can_dequeue(asd_ha, 1);
return res;
}
diff --git a/drivers/scsi/am53c974.c b/drivers/scsi/am53c974.c
new file mode 100644
index 0000000..aa3e2c7
--- /dev/null
+++ b/drivers/scsi/am53c974.c
@@ -0,0 +1,586 @@
+/*
+ * AMD am53c974 driver.
+ * Copyright (c) 2014 Hannes Reinecke, SUSE Linux GmbH
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/interrupt.h>
+
+#include <scsi/scsi_host.h>
+
+#include "esp_scsi.h"
+
+#define DRV_MODULE_NAME "am53c974"
+#define DRV_MODULE_VERSION "1.00"
+
+static bool am53c974_debug;
+static bool am53c974_fenab = true;
+
+#define esp_dma_log(f, a...) \
+ do { \
+ if (am53c974_debug) \
+ shost_printk(KERN_DEBUG, esp->host, f, ##a); \
+ } while (0)
+
+#define ESP_DMA_CMD 0x10
+#define ESP_DMA_STC 0x11
+#define ESP_DMA_SPA 0x12
+#define ESP_DMA_WBC 0x13
+#define ESP_DMA_WAC 0x14
+#define ESP_DMA_STATUS 0x15
+#define ESP_DMA_SMDLA 0x16
+#define ESP_DMA_WMAC 0x17
+
+#define ESP_DMA_CMD_IDLE 0x00
+#define ESP_DMA_CMD_BLAST 0x01
+#define ESP_DMA_CMD_ABORT 0x02
+#define ESP_DMA_CMD_START 0x03
+#define ESP_DMA_CMD_MASK 0x03
+#define ESP_DMA_CMD_DIAG 0x04
+#define ESP_DMA_CMD_MDL 0x10
+#define ESP_DMA_CMD_INTE_P 0x20
+#define ESP_DMA_CMD_INTE_D 0x40
+#define ESP_DMA_CMD_DIR 0x80
+
+#define ESP_DMA_STAT_PWDN 0x01
+#define ESP_DMA_STAT_ERROR 0x02
+#define ESP_DMA_STAT_ABORT 0x04
+#define ESP_DMA_STAT_DONE 0x08
+#define ESP_DMA_STAT_SCSIINT 0x10
+#define ESP_DMA_STAT_BCMPLT 0x20
+
+/* EEPROM is accessed with 16-bit values */
+#define DC390_EEPROM_READ 0x80
+#define DC390_EEPROM_LEN 0x40
+
+/*
+ * DC390 EEPROM
+ *
+ * 8 * 4 bytes of per-device options
+ * followed by HBA specific options
+ */
+
+/* Per-device options */
+#define DC390_EE_MODE1 0x00
+#define DC390_EE_SPEED 0x01
+
+/* HBA-specific options */
+#define DC390_EE_ADAPT_SCSI_ID 0x40
+#define DC390_EE_MODE2 0x41
+#define DC390_EE_DELAY 0x42
+#define DC390_EE_TAG_CMD_NUM 0x43
+
+#define DC390_EE_MODE1_PARITY_CHK 0x01
+#define DC390_EE_MODE1_SYNC_NEGO 0x02
+#define DC390_EE_MODE1_EN_DISC 0x04
+#define DC390_EE_MODE1_SEND_START 0x08
+#define DC390_EE_MODE1_TCQ 0x10
+
+#define DC390_EE_MODE2_MORE_2DRV 0x01
+#define DC390_EE_MODE2_GREATER_1G 0x02
+#define DC390_EE_MODE2_RST_SCSI_BUS 0x04
+#define DC390_EE_MODE2_ACTIVE_NEGATION 0x08
+#define DC390_EE_MODE2_NO_SEEK 0x10
+#define DC390_EE_MODE2_LUN_CHECK 0x20
+
+struct pci_esp_priv {
+ struct esp *esp;
+ u8 dma_status;
+};
+
+static void pci_esp_dma_drain(struct esp *esp);
+
+static inline struct pci_esp_priv *pci_esp_get_priv(struct esp *esp)
+{
+ struct pci_dev *pdev = esp->dev;
+
+ return pci_get_drvdata(pdev);
+}
+
+static void pci_esp_write8(struct esp *esp, u8 val, unsigned long reg)
+{
+ iowrite8(val, esp->regs + (reg * 4UL));
+}
+
+static u8 pci_esp_read8(struct esp *esp, unsigned long reg)
+{
+ return ioread8(esp->regs + (reg * 4UL));
+}
+
+static void pci_esp_write32(struct esp *esp, u32 val, unsigned long reg)
+{
+ return iowrite32(val, esp->regs + (reg * 4UL));
+}
+
+static dma_addr_t pci_esp_map_single(struct esp *esp, void *buf,
+ size_t sz, int dir)
+{
+ return pci_map_single(esp->dev, buf, sz, dir);
+}
+
+static int pci_esp_map_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ return pci_map_sg(esp->dev, sg, num_sg, dir);
+}
+
+static void pci_esp_unmap_single(struct esp *esp, dma_addr_t addr,
+ size_t sz, int dir)
+{
+ pci_unmap_single(esp->dev, addr, sz, dir);
+}
+
+static void pci_esp_unmap_sg(struct esp *esp, struct scatterlist *sg,
+ int num_sg, int dir)
+{
+ pci_unmap_sg(esp->dev, sg, num_sg, dir);
+}
+
+static int pci_esp_irq_pending(struct esp *esp)
+{
+ struct pci_esp_priv *pep = pci_esp_get_priv(esp);
+
+ pep->dma_status = pci_esp_read8(esp, ESP_DMA_STATUS);
+ esp_dma_log("dma intr dreg[%02x]\n", pep->dma_status);
+
+ if (pep->dma_status & (ESP_DMA_STAT_ERROR |
+ ESP_DMA_STAT_ABORT |
+ ESP_DMA_STAT_DONE |
+ ESP_DMA_STAT_SCSIINT))
+ return 1;
+
+ return 0;
+}
+
+static void pci_esp_reset_dma(struct esp *esp)
+{
+ /* Nothing to do ? */
+}
+
+static void pci_esp_dma_drain(struct esp *esp)
+{
+ u8 resid;
+ int lim = 1000;
+
+
+ if ((esp->sreg & ESP_STAT_PMASK) == ESP_DOP ||
+ (esp->sreg & ESP_STAT_PMASK) == ESP_DIP)
+ /* Data-In or Data-Out, nothing to be done */
+ return;
+
+ while (--lim > 0) {
+ resid = pci_esp_read8(esp, ESP_FFLAGS) & ESP_FF_FBYTES;
+ if (resid <= 1)
+ break;
+ cpu_relax();
+ }
+ if (resid > 1) {
+ /* FIFO not cleared */
+ shost_printk(KERN_INFO, esp->host,
+ "FIFO not cleared, %d bytes left\n",
+ resid);
+ }
+
+ /*
+ * When there is a residual BCMPLT will never be set
+ * (obviously). But we still have to issue the BLAST
+ * command, otherwise the data will not being transferred.
+ * But we'll never know when the BLAST operation is
+ * finished. So check for some time and give up eventually.
+ */
+ lim = 1000;
+ pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_BLAST, ESP_DMA_CMD);
+ while (pci_esp_read8(esp, ESP_DMA_STATUS) & ESP_DMA_STAT_BCMPLT) {
+ if (--lim == 0)
+ break;
+ cpu_relax();
+ }
+ pci_esp_write8(esp, ESP_DMA_CMD_DIR | ESP_DMA_CMD_IDLE, ESP_DMA_CMD);
+ esp_dma_log("DMA blast done (%d tries, %d bytes left)\n", lim, resid);
+ /* BLAST residual handling is currently untested */
+ if (WARN_ON_ONCE(resid == 1)) {
+ struct esp_cmd_entry *ent = esp->active_cmd;
+
+ ent->flags |= ESP_CMD_FLAG_RESIDUAL;
+ }
+}
+
+static void pci_esp_dma_invalidate(struct esp *esp)
+{
+ struct pci_esp_priv *pep = pci_esp_get_priv(esp);
+
+ esp_dma_log("invalidate DMA\n");
+
+ pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD);
+ pep->dma_status = 0;
+}
+
+static int pci_esp_dma_error(struct esp *esp)
+{
+ struct pci_esp_priv *pep = pci_esp_get_priv(esp);
+
+ if (pep->dma_status & ESP_DMA_STAT_ERROR) {
+ u8 dma_cmd = pci_esp_read8(esp, ESP_DMA_CMD);
+
+ if ((dma_cmd & ESP_DMA_CMD_MASK) == ESP_DMA_CMD_START)
+ pci_esp_write8(esp, ESP_DMA_CMD_ABORT, ESP_DMA_CMD);
+
+ return 1;
+ }
+ if (pep->dma_status & ESP_DMA_STAT_ABORT) {
+ pci_esp_write8(esp, ESP_DMA_CMD_IDLE, ESP_DMA_CMD);
+ pep->dma_status = pci_esp_read8(esp, ESP_DMA_CMD);
+ return 1;
+ }
+ return 0;
+}
+
+static void pci_esp_send_dma_cmd(struct esp *esp, u32 addr, u32 esp_count,
+ u32 dma_count, int write, u8 cmd)
+{
+ struct pci_esp_priv *pep = pci_esp_get_priv(esp);
+ u32 val = 0;
+
+ BUG_ON(!(cmd & ESP_CMD_DMA));
+
+ pep->dma_status = 0;
+
+ /* Set DMA engine to IDLE */
+ if (write)
+ /* DMA write direction logic is inverted */
+ val |= ESP_DMA_CMD_DIR;
+ pci_esp_write8(esp, ESP_DMA_CMD_IDLE | val, ESP_DMA_CMD);
+
+ pci_esp_write8(esp, (esp_count >> 0) & 0xff, ESP_TCLOW);
+ pci_esp_write8(esp, (esp_count >> 8) & 0xff, ESP_TCMED);
+ if (esp->config2 & ESP_CONFIG2_FENAB)
+ pci_esp_write8(esp, (esp_count >> 16) & 0xff, ESP_TCHI);
+
+ pci_esp_write32(esp, esp_count, ESP_DMA_STC);
+ pci_esp_write32(esp, addr, ESP_DMA_SPA);
+
+ esp_dma_log("start dma addr[%x] count[%d:%d]\n",
+ addr, esp_count, dma_count);
+
+ scsi_esp_cmd(esp, cmd);
+ /* Send DMA Start command */
+ pci_esp_write8(esp, ESP_DMA_CMD_START | val, ESP_DMA_CMD);
+}
+
+static u32 pci_esp_dma_length_limit(struct esp *esp, u32 dma_addr, u32 dma_len)
+{
+ int dma_limit = 16;
+ u32 base, end;
+
+ /*
+ * If CONFIG2_FENAB is set we can
+ * handle up to 24 bit addresses
+ */
+ if (esp->config2 & ESP_CONFIG2_FENAB)
+ dma_limit = 24;
+
+ if (dma_len > (1U << dma_limit))
+ dma_len = (1U << dma_limit);
+
+ /*
+ * Prevent crossing a 24-bit address boundary.
+ */
+ base = dma_addr & ((1U << 24) - 1U);
+ end = base + dma_len;
+ if (end > (1U << 24))
+ end = (1U <<24);
+ dma_len = end - base;
+
+ return dma_len;
+}
+
+static const struct esp_driver_ops pci_esp_ops = {
+ .esp_write8 = pci_esp_write8,
+ .esp_read8 = pci_esp_read8,
+ .map_single = pci_esp_map_single,
+ .map_sg = pci_esp_map_sg,
+ .unmap_single = pci_esp_unmap_single,
+ .unmap_sg = pci_esp_unmap_sg,
+ .irq_pending = pci_esp_irq_pending,
+ .reset_dma = pci_esp_reset_dma,
+ .dma_drain = pci_esp_dma_drain,
+ .dma_invalidate = pci_esp_dma_invalidate,
+ .send_dma_cmd = pci_esp_send_dma_cmd,
+ .dma_error = pci_esp_dma_error,
+ .dma_length_limit = pci_esp_dma_length_limit,
+};
+
+/*
+ * Read DC-390 eeprom
+ */
+static void dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
+{
+ u8 carry_flag = 1, j = 0x80, bval;
+ int i;
+
+ for (i = 0; i < 9; i++) {
+ if (carry_flag) {
+ pci_write_config_byte(pdev, 0x80, 0x40);
+ bval = 0xc0;
+ } else
+ bval = 0x80;
+
+ udelay(160);
+ pci_write_config_byte(pdev, 0x80, bval);
+ udelay(160);
+ pci_write_config_byte(pdev, 0x80, 0);
+ udelay(160);
+
+ carry_flag = (cmd & j) ? 1 : 0;
+ j >>= 1;
+ }
+}
+
+static u16 dc390_eeprom_get_data(struct pci_dev *pdev)
+{
+ int i;
+ u16 wval = 0;
+ u8 bval;
+
+ for (i = 0; i < 16; i++) {
+ wval <<= 1;
+
+ pci_write_config_byte(pdev, 0x80, 0x80);
+ udelay(160);
+ pci_write_config_byte(pdev, 0x80, 0x40);
+ udelay(160);
+ pci_read_config_byte(pdev, 0x00, &bval);
+
+ if (bval == 0x22)
+ wval |= 1;
+ }
+
+ return wval;
+}
+
+static void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
+{
+ u8 cmd = DC390_EEPROM_READ, i;
+
+ for (i = 0; i < DC390_EEPROM_LEN; i++) {
+ pci_write_config_byte(pdev, 0xc0, 0);
+ udelay(160);
+
+ dc390_eeprom_prepare_read(pdev, cmd++);
+ *ptr++ = dc390_eeprom_get_data(pdev);
+
+ pci_write_config_byte(pdev, 0x80, 0);
+ pci_write_config_byte(pdev, 0x80, 0);
+ udelay(160);
+ }
+}
+
+static void dc390_check_eeprom(struct esp *esp)
+{
+ u8 EEbuf[128];
+ u16 *ptr = (u16 *)EEbuf, wval = 0;
+ int i;
+
+ dc390_read_eeprom((struct pci_dev *)esp->dev, ptr);
+
+ for (i = 0; i < DC390_EEPROM_LEN; i++, ptr++)
+ wval += *ptr;
+
+ /* no Tekram EEprom found */
+ if (wval != 0x1234) {
+ struct pci_dev *pdev = esp->dev;
+ dev_printk(KERN_INFO, &pdev->dev,
+ "No valid Tekram EEprom found\n");
+ return;
+ }
+ esp->scsi_id = EEbuf[DC390_EE_ADAPT_SCSI_ID];
+ esp->num_tags = 2 << EEbuf[DC390_EE_TAG_CMD_NUM];
+ if (EEbuf[DC390_EE_MODE2] & DC390_EE_MODE2_ACTIVE_NEGATION)
+ esp->config4 |= ESP_CONFIG4_RADE | ESP_CONFIG4_RAE;
+}
+
+static int pci_esp_probe_one(struct pci_dev *pdev,
+ const struct pci_device_id *id)
+{
+ struct scsi_host_template *hostt = &scsi_esp_template;
+ int err = -ENODEV;
+ struct Scsi_Host *shost;
+ struct esp *esp;
+ struct pci_esp_priv *pep;
+
+ if (pci_enable_device(pdev)) {
+ dev_printk(KERN_INFO, &pdev->dev, "cannot enable device\n");
+ return -ENODEV;
+ }
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "failed to set 32bit DMA mask\n");
+ goto fail_disable_device;
+ }
+
+ shost = scsi_host_alloc(hostt, sizeof(struct esp));
+ if (!shost) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "failed to allocate scsi host\n");
+ err = -ENOMEM;
+ goto fail_disable_device;
+ }
+
+ pep = kzalloc(sizeof(struct pci_esp_priv), GFP_KERNEL);
+ if (!pep) {
+ dev_printk(KERN_INFO, &pdev->dev,
+ "failed to allocate esp_priv\n");
+ err = -ENOMEM;
+ goto fail_host_alloc;
+ }
+
+ esp = shost_priv(shost);
+ esp->host = shost;
+ esp->dev = pdev;
+ esp->ops = &pci_esp_ops;
+ /*
+ * The am53c974 HBA has a design flaw of generating
+ * spurious DMA completion interrupts when using
+ * DMA for command submission.
+ */
+ esp->flags |= ESP_FLAG_USE_FIFO;
+ /*
+ * Enable CONFIG2_FENAB to allow for large DMA transfers
+ */
+ if (am53c974_fenab)
+ esp->config2 |= ESP_CONFIG2_FENAB;
+
+ pep->esp = esp;
+
+ if (pci_request_regions(pdev, DRV_MODULE_NAME)) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "pci memory selection failed\n");
+ goto fail_priv_alloc;
+ }
+
+ esp->regs = pci_iomap(pdev, 0, pci_resource_len(pdev, 0));
+ if (!esp->regs) {
+ dev_printk(KERN_ERR, &pdev->dev, "pci I/O map failed\n");
+ err = -EINVAL;
+ goto fail_release_regions;
+ }
+ esp->dma_regs = esp->regs;
+
+ pci_set_master(pdev);
+
+ esp->command_block = pci_alloc_consistent(pdev, 16,
+ &esp->command_block_dma);
+ if (!esp->command_block) {
+ dev_printk(KERN_ERR, &pdev->dev,
+ "failed to allocate command block\n");
+ err = -ENOMEM;
+ goto fail_unmap_regs;
+ }
+
+ err = request_irq(pdev->irq, scsi_esp_intr, IRQF_SHARED,
+ DRV_MODULE_NAME, esp);
+ if (err < 0) {
+ dev_printk(KERN_ERR, &pdev->dev, "failed to register IRQ\n");
+ goto fail_unmap_command_block;
+ }
+
+ esp->scsi_id = 7;
+ dc390_check_eeprom(esp);
+
+ shost->this_id = esp->scsi_id;
+ shost->max_id = 8;
+ shost->irq = pdev->irq;
+ shost->io_port = pci_resource_start(pdev, 0);
+ shost->n_io_port = pci_resource_len(pdev, 0);
+ shost->unique_id = shost->io_port;
+ esp->scsi_id_mask = (1 << esp->scsi_id);
+ /* Assume 40MHz clock */
+ esp->cfreq = 40000000;
+
+ pci_set_drvdata(pdev, pep);
+
+ err = scsi_esp_register(esp, &pdev->dev);
+ if (err)
+ goto fail_free_irq;
+
+ return 0;
+
+fail_free_irq:
+ free_irq(pdev->irq, esp);
+fail_unmap_command_block:
+ pci_free_consistent(pdev, 16, esp->command_block,
+ esp->command_block_dma);
+fail_unmap_regs:
+ pci_iounmap(pdev, esp->regs);
+fail_release_regions:
+ pci_release_regions(pdev);
+fail_priv_alloc:
+ kfree(pep);
+fail_host_alloc:
+ scsi_host_put(shost);
+fail_disable_device:
+ pci_disable_device(pdev);
+
+ return err;
+}
+
+static void pci_esp_remove_one(struct pci_dev *pdev)
+{
+ struct pci_esp_priv *pep = pci_get_drvdata(pdev);
+ struct esp *esp = pep->esp;
+
+ scsi_esp_unregister(esp);
+ free_irq(pdev->irq, esp);
+ pci_free_consistent(pdev, 16, esp->command_block,
+ esp->command_block_dma);
+ pci_iounmap(pdev, esp->regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+ kfree(pep);
+
+ scsi_host_put(esp->host);
+}
+
+static struct pci_device_id am53c974_pci_tbl[] = {
+ { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_SCSI,
+ PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(pci, am53c974_pci_tbl);
+
+static struct pci_driver am53c974_driver = {
+ .name = DRV_MODULE_NAME,
+ .id_table = am53c974_pci_tbl,
+ .probe = pci_esp_probe_one,
+ .remove = pci_esp_remove_one,
+};
+
+static int __init am53c974_module_init(void)
+{
+ return pci_register_driver(&am53c974_driver);
+}
+
+static void __exit am53c974_module_exit(void)
+{
+ pci_unregister_driver(&am53c974_driver);
+}
+
+MODULE_DESCRIPTION("AM53C974 SCSI driver");
+MODULE_AUTHOR("Hannes Reinecke <hare@suse.de>");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(DRV_MODULE_VERSION);
+MODULE_ALIAS("tmscsim");
+
+module_param(am53c974_debug, bool, 0644);
+MODULE_PARM_DESC(am53c974_debug, "Enable debugging");
+
+module_param(am53c974_fenab, bool, 0444);
+MODULE_PARM_DESC(am53c974_fenab, "Enable 24-bit DMA transfer sizes");
+
+module_init(am53c974_module_init);
+module_exit(am53c974_module_exit);
diff --git a/drivers/scsi/arcmsr/arcmsr_hba.c b/drivers/scsi/arcmsr/arcmsr_hba.c
index 0b44fb5..914c39f 100644
--- a/drivers/scsi/arcmsr/arcmsr_hba.c
+++ b/drivers/scsi/arcmsr/arcmsr_hba.c
@@ -114,16 +114,11 @@ static void arcmsr_hardware_reset(struct AdapterControlBlock *acb);
static const char *arcmsr_info(struct Scsi_Host *);
static irqreturn_t arcmsr_interrupt(struct AdapterControlBlock *acb);
static void arcmsr_free_irq(struct pci_dev *, struct AdapterControlBlock *);
-static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev,
- int queue_depth, int reason)
+static int arcmsr_adjust_disk_queue_depth(struct scsi_device *sdev, int queue_depth)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (queue_depth > ARCMSR_MAX_CMD_PERLUN)
queue_depth = ARCMSR_MAX_CMD_PERLUN;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
- return queue_depth;
+ return scsi_change_queue_depth(sdev, queue_depth);
}
static struct scsi_host_template arcmsr_scsi_host_template = {
diff --git a/drivers/scsi/arm/acornscsi.c b/drivers/scsi/arm/acornscsi.c
index d89b9b4..deaaf84 100644
--- a/drivers/scsi/arm/acornscsi.c
+++ b/drivers/scsi/arm/acornscsi.c
@@ -850,13 +850,13 @@ static void acornscsi_done(AS_Host *host, struct scsi_cmnd **SCpntp,
break;
default:
- printk(KERN_ERR "scsi%d.H: incomplete data transfer detected: result=%08X command=",
- host->host->host_no, SCpnt->result);
- __scsi_print_command(SCpnt->cmnd);
+ scmd_printk(KERN_ERR, SCpnt,
+ "incomplete data transfer detected: "
+ "result=%08X", SCpnt->result);
+ scsi_print_command(SCpnt);
acornscsi_dumpdma(host, "done");
- acornscsi_dumplog(host, SCpnt->device->id);
- SCpnt->result &= 0xffff;
- SCpnt->result |= DID_ERROR << 16;
+ acornscsi_dumplog(host, SCpnt->device->id);
+ set_host_byte(SCpnt, DID_ERROR);
}
}
}
diff --git a/drivers/scsi/arm/cumana_1.c b/drivers/scsi/arm/cumana_1.c
index 8ef810a..d28d6c0 100644
--- a/drivers/scsi/arm/cumana_1.c
+++ b/drivers/scsi/arm/cumana_1.c
@@ -13,16 +13,12 @@
#include <asm/ecard.h>
#include <asm/io.h>
-#include "../scsi.h"
#include <scsi/scsi_host.h>
#include <scsi/scsicam.h>
-#define AUTOSENSE
#define PSEUDO_DMA
-#define CUMANASCSI_PUBLIC_RELEASE 1
-
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
#define NCR5380_local_declare() struct Scsi_Host *_instance
#define NCR5380_setup(instance) _instance = instance
@@ -30,6 +26,7 @@
#define NCR5380_write(reg, value) cumanascsi_write(_instance, reg, value)
#define NCR5380_intr cumanascsi_intr
#define NCR5380_queue_command cumanascsi_queue_command
+#define NCR5380_info cumanascsi_info
#define NCR5380_implementation_fields \
unsigned ctrl; \
@@ -42,11 +39,6 @@ void cumanascsi_setup(char *str, int *ints)
{
}
-const char *cumanascsi_info(struct Scsi_Host *spnt)
-{
- return "";
-}
-
#define CTRL 0x16fc
#define STAT 0x2004
#define L(v) (((v)<<16)|((v) & 0x0000ffff))
@@ -267,14 +259,6 @@ static int cumanascsi1_probe(struct expansion_card *ec,
goto out_unmap;
}
- printk("scsi%d: at port 0x%08lx irq %d",
- host->host_no, host->io_port, host->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- host->can_queue, host->cmd_per_lun, CUMANASCSI_PUBLIC_RELEASE);
- printk("\nscsi%d:", host->host_no);
- NCR5380_print_options(host);
- printk("\n");
-
ret = scsi_add_host(host, &ec->dev);
if (ret)
goto out_free_irq;
diff --git a/drivers/scsi/arm/fas216.c b/drivers/scsi/arm/fas216.c
index 71cfb1e..e64c3af 100644
--- a/drivers/scsi/arm/fas216.c
+++ b/drivers/scsi/arm/fas216.c
@@ -308,8 +308,7 @@ static void fas216_log_command(FAS216_Info *info, int level,
fas216_do_log(info, '0' + SCpnt->device->id, fmt, args);
va_end(args);
- printk(" CDB: ");
- __scsi_print_command(SCpnt->cmnd);
+ scsi_print_command(SCpnt);
}
static void
@@ -2079,14 +2078,12 @@ fas216_std_done(FAS216_Info *info, struct scsi_cmnd *SCpnt, unsigned int result)
break;
default:
- printk(KERN_ERR "scsi%d.%c: incomplete data transfer "
- "detected: res=%08X ptr=%p len=%X CDB: ",
- info->host->host_no, '0' + SCpnt->device->id,
- SCpnt->result, info->scsi.SCp.ptr,
- info->scsi.SCp.this_residual);
- __scsi_print_command(SCpnt->cmnd);
- SCpnt->result &= ~(255 << 16);
- SCpnt->result |= DID_BAD_TARGET << 16;
+ scmd_printk(KERN_ERR, SCpnt,
+ "incomplete data transfer detected: res=%08X ptr=%p len=%X\n",
+ SCpnt->result, info->scsi.SCp.ptr,
+ info->scsi.SCp.this_residual);
+ scsi_print_command(SCpnt);
+ set_host_byte(SCpnt, DID_ERROR);
goto request_sense;
}
}
@@ -2158,12 +2155,11 @@ static void fas216_done(FAS216_Info *info, unsigned int result)
* to transfer, we should not have a valid pointer.
*/
if (info->scsi.SCp.ptr && info->scsi.SCp.this_residual == 0) {
- printk("scsi%d.%c: zero bytes left to transfer, but "
- "buffer pointer still valid: ptr=%p len=%08x CDB: ",
- info->host->host_no, '0' + SCpnt->device->id,
- info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
+ scmd_printk(KERN_INFO, SCpnt,
+ "zero bytes left to transfer, but buffer pointer still valid: ptr=%p len=%08x\n",
+ info->scsi.SCp.ptr, info->scsi.SCp.this_residual);
info->scsi.SCp.ptr = NULL;
- __scsi_print_command(SCpnt->cmnd);
+ scsi_print_command(SCpnt);
}
/*
@@ -2427,14 +2423,11 @@ int fas216_eh_abort(struct scsi_cmnd *SCpnt)
info->stats.aborts += 1;
- printk(KERN_WARNING "scsi%d: abort command ", info->host->host_no);
- __scsi_print_command(SCpnt->cmnd);
+ scmd_printk(KERN_WARNING, SCpnt, "abort command\n");
print_debug_list();
fas216_dumpstate(info);
- printk(KERN_WARNING "scsi%d: abort %p ", info->host->host_no, SCpnt);
-
switch (fas216_find_command(info, SCpnt)) {
/*
* We found the command, and cleared it out. Either
@@ -2442,7 +2435,7 @@ int fas216_eh_abort(struct scsi_cmnd *SCpnt)
* target, or the busylun bit is not set.
*/
case res_success:
- printk("success\n");
+ scmd_printk(KERN_WARNING, SCpnt, "abort %p success\n", SCpnt);
result = SUCCESS;
break;
@@ -2452,14 +2445,13 @@ int fas216_eh_abort(struct scsi_cmnd *SCpnt)
* if the bus is free.
*/
case res_hw_abort:
-
/*
* We are unable to abort the command for some reason.
*/
default:
case res_failed:
- printk("failed\n");
+ scmd_printk(KERN_WARNING, SCpnt, "abort %p failed\n", SCpnt);
break;
}
@@ -2664,8 +2656,7 @@ int fas216_eh_host_reset(struct scsi_cmnd *SCpnt)
fas216_checkmagic(info);
- printk("scsi%d.%c: %s: resetting host\n",
- info->host->host_no, '0' + SCpnt->device->id, __func__);
+ fas216_log(info, LOG_ERROR, "resetting host");
/*
* Reset the SCSI chip.
diff --git a/drivers/scsi/arm/oak.c b/drivers/scsi/arm/oak.c
index 188e734..7c6fa14 100644
--- a/drivers/scsi/arm/oak.c
+++ b/drivers/scsi/arm/oak.c
@@ -14,13 +14,9 @@
#include <asm/ecard.h>
#include <asm/io.h>
-#include "../scsi.h"
#include <scsi/scsi_host.h>
-#define AUTOSENSE
/*#define PSEUDO_DMA*/
-
-#define OAKSCSI_PUBLIC_RELEASE 1
#define DONT_USE_INTR
#define priv(host) ((struct NCR5380_hostdata *)(host)->hostdata)
@@ -29,10 +25,9 @@
#define NCR5380_read(reg) readb(_base + ((reg) << 2))
#define NCR5380_write(reg, value) writeb(value, _base + ((reg) << 2))
-#define NCR5380_intr oakscsi_intr
#define NCR5380_queue_command oakscsi_queue_command
+#define NCR5380_info oakscsi_info
#define NCR5380_show_info oakscsi_show_info
-#define NCR5380_write_info oakscsi_write_info
#define NCR5380_implementation_fields \
void __iomem *base
@@ -42,11 +37,6 @@
#undef START_DMA_INITIATOR_RECEIVE_REG
#define START_DMA_INITIATOR_RECEIVE_REG (128 + 7)
-const char * oakscsi_info (struct Scsi_Host *spnt)
-{
- return "";
-}
-
#define STAT ((128 + 16) << 2)
#define DATA ((128 + 8) << 2)
@@ -114,7 +104,6 @@ printk("reading %p len %d\n", addr, len);
static struct scsi_host_template oakscsi_template = {
.module = THIS_MODULE,
.show_info = oakscsi_show_info,
- .write_info = oakscsi_write_info,
.name = "Oak 16-bit SCSI",
.info = oakscsi_info,
.queuecommand = oakscsi_queue_command,
@@ -150,19 +139,11 @@ static int oakscsi_probe(struct expansion_card *ec, const struct ecard_id *id)
goto unreg;
}
- host->irq = IRQ_NONE;
+ host->irq = NO_IRQ;
host->n_io_port = 255;
NCR5380_init(host, 0);
- printk("scsi%d: at port 0x%08lx irqs disabled",
- host->host_no, host->io_port);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- host->can_queue, host->cmd_per_lun, OAKSCSI_PUBLIC_RELEASE);
- printk("\nscsi%d:", host->host_no);
- NCR5380_print_options(host);
- printk("\n");
-
ret = scsi_add_host(host, &ec->dev);
if (ret)
goto out_unmap;
diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c
index 79e6f04..6daed6b 100644
--- a/drivers/scsi/atari_NCR5380.c
+++ b/drivers/scsi/atari_NCR5380.c
@@ -11,8 +11,6 @@
* drew@colorado.edu
* +1 (303) 666-5836
*
- * DISTRIBUTION RELEASE 6.
- *
* For more information, please consult
*
* NCR 5380 Family
@@ -73,6 +71,9 @@
* 1. Test linked command handling code after Eric is ready with
* the high level code.
*/
+
+/* Adapted for the sun3 by Sam Creasey. */
+
#include <scsi/scsi_dbg.h>
#include <scsi/scsi_transport_spi.h>
@@ -103,27 +104,7 @@
/*
* Design
- * Issues :
- *
- * The other Linux SCSI drivers were written when Linux was Intel PC-only,
- * and specifically for each board rather than each chip. This makes their
- * adaptation to platforms like the Mac (Some of which use NCR5380's)
- * more difficult than it has to be.
*
- * Also, many of the SCSI drivers were written before the command queuing
- * routines were implemented, meaning their implementations of queued
- * commands were hacked on rather than designed in from the start.
- *
- * When I designed the Linux SCSI drivers I figured that
- * while having two different SCSI boards in a system might be useful
- * for debugging things, two of the same type wouldn't be used.
- * Well, I was wrong and a number of users have mailed me about running
- * multiple high-performance SCSI boards in a server.
- *
- * Finally, when I get questions from users, I have no idea what
- * revision of my driver they are running.
- *
- * This driver attempts to address these problems :
* This is a generic 5380 driver. To use it on a different platform,
* one simply writes appropriate system specific macros (ie, data
* transfer - some PC's will use the I/O bus, 68K's must use
@@ -138,17 +119,6 @@
* allowing multiple commands to propagate all the way to a SCSI-II device
* while a command is already executing.
*
- * To solve the multiple-boards-in-the-same-system problem,
- * there is a separate instance structure for each instance
- * of a 5380 in the system. So, multiple NCR5380 drivers will
- * be able to coexist with appropriate changes to the high level
- * SCSI code.
- *
- * A NCR5380_PUBLIC_REVISION macro is provided, with the release
- * number (updated for each public release) printed by the
- * NCR5380_print_options command, which should be called from the
- * wrapper detect function, so that I know what release of the driver
- * users are using.
*
* Issues specific to the NCR5380 :
*
@@ -173,19 +143,17 @@
* Architecture :
*
* At the heart of the design is a coroutine, NCR5380_main,
- * which is started when not running by the interrupt handler,
- * timer, and queue command function. It attempts to establish
- * I_T_L or I_T_L_Q nexuses by removing the commands from the
- * issue queue and calling NCR5380_select() if a nexus
- * is not established.
+ * which is started from a workqueue for each NCR5380 host in the
+ * system. It attempts to establish I_T_L or I_T_L_Q nexuses by
+ * removing the commands from the issue queue and calling
+ * NCR5380_select() if a nexus is not established.
*
* Once a nexus is established, the NCR5380_information_transfer()
* phase goes through the various phases as instructed by the target.
* if the target goes into MSG IN and sends a DISCONNECT message,
* the command structure is placed into the per instance disconnected
- * queue, and NCR5380_main tries to find more work. If USLEEP
- * was defined, and the target is idle for too long, the system
- * will try to sleep.
+ * queue, and NCR5380_main tries to find more work. If the target is
+ * idle for too long, the system will try to sleep.
*
* If a command has disconnected, eventually an interrupt will trigger,
* calling NCR5380_intr() which will in turn call NCR5380_reselect
@@ -211,6 +179,9 @@
* AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
* for commands that return with a CHECK CONDITION status.
*
+ * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
+ * transceivers.
+ *
* LINKED - if defined, linked commands are supported.
*
* REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
@@ -223,6 +194,9 @@
*
* NCR5380_write(register, value) - write to the specific register
*
+ * NCR5380_implementation_fields - additional fields needed for this
+ * specific implementation of the NCR5380
+ *
* Either real DMA *or* pseudo DMA may be implemented
* REAL functions :
* NCR5380_REAL_DMA should be defined if real DMA is to be used.
@@ -241,40 +215,21 @@
* NCR5380_pwrite(instance, src, count)
* NCR5380_pread(instance, dst, count);
*
- * If nothing specific to this implementation needs doing (ie, with external
- * hardware), you must also define
- *
- * NCR5380_queue_command
- * NCR5380_reset
- * NCR5380_abort
- * NCR5380_proc_info
- *
- * to be the global entry points into the specific driver, ie
- * #define NCR5380_queue_command t128_queue_command.
- *
- * If this is not done, the routines will be defined as static functions
- * with the NCR5380* names and the user must provide a globally
- * accessible wrapper function.
- *
* The generic driver is initialized by calling NCR5380_init(instance),
* after setting the appropriate host specific fields and ID. If the
* driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
- * possible) function may be used. Before the specific driver initialization
- * code finishes, NCR5380_print_options should be called.
+ * possible) function may be used.
*/
-static struct Scsi_Host *first_instance = NULL;
-static struct scsi_host_template *the_template = NULL;
-
/* Macros ease life... :-) */
#define SETUP_HOSTDATA(in) \
struct NCR5380_hostdata *hostdata = \
(struct NCR5380_hostdata *)(in)->hostdata
#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-#define NEXT(cmd) ((Scsi_Cmnd *)(cmd)->host_scribble)
+#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble)
#define SET_NEXT(cmd,next) ((cmd)->host_scribble = (void *)(next))
-#define NEXTADDR(cmd) ((Scsi_Cmnd **)&(cmd)->host_scribble)
+#define NEXTADDR(cmd) ((struct scsi_cmnd **)&(cmd)->host_scribble)
#define HOSTNO instance->host_no
#define H_NO(cmd) (cmd)->device->host->host_no
@@ -316,30 +271,17 @@ static struct scsi_host_template *the_template = NULL;
* important: the tag bit must be cleared before 'nr_allocated' is decreased.
*/
-/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
-#undef TAG_NONE
-#define TAG_NONE 0xff
-
-typedef struct {
- DECLARE_BITMAP(allocated, MAX_TAGS);
- int nr_allocated;
- int queue_size;
-} TAG_ALLOC;
-
-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
-
-
-static void __init init_tags(void)
+static void __init init_tags(struct NCR5380_hostdata *hostdata)
{
int target, lun;
- TAG_ALLOC *ta;
+ struct tag_alloc *ta;
- if (!setup_use_tagged_queuing)
+ if (!(hostdata->flags & FLAG_TAGGED_QUEUING))
return;
for (target = 0; target < 8; ++target) {
for (lun = 0; lun < 8; ++lun) {
- ta = &TagAlloc[target][lun];
+ ta = &hostdata->TagAlloc[target][lun];
bitmap_zero(ta->allocated, MAX_TAGS);
ta->nr_allocated = 0;
/* At the beginning, assume the maximum queue size we could
@@ -359,7 +301,7 @@ static void __init init_tags(void)
* conditions.
*/
-static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
+static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
{
u8 lun = cmd->device->lun;
SETUP_HOSTDATA(cmd->device->host);
@@ -367,10 +309,11 @@ static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
if (hostdata->busy[cmd->device->id] & (1 << lun))
return 1;
if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported)
+ !(hostdata->flags & FLAG_TAGGED_QUEUING) ||
+ !cmd->device->tagged_supported)
return 0;
- if (TagAlloc[cmd->device->id][lun].nr_allocated >=
- TagAlloc[cmd->device->id][lun].queue_size) {
+ if (hostdata->TagAlloc[scmd_id(cmd)][lun].nr_allocated >=
+ hostdata->TagAlloc[scmd_id(cmd)][lun].queue_size) {
dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d: no free tags\n",
H_NO(cmd), cmd->device->id, lun);
return 1;
@@ -384,7 +327,7 @@ static int is_lun_busy(Scsi_Cmnd *cmd, int should_be_tagged)
* untagged.
*/
-static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged)
+static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
{
u8 lun = cmd->device->lun;
SETUP_HOSTDATA(cmd->device->host);
@@ -393,13 +336,14 @@ static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged)
* an untagged command.
*/
if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
+ !(hostdata->flags & FLAG_TAGGED_QUEUING) ||
+ !cmd->device->tagged_supported) {
cmd->tag = TAG_NONE;
hostdata->busy[cmd->device->id] |= (1 << lun);
dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d now allocated by untagged "
"command\n", H_NO(cmd), cmd->device->id, lun);
} else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][lun];
+ struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
cmd->tag = find_first_zero_bit(ta->allocated, MAX_TAGS);
set_bit(cmd->tag, ta->allocated);
@@ -416,7 +360,7 @@ static void cmd_get_tag(Scsi_Cmnd *cmd, int should_be_tagged)
* unlock the LUN.
*/
-static void cmd_free_tag(Scsi_Cmnd *cmd)
+static void cmd_free_tag(struct scsi_cmnd *cmd)
{
u8 lun = cmd->device->lun;
SETUP_HOSTDATA(cmd->device->host);
@@ -429,7 +373,7 @@ static void cmd_free_tag(Scsi_Cmnd *cmd)
printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
H_NO(cmd), cmd->tag);
} else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][lun];
+ struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][lun];
clear_bit(cmd->tag, ta->allocated);
ta->nr_allocated--;
dprintk(NDEBUG_TAGS, "scsi%d: freed tag %d for target %d lun %d\n",
@@ -438,17 +382,17 @@ static void cmd_free_tag(Scsi_Cmnd *cmd)
}
-static void free_all_tags(void)
+static void free_all_tags(struct NCR5380_hostdata *hostdata)
{
int target, lun;
- TAG_ALLOC *ta;
+ struct tag_alloc *ta;
- if (!setup_use_tagged_queuing)
+ if (!(hostdata->flags & FLAG_TAGGED_QUEUING))
return;
for (target = 0; target < 8; ++target) {
for (lun = 0; lun < 8; ++lun) {
- ta = &TagAlloc[target][lun];
+ ta = &hostdata->TagAlloc[target][lun];
bitmap_zero(ta->allocated, MAX_TAGS);
ta->nr_allocated = 0;
}
@@ -459,19 +403,20 @@ static void free_all_tags(void)
/*
- * Function: void merge_contiguous_buffers( Scsi_Cmnd *cmd )
+ * Function: void merge_contiguous_buffers( struct scsi_cmnd *cmd )
*
* Purpose: Try to merge several scatter-gather requests into one DMA
* transfer. This is possible if the scatter buffers lie on
* physical contiguous addresses.
*
- * Parameters: Scsi_Cmnd *cmd
+ * Parameters: struct scsi_cmnd *cmd
* The command to work on. The first scatter buffer's data are
* assumed to be already transferred into ptr/this_residual.
*/
-static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
+static void merge_contiguous_buffers(struct scsi_cmnd *cmd)
{
+#if !defined(CONFIG_SUN3)
unsigned long endaddr;
#if (NDEBUG & NDEBUG_MERGING)
unsigned long oldlen = cmd->SCp.this_residual;
@@ -496,18 +441,17 @@ static void merge_contiguous_buffers(Scsi_Cmnd *cmd)
dprintk(NDEBUG_MERGING, "merged %d buffers from %p, new length %08x\n",
cnt, cmd->SCp.ptr, cmd->SCp.this_residual);
#endif
+#endif /* !defined(CONFIG_SUN3) */
}
-/*
- * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+/**
+ * initialize_SCp - init the scsi pointer field
+ * @cmd: command block to set up
*
- * Purpose : initialize the saved data pointers for cmd to point to the
- * start of the buffer.
- *
- * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ * Set up the internal fields in the SCSI command.
*/
-static inline void initialize_SCp(Scsi_Cmnd *cmd)
+static inline void initialize_SCp(struct scsi_cmnd *cmd)
{
/*
* Initialize the Scsi Pointer field so that all of the commands in the
@@ -557,12 +501,11 @@ static struct {
{0, NULL}
};
-/*
- * Function : void NCR5380_print(struct Scsi_Host *instance)
+/**
+ * NCR5380_print - print scsi bus signals
+ * @instance: adapter state to dump
*
- * Purpose : print the SCSI bus signals for debugging purposes
- *
- * Input : instance - which NCR5380
+ * Print the SCSI bus signals for debugging purposes
*/
static void NCR5380_print(struct Scsi_Host *instance)
@@ -605,12 +548,13 @@ static struct {
{PHASE_UNKNOWN, "UNKNOWN"}
};
-/*
- * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+/**
+ * NCR5380_print_phase - show SCSI phase
+ * @instance: adapter to dump
*
- * Purpose : print the current SCSI phase for debugging purposes
+ * Print the current SCSI phase for debugging purposes
*
- * Input : instance - which NCR5380
+ * Locks: none
*/
static void NCR5380_print_phase(struct Scsi_Host *instance)
@@ -648,71 +592,75 @@ static void NCR5380_print_phase(struct Scsi_Host *instance)
#include <linux/workqueue.h>
#include <linux/interrupt.h>
-static volatile int main_running;
-static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
-
-static inline void queue_main(void)
+static inline void queue_main(struct NCR5380_hostdata *hostdata)
{
- if (!main_running) {
+ if (!hostdata->main_running) {
/* If in interrupt and NCR5380_main() not already running,
queue it on the 'immediate' task queue, to be processed
immediately after the current interrupt processing has
finished. */
- schedule_work(&NCR5380_tqueue);
+ schedule_work(&hostdata->main_task);
}
/* else: nothing to do: the running NCR5380_main() will pick up
any newly queued command. */
}
-
-static inline void NCR5380_all_init(void)
-{
- static int done = 0;
- if (!done) {
- dprintk(NDEBUG_INIT, "scsi : NCR5380_all_init()\n");
- done = 1;
- }
-}
-
-
-/*
- * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+/**
+ * NCR58380_info - report driver and host information
+ * @instance: relevant scsi host instance
*
- * Purpose : called by probe code indicating the NCR5380 driver
- * options that were selected.
+ * For use as the host template info() handler.
*
- * Inputs : instance, pointer to this instance. Unused.
+ * Locks: none
*/
-static void __init NCR5380_print_options(struct Scsi_Host *instance)
+static const char *NCR5380_info(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ return hostdata->info;
+}
+
+static void prepare_info(struct Scsi_Host *instance)
{
- printk(" generic options"
-#ifdef AUTOSENSE
- " AUTOSENSE"
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ snprintf(hostdata->info, sizeof(hostdata->info),
+ "%s, io_port 0x%lx, n_io_port %d, "
+ "base 0x%lx, irq %d, "
+ "can_queue %d, cmd_per_lun %d, "
+ "sg_tablesize %d, this_id %d, "
+ "flags { %s}, "
+ "options { %s} ",
+ instance->hostt->name, instance->io_port, instance->n_io_port,
+ instance->base, instance->irq,
+ instance->can_queue, instance->cmd_per_lun,
+ instance->sg_tablesize, instance->this_id,
+ hostdata->flags & FLAG_TAGGED_QUEUING ? "TAGGED_QUEUING " : "",
+#ifdef DIFFERENTIAL
+ "DIFFERENTIAL "
#endif
#ifdef REAL_DMA
- " REAL DMA"
+ "REAL_DMA "
#endif
#ifdef PARITY
- " PARITY"
+ "PARITY "
#endif
#ifdef SUPPORT_TAGS
- " SCSI-2 TAGGED QUEUING"
+ "SUPPORT_TAGS "
#endif
- );
- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+ "");
}
-/*
- * Function : void NCR5380_print_status (struct Scsi_Host *instance)
+/**
+ * NCR5380_print_status - dump controller info
+ * @instance: controller to dump
*
- * Purpose : print commands in the various queues, called from
- * NCR5380_abort and NCR5380_debug to aid debugging.
- *
- * Inputs : instance, pointer to this instance.
+ * Print commands in the various queues, called from NCR5380_abort
+ * to aid debugging.
*/
-static void lprint_Scsi_Cmnd(Scsi_Cmnd *cmd)
+static void lprint_Scsi_Cmnd(struct scsi_cmnd *cmd)
{
int i, s;
unsigned char *command;
@@ -729,7 +677,7 @@ static void lprint_Scsi_Cmnd(Scsi_Cmnd *cmd)
static void NCR5380_print_status(struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
+ struct scsi_cmnd *ptr;
unsigned long flags;
NCR5380_dprint(NDEBUG_ANY, instance);
@@ -737,20 +685,19 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
- printk("\nNCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
local_irq_save(flags);
printk("NCR5380: coroutine is%s running.\n",
- main_running ? "" : "n't");
+ hostdata->main_running ? "" : "n't");
if (!hostdata->connected)
printk("scsi%d: no currently connected command\n", HOSTNO);
else
- lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected);
+ lprint_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected);
printk("scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+ for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
lprint_Scsi_Cmnd(ptr);
printk("scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
ptr = NEXT(ptr))
lprint_Scsi_Cmnd(ptr);
@@ -758,7 +705,7 @@ static void NCR5380_print_status(struct Scsi_Host *instance)
printk("\n");
}
-static void show_Scsi_Cmnd(Scsi_Cmnd *cmd, struct seq_file *m)
+static void show_Scsi_Cmnd(struct scsi_cmnd *cmd, struct seq_file *m)
{
int i, s;
unsigned char *command;
@@ -772,28 +719,28 @@ static void show_Scsi_Cmnd(Scsi_Cmnd *cmd, struct seq_file *m)
seq_printf(m, "\n");
}
-static int NCR5380_show_info(struct seq_file *m, struct Scsi_Host *instance)
+static int __maybe_unused NCR5380_show_info(struct seq_file *m,
+ struct Scsi_Host *instance)
{
struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
+ struct scsi_cmnd *ptr;
unsigned long flags;
hostdata = (struct NCR5380_hostdata *)instance->hostdata;
- seq_printf(m, "NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
local_irq_save(flags);
seq_printf(m, "NCR5380: coroutine is%s running.\n",
- main_running ? "" : "n't");
+ hostdata->main_running ? "" : "n't");
if (!hostdata->connected)
seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
else
- show_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
+ show_Scsi_Cmnd((struct scsi_cmnd *) hostdata->connected, m);
seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
+ for (ptr = (struct scsi_cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
show_Scsi_Cmnd(ptr, m);
seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
+ for (ptr = (struct scsi_cmnd *) hostdata->disconnected_queue; ptr;
ptr = NEXT(ptr))
show_Scsi_Cmnd(ptr, m);
@@ -801,16 +748,18 @@ static int NCR5380_show_info(struct seq_file *m, struct Scsi_Host *instance)
return 0;
}
-/*
- * Function : void NCR5380_init (struct Scsi_Host *instance)
+/**
+ * NCR5380_init - initialise an NCR5380
+ * @instance: adapter to configure
+ * @flags: control flags
*
- * Purpose : initializes *instance and corresponding 5380 chip.
- *
- * Inputs : instance - instantiation of the 5380 driver.
+ * Initializes *instance and corresponding 5380 chip,
+ * with flags OR'd into the initial flags value.
*
* Notes : I assume that the host, hostno, and id bits have been
- * set correctly. I don't care about the irq and other fields.
+ * set correctly. I don't care about the irq and other fields.
*
+ * Returns 0 for success
*/
static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
@@ -818,8 +767,7 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
int i;
SETUP_HOSTDATA(instance);
- NCR5380_all_init();
-
+ hostdata->host = instance;
hostdata->aborted = 0;
hostdata->id_mask = 1 << instance->this_id;
hostdata->id_higher_mask = 0;
@@ -829,7 +777,7 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
for (i = 0; i < 8; ++i)
hostdata->busy[i] = 0;
#ifdef SUPPORT_TAGS
- init_tags();
+ init_tags(hostdata);
#endif
#if defined (REAL_DMA)
hostdata->dma_len = 0;
@@ -838,19 +786,11 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
hostdata->connected = NULL;
hostdata->issue_queue = NULL;
hostdata->disconnected_queue = NULL;
- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
+ hostdata->flags = flags;
- if (!the_template) {
- the_template = instance->hostt;
- first_instance = instance;
- }
+ INIT_WORK(&hostdata->main_task, NCR5380_main);
-#ifndef AUTOSENSE
- if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
- printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
- " without AUTOSENSE option, contingent allegiance conditions may\n"
- " be incorrectly cleared.\n", HOSTNO);
-#endif /* def AUTOSENSE */
+ prepare_info(instance);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
NCR5380_write(MODE_REG, MR_BASE);
@@ -860,33 +800,35 @@ static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
return 0;
}
+/**
+ * NCR5380_exit - remove an NCR5380
+ * @instance: adapter to remove
+ *
+ * Assumes that no more work can be queued (e.g. by NCR5380_intr).
+ */
+
static void NCR5380_exit(struct Scsi_Host *instance)
{
- /* Empty, as we didn't schedule any delayed work */
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ cancel_work_sync(&hostdata->main_task);
}
-/*
- * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
- * void (*done)(Scsi_Cmnd *))
- *
- * Purpose : enqueues a SCSI command
- *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
- *
- * Returns : 0
- *
- * Side effects :
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
- * main coroutine is not running, it is restarted.
+/**
+ * NCR5380_queue_command - queue a command
+ * @instance: the relevant SCSI adapter
+ * @cmd: SCSI command
*
+ * cmd is added to the per instance issue_queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
*/
-static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
+static int NCR5380_queue_command(struct Scsi_Host *instance,
+ struct scsi_cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
- Scsi_Cmnd *tmp;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ struct scsi_cmnd *tmp;
unsigned long flags;
#if (NDEBUG & NDEBUG_NO_WRITE)
@@ -896,47 +838,17 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
H_NO(cmd));
cmd->result = (DID_ERROR << 16);
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-#ifdef NCR5380_STATS
-# if 0
- if (!hostdata->connected && !hostdata->issue_queue &&
- !hostdata->disconnected_queue) {
- hostdata->timebase = jiffies;
- }
-# endif
-# ifdef NCR5380_STAT_LIMIT
- if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
-# endif
- switch (cmd->cmnd[0]) {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
- hostdata->pendingw++;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
- hostdata->pendingr++;
- break;
- }
-#endif
-
/*
* We use the host_scribble field as a pointer to the next command
* in a queue
*/
SET_NEXT(cmd, NULL);
- cmd->scsi_done = done;
-
cmd->result = 0;
/*
@@ -946,7 +858,6 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* sense data is only guaranteed to be valid while the condition exists.
*/
- local_irq_save(flags);
/* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
* Otherwise a running NCR5380_main may steal the lock.
* Lock before actually inserting due to fairness reasons explained in
@@ -959,17 +870,24 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* because also a timer int can trigger an abort or reset, which would
* alter queues and touch the lock.
*/
- if (!IS_A_TT()) {
- /* perhaps stop command timer here */
- falcon_get_lock();
- /* perhaps restart command timer here */
- }
+ if (!NCR5380_acquire_dma_irq(instance))
+ return SCSI_MLQUEUE_HOST_BUSY;
+
+ local_irq_save(flags);
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ * commands are added to the head of the queue since any command will
+ * clear the contingent allegiance condition that exists and the
+ * sense data is only guaranteed to be valid while the condition exists.
+ */
+
if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
LIST(cmd, hostdata->issue_queue);
SET_NEXT(cmd, hostdata->issue_queue);
hostdata->issue_queue = cmd;
} else {
- for (tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
NEXT(tmp); tmp = NEXT(tmp))
;
LIST(cmd, tmp);
@@ -987,32 +905,42 @@ static int NCR5380_queue_command_lck(Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *))
* If we're not in an interrupt, we can call NCR5380_main()
* unconditionally, because it cannot be already running.
*/
- if (in_interrupt() || ((flags >> 8) & 7) >= 6)
- queue_main();
+ if (in_interrupt() || irqs_disabled())
+ queue_main(hostdata);
else
- NCR5380_main(NULL);
+ NCR5380_main(&hostdata->main_task);
return 0;
}
-static DEF_SCSI_QCMD(NCR5380_queue_command)
+static inline void maybe_release_dma_irq(struct Scsi_Host *instance)
+{
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ /* Caller does the locking needed to set & test these data atomically */
+ if (!hostdata->disconnected_queue &&
+ !hostdata->issue_queue &&
+ !hostdata->connected &&
+ !hostdata->retain_dma_intr)
+ NCR5380_release_dma_irq(instance);
+}
-/*
- * Function : NCR5380_main (void)
+/**
+ * NCR5380_main - NCR state machines
*
- * Purpose : NCR5380_main is a coroutine that runs as long as more work can
- * be done on the NCR5380 host adapters in a system. Both
- * NCR5380_queue_command() and NCR5380_intr() will try to start it
- * in case it is not running.
+ * NCR5380_main is a coroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
*
- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
- * reenable them. This prevents reentrancy and kernel stack overflow.
+ * Locks: called as its own thread with no locks held.
*/
static void NCR5380_main(struct work_struct *work)
{
- Scsi_Cmnd *tmp, *prev;
- struct Scsi_Host *instance = first_instance;
- struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
+ struct NCR5380_hostdata *hostdata =
+ container_of(work, struct NCR5380_hostdata, main_task);
+ struct Scsi_Host *instance = hostdata->host;
+ struct scsi_cmnd *tmp, *prev;
int done;
unsigned long flags;
@@ -1037,9 +965,9 @@ static void NCR5380_main(struct work_struct *work)
'main_running' is set here, and queues/executes main via the
task queue, it doesn't do any harm, just this instance of main
won't find any work left to do. */
- if (main_running)
+ if (hostdata->main_running)
return;
- main_running = 1;
+ hostdata->main_running = 1;
local_save_flags(flags);
do {
@@ -1053,7 +981,7 @@ static void NCR5380_main(struct work_struct *work)
* for a target that's not busy.
*/
#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue, prev = NULL;
+ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
;
/*printk("%p ", tmp);*/
@@ -1061,16 +989,14 @@ static void NCR5380_main(struct work_struct *work)
printk(" LOOP\n");
/* else printk("\n"); */
#endif
- for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp)) {
u8 lun = tmp->device->lun;
-#if (NDEBUG & NDEBUG_LISTS)
- if (prev != tmp)
- printk("MAIN tmp=%p target=%d busy=%d lun=%llu\n",
- tmp, tmp->device->id, hostdata->busy[tmp->device->id],
- lun);
-#endif
+ dprintk(NDEBUG_LISTS,
+ "MAIN tmp=%p target=%d busy=%d lun=%d\n",
+ tmp, scmd_id(tmp), hostdata->busy[scmd_id(tmp)],
+ lun);
/* When we find one, remove it from the issue queue. */
/* ++guenther: possible race with Falcon locking */
if (
@@ -1090,7 +1016,7 @@ static void NCR5380_main(struct work_struct *work)
hostdata->issue_queue = NEXT(tmp);
}
SET_NEXT(tmp, NULL);
- falcon_dont_release++;
+ hostdata->retain_dma_intr++;
/* reenable interrupts after finding one */
local_irq_restore(flags);
@@ -1117,12 +1043,12 @@ static void NCR5380_main(struct work_struct *work)
#ifdef SUPPORT_TAGS
cmd_get_tag(tmp, tmp->cmnd[0] != REQUEST_SENSE);
#endif
- if (!NCR5380_select(instance, tmp,
- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
- TAG_NEXT)) {
- falcon_dont_release--;
+ if (!NCR5380_select(instance, tmp)) {
+ local_irq_disable();
+ hostdata->retain_dma_intr--;
/* release if target did not response! */
- falcon_release_lock_if_possible(hostdata);
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
break;
} else {
local_irq_disable();
@@ -1132,7 +1058,7 @@ static void NCR5380_main(struct work_struct *work)
#ifdef SUPPORT_TAGS
cmd_free_tag(tmp);
#endif
- falcon_dont_release--;
+ hostdata->retain_dma_intr--;
local_irq_restore(flags);
dprintk(NDEBUG_MAIN, "scsi%d: main(): select() failed, "
"returned to issue_queue\n", HOSTNO);
@@ -1160,7 +1086,7 @@ static void NCR5380_main(struct work_struct *work)
/* Better allow ints _after_ 'main_running' has been cleared, else
an interrupt could believe we'll pick up the work it left for
us, but we won't see it anymore here... */
- main_running = 0;
+ hostdata->main_running = 0;
local_irq_restore(flags);
}
@@ -1179,9 +1105,11 @@ static void NCR5380_main(struct work_struct *work)
static void NCR5380_dma_complete(struct Scsi_Host *instance)
{
SETUP_HOSTDATA(instance);
- int transfered, saved_data = 0, overrun = 0, cnt, toPIO;
- unsigned char **data, p;
+ int transferred;
+ unsigned char **data;
volatile int *count;
+ int saved_data = 0, overrun = 0;
+ unsigned char p;
if (!hostdata->connected) {
printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
@@ -1189,7 +1117,7 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
return;
}
- if (atari_read_overruns) {
+ if (hostdata->read_overruns) {
p = hostdata->connected->SCp.phase;
if (p & SR_IO) {
udelay(10);
@@ -1207,21 +1135,41 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
NCR5380_read(STATUS_REG));
+#if defined(CONFIG_SUN3)
+ if ((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) {
+ pr_err("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n",
+ instance->host_no);
+ BUG();
+ }
+
+ /* make sure we're not stuck in a data phase */
+ if ((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH | BASR_ACK)) ==
+ (BASR_PHASE_MATCH | BASR_ACK)) {
+ pr_err("scsi%d: BASR %02x\n", instance->host_no,
+ NCR5380_read(BUS_AND_STATUS_REG));
+ pr_err("scsi%d: bus stuck in data phase -- probably a single byte overrun!\n",
+ instance->host_no);
+ BUG();
+ }
+#endif
+
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_BASE);
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
+ transferred = hostdata->dma_len - NCR5380_dma_residual(instance);
hostdata->dma_len = 0;
data = (unsigned char **)&hostdata->connected->SCp.ptr;
count = &hostdata->connected->SCp.this_residual;
- *data += transfered;
- *count -= transfered;
+ *data += transferred;
+ *count -= transferred;
+
+ if (hostdata->read_overruns) {
+ int cnt, toPIO;
- if (atari_read_overruns) {
if ((NCR5380_read(STATUS_REG) & PHASE_MASK) == p && (p & SR_IO)) {
- cnt = toPIO = atari_read_overruns;
+ cnt = toPIO = hostdata->read_overruns;
if (overrun) {
dprintk(NDEBUG_DMA, "Got an input overrun, using saved byte\n");
*(*data)++ = saved_data;
@@ -1238,20 +1186,19 @@ static void NCR5380_dma_complete(struct Scsi_Host *instance)
#endif /* REAL_DMA */
-/*
- * Function : void NCR5380_intr (int irq)
- *
- * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- * from the disconnected queue, and restarting NCR5380_main()
- * as required.
- *
- * Inputs : int irq, irq that caused this interrupt.
+/**
+ * NCR5380_intr - generic NCR5380 irq handler
+ * @irq: interrupt number
+ * @dev_id: device info
*
+ * Handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
*/
static irqreturn_t NCR5380_intr(int irq, void *dev_id)
{
- struct Scsi_Host *instance = first_instance;
+ struct Scsi_Host *instance = dev_id;
int done = 1, handled = 0;
unsigned char basr;
@@ -1265,7 +1212,6 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
NCR5380_dprint(NDEBUG_INTR, instance);
if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
done = 0;
- ENABLE_IRQ();
dprintk(NDEBUG_INTR, "scsi%d: SEL interrupt\n", HOSTNO);
NCR5380_reselect(instance);
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
@@ -1295,17 +1241,19 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
dprintk(NDEBUG_INTR, "scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
NCR5380_dma_complete( instance );
done = 0;
- ENABLE_IRQ();
} else
#endif /* REAL_DMA */
{
/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
if (basr & BASR_PHASE_MATCH)
- printk(KERN_NOTICE "scsi%d: unknown interrupt, "
+ dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt, "
"BASR 0x%x, MR 0x%x, SR 0x%x\n",
HOSTNO, basr, NCR5380_read(MODE_REG),
NCR5380_read(STATUS_REG));
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_DMA_ENABLE;
+#endif
}
} /* if !(SELECTION || PARITY) */
handled = 1;
@@ -1314,53 +1262,29 @@ static irqreturn_t NCR5380_intr(int irq, void *dev_id)
"BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_DMA_ENABLE;
+#endif
}
if (!done) {
dprintk(NDEBUG_INTR, "scsi%d: in int routine, calling main\n", HOSTNO);
/* Put a call to NCR5380_main() on the queue... */
- queue_main();
+ queue_main(shost_priv(instance));
}
return IRQ_RETVAL(handled);
}
-#ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
-{
-# ifdef NCR5380_STAT_LIMIT
- if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
-# endif
- switch (cmd->cmnd[0]) {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
- hostdata->pendingw--;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
- hostdata->pendingr--;
- break;
- }
-}
-#endif
-
/*
- * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
- * int tag);
+ * Function : int NCR5380_select(struct Scsi_Host *instance,
+ * struct scsi_cmnd *cmd)
*
* Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
* including ARBITRATION, SELECTION, and initial message out for
* IDENTIFY and queue messages.
*
* Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
- * the command that is presently connected.
+ * target lives, cmd - SCSI command to execute.
*
* Returns : -1 if selection could not execute for some reason,
* 0 if selection succeeded or failed because the target
@@ -1380,7 +1304,7 @@ static void collect_stats(struct NCR5380_hostdata* hostdata, Scsi_Cmnd *cmd)
* cmd->result host byte set to DID_BAD_TARGET.
*/
-static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
+static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd)
{
SETUP_HOSTDATA(instance);
unsigned char tmp[3], phase;
@@ -1562,7 +1486,7 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
* selection.
*/
- timeout = jiffies + 25;
+ timeout = jiffies + (250 * HZ / 1000);
/*
* XXX very interesting - we're seeing a bounce where the BSY we
@@ -1616,9 +1540,6 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
return -1;
}
cmd->result = DID_BAD_TARGET << 16;
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
#endif
@@ -1676,6 +1597,9 @@ static int NCR5380_select(struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag)
#ifndef SUPPORT_TAGS
hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
#endif
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_INTR;
+#endif
initialize_SCp(cmd);
@@ -1826,7 +1750,7 @@ static int NCR5380_transfer_pio(struct Scsi_Host *instance,
* Returns : 0 on success, -1 on failure.
*/
-static int do_abort(struct Scsi_Host *host)
+static int do_abort(struct Scsi_Host *instance)
{
unsigned char tmp, *msgptr, phase;
int len;
@@ -1861,7 +1785,7 @@ static int do_abort(struct Scsi_Host *host)
msgptr = &tmp;
len = 1;
phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(host, &phase, &len, &msgptr);
+ NCR5380_transfer_pio(instance, &phase, &len, &msgptr);
/*
* If we got here, and the command completed successfully,
@@ -1899,17 +1823,62 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
SETUP_HOSTDATA(instance);
register int c = *count;
register unsigned char p = *phase;
+ unsigned long flags;
+
+#if defined(CONFIG_SUN3)
+ /* sanity check */
+ if (!sun3_dma_setup_done) {
+ pr_err("scsi%d: transfer_dma without setup!\n",
+ instance->host_no);
+ BUG();
+ }
+ hostdata->dma_len = c;
+
+ dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
+ instance->host_no, (p & SR_IO) ? "reading" : "writing",
+ c, (p & SR_IO) ? "to" : "from", *data);
+
+ /* netbsd turns off ints here, why not be safe and do it too */
+ local_irq_save(flags);
+
+ /* send start chain */
+ sun3scsi_dma_start(c, *data);
+
+ if (p & SR_IO) {
+ NCR5380_write(TARGET_COMMAND_REG, 1);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(INITIATOR_COMMAND_REG, 0);
+ NCR5380_write(MODE_REG,
+ (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+ NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
+ } else {
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
+ NCR5380_write(MODE_REG,
+ (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
+ NCR5380_write(START_DMA_SEND_REG, 0);
+ }
+
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_DMA_ENABLE;
+#endif
+
+ local_irq_restore(flags);
+
+ sun3_dma_active = 1;
+
+#else /* !defined(CONFIG_SUN3) */
register unsigned char *d = *data;
unsigned char tmp;
- unsigned long flags;
if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
*phase = tmp;
return -1;
}
- if (atari_read_overruns && (p & SR_IO))
- c -= atari_read_overruns;
+ if (hostdata->read_overruns && (p & SR_IO))
+ c -= hostdata->read_overruns;
dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
HOSTNO, (p & SR_IO) ? "reading" : "writing",
@@ -1921,7 +1890,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
#endif /* def REAL_DMA */
- if (IS_A_TT()) {
+ if (!(hostdata->flags & FLAG_LATE_DMA_SETUP)) {
/* On the Medusa, it is a must to initialize the DMA before
* starting the NCR. This is also the cleaner way for the TT.
*/
@@ -1939,7 +1908,7 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
NCR5380_write(START_DMA_SEND_REG, 0);
}
- if (!IS_A_TT()) {
+ if (hostdata->flags & FLAG_LATE_DMA_SETUP) {
/* On the Falcon, the DMA setup must be done after the last */
/* NCR access, else the DMA setup gets trashed!
*/
@@ -1949,6 +1918,8 @@ static int NCR5380_transfer_dma(struct Scsi_Host *instance,
NCR5380_dma_write_setup(instance, d, c);
local_irq_restore(flags);
}
+#endif /* !defined(CONFIG_SUN3) */
+
return 0;
}
#endif /* defined(REAL_DMA) */
@@ -1982,7 +1953,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
#endif
unsigned char *data;
unsigned char phase, tmp, extended_msg[10], old_phase = 0xff;
- Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+ struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
+
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_INTR;
+#endif
while (1) {
tmp = NCR5380_read(STATUS_REG);
@@ -1993,6 +1968,33 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
old_phase = phase;
NCR5380_dprint_phase(NDEBUG_INFORMATION, instance);
}
+#if defined(CONFIG_SUN3)
+ if (phase == PHASE_CMDOUT) {
+#if defined(REAL_DMA)
+ void *d;
+ unsigned long count;
+
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ count = cmd->SCp.buffer->length;
+ d = sg_virt(cmd->SCp.buffer);
+ } else {
+ count = cmd->SCp.this_residual;
+ d = cmd->SCp.ptr;
+ }
+ /* this command setup for dma yet? */
+ if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != cmd)) {
+ if (cmd->request->cmd_type == REQ_TYPE_FS) {
+ sun3scsi_dma_setup(d, count,
+ rq_data_dir(cmd->request));
+ sun3_dma_setup_done = cmd;
+ }
+ }
+#endif
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_INTR;
+#endif
+ }
+#endif /* CONFIG_SUN3 */
if (sink && (phase != PHASE_MSGOUT)) {
NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
@@ -2054,8 +2056,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
#if defined(REAL_DMA)
- if (!cmd->device->borken &&
- (transfersize = NCR5380_dma_xfer_len(instance,cmd,phase)) > 31) {
+ if (
+#if !defined(CONFIG_SUN3)
+ !cmd->device->borken &&
+#endif
+ (transfersize = NCR5380_dma_xfer_len(instance, cmd, phase)) >= DMA_MIN_SIZE) {
len = transfersize;
cmd->SCp.phase = phase;
if (NCR5380_transfer_dma(instance, &phase,
@@ -2064,9 +2069,8 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
* If the watchdog timer fires, all future
* accesses to this device will use the
* polled-IO. */
- printk(KERN_NOTICE "scsi%d: switching target %d "
- "lun %llu to slow handshake\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
+ scmd_printk(KERN_INFO, cmd,
+ "switching to slow handshake\n");
cmd->device->borken = 1;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
ICR_ASSERT_ATN);
@@ -2092,6 +2096,11 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
NCR5380_transfer_pio(instance, &phase,
(int *)&cmd->SCp.this_residual,
(unsigned char **)&cmd->SCp.ptr);
+#if defined(CONFIG_SUN3) && defined(REAL_DMA)
+ /* if we had intended to dma that command clear it */
+ if (sun3_dma_setup_done == cmd)
+ sun3_dma_setup_done = NULL;
+#endif
break;
case PHASE_MSGIN:
len = 1;
@@ -2145,9 +2154,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked request "
"done, calling scsi_done().\n",
HOSTNO, cmd->device->id, cmd->device->lun);
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
cmd->scsi_done(cmd);
cmd = hostdata->connected;
break;
@@ -2156,11 +2162,12 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
case COMMAND_COMPLETE:
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* ++guenther: possible race with Falcon locking */
- falcon_dont_release++;
- hostdata->connected = NULL;
dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
"completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
+
+ local_irq_save(flags);
+ hostdata->retain_dma_intr++;
+ hostdata->connected = NULL;
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
@@ -2172,7 +2179,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
/* ++Andreas: the mid level code knows about
QUEUE_FULL now. */
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
+ struct tag_alloc *ta = &hostdata->TagAlloc[scmd_id(cmd)][cmd->device->lun];
dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu returned "
"QUEUE_FULL after %d commands\n",
HOSTNO, cmd->device->id, cmd->device->lun,
@@ -2207,7 +2214,6 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
else if (status_byte(cmd->SCp.Status) != GOOD)
cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-#ifdef AUTOSENSE
if ((cmd->cmnd[0] == REQUEST_SENSE) &&
hostdata->ses.cmd_len) {
scsi_eh_restore_cmnd(cmd, &hostdata->ses);
@@ -2220,22 +2226,17 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n", HOSTNO);
- local_irq_save(flags);
LIST(cmd,hostdata->issue_queue);
SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = (Scsi_Cmnd *) cmd;
- local_irq_restore(flags);
+ hostdata->issue_queue = (struct scsi_cmnd *) cmd;
dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
"issue queue\n", H_NO(cmd));
- } else
-#endif /* def AUTOSENSE */
- {
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
+ } else {
cmd->scsi_done(cmd);
}
+ local_irq_restore(flags);
+
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
/*
* Restore phase bits to 0 so an interrupted selection,
@@ -2246,12 +2247,14 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
- falcon_dont_release--;
+ local_irq_save(flags);
+ hostdata->retain_dma_intr--;
/* ++roman: For Falcon SCSI, release the lock on the
* ST-DMA here if no other commands are waiting on the
* disconnected queue.
*/
- falcon_release_lock_if_possible(hostdata);
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
return;
case MESSAGE_REJECT:
/* Accept message by clearing ACK */
@@ -2303,6 +2306,9 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
/* Wait for bus free to avoid nasty timeouts */
while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
barrier();
+#ifdef SUN3_SCSI_VME
+ dregs->csr |= CSR_DMA_ENABLE;
+#endif
return;
/*
* The SCSI data pointer is *IMPLICITLY* saved on a disconnect
@@ -2384,20 +2390,18 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
default:
if (!tmp) {
- printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
+ printk(KERN_INFO "scsi%d: rejecting message ",
+ instance->host_no);
spi_print_msg(extended_msg);
printk("\n");
} else if (tmp != EXTENDED_MESSAGE)
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "message %02x from target %d, lun %llu\n",
- HOSTNO, tmp, cmd->device->id, cmd->device->lun);
+ scmd_printk(KERN_INFO, cmd,
+ "rejecting unknown message %02x\n",
+ tmp);
else
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "extended message "
- "code %02x, length %d from target %d, lun %llu\n",
- HOSTNO, extended_msg[1], extended_msg[0],
- cmd->device->id, cmd->device->lun);
-
+ scmd_printk(KERN_INFO, cmd,
+ "rejecting unknown extended message code %02x, length %d\n",
+ extended_msg[1], extended_msg[0]);
msgout = MESSAGE_REJECT;
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
@@ -2410,6 +2414,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
hostdata->last_message = msgout;
NCR5380_transfer_pio(instance, &phase, &len, &data);
if (msgout == ABORT) {
+ local_irq_save(flags);
#ifdef SUPPORT_TAGS
cmd_free_tag(cmd);
#else
@@ -2417,12 +2422,10 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
#endif
hostdata->connected = NULL;
cmd->result = DID_ERROR << 16;
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
- cmd->scsi_done(cmd);
NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- falcon_release_lock_if_possible(hostdata);
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
+ cmd->scsi_done(cmd);
return;
}
msgout = NOP;
@@ -2455,7 +2458,7 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
* Function : void NCR5380_reselect (struct Scsi_Host *instance)
*
* Purpose : does reselection, initializing the instance->connected
- * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * field to point to the scsi_cmnd for which the I_T_L or I_T_L_Q
* nexus has been reestablished,
*
* Inputs : instance - this instance of the NCR5380.
@@ -2463,19 +2466,21 @@ static void NCR5380_information_transfer(struct Scsi_Host *instance)
*/
+/* it might eventually prove necessary to do a dma setup on
+ reselection, but it doesn't seem to be needed now -- sam */
+
static void NCR5380_reselect(struct Scsi_Host *instance)
{
SETUP_HOSTDATA(instance);
unsigned char target_mask;
- unsigned char lun, phase;
- int len;
+ unsigned char lun;
#ifdef SUPPORT_TAGS
unsigned char tag;
#endif
unsigned char msg[3];
- unsigned char *data;
- Scsi_Cmnd *tmp = NULL, *prev;
-/* unsigned long flags; */
+ int __maybe_unused len;
+ unsigned char __maybe_unused *data, __maybe_unused phase;
+ struct scsi_cmnd *tmp = NULL, *prev;
/*
* Disable arbitration, etc. since the host adapter obviously
@@ -2511,10 +2516,18 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
while (!(NCR5380_read(STATUS_REG) & SR_REQ))
;
+#if defined(CONFIG_SUN3) && defined(REAL_DMA)
+ /* acknowledge toggle to MSGIN */
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
+
+ /* peek at the byte without really hitting the bus */
+ msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
+#else
len = 1;
data = msg;
phase = PHASE_MSGIN;
NCR5380_transfer_pio(instance, &phase, &len, &data);
+#endif
if (!(msg[0] & 0x80)) {
printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
@@ -2524,13 +2537,13 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
}
lun = (msg[0] & 0x07);
-#ifdef SUPPORT_TAGS
+#if defined(SUPPORT_TAGS) && !defined(CONFIG_SUN3)
/* If the phase is still MSGIN, the target wants to send some more
* messages. In case it supports tagged queuing, this is probably a
* SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
*/
tag = TAG_NONE;
- if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+ if (phase == PHASE_MSGIN && (hostdata->flags & FLAG_TAGGED_QUEUING)) {
/* Accept previous IDENTIFY message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
len = 2;
@@ -2548,15 +2561,13 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
* just reestablished, and remove it from the disconnected queue.
*/
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
tmp; prev = tmp, tmp = NEXT(tmp)) {
if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
#ifdef SUPPORT_TAGS
&& (tag == tmp->tag)
#endif
) {
- /* ++guenther: prevent race with falcon_release_lock */
- falcon_dont_release++;
if (prev) {
REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
SET_NEXT(prev, NEXT(tmp));
@@ -2588,26 +2599,67 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
return;
}
+#if defined(CONFIG_SUN3) && defined(REAL_DMA)
+ /* engage dma setup for the command we just saw */
+ {
+ void *d;
+ unsigned long count;
+
+ if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
+ count = tmp->SCp.buffer->length;
+ d = sg_virt(tmp->SCp.buffer);
+ } else {
+ count = tmp->SCp.this_residual;
+ d = tmp->SCp.ptr;
+ }
+ /* setup this command for dma if not already */
+ if ((count >= DMA_MIN_SIZE) && (sun3_dma_setup_done != tmp)) {
+ sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request));
+ sun3_dma_setup_done = tmp;
+ }
+ }
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+#endif
+
/* Accept message by clearing ACK */
NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+#if defined(SUPPORT_TAGS) && defined(CONFIG_SUN3)
+ /* If the phase is still MSGIN, the target wants to send some more
+ * messages. In case it supports tagged queuing, this is probably a
+ * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
+ */
+ tag = TAG_NONE;
+ if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
+ /* Accept previous IDENTIFY message by clearing ACK */
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ len = 2;
+ data = msg + 1;
+ if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
+ msg[1] == SIMPLE_QUEUE_TAG)
+ tag = msg[2];
+ dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at reselection\n"
+ HOSTNO, target_mask, lun, tag);
+ }
+#endif
+
hostdata->connected = tmp;
dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
- falcon_dont_release--;
}
/*
- * Function : int NCR5380_abort (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_abort (struct scsi_cmnd *cmd)
*
* Purpose : abort a command
*
- * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * Inputs : cmd - the scsi_cmnd to abort, code - code to set the
* host byte of the result field to, if zero DID_ABORTED is
* used.
*
- * Returns : 0 - success, -1 on failure.
+ * Returns : SUCCESS - success, FAILED on failure.
*
* XXX - there is no way to abort the command that is currently
* connected, you have to wait for it to complete. If this is
@@ -2616,24 +2668,19 @@ static void NCR5380_reselect(struct Scsi_Host *instance)
*/
static
-int NCR5380_abort(Scsi_Cmnd *cmd)
+int NCR5380_abort(struct scsi_cmnd *cmd)
{
struct Scsi_Host *instance = cmd->device->host;
SETUP_HOSTDATA(instance);
- Scsi_Cmnd *tmp, **prev;
+ struct scsi_cmnd *tmp, **prev;
unsigned long flags;
- printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
- scsi_print_command(cmd);
+ scmd_printk(KERN_NOTICE, cmd, "aborting command\n");
NCR5380_print_status(instance);
local_irq_save(flags);
- if (!IS_A_TT() && !falcon_got_lock)
- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_abort\n",
- HOSTNO);
-
dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
NCR5380_read(BUS_AND_STATUS_REG),
NCR5380_read(STATUS_REG));
@@ -2674,12 +2721,12 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
cmd->scsi_done(cmd);
- falcon_release_lock_if_possible(hostdata);
return SUCCESS;
} else {
-/* local_irq_restore(flags); */
+ local_irq_restore(flags);
printk("scsi%d: abort of connected command failed!\n", HOSTNO);
return FAILED;
}
@@ -2690,21 +2737,21 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
* Case 2 : If the command hasn't been issued yet, we simply remove it
* from the issue queue.
*/
- for (prev = (Scsi_Cmnd **)&(hostdata->issue_queue),
- tmp = (Scsi_Cmnd *)hostdata->issue_queue;
+ for (prev = (struct scsi_cmnd **)&(hostdata->issue_queue),
+ tmp = (struct scsi_cmnd *)hostdata->issue_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
if (cmd == tmp) {
REMOVE(5, *prev, tmp, NEXT(tmp));
(*prev) = NEXT(tmp);
SET_NEXT(tmp, NULL);
tmp->result = DID_ABORT << 16;
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
HOSTNO);
/* Tagged queuing note: no tag to free here, hasn't been assigned
* yet... */
tmp->scsi_done(tmp);
- falcon_release_lock_if_possible(hostdata);
return SUCCESS;
}
}
@@ -2751,13 +2798,13 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
* it from the disconnected queue.
*/
- for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
tmp = NEXT(tmp)) {
if (cmd == tmp) {
local_irq_restore(flags);
dprintk(NDEBUG_ABORT, "scsi%d: aborting disconnected command.\n", HOSTNO);
- if (NCR5380_select(instance, cmd, (int)cmd->tag))
+ if (NCR5380_select(instance, cmd))
return FAILED;
dprintk(NDEBUG_ABORT, "scsi%d: nexus reestablished.\n", HOSTNO);
@@ -2765,8 +2812,8 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
do_abort(instance);
local_irq_save(flags);
- for (prev = (Scsi_Cmnd **)&(hostdata->disconnected_queue),
- tmp = (Scsi_Cmnd *)hostdata->disconnected_queue;
+ for (prev = (struct scsi_cmnd **)&(hostdata->disconnected_queue),
+ tmp = (struct scsi_cmnd *)hostdata->disconnected_queue;
tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp)) {
if (cmd == tmp) {
REMOVE(5, *prev, tmp, NEXT(tmp));
@@ -2782,15 +2829,22 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
#else
hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
#endif
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
tmp->scsi_done(tmp);
- falcon_release_lock_if_possible(hostdata);
return SUCCESS;
}
}
}
}
+ /* Maybe it is sufficient just to release the ST-DMA lock... (if
+ * possible at all) At least, we should check if the lock could be
+ * released after the abort, in case it is kept due to some bug.
+ */
+ maybe_release_dma_irq(instance);
+ local_irq_restore(flags);
+
/*
* Case 5 : If we reached this point, the command was not found in any of
* the queues.
@@ -2801,21 +2855,14 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
* broke.
*/
- local_irq_restore(flags);
printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
- /* Maybe it is sufficient just to release the ST-DMA lock... (if
- * possible at all) At least, we should check if the lock could be
- * released after the abort, in case it is kept due to some bug.
- */
- falcon_release_lock_if_possible(hostdata);
-
return FAILED;
}
/*
- * Function : int NCR5380_reset (Scsi_Cmnd *cmd)
+ * Function : int NCR5380_reset (struct scsi_cmnd *cmd)
*
* Purpose : reset the SCSI bus.
*
@@ -2823,20 +2870,14 @@ int NCR5380_abort(Scsi_Cmnd *cmd)
*
*/
-static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
+static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
{
- SETUP_HOSTDATA(cmd->device->host);
+ struct Scsi_Host *instance = cmd->device->host;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
int i;
unsigned long flags;
-#if defined(RESET_RUN_DONE)
- Scsi_Cmnd *connected, *disconnected_queue;
-#endif
-
- if (!IS_A_TT() && !falcon_got_lock)
- printk(KERN_ERR "scsi%d: !!BINGO!! Falcon has no lock in NCR5380_reset\n",
- H_NO(cmd));
- NCR5380_print_status(cmd->device->host);
+ NCR5380_print_status(instance);
/* get in phase */
NCR5380_write(TARGET_COMMAND_REG,
@@ -2853,89 +2894,6 @@ static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
* through anymore ... */
(void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- /* MSch 20140115 - looking at the generic NCR5380 driver, all of this
- * should go.
- * Catch-22: if we don't clear all queues, the SCSI driver lock will
- * not be reset by atari_scsi_reset()!
- */
-
-#if defined(RESET_RUN_DONE)
- /* XXX Should now be done by midlevel code, but it's broken XXX */
- /* XXX see below XXX */
-
- /* MSch: old-style reset: actually abort all command processing here */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; to avoid problems with re-inserting the commands
- * into the issue_queue (via scsi_done()), the aborted commands are
- * remembered in local variables first.
- */
- local_irq_save(flags);
- connected = (Scsi_Cmnd *)hostdata->connected;
- hostdata->connected = NULL;
- disconnected_queue = (Scsi_Cmnd *)hostdata->disconnected_queue;
- hostdata->disconnected_queue = NULL;
-#ifdef SUPPORT_TAGS
- free_all_tags();
-#endif
- for (i = 0; i < 8; ++i)
- hostdata->busy[i] = 0;
-#ifdef REAL_DMA
- hostdata->dma_len = 0;
-#endif
- local_irq_restore(flags);
-
- /* In order to tell the mid-level code which commands were aborted,
- * set the command status to DID_RESET and call scsi_done() !!!
- * This ultimately aborts processing of these commands in the mid-level.
- */
-
- if ((cmd = connected)) {
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted a connected command\n", H_NO(cmd));
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done(cmd);
- }
-
- for (i = 0; (cmd = disconnected_queue); ++i) {
- disconnected_queue = NEXT(cmd);
- SET_NEXT(cmd, NULL);
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done(cmd);
- }
- if (i > 0)
- dprintk(NDEBUG_ABORT, "scsi: reset aborted %d disconnected command(s)\n", i);
-
- /* The Falcon lock should be released after a reset...
- */
- /* ++guenther: moved to atari_scsi_reset(), to prevent a race between
- * unlocking and enabling dma interrupt.
- */
-/* falcon_release_lock_if_possible( hostdata );*/
-
- /* since all commands have been explicitly terminated, we need to tell
- * the midlevel code that the reset was SUCCESSFUL, and there is no
- * need to 'wake up' the commands by a request_sense
- */
- return SUCCESS;
-#else /* 1 */
-
- /* MSch: new-style reset handling: let the mid-level do what it can */
-
- /* ++guenther: MID-LEVEL IS STILL BROKEN.
- * Mid-level is supposed to requeue all commands that were active on the
- * various low-level queues. In fact it does this, but that's not enough
- * because all these commands are subject to timeout. And if a timeout
- * happens for any removed command, *_abort() is called but all queues
- * are now empty. Abort then gives up the falcon lock, which is fatal,
- * since the mid-level will queue more commands and must have the lock
- * (it's all happening inside timer interrupt handler!!).
- * Even worse, abort will return NOT_RUNNING for all those commands not
- * on any queue, so they won't be retried ...
- *
- * Conclusion: either scsi.c disables timeout for all resetted commands
- * immediately, or we lose! As of linux-2.0.20 it doesn't.
- */
-
/* After the reset, there are no more connected or disconnected commands
* and no busy units; so clear the low-level status here to avoid
* conflicts when the mid-level code tries to wake up the affected
@@ -2954,16 +2912,16 @@ static int NCR5380_bus_reset(Scsi_Cmnd *cmd)
hostdata->connected = NULL;
hostdata->disconnected_queue = NULL;
#ifdef SUPPORT_TAGS
- free_all_tags();
+ free_all_tags(hostdata);
#endif
for (i = 0; i < 8; ++i)
hostdata->busy[i] = 0;
#ifdef REAL_DMA
hostdata->dma_len = 0;
#endif
+
+ maybe_release_dma_irq(instance);
local_irq_restore(flags);
- /* we did no complete reset of all commands, so a wakeup is required */
return SUCCESS;
-#endif /* 1 */
}
diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c
index b522134..d1c37a3 100644
--- a/drivers/scsi/atari_scsi.c
+++ b/drivers/scsi/atari_scsi.c
@@ -64,45 +64,57 @@
/**************************************************************************/
-
#include <linux/module.h>
-
-#define AUTOSENSE
-/* For the Atari version, use only polled IO or REAL_DMA */
-#define REAL_DMA
-/* Support tagged queuing? (on devices that are able to... :-) */
-#define SUPPORT_TAGS
-#define MAX_TAGS 32
-
#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/ctype.h>
#include <linux/delay.h>
-#include <linux/mm.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
#include <linux/init.h>
#include <linux/nvram.h>
#include <linux/bitops.h>
#include <linux/wait.h>
+#include <linux/platform_device.h>
#include <asm/setup.h>
#include <asm/atarihw.h>
#include <asm/atariints.h>
-#include <asm/page.h>
-#include <asm/pgtable.h>
-#include <asm/irq.h>
-#include <asm/traps.h>
-
-#include "scsi.h"
-#include <scsi/scsi_host.h>
-#include "atari_scsi.h"
-#include "NCR5380.h"
#include <asm/atari_stdma.h>
#include <asm/atari_stram.h>
#include <asm/io.h>
-#include <linux/stat.h>
+#include <scsi/scsi_host.h>
+
+/* Definitions for the core NCR5380 driver. */
+
+#define REAL_DMA
+#define SUPPORT_TAGS
+#define MAX_TAGS 32
+#define DMA_MIN_SIZE 32
+
+#define NCR5380_implementation_fields /* none */
+
+#define NCR5380_read(reg) atari_scsi_reg_read(reg)
+#define NCR5380_write(reg, value) atari_scsi_reg_write(reg, value)
+
+#define NCR5380_queue_command atari_scsi_queue_command
+#define NCR5380_abort atari_scsi_abort
+#define NCR5380_show_info atari_scsi_show_info
+#define NCR5380_info atari_scsi_info
+
+#define NCR5380_dma_read_setup(instance, data, count) \
+ atari_scsi_dma_setup(instance, data, count, 0)
+#define NCR5380_dma_write_setup(instance, data, count) \
+ atari_scsi_dma_setup(instance, data, count, 1)
+#define NCR5380_dma_residual(instance) \
+ atari_scsi_dma_residual(instance)
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+ atari_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO))
+
+#define NCR5380_acquire_dma_irq(instance) falcon_get_lock(instance)
+#define NCR5380_release_dma_irq(instance) falcon_release_lock()
+
+#include "NCR5380.h"
+
#define IS_A_TT() ATARIHW_PRESENT(TT_SCSI)
@@ -149,23 +161,6 @@ static inline unsigned long SCSI_DMA_GETADR(void)
return adr;
}
-static inline void ENABLE_IRQ(void)
-{
- if (IS_A_TT())
- atari_enable_irq(IRQ_TT_MFP_SCSI);
- else
- atari_enable_irq(IRQ_MFP_FSCSI);
-}
-
-static inline void DISABLE_IRQ(void)
-{
- if (IS_A_TT())
- atari_disable_irq(IRQ_TT_MFP_SCSI);
- else
- atari_disable_irq(IRQ_MFP_FSCSI);
-}
-
-
#define HOSTDATA_DMALEN (((struct NCR5380_hostdata *) \
(atari_scsi_host->hostdata))->dma_len)
@@ -178,30 +173,9 @@ static inline void DISABLE_IRQ(void)
#define AFTER_RESET_DELAY (5*HZ/2)
#endif
-/***************************** Prototypes *****************************/
-
#ifdef REAL_DMA
-static int scsi_dma_is_ignored_buserr(unsigned char dma_stat);
static void atari_scsi_fetch_restbytes(void);
-static long atari_scsi_dma_residual(struct Scsi_Host *instance);
-static int falcon_classify_cmd(Scsi_Cmnd *cmd);
-static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
- Scsi_Cmnd *cmd, int write_flag);
-#endif
-static irqreturn_t scsi_tt_intr(int irq, void *dummy);
-static irqreturn_t scsi_falcon_intr(int irq, void *dummy);
-static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata);
-static void falcon_get_lock(void);
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
-static void atari_scsi_reset_boot(void);
#endif
-static unsigned char atari_scsi_tt_reg_read(unsigned char reg);
-static void atari_scsi_tt_reg_write(unsigned char reg, unsigned char value);
-static unsigned char atari_scsi_falcon_reg_read(unsigned char reg);
-static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value);
-
-/************************* End of Prototypes **************************/
-
static struct Scsi_Host *atari_scsi_host;
static unsigned char (*atari_scsi_reg_read)(unsigned char reg);
@@ -226,8 +200,6 @@ static char *atari_dma_orig_addr;
/* mask for address bits that can't be used with the ST-DMA */
static unsigned long atari_dma_stram_mask;
#define STRAM_ADDR(a) (((a) & atari_dma_stram_mask) == 0)
-/* number of bytes to cut from a transfer to handle NCR overruns */
-static int atari_read_overruns;
#endif
static int setup_can_queue = -1;
@@ -386,10 +358,6 @@ static irqreturn_t scsi_tt_intr(int irq, void *dummy)
NCR5380_intr(irq, dummy);
-#if 0
- /* To be sure the int is not masked */
- atari_enable_irq(IRQ_TT_MFP_SCSI);
-#endif
return IRQ_HANDLED;
}
@@ -480,257 +448,35 @@ static void atari_scsi_fetch_restbytes(void)
#endif /* REAL_DMA */
-static int falcon_got_lock = 0;
-static DECLARE_WAIT_QUEUE_HEAD(falcon_fairness_wait);
-static int falcon_trying_lock = 0;
-static DECLARE_WAIT_QUEUE_HEAD(falcon_try_wait);
-static int falcon_dont_release = 0;
-
/* This function releases the lock on the DMA chip if there is no
- * connected command and the disconnected queue is empty. On
- * releasing, instances of falcon_get_lock are awoken, that put
- * themselves to sleep for fairness. They can now try to get the lock
- * again (but others waiting longer more probably will win).
+ * connected command and the disconnected queue is empty.
*/
-static void falcon_release_lock_if_possible(struct NCR5380_hostdata *hostdata)
+static void falcon_release_lock(void)
{
- unsigned long flags;
-
if (IS_A_TT())
return;
- local_irq_save(flags);
-
- if (falcon_got_lock && !hostdata->disconnected_queue &&
- !hostdata->issue_queue && !hostdata->connected) {
-
- if (falcon_dont_release) {
-#if 0
- printk("WARNING: Lock release not allowed. Ignored\n");
-#endif
- local_irq_restore(flags);
- return;
- }
- falcon_got_lock = 0;
+ if (stdma_is_locked_by(scsi_falcon_intr))
stdma_release();
- wake_up(&falcon_fairness_wait);
- }
-
- local_irq_restore(flags);
}
/* This function manages the locking of the ST-DMA.
* If the DMA isn't locked already for SCSI, it tries to lock it by
* calling stdma_lock(). But if the DMA is locked by the SCSI code and
* there are other drivers waiting for the chip, we do not issue the
- * command immediately but wait on 'falcon_fairness_queue'. We will be
- * waked up when the DMA is unlocked by some SCSI interrupt. After that
- * we try to get the lock again.
- * But we must be prepared that more than one instance of
- * falcon_get_lock() is waiting on the fairness queue. They should not
- * try all at once to call stdma_lock(), one is enough! For that, the
- * first one sets 'falcon_trying_lock', others that see that variable
- * set wait on the queue 'falcon_try_wait'.
- * Complicated, complicated.... Sigh...
+ * command immediately but tell the SCSI mid-layer to defer.
*/
-static void falcon_get_lock(void)
+static int falcon_get_lock(struct Scsi_Host *instance)
{
- unsigned long flags;
-
if (IS_A_TT())
- return;
-
- local_irq_save(flags);
-
- wait_event_cmd(falcon_fairness_wait,
- in_interrupt() || !falcon_got_lock || !stdma_others_waiting(),
- local_irq_restore(flags),
- local_irq_save(flags));
-
- while (!falcon_got_lock) {
- if (in_irq())
- panic("Falcon SCSI hasn't ST-DMA lock in interrupt");
- if (!falcon_trying_lock) {
- falcon_trying_lock = 1;
- stdma_lock(scsi_falcon_intr, NULL);
- falcon_got_lock = 1;
- falcon_trying_lock = 0;
- wake_up(&falcon_try_wait);
- } else {
- wait_event_cmd(falcon_try_wait,
- falcon_got_lock && !falcon_trying_lock,
- local_irq_restore(flags),
- local_irq_save(flags));
- }
- }
-
- local_irq_restore(flags);
- if (!falcon_got_lock)
- panic("Falcon SCSI: someone stole the lock :-(\n");
-}
-
-
-static int __init atari_scsi_detect(struct scsi_host_template *host)
-{
- static int called = 0;
- struct Scsi_Host *instance;
-
- if (!MACH_IS_ATARI ||
- (!ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(TT_SCSI)) ||
- called)
- return 0;
-
- host->proc_name = "Atari";
-
- atari_scsi_reg_read = IS_A_TT() ? atari_scsi_tt_reg_read :
- atari_scsi_falcon_reg_read;
- atari_scsi_reg_write = IS_A_TT() ? atari_scsi_tt_reg_write :
- atari_scsi_falcon_reg_write;
-
- /* setup variables */
- host->can_queue =
- (setup_can_queue > 0) ? setup_can_queue :
- IS_A_TT() ? ATARI_TT_CAN_QUEUE : ATARI_FALCON_CAN_QUEUE;
- host->cmd_per_lun =
- (setup_cmd_per_lun > 0) ? setup_cmd_per_lun :
- IS_A_TT() ? ATARI_TT_CMD_PER_LUN : ATARI_FALCON_CMD_PER_LUN;
- /* Force sg_tablesize to 0 on a Falcon! */
- host->sg_tablesize =
- !IS_A_TT() ? ATARI_FALCON_SG_TABLESIZE :
- (setup_sg_tablesize >= 0) ? setup_sg_tablesize : ATARI_TT_SG_TABLESIZE;
-
- if (setup_hostid >= 0)
- host->this_id = setup_hostid;
- else {
- /* use 7 as default */
- host->this_id = 7;
- /* Test if a host id is set in the NVRam */
- if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
- unsigned char b = nvram_read_byte( 14 );
- /* Arbitration enabled? (for TOS) If yes, use configured host ID */
- if (b & 0x80)
- host->this_id = b & 7;
- }
- }
+ return 1;
-#ifdef SUPPORT_TAGS
- if (setup_use_tagged_queuing < 0)
- setup_use_tagged_queuing = DEFAULT_USE_TAGGED_QUEUING;
-#endif
-#ifdef REAL_DMA
- /* If running on a Falcon and if there's TT-Ram (i.e., more than one
- * memory block, since there's always ST-Ram in a Falcon), then allocate a
- * STRAM_BUFFER_SIZE byte dribble buffer for transfers from/to alternative
- * Ram.
- */
- if (MACH_IS_ATARI && ATARIHW_PRESENT(ST_SCSI) &&
- !ATARIHW_PRESENT(EXTD_DMA) && m68k_num_memory > 1) {
- atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
- if (!atari_dma_buffer) {
- printk(KERN_ERR "atari_scsi_detect: can't allocate ST-RAM "
- "double buffer\n");
- return 0;
- }
- atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer);
- atari_dma_orig_addr = 0;
- }
-#endif
- instance = scsi_register(host, sizeof(struct NCR5380_hostdata));
- if (instance == NULL) {
- atari_stram_free(atari_dma_buffer);
- atari_dma_buffer = 0;
- return 0;
- }
- atari_scsi_host = instance;
- /*
- * Set irq to 0, to avoid that the mid-level code disables our interrupt
- * during queue_command calls. This is completely unnecessary, and even
- * worse causes bad problems on the Falcon, where the int is shared with
- * IDE and floppy!
- */
- instance->irq = 0;
-
-#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
- atari_scsi_reset_boot();
-#endif
- NCR5380_init(instance, 0);
-
- if (IS_A_TT()) {
-
- /* This int is actually "pseudo-slow", i.e. it acts like a slow
- * interrupt after having cleared the pending flag for the DMA
- * interrupt. */
- if (request_irq(IRQ_TT_MFP_SCSI, scsi_tt_intr, IRQ_TYPE_SLOW,
- "SCSI NCR5380", instance)) {
- printk(KERN_ERR "atari_scsi_detect: cannot allocate irq %d, aborting",IRQ_TT_MFP_SCSI);
- scsi_unregister(atari_scsi_host);
- atari_stram_free(atari_dma_buffer);
- atari_dma_buffer = 0;
- return 0;
- }
- tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */
-#ifdef REAL_DMA
- tt_scsi_dma.dma_ctrl = 0;
- atari_dma_residual = 0;
-
- if (MACH_IS_MEDUSA) {
- /* While the read overruns (described by Drew Eckhardt in
- * NCR5380.c) never happened on TTs, they do in fact on the Medusa
- * (This was the cause why SCSI didn't work right for so long
- * there.) Since handling the overruns slows down a bit, I turned
- * the #ifdef's into a runtime condition.
- *
- * In principle it should be sufficient to do max. 1 byte with
- * PIO, but there is another problem on the Medusa with the DMA
- * rest data register. So 'atari_read_overruns' is currently set
- * to 4 to avoid having transfers that aren't a multiple of 4. If
- * the rest data bug is fixed, this can be lowered to 1.
- */
- atari_read_overruns = 4;
- }
-#endif /*REAL_DMA*/
- } else { /* ! IS_A_TT */
-
- /* Nothing to do for the interrupt: the ST-DMA is initialized
- * already by atari_init_INTS()
- */
-
-#ifdef REAL_DMA
- atari_dma_residual = 0;
- atari_dma_active = 0;
- atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000
- : 0xff000000);
-#endif
- }
+ if (in_interrupt())
+ return stdma_try_lock(scsi_falcon_intr, instance);
- printk(KERN_INFO "scsi%d: options CAN_QUEUE=%d CMD_PER_LUN=%d SCAT-GAT=%d "
-#ifdef SUPPORT_TAGS
- "TAGGED-QUEUING=%s "
-#endif
- "HOSTID=%d",
- instance->host_no, instance->hostt->can_queue,
- instance->hostt->cmd_per_lun,
- instance->hostt->sg_tablesize,
-#ifdef SUPPORT_TAGS
- setup_use_tagged_queuing ? "yes" : "no",
-#endif
- instance->hostt->this_id );
- NCR5380_print_options(instance);
- printk("\n");
-
- called = 1;
- return 1;
-}
-
-static int atari_scsi_release(struct Scsi_Host *sh)
-{
- if (IS_A_TT())
- free_irq(IRQ_TT_MFP_SCSI, sh);
- if (atari_dma_buffer)
- atari_stram_free(atari_dma_buffer);
- NCR5380_exit(sh);
+ stdma_lock(scsi_falcon_intr, instance);
return 1;
}
@@ -739,7 +485,7 @@ static int __init atari_scsi_setup(char *str)
{
/* Format of atascsi parameter is:
* atascsi=<can_queue>,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>
- * Defaults depend on TT or Falcon, hostid determined at run time.
+ * Defaults depend on TT or Falcon, determined at run time.
* Negative values mean don't change.
*/
int ints[6];
@@ -750,36 +496,17 @@ static int __init atari_scsi_setup(char *str)
printk("atari_scsi_setup: no arguments!\n");
return 0;
}
-
- if (ints[0] >= 1) {
- if (ints[1] > 0)
- /* no limits on this, just > 0 */
- setup_can_queue = ints[1];
- }
- if (ints[0] >= 2) {
- if (ints[2] > 0)
- setup_cmd_per_lun = ints[2];
- }
- if (ints[0] >= 3) {
- if (ints[3] >= 0) {
- setup_sg_tablesize = ints[3];
- /* Must be <= SG_ALL (255) */
- if (setup_sg_tablesize > SG_ALL)
- setup_sg_tablesize = SG_ALL;
- }
- }
- if (ints[0] >= 4) {
- /* Must be between 0 and 7 */
- if (ints[4] >= 0 && ints[4] <= 7)
- setup_hostid = ints[4];
- else if (ints[4] > 7)
- printk("atari_scsi_setup: invalid host ID %d !\n", ints[4]);
- }
+ if (ints[0] >= 1)
+ setup_can_queue = ints[1];
+ if (ints[0] >= 2)
+ setup_cmd_per_lun = ints[2];
+ if (ints[0] >= 3)
+ setup_sg_tablesize = ints[3];
+ if (ints[0] >= 4)
+ setup_hostid = ints[4];
#ifdef SUPPORT_TAGS
- if (ints[0] >= 5) {
- if (ints[5] >= 0)
- setup_use_tagged_queuing = !!ints[5];
- }
+ if (ints[0] >= 5)
+ setup_use_tagged_queuing = ints[5];
#endif
return 1;
@@ -788,45 +515,6 @@ static int __init atari_scsi_setup(char *str)
__setup("atascsi=", atari_scsi_setup);
#endif /* !MODULE */
-static int atari_scsi_bus_reset(Scsi_Cmnd *cmd)
-{
- int rv;
- struct NCR5380_hostdata *hostdata =
- (struct NCR5380_hostdata *)cmd->device->host->hostdata;
-
- /* For doing the reset, SCSI interrupts must be disabled first,
- * since the 5380 raises its IRQ line while _RST is active and we
- * can't disable interrupts completely, since we need the timer.
- */
- /* And abort a maybe active DMA transfer */
- if (IS_A_TT()) {
- atari_turnoff_irq(IRQ_TT_MFP_SCSI);
-#ifdef REAL_DMA
- tt_scsi_dma.dma_ctrl = 0;
-#endif /* REAL_DMA */
- } else {
- atari_turnoff_irq(IRQ_MFP_FSCSI);
-#ifdef REAL_DMA
- st_dma.dma_mode_status = 0x90;
- atari_dma_active = 0;
- atari_dma_orig_addr = NULL;
-#endif /* REAL_DMA */
- }
-
- rv = NCR5380_bus_reset(cmd);
-
- /* Re-enable ints */
- if (IS_A_TT()) {
- atari_turnon_irq(IRQ_TT_MFP_SCSI);
- } else {
- atari_turnon_irq(IRQ_MFP_FSCSI);
- }
- if (rv == SUCCESS)
- falcon_release_lock_if_possible(hostdata);
-
- return rv;
-}
-
#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
static void __init atari_scsi_reset_boot(void)
@@ -860,15 +548,6 @@ static void __init atari_scsi_reset_boot(void)
}
#endif
-
-static const char *atari_scsi_info(struct Scsi_Host *host)
-{
- /* atari_scsi_detect() is verbose enough... */
- static const char string[] = "Atari native SCSI";
- return string;
-}
-
-
#if defined(REAL_DMA)
static unsigned long atari_scsi_dma_setup(struct Scsi_Host *instance,
@@ -949,7 +628,7 @@ static long atari_scsi_dma_residual(struct Scsi_Host *instance)
#define CMD_SURELY_BYTE_MODE 1
#define CMD_MODE_UNKNOWN 2
-static int falcon_classify_cmd(Scsi_Cmnd *cmd)
+static int falcon_classify_cmd(struct scsi_cmnd *cmd)
{
unsigned char opcode = cmd->cmnd[0];
@@ -981,7 +660,7 @@ static int falcon_classify_cmd(Scsi_Cmnd *cmd)
*/
static unsigned long atari_dma_xfer_len(unsigned long wanted_len,
- Scsi_Cmnd *cmd, int write_flag)
+ struct scsi_cmnd *cmd, int write_flag)
{
unsigned long possible_len, limit;
@@ -1099,23 +778,247 @@ static void atari_scsi_falcon_reg_write(unsigned char reg, unsigned char value)
#include "atari_NCR5380.c"
-static struct scsi_host_template driver_template = {
+static int atari_scsi_bus_reset(struct scsi_cmnd *cmd)
+{
+ int rv;
+ unsigned long flags;
+
+ local_irq_save(flags);
+
+#ifdef REAL_DMA
+ /* Abort a maybe active DMA transfer */
+ if (IS_A_TT()) {
+ tt_scsi_dma.dma_ctrl = 0;
+ } else {
+ st_dma.dma_mode_status = 0x90;
+ atari_dma_active = 0;
+ atari_dma_orig_addr = NULL;
+ }
+#endif
+
+ rv = NCR5380_bus_reset(cmd);
+
+ /* The 5380 raises its IRQ line while _RST is active but the ST DMA
+ * "lock" has been released so this interrupt may end up handled by
+ * floppy or IDE driver (if one of them holds the lock). The NCR5380
+ * interrupt flag has been cleared already.
+ */
+
+ local_irq_restore(flags);
+
+ return rv;
+}
+
+#define DRV_MODULE_NAME "atari_scsi"
+#define PFX DRV_MODULE_NAME ": "
+
+static struct scsi_host_template atari_scsi_template = {
+ .module = THIS_MODULE,
+ .proc_name = DRV_MODULE_NAME,
.show_info = atari_scsi_show_info,
.name = "Atari native SCSI",
- .detect = atari_scsi_detect,
- .release = atari_scsi_release,
.info = atari_scsi_info,
.queuecommand = atari_scsi_queue_command,
.eh_abort_handler = atari_scsi_abort,
.eh_bus_reset_handler = atari_scsi_bus_reset,
- .can_queue = 0, /* initialized at run-time */
- .this_id = 0, /* initialized at run-time */
- .sg_tablesize = 0, /* initialized at run-time */
- .cmd_per_lun = 0, /* initialized at run-time */
+ .this_id = 7,
.use_clustering = DISABLE_CLUSTERING
};
+static int __init atari_scsi_probe(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance;
+ int error;
+ struct resource *irq;
+ int host_flags = 0;
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!irq)
+ return -ENODEV;
+
+ if (ATARIHW_PRESENT(TT_SCSI)) {
+ atari_scsi_reg_read = atari_scsi_tt_reg_read;
+ atari_scsi_reg_write = atari_scsi_tt_reg_write;
+ } else {
+ atari_scsi_reg_read = atari_scsi_falcon_reg_read;
+ atari_scsi_reg_write = atari_scsi_falcon_reg_write;
+ }
+
+ /* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary.
+ * Higher values should work, too; try it!
+ * (But cmd_per_lun costs memory!)
+ *
+ * But there seems to be a bug somewhere that requires CAN_QUEUE to be
+ * 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since
+ * changed CMD_PER_LUN...
+ *
+ * Note: The Falcon currently uses 8/1 setting due to unsolved problems
+ * with cmd_per_lun != 1
+ */
+ if (ATARIHW_PRESENT(TT_SCSI)) {
+ atari_scsi_template.can_queue = 16;
+ atari_scsi_template.cmd_per_lun = 8;
+ atari_scsi_template.sg_tablesize = SG_ALL;
+ } else {
+ atari_scsi_template.can_queue = 8;
+ atari_scsi_template.cmd_per_lun = 1;
+ atari_scsi_template.sg_tablesize = SG_NONE;
+ }
+
+ if (setup_can_queue > 0)
+ atari_scsi_template.can_queue = setup_can_queue;
+
+ if (setup_cmd_per_lun > 0)
+ atari_scsi_template.cmd_per_lun = setup_cmd_per_lun;
+
+ /* Leave sg_tablesize at 0 on a Falcon! */
+ if (ATARIHW_PRESENT(TT_SCSI) && setup_sg_tablesize >= 0)
+ atari_scsi_template.sg_tablesize = setup_sg_tablesize;
+
+ if (setup_hostid >= 0) {
+ atari_scsi_template.this_id = setup_hostid & 7;
+ } else {
+ /* Test if a host id is set in the NVRam */
+ if (ATARIHW_PRESENT(TT_CLK) && nvram_check_checksum()) {
+ unsigned char b = nvram_read_byte(14);
+
+ /* Arbitration enabled? (for TOS)
+ * If yes, use configured host ID
+ */
+ if (b & 0x80)
+ atari_scsi_template.this_id = b & 7;
+ }
+ }
+
+
+#ifdef REAL_DMA
+ /* If running on a Falcon and if there's TT-Ram (i.e., more than one
+ * memory block, since there's always ST-Ram in a Falcon), then
+ * allocate a STRAM_BUFFER_SIZE byte dribble buffer for transfers
+ * from/to alternative Ram.
+ */
+ if (ATARIHW_PRESENT(ST_SCSI) && !ATARIHW_PRESENT(EXTD_DMA) &&
+ m68k_num_memory > 1) {
+ atari_dma_buffer = atari_stram_alloc(STRAM_BUFFER_SIZE, "SCSI");
+ if (!atari_dma_buffer) {
+ pr_err(PFX "can't allocate ST-RAM double buffer\n");
+ return -ENOMEM;
+ }
+ atari_dma_phys_buffer = atari_stram_to_phys(atari_dma_buffer);
+ atari_dma_orig_addr = 0;
+ }
+#endif
+
+ instance = scsi_host_alloc(&atari_scsi_template,
+ sizeof(struct NCR5380_hostdata));
+ if (!instance) {
+ error = -ENOMEM;
+ goto fail_alloc;
+ }
+ atari_scsi_host = instance;
+
+#ifdef CONFIG_ATARI_SCSI_RESET_BOOT
+ atari_scsi_reset_boot();
+#endif
+
+ instance->irq = irq->start;
+
+ host_flags |= IS_A_TT() ? 0 : FLAG_LATE_DMA_SETUP;
+
+#ifdef SUPPORT_TAGS
+ host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
+#endif
+
+ NCR5380_init(instance, host_flags);
+
+ if (IS_A_TT()) {
+ error = request_irq(instance->irq, scsi_tt_intr, 0,
+ "NCR5380", instance);
+ if (error) {
+ pr_err(PFX "request irq %d failed, aborting\n",
+ instance->irq);
+ goto fail_irq;
+ }
+ tt_mfp.active_edge |= 0x80; /* SCSI int on L->H */
+#ifdef REAL_DMA
+ tt_scsi_dma.dma_ctrl = 0;
+ atari_dma_residual = 0;
+
+ /* While the read overruns (described by Drew Eckhardt in
+ * NCR5380.c) never happened on TTs, they do in fact on the
+ * Medusa (This was the cause why SCSI didn't work right for
+ * so long there.) Since handling the overruns slows down
+ * a bit, I turned the #ifdef's into a runtime condition.
+ *
+ * In principle it should be sufficient to do max. 1 byte with
+ * PIO, but there is another problem on the Medusa with the DMA
+ * rest data register. So read_overruns is currently set
+ * to 4 to avoid having transfers that aren't a multiple of 4.
+ * If the rest data bug is fixed, this can be lowered to 1.
+ */
+ if (MACH_IS_MEDUSA) {
+ struct NCR5380_hostdata *hostdata =
+ shost_priv(instance);
+
+ hostdata->read_overruns = 4;
+ }
+#endif
+ } else {
+ /* Nothing to do for the interrupt: the ST-DMA is initialized
+ * already.
+ */
+#ifdef REAL_DMA
+ atari_dma_residual = 0;
+ atari_dma_active = 0;
+ atari_dma_stram_mask = (ATARIHW_PRESENT(EXTD_DMA) ? 0x00000000
+ : 0xff000000);
+#endif
+ }
+
+ error = scsi_add_host(instance, NULL);
+ if (error)
+ goto fail_host;
+
+ platform_set_drvdata(pdev, instance);
+
+ scsi_scan_host(instance);
+ return 0;
+
+fail_host:
+ if (IS_A_TT())
+ free_irq(instance->irq, instance);
+fail_irq:
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+fail_alloc:
+ if (atari_dma_buffer)
+ atari_stram_free(atari_dma_buffer);
+ return error;
+}
+
+static int __exit atari_scsi_remove(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance = platform_get_drvdata(pdev);
+
+ scsi_remove_host(instance);
+ if (IS_A_TT())
+ free_irq(instance->irq, instance);
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+ if (atari_dma_buffer)
+ atari_stram_free(atari_dma_buffer);
+ return 0;
+}
+
+static struct platform_driver atari_scsi_driver = {
+ .remove = __exit_p(atari_scsi_remove),
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
-#include "scsi_module.c"
+module_platform_driver_probe(atari_scsi_driver, atari_scsi_probe);
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h
deleted file mode 100644
index 3299d91..0000000
--- a/drivers/scsi/atari_scsi.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * atari_scsi.h -- Header file for the Atari native SCSI driver
- *
- * Copyright 1994 Roman Hodek <Roman.Hodek@informatik.uni-erlangen.de>
- *
- * (Loosely based on the work of Robert De Vries' team)
- *
- * This file is subject to the terms and conditions of the GNU General Public
- * License. See the file COPYING in the main directory of this archive
- * for more details.
- *
- */
-
-
-#ifndef ATARI_SCSI_H
-#define ATARI_SCSI_H
-
-/* (I_HAVE_OVERRUNS stuff removed) */
-
-#ifndef ASM
-/* The values for CMD_PER_LUN and CAN_QUEUE are somehow arbitrary. Higher
- * values should work, too; try it! (but cmd_per_lun costs memory!) */
-
-/* But there seems to be a bug somewhere that requires CAN_QUEUE to be
- * 2*CMD_PER_LUN. At least on a TT, no spurious timeouts seen since
- * changed CMD_PER_LUN... */
-
-/* Note: The Falcon currently uses 8/1 setting due to unsolved problems with
- * cmd_per_lun != 1 */
-
-#define ATARI_TT_CAN_QUEUE 16
-#define ATARI_TT_CMD_PER_LUN 8
-#define ATARI_TT_SG_TABLESIZE SG_ALL
-
-#define ATARI_FALCON_CAN_QUEUE 8
-#define ATARI_FALCON_CMD_PER_LUN 1
-#define ATARI_FALCON_SG_TABLESIZE SG_NONE
-
-#define DEFAULT_USE_TAGGED_QUEUING 0
-
-
-#define NCR5380_implementation_fields /* none */
-
-#define NCR5380_read(reg) atari_scsi_reg_read( reg )
-#define NCR5380_write(reg, value) atari_scsi_reg_write( reg, value )
-
-#define NCR5380_intr atari_scsi_intr
-#define NCR5380_queue_command atari_scsi_queue_command
-#define NCR5380_abort atari_scsi_abort
-#define NCR5380_show_info atari_scsi_show_info
-#define NCR5380_dma_read_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 0)
-#define NCR5380_dma_write_setup(inst,d,c) atari_scsi_dma_setup (inst, d, c, 1)
-#define NCR5380_dma_residual(inst) atari_scsi_dma_residual( inst )
-#define NCR5380_dma_xfer_len(i,cmd,phase) \
- atari_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
-
-#endif /* ndef ASM */
-#endif /* ATARI_SCSI_H */
-
-
diff --git a/drivers/scsi/be2iscsi/be_main.c b/drivers/scsi/be2iscsi/be_main.c
index 30d74a0..f319340 100644
--- a/drivers/scsi/be2iscsi/be_main.c
+++ b/drivers/scsi/be2iscsi/be_main.c
@@ -556,7 +556,7 @@ static struct scsi_host_template beiscsi_sht = {
.name = "Emulex 10Gbe open-iscsi Initiator Driver",
.proc_name = DRV_NAME,
.queuecommand = iscsi_queuecommand,
- .change_queue_depth = iscsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.slave_configure = beiscsi_slave_configure,
.target_alloc = iscsi_target_alloc,
.eh_abort_handler = beiscsi_eh_abort,
@@ -570,7 +570,7 @@ static struct scsi_host_template beiscsi_sht = {
.cmd_per_lun = BEISCSI_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.vendor_id = SCSI_NL_VID_TYPE_PCI | BE_VENDOR_ID,
-
+ .track_queue_depth = 1,
};
static struct scsi_transport_template *beiscsi_scsi_transport;
diff --git a/drivers/scsi/bfa/bfad_debugfs.c b/drivers/scsi/bfa/bfad_debugfs.c
index 8e83d04..74a307c 100644
--- a/drivers/scsi/bfa/bfad_debugfs.c
+++ b/drivers/scsi/bfa/bfad_debugfs.c
@@ -260,18 +260,9 @@ bfad_debugfs_write_regrd(struct file *file, const char __user *buf,
unsigned long flags;
void *kern_buf;
- kern_buf = kzalloc(nbytes, GFP_KERNEL);
-
- if (!kern_buf) {
- printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
- bfad->inst_no);
- return -ENOMEM;
- }
-
- if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
- kfree(kern_buf);
- return -ENOMEM;
- }
+ kern_buf = memdup_user(buf, nbytes);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
rc = sscanf(kern_buf, "%x:%x", &addr, &len);
if (rc < 2) {
@@ -336,18 +327,9 @@ bfad_debugfs_write_regwr(struct file *file, const char __user *buf,
unsigned long flags;
void *kern_buf;
- kern_buf = kzalloc(nbytes, GFP_KERNEL);
-
- if (!kern_buf) {
- printk(KERN_INFO "bfad[%d]: Failed to allocate buffer\n",
- bfad->inst_no);
- return -ENOMEM;
- }
-
- if (copy_from_user(kern_buf, (void __user *)buf, nbytes)) {
- kfree(kern_buf);
- return -ENOMEM;
- }
+ kern_buf = memdup_user(buf, nbytes);
+ if (IS_ERR(kern_buf))
+ return PTR_ERR(kern_buf);
rc = sscanf(kern_buf, "%x:%x", &addr, &val);
if (rc < 2) {
diff --git a/drivers/scsi/bfa/bfad_im.c b/drivers/scsi/bfa/bfad_im.c
index f067332..7223b00 100644
--- a/drivers/scsi/bfa/bfad_im.c
+++ b/drivers/scsi/bfa/bfad_im.c
@@ -776,11 +776,7 @@ bfad_thread_workq(struct bfad_s *bfad)
static int
bfad_im_slave_configure(struct scsi_device *sdev)
{
- if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, bfa_lun_queue_depth);
- else
- scsi_deactivate_tcq(sdev, bfa_lun_queue_depth);
-
+ scsi_change_queue_depth(sdev, bfa_lun_queue_depth);
return 0;
}
@@ -804,6 +800,7 @@ struct scsi_host_template bfad_im_scsi_host_template = {
.shost_attrs = bfad_im_host_attrs,
.max_sectors = BFAD_MAX_SECTORS,
.vendor_id = BFA_PCI_VENDOR_ID_BROCADE,
+ .use_blk_tags = 1,
};
struct scsi_host_template bfad_im_vport_template = {
@@ -825,6 +822,7 @@ struct scsi_host_template bfad_im_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = bfad_im_vport_attrs,
.max_sectors = BFAD_MAX_SECTORS,
+ .use_blk_tags = 1,
};
bfa_status_t
@@ -868,14 +866,8 @@ bfad_ramp_up_qdepth(struct bfad_itnim_s *itnim, struct scsi_device *sdev)
if (bfa_lun_queue_depth > tmp_sdev->queue_depth) {
if (tmp_sdev->id != sdev->id)
continue;
- if (tmp_sdev->ordered_tags)
- scsi_adjust_queue_depth(tmp_sdev,
- MSG_ORDERED_TAG,
- tmp_sdev->queue_depth + 1);
- else
- scsi_adjust_queue_depth(tmp_sdev,
- MSG_SIMPLE_TAG,
- tmp_sdev->queue_depth + 1);
+ scsi_change_queue_depth(tmp_sdev,
+ tmp_sdev->queue_depth + 1);
itnim->last_ramp_up_time = jiffies;
}
diff --git a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
index 72533c5..e861f28 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_fcoe.c
@@ -1088,7 +1088,7 @@ static int bnx2fc_vport_create(struct fc_vport *vport, bool disabled)
mutex_unlock(&bnx2fc_dev_lock);
rtnl_unlock();
- if (IS_ERR(vn_port)) {
+ if (!vn_port) {
printk(KERN_ERR PFX "bnx2fc_vport_create (%s) failed\n",
netdev->name);
return -EIO;
@@ -2202,6 +2202,7 @@ static int _bnx2fc_create(struct net_device *netdev,
interface = bnx2fc_interface_create(hba, netdev, fip_mode);
if (!interface) {
printk(KERN_ERR PFX "bnx2fc_interface_create failed\n");
+ rc = -ENOMEM;
goto ifput_err;
}
@@ -2790,13 +2791,15 @@ static struct scsi_host_template bnx2fc_shost_template = {
.eh_target_reset_handler = bnx2fc_eh_target_reset, /* tgt reset */
.eh_host_reset_handler = fc_eh_host_reset,
.slave_alloc = fc_slave_alloc,
- .change_queue_depth = fc_change_queue_depth,
- .change_queue_type = fc_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = BNX2FC_MAX_BDS_PER_CMD,
.max_sectors = 1024,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static struct libfc_function_template bnx2fc_libfc_fcn_templ = {
diff --git a/drivers/scsi/bnx2fc/bnx2fc_io.c b/drivers/scsi/bnx2fc/bnx2fc_io.c
index 5b99844..4b56858 100644
--- a/drivers/scsi/bnx2fc/bnx2fc_io.c
+++ b/drivers/scsi/bnx2fc/bnx2fc_io.c
@@ -1725,7 +1725,6 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
struct fcp_cmnd *fcp_cmnd)
{
struct scsi_cmnd *sc_cmd = io_req->sc_cmd;
- char tag[2];
memset(fcp_cmnd, 0, sizeof(struct fcp_cmnd));
@@ -1739,21 +1738,10 @@ void bnx2fc_build_fcp_cmnd(struct bnx2fc_cmd *io_req,
fcp_cmnd->fc_tm_flags = io_req->mp_req.tm_flags;
fcp_cmnd->fc_flags = io_req->io_req_flags;
- if (scsi_populate_tag_msg(sc_cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- fcp_cmnd->fc_pri_ta = FCP_PTA_HEADQ;
- break;
- case ORDERED_QUEUE_TAG:
- fcp_cmnd->fc_pri_ta = FCP_PTA_ORDERED;
- break;
- default:
- fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
- break;
- }
- } else {
+ if (sc_cmd->flags & SCMD_TAGGED)
+ fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
+ else
fcp_cmnd->fc_pri_ta = 0;
- }
}
static void bnx2fc_parse_fcp_rsp(struct bnx2fc_cmd *io_req,
diff --git a/drivers/scsi/bnx2i/bnx2i_iscsi.c b/drivers/scsi/bnx2i/bnx2i_iscsi.c
index 7a36388..e53078d 100644
--- a/drivers/scsi/bnx2i/bnx2i_iscsi.c
+++ b/drivers/scsi/bnx2i/bnx2i_iscsi.c
@@ -2259,7 +2259,7 @@ static struct scsi_host_template bnx2i_host_template = {
.eh_abort_handler = iscsi_eh_abort,
.eh_device_reset_handler = iscsi_eh_device_reset,
.eh_target_reset_handler = iscsi_eh_recover_target,
- .change_queue_depth = iscsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.target_alloc = iscsi_target_alloc,
.can_queue = 2048,
.max_sectors = 127,
@@ -2268,6 +2268,7 @@ static struct scsi_host_template bnx2i_host_template = {
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = ISCSI_MAX_BDS_PER_CMD,
.shost_attrs = bnx2i_dev_attributes,
+ .track_queue_depth = 1,
};
struct iscsi_transport bnx2i_iscsi_transport = {
diff --git a/drivers/scsi/ch.c b/drivers/scsi/ch.c
index ef5ae0d..6bac8a7 100644
--- a/drivers/scsi/ch.c
+++ b/drivers/scsi/ch.c
@@ -85,8 +85,7 @@ static const char * vendor_labels[CH_TYPES-4] = {
// module_param_string_array(vendor_labels, NULL, 0444);
#define ch_printk(prefix, ch, fmt, a...) \
- sdev_printk(prefix, (ch)->device, "[%s] " fmt, \
- (ch)->name, ##a)
+ sdev_prefix_printk(prefix, (ch)->device, (ch)->name, fmt, ##a)
#define DPRINTK(fmt, arg...) \
do { \
@@ -183,7 +182,7 @@ static int ch_find_errno(struct scsi_sense_hdr *sshdr)
}
static int
-ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
+ch_do_scsi(scsi_changer *ch, unsigned char *cmd, int cmd_len,
void *buffer, unsigned buflength,
enum dma_data_direction direction)
{
@@ -197,7 +196,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
errno = 0;
if (debug) {
DPRINTK("command: ");
- __scsi_print_command(cmd);
+ __scsi_print_command(cmd, cmd_len);
}
result = scsi_execute_req(ch->device, cmd, direction, buffer,
@@ -207,7 +206,7 @@ ch_do_scsi(scsi_changer *ch, unsigned char *cmd,
DPRINTK("result: 0x%x\n",result);
if (driver_byte(result) & DRIVER_SENSE) {
if (debug)
- scsi_print_sense_hdr(ch->name, &sshdr);
+ scsi_print_sense_hdr(ch->device, ch->name, &sshdr);
errno = ch_find_errno(&sshdr);
switch(sshdr.sense_key) {
@@ -258,7 +257,8 @@ ch_read_element_status(scsi_changer *ch, u_int elem, char *data)
cmd[3] = elem & 0xff;
cmd[5] = 1;
cmd[9] = 255;
- if (0 == (result = ch_do_scsi(ch, cmd, buffer, 256, DMA_FROM_DEVICE))) {
+ if (0 == (result = ch_do_scsi(ch, cmd, 12,
+ buffer, 256, DMA_FROM_DEVICE))) {
if (((buffer[16] << 8) | buffer[17]) != elem) {
DPRINTK("asked for element 0x%02x, got 0x%02x\n",
elem,(buffer[16] << 8) | buffer[17]);
@@ -288,7 +288,7 @@ ch_init_elem(scsi_changer *ch)
memset(cmd,0,sizeof(cmd));
cmd[0] = INITIALIZE_ELEMENT_STATUS;
cmd[1] = (ch->device->lun & 0x7) << 5;
- err = ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
+ err = ch_do_scsi(ch, cmd, 6, NULL, 0, DMA_NONE);
VPRINTK(KERN_INFO, "... finished\n");
return err;
}
@@ -310,10 +310,10 @@ ch_readconfig(scsi_changer *ch)
cmd[1] = (ch->device->lun & 0x7) << 5;
cmd[2] = 0x1d;
cmd[4] = 255;
- result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
+ result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
if (0 != result) {
cmd[1] |= (1<<3);
- result = ch_do_scsi(ch, cmd, buffer, 255, DMA_FROM_DEVICE);
+ result = ch_do_scsi(ch, cmd, 10, buffer, 255, DMA_FROM_DEVICE);
}
if (0 == result) {
ch->firsts[CHET_MT] =
@@ -438,7 +438,7 @@ ch_position(scsi_changer *ch, u_int trans, u_int elem, int rotate)
cmd[4] = (elem >> 8) & 0xff;
cmd[5] = elem & 0xff;
cmd[8] = rotate ? 1 : 0;
- return ch_do_scsi(ch, cmd, NULL, 0, DMA_NONE);
+ return ch_do_scsi(ch, cmd, 10, NULL, 0, DMA_NONE);
}
static int
@@ -459,7 +459,7 @@ ch_move(scsi_changer *ch, u_int trans, u_int src, u_int dest, int rotate)
cmd[6] = (dest >> 8) & 0xff;
cmd[7] = dest & 0xff;
cmd[10] = rotate ? 1 : 0;
- return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
+ return ch_do_scsi(ch, cmd, 12, NULL,0, DMA_NONE);
}
static int
@@ -485,7 +485,7 @@ ch_exchange(scsi_changer *ch, u_int trans, u_int src,
cmd[9] = dest2 & 0xff;
cmd[10] = (rotate1 ? 1 : 0) | (rotate2 ? 2 : 0);
- return ch_do_scsi(ch, cmd, NULL,0, DMA_NONE);
+ return ch_do_scsi(ch, cmd, 12, NULL, 0, DMA_NONE);
}
static void
@@ -535,7 +535,7 @@ ch_set_voltag(scsi_changer *ch, u_int elem,
memcpy(buffer,tag,32);
ch_check_voltag(buffer);
- result = ch_do_scsi(ch, cmd, buffer, 256, DMA_TO_DEVICE);
+ result = ch_do_scsi(ch, cmd, 12, buffer, 256, DMA_TO_DEVICE);
kfree(buffer);
return result;
}
@@ -616,6 +616,11 @@ static long ch_ioctl(struct file *file,
int retval;
void __user *argp = (void __user *)arg;
+ retval = scsi_ioctl_block_when_processing_errors(ch->device, cmd,
+ file->f_flags & O_NDELAY);
+ if (retval)
+ return retval;
+
switch (cmd) {
case CHIOGPARAMS:
{
@@ -766,7 +771,8 @@ static long ch_ioctl(struct file *file,
ch_cmd[5] = 1;
ch_cmd[9] = 255;
- result = ch_do_scsi(ch, ch_cmd, buffer, 256, DMA_FROM_DEVICE);
+ result = ch_do_scsi(ch, ch_cmd, 12,
+ buffer, 256, DMA_FROM_DEVICE);
if (!result) {
cge.cge_status = buffer[18];
cge.cge_flags = 0;
@@ -966,9 +972,9 @@ static int ch_remove(struct device *dev)
}
static struct scsi_driver ch_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "ch",
+ .owner = THIS_MODULE,
.probe = ch_probe,
.remove = ch_remove,
},
diff --git a/drivers/scsi/constants.c b/drivers/scsi/constants.c
index d35a5d6..e2068a2 100644
--- a/drivers/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -21,15 +21,21 @@
/* Commands with service actions that change the command name */
-#define SERVICE_ACTION_IN_12 0xab
-#define SERVICE_ACTION_OUT_12 0xa9
-#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
-#define SERVICE_ACTION_IN_16 0x9e
-#define SERVICE_ACTION_OUT_16 0x9f
#define THIRD_PARTY_COPY_OUT 0x83
#define THIRD_PARTY_COPY_IN 0x84
+#define VENDOR_SPECIFIC_CDB 0xc0
+struct sa_name_list {
+ int opcode;
+ const struct value_name_pair *arr;
+ int arr_sz;
+};
+
+struct value_name_pair {
+ int value;
+ const char * name;
+};
#ifdef CONFIG_SCSI_CONSTANTS
static const char * cdb_byte0_names[] = {
@@ -102,11 +108,6 @@ static const char * cdb_byte0_names[] = {
"Volume set (out), Send DVD structure",
};
-struct value_name_pair {
- int value;
- const char * name;
-};
-
static const struct value_name_pair maint_in_arr[] = {
{0x5, "Report identifying information"},
{0xa, "Report target port groups"},
@@ -244,170 +245,119 @@ static const struct value_name_pair variable_length_arr[] = {
};
#define VARIABLE_LENGTH_SZ ARRAY_SIZE(variable_length_arr)
-static const char * get_sa_name(const struct value_name_pair * arr,
- int arr_sz, int service_action)
-{
- int k;
+static struct sa_name_list sa_names_arr[] = {
+ {VARIABLE_LENGTH_CMD, variable_length_arr, VARIABLE_LENGTH_SZ},
+ {MAINTENANCE_IN, maint_in_arr, MAINT_IN_SZ},
+ {MAINTENANCE_OUT, maint_out_arr, MAINT_OUT_SZ},
+ {PERSISTENT_RESERVE_IN, pr_in_arr, PR_IN_SZ},
+ {PERSISTENT_RESERVE_OUT, pr_out_arr, PR_OUT_SZ},
+ {SERVICE_ACTION_IN_12, serv_in12_arr, SERV_IN12_SZ},
+ {SERVICE_ACTION_OUT_12, serv_out12_arr, SERV_OUT12_SZ},
+ {SERVICE_ACTION_BIDIRECTIONAL, serv_bidi_arr, SERV_BIDI_SZ},
+ {SERVICE_ACTION_IN_16, serv_in16_arr, SERV_IN16_SZ},
+ {SERVICE_ACTION_OUT_16, serv_out16_arr, SERV_OUT16_SZ},
+ {THIRD_PARTY_COPY_IN, tpc_in_arr, TPC_IN_SZ},
+ {THIRD_PARTY_COPY_OUT, tpc_out_arr, TPC_OUT_SZ},
+ {0, NULL, 0},
+};
- for (k = 0; k < arr_sz; ++k, ++arr) {
- if (service_action == arr->value)
- break;
- }
- return (k < arr_sz) ? arr->name : NULL;
-}
+#else /* ifndef CONFIG_SCSI_CONSTANTS */
+static const char *cdb_byte0_names[0];
+
+static struct sa_name_list sa_names_arr[] = {
+ {VARIABLE_LENGTH_CMD, NULL, 0},
+ {MAINTENANCE_IN, NULL, 0},
+ {MAINTENANCE_OUT, NULL, 0},
+ {PERSISTENT_RESERVE_IN, NULL, 0},
+ {PERSISTENT_RESERVE_OUT, NULL, 0},
+ {SERVICE_ACTION_IN_12, NULL, 0},
+ {SERVICE_ACTION_OUT_12, NULL, 0},
+ {SERVICE_ACTION_BIDIRECTIONAL, NULL, 0},
+ {SERVICE_ACTION_IN_16, NULL, 0},
+ {SERVICE_ACTION_OUT_16, NULL, 0},
+ {THIRD_PARTY_COPY_IN, NULL, 0},
+ {THIRD_PARTY_COPY_OUT, NULL, 0},
+ {0, NULL, 0},
+};
+#endif /* CONFIG_SCSI_CONSTANTS */
-/* attempt to guess cdb length if cdb_len==0 . No trailing linefeed. */
-static void print_opcode_name(unsigned char * cdbp, int cdb_len)
+static bool scsi_opcode_sa_name(int opcode, int service_action,
+ const char **cdb_name, const char **sa_name)
{
- int sa, len, cdb0;
- int fin_name = 0;
- const char * name;
+ struct sa_name_list *sa_name_ptr;
+ const struct value_name_pair *arr = NULL;
+ int arr_sz, k;
- cdb0 = cdbp[0];
- switch(cdb0) {
- case VARIABLE_LENGTH_CMD:
- len = scsi_varlen_cdb_length(cdbp);
- if (len < 10) {
- printk("short variable length command, "
- "len=%d ext_len=%d", len, cdb_len);
- break;
- }
- sa = (cdbp[8] << 8) + cdbp[9];
- name = get_sa_name(variable_length_arr, VARIABLE_LENGTH_SZ,
- sa);
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ *cdb_name = NULL;
+ if (opcode >= VENDOR_SPECIFIC_CDB)
+ return false;
- if ((cdb_len > 0) && (len != cdb_len))
- printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
+ if (opcode < ARRAY_SIZE(cdb_byte0_names))
+ *cdb_name = cdb_byte0_names[opcode];
- break;
- case MAINTENANCE_IN:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(maint_in_arr, MAINT_IN_SZ, sa);
- fin_name = 1;
- break;
- case MAINTENANCE_OUT:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(maint_out_arr, MAINT_OUT_SZ, sa);
- fin_name = 1;
- break;
- case PERSISTENT_RESERVE_IN:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(pr_in_arr, PR_IN_SZ, sa);
- fin_name = 1;
- break;
- case PERSISTENT_RESERVE_OUT:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(pr_out_arr, PR_OUT_SZ, sa);
- fin_name = 1;
- break;
- case SERVICE_ACTION_IN_12:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(serv_in12_arr, SERV_IN12_SZ, sa);
- fin_name = 1;
- break;
- case SERVICE_ACTION_OUT_12:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(serv_out12_arr, SERV_OUT12_SZ, sa);
- fin_name = 1;
- break;
- case SERVICE_ACTION_BIDIRECTIONAL:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(serv_bidi_arr, SERV_BIDI_SZ, sa);
- fin_name = 1;
- break;
- case SERVICE_ACTION_IN_16:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(serv_in16_arr, SERV_IN16_SZ, sa);
- fin_name = 1;
- break;
- case SERVICE_ACTION_OUT_16:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(serv_out16_arr, SERV_OUT16_SZ, sa);
- fin_name = 1;
- break;
- case THIRD_PARTY_COPY_IN:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(tpc_in_arr, TPC_IN_SZ, sa);
- fin_name = 1;
- break;
- case THIRD_PARTY_COPY_OUT:
- sa = cdbp[1] & 0x1f;
- name = get_sa_name(tpc_out_arr, TPC_OUT_SZ, sa);
- fin_name = 1;
- break;
- default:
- if (cdb0 < 0xc0) {
- name = cdb_byte0_names[cdb0];
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x (reserved)", cdb0);
- } else
- printk("cdb[0]=0x%x (vendor)", cdb0);
- break;
+ for (sa_name_ptr = sa_names_arr; sa_name_ptr->arr; ++sa_name_ptr) {
+ if (sa_name_ptr->opcode == opcode) {
+ arr = sa_name_ptr->arr;
+ arr_sz = sa_name_ptr->arr_sz;
+ break;
+ }
}
- if (fin_name) {
- if (name)
- printk("%s", name);
- else
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
+ if (!arr)
+ return false;
+
+ for (k = 0; k < arr_sz; ++k, ++arr) {
+ if (service_action == arr->value)
+ break;
}
-}
+ if (k < arr_sz)
+ *sa_name = arr->name;
-#else /* ifndef CONFIG_SCSI_CONSTANTS */
+ return true;
+}
-static void print_opcode_name(unsigned char * cdbp, int cdb_len)
+static void print_opcode_name(const unsigned char *cdbp, size_t cdb_len)
{
- int sa, len, cdb0;
+ int sa, cdb0;
+ const char *cdb_name = NULL, *sa_name = NULL;
cdb0 = cdbp[0];
- switch(cdb0) {
- case VARIABLE_LENGTH_CMD:
- len = scsi_varlen_cdb_length(cdbp);
- if (len < 10) {
- printk("short opcode=0x%x command, len=%d "
- "ext_len=%d", cdb0, len, cdb_len);
- break;
+ if (cdb0 == VARIABLE_LENGTH_CMD) {
+ if (cdb_len < 10) {
+ printk("short variable length command, len=%zu",
+ cdb_len);
+ return;
}
sa = (cdbp[8] << 8) + cdbp[9];
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
- if (len != cdb_len)
- printk(", in_cdb_len=%d, ext_len=%d", len, cdb_len);
- break;
- case MAINTENANCE_IN:
- case MAINTENANCE_OUT:
- case PERSISTENT_RESERVE_IN:
- case PERSISTENT_RESERVE_OUT:
- case SERVICE_ACTION_IN_12:
- case SERVICE_ACTION_OUT_12:
- case SERVICE_ACTION_BIDIRECTIONAL:
- case SERVICE_ACTION_IN_16:
- case SERVICE_ACTION_OUT_16:
- case THIRD_PARTY_COPY_IN:
- case THIRD_PARTY_COPY_OUT:
+ } else
sa = cdbp[1] & 0x1f;
- printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
- break;
- default:
- if (cdb0 < 0xc0)
+
+ if (!scsi_opcode_sa_name(cdb0, sa, &cdb_name, &sa_name)) {
+ if (cdb_name)
+ printk("%s", cdb_name);
+ else if (cdb0 >= VENDOR_SPECIFIC_CDB)
+ printk("cdb[0]=0x%x (vendor)", cdb0);
+ else if (cdb0 >= 0x60 && cdb0 < 0x7e)
+ printk("cdb[0]=0x%x (reserved)", cdb0);
+ else
printk("cdb[0]=0x%x", cdb0);
+ } else {
+ if (sa_name)
+ printk("%s", sa_name);
+ else if (cdb_name)
+ printk("%s, sa=0x%x", cdb_name, sa);
else
- printk("cdb[0]=0x%x (vendor)", cdb0);
- break;
+ printk("cdb[0]=0x%x, sa=0x%x", cdb0, sa);
}
}
-#endif
-void __scsi_print_command(unsigned char *cdb)
+void __scsi_print_command(const unsigned char *cdb, size_t cdb_len)
{
int k, len;
- print_opcode_name(cdb, 0);
+ print_opcode_name(cdb, cdb_len);
len = scsi_command_size(cdb);
+ if (cdb_len < len)
+ len = cdb_len;
/* print out all bytes in cdb */
for (k = 0; k < len; ++k)
printk(" %02x", cdb[k]);
@@ -433,41 +383,6 @@ void scsi_print_command(struct scsi_cmnd *cmd)
}
EXPORT_SYMBOL(scsi_print_command);
-/**
- * scsi_print_status - print scsi status description
- * @scsi_status: scsi status value
- *
- * If the status is recognized, the description is printed.
- * Otherwise "Unknown status" is output. No trailing space.
- * If CONFIG_SCSI_CONSTANTS is not set, then print status in hex
- * (e.g. "0x2" for Check Condition).
- **/
-void
-scsi_print_status(unsigned char scsi_status) {
-#ifdef CONFIG_SCSI_CONSTANTS
- const char * ccp;
-
- switch (scsi_status) {
- case 0: ccp = "Good"; break;
- case 0x2: ccp = "Check Condition"; break;
- case 0x4: ccp = "Condition Met"; break;
- case 0x8: ccp = "Busy"; break;
- case 0x10: ccp = "Intermediate"; break;
- case 0x14: ccp = "Intermediate-Condition Met"; break;
- case 0x18: ccp = "Reservation Conflict"; break;
- case 0x22: ccp = "Command Terminated"; break; /* obsolete */
- case 0x28: ccp = "Task set Full"; break; /* was: Queue Full */
- case 0x30: ccp = "ACA Active"; break;
- case 0x40: ccp = "Task Aborted"; break;
- default: ccp = "Unknown status";
- }
- printk(KERN_INFO "%s", ccp);
-#else
- printk(KERN_INFO "0x%0x", scsi_status);
-#endif
-}
-EXPORT_SYMBOL(scsi_print_status);
-
#ifdef CONFIG_SCSI_CONSTANTS
struct error_info {
@@ -1292,18 +1207,19 @@ static const struct error_info additional[] =
struct error_info2 {
unsigned char code1, code2_min, code2_max;
+ const char * str;
const char * fmt;
};
static const struct error_info2 additional2[] =
{
- {0x40, 0x00, 0x7f, "Ram failure (%x)"},
- {0x40, 0x80, 0xff, "Diagnostic failure on component (%x)"},
- {0x41, 0x00, 0xff, "Data path failure (%x)"},
- {0x42, 0x00, 0xff, "Power-on or self-test failure (%x)"},
- {0x4D, 0x00, 0xff, "Tagged overlapped commands (task tag %x)"},
- {0x70, 0x00, 0xff, "Decompression exception short algorithm id of %x"},
- {0, 0, 0, NULL}
+ {0x40, 0x00, 0x7f, "Ram failure", ""},
+ {0x40, 0x80, 0xff, "Diagnostic failure on component", ""},
+ {0x41, 0x00, 0xff, "Data path failure", ""},
+ {0x42, 0x00, 0xff, "Power-on or self-test failure", ""},
+ {0x4D, 0x00, 0xff, "Tagged overlapped commands", "task tag "},
+ {0x70, 0x00, 0xff, "Decompression exception", "short algorithm id of "},
+ {0, 0, 0, NULL, NULL}
};
/* description of the sense key values */
@@ -1349,69 +1265,79 @@ EXPORT_SYMBOL(scsi_sense_key_string);
* This string may contain a "%x" and should be printed with ascq as arg.
*/
const char *
-scsi_extd_sense_format(unsigned char asc, unsigned char ascq) {
+scsi_extd_sense_format(unsigned char asc, unsigned char ascq, const char **fmt)
+{
#ifdef CONFIG_SCSI_CONSTANTS
int i;
unsigned short code = ((asc << 8) | ascq);
+ *fmt = NULL;
for (i = 0; additional[i].text; i++)
if (additional[i].code12 == code)
return additional[i].text;
for (i = 0; additional2[i].fmt; i++) {
if (additional2[i].code1 == asc &&
ascq >= additional2[i].code2_min &&
- ascq <= additional2[i].code2_max)
- return additional2[i].fmt;
+ ascq <= additional2[i].code2_max) {
+ *fmt = additional2[i].fmt;
+ return additional2[i].str;
+ }
}
+#else
+ *fmt = NULL;
#endif
return NULL;
}
EXPORT_SYMBOL(scsi_extd_sense_format);
void
-scsi_show_extd_sense(unsigned char asc, unsigned char ascq)
+scsi_show_extd_sense(const struct scsi_device *sdev, const char *name,
+ unsigned char asc, unsigned char ascq)
{
- const char *extd_sense_fmt = scsi_extd_sense_format(asc, ascq);
-
- if (extd_sense_fmt) {
- if (strstr(extd_sense_fmt, "%x")) {
- printk("Add. Sense: ");
- printk(extd_sense_fmt, ascq);
- } else
- printk("Add. Sense: %s", extd_sense_fmt);
- } else {
- if (asc >= 0x80)
- printk("<<vendor>> ASC=0x%x ASCQ=0x%x", asc,
- ascq);
- if (ascq >= 0x80)
- printk("ASC=0x%x <<vendor>> ASCQ=0x%x", asc,
- ascq);
+ const char *extd_sense_fmt = NULL;
+ const char *extd_sense_str = scsi_extd_sense_format(asc, ascq,
+ &extd_sense_fmt);
+
+ if (extd_sense_str) {
+ if (extd_sense_fmt)
+ sdev_prefix_printk(KERN_INFO, sdev, name,
+ "Add. Sense: %s (%s%x)",
+ extd_sense_str, extd_sense_fmt,
+ ascq);
else
- printk("ASC=0x%x ASCQ=0x%x", asc, ascq);
- }
+ sdev_prefix_printk(KERN_INFO, sdev, name,
+ "Add. Sense: %s", extd_sense_str);
- printk("\n");
+ } else {
+ sdev_prefix_printk(KERN_INFO, sdev, name,
+ "%sASC=0x%x %sASCQ=0x%x\n",
+ asc >= 0x80 ? "<<vendor>> " : "", asc,
+ ascq >= 0x80 ? "<<vendor>> " : "", ascq);
+ }
}
EXPORT_SYMBOL(scsi_show_extd_sense);
void
-scsi_show_sense_hdr(struct scsi_sense_hdr *sshdr)
+scsi_show_sense_hdr(const struct scsi_device *sdev, const char *name,
+ const struct scsi_sense_hdr *sshdr)
{
const char *sense_txt;
sense_txt = scsi_sense_key_string(sshdr->sense_key);
if (sense_txt)
- printk("Sense Key : %s ", sense_txt);
+ sdev_prefix_printk(KERN_INFO, sdev, name,
+ "Sense Key : %s [%s]%s\n", sense_txt,
+ scsi_sense_is_deferred(sshdr) ?
+ "deferred" : "current",
+ sshdr->response_code >= 0x72 ?
+ " [descriptor]" : "");
else
- printk("Sense Key : 0x%x ", sshdr->sense_key);
-
- printk("%s", scsi_sense_is_deferred(sshdr) ? "[deferred] " :
- "[current] ");
-
- if (sshdr->response_code >= 0x72)
- printk("[descriptor]");
-
- printk("\n");
+ sdev_prefix_printk(KERN_INFO, sdev, name,
+ "Sense Key : 0x%x [%s]%s", sshdr->sense_key,
+ scsi_sense_is_deferred(sshdr) ?
+ "deferred" : "current",
+ sshdr->response_code >= 0x72 ?
+ " [descriptor]" : "");
}
EXPORT_SYMBOL(scsi_show_sense_hdr);
@@ -1419,141 +1345,55 @@ EXPORT_SYMBOL(scsi_show_sense_hdr);
* Print normalized SCSI sense header with a prefix.
*/
void
-scsi_print_sense_hdr(const char *name, struct scsi_sense_hdr *sshdr)
+scsi_print_sense_hdr(const struct scsi_device *sdev, const char *name,
+ const struct scsi_sense_hdr *sshdr)
{
- printk(KERN_INFO "%s: ", name);
- scsi_show_sense_hdr(sshdr);
- printk(KERN_INFO "%s: ", name);
- scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+ scsi_show_sense_hdr(sdev, name, sshdr);
+ scsi_show_extd_sense(sdev, name, sshdr->asc, sshdr->ascq);
}
EXPORT_SYMBOL(scsi_print_sense_hdr);
-/*
- * Print normalized SCSI sense header with device information and a prefix.
- */
-void
-scsi_cmd_print_sense_hdr(struct scsi_cmnd *scmd, const char *desc,
- struct scsi_sense_hdr *sshdr)
-{
- scmd_printk(KERN_INFO, scmd, "%s: ", desc);
- scsi_show_sense_hdr(sshdr);
- scmd_printk(KERN_INFO, scmd, "%s: ", desc);
- scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
-}
-EXPORT_SYMBOL(scsi_cmd_print_sense_hdr);
-
static void
-scsi_decode_sense_buffer(const unsigned char *sense_buffer, int sense_len,
- struct scsi_sense_hdr *sshdr)
+scsi_dump_sense_buffer(const unsigned char *sense_buffer, int sense_len)
{
- int k, num, res;
-
- res = scsi_normalize_sense(sense_buffer, sense_len, sshdr);
- if (0 == res) {
- /* this may be SCSI-1 sense data */
- num = (sense_len < 32) ? sense_len : 32;
- printk("Unrecognized sense data (in hex):");
- for (k = 0; k < num; ++k) {
- if (0 == (k % 16)) {
- printk("\n");
- printk(KERN_INFO " ");
- }
- printk("%02x ", sense_buffer[k]);
+ int k, num;
+
+ num = (sense_len < 32) ? sense_len : 32;
+ printk("Unrecognized sense data (in hex):");
+ for (k = 0; k < num; ++k) {
+ if (0 == (k % 16)) {
+ printk("\n");
+ printk(KERN_INFO " ");
}
- printk("\n");
- return;
+ printk("%02x ", sense_buffer[k]);
}
-}
-
-static void
-scsi_decode_sense_extras(const unsigned char *sense_buffer, int sense_len,
- struct scsi_sense_hdr *sshdr)
-{
- int k, num, res;
-
- if (sshdr->response_code < 0x72)
- {
- /* only decode extras for "fixed" format now */
- char buff[80];
- int blen, fixed_valid;
- unsigned int info;
-
- fixed_valid = sense_buffer[0] & 0x80;
- info = ((sense_buffer[3] << 24) | (sense_buffer[4] << 16) |
- (sense_buffer[5] << 8) | sense_buffer[6]);
- res = 0;
- memset(buff, 0, sizeof(buff));
- blen = sizeof(buff) - 1;
- if (fixed_valid)
- res += snprintf(buff + res, blen - res,
- "Info fld=0x%x", info);
- if (sense_buffer[2] & 0x80) {
- /* current command has read a filemark */
- if (res > 0)
- res += snprintf(buff + res, blen - res, ", ");
- res += snprintf(buff + res, blen - res, "FMK");
- }
- if (sense_buffer[2] & 0x40) {
- /* end-of-medium condition exists */
- if (res > 0)
- res += snprintf(buff + res, blen - res, ", ");
- res += snprintf(buff + res, blen - res, "EOM");
- }
- if (sense_buffer[2] & 0x20) {
- /* incorrect block length requested */
- if (res > 0)
- res += snprintf(buff + res, blen - res, ", ");
- res += snprintf(buff + res, blen - res, "ILI");
- }
- if (res > 0)
- printk("%s\n", buff);
- } else if (sshdr->additional_length > 0) {
- /* descriptor format with sense descriptors */
- num = 8 + sshdr->additional_length;
- num = (sense_len < num) ? sense_len : num;
- printk("Descriptor sense data with sense descriptors "
- "(in hex):");
- for (k = 0; k < num; ++k) {
- if (0 == (k % 16)) {
- printk("\n");
- printk(KERN_INFO " ");
- }
- printk("%02x ", sense_buffer[k]);
- }
-
- printk("\n");
- }
-
+ printk("\n");
+ return;
}
/* Normalize and print sense buffer with name prefix */
-void __scsi_print_sense(const char *name, const unsigned char *sense_buffer,
- int sense_len)
+void __scsi_print_sense(const struct scsi_device *sdev, const char *name,
+ const unsigned char *sense_buffer, int sense_len)
{
struct scsi_sense_hdr sshdr;
- printk(KERN_INFO "%s: ", name);
- scsi_decode_sense_buffer(sense_buffer, sense_len, &sshdr);
- scsi_show_sense_hdr(&sshdr);
- scsi_decode_sense_extras(sense_buffer, sense_len, &sshdr);
- printk(KERN_INFO "%s: ", name);
- scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
+ if (!scsi_normalize_sense(sense_buffer, sense_len, &sshdr)) {
+ scsi_dump_sense_buffer(sense_buffer, sense_len);
+ return;
+ }
+ scsi_show_sense_hdr(sdev, name, &sshdr);
+ scsi_show_extd_sense(sdev, name, sshdr.asc, sshdr.ascq);
}
EXPORT_SYMBOL(__scsi_print_sense);
/* Normalize and print sense buffer in SCSI command */
-void scsi_print_sense(char *name, struct scsi_cmnd *cmd)
+void scsi_print_sense(const struct scsi_cmnd *cmd)
{
- struct scsi_sense_hdr sshdr;
+ struct gendisk *disk = cmd->request->rq_disk;
+ const char *disk_name = disk ? disk->disk_name : NULL;
- scmd_printk(KERN_INFO, cmd, " ");
- scsi_decode_sense_buffer(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
- &sshdr);
- scsi_show_sense_hdr(&sshdr);
- scsi_decode_sense_extras(cmd->sense_buffer, SCSI_SENSE_BUFFERSIZE,
- &sshdr);
- scmd_printk(KERN_INFO, cmd, " ");
- scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
+ __scsi_print_sense(cmd->device, disk_name, cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE);
}
EXPORT_SYMBOL(scsi_print_sense);
@@ -1565,38 +1405,87 @@ static const char * const hostbyte_table[]={
"DID_PASSTHROUGH", "DID_SOFT_ERROR", "DID_IMM_RETRY", "DID_REQUEUE",
"DID_TRANSPORT_DISRUPTED", "DID_TRANSPORT_FAILFAST", "DID_TARGET_FAILURE",
"DID_NEXUS_FAILURE" };
-#define NUM_HOSTBYTE_STRS ARRAY_SIZE(hostbyte_table)
static const char * const driverbyte_table[]={
"DRIVER_OK", "DRIVER_BUSY", "DRIVER_SOFT", "DRIVER_MEDIA", "DRIVER_ERROR",
"DRIVER_INVALID", "DRIVER_TIMEOUT", "DRIVER_HARD", "DRIVER_SENSE"};
-#define NUM_DRIVERBYTE_STRS ARRAY_SIZE(driverbyte_table)
-void scsi_show_result(int result)
+#endif
+
+const char *scsi_hostbyte_string(int result)
{
+ const char *hb_string = NULL;
+#ifdef CONFIG_SCSI_CONSTANTS
int hb = host_byte(result);
- int db = driver_byte(result);
- printk("Result: hostbyte=%s driverbyte=%s\n",
- (hb < NUM_HOSTBYTE_STRS ? hostbyte_table[hb] : "invalid"),
- (db < NUM_DRIVERBYTE_STRS ? driverbyte_table[db] : "invalid"));
+ if (hb < ARRAY_SIZE(hostbyte_table))
+ hb_string = hostbyte_table[hb];
+#endif
+ return hb_string;
}
+EXPORT_SYMBOL(scsi_hostbyte_string);
-#else
-
-void scsi_show_result(int result)
+const char *scsi_driverbyte_string(int result)
{
- printk("Result: hostbyte=0x%02x driverbyte=0x%02x\n",
- host_byte(result), driver_byte(result));
+ const char *db_string = NULL;
+#ifdef CONFIG_SCSI_CONSTANTS
+ int db = driver_byte(result);
+
+ if (db < ARRAY_SIZE(driverbyte_table))
+ db_string = driverbyte_table[db];
+#endif
+ return db_string;
}
+EXPORT_SYMBOL(scsi_driverbyte_string);
+#ifdef CONFIG_SCSI_CONSTANTS
+#define scsi_mlreturn_name(result) { result, #result }
+static const struct value_name_pair scsi_mlreturn_arr[] = {
+ scsi_mlreturn_name(NEEDS_RETRY),
+ scsi_mlreturn_name(SUCCESS),
+ scsi_mlreturn_name(FAILED),
+ scsi_mlreturn_name(QUEUED),
+ scsi_mlreturn_name(SOFT_ERROR),
+ scsi_mlreturn_name(ADD_TO_MLQUEUE),
+ scsi_mlreturn_name(TIMEOUT_ERROR),
+ scsi_mlreturn_name(SCSI_RETURN_NOT_HANDLED),
+ scsi_mlreturn_name(FAST_IO_FAIL)
+};
#endif
-EXPORT_SYMBOL(scsi_show_result);
+const char *scsi_mlreturn_string(int result)
+{
+#ifdef CONFIG_SCSI_CONSTANTS
+ const struct value_name_pair *arr = scsi_mlreturn_arr;
+ int k;
-void scsi_print_result(struct scsi_cmnd *cmd)
+ for (k = 0; k < ARRAY_SIZE(scsi_mlreturn_arr); ++k, ++arr) {
+ if (result == arr->value)
+ return arr->name;
+ }
+#endif
+ return NULL;
+}
+EXPORT_SYMBOL(scsi_mlreturn_string);
+
+void scsi_print_result(struct scsi_cmnd *cmd, const char *msg, int disposition)
{
- scmd_printk(KERN_INFO, cmd, " ");
- scsi_show_result(cmd->result);
+ const char *mlret_string = scsi_mlreturn_string(disposition);
+ const char *hb_string = scsi_hostbyte_string(cmd->result);
+ const char *db_string = scsi_driverbyte_string(cmd->result);
+
+ if (hb_string || db_string)
+ scmd_printk(KERN_INFO, cmd,
+ "%s%s Result: hostbyte=%s driverbyte=%s",
+ msg ? msg : "",
+ mlret_string ? mlret_string : "UNKNOWN",
+ hb_string ? hb_string : "invalid",
+ db_string ? db_string : "invalid");
+ else
+ scmd_printk(KERN_INFO, cmd,
+ "%s%s Result: hostbyte=0x%02x driverbyte=0x%02x",
+ msg ? msg : "",
+ mlret_string ? mlret_string : "UNKNOWN",
+ host_byte(cmd->result), driver_byte(cmd->result));
}
EXPORT_SYMBOL(scsi_print_result);
diff --git a/drivers/scsi/csiostor/csio_scsi.c b/drivers/scsi/csiostor/csio_scsi.c
index b9c012b..51ea5dc 100644
--- a/drivers/scsi/csiostor/csio_scsi.c
+++ b/drivers/scsi/csiostor/csio_scsi.c
@@ -152,28 +152,6 @@ csio_scsi_itnexus_loss_error(uint16_t error)
return 0;
}
-static inline void
-csio_scsi_tag(struct scsi_cmnd *scmnd, uint8_t *tag, uint8_t hq,
- uint8_t oq, uint8_t sq)
-{
- char stag[2];
-
- if (scsi_populate_tag_msg(scmnd, stag)) {
- switch (stag[0]) {
- case HEAD_OF_QUEUE_TAG:
- *tag = hq;
- break;
- case ORDERED_QUEUE_TAG:
- *tag = oq;
- break;
- default:
- *tag = sq;
- break;
- }
- } else
- *tag = 0;
-}
-
/*
* csio_scsi_fcp_cmnd - Frame the SCSI FCP command paylod.
* @req: IO req structure.
@@ -192,11 +170,12 @@ csio_scsi_fcp_cmnd(struct csio_ioreq *req, void *addr)
int_to_scsilun(scmnd->device->lun, &fcp_cmnd->fc_lun);
fcp_cmnd->fc_tm_flags = 0;
fcp_cmnd->fc_cmdref = 0;
- fcp_cmnd->fc_pri_ta = 0;
memcpy(fcp_cmnd->fc_cdb, scmnd->cmnd, 16);
- csio_scsi_tag(scmnd, &fcp_cmnd->fc_pri_ta,
- FCP_PTA_HEADQ, FCP_PTA_ORDERED, FCP_PTA_SIMPLE);
+ if (scmnd->flags & SCMD_TAGGED)
+ fcp_cmnd->fc_pri_ta = FCP_PTA_SIMPLE;
+ else
+ fcp_cmnd->fc_pri_ta = 0;
fcp_cmnd->fc_dl = cpu_to_be32(scsi_bufflen(scmnd));
if (req->nsge)
@@ -2262,11 +2241,7 @@ csio_slave_alloc(struct scsi_device *sdev)
static int
csio_slave_configure(struct scsi_device *sdev)
{
- if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, csio_lun_qdepth);
- else
- scsi_deactivate_tcq(sdev, csio_lun_qdepth);
-
+ scsi_change_queue_depth(sdev, csio_lun_qdepth);
return 0;
}
@@ -2311,6 +2286,7 @@ struct scsi_host_template csio_fcoe_shost_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = csio_fcoe_lport_attrs,
.max_sectors = CSIO_MAX_SECTOR_SIZE,
+ .use_blk_tags = 1,
};
struct scsi_host_template csio_fcoe_shost_vport_template = {
@@ -2330,6 +2306,7 @@ struct scsi_host_template csio_fcoe_shost_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = csio_fcoe_vport_attrs,
.max_sectors = CSIO_MAX_SECTOR_SIZE,
+ .use_blk_tags = 1,
};
/*
diff --git a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
index 49692a1..3db4c63 100644
--- a/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
+++ b/drivers/scsi/cxgbi/cxgb3i/cxgb3i.c
@@ -86,7 +86,7 @@ static struct scsi_host_template cxgb3i_host_template = {
.proc_name = DRV_MODULE_NAME,
.can_queue = CXGB3I_SCSI_HOST_QDEPTH,
.queuecommand = iscsi_queuecommand,
- .change_queue_depth = iscsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
@@ -96,6 +96,7 @@ static struct scsi_host_template cxgb3i_host_template = {
.target_alloc = iscsi_target_alloc,
.use_clustering = DISABLE_CLUSTERING,
.this_id = -1,
+ .track_queue_depth = 1,
};
static struct iscsi_transport cxgb3i_iscsi_transport = {
diff --git a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
index dd5f4e0..69fbfc8 100644
--- a/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
+++ b/drivers/scsi/cxgbi/cxgb4i/cxgb4i.c
@@ -89,7 +89,7 @@ static struct scsi_host_template cxgb4i_host_template = {
.proc_name = DRV_MODULE_NAME,
.can_queue = CXGB4I_SCSI_HOST_QDEPTH,
.queuecommand = iscsi_queuecommand,
- .change_queue_depth = iscsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.sg_tablesize = SG_ALL,
.max_sectors = 0xFFFF,
.cmd_per_lun = ISCSI_DEF_CMD_PER_LUN,
@@ -99,6 +99,7 @@ static struct scsi_host_template cxgb4i_host_template = {
.target_alloc = iscsi_target_alloc,
.use_clustering = DISABLE_CLUSTERING,
.this_id = -1,
+ .track_queue_depth = 1,
};
static struct iscsi_transport cxgb4i_iscsi_transport = {
diff --git a/drivers/scsi/device_handler/scsi_dh.c b/drivers/scsi/device_handler/scsi_dh.c
index 33e422e..1dba62c 100644
--- a/drivers/scsi/device_handler/scsi_dh.c
+++ b/drivers/scsi/device_handler/scsi_dh.c
@@ -98,27 +98,51 @@ device_handler_match(struct scsi_device_handler *scsi_dh,
static int scsi_dh_handler_attach(struct scsi_device *sdev,
struct scsi_device_handler *scsi_dh)
{
- int err = 0;
+ struct scsi_dh_data *d;
if (sdev->scsi_dh_data) {
if (sdev->scsi_dh_data->scsi_dh != scsi_dh)
- err = -EBUSY;
- else
- kref_get(&sdev->scsi_dh_data->kref);
- } else if (scsi_dh->attach) {
- err = scsi_dh->attach(sdev);
- if (!err) {
- kref_init(&sdev->scsi_dh_data->kref);
- sdev->scsi_dh_data->sdev = sdev;
- }
+ return -EBUSY;
+
+ kref_get(&sdev->scsi_dh_data->kref);
+ return 0;
}
- return err;
+
+ if (!try_module_get(scsi_dh->module))
+ return -EINVAL;
+
+ d = scsi_dh->attach(sdev);
+ if (IS_ERR(d)) {
+ sdev_printk(KERN_ERR, sdev, "%s: Attach failed (%ld)\n",
+ scsi_dh->name, PTR_ERR(d));
+ module_put(scsi_dh->module);
+ return PTR_ERR(d);
+ }
+
+ d->scsi_dh = scsi_dh;
+ kref_init(&d->kref);
+ d->sdev = sdev;
+
+ spin_lock_irq(sdev->request_queue->queue_lock);
+ sdev->scsi_dh_data = d;
+ spin_unlock_irq(sdev->request_queue->queue_lock);
+ return 0;
}
static void __detach_handler (struct kref *kref)
{
- struct scsi_dh_data *scsi_dh_data = container_of(kref, struct scsi_dh_data, kref);
- scsi_dh_data->scsi_dh->detach(scsi_dh_data->sdev);
+ struct scsi_dh_data *scsi_dh_data =
+ container_of(kref, struct scsi_dh_data, kref);
+ struct scsi_device_handler *scsi_dh = scsi_dh_data->scsi_dh;
+ struct scsi_device *sdev = scsi_dh_data->sdev;
+
+ spin_lock_irq(sdev->request_queue->queue_lock);
+ sdev->scsi_dh_data = NULL;
+ spin_unlock_irq(sdev->request_queue->queue_lock);
+
+ scsi_dh->detach(sdev);
+ sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", scsi_dh->name);
+ module_put(scsi_dh->module);
}
/*
@@ -141,7 +165,7 @@ static void scsi_dh_handler_detach(struct scsi_device *sdev,
if (!scsi_dh)
scsi_dh = sdev->scsi_dh_data->scsi_dh;
- if (scsi_dh && scsi_dh->detach)
+ if (scsi_dh)
kref_put(&sdev->scsi_dh_data->kref, __detach_handler);
}
@@ -330,6 +354,9 @@ int scsi_register_device_handler(struct scsi_device_handler *scsi_dh)
if (get_device_handler(scsi_dh->name))
return -EBUSY;
+ if (!scsi_dh->attach || !scsi_dh->detach)
+ return -EINVAL;
+
spin_lock(&list_lock);
list_add(&scsi_dh->list, &scsi_dh_list);
spin_unlock(&list_lock);
diff --git a/drivers/scsi/device_handler/scsi_dh_alua.c b/drivers/scsi/device_handler/scsi_dh_alua.c
index fd78bdc..854b568 100644
--- a/drivers/scsi/device_handler/scsi_dh_alua.c
+++ b/drivers/scsi/device_handler/scsi_dh_alua.c
@@ -62,6 +62,7 @@
#define ALUA_OPTIMIZE_STPG 1
struct alua_dh_data {
+ struct scsi_dh_data dh_data;
int group_id;
int rel_port;
int tpgs;
@@ -87,9 +88,7 @@ static int alua_check_sense(struct scsi_device *, struct scsi_sense_hdr *);
static inline struct alua_dh_data *get_alua_data(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
- BUG_ON(scsi_dh_data == NULL);
- return ((struct alua_dh_data *) scsi_dh_data->buf);
+ return container_of(sdev->scsi_dh_data, struct alua_dh_data, dh_data);
}
static int realloc_buffer(struct alua_dh_data *h, unsigned len)
@@ -825,42 +824,18 @@ static bool alua_match(struct scsi_device *sdev)
return (scsi_device_tpgs(sdev) != 0);
}
-static int alua_bus_attach(struct scsi_device *sdev);
-static void alua_bus_detach(struct scsi_device *sdev);
-
-static struct scsi_device_handler alua_dh = {
- .name = ALUA_DH_NAME,
- .module = THIS_MODULE,
- .attach = alua_bus_attach,
- .detach = alua_bus_detach,
- .prep_fn = alua_prep_fn,
- .check_sense = alua_check_sense,
- .activate = alua_activate,
- .set_params = alua_set_params,
- .match = alua_match,
-};
-
/*
* alua_bus_attach - Attach device handler
* @sdev: device to be attached to
*/
-static int alua_bus_attach(struct scsi_device *sdev)
+static struct scsi_dh_data *alua_bus_attach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data;
struct alua_dh_data *h;
- unsigned long flags;
- int err = SCSI_DH_OK;
-
- scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
- + sizeof(*h) , GFP_KERNEL);
- if (!scsi_dh_data) {
- sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
- ALUA_DH_NAME);
- return -ENOMEM;
- }
+ int err;
- scsi_dh_data->scsi_dh = &alua_dh;
- h = (struct alua_dh_data *) scsi_dh_data->buf;
+ h = kzalloc(sizeof(*h) , GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
h->tpgs = TPGS_MODE_UNINITIALIZED;
h->state = TPGS_STATE_OPTIMIZED;
h->group_id = -1;
@@ -870,23 +845,14 @@ static int alua_bus_attach(struct scsi_device *sdev)
h->sdev = sdev;
err = alua_initialize(sdev, h);
- if ((err != SCSI_DH_OK) && (err != SCSI_DH_DEV_OFFLINED))
- goto failed;
-
- if (!try_module_get(THIS_MODULE))
+ if (err != SCSI_DH_OK && err != SCSI_DH_DEV_OFFLINED)
goto failed;
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- sdev->scsi_dh_data = scsi_dh_data;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
sdev_printk(KERN_NOTICE, sdev, "%s: Attached\n", ALUA_DH_NAME);
-
- return 0;
-
+ return &h->dh_data;
failed:
- kfree(scsi_dh_data);
- sdev_printk(KERN_ERR, sdev, "%s: not attached\n", ALUA_DH_NAME);
- return -EINVAL;
+ kfree(h);
+ return ERR_PTR(-EINVAL);
}
/*
@@ -895,23 +861,25 @@ failed:
*/
static void alua_bus_detach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data;
- struct alua_dh_data *h;
- unsigned long flags;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- scsi_dh_data = sdev->scsi_dh_data;
- sdev->scsi_dh_data = NULL;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+ struct alua_dh_data *h = get_alua_data(sdev);
- h = (struct alua_dh_data *) scsi_dh_data->buf;
if (h->buff && h->inq != h->buff)
kfree(h->buff);
- kfree(scsi_dh_data);
- module_put(THIS_MODULE);
- sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", ALUA_DH_NAME);
+ kfree(h);
}
+static struct scsi_device_handler alua_dh = {
+ .name = ALUA_DH_NAME,
+ .module = THIS_MODULE,
+ .attach = alua_bus_attach,
+ .detach = alua_bus_detach,
+ .prep_fn = alua_prep_fn,
+ .check_sense = alua_check_sense,
+ .activate = alua_activate,
+ .set_params = alua_set_params,
+ .match = alua_match,
+};
+
static int __init alua_init(void)
{
int r;
diff --git a/drivers/scsi/device_handler/scsi_dh_emc.c b/drivers/scsi/device_handler/scsi_dh_emc.c
index 8476538..6ed1caa 100644
--- a/drivers/scsi/device_handler/scsi_dh_emc.c
+++ b/drivers/scsi/device_handler/scsi_dh_emc.c
@@ -72,6 +72,7 @@ static const char * lun_state[] =
};
struct clariion_dh_data {
+ struct scsi_dh_data dh_data;
/*
* Flags:
* CLARIION_SHORT_TRESPASS
@@ -116,9 +117,8 @@ struct clariion_dh_data {
static inline struct clariion_dh_data
*get_clariion_data(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
- BUG_ON(scsi_dh_data == NULL);
- return ((struct clariion_dh_data *) scsi_dh_data->buf);
+ return container_of(sdev->scsi_dh_data, struct clariion_dh_data,
+ dh_data);
}
/*
@@ -622,7 +622,10 @@ done:
return result;
}
-static const struct scsi_dh_devlist clariion_dev_list[] = {
+static const struct {
+ char *vendor;
+ char *model;
+} clariion_dev_list[] = {
{"DGC", "RAID"},
{"DGC", "DISK"},
{"DGC", "VRAID"},
@@ -647,39 +650,14 @@ static bool clariion_match(struct scsi_device *sdev)
return false;
}
-static int clariion_bus_attach(struct scsi_device *sdev);
-static void clariion_bus_detach(struct scsi_device *sdev);
-
-static struct scsi_device_handler clariion_dh = {
- .name = CLARIION_NAME,
- .module = THIS_MODULE,
- .devlist = clariion_dev_list,
- .attach = clariion_bus_attach,
- .detach = clariion_bus_detach,
- .check_sense = clariion_check_sense,
- .activate = clariion_activate,
- .prep_fn = clariion_prep_fn,
- .set_params = clariion_set_params,
- .match = clariion_match,
-};
-
-static int clariion_bus_attach(struct scsi_device *sdev)
+static struct scsi_dh_data *clariion_bus_attach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data;
struct clariion_dh_data *h;
- unsigned long flags;
int err;
- scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
- + sizeof(*h) , GFP_KERNEL);
- if (!scsi_dh_data) {
- sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
- CLARIION_NAME);
- return -ENOMEM;
- }
-
- scsi_dh_data->scsi_dh = &clariion_dh;
- h = (struct clariion_dh_data *) scsi_dh_data->buf;
+ h = kzalloc(sizeof(*h) , GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
h->lun_state = CLARIION_LUN_UNINITIALIZED;
h->default_sp = CLARIION_UNBOUND_LU;
h->current_sp = CLARIION_UNBOUND_LU;
@@ -692,45 +670,37 @@ static int clariion_bus_attach(struct scsi_device *sdev)
if (err != SCSI_DH_OK)
goto failed;
- if (!try_module_get(THIS_MODULE))
- goto failed;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- sdev->scsi_dh_data = scsi_dh_data;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
sdev_printk(KERN_INFO, sdev,
"%s: connected to SP %c Port %d (%s, default SP %c)\n",
CLARIION_NAME, h->current_sp + 'A',
h->port, lun_state[h->lun_state],
h->default_sp + 'A');
-
- return 0;
+ return &h->dh_data;
failed:
- kfree(scsi_dh_data);
- sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
- CLARIION_NAME);
- return -EINVAL;
+ kfree(h);
+ return ERR_PTR(-EINVAL);
}
static void clariion_bus_detach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data;
- unsigned long flags;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- scsi_dh_data = sdev->scsi_dh_data;
- sdev->scsi_dh_data = NULL;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
- sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n",
- CLARIION_NAME);
+ struct clariion_dh_data *h = get_clariion_data(sdev);
- kfree(scsi_dh_data);
- module_put(THIS_MODULE);
+ kfree(h);
}
+static struct scsi_device_handler clariion_dh = {
+ .name = CLARIION_NAME,
+ .module = THIS_MODULE,
+ .attach = clariion_bus_attach,
+ .detach = clariion_bus_detach,
+ .check_sense = clariion_check_sense,
+ .activate = clariion_activate,
+ .prep_fn = clariion_prep_fn,
+ .set_params = clariion_set_params,
+ .match = clariion_match,
+};
+
static int __init clariion_init(void)
{
int r;
diff --git a/drivers/scsi/device_handler/scsi_dh_hp_sw.c b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
index 4ee2759..485d995 100644
--- a/drivers/scsi/device_handler/scsi_dh_hp_sw.c
+++ b/drivers/scsi/device_handler/scsi_dh_hp_sw.c
@@ -38,6 +38,7 @@
#define HP_SW_PATH_PASSIVE 1
struct hp_sw_dh_data {
+ struct scsi_dh_data dh_data;
unsigned char sense[SCSI_SENSE_BUFFERSIZE];
int path_state;
int retries;
@@ -51,9 +52,7 @@ static int hp_sw_start_stop(struct hp_sw_dh_data *);
static inline struct hp_sw_dh_data *get_hp_sw_data(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
- BUG_ON(scsi_dh_data == NULL);
- return ((struct hp_sw_dh_data *) scsi_dh_data->buf);
+ return container_of(sdev->scsi_dh_data, struct hp_sw_dh_data, dh_data);
}
/*
@@ -312,7 +311,10 @@ static int hp_sw_activate(struct scsi_device *sdev,
return 0;
}
-static const struct scsi_dh_devlist hp_sw_dh_data_list[] = {
+static const struct {
+ char *vendor;
+ char *model;
+} hp_sw_dh_data_list[] = {
{"COMPAQ", "MSA1000 VOLUME"},
{"COMPAQ", "HSV110"},
{"HP", "HSV100"},
@@ -338,37 +340,14 @@ static bool hp_sw_match(struct scsi_device *sdev)
return false;
}
-static int hp_sw_bus_attach(struct scsi_device *sdev);
-static void hp_sw_bus_detach(struct scsi_device *sdev);
-
-static struct scsi_device_handler hp_sw_dh = {
- .name = HP_SW_NAME,
- .module = THIS_MODULE,
- .devlist = hp_sw_dh_data_list,
- .attach = hp_sw_bus_attach,
- .detach = hp_sw_bus_detach,
- .activate = hp_sw_activate,
- .prep_fn = hp_sw_prep_fn,
- .match = hp_sw_match,
-};
-
-static int hp_sw_bus_attach(struct scsi_device *sdev)
+static struct scsi_dh_data *hp_sw_bus_attach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data;
struct hp_sw_dh_data *h;
- unsigned long flags;
int ret;
- scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
- + sizeof(*h) , GFP_KERNEL);
- if (!scsi_dh_data) {
- sdev_printk(KERN_ERR, sdev, "%s: Attach Failed\n",
- HP_SW_NAME);
- return 0;
- }
-
- scsi_dh_data->scsi_dh = &hp_sw_dh;
- h = (struct hp_sw_dh_data *) scsi_dh_data->buf;
+ h = kzalloc(sizeof(*h), GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
h->path_state = HP_SW_PATH_UNINITIALIZED;
h->retries = HP_SW_RETRIES;
h->sdev = sdev;
@@ -377,42 +356,32 @@ static int hp_sw_bus_attach(struct scsi_device *sdev)
if (ret != SCSI_DH_OK || h->path_state == HP_SW_PATH_UNINITIALIZED)
goto failed;
- if (!try_module_get(THIS_MODULE))
- goto failed;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- sdev->scsi_dh_data = scsi_dh_data;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
sdev_printk(KERN_INFO, sdev, "%s: attached to %s path\n",
HP_SW_NAME, h->path_state == HP_SW_PATH_ACTIVE?
"active":"passive");
-
- return 0;
-
+ return &h->dh_data;
failed:
- kfree(scsi_dh_data);
- sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
- HP_SW_NAME);
- return -EINVAL;
+ kfree(h);
+ return ERR_PTR(-EINVAL);
}
static void hp_sw_bus_detach( struct scsi_device *sdev )
{
- struct scsi_dh_data *scsi_dh_data;
- unsigned long flags;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- scsi_dh_data = sdev->scsi_dh_data;
- sdev->scsi_dh_data = NULL;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
- module_put(THIS_MODULE);
-
- sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", HP_SW_NAME);
+ struct hp_sw_dh_data *h = get_hp_sw_data(sdev);
- kfree(scsi_dh_data);
+ kfree(h);
}
+static struct scsi_device_handler hp_sw_dh = {
+ .name = HP_SW_NAME,
+ .module = THIS_MODULE,
+ .attach = hp_sw_bus_attach,
+ .detach = hp_sw_bus_detach,
+ .activate = hp_sw_activate,
+ .prep_fn = hp_sw_prep_fn,
+ .match = hp_sw_match,
+};
+
static int __init hp_sw_init(void)
{
return scsi_register_device_handler(&hp_sw_dh);
diff --git a/drivers/scsi/device_handler/scsi_dh_rdac.c b/drivers/scsi/device_handler/scsi_dh_rdac.c
index 1b5bc92..b46ace3 100644
--- a/drivers/scsi/device_handler/scsi_dh_rdac.c
+++ b/drivers/scsi/device_handler/scsi_dh_rdac.c
@@ -181,6 +181,7 @@ struct c2_inquiry {
};
struct rdac_dh_data {
+ struct scsi_dh_data dh_data;
struct rdac_controller *ctlr;
#define UNINITIALIZED_LUN (1 << 8)
unsigned lun;
@@ -261,9 +262,7 @@ do { \
static inline struct rdac_dh_data *get_rdac_data(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data = sdev->scsi_dh_data;
- BUG_ON(scsi_dh_data == NULL);
- return ((struct rdac_dh_data *) scsi_dh_data->buf);
+ return container_of(sdev->scsi_dh_data, struct rdac_dh_data, dh_data);
}
static struct request *get_rdac_req(struct scsi_device *sdev,
@@ -779,7 +778,10 @@ static int rdac_check_sense(struct scsi_device *sdev,
return SCSI_RETURN_NOT_HANDLED;
}
-static const struct scsi_dh_devlist rdac_dev_list[] = {
+static const struct {
+ char *vendor;
+ char *model;
+} rdac_dev_list[] = {
{"IBM", "1722"},
{"IBM", "1724"},
{"IBM", "1726"},
@@ -825,40 +827,16 @@ static bool rdac_match(struct scsi_device *sdev)
return false;
}
-static int rdac_bus_attach(struct scsi_device *sdev);
-static void rdac_bus_detach(struct scsi_device *sdev);
-
-static struct scsi_device_handler rdac_dh = {
- .name = RDAC_NAME,
- .module = THIS_MODULE,
- .devlist = rdac_dev_list,
- .prep_fn = rdac_prep_fn,
- .check_sense = rdac_check_sense,
- .attach = rdac_bus_attach,
- .detach = rdac_bus_detach,
- .activate = rdac_activate,
- .match = rdac_match,
-};
-
-static int rdac_bus_attach(struct scsi_device *sdev)
+static struct scsi_dh_data *rdac_bus_attach(struct scsi_device *sdev)
{
- struct scsi_dh_data *scsi_dh_data;
struct rdac_dh_data *h;
- unsigned long flags;
int err;
char array_name[ARRAY_LABEL_LEN];
char array_id[UNIQUE_ID_LEN];
- scsi_dh_data = kzalloc(sizeof(*scsi_dh_data)
- + sizeof(*h) , GFP_KERNEL);
- if (!scsi_dh_data) {
- sdev_printk(KERN_ERR, sdev, "%s: Attach failed\n",
- RDAC_NAME);
- return -ENOMEM;
- }
-
- scsi_dh_data->scsi_dh = &rdac_dh;
- h = (struct rdac_dh_data *) scsi_dh_data->buf;
+ h = kzalloc(sizeof(*h) , GFP_KERNEL);
+ if (!h)
+ return ERR_PTR(-ENOMEM);
h->lun = UNINITIALIZED_LUN;
h->state = RDAC_STATE_ACTIVE;
@@ -878,19 +856,12 @@ static int rdac_bus_attach(struct scsi_device *sdev)
if (err != SCSI_DH_OK)
goto clean_ctlr;
- if (!try_module_get(THIS_MODULE))
- goto clean_ctlr;
-
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- sdev->scsi_dh_data = scsi_dh_data;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
sdev_printk(KERN_NOTICE, sdev,
"%s: LUN %d (%s) (%s)\n",
RDAC_NAME, h->lun, mode[(int)h->mode],
lun_state[(int)h->lun_state]);
- return 0;
+ return &h->dh_data;
clean_ctlr:
spin_lock(&list_lock);
@@ -898,37 +869,34 @@ clean_ctlr:
spin_unlock(&list_lock);
failed:
- kfree(scsi_dh_data);
- sdev_printk(KERN_ERR, sdev, "%s: not attached\n",
- RDAC_NAME);
- return -EINVAL;
+ kfree(h);
+ return ERR_PTR(-EINVAL);
}
static void rdac_bus_detach( struct scsi_device *sdev )
{
- struct scsi_dh_data *scsi_dh_data;
- struct rdac_dh_data *h;
- unsigned long flags;
+ struct rdac_dh_data *h = get_rdac_data(sdev);
- scsi_dh_data = sdev->scsi_dh_data;
- h = (struct rdac_dh_data *) scsi_dh_data->buf;
if (h->ctlr && h->ctlr->ms_queued)
flush_workqueue(kmpath_rdacd);
- spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
- sdev->scsi_dh_data = NULL;
- spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
-
spin_lock(&list_lock);
if (h->ctlr)
kref_put(&h->ctlr->kref, release_controller);
spin_unlock(&list_lock);
- kfree(scsi_dh_data);
- module_put(THIS_MODULE);
- sdev_printk(KERN_NOTICE, sdev, "%s: Detached\n", RDAC_NAME);
+ kfree(h);
}
-
+static struct scsi_device_handler rdac_dh = {
+ .name = RDAC_NAME,
+ .module = THIS_MODULE,
+ .prep_fn = rdac_prep_fn,
+ .check_sense = rdac_check_sense,
+ .attach = rdac_bus_attach,
+ .detach = rdac_bus_detach,
+ .activate = rdac_activate,
+ .match = rdac_match,
+};
static int __init rdac_init(void)
{
diff --git a/drivers/scsi/dmx3191d.c b/drivers/scsi/dmx3191d.c
index 4b0dd8c..3e08812 100644
--- a/drivers/scsi/dmx3191d.c
+++ b/drivers/scsi/dmx3191d.c
@@ -33,20 +33,20 @@
/*
* Definitions for the generic 5380 driver.
*/
-#define AUTOSENSE
+
+#define DONT_USE_INTR
#define NCR5380_read(reg) inb(port + reg)
#define NCR5380_write(reg, value) outb(value, port + reg)
-#define NCR5380_implementation_fields unsigned int port
-#define NCR5380_local_declare() NCR5380_implementation_fields
+#define NCR5380_implementation_fields /* none */
+#define NCR5380_local_declare() unsigned int port
#define NCR5380_setup(instance) port = instance->io_port
/*
* Includes needed for NCR5380.[ch] (XXX: Move them to NCR5380.h)
*/
#include <linux/delay.h>
-#include "scsi.h"
#include "NCR5380.h"
#include "NCR5380.c"
@@ -58,6 +58,7 @@
static struct scsi_host_template dmx3191d_driver_template = {
.proc_name = DMX3191D_DRIVER_NAME,
.name = "Domex DMX3191D",
+ .info = NCR5380_info,
.queuecommand = NCR5380_queue_command,
.eh_abort_handler = NCR5380_abort,
.eh_bus_reset_handler = NCR5380_bus_reset,
@@ -90,31 +91,23 @@ static int dmx3191d_probe_one(struct pci_dev *pdev,
if (!shost)
goto out_release_region;
shost->io_port = io;
- shost->irq = pdev->irq;
- NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
+ /* This card does not seem to raise an interrupt on pdev->irq.
+ * Steam-powered SCSI controllers run without an IRQ anyway.
+ */
+ shost->irq = NO_IRQ;
- if (request_irq(pdev->irq, NCR5380_intr, IRQF_SHARED,
- DMX3191D_DRIVER_NAME, shost)) {
- /*
- * Steam powered scsi controllers run without an IRQ anyway
- */
- printk(KERN_WARNING "dmx3191: IRQ %d not available - "
- "switching to polled mode.\n", pdev->irq);
- shost->irq = SCSI_IRQ_NONE;
- }
+ NCR5380_init(shost, FLAG_NO_PSEUDO_DMA | FLAG_DTC3181E);
pci_set_drvdata(pdev, shost);
error = scsi_add_host(shost, &pdev->dev);
if (error)
- goto out_free_irq;
+ goto out_release_region;
scsi_scan_host(shost);
return 0;
- out_free_irq:
- free_irq(shost->irq, shost);
out_release_region:
release_region(io, DMX3191D_REGION_LEN);
out_disable_device:
@@ -131,8 +124,6 @@ static void dmx3191d_remove_one(struct pci_dev *pdev)
NCR5380_exit(shost);
- if (shost->irq != SCSI_IRQ_NONE)
- free_irq(shost->irq, shost);
release_region(shost->io_port, DMX3191D_REGION_LEN);
pci_disable_device(pdev);
diff --git a/drivers/scsi/dpt_i2o.c b/drivers/scsi/dpt_i2o.c
index 072f0ec..0bf9769 100644
--- a/drivers/scsi/dpt_i2o.c
+++ b/drivers/scsi/dpt_i2o.c
@@ -415,10 +415,8 @@ static int adpt_slave_configure(struct scsi_device * device)
pHba = (adpt_hba *) host->hostdata[0];
if (host->can_queue && device->tagged_supported) {
- scsi_adjust_queue_depth(device, MSG_SIMPLE_TAG,
+ scsi_change_queue_depth(device,
host->can_queue - 1);
- } else {
- scsi_adjust_queue_depth(device, 0, 1);
}
return 0;
}
diff --git a/drivers/scsi/dtc.c b/drivers/scsi/dtc.c
index 0a667fe..4c74c7b 100644
--- a/drivers/scsi/dtc.c
+++ b/drivers/scsi/dtc.c
@@ -1,5 +1,4 @@
-#define AUTOSENSE
#define PSEUDO_DMA
#define DONT_USE_INTR
#define UNSAFE /* Leave interrupts enabled during pseudo-dma I/O */
@@ -18,29 +17,9 @@
* (Unix and Linux consulting and custom programming)
* drew@colorado.edu
* +1 (303) 440-4894
- *
- * DISTRIBUTION RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
-*/
+ */
/*
- * Options :
- * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
- *
- * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
- * increase compared to polled I/O.
- *
- * PARITY - enable parity checking. Not supported.
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers.
- * You probably want this.
- *
* The card is detected and initialized in one of several ways :
* 1. Autoprobe (default) - since the board is memory mapped,
* a BIOS signature is scanned for to locate the registers.
@@ -79,15 +58,11 @@
#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/io.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include "dtc.h"
#define AUTOPROBE_IRQ
#include "NCR5380.h"
-
-#define DTC_PUBLIC_RELEASE 2
-
/*
* The DTC3180 & 3280 boards are memory mapped.
*
@@ -173,10 +148,13 @@ static const struct signature {
*
*/
-static void __init dtc_setup(char *str, int *ints)
+static int __init dtc_setup(char *str)
{
static int commandline_current = 0;
int i;
+ int ints[10];
+
+ get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] != 2)
printk("dtc_setup: usage dtc=address,irq\n");
else if (commandline_current < NO_OVERRIDES) {
@@ -189,7 +167,10 @@ static void __init dtc_setup(char *str, int *ints)
}
++commandline_current;
}
+ return 1;
}
+
+__setup("dtc=", dtc_setup);
#endif
/*
@@ -213,10 +194,6 @@ static int __init dtc_detect(struct scsi_host_template * tpnt)
void __iomem *base;
int sig, count;
- tpnt->proc_name = "dtc3x80";
- tpnt->show_info = dtc_show_info;
- tpnt->write_info = dtc_write_info;
-
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
addr = 0;
base = NULL;
@@ -271,38 +248,33 @@ found:
else
instance->irq = NCR5380_probe_irq(instance, DTC_IRQS);
+ /* Compatibility with documented NCR5380 kernel parameters */
+ if (instance->irq == 255)
+ instance->irq = NO_IRQ;
+
#ifndef DONT_USE_INTR
/* With interrupts enabled, it will sometimes hang when doing heavy
* reads. So better not enable them until I finger it out. */
- if (instance->irq != SCSI_IRQ_NONE)
+ if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, dtc_intr, 0,
"dtc", instance)) {
printk(KERN_ERR "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
+ instance->irq = NO_IRQ;
}
- if (instance->irq == SCSI_IRQ_NONE) {
+ if (instance->irq == NO_IRQ) {
printk(KERN_WARNING "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk(KERN_WARNING "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
#else
- if (instance->irq != SCSI_IRQ_NONE)
+ if (instance->irq != NO_IRQ)
printk(KERN_WARNING "scsi%d : interrupts not used. Might as well not jumper it.\n", instance->host_no);
- instance->irq = SCSI_IRQ_NONE;
+ instance->irq = NO_IRQ;
#endif
#if defined(DTCDEBUG) && (DTCDEBUG & DTCDEBUG_INIT)
printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
#endif
- printk(KERN_INFO "scsi%d : at 0x%05X", instance->host_no, (int) instance->base);
- if (instance->irq == SCSI_IRQ_NONE)
- printk(" interrupts disabled");
- else
- printk(" irq %d", instance->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, DTC_PUBLIC_RELEASE);
- NCR5380_print_options(instance);
- printk("\n");
-
++current_override;
++count;
}
@@ -354,20 +326,18 @@ static int dtc_biosparam(struct scsi_device *sdev, struct block_device *dev,
* timeout.
*/
-static int dtc_maxi = 0;
-static int dtc_wmaxi = 0;
-
static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst, int len)
{
unsigned char *d = dst;
int i; /* For counting time spent in the poll-loop */
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
NCR5380_local_declare();
NCR5380_setup(instance);
i = 0;
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
- if (instance->irq == SCSI_IRQ_NONE)
+ if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ);
else
NCR5380_write(DTC_CONTROL_REG, CSR_DIR_READ | CSR_INT_BASE);
@@ -391,8 +361,8 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
rtrc(0);
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- if (i > dtc_maxi)
- dtc_maxi = i;
+ if (i > hostdata->spin_max_r)
+ hostdata->spin_max_r = i;
return (0);
}
@@ -412,13 +382,14 @@ static inline int NCR5380_pread(struct Scsi_Host *instance, unsigned char *dst,
static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src, int len)
{
int i;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
NCR5380_local_declare();
NCR5380_setup(instance);
NCR5380_read(RESET_PARITY_INTERRUPT_REG);
NCR5380_write(MODE_REG, MR_ENABLE_EOP_INTR | MR_DMA_MODE);
/* set direction (write) */
- if (instance->irq == SCSI_IRQ_NONE)
+ if (instance->irq == NO_IRQ)
NCR5380_write(DTC_CONTROL_REG, 0);
else
NCR5380_write(DTC_CONTROL_REG, CSR_5380_INTR);
@@ -444,8 +415,8 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
/* Check for parity error here. fixme. */
NCR5380_write(MODE_REG, 0); /* Clear the operating mode */
rtrc(0);
- if (i > dtc_wmaxi)
- dtc_wmaxi = i;
+ if (i > hostdata->spin_max_w)
+ hostdata->spin_max_w = i;
return (0);
}
@@ -457,7 +428,7 @@ static int dtc_release(struct Scsi_Host *shost)
{
NCR5380_local_declare();
NCR5380_setup(shost);
- if (shost->irq)
+ if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
if (shost->io_port && shost->n_io_port)
@@ -471,6 +442,10 @@ static struct scsi_host_template driver_template = {
.name = "DTC 3180/3280 ",
.detect = dtc_detect,
.release = dtc_release,
+ .proc_name = "dtc3x80",
+ .show_info = dtc_show_info,
+ .write_info = dtc_write_info,
+ .info = dtc_info,
.queuecommand = dtc_queue_command,
.eh_abort_handler = dtc_abort,
.eh_bus_reset_handler = dtc_bus_reset,
diff --git a/drivers/scsi/dtc.h b/drivers/scsi/dtc.h
index 92d7cfc..78a2332 100644
--- a/drivers/scsi/dtc.h
+++ b/drivers/scsi/dtc.h
@@ -5,24 +5,6 @@
* (Unix and Linux consulting and custom programming)
* drew@colorado.edu
* +1 (303) 440-4894
- *
- * DISTRIBUTION RELEASE 2.
- *
- * For more information, please consult
- *
- *
- *
- * and
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
#ifndef DTC3280_H
@@ -32,13 +14,6 @@
#define DTCDEBUG_INIT 0x1
#define DTCDEBUG_TRANSFER 0x2
-static int dtc_abort(Scsi_Cmnd *);
-static int dtc_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int*);
-static int dtc_detect(struct scsi_host_template *);
-static int dtc_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int dtc_bus_reset(Scsi_Cmnd *);
-
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
#endif
@@ -88,6 +63,7 @@ static int dtc_bus_reset(Scsi_Cmnd *);
#define NCR5380_queue_command dtc_queue_command
#define NCR5380_abort dtc_abort
#define NCR5380_bus_reset dtc_bus_reset
+#define NCR5380_info dtc_info
#define NCR5380_show_info dtc_show_info
#define NCR5380_write_info dtc_write_info
diff --git a/drivers/scsi/eata.c b/drivers/scsi/eata.c
index 943ad3a..227dd2c 100644
--- a/drivers/scsi/eata.c
+++ b/drivers/scsi/eata.c
@@ -946,20 +946,18 @@ static int eata2x_slave_configure(struct scsi_device *dev)
if (TLDEV(dev->type) && dev->tagged_supported) {
if (tag_mode == TAG_SIMPLE) {
- scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
tag_suffix = ", simple tags";
} else if (tag_mode == TAG_ORDERED) {
- scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd);
tag_suffix = ", ordered tags";
} else {
- scsi_adjust_queue_depth(dev, 0, tqd);
tag_suffix = ", no tags";
}
+ scsi_change_queue_depth(dev, tqd);
} else if (TLDEV(dev->type) && linked_comm) {
- scsi_adjust_queue_depth(dev, 0, tqd);
+ scsi_change_queue_depth(dev, tqd);
tag_suffix = ", untagged";
} else {
- scsi_adjust_queue_depth(dev, 0, utqd);
+ scsi_change_queue_depth(dev, utqd);
tag_suffix = "";
}
diff --git a/drivers/scsi/esas2r/esas2r.h b/drivers/scsi/esas2r/esas2r.h
index 3fd305d..b6030e3 100644
--- a/drivers/scsi/esas2r/esas2r.h
+++ b/drivers/scsi/esas2r/esas2r.h
@@ -972,11 +972,6 @@ u8 handle_hba_ioctl(struct esas2r_adapter *a,
struct atto_ioctl *ioctl_hba);
int esas2r_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd);
int esas2r_show_info(struct seq_file *m, struct Scsi_Host *sh);
-int esas2r_slave_alloc(struct scsi_device *dev);
-int esas2r_slave_configure(struct scsi_device *dev);
-void esas2r_slave_destroy(struct scsi_device *dev);
-int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason);
-int esas2r_change_queue_type(struct scsi_device *dev, int type);
long esas2r_proc_ioctl(struct file *fp, unsigned int cmd, unsigned long arg);
/* SCSI error handler (eh) functions */
diff --git a/drivers/scsi/esas2r/esas2r_ioctl.c b/drivers/scsi/esas2r/esas2r_ioctl.c
index d89a027..baf9130 100644
--- a/drivers/scsi/esas2r/esas2r_ioctl.c
+++ b/drivers/scsi/esas2r/esas2r_ioctl.c
@@ -117,9 +117,8 @@ static void do_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
rq = esas2r_alloc_request(a);
if (rq == NULL) {
- up(&a->fm_api_semaphore);
fi->status = FI_STAT_BUSY;
- return;
+ goto free_sem;
}
if (fi == &a->firmware.header) {
@@ -135,7 +134,7 @@ static void do_fm_api(struct esas2r_adapter *a, struct esas2r_flash_img *fi)
if (a->firmware.header_buff == NULL) {
esas2r_debug("failed to allocate header buffer!");
fi->status = FI_STAT_BUSY;
- return;
+ goto free_req;
}
memcpy(a->firmware.header_buff, fi,
@@ -171,9 +170,10 @@ all_done:
a->firmware.header_buff,
(dma_addr_t)a->firmware.header_buff_phys);
}
-
- up(&a->fm_api_semaphore);
+free_req:
esas2r_free_request(a, (struct esas2r_request *)rq);
+free_sem:
+ up(&a->fm_api_semaphore);
return;
}
@@ -1420,9 +1420,10 @@ int esas2r_ioctl_handler(void *hostdata, int cmd, void __user *arg)
rq = esas2r_alloc_request(a);
if (rq == NULL) {
- up(&a->nvram_semaphore);
- ioctl->data.prw.code = 0;
- break;
+ kfree(ioctl);
+ esas2r_log(ESAS2R_LOG_WARN,
+ "could not allocate an internal request");
+ return -ENOMEM;
}
code = esas2r_write_params(a, rq,
@@ -1523,9 +1524,12 @@ ioctl_done:
case -EINVAL:
ioctl->header.return_code = IOCTL_INVALID_PARAM;
break;
+
+ default:
+ ioctl->header.return_code = IOCTL_GENERAL_ERROR;
+ break;
}
- ioctl->header.return_code = IOCTL_GENERAL_ERROR;
}
/* Always copy the buffer back, if only to pick up the status */
diff --git a/drivers/scsi/esas2r/esas2r_main.c b/drivers/scsi/esas2r/esas2r_main.c
index 6504a19..593ff8a 100644
--- a/drivers/scsi/esas2r/esas2r_main.c
+++ b/drivers/scsi/esas2r/esas2r_main.c
@@ -254,12 +254,10 @@ static struct scsi_host_template driver_template = {
.use_clustering = ENABLE_CLUSTERING,
.emulated = 0,
.proc_name = ESAS2R_DRVR_NAME,
- .slave_configure = esas2r_slave_configure,
- .slave_alloc = esas2r_slave_alloc,
- .slave_destroy = esas2r_slave_destroy,
- .change_queue_depth = esas2r_change_queue_depth,
- .change_queue_type = esas2r_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
.max_sectors = 0xFFFF,
+ .use_blk_tags = 1,
};
int sgl_page_size = 512;
@@ -1057,7 +1055,7 @@ int esas2r_eh_abort(struct scsi_cmnd *cmd)
cmd->scsi_done(cmd);
- return 0;
+ return SUCCESS;
}
spin_lock_irqsave(&a->queue_lock, flags);
@@ -1259,60 +1257,6 @@ int esas2r_target_reset(struct scsi_cmnd *cmd)
return esas2r_dev_targ_reset(cmd, true);
}
-int esas2r_change_queue_depth(struct scsi_device *dev, int depth, int reason)
-{
- esas2r_log(ESAS2R_LOG_INFO, "change_queue_depth %p, %d", dev, depth);
-
- scsi_adjust_queue_depth(dev, scsi_get_tag_type(dev), depth);
-
- return dev->queue_depth;
-}
-
-int esas2r_change_queue_type(struct scsi_device *dev, int type)
-{
- esas2r_log(ESAS2R_LOG_INFO, "change_queue_type %p, %d", dev, type);
-
- if (dev->tagged_supported) {
- scsi_set_tag_type(dev, type);
-
- if (type)
- scsi_activate_tcq(dev, dev->queue_depth);
- else
- scsi_deactivate_tcq(dev, dev->queue_depth);
- } else {
- type = 0;
- }
-
- return type;
-}
-
-int esas2r_slave_alloc(struct scsi_device *dev)
-{
- return 0;
-}
-
-int esas2r_slave_configure(struct scsi_device *dev)
-{
- esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
- "esas2r_slave_configure()");
-
- if (dev->tagged_supported) {
- scsi_set_tag_type(dev, MSG_SIMPLE_TAG);
- scsi_activate_tcq(dev, cmd_per_lun);
- } else {
- scsi_set_tag_type(dev, 0);
- scsi_deactivate_tcq(dev, cmd_per_lun);
- }
-
- return 0;
-}
-
-void esas2r_slave_destroy(struct scsi_device *dev)
-{
- esas2r_log_dev(ESAS2R_LOG_INFO, &(dev->sdev_gendev),
- "esas2r_slave_destroy()");
-}
-
void esas2r_log_request_failure(struct esas2r_adapter *a,
struct esas2r_request *rq)
{
diff --git a/drivers/scsi/esp_scsi.c b/drivers/scsi/esp_scsi.c
index 55548dc..ce5bd52 100644
--- a/drivers/scsi/esp_scsi.c
+++ b/drivers/scsi/esp_scsi.c
@@ -49,55 +49,67 @@ static u32 esp_debug;
#define ESP_DEBUG_DATADONE 0x00000100
#define ESP_DEBUG_RECONNECT 0x00000200
#define ESP_DEBUG_AUTOSENSE 0x00000400
+#define ESP_DEBUG_EVENT 0x00000800
+#define ESP_DEBUG_COMMAND 0x00001000
#define esp_log_intr(f, a...) \
do { if (esp_debug & ESP_DEBUG_INTR) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_reset(f, a...) \
do { if (esp_debug & ESP_DEBUG_RESET) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_msgin(f, a...) \
do { if (esp_debug & ESP_DEBUG_MSGIN) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_msgout(f, a...) \
do { if (esp_debug & ESP_DEBUG_MSGOUT) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_cmddone(f, a...) \
do { if (esp_debug & ESP_DEBUG_CMDDONE) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_disconnect(f, a...) \
do { if (esp_debug & ESP_DEBUG_DISCONNECT) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_datastart(f, a...) \
do { if (esp_debug & ESP_DEBUG_DATASTART) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_datadone(f, a...) \
do { if (esp_debug & ESP_DEBUG_DATADONE) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_reconnect(f, a...) \
do { if (esp_debug & ESP_DEBUG_RECONNECT) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_log_autosense(f, a...) \
do { if (esp_debug & ESP_DEBUG_AUTOSENSE) \
- printk(f, ## a); \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
+} while (0)
+
+#define esp_log_event(f, a...) \
+do { if (esp_debug & ESP_DEBUG_EVENT) \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
+} while (0)
+
+#define esp_log_command(f, a...) \
+do { if (esp_debug & ESP_DEBUG_COMMAND) \
+ shost_printk(KERN_DEBUG, esp->host, f, ## a); \
} while (0)
#define esp_read8(REG) esp->ops->esp_read8(esp, REG)
@@ -126,10 +138,29 @@ void scsi_esp_cmd(struct esp *esp, u8 val)
esp->esp_event_cur = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
+ esp_log_command("cmd[%02x]\n", val);
esp_write8(val, ESP_CMD);
}
EXPORT_SYMBOL(scsi_esp_cmd);
+static void esp_send_dma_cmd(struct esp *esp, int len, int max_len, int cmd)
+{
+ if (esp->flags & ESP_FLAG_USE_FIFO) {
+ int i;
+
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ for (i = 0; i < len; i++)
+ esp_write8(esp->command_block[i], ESP_FDATA);
+ scsi_esp_cmd(esp, cmd);
+ } else {
+ if (esp->rev == FASHME)
+ scsi_esp_cmd(esp, ESP_CMD_FLUSH);
+ cmd |= ESP_CMD_DMA;
+ esp->ops->send_dma_cmd(esp, esp->command_block_dma,
+ len, max_len, 0, cmd);
+ }
+}
+
static void esp_event(struct esp *esp, u8 val)
{
struct esp_event_ent *p;
@@ -150,19 +181,17 @@ static void esp_dump_cmd_log(struct esp *esp)
int idx = esp->esp_event_cur;
int stop = idx;
- printk(KERN_INFO PFX "esp%d: Dumping command log\n",
- esp->host->unique_id);
+ shost_printk(KERN_INFO, esp->host, "Dumping command log\n");
do {
struct esp_event_ent *p = &esp->esp_event_log[idx];
- printk(KERN_INFO PFX "esp%d: ent[%d] %s ",
- esp->host->unique_id, idx,
- p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT");
-
- printk("val[%02x] sreg[%02x] seqreg[%02x] "
- "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
- p->val, p->sreg, p->seqreg,
- p->sreg2, p->ireg, p->select_state, p->event);
+ shost_printk(KERN_INFO, esp->host,
+ "ent[%d] %s val[%02x] sreg[%02x] seqreg[%02x] "
+ "sreg2[%02x] ireg[%02x] ss[%02x] event[%02x]\n",
+ idx,
+ p->type == ESP_EVENT_TYPE_CMD ? "CMD" : "EVENT",
+ p->val, p->sreg, p->seqreg,
+ p->sreg2, p->ireg, p->select_state, p->event);
idx = (idx + 1) & (ESP_EVENT_LOG_SZ - 1);
} while (idx != stop);
@@ -176,9 +205,8 @@ static void esp_flush_fifo(struct esp *esp)
while (esp_read8(ESP_FFLAGS) & ESP_FF_FBYTES) {
if (--lim == 0) {
- printk(KERN_ALERT PFX "esp%d: ESP_FF_BYTES "
- "will not clear!\n",
- esp->host->unique_id);
+ shost_printk(KERN_ALERT, esp->host,
+ "ESP_FF_BYTES will not clear!\n");
break;
}
udelay(1);
@@ -240,6 +268,19 @@ static void esp_reset_esp(struct esp *esp)
} else {
esp->min_period = ((5 * esp->ccycle) / 1000);
}
+ if (esp->rev == FAS236) {
+ /*
+ * The AM53c974 chip returns the same ID as FAS236;
+ * try to configure glitch eater.
+ */
+ u8 config4 = ESP_CONFIG4_GE1;
+ esp_write8(config4, ESP_CFG4);
+ config4 = esp_read8(ESP_CFG4);
+ if (config4 & ESP_CONFIG4_GE1) {
+ esp->rev = PCSCSI;
+ esp_write8(esp->config4, ESP_CFG4);
+ }
+ }
esp->max_period = (esp->max_period + 3)>>2;
esp->min_period = (esp->min_period + 3)>>2;
@@ -265,7 +306,8 @@ static void esp_reset_esp(struct esp *esp)
/* fallthrough... */
case FAS236:
- /* Fast 236 or HME */
+ case PCSCSI:
+ /* Fast 236, AM53c974 or HME */
esp_write8(esp->config2, ESP_CFG2);
if (esp->rev == FASHME) {
u8 cfg3 = esp->target[0].esp_config3;
@@ -383,12 +425,11 @@ static void esp_advance_dma(struct esp *esp, struct esp_cmd_entry *ent,
p->cur_residue -= len;
p->tot_residue -= len;
if (p->cur_residue < 0 || p->tot_residue < 0) {
- printk(KERN_ERR PFX "esp%d: Data transfer overflow.\n",
- esp->host->unique_id);
- printk(KERN_ERR PFX "esp%d: cur_residue[%d] tot_residue[%d] "
- "len[%u]\n",
- esp->host->unique_id,
- p->cur_residue, p->tot_residue, len);
+ shost_printk(KERN_ERR, esp->host,
+ "Data transfer overflow.\n");
+ shost_printk(KERN_ERR, esp->host,
+ "cur_residue[%d] tot_residue[%d] len[%u]\n",
+ p->cur_residue, p->tot_residue, len);
p->cur_residue = 0;
p->tot_residue = 0;
}
@@ -604,9 +645,8 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
if (!ent->sense_ptr) {
- esp_log_autosense("esp%d: Doing auto-sense for "
- "tgt[%d] lun[%d]\n",
- esp->host->unique_id, tgt, lun);
+ esp_log_autosense("Doing auto-sense for tgt[%d] lun[%d]\n",
+ tgt, lun);
ent->sense_ptr = cmd->sense_buffer;
ent->sense_dma = esp->ops->map_single(esp,
@@ -642,10 +682,7 @@ static void esp_autosense(struct esp *esp, struct esp_cmd_entry *ent)
val = (p - esp->command_block);
- if (esp->rev == FASHME)
- scsi_esp_cmd(esp, ESP_CMD_FLUSH);
- esp->ops->send_dma_cmd(esp, esp->command_block_dma,
- val, 16, 0, ESP_CMD_DMA | ESP_CMD_SELA);
+ esp_send_dma_cmd(esp, val, 16, ESP_CMD_SELA);
}
static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
@@ -663,7 +700,7 @@ static struct esp_cmd_entry *find_and_prep_issuable_command(struct esp *esp)
return ent;
}
- if (!scsi_populate_tag_msg(cmd, &ent->tag[0])) {
+ if (!spi_populate_tag_msg(&ent->tag[0], cmd)) {
ent->tag[0] = 0;
ent->tag[1] = 0;
}
@@ -781,12 +818,12 @@ build_identify:
}
if (!(esp->flags & ESP_FLAG_DOING_SLOWCMD)) {
- start_cmd = ESP_CMD_DMA | ESP_CMD_SELA;
+ start_cmd = ESP_CMD_SELA;
if (ent->tag[0]) {
*p++ = ent->tag[0];
*p++ = ent->tag[1];
- start_cmd = ESP_CMD_DMA | ESP_CMD_SA3;
+ start_cmd = ESP_CMD_SA3;
}
for (i = 0; i < cmd->cmd_len; i++)
@@ -806,7 +843,7 @@ build_identify:
esp->msg_out_len += 2;
}
- start_cmd = ESP_CMD_DMA | ESP_CMD_SELAS;
+ start_cmd = ESP_CMD_SELAS;
esp->select_state = ESP_SELECT_MSGOUT;
}
val = tgt;
@@ -826,10 +863,7 @@ build_identify:
printk("]\n");
}
- if (esp->rev == FASHME)
- scsi_esp_cmd(esp, ESP_CMD_FLUSH);
- esp->ops->send_dma_cmd(esp, esp->command_block_dma,
- val, 16, 0, start_cmd);
+ esp_send_dma_cmd(esp, val, 16, start_cmd);
}
static struct esp_cmd_entry *esp_get_ent(struct esp *esp)
@@ -953,8 +987,8 @@ static int esp_check_gross_error(struct esp *esp)
* - DMA programmed with wrong direction
* - improper phase change
*/
- printk(KERN_ERR PFX "esp%d: Gross error sreg[%02x]\n",
- esp->host->unique_id, esp->sreg);
+ shost_printk(KERN_ERR, esp->host,
+ "Gross error sreg[%02x]\n", esp->sreg);
/* XXX Reset the chip. XXX */
return 1;
}
@@ -974,7 +1008,6 @@ static int esp_check_spur_intr(struct esp *esp)
default:
if (!(esp->sreg & ESP_STAT_INTR)) {
- esp->ireg = esp_read8(ESP_INTRPT);
if (esp->ireg & ESP_INTR_SR)
return 1;
@@ -982,14 +1015,13 @@ static int esp_check_spur_intr(struct esp *esp)
* ESP is not, the only possibility is a DMA error.
*/
if (!esp->ops->dma_error(esp)) {
- printk(KERN_ERR PFX "esp%d: Spurious irq, "
- "sreg=%02x.\n",
- esp->host->unique_id, esp->sreg);
+ shost_printk(KERN_ERR, esp->host,
+ "Spurious irq, sreg=%02x.\n",
+ esp->sreg);
return -1;
}
- printk(KERN_ERR PFX "esp%d: DMA error\n",
- esp->host->unique_id);
+ shost_printk(KERN_ERR, esp->host, "DMA error\n");
/* XXX Reset the chip. XXX */
return -1;
@@ -1002,7 +1034,7 @@ static int esp_check_spur_intr(struct esp *esp)
static void esp_schedule_reset(struct esp *esp)
{
- esp_log_reset("ESP: esp_schedule_reset() from %pf\n",
+ esp_log_reset("esp_schedule_reset() from %pf\n",
__builtin_return_address(0));
esp->flags |= ESP_FLAG_RESETTING;
esp_event(esp, ESP_EVENT_RESET);
@@ -1019,20 +1051,20 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
int i;
if (!lp->num_tagged) {
- printk(KERN_ERR PFX "esp%d: Reconnect w/num_tagged==0\n",
- esp->host->unique_id);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect w/num_tagged==0\n");
return NULL;
}
- esp_log_reconnect("ESP: reconnect tag, ");
+ esp_log_reconnect("reconnect tag, ");
for (i = 0; i < ESP_QUICKIRQ_LIMIT; i++) {
if (esp->ops->irq_pending(esp))
break;
}
if (i == ESP_QUICKIRQ_LIMIT) {
- printk(KERN_ERR PFX "esp%d: Reconnect IRQ1 timeout\n",
- esp->host->unique_id);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect IRQ1 timeout\n");
return NULL;
}
@@ -1043,14 +1075,14 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
i, esp->ireg, esp->sreg);
if (esp->ireg & ESP_INTR_DC) {
- printk(KERN_ERR PFX "esp%d: Reconnect, got disconnect.\n",
- esp->host->unique_id);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect, got disconnect.\n");
return NULL;
}
if ((esp->sreg & ESP_STAT_PMASK) != ESP_MIP) {
- printk(KERN_ERR PFX "esp%d: Reconnect, not MIP sreg[%02x].\n",
- esp->host->unique_id, esp->sreg);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect, not MIP sreg[%02x].\n", esp->sreg);
return NULL;
}
@@ -1073,8 +1105,7 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
udelay(1);
}
if (i == ESP_RESELECT_TAG_LIMIT) {
- printk(KERN_ERR PFX "esp%d: Reconnect IRQ2 timeout\n",
- esp->host->unique_id);
+ shost_printk(KERN_ERR, esp->host, "Reconnect IRQ2 timeout\n");
return NULL;
}
esp->ops->dma_drain(esp);
@@ -1087,17 +1118,17 @@ static struct esp_cmd_entry *esp_reconnect_with_tag(struct esp *esp,
if (esp->command_block[0] < SIMPLE_QUEUE_TAG ||
esp->command_block[0] > ORDERED_QUEUE_TAG) {
- printk(KERN_ERR PFX "esp%d: Reconnect, bad tag "
- "type %02x.\n",
- esp->host->unique_id, esp->command_block[0]);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect, bad tag type %02x.\n",
+ esp->command_block[0]);
return NULL;
}
ent = lp->tagged_cmds[esp->command_block[1]];
if (!ent) {
- printk(KERN_ERR PFX "esp%d: Reconnect, no entry for "
- "tag %02x.\n",
- esp->host->unique_id, esp->command_block[1]);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect, no entry for tag %02x.\n",
+ esp->command_block[1]);
return NULL;
}
@@ -1163,9 +1194,9 @@ static int esp_reconnect(struct esp *esp)
tp = &esp->target[target];
dev = __scsi_device_lookup_by_target(tp->starget, lun);
if (!dev) {
- printk(KERN_ERR PFX "esp%d: Reconnect, no lp "
- "tgt[%u] lun[%u]\n",
- esp->host->unique_id, target, lun);
+ shost_printk(KERN_ERR, esp->host,
+ "Reconnect, no lp tgt[%u] lun[%u]\n",
+ target, lun);
goto do_reset;
}
lp = dev->hostdata;
@@ -1291,8 +1322,8 @@ static int esp_finish_select(struct esp *esp)
return 0;
}
- printk("ESP: Unexpected selection completion ireg[%x].\n",
- esp->ireg);
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected selection completion ireg[%x]\n", esp->ireg);
esp_schedule_reset(esp);
return 0;
}
@@ -1312,11 +1343,42 @@ static int esp_data_bytes_sent(struct esp *esp, struct esp_cmd_entry *ent,
(((unsigned int)esp_read8(ESP_TCMED)) << 8));
if (esp->rev == FASHME)
ecount |= ((unsigned int)esp_read8(FAS_RLO)) << 16;
+ if (esp->rev == PCSCSI && (esp->config2 & ESP_CONFIG2_FENAB))
+ ecount |= ((unsigned int)esp_read8(ESP_TCHI)) << 16;
}
bytes_sent = esp->data_dma_len;
bytes_sent -= ecount;
+ /*
+ * The am53c974 has a DMA 'pecularity'. The doc states:
+ * In some odd byte conditions, one residual byte will
+ * be left in the SCSI FIFO, and the FIFO Flags will
+ * never count to '0 '. When this happens, the residual
+ * byte should be retrieved via PIO following completion
+ * of the BLAST operation.
+ */
+ if (fifo_cnt == 1 && ent->flags & ESP_CMD_FLAG_RESIDUAL) {
+ size_t count = 1;
+ size_t offset = bytes_sent;
+ u8 bval = esp_read8(ESP_FDATA);
+
+ if (ent->flags & ESP_CMD_FLAG_AUTOSENSE)
+ ent->sense_ptr[bytes_sent] = bval;
+ else {
+ struct esp_cmd_priv *p = ESP_CMD_PRIV(cmd);
+ u8 *ptr;
+
+ ptr = scsi_kmap_atomic_sg(p->cur_sg, p->u.num_sg,
+ &offset, &count);
+ if (likely(ptr)) {
+ *(ptr + offset) = bval;
+ scsi_kunmap_atomic_sg(ptr);
+ }
+ }
+ bytes_sent += fifo_cnt;
+ ent->flags &= ~ESP_CMD_FLAG_RESIDUAL;
+ }
if (!(ent->flags & ESP_CMD_FLAG_WRITE))
bytes_sent -= fifo_cnt;
@@ -1556,8 +1618,8 @@ static void esp_msgin_extended(struct esp *esp)
return;
}
- printk("ESP: Unexpected extended msg type %x\n",
- esp->msg_in[2]);
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected extended msg type %x\n", esp->msg_in[2]);
esp->msg_out[0] = ABORT_TASK_SET;
esp->msg_out_len = 1;
@@ -1574,7 +1636,8 @@ static int esp_msgin_process(struct esp *esp)
if (msg0 & 0x80) {
/* Identify */
- printk("ESP: Unexpected msgin identify\n");
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected msgin identify\n");
return 0;
}
@@ -1640,10 +1703,12 @@ static int esp_msgin_process(struct esp *esp)
static int esp_process_event(struct esp *esp)
{
- int write;
+ int write, i;
again:
write = 0;
+ esp_log_event("process event %d phase %x\n",
+ esp->event, esp->sreg & ESP_STAT_PMASK);
switch (esp->event) {
case ESP_EVENT_CHECK_PHASE:
switch (esp->sreg & ESP_STAT_PMASK) {
@@ -1673,8 +1738,9 @@ again:
break;
default:
- printk("ESP: Unexpected phase, sreg=%02x\n",
- esp->sreg);
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected phase, sreg=%02x\n",
+ esp->sreg);
esp_schedule_reset(esp);
return 0;
}
@@ -1708,18 +1774,17 @@ again:
esp->data_dma_len = dma_len;
if (!dma_len) {
- printk(KERN_ERR PFX "esp%d: DMA length is zero!\n",
- esp->host->unique_id);
- printk(KERN_ERR PFX "esp%d: cur adr[%08llx] len[%08x]\n",
- esp->host->unique_id,
- (unsigned long long)esp_cur_dma_addr(ent, cmd),
- esp_cur_dma_len(ent, cmd));
+ shost_printk(KERN_ERR, esp->host,
+ "DMA length is zero!\n");
+ shost_printk(KERN_ERR, esp->host,
+ "cur adr[%08llx] len[%08x]\n",
+ (unsigned long long)esp_cur_dma_addr(ent, cmd),
+ esp_cur_dma_len(ent, cmd));
esp_schedule_reset(esp);
return 0;
}
- esp_log_datastart("ESP: start data addr[%08llx] len[%u] "
- "write(%d)\n",
+ esp_log_datastart("start data addr[%08llx] len[%u] write(%d)\n",
(unsigned long long)dma_addr, dma_len, write);
esp->ops->send_dma_cmd(esp, dma_addr, dma_len, dma_len,
@@ -1733,7 +1798,8 @@ again:
int bytes_sent;
if (esp->ops->dma_error(esp)) {
- printk("ESP: data done, DMA error, resetting\n");
+ shost_printk(KERN_INFO, esp->host,
+ "data done, DMA error, resetting\n");
esp_schedule_reset(esp);
return 0;
}
@@ -1749,14 +1815,15 @@ again:
/* We should always see exactly a bus-service
* interrupt at the end of a successful transfer.
*/
- printk("ESP: data done, not BSERV, resetting\n");
+ shost_printk(KERN_INFO, esp->host,
+ "data done, not BSERV, resetting\n");
esp_schedule_reset(esp);
return 0;
}
bytes_sent = esp_data_bytes_sent(esp, ent, cmd);
- esp_log_datadone("ESP: data done flgs[%x] sent[%d]\n",
+ esp_log_datadone("data done flgs[%x] sent[%d]\n",
ent->flags, bytes_sent);
if (bytes_sent < 0) {
@@ -1785,8 +1852,9 @@ again:
}
if (ent->message != COMMAND_COMPLETE) {
- printk("ESP: Unexpected message %x in status\n",
- ent->message);
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected message %x in status\n",
+ ent->message);
esp_schedule_reset(esp);
return 0;
}
@@ -1804,8 +1872,7 @@ again:
scsi_esp_cmd(esp, ESP_CMD_ESEL);
if (ent->message == COMMAND_COMPLETE) {
- esp_log_cmddone("ESP: Command done status[%x] "
- "message[%x]\n",
+ esp_log_cmddone("Command done status[%x] message[%x]\n",
ent->status, ent->message);
if (ent->status == SAM_STAT_TASK_SET_FULL)
esp_event_queue_full(esp, ent);
@@ -1821,16 +1888,16 @@ again:
DID_OK));
}
} else if (ent->message == DISCONNECT) {
- esp_log_disconnect("ESP: Disconnecting tgt[%d] "
- "tag[%x:%x]\n",
+ esp_log_disconnect("Disconnecting tgt[%d] tag[%x:%x]\n",
cmd->device->id,
ent->tag[0], ent->tag[1]);
esp->active_cmd = NULL;
esp_maybe_execute_command(esp);
} else {
- printk("ESP: Unexpected message %x in freebus\n",
- ent->message);
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected message %x in freebus\n",
+ ent->message);
esp_schedule_reset(esp);
return 0;
}
@@ -1862,6 +1929,10 @@ again:
if (esp->msg_out_len == 1) {
esp_write8(esp->msg_out[0], ESP_FDATA);
scsi_esp_cmd(esp, ESP_CMD_TI);
+ } else if (esp->flags & ESP_FLAG_USE_FIFO) {
+ for (i = 0; i < esp->msg_out_len; i++)
+ esp_write8(esp->msg_out[i], ESP_FDATA);
+ scsi_esp_cmd(esp, ESP_CMD_TI);
} else {
/* Use DMA. */
memcpy(esp->command_block,
@@ -1917,7 +1988,7 @@ again:
val = esp_read8(ESP_FDATA);
esp->msg_in[esp->msg_in_len++] = val;
- esp_log_msgin("ESP: Got msgin byte %x\n", val);
+ esp_log_msgin("Got msgin byte %x\n", val);
if (!esp_msgin_process(esp))
esp->msg_in_len = 0;
@@ -1930,7 +2001,8 @@ again:
if (esp->event != ESP_EVENT_FREE_BUS)
esp_event(esp, ESP_EVENT_CHECK_PHASE);
} else {
- printk("ESP: MSGIN neither BSERV not FDON, resetting");
+ shost_printk(KERN_INFO, esp->host,
+ "MSGIN neither BSERV not FDON, resetting");
esp_schedule_reset(esp);
return 0;
}
@@ -1938,11 +2010,7 @@ again:
case ESP_EVENT_CMD_START:
memcpy(esp->command_block, esp->cmd_bytes_ptr,
esp->cmd_bytes_left);
- if (esp->rev == FASHME)
- scsi_esp_cmd(esp, ESP_CMD_FLUSH);
- esp->ops->send_dma_cmd(esp, esp->command_block_dma,
- esp->cmd_bytes_left, 16, 0,
- ESP_CMD_DMA | ESP_CMD_TI);
+ esp_send_dma_cmd(esp, esp->cmd_bytes_left, 16, ESP_CMD_TI);
esp_event(esp, ESP_EVENT_CMD_DONE);
esp->flags |= ESP_FLAG_QUICKIRQ_CHECK;
break;
@@ -1961,8 +2029,8 @@ again:
break;
default:
- printk("ESP: Unexpected event %x, resetting\n",
- esp->event);
+ shost_printk(KERN_INFO, esp->host,
+ "Unexpected event %x, resetting\n", esp->event);
esp_schedule_reset(esp);
return 0;
break;
@@ -2044,7 +2112,12 @@ static void __esp_interrupt(struct esp *esp)
int finish_reset, intr_done;
u8 phase;
+ /*
+ * Once INTRPT is read STATUS and SSTEP are cleared.
+ */
esp->sreg = esp_read8(ESP_STATUS);
+ esp->seqreg = esp_read8(ESP_SSTEP);
+ esp->ireg = esp_read8(ESP_INTRPT);
if (esp->flags & ESP_FLAG_RESETTING) {
finish_reset = 1;
@@ -2057,8 +2130,6 @@ static void __esp_interrupt(struct esp *esp)
return;
}
- esp->ireg = esp_read8(ESP_INTRPT);
-
if (esp->ireg & ESP_INTR_SR)
finish_reset = 1;
@@ -2085,14 +2156,15 @@ static void __esp_interrupt(struct esp *esp)
}
}
- esp_log_intr("ESP: intr sreg[%02x] seqreg[%02x] "
+ esp_log_intr("intr sreg[%02x] seqreg[%02x] "
"sreg2[%02x] ireg[%02x]\n",
esp->sreg, esp->seqreg, esp->sreg2, esp->ireg);
intr_done = 0;
if (esp->ireg & (ESP_INTR_S | ESP_INTR_SATN | ESP_INTR_IC)) {
- printk("ESP: unexpected IREG %02x\n", esp->ireg);
+ shost_printk(KERN_INFO, esp->host,
+ "unexpected IREG %02x\n", esp->ireg);
if (esp->ireg & ESP_INTR_IC)
esp_dump_cmd_log(esp);
@@ -2149,46 +2221,50 @@ static void esp_get_revision(struct esp *esp)
u8 val;
esp->config1 = (ESP_CONFIG1_PENABLE | (esp->scsi_id & 7));
- esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+ if (esp->config2 == 0) {
+ esp->config2 = (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY);
+ esp_write8(esp->config2, ESP_CFG2);
+
+ val = esp_read8(ESP_CFG2);
+ val &= ~ESP_CONFIG2_MAGIC;
+
+ esp->config2 = 0;
+ if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
+ /*
+ * If what we write to cfg2 does not come back,
+ * cfg2 is not implemented.
+ * Therefore this must be a plain esp100.
+ */
+ esp->rev = ESP100;
+ return;
+ }
+ }
+
+ esp_set_all_config3(esp, 5);
+ esp->prev_cfg3 = 5;
esp_write8(esp->config2, ESP_CFG2);
+ esp_write8(0, ESP_CFG3);
+ esp_write8(esp->prev_cfg3, ESP_CFG3);
- val = esp_read8(ESP_CFG2);
- val &= ~ESP_CONFIG2_MAGIC;
- if (val != (ESP_CONFIG2_SCSI2ENAB | ESP_CONFIG2_REGPARITY)) {
- /* If what we write to cfg2 does not come back, cfg2 is not
- * implemented, therefore this must be a plain esp100.
+ val = esp_read8(ESP_CFG3);
+ if (val != 5) {
+ /* The cfg2 register is implemented, however
+ * cfg3 is not, must be esp100a.
*/
- esp->rev = ESP100;
+ esp->rev = ESP100A;
} else {
- esp->config2 = 0;
- esp_set_all_config3(esp, 5);
- esp->prev_cfg3 = 5;
- esp_write8(esp->config2, ESP_CFG2);
- esp_write8(0, ESP_CFG3);
+ esp_set_all_config3(esp, 0);
+ esp->prev_cfg3 = 0;
esp_write8(esp->prev_cfg3, ESP_CFG3);
- val = esp_read8(ESP_CFG3);
- if (val != 5) {
- /* The cfg2 register is implemented, however
- * cfg3 is not, must be esp100a.
- */
- esp->rev = ESP100A;
+ /* All of cfg{1,2,3} implemented, must be one of
+ * the fas variants, figure out which one.
+ */
+ if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
+ esp->rev = FAST;
+ esp->sync_defp = SYNC_DEFP_FAST;
} else {
- esp_set_all_config3(esp, 0);
- esp->prev_cfg3 = 0;
- esp_write8(esp->prev_cfg3, ESP_CFG3);
-
- /* All of cfg{1,2,3} implemented, must be one of
- * the fas variants, figure out which one.
- */
- if (esp->cfact == 0 || esp->cfact > ESP_CCF_F5) {
- esp->rev = FAST;
- esp->sync_defp = SYNC_DEFP_FAST;
- } else {
- esp->rev = ESP236;
- }
- esp->config2 = 0;
- esp_write8(esp->config2, ESP_CFG2);
+ esp->rev = ESP236;
}
}
}
@@ -2308,6 +2384,7 @@ static const char *esp_chip_names[] = {
"FAS100A",
"FAST",
"FASHME",
+ "AM53C974",
};
static struct scsi_transport_template *esp_transport_template;
@@ -2317,6 +2394,10 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
static int instance;
int err;
+ if (!esp->num_tags)
+ esp->num_tags = ESP_DEFAULT_TAGS;
+ else if (esp->num_tags >= ESP_MAX_TAG)
+ esp->num_tags = ESP_MAX_TAG - 1;
esp->host->transportt = esp_transport_template;
esp->host->max_lun = ESP_MAX_LUN;
esp->host->cmd_per_lun = 2;
@@ -2330,12 +2411,13 @@ int scsi_esp_register(struct esp *esp, struct device *dev)
esp_bootup_reset(esp);
- printk(KERN_INFO PFX "esp%u, regs[%1p:%1p] irq[%u]\n",
- esp->host->unique_id, esp->regs, esp->dma_regs,
- esp->host->irq);
- printk(KERN_INFO PFX "esp%u is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
- esp->host->unique_id, esp_chip_names[esp->rev],
- esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
+ dev_printk(KERN_INFO, dev, "esp%u: regs[%1p:%1p] irq[%u]\n",
+ esp->host->unique_id, esp->regs, esp->dma_regs,
+ esp->host->irq);
+ dev_printk(KERN_INFO, dev,
+ "esp%u: is a %s, %u MHz (ccf=%u), SCSI ID %u\n",
+ esp->host->unique_id, esp_chip_names[esp->rev],
+ esp->cfreq / 1000000, esp->cfact, esp->scsi_id);
/* Let the SCSI bus reset settle. */
ssleep(esp_bus_reset_settle);
@@ -2402,28 +2484,10 @@ static int esp_slave_configure(struct scsi_device *dev)
{
struct esp *esp = shost_priv(dev->host);
struct esp_target_data *tp = &esp->target[dev->id];
- int goal_tags, queue_depth;
-
- goal_tags = 0;
- if (dev->tagged_supported) {
- /* XXX make this configurable somehow XXX */
- goal_tags = ESP_DEFAULT_TAGS;
-
- if (goal_tags > ESP_MAX_TAG)
- goal_tags = ESP_MAX_TAG;
- }
+ if (dev->tagged_supported)
+ scsi_change_queue_depth(dev, esp->num_tags);
- queue_depth = goal_tags;
- if (queue_depth < dev->host->cmd_per_lun)
- queue_depth = dev->host->cmd_per_lun;
-
- if (goal_tags) {
- scsi_set_tag_type(dev, MSG_ORDERED_TAG);
- scsi_activate_tcq(dev, queue_depth);
- } else {
- scsi_deactivate_tcq(dev, queue_depth);
- }
tp->flags |= ESP_TGT_DISCONNECT;
if (!spi_initial_dv(dev->sdev_target))
@@ -2451,19 +2515,20 @@ static int esp_eh_abort_handler(struct scsi_cmnd *cmd)
* XXX much for the final driver.
*/
spin_lock_irqsave(esp->host->host_lock, flags);
- printk(KERN_ERR PFX "esp%d: Aborting command [%p:%02x]\n",
- esp->host->unique_id, cmd, cmd->cmnd[0]);
+ shost_printk(KERN_ERR, esp->host, "Aborting command [%p:%02x]\n",
+ cmd, cmd->cmnd[0]);
ent = esp->active_cmd;
if (ent)
- printk(KERN_ERR PFX "esp%d: Current command [%p:%02x]\n",
- esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ shost_printk(KERN_ERR, esp->host,
+ "Current command [%p:%02x]\n",
+ ent->cmd, ent->cmd->cmnd[0]);
list_for_each_entry(ent, &esp->queued_cmds, list) {
- printk(KERN_ERR PFX "esp%d: Queued command [%p:%02x]\n",
- esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ shost_printk(KERN_ERR, esp->host, "Queued command [%p:%02x]\n",
+ ent->cmd, ent->cmd->cmnd[0]);
}
list_for_each_entry(ent, &esp->active_cmds, list) {
- printk(KERN_ERR PFX "esp%d: Active command [%p:%02x]\n",
- esp->host->unique_id, ent->cmd, ent->cmd->cmnd[0]);
+ shost_printk(KERN_ERR, esp->host, " Active command [%p:%02x]\n",
+ ent->cmd, ent->cmd->cmnd[0]);
}
esp_dump_cmd_log(esp);
spin_unlock_irqrestore(esp->host->host_lock, flags);
@@ -2631,6 +2696,7 @@ struct scsi_host_template scsi_esp_template = {
.use_clustering = ENABLE_CLUSTERING,
.max_sectors = 0xffff,
.skip_settle_delay = 1,
+ .use_blk_tags = 1,
};
EXPORT_SYMBOL(scsi_esp_template);
diff --git a/drivers/scsi/esp_scsi.h b/drivers/scsi/esp_scsi.h
index cd68805..84dcbe4 100644
--- a/drivers/scsi/esp_scsi.h
+++ b/drivers/scsi/esp_scsi.h
@@ -1,4 +1,4 @@
-/* esp_scsi.h: Defines and structures for the ESP drier.
+/* esp_scsi.h: Defines and structures for the ESP driver.
*
* Copyright (C) 2007 David S. Miller (davem@davemloft.net)
*/
@@ -25,6 +25,7 @@
#define ESP_CTEST 0x0aUL /* wo Chip test register 0x28 */
#define ESP_CFG2 0x0bUL /* rw Second cfg register 0x2c */
#define ESP_CFG3 0x0cUL /* rw Third cfg register 0x30 */
+#define ESP_CFG4 0x0dUL /* rw Fourth cfg register 0x34 */
#define ESP_TCHI 0x0eUL /* rw High bits transf count 0x38 */
#define ESP_UID ESP_TCHI /* ro Unique ID code 0x38 */
#define FAS_RLO ESP_TCHI /* rw HME extended counter 0x38 */
@@ -76,6 +77,18 @@
#define ESP_CONFIG3_IMS 0x80 /* ID msg chk'ng (esp/fas236) */
#define ESP_CONFIG3_OBPUSH 0x80 /* Push odd-byte to dma (hme) */
+/* ESP config register 4 read-write, found only on am53c974 chips */
+#define ESP_CONFIG4_RADE 0x04 /* Active negation */
+#define ESP_CONFIG4_RAE 0x08 /* Active negation on REQ and ACK */
+#define ESP_CONFIG4_PWD 0x20 /* Reduced power feature */
+#define ESP_CONFIG4_GE0 0x40 /* Glitch eater bit 0 */
+#define ESP_CONFIG4_GE1 0x80 /* Glitch eater bit 1 */
+
+#define ESP_CONFIG_GE_12NS (0)
+#define ESP_CONFIG_GE_25NS (ESP_CONFIG_GE1)
+#define ESP_CONFIG_GE_35NS (ESP_CONFIG_GE0)
+#define ESP_CONFIG_GE_0NS (ESP_CONFIG_GE0 | ESP_CONFIG_GE1)
+
/* ESP command register read-write */
/* Group 1 commands: These may be sent at any point in time to the ESP
* chip. None of them can generate interrupts 'cept
@@ -254,6 +267,7 @@ enum esp_rev {
FAS100A = 0x04,
FAST = 0x05,
FASHME = 0x06,
+ PCSCSI = 0x07, /* AM53c974 */
};
struct esp_cmd_entry {
@@ -269,6 +283,7 @@ struct esp_cmd_entry {
#define ESP_CMD_FLAG_WRITE 0x01 /* DMA is a write */
#define ESP_CMD_FLAG_ABORT 0x02 /* being aborted */
#define ESP_CMD_FLAG_AUTOSENSE 0x04 /* Doing automatic REQUEST_SENSE */
+#define ESP_CMD_FLAG_RESIDUAL 0x08 /* AM53c974 BLAST residual */
u8 tag[2];
u8 orig_tag[2];
@@ -283,7 +298,6 @@ struct esp_cmd_entry {
struct completion *eh_done;
};
-/* XXX make this configurable somehow XXX */
#define ESP_DEFAULT_TAGS 16
#define ESP_MAX_TARGET 16
@@ -445,7 +459,7 @@ struct esp {
u8 prev_soff;
u8 prev_stp;
u8 prev_cfg3;
- u8 __pad;
+ u8 num_tags;
struct list_head esp_cmd_pool;
@@ -466,6 +480,7 @@ struct esp {
u8 bursts;
u8 config1;
u8 config2;
+ u8 config4;
u8 scsi_id;
u32 scsi_id_mask;
@@ -479,6 +494,7 @@ struct esp {
#define ESP_FLAG_WIDE_CAPABLE 0x00000008
#define ESP_FLAG_QUICKIRQ_CHECK 0x00000010
#define ESP_FLAG_DISABLE_SYNC 0x00000020
+#define ESP_FLAG_USE_FIFO 0x00000040
u8 select_state;
#define ESP_SELECT_NONE 0x00 /* Not selecting */
diff --git a/drivers/scsi/fcoe/fcoe.c b/drivers/scsi/fcoe/fcoe.c
index 73a8cc4..cd00a6c 100644
--- a/drivers/scsi/fcoe/fcoe.c
+++ b/drivers/scsi/fcoe/fcoe.c
@@ -280,14 +280,16 @@ static struct scsi_host_template fcoe_shost_template = {
.eh_device_reset_handler = fc_eh_device_reset,
.eh_host_reset_handler = fc_eh_host_reset,
.slave_alloc = fc_slave_alloc,
- .change_queue_depth = fc_change_queue_depth,
- .change_queue_type = fc_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.can_queue = FCOE_MAX_OUTSTANDING_COMMANDS,
.use_clustering = ENABLE_CLUSTERING,
.sg_tablesize = SG_ALL,
.max_sectors = 0xffff,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
/**
diff --git a/drivers/scsi/fnic/fnic.h b/drivers/scsi/fnic/fnic.h
index bf8d34c..3b73b96 100644
--- a/drivers/scsi/fnic/fnic.h
+++ b/drivers/scsi/fnic/fnic.h
@@ -39,7 +39,7 @@
#define DRV_NAME "fnic"
#define DRV_DESCRIPTION "Cisco FCoE HBA Driver"
-#define DRV_VERSION "1.6.0.11"
+#define DRV_VERSION "1.6.0.16"
#define PFX DRV_NAME ": "
#define DFX DRV_NAME "%d: "
diff --git a/drivers/scsi/fnic/fnic_fcs.c b/drivers/scsi/fnic/fnic_fcs.c
index f3984b4..bf0bbd4 100644
--- a/drivers/scsi/fnic/fnic_fcs.c
+++ b/drivers/scsi/fnic/fnic_fcs.c
@@ -135,6 +135,11 @@ void fnic_handle_link(struct work_struct *work)
fnic->lport->host->host_no, FNIC_FC_LE,
"Link Status: UP_DOWN",
strlen("Link Status: UP_DOWN"));
+ if (fnic->config.flags & VFCF_FIP_CAPABLE) {
+ FNIC_FCS_DBG(KERN_DEBUG, fnic->lport->host,
+ "deleting fip-timer during link-down\n");
+ del_timer_sync(&fnic->fip_timer);
+ }
fcoe_ctlr_link_down(&fnic->ctlr);
}
diff --git a/drivers/scsi/fnic/fnic_main.c b/drivers/scsi/fnic/fnic_main.c
index 8c56fdc..0c1f817 100644
--- a/drivers/scsi/fnic/fnic_main.c
+++ b/drivers/scsi/fnic/fnic_main.c
@@ -95,12 +95,10 @@ static int fnic_slave_alloc(struct scsi_device *sdev)
{
struct fc_rport *rport = starget_to_rport(scsi_target(sdev));
- sdev->tagged_supported = 1;
-
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- scsi_activate_tcq(sdev, fnic_max_qdepth);
+ scsi_change_queue_depth(sdev, fnic_max_qdepth);
return 0;
}
@@ -112,8 +110,8 @@ static struct scsi_host_template fnic_host_template = {
.eh_device_reset_handler = fnic_device_reset,
.eh_host_reset_handler = fnic_host_reset,
.slave_alloc = fnic_slave_alloc,
- .change_queue_depth = fc_change_queue_depth,
- .change_queue_type = fc_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.can_queue = FNIC_DFLT_IO_REQ,
@@ -121,6 +119,8 @@ static struct scsi_host_template fnic_host_template = {
.sg_tablesize = FNIC_MAX_SG_DESC_CNT,
.max_sectors = 0xffff,
.shost_attrs = fnic_attrs,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static void
@@ -438,21 +438,30 @@ static int fnic_dev_wait(struct vnic_dev *vdev,
unsigned long time;
int done;
int err;
+ int count;
+
+ count = 0;
err = start(vdev, arg);
if (err)
return err;
- /* Wait for func to complete...2 seconds max */
+ /* Wait for func to complete.
+ * Sometime schedule_timeout_uninterruptible take long time
+ * to wake up so we do not retry as we are only waiting for
+ * 2 seconds in while loop. By adding count, we make sure
+ * we try atleast three times before returning -ETIMEDOUT
+ */
time = jiffies + (HZ * 2);
do {
err = finished(vdev, &done);
+ count++;
if (err)
return err;
if (done)
return 0;
schedule_timeout_uninterruptible(HZ / 10);
- } while (time_after(time, jiffies));
+ } while (time_after(time, jiffies) || (count < 3));
return -ETIMEDOUT;
}
diff --git a/drivers/scsi/fnic/fnic_scsi.c b/drivers/scsi/fnic/fnic_scsi.c
index 961bdf5..2097de4 100644
--- a/drivers/scsi/fnic/fnic_scsi.c
+++ b/drivers/scsi/fnic/fnic_scsi.c
@@ -325,13 +325,11 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
struct fc_rport_libfc_priv *rp = rport->dd_data;
struct host_sg_desc *desc;
struct misc_stats *misc_stats = &fnic->fnic_stats.misc_stats;
- u8 pri_tag = 0;
unsigned int i;
unsigned long intr_flags;
int flags;
u8 exch_flags;
struct scsi_lun fc_lun;
- char msg[2];
if (sg_count) {
/* For each SGE, create a device desc entry */
@@ -357,12 +355,6 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
int_to_scsilun(sc->device->lun, &fc_lun);
- pri_tag = FCPIO_ICMND_PTA_SIMPLE;
- msg[0] = MSG_SIMPLE_TAG;
- scsi_populate_tag_msg(sc, msg);
- if (msg[0] == MSG_ORDERED_TAG)
- pri_tag = FCPIO_ICMND_PTA_ORDERED;
-
/* Enqueue the descriptor in the Copy WQ */
spin_lock_irqsave(&fnic->wq_copy_lock[0], intr_flags);
@@ -394,7 +386,8 @@ static inline int fnic_queue_wq_copy_desc(struct fnic *fnic,
io_req->sgl_list_pa,
io_req->sense_buf_pa,
0, /* scsi cmd ref, always 0 */
- pri_tag, /* scsi pri and tag */
+ FCPIO_ICMND_PTA_SIMPLE,
+ /* scsi pri and tag */
flags, /* command flags */
sc->cmnd, sc->cmd_len,
scsi_bufflen(sc),
@@ -428,8 +421,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
int ret;
u64 cmd_trace;
int sg_count = 0;
- unsigned long flags;
+ unsigned long flags = 0;
unsigned long ptr;
+ struct fc_rport_priv *rdata;
+ spinlock_t *io_lock = NULL;
if (unlikely(fnic_chk_state_flags_locked(fnic, FNIC_FLAGS_IO_BLOCKED)))
return SCSI_MLQUEUE_HOST_BUSY;
@@ -443,6 +438,16 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
return 0;
}
+ rdata = lp->tt.rport_lookup(lp, rport->port_id);
+ if (!rdata || (rdata->rp_state == RPORT_ST_DELETE)) {
+ FNIC_SCSI_DBG(KERN_DEBUG, fnic->lport->host,
+ "returning IO as rport is removed\n");
+ atomic64_inc(&fnic_stats->misc_stats.rport_not_ready);
+ sc->result = DID_NO_CONNECT;
+ done(sc);
+ return 0;
+ }
+
if (lp->state != LPORT_ST_READY || !(lp->link_up))
return SCSI_MLQUEUE_HOST_BUSY;
@@ -505,6 +510,13 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
}
}
+ /*
+ * Will acquire lock defore setting to IO initialized.
+ */
+
+ io_lock = fnic_io_lock_hash(fnic, sc);
+ spin_lock_irqsave(io_lock, flags);
+
/* initialize rest of io_req */
io_req->port_id = rport->port_id;
io_req->start_time = jiffies;
@@ -521,11 +533,9 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
* In case another thread cancelled the request,
* refetch the pointer under the lock.
*/
- spinlock_t *io_lock = fnic_io_lock_hash(fnic, sc);
FNIC_TRACE(fnic_queuecommand, sc->device->host->host_no,
sc->request->tag, sc, 0, 0, 0,
(((u64)CMD_FLAGS(sc) << 32) | CMD_STATE(sc)));
- spin_lock_irqsave(io_lock, flags);
io_req = (struct fnic_io_req *)CMD_SP(sc);
CMD_SP(sc) = NULL;
CMD_STATE(sc) = FNIC_IOREQ_CMD_COMPLETE;
@@ -534,6 +544,10 @@ static int fnic_queuecommand_lck(struct scsi_cmnd *sc, void (*done)(struct scsi_
fnic_release_ioreq_buf(fnic, io_req, sc);
mempool_free(io_req, fnic->io_req_pool);
}
+ atomic_dec(&fnic->in_flight);
+ /* acquire host lock before returning to SCSI */
+ spin_lock(lp->host->host_lock);
+ return ret;
} else {
atomic64_inc(&fnic_stats->io_stats.active_ios);
atomic64_inc(&fnic_stats->io_stats.num_ios);
@@ -555,6 +569,11 @@ out:
sc->request->tag, sc, io_req,
sg_count, cmd_trace,
(((u64)CMD_FLAGS(sc) >> 32) | CMD_STATE(sc)));
+
+ /* if only we issued IO, will we have the io lock */
+ if (CMD_FLAGS(sc) & FNIC_IO_INITIALIZED)
+ spin_unlock_irqrestore(io_lock, flags);
+
atomic_dec(&fnic->in_flight);
/* acquire host lock before returning to SCSI */
spin_lock(lp->host->host_lock);
diff --git a/drivers/scsi/fnic/fnic_trace.c b/drivers/scsi/fnic/fnic_trace.c
index acf1f95..65a9bde 100644
--- a/drivers/scsi/fnic/fnic_trace.c
+++ b/drivers/scsi/fnic/fnic_trace.c
@@ -624,12 +624,12 @@ int fnic_fc_trace_set_data(u32 host_no, u8 frame_type,
if (frame_type == FNIC_FC_RECV) {
eth_fcoe_hdr_len = sizeof(struct ethhdr) +
sizeof(struct fcoe_hdr);
- fc_trc_frame_len = fc_trc_frame_len + eth_fcoe_hdr_len;
memset((char *)fc_trace, 0xff, eth_fcoe_hdr_len);
/* Copy the rest of data frame */
memcpy((char *)(fc_trace + eth_fcoe_hdr_len), (void *)frame,
min_t(u8, fc_trc_frame_len,
- (u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE)));
+ (u8)(FC_TRC_SIZE_BYTES - FC_TRC_HEADER_SIZE
+ - eth_fcoe_hdr_len)));
} else {
memcpy((char *)fc_trace, (void *)frame,
min_t(u8, fc_trc_frame_len,
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
index b331272..f35792f 100644
--- a/drivers/scsi/g_NCR5380.c
+++ b/drivers/scsi/g_NCR5380.c
@@ -18,20 +18,6 @@
*
* Added ISAPNP support for DTC436 adapters,
* Thomas Sailer, sailer@ife.ee.ethz.ch
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
/*
@@ -40,14 +26,6 @@
*/
/*
- * Options :
- *
- * PARITY - enable parity checking. Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
- *
- * USLEEP - enable support for devices that don't disconnect. Untested.
- *
* The card is detected and initialized in one of several ways :
* 1. With command line overrides - NCR5380=port,irq may be
* used on the LILO command line to override the defaults.
@@ -79,27 +57,21 @@
*/
/* settings for DTC3181E card with only Mustek scanner attached */
-#define USLEEP
#define USLEEP_POLL 1
#define USLEEP_SLEEP 20
#define USLEEP_WAITLONG 500
#define AUTOPROBE_IRQ
-#define AUTOSENSE
-
#ifdef CONFIG_SCSI_GENERIC_NCR53C400
#define NCR53C400_PSEUDO_DMA 1
#define PSEUDO_DMA
#define NCR53C400
-#define NCR5380_STATS
-#undef NCR5380_STAT_LIMIT
#endif
#include <asm/io.h>
#include <linux/signal.h>
#include <linux/blkdev.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include "g_NCR5380.h"
#include "NCR5380.h"
@@ -277,7 +249,7 @@ static int __init do_DTC3181E_setup(char *str)
* Locks: none
*/
-int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
+static int __init generic_NCR5380_detect(struct scsi_host_template *tpnt)
{
static int current_override = 0;
int count;
@@ -335,7 +307,7 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
if (pnp_irq_valid(dev, 0))
overrides[count].irq = pnp_irq(dev, 0);
else
- overrides[count].irq = SCSI_IRQ_NONE;
+ overrides[count].irq = NO_IRQ;
if (pnp_dma_valid(dev, 0))
overrides[count].dma = pnp_dma(dev, 0);
else
@@ -455,27 +427,22 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
else
instance->irq = NCR5380_probe_irq(instance, 0xffff);
- if (instance->irq != SCSI_IRQ_NONE)
+ /* Compatibility with documented NCR5380 kernel parameters */
+ if (instance->irq == 255)
+ instance->irq = NO_IRQ;
+
+ if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, generic_NCR5380_intr,
0, "NCR5380", instance)) {
printk(KERN_WARNING "scsi%d : IRQ%d not free, interrupts disabled\n", instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
+ instance->irq = NO_IRQ;
}
- if (instance->irq == SCSI_IRQ_NONE) {
+ if (instance->irq == NO_IRQ) {
printk(KERN_INFO "scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk(KERN_INFO "scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
- printk(KERN_INFO "scsi%d : at " STRVAL(NCR5380_map_name) " 0x%x", instance->host_no, (unsigned int) instance->NCR5380_instance_name);
- if (instance->irq == SCSI_IRQ_NONE)
- printk(" interrupts disabled");
- else
- printk(" irq %d", instance->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d", CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
- NCR5380_print_options(instance);
- printk("\n");
-
++current_override;
++count;
}
@@ -483,19 +450,6 @@ int __init generic_NCR5380_detect(struct scsi_host_template * tpnt)
}
/**
- * generic_NCR5380_info - reporting string
- * @host: NCR5380 to report on
- *
- * Report driver information for the NCR5380
- */
-
-const char *generic_NCR5380_info(struct Scsi_Host *host)
-{
- static const char string[] = "Generic NCR5380/53C400 Driver";
- return string;
-}
-
-/**
* generic_NCR5380_release_resources - free resources
* @instance: host adapter to clean up
*
@@ -504,12 +458,12 @@ const char *generic_NCR5380_info(struct Scsi_Host *host)
* Locks: none
*/
-int generic_NCR5380_release_resources(struct Scsi_Host *instance)
+static int generic_NCR5380_release_resources(struct Scsi_Host *instance)
{
NCR5380_local_declare();
NCR5380_setup(instance);
- if (instance->irq != SCSI_IRQ_NONE)
+ if (instance->irq != NO_IRQ)
free_irq(instance->irq, instance);
NCR5380_exit(instance);
@@ -741,163 +695,9 @@ static inline int NCR5380_pwrite(struct Scsi_Host *instance, unsigned char *src,
#include "NCR5380.c"
-#define PRINTP(x) seq_printf(m, x)
-#define ANDP ,
-
-static void sprint_opcode(struct seq_file *m, int opcode)
-{
- PRINTP("0x%02x " ANDP opcode);
-}
-
-static void sprint_command(struct seq_file *m, unsigned char *command)
-{
- int i, s;
- sprint_opcode(m, command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- PRINTP("%02x " ANDP command[i]);
- PRINTP("\n");
-}
-
-/**
- * sprintf_Scsi_Cmnd - print a scsi command
- * @m: seq_fil to print into
- * @cmd: SCSI command block
- *
- * Print out the target and command data in hex
- */
-
-static void sprint_Scsi_Cmnd(struct seq_file *m, Scsi_Cmnd * cmd)
-{
- PRINTP("host number %d destination target %d, lun %llu\n" ANDP cmd->device->host->host_no ANDP cmd->device->id ANDP cmd->device->lun);
- PRINTP(" command = ");
- sprint_command(m, cmd->cmnd);
-}
-
-/**
- * generic_NCR5380_proc_info - /proc for NCR5380 driver
- * @buffer: buffer to print into
- * @start: start position
- * @offset: offset into buffer
- * @len: length
- * @hostno: instance to affect
- * @inout: read/write
- *
- * Provide the procfs information for the 5380 controller. We fill
- * this with useful debugging information including the commands
- * being executed, disconnected command queue and the statistical
- * data
- *
- * Locks: global cli/lock for queue walk
- */
-
-static int generic_NCR5380_show_info(struct seq_file *m, struct Scsi_Host *scsi_ptr)
-{
- NCR5380_local_declare();
- unsigned long flags;
- unsigned char status;
- int i;
- Scsi_Cmnd *ptr;
- struct NCR5380_hostdata *hostdata;
-#ifdef NCR5380_STATS
- struct scsi_device *dev;
-#endif
-
- NCR5380_setup(scsi_ptr);
- hostdata = (struct NCR5380_hostdata *) scsi_ptr->hostdata;
-
- spin_lock_irqsave(scsi_ptr->host_lock, flags);
- PRINTP("SCSI host number %d : %s\n" ANDP scsi_ptr->host_no ANDP scsi_ptr->hostt->name);
- PRINTP("Generic NCR5380 driver version %d\n" ANDP GENERIC_NCR5380_PUBLIC_RELEASE);
- PRINTP("NCR5380 core version %d\n" ANDP NCR5380_PUBLIC_RELEASE);
-#ifdef NCR53C400
- PRINTP("NCR53C400 extension version %d\n" ANDP NCR53C400_PUBLIC_RELEASE);
- PRINTP("NCR53C400 card%s detected\n" ANDP(((struct NCR5380_hostdata *) scsi_ptr->hostdata)->flags & FLAG_NCR53C400) ? "" : " not");
-# if NCR53C400_PSEUDO_DMA
- PRINTP("NCR53C400 pseudo DMA used\n");
-# endif
-#else
- PRINTP("NO NCR53C400 driver extensions\n");
-#endif
- PRINTP("Using %s mapping at %s 0x%lx, " ANDP STRVAL(NCR5380_map_config) ANDP STRVAL(NCR5380_map_name) ANDP scsi_ptr->NCR5380_instance_name);
- if (scsi_ptr->irq == SCSI_IRQ_NONE)
- PRINTP("no interrupt\n");
- else
- PRINTP("on interrupt %d\n" ANDP scsi_ptr->irq);
-
-#ifdef NCR5380_STATS
- if (hostdata->connected || hostdata->issue_queue || hostdata->disconnected_queue)
- PRINTP("There are commands pending, transfer rates may be crud\n");
- if (hostdata->pendingr)
- PRINTP(" %d pending reads" ANDP hostdata->pendingr);
- if (hostdata->pendingw)
- PRINTP(" %d pending writes" ANDP hostdata->pendingw);
- if (hostdata->pendingr || hostdata->pendingw)
- PRINTP("\n");
- shost_for_each_device(dev, scsi_ptr) {
- unsigned long br = hostdata->bytes_read[dev->id];
- unsigned long bw = hostdata->bytes_write[dev->id];
- long tr = hostdata->time_read[dev->id] / HZ;
- long tw = hostdata->time_write[dev->id] / HZ;
-
- PRINTP(" T:%d %s " ANDP dev->id ANDP scsi_device_type(dev->type));
- for (i = 0; i < 8; i++)
- if (dev->vendor[i] >= 0x20)
- seq_putc(m, dev->vendor[i]);
- seq_putc(m, ' ');
- for (i = 0; i < 16; i++)
- if (dev->model[i] >= 0x20)
- seq_putc(m, dev->model[i]);
- seq_putc(m, ' ');
- for (i = 0; i < 4; i++)
- if (dev->rev[i] >= 0x20)
- seq_putc(m, dev->rev[i]);
- seq_putc(m, ' ');
-
- PRINTP("\n%10ld kb read in %5ld secs" ANDP br / 1024 ANDP tr);
- if (tr)
- PRINTP(" @ %5ld bps" ANDP br / tr);
-
- PRINTP("\n%10ld kb written in %5ld secs" ANDP bw / 1024 ANDP tw);
- if (tw)
- PRINTP(" @ %5ld bps" ANDP bw / tw);
- PRINTP("\n");
- }
-#endif
-
- status = NCR5380_read(STATUS_REG);
- if (!(status & SR_REQ))
- PRINTP("REQ not asserted, phase unknown.\n");
- else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) && (phases[i].value != (status & PHASE_MASK)); ++i);
- PRINTP("Phase %s\n" ANDP phases[i].name);
- }
-
- if (!hostdata->connected) {
- PRINTP("No currently connected command\n");
- } else {
- sprint_Scsi_Cmnd(m, (Scsi_Cmnd *) hostdata->connected);
- }
-
- PRINTP("issue_queue\n");
-
- for (ptr = (Scsi_Cmnd *) hostdata->issue_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- sprint_Scsi_Cmnd(m, ptr);
-
- PRINTP("disconnected_queue\n");
-
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble)
- sprint_Scsi_Cmnd(m, ptr);
-
- spin_unlock_irqrestore(scsi_ptr->host_lock, flags);
- return 0;
-}
-
-#undef PRINTP
-#undef ANDP
-
static struct scsi_host_template driver_template = {
.show_info = generic_NCR5380_show_info,
- .name = "Generic NCR5380/NCR53C400 Scsi Driver",
+ .name = "Generic NCR5380/NCR53C400 SCSI",
.detect = generic_NCR5380_detect,
.release = generic_NCR5380_release_resources,
.info = generic_NCR5380_info,
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
index 703adf7..bea1a3b 100644
--- a/drivers/scsi/g_NCR5380.h
+++ b/drivers/scsi/g_NCR5380.h
@@ -9,28 +9,11 @@
*
* NCR53C400 extensions (c) 1994,1995,1996, Kevin Lentin
* K.Lentin@cs.monash.edu.au
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
#ifndef GENERIC_NCR5380_H
#define GENERIC_NCR5380_H
-
-#define GENERIC_NCR5380_PUBLIC_RELEASE 1
-
#ifdef NCR53C400
#define BIOSPARAM
#define NCR5380_BIOSPARAM generic_NCR5380_biosparam
@@ -39,12 +22,6 @@
#endif
#ifndef ASM
-static int generic_NCR5380_abort(Scsi_Cmnd *);
-static int generic_NCR5380_detect(struct scsi_host_template *);
-static int generic_NCR5380_release_resources(struct Scsi_Host *);
-static int generic_NCR5380_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int generic_NCR5380_bus_reset(Scsi_Cmnd *);
-static const char* generic_NCR5380_info(struct Scsi_Host *);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
@@ -118,7 +95,8 @@ static const char* generic_NCR5380_info(struct Scsi_Host *);
#define NCR5380_bus_reset generic_NCR5380_bus_reset
#define NCR5380_pread generic_NCR5380_pread
#define NCR5380_pwrite generic_NCR5380_pwrite
-#define NCR5380_proc_info notyet_generic_proc_info
+#define NCR5380_info generic_NCR5380_info
+#define NCR5380_show_info generic_NCR5380_show_info
#define BOARD_NCR5380 0
#define BOARD_NCR53C400 1
diff --git a/drivers/scsi/gdth.c b/drivers/scsi/gdth.c
index 0f1ae13..71e1380 100644
--- a/drivers/scsi/gdth.c
+++ b/drivers/scsi/gdth.c
@@ -2159,7 +2159,7 @@ static void gdth_next(gdth_ha_str *ha)
case VERIFY:
case START_STOP:
case MODE_SENSE:
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
TRACE(("cache cmd %x/%x/%x/%x/%x/%x\n",nscp->cmnd[0],
nscp->cmnd[1],nscp->cmnd[2],nscp->cmnd[3],
nscp->cmnd[4],nscp->cmnd[5]));
@@ -2391,7 +2391,7 @@ static int gdth_internal_cache_cmd(gdth_ha_str *ha, Scsi_Cmnd *scp)
gdth_copy_internal_data(ha, scp, (char*)&rdc, sizeof(gdth_rdcap_data));
break;
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
if ((scp->cmnd[1] & 0x1f) == SAI_READ_CAPACITY_16 &&
(ha->cache_feat & GDT_64BIT)) {
gdth_rdcap16_data rdc16;
@@ -4661,7 +4661,6 @@ static void gdth_flush(gdth_ha_str *ha)
/* configure lun */
static int gdth_slave_configure(struct scsi_device *sdev)
{
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
sdev->skip_ms_page_3f = 1;
sdev->skip_ms_page_8 = 1;
return 0;
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
index 6de80e3..8bb173e 100644
--- a/drivers/scsi/hosts.c
+++ b/drivers/scsi/hosts.c
@@ -418,7 +418,6 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
shost->cmd_per_lun = sht->cmd_per_lun;
shost->unchecked_isa_dma = sht->unchecked_isa_dma;
shost->use_clustering = sht->use_clustering;
- shost->ordered_tag = sht->ordered_tag;
shost->no_write_same = sht->no_write_same;
if (shost_eh_deadline == -1 || !sht->eh_host_reset_handler)
@@ -485,8 +484,8 @@ struct Scsi_Host *scsi_host_alloc(struct scsi_host_template *sht, int privsize)
WQ_UNBOUND | WQ_MEM_RECLAIM,
1, shost->host_no);
if (!shost->tmf_work_q) {
- printk(KERN_WARNING "scsi%d: failed to create tmf workq\n",
- shost->host_no);
+ shost_printk(KERN_WARNING, shost,
+ "failed to create tmf workq\n");
goto fail_kthread;
}
scsi_proc_hostdir_add(shost->hostt);
diff --git a/drivers/scsi/hpsa.c b/drivers/scsi/hpsa.c
index cef5d49..6bb4611 100644
--- a/drivers/scsi/hpsa.c
+++ b/drivers/scsi/hpsa.c
@@ -48,6 +48,7 @@
#include <linux/bitmap.h>
#include <linux/atomic.h>
#include <linux/jiffies.h>
+#include <linux/percpu-defs.h>
#include <linux/percpu.h>
#include <asm/div64.h>
#include "hpsa_cmd.h"
@@ -103,7 +104,6 @@ static const struct pci_device_id hpsa_pci_device_id[] = {
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1922},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1923},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1924},
- {PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1925},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1926},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1928},
{PCI_VENDOR_ID_HP, PCI_DEVICE_ID_HP_CISSH, 0x103C, 0x1929},
@@ -149,6 +149,7 @@ static struct board_type products[] = {
{0x3249103C, "Smart Array P812", &SA5_access},
{0x324A103C, "Smart Array P712m", &SA5_access},
{0x324B103C, "Smart Array P711m", &SA5_access},
+ {0x3233103C, "HP StorageWorks 1210m", &SA5_access}, /* alias of 333f */
{0x3350103C, "Smart Array P222", &SA5_access},
{0x3351103C, "Smart Array P420", &SA5_access},
{0x3352103C, "Smart Array P421", &SA5_access},
@@ -193,12 +194,13 @@ static int number_of_controllers;
static irqreturn_t do_hpsa_intr_intx(int irq, void *dev_id);
static irqreturn_t do_hpsa_intr_msi(int irq, void *dev_id);
-static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg);
+static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg);
static void lock_and_start_io(struct ctlr_info *h);
static void start_io(struct ctlr_info *h, unsigned long *flags);
#ifdef CONFIG_COMPAT
-static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg);
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd,
+ void __user *arg);
#endif
static void cmd_free(struct ctlr_info *h, struct CommandList *c);
@@ -214,8 +216,6 @@ static int hpsa_scsi_queue_command(struct Scsi_Host *h, struct scsi_cmnd *cmd);
static void hpsa_scan_start(struct Scsi_Host *);
static int hpsa_scan_finished(struct Scsi_Host *sh,
unsigned long elapsed_time);
-static int hpsa_change_queue_depth(struct scsi_device *sdev,
- int qdepth, int reason);
static int hpsa_eh_device_reset_handler(struct scsi_cmnd *scsicmd);
static int hpsa_eh_abort_handler(struct scsi_cmnd *scsicmd);
@@ -274,12 +274,12 @@ static int check_for_unit_attention(struct ctlr_info *h,
"detected, command retried\n", h->ctlr);
break;
case LUN_FAILED:
- dev_warn(&h->pdev->dev, HPSA "%d: LUN failure "
- "detected, action required\n", h->ctlr);
+ dev_warn(&h->pdev->dev,
+ HPSA "%d: LUN failure detected\n", h->ctlr);
break;
case REPORT_LUNS_CHANGED:
- dev_warn(&h->pdev->dev, HPSA "%d: report LUN data "
- "changed, action required\n", h->ctlr);
+ dev_warn(&h->pdev->dev,
+ HPSA "%d: report LUN data changed\n", h->ctlr);
/*
* Note: this REPORT_LUNS_CHANGED condition only occurs on the external
* target (array) devices.
@@ -392,7 +392,8 @@ static ssize_t host_show_commands_outstanding(struct device *dev,
struct Scsi_Host *shost = class_to_shost(dev);
struct ctlr_info *h = shost_to_hba(shost);
- return snprintf(buf, 20, "%d\n", h->commands_outstanding);
+ return snprintf(buf, 20, "%d\n",
+ atomic_read(&h->commands_outstanding));
}
static ssize_t host_show_transport_mode(struct device *dev,
@@ -670,7 +671,7 @@ static struct scsi_host_template hpsa_driver_template = {
.queuecommand = hpsa_scsi_queue_command,
.scan_start = hpsa_scan_start,
.scan_finished = hpsa_scan_finished,
- .change_queue_depth = hpsa_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.this_id = -1,
.use_clustering = ENABLE_CLUSTERING,
.eh_abort_handler = hpsa_eh_abort_handler,
@@ -698,7 +699,6 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
{
u32 a;
struct reply_queue_buffer *rq = &h->reply_queue[q];
- unsigned long flags;
if (h->transMethod & CFGTBL_Trans_io_accel1)
return h->access.command_completed(h, q);
@@ -709,9 +709,7 @@ static inline u32 next_command(struct ctlr_info *h, u8 q)
if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
a = rq->head[rq->current_entry];
rq->current_entry++;
- spin_lock_irqsave(&h->lock, flags);
- h->commands_outstanding--;
- spin_unlock_irqrestore(&h->lock, flags);
+ atomic_dec(&h->commands_outstanding);
} else {
a = FIFO_EMPTY;
}
@@ -1500,22 +1498,22 @@ static int hpsa_map_sg_chain_block(struct ctlr_info *h,
{
struct SGDescriptor *chain_sg, *chain_block;
u64 temp64;
+ u32 chain_len;
chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
chain_block = h->cmd_sg_list[c->cmdindex];
- chain_sg->Ext = HPSA_SG_CHAIN;
- chain_sg->Len = sizeof(*chain_sg) *
+ chain_sg->Ext = cpu_to_le32(HPSA_SG_CHAIN);
+ chain_len = sizeof(*chain_sg) *
(c->Header.SGTotal - h->max_cmd_sg_entries);
- temp64 = pci_map_single(h->pdev, chain_block, chain_sg->Len,
+ chain_sg->Len = cpu_to_le32(chain_len);
+ temp64 = pci_map_single(h->pdev, chain_block, chain_len,
PCI_DMA_TODEVICE);
if (dma_mapping_error(&h->pdev->dev, temp64)) {
/* prevent subsequent unmapping */
- chain_sg->Addr.lower = 0;
- chain_sg->Addr.upper = 0;
+ chain_sg->Addr = cpu_to_le64(0);
return -1;
}
- chain_sg->Addr.lower = (u32) (temp64 & 0x0FFFFFFFFULL);
- chain_sg->Addr.upper = (u32) ((temp64 >> 32) & 0x0FFFFFFFFULL);
+ chain_sg->Addr = cpu_to_le64(temp64);
return 0;
}
@@ -1523,15 +1521,13 @@ static void hpsa_unmap_sg_chain_block(struct ctlr_info *h,
struct CommandList *c)
{
struct SGDescriptor *chain_sg;
- union u64bit temp64;
- if (c->Header.SGTotal <= h->max_cmd_sg_entries)
+ if (le16_to_cpu(c->Header.SGTotal) <= h->max_cmd_sg_entries)
return;
chain_sg = &c->SG[h->max_cmd_sg_entries - 1];
- temp64.val32.lower = chain_sg->Addr.lower;
- temp64.val32.upper = chain_sg->Addr.upper;
- pci_unmap_single(h->pdev, temp64.val, chain_sg->Len, PCI_DMA_TODEVICE);
+ pci_unmap_single(h->pdev, le64_to_cpu(chain_sg->Addr),
+ le32_to_cpu(chain_sg->Len), PCI_DMA_TODEVICE);
}
@@ -1732,8 +1728,7 @@ static void complete_scsi_command(struct CommandList *cp)
struct io_accel1_cmd *c = &h->ioaccel_cmd_pool[cp->cmdindex];
cp->Header.SGList = cp->Header.SGTotal = scsi_sg_count(cmd);
cp->Request.CDBLen = c->io_flags & IOACCEL1_IOFLAGS_CDBLEN_MASK;
- cp->Header.Tag.lower = c->Tag.lower;
- cp->Header.Tag.upper = c->Tag.upper;
+ cp->Header.tag = c->tag;
memcpy(cp->Header.LUN.LunAddrBytes, c->CISS_LUN, 8);
memcpy(cp->Request.CDB, c->CDB, cp->Request.CDBLen);
@@ -1763,72 +1758,13 @@ static void complete_scsi_command(struct CommandList *cp)
/* Get addition sense code qualifier */
ascq = ei->SenseInfo[13];
}
-
if (ei->ScsiStatus == SAM_STAT_CHECK_CONDITION) {
- if (check_for_unit_attention(h, cp))
- break;
- if (sense_key == ILLEGAL_REQUEST) {
- /*
- * SCSI REPORT_LUNS is commonly unsupported on
- * Smart Array. Suppress noisy complaint.
- */
- if (cp->Request.CDB[0] == REPORT_LUNS)
- break;
-
- /* If ASC/ASCQ indicate Logical Unit
- * Not Supported condition,
- */
- if ((asc == 0x25) && (ascq == 0x0)) {
- dev_warn(&h->pdev->dev, "cp %p "
- "has check condition\n", cp);
- break;
- }
- }
-
- if (sense_key == NOT_READY) {
- /* If Sense is Not Ready, Logical Unit
- * Not ready, Manual Intervention
- * required
- */
- if ((asc == 0x04) && (ascq == 0x03)) {
- dev_warn(&h->pdev->dev, "cp %p "
- "has check condition: unit "
- "not ready, manual "
- "intervention required\n", cp);
- break;
- }
- }
if (sense_key == ABORTED_COMMAND) {
- /* Aborted command is retryable */
- dev_warn(&h->pdev->dev, "cp %p "
- "has check condition: aborted command: "
- "ASC: 0x%x, ASCQ: 0x%x\n",
- cp, asc, ascq);
cmd->result |= DID_SOFT_ERROR << 16;
break;
}
- /* Must be some other type of check condition */
- dev_dbg(&h->pdev->dev, "cp %p has check condition: "
- "unknown type: "
- "Sense: 0x%x, ASC: 0x%x, ASCQ: 0x%x, "
- "Returning result: 0x%x, "
- "cmd=[%02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x %02x "
- "%02x %02x %02x %02x %02x]\n",
- cp, sense_key, asc, ascq,
- cmd->result,
- cmd->cmnd[0], cmd->cmnd[1],
- cmd->cmnd[2], cmd->cmnd[3],
- cmd->cmnd[4], cmd->cmnd[5],
- cmd->cmnd[6], cmd->cmnd[7],
- cmd->cmnd[8], cmd->cmnd[9],
- cmd->cmnd[10], cmd->cmnd[11],
- cmd->cmnd[12], cmd->cmnd[13],
- cmd->cmnd[14], cmd->cmnd[15]);
break;
}
-
-
/* Problem was not a check condition
* Pass it up to the upper layers...
*/
@@ -1934,14 +1870,11 @@ static void hpsa_pci_unmap(struct pci_dev *pdev,
struct CommandList *c, int sg_used, int data_direction)
{
int i;
- union u64bit addr64;
- for (i = 0; i < sg_used; i++) {
- addr64.val32.lower = c->SG[i].Addr.lower;
- addr64.val32.upper = c->SG[i].Addr.upper;
- pci_unmap_single(pdev, (dma_addr_t) addr64.val, c->SG[i].Len,
- data_direction);
- }
+ for (i = 0; i < sg_used; i++)
+ pci_unmap_single(pdev, (dma_addr_t) le64_to_cpu(c->SG[i].Addr),
+ le32_to_cpu(c->SG[i].Len),
+ data_direction);
}
static int hpsa_map_one(struct pci_dev *pdev,
@@ -1954,25 +1887,22 @@ static int hpsa_map_one(struct pci_dev *pdev,
if (buflen == 0 || data_direction == PCI_DMA_NONE) {
cp->Header.SGList = 0;
- cp->Header.SGTotal = 0;
+ cp->Header.SGTotal = cpu_to_le16(0);
return 0;
}
- addr64 = (u64) pci_map_single(pdev, buf, buflen, data_direction);
+ addr64 = pci_map_single(pdev, buf, buflen, data_direction);
if (dma_mapping_error(&pdev->dev, addr64)) {
/* Prevent subsequent unmap of something never mapped */
cp->Header.SGList = 0;
- cp->Header.SGTotal = 0;
+ cp->Header.SGTotal = cpu_to_le16(0);
return -1;
}
- cp->SG[0].Addr.lower =
- (u32) (addr64 & (u64) 0x00000000FFFFFFFF);
- cp->SG[0].Addr.upper =
- (u32) ((addr64 >> 32) & (u64) 0x00000000FFFFFFFF);
- cp->SG[0].Len = buflen;
- cp->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining */
- cp->Header.SGList = (u8) 1; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (u16) 1; /* total sgs in this cmd list */
+ cp->SG[0].Addr = cpu_to_le64(addr64);
+ cp->SG[0].Len = cpu_to_le32(buflen);
+ cp->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* we are not chaining */
+ cp->Header.SGList = 1; /* no. SGs contig in this cmd */
+ cp->Header.SGTotal = cpu_to_le16(1); /* total sgs in cmd list */
return 0;
}
@@ -2830,8 +2760,8 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
if (d == NULL)
return 0; /* no match */
- it_nexus = cpu_to_le32((u32) d->ioaccel_handle);
- scsi_nexus = cpu_to_le32((u32) c2a->scsi_nexus);
+ it_nexus = cpu_to_le32(d->ioaccel_handle);
+ scsi_nexus = cpu_to_le32(c2a->scsi_nexus);
find = c2a->scsi_nexus;
if (h->raid_offload_debug > 0)
@@ -2891,7 +2821,7 @@ static int hpsa_get_pdisk_of_ioaccel2(struct ctlr_info *h,
* Returns 0 on success, -1 otherwise.
*/
static int hpsa_gather_lun_info(struct ctlr_info *h,
- int reportlunsize,
+ int reportphyslunsize, int reportloglunsize,
struct ReportLUNdata *physdev, u32 *nphysicals, int *physical_mode,
struct ReportLUNdata *logdev, u32 *nlogicals)
{
@@ -2905,7 +2835,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
*physical_mode = HPSA_REPORT_PHYS_EXTENDED;
physical_entry_size = 24;
}
- if (hpsa_scsi_do_report_phys_luns(h, physdev, reportlunsize,
+ if (hpsa_scsi_do_report_phys_luns(h, physdev, reportphyslunsize,
*physical_mode)) {
dev_err(&h->pdev->dev, "report physical LUNs failed.\n");
return -1;
@@ -2918,7 +2848,7 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
*nphysicals - HPSA_MAX_PHYS_LUN);
*nphysicals = HPSA_MAX_PHYS_LUN;
}
- if (hpsa_scsi_do_report_log_luns(h, logdev, reportlunsize)) {
+ if (hpsa_scsi_do_report_log_luns(h, logdev, reportloglunsize)) {
dev_err(&h->pdev->dev, "report logical LUNs failed.\n");
return -1;
}
@@ -2941,8 +2871,8 @@ static int hpsa_gather_lun_info(struct ctlr_info *h,
return 0;
}
-u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position, int i,
- int nphysicals, int nlogicals,
+static u8 *figure_lunaddrbytes(struct ctlr_info *h, int raid_ctlr_position,
+ int i, int nphysicals, int nlogicals,
struct ReportExtendedLUNdata *physdev_list,
struct ReportLUNdata *logdev_list)
{
@@ -3011,15 +2941,14 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
u32 ndev_allocated = 0;
struct hpsa_scsi_dev_t **currentsd, *this_device, *tmpdevice;
int ncurrent = 0;
- int reportlunsize = sizeof(*physdev_list) + HPSA_MAX_PHYS_LUN * 24;
int i, n_ext_target_devs, ndevs_to_allocate;
int raid_ctlr_position;
int rescan_hba_mode;
DECLARE_BITMAP(lunzerobits, MAX_EXT_TARGETS);
currentsd = kzalloc(sizeof(*currentsd) * HPSA_MAX_DEVICES, GFP_KERNEL);
- physdev_list = kzalloc(reportlunsize, GFP_KERNEL);
- logdev_list = kzalloc(reportlunsize, GFP_KERNEL);
+ physdev_list = kzalloc(sizeof(*physdev_list), GFP_KERNEL);
+ logdev_list = kzalloc(sizeof(*logdev_list), GFP_KERNEL);
tmpdevice = kzalloc(sizeof(*tmpdevice), GFP_KERNEL);
if (!currentsd || !physdev_list || !logdev_list || !tmpdevice) {
@@ -3039,7 +2968,8 @@ static void hpsa_update_scsi_devices(struct ctlr_info *h, int hostno)
h->hba_mode_enabled = rescan_hba_mode;
- if (hpsa_gather_lun_info(h, reportlunsize,
+ if (hpsa_gather_lun_info(h,
+ sizeof(*physdev_list), sizeof(*logdev_list),
(struct ReportLUNdata *) physdev_list, &nphysicals,
&physical_mode, logdev_list, &nlogicals))
goto out;
@@ -3210,19 +3140,19 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
}
addr64 = (u64) sg_dma_address(sg);
len = sg_dma_len(sg);
- curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
- curr_sg->Addr.upper = (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
- curr_sg->Len = len;
- curr_sg->Ext = (i < scsi_sg_count(cmd) - 1) ? 0 : HPSA_SG_LAST;
+ curr_sg->Addr = cpu_to_le64(addr64);
+ curr_sg->Len = cpu_to_le32(len);
+ curr_sg->Ext = cpu_to_le32(0);
curr_sg++;
}
+ (--curr_sg)->Ext = cpu_to_le32(HPSA_SG_LAST);
if (use_sg + chained > h->maxSG)
h->maxSG = use_sg + chained;
if (chained) {
cp->Header.SGList = h->max_cmd_sg_entries;
- cp->Header.SGTotal = (u16) (use_sg + 1);
+ cp->Header.SGTotal = cpu_to_le16(use_sg + 1);
if (hpsa_map_sg_chain_block(h, cp)) {
scsi_dma_unmap(cmd);
return -1;
@@ -3233,7 +3163,7 @@ static int hpsa_scatter_gather(struct ctlr_info *h,
sglist_finished:
cp->Header.SGList = (u8) use_sg; /* no. SGs contig in this cmd */
- cp->Header.SGTotal = (u16) use_sg; /* total sgs in this cmd list */
+ cp->Header.SGTotal = cpu_to_le16(use_sg); /* total sgs in this cmd list */
return 0;
}
@@ -3325,17 +3255,12 @@ static int hpsa_scsi_ioaccel1_queue_command(struct ctlr_info *h,
addr64 = (u64) sg_dma_address(sg);
len = sg_dma_len(sg);
total_len += len;
- curr_sg->Addr.lower = (u32) (addr64 & 0x0FFFFFFFFULL);
- curr_sg->Addr.upper =
- (u32) ((addr64 >> 32) & 0x0FFFFFFFFULL);
- curr_sg->Len = len;
-
- if (i == (scsi_sg_count(cmd) - 1))
- curr_sg->Ext = HPSA_SG_LAST;
- else
- curr_sg->Ext = 0; /* we are not chaining */
+ curr_sg->Addr = cpu_to_le64(addr64);
+ curr_sg->Len = cpu_to_le32(len);
+ curr_sg->Ext = cpu_to_le32(0);
curr_sg++;
}
+ (--curr_sg)->Ext = cpu_to_le32(HPSA_SG_LAST);
switch (cmd->sc_data_direction) {
case DMA_TO_DEVICE:
@@ -3592,7 +3517,7 @@ static int hpsa_scsi_ioaccel2_queue_command(struct ctlr_info *h,
cp->data_len = cpu_to_le32(total_len);
cp->err_ptr = cpu_to_le64(c->busaddr +
offsetof(struct io_accel2_cmd, error_data));
- cp->err_len = cpu_to_le32((u32) sizeof(cp->error_data));
+ cp->err_len = cpu_to_le32(sizeof(cp->error_data));
enqueue_cmd_and_start_io(h, c);
return 0;
@@ -3809,11 +3734,6 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
offload_to_mirror =
(offload_to_mirror >= map->layout_map_count - 1)
? 0 : offload_to_mirror + 1;
- /* FIXME: remove after debug/dev */
- BUG_ON(offload_to_mirror >= map->layout_map_count);
- dev_warn(&h->pdev->dev,
- "DEBUG: Using physical disk map index %d from mirror group %d\n",
- map_index, offload_to_mirror);
dev->offload_to_mirror = offload_to_mirror;
/* Avoid direct use of dev->offload_to_mirror within this
* function since multiple threads might simultaneously
@@ -3959,8 +3879,11 @@ static int hpsa_scsi_ioaccel_raid_map(struct ctlr_info *h,
dev->scsi3addr);
}
-static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
+/*
+ * Running in struct Scsi_Host->host_lock less mode using LLD internal
+ * struct ctlr_info *h->lock w/ spin_lock_irqsave() protection.
+ */
+static int hpsa_scsi_queue_command(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
{
struct ctlr_info *h;
struct hpsa_scsi_dev_t *dev;
@@ -3973,14 +3896,14 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
dev = cmd->device->hostdata;
if (!dev) {
cmd->result = DID_NO_CONNECT << 16;
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
memcpy(scsi3addr, dev->scsi3addr, sizeof(scsi3addr));
if (unlikely(lockup_detected(h))) {
cmd->result = DID_ERROR << 16;
- done(cmd);
+ cmd->scsi_done(cmd);
return 0;
}
c = cmd_alloc(h);
@@ -3990,9 +3913,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
}
/* Fill in the command list header */
-
- cmd->scsi_done = done; /* save this for use by completion code */
-
/* save c in case we have to abort it */
cmd->host_scribble = (unsigned char *) c;
@@ -4026,8 +3946,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
c->Header.ReplyQueue = 0; /* unused in simple mode */
memcpy(&c->Header.LUN.LunAddrBytes[0], &scsi3addr[0], 8);
- c->Header.Tag.lower = (c->cmdindex << DIRECT_LOOKUP_SHIFT);
- c->Header.Tag.lower |= DIRECT_LOOKUP_BIT;
+ c->Header.tag = cpu_to_le64((c->cmdindex << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT);
/* Fill in the request block... */
@@ -4036,17 +3956,18 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
BUG_ON(cmd->cmd_len > sizeof(c->Request.CDB));
c->Request.CDBLen = cmd->cmd_len;
memcpy(c->Request.CDB, cmd->cmnd, cmd->cmd_len);
- c->Request.Type.Type = TYPE_CMD;
- c->Request.Type.Attribute = ATTR_SIMPLE;
switch (cmd->sc_data_direction) {
case DMA_TO_DEVICE:
- c->Request.Type.Direction = XFER_WRITE;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_WRITE);
break;
case DMA_FROM_DEVICE:
- c->Request.Type.Direction = XFER_READ;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_READ);
break;
case DMA_NONE:
- c->Request.Type.Direction = XFER_NONE;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_NONE);
break;
case DMA_BIDIRECTIONAL:
/* This can happen if a buggy application does a scsi passthru
@@ -4054,7 +3975,8 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
* ../scsi/scsi_ioctl.c:scsi_ioctl_send_command() )
*/
- c->Request.Type.Direction = XFER_RSVD;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(TYPE_CMD, ATTR_SIMPLE, XFER_RSVD);
/* This is technically wrong, and hpsa controllers should
* reject it with CMD_INVALID, which is the most correct
* response, but non-fibre backends appear to let it
@@ -4081,8 +4003,6 @@ static int hpsa_scsi_queue_command_lck(struct scsi_cmnd *cmd,
return 0;
}
-static DEF_SCSI_QCMD(hpsa_scsi_queue_command)
-
static int do_not_scan_if_controller_locked_up(struct ctlr_info *h)
{
unsigned long flags;
@@ -4152,23 +4072,6 @@ static int hpsa_scan_finished(struct Scsi_Host *sh,
return finished;
}
-static int hpsa_change_queue_depth(struct scsi_device *sdev,
- int qdepth, int reason)
-{
- struct ctlr_info *h = sdev_to_hba(sdev);
-
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -ENOTSUPP;
-
- if (qdepth < 1)
- qdepth = 1;
- else
- if (qdepth > h->nr_cmds)
- qdepth = h->nr_cmds;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- return sdev->queue_depth;
-}
-
static void hpsa_unregister_scsi(struct ctlr_info *h)
{
/* we are being forcibly unloaded, and may not refuse. */
@@ -4329,8 +4232,8 @@ static void hpsa_get_tag(struct ctlr_info *h,
if (c->cmd_type == CMD_IOACCEL1) {
struct io_accel1_cmd *cm1 = (struct io_accel1_cmd *)
&h->ioaccel_cmd_pool[c->cmdindex];
- *tagupper = cm1->Tag.upper;
- *taglower = cm1->Tag.lower;
+ *tagupper = (u32) (cm1->tag >> 32);
+ *taglower = (u32) (cm1->tag & 0x0ffffffffULL);
return;
}
if (c->cmd_type == CMD_IOACCEL2) {
@@ -4341,11 +4244,10 @@ static void hpsa_get_tag(struct ctlr_info *h,
*taglower = cm2->Tag;
return;
}
- *tagupper = c->Header.Tag.upper;
- *taglower = c->Header.Tag.lower;
+ *tagupper = (u32) (c->Header.tag >> 32);
+ *taglower = (u32) (c->Header.tag & 0x0ffffffffULL);
}
-
static int hpsa_send_abort(struct ctlr_info *h, unsigned char *scsi3addr,
struct CommandList *abort, int swizzle)
{
@@ -4410,7 +4312,7 @@ static struct CommandList *hpsa_find_cmd_in_queue(struct ctlr_info *h,
struct CommandList *c = NULL; /* ptr into cmpQ */
if (!find)
- return 0;
+ return NULL;
spin_lock_irqsave(&h->lock, flags);
list_for_each_entry(c, queue_head, list) {
if (c->scsi_cmd == NULL) /* e.g.: passthru ioctl */
@@ -4432,7 +4334,7 @@ static struct CommandList *hpsa_find_cmd_in_queue_by_tag(struct ctlr_info *h,
spin_lock_irqsave(&h->lock, flags);
list_for_each_entry(c, queue_head, list) {
- if (memcmp(&c->Header.Tag, tag, 8) != 0)
+ if (memcmp(&c->Header.tag, tag, 8) != 0)
continue;
spin_unlock_irqrestore(&h->lock, flags);
return c;
@@ -4686,19 +4588,32 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
int i;
union u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
- unsigned long flags;
+ int loopcount;
+
+ /* There is some *extremely* small but non-zero chance that that
+ * multiple threads could get in here, and one thread could
+ * be scanning through the list of bits looking for a free
+ * one, but the free ones are always behind him, and other
+ * threads sneak in behind him and eat them before he can
+ * get to them, so that while there is always a free one, a
+ * very unlucky thread might be starved anyway, never able to
+ * beat the other threads. In reality, this happens so
+ * infrequently as to be indistinguishable from never.
+ */
- spin_lock_irqsave(&h->lock, flags);
+ loopcount = 0;
do {
i = find_first_zero_bit(h->cmd_pool_bits, h->nr_cmds);
- if (i == h->nr_cmds) {
- spin_unlock_irqrestore(&h->lock, flags);
- return NULL;
- }
- } while (test_and_set_bit
- (i & (BITS_PER_LONG - 1),
- h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0);
- spin_unlock_irqrestore(&h->lock, flags);
+ if (i == h->nr_cmds)
+ i = 0;
+ loopcount++;
+ } while (test_and_set_bit(i & (BITS_PER_LONG - 1),
+ h->cmd_pool_bits + (i / BITS_PER_LONG)) != 0 &&
+ loopcount < 10);
+
+ /* Thread got starved? We do not expect this to ever happen. */
+ if (loopcount >= 10)
+ return NULL;
c = h->cmd_pool + i;
memset(c, 0, sizeof(*c));
@@ -4714,9 +4629,8 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
temp64.val = (u64) err_dma_handle;
- c->ErrDesc.Addr.lower = temp64.val32.lower;
- c->ErrDesc.Addr.upper = temp64.val32.upper;
- c->ErrDesc.Len = sizeof(*c->err_info);
+ c->ErrDesc.Addr = cpu_to_le64(err_dma_handle);
+ c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info));
c->h = h;
return c;
@@ -4729,7 +4643,6 @@ static struct CommandList *cmd_alloc(struct ctlr_info *h)
static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
{
struct CommandList *c;
- union u64bit temp64;
dma_addr_t cmd_dma_handle, err_dma_handle;
c = pci_zalloc_consistent(h->pdev, sizeof(*c), &cmd_dma_handle);
@@ -4750,10 +4663,8 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
INIT_LIST_HEAD(&c->list);
c->busaddr = (u32) cmd_dma_handle;
- temp64.val = (u64) err_dma_handle;
- c->ErrDesc.Addr.lower = temp64.val32.lower;
- c->ErrDesc.Addr.upper = temp64.val32.upper;
- c->ErrDesc.Len = sizeof(*c->err_info);
+ c->ErrDesc.Addr = cpu_to_le64(err_dma_handle);
+ c->ErrDesc.Len = cpu_to_le32(sizeof(*c->err_info));
c->h = h;
return c;
@@ -4762,30 +4673,25 @@ static struct CommandList *cmd_special_alloc(struct ctlr_info *h)
static void cmd_free(struct ctlr_info *h, struct CommandList *c)
{
int i;
- unsigned long flags;
i = c - h->cmd_pool;
- spin_lock_irqsave(&h->lock, flags);
clear_bit(i & (BITS_PER_LONG - 1),
h->cmd_pool_bits + (i / BITS_PER_LONG));
- spin_unlock_irqrestore(&h->lock, flags);
}
static void cmd_special_free(struct ctlr_info *h, struct CommandList *c)
{
- union u64bit temp64;
-
- temp64.val32.lower = c->ErrDesc.Addr.lower;
- temp64.val32.upper = c->ErrDesc.Addr.upper;
pci_free_consistent(h->pdev, sizeof(*c->err_info),
- c->err_info, (dma_addr_t) temp64.val);
+ c->err_info,
+ (dma_addr_t) le64_to_cpu(c->ErrDesc.Addr));
pci_free_consistent(h->pdev, sizeof(*c),
c, (dma_addr_t) (c->busaddr & DIRECT_LOOKUP_MASK));
}
#ifdef CONFIG_COMPAT
-static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
+static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd,
+ void __user *arg)
{
IOCTL32_Command_struct __user *arg32 =
(IOCTL32_Command_struct __user *) arg;
@@ -4810,7 +4716,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
if (err)
return -EFAULT;
- err = hpsa_ioctl(dev, CCISS_PASSTHRU, (void *)p);
+ err = hpsa_ioctl(dev, CCISS_PASSTHRU, p);
if (err)
return err;
err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -4821,7 +4727,7 @@ static int hpsa_ioctl32_passthru(struct scsi_device *dev, int cmd, void *arg)
}
static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
- int cmd, void *arg)
+ int cmd, void __user *arg)
{
BIG_IOCTL32_Command_struct __user *arg32 =
(BIG_IOCTL32_Command_struct __user *) arg;
@@ -4848,7 +4754,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
if (err)
return -EFAULT;
- err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, (void *)p);
+ err = hpsa_ioctl(dev, CCISS_BIG_PASSTHRU, p);
if (err)
return err;
err |= copy_in_user(&arg32->error_info, &p->error_info,
@@ -4858,7 +4764,7 @@ static int hpsa_ioctl32_big_passthru(struct scsi_device *dev,
return err;
}
-static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void *arg)
+static int hpsa_compat_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
{
switch (cmd) {
case CCISS_GETPCIINFO:
@@ -4932,7 +4838,7 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
IOCTL_Command_struct iocommand;
struct CommandList *c;
char *buff = NULL;
- union u64bit temp64;
+ u64 temp64;
int rc = 0;
if (!argp)
@@ -4971,14 +4877,14 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
c->Header.ReplyQueue = 0; /* unused in simple mode */
if (iocommand.buf_size > 0) { /* buffer to fill */
c->Header.SGList = 1;
- c->Header.SGTotal = 1;
+ c->Header.SGTotal = cpu_to_le16(1);
} else { /* no buffers to fill */
c->Header.SGList = 0;
- c->Header.SGTotal = 0;
+ c->Header.SGTotal = cpu_to_le16(0);
}
memcpy(&c->Header.LUN, &iocommand.LUN_info, sizeof(c->Header.LUN));
/* use the kernel address the cmd block for tag */
- c->Header.Tag.lower = c->busaddr;
+ c->Header.tag = c->busaddr;
/* Fill in Request block */
memcpy(&c->Request, &iocommand.Request,
@@ -4986,19 +4892,17 @@ static int hpsa_passthru_ioctl(struct ctlr_info *h, void __user *argp)
/* Fill in the scatter gather information */
if (iocommand.buf_size > 0) {
- temp64.val = pci_map_single(h->pdev, buff,
+ temp64 = pci_map_single(h->pdev, buff,
iocommand.buf_size, PCI_DMA_BIDIRECTIONAL);
- if (dma_mapping_error(&h->pdev->dev, temp64.val)) {
- c->SG[0].Addr.lower = 0;
- c->SG[0].Addr.upper = 0;
- c->SG[0].Len = 0;
+ if (dma_mapping_error(&h->pdev->dev, (dma_addr_t) temp64)) {
+ c->SG[0].Addr = cpu_to_le64(0);
+ c->SG[0].Len = cpu_to_le32(0);
rc = -ENOMEM;
goto out;
}
- c->SG[0].Addr.lower = temp64.val32.lower;
- c->SG[0].Addr.upper = temp64.val32.upper;
- c->SG[0].Len = iocommand.buf_size;
- c->SG[0].Ext = HPSA_SG_LAST; /* we are not chaining*/
+ c->SG[0].Addr = cpu_to_le64(temp64);
+ c->SG[0].Len = cpu_to_le32(iocommand.buf_size);
+ c->SG[0].Ext = cpu_to_le32(HPSA_SG_LAST); /* not chaining */
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
if (iocommand.buf_size > 0)
@@ -5033,7 +4937,7 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
struct CommandList *c;
unsigned char **buff = NULL;
int *buff_size = NULL;
- union u64bit temp64;
+ u64 temp64;
BYTE sg_used = 0;
int status = 0;
int i;
@@ -5107,29 +5011,30 @@ static int hpsa_big_passthru_ioctl(struct ctlr_info *h, void __user *argp)
}
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
- c->Header.SGList = c->Header.SGTotal = sg_used;
+ c->Header.SGList = (u8) sg_used;
+ c->Header.SGTotal = cpu_to_le16(sg_used);
memcpy(&c->Header.LUN, &ioc->LUN_info, sizeof(c->Header.LUN));
- c->Header.Tag.lower = c->busaddr;
+ c->Header.tag = c->busaddr;
memcpy(&c->Request, &ioc->Request, sizeof(c->Request));
if (ioc->buf_size > 0) {
int i;
for (i = 0; i < sg_used; i++) {
- temp64.val = pci_map_single(h->pdev, buff[i],
+ temp64 = pci_map_single(h->pdev, buff[i],
buff_size[i], PCI_DMA_BIDIRECTIONAL);
- if (dma_mapping_error(&h->pdev->dev, temp64.val)) {
- c->SG[i].Addr.lower = 0;
- c->SG[i].Addr.upper = 0;
- c->SG[i].Len = 0;
+ if (dma_mapping_error(&h->pdev->dev,
+ (dma_addr_t) temp64)) {
+ c->SG[i].Addr = cpu_to_le64(0);
+ c->SG[i].Len = cpu_to_le32(0);
hpsa_pci_unmap(h->pdev, c, i,
PCI_DMA_BIDIRECTIONAL);
status = -ENOMEM;
goto cleanup0;
}
- c->SG[i].Addr.lower = temp64.val32.lower;
- c->SG[i].Addr.upper = temp64.val32.upper;
- c->SG[i].Len = buff_size[i];
- c->SG[i].Ext = i < sg_used - 1 ? 0 : HPSA_SG_LAST;
+ c->SG[i].Addr = cpu_to_le64(temp64);
+ c->SG[i].Len = cpu_to_le32(buff_size[i]);
+ c->SG[i].Ext = cpu_to_le32(0);
}
+ c->SG[--i].Ext = cpu_to_le32(HPSA_SG_LAST);
}
hpsa_scsi_do_simple_cmd_core_if_no_lockup(h, c);
if (sg_used)
@@ -5206,7 +5111,7 @@ static void decrement_passthru_count(struct ctlr_info *h)
/*
* ioctl
*/
-static int hpsa_ioctl(struct scsi_device *dev, int cmd, void *arg)
+static int hpsa_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
{
struct ctlr_info *h;
void __user *argp = (void __user *)arg;
@@ -5268,20 +5173,20 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
{
int pci_dir = XFER_NONE;
struct CommandList *a; /* for commands to be aborted */
+ u32 tupper, tlower;
c->cmd_type = CMD_IOCTL_PEND;
c->Header.ReplyQueue = 0;
if (buff != NULL && size > 0) {
c->Header.SGList = 1;
- c->Header.SGTotal = 1;
+ c->Header.SGTotal = cpu_to_le16(1);
} else {
c->Header.SGList = 0;
- c->Header.SGTotal = 0;
+ c->Header.SGTotal = cpu_to_le16(0);
}
- c->Header.Tag.lower = c->busaddr;
+ c->Header.tag = c->busaddr;
memcpy(c->Header.LUN.LunAddrBytes, scsi3addr, 8);
- c->Request.Type.Type = cmd_type;
if (cmd_type == TYPE_CMD) {
switch (cmd) {
case HPSA_INQUIRY:
@@ -5291,8 +5196,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
c->Request.CDB[2] = (page_code & 0xff);
}
c->Request.CDBLen = 6;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_READ;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
c->Request.Timeout = 0;
c->Request.CDB[0] = HPSA_INQUIRY;
c->Request.CDB[4] = size & 0xFF;
@@ -5303,8 +5208,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
mode = 00 target = 0. Nothing to write.
*/
c->Request.CDBLen = 12;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_READ;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
c->Request.Timeout = 0;
c->Request.CDB[0] = cmd;
c->Request.CDB[6] = (size >> 24) & 0xFF; /* MSB */
@@ -5314,8 +5219,9 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
break;
case HPSA_CACHE_FLUSH:
c->Request.CDBLen = 12;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_WRITE;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type,
+ ATTR_SIMPLE, XFER_WRITE);
c->Request.Timeout = 0;
c->Request.CDB[0] = BMIC_WRITE;
c->Request.CDB[6] = BMIC_CACHE_FLUSH;
@@ -5324,14 +5230,14 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
break;
case TEST_UNIT_READY:
c->Request.CDBLen = 6;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_NONE;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
c->Request.Timeout = 0;
break;
case HPSA_GET_RAID_MAP:
c->Request.CDBLen = 12;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_READ;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
c->Request.Timeout = 0;
c->Request.CDB[0] = HPSA_CISS_READ;
c->Request.CDB[1] = cmd;
@@ -5342,8 +5248,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
break;
case BMIC_SENSE_CONTROLLER_PARAMETERS:
c->Request.CDBLen = 10;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_READ;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_READ);
c->Request.Timeout = 0;
c->Request.CDB[0] = BMIC_READ;
c->Request.CDB[6] = BMIC_SENSE_CONTROLLER_PARAMETERS;
@@ -5360,9 +5266,8 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
case HPSA_DEVICE_RESET_MSG:
c->Request.CDBLen = 16;
- c->Request.Type.Type = 1; /* It is a MSG not a CMD */
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_NONE;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type, ATTR_SIMPLE, XFER_NONE);
c->Request.Timeout = 0; /* Don't time out */
memset(&c->Request.CDB[0], 0, sizeof(c->Request.CDB));
c->Request.CDB[0] = cmd;
@@ -5376,27 +5281,28 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
break;
case HPSA_ABORT_MSG:
a = buff; /* point to command to be aborted */
- dev_dbg(&h->pdev->dev, "Abort Tag:0x%08x:%08x using request Tag:0x%08x:%08x\n",
- a->Header.Tag.upper, a->Header.Tag.lower,
- c->Header.Tag.upper, c->Header.Tag.lower);
+ dev_dbg(&h->pdev->dev, "Abort Tag:0x%016llx using request Tag:0x%016llx",
+ a->Header.tag, c->Header.tag);
+ tlower = (u32) (a->Header.tag >> 32);
+ tupper = (u32) (a->Header.tag & 0x0ffffffffULL);
c->Request.CDBLen = 16;
- c->Request.Type.Type = TYPE_MSG;
- c->Request.Type.Attribute = ATTR_SIMPLE;
- c->Request.Type.Direction = XFER_WRITE;
+ c->Request.type_attr_dir =
+ TYPE_ATTR_DIR(cmd_type,
+ ATTR_SIMPLE, XFER_WRITE);
c->Request.Timeout = 0; /* Don't time out */
c->Request.CDB[0] = HPSA_TASK_MANAGEMENT;
c->Request.CDB[1] = HPSA_TMF_ABORT_TASK;
c->Request.CDB[2] = 0x00; /* reserved */
c->Request.CDB[3] = 0x00; /* reserved */
/* Tag to abort goes in CDB[4]-CDB[11] */
- c->Request.CDB[4] = a->Header.Tag.lower & 0xFF;
- c->Request.CDB[5] = (a->Header.Tag.lower >> 8) & 0xFF;
- c->Request.CDB[6] = (a->Header.Tag.lower >> 16) & 0xFF;
- c->Request.CDB[7] = (a->Header.Tag.lower >> 24) & 0xFF;
- c->Request.CDB[8] = a->Header.Tag.upper & 0xFF;
- c->Request.CDB[9] = (a->Header.Tag.upper >> 8) & 0xFF;
- c->Request.CDB[10] = (a->Header.Tag.upper >> 16) & 0xFF;
- c->Request.CDB[11] = (a->Header.Tag.upper >> 24) & 0xFF;
+ c->Request.CDB[4] = tlower & 0xFF;
+ c->Request.CDB[5] = (tlower >> 8) & 0xFF;
+ c->Request.CDB[6] = (tlower >> 16) & 0xFF;
+ c->Request.CDB[7] = (tlower >> 24) & 0xFF;
+ c->Request.CDB[8] = tupper & 0xFF;
+ c->Request.CDB[9] = (tupper >> 8) & 0xFF;
+ c->Request.CDB[10] = (tupper >> 16) & 0xFF;
+ c->Request.CDB[11] = (tupper >> 24) & 0xFF;
c->Request.CDB[12] = 0x00; /* reserved */
c->Request.CDB[13] = 0x00; /* reserved */
c->Request.CDB[14] = 0x00; /* reserved */
@@ -5412,7 +5318,7 @@ static int fill_cmd(struct CommandList *c, u8 cmd, struct ctlr_info *h,
BUG();
}
- switch (c->Request.Type.Direction) {
+ switch (GET_DIR(c->Request.type_attr_dir)) {
case XFER_READ:
pci_dir = PCI_DMA_FROMDEVICE;
break;
@@ -5467,15 +5373,9 @@ static void start_io(struct ctlr_info *h, unsigned long *flags)
/* Put job onto the completed Q */
addQ(&h->cmpQ, c);
-
- /* Must increment commands_outstanding before unlocking
- * and submitting to avoid race checking for fifo full
- * condition.
- */
- h->commands_outstanding++;
-
- /* Tell the controller execute command */
+ atomic_inc(&h->commands_outstanding);
spin_unlock_irqrestore(&h->lock, *flags);
+ /* Tell the controller execute command */
h->access.submit_command(h, c);
spin_lock_irqsave(&h->lock, *flags);
}
@@ -5521,6 +5421,7 @@ static inline void finish_cmd(struct CommandList *c)
unsigned long flags;
int io_may_be_stalled = 0;
struct ctlr_info *h = c->h;
+ int count;
spin_lock_irqsave(&h->lock, flags);
removeQ(c);
@@ -5541,11 +5442,10 @@ static inline void finish_cmd(struct CommandList *c)
* want to get in a cycle where we call start_io every time
* through here.
*/
- if (unlikely(h->fifo_recently_full) &&
- h->commands_outstanding < 5)
- io_may_be_stalled = 1;
-
+ count = atomic_read(&h->commands_outstanding);
spin_unlock_irqrestore(&h->lock, flags);
+ if (unlikely(h->fifo_recently_full) && count < 5)
+ io_may_be_stalled = 1;
dial_up_lockup_detection_on_fw_flash_complete(c->h, c);
if (likely(c->cmd_type == CMD_IOACCEL1 || c->cmd_type == CMD_SCSI
@@ -5765,22 +5665,20 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
cmd->CommandHeader.ReplyQueue = 0;
cmd->CommandHeader.SGList = 0;
- cmd->CommandHeader.SGTotal = 0;
- cmd->CommandHeader.Tag.lower = paddr32;
- cmd->CommandHeader.Tag.upper = 0;
+ cmd->CommandHeader.SGTotal = cpu_to_le16(0);
+ cmd->CommandHeader.tag = paddr32;
memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
cmd->Request.CDBLen = 16;
- cmd->Request.Type.Type = TYPE_MSG;
- cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE;
- cmd->Request.Type.Direction = XFER_NONE;
+ cmd->Request.type_attr_dir =
+ TYPE_ATTR_DIR(TYPE_MSG, ATTR_HEADOFQUEUE, XFER_NONE);
cmd->Request.Timeout = 0; /* Don't time out */
cmd->Request.CDB[0] = opcode;
cmd->Request.CDB[1] = type;
memset(&cmd->Request.CDB[2], 0, 14); /* rest of the CDB is reserved */
- cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(*cmd);
- cmd->ErrorDescriptor.Addr.upper = 0;
- cmd->ErrorDescriptor.Len = sizeof(struct ErrorInfo);
+ cmd->ErrorDescriptor.Addr =
+ cpu_to_le64((paddr32 + sizeof(*cmd)));
+ cmd->ErrorDescriptor.Len = cpu_to_le32(sizeof(struct ErrorInfo));
writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET);
@@ -5818,7 +5716,7 @@ static int hpsa_message(struct pci_dev *pdev, unsigned char opcode,
#define hpsa_noop(p) hpsa_message(p, 3, 0)
static int hpsa_controller_hard_reset(struct pci_dev *pdev,
- void * __iomem vaddr, u32 use_doorbell)
+ void __iomem *vaddr, u32 use_doorbell)
{
u16 pmcsr;
int pos;
@@ -6056,7 +5954,7 @@ unmap_vaddr:
* the io functions.
* This is for debug only.
*/
-static void print_cfg_table(struct device *dev, struct CfgTable *tb)
+static void print_cfg_table(struct device *dev, struct CfgTable __iomem *tb)
{
#ifdef HPSA_DEBUG
int i;
@@ -6323,11 +6221,11 @@ static void hpsa_find_board_params(struct ctlr_info *h)
h->max_cmd_sg_entries = 31;
if (h->maxsgentries > 512) {
h->max_cmd_sg_entries = 32;
- h->chainsize = h->maxsgentries - h->max_cmd_sg_entries + 1;
+ h->chainsize = h->maxsgentries - h->max_cmd_sg_entries;
h->maxsgentries--; /* save one for chain pointer */
} else {
- h->maxsgentries = 31; /* default to traditional values */
h->chainsize = 0;
+ h->maxsgentries = 31; /* default to traditional values */
}
/* Find out what task management functions are supported and cache */
@@ -6456,15 +6354,15 @@ static int hpsa_pci_init(struct ctlr_info *h)
return err;
}
- /* Enable bus mastering (pci_disable_device may disable this) */
- pci_set_master(h->pdev);
-
err = pci_request_regions(h->pdev, HPSA);
if (err) {
dev_err(&h->pdev->dev,
"cannot obtain PCI resources, aborting\n");
return err;
}
+
+ pci_set_master(h->pdev);
+
hpsa_interrupt_mode(h);
err = hpsa_pci_find_memory_BAR(h->pdev, &h->paddr);
if (err)
@@ -6544,7 +6442,9 @@ static int hpsa_init_reset_devices(struct pci_dev *pdev)
dev_warn(&pdev->dev, "failed to enable device.\n");
return -ENODEV;
}
+
pci_set_master(pdev);
+
/* Reset the controller with a PCI power-cycle or via doorbell */
rc = hpsa_kdump_hard_reset_controller(pdev);
@@ -7431,13 +7331,12 @@ static void hpsa_enter_performant_mode(struct ctlr_info *h, u32 trans_support)
cp->host_context_flags = IOACCEL1_HCFLAGS_CISS_FORMAT;
cp->timeout_sec = 0;
cp->ReplyQueue = 0;
- cp->Tag.lower = (i << DIRECT_LOOKUP_SHIFT) |
- DIRECT_LOOKUP_BIT;
- cp->Tag.upper = 0;
- cp->host_addr.lower =
- (u32) (h->ioaccel_cmd_pool_dhandle +
+ cp->tag =
+ cpu_to_le64((i << DIRECT_LOOKUP_SHIFT) |
+ DIRECT_LOOKUP_BIT);
+ cp->host_addr =
+ cpu_to_le64(h->ioaccel_cmd_pool_dhandle +
(i * sizeof(struct io_accel1_cmd)));
- cp->host_addr.upper = 0;
}
} else if (trans_support & CFGTBL_Trans_io_accel2) {
u64 cfg_offset, cfg_base_addr_index;
@@ -7711,7 +7610,7 @@ static void __attribute__((unused)) verify_offsets(void)
VERIFY_OFFSET(timeout_sec, 0x62);
VERIFY_OFFSET(ReplyQueue, 0x64);
VERIFY_OFFSET(reserved9, 0x65);
- VERIFY_OFFSET(Tag, 0x68);
+ VERIFY_OFFSET(tag, 0x68);
VERIFY_OFFSET(host_addr, 0x70);
VERIFY_OFFSET(CISS_LUN, 0x78);
VERIFY_OFFSET(SG, 0x78 + 8);
diff --git a/drivers/scsi/hpsa.h b/drivers/scsi/hpsa.h
index 24472ce..8e06d9e 100644
--- a/drivers/scsi/hpsa.h
+++ b/drivers/scsi/hpsa.h
@@ -118,7 +118,7 @@ struct ctlr_info {
struct CfgTable __iomem *cfgtable;
int interrupts_enabled;
int max_commands;
- int commands_outstanding;
+ atomic_t commands_outstanding;
# define PERF_MODE_INT 0
# define DOORBELL_INT 1
# define SIMPLE_MODE_INT 2
@@ -164,7 +164,7 @@ struct ctlr_info {
*/
u32 trans_support;
u32 trans_offset;
- struct TransTable_struct *transtable;
+ struct TransTable_struct __iomem *transtable;
unsigned long transMethod;
/* cap concurrent passthrus at some reasonable maximum */
@@ -181,7 +181,7 @@ struct ctlr_info {
u32 *blockFetchTable;
u32 *ioaccel1_blockFetchTable;
u32 *ioaccel2_blockFetchTable;
- u32 *ioaccel2_bft2_regs;
+ u32 __iomem *ioaccel2_bft2_regs;
unsigned char *hba_inquiry_data;
u32 driver_support;
u32 fw_support;
@@ -192,7 +192,7 @@ struct ctlr_info {
u64 last_heartbeat_timestamp;
u32 heartbeat_sample_interval;
atomic_t firmware_flash_in_progress;
- u32 *lockup_detected;
+ u32 __percpu *lockup_detected;
struct delayed_work monitor_ctlr_work;
int remove_in_progress;
u32 fifo_recently_full;
@@ -395,7 +395,7 @@ static void SA5_performant_intr_mask(struct ctlr_info *h, unsigned long val)
static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
{
struct reply_queue_buffer *rq = &h->reply_queue[q];
- unsigned long flags, register_value = FIFO_EMPTY;
+ unsigned long register_value = FIFO_EMPTY;
/* msi auto clears the interrupt pending bit. */
if (!(h->msi_vector || h->msix_vector)) {
@@ -413,9 +413,7 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
if ((rq->head[rq->current_entry] & 1) == rq->wraparound) {
register_value = rq->head[rq->current_entry];
rq->current_entry++;
- spin_lock_irqsave(&h->lock, flags);
- h->commands_outstanding--;
- spin_unlock_irqrestore(&h->lock, flags);
+ atomic_dec(&h->commands_outstanding);
} else {
register_value = FIFO_EMPTY;
}
@@ -433,11 +431,7 @@ static unsigned long SA5_performant_completed(struct ctlr_info *h, u8 q)
*/
static unsigned long SA5_fifo_full(struct ctlr_info *h)
{
- if (h->commands_outstanding >= h->max_commands)
- return 1;
- else
- return 0;
-
+ return atomic_read(&h->commands_outstanding) >= h->max_commands;
}
/*
* returns value read from hardware.
@@ -448,13 +442,9 @@ static unsigned long SA5_completed(struct ctlr_info *h,
{
unsigned long register_value
= readl(h->vaddr + SA5_REPLY_PORT_OFFSET);
- unsigned long flags;
- if (register_value != FIFO_EMPTY) {
- spin_lock_irqsave(&h->lock, flags);
- h->commands_outstanding--;
- spin_unlock_irqrestore(&h->lock, flags);
- }
+ if (register_value != FIFO_EMPTY)
+ atomic_dec(&h->commands_outstanding);
#ifdef HPSA_DEBUG
if (register_value != FIFO_EMPTY)
@@ -510,7 +500,6 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
{
u64 register_value;
struct reply_queue_buffer *rq = &h->reply_queue[q];
- unsigned long flags;
BUG_ON(q >= h->nreply_queues);
@@ -528,9 +517,7 @@ static unsigned long SA5_ioaccel_mode1_completed(struct ctlr_info *h, u8 q)
wmb();
writel((q << 24) | rq->current_entry, h->vaddr +
IOACCEL_MODE1_CONSUMER_INDEX);
- spin_lock_irqsave(&h->lock, flags);
- h->commands_outstanding--;
- spin_unlock_irqrestore(&h->lock, flags);
+ atomic_dec(&h->commands_outstanding);
}
return (unsigned long) register_value;
}
diff --git a/drivers/scsi/hpsa_cmd.h b/drivers/scsi/hpsa_cmd.h
index b5125dc..cb988c4 100644
--- a/drivers/scsi/hpsa_cmd.h
+++ b/drivers/scsi/hpsa_cmd.h
@@ -252,7 +252,7 @@ struct ReportExtendedLUNdata {
u8 LUNListLength[4];
u8 extended_response_flag;
u8 reserved[3];
- struct ext_report_lun_entry LUN[HPSA_MAX_LUN];
+ struct ext_report_lun_entry LUN[HPSA_MAX_PHYS_LUN];
};
struct SenseSubsystem_info {
@@ -314,28 +314,36 @@ struct CommandListHeader {
u8 ReplyQueue;
u8 SGList;
u16 SGTotal;
- struct vals32 Tag;
+ u64 tag;
union LUNAddr LUN;
};
struct RequestBlock {
u8 CDBLen;
- struct {
- u8 Type:3;
- u8 Attribute:3;
- u8 Direction:2;
- } Type;
+ /*
+ * type_attr_dir:
+ * type: low 3 bits
+ * attr: middle 3 bits
+ * dir: high 2 bits
+ */
+ u8 type_attr_dir;
+#define TYPE_ATTR_DIR(t, a, d) ((((d) & 0x03) << 6) |\
+ (((a) & 0x07) << 3) |\
+ ((t) & 0x07))
+#define GET_TYPE(tad) ((tad) & 0x07)
+#define GET_ATTR(tad) (((tad) >> 3) & 0x07)
+#define GET_DIR(tad) (((tad) >> 6) & 0x03)
u16 Timeout;
u8 CDB[16];
};
struct ErrDescriptor {
- struct vals32 Addr;
+ u64 Addr;
u32 Len;
};
struct SGDescriptor {
- struct vals32 Addr;
+ u64 Addr;
u32 Len;
u32 Ext;
};
@@ -434,8 +442,8 @@ struct io_accel1_cmd {
u16 timeout_sec; /* 0x62 - 0x63 */
u8 ReplyQueue; /* 0x64 */
u8 reserved9[3]; /* 0x65 - 0x67 */
- struct vals32 Tag; /* 0x68 - 0x6F */
- struct vals32 host_addr; /* 0x70 - 0x77 */
+ u64 tag; /* 0x68 - 0x6F */
+ u64 host_addr; /* 0x70 - 0x77 */
u8 CISS_LUN[8]; /* 0x78 - 0x7F */
struct SGDescriptor SG[IOACCEL1_MAXSGENTRIES];
} __aligned(IOACCEL1_COMMANDLIST_ALIGNMENT);
@@ -555,8 +563,8 @@ struct hpsa_tmf_struct {
u8 reserved1; /* byte 3 Reserved */
u32 it_nexus; /* SCSI I-T Nexus */
u8 lun_id[8]; /* LUN ID for TMF request */
- struct vals32 Tag; /* cciss tag associated w/ request */
- struct vals32 abort_tag;/* cciss tag of SCSI cmd or task to abort */
+ u64 tag; /* cciss tag associated w/ request */
+ u64 abort_tag; /* cciss tag of SCSI cmd or task to abort */
u64 error_ptr; /* Error Pointer */
u32 error_len; /* Error Length */
};
diff --git a/drivers/scsi/hptiop.c b/drivers/scsi/hptiop.c
index dedb62c..e995218 100644
--- a/drivers/scsi/hptiop.c
+++ b/drivers/scsi/hptiop.c
@@ -1118,17 +1118,13 @@ static int hptiop_reset(struct scsi_cmnd *scp)
}
static int hptiop_adjust_disk_queue_depth(struct scsi_device *sdev,
- int queue_depth, int reason)
+ int queue_depth)
{
struct hptiop_hba *hba = (struct hptiop_hba *)sdev->host->hostdata;
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (queue_depth > hba->max_requests)
queue_depth = hba->max_requests;
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, queue_depth);
- return queue_depth;
+ return scsi_change_queue_depth(sdev, queue_depth);
}
static ssize_t hptiop_show_version(struct device *dev,
diff --git a/drivers/scsi/ibmvscsi/ibmvfc.c b/drivers/scsi/ibmvscsi/ibmvfc.c
index 598c42c..f58c6d8 100644
--- a/drivers/scsi/ibmvscsi/ibmvfc.c
+++ b/drivers/scsi/ibmvscsi/ibmvfc.c
@@ -1643,19 +1643,9 @@ static int ibmvfc_queuecommand_lck(struct scsi_cmnd *cmnd,
int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun);
memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len);
- if (scsi_populate_tag_msg(cmnd, tag)) {
- vfc_cmd->task_tag = cpu_to_be64(tag[1]);
- switch (tag[0]) {
- case MSG_SIMPLE_TAG:
- vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK;
- break;
- case MSG_HEAD_TAG:
- vfc_cmd->iu.pri_task_attr = IBMVFC_HEAD_OF_QUEUE;
- break;
- case MSG_ORDERED_TAG:
- vfc_cmd->iu.pri_task_attr = IBMVFC_ORDERED_TASK;
- break;
- };
+ if (cmnd->flags & SCMD_TAGGED) {
+ vfc_cmd->task_tag = cpu_to_be64(cmnd->tag);
+ vfc_cmd->iu.pri_task_attr = IBMVFC_SIMPLE_TASK;
}
if (likely(!(rc = ibmvfc_map_sg_data(cmnd, evt, vfc_cmd, vhost->dev))))
@@ -2897,12 +2887,6 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev)
spin_lock_irqsave(shost->host_lock, flags);
if (sdev->type == TYPE_DISK)
sdev->allow_restart = 1;
-
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);
- scsi_activate_tcq(sdev, sdev->queue_depth);
- } else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
spin_unlock_irqrestore(shost->host_lock, flags);
return 0;
}
@@ -2916,40 +2900,12 @@ static int ibmvfc_slave_configure(struct scsi_device *sdev)
* Return value:
* actual depth set
**/
-static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason)
+static int ibmvfc_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (qdepth > IBMVFC_MAX_CMDS_PER_LUN)
qdepth = IBMVFC_MAX_CMDS_PER_LUN;
- scsi_adjust_queue_depth(sdev, 0, qdepth);
- return sdev->queue_depth;
-}
-
-/**
- * ibmvfc_change_queue_type - Change the device's queue type
- * @sdev: scsi device struct
- * @tag_type: type of tags to use
- *
- * Return value:
- * actual queue type set
- **/
-static int ibmvfc_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
-
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
+ return scsi_change_queue_depth(sdev, qdepth);
}
static ssize_t ibmvfc_show_host_partition_name(struct device *dev,
@@ -3133,7 +3089,7 @@ static struct scsi_host_template driver_template = {
.target_alloc = ibmvfc_target_alloc,
.scan_finished = ibmvfc_scan_finished,
.change_queue_depth = ibmvfc_change_queue_depth,
- .change_queue_type = ibmvfc_change_queue_type,
+ .change_queue_type = scsi_change_queue_type,
.cmd_per_lun = 16,
.can_queue = IBMVFC_MAX_REQUESTS_DEFAULT,
.this_id = -1,
@@ -3141,6 +3097,8 @@ static struct scsi_host_template driver_template = {
.max_sectors = IBMVFC_MAX_SECTORS,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = ibmvfc_attrs,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
/**
diff --git a/drivers/scsi/ibmvscsi/ibmvscsi.c b/drivers/scsi/ibmvscsi/ibmvscsi.c
index 7b23f21..acea5d6 100644
--- a/drivers/scsi/ibmvscsi/ibmvscsi.c
+++ b/drivers/scsi/ibmvscsi/ibmvscsi.c
@@ -1929,7 +1929,6 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
blk_queue_rq_timeout(sdev->request_queue, 120 * HZ);
}
spin_unlock_irqrestore(shost->host_lock, lock_flags);
- scsi_adjust_queue_depth(sdev, 0, shost->cmd_per_lun);
return 0;
}
@@ -1942,17 +1941,11 @@ static int ibmvscsi_slave_configure(struct scsi_device *sdev)
* Return value:
* actual depth set
**/
-static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason)
+static int ibmvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (qdepth > IBMVSCSI_MAX_CMDS_PER_LUN)
qdepth = IBMVSCSI_MAX_CMDS_PER_LUN;
-
- scsi_adjust_queue_depth(sdev, 0, qdepth);
- return sdev->queue_depth;
+ return scsi_change_queue_depth(sdev, qdepth);
}
/* ------------------------------------------------------------
diff --git a/drivers/scsi/ipr.c b/drivers/scsi/ipr.c
index 2a9578c..5402943 100644
--- a/drivers/scsi/ipr.c
+++ b/drivers/scsi/ipr.c
@@ -3942,8 +3942,9 @@ static int ipr_update_ioa_ucode(struct ipr_ioa_cfg *ioa_cfg,
return -EIO;
}
- sglist->num_dma_sg = pci_map_sg(ioa_cfg->pdev, sglist->scatterlist,
- sglist->num_sg, DMA_TO_DEVICE);
+ sglist->num_dma_sg = dma_map_sg(&ioa_cfg->pdev->dev,
+ sglist->scatterlist, sglist->num_sg,
+ DMA_TO_DEVICE);
if (!sglist->num_dma_sg) {
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
@@ -4327,16 +4328,12 @@ static int ipr_free_dump(struct ipr_ioa_cfg *ioa_cfg) { return 0; };
* Return value:
* actual depth set
**/
-static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason)
+static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct ipr_ioa_cfg *ioa_cfg = (struct ipr_ioa_cfg *)sdev->host->hostdata;
struct ipr_resource_entry *res;
unsigned long lock_flags = 0;
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res = (struct ipr_resource_entry *)sdev->hostdata;
@@ -4344,7 +4341,7 @@ static int ipr_change_queue_depth(struct scsi_device *sdev, int qdepth,
qdepth = IPR_MAX_CMD_PER_ATA_LUN;
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ scsi_change_queue_depth(sdev, qdepth);
return sdev->queue_depth;
}
@@ -4364,24 +4361,10 @@ static int ipr_change_queue_type(struct scsi_device *sdev, int tag_type)
spin_lock_irqsave(ioa_cfg->host->host_lock, lock_flags);
res = (struct ipr_resource_entry *)sdev->hostdata;
-
- if (res) {
- if (ipr_is_gscsi(res) && sdev->tagged_supported) {
- /*
- * We don't bother quiescing the device here since the
- * adapter firmware does it for us.
- */
- scsi_set_tag_type(sdev, tag_type);
-
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
- } else
+ if (res && ipr_is_gscsi(res))
+ tag_type = scsi_change_queue_type(sdev, tag_type);
+ else
tag_type = 0;
-
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
return tag_type;
}
@@ -4765,10 +4748,10 @@ static int ipr_slave_configure(struct scsi_device *sdev)
spin_unlock_irqrestore(ioa_cfg->host->host_lock, lock_flags);
if (ap) {
- scsi_adjust_queue_depth(sdev, 0, IPR_MAX_CMD_PER_ATA_LUN);
+ scsi_change_queue_depth(sdev, IPR_MAX_CMD_PER_ATA_LUN);
ata_sas_slave_configure(sdev, ap);
- } else
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+ }
+
if (ioa_cfg->sis64)
sdev_printk(KERN_INFO, sdev, "Resource path: %s\n",
ipr_format_res_path(ioa_cfg,
@@ -5585,7 +5568,7 @@ static int ipr_build_ioadl64(struct ipr_ioa_cfg *ioa_cfg,
nseg = scsi_dma_map(scsi_cmd);
if (nseg < 0) {
if (printk_ratelimit())
- dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+ dev_err(&ioa_cfg->pdev->dev, "scsi_dma_map failed!\n");
return -1;
}
@@ -5636,7 +5619,7 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
nseg = scsi_dma_map(scsi_cmd);
if (nseg < 0) {
- dev_err(&ioa_cfg->pdev->dev, "pci_map_sg failed!\n");
+ dev_err(&ioa_cfg->pdev->dev, "scsi_dma_map failed!\n");
return -1;
}
@@ -5673,35 +5656,6 @@ static int ipr_build_ioadl(struct ipr_ioa_cfg *ioa_cfg,
}
/**
- * ipr_get_task_attributes - Translate SPI Q-Tag to task attributes
- * @scsi_cmd: scsi command struct
- *
- * Return value:
- * task attributes
- **/
-static u8 ipr_get_task_attributes(struct scsi_cmnd *scsi_cmd)
-{
- u8 tag[2];
- u8 rc = IPR_FLAGS_LO_UNTAGGED_TASK;
-
- if (scsi_populate_tag_msg(scsi_cmd, tag)) {
- switch (tag[0]) {
- case MSG_SIMPLE_TAG:
- rc = IPR_FLAGS_LO_SIMPLE_TASK;
- break;
- case MSG_HEAD_TAG:
- rc = IPR_FLAGS_LO_HEAD_OF_Q_TASK;
- break;
- case MSG_ORDERED_TAG:
- rc = IPR_FLAGS_LO_ORDERED_TASK;
- break;
- };
- }
-
- return rc;
-}
-
-/**
* ipr_erp_done - Process completion of ERP for a device
* @ipr_cmd: ipr command struct
*
@@ -6236,7 +6190,10 @@ static int ipr_queuecommand(struct Scsi_Host *shost,
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_DELAY_AFTER_RST;
}
ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_ALIGNED_BFR;
- ioarcb->cmd_pkt.flags_lo |= ipr_get_task_attributes(scsi_cmd);
+ if (scsi_cmd->flags & SCMD_TAGGED)
+ ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_SIMPLE_TASK;
+ else
+ ioarcb->cmd_pkt.flags_lo |= IPR_FLAGS_LO_UNTAGGED_TASK;
}
if (scsi_cmd->cmnd[0] >= 0xC0 &&
@@ -6357,6 +6314,7 @@ static struct scsi_host_template driver_template = {
.sdev_attrs = ipr_dev_attrs,
.proc_name = IPR_NAME,
.no_write_same = 1,
+ .use_blk_tags = 1,
};
/**
@@ -8431,7 +8389,7 @@ static int ipr_reset_ucode_download_done(struct ipr_cmnd *ipr_cmd)
struct ipr_ioa_cfg *ioa_cfg = ipr_cmd->ioa_cfg;
struct ipr_sglist *sglist = ioa_cfg->ucode_sglist;
- pci_unmap_sg(ioa_cfg->pdev, sglist->scatterlist,
+ dma_unmap_sg(&ioa_cfg->pdev->dev, sglist->scatterlist,
sglist->num_sg, DMA_TO_DEVICE);
ipr_cmd->job_step = ipr_reset_alert;
@@ -8871,7 +8829,7 @@ static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
if (ioa_cfg->ipr_cmnd_list[i])
- pci_pool_free(ioa_cfg->ipr_cmd_pool,
+ dma_pool_free(ioa_cfg->ipr_cmd_pool,
ioa_cfg->ipr_cmnd_list[i],
ioa_cfg->ipr_cmnd_list_dma[i]);
@@ -8879,7 +8837,7 @@ static void ipr_free_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
}
if (ioa_cfg->ipr_cmd_pool)
- pci_pool_destroy(ioa_cfg->ipr_cmd_pool);
+ dma_pool_destroy(ioa_cfg->ipr_cmd_pool);
kfree(ioa_cfg->ipr_cmnd_list);
kfree(ioa_cfg->ipr_cmnd_list_dma);
@@ -8900,25 +8858,24 @@ static void ipr_free_mem(struct ipr_ioa_cfg *ioa_cfg)
int i;
kfree(ioa_cfg->res_entries);
- pci_free_consistent(ioa_cfg->pdev, sizeof(struct ipr_misc_cbs),
- ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
+ dma_free_coherent(&ioa_cfg->pdev->dev, sizeof(struct ipr_misc_cbs),
+ ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
ipr_free_cmd_blks(ioa_cfg);
for (i = 0; i < ioa_cfg->hrrq_num; i++)
- pci_free_consistent(ioa_cfg->pdev,
- sizeof(u32) * ioa_cfg->hrrq[i].size,
- ioa_cfg->hrrq[i].host_rrq,
- ioa_cfg->hrrq[i].host_rrq_dma);
+ dma_free_coherent(&ioa_cfg->pdev->dev,
+ sizeof(u32) * ioa_cfg->hrrq[i].size,
+ ioa_cfg->hrrq[i].host_rrq,
+ ioa_cfg->hrrq[i].host_rrq_dma);
- pci_free_consistent(ioa_cfg->pdev, ioa_cfg->cfg_table_size,
- ioa_cfg->u.cfg_table,
- ioa_cfg->cfg_table_dma);
+ dma_free_coherent(&ioa_cfg->pdev->dev, ioa_cfg->cfg_table_size,
+ ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma);
for (i = 0; i < IPR_NUM_HCAMS; i++) {
- pci_free_consistent(ioa_cfg->pdev,
- sizeof(struct ipr_hostrcb),
- ioa_cfg->hostrcb[i],
- ioa_cfg->hostrcb_dma[i]);
+ dma_free_coherent(&ioa_cfg->pdev->dev,
+ sizeof(struct ipr_hostrcb),
+ ioa_cfg->hostrcb[i],
+ ioa_cfg->hostrcb_dma[i]);
}
ipr_free_dump(ioa_cfg);
@@ -8979,7 +8936,7 @@ static int ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
dma_addr_t dma_addr;
int i, entries_each_hrrq, hrrq_id = 0;
- ioa_cfg->ipr_cmd_pool = pci_pool_create(IPR_NAME, ioa_cfg->pdev,
+ ioa_cfg->ipr_cmd_pool = dma_pool_create(IPR_NAME, &ioa_cfg->pdev->dev,
sizeof(struct ipr_cmnd), 512, 0);
if (!ioa_cfg->ipr_cmd_pool)
@@ -9029,7 +8986,7 @@ static int ipr_alloc_cmd_blks(struct ipr_ioa_cfg *ioa_cfg)
}
for (i = 0; i < IPR_NUM_CMD_BLKS; i++) {
- ipr_cmd = pci_pool_alloc(ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
+ ipr_cmd = dma_pool_alloc(ioa_cfg->ipr_cmd_pool, GFP_KERNEL, &dma_addr);
if (!ipr_cmd) {
ipr_free_cmd_blks(ioa_cfg);
@@ -9100,9 +9057,10 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
ioa_cfg->res_entries[i].ioa_cfg = ioa_cfg;
}
- ioa_cfg->vpd_cbs = pci_alloc_consistent(ioa_cfg->pdev,
- sizeof(struct ipr_misc_cbs),
- &ioa_cfg->vpd_cbs_dma);
+ ioa_cfg->vpd_cbs = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct ipr_misc_cbs),
+ &ioa_cfg->vpd_cbs_dma,
+ GFP_KERNEL);
if (!ioa_cfg->vpd_cbs)
goto out_free_res_entries;
@@ -9111,13 +9069,14 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
goto out_free_vpd_cbs;
for (i = 0; i < ioa_cfg->hrrq_num; i++) {
- ioa_cfg->hrrq[i].host_rrq = pci_alloc_consistent(ioa_cfg->pdev,
+ ioa_cfg->hrrq[i].host_rrq = dma_alloc_coherent(&pdev->dev,
sizeof(u32) * ioa_cfg->hrrq[i].size,
- &ioa_cfg->hrrq[i].host_rrq_dma);
+ &ioa_cfg->hrrq[i].host_rrq_dma,
+ GFP_KERNEL);
if (!ioa_cfg->hrrq[i].host_rrq) {
while (--i > 0)
- pci_free_consistent(pdev,
+ dma_free_coherent(&pdev->dev,
sizeof(u32) * ioa_cfg->hrrq[i].size,
ioa_cfg->hrrq[i].host_rrq,
ioa_cfg->hrrq[i].host_rrq_dma);
@@ -9126,17 +9085,19 @@ static int ipr_alloc_mem(struct ipr_ioa_cfg *ioa_cfg)
ioa_cfg->hrrq[i].ioa_cfg = ioa_cfg;
}
- ioa_cfg->u.cfg_table = pci_alloc_consistent(ioa_cfg->pdev,
- ioa_cfg->cfg_table_size,
- &ioa_cfg->cfg_table_dma);
+ ioa_cfg->u.cfg_table = dma_alloc_coherent(&pdev->dev,
+ ioa_cfg->cfg_table_size,
+ &ioa_cfg->cfg_table_dma,
+ GFP_KERNEL);
if (!ioa_cfg->u.cfg_table)
goto out_free_host_rrq;
for (i = 0; i < IPR_NUM_HCAMS; i++) {
- ioa_cfg->hostrcb[i] = pci_alloc_consistent(ioa_cfg->pdev,
- sizeof(struct ipr_hostrcb),
- &ioa_cfg->hostrcb_dma[i]);
+ ioa_cfg->hostrcb[i] = dma_alloc_coherent(&pdev->dev,
+ sizeof(struct ipr_hostrcb),
+ &ioa_cfg->hostrcb_dma[i],
+ GFP_KERNEL);
if (!ioa_cfg->hostrcb[i])
goto out_free_hostrcb_dma;
@@ -9160,25 +9121,24 @@ out:
out_free_hostrcb_dma:
while (i-- > 0) {
- pci_free_consistent(pdev, sizeof(struct ipr_hostrcb),
- ioa_cfg->hostrcb[i],
- ioa_cfg->hostrcb_dma[i]);
+ dma_free_coherent(&pdev->dev, sizeof(struct ipr_hostrcb),
+ ioa_cfg->hostrcb[i],
+ ioa_cfg->hostrcb_dma[i]);
}
- pci_free_consistent(pdev, ioa_cfg->cfg_table_size,
- ioa_cfg->u.cfg_table,
- ioa_cfg->cfg_table_dma);
+ dma_free_coherent(&pdev->dev, ioa_cfg->cfg_table_size,
+ ioa_cfg->u.cfg_table, ioa_cfg->cfg_table_dma);
out_free_host_rrq:
for (i = 0; i < ioa_cfg->hrrq_num; i++) {
- pci_free_consistent(pdev,
- sizeof(u32) * ioa_cfg->hrrq[i].size,
- ioa_cfg->hrrq[i].host_rrq,
- ioa_cfg->hrrq[i].host_rrq_dma);
+ dma_free_coherent(&pdev->dev,
+ sizeof(u32) * ioa_cfg->hrrq[i].size,
+ ioa_cfg->hrrq[i].host_rrq,
+ ioa_cfg->hrrq[i].host_rrq_dma);
}
out_ipr_free_cmd_blocks:
ipr_free_cmd_blks(ioa_cfg);
out_free_vpd_cbs:
- pci_free_consistent(pdev, sizeof(struct ipr_misc_cbs),
- ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
+ dma_free_coherent(&pdev->dev, sizeof(struct ipr_misc_cbs),
+ ioa_cfg->vpd_cbs, ioa_cfg->vpd_cbs_dma);
out_free_res_entries:
kfree(ioa_cfg->res_entries);
goto out;
@@ -9618,16 +9578,17 @@ static int ipr_probe_ioa(struct pci_dev *pdev,
ipr_init_regs(ioa_cfg);
if (ioa_cfg->sis64) {
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(64));
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64));
if (rc < 0) {
- dev_dbg(&pdev->dev, "Failed to set 64 bit PCI DMA mask\n");
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ dev_dbg(&pdev->dev, "Failed to set 64 bit DMA mask\n");
+ rc = dma_set_mask_and_coherent(&pdev->dev,
+ DMA_BIT_MASK(32));
}
} else
- rc = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+ rc = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32));
if (rc < 0) {
- dev_err(&pdev->dev, "Failed to set PCI DMA mask\n");
+ dev_err(&pdev->dev, "Failed to set DMA mask\n");
goto cleanup_nomem;
}
diff --git a/drivers/scsi/ipr.h b/drivers/scsi/ipr.h
index d0201ce..9ebdebd 100644
--- a/drivers/scsi/ipr.h
+++ b/drivers/scsi/ipr.h
@@ -1549,7 +1549,7 @@ struct ipr_ioa_cfg {
struct ipr_misc_cbs *vpd_cbs;
dma_addr_t vpd_cbs_dma;
- struct pci_pool *ipr_cmd_pool;
+ struct dma_pool *ipr_cmd_pool;
struct ipr_cmnd *reset_cmd;
int (*reset) (struct ipr_cmnd *);
diff --git a/drivers/scsi/ips.c b/drivers/scsi/ips.c
index e5afc38..e5c2843 100644
--- a/drivers/scsi/ips.c
+++ b/drivers/scsi/ips.c
@@ -1210,7 +1210,7 @@ ips_slave_configure(struct scsi_device * SDptr)
min = ha->max_cmds / 2;
if (ha->enq->ucLogDriveCount <= 2)
min = ha->max_cmds - 1;
- scsi_adjust_queue_depth(SDptr, MSG_ORDERED_TAG, min);
+ scsi_change_queue_depth(SDptr, min);
}
SDptr->skip_ms_page_8 = 1;
diff --git a/drivers/scsi/isci/init.c b/drivers/scsi/isci/init.c
index 2e890b1..724c626 100644
--- a/drivers/scsi/isci/init.c
+++ b/drivers/scsi/isci/init.c
@@ -172,6 +172,8 @@ static struct scsi_host_template isci_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = isci_host_attrs,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static struct sas_domain_function_template isci_transport_ops = {
@@ -258,8 +260,6 @@ static int isci_register_sas_ha(struct isci_host *isci_host)
sas_ha->sas_port = sas_ports;
sas_ha->num_phys = SCI_MAX_PHYS;
- sas_ha->lldd_queue_size = ISCI_CAN_QUEUE_VAL;
- sas_ha->lldd_max_execute_num = 1;
sas_ha->strict_wide_ports = 1;
sas_register_ha(sas_ha);
diff --git a/drivers/scsi/isci/task.c b/drivers/scsi/isci/task.c
index 5d6fda7..3f63c63 100644
--- a/drivers/scsi/isci/task.c
+++ b/drivers/scsi/isci/task.c
@@ -117,104 +117,97 @@ static inline int isci_device_io_ready(struct isci_remote_device *idev,
* functions. This function is called by libsas to send a task down to
* hardware.
* @task: This parameter specifies the SAS task to send.
- * @num: This parameter specifies the number of tasks to queue.
* @gfp_flags: This parameter specifies the context of this call.
*
* status, zero indicates success.
*/
-int isci_task_execute_task(struct sas_task *task, int num, gfp_t gfp_flags)
+int isci_task_execute_task(struct sas_task *task, gfp_t gfp_flags)
{
struct isci_host *ihost = dev_to_ihost(task->dev);
struct isci_remote_device *idev;
unsigned long flags;
+ enum sci_status status = SCI_FAILURE;
bool io_ready;
u16 tag;
- dev_dbg(&ihost->pdev->dev, "%s: num=%d\n", __func__, num);
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ idev = isci_lookup_device(task->dev);
+ io_ready = isci_device_io_ready(idev, task);
+ tag = isci_alloc_tag(ihost);
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
- for_each_sas_task(num, task) {
- enum sci_status status = SCI_FAILURE;
+ dev_dbg(&ihost->pdev->dev,
+ "task: %p, dev: %p idev: %p:%#lx cmd = %p\n",
+ task, task->dev, idev, idev ? idev->flags : 0,
+ task->uldd_task);
- spin_lock_irqsave(&ihost->scic_lock, flags);
- idev = isci_lookup_device(task->dev);
- io_ready = isci_device_io_ready(idev, task);
- tag = isci_alloc_tag(ihost);
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ if (!idev) {
+ isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED,
+ SAS_DEVICE_UNKNOWN);
+ } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) {
+ /* Indicate QUEUE_FULL so that the scsi midlayer
+ * retries.
+ */
+ isci_task_refuse(ihost, task, SAS_TASK_COMPLETE,
+ SAS_QUEUE_FULL);
+ } else {
+ /* There is a device and it's ready for I/O. */
+ spin_lock_irqsave(&task->task_state_lock, flags);
- dev_dbg(&ihost->pdev->dev,
- "task: %p, num: %d dev: %p idev: %p:%#lx cmd = %p\n",
- task, num, task->dev, idev, idev ? idev->flags : 0,
- task->uldd_task);
-
- if (!idev) {
- isci_task_refuse(ihost, task, SAS_TASK_UNDELIVERED,
- SAS_DEVICE_UNKNOWN);
- } else if (!io_ready || tag == SCI_CONTROLLER_INVALID_IO_TAG) {
- /* Indicate QUEUE_FULL so that the scsi midlayer
- * retries.
- */
- isci_task_refuse(ihost, task, SAS_TASK_COMPLETE,
- SAS_QUEUE_FULL);
+ if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
+ /* The I/O was aborted. */
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ isci_task_refuse(ihost, task,
+ SAS_TASK_UNDELIVERED,
+ SAM_STAT_TASK_ABORTED);
} else {
- /* There is a device and it's ready for I/O. */
- spin_lock_irqsave(&task->task_state_lock, flags);
-
- if (task->task_state_flags & SAS_TASK_STATE_ABORTED) {
- /* The I/O was aborted. */
- spin_unlock_irqrestore(&task->task_state_lock,
- flags);
-
- isci_task_refuse(ihost, task,
- SAS_TASK_UNDELIVERED,
- SAM_STAT_TASK_ABORTED);
- } else {
- task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ task->task_state_flags |= SAS_TASK_AT_INITIATOR;
+ spin_unlock_irqrestore(&task->task_state_lock, flags);
+
+ /* build and send the request. */
+ status = isci_request_execute(ihost, idev, task, tag);
+
+ if (status != SCI_SUCCESS) {
+ spin_lock_irqsave(&task->task_state_lock, flags);
+ /* Did not really start this command. */
+ task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
spin_unlock_irqrestore(&task->task_state_lock, flags);
- /* build and send the request. */
- status = isci_request_execute(ihost, idev, task, tag);
-
- if (status != SCI_SUCCESS) {
-
- spin_lock_irqsave(&task->task_state_lock, flags);
- /* Did not really start this command. */
- task->task_state_flags &= ~SAS_TASK_AT_INITIATOR;
- spin_unlock_irqrestore(&task->task_state_lock, flags);
-
- if (test_bit(IDEV_GONE, &idev->flags)) {
-
- /* Indicate that the device
- * is gone.
- */
- isci_task_refuse(ihost, task,
- SAS_TASK_UNDELIVERED,
- SAS_DEVICE_UNKNOWN);
- } else {
- /* Indicate QUEUE_FULL so that
- * the scsi midlayer retries.
- * If the request failed for
- * remote device reasons, it
- * gets returned as
- * SAS_TASK_UNDELIVERED next
- * time through.
- */
- isci_task_refuse(ihost, task,
- SAS_TASK_COMPLETE,
- SAS_QUEUE_FULL);
- }
+ if (test_bit(IDEV_GONE, &idev->flags)) {
+ /* Indicate that the device
+ * is gone.
+ */
+ isci_task_refuse(ihost, task,
+ SAS_TASK_UNDELIVERED,
+ SAS_DEVICE_UNKNOWN);
+ } else {
+ /* Indicate QUEUE_FULL so that
+ * the scsi midlayer retries.
+ * If the request failed for
+ * remote device reasons, it
+ * gets returned as
+ * SAS_TASK_UNDELIVERED next
+ * time through.
+ */
+ isci_task_refuse(ihost, task,
+ SAS_TASK_COMPLETE,
+ SAS_QUEUE_FULL);
}
}
}
- if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) {
- spin_lock_irqsave(&ihost->scic_lock, flags);
- /* command never hit the device, so just free
- * the tci and skip the sequence increment
- */
- isci_tci_free(ihost, ISCI_TAG_TCI(tag));
- spin_unlock_irqrestore(&ihost->scic_lock, flags);
- }
- isci_put_device(idev);
}
+
+ if (status != SCI_SUCCESS && tag != SCI_CONTROLLER_INVALID_IO_TAG) {
+ spin_lock_irqsave(&ihost->scic_lock, flags);
+ /* command never hit the device, so just free
+ * the tci and skip the sequence increment
+ */
+ isci_tci_free(ihost, ISCI_TAG_TCI(tag));
+ spin_unlock_irqrestore(&ihost->scic_lock, flags);
+ }
+
+ isci_put_device(idev);
return 0;
}
diff --git a/drivers/scsi/isci/task.h b/drivers/scsi/isci/task.h
index 9c06cba..8f4531f 100644
--- a/drivers/scsi/isci/task.h
+++ b/drivers/scsi/isci/task.h
@@ -131,7 +131,6 @@ static inline void isci_print_tmf(struct isci_host *ihost, struct isci_tmf *tmf)
int isci_task_execute_task(
struct sas_task *task,
- int num,
gfp_t gfp_flags);
int isci_task_abort_task(
diff --git a/drivers/scsi/iscsi_tcp.c b/drivers/scsi/iscsi_tcp.c
index 427af0f..0b8af18 100644
--- a/drivers/scsi/iscsi_tcp.c
+++ b/drivers/scsi/iscsi_tcp.c
@@ -952,7 +952,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
.module = THIS_MODULE,
.name = "iSCSI Initiator over TCP/IP",
.queuecommand = iscsi_queuecommand,
- .change_queue_depth = iscsi_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.can_queue = ISCSI_DEF_XMIT_CMDS_MAX - 1,
.sg_tablesize = 4096,
.max_sectors = 0xFFFF,
@@ -966,6 +966,7 @@ static struct scsi_host_template iscsi_sw_tcp_sht = {
.target_alloc = iscsi_target_alloc,
.proc_name = "iscsi_tcp",
.this_id = -1,
+ .track_queue_depth = 1,
};
static struct iscsi_transport iscsi_sw_tcp_transport = {
diff --git a/drivers/scsi/libfc/fc_fcp.c b/drivers/scsi/libfc/fc_fcp.c
index 1d7e76e..c679594 100644
--- a/drivers/scsi/libfc/fc_fcp.c
+++ b/drivers/scsi/libfc/fc_fcp.c
@@ -2160,62 +2160,12 @@ int fc_slave_alloc(struct scsi_device *sdev)
if (!rport || fc_remote_port_chkready(rport))
return -ENXIO;
- if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, FC_FCP_DFLT_QUEUE_DEPTH);
- else
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev),
- FC_FCP_DFLT_QUEUE_DEPTH);
-
+ scsi_change_queue_depth(sdev, FC_FCP_DFLT_QUEUE_DEPTH);
return 0;
}
EXPORT_SYMBOL(fc_slave_alloc);
/**
- * fc_change_queue_depth() - Change a device's queue depth
- * @sdev: The SCSI device whose queue depth is to change
- * @qdepth: The new queue depth
- * @reason: The resason for the change
- */
-int fc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
-{
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, qdepth);
- break;
- case SCSI_QDEPTH_RAMP_UP:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- break;
- default:
- return -EOPNOTSUPP;
- }
- return sdev->queue_depth;
-}
-EXPORT_SYMBOL(fc_change_queue_depth);
-
-/**
- * fc_change_queue_type() - Change a device's queue type
- * @sdev: The SCSI device whose queue depth is to change
- * @tag_type: Identifier for queue type
- */
-int fc_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
-}
-EXPORT_SYMBOL(fc_change_queue_type);
-
-/**
* fc_fcp_destory() - Tear down the FCP layer for a given local port
* @lport: The local port that no longer needs the FCP layer
*/
diff --git a/drivers/scsi/libiscsi.c b/drivers/scsi/libiscsi.c
index 0d8bc6c..8053f24 100644
--- a/drivers/scsi/libiscsi.c
+++ b/drivers/scsi/libiscsi.c
@@ -1771,25 +1771,6 @@ fault:
}
EXPORT_SYMBOL_GPL(iscsi_queuecommand);
-int iscsi_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
-{
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, depth);
- break;
- case SCSI_QDEPTH_RAMP_UP:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
- return sdev->queue_depth;
-}
-EXPORT_SYMBOL_GPL(iscsi_change_queue_depth);
-
int iscsi_target_alloc(struct scsi_target *starget)
{
struct iscsi_cls_session *cls_session = starget_to_session(starget);
diff --git a/drivers/scsi/libsas/sas_ata.c b/drivers/scsi/libsas/sas_ata.c
index 766098a..577770f 100644
--- a/drivers/scsi/libsas/sas_ata.c
+++ b/drivers/scsi/libsas/sas_ata.c
@@ -171,7 +171,6 @@ static void sas_ata_task_done(struct sas_task *task)
spin_unlock_irqrestore(ap->lock, flags);
qc_already_gone:
- list_del_init(&task->list);
sas_free_task(task);
}
@@ -244,12 +243,7 @@ static unsigned int sas_ata_qc_issue(struct ata_queued_cmd *qc)
if (qc->scsicmd)
ASSIGN_SAS_TASK(qc->scsicmd, task);
- if (sas_ha->lldd_max_execute_num < 2)
- ret = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
- else
- ret = sas_queue_up(task);
-
- /* Examine */
+ ret = i->dft->lldd_execute_task(task, GFP_ATOMIC);
if (ret) {
SAS_DPRINTK("lldd_execute_task returned: %d\n", ret);
@@ -485,7 +479,6 @@ static void sas_ata_internal_abort(struct sas_task *task)
return;
out:
- list_del_init(&task->list);
sas_free_task(task);
}
diff --git a/drivers/scsi/libsas/sas_expander.c b/drivers/scsi/libsas/sas_expander.c
index 0cac7d8..022bb6e 100644
--- a/drivers/scsi/libsas/sas_expander.c
+++ b/drivers/scsi/libsas/sas_expander.c
@@ -96,7 +96,7 @@ static int smp_execute_task(struct domain_device *dev, void *req, int req_size,
task->slow_task->timer.expires = jiffies + SMP_TIMEOUT*HZ;
add_timer(&task->slow_task->timer);
- res = i->dft->lldd_execute_task(task, 1, GFP_KERNEL);
+ res = i->dft->lldd_execute_task(task, GFP_KERNEL);
if (res) {
del_timer(&task->slow_task->timer);
diff --git a/drivers/scsi/libsas/sas_init.c b/drivers/scsi/libsas/sas_init.c
index dbc8a79..362da44 100644
--- a/drivers/scsi/libsas/sas_init.c
+++ b/drivers/scsi/libsas/sas_init.c
@@ -45,7 +45,6 @@ struct sas_task *sas_alloc_task(gfp_t flags)
struct sas_task *task = kmem_cache_zalloc(sas_task_cache, flags);
if (task) {
- INIT_LIST_HEAD(&task->list);
spin_lock_init(&task->task_state_lock);
task->task_state_flags = SAS_TASK_STATE_PENDING;
}
@@ -77,7 +76,6 @@ EXPORT_SYMBOL_GPL(sas_alloc_slow_task);
void sas_free_task(struct sas_task *task)
{
if (task) {
- BUG_ON(!list_empty(&task->list));
kfree(task->slow_task);
kmem_cache_free(sas_task_cache, task);
}
@@ -127,11 +125,6 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
spin_lock_init(&sas_ha->phy_port_lock);
sas_hash_addr(sas_ha->hashed_sas_addr, sas_ha->sas_addr);
- if (sas_ha->lldd_queue_size == 0)
- sas_ha->lldd_queue_size = 1;
- else if (sas_ha->lldd_queue_size == -1)
- sas_ha->lldd_queue_size = 128; /* Sanity */
-
set_bit(SAS_HA_REGISTERED, &sas_ha->state);
spin_lock_init(&sas_ha->lock);
mutex_init(&sas_ha->drain_mutex);
@@ -157,15 +150,6 @@ int sas_register_ha(struct sas_ha_struct *sas_ha)
goto Undo_ports;
}
- if (sas_ha->lldd_max_execute_num > 1) {
- error = sas_init_queue(sas_ha);
- if (error) {
- printk(KERN_NOTICE "couldn't start queue thread:%d, "
- "running in direct mode\n", error);
- sas_ha->lldd_max_execute_num = 1;
- }
- }
-
INIT_LIST_HEAD(&sas_ha->eh_done_q);
INIT_LIST_HEAD(&sas_ha->eh_ata_q);
@@ -201,11 +185,6 @@ int sas_unregister_ha(struct sas_ha_struct *sas_ha)
__sas_drain_work(sas_ha);
mutex_unlock(&sas_ha->drain_mutex);
- if (sas_ha->lldd_max_execute_num > 1) {
- sas_shutdown_queue(sas_ha);
- sas_ha->lldd_max_execute_num = 1;
- }
-
return 0;
}
diff --git a/drivers/scsi/libsas/sas_internal.h b/drivers/scsi/libsas/sas_internal.h
index 7e7ba83..9cf0bc2 100644
--- a/drivers/scsi/libsas/sas_internal.h
+++ b/drivers/scsi/libsas/sas_internal.h
@@ -66,9 +66,7 @@ void sas_unregister_ports(struct sas_ha_struct *sas_ha);
enum blk_eh_timer_return sas_scsi_timed_out(struct scsi_cmnd *);
-int sas_init_queue(struct sas_ha_struct *sas_ha);
int sas_init_events(struct sas_ha_struct *sas_ha);
-void sas_shutdown_queue(struct sas_ha_struct *sas_ha);
void sas_disable_revalidation(struct sas_ha_struct *ha);
void sas_enable_revalidation(struct sas_ha_struct *ha);
void __sas_drain_work(struct sas_ha_struct *ha);
diff --git a/drivers/scsi/libsas/sas_scsi_host.c b/drivers/scsi/libsas/sas_scsi_host.c
index 24e477d..72918d2 100644
--- a/drivers/scsi/libsas/sas_scsi_host.c
+++ b/drivers/scsi/libsas/sas_scsi_host.c
@@ -112,7 +112,6 @@ static void sas_end_task(struct scsi_cmnd *sc, struct sas_task *task)
sc->result = (hs << 16) | stat;
ASSIGN_SAS_TASK(sc, NULL);
- list_del_init(&task->list);
sas_free_task(task);
}
@@ -138,7 +137,6 @@ static void sas_scsi_task_done(struct sas_task *task)
if (unlikely(!sc)) {
SAS_DPRINTK("task_done called with non existing SCSI cmnd!\n");
- list_del_init(&task->list);
sas_free_task(task);
return;
}
@@ -179,31 +177,10 @@ static struct sas_task *sas_create_task(struct scsi_cmnd *cmd,
return task;
}
-int sas_queue_up(struct sas_task *task)
-{
- struct sas_ha_struct *sas_ha = task->dev->port->ha;
- struct scsi_core *core = &sas_ha->core;
- unsigned long flags;
- LIST_HEAD(list);
-
- spin_lock_irqsave(&core->task_queue_lock, flags);
- if (sas_ha->lldd_queue_size < core->task_queue_size + 1) {
- spin_unlock_irqrestore(&core->task_queue_lock, flags);
- return -SAS_QUEUE_FULL;
- }
- list_add_tail(&task->list, &core->task_queue);
- core->task_queue_size += 1;
- spin_unlock_irqrestore(&core->task_queue_lock, flags);
- wake_up_process(core->queue_thread);
-
- return 0;
-}
-
int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
{
struct sas_internal *i = to_sas_internal(host->transportt);
struct domain_device *dev = cmd_to_domain_dev(cmd);
- struct sas_ha_struct *sas_ha = dev->port->ha;
struct sas_task *task;
int res = 0;
@@ -224,12 +201,7 @@ int sas_queuecommand(struct Scsi_Host *host, struct scsi_cmnd *cmd)
if (!task)
return SCSI_MLQUEUE_HOST_BUSY;
- /* Queue up, Direct Mode or Task Collector Mode. */
- if (sas_ha->lldd_max_execute_num < 2)
- res = i->dft->lldd_execute_task(task, 1, GFP_ATOMIC);
- else
- res = sas_queue_up(task);
-
+ res = i->dft->lldd_execute_task(task, GFP_ATOMIC);
if (res)
goto out_free_task;
return 0;
@@ -323,37 +295,17 @@ enum task_disposition {
TASK_IS_DONE,
TASK_IS_ABORTED,
TASK_IS_AT_LU,
- TASK_IS_NOT_AT_HA,
TASK_IS_NOT_AT_LU,
TASK_ABORT_FAILED,
};
static enum task_disposition sas_scsi_find_task(struct sas_task *task)
{
- struct sas_ha_struct *ha = task->dev->port->ha;
unsigned long flags;
int i, res;
struct sas_internal *si =
to_sas_internal(task->dev->port->ha->core.shost->transportt);
- if (ha->lldd_max_execute_num > 1) {
- struct scsi_core *core = &ha->core;
- struct sas_task *t, *n;
-
- mutex_lock(&core->task_queue_flush);
- spin_lock_irqsave(&core->task_queue_lock, flags);
- list_for_each_entry_safe(t, n, &core->task_queue, list)
- if (task == t) {
- list_del_init(&t->list);
- break;
- }
- spin_unlock_irqrestore(&core->task_queue_lock, flags);
- mutex_unlock(&core->task_queue_flush);
-
- if (task == t)
- return TASK_IS_NOT_AT_HA;
- }
-
for (i = 0; i < 5; i++) {
SAS_DPRINTK("%s: aborting task 0x%p\n", __func__, task);
res = si->dft->lldd_abort_task(task);
@@ -667,14 +619,6 @@ static void sas_eh_handle_sas_errors(struct Scsi_Host *shost, struct list_head *
cmd->eh_eflags = 0;
switch (res) {
- case TASK_IS_NOT_AT_HA:
- SAS_DPRINTK("%s: task 0x%p is not at ha: %s\n",
- __func__, task,
- cmd->retries ? "retry" : "aborted");
- if (cmd->retries)
- cmd->retries--;
- sas_eh_finish_cmd(cmd);
- continue;
case TASK_IS_DONE:
SAS_DPRINTK("%s: task 0x%p is done\n", __func__,
task);
@@ -836,9 +780,6 @@ retry:
scsi_eh_ready_devs(shost, &eh_work_q, &ha->eh_done_q);
out:
- if (ha->lldd_max_execute_num > 1)
- wake_up_process(ha->core.queue_thread);
-
sas_eh_handle_resets(shost);
/* now link into libata eh --- if we have any ata devices */
@@ -940,15 +881,12 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
sas_read_port_mode_page(scsi_dev);
if (scsi_dev->tagged_supported) {
- scsi_set_tag_type(scsi_dev, MSG_SIMPLE_TAG);
- scsi_activate_tcq(scsi_dev, SAS_DEF_QD);
+ scsi_change_queue_depth(scsi_dev, SAS_DEF_QD);
} else {
SAS_DPRINTK("device %llx, LUN %llx doesn't support "
"TCQ\n", SAS_ADDR(dev->sas_addr),
scsi_dev->lun);
- scsi_dev->tagged_supported = 0;
- scsi_set_tag_type(scsi_dev, 0);
- scsi_deactivate_tcq(scsi_dev, 1);
+ scsi_change_queue_depth(scsi_dev, 1);
}
scsi_dev->allow_restart = 1;
@@ -956,47 +894,23 @@ int sas_slave_configure(struct scsi_device *scsi_dev)
return 0;
}
-int sas_change_queue_depth(struct scsi_device *sdev, int depth, int reason)
+int sas_change_queue_depth(struct scsi_device *sdev, int depth)
{
struct domain_device *dev = sdev_to_domain_dev(sdev);
if (dev_is_sata(dev))
- return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth,
- reason);
-
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- case SCSI_QDEPTH_RAMP_UP:
- if (!sdev->tagged_supported)
- depth = 1;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
+ return __ata_change_queue_depth(dev->sata_dev.ap, sdev, depth);
- return depth;
+ if (!sdev->tagged_supported)
+ depth = 1;
+ return scsi_change_queue_depth(sdev, depth);
}
-int sas_change_queue_type(struct scsi_device *scsi_dev, int qt)
+int sas_change_queue_type(struct scsi_device *scsi_dev, int type)
{
- struct domain_device *dev = sdev_to_domain_dev(scsi_dev);
-
- if (dev_is_sata(dev))
+ if (dev_is_sata(sdev_to_domain_dev(scsi_dev)))
return -EINVAL;
-
- if (!scsi_dev->tagged_supported)
- return 0;
-
- scsi_deactivate_tcq(scsi_dev, 1);
-
- scsi_set_tag_type(scsi_dev, qt);
- scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
-
- return qt;
+ return scsi_change_queue_type(scsi_dev, type);
}
int sas_bios_param(struct scsi_device *scsi_dev,
@@ -1011,121 +925,6 @@ int sas_bios_param(struct scsi_device *scsi_dev,
return 0;
}
-/* ---------- Task Collector Thread implementation ---------- */
-
-static void sas_queue(struct sas_ha_struct *sas_ha)
-{
- struct scsi_core *core = &sas_ha->core;
- unsigned long flags;
- LIST_HEAD(q);
- int can_queue;
- int res;
- struct sas_internal *i = to_sas_internal(core->shost->transportt);
-
- mutex_lock(&core->task_queue_flush);
- spin_lock_irqsave(&core->task_queue_lock, flags);
- while (!kthread_should_stop() &&
- !list_empty(&core->task_queue) &&
- !test_bit(SAS_HA_FROZEN, &sas_ha->state)) {
-
- can_queue = sas_ha->lldd_queue_size - core->task_queue_size;
- if (can_queue >= 0) {
- can_queue = core->task_queue_size;
- list_splice_init(&core->task_queue, &q);
- } else {
- struct list_head *a, *n;
-
- can_queue = sas_ha->lldd_queue_size;
- list_for_each_safe(a, n, &core->task_queue) {
- list_move_tail(a, &q);
- if (--can_queue == 0)
- break;
- }
- can_queue = sas_ha->lldd_queue_size;
- }
- core->task_queue_size -= can_queue;
- spin_unlock_irqrestore(&core->task_queue_lock, flags);
- {
- struct sas_task *task = list_entry(q.next,
- struct sas_task,
- list);
- list_del_init(&q);
- res = i->dft->lldd_execute_task(task, can_queue,
- GFP_KERNEL);
- if (unlikely(res))
- __list_add(&q, task->list.prev, &task->list);
- }
- spin_lock_irqsave(&core->task_queue_lock, flags);
- if (res) {
- list_splice_init(&q, &core->task_queue); /*at head*/
- core->task_queue_size += can_queue;
- }
- }
- spin_unlock_irqrestore(&core->task_queue_lock, flags);
- mutex_unlock(&core->task_queue_flush);
-}
-
-/**
- * sas_queue_thread -- The Task Collector thread
- * @_sas_ha: pointer to struct sas_ha
- */
-static int sas_queue_thread(void *_sas_ha)
-{
- struct sas_ha_struct *sas_ha = _sas_ha;
-
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- sas_queue(sas_ha);
- if (kthread_should_stop())
- break;
- }
-
- return 0;
-}
-
-int sas_init_queue(struct sas_ha_struct *sas_ha)
-{
- struct scsi_core *core = &sas_ha->core;
-
- spin_lock_init(&core->task_queue_lock);
- mutex_init(&core->task_queue_flush);
- core->task_queue_size = 0;
- INIT_LIST_HEAD(&core->task_queue);
-
- core->queue_thread = kthread_run(sas_queue_thread, sas_ha,
- "sas_queue_%d", core->shost->host_no);
- if (IS_ERR(core->queue_thread))
- return PTR_ERR(core->queue_thread);
- return 0;
-}
-
-void sas_shutdown_queue(struct sas_ha_struct *sas_ha)
-{
- unsigned long flags;
- struct scsi_core *core = &sas_ha->core;
- struct sas_task *task, *n;
-
- kthread_stop(core->queue_thread);
-
- if (!list_empty(&core->task_queue))
- SAS_DPRINTK("HA: %llx: scsi core task queue is NOT empty!?\n",
- SAS_ADDR(sas_ha->sas_addr));
-
- spin_lock_irqsave(&core->task_queue_lock, flags);
- list_for_each_entry_safe(task, n, &core->task_queue, list) {
- struct scsi_cmnd *cmd = task->uldd_task;
-
- list_del_init(&task->list);
-
- ASSIGN_SAS_TASK(cmd, NULL);
- sas_free_task(task);
- cmd->result = DID_ABORT << 16;
- cmd->scsi_done(cmd);
- }
- spin_unlock_irqrestore(&core->task_queue_lock, flags);
-}
-
/*
* Tell an upper layer that it needs to initiate an abort for a given task.
* This should only ever be called by an LLDD.
diff --git a/drivers/scsi/lpfc/lpfc_debugfs.c b/drivers/scsi/lpfc/lpfc_debugfs.c
index 786a2af..5633e7da 100644
--- a/drivers/scsi/lpfc/lpfc_debugfs.c
+++ b/drivers/scsi/lpfc/lpfc_debugfs.c
@@ -968,8 +968,8 @@ lpfc_debugfs_dumpDif_open(struct inode *inode, struct file *file)
goto out;
/* Round to page boundary */
- printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%s\n",
- __func__, _dump_buf_dif, file->f_dentry->d_name.name);
+ printk(KERN_ERR "9060 BLKGRD: %s: _dump_buf_dif=0x%p file=%pD\n",
+ __func__, _dump_buf_dif, file);
debug->buffer = _dump_buf_dif;
if (!debug->buffer) {
kfree(debug);
@@ -1011,7 +1011,7 @@ static ssize_t
lpfc_debugfs_dif_err_read(struct file *file, char __user *buf,
size_t nbytes, loff_t *ppos)
{
- struct dentry *dent = file->f_dentry;
+ struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
char cbuf[32];
uint64_t tmp = 0;
@@ -1052,7 +1052,7 @@ static ssize_t
lpfc_debugfs_dif_err_write(struct file *file, const char __user *buf,
size_t nbytes, loff_t *ppos)
{
- struct dentry *dent = file->f_dentry;
+ struct dentry *dent = file->f_path.dentry;
struct lpfc_hba *phba = file->private_data;
char dstbuf[32];
uint64_t tmp = 0;
diff --git a/drivers/scsi/lpfc/lpfc_scsi.c b/drivers/scsi/lpfc/lpfc_scsi.c
index b99399f..fd85952 100644
--- a/drivers/scsi/lpfc/lpfc_scsi.c
+++ b/drivers/scsi/lpfc/lpfc_scsi.c
@@ -243,128 +243,6 @@ lpfc_update_stats(struct lpfc_hba *phba, struct lpfc_scsi_buf *lpfc_cmd)
}
/**
- * lpfc_send_sdev_queuedepth_change_event - Posts a queuedepth change event
- * @phba: Pointer to HBA context object.
- * @vport: Pointer to vport object.
- * @ndlp: Pointer to FC node associated with the target.
- * @lun: Lun number of the scsi device.
- * @old_val: Old value of the queue depth.
- * @new_val: New value of the queue depth.
- *
- * This function sends an event to the mgmt application indicating
- * there is a change in the scsi device queue depth.
- **/
-static void
-lpfc_send_sdev_queuedepth_change_event(struct lpfc_hba *phba,
- struct lpfc_vport *vport,
- struct lpfc_nodelist *ndlp,
- uint64_t lun,
- uint32_t old_val,
- uint32_t new_val)
-{
- struct lpfc_fast_path_event *fast_path_evt;
- unsigned long flags;
-
- fast_path_evt = lpfc_alloc_fast_evt(phba);
- if (!fast_path_evt)
- return;
-
- fast_path_evt->un.queue_depth_evt.scsi_event.event_type =
- FC_REG_SCSI_EVENT;
- fast_path_evt->un.queue_depth_evt.scsi_event.subcategory =
- LPFC_EVENT_VARQUEDEPTH;
-
- /* Report all luns with change in queue depth */
- fast_path_evt->un.queue_depth_evt.scsi_event.lun = lun;
- if (ndlp && NLP_CHK_NODE_ACT(ndlp)) {
- memcpy(&fast_path_evt->un.queue_depth_evt.scsi_event.wwpn,
- &ndlp->nlp_portname, sizeof(struct lpfc_name));
- memcpy(&fast_path_evt->un.queue_depth_evt.scsi_event.wwnn,
- &ndlp->nlp_nodename, sizeof(struct lpfc_name));
- }
-
- fast_path_evt->un.queue_depth_evt.oldval = old_val;
- fast_path_evt->un.queue_depth_evt.newval = new_val;
- fast_path_evt->vport = vport;
-
- fast_path_evt->work_evt.evt = LPFC_EVT_FASTPATH_MGMT_EVT;
- spin_lock_irqsave(&phba->hbalock, flags);
- list_add_tail(&fast_path_evt->work_evt.evt_listp, &phba->work_list);
- spin_unlock_irqrestore(&phba->hbalock, flags);
- lpfc_worker_wake_up(phba);
-
- return;
-}
-
-/**
- * lpfc_change_queue_depth - Alter scsi device queue depth
- * @sdev: Pointer the scsi device on which to change the queue depth.
- * @qdepth: New queue depth to set the sdev to.
- * @reason: The reason for the queue depth change.
- *
- * This function is called by the midlayer and the LLD to alter the queue
- * depth for a scsi device. This function sets the queue depth to the new
- * value and sends an event out to log the queue depth change.
- **/
-static int
-lpfc_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
-{
- struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
- struct lpfc_hba *phba = vport->phba;
- struct lpfc_rport_data *rdata;
- unsigned long new_queue_depth, old_queue_depth;
-
- old_queue_depth = sdev->queue_depth;
-
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- /* change request from sysfs, fall through */
- case SCSI_QDEPTH_RAMP_UP:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- break;
- case SCSI_QDEPTH_QFULL:
- if (scsi_track_queue_full(sdev, qdepth) == 0)
- return sdev->queue_depth;
-
- lpfc_printf_vlog(vport, KERN_WARNING, LOG_FCP,
- "0711 detected queue full - lun queue "
- "depth adjusted to %d.\n", sdev->queue_depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- new_queue_depth = sdev->queue_depth;
- rdata = lpfc_rport_data_from_scsi_device(sdev);
- if (rdata)
- lpfc_send_sdev_queuedepth_change_event(phba, vport,
- rdata->pnode, sdev->lun,
- old_queue_depth,
- new_queue_depth);
- return sdev->queue_depth;
-}
-
-/**
- * lpfc_change_queue_type() - Change a device's scsi tag queuing type
- * @sdev: Pointer the scsi device whose queue depth is to change
- * @tag_type: Identifier for queue tag type
- */
-static int
-lpfc_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
-}
-
-/**
* lpfc_rampdown_queue_depth - Post RAMP_DOWN_QUEUE event to worker thread
* @phba: The Hba for which this call is being executed.
*
@@ -449,8 +327,7 @@ lpfc_ramp_down_queue_handler(struct lpfc_hba *phba)
else
new_queue_depth = sdev->queue_depth -
new_queue_depth;
- lpfc_change_queue_depth(sdev, new_queue_depth,
- SCSI_QDEPTH_DEFAULT);
+ scsi_change_queue_depth(sdev, new_queue_depth);
}
}
lpfc_destroy_vport_work_array(phba, vports);
@@ -4286,7 +4163,6 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
IOCB_t *iocb_cmd = &lpfc_cmd->cur_iocbq.iocb;
struct lpfc_iocbq *piocbq = &(lpfc_cmd->cur_iocbq);
int datadir = scsi_cmnd->sc_data_direction;
- char tag[2];
uint8_t *ptr;
bool sli4;
uint32_t fcpdl;
@@ -4308,20 +4184,7 @@ lpfc_scsi_prep_cmnd(struct lpfc_vport *vport, struct lpfc_scsi_buf *lpfc_cmd,
memset(ptr, 0, (LPFC_FCP_CDB_LEN - scsi_cmnd->cmd_len));
}
- if (scsi_populate_tag_msg(scsi_cmnd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- fcp_cmnd->fcpCntl1 = HEAD_OF_Q;
- break;
- case ORDERED_QUEUE_TAG:
- fcp_cmnd->fcpCntl1 = ORDERED_Q;
- break;
- default:
- fcp_cmnd->fcpCntl1 = SIMPLE_Q;
- break;
- }
- } else
- fcp_cmnd->fcpCntl1 = SIMPLE_Q;
+ fcp_cmnd->fcpCntl1 = SIMPLE_Q;
sli4 = (phba->sli_rev == LPFC_SLI_REV4);
piocbq->iocb.un.fcpi.fcpi_XRdy = 0;
@@ -5632,10 +5495,7 @@ lpfc_slave_configure(struct scsi_device *sdev)
struct lpfc_vport *vport = (struct lpfc_vport *) sdev->host->hostdata;
struct lpfc_hba *phba = vport->phba;
- if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, vport->cfg_lun_queue_depth);
- else
- scsi_deactivate_tcq(sdev, vport->cfg_lun_queue_depth);
+ scsi_change_queue_depth(sdev, vport->cfg_lun_queue_depth);
if (phba->cfg_poll & ENABLE_FCP_RING_POLLING) {
lpfc_sli_handle_fast_ring_event(phba,
@@ -6018,8 +5878,10 @@ struct scsi_host_template lpfc_template = {
.shost_attrs = lpfc_hba_attrs,
.max_sectors = 0xFFFF,
.vendor_id = LPFC_NL_VENDOR_ID,
- .change_queue_depth = lpfc_change_queue_depth,
- .change_queue_type = lpfc_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
struct scsi_host_template lpfc_vport_template = {
@@ -6041,6 +5903,8 @@ struct scsi_host_template lpfc_vport_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = lpfc_vport_attrs,
.max_sectors = 0xFFFF,
- .change_queue_depth = lpfc_change_queue_depth,
- .change_queue_type = lpfc_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
diff --git a/drivers/scsi/mac_scsi.c b/drivers/scsi/mac_scsi.c
index 6a039eb..953fd9b 100644
--- a/drivers/scsi/mac_scsi.c
+++ b/drivers/scsi/mac_scsi.c
@@ -9,69 +9,62 @@
* Generic Generic NCR5380 driver
*
* Copyright 1995, Russell King
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/ctype.h>
#include <linux/delay.h>
-
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkdev.h>
#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <asm/hwtest.h>
#include <asm/io.h>
-#include <asm/irq.h>
-
-#include <asm/macintosh.h>
#include <asm/macints.h>
-#include <asm/mac_via.h>
+#include <asm/setup.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
-#include "mac_scsi.h"
-/* These control the behaviour of the generic 5380 core */
-#define AUTOSENSE
+/* Definitions for the core NCR5380 driver. */
+
#define PSEUDO_DMA
-#include "NCR5380.h"
+#define NCR5380_implementation_fields unsigned char *pdma_base
+#define NCR5380_local_declare() struct Scsi_Host *_instance
+#define NCR5380_setup(instance) _instance = instance
-#define RESET_BOOT
-#define DRIVER_SETUP
+#define NCR5380_read(reg) macscsi_read(_instance, reg)
+#define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
-extern void via_scsi_clear(void);
+#define NCR5380_pread macscsi_pread
+#define NCR5380_pwrite macscsi_pwrite
-#ifdef RESET_BOOT
-static void mac_scsi_reset_boot(struct Scsi_Host *instance);
-#endif
+#define NCR5380_intr macscsi_intr
+#define NCR5380_queue_command macscsi_queue_command
+#define NCR5380_abort macscsi_abort
+#define NCR5380_bus_reset macscsi_bus_reset
+#define NCR5380_info macscsi_info
+#define NCR5380_show_info macscsi_show_info
+#define NCR5380_write_info macscsi_write_info
+
+#include "NCR5380.h"
+
+#define RESET_BOOT
-static int setup_called = 0;
static int setup_can_queue = -1;
+module_param(setup_can_queue, int, 0);
static int setup_cmd_per_lun = -1;
+module_param(setup_cmd_per_lun, int, 0);
static int setup_sg_tablesize = -1;
+module_param(setup_sg_tablesize, int, 0);
static int setup_use_pdma = -1;
-#ifdef SUPPORT_TAGS
+module_param(setup_use_pdma, int, 0);
static int setup_use_tagged_queuing = -1;
-#endif
+module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
+module_param(setup_hostid, int, 0);
/* Time (in jiffies) to wait after a reset; the SCSI standard calls for 250ms,
* we usually do 0.5s to be on the safe side. But Toshiba CD-ROMs once more
@@ -84,232 +77,48 @@ static int setup_hostid = -1;
#define AFTER_RESET_DELAY (HZ/2)
#endif
-static volatile unsigned char *mac_scsi_regp = NULL;
-static volatile unsigned char *mac_scsi_drq = NULL;
-static volatile unsigned char *mac_scsi_nodrq = NULL;
-
-
/*
* NCR 5380 register access functions
*/
-#if 0
-/* Debug versions */
-#define CTRL(p,v) (*ctrl = (v))
-
-static char macscsi_read(struct Scsi_Host *instance, int reg)
+static inline char macscsi_read(struct Scsi_Host *instance, int reg)
{
- int iobase = instance->io_port;
- int i;
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-
- CTRL(iobase, 0);
- i = in_8(iobase + (reg<<4));
- CTRL(iobase, 0x40);
-
- return i;
+ return in_8(instance->base + (reg << 4));
}
-static void macscsi_write(struct Scsi_Host *instance, int reg, int value)
-{
- int iobase = instance->io_port;
- int *ctrl = &((struct NCR5380_hostdata *)instance->hostdata)->ctrl;
-
- CTRL(iobase, 0);
- out_8(iobase + (reg<<4), value);
- CTRL(iobase, 0x40);
-}
-#else
-
-/* Fast versions */
-static __inline__ char macscsi_read(struct Scsi_Host *instance, int reg)
+static inline void macscsi_write(struct Scsi_Host *instance, int reg, int value)
{
- return in_8(instance->io_port + (reg<<4));
+ out_8(instance->base + (reg << 4), value);
}
-static __inline__ void macscsi_write(struct Scsi_Host *instance, int reg, int value)
+#ifndef MODULE
+static int __init mac_scsi_setup(char *str)
{
- out_8(instance->io_port + (reg<<4), value);
-}
-#endif
-
+ int ints[7];
-/*
- * Function : mac_scsi_setup(char *str)
- *
- * Purpose : booter command line initialization of the overrides array,
- *
- * Inputs : str - comma delimited list of options
- *
- */
+ (void)get_options(str, ARRAY_SIZE(ints), ints);
-static int __init mac_scsi_setup(char *str) {
-#ifdef DRIVER_SETUP
- int ints[7];
-
- (void)get_options( str, ARRAY_SIZE(ints), ints);
-
- if (setup_called++ || ints[0] < 1 || ints[0] > 6) {
- printk(KERN_WARNING "scsi: <mac5380>"
- " Usage: mac5380=<can_queue>[,<cmd_per_lun>,<sg_tablesize>,<hostid>,<use_tags>,<use_pdma>]\n");
- printk(KERN_ALERT "scsi: <mac5380> Bad Penguin parameters?\n");
- return 0;
- }
-
- if (ints[0] >= 1) {
- if (ints[1] > 0)
- /* no limits on this, just > 0 */
- setup_can_queue = ints[1];
- }
- if (ints[0] >= 2) {
- if (ints[2] > 0)
- setup_cmd_per_lun = ints[2];
- }
- if (ints[0] >= 3) {
- if (ints[3] >= 0) {
- setup_sg_tablesize = ints[3];
- /* Must be <= SG_ALL (255) */
- if (setup_sg_tablesize > SG_ALL)
- setup_sg_tablesize = SG_ALL;
- }
- }
- if (ints[0] >= 4) {
- /* Must be between 0 and 7 */
- if (ints[4] >= 0 && ints[4] <= 7)
- setup_hostid = ints[4];
- else if (ints[4] > 7)
- printk(KERN_WARNING "mac_scsi_setup: invalid host ID %d !\n", ints[4] );
- }
-#ifdef SUPPORT_TAGS
- if (ints[0] >= 5) {
- if (ints[5] >= 0)
- setup_use_tagged_queuing = !!ints[5];
+ if (ints[0] < 1 || ints[0] > 6) {
+ pr_err("Usage: mac5380=<can_queue>[,<cmd_per_lun>[,<sg_tablesize>[,<hostid>[,<use_tags>[,<use_pdma>]]]]]\n");
+ return 0;
}
-
- if (ints[0] == 6) {
- if (ints[6] >= 0)
+ if (ints[0] >= 1)
+ setup_can_queue = ints[1];
+ if (ints[0] >= 2)
+ setup_cmd_per_lun = ints[2];
+ if (ints[0] >= 3)
+ setup_sg_tablesize = ints[3];
+ if (ints[0] >= 4)
+ setup_hostid = ints[4];
+ if (ints[0] >= 5)
+ setup_use_tagged_queuing = ints[5];
+ if (ints[0] >= 6)
setup_use_pdma = ints[6];
- }
-#else
- if (ints[0] == 5) {
- if (ints[5] >= 0)
- setup_use_pdma = ints[5];
- }
-#endif /* SUPPORT_TAGS */
-
-#endif /* DRIVER_SETUP */
return 1;
}
__setup("mac5380=", mac_scsi_setup);
-
-/*
- * Function : int macscsi_detect(struct scsi_host_template * tpnt)
- *
- * Purpose : initializes mac NCR5380 driver based on the
- * command line / compile time port and irq definitions.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
- */
-
-int __init macscsi_detect(struct scsi_host_template * tpnt)
-{
- static int called = 0;
- int flags = 0;
- struct Scsi_Host *instance;
-
- if (!MACH_IS_MAC || called)
- return( 0 );
-
- if (macintosh_config->scsi_type != MAC_SCSI_OLD)
- return( 0 );
-
- /* setup variables */
- tpnt->can_queue =
- (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
- tpnt->cmd_per_lun =
- (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
- tpnt->sg_tablesize =
- (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
-
- if (setup_hostid >= 0)
- tpnt->this_id = setup_hostid;
- else {
- /* use 7 as default */
- tpnt->this_id = 7;
- }
-
-#ifdef SUPPORT_TAGS
- if (setup_use_tagged_queuing < 0)
- setup_use_tagged_queuing = USE_TAGGED_QUEUING;
-#endif
-
- /* Once we support multiple 5380s (e.g. DuoDock) we'll do
- something different here */
- instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
- if (instance == NULL)
- return 0;
-
- if (macintosh_config->ident == MAC_MODEL_IIFX) {
- mac_scsi_regp = via1+0x8000;
- mac_scsi_drq = via1+0xE000;
- mac_scsi_nodrq = via1+0xC000;
- /* The IIFX should be able to do true DMA, but pseudo-dma doesn't work */
- flags = FLAG_NO_PSEUDO_DMA;
- } else {
- mac_scsi_regp = via1+0x10000;
- mac_scsi_drq = via1+0x6000;
- mac_scsi_nodrq = via1+0x12000;
- }
-
- if (! setup_use_pdma)
- flags = FLAG_NO_PSEUDO_DMA;
-
- instance->io_port = (unsigned long) mac_scsi_regp;
- instance->irq = IRQ_MAC_SCSI;
-
-#ifdef RESET_BOOT
- mac_scsi_reset_boot(instance);
-#endif
-
- NCR5380_init(instance, flags);
-
- instance->n_io_port = 255;
-
- ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
-
- if (instance->irq != SCSI_IRQ_NONE)
- if (request_irq(instance->irq, NCR5380_intr, 0, "ncr5380", instance)) {
- printk(KERN_WARNING "scsi%d: IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
- }
-
- printk(KERN_INFO "scsi%d: generic 5380 at port %lX irq", instance->host_no, instance->io_port);
- if (instance->irq == SCSI_IRQ_NONE)
- printk (KERN_INFO "s disabled");
- else
- printk (KERN_INFO " %d", instance->irq);
- printk(KERN_INFO " options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- instance->can_queue, instance->cmd_per_lun, MACSCSI_PUBLIC_RELEASE);
- printk(KERN_INFO "\nscsi%d:", instance->host_no);
- NCR5380_print_options(instance);
- printk("\n");
- called = 1;
- return 1;
-}
-
-int macscsi_release (struct Scsi_Host *shpnt)
-{
- if (shpnt->irq != SCSI_IRQ_NONE)
- free_irq(shpnt->irq, shpnt);
- NCR5380_exit(shpnt);
-
- return 0;
-}
+#endif /* !MODULE */
#ifdef RESET_BOOT
/*
@@ -349,10 +158,7 @@ static void mac_scsi_reset_boot(struct Scsi_Host *instance)
}
#endif
-const char * macscsi_info (struct Scsi_Host *spnt) {
- return "";
-}
-
+#ifdef PSEUDO_DMA
/*
Pseudo-DMA: (Ove Edlund)
The code attempts to catch bus errors that occur if one for example
@@ -422,38 +228,39 @@ __asm__ __volatile__ \
: "0"(s), "1"(d), "2"(len) \
: "d0")
-
-static int macscsi_pread (struct Scsi_Host *instance,
- unsigned char *dst, int len)
+static int macscsi_pread(struct Scsi_Host *instance,
+ unsigned char *dst, int len)
{
- unsigned char *d;
- volatile unsigned char *s;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- s = mac_scsi_drq+0x60;
- d = dst;
-
-/* These conditions are derived from MacOS */
-
- while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)
- && !(NCR5380_read(STATUS_REG) & SR_REQ))
- ;
- if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)
- && (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
- printk(KERN_ERR "Error in macscsi_pread\n");
- return -1;
- }
-
- CP_IO_TO_MEM(s, d, len);
-
- if (len != 0) {
- printk(KERN_NOTICE "Bus error in macscsi_pread\n");
- return -1;
- }
-
- return 0;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned char *d;
+ unsigned char *s;
+
+ NCR5380_local_declare();
+ NCR5380_setup(instance);
+
+ s = hostdata->pdma_base + (INPUT_DATA_REG << 4);
+ d = dst;
+
+ /* These conditions are derived from MacOS */
+
+ while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) &&
+ !(NCR5380_read(STATUS_REG) & SR_REQ))
+ ;
+
+ if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) &&
+ (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)) {
+ pr_err("Error in macscsi_pread\n");
+ return -1;
+ }
+
+ CP_IO_TO_MEM(s, d, len);
+
+ if (len != 0) {
+ pr_notice("Bus error in macscsi_pread\n");
+ return -1;
+ }
+
+ return 0;
}
@@ -515,59 +322,172 @@ __asm__ __volatile__ \
: "0"(s), "1"(d), "2"(len) \
: "d0")
-static int macscsi_pwrite (struct Scsi_Host *instance,
- unsigned char *src, int len)
+static int macscsi_pwrite(struct Scsi_Host *instance,
+ unsigned char *src, int len)
{
- unsigned char *s;
- volatile unsigned char *d;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
-
- s = src;
- d = mac_scsi_drq;
-
-/* These conditions are derived from MacOS */
-
- while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)
- && (!(NCR5380_read(STATUS_REG) & SR_REQ)
- || (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)))
- ;
- if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) {
- printk(KERN_ERR "Error in macscsi_pwrite\n");
- return -1;
- }
-
- CP_MEM_TO_IO(s, d, len);
-
- if (len != 0) {
- printk(KERN_NOTICE "Bus error in macscsi_pwrite\n");
- return -1;
- }
-
- return 0;
-}
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+ unsigned char *s;
+ unsigned char *d;
+
+ NCR5380_local_declare();
+ NCR5380_setup(instance);
+
+ s = src;
+ d = hostdata->pdma_base + (OUTPUT_DATA_REG << 4);
+
+ /* These conditions are derived from MacOS */
+
+ while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ) &&
+ (!(NCR5380_read(STATUS_REG) & SR_REQ) ||
+ (NCR5380_read(BUS_AND_STATUS_REG) & BASR_PHASE_MATCH)))
+ ;
+
+ if (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)) {
+ pr_err("Error in macscsi_pwrite\n");
+ return -1;
+ }
+
+ CP_MEM_TO_IO(s, d, len);
+
+ if (len != 0) {
+ pr_notice("Bus error in macscsi_pwrite\n");
+ return -1;
+ }
+ return 0;
+}
+#endif
#include "NCR5380.c"
-static struct scsi_host_template driver_template = {
- .proc_name = "Mac5380",
+#define DRV_MODULE_NAME "mac_scsi"
+#define PFX DRV_MODULE_NAME ": "
+
+static struct scsi_host_template mac_scsi_template = {
+ .module = THIS_MODULE,
+ .proc_name = DRV_MODULE_NAME,
.show_info = macscsi_show_info,
.write_info = macscsi_write_info,
.name = "Macintosh NCR5380 SCSI",
- .detect = macscsi_detect,
- .release = macscsi_release,
.info = macscsi_info,
.queuecommand = macscsi_queue_command,
.eh_abort_handler = macscsi_abort,
.eh_bus_reset_handler = macscsi_bus_reset,
- .can_queue = CAN_QUEUE,
+ .can_queue = 16,
.this_id = 7,
.sg_tablesize = SG_ALL,
- .cmd_per_lun = CMD_PER_LUN,
+ .cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING
};
+static int __init mac_scsi_probe(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance;
+ int error;
+ int host_flags = 0;
+ struct resource *irq, *pio_mem, *pdma_mem = NULL;
+
+ pio_mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!pio_mem)
+ return -ENODEV;
+
+#ifdef PSEUDO_DMA
+ pdma_mem = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+#endif
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+
+ if (!hwreg_present((unsigned char *)pio_mem->start +
+ (STATUS_REG << 4))) {
+ pr_info(PFX "no device detected at %pap\n", &pio_mem->start);
+ return -ENODEV;
+ }
+
+ if (setup_can_queue > 0)
+ mac_scsi_template.can_queue = setup_can_queue;
+ if (setup_cmd_per_lun > 0)
+ mac_scsi_template.cmd_per_lun = setup_cmd_per_lun;
+ if (setup_sg_tablesize >= 0)
+ mac_scsi_template.sg_tablesize = setup_sg_tablesize;
+ if (setup_hostid >= 0)
+ mac_scsi_template.this_id = setup_hostid & 7;
+ if (setup_use_pdma < 0)
+ setup_use_pdma = 0;
+
+ instance = scsi_host_alloc(&mac_scsi_template,
+ sizeof(struct NCR5380_hostdata));
+ if (!instance)
+ return -ENOMEM;
+
+ instance->base = pio_mem->start;
+ if (irq)
+ instance->irq = irq->start;
+ else
+ instance->irq = NO_IRQ;
+
+ if (pdma_mem && setup_use_pdma) {
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
+
+ hostdata->pdma_base = (unsigned char *)pdma_mem->start;
+ } else
+ host_flags |= FLAG_NO_PSEUDO_DMA;
+
+#ifdef RESET_BOOT
+ mac_scsi_reset_boot(instance);
+#endif
+
+#ifdef SUPPORT_TAGS
+ host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
+#endif
+
+ NCR5380_init(instance, host_flags);
+
+ if (instance->irq != NO_IRQ) {
+ error = request_irq(instance->irq, macscsi_intr, IRQF_SHARED,
+ "NCR5380", instance);
+ if (error)
+ goto fail_irq;
+ }
+
+ error = scsi_add_host(instance, NULL);
+ if (error)
+ goto fail_host;
+
+ platform_set_drvdata(pdev, instance);
+
+ scsi_scan_host(instance);
+ return 0;
+
+fail_host:
+ if (instance->irq != NO_IRQ)
+ free_irq(instance->irq, instance);
+fail_irq:
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+ return error;
+}
+
+static int __exit mac_scsi_remove(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance = platform_get_drvdata(pdev);
+
+ scsi_remove_host(instance);
+ if (instance->irq != NO_IRQ)
+ free_irq(instance->irq, instance);
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+ return 0;
+}
+
+static struct platform_driver mac_scsi_driver = {
+ .remove = __exit_p(mac_scsi_remove),
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
+
+module_platform_driver_probe(mac_scsi_driver, mac_scsi_probe);
-#include "scsi_module.c"
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
+MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/mac_scsi.h b/drivers/scsi/mac_scsi.h
deleted file mode 100644
index 06969b0..0000000
--- a/drivers/scsi/mac_scsi.h
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- * Cumana Generic NCR5380 driver defines
- *
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 440-4894
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
- */
-
-#ifndef MAC_NCR5380_H
-#define MAC_NCR5380_H
-
-#define MACSCSI_PUBLIC_RELEASE 2
-
-#ifndef ASM
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
-#ifndef SG_TABLESIZE
-#define SG_TABLESIZE SG_NONE
-#endif
-
-#ifndef USE_TAGGED_QUEUING
-#define USE_TAGGED_QUEUING 0
-#endif
-
-#include <scsi/scsicam.h>
-
-#define NCR5380_implementation_fields \
- int port, ctrl
-
-#define NCR5380_local_declare() \
- struct Scsi_Host *_instance
-
-#define NCR5380_setup(instance) \
- _instance = instance
-
-#define NCR5380_read(reg) macscsi_read(_instance, reg)
-#define NCR5380_write(reg, value) macscsi_write(_instance, reg, value)
-
-#define NCR5380_pread macscsi_pread
-#define NCR5380_pwrite macscsi_pwrite
-
-#define NCR5380_intr macscsi_intr
-#define NCR5380_queue_command macscsi_queue_command
-#define NCR5380_abort macscsi_abort
-#define NCR5380_bus_reset macscsi_bus_reset
-#define NCR5380_show_info macscsi_show_info
-#define NCR5380_write_info macscsi_write_info
-
-#endif /* ndef ASM */
-#endif /* MAC_NCR5380_H */
-
diff --git a/drivers/scsi/megaraid.c b/drivers/scsi/megaraid.c
index ac5d94c..2485255 100644
--- a/drivers/scsi/megaraid.c
+++ b/drivers/scsi/megaraid.c
@@ -1945,7 +1945,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
cmd->device->id, (u32)cmd->device->lun);
if(list_empty(&adapter->pending_list))
- return FALSE;
+ return FAILED;
list_for_each_safe(pos, next, &adapter->pending_list) {
@@ -1968,7 +1968,7 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
(aor==SCB_ABORT) ? "ABORTING":"RESET",
scb->idx);
- return FALSE;
+ return FAILED;
}
else {
@@ -1993,12 +1993,12 @@ megaraid_abort_and_reset(adapter_t *adapter, Scsi_Cmnd *cmd, int aor)
list_add_tail(SCSI_LIST(cmd),
&adapter->completed_list);
- return TRUE;
+ return SUCCESS;
}
}
}
- return FALSE;
+ return FAILED;
}
static inline int
diff --git a/drivers/scsi/megaraid/megaraid_mbox.c b/drivers/scsi/megaraid/megaraid_mbox.c
index 531dce4..f0987f2 100644
--- a/drivers/scsi/megaraid/megaraid_mbox.c
+++ b/drivers/scsi/megaraid/megaraid_mbox.c
@@ -332,27 +332,6 @@ static struct device_attribute *megaraid_sdev_attrs[] = {
NULL,
};
-/**
- * megaraid_change_queue_depth - Change the device's queue depth
- * @sdev: scsi device struct
- * @qdepth: depth to set
- * @reason: calling context
- *
- * Return value:
- * actual depth set
- */
-static int megaraid_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason)
-{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
- if (qdepth > MBOX_MAX_SCSI_CMDS)
- qdepth = MBOX_MAX_SCSI_CMDS;
- scsi_adjust_queue_depth(sdev, 0, qdepth);
- return sdev->queue_depth;
-}
-
/*
* Scsi host template for megaraid unified driver
*/
@@ -365,7 +344,7 @@ static struct scsi_host_template megaraid_template_g = {
.eh_device_reset_handler = megaraid_reset_handler,
.eh_bus_reset_handler = megaraid_reset_handler,
.eh_host_reset_handler = megaraid_reset_handler,
- .change_queue_depth = megaraid_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.use_clustering = ENABLE_CLUSTERING,
.no_write_same = 1,
.sdev_attrs = megaraid_sdev_attrs,
diff --git a/drivers/scsi/megaraid/megaraid_sas.h b/drivers/scsi/megaraid/megaraid_sas.h
index a49914d..0d44d91 100644
--- a/drivers/scsi/megaraid/megaraid_sas.h
+++ b/drivers/scsi/megaraid/megaraid_sas.h
@@ -1,7 +1,8 @@
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2003-2012 LSI Corporation.
+ * Copyright (c) 2003-2013 LSI Corporation
+ * Copyright (c) 2013-2014 Avago Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,17 +15,18 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* FILE: megaraid_sas.h
*
- * Authors: LSI Corporation
+ * Authors: Avago Technologies
+ * Kashyap Desai <kashyap.desai@avagotech.com>
+ * Sumit Saxena <sumit.saxena@avagotech.com>
*
- * Send feedback to: <megaraidlinux@lsi.com>
+ * Send feedback to: megaraidlinux.pdl@avagotech.com
*
- * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
- * ATTN: Linuxraid
+ * Mail to: Avago Technologies, 350 West Trimble Road, Building 90,
+ * San Jose, California 95131
*/
#ifndef LSI_MEGARAID_SAS_H
@@ -33,9 +35,7 @@
/*
* MegaRAID SAS Driver meta data
*/
-#define MEGASAS_VERSION "06.805.06.00-rc1"
-#define MEGASAS_RELDATE "Sep. 4, 2014"
-#define MEGASAS_EXT_VERSION "Thu. Sep. 4 17:00:00 PDT 2014"
+#define MEGASAS_VERSION "06.805.06.01-rc1"
/*
* Device IDs
@@ -1931,8 +1931,7 @@ u16 get_updated_dev_handle(struct megasas_instance *instance,
struct LD_LOAD_BALANCE_INFO *lbInfo, struct IO_REQUEST_INFO *in_info);
void mr_update_load_balance_params(struct MR_DRV_RAID_MAP_ALL *map,
struct LD_LOAD_BALANCE_INFO *lbInfo);
-int megasas_get_ctrl_info(struct megasas_instance *instance,
- struct megasas_ctrl_info *ctrl_info);
+int megasas_get_ctrl_info(struct megasas_instance *instance);
int megasas_set_crash_dump_params(struct megasas_instance *instance,
u8 crash_buf_state);
void megasas_free_host_crash_buffer(struct megasas_instance *instance);
diff --git a/drivers/scsi/megaraid/megaraid_sas_base.c b/drivers/scsi/megaraid/megaraid_sas_base.c
index 5640ad1..f05580e 100644
--- a/drivers/scsi/megaraid/megaraid_sas_base.c
+++ b/drivers/scsi/megaraid/megaraid_sas_base.c
@@ -1,7 +1,8 @@
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2003-2012 LSI Corporation.
+ * Copyright (c) 2003-2013 LSI Corporation
+ * Copyright (c) 2013-2014 Avago Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,22 +15,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
- * FILE: megaraid_sas_base.c
- * Version : 06.805.06.00-rc1
- *
- * Authors: LSI Corporation
+ * Authors: Avago Technologies
* Sreenivas Bagalkote
* Sumant Patro
* Bo Yang
- * Adam Radford <linuxraid@lsi.com>
+ * Adam Radford
+ * Kashyap Desai <kashyap.desai@avagotech.com>
+ * Sumit Saxena <sumit.saxena@avagotech.com>
*
- * Send feedback to: <megaraidlinux@lsi.com>
+ * Send feedback to: megaraidlinux.pdl@avagotech.com
*
- * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
- * ATTN: Linuxraid
+ * Mail to: Avago Technologies, 350 West Trimble Road, Building 90,
+ * San Jose, California 95131
*/
#include <linux/kernel.h>
@@ -1008,7 +1007,7 @@ megasas_issue_blocked_abort_cmd(struct megasas_instance *instance,
cpu_to_le32(upper_32_bits(cmd_to_abort->frame_phys_addr));
cmd->sync_cmd = 1;
- cmd->cmd_status = 0xFF;
+ cmd->cmd_status = ENODATA;
instance->instancet->issue_dcmd(instance, cmd);
@@ -1572,6 +1571,12 @@ megasas_queue_command(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
instance = (struct megasas_instance *)
scmd->device->host->hostdata;
+ if (instance->unload == 1) {
+ scmd->result = DID_NO_CONNECT << 16;
+ scmd->scsi_done(scmd);
+ return 0;
+ }
+
if (instance->issuepend_done == 0)
return SCSI_MLQUEUE_HOST_BUSY;
@@ -2586,20 +2591,6 @@ megasas_service_aen(struct megasas_instance *instance, struct megasas_cmd *cmd)
}
}
-static int megasas_change_queue_depth(struct scsi_device *sdev,
- int queue_depth, int reason)
-{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
- if (queue_depth > sdev->host->can_queue)
- queue_depth = sdev->host->can_queue;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev),
- queue_depth);
-
- return queue_depth;
-}
-
static ssize_t
megasas_fw_crash_buffer_store(struct device *cdev,
struct device_attribute *attr, const char *buf, size_t count)
@@ -2764,7 +2755,7 @@ static struct scsi_host_template megasas_template = {
.shost_attrs = megaraid_host_attrs,
.bios_param = megasas_bios_param,
.use_clustering = ENABLE_CLUSTERING,
- .change_queue_depth = megasas_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.no_write_same = 1,
};
@@ -4028,25 +4019,83 @@ megasas_ld_list_query(struct megasas_instance *instance, u8 query_type)
return ret;
}
+/*
+ * megasas_update_ext_vd_details : Update details w.r.t Extended VD
+ * instance : Controller's instance
+*/
+static void megasas_update_ext_vd_details(struct megasas_instance *instance)
+{
+ struct fusion_context *fusion;
+ u32 old_map_sz;
+ u32 new_map_sz;
+
+ fusion = instance->ctrl_context;
+ /* For MFI based controllers return dummy success */
+ if (!fusion)
+ return;
+
+ instance->supportmax256vd =
+ instance->ctrl_info->adapterOperations3.supportMaxExtLDs;
+ /* Below is additional check to address future FW enhancement */
+ if (instance->ctrl_info->max_lds > 64)
+ instance->supportmax256vd = 1;
+
+ instance->drv_supported_vd_count = MEGASAS_MAX_LD_CHANNELS
+ * MEGASAS_MAX_DEV_PER_CHANNEL;
+ instance->drv_supported_pd_count = MEGASAS_MAX_PD_CHANNELS
+ * MEGASAS_MAX_DEV_PER_CHANNEL;
+ if (instance->supportmax256vd) {
+ instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES_EXT;
+ instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
+ } else {
+ instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
+ instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
+ }
+ dev_info(&instance->pdev->dev, "Firmware supports %d VD %d PD\n",
+ instance->fw_supported_vd_count,
+ instance->fw_supported_pd_count);
+ dev_info(&instance->pdev->dev, "Driver supports %d VD %d PD\n",
+ instance->drv_supported_vd_count,
+ instance->drv_supported_pd_count);
+
+ old_map_sz = sizeof(struct MR_FW_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *
+ (instance->fw_supported_vd_count - 1));
+ new_map_sz = sizeof(struct MR_FW_RAID_MAP_EXT);
+ fusion->drv_map_sz = sizeof(struct MR_DRV_RAID_MAP) +
+ (sizeof(struct MR_LD_SPAN_MAP) *
+ (instance->drv_supported_vd_count - 1));
+
+ fusion->max_map_sz = max(old_map_sz, new_map_sz);
+
+
+ if (instance->supportmax256vd)
+ fusion->current_map_sz = new_map_sz;
+ else
+ fusion->current_map_sz = old_map_sz;
+
+}
+
/**
* megasas_get_controller_info - Returns FW's controller structure
* @instance: Adapter soft state
- * @ctrl_info: Controller information structure
*
* Issues an internal command (DCMD) to get the FW's controller structure.
* This information is mainly used to find out the maximum IO transfer per
* command supported by the FW.
*/
int
-megasas_get_ctrl_info(struct megasas_instance *instance,
- struct megasas_ctrl_info *ctrl_info)
+megasas_get_ctrl_info(struct megasas_instance *instance)
{
int ret = 0;
struct megasas_cmd *cmd;
struct megasas_dcmd_frame *dcmd;
struct megasas_ctrl_info *ci;
+ struct megasas_ctrl_info *ctrl_info;
dma_addr_t ci_h = 0;
+ ctrl_info = instance->ctrl_info;
+
cmd = megasas_get_cmd(instance);
if (!cmd) {
@@ -4086,8 +4135,13 @@ megasas_get_ctrl_info(struct megasas_instance *instance,
else
ret = megasas_issue_polled(instance, cmd);
- if (!ret)
+ if (!ret) {
memcpy(ctrl_info, ci, sizeof(struct megasas_ctrl_info));
+ le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
+ le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
+ le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
+ megasas_update_ext_vd_details(instance);
+ }
pci_free_consistent(instance->pdev, sizeof(struct megasas_ctrl_info),
ci, ci_h);
@@ -4289,7 +4343,7 @@ megasas_init_adapter_mfi(struct megasas_instance *instance)
if (megasas_issue_init_mfi(instance))
goto fail_fw_init;
- if (megasas_get_ctrl_info(instance, instance->ctrl_info)) {
+ if (megasas_get_ctrl_info(instance)) {
dev_err(&instance->pdev->dev, "(%d): Could get controller info "
"Fail from %s %d\n", instance->unique_id,
__func__, __LINE__);
@@ -4527,12 +4581,8 @@ static int megasas_init_fw(struct megasas_instance *instance)
dev_info(&instance->pdev->dev,
"Controller type: iMR\n");
}
- /* OnOffProperties are converted into CPU arch*/
- le32_to_cpus((u32 *)&ctrl_info->properties.OnOffProperties);
instance->disableOnlineCtrlReset =
ctrl_info->properties.OnOffProperties.disableOnlineCtrlReset;
- /* adapterOperations2 are converted into CPU arch*/
- le32_to_cpus((u32 *)&ctrl_info->adapterOperations2);
instance->mpio = ctrl_info->adapterOperations2.mpio;
instance->UnevenSpanSupport =
ctrl_info->adapterOperations2.supportUnevenSpans;
@@ -4562,7 +4612,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
"requestorId %d\n", instance->requestorId);
}
- le32_to_cpus((u32 *)&ctrl_info->adapterOperations3);
instance->crash_dump_fw_support =
ctrl_info->adapterOperations3.supportCrashDump;
instance->crash_dump_drv_support =
@@ -4587,8 +4636,6 @@ static int megasas_init_fw(struct megasas_instance *instance)
if (tmp_sectors && (instance->max_sectors_per_req > tmp_sectors))
instance->max_sectors_per_req = tmp_sectors;
- kfree(ctrl_info);
-
/* Check for valid throttlequeuedepth module parameter */
if (instance->is_imr) {
if (throttlequeuedepth > (instance->max_fw_cmds -
@@ -4957,10 +5004,6 @@ static int megasas_io_attach(struct megasas_instance *instance)
return -ENODEV;
}
- /*
- * Trigger SCSI to scan our drives
- */
- scsi_scan_host(host);
return 0;
}
@@ -5083,6 +5126,8 @@ static int megasas_probe_one(struct pci_dev *pdev,
goto fail_alloc_dma_buf;
}
fusion = instance->ctrl_context;
+ memset(fusion, 0,
+ ((1 << PAGE_SHIFT) << instance->ctrl_context_pages));
INIT_LIST_HEAD(&fusion->cmd_pool);
spin_lock_init(&fusion->mpt_pool_lock);
memset(fusion->load_balance_info, 0,
@@ -5288,6 +5333,10 @@ retry_irq_register:
goto fail_io_attach;
instance->unload = 0;
+ /*
+ * Trigger SCSI to scan our drives
+ */
+ scsi_scan_host(host);
/*
* Initiate AEN (Asynchronous Event Notification)
@@ -6051,6 +6100,11 @@ megasas_mgmt_fw_ioctl(struct megasas_instance *instance,
megasas_issue_blocked_cmd(instance, cmd, 0);
cmd->sync_cmd = 0;
+ if (instance->unload == 1) {
+ dev_info(&instance->pdev->dev, "Driver unload is in progress "
+ "don't submit data to application\n");
+ goto out;
+ }
/*
* copy out the kernel buffers to user buffers
*/
@@ -6400,16 +6454,6 @@ static ssize_t megasas_sysfs_show_version(struct device_driver *dd, char *buf)
static DRIVER_ATTR(version, S_IRUGO, megasas_sysfs_show_version, NULL);
static ssize_t
-megasas_sysfs_show_release_date(struct device_driver *dd, char *buf)
-{
- return snprintf(buf, strlen(MEGASAS_RELDATE) + 2, "%s\n",
- MEGASAS_RELDATE);
-}
-
-static DRIVER_ATTR(release_date, S_IRUGO, megasas_sysfs_show_release_date,
- NULL);
-
-static ssize_t
megasas_sysfs_show_support_poll_for_event(struct device_driver *dd, char *buf)
{
return sprintf(buf, "%u\n", support_poll_for_event);
@@ -6712,8 +6756,7 @@ static int __init megasas_init(void)
/*
* Announce driver version and other information
*/
- printk(KERN_INFO "megasas: %s %s\n", MEGASAS_VERSION,
- MEGASAS_EXT_VERSION);
+ pr_info("megasas: %s\n", MEGASAS_VERSION);
spin_lock_init(&poll_aen_lock);
@@ -6748,10 +6791,6 @@ static int __init megasas_init(void)
&driver_attr_version);
if (rval)
goto err_dcf_attr_ver;
- rval = driver_create_file(&megasas_pci_driver.driver,
- &driver_attr_release_date);
- if (rval)
- goto err_dcf_rel_date;
rval = driver_create_file(&megasas_pci_driver.driver,
&driver_attr_support_poll_for_event);
@@ -6775,12 +6814,7 @@ err_dcf_support_device_change:
err_dcf_dbg_lvl:
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_support_poll_for_event);
-
err_dcf_support_poll_for_event:
- driver_remove_file(&megasas_pci_driver.driver,
- &driver_attr_release_date);
-
-err_dcf_rel_date:
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
err_dcf_attr_ver:
pci_unregister_driver(&megasas_pci_driver);
@@ -6800,8 +6834,6 @@ static void __exit megasas_exit(void)
&driver_attr_support_poll_for_event);
driver_remove_file(&megasas_pci_driver.driver,
&driver_attr_support_device_change);
- driver_remove_file(&megasas_pci_driver.driver,
- &driver_attr_release_date);
driver_remove_file(&megasas_pci_driver.driver, &driver_attr_version);
pci_unregister_driver(&megasas_pci_driver);
diff --git a/drivers/scsi/megaraid/megaraid_sas_fp.c b/drivers/scsi/megaraid/megaraid_sas_fp.c
index 685e6f3..460c6a3 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fp.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fp.c
@@ -1,7 +1,8 @@
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2009-2012 LSI Corporation.
+ * Copyright (c) 2009-2013 LSI Corporation
+ * Copyright (c) 2013-2014 Avago Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,20 +15,21 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* FILE: megaraid_sas_fp.c
*
- * Authors: LSI Corporation
+ * Authors: Avago Technologies
* Sumant Patro
* Varad Talamacki
* Manoj Jose
+ * Kashyap Desai <kashyap.desai@avagotech.com>
+ * Sumit Saxena <sumit.saxena@avagotech.com>
*
- * Send feedback to: <megaraidlinux@lsi.com>
+ * Send feedback to: megaraidlinux.pdl@avagotech.com
*
- * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
- * ATTN: Linuxraid
+ * Mail to: Avago Technologies, 350 West Trimble Road, Building 90,
+ * San Jose, California 95131
*/
#include <linux/kernel.h>
@@ -183,14 +185,15 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
/* New Raid map will not set totalSize, so keep expected value
* for legacy code in ValidateMapInfo
*/
- pDrvRaidMap->totalSize = sizeof(struct MR_FW_RAID_MAP_EXT);
+ pDrvRaidMap->totalSize =
+ cpu_to_le32(sizeof(struct MR_FW_RAID_MAP_EXT));
} else {
fw_map_old = (struct MR_FW_RAID_MAP_ALL *)
fusion->ld_map[(instance->map_id & 1)];
pFwRaidMap = &fw_map_old->raidMap;
#if VD_EXT_DEBUG
- for (i = 0; i < pFwRaidMap->ldCount; i++) {
+ for (i = 0; i < le16_to_cpu(pFwRaidMap->ldCount); i++) {
dev_dbg(&instance->pdev->dev, "(%d) :Index 0x%x "
"Target Id 0x%x Seq Num 0x%x Size 0/%llx\n",
instance->unique_id, i,
@@ -202,12 +205,12 @@ void MR_PopulateDrvRaidMap(struct megasas_instance *instance)
memset(drv_map, 0, fusion->drv_map_sz);
pDrvRaidMap->totalSize = pFwRaidMap->totalSize;
- pDrvRaidMap->ldCount = pFwRaidMap->ldCount;
+ pDrvRaidMap->ldCount = (__le16)pFwRaidMap->ldCount;
pDrvRaidMap->fpPdIoTimeoutSec = pFwRaidMap->fpPdIoTimeoutSec;
for (i = 0; i < MAX_RAIDMAP_LOGICAL_DRIVES + MAX_RAIDMAP_VIEWS; i++)
pDrvRaidMap->ldTgtIdToLd[i] =
(u8)pFwRaidMap->ldTgtIdToLd[i];
- for (i = 0; i < pDrvRaidMap->ldCount; i++) {
+ for (i = 0; i < le16_to_cpu(pDrvRaidMap->ldCount); i++) {
pDrvRaidMap->ldSpanMap[i] = pFwRaidMap->ldSpanMap[i];
#if VD_EXT_DEBUG
dev_dbg(&instance->pdev->dev,
@@ -268,7 +271,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
else
expected_size =
(sizeof(struct MR_FW_RAID_MAP) - sizeof(struct MR_LD_SPAN_MAP) +
- (sizeof(struct MR_LD_SPAN_MAP) * le32_to_cpu(pDrvRaidMap->ldCount)));
+ (sizeof(struct MR_LD_SPAN_MAP) * le16_to_cpu(pDrvRaidMap->ldCount)));
if (le32_to_cpu(pDrvRaidMap->totalSize) != expected_size) {
dev_err(&instance->pdev->dev, "map info structure size 0x%x is not matching with ld count\n",
@@ -284,7 +287,7 @@ u8 MR_ValidateMapInfo(struct megasas_instance *instance)
mr_update_load_balance_params(drv_map, lbInfo);
- num_lds = le32_to_cpu(drv_map->raidMap.ldCount);
+ num_lds = le16_to_cpu(drv_map->raidMap.ldCount);
/*Convert Raid capability values to CPU arch */
for (ldCount = 0; ldCount < num_lds; ldCount++) {
@@ -457,7 +460,7 @@ u32 mr_spanset_get_span_block(struct megasas_instance *instance,
quad = &map->raidMap.ldSpanMap[ld].
spanBlock[span].
block_span_info.quad[info];
- if (le32_to_cpu(quad->diff == 0))
+ if (le32_to_cpu(quad->diff) == 0)
return SPAN_INVALID;
if (le64_to_cpu(quad->logStart) <= row &&
row <= le64_to_cpu(quad->logEnd) &&
@@ -520,7 +523,7 @@ static u64 get_row_from_strip(struct megasas_instance *instance,
span_set->span_row_data_width) * span_set->diff;
for (span = 0, span_offset = 0; span < raid->spanDepth; span++)
if (le32_to_cpu(map->raidMap.ldSpanMap[ld].spanBlock[span].
- block_span_info.noElements >= info+1)) {
+ block_span_info.noElements) >= info+1) {
if (strip_offset >=
span_set->strip_offset[span])
span_offset++;
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.c b/drivers/scsi/megaraid/megaraid_sas_fusion.c
index f37eed6..71557f6 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.c
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.c
@@ -1,7 +1,8 @@
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2009-2012 LSI Corporation.
+ * Copyright (c) 2009-2013 LSI Corporation
+ * Copyright (c) 2013-2014 Avago Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,19 +15,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* FILE: megaraid_sas_fusion.c
*
- * Authors: LSI Corporation
+ * Authors: Avago Technologies
* Sumant Patro
- * Adam Radford <linuxraid@lsi.com>
+ * Adam Radford
+ * Kashyap Desai <kashyap.desai@avagotech.com>
+ * Sumit Saxena <sumit.saxena@avagotech.com>
*
- * Send feedback to: <megaraidlinux@lsi.com>
+ * Send feedback to: megaraidlinux.pdl@avagotech.com
*
- * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
- * ATTN: Linuxraid
+ * Mail to: Avago Technologies, 350 West Trimble Road, Building 90,
+ * San Jose, California 95131
*/
#include <linux/kernel.h>
@@ -880,7 +882,7 @@ megasas_sync_map_info(struct megasas_instance *instance)
map = fusion->ld_drv_map[instance->map_id & 1];
- num_lds = le32_to_cpu(map->raidMap.ldCount);
+ num_lds = le16_to_cpu(map->raidMap.ldCount);
dcmd = &cmd->frame->dcmd;
@@ -1065,48 +1067,16 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
goto fail_ioc_init;
megasas_display_intel_branding(instance);
- if (megasas_get_ctrl_info(instance, instance->ctrl_info)) {
+ if (megasas_get_ctrl_info(instance)) {
dev_err(&instance->pdev->dev,
"Could not get controller info. Fail from %s %d\n",
__func__, __LINE__);
goto fail_ioc_init;
}
- instance->supportmax256vd =
- instance->ctrl_info->adapterOperations3.supportMaxExtLDs;
- /* Below is additional check to address future FW enhancement */
- if (instance->ctrl_info->max_lds > 64)
- instance->supportmax256vd = 1;
- instance->drv_supported_vd_count = MEGASAS_MAX_LD_CHANNELS
- * MEGASAS_MAX_DEV_PER_CHANNEL;
- instance->drv_supported_pd_count = MEGASAS_MAX_PD_CHANNELS
- * MEGASAS_MAX_DEV_PER_CHANNEL;
- if (instance->supportmax256vd) {
- instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES_EXT;
- instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
- } else {
- instance->fw_supported_vd_count = MAX_LOGICAL_DRIVES;
- instance->fw_supported_pd_count = MAX_PHYSICAL_DEVICES;
- }
- dev_info(&instance->pdev->dev, "Firmware supports %d VDs %d PDs\n"
- "Driver supports %d VDs %d PDs\n",
- instance->fw_supported_vd_count,
- instance->fw_supported_pd_count,
- instance->drv_supported_vd_count,
- instance->drv_supported_pd_count);
-
instance->flag_ieee = 1;
fusion->fast_path_io = 0;
- fusion->old_map_sz =
- sizeof(struct MR_FW_RAID_MAP) + (sizeof(struct MR_LD_SPAN_MAP) *
- (instance->fw_supported_vd_count - 1));
- fusion->new_map_sz =
- sizeof(struct MR_FW_RAID_MAP_EXT);
- fusion->drv_map_sz =
- sizeof(struct MR_DRV_RAID_MAP) + (sizeof(struct MR_LD_SPAN_MAP) *
- (instance->drv_supported_vd_count - 1));
-
fusion->drv_map_pages = get_order(fusion->drv_map_sz);
for (i = 0; i < 2; i++) {
fusion->ld_map[i] = NULL;
@@ -1121,16 +1091,10 @@ megasas_init_adapter_fusion(struct megasas_instance *instance)
fusion->drv_map_pages);
goto fail_ioc_init;
}
+ memset(fusion->ld_drv_map[i], 0,
+ ((1 << PAGE_SHIFT) << fusion->drv_map_pages));
}
- fusion->max_map_sz = max(fusion->old_map_sz, fusion->new_map_sz);
-
- if (instance->supportmax256vd)
- fusion->current_map_sz = fusion->new_map_sz;
- else
- fusion->current_map_sz = fusion->old_map_sz;
-
-
for (i = 0; i < 2; i++) {
fusion->ld_map[i] = dma_alloc_coherent(&instance->pdev->dev,
fusion->max_map_sz,
@@ -1173,9 +1137,10 @@ megasas_fire_cmd_fusion(struct megasas_instance *instance,
struct megasas_register_set __iomem *regs)
{
#if defined(writeq) && defined(CONFIG_64BIT)
- u64 req_data = (((u64)req_desc_hi << 32) | (u32)req_desc_lo);
+ u64 req_data = (((u64)le32_to_cpu(req_desc_hi) << 32) |
+ le32_to_cpu(req_desc_lo));
- writeq(le64_to_cpu(req_data), &(regs)->inbound_low_queue_port);
+ writeq(req_data, &(regs)->inbound_low_queue_port);
#else
unsigned long flags;
@@ -1373,7 +1338,7 @@ megasas_set_pd_lba(struct MPI2_RAID_SCSI_IO_REQUEST *io_request, u8 cdb_len,
/* Logical block reference tag */
io_request->CDB.EEDP32.PrimaryReferenceTag =
cpu_to_be32(ref_tag);
- io_request->CDB.EEDP32.PrimaryApplicationTagMask = 0xffff;
+ io_request->CDB.EEDP32.PrimaryApplicationTagMask = cpu_to_be16(0xffff);
io_request->IoFlags = cpu_to_le16(32); /* Specify 32-byte cdb */
/* Transfer length */
@@ -1769,7 +1734,7 @@ megasas_build_dcdb_fusion(struct megasas_instance *instance,
/* set RAID context values */
pRAID_Context->regLockFlags = REGION_TYPE_SHARED_READ;
- pRAID_Context->timeoutValue = raid->fpIoTimeoutForLd;
+ pRAID_Context->timeoutValue = cpu_to_le16(raid->fpIoTimeoutForLd);
pRAID_Context->VirtualDiskTgtId = cpu_to_le16(device_id);
pRAID_Context->regLockRowLBA = 0;
pRAID_Context->regLockLength = 0;
@@ -2254,7 +2219,7 @@ build_mpt_mfi_pass_thru(struct megasas_instance *instance,
* megasas_complete_cmd
*/
- if (frame_hdr->flags & MFI_FRAME_DONT_POST_IN_REPLY_QUEUE)
+ if (frame_hdr->flags & cpu_to_le16(MFI_FRAME_DONT_POST_IN_REPLY_QUEUE))
cmd->flags = MFI_FRAME_DONT_POST_IN_REPLY_QUEUE;
fusion = instance->ctrl_context;
@@ -2385,6 +2350,8 @@ megasas_alloc_host_crash_buffer(struct megasas_instance *instance)
"memory allocation failed at index %d\n", i);
break;
}
+ memset(instance->crash_buf[i], 0,
+ ((1 << PAGE_SHIFT) << instance->crash_buf_pages));
}
instance->drv_buf_alloc = i;
}
@@ -2837,11 +2804,15 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
}
}
- clear_bit(MEGASAS_FUSION_IN_RESET,
- &instance->reset_flags);
- instance->instancet->enable_intr(instance);
- instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
-
+ if (megasas_get_ctrl_info(instance)) {
+ dev_info(&instance->pdev->dev,
+ "Failed from %s %d\n",
+ __func__, __LINE__);
+ instance->adprecovery =
+ MEGASAS_HW_CRITICAL_ERROR;
+ megaraid_sas_kill_hba(instance);
+ retval = FAILED;
+ }
/* Reset load balance info */
memset(fusion->load_balance_info, 0,
sizeof(struct LD_LOAD_BALANCE_INFO)
@@ -2850,6 +2821,11 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
if (!megasas_get_map_info(instance))
megasas_sync_map_info(instance);
+ clear_bit(MEGASAS_FUSION_IN_RESET,
+ &instance->reset_flags);
+ instance->instancet->enable_intr(instance);
+ instance->adprecovery = MEGASAS_HBA_OPERATIONAL;
+
/* Restart SR-IOV heartbeat */
if (instance->requestorId) {
if (!megasas_sriov_start_heartbeat(instance, 0))
@@ -2866,14 +2842,14 @@ int megasas_reset_fusion(struct Scsi_Host *shost, int iotimeout)
"successful for scsi%d.\n",
instance->host->host_no);
- if (instance->crash_dump_drv_support) {
- if (instance->crash_dump_app_support)
- megasas_set_crash_dump_params(instance,
- MR_CRASH_BUF_TURN_ON);
- else
- megasas_set_crash_dump_params(instance,
- MR_CRASH_BUF_TURN_OFF);
- }
+ if (instance->crash_dump_drv_support &&
+ instance->crash_dump_app_support)
+ megasas_set_crash_dump_params(instance,
+ MR_CRASH_BUF_TURN_ON);
+ else
+ megasas_set_crash_dump_params(instance,
+ MR_CRASH_BUF_TURN_OFF);
+
retval = SUCCESS;
goto out;
}
diff --git a/drivers/scsi/megaraid/megaraid_sas_fusion.h b/drivers/scsi/megaraid/megaraid_sas_fusion.h
index 0d183d5..5ab7dae 100644
--- a/drivers/scsi/megaraid/megaraid_sas_fusion.h
+++ b/drivers/scsi/megaraid/megaraid_sas_fusion.h
@@ -1,7 +1,8 @@
/*
* Linux MegaRAID driver for SAS based RAID controllers
*
- * Copyright (c) 2009-2012 LSI Corporation.
+ * Copyright (c) 2009-2013 LSI Corporation
+ * Copyright (c) 2013-2014 Avago Technologies
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -14,19 +15,20 @@
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
*
* FILE: megaraid_sas_fusion.h
*
- * Authors: LSI Corporation
+ * Authors: Avago Technologies
* Manoj Jose
* Sumant Patro
+ * Kashyap Desai <kashyap.desai@avagotech.com>
+ * Sumit Saxena <sumit.saxena@avagotech.com>
*
- * Send feedback to: <megaraidlinux@lsi.com>
+ * Send feedback to: megaraidlinux.pdl@avagotech.com
*
- * Mail to: LSI Corporation, 1621 Barber Lane, Milpitas, CA 95035
- * ATTN: Linuxraid
+ * Mail to: Avago Technologies, 350 West Trimble Road, Building 90,
+ * San Jose, California 95131
*/
#ifndef _MEGARAID_SAS_FUSION_H_
@@ -834,8 +836,6 @@ struct fusion_context {
u32 max_map_sz;
u32 current_map_sz;
- u32 old_map_sz;
- u32 new_map_sz;
u32 drv_map_sz;
u32 drv_map_pages;
u8 fast_path_io;
diff --git a/drivers/scsi/mpt2sas/mpt2sas_scsih.c b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
index c80ed04..8431eb1 100644
--- a/drivers/scsi/mpt2sas/mpt2sas_scsih.c
+++ b/drivers/scsi/mpt2sas/mpt2sas_scsih.c
@@ -1179,15 +1179,14 @@ _scsih_build_scatter_gather(struct MPT2SAS_ADAPTER *ioc,
}
/**
- * _scsih_adjust_queue_depth - setting device queue depth
+ * _scsih_change_queue_depth - setting device queue depth
* @sdev: scsi device struct
* @qdepth: requested queue depth
*
- *
- * Returns nothing
+ * Returns queue depth.
*/
-static void
-_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
+static int
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
@@ -1217,63 +1216,11 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
spin_unlock_irqrestore(&ioc->sas_device_lock, flags);
not_sata:
-
if (!sdev->tagged_supported)
max_depth = 1;
if (qdepth > max_depth)
qdepth = max_depth;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
-}
-
-/**
- * _scsih_change_queue_depth - setting device queue depth
- * @sdev: scsi device struct
- * @qdepth: requested queue depth
- * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
- * (see include/scsi/scsi_host.h for definition)
- *
- * Returns queue depth.
- */
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
-{
- if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP)
- _scsih_adjust_queue_depth(sdev, qdepth);
- else if (reason == SCSI_QDEPTH_QFULL)
- scsi_track_queue_full(sdev, qdepth);
- else
- return -EOPNOTSUPP;
-
- if (sdev->inquiry_len > 7)
- sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), "
- "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
- sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
- sdev->ordered_tags, sdev->scsi_level,
- (sdev->inquiry[7] & 2) >> 1);
-
- return sdev->queue_depth;
-}
-
-/**
- * _scsih_change_queue_type - changing device queue tag type
- * @sdev: scsi device struct
- * @tag_type: requested tag type
- *
- * Returns queue tag type.
- */
-static int
-_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
+ return scsi_change_queue_depth(sdev, qdepth);
}
/**
@@ -2104,7 +2051,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
r_level, raid_device->handle,
(unsigned long long)raid_device->wwid,
raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
+ _scsih_change_queue_depth(sdev, qdepth);
/* raid transport support */
if (!ioc->is_warpdrive)
_scsih_set_level(sdev, raid_device->volume_type);
@@ -2169,7 +2116,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_display_sata_capabilities(ioc, handle, sdev);
- _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
+ _scsih_change_queue_depth(sdev, qdepth);
if (ssp_target) {
sas_read_port_mode_page(sdev);
@@ -3966,16 +3913,8 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
/* set tags */
- if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
- if (scmd->device->tagged_supported) {
- if (scmd->device->ordered_tags)
- mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
- else
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- } else
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- } else
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+
/* Make sure Device is not raid volume.
* We do not expose raid functionality to upper layer for warpdrive.
*/
@@ -7653,7 +7592,7 @@ static struct scsi_host_template scsih_driver_template = {
.scan_finished = _scsih_scan_finished,
.scan_start = _scsih_scan_start,
.change_queue_depth = _scsih_change_queue_depth,
- .change_queue_type = _scsih_change_queue_type,
+ .change_queue_type = scsi_change_queue_type,
.eh_abort_handler = _scsih_abort,
.eh_device_reset_handler = _scsih_dev_reset,
.eh_target_reset_handler = _scsih_target_reset,
@@ -7667,6 +7606,7 @@ static struct scsi_host_template scsih_driver_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = mpt2sas_host_attrs,
.sdev_attrs = mpt2sas_dev_attrs,
+ .track_queue_depth = 1,
};
/**
diff --git a/drivers/scsi/mpt3sas/mpt3sas_scsih.c b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
index 857276b..a2b6099 100644
--- a/drivers/scsi/mpt3sas/mpt3sas_scsih.c
+++ b/drivers/scsi/mpt3sas/mpt3sas_scsih.c
@@ -1053,9 +1053,15 @@ _scsih_scsi_lookup_find_by_lun(struct MPT3SAS_ADAPTER *ioc, int id,
return found;
}
-
-static void
-_scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
+/**
+ * _scsih_change_queue_depth - setting device queue depth
+ * @sdev: scsi device struct
+ * @qdepth: requested queue depth
+ *
+ * Returns queue depth.
+ */
+static int
+_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth;
@@ -1090,62 +1096,10 @@ _scsih_adjust_queue_depth(struct scsi_device *sdev, int qdepth)
max_depth = 1;
if (qdepth > max_depth)
qdepth = max_depth;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
+ return scsi_change_queue_depth(sdev, qdepth);
}
/**
- * _scsih_change_queue_depth - setting device queue depth
- * @sdev: scsi device struct
- * @qdepth: requested queue depth
- * @reason: SCSI_QDEPTH_DEFAULT/SCSI_QDEPTH_QFULL/SCSI_QDEPTH_RAMP_UP
- * (see include/scsi/scsi_host.h for definition)
- *
- * Returns queue depth.
- */
-static int
-_scsih_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
-{
- if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP)
- _scsih_adjust_queue_depth(sdev, qdepth);
- else if (reason == SCSI_QDEPTH_QFULL)
- scsi_track_queue_full(sdev, qdepth);
- else
- return -EOPNOTSUPP;
-
- if (sdev->inquiry_len > 7)
- sdev_printk(KERN_INFO, sdev, "qdepth(%d), tagged(%d), " \
- "simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
- sdev->queue_depth, sdev->tagged_supported, sdev->simple_tags,
- sdev->ordered_tags, sdev->scsi_level,
- (sdev->inquiry[7] & 2) >> 1);
-
- return sdev->queue_depth;
-}
-
-/**
- * _scsih_change_queue_type - changing device queue tag type
- * @sdev: scsi device struct
- * @tag_type: requested tag type
- *
- * Returns queue tag type.
- */
-static int
-_scsih_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
-}
-
-
-/**
* _scsih_target_alloc - target add routine
* @starget: scsi target struct
*
@@ -1762,7 +1716,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
raid_device->num_pds, ds);
- _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
+ _scsih_change_queue_depth(sdev, qdepth);
/* raid transport support */
_scsih_set_level(sdev, raid_device->volume_type);
@@ -1828,7 +1782,7 @@ _scsih_slave_configure(struct scsi_device *sdev)
_scsih_display_sata_capabilities(ioc, handle, sdev);
- _scsih_change_queue_depth(sdev, qdepth, SCSI_QDEPTH_DEFAULT);
+ _scsih_change_queue_depth(sdev, qdepth);
if (ssp_target) {
sas_read_port_mode_page(sdev);
@@ -3586,16 +3540,7 @@ _scsih_qcmd(struct Scsi_Host *shost, struct scsi_cmnd *scmd)
mpi_control = MPI2_SCSIIO_CONTROL_NODATATRANSFER;
/* set tags */
- if (!(sas_device_priv_data->flags & MPT_DEVICE_FLAGS_INIT)) {
- if (scmd->device->tagged_supported) {
- if (scmd->device->ordered_tags)
- mpi_control |= MPI2_SCSIIO_CONTROL_ORDEREDQ;
- else
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- } else
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
- } else
- mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
+ mpi_control |= MPI2_SCSIIO_CONTROL_SIMPLEQ;
if ((sas_device_priv_data->flags & MPT_DEVICE_TLR_ON) &&
scmd->cmd_len != 32)
@@ -7284,7 +7229,7 @@ static struct scsi_host_template scsih_driver_template = {
.scan_finished = _scsih_scan_finished,
.scan_start = _scsih_scan_start,
.change_queue_depth = _scsih_change_queue_depth,
- .change_queue_type = _scsih_change_queue_type,
+ .change_queue_type = scsi_change_queue_type,
.eh_abort_handler = _scsih_abort,
.eh_device_reset_handler = _scsih_dev_reset,
.eh_target_reset_handler = _scsih_target_reset,
@@ -7298,6 +7243,7 @@ static struct scsi_host_template scsih_driver_template = {
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = mpt3sas_host_attrs,
.sdev_attrs = mpt3sas_dev_attrs,
+ .track_queue_depth = 1,
};
/**
diff --git a/drivers/scsi/mvsas/mv_init.c b/drivers/scsi/mvsas/mv_init.c
index eacee48..f15df3d 100644
--- a/drivers/scsi/mvsas/mv_init.c
+++ b/drivers/scsi/mvsas/mv_init.c
@@ -26,18 +26,9 @@
#include "mv_sas.h"
-static int lldd_max_execute_num = 1;
-module_param_named(collector, lldd_max_execute_num, int, S_IRUGO);
-MODULE_PARM_DESC(collector, "\n"
- "\tIf greater than one, tells the SAS Layer to run in Task Collector\n"
- "\tMode. If 1 or 0, tells the SAS Layer to run in Direct Mode.\n"
- "\tThe mvsas SAS LLDD supports both modes.\n"
- "\tDefault: 1 (Direct Mode).\n");
-
int interrupt_coalescing = 0x80;
static struct scsi_transport_template *mvs_stt;
-struct kmem_cache *mvs_task_list_cache;
static const struct mvs_chip_info mvs_chips[] = {
[chip_6320] = { 1, 2, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, },
[chip_6440] = { 1, 4, 0x400, 17, 16, 6, 9, &mvs_64xx_dispatch, },
@@ -76,6 +67,8 @@ static struct scsi_host_template mvs_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = mvst_host_attrs,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static struct sas_domain_function_template mvs_transport_ops = {
@@ -511,14 +504,11 @@ static void mvs_post_sas_ha_init(struct Scsi_Host *shost,
sha->num_phys = nr_core * chip_info->n_phy;
- sha->lldd_max_execute_num = lldd_max_execute_num;
-
if (mvi->flags & MVF_FLAG_SOC)
can_queue = MVS_SOC_CAN_QUEUE;
else
can_queue = MVS_CHIP_SLOT_SZ;
- sha->lldd_queue_size = can_queue;
shost->sg_tablesize = min_t(u16, SG_ALL, MVS_MAX_SG);
shost->can_queue = can_queue;
mvi->shost->cmd_per_lun = MVS_QUEUE_SIZE;
@@ -831,16 +821,7 @@ static int __init mvs_init(void)
if (!mvs_stt)
return -ENOMEM;
- mvs_task_list_cache = kmem_cache_create("mvs_task_list", sizeof(struct mvs_task_list),
- 0, SLAB_HWCACHE_ALIGN, NULL);
- if (!mvs_task_list_cache) {
- rc = -ENOMEM;
- mv_printk("%s: mvs_task_list_cache alloc failed! \n", __func__);
- goto err_out;
- }
-
rc = pci_register_driver(&mvs_pci_driver);
-
if (rc)
goto err_out;
@@ -855,7 +836,6 @@ static void __exit mvs_exit(void)
{
pci_unregister_driver(&mvs_pci_driver);
sas_release_transport(mvs_stt);
- kmem_cache_destroy(mvs_task_list_cache);
}
struct device_attribute *mvst_host_attrs[] = {
diff --git a/drivers/scsi/mvsas/mv_sas.c b/drivers/scsi/mvsas/mv_sas.c
index ac52f7c..85d86a5 100644
--- a/drivers/scsi/mvsas/mv_sas.c
+++ b/drivers/scsi/mvsas/mv_sas.c
@@ -852,43 +852,7 @@ prep_out:
return rc;
}
-static struct mvs_task_list *mvs_task_alloc_list(int *num, gfp_t gfp_flags)
-{
- struct mvs_task_list *first = NULL;
-
- for (; *num > 0; --*num) {
- struct mvs_task_list *mvs_list = kmem_cache_zalloc(mvs_task_list_cache, gfp_flags);
-
- if (!mvs_list)
- break;
-
- INIT_LIST_HEAD(&mvs_list->list);
- if (!first)
- first = mvs_list;
- else
- list_add_tail(&mvs_list->list, &first->list);
-
- }
-
- return first;
-}
-
-static inline void mvs_task_free_list(struct mvs_task_list *mvs_list)
-{
- LIST_HEAD(list);
- struct list_head *pos, *a;
- struct mvs_task_list *mlist = NULL;
-
- __list_add(&list, mvs_list->list.prev, &mvs_list->list);
-
- list_for_each_safe(pos, a, &list) {
- list_del_init(pos);
- mlist = list_entry(pos, struct mvs_task_list, list);
- kmem_cache_free(mvs_task_list_cache, mlist);
- }
-}
-
-static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
+static int mvs_task_exec(struct sas_task *task, gfp_t gfp_flags,
struct completion *completion, int is_tmf,
struct mvs_tmf_task *tmf)
{
@@ -912,74 +876,9 @@ static int mvs_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
return rc;
}
-static int mvs_collector_task_exec(struct sas_task *task, const int num, gfp_t gfp_flags,
- struct completion *completion, int is_tmf,
- struct mvs_tmf_task *tmf)
+int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags)
{
- struct domain_device *dev = task->dev;
- struct mvs_prv_info *mpi = dev->port->ha->lldd_ha;
- struct mvs_info *mvi = NULL;
- struct sas_task *t = task;
- struct mvs_task_list *mvs_list = NULL, *a;
- LIST_HEAD(q);
- int pass[2] = {0};
- u32 rc = 0;
- u32 n = num;
- unsigned long flags = 0;
-
- mvs_list = mvs_task_alloc_list(&n, gfp_flags);
- if (n) {
- printk(KERN_ERR "%s: mvs alloc list failed.\n", __func__);
- rc = -ENOMEM;
- goto free_list;
- }
-
- __list_add(&q, mvs_list->list.prev, &mvs_list->list);
-
- list_for_each_entry(a, &q, list) {
- a->task = t;
- t = list_entry(t->list.next, struct sas_task, list);
- }
-
- list_for_each_entry(a, &q , list) {
-
- t = a->task;
- mvi = ((struct mvs_device *)t->dev->lldd_dev)->mvi_info;
-
- spin_lock_irqsave(&mvi->lock, flags);
- rc = mvs_task_prep(t, mvi, is_tmf, tmf, &pass[mvi->id]);
- if (rc)
- dev_printk(KERN_ERR, mvi->dev, "mvsas exec failed[%d]!\n", rc);
- spin_unlock_irqrestore(&mvi->lock, flags);
- }
-
- if (likely(pass[0]))
- MVS_CHIP_DISP->start_delivery(mpi->mvi[0],
- (mpi->mvi[0]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-
- if (likely(pass[1]))
- MVS_CHIP_DISP->start_delivery(mpi->mvi[1],
- (mpi->mvi[1]->tx_prod - 1) & (MVS_CHIP_SLOT_SZ - 1));
-
- list_del_init(&q);
-
-free_list:
- if (mvs_list)
- mvs_task_free_list(mvs_list);
-
- return rc;
-}
-
-int mvs_queue_command(struct sas_task *task, const int num,
- gfp_t gfp_flags)
-{
- struct mvs_device *mvi_dev = task->dev->lldd_dev;
- struct sas_ha_struct *sas = mvi_dev->mvi_info->sas;
-
- if (sas->lldd_max_execute_num < 2)
- return mvs_task_exec(task, num, gfp_flags, NULL, 0, NULL);
- else
- return mvs_collector_task_exec(task, num, gfp_flags, NULL, 0, NULL);
+ return mvs_task_exec(task, gfp_flags, NULL, 0, NULL);
}
static void mvs_slot_free(struct mvs_info *mvi, u32 rx_desc)
@@ -1411,7 +1310,7 @@ static int mvs_exec_internal_tmf_task(struct domain_device *dev,
task->slow_task->timer.expires = jiffies + MVS_TASK_TIMEOUT*HZ;
add_timer(&task->slow_task->timer);
- res = mvs_task_exec(task, 1, GFP_KERNEL, NULL, 1, tmf);
+ res = mvs_task_exec(task, GFP_KERNEL, NULL, 1, tmf);
if (res) {
del_timer(&task->slow_task->timer);
diff --git a/drivers/scsi/mvsas/mv_sas.h b/drivers/scsi/mvsas/mv_sas.h
index d6b19dc..dc409c0 100644
--- a/drivers/scsi/mvsas/mv_sas.h
+++ b/drivers/scsi/mvsas/mv_sas.h
@@ -65,7 +65,6 @@ extern struct mvs_tgt_initiator mvs_tgt;
extern struct mvs_info *tgt_mvi;
extern const struct mvs_dispatch mvs_64xx_dispatch;
extern const struct mvs_dispatch mvs_94xx_dispatch;
-extern struct kmem_cache *mvs_task_list_cache;
#define DEV_IS_EXPANDER(type) \
((type == SAS_EDGE_EXPANDER_DEVICE) || (type == SAS_FANOUT_EXPANDER_DEVICE))
@@ -440,12 +439,6 @@ struct mvs_task_exec_info {
int n_elem;
};
-struct mvs_task_list {
- struct sas_task *task;
- struct list_head list;
-};
-
-
/******************** function prototype *********************/
void mvs_get_sas_addr(void *buf, u32 buflen);
void mvs_tag_clear(struct mvs_info *mvi, u32 tag);
@@ -462,8 +455,7 @@ void mvs_set_sas_addr(struct mvs_info *mvi, int port_id, u32 off_lo,
u32 off_hi, u64 sas_addr);
void mvs_scan_start(struct Scsi_Host *shost);
int mvs_scan_finished(struct Scsi_Host *shost, unsigned long time);
-int mvs_queue_command(struct sas_task *task, const int num,
- gfp_t gfp_flags);
+int mvs_queue_command(struct sas_task *task, gfp_t gfp_flags);
int mvs_abort_task(struct sas_task *task);
int mvs_abort_task_set(struct domain_device *dev, u8 *lun);
int mvs_clear_aca(struct domain_device *dev, u8 *lun);
diff --git a/drivers/scsi/ncr53c8xx.c b/drivers/scsi/ncr53c8xx.c
index a7305ff..5b93ed8 100644
--- a/drivers/scsi/ncr53c8xx.c
+++ b/drivers/scsi/ncr53c8xx.c
@@ -7997,10 +7997,7 @@ static int ncr53c8xx_slave_configure(struct scsi_device *device)
if (depth_to_use > MAX_TAGS)
depth_to_use = MAX_TAGS;
- scsi_adjust_queue_depth(device,
- (device->tagged_supported ?
- MSG_SIMPLE_TAG : 0),
- depth_to_use);
+ scsi_change_queue_depth(device, depth_to_use);
/*
** Since the queue depth is not tunable under Linux,
diff --git a/drivers/scsi/osd/osd_uld.c b/drivers/scsi/osd/osd_uld.c
index 92cdd4b..243eab3 100644
--- a/drivers/scsi/osd/osd_uld.c
+++ b/drivers/scsi/osd/osd_uld.c
@@ -540,9 +540,9 @@ static int osd_remove(struct device *dev)
*/
static struct scsi_driver osd_driver = {
- .owner = THIS_MODULE,
.gendrv = {
.name = osd_name,
+ .owner = THIS_MODULE,
.probe = osd_probe,
.remove = osd_remove,
}
diff --git a/drivers/scsi/osst.c b/drivers/scsi/osst.c
index dff37a25..5033223 100644
--- a/drivers/scsi/osst.c
+++ b/drivers/scsi/osst.c
@@ -172,9 +172,9 @@ static int osst_probe(struct device *);
static int osst_remove(struct device *);
static struct scsi_driver osst_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "osst",
+ .owner = THIS_MODULE,
.probe = osst_probe,
.remove = osst_remove,
}
@@ -259,9 +259,10 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
if (scode) printk(OSST_DEB_MSG "%s:D: Sense: %02x, ASC: %02x, ASCQ: %02x\n",
- name, scode, sense[12], sense[13]);
+ name, scode, sense[12], sense[13]);
if (cmdstatp->have_sense)
- __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(STp->device, name,
+ SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
else
#endif
@@ -275,7 +276,8 @@ static int osst_chk_result(struct osst_tape * STp, struct osst_request * SRpnt)
SRpnt->cmd[0] != TEST_UNIT_READY)) { /* Abnormal conditions for tape */
if (cmdstatp->have_sense) {
printk(KERN_WARNING "%s:W: Command with sense data:\n", name);
- __scsi_print_sense("osst ", SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(STp->device, name,
+ SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
else {
static int notyetprinted = 1;
@@ -3325,19 +3327,18 @@ static int osst_write_frame(struct osst_tape * STp, struct osst_request ** aSRpn
/* Lock or unlock the drive door. Don't use when struct osst_request allocated. */
static int do_door_lock(struct osst_tape * STp, int do_lock)
{
- int retval, cmd;
+ int retval;
- cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
#if DEBUG
printk(OSST_DEB_MSG "%s:D: %socking drive door.\n", tape_name(STp), do_lock ? "L" : "Unl");
#endif
- retval = scsi_ioctl(STp->device, cmd, NULL);
- if (!retval) {
+
+ retval = scsi_set_medium_removal(STp->device,
+ do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
+ if (!retval)
STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
- }
- else {
+ else
STp->door_locked = ST_LOCK_FAILS;
- }
return retval;
}
@@ -4967,10 +4968,10 @@ static long osst_ioctl(struct file * file,
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- if( !scsi_block_when_processing_errors(STp->device) ) {
- retval = (-ENXIO);
+ retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
+ file->f_flags & O_NDELAY);
+ if (retval)
goto out;
- }
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
index 80bacb5..e81eadd 100644
--- a/drivers/scsi/pas16.c
+++ b/drivers/scsi/pas16.c
@@ -1,6 +1,4 @@
-#define AUTOSENSE
#define PSEUDO_DMA
-#define FOO
#define UNSAFE /* Not unsafe for PAS16 -- use it */
#define PDEBUG 0
@@ -24,47 +22,9 @@
* Media Vision
* (510) 770-8600
* (800) 348-7116
- *
- * and
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
/*
- * Options :
- * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
- *
- * LIMIT_TRANSFERSIZE - if defined, limit the pseudo-dma transfers to 512
- * bytes at a time. Since interrupts are disabled by default during
- * these transfers, we might need this to give reasonable interrupt
- * service time if the transfer size gets too large.
- *
- * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
- * increase compared to polled I/O.
- *
- * PARITY - enable parity checking. Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. This
- * parameter comes from the NCR5380 code. It is NOT unsafe with
- * the PAS16 and you should use it. If you don't you will have
- * a problem with dropped characters during high speed
- * communications during SCSI transfers. If you really don't
- * want to use UNSAFE you can try defining LIMIT_TRANSFERSIZE or
- * twiddle with the transfer size in the high level code.
- *
- * USLEEP - enable support for devices that don't disconnect. Untested.
- *
* The card is detected and initialized in one of several ways :
* 1. Autoprobe (default) - There are many different models of
* the Pro Audio Spectrum/Studio 16, and I only have one of
@@ -102,13 +62,11 @@
* If you have problems with your card not being recognized, use
* the LILO command line override. Try to get it recognized without
* interrupts. Ie, for a board at the default 0x388 base port,
- * boot: linux pas16=0x388,255
+ * boot: linux pas16=0x388,0
*
- * SCSI_IRQ_NONE (255) should be specified for no interrupt,
+ * NO_IRQ (0) should be specified for no interrupt,
* IRQ_AUTO (254) to autoprobe for an IRQ line if overridden
* on the command line.
- *
- * (IRQ_AUTO == 254, SCSI_IRQ_NONE == 255 in NCR5380.h)
*/
#include <linux/module.h>
@@ -123,15 +81,12 @@
#include <linux/stat.h>
#include <linux/init.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include "pas16.h"
#define AUTOPROBE_IRQ
#include "NCR5380.h"
-static int pas_maxi = 0;
-static int pas_wmaxi = 0;
static unsigned short pas16_addr = 0;
static int pas16_irq = 0;
@@ -337,6 +292,7 @@ static int __init
}
+#ifndef MODULE
/*
* Function : pas16_setup(char *str, int *ints)
*
@@ -347,10 +303,13 @@ static int __init
*
*/
-void __init pas16_setup(char *str, int *ints)
+static int __init pas16_setup(char *str)
{
static int commandline_current = 0;
int i;
+ int ints[10];
+
+ get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] != 2)
printk("pas16_setup : usage pas16=io_port,irq\n");
else
@@ -364,8 +323,12 @@ void __init pas16_setup(char *str, int *ints)
}
++commandline_current;
}
+ return 1;
}
+__setup("pas16=", pas16_setup);
+#endif
+
/*
* Function : int pas16_detect(struct scsi_host_template * tpnt)
*
@@ -379,7 +342,7 @@ void __init pas16_setup(char *str, int *ints)
*
*/
-int __init pas16_detect(struct scsi_host_template * tpnt)
+static int __init pas16_detect(struct scsi_host_template *tpnt)
{
static int current_override = 0;
static unsigned short current_base = 0;
@@ -387,10 +350,6 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
unsigned short io_port;
int count;
- tpnt->proc_name = "pas16";
- tpnt->show_info = pas16_show_info;
- tpnt->write_info = pas16_write_info;
-
if (pas16_addr != 0) {
overrides[0].io_port = pas16_addr;
/*
@@ -452,15 +411,19 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
else
instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
- if (instance->irq != SCSI_IRQ_NONE)
+ /* Compatibility with documented NCR5380 kernel parameters */
+ if (instance->irq == 255)
+ instance->irq = NO_IRQ;
+
+ if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, pas16_intr, 0,
"pas16", instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
+ instance->irq = NO_IRQ;
}
- if (instance->irq == SCSI_IRQ_NONE) {
+ if (instance->irq == NO_IRQ) {
printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
/* Disable 5380 interrupts, leave drive params the same */
@@ -472,17 +435,6 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
#endif
- printk("scsi%d : at 0x%04x", instance->host_no, (int)
- instance->io_port);
- if (instance->irq == SCSI_IRQ_NONE)
- printk (" interrupts disabled");
- else
- printk (" irq %d", instance->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
- NCR5380_print_options(instance);
- printk("\n");
-
++current_override;
++count;
}
@@ -509,8 +461,8 @@ int __init pas16_detect(struct scsi_host_template * tpnt)
* and matching the H_C_S coordinates to what DOS uses.
*/
-int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev,
- sector_t capacity, int * ip)
+static int pas16_biosparam(struct scsi_device *sdev, struct block_device *dev,
+ sector_t capacity, int *ip)
{
int size = capacity;
ip[0] = 64;
@@ -547,6 +499,7 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
P_DATA_REG_OFFSET);
register int i = len;
int ii = 0;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
while ( !(inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY) )
++ii;
@@ -559,8 +512,8 @@ static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
instance->host_no);
return -1;
}
- if (ii > pas_maxi)
- pas_maxi = ii;
+ if (ii > hostdata->spin_max_r)
+ hostdata->spin_max_r = ii;
return 0;
}
@@ -583,6 +536,7 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
register int i = len;
int ii = 0;
+ struct NCR5380_hostdata *hostdata = shost_priv(instance);
while ( !((inb(instance->io_port + P_STATUS_REG_OFFSET)) & P_ST_RDY) )
++ii;
@@ -595,8 +549,8 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
instance->host_no);
return -1;
}
- if (ii > pas_maxi)
- pas_wmaxi = ii;
+ if (ii > hostdata->spin_max_w)
+ hostdata->spin_max_w = ii;
return 0;
}
@@ -604,7 +558,7 @@ static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src
static int pas16_release(struct Scsi_Host *shost)
{
- if (shost->irq)
+ if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
if (shost->io_port && shost->n_io_port)
@@ -617,6 +571,10 @@ static struct scsi_host_template driver_template = {
.name = "Pro Audio Spectrum-16 SCSI",
.detect = pas16_detect,
.release = pas16_release,
+ .proc_name = "pas16",
+ .show_info = pas16_show_info,
+ .write_info = pas16_write_info,
+ .info = pas16_info,
.queuecommand = pas16_queue_command,
.eh_abort_handler = pas16_abort,
.eh_bus_reset_handler = pas16_bus_reset,
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
index aa528f5..c6109c8 100644
--- a/drivers/scsi/pas16.h
+++ b/drivers/scsi/pas16.h
@@ -18,26 +18,12 @@
* Media Vision
* (510) 770-8600
* (800) 348-7116
- *
- * and
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
#ifndef PAS16_H
#define PAS16_H
-#define PAS16_PUBLIC_RELEASE 3
-
#define PDEBUG_INIT 0x1
#define PDEBUG_TRANSFER 0x2
@@ -114,12 +100,6 @@
#ifndef ASM
-static int pas16_abort(Scsi_Cmnd *);
-static int pas16_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int*);
-static int pas16_detect(struct scsi_host_template *);
-static int pas16_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int pas16_bus_reset(Scsi_Cmnd *);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
@@ -161,6 +141,7 @@ static int pas16_bus_reset(Scsi_Cmnd *);
#define NCR5380_queue_command pas16_queue_command
#define NCR5380_abort pas16_abort
#define NCR5380_bus_reset pas16_bus_reset
+#define NCR5380_info pas16_info
#define NCR5380_show_info pas16_show_info
#define NCR5380_write_info pas16_write_info
diff --git a/drivers/scsi/pm8001/pm8001_init.c b/drivers/scsi/pm8001/pm8001_init.c
index 666bf5a..329aba0 100644
--- a/drivers/scsi/pm8001/pm8001_init.c
+++ b/drivers/scsi/pm8001/pm8001_init.c
@@ -89,6 +89,8 @@ static struct scsi_host_template pm8001_sht = {
.target_destroy = sas_target_destroy,
.ioctl = sas_ioctl,
.shost_attrs = pm8001_host_attrs,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
/**
@@ -599,8 +601,6 @@ static void pm8001_post_sas_ha_init(struct Scsi_Host *shost,
sha->lldd_module = THIS_MODULE;
sha->sas_addr = &pm8001_ha->sas_addr[0];
sha->num_phys = chip_info->n_phy;
- sha->lldd_max_execute_num = 1;
- sha->lldd_queue_size = PM8001_CAN_QUEUE;
sha->core.shost = shost;
}
diff --git a/drivers/scsi/pm8001/pm8001_sas.c b/drivers/scsi/pm8001/pm8001_sas.c
index 76570e6..b93f289 100644
--- a/drivers/scsi/pm8001/pm8001_sas.c
+++ b/drivers/scsi/pm8001/pm8001_sas.c
@@ -350,7 +350,7 @@ static int sas_find_local_port_id(struct domain_device *dev)
*/
#define DEV_IS_GONE(pm8001_dev) \
((!pm8001_dev || (pm8001_dev->dev_type == SAS_PHY_UNUSED)))
-static int pm8001_task_exec(struct sas_task *task, const int num,
+static int pm8001_task_exec(struct sas_task *task,
gfp_t gfp_flags, int is_tmf, struct pm8001_tmf_task *tmf)
{
struct domain_device *dev = task->dev;
@@ -360,7 +360,6 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
struct sas_task *t = task;
struct pm8001_ccb_info *ccb;
u32 tag = 0xdeadbeef, rc, n_elem = 0;
- u32 n = num;
unsigned long flags = 0;
if (!dev->port) {
@@ -387,18 +386,12 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
spin_unlock_irqrestore(&pm8001_ha->lock, flags);
t->task_done(t);
spin_lock_irqsave(&pm8001_ha->lock, flags);
- if (n > 1)
- t = list_entry(t->list.next,
- struct sas_task, list);
continue;
} else {
struct task_status_struct *ts = &t->task_status;
ts->resp = SAS_TASK_UNDELIVERED;
ts->stat = SAS_PHY_DOWN;
t->task_done(t);
- if (n > 1)
- t = list_entry(t->list.next,
- struct sas_task, list);
continue;
}
}
@@ -460,9 +453,7 @@ static int pm8001_task_exec(struct sas_task *task, const int num,
t->task_state_flags |= SAS_TASK_AT_INITIATOR;
spin_unlock(&t->task_state_lock);
pm8001_dev->running_req++;
- if (n > 1)
- t = list_entry(t->list.next, struct sas_task, list);
- } while (--n);
+ } while (0);
rc = 0;
goto out_done;
@@ -483,14 +474,11 @@ out_done:
* pm8001_queue_command - register for upper layer used, all IO commands sent
* to HBA are from this interface.
* @task: the task to be execute.
- * @num: if can_queue great than 1, the task can be queued up. for SMP task,
- * we always execute one one time
* @gfp_flags: gfp_flags
*/
-int pm8001_queue_command(struct sas_task *task, const int num,
- gfp_t gfp_flags)
+int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags)
{
- return pm8001_task_exec(task, num, gfp_flags, 0, NULL);
+ return pm8001_task_exec(task, gfp_flags, 0, NULL);
}
/**
@@ -708,7 +696,7 @@ static int pm8001_exec_internal_tmf_task(struct domain_device *dev,
task->slow_task->timer.expires = jiffies + PM8001_TASK_TIMEOUT*HZ;
add_timer(&task->slow_task->timer);
- res = pm8001_task_exec(task, 1, GFP_KERNEL, 1, tmf);
+ res = pm8001_task_exec(task, GFP_KERNEL, 1, tmf);
if (res) {
del_timer(&task->slow_task->timer);
diff --git a/drivers/scsi/pm8001/pm8001_sas.h b/drivers/scsi/pm8001/pm8001_sas.h
index f6b2ac5..8dd8b78 100644
--- a/drivers/scsi/pm8001/pm8001_sas.h
+++ b/drivers/scsi/pm8001/pm8001_sas.h
@@ -623,8 +623,7 @@ int pm8001_phy_control(struct asd_sas_phy *sas_phy, enum phy_func func,
void *funcdata);
void pm8001_scan_start(struct Scsi_Host *shost);
int pm8001_scan_finished(struct Scsi_Host *shost, unsigned long time);
-int pm8001_queue_command(struct sas_task *task, const int num,
- gfp_t gfp_flags);
+int pm8001_queue_command(struct sas_task *task, gfp_t gfp_flags);
int pm8001_abort_task(struct sas_task *task);
int pm8001_abort_task_set(struct domain_device *dev, u8 *lun);
int pm8001_clear_aca(struct domain_device *dev, u8 *lun);
diff --git a/drivers/scsi/pmcraid.c b/drivers/scsi/pmcraid.c
index bcb64eb..b1b1f66 100644
--- a/drivers/scsi/pmcraid.c
+++ b/drivers/scsi/pmcraid.c
@@ -249,15 +249,11 @@ static int pmcraid_slave_configure(struct scsi_device *scsi_dev)
PMCRAID_VSET_MAX_SECTORS);
}
- if (scsi_dev->tagged_supported &&
- (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) {
- scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
- scsi_adjust_queue_depth(scsi_dev, MSG_SIMPLE_TAG,
- scsi_dev->host->cmd_per_lun);
- } else {
- scsi_adjust_queue_depth(scsi_dev, 0,
- scsi_dev->host->cmd_per_lun);
- }
+ /*
+ * We never want to report TCQ support for these types of devices.
+ */
+ if (!RES_IS_GSCSI(res->cfg_entry) && !RES_IS_VSET(res->cfg_entry))
+ scsi_dev->tagged_supported = 0;
return 0;
}
@@ -289,55 +285,18 @@ static void pmcraid_slave_destroy(struct scsi_device *scsi_dev)
* pmcraid_change_queue_depth - Change the device's queue depth
* @scsi_dev: scsi device struct
* @depth: depth to set
- * @reason: calling context
*
* Return value
* actual depth set
*/
-static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth,
- int reason)
+static int pmcraid_change_queue_depth(struct scsi_device *scsi_dev, int depth)
{
- if (reason != SCSI_QDEPTH_DEFAULT)
- return -EOPNOTSUPP;
-
if (depth > PMCRAID_MAX_CMD_PER_LUN)
depth = PMCRAID_MAX_CMD_PER_LUN;
-
- scsi_adjust_queue_depth(scsi_dev, scsi_get_tag_type(scsi_dev), depth);
-
- return scsi_dev->queue_depth;
+ return scsi_change_queue_depth(scsi_dev, depth);
}
/**
- * pmcraid_change_queue_type - Change the device's queue type
- * @scsi_dev: scsi device struct
- * @tag: type of tags to use
- *
- * Return value:
- * actual queue type set
- */
-static int pmcraid_change_queue_type(struct scsi_device *scsi_dev, int tag)
-{
- struct pmcraid_resource_entry *res;
-
- res = (struct pmcraid_resource_entry *)scsi_dev->hostdata;
-
- if ((res) && scsi_dev->tagged_supported &&
- (RES_IS_GSCSI(res->cfg_entry) || RES_IS_VSET(res->cfg_entry))) {
- scsi_set_tag_type(scsi_dev, tag);
-
- if (tag)
- scsi_activate_tcq(scsi_dev, scsi_dev->queue_depth);
- else
- scsi_deactivate_tcq(scsi_dev, scsi_dev->queue_depth);
- } else
- tag = 0;
-
- return tag;
-}
-
-
-/**
* pmcraid_init_cmdblk - initializes a command block
*
* @cmd: pointer to struct pmcraid_cmd to be initialized
@@ -3175,36 +3134,6 @@ static int pmcraid_eh_host_reset_handler(struct scsi_cmnd *scmd)
}
/**
- * pmcraid_task_attributes - Translate SPI Q-Tags to task attributes
- * @scsi_cmd: scsi command struct
- *
- * Return value
- * number of tags or 0 if the task is not tagged
- */
-static u8 pmcraid_task_attributes(struct scsi_cmnd *scsi_cmd)
-{
- char tag[2];
- u8 rc = 0;
-
- if (scsi_populate_tag_msg(scsi_cmd, tag)) {
- switch (tag[0]) {
- case MSG_SIMPLE_TAG:
- rc = TASK_TAG_SIMPLE;
- break;
- case MSG_HEAD_TAG:
- rc = TASK_TAG_QUEUE_HEAD;
- break;
- case MSG_ORDERED_TAG:
- rc = TASK_TAG_ORDERED;
- break;
- };
- }
-
- return rc;
-}
-
-
-/**
* pmcraid_init_ioadls - initializes IOADL related fields in IOARCB
* @cmd: pmcraid command struct
* @sgcount: count of scatter-gather elements
@@ -3559,7 +3488,9 @@ static int pmcraid_queuecommand_lck(
}
ioarcb->request_flags0 |= NO_LINK_DESCS;
- ioarcb->request_flags1 |= pmcraid_task_attributes(scsi_cmd);
+
+ if (scsi_cmd->flags & SCMD_TAGGED)
+ ioarcb->request_flags1 |= TASK_TAG_SIMPLE;
if (RES_IS_GSCSI(res->cfg_entry))
ioarcb->request_flags1 |= DELAY_AFTER_RESET;
@@ -4320,7 +4251,7 @@ static struct scsi_host_template pmcraid_host_template = {
.slave_configure = pmcraid_slave_configure,
.slave_destroy = pmcraid_slave_destroy,
.change_queue_depth = pmcraid_change_queue_depth,
- .change_queue_type = pmcraid_change_queue_type,
+ .change_queue_type = scsi_change_queue_type,
.can_queue = PMCRAID_MAX_IO_CMD,
.this_id = -1,
.sg_tablesize = PMCRAID_MAX_IOADLS,
@@ -4329,7 +4260,8 @@ static struct scsi_host_template pmcraid_host_template = {
.cmd_per_lun = PMCRAID_MAX_CMD_PER_LUN,
.use_clustering = ENABLE_CLUSTERING,
.shost_attrs = pmcraid_host_attrs,
- .proc_name = PMCRAID_DRIVER_NAME
+ .proc_name = PMCRAID_DRIVER_NAME,
+ .use_blk_tags = 1,
};
/*
diff --git a/drivers/scsi/ps3rom.c b/drivers/scsi/ps3rom.c
index ef23fab..b3b48b5 100644
--- a/drivers/scsi/ps3rom.c
+++ b/drivers/scsi/ps3rom.c
@@ -220,10 +220,6 @@ static int ps3rom_queuecommand_lck(struct scsi_cmnd *cmd,
unsigned char opcode;
int res;
-#ifdef DEBUG
- scsi_print_command(cmd);
-#endif
-
priv->curr_cmd = cmd;
cmd->scsi_done = done;
diff --git a/drivers/scsi/qla1280.c b/drivers/scsi/qla1280.c
index 1580205..c68a66e 100644
--- a/drivers/scsi/qla1280.c
+++ b/drivers/scsi/qla1280.c
@@ -1224,10 +1224,9 @@ qla1280_slave_configure(struct scsi_device *device)
if (device->tagged_supported &&
(ha->bus_settings[bus].qtag_enables & (BIT_0 << target))) {
- scsi_adjust_queue_depth(device, MSG_ORDERED_TAG,
- ha->bus_settings[bus].hiwat);
+ scsi_change_queue_depth(device, ha->bus_settings[bus].hiwat);
} else {
- scsi_adjust_queue_depth(device, 0, default_depth);
+ scsi_change_queue_depth(device, default_depth);
}
nv->bus[bus].target[target].parameter.enable_sync = device->sdtr;
diff --git a/drivers/scsi/qla2xxx/qla_gbl.h b/drivers/scsi/qla2xxx/qla_gbl.h
index b1865a7..7686bfe 100644
--- a/drivers/scsi/qla2xxx/qla_gbl.h
+++ b/drivers/scsi/qla2xxx/qla_gbl.h
@@ -752,8 +752,6 @@ extern void qla8044_set_idc_dontreset(struct scsi_qla_host *ha);
extern int qla8044_rd_direct(struct scsi_qla_host *vha, const uint32_t crb_reg);
extern void qla8044_wr_direct(struct scsi_qla_host *vha,
const uint32_t crb_reg, const uint32_t value);
-extern inline void qla8044_set_qsnt_ready(struct scsi_qla_host *vha);
-extern inline void qla8044_need_reset_handler(struct scsi_qla_host *vha);
extern int qla8044_device_state_handler(struct scsi_qla_host *vha);
extern void qla8044_clear_qsnt_ready(struct scsi_qla_host *vha);
extern void qla8044_clear_drv_active(struct qla_hw_data *);
diff --git a/drivers/scsi/qla2xxx/qla_iocb.c b/drivers/scsi/qla2xxx/qla_iocb.c
index f0edb07..a1ab25f 100644
--- a/drivers/scsi/qla2xxx/qla_iocb.c
+++ b/drivers/scsi/qla2xxx/qla_iocb.c
@@ -325,7 +325,6 @@ qla2x00_start_scsi(srb_t *sp)
struct qla_hw_data *ha;
struct req_que *req;
struct rsp_que *rsp;
- char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -404,26 +403,7 @@ qla2x00_start_scsi(srb_t *sp)
/* Set target ID and LUN number*/
SET_TARGET_ID(ha, cmd_pkt->target, sp->fcport->loop_id);
cmd_pkt->lun = cpu_to_le16(cmd->device->lun);
-
- /* Update tagged queuing modifier */
- if (scsi_populate_tag_msg(cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- cmd_pkt->control_flags =
- __constant_cpu_to_le16(CF_HEAD_TAG);
- break;
- case ORDERED_QUEUE_TAG:
- cmd_pkt->control_flags =
- __constant_cpu_to_le16(CF_ORDERED_TAG);
- break;
- default:
- cmd_pkt->control_flags =
- __constant_cpu_to_le16(CF_SIMPLE_TAG);
- break;
- }
- } else {
- cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
- }
+ cmd_pkt->control_flags = __constant_cpu_to_le16(CF_SIMPLE_TAG);
/* Load SCSI command packet. */
memcpy(cmd_pkt->scsi_cdb, cmd->cmnd, cmd->cmd_len);
@@ -1264,7 +1244,6 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
uint16_t fcp_cmnd_len;
struct fcp_cmnd *fcp_cmnd;
dma_addr_t crc_ctx_dma;
- char tag[2];
cmd = GET_CMD_SP(sp);
@@ -1356,25 +1335,7 @@ qla24xx_build_scsi_crc_2_iocbs(srb_t *sp, struct cmd_type_crc_2 *cmd_pkt,
cmd_pkt->fcp_cmnd_dseg_address[1] = cpu_to_le32(
MSD(crc_ctx_dma + CRC_CONTEXT_FCPCMND_OFF));
fcp_cmnd->task_management = 0;
-
- /*
- * Update tagged queuing modifier if using command tag queuing
- */
- if (scsi_populate_tag_msg(cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- fcp_cmnd->task_attribute = TSK_HEAD_OF_QUEUE;
- break;
- case ORDERED_QUEUE_TAG:
- fcp_cmnd->task_attribute = TSK_ORDERED;
- break;
- default:
- fcp_cmnd->task_attribute = TSK_SIMPLE;
- break;
- }
- } else {
- fcp_cmnd->task_attribute = TSK_SIMPLE;
- }
+ fcp_cmnd->task_attribute = TSK_SIMPLE;
cmd_pkt->fcp_rsp_dseg_len = 0; /* Let response come in status iocb */
@@ -1495,7 +1456,6 @@ qla24xx_start_scsi(srb_t *sp)
struct scsi_cmnd *cmd = GET_CMD_SP(sp);
struct scsi_qla_host *vha = sp->fcport->vha;
struct qla_hw_data *ha = vha->hw;
- char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -1578,22 +1538,7 @@ qla24xx_start_scsi(srb_t *sp)
int_to_scsilun(cmd->device->lun, &cmd_pkt->lun);
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun, sizeof(cmd_pkt->lun));
- /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */
- if (scsi_populate_tag_msg(cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- cmd_pkt->task = TSK_HEAD_OF_QUEUE;
- break;
- case ORDERED_QUEUE_TAG:
- cmd_pkt->task = TSK_ORDERED;
- break;
- default:
- cmd_pkt->task = TSK_SIMPLE;
- break;
- }
- } else {
- cmd_pkt->task = TSK_SIMPLE;
- }
+ cmd_pkt->task = TSK_SIMPLE;
/* Load SCSI command packet. */
memcpy(cmd_pkt->fcp_cdb, cmd->cmnd, cmd->cmd_len);
@@ -2310,7 +2255,6 @@ qla82xx_start_scsi(srb_t *sp)
struct qla_hw_data *ha = vha->hw;
struct req_que *req = NULL;
struct rsp_que *rsp = NULL;
- char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -2489,22 +2433,6 @@ sufficient_dsds:
else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
ctx->fcp_cmnd->additional_cdb_len |= 2;
- /*
- * Update tagged queuing modifier -- default is TSK_SIMPLE (0).
- */
- if (scsi_populate_tag_msg(cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- ctx->fcp_cmnd->task_attribute =
- TSK_HEAD_OF_QUEUE;
- break;
- case ORDERED_QUEUE_TAG:
- ctx->fcp_cmnd->task_attribute =
- TSK_ORDERED;
- break;
- }
- }
-
/* Populate the FCP_PRIO. */
if (ha->flags.fcp_prio_enabled)
ctx->fcp_cmnd->task_attribute |=
@@ -2565,20 +2493,6 @@ sufficient_dsds:
host_to_fcp_swap((uint8_t *)&cmd_pkt->lun,
sizeof(cmd_pkt->lun));
- /*
- * Update tagged queuing modifier -- default is TSK_SIMPLE (0).
- */
- if (scsi_populate_tag_msg(cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- cmd_pkt->task = TSK_HEAD_OF_QUEUE;
- break;
- case ORDERED_QUEUE_TAG:
- cmd_pkt->task = TSK_ORDERED;
- break;
- }
- }
-
/* Populate the FCP_PRIO. */
if (ha->flags.fcp_prio_enabled)
cmd_pkt->task |= sp->fcport->fcp_prio << 3;
diff --git a/drivers/scsi/qla2xxx/qla_mr.c b/drivers/scsi/qla2xxx/qla_mr.c
index 8086759..6d190b4 100644
--- a/drivers/scsi/qla2xxx/qla_mr.c
+++ b/drivers/scsi/qla2xxx/qla_mr.c
@@ -3086,7 +3086,6 @@ qlafx00_start_scsi(srb_t *sp)
struct cmd_type_7_fx00 *cmd_pkt;
struct cmd_type_7_fx00 lcmd_pkt;
struct scsi_lun llun;
- char tag[2];
/* Setup device pointers. */
ret = 0;
@@ -3157,18 +3156,6 @@ qlafx00_start_scsi(srb_t *sp)
host_to_adap((uint8_t *)&llun, (uint8_t *)&lcmd_pkt.lun,
sizeof(lcmd_pkt.lun));
- /* Update tagged queuing modifier -- default is TSK_SIMPLE (0). */
- if (scsi_populate_tag_msg(cmd, tag)) {
- switch (tag[0]) {
- case HEAD_OF_QUEUE_TAG:
- lcmd_pkt.task = TSK_HEAD_OF_QUEUE;
- break;
- case ORDERED_QUEUE_TAG:
- lcmd_pkt.task = TSK_ORDERED;
- break;
- }
- }
-
/* Load SCSI command packet. */
host_to_adap(cmd->cmnd, lcmd_pkt.fcp_cdb, sizeof(lcmd_pkt.fcp_cdb));
lcmd_pkt.byte_count = cpu_to_le32((uint32_t)scsi_bufflen(cmd));
diff --git a/drivers/scsi/qla2xxx/qla_nx2.c b/drivers/scsi/qla2xxx/qla_nx2.c
index 24a8528..ed4d6b6 100644
--- a/drivers/scsi/qla2xxx/qla_nx2.c
+++ b/drivers/scsi/qla2xxx/qla_nx2.c
@@ -238,7 +238,7 @@ qla8044_rmw_crb_reg(struct scsi_qla_host *vha,
return;
}
-inline void
+static inline void
qla8044_set_qsnt_ready(struct scsi_qla_host *vha)
{
uint32_t qsnt_state;
diff --git a/drivers/scsi/qla2xxx/qla_os.c b/drivers/scsi/qla2xxx/qla_os.c
index db3dbd9..6b4d923 100644
--- a/drivers/scsi/qla2xxx/qla_os.c
+++ b/drivers/scsi/qla2xxx/qla_os.c
@@ -236,8 +236,6 @@ static int qla2xxx_eh_target_reset(struct scsi_cmnd *);
static int qla2xxx_eh_bus_reset(struct scsi_cmnd *);
static int qla2xxx_eh_host_reset(struct scsi_cmnd *);
-static int qla2x00_change_queue_depth(struct scsi_device *, int, int);
-static int qla2x00_change_queue_type(struct scsi_device *, int);
static void qla2x00_clear_drv_active(struct qla_hw_data *);
static void qla2x00_free_device(scsi_qla_host_t *);
static void qla83xx_disable_laser(scsi_qla_host_t *vha);
@@ -259,8 +257,8 @@ struct scsi_host_template qla2xxx_driver_template = {
.slave_destroy = qla2xxx_slave_destroy,
.scan_finished = qla2xxx_scan_finished,
.scan_start = qla2xxx_scan_start,
- .change_queue_depth = qla2x00_change_queue_depth,
- .change_queue_type = qla2x00_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
.this_id = -1,
.cmd_per_lun = 3,
.use_clustering = ENABLE_CLUSTERING,
@@ -270,6 +268,8 @@ struct scsi_host_template qla2xxx_driver_template = {
.shost_attrs = qla2x00_host_attrs,
.supported_mode = MODE_INITIATOR,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static struct scsi_transport_template *qla2xxx_transport_template = NULL;
@@ -1405,10 +1405,7 @@ qla2xxx_slave_configure(struct scsi_device *sdev)
if (IS_T10_PI_CAPABLE(vha->hw))
blk_queue_update_dma_alignment(sdev->request_queue, 0x7);
- if (sdev->tagged_supported)
- scsi_activate_tcq(sdev, req->max_q_depth);
- else
- scsi_deactivate_tcq(sdev, req->max_q_depth);
+ scsi_change_queue_depth(sdev, req->max_q_depth);
return 0;
}
@@ -1418,76 +1415,6 @@ qla2xxx_slave_destroy(struct scsi_device *sdev)
sdev->hostdata = NULL;
}
-static void qla2x00_handle_queue_full(struct scsi_device *sdev, int qdepth)
-{
- fc_port_t *fcport = (struct fc_port *) sdev->hostdata;
-
- if (!scsi_track_queue_full(sdev, qdepth))
- return;
-
- ql_dbg(ql_dbg_io, fcport->vha, 0x3029,
- "Queue depth adjusted-down to %d for nexus=%ld:%d:%llu.\n",
- sdev->queue_depth, fcport->vha->host_no, sdev->id, sdev->lun);
-}
-
-static void qla2x00_adjust_sdev_qdepth_up(struct scsi_device *sdev, int qdepth)
-{
- fc_port_t *fcport = sdev->hostdata;
- struct scsi_qla_host *vha = fcport->vha;
- struct req_que *req = NULL;
-
- req = vha->req;
- if (!req)
- return;
-
- if (req->max_q_depth <= sdev->queue_depth || req->max_q_depth < qdepth)
- return;
-
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, qdepth);
- else
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, qdepth);
-
- ql_dbg(ql_dbg_io, vha, 0x302a,
- "Queue depth adjusted-up to %d for nexus=%ld:%d:%llu.\n",
- sdev->queue_depth, fcport->vha->host_no, sdev->id, sdev->lun);
-}
-
-static int
-qla2x00_change_queue_depth(struct scsi_device *sdev, int qdepth, int reason)
-{
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- break;
- case SCSI_QDEPTH_QFULL:
- qla2x00_handle_queue_full(sdev, qdepth);
- break;
- case SCSI_QDEPTH_RAMP_UP:
- qla2x00_adjust_sdev_qdepth_up(sdev, qdepth);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return sdev->queue_depth;
-}
-
-static int
-qla2x00_change_queue_type(struct scsi_device *sdev, int tag_type)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag_type);
- if (tag_type)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag_type = 0;
-
- return tag_type;
-}
-
/**
* qla2x00_config_dma_addressing() - Configure OS DMA addressing method.
* @ha: HA context
diff --git a/drivers/scsi/qla4xxx/ql4_iocb.c b/drivers/scsi/qla4xxx/ql4_iocb.c
index 08ab6da..17222eb 100644
--- a/drivers/scsi/qla4xxx/ql4_iocb.c
+++ b/drivers/scsi/qla4xxx/ql4_iocb.c
@@ -280,7 +280,6 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
uint16_t req_cnt;
unsigned long flags;
uint32_t index;
- char tag[2];
/* Get real lun and adapter */
ddb_entry = srb->ddb;
@@ -352,15 +351,6 @@ int qla4xxx_send_command_to_isp(struct scsi_qla_host *ha, struct srb * srb)
/* Set tagged queueing control flags */
cmd_entry->control_flags |= CF_SIMPLE_TAG;
- if (scsi_populate_tag_msg(cmd, tag))
- switch (tag[0]) {
- case MSG_HEAD_TAG:
- cmd_entry->control_flags |= CF_HEAD_TAG;
- break;
- case MSG_ORDERED_TAG:
- cmd_entry->control_flags |= CF_ORDERED_TAG;
- break;
- }
qla4xxx_advance_req_ring_ptr(ha);
qla4xxx_build_scsi_iocbs(srb, cmd_entry, tot_dsds);
diff --git a/drivers/scsi/qla4xxx/ql4_os.c b/drivers/scsi/qla4xxx/ql4_os.c
index 199fcf7..6d25879 100644
--- a/drivers/scsi/qla4xxx/ql4_os.c
+++ b/drivers/scsi/qla4xxx/ql4_os.c
@@ -162,12 +162,8 @@ static int qla4xxx_eh_device_reset(struct scsi_cmnd *cmd);
static int qla4xxx_eh_target_reset(struct scsi_cmnd *cmd);
static int qla4xxx_eh_host_reset(struct scsi_cmnd *cmd);
static int qla4xxx_slave_alloc(struct scsi_device *device);
-static int qla4xxx_slave_configure(struct scsi_device *device);
-static void qla4xxx_slave_destroy(struct scsi_device *sdev);
static umode_t qla4_attr_is_visible(int param_type, int param);
static int qla4xxx_host_reset(struct Scsi_Host *shost, int reset_type);
-static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason);
/*
* iSCSI Flash DDB sysfs entry points
@@ -204,10 +200,8 @@ static struct scsi_host_template qla4xxx_driver_template = {
.eh_host_reset_handler = qla4xxx_eh_host_reset,
.eh_timed_out = qla4xxx_eh_cmd_timed_out,
- .slave_configure = qla4xxx_slave_configure,
.slave_alloc = qla4xxx_slave_alloc,
- .slave_destroy = qla4xxx_slave_destroy,
- .change_queue_depth = qla4xxx_change_queue_depth,
+ .change_queue_depth = scsi_change_queue_depth,
.this_id = -1,
.cmd_per_lun = 3,
@@ -218,6 +212,7 @@ static struct scsi_host_template qla4xxx_driver_template = {
.shost_attrs = qla4xxx_host_attrs,
.host_reset = qla4xxx_host_reset,
.vendor_id = SCSI_NL_VID_TYPE_PCI | PCI_VENDOR_ID_QLOGIC,
+ .use_blk_tags = 1,
};
static struct iscsi_transport qla4xxx_iscsi_transport = {
@@ -9060,35 +9055,14 @@ static int qla4xxx_slave_alloc(struct scsi_device *sdev)
ddb = sess->dd_data;
sdev->hostdata = ddb;
- sdev->tagged_supported = 1;
if (ql4xmaxqdepth != 0 && ql4xmaxqdepth <= 0xffffU)
queue_depth = ql4xmaxqdepth;
- scsi_activate_tcq(sdev, queue_depth);
+ scsi_change_queue_depth(sdev, queue_depth);
return 0;
}
-static int qla4xxx_slave_configure(struct scsi_device *sdev)
-{
- sdev->tagged_supported = 1;
- return 0;
-}
-
-static void qla4xxx_slave_destroy(struct scsi_device *sdev)
-{
- scsi_deactivate_tcq(sdev, 1);
-}
-
-static int qla4xxx_change_queue_depth(struct scsi_device *sdev, int qdepth,
- int reason)
-{
- if (!ql4xqfulltracking)
- return -EOPNOTSUPP;
-
- return iscsi_change_queue_depth(sdev, qdepth, reason);
-}
-
/**
* qla4xxx_del_from_active_array - returns an active srb
* @ha: Pointer to host adapter structure.
@@ -9888,6 +9862,9 @@ static int __init qla4xxx_module_init(void)
{
int ret;
+ if (ql4xqfulltracking)
+ qla4xxx_driver_template.track_queue_depth = 1;
+
/* Allocate cache for SRBs. */
srb_cachep = kmem_cache_create("qla4xxx_srbs", sizeof(struct srb), 0,
SLAB_HWCACHE_ALIGN, NULL);
diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c
index 79c77b4..1ad0c36 100644
--- a/drivers/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -527,9 +527,9 @@ void scsi_log_send(struct scsi_cmnd *cmd)
*
* 1: nothing (match completion)
*
- * 2: log opcode + command of all commands
+ * 2: log opcode + command of all commands + cmd address
*
- * 3: same as 2 plus dump cmd address
+ * 3: same as 2
*
* 4: same as 3 plus dump extra junk
*/
@@ -537,10 +537,8 @@ void scsi_log_send(struct scsi_cmnd *cmd)
level = SCSI_LOG_LEVEL(SCSI_LOG_MLQUEUE_SHIFT,
SCSI_LOG_MLQUEUE_BITS);
if (level > 1) {
- scmd_printk(KERN_INFO, cmd, "Send: ");
- if (level > 2)
- printk("0x%p ", cmd);
- printk("\n");
+ scmd_printk(KERN_INFO, cmd,
+ "Send: scmd 0x%p\n", cmd);
scsi_print_command(cmd);
if (level > 3) {
printk(KERN_INFO "buffer = 0x%p, bufflen = %d,"
@@ -565,7 +563,7 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
*
* 2: same as 1 but for all command completions.
*
- * 3: same as 2 plus dump cmd address
+ * 3: same as 2
*
* 4: same as 3 plus dump extra junk
*/
@@ -574,39 +572,10 @@ void scsi_log_completion(struct scsi_cmnd *cmd, int disposition)
SCSI_LOG_MLCOMPLETE_BITS);
if (((level > 0) && (cmd->result || disposition != SUCCESS)) ||
(level > 1)) {
- scmd_printk(KERN_INFO, cmd, "Done: ");
- if (level > 2)
- printk("0x%p ", cmd);
- /*
- * Dump truncated values, so we usually fit within
- * 80 chars.
- */
- switch (disposition) {
- case SUCCESS:
- printk("SUCCESS\n");
- break;
- case NEEDS_RETRY:
- printk("RETRY\n");
- break;
- case ADD_TO_MLQUEUE:
- printk("MLQUEUE\n");
- break;
- case FAILED:
- printk("FAILED\n");
- break;
- case TIMEOUT_ERROR:
- /*
- * If called via scsi_times_out.
- */
- printk("TIMEOUT\n");
- break;
- default:
- printk("UNKNOWN\n");
- }
- scsi_print_result(cmd);
+ scsi_print_result(cmd, "Done: ", disposition);
scsi_print_command(cmd);
if (status_byte(cmd->result) & CHECK_CONDITION)
- scsi_print_sense("", cmd);
+ scsi_print_sense(cmd);
if (level > 3)
scmd_printk(KERN_INFO, cmd,
"scsi host busy %d failed %d\n",
@@ -634,87 +603,6 @@ void scsi_cmd_get_serial(struct Scsi_Host *host, struct scsi_cmnd *cmd)
EXPORT_SYMBOL(scsi_cmd_get_serial);
/**
- * scsi_dispatch_command - Dispatch a command to the low-level driver.
- * @cmd: command block we are dispatching.
- *
- * Return: nonzero return request was rejected and device's queue needs to be
- * plugged.
- */
-int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *host = cmd->device->host;
- int rtn = 0;
-
- atomic_inc(&cmd->device->iorequest_cnt);
-
- /* check if the device is still usable */
- if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
- /* in SDEV_DEL we error all commands. DID_NO_CONNECT
- * returns an immediate error upwards, and signals
- * that the device is no longer present */
- cmd->result = DID_NO_CONNECT << 16;
- goto done;
- }
-
- /* Check to see if the scsi lld made this device blocked. */
- if (unlikely(scsi_device_blocked(cmd->device))) {
- /*
- * in blocked state, the command is just put back on
- * the device queue. The suspend state has already
- * blocked the queue so future requests should not
- * occur until the device transitions out of the
- * suspend state.
- */
- SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
- "queuecommand : device blocked\n"));
- return SCSI_MLQUEUE_DEVICE_BUSY;
- }
-
- /* Store the LUN value in cmnd, if needed. */
- if (cmd->device->lun_in_cdb)
- cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
- (cmd->device->lun << 5 & 0xe0);
-
- scsi_log_send(cmd);
-
- /*
- * Before we queue this command, check if the command
- * length exceeds what the host adapter can handle.
- */
- if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
- SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
- "queuecommand : command too long. "
- "cdb_size=%d host->max_cmd_len=%d\n",
- cmd->cmd_len, cmd->device->host->max_cmd_len));
- cmd->result = (DID_ABORT << 16);
- goto done;
- }
-
- if (unlikely(host->shost_state == SHOST_DEL)) {
- cmd->result = (DID_NO_CONNECT << 16);
- goto done;
-
- }
-
- trace_scsi_dispatch_cmd_start(cmd);
- rtn = host->hostt->queuecommand(host, cmd);
- if (rtn) {
- trace_scsi_dispatch_cmd_error(cmd, rtn);
- if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
- rtn != SCSI_MLQUEUE_TARGET_BUSY)
- rtn = SCSI_MLQUEUE_HOST_BUSY;
-
- SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
- "queuecommand : request rejected\n"));
- }
-
- return rtn;
- done:
- cmd->scsi_done(cmd);
- return 0;
-}
-
-/**
* scsi_finish_command - cleanup and pass command back to upper layer
* @cmd: the command
*
@@ -773,32 +661,18 @@ void scsi_finish_command(struct scsi_cmnd *cmd)
}
/**
- * scsi_adjust_queue_depth - Let low level drivers change a device's queue depth
+ * scsi_change_queue_depth - change a device's queue depth
* @sdev: SCSI Device in question
- * @tagged: Do we use tagged queueing (non-0) or do we treat
- * this device as an untagged device (0)
- * @tags: Number of tags allowed if tagged queueing enabled,
- * or number of commands the low level driver can
- * queue up in non-tagged mode (as per cmd_per_lun).
- *
- * Returns: Nothing
+ * @depth: number of commands allowed to be queued to the driver
*
- * Lock Status: None held on entry
- *
- * Notes: Low level drivers may call this at any time and we will do
- * the right thing depending on whether or not the device is
- * currently active and whether or not it even has the
- * command blocks built yet.
+ * Sets the device queue depth and returns the new value.
*/
-void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
+int scsi_change_queue_depth(struct scsi_device *sdev, int depth)
{
unsigned long flags;
- /*
- * refuse to set tagged depth to an unworkable size
- */
- if (tags <= 0)
- return;
+ if (depth <= 0)
+ goto out;
spin_lock_irqsave(sdev->request_queue->queue_lock, flags);
@@ -813,35 +687,17 @@ void scsi_adjust_queue_depth(struct scsi_device *sdev, int tagged, int tags)
*/
if (!shost_use_blk_mq(sdev->host) && !sdev->host->bqt) {
if (blk_queue_tagged(sdev->request_queue) &&
- blk_queue_resize_tags(sdev->request_queue, tags) != 0)
- goto out;
+ blk_queue_resize_tags(sdev->request_queue, depth) != 0)
+ goto out_unlock;
}
- sdev->queue_depth = tags;
- switch (tagged) {
- case 0:
- sdev->ordered_tags = 0;
- sdev->simple_tags = 0;
- break;
- case MSG_ORDERED_TAG:
- sdev->ordered_tags = 1;
- sdev->simple_tags = 1;
- break;
- case MSG_SIMPLE_TAG:
- sdev->ordered_tags = 0;
- sdev->simple_tags = 1;
- break;
- default:
- sdev->ordered_tags = 0;
- sdev->simple_tags = 0;
- sdev_printk(KERN_WARNING, sdev,
- "scsi_adjust_queue_depth, bad queue type, "
- "disabled\n");
- }
- out:
+ sdev->queue_depth = depth;
+out_unlock:
spin_unlock_irqrestore(sdev->request_queue->queue_lock, flags);
+out:
+ return sdev->queue_depth;
}
-EXPORT_SYMBOL(scsi_adjust_queue_depth);
+EXPORT_SYMBOL(scsi_change_queue_depth);
/**
* scsi_track_queue_full - track QUEUE_FULL events to adjust queue depth
@@ -885,19 +741,32 @@ int scsi_track_queue_full(struct scsi_device *sdev, int depth)
return 0;
if (sdev->last_queue_full_depth < 8) {
/* Drop back to untagged */
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+ scsi_set_tag_type(sdev, 0);
+ scsi_change_queue_depth(sdev, sdev->host->cmd_per_lun);
return -1;
}
-
- if (sdev->ordered_tags)
- scsi_adjust_queue_depth(sdev, MSG_ORDERED_TAG, depth);
- else
- scsi_adjust_queue_depth(sdev, MSG_SIMPLE_TAG, depth);
- return depth;
+
+ return scsi_change_queue_depth(sdev, depth);
}
EXPORT_SYMBOL(scsi_track_queue_full);
/**
+ * scsi_change_queue_type() - Change a device's queue type
+ * @sdev: The SCSI device whose queue depth is to change
+ * @tag_type: Identifier for queue type
+ */
+int scsi_change_queue_type(struct scsi_device *sdev, int tag_type)
+{
+ if (!sdev->tagged_supported)
+ return 0;
+
+ scsi_set_tag_type(sdev, tag_type);
+ return tag_type;
+
+}
+EXPORT_SYMBOL(scsi_change_queue_type);
+
+/**
* scsi_vpd_inquiry - Request a device provide us with a VPD page
* @sdev: The device to ask
* @buffer: Where to put the result
diff --git a/drivers/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index 238e06f..aa4b6b8 100644
--- a/drivers/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -63,8 +63,8 @@
#include "sd.h"
#include "scsi_logging.h"
-#define SCSI_DEBUG_VERSION "1.84"
-static const char *scsi_debug_version_date = "20140706";
+#define SCSI_DEBUG_VERSION "1.85"
+static const char *scsi_debug_version_date = "20141022";
#define MY_NAME "scsi_debug"
@@ -75,19 +75,22 @@ static const char *scsi_debug_version_date = "20140706";
#define UNRECOVERED_READ_ERR 0x11
#define PARAMETER_LIST_LENGTH_ERR 0x1a
#define INVALID_OPCODE 0x20
-#define ADDR_OUT_OF_RANGE 0x21
-#define INVALID_COMMAND_OPCODE 0x20
+#define LBA_OUT_OF_RANGE 0x21
#define INVALID_FIELD_IN_CDB 0x24
#define INVALID_FIELD_IN_PARAM_LIST 0x26
#define UA_RESET_ASC 0x29
#define UA_CHANGED_ASC 0x2a
+#define INSUFF_RES_ASC 0x55
+#define INSUFF_RES_ASCQ 0x3
#define POWER_ON_RESET_ASCQ 0x0
#define BUS_RESET_ASCQ 0x2 /* scsi bus reset occurred */
#define MODE_CHANGED_ASCQ 0x1 /* mode parameters changed */
+#define CAPACITY_CHANGED_ASCQ 0x9
#define SAVING_PARAMS_UNSUP 0x39
#define TRANSPORT_PROBLEM 0x4b
#define THRESHOLD_EXCEEDED 0x5d
#define LOW_POWER_COND_ON 0x5e
+#define MISCOMPARE_VERIFY_ASC 0x1d
/* Additional Sense Code Qualifier (ASCQ) */
#define ACK_NAK_TO 0x3
@@ -133,6 +136,7 @@ static const char *scsi_debug_version_date = "20140706";
#define DEF_VIRTUAL_GB 0
#define DEF_VPD_USE_HOSTNO 1
#define DEF_WRITESAME_LENGTH 0xFFFF
+#define DEF_STRICT 0
#define DELAY_OVERRIDDEN -9999
/* bit mask values for scsi_debug_opts */
@@ -176,11 +180,12 @@ static const char *scsi_debug_version_date = "20140706";
#define SDEBUG_UA_POR 0 /* Power on, reset, or bus device reset */
#define SDEBUG_UA_BUS_RESET 1
#define SDEBUG_UA_MODE_CHANGED 2
-#define SDEBUG_NUM_UAS 3
+#define SDEBUG_UA_CAPACITY_CHANGED 3
+#define SDEBUG_NUM_UAS 4
/* for check_readiness() */
-#define UAS_ONLY 1
-#define UAS_TUR 0
+#define UAS_ONLY 1 /* check for UAs only */
+#define UAS_TUR 0 /* if no UAs then check if media access possible */
/* when 1==SCSI_DEBUG_OPT_MEDIUM_ERR, a medium error is simulated at this
* sector on read commands: */
@@ -206,6 +211,301 @@ static const char *scsi_debug_version_date = "20140706";
#warning "Expect DEF_CMD_PER_LUN <= SCSI_DEBUG_CANQUEUE"
#endif
+/* SCSI opcodes (first byte of cdb) mapped onto these indexes */
+enum sdeb_opcode_index {
+ SDEB_I_INVALID_OPCODE = 0,
+ SDEB_I_INQUIRY = 1,
+ SDEB_I_REPORT_LUNS = 2,
+ SDEB_I_REQUEST_SENSE = 3,
+ SDEB_I_TEST_UNIT_READY = 4,
+ SDEB_I_MODE_SENSE = 5, /* 6, 10 */
+ SDEB_I_MODE_SELECT = 6, /* 6, 10 */
+ SDEB_I_LOG_SENSE = 7,
+ SDEB_I_READ_CAPACITY = 8, /* 10; 16 is in SA_IN(16) */
+ SDEB_I_READ = 9, /* 6, 10, 12, 16 */
+ SDEB_I_WRITE = 10, /* 6, 10, 12, 16 */
+ SDEB_I_START_STOP = 11,
+ SDEB_I_SERV_ACT_IN = 12, /* 12, 16 */
+ SDEB_I_SERV_ACT_OUT = 13, /* 12, 16 */
+ SDEB_I_MAINT_IN = 14,
+ SDEB_I_MAINT_OUT = 15,
+ SDEB_I_VERIFY = 16, /* 10 only */
+ SDEB_I_VARIABLE_LEN = 17,
+ SDEB_I_RESERVE = 18, /* 6, 10 */
+ SDEB_I_RELEASE = 19, /* 6, 10 */
+ SDEB_I_ALLOW_REMOVAL = 20, /* PREVENT ALLOW MEDIUM REMOVAL */
+ SDEB_I_REZERO_UNIT = 21, /* REWIND in SSC */
+ SDEB_I_ATA_PT = 22, /* 12, 16 */
+ SDEB_I_SEND_DIAG = 23,
+ SDEB_I_UNMAP = 24,
+ SDEB_I_XDWRITEREAD = 25, /* 10 only */
+ SDEB_I_WRITE_BUFFER = 26,
+ SDEB_I_WRITE_SAME = 27, /* 10, 16 */
+ SDEB_I_SYNC_CACHE = 28, /* 10 only */
+ SDEB_I_COMP_WRITE = 29,
+ SDEB_I_LAST_ELEMENT = 30, /* keep this last */
+};
+
+static const unsigned char opcode_ind_arr[256] = {
+/* 0x0; 0x0->0x1f: 6 byte cdbs */
+ SDEB_I_TEST_UNIT_READY, SDEB_I_REZERO_UNIT, 0, SDEB_I_REQUEST_SENSE,
+ 0, 0, 0, 0,
+ SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, 0,
+ 0, 0, SDEB_I_INQUIRY, 0, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
+ SDEB_I_RELEASE,
+ 0, 0, SDEB_I_MODE_SENSE, SDEB_I_START_STOP, 0, SDEB_I_SEND_DIAG,
+ SDEB_I_ALLOW_REMOVAL, 0,
+/* 0x20; 0x20->0x3f: 10 byte cdbs */
+ 0, 0, 0, 0, 0, SDEB_I_READ_CAPACITY, 0, 0,
+ SDEB_I_READ, 0, SDEB_I_WRITE, 0, 0, 0, 0, SDEB_I_VERIFY,
+ 0, 0, 0, 0, 0, SDEB_I_SYNC_CACHE, 0, 0,
+ 0, 0, 0, SDEB_I_WRITE_BUFFER, 0, 0, 0, 0,
+/* 0x40; 0x40->0x5f: 10 byte cdbs */
+ 0, SDEB_I_WRITE_SAME, SDEB_I_UNMAP, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, SDEB_I_LOG_SENSE, 0, 0,
+ 0, 0, 0, SDEB_I_XDWRITEREAD, 0, SDEB_I_MODE_SELECT, SDEB_I_RESERVE,
+ SDEB_I_RELEASE,
+ 0, 0, SDEB_I_MODE_SENSE, 0, 0, 0, 0, 0,
+/* 0x60; 0x60->0x7d are reserved */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, SDEB_I_VARIABLE_LEN,
+/* 0x80; 0x80->0x9f: 16 byte cdbs */
+ 0, 0, 0, 0, 0, SDEB_I_ATA_PT, 0, 0,
+ SDEB_I_READ, SDEB_I_COMP_WRITE, SDEB_I_WRITE, 0, 0, 0, 0, 0,
+ 0, 0, 0, SDEB_I_WRITE_SAME, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, SDEB_I_SERV_ACT_IN, SDEB_I_SERV_ACT_OUT,
+/* 0xa0; 0xa0->0xbf: 12 byte cdbs */
+ SDEB_I_REPORT_LUNS, SDEB_I_ATA_PT, 0, SDEB_I_MAINT_IN,
+ SDEB_I_MAINT_OUT, 0, 0, 0,
+ SDEB_I_READ, SDEB_I_SERV_ACT_OUT, SDEB_I_WRITE, SDEB_I_SERV_ACT_IN,
+ 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+/* 0xc0; 0xc0->0xff: vendor specific */
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+};
+
+#define F_D_IN 1
+#define F_D_OUT 2
+#define F_D_OUT_MAYBE 4 /* WRITE SAME, NDOB bit */
+#define F_D_UNKN 8
+#define F_RL_WLUN_OK 0x10
+#define F_SKIP_UA 0x20
+#define F_DELAY_OVERR 0x40
+#define F_SA_LOW 0x80 /* cdb byte 1, bits 4 to 0 */
+#define F_SA_HIGH 0x100 /* as used by variable length cdbs */
+#define F_INV_OP 0x200
+#define F_FAKE_RW 0x400
+#define F_M_ACCESS 0x800 /* media access */
+
+#define FF_RESPOND (F_RL_WLUN_OK | F_SKIP_UA | F_DELAY_OVERR)
+#define FF_DIRECT_IO (F_M_ACCESS | F_FAKE_RW)
+#define FF_SA (F_SA_HIGH | F_SA_LOW)
+
+struct sdebug_dev_info;
+static int resp_inquiry(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_report_luns(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_requests(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_mode_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_mode_select(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_log_sense(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_readcap(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_read_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_write_dt0(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_start_stop(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_readcap16(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_get_lba_status(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_report_tgtpgs(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_unmap(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_rsup_opcodes(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_rsup_tmfs(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_write_same_10(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_write_same_16(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_xdwriteread_10(struct scsi_cmnd *, struct sdebug_dev_info *);
+static int resp_comp_write(struct scsi_cmnd *, struct sdebug_dev_info *);
+
+struct opcode_info_t {
+ u8 num_attached; /* 0 if this is it (i.e. a leaf); use 0xff
+ * for terminating element */
+ u8 opcode; /* if num_attached > 0, preferred */
+ u16 sa; /* service action */
+ u32 flags; /* OR-ed set of SDEB_F_* */
+ int (*pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
+ const struct opcode_info_t *arrp; /* num_attached elements or NULL */
+ u8 len_mask[16]; /* len=len_mask[0], then mask for cdb[1]... */
+ /* ignore cdb bytes after position 15 */
+};
+
+static const struct opcode_info_t msense_iarr[1] = {
+ {0, 0x1a, 0, F_D_IN, NULL, NULL,
+ {6, 0xe8, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+};
+
+static const struct opcode_info_t mselect_iarr[1] = {
+ {0, 0x15, 0, F_D_OUT, NULL, NULL,
+ {6, 0xf1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+};
+
+static const struct opcode_info_t read_iarr[3] = {
+ {0, 0x28, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(10) */
+ {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
+ 0, 0, 0, 0} },
+ {0, 0x8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL, /* READ(6) */
+ {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0xa8, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, NULL,/* READ(12) */
+ {12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
+ 0xc7, 0, 0, 0, 0} },
+};
+
+static const struct opcode_info_t write_iarr[3] = {
+ {0, 0x2a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 10 */
+ {10, 0xfb, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
+ 0, 0, 0, 0} },
+ {0, 0xa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 6 */
+ {6, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0xaa, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, NULL, /* 12 */
+ {12, 0xfb, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x9f,
+ 0xc7, 0, 0, 0, 0} },
+};
+
+static const struct opcode_info_t sa_in_iarr[1] = {
+ {0, 0x9e, 0x12, F_SA_LOW | F_D_IN, resp_get_lba_status, NULL,
+ {16, 0x12, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0, 0xc7} },
+};
+
+static const struct opcode_info_t vl_iarr[1] = { /* VARIABLE LENGTH */
+ {0, 0x7f, 0xb, F_SA_HIGH | F_D_OUT | FF_DIRECT_IO, resp_write_dt0,
+ NULL, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0xb, 0xfa,
+ 0, 0xff, 0xff, 0xff, 0xff} }, /* WRITE(32) */
+};
+
+static const struct opcode_info_t maint_in_iarr[2] = {
+ {0, 0xa3, 0xc, F_SA_LOW | F_D_IN, resp_rsup_opcodes, NULL,
+ {12, 0xc, 0x87, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0,
+ 0xc7, 0, 0, 0, 0} },
+ {0, 0xa3, 0xd, F_SA_LOW | F_D_IN, resp_rsup_tmfs, NULL,
+ {12, 0xd, 0x80, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
+ 0, 0} },
+};
+
+static const struct opcode_info_t write_same_iarr[1] = {
+ {0, 0x93, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_16, NULL,
+ {16, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x1f, 0xc7} },
+};
+
+static const struct opcode_info_t reserve_iarr[1] = {
+ {0, 0x16, 0, F_D_OUT, NULL, NULL, /* RESERVE(6) */
+ {6, 0x1f, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+};
+
+static const struct opcode_info_t release_iarr[1] = {
+ {0, 0x17, 0, F_D_OUT, NULL, NULL, /* RELEASE(6) */
+ {6, 0x1f, 0xff, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+};
+
+
+/* This array is accessed via SDEB_I_* values. Make sure all are mapped,
+ * plus the terminating elements for logic that scans this table such as
+ * REPORT SUPPORTED OPERATION CODES. */
+static const struct opcode_info_t opcode_info_arr[SDEB_I_LAST_ELEMENT + 1] = {
+/* 0 */
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL,
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x12, 0, FF_RESPOND | F_D_IN, resp_inquiry, NULL,
+ {6, 0xe3, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0xa0, 0, FF_RESPOND | F_D_IN, resp_report_luns, NULL,
+ {12, 0xe3, 0xff, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0,
+ 0, 0} },
+ {0, 0x3, 0, FF_RESPOND | F_D_IN, resp_requests, NULL,
+ {6, 0xe1, 0, 0, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x0, 0, F_M_ACCESS | F_RL_WLUN_OK, NULL, NULL,/* TEST UNIT READY */
+ {6, 0, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {1, 0x5a, 0, F_D_IN, resp_mode_sense, msense_iarr,
+ {10, 0xf8, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
+ 0} },
+ {1, 0x55, 0, F_D_OUT, resp_mode_select, mselect_iarr,
+ {10, 0xf1, 0, 0, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
+ {0, 0x4d, 0, F_D_IN, resp_log_sense, NULL,
+ {10, 0xe3, 0xff, 0xff, 0, 0xff, 0xff, 0xff, 0xff, 0xc7, 0, 0, 0,
+ 0, 0, 0} },
+ {0, 0x25, 0, F_D_IN, resp_readcap, NULL,
+ {10, 0xe1, 0xff, 0xff, 0xff, 0xff, 0, 0, 0x1, 0xc7, 0, 0, 0, 0,
+ 0, 0} },
+ {3, 0x88, 0, F_D_IN | FF_DIRECT_IO, resp_read_dt0, read_iarr,
+ {16, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* READ(16) */
+/* 10 */
+ {3, 0x8a, 0, F_D_OUT | FF_DIRECT_IO, resp_write_dt0, write_iarr,
+ {16, 0xfa, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x9f, 0xc7} }, /* WRITE(16) */
+ {0, 0x1b, 0, 0, resp_start_stop, NULL, /* START STOP UNIT */
+ {6, 0x1, 0, 0xf, 0xf7, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {1, 0x9e, 0x10, F_SA_LOW | F_D_IN, resp_readcap16, sa_in_iarr,
+ {16, 0x10, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0x1, 0xc7} }, /* READ CAPACITY(16) */
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* SA OUT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {2, 0xa3, 0xa, F_SA_LOW | F_D_IN, resp_report_tgtpgs, maint_in_iarr,
+ {12, 0xea, 0, 0, 0, 0, 0xff, 0xff, 0xff, 0xff, 0, 0xc7, 0, 0, 0,
+ 0} },
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* MAINT OUT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* VERIFY */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {1, 0x7f, 0x9, F_SA_HIGH | F_D_IN | FF_DIRECT_IO, resp_read_dt0,
+ vl_iarr, {32, 0xc7, 0, 0, 0, 0, 0x1f, 0x18, 0x0, 0x9, 0xfe, 0,
+ 0xff, 0xff, 0xff, 0xff} },/* VARIABLE LENGTH, READ(32) */
+ {1, 0x56, 0, F_D_OUT, NULL, reserve_iarr, /* RESERVE(10) */
+ {10, 0xff, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
+ 0} },
+ {1, 0x57, 0, F_D_OUT, NULL, release_iarr, /* RELEASE(10) */
+ {10, 0x13, 0xff, 0xff, 0, 0, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0,
+ 0} },
+/* 20 */
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ALLOW REMOVAL */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x1, 0, 0, resp_start_stop, NULL, /* REWIND ?? */
+ {6, 0x1, 0, 0, 0, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* ATA_PT */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x1d, F_D_OUT, 0, NULL, NULL, /* SEND DIAGNOSTIC */
+ {6, 0xf7, 0, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {0, 0x42, 0, F_D_OUT | FF_DIRECT_IO, resp_unmap, NULL, /* UNMAP */
+ {10, 0x1, 0, 0, 0, 0, 0x1f, 0xff, 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
+ {0, 0x53, 0, F_D_IN | F_D_OUT | FF_DIRECT_IO, resp_xdwriteread_10,
+ NULL, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7,
+ 0, 0, 0, 0, 0, 0} },
+ {0, 0, 0, F_INV_OP | FF_RESPOND, NULL, NULL, /* WRITE_BUFFER */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+ {1, 0x41, 0, F_D_OUT_MAYBE | FF_DIRECT_IO, resp_write_same_10,
+ write_same_iarr, {10, 0xff, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff,
+ 0xff, 0xc7, 0, 0, 0, 0, 0, 0} },
+ {0, 0x35, 0, F_DELAY_OVERR | FF_DIRECT_IO, NULL, NULL, /* SYNC_CACHE */
+ {10, 0x7, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xff, 0xff, 0xc7, 0, 0,
+ 0, 0, 0, 0} },
+ {0, 0x89, 0, F_D_OUT | FF_DIRECT_IO, resp_comp_write, NULL,
+ {16, 0xf8, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0, 0,
+ 0, 0xff, 0x1f, 0xc7} }, /* COMPARE AND WRITE */
+
+/* 30 */
+ {0xff, 0, 0, 0, NULL, NULL, /* terminating element */
+ {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} },
+};
+
+struct sdebug_scmd_extra_t {
+ bool inj_recovered;
+ bool inj_transport;
+ bool inj_dif;
+ bool inj_dix;
+ bool inj_short;
+};
+
static int scsi_debug_add_host = DEF_NUM_HOST;
static int scsi_debug_ato = DEF_ATO;
static int scsi_debug_delay = DEF_DELAY;
@@ -245,6 +545,8 @@ static unsigned int scsi_debug_write_same_length = DEF_WRITESAME_LENGTH;
static bool scsi_debug_removable = DEF_REMOVABLE;
static bool scsi_debug_clustering;
static bool scsi_debug_host_lock = DEF_HOST_LOCK;
+static bool scsi_debug_strict = DEF_STRICT;
+static bool sdebug_any_injecting_opt;
static atomic_t sdebug_cmnd_count;
static atomic_t sdebug_completions;
@@ -277,11 +579,10 @@ struct sdebug_dev_info {
unsigned int target;
u64 lun;
struct sdebug_host_info *sdbg_host;
- u64 wlun;
unsigned long uas_bm[1];
atomic_t num_in_q;
- char stopped;
- char used;
+ char stopped; /* TODO: should be atomic */
+ bool used;
};
struct sdebug_host_info {
@@ -394,6 +695,50 @@ static void sdebug_max_tgts_luns(void)
spin_unlock(&sdebug_host_list_lock);
}
+enum sdeb_cmd_data {SDEB_IN_DATA = 0, SDEB_IN_CDB = 1};
+
+/* Set in_bit to -1 to indicate no bit position of invalid field */
+static void
+mk_sense_invalid_fld(struct scsi_cmnd *scp, enum sdeb_cmd_data c_d,
+ int in_byte, int in_bit)
+{
+ unsigned char *sbuff;
+ u8 sks[4];
+ int sl, asc;
+
+ sbuff = scp->sense_buffer;
+ if (!sbuff) {
+ sdev_printk(KERN_ERR, scp->device,
+ "%s: sense_buffer is NULL\n", __func__);
+ return;
+ }
+ asc = c_d ? INVALID_FIELD_IN_CDB : INVALID_FIELD_IN_PARAM_LIST;
+ memset(sbuff, 0, SCSI_SENSE_BUFFERSIZE);
+ scsi_build_sense_buffer(scsi_debug_dsense, sbuff, ILLEGAL_REQUEST,
+ asc, 0);
+ memset(sks, 0, sizeof(sks));
+ sks[0] = 0x80;
+ if (c_d)
+ sks[0] |= 0x40;
+ if (in_bit >= 0) {
+ sks[0] |= 0x8;
+ sks[0] |= 0x7 & in_bit;
+ }
+ put_unaligned_be16(in_byte, sks + 1);
+ if (scsi_debug_dsense) {
+ sl = sbuff[7] + 8;
+ sbuff[7] = sl;
+ sbuff[sl] = 0x2;
+ sbuff[sl + 1] = 0x6;
+ memcpy(sbuff + sl + 4, sks, 3);
+ } else
+ memcpy(sbuff + 15, sks, 3);
+ if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
+ sdev_printk(KERN_INFO, scp->device, "%s: [sense_key,asc,ascq"
+ "]: [0x5,0x%x,0x0] %c byte=%d, bit=%d\n",
+ my_name, asc, c_d ? 'C' : 'D', in_byte, in_bit);
+}
+
static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
{
unsigned char *sbuff;
@@ -414,63 +759,10 @@ static void mk_sense_buffer(struct scsi_cmnd *scp, int key, int asc, int asq)
my_name, key, asc, asq);
}
-static void get_data_transfer_info(unsigned char *cmd,
- unsigned long long *lba, unsigned int *num,
- u32 *ei_lba)
+static void
+mk_sense_invalid_opcode(struct scsi_cmnd *scp)
{
- *ei_lba = 0;
-
- switch (*cmd) {
- case VARIABLE_LENGTH_CMD:
- *lba = (u64)cmd[19] | (u64)cmd[18] << 8 |
- (u64)cmd[17] << 16 | (u64)cmd[16] << 24 |
- (u64)cmd[15] << 32 | (u64)cmd[14] << 40 |
- (u64)cmd[13] << 48 | (u64)cmd[12] << 56;
-
- *ei_lba = (u32)cmd[23] | (u32)cmd[22] << 8 |
- (u32)cmd[21] << 16 | (u32)cmd[20] << 24;
-
- *num = (u32)cmd[31] | (u32)cmd[30] << 8 | (u32)cmd[29] << 16 |
- (u32)cmd[28] << 24;
- break;
-
- case WRITE_SAME_16:
- case WRITE_16:
- case READ_16:
- *lba = (u64)cmd[9] | (u64)cmd[8] << 8 |
- (u64)cmd[7] << 16 | (u64)cmd[6] << 24 |
- (u64)cmd[5] << 32 | (u64)cmd[4] << 40 |
- (u64)cmd[3] << 48 | (u64)cmd[2] << 56;
-
- *num = (u32)cmd[13] | (u32)cmd[12] << 8 | (u32)cmd[11] << 16 |
- (u32)cmd[10] << 24;
- break;
- case WRITE_12:
- case READ_12:
- *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
- (u32)cmd[2] << 24;
-
- *num = (u32)cmd[9] | (u32)cmd[8] << 8 | (u32)cmd[7] << 16 |
- (u32)cmd[6] << 24;
- break;
- case WRITE_SAME:
- case WRITE_10:
- case READ_10:
- case XDWRITEREAD_10:
- *lba = (u32)cmd[5] | (u32)cmd[4] << 8 | (u32)cmd[3] << 16 |
- (u32)cmd[2] << 24;
-
- *num = (u32)cmd[8] | (u32)cmd[7] << 8;
- break;
- case WRITE_6:
- case READ_6:
- *lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
- (u32)(cmd[1] & 0x1f) << 16;
- *num = (0 == cmd[4]) ? 256 : cmd[4];
- break;
- default:
- break;
- }
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
}
static int scsi_debug_ioctl(struct scsi_device *dev, int cmd, void __user *arg)
@@ -520,6 +812,11 @@ static int check_readiness(struct scsi_cmnd *SCpnt, int uas_only,
if (debug)
cp = "mode parameters changed";
break;
+ case SDEBUG_UA_CAPACITY_CHANGED:
+ mk_sense_buffer(SCpnt, UNIT_ATTENTION,
+ UA_CHANGED_ASC, CAPACITY_CHANGED_ASCQ);
+ if (debug)
+ cp = "capacity data changed";
default:
pr_warn("%s: unexpected unit attention code=%d\n",
__func__, k);
@@ -924,19 +1221,20 @@ static int inquiry_evpd_b2(unsigned char *arr)
#define SDEBUG_LONG_INQ_SZ 96
#define SDEBUG_MAX_INQ_ARR_SZ 584
-static int resp_inquiry(struct scsi_cmnd *scp, int target,
- struct sdebug_dev_info * devip)
+static int resp_inquiry(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
unsigned char pq_pdt;
unsigned char * arr;
unsigned char *cmd = scp->cmnd;
int alloc_len, n, ret;
+ bool have_wlun;
alloc_len = (cmd[3] << 8) + cmd[4];
arr = kzalloc(SDEBUG_MAX_INQ_ARR_SZ, GFP_ATOMIC);
if (! arr)
return DID_REQUEUE << 16;
- if (devip->wlun)
+ have_wlun = (scp->device->lun == SAM2_WLUN_REPORT_LUNS);
+ if (have_wlun)
pq_pdt = 0x1e; /* present, wlun */
else if (scsi_debug_no_lun_0 && (0 == devip->lun))
pq_pdt = 0x7f; /* not present, no device type */
@@ -944,8 +1242,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, int target,
pq_pdt = (scsi_debug_ptype & 0x1f);
arr[0] = pq_pdt;
if (0x2 & cmd[1]) { /* CMDDT bit set */
- mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
- 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 1);
kfree(arr);
return check_condition_result;
} else if (0x1 & cmd[1]) { /* EVPD bit set */
@@ -957,7 +1254,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, int target,
(devip->channel & 0x7f);
if (0 == scsi_debug_vpd_use_hostno)
host_no = 0;
- lu_id_num = devip->wlun ? -1 : (((host_no + 1) * 2000) +
+ lu_id_num = have_wlun ? -1 : (((host_no + 1) * 2000) +
(devip->target * 1000) + devip->lun);
target_dev_id = ((host_no + 1) * 2000) +
(devip->target * 1000) - 3;
@@ -1029,9 +1326,7 @@ static int resp_inquiry(struct scsi_cmnd *scp, int target,
arr[1] = cmd[2]; /*sanity */
arr[3] = inquiry_evpd_b2(&arr[4]);
} else {
- /* Illegal request, invalid field in cdb */
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, -1);
kfree(arr);
return check_condition_result;
}
@@ -1077,18 +1372,20 @@ static int resp_requests(struct scsi_cmnd * scp,
unsigned char * sbuff;
unsigned char *cmd = scp->cmnd;
unsigned char arr[SCSI_SENSE_BUFFERSIZE];
- int want_dsense;
+ bool dsense, want_dsense;
int len = 18;
memset(arr, 0, sizeof(arr));
- want_dsense = !!(cmd[1] & 1) || scsi_debug_dsense;
+ dsense = !!(cmd[1] & 1);
+ want_dsense = dsense || scsi_debug_dsense;
sbuff = scp->sense_buffer;
if ((iec_m_pg[2] & 0x4) && (6 == (iec_m_pg[3] & 0xf))) {
- if (want_dsense) {
+ if (dsense) {
arr[0] = 0x72;
arr[1] = 0x0; /* NO_SENSE in sense_key */
arr[2] = THRESHOLD_EXCEEDED;
arr[3] = 0xff; /* TEST set and MRIE==6 */
+ len = 8;
} else {
arr[0] = 0x70;
arr[2] = 0x0; /* NO_SENSE in sense_key */
@@ -1098,15 +1395,34 @@ static int resp_requests(struct scsi_cmnd * scp,
}
} else {
memcpy(arr, sbuff, SCSI_SENSE_BUFFERSIZE);
- if ((cmd[1] & 1) && (! scsi_debug_dsense)) {
- /* DESC bit set and sense_buff in fixed format */
- memset(arr, 0, sizeof(arr));
+ if (arr[0] >= 0x70 && dsense == scsi_debug_dsense)
+ ; /* have sense and formats match */
+ else if (arr[0] <= 0x70) {
+ if (dsense) {
+ memset(arr, 0, 8);
+ arr[0] = 0x72;
+ len = 8;
+ } else {
+ memset(arr, 0, 18);
+ arr[0] = 0x70;
+ arr[7] = 0xa;
+ }
+ } else if (dsense) {
+ memset(arr, 0, 8);
arr[0] = 0x72;
arr[1] = sbuff[2]; /* sense key */
arr[2] = sbuff[12]; /* asc */
arr[3] = sbuff[13]; /* ascq */
len = 8;
+ } else {
+ memset(arr, 0, 18);
+ arr[0] = 0x70;
+ arr[2] = sbuff[1];
+ arr[7] = 0xa;
+ arr[12] = sbuff[1];
+ arr[13] = sbuff[3];
}
+
}
mk_sense_buffer(scp, 0, NO_ADDITIONAL_SENSE, 0);
return fill_from_dev_buffer(scp, arr, len);
@@ -1116,15 +1432,11 @@ static int resp_start_stop(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
unsigned char *cmd = scp->cmnd;
- int power_cond, errsts, start;
+ int power_cond, start;
- errsts = check_readiness(scp, UAS_ONLY, devip);
- if (errsts)
- return errsts;
power_cond = (cmd[4] & 0xf0) >> 4;
if (power_cond) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
- 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, 7);
return check_condition_result;
}
start = cmd[4] & 1;
@@ -1148,11 +1460,7 @@ static int resp_readcap(struct scsi_cmnd * scp,
{
unsigned char arr[SDEBUG_READCAP_ARR_SZ];
unsigned int capac;
- int errsts;
- errsts = check_readiness(scp, UAS_ONLY, devip);
- if (errsts)
- return errsts;
/* following just in case virtual_gb changed */
sdebug_capacity = get_sdebug_capacity();
memset(arr, 0, SDEBUG_READCAP_ARR_SZ);
@@ -1180,11 +1488,8 @@ static int resp_readcap16(struct scsi_cmnd * scp,
unsigned char *cmd = scp->cmnd;
unsigned char arr[SDEBUG_READCAP16_ARR_SZ];
unsigned long long capac;
- int errsts, k, alloc_len;
+ int k, alloc_len;
- errsts = check_readiness(scp, UAS_ONLY, devip);
- if (errsts)
- return errsts;
alloc_len = ((cmd[10] << 24) + (cmd[11] << 16) + (cmd[12] << 8)
+ cmd[13]);
/* following just in case virtual_gb changed */
@@ -1300,6 +1605,184 @@ static int resp_report_tgtpgs(struct scsi_cmnd * scp,
return ret;
}
+static int
+resp_rsup_opcodes(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ bool rctd;
+ u8 reporting_opts, req_opcode, sdeb_i, supp;
+ u16 req_sa, u;
+ u32 alloc_len, a_len;
+ int k, offset, len, errsts, count, bump, na;
+ const struct opcode_info_t *oip;
+ const struct opcode_info_t *r_oip;
+ u8 *arr;
+ u8 *cmd = scp->cmnd;
+
+ rctd = !!(cmd[2] & 0x80);
+ reporting_opts = cmd[2] & 0x7;
+ req_opcode = cmd[3];
+ req_sa = get_unaligned_be16(cmd + 4);
+ alloc_len = get_unaligned_be32(cmd + 6);
+ if (alloc_len < 4 && alloc_len > 0xffff) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
+ return check_condition_result;
+ }
+ if (alloc_len > 8192)
+ a_len = 8192;
+ else
+ a_len = alloc_len;
+ arr = kzalloc((a_len < 256) ? 320 : a_len + 64, GFP_KERNEL);
+ if (NULL == arr) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+ INSUFF_RES_ASCQ);
+ return check_condition_result;
+ }
+ switch (reporting_opts) {
+ case 0: /* all commands */
+ /* count number of commands */
+ for (count = 0, oip = opcode_info_arr;
+ oip->num_attached != 0xff; ++oip) {
+ if (F_INV_OP & oip->flags)
+ continue;
+ count += (oip->num_attached + 1);
+ }
+ bump = rctd ? 20 : 8;
+ put_unaligned_be32(count * bump, arr);
+ for (offset = 4, oip = opcode_info_arr;
+ oip->num_attached != 0xff && offset < a_len; ++oip) {
+ if (F_INV_OP & oip->flags)
+ continue;
+ na = oip->num_attached;
+ arr[offset] = oip->opcode;
+ put_unaligned_be16(oip->sa, arr + offset + 2);
+ if (rctd)
+ arr[offset + 5] |= 0x2;
+ if (FF_SA & oip->flags)
+ arr[offset + 5] |= 0x1;
+ put_unaligned_be16(oip->len_mask[0], arr + offset + 6);
+ if (rctd)
+ put_unaligned_be16(0xa, arr + offset + 8);
+ r_oip = oip;
+ for (k = 0, oip = oip->arrp; k < na; ++k, ++oip) {
+ if (F_INV_OP & oip->flags)
+ continue;
+ offset += bump;
+ arr[offset] = oip->opcode;
+ put_unaligned_be16(oip->sa, arr + offset + 2);
+ if (rctd)
+ arr[offset + 5] |= 0x2;
+ if (FF_SA & oip->flags)
+ arr[offset + 5] |= 0x1;
+ put_unaligned_be16(oip->len_mask[0],
+ arr + offset + 6);
+ if (rctd)
+ put_unaligned_be16(0xa,
+ arr + offset + 8);
+ }
+ oip = r_oip;
+ offset += bump;
+ }
+ break;
+ case 1: /* one command: opcode only */
+ case 2: /* one command: opcode plus service action */
+ case 3: /* one command: if sa==0 then opcode only else opcode+sa */
+ sdeb_i = opcode_ind_arr[req_opcode];
+ oip = &opcode_info_arr[sdeb_i];
+ if (F_INV_OP & oip->flags) {
+ supp = 1;
+ offset = 4;
+ } else {
+ if (1 == reporting_opts) {
+ if (FF_SA & oip->flags) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB,
+ 2, 2);
+ kfree(arr);
+ return check_condition_result;
+ }
+ req_sa = 0;
+ } else if (2 == reporting_opts &&
+ 0 == (FF_SA & oip->flags)) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 4, -1);
+ kfree(arr); /* point at requested sa */
+ return check_condition_result;
+ }
+ if (0 == (FF_SA & oip->flags) &&
+ req_opcode == oip->opcode)
+ supp = 3;
+ else if (0 == (FF_SA & oip->flags)) {
+ na = oip->num_attached;
+ for (k = 0, oip = oip->arrp; k < na;
+ ++k, ++oip) {
+ if (req_opcode == oip->opcode)
+ break;
+ }
+ supp = (k >= na) ? 1 : 3;
+ } else if (req_sa != oip->sa) {
+ na = oip->num_attached;
+ for (k = 0, oip = oip->arrp; k < na;
+ ++k, ++oip) {
+ if (req_sa == oip->sa)
+ break;
+ }
+ supp = (k >= na) ? 1 : 3;
+ } else
+ supp = 3;
+ if (3 == supp) {
+ u = oip->len_mask[0];
+ put_unaligned_be16(u, arr + 2);
+ arr[4] = oip->opcode;
+ for (k = 1; k < u; ++k)
+ arr[4 + k] = (k < 16) ?
+ oip->len_mask[k] : 0xff;
+ offset = 4 + u;
+ } else
+ offset = 4;
+ }
+ arr[1] = (rctd ? 0x80 : 0) | supp;
+ if (rctd) {
+ put_unaligned_be16(0xa, arr + offset);
+ offset += 12;
+ }
+ break;
+ default:
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 2);
+ kfree(arr);
+ return check_condition_result;
+ }
+ offset = (offset < a_len) ? offset : a_len;
+ len = (offset < alloc_len) ? offset : alloc_len;
+ errsts = fill_from_dev_buffer(scp, arr, len);
+ kfree(arr);
+ return errsts;
+}
+
+static int
+resp_rsup_tmfs(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ bool repd;
+ u32 alloc_len, len;
+ u8 arr[16];
+ u8 *cmd = scp->cmnd;
+
+ memset(arr, 0, sizeof(arr));
+ repd = !!(cmd[2] & 0x80);
+ alloc_len = get_unaligned_be32(cmd + 6);
+ if (alloc_len < 4) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 6, -1);
+ return check_condition_result;
+ }
+ arr[0] = 0xc8; /* ATS | ATSS | LURS */
+ arr[1] = 0x1; /* ITNRS */
+ if (repd) {
+ arr[3] = 0xc;
+ len = 16;
+ } else
+ len = 4;
+
+ len = (len < alloc_len) ? len : alloc_len;
+ return fill_from_dev_buffer(scp, arr, len);
+}
+
/* <<Following mode page info copied from ST318451LW>> */
static int resp_err_recov_pg(unsigned char * p, int pcontrol, int target)
@@ -1459,20 +1942,18 @@ static int resp_sas_sha_m_spg(unsigned char * p, int pcontrol)
#define SDEBUG_MAX_MSENSE_SZ 256
-static int resp_mode_sense(struct scsi_cmnd * scp, int target,
- struct sdebug_dev_info * devip)
+static int
+resp_mode_sense(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
unsigned char dbd, llbaa;
int pcontrol, pcode, subpcode, bd_len;
unsigned char dev_spec;
- int k, alloc_len, msense_6, offset, len, errsts, target_dev_id;
+ int k, alloc_len, msense_6, offset, len, target_dev_id;
+ int target = scp->device->id;
unsigned char * ap;
unsigned char arr[SDEBUG_MAX_MSENSE_SZ];
unsigned char *cmd = scp->cmnd;
- errsts = check_readiness(scp, UAS_ONLY, devip);
- if (errsts)
- return errsts;
dbd = !!(cmd[1] & 0x8);
pcontrol = (cmd[2] & 0xc0) >> 6;
pcode = cmd[2] & 0x3f;
@@ -1542,8 +2023,7 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
if ((subpcode > 0x0) && (subpcode < 0xff) && (0x19 != pcode)) {
/* TODO: Control Extension page */
- mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
- 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
return check_condition_result;
}
switch (pcode) {
@@ -1569,8 +2049,7 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
break;
case 0x19: /* if spc==1 then sas phy, control+discover */
if ((subpcode > 0x2) && (subpcode < 0xff)) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
return check_condition_result;
}
len = 0;
@@ -1602,15 +2081,13 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
}
len += resp_iec_m_pg(ap + len, pcontrol, target);
} else {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
return check_condition_result;
}
offset += len;
break;
default:
- mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
- 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
return check_condition_result;
}
if (msense_6)
@@ -1624,24 +2101,21 @@ static int resp_mode_sense(struct scsi_cmnd * scp, int target,
#define SDEBUG_MAX_MSELECT_SZ 512
-static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
- struct sdebug_dev_info * devip)
+static int
+resp_mode_select(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
int pf, sp, ps, md_len, bd_len, off, spf, pg_len;
- int param_len, res, errsts, mpage;
+ int param_len, res, mpage;
unsigned char arr[SDEBUG_MAX_MSELECT_SZ];
unsigned char *cmd = scp->cmnd;
+ int mselect6 = (MODE_SELECT == cmd[0]);
- errsts = check_readiness(scp, UAS_ONLY, devip);
- if (errsts)
- return errsts;
memset(arr, 0, sizeof(arr));
pf = cmd[1] & 0x10;
sp = cmd[1] & 0x1;
param_len = mselect6 ? cmd[4] : ((cmd[7] << 8) + cmd[8]);
if ((0 == pf) || sp || (param_len > SDEBUG_MAX_MSELECT_SZ)) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, mselect6 ? 4 : 7, -1);
return check_condition_result;
}
res = fetch_to_dev_buffer(scp, arr, param_len);
@@ -1655,16 +2129,14 @@ static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
md_len = mselect6 ? (arr[0] + 1) : ((arr[0] << 8) + arr[1] + 2);
bd_len = mselect6 ? arr[3] : ((arr[6] << 8) + arr[7]);
if (md_len > 2) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_PARAM_LIST, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_DATA, 0, -1);
return check_condition_result;
}
off = bd_len + (mselect6 ? 4 : 8);
mpage = arr[off] & 0x3f;
ps = !!(arr[off] & 0x80);
if (ps) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_PARAM_LIST, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 7);
return check_condition_result;
}
spf = !!(arr[off] & 0x40);
@@ -1701,8 +2173,7 @@ static int resp_mode_select(struct scsi_cmnd * scp, int mselect6,
default:
break;
}
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_PARAM_LIST, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_DATA, off, 5);
return check_condition_result;
set_mode_changed_ua:
set_bit(SDEBUG_UA_MODE_CHANGED, devip->uas_bm);
@@ -1737,19 +2208,15 @@ static int resp_ie_l_pg(unsigned char * arr)
static int resp_log_sense(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
- int ppc, sp, pcontrol, pcode, subpcode, alloc_len, errsts, len, n;
+ int ppc, sp, pcontrol, pcode, subpcode, alloc_len, len, n;
unsigned char arr[SDEBUG_MAX_LSENSE_SZ];
unsigned char *cmd = scp->cmnd;
- errsts = check_readiness(scp, UAS_ONLY, devip);
- if (errsts)
- return errsts;
memset(arr, 0, sizeof(arr));
ppc = cmd[1] & 0x2;
sp = cmd[1] & 0x1;
if (ppc || sp) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, ppc ? 1 : 0);
return check_condition_result;
}
pcontrol = (cmd[2] & 0xc0) >> 6;
@@ -1773,8 +2240,7 @@ static int resp_log_sense(struct scsi_cmnd * scp,
arr[3] = resp_ie_l_pg(arr + 4);
break;
default:
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
return check_condition_result;
}
} else if (0xff == subpcode) {
@@ -1806,13 +2272,11 @@ static int resp_log_sense(struct scsi_cmnd * scp,
arr[3] = n - 4;
break;
default:
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 2, 5);
return check_condition_result;
}
} else {
- mk_sense_buffer(scp, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 3, -1);
return check_condition_result;
}
len = min(((arr[2] << 8) + arr[3]) + 4, alloc_len);
@@ -1824,11 +2288,12 @@ static int check_device_access_params(struct scsi_cmnd *scp,
unsigned long long lba, unsigned int num)
{
if (lba + num > sdebug_capacity) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST, ADDR_OUT_OF_RANGE, 0);
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
return check_condition_result;
}
/* transfer length excessive (tie in to block limits VPD page) */
if (num > sdebug_store_sectors) {
+ /* needs work to find which cdb byte 'num' comes from */
mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
return check_condition_result;
}
@@ -1836,17 +2301,17 @@ static int check_device_access_params(struct scsi_cmnd *scp,
}
/* Returns number of bytes copied or -1 if error. */
-static int do_device_access(struct scsi_cmnd *scmd,
- unsigned long long lba, unsigned int num, int write)
+static int
+do_device_access(struct scsi_cmnd *scmd, u64 lba, u32 num, bool do_write)
{
int ret;
- unsigned long long block, rest = 0;
+ u64 block, rest = 0;
struct scsi_data_buffer *sdb;
enum dma_data_direction dir;
size_t (*func)(struct scatterlist *, unsigned int, void *, size_t,
off_t);
- if (write) {
+ if (do_write) {
sdb = scsi_out(scmd);
dir = DMA_TO_DEVICE;
func = sg_pcopy_to_buffer;
@@ -1880,6 +2345,38 @@ static int do_device_access(struct scsi_cmnd *scmd,
return ret;
}
+/* If fake_store(lba,num) compares equal to arr(num), then copy top half of
+ * arr into fake_store(lba,num) and return true. If comparison fails then
+ * return false. */
+static bool
+comp_write_worker(u64 lba, u32 num, const u8 *arr)
+{
+ bool res;
+ u64 block, rest = 0;
+ u32 store_blks = sdebug_store_sectors;
+ u32 lb_size = scsi_debug_sector_size;
+
+ block = do_div(lba, store_blks);
+ if (block + num > store_blks)
+ rest = block + num - store_blks;
+
+ res = !memcmp(fake_storep + (block * lb_size), arr,
+ (num - rest) * lb_size);
+ if (!res)
+ return res;
+ if (rest)
+ res = memcmp(fake_storep, arr + ((num - rest) * lb_size),
+ rest * lb_size);
+ if (!res)
+ return res;
+ arr += num * lb_size;
+ memcpy(fake_storep + (block * lb_size), arr, (num - rest) * lb_size);
+ if (rest)
+ memcpy(fake_storep, arr + ((num - rest) * lb_size),
+ rest * lb_size);
+ return res;
+}
+
static __be16 dif_compute_csum(const void *buf, int len)
{
__be16 csum;
@@ -1992,55 +2489,143 @@ static int prot_verify_read(struct scsi_cmnd *SCpnt, sector_t start_sec,
return 0;
}
-static int resp_read(struct scsi_cmnd *SCpnt, unsigned long long lba,
- unsigned int num, u32 ei_lba)
+static int
+resp_read_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
+ u8 *cmd = scp->cmnd;
+ u64 lba;
+ u32 num;
+ u32 ei_lba;
unsigned long iflags;
int ret;
+ bool check_prot;
- ret = check_device_access_params(SCpnt, lba, num);
- if (ret)
- return ret;
+ switch (cmd[0]) {
+ case READ_16:
+ ei_lba = 0;
+ lba = get_unaligned_be64(cmd + 2);
+ num = get_unaligned_be32(cmd + 10);
+ check_prot = true;
+ break;
+ case READ_10:
+ ei_lba = 0;
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be16(cmd + 7);
+ check_prot = true;
+ break;
+ case READ_6:
+ ei_lba = 0;
+ lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
+ (u32)(cmd[1] & 0x1f) << 16;
+ num = (0 == cmd[4]) ? 256 : cmd[4];
+ check_prot = true;
+ break;
+ case READ_12:
+ ei_lba = 0;
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be32(cmd + 6);
+ check_prot = true;
+ break;
+ case XDWRITEREAD_10:
+ ei_lba = 0;
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be16(cmd + 7);
+ check_prot = false;
+ break;
+ default: /* assume READ(32) */
+ lba = get_unaligned_be64(cmd + 12);
+ ei_lba = get_unaligned_be32(cmd + 20);
+ num = get_unaligned_be32(cmd + 28);
+ check_prot = false;
+ break;
+ }
+ if (check_prot) {
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ (cmd[1] & 0xe0)) {
+ mk_sense_invalid_opcode(scp);
+ return check_condition_result;
+ }
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ sdev_printk(KERN_ERR, scp->device, "Unprotected RD "
+ "to DIF device\n");
+ }
+ if (sdebug_any_injecting_opt) {
+ struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
+
+ if (ep->inj_short)
+ num /= 2;
+ }
+
+ /* inline check_device_access_params() */
+ if (lba + num > sdebug_capacity) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
+ return check_condition_result;
+ }
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ /* needs work to find which cdb byte 'num' comes from */
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
if ((SCSI_DEBUG_OPT_MEDIUM_ERR & scsi_debug_opts) &&
(lba <= (OPT_MEDIUM_ERR_ADDR + OPT_MEDIUM_ERR_NUM - 1)) &&
((lba + num) > OPT_MEDIUM_ERR_ADDR)) {
/* claim unrecoverable read error */
- mk_sense_buffer(SCpnt, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
+ mk_sense_buffer(scp, MEDIUM_ERROR, UNRECOVERED_READ_ERR, 0);
/* set info field and valid bit for fixed descriptor */
- if (0x70 == (SCpnt->sense_buffer[0] & 0x7f)) {
- SCpnt->sense_buffer[0] |= 0x80; /* Valid bit */
+ if (0x70 == (scp->sense_buffer[0] & 0x7f)) {
+ scp->sense_buffer[0] |= 0x80; /* Valid bit */
ret = (lba < OPT_MEDIUM_ERR_ADDR)
? OPT_MEDIUM_ERR_ADDR : (int)lba;
- SCpnt->sense_buffer[3] = (ret >> 24) & 0xff;
- SCpnt->sense_buffer[4] = (ret >> 16) & 0xff;
- SCpnt->sense_buffer[5] = (ret >> 8) & 0xff;
- SCpnt->sense_buffer[6] = ret & 0xff;
+ put_unaligned_be32(ret, scp->sense_buffer + 3);
}
- scsi_set_resid(SCpnt, scsi_bufflen(SCpnt));
+ scsi_set_resid(scp, scsi_bufflen(scp));
return check_condition_result;
}
read_lock_irqsave(&atomic_rw, iflags);
/* DIX + T10 DIF */
- if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
- int prot_ret = prot_verify_read(SCpnt, lba, num, ei_lba);
+ if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
+ int prot_ret = prot_verify_read(scp, lba, num, ei_lba);
if (prot_ret) {
read_unlock_irqrestore(&atomic_rw, iflags);
- mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, prot_ret);
+ mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, prot_ret);
return illegal_condition_result;
}
}
- ret = do_device_access(SCpnt, lba, num, 0);
+ ret = do_device_access(scp, lba, num, false);
read_unlock_irqrestore(&atomic_rw, iflags);
if (ret == -1)
return DID_ERROR << 16;
- scsi_in(SCpnt)->resid = scsi_bufflen(SCpnt) - ret;
+ scsi_in(scp)->resid = scsi_bufflen(scp) - ret;
+
+ if (sdebug_any_injecting_opt) {
+ struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
+ if (ep->inj_recovered) {
+ mk_sense_buffer(scp, RECOVERED_ERROR,
+ THRESHOLD_EXCEEDED, 0);
+ return check_condition_result;
+ } else if (ep->inj_transport) {
+ mk_sense_buffer(scp, ABORTED_COMMAND,
+ TRANSPORT_PROBLEM, ACK_NAK_TO);
+ return check_condition_result;
+ } else if (ep->inj_dif) {
+ /* Logical block guard check failed */
+ mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
+ return illegal_condition_result;
+ } else if (ep->inj_dix) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
+ return illegal_condition_result;
+ }
+ }
return 0;
}
@@ -2223,31 +2808,95 @@ static void unmap_region(sector_t lba, unsigned int len)
}
}
-static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
- unsigned int num, u32 ei_lba)
+static int
+resp_write_dt0(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
+ u8 *cmd = scp->cmnd;
+ u64 lba;
+ u32 num;
+ u32 ei_lba;
unsigned long iflags;
int ret;
+ bool check_prot;
- ret = check_device_access_params(SCpnt, lba, num);
- if (ret)
- return ret;
+ switch (cmd[0]) {
+ case WRITE_16:
+ ei_lba = 0;
+ lba = get_unaligned_be64(cmd + 2);
+ num = get_unaligned_be32(cmd + 10);
+ check_prot = true;
+ break;
+ case WRITE_10:
+ ei_lba = 0;
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be16(cmd + 7);
+ check_prot = true;
+ break;
+ case WRITE_6:
+ ei_lba = 0;
+ lba = (u32)cmd[3] | (u32)cmd[2] << 8 |
+ (u32)(cmd[1] & 0x1f) << 16;
+ num = (0 == cmd[4]) ? 256 : cmd[4];
+ check_prot = true;
+ break;
+ case WRITE_12:
+ ei_lba = 0;
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be32(cmd + 6);
+ check_prot = true;
+ break;
+ case 0x53: /* XDWRITEREAD(10) */
+ ei_lba = 0;
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be16(cmd + 7);
+ check_prot = false;
+ break;
+ default: /* assume WRITE(32) */
+ lba = get_unaligned_be64(cmd + 12);
+ ei_lba = get_unaligned_be32(cmd + 20);
+ num = get_unaligned_be32(cmd + 28);
+ check_prot = false;
+ break;
+ }
+ if (check_prot) {
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ (cmd[1] & 0xe0)) {
+ mk_sense_invalid_opcode(scp);
+ return check_condition_result;
+ }
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
+ "to DIF device\n");
+ }
+
+ /* inline check_device_access_params() */
+ if (lba + num > sdebug_capacity) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
+ return check_condition_result;
+ }
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ /* needs work to find which cdb byte 'num' comes from */
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
write_lock_irqsave(&atomic_rw, iflags);
/* DIX + T10 DIF */
- if (scsi_debug_dix && scsi_prot_sg_count(SCpnt)) {
- int prot_ret = prot_verify_write(SCpnt, lba, num, ei_lba);
+ if (scsi_debug_dix && scsi_prot_sg_count(scp)) {
+ int prot_ret = prot_verify_write(scp, lba, num, ei_lba);
if (prot_ret) {
write_unlock_irqrestore(&atomic_rw, iflags);
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10,
- prot_ret);
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, prot_ret);
return illegal_condition_result;
}
}
- ret = do_device_access(SCpnt, lba, num, 1);
+ ret = do_device_access(scp, lba, num, true);
if (scsi_debug_lbp())
map_region(lba, num);
write_unlock_irqrestore(&atomic_rw, iflags);
@@ -2255,30 +2904,41 @@ static int resp_write(struct scsi_cmnd *SCpnt, unsigned long long lba,
return (DID_ERROR << 16);
else if ((ret < (num * scsi_debug_sector_size)) &&
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
- sdev_printk(KERN_INFO, SCpnt->device,
+ sdev_printk(KERN_INFO, scp->device,
"%s: write: cdb indicated=%u, IO sent=%d bytes\n",
my_name, num * scsi_debug_sector_size, ret);
+ if (sdebug_any_injecting_opt) {
+ struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
+
+ if (ep->inj_recovered) {
+ mk_sense_buffer(scp, RECOVERED_ERROR,
+ THRESHOLD_EXCEEDED, 0);
+ return check_condition_result;
+ } else if (ep->inj_dif) {
+ /* Logical block guard check failed */
+ mk_sense_buffer(scp, ABORTED_COMMAND, 0x10, 1);
+ return illegal_condition_result;
+ } else if (ep->inj_dix) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, 0x10, 1);
+ return illegal_condition_result;
+ }
+ }
return 0;
}
-static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
- unsigned int num, u32 ei_lba, unsigned int unmap)
+static int
+resp_write_same(struct scsi_cmnd *scp, u64 lba, u32 num, u32 ei_lba,
+ bool unmap, bool ndob)
{
unsigned long iflags;
unsigned long long i;
int ret;
- ret = check_device_access_params(scmd, lba, num);
+ ret = check_device_access_params(scp, lba, num);
if (ret)
return ret;
- if (num > scsi_debug_write_same_length) {
- mk_sense_buffer(scmd, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
- 0);
- return check_condition_result;
- }
-
write_lock_irqsave(&atomic_rw, iflags);
if (unmap && scsi_debug_lbp()) {
@@ -2286,17 +2946,22 @@ static int resp_write_same(struct scsi_cmnd *scmd, unsigned long long lba,
goto out;
}
- /* Else fetch one logical block */
- ret = fetch_to_dev_buffer(scmd,
- fake_storep + (lba * scsi_debug_sector_size),
- scsi_debug_sector_size);
+ /* if ndob then zero 1 logical block, else fetch 1 logical block */
+ if (ndob) {
+ memset(fake_storep + (lba * scsi_debug_sector_size), 0,
+ scsi_debug_sector_size);
+ ret = 0;
+ } else
+ ret = fetch_to_dev_buffer(scp, fake_storep +
+ (lba * scsi_debug_sector_size),
+ scsi_debug_sector_size);
if (-1 == ret) {
write_unlock_irqrestore(&atomic_rw, iflags);
return (DID_ERROR << 16);
} else if ((ret < (num * scsi_debug_sector_size)) &&
(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
- sdev_printk(KERN_INFO, scmd->device,
+ sdev_printk(KERN_INFO, scp->device,
"%s: %s: cdb indicated=%u, IO sent=%d bytes\n",
my_name, "write same",
num * scsi_debug_sector_size, ret);
@@ -2315,13 +2980,143 @@ out:
return 0;
}
+static int
+resp_write_same_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ u8 *cmd = scp->cmnd;
+ u32 lba;
+ u16 num;
+ u32 ei_lba = 0;
+ bool unmap = false;
+
+ if (cmd[1] & 0x8) {
+ if (scsi_debug_lbpws10 == 0) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
+ return check_condition_result;
+ } else
+ unmap = true;
+ }
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be16(cmd + 7);
+ if (num > scsi_debug_write_same_length) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
+ return check_condition_result;
+ }
+ return resp_write_same(scp, lba, num, ei_lba, unmap, false);
+}
+
+static int
+resp_write_same_16(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ u8 *cmd = scp->cmnd;
+ u64 lba;
+ u32 num;
+ u32 ei_lba = 0;
+ bool unmap = false;
+ bool ndob = false;
+
+ if (cmd[1] & 0x8) { /* UNMAP */
+ if (scsi_debug_lbpws == 0) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 3);
+ return check_condition_result;
+ } else
+ unmap = true;
+ }
+ if (cmd[1] & 0x1) /* NDOB (no data-out buffer, assumes zeroes) */
+ ndob = true;
+ lba = get_unaligned_be64(cmd + 2);
+ num = get_unaligned_be32(cmd + 10);
+ if (num > scsi_debug_write_same_length) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 10, -1);
+ return check_condition_result;
+ }
+ return resp_write_same(scp, lba, num, ei_lba, unmap, ndob);
+}
+
+static int
+resp_comp_write(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ u8 *cmd = scp->cmnd;
+ u8 *arr;
+ u8 *fake_storep_hold;
+ u64 lba;
+ u32 dnum;
+ u32 lb_size = scsi_debug_sector_size;
+ u8 num;
+ unsigned long iflags;
+ int ret;
+
+ lba = get_unaligned_be32(cmd + 2);
+ num = cmd[13]; /* 1 to a maximum of 255 logical blocks */
+ if (0 == num)
+ return 0; /* degenerate case, not an error */
+ dnum = 2 * num;
+ arr = kzalloc(dnum * lb_size, GFP_ATOMIC);
+ if (NULL == arr) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+ INSUFF_RES_ASCQ);
+ return check_condition_result;
+ }
+ if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
+ (cmd[1] & 0xe0)) {
+ mk_sense_invalid_opcode(scp);
+ return check_condition_result;
+ }
+ if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
+ scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
+ (cmd[1] & 0xe0) == 0)
+ sdev_printk(KERN_ERR, scp->device, "Unprotected WR "
+ "to DIF device\n");
+
+ /* inline check_device_access_params() */
+ if (lba + num > sdebug_capacity) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, LBA_OUT_OF_RANGE, 0);
+ return check_condition_result;
+ }
+ /* transfer length excessive (tie in to block limits VPD page) */
+ if (num > sdebug_store_sectors) {
+ /* needs work to find which cdb byte 'num' comes from */
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB, 0);
+ return check_condition_result;
+ }
+
+ write_lock_irqsave(&atomic_rw, iflags);
+
+ /* trick do_device_access() to fetch both compare and write buffers
+ * from data-in into arr. Safe (atomic) since write_lock held. */
+ fake_storep_hold = fake_storep;
+ fake_storep = arr;
+ ret = do_device_access(scp, 0, dnum, true);
+ fake_storep = fake_storep_hold;
+ if (ret == -1) {
+ write_unlock_irqrestore(&atomic_rw, iflags);
+ kfree(arr);
+ return DID_ERROR << 16;
+ } else if ((ret < (dnum * lb_size)) &&
+ (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts))
+ sdev_printk(KERN_INFO, scp->device, "%s: compare_write: cdb "
+ "indicated=%u, IO sent=%d bytes\n", my_name,
+ dnum * lb_size, ret);
+ if (!comp_write_worker(lba, num, arr)) {
+ write_unlock_irqrestore(&atomic_rw, iflags);
+ kfree(arr);
+ mk_sense_buffer(scp, MISCOMPARE, MISCOMPARE_VERIFY_ASC, 0);
+ return check_condition_result;
+ }
+ if (scsi_debug_lbp())
+ map_region(lba, num);
+ write_unlock_irqrestore(&atomic_rw, iflags);
+ return 0;
+}
+
struct unmap_block_desc {
__be64 lba;
__be32 blocks;
__be32 __reserved;
};
-static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
+static int
+resp_unmap(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
unsigned char *buf;
struct unmap_block_desc *desc;
@@ -2329,20 +3124,26 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
int ret;
unsigned long iflags;
- ret = check_readiness(scmd, UAS_ONLY, devip);
- if (ret)
- return ret;
- payload_len = get_unaligned_be16(&scmd->cmnd[7]);
- BUG_ON(scsi_bufflen(scmd) != payload_len);
+ if (!scsi_debug_lbp())
+ return 0; /* fib and say its done */
+ payload_len = get_unaligned_be16(scp->cmnd + 7);
+ BUG_ON(scsi_bufflen(scp) != payload_len);
descriptors = (payload_len - 8) / 16;
+ if (descriptors > scsi_debug_unmap_max_desc) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 7, -1);
+ return check_condition_result;
+ }
- buf = kmalloc(scsi_bufflen(scmd), GFP_ATOMIC);
- if (!buf)
+ buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
+ if (!buf) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+ INSUFF_RES_ASCQ);
return check_condition_result;
+ }
- scsi_sg_copy_to_buffer(scmd, buf, scsi_bufflen(scmd));
+ scsi_sg_copy_to_buffer(scp, buf, scsi_bufflen(scp));
BUG_ON(get_unaligned_be16(&buf[0]) != payload_len - 2);
BUG_ON(get_unaligned_be16(&buf[2]) != descriptors * 16);
@@ -2355,7 +3156,7 @@ static int resp_unmap(struct scsi_cmnd * scmd, struct sdebug_dev_info * devip)
unsigned long long lba = get_unaligned_be64(&desc[i].lba);
unsigned int num = get_unaligned_be32(&desc[i].blocks);
- ret = check_device_access_params(scmd, lba, num);
+ ret = check_device_access_params(scp, lba, num);
if (ret)
goto out;
@@ -2373,37 +3174,44 @@ out:
#define SDEBUG_GET_LBA_STATUS_LEN 32
-static int resp_get_lba_status(struct scsi_cmnd * scmd,
- struct sdebug_dev_info * devip)
+static int
+resp_get_lba_status(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
{
- unsigned long long lba;
- unsigned int alloc_len, mapped, num;
- unsigned char arr[SDEBUG_GET_LBA_STATUS_LEN];
+ u8 *cmd = scp->cmnd;
+ u64 lba;
+ u32 alloc_len, mapped, num;
+ u8 arr[SDEBUG_GET_LBA_STATUS_LEN];
int ret;
- ret = check_readiness(scmd, UAS_ONLY, devip);
- if (ret)
- return ret;
-
- lba = get_unaligned_be64(&scmd->cmnd[2]);
- alloc_len = get_unaligned_be32(&scmd->cmnd[10]);
+ lba = get_unaligned_be64(cmd + 2);
+ alloc_len = get_unaligned_be32(cmd + 10);
if (alloc_len < 24)
return 0;
- ret = check_device_access_params(scmd, lba, 1);
+ ret = check_device_access_params(scp, lba, 1);
if (ret)
return ret;
- mapped = map_state(lba, &num);
+ if (scsi_debug_lbp())
+ mapped = map_state(lba, &num);
+ else {
+ mapped = 1;
+ /* following just in case virtual_gb changed */
+ sdebug_capacity = get_sdebug_capacity();
+ if (sdebug_capacity - lba <= 0xffffffff)
+ num = sdebug_capacity - lba;
+ else
+ num = 0xffffffff;
+ }
memset(arr, 0, SDEBUG_GET_LBA_STATUS_LEN);
- put_unaligned_be32(20, &arr[0]); /* Parameter Data Length */
- put_unaligned_be64(lba, &arr[8]); /* LBA */
- put_unaligned_be32(num, &arr[16]); /* Number of blocks */
- arr[20] = !mapped; /* mapped = 0, unmapped = 1 */
+ put_unaligned_be32(20, arr); /* Parameter Data Length */
+ put_unaligned_be64(lba, arr + 8); /* LBA */
+ put_unaligned_be32(num, arr + 16); /* Number of blocks */
+ arr[20] = !mapped; /* prov_stat=0: mapped; 1: dealloc */
- return fill_from_dev_buffer(scmd, arr, SDEBUG_GET_LBA_STATUS_LEN);
+ return fill_from_dev_buffer(scp, arr, SDEBUG_GET_LBA_STATUS_LEN);
}
#define SDEBUG_RLUN_ARR_SZ 256
@@ -2412,8 +3220,8 @@ static int resp_report_luns(struct scsi_cmnd * scp,
struct sdebug_dev_info * devip)
{
unsigned int alloc_len;
- int lun_cnt, i, upper, num, n;
- u64 wlun, lun;
+ int lun_cnt, i, upper, num, n, want_wlun, shortish;
+ u64 lun;
unsigned char *cmd = scp->cmnd;
int select_report = (int)cmd[2];
struct scsi_lun *one_lun;
@@ -2421,9 +3229,9 @@ static int resp_report_luns(struct scsi_cmnd * scp,
unsigned char * max_addr;
alloc_len = cmd[9] + (cmd[8] << 8) + (cmd[7] << 16) + (cmd[6] << 24);
- if ((alloc_len < 4) || (select_report > 2)) {
- mk_sense_buffer(scp, ILLEGAL_REQUEST, INVALID_FIELD_IN_CDB,
- 0);
+ shortish = (alloc_len < 4);
+ if (shortish || (select_report > 2)) {
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, shortish ? 6 : 2, -1);
return check_condition_result;
}
/* can produce response with up to 16k luns (lun 0 to lun 16383) */
@@ -2433,14 +3241,14 @@ static int resp_report_luns(struct scsi_cmnd * scp,
lun_cnt = 0;
else if (scsi_debug_no_lun_0 && (lun_cnt > 0))
--lun_cnt;
- wlun = (select_report > 0) ? 1 : 0;
- num = lun_cnt + wlun;
+ want_wlun = (select_report > 0) ? 1 : 0;
+ num = lun_cnt + want_wlun;
arr[2] = ((sizeof(struct scsi_lun) * num) >> 8) & 0xff;
arr[3] = (sizeof(struct scsi_lun) * num) & 0xff;
n = min((int)((SDEBUG_RLUN_ARR_SZ - 8) /
sizeof(struct scsi_lun)), num);
if (n < num) {
- wlun = 0;
+ want_wlun = 0;
lun_cnt = n;
}
one_lun = (struct scsi_lun *) &arr[8];
@@ -2454,7 +3262,7 @@ static int resp_report_luns(struct scsi_cmnd * scp,
(upper | (SAM2_LUN_ADDRESS_METHOD << 6));
one_lun[i].scsi_lun[1] = lun & 0xff;
}
- if (wlun) {
+ if (want_wlun) {
one_lun[i].scsi_lun[0] = (SAM2_WLUN_REPORT_LUNS >> 8) & 0xff;
one_lun[i].scsi_lun[1] = SAM2_WLUN_REPORT_LUNS & 0xff;
i++;
@@ -2476,8 +3284,8 @@ static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
/* better not to use temporary buffer. */
buf = kmalloc(scsi_bufflen(scp), GFP_ATOMIC);
if (!buf) {
- mk_sense_buffer(scp, NOT_READY,
- LOGICAL_UNIT_COMMUNICATION_FAILURE, 0);
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+ INSUFF_RES_ASCQ);
return check_condition_result;
}
@@ -2500,6 +3308,32 @@ static int resp_xdwriteread(struct scsi_cmnd *scp, unsigned long long lba,
return 0;
}
+static int
+resp_xdwriteread_10(struct scsi_cmnd *scp, struct sdebug_dev_info *devip)
+{
+ u8 *cmd = scp->cmnd;
+ u64 lba;
+ u32 num;
+ int errsts;
+
+ if (!scsi_bidi_cmnd(scp)) {
+ mk_sense_buffer(scp, ILLEGAL_REQUEST, INSUFF_RES_ASC,
+ INSUFF_RES_ASCQ);
+ return check_condition_result;
+ }
+ errsts = resp_read_dt0(scp, devip);
+ if (errsts)
+ return errsts;
+ if (!(cmd[1] & 0x4)) { /* DISABLE_WRITE is not set */
+ errsts = resp_write_dt0(scp, devip);
+ if (errsts)
+ return errsts;
+ }
+ lba = get_unaligned_be32(cmd + 2);
+ num = get_unaligned_be16(cmd + 7);
+ return resp_xdwriteread(scp, lba, num, devip);
+}
+
/* When timer or tasklet goes off this function is called. */
static void sdebug_q_cmd_complete(unsigned long indx)
{
@@ -2672,10 +3506,7 @@ static struct sdebug_dev_info * devInfoReg(struct scsi_device * sdev)
open_devip->sdbg_host = sdbg_host;
atomic_set(&open_devip->num_in_q, 0);
set_bit(SDEBUG_UA_POR, open_devip->uas_bm);
- open_devip->used = 1;
- if (sdev->lun == SAM2_WLUN_REPORT_LUNS)
- open_devip->wlun = SAM2_WLUN_REPORT_LUNS & 0xff;
-
+ open_devip->used = true;
return open_devip;
}
@@ -2701,10 +3532,6 @@ static int scsi_debug_slave_configure(struct scsi_device *sdp)
if (NULL == devip)
return 1; /* no resources, will be marked offline */
sdp->hostdata = devip;
- sdp->tagged_supported = 1;
- if (sdp->host->cmd_per_lun)
- scsi_adjust_queue_depth(sdp, DEF_TAGGED_QUEUING,
- DEF_CMD_PER_LUN);
blk_queue_max_segment_size(sdp->request_queue, -1U);
if (scsi_debug_no_uld)
sdp->no_uld_attach = 1;
@@ -2721,7 +3548,7 @@ static void scsi_debug_slave_destroy(struct scsi_device *sdp)
sdp->host->host_no, sdp->channel, sdp->id, sdp->lun);
if (devip) {
/* make this slot available for re-use */
- devip->used = 0;
+ devip->used = false;
sdp->hostdata = NULL;
}
}
@@ -3166,6 +3993,7 @@ module_param_named(ptype, scsi_debug_ptype, int, S_IRUGO | S_IWUSR);
module_param_named(removable, scsi_debug_removable, bool, S_IRUGO | S_IWUSR);
module_param_named(scsi_level, scsi_debug_scsi_level, int, S_IRUGO);
module_param_named(sector_size, scsi_debug_sector_size, int, S_IRUGO);
+module_param_named(strict, scsi_debug_strict, bool, S_IRUGO | S_IWUSR);
module_param_named(unmap_alignment, scsi_debug_unmap_alignment, int, S_IRUGO);
module_param_named(unmap_granularity, scsi_debug_unmap_granularity, int, S_IRUGO);
module_param_named(unmap_max_blocks, scsi_debug_unmap_max_blocks, int, S_IRUGO);
@@ -3185,7 +4013,7 @@ MODULE_PARM_DESC(add_host, "0..127 hosts allowed(def=1)");
MODULE_PARM_DESC(ato, "application tag ownership: 0=disk 1=host (def=1)");
MODULE_PARM_DESC(clustering, "when set enables larger transfers (def=0)");
MODULE_PARM_DESC(delay, "response delay (def=1 jiffy); 0:imm, -1,-2:tiny");
-MODULE_PARM_DESC(dev_size_mb, "size in MB of ram shared by devs(def=8)");
+MODULE_PARM_DESC(dev_size_mb, "size in MiB of ram shared by devs(def=8)");
MODULE_PARM_DESC(dif, "data integrity field type: 0-3 (def=0)");
MODULE_PARM_DESC(dix, "data integrity extensions mask (def=0)");
MODULE_PARM_DESC(dsense, "use descriptor sense format(def=0 -> fixed)");
@@ -3212,11 +4040,12 @@ MODULE_PARM_DESC(ptype, "SCSI peripheral type(def=0[disk])");
MODULE_PARM_DESC(removable, "claim to have removable media (def=0)");
MODULE_PARM_DESC(scsi_level, "SCSI level to simulate(def=6[SPC-4])");
MODULE_PARM_DESC(sector_size, "logical block size in bytes (def=512)");
+MODULE_PARM_DESC(strict, "stricter checks: reserved field in cdb (def=0)");
MODULE_PARM_DESC(unmap_alignment, "lowest aligned thin provisioning lba (def=0)");
MODULE_PARM_DESC(unmap_granularity, "thin provisioning granularity in blocks (def=1)");
MODULE_PARM_DESC(unmap_max_blocks, "max # of blocks can be unmapped in one cmd (def=0xffffffff)");
MODULE_PARM_DESC(unmap_max_desc, "max # of ranges that can be unmapped in one cmd (def=256)");
-MODULE_PARM_DESC(virtual_gb, "virtual gigabyte size (def=0 -> use dev_size_mb)");
+MODULE_PARM_DESC(virtual_gb, "virtual gigabyte (GiB) size (def=0 -> use dev_size_mb)");
MODULE_PARM_DESC(vpd_use_hostno, "0 -> dev ids ignore hostno (def=1 -> unique dev ids)");
MODULE_PARM_DESC(write_same_length, "Maximum blocks per WRITE SAME cmd (def=0xffff)");
@@ -3382,6 +4211,16 @@ static ssize_t opts_store(struct device_driver *ddp, const char *buf,
return -EINVAL;
opts_done:
scsi_debug_opts = opts;
+ if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
+ sdebug_any_injecting_opt = true;
atomic_set(&sdebug_cmnd_count, 0);
atomic_set(&sdebug_a_tsf, 0);
return count;
@@ -3589,12 +4428,25 @@ static ssize_t virtual_gb_store(struct device_driver *ddp, const char *buf,
size_t count)
{
int n;
+ bool changed;
if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ changed = (scsi_debug_virtual_gb != n);
scsi_debug_virtual_gb = n;
-
sdebug_capacity = get_sdebug_capacity();
-
+ if (changed) {
+ struct sdebug_host_info *sdhp;
+ struct sdebug_dev_info *dp;
+
+ list_for_each_entry(sdhp, &sdebug_host_list,
+ host_list) {
+ list_for_each_entry(dp, &sdhp->dev_info_list,
+ dev_list) {
+ set_bit(SDEBUG_UA_CAPACITY_CHANGED,
+ dp->uas_bm);
+ }
+ }
+ }
return count;
}
return -EINVAL;
@@ -3740,6 +4592,23 @@ static ssize_t host_lock_store(struct device_driver *ddp, const char *buf,
}
static DRIVER_ATTR_RW(host_lock);
+static ssize_t strict_show(struct device_driver *ddp, char *buf)
+{
+ return scnprintf(buf, PAGE_SIZE, "%d\n", !!scsi_debug_strict);
+}
+static ssize_t strict_store(struct device_driver *ddp, const char *buf,
+ size_t count)
+{
+ int n;
+
+ if ((count > 0) && (1 == sscanf(buf, "%d", &n)) && (n >= 0)) {
+ scsi_debug_strict = (n > 0);
+ return count;
+ }
+ return -EINVAL;
+}
+static DRIVER_ATTR_RW(strict);
+
/* Note: The following array creates attribute files in the
/sys/bus/pseudo/drivers/scsi_debug directory. The advantage of these
@@ -3775,6 +4644,7 @@ static struct attribute *sdebug_drv_attrs[] = {
&driver_attr_removable.attr,
&driver_attr_host_lock.attr,
&driver_attr_ndelay.attr,
+ &driver_attr_strict.attr,
NULL,
};
ATTRIBUTE_GROUPS(sdebug_drv);
@@ -4087,396 +4957,9 @@ static void sdebug_remove_adapter(void)
}
static int
-scsi_debug_queuecommand(struct scsi_cmnd *SCpnt)
-{
- unsigned char *cmd = SCpnt->cmnd;
- int len, k;
- unsigned int num;
- unsigned long long lba;
- u32 ei_lba;
- int errsts = 0;
- int target = SCpnt->device->id;
- struct sdebug_dev_info *devip = NULL;
- int inj_recovered = 0;
- int inj_transport = 0;
- int inj_dif = 0;
- int inj_dix = 0;
- int inj_short = 0;
- int delay_override = 0;
- int unmap = 0;
-
- scsi_set_resid(SCpnt, 0);
- if ((SCSI_DEBUG_OPT_NOISE & scsi_debug_opts) &&
- !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
- char b[120];
- int n;
-
- len = SCpnt->cmd_len;
- if (len > 32)
- strcpy(b, "too long, over 32 bytes");
- else {
- for (k = 0, n = 0; k < len; ++k)
- n += scnprintf(b + n, sizeof(b) - n, "%02x ",
- (unsigned int)cmd[k]);
- }
- sdev_printk(KERN_INFO, SCpnt->device, "%s: cmd %s\n", my_name,
- b);
- }
-
- if ((SCpnt->device->lun >= scsi_debug_max_luns) &&
- (SCpnt->device->lun != SAM2_WLUN_REPORT_LUNS))
- return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
- devip = devInfoReg(SCpnt->device);
- if (NULL == devip)
- return schedule_resp(SCpnt, NULL, DID_NO_CONNECT << 16, 0);
-
- if ((scsi_debug_every_nth != 0) &&
- (atomic_inc_return(&sdebug_cmnd_count) >=
- abs(scsi_debug_every_nth))) {
- atomic_set(&sdebug_cmnd_count, 0);
- if (scsi_debug_every_nth < -1)
- scsi_debug_every_nth = -1;
- if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
- return 0; /* ignore command causing timeout */
- else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
- scsi_medium_access_command(SCpnt))
- return 0; /* time out reads and writes */
- else if (SCSI_DEBUG_OPT_RECOVERED_ERR & scsi_debug_opts)
- inj_recovered = 1; /* to reads and writes below */
- else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & scsi_debug_opts)
- inj_transport = 1; /* to reads and writes below */
- else if (SCSI_DEBUG_OPT_DIF_ERR & scsi_debug_opts)
- inj_dif = 1; /* to reads and writes below */
- else if (SCSI_DEBUG_OPT_DIX_ERR & scsi_debug_opts)
- inj_dix = 1; /* to reads and writes below */
- else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & scsi_debug_opts)
- inj_short = 1;
- }
-
- if (devip->wlun) {
- switch (*cmd) {
- case INQUIRY:
- case REQUEST_SENSE:
- case TEST_UNIT_READY:
- case REPORT_LUNS:
- break; /* only allowable wlun commands */
- default:
- if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- printk(KERN_INFO "scsi_debug: Opcode: 0x%x "
- "not supported for wlun\n", *cmd);
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_OPCODE, 0);
- errsts = check_condition_result;
- return schedule_resp(SCpnt, devip, errsts, 0);
- }
- }
-
- switch (*cmd) {
- case INQUIRY: /* mandatory, ignore unit attention */
- delay_override = 1;
- errsts = resp_inquiry(SCpnt, target, devip);
- break;
- case REQUEST_SENSE: /* mandatory, ignore unit attention */
- delay_override = 1;
- errsts = resp_requests(SCpnt, devip);
- break;
- case REZERO_UNIT: /* actually this is REWIND for SSC */
- case START_STOP:
- errsts = resp_start_stop(SCpnt, devip);
- break;
- case ALLOW_MEDIUM_REMOVAL:
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- if (errsts)
- break;
- if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- printk(KERN_INFO "scsi_debug: Medium removal %s\n",
- cmd[4] ? "inhibited" : "enabled");
- break;
- case SEND_DIAGNOSTIC: /* mandatory */
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- break;
- case TEST_UNIT_READY: /* mandatory */
- /* delay_override = 1; */
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- break;
- case RESERVE:
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- break;
- case RESERVE_10:
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- break;
- case RELEASE:
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- break;
- case RELEASE_10:
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- break;
- case READ_CAPACITY:
- errsts = resp_readcap(SCpnt, devip);
- break;
- case SERVICE_ACTION_IN:
- if (cmd[1] == SAI_READ_CAPACITY_16)
- errsts = resp_readcap16(SCpnt, devip);
- else if (cmd[1] == SAI_GET_LBA_STATUS) {
-
- if (scsi_debug_lbp() == 0) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_COMMAND_OPCODE, 0);
- errsts = check_condition_result;
- } else
- errsts = resp_get_lba_status(SCpnt, devip);
- } else {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_OPCODE, 0);
- errsts = check_condition_result;
- }
- break;
- case MAINTENANCE_IN:
- if (MI_REPORT_TARGET_PGS != cmd[1]) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_OPCODE, 0);
- errsts = check_condition_result;
- break;
- }
- errsts = resp_report_tgtpgs(SCpnt, devip);
- break;
- case READ_16:
- case READ_12:
- case READ_10:
- /* READ{10,12,16} and DIF Type 2 are natural enemies */
- if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
- cmd[1] & 0xe0) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_COMMAND_OPCODE, 0);
- errsts = check_condition_result;
- break;
- }
-
- if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
- scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
- (cmd[1] & 0xe0) == 0)
- printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
-
- /* fall through */
- case READ_6:
-read:
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- if (errsts)
- break;
- if (scsi_debug_fake_rw)
- break;
- get_data_transfer_info(cmd, &lba, &num, &ei_lba);
-
- if (inj_short)
- num /= 2;
-
- errsts = resp_read(SCpnt, lba, num, ei_lba);
- if (inj_recovered && (0 == errsts)) {
- mk_sense_buffer(SCpnt, RECOVERED_ERROR,
- THRESHOLD_EXCEEDED, 0);
- errsts = check_condition_result;
- } else if (inj_transport && (0 == errsts)) {
- mk_sense_buffer(SCpnt, ABORTED_COMMAND,
- TRANSPORT_PROBLEM, ACK_NAK_TO);
- errsts = check_condition_result;
- } else if (inj_dif && (0 == errsts)) {
- /* Logical block guard check failed */
- mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
- errsts = illegal_condition_result;
- } else if (inj_dix && (0 == errsts)) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
- errsts = illegal_condition_result;
- }
- break;
- case REPORT_LUNS: /* mandatory, ignore unit attention */
- delay_override = 1;
- errsts = resp_report_luns(SCpnt, devip);
- break;
- case VERIFY: /* 10 byte SBC-2 command */
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- break;
- case WRITE_16:
- case WRITE_12:
- case WRITE_10:
- /* WRITE{10,12,16} and DIF Type 2 are natural enemies */
- if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION &&
- cmd[1] & 0xe0) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_COMMAND_OPCODE, 0);
- errsts = check_condition_result;
- break;
- }
-
- if ((scsi_debug_dif == SD_DIF_TYPE1_PROTECTION ||
- scsi_debug_dif == SD_DIF_TYPE3_PROTECTION) &&
- (cmd[1] & 0xe0) == 0)
- printk(KERN_ERR "Unprotected RD/WR to DIF device\n");
-
- /* fall through */
- case WRITE_6:
-write:
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- if (errsts)
- break;
- if (scsi_debug_fake_rw)
- break;
- get_data_transfer_info(cmd, &lba, &num, &ei_lba);
- errsts = resp_write(SCpnt, lba, num, ei_lba);
- if (inj_recovered && (0 == errsts)) {
- mk_sense_buffer(SCpnt, RECOVERED_ERROR,
- THRESHOLD_EXCEEDED, 0);
- errsts = check_condition_result;
- } else if (inj_dif && (0 == errsts)) {
- mk_sense_buffer(SCpnt, ABORTED_COMMAND, 0x10, 1);
- errsts = illegal_condition_result;
- } else if (inj_dix && (0 == errsts)) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, 0x10, 1);
- errsts = illegal_condition_result;
- }
- break;
- case WRITE_SAME_16:
- case WRITE_SAME:
- if (cmd[1] & 0x8) {
- if ((*cmd == WRITE_SAME_16 && scsi_debug_lbpws == 0) ||
- (*cmd == WRITE_SAME && scsi_debug_lbpws10 == 0)) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
- errsts = check_condition_result;
- } else
- unmap = 1;
- }
- if (errsts)
- break;
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- if (errsts)
- break;
- if (scsi_debug_fake_rw)
- break;
- get_data_transfer_info(cmd, &lba, &num, &ei_lba);
- errsts = resp_write_same(SCpnt, lba, num, ei_lba, unmap);
- break;
- case UNMAP:
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- if (errsts)
- break;
- if (scsi_debug_fake_rw)
- break;
-
- if (scsi_debug_unmap_max_desc == 0 || scsi_debug_lbpu == 0) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_COMMAND_OPCODE, 0);
- errsts = check_condition_result;
- } else
- errsts = resp_unmap(SCpnt, devip);
- break;
- case MODE_SENSE:
- case MODE_SENSE_10:
- errsts = resp_mode_sense(SCpnt, target, devip);
- break;
- case MODE_SELECT:
- errsts = resp_mode_select(SCpnt, 1, devip);
- break;
- case MODE_SELECT_10:
- errsts = resp_mode_select(SCpnt, 0, devip);
- break;
- case LOG_SENSE:
- errsts = resp_log_sense(SCpnt, devip);
- break;
- case SYNCHRONIZE_CACHE:
- delay_override = 1;
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- break;
- case WRITE_BUFFER:
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- break;
- case XDWRITEREAD_10:
- if (!scsi_bidi_cmnd(SCpnt)) {
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
- errsts = check_condition_result;
- break;
- }
-
- errsts = check_readiness(SCpnt, UAS_TUR, devip);
- if (errsts)
- break;
- if (scsi_debug_fake_rw)
- break;
- get_data_transfer_info(cmd, &lba, &num, &ei_lba);
- errsts = resp_read(SCpnt, lba, num, ei_lba);
- if (errsts)
- break;
- errsts = resp_write(SCpnt, lba, num, ei_lba);
- if (errsts)
- break;
- errsts = resp_xdwriteread(SCpnt, lba, num, devip);
- break;
- case VARIABLE_LENGTH_CMD:
- if (scsi_debug_dif == SD_DIF_TYPE2_PROTECTION) {
-
- if ((cmd[10] & 0xe0) == 0)
- printk(KERN_ERR
- "Unprotected RD/WR to DIF device\n");
-
- if (cmd[9] == READ_32) {
- BUG_ON(SCpnt->cmd_len < 32);
- goto read;
- }
-
- if (cmd[9] == WRITE_32) {
- BUG_ON(SCpnt->cmd_len < 32);
- goto write;
- }
- }
-
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_FIELD_IN_CDB, 0);
- errsts = check_condition_result;
- break;
- case 0x85:
- if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, SCpnt->device,
- "%s: ATA PASS-THROUGH(16) not supported\n", my_name);
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST,
- INVALID_OPCODE, 0);
- errsts = check_condition_result;
- break;
- default:
- if (SCSI_DEBUG_OPT_NOISE & scsi_debug_opts)
- sdev_printk(KERN_INFO, SCpnt->device,
- "%s: Opcode: 0x%x not supported\n",
- my_name, *cmd);
- errsts = check_readiness(SCpnt, UAS_ONLY, devip);
- if (errsts)
- break; /* Unit attention takes precedence */
- mk_sense_buffer(SCpnt, ILLEGAL_REQUEST, INVALID_OPCODE, 0);
- errsts = check_condition_result;
- break;
- }
- return schedule_resp(SCpnt, devip, errsts,
- (delay_override ? 0 : scsi_debug_delay));
-}
-
-static int
-sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
-{
- if (scsi_debug_host_lock) {
- unsigned long iflags;
- int rc;
-
- spin_lock_irqsave(shost->host_lock, iflags);
- rc = scsi_debug_queuecommand(cmd);
- spin_unlock_irqrestore(shost->host_lock, iflags);
- return rc;
- } else
- return scsi_debug_queuecommand(cmd);
-}
-
-static int
-sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason)
+sdebug_change_qdepth(struct scsi_device *sdev, int qdepth)
{
int num_in_q = 0;
- int bad = 0;
unsigned long iflags;
struct sdebug_dev_info *devip;
@@ -4488,43 +4971,18 @@ sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason)
}
num_in_q = atomic_read(&devip->num_in_q);
spin_unlock_irqrestore(&queued_arr_lock, iflags);
- if (reason == SCSI_QDEPTH_DEFAULT || reason == SCSI_QDEPTH_RAMP_UP) {
- if (qdepth < 1)
- qdepth = 1;
- /* allow to exceed max host queued_arr elements for testing */
- if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
- qdepth = SCSI_DEBUG_CANQUEUE + 10;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
- } else if (reason == SCSI_QDEPTH_QFULL)
- scsi_track_queue_full(sdev, qdepth);
- else
- bad = 1;
- if (bad)
- sdev_printk(KERN_WARNING, sdev,
- "%s: unknown reason=0x%x\n", __func__, reason);
+
+ if (qdepth < 1)
+ qdepth = 1;
+ /* allow to exceed max host queued_arr elements for testing */
+ if (qdepth > SCSI_DEBUG_CANQUEUE + 10)
+ qdepth = SCSI_DEBUG_CANQUEUE + 10;
+ scsi_change_queue_depth(sdev, qdepth);
+
if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
- if (SCSI_QDEPTH_QFULL == reason)
- sdev_printk(KERN_INFO, sdev,
- "%s: -> %d, num_in_q=%d, reason: queue full\n",
- __func__, qdepth, num_in_q);
- else {
- const char *cp;
-
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- cp = "default (sysfs ?)";
- break;
- case SCSI_QDEPTH_RAMP_UP:
- cp = "ramp up";
- break;
- default:
- cp = "unknown";
- break;
- }
- sdev_printk(KERN_INFO, sdev,
- "%s: qdepth=%d, num_in_q=%d, reason: %s\n",
- __func__, qdepth, num_in_q, cp);
- }
+ sdev_printk(KERN_INFO, sdev,
+ "%s: qdepth=%d, num_in_q=%d\n",
+ __func__, qdepth, num_in_q);
}
return sdev->queue_depth;
}
@@ -4532,14 +4990,7 @@ sdebug_change_qdepth(struct scsi_device *sdev, int qdepth, int reason)
static int
sdebug_change_qtype(struct scsi_device *sdev, int qtype)
{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, qtype);
- if (qtype)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- qtype = 0;
+ qtype = scsi_change_queue_type(sdev, qtype);
if (SCSI_DEBUG_OPT_Q_NOISE & scsi_debug_opts) {
const char *cp;
@@ -4562,6 +5013,193 @@ sdebug_change_qtype(struct scsi_device *sdev, int qtype)
return qtype;
}
+static int
+check_inject(struct scsi_cmnd *scp)
+{
+ struct sdebug_scmd_extra_t *ep = scsi_cmd_priv(scp);
+
+ memset(ep, 0, sizeof(struct sdebug_scmd_extra_t));
+
+ if (atomic_inc_return(&sdebug_cmnd_count) >=
+ abs(scsi_debug_every_nth)) {
+ atomic_set(&sdebug_cmnd_count, 0);
+ if (scsi_debug_every_nth < -1)
+ scsi_debug_every_nth = -1;
+ if (SCSI_DEBUG_OPT_TIMEOUT & scsi_debug_opts)
+ return 1; /* ignore command causing timeout */
+ else if (SCSI_DEBUG_OPT_MAC_TIMEOUT & scsi_debug_opts &&
+ scsi_medium_access_command(scp))
+ return 1; /* time out reads and writes */
+ if (sdebug_any_injecting_opt) {
+ int opts = scsi_debug_opts;
+
+ if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
+ ep->inj_recovered = true;
+ else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
+ ep->inj_transport = true;
+ else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
+ ep->inj_dif = true;
+ else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
+ ep->inj_dix = true;
+ else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
+ ep->inj_short = true;
+ }
+ }
+ return 0;
+}
+
+static int
+scsi_debug_queuecommand(struct scsi_cmnd *scp)
+{
+ u8 sdeb_i;
+ struct scsi_device *sdp = scp->device;
+ const struct opcode_info_t *oip;
+ const struct opcode_info_t *r_oip;
+ struct sdebug_dev_info *devip;
+ u8 *cmd = scp->cmnd;
+ int (*r_pfp)(struct scsi_cmnd *, struct sdebug_dev_info *);
+ int k, na;
+ int errsts = 0;
+ int errsts_no_connect = DID_NO_CONNECT << 16;
+ u32 flags;
+ u16 sa;
+ u8 opcode = cmd[0];
+ bool has_wlun_rl;
+ bool debug = !!(SCSI_DEBUG_OPT_NOISE & scsi_debug_opts);
+
+ scsi_set_resid(scp, 0);
+ if (debug && !(SCSI_DEBUG_OPT_NO_CDB_NOISE & scsi_debug_opts)) {
+ char b[120];
+ int n, len, sb;
+
+ len = scp->cmd_len;
+ sb = (int)sizeof(b);
+ if (len > 32)
+ strcpy(b, "too long, over 32 bytes");
+ else {
+ for (k = 0, n = 0; k < len && n < sb; ++k)
+ n += scnprintf(b + n, sb - n, "%02x ",
+ (u32)cmd[k]);
+ }
+ sdev_printk(KERN_INFO, sdp, "%s: cmd %s\n", my_name, b);
+ }
+ has_wlun_rl = (sdp->lun == SAM2_WLUN_REPORT_LUNS);
+ if ((sdp->lun >= scsi_debug_max_luns) && !has_wlun_rl)
+ return schedule_resp(scp, NULL, errsts_no_connect, 0);
+
+ sdeb_i = opcode_ind_arr[opcode]; /* fully mapped */
+ oip = &opcode_info_arr[sdeb_i]; /* safe if table consistent */
+ devip = (struct sdebug_dev_info *)sdp->hostdata;
+ if (!devip) {
+ devip = devInfoReg(sdp);
+ if (NULL == devip)
+ return schedule_resp(scp, NULL, errsts_no_connect, 0);
+ }
+ na = oip->num_attached;
+ r_pfp = oip->pfp;
+ if (na) { /* multiple commands with this opcode */
+ r_oip = oip;
+ if (FF_SA & r_oip->flags) {
+ if (F_SA_LOW & oip->flags)
+ sa = 0x1f & cmd[1];
+ else
+ sa = get_unaligned_be16(cmd + 8);
+ for (k = 0; k <= na; oip = r_oip->arrp + k++) {
+ if (opcode == oip->opcode && sa == oip->sa)
+ break;
+ }
+ } else { /* since no service action only check opcode */
+ for (k = 0; k <= na; oip = r_oip->arrp + k++) {
+ if (opcode == oip->opcode)
+ break;
+ }
+ }
+ if (k > na) {
+ if (F_SA_LOW & r_oip->flags)
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 1, 4);
+ else if (F_SA_HIGH & r_oip->flags)
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, 8, 7);
+ else
+ mk_sense_invalid_opcode(scp);
+ goto check_cond;
+ }
+ } /* else (when na==0) we assume the oip is a match */
+ flags = oip->flags;
+ if (F_INV_OP & flags) {
+ mk_sense_invalid_opcode(scp);
+ goto check_cond;
+ }
+ if (has_wlun_rl && !(F_RL_WLUN_OK & flags)) {
+ if (debug)
+ sdev_printk(KERN_INFO, sdp, "scsi_debug: Opcode: "
+ "0x%x not supported for wlun\n", opcode);
+ mk_sense_invalid_opcode(scp);
+ goto check_cond;
+ }
+ if (scsi_debug_strict) { /* check cdb against mask */
+ u8 rem;
+ int j;
+
+ for (k = 1; k < oip->len_mask[0] && k < 16; ++k) {
+ rem = ~oip->len_mask[k] & cmd[k];
+ if (rem) {
+ for (j = 7; j >= 0; --j, rem <<= 1) {
+ if (0x80 & rem)
+ break;
+ }
+ mk_sense_invalid_fld(scp, SDEB_IN_CDB, k, j);
+ goto check_cond;
+ }
+ }
+ }
+ if (!(F_SKIP_UA & flags) &&
+ SDEBUG_NUM_UAS != find_first_bit(devip->uas_bm, SDEBUG_NUM_UAS)) {
+ errsts = check_readiness(scp, UAS_ONLY, devip);
+ if (errsts)
+ goto check_cond;
+ }
+ if ((F_M_ACCESS & flags) && devip->stopped) {
+ mk_sense_buffer(scp, NOT_READY, LOGICAL_UNIT_NOT_READY, 0x2);
+ if (debug)
+ sdev_printk(KERN_INFO, sdp, "%s reports: Not ready: "
+ "%s\n", my_name, "initializing command "
+ "required");
+ errsts = check_condition_result;
+ goto fini;
+ }
+ if (scsi_debug_fake_rw && (F_FAKE_RW & flags))
+ goto fini;
+ if (scsi_debug_every_nth) {
+ if (check_inject(scp))
+ return 0; /* ignore command: make trouble */
+ }
+ if (oip->pfp) /* if this command has a resp_* function, call it */
+ errsts = oip->pfp(scp, devip);
+ else if (r_pfp) /* if leaf function ptr NULL, try the root's */
+ errsts = r_pfp(scp, devip);
+
+fini:
+ return schedule_resp(scp, devip, errsts,
+ ((F_DELAY_OVERR & flags) ? 0 : scsi_debug_delay));
+check_cond:
+ return schedule_resp(scp, devip, check_condition_result, 0);
+}
+
+static int
+sdebug_queuecommand_lock_or_not(struct Scsi_Host *shost, struct scsi_cmnd *cmd)
+{
+ if (scsi_debug_host_lock) {
+ unsigned long iflags;
+ int rc;
+
+ spin_lock_irqsave(shost->host_lock, iflags);
+ rc = scsi_debug_queuecommand(cmd);
+ spin_unlock_irqrestore(shost->host_lock, iflags);
+ return rc;
+ } else
+ return scsi_debug_queuecommand(cmd);
+}
+
static struct scsi_host_template sdebug_driver_template = {
.show_info = scsi_debug_show_info,
.write_info = scsi_debug_write_info,
@@ -4587,13 +5225,16 @@ static struct scsi_host_template sdebug_driver_template = {
.max_sectors = -1U,
.use_clustering = DISABLE_CLUSTERING,
.module = THIS_MODULE,
+ .track_queue_depth = 1,
+ .cmd_size = sizeof(struct sdebug_scmd_extra_t),
};
static int sdebug_driver_probe(struct device * dev)
{
- int error = 0;
- struct sdebug_host_info *sdbg_host;
- struct Scsi_Host *hpnt;
+ int error = 0;
+ int opts;
+ struct sdebug_host_info *sdbg_host;
+ struct Scsi_Host *hpnt;
int host_prot;
sdbg_host = to_sdebug_host(dev);
@@ -4603,7 +5244,7 @@ static int sdebug_driver_probe(struct device * dev)
sdebug_driver_template.use_clustering = ENABLE_CLUSTERING;
hpnt = scsi_host_alloc(&sdebug_driver_template, sizeof(sdbg_host));
if (NULL == hpnt) {
- printk(KERN_ERR "%s: scsi_register failed\n", __func__);
+ pr_err("%s: scsi_host_alloc failed\n", __func__);
error = -ENODEV;
return error;
}
@@ -4660,6 +5301,18 @@ static int sdebug_driver_probe(struct device * dev)
else
scsi_host_set_guard(hpnt, SHOST_DIX_GUARD_CRC);
+ opts = scsi_debug_opts;
+ if (SCSI_DEBUG_OPT_RECOVERED_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_TRANSPORT_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_DIF_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_DIX_ERR & opts)
+ sdebug_any_injecting_opt = true;
+ else if (SCSI_DEBUG_OPT_SHORT_TRANSFER & opts)
+ sdebug_any_injecting_opt = true;
+
error = scsi_add_host(hpnt, &sdbg_host->dev);
if (error) {
printk(KERN_ERR "%s: scsi_add_host failed\n", __func__);
diff --git a/drivers/scsi/scsi_error.c b/drivers/scsi/scsi_error.c
index bc5ff6f..e42fff6 100644
--- a/drivers/scsi/scsi_error.c
+++ b/drivers/scsi/scsi_error.c
@@ -36,6 +36,7 @@
#include <scsi/scsi_transport.h>
#include <scsi/scsi_host.h>
#include <scsi/scsi_ioctl.h>
+#include <scsi/sg.h>
#include "scsi_priv.h"
#include "scsi_logging.h"
@@ -157,8 +158,9 @@ scmd_eh_abort_handler(struct work_struct *work)
} else {
SCSI_LOG_ERROR_RECOVERY(3,
scmd_printk(KERN_INFO, scmd,
- "scmd %p abort failed, rtn %d\n",
- scmd, rtn));
+ "scmd %p abort %s\n", scmd,
+ (rtn == FAST_IO_FAIL) ?
+ "not send" : "failed"));
}
}
@@ -355,7 +357,7 @@ static inline void scsi_eh_prt_fail_stats(struct Scsi_Host *shost,
if (cmd_cancel || cmd_failed) {
SCSI_LOG_ERROR_RECOVERY(3,
- sdev_printk(KERN_INFO, sdev,
+ shost_printk(KERN_INFO, shost,
"%s: cmds failed: %d, cancel: %d\n",
__func__, cmd_failed,
cmd_cancel));
@@ -608,7 +610,7 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
struct scsi_host_template *sht = sdev->host->hostt;
struct scsi_device *tmp_sdev;
- if (!sht->change_queue_depth ||
+ if (!sht->track_queue_depth ||
sdev->queue_depth >= sdev->max_queue_depth)
return;
@@ -629,12 +631,8 @@ static void scsi_handle_queue_ramp_up(struct scsi_device *sdev)
tmp_sdev->id != sdev->id ||
tmp_sdev->queue_depth == sdev->max_queue_depth)
continue;
- /*
- * call back into LLD to increase queue_depth by one
- * with ramp up reason code.
- */
- sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1,
- SCSI_QDEPTH_RAMP_UP);
+
+ scsi_change_queue_depth(tmp_sdev, tmp_sdev->queue_depth + 1);
sdev->last_queue_ramp_up = jiffies;
}
}
@@ -644,7 +642,7 @@ static void scsi_handle_queue_full(struct scsi_device *sdev)
struct scsi_host_template *sht = sdev->host->hostt;
struct scsi_device *tmp_sdev;
- if (!sht->change_queue_depth)
+ if (!sht->track_queue_depth)
return;
shost_for_each_device(tmp_sdev, sdev->host) {
@@ -656,8 +654,7 @@ static void scsi_handle_queue_full(struct scsi_device *sdev)
* the device when we got the queue full so we start
* from the highest possible value and work our way down.
*/
- sht->change_queue_depth(tmp_sdev, tmp_sdev->queue_depth - 1,
- SCSI_QDEPTH_QFULL);
+ scsi_track_queue_full(tmp_sdev, tmp_sdev->queue_depth - 1);
}
}
@@ -869,7 +866,24 @@ static int scsi_try_bus_device_reset(struct scsi_cmnd *scmd)
return rtn;
}
-static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt, struct scsi_cmnd *scmd)
+/**
+ * scsi_try_to_abort_cmd - Ask host to abort a SCSI command
+ * @scmd: SCSI cmd used to send a target reset
+ *
+ * Return value:
+ * SUCCESS, FAILED, or FAST_IO_FAIL
+ *
+ * Notes:
+ * SUCCESS does not necessarily indicate that the command
+ * has been aborted; it only indicates that the LLDDs
+ * has cleared all references to that command.
+ * LLDDs should return FAILED only if an abort was required
+ * but could not be executed. LLDDs should return FAST_IO_FAIL
+ * if the device is temporarily unavailable (eg due to a
+ * link down on FibreChannel)
+ */
+static int scsi_try_to_abort_cmd(struct scsi_host_template *hostt,
+ struct scsi_cmnd *scmd)
{
if (!hostt->eh_abort_handler)
return FAILED;
@@ -1156,9 +1170,9 @@ int scsi_eh_get_sense(struct list_head *work_q,
shost = scmd->device->host;
if (scsi_host_eh_past_deadline(shost)) {
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "skip %s, past eh deadline\n",
- __func__));
+ scmd_printk(KERN_INFO, scmd,
+ "%s: skip request sense, past eh deadline\n",
+ current->comm));
break;
}
if (status_byte(scmd->result) != CHECK_CONDITION)
@@ -1180,7 +1194,7 @@ int scsi_eh_get_sense(struct list_head *work_q,
SCSI_LOG_ERROR_RECOVERY(3, scmd_printk(KERN_INFO, scmd,
"sense requested for %p result %x\n",
scmd, scmd->result));
- SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense("bh", scmd));
+ SCSI_LOG_ERROR_RECOVERY(3, scsi_print_sense(scmd));
rtn = scsi_decide_disposition(scmd);
@@ -1265,9 +1279,9 @@ static int scsi_eh_test_devices(struct list_head *cmd_list,
/* Push items back onto work_q */
list_splice_init(cmd_list, work_q);
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, sdev->host,
- "skip %s, past eh deadline",
- __func__));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: skip test device, past eh deadline",
+ current->comm));
break;
}
}
@@ -1318,21 +1332,20 @@ static int scsi_eh_abort_cmds(struct list_head *work_q,
if (scsi_host_eh_past_deadline(shost)) {
list_splice_init(&check_list, work_q);
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "skip %s, past eh deadline\n",
- __func__));
+ scmd_printk(KERN_INFO, scmd,
+ "%s: skip aborting cmd, past eh deadline\n",
+ current->comm));
return list_empty(work_q);
}
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "%s: aborting cmd: 0x%p\n",
- current->comm, scmd));
+ scmd_printk(KERN_INFO, scmd,
+ "%s: aborting cmd\n", current->comm));
rtn = scsi_try_to_abort_cmd(shost->hostt, scmd);
if (rtn == FAILED) {
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "%s: aborting cmd failed: 0x%p\n",
- current->comm, scmd));
+ scmd_printk(KERN_INFO, scmd,
+ "%s: aborting cmd failed\n",
+ current->comm));
list_splice_init(&check_list, work_q);
return list_empty(work_q);
}
@@ -1390,9 +1403,9 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
shost_for_each_device(sdev, shost) {
if (scsi_host_eh_past_deadline(shost)) {
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "skip %s, past eh deadline\n",
- __func__));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: skip START_UNIT, past eh deadline\n",
+ current->comm));
break;
}
stu_scmd = NULL;
@@ -1407,9 +1420,9 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
continue;
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "%s: Sending START_UNIT to sdev: 0x%p\n",
- current->comm, sdev));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: Sending START_UNIT\n",
+ current->comm));
if (!scsi_eh_try_stu(stu_scmd)) {
if (!scsi_device_online(sdev) ||
@@ -1423,9 +1436,9 @@ static int scsi_eh_stu(struct Scsi_Host *shost,
}
} else {
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "%s: START_UNIT failed to sdev:"
- " 0x%p\n", current->comm, sdev));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: START_UNIT failed\n",
+ current->comm));
}
}
@@ -1456,9 +1469,9 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
shost_for_each_device(sdev, shost) {
if (scsi_host_eh_past_deadline(shost)) {
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "skip %s, past eh deadline\n",
- __func__));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: skip BDR, past eh deadline\n",
+ current->comm));
break;
}
bdr_scmd = NULL;
@@ -1472,9 +1485,8 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
continue;
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "%s: Sending BDR sdev: 0x%p\n",
- current->comm, sdev));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: Sending BDR\n", current->comm));
rtn = scsi_try_bus_device_reset(bdr_scmd);
if (rtn == SUCCESS || rtn == FAST_IO_FAIL) {
if (!scsi_device_online(sdev) ||
@@ -1490,9 +1502,8 @@ static int scsi_eh_bus_device_reset(struct Scsi_Host *shost,
}
} else {
SCSI_LOG_ERROR_RECOVERY(3,
- shost_printk(KERN_INFO, shost,
- "%s: BDR failed sdev: 0x%p\n",
- current->comm, sdev));
+ sdev_printk(KERN_INFO, sdev,
+ "%s: BDR failed\n", current->comm));
}
}
@@ -1528,8 +1539,8 @@ static int scsi_eh_target_reset(struct Scsi_Host *shost,
list_splice_init(&tmp_list, work_q);
SCSI_LOG_ERROR_RECOVERY(3,
shost_printk(KERN_INFO, shost,
- "skip %s, past eh deadline\n",
- __func__));
+ "%s: Skip target reset, past eh deadline\n",
+ current->comm));
return list_empty(work_q);
}
@@ -1591,8 +1602,8 @@ static int scsi_eh_bus_reset(struct Scsi_Host *shost,
list_splice_init(&check_list, work_q);
SCSI_LOG_ERROR_RECOVERY(3,
shost_printk(KERN_INFO, shost,
- "skip %s, past eh deadline\n",
- __func__));
+ "%s: skip BRST, past eh deadline\n",
+ current->comm));
return list_empty(work_q);
}
@@ -2193,9 +2204,9 @@ int scsi_error_handler(void *data)
*/
if (!shost->eh_noresume && scsi_autopm_get_host(shost) != 0) {
SCSI_LOG_ERROR_RECOVERY(1,
- printk(KERN_ERR "Error handler scsi_eh_%d "
- "unable to autoresume\n",
- shost->host_no));
+ shost_printk(KERN_ERR, shost,
+ "scsi_eh_%d: unable to autoresume\n",
+ shost->host_no));
continue;
}
@@ -2296,42 +2307,34 @@ scsi_reset_provider_done_command(struct scsi_cmnd *scmd)
{
}
-/*
- * Function: scsi_reset_provider
- *
- * Purpose: Send requested reset to a bus or device at any phase.
- *
- * Arguments: device - device to send reset to
- * flag - reset type (see scsi.h)
- *
- * Returns: SUCCESS/FAILURE.
- *
- * Notes: This is used by the SCSI Generic driver to provide
- * Bus/Device reset capability.
+/**
+ * scsi_ioctl_reset: explicitly reset a host/bus/target/device
+ * @dev: scsi_device to operate on
+ * @arg: reset type (see sg.h)
*/
int
-scsi_reset_provider(struct scsi_device *dev, int flag)
+scsi_ioctl_reset(struct scsi_device *dev, int __user *arg)
{
struct scsi_cmnd *scmd;
struct Scsi_Host *shost = dev->host;
struct request req;
unsigned long flags;
- int rtn;
+ int error = 0, rtn, val;
- if (scsi_autopm_get_host(shost) < 0)
- return FAILED;
+ if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
+ return -EACCES;
- if (!get_device(&dev->sdev_gendev)) {
- rtn = FAILED;
- goto out_put_autopm_host;
- }
+ error = get_user(val, arg);
+ if (error)
+ return error;
+ if (scsi_autopm_get_host(shost) < 0)
+ return -EIO;
+
+ error = -EIO;
scmd = scsi_get_command(dev, GFP_KERNEL);
- if (!scmd) {
- rtn = FAILED;
- put_device(&dev->sdev_gendev);
+ if (!scmd)
goto out_put_autopm_host;
- }
blk_rq_init(NULL, &req);
scmd->request = &req;
@@ -2349,29 +2352,37 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
shost->tmf_in_progress = 1;
spin_unlock_irqrestore(shost->host_lock, flags);
- switch (flag) {
- case SCSI_TRY_RESET_DEVICE:
+ switch (val & ~SG_SCSI_RESET_NO_ESCALATE) {
+ case SG_SCSI_RESET_NOTHING:
+ rtn = SUCCESS;
+ break;
+ case SG_SCSI_RESET_DEVICE:
rtn = scsi_try_bus_device_reset(scmd);
- if (rtn == SUCCESS)
+ if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
break;
/* FALLTHROUGH */
- case SCSI_TRY_RESET_TARGET:
+ case SG_SCSI_RESET_TARGET:
rtn = scsi_try_target_reset(scmd);
- if (rtn == SUCCESS)
+ if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
break;
/* FALLTHROUGH */
- case SCSI_TRY_RESET_BUS:
+ case SG_SCSI_RESET_BUS:
rtn = scsi_try_bus_reset(scmd);
- if (rtn == SUCCESS)
+ if (rtn == SUCCESS || (val & SG_SCSI_RESET_NO_ESCALATE))
break;
/* FALLTHROUGH */
- case SCSI_TRY_RESET_HOST:
+ case SG_SCSI_RESET_HOST:
rtn = scsi_try_host_reset(scmd);
- break;
+ if (rtn == SUCCESS)
+ break;
default:
+ /* FALLTHROUGH */
rtn = FAILED;
+ break;
}
+ error = (rtn == SUCCESS) ? 0 : -EIO;
+
spin_lock_irqsave(shost->host_lock, flags);
shost->tmf_in_progress = 0;
spin_unlock_irqrestore(shost->host_lock, flags);
@@ -2385,15 +2396,15 @@ scsi_reset_provider(struct scsi_device *dev, int flag)
"waking up host to restart after TMF\n"));
wake_up(&shost->host_wait);
-
scsi_run_host_queues(shost);
- scsi_next_command(scmd);
+ scsi_put_command(scmd);
+
out_put_autopm_host:
scsi_autopm_put_host(shost);
- return rtn;
+ return error;
}
-EXPORT_SYMBOL(scsi_reset_provider);
+EXPORT_SYMBOL(scsi_ioctl_reset);
/**
* scsi_normalize_sense - normalize main elements from either fixed or
@@ -2412,20 +2423,20 @@ EXPORT_SYMBOL(scsi_reset_provider);
* responded to a SCSI command with the CHECK_CONDITION status.
*
* Return value:
- * 1 if valid sense data information found, else 0;
+ * true if valid sense data information found, else false;
*/
-int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
- struct scsi_sense_hdr *sshdr)
+bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
+ struct scsi_sense_hdr *sshdr)
{
if (!sense_buffer || !sb_len)
- return 0;
+ return false;
memset(sshdr, 0, sizeof(struct scsi_sense_hdr));
sshdr->response_code = (sense_buffer[0] & 0x7f);
if (!scsi_sense_valid(sshdr))
- return 0;
+ return false;
if (sshdr->response_code >= 0x72) {
/*
@@ -2455,12 +2466,12 @@ int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
}
}
- return 1;
+ return true;
}
EXPORT_SYMBOL(scsi_normalize_sense);
-int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
- struct scsi_sense_hdr *sshdr)
+bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
+ struct scsi_sense_hdr *sshdr)
{
return scsi_normalize_sense(cmd->sense_buffer,
SCSI_SENSE_BUFFERSIZE, sshdr);
diff --git a/drivers/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index 1aaaf43..c4f7b56 100644
--- a/drivers/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -126,7 +126,7 @@ static int ioctl_internal_command(struct scsi_device *sdev, char *cmd,
sdev_printk(KERN_INFO, sdev,
"ioctl_internal_command return code = %x\n",
result);
- scsi_print_sense_hdr(" ", &sshdr);
+ scsi_print_sense_hdr(sdev, NULL, &sshdr);
break;
}
}
@@ -200,19 +200,6 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
{
char scsi_cmd[MAX_COMMAND_SIZE];
- /* No idea how this happens.... */
- if (!sdev)
- return -ENXIO;
-
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- if (!scsi_block_when_processing_errors(sdev))
- return -ENODEV;
-
/* Check for deprecated ioctls ... all the ioctls which don't
* follow the new unique numbering scheme are deprecated */
switch (cmd) {
@@ -273,6 +260,8 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
START_STOP_TIMEOUT, NORMAL_RETRIES);
case SCSI_IOCTL_GET_PCI:
return scsi_ioctl_get_pci(sdev, arg);
+ case SG_SCSI_RESET:
+ return scsi_ioctl_reset(sdev, arg);
default:
if (sdev->host->hostt->ioctl)
return sdev->host->hostt->ioctl(sdev, cmd, arg);
@@ -281,55 +270,20 @@ int scsi_ioctl(struct scsi_device *sdev, int cmd, void __user *arg)
}
EXPORT_SYMBOL(scsi_ioctl);
-/**
- * scsi_nonblockable_ioctl() - Handle SG_SCSI_RESET
- * @sdev: scsi device receiving ioctl
- * @cmd: Must be SC_SCSI_RESET
- * @arg: pointer to int containing SG_SCSI_RESET_{DEVICE,BUS,HOST}
- * @ndelay: file mode O_NDELAY flag
+/*
+ * We can process a reset even when a device isn't fully operable.
*/
-int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
- void __user *arg, int ndelay)
+int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev, int cmd,
+ bool ndelay)
{
- int val, result;
-
- /* The first set of iocts may be executed even if we're doing
- * error processing, as long as the device was opened
- * non-blocking */
- if (ndelay) {
+ if (cmd == SG_SCSI_RESET && ndelay) {
if (scsi_host_in_recovery(sdev->host))
+ return -EAGAIN;
+ } else {
+ if (!scsi_block_when_processing_errors(sdev))
return -ENODEV;
- } else if (!scsi_block_when_processing_errors(sdev))
- return -ENODEV;
-
- switch (cmd) {
- case SG_SCSI_RESET:
- result = get_user(val, (int __user *)arg);
- if (result)
- return result;
- if (val == SG_SCSI_RESET_NOTHING)
- return 0;
- switch (val) {
- case SG_SCSI_RESET_DEVICE:
- val = SCSI_TRY_RESET_DEVICE;
- break;
- case SG_SCSI_RESET_TARGET:
- val = SCSI_TRY_RESET_TARGET;
- break;
- case SG_SCSI_RESET_BUS:
- val = SCSI_TRY_RESET_BUS;
- break;
- case SG_SCSI_RESET_HOST:
- val = SCSI_TRY_RESET_HOST;
- break;
- default:
- return -EINVAL;
- }
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- return (scsi_reset_provider(sdev, val) ==
- SUCCESS) ? 0 : -EIO;
}
- return -ENODEV;
+
+ return 0;
}
-EXPORT_SYMBOL(scsi_nonblockable_ioctl);
+EXPORT_SYMBOL_GPL(scsi_ioctl_block_when_processing_errors);
diff --git a/drivers/scsi/scsi_lib.c b/drivers/scsi/scsi_lib.c
index 50a6e1a..7e3d954 100644
--- a/drivers/scsi/scsi_lib.c
+++ b/drivers/scsi/scsi_lib.c
@@ -22,6 +22,7 @@
#include <linux/hardirq.h>
#include <linux/scatterlist.h>
#include <linux/blk-mq.h>
+#include <linux/ratelimit.h>
#include <scsi/scsi.h>
#include <scsi/scsi_cmnd.h>
@@ -47,7 +48,7 @@ struct scsi_host_sg_pool {
mempool_t *pool;
};
-#define SP(x) { x, "sgpool-" __stringify(x) }
+#define SP(x) { .size = x, "sgpool-" __stringify(x) }
#if (SCSI_MAX_SG_SEGMENTS < 32)
#error SCSI_MAX_SG_SEGMENTS is too small (must be 32 or greater)
#endif
@@ -542,17 +543,6 @@ static void scsi_requeue_command(struct request_queue *q, struct scsi_cmnd *cmd)
put_device(&sdev->sdev_gendev);
}
-void scsi_next_command(struct scsi_cmnd *cmd)
-{
- struct scsi_device *sdev = cmd->device;
- struct request_queue *q = sdev->request_queue;
-
- scsi_put_command(cmd);
- scsi_run_queue(q);
-
- put_device(&sdev->sdev_gendev);
-}
-
void scsi_run_host_queues(struct Scsi_Host *shost)
{
struct scsi_device *sdev;
@@ -598,10 +588,10 @@ static void scsi_free_sgtable(struct scsi_data_buffer *sdb, bool mq)
__sg_free_table(&sdb->table, SCSI_MAX_SG_SEGMENTS, mq, scsi_sg_free);
}
-static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents,
- gfp_t gfp_mask, bool mq)
+static int scsi_alloc_sgtable(struct scsi_data_buffer *sdb, int nents, bool mq)
{
struct scatterlist *first_chunk = NULL;
+ gfp_t gfp_mask = mq ? GFP_NOIO : GFP_ATOMIC;
int ret;
BUG_ON(!nents);
@@ -730,8 +720,6 @@ static bool scsi_end_request(struct request *req, int error,
kblockd_schedule_work(&sdev->requeue_work);
else
blk_mq_start_stopped_hw_queues(q, true);
-
- put_device(&sdev->sdev_gendev);
} else {
unsigned long flags;
@@ -743,9 +731,12 @@ static bool scsi_end_request(struct request *req, int error,
spin_unlock_irqrestore(q->queue_lock, flags);
scsi_release_buffers(cmd);
- scsi_next_command(cmd);
+
+ scsi_put_command(cmd);
+ scsi_run_queue(q);
}
+ put_device(&sdev->sdev_gendev);
return false;
}
@@ -831,8 +822,8 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
struct request *req = cmd->request;
int error = 0;
struct scsi_sense_hdr sshdr;
- int sense_valid = 0;
- int sense_deferred = 0;
+ bool sense_valid = false;
+ int sense_deferred = 0, level = 0;
enum {ACTION_FAIL, ACTION_REPREP, ACTION_RETRY,
ACTION_DELAYED_RETRY} action;
unsigned long wait_for = (cmd->allowed + 1) * req->timeout;
@@ -912,7 +903,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
if ((sshdr.asc == 0x0) && (sshdr.ascq == 0x1d))
;
else if (!(req->cmd_flags & REQ_QUIET))
- scsi_print_sense("", cmd);
+ scsi_print_sense(cmd);
result = 0;
/* BLOCK_PC may have set error */
error = 0;
@@ -1039,10 +1030,24 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
case ACTION_FAIL:
/* Give up and fail the remainder of the request */
if (!(req->cmd_flags & REQ_QUIET)) {
- scsi_print_result(cmd);
- if (driver_byte(result) & DRIVER_SENSE)
- scsi_print_sense("", cmd);
- scsi_print_command(cmd);
+ static DEFINE_RATELIMIT_STATE(_rs,
+ DEFAULT_RATELIMIT_INTERVAL,
+ DEFAULT_RATELIMIT_BURST);
+
+ if (unlikely(scsi_logging_level))
+ level = SCSI_LOG_LEVEL(SCSI_LOG_MLCOMPLETE_SHIFT,
+ SCSI_LOG_MLCOMPLETE_BITS);
+
+ /*
+ * if logging is enabled the failure will be printed
+ * in scsi_log_completion(), so avoid duplicate messages
+ */
+ if (!level && __ratelimit(&_rs)) {
+ scsi_print_result(cmd, NULL, FAILED);
+ if (driver_byte(result) & DRIVER_SENSE)
+ scsi_print_sense(cmd);
+ scsi_print_command(cmd);
+ }
}
if (!scsi_end_request(req, error, blk_rq_err_bytes(req), 0))
return;
@@ -1072,8 +1077,7 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
}
}
-static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
- gfp_t gfp_mask)
+static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb)
{
int count;
@@ -1081,7 +1085,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
* If sg table allocation fails, requeue request later.
*/
if (unlikely(scsi_alloc_sgtable(sdb, req->nr_phys_segments,
- gfp_mask, req->mq_ctx != NULL)))
+ req->mq_ctx != NULL)))
return BLKPREP_DEFER;
/*
@@ -1106,7 +1110,7 @@ static int scsi_init_sgtable(struct request *req, struct scsi_data_buffer *sdb,
* BLKPREP_DEFER if the failure is retryable
* BLKPREP_KILL if the failure is fatal
*/
-int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
+int scsi_init_io(struct scsi_cmnd *cmd)
{
struct scsi_device *sdev = cmd->device;
struct request *rq = cmd->request;
@@ -1115,7 +1119,7 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
BUG_ON(!rq->nr_phys_segments);
- error = scsi_init_sgtable(rq, &cmd->sdb, gfp_mask);
+ error = scsi_init_sgtable(rq, &cmd->sdb);
if (error)
goto err_exit;
@@ -1131,8 +1135,7 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
rq->next_rq->special = bidi_sdb;
}
- error = scsi_init_sgtable(rq->next_rq, rq->next_rq->special,
- GFP_ATOMIC);
+ error = scsi_init_sgtable(rq->next_rq, rq->next_rq->special);
if (error)
goto err_exit;
}
@@ -1144,7 +1147,7 @@ int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask)
BUG_ON(prot_sdb == NULL);
ivecs = blk_rq_count_integrity_sg(rq->q, rq->bio);
- if (scsi_alloc_sgtable(prot_sdb, ivecs, gfp_mask, is_mq)) {
+ if (scsi_alloc_sgtable(prot_sdb, ivecs, is_mq)) {
error = BLKPREP_DEFER;
goto err_exit;
}
@@ -1213,7 +1216,7 @@ static int scsi_setup_blk_pc_cmnd(struct scsi_device *sdev, struct request *req)
* submit a request without an attached bio.
*/
if (req->bio) {
- int ret = scsi_init_io(cmd, GFP_ATOMIC);
+ int ret = scsi_init_io(cmd);
if (unlikely(ret))
return ret;
} else {
@@ -1638,6 +1641,87 @@ static void scsi_softirq_done(struct request *rq)
}
/**
+ * scsi_dispatch_command - Dispatch a command to the low-level driver.
+ * @cmd: command block we are dispatching.
+ *
+ * Return: nonzero return request was rejected and device's queue needs to be
+ * plugged.
+ */
+static int scsi_dispatch_cmd(struct scsi_cmnd *cmd)
+{
+ struct Scsi_Host *host = cmd->device->host;
+ int rtn = 0;
+
+ atomic_inc(&cmd->device->iorequest_cnt);
+
+ /* check if the device is still usable */
+ if (unlikely(cmd->device->sdev_state == SDEV_DEL)) {
+ /* in SDEV_DEL we error all commands. DID_NO_CONNECT
+ * returns an immediate error upwards, and signals
+ * that the device is no longer present */
+ cmd->result = DID_NO_CONNECT << 16;
+ goto done;
+ }
+
+ /* Check to see if the scsi lld made this device blocked. */
+ if (unlikely(scsi_device_blocked(cmd->device))) {
+ /*
+ * in blocked state, the command is just put back on
+ * the device queue. The suspend state has already
+ * blocked the queue so future requests should not
+ * occur until the device transitions out of the
+ * suspend state.
+ */
+ SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
+ "queuecommand : device blocked\n"));
+ return SCSI_MLQUEUE_DEVICE_BUSY;
+ }
+
+ /* Store the LUN value in cmnd, if needed. */
+ if (cmd->device->lun_in_cdb)
+ cmd->cmnd[1] = (cmd->cmnd[1] & 0x1f) |
+ (cmd->device->lun << 5 & 0xe0);
+
+ scsi_log_send(cmd);
+
+ /*
+ * Before we queue this command, check if the command
+ * length exceeds what the host adapter can handle.
+ */
+ if (cmd->cmd_len > cmd->device->host->max_cmd_len) {
+ SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
+ "queuecommand : command too long. "
+ "cdb_size=%d host->max_cmd_len=%d\n",
+ cmd->cmd_len, cmd->device->host->max_cmd_len));
+ cmd->result = (DID_ABORT << 16);
+ goto done;
+ }
+
+ if (unlikely(host->shost_state == SHOST_DEL)) {
+ cmd->result = (DID_NO_CONNECT << 16);
+ goto done;
+
+ }
+
+ trace_scsi_dispatch_cmd_start(cmd);
+ rtn = host->hostt->queuecommand(host, cmd);
+ if (rtn) {
+ trace_scsi_dispatch_cmd_error(cmd, rtn);
+ if (rtn != SCSI_MLQUEUE_DEVICE_BUSY &&
+ rtn != SCSI_MLQUEUE_TARGET_BUSY)
+ rtn = SCSI_MLQUEUE_HOST_BUSY;
+
+ SCSI_LOG_MLQUEUE(3, scmd_printk(KERN_INFO, cmd,
+ "queuecommand : request rejected\n"));
+ }
+
+ return rtn;
+ done:
+ cmd->scsi_done(cmd);
+ return 0;
+}
+
+/**
* scsi_done - Invoke completion on finished SCSI command.
* @cmd: The SCSI Command for which a low-level device driver (LLDD) gives
* ownership back to SCSI Core -- i.e. the LLDD has finished with it.
@@ -1725,7 +1809,7 @@ static void scsi_request_fn(struct request_queue *q)
* we add the dev to the starved list so it eventually gets
* a run when a tag is freed.
*/
- if (blk_queue_tagged(q) && !blk_rq_tagged(req)) {
+ if (blk_queue_tagged(q) && !(req->cmd_flags & REQ_QUEUED)) {
spin_lock_irq(shost->host_lock);
if (list_empty(&sdev->starved_entry))
list_add_tail(&sdev->starved_entry,
@@ -1739,6 +1823,11 @@ static void scsi_request_fn(struct request_queue *q)
if (!scsi_host_queue_ready(q, shost, sdev))
goto host_not_ready;
+
+ if (sdev->simple_tags)
+ cmd->flags |= SCMD_TAGGED;
+ else
+ cmd->flags &= ~SCMD_TAGGED;
/*
* Finally, initialize any error handling parameters, and set up
@@ -1893,10 +1982,10 @@ static int scsi_queue_rq(struct blk_mq_hw_ctx *hctx, struct request *req,
blk_mq_start_request(req);
}
- if (blk_queue_tagged(q))
- req->cmd_flags |= REQ_QUEUED;
+ if (sdev->simple_tags)
+ cmd->flags |= SCMD_TAGGED;
else
- req->cmd_flags &= ~REQ_QUEUED;
+ cmd->flags &= ~SCMD_TAGGED;
scsi_init_cmd_errh(cmd);
cmd->scsi_done = scsi_mq_done;
@@ -2091,7 +2180,7 @@ int scsi_mq_setup_tags(struct Scsi_Host *shost)
memset(&shost->tag_set, 0, sizeof(shost->tag_set));
shost->tag_set.ops = &scsi_mq_ops;
- shost->tag_set.nr_hw_queues = 1;
+ shost->tag_set.nr_hw_queues = shost->nr_hw_queues ? : 1;
shost->tag_set.queue_depth = shost->can_queue;
shost->tag_set.cmd_size = cmd_size;
shost->tag_set.numa_node = NUMA_NO_NODE;
diff --git a/drivers/scsi/scsi_logging.h b/drivers/scsi/scsi_logging.h
index 1f65139..7fe64a8 100644
--- a/drivers/scsi/scsi_logging.h
+++ b/drivers/scsi/scsi_logging.h
@@ -51,6 +51,7 @@ do { \
} while (0); \
} while (0)
#else
+#define SCSI_LOG_LEVEL(SHIFT, BITS) 0
#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD)
#endif /* CONFIG_SCSI_LOGGING */
diff --git a/drivers/scsi/scsi_priv.h b/drivers/scsi/scsi_priv.h
index 12b8e1b..2dc4a83 100644
--- a/drivers/scsi/scsi_priv.h
+++ b/drivers/scsi/scsi_priv.h
@@ -29,7 +29,6 @@ extern int scsi_init_hosts(void);
extern void scsi_exit_hosts(void);
/* scsi.c */
-extern int scsi_dispatch_cmd(struct scsi_cmnd *cmd);
extern int scsi_setup_command_freelist(struct Scsi_Host *shost);
extern void scsi_destroy_command_freelist(struct Scsi_Host *shost);
#ifdef CONFIG_SCSI_LOGGING
@@ -84,7 +83,6 @@ int scsi_noretry_cmd(struct scsi_cmnd *scmd);
extern int scsi_maybe_unblock_host(struct scsi_device *sdev);
extern void scsi_device_unbusy(struct scsi_device *sdev);
extern void scsi_queue_insert(struct scsi_cmnd *cmd, int reason);
-extern void scsi_next_command(struct scsi_cmnd *cmd);
extern void scsi_io_completion(struct scsi_cmnd *, unsigned int);
extern void scsi_run_host_queues(struct Scsi_Host *shost);
extern struct request_queue *scsi_alloc_queue(struct scsi_device *sdev);
diff --git a/drivers/scsi/scsi_scan.c b/drivers/scsi/scsi_scan.c
index ba3f1e8..983aed1 100644
--- a/drivers/scsi/scsi_scan.c
+++ b/drivers/scsi/scsi_scan.c
@@ -286,7 +286,13 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
}
WARN_ON_ONCE(!blk_get_queue(sdev->request_queue));
sdev->request_queue->queuedata = sdev;
- scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
+
+ if (!shost_use_blk_mq(sdev->host) &&
+ (shost->bqt || shost->hostt->use_blk_tags)) {
+ blk_queue_init_tags(sdev->request_queue,
+ sdev->host->cmd_per_lun, shost->bqt);
+ }
+ scsi_change_queue_depth(sdev, sdev->host->cmd_per_lun);
scsi_sysfs_device_initialize(sdev);
@@ -874,8 +880,10 @@ static int scsi_add_lun(struct scsi_device *sdev, unsigned char *inq_result,
(inq_result[3] & 0x0f) == 1 ? " CCS" : "");
if ((sdev->scsi_level >= SCSI_2) && (inq_result[7] & 2) &&
- !(*bflags & BLIST_NOTQ))
+ !(*bflags & BLIST_NOTQ)) {
sdev->tagged_supported = 1;
+ sdev->simple_tags = 1;
+ }
/*
* Some devices (Texel CD ROM drives) have handshaking problems
@@ -1214,9 +1222,9 @@ static void scsi_sequential_lun_scan(struct scsi_target *starget,
sparse_lun = 0;
/*
- * If less than SCSI_1_CSS, and no special lun scaning, stop
+ * If less than SCSI_1_CCS, and no special lun scanning, stop
* scanning; this matches 2.4 behaviour, but could just be a bug
- * (to continue scanning a SCSI_1_CSS device).
+ * (to continue scanning a SCSI_1_CCS device).
*
* This test is broken. We might not have any device on lun0 for
* a sparselun device, and if that's the case then how would we
@@ -1585,16 +1593,15 @@ EXPORT_SYMBOL(scsi_add_device);
void scsi_rescan_device(struct device *dev)
{
- struct scsi_driver *drv;
-
if (!dev->driver)
return;
- drv = to_scsi_driver(dev->driver);
- if (try_module_get(drv->owner)) {
+ if (try_module_get(dev->driver->owner)) {
+ struct scsi_driver *drv = to_scsi_driver(dev->driver);
+
if (drv->rescan)
drv->rescan(dev);
- module_put(drv->owner);
+ module_put(dev->driver->owner);
}
}
EXPORT_SYMBOL(scsi_rescan_device);
@@ -1727,7 +1734,7 @@ int scsi_scan_host_selected(struct Scsi_Host *shost, unsigned int channel,
if (((channel != SCAN_WILD_CARD) && (channel > shost->max_channel)) ||
((id != SCAN_WILD_CARD) && (id >= shost->max_id)) ||
- ((lun != SCAN_WILD_CARD) && (lun > shost->max_lun)))
+ ((lun != SCAN_WILD_CARD) && (lun >= shost->max_lun)))
return -EINVAL;
mutex_lock(&shost->scan_mutex);
diff --git a/drivers/scsi/scsi_sysfs.c b/drivers/scsi/scsi_sysfs.c
index f4cb7b3..1cb64a8 100644
--- a/drivers/scsi/scsi_sysfs.c
+++ b/drivers/scsi/scsi_sysfs.c
@@ -727,9 +727,7 @@ show_queue_type_field(struct device *dev, struct device_attribute *attr,
struct scsi_device *sdev = to_scsi_device(dev);
const char *name = "none";
- if (sdev->ordered_tags)
- name = "ordered";
- else if (sdev->simple_tags)
+ if (sdev->simple_tags)
name = "simple";
return snprintf(buf, 20, "%s\n", name);
@@ -747,9 +745,12 @@ store_queue_type_field(struct device *dev, struct device_attribute *attr,
if (!sdev->tagged_supported || !sht->change_queue_type)
return -EINVAL;
- if (strncmp(buf, "ordered", 7) == 0)
- tag_type = MSG_ORDERED_TAG;
- else if (strncmp(buf, "simple", 6) == 0)
+ /*
+ * We're never issueing order tags these days, but allow the value
+ * for backwards compatibility.
+ */
+ if (strncmp(buf, "ordered", 7) == 0 ||
+ strncmp(buf, "simple", 6) == 0)
tag_type = MSG_SIMPLE_TAG;
else if (strncmp(buf, "none", 4) != 0)
return -EINVAL;
@@ -876,11 +877,10 @@ sdev_store_queue_depth(struct device *dev, struct device_attribute *attr,
depth = simple_strtoul(buf, NULL, 0);
- if (depth < 1)
+ if (depth < 1 || depth > sht->can_queue)
return -EINVAL;
- retval = sht->change_queue_depth(sdev, depth,
- SCSI_QDEPTH_DEFAULT);
+ retval = sht->change_queue_depth(sdev, depth);
if (retval < 0)
return retval;
diff --git a/drivers/scsi/scsi_trace.c b/drivers/scsi/scsi_trace.c
index 503594e..82af28b 100644
--- a/drivers/scsi/scsi_trace.c
+++ b/drivers/scsi/scsi_trace.c
@@ -278,7 +278,7 @@ scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
return scsi_trace_rw16(p, cdb, len);
case UNMAP:
return scsi_trace_unmap(p, cdb, len);
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
return scsi_trace_service_action_in(p, cdb, len);
case VARIABLE_LENGTH_CMD:
return scsi_trace_varlen(p, cdb, len);
diff --git a/drivers/scsi/scsi_transport_spi.c b/drivers/scsi/scsi_transport_spi.c
index cf08071..fa2aece 100644
--- a/drivers/scsi/scsi_transport_spi.c
+++ b/drivers/scsi/scsi_transport_spi.c
@@ -32,6 +32,7 @@
#include <scsi/scsi_host.h>
#include <scsi/scsi_cmnd.h>
#include <scsi/scsi_eh.h>
+#include <scsi/scsi_tcq.h>
#include <scsi/scsi_transport.h>
#include <scsi/scsi_transport_spi.h>
@@ -1207,6 +1208,28 @@ int spi_populate_ppr_msg(unsigned char *msg, int period, int offset,
}
EXPORT_SYMBOL_GPL(spi_populate_ppr_msg);
+/**
+ * spi_populate_tag_msg - place a tag message in a buffer
+ * @msg: pointer to the area to place the tag
+ * @cmd: pointer to the scsi command for the tag
+ *
+ * Notes:
+ * designed to create the correct type of tag message for the
+ * particular request. Returns the size of the tag message.
+ * May return 0 if TCQ is disabled for this device.
+ **/
+int spi_populate_tag_msg(unsigned char *msg, struct scsi_cmnd *cmd)
+{
+ if (cmd->flags & SCMD_TAGGED) {
+ *msg++ = MSG_SIMPLE_TAG;
+ *msg++ = cmd->request->tag;
+ return 2;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(spi_populate_tag_msg);
+
#ifdef CONFIG_SCSI_CONSTANTS
static const char * const one_byte_msgs[] = {
/* 0x00 */ "Task Complete", NULL /* Extended Message */, "Save Pointers",
diff --git a/drivers/scsi/scsicam.c b/drivers/scsi/scsicam.c
index 92d24d6..910f4a7 100644
--- a/drivers/scsi/scsicam.c
+++ b/drivers/scsi/scsicam.c
@@ -163,8 +163,8 @@ int scsi_partsize(unsigned char *buf, unsigned long capacity,
end_head * end_sector + end_sector;
/* This is the actual _sector_ number at the end */
- logical_end = get_unaligned(&largest->start_sect)
- + get_unaligned(&largest->nr_sects);
+ logical_end = get_unaligned_le32(&largest->start_sect)
+ + get_unaligned_le32(&largest->nr_sects);
/* This is for >1023 cylinders */
ext_cyl = (logical_end - (end_head * end_sector + end_sector))
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c
index cfba74c..fedab3c 100644
--- a/drivers/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -116,7 +116,7 @@ static int sd_eh_action(struct scsi_cmnd *, int);
static void sd_read_capacity(struct scsi_disk *sdkp, unsigned char *buffer);
static void scsi_disk_release(struct device *cdev);
static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
-static void sd_print_result(struct scsi_disk *, int);
+static void sd_print_result(const struct scsi_disk *, const char *, int);
static DEFINE_SPINLOCK(sd_index_lock);
static DEFINE_IDA(sd_index_ida);
@@ -510,9 +510,9 @@ static const struct dev_pm_ops sd_pm_ops = {
};
static struct scsi_driver sd_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "sd",
+ .owner = THIS_MODULE,
.probe = sd_probe,
.remove = sd_remove,
.shutdown = sd_shutdown,
@@ -656,7 +656,7 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
unsigned int logical_block_size = sdkp->device->sector_size;
unsigned int max_blocks = 0;
- q->limits.discard_zeroes_data = sdkp->lbprz;
+ q->limits.discard_zeroes_data = 0;
q->limits.discard_alignment = sdkp->unmap_alignment *
logical_block_size;
q->limits.discard_granularity =
@@ -680,11 +680,13 @@ static void sd_config_discard(struct scsi_disk *sdkp, unsigned int mode)
case SD_LBP_WS16:
max_blocks = min_not_zero(sdkp->max_ws_blocks,
(u32)SD_MAX_WS16_BLOCKS);
+ q->limits.discard_zeroes_data = sdkp->lbprz;
break;
case SD_LBP_WS10:
max_blocks = min_not_zero(sdkp->max_ws_blocks,
(u32)SD_MAX_WS10_BLOCKS);
+ q->limits.discard_zeroes_data = sdkp->lbprz;
break;
case SD_LBP_ZERO:
@@ -784,7 +786,7 @@ static int sd_setup_discard_cmnd(struct scsi_cmnd *cmd)
* amount of blocks described by the request.
*/
blk_add_request_payload(rq, page, len);
- ret = scsi_init_io(cmd, GFP_ATOMIC);
+ ret = scsi_init_io(cmd);
rq->__data_len = nr_bytes;
out:
@@ -878,7 +880,7 @@ static int sd_setup_write_same_cmnd(struct scsi_cmnd *cmd)
* knows how much to actually write.
*/
rq->__data_len = sdp->sector_size;
- ret = scsi_init_io(cmd, GFP_ATOMIC);
+ ret = scsi_init_io(cmd);
rq->__data_len = nr_bytes;
return ret;
}
@@ -912,7 +914,7 @@ static int sd_setup_read_write_cmnd(struct scsi_cmnd *SCpnt)
int ret;
unsigned char protect;
- ret = scsi_init_io(SCpnt, GFP_ATOMIC);
+ ret = scsi_init_io(SCpnt);
if (ret != BLKPREP_OK)
goto out;
SCpnt = rq->special;
@@ -1334,9 +1336,9 @@ static int sd_ioctl(struct block_device *bdev, fmode_t mode,
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- error = scsi_nonblockable_ioctl(sdp, cmd, p,
- (mode & FMODE_NDELAY) != 0);
- if (!scsi_block_when_processing_errors(sdp) || !error)
+ error = scsi_ioctl_block_when_processing_errors(sdp, cmd,
+ (mode & FMODE_NDELAY) != 0);
+ if (error)
goto out;
/*
@@ -1492,7 +1494,7 @@ static int sd_sync_cache(struct scsi_disk *sdkp)
}
if (res) {
- sd_print_result(sdkp, res);
+ sd_print_result(sdkp, "Synchronize Cache(10) failed", res);
if (driver_byte(res) & DRIVER_SENSE)
sd_print_sense_hdr(sdkp, &sshdr);
@@ -1541,31 +1543,19 @@ static int sd_compat_ioctl(struct block_device *bdev, fmode_t mode,
unsigned int cmd, unsigned long arg)
{
struct scsi_device *sdev = scsi_disk(bdev->bd_disk)->device;
- int ret;
-
- ret = scsi_verify_blk_ioctl(bdev, cmd);
- if (ret < 0)
- return ret;
+ int error;
- /*
- * If we are in the middle of error recovery, don't let anyone
- * else try and use this device. Also, if error recovery fails, it
- * may try and take the device offline, in which case all further
- * access to the device is prohibited.
- */
- if (!scsi_block_when_processing_errors(sdev))
- return -ENODEV;
+ error = scsi_ioctl_block_when_processing_errors(sdev, cmd,
+ (mode & FMODE_NDELAY) != 0);
+ if (error)
+ return error;
- if (sdev->host->hostt->compat_ioctl) {
- ret = sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
-
- return ret;
- }
-
/*
* Let the static ioctl translation table take care of it.
*/
- return -ENOIOCTLCMD;
+ if (!sdev->host->hostt->compat_ioctl)
+ return -ENOIOCTLCMD;
+ return sdev->host->hostt->compat_ioctl(sdev, cmd, (void __user *)arg);
}
#endif
@@ -1713,17 +1703,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
if (sense_valid)
sense_deferred = scsi_sense_is_deferred(&sshdr);
}
-#ifdef CONFIG_SCSI_LOGGING
- SCSI_LOG_HLCOMPLETE(1, scsi_print_result(SCpnt));
- if (sense_valid) {
- SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
- "sd_done: sb[respc,sk,asc,"
- "ascq]=%x,%x,%x,%x\n",
- sshdr.response_code,
- sshdr.sense_key, sshdr.asc,
- sshdr.ascq));
- }
-#endif
sdkp->medium_access_timed_out = 0;
if (driver_byte(result) != DRIVER_SENSE &&
@@ -1743,7 +1722,6 @@ static int sd_done(struct scsi_cmnd *SCpnt)
* unknown amount of data was transferred so treat it as an
* error.
*/
- scsi_print_sense("sd", SCpnt);
SCpnt->result = 0;
memset(SCpnt->sense_buffer, 0, SCSI_SENSE_BUFFERSIZE);
break;
@@ -1779,6 +1757,10 @@ static int sd_done(struct scsi_cmnd *SCpnt)
break;
}
out:
+ SCSI_LOG_HLCOMPLETE(1, scmd_printk(KERN_INFO, SCpnt,
+ "sd_done: completed %d of %d bytes\n",
+ good_bytes, scsi_bufflen(SCpnt)));
+
if (rq_data_dir(SCpnt->request) == READ && scsi_prot_sg_count(SCpnt))
sd_dif_complete(SCpnt, good_bytes);
@@ -1834,12 +1816,12 @@ sd_spinup_disk(struct scsi_disk *sdkp)
/* no sense, TUR either succeeded or failed
* with a status error */
if(!spintime && !scsi_status_is_good(the_result)) {
- sd_printk(KERN_NOTICE, sdkp, "Unit Not Ready\n");
- sd_print_result(sdkp, the_result);
+ sd_print_result(sdkp, "Test Unit Ready failed",
+ the_result);
}
break;
}
-
+
/*
* The device does not want the automatic start to be issued.
*/
@@ -1955,7 +1937,6 @@ static void read_capacity_error(struct scsi_disk *sdkp, struct scsi_device *sdp,
struct scsi_sense_hdr *sshdr, int sense_valid,
int the_result)
{
- sd_print_result(sdkp, the_result);
if (driver_byte(the_result) & DRIVER_SENSE)
sd_print_sense_hdr(sdkp, sshdr);
else
@@ -2001,7 +1982,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
do {
memset(cmd, 0, 16);
- cmd[0] = SERVICE_ACTION_IN;
+ cmd[0] = SERVICE_ACTION_IN_16;
cmd[1] = SAI_READ_CAPACITY_16;
cmd[13] = RC16_LEN;
memset(buffer, 0, RC16_LEN);
@@ -2036,7 +2017,7 @@ static int read_capacity_16(struct scsi_disk *sdkp, struct scsi_device *sdp,
} while (the_result && retries);
if (the_result) {
- sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY(16) failed\n");
+ sd_print_result(sdkp, "Read Capacity(16) failed", the_result);
read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result);
return -EINVAL;
}
@@ -2118,7 +2099,7 @@ static int read_capacity_10(struct scsi_disk *sdkp, struct scsi_device *sdp,
} while (the_result && retries);
if (the_result) {
- sd_printk(KERN_NOTICE, sdkp, "READ CAPACITY failed\n");
+ sd_print_result(sdkp, "Read Capacity(10) failed", the_result);
read_capacity_error(sdkp, sdp, &sshdr, sense_valid, the_result);
return -EINVAL;
}
@@ -2643,12 +2624,12 @@ static void sd_read_block_limits(struct scsi_disk *sdkp)
} else { /* LBP VPD page tells us what to use */
- if (sdkp->lbpu && sdkp->max_unmap_blocks)
- sd_config_discard(sdkp, SD_LBP_UNMAP);
- else if (sdkp->lbpws)
+ if (sdkp->lbpws)
sd_config_discard(sdkp, SD_LBP_WS16);
else if (sdkp->lbpws10)
sd_config_discard(sdkp, SD_LBP_WS10);
+ else if (sdkp->lbpu && sdkp->max_unmap_blocks)
+ sd_config_discard(sdkp, SD_LBP_UNMAP);
else
sd_config_discard(sdkp, SD_LBP_DISABLE);
}
@@ -3142,8 +3123,7 @@ static int sd_start_stop_device(struct scsi_disk *sdkp, int start)
res = scsi_execute_req_flags(sdp, cmd, DMA_NONE, NULL, 0, &sshdr,
SD_TIMEOUT, SD_MAX_RETRIES, NULL, REQ_PM);
if (res) {
- sd_printk(KERN_WARNING, sdkp, "START_STOP FAILED\n");
- sd_print_result(sdkp, res);
+ sd_print_result(sdkp, "Start/Stop Unit failed", res);
if (driver_byte(res) & DRIVER_SENSE)
sd_print_sense_hdr(sdkp, &sshdr);
if (scsi_sense_valid(&sshdr) &&
@@ -3337,15 +3317,27 @@ module_exit(exit_sd);
static void sd_print_sense_hdr(struct scsi_disk *sdkp,
struct scsi_sense_hdr *sshdr)
{
- sd_printk(KERN_INFO, sdkp, " ");
- scsi_show_sense_hdr(sshdr);
- sd_printk(KERN_INFO, sdkp, " ");
- scsi_show_extd_sense(sshdr->asc, sshdr->ascq);
+ scsi_show_sense_hdr(sdkp->device,
+ sdkp->disk ? sdkp->disk->disk_name : NULL, sshdr);
+ scsi_show_extd_sense(sdkp->device,
+ sdkp->disk ? sdkp->disk->disk_name : NULL,
+ sshdr->asc, sshdr->ascq);
}
-static void sd_print_result(struct scsi_disk *sdkp, int result)
+static void sd_print_result(const struct scsi_disk *sdkp, const char *msg,
+ int result)
{
- sd_printk(KERN_INFO, sdkp, " ");
- scsi_show_result(result);
+ const char *hb_string = scsi_hostbyte_string(result);
+ const char *db_string = scsi_driverbyte_string(result);
+
+ if (hb_string || db_string)
+ sd_printk(KERN_INFO, sdkp,
+ "%s: Result: hostbyte=%s driverbyte=%s\n", msg,
+ hb_string ? hb_string : "invalid",
+ db_string ? db_string : "invalid");
+ else
+ sd_printk(KERN_INFO, sdkp,
+ "%s: Result: hostbyte=0x%02x driverbyte=0x%02x\n",
+ msg, host_byte(result), driver_byte(result));
}
diff --git a/drivers/scsi/sd.h b/drivers/scsi/sd.h
index 4673778..63ba5ca 100644
--- a/drivers/scsi/sd.h
+++ b/drivers/scsi/sd.h
@@ -103,9 +103,9 @@ static inline struct scsi_disk *scsi_disk(struct gendisk *disk)
#define sd_printk(prefix, sdsk, fmt, a...) \
(sdsk)->disk ? \
- sdev_printk(prefix, (sdsk)->device, "[%s] " fmt, \
- (sdsk)->disk->disk_name, ##a) : \
- sdev_printk(prefix, (sdsk)->device, fmt, ##a)
+ sdev_prefix_printk(prefix, (sdsk)->device, \
+ (sdsk)->disk->disk_name, fmt, ##a) : \
+ sdev_printk(prefix, (sdsk)->device, fmt, ##a)
#define sd_first_printk(prefix, sdsk, fmt, a...) \
do { \
diff --git a/drivers/scsi/ses.c b/drivers/scsi/ses.c
index 80bfece..b7e79e7 100644
--- a/drivers/scsi/ses.c
+++ b/drivers/scsi/ses.c
@@ -693,9 +693,9 @@ static struct class_interface ses_interface = {
};
static struct scsi_driver ses_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "ses",
+ .owner = THIS_MODULE,
.probe = ses_probe,
.remove = ses_remove,
},
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
index 6035444..b14f64c 100644
--- a/drivers/scsi/sg.c
+++ b/drivers/scsi/sg.c
@@ -219,8 +219,8 @@ static void sg_device_destroy(struct kref *kref);
#define SZ_SG_REQ_INFO sizeof(sg_req_info_t)
#define sg_printk(prefix, sdp, fmt, a...) \
- sdev_printk(prefix, (sdp)->device, "[%s] " fmt, \
- (sdp)->disk->disk_name, ##a)
+ sdev_prefix_printk(prefix, (sdp)->device, \
+ (sdp)->disk->disk_name, fmt, ##a)
static int sg_allow_access(struct file *filp, unsigned char *cmd)
{
@@ -1071,39 +1071,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
if (atomic_read(&sdp->detaching))
return -ENODEV;
return put_user(sdp->device->host->hostt->emulated, ip);
- case SG_SCSI_RESET:
- if (atomic_read(&sdp->detaching))
- return -ENODEV;
- if (filp->f_flags & O_NONBLOCK) {
- if (scsi_host_in_recovery(sdp->device->host))
- return -EBUSY;
- } else if (!scsi_block_when_processing_errors(sdp->device))
- return -EBUSY;
- result = get_user(val, ip);
- if (result)
- return result;
- if (SG_SCSI_RESET_NOTHING == val)
- return 0;
- switch (val) {
- case SG_SCSI_RESET_DEVICE:
- val = SCSI_TRY_RESET_DEVICE;
- break;
- case SG_SCSI_RESET_TARGET:
- val = SCSI_TRY_RESET_TARGET;
- break;
- case SG_SCSI_RESET_BUS:
- val = SCSI_TRY_RESET_BUS;
- break;
- case SG_SCSI_RESET_HOST:
- val = SCSI_TRY_RESET_HOST;
- break;
- default:
- return -EINVAL;
- }
- if (!capable(CAP_SYS_ADMIN) || !capable(CAP_SYS_RAWIO))
- return -EACCES;
- return (scsi_reset_provider(sdp->device, val) ==
- SUCCESS) ? 0 : -EIO;
case SCSI_IOCTL_SEND_COMMAND:
if (atomic_read(&sdp->detaching))
return -ENODEV;
@@ -1123,13 +1090,6 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
return result;
sdp->sgdebug = (char) val;
return 0;
- case SCSI_IOCTL_GET_IDLUN:
- case SCSI_IOCTL_GET_BUS_NUMBER:
- case SCSI_IOCTL_PROBE_HOST:
- case SG_GET_TRANSFORM:
- if (atomic_read(&sdp->detaching))
- return -ENODEV;
- return scsi_ioctl(sdp->device, cmd_in, p);
case BLKSECTGET:
return put_user(max_sectors_bytes(sdp->device->request_queue),
ip);
@@ -1145,11 +1105,25 @@ sg_ioctl(struct file *filp, unsigned int cmd_in, unsigned long arg)
return blk_trace_startstop(sdp->device->request_queue, 0);
case BLKTRACETEARDOWN:
return blk_trace_remove(sdp->device->request_queue);
+ case SCSI_IOCTL_GET_IDLUN:
+ case SCSI_IOCTL_GET_BUS_NUMBER:
+ case SCSI_IOCTL_PROBE_HOST:
+ case SG_GET_TRANSFORM:
+ case SG_SCSI_RESET:
+ if (atomic_read(&sdp->detaching))
+ return -ENODEV;
+ break;
default:
if (read_only)
return -EPERM; /* don't know so take safe approach */
- return scsi_ioctl(sdp->device, cmd_in, p);
+ break;
}
+
+ result = scsi_ioctl_block_when_processing_errors(sdp->device,
+ cmd_in, filp->f_flags & O_NDELAY);
+ if (result)
+ return result;
+ return scsi_ioctl(sdp->device, cmd_in, p);
}
#ifdef CONFIG_COMPAT
@@ -1360,7 +1334,7 @@ sg_rq_end_io(struct request *rq, int uptodate)
if ((sdp->sgdebug > 0) &&
((CHECK_CONDITION == srp->header.masked_status) ||
(COMMAND_TERMINATED == srp->header.masked_status)))
- __scsi_print_sense(__func__, sense,
+ __scsi_print_sense(sdp->device, __func__, sense,
SCSI_SENSE_BUFFERSIZE);
/* Following if statement is a patch supplied by Eric Youngdale */
diff --git a/drivers/scsi/sr.c b/drivers/scsi/sr.c
index 2de44cc..8bd54a6 100644
--- a/drivers/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -88,9 +88,9 @@ static struct dev_pm_ops sr_pm_ops = {
};
static struct scsi_driver sr_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "sr",
+ .owner = THIS_MODULE,
.probe = sr_probe,
.remove = sr_remove,
.pm = &sr_pm_ops,
@@ -387,7 +387,7 @@ static int sr_init_command(struct scsi_cmnd *SCpnt)
struct request *rq = SCpnt->request;
int ret;
- ret = scsi_init_io(SCpnt, GFP_ATOMIC);
+ ret = scsi_init_io(SCpnt);
if (ret != BLKPREP_OK)
goto out;
SCpnt = rq->special;
@@ -549,6 +549,11 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
mutex_lock(&sr_mutex);
+ ret = scsi_ioctl_block_when_processing_errors(sdev, cmd,
+ (mode & FMODE_NDELAY) != 0);
+ if (ret)
+ goto out;
+
/*
* Send SCSI addressing ioctls directly to mid level, send other
* ioctls to cdrom/block level.
@@ -564,16 +569,6 @@ static int sr_block_ioctl(struct block_device *bdev, fmode_t mode, unsigned cmd,
if (ret != -ENOSYS)
goto out;
- /*
- * ENODEV means that we didn't recognise the ioctl, or that we
- * cannot execute it in the current device state. In either
- * case fall through to scsi_ioctl, which will return ENDOEV again
- * if it doesn't recognise the ioctl
- */
- ret = scsi_nonblockable_ioctl(sdev, cmd, argp,
- (mode & FMODE_NDELAY) != 0);
- if (ret != -ENODEV)
- goto out;
ret = scsi_ioctl(sdev, cmd, argp);
out:
diff --git a/drivers/scsi/sr.h b/drivers/scsi/sr.h
index 1d1f6f41..1de3371 100644
--- a/drivers/scsi/sr.h
+++ b/drivers/scsi/sr.h
@@ -57,8 +57,7 @@ typedef struct scsi_cd {
} Scsi_CD;
#define sr_printk(prefix, cd, fmt, a...) \
- sdev_printk(prefix, (cd)->device, "[%s] " fmt, \
- (cd)->cdi.name, ##a)
+ sdev_prefix_printk(prefix, (cd)->device, (cd)->cdi.name, fmt, ##a)
int sr_do_ioctl(Scsi_CD *, struct packet_command *);
diff --git a/drivers/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 6389fcf..fb929fa 100644
--- a/drivers/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -246,7 +246,7 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
"CDROM not ready. Make sure there "
"is a disc in the drive.\n");
#ifdef DEBUG
- scsi_print_sense_hdr("sr", &sshdr);
+ scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr);
#endif
err = -ENOMEDIUM;
break;
@@ -257,15 +257,15 @@ int sr_do_ioctl(Scsi_CD *cd, struct packet_command *cgc)
/* sense: Invalid command operation code */
err = -EDRIVE_CANT_DO_THIS;
#ifdef DEBUG
- __scsi_print_command(cgc->cmd);
- scsi_print_sense_hdr("sr", &sshdr);
+ __scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE);
+ scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr);
#endif
break;
default:
sr_printk(KERN_ERR, cd,
"CDROM (ioctl) error, command: ");
- __scsi_print_command(cgc->cmd);
- scsi_print_sense_hdr("sr", &sshdr);
+ __scsi_print_command(cgc->cmd, CDROM_PACKET_SIZE);
+ scsi_print_sense_hdr(cd->device, cd->cdi.name, &sshdr);
err = -EIO;
}
}
diff --git a/drivers/scsi/st.c b/drivers/scsi/st.c
index 4daa372..128d3b5 100644
--- a/drivers/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -56,7 +56,8 @@ static const char *verstr = "20101219";
/* The driver prints some debugging information on the console if DEBUG
is defined and non-zero. */
-#define DEBUG 0
+#define DEBUG 1
+#define NO_DEBUG 0
#define ST_DEB_MSG KERN_NOTICE
#if DEBUG
@@ -80,6 +81,7 @@ static int max_sg_segs;
static int try_direct_io = TRY_DIRECT_IO;
static int try_rdio = 1;
static int try_wdio = 1;
+static int debug_flag;
static struct class st_sysfs_class;
static const struct attribute_group *st_dev_groups[];
@@ -100,6 +102,9 @@ module_param_named(max_sg_segs, max_sg_segs, int, 0);
MODULE_PARM_DESC(max_sg_segs, "Maximum number of scatter/gather segments to use (256)");
module_param_named(try_direct_io, try_direct_io, int, 0);
MODULE_PARM_DESC(try_direct_io, "Try direct I/O between user buffer and tape drive (1)");
+module_param_named(debug_flag, debug_flag, int, 0);
+MODULE_PARM_DESC(debug_flag, "Enable DEBUG, same as setting debugging=1");
+
/* Extra parameters for testing */
module_param_named(try_rdio, try_rdio, int, 0);
@@ -124,6 +129,9 @@ static struct st_dev_parm {
},
{
"try_direct_io", &try_direct_io
+ },
+ {
+ "debug_flag", &debug_flag
}
};
#endif
@@ -194,9 +202,9 @@ static int do_create_sysfs_files(void);
static void do_remove_sysfs_files(void);
static struct scsi_driver st_template = {
- .owner = THIS_MODULE,
.gendrv = {
.name = "st",
+ .owner = THIS_MODULE,
.probe = st_probe,
.remove = st_remove,
},
@@ -306,8 +314,7 @@ static inline char *tape_name(struct scsi_tape *tape)
}
#define st_printk(prefix, t, fmt, a...) \
- sdev_printk(prefix, (t)->device, "%s: " fmt, \
- tape_name(t), ##a)
+ sdev_prefix_printk(prefix, (t)->device, tape_name(t), fmt, ##a)
#ifdef DEBUG
#define DEBC_printk(t, fmt, a...) \
if (debugging) { st_printk(ST_DEB_MSG, t, fmt, ##a ); }
@@ -374,7 +381,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
SRpnt->cmd[0], SRpnt->cmd[1], SRpnt->cmd[2],
SRpnt->cmd[3], SRpnt->cmd[4], SRpnt->cmd[5]);
if (cmdstatp->have_sense)
- __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(STp->device, name,
+ SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
} ) /* end DEB */
if (!debugging) { /* Abnormal conditions for tape */
if (!cmdstatp->have_sense)
@@ -390,7 +398,8 @@ static int st_chk_result(struct scsi_tape *STp, struct st_request * SRpnt)
SRpnt->cmd[0] != MODE_SENSE &&
SRpnt->cmd[0] != TEST_UNIT_READY) {
- __scsi_print_sense(name, SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
+ __scsi_print_sense(STp->device, name,
+ SRpnt->sense, SCSI_SENSE_BUFFERSIZE);
}
}
@@ -852,17 +861,16 @@ static int set_mode_densblk(struct scsi_tape * STp, struct st_modedef * STm)
/* Lock or unlock the drive door. Don't use when st_request allocated. */
static int do_door_lock(struct scsi_tape * STp, int do_lock)
{
- int retval, cmd;
+ int retval;
- cmd = do_lock ? SCSI_IOCTL_DOORLOCK : SCSI_IOCTL_DOORUNLOCK;
DEBC_printk(STp, "%socking drive door.\n", do_lock ? "L" : "Unl");
- retval = scsi_ioctl(STp->device, cmd, NULL);
- if (!retval) {
+
+ retval = scsi_set_medium_removal(STp->device,
+ do_lock ? SCSI_REMOVAL_PREVENT : SCSI_REMOVAL_ALLOW);
+ if (!retval)
STp->door_locked = do_lock ? ST_LOCKED_EXPLICIT : ST_UNLOCKED;
- }
- else {
+ else
STp->door_locked = ST_LOCK_FAILS;
- }
return retval;
}
@@ -3367,11 +3375,10 @@ static long st_ioctl(struct file *file, unsigned int cmd_in, unsigned long arg)
* may try and take the device offline, in which case all further
* access to the device is prohibited.
*/
- retval = scsi_nonblockable_ioctl(STp->device, cmd_in, p,
- file->f_flags & O_NDELAY);
- if (!scsi_block_when_processing_errors(STp->device) || retval != -ENODEV)
+ retval = scsi_ioctl_block_when_processing_errors(STp->device, cmd_in,
+ file->f_flags & O_NDELAY);
+ if (retval)
goto out;
- retval = 0;
cmd_type = _IOC_TYPE(cmd_in);
cmd_nr = _IOC_NR(cmd_in);
@@ -4309,6 +4316,12 @@ static int __init init_st(void)
printk(KERN_INFO "st: Version %s, fixed bufsize %d, s/g segs %d\n",
verstr, st_fixed_buffer_size, st_max_sg_segs);
+ debugging = (debug_flag > 0) ? debug_flag : NO_DEBUG;
+ if (debugging) {
+ printk(KERN_INFO "st: Debugging enabled debug_flag = %d\n",
+ debugging);
+ }
+
err = class_register(&st_sysfs_class);
if (err) {
pr_err("Unable register sysfs class for SCSI tapes\n");
diff --git a/drivers/scsi/stex.c b/drivers/scsi/stex.c
index 1aa4bef..98a62bc 100644
--- a/drivers/scsi/stex.c
+++ b/drivers/scsi/stex.c
@@ -544,33 +544,15 @@ stex_ss_send_cmd(struct st_hba *hba, struct req_msg *req, u16 tag)
}
static int
-stex_slave_alloc(struct scsi_device *sdev)
-{
- /* Cheat: usually extracted from Inquiry data */
- sdev->tagged_supported = 1;
-
- scsi_activate_tcq(sdev, sdev->host->can_queue);
-
- return 0;
-}
-
-static int
stex_slave_config(struct scsi_device *sdev)
{
sdev->use_10_for_rw = 1;
sdev->use_10_for_ms = 1;
blk_queue_rq_timeout(sdev->request_queue, 60 * HZ);
- sdev->tagged_supported = 1;
return 0;
}
-static void
-stex_slave_destroy(struct scsi_device *sdev)
-{
- scsi_deactivate_tcq(sdev, 1);
-}
-
static int
stex_queuecommand_lck(struct scsi_cmnd *cmd, void (*done)(struct scsi_cmnd *))
{
@@ -1162,9 +1144,7 @@ static int stex_abort(struct scsi_cmnd *cmd)
int result = SUCCESS;
unsigned long flags;
- printk(KERN_INFO DRV_NAME
- "(%s): aborting command\n", pci_name(hba->pdev));
- scsi_print_command(cmd);
+ scmd_printk(KERN_INFO, cmd, "aborting command\n");
base = hba->mmio_base;
spin_lock_irqsave(host->host_lock, flags);
@@ -1352,9 +1332,8 @@ static int stex_reset(struct scsi_cmnd *cmd)
hba = (struct st_hba *) &cmd->device->host->hostdata[0];
- printk(KERN_INFO DRV_NAME
- "(%s): resetting host\n", pci_name(hba->pdev));
- scsi_print_command(cmd);
+ shost_printk(KERN_INFO, cmd->device->host,
+ "resetting host\n");
return stex_do_reset(hba) ? FAILED : SUCCESS;
}
@@ -1391,12 +1370,11 @@ static struct scsi_host_template driver_template = {
.proc_name = DRV_NAME,
.bios_param = stex_biosparam,
.queuecommand = stex_queuecommand,
- .slave_alloc = stex_slave_alloc,
.slave_configure = stex_slave_config,
- .slave_destroy = stex_slave_destroy,
.eh_abort_handler = stex_abort,
.eh_host_reset_handler = stex_reset,
.this_id = -1,
+ .use_blk_tags = 1,
};
static struct pci_device_id stex_pci_tbl[] = {
diff --git a/drivers/scsi/storvsc_drv.c b/drivers/scsi/storvsc_drv.c
index 733e5f7..e3ba251 100644
--- a/drivers/scsi/storvsc_drv.c
+++ b/drivers/scsi/storvsc_drv.c
@@ -1097,7 +1097,8 @@ static void storvsc_command_completion(struct storvsc_cmd_request *cmd_request)
if (scmnd->result) {
if (scsi_normalize_sense(scmnd->sense_buffer,
SCSI_SENSE_BUFFERSIZE, &sense_hdr))
- scsi_print_sense_hdr("storvsc", &sense_hdr);
+ scsi_print_sense_hdr(scmnd->device, "storvsc",
+ &sense_hdr);
}
if (vm_srb->srb_status != SRB_STATUS_SUCCESS)
@@ -1428,8 +1429,7 @@ static void storvsc_device_destroy(struct scsi_device *sdevice)
static int storvsc_device_configure(struct scsi_device *sdevice)
{
- scsi_adjust_queue_depth(sdevice, MSG_SIMPLE_TAG,
- STORVSC_MAX_IO_REQUESTS);
+ scsi_change_queue_depth(sdevice, STORVSC_MAX_IO_REQUESTS);
blk_queue_max_segment_size(sdevice->request_queue, PAGE_SIZE);
diff --git a/drivers/scsi/sun3_NCR5380.c b/drivers/scsi/sun3_NCR5380.c
deleted file mode 100644
index 1a2367a..0000000
--- a/drivers/scsi/sun3_NCR5380.c
+++ /dev/null
@@ -1,2933 +0,0 @@
-/* sun3_NCR5380.c -- adapted from atari_NCR5380.c for the sun3 by
- Sam Creasey. */
-/*
- * NCR 5380 generic driver routines. These should make it *trivial*
- * to implement 5380 SCSI drivers under Linux with a non-trantor
- * architecture.
- *
- * Note that these routines also work with NR53c400 family chips.
- *
- * Copyright 1993, Drew Eckhardt
- * Visionary Computing
- * (Unix and Linux consulting and custom programming)
- * drew@colorado.edu
- * +1 (303) 666-5836
- *
- * DISTRIBUTION RELEASE 6.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
- */
-
-/*
- * ++roman: To port the 5380 driver to the Atari, I had to do some changes in
- * this file, too:
- *
- * - Some of the debug statements were incorrect (undefined variables and the
- * like). I fixed that.
- *
- * - In information_transfer(), I think a #ifdef was wrong. Looking at the
- * possible DMA transfer size should also happen for REAL_DMA. I added this
- * in the #if statement.
- *
- * - When using real DMA, information_transfer() should return in a DATAOUT
- * phase after starting the DMA. It has nothing more to do.
- *
- * - The interrupt service routine should run main after end of DMA, too (not
- * only after RESELECTION interrupts). Additionally, it should _not_ test
- * for more interrupts after running main, since a DMA process may have
- * been started and interrupts are turned on now. The new int could happen
- * inside the execution of NCR5380_intr(), leading to recursive
- * calls.
- *
- * - I've deleted all the stuff for AUTOPROBE_IRQ, REAL_DMA_POLL, PSEUDO_DMA
- * and USLEEP, because these were messing up readability and will never be
- * needed for Atari SCSI.
- *
- * - I've revised the NCR5380_main() calling scheme (relax the 'main_running'
- * stuff), and 'main' is executed in a bottom half if awoken by an
- * interrupt.
- *
- * - The code was quite cluttered up by "#if (NDEBUG & NDEBUG_*) printk..."
- * constructs. In my eyes, this made the source rather unreadable, so I
- * finally replaced that by the *_PRINTK() macros.
- *
- */
-#include <scsi/scsi_dbg.h>
-#include <scsi/scsi_transport_spi.h>
-
-/*
- * Further development / testing that should be done :
- * 1. Test linked command handling code after Eric is ready with
- * the high level code.
- */
-
-#if (NDEBUG & NDEBUG_LISTS)
-#define LIST(x,y) \
- { printk("LINE:%d Adding %p to %p\n", __LINE__, (void*)(x), (void*)(y)); \
- if ((x)==(y)) udelay(5); }
-#define REMOVE(w,x,y,z) \
- { printk("LINE:%d Removing: %p->%p %p->%p \n", __LINE__, \
- (void*)(w), (void*)(x), (void*)(y), (void*)(z)); \
- if ((x)==(y)) udelay(5); }
-#else
-#define LIST(x,y)
-#define REMOVE(w,x,y,z)
-#endif
-
-#ifndef notyet
-#undef LINKED
-#endif
-
-/*
- * Design
- * Issues :
- *
- * The other Linux SCSI drivers were written when Linux was Intel PC-only,
- * and specifically for each board rather than each chip. This makes their
- * adaptation to platforms like the Mac (Some of which use NCR5380's)
- * more difficult than it has to be.
- *
- * Also, many of the SCSI drivers were written before the command queuing
- * routines were implemented, meaning their implementations of queued
- * commands were hacked on rather than designed in from the start.
- *
- * When I designed the Linux SCSI drivers I figured that
- * while having two different SCSI boards in a system might be useful
- * for debugging things, two of the same type wouldn't be used.
- * Well, I was wrong and a number of users have mailed me about running
- * multiple high-performance SCSI boards in a server.
- *
- * Finally, when I get questions from users, I have no idea what
- * revision of my driver they are running.
- *
- * This driver attempts to address these problems :
- * This is a generic 5380 driver. To use it on a different platform,
- * one simply writes appropriate system specific macros (ie, data
- * transfer - some PC's will use the I/O bus, 68K's must use
- * memory mapped) and drops this file in their 'C' wrapper.
- *
- * As far as command queueing, two queues are maintained for
- * each 5380 in the system - commands that haven't been issued yet,
- * and commands that are currently executing. This means that an
- * unlimited number of commands may be queued, letting
- * more commands propagate from the higher driver levels giving higher
- * throughput. Note that both I_T_L and I_T_L_Q nexuses are supported,
- * allowing multiple commands to propagate all the way to a SCSI-II device
- * while a command is already executing.
- *
- * To solve the multiple-boards-in-the-same-system problem,
- * there is a separate instance structure for each instance
- * of a 5380 in the system. So, multiple NCR5380 drivers will
- * be able to coexist with appropriate changes to the high level
- * SCSI code.
- *
- * A NCR5380_PUBLIC_REVISION macro is provided, with the release
- * number (updated for each public release) printed by the
- * NCR5380_print_options command, which should be called from the
- * wrapper detect function, so that I know what release of the driver
- * users are using.
- *
- * Issues specific to the NCR5380 :
- *
- * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
- * piece of hardware that requires you to sit in a loop polling for
- * the REQ signal as long as you are connected. Some devices are
- * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
- * while doing long seek operations.
- *
- * The workaround for this is to keep track of devices that have
- * disconnected. If the device hasn't disconnected, for commands that
- * should disconnect, we do something like
- *
- * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
- *
- * Some tweaking of N and M needs to be done. An algorithm based
- * on "time to data" would give the best results as long as short time
- * to datas (ie, on the same track) were considered, however these
- * broken devices are the exception rather than the rule and I'd rather
- * spend my time optimizing for the normal case.
- *
- * Architecture :
- *
- * At the heart of the design is a coroutine, NCR5380_main,
- * which is started when not running by the interrupt handler,
- * timer, and queue command function. It attempts to establish
- * I_T_L or I_T_L_Q nexuses by removing the commands from the
- * issue queue and calling NCR5380_select() if a nexus
- * is not established.
- *
- * Once a nexus is established, the NCR5380_information_transfer()
- * phase goes through the various phases as instructed by the target.
- * if the target goes into MSG IN and sends a DISCONNECT message,
- * the command structure is placed into the per instance disconnected
- * queue, and NCR5380_main tries to find more work. If USLEEP
- * was defined, and the target is idle for too long, the system
- * will try to sleep.
- *
- * If a command has disconnected, eventually an interrupt will trigger,
- * calling NCR5380_intr() which will in turn call NCR5380_reselect
- * to reestablish a nexus. This will run main if necessary.
- *
- * On command termination, the done function will be called as
- * appropriate.
- *
- * SCSI pointers are maintained in the SCp field of SCSI command
- * structures, being initialized after the command is connected
- * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
- * Note that in violation of the standard, an implicit SAVE POINTERS operation
- * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
- */
-
-/*
- * Using this file :
- * This file a skeleton Linux SCSI driver for the NCR 5380 series
- * of chips. To use it, you write an architecture specific functions
- * and macros and include this file in your driver.
- *
- * These macros control options :
- * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
- *
- * LINKED - if defined, linked commands are supported.
- *
- * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
- *
- * SUPPORT_TAGS - if defined, SCSI-2 tagged queuing is used where possible
- *
- * These macros MUST be defined :
- *
- * NCR5380_read(register) - read from the specified register
- *
- * NCR5380_write(register, value) - write to the specific register
- *
- * Either real DMA *or* pseudo DMA may be implemented
- * REAL functions :
- * NCR5380_REAL_DMA should be defined if real DMA is to be used.
- * Note that the DMA setup functions should return the number of bytes
- * that they were able to program the controller for.
- *
- * Also note that generic i386/PC versions of these macros are
- * available as NCR5380_i386_dma_write_setup,
- * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual.
- *
- * NCR5380_dma_write_setup(instance, src, count) - initialize
- * NCR5380_dma_read_setup(instance, dst, count) - initialize
- * NCR5380_dma_residual(instance); - residual count
- *
- * PSEUDO functions :
- * NCR5380_pwrite(instance, src, count)
- * NCR5380_pread(instance, dst, count);
- *
- * If nothing specific to this implementation needs doing (ie, with external
- * hardware), you must also define
- *
- * NCR5380_queue_command
- * NCR5380_reset
- * NCR5380_abort
- * NCR5380_proc_info
- *
- * to be the global entry points into the specific driver, ie
- * #define NCR5380_queue_command t128_queue_command.
- *
- * If this is not done, the routines will be defined as static functions
- * with the NCR5380* names and the user must provide a globally
- * accessible wrapper function.
- *
- * The generic driver is initialized by calling NCR5380_init(instance),
- * after setting the appropriate host specific fields and ID. If the
- * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
- * possible) function may be used. Before the specific driver initialization
- * code finishes, NCR5380_print_options should be called.
- */
-
-static struct Scsi_Host *first_instance = NULL;
-static struct scsi_host_template *the_template = NULL;
-
-/* Macros ease life... :-) */
-#define SETUP_HOSTDATA(in) \
- struct NCR5380_hostdata *hostdata = \
- (struct NCR5380_hostdata *)(in)->hostdata
-#define HOSTDATA(in) ((struct NCR5380_hostdata *)(in)->hostdata)
-
-#define NEXT(cmd) ((struct scsi_cmnd *)(cmd)->host_scribble)
-#define SET_NEXT(cmd, next) ((cmd)->host_scribble = (void *)(next))
-#define NEXTADDR(cmd) ((struct scsi_cmnd **)&((cmd)->host_scribble))
-
-#define HOSTNO instance->host_no
-#define H_NO(cmd) (cmd)->device->host->host_no
-
-#define SGADDR(buffer) (void *)(((unsigned long)sg_virt(((buffer)))))
-
-#ifdef SUPPORT_TAGS
-
-/*
- * Functions for handling tagged queuing
- * =====================================
- *
- * ++roman (01/96): Now I've implemented SCSI-2 tagged queuing. Some notes:
- *
- * Using consecutive numbers for the tags is no good idea in my eyes. There
- * could be wrong re-usings if the counter (8 bit!) wraps and some early
- * command has been preempted for a long time. My solution: a bitfield for
- * remembering used tags.
- *
- * There's also the problem that each target has a certain queue size, but we
- * cannot know it in advance :-( We just see a QUEUE_FULL status being
- * returned. So, in this case, the driver internal queue size assumption is
- * reduced to the number of active tags if QUEUE_FULL is returned by the
- * target. The command is returned to the mid-level, but with status changed
- * to BUSY, since --as I've seen-- the mid-level can't handle QUEUE_FULL
- * correctly.
- *
- * We're also not allowed running tagged commands as long as an untagged
- * command is active. And REQUEST SENSE commands after a contingent allegiance
- * condition _must_ be untagged. To keep track whether an untagged command has
- * been issued, the host->busy array is still employed, as it is without
- * support for tagged queuing.
- *
- * One could suspect that there are possible race conditions between
- * is_lun_busy(), cmd_get_tag() and cmd_free_tag(). But I think this isn't the
- * case: is_lun_busy() and cmd_get_tag() are both called from NCR5380_main(),
- * which already guaranteed to be running at most once. It is also the only
- * place where tags/LUNs are allocated. So no other allocation can slip
- * between that pair, there could only happen a reselection, which can free a
- * tag, but that doesn't hurt. Only the sequence in cmd_free_tag() becomes
- * important: the tag bit must be cleared before 'nr_allocated' is decreased.
- */
-
-/* -1 for TAG_NONE is not possible with unsigned char cmd->tag */
-#undef TAG_NONE
-#define TAG_NONE 0xff
-
-/* For the m68k, the number of bits in 'allocated' must be a multiple of 32! */
-#if (MAX_TAGS % 32) != 0
-#error "MAX_TAGS must be a multiple of 32!"
-#endif
-
-typedef struct {
- char allocated[MAX_TAGS/8];
- int nr_allocated;
- int queue_size;
-} TAG_ALLOC;
-
-static TAG_ALLOC TagAlloc[8][8]; /* 8 targets and 8 LUNs */
-
-
-static void __init init_tags( void )
-{
- int target, lun;
- TAG_ALLOC *ta;
-
- if (!setup_use_tagged_queuing)
- return;
-
- for( target = 0; target < 8; ++target ) {
- for( lun = 0; lun < 8; ++lun ) {
- ta = &TagAlloc[target][lun];
- memset( &ta->allocated, 0, MAX_TAGS/8 );
- ta->nr_allocated = 0;
- /* At the beginning, assume the maximum queue size we could
- * support (MAX_TAGS). This value will be decreased if the target
- * returns QUEUE_FULL status.
- */
- ta->queue_size = MAX_TAGS;
- }
- }
-}
-
-
-/* Check if we can issue a command to this LUN: First see if the LUN is marked
- * busy by an untagged command. If the command should use tagged queuing, also
- * check that there is a free tag and the target's queue won't overflow. This
- * function should be called with interrupts disabled to avoid race
- * conditions.
- */
-
-static int is_lun_busy(struct scsi_cmnd *cmd, int should_be_tagged)
-{
- u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
-
- if (hostdata->busy[cmd->device->id] & (1 << lun))
- return( 1 );
- if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported)
- return( 0 );
- if (TagAlloc[cmd->device->id][lun].nr_allocated >=
- TagAlloc[cmd->device->id][lun].queue_size ) {
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d: no free tags\n",
- H_NO(cmd), cmd->device->id, lun );
- return( 1 );
- }
- return( 0 );
-}
-
-
-/* Allocate a tag for a command (there are no checks anymore, check_lun_busy()
- * must be called before!), or reserve the LUN in 'busy' if the command is
- * untagged.
- */
-
-static void cmd_get_tag(struct scsi_cmnd *cmd, int should_be_tagged)
-{
- u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
-
- /* If we or the target don't support tagged queuing, allocate the LUN for
- * an untagged command.
- */
- if (!should_be_tagged ||
- !setup_use_tagged_queuing || !cmd->device->tagged_supported) {
- cmd->tag = TAG_NONE;
- hostdata->busy[cmd->device->id] |= (1 << lun);
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d now allocated by untagged "
- "command\n", H_NO(cmd), cmd->device->id, lun );
- }
- else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][lun];
-
- cmd->tag = find_first_zero_bit( &ta->allocated, MAX_TAGS );
- set_bit( cmd->tag, &ta->allocated );
- ta->nr_allocated++;
- dprintk(NDEBUG_TAGS, "scsi%d: using tag %d for target %d lun %d "
- "(now %d tags in use)\n",
- H_NO(cmd), cmd->tag, cmd->device->id, lun,
- ta->nr_allocated );
- }
-}
-
-
-/* Mark the tag of command 'cmd' as free, or in case of an untagged command,
- * unlock the LUN.
- */
-
-static void cmd_free_tag(struct scsi_cmnd *cmd)
-{
- u8 lun = cmd->device->lun;
- SETUP_HOSTDATA(cmd->device->host);
-
- if (cmd->tag == TAG_NONE) {
- hostdata->busy[cmd->device->id] &= ~(1 << lun);
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %d untagged cmd finished\n",
- H_NO(cmd), cmd->device->id, lun );
- }
- else if (cmd->tag >= MAX_TAGS) {
- printk(KERN_NOTICE "scsi%d: trying to free bad tag %d!\n",
- H_NO(cmd), cmd->tag );
- }
- else {
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][lun];
- clear_bit( cmd->tag, &ta->allocated );
- ta->nr_allocated--;
- dprintk(NDEBUG_TAGS, "scsi%d: freed tag %d for target %d lun %d\n",
- H_NO(cmd), cmd->tag, cmd->device->id, lun );
- }
-}
-
-
-static void free_all_tags( void )
-{
- int target, lun;
- TAG_ALLOC *ta;
-
- if (!setup_use_tagged_queuing)
- return;
-
- for( target = 0; target < 8; ++target ) {
- for( lun = 0; lun < 8; ++lun ) {
- ta = &TagAlloc[target][lun];
- memset( &ta->allocated, 0, MAX_TAGS/8 );
- ta->nr_allocated = 0;
- }
- }
-}
-
-#endif /* SUPPORT_TAGS */
-
-
-/*
- * Function : void initialize_SCp(struct scsi_cmnd *cmd)
- *
- * Purpose : initialize the saved data pointers for cmd to point to the
- * start of the buffer.
- *
- * Inputs : cmd - struct scsi_cmnd structure to have pointers reset.
- */
-
-static __inline__ void initialize_SCp(struct scsi_cmnd *cmd)
-{
- /*
- * Initialize the Scsi Pointer field so that all of the commands in the
- * various queues are valid.
- */
-
- if (scsi_bufflen(cmd)) {
- cmd->SCp.buffer = scsi_sglist(cmd);
- cmd->SCp.buffers_residual = scsi_sg_count(cmd) - 1;
- cmd->SCp.ptr = (char *) SGADDR(cmd->SCp.buffer);
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- } else {
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- cmd->SCp.ptr = NULL;
- cmd->SCp.this_residual = 0;
- }
-
-}
-
-#include <linux/delay.h>
-
-#if NDEBUG
-static struct {
- unsigned char mask;
- const char * name;}
-signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
- { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
- { SR_SEL, "SEL" }, {0, NULL}},
-basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
-icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
- {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
- {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
- {0, NULL}},
-mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
- {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
- "MODE PARITY INTR"}, {MR_ENABLE_EOP_INTR,"MODE EOP INTR"},
- {MR_MONITOR_BSY, "MODE MONITOR BSY"},
- {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
- {0, NULL}};
-
-/*
- * Function : void NCR5380_print(struct Scsi_Host *instance)
- *
- * Purpose : print the SCSI bus signals for debugging purposes
- *
- * Input : instance - which NCR5380
- */
-
-static void NCR5380_print(struct Scsi_Host *instance) {
- unsigned char status, data, basr, mr, icr, i;
- unsigned long flags;
-
- local_irq_save(flags);
- data = NCR5380_read(CURRENT_SCSI_DATA_REG);
- status = NCR5380_read(STATUS_REG);
- mr = NCR5380_read(MODE_REG);
- icr = NCR5380_read(INITIATOR_COMMAND_REG);
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- local_irq_restore(flags);
- printk("STATUS_REG: %02x ", status);
- for (i = 0; signals[i].mask ; ++i)
- if (status & signals[i].mask)
- printk(",%s", signals[i].name);
- printk("\nBASR: %02x ", basr);
- for (i = 0; basrs[i].mask ; ++i)
- if (basr & basrs[i].mask)
- printk(",%s", basrs[i].name);
- printk("\nICR: %02x ", icr);
- for (i = 0; icrs[i].mask; ++i)
- if (icr & icrs[i].mask)
- printk(",%s", icrs[i].name);
- printk("\nMODE: %02x ", mr);
- for (i = 0; mrs[i].mask; ++i)
- if (mr & mrs[i].mask)
- printk(",%s", mrs[i].name);
- printk("\n");
-}
-
-static struct {
- unsigned char value;
- const char *name;
-} phases[] = {
- {PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
- {PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
- {PHASE_UNKNOWN, "UNKNOWN"}};
-
-/*
- * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
- *
- * Purpose : print the current SCSI phase for debugging purposes
- *
- * Input : instance - which NCR5380
- */
-
-static void NCR5380_print_phase(struct Scsi_Host *instance)
-{
- unsigned char status;
- int i;
-
- status = NCR5380_read(STATUS_REG);
- if (!(status & SR_REQ))
- printk(KERN_DEBUG "scsi%d: REQ not asserted, phase unknown.\n", HOSTNO);
- else {
- for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
- (phases[i].value != (status & PHASE_MASK)); ++i);
- printk(KERN_DEBUG "scsi%d: phase %s\n", HOSTNO, phases[i].name);
- }
-}
-
-#endif
-
-/*
- * ++roman: New scheme of calling NCR5380_main()
- *
- * If we're not in an interrupt, we can call our main directly, it cannot be
- * already running. Else, we queue it on a task queue, if not 'main_running'
- * tells us that a lower level is already executing it. This way,
- * 'main_running' needs not be protected in a special way.
- *
- * queue_main() is a utility function for putting our main onto the task
- * queue, if main_running is false. It should be called only from a
- * interrupt or bottom half.
- */
-
-#include <linux/gfp.h>
-#include <linux/workqueue.h>
-#include <linux/interrupt.h>
-
-static volatile int main_running = 0;
-static DECLARE_WORK(NCR5380_tqueue, NCR5380_main);
-
-static __inline__ void queue_main(void)
-{
- if (!main_running) {
- /* If in interrupt and NCR5380_main() not already running,
- queue it on the 'immediate' task queue, to be processed
- immediately after the current interrupt processing has
- finished. */
- schedule_work(&NCR5380_tqueue);
- }
- /* else: nothing to do: the running NCR5380_main() will pick up
- any newly queued command. */
-}
-
-
-static inline void NCR5380_all_init (void)
-{
- static int done = 0;
- if (!done) {
- dprintk(NDEBUG_INIT, "scsi : NCR5380_all_init()\n");
- done = 1;
- }
-}
-
-
-/*
- * Function : void NCR58380_print_options (struct Scsi_Host *instance)
- *
- * Purpose : called by probe code indicating the NCR5380 driver
- * options that were selected.
- *
- * Inputs : instance, pointer to this instance. Unused.
- */
-
-static void __init NCR5380_print_options (struct Scsi_Host *instance)
-{
- printk(" generic options"
-#ifdef AUTOSENSE
- " AUTOSENSE"
-#endif
-#ifdef REAL_DMA
- " REAL DMA"
-#endif
-#ifdef PARITY
- " PARITY"
-#endif
-#ifdef SUPPORT_TAGS
- " SCSI-2 TAGGED QUEUING"
-#endif
- );
- printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
-}
-
-/*
- * Function : void NCR5380_print_status (struct Scsi_Host *instance)
- *
- * Purpose : print commands in the various queues, called from
- * NCR5380_abort and NCR5380_debug to aid debugging.
- *
- * Inputs : instance, pointer to this instance.
- */
-
-static void lprint_Scsi_Cmnd(Scsi_Cmnd *cmd)
-{
- int i, s;
- unsigned char *command;
- printk("scsi%d: destination target %d, lun %llu\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- printk(KERN_CONT " command = ");
- command = cmd->cmnd;
- printk(KERN_CONT "%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- printk(KERN_CONT " %02x", command[i]);
- printk("\n");
-}
-
-static void NCR5380_print_status(struct Scsi_Host *instance)
-{
- struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
- unsigned long flags;
-
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_dprint_phase(NDEBUG_ANY, instance);
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- printk("\nNCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
- local_irq_save(flags);
- printk("NCR5380: coroutine is%s running.\n",
- main_running ? "" : "n't");
- if (!hostdata->connected)
- printk("scsi%d: no currently connected command\n", HOSTNO);
- else
- lprint_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected);
- printk("scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- lprint_Scsi_Cmnd(ptr);
-
- printk("scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr))
- lprint_Scsi_Cmnd(ptr);
-
- local_irq_restore(flags);
- printk("\n");
-}
-
-static void show_Scsi_Cmnd(Scsi_Cmnd *cmd, struct seq_file *m)
-{
- int i, s;
- unsigned char *command;
- seq_printf(m, "scsi%d: destination target %d, lun %llu\n",
- H_NO(cmd), cmd->device->id, cmd->device->lun);
- seq_printf(m, " command = ");
- command = cmd->cmnd;
- seq_printf(m, "%2d (0x%02x)", command[0], command[0]);
- for (i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i)
- seq_printf(m, " %02x", command[i]);
- seq_printf(m, "\n");
-}
-
-static int NCR5380_show_info(struct seq_file *m, struct Scsi_Host *instance)
-{
- struct NCR5380_hostdata *hostdata;
- Scsi_Cmnd *ptr;
- unsigned long flags;
-
- hostdata = (struct NCR5380_hostdata *)instance->hostdata;
-
- seq_printf(m, "NCR5380 core release=%d.\n", NCR5380_PUBLIC_RELEASE);
- local_irq_save(flags);
- seq_printf(m, "NCR5380: coroutine is%s running.\n",
- main_running ? "" : "n't");
- if (!hostdata->connected)
- seq_printf(m, "scsi%d: no currently connected command\n", HOSTNO);
- else
- show_Scsi_Cmnd((Scsi_Cmnd *) hostdata->connected, m);
- seq_printf(m, "scsi%d: issue_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *)hostdata->issue_queue; ptr; ptr = NEXT(ptr))
- show_Scsi_Cmnd(ptr, m);
-
- seq_printf(m, "scsi%d: disconnected_queue\n", HOSTNO);
- for (ptr = (Scsi_Cmnd *) hostdata->disconnected_queue; ptr;
- ptr = NEXT(ptr))
- show_Scsi_Cmnd(ptr, m);
-
- local_irq_restore(flags);
- return 0;
-}
-
-/*
- * Function : void NCR5380_init (struct Scsi_Host *instance)
- *
- * Purpose : initializes *instance and corresponding 5380 chip.
- *
- * Inputs : instance - instantiation of the 5380 driver.
- *
- * Notes : I assume that the host, hostno, and id bits have been
- * set correctly. I don't care about the irq and other fields.
- *
- */
-
-static int __init NCR5380_init(struct Scsi_Host *instance, int flags)
-{
- int i;
- SETUP_HOSTDATA(instance);
-
- NCR5380_all_init();
-
- hostdata->aborted = 0;
- hostdata->id_mask = 1 << instance->this_id;
- hostdata->id_higher_mask = 0;
- for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
- if (i > hostdata->id_mask)
- hostdata->id_higher_mask |= i;
- for (i = 0; i < 8; ++i)
- hostdata->busy[i] = 0;
-#ifdef SUPPORT_TAGS
- init_tags();
-#endif
-#if defined (REAL_DMA)
- hostdata->dma_len = 0;
-#endif
- hostdata->targets_present = 0;
- hostdata->connected = NULL;
- hostdata->issue_queue = NULL;
- hostdata->disconnected_queue = NULL;
- hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT;
-
- if (!the_template) {
- the_template = instance->hostt;
- first_instance = instance;
- }
-
-
-#ifndef AUTOSENSE
- if ((instance->cmd_per_lun > 1) || (instance->can_queue > 1))
- printk("scsi%d: WARNING : support for multiple outstanding commands enabled\n"
- " without AUTOSENSE option, contingent allegiance conditions may\n"
- " be incorrectly cleared.\n", HOSTNO);
-#endif /* def AUTOSENSE */
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_write(SELECT_ENABLE_REG, 0);
-
- return 0;
-}
-
-static void NCR5380_exit(struct Scsi_Host *instance)
-{
- /* Empty, as we didn't schedule any delayed work */
-}
-
-/*
- * Function : int NCR5380_queue_command (struct scsi_cmnd *cmd,
- * void (*done)(struct scsi_cmnd *))
- *
- * Purpose : enqueues a SCSI command
- *
- * Inputs : cmd - SCSI command, done - function called on completion, with
- * a pointer to the command descriptor.
- *
- * Returns : 0
- *
- * Side effects :
- * cmd is added to the per instance issue_queue, with minor
- * twiddling done to the host specific fields of cmd. If the
- * main coroutine is not running, it is restarted.
- *
- */
-
-/* Only make static if a wrapper function is used */
-static int NCR5380_queue_command_lck(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
-{
- SETUP_HOSTDATA(cmd->device->host);
- struct scsi_cmnd *tmp;
- unsigned long flags;
-
-#if (NDEBUG & NDEBUG_NO_WRITE)
- switch (cmd->cmnd[0]) {
- case WRITE_6:
- case WRITE_10:
- printk(KERN_NOTICE "scsi%d: WRITE attempted with NO_WRITE debugging flag set\n",
- H_NO(cmd));
- cmd->result = (DID_ERROR << 16);
- done(cmd);
- return 0;
- }
-#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
-
-
-#ifdef NCR5380_STATS
-# if 0
- if (!hostdata->connected && !hostdata->issue_queue &&
- !hostdata->disconnected_queue) {
- hostdata->timebase = jiffies;
- }
-# endif
-# ifdef NCR5380_STAT_LIMIT
- if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
-# endif
- switch (cmd->cmnd[0])
- {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);
- hostdata->pendingw++;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] -= (jiffies - hostdata->timebase);
- hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);
- hostdata->pendingr++;
- break;
- }
-#endif
-
- /*
- * We use the host_scribble field as a pointer to the next command
- * in a queue
- */
-
- SET_NEXT(cmd, NULL);
- cmd->scsi_done = done;
-
- cmd->result = 0;
-
-
- /*
- * Insert the cmd into the issue queue. Note that REQUEST SENSE
- * commands are added to the head of the queue since any command will
- * clear the contingent allegiance condition that exists and the
- * sense data is only guaranteed to be valid while the condition exists.
- */
-
- local_irq_save(flags);
- /* ++guenther: now that the issue queue is being set up, we can lock ST-DMA.
- * Otherwise a running NCR5380_main may steal the lock.
- * Lock before actually inserting due to fairness reasons explained in
- * atari_scsi.c. If we insert first, then it's impossible for this driver
- * to release the lock.
- * Stop timer for this command while waiting for the lock, or timeouts
- * may happen (and they really do), and it's no good if the command doesn't
- * appear in any of the queues.
- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
- * because also a timer int can trigger an abort or reset, which would
- * alter queues and touch the lock.
- */
- if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
- LIST(cmd, hostdata->issue_queue);
- SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = cmd;
- } else {
- for (tmp = (struct scsi_cmnd *)hostdata->issue_queue;
- NEXT(tmp); tmp = NEXT(tmp))
- ;
- LIST(cmd, tmp);
- SET_NEXT(tmp, cmd);
- }
-
- local_irq_restore(flags);
-
- dprintk(NDEBUG_QUEUES, "scsi%d: command added to %s of queue\n", H_NO(cmd),
- (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
-
- /* If queue_command() is called from an interrupt (real one or bottom
- * half), we let queue_main() do the job of taking care about main. If it
- * is already running, this is a no-op, else main will be queued.
- *
- * If we're not in an interrupt, we can call NCR5380_main()
- * unconditionally, because it cannot be already running.
- */
- if (in_interrupt() || ((flags >> 8) & 7) >= 6)
- queue_main();
- else
- NCR5380_main(NULL);
- return 0;
-}
-
-static DEF_SCSI_QCMD(NCR5380_queue_command)
-
-/*
- * Function : NCR5380_main (void)
- *
- * Purpose : NCR5380_main is a coroutine that runs as long as more work can
- * be done on the NCR5380 host adapters in a system. Both
- * NCR5380_queue_command() and NCR5380_intr() will try to start it
- * in case it is not running.
- *
- * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
- * reenable them. This prevents reentrancy and kernel stack overflow.
- */
-
-static void NCR5380_main (struct work_struct *bl)
-{
- struct scsi_cmnd *tmp, *prev;
- struct Scsi_Host *instance = first_instance;
- struct NCR5380_hostdata *hostdata = HOSTDATA(instance);
- int done;
- unsigned long flags;
-
- /*
- * We run (with interrupts disabled) until we're sure that none of
- * the host adapters have anything that can be done, at which point
- * we set main_running to 0 and exit.
- *
- * Interrupts are enabled before doing various other internal
- * instructions, after we've decided that we need to run through
- * the loop again.
- *
- * this should prevent any race conditions.
- *
- * ++roman: Just disabling the NCR interrupt isn't sufficient here,
- * because also a timer int can trigger an abort or reset, which can
- * alter queues and touch the Falcon lock.
- */
-
- /* Tell int handlers main() is now already executing. Note that
- no races are possible here. If an int comes in before
- 'main_running' is set here, and queues/executes main via the
- task queue, it doesn't do any harm, just this instance of main
- won't find any work left to do. */
- if (main_running)
- return;
- main_running = 1;
-
- local_save_flags(flags);
- do {
- local_irq_disable(); /* Freeze request queues */
- done = 1;
-
- if (!hostdata->connected) {
- dprintk(NDEBUG_MAIN, "scsi%d: not connected\n", HOSTNO );
- /*
- * Search through the issue_queue for a command destined
- * for a target that's not busy.
- */
-#if (NDEBUG & NDEBUG_LISTS)
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue, prev = NULL;
- tmp && (tmp != prev); prev = tmp, tmp = NEXT(tmp))
- ;
- if ((tmp == prev) && tmp) printk(" LOOP\n");/* else printk("\n");*/
-#endif
- for (tmp = (struct scsi_cmnd *) hostdata->issue_queue,
- prev = NULL; tmp; prev = tmp, tmp = NEXT(tmp) ) {
-
- if (prev != tmp)
- dprintk(NDEBUG_LISTS, "MAIN tmp=%p target=%d busy=%d lun=%llu\n", tmp, tmp->device->id, hostdata->busy[tmp->device->id], tmp->device->lun);
- /* When we find one, remove it from the issue queue. */
- /* ++guenther: possible race with Falcon locking */
- if (
-#ifdef SUPPORT_TAGS
- !is_lun_busy( tmp, tmp->cmnd[0] != REQUEST_SENSE)
-#else
- !(hostdata->busy[tmp->device->id] & (1 << tmp->device->lun))
-#endif
- ) {
- /* ++guenther: just to be sure, this must be atomic */
- local_irq_disable();
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- SET_NEXT(prev, NEXT(tmp));
- } else {
- REMOVE(-1, hostdata->issue_queue, tmp, NEXT(tmp));
- hostdata->issue_queue = NEXT(tmp);
- }
- SET_NEXT(tmp, NULL);
-
- /* reenable interrupts after finding one */
- local_irq_restore(flags);
-
- /*
- * Attempt to establish an I_T_L nexus here.
- * On success, instance->hostdata->connected is set.
- * On failure, we must add the command back to the
- * issue queue so we can keep trying.
- */
- dprintk(NDEBUG_MAIN, "scsi%d: main(): command for target %d "
- "lun %llu removed from issue_queue\n",
- HOSTNO, tmp->device->id, tmp->device->lun);
- /*
- * REQUEST SENSE commands are issued without tagged
- * queueing, even on SCSI-II devices because the
- * contingent allegiance condition exists for the
- * entire unit.
- */
- /* ++roman: ...and the standard also requires that
- * REQUEST SENSE command are untagged.
- */
-
-#ifdef SUPPORT_TAGS
- cmd_get_tag( tmp, tmp->cmnd[0] != REQUEST_SENSE );
-#endif
- if (!NCR5380_select(instance, tmp,
- (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
- TAG_NEXT)) {
- break;
- } else {
- local_irq_disable();
- LIST(tmp, hostdata->issue_queue);
- SET_NEXT(tmp, hostdata->issue_queue);
- hostdata->issue_queue = tmp;
-#ifdef SUPPORT_TAGS
- cmd_free_tag( tmp );
-#endif
- local_irq_restore(flags);
- dprintk(NDEBUG_MAIN, "scsi%d: main(): select() failed, "
- "returned to issue_queue\n", HOSTNO);
- if (hostdata->connected)
- break;
- }
- } /* if target/lun/target queue is not busy */
- } /* for issue_queue */
- } /* if (!hostdata->connected) */
- if (hostdata->connected
-#ifdef REAL_DMA
- && !hostdata->dma_len
-#endif
- ) {
- local_irq_restore(flags);
- dprintk(NDEBUG_MAIN, "scsi%d: main: performing information transfer\n",
- HOSTNO);
- NCR5380_information_transfer(instance);
- dprintk(NDEBUG_MAIN, "scsi%d: main: done set false\n", HOSTNO);
- done = 0;
- }
- } while (!done);
-
- /* Better allow ints _after_ 'main_running' has been cleared, else
- an interrupt could believe we'll pick up the work it left for
- us, but we won't see it anymore here... */
- main_running = 0;
- local_irq_restore(flags);
-}
-
-
-#ifdef REAL_DMA
-/*
- * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
- *
- * Purpose : Called by interrupt handler when DMA finishes or a phase
- * mismatch occurs (which would finish the DMA transfer).
- *
- * Inputs : instance - this instance of the NCR5380.
- *
- */
-
-static void NCR5380_dma_complete( struct Scsi_Host *instance )
-{
- SETUP_HOSTDATA(instance);
- int transfered;
- unsigned char **data;
- volatile int *count;
-
- if (!hostdata->connected) {
- printk(KERN_WARNING "scsi%d: received end of DMA interrupt with "
- "no connected cmd\n", HOSTNO);
- return;
- }
-
- dprintk(NDEBUG_DMA, "scsi%d: real DMA transfer complete, basr 0x%X, sr 0x%X\n",
- HOSTNO, NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
-
- if((sun3scsi_dma_finish(rq_data_dir(hostdata->connected->request)))) {
- printk("scsi%d: overrun in UDC counter -- not prepared to deal with this!\n", HOSTNO);
- printk("please e-mail sammy@sammy.net with a description of how this\n");
- printk("error was produced.\n");
- BUG();
- }
-
- /* make sure we're not stuck in a data phase */
- if((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH |
- BASR_ACK)) ==
- (BASR_PHASE_MATCH | BASR_ACK)) {
- printk("scsi%d: BASR %02x\n", HOSTNO, NCR5380_read(BUS_AND_STATUS_REG));
- printk("scsi%d: bus stuck in data phase -- probably a single byte "
- "overrun!\n", HOSTNO);
- printk("not prepared for this error!\n");
- printk("please e-mail sammy@sammy.net with a description of how this\n");
- printk("error was produced.\n");
- BUG();
- }
-
-
-
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- transfered = hostdata->dma_len - NCR5380_dma_residual(instance);
- hostdata->dma_len = 0;
-
- data = (unsigned char **) &(hostdata->connected->SCp.ptr);
- count = &(hostdata->connected->SCp.this_residual);
- *data += transfered;
- *count -= transfered;
-
-}
-#endif /* REAL_DMA */
-
-
-/*
- * Function : void NCR5380_intr (int irq)
- *
- * Purpose : handle interrupts, reestablishing I_T_L or I_T_L_Q nexuses
- * from the disconnected queue, and restarting NCR5380_main()
- * as required.
- *
- * Inputs : int irq, irq that caused this interrupt.
- *
- */
-
-static irqreturn_t NCR5380_intr (int irq, void *dev_id)
-{
- struct Scsi_Host *instance = first_instance;
- int done = 1, handled = 0;
- unsigned char basr;
-
- dprintk(NDEBUG_INTR, "scsi%d: NCR5380 irq triggered\n", HOSTNO);
-
- /* Look for pending interrupts */
- basr = NCR5380_read(BUS_AND_STATUS_REG);
- dprintk(NDEBUG_INTR, "scsi%d: BASR=%02x\n", HOSTNO, basr);
- /* dispatch to appropriate routine if found and done=0 */
- if (basr & BASR_IRQ) {
- NCR5380_dprint(NDEBUG_INTR, instance);
- if ((NCR5380_read(STATUS_REG) & (SR_SEL|SR_IO)) == (SR_SEL|SR_IO)) {
- done = 0;
-// ENABLE_IRQ();
- dprintk(NDEBUG_INTR, "scsi%d: SEL interrupt\n", HOSTNO);
- NCR5380_reselect(instance);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else if (basr & BASR_PARITY_ERROR) {
- dprintk(NDEBUG_INTR, "scsi%d: PARITY interrupt\n", HOSTNO);
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else if ((NCR5380_read(STATUS_REG) & SR_RST) == SR_RST) {
- dprintk(NDEBUG_INTR, "scsi%d: RESET interrupt\n", HOSTNO);
- (void)NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- }
- else {
- /*
- * The rest of the interrupt conditions can occur only during a
- * DMA transfer
- */
-
-#if defined(REAL_DMA)
- /*
- * We should only get PHASE MISMATCH and EOP interrupts if we have
- * DMA enabled, so do a sanity check based on the current setting
- * of the MODE register.
- */
-
- if ((NCR5380_read(MODE_REG) & MR_DMA_MODE) &&
- ((basr & BASR_END_DMA_TRANSFER) ||
- !(basr & BASR_PHASE_MATCH))) {
-
- dprintk(NDEBUG_INTR, "scsi%d: PHASE MISM or EOP interrupt\n", HOSTNO);
- NCR5380_dma_complete( instance );
- done = 0;
-// ENABLE_IRQ();
- } else
-#endif /* REAL_DMA */
- {
-/* MS: Ignore unknown phase mismatch interrupts (caused by EOP interrupt) */
- if (basr & BASR_PHASE_MATCH)
- dprintk(NDEBUG_INTR, "scsi%d: unknown interrupt, "
- "BASR 0x%x, MR 0x%x, SR 0x%x\n",
- HOSTNO, basr, NCR5380_read(MODE_REG),
- NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
-#endif
- }
- } /* if !(SELECTION || PARITY) */
- handled = 1;
- } /* BASR & IRQ */
- else {
-
- printk(KERN_NOTICE "scsi%d: interrupt without IRQ bit set in BASR, "
- "BASR 0x%X, MR 0x%X, SR 0x%x\n", HOSTNO, basr,
- NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG));
- (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
-#endif
- }
-
- if (!done) {
- dprintk(NDEBUG_INTR, "scsi%d: in int routine, calling main\n", HOSTNO);
- /* Put a call to NCR5380_main() on the queue... */
- queue_main();
- }
- return IRQ_RETVAL(handled);
-}
-
-#ifdef NCR5380_STATS
-static void collect_stats(struct NCR5380_hostdata *hostdata,
- struct scsi_cmnd *cmd)
-{
-# ifdef NCR5380_STAT_LIMIT
- if (scsi_bufflen(cmd) > NCR5380_STAT_LIMIT)
-# endif
- switch (cmd->cmnd[0])
- {
- case WRITE:
- case WRITE_6:
- case WRITE_10:
- hostdata->time_write[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_write[cmd->device->id] += scsi_bufflen(cmd);*/
- hostdata->pendingw--;
- break;
- case READ:
- case READ_6:
- case READ_10:
- hostdata->time_read[cmd->device->id] += (jiffies - hostdata->timebase);
- /*hostdata->bytes_read[cmd->device->id] += scsi_bufflen(cmd);*/
- hostdata->pendingr--;
- break;
- }
-}
-#endif
-
-/*
- * Function : int NCR5380_select(struct Scsi_Host *instance,
- * struct scsi_cmnd *cmd, int tag);
- *
- * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
- * including ARBITRATION, SELECTION, and initial message out for
- * IDENTIFY and queue messages.
- *
- * Inputs : instance - instantiation of the 5380 driver on which this
- * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
- * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
- * the command that is presently connected.
- *
- * Returns : -1 if selection could not execute for some reason,
- * 0 if selection succeeded or failed because the target
- * did not respond.
- *
- * Side effects :
- * If bus busy, arbitration failed, etc, NCR5380_select() will exit
- * with registers as they should have been on entry - ie
- * SELECT_ENABLE will be set appropriately, the NCR5380
- * will cease to drive any SCSI bus signals.
- *
- * If successful : I_T_L or I_T_L_Q nexus will be established,
- * instance->connected will be set to cmd.
- * SELECT interrupt will be disabled.
- *
- * If failed (no target) : cmd->scsi_done() will be called, and the
- * cmd->result host byte set to DID_BAD_TARGET.
- */
-
-static int NCR5380_select(struct Scsi_Host *instance, struct scsi_cmnd *cmd,
- int tag)
-{
- SETUP_HOSTDATA(instance);
- unsigned char tmp[3], phase;
- unsigned char *data;
- int len;
- unsigned long timeout;
- unsigned long flags;
-
- hostdata->restart_select = 0;
- NCR5380_dprint(NDEBUG_ARBITRATION, instance);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: starting arbitration, id = %d\n", HOSTNO,
- instance->this_id);
-
- /*
- * Set the phase bits to 0, otherwise the NCR5380 won't drive the
- * data bus during SELECTION.
- */
-
- local_irq_save(flags);
- if (hostdata->connected) {
- local_irq_restore(flags);
- return -1;
- }
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
-
- /*
- * Start arbitration.
- */
-
- NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
- NCR5380_write(MODE_REG, MR_ARBITRATE);
-
- local_irq_restore(flags);
-
- /* Wait for arbitration logic to complete */
-#ifdef NCR_TIMEOUT
- {
- unsigned long timeout = jiffies + 2*NCR_TIMEOUT;
-
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && time_before(jiffies, timeout) && !hostdata->connected)
- ;
- if (time_after_eq(jiffies, timeout))
- {
- printk("scsi : arbitration timeout at %d\n", __LINE__);
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- }
-#else /* NCR_TIMEOUT */
- while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS)
- && !hostdata->connected);
-#endif
-
- dprintk(NDEBUG_ARBITRATION, "scsi%d: arbitration complete\n", HOSTNO);
-
- if (hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- return -1;
- }
- /*
- * The arbitration delay is 2.2us, but this is a minimum and there is
- * no maximum so we can safely sleep for ceil(2.2) usecs to accommodate
- * the integral nature of udelay().
- *
- */
-
- udelay(3);
-
- /* Check for lost arbitration */
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
- (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting MR_ARBITRATE\n",
- HOSTNO);
- return -1;
- }
-
- /* after/during arbitration, BSY should be asserted.
- IBM DPES-31080 Version S31Q works now */
- /* Tnx to Thomas_Roesch@m2.maus.de for finding this! (Roman) */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL |
- ICR_ASSERT_BSY ) ;
-
- if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
- hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- dprintk(NDEBUG_ARBITRATION, "scsi%d: lost arbitration, deasserting ICR_ASSERT_SEL\n",
- HOSTNO);
- return -1;
- }
-
- /*
- * Again, bus clear + bus settle time is 1.2us, however, this is
- * a minimum so we'll udelay ceil(1.2)
- */
-
-#ifdef CONFIG_ATARI_SCSI_TOSHIBA_DELAY
- /* ++roman: But some targets (see above :-) seem to need a bit more... */
- udelay(15);
-#else
- udelay(2);
-#endif
-
- if (hostdata->connected) {
- NCR5380_write(MODE_REG, MR_BASE);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
-
- dprintk(NDEBUG_ARBITRATION, "scsi%d: won arbitration\n", HOSTNO);
-
- /*
- * Now that we have won arbitration, start Selection process, asserting
- * the host and target ID's on the SCSI bus.
- */
-
- NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->device->id)));
-
- /*
- * Raise ATN while SEL is true before BSY goes false from arbitration,
- * since this is the only way to guarantee that we'll get a MESSAGE OUT
- * phase immediately after selection.
- */
-
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
- NCR5380_write(MODE_REG, MR_BASE);
-
- /*
- * Reselect interrupts must be turned off prior to the dropping of BSY,
- * otherwise we will trigger an interrupt.
- */
-
- if (hostdata->connected) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- return -1;
- }
-
- NCR5380_write(SELECT_ENABLE_REG, 0);
-
- /*
- * The initiator shall then wait at least two deskew delays and release
- * the BSY signal.
- */
- udelay(1); /* wingel -- wait two bus deskew delay >2*45ns */
-
- /* Reset BSY */
- NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
- ICR_ASSERT_ATN | ICR_ASSERT_SEL));
-
- /*
- * Something weird happens when we cease to drive BSY - looks
- * like the board/chip is letting us do another read before the
- * appropriate propagation delay has expired, and we're confusing
- * a BSY signal from ourselves as the target's response to SELECTION.
- *
- * A small delay (the 'C++' frontend breaks the pipeline with an
- * unnecessary jump, making it work on my 386-33/Trantor T128, the
- * tighter 'C' code breaks and requires this) solves the problem -
- * the 1 us delay is arbitrary, and only used because this delay will
- * be the same on other platforms and since it works here, it should
- * work there.
- *
- * wingel suggests that this could be due to failing to wait
- * one deskew delay.
- */
-
- udelay(1);
-
- dprintk(NDEBUG_SELECTION, "scsi%d: selecting target %d\n", HOSTNO, cmd->device->id);
-
- /*
- * The SCSI specification calls for a 250 ms timeout for the actual
- * selection.
- */
-
- timeout = jiffies + 25;
-
- /*
- * XXX very interesting - we're seeing a bounce where the BSY we
- * asserted is being reflected / still asserted (propagation delay?)
- * and it's detecting as true. Sigh.
- */
-
-#if 0
- /* ++roman: If a target conformed to the SCSI standard, it wouldn't assert
- * IO while SEL is true. But again, there are some disks out the in the
- * world that do that nevertheless. (Somebody claimed that this announces
- * reselection capability of the target.) So we better skip that test and
- * only wait for BSY... (Famous german words: Der Klügere gibt nach :-)
- */
-
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) &
- (SR_BSY | SR_IO)));
-
- if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
- (SR_SEL | SR_IO)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- NCR5380_reselect(instance);
- printk (KERN_ERR "scsi%d: reselection after won arbitration?\n",
- HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
-#else
- while (time_before(jiffies, timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
-#endif
-
- /*
- * No less than two deskew delays after the initiator detects the
- * BSY signal is true, it shall release the SEL signal and may
- * change the DATA BUS. -wingel
- */
-
- udelay(1);
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
- if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- if (hostdata->targets_present & (1 << cmd->device->id)) {
- printk(KERN_ERR "scsi%d: weirdness\n", HOSTNO);
- if (hostdata->restart_select)
- printk(KERN_NOTICE "\trestart select\n");
- NCR5380_dprint(NDEBUG_ANY, instance);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return -1;
- }
- cmd->result = DID_BAD_TARGET << 16;
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
-#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
-#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- dprintk(NDEBUG_SELECTION, "scsi%d: target did not respond within 250ms\n", HOSTNO);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return 0;
- }
-
- hostdata->targets_present |= (1 << cmd->device->id);
-
- /*
- * Since we followed the SCSI spec, and raised ATN while SEL
- * was true but before BSY was false during selection, the information
- * transfer phase should be a MESSAGE OUT phase so that we can send the
- * IDENTIFY message.
- *
- * If SCSI-II tagged queuing is enabled, we also send a SIMPLE_QUEUE_TAG
- * message (2 bytes) with a tag ID that we increment with every command
- * until it wraps back to 0.
- *
- * XXX - it turns out that there are some broken SCSI-II devices,
- * which claim to support tagged queuing but fail when more than
- * some number of commands are issued at once.
- */
-
- /* Wait for start of REQ/ACK handshake */
- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
- dprintk(NDEBUG_SELECTION, "scsi%d: target %d selected, going into MESSAGE OUT phase.\n",
- HOSTNO, cmd->device->id);
- tmp[0] = IDENTIFY(1, cmd->device->lun);
-
-#ifdef SUPPORT_TAGS
- if (cmd->tag != TAG_NONE) {
- tmp[1] = hostdata->last_message = SIMPLE_QUEUE_TAG;
- tmp[2] = cmd->tag;
- len = 3;
- } else
- len = 1;
-#else
- len = 1;
- cmd->tag=0;
-#endif /* SUPPORT_TAGS */
-
- /* Send message(s) */
- data = tmp;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_SELECTION, "scsi%d: nexus established.\n", HOSTNO);
- /* XXX need to handle errors here */
- hostdata->connected = cmd;
-#ifndef SUPPORT_TAGS
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
-#endif
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_INTR;
-#endif
- initialize_SCp(cmd);
-
-
- return 0;
-}
-
-/*
- * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
- *
- * Purpose : transfers data in given phase using polled I/O
- *
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
- *
- * Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes are transferred or exit
- * is in same phase.
- *
- * Also, *phase, *count, *data are modified in place.
- *
- * XXX Note : handling for bus free may be useful.
- */
-
-/*
- * Note : this code is not as quick as it could be, however it
- * IS 100% reliable, and for the actual data transfer where speed
- * counts, we will always do a pseudo DMA or DMA transfer.
- */
-
-static int NCR5380_transfer_pio( struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
-{
- register unsigned char p = *phase, tmp;
- register int c = *count;
- register unsigned char *d = *data;
-
- /*
- * The NCR5380 chip will only drive the SCSI bus when the
- * phase specified in the appropriate bits of the TARGET COMMAND
- * REGISTER match the STATUS REGISTER
- */
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
-
- do {
- /*
- * Wait for assertion of REQ, after which the phase bits will be
- * valid
- */
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
-
- dprintk(NDEBUG_HANDSHAKE, "scsi%d: REQ detected\n", HOSTNO);
-
- /* Check for phase mismatch */
- if ((tmp & PHASE_MASK) != p) {
- dprintk(NDEBUG_PIO, "scsi%d: phase mismatch\n", HOSTNO);
- NCR5380_dprint_phase(NDEBUG_PIO, instance);
- break;
- }
-
- /* Do actual transfer from SCSI bus to / from memory */
- if (!(p & SR_IO))
- NCR5380_write(OUTPUT_DATA_REG, *d);
- else
- *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
-
- ++d;
-
- /*
- * The SCSI standard suggests that in MSGOUT phase, the initiator
- * should drop ATN on the last byte of the message phase
- * after REQ has been asserted for the handshake but before
- * the initiator raises ACK.
- */
-
- if (!(p & SR_IO)) {
- if (!((p & SR_MSG) && c > 1)) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA);
- NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ACK);
- } else {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN);
- NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
- }
- } else {
- NCR5380_dprint(NDEBUG_PIO, instance);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
- }
-
- while (NCR5380_read(STATUS_REG) & SR_REQ);
-
- dprintk(NDEBUG_HANDSHAKE, "scsi%d: req false, handshake complete\n", HOSTNO);
-
-/*
- * We have several special cases to consider during REQ/ACK handshaking :
- * 1. We were in MSGOUT phase, and we are on the last byte of the
- * message. ATN must be dropped as ACK is dropped.
- *
- * 2. We are in a MSGIN phase, and we are on the last byte of the
- * message. We must exit with ACK asserted, so that the calling
- * code may raise ATN before dropping ACK to reject the message.
- *
- * 3. ACK and ATN are clear and the target may proceed as normal.
- */
- if (!(p == PHASE_MSGIN && c == 1)) {
- if (p == PHASE_MSGOUT && c > 1)
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- else
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- }
- } while (--c);
-
- dprintk(NDEBUG_PIO, "scsi%d: residual %d\n", HOSTNO, c);
-
- *count = c;
- *data = d;
- tmp = NCR5380_read(STATUS_REG);
- /* The phase read from the bus is valid if either REQ is (already)
- * asserted or if ACK hasn't been released yet. The latter is the case if
- * we're in MSGIN and all wanted bytes have been received. */
- if ((tmp & SR_REQ) || (p == PHASE_MSGIN && c == 0))
- *phase = tmp & PHASE_MASK;
- else
- *phase = PHASE_UNKNOWN;
-
- if (!c || (*phase == p))
- return 0;
- else
- return -1;
-}
-
-/*
- * Function : do_abort (Scsi_Host *host)
- *
- * Purpose : abort the currently established nexus. Should only be
- * called from a routine which can drop into a
- *
- * Returns : 0 on success, -1 on failure.
- */
-
-static int do_abort (struct Scsi_Host *host)
-{
- unsigned char tmp, *msgptr, phase;
- int len;
-
- /* Request message out phase */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
-
- /*
- * Wait for the target to indicate a valid phase by asserting
- * REQ. Once this happens, we'll have either a MSGOUT phase
- * and can immediately send the ABORT message, or we'll have some
- * other phase and will have to source/sink data.
- *
- * We really don't care what value was on the bus or what value
- * the target sees, so we just handshake.
- */
-
- while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
-
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
- if ((tmp & PHASE_MASK) != PHASE_MSGOUT) {
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
- }
-
- tmp = ABORT;
- msgptr = &tmp;
- len = 1;
- phase = PHASE_MSGOUT;
- NCR5380_transfer_pio (host, &phase, &len, &msgptr);
-
- /*
- * If we got here, and the command completed successfully,
- * we're about to go into bus free state.
- */
-
- return len ? -1 : 0;
-}
-
-#if defined(REAL_DMA)
-/*
- * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
- * unsigned char *phase, int *count, unsigned char **data)
- *
- * Purpose : transfers data in given phase using either real
- * or pseudo DMA.
- *
- * Inputs : instance - instance of driver, *phase - pointer to
- * what phase is expected, *count - pointer to number of
- * bytes to transfer, **data - pointer to data pointer.
- *
- * Returns : -1 when different phase is entered without transferring
- * maximum number of bytes, 0 if all bytes or transferred or exit
- * is in same phase.
- *
- * Also, *phase, *count, *data are modified in place.
- *
- */
-
-
-static int NCR5380_transfer_dma( struct Scsi_Host *instance,
- unsigned char *phase, int *count,
- unsigned char **data)
-{
- SETUP_HOSTDATA(instance);
- register int c = *count;
- register unsigned char p = *phase;
- unsigned long flags;
-
- /* sanity check */
- if(!sun3_dma_setup_done) {
- printk("scsi%d: transfer_dma without setup!\n", HOSTNO);
- BUG();
- }
- hostdata->dma_len = c;
-
- dprintk(NDEBUG_DMA, "scsi%d: initializing DMA for %s, %d bytes %s %p\n",
- HOSTNO, (p & SR_IO) ? "reading" : "writing",
- c, (p & SR_IO) ? "to" : "from", *data);
-
- /* netbsd turns off ints here, why not be safe and do it too */
- local_irq_save(flags);
-
- /* send start chain */
- sun3scsi_dma_start(c, *data);
-
- if (p & SR_IO) {
- NCR5380_write(TARGET_COMMAND_REG, 1);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(INITIATOR_COMMAND_REG, 0);
- NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
- NCR5380_write(START_DMA_INITIATOR_RECEIVE_REG, 0);
- } else {
- NCR5380_write(TARGET_COMMAND_REG, 0);
- NCR5380_read(RESET_PARITY_INTERRUPT_REG);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_DATA);
- NCR5380_write(MODE_REG, (NCR5380_read(MODE_REG) | MR_DMA_MODE | MR_ENABLE_EOP_INTR));
- NCR5380_write(START_DMA_SEND_REG, 0);
- }
-
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
-#endif
-
- local_irq_restore(flags);
-
- sun3_dma_active = 1;
- return 0;
-}
-#endif /* defined(REAL_DMA) */
-
-/*
- * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
- *
- * Purpose : run through the various SCSI phases and do as the target
- * directs us to. Operates on the currently connected command,
- * instance->connected.
- *
- * Inputs : instance, instance for which we are doing commands
- *
- * Side effects : SCSI things happen, the disconnected queue will be
- * modified if a command disconnects, *instance->connected will
- * change.
- *
- * XXX Note : we need to watch for bus free or a reset condition here
- * to recover from an unexpected bus free condition.
- */
-
-static void NCR5380_information_transfer (struct Scsi_Host *instance)
-{
- SETUP_HOSTDATA(instance);
- unsigned long flags;
- unsigned char msgout = NOP;
- int sink = 0;
- int len;
-#if defined(REAL_DMA)
- int transfersize;
-#endif
- unsigned char *data;
- unsigned char phase, tmp, extended_msg[10], old_phase=0xff;
- struct scsi_cmnd *cmd = (struct scsi_cmnd *) hostdata->connected;
-
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_INTR;
-#endif
-
- while (1) {
- tmp = NCR5380_read(STATUS_REG);
- /* We only have a valid SCSI phase when REQ is asserted */
- if (tmp & SR_REQ) {
- phase = (tmp & PHASE_MASK);
- if (phase != old_phase) {
- old_phase = phase;
- NCR5380_dprint_phase(NDEBUG_INFORMATION, instance);
- }
-
- if(phase == PHASE_CMDOUT) {
- void *d;
- unsigned long count;
-
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- count = cmd->SCp.buffer->length;
- d = SGADDR(cmd->SCp.buffer);
- } else {
- count = cmd->SCp.this_residual;
- d = cmd->SCp.ptr;
- }
-#ifdef REAL_DMA
- /* this command setup for dma yet? */
- if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done
- != cmd))
- {
- if (cmd->request->cmd_type == REQ_TYPE_FS) {
- sun3scsi_dma_setup(d, count,
- rq_data_dir(cmd->request));
- sun3_dma_setup_done = cmd;
- }
- }
-#endif
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_INTR;
-#endif
- }
-
-
- if (sink && (phase != PHASE_MSGOUT)) {
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(tmp));
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN |
- ICR_ASSERT_ACK);
- while (NCR5380_read(STATUS_REG) & SR_REQ);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 0;
- continue;
- }
-
- switch (phase) {
- case PHASE_DATAOUT:
-#if (NDEBUG & NDEBUG_NO_DATAOUT)
- printk("scsi%d: NDEBUG_NO_DATAOUT set, attempted DATAOUT "
- "aborted\n", HOSTNO);
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
- return;
-#endif
- case PHASE_DATAIN:
- /*
- * If there is no room left in the current buffer in the
- * scatter-gather list, move onto the next one.
- */
- if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
- ++cmd->SCp.buffer;
- --cmd->SCp.buffers_residual;
- cmd->SCp.this_residual = cmd->SCp.buffer->length;
- cmd->SCp.ptr = SGADDR(cmd->SCp.buffer);
- dprintk(NDEBUG_INFORMATION, "scsi%d: %d bytes and %d buffers left\n",
- HOSTNO, cmd->SCp.this_residual,
- cmd->SCp.buffers_residual);
- }
-
- /*
- * The preferred transfer method is going to be
- * PSEUDO-DMA for systems that are strictly PIO,
- * since we can let the hardware do the handshaking.
- *
- * For this to work, we need to know the transfersize
- * ahead of time, since the pseudo-DMA code will sit
- * in an unconditional loop.
- */
-
-/* ++roman: I suggest, this should be
- * #if def(REAL_DMA)
- * instead of leaving REAL_DMA out.
- */
-
-#if defined(REAL_DMA)
-// if (!cmd->device->borken &&
- if((transfersize =
- NCR5380_dma_xfer_len(instance,cmd,phase)) > SUN3_DMA_MINSIZE) {
- len = transfersize;
- cmd->SCp.phase = phase;
-
- if (NCR5380_transfer_dma(instance, &phase,
- &len, (unsigned char **) &cmd->SCp.ptr)) {
- /*
- * If the watchdog timer fires, all future
- * accesses to this device will use the
- * polled-IO. */
- printk(KERN_NOTICE "scsi%d: switching target %d "
- "lun %llu to slow handshake\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
- cmd->device->borken = 1;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- sink = 1;
- do_abort(instance);
- cmd->result = DID_ERROR << 16;
- cmd->scsi_done(cmd);
- /* XXX - need to source or sink data here, as appropriate */
- } else {
-#ifdef REAL_DMA
- /* ++roman: When using real DMA,
- * information_transfer() should return after
- * starting DMA since it has nothing more to
- * do.
- */
- return;
-#else
- cmd->SCp.this_residual -= transfersize - len;
-#endif
- }
- } else
-#endif /* defined(REAL_DMA) */
- NCR5380_transfer_pio(instance, &phase,
- (int *) &cmd->SCp.this_residual, (unsigned char **)
- &cmd->SCp.ptr);
-#ifdef REAL_DMA
- /* if we had intended to dma that command clear it */
- if(sun3_dma_setup_done == cmd)
- sun3_dma_setup_done = NULL;
-#endif
-
- break;
- case PHASE_MSGIN:
- len = 1;
- data = &tmp;
- NCR5380_write(SELECT_ENABLE_REG, 0); /* disable reselects */
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- cmd->SCp.Message = tmp;
-
- switch (tmp) {
- /*
- * Linking lets us reduce the time required to get the
- * next command out to the device, hopefully this will
- * mean we don't waste another revolution due to the delays
- * required by ARBITRATION and another SELECTION.
- *
- * In the current implementation proposal, low level drivers
- * merely have to start the next command, pointed to by
- * next_link, done() is called as with unlinked commands.
- */
-#ifdef LINKED
- case LINKED_CMD_COMPLETE:
- case LINKED_FLG_CMD_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked command "
- "complete.\n", HOSTNO, cmd->device->id, cmd->device->lun);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Sanity check : A linked command should only terminate
- * with one of these messages if there are more linked
- * commands available.
- */
-
- if (!cmd->next_link) {
- printk(KERN_NOTICE "scsi%d: target %d lun %llu "
- "linked command complete, no next_link\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- sink = 1;
- do_abort (instance);
- return;
- }
-
- initialize_SCp(cmd->next_link);
- /* The next command is still part of this process; copy it
- * and don't free it! */
- cmd->next_link->tag = cmd->tag;
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- dprintk(NDEBUG_LINKED, "scsi%d: target %d lun %llu linked request "
- "done, calling scsi_done().\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
- cmd->scsi_done(cmd);
- cmd = hostdata->connected;
- break;
-#endif /* def LINKED */
- case ABORT:
- case COMMAND_COMPLETE:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- hostdata->connected = NULL;
- dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d, lun %llu "
- "completed\n", HOSTNO, cmd->device->id, cmd->device->lun);
-#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
- if (status_byte(cmd->SCp.Status) == QUEUE_FULL) {
- /* Turn a QUEUE FULL status into BUSY, I think the
- * mid level cannot handle QUEUE FULL :-( (The
- * command is retried after BUSY). Also update our
- * queue size to the number of currently issued
- * commands now.
- */
- /* ++Andreas: the mid level code knows about
- QUEUE_FULL now. */
- TAG_ALLOC *ta = &TagAlloc[cmd->device->id][cmd->device->lun];
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu returned "
- "QUEUE_FULL after %d commands\n",
- HOSTNO, cmd->device->id, cmd->device->lun,
- ta->nr_allocated);
- if (ta->queue_size > ta->nr_allocated)
- ta->nr_allocated = ta->queue_size;
- }
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
-
- /*
- * I'm not sure what the correct thing to do here is :
- *
- * If the command that just executed is NOT a request
- * sense, the obvious thing to do is to set the result
- * code to the values of the stored parameters.
- *
- * If it was a REQUEST SENSE command, we need some way to
- * differentiate between the failure code of the original
- * and the failure code of the REQUEST sense - the obvious
- * case is success, where we fall through and leave the
- * result code unchanged.
- *
- * The non-obvious place is where the REQUEST SENSE failed
- */
-
- if (cmd->cmnd[0] != REQUEST_SENSE)
- cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
- else if (status_byte(cmd->SCp.Status) != GOOD)
- cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
-
-#ifdef AUTOSENSE
- if ((cmd->cmnd[0] == REQUEST_SENSE) &&
- hostdata->ses.cmd_len) {
- scsi_eh_restore_cmnd(cmd, &hostdata->ses);
- hostdata->ses.cmd_len = 0 ;
- }
-
- if ((cmd->cmnd[0] != REQUEST_SENSE) &&
- (status_byte(cmd->SCp.Status) == CHECK_CONDITION)) {
- scsi_eh_prep_cmnd(cmd, &hostdata->ses, NULL, 0, ~0);
- dprintk(NDEBUG_AUTOSENSE, "scsi%d: performing request sense\n",
- HOSTNO);
- /* this is initialized from initialize_SCp
- cmd->SCp.buffer = NULL;
- cmd->SCp.buffers_residual = 0;
- */
-
- local_irq_save(flags);
- LIST(cmd,hostdata->issue_queue);
- SET_NEXT(cmd, hostdata->issue_queue);
- hostdata->issue_queue = (struct scsi_cmnd *) cmd;
- local_irq_restore(flags);
- dprintk(NDEBUG_QUEUES, "scsi%d: REQUEST SENSE added to head of "
- "issue queue\n", H_NO(cmd));
- } else
-#endif /* def AUTOSENSE */
- {
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
- cmd->scsi_done(cmd);
- }
-
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
-
- return;
- case MESSAGE_REJECT:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- switch (hostdata->last_message) {
- case HEAD_OF_QUEUE_TAG:
- case ORDERED_QUEUE_TAG:
- case SIMPLE_QUEUE_TAG:
- /* The target obviously doesn't support tagged
- * queuing, even though it announced this ability in
- * its INQUIRY data ?!? (maybe only this LUN?) Ok,
- * clear 'tagged_supported' and lock the LUN, since
- * the command is treated as untagged further on.
- */
- cmd->device->tagged_supported = 0;
- hostdata->busy[cmd->device->id] |= (1 << cmd->device->lun);
- cmd->tag = TAG_NONE;
- dprintk(NDEBUG_TAGS, "scsi%d: target %d lun %llu rejected "
- "QUEUE_TAG message; tagged queuing "
- "disabled\n",
- HOSTNO, cmd->device->id, cmd->device->lun);
- break;
- }
- break;
- case DISCONNECT:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- local_irq_save(flags);
- cmd->device->disconnect = 1;
- LIST(cmd,hostdata->disconnected_queue);
- SET_NEXT(cmd, hostdata->disconnected_queue);
- hostdata->connected = NULL;
- hostdata->disconnected_queue = cmd;
- local_irq_restore(flags);
- dprintk(NDEBUG_QUEUES, "scsi%d: command for target %d lun %llu was "
- "moved from connected to the "
- "disconnected_queue\n", HOSTNO,
- cmd->device->id, cmd->device->lun);
- /*
- * Restore phase bits to 0 so an interrupted selection,
- * arbitration can resume.
- */
- NCR5380_write(TARGET_COMMAND_REG, 0);
-
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- /* Wait for bus free to avoid nasty timeouts */
- while ((NCR5380_read(STATUS_REG) & SR_BSY) && !hostdata->connected)
- barrier();
-#ifdef SUN3_SCSI_VME
- dregs->csr |= CSR_DMA_ENABLE;
-#endif
- return;
- /*
- * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
- * operation, in violation of the SCSI spec so we can safely
- * ignore SAVE/RESTORE pointers calls.
- *
- * Unfortunately, some disks violate the SCSI spec and
- * don't issue the required SAVE_POINTERS message before
- * disconnecting, and we have to break spec to remain
- * compatible.
- */
- case SAVE_POINTERS:
- case RESTORE_POINTERS:
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- /* Enable reselect interrupts */
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- break;
- case EXTENDED_MESSAGE:
-/*
- * Extended messages are sent in the following format :
- * Byte
- * 0 EXTENDED_MESSAGE == 1
- * 1 length (includes one byte for code, doesn't
- * include first two bytes)
- * 2 code
- * 3..length+1 arguments
- *
- * Start the extended message buffer with the EXTENDED_MESSAGE
- * byte, since spi_print_msg() wants the whole thing.
- */
- extended_msg[0] = EXTENDED_MESSAGE;
- /* Accept first byte by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- dprintk(NDEBUG_EXTENDED, "scsi%d: receiving extended message\n", HOSTNO);
-
- len = 2;
- data = extended_msg + 1;
- phase = PHASE_MSGIN;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d: length=%d, code=0x%02x\n", HOSTNO,
- (int)extended_msg[1], (int)extended_msg[2]);
-
- if (!len && extended_msg[1] <=
- (sizeof (extended_msg) - 1)) {
- /* Accept third byte by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
- len = extended_msg[1] - 1;
- data = extended_msg + 3;
- phase = PHASE_MSGIN;
-
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- dprintk(NDEBUG_EXTENDED, "scsi%d: message received, residual %d\n",
- HOSTNO, len);
-
- switch (extended_msg[2]) {
- case EXTENDED_SDTR:
- case EXTENDED_WDTR:
- case EXTENDED_MODIFY_DATA_POINTER:
- case EXTENDED_EXTENDED_IDENTIFY:
- tmp = 0;
- }
- } else if (len) {
- printk(KERN_NOTICE "scsi%d: error receiving "
- "extended message\n", HOSTNO);
- tmp = 0;
- } else {
- printk(KERN_NOTICE "scsi%d: extended message "
- "code %02x length %d is too long\n",
- HOSTNO, extended_msg[2], extended_msg[1]);
- tmp = 0;
- }
- /* Fall through to reject message */
-
- /*
- * If we get something weird that we aren't expecting,
- * reject it.
- */
- default:
- if (!tmp) {
- printk(KERN_DEBUG "scsi%d: rejecting message ", HOSTNO);
- spi_print_msg(extended_msg);
- printk("\n");
- } else if (tmp != EXTENDED_MESSAGE)
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "message %02x from target %d, lun %llu\n",
- HOSTNO, tmp, cmd->device->id, cmd->device->lun);
- else
- printk(KERN_DEBUG "scsi%d: rejecting unknown "
- "extended message "
- "code %02x, length %d from target %d, lun %llu\n",
- HOSTNO, extended_msg[1], extended_msg[0],
- cmd->device->id, cmd->device->lun);
-
-
- msgout = MESSAGE_REJECT;
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
- ICR_ASSERT_ATN);
- break;
- } /* switch (tmp) */
- break;
- case PHASE_MSGOUT:
- len = 1;
- data = &msgout;
- hostdata->last_message = msgout;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- if (msgout == ABORT) {
-#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- hostdata->connected = NULL;
- cmd->result = DID_ERROR << 16;
-#ifdef NCR5380_STATS
- collect_stats(hostdata, cmd);
-#endif
- cmd->scsi_done(cmd);
- NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
- return;
- }
- msgout = NOP;
- break;
- case PHASE_CMDOUT:
- len = cmd->cmd_len;
- data = cmd->cmnd;
- /*
- * XXX for performance reasons, on machines with a
- * PSEUDO-DMA architecture we should probably
- * use the dma transfer function.
- */
- NCR5380_transfer_pio(instance, &phase, &len,
- &data);
- break;
- case PHASE_STATIN:
- len = 1;
- data = &tmp;
- NCR5380_transfer_pio(instance, &phase, &len, &data);
- cmd->SCp.Status = tmp;
- break;
- default:
- printk("scsi%d: unknown phase\n", HOSTNO);
- NCR5380_dprint(NDEBUG_ANY, instance);
- } /* switch(phase) */
- } /* if (tmp * SR_REQ) */
- } /* while (1) */
-}
-
-/*
- * Function : void NCR5380_reselect (struct Scsi_Host *instance)
- *
- * Purpose : does reselection, initializing the instance->connected
- * field to point to the struct scsi_cmnd for which the I_T_L or I_T_L_Q
- * nexus has been reestablished,
- *
- * Inputs : instance - this instance of the NCR5380.
- *
- */
-
-/* it might eventually prove necessary to do a dma setup on
- reselection, but it doesn't seem to be needed now -- sam */
-
-static void NCR5380_reselect (struct Scsi_Host *instance)
-{
- SETUP_HOSTDATA(instance);
- unsigned char target_mask;
- unsigned char lun;
-#ifdef SUPPORT_TAGS
- unsigned char tag;
-#endif
- unsigned char msg[3];
- struct scsi_cmnd *tmp = NULL, *prev;
-/* unsigned long flags; */
-
- /*
- * Disable arbitration, etc. since the host adapter obviously
- * lost, and tell an interrupted NCR5380_select() to restart.
- */
-
- NCR5380_write(MODE_REG, MR_BASE);
- hostdata->restart_select = 1;
-
- target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
-
- dprintk(NDEBUG_RESELECTION, "scsi%d: reselect\n", HOSTNO);
-
- /*
- * At this point, we have detected that our SCSI ID is on the bus,
- * SEL is true and BSY was false for at least one bus settle delay
- * (400 ns).
- *
- * We must assert BSY ourselves, until the target drops the SEL
- * signal.
- */
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
-
- while (NCR5380_read(STATUS_REG) & SR_SEL);
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
- /*
- * Wait for target to go into MSGIN.
- */
-
- while (!(NCR5380_read(STATUS_REG) & SR_REQ));
-
-#if 1
- // acknowledge toggle to MSGIN
- NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(PHASE_MSGIN));
-
- // peek at the byte without really hitting the bus
- msg[0] = NCR5380_read(CURRENT_SCSI_DATA_REG);
-#endif
-
- if (!(msg[0] & 0x80)) {
- printk(KERN_DEBUG "scsi%d: expecting IDENTIFY message, got ", HOSTNO);
- spi_print_msg(msg);
- do_abort(instance);
- return;
- }
- lun = (msg[0] & 0x07);
-
- /*
- * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
- * just reestablished, and remove it from the disconnected queue.
- */
-
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue, prev = NULL;
- tmp; prev = tmp, tmp = NEXT(tmp) ) {
- if ((target_mask == (1 << tmp->device->id)) && (lun == tmp->device->lun)
-#ifdef SUPPORT_TAGS
- && (tag == tmp->tag)
-#endif
- ) {
- if (prev) {
- REMOVE(prev, NEXT(prev), tmp, NEXT(tmp));
- SET_NEXT(prev, NEXT(tmp));
- } else {
- REMOVE(-1, hostdata->disconnected_queue, tmp, NEXT(tmp));
- hostdata->disconnected_queue = NEXT(tmp);
- }
- SET_NEXT(tmp, NULL);
- break;
- }
- }
-
- if (!tmp) {
- printk(KERN_WARNING "scsi%d: warning: target bitmask %02x lun %d "
-#ifdef SUPPORT_TAGS
- "tag %d "
-#endif
- "not in disconnected_queue.\n",
- HOSTNO, target_mask, lun
-#ifdef SUPPORT_TAGS
- , tag
-#endif
- );
- /*
- * Since we have an established nexus that we can't do anything
- * with, we must abort it.
- */
- do_abort(instance);
- return;
- }
-#if 1
- /* engage dma setup for the command we just saw */
- {
- void *d;
- unsigned long count;
-
- if (!tmp->SCp.this_residual && tmp->SCp.buffers_residual) {
- count = tmp->SCp.buffer->length;
- d = SGADDR(tmp->SCp.buffer);
- } else {
- count = tmp->SCp.this_residual;
- d = tmp->SCp.ptr;
- }
-#ifdef REAL_DMA
- /* setup this command for dma if not already */
- if((count > SUN3_DMA_MINSIZE) && (sun3_dma_setup_done != tmp))
- {
- sun3scsi_dma_setup(d, count, rq_data_dir(tmp->request));
- sun3_dma_setup_done = tmp;
- }
-#endif
- }
-#endif
-
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
- /* Accept message by clearing ACK */
- NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
-
-#ifdef SUPPORT_TAGS
- /* If the phase is still MSGIN, the target wants to send some more
- * messages. In case it supports tagged queuing, this is probably a
- * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus.
- */
- tag = TAG_NONE;
- if (phase == PHASE_MSGIN && setup_use_tagged_queuing) {
- /* Accept previous IDENTIFY message by clearing ACK */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- len = 2;
- data = msg+1;
- if (!NCR5380_transfer_pio(instance, &phase, &len, &data) &&
- msg[1] == SIMPLE_QUEUE_TAG)
- tag = msg[2];
- dprintk(NDEBUG_TAGS, "scsi%d: target mask %02x, lun %d sent tag %d at "
- "reselection\n", HOSTNO, target_mask, lun, tag);
- }
-#endif
-
- hostdata->connected = tmp;
- dprintk(NDEBUG_RESELECTION, "scsi%d: nexus established, target = %d, lun = %llu, tag = %d\n",
- HOSTNO, tmp->device->id, tmp->device->lun, tmp->tag);
-}
-
-
-/*
- * Function : int NCR5380_abort(struct scsi_cmnd *cmd)
- *
- * Purpose : abort a command
- *
- * Inputs : cmd - the struct scsi_cmnd to abort, code - code to set the
- * host byte of the result field to, if zero DID_ABORTED is
- * used.
- *
- * Returns : 0 - success, -1 on failure.
- *
- * XXX - there is no way to abort the command that is currently
- * connected, you have to wait for it to complete. If this is
- * a problem, we could implement longjmp() / setjmp(), setjmp()
- * called where the loop started in NCR5380_main().
- */
-
-static int NCR5380_abort(struct scsi_cmnd *cmd)
-{
- struct Scsi_Host *instance = cmd->device->host;
- SETUP_HOSTDATA(instance);
- struct scsi_cmnd *tmp, **prev;
- unsigned long flags;
-
- printk(KERN_NOTICE "scsi%d: aborting command\n", HOSTNO);
- scsi_print_command(cmd);
-
- NCR5380_print_status (instance);
-
- local_irq_save(flags);
-
- dprintk(NDEBUG_ABORT, "scsi%d: abort called basr 0x%02x, sr 0x%02x\n", HOSTNO,
- NCR5380_read(BUS_AND_STATUS_REG),
- NCR5380_read(STATUS_REG));
-
-#if 1
-/*
- * Case 1 : If the command is the currently executing command,
- * we'll set the aborted flag and return control so that
- * information transfer routine can exit cleanly.
- */
-
- if (hostdata->connected == cmd) {
-
- dprintk(NDEBUG_ABORT, "scsi%d: aborting connected command\n", HOSTNO);
-/*
- * We should perform BSY checking, and make sure we haven't slipped
- * into BUS FREE.
- */
-
-/* NCR5380_write(INITIATOR_COMMAND_REG, ICR_ASSERT_ATN); */
-/*
- * Since we can't change phases until we've completed the current
- * handshake, we have to source or sink a byte of data if the current
- * phase is not MSGOUT.
- */
-
-/*
- * Return control to the executing NCR drive so we can clear the
- * aborted flag and get back into our main loop.
- */
-
- if (do_abort(instance) == 0) {
- hostdata->aborted = 1;
- hostdata->connected = NULL;
- cmd->result = DID_ABORT << 16;
-#ifdef SUPPORT_TAGS
- cmd_free_tag( cmd );
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- local_irq_restore(flags);
- cmd->scsi_done(cmd);
- return SUCCESS;
- } else {
-/* local_irq_restore(flags); */
- printk("scsi%d: abort of connected command failed!\n", HOSTNO);
- return FAILED;
- }
- }
-#endif
-
-/*
- * Case 2 : If the command hasn't been issued yet, we simply remove it
- * from the issue queue.
- */
- for (prev = (struct scsi_cmnd **) &(hostdata->issue_queue),
- tmp = (struct scsi_cmnd *) hostdata->issue_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp))
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- (*prev) = NEXT(tmp);
- SET_NEXT(tmp, NULL);
- tmp->result = DID_ABORT << 16;
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: abort removed command from issue queue.\n",
- HOSTNO);
- /* Tagged queuing note: no tag to free here, hasn't been assigned
- * yet... */
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
-
-/*
- * Case 3 : If any commands are connected, we're going to fail the abort
- * and let the high level SCSI driver retry at a later time or
- * issue a reset.
- *
- * Timeouts, and therefore aborted commands, will be highly unlikely
- * and handling them cleanly in this situation would make the common
- * case of noresets less efficient, and would pollute our code. So,
- * we fail.
- */
-
- if (hostdata->connected) {
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: abort failed, command connected.\n", HOSTNO);
- return FAILED;
- }
-
-/*
- * Case 4: If the command is currently disconnected from the bus, and
- * there are no connected commands, we reconnect the I_T_L or
- * I_T_L_Q nexus associated with it, go into message out, and send
- * an abort message.
- *
- * This case is especially ugly. In order to reestablish the nexus, we
- * need to call NCR5380_select(). The easiest way to implement this
- * function was to abort if the bus was busy, and let the interrupt
- * handler triggered on the SEL for reselect take care of lost arbitrations
- * where necessary, meaning interrupts need to be enabled.
- *
- * When interrupts are enabled, the queues may change - so we
- * can't remove it from the disconnected queue before selecting it
- * because that could cause a failure in hashing the nexus if that
- * device reselected.
- *
- * Since the queues may change, we can't use the pointers from when we
- * first locate it.
- *
- * So, we must first locate the command, and if NCR5380_select()
- * succeeds, then issue the abort, relocate the command and remove
- * it from the disconnected queue.
- */
-
- for (tmp = (struct scsi_cmnd *) hostdata->disconnected_queue; tmp;
- tmp = NEXT(tmp))
- if (cmd == tmp) {
- local_irq_restore(flags);
- dprintk(NDEBUG_ABORT, "scsi%d: aborting disconnected command.\n", HOSTNO);
-
- if (NCR5380_select (instance, cmd, (int) cmd->tag))
- return FAILED;
-
- dprintk(NDEBUG_ABORT, "scsi%d: nexus reestablished.\n", HOSTNO);
-
- do_abort (instance);
-
- local_irq_save(flags);
- for (prev = (struct scsi_cmnd **) &(hostdata->disconnected_queue),
- tmp = (struct scsi_cmnd *) hostdata->disconnected_queue;
- tmp; prev = NEXTADDR(tmp), tmp = NEXT(tmp) )
- if (cmd == tmp) {
- REMOVE(5, *prev, tmp, NEXT(tmp));
- *prev = NEXT(tmp);
- SET_NEXT(tmp, NULL);
- tmp->result = DID_ABORT << 16;
- /* We must unlock the tag/LUN immediately here, since the
- * target goes to BUS FREE and doesn't send us another
- * message (COMMAND_COMPLETE or the like)
- */
-#ifdef SUPPORT_TAGS
- cmd_free_tag( tmp );
-#else
- hostdata->busy[cmd->device->id] &= ~(1 << cmd->device->lun);
-#endif
- local_irq_restore(flags);
- tmp->scsi_done(tmp);
- return SUCCESS;
- }
- }
-
-/*
- * Case 5 : If we reached this point, the command was not found in any of
- * the queues.
- *
- * We probably reached this point because of an unlikely race condition
- * between the command completing successfully and the abortion code,
- * so we won't panic, but we will notify the user in case something really
- * broke.
- */
-
- local_irq_restore(flags);
- printk(KERN_INFO "scsi%d: warning : SCSI command probably completed successfully before abortion\n", HOSTNO);
-
- return FAILED;
-}
-
-
-/*
- * Function : int NCR5380_bus_reset(struct scsi_cmnd *cmd)
- *
- * Purpose : reset the SCSI bus.
- *
- * Returns : SUCCESS or FAILURE
- *
- */
-
-static int NCR5380_bus_reset(struct scsi_cmnd *cmd)
-{
- SETUP_HOSTDATA(cmd->device->host);
- int i;
- unsigned long flags;
-#if defined(RESET_RUN_DONE)
- struct scsi_cmnd *connected, *disconnected_queue;
-#endif
-
-
- NCR5380_print_status (cmd->device->host);
-
- /* get in phase */
- NCR5380_write( TARGET_COMMAND_REG,
- PHASE_SR_TO_TCR( NCR5380_read(STATUS_REG) ));
- /* assert RST */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST );
- udelay (40);
- /* reset NCR registers */
- NCR5380_write( INITIATOR_COMMAND_REG, ICR_BASE );
- NCR5380_write( MODE_REG, MR_BASE );
- NCR5380_write( TARGET_COMMAND_REG, 0 );
- NCR5380_write( SELECT_ENABLE_REG, 0 );
- /* ++roman: reset interrupt condition! otherwise no interrupts don't get
- * through anymore ... */
- (void)NCR5380_read( RESET_PARITY_INTERRUPT_REG );
-
- /* MSch 20140115 - looking at the generic NCR5380 driver, all of this
- * should go.
- * Catch-22: if we don't clear all queues, the SCSI driver lock will
- * not be released by atari_scsi_reset()!
- */
-
-#if defined(RESET_RUN_DONE)
- /* XXX Should now be done by midlevel code, but it's broken XXX */
- /* XXX see below XXX */
-
- /* MSch: old-style reset: actually abort all command processing here */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; to avoid problems with re-inserting the commands
- * into the issue_queue (via scsi_done()), the aborted commands are
- * remembered in local variables first.
- */
- local_irq_save(flags);
- connected = (struct scsi_cmnd *)hostdata->connected;
- hostdata->connected = NULL;
- disconnected_queue = (struct scsi_cmnd *)hostdata->disconnected_queue;
- hostdata->disconnected_queue = NULL;
-#ifdef SUPPORT_TAGS
- free_all_tags();
-#endif
- for( i = 0; i < 8; ++i )
- hostdata->busy[i] = 0;
-#ifdef REAL_DMA
- hostdata->dma_len = 0;
-#endif
- local_irq_restore(flags);
-
- /* In order to tell the mid-level code which commands were aborted,
- * set the command status to DID_RESET and call scsi_done() !!!
- * This ultimately aborts processing of these commands in the mid-level.
- */
-
- if ((cmd = connected)) {
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted a connected command\n", H_NO(cmd));
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done( cmd );
- }
-
- for (i = 0; (cmd = disconnected_queue); ++i) {
- disconnected_queue = NEXT(cmd);
- SET_NEXT(cmd, NULL);
- cmd->result = (cmd->result & 0xffff) | (DID_RESET << 16);
- cmd->scsi_done( cmd );
- }
- if (i > 0)
- dprintk(NDEBUG_ABORT, "scsi: reset aborted %d disconnected command(s)\n", i);
-
-
- /* since all commands have been explicitly terminated, we need to tell
- * the midlevel code that the reset was SUCCESSFUL, and there is no
- * need to 'wake up' the commands by a request_sense
- */
- return SUCCESS;
-#else /* 1 */
-
- /* MSch: new-style reset handling: let the mid-level do what it can */
-
- /* ++guenther: MID-LEVEL IS STILL BROKEN.
- * Mid-level is supposed to requeue all commands that were active on the
- * various low-level queues. In fact it does this, but that's not enough
- * because all these commands are subject to timeout. And if a timeout
- * happens for any removed command, *_abort() is called but all queues
- * are now empty. Abort then gives up the falcon lock, which is fatal,
- * since the mid-level will queue more commands and must have the lock
- * (it's all happening inside timer interrupt handler!!).
- * Even worse, abort will return NOT_RUNNING for all those commands not
- * on any queue, so they won't be retried ...
- *
- * Conclusion: either scsi.c disables timeout for all resetted commands
- * immediately, or we lose! As of linux-2.0.20 it doesn't.
- */
-
- /* After the reset, there are no more connected or disconnected commands
- * and no busy units; so clear the low-level status here to avoid
- * conflicts when the mid-level code tries to wake up the affected
- * commands!
- */
-
- if (hostdata->issue_queue)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted issued command(s)\n", H_NO(cmd));
- if (hostdata->connected)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted a connected command\n", H_NO(cmd));
- if (hostdata->disconnected_queue)
- dprintk(NDEBUG_ABORT, "scsi%d: reset aborted disconnected command(s)\n", H_NO(cmd));
-
- local_irq_save(flags);
- hostdata->issue_queue = NULL;
- hostdata->connected = NULL;
- hostdata->disconnected_queue = NULL;
-#ifdef SUPPORT_TAGS
- free_all_tags();
-#endif
- for( i = 0; i < 8; ++i )
- hostdata->busy[i] = 0;
-#ifdef REAL_DMA
- hostdata->dma_len = 0;
-#endif
- local_irq_restore(flags);
-
- /* we did no complete reset of all commands, so a wakeup is required */
- return SUCCESS;
-#endif /* 1 */
-}
-
-/* Local Variables: */
-/* tab-width: 8 */
-/* End: */
diff --git a/drivers/scsi/sun3_scsi.c b/drivers/scsi/sun3_scsi.c
index 9707b74..2a906d1 100644
--- a/drivers/scsi/sun3_scsi.c
+++ b/drivers/scsi/sun3_scsi.c
@@ -20,89 +20,58 @@
* Generic Generic NCR5380 driver
*
* Copyright 1995, Russell King
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
-
-/*
- * This is from mac_scsi.h, but hey, maybe this is useful for Sun3 too! :)
- *
- * Options :
- *
- * PARITY - enable parity checking. Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
- *
- * USLEEP - enable support for devices that don't disconnect. Untested.
- */
-
-#define AUTOSENSE
-
#include <linux/types.h>
-#include <linux/stddef.h>
-#include <linux/ctype.h>
#include <linux/delay.h>
-
#include <linux/module.h>
-#include <linux/signal.h>
#include <linux/ioport.h>
#include <linux/init.h>
#include <linux/blkdev.h>
+#include <linux/platform_device.h>
#include <asm/io.h>
-
-#include <asm/sun3ints.h>
#include <asm/dvma.h>
-#include <asm/idprom.h>
-#include <asm/machines.h>
-/* dma on! */
-#define REAL_DMA
-
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include "sun3_scsi.h"
-#include "NCR5380.h"
-extern int sun3_map_test(unsigned long, char *);
+/* Definitions for the core NCR5380 driver. */
-#define USE_WRAPPER
-/*#define RESET_BOOT */
-#define DRIVER_SETUP
+#define REAL_DMA
+/* #define SUPPORT_TAGS */
+/* minimum number of bytes to do dma on */
+#define DMA_MIN_SIZE 129
-/*
- * BUG can be used to trigger a strange code-size related hang on 2.1 kernels
- */
-#ifdef BUG
-#undef RESET_BOOT
-#undef DRIVER_SETUP
-#endif
+/* #define MAX_TAGS 32 */
-/* #define SUPPORT_TAGS */
+#define NCR5380_implementation_fields /* none */
-#ifdef SUN3_SCSI_VME
-#define ENABLE_IRQ()
-#else
-#define ENABLE_IRQ() enable_irq( IRQ_SUN3_SCSI );
-#endif
+#define NCR5380_read(reg) sun3scsi_read(reg)
+#define NCR5380_write(reg, value) sun3scsi_write(reg, value)
+
+#define NCR5380_queue_command sun3scsi_queue_command
+#define NCR5380_bus_reset sun3scsi_bus_reset
+#define NCR5380_abort sun3scsi_abort
+#define NCR5380_show_info sun3scsi_show_info
+#define NCR5380_info sun3scsi_info
+#define NCR5380_dma_read_setup(instance, data, count) \
+ sun3scsi_dma_setup(data, count, 0)
+#define NCR5380_dma_write_setup(instance, data, count) \
+ sun3scsi_dma_setup(data, count, 1)
+#define NCR5380_dma_residual(instance) \
+ sun3scsi_dma_residual(instance)
+#define NCR5380_dma_xfer_len(instance, cmd, phase) \
+ sun3scsi_dma_xfer_len(cmd->SCp.this_residual, cmd, !((phase) & SR_IO))
-static irqreturn_t scsi_sun3_intr(int irq, void *dummy);
-static inline unsigned char sun3scsi_read(int reg);
-static inline void sun3scsi_write(int reg, int value);
+#define NCR5380_acquire_dma_irq(instance) (1)
+#define NCR5380_release_dma_irq(instance)
+
+#include "NCR5380.h"
+
+
+extern int sun3_map_test(unsigned long, char *);
static int setup_can_queue = -1;
module_param(setup_can_queue, int, 0);
@@ -117,9 +86,7 @@ module_param(setup_use_tagged_queuing, int, 0);
static int setup_hostid = -1;
module_param(setup_hostid, int, 0);
-static struct scsi_cmnd *sun3_dma_setup_done = NULL;
-
-#define RESET_RUN_DONE
+/* #define RESET_BOOT */
#define AFTER_RESET_DELAY (HZ/2)
@@ -129,18 +96,15 @@ static struct scsi_cmnd *sun3_dma_setup_done = NULL;
/* dvma buffer to allocate -- 32k should hopefully be more than sufficient */
#define SUN3_DVMA_BUFSIZE 0xe000
-/* minimum number of bytes to do dma on */
-#define SUN3_DMA_MINSIZE 128
-
-static volatile unsigned char *sun3_scsi_regp;
+static struct scsi_cmnd *sun3_dma_setup_done;
+static unsigned char *sun3_scsi_regp;
static volatile struct sun3_dma_regs *dregs;
-#ifndef SUN3_SCSI_VME
-static struct sun3_udc_regs *udc_regs = NULL;
-#endif
+static struct sun3_udc_regs *udc_regs;
static unsigned char *sun3_dma_orig_addr = NULL;
static unsigned long sun3_dma_orig_count = 0;
static int sun3_dma_active = 0;
static unsigned long last_residual = 0;
+static struct Scsi_Host *default_instance;
/*
* NCR 5380 register access functions
@@ -148,12 +112,12 @@ static unsigned long last_residual = 0;
static inline unsigned char sun3scsi_read(int reg)
{
- return( sun3_scsi_regp[reg] );
+ return in_8(sun3_scsi_regp + reg);
}
static inline void sun3scsi_write(int reg, int value)
{
- sun3_scsi_regp[reg] = value;
+ out_8(sun3_scsi_regp + reg, value);
}
#ifndef SUN3_SCSI_VME
@@ -180,213 +144,10 @@ static inline void sun3_udc_write(unsigned short val, unsigned char reg)
}
#endif
-/*
- * XXX: status debug
- */
-static struct Scsi_Host *default_instance;
-
-/*
- * Function : int sun3scsi_detect(struct scsi_host_template * tpnt)
- *
- * Purpose : initializes mac NCR5380 driver based on the
- * command line / compile time port and irq definitions.
- *
- * Inputs : tpnt - template for this SCSI adapter.
- *
- * Returns : 1 if a host adapter was found, 0 if not.
- *
- */
-
-static int __init sun3scsi_detect(struct scsi_host_template *tpnt)
-{
- unsigned long ioaddr, irq;
- static int called = 0;
- struct Scsi_Host *instance;
-#ifdef SUN3_SCSI_VME
- int i;
- unsigned long addrs[3] = { IOBASE_SUN3_VMESCSI,
- IOBASE_SUN3_VMESCSI + 0x4000,
- 0 };
- unsigned long vecs[3] = { SUN3_VEC_VMESCSI0,
- SUN3_VEC_VMESCSI1,
- 0 };
-#endif
-
- /* check that this machine has an onboard 5380 */
- switch(idprom->id_machtype) {
-#ifdef SUN3_SCSI_VME
- case SM_SUN3|SM_3_160:
- case SM_SUN3|SM_3_260:
- break;
-#else
- case SM_SUN3|SM_3_50:
- case SM_SUN3|SM_3_60:
- break;
-#endif
-
- default:
- return 0;
- }
-
- if(called)
- return 0;
-
-#ifdef SUN3_SCSI_VME
- tpnt->proc_name = "Sun3 5380 VME SCSI";
-#else
- tpnt->proc_name = "Sun3 5380 SCSI";
-#endif
-
- /* setup variables */
- tpnt->can_queue =
- (setup_can_queue > 0) ? setup_can_queue : CAN_QUEUE;
- tpnt->cmd_per_lun =
- (setup_cmd_per_lun > 0) ? setup_cmd_per_lun : CMD_PER_LUN;
- tpnt->sg_tablesize =
- (setup_sg_tablesize >= 0) ? setup_sg_tablesize : SG_TABLESIZE;
-
- if (setup_hostid >= 0)
- tpnt->this_id = setup_hostid;
- else {
- /* use 7 as default */
- tpnt->this_id = 7;
- }
-
-#ifdef SUN3_SCSI_VME
- ioaddr = 0;
- for (i = 0; addrs[i] != 0; i++) {
- unsigned char x;
-
- ioaddr = (unsigned long)sun3_ioremap(addrs[i], PAGE_SIZE,
- SUN3_PAGE_TYPE_VME16);
- irq = vecs[i];
- sun3_scsi_regp = (unsigned char *)ioaddr;
-
- dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
-
- if (sun3_map_test((unsigned long)dregs, &x)) {
- unsigned short oldcsr;
-
- oldcsr = dregs->csr;
- dregs->csr = 0;
- udelay(SUN3_DMA_DELAY);
- if (dregs->csr == 0x1400)
- break;
-
- dregs->csr = oldcsr;
- }
-
- iounmap((void *)ioaddr);
- ioaddr = 0;
- }
-
- if (!ioaddr)
- return 0;
-#else
- irq = IRQ_SUN3_SCSI;
- ioaddr = (unsigned long)ioremap(IOBASE_SUN3_SCSI, PAGE_SIZE);
- sun3_scsi_regp = (unsigned char *)ioaddr;
-
- dregs = (struct sun3_dma_regs *)(((unsigned char *)ioaddr) + 8);
-
- if((udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs)))
- == NULL) {
- printk("SUN3 Scsi couldn't allocate DVMA memory!\n");
- return 0;
- }
-#endif
-#ifdef SUPPORT_TAGS
- if (setup_use_tagged_queuing < 0)
- setup_use_tagged_queuing = USE_TAGGED_QUEUING;
-#endif
-
- instance = scsi_register (tpnt, sizeof(struct NCR5380_hostdata));
- if(instance == NULL)
- return 0;
-
- default_instance = instance;
-
- instance->io_port = (unsigned long) ioaddr;
- instance->irq = irq;
-
- NCR5380_init(instance, 0);
-
- instance->n_io_port = 32;
-
- ((struct NCR5380_hostdata *)instance->hostdata)->ctrl = 0;
-
- if (request_irq(instance->irq, scsi_sun3_intr,
- 0, "Sun3SCSI-5380", instance)) {
-#ifndef REAL_DMA
- printk("scsi%d: IRQ%d not free, interrupts disabled\n",
- instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
-#else
- printk("scsi%d: IRQ%d not free, bailing out\n",
- instance->host_no, instance->irq);
- return 0;
-#endif
- }
-
- pr_info("scsi%d: %s at port %lX irq", instance->host_no,
- tpnt->proc_name, instance->io_port);
- if (instance->irq == SCSI_IRQ_NONE)
- printk ("s disabled");
- else
- printk (" %d", instance->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- instance->can_queue, instance->cmd_per_lun,
- SUN3SCSI_PUBLIC_RELEASE);
- printk("\nscsi%d:", instance->host_no);
- NCR5380_print_options(instance);
- printk("\n");
-
- dregs->csr = 0;
- udelay(SUN3_DMA_DELAY);
- dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
- udelay(SUN3_DMA_DELAY);
- dregs->fifo_count = 0;
-#ifdef SUN3_SCSI_VME
- dregs->fifo_count_hi = 0;
- dregs->dma_addr_hi = 0;
- dregs->dma_addr_lo = 0;
- dregs->dma_count_hi = 0;
- dregs->dma_count_lo = 0;
-
- dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
-#endif
-
- called = 1;
-
-#ifdef RESET_BOOT
- sun3_scsi_reset_boot(instance);
-#endif
-
- return 1;
-}
-
-int sun3scsi_release (struct Scsi_Host *shpnt)
-{
- if (shpnt->irq != SCSI_IRQ_NONE)
- free_irq(shpnt->irq, shpnt);
-
- iounmap((void *)sun3_scsi_regp);
-
- NCR5380_exit(shpnt);
- return 0;
-}
-
#ifdef RESET_BOOT
-/*
- * Our 'bus reset on boot' function
- */
-
static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
{
unsigned long end;
-
- NCR5380_local_declare();
- NCR5380_setup(instance);
/*
* Do a SCSI reset to clean up the bus during initialization. No
@@ -422,11 +183,6 @@ static void sun3_scsi_reset_boot(struct Scsi_Host *instance)
}
#endif
-static const char *sun3scsi_info(struct Scsi_Host *spnt)
-{
- return "";
-}
-
// safe bits for the CSR
#define CSR_GOOD 0x060f
@@ -468,7 +224,6 @@ static irqreturn_t scsi_sun3_intr(int irq, void *dummy)
void sun3_sun3_debug (void)
{
unsigned long flags;
- NCR5380_local_declare();
if (default_instance) {
local_irq_save(flags);
@@ -732,25 +487,200 @@ static int sun3scsi_dma_finish(int write_flag)
}
-#include "sun3_NCR5380.c"
+#include "atari_NCR5380.c"
-static struct scsi_host_template driver_template = {
+#ifdef SUN3_SCSI_VME
+#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI"
+#define DRV_MODULE_NAME "sun3_scsi_vme"
+#else
+#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI"
+#define DRV_MODULE_NAME "sun3_scsi"
+#endif
+
+#define PFX DRV_MODULE_NAME ": "
+
+static struct scsi_host_template sun3_scsi_template = {
+ .module = THIS_MODULE,
+ .proc_name = DRV_MODULE_NAME,
.show_info = sun3scsi_show_info,
.name = SUN3_SCSI_NAME,
- .detect = sun3scsi_detect,
- .release = sun3scsi_release,
.info = sun3scsi_info,
.queuecommand = sun3scsi_queue_command,
.eh_abort_handler = sun3scsi_abort,
.eh_bus_reset_handler = sun3scsi_bus_reset,
- .can_queue = CAN_QUEUE,
+ .can_queue = 16,
.this_id = 7,
- .sg_tablesize = SG_TABLESIZE,
- .cmd_per_lun = CMD_PER_LUN,
+ .sg_tablesize = SG_NONE,
+ .cmd_per_lun = 2,
.use_clustering = DISABLE_CLUSTERING
};
+static int __init sun3_scsi_probe(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance;
+ int error;
+ struct resource *irq, *mem;
+ unsigned char *ioaddr;
+ int host_flags = 0;
+#ifdef SUN3_SCSI_VME
+ int i;
+#endif
+
+ if (setup_can_queue > 0)
+ sun3_scsi_template.can_queue = setup_can_queue;
+ if (setup_cmd_per_lun > 0)
+ sun3_scsi_template.cmd_per_lun = setup_cmd_per_lun;
+ if (setup_sg_tablesize >= 0)
+ sun3_scsi_template.sg_tablesize = setup_sg_tablesize;
+ if (setup_hostid >= 0)
+ sun3_scsi_template.this_id = setup_hostid & 7;
+
+#ifdef SUN3_SCSI_VME
+ ioaddr = NULL;
+ for (i = 0; i < 2; i++) {
+ unsigned char x;
+
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, i);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, i);
+ if (!irq || !mem)
+ break;
+
+ ioaddr = sun3_ioremap(mem->start, resource_size(mem),
+ SUN3_PAGE_TYPE_VME16);
+ dregs = (struct sun3_dma_regs *)(ioaddr + 8);
+
+ if (sun3_map_test((unsigned long)dregs, &x)) {
+ unsigned short oldcsr;
+
+ oldcsr = dregs->csr;
+ dregs->csr = 0;
+ udelay(SUN3_DMA_DELAY);
+ if (dregs->csr == 0x1400)
+ break;
+
+ dregs->csr = oldcsr;
+ }
+
+ iounmap(ioaddr);
+ ioaddr = NULL;
+ }
+ if (!ioaddr)
+ return -ENODEV;
+#else
+ irq = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!irq || !mem)
+ return -ENODEV;
+
+ ioaddr = ioremap(mem->start, resource_size(mem));
+ dregs = (struct sun3_dma_regs *)(ioaddr + 8);
+
+ udc_regs = dvma_malloc(sizeof(struct sun3_udc_regs));
+ if (!udc_regs) {
+ pr_err(PFX "couldn't allocate DVMA memory!\n");
+ iounmap(ioaddr);
+ return -ENOMEM;
+ }
+#endif
+
+ sun3_scsi_regp = ioaddr;
+
+ instance = scsi_host_alloc(&sun3_scsi_template,
+ sizeof(struct NCR5380_hostdata));
+ if (!instance) {
+ error = -ENOMEM;
+ goto fail_alloc;
+ }
+ default_instance = instance;
+
+ instance->io_port = (unsigned long)ioaddr;
+ instance->irq = irq->start;
+
+#ifdef SUPPORT_TAGS
+ host_flags |= setup_use_tagged_queuing > 0 ? FLAG_TAGGED_QUEUING : 0;
+#endif
+
+ NCR5380_init(instance, host_flags);
+
+ error = request_irq(instance->irq, scsi_sun3_intr, 0,
+ "NCR5380", instance);
+ if (error) {
+#ifdef REAL_DMA
+ pr_err(PFX "scsi%d: IRQ %d not free, bailing out\n",
+ instance->host_no, instance->irq);
+ goto fail_irq;
+#else
+ pr_warn(PFX "scsi%d: IRQ %d not free, interrupts disabled\n",
+ instance->host_no, instance->irq);
+ instance->irq = NO_IRQ;
+#endif
+ }
+
+ dregs->csr = 0;
+ udelay(SUN3_DMA_DELAY);
+ dregs->csr = CSR_SCSI | CSR_FIFO | CSR_INTR;
+ udelay(SUN3_DMA_DELAY);
+ dregs->fifo_count = 0;
+#ifdef SUN3_SCSI_VME
+ dregs->fifo_count_hi = 0;
+ dregs->dma_addr_hi = 0;
+ dregs->dma_addr_lo = 0;
+ dregs->dma_count_hi = 0;
+ dregs->dma_count_lo = 0;
+
+ dregs->ivect = VME_DATA24 | (instance->irq & 0xff);
+#endif
+
+#ifdef RESET_BOOT
+ sun3_scsi_reset_boot(instance);
+#endif
+
+ error = scsi_add_host(instance, NULL);
+ if (error)
+ goto fail_host;
+
+ platform_set_drvdata(pdev, instance);
+
+ scsi_scan_host(instance);
+ return 0;
+
+fail_host:
+ if (instance->irq != NO_IRQ)
+ free_irq(instance->irq, instance);
+fail_irq:
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+fail_alloc:
+ if (udc_regs)
+ dvma_free(udc_regs);
+ iounmap(sun3_scsi_regp);
+ return error;
+}
+
+static int __exit sun3_scsi_remove(struct platform_device *pdev)
+{
+ struct Scsi_Host *instance = platform_get_drvdata(pdev);
+
+ scsi_remove_host(instance);
+ if (instance->irq != NO_IRQ)
+ free_irq(instance->irq, instance);
+ NCR5380_exit(instance);
+ scsi_host_put(instance);
+ if (udc_regs)
+ dvma_free(udc_regs);
+ iounmap(sun3_scsi_regp);
+ return 0;
+}
+
+static struct platform_driver sun3_scsi_driver = {
+ .remove = __exit_p(sun3_scsi_remove),
+ .driver = {
+ .name = DRV_MODULE_NAME,
+ .owner = THIS_MODULE,
+ },
+};
-#include "scsi_module.c"
+module_platform_driver_probe(sun3_scsi_driver, sun3_scsi_probe);
+MODULE_ALIAS("platform:" DRV_MODULE_NAME);
MODULE_LICENSE("GPL");
diff --git a/drivers/scsi/sun3_scsi.h b/drivers/scsi/sun3_scsi.h
index e96a37c..d22745f 100644
--- a/drivers/scsi/sun3_scsi.h
+++ b/drivers/scsi/sun3_scsi.h
@@ -13,95 +13,11 @@
* (Unix and Linux consulting and custom programming)
* drew@colorado.edu
* +1 (303) 440-4894
- *
- * ALPHA RELEASE 1.
- *
- * For more information, please consult
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
#ifndef SUN3_SCSI_H
#define SUN3_SCSI_H
-#define SUN3SCSI_PUBLIC_RELEASE 1
-
-/*
- * Int: level 2 autovector
- * IO: type 1, base 0x00140000, 5 bits phys space: A<4..0>
- */
-#define IRQ_SUN3_SCSI 2
-#define IOBASE_SUN3_SCSI 0x00140000
-
-#define IOBASE_SUN3_VMESCSI 0xff200000
-
-static int sun3scsi_abort(struct scsi_cmnd *);
-static int sun3scsi_detect (struct scsi_host_template *);
-static const char *sun3scsi_info (struct Scsi_Host *);
-static int sun3scsi_bus_reset(struct scsi_cmnd *);
-static int sun3scsi_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int sun3scsi_release (struct Scsi_Host *);
-
-#ifndef CMD_PER_LUN
-#define CMD_PER_LUN 2
-#endif
-
-#ifndef CAN_QUEUE
-#define CAN_QUEUE 16
-#endif
-
-#ifndef SG_TABLESIZE
-#define SG_TABLESIZE SG_NONE
-#endif
-
-#ifndef MAX_TAGS
-#define MAX_TAGS 32
-#endif
-
-#ifndef USE_TAGGED_QUEUING
-#define USE_TAGGED_QUEUING 1
-#endif
-
-#include <scsi/scsicam.h>
-
-#ifdef SUN3_SCSI_VME
-#define SUN3_SCSI_NAME "Sun3 NCR5380 VME SCSI"
-#else
-#define SUN3_SCSI_NAME "Sun3 NCR5380 SCSI"
-#endif
-
-#define NCR5380_implementation_fields \
- int port, ctrl
-
-#define NCR5380_local_declare() \
- struct Scsi_Host *_instance
-
-#define NCR5380_setup(instance) \
- _instance = instance
-
-#define NCR5380_read(reg) sun3scsi_read(reg)
-#define NCR5380_write(reg, value) sun3scsi_write(reg, value)
-
-#define NCR5380_intr sun3scsi_intr
-#define NCR5380_queue_command sun3scsi_queue_command
-#define NCR5380_bus_reset sun3scsi_bus_reset
-#define NCR5380_abort sun3scsi_abort
-#define NCR5380_show_info sun3scsi_show_info
-#define NCR5380_dma_xfer_len(i, cmd, phase) \
- sun3scsi_dma_xfer_len(cmd->SCp.this_residual,cmd,((phase) & SR_IO) ? 0 : 1)
-
-#define NCR5380_dma_write_setup(instance, data, count) sun3scsi_dma_setup(data, count, 1)
-#define NCR5380_dma_read_setup(instance, data, count) sun3scsi_dma_setup(data, count, 0)
-#define NCR5380_dma_residual sun3scsi_dma_residual
-
/* additional registers - mainly DMA control regs */
/* these start at regbase + 8 -- directly after the NCR regs */
struct sun3_dma_regs {
diff --git a/drivers/scsi/sym53c8xx_2/sym_glue.c b/drivers/scsi/sym53c8xx_2/sym_glue.c
index e59e6f9..5d00e51 100644
--- a/drivers/scsi/sym53c8xx_2/sym_glue.c
+++ b/drivers/scsi/sym53c8xx_2/sym_glue.c
@@ -820,9 +820,7 @@ static int sym53c8xx_slave_configure(struct scsi_device *sdev)
if (reqtags > SYM_CONF_MAX_TAG)
reqtags = SYM_CONF_MAX_TAG;
depth_to_use = reqtags ? reqtags : 1;
- scsi_adjust_queue_depth(sdev,
- sdev->tagged_supported ? MSG_SIMPLE_TAG : 0,
- depth_to_use);
+ scsi_change_queue_depth(sdev, depth_to_use);
lp->s.scdev_depth = depth_to_use;
sym_tune_dev_queuing(tp, sdev->lun, reqtags);
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
index 8cc8093..87828ac 100644
--- a/drivers/scsi/t128.c
+++ b/drivers/scsi/t128.c
@@ -1,4 +1,3 @@
-#define AUTOSENSE
#define PSEUDO_DMA
/*
@@ -12,8 +11,6 @@
* drew@colorado.edu
* +1 (303) 440-4894
*
- * DISTRIBUTION RELEASE 3.
- *
* For more information, please consult
*
* Trantor Systems, Ltd.
@@ -24,40 +21,9 @@
* 5415 Randall Place
* Fremont, CA 94538
* 1+ (415) 770-1400, FAX 1+ (415) 770-9910
- *
- * and
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
/*
- * Options :
- * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
- * for commands that return with a CHECK CONDITION status.
- *
- * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
- * increase compared to polled I/O.
- *
- * PARITY - enable parity checking. Not supported.
- *
- * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
- *
- *
- * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
- * only really want to use this if you're having a problem with
- * dropped characters during high speed communications, and even
- * then, you're going to be better off twiddling with transfersize.
- *
- * USLEEP - enable support for devices that don't disconnect. Untested.
- *
* The card is detected and initialized in one of several ways :
* 1. Autoprobe (default) - since the board is memory mapped,
* a BIOS signature is scanned for to locate the registers.
@@ -111,7 +77,6 @@
#include <linux/module.h>
#include <linux/delay.h>
-#include "scsi.h"
#include <scsi/scsi_host.h>
#include "t128.h"
#define AUTOPROBE_IRQ
@@ -148,6 +113,7 @@ static struct signature {
#define NO_SIGNATURES ARRAY_SIZE(signatures)
+#ifndef MODULE
/*
* Function : t128_setup(char *str, int *ints)
*
@@ -158,9 +124,13 @@ static struct signature {
*
*/
-void __init t128_setup(char *str, int *ints){
+static int __init t128_setup(char *str)
+{
static int commandline_current = 0;
int i;
+ int ints[10];
+
+ get_options(str, ARRAY_SIZE(ints), ints);
if (ints[0] != 2)
printk("t128_setup : usage t128=address,irq\n");
else
@@ -174,8 +144,12 @@ void __init t128_setup(char *str, int *ints){
}
++commandline_current;
}
+ return 1;
}
+__setup("t128=", t128_setup);
+#endif
+
/*
* Function : int t128_detect(struct scsi_host_template * tpnt)
*
@@ -189,17 +163,14 @@ void __init t128_setup(char *str, int *ints){
*
*/
-int __init t128_detect(struct scsi_host_template * tpnt){
+static int __init t128_detect(struct scsi_host_template *tpnt)
+{
static int current_override = 0, current_base = 0;
struct Scsi_Host *instance;
unsigned long base;
void __iomem *p;
int sig, count;
- tpnt->proc_name = "t128";
- tpnt->show_info = t128_show_info;
- tpnt->write_info = t128_write_info;
-
for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
base = 0;
p = NULL;
@@ -254,15 +225,19 @@ found:
else
instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
- if (instance->irq != SCSI_IRQ_NONE)
+ /* Compatibility with documented NCR5380 kernel parameters */
+ if (instance->irq == 255)
+ instance->irq = NO_IRQ;
+
+ if (instance->irq != NO_IRQ)
if (request_irq(instance->irq, t128_intr, 0, "t128",
instance)) {
printk("scsi%d : IRQ%d not free, interrupts disabled\n",
instance->host_no, instance->irq);
- instance->irq = SCSI_IRQ_NONE;
+ instance->irq = NO_IRQ;
}
- if (instance->irq == SCSI_IRQ_NONE) {
+ if (instance->irq == NO_IRQ) {
printk("scsi%d : interrupts not enabled. for better interactive performance,\n", instance->host_no);
printk("scsi%d : please jumper the board for a free IRQ.\n", instance->host_no);
}
@@ -271,16 +246,6 @@ found:
printk("scsi%d : irq = %d\n", instance->host_no, instance->irq);
#endif
- printk("scsi%d : at 0x%08lx", instance->host_no, instance->base);
- if (instance->irq == SCSI_IRQ_NONE)
- printk (" interrupts disabled");
- else
- printk (" irq %d", instance->irq);
- printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
- CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE);
- NCR5380_print_options(instance);
- printk("\n");
-
++current_override;
++count;
}
@@ -291,7 +256,7 @@ static int t128_release(struct Scsi_Host *shost)
{
NCR5380_local_declare();
NCR5380_setup(shost);
- if (shost->irq)
+ if (shost->irq != NO_IRQ)
free_irq(shost->irq, shost);
NCR5380_exit(shost);
if (shost->io_port && shost->n_io_port)
@@ -321,8 +286,8 @@ static int t128_release(struct Scsi_Host *shost)
* and matching the H_C_S coordinates to what DOS uses.
*/
-int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
- sector_t capacity, int * ip)
+static int t128_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int *ip)
{
ip[0] = 64;
ip[1] = 32;
@@ -430,6 +395,10 @@ static struct scsi_host_template driver_template = {
.name = "Trantor T128/T128F/T228",
.detect = t128_detect,
.release = t128_release,
+ .proc_name = "t128",
+ .show_info = t128_show_info,
+ .write_info = t128_write_info,
+ .info = t128_info,
.queuecommand = t128_queue_command,
.eh_abort_handler = t128_abort,
.eh_bus_reset_handler = t128_bus_reset,
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
index fd68cec..2c73714 100644
--- a/drivers/scsi/t128.h
+++ b/drivers/scsi/t128.h
@@ -8,8 +8,6 @@
* drew@colorado.edu
* +1 (303) 440-4894
*
- * DISTRIBUTION RELEASE 3.
- *
* For more information, please consult
*
* Trantor Systems, Ltd.
@@ -20,25 +18,11 @@
* 5415 Randall Place
* Fremont, CA 94538
* 1+ (415) 770-1400, FAX 1+ (415) 770-9910
- *
- * and
- *
- * NCR 5380 Family
- * SCSI Protocol Controller
- * Databook
- *
- * NCR Microelectronics
- * 1635 Aeroplaza Drive
- * Colorado Springs, CO 80916
- * 1+ (719) 578-3400
- * 1+ (800) 334-5454
*/
#ifndef T128_H
#define T128_H
-#define T128_PUBLIC_RELEASE 3
-
#define TDEBUG 0
#define TDEBUG_INIT 0x1
#define TDEBUG_TRANSFER 0x2
@@ -88,12 +72,6 @@
#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
#ifndef ASM
-static int t128_abort(struct scsi_cmnd *);
-static int t128_biosparam(struct scsi_device *, struct block_device *,
- sector_t, int*);
-static int t128_detect(struct scsi_host_template *);
-static int t128_queue_command(struct Scsi_Host *, struct scsi_cmnd *);
-static int t128_bus_reset(struct scsi_cmnd *);
#ifndef CMD_PER_LUN
#define CMD_PER_LUN 2
@@ -134,6 +112,7 @@ static int t128_bus_reset(struct scsi_cmnd *);
#define NCR5380_queue_command t128_queue_command
#define NCR5380_abort t128_abort
#define NCR5380_bus_reset t128_bus_reset
+#define NCR5380_info t128_info
#define NCR5380_show_info t128_show_info
#define NCR5380_write_info t128_write_info
diff --git a/drivers/scsi/tmscsim.c b/drivers/scsi/tmscsim.c
deleted file mode 100644
index 7645757..0000000
--- a/drivers/scsi/tmscsim.c
+++ /dev/null
@@ -1,2620 +0,0 @@
-/************************************************************************
- * FILE NAME : TMSCSIM.C *
- * BY : C.L. Huang, ching@tekram.com.tw *
- * Description: Device Driver for Tekram DC-390(T) PCI SCSI *
- * Bus Master Host Adapter *
- * (C)Copyright 1995-1996 Tekram Technology Co., Ltd. *
- ************************************************************************
- * (C) Copyright: put under GNU GPL in 10/96 *
- * (see Documentation/scsi/tmscsim.txt) *
- ************************************************************************
- * $Id: tmscsim.c,v 2.60.2.30 2000/12/20 01:07:12 garloff Exp $ *
- * Enhancements and bugfixes by *
- * Kurt Garloff <kurt@garloff.de> <garloff@suse.de> *
- ************************************************************************
- * HISTORY: *
- * *
- * REV# DATE NAME DESCRIPTION *
- * 1.00 96/04/24 CLH First release *
- * 1.01 96/06/12 CLH Fixed bug of Media Change for Removable *
- * Device, scan all LUN. Support Pre2.0.10 *
- * 1.02 96/06/18 CLH Fixed bug of Command timeout ... *
- * 1.03 96/09/25 KG Added tmscsim_proc_info() *
- * 1.04 96/10/11 CLH Updating for support KV 2.0.x *
- * 1.05 96/10/18 KG Fixed bug in DC390_abort(null ptr deref)*
- * 1.06 96/10/25 KG Fixed module support *
- * 1.07 96/11/09 KG Fixed tmscsim_proc_info() *
- * 1.08 96/11/18 KG Fixed null ptr in DC390_Disconnect() *
- * 1.09 96/11/30 KG Added register the allocated IO space *
- * 1.10 96/12/05 CLH Modified tmscsim_proc_info(), and reset *
- * pending interrupt in DC390_detect() *
- * 1.11 97/02/05 KG/CLH Fixeds problem with partitions greater *
- * than 1GB *
- * 1.12 98/02/15 MJ Rewritten PCI probing *
- * 1.13 98/04/08 KG Support for non DC390, __initfunc decls,*
- * changed max devs from 10 to 16 *
- * 1.14a 98/05/05 KG Dynamic DCB allocation, add-single-dev *
- * for LUNs if LUN_SCAN (BIOS) not set *
- * runtime config using /proc interface *
- * 1.14b 98/05/06 KG eliminated cli (); sti (); spinlocks *
- * 1.14c 98/05/07 KG 2.0.x compatibility *
- * 1.20a 98/05/07 KG changed names of funcs to be consistent *
- * DC390_ (entry points), dc390_ (internal)*
- * reworked locking *
- * 1.20b 98/05/12 KG bugs: version, kfree, _ctmp *
- * debug output *
- * 1.20c 98/05/12 KG bugs: kfree, parsing, EEpromDefaults *
- * 1.20d 98/05/14 KG bugs: list linkage, clear flag after *
- * reset on startup, code cleanup *
- * 1.20e 98/05/15 KG spinlock comments, name space cleanup *
- * pLastDCB now part of ACB structure *
- * added stats, timeout for 2.1, TagQ bug *
- * RESET and INQUIRY interface commands *
- * 1.20f 98/05/18 KG spinlocks fixes, max_lun fix, free DCBs *
- * for missing LUNs, pending int *
- * 1.20g 98/05/19 KG Clean up: Avoid short *
- * 1.20h 98/05/21 KG Remove AdaptSCSIID, max_lun ... *
- * 1.20i 98/05/21 KG Aiiie: Bug with TagQMask *
- * 1.20j 98/05/24 KG Handle STAT_BUSY, handle pACB->pLinkDCB *
- * == 0 in remove_dev and DoingSRB_Done *
- * 1.20k 98/05/25 KG DMA_INT (experimental) *
- * 1.20l 98/05/27 KG remove DMA_INT; DMA_IDLE cmds added; *
- * 1.20m 98/06/10 KG glitch configurable; made some global *
- * vars part of ACB; use DC390_readX *
- * 1.20n 98/06/11 KG startup params *
- * 1.20o 98/06/15 KG added TagMaxNum to boot/module params *
- * Device Nr -> Idx, TagMaxNum power of 2 *
- * 1.20p 98/06/17 KG Docu updates. Reset depends on settings *
- * pci_set_master added; 2.0.xx: pcibios_* *
- * used instead of MechNum things ... *
- * 1.20q 98/06/23 KG Changed defaults. Added debug code for *
- * removable media and fixed it. TagMaxNum *
- * fixed for DC390. Locking: ACB, DRV for *
- * better IRQ sharing. Spelling: Queueing *
- * Parsing and glitch_cfg changes. Display *
- * real SyncSpeed value. Made DisConn *
- * functional (!) *
- * 1.20r 98/06/30 KG Debug macros, allow disabling DsCn, set *
- * BIT4 in CtrlR4, EN_PAGE_INT, 2.0 module *
- * param -1 fixed. *
- * 1.20s 98/08/20 KG Debug info on abort(), try to check PCI,*
- * phys_to_bus instead of phys_to_virt, *
- * fixed sel. process, fixed locking, *
- * added MODULE_XXX infos, changed IRQ *
- * request flags, disable DMA_INT *
- * 1.20t 98/09/07 KG TagQ report fixed; Write Erase DMA Stat;*
- * initfunc -> __init; better abort; *
- * Timeout for XFER_DONE & BLAST_COMPLETE; *
- * Allow up to 33 commands being processed *
- * 2.0a 98/10/14 KG Max Cmnds back to 17. DMA_Stat clearing *
- * all flags. Clear within while() loops *
- * in DataIn_0/Out_0. Null ptr in dumpinfo *
- * for pSRB==0. Better locking during init.*
- * bios_param() now respects part. table. *
- * 2.0b 98/10/24 KG Docu fixes. Timeout Msg in DMA Blast. *
- * Disallow illegal idx in INQUIRY/REMOVE *
- * 2.0c 98/11/19 KG Cleaned up detect/init for SMP boxes, *
- * Write Erase DMA (1.20t) caused problems *
- * 2.0d 98/12/25 KG Christmas release ;-) Message handling *
- * completely reworked. Handle target ini- *
- * tiated SDTR correctly. *
- * 2.0d1 99/01/25 KG Try to handle RESTORE_PTR *
- * 2.0d2 99/02/08 KG Check for failure of kmalloc, correct *
- * inclusion of scsicam.h, DelayReset *
- * 2.0d3 99/05/31 KG DRIVER_OK -> DID_OK, DID_NO_CONNECT, *
- * detect Target mode and warn. *
- * pcmd->result handling cleaned up. *
- * 2.0d4 99/06/01 KG Cleaned selection process. Found bug *
- * which prevented more than 16 tags. Now: *
- * 24. SDTR cleanup. Cleaner multi-LUN *
- * handling. Don't modify ControlRegs/FIFO *
- * when connected. *
- * 2.0d5 99/06/01 KG Clear DevID, Fix INQUIRY after cfg chg. *
- * 2.0d6 99/06/02 KG Added ADD special command to allow cfg. *
- * before detection. Reset SYNC_NEGO_DONE *
- * after a bus reset. *
- * 2.0d7 99/06/03 KG Fixed bugs wrt add,remove commands *
- * 2.0d8 99/06/04 KG Removed copying of cmnd into CmdBlock. *
- * Fixed Oops in _release(). *
- * 2.0d9 99/06/06 KG Also tag queue INQUIRY, T_U_R, ... *
- * Allow arb. no. of Tagged Cmnds. Max 32 *
- * 2.0d1099/06/20 KG TagMaxNo changes now honoured! Queueing *
- * clearified (renamed ..) TagMask handling*
- * cleaned. *
- * 2.0d1199/06/28 KG cmd->result now identical to 2.0d2 *
- * 2.0d1299/07/04 KG Changed order of processing in IRQ *
- * 2.0d1399/07/05 KG Don't update DCB fields if removed *
- * 2.0d1499/07/05 KG remove_dev: Move kfree() to the end *
- * 2.0d1599/07/12 KG use_new_eh_code: 0, ULONG -> UINT where *
- * appropriate *
- * 2.0d1699/07/13 KG Reenable StartSCSI interrupt, Retry msg *
- * 2.0d1799/07/15 KG Remove debug msg. Disable recfg. when *
- * there are queued cmnds *
- * 2.0d1899/07/18 KG Selection timeout: Don't requeue *
- * 2.0d1999/07/18 KG Abort: Only call scsi_done if dequeued *
- * 2.0d2099/07/19 KG Rst_Detect: DoingSRB_Done *
- * 2.0d2199/08/15 KG dev_id for request/free_irq, cmnd[0] for*
- * RETRY, SRBdone does DID_ABORT for the *
- * cmd passed by DC390_reset() *
- * 2.0d2299/08/25 KG dev_id fixed. can_queue: 42 *
- * 2.0d2399/08/25 KG Removed some debugging code. dev_id *
- * now is set to pACB. Use u8,u16,u32. *
- * 2.0d2499/11/14 KG Unreg. I/O if failed IRQ alloc. Call *
- * done () w/ DID_BAD_TARGET in case of *
- * missing DCB. We are old EH!! *
- * 2.0d2500/01/15 KG 2.3.3x compat from Andreas Schultz *
- * set unique_id. Disable RETRY message. *
- * 2.0d2600/01/29 KG Go to new EH. *
- * 2.0d2700/01/31 KG ... but maintain 2.0 compat. *
- * and fix DCB freeing *
- * 2.0d2800/02/14 KG Queue statistics fixed, dump special cmd*
- * Waiting_Timer for failed StartSCSI *
- * New EH: Don't return cmnds to ML on RST *
- * Use old EH (don't have new EH fns yet) *
- * Reset: Unlock, but refuse to queue *
- * 2.3 __setup function *
- * 2.0e 00/05/22 KG Return residual for 2.3 *
- * 2.0e1 00/05/25 KG Compile fixes for 2.3.99 *
- * 2.0e2 00/05/27 KG Jeff Garzik's pci_enable_device() *
- * 2.0e3 00/09/29 KG Some 2.4 changes. Don't try Sync Nego *
- * before INQUIRY has reported ability. *
- * Recognise INQUIRY as scanning command. *
- * 2.0e4 00/10/13 KG Allow compilation into 2.4 kernel *
- * 2.0e5 00/11/17 KG Store Inq.flags in DCB *
- * 2.0e6 00/11/22 KG 2.4 init function (Thx to O.Schumann) *
- * 2.4 PCI device table (Thx to A.Richter) *
- * 2.0e7 00/11/28 KG Allow overriding of BIOS settings *
- * 2.0f 00/12/20 KG Handle failed INQUIRYs during scan *
- * 2.1a 03/11/29 GL, KG Initial fixing for 2.6. Convert to *
- * use the current PCI-mapping API, update *
- * command-queuing. *
- * 2.1b 04/04/13 GL Fix for 64-bit platforms *
- * 2.1b1 04/01/31 GL (applied 05.04) Remove internal *
- * command-queuing. *
- * 2.1b2 04/02/01 CH (applied 05.04) Fix error-handling *
- * 2.1c 04/05/23 GL Update to use the new pci_driver API, *
- * some scsi EH updates, more cleanup. *
- * 2.1d 04/05/27 GL Moved setting of scan_devices to *
- * slave_alloc/_configure/_destroy, as *
- * suggested by CH. *
- ***********************************************************************/
-
-/* DEBUG options */
-//#define DC390_DEBUG0
-//#define DC390_DEBUG1
-//#define DC390_DCBDEBUG
-//#define DC390_PARSEDEBUG
-//#define DC390_REMOVABLEDEBUG
-//#define DC390_LOCKDEBUG
-
-//#define NOP do{}while(0)
-#define C_NOP
-
-/* Debug definitions */
-#ifdef DC390_DEBUG0
-# define DEBUG0(x) x
-#else
-# define DEBUG0(x) C_NOP
-#endif
-#ifdef DC390_DEBUG1
-# define DEBUG1(x) x
-#else
-# define DEBUG1(x) C_NOP
-#endif
-#ifdef DC390_DCBDEBUG
-# define DCBDEBUG(x) x
-#else
-# define DCBDEBUG(x) C_NOP
-#endif
-#ifdef DC390_PARSEDEBUG
-# define PARSEDEBUG(x) x
-#else
-# define PARSEDEBUG(x) C_NOP
-#endif
-#ifdef DC390_REMOVABLEDEBUG
-# define REMOVABLEDEBUG(x) x
-#else
-# define REMOVABLEDEBUG(x) C_NOP
-#endif
-#define DCBDEBUG1(x) C_NOP
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/signal.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-#include <linux/pci.h>
-#include <linux/proc_fs.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/blkdev.h>
-#include <linux/timer.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/slab.h>
-#include <asm/io.h>
-
-#include <scsi/scsi.h>
-#include <scsi/scsi_cmnd.h>
-#include <scsi/scsi_device.h>
-#include <scsi/scsi_host.h>
-#include <scsi/scsicam.h>
-#include <scsi/scsi_tcq.h>
-
-
-#define DC390_BANNER "Tekram DC390/AM53C974"
-#define DC390_VERSION "2.1d 2004-05-27"
-
-#define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI
-
-#include "tmscsim.h"
-
-
-static void dc390_DataOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_DataIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-static void dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus);
-
-static void dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB );
-static void dc390_Disconnect( struct dc390_acb* pACB );
-static void dc390_Reselect( struct dc390_acb* pACB );
-static void dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB );
-static void dc390_ScsiRstDetect( struct dc390_acb* pACB );
-static void dc390_EnableMsgOut_Abort(struct dc390_acb*, struct dc390_srb*);
-static void dc390_dumpinfo(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB);
-static void dc390_ResetDevParam(struct dc390_acb* pACB);
-
-static u32 dc390_laststatus = 0;
-static u8 dc390_adapterCnt = 0;
-
-static int disable_clustering;
-module_param(disable_clustering, int, S_IRUGO);
-MODULE_PARM_DESC(disable_clustering, "If you experience problems with your devices, try setting to 1");
-
-/* Startup values, to be overriden on the commandline */
-static int tmscsim[] = {-2, -2, -2, -2, -2, -2};
-
-module_param_array(tmscsim, int, NULL, 0);
-MODULE_PARM_DESC(tmscsim, "Host SCSI ID, Speed (0=10MHz), Device Flags, Adapter Flags, Max Tags (log2(tags)-1), DelayReset (s)");
-MODULE_AUTHOR("C.L. Huang / Kurt Garloff");
-MODULE_DESCRIPTION("SCSI host adapter driver for Tekram DC390 and other AMD53C974A based PCI SCSI adapters");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("sd,sr,sg,st");
-
-static void *dc390_phase0[]={
- dc390_DataOut_0,
- dc390_DataIn_0,
- dc390_Command_0,
- dc390_Status_0,
- dc390_Nop_0,
- dc390_Nop_0,
- dc390_MsgOut_0,
- dc390_MsgIn_0,
- dc390_Nop_1
- };
-
-static void *dc390_phase1[]={
- dc390_DataOutPhase,
- dc390_DataInPhase,
- dc390_CommandPhase,
- dc390_StatusPhase,
- dc390_Nop_0,
- dc390_Nop_0,
- dc390_MsgOutPhase,
- dc390_MsgInPhase,
- dc390_Nop_1
- };
-
-#ifdef DC390_DEBUG1
-static char* dc390_p0_str[] = {
- "dc390_DataOut_0",
- "dc390_DataIn_0",
- "dc390_Command_0",
- "dc390_Status_0",
- "dc390_Nop_0",
- "dc390_Nop_0",
- "dc390_MsgOut_0",
- "dc390_MsgIn_0",
- "dc390_Nop_1"
- };
-
-static char* dc390_p1_str[] = {
- "dc390_DataOutPhase",
- "dc390_DataInPhase",
- "dc390_CommandPhase",
- "dc390_StatusPhase",
- "dc390_Nop_0",
- "dc390_Nop_0",
- "dc390_MsgOutPhase",
- "dc390_MsgInPhase",
- "dc390_Nop_1"
- };
-#endif
-
-static u8 dc390_eepromBuf[MAX_ADAPTER_NUM][EE_LEN];
-static u8 dc390_clock_period1[] = {4, 5, 6, 7, 8, 10, 13, 20};
-static u8 dc390_clock_speed[] = {100,80,67,57,50, 40, 31, 20};
-
-/***********************************************************************
- * Functions for the management of the internal structures
- * (DCBs, SRBs, Queueing)
- *
- **********************************************************************/
-static void inline dc390_start_segment(struct dc390_srb* pSRB)
-{
- struct scatterlist *psgl = pSRB->pSegmentList;
-
- /* start new sg segment */
- pSRB->SGBusAddr = sg_dma_address(psgl);
- pSRB->SGToBeXferLen = sg_dma_len(psgl);
-}
-
-static unsigned long inline dc390_advance_segment(struct dc390_srb* pSRB, u32 residue)
-{
- unsigned long xfer = pSRB->SGToBeXferLen - residue;
-
- /* xfer more bytes transferred */
- pSRB->SGBusAddr += xfer;
- pSRB->TotalXferredLen += xfer;
- pSRB->SGToBeXferLen = residue;
-
- return xfer;
-}
-
-static struct dc390_dcb __inline__ *dc390_findDCB ( struct dc390_acb* pACB, u8 id, u8 lun)
-{
- struct dc390_dcb* pDCB = pACB->pLinkDCB; if (!pDCB) return NULL;
- while (pDCB->TargetID != id || pDCB->TargetLUN != lun)
- {
- pDCB = pDCB->pNextDCB;
- if (pDCB == pACB->pLinkDCB)
- return NULL;
- }
- DCBDEBUG1( printk (KERN_DEBUG "DCB %p (%02x,%02x) found.\n", \
- pDCB, pDCB->TargetID, pDCB->TargetLUN));
- return pDCB;
-}
-
-/* Insert SRB oin top of free list */
-static __inline__ void dc390_Free_insert (struct dc390_acb* pACB, struct dc390_srb* pSRB)
-{
- DEBUG0(printk ("DC390: Free SRB %p\n", pSRB));
- pSRB->pNextSRB = pACB->pFreeSRB;
- pACB->pFreeSRB = pSRB;
-}
-
-static __inline__ void dc390_Going_append (struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
-{
- pDCB->GoingSRBCnt++;
- DEBUG0(printk("DC390: Append SRB %p to Going\n", pSRB));
- /* Append to the list of Going commands */
- if( pDCB->pGoingSRB )
- pDCB->pGoingLast->pNextSRB = pSRB;
- else
- pDCB->pGoingSRB = pSRB;
-
- pDCB->pGoingLast = pSRB;
- /* No next one in sent list */
- pSRB->pNextSRB = NULL;
-}
-
-static __inline__ void dc390_Going_remove (struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
-{
- DEBUG0(printk("DC390: Remove SRB %p from Going\n", pSRB));
- if (pSRB == pDCB->pGoingSRB)
- pDCB->pGoingSRB = pSRB->pNextSRB;
- else
- {
- struct dc390_srb* psrb = pDCB->pGoingSRB;
- while (psrb && psrb->pNextSRB != pSRB)
- psrb = psrb->pNextSRB;
- if (!psrb)
- { printk (KERN_ERR "DC390: Remove non-ex. SRB %p from Going!\n", pSRB); return; }
- psrb->pNextSRB = pSRB->pNextSRB;
- if (pSRB == pDCB->pGoingLast)
- pDCB->pGoingLast = psrb;
- }
- pDCB->GoingSRBCnt--;
-}
-
-static struct scatterlist* dc390_sg_build_single(struct scatterlist *sg, void *addr, unsigned int length)
-{
- sg_init_one(sg, addr, length);
- return sg;
-}
-
-/* Create pci mapping */
-static int dc390_pci_map (struct dc390_srb* pSRB)
-{
- int error = 0;
- struct scsi_cmnd *pcmd = pSRB->pcmd;
- struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev;
- dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp));
-
- /* Map sense buffer */
- if (pSRB->SRBFlag & AUTO_REQSENSE) {
- pSRB->pSegmentList = dc390_sg_build_single(&pSRB->Segmentx, pcmd->sense_buffer, SCSI_SENSE_BUFFERSIZE);
- pSRB->SGcount = pci_map_sg(pdev, pSRB->pSegmentList, 1,
- DMA_FROM_DEVICE);
- cmdp->saved_dma_handle = sg_dma_address(pSRB->pSegmentList);
-
- /* TODO: error handling */
- if (pSRB->SGcount != 1)
- error = 1;
- DEBUG1(printk("%s(): Mapped sense buffer %p at %x\n", __func__, pcmd->sense_buffer, cmdp->saved_dma_handle));
- /* Map SG list */
- } else if (scsi_sg_count(pcmd)) {
- int nseg;
-
- nseg = scsi_dma_map(pcmd);
-
- pSRB->pSegmentList = scsi_sglist(pcmd);
- pSRB->SGcount = nseg;
-
- /* TODO: error handling */
- if (nseg < 0)
- error = 1;
- DEBUG1(printk("%s(): Mapped SG %p with %d (%d) elements\n",\
- __func__, scsi_sglist(pcmd), nseg, scsi_sg_count(pcmd)));
- /* Map single segment */
- } else
- pSRB->SGcount = 0;
-
- return error;
-}
-
-/* Remove pci mapping */
-static void dc390_pci_unmap (struct dc390_srb* pSRB)
-{
- struct scsi_cmnd *pcmd = pSRB->pcmd;
- struct pci_dev *pdev = pSRB->pSRBDCB->pDCBACB->pdev;
- DEBUG1(dc390_cmd_scp_t* cmdp = ((dc390_cmd_scp_t*)(&pcmd->SCp)));
-
- if (pSRB->SRBFlag) {
- pci_unmap_sg(pdev, &pSRB->Segmentx, 1, DMA_FROM_DEVICE);
- DEBUG1(printk("%s(): Unmapped sense buffer at %x\n", __func__, cmdp->saved_dma_handle));
- } else {
- scsi_dma_unmap(pcmd);
- DEBUG1(printk("%s(): Unmapped SG at %p with %d elements\n",
- __func__, scsi_sglist(pcmd), scsi_sg_count(pcmd)));
- }
-}
-
-static void __inline__
-dc390_freetag (struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
-{
- if (pSRB->TagNumber != SCSI_NO_TAG) {
- pDCB->TagMask &= ~(1 << pSRB->TagNumber); /* free tag mask */
- pSRB->TagNumber = SCSI_NO_TAG;
- }
-}
-
-
-static int
-dc390_StartSCSI( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB )
-{
- struct scsi_cmnd *scmd = pSRB->pcmd;
- struct scsi_device *sdev = scmd->device;
- u8 cmd, disc_allowed, try_sync_nego;
- char tag[2];
-
- pSRB->ScsiPhase = SCSI_NOP0;
-
- if (pACB->Connected)
- {
- // Should not happen normally
- printk (KERN_WARNING "DC390: Can't select when connected! (%08x,%02x)\n",
- pSRB->SRBState, pSRB->SRBFlag);
- pSRB->SRBState = SRB_READY;
- pACB->SelConn++;
- return 1;
- }
- if (time_before (jiffies, pACB->last_reset))
- {
- DEBUG0(printk ("DC390: We were just reset and don't accept commands yet!\n"));
- return 1;
- }
- /* KG: Moved pci mapping here */
- dc390_pci_map(pSRB);
- /* TODO: error handling */
- DC390_write8 (Scsi_Dest_ID, pDCB->TargetID);
- DC390_write8 (Sync_Period, pDCB->SyncPeriod);
- DC390_write8 (Sync_Offset, pDCB->SyncOffset);
- DC390_write8 (CtrlReg1, pDCB->CtrlR1);
- DC390_write8 (CtrlReg3, pDCB->CtrlR3);
- DC390_write8 (CtrlReg4, pDCB->CtrlR4);
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD); /* Flush FIFO */
- DEBUG1(printk (KERN_INFO "DC390: Start SCSI command: %02x (Sync:%02x)\n",\
- scmd->cmnd[0], pDCB->SyncMode));
-
- /* Don't disconnect on AUTO_REQSENSE, cause it might be an
- * Contingent Allegiance Condition (6.6), where no tags should be used.
- * All other have to be allowed to disconnect to prevent Incorrect
- * Initiator Connection (6.8.2/6.5.2) */
- /* Changed KG, 99/06/06 */
- if (! (pSRB->SRBFlag & AUTO_REQSENSE))
- disc_allowed = pDCB->DevMode & EN_DISCONNECT_;
- else
- disc_allowed = 0;
-
- if ((pDCB->SyncMode & SYNC_ENABLE) && pDCB->TargetLUN == 0 && sdev->sdtr &&
- (((scmd->cmnd[0] == REQUEST_SENSE || (pSRB->SRBFlag & AUTO_REQSENSE)) &&
- !(pDCB->SyncMode & SYNC_NEGO_DONE)) || scmd->cmnd[0] == INQUIRY))
- try_sync_nego = 1;
- else
- try_sync_nego = 0;
-
- pSRB->MsgCnt = 0;
- cmd = SEL_W_ATN;
- DC390_write8 (ScsiFifo, IDENTIFY(disc_allowed, pDCB->TargetLUN));
- /* Change 99/05/31: Don't use tags when not disconnecting (BUSY) */
- if ((pDCB->SyncMode & EN_TAG_QUEUEING) && disc_allowed && scsi_populate_tag_msg(scmd, tag)) {
- DC390_write8(ScsiFifo, tag[0]);
- pDCB->TagMask |= 1 << tag[1];
- pSRB->TagNumber = tag[1];
- DC390_write8(ScsiFifo, tag[1]);
- DEBUG1(printk(KERN_INFO "DC390: Select w/DisCn for SRB %p, block tag %02x\n", pSRB, tag[1]));
- cmd = SEL_W_ATN3;
- } else {
- /* No TagQ */
-//no_tag:
- DEBUG1(printk(KERN_INFO "DC390: Select w%s/DisCn for SRB %p, No TagQ\n", disc_allowed ? "" : "o", pSRB));
- }
-
- pSRB->SRBState = SRB_START_;
-
- if (try_sync_nego)
- {
- u8 Sync_Off = pDCB->SyncOffset;
- DEBUG0(printk (KERN_INFO "DC390: NEW Sync Nego code triggered (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN));
- pSRB->MsgOutBuf[0] = EXTENDED_MESSAGE;
- pSRB->MsgOutBuf[1] = 3;
- pSRB->MsgOutBuf[2] = EXTENDED_SDTR;
- pSRB->MsgOutBuf[3] = pDCB->NegoPeriod;
- if (!(Sync_Off & 0x0f)) Sync_Off = SYNC_NEGO_OFFSET;
- pSRB->MsgOutBuf[4] = Sync_Off;
- pSRB->MsgCnt = 5;
- //pSRB->SRBState = SRB_MSGOUT_;
- pSRB->SRBState |= DO_SYNC_NEGO;
- cmd = SEL_W_ATN_STOP;
- }
-
- /* Command is written in CommandPhase, if SEL_W_ATN_STOP ... */
- if (cmd != SEL_W_ATN_STOP)
- {
- if( pSRB->SRBFlag & AUTO_REQSENSE )
- {
- DC390_write8 (ScsiFifo, REQUEST_SENSE);
- DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
- DC390_write8 (ScsiFifo, 0);
- DC390_write8 (ScsiFifo, 0);
- DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
- DC390_write8 (ScsiFifo, 0);
- DEBUG1(printk (KERN_DEBUG "DC390: AutoReqSense !\n"));
- }
- else /* write cmnd to bus */
- {
- u8 *ptr; u8 i;
- ptr = (u8 *)scmd->cmnd;
- for (i = 0; i < scmd->cmd_len; i++)
- DC390_write8 (ScsiFifo, *(ptr++));
- }
- }
- DEBUG0(if (pACB->pActiveDCB) \
- printk (KERN_WARNING "DC390: ActiveDCB != 0\n"));
- DEBUG0(if (pDCB->pActiveSRB) \
- printk (KERN_WARNING "DC390: ActiveSRB != 0\n"));
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
- if (DC390_read8 (Scsi_Status) & INTERRUPT)
- {
- dc390_freetag (pDCB, pSRB);
- DEBUG0(printk ("DC390: Interrupt during Start SCSI (target %02i-%02i)\n",
- scmd->device->id, (u8)scmd->device->lun));
- pSRB->SRBState = SRB_READY;
- //DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- pACB->SelLost++;
- return 1;
- }
- DC390_write8 (ScsiCmd, cmd);
- pACB->pActiveDCB = pDCB;
- pDCB->pActiveSRB = pSRB;
- pACB->Connected = 1;
- pSRB->ScsiPhase = SCSI_NOP1;
- return 0;
-}
-
-
-static void __inline__
-dc390_InvalidCmd(struct dc390_acb* pACB)
-{
- if (pACB->pActiveDCB->pActiveSRB->SRBState & (SRB_START_ | SRB_MSGOUT))
- DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
-}
-
-
-static irqreturn_t __inline__
-DC390_Interrupt(void *dev_id)
-{
- struct dc390_acb *pACB = dev_id;
- struct dc390_dcb *pDCB;
- struct dc390_srb *pSRB;
- u8 sstatus=0;
- u8 phase;
- void (*stateV)( struct dc390_acb*, struct dc390_srb*, u8 *);
- u8 istate, istatus;
-
- sstatus = DC390_read8 (Scsi_Status);
- if( !(sstatus & INTERRUPT) )
- return IRQ_NONE;
-
- DEBUG1(printk (KERN_DEBUG "sstatus=%02x,", sstatus));
-
- //DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
- //dstatus = DC390_read8 (DMA_Status);
- //DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-
- spin_lock_irq(pACB->pScsiHost->host_lock);
-
- istate = DC390_read8 (Intern_State);
- istatus = DC390_read8 (INT_Status); /* This clears Scsi_Status, Intern_State and INT_Status ! */
-
- DEBUG1(printk (KERN_INFO "Istatus(Res,Inv,Dis,Serv,Succ,ReS,SelA,Sel)=%02x,",istatus));
- dc390_laststatus &= ~0x00ffffff;
- dc390_laststatus |= /* dstatus<<24 | */ sstatus<<16 | istate<<8 | istatus;
-
- if (sstatus & ILLEGAL_OP_ERR)
- {
- printk ("DC390: Illegal Operation detected (%08x)!\n", dc390_laststatus);
- dc390_dumpinfo (pACB, pACB->pActiveDCB, pACB->pActiveDCB->pActiveSRB);
- }
-
- else if (istatus & INVALID_CMD)
- {
- printk ("DC390: Invalid Command detected (%08x)!\n", dc390_laststatus);
- dc390_InvalidCmd( pACB );
- goto unlock;
- }
-
- if (istatus & SCSI_RESET)
- {
- dc390_ScsiRstDetect( pACB );
- goto unlock;
- }
-
- if (istatus & DISCONNECTED)
- {
- dc390_Disconnect( pACB );
- goto unlock;
- }
-
- if (istatus & RESELECTED)
- {
- dc390_Reselect( pACB );
- goto unlock;
- }
-
- else if (istatus & (SELECTED | SEL_ATTENTION))
- {
- printk (KERN_ERR "DC390: Target mode not supported!\n");
- goto unlock;
- }
-
- if (istatus & (SUCCESSFUL_OP|SERVICE_REQUEST) )
- {
- pDCB = pACB->pActiveDCB;
- if (!pDCB)
- {
- printk (KERN_ERR "DC390: Suc. op/ Serv. req: pActiveDCB = 0!\n");
- goto unlock;
- }
- pSRB = pDCB->pActiveSRB;
- if( pDCB->DCBFlag & ABORT_DEV_ )
- dc390_EnableMsgOut_Abort (pACB, pSRB);
-
- phase = pSRB->ScsiPhase;
- DEBUG1(printk (KERN_INFO "DC390: [%i]%s(0) (%02x)\n", phase, dc390_p0_str[phase], sstatus));
- stateV = (void *) dc390_phase0[phase];
- ( *stateV )( pACB, pSRB, &sstatus );
-
- pSRB->ScsiPhase = sstatus & 7;
- phase = (u8) sstatus & 7;
- DEBUG1(printk (KERN_INFO "DC390: [%i]%s(1) (%02x)\n", phase, dc390_p1_str[phase], sstatus));
- stateV = (void *) dc390_phase1[phase];
- ( *stateV )( pACB, pSRB, &sstatus );
- }
-
- unlock:
- spin_unlock_irq(pACB->pScsiHost->host_lock);
- return IRQ_HANDLED;
-}
-
-static irqreturn_t do_DC390_Interrupt(int irq, void *dev_id)
-{
- irqreturn_t ret;
- DEBUG1(printk (KERN_INFO "DC390: Irq (%i) caught: ", irq));
- /* Locking is done in DC390_Interrupt */
- ret = DC390_Interrupt(dev_id);
- DEBUG1(printk (".. IRQ returned\n"));
- return ret;
-}
-
-static void
-dc390_DataOut_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- u8 sstatus;
- u32 ResidCnt;
- u8 dstate = 0;
-
- sstatus = *psstatus;
-
- if( !(pSRB->SRBState & SRB_XFERPAD) )
- {
- if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR) )
- pSRB->SRBStatus |= PARITY_ERROR;
-
- if( sstatus & COUNT_2_ZERO )
- {
- unsigned long timeout = jiffies + HZ;
-
- /* Function called from the ISR with the host_lock held and interrupts disabled */
- if (pSRB->SGToBeXferLen)
- while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) {
- spin_unlock_irq(pACB->pScsiHost->host_lock);
- udelay(50);
- spin_lock_irq(pACB->pScsiHost->host_lock);
- }
- if (!time_before(jiffies, timeout))
- printk (KERN_CRIT "DC390: Deadlock in DataOut_0: DMA aborted unfinished: %06x bytes remain!!\n",
- DC390_read32 (DMA_Wk_ByteCntr));
- dc390_laststatus &= ~0xff000000;
- dc390_laststatus |= dstate << 24;
- pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
- pSRB->SGIndex++;
- if( pSRB->SGIndex < pSRB->SGcount )
- {
- pSRB->pSegmentList++;
-
- dc390_start_segment(pSRB);
- }
- else
- pSRB->SGToBeXferLen = 0;
- }
- else
- {
- ResidCnt = ((u32) DC390_read8 (Current_Fifo) & 0x1f) +
- (((u32) DC390_read8 (CtcReg_High) << 16) |
- ((u32) DC390_read8 (CtcReg_Mid) << 8) |
- (u32) DC390_read8 (CtcReg_Low));
-
- dc390_advance_segment(pSRB, ResidCnt);
- }
- }
- if ((*psstatus & 7) != SCSI_DATA_OUT)
- {
- DC390_write8 (DMA_Cmd, WRITE_DIRECTION+DMA_IDLE_CMD);
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- }
-}
-
-static void
-dc390_DataIn_0(struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- u8 sstatus, residual, bval;
- u32 ResidCnt, i;
- unsigned long xferCnt;
-
- sstatus = *psstatus;
-
- if( !(pSRB->SRBState & SRB_XFERPAD) )
- {
- if( sstatus & (PARITY_ERR | ILLEGAL_OP_ERR))
- pSRB->SRBStatus |= PARITY_ERROR;
-
- if( sstatus & COUNT_2_ZERO )
- {
- int dstate = 0;
- unsigned long timeout = jiffies + HZ;
-
- /* Function called from the ISR with the host_lock held and interrupts disabled */
- if (pSRB->SGToBeXferLen)
- while (time_before(jiffies, timeout) && !((dstate = DC390_read8 (DMA_Status)) & DMA_XFER_DONE)) {
- spin_unlock_irq(pACB->pScsiHost->host_lock);
- udelay(50);
- spin_lock_irq(pACB->pScsiHost->host_lock);
- }
- if (!time_before(jiffies, timeout)) {
- printk (KERN_CRIT "DC390: Deadlock in DataIn_0: DMA aborted unfinished: %06x bytes remain!!\n",
- DC390_read32 (DMA_Wk_ByteCntr));
- printk (KERN_CRIT "DC390: DataIn_0: DMA State: %i\n", dstate);
- }
- dc390_laststatus &= ~0xff000000;
- dc390_laststatus |= dstate << 24;
- DEBUG1(ResidCnt = ((unsigned long) DC390_read8 (CtcReg_High) << 16) \
- + ((unsigned long) DC390_read8 (CtcReg_Mid) << 8) \
- + ((unsigned long) DC390_read8 (CtcReg_Low)));
- DEBUG1(printk (KERN_DEBUG "Count_2_Zero (ResidCnt=%u,ToBeXfer=%lu),", ResidCnt, pSRB->SGToBeXferLen));
-
- DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
-
- pSRB->TotalXferredLen += pSRB->SGToBeXferLen;
- pSRB->SGIndex++;
- if( pSRB->SGIndex < pSRB->SGcount )
- {
- pSRB->pSegmentList++;
-
- dc390_start_segment(pSRB);
- }
- else
- pSRB->SGToBeXferLen = 0;
- }
- else /* phase changed */
- {
- residual = 0;
- bval = DC390_read8 (Current_Fifo);
- while( bval & 0x1f )
- {
- DEBUG1(printk (KERN_DEBUG "Check for residuals,"));
- if( (bval & 0x1f) == 1 )
- {
- for(i=0; i < 0x100; i++)
- {
- bval = DC390_read8 (Current_Fifo);
- if( !(bval & 0x1f) )
- goto din_1;
- else if( i == 0x0ff )
- {
- residual = 1; /* ;1 residual byte */
- goto din_1;
- }
- }
- }
- else
- bval = DC390_read8 (Current_Fifo);
- }
-din_1:
- DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_BLAST_CMD);
- for (i = 0xa000; i; i--)
- {
- bval = DC390_read8 (DMA_Status);
- if (bval & BLAST_COMPLETE)
- break;
- }
- /* It seems a DMA Blast abort isn't that bad ... */
- if (!i) printk (KERN_ERR "DC390: DMA Blast aborted unfinished!\n");
- //DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
- dc390_laststatus &= ~0xff000000;
- dc390_laststatus |= bval << 24;
-
- DEBUG1(printk (KERN_DEBUG "Blast: Read %i times DMA_Status %02x", 0xa000-i, bval));
- ResidCnt = (((u32) DC390_read8 (CtcReg_High) << 16) |
- ((u32) DC390_read8 (CtcReg_Mid) << 8)) |
- (u32) DC390_read8 (CtcReg_Low);
-
- xferCnt = dc390_advance_segment(pSRB, ResidCnt);
-
- if (residual) {
- size_t count = 1;
- size_t offset = pSRB->SGBusAddr - sg_dma_address(pSRB->pSegmentList);
- unsigned long flags;
- u8 *ptr;
-
- bval = DC390_read8 (ScsiFifo); /* get one residual byte */
-
- local_irq_save(flags);
- ptr = scsi_kmap_atomic_sg(pSRB->pSegmentList, pSRB->SGcount, &offset, &count);
- if (likely(ptr)) {
- *(ptr + offset) = bval;
- scsi_kunmap_atomic_sg(ptr);
- }
- local_irq_restore(flags);
- WARN_ON(!ptr);
-
- /* 1 more byte read */
- xferCnt += dc390_advance_segment(pSRB, pSRB->SGToBeXferLen - 1);
- }
- DEBUG1(printk (KERN_DEBUG "Xfered: %lu, Total: %lu, Remaining: %lu\n", xferCnt,\
- pSRB->TotalXferredLen, pSRB->SGToBeXferLen));
- }
- }
- if ((*psstatus & 7) != SCSI_DATA_IN)
- {
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- DC390_write8 (DMA_Cmd, READ_DIRECTION+DMA_IDLE_CMD);
- }
-}
-
-static void
-dc390_Command_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
-}
-
-static void
-dc390_Status_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
-
- pSRB->TargetStatus = DC390_read8 (ScsiFifo);
- //udelay (1);
- pSRB->EndMessage = DC390_read8 (ScsiFifo); /* get message */
-
- *psstatus = SCSI_NOP0;
- pSRB->SRBState = SRB_COMPLETED;
- DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
-}
-
-static void
-dc390_MsgOut_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- if( pSRB->SRBState & (SRB_UNEXPECT_RESEL+SRB_ABORT_SENT) )
- *psstatus = SCSI_NOP0;
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-}
-
-
-static void __inline__
-dc390_reprog (struct dc390_acb* pACB, struct dc390_dcb* pDCB)
-{
- DC390_write8 (Sync_Period, pDCB->SyncPeriod);
- DC390_write8 (Sync_Offset, pDCB->SyncOffset);
- DC390_write8 (CtrlReg3, pDCB->CtrlR3);
- DC390_write8 (CtrlReg4, pDCB->CtrlR4);
- dc390_SetXferRate (pACB, pDCB);
-}
-
-
-#ifdef DC390_DEBUG0
-static void
-dc390_printMsg (u8 *MsgBuf, u8 len)
-{
- int i;
- printk (" %02x", MsgBuf[0]);
- for (i = 1; i < len; i++)
- printk (" %02x", MsgBuf[i]);
- printk ("\n");
-}
-#endif
-
-#define DC390_ENABLE_MSGOUT DC390_write8 (ScsiCmd, SET_ATN_CMD)
-
-/* reject_msg */
-static void __inline__
-dc390_MsgIn_reject (struct dc390_acb* pACB, struct dc390_srb* pSRB)
-{
- pSRB->MsgOutBuf[0] = MESSAGE_REJECT;
- pSRB->MsgCnt = 1;
- DC390_ENABLE_MSGOUT;
- DEBUG0 (printk (KERN_INFO "DC390: Reject message\n"));
-}
-
-/* abort command */
-static void
-dc390_EnableMsgOut_Abort ( struct dc390_acb* pACB, struct dc390_srb* pSRB )
-{
- pSRB->MsgOutBuf[0] = ABORT;
- pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
- pSRB->pSRBDCB->DCBFlag &= ~ABORT_DEV_;
-}
-
-static struct dc390_srb*
-dc390_MsgIn_QTag (struct dc390_acb* pACB, struct dc390_dcb* pDCB, s8 tag)
-{
- struct dc390_srb* pSRB = pDCB->pGoingSRB;
-
- if (pSRB)
- {
- struct scsi_cmnd *scmd = scsi_find_tag(pSRB->pcmd->device, tag);
- pSRB = (struct dc390_srb *)scmd->host_scribble;
-
- if (pDCB->DCBFlag & ABORT_DEV_)
- {
- pSRB->SRBState = SRB_ABORT_SENT;
- dc390_EnableMsgOut_Abort( pACB, pSRB );
- }
-
- if (!(pSRB->SRBState & SRB_DISCONNECT))
- goto mingx0;
-
- pDCB->pActiveSRB = pSRB;
- pSRB->SRBState = SRB_DATA_XFER;
- }
- else
- {
- mingx0:
- pSRB = pACB->pTmpSRB;
- pSRB->SRBState = SRB_UNEXPECT_RESEL;
- pDCB->pActiveSRB = pSRB;
- pSRB->MsgOutBuf[0] = ABORT_TAG;
- pSRB->MsgCnt = 1; DC390_ENABLE_MSGOUT;
- }
- return pSRB;
-}
-
-
-/* set async transfer mode */
-static void
-dc390_MsgIn_set_async (struct dc390_acb* pACB, struct dc390_srb* pSRB)
-{
- struct dc390_dcb* pDCB = pSRB->pSRBDCB;
- if (!(pSRB->SRBState & DO_SYNC_NEGO))
- printk (KERN_INFO "DC390: Target %i initiates Non-Sync?\n", pDCB->TargetID);
- pSRB->SRBState &= ~DO_SYNC_NEGO;
- pDCB->SyncMode &= ~(SYNC_ENABLE+SYNC_NEGO_DONE);
- pDCB->SyncPeriod = 0;
- pDCB->SyncOffset = 0;
- //pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
- pDCB->CtrlR3 = FAST_CLK; /* fast clock / normal scsi */
- pDCB->CtrlR4 &= 0x3f;
- pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */
- dc390_reprog (pACB, pDCB);
-}
-
-/* set sync transfer mode */
-static void
-dc390_MsgIn_set_sync (struct dc390_acb* pACB, struct dc390_srb* pSRB)
-{
- u8 bval;
- u16 wval, wval1;
- struct dc390_dcb* pDCB = pSRB->pSRBDCB;
- u8 oldsyncperiod = pDCB->SyncPeriod;
- u8 oldsyncoffset = pDCB->SyncOffset;
-
- if (!(pSRB->SRBState & DO_SYNC_NEGO))
- {
- printk (KERN_INFO "DC390: Target %i initiates Sync: %ins %i ... answer ...\n",
- pDCB->TargetID, pSRB->MsgInBuf[3]<<2, pSRB->MsgInBuf[4]);
-
- /* reject */
- //dc390_MsgIn_reject (pACB, pSRB);
- //return dc390_MsgIn_set_async (pACB, pSRB);
-
- /* Reply with corrected SDTR Message */
- if (pSRB->MsgInBuf[4] > 15)
- {
- printk (KERN_INFO "DC390: Lower Sync Offset to 15\n");
- pSRB->MsgInBuf[4] = 15;
- }
- if (pSRB->MsgInBuf[3] < pDCB->NegoPeriod)
- {
- printk (KERN_INFO "DC390: Set sync nego period to %ins\n", pDCB->NegoPeriod << 2);
- pSRB->MsgInBuf[3] = pDCB->NegoPeriod;
- }
- memcpy (pSRB->MsgOutBuf, pSRB->MsgInBuf, 5);
- pSRB->MsgCnt = 5;
- DC390_ENABLE_MSGOUT;
- }
-
- pSRB->SRBState &= ~DO_SYNC_NEGO;
- pDCB->SyncMode |= SYNC_ENABLE+SYNC_NEGO_DONE;
- pDCB->SyncOffset &= 0x0f0;
- pDCB->SyncOffset |= pSRB->MsgInBuf[4];
- pDCB->NegoPeriod = pSRB->MsgInBuf[3];
-
- wval = (u16) pSRB->MsgInBuf[3];
- wval = wval << 2; wval -= 3; wval1 = wval / 25; /* compute speed */
- if( (wval1 * 25) != wval) wval1++;
- bval = FAST_CLK+FAST_SCSI; /* fast clock / fast scsi */
-
- pDCB->CtrlR4 &= 0x3f; /* Glitch eater: 12ns less than normal */
- if (pACB->glitch_cfg != NS_TO_GLITCH(0))
- pDCB->CtrlR4 |= NS_TO_GLITCH(((GLITCH_TO_NS(pACB->glitch_cfg)) - 1));
- else
- pDCB->CtrlR4 |= NS_TO_GLITCH(0);
- if (wval1 < 4) pDCB->CtrlR4 |= NS_TO_GLITCH(0); /* Ultra */
-
- if (wval1 >= 8)
- {
- wval1--; /* Timing computation differs by 1 from FAST_SCSI */
- bval = FAST_CLK; /* fast clock / normal scsi */
- pDCB->CtrlR4 |= pACB->glitch_cfg; /* glitch eater */
- }
-
- pDCB->CtrlR3 = bval;
- pDCB->SyncPeriod = (u8)wval1;
-
- if ((oldsyncperiod != wval1 || oldsyncoffset != pDCB->SyncOffset) && pDCB->TargetLUN == 0)
- {
- if (! (bval & FAST_SCSI)) wval1++;
- printk (KERN_INFO "DC390: Target %i: Sync transfer %i.%1i MHz, Offset %i\n", pDCB->TargetID,
- 40/wval1, ((40%wval1)*10+wval1/2)/wval1, pDCB->SyncOffset & 0x0f);
- }
-
- dc390_reprog (pACB, pDCB);
-}
-
-
-/* handle RESTORE_PTR */
-/* This doesn't look very healthy... to-be-fixed */
-static void
-dc390_restore_ptr (struct dc390_acb* pACB, struct dc390_srb* pSRB)
-{
- struct scsi_cmnd *pcmd = pSRB->pcmd;
- struct scatterlist *psgl;
- pSRB->TotalXferredLen = 0;
- pSRB->SGIndex = 0;
- if (scsi_sg_count(pcmd)) {
- size_t saved;
- pSRB->pSegmentList = scsi_sglist(pcmd);
- psgl = pSRB->pSegmentList;
- //dc390_pci_sync(pSRB);
-
- while (pSRB->TotalXferredLen + (unsigned long) sg_dma_len(psgl) < pSRB->Saved_Ptr)
- {
- pSRB->TotalXferredLen += (unsigned long) sg_dma_len(psgl);
- pSRB->SGIndex++;
- if( pSRB->SGIndex < pSRB->SGcount )
- {
- pSRB->pSegmentList++;
-
- dc390_start_segment(pSRB);
- }
- else
- pSRB->SGToBeXferLen = 0;
- }
-
- saved = pSRB->Saved_Ptr - pSRB->TotalXferredLen;
- pSRB->SGToBeXferLen -= saved;
- pSRB->SGBusAddr += saved;
- printk (KERN_INFO "DC390: Pointer restored. Segment %i, Total %li, Bus %08lx\n",
- pSRB->SGIndex, pSRB->Saved_Ptr, pSRB->SGBusAddr);
-
- } else {
- pSRB->SGcount = 0;
- printk (KERN_INFO "DC390: RESTORE_PTR message for Transfer without Scatter-Gather ??\n");
- }
-
- pSRB->TotalXferredLen = pSRB->Saved_Ptr;
-}
-
-
-/* According to the docs, the AM53C974 reads the message and
- * generates a Successful Operation IRQ before asserting ACK for
- * the last byte (how does it know whether it's the last ?) */
-/* The old code handled it in another way, indicating, that on
- * every message byte an IRQ is generated and every byte has to
- * be manually ACKed. Hmmm ? (KG, 98/11/28) */
-/* The old implementation was correct. Sigh! */
-
-/* Check if the message is complete */
-static u8 __inline__
-dc390_MsgIn_complete (u8 *msgbuf, u32 len)
-{
- if (*msgbuf == EXTENDED_MESSAGE)
- {
- if (len < 2) return 0;
- if (len < msgbuf[1] + 2) return 0;
- }
- else if (*msgbuf >= 0x20 && *msgbuf <= 0x2f) // two byte messages
- if (len < 2) return 0;
- return 1;
-}
-
-
-
-/* read and eval received messages */
-static void
-dc390_MsgIn_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- struct dc390_dcb* pDCB = pACB->pActiveDCB;
-
- /* Read the msg */
-
- pSRB->MsgInBuf[pACB->MsgLen++] = DC390_read8 (ScsiFifo);
- //pSRB->SRBState = 0;
-
- /* Msg complete ? */
- if (dc390_MsgIn_complete (pSRB->MsgInBuf, pACB->MsgLen))
- {
- DEBUG0 (printk (KERN_INFO "DC390: MsgIn:"); dc390_printMsg (pSRB->MsgInBuf, pACB->MsgLen));
- /* Now eval the msg */
- switch (pSRB->MsgInBuf[0])
- {
- case DISCONNECT:
- pSRB->SRBState = SRB_DISCONNECT; break;
-
- case SIMPLE_QUEUE_TAG:
- case HEAD_OF_QUEUE_TAG:
- case ORDERED_QUEUE_TAG:
- pSRB = dc390_MsgIn_QTag (pACB, pDCB, pSRB->MsgInBuf[1]);
- break;
-
- case MESSAGE_REJECT:
- DC390_write8 (ScsiCmd, RESET_ATN_CMD);
- pDCB->NegoPeriod = 50; /* 200ns <=> 5 MHz */
- if( pSRB->SRBState & DO_SYNC_NEGO)
- dc390_MsgIn_set_async (pACB, pSRB);
- break;
-
- case EXTENDED_MESSAGE:
- /* reject every extended msg but SDTR */
- if (pSRB->MsgInBuf[1] != 3 || pSRB->MsgInBuf[2] != EXTENDED_SDTR)
- dc390_MsgIn_reject (pACB, pSRB);
- else
- {
- if (pSRB->MsgInBuf[3] == 0 || pSRB->MsgInBuf[4] == 0)
- dc390_MsgIn_set_async (pACB, pSRB);
- else
- dc390_MsgIn_set_sync (pACB, pSRB);
- }
-
- // nothing has to be done
- case COMMAND_COMPLETE: break;
-
- // SAVE POINTER may be ignored as we have the struct dc390_srb* associated with the
- // scsi command. Thanks, Gerard, for pointing it out.
- case SAVE_POINTERS:
- pSRB->Saved_Ptr = pSRB->TotalXferredLen;
- break;
- // The device might want to restart transfer with a RESTORE
- case RESTORE_POINTERS:
- DEBUG0(printk ("DC390: RESTORE POINTER message received ... try to handle\n"));
- dc390_restore_ptr (pACB, pSRB);
- break;
-
- // reject unknown messages
- default: dc390_MsgIn_reject (pACB, pSRB);
- }
-
- /* Clear counter and MsgIn state */
- pSRB->SRBState &= ~SRB_MSGIN;
- pACB->MsgLen = 0;
- }
-
- *psstatus = SCSI_NOP0;
- DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD);
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-}
-
-
-static void
-dc390_DataIO_Comm( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 ioDir)
-{
- unsigned long lval;
- struct dc390_dcb* pDCB = pACB->pActiveDCB;
-
- if (pSRB == pACB->pTmpSRB)
- {
- if (pDCB)
- printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (%02i-%i)\n", pDCB->TargetID, pDCB->TargetLUN);
- else
- printk(KERN_ERR "DC390: pSRB == pTmpSRB! (TagQ Error?) (DCB 0!)\n");
-
- /* Try to recover - some broken disks react badly to tagged INQUIRY */
- if (pDCB && pACB->scan_devices && pDCB->GoingSRBCnt == 1) {
- pSRB = pDCB->pGoingSRB;
- pDCB->pActiveSRB = pSRB;
- } else {
- pSRB->pSRBDCB = pDCB;
- dc390_EnableMsgOut_Abort(pACB, pSRB);
- if (pDCB)
- pDCB->DCBFlag |= ABORT_DEV;
- return;
- }
- }
-
- if( pSRB->SGIndex < pSRB->SGcount )
- {
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
- if( !pSRB->SGToBeXferLen )
- {
- dc390_start_segment(pSRB);
-
- DEBUG1(printk (KERN_DEBUG " DC390: Next SG segment."));
- }
- lval = pSRB->SGToBeXferLen;
- DEBUG1(printk (KERN_DEBUG " DC390: Start transfer: %li bytes (address %08lx)\n", lval, pSRB->SGBusAddr));
- DC390_write8 (CtcReg_Low, (u8) lval);
- lval >>= 8;
- DC390_write8 (CtcReg_Mid, (u8) lval);
- lval >>= 8;
- DC390_write8 (CtcReg_High, (u8) lval);
-
- DC390_write32 (DMA_XferCnt, pSRB->SGToBeXferLen);
- DC390_write32 (DMA_XferAddr, pSRB->SGBusAddr);
-
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
- pSRB->SRBState = SRB_DATA_XFER;
-
- DC390_write8 (ScsiCmd, DMA_COMMAND+INFO_XFER_CMD);
-
- DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
- //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT));
- //DEBUG1(printk (KERN_DEBUG "DC390: DMA_Status: %02x\n", DC390_read8 (DMA_Status)));
- //DEBUG1(DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT));
- }
- else /* xfer pad */
- {
- if( pSRB->SGcount )
- {
- pSRB->AdaptStatus = H_OVER_UNDER_RUN;
- pSRB->SRBStatus |= OVER_RUN;
- DEBUG0(printk (KERN_WARNING " DC390: Overrun -"));
- }
- DEBUG0(printk (KERN_WARNING " Clear transfer pad \n"));
- DC390_write8 (CtcReg_Low, 0);
- DC390_write8 (CtcReg_Mid, 0);
- DC390_write8 (CtcReg_High, 0);
-
- pSRB->SRBState |= SRB_XFERPAD;
- DC390_write8 (ScsiCmd, DMA_COMMAND+XFER_PAD_BYTE);
-/*
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD | ioDir);
- DC390_write8 (DMA_Cmd, DMA_START_CMD | ioDir);
-*/
- }
-}
-
-
-static void
-dc390_DataOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- dc390_DataIO_Comm (pACB, pSRB, WRITE_DIRECTION);
-}
-
-static void
-dc390_DataInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- dc390_DataIO_Comm (pACB, pSRB, READ_DIRECTION);
-}
-
-static void
-dc390_CommandPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- struct dc390_dcb* pDCB;
- u8 i, cnt;
- u8 *ptr;
-
- DC390_write8 (ScsiCmd, RESET_ATN_CMD);
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- if( !(pSRB->SRBFlag & AUTO_REQSENSE) )
- {
- cnt = (u8) pSRB->pcmd->cmd_len;
- ptr = (u8 *) pSRB->pcmd->cmnd;
- for(i=0; i < cnt; i++)
- DC390_write8 (ScsiFifo, *(ptr++));
- }
- else
- {
- DC390_write8 (ScsiFifo, REQUEST_SENSE);
- pDCB = pACB->pActiveDCB;
- DC390_write8 (ScsiFifo, pDCB->TargetLUN << 5);
- DC390_write8 (ScsiFifo, 0);
- DC390_write8 (ScsiFifo, 0);
- DC390_write8 (ScsiFifo, SCSI_SENSE_BUFFERSIZE);
- DC390_write8 (ScsiFifo, 0);
- DEBUG0(printk(KERN_DEBUG "DC390: AutoReqSense (CmndPhase)!\n"));
- }
- pSRB->SRBState = SRB_COMMAND;
- DC390_write8 (ScsiCmd, INFO_XFER_CMD);
-}
-
-static void
-dc390_StatusPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- pSRB->SRBState = SRB_STATUS;
- DC390_write8 (ScsiCmd, INITIATOR_CMD_CMPLTE);
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-}
-
-static void
-dc390_MsgOutPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- u8 bval, i, cnt;
- u8 *ptr;
- struct dc390_dcb* pDCB;
-
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- pDCB = pACB->pActiveDCB;
- if( !(pSRB->SRBState & SRB_MSGOUT) )
- {
- cnt = pSRB->MsgCnt;
- if( cnt )
- {
- ptr = (u8 *) pSRB->MsgOutBuf;
- for(i=0; i < cnt; i++)
- DC390_write8 (ScsiFifo, *(ptr++));
- pSRB->MsgCnt = 0;
- if( (pDCB->DCBFlag & ABORT_DEV_) &&
- (pSRB->MsgOutBuf[0] == ABORT) )
- pSRB->SRBState = SRB_ABORT_SENT;
- }
- else
- {
- bval = ABORT; /* ??? MSG_NOP */
- if( (pSRB->pcmd->cmnd[0] == INQUIRY ) ||
- (pSRB->pcmd->cmnd[0] == REQUEST_SENSE) ||
- (pSRB->SRBFlag & AUTO_REQSENSE) )
- {
- if( pDCB->SyncMode & SYNC_ENABLE )
- goto mop1;
- }
- DC390_write8 (ScsiFifo, bval);
- }
- DC390_write8 (ScsiCmd, INFO_XFER_CMD);
- }
- else
- {
-mop1:
- printk (KERN_ERR "DC390: OLD Sync Nego code triggered! (%i %i)\n", pDCB->TargetID, pDCB->TargetLUN);
- DC390_write8 (ScsiFifo, EXTENDED_MESSAGE);
- DC390_write8 (ScsiFifo, 3); /* ;length of extended msg */
- DC390_write8 (ScsiFifo, EXTENDED_SDTR); /* ; sync nego */
- DC390_write8 (ScsiFifo, pDCB->NegoPeriod);
- if (pDCB->SyncOffset & 0x0f)
- DC390_write8 (ScsiFifo, pDCB->SyncOffset);
- else
- DC390_write8 (ScsiFifo, SYNC_NEGO_OFFSET);
- pSRB->SRBState |= DO_SYNC_NEGO;
- DC390_write8 (ScsiCmd, INFO_XFER_CMD);
- }
-}
-
-static void
-dc390_MsgInPhase( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- if( !(pSRB->SRBState & SRB_MSGIN) )
- {
- pSRB->SRBState &= ~SRB_DISCONNECT;
- pSRB->SRBState |= SRB_MSGIN;
- }
- DC390_write8 (ScsiCmd, INFO_XFER_CMD);
- //DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
-}
-
-static void
-dc390_Nop_0( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
-}
-
-static void
-dc390_Nop_1( struct dc390_acb* pACB, struct dc390_srb* pSRB, u8 *psstatus)
-{
-}
-
-
-static void
-dc390_SetXferRate( struct dc390_acb* pACB, struct dc390_dcb* pDCB )
-{
- u8 bval, i, cnt;
- struct dc390_dcb* ptr;
-
- if( !(pDCB->TargetLUN) )
- {
- if( !pACB->scan_devices )
- {
- ptr = pACB->pLinkDCB;
- cnt = pACB->DCBCnt;
- bval = pDCB->TargetID;
- for(i=0; i<cnt; i++)
- {
- if( ptr->TargetID == bval )
- {
- ptr->SyncPeriod = pDCB->SyncPeriod;
- ptr->SyncOffset = pDCB->SyncOffset;
- ptr->CtrlR3 = pDCB->CtrlR3;
- ptr->CtrlR4 = pDCB->CtrlR4;
- ptr->SyncMode = pDCB->SyncMode;
- }
- ptr = ptr->pNextDCB;
- }
- }
- }
- return;
-}
-
-
-static void
-dc390_Disconnect( struct dc390_acb* pACB )
-{
- struct dc390_dcb *pDCB;
- struct dc390_srb *pSRB, *psrb;
- u8 i, cnt;
-
- DEBUG0(printk(KERN_INFO "DISC,"));
-
- if (!pACB->Connected) printk(KERN_ERR "DC390: Disconnect not-connected bus?\n");
- pACB->Connected = 0;
- pDCB = pACB->pActiveDCB;
- if (!pDCB)
- {
- DEBUG0(printk(KERN_ERR "ACB:%p->ActiveDCB:%p IOPort:%04x IRQ:%02x !\n",\
- pACB, pDCB, pACB->IOPortBase, pACB->IRQLevel));
- mdelay(400);
- DC390_read8 (INT_Status); /* Reset Pending INT */
- DC390_write8 (ScsiCmd, EN_SEL_RESEL);
- return;
- }
- DC390_write8 (ScsiCmd, EN_SEL_RESEL);
- pSRB = pDCB->pActiveSRB;
- pACB->pActiveDCB = NULL;
- pSRB->ScsiPhase = SCSI_NOP0;
- if( pSRB->SRBState & SRB_UNEXPECT_RESEL )
- pSRB->SRBState = 0;
- else if( pSRB->SRBState & SRB_ABORT_SENT )
- {
- pDCB->TagMask = 0;
- pDCB->DCBFlag = 0;
- cnt = pDCB->GoingSRBCnt;
- pDCB->GoingSRBCnt = 0;
- pSRB = pDCB->pGoingSRB;
- for( i=0; i < cnt; i++)
- {
- psrb = pSRB->pNextSRB;
- dc390_Free_insert (pACB, pSRB);
- pSRB = psrb;
- }
- pDCB->pGoingSRB = NULL;
- }
- else
- {
- if( (pSRB->SRBState & (SRB_START_+SRB_MSGOUT)) ||
- !(pSRB->SRBState & (SRB_DISCONNECT+SRB_COMPLETED)) )
- { /* Selection time out */
- pSRB->AdaptStatus = H_SEL_TIMEOUT;
- pSRB->TargetStatus = 0;
- goto disc1;
- }
- else if (!(pSRB->SRBState & SRB_DISCONNECT) && (pSRB->SRBState & SRB_COMPLETED))
- {
-disc1:
- dc390_freetag (pDCB, pSRB);
- pDCB->pActiveSRB = NULL;
- pSRB->SRBState = SRB_FREE;
- dc390_SRBdone( pACB, pDCB, pSRB);
- }
- }
- pACB->MsgLen = 0;
-}
-
-
-static void
-dc390_Reselect( struct dc390_acb* pACB )
-{
- struct dc390_dcb* pDCB;
- struct dc390_srb* pSRB;
- u8 id, lun;
-
- DEBUG0(printk(KERN_INFO "RSEL,"));
- pACB->Connected = 1;
- pDCB = pACB->pActiveDCB;
- if( pDCB )
- { /* Arbitration lost but Reselection won */
- DEBUG0(printk ("DC390: (ActiveDCB != 0: Arb. lost but resel. won)!\n"));
- pSRB = pDCB->pActiveSRB;
- if( !( pACB->scan_devices ) )
- {
- struct scsi_cmnd *pcmd = pSRB->pcmd;
- scsi_set_resid(pcmd, scsi_bufflen(pcmd));
- SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
- dc390_Going_remove(pDCB, pSRB);
- dc390_Free_insert(pACB, pSRB);
- pcmd->scsi_done (pcmd);
- DEBUG0(printk(KERN_DEBUG"DC390: Return SRB %p to free\n", pSRB));
- }
- }
- /* Get ID */
- lun = DC390_read8 (ScsiFifo);
- DEBUG0(printk ("Dev %02x,", lun));
- if (!(lun & (1 << pACB->pScsiHost->this_id)))
- printk (KERN_ERR "DC390: Reselection must select host adapter: %02x!\n", lun);
- else
- lun ^= 1 << pACB->pScsiHost->this_id; /* Mask AdapterID */
- id = 0; while (lun >>= 1) id++;
- /* Get LUN */
- lun = DC390_read8 (ScsiFifo);
- if (!(lun & IDENTIFY_BASE)) printk (KERN_ERR "DC390: Resel: Expect identify message!\n");
- lun &= 7;
- DEBUG0(printk ("(%02i-%i),", id, lun));
- pDCB = dc390_findDCB (pACB, id, lun);
- if (!pDCB)
- {
- printk (KERN_ERR "DC390: Reselect from non existing device (%02i-%i)\n",
- id, lun);
- return;
- }
- pACB->pActiveDCB = pDCB;
- /* TagQ: We expect a message soon, so never mind the exact SRB */
- if( pDCB->SyncMode & EN_TAG_QUEUEING )
- {
- pSRB = pACB->pTmpSRB;
- pDCB->pActiveSRB = pSRB;
- }
- else
- {
- pSRB = pDCB->pActiveSRB;
- if( !pSRB || !(pSRB->SRBState & SRB_DISCONNECT) )
- {
- pSRB= pACB->pTmpSRB;
- pSRB->SRBState = SRB_UNEXPECT_RESEL;
- printk (KERN_ERR "DC390: Reselect without outstanding cmnd (%02i-%i)\n",
- id, lun);
- pDCB->pActiveSRB = pSRB;
- dc390_EnableMsgOut_Abort ( pACB, pSRB );
- }
- else
- {
- if( pDCB->DCBFlag & ABORT_DEV_ )
- {
- pSRB->SRBState = SRB_ABORT_SENT;
- printk (KERN_INFO "DC390: Reselect: Abort (%02i-%i)\n",
- id, lun);
- dc390_EnableMsgOut_Abort( pACB, pSRB );
- }
- else
- pSRB->SRBState = SRB_DATA_XFER;
- }
- }
-
- DEBUG1(printk (KERN_DEBUG "Resel SRB(%p): TagNum (%02x)\n", pSRB, pSRB->TagNumber));
- pSRB->ScsiPhase = SCSI_NOP0;
- DC390_write8 (Scsi_Dest_ID, pDCB->TargetID);
- DC390_write8 (Sync_Period, pDCB->SyncPeriod);
- DC390_write8 (Sync_Offset, pDCB->SyncOffset);
- DC390_write8 (CtrlReg1, pDCB->CtrlR1);
- DC390_write8 (CtrlReg3, pDCB->CtrlR3);
- DC390_write8 (CtrlReg4, pDCB->CtrlR4); /* ; Glitch eater */
- DC390_write8 (ScsiCmd, MSG_ACCEPTED_CMD); /* ;to release the /ACK signal */
-}
-
-static int __inline__
-dc390_RequestSense(struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
-{
- struct scsi_cmnd *pcmd;
-
- pcmd = pSRB->pcmd;
-
- REMOVABLEDEBUG(printk(KERN_INFO "DC390: RequestSense(Cmd %02x, Id %02x, LUN %02x)\n",\
- pcmd->cmnd[0], pDCB->TargetID, pDCB->TargetLUN));
-
- pSRB->SRBFlag |= AUTO_REQSENSE;
- pSRB->SavedTotXLen = pSRB->TotalXferredLen;
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0; /* CHECK_CONDITION<<1; */
-
- /* We are called from SRBdone, original PCI mapping has been removed
- * already, new one is set up from StartSCSI */
- pSRB->SGIndex = 0;
-
- pSRB->TotalXferredLen = 0;
- pSRB->SGToBeXferLen = 0;
- return dc390_StartSCSI(pACB, pDCB, pSRB);
-}
-
-
-static void
-dc390_SRBdone( struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB )
-{
- u8 status;
- struct scsi_cmnd *pcmd;
-
- pcmd = pSRB->pcmd;
- /* KG: Moved pci_unmap here */
- dc390_pci_unmap(pSRB);
-
- status = pSRB->TargetStatus;
-
- DEBUG0(printk (" SRBdone (%02x,%08x), SRB %p\n", status, pcmd->result, pSRB));
- if(pSRB->SRBFlag & AUTO_REQSENSE)
- { /* Last command was a Request Sense */
- pSRB->SRBFlag &= ~AUTO_REQSENSE;
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = SAM_STAT_CHECK_CONDITION;
-
- //pcmd->result = MK_RES(DRIVER_SENSE,DID_OK,0,status);
- if (status == SAM_STAT_CHECK_CONDITION)
- pcmd->result = MK_RES_LNX(0, DID_BAD_TARGET, 0, /*CHECK_CONDITION*/0);
- else /* Retry */
- {
- if( pSRB->pcmd->cmnd[0] == TEST_UNIT_READY /* || pSRB->pcmd->cmnd[0] == START_STOP */)
- {
- /* Don't retry on TEST_UNIT_READY */
- pcmd->result = MK_RES_LNX(DRIVER_SENSE, DID_OK, 0, SAM_STAT_CHECK_CONDITION);
- REMOVABLEDEBUG(printk(KERN_INFO "Cmd=%02x, Result=%08x, XferL=%08x\n",pSRB->pcmd->cmnd[0],\
- (u32) pcmd->result, (u32) pSRB->TotalXferredLen));
- } else {
- SET_RES_DRV(pcmd->result, DRIVER_SENSE);
- //pSRB->ScsiCmdLen = (u8) (pSRB->Segment1[0] >> 8);
- DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, (u8)pcmd->device->lun));
- pSRB->TotalXferredLen = 0;
- SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
- }
- }
- goto cmd_done;
- }
- if( status )
- {
- if (status == SAM_STAT_CHECK_CONDITION)
- {
- if (dc390_RequestSense(pACB, pDCB, pSRB)) {
- SET_RES_DID(pcmd->result, DID_ERROR);
- goto cmd_done;
- }
- return;
- }
- else if (status == SAM_STAT_TASK_SET_FULL)
- {
- scsi_track_queue_full(pcmd->device, pDCB->GoingSRBCnt - 1);
- DEBUG0 (printk ("DC390: RETRY (%02x), target %02i-%02i\n", pcmd->cmnd[0], pcmd->device->id, (u8)pcmd->device->lun));
- pSRB->TotalXferredLen = 0;
- SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
- }
- else if (status == SAM_STAT_BUSY &&
- (pcmd->cmnd[0] == TEST_UNIT_READY || pcmd->cmnd[0] == INQUIRY) &&
- pACB->scan_devices)
- {
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = status;
- pcmd->result = MK_RES(0,0,pSRB->EndMessage,/*status*/0);
- }
- else
- { /* Another error */
- pSRB->TotalXferredLen = 0;
- SET_RES_DID(pcmd->result, DID_SOFT_ERROR);
- goto cmd_done;
- }
- }
- else
- { /* Target status == 0 */
- status = pSRB->AdaptStatus;
- if (status == H_OVER_UNDER_RUN)
- {
- pSRB->TargetStatus = 0;
- SET_RES_DID(pcmd->result,DID_OK);
- SET_RES_MSG(pcmd->result,pSRB->EndMessage);
- }
- else if (status == H_SEL_TIMEOUT)
- {
- pcmd->result = MK_RES(0, DID_NO_CONNECT, 0, 0);
- /* Devices are removed below ... */
- }
- else if( pSRB->SRBStatus & PARITY_ERROR)
- {
- //pcmd->result = MK_RES(0,DID_PARITY,pSRB->EndMessage,0);
- SET_RES_DID(pcmd->result,DID_PARITY);
- SET_RES_MSG(pcmd->result,pSRB->EndMessage);
- }
- else /* No error */
- {
- pSRB->AdaptStatus = 0;
- pSRB->TargetStatus = 0;
- SET_RES_DID(pcmd->result,DID_OK);
- }
- }
-
-cmd_done:
- scsi_set_resid(pcmd, scsi_bufflen(pcmd) - pSRB->TotalXferredLen);
-
- dc390_Going_remove (pDCB, pSRB);
- /* Add to free list */
- dc390_Free_insert (pACB, pSRB);
-
- DEBUG0(printk (KERN_DEBUG "DC390: SRBdone: done\n"));
- pcmd->scsi_done (pcmd);
-
- return;
-}
-
-
-/* Remove all SRBs from Going list and inform midlevel */
-static void
-dc390_DoingSRB_Done(struct dc390_acb* pACB, struct scsi_cmnd *cmd)
-{
- struct dc390_dcb *pDCB, *pdcb;
- struct dc390_srb *psrb, *psrb2;
- int i;
- struct scsi_cmnd *pcmd;
-
- pDCB = pACB->pLinkDCB;
- pdcb = pDCB;
- if (! pdcb) return;
- do
- {
- psrb = pdcb->pGoingSRB;
- for (i = 0; i < pdcb->GoingSRBCnt; i++)
- {
- psrb2 = psrb->pNextSRB;
- pcmd = psrb->pcmd;
- dc390_Free_insert (pACB, psrb);
- psrb = psrb2;
- }
- pdcb->GoingSRBCnt = 0;
- pdcb->pGoingSRB = NULL;
- pdcb->TagMask = 0;
- pdcb = pdcb->pNextDCB;
- } while( pdcb != pDCB );
-}
-
-
-static void
-dc390_ResetSCSIBus( struct dc390_acb* pACB )
-{
- //DC390_write8 (ScsiCmd, RST_DEVICE_CMD);
- //udelay (250);
- //DC390_write8 (ScsiCmd, NOP_CMD);
-
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
- DC390_write8 (ScsiCmd, RST_SCSI_BUS_CMD);
- pACB->Connected = 0;
-
- return;
-}
-
-static void
-dc390_ScsiRstDetect( struct dc390_acb* pACB )
-{
- printk ("DC390: Rst_Detect: laststat = %08x\n", dc390_laststatus);
- //DEBUG0(printk(KERN_INFO "RST_DETECT,"));
-
- DC390_write8 (DMA_Cmd, DMA_IDLE_CMD);
- /* Unlock before ? */
- /* delay half a second */
- udelay (1000);
- DC390_write8 (ScsiCmd, CLEAR_FIFO_CMD);
- pACB->last_reset = jiffies + 5*HZ/2
- + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
- pACB->Connected = 0;
-
- if( pACB->ACBFlag & RESET_DEV )
- pACB->ACBFlag |= RESET_DONE;
- else
- { /* Reset was issued by sb else */
- pACB->ACBFlag |= RESET_DETECT;
-
- dc390_ResetDevParam( pACB );
- dc390_DoingSRB_Done( pACB, NULL);
- //dc390_RecoverSRB( pACB );
- pACB->pActiveDCB = NULL;
- pACB->ACBFlag = 0;
- }
- return;
-}
-
-static int DC390_queuecommand_lck(struct scsi_cmnd *cmd,
- void (*done)(struct scsi_cmnd *))
-{
- struct scsi_device *sdev = cmd->device;
- struct dc390_acb *acb = (struct dc390_acb *)sdev->host->hostdata;
- struct dc390_dcb *dcb = sdev->hostdata;
- struct dc390_srb *srb;
-
- if (sdev->queue_depth <= dcb->GoingSRBCnt)
- goto device_busy;
- if (acb->pActiveDCB)
- goto host_busy;
- if (acb->ACBFlag & (RESET_DETECT|RESET_DONE|RESET_DEV))
- goto host_busy;
-
- srb = acb->pFreeSRB;
- if (unlikely(srb == NULL))
- goto host_busy;
-
- cmd->scsi_done = done;
- cmd->result = 0;
- acb->Cmds++;
-
- acb->pFreeSRB = srb->pNextSRB;
- srb->pNextSRB = NULL;
-
- srb->pSRBDCB = dcb;
- srb->pcmd = cmd;
- cmd->host_scribble = (char *)srb;
-
- srb->SGIndex = 0;
- srb->AdaptStatus = 0;
- srb->TargetStatus = 0;
- srb->MsgCnt = 0;
-
- srb->SRBStatus = 0;
- srb->SRBFlag = 0;
- srb->SRBState = 0;
- srb->TotalXferredLen = 0;
- srb->SGBusAddr = 0;
- srb->SGToBeXferLen = 0;
- srb->ScsiPhase = 0;
- srb->EndMessage = 0;
- srb->TagNumber = SCSI_NO_TAG;
-
- if (dc390_StartSCSI(acb, dcb, srb)) {
- dc390_Free_insert(acb, srb);
- goto host_busy;
- }
-
- dc390_Going_append(dcb, srb);
-
- return 0;
-
- host_busy:
- return SCSI_MLQUEUE_HOST_BUSY;
-
- device_busy:
- return SCSI_MLQUEUE_DEVICE_BUSY;
-}
-
-static DEF_SCSI_QCMD(DC390_queuecommand)
-
-static void dc390_dumpinfo (struct dc390_acb* pACB, struct dc390_dcb* pDCB, struct dc390_srb* pSRB)
-{
- struct pci_dev *pdev;
- u16 pstat;
-
- if (!pDCB) pDCB = pACB->pActiveDCB;
- if (!pSRB && pDCB) pSRB = pDCB->pActiveSRB;
-
- if (pSRB)
- {
- printk ("DC390: SRB: Xferred %08lx, Remain %08lx, State %08x, Phase %02x\n",
- pSRB->TotalXferredLen, pSRB->SGToBeXferLen, pSRB->SRBState,
- pSRB->ScsiPhase);
- printk ("DC390: AdpaterStatus: %02x, SRB Status %02x\n", pSRB->AdaptStatus, pSRB->SRBStatus);
- }
- printk ("DC390: Status of last IRQ (DMA/SC/Int/IRQ): %08x\n", dc390_laststatus);
- printk ("DC390: Register dump: SCSI block:\n");
- printk ("DC390: XferCnt Cmd Stat IntS IRQS FFIS Ctl1 Ctl2 Ctl3 Ctl4\n");
- printk ("DC390: %06x %02x %02x %02x",
- DC390_read8(CtcReg_Low) + (DC390_read8(CtcReg_Mid) << 8) + (DC390_read8(CtcReg_High) << 16),
- DC390_read8(ScsiCmd), DC390_read8(Scsi_Status), DC390_read8(Intern_State));
- printk (" %02x %02x %02x %02x %02x %02x\n",
- DC390_read8(INT_Status), DC390_read8(Current_Fifo), DC390_read8(CtrlReg1),
- DC390_read8(CtrlReg2), DC390_read8(CtrlReg3), DC390_read8(CtrlReg4));
- DC390_write32 (DMA_ScsiBusCtrl, WRT_ERASE_DMA_STAT | EN_INT_ON_PCI_ABORT);
- if (DC390_read8(Current_Fifo) & 0x1f)
- {
- printk ("DC390: FIFO:");
- while (DC390_read8(Current_Fifo) & 0x1f) printk (" %02x", DC390_read8(ScsiFifo));
- printk ("\n");
- }
- printk ("DC390: Register dump: DMA engine:\n");
- printk ("DC390: Cmd STrCnt SBusA WrkBC WrkAC Stat SBusCtrl\n");
- printk ("DC390: %02x %08x %08x %08x %08x %02x %08x\n",
- DC390_read8(DMA_Cmd), DC390_read32(DMA_XferCnt), DC390_read32(DMA_XferAddr),
- DC390_read32(DMA_Wk_ByteCntr), DC390_read32(DMA_Wk_AddrCntr),
- DC390_read8(DMA_Status), DC390_read32(DMA_ScsiBusCtrl));
- DC390_write32 (DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-
- pdev = pACB->pdev;
- pci_read_config_word(pdev, PCI_STATUS, &pstat);
- printk ("DC390: Register dump: PCI Status: %04x\n", pstat);
- printk ("DC390: In case of driver trouble read Documentation/scsi/tmscsim.txt\n");
-}
-
-
-static int DC390_abort(struct scsi_cmnd *cmd)
-{
- struct dc390_acb *pACB = (struct dc390_acb*) cmd->device->host->hostdata;
- struct dc390_dcb *pDCB = (struct dc390_dcb*) cmd->device->hostdata;
-
- scmd_printk(KERN_WARNING, cmd, "DC390: Abort command\n");
-
- /* abort() is too stupid for already sent commands at the moment.
- * If it's called we are in trouble anyway, so let's dump some info
- * into the syslog at least. (KG, 98/08/20,99/06/20) */
- dc390_dumpinfo(pACB, pDCB, NULL);
-
- pDCB->DCBFlag |= ABORT_DEV_;
- printk(KERN_INFO "DC390: Aborted.\n");
-
- return FAILED;
-}
-
-
-static void dc390_ResetDevParam( struct dc390_acb* pACB )
-{
- struct dc390_dcb *pDCB, *pdcb;
-
- pDCB = pACB->pLinkDCB;
- if (! pDCB) return;
- pdcb = pDCB;
- do
- {
- pDCB->SyncMode &= ~SYNC_NEGO_DONE;
- pDCB->SyncPeriod = 0;
- pDCB->SyncOffset = 0;
- pDCB->TagMask = 0;
- pDCB->CtrlR3 = FAST_CLK;
- pDCB->CtrlR4 &= NEGATE_REQACKDATA | CTRL4_RESERVED | NEGATE_REQACK;
- pDCB->CtrlR4 |= pACB->glitch_cfg;
- pDCB = pDCB->pNextDCB;
- }
- while( pdcb != pDCB );
- pACB->ACBFlag &= ~(RESET_DEV | RESET_DONE | RESET_DETECT);
-
-}
-
-static int DC390_bus_reset (struct scsi_cmnd *cmd)
-{
- struct dc390_acb* pACB = (struct dc390_acb*) cmd->device->host->hostdata;
- u8 bval;
-
- spin_lock_irq(cmd->device->host->host_lock);
-
- bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST;
- DC390_write8(CtrlReg1, bval); /* disable IRQ on bus reset */
-
- pACB->ACBFlag |= RESET_DEV;
- dc390_ResetSCSIBus(pACB);
-
- dc390_ResetDevParam(pACB);
- mdelay(1);
- pACB->last_reset = jiffies + 3*HZ/2
- + HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
-
- DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
- DC390_read8(INT_Status); /* Reset Pending INT */
-
- dc390_DoingSRB_Done(pACB, cmd);
-
- pACB->pActiveDCB = NULL;
- pACB->ACBFlag = 0;
-
- bval = DC390_read8(CtrlReg1) & ~DIS_INT_ON_SCSI_RST;
- DC390_write8(CtrlReg1, bval); /* re-enable interrupt */
-
- spin_unlock_irq(cmd->device->host->host_lock);
-
- return SUCCESS;
-}
-
-/**
- * dc390_slave_alloc - Called by the scsi mid layer to tell us about a new
- * scsi device that we need to deal with.
- *
- * @scsi_device: The new scsi device that we need to handle.
- */
-static int dc390_slave_alloc(struct scsi_device *scsi_device)
-{
- struct dc390_acb *pACB = (struct dc390_acb*) scsi_device->host->hostdata;
- struct dc390_dcb *pDCB, *pDCB2 = NULL;
- uint id = scsi_device->id;
- uint lun = scsi_device->lun;
-
- pDCB = kzalloc(sizeof(struct dc390_dcb), GFP_KERNEL);
- if (!pDCB)
- return -ENOMEM;
-
- if (!pACB->DCBCnt++) {
- pACB->pLinkDCB = pDCB;
- pACB->pDCBRunRobin = pDCB;
- } else {
- pACB->pLastDCB->pNextDCB = pDCB;
- }
-
- pDCB->pNextDCB = pACB->pLinkDCB;
- pACB->pLastDCB = pDCB;
-
- pDCB->pDCBACB = pACB;
- pDCB->TargetID = id;
- pDCB->TargetLUN = lun;
-
- /*
- * Some values are for all LUNs: Copy them
- * In a clean way: We would have an own structure for a SCSI-ID
- */
- if (lun && (pDCB2 = dc390_findDCB(pACB, id, 0))) {
- pDCB->DevMode = pDCB2->DevMode;
- pDCB->SyncMode = pDCB2->SyncMode & SYNC_NEGO_DONE;
- pDCB->SyncPeriod = pDCB2->SyncPeriod;
- pDCB->SyncOffset = pDCB2->SyncOffset;
- pDCB->NegoPeriod = pDCB2->NegoPeriod;
-
- pDCB->CtrlR3 = pDCB2->CtrlR3;
- pDCB->CtrlR4 = pDCB2->CtrlR4;
- } else {
- u8 index = pACB->AdapterIndex;
- PEEprom prom = (PEEprom) &dc390_eepromBuf[index][id << 2];
-
- pDCB->DevMode = prom->EE_MODE1;
- pDCB->NegoPeriod =
- (dc390_clock_period1[prom->EE_SPEED] * 25) >> 2;
- pDCB->CtrlR3 = FAST_CLK;
- pDCB->CtrlR4 = pACB->glitch_cfg | CTRL4_RESERVED;
- if (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION)
- pDCB->CtrlR4 |= NEGATE_REQACKDATA | NEGATE_REQACK;
- }
-
- if (pDCB->DevMode & SYNC_NEGO_)
- pDCB->SyncMode |= SYNC_ENABLE;
- else {
- pDCB->SyncMode = 0;
- pDCB->SyncOffset &= ~0x0f;
- }
-
- pDCB->CtrlR1 = pACB->pScsiHost->this_id;
- if (pDCB->DevMode & PARITY_CHK_)
- pDCB->CtrlR1 |= PARITY_ERR_REPO;
-
- pACB->scan_devices = 1;
- scsi_device->hostdata = pDCB;
- return 0;
-}
-
-/**
- * dc390_slave_destroy - Called by the scsi mid layer to tell us about a
- * device that is going away.
- *
- * @scsi_device: The scsi device that we need to remove.
- */
-static void dc390_slave_destroy(struct scsi_device *scsi_device)
-{
- struct dc390_acb* pACB = (struct dc390_acb*) scsi_device->host->hostdata;
- struct dc390_dcb* pDCB = (struct dc390_dcb*) scsi_device->hostdata;
- struct dc390_dcb* pPrevDCB = pACB->pLinkDCB;
-
- pACB->scan_devices = 0;
-
- BUG_ON(pDCB->GoingSRBCnt > 1);
-
- if (pDCB == pACB->pLinkDCB) {
- if (pACB->pLastDCB == pDCB) {
- pDCB->pNextDCB = NULL;
- pACB->pLastDCB = NULL;
- }
- pACB->pLinkDCB = pDCB->pNextDCB;
- } else {
- while (pPrevDCB->pNextDCB != pDCB)
- pPrevDCB = pPrevDCB->pNextDCB;
- pPrevDCB->pNextDCB = pDCB->pNextDCB;
- if (pDCB == pACB->pLastDCB)
- pACB->pLastDCB = pPrevDCB;
- }
-
- if (pDCB == pACB->pActiveDCB)
- pACB->pActiveDCB = NULL;
- if (pDCB == pACB->pLinkDCB)
- pACB->pLinkDCB = pDCB->pNextDCB;
- if (pDCB == pACB->pDCBRunRobin)
- pACB->pDCBRunRobin = pDCB->pNextDCB;
- kfree(pDCB);
-
- pACB->DCBCnt--;
-}
-
-static int dc390_slave_configure(struct scsi_device *sdev)
-{
- struct dc390_acb *acb = (struct dc390_acb *)sdev->host->hostdata;
- struct dc390_dcb *dcb = (struct dc390_dcb *)sdev->hostdata;
-
- acb->scan_devices = 0;
- if (sdev->tagged_supported && (dcb->DevMode & TAG_QUEUEING_)) {
- dcb->SyncMode |= EN_TAG_QUEUEING;
- scsi_activate_tcq(sdev, acb->TagMaxNum);
- }
-
- return 0;
-}
-
-static struct scsi_host_template driver_template = {
- .module = THIS_MODULE,
- .proc_name = "tmscsim",
- .name = DC390_BANNER " V" DC390_VERSION,
- .slave_alloc = dc390_slave_alloc,
- .slave_configure = dc390_slave_configure,
- .slave_destroy = dc390_slave_destroy,
- .queuecommand = DC390_queuecommand,
- .eh_abort_handler = DC390_abort,
- .eh_bus_reset_handler = DC390_bus_reset,
- .can_queue = 1,
- .this_id = 7,
- .sg_tablesize = SG_ALL,
- .cmd_per_lun = 1,
- .use_clustering = ENABLE_CLUSTERING,
- .max_sectors = 0x4000, /* 8MiB = 16 * 1024 * 512 */
-};
-
-/***********************************************************************
- * Functions for access to DC390 EEPROM
- * and some to emulate it
- *
- **********************************************************************/
-
-static void dc390_eeprom_prepare_read(struct pci_dev *pdev, u8 cmd)
-{
- u8 carryFlag = 1, j = 0x80, bval;
- int i;
-
- for (i = 0; i < 9; i++) {
- if (carryFlag) {
- pci_write_config_byte(pdev, 0x80, 0x40);
- bval = 0xc0;
- } else
- bval = 0x80;
-
- udelay(160);
- pci_write_config_byte(pdev, 0x80, bval);
- udelay(160);
- pci_write_config_byte(pdev, 0x80, 0);
- udelay(160);
-
- carryFlag = (cmd & j) ? 1 : 0;
- j >>= 1;
- }
-}
-
-static u16 dc390_eeprom_get_data(struct pci_dev *pdev)
-{
- int i;
- u16 wval = 0;
- u8 bval;
-
- for (i = 0; i < 16; i++) {
- wval <<= 1;
-
- pci_write_config_byte(pdev, 0x80, 0x80);
- udelay(160);
- pci_write_config_byte(pdev, 0x80, 0x40);
- udelay(160);
- pci_read_config_byte(pdev, 0x00, &bval);
-
- if (bval == 0x22)
- wval |= 1;
- }
-
- return wval;
-}
-
-static void dc390_read_eeprom(struct pci_dev *pdev, u16 *ptr)
-{
- u8 cmd = EEPROM_READ, i;
-
- for (i = 0; i < 0x40; i++) {
- pci_write_config_byte(pdev, 0xc0, 0);
- udelay(160);
-
- dc390_eeprom_prepare_read(pdev, cmd++);
- *ptr++ = dc390_eeprom_get_data(pdev);
-
- pci_write_config_byte(pdev, 0x80, 0);
- pci_write_config_byte(pdev, 0x80, 0);
- udelay(160);
- }
-}
-
-/* Override EEprom values with explicitly set values */
-static void dc390_eeprom_override(u8 index)
-{
- u8 *ptr = (u8 *) dc390_eepromBuf[index], id;
-
- /* Adapter Settings */
- if (tmscsim[0] != -2)
- ptr[EE_ADAPT_SCSI_ID] = (u8)tmscsim[0]; /* Adapter ID */
- if (tmscsim[3] != -2)
- ptr[EE_MODE2] = (u8)tmscsim[3];
- if (tmscsim[5] != -2)
- ptr[EE_DELAY] = tmscsim[5]; /* Reset delay */
- if (tmscsim[4] != -2)
- ptr[EE_TAG_CMD_NUM] = (u8)tmscsim[4]; /* Tagged Cmds */
-
- /* Device Settings */
- for (id = 0; id < MAX_SCSI_ID; id++) {
- if (tmscsim[2] != -2)
- ptr[id << 2] = (u8)tmscsim[2]; /* EE_MODE1 */
- if (tmscsim[1] != -2)
- ptr[(id << 2) + 1] = (u8)tmscsim[1]; /* EE_Speed */
- }
-}
-
-static int tmscsim_def[] = {
- 7,
- 0 /* 10MHz */,
- PARITY_CHK_ | SEND_START_ | EN_DISCONNECT_ | SYNC_NEGO_ | TAG_QUEUEING_,
- MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION | LUN_CHECK,
- 3 /* 16 Tags per LUN */,
- 1 /* s delay after Reset */,
-};
-
-/* Copy defaults over set values where missing */
-static void dc390_fill_with_defaults (void)
-{
- int i;
-
- for (i = 0; i < 6; i++) {
- if (tmscsim[i] < 0 || tmscsim[i] > 255)
- tmscsim[i] = tmscsim_def[i];
- }
-
- /* Sanity checks */
- if (tmscsim[0] > 7)
- tmscsim[0] = 7;
- if (tmscsim[1] > 7)
- tmscsim[1] = 4;
- if (tmscsim[4] > 5)
- tmscsim[4] = 4;
- if (tmscsim[5] > 180)
- tmscsim[5] = 180;
-}
-
-static void dc390_check_eeprom(struct pci_dev *pdev, u8 index)
-{
- u8 interpd[] = {1, 3, 5, 10, 16, 30, 60, 120};
- u8 EEbuf[128];
- u16 *ptr = (u16 *)EEbuf, wval = 0;
- int i;
-
- dc390_read_eeprom(pdev, ptr);
- memcpy(dc390_eepromBuf[index], EEbuf, EE_ADAPT_SCSI_ID);
- memcpy(&dc390_eepromBuf[index][EE_ADAPT_SCSI_ID],
- &EEbuf[REAL_EE_ADAPT_SCSI_ID], EE_LEN - EE_ADAPT_SCSI_ID);
-
- dc390_eepromBuf[index][EE_DELAY] = interpd[dc390_eepromBuf[index][EE_DELAY]];
-
- for (i = 0; i < 0x40; i++, ptr++)
- wval += *ptr;
-
- /* no Tekram EEprom found */
- if (wval != 0x1234) {
- int speed;
-
- printk(KERN_INFO "DC390_init: No EEPROM found! Trying default settings ...\n");
-
- /*
- * XXX(hch): bogus, because we might have tekram and
- * non-tekram hbas in a single machine.
- */
- dc390_fill_with_defaults();
-
- speed = dc390_clock_speed[tmscsim[1]];
- printk(KERN_INFO "DC390: Used defaults: AdaptID=%i, SpeedIdx=%i (%i.%i MHz), "
- "DevMode=0x%02x, AdaptMode=0x%02x, TaggedCmnds=%i (%i), DelayReset=%is\n",
- tmscsim[0], tmscsim[1], speed / 10, speed % 10,
- (u8)tmscsim[2], (u8)tmscsim[3], tmscsim[4], 2 << (tmscsim[4]), tmscsim[5]);
- }
-}
-
-static void dc390_init_hw(struct dc390_acb *pACB, u8 index)
-{
- struct Scsi_Host *shost = pACB->pScsiHost;
- u8 dstate;
-
- /* Disable SCSI bus reset interrupt */
- DC390_write8(CtrlReg1, DIS_INT_ON_SCSI_RST | shost->this_id);
-
- if (pACB->Gmode2 & RST_SCSI_BUS) {
- dc390_ResetSCSIBus(pACB);
- udelay(1000);
- pACB->last_reset = jiffies + HZ/2 +
- HZ * dc390_eepromBuf[pACB->AdapterIndex][EE_DELAY];
- }
-
- pACB->ACBFlag = 0;
-
- /* Reset Pending INT */
- DC390_read8(INT_Status);
-
- /* 250ms selection timeout */
- DC390_write8(Scsi_TimeOut, SEL_TIMEOUT);
-
- /* Conversion factor = 0 , 40MHz clock */
- DC390_write8(Clk_Factor, CLK_FREQ_40MHZ);
-
- /* NOP cmd - clear command register */
- DC390_write8(ScsiCmd, NOP_CMD);
-
- /* Enable Feature and SCSI-2 */
- DC390_write8(CtrlReg2, EN_FEATURE+EN_SCSI2_CMD);
-
- /* Fast clock */
- DC390_write8(CtrlReg3, FAST_CLK);
-
- /* Negation */
- DC390_write8(CtrlReg4, pACB->glitch_cfg | /* glitch eater */
- (dc390_eepromBuf[index][EE_MODE2] & ACTIVE_NEGATION) ?
- NEGATE_REQACKDATA : 0);
-
- /* Clear Transfer Count High: ID */
- DC390_write8(CtcReg_High, 0);
- DC390_write8(DMA_Cmd, DMA_IDLE_CMD);
- DC390_write8(ScsiCmd, CLEAR_FIFO_CMD);
- DC390_write32(DMA_ScsiBusCtrl, EN_INT_ON_PCI_ABORT);
-
- dstate = DC390_read8(DMA_Status);
- DC390_write8(DMA_Status, dstate);
-}
-
-static int dc390_probe_one(struct pci_dev *pdev, const struct pci_device_id *id)
-{
- struct dc390_acb *pACB;
- struct Scsi_Host *shost;
- unsigned long io_port;
- int error = -ENODEV, i;
-
- if (pci_enable_device(pdev))
- goto out;
-
- pci_set_master(pdev);
-
- error = -ENOMEM;
- if (disable_clustering)
- driver_template.use_clustering = DISABLE_CLUSTERING;
- shost = scsi_host_alloc(&driver_template, sizeof(struct dc390_acb));
- if (!shost)
- goto out_disable_device;
-
- pACB = (struct dc390_acb *)shost->hostdata;
- memset(pACB, 0, sizeof(struct dc390_acb));
-
- dc390_check_eeprom(pdev, dc390_adapterCnt);
- dc390_eeprom_override(dc390_adapterCnt);
-
- io_port = pci_resource_start(pdev, 0);
-
- shost->this_id = dc390_eepromBuf[dc390_adapterCnt][EE_ADAPT_SCSI_ID];
- shost->io_port = io_port;
- shost->n_io_port = 0x80;
- shost->irq = pdev->irq;
- shost->base = io_port;
- shost->unique_id = io_port;
-
- pACB->last_reset = jiffies;
- pACB->pScsiHost = shost;
- pACB->IOPortBase = (u16) io_port;
- pACB->IRQLevel = pdev->irq;
-
- shost->max_id = 8;
-
- if (shost->max_id - 1 ==
- dc390_eepromBuf[dc390_adapterCnt][EE_ADAPT_SCSI_ID])
- shost->max_id--;
-
- if (dc390_eepromBuf[dc390_adapterCnt][EE_MODE2] & LUN_CHECK)
- shost->max_lun = 8;
- else
- shost->max_lun = 1;
-
- pACB->pFreeSRB = pACB->SRB_array;
- pACB->SRBCount = MAX_SRB_CNT;
- pACB->AdapterIndex = dc390_adapterCnt;
- pACB->TagMaxNum =
- 2 << dc390_eepromBuf[dc390_adapterCnt][EE_TAG_CMD_NUM];
- pACB->Gmode2 = dc390_eepromBuf[dc390_adapterCnt][EE_MODE2];
-
- for (i = 0; i < pACB->SRBCount-1; i++)
- pACB->SRB_array[i].pNextSRB = &pACB->SRB_array[i+1];
- pACB->SRB_array[pACB->SRBCount-1].pNextSRB = NULL;
- pACB->pTmpSRB = &pACB->TmpSRB;
-
- pACB->sel_timeout = SEL_TIMEOUT;
- pACB->glitch_cfg = EATER_25NS;
- pACB->pdev = pdev;
-
- if (!request_region(io_port, shost->n_io_port, "tmscsim")) {
- printk(KERN_ERR "DC390: register IO ports error!\n");
- goto out_host_put;
- }
-
- /* Reset Pending INT */
- DC390_read8_(INT_Status, io_port);
-
- if (request_irq(pdev->irq, do_DC390_Interrupt, IRQF_SHARED,
- "tmscsim", pACB)) {
- printk(KERN_ERR "DC390: register IRQ error!\n");
- goto out_release_region;
- }
-
- dc390_init_hw(pACB, dc390_adapterCnt);
-
- dc390_adapterCnt++;
-
- pci_set_drvdata(pdev, shost);
-
- error = scsi_add_host(shost, &pdev->dev);
- if (error)
- goto out_free_irq;
- scsi_scan_host(shost);
- return 0;
-
- out_free_irq:
- free_irq(pdev->irq, pACB);
- out_release_region:
- release_region(io_port, shost->n_io_port);
- out_host_put:
- scsi_host_put(shost);
- out_disable_device:
- pci_disable_device(pdev);
- out:
- return error;
-}
-
-/**
- * dc390_remove_one - Called to remove a single instance of the adapter.
- *
- * @dev: The PCI device to remove.
- */
-static void dc390_remove_one(struct pci_dev *dev)
-{
- struct Scsi_Host *scsi_host = pci_get_drvdata(dev);
- unsigned long iflags;
- struct dc390_acb* pACB = (struct dc390_acb*) scsi_host->hostdata;
- u8 bval;
-
- scsi_remove_host(scsi_host);
-
- spin_lock_irqsave(scsi_host->host_lock, iflags);
- pACB->ACBFlag = RESET_DEV;
- bval = DC390_read8(CtrlReg1) | DIS_INT_ON_SCSI_RST;
- DC390_write8 (CtrlReg1, bval); /* disable interrupt */
- if (pACB->Gmode2 & RST_SCSI_BUS)
- dc390_ResetSCSIBus(pACB);
- spin_unlock_irqrestore(scsi_host->host_lock, iflags);
-
- free_irq(scsi_host->irq, pACB);
- release_region(scsi_host->io_port, scsi_host->n_io_port);
-
- pci_disable_device(dev);
- scsi_host_put(scsi_host);
-}
-
-static struct pci_device_id tmscsim_pci_tbl[] = {
- { PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD53C974,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 },
- { }
-};
-MODULE_DEVICE_TABLE(pci, tmscsim_pci_tbl);
-
-static struct pci_driver dc390_driver = {
- .name = "tmscsim",
- .id_table = tmscsim_pci_tbl,
- .probe = dc390_probe_one,
- .remove = dc390_remove_one,
-};
-
-static int __init dc390_module_init(void)
-{
- if (!disable_clustering) {
- printk(KERN_INFO "DC390: clustering now enabled by default. If you get problems load\n");
- printk(KERN_INFO " with \"disable_clustering=1\" and report to maintainers\n");
- }
-
- if (tmscsim[0] == -1 || tmscsim[0] > 15) {
- tmscsim[0] = 7;
- tmscsim[1] = 4;
- tmscsim[2] = PARITY_CHK_ | TAG_QUEUEING_;
- tmscsim[3] = MORE2_DRV | GREATER_1G | RST_SCSI_BUS | ACTIVE_NEGATION;
- tmscsim[4] = 2;
- tmscsim[5] = 10;
- printk (KERN_INFO "DC390: Using safe settings.\n");
- }
-
- return pci_register_driver(&dc390_driver);
-}
-
-static void __exit dc390_module_exit(void)
-{
- pci_unregister_driver(&dc390_driver);
-}
-
-module_init(dc390_module_init);
-module_exit(dc390_module_exit);
-
-#ifndef MODULE
-static int __init dc390_setup (char *str)
-{
- int ints[8],i, im;
-
- get_options(str, ARRAY_SIZE(ints), ints);
- im = ints[0];
-
- if (im > 6) {
- printk (KERN_NOTICE "DC390: ignore extra params!\n");
- im = 6;
- }
-
- for (i = 0; i < im; i++)
- tmscsim[i] = ints[i+1];
- /* dc390_checkparams (); */
- return 1;
-}
-
-__setup("tmscsim=", dc390_setup);
-#endif
diff --git a/drivers/scsi/tmscsim.h b/drivers/scsi/tmscsim.h
deleted file mode 100644
index 3d1bb4a..0000000
--- a/drivers/scsi/tmscsim.h
+++ /dev/null
@@ -1,551 +0,0 @@
-/***********************************************************************
-;* File Name : TMSCSIM.H *
-;* TEKRAM DC-390(T) PCI SCSI Bus Master Host Adapter *
-;* Device Driver *
-;***********************************************************************/
-/* $Id: tmscsim.h,v 2.15.2.3 2000/11/17 20:52:27 garloff Exp $ */
-
-#ifndef _TMSCSIM_H
-#define _TMSCSIM_H
-
-#include <linux/types.h>
-
-#define SCSI_IRQ_NONE 255
-
-#define MAX_ADAPTER_NUM 4
-#define MAX_SG_LIST_BUF 16 /* Not used */
-#define MAX_SCSI_ID 8
-#define MAX_SRB_CNT 50 /* Max number of started commands */
-
-#define SEL_TIMEOUT 153 /* 250 ms selection timeout (@ 40 MHz) */
-
-/*
-;-----------------------------------------------------------------------
-; SCSI Request Block
-;-----------------------------------------------------------------------
-*/
-struct dc390_srb
-{
-//u8 CmdBlock[12];
-
-struct dc390_srb *pNextSRB;
-struct dc390_dcb *pSRBDCB;
-struct scsi_cmnd *pcmd;
-struct scatterlist *pSegmentList;
-
-struct scatterlist Segmentx; /* make a one entry of S/G list table */
-
-unsigned long SGBusAddr; /*;a segment starting address as seen by AM53C974A
- in CPU endianness. We're only getting 32-bit bus
- addresses by default */
-unsigned long SGToBeXferLen; /*; to be xfer length */
-unsigned long TotalXferredLen;
-unsigned long SavedTotXLen;
-unsigned long Saved_Ptr;
-u32 SRBState;
-
-u8 SRBStatus;
-u8 SRBFlag; /*; b0-AutoReqSense,b6-Read,b7-write */
- /*; b4-settimeout,b5-Residual valid */
-u8 AdaptStatus;
-u8 TargetStatus;
-
-u8 ScsiPhase;
-s8 TagNumber;
-u8 SGIndex;
-u8 SGcount;
-
-u8 MsgCnt;
-u8 EndMessage;
-
-u8 MsgInBuf[6];
-u8 MsgOutBuf[6];
-
-//u8 IORBFlag; /*;81h-Reset, 2-retry */
-};
-
-
-/*
-;-----------------------------------------------------------------------
-; Device Control Block
-;-----------------------------------------------------------------------
-*/
-struct dc390_dcb
-{
-struct dc390_dcb *pNextDCB;
-struct dc390_acb *pDCBACB;
-
-/* Queued SRBs */
-struct dc390_srb *pGoingSRB;
-struct dc390_srb *pGoingLast;
-struct dc390_srb *pActiveSRB;
-u8 GoingSRBCnt;
-
-u32 TagMask;
-
-u8 TargetID; /*; SCSI Target ID (SCSI Only) */
-u8 TargetLUN; /*; SCSI Log. Unit (SCSI Only) */
-u8 DevMode;
-u8 DCBFlag;
-
-u8 CtrlR1;
-u8 CtrlR3;
-u8 CtrlR4;
-
-u8 SyncMode; /*; 0:async mode */
-u8 NegoPeriod; /*;for nego. */
-u8 SyncPeriod; /*;for reg. */
-u8 SyncOffset; /*;for reg. and nego.(low nibble) */
-};
-
-
-/*
-;-----------------------------------------------------------------------
-; Adapter Control Block
-;-----------------------------------------------------------------------
-*/
-struct dc390_acb
-{
-struct Scsi_Host *pScsiHost;
-u16 IOPortBase;
-u8 IRQLevel;
-u8 status;
-
-u8 SRBCount;
-u8 AdapterIndex; /*; nth Adapter this driver */
-u8 DCBCnt;
-
-u8 TagMaxNum;
-u8 ACBFlag;
-u8 Gmode2;
-u8 scan_devices;
-
-struct dc390_dcb *pLinkDCB;
-struct dc390_dcb *pLastDCB;
-struct dc390_dcb *pDCBRunRobin;
-
-struct dc390_dcb *pActiveDCB;
-struct dc390_srb *pFreeSRB;
-struct dc390_srb *pTmpSRB;
-
-u8 msgin123[4];
-u8 Connected;
-u8 pad;
-
-#if defined(USE_SPINLOCKS) && USE_SPINLOCKS > 1 && (defined(CONFIG_SMP) || DEBUG_SPINLOCKS > 0)
-spinlock_t lock;
-#endif
-u8 sel_timeout;
-u8 glitch_cfg;
-
-u8 MsgLen;
-u8 Ignore_IRQ; /* Not used */
-
-struct pci_dev *pdev;
-
-unsigned long last_reset;
-unsigned long Cmds;
-u32 SelLost;
-u32 SelConn;
-u32 CmdInQ;
-u32 CmdOutOfSRB;
-
-struct dc390_srb TmpSRB;
-struct dc390_srb SRB_array[MAX_SRB_CNT]; /* 50 SRBs */
-};
-
-
-/*;-----------------------------------------------------------------------*/
-
-
-#define BIT31 0x80000000
-#define BIT30 0x40000000
-#define BIT29 0x20000000
-#define BIT28 0x10000000
-#define BIT27 0x08000000
-#define BIT26 0x04000000
-#define BIT25 0x02000000
-#define BIT24 0x01000000
-#define BIT23 0x00800000
-#define BIT22 0x00400000
-#define BIT21 0x00200000
-#define BIT20 0x00100000
-#define BIT19 0x00080000
-#define BIT18 0x00040000
-#define BIT17 0x00020000
-#define BIT16 0x00010000
-#define BIT15 0x00008000
-#define BIT14 0x00004000
-#define BIT13 0x00002000
-#define BIT12 0x00001000
-#define BIT11 0x00000800
-#define BIT10 0x00000400
-#define BIT9 0x00000200
-#define BIT8 0x00000100
-#define BIT7 0x00000080
-#define BIT6 0x00000040
-#define BIT5 0x00000020
-#define BIT4 0x00000010
-#define BIT3 0x00000008
-#define BIT2 0x00000004
-#define BIT1 0x00000002
-#define BIT0 0x00000001
-
-/*;---UnitCtrlFlag */
-#define UNIT_ALLOCATED BIT0
-#define UNIT_INFO_CHANGED BIT1
-#define FORMATING_MEDIA BIT2
-#define UNIT_RETRY BIT3
-
-/*;---UnitFlags */
-#define DASD_SUPPORT BIT0
-#define SCSI_SUPPORT BIT1
-#define ASPI_SUPPORT BIT2
-
-/*;----SRBState machine definition */
-#define SRB_FREE 0
-#define SRB_WAIT BIT0
-#define SRB_READY BIT1
-#define SRB_MSGOUT BIT2 /*;arbitration+msg_out 1st byte*/
-#define SRB_MSGIN BIT3
-#define SRB_MSGIN_MULTI BIT4
-#define SRB_COMMAND BIT5
-#define SRB_START_ BIT6 /*;arbitration+msg_out+command_out*/
-#define SRB_DISCONNECT BIT7
-#define SRB_DATA_XFER BIT8
-#define SRB_XFERPAD BIT9
-#define SRB_STATUS BIT10
-#define SRB_COMPLETED BIT11
-#define SRB_ABORT_SENT BIT12
-#define DO_SYNC_NEGO BIT13
-#define SRB_UNEXPECT_RESEL BIT14
-
-/*;---SRBstatus */
-#define SRB_OK BIT0
-#define ABORTION BIT1
-#define OVER_RUN BIT2
-#define UNDER_RUN BIT3
-#define PARITY_ERROR BIT4
-#define SRB_ERROR BIT5
-
-/*;---ACBFlag */
-#define RESET_DEV BIT0
-#define RESET_DETECT BIT1
-#define RESET_DONE BIT2
-
-/*;---DCBFlag */
-#define ABORT_DEV_ BIT0
-
-/*;---SRBFlag */
-#define DATAOUT BIT7
-#define DATAIN BIT6
-#define RESIDUAL_VALID BIT5
-#define ENABLE_TIMER BIT4
-#define RESET_DEV0 BIT2
-#define ABORT_DEV BIT1
-#define AUTO_REQSENSE BIT0
-
-/*;---Adapter status */
-#define H_STATUS_GOOD 0
-#define H_SEL_TIMEOUT 0x11
-#define H_OVER_UNDER_RUN 0x12
-#define H_UNEXP_BUS_FREE 0x13
-#define H_TARGET_PHASE_F 0x14
-#define H_INVALID_CCB_OP 0x16
-#define H_LINK_CCB_BAD 0x17
-#define H_BAD_TARGET_DIR 0x18
-#define H_DUPLICATE_CCB 0x19
-#define H_BAD_CCB_OR_SG 0x1A
-#define H_ABORT 0x0FF
-
-/* cmd->result */
-#define RES_TARGET 0x000000FF /* Target State */
-#define RES_TARGET_LNX STATUS_MASK /* Only official ... */
-#define RES_ENDMSG 0x0000FF00 /* End Message */
-#define RES_DID 0x00FF0000 /* DID_ codes */
-#define RES_DRV 0xFF000000 /* DRIVER_ codes */
-
-#define MK_RES(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
-#define MK_RES_LNX(drv,did,msg,tgt) ((int)(drv)<<24 | (int)(did)<<16 | (int)(msg)<<8 | (int)(tgt))
-
-#define SET_RES_TARGET(who, tgt) do { who &= ~RES_TARGET; who |= (int)(tgt); } while (0)
-#define SET_RES_TARGET_LNX(who, tgt) do { who &= ~RES_TARGET_LNX; who |= (int)(tgt) << 1; } while (0)
-#define SET_RES_MSG(who, msg) do { who &= ~RES_ENDMSG; who |= (int)(msg) << 8; } while (0)
-#define SET_RES_DID(who, did) do { who &= ~RES_DID; who |= (int)(did) << 16; } while (0)
-#define SET_RES_DRV(who, drv) do { who &= ~RES_DRV; who |= (int)(drv) << 24; } while (0)
-
-/*;---Sync_Mode */
-#define SYNC_DISABLE 0
-#define SYNC_ENABLE BIT0
-#define SYNC_NEGO_DONE BIT1
-#define WIDE_ENABLE BIT2 /* Not used ;-) */
-#define WIDE_NEGO_DONE BIT3 /* Not used ;-) */
-#define EN_TAG_QUEUEING BIT4
-#define EN_ATN_STOP BIT5
-
-#define SYNC_NEGO_OFFSET 15
-
-/*;---SCSI bus phase*/
-#define SCSI_DATA_OUT 0
-#define SCSI_DATA_IN 1
-#define SCSI_COMMAND 2
-#define SCSI_STATUS_ 3
-#define SCSI_NOP0 4
-#define SCSI_NOP1 5
-#define SCSI_MSG_OUT 6
-#define SCSI_MSG_IN 7
-
-/*;----SCSI MSG BYTE*/ /* see scsi/scsi.h */ /* One is missing ! */
-#define ABORT_TAG 0x0d
-
-/*
- * SISC query queue
- */
-typedef struct {
- dma_addr_t saved_dma_handle;
-} dc390_cmd_scp_t;
-
-/*
-;==========================================================
-; EEPROM byte offset
-;==========================================================
-*/
-typedef struct _EEprom
-{
-u8 EE_MODE1;
-u8 EE_SPEED;
-u8 xx1;
-u8 xx2;
-} EEprom, *PEEprom;
-
-#define REAL_EE_ADAPT_SCSI_ID 64
-#define REAL_EE_MODE2 65
-#define REAL_EE_DELAY 66
-#define REAL_EE_TAG_CMD_NUM 67
-
-#define EE_ADAPT_SCSI_ID 32
-#define EE_MODE2 33
-#define EE_DELAY 34
-#define EE_TAG_CMD_NUM 35
-
-#define EE_LEN 40
-
-/*; EE_MODE1 bits definition*/
-#define PARITY_CHK_ BIT0
-#define SYNC_NEGO_ BIT1
-#define EN_DISCONNECT_ BIT2
-#define SEND_START_ BIT3
-#define TAG_QUEUEING_ BIT4
-
-/*; EE_MODE2 bits definition*/
-#define MORE2_DRV BIT0
-#define GREATER_1G BIT1
-#define RST_SCSI_BUS BIT2
-#define ACTIVE_NEGATION BIT3
-#define NO_SEEK BIT4
-#define LUN_CHECK BIT5
-
-#define ENABLE_CE 1
-#define DISABLE_CE 0
-#define EEPROM_READ 0x80
-
-/*
-;==========================================================
-; AMD 53C974 Registers bit Definition
-;==========================================================
-*/
-/*
-;====================
-; SCSI Register
-;====================
-*/
-
-/*; Command Reg.(+0CH) (rw) */
-#define DMA_COMMAND BIT7
-#define NOP_CMD 0
-#define CLEAR_FIFO_CMD 1
-#define RST_DEVICE_CMD 2
-#define RST_SCSI_BUS_CMD 3
-
-#define INFO_XFER_CMD 0x10
-#define INITIATOR_CMD_CMPLTE 0x11
-#define MSG_ACCEPTED_CMD 0x12
-#define XFER_PAD_BYTE 0x18
-#define SET_ATN_CMD 0x1A
-#define RESET_ATN_CMD 0x1B
-
-#define SEL_WO_ATN 0x41 /* currently not used */
-#define SEL_W_ATN 0x42
-#define SEL_W_ATN_STOP 0x43
-#define SEL_W_ATN3 0x46
-#define EN_SEL_RESEL 0x44
-#define DIS_SEL_RESEL 0x45 /* currently not used */
-#define RESEL 0x40 /* " */
-#define RESEL_ATN3 0x47 /* " */
-
-#define DATA_XFER_CMD INFO_XFER_CMD
-
-
-/*; SCSI Status Reg.(+10H) (r) */
-#define INTERRUPT BIT7
-#define ILLEGAL_OP_ERR BIT6
-#define PARITY_ERR BIT5
-#define COUNT_2_ZERO BIT4
-#define GROUP_CODE_VALID BIT3
-#define SCSI_PHASE_MASK (BIT2+BIT1+BIT0)
-/* BIT2: MSG phase; BIT1: C/D physe; BIT0: I/O phase */
-
-/*; Interrupt Status Reg.(+14H) (r) */
-#define SCSI_RESET BIT7
-#define INVALID_CMD BIT6
-#define DISCONNECTED BIT5
-#define SERVICE_REQUEST BIT4
-#define SUCCESSFUL_OP BIT3
-#define RESELECTED BIT2
-#define SEL_ATTENTION BIT1
-#define SELECTED BIT0
-
-/*; Internal State Reg.(+18H) (r) */
-#define SYNC_OFFSET_FLAG BIT3
-#define INTRN_STATE_MASK (BIT2+BIT1+BIT0)
-/* 0x04: Sel. successful (w/o stop), 0x01: Sel. successful (w/ stop) */
-
-/*; Clock Factor Reg.(+24H) (w) */
-#define CLK_FREQ_40MHZ 0
-#define CLK_FREQ_35MHZ (BIT2+BIT1+BIT0)
-#define CLK_FREQ_30MHZ (BIT2+BIT1)
-#define CLK_FREQ_25MHZ (BIT2+BIT0)
-#define CLK_FREQ_20MHZ BIT2
-#define CLK_FREQ_15MHZ (BIT1+BIT0)
-#define CLK_FREQ_10MHZ BIT1
-
-/*; Control Reg. 1(+20H) (rw) */
-#define EXTENDED_TIMING BIT7
-#define DIS_INT_ON_SCSI_RST BIT6
-#define PARITY_ERR_REPO BIT4
-#define SCSI_ID_ON_BUS (BIT2+BIT1+BIT0) /* host adapter ID */
-
-/*; Control Reg. 2(+2CH) (rw) */
-#define EN_FEATURE BIT6
-#define EN_SCSI2_CMD BIT3
-
-/*; Control Reg. 3(+30H) (rw) */
-#define ID_MSG_CHECK BIT7
-#define EN_QTAG_MSG BIT6
-#define EN_GRP2_CMD BIT5
-#define FAST_SCSI BIT4 /* ;10MB/SEC */
-#define FAST_CLK BIT3 /* ;25 - 40 MHZ */
-
-/*; Control Reg. 4(+34H) (rw) */
-#define EATER_12NS 0
-#define EATER_25NS BIT7
-#define EATER_35NS BIT6
-#define EATER_0NS (BIT7+BIT6)
-#define REDUCED_POWER BIT5
-#define CTRL4_RESERVED BIT4 /* must be 1 acc. to AM53C974.c */
-#define NEGATE_REQACKDATA BIT2
-#define NEGATE_REQACK BIT3
-
-#define GLITCH_TO_NS(x) (((~x>>6 & 2) >> 1) | ((x>>6 & 1) << 1 ^ (x>>6 & 2)))
-#define NS_TO_GLITCH(y) (((~y<<7) | ~((y<<6) ^ ((y<<5 & 1<<6) | ~0x40))) & 0xc0)
-
-/*
-;====================
-; DMA Register
-;====================
-*/
-/*; DMA Command Reg.(+40H) (rw) */
-#define READ_DIRECTION BIT7
-#define WRITE_DIRECTION 0
-#define EN_DMA_INT BIT6
-#define EN_PAGE_INT BIT5 /* page transfer interrupt enable */
-#define MAP_TO_MDL BIT4
-#define DIAGNOSTIC BIT2
-#define DMA_IDLE_CMD 0
-#define DMA_BLAST_CMD BIT0
-#define DMA_ABORT_CMD BIT1
-#define DMA_START_CMD (BIT1+BIT0)
-
-/*; DMA Status Reg.(+54H) (r) */
-#define PCI_MS_ABORT BIT6
-#define BLAST_COMPLETE BIT5
-#define SCSI_INTERRUPT BIT4
-#define DMA_XFER_DONE BIT3
-#define DMA_XFER_ABORT BIT2
-#define DMA_XFER_ERROR BIT1
-#define POWER_DOWN BIT0
-
-/*; DMA SCSI Bus and Ctrl.(+70H) */
-#define EN_INT_ON_PCI_ABORT BIT25
-#define WRT_ERASE_DMA_STAT BIT24
-#define PW_DOWN_CTRL BIT21
-#define SCSI_BUSY BIT20
-#define SCLK BIT19
-#define SCAM BIT18
-#define SCSI_LINES 0x0003ffff
-
-/*
-;==========================================================
-; SCSI Chip register address offset
-;==========================================================
-;Registers are rw unless declared otherwise
-*/
-#define CtcReg_Low 0x00 /* r curr. transfer count */
-#define CtcReg_Mid 0x04 /* r */
-#define CtcReg_High 0x38 /* r */
-#define ScsiFifo 0x08
-#define ScsiCmd 0x0C
-#define Scsi_Status 0x10 /* r */
-#define INT_Status 0x14 /* r */
-#define Sync_Period 0x18 /* w */
-#define Sync_Offset 0x1C /* w */
-#define Clk_Factor 0x24 /* w */
-#define CtrlReg1 0x20
-#define CtrlReg2 0x2C
-#define CtrlReg3 0x30
-#define CtrlReg4 0x34
-#define DMA_Cmd 0x40
-#define DMA_XferCnt 0x44 /* rw starting transfer count (32 bit) */
-#define DMA_XferAddr 0x48 /* rw starting physical address (32 bit) */
-#define DMA_Wk_ByteCntr 0x4C /* r working byte counter */
-#define DMA_Wk_AddrCntr 0x50 /* r working address counter */
-#define DMA_Status 0x54 /* r */
-#define DMA_MDL_Addr 0x58 /* rw starting MDL address */
-#define DMA_Wk_MDL_Cntr 0x5C /* r working MDL counter */
-#define DMA_ScsiBusCtrl 0x70 /* rw SCSI Bus, PCI/DMA Ctrl */
-
-#define StcReg_Low CtcReg_Low /* w start transfer count */
-#define StcReg_Mid CtcReg_Mid /* w */
-#define StcReg_High CtcReg_High /* w */
-#define Scsi_Dest_ID Scsi_Status /* w */
-#define Scsi_TimeOut INT_Status /* w */
-#define Intern_State Sync_Period /* r */
-#define Current_Fifo Sync_Offset /* r Curr. FIFO / int. state */
-
-
-#define DC390_read8(address) \
- (inb (pACB->IOPortBase + (address)))
-
-#define DC390_read8_(address, base) \
- (inb ((u16)(base) + (address)))
-
-#define DC390_read16(address) \
- (inw (pACB->IOPortBase + (address)))
-
-#define DC390_read32(address) \
- (inl (pACB->IOPortBase + (address)))
-
-#define DC390_write8(address,value) \
- outb ((value), pACB->IOPortBase + (address))
-
-#define DC390_write8_(address,value,base) \
- outb ((value), (u16)(base) + (address))
-
-#define DC390_write16(address,value) \
- outw ((value), pACB->IOPortBase + (address))
-
-#define DC390_write32(address,value) \
- outl ((value), pACB->IOPortBase + (address))
-
-
-#endif /* _TMSCSIM_H */
diff --git a/drivers/scsi/u14-34f.c b/drivers/scsi/u14-34f.c
index d8dcf36..14eb50b 100644
--- a/drivers/scsi/u14-34f.c
+++ b/drivers/scsi/u14-34f.c
@@ -696,25 +696,25 @@ static int u14_34f_slave_configure(struct scsi_device *dev) {
if (TLDEV(dev->type) && dev->tagged_supported)
if (tag_mode == TAG_SIMPLE) {
- scsi_adjust_queue_depth(dev, MSG_SIMPLE_TAG, tqd);
+ scsi_change_queue_depth(dev, tqd);
tag_suffix = ", simple tags";
}
else if (tag_mode == TAG_ORDERED) {
- scsi_adjust_queue_depth(dev, MSG_ORDERED_TAG, tqd);
+ scsi_change_queue_depth(dev, tqd);
tag_suffix = ", ordered tags";
}
else {
- scsi_adjust_queue_depth(dev, 0, tqd);
+ scsi_change_queue_depth(dev, tqd);
tag_suffix = ", no tags";
}
else if (TLDEV(dev->type) && linked_comm) {
- scsi_adjust_queue_depth(dev, 0, tqd);
+ scsi_change_queue_depth(dev, tqd);
tag_suffix = ", untagged";
}
else {
- scsi_adjust_queue_depth(dev, 0, utqd);
+ scsi_change_queue_depth(dev, utqd);
tag_suffix = "";
}
diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c
index 605ca60..2e4614b 100644
--- a/drivers/scsi/ufs/ufshcd.c
+++ b/drivers/scsi/ufs/ufshcd.c
@@ -2713,7 +2713,7 @@ static void ufshcd_set_queue_depth(struct scsi_device *sdev)
dev_dbg(hba->dev, "%s: activate tcq with queue depth %d\n",
__func__, lun_qdepth);
- scsi_activate_tcq(sdev, lun_qdepth);
+ scsi_change_queue_depth(sdev, lun_qdepth);
}
/*
@@ -2783,11 +2783,9 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
struct ufs_hba *hba;
hba = shost_priv(sdev->host);
- sdev->tagged_supported = 1;
/* Mode sense(6) is not supported by UFS, so use Mode sense(10) */
sdev->use_10_for_ms = 1;
- scsi_set_tag_type(sdev, MSG_SIMPLE_TAG);
/* allow SCSI layer to restart the device in case of errors */
sdev->allow_restart = 1;
@@ -2807,34 +2805,16 @@ static int ufshcd_slave_alloc(struct scsi_device *sdev)
* ufshcd_change_queue_depth - change queue depth
* @sdev: pointer to SCSI device
* @depth: required depth to set
- * @reason: reason for changing the depth
*
- * Change queue depth according to the reason and make sure
- * the max. limits are not crossed.
+ * Change queue depth and make sure the max. limits are not crossed.
*/
-static int ufshcd_change_queue_depth(struct scsi_device *sdev,
- int depth, int reason)
+static int ufshcd_change_queue_depth(struct scsi_device *sdev, int depth)
{
struct ufs_hba *hba = shost_priv(sdev->host);
if (depth > hba->nutrs)
depth = hba->nutrs;
-
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- case SCSI_QDEPTH_RAMP_UP:
- if (!sdev->tagged_supported)
- depth = 1;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return depth;
+ return scsi_change_queue_depth(sdev, depth);
}
/**
@@ -2860,7 +2840,6 @@ static void ufshcd_slave_destroy(struct scsi_device *sdev)
struct ufs_hba *hba;
hba = shost_priv(sdev->host);
- scsi_deactivate_tcq(sdev, hba->nutrs);
/* Drop the reference as it won't be needed anymore */
if (ufshcd_scsi_to_upiu_lun(sdev->lun) == UFS_UPIU_UFS_DEVICE_WLUN) {
unsigned long flags;
@@ -4239,6 +4218,8 @@ static struct scsi_host_template ufshcd_driver_template = {
.cmd_per_lun = UFSHCD_CMD_PER_LUN,
.can_queue = UFSHCD_CAN_QUEUE,
.max_host_blocked = 1,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static int ufshcd_config_vreg_load(struct device *dev, struct ufs_vreg *vreg,
@@ -4731,11 +4712,11 @@ static int ufshcd_set_dev_pwr_mode(struct ufs_hba *hba,
START_STOP_TIMEOUT, 0, NULL, REQ_PM);
if (ret) {
sdev_printk(KERN_WARNING, sdp,
- "START_STOP failed for power mode: %d\n", pwr_mode);
- scsi_show_result(ret);
+ "START_STOP failed for power mode: %d, result %x\n",
+ pwr_mode, ret);
if (driver_byte(ret) & DRIVER_SENSE) {
- scsi_show_sense_hdr(&sshdr);
- scsi_show_extd_sense(sshdr.asc, sshdr.ascq);
+ scsi_show_sense_hdr(sdp, NULL, &sshdr);
+ scsi_show_extd_sense(sdp, NULL, sshdr.asc, sshdr.ascq);
}
}
diff --git a/drivers/scsi/virtio_scsi.c b/drivers/scsi/virtio_scsi.c
index b83846f..c52bb5d 100644
--- a/drivers/scsi/virtio_scsi.c
+++ b/drivers/scsi/virtio_scsi.c
@@ -158,7 +158,7 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
sc, resp->response, resp->status, resp->sense_len);
sc->result = resp->status;
- virtscsi_compute_resid(sc, resp->resid);
+ virtscsi_compute_resid(sc, virtio32_to_cpu(vscsi->vdev, resp->resid));
switch (resp->response) {
case VIRTIO_SCSI_S_OK:
set_host_byte(sc, DID_OK);
@@ -196,10 +196,13 @@ static void virtscsi_complete_cmd(struct virtio_scsi *vscsi, void *buf)
break;
}
- WARN_ON(resp->sense_len > VIRTIO_SCSI_SENSE_SIZE);
+ WARN_ON(virtio32_to_cpu(vscsi->vdev, resp->sense_len) >
+ VIRTIO_SCSI_SENSE_SIZE);
if (sc->sense_buffer) {
memcpy(sc->sense_buffer, resp->sense,
- min_t(u32, resp->sense_len, VIRTIO_SCSI_SENSE_SIZE));
+ min_t(u32,
+ virtio32_to_cpu(vscsi->vdev, resp->sense_len),
+ VIRTIO_SCSI_SENSE_SIZE));
if (resp->sense_len)
set_driver_byte(sc, DRIVER_SENSE);
}
@@ -323,7 +326,7 @@ static void virtscsi_handle_transport_reset(struct virtio_scsi *vscsi,
unsigned int target = event->lun[1];
unsigned int lun = (event->lun[2] << 8) | event->lun[3];
- switch (event->reason) {
+ switch (virtio32_to_cpu(vscsi->vdev, event->reason)) {
case VIRTIO_SCSI_EVT_RESET_RESCAN:
scsi_add_device(shost, 0, target, lun);
break;
@@ -349,8 +352,8 @@ static void virtscsi_handle_param_change(struct virtio_scsi *vscsi,
struct Scsi_Host *shost = virtio_scsi_host(vscsi->vdev);
unsigned int target = event->lun[1];
unsigned int lun = (event->lun[2] << 8) | event->lun[3];
- u8 asc = event->reason & 255;
- u8 ascq = event->reason >> 8;
+ u8 asc = virtio32_to_cpu(vscsi->vdev, event->reason) & 255;
+ u8 ascq = virtio32_to_cpu(vscsi->vdev, event->reason) >> 8;
sdev = scsi_device_lookup(shost, 0, target, lun);
if (!sdev) {
@@ -374,12 +377,14 @@ static void virtscsi_handle_event(struct work_struct *work)
struct virtio_scsi *vscsi = event_node->vscsi;
struct virtio_scsi_event *event = &event_node->event;
- if (event->event & VIRTIO_SCSI_T_EVENTS_MISSED) {
- event->event &= ~VIRTIO_SCSI_T_EVENTS_MISSED;
+ if (event->event &
+ cpu_to_virtio32(vscsi->vdev, VIRTIO_SCSI_T_EVENTS_MISSED)) {
+ event->event &= ~cpu_to_virtio32(vscsi->vdev,
+ VIRTIO_SCSI_T_EVENTS_MISSED);
scsi_scan_host(virtio_scsi_host(vscsi->vdev));
}
- switch (event->event) {
+ switch (virtio32_to_cpu(vscsi->vdev, event->event)) {
case VIRTIO_SCSI_T_NO_EVENT:
break;
case VIRTIO_SCSI_T_TRANSPORT_RESET:
@@ -482,26 +487,28 @@ static int virtscsi_kick_cmd(struct virtio_scsi_vq *vq,
return err;
}
-static void virtio_scsi_init_hdr(struct virtio_scsi_cmd_req *cmd,
+static void virtio_scsi_init_hdr(struct virtio_device *vdev,
+ struct virtio_scsi_cmd_req *cmd,
struct scsi_cmnd *sc)
{
cmd->lun[0] = 1;
cmd->lun[1] = sc->device->id;
cmd->lun[2] = (sc->device->lun >> 8) | 0x40;
cmd->lun[3] = sc->device->lun & 0xff;
- cmd->tag = (unsigned long)sc;
+ cmd->tag = cpu_to_virtio64(vdev, (unsigned long)sc);
cmd->task_attr = VIRTIO_SCSI_S_SIMPLE;
cmd->prio = 0;
cmd->crn = 0;
}
-static void virtio_scsi_init_hdr_pi(struct virtio_scsi_cmd_req_pi *cmd_pi,
+static void virtio_scsi_init_hdr_pi(struct virtio_device *vdev,
+ struct virtio_scsi_cmd_req_pi *cmd_pi,
struct scsi_cmnd *sc)
{
struct request *rq = sc->request;
struct blk_integrity *bi;
- virtio_scsi_init_hdr((struct virtio_scsi_cmd_req *)cmd_pi, sc);
+ virtio_scsi_init_hdr(vdev, (struct virtio_scsi_cmd_req *)cmd_pi, sc);
if (!rq || !scsi_prot_sg_count(sc))
return;
@@ -509,9 +516,13 @@ static void virtio_scsi_init_hdr_pi(struct virtio_scsi_cmd_req_pi *cmd_pi,
bi = blk_get_integrity(rq->rq_disk);
if (sc->sc_data_direction == DMA_TO_DEVICE)
- cmd_pi->pi_bytesout = blk_rq_sectors(rq) * bi->tuple_size;
+ cmd_pi->pi_bytesout = cpu_to_virtio32(vdev,
+ blk_rq_sectors(rq) *
+ bi->tuple_size);
else if (sc->sc_data_direction == DMA_FROM_DEVICE)
- cmd_pi->pi_bytesin = blk_rq_sectors(rq) * bi->tuple_size;
+ cmd_pi->pi_bytesin = cpu_to_virtio32(vdev,
+ blk_rq_sectors(rq) *
+ bi->tuple_size);
}
static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
@@ -536,11 +547,11 @@ static int virtscsi_queuecommand(struct virtio_scsi *vscsi,
BUG_ON(sc->cmd_len > VIRTIO_SCSI_CDB_SIZE);
if (virtio_has_feature(vscsi->vdev, VIRTIO_SCSI_F_T10_PI)) {
- virtio_scsi_init_hdr_pi(&cmd->req.cmd_pi, sc);
+ virtio_scsi_init_hdr_pi(vscsi->vdev, &cmd->req.cmd_pi, sc);
memcpy(cmd->req.cmd_pi.cdb, sc->cmnd, sc->cmd_len);
req_size = sizeof(cmd->req.cmd_pi);
} else {
- virtio_scsi_init_hdr(&cmd->req.cmd, sc);
+ virtio_scsi_init_hdr(vscsi->vdev, &cmd->req.cmd, sc);
memcpy(cmd->req.cmd.cdb, sc->cmnd, sc->cmd_len);
req_size = sizeof(cmd->req.cmd);
}
@@ -561,6 +572,15 @@ static int virtscsi_queuecommand_single(struct Scsi_Host *sh,
return virtscsi_queuecommand(vscsi, &vscsi->req_vqs[0], sc);
}
+static struct virtio_scsi_vq *virtscsi_pick_vq_mq(struct virtio_scsi *vscsi,
+ struct scsi_cmnd *sc)
+{
+ u32 tag = blk_mq_unique_tag(sc->request);
+ u16 hwq = blk_mq_unique_tag_to_hwq(tag);
+
+ return &vscsi->req_vqs[hwq];
+}
+
static struct virtio_scsi_vq *virtscsi_pick_vq(struct virtio_scsi *vscsi,
struct virtio_scsi_target_state *tgt)
{
@@ -604,7 +624,12 @@ static int virtscsi_queuecommand_multi(struct Scsi_Host *sh,
struct virtio_scsi *vscsi = shost_priv(sh);
struct virtio_scsi_target_state *tgt =
scsi_target(sc->device)->hostdata;
- struct virtio_scsi_vq *req_vq = virtscsi_pick_vq(vscsi, tgt);
+ struct virtio_scsi_vq *req_vq;
+
+ if (shost_use_blk_mq(sh))
+ req_vq = virtscsi_pick_vq_mq(vscsi, sc);
+ else
+ req_vq = virtscsi_pick_vq(vscsi, tgt);
return virtscsi_queuecommand(vscsi, req_vq, sc);
}
@@ -655,7 +680,8 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc)
cmd->sc = sc;
cmd->req.tmf = (struct virtio_scsi_ctrl_tmf_req){
.type = VIRTIO_SCSI_T_TMF,
- .subtype = VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET,
+ .subtype = cpu_to_virtio32(vscsi->vdev,
+ VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET),
.lun[0] = 1,
.lun[1] = sc->device->id,
.lun[2] = (sc->device->lun >> 8) | 0x40,
@@ -668,30 +694,13 @@ static int virtscsi_device_reset(struct scsi_cmnd *sc)
* virtscsi_change_queue_depth() - Change a virtscsi target's queue depth
* @sdev: Virtscsi target whose queue depth to change
* @qdepth: New queue depth
- * @reason: Reason for the queue depth change.
*/
-static int virtscsi_change_queue_depth(struct scsi_device *sdev,
- int qdepth,
- int reason)
+static int virtscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
struct Scsi_Host *shost = sdev->host;
int max_depth = shost->cmd_per_lun;
- switch (reason) {
- case SCSI_QDEPTH_QFULL: /* Drop qdepth in response to BUSY state */
- scsi_track_queue_full(sdev, qdepth);
- break;
- case SCSI_QDEPTH_RAMP_UP: /* Raise qdepth after BUSY state resolved */
- case SCSI_QDEPTH_DEFAULT: /* Manual change via sysfs */
- scsi_adjust_queue_depth(sdev,
- scsi_get_tag_type(sdev),
- min(max_depth, qdepth));
- break;
- default:
- return -EOPNOTSUPP;
- }
-
- return sdev->queue_depth;
+ return scsi_change_queue_depth(sdev, min(max_depth, qdepth));
}
static int virtscsi_abort(struct scsi_cmnd *sc)
@@ -713,7 +722,7 @@ static int virtscsi_abort(struct scsi_cmnd *sc)
.lun[1] = sc->device->id,
.lun[2] = (sc->device->lun >> 8) | 0x40,
.lun[3] = sc->device->lun & 0xff,
- .tag = (unsigned long)sc,
+ .tag = cpu_to_virtio64(vscsi->vdev, (unsigned long)sc),
};
return virtscsi_tmf(vscsi, cmd);
}
@@ -758,6 +767,7 @@ static struct scsi_host_template virtscsi_host_template_single = {
.use_clustering = ENABLE_CLUSTERING,
.target_alloc = virtscsi_target_alloc,
.target_destroy = virtscsi_target_destroy,
+ .track_queue_depth = 1,
};
static struct scsi_host_template virtscsi_host_template_multi = {
@@ -776,6 +786,7 @@ static struct scsi_host_template virtscsi_host_template_multi = {
.use_clustering = ENABLE_CLUSTERING,
.target_alloc = virtscsi_target_alloc,
.target_destroy = virtscsi_target_destroy,
+ .track_queue_depth = 1,
};
#define virtscsi_config_get(vdev, fld) \
@@ -983,6 +994,7 @@ static int virtscsi_probe(struct virtio_device *vdev)
shost->max_id = num_targets;
shost->max_channel = 0;
shost->max_cmd_len = VIRTIO_SCSI_CDB_SIZE;
+ shost->nr_hw_queues = num_queues;
if (virtio_has_feature(vdev, VIRTIO_SCSI_F_T10_PI)) {
host_prot = SHOST_DIF_TYPE1_PROTECTION | SHOST_DIF_TYPE2_PROTECTION |
diff --git a/drivers/scsi/vmw_pvscsi.c b/drivers/scsi/vmw_pvscsi.c
index 598f65e..0f133c1 100644
--- a/drivers/scsi/vmw_pvscsi.c
+++ b/drivers/scsi/vmw_pvscsi.c
@@ -504,33 +504,11 @@ static void pvscsi_setup_all_rings(const struct pvscsi_adapter *adapter)
}
}
-static int pvscsi_change_queue_depth(struct scsi_device *sdev,
- int qdepth,
- int reason)
+static int pvscsi_change_queue_depth(struct scsi_device *sdev, int qdepth)
{
- int max_depth;
- struct Scsi_Host *shost = sdev->host;
-
- if (reason != SCSI_QDEPTH_DEFAULT)
- /*
- * We support only changing default.
- */
- return -EOPNOTSUPP;
-
- max_depth = shost->can_queue;
if (!sdev->tagged_supported)
- max_depth = 1;
- if (qdepth > max_depth)
- qdepth = max_depth;
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), qdepth);
-
- if (sdev->inquiry_len > 7)
- sdev_printk(KERN_INFO, sdev,
- "qdepth(%d), tagged(%d), simple(%d), ordered(%d), scsi_level(%d), cmd_que(%d)\n",
- sdev->queue_depth, sdev->tagged_supported,
- sdev->simple_tags, sdev->ordered_tags,
- sdev->scsi_level, (sdev->inquiry[7] & 2) >> 1);
- return sdev->queue_depth;
+ qdepth = 1;
+ return scsi_change_queue_depth(sdev, qdepth);
}
/*
@@ -723,10 +701,6 @@ static int pvscsi_queue_ring(struct pvscsi_adapter *adapter,
memcpy(e->cdb, cmd->cmnd, e->cdbLen);
e->tag = SIMPLE_QUEUE_TAG;
- if (sdev->tagged_supported &&
- (cmd->tag == HEAD_OF_QUEUE_TAG ||
- cmd->tag == ORDERED_QUEUE_TAG))
- e->tag = cmd->tag;
if (cmd->sc_data_direction == DMA_FROM_DEVICE)
e->flags = PVSCSI_FLAG_CMD_DIR_TOHOST;
diff --git a/drivers/scsi/wd7000.c b/drivers/scsi/wd7000.c
index 3267423..f94d736 100644
--- a/drivers/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -1653,7 +1653,6 @@ static struct scsi_host_template driver_template = {
.can_queue = WD7000_Q,
.this_id = 7,
.sg_tablesize = WD7000_SG,
- .cmd_per_lun = 1,
.unchecked_isa_dma = 1,
.use_clustering = ENABLE_CLUSTERING,
};
diff --git a/drivers/scsi/wd719x.c b/drivers/scsi/wd719x.c
new file mode 100644
index 0000000..7702664
--- /dev/null
+++ b/drivers/scsi/wd719x.c
@@ -0,0 +1,996 @@
+/*
+ * Driver for Western Digital WD7193, WD7197 and WD7296 SCSI cards
+ * Copyright 2013 Ondrej Zary
+ *
+ * Original driver by
+ * Aaron Dewell <dewell@woods.net>
+ * Gaerti <Juergen.Gaertner@mbox.si.uni-hannover.de>
+ *
+ * HW documentation available in book:
+ *
+ * SPIDER Command Protocol
+ * by Chandru M. Sippy
+ * SCSI Storage Products (MCP)
+ * Western Digital Corporation
+ * 09-15-95
+ *
+ * http://web.archive.org/web/20070717175254/http://sun1.rrzn.uni-hannover.de/gaertner.juergen/wd719x/Linux/Docu/Spider/
+ */
+
+/*
+ * Driver workflow:
+ * 1. SCSI command is transformed to SCB (Spider Control Block) by the
+ * queuecommand function.
+ * 2. The address of the SCB is stored in a list to be able to access it, if
+ * something goes wrong.
+ * 3. The address of the SCB is written to the Controller, which loads the SCB
+ * via BM-DMA and processes it.
+ * 4. After it has finished, it generates an interrupt, and sets registers.
+ *
+ * flaws:
+ * - abort/reset functions
+ *
+ * ToDo:
+ * - tagged queueing
+ */
+
+#include <linux/interrupt.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/eeprom_93cx6.h>
+#include <scsi/scsi_cmnd.h>
+#include <scsi/scsi_device.h>
+#include <scsi/scsi_host.h>
+#include "wd719x.h"
+
+/* low-level register access */
+static inline u8 wd719x_readb(struct wd719x *wd, u8 reg)
+{
+ return ioread8(wd->base + reg);
+}
+
+static inline u32 wd719x_readl(struct wd719x *wd, u8 reg)
+{
+ return ioread32(wd->base + reg);
+}
+
+static inline void wd719x_writeb(struct wd719x *wd, u8 reg, u8 val)
+{
+ iowrite8(val, wd->base + reg);
+}
+
+static inline void wd719x_writew(struct wd719x *wd, u8 reg, u16 val)
+{
+ iowrite16(val, wd->base + reg);
+}
+
+static inline void wd719x_writel(struct wd719x *wd, u8 reg, u32 val)
+{
+ iowrite32(val, wd->base + reg);
+}
+
+/* wait until the command register is ready */
+static inline int wd719x_wait_ready(struct wd719x *wd)
+{
+ int i = 0;
+
+ do {
+ if (wd719x_readb(wd, WD719X_AMR_COMMAND) == WD719X_CMD_READY)
+ return 0;
+ udelay(1);
+ } while (i++ < WD719X_WAIT_FOR_CMD_READY);
+
+ dev_err(&wd->pdev->dev, "command register is not ready: 0x%02x\n",
+ wd719x_readb(wd, WD719X_AMR_COMMAND));
+
+ return -ETIMEDOUT;
+}
+
+/* poll interrupt status register until command finishes */
+static inline int wd719x_wait_done(struct wd719x *wd, int timeout)
+{
+ u8 status;
+
+ while (timeout > 0) {
+ status = wd719x_readb(wd, WD719X_AMR_INT_STATUS);
+ if (status)
+ break;
+ timeout--;
+ udelay(1);
+ }
+
+ if (timeout <= 0) {
+ dev_err(&wd->pdev->dev, "direct command timed out\n");
+ return -ETIMEDOUT;
+ }
+
+ if (status != WD719X_INT_NOERRORS) {
+ dev_err(&wd->pdev->dev, "direct command failed, status 0x%02x, SUE 0x%02x\n",
+ status, wd719x_readb(wd, WD719X_AMR_SCB_ERROR));
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int wd719x_direct_cmd(struct wd719x *wd, u8 opcode, u8 dev, u8 lun,
+ u8 tag, dma_addr_t data, int timeout)
+{
+ int ret = 0;
+
+ /* clear interrupt status register (allow command register to clear) */
+ wd719x_writeb(wd, WD719X_AMR_INT_STATUS, WD719X_INT_NONE);
+
+ /* Wait for the Command register to become free */
+ if (wd719x_wait_ready(wd))
+ return -ETIMEDOUT;
+
+ /* make sure we get NO interrupts */
+ dev |= WD719X_DISABLE_INT;
+ wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, dev);
+ wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_2, lun);
+ wd719x_writeb(wd, WD719X_AMR_CMD_PARAM_3, tag);
+ if (data)
+ wd719x_writel(wd, WD719X_AMR_SCB_IN, data);
+
+ /* clear interrupt status register again */
+ wd719x_writeb(wd, WD719X_AMR_INT_STATUS, WD719X_INT_NONE);
+
+ /* Now, write the command */
+ wd719x_writeb(wd, WD719X_AMR_COMMAND, opcode);
+
+ if (timeout) /* wait for the command to complete */
+ ret = wd719x_wait_done(wd, timeout);
+
+ /* clear interrupt status register (clean up) */
+ if (opcode != WD719X_CMD_READ_FIRMVER)
+ wd719x_writeb(wd, WD719X_AMR_INT_STATUS, WD719X_INT_NONE);
+
+ return ret;
+}
+
+static void wd719x_destroy(struct wd719x *wd)
+{
+ struct wd719x_scb *scb;
+
+ /* stop the RISC */
+ if (wd719x_direct_cmd(wd, WD719X_CMD_SLEEP, 0, 0, 0, 0,
+ WD719X_WAIT_FOR_RISC))
+ dev_warn(&wd->pdev->dev, "RISC sleep command failed\n");
+ /* disable RISC */
+ wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
+
+ /* free all SCBs */
+ list_for_each_entry(scb, &wd->active_scbs, list)
+ pci_free_consistent(wd->pdev, sizeof(struct wd719x_scb), scb,
+ scb->phys);
+ list_for_each_entry(scb, &wd->free_scbs, list)
+ pci_free_consistent(wd->pdev, sizeof(struct wd719x_scb), scb,
+ scb->phys);
+ /* free internal buffers */
+ pci_free_consistent(wd->pdev, wd->fw_size, wd->fw_virt, wd->fw_phys);
+ wd->fw_virt = NULL;
+ pci_free_consistent(wd->pdev, WD719X_HASH_TABLE_SIZE, wd->hash_virt,
+ wd->hash_phys);
+ wd->hash_virt = NULL;
+ pci_free_consistent(wd->pdev, sizeof(struct wd719x_host_param),
+ wd->params, wd->params_phys);
+ wd->params = NULL;
+ free_irq(wd->pdev->irq, wd);
+}
+
+/* finish a SCSI command, mark SCB (if any) as free, unmap buffers */
+static void wd719x_finish_cmd(struct scsi_cmnd *cmd, int result)
+{
+ struct wd719x *wd = shost_priv(cmd->device->host);
+ struct wd719x_scb *scb = (struct wd719x_scb *) cmd->host_scribble;
+
+ if (scb) {
+ list_move(&scb->list, &wd->free_scbs);
+ dma_unmap_single(&wd->pdev->dev, cmd->SCp.dma_handle,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ scsi_dma_unmap(cmd);
+ }
+ cmd->result = result << 16;
+ cmd->scsi_done(cmd);
+}
+
+/* Build a SCB and send it to the card */
+static int wd719x_queuecommand(struct Scsi_Host *sh, struct scsi_cmnd *cmd)
+{
+ int i, count_sg;
+ unsigned long flags;
+ struct wd719x_scb *scb;
+ struct wd719x *wd = shost_priv(sh);
+ dma_addr_t phys;
+
+ cmd->host_scribble = NULL;
+
+ /* get a free SCB - either from existing ones or allocate a new one */
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+ scb = list_first_entry_or_null(&wd->free_scbs, struct wd719x_scb, list);
+ if (scb) {
+ list_del(&scb->list);
+ phys = scb->phys;
+ } else {
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ scb = pci_alloc_consistent(wd->pdev, sizeof(struct wd719x_scb),
+ &phys);
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+ if (!scb) {
+ dev_err(&wd->pdev->dev, "unable to allocate SCB\n");
+ wd719x_finish_cmd(cmd, DID_ERROR);
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ return 0;
+ }
+ }
+ memset(scb, 0, sizeof(struct wd719x_scb));
+ list_add(&scb->list, &wd->active_scbs);
+
+ scb->phys = phys;
+ scb->cmd = cmd;
+ cmd->host_scribble = (char *) scb;
+
+ scb->CDB_tag = 0; /* Tagged queueing not supported yet */
+ scb->devid = cmd->device->id;
+ scb->lun = cmd->device->lun;
+
+ /* copy the command */
+ memcpy(scb->CDB, cmd->cmnd, cmd->cmd_len);
+
+ /* map sense buffer */
+ scb->sense_buf_length = SCSI_SENSE_BUFFERSIZE;
+ cmd->SCp.dma_handle = dma_map_single(&wd->pdev->dev, cmd->sense_buffer,
+ SCSI_SENSE_BUFFERSIZE, DMA_FROM_DEVICE);
+ scb->sense_buf = cpu_to_le32(cmd->SCp.dma_handle);
+
+ /* request autosense */
+ scb->SCB_options |= WD719X_SCB_FLAGS_AUTO_REQUEST_SENSE;
+
+ /* check direction */
+ if (cmd->sc_data_direction == DMA_TO_DEVICE)
+ scb->SCB_options |= WD719X_SCB_FLAGS_CHECK_DIRECTION
+ | WD719X_SCB_FLAGS_PCI_TO_SCSI;
+ else if (cmd->sc_data_direction == DMA_FROM_DEVICE)
+ scb->SCB_options |= WD719X_SCB_FLAGS_CHECK_DIRECTION;
+
+ /* Scather/gather */
+ count_sg = scsi_dma_map(cmd);
+ if (count_sg < 0) {
+ wd719x_finish_cmd(cmd, DID_ERROR);
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ return 0;
+ }
+ BUG_ON(count_sg > WD719X_SG);
+
+ if (count_sg) {
+ struct scatterlist *sg;
+
+ scb->data_length = cpu_to_le32(count_sg *
+ sizeof(struct wd719x_sglist));
+ scb->data_p = cpu_to_le32(scb->phys +
+ offsetof(struct wd719x_scb, sg_list));
+
+ scsi_for_each_sg(cmd, sg, count_sg, i) {
+ scb->sg_list[i].ptr = cpu_to_le32(sg_dma_address(sg));
+ scb->sg_list[i].length = cpu_to_le32(sg_dma_len(sg));
+ }
+ scb->SCB_options |= WD719X_SCB_FLAGS_DO_SCATTER_GATHER;
+ } else { /* zero length */
+ scb->data_length = 0;
+ scb->data_p = 0;
+ }
+
+ /* check if the Command register is free */
+ if (wd719x_readb(wd, WD719X_AMR_COMMAND) != WD719X_CMD_READY) {
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ return SCSI_MLQUEUE_HOST_BUSY;
+ }
+
+ /* write pointer to the AMR */
+ wd719x_writel(wd, WD719X_AMR_SCB_IN, scb->phys);
+ /* send SCB opcode */
+ wd719x_writeb(wd, WD719X_AMR_COMMAND, WD719X_CMD_PROCESS_SCB);
+
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+
+ return 0;
+}
+
+static int wd719x_chip_init(struct wd719x *wd)
+{
+ int i, ret;
+ u32 risc_init[3];
+ const struct firmware *fw_wcs, *fw_risc;
+ const char fwname_wcs[] = "wd719x-wcs.bin";
+ const char fwname_risc[] = "wd719x-risc.bin";
+
+ memset(wd->hash_virt, 0, WD719X_HASH_TABLE_SIZE);
+
+ /* WCS (sequencer) firmware */
+ ret = request_firmware(&fw_wcs, fwname_wcs, &wd->pdev->dev);
+ if (ret) {
+ dev_err(&wd->pdev->dev, "Unable to load firmware %s: %d\n",
+ fwname_wcs, ret);
+ return ret;
+ }
+ /* RISC firmware */
+ ret = request_firmware(&fw_risc, fwname_risc, &wd->pdev->dev);
+ if (ret) {
+ dev_err(&wd->pdev->dev, "Unable to load firmware %s: %d\n",
+ fwname_risc, ret);
+ release_firmware(fw_wcs);
+ return ret;
+ }
+ wd->fw_size = ALIGN(fw_wcs->size, 4) + fw_risc->size;
+
+ if (!wd->fw_virt)
+ wd->fw_virt = pci_alloc_consistent(wd->pdev, wd->fw_size,
+ &wd->fw_phys);
+ if (!wd->fw_virt) {
+ ret = -ENOMEM;
+ goto wd719x_init_end;
+ }
+
+ /* make a fresh copy of WCS and RISC code */
+ memcpy(wd->fw_virt, fw_wcs->data, fw_wcs->size);
+ memcpy(wd->fw_virt + ALIGN(fw_wcs->size, 4), fw_risc->data,
+ fw_risc->size);
+
+ /* Reset the Spider Chip and adapter itself */
+ wd719x_writeb(wd, WD719X_PCI_PORT_RESET, WD719X_PCI_RESET);
+ udelay(WD719X_WAIT_FOR_RISC);
+ /* Clear PIO mode bits set by BIOS */
+ wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, 0);
+ /* ensure RISC is not running */
+ wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, 0);
+ /* ensure command port is ready */
+ wd719x_writeb(wd, WD719X_AMR_COMMAND, 0);
+ if (wd719x_wait_ready(wd)) {
+ ret = -ETIMEDOUT;
+ goto wd719x_init_end;
+ }
+
+ /* Transfer the first 2K words of RISC code to kick start the uP */
+ risc_init[0] = wd->fw_phys; /* WCS FW */
+ risc_init[1] = wd->fw_phys + ALIGN(fw_wcs->size, 4); /* RISC FW */
+ risc_init[2] = wd->hash_phys; /* hash table */
+
+ /* clear DMA status */
+ wd719x_writeb(wd, WD719X_PCI_CHANNEL2_3STATUS, 0);
+
+ /* address to read firmware from */
+ wd719x_writel(wd, WD719X_PCI_EXTERNAL_ADDR, risc_init[1]);
+ /* base address to write firmware to (on card) */
+ wd719x_writew(wd, WD719X_PCI_INTERNAL_ADDR, WD719X_PRAM_BASE_ADDR);
+ /* size: first 2K words */
+ wd719x_writew(wd, WD719X_PCI_DMA_TRANSFER_SIZE, 2048 * 2);
+ /* start DMA */
+ wd719x_writeb(wd, WD719X_PCI_CHANNEL2_3CMD, WD719X_START_CHANNEL2_3DMA);
+
+ /* wait for DMA to complete */
+ i = WD719X_WAIT_FOR_RISC;
+ while (i-- > 0) {
+ u8 status = wd719x_readb(wd, WD719X_PCI_CHANNEL2_3STATUS);
+ if (status == WD719X_START_CHANNEL2_3DONE)
+ break;
+ if (status == WD719X_START_CHANNEL2_3ABORT) {
+ dev_warn(&wd->pdev->dev, "RISC bootstrap failed: DMA aborted\n");
+ ret = -EIO;
+ goto wd719x_init_end;
+ }
+ udelay(1);
+ }
+ if (i < 1) {
+ dev_warn(&wd->pdev->dev, "RISC bootstrap failed: DMA timeout\n");
+ ret = -ETIMEDOUT;
+ goto wd719x_init_end;
+ }
+
+ /* firmware is loaded, now initialize and wake up the RISC */
+ /* write RISC initialization long words to Spider */
+ wd719x_writel(wd, WD719X_AMR_SCB_IN, risc_init[0]);
+ wd719x_writel(wd, WD719X_AMR_SCB_IN + 4, risc_init[1]);
+ wd719x_writel(wd, WD719X_AMR_SCB_IN + 8, risc_init[2]);
+
+ /* disable interrupts during initialization of RISC */
+ wd719x_writeb(wd, WD719X_AMR_CMD_PARAM, WD719X_DISABLE_INT);
+
+ /* issue INITIALIZE RISC comand */
+ wd719x_writeb(wd, WD719X_AMR_COMMAND, WD719X_CMD_INIT_RISC);
+ /* enable advanced mode (wake up RISC) */
+ wd719x_writeb(wd, WD719X_PCI_MODE_SELECT, WD719X_ENABLE_ADVANCE_MODE);
+ udelay(WD719X_WAIT_FOR_RISC);
+
+ ret = wd719x_wait_done(wd, WD719X_WAIT_FOR_RISC);
+ /* clear interrupt status register */
+ wd719x_writeb(wd, WD719X_AMR_INT_STATUS, WD719X_INT_NONE);
+ if (ret) {
+ dev_warn(&wd->pdev->dev, "Unable to initialize RISC\n");
+ goto wd719x_init_end;
+ }
+ /* RISC is up and running */
+
+ /* Read FW version from RISC */
+ ret = wd719x_direct_cmd(wd, WD719X_CMD_READ_FIRMVER, 0, 0, 0, 0,
+ WD719X_WAIT_FOR_RISC);
+ if (ret) {
+ dev_warn(&wd->pdev->dev, "Unable to read firmware version\n");
+ goto wd719x_init_end;
+ }
+ dev_info(&wd->pdev->dev, "RISC initialized with firmware version %.2x.%.2x\n",
+ wd719x_readb(wd, WD719X_AMR_SCB_OUT + 1),
+ wd719x_readb(wd, WD719X_AMR_SCB_OUT));
+
+ /* RESET SCSI bus */
+ ret = wd719x_direct_cmd(wd, WD719X_CMD_BUSRESET, 0, 0, 0, 0,
+ WD719X_WAIT_FOR_SCSI_RESET);
+ if (ret) {
+ dev_warn(&wd->pdev->dev, "SCSI bus reset failed\n");
+ goto wd719x_init_end;
+ }
+
+ /* use HostParameter structure to set Spider's Host Parameter Block */
+ ret = wd719x_direct_cmd(wd, WD719X_CMD_SET_PARAM, 0,
+ sizeof(struct wd719x_host_param), 0,
+ wd->params_phys, WD719X_WAIT_FOR_RISC);
+ if (ret) {
+ dev_warn(&wd->pdev->dev, "Failed to set HOST PARAMETERS\n");
+ goto wd719x_init_end;
+ }
+
+ /* initiate SCAM (does nothing if disabled in BIOS) */
+ /* bug?: we should pass a mask of static IDs which we don't have */
+ ret = wd719x_direct_cmd(wd, WD719X_CMD_INIT_SCAM, 0, 0, 0, 0,
+ WD719X_WAIT_FOR_SCSI_RESET);
+ if (ret) {
+ dev_warn(&wd->pdev->dev, "SCAM initialization failed\n");
+ goto wd719x_init_end;
+ }
+
+ /* clear AMR_BIOS_SHARE_INT register */
+ wd719x_writeb(wd, WD719X_AMR_BIOS_SHARE_INT, 0);
+
+wd719x_init_end:
+ release_firmware(fw_wcs);
+ release_firmware(fw_risc);
+
+ return ret;
+}
+
+static int wd719x_abort(struct scsi_cmnd *cmd)
+{
+ int action, result;
+ unsigned long flags;
+ struct wd719x_scb *scb = (struct wd719x_scb *)cmd->host_scribble;
+ struct wd719x *wd = shost_priv(cmd->device->host);
+
+ dev_info(&wd->pdev->dev, "abort command, tag: %x\n", cmd->tag);
+
+ action = /*cmd->tag ? WD719X_CMD_ABORT_TAG : */WD719X_CMD_ABORT;
+
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+ result = wd719x_direct_cmd(wd, action, cmd->device->id,
+ cmd->device->lun, cmd->tag, scb->phys, 0);
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ if (result)
+ return FAILED;
+
+ return SUCCESS;
+}
+
+static int wd719x_reset(struct scsi_cmnd *cmd, u8 opcode, u8 device)
+{
+ int result;
+ unsigned long flags;
+ struct wd719x *wd = shost_priv(cmd->device->host);
+
+ dev_info(&wd->pdev->dev, "%s reset requested\n",
+ (opcode == WD719X_CMD_BUSRESET) ? "bus" : "device");
+
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+ result = wd719x_direct_cmd(wd, opcode, device, 0, 0, 0,
+ WD719X_WAIT_FOR_SCSI_RESET);
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ if (result)
+ return FAILED;
+
+ return SUCCESS;
+}
+
+static int wd719x_dev_reset(struct scsi_cmnd *cmd)
+{
+ return wd719x_reset(cmd, WD719X_CMD_RESET, cmd->device->id);
+}
+
+static int wd719x_bus_reset(struct scsi_cmnd *cmd)
+{
+ return wd719x_reset(cmd, WD719X_CMD_BUSRESET, 0);
+}
+
+static int wd719x_host_reset(struct scsi_cmnd *cmd)
+{
+ struct wd719x *wd = shost_priv(cmd->device->host);
+ struct wd719x_scb *scb, *tmp;
+ unsigned long flags;
+ int result;
+
+ dev_info(&wd->pdev->dev, "host reset requested\n");
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+ /* Try to reinit the RISC */
+ if (wd719x_chip_init(wd) == 0)
+ result = SUCCESS;
+ else
+ result = FAILED;
+
+ /* flush all SCBs */
+ list_for_each_entry_safe(scb, tmp, &wd->active_scbs, list) {
+ struct scsi_cmnd *tmp_cmd = scb->cmd;
+ wd719x_finish_cmd(tmp_cmd, result);
+ }
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+
+ return result;
+}
+
+static int wd719x_biosparam(struct scsi_device *sdev, struct block_device *bdev,
+ sector_t capacity, int geom[])
+{
+ if (capacity >= 0x200000) {
+ geom[0] = 255; /* heads */
+ geom[1] = 63; /* sectors */
+ } else {
+ geom[0] = 64; /* heads */
+ geom[1] = 32; /* sectors */
+ }
+ geom[2] = sector_div(capacity, geom[0] * geom[1]); /* cylinders */
+
+ return 0;
+}
+
+/* process a SCB-completion interrupt */
+static inline void wd719x_interrupt_SCB(struct wd719x *wd,
+ union wd719x_regs regs,
+ struct wd719x_scb *scb)
+{
+ struct scsi_cmnd *cmd;
+ int result;
+
+ /* now have to find result from card */
+ switch (regs.bytes.SUE) {
+ case WD719X_SUE_NOERRORS:
+ result = DID_OK;
+ break;
+ case WD719X_SUE_REJECTED:
+ dev_err(&wd->pdev->dev, "command rejected\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_SCBQFULL:
+ dev_err(&wd->pdev->dev, "SCB queue is full\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_TERM:
+ dev_dbg(&wd->pdev->dev, "SCB terminated by direct command\n");
+ result = DID_ABORT; /* or DID_RESET? */
+ break;
+ case WD719X_SUE_CHAN1ABORT:
+ case WD719X_SUE_CHAN23ABORT:
+ result = DID_ABORT;
+ dev_err(&wd->pdev->dev, "DMA abort\n");
+ break;
+ case WD719X_SUE_CHAN1PAR:
+ case WD719X_SUE_CHAN23PAR:
+ result = DID_PARITY;
+ dev_err(&wd->pdev->dev, "DMA parity error\n");
+ break;
+ case WD719X_SUE_TIMEOUT:
+ result = DID_TIME_OUT;
+ dev_dbg(&wd->pdev->dev, "selection timeout\n");
+ break;
+ case WD719X_SUE_RESET:
+ dev_dbg(&wd->pdev->dev, "bus reset occured\n");
+ result = DID_RESET;
+ break;
+ case WD719X_SUE_BUSERROR:
+ dev_dbg(&wd->pdev->dev, "SCSI bus error\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_WRONGWAY:
+ dev_err(&wd->pdev->dev, "wrong data transfer direction\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_BADPHASE:
+ dev_err(&wd->pdev->dev, "invalid SCSI phase\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_TOOLONG:
+ dev_err(&wd->pdev->dev, "record too long\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_BUSFREE:
+ dev_err(&wd->pdev->dev, "unexpected bus free\n");
+ result = DID_NO_CONNECT; /* or DID_ERROR ???*/
+ break;
+ case WD719X_SUE_ARSDONE:
+ dev_dbg(&wd->pdev->dev, "auto request sense\n");
+ if (regs.bytes.SCSI == 0)
+ result = DID_OK;
+ else
+ result = DID_PARITY;
+ break;
+ case WD719X_SUE_IGNORED:
+ dev_err(&wd->pdev->dev, "target id %d ignored command\n",
+ scb->cmd->device->id);
+ result = DID_NO_CONNECT;
+ break;
+ case WD719X_SUE_WRONGTAGS:
+ dev_err(&wd->pdev->dev, "reversed tags\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_BADTAGS:
+ dev_err(&wd->pdev->dev, "tag type not supported by target\n");
+ result = DID_ERROR;
+ break;
+ case WD719X_SUE_NOSCAMID:
+ dev_err(&wd->pdev->dev, "no SCAM soft ID available\n");
+ result = DID_ERROR;
+ break;
+ default:
+ dev_warn(&wd->pdev->dev, "unknown SUE error code: 0x%x\n",
+ regs.bytes.SUE);
+ result = DID_ERROR;
+ break;
+ }
+ cmd = scb->cmd;
+
+ wd719x_finish_cmd(cmd, result);
+}
+
+static irqreturn_t wd719x_interrupt(int irq, void *dev_id)
+{
+ struct wd719x *wd = dev_id;
+ union wd719x_regs regs;
+ unsigned long flags;
+ u32 SCB_out;
+
+ spin_lock_irqsave(wd->sh->host_lock, flags);
+ /* read SCB pointer back from card */
+ SCB_out = wd719x_readl(wd, WD719X_AMR_SCB_OUT);
+ /* read all status info at once */
+ regs.all = cpu_to_le32(wd719x_readl(wd, WD719X_AMR_OP_CODE));
+
+ switch (regs.bytes.INT) {
+ case WD719X_INT_NONE:
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+ return IRQ_NONE;
+ case WD719X_INT_LINKNOSTATUS:
+ dev_err(&wd->pdev->dev, "linked command completed with no status\n");
+ break;
+ case WD719X_INT_BADINT:
+ dev_err(&wd->pdev->dev, "unsolicited interrupt\n");
+ break;
+ case WD719X_INT_NOERRORS:
+ case WD719X_INT_LINKNOERRORS:
+ case WD719X_INT_ERRORSLOGGED:
+ case WD719X_INT_SPIDERFAILED:
+ /* was the cmd completed a direct or SCB command? */
+ if (regs.bytes.OPC == WD719X_CMD_PROCESS_SCB) {
+ struct wd719x_scb *scb;
+ list_for_each_entry(scb, &wd->active_scbs, list)
+ if (SCB_out == scb->phys)
+ break;
+ if (SCB_out == scb->phys)
+ wd719x_interrupt_SCB(wd, regs, scb);
+ else
+ dev_err(&wd->pdev->dev, "card returned invalid SCB pointer\n");
+ } else
+ dev_warn(&wd->pdev->dev, "direct command 0x%x completed\n",
+ regs.bytes.OPC);
+ break;
+ case WD719X_INT_PIOREADY:
+ dev_err(&wd->pdev->dev, "card indicates PIO data ready but we never use PIO\n");
+ /* interrupt will not be cleared until all data is read */
+ break;
+ default:
+ dev_err(&wd->pdev->dev, "unknown interrupt reason: %d\n",
+ regs.bytes.INT);
+
+ }
+ /* clear interrupt so another can happen */
+ wd719x_writeb(wd, WD719X_AMR_INT_STATUS, WD719X_INT_NONE);
+ spin_unlock_irqrestore(wd->sh->host_lock, flags);
+
+ return IRQ_HANDLED;
+}
+
+static void wd719x_eeprom_reg_read(struct eeprom_93cx6 *eeprom)
+{
+ struct wd719x *wd = eeprom->data;
+ u8 reg = wd719x_readb(wd, WD719X_PCI_GPIO_DATA);
+
+ eeprom->reg_data_out = reg & WD719X_EE_DO;
+}
+
+static void wd719x_eeprom_reg_write(struct eeprom_93cx6 *eeprom)
+{
+ struct wd719x *wd = eeprom->data;
+ u8 reg = 0;
+
+ if (eeprom->reg_data_in)
+ reg |= WD719X_EE_DI;
+ if (eeprom->reg_data_clock)
+ reg |= WD719X_EE_CLK;
+ if (eeprom->reg_chip_select)
+ reg |= WD719X_EE_CS;
+
+ wd719x_writeb(wd, WD719X_PCI_GPIO_DATA, reg);
+}
+
+/* read config from EEPROM so it can be downloaded by the RISC on (re-)init */
+static void wd719x_read_eeprom(struct wd719x *wd)
+{
+ struct eeprom_93cx6 eeprom;
+ u8 gpio;
+ struct wd719x_eeprom_header header;
+
+ eeprom.data = wd;
+ eeprom.register_read = wd719x_eeprom_reg_read;
+ eeprom.register_write = wd719x_eeprom_reg_write;
+ eeprom.width = PCI_EEPROM_WIDTH_93C46;
+
+ /* set all outputs to low */
+ wd719x_writeb(wd, WD719X_PCI_GPIO_DATA, 0);
+ /* configure GPIO pins */
+ gpio = wd719x_readb(wd, WD719X_PCI_GPIO_CONTROL);
+ /* GPIO outputs */
+ gpio &= (~(WD719X_EE_CLK | WD719X_EE_DI | WD719X_EE_CS));
+ /* GPIO input */
+ gpio |= WD719X_EE_DO;
+ wd719x_writeb(wd, WD719X_PCI_GPIO_CONTROL, gpio);
+
+ /* read EEPROM header */
+ eeprom_93cx6_multireadb(&eeprom, 0, (u8 *)&header, sizeof(header));
+
+ if (header.sig1 == 'W' && header.sig2 == 'D')
+ eeprom_93cx6_multireadb(&eeprom, header.cfg_offset,
+ (u8 *)wd->params,
+ sizeof(struct wd719x_host_param));
+ else { /* default EEPROM values */
+ dev_warn(&wd->pdev->dev, "EEPROM signature is invalid (0x%02x 0x%02x), using default values\n",
+ header.sig1, header.sig2);
+ wd->params->ch_1_th = 0x10; /* 16 DWs = 64 B */
+ wd->params->scsi_conf = 0x4c; /* 48ma, spue, parity check */
+ wd->params->own_scsi_id = 0x07; /* ID 7, SCAM disabled */
+ wd->params->sel_timeout = 0x4d; /* 250 ms */
+ wd->params->sleep_timer = 0x01;
+ wd->params->cdb_size = cpu_to_le16(0x5555); /* all 6 B */
+ wd->params->scsi_pad = 0x1b;
+ if (wd->type == WD719X_TYPE_7193) /* narrow card - disable */
+ wd->params->wide = cpu_to_le32(0x00000000);
+ else /* initiate & respond to WIDE messages */
+ wd->params->wide = cpu_to_le32(0xffffffff);
+ wd->params->sync = cpu_to_le32(0xffffffff);
+ wd->params->soft_mask = 0x00; /* all disabled */
+ wd->params->unsol_mask = 0x00; /* all disabled */
+ }
+ /* disable TAGGED messages */
+ wd->params->tag_en = cpu_to_le16(0x0000);
+}
+
+/* Read card type from GPIO bits 1 and 3 */
+static enum wd719x_card_type wd719x_detect_type(struct wd719x *wd)
+{
+ u8 card = wd719x_readb(wd, WD719X_PCI_GPIO_CONTROL);
+
+ card |= WD719X_GPIO_ID_BITS;
+ wd719x_writeb(wd, WD719X_PCI_GPIO_CONTROL, card);
+ card = wd719x_readb(wd, WD719X_PCI_GPIO_DATA) & WD719X_GPIO_ID_BITS;
+ switch (card) {
+ case 0x08:
+ return WD719X_TYPE_7193;
+ case 0x02:
+ return WD719X_TYPE_7197;
+ case 0x00:
+ return WD719X_TYPE_7296;
+ default:
+ dev_warn(&wd->pdev->dev, "unknown card type 0x%x\n", card);
+ return WD719X_TYPE_UNKNOWN;
+ }
+}
+
+static int wd719x_board_found(struct Scsi_Host *sh)
+{
+ struct wd719x *wd = shost_priv(sh);
+ char *card_types[] = { "Unknown card", "WD7193", "WD7197", "WD7296" };
+ int ret;
+
+ INIT_LIST_HEAD(&wd->active_scbs);
+ INIT_LIST_HEAD(&wd->free_scbs);
+
+ sh->base = pci_resource_start(wd->pdev, 0);
+
+ wd->type = wd719x_detect_type(wd);
+
+ wd->sh = sh;
+ sh->irq = wd->pdev->irq;
+ wd->fw_virt = NULL;
+
+ /* memory area for host (EEPROM) parameters */
+ wd->params = pci_alloc_consistent(wd->pdev,
+ sizeof(struct wd719x_host_param),
+ &wd->params_phys);
+ if (!wd->params) {
+ dev_warn(&wd->pdev->dev, "unable to allocate parameter buffer\n");
+ return -ENOMEM;
+ }
+
+ /* memory area for the RISC for hash table of outstanding requests */
+ wd->hash_virt = pci_alloc_consistent(wd->pdev, WD719X_HASH_TABLE_SIZE,
+ &wd->hash_phys);
+ if (!wd->hash_virt) {
+ dev_warn(&wd->pdev->dev, "unable to allocate hash buffer\n");
+ ret = -ENOMEM;
+ goto fail_free_params;
+ }
+
+ ret = request_irq(wd->pdev->irq, wd719x_interrupt, IRQF_SHARED,
+ "wd719x", wd);
+ if (ret) {
+ dev_warn(&wd->pdev->dev, "unable to assign IRQ %d\n",
+ wd->pdev->irq);
+ goto fail_free_hash;
+ }
+
+ /* read parameters from EEPROM */
+ wd719x_read_eeprom(wd);
+
+ ret = wd719x_chip_init(wd);
+ if (ret)
+ goto fail_free_irq;
+
+ sh->this_id = wd->params->own_scsi_id & WD719X_EE_SCSI_ID_MASK;
+
+ dev_info(&wd->pdev->dev, "%s at I/O 0x%lx, IRQ %u, SCSI ID %d\n",
+ card_types[wd->type], sh->base, sh->irq, sh->this_id);
+
+ return 0;
+
+fail_free_irq:
+ free_irq(wd->pdev->irq, wd);
+fail_free_hash:
+ pci_free_consistent(wd->pdev, WD719X_HASH_TABLE_SIZE, wd->hash_virt,
+ wd->hash_phys);
+fail_free_params:
+ pci_free_consistent(wd->pdev, sizeof(struct wd719x_host_param),
+ wd->params, wd->params_phys);
+
+ return ret;
+}
+
+static struct scsi_host_template wd719x_template = {
+ .name = "Western Digital 719x",
+ .queuecommand = wd719x_queuecommand,
+ .eh_abort_handler = wd719x_abort,
+ .eh_device_reset_handler = wd719x_dev_reset,
+ .eh_bus_reset_handler = wd719x_bus_reset,
+ .eh_host_reset_handler = wd719x_host_reset,
+ .bios_param = wd719x_biosparam,
+ .proc_name = "wd719x",
+ .can_queue = 255,
+ .this_id = 7,
+ .sg_tablesize = WD719X_SG,
+ .cmd_per_lun = WD719X_CMD_PER_LUN,
+ .use_clustering = ENABLE_CLUSTERING,
+};
+
+static int wd719x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *d)
+{
+ int err;
+ struct Scsi_Host *sh;
+ struct wd719x *wd;
+
+ err = pci_enable_device(pdev);
+ if (err)
+ goto fail;
+
+ if (pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
+ dev_warn(&pdev->dev, "Unable to set 32-bit DMA mask\n");
+ goto disable_device;
+ }
+
+ err = pci_request_regions(pdev, "wd719x");
+ if (err)
+ goto disable_device;
+ pci_set_master(pdev);
+
+ err = -ENODEV;
+ if (pci_resource_len(pdev, 0) == 0)
+ goto release_region;
+
+ err = -ENOMEM;
+ sh = scsi_host_alloc(&wd719x_template, sizeof(struct wd719x));
+ if (!sh)
+ goto release_region;
+
+ wd = shost_priv(sh);
+ wd->base = pci_iomap(pdev, 0, 0);
+ if (!wd->base)
+ goto free_host;
+ wd->pdev = pdev;
+
+ err = wd719x_board_found(sh);
+ if (err)
+ goto unmap;
+
+ err = scsi_add_host(sh, &wd->pdev->dev);
+ if (err)
+ goto destroy;
+
+ scsi_scan_host(sh);
+
+ pci_set_drvdata(pdev, sh);
+ return 0;
+
+destroy:
+ wd719x_destroy(wd);
+unmap:
+ pci_iounmap(pdev, wd->base);
+free_host:
+ scsi_host_put(sh);
+release_region:
+ pci_release_regions(pdev);
+disable_device:
+ pci_disable_device(pdev);
+fail:
+ return err;
+}
+
+
+static void wd719x_pci_remove(struct pci_dev *pdev)
+{
+ struct Scsi_Host *sh = pci_get_drvdata(pdev);
+ struct wd719x *wd = shost_priv(sh);
+
+ scsi_remove_host(sh);
+ wd719x_destroy(wd);
+ pci_iounmap(pdev, wd->base);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+
+ scsi_host_put(sh);
+}
+
+static DEFINE_PCI_DEVICE_TABLE(wd719x_pci_table) = {
+ { PCI_DEVICE(PCI_VENDOR_ID_WD, 0x3296) },
+ {}
+};
+
+MODULE_DEVICE_TABLE(pci, wd719x_pci_table);
+
+static struct pci_driver wd719x_pci_driver = {
+ .name = "wd719x",
+ .id_table = wd719x_pci_table,
+ .probe = wd719x_pci_probe,
+ .remove = wd719x_pci_remove,
+};
+
+static int __init wd719x_init(void)
+{
+ return pci_register_driver(&wd719x_pci_driver);
+}
+
+static void __exit wd719x_exit(void)
+{
+ pci_unregister_driver(&wd719x_pci_driver);
+}
+
+module_init(wd719x_init);
+module_exit(wd719x_exit);
+
+MODULE_DESCRIPTION("Western Digital WD7193/7197/7296 SCSI driver");
+MODULE_AUTHOR("Ondrej Zary, Aaron Dewell, Juergen Gaertner");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE("wd719x-wcs.bin");
+MODULE_FIRMWARE("wd719x-risc.bin");
diff --git a/drivers/scsi/wd719x.h b/drivers/scsi/wd719x.h
new file mode 100644
index 0000000..185e30e
--- /dev/null
+++ b/drivers/scsi/wd719x.h
@@ -0,0 +1,249 @@
+#ifndef _WD719X_H_
+#define _WD719X_H_
+
+#define WD719X_SG 255 /* Scatter/gather size */
+#define WD719X_CMD_PER_LUN 1 /* We should be able to do linked commands, but
+ * this is 1 for now to be safe. */
+
+struct wd719x_sglist {
+ __le32 ptr;
+ __le32 length;
+} __packed;
+
+enum wd719x_card_type {
+ WD719X_TYPE_UNKNOWN = 0,
+ WD719X_TYPE_7193,
+ WD719X_TYPE_7197,
+ WD719X_TYPE_7296,
+};
+
+union wd719x_regs {
+ __le32 all; /* All Status at once */
+ struct {
+ u8 OPC; /* Opcode register */
+ u8 SCSI; /* SCSI Errors */
+ u8 SUE; /* Spider unique Errors */
+ u8 INT; /* Interrupt Status */
+ } bytes;
+};
+
+/* Spider Command Block (SCB) */
+struct wd719x_scb {
+ __le32 Int_SCB; /* 00-03 Internal SCB link pointer (must be cleared) */
+ u8 SCB_opcode; /* 04 SCB Command opcode */
+ u8 CDB_tag; /* 05 SCSI Tag byte for CDB queues (0 if untagged) */
+ u8 lun; /* 06 SCSI LUN */
+ u8 devid; /* 07 SCSI Device ID */
+ u8 CDB[16]; /* 08-23 SCSI CDB (16 bytes as defined by ANSI spec. */
+ __le32 data_p; /* 24-27 Data transfer address (or SG list address) */
+ __le32 data_length; /* 28-31 Data transfer Length (or SG list length) */
+ __le32 CDB_link; /* 32-35 SCSI CDB Link Ptr */
+ __le32 sense_buf; /* 36-39 Auto request sense buffer address */
+ u8 sense_buf_length;/* 40 Auto request sense transfer length */
+ u8 reserved; /* 41 reserved */
+ u8 SCB_options; /* 42 SCB-options */
+ u8 SCB_tag_msg; /* 43 Tagged messages options */
+ /* Not filled in by host */
+ __le32 req_ptr; /* 44-47 Ptr to Host Request returned on interrupt */
+ u8 host_opcode; /* 48 Host Command Opcode (same as AMR_00) */
+ u8 scsi_stat; /* 49 SCSI Status returned */
+ u8 ret_error; /* 50 SPIDER Unique Error Code returned (SUE) */
+ u8 int_stat; /* 51 Message u8 / Interrupt Status byte returned */
+ __le32 transferred; /* 52-55 Bytes Transferred */
+ u8 last_trans[3]; /* 56-58 Bytes Transferred in last session */
+ u8 length; /* 59 SCSI Messages Length (1-8) */
+ u8 sync_offset; /* 60 Synchronous offset */
+ u8 sync_rate; /* 61 Synchronous rate */
+ u8 flags[2]; /* 62-63 SCB specific flags (local to each thread) */
+ /* everything below is for driver use (not used by card) */
+ dma_addr_t phys; /* bus address of the SCB */
+ struct scsi_cmnd *cmd; /* a copy of the pointer we were passed */
+ struct list_head list;
+ struct wd719x_sglist sg_list[WD719X_SG] __aligned(8); /* SG list */
+} __packed;
+
+struct wd719x {
+ struct Scsi_Host *sh; /* pointer to host structure */
+ struct pci_dev *pdev;
+ void __iomem *base;
+ enum wd719x_card_type type; /* type of card */
+ void *fw_virt; /* firmware buffer CPU address */
+ dma_addr_t fw_phys; /* firmware buffer bus address */
+ size_t fw_size; /* firmware buffer size */
+ struct wd719x_host_param *params; /* host parameters (EEPROM) */
+ dma_addr_t params_phys; /* host parameters bus address */
+ void *hash_virt; /* hash table CPU address */
+ dma_addr_t hash_phys; /* hash table bus address */
+ struct list_head active_scbs;
+ struct list_head free_scbs;
+};
+
+/* timeout delays in microsecs */
+#define WD719X_WAIT_FOR_CMD_READY 500
+#define WD719X_WAIT_FOR_RISC 2000
+#define WD719X_WAIT_FOR_SCSI_RESET 3000000
+
+/* All commands except 0x00 generate an interrupt */
+#define WD719X_CMD_READY 0x00 /* Command register ready (or noop) */
+#define WD719X_CMD_INIT_RISC 0x01 /* Initialize RISC */
+/* 0x02 is reserved */
+#define WD719X_CMD_BUSRESET 0x03 /* Assert SCSI bus reset */
+#define WD719X_CMD_READ_FIRMVER 0x04 /* Read the Firmware Revision */
+#define WD719X_CMD_ECHO_BYTES 0x05 /* Echo command bytes (DW) */
+/* 0x06 is reserved */
+/* 0x07 is reserved */
+#define WD719X_CMD_GET_PARAM 0x08 /* Get programmable parameters */
+#define WD719X_CMD_SET_PARAM 0x09 /* Set programmable parameters */
+#define WD719X_CMD_SLEEP 0x0a /* Put SPIDER to sleep */
+#define WD719X_CMD_READ_INIT 0x0b /* Read initialization parameters */
+#define WD719X_CMD_RESTORE_INIT 0x0c /* Restore initialization parameters */
+/* 0x0d is reserved */
+/* 0x0e is reserved */
+/* 0x0f is reserved */
+#define WD719X_CMD_ABORT_TAG 0x10 /* Send Abort tag message to target */
+#define WD719X_CMD_ABORT 0x11 /* Send Abort message to target */
+#define WD719X_CMD_RESET 0x12 /* Send Reset message to target */
+#define WD719X_CMD_INIT_SCAM 0x13 /* Initiate SCAM */
+#define WD719X_CMD_GET_SYNC 0x14 /* Get synchronous rates */
+#define WD719X_CMD_SET_SYNC 0x15 /* Set synchronous rates */
+#define WD719X_CMD_GET_WIDTH 0x16 /* Get SCSI bus width */
+#define WD719X_CMD_SET_WIDTH 0x17 /* Set SCSI bus width */
+#define WD719X_CMD_GET_TAGS 0x18 /* Get tag flags */
+#define WD719X_CMD_SET_TAGS 0x19 /* Set tag flags */
+#define WD719X_CMD_GET_PARAM2 0x1a /* Get programmable params (format 2) */
+#define WD719X_CMD_SET_PARAM2 0x1b /* Set programmable params (format 2) */
+/* Commands with request pointers (mailbox) */
+#define WD719X_CMD_PROCESS_SCB 0x80 /* Process SCSI Control Block (SCB) */
+/* No interrupt generated on acceptance of SCB pointer */
+
+/* interrupt status defines */
+#define WD719X_INT_NONE 0x00 /* No interrupt pending */
+#define WD719X_INT_NOERRORS 0x01 /* Command completed with no errors */
+#define WD719X_INT_LINKNOERRORS 0x02 /* link cmd completed with no errors */
+#define WD719X_INT_LINKNOSTATUS 0x03 /* link cmd completed with no flag set */
+#define WD719X_INT_ERRORSLOGGED 0x04 /* cmd completed with errors logged */
+#define WD719X_INT_SPIDERFAILED 0x05 /* cmd failed without valid SCSI status */
+#define WD719X_INT_BADINT 0x80 /* unsolicited interrupt */
+#define WD719X_INT_PIOREADY 0xf0 /* data ready for PIO output */
+
+/* Spider Unique Error Codes (SUE) */
+#define WD719X_SUE_NOERRORS 0x00 /* No errors detected by SPIDER */
+#define WD719X_SUE_REJECTED 0x01 /* Command Rejected (bad opcode/param) */
+#define WD719X_SUE_SCBQFULL 0x02 /* SCB queue full */
+/* 0x03 is reserved */
+#define WD719X_SUE_TERM 0x04 /* Host terminated SCB via primative cmd */
+#define WD719X_SUE_CHAN1PAR 0x05 /* PCI Channel 1 parity error occurred */
+#define WD719X_SUE_CHAN1ABORT 0x06 /* PCI Channel 1 system abort occurred */
+#define WD719X_SUE_CHAN23PAR 0x07 /* PCI Channel 2/3 parity error occurred */
+#define WD719X_SUE_CHAN23ABORT 0x08 /* PCI Channel 2/3 system abort occurred */
+#define WD719X_SUE_TIMEOUT 0x10 /* Selection/reselection timeout */
+#define WD719X_SUE_RESET 0x11 /* SCSI bus reset occurred */
+#define WD719X_SUE_BUSERROR 0x12 /* SCSI bus error */
+#define WD719X_SUE_WRONGWAY 0x13 /* Wrong data transfer dir set by target */
+#define WD719X_SUE_BADPHASE 0x14 /* SCSI phase illegal or unexpected */
+#define WD719X_SUE_TOOLONG 0x15 /* target requested too much data */
+#define WD719X_SUE_BUSFREE 0x16 /* Unexpected SCSI bus free */
+#define WD719X_SUE_ARSDONE 0x17 /* Auto request sense executed */
+#define WD719X_SUE_IGNORED 0x18 /* SCSI message was ignored by target */
+#define WD719X_SUE_WRONGTAGS 0x19 /* Tagged SCB & tags off (or vice versa) */
+#define WD719X_SUE_BADTAGS 0x1a /* Wrong tag message type for target */
+#define WD719X_SUE_NOSCAMID 0x1b /* No SCAM soft ID available */
+
+/* code sizes */
+#define WD719X_HASH_TABLE_SIZE 4096
+
+/* Advanced Mode Registers */
+/* Regs 0x00..0x1f are for Advanced Mode of the card (RISC is running). */
+#define WD719X_AMR_COMMAND 0x00
+#define WD719X_AMR_CMD_PARAM 0x01
+#define WD719X_AMR_CMD_PARAM_2 0x02
+#define WD719X_AMR_CMD_PARAM_3 0x03
+#define WD719X_AMR_SCB_IN 0x04
+
+#define WD719X_AMR_BIOS_SHARE_INT 0x0f
+
+#define WD719X_AMR_SCB_OUT 0x18
+#define WD719X_AMR_OP_CODE 0x1c
+#define WD719X_AMR_SCSI_STATUS 0x1d
+#define WD719X_AMR_SCB_ERROR 0x1e
+#define WD719X_AMR_INT_STATUS 0x1f
+
+#define WD719X_DISABLE_INT 0x80
+
+/* SCB flags */
+#define WD719X_SCB_FLAGS_CHECK_DIRECTION 0x01
+#define WD719X_SCB_FLAGS_PCI_TO_SCSI 0x02
+#define WD719X_SCB_FLAGS_AUTO_REQUEST_SENSE 0x10
+#define WD719X_SCB_FLAGS_DO_SCATTER_GATHER 0x20
+#define WD719X_SCB_FLAGS_NO_DISCONNECT 0x40
+
+/* PCI Registers used for reset, initial code download */
+/* Regs 0x20..0x3f are for Normal (DOS) mode (RISC is asleep). */
+#define WD719X_PCI_GPIO_CONTROL 0x3C
+#define WD719X_PCI_GPIO_DATA 0x3D
+#define WD719X_PCI_PORT_RESET 0x3E
+#define WD719X_PCI_MODE_SELECT 0x3F
+
+#define WD719X_PCI_EXTERNAL_ADDR 0x60
+#define WD719X_PCI_INTERNAL_ADDR 0x64
+#define WD719X_PCI_DMA_TRANSFER_SIZE 0x66
+#define WD719X_PCI_CHANNEL2_3CMD 0x68
+#define WD719X_PCI_CHANNEL2_3STATUS 0x69
+
+#define WD719X_GPIO_ID_BITS 0x0a
+#define WD719X_PRAM_BASE_ADDR 0x00
+
+/* codes written to or read from the card */
+#define WD719X_PCI_RESET 0x01
+#define WD719X_ENABLE_ADVANCE_MODE 0x01
+
+#define WD719X_START_CHANNEL2_3DMA 0x17
+#define WD719X_START_CHANNEL2_3DONE 0x01
+#define WD719X_START_CHANNEL2_3ABORT 0x20
+
+/* 33C296 GPIO bits for EEPROM pins */
+#define WD719X_EE_DI (1 << 1)
+#define WD719X_EE_CS (1 << 2)
+#define WD719X_EE_CLK (1 << 3)
+#define WD719X_EE_DO (1 << 4)
+
+/* EEPROM contents */
+struct wd719x_eeprom_header {
+ u8 sig1;
+ u8 sig2;
+ u8 version;
+ u8 checksum;
+ u8 cfg_offset;
+ u8 cfg_size;
+ u8 setup_offset;
+ u8 setup_size;
+} __packed;
+
+#define WD719X_EE_SIG1 0
+#define WD719X_EE_SIG2 1
+#define WD719X_EE_VERSION 2
+#define WD719X_EE_CHECKSUM 3
+#define WD719X_EE_CFG_OFFSET 4
+#define WD719X_EE_CFG_SIZE 5
+#define WD719X_EE_SETUP_OFFSET 6
+#define WD719X_EE_SETUP_SIZE 7
+
+#define WD719X_EE_SCSI_ID_MASK 0xf
+
+/* SPIDER Host Parameters Block (=EEPROM configuration block) */
+struct wd719x_host_param {
+ u8 ch_1_th; /* FIFO threshold */
+ u8 scsi_conf; /* SCSI configuration */
+ u8 own_scsi_id; /* controller SCSI ID */
+ u8 sel_timeout; /* selection timeout*/
+ u8 sleep_timer; /* seep timer */
+ __le16 cdb_size;/* CDB size groups */
+ __le16 tag_en; /* Tag msg enables (ID 0-15) */
+ u8 scsi_pad; /* SCSI pad control */
+ __le32 wide; /* WIDE msg options (ID 0-15) */
+ __le32 sync; /* SYNC msg options (ID 0-15) */
+ u8 soft_mask; /* soft error mask */
+ u8 unsol_mask; /* unsolicited error mask */
+} __packed;
+
+#endif /* _WD719X_H_ */
diff --git a/drivers/sh/pm_runtime.c b/drivers/sh/pm_runtime.c
index fe2c2d5..f3ee439d 100644
--- a/drivers/sh/pm_runtime.c
+++ b/drivers/sh/pm_runtime.c
@@ -20,7 +20,7 @@
#include <linux/bitmap.h>
#include <linux/slab.h>
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int sh_pm_runtime_suspend(struct device *dev)
{
int ret;
@@ -68,7 +68,7 @@ static struct dev_pm_domain default_pm_domain = {
#define DEFAULT_PM_DOMAIN_PTR NULL
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
static struct pm_clk_notifier_block platform_bus_notifier = {
.pm_domain = DEFAULT_PM_DOMAIN_PTR,
diff --git a/drivers/soc/ti/knav_qmss.h b/drivers/soc/ti/knav_qmss.h
index bc9dcc8..51da234 100644
--- a/drivers/soc/ti/knav_qmss.h
+++ b/drivers/soc/ti/knav_qmss.h
@@ -348,15 +348,15 @@ struct knav_range_info {
list_for_each_entry(region, &kdev->regions, list)
#define first_region(kdev) \
- list_first_entry(&kdev->regions, \
- struct knav_region, list)
+ list_first_entry_or_null(&kdev->regions, \
+ struct knav_region, list)
#define for_each_queue_range(kdev, range) \
list_for_each_entry(range, &kdev->queue_ranges, list)
#define first_queue_range(kdev) \
- list_first_entry(&kdev->queue_ranges, \
- struct knav_range_info, list)
+ list_first_entry_or_null(&kdev->queue_ranges, \
+ struct knav_range_info, list)
#define for_each_pool(kdev, pool) \
list_for_each_entry(pool, &kdev->pools, list)
diff --git a/drivers/soc/ti/knav_qmss_queue.c b/drivers/soc/ti/knav_qmss_queue.c
index 0a2c863..9b8dd67 100644
--- a/drivers/soc/ti/knav_qmss_queue.c
+++ b/drivers/soc/ti/knav_qmss_queue.c
@@ -785,7 +785,7 @@ void *knav_pool_create(const char *name,
dev_err(kdev->dev, "out of descs in region(%d) for pool(%s)\n",
region_id, name);
ret = -ENOMEM;
- goto err;
+ goto err_unlock;
}
/* Region maintains a sorted (by region offset) list of pools
@@ -815,15 +815,16 @@ void *knav_pool_create(const char *name,
dev_err(kdev->dev, "pool(%s) create failed: fragmented desc pool in region(%d)\n",
name, region_id);
ret = -ENOMEM;
- goto err;
+ goto err_unlock;
}
mutex_unlock(&knav_dev_lock);
kdesc_fill_pool(pool);
return pool;
-err:
+err_unlock:
mutex_unlock(&knav_dev_lock);
+err:
kfree(pool->name);
devm_kfree(kdev->dev, pool);
return ERR_PTR(ret);
@@ -1305,14 +1306,14 @@ static void knav_free_queue_ranges(struct knav_device *kdev)
static void knav_queue_free_regions(struct knav_device *kdev)
{
struct knav_region *region;
- struct knav_pool *pool;
+ struct knav_pool *pool, *tmp;
unsigned size;
for (;;) {
region = first_region(kdev);
if (!region)
break;
- list_for_each_entry(pool, &region->pools, region_inst)
+ list_for_each_entry_safe(pool, tmp, &region->pools, region_inst)
knav_pool_destroy(pool);
size = region->virt_end - region->virt_start;
@@ -1639,7 +1640,7 @@ static int knav_queue_init_queues(struct knav_device *kdev)
size = (1 << kdev->inst_shift) * kdev->num_queues_in_use;
kdev->instances = devm_kzalloc(kdev->dev, size, GFP_KERNEL);
if (!kdev->instances)
- return -1;
+ return -ENOMEM;
for_each_queue_range(kdev, range) {
if (range->ops && range->ops->init_range)
diff --git a/drivers/soc/versatile/Kconfig b/drivers/soc/versatile/Kconfig
index bf5ee9c..a928a7f 100644
--- a/drivers/soc/versatile/Kconfig
+++ b/drivers/soc/versatile/Kconfig
@@ -1,6 +1,15 @@
#
# ARM Versatile SoC drivers
#
+config SOC_INTEGRATOR_CM
+ bool "SoC bus device for the ARM Integrator platform core modules"
+ depends on ARCH_INTEGRATOR
+ select SOC_BUS
+ help
+ Include support for the SoC bus on the ARM Integrator platform
+ core modules providing some sysfs information about the ASIC
+ variant.
+
config SOC_REALVIEW
bool "SoC bus device for the ARM RealView platforms"
depends on ARCH_REALVIEW
diff --git a/drivers/soc/versatile/Makefile b/drivers/soc/versatile/Makefile
index ad54743..cf612fe 100644
--- a/drivers/soc/versatile/Makefile
+++ b/drivers/soc/versatile/Makefile
@@ -1 +1,2 @@
+obj-$(CONFIG_SOC_INTEGRATOR_CM) += soc-integrator.o
obj-$(CONFIG_SOC_REALVIEW) += soc-realview.o
diff --git a/drivers/soc/versatile/soc-integrator.c b/drivers/soc/versatile/soc-integrator.c
new file mode 100644
index 0000000..a5d7d39
--- /dev/null
+++ b/drivers/soc/versatile/soc-integrator.c
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Linus Walleij <linus.walleij@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2, as
+ * published by the Free Software Foundation.
+ *
+ */
+#include <linux/init.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/sys_soc.h>
+#include <linux/platform_device.h>
+#include <linux/mfd/syscon.h>
+#include <linux/regmap.h>
+#include <linux/of.h>
+
+#define INTEGRATOR_HDR_ID_OFFSET 0x00
+
+static u32 integrator_coreid;
+
+static const struct of_device_id integrator_cm_match[] = {
+ { .compatible = "arm,core-module-integrator", },
+ { }
+};
+
+static const char *integrator_arch_str(u32 id)
+{
+ switch ((id >> 16) & 0xff) {
+ case 0x00:
+ return "ASB little-endian";
+ case 0x01:
+ return "AHB little-endian";
+ case 0x03:
+ return "AHB-Lite system bus, bi-endian";
+ case 0x04:
+ return "AHB";
+ case 0x08:
+ return "AHB system bus, ASB processor bus";
+ default:
+ return "Unknown";
+ }
+}
+
+static const char *integrator_fpga_str(u32 id)
+{
+ switch ((id >> 12) & 0xf) {
+ case 0x01:
+ return "XC4062";
+ case 0x02:
+ return "XC4085";
+ case 0x03:
+ return "XVC600";
+ case 0x04:
+ return "EPM7256AE (Altera PLD)";
+ default:
+ return "Unknown";
+ }
+}
+
+static ssize_t integrator_get_manf(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%02x\n", integrator_coreid >> 24);
+}
+
+static struct device_attribute integrator_manf_attr =
+ __ATTR(manufacturer, S_IRUGO, integrator_get_manf, NULL);
+
+static ssize_t integrator_get_arch(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", integrator_arch_str(integrator_coreid));
+}
+
+static struct device_attribute integrator_arch_attr =
+ __ATTR(arch, S_IRUGO, integrator_get_arch, NULL);
+
+static ssize_t integrator_get_fpga(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%s\n", integrator_fpga_str(integrator_coreid));
+}
+
+static struct device_attribute integrator_fpga_attr =
+ __ATTR(fpga, S_IRUGO, integrator_get_fpga, NULL);
+
+static ssize_t integrator_get_build(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
+{
+ return sprintf(buf, "%02x\n", (integrator_coreid >> 4) & 0xFF);
+}
+
+static struct device_attribute integrator_build_attr =
+ __ATTR(build, S_IRUGO, integrator_get_build, NULL);
+
+static int __init integrator_soc_init(void)
+{
+ static struct regmap *syscon_regmap;
+ struct soc_device *soc_dev;
+ struct soc_device_attribute *soc_dev_attr;
+ struct device_node *np;
+ struct device *dev;
+ u32 val;
+ int ret;
+
+ np = of_find_matching_node(NULL, integrator_cm_match);
+ if (!np)
+ return -ENODEV;
+
+ syscon_regmap = syscon_node_to_regmap(np);
+ if (IS_ERR(syscon_regmap))
+ return PTR_ERR(syscon_regmap);
+
+ ret = regmap_read(syscon_regmap, INTEGRATOR_HDR_ID_OFFSET,
+ &val);
+ if (ret)
+ return -ENODEV;
+ integrator_coreid = val;
+
+ soc_dev_attr = kzalloc(sizeof(*soc_dev_attr), GFP_KERNEL);
+ if (!soc_dev_attr)
+ return -ENOMEM;
+
+ soc_dev_attr->soc_id = "Integrator";
+ soc_dev_attr->machine = "Integrator";
+ soc_dev_attr->family = "Versatile";
+ soc_dev = soc_device_register(soc_dev_attr);
+ if (IS_ERR(soc_dev)) {
+ kfree(soc_dev_attr);
+ return -ENODEV;
+ }
+ dev = soc_device_to_device(soc_dev);
+
+ device_create_file(dev, &integrator_manf_attr);
+ device_create_file(dev, &integrator_arch_attr);
+ device_create_file(dev, &integrator_fpga_attr);
+ device_create_file(dev, &integrator_build_attr);
+
+ dev_info(dev, "Detected ARM core module:\n");
+ dev_info(dev, " Manufacturer: %02x\n", (val >> 24));
+ dev_info(dev, " Architecture: %s\n", integrator_arch_str(val));
+ dev_info(dev, " FPGA: %s\n", integrator_fpga_str(val));
+ dev_info(dev, " Build: %02x\n", (val >> 4) & 0xFF);
+ dev_info(dev, " Rev: %c\n", ('A' + (val & 0x03)));
+
+ return 0;
+}
+device_initcall(integrator_soc_init);
diff --git a/drivers/spi/Kconfig b/drivers/spi/Kconfig
index 84e7c9e..9982998 100644
--- a/drivers/spi/Kconfig
+++ b/drivers/spi/Kconfig
@@ -225,6 +225,13 @@ config SPI_GPIO
GPIO operations, you should be able to leverage that for better
speed with a custom version of this driver; see the source code.
+config SPI_IMG_SPFI
+ tristate "IMG SPFI controller"
+ depends on MIPS || COMPILE_TEST
+ help
+ This enables support for the SPFI master controller found on
+ IMG SoCs.
+
config SPI_IMX
tristate "Freescale i.MX SPI controllers"
depends on ARCH_MXC || COMPILE_TEST
@@ -301,6 +308,14 @@ config SPI_FSL_ESPI
From MPC8536, 85xx platform uses the controller, and all P10xx,
P20xx, P30xx,P40xx, P50xx uses this controller.
+config SPI_MESON_SPIFC
+ tristate "Amlogic Meson SPIFC controller"
+ depends on ARCH_MESON || COMPILE_TEST
+ select REGMAP_MMIO
+ help
+ This enables master mode support for the SPIFC (SPI flash
+ controller) available in Amlogic Meson SoCs.
+
config SPI_OC_TINY
tristate "OpenCores tiny SPI"
depends on GPIOLIB
@@ -444,7 +459,7 @@ config SPI_S3C24XX_FIQ
config SPI_S3C64XX
tristate "Samsung S3C64XX series type SPI"
- depends on PLAT_SAMSUNG
+ depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
select S3C64XX_PL080 if ARCH_S3C64XX
help
SPI driver for Samsung S3C64XX and newer SoCs.
diff --git a/drivers/spi/Makefile b/drivers/spi/Makefile
index 78f24ca..6b9d2ac 100644
--- a/drivers/spi/Makefile
+++ b/drivers/spi/Makefile
@@ -40,8 +40,10 @@ obj-$(CONFIG_SPI_FSL_LIB) += spi-fsl-lib.o
obj-$(CONFIG_SPI_FSL_ESPI) += spi-fsl-espi.o
obj-$(CONFIG_SPI_FSL_SPI) += spi-fsl-spi.o
obj-$(CONFIG_SPI_GPIO) += spi-gpio.o
+obj-$(CONFIG_SPI_IMG_SPFI) += spi-img-spfi.o
obj-$(CONFIG_SPI_IMX) += spi-imx.o
obj-$(CONFIG_SPI_LM70_LLP) += spi-lm70llp.o
+obj-$(CONFIG_SPI_MESON_SPIFC) += spi-meson-spifc.o
obj-$(CONFIG_SPI_MPC512x_PSC) += spi-mpc512x-psc.o
obj-$(CONFIG_SPI_MPC52xx_PSC) += spi-mpc52xx-psc.o
obj-$(CONFIG_SPI_MPC52xx) += spi-mpc52xx.o
diff --git a/drivers/spi/spi-atmel.c b/drivers/spi/spi-atmel.c
index 113c83f..e4193cc 100644
--- a/drivers/spi/spi-atmel.c
+++ b/drivers/spi/spi-atmel.c
@@ -26,6 +26,7 @@
#include <linux/io.h>
#include <linux/gpio.h>
#include <linux/pinctrl/consumer.h>
+#include <linux/pm_runtime.h>
/* SPI register offsets */
#define SPI_CR 0x0000
@@ -191,6 +192,8 @@
#define SPI_DMA_TIMEOUT (msecs_to_jiffies(1000))
+#define AUTOSUSPEND_TIMEOUT 2000
+
struct atmel_spi_dma {
struct dma_chan *chan_rx;
struct dma_chan *chan_tx;
@@ -414,23 +417,6 @@ static int atmel_spi_dma_slave_config(struct atmel_spi *as,
return err;
}
-static bool filter(struct dma_chan *chan, void *pdata)
-{
- struct atmel_spi_dma *sl_pdata = pdata;
- struct at_dma_slave *sl;
-
- if (!sl_pdata)
- return false;
-
- sl = &sl_pdata->dma_slave;
- if (sl->dma_dev == chan->device->dev) {
- chan->private = sl;
- return true;
- } else {
- return false;
- }
-}
-
static int atmel_spi_configure_dma(struct atmel_spi *as)
{
struct dma_slave_config slave_config;
@@ -441,19 +427,24 @@ static int atmel_spi_configure_dma(struct atmel_spi *as)
dma_cap_zero(mask);
dma_cap_set(DMA_SLAVE, mask);
- as->dma.chan_tx = dma_request_slave_channel_compat(mask, filter,
- &as->dma,
- dev, "tx");
- if (!as->dma.chan_tx) {
+ as->dma.chan_tx = dma_request_slave_channel_reason(dev, "tx");
+ if (IS_ERR(as->dma.chan_tx)) {
+ err = PTR_ERR(as->dma.chan_tx);
+ if (err == -EPROBE_DEFER) {
+ dev_warn(dev, "no DMA channel available at the moment\n");
+ return err;
+ }
dev_err(dev,
"DMA TX channel not available, SPI unable to use DMA\n");
err = -EBUSY;
goto error;
}
- as->dma.chan_rx = dma_request_slave_channel_compat(mask, filter,
- &as->dma,
- dev, "rx");
+ /*
+ * No reason to check EPROBE_DEFER here since we have already requested
+ * tx channel. If it fails here, it's for another reason.
+ */
+ as->dma.chan_rx = dma_request_slave_channel(dev, "rx");
if (!as->dma.chan_rx) {
dev_err(dev,
@@ -474,7 +465,7 @@ static int atmel_spi_configure_dma(struct atmel_spi *as)
error:
if (as->dma.chan_rx)
dma_release_channel(as->dma.chan_rx);
- if (as->dma.chan_tx)
+ if (!IS_ERR(as->dma.chan_tx))
dma_release_channel(as->dma.chan_tx);
return err;
}
@@ -482,11 +473,9 @@ error:
static void atmel_spi_stop_dma(struct atmel_spi *as)
{
if (as->dma.chan_rx)
- as->dma.chan_rx->device->device_control(as->dma.chan_rx,
- DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(as->dma.chan_rx);
if (as->dma.chan_tx)
- as->dma.chan_tx->device->device_control(as->dma.chan_tx,
- DMA_TERMINATE_ALL, 0);
+ dmaengine_terminate_all(as->dma.chan_tx);
}
static void atmel_spi_release_dma(struct atmel_spi *as)
@@ -1315,6 +1304,7 @@ static int atmel_spi_probe(struct platform_device *pdev)
master->setup = atmel_spi_setup;
master->transfer_one_message = atmel_spi_transfer_one_message;
master->cleanup = atmel_spi_cleanup;
+ master->auto_runtime_pm = true;
platform_set_drvdata(pdev, master);
as = spi_master_get_devdata(master);
@@ -1347,8 +1337,11 @@ static int atmel_spi_probe(struct platform_device *pdev)
as->use_dma = false;
as->use_pdc = false;
if (as->caps.has_dma_support) {
- if (atmel_spi_configure_dma(as) == 0)
+ ret = atmel_spi_configure_dma(as);
+ if (ret == 0)
as->use_dma = true;
+ else if (ret == -EPROBE_DEFER)
+ return ret;
} else {
as->use_pdc = true;
}
@@ -1387,6 +1380,11 @@ static int atmel_spi_probe(struct platform_device *pdev)
dev_info(&pdev->dev, "Atmel SPI Controller at 0x%08lx (irq %d)\n",
(unsigned long)regs->start, irq);
+ pm_runtime_set_autosuspend_delay(&pdev->dev, AUTOSUSPEND_TIMEOUT);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_enable(&pdev->dev);
+
ret = devm_spi_register_master(&pdev->dev, master);
if (ret)
goto out_free_dma;
@@ -1394,6 +1392,9 @@ static int atmel_spi_probe(struct platform_device *pdev)
return 0;
out_free_dma:
+ pm_runtime_disable(&pdev->dev);
+ pm_runtime_set_suspended(&pdev->dev);
+
if (as->use_dma)
atmel_spi_release_dma(as);
@@ -1415,6 +1416,8 @@ static int atmel_spi_remove(struct platform_device *pdev)
struct spi_master *master = platform_get_drvdata(pdev);
struct atmel_spi *as = spi_master_get_devdata(master);
+ pm_runtime_get_sync(&pdev->dev);
+
/* reset the hardware and block queue progress */
spin_lock_irq(&as->lock);
if (as->use_dma) {
@@ -1432,14 +1435,37 @@ static int atmel_spi_remove(struct platform_device *pdev)
clk_disable_unprepare(as->clk);
+ pm_runtime_put_noidle(&pdev->dev);
+ pm_runtime_disable(&pdev->dev);
+
return 0;
}
-#ifdef CONFIG_PM_SLEEP
+#ifdef CONFIG_PM
+static int atmel_spi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(as->clk);
+ pinctrl_pm_select_sleep_state(dev);
+
+ return 0;
+}
+
+static int atmel_spi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct atmel_spi *as = spi_master_get_devdata(master);
+
+ pinctrl_pm_select_default_state(dev);
+
+ return clk_prepare_enable(as->clk);
+}
+
static int atmel_spi_suspend(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_master *master = dev_get_drvdata(dev);
int ret;
/* Stop the queue running */
@@ -1449,22 +1475,22 @@ static int atmel_spi_suspend(struct device *dev)
return ret;
}
- clk_disable_unprepare(as->clk);
-
- pinctrl_pm_select_sleep_state(dev);
+ if (!pm_runtime_suspended(dev))
+ atmel_spi_runtime_suspend(dev);
return 0;
}
static int atmel_spi_resume(struct device *dev)
{
- struct spi_master *master = dev_get_drvdata(dev);
- struct atmel_spi *as = spi_master_get_devdata(master);
+ struct spi_master *master = dev_get_drvdata(dev);
int ret;
- pinctrl_pm_select_default_state(dev);
-
- clk_prepare_enable(as->clk);
+ if (!pm_runtime_suspended(dev)) {
+ ret = atmel_spi_runtime_resume(dev);
+ if (ret)
+ return ret;
+ }
/* Start the queue running */
ret = spi_master_resume(master);
@@ -1474,8 +1500,11 @@ static int atmel_spi_resume(struct device *dev)
return ret;
}
-static SIMPLE_DEV_PM_OPS(atmel_spi_pm_ops, atmel_spi_suspend, atmel_spi_resume);
-
+static const struct dev_pm_ops atmel_spi_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(atmel_spi_suspend, atmel_spi_resume)
+ SET_RUNTIME_PM_OPS(atmel_spi_runtime_suspend,
+ atmel_spi_runtime_resume, NULL)
+};
#define ATMEL_SPI_PM_OPS (&atmel_spi_pm_ops)
#else
#define ATMEL_SPI_PM_OPS NULL
diff --git a/drivers/spi/spi-cadence.c b/drivers/spi/spi-cadence.c
index 7b811e3..5a67498 100644
--- a/drivers/spi/spi-cadence.c
+++ b/drivers/spi/spi-cadence.c
@@ -47,6 +47,7 @@
#define CDNS_SPI_CR_CPHA_MASK 0x00000004 /* Clock Phase Control */
#define CDNS_SPI_CR_CPOL_MASK 0x00000002 /* Clock Polarity Control */
#define CDNS_SPI_CR_SSCTRL_MASK 0x00003C00 /* Slave Select Mask */
+#define CDNS_SPI_CR_PERI_SEL_MASK 0x00000200 /* Peripheral Select Decode */
#define CDNS_SPI_CR_BAUD_DIV_MASK 0x00000038 /* Baud Rate Divisor Mask */
#define CDNS_SPI_CR_MSTREN_MASK 0x00000001 /* Master Enable Mask */
#define CDNS_SPI_CR_MANSTRTEN_MASK 0x00008000 /* Manual TX Enable Mask */
@@ -148,6 +149,11 @@ static inline void cdns_spi_write(struct cdns_spi *xspi, u32 offset, u32 val)
*/
static void cdns_spi_init_hw(struct cdns_spi *xspi)
{
+ u32 ctrl_reg = CDNS_SPI_CR_DEFAULT_MASK;
+
+ if (xspi->is_decoded_cs)
+ ctrl_reg |= CDNS_SPI_CR_PERI_SEL_MASK;
+
cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET,
CDNS_SPI_ER_DISABLE_MASK);
cdns_spi_write(xspi, CDNS_SPI_IDR_OFFSET,
@@ -160,8 +166,7 @@ static void cdns_spi_init_hw(struct cdns_spi *xspi)
cdns_spi_write(xspi, CDNS_SPI_ISR_OFFSET,
CDNS_SPI_IXR_ALL_MASK);
- cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET,
- CDNS_SPI_CR_DEFAULT_MASK);
+ cdns_spi_write(xspi, CDNS_SPI_CR_OFFSET, ctrl_reg);
cdns_spi_write(xspi, CDNS_SPI_ER_OFFSET,
CDNS_SPI_ER_ENABLE_MASK);
}
@@ -516,6 +521,17 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto clk_dis_apb;
}
+ ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
+ if (ret < 0)
+ master->num_chipselect = CDNS_SPI_DEFAULT_NUM_CS;
+ else
+ master->num_chipselect = num_cs;
+
+ ret = of_property_read_u32(pdev->dev.of_node, "is-decoded-cs",
+ &xspi->is_decoded_cs);
+ if (ret < 0)
+ xspi->is_decoded_cs = 0;
+
/* SPI controller initializations */
cdns_spi_init_hw(xspi);
@@ -534,19 +550,6 @@ static int cdns_spi_probe(struct platform_device *pdev)
goto remove_master;
}
- ret = of_property_read_u32(pdev->dev.of_node, "num-cs", &num_cs);
-
- if (ret < 0)
- master->num_chipselect = CDNS_SPI_DEFAULT_NUM_CS;
- else
- master->num_chipselect = num_cs;
-
- ret = of_property_read_u32(pdev->dev.of_node, "is-decoded-cs",
- &xspi->is_decoded_cs);
-
- if (ret < 0)
- xspi->is_decoded_cs = 0;
-
master->prepare_transfer_hardware = cdns_prepare_transfer_hardware;
master->prepare_message = cdns_prepare_message;
master->transfer_one = cdns_transfer_one;
diff --git a/drivers/spi/spi-dw-mid.c b/drivers/spi/spi-dw-mid.c
index 46c6d58..7281316 100644
--- a/drivers/spi/spi-dw-mid.c
+++ b/drivers/spi/spi-dw-mid.c
@@ -26,6 +26,9 @@
#include <linux/intel_mid_dma.h>
#include <linux/pci.h>
+#define RX_BUSY 0
+#define TX_BUSY 1
+
struct mid_dma {
struct intel_mid_dma_slave dmas_tx;
struct intel_mid_dma_slave dmas_rx;
@@ -98,41 +101,26 @@ static void mid_spi_dma_exit(struct dw_spi *dws)
}
/*
- * dws->dma_chan_done is cleared before the dma transfer starts,
- * callback for rx/tx channel will each increment it by 1.
- * Reaching 2 means the whole spi transaction is done.
+ * dws->dma_chan_busy is set before the dma transfer starts, callback for tx
+ * channel will clear a corresponding bit.
*/
-static void dw_spi_dma_done(void *arg)
+static void dw_spi_dma_tx_done(void *arg)
{
struct dw_spi *dws = arg;
- if (++dws->dma_chan_done != 2)
+ if (test_and_clear_bit(TX_BUSY, &dws->dma_chan_busy) & BIT(RX_BUSY))
return;
dw_spi_xfer_done(dws);
}
-static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+static struct dma_async_tx_descriptor *dw_spi_dma_prepare_tx(struct dw_spi *dws)
{
- struct dma_async_tx_descriptor *txdesc, *rxdesc;
- struct dma_slave_config txconf, rxconf;
- u16 dma_ctrl = 0;
-
- /* 1. setup DMA related registers */
- if (cs_change) {
- spi_enable_chip(dws, 0);
- dw_writew(dws, DW_SPI_DMARDLR, 0xf);
- dw_writew(dws, DW_SPI_DMATDLR, 0x10);
- if (dws->tx_dma)
- dma_ctrl |= SPI_DMA_TDMAE;
- if (dws->rx_dma)
- dma_ctrl |= SPI_DMA_RDMAE;
- dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
- spi_enable_chip(dws, 1);
- }
+ struct dma_slave_config txconf;
+ struct dma_async_tx_descriptor *txdesc;
- dws->dma_chan_done = 0;
+ if (!dws->tx_dma)
+ return NULL;
- /* 2. Prepare the TX dma transfer */
txconf.direction = DMA_MEM_TO_DEV;
txconf.dst_addr = dws->dma_addr;
txconf.dst_maxburst = LNW_DMA_MSIZE_16;
@@ -151,10 +139,33 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
1,
DMA_MEM_TO_DEV,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- txdesc->callback = dw_spi_dma_done;
+ txdesc->callback = dw_spi_dma_tx_done;
txdesc->callback_param = dws;
- /* 3. Prepare the RX dma transfer */
+ return txdesc;
+}
+
+/*
+ * dws->dma_chan_busy is set before the dma transfer starts, callback for rx
+ * channel will clear a corresponding bit.
+ */
+static void dw_spi_dma_rx_done(void *arg)
+{
+ struct dw_spi *dws = arg;
+
+ if (test_and_clear_bit(RX_BUSY, &dws->dma_chan_busy) & BIT(TX_BUSY))
+ return;
+ dw_spi_xfer_done(dws);
+}
+
+static struct dma_async_tx_descriptor *dw_spi_dma_prepare_rx(struct dw_spi *dws)
+{
+ struct dma_slave_config rxconf;
+ struct dma_async_tx_descriptor *rxdesc;
+
+ if (!dws->rx_dma)
+ return NULL;
+
rxconf.direction = DMA_DEV_TO_MEM;
rxconf.src_addr = dws->dma_addr;
rxconf.src_maxburst = LNW_DMA_MSIZE_16;
@@ -173,15 +184,56 @@ static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
1,
DMA_DEV_TO_MEM,
DMA_PREP_INTERRUPT | DMA_CTRL_ACK);
- rxdesc->callback = dw_spi_dma_done;
+ rxdesc->callback = dw_spi_dma_rx_done;
rxdesc->callback_param = dws;
+ return rxdesc;
+}
+
+static void dw_spi_dma_setup(struct dw_spi *dws)
+{
+ u16 dma_ctrl = 0;
+
+ spi_enable_chip(dws, 0);
+
+ dw_writew(dws, DW_SPI_DMARDLR, 0xf);
+ dw_writew(dws, DW_SPI_DMATDLR, 0x10);
+
+ if (dws->tx_dma)
+ dma_ctrl |= SPI_DMA_TDMAE;
+ if (dws->rx_dma)
+ dma_ctrl |= SPI_DMA_RDMAE;
+ dw_writew(dws, DW_SPI_DMACR, dma_ctrl);
+
+ spi_enable_chip(dws, 1);
+}
+
+static int mid_spi_dma_transfer(struct dw_spi *dws, int cs_change)
+{
+ struct dma_async_tx_descriptor *txdesc, *rxdesc;
+
+ /* 1. setup DMA related registers */
+ if (cs_change)
+ dw_spi_dma_setup(dws);
+
+ /* 2. Prepare the TX dma transfer */
+ txdesc = dw_spi_dma_prepare_tx(dws);
+
+ /* 3. Prepare the RX dma transfer */
+ rxdesc = dw_spi_dma_prepare_rx(dws);
+
/* rx must be started before tx due to spi instinct */
- dmaengine_submit(rxdesc);
- dma_async_issue_pending(dws->rxchan);
+ if (rxdesc) {
+ set_bit(RX_BUSY, &dws->dma_chan_busy);
+ dmaengine_submit(rxdesc);
+ dma_async_issue_pending(dws->rxchan);
+ }
- dmaengine_submit(txdesc);
- dma_async_issue_pending(dws->txchan);
+ if (txdesc) {
+ set_bit(TX_BUSY, &dws->dma_chan_busy);
+ dmaengine_submit(txdesc);
+ dma_async_issue_pending(dws->txchan);
+ }
return 0;
}
diff --git a/drivers/spi/spi-dw.h b/drivers/spi/spi-dw.h
index 83a103a..3d32be6 100644
--- a/drivers/spi/spi-dw.h
+++ b/drivers/spi/spi-dw.h
@@ -139,7 +139,7 @@ struct dw_spi {
struct scatterlist tx_sgl;
struct dma_chan *rxchan;
struct scatterlist rx_sgl;
- int dma_chan_done;
+ unsigned long dma_chan_busy;
struct device *dma_dev;
dma_addr_t dma_addr; /* phy address of the Data register */
struct dw_spi_dma_ops *dma_ops;
diff --git a/drivers/spi/spi-fsl-cpm.c b/drivers/spi/spi-fsl-cpm.c
index c5dd20b..e85ab1c 100644
--- a/drivers/spi/spi-fsl-cpm.c
+++ b/drivers/spi/spi-fsl-cpm.c
@@ -56,12 +56,15 @@ void fsl_spi_cpm_reinit_txrx(struct mpc8xxx_spi *mspi)
qe_issue_cmd(QE_INIT_TX_RX, mspi->subblock,
QE_CR_PROTOCOL_UNSPECIFIED, 0);
} else {
- cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
if (mspi->flags & SPI_CPM1) {
+ out_be32(&mspi->pram->rstate, 0);
out_be16(&mspi->pram->rbptr,
in_be16(&mspi->pram->rbase));
+ out_be32(&mspi->pram->tstate, 0);
out_be16(&mspi->pram->tbptr,
in_be16(&mspi->pram->tbase));
+ } else {
+ cpm_command(CPM_SPI_CMD, CPM_CR_INIT_TRX);
}
}
}
diff --git a/drivers/spi/spi-fsl-dspi.c b/drivers/spi/spi-fsl-dspi.c
index 831ceb4..4cda994 100644
--- a/drivers/spi/spi-fsl-dspi.c
+++ b/drivers/spi/spi-fsl-dspi.c
@@ -438,7 +438,7 @@ static int dspi_resume(struct device *dev)
static SIMPLE_DEV_PM_OPS(dspi_pm, dspi_suspend, dspi_resume);
-static struct regmap_config dspi_regmap_config = {
+static const struct regmap_config dspi_regmap_config = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
@@ -492,7 +492,6 @@ static int dspi_probe(struct platform_device *pdev)
goto out_master_put;
}
- dspi_regmap_config.lock_arg = dspi;
dspi->regmap = devm_regmap_init_mmio_clk(&pdev->dev, "dspi", base,
&dspi_regmap_config);
if (IS_ERR(dspi->regmap)) {
diff --git a/drivers/spi/spi-fsl-espi.c b/drivers/spi/spi-fsl-espi.c
index a7f94b6..56cadf1 100644
--- a/drivers/spi/spi-fsl-espi.c
+++ b/drivers/spi/spi-fsl-espi.c
@@ -411,7 +411,8 @@ static void fsl_espi_rw_trans(struct spi_message *m,
kfree(local_buf);
}
-static void fsl_espi_do_one_msg(struct spi_message *m)
+static int fsl_espi_do_one_msg(struct spi_master *master,
+ struct spi_message *m)
{
struct spi_transfer *t;
u8 *rx_buf = NULL;
@@ -441,8 +442,8 @@ static void fsl_espi_do_one_msg(struct spi_message *m)
m->actual_length = espi_trans.actual_length;
m->status = espi_trans.status;
- if (m->complete)
- m->complete(m->context);
+ spi_finalize_current_message(master);
+ return 0;
}
static int fsl_espi_setup(struct spi_device *spi)
@@ -587,6 +588,38 @@ static void fsl_espi_remove(struct mpc8xxx_spi *mspi)
iounmap(mspi->reg_base);
}
+static int fsl_espi_suspend(struct spi_master *master)
+{
+ struct mpc8xxx_spi *mpc8xxx_spi;
+ struct fsl_espi_reg *reg_base;
+ u32 regval;
+
+ mpc8xxx_spi = spi_master_get_devdata(master);
+ reg_base = mpc8xxx_spi->reg_base;
+
+ regval = mpc8xxx_spi_read_reg(&reg_base->mode);
+ regval &= ~SPMODE_ENABLE;
+ mpc8xxx_spi_write_reg(&reg_base->mode, regval);
+
+ return 0;
+}
+
+static int fsl_espi_resume(struct spi_master *master)
+{
+ struct mpc8xxx_spi *mpc8xxx_spi;
+ struct fsl_espi_reg *reg_base;
+ u32 regval;
+
+ mpc8xxx_spi = spi_master_get_devdata(master);
+ reg_base = mpc8xxx_spi->reg_base;
+
+ regval = mpc8xxx_spi_read_reg(&reg_base->mode);
+ regval |= SPMODE_ENABLE;
+ mpc8xxx_spi_write_reg(&reg_base->mode, regval);
+
+ return 0;
+}
+
static struct spi_master * fsl_espi_probe(struct device *dev,
struct resource *mem, unsigned int irq)
{
@@ -607,16 +640,16 @@ static struct spi_master * fsl_espi_probe(struct device *dev,
dev_set_drvdata(dev, master);
- ret = mpc8xxx_spi_probe(dev, mem, irq);
- if (ret)
- goto err_probe;
+ mpc8xxx_spi_probe(dev, mem, irq);
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
master->setup = fsl_espi_setup;
master->cleanup = fsl_espi_cleanup;
+ master->transfer_one_message = fsl_espi_do_one_msg;
+ master->prepare_transfer_hardware = fsl_espi_resume;
+ master->unprepare_transfer_hardware = fsl_espi_suspend;
mpc8xxx_spi = spi_master_get_devdata(master);
- mpc8xxx_spi->spi_do_one_msg = fsl_espi_do_one_msg;
mpc8xxx_spi->spi_remove = fsl_espi_remove;
mpc8xxx_spi->reg_base = ioremap(mem->start, resource_size(mem));
@@ -762,25 +795,15 @@ static int of_fsl_espi_remove(struct platform_device *dev)
static int of_fsl_espi_suspend(struct device *dev)
{
struct spi_master *master = dev_get_drvdata(dev);
- struct mpc8xxx_spi *mpc8xxx_spi;
- struct fsl_espi_reg *reg_base;
- u32 regval;
int ret;
- mpc8xxx_spi = spi_master_get_devdata(master);
- reg_base = mpc8xxx_spi->reg_base;
-
ret = spi_master_suspend(master);
if (ret) {
dev_warn(dev, "cannot suspend master\n");
return ret;
}
- regval = mpc8xxx_spi_read_reg(&reg_base->mode);
- regval &= ~SPMODE_ENABLE;
- mpc8xxx_spi_write_reg(&reg_base->mode, regval);
-
- return 0;
+ return fsl_espi_suspend(master);
}
static int of_fsl_espi_resume(struct device *dev)
diff --git a/drivers/spi/spi-fsl-lib.c b/drivers/spi/spi-fsl-lib.c
index 5ddb5b0..446b737 100644
--- a/drivers/spi/spi-fsl-lib.c
+++ b/drivers/spi/spi-fsl-lib.c
@@ -61,44 +61,6 @@ struct mpc8xxx_spi_probe_info *to_of_pinfo(struct fsl_spi_platform_data *pdata)
return container_of(pdata, struct mpc8xxx_spi_probe_info, pdata);
}
-static void mpc8xxx_spi_work(struct work_struct *work)
-{
- struct mpc8xxx_spi *mpc8xxx_spi = container_of(work, struct mpc8xxx_spi,
- work);
-
- spin_lock_irq(&mpc8xxx_spi->lock);
- while (!list_empty(&mpc8xxx_spi->queue)) {
- struct spi_message *m = container_of(mpc8xxx_spi->queue.next,
- struct spi_message, queue);
-
- list_del_init(&m->queue);
- spin_unlock_irq(&mpc8xxx_spi->lock);
-
- if (mpc8xxx_spi->spi_do_one_msg)
- mpc8xxx_spi->spi_do_one_msg(m);
-
- spin_lock_irq(&mpc8xxx_spi->lock);
- }
- spin_unlock_irq(&mpc8xxx_spi->lock);
-}
-
-int mpc8xxx_spi_transfer(struct spi_device *spi,
- struct spi_message *m)
-{
- struct mpc8xxx_spi *mpc8xxx_spi = spi_master_get_devdata(spi->master);
- unsigned long flags;
-
- m->actual_length = 0;
- m->status = -EINPROGRESS;
-
- spin_lock_irqsave(&mpc8xxx_spi->lock, flags);
- list_add_tail(&m->queue, &mpc8xxx_spi->queue);
- queue_work(mpc8xxx_spi->workqueue, &mpc8xxx_spi->work);
- spin_unlock_irqrestore(&mpc8xxx_spi->lock, flags);
-
- return 0;
-}
-
const char *mpc8xxx_spi_strmode(unsigned int flags)
{
if (flags & SPI_QE_CPU_MODE) {
@@ -114,13 +76,12 @@ const char *mpc8xxx_spi_strmode(unsigned int flags)
return "CPU";
}
-int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq)
{
struct fsl_spi_platform_data *pdata = dev_get_platdata(dev);
struct spi_master *master;
struct mpc8xxx_spi *mpc8xxx_spi;
- int ret = 0;
master = dev_get_drvdata(dev);
@@ -128,7 +89,6 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_CS_HIGH
| SPI_LSB_FIRST | SPI_LOOP;
- master->transfer = mpc8xxx_spi_transfer;
master->dev.of_node = dev->of_node;
mpc8xxx_spi = spi_master_get_devdata(master);
@@ -147,22 +107,7 @@ int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
master->bus_num = pdata->bus_num;
master->num_chipselect = pdata->max_chipselect;
- spin_lock_init(&mpc8xxx_spi->lock);
init_completion(&mpc8xxx_spi->done);
- INIT_WORK(&mpc8xxx_spi->work, mpc8xxx_spi_work);
- INIT_LIST_HEAD(&mpc8xxx_spi->queue);
-
- mpc8xxx_spi->workqueue = create_singlethread_workqueue(
- dev_name(master->dev.parent));
- if (mpc8xxx_spi->workqueue == NULL) {
- ret = -EBUSY;
- goto err;
- }
-
- return 0;
-
-err:
- return ret;
}
int mpc8xxx_spi_remove(struct device *dev)
@@ -173,8 +118,6 @@ int mpc8xxx_spi_remove(struct device *dev)
master = dev_get_drvdata(dev);
mpc8xxx_spi = spi_master_get_devdata(master);
- flush_workqueue(mpc8xxx_spi->workqueue);
- destroy_workqueue(mpc8xxx_spi->workqueue);
spi_unregister_master(master);
free_irq(mpc8xxx_spi->irq, mpc8xxx_spi);
diff --git a/drivers/spi/spi-fsl-lib.h b/drivers/spi/spi-fsl-lib.h
index 2fcbfd0..b4ed04e 100644
--- a/drivers/spi/spi-fsl-lib.h
+++ b/drivers/spi/spi-fsl-lib.h
@@ -55,7 +55,6 @@ struct mpc8xxx_spi {
u32(*get_tx) (struct mpc8xxx_spi *);
/* hooks for different controller driver */
- void (*spi_do_one_msg) (struct spi_message *m);
void (*spi_remove) (struct mpc8xxx_spi *mspi);
unsigned int count;
@@ -78,12 +77,6 @@ struct mpc8xxx_spi {
int bits_per_word, int msb_first);
#endif
- struct workqueue_struct *workqueue;
- struct work_struct work;
-
- struct list_head queue;
- spinlock_t lock;
-
struct completion done;
};
@@ -123,9 +116,8 @@ extern struct mpc8xxx_spi_probe_info *to_of_pinfo(
struct fsl_spi_platform_data *pdata);
extern int mpc8xxx_spi_bufs(struct mpc8xxx_spi *mspi,
struct spi_transfer *t, unsigned int len);
-extern int mpc8xxx_spi_transfer(struct spi_device *spi, struct spi_message *m);
extern const char *mpc8xxx_spi_strmode(unsigned int flags);
-extern int mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
+extern void mpc8xxx_spi_probe(struct device *dev, struct resource *mem,
unsigned int irq);
extern int mpc8xxx_spi_remove(struct device *dev);
extern int of_mpc8xxx_spi_probe(struct platform_device *ofdev);
diff --git a/drivers/spi/spi-fsl-spi.c b/drivers/spi/spi-fsl-spi.c
index ed79288..3b15936 100644
--- a/drivers/spi/spi-fsl-spi.c
+++ b/drivers/spi/spi-fsl-spi.c
@@ -353,7 +353,8 @@ static int fsl_spi_bufs(struct spi_device *spi, struct spi_transfer *t,
return mpc8xxx_spi->count;
}
-static void fsl_spi_do_one_msg(struct spi_message *m)
+static int fsl_spi_do_one_msg(struct spi_master *master,
+ struct spi_message *m)
{
struct spi_device *spi = m->spi;
struct spi_transfer *t, *first;
@@ -367,10 +368,9 @@ static void fsl_spi_do_one_msg(struct spi_message *m)
list_for_each_entry(t, &m->transfers, transfer_list) {
if ((first->bits_per_word != t->bits_per_word) ||
(first->speed_hz != t->speed_hz)) {
- status = -EINVAL;
dev_err(&spi->dev,
"bits_per_word/speed_hz should be same for the same SPI transfer\n");
- return;
+ return -EINVAL;
}
}
@@ -408,8 +408,7 @@ static void fsl_spi_do_one_msg(struct spi_message *m)
}
m->status = status;
- if (m->complete)
- m->complete(m->context);
+ spi_finalize_current_message(master);
if (status || !cs_change) {
ndelay(nsecs);
@@ -417,6 +416,7 @@ static void fsl_spi_do_one_msg(struct spi_message *m)
}
fsl_spi_setup_transfer(spi, NULL);
+ return 0;
}
static int fsl_spi_setup(struct spi_device *spi)
@@ -624,15 +624,13 @@ static struct spi_master * fsl_spi_probe(struct device *dev,
dev_set_drvdata(dev, master);
- ret = mpc8xxx_spi_probe(dev, mem, irq);
- if (ret)
- goto err_probe;
+ mpc8xxx_spi_probe(dev, mem, irq);
master->setup = fsl_spi_setup;
master->cleanup = fsl_spi_cleanup;
+ master->transfer_one_message = fsl_spi_do_one_msg;
mpc8xxx_spi = spi_master_get_devdata(master);
- mpc8xxx_spi->spi_do_one_msg = fsl_spi_do_one_msg;
mpc8xxx_spi->spi_remove = fsl_spi_remove;
mpc8xxx_spi->max_bits_per_word = 32;
mpc8xxx_spi->type = fsl_spi_get_type(dev);
@@ -704,7 +702,6 @@ free_irq:
err_ioremap:
fsl_spi_cpm_free(mpc8xxx_spi);
err_cpm_init:
-err_probe:
spi_master_put(master);
err:
return ERR_PTR(ret);
diff --git a/drivers/spi/spi-gpio.c b/drivers/spi/spi-gpio.c
index 9f59553..4b600d4 100644
--- a/drivers/spi/spi-gpio.c
+++ b/drivers/spi/spi-gpio.c
@@ -48,7 +48,7 @@ struct spi_gpio {
struct spi_bitbang bitbang;
struct spi_gpio_platform_data pdata;
struct platform_device *pdev;
- int cs_gpios[0];
+ unsigned long cs_gpios[0];
};
/*----------------------------------------------------------------------*/
@@ -220,7 +220,7 @@ static u32 spi_gpio_spec_txrx_word_mode3(struct spi_device *spi,
static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
{
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
- unsigned int cs = spi_gpio->cs_gpios[spi->chip_select];
+ unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
/* set initial clock polarity */
if (is_active)
@@ -234,7 +234,7 @@ static void spi_gpio_chipselect(struct spi_device *spi, int is_active)
static int spi_gpio_setup(struct spi_device *spi)
{
- unsigned int cs;
+ unsigned long cs;
int status = 0;
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
struct device_node *np = spi->master->dev.of_node;
@@ -249,7 +249,7 @@ static int spi_gpio_setup(struct spi_device *spi)
/*
* ... otherwise, take it from spi->controller_data
*/
- cs = (unsigned int)(uintptr_t) spi->controller_data;
+ cs = (uintptr_t) spi->controller_data;
}
if (!spi->controller_state) {
@@ -277,7 +277,7 @@ static int spi_gpio_setup(struct spi_device *spi)
static void spi_gpio_cleanup(struct spi_device *spi)
{
struct spi_gpio *spi_gpio = spi_to_spi_gpio(spi);
- unsigned int cs = spi_gpio->cs_gpios[spi->chip_select];
+ unsigned long cs = spi_gpio->cs_gpios[spi->chip_select];
if (cs != SPI_GPIO_NO_CHIPSELECT)
gpio_free(cs);
@@ -413,6 +413,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
struct spi_gpio_platform_data *pdata;
u16 master_flags = 0;
bool use_of = 0;
+ int num_devices;
status = spi_gpio_probe_dt(pdev);
if (status < 0)
@@ -422,16 +423,21 @@ static int spi_gpio_probe(struct platform_device *pdev)
pdata = dev_get_platdata(&pdev->dev);
#ifdef GENERIC_BITBANG
- if (!pdata || !pdata->num_chipselect)
+ if (!pdata || (!use_of && !pdata->num_chipselect))
return -ENODEV;
#endif
+ if (use_of && !SPI_N_CHIPSEL)
+ num_devices = 1;
+ else
+ num_devices = SPI_N_CHIPSEL;
+
status = spi_gpio_request(pdata, dev_name(&pdev->dev), &master_flags);
if (status < 0)
return status;
master = spi_alloc_master(&pdev->dev, sizeof(*spi_gpio) +
- (sizeof(int) * SPI_N_CHIPSEL));
+ (sizeof(unsigned long) * num_devices));
if (!master) {
status = -ENOMEM;
goto gpio_free;
@@ -446,7 +452,7 @@ static int spi_gpio_probe(struct platform_device *pdev)
master->bits_per_word_mask = SPI_BPW_RANGE_MASK(1, 32);
master->flags = master_flags;
master->bus_num = pdev->id;
- master->num_chipselect = SPI_N_CHIPSEL;
+ master->num_chipselect = num_devices;
master->setup = spi_gpio_setup;
master->cleanup = spi_gpio_cleanup;
#ifdef CONFIG_OF
@@ -461,9 +467,18 @@ static int spi_gpio_probe(struct platform_device *pdev)
* property of the node.
*/
- for (i = 0; i < SPI_N_CHIPSEL; i++)
- spi_gpio->cs_gpios[i] =
- of_get_named_gpio(np, "cs-gpios", i);
+ if (!SPI_N_CHIPSEL)
+ spi_gpio->cs_gpios[0] = SPI_GPIO_NO_CHIPSELECT;
+ else
+ for (i = 0; i < SPI_N_CHIPSEL; i++) {
+ status = of_get_named_gpio(np, "cs-gpios", i);
+ if (status < 0) {
+ dev_err(&pdev->dev,
+ "invalid cs-gpios property\n");
+ goto gpio_free;
+ }
+ spi_gpio->cs_gpios[i] = status;
+ }
}
#endif
diff --git a/drivers/spi/spi-img-spfi.c b/drivers/spi/spi-img-spfi.c
new file mode 100644
index 0000000..43781c9
--- /dev/null
+++ b/drivers/spi/spi-img-spfi.c
@@ -0,0 +1,746 @@
+/*
+ * IMG SPFI controller driver
+ *
+ * Copyright (C) 2007,2008,2013 Imagination Technologies Ltd.
+ * Copyright (C) 2014 Google, 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.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/dmaengine.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/irq.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/scatterlist.h>
+#include <linux/slab.h>
+#include <linux/spi/spi.h>
+#include <linux/spinlock.h>
+
+#define SPFI_DEVICE_PARAMETER(x) (0x00 + 0x4 * (x))
+#define SPFI_DEVICE_PARAMETER_BITCLK_SHIFT 24
+#define SPFI_DEVICE_PARAMETER_BITCLK_MASK 0xff
+#define SPFI_DEVICE_PARAMETER_CSSETUP_SHIFT 16
+#define SPFI_DEVICE_PARAMETER_CSSETUP_MASK 0xff
+#define SPFI_DEVICE_PARAMETER_CSHOLD_SHIFT 8
+#define SPFI_DEVICE_PARAMETER_CSHOLD_MASK 0xff
+#define SPFI_DEVICE_PARAMETER_CSDELAY_SHIFT 0
+#define SPFI_DEVICE_PARAMETER_CSDELAY_MASK 0xff
+
+#define SPFI_CONTROL 0x14
+#define SPFI_CONTROL_CONTINUE BIT(12)
+#define SPFI_CONTROL_SOFT_RESET BIT(11)
+#define SPFI_CONTROL_SEND_DMA BIT(10)
+#define SPFI_CONTROL_GET_DMA BIT(9)
+#define SPFI_CONTROL_TMODE_SHIFT 5
+#define SPFI_CONTROL_TMODE_MASK 0x7
+#define SPFI_CONTROL_TMODE_SINGLE 0
+#define SPFI_CONTROL_TMODE_DUAL 1
+#define SPFI_CONTROL_TMODE_QUAD 2
+#define SPFI_CONTROL_SPFI_EN BIT(0)
+
+#define SPFI_TRANSACTION 0x18
+#define SPFI_TRANSACTION_TSIZE_SHIFT 16
+#define SPFI_TRANSACTION_TSIZE_MASK 0xffff
+
+#define SPFI_PORT_STATE 0x1c
+#define SPFI_PORT_STATE_DEV_SEL_SHIFT 20
+#define SPFI_PORT_STATE_DEV_SEL_MASK 0x7
+#define SPFI_PORT_STATE_CK_POL(x) BIT(19 - (x))
+#define SPFI_PORT_STATE_CK_PHASE(x) BIT(14 - (x))
+
+#define SPFI_TX_32BIT_VALID_DATA 0x20
+#define SPFI_TX_8BIT_VALID_DATA 0x24
+#define SPFI_RX_32BIT_VALID_DATA 0x28
+#define SPFI_RX_8BIT_VALID_DATA 0x2c
+
+#define SPFI_INTERRUPT_STATUS 0x30
+#define SPFI_INTERRUPT_ENABLE 0x34
+#define SPFI_INTERRUPT_CLEAR 0x38
+#define SPFI_INTERRUPT_IACCESS BIT(12)
+#define SPFI_INTERRUPT_GDEX8BIT BIT(11)
+#define SPFI_INTERRUPT_ALLDONETRIG BIT(9)
+#define SPFI_INTERRUPT_GDFUL BIT(8)
+#define SPFI_INTERRUPT_GDHF BIT(7)
+#define SPFI_INTERRUPT_GDEX32BIT BIT(6)
+#define SPFI_INTERRUPT_GDTRIG BIT(5)
+#define SPFI_INTERRUPT_SDFUL BIT(3)
+#define SPFI_INTERRUPT_SDHF BIT(2)
+#define SPFI_INTERRUPT_SDE BIT(1)
+#define SPFI_INTERRUPT_SDTRIG BIT(0)
+
+/*
+ * There are four parallel FIFOs of 16 bytes each. The word buffer
+ * (*_32BIT_VALID_DATA) accesses all four FIFOs at once, resulting in an
+ * effective FIFO size of 64 bytes. The byte buffer (*_8BIT_VALID_DATA)
+ * accesses only a single FIFO, resulting in an effective FIFO size of
+ * 16 bytes.
+ */
+#define SPFI_32BIT_FIFO_SIZE 64
+#define SPFI_8BIT_FIFO_SIZE 16
+
+struct img_spfi {
+ struct device *dev;
+ struct spi_master *master;
+ spinlock_t lock;
+
+ void __iomem *regs;
+ phys_addr_t phys;
+ int irq;
+ struct clk *spfi_clk;
+ struct clk *sys_clk;
+
+ struct dma_chan *rx_ch;
+ struct dma_chan *tx_ch;
+ bool tx_dma_busy;
+ bool rx_dma_busy;
+};
+
+static inline u32 spfi_readl(struct img_spfi *spfi, u32 reg)
+{
+ return readl(spfi->regs + reg);
+}
+
+static inline void spfi_writel(struct img_spfi *spfi, u32 val, u32 reg)
+{
+ writel(val, spfi->regs + reg);
+}
+
+static inline void spfi_start(struct img_spfi *spfi)
+{
+ u32 val;
+
+ val = spfi_readl(spfi, SPFI_CONTROL);
+ val |= SPFI_CONTROL_SPFI_EN;
+ spfi_writel(spfi, val, SPFI_CONTROL);
+}
+
+static inline void spfi_stop(struct img_spfi *spfi)
+{
+ u32 val;
+
+ val = spfi_readl(spfi, SPFI_CONTROL);
+ val &= ~SPFI_CONTROL_SPFI_EN;
+ spfi_writel(spfi, val, SPFI_CONTROL);
+}
+
+static inline void spfi_reset(struct img_spfi *spfi)
+{
+ spfi_writel(spfi, SPFI_CONTROL_SOFT_RESET, SPFI_CONTROL);
+ udelay(1);
+ spfi_writel(spfi, 0, SPFI_CONTROL);
+}
+
+static void spfi_flush_tx_fifo(struct img_spfi *spfi)
+{
+ unsigned long timeout = jiffies + msecs_to_jiffies(10);
+
+ spfi_writel(spfi, SPFI_INTERRUPT_SDE, SPFI_INTERRUPT_CLEAR);
+ while (time_before(jiffies, timeout)) {
+ if (spfi_readl(spfi, SPFI_INTERRUPT_STATUS) &
+ SPFI_INTERRUPT_SDE)
+ return;
+ cpu_relax();
+ }
+
+ dev_err(spfi->dev, "Timed out waiting for FIFO to drain\n");
+ spfi_reset(spfi);
+}
+
+static unsigned int spfi_pio_write32(struct img_spfi *spfi, const u32 *buf,
+ unsigned int max)
+{
+ unsigned int count = 0;
+ u32 status;
+
+ while (count < max) {
+ spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR);
+ status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
+ if (status & SPFI_INTERRUPT_SDFUL)
+ break;
+ spfi_writel(spfi, buf[count / 4], SPFI_TX_32BIT_VALID_DATA);
+ count += 4;
+ }
+
+ return count;
+}
+
+static unsigned int spfi_pio_write8(struct img_spfi *spfi, const u8 *buf,
+ unsigned int max)
+{
+ unsigned int count = 0;
+ u32 status;
+
+ while (count < max) {
+ spfi_writel(spfi, SPFI_INTERRUPT_SDFUL, SPFI_INTERRUPT_CLEAR);
+ status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
+ if (status & SPFI_INTERRUPT_SDFUL)
+ break;
+ spfi_writel(spfi, buf[count], SPFI_TX_8BIT_VALID_DATA);
+ count++;
+ }
+
+ return count;
+}
+
+static unsigned int spfi_pio_read32(struct img_spfi *spfi, u32 *buf,
+ unsigned int max)
+{
+ unsigned int count = 0;
+ u32 status;
+
+ while (count < max) {
+ spfi_writel(spfi, SPFI_INTERRUPT_GDEX32BIT,
+ SPFI_INTERRUPT_CLEAR);
+ status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
+ if (!(status & SPFI_INTERRUPT_GDEX32BIT))
+ break;
+ buf[count / 4] = spfi_readl(spfi, SPFI_RX_32BIT_VALID_DATA);
+ count += 4;
+ }
+
+ return count;
+}
+
+static unsigned int spfi_pio_read8(struct img_spfi *spfi, u8 *buf,
+ unsigned int max)
+{
+ unsigned int count = 0;
+ u32 status;
+
+ while (count < max) {
+ spfi_writel(spfi, SPFI_INTERRUPT_GDEX8BIT,
+ SPFI_INTERRUPT_CLEAR);
+ status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
+ if (!(status & SPFI_INTERRUPT_GDEX8BIT))
+ break;
+ buf[count] = spfi_readl(spfi, SPFI_RX_8BIT_VALID_DATA);
+ count++;
+ }
+
+ return count;
+}
+
+static int img_spfi_start_pio(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ unsigned int tx_bytes = 0, rx_bytes = 0;
+ const void *tx_buf = xfer->tx_buf;
+ void *rx_buf = xfer->rx_buf;
+ unsigned long timeout;
+
+ if (tx_buf)
+ tx_bytes = xfer->len;
+ if (rx_buf)
+ rx_bytes = xfer->len;
+
+ spfi_start(spfi);
+
+ timeout = jiffies +
+ msecs_to_jiffies(xfer->len * 8 * 1000 / xfer->speed_hz + 100);
+ while ((tx_bytes > 0 || rx_bytes > 0) &&
+ time_before(jiffies, timeout)) {
+ unsigned int tx_count, rx_count;
+
+ switch (xfer->bits_per_word) {
+ case 32:
+ tx_count = spfi_pio_write32(spfi, tx_buf, tx_bytes);
+ rx_count = spfi_pio_read32(spfi, rx_buf, rx_bytes);
+ break;
+ case 8:
+ default:
+ tx_count = spfi_pio_write8(spfi, tx_buf, tx_bytes);
+ rx_count = spfi_pio_read8(spfi, rx_buf, rx_bytes);
+ break;
+ }
+
+ tx_buf += tx_count;
+ rx_buf += rx_count;
+ tx_bytes -= tx_count;
+ rx_bytes -= rx_count;
+
+ cpu_relax();
+ }
+
+ if (rx_bytes > 0 || tx_bytes > 0) {
+ dev_err(spfi->dev, "PIO transfer timed out\n");
+ spfi_reset(spfi);
+ return -ETIMEDOUT;
+ }
+
+ if (tx_buf)
+ spfi_flush_tx_fifo(spfi);
+ spfi_stop(spfi);
+
+ return 0;
+}
+
+static void img_spfi_dma_rx_cb(void *data)
+{
+ struct img_spfi *spfi = data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&spfi->lock, flags);
+
+ spfi->rx_dma_busy = false;
+ if (!spfi->tx_dma_busy) {
+ spfi_stop(spfi);
+ spi_finalize_current_transfer(spfi->master);
+ }
+
+ spin_unlock_irqrestore(&spfi->lock, flags);
+}
+
+static void img_spfi_dma_tx_cb(void *data)
+{
+ struct img_spfi *spfi = data;
+ unsigned long flags;
+
+ spfi_flush_tx_fifo(spfi);
+
+ spin_lock_irqsave(&spfi->lock, flags);
+
+ spfi->tx_dma_busy = false;
+ if (!spfi->rx_dma_busy) {
+ spfi_stop(spfi);
+ spi_finalize_current_transfer(spfi->master);
+ }
+
+ spin_unlock_irqrestore(&spfi->lock, flags);
+}
+
+static int img_spfi_start_dma(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ struct dma_async_tx_descriptor *rxdesc = NULL, *txdesc = NULL;
+ struct dma_slave_config rxconf, txconf;
+
+ spfi->rx_dma_busy = false;
+ spfi->tx_dma_busy = false;
+
+ if (xfer->rx_buf) {
+ rxconf.direction = DMA_DEV_TO_MEM;
+ switch (xfer->bits_per_word) {
+ case 32:
+ rxconf.src_addr = spfi->phys + SPFI_RX_32BIT_VALID_DATA;
+ rxconf.src_addr_width = 4;
+ rxconf.src_maxburst = 4;
+ break;
+ case 8:
+ default:
+ rxconf.src_addr = spfi->phys + SPFI_RX_8BIT_VALID_DATA;
+ rxconf.src_addr_width = 1;
+ rxconf.src_maxburst = 1;
+ }
+ dmaengine_slave_config(spfi->rx_ch, &rxconf);
+
+ rxdesc = dmaengine_prep_slave_sg(spfi->rx_ch, xfer->rx_sg.sgl,
+ xfer->rx_sg.nents,
+ DMA_DEV_TO_MEM,
+ DMA_PREP_INTERRUPT);
+ if (!rxdesc)
+ goto stop_dma;
+
+ rxdesc->callback = img_spfi_dma_rx_cb;
+ rxdesc->callback_param = spfi;
+ }
+
+ if (xfer->tx_buf) {
+ txconf.direction = DMA_MEM_TO_DEV;
+ switch (xfer->bits_per_word) {
+ case 32:
+ txconf.dst_addr = spfi->phys + SPFI_TX_32BIT_VALID_DATA;
+ txconf.dst_addr_width = 4;
+ txconf.dst_maxburst = 4;
+ break;
+ case 8:
+ default:
+ txconf.dst_addr = spfi->phys + SPFI_TX_8BIT_VALID_DATA;
+ txconf.dst_addr_width = 1;
+ txconf.dst_maxburst = 1;
+ break;
+ }
+ dmaengine_slave_config(spfi->tx_ch, &txconf);
+
+ txdesc = dmaengine_prep_slave_sg(spfi->tx_ch, xfer->tx_sg.sgl,
+ xfer->tx_sg.nents,
+ DMA_MEM_TO_DEV,
+ DMA_PREP_INTERRUPT);
+ if (!txdesc)
+ goto stop_dma;
+
+ txdesc->callback = img_spfi_dma_tx_cb;
+ txdesc->callback_param = spfi;
+ }
+
+ if (xfer->rx_buf) {
+ spfi->rx_dma_busy = true;
+ dmaengine_submit(rxdesc);
+ dma_async_issue_pending(spfi->rx_ch);
+ }
+
+ if (xfer->tx_buf) {
+ spfi->tx_dma_busy = true;
+ dmaengine_submit(txdesc);
+ dma_async_issue_pending(spfi->tx_ch);
+ }
+
+ spfi_start(spfi);
+
+ return 1;
+
+stop_dma:
+ dmaengine_terminate_all(spfi->rx_ch);
+ dmaengine_terminate_all(spfi->tx_ch);
+ return -EIO;
+}
+
+static void img_spfi_config(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ u32 val, div;
+
+ /*
+ * output = spfi_clk * (BITCLK / 512), where BITCLK must be a
+ * power of 2 up to 256 (where 255 == 256 since BITCLK is 8 bits)
+ */
+ div = DIV_ROUND_UP(master->max_speed_hz, xfer->speed_hz);
+ div = clamp(512 / (1 << get_count_order(div)), 1, 255);
+
+ val = spfi_readl(spfi, SPFI_DEVICE_PARAMETER(spi->chip_select));
+ val &= ~(SPFI_DEVICE_PARAMETER_BITCLK_MASK <<
+ SPFI_DEVICE_PARAMETER_BITCLK_SHIFT);
+ val |= div << SPFI_DEVICE_PARAMETER_BITCLK_SHIFT;
+ spfi_writel(spfi, val, SPFI_DEVICE_PARAMETER(spi->chip_select));
+
+ val = spfi_readl(spfi, SPFI_CONTROL);
+ val &= ~(SPFI_CONTROL_SEND_DMA | SPFI_CONTROL_GET_DMA);
+ if (xfer->tx_buf)
+ val |= SPFI_CONTROL_SEND_DMA;
+ if (xfer->rx_buf)
+ val |= SPFI_CONTROL_GET_DMA;
+ val &= ~(SPFI_CONTROL_TMODE_MASK << SPFI_CONTROL_TMODE_SHIFT);
+ if (xfer->tx_nbits == SPI_NBITS_DUAL &&
+ xfer->rx_nbits == SPI_NBITS_DUAL)
+ val |= SPFI_CONTROL_TMODE_DUAL << SPFI_CONTROL_TMODE_SHIFT;
+ else if (xfer->tx_nbits == SPI_NBITS_QUAD &&
+ xfer->rx_nbits == SPI_NBITS_QUAD)
+ val |= SPFI_CONTROL_TMODE_QUAD << SPFI_CONTROL_TMODE_SHIFT;
+ val &= ~SPFI_CONTROL_CONTINUE;
+ if (!xfer->cs_change && !list_is_last(&xfer->transfer_list,
+ &master->cur_msg->transfers))
+ val |= SPFI_CONTROL_CONTINUE;
+ spfi_writel(spfi, val, SPFI_CONTROL);
+
+ val = spfi_readl(spfi, SPFI_PORT_STATE);
+ if (spi->mode & SPI_CPHA)
+ val |= SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
+ else
+ val &= ~SPFI_PORT_STATE_CK_PHASE(spi->chip_select);
+ if (spi->mode & SPI_CPOL)
+ val |= SPFI_PORT_STATE_CK_POL(spi->chip_select);
+ else
+ val &= ~SPFI_PORT_STATE_CK_POL(spi->chip_select);
+ spfi_writel(spfi, val, SPFI_PORT_STATE);
+
+ spfi_writel(spfi, xfer->len << SPFI_TRANSACTION_TSIZE_SHIFT,
+ SPFI_TRANSACTION);
+}
+
+static int img_spfi_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ bool dma_reset = false;
+ unsigned long flags;
+ int ret;
+
+ /*
+ * Stop all DMA and reset the controller if the previous transaction
+ * timed-out and never completed it's DMA.
+ */
+ spin_lock_irqsave(&spfi->lock, flags);
+ if (spfi->tx_dma_busy || spfi->rx_dma_busy) {
+ dev_err(spfi->dev, "SPI DMA still busy\n");
+ dma_reset = true;
+ }
+ spin_unlock_irqrestore(&spfi->lock, flags);
+
+ if (dma_reset) {
+ dmaengine_terminate_all(spfi->tx_ch);
+ dmaengine_terminate_all(spfi->rx_ch);
+ spfi_reset(spfi);
+ }
+
+ img_spfi_config(master, spi, xfer);
+ if (master->can_dma && master->can_dma(master, spi, xfer))
+ ret = img_spfi_start_dma(master, spi, xfer);
+ else
+ ret = img_spfi_start_pio(master, spi, xfer);
+
+ return ret;
+}
+
+static void img_spfi_set_cs(struct spi_device *spi, bool enable)
+{
+ struct img_spfi *spfi = spi_master_get_devdata(spi->master);
+ u32 val;
+
+ val = spfi_readl(spfi, SPFI_PORT_STATE);
+ val &= ~(SPFI_PORT_STATE_DEV_SEL_MASK << SPFI_PORT_STATE_DEV_SEL_SHIFT);
+ val |= spi->chip_select << SPFI_PORT_STATE_DEV_SEL_SHIFT;
+ spfi_writel(spfi, val, SPFI_PORT_STATE);
+}
+
+static bool img_spfi_can_dma(struct spi_master *master, struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ if (xfer->bits_per_word == 8 && xfer->len > SPFI_8BIT_FIFO_SIZE)
+ return true;
+ if (xfer->bits_per_word == 32 && xfer->len > SPFI_32BIT_FIFO_SIZE)
+ return true;
+ return false;
+}
+
+static irqreturn_t img_spfi_irq(int irq, void *dev_id)
+{
+ struct img_spfi *spfi = (struct img_spfi *)dev_id;
+ u32 status;
+
+ status = spfi_readl(spfi, SPFI_INTERRUPT_STATUS);
+ if (status & SPFI_INTERRUPT_IACCESS) {
+ spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_CLEAR);
+ dev_err(spfi->dev, "Illegal access interrupt");
+ return IRQ_HANDLED;
+ }
+
+ return IRQ_NONE;
+}
+
+static int img_spfi_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct img_spfi *spfi;
+ struct resource *res;
+ int ret;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(*spfi));
+ if (!master)
+ return -ENOMEM;
+ platform_set_drvdata(pdev, master);
+
+ spfi = spi_master_get_devdata(master);
+ spfi->dev = &pdev->dev;
+ spfi->master = master;
+ spin_lock_init(&spfi->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ spfi->regs = devm_ioremap_resource(spfi->dev, res);
+ if (IS_ERR(spfi->regs)) {
+ ret = PTR_ERR(spfi->regs);
+ goto put_spi;
+ }
+ spfi->phys = res->start;
+
+ spfi->irq = platform_get_irq(pdev, 0);
+ if (spfi->irq < 0) {
+ ret = spfi->irq;
+ goto put_spi;
+ }
+ ret = devm_request_irq(spfi->dev, spfi->irq, img_spfi_irq,
+ IRQ_TYPE_LEVEL_HIGH, dev_name(spfi->dev), spfi);
+ if (ret)
+ goto put_spi;
+
+ spfi->sys_clk = devm_clk_get(spfi->dev, "sys");
+ if (IS_ERR(spfi->sys_clk)) {
+ ret = PTR_ERR(spfi->sys_clk);
+ goto put_spi;
+ }
+ spfi->spfi_clk = devm_clk_get(spfi->dev, "spfi");
+ if (IS_ERR(spfi->spfi_clk)) {
+ ret = PTR_ERR(spfi->spfi_clk);
+ goto put_spi;
+ }
+
+ ret = clk_prepare_enable(spfi->sys_clk);
+ if (ret)
+ goto put_spi;
+ ret = clk_prepare_enable(spfi->spfi_clk);
+ if (ret)
+ goto disable_pclk;
+
+ spfi_reset(spfi);
+ /*
+ * Only enable the error (IACCESS) interrupt. In PIO mode we'll
+ * poll the status of the FIFOs.
+ */
+ spfi_writel(spfi, SPFI_INTERRUPT_IACCESS, SPFI_INTERRUPT_ENABLE);
+
+ master->auto_runtime_pm = true;
+ master->bus_num = pdev->id;
+ master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_TX_DUAL | SPI_RX_DUAL;
+ if (of_property_read_bool(spfi->dev->of_node, "img,supports-quad-mode"))
+ master->mode_bits |= SPI_TX_QUAD | SPI_RX_QUAD;
+ master->num_chipselect = 5;
+ master->dev.of_node = pdev->dev.of_node;
+ master->bits_per_word_mask = SPI_BPW_MASK(32) | SPI_BPW_MASK(8);
+ master->max_speed_hz = clk_get_rate(spfi->spfi_clk);
+ master->min_speed_hz = master->max_speed_hz / 512;
+
+ master->set_cs = img_spfi_set_cs;
+ master->transfer_one = img_spfi_transfer_one;
+
+ spfi->tx_ch = dma_request_slave_channel(spfi->dev, "tx");
+ spfi->rx_ch = dma_request_slave_channel(spfi->dev, "rx");
+ if (!spfi->tx_ch || !spfi->rx_ch) {
+ if (spfi->tx_ch)
+ dma_release_channel(spfi->tx_ch);
+ if (spfi->rx_ch)
+ dma_release_channel(spfi->rx_ch);
+ dev_warn(spfi->dev, "Failed to get DMA channels, falling back to PIO mode\n");
+ } else {
+ master->dma_tx = spfi->tx_ch;
+ master->dma_rx = spfi->rx_ch;
+ master->can_dma = img_spfi_can_dma;
+ }
+
+ pm_runtime_set_active(spfi->dev);
+ pm_runtime_enable(spfi->dev);
+
+ ret = devm_spi_register_master(spfi->dev, master);
+ if (ret)
+ goto disable_pm;
+
+ return 0;
+
+disable_pm:
+ pm_runtime_disable(spfi->dev);
+ if (spfi->rx_ch)
+ dma_release_channel(spfi->rx_ch);
+ if (spfi->tx_ch)
+ dma_release_channel(spfi->tx_ch);
+ clk_disable_unprepare(spfi->spfi_clk);
+disable_pclk:
+ clk_disable_unprepare(spfi->sys_clk);
+put_spi:
+ spi_master_put(master);
+
+ return ret;
+}
+
+static int img_spfi_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+
+ if (spfi->tx_ch)
+ dma_release_channel(spfi->tx_ch);
+ if (spfi->rx_ch)
+ dma_release_channel(spfi->rx_ch);
+
+ pm_runtime_disable(spfi->dev);
+ if (!pm_runtime_status_suspended(spfi->dev)) {
+ clk_disable_unprepare(spfi->spfi_clk);
+ clk_disable_unprepare(spfi->sys_clk);
+ }
+
+ spi_master_put(master);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_RUNTIME
+static int img_spfi_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(spfi->spfi_clk);
+ clk_disable_unprepare(spfi->sys_clk);
+
+ return 0;
+}
+
+static int img_spfi_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = clk_prepare_enable(spfi->sys_clk);
+ if (ret)
+ return ret;
+ ret = clk_prepare_enable(spfi->spfi_clk);
+ if (ret) {
+ clk_disable_unprepare(spfi->sys_clk);
+ return ret;
+ }
+
+ return 0;
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+#ifdef CONFIG_PM_SLEEP
+static int img_spfi_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+
+ return spi_master_suspend(master);
+}
+
+static int img_spfi_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct img_spfi *spfi = spi_master_get_devdata(master);
+ int ret;
+
+ ret = pm_runtime_get_sync(dev);
+ if (ret)
+ return ret;
+ spfi_reset(spfi);
+ pm_runtime_put(dev);
+
+ return spi_master_resume(master);
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops img_spfi_pm_ops = {
+ SET_RUNTIME_PM_OPS(img_spfi_runtime_suspend, img_spfi_runtime_resume,
+ NULL)
+ SET_SYSTEM_SLEEP_PM_OPS(img_spfi_suspend, img_spfi_resume)
+};
+
+static const struct of_device_id img_spfi_of_match[] = {
+ { .compatible = "img,spfi", },
+ { },
+};
+MODULE_DEVICE_TABLE(of, img_spfi_of_match);
+
+static struct platform_driver img_spfi_driver = {
+ .driver = {
+ .name = "img-spfi",
+ .pm = &img_spfi_pm_ops,
+ .of_match_table = of_match_ptr(img_spfi_of_match),
+ },
+ .probe = img_spfi_probe,
+ .remove = img_spfi_remove,
+};
+module_platform_driver(img_spfi_driver);
+
+MODULE_DESCRIPTION("IMG SPFI controller driver");
+MODULE_AUTHOR("Andrew Bresticker <abrestic@chromium.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-meson-spifc.c b/drivers/spi/spi-meson-spifc.c
new file mode 100644
index 0000000..0e48f8c
--- /dev/null
+++ b/drivers/spi/spi-meson-spifc.c
@@ -0,0 +1,462 @@
+/*
+ * Driver for Amlogic Meson SPI flash controller (SPIFC)
+ *
+ * Copyright (C) 2014 Beniamino Galvani <b.galvani@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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/regmap.h>
+#include <linux/spi/spi.h>
+#include <linux/types.h>
+
+/* register map */
+#define REG_CMD 0x00
+#define REG_ADDR 0x04
+#define REG_CTRL 0x08
+#define REG_CTRL1 0x0c
+#define REG_STATUS 0x10
+#define REG_CTRL2 0x14
+#define REG_CLOCK 0x18
+#define REG_USER 0x1c
+#define REG_USER1 0x20
+#define REG_USER2 0x24
+#define REG_USER3 0x28
+#define REG_USER4 0x2c
+#define REG_SLAVE 0x30
+#define REG_SLAVE1 0x34
+#define REG_SLAVE2 0x38
+#define REG_SLAVE3 0x3c
+#define REG_C0 0x40
+#define REG_B8 0x60
+#define REG_MAX 0x7c
+
+/* register fields */
+#define CMD_USER BIT(18)
+#define CTRL_ENABLE_AHB BIT(17)
+#define CLOCK_SOURCE BIT(31)
+#define CLOCK_DIV_SHIFT 12
+#define CLOCK_DIV_MASK (0x3f << CLOCK_DIV_SHIFT)
+#define CLOCK_CNT_HIGH_SHIFT 6
+#define CLOCK_CNT_HIGH_MASK (0x3f << CLOCK_CNT_HIGH_SHIFT)
+#define CLOCK_CNT_LOW_SHIFT 0
+#define CLOCK_CNT_LOW_MASK (0x3f << CLOCK_CNT_LOW_SHIFT)
+#define USER_DIN_EN_MS BIT(0)
+#define USER_CMP_MODE BIT(2)
+#define USER_UC_DOUT_SEL BIT(27)
+#define USER_UC_DIN_SEL BIT(28)
+#define USER_UC_MASK ((BIT(5) - 1) << 27)
+#define USER1_BN_UC_DOUT_SHIFT 17
+#define USER1_BN_UC_DOUT_MASK (0xff << 16)
+#define USER1_BN_UC_DIN_SHIFT 8
+#define USER1_BN_UC_DIN_MASK (0xff << 8)
+#define USER4_CS_ACT BIT(30)
+#define SLAVE_TRST_DONE BIT(4)
+#define SLAVE_OP_MODE BIT(30)
+#define SLAVE_SW_RST BIT(31)
+
+#define SPIFC_BUFFER_SIZE 64
+
+/**
+ * struct meson_spifc
+ * @master: the SPI master
+ * @regmap: regmap for device registers
+ * @clk: input clock of the built-in baud rate generator
+ * @device: the device structure
+ */
+struct meson_spifc {
+ struct spi_master *master;
+ struct regmap *regmap;
+ struct clk *clk;
+ struct device *dev;
+};
+
+static struct regmap_config spifc_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = REG_MAX,
+};
+
+/**
+ * meson_spifc_wait_ready() - wait for the current operation to terminate
+ * @spifc: the Meson SPI device
+ * Return: 0 on success, a negative value on error
+ */
+static int meson_spifc_wait_ready(struct meson_spifc *spifc)
+{
+ unsigned long deadline = jiffies + msecs_to_jiffies(5);
+ u32 data;
+
+ do {
+ regmap_read(spifc->regmap, REG_SLAVE, &data);
+ if (data & SLAVE_TRST_DONE)
+ return 0;
+ cond_resched();
+ } while (!time_after(jiffies, deadline));
+
+ return -ETIMEDOUT;
+}
+
+/**
+ * meson_spifc_drain_buffer() - copy data from device buffer to memory
+ * @spifc: the Meson SPI device
+ * @buf: the destination buffer
+ * @len: number of bytes to copy
+ */
+static void meson_spifc_drain_buffer(struct meson_spifc *spifc, u8 *buf,
+ int len)
+{
+ u32 data;
+ int i = 0;
+
+ while (i < len) {
+ regmap_read(spifc->regmap, REG_C0 + i, &data);
+
+ if (len - i >= 4) {
+ *((u32 *)buf) = data;
+ buf += 4;
+ } else {
+ memcpy(buf, &data, len - i);
+ break;
+ }
+ i += 4;
+ }
+}
+
+/**
+ * meson_spifc_fill_buffer() - copy data from memory to device buffer
+ * @spifc: the Meson SPI device
+ * @buf: the source buffer
+ * @len: number of bytes to copy
+ */
+static void meson_spifc_fill_buffer(struct meson_spifc *spifc, const u8 *buf,
+ int len)
+{
+ u32 data;
+ int i = 0;
+
+ while (i < len) {
+ if (len - i >= 4)
+ data = *(u32 *)buf;
+ else
+ memcpy(&data, buf, len - i);
+
+ regmap_write(spifc->regmap, REG_C0 + i, data);
+
+ buf += 4;
+ i += 4;
+ }
+}
+
+/**
+ * meson_spifc_setup_speed() - program the clock divider
+ * @spifc: the Meson SPI device
+ * @speed: desired speed in Hz
+ */
+static void meson_spifc_setup_speed(struct meson_spifc *spifc, u32 speed)
+{
+ unsigned long parent, value;
+ int n;
+
+ parent = clk_get_rate(spifc->clk);
+ n = max_t(int, parent / speed - 1, 1);
+
+ dev_dbg(spifc->dev, "parent %lu, speed %u, n %d\n", parent,
+ speed, n);
+
+ value = (n << CLOCK_DIV_SHIFT) & CLOCK_DIV_MASK;
+ value |= (n << CLOCK_CNT_LOW_SHIFT) & CLOCK_CNT_LOW_MASK;
+ value |= (((n + 1) / 2 - 1) << CLOCK_CNT_HIGH_SHIFT) &
+ CLOCK_CNT_HIGH_MASK;
+
+ regmap_write(spifc->regmap, REG_CLOCK, value);
+}
+
+/**
+ * meson_spifc_txrx() - transfer a chunk of data
+ * @spifc: the Meson SPI device
+ * @xfer: the current SPI transfer
+ * @offset: offset of the data to transfer
+ * @len: length of the data to transfer
+ * @last_xfer: whether this is the last transfer of the message
+ * @last_chunk: whether this is the last chunk of the transfer
+ * Return: 0 on success, a negative value on error
+ */
+static int meson_spifc_txrx(struct meson_spifc *spifc,
+ struct spi_transfer *xfer,
+ int offset, int len, bool last_xfer,
+ bool last_chunk)
+{
+ bool keep_cs = true;
+ int ret;
+
+ if (xfer->tx_buf)
+ meson_spifc_fill_buffer(spifc, xfer->tx_buf + offset, len);
+
+ /* enable DOUT stage */
+ regmap_update_bits(spifc->regmap, REG_USER, USER_UC_MASK,
+ USER_UC_DOUT_SEL);
+ regmap_write(spifc->regmap, REG_USER1,
+ (8 * len - 1) << USER1_BN_UC_DOUT_SHIFT);
+
+ /* enable data input during DOUT */
+ regmap_update_bits(spifc->regmap, REG_USER, USER_DIN_EN_MS,
+ USER_DIN_EN_MS);
+
+ if (last_chunk) {
+ if (last_xfer)
+ keep_cs = xfer->cs_change;
+ else
+ keep_cs = !xfer->cs_change;
+ }
+
+ regmap_update_bits(spifc->regmap, REG_USER4, USER4_CS_ACT,
+ keep_cs ? USER4_CS_ACT : 0);
+
+ /* clear transition done bit */
+ regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_TRST_DONE, 0);
+ /* start transfer */
+ regmap_update_bits(spifc->regmap, REG_CMD, CMD_USER, CMD_USER);
+
+ ret = meson_spifc_wait_ready(spifc);
+
+ if (!ret && xfer->rx_buf)
+ meson_spifc_drain_buffer(spifc, xfer->rx_buf + offset, len);
+
+ return ret;
+}
+
+/**
+ * meson_spifc_transfer_one() - perform a single transfer
+ * @master: the SPI master
+ * @spi: the SPI device
+ * @xfer: the current SPI transfer
+ * Return: 0 on success, a negative value on error
+ */
+static int meson_spifc_transfer_one(struct spi_master *master,
+ struct spi_device *spi,
+ struct spi_transfer *xfer)
+{
+ struct meson_spifc *spifc = spi_master_get_devdata(master);
+ int len, done = 0, ret = 0;
+
+ meson_spifc_setup_speed(spifc, xfer->speed_hz);
+
+ regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB, 0);
+
+ while (done < xfer->len && !ret) {
+ len = min_t(int, xfer->len - done, SPIFC_BUFFER_SIZE);
+ ret = meson_spifc_txrx(spifc, xfer, done, len,
+ spi_transfer_is_last(master, xfer),
+ done + len >= xfer->len);
+ done += len;
+ }
+
+ regmap_update_bits(spifc->regmap, REG_CTRL, CTRL_ENABLE_AHB,
+ CTRL_ENABLE_AHB);
+
+ return ret;
+}
+
+/**
+ * meson_spifc_hw_init() - reset and initialize the SPI controller
+ * @spifc: the Meson SPI device
+ */
+static void meson_spifc_hw_init(struct meson_spifc *spifc)
+{
+ /* reset device */
+ regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_SW_RST,
+ SLAVE_SW_RST);
+ /* disable compatible mode */
+ regmap_update_bits(spifc->regmap, REG_USER, USER_CMP_MODE, 0);
+ /* set master mode */
+ regmap_update_bits(spifc->regmap, REG_SLAVE, SLAVE_OP_MODE, 0);
+}
+
+static int meson_spifc_probe(struct platform_device *pdev)
+{
+ struct spi_master *master;
+ struct meson_spifc *spifc;
+ struct resource *res;
+ void __iomem *base;
+ unsigned int rate;
+ int ret = 0;
+
+ master = spi_alloc_master(&pdev->dev, sizeof(struct meson_spifc));
+ if (!master)
+ return -ENOMEM;
+
+ platform_set_drvdata(pdev, master);
+
+ spifc = spi_master_get_devdata(master);
+ spifc->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ base = devm_ioremap_resource(spifc->dev, res);
+ if (IS_ERR(base)) {
+ ret = PTR_ERR(base);
+ goto out_err;
+ }
+
+ spifc->regmap = devm_regmap_init_mmio(spifc->dev, base,
+ &spifc_regmap_config);
+ if (IS_ERR(spifc->regmap)) {
+ ret = PTR_ERR(spifc->regmap);
+ goto out_err;
+ }
+
+ spifc->clk = devm_clk_get(spifc->dev, NULL);
+ if (IS_ERR(spifc->clk)) {
+ dev_err(spifc->dev, "missing clock\n");
+ ret = PTR_ERR(spifc->clk);
+ goto out_err;
+ }
+
+ ret = clk_prepare_enable(spifc->clk);
+ if (ret) {
+ dev_err(spifc->dev, "can't prepare clock\n");
+ goto out_err;
+ }
+
+ rate = clk_get_rate(spifc->clk);
+
+ master->num_chipselect = 1;
+ master->dev.of_node = pdev->dev.of_node;
+ master->bits_per_word_mask = SPI_BPW_MASK(8);
+ master->auto_runtime_pm = true;
+ master->transfer_one = meson_spifc_transfer_one;
+ master->min_speed_hz = rate >> 6;
+ master->max_speed_hz = rate >> 1;
+
+ meson_spifc_hw_init(spifc);
+
+ pm_runtime_set_active(spifc->dev);
+ pm_runtime_enable(spifc->dev);
+
+ ret = devm_spi_register_master(spifc->dev, master);
+ if (ret) {
+ dev_err(spifc->dev, "failed to register spi master\n");
+ goto out_clk;
+ }
+
+ return 0;
+out_clk:
+ clk_disable_unprepare(spifc->clk);
+out_err:
+ spi_master_put(master);
+ return ret;
+}
+
+static int meson_spifc_remove(struct platform_device *pdev)
+{
+ struct spi_master *master = platform_get_drvdata(pdev);
+ struct meson_spifc *spifc = spi_master_get_devdata(master);
+
+ pm_runtime_get_sync(&pdev->dev);
+ clk_disable_unprepare(spifc->clk);
+ pm_runtime_disable(&pdev->dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int meson_spifc_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_master_get_devdata(master);
+ int ret;
+
+ ret = spi_master_suspend(master);
+ if (ret)
+ return ret;
+
+ if (!pm_runtime_suspended(dev))
+ clk_disable_unprepare(spifc->clk);
+
+ return 0;
+}
+
+static int meson_spifc_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_master_get_devdata(master);
+ int ret;
+
+ if (!pm_runtime_suspended(dev)) {
+ ret = clk_prepare_enable(spifc->clk);
+ if (ret)
+ return ret;
+ }
+
+ meson_spifc_hw_init(spifc);
+
+ ret = spi_master_resume(master);
+ if (ret)
+ clk_disable_unprepare(spifc->clk);
+
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+#ifdef CONFIG_PM_RUNTIME
+static int meson_spifc_runtime_suspend(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_master_get_devdata(master);
+
+ clk_disable_unprepare(spifc->clk);
+
+ return 0;
+}
+
+static int meson_spifc_runtime_resume(struct device *dev)
+{
+ struct spi_master *master = dev_get_drvdata(dev);
+ struct meson_spifc *spifc = spi_master_get_devdata(master);
+
+ return clk_prepare_enable(spifc->clk);
+}
+#endif /* CONFIG_PM_RUNTIME */
+
+static const struct dev_pm_ops meson_spifc_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(meson_spifc_suspend, meson_spifc_resume)
+ SET_RUNTIME_PM_OPS(meson_spifc_runtime_suspend,
+ meson_spifc_runtime_resume,
+ NULL)
+};
+
+static const struct of_device_id meson_spifc_dt_match[] = {
+ { .compatible = "amlogic,meson6-spifc", },
+ { },
+};
+
+static struct platform_driver meson_spifc_driver = {
+ .probe = meson_spifc_probe,
+ .remove = meson_spifc_remove,
+ .driver = {
+ .name = "meson-spifc",
+ .of_match_table = of_match_ptr(meson_spifc_dt_match),
+ .pm = &meson_spifc_pm_ops,
+ },
+};
+
+module_platform_driver(meson_spifc_driver);
+
+MODULE_AUTHOR("Beniamino Galvani <b.galvani@gmail.com>");
+MODULE_DESCRIPTION("Amlogic Meson SPIFC driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/spi/spi-mxs.c b/drivers/spi/spi-mxs.c
index 5146087..06a1154 100644
--- a/drivers/spi/spi-mxs.c
+++ b/drivers/spi/spi-mxs.c
@@ -182,7 +182,6 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
int min, ret;
u32 ctrl0;
struct page *vm_page;
- void *sg_buf;
struct {
u32 pio[4];
struct scatterlist sg;
@@ -232,13 +231,14 @@ static int mxs_spi_txrx_dma(struct mxs_spi *spi,
ret = -ENOMEM;
goto err_vmalloc;
}
- sg_buf = page_address(vm_page) +
- ((size_t)buf & ~PAGE_MASK);
+
+ sg_init_table(&dma_xfer[sg_count].sg, 1);
+ sg_set_page(&dma_xfer[sg_count].sg, vm_page,
+ min, offset_in_page(buf));
} else {
- sg_buf = buf;
+ sg_init_one(&dma_xfer[sg_count].sg, buf, min);
}
- sg_init_one(&dma_xfer[sg_count].sg, sg_buf, min);
ret = dma_map_sg(ssp->dev, &dma_xfer[sg_count].sg, 1,
(flags & TXRX_WRITE) ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
@@ -511,7 +511,7 @@ static int mxs_spi_probe(struct platform_device *pdev)
init_completion(&spi->c);
ret = devm_request_irq(&pdev->dev, irq_err, mxs_ssp_irq_handler, 0,
- DRIVER_NAME, ssp);
+ dev_name(&pdev->dev), ssp);
if (ret)
goto out_master_free;
diff --git a/drivers/spi/spi-pl022.c b/drivers/spi/spi-pl022.c
index fc2dd84..89ca162 100644
--- a/drivers/spi/spi-pl022.c
+++ b/drivers/spi/spi-pl022.c
@@ -2377,7 +2377,7 @@ static int pl022_runtime_resume(struct device *dev)
static const struct dev_pm_ops pl022_dev_pm_ops = {
SET_SYSTEM_SLEEP_PM_OPS(pl022_suspend, pl022_resume)
- SET_PM_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
+ SET_RUNTIME_PM_OPS(pl022_runtime_suspend, pl022_runtime_resume, NULL)
};
static struct vendor_data vendor_arm = {
diff --git a/drivers/spi/spi-pxa2xx-pci.c b/drivers/spi/spi-pxa2xx-pci.c
index 6beee8c..fa7399e 100644
--- a/drivers/spi/spi-pxa2xx-pci.c
+++ b/drivers/spi/spi-pxa2xx-pci.c
@@ -19,6 +19,7 @@ enum {
PORT_BSW0,
PORT_BSW1,
PORT_BSW2,
+ PORT_QUARK_X1000,
};
struct pxa_spi_info {
@@ -92,6 +93,12 @@ static struct pxa_spi_info spi_info_configs[] = {
.tx_param = &bsw2_tx_param,
.rx_param = &bsw2_rx_param,
},
+ [PORT_QUARK_X1000] = {
+ .type = QUARK_X1000_SSP,
+ .port_id = -1,
+ .num_chipselect = 1,
+ .max_clk_rate = 50000000,
+ },
};
static int pxa2xx_spi_pci_probe(struct pci_dev *dev,
@@ -191,6 +198,7 @@ static void pxa2xx_spi_pci_remove(struct pci_dev *dev)
static const struct pci_device_id pxa2xx_spi_pci_devices[] = {
{ PCI_VDEVICE(INTEL, 0x2e6a), PORT_CE4100 },
+ { PCI_VDEVICE(INTEL, 0x0935), PORT_QUARK_X1000 },
{ PCI_VDEVICE(INTEL, 0x0f0e), PORT_BYT },
{ PCI_VDEVICE(INTEL, 0x228e), PORT_BSW0 },
{ PCI_VDEVICE(INTEL, 0x2290), PORT_BSW1 },
diff --git a/drivers/spi/spi-pxa2xx.c b/drivers/spi/spi-pxa2xx.c
index 9e9e0f9..1a1df50 100644
--- a/drivers/spi/spi-pxa2xx.c
+++ b/drivers/spi/spi-pxa2xx.c
@@ -63,10 +63,64 @@ MODULE_ALIAS("platform:pxa2xx-spi");
| SSCR1_RFT | SSCR1_TFT | SSCR1_MWDS \
| SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+#define QUARK_X1000_SSCR1_CHANGE_MASK (QUARK_X1000_SSCR1_STRF \
+ | QUARK_X1000_SSCR1_EFWR \
+ | QUARK_X1000_SSCR1_RFT \
+ | QUARK_X1000_SSCR1_TFT \
+ | SSCR1_SPH | SSCR1_SPO | SSCR1_LBM)
+
#define LPSS_RX_THRESH_DFLT 64
#define LPSS_TX_LOTHRESH_DFLT 160
#define LPSS_TX_HITHRESH_DFLT 224
+struct quark_spi_rate {
+ u32 bitrate;
+ u32 dds_clk_rate;
+ u32 clk_div;
+};
+
+/*
+ * 'rate', 'dds', 'clk_div' lookup table, which is defined in
+ * the Quark SPI datasheet.
+ */
+static const struct quark_spi_rate quark_spi_rate_table[] = {
+/* bitrate, dds_clk_rate, clk_div */
+ {50000000, 0x800000, 0},
+ {40000000, 0x666666, 0},
+ {25000000, 0x400000, 0},
+ {20000000, 0x666666, 1},
+ {16667000, 0x800000, 2},
+ {13333000, 0x666666, 2},
+ {12500000, 0x200000, 0},
+ {10000000, 0x800000, 4},
+ {8000000, 0x666666, 4},
+ {6250000, 0x400000, 3},
+ {5000000, 0x400000, 4},
+ {4000000, 0x666666, 9},
+ {3125000, 0x80000, 0},
+ {2500000, 0x400000, 9},
+ {2000000, 0x666666, 19},
+ {1563000, 0x40000, 0},
+ {1250000, 0x200000, 9},
+ {1000000, 0x400000, 24},
+ {800000, 0x666666, 49},
+ {781250, 0x20000, 0},
+ {625000, 0x200000, 19},
+ {500000, 0x400000, 49},
+ {400000, 0x666666, 99},
+ {390625, 0x10000, 0},
+ {250000, 0x400000, 99},
+ {200000, 0x666666, 199},
+ {195313, 0x8000, 0},
+ {125000, 0x100000, 49},
+ {100000, 0x200000, 124},
+ {50000, 0x100000, 124},
+ {25000, 0x80000, 124},
+ {10016, 0x20000, 77},
+ {5040, 0x20000, 154},
+ {1002, 0x8000, 194},
+};
+
/* Offset from drv_data->lpss_base */
#define GENERAL_REG 0x08
#define GENERAL_REG_RXTO_HOLDOFF_DISABLE BIT(24)
@@ -80,6 +134,96 @@ static bool is_lpss_ssp(const struct driver_data *drv_data)
return drv_data->ssp_type == LPSS_SSP;
}
+static bool is_quark_x1000_ssp(const struct driver_data *drv_data)
+{
+ return drv_data->ssp_type == QUARK_X1000_SSP;
+}
+
+static u32 pxa2xx_spi_get_ssrc1_change_mask(const struct driver_data *drv_data)
+{
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ return QUARK_X1000_SSCR1_CHANGE_MASK;
+ default:
+ return SSCR1_CHANGE_MASK;
+ }
+}
+
+static u32
+pxa2xx_spi_get_rx_default_thre(const struct driver_data *drv_data)
+{
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ return RX_THRESH_QUARK_X1000_DFLT;
+ default:
+ return RX_THRESH_DFLT;
+ }
+}
+
+static bool pxa2xx_spi_txfifo_full(const struct driver_data *drv_data)
+{
+ void __iomem *reg = drv_data->ioaddr;
+ u32 mask;
+
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ mask = QUARK_X1000_SSSR_TFL_MASK;
+ break;
+ default:
+ mask = SSSR_TFL_MASK;
+ break;
+ }
+
+ return (read_SSSR(reg) & mask) == mask;
+}
+
+static void pxa2xx_spi_clear_rx_thre(const struct driver_data *drv_data,
+ u32 *sccr1_reg)
+{
+ u32 mask;
+
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ mask = QUARK_X1000_SSCR1_RFT;
+ break;
+ default:
+ mask = SSCR1_RFT;
+ break;
+ }
+ *sccr1_reg &= ~mask;
+}
+
+static void pxa2xx_spi_set_rx_thre(const struct driver_data *drv_data,
+ u32 *sccr1_reg, u32 threshold)
+{
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ *sccr1_reg |= QUARK_X1000_SSCR1_RxTresh(threshold);
+ break;
+ default:
+ *sccr1_reg |= SSCR1_RxTresh(threshold);
+ break;
+ }
+}
+
+static u32 pxa2xx_configure_sscr0(const struct driver_data *drv_data,
+ u32 clk_div, u8 bits)
+{
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ return clk_div
+ | QUARK_X1000_SSCR0_Motorola
+ | QUARK_X1000_SSCR0_DataSize(bits > 32 ? 8 : bits)
+ | SSCR0_SSE;
+ default:
+ return clk_div
+ | SSCR0_Motorola
+ | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
+ | SSCR0_SSE
+ | (bits > 16 ? SSCR0_EDSS : 0);
+ }
+}
+
/*
* Read and write LPSS SSP private registers. Caller must first check that
* is_lpss_ssp() returns true before these can be called.
@@ -234,7 +378,7 @@ static int null_writer(struct driver_data *drv_data)
void __iomem *reg = drv_data->ioaddr;
u8 n_bytes = drv_data->n_bytes;
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+ if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -262,7 +406,7 @@ static int u8_writer(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+ if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -289,7 +433,7 @@ static int u16_writer(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+ if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -316,7 +460,7 @@ static int u32_writer(struct driver_data *drv_data)
{
void __iomem *reg = drv_data->ioaddr;
- if (((read_SSSR(reg) & SSSR_TFL_MASK) == SSSR_TFL_MASK)
+ if (pxa2xx_spi_txfifo_full(drv_data)
|| (drv_data->tx == drv_data->tx_end))
return 0;
@@ -508,8 +652,9 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
* remaining RX bytes.
*/
if (pxa25x_ssp_comp(drv_data)) {
+ u32 rx_thre;
- sccr1_reg &= ~SSCR1_RFT;
+ pxa2xx_spi_clear_rx_thre(drv_data, &sccr1_reg);
bytes_left = drv_data->rx_end - drv_data->rx;
switch (drv_data->n_bytes) {
@@ -519,10 +664,11 @@ static irqreturn_t interrupt_transfer(struct driver_data *drv_data)
bytes_left >>= 1;
}
- if (bytes_left > RX_THRESH_DFLT)
- bytes_left = RX_THRESH_DFLT;
+ rx_thre = pxa2xx_spi_get_rx_default_thre(drv_data);
+ if (rx_thre > bytes_left)
+ rx_thre = bytes_left;
- sccr1_reg |= SSCR1_RxTresh(bytes_left);
+ pxa2xx_spi_set_rx_thre(drv_data, &sccr1_reg, rx_thre);
}
write_SSCR1(sccr1_reg, reg);
}
@@ -585,6 +731,28 @@ static irqreturn_t ssp_int(int irq, void *dev_id)
return drv_data->transfer_handler(drv_data);
}
+/*
+ * The Quark SPI data sheet gives a table, and for the given 'rate',
+ * the 'dds' and 'clk_div' can be found in the table.
+ */
+static u32 quark_x1000_set_clk_regvals(u32 rate, u32 *dds, u32 *clk_div)
+{
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(quark_spi_rate_table); i++) {
+ if (rate >= quark_spi_rate_table[i].bitrate) {
+ *dds = quark_spi_rate_table[i].dds_clk_rate;
+ *clk_div = quark_spi_rate_table[i].clk_div;
+ return quark_spi_rate_table[i].bitrate;
+ }
+ }
+
+ *dds = quark_spi_rate_table[i-1].dds_clk_rate;
+ *clk_div = quark_spi_rate_table[i-1].clk_div;
+
+ return quark_spi_rate_table[i-1].bitrate;
+}
+
static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
{
unsigned long ssp_clk = drv_data->max_clk_rate;
@@ -598,6 +766,20 @@ static unsigned int ssp_get_clk_div(struct driver_data *drv_data, int rate)
return ((ssp_clk / rate - 1) & 0xfff) << 8;
}
+static unsigned int pxa2xx_ssp_get_clk_div(struct driver_data *drv_data,
+ struct chip_data *chip, int rate)
+{
+ u32 clk_div;
+
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ quark_x1000_set_clk_regvals(rate, &chip->dds_rate, &clk_div);
+ return clk_div << 8;
+ default:
+ return ssp_get_clk_div(drv_data, rate);
+ }
+}
+
static void pump_transfers(unsigned long data)
{
struct driver_data *drv_data = (struct driver_data *)data;
@@ -613,6 +795,7 @@ static void pump_transfers(unsigned long data)
u32 cr1;
u32 dma_thresh = drv_data->cur_chip->dma_threshold;
u32 dma_burst = drv_data->cur_chip->dma_burst_size;
+ u32 change_mask = pxa2xx_spi_get_ssrc1_change_mask(drv_data);
/* Get current state information */
message = drv_data->cur_msg;
@@ -699,7 +882,7 @@ static void pump_transfers(unsigned long data)
if (transfer->bits_per_word)
bits = transfer->bits_per_word;
- clk_div = ssp_get_clk_div(drv_data, speed);
+ clk_div = pxa2xx_ssp_get_clk_div(drv_data, chip, speed);
if (bits <= 8) {
drv_data->n_bytes = 1;
@@ -731,11 +914,7 @@ static void pump_transfers(unsigned long data)
"pump_transfers: DMA burst size reduced to match bits_per_word\n");
}
- cr0 = clk_div
- | SSCR0_Motorola
- | SSCR0_DataSize(bits > 16 ? bits - 16 : bits)
- | SSCR0_SSE
- | (bits > 16 ? SSCR0_EDSS : 0);
+ cr0 = pxa2xx_configure_sscr0(drv_data, clk_div, bits);
}
message->state = RUNNING_STATE;
@@ -771,17 +950,20 @@ static void pump_transfers(unsigned long data)
write_SSITF(chip->lpss_tx_threshold, reg);
}
+ if (is_quark_x1000_ssp(drv_data) &&
+ (read_DDS_RATE(reg) != chip->dds_rate))
+ write_DDS_RATE(chip->dds_rate, reg);
+
/* see if we need to reload the config registers */
- if ((read_SSCR0(reg) != cr0)
- || (read_SSCR1(reg) & SSCR1_CHANGE_MASK) !=
- (cr1 & SSCR1_CHANGE_MASK)) {
+ if ((read_SSCR0(reg) != cr0) ||
+ (read_SSCR1(reg) & change_mask) != (cr1 & change_mask)) {
/* stop the SSP, and update the other bits */
write_SSCR0(cr0 & ~SSCR0_SSE, reg);
if (!pxa25x_ssp_comp(drv_data))
write_SSTO(chip->timeout, reg);
/* first set CR1 without interrupt and service enables */
- write_SSCR1(cr1 & SSCR1_CHANGE_MASK, reg);
+ write_SSCR1(cr1 & change_mask, reg);
/* restart the SSP */
write_SSCR0(cr0, reg);
@@ -875,14 +1057,22 @@ static int setup(struct spi_device *spi)
unsigned int clk_div;
uint tx_thres, tx_hi_thres, rx_thres;
- if (is_lpss_ssp(drv_data)) {
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ tx_thres = TX_THRESH_QUARK_X1000_DFLT;
+ tx_hi_thres = 0;
+ rx_thres = RX_THRESH_QUARK_X1000_DFLT;
+ break;
+ case LPSS_SSP:
tx_thres = LPSS_TX_LOTHRESH_DFLT;
tx_hi_thres = LPSS_TX_HITHRESH_DFLT;
rx_thres = LPSS_RX_THRESH_DFLT;
- } else {
+ break;
+ default:
tx_thres = TX_THRESH_DFLT;
tx_hi_thres = 0;
rx_thres = RX_THRESH_DFLT;
+ break;
}
/* Only alloc on first setup */
@@ -935,9 +1125,6 @@ static int setup(struct spi_device *spi)
chip->enable_dma = drv_data->master_info->enable_dma;
}
- chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
- (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
-
chip->lpss_rx_threshold = SSIRF_RxThresh(rx_thres);
chip->lpss_tx_threshold = SSITF_TxLoThresh(tx_thres)
| SSITF_TxHiThresh(tx_hi_thres);
@@ -956,15 +1143,24 @@ static int setup(struct spi_device *spi)
}
}
- clk_div = ssp_get_clk_div(drv_data, spi->max_speed_hz);
+ clk_div = pxa2xx_ssp_get_clk_div(drv_data, chip, spi->max_speed_hz);
chip->speed_hz = spi->max_speed_hz;
- chip->cr0 = clk_div
- | SSCR0_Motorola
- | SSCR0_DataSize(spi->bits_per_word > 16 ?
- spi->bits_per_word - 16 : spi->bits_per_word)
- | SSCR0_SSE
- | (spi->bits_per_word > 16 ? SSCR0_EDSS : 0);
+ chip->cr0 = pxa2xx_configure_sscr0(drv_data, clk_div,
+ spi->bits_per_word);
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ chip->threshold = (QUARK_X1000_SSCR1_RxTresh(rx_thres)
+ & QUARK_X1000_SSCR1_RFT)
+ | (QUARK_X1000_SSCR1_TxTresh(tx_thres)
+ & QUARK_X1000_SSCR1_TFT);
+ break;
+ default:
+ chip->threshold = (SSCR1_RxTresh(rx_thres) & SSCR1_RFT) |
+ (SSCR1_TxTresh(tx_thres) & SSCR1_TFT);
+ break;
+ }
+
chip->cr1 &= ~(SSCR1_SPO | SSCR1_SPH);
chip->cr1 |= (((spi->mode & SPI_CPHA) != 0) ? SSCR1_SPH : 0)
| (((spi->mode & SPI_CPOL) != 0) ? SSCR1_SPO : 0);
@@ -993,7 +1189,8 @@ static int setup(struct spi_device *spi)
chip->read = u16_reader;
chip->write = u16_writer;
} else if (spi->bits_per_word <= 32) {
- chip->cr0 |= SSCR0_EDSS;
+ if (!is_quark_x1000_ssp(drv_data))
+ chip->cr0 |= SSCR0_EDSS;
chip->n_bytes = 4;
chip->read = u32_reader;
chip->write = u32_writer;
@@ -1144,7 +1341,15 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
drv_data->ioaddr = ssp->mmio_base;
drv_data->ssdr_physical = ssp->phys_base + SSDR;
if (pxa25x_ssp_comp(drv_data)) {
- master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 32);
+ break;
+ default:
+ master->bits_per_word_mask = SPI_BPW_RANGE_MASK(4, 16);
+ break;
+ }
+
drv_data->int_cr1 = SSCR1_TIE | SSCR1_RIE;
drv_data->dma_cr1 = 0;
drv_data->clear_sr = SSSR_ROR;
@@ -1182,16 +1387,35 @@ static int pxa2xx_spi_probe(struct platform_device *pdev)
/* Load default SSP configuration */
write_SSCR0(0, drv_data->ioaddr);
- write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
- SSCR1_TxTresh(TX_THRESH_DFLT),
- drv_data->ioaddr);
- write_SSCR0(SSCR0_SCR(2)
- | SSCR0_Motorola
- | SSCR0_DataSize(8),
- drv_data->ioaddr);
+ switch (drv_data->ssp_type) {
+ case QUARK_X1000_SSP:
+ write_SSCR1(QUARK_X1000_SSCR1_RxTresh(
+ RX_THRESH_QUARK_X1000_DFLT) |
+ QUARK_X1000_SSCR1_TxTresh(
+ TX_THRESH_QUARK_X1000_DFLT),
+ drv_data->ioaddr);
+
+ /* using the Motorola SPI protocol and use 8 bit frame */
+ write_SSCR0(QUARK_X1000_SSCR0_Motorola
+ | QUARK_X1000_SSCR0_DataSize(8),
+ drv_data->ioaddr);
+ break;
+ default:
+ write_SSCR1(SSCR1_RxTresh(RX_THRESH_DFLT) |
+ SSCR1_TxTresh(TX_THRESH_DFLT),
+ drv_data->ioaddr);
+ write_SSCR0(SSCR0_SCR(2)
+ | SSCR0_Motorola
+ | SSCR0_DataSize(8),
+ drv_data->ioaddr);
+ break;
+ }
+
if (!pxa25x_ssp_comp(drv_data))
write_SSTO(0, drv_data->ioaddr);
- write_SSPSP(0, drv_data->ioaddr);
+
+ if (!is_quark_x1000_ssp(drv_data))
+ write_SSPSP(0, drv_data->ioaddr);
lpss_ssp_setup(drv_data);
diff --git a/drivers/spi/spi-pxa2xx.h b/drivers/spi/spi-pxa2xx.h
index 5adc2a1..6bec59c 100644
--- a/drivers/spi/spi-pxa2xx.h
+++ b/drivers/spi/spi-pxa2xx.h
@@ -93,6 +93,7 @@ struct driver_data {
struct chip_data {
u32 cr0;
u32 cr1;
+ u32 dds_rate;
u32 psp;
u32 timeout;
u8 n_bytes;
@@ -126,6 +127,7 @@ DEFINE_SSP_REG(SSCR1, 0x04)
DEFINE_SSP_REG(SSSR, 0x08)
DEFINE_SSP_REG(SSITR, 0x0c)
DEFINE_SSP_REG(SSDR, 0x10)
+DEFINE_SSP_REG(DDS_RATE, 0x28) /* DDS Clock Rate */
DEFINE_SSP_REG(SSTO, 0x28)
DEFINE_SSP_REG(SSPSP, 0x2c)
DEFINE_SSP_REG(SSITF, SSITF)
@@ -141,18 +143,22 @@ DEFINE_SSP_REG(SSIRF, SSIRF)
static inline int pxa25x_ssp_comp(struct driver_data *drv_data)
{
- if (drv_data->ssp_type == PXA25x_SSP)
+ switch (drv_data->ssp_type) {
+ case PXA25x_SSP:
+ case CE4100_SSP:
+ case QUARK_X1000_SSP:
return 1;
- if (drv_data->ssp_type == CE4100_SSP)
- return 1;
- return 0;
+ default:
+ return 0;
+ }
}
static inline void write_SSSR_CS(struct driver_data *drv_data, u32 val)
{
void __iomem *reg = drv_data->ioaddr;
- if (drv_data->ssp_type == CE4100_SSP)
+ if (drv_data->ssp_type == CE4100_SSP ||
+ drv_data->ssp_type == QUARK_X1000_SSP)
val |= read_SSSR(reg) & SSSR_ALT_FRM_MASK;
write_SSSR(val, reg);
diff --git a/drivers/spi/spi-rockchip.c b/drivers/spi/spi-rockchip.c
index 87bc16f..80637e9 100644
--- a/drivers/spi/spi-rockchip.c
+++ b/drivers/spi/spi-rockchip.c
@@ -749,8 +749,6 @@ static int rockchip_spi_remove(struct platform_device *pdev)
if (rs->dma_rx.ch)
dma_release_channel(rs->dma_rx.ch);
- spi_master_put(master);
-
return 0;
}
diff --git a/drivers/spi/spi-s3c64xx.c b/drivers/spi/spi-s3c64xx.c
index 480133e..0f602cb 100644
--- a/drivers/spi/spi-s3c64xx.c
+++ b/drivers/spi/spi-s3c64xx.c
@@ -33,8 +33,9 @@
#include <linux/platform_data/spi-s3c64xx.h>
-#define MAX_SPI_PORTS 3
+#define MAX_SPI_PORTS 6
#define S3C64XX_SPI_QUIRK_POLL (1 << 0)
+#define S3C64XX_SPI_QUIRK_CS_AUTO (1 << 1)
/* Registers and bit-fields */
@@ -78,6 +79,7 @@
#define S3C64XX_SPI_SLAVE_AUTO (1<<1)
#define S3C64XX_SPI_SLAVE_SIG_INACT (1<<0)
+#define S3C64XX_SPI_SLAVE_NSC_CNT_2 (2<<4)
#define S3C64XX_SPI_INT_TRAILING_EN (1<<6)
#define S3C64XX_SPI_INT_RX_OVERRUN_EN (1<<5)
@@ -344,16 +346,8 @@ static int s3c64xx_spi_prepare_transfer(struct spi_master *spi)
spi->dma_tx = sdd->tx_dma.ch;
}
- ret = pm_runtime_get_sync(&sdd->pdev->dev);
- if (ret < 0) {
- dev_err(dev, "Failed to enable device: %d\n", ret);
- goto out_tx;
- }
-
return 0;
-out_tx:
- dma_release_channel(sdd->tx_dma.ch);
out_rx:
dma_release_channel(sdd->rx_dma.ch);
out:
@@ -370,7 +364,6 @@ static int s3c64xx_spi_unprepare_transfer(struct spi_master *spi)
dma_release_channel(sdd->tx_dma.ch);
}
- pm_runtime_put(&sdd->pdev->dev);
return 0;
}
@@ -717,7 +710,12 @@ static int s3c64xx_spi_transfer_one(struct spi_master *master,
enable_datapath(sdd, spi, xfer, use_dma);
/* Start the signals */
- writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+ writel(0, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ else
+ writel(readl(sdd->regs + S3C64XX_SPI_SLAVE_SEL)
+ | S3C64XX_SPI_SLAVE_AUTO | S3C64XX_SPI_SLAVE_NSC_CNT_2,
+ sdd->regs + S3C64XX_SPI_SLAVE_SEL);
spin_unlock_irqrestore(&sdd->lock, flags);
@@ -866,13 +864,15 @@ static int s3c64xx_spi_setup(struct spi_device *spi)
}
pm_runtime_put(&sdd->pdev->dev);
- writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+ writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
return 0;
setup_exit:
pm_runtime_put(&sdd->pdev->dev);
/* setup() returns with device de-selected */
- writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+ writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
if (gpio_is_valid(spi->cs_gpio))
gpio_free(spi->cs_gpio);
@@ -946,7 +946,8 @@ static void s3c64xx_spi_hwinit(struct s3c64xx_spi_driver_data *sdd, int channel)
sdd->cur_speed = 0;
- writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
+ if (!(sdd->port_conf->quirks & S3C64XX_SPI_QUIRK_CS_AUTO))
+ writel(S3C64XX_SPI_SLAVE_SIG_INACT, sdd->regs + S3C64XX_SPI_SLAVE_SEL);
/* Disable Interrupts - we use Polling if not DMA mode */
writel(0, regs + S3C64XX_SPI_INT_EN);
@@ -1341,6 +1342,15 @@ static struct s3c64xx_spi_port_config exynos5440_spi_port_config = {
.quirks = S3C64XX_SPI_QUIRK_POLL,
};
+static struct s3c64xx_spi_port_config exynos7_spi_port_config = {
+ .fifo_lvl_mask = { 0x1ff, 0x7F, 0x7F, 0x7F, 0x7F, 0x1ff},
+ .rx_lvl_offset = 15,
+ .tx_st_done = 25,
+ .high_speed = true,
+ .clk_from_cmu = true,
+ .quirks = S3C64XX_SPI_QUIRK_CS_AUTO,
+};
+
static struct platform_device_id s3c64xx_spi_driver_ids[] = {
{
.name = "s3c2443-spi",
@@ -1374,6 +1384,9 @@ static const struct of_device_id s3c64xx_spi_dt_match[] = {
{ .compatible = "samsung,exynos5440-spi",
.data = (void *)&exynos5440_spi_port_config,
},
+ { .compatible = "samsung,exynos7-spi",
+ .data = (void *)&exynos7_spi_port_config,
+ },
{ },
};
MODULE_DEVICE_TABLE(of, s3c64xx_spi_dt_match);
diff --git a/drivers/spi/spi-sirf.c b/drivers/spi/spi-sirf.c
index f63de78..73a88b3 100644
--- a/drivers/spi/spi-sirf.c
+++ b/drivers/spi/spi-sirf.c
@@ -23,6 +23,7 @@
#include <linux/dmaengine.h>
#include <linux/dma-direction.h>
#include <linux/dma-mapping.h>
+#include <linux/reset.h>
#define DRIVER_NAME "sirfsoc_spi"
@@ -134,6 +135,7 @@
ALIGNED(x->len) && (x->len < 2 * PAGE_SIZE))
#define SIRFSOC_MAX_CMD_BYTES 4
+#define SIRFSOC_SPI_DEFAULT_FRQ 1000000
struct sirfsoc_spi {
struct spi_bitbang bitbang;
@@ -629,9 +631,6 @@ static int spi_sirfsoc_setup(struct spi_device *spi)
{
struct sirfsoc_spi *sspi;
- if (!spi->max_speed_hz)
- return -EINVAL;
-
sspi = spi_master_get_devdata(spi->master);
if (spi->cs_gpio == -ENOENT)
@@ -649,6 +648,12 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
int irq;
int i, ret;
+ ret = device_reset(&pdev->dev);
+ if (ret) {
+ dev_err(&pdev->dev, "SPI reset failed!\n");
+ return ret;
+ }
+
master = spi_alloc_master(&pdev->dev, sizeof(*sspi));
if (!master) {
dev_err(&pdev->dev, "Unable to allocate SPI master\n");
@@ -683,6 +688,7 @@ static int spi_sirfsoc_probe(struct platform_device *pdev)
master->mode_bits = SPI_CPOL | SPI_CPHA | SPI_LSB_FIRST | SPI_CS_HIGH;
master->bits_per_word_mask = SPI_BPW_MASK(8) | SPI_BPW_MASK(12) |
SPI_BPW_MASK(16) | SPI_BPW_MASK(32);
+ master->max_speed_hz = SIRFSOC_SPI_DEFAULT_FRQ;
sspi->bitbang.master->dev.of_node = pdev->dev.of_node;
/* request DMA channels */
diff --git a/drivers/spi/spi-txx9.c b/drivers/spi/spi-txx9.c
index 2501a83..f2ab827 100644
--- a/drivers/spi/spi-txx9.c
+++ b/drivers/spi/spi-txx9.c
@@ -402,8 +402,7 @@ exit_busy:
exit:
if (c->workqueue)
destroy_workqueue(c->workqueue);
- if (c->clk)
- clk_disable(c->clk);
+ clk_disable(c->clk);
spi_master_put(master);
return ret;
}
diff --git a/drivers/spi/spi.c b/drivers/spi/spi.c
index 50f20f2..66a70e9 100644
--- a/drivers/spi/spi.c
+++ b/drivers/spi/spi.c
@@ -1001,7 +1001,7 @@ static int spi_init_queue(struct spi_master *master)
dev_name(&master->dev));
if (IS_ERR(master->kworker_task)) {
dev_err(&master->dev, "failed to create message pump task\n");
- return -ENOMEM;
+ return PTR_ERR(master->kworker_task);
}
init_kthread_work(&master->pump_messages, spi_pump_messages);
@@ -1220,6 +1220,121 @@ err_init_queue:
/*-------------------------------------------------------------------------*/
#if defined(CONFIG_OF)
+static struct spi_device *
+of_register_spi_device(struct spi_master *master, struct device_node *nc)
+{
+ struct spi_device *spi;
+ int rc;
+ u32 value;
+
+ /* Alloc an spi_device */
+ spi = spi_alloc_device(master);
+ if (!spi) {
+ dev_err(&master->dev, "spi_device alloc error for %s\n",
+ nc->full_name);
+ rc = -ENOMEM;
+ goto err_out;
+ }
+
+ /* Select device driver */
+ rc = of_modalias_node(nc, spi->modalias,
+ sizeof(spi->modalias));
+ if (rc < 0) {
+ dev_err(&master->dev, "cannot find modalias for %s\n",
+ nc->full_name);
+ goto err_out;
+ }
+
+ /* Device address */
+ rc = of_property_read_u32(nc, "reg", &value);
+ if (rc) {
+ dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
+ nc->full_name, rc);
+ goto err_out;
+ }
+ spi->chip_select = value;
+
+ /* Mode (clock phase/polarity/etc.) */
+ if (of_find_property(nc, "spi-cpha", NULL))
+ spi->mode |= SPI_CPHA;
+ if (of_find_property(nc, "spi-cpol", NULL))
+ spi->mode |= SPI_CPOL;
+ if (of_find_property(nc, "spi-cs-high", NULL))
+ spi->mode |= SPI_CS_HIGH;
+ if (of_find_property(nc, "spi-3wire", NULL))
+ spi->mode |= SPI_3WIRE;
+ if (of_find_property(nc, "spi-lsb-first", NULL))
+ spi->mode |= SPI_LSB_FIRST;
+
+ /* Device DUAL/QUAD mode */
+ if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
+ switch (value) {
+ case 1:
+ break;
+ case 2:
+ spi->mode |= SPI_TX_DUAL;
+ break;
+ case 4:
+ spi->mode |= SPI_TX_QUAD;
+ break;
+ default:
+ dev_warn(&master->dev,
+ "spi-tx-bus-width %d not supported\n",
+ value);
+ break;
+ }
+ }
+
+ if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
+ switch (value) {
+ case 1:
+ break;
+ case 2:
+ spi->mode |= SPI_RX_DUAL;
+ break;
+ case 4:
+ spi->mode |= SPI_RX_QUAD;
+ break;
+ default:
+ dev_warn(&master->dev,
+ "spi-rx-bus-width %d not supported\n",
+ value);
+ break;
+ }
+ }
+
+ /* Device speed */
+ rc = of_property_read_u32(nc, "spi-max-frequency", &value);
+ if (rc) {
+ dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
+ nc->full_name, rc);
+ goto err_out;
+ }
+ spi->max_speed_hz = value;
+
+ /* IRQ */
+ spi->irq = irq_of_parse_and_map(nc, 0);
+
+ /* Store a pointer to the node in the device structure */
+ of_node_get(nc);
+ spi->dev.of_node = nc;
+
+ /* Register the new device */
+ request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias);
+ rc = spi_add_device(spi);
+ if (rc) {
+ dev_err(&master->dev, "spi_device register error %s\n",
+ nc->full_name);
+ goto err_out;
+ }
+
+ return spi;
+
+err_out:
+ spi_dev_put(spi);
+ return ERR_PTR(rc);
+}
+
/**
* of_register_spi_devices() - Register child devices onto the SPI bus
* @master: Pointer to spi_master device
@@ -1231,116 +1346,15 @@ static void of_register_spi_devices(struct spi_master *master)
{
struct spi_device *spi;
struct device_node *nc;
- int rc;
- u32 value;
if (!master->dev.of_node)
return;
for_each_available_child_of_node(master->dev.of_node, nc) {
- /* Alloc an spi_device */
- spi = spi_alloc_device(master);
- if (!spi) {
- dev_err(&master->dev, "spi_device alloc error for %s\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
-
- /* Select device driver */
- if (of_modalias_node(nc, spi->modalias,
- sizeof(spi->modalias)) < 0) {
- dev_err(&master->dev, "cannot find modalias for %s\n",
- nc->full_name);
- spi_dev_put(spi);
- continue;
- }
-
- /* Device address */
- rc = of_property_read_u32(nc, "reg", &value);
- if (rc) {
- dev_err(&master->dev, "%s has no valid 'reg' property (%d)\n",
- nc->full_name, rc);
- spi_dev_put(spi);
- continue;
- }
- spi->chip_select = value;
-
- /* Mode (clock phase/polarity/etc.) */
- if (of_find_property(nc, "spi-cpha", NULL))
- spi->mode |= SPI_CPHA;
- if (of_find_property(nc, "spi-cpol", NULL))
- spi->mode |= SPI_CPOL;
- if (of_find_property(nc, "spi-cs-high", NULL))
- spi->mode |= SPI_CS_HIGH;
- if (of_find_property(nc, "spi-3wire", NULL))
- spi->mode |= SPI_3WIRE;
- if (of_find_property(nc, "spi-lsb-first", NULL))
- spi->mode |= SPI_LSB_FIRST;
-
- /* Device DUAL/QUAD mode */
- if (!of_property_read_u32(nc, "spi-tx-bus-width", &value)) {
- switch (value) {
- case 1:
- break;
- case 2:
- spi->mode |= SPI_TX_DUAL;
- break;
- case 4:
- spi->mode |= SPI_TX_QUAD;
- break;
- default:
- dev_warn(&master->dev,
- "spi-tx-bus-width %d not supported\n",
- value);
- break;
- }
- }
-
- if (!of_property_read_u32(nc, "spi-rx-bus-width", &value)) {
- switch (value) {
- case 1:
- break;
- case 2:
- spi->mode |= SPI_RX_DUAL;
- break;
- case 4:
- spi->mode |= SPI_RX_QUAD;
- break;
- default:
- dev_warn(&master->dev,
- "spi-rx-bus-width %d not supported\n",
- value);
- break;
- }
- }
-
- /* Device speed */
- rc = of_property_read_u32(nc, "spi-max-frequency", &value);
- if (rc) {
- dev_err(&master->dev, "%s has no valid 'spi-max-frequency' property (%d)\n",
- nc->full_name, rc);
- spi_dev_put(spi);
- continue;
- }
- spi->max_speed_hz = value;
-
- /* IRQ */
- spi->irq = irq_of_parse_and_map(nc, 0);
-
- /* Store a pointer to the node in the device structure */
- of_node_get(nc);
- spi->dev.of_node = nc;
-
- /* Register the new device */
- request_module("%s%s", SPI_MODULE_PREFIX, spi->modalias);
- rc = spi_add_device(spi);
- if (rc) {
- dev_err(&master->dev, "spi_device register error %s\n",
+ spi = of_register_spi_device(master, nc);
+ if (IS_ERR(spi))
+ dev_warn(&master->dev, "Failed to create SPI device for %s\n",
nc->full_name);
- spi_dev_put(spi);
- }
-
}
}
#else
@@ -2303,6 +2317,86 @@ EXPORT_SYMBOL_GPL(spi_write_then_read);
/*-------------------------------------------------------------------------*/
+#if IS_ENABLED(CONFIG_OF_DYNAMIC)
+static int __spi_of_device_match(struct device *dev, void *data)
+{
+ return dev->of_node == data;
+}
+
+/* must call put_device() when done with returned spi_device device */
+static struct spi_device *of_find_spi_device_by_node(struct device_node *node)
+{
+ struct device *dev = bus_find_device(&spi_bus_type, NULL, node,
+ __spi_of_device_match);
+ return dev ? to_spi_device(dev) : NULL;
+}
+
+static int __spi_of_master_match(struct device *dev, const void *data)
+{
+ return dev->of_node == data;
+}
+
+/* the spi masters are not using spi_bus, so we find it with another way */
+static struct spi_master *of_find_spi_master_by_node(struct device_node *node)
+{
+ struct device *dev;
+
+ dev = class_find_device(&spi_master_class, NULL, node,
+ __spi_of_master_match);
+ if (!dev)
+ return NULL;
+
+ /* reference got in class_find_device */
+ return container_of(dev, struct spi_master, dev);
+}
+
+static int of_spi_notify(struct notifier_block *nb, unsigned long action,
+ void *arg)
+{
+ struct of_reconfig_data *rd = arg;
+ struct spi_master *master;
+ struct spi_device *spi;
+
+ switch (of_reconfig_get_state_change(action, arg)) {
+ case OF_RECONFIG_CHANGE_ADD:
+ master = of_find_spi_master_by_node(rd->dn->parent);
+ if (master == NULL)
+ return NOTIFY_OK; /* not for us */
+
+ spi = of_register_spi_device(master, rd->dn);
+ put_device(&master->dev);
+
+ if (IS_ERR(spi)) {
+ pr_err("%s: failed to create for '%s'\n",
+ __func__, rd->dn->full_name);
+ return notifier_from_errno(PTR_ERR(spi));
+ }
+ break;
+
+ case OF_RECONFIG_CHANGE_REMOVE:
+ /* find our device by node */
+ spi = of_find_spi_device_by_node(rd->dn);
+ if (spi == NULL)
+ return NOTIFY_OK; /* no? not meant for us */
+
+ /* unregister takes one ref away */
+ spi_unregister_device(spi);
+
+ /* and put the reference of the find */
+ put_device(&spi->dev);
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static struct notifier_block spi_of_notifier = {
+ .notifier_call = of_spi_notify,
+};
+#else /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
+extern struct notifier_block spi_of_notifier;
+#endif /* IS_ENABLED(CONFIG_OF_DYNAMIC) */
+
static int __init spi_init(void)
{
int status;
@@ -2320,6 +2414,10 @@ static int __init spi_init(void)
status = class_register(&spi_master_class);
if (status < 0)
goto err2;
+
+ if (IS_ENABLED(CONFIG_OF_DYNAMIC))
+ WARN_ON(of_reconfig_notifier_register(&spi_of_notifier));
+
return 0;
err2:
diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c
index e50039f..6941e04 100644
--- a/drivers/spi/spidev.c
+++ b/drivers/spi/spidev.c
@@ -87,6 +87,7 @@ struct spidev_data {
unsigned users;
u8 *tx_buffer;
u8 *rx_buffer;
+ u32 speed_hz;
};
static LIST_HEAD(device_list);
@@ -138,6 +139,7 @@ spidev_sync_write(struct spidev_data *spidev, size_t len)
struct spi_transfer t = {
.tx_buf = spidev->tx_buffer,
.len = len,
+ .speed_hz = spidev->speed_hz,
};
struct spi_message m;
@@ -152,6 +154,7 @@ spidev_sync_read(struct spidev_data *spidev, size_t len)
struct spi_transfer t = {
.rx_buf = spidev->rx_buffer,
.len = len,
+ .speed_hz = spidev->speed_hz,
};
struct spi_message m;
@@ -274,6 +277,8 @@ static int spidev_message(struct spidev_data *spidev,
k_tmp->bits_per_word = u_tmp->bits_per_word;
k_tmp->delay_usecs = u_tmp->delay_usecs;
k_tmp->speed_hz = u_tmp->speed_hz;
+ if (!k_tmp->speed_hz)
+ k_tmp->speed_hz = spidev->speed_hz;
#ifdef VERBOSE
dev_dbg(&spidev->spi->dev,
" xfer len %zd %s%s%s%dbits %u usec %uHz\n",
@@ -377,7 +382,7 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
retval = __put_user(spi->bits_per_word, (__u8 __user *)arg);
break;
case SPI_IOC_RD_MAX_SPEED_HZ:
- retval = __put_user(spi->max_speed_hz, (__u32 __user *)arg);
+ retval = __put_user(spidev->speed_hz, (__u32 __user *)arg);
break;
/* write requests */
@@ -441,10 +446,11 @@ spidev_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
spi->max_speed_hz = tmp;
retval = spi_setup(spi);
- if (retval < 0)
- spi->max_speed_hz = save;
+ if (retval >= 0)
+ spidev->speed_hz = tmp;
else
dev_dbg(&spi->dev, "%d Hz (max)\n", tmp);
+ spi->max_speed_hz = save;
}
break;
@@ -570,6 +576,8 @@ static int spidev_release(struct inode *inode, struct file *filp)
kfree(spidev->rx_buffer);
spidev->rx_buffer = NULL;
+ spidev->speed_hz = spidev->spi->max_speed_hz;
+
/* ... after we unbound from the underlying device? */
spin_lock_irq(&spidev->spi_lock);
dofree = (spidev->spi == NULL);
@@ -650,6 +658,8 @@ static int spidev_probe(struct spi_device *spi)
}
mutex_unlock(&device_list_lock);
+ spidev->speed_hz = spi->max_speed_hz;
+
if (status == 0)
spi_set_drvdata(spi, spidev);
else
diff --git a/drivers/staging/iio/light/isl29028.c b/drivers/staging/iio/light/isl29028.c
index 6014625..e969107 100644
--- a/drivers/staging/iio/light/isl29028.c
+++ b/drivers/staging/iio/light/isl29028.c
@@ -537,7 +537,8 @@ static const struct i2c_device_id isl29028_id[] = {
MODULE_DEVICE_TABLE(i2c, isl29028_id);
static const struct of_device_id isl29028_of_match[] = {
- { .compatible = "isil,isl29028", },
+ { .compatible = "isl,isl29028", },
+ { .compatible = "isil,isl29028", },/* deprecated, don't use */
{ },
};
MODULE_DEVICE_TABLE(of, isl29028_of_match);
diff --git a/drivers/staging/lustre/lustre/libcfs/tracefile.c b/drivers/staging/lustre/lustre/libcfs/tracefile.c
index 7e3f6a4..7561030 100644
--- a/drivers/staging/lustre/lustre/libcfs/tracefile.c
+++ b/drivers/staging/lustre/lustre/libcfs/tracefile.c
@@ -1025,8 +1025,8 @@ static int tracefiled(void *arg)
if (f_pos >= (off_t)cfs_tracefile_size)
f_pos = 0;
- else if (f_pos > i_size_read(filp->f_dentry->d_inode))
- f_pos = i_size_read(filp->f_dentry->d_inode);
+ else if (f_pos > i_size_read(file_inode(filp)))
+ f_pos = i_size_read(file_inode(filp));
buf = kmap(tage->page);
rc = vfs_write(filp, (__force const char __user *)buf,
diff --git a/drivers/staging/lustre/lustre/llite/dcache.c b/drivers/staging/lustre/lustre/llite/dcache.c
index 439e487..f692261 100644
--- a/drivers/staging/lustre/lustre/llite/dcache.c
+++ b/drivers/staging/lustre/lustre/llite/dcache.c
@@ -151,10 +151,10 @@ static int ll_ddelete(const struct dentry *de)
{
LASSERT(de);
- CDEBUG(D_DENTRY, "%s dentry %.*s (%p, parent %p, inode %p) %s%s\n",
+ CDEBUG(D_DENTRY, "%s dentry %pd (%p, parent %p, inode %p) %s%s\n",
d_lustre_invalid((struct dentry *)de) ? "deleting" : "keeping",
- de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode,
- d_unhashed((struct dentry *)de) ? "" : "hashed,",
+ de, de, de->d_parent, de->d_inode,
+ d_unhashed(de) ? "" : "hashed,",
list_empty(&de->d_subdirs) ? "" : "subdirs");
/* kernel >= 2.6.38 last refcount is decreased after this function. */
@@ -180,8 +180,8 @@ int ll_d_init(struct dentry *de)
{
LASSERT(de != NULL);
- CDEBUG(D_DENTRY, "ldd on dentry %.*s (%p) parent %p inode %p refc %d\n",
- de->d_name.len, de->d_name.name, de, de->d_parent, de->d_inode,
+ CDEBUG(D_DENTRY, "ldd on dentry %pd (%p) parent %p inode %p refc %d\n",
+ de, de, de->d_parent, de->d_inode,
d_count(de));
if (de->d_fsdata == NULL) {
@@ -258,10 +258,9 @@ void ll_invalidate_aliases(struct inode *inode)
inode->i_ino, inode->i_generation, inode);
ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
- CDEBUG(D_DENTRY, "dentry in drop %.*s (%p) parent %p "
- "inode %p flags %d\n", dentry->d_name.len,
- dentry->d_name.name, dentry, dentry->d_parent,
+ ll_d_hlist_for_each_entry(dentry, p, &inode->i_dentry, d_u.d_alias) {
+ CDEBUG(D_DENTRY, "dentry in drop %pd (%p) parent %p "
+ "inode %p flags %d\n", dentry, dentry, dentry->d_parent,
dentry->d_inode, dentry->d_flags);
if (unlikely(dentry == dentry->d_sb->s_root)) {
@@ -352,8 +351,8 @@ static int ll_revalidate_nd(struct dentry *dentry, unsigned int flags)
{
int rc;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%s, flags=%u\n",
- dentry->d_name.name, flags);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd, flags=%u\n",
+ dentry, flags);
rc = ll_revalidate_dentry(dentry, flags);
return rc;
diff --git a/drivers/staging/lustre/lustre/llite/dir.c b/drivers/staging/lustre/lustre/llite/dir.c
index b0bb709..a79fd65 100644
--- a/drivers/staging/lustre/lustre/llite/dir.c
+++ b/drivers/staging/lustre/lustre/llite/dir.c
@@ -593,7 +593,7 @@ int ll_dir_read(struct inode *inode, struct dir_context *ctx)
static int ll_readdir(struct file *filp, struct dir_context *ctx)
{
- struct inode *inode = filp->f_dentry->d_inode;
+ struct inode *inode = file_inode(filp);
struct ll_file_data *lfd = LUSTRE_FPRIVATE(filp);
struct ll_sb_info *sbi = ll_i2sbi(inode);
int hash64 = sbi->ll_flags & LL_SBI_64BIT_HASH;
@@ -1242,7 +1242,7 @@ ll_getname(const char __user *filename)
static long ll_dir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct obd_ioctl_data *data;
int rc = 0;
@@ -1389,7 +1389,7 @@ lmv_out_free:
return -EFAULT;
}
- if (inode->i_sb->s_root == file->f_dentry)
+ if (is_root_inode(inode))
set_default = 1;
/* in v1 and v3 cases lumv1 points to data */
@@ -1780,8 +1780,7 @@ out_quotactl:
return ll_flush_ctx(inode);
#ifdef CONFIG_FS_POSIX_ACL
case LL_IOC_RMTACL: {
- if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
- inode == inode->i_sb->s_root->d_inode) {
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT && is_root_inode(inode)) {
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
LASSERT(fd != NULL);
diff --git a/drivers/staging/lustre/lustre/llite/file.c b/drivers/staging/lustre/lustre/llite/file.c
index c99b741..a2ae9a6 100644
--- a/drivers/staging/lustre/lustre/llite/file.c
+++ b/drivers/staging/lustre/lustre/llite/file.c
@@ -266,6 +266,10 @@ static int ll_md_close(struct obd_export *md_exp, struct inode *inode,
{
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct ll_inode_info *lli = ll_i2info(inode);
+ int lockmode;
+ __u64 flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_TEST_LOCK;
+ struct lustre_handle lockh;
+ ldlm_policy_data_t policy = {.l_inodebits={MDS_INODELOCK_OPEN}};
int rc = 0;
/* clear group lock, if present */
@@ -292,39 +296,26 @@ static int ll_md_close(struct obd_export *md_exp, struct inode *inode,
/* Let's see if we have good enough OPEN lock on the file and if
we can skip talking to MDS */
- if (file->f_dentry->d_inode) { /* Can this ever be false? */
- int lockmode;
- __u64 flags = LDLM_FL_BLOCK_GRANTED | LDLM_FL_TEST_LOCK;
- struct lustre_handle lockh;
- struct inode *inode = file->f_dentry->d_inode;
- ldlm_policy_data_t policy = {.l_inodebits={MDS_INODELOCK_OPEN}};
-
- mutex_lock(&lli->lli_och_mutex);
- if (fd->fd_omode & FMODE_WRITE) {
- lockmode = LCK_CW;
- LASSERT(lli->lli_open_fd_write_count);
- lli->lli_open_fd_write_count--;
- } else if (fd->fd_omode & FMODE_EXEC) {
- lockmode = LCK_PR;
- LASSERT(lli->lli_open_fd_exec_count);
- lli->lli_open_fd_exec_count--;
- } else {
- lockmode = LCK_CR;
- LASSERT(lli->lli_open_fd_read_count);
- lli->lli_open_fd_read_count--;
- }
- mutex_unlock(&lli->lli_och_mutex);
- if (!md_lock_match(md_exp, flags, ll_inode2fid(inode),
- LDLM_IBITS, &policy, lockmode,
- &lockh)) {
- rc = ll_md_real_close(file->f_dentry->d_inode,
- fd->fd_omode);
- }
+ mutex_lock(&lli->lli_och_mutex);
+ if (fd->fd_omode & FMODE_WRITE) {
+ lockmode = LCK_CW;
+ LASSERT(lli->lli_open_fd_write_count);
+ lli->lli_open_fd_write_count--;
+ } else if (fd->fd_omode & FMODE_EXEC) {
+ lockmode = LCK_PR;
+ LASSERT(lli->lli_open_fd_exec_count);
+ lli->lli_open_fd_exec_count--;
} else {
- CERROR("Releasing a file %p with negative dentry %p. Name %s",
- file, file->f_dentry, file->f_dentry->d_name.name);
+ lockmode = LCK_CR;
+ LASSERT(lli->lli_open_fd_read_count);
+ lli->lli_open_fd_read_count--;
}
+ mutex_unlock(&lli->lli_och_mutex);
+
+ if (!md_lock_match(md_exp, flags, ll_inode2fid(inode),
+ LDLM_IBITS, &policy, lockmode, &lockh))
+ rc = ll_md_real_close(inode, fd->fd_omode);
out:
LUSTRE_FPRIVATE(file) = NULL;
@@ -350,8 +341,7 @@ int ll_file_release(struct inode *inode, struct file *file)
inode->i_generation, inode);
#ifdef CONFIG_FS_POSIX_ACL
- if (sbi->ll_flags & LL_SBI_RMT_CLIENT &&
- inode == inode->i_sb->s_root->d_inode) {
+ if (sbi->ll_flags & LL_SBI_RMT_CLIENT && is_root_inode(inode)) {
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
LASSERT(fd != NULL);
@@ -363,7 +353,7 @@ int ll_file_release(struct inode *inode, struct file *file)
}
#endif
- if (inode->i_sb->s_root != file->f_dentry)
+ if (!is_root_inode(inode))
ll_stats_ops_tally(sbi, LPROC_LL_RELEASE, 1);
fd = LUSTRE_FPRIVATE(file);
LASSERT(fd != NULL);
@@ -375,7 +365,7 @@ int ll_file_release(struct inode *inode, struct file *file)
lli->lli_opendir_pid != 0)
ll_stop_statahead(inode, lli->lli_opendir_key);
- if (inode->i_sb->s_root == file->f_dentry) {
+ if (is_root_inode(inode)) {
LUSTRE_FPRIVATE(file) = NULL;
ll_file_data_put(fd);
return 0;
@@ -394,21 +384,19 @@ int ll_file_release(struct inode *inode, struct file *file)
return rc;
}
-static int ll_intent_file_open(struct file *file, void *lmm,
+static int ll_intent_file_open(struct dentry *dentry, void *lmm,
int lmmsize, struct lookup_intent *itp)
{
- struct ll_sb_info *sbi = ll_i2sbi(file->f_dentry->d_inode);
- struct dentry *parent = file->f_dentry->d_parent;
- const char *name = file->f_dentry->d_name.name;
- const int len = file->f_dentry->d_name.len;
+ struct inode *inode = dentry->d_inode;
+ struct ll_sb_info *sbi = ll_i2sbi(inode);
+ struct dentry *parent = dentry->d_parent;
+ const char *name = dentry->d_name.name;
+ const int len = dentry->d_name.len;
struct md_op_data *op_data;
struct ptlrpc_request *req;
__u32 opc = LUSTRE_OPC_ANY;
int rc;
- if (!parent)
- return -ENOENT;
-
/* Usually we come here only for NFSD, and we want open lock.
But we can also get here with pre 2.6.15 patchless kernels, and in
that case that lock is also ok */
@@ -425,7 +413,7 @@ static int ll_intent_file_open(struct file *file, void *lmm,
}
op_data = ll_prep_md_op_data(NULL, parent->d_inode,
- file->f_dentry->d_inode, name, len,
+ inode, name, len,
O_RDWR, opc, NULL);
if (IS_ERR(op_data))
return PTR_ERR(op_data);
@@ -441,7 +429,7 @@ static int ll_intent_file_open(struct file *file, void *lmm,
if (!it_disposition(itp, DISP_OPEN_OPEN) ||
it_open_error(DISP_OPEN_OPEN, itp))
goto out;
- ll_release_openhandle(file->f_dentry, itp);
+ ll_release_openhandle(inode, itp);
goto out;
}
@@ -456,10 +444,9 @@ static int ll_intent_file_open(struct file *file, void *lmm,
goto out;
}
- rc = ll_prep_inode(&file->f_dentry->d_inode, req, NULL, itp);
+ rc = ll_prep_inode(&inode, req, NULL, itp);
if (!rc && itp->d.lustre.it_lock_mode)
- ll_set_lock_data(sbi->ll_md_exp, file->f_dentry->d_inode,
- itp, NULL);
+ ll_set_lock_data(sbi->ll_md_exp, inode, itp, NULL);
out:
ptlrpc_req_finished(req);
@@ -501,7 +488,7 @@ static int ll_och_fill(struct obd_export *md_exp, struct lookup_intent *it,
static int ll_local_open(struct file *file, struct lookup_intent *it,
struct ll_file_data *fd, struct obd_client_handle *och)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ll_inode_info *lli = ll_i2info(inode);
LASSERT(!LUSTRE_FPRIVATE(file));
@@ -574,7 +561,7 @@ int ll_file_open(struct inode *inode, struct file *file)
spin_unlock(&lli->lli_sa_lock);
}
- if (inode->i_sb->s_root == file->f_dentry) {
+ if (is_root_inode(inode)) {
LUSTRE_FPRIVATE(file) = fd;
return 0;
}
@@ -632,7 +619,7 @@ restart:
goto out_openerr;
}
- ll_release_openhandle(file->f_dentry, it);
+ ll_release_openhandle(inode, it);
}
(*och_usecount)++;
@@ -652,7 +639,7 @@ restart:
result in a deadlock */
mutex_unlock(&lli->lli_och_mutex);
it->it_create_mode |= M_CHECK_STALE;
- rc = ll_intent_file_open(file, NULL, 0, it);
+ rc = ll_intent_file_open(file->f_path.dentry, NULL, 0, it);
it->it_create_mode &= ~M_CHECK_STALE;
if (rc)
goto out_openerr;
@@ -1065,7 +1052,7 @@ int ll_glimpse_ioctl(struct ll_sb_info *sbi, struct lov_stripe_md *lsm,
static bool file_is_noatime(const struct file *file)
{
const struct vfsmount *mnt = file->f_path.mnt;
- const struct inode *inode = file->f_path.dentry->d_inode;
+ const struct inode *inode = file_inode(file);
/* Adapted from file_accessed() and touch_atime().*/
if (file->f_flags & O_NOATIME)
@@ -1091,7 +1078,7 @@ static bool file_is_noatime(const struct file *file)
void ll_io_init(struct cl_io *io, const struct file *file, int write)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
io->u.ci_rw.crw_nonblock = file->f_flags & O_NONBLOCK;
if (write) {
@@ -1117,7 +1104,7 @@ ll_file_io_generic(const struct lu_env *env, struct vvp_io_args *args,
struct file *file, enum cl_io_type iot,
loff_t *ppos, size_t count)
{
- struct ll_inode_info *lli = ll_i2info(file->f_dentry->d_inode);
+ struct ll_inode_info *lli = ll_i2info(file_inode(file));
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
struct cl_io *io;
ssize_t result;
@@ -1178,20 +1165,20 @@ out:
/* If any bit been read/written (result != 0), we just return
* short read/write instead of restart io. */
if ((result == 0 || result == -ENODATA) && io->ci_need_restart) {
- CDEBUG(D_VFSTRACE, "Restart %s on %s from %lld, count:%zd\n",
+ CDEBUG(D_VFSTRACE, "Restart %s on %pD from %lld, count:%zd\n",
iot == CIT_READ ? "read" : "write",
- file->f_dentry->d_name.name, *ppos, count);
+ file, *ppos, count);
LASSERTF(io->ci_nob == 0, "%zd", io->ci_nob);
goto restart;
}
if (iot == CIT_READ) {
if (result >= 0)
- ll_stats_ops_tally(ll_i2sbi(file->f_dentry->d_inode),
+ ll_stats_ops_tally(ll_i2sbi(file_inode(file)),
LPROC_LL_READ_BYTES, result);
} else if (iot == CIT_WRITE) {
if (result >= 0) {
- ll_stats_ops_tally(ll_i2sbi(file->f_dentry->d_inode),
+ ll_stats_ops_tally(ll_i2sbi(file_inode(file)),
LPROC_LL_WRITE_BYTES, result);
fd->fd_write_failed = false;
} else if (result != -ERESTARTSYS) {
@@ -1354,7 +1341,7 @@ static int ll_lov_recreate_fid(struct inode *inode, unsigned long arg)
return ll_lov_recreate(inode, &oi, ost_idx);
}
-int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
+int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry,
int flags, struct lov_user_md *lum, int lum_size)
{
struct lov_stripe_md *lsm = NULL;
@@ -1371,21 +1358,20 @@ int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
}
ll_inode_size_lock(inode);
- rc = ll_intent_file_open(file, lum, lum_size, &oit);
+ rc = ll_intent_file_open(dentry, lum, lum_size, &oit);
if (rc)
goto out_unlock;
rc = oit.d.lustre.it_status;
if (rc < 0)
goto out_req_free;
- ll_release_openhandle(file->f_dentry, &oit);
+ ll_release_openhandle(inode, &oit);
out_unlock:
ll_inode_size_unlock(inode);
ll_intent_release(&oit);
ccc_inode_lsm_put(inode, lsm);
out:
- cl_lov_delay_create_clear(&file->f_flags);
return rc;
out_req_free:
ptlrpc_req_finished((struct ptlrpc_request *) oit.d.lustre.it_data);
@@ -1499,7 +1485,9 @@ static int ll_lov_setea(struct inode *inode, struct file *file,
return -EFAULT;
}
- rc = ll_lov_setstripe_ea_info(inode, file, flags, lump, lum_size);
+ rc = ll_lov_setstripe_ea_info(inode, file->f_path.dentry, flags, lump,
+ lum_size);
+ cl_lov_delay_create_clear(&file->f_flags);
OBD_FREE_LARGE(lump, lum_size);
return rc;
@@ -1526,7 +1514,9 @@ static int ll_lov_setstripe(struct inode *inode, struct file *file,
return -EFAULT;
}
- rc = ll_lov_setstripe_ea_info(inode, file, flags, lumv1, lum_size);
+ rc = ll_lov_setstripe_ea_info(inode, file->f_path.dentry, flags, lumv1,
+ lum_size);
+ cl_lov_delay_create_clear(&file->f_flags);
if (rc == 0) {
struct lov_stripe_md *lsm;
__u32 gen;
@@ -1631,22 +1621,21 @@ int ll_put_grouplock(struct inode *inode, struct file *file, unsigned long arg)
/**
* Close inode open handle
*
- * \param dentry [in] dentry which contains the inode
+ * \param inode [in] inode in question
* \param it [in,out] intent which contains open info and result
*
* \retval 0 success
* \retval <0 failure
*/
-int ll_release_openhandle(struct dentry *dentry, struct lookup_intent *it)
+int ll_release_openhandle(struct inode *inode, struct lookup_intent *it)
{
- struct inode *inode = dentry->d_inode;
struct obd_client_handle *och;
int rc;
LASSERT(inode);
/* Root ? Do nothing. */
- if (dentry->d_inode->i_sb->s_root == dentry)
+ if (is_root_inode(inode))
return 0;
/* No open handle to close? Move away */
@@ -1959,8 +1948,8 @@ static int ll_swap_layouts(struct file *file1, struct file *file2,
if (!llss)
return -ENOMEM;
- llss->inode1 = file1->f_dentry->d_inode;
- llss->inode2 = file2->f_dentry->d_inode;
+ llss->inode1 = file_inode(file1);
+ llss->inode2 = file_inode(file2);
if (!S_ISREG(llss->inode2->i_mode)) {
rc = -EINVAL;
@@ -2092,7 +2081,7 @@ putgl:
rc = 0;
if (llss->ia2.ia_valid != 0) {
mutex_lock(&llss->inode1->i_mutex);
- rc = ll_setattr(file1->f_dentry, &llss->ia2);
+ rc = ll_setattr(file1->f_path.dentry, &llss->ia2);
mutex_unlock(&llss->inode1->i_mutex);
}
@@ -2100,7 +2089,7 @@ putgl:
int rc1;
mutex_lock(&llss->inode2->i_mutex);
- rc1 = ll_setattr(file2->f_dentry, &llss->ia1);
+ rc1 = ll_setattr(file2->f_path.dentry, &llss->ia1);
mutex_unlock(&llss->inode2->i_mutex);
if (rc == 0)
rc = rc1;
@@ -2185,7 +2174,7 @@ static int ll_hsm_import(struct inode *inode, struct file *file,
mutex_lock(&inode->i_mutex);
- rc = ll_setattr_raw(file->f_dentry, attr, true);
+ rc = ll_setattr_raw(file->f_path.dentry, attr, true);
if (rc == -ENODATA)
rc = 0;
@@ -2204,7 +2193,7 @@ out:
static long
ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
int flags, rc;
@@ -2523,7 +2512,7 @@ ll_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
static loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
loff_t retval, eof = 0;
retval = offset + ((origin == SEEK_END) ? i_size_read(inode) :
@@ -2547,7 +2536,7 @@ static loff_t ll_file_seek(struct file *file, loff_t offset, int origin)
static int ll_flush(struct file *file, fl_owner_t id)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ll_inode_info *lli = ll_i2info(inode);
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
int rc, err;
@@ -2622,16 +2611,9 @@ int cl_sync_file_range(struct inode *inode, loff_t start, loff_t end,
return result;
}
-/*
- * When dentry is provided (the 'else' case), *file->f_dentry may be
- * null and dentry must be used directly rather than pulled from
- * *file->f_dentry as is done otherwise.
- */
-
int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
- struct dentry *dentry = file->f_dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ll_inode_info *lli = ll_i2info(inode);
struct ptlrpc_request *req;
struct obd_capa *oc;
@@ -2684,7 +2666,7 @@ int ll_fsync(struct file *file, loff_t start, loff_t end, int datasync)
static int
ll_file_flock(struct file *file, int cmd, struct file_lock *file_lock)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ll_sb_info *sbi = ll_i2sbi(inode);
struct ldlm_enqueue_info einfo = {
.ei_type = LDLM_FLOCK,
@@ -2908,8 +2890,8 @@ static int __ll_inode_revalidate(struct dentry *dentry, __u64 ibits)
LASSERT(inode != NULL);
- CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),name=%s\n",
- inode->i_ino, inode->i_generation, inode, dentry->d_name.name);
+ CDEBUG(D_VFSTRACE, "VFS Op:inode=%lu/%u(%p),name=%pd\n",
+ inode->i_ino, inode->i_generation, inode, dentry);
exp = ll_i2mdexp(inode);
@@ -3119,7 +3101,7 @@ int ll_inode_permission(struct inode *inode, int mask)
/* as root inode are NOT getting validated in lookup operation,
* need to do it before permission check. */
- if (inode == inode->i_sb->s_root->d_inode) {
+ if (is_root_inode(inode)) {
rc = __ll_inode_revalidate(inode->i_sb->s_root,
MDS_INODELOCK_LOOKUP);
if (rc)
diff --git a/drivers/staging/lustre/lustre/llite/llite_internal.h b/drivers/staging/lustre/lustre/llite/llite_internal.h
index 36aa0fd..77d1c127 100644
--- a/drivers/staging/lustre/lustre/llite/llite_internal.h
+++ b/drivers/staging/lustre/lustre/llite/llite_internal.h
@@ -748,7 +748,7 @@ int ll_file_release(struct inode *inode, struct file *file);
int ll_glimpse_ioctl(struct ll_sb_info *sbi,
struct lov_stripe_md *lsm, lstat_t *st);
void ll_ioepoch_open(struct ll_inode_info *lli, __u64 ioepoch);
-int ll_release_openhandle(struct dentry *, struct lookup_intent *);
+int ll_release_openhandle(struct inode *, struct lookup_intent *);
int ll_md_real_close(struct inode *inode, fmode_t fmode);
void ll_ioepoch_close(struct inode *inode, struct md_op_data *op_data,
struct obd_client_handle **och, unsigned long flags);
@@ -763,7 +763,7 @@ struct posix_acl *ll_get_acl(struct inode *inode, int type);
int ll_inode_permission(struct inode *inode, int mask);
-int ll_lov_setstripe_ea_info(struct inode *inode, struct file *file,
+int ll_lov_setstripe_ea_info(struct inode *inode, struct dentry *dentry,
int flags, struct lov_user_md *lum,
int lum_size);
int ll_lov_getstripe_ea_info(struct inode *inode, const char *filename,
@@ -1413,7 +1413,7 @@ extern ssize_t ll_direct_rw_pages(const struct lu_env *env, struct cl_io *io,
static inline int ll_file_nolock(const struct file *file)
{
struct ll_file_data *fd = LUSTRE_FPRIVATE(file);
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
LASSERT(fd != NULL);
return ((fd->fd_flags & LL_FILE_IGNORE_LOCK) ||
@@ -1489,8 +1489,8 @@ static inline void __d_lustre_invalidate(struct dentry *dentry)
*/
static inline void d_lustre_invalidate(struct dentry *dentry, int nested)
{
- CDEBUG(D_DENTRY, "invalidate dentry %.*s (%p) parent %p inode %p "
- "refc %d\n", dentry->d_name.len, dentry->d_name.name, dentry,
+ CDEBUG(D_DENTRY, "invalidate dentry %pd (%p) parent %p inode %p "
+ "refc %d\n", dentry, dentry,
dentry->d_parent, dentry->d_inode, d_count(dentry));
spin_lock_nested(&dentry->d_lock,
diff --git a/drivers/staging/lustre/lustre/llite/llite_lib.c b/drivers/staging/lustre/lustre/llite/llite_lib.c
index a8bcc51..7b6b9e2 100644
--- a/drivers/staging/lustre/lustre/llite/llite_lib.c
+++ b/drivers/staging/lustre/lustre/llite/llite_lib.c
@@ -698,10 +698,8 @@ void lustre_dump_dentry(struct dentry *dentry, int recur)
list_for_each(tmp, &dentry->d_subdirs)
subdirs++;
- CERROR("dentry %p dump: name=%.*s parent=%.*s (%p), inode=%p, count=%u,"
- " flags=0x%x, fsdata=%p, %d subdirs\n", dentry,
- dentry->d_name.len, dentry->d_name.name,
- dentry->d_parent->d_name.len, dentry->d_parent->d_name.name,
+ CERROR("dentry %p dump: name=%pd parent=%p, inode=%p, count=%u,"
+ " flags=0x%x, fsdata=%p, %d subdirs\n", dentry, dentry,
dentry->d_parent, dentry->d_inode, d_count(dentry),
dentry->d_flags, dentry->d_fsdata, subdirs);
if (dentry->d_inode != NULL)
@@ -711,7 +709,7 @@ void lustre_dump_dentry(struct dentry *dentry, int recur)
return;
list_for_each(tmp, &dentry->d_subdirs) {
- struct dentry *d = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(tmp, struct dentry, d_child);
lustre_dump_dentry(d, recur - 1);
}
}
diff --git a/drivers/staging/lustre/lustre/llite/llite_mmap.c b/drivers/staging/lustre/lustre/llite/llite_mmap.c
index ae605a6..ba1c047 100644
--- a/drivers/staging/lustre/lustre/llite/llite_mmap.c
+++ b/drivers/staging/lustre/lustre/llite/llite_mmap.c
@@ -100,7 +100,7 @@ ll_fault_io_init(struct vm_area_struct *vma, struct lu_env **env_ret,
unsigned long *ra_flags)
{
struct file *file = vma->vm_file;
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct cl_io *io;
struct cl_fault_io *fio;
struct lu_env *env;
@@ -213,7 +213,7 @@ static int ll_page_mkwrite0(struct vm_area_struct *vma, struct page *vmpage,
cfs_restore_sigs(set);
if (result == 0) {
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = file_inode(vma->vm_file);
struct ll_inode_info *lli = ll_i2info(inode);
lock_page(vmpage);
@@ -396,7 +396,7 @@ static int ll_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
CWARN("app(%s): the page %lu of file %lu is under heavy"
" contention.\n",
current->comm, vmf->pgoff,
- vma->vm_file->f_dentry->d_inode->i_ino);
+ file_inode(vma->vm_file)->i_ino);
printed = true;
}
} while (retry);
@@ -430,7 +430,7 @@ static int ll_page_mkwrite(struct vm_area_struct *vma, struct vm_fault *vmf)
*/
static void ll_vm_open(struct vm_area_struct *vma)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = file_inode(vma->vm_file);
struct ccc_object *vob = cl_inode2ccc(inode);
LASSERT(vma->vm_file);
@@ -443,7 +443,7 @@ static void ll_vm_open(struct vm_area_struct *vma)
*/
static void ll_vm_close(struct vm_area_struct *vma)
{
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = file_inode(vma->vm_file);
struct ccc_object *vob = cl_inode2ccc(inode);
LASSERT(vma->vm_file);
@@ -476,7 +476,7 @@ static const struct vm_operations_struct ll_file_vm_ops = {
int ll_file_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct inode *inode = file->f_dentry->d_inode;
+ struct inode *inode = file_inode(file);
int rc;
if (ll_file_nolock(file))
diff --git a/drivers/staging/lustre/lustre/llite/llite_nfs.c b/drivers/staging/lustre/lustre/llite/llite_nfs.c
index ae3a12a..243a784 100644
--- a/drivers/staging/lustre/lustre/llite/llite_nfs.c
+++ b/drivers/staging/lustre/lustre/llite/llite_nfs.c
@@ -207,13 +207,15 @@ static int ll_encode_fh(struct inode *inode, __u32 *fh, int *plen,
return LUSTRE_NFS_FID;
}
-static int ll_nfs_get_name_filldir(void *cookie, const char *name, int namelen,
- loff_t hash, u64 ino, unsigned type)
+static int ll_nfs_get_name_filldir(struct dir_context *ctx, const char *name,
+ int namelen, loff_t hash, u64 ino,
+ unsigned type)
{
/* It is hack to access lde_fid for comparison with lgd_fid.
* So the input 'name' must be part of the 'lu_dirent'. */
struct lu_dirent *lde = container_of0(name, struct lu_dirent, lde_name);
- struct ll_getname_data *lgd = cookie;
+ struct ll_getname_data *lgd =
+ container_of(ctx, struct ll_getname_data, ctx);
struct lu_fid fid;
fid_le_to_cpu(&fid, &lde->lde_fid);
diff --git a/drivers/staging/lustre/lustre/llite/lloop.c b/drivers/staging/lustre/lustre/llite/lloop.c
index 264e5ec..9e31b78 100644
--- a/drivers/staging/lustre/lustre/llite/lloop.c
+++ b/drivers/staging/lustre/lustre/llite/lloop.c
@@ -187,7 +187,7 @@ static int do_bio_lustrebacked(struct lloop_device *lo, struct bio *head)
{
const struct lu_env *env = lo->lo_env;
struct cl_io *io = &lo->lo_io;
- struct inode *inode = lo->lo_backing_file->f_dentry->d_inode;
+ struct inode *inode = file_inode(lo->lo_backing_file);
struct cl_object *obj = ll_i2info(inode)->lli_clob;
pgoff_t offset;
int ret;
@@ -626,7 +626,7 @@ static int lo_ioctl(struct block_device *bdev, fmode_t mode,
break;
}
if (inode == NULL)
- inode = lo->lo_backing_file->f_dentry->d_inode;
+ inode = file_inode(lo->lo_backing_file);
if (lo->lo_state == LLOOP_BOUND)
fid = ll_i2info(inode)->lli_fid;
else
@@ -692,8 +692,7 @@ static enum llioc_iter lloop_ioctl(struct inode *unused, struct file *file,
lo_free = lo;
continue;
}
- if (lo->lo_backing_file->f_dentry->d_inode ==
- file->f_dentry->d_inode)
+ if (file_inode(lo->lo_backing_file) == file_inode(file))
break;
}
if (lo || !lo_free) {
diff --git a/drivers/staging/lustre/lustre/llite/namei.c b/drivers/staging/lustre/lustre/llite/namei.c
index 7a68c1e..8e926b3 100644
--- a/drivers/staging/lustre/lustre/llite/namei.c
+++ b/drivers/staging/lustre/lustre/llite/namei.c
@@ -54,27 +54,6 @@
static int ll_create_it(struct inode *, struct dentry *,
int, struct lookup_intent *);
-/*
- * Check if we have something mounted at the named dchild.
- * In such a case there would always be dentry present.
- */
-static int ll_d_mountpoint(struct dentry *dparent, struct dentry *dchild,
- struct qstr *name)
-{
- int mounted = 0;
-
- if (unlikely(dchild)) {
- mounted = d_mountpoint(dchild);
- } else if (dparent) {
- dchild = d_lookup(dparent, name);
- if (dchild) {
- mounted = d_mountpoint(dchild);
- dput(dchild);
- }
- }
- return mounted;
-}
-
/* called from iget5_locked->find_inode() under inode_hash_lock spinlock */
static int ll_test_inode(struct inode *inode, void *opaque)
{
@@ -167,14 +146,14 @@ static void ll_invalidate_negative_children(struct inode *dir)
struct ll_d_hlist_node *p;
ll_lock_dcache(dir);
- ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(dentry, p, &dir->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!list_empty(&dentry->d_subdirs)) {
struct dentry *child;
list_for_each_entry_safe(child, tmp_subdir,
&dentry->d_subdirs,
- d_u.d_child) {
+ d_child) {
if (child->d_inode == NULL)
d_lustre_invalidate(child, 1);
}
@@ -285,7 +264,7 @@ int ll_md_blocking_ast(struct ldlm_lock *lock, struct ldlm_lock_desc *desc,
if ((bits & (MDS_INODELOCK_LOOKUP | MDS_INODELOCK_PERM)) &&
inode->i_sb->s_root != NULL &&
- inode != inode->i_sb->s_root->d_inode)
+ is_root_inode(inode))
ll_invalidate_aliases(inode);
iput(inode);
@@ -362,7 +341,7 @@ static struct dentry *ll_find_alias(struct inode *inode, struct dentry *dentry)
discon_alias = invalid_alias = NULL;
ll_lock_dcache(inode);
- ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
+ ll_d_hlist_for_each_entry(alias, p, &inode->i_dentry, d_u.d_alias) {
LASSERT(alias != dentry);
spin_lock(&alias->d_lock);
@@ -509,8 +488,8 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
if (dentry->d_name.len > ll_i2sbi(parent)->ll_namelen)
return ERR_PTR(-ENAMETOOLONG);
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
- dentry->d_name.len, dentry->d_name.name, parent->i_ino,
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p),intent=%s\n",
+ dentry, parent->i_ino,
parent->i_generation, parent, LL_IT2STR(it));
if (d_mountpoint(dentry))
@@ -563,7 +542,7 @@ static struct dentry *ll_lookup_it(struct inode *parent, struct dentry *dentry,
if ((it->it_op & IT_OPEN) && dentry->d_inode &&
!S_ISREG(dentry->d_inode->i_mode) &&
!S_ISDIR(dentry->d_inode->i_mode)) {
- ll_release_openhandle(dentry, it);
+ ll_release_openhandle(dentry->d_inode, it);
}
ll_lookup_finish_locks(it, dentry);
@@ -586,8 +565,8 @@ static struct dentry *ll_lookup_nd(struct inode *parent, struct dentry *dentry,
struct lookup_intent *itp, it = { .it_op = IT_GETATTR };
struct dentry *de;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),flags=%u\n",
- dentry->d_name.len, dentry->d_name.name, parent->i_ino,
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p),flags=%u\n",
+ dentry, parent->i_ino,
parent->i_generation, parent, flags);
/* Optimize away (CREATE && !OPEN). Let .create handle the race. */
@@ -619,9 +598,9 @@ static int ll_atomic_open(struct inode *dir, struct dentry *dentry,
long long lookup_flags = LOOKUP_OPEN;
int rc = 0;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),file %p,"
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p),file %p,"
"open_flags %x,mode %x opened %d\n",
- dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dentry, dir->i_ino,
dir->i_generation, dir, file, open_flags, mode, *opened);
it = kzalloc(sizeof(*it), GFP_NOFS);
@@ -741,8 +720,8 @@ static int ll_create_it(struct inode *dir, struct dentry *dentry, int mode,
struct inode *inode;
int rc = 0;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),intent=%s\n",
- dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p),intent=%s\n",
+ dentry, dir->i_ino,
dir->i_generation, dir, LL_IT2STR(it));
rc = it_open_error(DISP_OPEN_CREATE, it);
@@ -775,9 +754,9 @@ static void ll_update_times(struct ptlrpc_request *request,
LTIME_S(inode->i_ctime) = body->ctime;
}
-static int ll_new_node(struct inode *dir, struct qstr *name,
+static int ll_new_node(struct inode *dir, struct dentry *dentry,
const char *tgt, int mode, int rdev,
- struct dentry *dchild, __u32 opc)
+ __u32 opc)
{
struct ptlrpc_request *request = NULL;
struct md_op_data *op_data;
@@ -789,8 +768,10 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
if (unlikely(tgt != NULL))
tgt_len = strlen(tgt) + 1;
- op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
- name->len, 0, opc, NULL);
+ op_data = ll_prep_md_op_data(NULL, dir, NULL,
+ dentry->d_name.name,
+ dentry->d_name.len,
+ 0, opc, NULL);
if (IS_ERR(op_data)) {
err = PTR_ERR(op_data);
goto err_exit;
@@ -806,27 +787,25 @@ static int ll_new_node(struct inode *dir, struct qstr *name,
ll_update_times(request, dir);
- if (dchild) {
- err = ll_prep_inode(&inode, request, dchild->d_sb, NULL);
- if (err)
- goto err_exit;
+ err = ll_prep_inode(&inode, request, dir->i_sb, NULL);
+ if (err)
+ goto err_exit;
- d_instantiate(dchild, inode);
- }
+ d_instantiate(dentry, inode);
err_exit:
ptlrpc_req_finished(request);
return err;
}
-static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
- unsigned rdev, struct dentry *dchild)
+static int ll_mknod(struct inode *dir, struct dentry *dchild,
+ umode_t mode, dev_t rdev)
{
int err;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p) mode %o dev %x\n",
- name->len, name->name, dir->i_ino, dir->i_generation, dir,
- mode, rdev);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p) mode %o dev %x\n",
+ dchild, dir->i_ino, dir->i_generation, dir,
+ mode, old_encode_dev(rdev));
if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
mode &= ~current_umask();
@@ -839,7 +818,8 @@ static int ll_mknod_generic(struct inode *dir, struct qstr *name, int mode,
case S_IFBLK:
case S_IFIFO:
case S_IFSOCK:
- err = ll_new_node(dir, name, NULL, mode, rdev, dchild,
+ err = ll_new_node(dir, dchild, NULL, mode,
+ old_encode_dev(rdev),
LUSTRE_OPC_MKNOD);
break;
case S_IFDIR:
@@ -863,134 +843,25 @@ static int ll_create_nd(struct inode *dir, struct dentry *dentry,
{
int rc;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),"
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p),"
"flags=%u, excl=%d\n",
- dentry->d_name.len, dentry->d_name.name, dir->i_ino,
+ dentry, dir->i_ino,
dir->i_generation, dir, mode, want_excl);
- rc = ll_mknod_generic(dir, &dentry->d_name, mode, 0, dentry);
+ rc = ll_mknod(dir, dentry, mode, 0);
ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_CREATE, 1);
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s, unhashed %d\n",
- dentry->d_name.len, dentry->d_name.name, d_unhashed(dentry));
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd, unhashed %d\n",
+ dentry, d_unhashed(dentry));
return rc;
}
-static int ll_symlink_generic(struct inode *dir, struct qstr *name,
- const char *tgt, struct dentry *dchild)
+static inline void ll_get_child_fid(struct dentry *child, struct lu_fid *fid)
{
- int err;
-
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p),target=%.*s\n",
- name->len, name->name, dir->i_ino, dir->i_generation,
- dir, 3000, tgt);
-
- err = ll_new_node(dir, name, (char *)tgt, S_IFLNK | S_IRWXUGO,
- 0, dchild, LUSTRE_OPC_SYMLINK);
-
- if (!err)
- ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_SYMLINK, 1);
-
- return err;
-}
-
-static int ll_link_generic(struct inode *src, struct inode *dir,
- struct qstr *name, struct dentry *dchild)
-{
- struct ll_sb_info *sbi = ll_i2sbi(dir);
- struct ptlrpc_request *request = NULL;
- struct md_op_data *op_data;
- int err;
-
- CDEBUG(D_VFSTRACE,
- "VFS Op: inode=%lu/%u(%p), dir=%lu/%u(%p), target=%.*s\n",
- src->i_ino, src->i_generation, src, dir->i_ino,
- dir->i_generation, dir, name->len, name->name);
-
- op_data = ll_prep_md_op_data(NULL, src, dir, name->name, name->len,
- 0, LUSTRE_OPC_ANY, NULL);
- if (IS_ERR(op_data))
- return PTR_ERR(op_data);
-
- err = md_link(sbi->ll_md_exp, op_data, &request);
- ll_finish_md_op_data(op_data);
- if (err)
- goto out;
-
- ll_update_times(request, dir);
- ll_stats_ops_tally(sbi, LPROC_LL_LINK, 1);
-out:
- ptlrpc_req_finished(request);
- return err;
-}
-
-static int ll_mkdir_generic(struct inode *dir, struct qstr *name,
- int mode, struct dentry *dchild)
-
-{
- int err;
-
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
- name->len, name->name, dir->i_ino, dir->i_generation, dir);
-
- if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
- mode &= ~current_umask();
- mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR;
- err = ll_new_node(dir, name, NULL, mode, 0, dchild, LUSTRE_OPC_MKDIR);
-
- if (!err)
- ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKDIR, 1);
-
- return err;
-}
-
-/* Try to find the child dentry by its name.
- If found, put the result fid into @fid. */
-static void ll_get_child_fid(struct inode * dir, struct qstr *name,
- struct lu_fid *fid)
-{
- struct dentry *parent, *child;
-
- parent = ll_d_hlist_entry(dir->i_dentry, struct dentry, d_alias);
- child = d_lookup(parent, name);
- if (child) {
- if (child->d_inode)
- *fid = *ll_inode2fid(child->d_inode);
- dput(child);
- }
-}
-
-static int ll_rmdir_generic(struct inode *dir, struct dentry *dparent,
- struct dentry *dchild, struct qstr *name)
-{
- struct ptlrpc_request *request = NULL;
- struct md_op_data *op_data;
- int rc;
-
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
- name->len, name->name, dir->i_ino, dir->i_generation, dir);
-
- if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
- return -EBUSY;
-
- op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name, name->len,
- S_IFDIR, LUSTRE_OPC_ANY, NULL);
- if (IS_ERR(op_data))
- return PTR_ERR(op_data);
-
- ll_get_child_fid(dir, name, &op_data->op_fid3);
- op_data->op_fid2 = op_data->op_fid3;
- rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
- ll_finish_md_op_data(op_data);
- if (rc == 0) {
- ll_update_times(request, dir);
- ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_RMDIR, 1);
- }
-
- ptlrpc_req_finished(request);
- return rc;
+ if (child->d_inode)
+ *fid = *ll_inode2fid(child->d_inode);
}
/**
@@ -1099,32 +970,26 @@ out:
return rc;
}
-/* ll_unlink_generic() doesn't update the inode with the new link count.
+/* ll_unlink() doesn't update the inode with the new link count.
* Instead, ll_ddelete() and ll_d_iput() will update it based upon if there
* is any lock existing. They will recycle dentries and inodes based upon locks
* too. b=20433 */
-static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
- struct dentry *dchild, struct qstr *name)
+static int ll_unlink(struct inode * dir, struct dentry *dentry)
{
struct ptlrpc_request *request = NULL;
struct md_op_data *op_data;
int rc;
- CDEBUG(D_VFSTRACE, "VFS Op:name=%.*s,dir=%lu/%u(%p)\n",
- name->len, name->name, dir->i_ino, dir->i_generation, dir);
-
- /*
- * XXX: unlink bind mountpoint maybe call to here,
- * just check it as vfs_unlink does.
- */
- if (unlikely(ll_d_mountpoint(dparent, dchild, name)))
- return -EBUSY;
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p)\n",
+ dentry, dir->i_ino, dir->i_generation, dir);
- op_data = ll_prep_md_op_data(NULL, dir, NULL, name->name,
- name->len, 0, LUSTRE_OPC_ANY, NULL);
+ op_data = ll_prep_md_op_data(NULL, dir, NULL,
+ dentry->d_name.name,
+ dentry->d_name.len,
+ 0, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
return PTR_ERR(op_data);
- ll_get_child_fid(dir, name, &op_data->op_fid3);
+ ll_get_child_fid(dentry, &op_data->op_fid3);
op_data->op_fid2 = op_data->op_fid3;
rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
@@ -1140,95 +1005,140 @@ static int ll_unlink_generic(struct inode *dir, struct dentry *dparent,
return rc;
}
-static int ll_rename_generic(struct inode *src, struct dentry *src_dparent,
- struct dentry *src_dchild, struct qstr *src_name,
- struct inode *tgt, struct dentry *tgt_dparent,
- struct dentry *tgt_dchild, struct qstr *tgt_name)
+static int ll_mkdir(struct inode *dir, struct dentry *dentry, ll_umode_t mode)
{
- struct ptlrpc_request *request = NULL;
- struct ll_sb_info *sbi = ll_i2sbi(src);
- struct md_op_data *op_data;
int err;
- CDEBUG(D_VFSTRACE,
- "VFS Op:oldname=%.*s,src_dir=%lu/%u(%p),newname=%.*s,"
- "tgt_dir=%lu/%u(%p)\n", src_name->len, src_name->name,
- src->i_ino, src->i_generation, src, tgt_name->len,
- tgt_name->name, tgt->i_ino, tgt->i_generation, tgt);
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p)\n",
+ dentry, dir->i_ino, dir->i_generation, dir);
- if (unlikely(ll_d_mountpoint(src_dparent, src_dchild, src_name) ||
- ll_d_mountpoint(tgt_dparent, tgt_dchild, tgt_name)))
- return -EBUSY;
+ if (!IS_POSIXACL(dir) || !exp_connect_umask(ll_i2mdexp(dir)))
+ mode &= ~current_umask();
+ mode = (mode & (S_IRWXUGO|S_ISVTX)) | S_IFDIR;
+ err = ll_new_node(dir, dentry, NULL, mode, 0, LUSTRE_OPC_MKDIR);
- op_data = ll_prep_md_op_data(NULL, src, tgt, NULL, 0, 0,
- LUSTRE_OPC_ANY, NULL);
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_MKDIR, 1);
+
+ return err;
+}
+
+static int ll_rmdir(struct inode *dir, struct dentry *dentry)
+{
+ struct ptlrpc_request *request = NULL;
+ struct md_op_data *op_data;
+ int rc;
+
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p)\n",
+ dentry, dir->i_ino, dir->i_generation, dir);
+
+ op_data = ll_prep_md_op_data(NULL, dir, NULL,
+ dentry->d_name.name,
+ dentry->d_name.len,
+ S_IFDIR, LUSTRE_OPC_ANY, NULL);
if (IS_ERR(op_data))
return PTR_ERR(op_data);
- ll_get_child_fid(src, src_name, &op_data->op_fid3);
- ll_get_child_fid(tgt, tgt_name, &op_data->op_fid4);
- err = md_rename(sbi->ll_md_exp, op_data,
- src_name->name, src_name->len,
- tgt_name->name, tgt_name->len, &request);
+ ll_get_child_fid(dentry, &op_data->op_fid3);
+ op_data->op_fid2 = op_data->op_fid3;
+ rc = md_unlink(ll_i2sbi(dir)->ll_md_exp, op_data, &request);
ll_finish_md_op_data(op_data);
- if (!err) {
- ll_update_times(request, src);
- ll_update_times(request, tgt);
- ll_stats_ops_tally(sbi, LPROC_LL_RENAME, 1);
- err = ll_objects_destroy(request, src);
+ if (rc == 0) {
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_RMDIR, 1);
}
ptlrpc_req_finished(request);
-
- return err;
+ return rc;
}
-static int ll_mknod(struct inode *dir, struct dentry *dchild, ll_umode_t mode,
- dev_t rdev)
+static int ll_symlink(struct inode *dir, struct dentry *dentry,
+ const char *oldname)
{
- return ll_mknod_generic(dir, &dchild->d_name, mode,
- old_encode_dev(rdev), dchild);
-}
+ int err;
-static int ll_unlink(struct inode * dir, struct dentry *dentry)
-{
- return ll_unlink_generic(dir, NULL, dentry, &dentry->d_name);
-}
+ CDEBUG(D_VFSTRACE, "VFS Op:name=%pd,dir=%lu/%u(%p),target=%.*s\n",
+ dentry, dir->i_ino, dir->i_generation,
+ dir, 3000, oldname);
-static int ll_mkdir(struct inode *dir, struct dentry *dentry, ll_umode_t mode)
-{
- return ll_mkdir_generic(dir, &dentry->d_name, mode, dentry);
-}
+ err = ll_new_node(dir, dentry, oldname, S_IFLNK | S_IRWXUGO,
+ 0, LUSTRE_OPC_SYMLINK);
-static int ll_rmdir(struct inode *dir, struct dentry *dentry)
-{
- return ll_rmdir_generic(dir, NULL, dentry, &dentry->d_name);
-}
+ if (!err)
+ ll_stats_ops_tally(ll_i2sbi(dir), LPROC_LL_SYMLINK, 1);
-static int ll_symlink(struct inode *dir, struct dentry *dentry,
- const char *oldname)
-{
- return ll_symlink_generic(dir, &dentry->d_name, oldname, dentry);
+ return err;
}
static int ll_link(struct dentry *old_dentry, struct inode *dir,
struct dentry *new_dentry)
{
- return ll_link_generic(old_dentry->d_inode, dir, &new_dentry->d_name,
- new_dentry);
+ struct inode *src = old_dentry->d_inode;
+ struct ll_sb_info *sbi = ll_i2sbi(dir);
+ struct ptlrpc_request *request = NULL;
+ struct md_op_data *op_data;
+ int err;
+
+ CDEBUG(D_VFSTRACE,
+ "VFS Op: inode=%lu/%u(%p), dir=%lu/%u(%p), target=%pd\n",
+ src->i_ino, src->i_generation, src, dir->i_ino,
+ dir->i_generation, dir, new_dentry);
+
+ op_data = ll_prep_md_op_data(NULL, src, dir, new_dentry->d_name.name,
+ new_dentry->d_name.len,
+ 0, LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ return PTR_ERR(op_data);
+
+ err = md_link(sbi->ll_md_exp, op_data, &request);
+ ll_finish_md_op_data(op_data);
+ if (err)
+ goto out;
+
+ ll_update_times(request, dir);
+ ll_stats_ops_tally(sbi, LPROC_LL_LINK, 1);
+out:
+ ptlrpc_req_finished(request);
+ return err;
}
static int ll_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry)
{
+ struct ptlrpc_request *request = NULL;
+ struct ll_sb_info *sbi = ll_i2sbi(old_dir);
+ struct md_op_data *op_data;
int err;
- err = ll_rename_generic(old_dir, NULL,
- old_dentry, &old_dentry->d_name,
- new_dir, NULL, new_dentry,
- &new_dentry->d_name);
+
+ CDEBUG(D_VFSTRACE,
+ "VFS Op:oldname=%pd,src_dir=%lu/%u(%p),newname=%pd,"
+ "tgt_dir=%lu/%u(%p)\n", old_dentry,
+ old_dir->i_ino, old_dir->i_generation, old_dir, new_dentry,
+ new_dir->i_ino, new_dir->i_generation, new_dir);
+
+ op_data = ll_prep_md_op_data(NULL, old_dir, new_dir, NULL, 0, 0,
+ LUSTRE_OPC_ANY, NULL);
+ if (IS_ERR(op_data))
+ return PTR_ERR(op_data);
+
+ ll_get_child_fid(old_dentry, &op_data->op_fid3);
+ ll_get_child_fid(new_dentry, &op_data->op_fid4);
+ err = md_rename(sbi->ll_md_exp, op_data,
+ old_dentry->d_name.name,
+ old_dentry->d_name.len,
+ new_dentry->d_name.name,
+ new_dentry->d_name.len, &request);
+ ll_finish_md_op_data(op_data);
if (!err) {
- d_move(old_dentry, new_dentry);
+ ll_update_times(request, old_dir);
+ ll_update_times(request, new_dir);
+ ll_stats_ops_tally(sbi, LPROC_LL_RENAME, 1);
+ err = ll_objects_destroy(request, old_dir);
}
+
+ ptlrpc_req_finished(request);
+ if (!err)
+ d_move(old_dentry, new_dentry);
return err;
}
diff --git a/drivers/staging/lustre/lustre/llite/statahead.c b/drivers/staging/lustre/lustre/llite/statahead.c
index 06b71bc..09d965e 100644
--- a/drivers/staging/lustre/lustre/llite/statahead.c
+++ b/drivers/staging/lustre/lustre/llite/statahead.c
@@ -969,8 +969,8 @@ static int ll_agl_thread(void *arg)
struct l_wait_info lwi = { 0 };
thread->t_pid = current_pid();
- CDEBUG(D_READA, "agl thread started: sai %p, parent %.*s\n",
- sai, parent->d_name.len, parent->d_name.name);
+ CDEBUG(D_READA, "agl thread started: sai %p, parent %pd\n",
+ sai, parent);
atomic_inc(&sbi->ll_agl_total);
spin_lock(&plli->lli_agl_lock);
@@ -1019,8 +1019,8 @@ static int ll_agl_thread(void *arg)
spin_unlock(&plli->lli_agl_lock);
wake_up(&thread->t_ctl_waitq);
ll_sai_put(sai);
- CDEBUG(D_READA, "agl thread stopped: sai %p, parent %.*s\n",
- sai, parent->d_name.len, parent->d_name.name);
+ CDEBUG(D_READA, "agl thread stopped: sai %p, parent %pd\n",
+ sai, parent);
return 0;
}
@@ -1031,8 +1031,8 @@ static void ll_start_agl(struct dentry *parent, struct ll_statahead_info *sai)
struct ll_inode_info *plli;
struct task_struct *task;
- CDEBUG(D_READA, "start agl thread: sai %p, parent %.*s\n",
- sai, parent->d_name.len, parent->d_name.name);
+ CDEBUG(D_READA, "start agl thread: sai %p, parent %pd\n",
+ sai, parent);
plli = ll_i2info(parent->d_inode);
task = kthread_run(ll_agl_thread, parent,
@@ -1066,8 +1066,8 @@ static int ll_statahead_thread(void *arg)
struct l_wait_info lwi = { 0 };
thread->t_pid = current_pid();
- CDEBUG(D_READA, "statahead thread starting: sai %p, parent %.*s\n",
- sai, parent->d_name.len, parent->d_name.name);
+ CDEBUG(D_READA, "statahead thread starting: sai %p, parent %pd\n",
+ sai, parent);
if (sbi->ll_flags & LL_SBI_AGL_ENABLED)
ll_start_agl(parent, sai);
@@ -1288,8 +1288,8 @@ out:
wake_up(&thread->t_ctl_waitq);
ll_sai_put(sai);
dput(parent);
- CDEBUG(D_READA, "statahead thread stopped: sai %p, parent %.*s\n",
- sai, parent->d_name.len, parent->d_name.name);
+ CDEBUG(D_READA, "statahead thread stopped: sai %p, parent %pd\n",
+ sai, parent);
return rc;
}
@@ -1612,10 +1612,9 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
} else if ((*dentryp)->d_inode != inode) {
/* revalidate, but inode is recreated */
CDEBUG(D_READA,
- "stale dentry %.*s inode %lu/%u, "
+ "stale dentry %pd inode %lu/%u, "
"statahead inode %lu/%u\n",
- (*dentryp)->d_name.len,
- (*dentryp)->d_name.name,
+ *dentryp,
(*dentryp)->d_inode->i_ino,
(*dentryp)->d_inode->i_generation,
inode->i_ino,
@@ -1666,9 +1665,9 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
if (unlikely(sai->sai_inode != parent->d_inode)) {
struct ll_inode_info *nlli = ll_i2info(parent->d_inode);
- CWARN("Race condition, someone changed %.*s just now: "
+ CWARN("Race condition, someone changed %pd just now: "
"old parent "DFID", new parent "DFID"\n",
- (*dentryp)->d_name.len, (*dentryp)->d_name.name,
+ *dentryp,
PFID(&lli->lli_fid), PFID(&nlli->lli_fid));
dput(parent);
iput(sai->sai_inode);
@@ -1676,8 +1675,8 @@ int do_statahead_enter(struct inode *dir, struct dentry **dentryp,
goto out;
}
- CDEBUG(D_READA, "start statahead thread: sai %p, parent %.*s\n",
- sai, parent->d_name.len, parent->d_name.name);
+ CDEBUG(D_READA, "start statahead thread: sai %p, parent %pd\n",
+ sai, parent);
/* The sai buffer already has one reference taken at allocation time,
* but as soon as we expose the sai by attaching it to the lli that
diff --git a/drivers/staging/lustre/lustre/llite/vvp_io.c b/drivers/staging/lustre/lustre/llite/vvp_io.c
index d3f967a..e540a6d 100644
--- a/drivers/staging/lustre/lustre/llite/vvp_io.c
+++ b/drivers/staging/lustre/lustre/llite/vvp_io.c
@@ -108,7 +108,7 @@ static int vvp_io_fault_iter_init(const struct lu_env *env,
struct inode *inode = ccc_object_inode(ios->cis_obj);
LASSERT(inode ==
- cl2ccc_io(env, ios)->cui_fd->fd_file->f_dentry->d_inode);
+ file_inode(cl2ccc_io(env, ios)->cui_fd->fd_file));
vio->u.fault.ft_mtime = LTIME_S(inode->i_mtime);
return 0;
}
@@ -239,7 +239,7 @@ static int vvp_mmap_locks(const struct lu_env *env,
down_read(&mm->mmap_sem);
while ((vma = our_vma(mm, addr, count)) != NULL) {
- struct inode *inode = vma->vm_file->f_dentry->d_inode;
+ struct inode *inode = file_inode(vma->vm_file);
int flags = CEF_MUST;
if (ll_file_nolock(vma->vm_file)) {
diff --git a/drivers/staging/lustre/lustre/llite/xattr.c b/drivers/staging/lustre/lustre/llite/xattr.c
index 252a619..3151baf 100644
--- a/drivers/staging/lustre/lustre/llite/xattr.c
+++ b/drivers/staging/lustre/lustre/llite/xattr.c
@@ -241,14 +241,11 @@ int ll_setxattr(struct dentry *dentry, const char *name,
lump->lmm_stripe_offset = -1;
if (lump != NULL && S_ISREG(inode->i_mode)) {
- struct file f;
int flags = FMODE_WRITE;
int lum_size = (lump->lmm_magic == LOV_USER_MAGIC_V1) ?
sizeof(*lump) : sizeof(struct lov_user_md_v3);
- memset(&f, 0, sizeof(f)); /* f.f_flags is used below */
- f.f_dentry = dentry;
- rc = ll_lov_setstripe_ea_info(inode, &f, flags, lump,
+ rc = ll_lov_setstripe_ea_info(inode, dentry, flags, lump,
lum_size);
/* b10667: rc always be 0 here for now */
rc = 0;
@@ -519,8 +516,8 @@ ssize_t ll_getxattr(struct dentry *dentry, const char *name,
}
if (size < lmmsize) {
- CERROR("server bug: replied size %d > %d for %s (%s)\n",
- lmmsize, (int)size, dentry->d_name.name, name);
+ CERROR("server bug: replied size %d > %d for %pd (%s)\n",
+ lmmsize, (int)size, dentry, name);
rc = -ERANGE;
goto out;
}
diff --git a/drivers/staging/media/Kconfig b/drivers/staging/media/Kconfig
index 655cf50..96498b7 100644
--- a/drivers/staging/media/Kconfig
+++ b/drivers/staging/media/Kconfig
@@ -27,7 +27,9 @@ source "drivers/staging/media/davinci_vpfe/Kconfig"
source "drivers/staging/media/dt3155v4l/Kconfig"
-source "drivers/staging/media/omap24xx/Kconfig"
+source "drivers/staging/media/mn88472/Kconfig"
+
+source "drivers/staging/media/mn88473/Kconfig"
source "drivers/staging/media/omap4iss/Kconfig"
diff --git a/drivers/staging/media/Makefile b/drivers/staging/media/Makefile
index 6dbe578..30fb352 100644
--- a/drivers/staging/media/Makefile
+++ b/drivers/staging/media/Makefile
@@ -4,6 +4,6 @@ obj-$(CONFIG_LIRC_STAGING) += lirc/
obj-$(CONFIG_VIDEO_DT3155) += dt3155v4l/
obj-$(CONFIG_VIDEO_DM365_VPFE) += davinci_vpfe/
obj-$(CONFIG_VIDEO_OMAP4) += omap4iss/
-obj-$(CONFIG_VIDEO_OMAP2) += omap24xx/
-obj-$(CONFIG_VIDEO_TCM825X) += omap24xx/
+obj-$(CONFIG_DVB_MN88472) += mn88472/
+obj-$(CONFIG_DVB_MN88473) += mn88473/
diff --git a/drivers/staging/media/bcm2048/radio-bcm2048.c b/drivers/staging/media/bcm2048/radio-bcm2048.c
index 2bba370..60a57b2 100644
--- a/drivers/staging/media/bcm2048/radio-bcm2048.c
+++ b/drivers/staging/media/bcm2048/radio-bcm2048.c
@@ -2327,9 +2327,10 @@ static int bcm2048_vidioc_querycap(struct file *file, void *priv,
strlcpy(capability->card, BCM2048_DRIVER_CARD,
sizeof(capability->card));
snprintf(capability->bus_info, 32, "I2C: 0x%X", bdev->client->addr);
- capability->version = BCM2048_DRIVER_VERSION;
- capability->capabilities = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
+ capability->device_caps = V4L2_CAP_TUNER | V4L2_CAP_RADIO |
V4L2_CAP_HW_FREQ_SEEK;
+ capability->capabilities = capability->device_caps |
+ V4L2_CAP_DEVICE_CAPS;
return 0;
}
@@ -2707,7 +2708,7 @@ static int __exit bcm2048_i2c_driver_remove(struct i2c_client *client)
* bcm2048_i2c_driver - i2c driver interface
*/
static const struct i2c_device_id bcm2048_id[] = {
- { "bcm2048" , 0 },
+ { "bcm2048", 0 },
{ },
};
MODULE_DEVICE_TABLE(i2c, bcm2048_id);
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
index bdc7f00..704fa20 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe.c
@@ -37,15 +37,15 @@
/* ipipe input format's */
static const unsigned int ipipe_input_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_SGRBG12_1X12,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
};
/* ipipe output format's */
static const unsigned int ipipe_output_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
};
static int ipipe_validate_lutdpc_params(struct vpfe_ipipe_lutdpc *lutdpc)
@@ -1457,7 +1457,7 @@ ipipe_try_format(struct vpfe_ipipe_device *ipipe,
/* If not found, use SBGGR10 as default */
if (i >= ARRAY_SIZE(ipipe_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12;
} else if (pad == IPIPE_PAD_SOURCE) {
for (i = 0; i < ARRAY_SIZE(ipipe_output_fmts); i++)
if (fmt->code == ipipe_output_fmts[i])
@@ -1465,7 +1465,7 @@ ipipe_try_format(struct vpfe_ipipe_device *ipipe,
/* If not found, use UYVY as default */
if (i >= ARRAY_SIZE(ipipe_output_fmts))
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
}
fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
@@ -1642,7 +1642,7 @@ ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = IPIPE_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
ipipe_set_format(sd, fh, &format);
@@ -1650,7 +1650,7 @@ ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = IPIPE_PAD_SOURCE;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
ipipe_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
index b2daf5e..6461de1 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipe_hw.c
@@ -196,12 +196,12 @@ ipipe_setup_resizer(void *__iomem rsz_base, struct resizer_params *params)
rsz_set_rsz_regs(rsz_base, RSZ_B, params);
}
-static u32 ipipe_get_color_pat(enum v4l2_mbus_pixelcode pix)
+static u32 ipipe_get_color_pat(u32 pix)
{
switch (pix) {
- case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
return ipipe_sgrbg_pattern;
default:
@@ -211,23 +211,23 @@ static u32 ipipe_get_color_pat(enum v4l2_mbus_pixelcode pix)
static int ipipe_get_data_path(struct vpfe_ipipe_device *ipipe)
{
- enum v4l2_mbus_pixelcode temp_pix_fmt;
+ u32 temp_pix_fmt;
switch (ipipe->formats[IPIPE_PAD_SINK].code) {
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGRBG12_1X12:
- temp_pix_fmt = V4L2_MBUS_FMT_SGRBG12_1X12;
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
+ temp_pix_fmt = MEDIA_BUS_FMT_SGRBG12_1X12;
break;
default:
- temp_pix_fmt = V4L2_MBUS_FMT_UYVY8_2X8;
+ temp_pix_fmt = MEDIA_BUS_FMT_UYVY8_2X8;
}
- if (temp_pix_fmt == V4L2_MBUS_FMT_SGRBG12_1X12) {
+ if (temp_pix_fmt == MEDIA_BUS_FMT_SGRBG12_1X12) {
if (ipipe->formats[IPIPE_PAD_SOURCE].code ==
- V4L2_MBUS_FMT_SGRBG12_1X12)
+ MEDIA_BUS_FMT_SGRBG12_1X12)
return IPIPE_RAW2RAW;
return IPIPE_RAW2YUV;
}
diff --git a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
index 6d4893b..a86f16f 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_ipipeif.c
@@ -23,42 +23,42 @@
#include "vpfe_mc_capture.h"
static const unsigned int ipipeif_input_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_SGRBG12_1X12,
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_UV8_1X8,
- V4L2_MBUS_FMT_YDYUYDYV8_1X16,
- V4L2_MBUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_UV8_1X8,
+ MEDIA_BUS_FMT_YDYUYDYV8_1X16,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
};
static const unsigned int ipipeif_output_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_SGRBG12_1X12,
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_UV8_1X8,
- V4L2_MBUS_FMT_YDYUYDYV8_1X16,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_UV8_1X8,
+ MEDIA_BUS_FMT_YDYUYDYV8_1X16,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
};
static int
-ipipeif_get_pack_mode(enum v4l2_mbus_pixelcode in_pix_fmt)
+ipipeif_get_pack_mode(u32 in_pix_fmt)
{
switch (in_pix_fmt) {
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_UV8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_UV8_1X8:
return IPIPEIF_5_1_PACK_8_BIT;
- case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
return IPIPEIF_5_1_PACK_8_BIT_A_LAW;
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
return IPIPEIF_5_1_PACK_16_BIT;
- case V4L2_MBUS_FMT_SBGGR12_1X12:
+ case MEDIA_BUS_FMT_SBGGR12_1X12:
return IPIPEIF_5_1_PACK_12_BIT;
default:
@@ -107,8 +107,8 @@ ipipeif_get_cfg_src1(struct vpfe_ipipeif_device *ipipeif)
informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
if (ipipeif->input == IPIPEIF_INPUT_MEMORY &&
- (informat->code == V4L2_MBUS_FMT_Y8_1X8 ||
- informat->code == V4L2_MBUS_FMT_UV8_1X8))
+ (informat->code == MEDIA_BUS_FMT_Y8_1X8 ||
+ informat->code == MEDIA_BUS_FMT_UV8_1X8))
return IPIPEIF_CCDC;
return IPIPEIF_SRC1_PARALLEL_PORT;
@@ -122,11 +122,11 @@ ipipeif_get_data_shift(struct vpfe_ipipeif_device *ipipeif)
informat = &ipipeif->formats[IPIPEIF_PAD_SINK];
switch (informat->code) {
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
return IPIPEIF_5_1_BITS11_0;
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_UV8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_UV8_1X8:
return IPIPEIF_5_1_BITS11_0;
default:
@@ -143,7 +143,7 @@ ipipeif_get_source(struct vpfe_ipipeif_device *ipipeif)
if (ipipeif->input == IPIPEIF_INPUT_ISIF)
return IPIPEIF_CCDC;
- if (informat->code == V4L2_MBUS_FMT_UYVY8_2X8)
+ if (informat->code == MEDIA_BUS_FMT_UYVY8_2X8)
return IPIPEIF_SDRAM_YUV;
return IPIPEIF_SDRAM_RAW;
@@ -190,7 +190,7 @@ static int ipipeif_hw_setup(struct v4l2_subdev *sd)
struct v4l2_mbus_framefmt *informat, *outformat;
struct ipipeif_params params = ipipeif->config;
enum ipipeif_input_source ipipeif_source;
- enum v4l2_mbus_pixelcode isif_port_if;
+ u32 isif_port_if;
void *ipipeif_base_addr;
unsigned int val;
int data_shift;
@@ -268,16 +268,16 @@ static int ipipeif_hw_setup(struct v4l2_subdev *sd)
ipipeif_write(val, ipipeif_base_addr, IPIPEIF_INIRSZ);
isif_port_if = informat->code;
- if (isif_port_if == V4L2_MBUS_FMT_Y8_1X8)
- isif_port_if = V4L2_MBUS_FMT_YUYV8_1X16;
- else if (isif_port_if == V4L2_MBUS_FMT_UV8_1X8)
- isif_port_if = V4L2_MBUS_FMT_SGRBG12_1X12;
+ if (isif_port_if == MEDIA_BUS_FMT_Y8_1X8)
+ isif_port_if = MEDIA_BUS_FMT_YUYV8_1X16;
+ else if (isif_port_if == MEDIA_BUS_FMT_UV8_1X8)
+ isif_port_if = MEDIA_BUS_FMT_SGRBG12_1X12;
/* Enable DPCM decompression */
switch (ipipeif_source) {
case IPIPEIF_SDRAM_RAW:
val = 0;
- if (outformat->code == V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8) {
+ if (outformat->code == MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8) {
val = 1;
val |= (IPIPEIF_DPCM_8BIT_10BIT & 1) <<
IPIPEIF_DPCM_BITS_SHIFT;
@@ -296,9 +296,9 @@ static int ipipeif_hw_setup(struct v4l2_subdev *sd)
/* configure CFG2 */
val = ipipeif_read(ipipeif_base_addr, IPIPEIF_CFG2);
switch (isif_port_if) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
ipipeif_write(val, ipipeif_base_addr, IPIPEIF_CFG2);
@@ -344,16 +344,16 @@ static int ipipeif_hw_setup(struct v4l2_subdev *sd)
val |= VPFE_PINPOL_POSITIVE << IPIPEIF_CFG2_VDPOL_SHIFT;
switch (isif_port_if) {
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
RESETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
SETBIT(val, IPIPEIF_CFG2_YUV8_SHIFT);
SETBIT(val, IPIPEIF_CFG2_YUV16_SHIFT);
val |= IPIPEIF_CBCR_Y << IPIPEIF_CFG2_YUV8P_SHIFT;
@@ -625,7 +625,7 @@ ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
/* If not found, use SBGGR10 as default */
if (i >= ARRAY_SIZE(ipipeif_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ fmt->code = MEDIA_BUS_FMT_SGRBG12_1X12;
} else if (pad == IPIPEIF_PAD_SOURCE) {
for (i = 0; i < ARRAY_SIZE(ipipeif_output_fmts); i++)
if (fmt->code == ipipeif_output_fmts[i])
@@ -633,7 +633,7 @@ ipipeif_try_format(struct vpfe_ipipeif_device *ipipeif,
/* If not found, use UYVY as default */
if (i >= ARRAY_SIZE(ipipeif_output_fmts))
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
}
fmt->width = clamp_t(u32, fmt->width, MIN_OUT_HEIGHT, max_out_width);
@@ -770,7 +770,7 @@ ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = IPIPEIF_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
ipipeif_set_format(sd, fh, &format);
@@ -778,7 +778,7 @@ ipipeif_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = IPIPEIF_PAD_SOURCE;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
ipipeif_set_format(sd, fh, &format);
@@ -805,9 +805,9 @@ ipipeif_video_in_queue(struct vpfe_device *vpfe_dev, unsigned long addr)
return -EINVAL;
switch (ipipeif->formats[IPIPEIF_PAD_SINK].code) {
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_UV8_1X8:
- case V4L2_MBUS_FMT_YDYUYDYV8_1X16:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_UV8_1X8:
+ case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
adofs = ipipeif->formats[IPIPEIF_PAD_SINK].width;
break;
diff --git a/drivers/staging/media/davinci_vpfe/dm365_isif.c b/drivers/staging/media/davinci_vpfe/dm365_isif.c
index 0d535b0..fa26f63 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_isif.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_isif.c
@@ -27,13 +27,13 @@
#define MAX_HEIGHT 4096
static const unsigned int isif_fmts[] = {
- V4L2_MBUS_FMT_YUYV8_2X8,
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_YUYV8_1X16,
- V4L2_MBUS_FMT_YUYV10_1X20,
- V4L2_MBUS_FMT_SGRBG12_1X12,
- V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_YUYV8_2X8,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YUYV10_1X20,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
};
#define ISIF_COLPTN_R_Ye 0x0
@@ -154,7 +154,7 @@ enum v4l2_field vpfe_isif_get_fid(struct vpfe_device *vpfe_dev)
static int
isif_set_pixel_format(struct vpfe_isif_device *isif, unsigned int pixfmt)
{
- if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12) {
+ if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
if (pixfmt == V4L2_PIX_FMT_SBGGR16)
isif->isif_cfg.data_pack = ISIF_PACK_16BIT;
else if ((pixfmt == V4L2_PIX_FMT_SGRBG10DPCM8) ||
@@ -184,7 +184,7 @@ static int
isif_set_frame_format(struct vpfe_isif_device *isif,
enum isif_frmfmt frm_fmt)
{
- if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
isif->isif_cfg.bayer.frm_fmt = frm_fmt;
else
isif->isif_cfg.ycbcr.frm_fmt = frm_fmt;
@@ -196,7 +196,7 @@ static int isif_set_image_window(struct vpfe_isif_device *isif)
{
struct v4l2_rect *win = &isif->crop;
- if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12) {
+ if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12) {
isif->isif_cfg.bayer.win.top = win->top;
isif->isif_cfg.bayer.win.left = win->left;
isif->isif_cfg.bayer.win.width = win->width;
@@ -214,7 +214,7 @@ static int isif_set_image_window(struct vpfe_isif_device *isif)
static int
isif_set_buftype(struct vpfe_isif_device *isif, enum isif_buftype buf_type)
{
- if (isif->formats[ISIF_PAD_SINK].code == V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (isif->formats[ISIF_PAD_SINK].code == MEDIA_BUS_FMT_SGRBG12_1X12)
isif->isif_cfg.bayer.buf_type = buf_type;
else
isif->isif_cfg.ycbcr.buf_type = buf_type;
@@ -296,7 +296,7 @@ isif_try_format(struct vpfe_isif_device *isif, struct v4l2_subdev_fh *fh,
/* If not found, use YUYV8_2x8 as default */
if (i >= ARRAY_SIZE(isif_fmts))
- fmt->format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ fmt->format.code = MEDIA_BUS_FMT_YUYV8_2X8;
/* Clamp the size. */
fmt->format.width = clamp_t(u32, width, 32, MAX_WIDTH);
@@ -429,7 +429,7 @@ static int isif_get_params(struct v4l2_subdev *sd, void *params)
struct vpfe_isif_device *isif = v4l2_get_subdevdata(sd);
/* only raw module parameters can be set through the IOCTL */
- if (isif->formats[ISIF_PAD_SINK].code != V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
return -EINVAL;
memcpy(params, &isif->isif_cfg.bayer.config_params,
sizeof(isif->isif_cfg.bayer.config_params));
@@ -604,7 +604,7 @@ static int isif_set_params(struct v4l2_subdev *sd, void *params)
int ret = -EINVAL;
/* only raw module parameters can be set through the IOCTL */
- if (isif->formats[ISIF_PAD_SINK].code != V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (isif->formats[ISIF_PAD_SINK].code != MEDIA_BUS_FMT_SGRBG12_1X12)
return ret;
memcpy(&isif_raw_params, params, sizeof(isif_raw_params));
@@ -1041,19 +1041,19 @@ isif_config_culling(struct vpfe_isif_device *isif, struct vpfe_isif_cul *cul)
static int isif_get_pix_fmt(u32 mbus_code)
{
switch (mbus_code) {
- case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
return ISIF_PIXFMT_RAW;
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_YUYV10_2X10:
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_Y8_1X8:
return ISIF_PIXFMT_YCBCR_8BIT;
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
return ISIF_PIXFMT_YCBCR_16BIT;
default:
@@ -1121,11 +1121,11 @@ static int isif_config_raw(struct v4l2_subdev *sd, int mode)
ISIF_FRM_FMT_MASK) << ISIF_FRM_FMT_SHIFT) | ((pix_fmt &
ISIF_INPUT_MASK) << ISIF_INPUT_SHIFT);
- /* currently only V4L2_MBUS_FMT_SGRBG12_1X12 is
+ /* currently only MEDIA_BUS_FMT_SGRBG12_1X12 is
* supported. shift appropriately depending on
* different MBUS fmt's added
*/
- if (format->code == V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
val |= ((VPFE_ISIF_NO_SHIFT &
ISIF_DATASFT_MASK) << ISIF_DATASFT_SHIFT);
@@ -1154,7 +1154,7 @@ static int isif_config_raw(struct v4l2_subdev *sd, int mode)
/* Configure Gain & Offset */
isif_config_gain_offset(isif);
/* Configure Color pattern */
- if (format->code == V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (format->code == MEDIA_BUS_FMT_SGRBG12_1X12)
val = isif_sgrbg_pattern;
else
/* default set to rggb */
@@ -1254,8 +1254,8 @@ static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
(((params->vd_pol & ISIF_VD_POL_MASK) << ISIF_VD_POL_SHIFT));
/* pack the data to 8-bit CCDCCFG */
switch (format->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
pr_debug("Invalid pix_fmt(input mode)\n");
return -EINVAL;
@@ -1266,7 +1266,7 @@ static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
ccdcfg = ccdcfg | ISIF_PACK_8BIT | ISIF_YCINSWP_YCBCR;
break;
- case V4L2_MBUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
pr_debug("Invalid pix_fmt(input mode)\n");
return -EINVAL;
@@ -1278,7 +1278,7 @@ static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
ISIF_BW656_ENABLE;
break;
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
pr_debug("Invalid pix_fmt(input mode)\n");
return -EINVAL;
@@ -1286,7 +1286,7 @@ static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
isif_write(isif->isif_cfg.base_addr, 3, REC656IF);
break;
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
ccdcfg |= ISIF_PACK_8BIT;
ccdcfg |= ISIF_YCINSWP_YCBCR;
if (pix_fmt != ISIF_PIXFMT_YCBCR_8BIT) {
@@ -1295,7 +1295,7 @@ static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
}
break;
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
if (pix_fmt != ISIF_PIXFMT_YCBCR_16BIT) {
pr_debug("Invalid pix_fmt(input mode)\n");
return -EINVAL;
@@ -1313,8 +1313,8 @@ static int isif_config_ycbcr(struct v4l2_subdev *sd, int mode)
ISIF_PIX_ORDER_SHIFT;
isif_write(isif->isif_cfg.base_addr, ccdcfg, CCDCFG);
/* configure video window */
- if (format->code == V4L2_MBUS_FMT_YUYV10_1X20 ||
- format->code == V4L2_MBUS_FMT_YUYV8_1X16)
+ if (format->code == MEDIA_BUS_FMT_YUYV10_1X20 ||
+ format->code == MEDIA_BUS_FMT_YUYV8_1X16)
isif_setwin(isif, &params->win, params->frm_fmt, 1, mode);
else
isif_setwin(isif, &params->win, params->frm_fmt, 2, mode);
@@ -1345,17 +1345,17 @@ static int isif_configure(struct v4l2_subdev *sd, int mode)
format = &isif->formats[ISIF_PAD_SINK];
switch (format->code) {
- case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
return isif_config_raw(sd, mode);
- case V4L2_MBUS_FMT_YUYV8_2X8:
- case V4L2_MBUS_FMT_UYVY8_2X8:
- case V4L2_MBUS_FMT_YUYV10_2X10:
- case V4L2_MBUS_FMT_Y8_1X8:
- case V4L2_MBUS_FMT_YUYV8_1X16:
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_YUYV10_2X10:
+ case MEDIA_BUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
return isif_config_ycbcr(sd, mode);
default:
@@ -1630,7 +1630,7 @@ isif_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = ISIF_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
format.format.width = MAX_WIDTH;
format.format.height = MAX_HEIGHT;
isif_set_format(sd, fh, &format);
@@ -1638,7 +1638,7 @@ isif_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = ISIF_PAD_SOURCE;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG12_1X12;
+ format.format.code = MEDIA_BUS_FMT_SGRBG12_1X12;
format.format.width = MAX_WIDTH;
format.format.height = MAX_HEIGHT;
isif_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/davinci_vpfe/dm365_resizer.c b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
index 8828d6c..e0b29c8 100644
--- a/drivers/staging/media/davinci_vpfe/dm365_resizer.c
+++ b/drivers/staging/media/davinci_vpfe/dm365_resizer.c
@@ -35,18 +35,18 @@
#define MIN_OUT_HEIGHT 2
static const unsigned int resizer_input_formats[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_UV8_1X8,
- V4L2_MBUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_UV8_1X8,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
};
static const unsigned int resizer_output_formats[] = {
- V4L2_MBUS_FMT_UYVY8_2X8,
- V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_UV8_1X8,
- V4L2_MBUS_FMT_YDYUYDYV8_1X16,
- V4L2_MBUS_FMT_SGRBG12_1X12,
+ MEDIA_BUS_FMT_UYVY8_2X8,
+ MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_UV8_1X8,
+ MEDIA_BUS_FMT_YDYUYDYV8_1X16,
+ MEDIA_BUS_FMT_SGRBG12_1X12,
};
/* resizer_calculate_line_length() - This function calculates the line length of
@@ -54,17 +54,17 @@ static const unsigned int resizer_output_formats[] = {
* output.
*/
static void
-resizer_calculate_line_length(enum v4l2_mbus_pixelcode pix, int width,
- int height, int *line_len, int *line_len_c)
+resizer_calculate_line_length(u32 pix, int width, int height,
+ int *line_len, int *line_len_c)
{
*line_len = 0;
*line_len_c = 0;
- if (pix == V4L2_MBUS_FMT_UYVY8_2X8 ||
- pix == V4L2_MBUS_FMT_SGRBG12_1X12) {
+ if (pix == MEDIA_BUS_FMT_UYVY8_2X8 ||
+ pix == MEDIA_BUS_FMT_SGRBG12_1X12) {
*line_len = width << 1;
- } else if (pix == V4L2_MBUS_FMT_Y8_1X8 ||
- pix == V4L2_MBUS_FMT_UV8_1X8) {
+ } else if (pix == MEDIA_BUS_FMT_Y8_1X8 ||
+ pix == MEDIA_BUS_FMT_UV8_1X8) {
*line_len = width;
*line_len_c = width;
} else {
@@ -85,11 +85,11 @@ resizer_validate_output_image_format(struct device *dev,
struct v4l2_mbus_framefmt *format,
int *in_line_len, int *in_line_len_c)
{
- if (format->code != V4L2_MBUS_FMT_UYVY8_2X8 &&
- format->code != V4L2_MBUS_FMT_Y8_1X8 &&
- format->code != V4L2_MBUS_FMT_UV8_1X8 &&
- format->code != V4L2_MBUS_FMT_YDYUYDYV8_1X16 &&
- format->code != V4L2_MBUS_FMT_SGRBG12_1X12) {
+ if (format->code != MEDIA_BUS_FMT_UYVY8_2X8 &&
+ format->code != MEDIA_BUS_FMT_Y8_1X8 &&
+ format->code != MEDIA_BUS_FMT_UV8_1X8 &&
+ format->code != MEDIA_BUS_FMT_YDYUYDYV8_1X16 &&
+ format->code != MEDIA_BUS_FMT_SGRBG12_1X12) {
dev_err(dev, "Invalid Mbus format, %d\n", format->code);
return -EINVAL;
}
@@ -281,7 +281,7 @@ resizer_calculate_sdram_offsets(struct vpfe_resizer_device *resizer, int index)
param->ext_mem_param[index].c_offset = 0;
param->ext_mem_param[index].flip_ofst_y = 0;
param->ext_mem_param[index].flip_ofst_c = 0;
- if (outformat->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16) {
+ if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16) {
/* YUV 420 */
yuv_420 = 1;
bytesperpixel = 1;
@@ -322,7 +322,7 @@ static int resizer_configure_output_win(struct vpfe_resizer_device *resizer)
outformat = &resizer->resizer_a.formats[RESIZER_PAD_SOURCE];
output_specs.vst_y = param->user_config.vst;
- if (outformat->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+ if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
output_specs.vst_c = param->user_config.vst;
configure_resizer_out_params(resizer, RSZ_A, &output_specs, 0, 0);
@@ -336,7 +336,7 @@ static int resizer_configure_output_win(struct vpfe_resizer_device *resizer)
if (param->rsz_en[RSZ_B])
resizer_calculate_resize_ratios(resizer, RSZ_B);
- if (outformat->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+ if (outformat->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
resizer_enable_422_420_conversion(param, RSZ_A, ENABLE);
else
resizer_enable_422_420_conversion(param, RSZ_A, DISABLE);
@@ -447,26 +447,26 @@ resizer_configure_common_in_params(struct vpfe_resizer_device *resizer)
param->rsz_common.source = IPIPE_DATA;
switch (informat->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
param->rsz_common.src_img_fmt = RSZ_IMG_422;
param->rsz_common.raw_flip = 0;
break;
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
param->rsz_common.src_img_fmt = RSZ_IMG_420;
/* Select y */
param->rsz_common.y_c = 0;
param->rsz_common.raw_flip = 0;
break;
- case V4L2_MBUS_FMT_UV8_1X8:
+ case MEDIA_BUS_FMT_UV8_1X8:
param->rsz_common.src_img_fmt = RSZ_IMG_420;
/* Select y */
param->rsz_common.y_c = 1;
param->rsz_common.raw_flip = 0;
break;
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
param->rsz_common.raw_flip = 1;
break;
@@ -519,7 +519,7 @@ resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer)
param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
configure_resizer_out_params(resizer, RSZ_B,
&cont_config->output2, 0, 1);
- if (outformat2->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+ if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
resizer_enable_422_420_conversion(param,
RSZ_B, ENABLE);
else
@@ -540,15 +540,15 @@ resizer_configure_in_continious_mode(struct vpfe_resizer_device *resizer)
static inline int
resizer_validate_input_image_format(struct device *dev,
- enum v4l2_mbus_pixelcode pix,
+ u32 pix,
int width, int height, int *line_len)
{
int val;
- if (pix != V4L2_MBUS_FMT_UYVY8_2X8 &&
- pix != V4L2_MBUS_FMT_Y8_1X8 &&
- pix != V4L2_MBUS_FMT_UV8_1X8 &&
- pix != V4L2_MBUS_FMT_SGRBG12_1X12) {
+ if (pix != MEDIA_BUS_FMT_UYVY8_2X8 &&
+ pix != MEDIA_BUS_FMT_Y8_1X8 &&
+ pix != MEDIA_BUS_FMT_UV8_1X8 &&
+ pix != MEDIA_BUS_FMT_SGRBG12_1X12) {
dev_err(dev,
"resizer validate output: pix format not supported, %d\n", pix);
return -EINVAL;
@@ -560,7 +560,7 @@ resizer_validate_input_image_format(struct device *dev,
return -EINVAL;
}
- if (pix == V4L2_MBUS_FMT_UV8_1X8)
+ if (pix == MEDIA_BUS_FMT_UV8_1X8)
resizer_calculate_line_length(pix, width,
height, &val, line_len);
else
@@ -709,12 +709,12 @@ resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
configure_resizer_out_params(resizer, RSZ_A,
&param->user_config.output1, 0, 1);
- if (outformat1->code == V4L2_MBUS_FMT_SGRBG12_1X12)
+ if (outformat1->code == MEDIA_BUS_FMT_SGRBG12_1X12)
param->rsz_common.raw_flip = 1;
else
param->rsz_common.raw_flip = 0;
- if (outformat1->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+ if (outformat1->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
resizer_enable_422_420_conversion(param,
RSZ_A, ENABLE);
else
@@ -732,7 +732,7 @@ resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
param->ext_mem_param[RSZ_B].rsz_sdr_oft_c = line_len_c;
configure_resizer_out_params(resizer, RSZ_B,
&param->user_config.output2, 0, 1);
- if (outformat2->code == V4L2_MBUS_FMT_YDYUYDYV8_1X16)
+ if (outformat2->code == MEDIA_BUS_FMT_YDYUYDYV8_1X16)
resizer_enable_422_420_conversion(param,
RSZ_B, ENABLE);
else
@@ -745,7 +745,7 @@ resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
resizer_calculate_resize_ratios(resizer, RSZ_A);
resizer_calculate_sdram_offsets(resizer, RSZ_A);
/* Overriding resize ratio calculation */
- if (informat->code == V4L2_MBUS_FMT_UV8_1X8) {
+ if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
param->rsz_rsc_param[RSZ_A].v_dif =
(((informat->height + 1) * 2) * 256) /
(param->rsz_rsc_param[RSZ_A].o_vsz + 1);
@@ -756,7 +756,7 @@ resizer_configure_in_single_shot_mode(struct vpfe_resizer_device *resizer)
resizer_calculate_resize_ratios(resizer, RSZ_B);
resizer_calculate_sdram_offsets(resizer, RSZ_B);
/* Overriding resize ratio calculation */
- if (informat->code == V4L2_MBUS_FMT_UV8_1X8) {
+ if (informat->code == MEDIA_BUS_FMT_UV8_1X8) {
param->rsz_rsc_param[RSZ_B].v_dif =
(((informat->height + 1) * 2) * 256) /
(param->rsz_rsc_param[RSZ_B].o_vsz + 1);
@@ -1340,7 +1340,7 @@ resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
/* If not found, use UYVY as default */
if (i >= ARRAY_SIZE(resizer_input_formats))
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->width = clamp_t(u32, fmt->width, MIN_IN_WIDTH,
MAX_IN_WIDTH);
@@ -1357,7 +1357,7 @@ resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
/* If not found, use UYVY as default */
if (i >= ARRAY_SIZE(resizer_output_formats))
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
max_out_width);
@@ -1375,7 +1375,7 @@ resizer_try_format(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh,
}
/* If not found, use UYVY as default */
if (i >= ARRAY_SIZE(resizer_output_formats))
- fmt->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_2X8;
fmt->width = clamp_t(u32, fmt->width, MIN_OUT_WIDTH,
max_out_width);
@@ -1548,7 +1548,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_CROP_PAD_SINK;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
format.format.width = MAX_IN_WIDTH;
format.format.height = MAX_IN_HEIGHT;
resizer_set_format(sd, fh, &format);
@@ -1556,7 +1556,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_CROP_PAD_SOURCE;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format.format.width = MAX_IN_WIDTH;
format.format.height = MAX_IN_WIDTH;
resizer_set_format(sd, fh, &format);
@@ -1564,7 +1564,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_CROP_PAD_SOURCE2;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format.format.width = MAX_IN_WIDTH;
format.format.height = MAX_IN_WIDTH;
resizer_set_format(sd, fh, &format);
@@ -1572,7 +1572,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_PAD_SINK;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
format.format.width = MAX_IN_WIDTH;
format.format.height = MAX_IN_HEIGHT;
resizer_set_format(sd, fh, &format);
@@ -1580,7 +1580,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_PAD_SOURCE;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format.format.width = IPIPE_MAX_OUTPUT_WIDTH_A;
format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_A;
resizer_set_format(sd, fh, &format);
@@ -1588,7 +1588,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_PAD_SINK;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_YUYV8_2X8;
+ format.format.code = MEDIA_BUS_FMT_YUYV8_2X8;
format.format.width = MAX_IN_WIDTH;
format.format.height = MAX_IN_HEIGHT;
resizer_set_format(sd, fh, &format);
@@ -1596,7 +1596,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_PAD_SOURCE;
format.which = which;
- format.format.code = V4L2_MBUS_FMT_UYVY8_2X8;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_2X8;
format.format.width = IPIPE_MAX_OUTPUT_WIDTH_B;
format.format.height = IPIPE_MAX_OUTPUT_HEIGHT_B;
resizer_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
index a862b28..bf45d2c 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_mc_capture.c
@@ -99,47 +99,47 @@ void mbus_to_pix(const struct v4l2_mbus_framefmt *mbus,
struct v4l2_pix_format *pix)
{
switch (mbus->code) {
- case V4L2_MBUS_FMT_UYVY8_2X8:
+ case MEDIA_BUS_FMT_UYVY8_2X8:
pix->pixelformat = V4L2_PIX_FMT_UYVY;
pix->bytesperline = pix->width * 2;
break;
- case V4L2_MBUS_FMT_YUYV8_2X8:
+ case MEDIA_BUS_FMT_YUYV8_2X8:
pix->pixelformat = V4L2_PIX_FMT_YUYV;
pix->bytesperline = pix->width * 2;
break;
- case V4L2_MBUS_FMT_YUYV10_1X20:
+ case MEDIA_BUS_FMT_YUYV10_1X20:
pix->pixelformat = V4L2_PIX_FMT_UYVY;
pix->bytesperline = pix->width * 2;
break;
- case V4L2_MBUS_FMT_SGRBG12_1X12:
+ case MEDIA_BUS_FMT_SGRBG12_1X12:
pix->pixelformat = V4L2_PIX_FMT_SBGGR16;
pix->bytesperline = pix->width * 2;
break;
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
pix->pixelformat = V4L2_PIX_FMT_SGRBG10DPCM8;
pix->bytesperline = pix->width;
break;
- case V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8:
pix->pixelformat = V4L2_PIX_FMT_SGRBG10ALAW8;
pix->bytesperline = pix->width;
break;
- case V4L2_MBUS_FMT_YDYUYDYV8_1X16:
+ case MEDIA_BUS_FMT_YDYUYDYV8_1X16:
pix->pixelformat = V4L2_PIX_FMT_NV12;
pix->bytesperline = pix->width;
break;
- case V4L2_MBUS_FMT_Y8_1X8:
+ case MEDIA_BUS_FMT_Y8_1X8:
pix->pixelformat = V4L2_PIX_FMT_GREY;
pix->bytesperline = pix->width;
break;
- case V4L2_MBUS_FMT_UV8_1X8:
+ case MEDIA_BUS_FMT_UV8_1X8:
pix->pixelformat = V4L2_PIX_FMT_UV8;
pix->bytesperline = pix->width;
break;
diff --git a/drivers/staging/media/davinci_vpfe/vpfe_video.c b/drivers/staging/media/davinci_vpfe/vpfe_video.c
index 6f9171c..06d48d5 100644
--- a/drivers/staging/media/davinci_vpfe/vpfe_video.c
+++ b/drivers/staging/media/davinci_vpfe/vpfe_video.c
@@ -600,11 +600,11 @@ static int vpfe_querycap(struct file *file, void *priv,
v4l2_dbg(1, debug, &vpfe_dev->v4l2_dev, "vpfe_querycap\n");
if (video->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
else
- cap->capabilities = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
- cap->device_caps = cap->capabilities;
- cap->version = VPFE_CAPTURE_VERSION_CODE;
+ cap->device_caps = V4L2_CAP_VIDEO_OUTPUT | V4L2_CAP_STREAMING;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT |
+ V4L2_CAP_STREAMING | V4L2_CAP_DEVICE_CAPS;
strlcpy(cap->driver, CAPTURE_DRV_NAME, sizeof(cap->driver));
strlcpy(cap->bus_info, "VPFE", sizeof(cap->bus_info));
strlcpy(cap->card, vpfe_dev->cfg->card_name, sizeof(cap->card));
diff --git a/drivers/staging/media/dt3155v4l/dt3155v4l.c b/drivers/staging/media/dt3155v4l/dt3155v4l.c
index 4058022..293ffda 100644
--- a/drivers/staging/media/dt3155v4l/dt3155v4l.c
+++ b/drivers/staging/media/dt3155v4l/dt3155v4l.c
@@ -512,10 +512,9 @@ dt3155_ioc_querycap(struct file *filp, void *p, struct v4l2_capability *cap)
strcpy(cap->driver, DT3155_NAME);
strcpy(cap->card, DT3155_NAME " frame grabber");
sprintf(cap->bus_info, "PCI:%s", pci_name(pd->pdev));
- cap->version =
- KERNEL_VERSION(DT3155_VER_MAJ, DT3155_VER_MIN, DT3155_VER_EXT);
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ cap->device_caps = V4L2_CAP_VIDEO_CAPTURE |
DT3155_CAPTURE_METHOD;
+ cap->capabilities = cap->device_caps | V4L2_CAP_DEVICE_CAPS;
return 0;
}
diff --git a/drivers/staging/media/lirc/Kconfig b/drivers/staging/media/lirc/Kconfig
index e60a59f..6879c46 100644
--- a/drivers/staging/media/lirc/Kconfig
+++ b/drivers/staging/media/lirc/Kconfig
@@ -18,12 +18,6 @@ config LIRC_BT829
help
Driver for the IR interface on BT829-based hardware
-config LIRC_IGORPLUGUSB
- tristate "Igor Cesko's USB IR Receiver"
- depends on LIRC && USB
- help
- Driver for Igor Cesko's USB IR Receiver
-
config LIRC_IMON
tristate "Legacy SoundGraph iMON Receiver and Display"
depends on LIRC && USB
diff --git a/drivers/staging/media/lirc/Makefile b/drivers/staging/media/lirc/Makefile
index b90fcab..5430adf 100644
--- a/drivers/staging/media/lirc/Makefile
+++ b/drivers/staging/media/lirc/Makefile
@@ -4,7 +4,6 @@
# Each configuration option enables a list of files.
obj-$(CONFIG_LIRC_BT829) += lirc_bt829.o
-obj-$(CONFIG_LIRC_IGORPLUGUSB) += lirc_igorplugusb.o
obj-$(CONFIG_LIRC_IMON) += lirc_imon.o
obj-$(CONFIG_LIRC_PARALLEL) += lirc_parallel.o
obj-$(CONFIG_LIRC_SASEM) += lirc_sasem.o
diff --git a/drivers/staging/media/lirc/lirc_igorplugusb.c b/drivers/staging/media/lirc/lirc_igorplugusb.c
deleted file mode 100644
index 431d1e8..0000000
--- a/drivers/staging/media/lirc/lirc_igorplugusb.c
+++ /dev/null
@@ -1,508 +0,0 @@
-/*
- * lirc_igorplugusb - USB remote support for LIRC
- *
- * Supports the standard homebrew IgorPlugUSB receiver with Igor's firmware.
- * See http://www.cesko.host.sk/IgorPlugUSB/IgorPlug-USB%20(AVR)_eng.htm
- *
- * The device can only record bursts of up to 36 pulses/spaces.
- * Works fine with RC5. Longer commands lead to device buffer overrun.
- * (Maybe a better firmware or a microcontroller with more ram can help?)
- *
- * Version 0.1 [beta status]
- *
- * Copyright (C) 2004 Jan M. Hochstein
- * <hochstein@algo.informatik.tu-darmstadt.de>
- *
- * This driver was derived from:
- * Paul Miller <pmiller9@users.sourceforge.net>
- * "lirc_atiusb" module
- * Vladimir Dergachev <volodya@minspring.com>'s 2002
- * "USB ATI Remote support" (input device)
- * Adrian Dewhurst <sailor-lk@sailorfrag.net>'s 2002
- * "USB StreamZap remote driver" (LIRC)
- * Artur Lipowski <alipowski@kki.net.pl>'s 2002
- * "lirc_dev" and "lirc_gpio" LIRC modules
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/sched.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/usb.h>
-#include <linux/time.h>
-
-#include <media/lirc.h>
-#include <media/lirc_dev.h>
-
-
-/* module identification */
-#define DRIVER_VERSION "0.2"
-#define DRIVER_AUTHOR \
- "Jan M. Hochstein <hochstein@algo.informatik.tu-darmstadt.de>"
-#define DRIVER_DESC "Igorplug USB remote driver for LIRC"
-#define DRIVER_NAME "lirc_igorplugusb"
-
-/* One mode2 pulse/space has 4 bytes. */
-#define CODE_LENGTH sizeof(int)
-
-/* Igor's firmware cannot record bursts longer than 36. */
-#define DEVICE_BUFLEN 36
-
-/*
- * Header at the beginning of the device's buffer:
- * unsigned char data_length
- * unsigned char data_start (!=0 means ring-buffer overrun)
- * unsigned char counter (incremented by each burst)
- */
-#define DEVICE_HEADERLEN 3
-
-/* This is for the gap */
-#define ADDITIONAL_LIRC_BYTES 2
-
-/* times to poll per second */
-#define SAMPLE_RATE 100
-static int sample_rate = SAMPLE_RATE;
-
-
-/**** Igor's USB Request Codes */
-
-#define SET_INFRABUFFER_EMPTY 1
-/**
- * Params: none
- * Answer: empty
- */
-
-#define GET_INFRACODE 2
-/**
- * Params:
- * wValue: offset to begin reading infra buffer
- *
- * Answer: infra data
- */
-
-#define SET_DATAPORT_DIRECTION 3
-/**
- * Params:
- * wValue: (byte) 1 bit for each data port pin (0=in, 1=out)
- *
- * Answer: empty
- */
-
-#define GET_DATAPORT_DIRECTION 4
-/**
- * Params: none
- *
- * Answer: (byte) 1 bit for each data port pin (0=in, 1=out)
- */
-
-#define SET_OUT_DATAPORT 5
-/**
- * Params:
- * wValue: byte to write to output data port
- *
- * Answer: empty
- */
-
-#define GET_OUT_DATAPORT 6
-/**
- * Params: none
- *
- * Answer: least significant 3 bits read from output data port
- */
-
-#define GET_IN_DATAPORT 7
-/**
- * Params: none
- *
- * Answer: least significant 3 bits read from input data port
- */
-
-#define READ_EEPROM 8
-/**
- * Params:
- * wValue: offset to begin reading EEPROM
- *
- * Answer: EEPROM bytes
- */
-
-#define WRITE_EEPROM 9
-/**
- * Params:
- * wValue: offset to EEPROM byte
- * wIndex: byte to write
- *
- * Answer: empty
- */
-
-#define SEND_RS232 10
-/**
- * Params:
- * wValue: byte to send
- *
- * Answer: empty
- */
-
-#define RECV_RS232 11
-/**
- * Params: none
- *
- * Answer: byte received
- */
-
-#define SET_RS232_BAUD 12
-/**
- * Params:
- * wValue: byte to write to UART bit rate register (UBRR)
- *
- * Answer: empty
- */
-
-#define GET_RS232_BAUD 13
-/**
- * Params: none
- *
- * Answer: byte read from UART bit rate register (UBRR)
- */
-
-
-/* data structure for each usb remote */
-struct igorplug {
-
- /* usb */
- struct usb_device *usbdev;
- int devnum;
-
- unsigned char *buf_in;
- unsigned int len_in;
- int in_space;
- struct timeval last_time;
-
- dma_addr_t dma_in;
-
- /* lirc */
- struct lirc_driver *d;
-
- /* handle sending (init strings) */
- int send_flags;
-};
-
-static int unregister_from_lirc(struct igorplug *ir)
-{
- struct lirc_driver *d;
- int devnum;
-
- devnum = ir->devnum;
- d = ir->d;
-
- if (!d) {
- dev_err(&ir->usbdev->dev,
- "%s: called with NULL lirc driver struct!\n", __func__);
- return -EINVAL;
- }
-
- dev_dbg(&ir->usbdev->dev, "calling lirc_unregister_driver\n");
- lirc_unregister_driver(d->minor);
-
- return devnum;
-}
-
-static int set_use_inc(void *data)
-{
- struct igorplug *ir = data;
-
- if (!ir) {
- printk(DRIVER_NAME "[?]: set_use_inc called with no context\n");
- return -EIO;
- }
-
- dev_dbg(&ir->usbdev->dev, "set use inc\n");
-
- if (!ir->usbdev)
- return -ENODEV;
-
- return 0;
-}
-
-static void set_use_dec(void *data)
-{
- struct igorplug *ir = data;
-
- if (!ir) {
- printk(DRIVER_NAME "[?]: set_use_dec called with no context\n");
- return;
- }
-
- dev_dbg(&ir->usbdev->dev, "set use dec\n");
-}
-
-static void send_fragment(struct igorplug *ir, struct lirc_buffer *buf,
- int i, int max)
-{
- int code;
-
- /* MODE2: pulse/space (PULSE_BIT) in 1us units */
- while (i < max) {
- /* 1 Igor-tick = 85.333333 us */
- code = (unsigned int)ir->buf_in[i] * 85 +
- (unsigned int)ir->buf_in[i] / 3;
- ir->last_time.tv_usec += code;
- if (ir->in_space)
- code |= PULSE_BIT;
- lirc_buffer_write(buf, (unsigned char *)&code);
- /* 1 chunk = CODE_LENGTH bytes */
- ir->in_space ^= 1;
- ++i;
- }
-}
-
-/**
- * Called in user context.
- * return 0 if data was added to the buffer and
- * -ENODATA if none was available. This should add some number of bits
- * evenly divisible by code_length to the buffer
- */
-static int igorplugusb_remote_poll(void *data, struct lirc_buffer *buf)
-{
- int ret;
- struct igorplug *ir = (struct igorplug *)data;
-
- if (!ir || !ir->usbdev) /* Has the device been removed? */
- return -ENODEV;
-
- memset(ir->buf_in, 0, ir->len_in);
-
- ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
- GET_INFRACODE, USB_TYPE_VENDOR | USB_DIR_IN,
- 0/* offset */, /*unused*/0,
- ir->buf_in, ir->len_in,
- /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
- if (ret > 0) {
- int code, timediff;
- struct timeval now;
-
- /* ACK packet has 1 byte --> ignore */
- if (ret < DEVICE_HEADERLEN)
- return -ENODATA;
-
- dev_dbg(&ir->usbdev->dev, "Got %d bytes. Header: %*ph\n",
- ret, 3, ir->buf_in);
-
- do_gettimeofday(&now);
- timediff = now.tv_sec - ir->last_time.tv_sec;
- if (timediff + 1 > PULSE_MASK / 1000000)
- timediff = PULSE_MASK;
- else {
- timediff *= 1000000;
- timediff += now.tv_usec - ir->last_time.tv_usec;
- }
- ir->last_time.tv_sec = now.tv_sec;
- ir->last_time.tv_usec = now.tv_usec;
-
- /* create leading gap */
- code = timediff;
- lirc_buffer_write(buf, (unsigned char *)&code);
- ir->in_space = 1; /* next comes a pulse */
-
- if (ir->buf_in[2] == 0)
- send_fragment(ir, buf, DEVICE_HEADERLEN, ret);
- else {
- dev_warn(&ir->usbdev->dev,
- "[%d]: Device buffer overrun.\n", ir->devnum);
- /* HHHNNNNNNNNNNNOOOOOOOO H = header
- <---[2]---> N = newer
- <---------ret--------> O = older */
- ir->buf_in[2] %= ret - DEVICE_HEADERLEN; /* sanitize */
- /* keep even-ness to not desync pulse/pause */
- send_fragment(ir, buf, DEVICE_HEADERLEN +
- ir->buf_in[2] - (ir->buf_in[2] & 1), ret);
- send_fragment(ir, buf, DEVICE_HEADERLEN,
- DEVICE_HEADERLEN + ir->buf_in[2]);
- }
-
- ret = usb_control_msg(
- ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
- SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
- /*unused*/0, /*unused*/0,
- /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
- /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
- if (ret < 0)
- printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
- ir->devnum, ret);
- return 0;
- } else if (ret < 0)
- printk(DRIVER_NAME "[%d]: GET_INFRACODE: error %d\n",
- ir->devnum, ret);
-
- return -ENODATA;
-}
-
-static int igorplugusb_remote_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev;
- struct usb_host_interface *idesc = NULL;
- struct usb_endpoint_descriptor *ep;
- struct igorplug *ir = NULL;
- struct lirc_driver *driver = NULL;
- int devnum, pipe, maxp;
- char buf[63], name[128] = "";
- int ret;
-
- dev_dbg(&intf->dev, "%s: usb probe called.\n", __func__);
-
- dev = interface_to_usbdev(intf);
-
- idesc = intf->cur_altsetting;
-
- if (idesc->desc.bNumEndpoints != 1)
- return -ENODEV;
-
- ep = &idesc->endpoint->desc;
- if (((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
- != USB_DIR_IN)
- || (ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
- != USB_ENDPOINT_XFER_CONTROL)
- return -ENODEV;
-
- pipe = usb_rcvctrlpipe(dev, ep->bEndpointAddress);
- devnum = dev->devnum;
- maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
-
- dev_dbg(&intf->dev, "%s: bytes_in_key=%zu maxp=%d\n",
- __func__, CODE_LENGTH, maxp);
-
- ir = devm_kzalloc(&intf->dev, sizeof(*ir), GFP_KERNEL);
- if (!ir)
- return -ENOMEM;
-
- driver = devm_kzalloc(&intf->dev, sizeof(*driver), GFP_KERNEL);
- if (!driver)
- return -ENOMEM;
-
- ir->buf_in = usb_alloc_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
- GFP_ATOMIC, &ir->dma_in);
- if (!ir->buf_in)
- return -ENOMEM;
-
- strcpy(driver->name, DRIVER_NAME " ");
- driver->minor = -1;
- driver->code_length = CODE_LENGTH * 8; /* in bits */
- driver->features = LIRC_CAN_REC_MODE2;
- driver->data = ir;
- driver->chunk_size = CODE_LENGTH;
- driver->buffer_size = DEVICE_BUFLEN + ADDITIONAL_LIRC_BYTES;
- driver->set_use_inc = &set_use_inc;
- driver->set_use_dec = &set_use_dec;
- driver->sample_rate = sample_rate; /* per second */
- driver->add_to_buf = &igorplugusb_remote_poll;
- driver->dev = &intf->dev;
- driver->owner = THIS_MODULE;
-
- ret = lirc_register_driver(driver);
- if (ret < 0) {
- usb_free_coherent(dev, DEVICE_BUFLEN + DEVICE_HEADERLEN,
- ir->buf_in, ir->dma_in);
- return ret;
- }
-
- driver->minor = ret;
- ir->d = driver;
- ir->devnum = devnum;
- ir->usbdev = dev;
- ir->len_in = DEVICE_BUFLEN + DEVICE_HEADERLEN;
- ir->in_space = 1; /* First mode2 event is a space. */
- do_gettimeofday(&ir->last_time);
-
- if (dev->descriptor.iManufacturer
- && usb_string(dev, dev->descriptor.iManufacturer,
- buf, sizeof(buf)) > 0)
- strlcpy(name, buf, sizeof(name));
- if (dev->descriptor.iProduct
- && usb_string(dev, dev->descriptor.iProduct, buf, sizeof(buf)) > 0)
- snprintf(name + strlen(name), sizeof(name) - strlen(name),
- " %s", buf);
- printk(DRIVER_NAME "[%d]: %s on usb%d:%d\n", devnum, name,
- dev->bus->busnum, devnum);
-
- /* clear device buffer */
- ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
- SET_INFRABUFFER_EMPTY, USB_TYPE_VENDOR|USB_DIR_IN,
- /*unused*/0, /*unused*/0,
- /*dummy*/ir->buf_in, /*dummy*/ir->len_in,
- /*timeout*/HZ * USB_CTRL_GET_TIMEOUT);
- if (ret < 0)
- printk(DRIVER_NAME "[%d]: SET_INFRABUFFER_EMPTY: error %d\n",
- devnum, ret);
-
- usb_set_intfdata(intf, ir);
- return 0;
-}
-
-static void igorplugusb_remote_disconnect(struct usb_interface *intf)
-{
- struct usb_device *usbdev = interface_to_usbdev(intf);
- struct igorplug *ir = usb_get_intfdata(intf);
- struct device *dev = &intf->dev;
- int devnum;
-
- usb_set_intfdata(intf, NULL);
-
- if (!ir || !ir->d)
- return;
-
- ir->usbdev = NULL;
-
- usb_free_coherent(usbdev, ir->len_in, ir->buf_in, ir->dma_in);
-
- devnum = unregister_from_lirc(ir);
-
- dev_info(dev, DRIVER_NAME "[%d]: %s done\n", devnum, __func__);
-}
-
-static struct usb_device_id igorplugusb_remote_id_table[] = {
- /* Igor Plug USB (Atmel's Manufact. ID) */
- { USB_DEVICE(0x03eb, 0x0002) },
- /* Fit PC2 Infrared Adapter */
- { USB_DEVICE(0x03eb, 0x21fe) },
-
- /* Terminating entry */
- { }
-};
-
-static struct usb_driver igorplugusb_remote_driver = {
- .name = DRIVER_NAME,
- .probe = igorplugusb_remote_probe,
- .disconnect = igorplugusb_remote_disconnect,
- .id_table = igorplugusb_remote_id_table
-};
-
-module_usb_driver(igorplugusb_remote_driver);
-
-#include <linux/vermagic.h>
-MODULE_INFO(vermagic, VERMAGIC_STRING);
-
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_LICENSE("GPL");
-MODULE_DEVICE_TABLE(usb, igorplugusb_remote_id_table);
-
-module_param(sample_rate, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(sample_rate, "Sampling rate in Hz (default: 100)");
diff --git a/drivers/staging/media/lirc/lirc_imon.c b/drivers/staging/media/lirc/lirc_imon.c
index 7aca44f..232edd5 100644
--- a/drivers/staging/media/lirc/lirc_imon.c
+++ b/drivers/staging/media/lirc/lirc_imon.c
@@ -606,7 +606,6 @@ static void imon_incoming_packet(struct imon_context *context,
struct device *dev = context->driver->dev;
int octet, bit;
unsigned char mask;
- int i;
/*
* just bail out if no listening IR client
@@ -620,13 +619,8 @@ static void imon_incoming_packet(struct imon_context *context,
return;
}
- if (debug) {
- dev_info(dev, "raw packet: ");
- for (i = 0; i < len; ++i)
- printk("%02x ", buf[i]);
- printk("\n");
- }
-
+ if (debug)
+ dev_info(dev, "raw packet: %*ph\n", len, buf);
/*
* Translate received data to pulse and space lengths.
* Received data is active low, i.e. pulses are 0 and
diff --git a/drivers/staging/media/lirc/lirc_sasem.c b/drivers/staging/media/lirc/lirc_sasem.c
index c20ef56..2f0463e 100644
--- a/drivers/staging/media/lirc/lirc_sasem.c
+++ b/drivers/staging/media/lirc/lirc_sasem.c
@@ -573,7 +573,6 @@ static void incoming_packet(struct sasem_context *context,
unsigned char *buf = urb->transfer_buffer;
long ms;
struct timeval tv;
- int i;
if (len != 8) {
dev_warn(&context->dev->dev,
@@ -582,13 +581,8 @@ static void incoming_packet(struct sasem_context *context,
return;
}
- if (debug) {
- printk(KERN_INFO "Incoming data: ");
- for (i = 0; i < 8; ++i)
- printk(KERN_CONT "%02x ", buf[i]);
- printk(KERN_CONT "\n");
- }
-
+ if (debug)
+ dev_info(&context->dev->dev, "Incoming data: %*ph\n", len, buf);
/*
* Lirc could deal with the repeat code, but we really need to block it
* if it arrives too late. Otherwise we could repeat the wrong code.
diff --git a/drivers/staging/media/lirc/lirc_zilog.c b/drivers/staging/media/lirc/lirc_zilog.c
index 567feba..1e15d2c 100644
--- a/drivers/staging/media/lirc/lirc_zilog.c
+++ b/drivers/staging/media/lirc/lirc_zilog.c
@@ -199,7 +199,7 @@ static void release_ir_device(struct kref *ref)
lirc_unregister_driver(ir->l.minor);
ir->l.minor = MAX_IRCTL_DEVICES;
}
- if (ir->rbuf.fifo_initialized)
+ if (kfifo_initialized(&ir->rbuf.fifo))
lirc_buffer_free(&ir->rbuf);
list_del(&ir->list);
kfree(ir);
@@ -730,11 +730,9 @@ static int send_boot_data(struct IR_tx *tx)
static void fw_unload_locked(void)
{
if (tx_data) {
- if (tx_data->code_sets)
- vfree(tx_data->code_sets);
+ vfree(tx_data->code_sets);
- if (tx_data->datap)
- vfree(tx_data->datap);
+ vfree(tx_data->datap);
vfree(tx_data);
tx_data = NULL;
diff --git a/drivers/staging/media/mn88472/Kconfig b/drivers/staging/media/mn88472/Kconfig
new file mode 100644
index 0000000..a85c90a
--- /dev/null
+++ b/drivers/staging/media/mn88472/Kconfig
@@ -0,0 +1,7 @@
+config DVB_MN88472
+ tristate "Panasonic MN88472"
+ depends on DVB_CORE && I2C
+ select REGMAP_I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
diff --git a/drivers/staging/media/mn88472/Makefile b/drivers/staging/media/mn88472/Makefile
new file mode 100644
index 0000000..5987b7e
--- /dev/null
+++ b/drivers/staging/media/mn88472/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_DVB_MN88472) += mn88472.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/staging/media/mn88472/TODO b/drivers/staging/media/mn88472/TODO
new file mode 100644
index 0000000..b90a14b
--- /dev/null
+++ b/drivers/staging/media/mn88472/TODO
@@ -0,0 +1,21 @@
+Driver general quality is not good enough for mainline. Also, other
+device drivers (USB-bridge, tuner) needed for Astrometa receiver in
+question could need some changes. However, if that driver is mainlined
+due to some other device than Astrometa, unrelated TODOs could be
+skipped. In that case rtl28xxu driver needs module parameter to prevent
+driver loading.
+
+Required TODOs:
+* missing lock flags
+* I2C errors
+* tuner sensitivity
+
+*Do not* send any patch fixing checkpatch.pl issues. Currently it passes
+checkpatch.pl tests. I don't want waste my time to review this kind of
+trivial stuff. *Do not* add missing register I/O error checks. Those are
+missing for the reason it is much easier to compare I2C data sniffs when
+there is less lines. Those error checks are about the last thing to be added.
+
+Patches should be submitted to:
+linux-media@vger.kernel.org and Antti Palosaari <crope@iki.fi>
+
diff --git a/drivers/staging/media/mn88472/mn88472.c b/drivers/staging/media/mn88472/mn88472.c
new file mode 100644
index 0000000..52de8f8
--- /dev/null
+++ b/drivers/staging/media/mn88472/mn88472.c
@@ -0,0 +1,523 @@
+/*
+ * Panasonic MN88472 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2013 Antti Palosaari <crope@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 "mn88472_priv.h"
+
+static int mn88472_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 400;
+ return 0;
+}
+
+static int mn88472_set_frontend(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88472_dev *dev = i2c_get_clientdata(client);
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u32 if_frequency = 0;
+ u8 delivery_system_val, if_val[3], bw_val[7], bw_val2;
+
+ dev_dbg(&client->dev,
+ "delivery_system=%d modulation=%d frequency=%d symbol_rate=%d inversion=%d\n",
+ c->delivery_system, c->modulation,
+ c->frequency, c->symbol_rate, c->inversion);
+
+ if (!dev->warm) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ delivery_system_val = 0x02;
+ break;
+ case SYS_DVBT2:
+ delivery_system_val = 0x03;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ delivery_system_val = 0x04;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ if (c->bandwidth_hz <= 6000000) {
+ /* IF 3570000 Hz, BW 6000000 Hz */
+ memcpy(if_val, "\x2c\x94\xdb", 3);
+ memcpy(bw_val, "\xbf\x55\x55\x15\x6b\x15\x6b", 7);
+ bw_val2 = 0x02;
+ } else if (c->bandwidth_hz <= 7000000) {
+ /* IF 4570000 Hz, BW 7000000 Hz */
+ memcpy(if_val, "\x39\x11\xbc", 3);
+ memcpy(bw_val, "\xa4\x00\x00\x0f\x2c\x0f\x2c", 7);
+ bw_val2 = 0x01;
+ } else if (c->bandwidth_hz <= 8000000) {
+ /* IF 4570000 Hz, BW 8000000 Hz */
+ memcpy(if_val, "\x39\x11\xbc", 3);
+ memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7);
+ bw_val2 = 0x00;
+ } else {
+ ret = -EINVAL;
+ goto err;
+ }
+ break;
+ case SYS_DVBC_ANNEX_A:
+ /* IF 5070000 Hz, BW 8000000 Hz */
+ memcpy(if_val, "\x3f\x50\x2c", 3);
+ memcpy(bw_val, "\x8f\x80\x00\x08\xee\x08\xee", 7);
+ bw_val2 = 0x00;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe);
+ if (ret)
+ goto err;
+ }
+
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+ if (ret)
+ goto err;
+
+ dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency);
+ }
+
+ switch (if_frequency) {
+ case 3570000:
+ case 4570000:
+ case 5070000:
+ break;
+ default:
+ dev_err(&client->dev, "IF frequency %d not supported\n",
+ if_frequency);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = regmap_write(dev->regmap[2], 0xfb, 0x13);
+ ret = regmap_write(dev->regmap[2], 0xef, 0x13);
+ ret = regmap_write(dev->regmap[2], 0xf9, 0x13);
+ if (ret)
+ goto err;
+
+ ret = regmap_write(dev->regmap[2], 0x00, 0x66);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap[2], 0x01, 0x00);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap[2], 0x02, 0x01);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val);
+ if (ret)
+ goto err;
+ ret = regmap_write(dev->regmap[2], 0x04, bw_val2);
+ if (ret)
+ goto err;
+
+ for (i = 0; i < sizeof(if_val); i++) {
+ ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]);
+ if (ret)
+ goto err;
+ }
+
+ for (i = 0; i < sizeof(bw_val); i++) {
+ ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]);
+ if (ret)
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ ret = regmap_write(dev->regmap[0], 0x07, 0x26);
+ ret = regmap_write(dev->regmap[0], 0xb0, 0x0a);
+ ret = regmap_write(dev->regmap[0], 0xb4, 0x00);
+ ret = regmap_write(dev->regmap[0], 0xcd, 0x1f);
+ ret = regmap_write(dev->regmap[0], 0xd4, 0x0a);
+ ret = regmap_write(dev->regmap[0], 0xd6, 0x48);
+ ret = regmap_write(dev->regmap[0], 0x00, 0xba);
+ ret = regmap_write(dev->regmap[0], 0x01, 0x13);
+ if (ret)
+ goto err;
+ break;
+ case SYS_DVBT2:
+ ret = regmap_write(dev->regmap[2], 0x2b, 0x13);
+ ret = regmap_write(dev->regmap[2], 0x4f, 0x05);
+ ret = regmap_write(dev->regmap[1], 0xf6, 0x05);
+ ret = regmap_write(dev->regmap[0], 0xb0, 0x0a);
+ ret = regmap_write(dev->regmap[0], 0xb4, 0xf6);
+ ret = regmap_write(dev->regmap[0], 0xcd, 0x01);
+ ret = regmap_write(dev->regmap[0], 0xd4, 0x09);
+ ret = regmap_write(dev->regmap[0], 0xd6, 0x46);
+ ret = regmap_write(dev->regmap[2], 0x30, 0x80);
+ ret = regmap_write(dev->regmap[2], 0x32, 0x00);
+ if (ret)
+ goto err;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ ret = regmap_write(dev->regmap[0], 0xb0, 0x0b);
+ ret = regmap_write(dev->regmap[0], 0xb4, 0x00);
+ ret = regmap_write(dev->regmap[0], 0xcd, 0x17);
+ ret = regmap_write(dev->regmap[0], 0xd4, 0x09);
+ ret = regmap_write(dev->regmap[0], 0xd6, 0x48);
+ ret = regmap_write(dev->regmap[1], 0x00, 0xb0);
+ if (ret)
+ goto err;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = regmap_write(dev->regmap[0], 0x46, 0x00);
+ ret = regmap_write(dev->regmap[0], 0xae, 0x00);
+ ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
+ ret = regmap_write(dev->regmap[0], 0xd9, 0xe3);
+ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
+ if (ret)
+ goto err;
+
+ dev->delivery_system = c->delivery_system;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88472_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88472_dev *dev = i2c_get_clientdata(client);
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret;
+ unsigned int utmp;
+
+ *status = 0;
+
+ if (!dev->warm) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ /* FIXME: implement me */
+ utmp = 0x08; /* DVB-C lock value */
+ break;
+ case SYS_DVBC_ANNEX_A:
+ ret = regmap_read(dev->regmap[1], 0x84, &utmp);
+ if (ret)
+ goto err;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ if (utmp == 0x08)
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88472_init(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88472_dev *dev = i2c_get_clientdata(client);
+ int ret, len, remaining;
+ const struct firmware *fw = NULL;
+ u8 *fw_file = MN88472_FIRMWARE;
+
+ dev_dbg(&client->dev, "\n");
+
+ /* set cold state by default */
+ dev->warm = false;
+
+ /* power on */
+ ret = regmap_write(dev->regmap[2], 0x05, 0x00);
+ if (ret)
+ goto err;
+
+ ret = regmap_bulk_write(dev->regmap[2], 0x0b, "\x00\x00", 2);
+ if (ret)
+ goto err;
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_file, &client->dev);
+ if (ret) {
+ dev_err(&client->dev, "firmare file '%s' not found\n",
+ fw_file);
+ goto err;
+ }
+
+ dev_info(&client->dev, "downloading firmware from file '%s'\n",
+ fw_file);
+
+ ret = regmap_write(dev->regmap[0], 0xf5, 0x03);
+ if (ret)
+ goto err;
+
+ for (remaining = fw->size; remaining > 0;
+ remaining -= (dev->i2c_wr_max - 1)) {
+ len = remaining;
+ if (len > (dev->i2c_wr_max - 1))
+ len = (dev->i2c_wr_max - 1);
+
+ ret = regmap_bulk_write(dev->regmap[0], 0xf6,
+ &fw->data[fw->size - remaining], len);
+ if (ret) {
+ dev_err(&client->dev,
+ "firmware download failed=%d\n", ret);
+ goto err;
+ }
+ }
+
+ ret = regmap_write(dev->regmap[0], 0xf5, 0x00);
+ if (ret)
+ goto err;
+
+ release_firmware(fw);
+ fw = NULL;
+
+ /* warm state */
+ dev->warm = true;
+
+ return 0;
+err:
+ if (fw)
+ release_firmware(fw);
+
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88472_sleep(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88472_dev *dev = i2c_get_clientdata(client);
+ int ret;
+
+ dev_dbg(&client->dev, "\n");
+
+ /* power off */
+ ret = regmap_write(dev->regmap[2], 0x0b, 0x30);
+
+ if (ret)
+ goto err;
+
+ ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
+ if (ret)
+ goto err;
+
+ dev->delivery_system = SYS_UNDEFINED;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static struct dvb_frontend_ops mn88472_ops = {
+ .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_A},
+ .info = {
+ .name = "Panasonic MN88472",
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION |
+ FE_CAN_MULTISTREAM
+ },
+
+ .get_tune_settings = mn88472_get_tune_settings,
+
+ .init = mn88472_init,
+ .sleep = mn88472_sleep,
+
+ .set_frontend = mn88472_set_frontend,
+
+ .read_status = mn88472_read_status,
+};
+
+static int mn88472_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mn88472_config *config = client->dev.platform_data;
+ struct mn88472_dev *dev;
+ int ret;
+ unsigned int utmp;
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+
+ dev_dbg(&client->dev, "\n");
+
+ /* Caller really need to provide pointer for frontend we create. */
+ if (config->fe == NULL) {
+ dev_err(&client->dev, "frontend pointer not defined\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev->i2c_wr_max = config->i2c_wr_max;
+ dev->client[0] = client;
+ dev->regmap[0] = regmap_init_i2c(dev->client[0], &regmap_config);
+ if (IS_ERR(dev->regmap[0])) {
+ ret = PTR_ERR(dev->regmap[0]);
+ goto err_kfree;
+ }
+
+ /* check demod answers to I2C */
+ ret = regmap_read(dev->regmap[0], 0x00, &utmp);
+ if (ret)
+ goto err_regmap_0_regmap_exit;
+
+ /*
+ * Chip has three I2C addresses for different register pages. Used
+ * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients,
+ * 0x1a and 0x1c, in order to get own I2C client for each register page.
+ */
+ dev->client[1] = i2c_new_dummy(client->adapter, 0x1a);
+ if (dev->client[1] == NULL) {
+ ret = -ENODEV;
+ dev_err(&client->dev, "I2C registration failed\n");
+ if (ret)
+ goto err_regmap_0_regmap_exit;
+ }
+ dev->regmap[1] = regmap_init_i2c(dev->client[1], &regmap_config);
+ if (IS_ERR(dev->regmap[1])) {
+ ret = PTR_ERR(dev->regmap[1]);
+ goto err_client_1_i2c_unregister_device;
+ }
+ i2c_set_clientdata(dev->client[1], dev);
+
+ dev->client[2] = i2c_new_dummy(client->adapter, 0x1c);
+ if (dev->client[2] == NULL) {
+ ret = -ENODEV;
+ dev_err(&client->dev, "2nd I2C registration failed\n");
+ if (ret)
+ goto err_regmap_1_regmap_exit;
+ }
+ dev->regmap[2] = regmap_init_i2c(dev->client[2], &regmap_config);
+ if (IS_ERR(dev->regmap[2])) {
+ ret = PTR_ERR(dev->regmap[2]);
+ goto err_client_2_i2c_unregister_device;
+ }
+ i2c_set_clientdata(dev->client[2], dev);
+
+ /* create dvb_frontend */
+ memcpy(&dev->fe.ops, &mn88472_ops, sizeof(struct dvb_frontend_ops));
+ dev->fe.demodulator_priv = client;
+ *config->fe = &dev->fe;
+ i2c_set_clientdata(client, dev);
+
+ dev_info(&client->dev, "Panasonic MN88472 successfully attached\n");
+ return 0;
+
+err_client_2_i2c_unregister_device:
+ i2c_unregister_device(dev->client[2]);
+err_regmap_1_regmap_exit:
+ regmap_exit(dev->regmap[1]);
+err_client_1_i2c_unregister_device:
+ i2c_unregister_device(dev->client[1]);
+err_regmap_0_regmap_exit:
+ regmap_exit(dev->regmap[0]);
+err_kfree:
+ kfree(dev);
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88472_remove(struct i2c_client *client)
+{
+ struct mn88472_dev *dev = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+
+ regmap_exit(dev->regmap[2]);
+ i2c_unregister_device(dev->client[2]);
+
+ regmap_exit(dev->regmap[1]);
+ i2c_unregister_device(dev->client[1]);
+
+ regmap_exit(dev->regmap[0]);
+
+ kfree(dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id mn88472_id_table[] = {
+ {"mn88472", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mn88472_id_table);
+
+static struct i2c_driver mn88472_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mn88472",
+ },
+ .probe = mn88472_probe,
+ .remove = mn88472_remove,
+ .id_table = mn88472_id_table,
+};
+
+module_i2c_driver(mn88472_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Panasonic MN88472 DVB-T/T2/C demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(MN88472_FIRMWARE);
diff --git a/drivers/staging/media/mn88472/mn88472_priv.h b/drivers/staging/media/mn88472/mn88472_priv.h
new file mode 100644
index 0000000..1095949
--- /dev/null
+++ b/drivers/staging/media/mn88472/mn88472_priv.h
@@ -0,0 +1,36 @@
+/*
+ * Panasonic MN88472 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2013 Antti Palosaari <crope@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MN88472_PRIV_H
+#define MN88472_PRIV_H
+
+#include "dvb_frontend.h"
+#include "mn88472.h"
+#include <linux/firmware.h>
+#include <linux/regmap.h>
+
+#define MN88472_FIRMWARE "dvb-demod-mn88472-02.fw"
+
+struct mn88472_dev {
+ struct i2c_client *client[3];
+ struct regmap *regmap[3];
+ struct dvb_frontend fe;
+ u16 i2c_wr_max;
+ fe_delivery_system_t delivery_system;
+ bool warm; /* FW running */
+};
+
+#endif
diff --git a/drivers/staging/media/mn88473/Kconfig b/drivers/staging/media/mn88473/Kconfig
new file mode 100644
index 0000000..6c9ebf5
--- /dev/null
+++ b/drivers/staging/media/mn88473/Kconfig
@@ -0,0 +1,7 @@
+config DVB_MN88473
+ tristate "Panasonic MN88473"
+ depends on DVB_CORE && I2C
+ select REGMAP_I2C
+ default m if !MEDIA_SUBDRV_AUTOSELECT
+ help
+ Say Y when you want to support this frontend.
diff --git a/drivers/staging/media/mn88473/Makefile b/drivers/staging/media/mn88473/Makefile
new file mode 100644
index 0000000..fac5541
--- /dev/null
+++ b/drivers/staging/media/mn88473/Makefile
@@ -0,0 +1,5 @@
+obj-$(CONFIG_DVB_MN88473) += mn88473.o
+
+ccflags-y += -Idrivers/media/dvb-core/
+ccflags-y += -Idrivers/media/dvb-frontends/
+ccflags-y += -Idrivers/media/tuners/
diff --git a/drivers/staging/media/mn88473/TODO b/drivers/staging/media/mn88473/TODO
new file mode 100644
index 0000000..b90a14b
--- /dev/null
+++ b/drivers/staging/media/mn88473/TODO
@@ -0,0 +1,21 @@
+Driver general quality is not good enough for mainline. Also, other
+device drivers (USB-bridge, tuner) needed for Astrometa receiver in
+question could need some changes. However, if that driver is mainlined
+due to some other device than Astrometa, unrelated TODOs could be
+skipped. In that case rtl28xxu driver needs module parameter to prevent
+driver loading.
+
+Required TODOs:
+* missing lock flags
+* I2C errors
+* tuner sensitivity
+
+*Do not* send any patch fixing checkpatch.pl issues. Currently it passes
+checkpatch.pl tests. I don't want waste my time to review this kind of
+trivial stuff. *Do not* add missing register I/O error checks. Those are
+missing for the reason it is much easier to compare I2C data sniffs when
+there is less lines. Those error checks are about the last thing to be added.
+
+Patches should be submitted to:
+linux-media@vger.kernel.org and Antti Palosaari <crope@iki.fi>
+
diff --git a/drivers/staging/media/mn88473/mn88473.c b/drivers/staging/media/mn88473/mn88473.c
new file mode 100644
index 0000000..a333744
--- /dev/null
+++ b/drivers/staging/media/mn88473/mn88473.c
@@ -0,0 +1,464 @@
+/*
+ * Panasonic MN88473 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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 "mn88473_priv.h"
+
+static int mn88473_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *s)
+{
+ s->min_delay_ms = 1000;
+ return 0;
+}
+
+static int mn88473_set_frontend(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88473_dev *dev = i2c_get_clientdata(client);
+ struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+ int ret, i;
+ u32 if_frequency;
+ u8 delivery_system_val, if_val[3], bw_val[7];
+
+ dev_dbg(&client->dev,
+ "delivery_system=%u modulation=%u frequency=%u bandwidth_hz=%u symbol_rate=%u inversion=%d stream_id=%d\n",
+ c->delivery_system, c->modulation,
+ c->frequency, c->bandwidth_hz, c->symbol_rate,
+ c->inversion, c->stream_id);
+
+ if (!dev->warm) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ delivery_system_val = 0x02;
+ break;
+ case SYS_DVBT2:
+ delivery_system_val = 0x03;
+ break;
+ case SYS_DVBC_ANNEX_A:
+ delivery_system_val = 0x04;
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ switch (c->delivery_system) {
+ case SYS_DVBT:
+ case SYS_DVBT2:
+ if (c->bandwidth_hz <= 6000000) {
+ /* IF 3570000 Hz, BW 6000000 Hz */
+ memcpy(if_val, "\x24\x8e\x8a", 3);
+ memcpy(bw_val, "\xe9\x55\x55\x1c\x29\x1c\x29", 7);
+ } else if (c->bandwidth_hz <= 7000000) {
+ /* IF 4570000 Hz, BW 7000000 Hz */
+ memcpy(if_val, "\x2e\xcb\xfb", 3);
+ memcpy(bw_val, "\xc8\x00\x00\x17\x0a\x17\x0a", 7);
+ } else if (c->bandwidth_hz <= 8000000) {
+ /* IF 4570000 Hz, BW 8000000 Hz */
+ memcpy(if_val, "\x2e\xcb\xfb", 3);
+ memcpy(bw_val, "\xaf\x00\x00\x11\xec\x11\xec", 7);
+ } else {
+ ret = -EINVAL;
+ goto err;
+ }
+ break;
+ case SYS_DVBC_ANNEX_A:
+ /* IF 5070000 Hz, BW 8000000 Hz */
+ memcpy(if_val, "\x33\xea\xb3", 3);
+ memcpy(bw_val, "\xaf\x00\x00\x11\xec\x11\xec", 7);
+ break;
+ default:
+ ret = -EINVAL;
+ goto err;
+ }
+
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe);
+ if (ret)
+ goto err;
+ }
+
+ if (fe->ops.tuner_ops.get_if_frequency) {
+ ret = fe->ops.tuner_ops.get_if_frequency(fe, &if_frequency);
+ if (ret)
+ goto err;
+
+ dev_dbg(&client->dev, "get_if_frequency=%d\n", if_frequency);
+ } else {
+ if_frequency = 0;
+ }
+
+ switch (if_frequency) {
+ case 3570000:
+ case 4570000:
+ case 5070000:
+ break;
+ default:
+ dev_err(&client->dev, "IF frequency %d not supported\n",
+ if_frequency);
+ ret = -EINVAL;
+ goto err;
+ }
+
+ ret = regmap_write(dev->regmap[2], 0x05, 0x00);
+ ret = regmap_write(dev->regmap[2], 0xfb, 0x13);
+ ret = regmap_write(dev->regmap[2], 0xef, 0x13);
+ ret = regmap_write(dev->regmap[2], 0xf9, 0x13);
+ ret = regmap_write(dev->regmap[2], 0x00, 0x18);
+ ret = regmap_write(dev->regmap[2], 0x01, 0x01);
+ ret = regmap_write(dev->regmap[2], 0x02, 0x21);
+ ret = regmap_write(dev->regmap[2], 0x03, delivery_system_val);
+ ret = regmap_write(dev->regmap[2], 0x0b, 0x00);
+
+ for (i = 0; i < sizeof(if_val); i++) {
+ ret = regmap_write(dev->regmap[2], 0x10 + i, if_val[i]);
+ if (ret)
+ goto err;
+ }
+
+ for (i = 0; i < sizeof(bw_val); i++) {
+ ret = regmap_write(dev->regmap[2], 0x13 + i, bw_val[i]);
+ if (ret)
+ goto err;
+ }
+
+ ret = regmap_write(dev->regmap[2], 0x2d, 0x3b);
+ ret = regmap_write(dev->regmap[2], 0x2e, 0x00);
+ ret = regmap_write(dev->regmap[2], 0x56, 0x0d);
+ ret = regmap_write(dev->regmap[0], 0x01, 0xba);
+ ret = regmap_write(dev->regmap[0], 0x02, 0x13);
+ ret = regmap_write(dev->regmap[0], 0x03, 0x80);
+ ret = regmap_write(dev->regmap[0], 0x04, 0xba);
+ ret = regmap_write(dev->regmap[0], 0x05, 0x91);
+ ret = regmap_write(dev->regmap[0], 0x07, 0xe7);
+ ret = regmap_write(dev->regmap[0], 0x08, 0x28);
+ ret = regmap_write(dev->regmap[0], 0x0a, 0x1a);
+ ret = regmap_write(dev->regmap[0], 0x13, 0x1f);
+ ret = regmap_write(dev->regmap[0], 0x19, 0x03);
+ ret = regmap_write(dev->regmap[0], 0x1d, 0xb0);
+ ret = regmap_write(dev->regmap[0], 0x2a, 0x72);
+ ret = regmap_write(dev->regmap[0], 0x2d, 0x00);
+ ret = regmap_write(dev->regmap[0], 0x3c, 0x00);
+ ret = regmap_write(dev->regmap[0], 0x3f, 0xf8);
+ ret = regmap_write(dev->regmap[0], 0x40, 0xf4);
+ ret = regmap_write(dev->regmap[0], 0x41, 0x08);
+ ret = regmap_write(dev->regmap[0], 0xd2, 0x29);
+ ret = regmap_write(dev->regmap[0], 0xd4, 0x55);
+ ret = regmap_write(dev->regmap[1], 0x10, 0x10);
+ ret = regmap_write(dev->regmap[1], 0x11, 0xab);
+ ret = regmap_write(dev->regmap[1], 0x12, 0x0d);
+ ret = regmap_write(dev->regmap[1], 0x13, 0xae);
+ ret = regmap_write(dev->regmap[1], 0x14, 0x1d);
+ ret = regmap_write(dev->regmap[1], 0x15, 0x9d);
+ ret = regmap_write(dev->regmap[1], 0xbe, 0x08);
+ ret = regmap_write(dev->regmap[2], 0x09, 0x08);
+ ret = regmap_write(dev->regmap[2], 0x08, 0x1d);
+ ret = regmap_write(dev->regmap[0], 0xb2, 0x37);
+ ret = regmap_write(dev->regmap[0], 0xd7, 0x04);
+ ret = regmap_write(dev->regmap[2], 0x32, 0x80);
+ ret = regmap_write(dev->regmap[2], 0x36, 0x00);
+ ret = regmap_write(dev->regmap[2], 0xf8, 0x9f);
+ if (ret)
+ goto err;
+
+ dev->delivery_system = c->delivery_system;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88473_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88473_dev *dev = i2c_get_clientdata(client);
+ int ret;
+
+ *status = 0;
+
+ if (!dev->warm) {
+ ret = -EAGAIN;
+ goto err;
+ }
+
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88473_init(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88473_dev *dev = i2c_get_clientdata(client);
+ int ret, len, remaining;
+ const struct firmware *fw = NULL;
+ u8 *fw_file = MN88473_FIRMWARE;
+
+ dev_dbg(&client->dev, "\n");
+
+ if (dev->warm)
+ return 0;
+
+ /* request the firmware, this will block and timeout */
+ ret = request_firmware(&fw, fw_file, &client->dev);
+ if (ret) {
+ dev_err(&client->dev, "firmare file '%s' not found\n", fw_file);
+ goto err_request_firmware;
+ }
+
+ dev_info(&client->dev, "downloading firmware from file '%s'\n",
+ fw_file);
+
+ ret = regmap_write(dev->regmap[0], 0xf5, 0x03);
+ if (ret)
+ goto err;
+
+ for (remaining = fw->size; remaining > 0;
+ remaining -= (dev->i2c_wr_max - 1)) {
+ len = remaining;
+ if (len > (dev->i2c_wr_max - 1))
+ len = (dev->i2c_wr_max - 1);
+
+ ret = regmap_bulk_write(dev->regmap[0], 0xf6,
+ &fw->data[fw->size - remaining], len);
+ if (ret) {
+ dev_err(&client->dev, "firmware download failed=%d\n",
+ ret);
+ goto err;
+ }
+ }
+
+ ret = regmap_write(dev->regmap[0], 0xf5, 0x00);
+ if (ret)
+ goto err;
+
+ release_firmware(fw);
+ fw = NULL;
+
+ /* warm state */
+ dev->warm = true;
+
+ return 0;
+
+err:
+ release_firmware(fw);
+err_request_firmware:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88473_sleep(struct dvb_frontend *fe)
+{
+ struct i2c_client *client = fe->demodulator_priv;
+ struct mn88473_dev *dev = i2c_get_clientdata(client);
+ int ret;
+
+ dev_dbg(&client->dev, "\n");
+
+ ret = regmap_write(dev->regmap[2], 0x05, 0x3e);
+ if (ret)
+ goto err;
+
+ dev->delivery_system = SYS_UNDEFINED;
+
+ return 0;
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static struct dvb_frontend_ops mn88473_ops = {
+ .delsys = {SYS_DVBT, SYS_DVBT2, SYS_DVBC_ANNEX_AC},
+ .info = {
+ .name = "Panasonic MN88473",
+ .caps = FE_CAN_FEC_1_2 |
+ FE_CAN_FEC_2_3 |
+ FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 |
+ FE_CAN_FEC_7_8 |
+ FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO |
+ FE_CAN_MUTE_TS |
+ FE_CAN_2G_MODULATION |
+ FE_CAN_MULTISTREAM
+ },
+
+ .get_tune_settings = mn88473_get_tune_settings,
+
+ .init = mn88473_init,
+ .sleep = mn88473_sleep,
+
+ .set_frontend = mn88473_set_frontend,
+
+ .read_status = mn88473_read_status,
+};
+
+static int mn88473_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct mn88473_config *config = client->dev.platform_data;
+ struct mn88473_dev *dev;
+ int ret;
+ unsigned int utmp;
+ static const struct regmap_config regmap_config = {
+ .reg_bits = 8,
+ .val_bits = 8,
+ };
+
+ dev_dbg(&client->dev, "\n");
+
+ /* Caller really need to provide pointer for frontend we create. */
+ if (config->fe == NULL) {
+ dev_err(&client->dev, "frontend pointer not defined\n");
+ ret = -EINVAL;
+ goto err;
+ }
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ dev->i2c_wr_max = config->i2c_wr_max;
+ dev->client[0] = client;
+ dev->regmap[0] = regmap_init_i2c(dev->client[0], &regmap_config);
+ if (IS_ERR(dev->regmap[0])) {
+ ret = PTR_ERR(dev->regmap[0]);
+ goto err_kfree;
+ }
+
+ /* check demod answers to I2C */
+ ret = regmap_read(dev->regmap[0], 0x00, &utmp);
+ if (ret)
+ goto err_regmap_0_regmap_exit;
+
+ /*
+ * Chip has three I2C addresses for different register pages. Used
+ * addresses are 0x18, 0x1a and 0x1c. We register two dummy clients,
+ * 0x1a and 0x1c, in order to get own I2C client for each register page.
+ */
+ dev->client[1] = i2c_new_dummy(client->adapter, 0x1a);
+ if (dev->client[1] == NULL) {
+ ret = -ENODEV;
+ dev_err(&client->dev, "I2C registration failed\n");
+ if (ret)
+ goto err_regmap_0_regmap_exit;
+ }
+ dev->regmap[1] = regmap_init_i2c(dev->client[1], &regmap_config);
+ if (IS_ERR(dev->regmap[1])) {
+ ret = PTR_ERR(dev->regmap[1]);
+ goto err_client_1_i2c_unregister_device;
+ }
+ i2c_set_clientdata(dev->client[1], dev);
+
+ dev->client[2] = i2c_new_dummy(client->adapter, 0x1c);
+ if (dev->client[2] == NULL) {
+ ret = -ENODEV;
+ dev_err(&client->dev, "2nd I2C registration failed\n");
+ if (ret)
+ goto err_regmap_1_regmap_exit;
+ }
+ dev->regmap[2] = regmap_init_i2c(dev->client[2], &regmap_config);
+ if (IS_ERR(dev->regmap[2])) {
+ ret = PTR_ERR(dev->regmap[2]);
+ goto err_client_2_i2c_unregister_device;
+ }
+ i2c_set_clientdata(dev->client[2], dev);
+
+ /* create dvb_frontend */
+ memcpy(&dev->fe.ops, &mn88473_ops, sizeof(struct dvb_frontend_ops));
+ dev->fe.demodulator_priv = client;
+ *config->fe = &dev->fe;
+ i2c_set_clientdata(client, dev);
+
+ dev_info(&dev->client[0]->dev, "Panasonic MN88473 successfully attached\n");
+ return 0;
+
+err_client_2_i2c_unregister_device:
+ i2c_unregister_device(dev->client[2]);
+err_regmap_1_regmap_exit:
+ regmap_exit(dev->regmap[1]);
+err_client_1_i2c_unregister_device:
+ i2c_unregister_device(dev->client[1]);
+err_regmap_0_regmap_exit:
+ regmap_exit(dev->regmap[0]);
+err_kfree:
+ kfree(dev);
+err:
+ dev_dbg(&client->dev, "failed=%d\n", ret);
+ return ret;
+}
+
+static int mn88473_remove(struct i2c_client *client)
+{
+ struct mn88473_dev *dev = i2c_get_clientdata(client);
+
+ dev_dbg(&client->dev, "\n");
+
+ regmap_exit(dev->regmap[2]);
+ i2c_unregister_device(dev->client[2]);
+
+ regmap_exit(dev->regmap[1]);
+ i2c_unregister_device(dev->client[1]);
+
+ regmap_exit(dev->regmap[0]);
+
+ kfree(dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id mn88473_id_table[] = {
+ {"mn88473", 0},
+ {}
+};
+MODULE_DEVICE_TABLE(i2c, mn88473_id_table);
+
+static struct i2c_driver mn88473_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mn88473",
+ },
+ .probe = mn88473_probe,
+ .remove = mn88473_remove,
+ .id_table = mn88473_id_table,
+};
+
+module_i2c_driver(mn88473_driver);
+
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_DESCRIPTION("Panasonic MN88473 DVB-T/T2/C demodulator driver");
+MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(MN88473_FIRMWARE);
diff --git a/drivers/staging/media/mn88473/mn88473_priv.h b/drivers/staging/media/mn88473/mn88473_priv.h
new file mode 100644
index 0000000..78af112
--- /dev/null
+++ b/drivers/staging/media/mn88473/mn88473_priv.h
@@ -0,0 +1,36 @@
+/*
+ * Panasonic MN88473 DVB-T/T2/C demodulator driver
+ *
+ * Copyright (C) 2014 Antti Palosaari <crope@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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef MN88473_PRIV_H
+#define MN88473_PRIV_H
+
+#include "dvb_frontend.h"
+#include "mn88473.h"
+#include <linux/firmware.h>
+#include <linux/regmap.h>
+
+#define MN88473_FIRMWARE "dvb-demod-mn88473-01.fw"
+
+struct mn88473_dev {
+ struct i2c_client *client[3];
+ struct regmap *regmap[3];
+ struct dvb_frontend fe;
+ u16 i2c_wr_max;
+ fe_delivery_system_t delivery_system;
+ bool warm; /* FW running */
+};
+
+#endif
diff --git a/drivers/staging/media/omap24xx/Kconfig b/drivers/staging/media/omap24xx/Kconfig
deleted file mode 100644
index 82e569a..0000000
--- a/drivers/staging/media/omap24xx/Kconfig
+++ /dev/null
@@ -1,35 +0,0 @@
-config VIDEO_V4L2_INT_DEVICE
- tristate
-
-config VIDEO_OMAP2
- tristate "OMAP2 Camera Capture Interface driver (DEPRECATED)"
- depends on VIDEO_DEV && ARCH_OMAP2
- select VIDEOBUF_DMA_SG
- select VIDEO_V4L2_INT_DEVICE
- ---help---
- This is a v4l2 driver for the TI OMAP2 camera capture interface
-
- It uses the deprecated int-device API. Since this driver is no
- longer actively maintained and nobody is interested in converting
- it to the subdev API, this driver will be removed soon.
-
- If you do want to keep this driver in the kernel, and are willing
- to convert it to the subdev API, then please contact the linux-media
- mailinglist.
-
-config VIDEO_TCM825X
- tristate "TCM825x camera sensor support (DEPRECATED)"
- depends on I2C && VIDEO_V4L2
- depends on MEDIA_CAMERA_SUPPORT
- select VIDEO_V4L2_INT_DEVICE
- ---help---
- This is a driver for the Toshiba TCM825x VGA camera sensor.
- It is used for example in Nokia N800.
-
- It uses the deprecated int-device API. Since this driver is no
- longer actively maintained and nobody is interested in converting
- it to the subdev API, this driver will be removed soon.
-
- If you do want to keep this driver in the kernel, and are willing
- to convert it to the subdev API, then please contact the linux-media
- mailinglist.
diff --git a/drivers/staging/media/omap24xx/Makefile b/drivers/staging/media/omap24xx/Makefile
deleted file mode 100644
index c2e7175..0000000
--- a/drivers/staging/media/omap24xx/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
-
-obj-$(CONFIG_VIDEO_OMAP2) += omap2cam.o
-obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
-obj-$(CONFIG_VIDEO_V4L2_INT_DEVICE) += v4l2-int-device.o
diff --git a/drivers/staging/media/omap24xx/omap24xxcam-dma.c b/drivers/staging/media/omap24xx/omap24xxcam-dma.c
deleted file mode 100644
index c427eb9..0000000
--- a/drivers/staging/media/omap24xx/omap24xxcam-dma.c
+++ /dev/null
@@ -1,598 +0,0 @@
-/*
- * drivers/media/platform/omap24xxcam-dma.c
- *
- * Copyright (C) 2004 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from Andy Lowe <source@mvista.com> and
- * David Cohen <david.cohen@indt.org.br>.
- *
- * This program is free software; you can 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/kernel.h>
-#include <linux/io.h>
-#include <linux/scatterlist.h>
-
-#include "omap24xxcam.h"
-
-/*
- *
- * DMA hardware.
- *
- */
-
-/* Ack all interrupt on CSR and IRQSTATUS_L0 */
-static void omap24xxcam_dmahw_ack_all(void __iomem *base)
-{
- u32 csr;
- int i;
-
- for (i = 0; i < NUM_CAMDMA_CHANNELS; ++i) {
- csr = omap24xxcam_reg_in(base, CAMDMA_CSR(i));
- /* ack interrupt in CSR */
- omap24xxcam_reg_out(base, CAMDMA_CSR(i), csr);
- }
- omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, 0xf);
-}
-
-/* Ack dmach on CSR and IRQSTATUS_L0 */
-static u32 omap24xxcam_dmahw_ack_ch(void __iomem *base, int dmach)
-{
- u32 csr;
-
- csr = omap24xxcam_reg_in(base, CAMDMA_CSR(dmach));
- /* ack interrupt in CSR */
- omap24xxcam_reg_out(base, CAMDMA_CSR(dmach), csr);
- /* ack interrupt in IRQSTATUS */
- omap24xxcam_reg_out(base, CAMDMA_IRQSTATUS_L0, (1 << dmach));
-
- return csr;
-}
-
-static int omap24xxcam_dmahw_running(void __iomem *base, int dmach)
-{
- return omap24xxcam_reg_in(base, CAMDMA_CCR(dmach)) & CAMDMA_CCR_ENABLE;
-}
-
-static void omap24xxcam_dmahw_transfer_setup(void __iomem *base, int dmach,
- dma_addr_t start, u32 len)
-{
- omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
- CAMDMA_CCR_SEL_SRC_DST_SYNC
- | CAMDMA_CCR_BS
- | CAMDMA_CCR_DST_AMODE_POST_INC
- | CAMDMA_CCR_SRC_AMODE_POST_INC
- | CAMDMA_CCR_FS
- | CAMDMA_CCR_WR_ACTIVE
- | CAMDMA_CCR_RD_ACTIVE
- | CAMDMA_CCR_SYNCHRO_CAMERA);
- omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CEN(dmach), len);
- omap24xxcam_reg_out(base, CAMDMA_CFN(dmach), 1);
- omap24xxcam_reg_out(base, CAMDMA_CSDP(dmach),
- CAMDMA_CSDP_WRITE_MODE_POSTED
- | CAMDMA_CSDP_DST_BURST_EN_32
- | CAMDMA_CSDP_DST_PACKED
- | CAMDMA_CSDP_SRC_BURST_EN_32
- | CAMDMA_CSDP_SRC_PACKED
- | CAMDMA_CSDP_DATA_TYPE_8BITS);
- omap24xxcam_reg_out(base, CAMDMA_CSSA(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CDSA(dmach), start);
- omap24xxcam_reg_out(base, CAMDMA_CSEI(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CSFI(dmach), DMA_THRESHOLD);
- omap24xxcam_reg_out(base, CAMDMA_CDEI(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CDFI(dmach), 0);
- omap24xxcam_reg_out(base, CAMDMA_CSR(dmach),
- CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR
- | CAMDMA_CSR_BLOCK
- | CAMDMA_CSR_DROP);
- omap24xxcam_reg_out(base, CAMDMA_CICR(dmach),
- CAMDMA_CICR_MISALIGNED_ERR_IE
- | CAMDMA_CICR_SECURE_ERR_IE
- | CAMDMA_CICR_TRANS_ERR_IE
- | CAMDMA_CICR_BLOCK_IE
- | CAMDMA_CICR_DROP_IE);
-}
-
-static void omap24xxcam_dmahw_transfer_start(void __iomem *base, int dmach)
-{
- omap24xxcam_reg_out(base, CAMDMA_CCR(dmach),
- CAMDMA_CCR_SEL_SRC_DST_SYNC
- | CAMDMA_CCR_BS
- | CAMDMA_CCR_DST_AMODE_POST_INC
- | CAMDMA_CCR_SRC_AMODE_POST_INC
- | CAMDMA_CCR_ENABLE
- | CAMDMA_CCR_FS
- | CAMDMA_CCR_SYNCHRO_CAMERA);
-}
-
-static void omap24xxcam_dmahw_transfer_chain(void __iomem *base, int dmach,
- int free_dmach)
-{
- int prev_dmach, ch;
-
- if (dmach == 0)
- prev_dmach = NUM_CAMDMA_CHANNELS - 1;
- else
- prev_dmach = dmach - 1;
- omap24xxcam_reg_out(base, CAMDMA_CLNK_CTRL(prev_dmach),
- CAMDMA_CLNK_CTRL_ENABLE_LNK | dmach);
- /* Did we chain the DMA transfer before the previous one
- * finished?
- */
- ch = (dmach + free_dmach) % NUM_CAMDMA_CHANNELS;
- while (!(omap24xxcam_reg_in(base, CAMDMA_CCR(ch))
- & CAMDMA_CCR_ENABLE)) {
- if (ch == dmach) {
- /* The previous transfer has ended and this one
- * hasn't started, so we must not have chained
- * to the previous one in time. We'll have to
- * start it now.
- */
- omap24xxcam_dmahw_transfer_start(base, dmach);
- break;
- }
- ch = (ch + 1) % NUM_CAMDMA_CHANNELS;
- }
-}
-
-/* Abort all chained DMA transfers. After all transfers have been
- * aborted and the DMA controller is idle, the completion routines for
- * any aborted transfers will be called in sequence. The DMA
- * controller may not be idle after this routine completes, because
- * the completion routines might start new transfers.
- */
-static void omap24xxcam_dmahw_abort_ch(void __iomem *base, int dmach)
-{
- /* mask all interrupts from this channel */
- omap24xxcam_reg_out(base, CAMDMA_CICR(dmach), 0);
- /* unlink this channel */
- omap24xxcam_reg_merge(base, CAMDMA_CLNK_CTRL(dmach), 0,
- CAMDMA_CLNK_CTRL_ENABLE_LNK);
- /* disable this channel */
- omap24xxcam_reg_merge(base, CAMDMA_CCR(dmach), 0, CAMDMA_CCR_ENABLE);
-}
-
-static void omap24xxcam_dmahw_init(void __iomem *base)
-{
- omap24xxcam_reg_out(base, CAMDMA_OCP_SYSCONFIG,
- CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY
- | CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE
- | CAMDMA_OCP_SYSCONFIG_AUTOIDLE);
-
- omap24xxcam_reg_merge(base, CAMDMA_GCR, 0x10,
- CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH);
-
- omap24xxcam_reg_out(base, CAMDMA_IRQENABLE_L0, 0xf);
-}
-
-/*
- *
- * Individual DMA channel handling.
- *
- */
-
-/* Start a DMA transfer from the camera to memory.
- * Returns zero if the transfer was successfully started, or non-zero if all
- * DMA channels are already in use or starting is currently inhibited.
- */
-static int omap24xxcam_dma_start(struct omap24xxcam_dma *dma, dma_addr_t start,
- u32 len, dma_callback_t callback, void *arg)
-{
- unsigned long flags;
- int dmach;
-
- spin_lock_irqsave(&dma->lock, flags);
-
- if (!dma->free_dmach || atomic_read(&dma->dma_stop)) {
- spin_unlock_irqrestore(&dma->lock, flags);
- return -EBUSY;
- }
-
- dmach = dma->next_dmach;
-
- dma->ch_state[dmach].callback = callback;
- dma->ch_state[dmach].arg = arg;
-
- omap24xxcam_dmahw_transfer_setup(dma->base, dmach, start, len);
-
- /* We're ready to start the DMA transfer. */
-
- if (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
- /* A transfer is already in progress, so try to chain to it. */
- omap24xxcam_dmahw_transfer_chain(dma->base, dmach,
- dma->free_dmach);
- } else {
- /* No transfer is in progress, so we'll just start this one
- * now.
- */
- omap24xxcam_dmahw_transfer_start(dma->base, dmach);
- }
-
- dma->next_dmach = (dma->next_dmach + 1) % NUM_CAMDMA_CHANNELS;
- dma->free_dmach--;
-
- spin_unlock_irqrestore(&dma->lock, flags);
-
- return 0;
-}
-
-/* Abort all chained DMA transfers. After all transfers have been
- * aborted and the DMA controller is idle, the completion routines for
- * any aborted transfers will be called in sequence. The DMA
- * controller may not be idle after this routine completes, because
- * the completion routines might start new transfers.
- */
-static void omap24xxcam_dma_abort(struct omap24xxcam_dma *dma, u32 csr)
-{
- unsigned long flags;
- int dmach, i, free_dmach;
- dma_callback_t callback;
- void *arg;
-
- spin_lock_irqsave(&dma->lock, flags);
-
- /* stop any DMA transfers in progress */
- dmach = (dma->next_dmach + dma->free_dmach) % NUM_CAMDMA_CHANNELS;
- for (i = 0; i < NUM_CAMDMA_CHANNELS; i++) {
- omap24xxcam_dmahw_abort_ch(dma->base, dmach);
- dmach = (dmach + 1) % NUM_CAMDMA_CHANNELS;
- }
-
- /* We have to be careful here because the callback routine
- * might start a new DMA transfer, and we only want to abort
- * transfers that were started before this routine was called.
- */
- free_dmach = dma->free_dmach;
- while ((dma->free_dmach < NUM_CAMDMA_CHANNELS) &&
- (free_dmach < NUM_CAMDMA_CHANNELS)) {
- dmach = (dma->next_dmach + dma->free_dmach)
- % NUM_CAMDMA_CHANNELS;
- callback = dma->ch_state[dmach].callback;
- arg = dma->ch_state[dmach].arg;
- dma->free_dmach++;
- free_dmach++;
- if (callback) {
- /* leave interrupts disabled during callback */
- spin_unlock(&dma->lock);
- (*callback) (dma, csr, arg);
- spin_lock(&dma->lock);
- }
- }
-
- spin_unlock_irqrestore(&dma->lock, flags);
-}
-
-/* Abort all chained DMA transfers. After all transfers have been
- * aborted and the DMA controller is idle, the completion routines for
- * any aborted transfers will be called in sequence. If the completion
- * routines attempt to start a new DMA transfer it will fail, so the
- * DMA controller will be idle after this routine completes.
- */
-static void omap24xxcam_dma_stop(struct omap24xxcam_dma *dma, u32 csr)
-{
- atomic_inc(&dma->dma_stop);
- omap24xxcam_dma_abort(dma, csr);
- atomic_dec(&dma->dma_stop);
-}
-
-/* Camera DMA interrupt service routine. */
-void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma)
-{
- int dmach;
- dma_callback_t callback;
- void *arg;
- u32 csr;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
-
- spin_lock(&dma->lock);
-
- if (dma->free_dmach == NUM_CAMDMA_CHANNELS) {
- /* A camera DMA interrupt occurred while all channels
- * are idle, so we'll acknowledge the interrupt in the
- * IRQSTATUS register and exit.
- */
- omap24xxcam_dmahw_ack_all(dma->base);
- spin_unlock(&dma->lock);
- return;
- }
-
- while (dma->free_dmach < NUM_CAMDMA_CHANNELS) {
- dmach = (dma->next_dmach + dma->free_dmach)
- % NUM_CAMDMA_CHANNELS;
- if (omap24xxcam_dmahw_running(dma->base, dmach)) {
- /* This buffer hasn't finished yet, so we're done. */
- break;
- }
- csr = omap24xxcam_dmahw_ack_ch(dma->base, dmach);
- if (csr & csr_error) {
- /* A DMA error occurred, so stop all DMA
- * transfers in progress.
- */
- spin_unlock(&dma->lock);
- omap24xxcam_dma_stop(dma, csr);
- return;
- }
- callback = dma->ch_state[dmach].callback;
- arg = dma->ch_state[dmach].arg;
- dma->free_dmach++;
- if (callback) {
- spin_unlock(&dma->lock);
- (*callback) (dma, csr, arg);
- spin_lock(&dma->lock);
- }
- }
-
- spin_unlock(&dma->lock);
-
- omap24xxcam_sgdma_process(
- container_of(dma, struct omap24xxcam_sgdma, dma));
-}
-
-void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&dma->lock, flags);
-
- omap24xxcam_dmahw_init(dma->base);
-
- spin_unlock_irqrestore(&dma->lock, flags);
-}
-
-static void omap24xxcam_dma_init(struct omap24xxcam_dma *dma,
- void __iomem *base)
-{
- int ch;
-
- /* group all channels on DMA IRQ0 and unmask irq */
- spin_lock_init(&dma->lock);
- dma->base = base;
- dma->free_dmach = NUM_CAMDMA_CHANNELS;
- dma->next_dmach = 0;
- for (ch = 0; ch < NUM_CAMDMA_CHANNELS; ch++) {
- dma->ch_state[ch].callback = NULL;
- dma->ch_state[ch].arg = NULL;
- }
-}
-
-/*
- *
- * Scatter-gather DMA.
- *
- * High-level DMA construct for transferring whole picture frames to
- * memory that is discontinuous.
- *
- */
-
-/* DMA completion routine for the scatter-gather DMA fragments. */
-static void omap24xxcam_sgdma_callback(struct omap24xxcam_dma *dma, u32 csr,
- void *arg)
-{
- struct omap24xxcam_sgdma *sgdma =
- container_of(dma, struct omap24xxcam_sgdma, dma);
- int sgslot = (int)arg;
- struct sgdma_state *sg_state;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
-
- spin_lock(&sgdma->lock);
-
- /* We got an interrupt, we can remove the timer */
- del_timer(&sgdma->reset_timer);
-
- sg_state = sgdma->sg_state + sgslot;
- if (!sg_state->queued_sglist) {
- spin_unlock(&sgdma->lock);
- printk(KERN_ERR "%s: sgdma completed when none queued!\n",
- __func__);
- return;
- }
-
- sg_state->csr |= csr;
- if (!--sg_state->queued_sglist) {
- /* Queue for this sglist is empty, so check to see if we're
- * done.
- */
- if ((sg_state->next_sglist == sg_state->sglen)
- || (sg_state->csr & csr_error)) {
- sgdma_callback_t callback = sg_state->callback;
- void *arg = sg_state->arg;
- u32 sg_csr = sg_state->csr;
- /* All done with this sglist */
- sgdma->free_sgdma++;
- if (callback) {
- spin_unlock(&sgdma->lock);
- (*callback) (sgdma, sg_csr, arg);
- return;
- }
- }
- }
-
- spin_unlock(&sgdma->lock);
-}
-
-/* Start queued scatter-gather DMA transfers. */
-void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma)
-{
- unsigned long flags;
- int queued_sgdma, sgslot;
- struct sgdma_state *sg_state;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
-
- spin_lock_irqsave(&sgdma->lock, flags);
-
- queued_sgdma = NUM_SG_DMA - sgdma->free_sgdma;
- sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
- while (queued_sgdma > 0) {
- sg_state = sgdma->sg_state + sgslot;
- while ((sg_state->next_sglist < sg_state->sglen) &&
- !(sg_state->csr & csr_error)) {
- const struct scatterlist *sglist;
- unsigned int len;
-
- sglist = sg_state->sglist + sg_state->next_sglist;
- /* try to start the next DMA transfer */
- if (sg_state->next_sglist + 1 == sg_state->sglen) {
- /*
- * On the last sg, we handle the case where
- * cam->img.pix.sizeimage % PAGE_ALIGN != 0
- */
- len = sg_state->len - sg_state->bytes_read;
- } else {
- len = sg_dma_len(sglist);
- }
-
- if (omap24xxcam_dma_start(&sgdma->dma,
- sg_dma_address(sglist),
- len,
- omap24xxcam_sgdma_callback,
- (void *)sgslot)) {
- /* DMA start failed */
- spin_unlock_irqrestore(&sgdma->lock, flags);
- return;
- }
- /* DMA start was successful */
- sg_state->next_sglist++;
- sg_state->bytes_read += len;
- sg_state->queued_sglist++;
-
- /* We start the reset timer */
- mod_timer(&sgdma->reset_timer, jiffies + HZ);
- }
- queued_sgdma--;
- sgslot = (sgslot + 1) % NUM_SG_DMA;
- }
-
- spin_unlock_irqrestore(&sgdma->lock, flags);
-}
-
-/*
- * Queue a scatter-gather DMA transfer from the camera to memory.
- * Returns zero if the transfer was successfully queued, or non-zero
- * if all of the scatter-gather slots are already in use.
- */
-int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
- const struct scatterlist *sglist, int sglen,
- int len, sgdma_callback_t callback, void *arg)
-{
- unsigned long flags;
- struct sgdma_state *sg_state;
-
- if ((sglen < 0) || ((sglen > 0) && !sglist))
- return -EINVAL;
-
- spin_lock_irqsave(&sgdma->lock, flags);
-
- if (!sgdma->free_sgdma) {
- spin_unlock_irqrestore(&sgdma->lock, flags);
- return -EBUSY;
- }
-
- sg_state = sgdma->sg_state + sgdma->next_sgdma;
-
- sg_state->sglist = sglist;
- sg_state->sglen = sglen;
- sg_state->next_sglist = 0;
- sg_state->bytes_read = 0;
- sg_state->len = len;
- sg_state->queued_sglist = 0;
- sg_state->csr = 0;
- sg_state->callback = callback;
- sg_state->arg = arg;
-
- sgdma->next_sgdma = (sgdma->next_sgdma + 1) % NUM_SG_DMA;
- sgdma->free_sgdma--;
-
- spin_unlock_irqrestore(&sgdma->lock, flags);
-
- omap24xxcam_sgdma_process(sgdma);
-
- return 0;
-}
-
-/* Sync scatter-gather DMA by aborting any DMA transfers currently in progress.
- * Any queued scatter-gather DMA transactions that have not yet been started
- * will remain queued. The DMA controller will be idle after this routine
- * completes. When the scatter-gather queue is restarted, the next
- * scatter-gather DMA transfer will begin at the start of a new transaction.
- */
-void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma)
-{
- unsigned long flags;
- int sgslot;
- struct sgdma_state *sg_state;
- u32 csr = CAMDMA_CSR_TRANS_ERR;
-
- /* stop any DMA transfers in progress */
- omap24xxcam_dma_stop(&sgdma->dma, csr);
-
- spin_lock_irqsave(&sgdma->lock, flags);
-
- if (sgdma->free_sgdma < NUM_SG_DMA) {
- sgslot = (sgdma->next_sgdma + sgdma->free_sgdma) % NUM_SG_DMA;
- sg_state = sgdma->sg_state + sgslot;
- if (sg_state->next_sglist != 0) {
- /* This DMA transfer was in progress, so abort it. */
- sgdma_callback_t callback = sg_state->callback;
- void *arg = sg_state->arg;
-
- sgdma->free_sgdma++;
- if (callback) {
- /* leave interrupts masked */
- spin_unlock(&sgdma->lock);
- (*callback) (sgdma, csr, arg);
- spin_lock(&sgdma->lock);
- }
- }
- }
-
- spin_unlock_irqrestore(&sgdma->lock, flags);
-}
-
-void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
- void __iomem *base,
- void (*reset_callback)(unsigned long data),
- unsigned long reset_callback_data)
-{
- int sg;
-
- spin_lock_init(&sgdma->lock);
- sgdma->free_sgdma = NUM_SG_DMA;
- sgdma->next_sgdma = 0;
- for (sg = 0; sg < NUM_SG_DMA; sg++) {
- sgdma->sg_state[sg].sglen = 0;
- sgdma->sg_state[sg].next_sglist = 0;
- sgdma->sg_state[sg].bytes_read = 0;
- sgdma->sg_state[sg].queued_sglist = 0;
- sgdma->sg_state[sg].csr = 0;
- sgdma->sg_state[sg].callback = NULL;
- sgdma->sg_state[sg].arg = NULL;
- }
-
- omap24xxcam_dma_init(&sgdma->dma, base);
- setup_timer(&sgdma->reset_timer, reset_callback, reset_callback_data);
-}
diff --git a/drivers/staging/media/omap24xx/omap24xxcam.c b/drivers/staging/media/omap24xx/omap24xxcam.c
deleted file mode 100644
index d590b3e..0000000
--- a/drivers/staging/media/omap24xx/omap24xxcam.c
+++ /dev/null
@@ -1,1882 +0,0 @@
-/*
- * drivers/media/platform/omap24xxcam.c
- *
- * OMAP 2 camera block driver.
- *
- * Copyright (C) 2004 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- * Copyright (C) 2007-2008 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from Andy Lowe <source@mvista.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/interrupt.h>
-#include <linux/videodev2.h>
-#include <linux/pci.h> /* needed for videobufs */
-#include <linux/platform_device.h>
-#include <linux/clk.h>
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <linux/sched.h>
-#include <linux/module.h>
-
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "omap24xxcam.h"
-
-#define OMAP24XXCAM_VERSION "0.0.1"
-
-#define RESET_TIMEOUT_NS 10000
-
-static void omap24xxcam_reset(struct omap24xxcam_device *cam);
-static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam);
-static void omap24xxcam_device_unregister(struct v4l2_int_device *s);
-static int omap24xxcam_remove(struct platform_device *pdev);
-
-/* module parameters */
-static int video_nr = -1; /* video device minor (-1 ==> auto assign) */
-/*
- * Maximum amount of memory to use for capture buffers.
- * Default is 4800KB, enough to double-buffer SXGA.
- */
-static int capture_mem = 1280 * 960 * 2 * 2;
-
-static struct v4l2_int_device omap24xxcam;
-
-/*
- *
- * Clocks.
- *
- */
-
-static void omap24xxcam_clock_put(struct omap24xxcam_device *cam)
-{
- if (cam->ick != NULL && !IS_ERR(cam->ick))
- clk_put(cam->ick);
- if (cam->fck != NULL && !IS_ERR(cam->fck))
- clk_put(cam->fck);
-
- cam->ick = cam->fck = NULL;
-}
-
-static int omap24xxcam_clock_get(struct omap24xxcam_device *cam)
-{
- int rval = 0;
-
- cam->fck = clk_get(cam->dev, "fck");
- if (IS_ERR(cam->fck)) {
- dev_err(cam->dev, "can't get camera fck");
- rval = PTR_ERR(cam->fck);
- omap24xxcam_clock_put(cam);
- return rval;
- }
-
- cam->ick = clk_get(cam->dev, "ick");
- if (IS_ERR(cam->ick)) {
- dev_err(cam->dev, "can't get camera ick");
- rval = PTR_ERR(cam->ick);
- omap24xxcam_clock_put(cam);
- }
-
- return rval;
-}
-
-static void omap24xxcam_clock_on(struct omap24xxcam_device *cam)
-{
- clk_enable(cam->fck);
- clk_enable(cam->ick);
-}
-
-static void omap24xxcam_clock_off(struct omap24xxcam_device *cam)
-{
- clk_disable(cam->fck);
- clk_disable(cam->ick);
-}
-
-/*
- *
- * Camera core
- *
- */
-
-/*
- * Set xclk.
- *
- * To disable xclk, use value zero.
- */
-static void omap24xxcam_core_xclk_set(const struct omap24xxcam_device *cam,
- u32 xclk)
-{
- if (xclk) {
- u32 divisor = CAM_MCLK / xclk;
-
- if (divisor == 1)
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
- CC_CTRL_XCLK,
- CC_CTRL_XCLK_DIV_BYPASS);
- else
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
- CC_CTRL_XCLK, divisor);
- } else
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET,
- CC_CTRL_XCLK, CC_CTRL_XCLK_DIV_STABLE_LOW);
-}
-
-static void omap24xxcam_core_hwinit(const struct omap24xxcam_device *cam)
-{
- /*
- * Setting the camera core AUTOIDLE bit causes problems with frame
- * synchronization, so we will clear the AUTOIDLE bit instead.
- */
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_SYSCONFIG,
- CC_SYSCONFIG_AUTOIDLE);
-
- /* program the camera interface DMA packet size */
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL_DMA,
- CC_CTRL_DMA_EN | (DMA_THRESHOLD / 4 - 1));
-
- /* enable camera core error interrupts */
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQENABLE,
- CC_IRQENABLE_FW_ERR_IRQ
- | CC_IRQENABLE_FSC_ERR_IRQ
- | CC_IRQENABLE_SSC_ERR_IRQ
- | CC_IRQENABLE_FIFO_OF_IRQ);
-}
-
-/*
- * Enable the camera core.
- *
- * Data transfer to the camera DMA starts from next starting frame.
- */
-static void omap24xxcam_core_enable(const struct omap24xxcam_device *cam)
-{
-
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
- cam->cc_ctrl);
-}
-
-/*
- * Disable camera core.
- *
- * The data transfer will be stopped immediately (CC_CTRL_CC_RST). The
- * core internal state machines will be reset. Use
- * CC_CTRL_CC_FRAME_TRIG instead if you want to transfer the current
- * frame completely.
- */
-static void omap24xxcam_core_disable(const struct omap24xxcam_device *cam)
-{
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_CTRL,
- CC_CTRL_CC_RST);
-}
-
-/* Interrupt service routine for camera core interrupts. */
-static void omap24xxcam_core_isr(struct omap24xxcam_device *cam)
-{
- u32 cc_irqstatus;
- const u32 cc_irqstatus_err =
- CC_IRQSTATUS_FW_ERR_IRQ
- | CC_IRQSTATUS_FSC_ERR_IRQ
- | CC_IRQSTATUS_SSC_ERR_IRQ
- | CC_IRQSTATUS_FIFO_UF_IRQ
- | CC_IRQSTATUS_FIFO_OF_IRQ;
-
- cc_irqstatus = omap24xxcam_reg_in(cam->mmio_base + CC_REG_OFFSET,
- CC_IRQSTATUS);
- omap24xxcam_reg_out(cam->mmio_base + CC_REG_OFFSET, CC_IRQSTATUS,
- cc_irqstatus);
-
- if (cc_irqstatus & cc_irqstatus_err
- && !atomic_read(&cam->in_reset)) {
- dev_dbg(cam->dev, "resetting camera, cc_irqstatus 0x%x\n",
- cc_irqstatus);
- omap24xxcam_reset(cam);
- }
-}
-
-/*
- *
- * videobuf_buffer handling.
- *
- * Memory for mmapped videobuf_buffers is not allocated
- * conventionally, but by several kmalloc allocations and then
- * creating the scatterlist on our own. User-space buffers are handled
- * normally.
- *
- */
-
-/*
- * Free the memory-mapped buffer memory allocated for a
- * videobuf_buffer and the associated scatterlist.
- */
-static void omap24xxcam_vbq_free_mmap_buffer(struct videobuf_buffer *vb)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
- size_t alloc_size;
- struct page *page;
- int i;
-
- if (dma->sglist == NULL)
- return;
-
- i = dma->sglen;
- while (i) {
- i--;
- alloc_size = sg_dma_len(&dma->sglist[i]);
- page = sg_page(&dma->sglist[i]);
- do {
- ClearPageReserved(page++);
- } while (alloc_size -= PAGE_SIZE);
- __free_pages(sg_page(&dma->sglist[i]),
- get_order(sg_dma_len(&dma->sglist[i])));
- }
-
- kfree(dma->sglist);
- dma->sglist = NULL;
-}
-
-/* Release all memory related to the videobuf_queue. */
-static void omap24xxcam_vbq_free_mmap_buffers(struct videobuf_queue *vbq)
-{
- int i;
-
- mutex_lock(&vbq->vb_lock);
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == vbq->bufs[i])
- continue;
- if (V4L2_MEMORY_MMAP != vbq->bufs[i]->memory)
- continue;
- vbq->ops->buf_release(vbq, vbq->bufs[i]);
- omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
- kfree(vbq->bufs[i]);
- vbq->bufs[i] = NULL;
- }
-
- mutex_unlock(&vbq->vb_lock);
-
- videobuf_mmap_free(vbq);
-}
-
-/*
- * Allocate physically as contiguous as possible buffer for video
- * frame and allocate and build DMA scatter-gather list for it.
- */
-static int omap24xxcam_vbq_alloc_mmap_buffer(struct videobuf_buffer *vb)
-{
- unsigned int order;
- size_t alloc_size, size = vb->bsize; /* vb->bsize is page aligned */
- struct page *page;
- int max_pages, err = 0, i = 0;
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- /*
- * allocate maximum size scatter-gather list. Note this is
- * overhead. We may not use as many entries as we allocate
- */
- max_pages = vb->bsize >> PAGE_SHIFT;
- dma->sglist = kcalloc(max_pages, sizeof(*dma->sglist), GFP_KERNEL);
- if (dma->sglist == NULL) {
- err = -ENOMEM;
- goto out;
- }
-
- while (size) {
- order = get_order(size);
- /*
- * do not over-allocate even if we would get larger
- * contiguous chunk that way
- */
- if ((PAGE_SIZE << order) > size)
- order--;
-
- /* try to allocate as many contiguous pages as possible */
- page = alloc_pages(GFP_KERNEL, order);
- /* if allocation fails, try to allocate smaller amount */
- while (page == NULL) {
- order--;
- page = alloc_pages(GFP_KERNEL, order);
- if (page == NULL && !order) {
- err = -ENOMEM;
- goto out;
- }
- }
- size -= (PAGE_SIZE << order);
-
- /* append allocated chunk of pages into scatter-gather list */
- sg_set_page(&dma->sglist[i], page, PAGE_SIZE << order, 0);
- dma->sglen++;
- i++;
-
- alloc_size = (PAGE_SIZE << order);
-
- /* clear pages before giving them to user space */
- memset(page_address(page), 0, alloc_size);
-
- /* mark allocated pages reserved */
- do {
- SetPageReserved(page++);
- } while (alloc_size -= PAGE_SIZE);
- }
- /*
- * REVISIT: not fully correct to assign nr_pages == sglen but
- * video-buf is passing nr_pages for e.g. unmap_sg calls
- */
- dma->nr_pages = dma->sglen;
- dma->direction = PCI_DMA_FROMDEVICE;
-
- return 0;
-
-out:
- omap24xxcam_vbq_free_mmap_buffer(vb);
- return err;
-}
-
-static int omap24xxcam_vbq_alloc_mmap_buffers(struct videobuf_queue *vbq,
- unsigned int count)
-{
- int i, err = 0;
- struct omap24xxcam_fh *fh =
- container_of(vbq, struct omap24xxcam_fh, vbq);
-
- mutex_lock(&vbq->vb_lock);
-
- for (i = 0; i < count; i++) {
- err = omap24xxcam_vbq_alloc_mmap_buffer(vbq->bufs[i]);
- if (err)
- goto out;
- dev_dbg(fh->cam->dev, "sglen is %d for buffer %d\n",
- videobuf_to_dma(vbq->bufs[i])->sglen, i);
- }
-
- mutex_unlock(&vbq->vb_lock);
-
- return 0;
-out:
- while (i) {
- i--;
- omap24xxcam_vbq_free_mmap_buffer(vbq->bufs[i]);
- }
-
- mutex_unlock(&vbq->vb_lock);
-
- return err;
-}
-
-/*
- * This routine is called from interrupt context when a scatter-gather DMA
- * transfer of a videobuf_buffer completes.
- */
-static void omap24xxcam_vbq_complete(struct omap24xxcam_sgdma *sgdma,
- u32 csr, void *arg)
-{
- struct omap24xxcam_device *cam =
- container_of(sgdma, struct omap24xxcam_device, sgdma);
- struct omap24xxcam_fh *fh = cam->streaming->private_data;
- struct videobuf_buffer *vb = (struct videobuf_buffer *)arg;
- const u32 csr_error = CAMDMA_CSR_MISALIGNED_ERR
- | CAMDMA_CSR_SUPERVISOR_ERR | CAMDMA_CSR_SECURE_ERR
- | CAMDMA_CSR_TRANS_ERR | CAMDMA_CSR_DROP;
- unsigned long flags;
-
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
- if (--cam->sgdma_in_queue == 0)
- omap24xxcam_core_disable(cam);
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
-
- v4l2_get_timestamp(&vb->ts);
- vb->field_count = atomic_add_return(2, &fh->field_count);
- if (csr & csr_error) {
- vb->state = VIDEOBUF_ERROR;
- if (!atomic_read(&fh->cam->in_reset)) {
- dev_dbg(cam->dev, "resetting camera, csr 0x%x\n", csr);
- omap24xxcam_reset(cam);
- }
- } else
- vb->state = VIDEOBUF_DONE;
- wake_up(&vb->done);
-}
-
-static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
- struct videobuf_buffer *vb)
-{
- struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
-
- /* wait for buffer, especially to get out of the sgdma queue */
- videobuf_waiton(vbq, vb, 0, 0);
- if (vb->memory == V4L2_MEMORY_MMAP) {
- dma_unmap_sg(vbq->dev, dma->sglist, dma->sglen,
- dma->direction);
- dma->direction = DMA_NONE;
- } else {
- videobuf_dma_unmap(vbq->dev, videobuf_to_dma(vb));
- videobuf_dma_free(videobuf_to_dma(vb));
- }
-
- vb->state = VIDEOBUF_NEEDS_INIT;
-}
-
-/*
- * Limit the number of available kernel image capture buffers based on the
- * number requested, the currently selected image size, and the maximum
- * amount of memory permitted for kernel capture buffers.
- */
-static int omap24xxcam_vbq_setup(struct videobuf_queue *vbq, unsigned int *cnt,
- unsigned int *size)
-{
- struct omap24xxcam_fh *fh = vbq->priv_data;
-
- if (*cnt <= 0)
- *cnt = VIDEO_MAX_FRAME; /* supply a default number of buffers */
-
- if (*cnt > VIDEO_MAX_FRAME)
- *cnt = VIDEO_MAX_FRAME;
-
- *size = fh->pix.sizeimage;
-
- /* accessing fh->cam->capture_mem is ok, it's constant */
- if (*size * *cnt > fh->cam->capture_mem)
- *cnt = fh->cam->capture_mem / *size;
-
- return 0;
-}
-
-static int omap24xxcam_dma_iolock(struct videobuf_queue *vbq,
- struct videobuf_dmabuf *dma)
-{
- int err = 0;
-
- dma->direction = PCI_DMA_FROMDEVICE;
- if (!dma_map_sg(vbq->dev, dma->sglist, dma->sglen, dma->direction)) {
- kfree(dma->sglist);
- dma->sglist = NULL;
- dma->sglen = 0;
- err = -EIO;
- }
-
- return err;
-}
-
-static int omap24xxcam_vbq_prepare(struct videobuf_queue *vbq,
- struct videobuf_buffer *vb,
- enum v4l2_field field)
-{
- struct omap24xxcam_fh *fh = vbq->priv_data;
- int err = 0;
-
- /*
- * Accessing pix here is okay since it's constant while
- * streaming is on (and we only get called then).
- */
- if (vb->baddr) {
- /* This is a userspace buffer. */
- if (fh->pix.sizeimage > vb->bsize) {
- /* The buffer isn't big enough. */
- err = -EINVAL;
- } else
- vb->size = fh->pix.sizeimage;
- } else {
- if (vb->state != VIDEOBUF_NEEDS_INIT) {
- /*
- * We have a kernel bounce buffer that has
- * already been allocated.
- */
- if (fh->pix.sizeimage > vb->size) {
- /*
- * The image size has been changed to
- * a larger size since this buffer was
- * allocated, so we need to free and
- * reallocate it.
- */
- omap24xxcam_vbq_release(vbq, vb);
- vb->size = fh->pix.sizeimage;
- }
- } else {
- /* We need to allocate a new kernel bounce buffer. */
- vb->size = fh->pix.sizeimage;
- }
- }
-
- if (err)
- return err;
-
- vb->width = fh->pix.width;
- vb->height = fh->pix.height;
- vb->field = field;
-
- if (vb->state == VIDEOBUF_NEEDS_INIT) {
- if (vb->memory == V4L2_MEMORY_MMAP)
- /*
- * we have built the scatter-gather list by ourself so
- * do the scatter-gather mapping as well
- */
- err = omap24xxcam_dma_iolock(vbq, videobuf_to_dma(vb));
- else
- err = videobuf_iolock(vbq, vb, NULL);
- }
-
- if (!err)
- vb->state = VIDEOBUF_PREPARED;
- else
- omap24xxcam_vbq_release(vbq, vb);
-
- return err;
-}
-
-static void omap24xxcam_vbq_queue(struct videobuf_queue *vbq,
- struct videobuf_buffer *vb)
-{
- struct omap24xxcam_fh *fh = vbq->priv_data;
- struct omap24xxcam_device *cam = fh->cam;
- enum videobuf_state state = vb->state;
- unsigned long flags;
- int err;
-
- /*
- * FIXME: We're marking the buffer active since we have no
- * pretty way of marking it active exactly when the
- * scatter-gather transfer starts.
- */
- vb->state = VIDEOBUF_ACTIVE;
-
- err = omap24xxcam_sgdma_queue(&fh->cam->sgdma,
- videobuf_to_dma(vb)->sglist,
- videobuf_to_dma(vb)->sglen, vb->size,
- omap24xxcam_vbq_complete, vb);
-
- if (!err) {
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
- if (++cam->sgdma_in_queue == 1
- && !atomic_read(&cam->in_reset))
- omap24xxcam_core_enable(cam);
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
- } else {
- /*
- * Oops. We're not supposed to get any errors here.
- * The only way we could get an error is if we ran out
- * of scatter-gather DMA slots, but we are supposed to
- * have at least as many scatter-gather DMA slots as
- * video buffers so that can't happen.
- */
- dev_err(cam->dev, "failed to queue a video buffer for dma!\n");
- dev_err(cam->dev, "likely a bug in the driver!\n");
- vb->state = state;
- }
-}
-
-static struct videobuf_queue_ops omap24xxcam_vbq_ops = {
- .buf_setup = omap24xxcam_vbq_setup,
- .buf_prepare = omap24xxcam_vbq_prepare,
- .buf_queue = omap24xxcam_vbq_queue,
- .buf_release = omap24xxcam_vbq_release,
-};
-
-/*
- *
- * OMAP main camera system
- *
- */
-
-/*
- * Reset camera block to power-on state.
- */
-static void omap24xxcam_poweron_reset(struct omap24xxcam_device *cam)
-{
- int max_loop = RESET_TIMEOUT_NS;
-
- /* Reset whole camera subsystem */
- omap24xxcam_reg_out(cam->mmio_base,
- CAM_SYSCONFIG,
- CAM_SYSCONFIG_SOFTRESET);
-
- /* Wait till it's finished */
- while (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
- & CAM_SYSSTATUS_RESETDONE)
- && --max_loop) {
- ndelay(1);
- }
-
- if (!(omap24xxcam_reg_in(cam->mmio_base, CAM_SYSSTATUS)
- & CAM_SYSSTATUS_RESETDONE))
- dev_err(cam->dev, "camera soft reset timeout\n");
-}
-
-/*
- * (Re)initialise the camera block.
- */
-static void omap24xxcam_hwinit(struct omap24xxcam_device *cam)
-{
- omap24xxcam_poweron_reset(cam);
-
- /* set the camera subsystem autoidle bit */
- omap24xxcam_reg_out(cam->mmio_base, CAM_SYSCONFIG,
- CAM_SYSCONFIG_AUTOIDLE);
-
- /* set the camera MMU autoidle bit */
- omap24xxcam_reg_out(cam->mmio_base,
- CAMMMU_REG_OFFSET + CAMMMU_SYSCONFIG,
- CAMMMU_SYSCONFIG_AUTOIDLE);
-
- omap24xxcam_core_hwinit(cam);
-
- omap24xxcam_dma_hwinit(&cam->sgdma.dma);
-}
-
-/*
- * Callback for dma transfer stalling.
- */
-static void omap24xxcam_stalled_dma_reset(unsigned long data)
-{
- struct omap24xxcam_device *cam = (struct omap24xxcam_device *)data;
-
- if (!atomic_read(&cam->in_reset)) {
- dev_dbg(cam->dev, "dma stalled, resetting camera\n");
- omap24xxcam_reset(cam);
- }
-}
-
-/*
- * Stop capture. Mark we're doing a reset, stop DMA transfers and
- * core. (No new scatter-gather transfers will be queued whilst
- * in_reset is non-zero.)
- *
- * If omap24xxcam_capture_stop is called from several places at
- * once, only the first call will have an effect. Similarly, the last
- * call omap24xxcam_streaming_cont will have effect.
- *
- * Serialisation is ensured by using cam->core_enable_disable_lock.
- */
-static void omap24xxcam_capture_stop(struct omap24xxcam_device *cam)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
-
- if (atomic_inc_return(&cam->in_reset) != 1) {
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
- return;
- }
-
- omap24xxcam_core_disable(cam);
-
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
-
- omap24xxcam_sgdma_sync(&cam->sgdma);
-}
-
-/*
- * Reset and continue streaming.
- *
- * Note: Resetting the camera FIFO via the CC_RST bit in the CC_CTRL
- * register is supposed to be sufficient to recover from a camera
- * interface error, but it doesn't seem to be enough. If we only do
- * that then subsequent image captures are out of sync by either one
- * or two times DMA_THRESHOLD bytes. Resetting and re-initializing the
- * entire camera subsystem prevents the problem with frame
- * synchronization.
- */
-static void omap24xxcam_capture_cont(struct omap24xxcam_device *cam)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cam->core_enable_disable_lock, flags);
-
- if (atomic_read(&cam->in_reset) != 1)
- goto out;
-
- omap24xxcam_hwinit(cam);
-
- omap24xxcam_sensor_if_enable(cam);
-
- omap24xxcam_sgdma_process(&cam->sgdma);
-
- if (cam->sgdma_in_queue)
- omap24xxcam_core_enable(cam);
-
-out:
- atomic_dec(&cam->in_reset);
- spin_unlock_irqrestore(&cam->core_enable_disable_lock, flags);
-}
-
-static ssize_t
-omap24xxcam_streaming_show(struct device *dev, struct device_attribute *attr,
- char *buf)
-{
- struct omap24xxcam_device *cam = dev_get_drvdata(dev);
-
- return sprintf(buf, "%s\n", cam->streaming ? "active" : "inactive");
-}
-static DEVICE_ATTR(streaming, S_IRUGO, omap24xxcam_streaming_show, NULL);
-
-/*
- * Stop capture and restart it. I.e. reset the camera during use.
- */
-static void omap24xxcam_reset(struct omap24xxcam_device *cam)
-{
- omap24xxcam_capture_stop(cam);
- omap24xxcam_capture_cont(cam);
-}
-
-/*
- * The main interrupt handler.
- */
-static irqreturn_t omap24xxcam_isr(int irq, void *arg)
-{
- struct omap24xxcam_device *cam = (struct omap24xxcam_device *)arg;
- u32 irqstatus;
- unsigned int irqhandled = 0;
-
- irqstatus = omap24xxcam_reg_in(cam->mmio_base, CAM_IRQSTATUS);
-
- if (irqstatus &
- (CAM_IRQSTATUS_DMA_IRQ2 | CAM_IRQSTATUS_DMA_IRQ1
- | CAM_IRQSTATUS_DMA_IRQ0)) {
- omap24xxcam_dma_isr(&cam->sgdma.dma);
- irqhandled = 1;
- }
- if (irqstatus & CAM_IRQSTATUS_CC_IRQ) {
- omap24xxcam_core_isr(cam);
- irqhandled = 1;
- }
- if (irqstatus & CAM_IRQSTATUS_MMU_IRQ)
- dev_err(cam->dev, "unhandled camera MMU interrupt!\n");
-
- return IRQ_RETVAL(irqhandled);
-}
-
-/*
- *
- * Sensor handling.
- *
- */
-
-/*
- * Enable the external sensor interface. Try to negotiate interface
- * parameters with the sensor and start using the new ones. The calls
- * to sensor_if_enable and sensor_if_disable need not to be balanced.
- */
-static int omap24xxcam_sensor_if_enable(struct omap24xxcam_device *cam)
-{
- int rval;
- struct v4l2_ifparm p;
-
- rval = vidioc_int_g_ifparm(cam->sdev, &p);
- if (rval) {
- dev_err(cam->dev, "vidioc_int_g_ifparm failed with %d\n", rval);
- return rval;
- }
-
- cam->if_type = p.if_type;
-
- cam->cc_ctrl = CC_CTRL_CC_EN;
-
- switch (p.if_type) {
- case V4L2_IF_TYPE_BT656:
- if (p.u.bt656.frame_start_on_rising_vs)
- cam->cc_ctrl |= CC_CTRL_NOBT_SYNCHRO;
- if (p.u.bt656.bt_sync_correct)
- cam->cc_ctrl |= CC_CTRL_BT_CORRECT;
- if (p.u.bt656.swap)
- cam->cc_ctrl |= CC_CTRL_PAR_ORDERCAM;
- if (p.u.bt656.latch_clk_inv)
- cam->cc_ctrl |= CC_CTRL_PAR_CLK_POL;
- if (p.u.bt656.nobt_hs_inv)
- cam->cc_ctrl |= CC_CTRL_NOBT_HS_POL;
- if (p.u.bt656.nobt_vs_inv)
- cam->cc_ctrl |= CC_CTRL_NOBT_VS_POL;
-
- switch (p.u.bt656.mode) {
- case V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT8;
- break;
- case V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT10;
- break;
- case V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_NOBT12;
- break;
- case V4L2_IF_TYPE_BT656_MODE_BT_8BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT8;
- break;
- case V4L2_IF_TYPE_BT656_MODE_BT_10BIT:
- cam->cc_ctrl |= CC_CTRL_PAR_MODE_BT10;
- break;
- default:
- dev_err(cam->dev,
- "bt656 interface mode %d not supported\n",
- p.u.bt656.mode);
- return -EINVAL;
- }
- /*
- * The clock rate that the sensor wants has changed.
- * We have to adjust the xclk from OMAP 2 side to
- * match the sensor's wish as closely as possible.
- */
- if (p.u.bt656.clock_curr != cam->if_u.bt656.xclk) {
- u32 xclk = p.u.bt656.clock_curr;
- u32 divisor;
-
- if (xclk == 0)
- return -EINVAL;
-
- if (xclk > CAM_MCLK)
- xclk = CAM_MCLK;
-
- divisor = CAM_MCLK / xclk;
- if (divisor * xclk < CAM_MCLK)
- divisor++;
- if (CAM_MCLK / divisor < p.u.bt656.clock_min
- && divisor > 1)
- divisor--;
- if (divisor > 30)
- divisor = 30;
-
- xclk = CAM_MCLK / divisor;
-
- if (xclk < p.u.bt656.clock_min
- || xclk > p.u.bt656.clock_max)
- return -EINVAL;
-
- cam->if_u.bt656.xclk = xclk;
- }
- omap24xxcam_core_xclk_set(cam, cam->if_u.bt656.xclk);
- break;
- default:
- /* FIXME: how about other interfaces? */
- dev_err(cam->dev, "interface type %d not supported\n",
- p.if_type);
- return -EINVAL;
- }
-
- return 0;
-}
-
-static void omap24xxcam_sensor_if_disable(const struct omap24xxcam_device *cam)
-{
- switch (cam->if_type) {
- case V4L2_IF_TYPE_BT656:
- omap24xxcam_core_xclk_set(cam, 0);
- break;
- }
-}
-
-/*
- * Initialise the sensor hardware.
- */
-static int omap24xxcam_sensor_init(struct omap24xxcam_device *cam)
-{
- int err = 0;
- struct v4l2_int_device *sdev = cam->sdev;
-
- omap24xxcam_clock_on(cam);
- err = omap24xxcam_sensor_if_enable(cam);
- if (err) {
- dev_err(cam->dev, "sensor interface could not be enabled at "
- "initialisation, %d\n", err);
- cam->sdev = NULL;
- goto out;
- }
-
- /* power up sensor during sensor initialization */
- vidioc_int_s_power(sdev, 1);
-
- err = vidioc_int_dev_init(sdev);
- if (err) {
- dev_err(cam->dev, "cannot initialize sensor, error %d\n", err);
- /* Sensor init failed --- it's nonexistent to us! */
- cam->sdev = NULL;
- goto out;
- }
-
- dev_info(cam->dev, "sensor is %s\n", sdev->name);
-
-out:
- omap24xxcam_sensor_if_disable(cam);
- omap24xxcam_clock_off(cam);
-
- vidioc_int_s_power(sdev, 0);
-
- return err;
-}
-
-static void omap24xxcam_sensor_exit(struct omap24xxcam_device *cam)
-{
- if (cam->sdev)
- vidioc_int_dev_exit(cam->sdev);
-}
-
-static void omap24xxcam_sensor_disable(struct omap24xxcam_device *cam)
-{
- omap24xxcam_sensor_if_disable(cam);
- omap24xxcam_clock_off(cam);
- vidioc_int_s_power(cam->sdev, 0);
-}
-
-/*
- * Power-up and configure camera sensor. It's ready for capturing now.
- */
-static int omap24xxcam_sensor_enable(struct omap24xxcam_device *cam)
-{
- int rval;
-
- omap24xxcam_clock_on(cam);
-
- omap24xxcam_sensor_if_enable(cam);
-
- rval = vidioc_int_s_power(cam->sdev, 1);
- if (rval)
- goto out;
-
- rval = vidioc_int_init(cam->sdev);
- if (rval)
- goto out;
-
- return 0;
-
-out:
- omap24xxcam_sensor_disable(cam);
-
- return rval;
-}
-
-static void omap24xxcam_sensor_reset_work(struct work_struct *work)
-{
- struct omap24xxcam_device *cam =
- container_of(work, struct omap24xxcam_device,
- sensor_reset_work);
-
- if (atomic_read(&cam->reset_disable))
- return;
-
- omap24xxcam_capture_stop(cam);
-
- if (vidioc_int_reset(cam->sdev) == 0) {
- vidioc_int_init(cam->sdev);
- } else {
- /* Can't reset it by vidioc_int_reset. */
- omap24xxcam_sensor_disable(cam);
- omap24xxcam_sensor_enable(cam);
- }
-
- omap24xxcam_capture_cont(cam);
-}
-
-/*
- *
- * IOCTL interface.
- *
- */
-
-static int vidioc_querycap(struct file *file, void *fh,
- struct v4l2_capability *cap)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
-
- strlcpy(cap->driver, CAM_NAME, sizeof(cap->driver));
- strlcpy(cap->card, cam->vfd->name, sizeof(cap->card));
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
-
- return 0;
-}
-
-static int vidioc_enum_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_fmtdesc *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
-
- return vidioc_int_enum_fmt_cap(cam->sdev, f);
-}
-
-static int vidioc_g_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_g_fmt_cap(cam->sdev, f);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_s_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- rval = -EBUSY;
- goto out;
- }
-
- rval = vidioc_int_s_fmt_cap(cam->sdev, f);
-
-out:
- mutex_unlock(&cam->mutex);
-
- if (!rval) {
- mutex_lock(&ofh->vbq.vb_lock);
- ofh->pix = f->fmt.pix;
- mutex_unlock(&ofh->vbq.vb_lock);
- }
-
- memset(f, 0, sizeof(*f));
- vidioc_g_fmt_vid_cap(file, fh, f);
-
- return rval;
-}
-
-static int vidioc_try_fmt_vid_cap(struct file *file, void *fh,
- struct v4l2_format *f)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_try_fmt_cap(cam->sdev, f);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_reqbufs(struct file *file, void *fh,
- struct v4l2_requestbuffers *b)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- mutex_unlock(&cam->mutex);
- return -EBUSY;
- }
-
- omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
- mutex_unlock(&cam->mutex);
-
- rval = videobuf_reqbufs(&ofh->vbq, b);
-
- /*
- * Either videobuf_reqbufs failed or the buffers are not
- * memory-mapped (which would need special attention).
- */
- if (rval < 0 || b->memory != V4L2_MEMORY_MMAP)
- goto out;
-
- rval = omap24xxcam_vbq_alloc_mmap_buffers(&ofh->vbq, rval);
- if (rval)
- omap24xxcam_vbq_free_mmap_buffers(&ofh->vbq);
-
-out:
- return rval;
-}
-
-static int vidioc_querybuf(struct file *file, void *fh,
- struct v4l2_buffer *b)
-{
- struct omap24xxcam_fh *ofh = fh;
-
- return videobuf_querybuf(&ofh->vbq, b);
-}
-
-static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct omap24xxcam_fh *ofh = fh;
-
- return videobuf_qbuf(&ofh->vbq, b);
-}
-
-static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *b)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- struct videobuf_buffer *vb;
- int rval;
-
-videobuf_dqbuf_again:
- rval = videobuf_dqbuf(&ofh->vbq, b, file->f_flags & O_NONBLOCK);
- if (rval)
- goto out;
-
- vb = ofh->vbq.bufs[b->index];
-
- mutex_lock(&cam->mutex);
- /* _needs_reset returns -EIO if reset is required. */
- rval = vidioc_int_g_needs_reset(cam->sdev, (void *)vb->baddr);
- mutex_unlock(&cam->mutex);
- if (rval == -EIO)
- schedule_work(&cam->sensor_reset_work);
- else
- rval = 0;
-
-out:
- /*
- * This is a hack. We don't want to show -EIO to the user
- * space. Requeue the buffer and try again if we're not doing
- * this in non-blocking mode.
- */
- if (rval == -EIO) {
- videobuf_qbuf(&ofh->vbq, b);
- if (!(file->f_flags & O_NONBLOCK))
- goto videobuf_dqbuf_again;
- /*
- * We don't have a videobuf_buffer now --- maybe next
- * time...
- */
- rval = -EAGAIN;
- }
-
- return rval;
-}
-
-static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- rval = -EBUSY;
- goto out;
- }
-
- rval = omap24xxcam_sensor_if_enable(cam);
- if (rval) {
- dev_dbg(cam->dev, "vidioc_int_g_ifparm failed\n");
- goto out;
- }
-
- rval = videobuf_streamon(&ofh->vbq);
- if (!rval) {
- cam->streaming = file;
- sysfs_notify(&cam->dev->kobj, NULL, "streaming");
- }
-
-out:
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- struct videobuf_queue *q = &ofh->vbq;
- int rval;
-
- atomic_inc(&cam->reset_disable);
-
- flush_work(&cam->sensor_reset_work);
-
- rval = videobuf_streamoff(q);
- if (!rval) {
- mutex_lock(&cam->mutex);
- cam->streaming = NULL;
- mutex_unlock(&cam->mutex);
- sysfs_notify(&cam->dev->kobj, NULL, "streaming");
- }
-
- atomic_dec(&cam->reset_disable);
-
- return rval;
-}
-
-static int vidioc_enum_input(struct file *file, void *fh,
- struct v4l2_input *inp)
-{
- if (inp->index > 0)
- return -EINVAL;
-
- strlcpy(inp->name, "camera", sizeof(inp->name));
- inp->type = V4L2_INPUT_TYPE_CAMERA;
-
- return 0;
-}
-
-static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
-{
- *i = 0;
-
- return 0;
-}
-
-static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
-{
- if (i > 0)
- return -EINVAL;
-
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *fh,
- struct v4l2_queryctrl *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
-
- return vidioc_int_queryctrl(cam->sdev, a);
-}
-
-static int vidioc_g_ctrl(struct file *file, void *fh,
- struct v4l2_control *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_g_ctrl(cam->sdev, a);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *fh,
- struct v4l2_control *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_s_ctrl(cam->sdev, a);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_g_parm(struct file *file, void *fh,
- struct v4l2_streamparm *a) {
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- int rval;
-
- mutex_lock(&cam->mutex);
- rval = vidioc_int_g_parm(cam->sdev, a);
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-static int vidioc_s_parm(struct file *file, void *fh,
- struct v4l2_streamparm *a)
-{
- struct omap24xxcam_fh *ofh = fh;
- struct omap24xxcam_device *cam = ofh->cam;
- struct v4l2_streamparm old_streamparm;
- int rval;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- rval = -EBUSY;
- goto out;
- }
-
- old_streamparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rval = vidioc_int_g_parm(cam->sdev, &old_streamparm);
- if (rval)
- goto out;
-
- rval = vidioc_int_s_parm(cam->sdev, a);
- if (rval)
- goto out;
-
- rval = omap24xxcam_sensor_if_enable(cam);
- /*
- * Revert to old streaming parameters if enabling sensor
- * interface with the new ones failed.
- */
- if (rval)
- vidioc_int_s_parm(cam->sdev, &old_streamparm);
-
-out:
- mutex_unlock(&cam->mutex);
-
- return rval;
-}
-
-/*
- *
- * File operations.
- *
- */
-
-static unsigned int omap24xxcam_poll(struct file *file,
- struct poll_table_struct *wait)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- struct omap24xxcam_device *cam = fh->cam;
- struct videobuf_buffer *vb;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming != file) {
- mutex_unlock(&cam->mutex);
- return POLLERR;
- }
- mutex_unlock(&cam->mutex);
-
- mutex_lock(&fh->vbq.vb_lock);
- if (list_empty(&fh->vbq.stream)) {
- mutex_unlock(&fh->vbq.vb_lock);
- return POLLERR;
- }
- vb = list_entry(fh->vbq.stream.next, struct videobuf_buffer, stream);
- mutex_unlock(&fh->vbq.vb_lock);
-
- poll_wait(file, &vb->done, wait);
-
- if (vb->state == VIDEOBUF_DONE || vb->state == VIDEOBUF_ERROR)
- return POLLIN | POLLRDNORM;
-
- return 0;
-}
-
-static int omap24xxcam_mmap_buffers(struct file *file,
- struct vm_area_struct *vma)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- struct omap24xxcam_device *cam = fh->cam;
- struct videobuf_queue *vbq = &fh->vbq;
- unsigned int first, last, size, i, j;
- int err = 0;
-
- mutex_lock(&cam->mutex);
- if (cam->streaming) {
- mutex_unlock(&cam->mutex);
- return -EBUSY;
- }
- mutex_unlock(&cam->mutex);
- mutex_lock(&vbq->vb_lock);
-
- /* look for first buffer to map */
- for (first = 0; first < VIDEO_MAX_FRAME; first++) {
- if (NULL == vbq->bufs[first])
- continue;
- if (V4L2_MEMORY_MMAP != vbq->bufs[first]->memory)
- continue;
- if (vbq->bufs[first]->boff == (vma->vm_pgoff << PAGE_SHIFT))
- break;
- }
-
- /* look for last buffer to map */
- for (size = 0, last = first; last < VIDEO_MAX_FRAME; last++) {
- if (NULL == vbq->bufs[last])
- continue;
- if (V4L2_MEMORY_MMAP != vbq->bufs[last]->memory)
- continue;
- size += vbq->bufs[last]->bsize;
- if (size == (vma->vm_end - vma->vm_start))
- break;
- }
-
- size = 0;
- for (i = first; i <= last && i < VIDEO_MAX_FRAME; i++) {
- struct videobuf_dmabuf *dma = videobuf_to_dma(vbq->bufs[i]);
-
- for (j = 0; j < dma->sglen; j++) {
- err = remap_pfn_range(
- vma, vma->vm_start + size,
- page_to_pfn(sg_page(&dma->sglist[j])),
- sg_dma_len(&dma->sglist[j]), vma->vm_page_prot);
- if (err)
- goto out;
- size += sg_dma_len(&dma->sglist[j]);
- }
- }
-
-out:
- mutex_unlock(&vbq->vb_lock);
-
- return err;
-}
-
-static int omap24xxcam_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- int rval;
-
- /* let the video-buf mapper check arguments and set-up structures */
- rval = videobuf_mmap_mapper(&fh->vbq, vma);
- if (rval)
- return rval;
-
- vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot);
-
- /* do mapping to our allocated buffers */
- rval = omap24xxcam_mmap_buffers(file, vma);
- /*
- * In case of error, free vma->vm_private_data allocated by
- * videobuf_mmap_mapper.
- */
- if (rval)
- kfree(vma->vm_private_data);
-
- return rval;
-}
-
-static int omap24xxcam_open(struct file *file)
-{
- struct omap24xxcam_device *cam = omap24xxcam.priv;
- struct omap24xxcam_fh *fh;
- struct v4l2_format format;
-
- if (!cam || !cam->vfd)
- return -ENODEV;
-
- fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (fh == NULL)
- return -ENOMEM;
-
- mutex_lock(&cam->mutex);
- if (cam->sdev == NULL || !try_module_get(cam->sdev->module)) {
- mutex_unlock(&cam->mutex);
- goto out_try_module_get;
- }
-
- if (atomic_inc_return(&cam->users) == 1) {
- omap24xxcam_hwinit(cam);
- if (omap24xxcam_sensor_enable(cam)) {
- mutex_unlock(&cam->mutex);
- goto out_omap24xxcam_sensor_enable;
- }
- }
- mutex_unlock(&cam->mutex);
-
- fh->cam = cam;
- mutex_lock(&cam->mutex);
- vidioc_int_g_fmt_cap(cam->sdev, &format);
- mutex_unlock(&cam->mutex);
- /* FIXME: how about fh->pix when there are more users? */
- fh->pix = format.fmt.pix;
-
- file->private_data = fh;
-
- spin_lock_init(&fh->vbq_lock);
-
- videobuf_queue_sg_init(&fh->vbq, &omap24xxcam_vbq_ops, NULL,
- &fh->vbq_lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), fh, NULL);
-
- return 0;
-
-out_omap24xxcam_sensor_enable:
- omap24xxcam_poweron_reset(cam);
- module_put(cam->sdev->module);
-
-out_try_module_get:
- kfree(fh);
-
- return -ENODEV;
-}
-
-static int omap24xxcam_release(struct file *file)
-{
- struct omap24xxcam_fh *fh = file->private_data;
- struct omap24xxcam_device *cam = fh->cam;
-
- atomic_inc(&cam->reset_disable);
-
- flush_work(&cam->sensor_reset_work);
-
- /* stop streaming capture */
- videobuf_streamoff(&fh->vbq);
-
- mutex_lock(&cam->mutex);
- if (cam->streaming == file) {
- cam->streaming = NULL;
- mutex_unlock(&cam->mutex);
- sysfs_notify(&cam->dev->kobj, NULL, "streaming");
- } else {
- mutex_unlock(&cam->mutex);
- }
-
- atomic_dec(&cam->reset_disable);
-
- omap24xxcam_vbq_free_mmap_buffers(&fh->vbq);
-
- /*
- * Make sure the reset work we might have scheduled is not
- * pending! It may be run *only* if we have users. (And it may
- * not be scheduled anymore since streaming is already
- * disabled.)
- */
- flush_work(&cam->sensor_reset_work);
-
- mutex_lock(&cam->mutex);
- if (atomic_dec_return(&cam->users) == 0) {
- omap24xxcam_sensor_disable(cam);
- omap24xxcam_poweron_reset(cam);
- }
- mutex_unlock(&cam->mutex);
-
- file->private_data = NULL;
-
- module_put(cam->sdev->module);
- kfree(fh);
-
- return 0;
-}
-
-static struct v4l2_file_operations omap24xxcam_fops = {
- .ioctl = video_ioctl2,
- .poll = omap24xxcam_poll,
- .mmap = omap24xxcam_mmap,
- .open = omap24xxcam_open,
- .release = omap24xxcam_release,
-};
-
-/*
- *
- * Power management.
- *
- */
-
-#ifdef CONFIG_PM
-static int omap24xxcam_suspend(struct platform_device *pdev, pm_message_t state)
-{
- struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
-
- if (atomic_read(&cam->users) == 0)
- return 0;
-
- if (!atomic_read(&cam->reset_disable))
- omap24xxcam_capture_stop(cam);
-
- omap24xxcam_sensor_disable(cam);
- omap24xxcam_poweron_reset(cam);
-
- return 0;
-}
-
-static int omap24xxcam_resume(struct platform_device *pdev)
-{
- struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
-
- if (atomic_read(&cam->users) == 0)
- return 0;
-
- omap24xxcam_hwinit(cam);
- omap24xxcam_sensor_enable(cam);
-
- if (!atomic_read(&cam->reset_disable))
- omap24xxcam_capture_cont(cam);
-
- return 0;
-}
-#endif /* CONFIG_PM */
-
-static const struct v4l2_ioctl_ops omap24xxcam_ioctl_fops = {
- .vidioc_querycap = vidioc_querycap,
- .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
- .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
- .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
- .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
- .vidioc_reqbufs = vidioc_reqbufs,
- .vidioc_querybuf = vidioc_querybuf,
- .vidioc_qbuf = vidioc_qbuf,
- .vidioc_dqbuf = vidioc_dqbuf,
- .vidioc_streamon = vidioc_streamon,
- .vidioc_streamoff = vidioc_streamoff,
- .vidioc_enum_input = vidioc_enum_input,
- .vidioc_g_input = vidioc_g_input,
- .vidioc_s_input = vidioc_s_input,
- .vidioc_queryctrl = vidioc_queryctrl,
- .vidioc_g_ctrl = vidioc_g_ctrl,
- .vidioc_s_ctrl = vidioc_s_ctrl,
- .vidioc_g_parm = vidioc_g_parm,
- .vidioc_s_parm = vidioc_s_parm,
-};
-
-/*
- *
- * Camera device (i.e. /dev/video).
- *
- */
-
-static int omap24xxcam_device_register(struct v4l2_int_device *s)
-{
- struct omap24xxcam_device *cam = s->u.slave->master->priv;
- struct video_device *vfd;
- int rval;
-
- /* We already have a slave. */
- if (cam->sdev)
- return -EBUSY;
-
- cam->sdev = s;
-
- if (device_create_file(cam->dev, &dev_attr_streaming) != 0) {
- dev_err(cam->dev, "could not register sysfs entry\n");
- rval = -EBUSY;
- goto err;
- }
-
- /* initialize the video_device struct */
- vfd = cam->vfd = video_device_alloc();
- if (!vfd) {
- dev_err(cam->dev, "could not allocate video device struct\n");
- rval = -ENOMEM;
- goto err;
- }
- vfd->release = video_device_release;
-
- vfd->v4l2_dev = &cam->v4l2_dev;
-
- strlcpy(vfd->name, CAM_NAME, sizeof(vfd->name));
- vfd->fops = &omap24xxcam_fops;
- vfd->ioctl_ops = &omap24xxcam_ioctl_fops;
-
- omap24xxcam_hwinit(cam);
-
- rval = omap24xxcam_sensor_init(cam);
- if (rval)
- goto err;
-
- if (video_register_device(vfd, VFL_TYPE_GRABBER, video_nr) < 0) {
- dev_err(cam->dev, "could not register V4L device\n");
- rval = -EBUSY;
- goto err;
- }
-
- omap24xxcam_poweron_reset(cam);
-
- dev_info(cam->dev, "registered device %s\n",
- video_device_node_name(vfd));
-
- return 0;
-
-err:
- omap24xxcam_device_unregister(s);
-
- return rval;
-}
-
-static void omap24xxcam_device_unregister(struct v4l2_int_device *s)
-{
- struct omap24xxcam_device *cam = s->u.slave->master->priv;
-
- omap24xxcam_sensor_exit(cam);
-
- if (cam->vfd) {
- if (!video_is_registered(cam->vfd)) {
- /*
- * The device was never registered, so release the
- * video_device struct directly.
- */
- video_device_release(cam->vfd);
- } else {
- /*
- * The unregister function will release the
- * video_device struct as well as
- * unregistering it.
- */
- video_unregister_device(cam->vfd);
- }
- cam->vfd = NULL;
- }
-
- device_remove_file(cam->dev, &dev_attr_streaming);
-
- cam->sdev = NULL;
-}
-
-static struct v4l2_int_master omap24xxcam_master = {
- .attach = omap24xxcam_device_register,
- .detach = omap24xxcam_device_unregister,
-};
-
-static struct v4l2_int_device omap24xxcam = {
- .module = THIS_MODULE,
- .name = CAM_NAME,
- .type = v4l2_int_type_master,
- .u = {
- .master = &omap24xxcam_master
- },
-};
-
-/*
- *
- * Driver initialisation and deinitialisation.
- *
- */
-
-static int omap24xxcam_probe(struct platform_device *pdev)
-{
- struct omap24xxcam_device *cam;
- struct resource *mem;
- int irq;
-
- cam = kzalloc(sizeof(*cam), GFP_KERNEL);
- if (!cam) {
- dev_err(&pdev->dev, "could not allocate memory\n");
- goto err;
- }
-
- platform_set_drvdata(pdev, cam);
-
- cam->dev = &pdev->dev;
-
- if (v4l2_device_register(&pdev->dev, &cam->v4l2_dev)) {
- dev_err(&pdev->dev, "v4l2_device_register failed\n");
- goto err;
- }
-
- /*
- * Impose a lower limit on the amount of memory allocated for
- * capture. We require at least enough memory to double-buffer
- * QVGA (300KB).
- */
- if (capture_mem < 320 * 240 * 2 * 2)
- capture_mem = 320 * 240 * 2 * 2;
- cam->capture_mem = capture_mem;
-
- /* request the mem region for the camera registers */
- mem = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!mem) {
- dev_err(cam->dev, "no mem resource?\n");
- goto err;
- }
- if (!request_mem_region(mem->start, resource_size(mem), pdev->name)) {
- dev_err(cam->dev,
- "cannot reserve camera register I/O region\n");
- goto err;
- }
- cam->mmio_base_phys = mem->start;
- cam->mmio_size = resource_size(mem);
-
- /* map the region */
- cam->mmio_base = ioremap_nocache(cam->mmio_base_phys, cam->mmio_size);
- if (!cam->mmio_base) {
- dev_err(cam->dev, "cannot map camera register I/O region\n");
- goto err;
- }
-
- irq = platform_get_irq(pdev, 0);
- if (irq <= 0) {
- dev_err(cam->dev, "no irq for camera?\n");
- goto err;
- }
-
- /* install the interrupt service routine */
- if (request_irq(irq, omap24xxcam_isr, 0, CAM_NAME, cam)) {
- dev_err(cam->dev,
- "could not install interrupt service routine\n");
- goto err;
- }
- cam->irq = irq;
-
- if (omap24xxcam_clock_get(cam))
- goto err;
-
- INIT_WORK(&cam->sensor_reset_work, omap24xxcam_sensor_reset_work);
-
- mutex_init(&cam->mutex);
- spin_lock_init(&cam->core_enable_disable_lock);
-
- omap24xxcam_sgdma_init(&cam->sgdma,
- cam->mmio_base + CAMDMA_REG_OFFSET,
- omap24xxcam_stalled_dma_reset,
- (unsigned long)cam);
-
- omap24xxcam.priv = cam;
-
- if (v4l2_int_device_register(&omap24xxcam))
- goto err;
-
- return 0;
-
-err:
- omap24xxcam_remove(pdev);
- return -ENODEV;
-}
-
-static int omap24xxcam_remove(struct platform_device *pdev)
-{
- struct omap24xxcam_device *cam = platform_get_drvdata(pdev);
-
- if (!cam)
- return 0;
-
- if (omap24xxcam.priv != NULL)
- v4l2_int_device_unregister(&omap24xxcam);
- omap24xxcam.priv = NULL;
-
- omap24xxcam_clock_put(cam);
-
- if (cam->irq) {
- free_irq(cam->irq, cam);
- cam->irq = 0;
- }
-
- if (cam->mmio_base) {
- iounmap((void *)cam->mmio_base);
- cam->mmio_base = 0;
- }
-
- if (cam->mmio_base_phys) {
- release_mem_region(cam->mmio_base_phys, cam->mmio_size);
- cam->mmio_base_phys = 0;
- }
-
- v4l2_device_unregister(&cam->v4l2_dev);
-
- kfree(cam);
-
- return 0;
-}
-
-static struct platform_driver omap24xxcam_driver = {
- .probe = omap24xxcam_probe,
- .remove = omap24xxcam_remove,
-#ifdef CONFIG_PM
- .suspend = omap24xxcam_suspend,
- .resume = omap24xxcam_resume,
-#endif
- .driver = {
- .name = CAM_NAME,
- .owner = THIS_MODULE,
- },
-};
-
-module_platform_driver(omap24xxcam_driver);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
-MODULE_DESCRIPTION("OMAP24xx Video for Linux camera driver");
-MODULE_LICENSE("GPL");
-MODULE_VERSION(OMAP24XXCAM_VERSION);
-module_param(video_nr, int, 0);
-MODULE_PARM_DESC(video_nr,
- "Minor number for video device (-1 ==> auto assign)");
-module_param(capture_mem, int, 0);
-MODULE_PARM_DESC(capture_mem, "Maximum amount of memory for capture "
- "buffers (default 4800kiB)");
diff --git a/drivers/staging/media/omap24xx/omap24xxcam.h b/drivers/staging/media/omap24xx/omap24xxcam.h
deleted file mode 100644
index 233bb40..0000000
--- a/drivers/staging/media/omap24xx/omap24xxcam.h
+++ /dev/null
@@ -1,596 +0,0 @@
-/*
- * drivers/media/platform/omap24xxcam.h
- *
- * Copyright (C) 2004 MontaVista Software, Inc.
- * Copyright (C) 2004 Texas Instruments.
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from Andy Lowe <source@mvista.com>.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef OMAP24XXCAM_H
-#define OMAP24XXCAM_H
-
-#include <media/videobuf-dma-sg.h>
-#include <media/v4l2-device.h>
-#include "v4l2-int-device.h"
-
-/*
- *
- * General driver related definitions.
- *
- */
-
-#define CAM_NAME "omap24xxcam"
-
-#define CAM_MCLK 96000000
-
-/* number of bytes transferred per DMA request */
-#define DMA_THRESHOLD 32
-
-/*
- * NUM_CAMDMA_CHANNELS is the number of logical channels provided by
- * the camera DMA controller.
- */
-#define NUM_CAMDMA_CHANNELS 4
-
-/*
- * NUM_SG_DMA is the number of scatter-gather DMA transfers that can
- * be queued. (We don't have any overlay sglists now.)
- */
-#define NUM_SG_DMA (VIDEO_MAX_FRAME)
-
-/*
- *
- * Register definitions.
- *
- */
-
-/* subsystem register block offsets */
-#define CC_REG_OFFSET 0x00000400
-#define CAMDMA_REG_OFFSET 0x00000800
-#define CAMMMU_REG_OFFSET 0x00000C00
-
-/* define camera subsystem register offsets */
-#define CAM_REVISION 0x000
-#define CAM_SYSCONFIG 0x010
-#define CAM_SYSSTATUS 0x014
-#define CAM_IRQSTATUS 0x018
-#define CAM_GPO 0x040
-#define CAM_GPI 0x050
-
-/* define camera core register offsets */
-#define CC_REVISION 0x000
-#define CC_SYSCONFIG 0x010
-#define CC_SYSSTATUS 0x014
-#define CC_IRQSTATUS 0x018
-#define CC_IRQENABLE 0x01C
-#define CC_CTRL 0x040
-#define CC_CTRL_DMA 0x044
-#define CC_CTRL_XCLK 0x048
-#define CC_FIFODATA 0x04C
-#define CC_TEST 0x050
-#define CC_GENPAR 0x054
-#define CC_CCPFSCR 0x058
-#define CC_CCPFECR 0x05C
-#define CC_CCPLSCR 0x060
-#define CC_CCPLECR 0x064
-#define CC_CCPDFR 0x068
-
-/* define camera dma register offsets */
-#define CAMDMA_REVISION 0x000
-#define CAMDMA_IRQSTATUS_L0 0x008
-#define CAMDMA_IRQSTATUS_L1 0x00C
-#define CAMDMA_IRQSTATUS_L2 0x010
-#define CAMDMA_IRQSTATUS_L3 0x014
-#define CAMDMA_IRQENABLE_L0 0x018
-#define CAMDMA_IRQENABLE_L1 0x01C
-#define CAMDMA_IRQENABLE_L2 0x020
-#define CAMDMA_IRQENABLE_L3 0x024
-#define CAMDMA_SYSSTATUS 0x028
-#define CAMDMA_OCP_SYSCONFIG 0x02C
-#define CAMDMA_CAPS_0 0x064
-#define CAMDMA_CAPS_2 0x06C
-#define CAMDMA_CAPS_3 0x070
-#define CAMDMA_CAPS_4 0x074
-#define CAMDMA_GCR 0x078
-#define CAMDMA_CCR(n) (0x080 + (n)*0x60)
-#define CAMDMA_CLNK_CTRL(n) (0x084 + (n)*0x60)
-#define CAMDMA_CICR(n) (0x088 + (n)*0x60)
-#define CAMDMA_CSR(n) (0x08C + (n)*0x60)
-#define CAMDMA_CSDP(n) (0x090 + (n)*0x60)
-#define CAMDMA_CEN(n) (0x094 + (n)*0x60)
-#define CAMDMA_CFN(n) (0x098 + (n)*0x60)
-#define CAMDMA_CSSA(n) (0x09C + (n)*0x60)
-#define CAMDMA_CDSA(n) (0x0A0 + (n)*0x60)
-#define CAMDMA_CSEI(n) (0x0A4 + (n)*0x60)
-#define CAMDMA_CSFI(n) (0x0A8 + (n)*0x60)
-#define CAMDMA_CDEI(n) (0x0AC + (n)*0x60)
-#define CAMDMA_CDFI(n) (0x0B0 + (n)*0x60)
-#define CAMDMA_CSAC(n) (0x0B4 + (n)*0x60)
-#define CAMDMA_CDAC(n) (0x0B8 + (n)*0x60)
-#define CAMDMA_CCEN(n) (0x0BC + (n)*0x60)
-#define CAMDMA_CCFN(n) (0x0C0 + (n)*0x60)
-#define CAMDMA_COLOR(n) (0x0C4 + (n)*0x60)
-
-/* define camera mmu register offsets */
-#define CAMMMU_REVISION 0x000
-#define CAMMMU_SYSCONFIG 0x010
-#define CAMMMU_SYSSTATUS 0x014
-#define CAMMMU_IRQSTATUS 0x018
-#define CAMMMU_IRQENABLE 0x01C
-#define CAMMMU_WALKING_ST 0x040
-#define CAMMMU_CNTL 0x044
-#define CAMMMU_FAULT_AD 0x048
-#define CAMMMU_TTB 0x04C
-#define CAMMMU_LOCK 0x050
-#define CAMMMU_LD_TLB 0x054
-#define CAMMMU_CAM 0x058
-#define CAMMMU_RAM 0x05C
-#define CAMMMU_GFLUSH 0x060
-#define CAMMMU_FLUSH_ENTRY 0x064
-#define CAMMMU_READ_CAM 0x068
-#define CAMMMU_READ_RAM 0x06C
-#define CAMMMU_EMU_FAULT_AD 0x070
-
-/* Define bit fields within selected registers */
-#define CAM_REVISION_MAJOR (15 << 4)
-#define CAM_REVISION_MAJOR_SHIFT 4
-#define CAM_REVISION_MINOR (15 << 0)
-#define CAM_REVISION_MINOR_SHIFT 0
-
-#define CAM_SYSCONFIG_SOFTRESET (1 << 1)
-#define CAM_SYSCONFIG_AUTOIDLE (1 << 0)
-
-#define CAM_SYSSTATUS_RESETDONE (1 << 0)
-
-#define CAM_IRQSTATUS_CC_IRQ (1 << 4)
-#define CAM_IRQSTATUS_MMU_IRQ (1 << 3)
-#define CAM_IRQSTATUS_DMA_IRQ2 (1 << 2)
-#define CAM_IRQSTATUS_DMA_IRQ1 (1 << 1)
-#define CAM_IRQSTATUS_DMA_IRQ0 (1 << 0)
-
-#define CAM_GPO_CAM_S_P_EN (1 << 1)
-#define CAM_GPO_CAM_CCP_MODE (1 << 0)
-
-#define CAM_GPI_CC_DMA_REQ1 (1 << 24)
-#define CAP_GPI_CC_DMA_REQ0 (1 << 23)
-#define CAP_GPI_CAM_MSTANDBY (1 << 21)
-#define CAP_GPI_CAM_WAIT (1 << 20)
-#define CAP_GPI_CAM_S_DATA (1 << 17)
-#define CAP_GPI_CAM_S_CLK (1 << 16)
-#define CAP_GPI_CAM_P_DATA (0xFFF << 3)
-#define CAP_GPI_CAM_P_DATA_SHIFT 3
-#define CAP_GPI_CAM_P_VS (1 << 2)
-#define CAP_GPI_CAM_P_HS (1 << 1)
-#define CAP_GPI_CAM_P_CLK (1 << 0)
-
-#define CC_REVISION_MAJOR (15 << 4)
-#define CC_REVISION_MAJOR_SHIFT 4
-#define CC_REVISION_MINOR (15 << 0)
-#define CC_REVISION_MINOR_SHIFT 0
-
-#define CC_SYSCONFIG_SIDLEMODE (3 << 3)
-#define CC_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
-#define CC_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
-#define CC_SYSCONFIG_SOFTRESET (1 << 1)
-#define CC_SYSCONFIG_AUTOIDLE (1 << 0)
-
-#define CC_SYSSTATUS_RESETDONE (1 << 0)
-
-#define CC_IRQSTATUS_FS_IRQ (1 << 19)
-#define CC_IRQSTATUS_LE_IRQ (1 << 18)
-#define CC_IRQSTATUS_LS_IRQ (1 << 17)
-#define CC_IRQSTATUS_FE_IRQ (1 << 16)
-#define CC_IRQSTATUS_FW_ERR_IRQ (1 << 10)
-#define CC_IRQSTATUS_FSC_ERR_IRQ (1 << 9)
-#define CC_IRQSTATUS_SSC_ERR_IRQ (1 << 8)
-#define CC_IRQSTATUS_FIFO_NOEMPTY_IRQ (1 << 4)
-#define CC_IRQSTATUS_FIFO_FULL_IRQ (1 << 3)
-#define CC_IRQSTATUS_FIFO_THR_IRQ (1 << 2)
-#define CC_IRQSTATUS_FIFO_OF_IRQ (1 << 1)
-#define CC_IRQSTATUS_FIFO_UF_IRQ (1 << 0)
-
-#define CC_IRQENABLE_FS_IRQ (1 << 19)
-#define CC_IRQENABLE_LE_IRQ (1 << 18)
-#define CC_IRQENABLE_LS_IRQ (1 << 17)
-#define CC_IRQENABLE_FE_IRQ (1 << 16)
-#define CC_IRQENABLE_FW_ERR_IRQ (1 << 10)
-#define CC_IRQENABLE_FSC_ERR_IRQ (1 << 9)
-#define CC_IRQENABLE_SSC_ERR_IRQ (1 << 8)
-#define CC_IRQENABLE_FIFO_NOEMPTY_IRQ (1 << 4)
-#define CC_IRQENABLE_FIFO_FULL_IRQ (1 << 3)
-#define CC_IRQENABLE_FIFO_THR_IRQ (1 << 2)
-#define CC_IRQENABLE_FIFO_OF_IRQ (1 << 1)
-#define CC_IRQENABLE_FIFO_UF_IRQ (1 << 0)
-
-#define CC_CTRL_CC_ONE_SHOT (1 << 20)
-#define CC_CTRL_CC_IF_SYNCHRO (1 << 19)
-#define CC_CTRL_CC_RST (1 << 18)
-#define CC_CTRL_CC_FRAME_TRIG (1 << 17)
-#define CC_CTRL_CC_EN (1 << 16)
-#define CC_CTRL_NOBT_SYNCHRO (1 << 13)
-#define CC_CTRL_BT_CORRECT (1 << 12)
-#define CC_CTRL_PAR_ORDERCAM (1 << 11)
-#define CC_CTRL_PAR_CLK_POL (1 << 10)
-#define CC_CTRL_NOBT_HS_POL (1 << 9)
-#define CC_CTRL_NOBT_VS_POL (1 << 8)
-#define CC_CTRL_PAR_MODE (7 << 1)
-#define CC_CTRL_PAR_MODE_SHIFT 1
-#define CC_CTRL_PAR_MODE_NOBT8 (0 << 1)
-#define CC_CTRL_PAR_MODE_NOBT10 (1 << 1)
-#define CC_CTRL_PAR_MODE_NOBT12 (2 << 1)
-#define CC_CTRL_PAR_MODE_BT8 (4 << 1)
-#define CC_CTRL_PAR_MODE_BT10 (5 << 1)
-#define CC_CTRL_PAR_MODE_FIFOTEST (7 << 1)
-#define CC_CTRL_CCP_MODE (1 << 0)
-
-#define CC_CTRL_DMA_EN (1 << 8)
-#define CC_CTRL_DMA_FIFO_THRESHOLD (0x7F << 0)
-#define CC_CTRL_DMA_FIFO_THRESHOLD_SHIFT 0
-
-#define CC_CTRL_XCLK_DIV (0x1F << 0)
-#define CC_CTRL_XCLK_DIV_SHIFT 0
-#define CC_CTRL_XCLK_DIV_STABLE_LOW (0 << 0)
-#define CC_CTRL_XCLK_DIV_STABLE_HIGH (1 << 0)
-#define CC_CTRL_XCLK_DIV_BYPASS (31 << 0)
-
-#define CC_TEST_FIFO_RD_POINTER (0xFF << 24)
-#define CC_TEST_FIFO_RD_POINTER_SHIFT 24
-#define CC_TEST_FIFO_WR_POINTER (0xFF << 16)
-#define CC_TEST_FIFO_WR_POINTER_SHIFT 16
-#define CC_TEST_FIFO_LEVEL (0xFF << 8)
-#define CC_TEST_FIFO_LEVEL_SHIFT 8
-#define CC_TEST_FIFO_LEVEL_PEAK (0xFF << 0)
-#define CC_TEST_FIFO_LEVEL_PEAK_SHIFT 0
-
-#define CC_GENPAR_FIFO_DEPTH (7 << 0)
-#define CC_GENPAR_FIFO_DEPTH_SHIFT 0
-
-#define CC_CCPDFR_ALPHA (0xFF << 8)
-#define CC_CCPDFR_ALPHA_SHIFT 8
-#define CC_CCPDFR_DATAFORMAT (15 << 0)
-#define CC_CCPDFR_DATAFORMAT_SHIFT 0
-#define CC_CCPDFR_DATAFORMAT_YUV422BE (0 << 0)
-#define CC_CCPDFR_DATAFORMAT_YUV422 (1 << 0)
-#define CC_CCPDFR_DATAFORMAT_YUV420 (2 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB444 (4 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB565 (5 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB888NDE (6 << 0)
-#define CC_CCPDFR_DATAFORMAT_RGB888 (7 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW8NDE (8 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW8 (9 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW10NDE (10 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW10 (11 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW12NDE (12 << 0)
-#define CC_CCPDFR_DATAFORMAT_RAW12 (13 << 0)
-#define CC_CCPDFR_DATAFORMAT_JPEG8 (15 << 0)
-
-#define CAMDMA_REVISION_MAJOR (15 << 4)
-#define CAMDMA_REVISION_MAJOR_SHIFT 4
-#define CAMDMA_REVISION_MINOR (15 << 0)
-#define CAMDMA_REVISION_MINOR_SHIFT 0
-
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE (3 << 12)
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_FSTANDBY (0 << 12)
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_NSTANDBY (1 << 12)
-#define CAMDMA_OCP_SYSCONFIG_MIDLEMODE_SSTANDBY (2 << 12)
-#define CAMDMA_OCP_SYSCONFIG_FUNC_CLOCK (1 << 9)
-#define CAMDMA_OCP_SYSCONFIG_OCP_CLOCK (1 << 8)
-#define CAMDMA_OCP_SYSCONFIG_EMUFREE (1 << 5)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE (3 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_FIDLE (0 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_NIDLE (1 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SIDLEMODE_SIDLE (2 << 3)
-#define CAMDMA_OCP_SYSCONFIG_SOFTRESET (1 << 1)
-#define CAMDMA_OCP_SYSCONFIG_AUTOIDLE (1 << 0)
-
-#define CAMDMA_SYSSTATUS_RESETDONE (1 << 0)
-
-#define CAMDMA_GCR_ARBITRATION_RATE (0xFF << 16)
-#define CAMDMA_GCR_ARBITRATION_RATE_SHIFT 16
-#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH (0xFF << 0)
-#define CAMDMA_GCR_MAX_CHANNEL_FIFO_DEPTH_SHIFT 0
-
-#define CAMDMA_CCR_SEL_SRC_DST_SYNC (1 << 24)
-#define CAMDMA_CCR_PREFETCH (1 << 23)
-#define CAMDMA_CCR_SUPERVISOR (1 << 22)
-#define CAMDMA_CCR_SECURE (1 << 21)
-#define CAMDMA_CCR_BS (1 << 18)
-#define CAMDMA_CCR_TRANSPARENT_COPY_ENABLE (1 << 17)
-#define CAMDMA_CCR_CONSTANT_FILL_ENABLE (1 << 16)
-#define CAMDMA_CCR_DST_AMODE (3 << 14)
-#define CAMDMA_CCR_DST_AMODE_CONST_ADDR (0 << 14)
-#define CAMDMA_CCR_DST_AMODE_POST_INC (1 << 14)
-#define CAMDMA_CCR_DST_AMODE_SGL_IDX (2 << 14)
-#define CAMDMA_CCR_DST_AMODE_DBL_IDX (3 << 14)
-#define CAMDMA_CCR_SRC_AMODE (3 << 12)
-#define CAMDMA_CCR_SRC_AMODE_CONST_ADDR (0 << 12)
-#define CAMDMA_CCR_SRC_AMODE_POST_INC (1 << 12)
-#define CAMDMA_CCR_SRC_AMODE_SGL_IDX (2 << 12)
-#define CAMDMA_CCR_SRC_AMODE_DBL_IDX (3 << 12)
-#define CAMDMA_CCR_WR_ACTIVE (1 << 10)
-#define CAMDMA_CCR_RD_ACTIVE (1 << 9)
-#define CAMDMA_CCR_SUSPEND_SENSITIVE (1 << 8)
-#define CAMDMA_CCR_ENABLE (1 << 7)
-#define CAMDMA_CCR_PRIO (1 << 6)
-#define CAMDMA_CCR_FS (1 << 5)
-#define CAMDMA_CCR_SYNCHRO ((3 << 19) | (31 << 0))
-#define CAMDMA_CCR_SYNCHRO_CAMERA 0x01
-
-#define CAMDMA_CLNK_CTRL_ENABLE_LNK (1 << 15)
-#define CAMDMA_CLNK_CTRL_NEXTLCH_ID (0x1F << 0)
-#define CAMDMA_CLNK_CTRL_NEXTLCH_ID_SHIFT 0
-
-#define CAMDMA_CICR_MISALIGNED_ERR_IE (1 << 11)
-#define CAMDMA_CICR_SUPERVISOR_ERR_IE (1 << 10)
-#define CAMDMA_CICR_SECURE_ERR_IE (1 << 9)
-#define CAMDMA_CICR_TRANS_ERR_IE (1 << 8)
-#define CAMDMA_CICR_PACKET_IE (1 << 7)
-#define CAMDMA_CICR_BLOCK_IE (1 << 5)
-#define CAMDMA_CICR_LAST_IE (1 << 4)
-#define CAMDMA_CICR_FRAME_IE (1 << 3)
-#define CAMDMA_CICR_HALF_IE (1 << 2)
-#define CAMDMA_CICR_DROP_IE (1 << 1)
-
-#define CAMDMA_CSR_MISALIGNED_ERR (1 << 11)
-#define CAMDMA_CSR_SUPERVISOR_ERR (1 << 10)
-#define CAMDMA_CSR_SECURE_ERR (1 << 9)
-#define CAMDMA_CSR_TRANS_ERR (1 << 8)
-#define CAMDMA_CSR_PACKET (1 << 7)
-#define CAMDMA_CSR_SYNC (1 << 6)
-#define CAMDMA_CSR_BLOCK (1 << 5)
-#define CAMDMA_CSR_LAST (1 << 4)
-#define CAMDMA_CSR_FRAME (1 << 3)
-#define CAMDMA_CSR_HALF (1 << 2)
-#define CAMDMA_CSR_DROP (1 << 1)
-
-#define CAMDMA_CSDP_SRC_ENDIANNESS (1 << 21)
-#define CAMDMA_CSDP_SRC_ENDIANNESS_LOCK (1 << 20)
-#define CAMDMA_CSDP_DST_ENDIANNESS (1 << 19)
-#define CAMDMA_CSDP_DST_ENDIANNESS_LOCK (1 << 18)
-#define CAMDMA_CSDP_WRITE_MODE (3 << 16)
-#define CAMDMA_CSDP_WRITE_MODE_WRNP (0 << 16)
-#define CAMDMA_CSDP_WRITE_MODE_POSTED (1 << 16)
-#define CAMDMA_CSDP_WRITE_MODE_POSTED_LAST_WRNP (2 << 16)
-#define CAMDMA_CSDP_DST_BURST_EN (3 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_1 (0 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_16 (1 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_32 (2 << 14)
-#define CAMDMA_CSDP_DST_BURST_EN_64 (3 << 14)
-#define CAMDMA_CSDP_DST_PACKED (1 << 13)
-#define CAMDMA_CSDP_WR_ADD_TRSLT (15 << 9)
-#define CAMDMA_CSDP_WR_ADD_TRSLT_ENABLE_MREQADD (3 << 9)
-#define CAMDMA_CSDP_SRC_BURST_EN (3 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_1 (0 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_16 (1 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_32 (2 << 7)
-#define CAMDMA_CSDP_SRC_BURST_EN_64 (3 << 7)
-#define CAMDMA_CSDP_SRC_PACKED (1 << 6)
-#define CAMDMA_CSDP_RD_ADD_TRSLT (15 << 2)
-#define CAMDMA_CSDP_RD_ADD_TRSLT_ENABLE_MREQADD (3 << 2)
-#define CAMDMA_CSDP_DATA_TYPE (3 << 0)
-#define CAMDMA_CSDP_DATA_TYPE_8BITS (0 << 0)
-#define CAMDMA_CSDP_DATA_TYPE_16BITS (1 << 0)
-#define CAMDMA_CSDP_DATA_TYPE_32BITS (2 << 0)
-
-#define CAMMMU_SYSCONFIG_AUTOIDLE (1 << 0)
-
-/*
- *
- * Declarations.
- *
- */
-
-/* forward declarations */
-struct omap24xxcam_sgdma;
-struct omap24xxcam_dma;
-
-typedef void (*sgdma_callback_t)(struct omap24xxcam_sgdma *cam,
- u32 status, void *arg);
-typedef void (*dma_callback_t)(struct omap24xxcam_dma *cam,
- u32 status, void *arg);
-
-struct channel_state {
- dma_callback_t callback;
- void *arg;
-};
-
-/* sgdma state for each of the possible videobuf_buffers + 2 overlays */
-struct sgdma_state {
- const struct scatterlist *sglist;
- int sglen; /* number of sglist entries */
- int next_sglist; /* index of next sglist entry to process */
- unsigned int bytes_read; /* number of bytes read */
- unsigned int len; /* total length of sglist (excluding
- * bytes due to page alignment) */
- int queued_sglist; /* number of sglist entries queued for DMA */
- u32 csr; /* DMA return code */
- sgdma_callback_t callback;
- void *arg;
-};
-
-/* physical DMA channel management */
-struct omap24xxcam_dma {
- spinlock_t lock; /* Lock for the whole structure. */
-
- void __iomem *base; /* base address for dma controller */
-
- /* While dma_stop!=0, an attempt to start a new DMA transfer will
- * fail.
- */
- atomic_t dma_stop;
- int free_dmach; /* number of dma channels free */
- int next_dmach; /* index of next dma channel to use */
- struct channel_state ch_state[NUM_CAMDMA_CHANNELS];
-};
-
-/* scatter-gather DMA (scatterlist stuff) management */
-struct omap24xxcam_sgdma {
- struct omap24xxcam_dma dma;
-
- spinlock_t lock; /* Lock for the fields below. */
- int free_sgdma; /* number of free sg dma slots */
- int next_sgdma; /* index of next sg dma slot to use */
- struct sgdma_state sg_state[NUM_SG_DMA];
-
- /* Reset timer data */
- struct timer_list reset_timer;
-};
-
-/* per-device data structure */
-struct omap24xxcam_device {
- /*** mutex ***/
- /*
- * mutex serialises access to this structure. Also camera
- * opening and releasing is synchronised by this.
- */
- struct mutex mutex;
-
- struct v4l2_device v4l2_dev;
-
- /*** general driver state information ***/
- atomic_t users;
- /*
- * Lock to serialise core enabling and disabling and access to
- * sgdma_in_queue.
- */
- spinlock_t core_enable_disable_lock;
- /*
- * Number or sgdma requests in scatter-gather queue, protected
- * by the lock above.
- */
- int sgdma_in_queue;
- /*
- * Sensor interface parameters: interface type, CC_CTRL
- * register value and interface specific data.
- */
- int if_type;
- union {
- struct parallel {
- u32 xclk;
- } bt656;
- } if_u;
- u32 cc_ctrl;
-
- /*** subsystem structures ***/
- struct omap24xxcam_sgdma sgdma;
-
- /*** hardware resources ***/
- unsigned int irq;
- void __iomem *mmio_base;
- unsigned long mmio_base_phys;
- unsigned long mmio_size;
-
- /*** interfaces and device ***/
- struct v4l2_int_device *sdev;
- struct device *dev;
- struct video_device *vfd;
-
- /*** camera and sensor reset related stuff ***/
- struct work_struct sensor_reset_work;
- /*
- * We're in the middle of a reset. Don't enable core if this
- * is non-zero! This exists to help decisionmaking in a case
- * where videobuf_qbuf is called while we are in the middle of
- * a reset.
- */
- atomic_t in_reset;
- /*
- * Non-zero if we don't want any resets for now. Used to
- * prevent reset work to run when we're about to stop
- * streaming.
- */
- atomic_t reset_disable;
-
- /*** video device parameters ***/
- int capture_mem;
-
- /*** camera module clocks ***/
- struct clk *fck;
- struct clk *ick;
-
- /*** capture data ***/
- /* file handle, if streaming is on */
- struct file *streaming;
-};
-
-/* Per-file handle data. */
-struct omap24xxcam_fh {
- spinlock_t vbq_lock; /* spinlock for the videobuf queue */
- struct videobuf_queue vbq;
- struct v4l2_pix_format pix; /* serialise pix by vbq->lock */
- atomic_t field_count; /* field counter for videobuf_buffer */
- /* accessing cam here doesn't need serialisation: it's constant */
- struct omap24xxcam_device *cam;
-};
-
-/*
- *
- * Register I/O functions.
- *
- */
-
-static inline u32 omap24xxcam_reg_in(u32 __iomem *base, u32 offset)
-{
- return readl(base + offset);
-}
-
-static inline u32 omap24xxcam_reg_out(u32 __iomem *base, u32 offset,
- u32 val)
-{
- writel(val, base + offset);
- return val;
-}
-
-static inline u32 omap24xxcam_reg_merge(u32 __iomem *base, u32 offset,
- u32 val, u32 mask)
-{
- u32 __iomem *addr = base + offset;
- u32 new_val = (readl(addr) & ~mask) | (val & mask);
-
- writel(new_val, addr);
- return new_val;
-}
-
-/*
- *
- * Function prototypes.
- *
- */
-
-/* dma prototypes */
-
-void omap24xxcam_dma_hwinit(struct omap24xxcam_dma *dma);
-void omap24xxcam_dma_isr(struct omap24xxcam_dma *dma);
-
-/* sgdma prototypes */
-
-void omap24xxcam_sgdma_process(struct omap24xxcam_sgdma *sgdma);
-int omap24xxcam_sgdma_queue(struct omap24xxcam_sgdma *sgdma,
- const struct scatterlist *sglist, int sglen,
- int len, sgdma_callback_t callback, void *arg);
-void omap24xxcam_sgdma_sync(struct omap24xxcam_sgdma *sgdma);
-void omap24xxcam_sgdma_init(struct omap24xxcam_sgdma *sgdma,
- void __iomem *base,
- void (*reset_callback)(unsigned long data),
- unsigned long reset_callback_data);
-void omap24xxcam_sgdma_exit(struct omap24xxcam_sgdma *sgdma);
-
-#endif
diff --git a/drivers/staging/media/omap24xx/tcm825x.c b/drivers/staging/media/omap24xx/tcm825x.c
deleted file mode 100644
index 9d9ecf1f..0000000
--- a/drivers/staging/media/omap24xx/tcm825x.c
+++ /dev/null
@@ -1,938 +0,0 @@
-/*
- * drivers/media/i2c/tcm825x.c
- *
- * TCM825X camera sensor driver.
- *
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * Based on code from David Cohen <david.cohen@indt.org.br>
- *
- * This driver was based on ov9640 sensor driver from MontaVista
- *
- * This program is free software; you can 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/i2c.h>
-#include <linux/module.h>
-#include "v4l2-int-device.h"
-
-#include "tcm825x.h"
-
-/*
- * The sensor has two fps modes: the lower one just gives half the fps
- * at the same xclk than the high one.
- */
-#define MAX_FPS 30
-#define MIN_FPS 8
-#define MAX_HALF_FPS (MAX_FPS / 2)
-#define HIGH_FPS_MODE_LOWER_LIMIT 14
-#define DEFAULT_FPS MAX_HALF_FPS
-
-struct tcm825x_sensor {
- const struct tcm825x_platform_data *platform_data;
- struct v4l2_int_device *v4l2_int_device;
- struct i2c_client *i2c_client;
- struct v4l2_pix_format pix;
- struct v4l2_fract timeperframe;
-};
-
-/* list of image formats supported by TCM825X sensor */
-static const struct v4l2_fmtdesc tcm825x_formats[] = {
- {
- .description = "YUYV (YUV 4:2:2), packed",
- .pixelformat = V4L2_PIX_FMT_UYVY,
- }, {
- /* Note: V4L2 defines RGB565 as:
- *
- * Byte 0 Byte 1
- * g2 g1 g0 r4 r3 r2 r1 r0 b4 b3 b2 b1 b0 g5 g4 g3
- *
- * We interpret RGB565 as:
- *
- * Byte 0 Byte 1
- * g2 g1 g0 b4 b3 b2 b1 b0 r4 r3 r2 r1 r0 g5 g4 g3
- */
- .description = "RGB565, le",
- .pixelformat = V4L2_PIX_FMT_RGB565,
- },
-};
-
-#define TCM825X_NUM_CAPTURE_FORMATS ARRAY_SIZE(tcm825x_formats)
-
-/*
- * TCM825X register configuration for all combinations of pixel format and
- * image size
- */
-static const struct tcm825x_reg subqcif = { 0x20, TCM825X_PICSIZ };
-static const struct tcm825x_reg qcif = { 0x18, TCM825X_PICSIZ };
-static const struct tcm825x_reg cif = { 0x14, TCM825X_PICSIZ };
-static const struct tcm825x_reg qqvga = { 0x0c, TCM825X_PICSIZ };
-static const struct tcm825x_reg qvga = { 0x04, TCM825X_PICSIZ };
-static const struct tcm825x_reg vga = { 0x00, TCM825X_PICSIZ };
-
-static const struct tcm825x_reg yuv422 = { 0x00, TCM825X_PICFMT };
-static const struct tcm825x_reg rgb565 = { 0x02, TCM825X_PICFMT };
-
-/* Our own specific controls */
-#define V4L2_CID_ALC V4L2_CID_PRIVATE_BASE
-#define V4L2_CID_H_EDGE_EN (V4L2_CID_PRIVATE_BASE + 1)
-#define V4L2_CID_V_EDGE_EN (V4L2_CID_PRIVATE_BASE + 2)
-#define V4L2_CID_LENS (V4L2_CID_PRIVATE_BASE + 3)
-#define V4L2_CID_MAX_EXPOSURE_TIME (V4L2_CID_PRIVATE_BASE + 4)
-#define V4L2_CID_LAST_PRIV V4L2_CID_MAX_EXPOSURE_TIME
-
-/* Video controls */
-static struct vcontrol {
- struct v4l2_queryctrl qc;
- u16 reg;
- u16 start_bit;
-} video_control[] = {
- {
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Gain",
- .minimum = 0,
- .maximum = 63,
- .step = 1,
- },
- .reg = TCM825X_AG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Red Balance",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- },
- .reg = TCM825X_MRG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Blue Balance",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- },
- .reg = TCM825X_MBG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto White Balance",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_AWBSW,
- .start_bit = 7,
- },
- {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Exposure Time",
- .minimum = 0,
- .maximum = 0x1fff,
- .step = 1,
- },
- .reg = TCM825X_ESRSPD_U,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mirror Image",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_H_INV,
- .start_bit = 6,
- },
- {
- {
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Vertical Flip",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_V_INV,
- .start_bit = 7,
- },
- /* Private controls */
- {
- {
- .id = V4L2_CID_ALC,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Auto Luminance Control",
- .minimum = 0,
- .maximum = 1,
- .step = 0,
- },
- .reg = TCM825X_ALCSW,
- .start_bit = 7,
- },
- {
- {
- .id = V4L2_CID_H_EDGE_EN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Horizontal Edge Enhancement",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- },
- .reg = TCM825X_HDTG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_V_EDGE_EN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Vertical Edge Enhancement",
- .minimum = 0,
- .maximum = 0xff,
- .step = 1,
- },
- .reg = TCM825X_VDTG,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_LENS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Lens Shading Compensation",
- .minimum = 0,
- .maximum = 0x3f,
- .step = 1,
- },
- .reg = TCM825X_LENS,
- .start_bit = 0,
- },
- {
- {
- .id = V4L2_CID_MAX_EXPOSURE_TIME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Maximum Exposure Time",
- .minimum = 0,
- .maximum = 0x3,
- .step = 1,
- },
- .reg = TCM825X_ESRLIM,
- .start_bit = 5,
- },
-};
-
-
-static const struct tcm825x_reg *tcm825x_siz_reg[NUM_IMAGE_SIZES] = {
- &subqcif, &qqvga, &qcif, &qvga, &cif, &vga };
-
-static const struct tcm825x_reg *tcm825x_fmt_reg[NUM_PIXEL_FORMATS] = {
- &yuv422, &rgb565 };
-
-/*
- * Read a value from a register in an TCM825X sensor device. The value is
- * returned in 'val'.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tcm825x_read_reg(struct i2c_client *client, int reg)
-{
- int err;
- struct i2c_msg msg[2];
- u8 reg_buf, data_buf = 0;
-
- if (!client->adapter)
- return -ENODEV;
-
- msg[0].addr = client->addr;
- msg[0].flags = 0;
- msg[0].len = 1;
- msg[0].buf = &reg_buf;
- msg[1].addr = client->addr;
- msg[1].flags = I2C_M_RD;
- msg[1].len = 1;
- msg[1].buf = &data_buf;
-
- reg_buf = reg;
-
- err = i2c_transfer(client->adapter, msg, 2);
- if (err < 0)
- return err;
- return data_buf;
-}
-
-/*
- * Write a value to a register in an TCM825X sensor device.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tcm825x_write_reg(struct i2c_client *client, u8 reg, u8 val)
-{
- int err;
- struct i2c_msg msg[1];
- unsigned char data[2];
-
- if (!client->adapter)
- return -ENODEV;
-
- msg->addr = client->addr;
- msg->flags = 0;
- msg->len = 2;
- msg->buf = data;
- data[0] = reg;
- data[1] = val;
- err = i2c_transfer(client->adapter, msg, 1);
- if (err >= 0)
- return 0;
- return err;
-}
-
-static int __tcm825x_write_reg_mask(struct i2c_client *client,
- u8 reg, u8 val, u8 mask)
-{
- int rc;
-
- /* need to do read - modify - write */
- rc = tcm825x_read_reg(client, reg);
- if (rc < 0)
- return rc;
-
- rc &= (~mask); /* Clear the masked bits */
- val &= mask; /* Enforce mask on value */
- val |= rc;
-
- /* write the new value to the register */
- rc = tcm825x_write_reg(client, reg, val);
- if (rc)
- return rc;
-
- return 0;
-}
-
-#define tcm825x_write_reg_mask(client, regmask, val) \
- __tcm825x_write_reg_mask(client, TCM825X_ADDR((regmask)), val, \
- TCM825X_MASK((regmask)))
-
-
-/*
- * Initialize a list of TCM825X registers.
- * The list of registers is terminated by the pair of values
- * { TCM825X_REG_TERM, TCM825X_VAL_TERM }.
- * Returns zero if successful, or non-zero otherwise.
- */
-static int tcm825x_write_default_regs(struct i2c_client *client,
- const struct tcm825x_reg *reglist)
-{
- int err;
- const struct tcm825x_reg *next = reglist;
-
- while (!((next->reg == TCM825X_REG_TERM)
- && (next->val == TCM825X_VAL_TERM))) {
- err = tcm825x_write_reg(client, next->reg, next->val);
- if (err) {
- dev_err(&client->dev, "register writing failed\n");
- return err;
- }
- next++;
- }
-
- return 0;
-}
-
-static struct vcontrol *find_vctrl(int id)
-{
- int i;
-
- if (id < V4L2_CID_BASE)
- return NULL;
-
- for (i = 0; i < ARRAY_SIZE(video_control); i++)
- if (video_control[i].qc.id == id)
- return &video_control[i];
-
- return NULL;
-}
-
-/*
- * Find the best match for a requested image capture size. The best match
- * is chosen as the nearest match that has the same number or fewer pixels
- * as the requested size, or the smallest image size if the requested size
- * has fewer pixels than the smallest image.
- */
-static enum image_size tcm825x_find_size(struct v4l2_int_device *s,
- unsigned int width,
- unsigned int height)
-{
- enum image_size isize;
- unsigned long pixels = width * height;
- struct tcm825x_sensor *sensor = s->priv;
-
- for (isize = subQCIF; isize < VGA; isize++) {
- if (tcm825x_sizes[isize + 1].height
- * tcm825x_sizes[isize + 1].width > pixels) {
- dev_dbg(&sensor->i2c_client->dev, "size %d\n", isize);
-
- return isize;
- }
- }
-
- dev_dbg(&sensor->i2c_client->dev, "format default VGA\n");
-
- return VGA;
-}
-
-/*
- * Configure the TCM825X for current image size, pixel format, and
- * frame period. fper is the frame period (in seconds) expressed as a
- * fraction. Returns zero if successful, or non-zero otherwise. The
- * actual frame period is returned in fper.
- */
-static int tcm825x_configure(struct v4l2_int_device *s)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_pix_format *pix = &sensor->pix;
- enum image_size isize = tcm825x_find_size(s, pix->width, pix->height);
- struct v4l2_fract *fper = &sensor->timeperframe;
- enum pixel_format pfmt;
- int err;
- u32 tgt_fps;
- u8 val;
-
- /* common register initialization */
- err = tcm825x_write_default_regs(
- sensor->i2c_client, sensor->platform_data->default_regs());
- if (err)
- return err;
-
- /* configure image size */
- val = tcm825x_siz_reg[isize]->val;
- dev_dbg(&sensor->i2c_client->dev,
- "configuring image size %d\n", isize);
- err = tcm825x_write_reg_mask(sensor->i2c_client,
- tcm825x_siz_reg[isize]->reg, val);
- if (err)
- return err;
-
- /* configure pixel format */
- switch (pix->pixelformat) {
- default:
- case V4L2_PIX_FMT_RGB565:
- pfmt = RGB565;
- break;
- case V4L2_PIX_FMT_UYVY:
- pfmt = YUV422;
- break;
- }
-
- dev_dbg(&sensor->i2c_client->dev,
- "configuring pixel format %d\n", pfmt);
- val = tcm825x_fmt_reg[pfmt]->val;
-
- err = tcm825x_write_reg_mask(sensor->i2c_client,
- tcm825x_fmt_reg[pfmt]->reg, val);
- if (err)
- return err;
-
- /*
- * For frame rate < 15, the FPS reg (addr 0x02, bit 7) must be
- * set. Frame rate will be halved from the normal.
- */
- tgt_fps = fper->denominator / fper->numerator;
- if (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) {
- val = tcm825x_read_reg(sensor->i2c_client, 0x02);
- val |= 0x80;
- tcm825x_write_reg(sensor->i2c_client, 0x02, val);
- }
-
- return 0;
-}
-
-static int ioctl_queryctrl(struct v4l2_int_device *s,
- struct v4l2_queryctrl *qc)
-{
- struct vcontrol *control;
-
- control = find_vctrl(qc->id);
-
- if (control == NULL)
- return -EINVAL;
-
- *qc = control->qc;
-
- return 0;
-}
-
-static int ioctl_g_ctrl(struct v4l2_int_device *s,
- struct v4l2_control *vc)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct i2c_client *client = sensor->i2c_client;
- int val, r;
- struct vcontrol *lvc;
-
- /* exposure time is special, spread across 2 registers */
- if (vc->id == V4L2_CID_EXPOSURE) {
- int val_lower, val_upper;
-
- val_upper = tcm825x_read_reg(client,
- TCM825X_ADDR(TCM825X_ESRSPD_U));
- if (val_upper < 0)
- return val_upper;
- val_lower = tcm825x_read_reg(client,
- TCM825X_ADDR(TCM825X_ESRSPD_L));
- if (val_lower < 0)
- return val_lower;
-
- vc->value = ((val_upper & 0x1f) << 8) | (val_lower);
- return 0;
- }
-
- lvc = find_vctrl(vc->id);
- if (lvc == NULL)
- return -EINVAL;
-
- r = tcm825x_read_reg(client, TCM825X_ADDR(lvc->reg));
- if (r < 0)
- return r;
- val = r & TCM825X_MASK(lvc->reg);
- val >>= lvc->start_bit;
-
- if (val < 0)
- return val;
-
- if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
- val ^= sensor->platform_data->is_upside_down();
-
- vc->value = val;
- return 0;
-}
-
-static int ioctl_s_ctrl(struct v4l2_int_device *s,
- struct v4l2_control *vc)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct i2c_client *client = sensor->i2c_client;
- struct vcontrol *lvc;
- int val = vc->value;
-
- /* exposure time is special, spread across 2 registers */
- if (vc->id == V4L2_CID_EXPOSURE) {
- int val_lower, val_upper;
-
- val_lower = val & TCM825X_MASK(TCM825X_ESRSPD_L);
- val_upper = (val >> 8) & TCM825X_MASK(TCM825X_ESRSPD_U);
-
- if (tcm825x_write_reg_mask(client,
- TCM825X_ESRSPD_U, val_upper))
- return -EIO;
-
- if (tcm825x_write_reg_mask(client,
- TCM825X_ESRSPD_L, val_lower))
- return -EIO;
-
- return 0;
- }
-
- lvc = find_vctrl(vc->id);
- if (lvc == NULL)
- return -EINVAL;
-
- if (vc->id == V4L2_CID_HFLIP || vc->id == V4L2_CID_VFLIP)
- val ^= sensor->platform_data->is_upside_down();
-
- val = val << lvc->start_bit;
- if (tcm825x_write_reg_mask(client, lvc->reg, val))
- return -EIO;
-
- return 0;
-}
-
-static int ioctl_enum_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_fmtdesc *fmt)
-{
- int index = fmt->index;
-
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (index >= TCM825X_NUM_CAPTURE_FORMATS)
- return -EINVAL;
- break;
-
- default:
- return -EINVAL;
- }
-
- fmt->flags = tcm825x_formats[index].flags;
- strlcpy(fmt->description, tcm825x_formats[index].description,
- sizeof(fmt->description));
- fmt->pixelformat = tcm825x_formats[index].pixelformat;
-
- return 0;
-}
-
-static int ioctl_try_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_format *f)
-{
- struct tcm825x_sensor *sensor = s->priv;
- enum image_size isize;
- int ifmt;
- struct v4l2_pix_format *pix = &f->fmt.pix;
-
- isize = tcm825x_find_size(s, pix->width, pix->height);
- dev_dbg(&sensor->i2c_client->dev, "isize = %d num_capture = %lu\n",
- isize, (unsigned long)TCM825X_NUM_CAPTURE_FORMATS);
-
- pix->width = tcm825x_sizes[isize].width;
- pix->height = tcm825x_sizes[isize].height;
-
- for (ifmt = 0; ifmt < TCM825X_NUM_CAPTURE_FORMATS; ifmt++)
- if (pix->pixelformat == tcm825x_formats[ifmt].pixelformat)
- break;
-
- if (ifmt == TCM825X_NUM_CAPTURE_FORMATS)
- ifmt = 0; /* Default = YUV 4:2:2 */
-
- pix->pixelformat = tcm825x_formats[ifmt].pixelformat;
- pix->field = V4L2_FIELD_NONE;
- pix->bytesperline = pix->width * TCM825X_BYTES_PER_PIXEL;
- pix->sizeimage = pix->bytesperline * pix->height;
- pix->priv = 0;
- dev_dbg(&sensor->i2c_client->dev, "format = 0x%08x\n",
- pix->pixelformat);
-
- switch (pix->pixelformat) {
- case V4L2_PIX_FMT_UYVY:
- default:
- pix->colorspace = V4L2_COLORSPACE_JPEG;
- break;
- case V4L2_PIX_FMT_RGB565:
- pix->colorspace = V4L2_COLORSPACE_SRGB;
- break;
- }
-
- return 0;
-}
-
-static int ioctl_s_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_format *f)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_pix_format *pix = &f->fmt.pix;
- int rval;
-
- rval = ioctl_try_fmt_cap(s, f);
- if (rval)
- return rval;
-
- rval = tcm825x_configure(s);
-
- sensor->pix = *pix;
-
- return rval;
-}
-
-static int ioctl_g_fmt_cap(struct v4l2_int_device *s,
- struct v4l2_format *f)
-{
- struct tcm825x_sensor *sensor = s->priv;
-
- f->fmt.pix = sensor->pix;
-
- return 0;
-}
-
-static int ioctl_g_parm(struct v4l2_int_device *s,
- struct v4l2_streamparm *a)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_captureparm *cparm = &a->parm.capture;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memset(a, 0, sizeof(*a));
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- cparm->capability = V4L2_CAP_TIMEPERFRAME;
- cparm->timeperframe = sensor->timeperframe;
-
- return 0;
-}
-
-static int ioctl_s_parm(struct v4l2_int_device *s,
- struct v4l2_streamparm *a)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_fract *timeperframe = &a->parm.capture.timeperframe;
- u32 tgt_fps; /* target frames per secound */
- int rval;
-
- if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if ((timeperframe->numerator == 0)
- || (timeperframe->denominator == 0)) {
- timeperframe->denominator = DEFAULT_FPS;
- timeperframe->numerator = 1;
- }
-
- tgt_fps = timeperframe->denominator / timeperframe->numerator;
-
- if (tgt_fps > MAX_FPS) {
- timeperframe->denominator = MAX_FPS;
- timeperframe->numerator = 1;
- } else if (tgt_fps < MIN_FPS) {
- timeperframe->denominator = MIN_FPS;
- timeperframe->numerator = 1;
- }
-
- sensor->timeperframe = *timeperframe;
-
- rval = tcm825x_configure(s);
-
- return rval;
-}
-
-static int ioctl_s_power(struct v4l2_int_device *s, int on)
-{
- struct tcm825x_sensor *sensor = s->priv;
-
- return sensor->platform_data->power_set(on);
-}
-
-/*
- * Given the image capture format in pix, the nominal frame period in
- * timeperframe, calculate the required xclk frequency.
- *
- * TCM825X input frequency characteristics are:
- * Minimum 11.9 MHz, Typical 24.57 MHz and maximum 25/27 MHz
- */
-
-static int ioctl_g_ifparm(struct v4l2_int_device *s, struct v4l2_ifparm *p)
-{
- struct tcm825x_sensor *sensor = s->priv;
- struct v4l2_fract *timeperframe = &sensor->timeperframe;
- u32 tgt_xclk; /* target xclk */
- u32 tgt_fps; /* target frames per secound */
- int rval;
-
- rval = sensor->platform_data->ifparm(p);
- if (rval)
- return rval;
-
- tgt_fps = timeperframe->denominator / timeperframe->numerator;
-
- tgt_xclk = (tgt_fps <= HIGH_FPS_MODE_LOWER_LIMIT) ?
- (2457 * tgt_fps) / MAX_HALF_FPS :
- (2457 * tgt_fps) / MAX_FPS;
- tgt_xclk *= 10000;
-
- tgt_xclk = min(tgt_xclk, (u32)TCM825X_XCLK_MAX);
- tgt_xclk = max(tgt_xclk, (u32)TCM825X_XCLK_MIN);
-
- p->u.bt656.clock_curr = tgt_xclk;
-
- return 0;
-}
-
-static int ioctl_g_needs_reset(struct v4l2_int_device *s, void *buf)
-{
- struct tcm825x_sensor *sensor = s->priv;
-
- return sensor->platform_data->needs_reset(s, buf, &sensor->pix);
-}
-
-static int ioctl_reset(struct v4l2_int_device *s)
-{
- return -EBUSY;
-}
-
-static int ioctl_init(struct v4l2_int_device *s)
-{
- return tcm825x_configure(s);
-}
-
-static int ioctl_dev_exit(struct v4l2_int_device *s)
-{
- return 0;
-}
-
-static int ioctl_dev_init(struct v4l2_int_device *s)
-{
- struct tcm825x_sensor *sensor = s->priv;
- int r;
-
- r = tcm825x_read_reg(sensor->i2c_client, 0x01);
- if (r < 0)
- return r;
- if (r == 0) {
- dev_err(&sensor->i2c_client->dev, "device not detected\n");
- return -EIO;
- }
- return 0;
-}
-
-static struct v4l2_int_ioctl_desc tcm825x_ioctl_desc[] = {
- { vidioc_int_dev_init_num,
- (v4l2_int_ioctl_func *)ioctl_dev_init },
- { vidioc_int_dev_exit_num,
- (v4l2_int_ioctl_func *)ioctl_dev_exit },
- { vidioc_int_s_power_num,
- (v4l2_int_ioctl_func *)ioctl_s_power },
- { vidioc_int_g_ifparm_num,
- (v4l2_int_ioctl_func *)ioctl_g_ifparm },
- { vidioc_int_g_needs_reset_num,
- (v4l2_int_ioctl_func *)ioctl_g_needs_reset },
- { vidioc_int_reset_num,
- (v4l2_int_ioctl_func *)ioctl_reset },
- { vidioc_int_init_num,
- (v4l2_int_ioctl_func *)ioctl_init },
- { vidioc_int_enum_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_enum_fmt_cap },
- { vidioc_int_try_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_try_fmt_cap },
- { vidioc_int_g_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_g_fmt_cap },
- { vidioc_int_s_fmt_cap_num,
- (v4l2_int_ioctl_func *)ioctl_s_fmt_cap },
- { vidioc_int_g_parm_num,
- (v4l2_int_ioctl_func *)ioctl_g_parm },
- { vidioc_int_s_parm_num,
- (v4l2_int_ioctl_func *)ioctl_s_parm },
- { vidioc_int_queryctrl_num,
- (v4l2_int_ioctl_func *)ioctl_queryctrl },
- { vidioc_int_g_ctrl_num,
- (v4l2_int_ioctl_func *)ioctl_g_ctrl },
- { vidioc_int_s_ctrl_num,
- (v4l2_int_ioctl_func *)ioctl_s_ctrl },
-};
-
-static struct v4l2_int_slave tcm825x_slave = {
- .ioctls = tcm825x_ioctl_desc,
- .num_ioctls = ARRAY_SIZE(tcm825x_ioctl_desc),
-};
-
-static struct tcm825x_sensor tcm825x;
-
-static struct v4l2_int_device tcm825x_int_device = {
- .module = THIS_MODULE,
- .name = TCM825X_NAME,
- .priv = &tcm825x,
- .type = v4l2_int_type_slave,
- .u = {
- .slave = &tcm825x_slave,
- },
-};
-
-static int tcm825x_probe(struct i2c_client *client,
- const struct i2c_device_id *did)
-{
- struct tcm825x_sensor *sensor = &tcm825x;
-
- if (i2c_get_clientdata(client))
- return -EBUSY;
-
- sensor->platform_data = client->dev.platform_data;
-
- if (sensor->platform_data == NULL
- || !sensor->platform_data->is_okay())
- return -ENODEV;
-
- sensor->v4l2_int_device = &tcm825x_int_device;
-
- sensor->i2c_client = client;
- i2c_set_clientdata(client, sensor);
-
- /* Make the default capture format QVGA RGB565 */
- sensor->pix.width = tcm825x_sizes[QVGA].width;
- sensor->pix.height = tcm825x_sizes[QVGA].height;
- sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
-
- return v4l2_int_device_register(sensor->v4l2_int_device);
-}
-
-static int tcm825x_remove(struct i2c_client *client)
-{
- struct tcm825x_sensor *sensor = i2c_get_clientdata(client);
-
- if (!client->adapter)
- return -ENODEV; /* our client isn't attached */
-
- v4l2_int_device_unregister(sensor->v4l2_int_device);
-
- return 0;
-}
-
-static const struct i2c_device_id tcm825x_id[] = {
- { "tcm825x", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tcm825x_id);
-
-static struct i2c_driver tcm825x_i2c_driver = {
- .driver = {
- .name = TCM825X_NAME,
- },
- .probe = tcm825x_probe,
- .remove = tcm825x_remove,
- .id_table = tcm825x_id,
-};
-
-static struct tcm825x_sensor tcm825x = {
- .timeperframe = {
- .numerator = 1,
- .denominator = DEFAULT_FPS,
- },
-};
-
-static int __init tcm825x_init(void)
-{
- int rval;
-
- rval = i2c_add_driver(&tcm825x_i2c_driver);
- if (rval)
- pr_info("%s: failed registering " TCM825X_NAME "\n",
- __func__);
-
- return rval;
-}
-
-static void __exit tcm825x_exit(void)
-{
- i2c_del_driver(&tcm825x_i2c_driver);
-}
-
-/*
- * FIXME: Menelaus isn't ready (?) at module_init stage, so use
- * late_initcall for now.
- */
-late_initcall(tcm825x_init);
-module_exit(tcm825x_exit);
-
-MODULE_AUTHOR("Sakari Ailus <sakari.ailus@nokia.com>");
-MODULE_DESCRIPTION("TCM825x camera sensor driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/omap24xx/tcm825x.h b/drivers/staging/media/omap24xx/tcm825x.h
deleted file mode 100644
index 8a29636..0000000
--- a/drivers/staging/media/omap24xx/tcm825x.h
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * drivers/media/i2c/tcm825x.h
- *
- * Register definitions for the TCM825X CameraChip.
- *
- * Author: David Cohen (david.cohen@indt.org.br)
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- * This file was based on ov9640.h from MontaVista
- */
-
-#ifndef TCM825X_H
-#define TCM825X_H
-
-#include <linux/videodev2.h>
-
-#include "v4l2-int-device.h"
-
-#define TCM825X_NAME "tcm825x"
-
-#define TCM825X_MASK(x) (x & 0x00ff)
-#define TCM825X_ADDR(x) ((x & 0xff00) >> 8)
-
-/* The TCM825X I2C sensor chip has a fixed slave address of 0x3d. */
-#define TCM825X_I2C_ADDR 0x3d
-
-/*
- * define register offsets for the TCM825X sensor chip
- * OFFSET(8 bits) + MASK(8 bits)
- * MASK bit 4 and 3 are used when the register uses more than one address
- */
-#define TCM825X_FPS 0x0280
-#define TCM825X_ACF 0x0240
-#define TCM825X_DOUTBUF 0x020C
-#define TCM825X_DCLKP 0x0202
-#define TCM825X_ACFDET 0x0201
-#define TCM825X_DOUTSW 0x0380
-#define TCM825X_DATAHZ 0x0340
-#define TCM825X_PICSIZ 0x033c
-#define TCM825X_PICFMT 0x0302
-#define TCM825X_V_INV 0x0480
-#define TCM825X_H_INV 0x0440
-#define TCM825X_ESRLSW 0x0430
-#define TCM825X_V_LENGTH 0x040F
-#define TCM825X_ALCSW 0x0580
-#define TCM825X_ESRLIM 0x0560
-#define TCM825X_ESRSPD_U 0x051F
-#define TCM825X_ESRSPD_L 0x06FF
-#define TCM825X_AG 0x07FF
-#define TCM825X_ESRSPD2 0x06FF
-#define TCM825X_ALCMODE 0x0830
-#define TCM825X_ALCH 0x080F
-#define TCM825X_ALCL 0x09FF
-#define TCM825X_AWBSW 0x0A80
-#define TCM825X_MRG 0x0BFF
-#define TCM825X_MBG 0x0CFF
-#define TCM825X_GAMSW 0x0D80
-#define TCM825X_HDTG 0x0EFF
-#define TCM825X_VDTG 0x0FFF
-#define TCM825X_HDTCORE 0x10F0
-#define TCM825X_VDTCORE 0x100F
-#define TCM825X_CONT 0x11FF
-#define TCM825X_BRIGHT 0x12FF
-#define TCM825X_VHUE 0x137F
-#define TCM825X_UHUE 0x147F
-#define TCM825X_VGAIN 0x153F
-#define TCM825X_UGAIN 0x163F
-#define TCM825X_UVCORE 0x170F
-#define TCM825X_SATU 0x187F
-#define TCM825X_MHMODE 0x1980
-#define TCM825X_MHLPFSEL 0x1940
-#define TCM825X_YMODE 0x1930
-#define TCM825X_MIXHG 0x1907
-#define TCM825X_LENS 0x1A3F
-#define TCM825X_AGLIM 0x1BE0
-#define TCM825X_LENSRPOL 0x1B10
-#define TCM825X_LENSRGAIN 0x1B0F
-#define TCM825X_ES100S 0x1CFF
-#define TCM825X_ES120S 0x1DFF
-#define TCM825X_DMASK 0x1EC0
-#define TCM825X_CODESW 0x1E20
-#define TCM825X_CODESEL 0x1E10
-#define TCM825X_TESPIC 0x1E04
-#define TCM825X_PICSEL 0x1E03
-#define TCM825X_HNUM 0x20FF
-#define TCM825X_VOUTPH 0x287F
-#define TCM825X_ESROUT 0x327F
-#define TCM825X_ESROUT2 0x33FF
-#define TCM825X_AGOUT 0x34FF
-#define TCM825X_DGOUT 0x353F
-#define TCM825X_AGSLOW1 0x39C0
-#define TCM825X_FLLSMODE 0x3930
-#define TCM825X_FLLSLIM 0x390F
-#define TCM825X_DETSEL 0x3AF0
-#define TCM825X_ACDETNC 0x3A0F
-#define TCM825X_AGSLOW2 0x3BC0
-#define TCM825X_DG 0x3B3F
-#define TCM825X_REJHLEV 0x3CFF
-#define TCM825X_ALCLOCK 0x3D80
-#define TCM825X_FPSLNKSW 0x3D40
-#define TCM825X_ALCSPD 0x3D30
-#define TCM825X_REJH 0x3D03
-#define TCM825X_SHESRSW 0x3E80
-#define TCM825X_ESLIMSEL 0x3E40
-#define TCM825X_SHESRSPD 0x3E30
-#define TCM825X_ELSTEP 0x3E0C
-#define TCM825X_ELSTART 0x3E03
-#define TCM825X_AGMIN 0x3FFF
-#define TCM825X_PREGRG 0x423F
-#define TCM825X_PREGBG 0x433F
-#define TCM825X_PRERG 0x443F
-#define TCM825X_PREBG 0x453F
-#define TCM825X_MSKBR 0x477F
-#define TCM825X_MSKGR 0x487F
-#define TCM825X_MSKRB 0x497F
-#define TCM825X_MSKGB 0x4A7F
-#define TCM825X_MSKRG 0x4B7F
-#define TCM825X_MSKBG 0x4C7F
-#define TCM825X_HDTCSW 0x4D80
-#define TCM825X_VDTCSW 0x4D40
-#define TCM825X_DTCYL 0x4D3F
-#define TCM825X_HDTPSW 0x4E80
-#define TCM825X_VDTPSW 0x4E40
-#define TCM825X_DTCGAIN 0x4E3F
-#define TCM825X_DTLLIMSW 0x4F10
-#define TCM825X_DTLYLIM 0x4F0F
-#define TCM825X_YLCUTLMSK 0x5080
-#define TCM825X_YLCUTL 0x503F
-#define TCM825X_YLCUTHMSK 0x5180
-#define TCM825X_YLCUTH 0x513F
-#define TCM825X_UVSKNC 0x527F
-#define TCM825X_UVLJ 0x537F
-#define TCM825X_WBGMIN 0x54FF
-#define TCM825X_WBGMAX 0x55FF
-#define TCM825X_WBSPDUP 0x5603
-#define TCM825X_ALLAREA 0x5820
-#define TCM825X_WBLOCK 0x5810
-#define TCM825X_WB2SP 0x580F
-#define TCM825X_KIZUSW 0x5920
-#define TCM825X_PBRSW 0x5910
-#define TCM825X_ABCSW 0x5903
-#define TCM825X_PBDLV 0x5AFF
-#define TCM825X_PBC1LV 0x5BFF
-
-#define TCM825X_NUM_REGS (TCM825X_ADDR(TCM825X_PBC1LV) + 1)
-
-#define TCM825X_BYTES_PER_PIXEL 2
-
-#define TCM825X_REG_TERM 0xff /* terminating list entry for reg */
-#define TCM825X_VAL_TERM 0xff /* terminating list entry for val */
-
-/* define a structure for tcm825x register initialization values */
-struct tcm825x_reg {
- u8 val;
- u16 reg;
-};
-
-enum image_size { subQCIF = 0, QQVGA, QCIF, QVGA, CIF, VGA };
-enum pixel_format { YUV422 = 0, RGB565 };
-#define NUM_IMAGE_SIZES 6
-#define NUM_PIXEL_FORMATS 2
-
-#define TCM825X_XCLK_MIN 11900000
-#define TCM825X_XCLK_MAX 25000000
-
-struct capture_size {
- unsigned long width;
- unsigned long height;
-};
-
-struct tcm825x_platform_data {
- /* Is the sensor usable? Doesn't yet mean it's there, but you
- * can try! */
- int (*is_okay)(void);
- /* Set power state, zero is off, non-zero is on. */
- int (*power_set)(int power);
- /* Default registers written after power-on or reset. */
- const struct tcm825x_reg * (*default_regs)(void);
- int (*needs_reset)(struct v4l2_int_device *s, void *buf,
- struct v4l2_pix_format *fmt);
- int (*ifparm)(struct v4l2_ifparm *p);
- int (*is_upside_down)(void);
-};
-
-/* Array of image sizes supported by TCM825X. These must be ordered from
- * smallest image size to largest.
- */
-static const struct capture_size tcm825x_sizes[] = {
- { 128, 96 }, /* subQCIF */
- { 160, 120 }, /* QQVGA */
- { 176, 144 }, /* QCIF */
- { 320, 240 }, /* QVGA */
- { 352, 288 }, /* CIF */
- { 640, 480 }, /* VGA */
-};
-
-#endif /* ifndef TCM825X_H */
diff --git a/drivers/staging/media/omap24xx/v4l2-int-device.c b/drivers/staging/media/omap24xx/v4l2-int-device.c
deleted file mode 100644
index 427a890..0000000
--- a/drivers/staging/media/omap24xx/v4l2-int-device.c
+++ /dev/null
@@ -1,164 +0,0 @@
-/*
- * drivers/media/video/v4l2-int-device.c
- *
- * V4L2 internal ioctl interface.
- *
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#include <linux/kernel.h>
-#include <linux/list.h>
-#include <linux/sort.h>
-#include <linux/string.h>
-#include <linux/module.h>
-
-#include "v4l2-int-device.h"
-
-static DEFINE_MUTEX(mutex);
-static LIST_HEAD(int_list);
-
-void v4l2_int_device_try_attach_all(void)
-{
- struct v4l2_int_device *m, *s;
-
- list_for_each_entry(m, &int_list, head) {
- if (m->type != v4l2_int_type_master)
- continue;
-
- list_for_each_entry(s, &int_list, head) {
- if (s->type != v4l2_int_type_slave)
- continue;
-
- /* Slave is connected? */
- if (s->u.slave->master)
- continue;
-
- /* Slave wants to attach to master? */
- if (s->u.slave->attach_to[0] != 0
- && strncmp(m->name, s->u.slave->attach_to,
- V4L2NAMESIZE))
- continue;
-
- if (!try_module_get(m->module))
- continue;
-
- s->u.slave->master = m;
- if (m->u.master->attach(s)) {
- s->u.slave->master = NULL;
- module_put(m->module);
- continue;
- }
- }
- }
-}
-EXPORT_SYMBOL_GPL(v4l2_int_device_try_attach_all);
-
-static int ioctl_sort_cmp(const void *a, const void *b)
-{
- const struct v4l2_int_ioctl_desc *d1 = a, *d2 = b;
-
- if (d1->num > d2->num)
- return 1;
-
- if (d1->num < d2->num)
- return -1;
-
- return 0;
-}
-
-int v4l2_int_device_register(struct v4l2_int_device *d)
-{
- if (d->type == v4l2_int_type_slave)
- sort(d->u.slave->ioctls, d->u.slave->num_ioctls,
- sizeof(struct v4l2_int_ioctl_desc),
- &ioctl_sort_cmp, NULL);
- mutex_lock(&mutex);
- list_add(&d->head, &int_list);
- v4l2_int_device_try_attach_all();
- mutex_unlock(&mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(v4l2_int_device_register);
-
-void v4l2_int_device_unregister(struct v4l2_int_device *d)
-{
- mutex_lock(&mutex);
- list_del(&d->head);
- if (d->type == v4l2_int_type_slave
- && d->u.slave->master != NULL) {
- d->u.slave->master->u.master->detach(d);
- module_put(d->u.slave->master->module);
- d->u.slave->master = NULL;
- }
- mutex_unlock(&mutex);
-}
-EXPORT_SYMBOL_GPL(v4l2_int_device_unregister);
-
-/* Adapted from search_extable in extable.c. */
-static v4l2_int_ioctl_func *find_ioctl(struct v4l2_int_slave *slave, int cmd,
- v4l2_int_ioctl_func *no_such_ioctl)
-{
- const struct v4l2_int_ioctl_desc *first = slave->ioctls;
- const struct v4l2_int_ioctl_desc *last =
- first + slave->num_ioctls - 1;
-
- while (first <= last) {
- const struct v4l2_int_ioctl_desc *mid;
-
- mid = (last - first) / 2 + first;
-
- if (mid->num < cmd)
- first = mid + 1;
- else if (mid->num > cmd)
- last = mid - 1;
- else
- return mid->func;
- }
-
- return no_such_ioctl;
-}
-
-static int no_such_ioctl_0(struct v4l2_int_device *d)
-{
- return -ENOIOCTLCMD;
-}
-
-int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd)
-{
- return ((v4l2_int_ioctl_func_0 *)
- find_ioctl(d->u.slave, cmd,
- (v4l2_int_ioctl_func *)no_such_ioctl_0))(d);
-}
-EXPORT_SYMBOL_GPL(v4l2_int_ioctl_0);
-
-static int no_such_ioctl_1(struct v4l2_int_device *d, void *arg)
-{
- return -ENOIOCTLCMD;
-}
-
-int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg)
-{
- return ((v4l2_int_ioctl_func_1 *)
- find_ioctl(d->u.slave, cmd,
- (v4l2_int_ioctl_func *)no_such_ioctl_1))(d, arg);
-}
-EXPORT_SYMBOL_GPL(v4l2_int_ioctl_1);
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/staging/media/omap24xx/v4l2-int-device.h b/drivers/staging/media/omap24xx/v4l2-int-device.h
deleted file mode 100644
index 0286c95..0000000
--- a/drivers/staging/media/omap24xx/v4l2-int-device.h
+++ /dev/null
@@ -1,305 +0,0 @@
-/*
- * include/media/v4l2-int-device.h
- *
- * V4L2 internal ioctl interface.
- *
- * Copyright (C) 2007 Nokia Corporation.
- *
- * Contact: Sakari Ailus <sakari.ailus@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- */
-
-#ifndef V4L2_INT_DEVICE_H
-#define V4L2_INT_DEVICE_H
-
-#include <media/v4l2-common.h>
-
-#define V4L2NAMESIZE 32
-
-/*
- *
- * The internal V4L2 device interface core.
- *
- */
-
-enum v4l2_int_type {
- v4l2_int_type_master = 1,
- v4l2_int_type_slave
-};
-
-struct module;
-
-struct v4l2_int_device;
-
-struct v4l2_int_master {
- int (*attach)(struct v4l2_int_device *slave);
- void (*detach)(struct v4l2_int_device *slave);
-};
-
-typedef int (v4l2_int_ioctl_func)(struct v4l2_int_device *);
-typedef int (v4l2_int_ioctl_func_0)(struct v4l2_int_device *);
-typedef int (v4l2_int_ioctl_func_1)(struct v4l2_int_device *, void *);
-
-struct v4l2_int_ioctl_desc {
- int num;
- v4l2_int_ioctl_func *func;
-};
-
-struct v4l2_int_slave {
- /* Don't touch master. */
- struct v4l2_int_device *master;
-
- char attach_to[V4L2NAMESIZE];
-
- int num_ioctls;
- struct v4l2_int_ioctl_desc *ioctls;
-};
-
-struct v4l2_int_device {
- /* Don't touch head. */
- struct list_head head;
-
- struct module *module;
-
- char name[V4L2NAMESIZE];
-
- enum v4l2_int_type type;
- union {
- struct v4l2_int_master *master;
- struct v4l2_int_slave *slave;
- } u;
-
- void *priv;
-};
-
-void v4l2_int_device_try_attach_all(void);
-
-int v4l2_int_device_register(struct v4l2_int_device *d);
-void v4l2_int_device_unregister(struct v4l2_int_device *d);
-
-int v4l2_int_ioctl_0(struct v4l2_int_device *d, int cmd);
-int v4l2_int_ioctl_1(struct v4l2_int_device *d, int cmd, void *arg);
-
-/*
- *
- * Types and definitions for IOCTL commands.
- *
- */
-
-enum v4l2_power {
- V4L2_POWER_OFF = 0,
- V4L2_POWER_ON,
- V4L2_POWER_STANDBY,
-};
-
-/* Slave interface type. */
-enum v4l2_if_type {
- /*
- * Parallel 8-, 10- or 12-bit interface, used by for example
- * on certain image sensors.
- */
- V4L2_IF_TYPE_BT656,
-};
-
-enum v4l2_if_type_bt656_mode {
- /*
- * Modes without Bt synchronisation codes. Separate
- * synchronisation signal lines are used.
- */
- V4L2_IF_TYPE_BT656_MODE_NOBT_8BIT,
- V4L2_IF_TYPE_BT656_MODE_NOBT_10BIT,
- V4L2_IF_TYPE_BT656_MODE_NOBT_12BIT,
- /*
- * Use Bt synchronisation codes. The vertical and horizontal
- * synchronisation is done based on synchronisation codes.
- */
- V4L2_IF_TYPE_BT656_MODE_BT_8BIT,
- V4L2_IF_TYPE_BT656_MODE_BT_10BIT,
-};
-
-struct v4l2_if_type_bt656 {
- /*
- * 0: Frame begins when vsync is high.
- * 1: Frame begins when vsync changes from low to high.
- */
- unsigned frame_start_on_rising_vs:1;
- /* Use Bt synchronisation codes for sync correction. */
- unsigned bt_sync_correct:1;
- /* Swap every two adjacent image data elements. */
- unsigned swap:1;
- /* Inverted latch clock polarity from slave. */
- unsigned latch_clk_inv:1;
- /* Hs polarity. 0 is active high, 1 active low. */
- unsigned nobt_hs_inv:1;
- /* Vs polarity. 0 is active high, 1 active low. */
- unsigned nobt_vs_inv:1;
- enum v4l2_if_type_bt656_mode mode;
- /* Minimum accepted bus clock for slave (in Hz). */
- u32 clock_min;
- /* Maximum accepted bus clock for slave. */
- u32 clock_max;
- /*
- * Current wish of the slave. May only change in response to
- * ioctls that affect image capture.
- */
- u32 clock_curr;
-};
-
-struct v4l2_ifparm {
- enum v4l2_if_type if_type;
- union {
- struct v4l2_if_type_bt656 bt656;
- } u;
-};
-
-/* IOCTL command numbers. */
-enum v4l2_int_ioctl_num {
- /*
- *
- * "Proper" V4L ioctls, as in struct video_device.
- *
- */
- vidioc_int_enum_fmt_cap_num = 1,
- vidioc_int_g_fmt_cap_num,
- vidioc_int_s_fmt_cap_num,
- vidioc_int_try_fmt_cap_num,
- vidioc_int_queryctrl_num,
- vidioc_int_g_ctrl_num,
- vidioc_int_s_ctrl_num,
- vidioc_int_cropcap_num,
- vidioc_int_g_crop_num,
- vidioc_int_s_crop_num,
- vidioc_int_g_parm_num,
- vidioc_int_s_parm_num,
- vidioc_int_querystd_num,
- vidioc_int_s_std_num,
- vidioc_int_s_video_routing_num,
-
- /*
- *
- * Strictly internal ioctls.
- *
- */
- /* Initialise the device when slave attaches to the master. */
- vidioc_int_dev_init_num = 1000,
- /* Delinitialise the device at slave detach. */
- vidioc_int_dev_exit_num,
- /* Set device power state. */
- vidioc_int_s_power_num,
- /*
- * Get slave private data, e.g. platform-specific slave
- * configuration used by the master.
- */
- vidioc_int_g_priv_num,
- /* Get slave interface parameters. */
- vidioc_int_g_ifparm_num,
- /* Does the slave need to be reset after VIDIOC_DQBUF? */
- vidioc_int_g_needs_reset_num,
- vidioc_int_enum_framesizes_num,
- vidioc_int_enum_frameintervals_num,
-
- /*
- *
- * VIDIOC_INT_* ioctls.
- *
- */
- /* VIDIOC_INT_RESET */
- vidioc_int_reset_num,
- /* VIDIOC_INT_INIT */
- vidioc_int_init_num,
-
- /*
- *
- * Start of private ioctls.
- *
- */
- vidioc_int_priv_start_num = 2000,
-};
-
-/*
- *
- * IOCTL wrapper functions for better type checking.
- *
- */
-
-#define V4L2_INT_WRAPPER_0(name) \
- static inline int vidioc_int_##name(struct v4l2_int_device *d) \
- { \
- return v4l2_int_ioctl_0(d, vidioc_int_##name##_num); \
- } \
- \
- static inline struct v4l2_int_ioctl_desc \
- vidioc_int_##name##_cb(int (*func) \
- (struct v4l2_int_device *)) \
- { \
- struct v4l2_int_ioctl_desc desc; \
- \
- desc.num = vidioc_int_##name##_num; \
- desc.func = (v4l2_int_ioctl_func *)func; \
- \
- return desc; \
- }
-
-#define V4L2_INT_WRAPPER_1(name, arg_type, asterisk) \
- static inline int vidioc_int_##name(struct v4l2_int_device *d, \
- arg_type asterisk arg) \
- { \
- return v4l2_int_ioctl_1(d, vidioc_int_##name##_num, \
- (void *)(unsigned long)arg); \
- } \
- \
- static inline struct v4l2_int_ioctl_desc \
- vidioc_int_##name##_cb(int (*func) \
- (struct v4l2_int_device *, \
- arg_type asterisk)) \
- { \
- struct v4l2_int_ioctl_desc desc; \
- \
- desc.num = vidioc_int_##name##_num; \
- desc.func = (v4l2_int_ioctl_func *)func; \
- \
- return desc; \
- }
-
-V4L2_INT_WRAPPER_1(enum_fmt_cap, struct v4l2_fmtdesc, *);
-V4L2_INT_WRAPPER_1(g_fmt_cap, struct v4l2_format, *);
-V4L2_INT_WRAPPER_1(s_fmt_cap, struct v4l2_format, *);
-V4L2_INT_WRAPPER_1(try_fmt_cap, struct v4l2_format, *);
-V4L2_INT_WRAPPER_1(queryctrl, struct v4l2_queryctrl, *);
-V4L2_INT_WRAPPER_1(g_ctrl, struct v4l2_control, *);
-V4L2_INT_WRAPPER_1(s_ctrl, struct v4l2_control, *);
-V4L2_INT_WRAPPER_1(cropcap, struct v4l2_cropcap, *);
-V4L2_INT_WRAPPER_1(g_crop, struct v4l2_crop, *);
-V4L2_INT_WRAPPER_1(s_crop, struct v4l2_crop, *);
-V4L2_INT_WRAPPER_1(g_parm, struct v4l2_streamparm, *);
-V4L2_INT_WRAPPER_1(s_parm, struct v4l2_streamparm, *);
-V4L2_INT_WRAPPER_1(querystd, v4l2_std_id, *);
-V4L2_INT_WRAPPER_1(s_std, v4l2_std_id, *);
-V4L2_INT_WRAPPER_1(s_video_routing, struct v4l2_routing, *);
-
-V4L2_INT_WRAPPER_0(dev_init);
-V4L2_INT_WRAPPER_0(dev_exit);
-V4L2_INT_WRAPPER_1(s_power, enum v4l2_power, );
-V4L2_INT_WRAPPER_1(g_priv, void, *);
-V4L2_INT_WRAPPER_1(g_ifparm, struct v4l2_ifparm, *);
-V4L2_INT_WRAPPER_1(g_needs_reset, void, *);
-V4L2_INT_WRAPPER_1(enum_framesizes, struct v4l2_frmsizeenum, *);
-V4L2_INT_WRAPPER_1(enum_frameintervals, struct v4l2_frmivalenum, *);
-
-V4L2_INT_WRAPPER_0(reset);
-V4L2_INT_WRAPPER_0(init);
-
-#endif
diff --git a/drivers/staging/media/omap4iss/iss_csi2.c b/drivers/staging/media/omap4iss/iss_csi2.c
index 92c2d5b..7dbf68c 100644
--- a/drivers/staging/media/omap4iss/iss_csi2.c
+++ b/drivers/staging/media/omap4iss/iss_csi2.c
@@ -93,20 +93,20 @@ static void csi2_recv_config(struct iss_csi2_device *csi2,
}
static const unsigned int csi2_input_fmts[] = {
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16,
};
/* To set the format on the CSI2 requires a mapping function that takes
@@ -201,26 +201,26 @@ static u16 csi2_ctx_map_format(struct iss_csi2_device *csi2)
int fmtidx, destidx;
switch (fmt->code) {
- case V4L2_MBUS_FMT_SGRBG10_1X10:
- case V4L2_MBUS_FMT_SRGGB10_1X10:
- case V4L2_MBUS_FMT_SBGGR10_1X10:
- case V4L2_MBUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
fmtidx = 0;
break;
- case V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8:
- case V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8:
+ case MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8:
fmtidx = 1;
break;
- case V4L2_MBUS_FMT_SBGGR8_1X8:
- case V4L2_MBUS_FMT_SGBRG8_1X8:
- case V4L2_MBUS_FMT_SGRBG8_1X8:
- case V4L2_MBUS_FMT_SRGGB8_1X8:
+ case MEDIA_BUS_FMT_SBGGR8_1X8:
+ case MEDIA_BUS_FMT_SGBRG8_1X8:
+ case MEDIA_BUS_FMT_SGRBG8_1X8:
+ case MEDIA_BUS_FMT_SRGGB8_1X8:
fmtidx = 2;
break;
- case V4L2_MBUS_FMT_UYVY8_1X16:
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
fmtidx = 3;
break;
default:
@@ -817,7 +817,7 @@ csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh,
unsigned int pad, struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
- enum v4l2_mbus_pixelcode pixelcode;
+ u32 pixelcode;
struct v4l2_mbus_framefmt *format;
const struct iss_format_info *info;
unsigned int i;
@@ -832,7 +832,7 @@ csi2_try_format(struct iss_csi2_device *csi2, struct v4l2_subdev_fh *fh,
/* If not found, use SGRBG10 as default */
if (i >= ARRAY_SIZE(csi2_input_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
fmt->width = clamp_t(u32, fmt->width, 1, 8191);
fmt->height = clamp_t(u32, fmt->height, 1, 8191);
@@ -1020,7 +1020,7 @@ static int csi2_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = CSI2_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
csi2_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/omap4iss/iss_ipipe.c b/drivers/staging/media/omap4iss/iss_ipipe.c
index 5404200..a1a46ef 100644
--- a/drivers/staging/media/omap4iss/iss_ipipe.c
+++ b/drivers/staging/media/omap4iss/iss_ipipe.c
@@ -28,10 +28,10 @@ __ipipe_get_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
unsigned int pad, enum v4l2_subdev_format_whence which);
static const unsigned int ipipe_fmts[] = {
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
};
/*
@@ -211,7 +211,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
/* If not found, use SGRBG10 as default */
if (i >= ARRAY_SIZE(ipipe_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
/* Clamp the input size. */
fmt->width = clamp_t(u32, width, 1, 8192);
@@ -223,7 +223,7 @@ ipipe_try_format(struct iss_ipipe_device *ipipe, struct v4l2_subdev_fh *fh,
format = __ipipe_get_format(ipipe, fh, IPIPE_PAD_SINK, which);
memcpy(fmt, format, sizeof(*fmt));
- fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
fmt->width = clamp_t(u32, width, 32, fmt->width);
fmt->height = clamp_t(u32, height, 32, fmt->height);
fmt->colorspace = V4L2_COLORSPACE_JPEG;
@@ -257,7 +257,7 @@ static int ipipe_enum_mbus_code(struct v4l2_subdev *sd,
if (code->index != 0)
return -EINVAL;
- code->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ code->code = MEDIA_BUS_FMT_UYVY8_1X16;
break;
default:
@@ -385,7 +385,7 @@ static int ipipe_init_formats(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh)
memset(&format, 0, sizeof(format));
format.pad = IPIPE_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
ipipe_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/omap4iss/iss_ipipeif.c b/drivers/staging/media/omap4iss/iss_ipipeif.c
index 75f6a15..32a7483 100644
--- a/drivers/staging/media/omap4iss/iss_ipipeif.c
+++ b/drivers/staging/media/omap4iss/iss_ipipeif.c
@@ -24,12 +24,12 @@
#include "iss_ipipeif.h"
static const unsigned int ipipeif_fmts[] = {
- V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16,
};
/*
@@ -140,8 +140,8 @@ static void ipipeif_configure(struct iss_ipipeif_device *ipipeif)
/* Select ISIF/IPIPEIF input format */
switch (format->code) {
- case V4L2_MBUS_FMT_UYVY8_1X16:
- case V4L2_MBUS_FMT_YUYV8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_YUYV8_1X16:
iss_reg_update(iss, OMAP4_ISS_MEM_ISP_ISIF, ISIF_MODESET,
ISIF_MODESET_CCDMD | ISIF_MODESET_INPMOD_MASK |
ISIF_MODESET_CCDW_MASK,
@@ -151,25 +151,25 @@ static void ipipeif_configure(struct iss_ipipeif_device *ipipeif)
IPIPEIF_CFG2_YUV8, IPIPEIF_CFG2_YUV16);
break;
- case V4L2_MBUS_FMT_SGRBG10_1X10:
+ case MEDIA_BUS_FMT_SGRBG10_1X10:
isif_ccolp = ISIF_CCOLP_CP0_F0_GR |
ISIF_CCOLP_CP1_F0_R |
ISIF_CCOLP_CP2_F0_B |
ISIF_CCOLP_CP3_F0_GB;
goto cont_raw;
- case V4L2_MBUS_FMT_SRGGB10_1X10:
+ case MEDIA_BUS_FMT_SRGGB10_1X10:
isif_ccolp = ISIF_CCOLP_CP0_F0_R |
ISIF_CCOLP_CP1_F0_GR |
ISIF_CCOLP_CP2_F0_GB |
ISIF_CCOLP_CP3_F0_B;
goto cont_raw;
- case V4L2_MBUS_FMT_SBGGR10_1X10:
+ case MEDIA_BUS_FMT_SBGGR10_1X10:
isif_ccolp = ISIF_CCOLP_CP0_F0_B |
ISIF_CCOLP_CP1_F0_GB |
ISIF_CCOLP_CP2_F0_GR |
ISIF_CCOLP_CP3_F0_R;
goto cont_raw;
- case V4L2_MBUS_FMT_SGBRG10_1X10:
+ case MEDIA_BUS_FMT_SGBRG10_1X10:
isif_ccolp = ISIF_CCOLP_CP0_F0_GB |
ISIF_CCOLP_CP1_F0_B |
ISIF_CCOLP_CP2_F0_R |
@@ -415,7 +415,7 @@ ipipeif_try_format(struct iss_ipipeif_device *ipipeif,
/* If not found, use SGRBG10 as default */
if (i >= ARRAY_SIZE(ipipeif_fmts))
- fmt->code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ fmt->code = MEDIA_BUS_FMT_SGRBG10_1X10;
/* Clamp the input size. */
fmt->width = clamp_t(u32, width, 1, 8192);
@@ -625,7 +625,7 @@ static int ipipeif_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = IPIPEIF_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_SGRBG10_1X10;
+ format.format.code = MEDIA_BUS_FMT_SGRBG10_1X10;
format.format.width = 4096;
format.format.height = 4096;
ipipeif_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/omap4iss/iss_resizer.c b/drivers/staging/media/omap4iss/iss_resizer.c
index a21e356..88522a8 100644
--- a/drivers/staging/media/omap4iss/iss_resizer.c
+++ b/drivers/staging/media/omap4iss/iss_resizer.c
@@ -24,8 +24,8 @@
#include "iss_resizer.h"
static const unsigned int resizer_fmts[] = {
- V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16,
};
/*
@@ -156,8 +156,8 @@ static void resizer_set_outaddr(struct iss_resizer_device *resizer, u32 addr)
addr & 0xffff);
/* Program UV buffer address... Hardcoded to be contiguous! */
- if ((informat->code == V4L2_MBUS_FMT_UYVY8_1X16) &&
- (outformat->code == V4L2_MBUS_FMT_YUYV8_1_5X8)) {
+ if ((informat->code == MEDIA_BUS_FMT_UYVY8_1X16) &&
+ (outformat->code == MEDIA_BUS_FMT_YUYV8_1_5X8)) {
u32 c_addr = addr + (resizer->video_out.bpl_value *
(outformat->height - 1));
@@ -242,8 +242,8 @@ static void resizer_configure(struct iss_resizer_device *resizer)
resizer->video_out.bpl_value);
/* UYVY -> NV12 conversion */
- if ((informat->code == V4L2_MBUS_FMT_UYVY8_1X16) &&
- (outformat->code == V4L2_MBUS_FMT_YUYV8_1_5X8)) {
+ if ((informat->code == MEDIA_BUS_FMT_UYVY8_1X16) &&
+ (outformat->code == MEDIA_BUS_FMT_YUYV8_1_5X8)) {
iss_reg_write(iss, OMAP4_ISS_MEM_ISP_RESIZER, RZA_420,
RSZ_420_CEN | RSZ_420_YEN);
@@ -457,7 +457,7 @@ resizer_try_format(struct iss_resizer_device *resizer,
struct v4l2_mbus_framefmt *fmt,
enum v4l2_subdev_format_whence which)
{
- enum v4l2_mbus_pixelcode pixelcode;
+ u32 pixelcode;
struct v4l2_mbus_framefmt *format;
unsigned int width = fmt->width;
unsigned int height = fmt->height;
@@ -472,7 +472,7 @@ resizer_try_format(struct iss_resizer_device *resizer,
/* If not found, use UYVY as default */
if (i >= ARRAY_SIZE(resizer_fmts))
- fmt->code = V4L2_MBUS_FMT_UYVY8_1X16;
+ fmt->code = MEDIA_BUS_FMT_UYVY8_1X16;
/* Clamp the input size. */
fmt->width = clamp_t(u32, width, 1, 8192);
@@ -485,8 +485,8 @@ resizer_try_format(struct iss_resizer_device *resizer,
which);
memcpy(fmt, format, sizeof(*fmt));
- if ((pixelcode == V4L2_MBUS_FMT_YUYV8_1_5X8) &&
- (fmt->code == V4L2_MBUS_FMT_UYVY8_1X16))
+ if ((pixelcode == MEDIA_BUS_FMT_YUYV8_1_5X8) &&
+ (fmt->code == MEDIA_BUS_FMT_UYVY8_1X16))
fmt->code = pixelcode;
/* The data formatter truncates the number of horizontal output
@@ -537,9 +537,9 @@ static int resizer_enum_mbus_code(struct v4l2_subdev *sd,
}
switch (format->code) {
- case V4L2_MBUS_FMT_UYVY8_1X16:
+ case MEDIA_BUS_FMT_UYVY8_1X16:
if (code->index == 1)
- code->code = V4L2_MBUS_FMT_YUYV8_1_5X8;
+ code->code = MEDIA_BUS_FMT_YUYV8_1_5X8;
else
return -EINVAL;
break;
@@ -680,7 +680,7 @@ static int resizer_init_formats(struct v4l2_subdev *sd,
memset(&format, 0, sizeof(format));
format.pad = RESIZER_PAD_SINK;
format.which = fh ? V4L2_SUBDEV_FORMAT_TRY : V4L2_SUBDEV_FORMAT_ACTIVE;
- format.format.code = V4L2_MBUS_FMT_UYVY8_1X16;
+ format.format.code = MEDIA_BUS_FMT_UYVY8_1X16;
format.format.width = 4096;
format.format.height = 4096;
resizer_set_format(sd, fh, &format);
diff --git a/drivers/staging/media/omap4iss/iss_video.c b/drivers/staging/media/omap4iss/iss_video.c
index 5d62503..cdee596 100644
--- a/drivers/staging/media/omap4iss/iss_video.c
+++ b/drivers/staging/media/omap4iss/iss_video.c
@@ -34,67 +34,67 @@ MODULE_PARM_DESC(debug, "activates debug info");
*/
static struct iss_format_info formats[] = {
- { V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
- V4L2_MBUS_FMT_Y8_1X8, V4L2_MBUS_FMT_Y8_1X8,
+ { MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
+ MEDIA_BUS_FMT_Y8_1X8, MEDIA_BUS_FMT_Y8_1X8,
V4L2_PIX_FMT_GREY, 8, "Greyscale 8 bpp", },
- { V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y10_1X10, V4L2_MBUS_FMT_Y8_1X8,
+ { MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_Y10_1X10, MEDIA_BUS_FMT_Y8_1X8,
V4L2_PIX_FMT_Y10, 10, "Greyscale 10 bpp", },
- { V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y10_1X10,
- V4L2_MBUS_FMT_Y12_1X12, V4L2_MBUS_FMT_Y8_1X8,
+ { MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y10_1X10,
+ MEDIA_BUS_FMT_Y12_1X12, MEDIA_BUS_FMT_Y8_1X8,
V4L2_PIX_FMT_Y12, 12, "Greyscale 12 bpp", },
- { V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
- V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_MBUS_FMT_SBGGR8_1X8,
+ { MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
+ MEDIA_BUS_FMT_SBGGR8_1X8, MEDIA_BUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR8, 8, "BGGR Bayer 8 bpp", },
- { V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
- V4L2_MBUS_FMT_SGBRG8_1X8, V4L2_MBUS_FMT_SGBRG8_1X8,
+ { MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
+ MEDIA_BUS_FMT_SGBRG8_1X8, MEDIA_BUS_FMT_SGBRG8_1X8,
V4L2_PIX_FMT_SGBRG8, 8, "GBRG Bayer 8 bpp", },
- { V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
- V4L2_MBUS_FMT_SGRBG8_1X8, V4L2_MBUS_FMT_SGRBG8_1X8,
+ { MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
+ MEDIA_BUS_FMT_SGRBG8_1X8, MEDIA_BUS_FMT_SGRBG8_1X8,
V4L2_PIX_FMT_SGRBG8, 8, "GRBG Bayer 8 bpp", },
- { V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
- V4L2_MBUS_FMT_SRGGB8_1X8, V4L2_MBUS_FMT_SRGGB8_1X8,
+ { MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
+ MEDIA_BUS_FMT_SRGGB8_1X8, MEDIA_BUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB8, 8, "RGGB Bayer 8 bpp", },
- { V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8, V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8,
- V4L2_MBUS_FMT_SGRBG10_1X10, 0,
+ { MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8, MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8,
+ MEDIA_BUS_FMT_SGRBG10_1X10, 0,
V4L2_PIX_FMT_SGRBG10DPCM8, 8, "GRBG Bayer 10 bpp DPCM8", },
- { V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR10_1X10, V4L2_MBUS_FMT_SBGGR8_1X8,
+ { MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR10_1X10, MEDIA_BUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR10, 10, "BGGR Bayer 10 bpp", },
- { V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG10_1X10, V4L2_MBUS_FMT_SGBRG8_1X8,
+ { MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGBRG10_1X10, MEDIA_BUS_FMT_SGBRG8_1X8,
V4L2_PIX_FMT_SGBRG10, 10, "GBRG Bayer 10 bpp", },
- { V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG10_1X10, V4L2_MBUS_FMT_SGRBG8_1X8,
+ { MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG10_1X10, MEDIA_BUS_FMT_SGRBG8_1X8,
V4L2_PIX_FMT_SGRBG10, 10, "GRBG Bayer 10 bpp", },
- { V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB10_1X10, V4L2_MBUS_FMT_SRGGB8_1X8,
+ { MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SRGGB10_1X10, MEDIA_BUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB10, 10, "RGGB Bayer 10 bpp", },
- { V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR10_1X10,
- V4L2_MBUS_FMT_SBGGR12_1X12, V4L2_MBUS_FMT_SBGGR8_1X8,
+ { MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR10_1X10,
+ MEDIA_BUS_FMT_SBGGR12_1X12, MEDIA_BUS_FMT_SBGGR8_1X8,
V4L2_PIX_FMT_SBGGR12, 12, "BGGR Bayer 12 bpp", },
- { V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG10_1X10,
- V4L2_MBUS_FMT_SGBRG12_1X12, V4L2_MBUS_FMT_SGBRG8_1X8,
+ { MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG10_1X10,
+ MEDIA_BUS_FMT_SGBRG12_1X12, MEDIA_BUS_FMT_SGBRG8_1X8,
V4L2_PIX_FMT_SGBRG12, 12, "GBRG Bayer 12 bpp", },
- { V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG10_1X10,
- V4L2_MBUS_FMT_SGRBG12_1X12, V4L2_MBUS_FMT_SGRBG8_1X8,
+ { MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG10_1X10,
+ MEDIA_BUS_FMT_SGRBG12_1X12, MEDIA_BUS_FMT_SGRBG8_1X8,
V4L2_PIX_FMT_SGRBG12, 12, "GRBG Bayer 12 bpp", },
- { V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB10_1X10,
- V4L2_MBUS_FMT_SRGGB12_1X12, V4L2_MBUS_FMT_SRGGB8_1X8,
+ { MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB10_1X10,
+ MEDIA_BUS_FMT_SRGGB12_1X12, MEDIA_BUS_FMT_SRGGB8_1X8,
V4L2_PIX_FMT_SRGGB12, 12, "RGGB Bayer 12 bpp", },
- { V4L2_MBUS_FMT_UYVY8_1X16, V4L2_MBUS_FMT_UYVY8_1X16,
- V4L2_MBUS_FMT_UYVY8_1X16, 0,
+ { MEDIA_BUS_FMT_UYVY8_1X16, MEDIA_BUS_FMT_UYVY8_1X16,
+ MEDIA_BUS_FMT_UYVY8_1X16, 0,
V4L2_PIX_FMT_UYVY, 16, "YUV 4:2:2 (UYVY)", },
- { V4L2_MBUS_FMT_YUYV8_1X16, V4L2_MBUS_FMT_YUYV8_1X16,
- V4L2_MBUS_FMT_YUYV8_1X16, 0,
+ { MEDIA_BUS_FMT_YUYV8_1X16, MEDIA_BUS_FMT_YUYV8_1X16,
+ MEDIA_BUS_FMT_YUYV8_1X16, 0,
V4L2_PIX_FMT_YUYV, 16, "YUV 4:2:2 (YUYV)", },
- { V4L2_MBUS_FMT_YUYV8_1_5X8, V4L2_MBUS_FMT_YUYV8_1_5X8,
- V4L2_MBUS_FMT_YUYV8_1_5X8, 0,
+ { MEDIA_BUS_FMT_YUYV8_1_5X8, MEDIA_BUS_FMT_YUYV8_1_5X8,
+ MEDIA_BUS_FMT_YUYV8_1_5X8, 0,
V4L2_PIX_FMT_NV12, 8, "YUV 4:2:0 (NV12)", },
};
const struct iss_format_info *
-omap4iss_video_format_info(enum v4l2_mbus_pixelcode code)
+omap4iss_video_format_info(u32 code)
{
unsigned int i;
diff --git a/drivers/staging/media/omap4iss/iss_video.h b/drivers/staging/media/omap4iss/iss_video.h
index 9dccdb1..f11fce2 100644
--- a/drivers/staging/media/omap4iss/iss_video.h
+++ b/drivers/staging/media/omap4iss/iss_video.h
@@ -43,10 +43,10 @@ struct v4l2_pix_format;
* @description: Human-readable format description
*/
struct iss_format_info {
- enum v4l2_mbus_pixelcode code;
- enum v4l2_mbus_pixelcode truncated;
- enum v4l2_mbus_pixelcode uncompressed;
- enum v4l2_mbus_pixelcode flavor;
+ u32 code;
+ u32 truncated;
+ u32 uncompressed;
+ u32 flavor;
u32 pixelformat;
unsigned int bpp;
const char *description;
@@ -199,6 +199,6 @@ void omap4iss_video_cancel_stream(struct iss_video *video);
struct media_pad *omap4iss_video_remote_pad(struct iss_video *video);
const struct iss_format_info *
-omap4iss_video_format_info(enum v4l2_mbus_pixelcode code);
+omap4iss_video_format_info(u32 code);
#endif /* OMAP4_ISS_VIDEO_H */
diff --git a/drivers/target/loopback/tcm_loop.c b/drivers/target/loopback/tcm_loop.c
index ab3ab27..4d1b722 100644
--- a/drivers/target/loopback/tcm_loop.c
+++ b/drivers/target/loopback/tcm_loop.c
@@ -110,58 +110,6 @@ static struct device_driver tcm_loop_driverfs = {
*/
struct device *tcm_loop_primary;
-/*
- * Copied from drivers/scsi/libfc/fc_fcp.c:fc_change_queue_depth() and
- * drivers/scsi/libiscsi.c:iscsi_change_queue_depth()
- */
-static int tcm_loop_change_queue_depth(
- struct scsi_device *sdev,
- int depth,
- int reason)
-{
- switch (reason) {
- case SCSI_QDEPTH_DEFAULT:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- case SCSI_QDEPTH_QFULL:
- scsi_track_queue_full(sdev, depth);
- break;
- case SCSI_QDEPTH_RAMP_UP:
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
- break;
- default:
- return -EOPNOTSUPP;
- }
- return sdev->queue_depth;
-}
-
-static int tcm_loop_change_queue_type(struct scsi_device *sdev, int tag)
-{
- if (sdev->tagged_supported) {
- scsi_set_tag_type(sdev, tag);
-
- if (tag)
- scsi_activate_tcq(sdev, sdev->queue_depth);
- else
- scsi_deactivate_tcq(sdev, sdev->queue_depth);
- } else
- tag = 0;
-
- return tag;
-}
-
-/*
- * Locate the SAM Task Attr from struct scsi_cmnd *
- */
-static int tcm_loop_sam_attr(struct scsi_cmnd *sc, int tag)
-{
- if (sc->device->tagged_supported &&
- sc->device->ordered_tags && tag >= 0)
- return MSG_ORDERED_TAG;
-
- return MSG_SIMPLE_TAG;
-}
-
static void tcm_loop_submission_work(struct work_struct *work)
{
struct tcm_loop_cmd *tl_cmd =
@@ -220,7 +168,7 @@ static void tcm_loop_submission_work(struct work_struct *work)
rc = target_submit_cmd_map_sgls(se_cmd, tl_nexus->se_sess, sc->cmnd,
&tl_cmd->tl_sense_buf[0], tl_cmd->sc->device->lun,
- transfer_length, tcm_loop_sam_attr(sc, tl_cmd->sc_cmd_tag),
+ transfer_length, MSG_SIMPLE_TAG,
sc->sc_data_direction, 0,
scsi_sglist(sc), scsi_sg_count(sc),
sgl_bidi, sgl_bidi_count,
@@ -431,27 +379,13 @@ static int tcm_loop_slave_alloc(struct scsi_device *sd)
return 0;
}
-static int tcm_loop_slave_configure(struct scsi_device *sd)
-{
- if (sd->tagged_supported) {
- scsi_activate_tcq(sd, sd->queue_depth);
- scsi_adjust_queue_depth(sd, MSG_SIMPLE_TAG,
- sd->host->cmd_per_lun);
- } else {
- scsi_adjust_queue_depth(sd, 0,
- sd->host->cmd_per_lun);
- }
-
- return 0;
-}
-
static struct scsi_host_template tcm_loop_driver_template = {
.show_info = tcm_loop_show_info,
.proc_name = "tcm_loopback",
.name = "TCM_Loopback",
.queuecommand = tcm_loop_queuecommand,
- .change_queue_depth = tcm_loop_change_queue_depth,
- .change_queue_type = tcm_loop_change_queue_type,
+ .change_queue_depth = scsi_change_queue_depth,
+ .change_queue_type = scsi_change_queue_type,
.eh_abort_handler = tcm_loop_abort_task,
.eh_device_reset_handler = tcm_loop_device_reset,
.eh_target_reset_handler = tcm_loop_target_reset,
@@ -462,8 +396,9 @@ static struct scsi_host_template tcm_loop_driver_template = {
.max_sectors = 0xFFFF,
.use_clustering = DISABLE_CLUSTERING,
.slave_alloc = tcm_loop_slave_alloc,
- .slave_configure = tcm_loop_slave_configure,
.module = THIS_MODULE,
+ .use_blk_tags = 1,
+ .track_queue_depth = 1,
};
static int tcm_loop_driver_probe(struct device *dev)
diff --git a/drivers/target/target_core_alua.c b/drivers/target/target_core_alua.c
index fb87780..75cbde1 100644
--- a/drivers/target/target_core_alua.c
+++ b/drivers/target/target_core_alua.c
@@ -576,7 +576,7 @@ static inline int core_alua_state_standby(
case SEND_DIAGNOSTIC:
case READ_CAPACITY:
return 0;
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
switch (cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
return 0;
diff --git a/drivers/target/target_core_pr.c b/drivers/target/target_core_pr.c
index 9f93b82..4c261c3 100644
--- a/drivers/target/target_core_pr.c
+++ b/drivers/target/target_core_pr.c
@@ -459,7 +459,7 @@ static int core_scsi3_pr_seq_non_holder(
case ACCESS_CONTROL_OUT:
case INQUIRY:
case LOG_SENSE:
- case READ_MEDIA_SERIAL_NUMBER:
+ case SERVICE_ACTION_IN_12:
case REPORT_LUNS:
case REQUEST_SENSE:
case PERSISTENT_RESERVE_IN:
diff --git a/drivers/target/target_core_sbc.c b/drivers/target/target_core_sbc.c
index ebe62af..8d171ff 100644
--- a/drivers/target/target_core_sbc.c
+++ b/drivers/target/target_core_sbc.c
@@ -852,7 +852,7 @@ sbc_parse_cdb(struct se_cmd *cmd, struct sbc_ops *ops)
size = READ_CAP_LEN;
cmd->execute_cmd = sbc_emulate_readcapacity;
break;
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
switch (cmd->t_task_cdb[1] & 0x1f) {
case SAI_READ_CAPACITY_16:
cmd->execute_cmd = sbc_emulate_readcapacity_16;
diff --git a/drivers/tty/n_tty.c b/drivers/tty/n_tty.c
index 2e900a9..26f097f 100644
--- a/drivers/tty/n_tty.c
+++ b/drivers/tty/n_tty.c
@@ -2123,7 +2123,7 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
{
struct n_tty_data *ldata = tty->disc_data;
unsigned char __user *b = buf;
- DECLARE_WAITQUEUE(wait, current);
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
int c;
int minimum, time;
ssize_t retval = 0;
@@ -2186,10 +2186,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
nr--;
break;
}
- /* This statement must be first before checking for input
- so that any interrupt will set the state back to
- TASK_RUNNING. */
- set_current_state(TASK_INTERRUPTIBLE);
if (((minimum - (b - buf)) < ldata->minimum_to_wake) &&
((minimum - (b - buf)) >= 1))
@@ -2220,13 +2216,13 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
n_tty_set_room(tty);
up_read(&tty->termios_rwsem);
- timeout = schedule_timeout(timeout);
+ timeout = wait_woken(&wait, TASK_INTERRUPTIBLE,
+ timeout);
down_read(&tty->termios_rwsem);
continue;
}
}
- __set_current_state(TASK_RUNNING);
/* Deal with packet mode. */
if (packet && b == buf) {
@@ -2273,7 +2269,6 @@ static ssize_t n_tty_read(struct tty_struct *tty, struct file *file,
mutex_unlock(&ldata->atomic_read_lock);
- __set_current_state(TASK_RUNNING);
if (b - buf)
retval = b - buf;
@@ -2306,7 +2301,7 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
const unsigned char *buf, size_t nr)
{
const unsigned char *b = buf;
- DECLARE_WAITQUEUE(wait, current);
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
int c;
ssize_t retval = 0;
@@ -2324,7 +2319,6 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
add_wait_queue(&tty->write_wait, &wait);
while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
if (signal_pending(current)) {
retval = -ERESTARTSYS;
break;
@@ -2378,12 +2372,11 @@ static ssize_t n_tty_write(struct tty_struct *tty, struct file *file,
}
up_read(&tty->termios_rwsem);
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
down_read(&tty->termios_rwsem);
}
break_out:
- __set_current_state(TASK_RUNNING);
remove_wait_queue(&tty->write_wait, &wait);
if (b - buf != nr && tty->fasync)
set_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
diff --git a/drivers/tty/serial/Kconfig b/drivers/tty/serial/Kconfig
index 649b784..98f8bca 100644
--- a/drivers/tty/serial/Kconfig
+++ b/drivers/tty/serial/Kconfig
@@ -249,14 +249,14 @@ config SERIAL_SAMSUNG
config SERIAL_SAMSUNG_UARTS_4
bool
- depends on PLAT_SAMSUNG
+ depends on SERIAL_SAMSUNG
default y if !(CPU_S3C2410 || CPU_S3C2412 || CPU_S3C2440 || CPU_S3C2442)
help
Internal node for the common case of 4 Samsung compatible UARTs
config SERIAL_SAMSUNG_UARTS
int
- depends on PLAT_SAMSUNG
+ depends on SERIAL_SAMSUNG
default 4 if SERIAL_SAMSUNG_UARTS_4 || CPU_S3C2416
default 3
help
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 9bffd26..874dec3 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1493,10 +1493,6 @@ int usb_resume(struct device *dev, pm_message_t msg)
return status;
}
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
-
/**
* usb_enable_autosuspend - allow a USB device to be autosuspended
* @udev: the USB device which may be autosuspended
@@ -1876,7 +1872,7 @@ int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
return ret;
}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
struct bus_type usb_bus_type = {
.name = "usb",
diff --git a/drivers/usb/core/hcd-pci.c b/drivers/usb/core/hcd-pci.c
index efc9531..9eb1cff 100644
--- a/drivers/usb/core/hcd-pci.c
+++ b/drivers/usb/core/hcd-pci.c
@@ -429,7 +429,6 @@ static int check_root_hub_suspended(struct device *dev)
return 0;
}
-#if defined(CONFIG_PM_SLEEP) || defined(CONFIG_PM_RUNTIME)
static int suspend_common(struct device *dev, bool do_wakeup)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -528,7 +527,6 @@ static int resume_common(struct device *dev, int event)
}
return retval;
}
-#endif /* SLEEP || RUNTIME */
#ifdef CONFIG_PM_SLEEP
@@ -607,8 +605,6 @@ static int hcd_pci_restore(struct device *dev)
#endif /* CONFIG_PM_SLEEP */
-#ifdef CONFIG_PM_RUNTIME
-
static int hcd_pci_runtime_suspend(struct device *dev)
{
int retval;
@@ -630,13 +626,6 @@ static int hcd_pci_runtime_resume(struct device *dev)
return retval;
}
-#else
-
-#define hcd_pci_runtime_suspend NULL
-#define hcd_pci_runtime_resume NULL
-
-#endif /* CONFIG_PM_RUNTIME */
-
const struct dev_pm_ops usb_hcd_pci_pm_ops = {
.suspend = hcd_pci_suspend,
.suspend_noirq = hcd_pci_suspend_noirq,
diff --git a/drivers/usb/core/hcd.c b/drivers/usb/core/hcd.c
index a6efb41..278be05 100644
--- a/drivers/usb/core/hcd.c
+++ b/drivers/usb/core/hcd.c
@@ -2258,10 +2258,6 @@ int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg)
return status;
}
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
-
/* Workqueue routine for root-hub remote wakeup */
static void hcd_resume_work(struct work_struct *work)
{
@@ -2293,7 +2289,7 @@ void usb_hcd_resume_root_hub (struct usb_hcd *hcd)
}
EXPORT_SYMBOL_GPL(usb_hcd_resume_root_hub);
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
@@ -2476,7 +2472,7 @@ struct usb_hcd *usb_create_shared_hcd(const struct hc_driver *driver,
init_timer(&hcd->rh_timer);
hcd->rh_timer.function = rh_timer_func;
hcd->rh_timer.data = (unsigned long) hcd;
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
INIT_WORK(&hcd->wakeup_work, hcd_resume_work);
#endif
@@ -2790,7 +2786,7 @@ error_create_attr_group:
hcd->rh_registered = 0;
spin_unlock_irq(&hcd_root_hub_lock);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
cancel_work_sync(&hcd->wakeup_work);
#endif
mutex_lock(&usb_bus_list_lock);
@@ -2858,7 +2854,7 @@ void usb_remove_hcd(struct usb_hcd *hcd)
hcd->rh_registered = 0;
spin_unlock_irq (&hcd_root_hub_lock);
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
cancel_work_sync(&hcd->wakeup_work);
#endif
diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c
index b649fef..c959652 100644
--- a/drivers/usb/core/hub.c
+++ b/drivers/usb/core/hub.c
@@ -1737,7 +1737,7 @@ static int hub_probe(struct usb_interface *intf, const struct usb_device_id *id)
* - If user has indicated to prevent autosuspend by passing
* usbcore.autosuspend = -1 then keep autosuspend disabled.
*/
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
if (hdev->dev.power.autosuspend_delay >= 0)
pm_runtime_set_autosuspend_delay(&hdev->dev, 0);
#endif
@@ -3449,7 +3449,7 @@ int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return status;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
int usb_remote_wakeup(struct usb_device *udev)
{
@@ -4856,7 +4856,7 @@ static void hub_port_connect_change(struct usb_hub *hub, int port1,
udev->state != USB_STATE_NOTATTACHED) {
if (portstatus & USB_PORT_STAT_ENABLE) {
status = 0; /* Nothing to do */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
} else if (udev->state == USB_STATE_SUSPENDED &&
udev->persist_enabled) {
/* For a suspended device, treat this as a
diff --git a/drivers/usb/core/port.c b/drivers/usb/core/port.c
index cd3f9dc..2106183 100644
--- a/drivers/usb/core/port.c
+++ b/drivers/usb/core/port.c
@@ -72,7 +72,7 @@ static void usb_port_device_release(struct device *dev)
kfree(port_dev);
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int usb_port_runtime_resume(struct device *dev)
{
struct usb_port *port_dev = to_usb_port(dev);
@@ -171,7 +171,7 @@ static int usb_port_runtime_suspend(struct device *dev)
#endif
static const struct dev_pm_ops usb_port_pm_ops = {
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
.runtime_suspend = usb_port_runtime_suspend,
.runtime_resume = usb_port_runtime_resume,
#endif
diff --git a/drivers/usb/core/sysfs.c b/drivers/usb/core/sysfs.c
index 1236c60..d269738 100644
--- a/drivers/usb/core/sysfs.c
+++ b/drivers/usb/core/sysfs.c
@@ -334,14 +334,6 @@ static void remove_persist_attributes(struct device *dev)
&dev_attr_persist.attr,
power_group_name);
}
-#else
-
-#define add_persist_attributes(dev) 0
-#define remove_persist_attributes(dev) do {} while (0)
-
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
static ssize_t connected_duration_show(struct device *dev,
struct device_attribute *attr, char *buf)
@@ -585,10 +577,13 @@ static void remove_power_attributes(struct device *dev)
#else
+#define add_persist_attributes(dev) 0
+#define remove_persist_attributes(dev) do {} while (0)
+
#define add_power_attributes(dev) 0
#define remove_power_attributes(dev) do {} while (0)
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
/* Descriptor fields */
diff --git a/drivers/usb/core/usb.c b/drivers/usb/core/usb.c
index 2dd2362..2a92b97 100644
--- a/drivers/usb/core/usb.c
+++ b/drivers/usb/core/usb.c
@@ -49,7 +49,7 @@ const char *usbcore_name = "usbcore";
static bool nousb; /* Disable USB when built into kernel image */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int usb_autosuspend_delay = 2; /* Default delay value,
* in seconds */
module_param_named(autosuspend, usb_autosuspend_delay, int, 0644);
@@ -348,11 +348,9 @@ static const struct dev_pm_ops usb_device_pm_ops = {
.thaw = usb_dev_thaw,
.poweroff = usb_dev_poweroff,
.restore = usb_dev_restore,
-#ifdef CONFIG_PM_RUNTIME
.runtime_suspend = usb_runtime_suspend,
.runtime_resume = usb_runtime_resume,
.runtime_idle = usb_runtime_idle,
-#endif
};
#endif /* CONFIG_PM */
diff --git a/drivers/usb/core/usb.h b/drivers/usb/core/usb.h
index b1b34d0..7eb1e26 100644
--- a/drivers/usb/core/usb.h
+++ b/drivers/usb/core/usb.h
@@ -75,6 +75,14 @@ extern int usb_resume_complete(struct device *dev);
extern int usb_port_suspend(struct usb_device *dev, pm_message_t msg);
extern int usb_port_resume(struct usb_device *dev, pm_message_t msg);
+extern void usb_autosuspend_device(struct usb_device *udev);
+extern int usb_autoresume_device(struct usb_device *udev);
+extern int usb_remote_wakeup(struct usb_device *dev);
+extern int usb_runtime_suspend(struct device *dev);
+extern int usb_runtime_resume(struct device *dev);
+extern int usb_runtime_idle(struct device *dev);
+extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
+
#else
static inline int usb_port_suspend(struct usb_device *udev, pm_message_t msg)
@@ -87,20 +95,6 @@ static inline int usb_port_resume(struct usb_device *udev, pm_message_t msg)
return 0;
}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-
-extern void usb_autosuspend_device(struct usb_device *udev);
-extern int usb_autoresume_device(struct usb_device *udev);
-extern int usb_remote_wakeup(struct usb_device *dev);
-extern int usb_runtime_suspend(struct device *dev);
-extern int usb_runtime_resume(struct device *dev);
-extern int usb_runtime_idle(struct device *dev);
-extern int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable);
-
-#else
-
#define usb_autosuspend_device(udev) do {} while (0)
static inline int usb_autoresume_device(struct usb_device *udev)
{
@@ -111,6 +105,7 @@ static inline int usb_set_usb2_hardware_lpm(struct usb_device *udev, int enable)
{
return 0;
}
+
#endif
extern struct bus_type usb_bus_type;
diff --git a/drivers/usb/gadget/legacy/tcm_usb_gadget.c b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
index 6cdb7a5..024f584 100644
--- a/drivers/usb/gadget/legacy/tcm_usb_gadget.c
+++ b/drivers/usb/gadget/legacy/tcm_usb_gadget.c
@@ -912,7 +912,7 @@ static int get_cmd_dir(const unsigned char *cdb)
case INQUIRY:
case MODE_SENSE:
case MODE_SENSE_10:
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
case MAINTENANCE_IN:
case PERSISTENT_RESERVE_IN:
case SECURITY_PROTOCOL_IN:
diff --git a/drivers/usb/host/ehci-pci.c b/drivers/usb/host/ehci-pci.c
index ca7b964..851006a 100644
--- a/drivers/usb/host/ehci-pci.c
+++ b/drivers/usb/host/ehci-pci.c
@@ -305,7 +305,7 @@ static int ehci_pci_setup(struct usb_hcd *hcd)
}
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
if (ehci->no_selective_suspend && device_can_wakeup(&pdev->dev))
ehci_warn(ehci, "selective suspend/wakeup unavailable\n");
#endif
diff --git a/drivers/usb/host/sl811-hcd.c b/drivers/usb/host/sl811-hcd.c
index ad0c348..25fb1da 100644
--- a/drivers/usb/host/sl811-hcd.c
+++ b/drivers/usb/host/sl811-hcd.c
@@ -22,7 +22,7 @@
* and usb-storage.
*
* TODO:
- * - usb suspend/resume triggered by sl811 (with PM_RUNTIME)
+ * - usb suspend/resume triggered by sl811
* - various issues noted in the code
* - performance work; use both register banks; ...
* - use urb->iso_frame_desc[] with ISO transfers
@@ -1752,8 +1752,7 @@ sl811h_probe(struct platform_device *dev)
#ifdef CONFIG_PM
/* for this device there's no useful distinction between the controller
- * and its root hub, except that the root hub only gets direct PM calls
- * when CONFIG_PM_RUNTIME is enabled.
+ * and its root hub.
*/
static int
diff --git a/drivers/usb/host/u132-hcd.c b/drivers/usb/host/u132-hcd.c
index c067175..bf86630 100644
--- a/drivers/usb/host/u132-hcd.c
+++ b/drivers/usb/host/u132-hcd.c
@@ -3144,8 +3144,7 @@ static int u132_probe(struct platform_device *pdev)
#ifdef CONFIG_PM
/*
* for this device there's no useful distinction between the controller
- * and its root hub, except that the root hub only gets direct PM calls
- * when CONFIG_PM_RUNTIME is enabled.
+ * and its root hub.
*/
static int u132_suspend(struct platform_device *pdev, pm_message_t state)
{
diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c
index 388cfd8..a7865c4 100644
--- a/drivers/usb/host/xhci-hub.c
+++ b/drivers/usb/host/xhci-hub.c
@@ -1145,7 +1145,7 @@ int xhci_bus_suspend(struct usb_hcd *hcd)
set_bit(port_index, &bus_state->bus_suspended);
}
/* USB core sets remote wake mask for USB 3.0 hubs,
- * including the USB 3.0 roothub, but only if CONFIG_PM_RUNTIME
+ * including the USB 3.0 roothub, but only if CONFIG_PM
* is enabled, so also enable remote wake here.
*/
if (hcd->self.root_hub->do_remote_wakeup) {
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 033b46c..cf34131 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -4029,7 +4029,7 @@ static int __maybe_unused xhci_change_max_exit_latency(struct xhci_hcd *xhci,
return ret;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
/* BESL to HIRD Encoding array for USB2 LPM */
static int xhci_besl_encoding[16] = {125, 150, 200, 300, 400, 500, 1000, 2000,
@@ -4244,24 +4244,8 @@ int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
return 0;
}
-#else
-
-int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
- struct usb_device *udev, int enable)
-{
- return 0;
-}
-
-int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
-{
- return 0;
-}
-
-#endif /* CONFIG_PM_RUNTIME */
-
/*---------------------- USB 3.0 Link PM functions ------------------------*/
-#ifdef CONFIG_PM
/* Service interval in nanoseconds = 2^(bInterval - 1) * 125us * 1000ns / 1us */
static unsigned long long xhci_service_interval_to_ns(
struct usb_endpoint_descriptor *desc)
@@ -4692,6 +4676,17 @@ int xhci_disable_usb3_lpm_timeout(struct usb_hcd *hcd,
}
#else /* CONFIG_PM */
+int xhci_set_usb2_hardware_lpm(struct usb_hcd *hcd,
+ struct usb_device *udev, int enable)
+{
+ return 0;
+}
+
+int xhci_update_device(struct usb_hcd *hcd, struct usb_device *udev)
+{
+ return 0;
+}
+
int xhci_enable_usb3_lpm_timeout(struct usb_hcd *hcd,
struct usb_device *udev, enum usb3_link_state state)
{
diff --git a/drivers/usb/phy/phy-msm-usb.c b/drivers/usb/phy/phy-msm-usb.c
index 7843ef7..29be0e6 100644
--- a/drivers/usb/phy/phy-msm-usb.c
+++ b/drivers/usb/phy/phy-msm-usb.c
@@ -1761,7 +1761,7 @@ static int msm_otg_remove(struct platform_device *pdev)
return 0;
}
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
static int msm_otg_runtime_idle(struct device *dev)
{
struct msm_otg *motg = dev_get_drvdata(dev);
diff --git a/drivers/usb/storage/debug.c b/drivers/usb/storage/debug.c
index e08f647..2d81e1d 100644
--- a/drivers/usb/storage/debug.c
+++ b/drivers/usb/storage/debug.c
@@ -164,10 +164,10 @@ void usb_stor_show_sense(const struct us_data *us,
unsigned char asc,
unsigned char ascq)
{
- const char *what, *keystr;
+ const char *what, *keystr, *fmt;
keystr = scsi_sense_key_string(key);
- what = scsi_extd_sense_format(asc, ascq);
+ what = scsi_extd_sense_format(asc, ascq, &fmt);
if (keystr == NULL)
keystr = "(Unknown Key)";
@@ -175,8 +175,10 @@ void usb_stor_show_sense(const struct us_data *us,
what = "(unknown ASC/ASCQ)";
usb_stor_dbg(us, "%s: ", keystr);
- US_DEBUGPX(what, ascq);
- US_DEBUGPX("\n");
+ if (fmt)
+ US_DEBUGPX("%s (%s%x)\n", what, fmt, ascq);
+ else
+ US_DEBUGPX("%s\n", what);
}
int usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
@@ -186,7 +188,7 @@ int usb_stor_dbg(const struct us_data *us, const char *fmt, ...)
va_start(args, fmt);
- r = dev_vprintk_emit(7, &us->pusb_dev->dev, fmt, args);
+ r = dev_vprintk_emit(LOGLEVEL_DEBUG, &us->pusb_dev->dev, fmt, args);
va_end(args);
diff --git a/drivers/usb/storage/uas.c b/drivers/usb/storage/uas.c
index 89b2434..4047edf 100644
--- a/drivers/usb/storage/uas.c
+++ b/drivers/usb/storage/uas.c
@@ -181,7 +181,7 @@ static int uas_get_tag(struct scsi_cmnd *cmnd)
{
int tag;
- if (blk_rq_tagged(cmnd->request))
+ if (cmnd->flags & SCMD_TAGGED)
tag = cmnd->request->tag + 2;
else
tag = 1;
@@ -799,8 +799,7 @@ static int uas_slave_configure(struct scsi_device *sdev)
if (devinfo->flags & US_FL_NO_REPORT_OPCODES)
sdev->no_report_opcodes = 1;
- scsi_set_tag_type(sdev, MSG_ORDERED_TAG);
- scsi_activate_tcq(sdev, devinfo->qdepth - 2);
+ scsi_change_queue_depth(sdev, devinfo->qdepth - 2);
return 0;
}
@@ -817,7 +816,6 @@ static struct scsi_host_template uas_host_template = {
.sg_tablesize = SG_NONE,
.cmd_per_lun = 1, /* until we override it */
.skip_settle_delay = 1,
- .ordered_tag = 1,
/*
* The uas drivers expects tags not to be bigger than the maximum
@@ -825,6 +823,7 @@ static struct scsi_host_template uas_host_template = {
* allocator.
*/
.disable_blk_mq = true,
+ .use_blk_tags = 1,
};
#define UNUSUAL_DEV(id_vendor, id_product, bcdDeviceMin, bcdDeviceMax, \
diff --git a/drivers/vfio/pci/vfio_pci_intrs.c b/drivers/vfio/pci/vfio_pci_intrs.c
index 553212f..e8d695b 100644
--- a/drivers/vfio/pci/vfio_pci_intrs.c
+++ b/drivers/vfio/pci/vfio_pci_intrs.c
@@ -560,7 +560,7 @@ static int vfio_msi_set_vector_signal(struct vfio_pci_device *vdev,
struct msi_msg msg;
get_cached_msi_msg(irq, &msg);
- write_msi_msg(irq, &msg);
+ pci_write_msi_msg(irq, &msg);
}
ret = request_irq(irq, vfio_msihandler, 0,
diff --git a/drivers/vhost/net.c b/drivers/vhost/net.c
index 9f06e70..14419a8 100644
--- a/drivers/vhost/net.c
+++ b/drivers/vhost/net.c
@@ -48,20 +48,21 @@ MODULE_PARM_DESC(experimental_zcopytx, "Enable Zero Copy TX;"
* status internally; used for zerocopy tx only.
*/
/* Lower device DMA failed */
-#define VHOST_DMA_FAILED_LEN 3
+#define VHOST_DMA_FAILED_LEN ((__force __virtio32)3)
/* Lower device DMA done */
-#define VHOST_DMA_DONE_LEN 2
+#define VHOST_DMA_DONE_LEN ((__force __virtio32)2)
/* Lower device DMA in progress */
-#define VHOST_DMA_IN_PROGRESS 1
+#define VHOST_DMA_IN_PROGRESS ((__force __virtio32)1)
/* Buffer unused */
-#define VHOST_DMA_CLEAR_LEN 0
+#define VHOST_DMA_CLEAR_LEN ((__force __virtio32)0)
-#define VHOST_DMA_IS_DONE(len) ((len) >= VHOST_DMA_DONE_LEN)
+#define VHOST_DMA_IS_DONE(len) ((__force u32)(len) >= (__force u32)VHOST_DMA_DONE_LEN)
enum {
VHOST_NET_FEATURES = VHOST_FEATURES |
(1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
- (1ULL << VIRTIO_NET_F_MRG_RXBUF),
+ (1ULL << VIRTIO_NET_F_MRG_RXBUF) |
+ (1ULL << VIRTIO_F_VERSION_1),
};
enum {
@@ -415,7 +416,7 @@ static void handle_tx(struct vhost_net *net)
struct ubuf_info *ubuf;
ubuf = nvq->ubuf_info + nvq->upend_idx;
- vq->heads[nvq->upend_idx].id = head;
+ vq->heads[nvq->upend_idx].id = cpu_to_vhost32(vq, head);
vq->heads[nvq->upend_idx].len = VHOST_DMA_IN_PROGRESS;
ubuf->callback = vhost_zerocopy_callback;
ubuf->ctx = nvq->ubufs;
@@ -499,6 +500,10 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
int headcount = 0;
unsigned d;
int r, nlogs = 0;
+ /* len is always initialized before use since we are always called with
+ * datalen > 0.
+ */
+ u32 uninitialized_var(len);
while (datalen > 0 && headcount < quota) {
if (unlikely(seg >= UIO_MAXIOV)) {
@@ -526,13 +531,14 @@ static int get_rx_bufs(struct vhost_virtqueue *vq,
nlogs += *log_num;
log += *log_num;
}
- heads[headcount].id = d;
- heads[headcount].len = iov_length(vq->iov + seg, in);
- datalen -= heads[headcount].len;
+ heads[headcount].id = cpu_to_vhost32(vq, d);
+ len = iov_length(vq->iov + seg, in);
+ heads[headcount].len = cpu_to_vhost32(vq, len);
+ datalen -= len;
++headcount;
seg += in;
}
- heads[headcount - 1].len += datalen;
+ heads[headcount - 1].len = cpu_to_vhost32(vq, len - datalen);
*iovcount = seg;
if (unlikely(log))
*log_num = nlogs;
@@ -1023,7 +1029,8 @@ static int vhost_net_set_features(struct vhost_net *n, u64 features)
size_t vhost_hlen, sock_hlen, hdr_len;
int i;
- hdr_len = (features & (1 << VIRTIO_NET_F_MRG_RXBUF)) ?
+ hdr_len = (features & ((1ULL << VIRTIO_NET_F_MRG_RXBUF) |
+ (1ULL << VIRTIO_F_VERSION_1))) ?
sizeof(struct virtio_net_hdr_mrg_rxbuf) :
sizeof(struct virtio_net_hdr);
if (features & (1 << VHOST_NET_F_VIRTIO_NET_HDR)) {
diff --git a/drivers/vhost/scsi.c b/drivers/vhost/scsi.c
index a17f118..01c01cb 100644
--- a/drivers/vhost/scsi.c
+++ b/drivers/vhost/scsi.c
@@ -168,6 +168,7 @@ enum {
VHOST_SCSI_VQ_IO = 2,
};
+/* Note: can't set VIRTIO_F_VERSION_1 yet, since that implies ANY_LAYOUT. */
enum {
VHOST_SCSI_FEATURES = VHOST_FEATURES | (1ULL << VIRTIO_SCSI_F_HOTPLUG) |
(1ULL << VIRTIO_SCSI_F_T10_PI)
@@ -577,8 +578,8 @@ tcm_vhost_allocate_evt(struct vhost_scsi *vs,
return NULL;
}
- evt->event.event = event;
- evt->event.reason = reason;
+ evt->event.event = cpu_to_vhost32(vq, event);
+ evt->event.reason = cpu_to_vhost32(vq, reason);
vs->vs_events_nr++;
return evt;
@@ -636,7 +637,7 @@ again:
}
if (vs->vs_events_missed) {
- event->event |= VIRTIO_SCSI_T_EVENTS_MISSED;
+ event->event |= cpu_to_vhost32(vq, VIRTIO_SCSI_T_EVENTS_MISSED);
vs->vs_events_missed = false;
}
@@ -695,12 +696,13 @@ static void vhost_scsi_complete_cmd_work(struct vhost_work *work)
cmd, se_cmd->residual_count, se_cmd->scsi_status);
memset(&v_rsp, 0, sizeof(v_rsp));
- v_rsp.resid = se_cmd->residual_count;
+ v_rsp.resid = cpu_to_vhost32(cmd->tvc_vq, se_cmd->residual_count);
/* TODO is status_qualifier field needed? */
v_rsp.status = se_cmd->scsi_status;
- v_rsp.sense_len = se_cmd->scsi_sense_length;
+ v_rsp.sense_len = cpu_to_vhost32(cmd->tvc_vq,
+ se_cmd->scsi_sense_length);
memcpy(v_rsp.sense, cmd->tvc_sense_buf,
- v_rsp.sense_len);
+ se_cmd->scsi_sense_length);
ret = copy_to_user(cmd->tvc_resp, &v_rsp, sizeof(v_rsp));
if (likely(ret == 0)) {
struct vhost_scsi_virtqueue *q;
@@ -1095,14 +1097,14 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
", but wrong data_direction\n");
goto err_cmd;
}
- prot_bytes = v_req_pi.pi_bytesout;
+ prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesout);
} else if (v_req_pi.pi_bytesin) {
if (data_direction != DMA_FROM_DEVICE) {
vq_err(vq, "Received non zero di_pi_niov"
", but wrong data_direction\n");
goto err_cmd;
}
- prot_bytes = v_req_pi.pi_bytesin;
+ prot_bytes = vhost32_to_cpu(vq, v_req_pi.pi_bytesin);
}
if (prot_bytes) {
int tmp = 0;
@@ -1117,12 +1119,12 @@ vhost_scsi_handle_vq(struct vhost_scsi *vs, struct vhost_virtqueue *vq)
data_first += prot_niov;
data_niov = data_num - prot_niov;
}
- tag = v_req_pi.tag;
+ tag = vhost64_to_cpu(vq, v_req_pi.tag);
task_attr = v_req_pi.task_attr;
cdb = &v_req_pi.cdb[0];
lun = ((v_req_pi.lun[2] << 8) | v_req_pi.lun[3]) & 0x3FFF;
} else {
- tag = v_req.tag;
+ tag = vhost64_to_cpu(vq, v_req.tag);
task_attr = v_req.task_attr;
cdb = &v_req.cdb[0];
lun = ((v_req.lun[2] << 8) | v_req.lun[3]) & 0x3FFF;
diff --git a/drivers/vhost/vhost.c b/drivers/vhost/vhost.c
index c90f437..ed71b53 100644
--- a/drivers/vhost/vhost.c
+++ b/drivers/vhost/vhost.c
@@ -33,8 +33,8 @@ enum {
VHOST_MEMORY_F_LOG = 0x1,
};
-#define vhost_used_event(vq) ((u16 __user *)&vq->avail->ring[vq->num])
-#define vhost_avail_event(vq) ((u16 __user *)&vq->used->ring[vq->num])
+#define vhost_used_event(vq) ((__virtio16 __user *)&vq->avail->ring[vq->num])
+#define vhost_avail_event(vq) ((__virtio16 __user *)&vq->used->ring[vq->num])
static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
poll_table *pt)
@@ -1001,7 +1001,7 @@ EXPORT_SYMBOL_GPL(vhost_log_write);
static int vhost_update_used_flags(struct vhost_virtqueue *vq)
{
void __user *used;
- if (__put_user(vq->used_flags, &vq->used->flags) < 0)
+ if (__put_user(cpu_to_vhost16(vq, vq->used_flags), &vq->used->flags) < 0)
return -EFAULT;
if (unlikely(vq->log_used)) {
/* Make sure the flag is seen before log. */
@@ -1019,7 +1019,7 @@ static int vhost_update_used_flags(struct vhost_virtqueue *vq)
static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
{
- if (__put_user(vq->avail_idx, vhost_avail_event(vq)))
+ if (__put_user(cpu_to_vhost16(vq, vq->avail_idx), vhost_avail_event(vq)))
return -EFAULT;
if (unlikely(vq->log_used)) {
void __user *used;
@@ -1038,6 +1038,7 @@ static int vhost_update_avail_event(struct vhost_virtqueue *vq, u16 avail_event)
int vhost_init_used(struct vhost_virtqueue *vq)
{
+ __virtio16 last_used_idx;
int r;
if (!vq->private_data)
return 0;
@@ -1046,7 +1047,13 @@ int vhost_init_used(struct vhost_virtqueue *vq)
if (r)
return r;
vq->signalled_used_valid = false;
- return get_user(vq->last_used_idx, &vq->used->idx);
+ if (!access_ok(VERIFY_READ, &vq->used->idx, sizeof vq->used->idx))
+ return -EFAULT;
+ r = __get_user(last_used_idx, &vq->used->idx);
+ if (r)
+ return r;
+ vq->last_used_idx = vhost16_to_cpu(vq, last_used_idx);
+ return 0;
}
EXPORT_SYMBOL_GPL(vhost_init_used);
@@ -1087,16 +1094,16 @@ static int translate_desc(struct vhost_virtqueue *vq, u64 addr, u32 len,
/* Each buffer in the virtqueues is actually a chain of descriptors. This
* function returns the next descriptor in the chain,
* or -1U if we're at the end. */
-static unsigned next_desc(struct vring_desc *desc)
+static unsigned next_desc(struct vhost_virtqueue *vq, struct vring_desc *desc)
{
unsigned int next;
/* If this descriptor says it doesn't chain, we're done. */
- if (!(desc->flags & VRING_DESC_F_NEXT))
+ if (!(desc->flags & cpu_to_vhost16(vq, VRING_DESC_F_NEXT)))
return -1U;
/* Check they're not leading us off end of descriptors. */
- next = desc->next;
+ next = vhost16_to_cpu(vq, desc->next);
/* Make sure compiler knows to grab that: we don't want it changing! */
/* We will use the result as an index in an array, so most
* architectures only need a compiler barrier here. */
@@ -1113,18 +1120,19 @@ static int get_indirect(struct vhost_virtqueue *vq,
{
struct vring_desc desc;
unsigned int i = 0, count, found = 0;
+ u32 len = vhost32_to_cpu(vq, indirect->len);
int ret;
/* Sanity check */
- if (unlikely(indirect->len % sizeof desc)) {
+ if (unlikely(len % sizeof desc)) {
vq_err(vq, "Invalid length in indirect descriptor: "
"len 0x%llx not multiple of 0x%zx\n",
- (unsigned long long)indirect->len,
+ (unsigned long long)len,
sizeof desc);
return -EINVAL;
}
- ret = translate_desc(vq, indirect->addr, indirect->len, vq->indirect,
+ ret = translate_desc(vq, vhost64_to_cpu(vq, indirect->addr), len, vq->indirect,
UIO_MAXIOV);
if (unlikely(ret < 0)) {
vq_err(vq, "Translation failure %d in indirect.\n", ret);
@@ -1135,7 +1143,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
* architectures only need a compiler barrier here. */
read_barrier_depends();
- count = indirect->len / sizeof desc;
+ count = len / sizeof desc;
/* Buffers are chained via a 16 bit next field, so
* we can have at most 2^16 of these. */
if (unlikely(count > USHRT_MAX + 1)) {
@@ -1155,16 +1163,17 @@ static int get_indirect(struct vhost_virtqueue *vq,
if (unlikely(memcpy_fromiovec((unsigned char *)&desc,
vq->indirect, sizeof desc))) {
vq_err(vq, "Failed indirect descriptor: idx %d, %zx\n",
- i, (size_t)indirect->addr + i * sizeof desc);
+ i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc);
return -EINVAL;
}
- if (unlikely(desc.flags & VRING_DESC_F_INDIRECT)) {
+ if (unlikely(desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_INDIRECT))) {
vq_err(vq, "Nested indirect descriptor: idx %d, %zx\n",
- i, (size_t)indirect->addr + i * sizeof desc);
+ i, (size_t)vhost64_to_cpu(vq, indirect->addr) + i * sizeof desc);
return -EINVAL;
}
- ret = translate_desc(vq, desc.addr, desc.len, iov + iov_count,
+ ret = translate_desc(vq, vhost64_to_cpu(vq, desc.addr),
+ vhost32_to_cpu(vq, desc.len), iov + iov_count,
iov_size - iov_count);
if (unlikely(ret < 0)) {
vq_err(vq, "Translation failure %d indirect idx %d\n",
@@ -1172,11 +1181,11 @@ static int get_indirect(struct vhost_virtqueue *vq,
return ret;
}
/* If this is an input descriptor, increment that count. */
- if (desc.flags & VRING_DESC_F_WRITE) {
+ if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) {
*in_num += ret;
if (unlikely(log)) {
- log[*log_num].addr = desc.addr;
- log[*log_num].len = desc.len;
+ log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
+ log[*log_num].len = vhost32_to_cpu(vq, desc.len);
++*log_num;
}
} else {
@@ -1189,7 +1198,7 @@ static int get_indirect(struct vhost_virtqueue *vq,
}
*out_num += ret;
}
- } while ((i = next_desc(&desc)) != -1);
+ } while ((i = next_desc(vq, &desc)) != -1);
return 0;
}
@@ -1209,15 +1218,18 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
struct vring_desc desc;
unsigned int i, head, found = 0;
u16 last_avail_idx;
+ __virtio16 avail_idx;
+ __virtio16 ring_head;
int ret;
/* Check it isn't doing very strange things with descriptor numbers. */
last_avail_idx = vq->last_avail_idx;
- if (unlikely(__get_user(vq->avail_idx, &vq->avail->idx))) {
+ if (unlikely(__get_user(avail_idx, &vq->avail->idx))) {
vq_err(vq, "Failed to access avail idx at %p\n",
&vq->avail->idx);
return -EFAULT;
}
+ vq->avail_idx = vhost16_to_cpu(vq, avail_idx);
if (unlikely((u16)(vq->avail_idx - last_avail_idx) > vq->num)) {
vq_err(vq, "Guest moved used index from %u to %u",
@@ -1234,7 +1246,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
/* Grab the next descriptor number they're advertising, and increment
* the index we've seen. */
- if (unlikely(__get_user(head,
+ if (unlikely(__get_user(ring_head,
&vq->avail->ring[last_avail_idx % vq->num]))) {
vq_err(vq, "Failed to read head: idx %d address %p\n",
last_avail_idx,
@@ -1242,6 +1254,8 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
return -EFAULT;
}
+ head = vhost16_to_cpu(vq, ring_head);
+
/* If their number is silly, that's an error. */
if (unlikely(head >= vq->num)) {
vq_err(vq, "Guest says index %u > %u is available",
@@ -1274,7 +1288,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
i, vq->desc + i);
return -EFAULT;
}
- if (desc.flags & VRING_DESC_F_INDIRECT) {
+ if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_INDIRECT)) {
ret = get_indirect(vq, iov, iov_size,
out_num, in_num,
log, log_num, &desc);
@@ -1286,20 +1300,21 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
continue;
}
- ret = translate_desc(vq, desc.addr, desc.len, iov + iov_count,
+ ret = translate_desc(vq, vhost64_to_cpu(vq, desc.addr),
+ vhost32_to_cpu(vq, desc.len), iov + iov_count,
iov_size - iov_count);
if (unlikely(ret < 0)) {
vq_err(vq, "Translation failure %d descriptor idx %d\n",
ret, i);
return ret;
}
- if (desc.flags & VRING_DESC_F_WRITE) {
+ if (desc.flags & cpu_to_vhost16(vq, VRING_DESC_F_WRITE)) {
/* If this is an input descriptor,
* increment that count. */
*in_num += ret;
if (unlikely(log)) {
- log[*log_num].addr = desc.addr;
- log[*log_num].len = desc.len;
+ log[*log_num].addr = vhost64_to_cpu(vq, desc.addr);
+ log[*log_num].len = vhost32_to_cpu(vq, desc.len);
++*log_num;
}
} else {
@@ -1312,7 +1327,7 @@ int vhost_get_vq_desc(struct vhost_virtqueue *vq,
}
*out_num += ret;
}
- } while ((i = next_desc(&desc)) != -1);
+ } while ((i = next_desc(vq, &desc)) != -1);
/* On success, increment avail index. */
vq->last_avail_idx++;
@@ -1335,7 +1350,10 @@ EXPORT_SYMBOL_GPL(vhost_discard_vq_desc);
* want to notify the guest, using eventfd. */
int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
{
- struct vring_used_elem heads = { head, len };
+ struct vring_used_elem heads = {
+ cpu_to_vhost32(vq, head),
+ cpu_to_vhost32(vq, len)
+ };
return vhost_add_used_n(vq, &heads, 1);
}
@@ -1404,7 +1422,7 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
/* Make sure buffer is written before we update index. */
smp_wmb();
- if (put_user(vq->last_used_idx, &vq->used->idx)) {
+ if (__put_user(cpu_to_vhost16(vq, vq->last_used_idx), &vq->used->idx)) {
vq_err(vq, "Failed to increment used idx");
return -EFAULT;
}
@@ -1422,7 +1440,8 @@ EXPORT_SYMBOL_GPL(vhost_add_used_n);
static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
- __u16 old, new, event;
+ __u16 old, new;
+ __virtio16 event;
bool v;
/* Flush out used index updates. This is paired
* with the barrier that the Guest executes when enabling
@@ -1434,12 +1453,12 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
return true;
if (!vhost_has_feature(vq, VIRTIO_RING_F_EVENT_IDX)) {
- __u16 flags;
+ __virtio16 flags;
if (__get_user(flags, &vq->avail->flags)) {
vq_err(vq, "Failed to get flags");
return true;
}
- return !(flags & VRING_AVAIL_F_NO_INTERRUPT);
+ return !(flags & cpu_to_vhost16(vq, VRING_AVAIL_F_NO_INTERRUPT));
}
old = vq->signalled_used;
v = vq->signalled_used_valid;
@@ -1449,11 +1468,11 @@ static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
if (unlikely(!v))
return true;
- if (get_user(event, vhost_used_event(vq))) {
+ if (__get_user(event, vhost_used_event(vq))) {
vq_err(vq, "Failed to get used event idx");
return true;
}
- return vring_need_event(event, new, old);
+ return vring_need_event(vhost16_to_cpu(vq, event), new, old);
}
/* This actually signals the guest, using eventfd. */
@@ -1488,7 +1507,7 @@ EXPORT_SYMBOL_GPL(vhost_add_used_and_signal_n);
/* OK, now we need to know about added descriptors. */
bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
{
- u16 avail_idx;
+ __virtio16 avail_idx;
int r;
if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
@@ -1519,7 +1538,7 @@ bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
return false;
}
- return avail_idx != vq->avail_idx;
+ return vhost16_to_cpu(vq, avail_idx) != vq->avail_idx;
}
EXPORT_SYMBOL_GPL(vhost_enable_notify);
diff --git a/drivers/vhost/vhost.h b/drivers/vhost/vhost.h
index 3eda654..8c1c792 100644
--- a/drivers/vhost/vhost.h
+++ b/drivers/vhost/vhost.h
@@ -12,8 +12,6 @@
#include <linux/virtio_ring.h>
#include <linux/atomic.h>
-struct vhost_device;
-
struct vhost_work;
typedef void (*vhost_work_fn_t)(struct vhost_work *work);
@@ -54,8 +52,6 @@ struct vhost_log {
u64 len;
};
-struct vhost_virtqueue;
-
/* The virtqueue structure describes a queue attached to a device. */
struct vhost_virtqueue {
struct vhost_dev *dev;
@@ -106,7 +102,7 @@ struct vhost_virtqueue {
/* Protected by virtqueue mutex. */
struct vhost_memory *memory;
void *private_data;
- unsigned acked_features;
+ u64 acked_features;
/* Log write descriptors */
void __user *log_base;
struct vhost_log *log;
@@ -172,8 +168,39 @@ enum {
(1ULL << VHOST_F_LOG_ALL),
};
-static inline int vhost_has_feature(struct vhost_virtqueue *vq, int bit)
+static inline bool vhost_has_feature(struct vhost_virtqueue *vq, int bit)
+{
+ return vq->acked_features & (1ULL << bit);
+}
+
+/* Memory accessors */
+static inline u16 vhost16_to_cpu(struct vhost_virtqueue *vq, __virtio16 val)
+{
+ return __virtio16_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio16 cpu_to_vhost16(struct vhost_virtqueue *vq, u16 val)
+{
+ return __cpu_to_virtio16(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val);
+}
+
+static inline u32 vhost32_to_cpu(struct vhost_virtqueue *vq, __virtio32 val)
+{
+ return __virtio32_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio32 cpu_to_vhost32(struct vhost_virtqueue *vq, u32 val)
+{
+ return __cpu_to_virtio32(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val);
+}
+
+static inline u64 vhost64_to_cpu(struct vhost_virtqueue *vq, __virtio64 val)
+{
+ return __virtio64_to_cpu(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio64 cpu_to_vhost64(struct vhost_virtqueue *vq, u64 val)
{
- return vq->acked_features & (1 << bit);
+ return __cpu_to_virtio64(vhost_has_feature(vq, VIRTIO_F_VERSION_1), val);
}
#endif
diff --git a/drivers/video/backlight/Kconfig b/drivers/video/backlight/Kconfig
index 8d03924..efb0904 100644
--- a/drivers/video/backlight/Kconfig
+++ b/drivers/video/backlight/Kconfig
@@ -168,7 +168,6 @@ if BACKLIGHT_CLASS_DEVICE
config BACKLIGHT_ATMEL_LCDC
bool "Atmel LCDC Contrast-as-Backlight control"
depends on FB_ATMEL
- default y if MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK || MACH_AT91SAM9263EK
help
This provides a backlight control internal to the Atmel LCDC
driver. If the LCD "contrast control" on your board is wired
diff --git a/drivers/video/backlight/lp855x_bl.c b/drivers/video/backlight/lp855x_bl.c
index 25fb8e3..a26d3bb 100644
--- a/drivers/video/backlight/lp855x_bl.c
+++ b/drivers/video/backlight/lp855x_bl.c
@@ -17,6 +17,7 @@
#include <linux/of.h>
#include <linux/platform_data/lp855x.h>
#include <linux/pwm.h>
+#include <linux/regulator/consumer.h>
/* LP8550/1/2/3/6 Registers */
#define LP855X_BRIGHTNESS_CTRL 0x00
@@ -341,8 +342,10 @@ static const struct attribute_group lp855x_attr_group = {
};
#ifdef CONFIG_OF
-static int lp855x_parse_dt(struct device *dev, struct device_node *node)
+static int lp855x_parse_dt(struct lp855x *lp)
{
+ struct device *dev = lp->dev;
+ struct device_node *node = dev->of_node;
struct lp855x_platform_data *pdata;
int rom_length;
@@ -381,12 +384,19 @@ static int lp855x_parse_dt(struct device *dev, struct device_node *node)
pdata->rom_data = &rom[0];
}
- dev->platform_data = pdata;
+ pdata->supply = devm_regulator_get(dev, "power");
+ if (IS_ERR(pdata->supply)) {
+ if (PTR_ERR(pdata->supply) == -EPROBE_DEFER)
+ return -EPROBE_DEFER;
+ pdata->supply = NULL;
+ }
+
+ lp->pdata = pdata;
return 0;
}
#else
-static int lp855x_parse_dt(struct device *dev, struct device_node *node)
+static int lp855x_parse_dt(struct lp855x *lp)
{
return -EINVAL;
}
@@ -395,18 +405,8 @@ static int lp855x_parse_dt(struct device *dev, struct device_node *node)
static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
{
struct lp855x *lp;
- struct lp855x_platform_data *pdata = dev_get_platdata(&cl->dev);
- struct device_node *node = cl->dev.of_node;
int ret;
- if (!pdata) {
- ret = lp855x_parse_dt(&cl->dev, node);
- if (ret < 0)
- return ret;
-
- pdata = dev_get_platdata(&cl->dev);
- }
-
if (!i2c_check_functionality(cl->adapter, I2C_FUNC_SMBUS_I2C_BLOCK))
return -EIO;
@@ -414,16 +414,31 @@ static int lp855x_probe(struct i2c_client *cl, const struct i2c_device_id *id)
if (!lp)
return -ENOMEM;
- if (pdata->period_ns > 0)
- lp->mode = PWM_BASED;
- else
- lp->mode = REGISTER_BASED;
-
lp->client = cl;
lp->dev = &cl->dev;
- lp->pdata = pdata;
lp->chipname = id->name;
lp->chip_id = id->driver_data;
+ lp->pdata = dev_get_platdata(&cl->dev);
+
+ if (!lp->pdata) {
+ ret = lp855x_parse_dt(lp);
+ if (ret < 0)
+ return ret;
+ }
+
+ if (lp->pdata->period_ns > 0)
+ lp->mode = PWM_BASED;
+ else
+ lp->mode = REGISTER_BASED;
+
+ if (lp->pdata->supply) {
+ ret = regulator_enable(lp->pdata->supply);
+ if (ret < 0) {
+ dev_err(&cl->dev, "failed to enable supply: %d\n", ret);
+ return ret;
+ }
+ }
+
i2c_set_clientdata(cl, lp);
ret = lp855x_configure(lp);
@@ -455,6 +470,8 @@ static int lp855x_remove(struct i2c_client *cl)
lp->bl->props.brightness = 0;
backlight_update_status(lp->bl);
+ if (lp->pdata->supply)
+ regulator_disable(lp->pdata->supply);
sysfs_remove_group(&lp->dev->kobj, &lp855x_attr_group);
return 0;
diff --git a/drivers/video/backlight/pwm_bl.c b/drivers/video/backlight/pwm_bl.c
index cb5ae4c..3a145a6 100644
--- a/drivers/video/backlight/pwm_bl.c
+++ b/drivers/video/backlight/pwm_bl.c
@@ -34,6 +34,7 @@ struct pwm_bl_data {
struct regulator *power_supply;
struct gpio_desc *enable_gpio;
unsigned int scale;
+ bool legacy;
int (*notify)(struct device *,
int brightness);
void (*notify_after)(struct device *,
@@ -274,7 +275,7 @@ static int pwm_backlight_probe(struct platform_device *pdev)
pb->pwm = devm_pwm_get(&pdev->dev, NULL);
if (IS_ERR(pb->pwm)) {
dev_err(&pdev->dev, "unable to request PWM, trying legacy API\n");
-
+ pb->legacy = true;
pb->pwm = pwm_request(data->pwm_id, "pwm-backlight");
if (IS_ERR(pb->pwm)) {
dev_err(&pdev->dev, "unable to request legacy PWM\n");
@@ -339,6 +340,8 @@ static int pwm_backlight_remove(struct platform_device *pdev)
if (pb->exit)
pb->exit(&pdev->dev);
+ if (pb->legacy)
+ pwm_free(pb->pwm);
return 0;
}
diff --git a/drivers/video/console/fbcon.c b/drivers/video/console/fbcon.c
index eb976ee..ea43724 100644
--- a/drivers/video/console/fbcon.c
+++ b/drivers/video/console/fbcon.c
@@ -3624,7 +3624,7 @@ static int __init fb_console_init(void)
return 0;
}
-module_init(fb_console_init);
+fs_initcall(fb_console_init);
#ifdef MODULE
diff --git a/drivers/video/fbdev/Kconfig b/drivers/video/fbdev/Kconfig
index c7bf606..4916c97 100644
--- a/drivers/video/fbdev/Kconfig
+++ b/drivers/video/fbdev/Kconfig
@@ -999,23 +999,6 @@ config FB_ATMEL
help
This enables support for the AT91/AT32 LCD Controller.
-config FB_INTSRAM
- bool "Frame Buffer in internal SRAM"
- depends on FB_ATMEL && ARCH_AT91SAM9261
- help
- Say Y if you want to map Frame Buffer in internal SRAM. Say N if you want
- to let frame buffer in external SDRAM.
-
-config FB_ATMEL_STN
- bool "Use a STN display with AT91/AT32 LCD Controller"
- depends on FB_ATMEL && (MACH_AT91SAM9261EK || MACH_AT91SAM9G10EK)
- default n
- help
- Say Y if you want to connect a STN LCD display to the AT91/AT32 LCD
- Controller. Say N if you want to connect a TFT.
-
- If unsure, say N.
-
config FB_NVIDIA
tristate "nVidia Framebuffer Support"
depends on FB && PCI
@@ -2425,7 +2408,7 @@ config FB_JZ4740
config FB_MXS
tristate "MXS LCD framebuffer support"
- depends on FB && ARCH_MXS
+ depends on FB && (ARCH_MXS || ARCH_MXC)
select FB_CFB_FILLRECT
select FB_CFB_COPYAREA
select FB_CFB_IMAGEBLIT
diff --git a/drivers/video/fbdev/amba-clcd.c b/drivers/video/fbdev/amba-clcd.c
index 6ad23bd..32c0b6b 100644
--- a/drivers/video/fbdev/amba-clcd.c
+++ b/drivers/video/fbdev/amba-clcd.c
@@ -27,7 +27,6 @@
#include <linux/bitops.h>
#include <linux/clk.h>
#include <linux/hardirq.h>
-#include <linux/dma-mapping.h>
#include <linux/of.h>
#include <linux/of_address.h>
#include <linux/of_graph.h>
diff --git a/drivers/video/fbdev/arkfb.c b/drivers/video/fbdev/arkfb.c
index adc4ea2..b305a1e 100644
--- a/drivers/video/fbdev/arkfb.c
+++ b/drivers/video/fbdev/arkfb.c
@@ -1016,7 +1016,7 @@ static int ark_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
- par->state.vgabase = (void __iomem *) vga_res.start;
+ par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
/* FIXME get memsize */
regval = vga_rseq(par->state.vgabase, 0x10);
diff --git a/drivers/video/fbdev/gbefb.c b/drivers/video/fbdev/gbefb.c
index 4aa56ba..6d9ef398 100644
--- a/drivers/video/fbdev/gbefb.c
+++ b/drivers/video/fbdev/gbefb.c
@@ -54,7 +54,8 @@ struct gbefb_par {
#endif
#endif
#ifdef CONFIG_X86
-#define pgprot_fb(_prot) ((_prot) | _PAGE_PCD)
+#define pgprot_fb(_prot) (((_prot) & ~_PAGE_CACHE_MASK) | \
+ cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS))
#endif
/*
diff --git a/drivers/video/fbdev/mmp/core.c b/drivers/video/fbdev/mmp/core.c
index b563b92..a0f4960 100644
--- a/drivers/video/fbdev/mmp/core.c
+++ b/drivers/video/fbdev/mmp/core.c
@@ -223,10 +223,10 @@ struct mmp_path *mmp_register_path(struct mmp_path_info *info)
EXPORT_SYMBOL_GPL(mmp_register_path);
/*
- * mmp_unregister_path - unregister and destory path
- * @p: path to be destoried.
+ * mmp_unregister_path - unregister and destroy path
+ * @p: path to be destroyed.
*
- * this function registers path and destorys it.
+ * this function registers path and destroys it.
*/
void mmp_unregister_path(struct mmp_path *path)
{
diff --git a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
index 8621a9f..3c12bd8 100644
--- a/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
+++ b/drivers/video/fbdev/mmp/hw/mmp_ctrl.c
@@ -441,8 +441,7 @@ static void path_deinit(struct mmphw_path_plat *path_plat)
if (!path_plat)
return;
- if (path_plat->path)
- mmp_unregister_path(path_plat->path);
+ mmp_unregister_path(path_plat->path);
}
static int mmphw_probe(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/mx3fb.c b/drivers/video/fbdev/mx3fb.c
index 23ec781e..f23fca0 100644
--- a/drivers/video/fbdev/mx3fb.c
+++ b/drivers/video/fbdev/mx3fb.c
@@ -334,8 +334,7 @@ static void mx3fb_init_backlight(struct mx3fb_data *fbd)
static void mx3fb_exit_backlight(struct mx3fb_data *fbd)
{
- if (fbd->bl)
- backlight_device_unregister(fbd->bl);
+ backlight_device_unregister(fbd->bl);
}
static void mx3fb_dma_done(void *);
diff --git a/drivers/video/fbdev/mxsfb.c b/drivers/video/fbdev/mxsfb.c
index accf48a2..f8ac4a4 100644
--- a/drivers/video/fbdev/mxsfb.c
+++ b/drivers/video/fbdev/mxsfb.c
@@ -172,6 +172,8 @@ struct mxsfb_info {
struct fb_info fb_info;
struct platform_device *pdev;
struct clk *clk;
+ struct clk *clk_axi;
+ struct clk *clk_disp_axi;
void __iomem *base; /* registers */
unsigned allocated_size;
int enabled;
@@ -331,6 +333,11 @@ static void mxsfb_enable_controller(struct fb_info *fb_info)
}
}
+ if (host->clk_axi)
+ clk_prepare_enable(host->clk_axi);
+
+ if (host->clk_disp_axi)
+ clk_prepare_enable(host->clk_disp_axi);
clk_prepare_enable(host->clk);
clk_set_rate(host->clk, PICOS2KHZ(fb_info->var.pixclock) * 1000U);
@@ -374,6 +381,10 @@ static void mxsfb_disable_controller(struct fb_info *fb_info)
writel(reg & ~VDCTRL4_SYNC_SIGNALS_ON, host->base + LCDC_VDCTRL4);
clk_disable_unprepare(host->clk);
+ if (host->clk_disp_axi)
+ clk_disable_unprepare(host->clk_disp_axi);
+ if (host->clk_axi)
+ clk_disable_unprepare(host->clk_axi);
host->enabled = 0;
@@ -867,6 +878,14 @@ static int mxsfb_probe(struct platform_device *pdev)
goto fb_release;
}
+ host->clk_axi = devm_clk_get(&host->pdev->dev, "axi");
+ if (IS_ERR(host->clk_axi))
+ host->clk_axi = NULL;
+
+ host->clk_disp_axi = devm_clk_get(&host->pdev->dev, "disp_axi");
+ if (IS_ERR(host->clk_disp_axi))
+ host->clk_disp_axi = NULL;
+
host->reg_lcd = devm_regulator_get(&pdev->dev, "lcd");
if (IS_ERR(host->reg_lcd))
host->reg_lcd = NULL;
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
index 2dfb6e5..3d38e47 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
+++ b/drivers/video/fbdev/omap2/displays-new/connector-dvi.c
@@ -262,8 +262,7 @@ static int dvic_probe_pdata(struct platform_device *pdev)
in = omap_dss_find_output(pdata->source);
if (in == NULL) {
- if (ddata->i2c_adapter)
- i2c_put_adapter(ddata->i2c_adapter);
+ i2c_put_adapter(ddata->i2c_adapter);
dev_err(&pdev->dev, "Failed to find video source\n");
return -EPROBE_DEFER;
@@ -352,8 +351,7 @@ static int dvic_probe(struct platform_device *pdev)
err_reg:
omap_dss_put_device(ddata->in);
- if (ddata->i2c_adapter)
- i2c_put_adapter(ddata->i2c_adapter);
+ i2c_put_adapter(ddata->i2c_adapter);
return r;
}
@@ -371,8 +369,7 @@ static int __exit dvic_remove(struct platform_device *pdev)
omap_dss_put_device(in);
- if (ddata->i2c_adapter)
- i2c_put_adapter(ddata->i2c_adapter);
+ i2c_put_adapter(ddata->i2c_adapter);
return 0;
}
diff --git a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
index 7b25967..219f14f 100644
--- a/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
+++ b/drivers/video/fbdev/omap2/displays-new/connector-hdmi.c
@@ -170,98 +170,6 @@ static bool hdmic_detect(struct omap_dss_device *dssdev)
return in->ops.hdmi->detect(in);
}
-static int hdmic_audio_enable(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
- int r;
-
- /* enable audio only if the display is active */
- if (!omapdss_device_is_enabled(dssdev))
- return -EPERM;
-
- r = in->ops.hdmi->audio_enable(in);
- if (r)
- return r;
-
- dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
-
- return 0;
-}
-
-static void hdmic_audio_disable(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- in->ops.hdmi->audio_disable(in);
-
- dssdev->audio_state = OMAP_DSS_AUDIO_DISABLED;
-}
-
-static int hdmic_audio_start(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
- int r;
-
- /*
- * No need to check the panel state. It was checked when trasitioning
- * to AUDIO_ENABLED.
- */
- if (dssdev->audio_state != OMAP_DSS_AUDIO_ENABLED)
- return -EPERM;
-
- r = in->ops.hdmi->audio_start(in);
- if (r)
- return r;
-
- dssdev->audio_state = OMAP_DSS_AUDIO_PLAYING;
-
- return 0;
-}
-
-static void hdmic_audio_stop(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- in->ops.hdmi->audio_stop(in);
-
- dssdev->audio_state = OMAP_DSS_AUDIO_ENABLED;
-}
-
-static bool hdmic_audio_supported(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- if (!omapdss_device_is_enabled(dssdev))
- return false;
-
- return in->ops.hdmi->audio_supported(in);
-}
-
-static int hdmic_audio_config(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
- int r;
-
- /* config audio only if the display is active */
- if (!omapdss_device_is_enabled(dssdev))
- return -EPERM;
-
- r = in->ops.hdmi->audio_config(in, audio);
- if (r)
- return r;
-
- dssdev->audio_state = OMAP_DSS_AUDIO_CONFIGURED;
-
- return 0;
-}
-
static int hdmic_set_hdmi_mode(struct omap_dss_device *dssdev, bool hdmi_mode)
{
struct panel_drv_data *ddata = to_panel_data(dssdev);
@@ -296,13 +204,6 @@ static struct omap_dss_driver hdmic_driver = {
.detect = hdmic_detect,
.set_hdmi_mode = hdmic_set_hdmi_mode,
.set_hdmi_infoframe = hdmic_set_infoframe,
-
- .audio_enable = hdmic_audio_enable,
- .audio_disable = hdmic_audio_disable,
- .audio_start = hdmic_audio_start,
- .audio_stop = hdmic_audio_stop,
- .audio_supported = hdmic_audio_supported,
- .audio_config = hdmic_audio_config,
};
static int hdmic_probe_pdata(struct platform_device *pdev)
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
index 47ee7cd..e349064 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-tfp410.c
@@ -249,6 +249,7 @@ static int tfp410_probe(struct platform_device *pdev)
dssdev->output_type = OMAP_DISPLAY_TYPE_DVI;
dssdev->owner = THIS_MODULE;
dssdev->phy.dpi.data_lines = ddata->data_lines;
+ dssdev->port_num = 1;
r = omapdss_register_output(dssdev);
if (r) {
diff --git a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
index c4abd56..c7a3ce2 100644
--- a/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
+++ b/drivers/video/fbdev/omap2/displays-new/encoder-tpd12s015.c
@@ -193,55 +193,6 @@ static bool tpd_detect(struct omap_dss_device *dssdev)
return gpio_get_value_cansleep(ddata->hpd_gpio);
}
-static int tpd_audio_enable(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- return in->ops.hdmi->audio_enable(in);
-}
-
-static void tpd_audio_disable(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- in->ops.hdmi->audio_disable(in);
-}
-
-static int tpd_audio_start(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- return in->ops.hdmi->audio_start(in);
-}
-
-static void tpd_audio_stop(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- in->ops.hdmi->audio_stop(in);
-}
-
-static bool tpd_audio_supported(struct omap_dss_device *dssdev)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- return in->ops.hdmi->audio_supported(in);
-}
-
-static int tpd_audio_config(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio)
-{
- struct panel_drv_data *ddata = to_panel_data(dssdev);
- struct omap_dss_device *in = ddata->in;
-
- return in->ops.hdmi->audio_config(in, audio);
-}
-
static int tpd_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
@@ -275,13 +226,6 @@ static const struct omapdss_hdmi_ops tpd_hdmi_ops = {
.detect = tpd_detect,
.set_infoframe = tpd_set_infoframe,
.set_hdmi_mode = tpd_set_hdmi_mode,
-
- .audio_enable = tpd_audio_enable,
- .audio_disable = tpd_audio_disable,
- .audio_start = tpd_audio_start,
- .audio_stop = tpd_audio_stop,
- .audio_supported = tpd_audio_supported,
- .audio_config = tpd_audio_config,
};
static int tpd_probe_pdata(struct platform_device *pdev)
@@ -409,6 +353,7 @@ static int tpd_probe(struct platform_device *pdev)
dssdev->type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->output_type = OMAP_DISPLAY_TYPE_HDMI;
dssdev->owner = THIS_MODULE;
+ dssdev->port_num = 1;
in = ddata->in;
diff --git a/drivers/video/fbdev/omap2/dss/Kconfig b/drivers/video/fbdev/omap2/dss/Kconfig
index 3d5eb6c..d1fa730 100644
--- a/drivers/video/fbdev/omap2/dss/Kconfig
+++ b/drivers/video/fbdev/omap2/dss/Kconfig
@@ -74,9 +74,6 @@ config OMAP4_DSS_HDMI
help
HDMI support for OMAP4 based SoCs.
-config OMAP4_DSS_HDMI_AUDIO
- bool
-
config OMAP5_DSS_HDMI
bool "HDMI support for OMAP5"
default n
@@ -86,10 +83,6 @@ config OMAP5_DSS_HDMI
Definition Multimedia Interface. See http://www.hdmi.org/ for HDMI
specification.
-config OMAP5_DSS_HDMI_AUDIO
- depends on OMAP5_DSS_HDMI
- bool
-
config OMAP2_DSS_SDI
bool "SDI support"
default n
diff --git a/drivers/video/fbdev/omap2/dss/Makefile b/drivers/video/fbdev/omap2/dss/Makefile
index 245f933..2ea9d38 100644
--- a/drivers/video/fbdev/omap2/dss/Makefile
+++ b/drivers/video/fbdev/omap2/dss/Makefile
@@ -2,7 +2,7 @@ obj-$(CONFIG_OMAP2_DSS_INIT) += omapdss-boot-init.o
obj-$(CONFIG_OMAP2_DSS) += omapdss.o
# Core DSS files
omapdss-y := core.o dss.o dss_features.o dispc.o dispc_coefs.o display.o \
- output.o dss-of.o
+ output.o dss-of.o pll.o
# DSS compat layer files
omapdss-y += manager.o manager-sysfs.o overlay.o overlay-sysfs.o apply.o \
dispc-compat.o display-sysfs.o
diff --git a/drivers/video/fbdev/omap2/dss/dispc.c b/drivers/video/fbdev/omap2/dss/dispc.c
index 0e9a74b..0729c08 100644
--- a/drivers/video/fbdev/omap2/dss/dispc.c
+++ b/drivers/video/fbdev/omap2/dss/dispc.c
@@ -3028,7 +3028,7 @@ static void dispc_mgr_get_lcd_divisor(enum omap_channel channel, int *lck_div,
unsigned long dispc_fclk_rate(void)
{
- struct platform_device *dsidev;
+ struct dss_pll *pll;
unsigned long r = 0;
switch (dss_get_dispc_clk_source()) {
@@ -3036,12 +3036,12 @@ unsigned long dispc_fclk_rate(void)
r = dss_get_dispc_clk_rate();
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
- dsidev = dsi_get_dsidev_from_id(0);
- r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+ pll = dss_pll_find("dsi0");
+ r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
- dsidev = dsi_get_dsidev_from_id(1);
- r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+ pll = dss_pll_find("dsi1");
+ r = pll->cinfo.clkout[0];
break;
default:
BUG();
@@ -3053,7 +3053,7 @@ unsigned long dispc_fclk_rate(void)
unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
{
- struct platform_device *dsidev;
+ struct dss_pll *pll;
int lcd;
unsigned long r;
u32 l;
@@ -3068,12 +3068,12 @@ unsigned long dispc_mgr_lclk_rate(enum omap_channel channel)
r = dss_get_dispc_clk_rate();
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
- dsidev = dsi_get_dsidev_from_id(0);
- r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+ pll = dss_pll_find("dsi0");
+ r = pll->cinfo.clkout[0];
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
- dsidev = dsi_get_dsidev_from_id(1);
- r = dsi_get_pll_hsdiv_dispc_rate(dsidev);
+ pll = dss_pll_find("dsi1");
+ r = pll->cinfo.clkout[0];
break;
default:
BUG();
diff --git a/drivers/video/fbdev/omap2/dss/dpi.c b/drivers/video/fbdev/omap2/dss/dpi.c
index 4a3363d..2edf5ca 100644
--- a/drivers/video/fbdev/omap2/dss/dpi.c
+++ b/drivers/video/fbdev/omap2/dss/dpi.c
@@ -31,17 +31,20 @@
#include <linux/regulator/consumer.h>
#include <linux/string.h>
#include <linux/of.h>
+#include <linux/clk.h>
#include <video/omapdss.h>
#include "dss.h"
#include "dss_features.h"
-static struct {
+#define HSDIV_DISPC 0
+
+struct dpi_data {
struct platform_device *pdev;
struct regulator *vdds_dsi_reg;
- struct platform_device *dsidev;
+ struct dss_pll *pll;
struct mutex lock;
@@ -52,9 +55,20 @@ static struct {
struct omap_dss_device output;
bool port_initialized;
-} dpi;
+};
+
+static struct dpi_data *dpi_get_data_from_dssdev(struct omap_dss_device *dssdev)
+{
+ return container_of(dssdev, struct dpi_data, output);
+}
+
+/* only used in non-DT mode */
+static struct dpi_data *dpi_get_data_from_pdev(struct platform_device *pdev)
+{
+ return dev_get_drvdata(&pdev->dev);
+}
-static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
+static struct dss_pll *dpi_get_pll(enum omap_channel channel)
{
/*
* XXX we can't currently use DSI PLL for DPI with OMAP3, as the DSI PLL
@@ -75,9 +89,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP4:
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
- return dsi_get_dsidev_from_id(0);
+ return dss_pll_find("dsi0");
case OMAP_DSS_CHANNEL_LCD2:
- return dsi_get_dsidev_from_id(1);
+ return dss_pll_find("dsi1");
default:
return NULL;
}
@@ -85,9 +99,9 @@ static struct platform_device *dpi_get_dsidev(enum omap_channel channel)
case OMAPDSS_VER_OMAP5:
switch (channel) {
case OMAP_DSS_CHANNEL_LCD:
- return dsi_get_dsidev_from_id(0);
+ return dss_pll_find("dsi0");
case OMAP_DSS_CHANNEL_LCD3:
- return dsi_get_dsidev_from_id(1);
+ return dss_pll_find("dsi1");
default:
return NULL;
}
@@ -114,7 +128,7 @@ static enum omap_dss_clk_source dpi_get_alt_clk_src(enum omap_channel channel)
}
struct dpi_clk_calc_ctx {
- struct platform_device *dsidev;
+ struct dss_pll *pll;
/* inputs */
@@ -122,7 +136,7 @@ struct dpi_clk_calc_ctx {
/* outputs */
- struct dsi_clock_info dsi_cinfo;
+ struct dss_pll_clock_info dsi_cinfo;
unsigned long fck;
struct dispc_clock_info dispc_cinfo;
};
@@ -154,7 +168,7 @@ static bool dpi_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
}
-static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+static bool dpi_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
void *data)
{
struct dpi_clk_calc_ctx *ctx = data;
@@ -164,30 +178,31 @@ static bool dpi_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
* shifted. So skip all odd dividers when the pixel clock is on the
* higher side.
*/
- if (regm_dispc > 1 && regm_dispc % 2 != 0 && ctx->pck_min >= 100000000)
+ if (m_dispc > 1 && m_dispc % 2 != 0 && ctx->pck_min >= 100000000)
return false;
- ctx->dsi_cinfo.regm_dispc = regm_dispc;
- ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+ ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+ ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
return dispc_div_calc(dispc, ctx->pck_min, ctx->pck_max,
dpi_calc_dispc_cb, ctx);
}
-static bool dpi_calc_pll_cb(int regn, int regm, unsigned long fint,
- unsigned long pll,
+static bool dpi_calc_pll_cb(int n, int m, unsigned long fint,
+ unsigned long clkdco,
void *data)
{
struct dpi_clk_calc_ctx *ctx = data;
- ctx->dsi_cinfo.regn = regn;
- ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.n = n;
+ ctx->dsi_cinfo.m = m;
ctx->dsi_cinfo.fint = fint;
- ctx->dsi_cinfo.clkin4ddr = pll;
+ ctx->dsi_cinfo.clkdco = clkdco;
- return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->pck_min,
- dpi_calc_hsdiv_cb, ctx);
+ return dss_pll_hsdiv_calc(ctx->pll, clkdco,
+ ctx->pck_min, dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
+ dpi_calc_hsdiv_cb, ctx);
}
static bool dpi_calc_dss_cb(unsigned long fck, void *data)
@@ -200,23 +215,23 @@ static bool dpi_calc_dss_cb(unsigned long fck, void *data)
dpi_calc_dispc_cb, ctx);
}
-static bool dpi_dsi_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
+static bool dpi_dsi_clk_calc(struct dpi_data *dpi, unsigned long pck,
+ struct dpi_clk_calc_ctx *ctx)
{
unsigned long clkin;
unsigned long pll_min, pll_max;
- clkin = dsi_get_pll_clkin(dpi.dsidev);
-
memset(ctx, 0, sizeof(*ctx));
- ctx->dsidev = dpi.dsidev;
+ ctx->pll = dpi->pll;
ctx->pck_min = pck - 1000;
ctx->pck_max = pck + 1000;
- ctx->dsi_cinfo.clkin = clkin;
pll_min = 0;
pll_max = 0;
- return dsi_pll_calc(dpi.dsidev, clkin,
+ clkin = clk_get_rate(ctx->pll->clkin);
+
+ return dss_pll_calc(ctx->pll, clkin,
pll_min, pll_max,
dpi_calc_pll_cb, ctx);
}
@@ -252,7 +267,7 @@ static bool dpi_dss_clk_calc(unsigned long pck, struct dpi_clk_calc_ctx *ctx)
-static int dpi_set_dsi_clk(enum omap_channel channel,
+static int dpi_set_dsi_clk(struct dpi_data *dpi, enum omap_channel channel,
unsigned long pck_req, unsigned long *fck, int *lck_div,
int *pck_div)
{
@@ -260,28 +275,28 @@ static int dpi_set_dsi_clk(enum omap_channel channel,
int r;
bool ok;
- ok = dpi_dsi_clk_calc(pck_req, &ctx);
+ ok = dpi_dsi_clk_calc(dpi, pck_req, &ctx);
if (!ok)
return -EINVAL;
- r = dsi_pll_set_clock_div(dpi.dsidev, &ctx.dsi_cinfo);
+ r = dss_pll_set_config(dpi->pll, &ctx.dsi_cinfo);
if (r)
return r;
dss_select_lcd_clk_source(channel,
dpi_get_alt_clk_src(channel));
- dpi.mgr_config.clock_info = ctx.dispc_cinfo;
+ dpi->mgr_config.clock_info = ctx.dispc_cinfo;
- *fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+ *fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
*lck_div = ctx.dispc_cinfo.lck_div;
*pck_div = ctx.dispc_cinfo.pck_div;
return 0;
}
-static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
- int *lck_div, int *pck_div)
+static int dpi_set_dispc_clk(struct dpi_data *dpi, unsigned long pck_req,
+ unsigned long *fck, int *lck_div, int *pck_div)
{
struct dpi_clk_calc_ctx ctx;
int r;
@@ -295,7 +310,7 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
if (r)
return r;
- dpi.mgr_config.clock_info = ctx.dispc_cinfo;
+ dpi->mgr_config.clock_info = ctx.dispc_cinfo;
*fck = ctx.fck;
*lck_div = ctx.dispc_cinfo.lck_div;
@@ -304,19 +319,21 @@ static int dpi_set_dispc_clk(unsigned long pck_req, unsigned long *fck,
return 0;
}
-static int dpi_set_mode(struct omap_overlay_manager *mgr)
+static int dpi_set_mode(struct dpi_data *dpi)
{
- struct omap_video_timings *t = &dpi.timings;
+ struct omap_dss_device *out = &dpi->output;
+ struct omap_overlay_manager *mgr = out->manager;
+ struct omap_video_timings *t = &dpi->timings;
int lck_div = 0, pck_div = 0;
unsigned long fck = 0;
unsigned long pck;
int r = 0;
- if (dpi.dsidev)
- r = dpi_set_dsi_clk(mgr->id, t->pixelclock, &fck,
+ if (dpi->pll)
+ r = dpi_set_dsi_clk(dpi, mgr->id, t->pixelclock, &fck,
&lck_div, &pck_div);
else
- r = dpi_set_dispc_clk(t->pixelclock, &fck,
+ r = dpi_set_dispc_clk(dpi, t->pixelclock, &fck,
&lck_div, &pck_div);
if (r)
return r;
@@ -335,28 +352,32 @@ static int dpi_set_mode(struct omap_overlay_manager *mgr)
return 0;
}
-static void dpi_config_lcd_manager(struct omap_overlay_manager *mgr)
+static void dpi_config_lcd_manager(struct dpi_data *dpi)
{
- dpi.mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
+ struct omap_dss_device *out = &dpi->output;
+ struct omap_overlay_manager *mgr = out->manager;
+
+ dpi->mgr_config.io_pad_mode = DSS_IO_PAD_MODE_BYPASS;
- dpi.mgr_config.stallmode = false;
- dpi.mgr_config.fifohandcheck = false;
+ dpi->mgr_config.stallmode = false;
+ dpi->mgr_config.fifohandcheck = false;
- dpi.mgr_config.video_port_width = dpi.data_lines;
+ dpi->mgr_config.video_port_width = dpi->data_lines;
- dpi.mgr_config.lcden_sig_polarity = 0;
+ dpi->mgr_config.lcden_sig_polarity = 0;
- dss_mgr_set_lcd_config(mgr, &dpi.mgr_config);
+ dss_mgr_set_lcd_config(mgr, &dpi->mgr_config);
}
static int dpi_display_enable(struct omap_dss_device *dssdev)
{
- struct omap_dss_device *out = &dpi.output;
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_dss_device *out = &dpi->output;
int r;
- mutex_lock(&dpi.lock);
+ mutex_lock(&dpi->lock);
- if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi.vdds_dsi_reg) {
+ if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI) && !dpi->vdds_dsi_reg) {
DSSERR("no VDSS_DSI regulator\n");
r = -ENODEV;
goto err_no_reg;
@@ -369,7 +390,7 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
}
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI)) {
- r = regulator_enable(dpi.vdds_dsi_reg);
+ r = regulator_enable(dpi->vdds_dsi_reg);
if (r)
goto err_reg_enable;
}
@@ -378,25 +399,21 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dispc;
- r = dss_dpi_select_source(out->manager->id);
+ r = dss_dpi_select_source(out->port_num, out->manager->id);
if (r)
goto err_src_sel;
- if (dpi.dsidev) {
- r = dsi_runtime_get(dpi.dsidev);
- if (r)
- goto err_get_dsi;
-
- r = dsi_pll_init(dpi.dsidev, 0, 1);
+ if (dpi->pll) {
+ r = dss_pll_enable(dpi->pll);
if (r)
goto err_dsi_pll_init;
}
- r = dpi_set_mode(out->manager);
+ r = dpi_set_mode(dpi);
if (r)
goto err_set_mode;
- dpi_config_lcd_manager(out->manager);
+ dpi_config_lcd_manager(dpi);
mdelay(2);
@@ -404,78 +421,80 @@ static int dpi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_mgr_enable;
- mutex_unlock(&dpi.lock);
+ mutex_unlock(&dpi->lock);
return 0;
err_mgr_enable:
err_set_mode:
- if (dpi.dsidev)
- dsi_pll_uninit(dpi.dsidev, true);
+ if (dpi->pll)
+ dss_pll_disable(dpi->pll);
err_dsi_pll_init:
- if (dpi.dsidev)
- dsi_runtime_put(dpi.dsidev);
-err_get_dsi:
err_src_sel:
dispc_runtime_put();
err_get_dispc:
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
- regulator_disable(dpi.vdds_dsi_reg);
+ regulator_disable(dpi->vdds_dsi_reg);
err_reg_enable:
err_no_out_mgr:
err_no_reg:
- mutex_unlock(&dpi.lock);
+ mutex_unlock(&dpi->lock);
return r;
}
static void dpi_display_disable(struct omap_dss_device *dssdev)
{
- struct omap_overlay_manager *mgr = dpi.output.manager;
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_overlay_manager *mgr = dpi->output.manager;
- mutex_lock(&dpi.lock);
+ mutex_lock(&dpi->lock);
dss_mgr_disable(mgr);
- if (dpi.dsidev) {
+ if (dpi->pll) {
dss_select_lcd_clk_source(mgr->id, OMAP_DSS_CLK_SRC_FCK);
- dsi_pll_uninit(dpi.dsidev, true);
- dsi_runtime_put(dpi.dsidev);
+ dss_pll_disable(dpi->pll);
}
dispc_runtime_put();
if (dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
- regulator_disable(dpi.vdds_dsi_reg);
+ regulator_disable(dpi->vdds_dsi_reg);
- mutex_unlock(&dpi.lock);
+ mutex_unlock(&dpi->lock);
}
static void dpi_set_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
DSSDBG("dpi_set_timings\n");
- mutex_lock(&dpi.lock);
+ mutex_lock(&dpi->lock);
- dpi.timings = *timings;
+ dpi->timings = *timings;
- mutex_unlock(&dpi.lock);
+ mutex_unlock(&dpi->lock);
}
static void dpi_get_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- mutex_lock(&dpi.lock);
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+
+ mutex_lock(&dpi->lock);
- *timings = dpi.timings;
+ *timings = dpi->timings;
- mutex_unlock(&dpi.lock);
+ mutex_unlock(&dpi->lock);
}
static int dpi_check_timings(struct omap_dss_device *dssdev,
struct omap_video_timings *timings)
{
- struct omap_overlay_manager *mgr = dpi.output.manager;
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
+ struct omap_overlay_manager *mgr = dpi->output.manager;
int lck_div, pck_div;
unsigned long fck;
unsigned long pck;
@@ -488,12 +507,12 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
if (timings->pixelclock == 0)
return -EINVAL;
- if (dpi.dsidev) {
- ok = dpi_dsi_clk_calc(timings->pixelclock, &ctx);
+ if (dpi->pll) {
+ ok = dpi_dsi_clk_calc(dpi, timings->pixelclock, &ctx);
if (!ok)
return -EINVAL;
- fck = ctx.dsi_cinfo.dsi_pll_hsdiv_dispc_clk;
+ fck = ctx.dsi_cinfo.clkout[HSDIV_DISPC];
} else {
ok = dpi_dss_clk_calc(timings->pixelclock, &ctx);
if (!ok)
@@ -514,74 +533,69 @@ static int dpi_check_timings(struct omap_dss_device *dssdev,
static void dpi_set_data_lines(struct omap_dss_device *dssdev, int data_lines)
{
- mutex_lock(&dpi.lock);
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
- dpi.data_lines = data_lines;
+ mutex_lock(&dpi->lock);
- mutex_unlock(&dpi.lock);
+ dpi->data_lines = data_lines;
+
+ mutex_unlock(&dpi->lock);
}
-static int dpi_verify_dsi_pll(struct platform_device *dsidev)
+static int dpi_verify_dsi_pll(struct dss_pll *pll)
{
int r;
/* do initial setup with the PLL to see if it is operational */
- r = dsi_runtime_get(dsidev);
+ r = dss_pll_enable(pll);
if (r)
return r;
- r = dsi_pll_init(dsidev, 0, 1);
- if (r) {
- dsi_runtime_put(dsidev);
- return r;
- }
-
- dsi_pll_uninit(dsidev, true);
- dsi_runtime_put(dsidev);
+ dss_pll_disable(pll);
return 0;
}
-static int dpi_init_regulator(void)
+static int dpi_init_regulator(struct dpi_data *dpi)
{
struct regulator *vdds_dsi;
if (!dss_has_feature(FEAT_DPI_USES_VDDS_DSI))
return 0;
- if (dpi.vdds_dsi_reg)
+ if (dpi->vdds_dsi_reg)
return 0;
- vdds_dsi = devm_regulator_get(&dpi.pdev->dev, "vdds_dsi");
+ vdds_dsi = devm_regulator_get(&dpi->pdev->dev, "vdds_dsi");
if (IS_ERR(vdds_dsi)) {
if (PTR_ERR(vdds_dsi) != -EPROBE_DEFER)
DSSERR("can't get VDDS_DSI regulator\n");
return PTR_ERR(vdds_dsi);
}
- dpi.vdds_dsi_reg = vdds_dsi;
+ dpi->vdds_dsi_reg = vdds_dsi;
return 0;
}
-static void dpi_init_pll(void)
+static void dpi_init_pll(struct dpi_data *dpi)
{
- struct platform_device *dsidev;
+ struct dss_pll *pll;
- if (dpi.dsidev)
+ if (dpi->pll)
return;
- dsidev = dpi_get_dsidev(dpi.output.dispc_channel);
- if (!dsidev)
+ pll = dpi_get_pll(dpi->output.dispc_channel);
+ if (!pll)
return;
- if (dpi_verify_dsi_pll(dsidev)) {
+ if (dpi_verify_dsi_pll(pll)) {
DSSWARN("DSI PLL not operational\n");
return;
}
- dpi.dsidev = dsidev;
+ dpi->pll = pll;
}
/*
@@ -590,7 +604,7 @@ static void dpi_init_pll(void)
* the channel in some more dynamic manner, or get the channel as a user
* parameter.
*/
-static enum omap_channel dpi_get_channel(void)
+static enum omap_channel dpi_get_channel(int port_num)
{
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP24xx:
@@ -618,14 +632,15 @@ static enum omap_channel dpi_get_channel(void)
static int dpi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
+ struct dpi_data *dpi = dpi_get_data_from_dssdev(dssdev);
struct omap_overlay_manager *mgr;
int r;
- r = dpi_init_regulator();
+ r = dpi_init_regulator(dpi);
if (r)
return r;
- dpi_init_pll();
+ dpi_init_pll(dpi);
mgr = omap_dss_get_overlay_manager(dssdev->dispc_channel);
if (!mgr)
@@ -676,13 +691,14 @@ static const struct omapdss_dpi_ops dpi_ops = {
static void dpi_init_output(struct platform_device *pdev)
{
- struct omap_dss_device *out = &dpi.output;
+ struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
+ struct omap_dss_device *out = &dpi->output;
out->dev = &pdev->dev;
out->id = OMAP_DSS_OUTPUT_DPI;
out->output_type = OMAP_DISPLAY_TYPE_DPI;
out->name = "dpi.0";
- out->dispc_channel = dpi_get_channel();
+ out->dispc_channel = dpi_get_channel(0);
out->ops.dpi = &dpi_ops;
out->owner = THIS_MODULE;
@@ -691,16 +707,69 @@ static void dpi_init_output(struct platform_device *pdev)
static void __exit dpi_uninit_output(struct platform_device *pdev)
{
- struct omap_dss_device *out = &dpi.output;
+ struct dpi_data *dpi = dpi_get_data_from_pdev(pdev);
+ struct omap_dss_device *out = &dpi->output;
+
+ omapdss_unregister_output(out);
+}
+
+static void dpi_init_output_port(struct platform_device *pdev,
+ struct device_node *port)
+{
+ struct dpi_data *dpi = port->data;
+ struct omap_dss_device *out = &dpi->output;
+ int r;
+ u32 port_num;
+
+ r = of_property_read_u32(port, "reg", &port_num);
+ if (r)
+ port_num = 0;
+
+ switch (port_num) {
+ case 2:
+ out->name = "dpi.2";
+ break;
+ case 1:
+ out->name = "dpi.1";
+ break;
+ case 0:
+ default:
+ out->name = "dpi.0";
+ break;
+ }
+
+ out->dev = &pdev->dev;
+ out->id = OMAP_DSS_OUTPUT_DPI;
+ out->output_type = OMAP_DISPLAY_TYPE_DPI;
+ out->dispc_channel = dpi_get_channel(port_num);
+ out->port_num = port_num;
+ out->ops.dpi = &dpi_ops;
+ out->owner = THIS_MODULE;
+
+ omapdss_register_output(out);
+}
+
+static void __exit dpi_uninit_output_port(struct device_node *port)
+{
+ struct dpi_data *dpi = port->data;
+ struct omap_dss_device *out = &dpi->output;
omapdss_unregister_output(out);
}
static int omap_dpi_probe(struct platform_device *pdev)
{
- dpi.pdev = pdev;
+ struct dpi_data *dpi;
+
+ dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+ if (!dpi)
+ return -ENOMEM;
- mutex_init(&dpi.lock);
+ dpi->pdev = pdev;
+
+ dev_set_drvdata(&pdev->dev, dpi);
+
+ mutex_init(&dpi->lock);
dpi_init_output(pdev);
@@ -736,10 +805,15 @@ void __exit dpi_uninit_platform_driver(void)
int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
{
+ struct dpi_data *dpi;
struct device_node *ep;
u32 datalines;
int r;
+ dpi = devm_kzalloc(&pdev->dev, sizeof(*dpi), GFP_KERNEL);
+ if (!dpi)
+ return -ENOMEM;
+
ep = omapdss_of_get_next_endpoint(port, NULL);
if (!ep)
return 0;
@@ -750,17 +824,18 @@ int __init dpi_init_port(struct platform_device *pdev, struct device_node *port)
goto err_datalines;
}
- dpi.data_lines = datalines;
+ dpi->data_lines = datalines;
of_node_put(ep);
- dpi.pdev = pdev;
+ dpi->pdev = pdev;
+ port->data = dpi;
- mutex_init(&dpi.lock);
+ mutex_init(&dpi->lock);
- dpi_init_output(pdev);
+ dpi_init_output_port(pdev, port);
- dpi.port_initialized = true;
+ dpi->port_initialized = true;
return 0;
@@ -770,10 +845,12 @@ err_datalines:
return r;
}
-void __exit dpi_uninit_port(void)
+void __exit dpi_uninit_port(struct device_node *port)
{
- if (!dpi.port_initialized)
+ struct dpi_data *dpi = port->data;
+
+ if (!dpi->port_initialized)
return;
- dpi_uninit_output(dpi.pdev);
+ dpi_uninit_output_port(port);
}
diff --git a/drivers/video/fbdev/omap2/dss/dsi.c b/drivers/video/fbdev/omap2/dss/dsi.c
index 0793bc6..73af351 100644
--- a/drivers/video/fbdev/omap2/dss/dsi.c
+++ b/drivers/video/fbdev/omap2/dss/dsi.c
@@ -219,6 +219,10 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev,
static int dsi_vc_send_null(struct omap_dss_device *dssdev, int channel);
+/* DSI PLL HSDIV indices */
+#define HSDIV_DISPC 0
+#define HSDIV_DSI 1
+
#define DSI_MAX_NR_ISRS 2
#define DSI_MAX_NR_LANES 5
@@ -271,6 +275,7 @@ struct dsi_isr_tables {
struct dsi_clk_calc_ctx {
struct platform_device *dsidev;
+ struct dss_pll *pll;
/* inputs */
@@ -280,13 +285,18 @@ struct dsi_clk_calc_ctx {
/* outputs */
- struct dsi_clock_info dsi_cinfo;
+ struct dss_pll_clock_info dsi_cinfo;
struct dispc_clock_info dispc_cinfo;
struct omap_video_timings dispc_vm;
struct omap_dss_dsi_videomode_timings dsi_vm;
};
+struct dsi_lp_clock_info {
+ unsigned long lp_clk;
+ u16 lp_clk_div;
+};
+
struct dsi_data {
struct platform_device *pdev;
void __iomem *proto_base;
@@ -300,12 +310,14 @@ struct dsi_data {
bool is_enabled;
struct clk *dss_clk;
- struct clk *sys_clk;
struct dispc_clock_info user_dispc_cinfo;
- struct dsi_clock_info user_dsi_cinfo;
+ struct dss_pll_clock_info user_dsi_cinfo;
+
+ struct dsi_lp_clock_info user_lp_cinfo;
+ struct dsi_lp_clock_info current_lp_cinfo;
- struct dsi_clock_info current_cinfo;
+ struct dss_pll pll;
bool vdds_dsi_enabled;
struct regulator *vdds_dsi_reg;
@@ -321,8 +333,6 @@ struct dsi_data {
struct mutex lock;
struct semaphore bus_lock;
- unsigned pll_locked;
-
spinlock_t irq_lock;
struct dsi_isr_tables isr_tables;
/* space for a copy used by the interrupt handler */
@@ -347,7 +357,7 @@ struct dsi_data {
unsigned long cache_req_pck;
unsigned long cache_clk_freq;
- struct dsi_clock_info cache_cinfo;
+ struct dss_pll_clock_info cache_cinfo;
u32 errors;
spinlock_t errors_lock;
@@ -362,11 +372,6 @@ struct dsi_data {
spinlock_t irq_stats_lock;
struct dsi_irq_stats irq_stats;
#endif
- /* DSI PLL Parameter Ranges */
- unsigned long regm_max, regn_max;
- unsigned long regm_dispc_max, regm_dsi_max;
- unsigned long fint_min, fint_max;
- unsigned long lpdiv_max;
unsigned num_lanes_supported;
unsigned line_buffer_size;
@@ -412,7 +417,7 @@ static inline struct platform_device *dsi_get_dsidev_from_dssdev(struct omap_dss
return to_platform_device(dssdev->dev);
}
-struct platform_device *dsi_get_dsidev_from_id(int module)
+static struct platform_device *dsi_get_dsidev_from_id(int module)
{
struct omap_dss_device *out;
enum omap_dss_output_id id;
@@ -1134,7 +1139,7 @@ static u32 dsi_get_errors(struct platform_device *dsidev)
return e;
}
-int dsi_runtime_get(struct platform_device *dsidev)
+static int dsi_runtime_get(struct platform_device *dsidev)
{
int r;
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
@@ -1146,7 +1151,7 @@ int dsi_runtime_get(struct platform_device *dsidev)
return r < 0 ? r : 0;
}
-void dsi_runtime_put(struct platform_device *dsidev)
+static void dsi_runtime_put(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r;
@@ -1188,23 +1193,6 @@ static int dsi_regulator_init(struct platform_device *dsidev)
return 0;
}
-/* source clock for DSI PLL. this could also be PCLKFREE */
-static inline void dsi_enable_pll_clock(struct platform_device *dsidev,
- bool enable)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
- if (enable)
- clk_prepare_enable(dsi->sys_clk);
- else
- clk_disable_unprepare(dsi->sys_clk);
-
- if (enable && dsi->pll_locked) {
- if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1)
- DSSERR("cannot lock PLL when enabling clocks\n");
- }
-}
-
static void _dsi_print_reset_status(struct platform_device *dsidev)
{
u32 l;
@@ -1256,25 +1244,25 @@ static inline int dsi_if_enable(struct platform_device *dsidev, bool enable)
return 0;
}
-unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
+static unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- return dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk;
+ return dsi->pll.cinfo.clkout[HSDIV_DISPC];
}
static unsigned long dsi_get_pll_hsdiv_dsi_rate(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- return dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk;
+ return dsi->pll.cinfo.clkout[HSDIV_DSI];
}
static unsigned long dsi_get_txbyteclkhs(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- return dsi->current_cinfo.clkin4ddr / 16;
+ return dsi->pll.cinfo.clkdco / 16;
}
static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
@@ -1293,10 +1281,10 @@ static unsigned long dsi_fclk_rate(struct platform_device *dsidev)
return r;
}
-static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
- unsigned long lp_clk_min, unsigned long lp_clk_max)
+static int dsi_lp_clock_calc(unsigned long dsi_fclk,
+ unsigned long lp_clk_min, unsigned long lp_clk_max,
+ struct dsi_lp_clock_info *lp_cinfo)
{
- unsigned long dsi_fclk = cinfo->dsi_pll_hsdiv_dsi_clk;
unsigned lp_clk_div;
unsigned long lp_clk;
@@ -1306,8 +1294,8 @@ static int dsi_lp_clock_calc(struct dsi_clock_info *cinfo,
if (lp_clk < lp_clk_min || lp_clk > lp_clk_max)
return -EINVAL;
- cinfo->lp_clk_div = lp_clk_div;
- cinfo->lp_clk = lp_clk;
+ lp_cinfo->lp_clk_div = lp_clk_div;
+ lp_cinfo->lp_clk = lp_clk;
return 0;
}
@@ -1318,10 +1306,12 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
unsigned long dsi_fclk;
unsigned lp_clk_div;
unsigned long lp_clk;
+ unsigned lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
+
- lp_clk_div = dsi->user_dsi_cinfo.lp_clk_div;
+ lp_clk_div = dsi->user_lp_cinfo.lp_clk_div;
- if (lp_clk_div == 0 || lp_clk_div > dsi->lpdiv_max)
+ if (lp_clk_div == 0 || lp_clk_div > lpdiv_max)
return -EINVAL;
dsi_fclk = dsi_fclk_rate(dsidev);
@@ -1329,8 +1319,8 @@ static int dsi_set_lp_clk_divisor(struct platform_device *dsidev)
lp_clk = dsi_fclk / 2 / lp_clk_div;
DSSDBG("LP_CLK_DIV %u, LP_CLK %lu\n", lp_clk_div, lp_clk);
- dsi->current_cinfo.lp_clk = lp_clk;
- dsi->current_cinfo.lp_clk_div = lp_clk_div;
+ dsi->current_lp_cinfo.lp_clk = lp_clk;
+ dsi->current_lp_cinfo.lp_clk_div = lp_clk_div;
/* LP_CLK_DIVISOR */
REG_FLD_MOD(dsidev, DSI_CLK_CTRL, lp_clk_div, 12, 0);
@@ -1391,286 +1381,33 @@ static int dsi_pll_power(struct platform_device *dsidev,
return 0;
}
-unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- return clk_get_rate(dsi->sys_clk);
-}
-
-bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
- unsigned long out_min, dsi_hsdiv_calc_func func, void *data)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- int regm, regm_start, regm_stop;
- unsigned long out_max;
- unsigned long out;
-
- out_min = out_min ? out_min : 1;
- out_max = dss_feat_get_param_max(FEAT_PARAM_DSS_FCK);
-
- regm_start = max(DIV_ROUND_UP(pll, out_max), 1ul);
- regm_stop = min(pll / out_min, dsi->regm_dispc_max);
-
- for (regm = regm_start; regm <= regm_stop; ++regm) {
- out = pll / regm;
-
- if (func(regm, out, data))
- return true;
- }
-
- return false;
-}
-
-bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
- unsigned long pll_min, unsigned long pll_max,
- dsi_pll_calc_func func, void *data)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- int regn, regn_start, regn_stop;
- int regm, regm_start, regm_stop;
- unsigned long fint, pll;
- const unsigned long pll_hw_max = 1800000000;
- unsigned long fint_hw_min, fint_hw_max;
-
- fint_hw_min = dsi->fint_min;
- fint_hw_max = dsi->fint_max;
- regn_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
- regn_stop = min(clkin / fint_hw_min, dsi->regn_max);
-
- pll_max = pll_max ? pll_max : ULONG_MAX;
-
- for (regn = regn_start; regn <= regn_stop; ++regn) {
- fint = clkin / regn;
-
- regm_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
- 1ul);
- regm_stop = min3(pll_max / fint / 2,
- pll_hw_max / fint / 2,
- dsi->regm_max);
-
- for (regm = regm_start; regm <= regm_stop; ++regm) {
- pll = 2 * regm * fint;
-
- if (func(regn, regm, fint, pll, data))
- return true;
- }
- }
-
- return false;
-}
-
-/* calculate clock rates using dividers in cinfo */
-static int dsi_calc_clock_rates(struct platform_device *dsidev,
- struct dsi_clock_info *cinfo)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
- if (cinfo->regn == 0 || cinfo->regn > dsi->regn_max)
- return -EINVAL;
-
- if (cinfo->regm == 0 || cinfo->regm > dsi->regm_max)
- return -EINVAL;
-
- if (cinfo->regm_dispc > dsi->regm_dispc_max)
- return -EINVAL;
-
- if (cinfo->regm_dsi > dsi->regm_dsi_max)
- return -EINVAL;
-
- cinfo->clkin = clk_get_rate(dsi->sys_clk);
- cinfo->fint = cinfo->clkin / cinfo->regn;
-
- if (cinfo->fint > dsi->fint_max || cinfo->fint < dsi->fint_min)
- return -EINVAL;
-
- cinfo->clkin4ddr = 2 * cinfo->regm * cinfo->fint;
-
- if (cinfo->clkin4ddr > 1800 * 1000 * 1000)
- return -EINVAL;
-
- if (cinfo->regm_dispc > 0)
- cinfo->dsi_pll_hsdiv_dispc_clk =
- cinfo->clkin4ddr / cinfo->regm_dispc;
- else
- cinfo->dsi_pll_hsdiv_dispc_clk = 0;
-
- if (cinfo->regm_dsi > 0)
- cinfo->dsi_pll_hsdiv_dsi_clk =
- cinfo->clkin4ddr / cinfo->regm_dsi;
- else
- cinfo->dsi_pll_hsdiv_dsi_clk = 0;
-
- return 0;
-}
-
-static void dsi_pll_calc_dsi_fck(struct dsi_clock_info *cinfo)
+static void dsi_pll_calc_dsi_fck(struct dss_pll_clock_info *cinfo)
{
unsigned long max_dsi_fck;
max_dsi_fck = dss_feat_get_param_max(FEAT_PARAM_DSI_FCK);
- cinfo->regm_dsi = DIV_ROUND_UP(cinfo->clkin4ddr, max_dsi_fck);
- cinfo->dsi_pll_hsdiv_dsi_clk = cinfo->clkin4ddr / cinfo->regm_dsi;
+ cinfo->mX[HSDIV_DSI] = DIV_ROUND_UP(cinfo->clkdco, max_dsi_fck);
+ cinfo->clkout[HSDIV_DSI] = cinfo->clkdco / cinfo->mX[HSDIV_DSI];
}
-int dsi_pll_set_clock_div(struct platform_device *dsidev,
- struct dsi_clock_info *cinfo)
+static int dsi_pll_enable(struct dss_pll *pll)
{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
+ struct platform_device *dsidev = dsi->pdev;
int r = 0;
- u32 l;
- int f = 0;
- u8 regn_start, regn_end, regm_start, regm_end;
- u8 regm_dispc_start, regm_dispc_end, regm_dsi_start, regm_dsi_end;
-
- DSSDBG("DSI PLL clock config starts");
-
- dsi->current_cinfo.clkin = cinfo->clkin;
- dsi->current_cinfo.fint = cinfo->fint;
- dsi->current_cinfo.clkin4ddr = cinfo->clkin4ddr;
- dsi->current_cinfo.dsi_pll_hsdiv_dispc_clk =
- cinfo->dsi_pll_hsdiv_dispc_clk;
- dsi->current_cinfo.dsi_pll_hsdiv_dsi_clk =
- cinfo->dsi_pll_hsdiv_dsi_clk;
-
- dsi->current_cinfo.regn = cinfo->regn;
- dsi->current_cinfo.regm = cinfo->regm;
- dsi->current_cinfo.regm_dispc = cinfo->regm_dispc;
- dsi->current_cinfo.regm_dsi = cinfo->regm_dsi;
-
- DSSDBG("DSI Fint %ld\n", cinfo->fint);
-
- DSSDBG("clkin rate %ld\n", cinfo->clkin);
-
- /* DSIPHY == CLKIN4DDR */
- DSSDBG("CLKIN4DDR = 2 * %d / %d * %lu = %lu\n",
- cinfo->regm,
- cinfo->regn,
- cinfo->clkin,
- cinfo->clkin4ddr);
-
- DSSDBG("Data rate on 1 DSI lane %ld Mbps\n",
- cinfo->clkin4ddr / 1000 / 1000 / 2);
-
- DSSDBG("Clock lane freq %ld Hz\n", cinfo->clkin4ddr / 4);
-
- DSSDBG("regm_dispc = %d, %s (%s) = %lu\n", cinfo->regm_dispc,
- dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
- dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
- cinfo->dsi_pll_hsdiv_dispc_clk);
- DSSDBG("regm_dsi = %d, %s (%s) = %lu\n", cinfo->regm_dsi,
- dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
- dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
- cinfo->dsi_pll_hsdiv_dsi_clk);
-
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGN, &regn_start, &regn_end);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM, &regm_start, &regm_end);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DISPC, &regm_dispc_start,
- &regm_dispc_end);
- dss_feat_get_reg_field(FEAT_REG_DSIPLL_REGM_DSI, &regm_dsi_start,
- &regm_dsi_end);
-
- /* DSI_PLL_AUTOMODE = manual */
- REG_FLD_MOD(dsidev, DSI_PLL_CONTROL, 0, 0, 0);
-
- l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION1);
- l = FLD_MOD(l, 1, 0, 0); /* DSI_PLL_STOPMODE */
- /* DSI_PLL_REGN */
- l = FLD_MOD(l, cinfo->regn - 1, regn_start, regn_end);
- /* DSI_PLL_REGM */
- l = FLD_MOD(l, cinfo->regm, regm_start, regm_end);
- /* DSI_CLOCK_DIV */
- l = FLD_MOD(l, cinfo->regm_dispc > 0 ? cinfo->regm_dispc - 1 : 0,
- regm_dispc_start, regm_dispc_end);
- /* DSIPROTO_CLOCK_DIV */
- l = FLD_MOD(l, cinfo->regm_dsi > 0 ? cinfo->regm_dsi - 1 : 0,
- regm_dsi_start, regm_dsi_end);
- dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION1, l);
-
- BUG_ON(cinfo->fint < dsi->fint_min || cinfo->fint > dsi->fint_max);
-
- l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
-
- if (dss_has_feature(FEAT_DSI_PLL_FREQSEL)) {
- f = cinfo->fint < 1000000 ? 0x3 :
- cinfo->fint < 1250000 ? 0x4 :
- cinfo->fint < 1500000 ? 0x5 :
- cinfo->fint < 1750000 ? 0x6 :
- 0x7;
-
- l = FLD_MOD(l, f, 4, 1); /* DSI_PLL_FREQSEL */
- } else if (dss_has_feature(FEAT_DSI_PLL_SELFREQDCO)) {
- f = cinfo->clkin4ddr < 1000000000 ? 0x2 : 0x4;
-
- l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
- }
-
- l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
- l = FLD_MOD(l, 0, 14, 14); /* DSIPHY_CLKINEN */
- l = FLD_MOD(l, 1, 20, 20); /* DSI_HSDIVBYPASS */
- if (dss_has_feature(FEAT_DSI_PLL_REFSEL))
- l = FLD_MOD(l, 3, 22, 21); /* REF_SYSCLK = sysclk */
- dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
-
- REG_FLD_MOD(dsidev, DSI_PLL_GO, 1, 0, 0); /* DSI_PLL_GO */
-
- if (wait_for_bit_change(dsidev, DSI_PLL_GO, 0, 0) != 0) {
- DSSERR("dsi pll go bit not going down.\n");
- r = -EIO;
- goto err;
- }
-
- if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 1, 1) != 1) {
- DSSERR("cannot lock PLL\n");
- r = -EIO;
- goto err;
- }
-
- dsi->pll_locked = 1;
-
- l = dsi_read_reg(dsidev, DSI_PLL_CONFIGURATION2);
- l = FLD_MOD(l, 0, 0, 0); /* DSI_PLL_IDLE */
- l = FLD_MOD(l, 0, 5, 5); /* DSI_PLL_PLLLPMODE */
- l = FLD_MOD(l, 0, 6, 6); /* DSI_PLL_LOWCURRSTBY */
- l = FLD_MOD(l, 0, 7, 7); /* DSI_PLL_TIGHTPHASELOCK */
- l = FLD_MOD(l, 0, 8, 8); /* DSI_PLL_DRIFTGUARDEN */
- l = FLD_MOD(l, 0, 10, 9); /* DSI_PLL_LOCKSEL */
- l = FLD_MOD(l, 1, 13, 13); /* DSI_PLL_REFEN */
- l = FLD_MOD(l, 1, 14, 14); /* DSIPHY_CLKINEN */
- l = FLD_MOD(l, 0, 15, 15); /* DSI_BYPASSEN */
- l = FLD_MOD(l, 1, 16, 16); /* DSS_CLOCK_EN */
- l = FLD_MOD(l, 0, 17, 17); /* DSS_CLOCK_PWDN */
- l = FLD_MOD(l, 1, 18, 18); /* DSI_PROTO_CLOCK_EN */
- l = FLD_MOD(l, 0, 19, 19); /* DSI_PROTO_CLOCK_PWDN */
- l = FLD_MOD(l, 0, 20, 20); /* DSI_HSDIVBYPASS */
- dsi_write_reg(dsidev, DSI_PLL_CONFIGURATION2, l);
-
- DSSDBG("PLL config done\n");
-err:
- return r;
-}
-
-int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
- bool enable_hsdiv)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- int r = 0;
- enum dsi_pll_power_state pwstate;
DSSDBG("PLL init\n");
- /*
- * It seems that on many OMAPs we need to enable both to have a
- * functional HSDivider.
- */
- enable_hsclk = enable_hsdiv = true;
-
r = dsi_regulator_init(dsidev);
if (r)
return r;
- dsi_enable_pll_clock(dsidev, 1);
+ r = dsi_runtime_get(dsidev);
+ if (r)
+ return r;
+
/*
* Note: SCP CLK is not required on OMAP3, but it is required on OMAP4.
*/
@@ -1697,16 +1434,7 @@ int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
* fill the whole display. No idea about this */
dispc_pck_free_enable(0);
- if (enable_hsclk && enable_hsdiv)
- pwstate = DSI_PLL_POWER_ON_ALL;
- else if (enable_hsclk)
- pwstate = DSI_PLL_POWER_ON_HSCLK;
- else if (enable_hsdiv)
- pwstate = DSI_PLL_POWER_ON_DIV;
- else
- pwstate = DSI_PLL_POWER_OFF;
-
- r = dsi_pll_power(dsidev, pwstate);
+ r = dsi_pll_power(dsidev, DSI_PLL_POWER_ON_ALL);
if (r)
goto err1;
@@ -1721,15 +1449,14 @@ err1:
}
err0:
dsi_disable_scp_clk(dsidev);
- dsi_enable_pll_clock(dsidev, 0);
+ dsi_runtime_put(dsidev);
return r;
}
-void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
+static void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- dsi->pll_locked = 0;
dsi_pll_power(dsidev, DSI_PLL_POWER_OFF);
if (disconnect_lanes) {
WARN_ON(!dsi->vdds_dsi_enabled);
@@ -1738,18 +1465,27 @@ void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes)
}
dsi_disable_scp_clk(dsidev);
- dsi_enable_pll_clock(dsidev, 0);
+ dsi_runtime_put(dsidev);
DSSDBG("PLL uninit done\n");
}
+static void dsi_pll_disable(struct dss_pll *pll)
+{
+ struct dsi_data *dsi = container_of(pll, struct dsi_data, pll);
+ struct platform_device *dsidev = dsi->pdev;
+
+ dsi_pll_uninit(dsidev, true);
+}
+
static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
struct seq_file *s)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info *cinfo = &dsi->current_cinfo;
+ struct dss_pll_clock_info *cinfo = &dsi->pll.cinfo;
enum omap_dss_clk_source dispc_clk_src, dsi_clk_src;
int dsi_module = dsi->module_id;
+ struct dss_pll *pll = &dsi->pll;
dispc_clk_src = dss_get_dispc_clk_source();
dsi_clk_src = dss_get_dsi_clk_source(dsi_module);
@@ -1759,28 +1495,28 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
seq_printf(s, "- DSI%d PLL -\n", dsi_module + 1);
- seq_printf(s, "dsi pll clkin\t%lu\n", cinfo->clkin);
+ seq_printf(s, "dsi pll clkin\t%lu\n", clk_get_rate(pll->clkin));
- seq_printf(s, "Fint\t\t%-16luregn %u\n", cinfo->fint, cinfo->regn);
+ seq_printf(s, "Fint\t\t%-16lun %u\n", cinfo->fint, cinfo->n);
- seq_printf(s, "CLKIN4DDR\t%-16luregm %u\n",
- cinfo->clkin4ddr, cinfo->regm);
+ seq_printf(s, "CLKIN4DDR\t%-16lum %u\n",
+ cinfo->clkdco, cinfo->m);
- seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16luregm_dispc %u\t(%s)\n",
+ seq_printf(s, "DSI_PLL_HSDIV_DISPC (%s)\t%-16lum_dispc %u\t(%s)\n",
dss_feat_get_clk_source_name(dsi_module == 0 ?
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC :
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC),
- cinfo->dsi_pll_hsdiv_dispc_clk,
- cinfo->regm_dispc,
+ cinfo->clkout[HSDIV_DISPC],
+ cinfo->mX[HSDIV_DISPC],
dispc_clk_src == OMAP_DSS_CLK_SRC_FCK ?
"off" : "on");
- seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16luregm_dsi %u\t(%s)\n",
+ seq_printf(s, "DSI_PLL_HSDIV_DSI (%s)\t%-16lum_dsi %u\t(%s)\n",
dss_feat_get_clk_source_name(dsi_module == 0 ?
OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI :
OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI),
- cinfo->dsi_pll_hsdiv_dsi_clk,
- cinfo->regm_dsi,
+ cinfo->clkout[HSDIV_DSI],
+ cinfo->mX[HSDIV_DSI],
dsi_clk_src == OMAP_DSS_CLK_SRC_FCK ?
"off" : "on");
@@ -1793,11 +1529,11 @@ static void dsi_dump_dsidev_clocks(struct platform_device *dsidev,
seq_printf(s, "DSI_FCLK\t%lu\n", dsi_fclk_rate(dsidev));
seq_printf(s, "DDR_CLK\t\t%lu\n",
- cinfo->clkin4ddr / 4);
+ cinfo->clkdco / 4);
seq_printf(s, "TxByteClkHS\t%lu\n", dsi_get_txbyteclkhs(dsidev));
- seq_printf(s, "LP_CLK\t\t%lu\n", cinfo->lp_clk);
+ seq_printf(s, "LP_CLK\t\t%lu\n", dsi->current_lp_cinfo.lp_clk);
dsi_runtime_put(dsidev);
}
@@ -2132,7 +1868,7 @@ static inline unsigned ns2ddr(struct platform_device *dsidev, unsigned ns)
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
/* convert time in ns to ddr ticks, rounding up */
- unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
+ unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
return (ns * (ddr_clk / 1000 / 1000) + 999) / 1000;
}
@@ -2140,7 +1876,7 @@ static inline unsigned ddr2ns(struct platform_device *dsidev, unsigned ddr)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- unsigned long ddr_clk = dsi->current_cinfo.clkin4ddr / 4;
+ unsigned long ddr_clk = dsi->pll.cinfo.clkdco / 4;
return ddr * 1000 * 1000 / (ddr_clk / 1000);
}
@@ -3730,7 +3466,7 @@ static void dsi_config_cmd_mode_interleaving(struct platform_device *dsidev)
struct omap_video_timings *timings = &dsi->timings;
int bpp = dsi_get_pixel_size(dsi->pix_fmt);
int ndl = dsi->num_lanes_used - 1;
- int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.regm_dsi + 1;
+ int dsi_fclk_hsdiv = dsi->user_dsi_cinfo.mX[HSDIV_DSI] + 1;
int hsa_interleave_hs = 0, hsa_interleave_lp = 0;
int hfp_interleave_hs = 0, hfp_interleave_lp = 0;
int hbp_interleave_hs = 0, hbp_interleave_lp = 0;
@@ -4441,18 +4177,12 @@ static void dsi_display_uninit_dispc(struct platform_device *dsidev,
static int dsi_configure_dsi_clocks(struct platform_device *dsidev)
{
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
- struct dsi_clock_info cinfo;
+ struct dss_pll_clock_info cinfo;
int r;
cinfo = dsi->user_dsi_cinfo;
- r = dsi_calc_clock_rates(dsidev, &cinfo);
- if (r) {
- DSSERR("Failed to calc dsi clocks\n");
- return r;
- }
-
- r = dsi_pll_set_clock_div(dsidev, &cinfo);
+ r = dss_pll_set_config(&dsi->pll, &cinfo);
if (r) {
DSSERR("Failed to set dsi clocks\n");
return r;
@@ -4466,7 +4196,7 @@ static int dsi_display_init_dsi(struct platform_device *dsidev)
struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
int r;
- r = dsi_pll_init(dsidev, true, true);
+ r = dss_pll_enable(&dsi->pll);
if (r)
goto err0;
@@ -4510,7 +4240,7 @@ err3:
err2:
dss_select_dsi_clk_source(dsi->module_id, OMAP_DSS_CLK_SRC_FCK);
err1:
- dsi_pll_uninit(dsidev, true);
+ dss_pll_disable(&dsi->pll);
err0:
return r;
}
@@ -4551,8 +4281,6 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
if (r)
goto err_get_dsi;
- dsi_enable_pll_clock(dsidev, 1);
-
_dsi_initialize_irq(dsidev);
r = dsi_display_init_dsi(dsidev);
@@ -4564,7 +4292,6 @@ static int dsi_display_enable(struct omap_dss_device *dssdev)
return 0;
err_init_dsi:
- dsi_enable_pll_clock(dsidev, 0);
dsi_runtime_put(dsidev);
err_get_dsi:
mutex_unlock(&dsi->lock);
@@ -4592,7 +4319,6 @@ static void dsi_display_disable(struct omap_dss_device *dssdev,
dsi_display_uninit_dsi(dsidev, disconnect_lanes, enter_ulps);
dsi_runtime_put(dsidev);
- dsi_enable_pll_clock(dsidev, 0);
mutex_unlock(&dsi->lock);
}
@@ -4713,29 +4439,30 @@ static bool dsi_cm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
return true;
}
-static bool dsi_cm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+static bool dsi_cm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
void *data)
{
struct dsi_clk_calc_ctx *ctx = data;
- ctx->dsi_cinfo.regm_dispc = regm_dispc;
- ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+ ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+ ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
return dispc_div_calc(dispc, ctx->req_pck_min, ctx->req_pck_max,
dsi_cm_calc_dispc_cb, ctx);
}
-static bool dsi_cm_calc_pll_cb(int regn, int regm, unsigned long fint,
- unsigned long pll, void *data)
+static bool dsi_cm_calc_pll_cb(int n, int m, unsigned long fint,
+ unsigned long clkdco, void *data)
{
struct dsi_clk_calc_ctx *ctx = data;
- ctx->dsi_cinfo.regn = regn;
- ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.n = n;
+ ctx->dsi_cinfo.m = m;
ctx->dsi_cinfo.fint = fint;
- ctx->dsi_cinfo.clkin4ddr = pll;
+ ctx->dsi_cinfo.clkdco = clkdco;
- return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+ return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
+ dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
dsi_cm_calc_hsdiv_cb, ctx);
}
@@ -4748,7 +4475,7 @@ static bool dsi_cm_calc(struct dsi_data *dsi,
unsigned long pll_min, pll_max;
unsigned long pck, txbyteclk;
- clkin = clk_get_rate(dsi->sys_clk);
+ clkin = clk_get_rate(dsi->pll.clkin);
bitspp = dsi_get_pixel_size(cfg->pixel_format);
ndl = dsi->num_lanes_used - 1;
@@ -4764,16 +4491,16 @@ static bool dsi_cm_calc(struct dsi_data *dsi,
memset(ctx, 0, sizeof(*ctx));
ctx->dsidev = dsi->pdev;
+ ctx->pll = &dsi->pll;
ctx->config = cfg;
ctx->req_pck_min = pck;
ctx->req_pck_nom = pck;
ctx->req_pck_max = pck * 3 / 2;
- ctx->dsi_cinfo.clkin = clkin;
pll_min = max(cfg->hs_clk_min * 4, txbyteclk * 4 * 4);
pll_max = cfg->hs_clk_max * 4;
- return dsi_pll_calc(dsi->pdev, clkin,
+ return dss_pll_calc(ctx->pll, clkin,
pll_min, pll_max,
dsi_cm_calc_pll_cb, ctx);
}
@@ -4784,7 +4511,7 @@ static bool dsi_vm_calc_blanking(struct dsi_clk_calc_ctx *ctx)
const struct omap_dss_dsi_config *cfg = ctx->config;
int bitspp = dsi_get_pixel_size(cfg->pixel_format);
int ndl = dsi->num_lanes_used - 1;
- unsigned long hsclk = ctx->dsi_cinfo.clkin4ddr / 4;
+ unsigned long hsclk = ctx->dsi_cinfo.clkdco / 4;
unsigned long byteclk = hsclk / 4;
unsigned long dispc_pck, req_pck_min, req_pck_nom, req_pck_max;
@@ -4999,14 +4726,14 @@ static bool dsi_vm_calc_dispc_cb(int lckd, int pckd, unsigned long lck,
return true;
}
-static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
+static bool dsi_vm_calc_hsdiv_cb(int m_dispc, unsigned long dispc,
void *data)
{
struct dsi_clk_calc_ctx *ctx = data;
unsigned long pck_max;
- ctx->dsi_cinfo.regm_dispc = regm_dispc;
- ctx->dsi_cinfo.dsi_pll_hsdiv_dispc_clk = dispc;
+ ctx->dsi_cinfo.mX[HSDIV_DISPC] = m_dispc;
+ ctx->dsi_cinfo.clkout[HSDIV_DISPC] = dispc;
/*
* In burst mode we can let the dispc pck be arbitrarily high, but it
@@ -5022,17 +4749,18 @@ static bool dsi_vm_calc_hsdiv_cb(int regm_dispc, unsigned long dispc,
dsi_vm_calc_dispc_cb, ctx);
}
-static bool dsi_vm_calc_pll_cb(int regn, int regm, unsigned long fint,
- unsigned long pll, void *data)
+static bool dsi_vm_calc_pll_cb(int n, int m, unsigned long fint,
+ unsigned long clkdco, void *data)
{
struct dsi_clk_calc_ctx *ctx = data;
- ctx->dsi_cinfo.regn = regn;
- ctx->dsi_cinfo.regm = regm;
+ ctx->dsi_cinfo.n = n;
+ ctx->dsi_cinfo.m = m;
ctx->dsi_cinfo.fint = fint;
- ctx->dsi_cinfo.clkin4ddr = pll;
+ ctx->dsi_cinfo.clkdco = clkdco;
- return dsi_hsdiv_calc(ctx->dsidev, pll, ctx->req_pck_min,
+ return dss_pll_hsdiv_calc(ctx->pll, clkdco, ctx->req_pck_min,
+ dss_feat_get_param_max(FEAT_PARAM_DSS_FCK),
dsi_vm_calc_hsdiv_cb, ctx);
}
@@ -5048,14 +4776,13 @@ static bool dsi_vm_calc(struct dsi_data *dsi,
int bitspp = dsi_get_pixel_size(cfg->pixel_format);
unsigned long byteclk_min;
- clkin = clk_get_rate(dsi->sys_clk);
+ clkin = clk_get_rate(dsi->pll.clkin);
memset(ctx, 0, sizeof(*ctx));
ctx->dsidev = dsi->pdev;
+ ctx->pll = &dsi->pll;
ctx->config = cfg;
- ctx->dsi_cinfo.clkin = clkin;
-
/* these limits should come from the panel driver */
ctx->req_pck_min = t->pixelclock - 1000;
ctx->req_pck_nom = t->pixelclock;
@@ -5074,7 +4801,7 @@ static bool dsi_vm_calc(struct dsi_data *dsi,
pll_max = byteclk_max * 4 * 4;
}
- return dsi_pll_calc(dsi->pdev, clkin,
+ return dss_pll_calc(ctx->pll, clkin,
pll_min, pll_max,
dsi_vm_calc_pll_cb, ctx);
}
@@ -5106,8 +4833,8 @@ static int dsi_set_config(struct omap_dss_device *dssdev,
dsi_pll_calc_dsi_fck(&ctx.dsi_cinfo);
- r = dsi_lp_clock_calc(&ctx.dsi_cinfo, config->lp_clk_min,
- config->lp_clk_max);
+ r = dsi_lp_clock_calc(ctx.dsi_cinfo.clkout[HSDIV_DSI],
+ config->lp_clk_min, config->lp_clk_max, &dsi->user_lp_cinfo);
if (r) {
DSSERR("failed to find suitable DSI LP clock settings\n");
goto err;
@@ -5234,35 +4961,6 @@ static void dsi_release_vc(struct omap_dss_device *dssdev, int channel)
}
}
-void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
-{
- if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 7, 1) != 1)
- DSSERR("%s (%s) not active\n",
- dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC),
- dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC));
-}
-
-void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
-{
- if (wait_for_bit_change(dsidev, DSI_PLL_STATUS, 8, 1) != 1)
- DSSERR("%s (%s) not active\n",
- dss_get_generic_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI),
- dss_feat_get_clk_source_name(OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI));
-}
-
-static void dsi_calc_clock_param_ranges(struct platform_device *dsidev)
-{
- struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
-
- dsi->regn_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGN);
- dsi->regm_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM);
- dsi->regm_dispc_max =
- dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DISPC);
- dsi->regm_dsi_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_REGM_DSI);
- dsi->fint_min = dss_feat_get_param_min(FEAT_PARAM_DSIPLL_FINT);
- dsi->fint_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_FINT);
- dsi->lpdiv_max = dss_feat_get_param_max(FEAT_PARAM_DSIPLL_LPDIV);
-}
static int dsi_get_clocks(struct platform_device *dsidev)
{
@@ -5277,14 +4975,6 @@ static int dsi_get_clocks(struct platform_device *dsidev)
dsi->dss_clk = clk;
- clk = devm_clk_get(&dsidev->dev, "sys_clk");
- if (IS_ERR(clk)) {
- DSSERR("can't get sys_clk\n");
- return PTR_ERR(clk);
- }
-
- dsi->sys_clk = clk;
-
return 0;
}
@@ -5453,6 +5143,135 @@ err:
return r;
}
+static const struct dss_pll_ops dsi_pll_ops = {
+ .enable = dsi_pll_enable,
+ .disable = dsi_pll_disable,
+ .set_config = dss_pll_write_config_type_a,
+};
+
+static const struct dss_pll_hw dss_omap3_dsi_pll_hw = {
+ .n_max = (1 << 7) - 1,
+ .m_max = (1 << 11) - 1,
+ .mX_max = (1 << 4) - 1,
+ .fint_min = 750000,
+ .fint_max = 2100000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 7,
+ .n_lsb = 1,
+ .m_msb = 18,
+ .m_lsb = 8,
+
+ .mX_msb[0] = 22,
+ .mX_lsb[0] = 19,
+ .mX_msb[1] = 26,
+ .mX_lsb[1] = 23,
+
+ .has_stopmode = true,
+ .has_freqsel = true,
+ .has_selfreqdco = false,
+ .has_refsel = false,
+};
+
+static const struct dss_pll_hw dss_omap4_dsi_pll_hw = {
+ .n_max = (1 << 8) - 1,
+ .m_max = (1 << 12) - 1,
+ .mX_max = (1 << 5) - 1,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 25,
+ .mX_lsb[0] = 21,
+ .mX_msb[1] = 30,
+ .mX_lsb[1] = 26,
+
+ .has_stopmode = true,
+ .has_freqsel = false,
+ .has_selfreqdco = false,
+ .has_refsel = false,
+};
+
+static const struct dss_pll_hw dss_omap5_dsi_pll_hw = {
+ .n_max = (1 << 8) - 1,
+ .m_max = (1 << 12) - 1,
+ .mX_max = (1 << 5) - 1,
+ .fint_min = 150000,
+ .fint_max = 52000000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 1800000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 25,
+ .mX_lsb[0] = 21,
+ .mX_msb[1] = 30,
+ .mX_lsb[1] = 26,
+
+ .has_stopmode = true,
+ .has_freqsel = false,
+ .has_selfreqdco = true,
+ .has_refsel = true,
+};
+
+static int dsi_init_pll_data(struct platform_device *dsidev)
+{
+ struct dsi_data *dsi = dsi_get_dsidrv_data(dsidev);
+ struct dss_pll *pll = &dsi->pll;
+ struct clk *clk;
+ int r;
+
+ clk = devm_clk_get(&dsidev->dev, "sys_clk");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get sys_clk\n");
+ return PTR_ERR(clk);
+ }
+
+ pll->name = dsi->module_id == 0 ? "dsi0" : "dsi1";
+ pll->clkin = clk;
+ pll->base = dsi->pll_base;
+
+ switch (omapdss_get_version()) {
+ case OMAPDSS_VER_OMAP34xx_ES1:
+ case OMAPDSS_VER_OMAP34xx_ES3:
+ case OMAPDSS_VER_OMAP3630:
+ case OMAPDSS_VER_AM35xx:
+ pll->hw = &dss_omap3_dsi_pll_hw;
+ break;
+
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ pll->hw = &dss_omap4_dsi_pll_hw;
+ break;
+
+ case OMAPDSS_VER_OMAP5:
+ pll->hw = &dss_omap5_dsi_pll_hw;
+ break;
+
+ default:
+ return -ENODEV;
+ }
+
+ pll->ops = &dsi_pll_ops;
+
+ r = dss_pll_register(pll);
+ if (r)
+ return r;
+
+ return 0;
+}
+
/* DSI1 HW IP initialisation */
static int omap_dsihw_probe(struct platform_device *dsidev)
{
@@ -5598,12 +5417,12 @@ static int omap_dsihw_probe(struct platform_device *dsidev)
dsi->vc[i].vc_id = 0;
}
- dsi_calc_clock_param_ranges(dsidev);
-
r = dsi_get_clocks(dsidev);
if (r)
return r;
+ dsi_init_pll_data(dsidev);
+
pm_runtime_enable(&dsidev->dev);
r = dsi_runtime_get(dsidev);
@@ -5672,6 +5491,8 @@ static int __exit omap_dsihw_remove(struct platform_device *dsidev)
WARN_ON(dsi->scp_clk_refcount > 0);
+ dss_pll_unregister(&dsi->pll);
+
dsi_uninit_output(dsidev);
pm_runtime_disable(&dsidev->dev);
diff --git a/drivers/video/fbdev/omap2/dss/dss-of.c b/drivers/video/fbdev/omap2/dss/dss-of.c
index a4b20aa..928ee63 100644
--- a/drivers/video/fbdev/omap2/dss/dss-of.c
+++ b/drivers/video/fbdev/omap2/dss/dss-of.c
@@ -20,6 +20,8 @@
#include <video/omapdss.h>
+#include "dss.h"
+
struct device_node *
omapdss_of_get_next_port(const struct device_node *parent,
struct device_node *prev)
@@ -84,20 +86,17 @@ omapdss_of_get_next_endpoint(const struct device_node *parent,
}
EXPORT_SYMBOL_GPL(omapdss_of_get_next_endpoint);
-static struct device_node *
-omapdss_of_get_remote_device_node(const struct device_node *node)
+struct device_node *dss_of_port_get_parent_device(struct device_node *port)
{
struct device_node *np;
int i;
- np = of_parse_phandle(node, "remote-endpoint", 0);
-
- if (!np)
+ if (!port)
return NULL;
- np = of_get_next_parent(np);
+ np = of_get_next_parent(port);
- for (i = 0; i < 3 && np; ++i) {
+ for (i = 0; i < 2 && np; ++i) {
struct property *prop;
prop = of_find_property(np, "compatible", NULL);
@@ -111,6 +110,31 @@ omapdss_of_get_remote_device_node(const struct device_node *node)
return NULL;
}
+u32 dss_of_port_get_port_number(struct device_node *port)
+{
+ int r;
+ u32 reg;
+
+ r = of_property_read_u32(port, "reg", &reg);
+ if (r)
+ reg = 0;
+
+ return reg;
+}
+
+static struct device_node *omapdss_of_get_remote_port(const struct device_node *node)
+{
+ struct device_node *np;
+
+ np = of_parse_phandle(node, "remote-endpoint", 0);
+ if (!np)
+ return NULL;
+
+ np = of_get_next_parent(np);
+
+ return np;
+}
+
struct device_node *
omapdss_of_get_first_endpoint(const struct device_node *parent)
{
@@ -133,27 +157,25 @@ struct omap_dss_device *
omapdss_of_find_source_for_first_ep(struct device_node *node)
{
struct device_node *ep;
- struct device_node *src_node;
+ struct device_node *src_port;
struct omap_dss_device *src;
ep = omapdss_of_get_first_endpoint(node);
if (!ep)
return ERR_PTR(-EINVAL);
- src_node = omapdss_of_get_remote_device_node(ep);
-
- of_node_put(ep);
-
- if (!src_node)
+ src_port = omapdss_of_get_remote_port(ep);
+ if (!src_port) {
+ of_node_put(ep);
return ERR_PTR(-EINVAL);
+ }
- src = omap_dss_find_output_by_node(src_node);
+ of_node_put(ep);
- of_node_put(src_node);
+ src = omap_dss_find_output_by_port_node(src_port);
- if (!src)
- return ERR_PTR(-EPROBE_DEFER);
+ of_node_put(src_port);
- return src;
+ return src ? src : ERR_PTR(-EPROBE_DEFER);
}
EXPORT_SYMBOL_GPL(omapdss_of_find_source_for_first_ep);
diff --git a/drivers/video/fbdev/omap2/dss/dss.c b/drivers/video/fbdev/omap2/dss/dss.c
index 14bcd6c..702c495 100644
--- a/drivers/video/fbdev/omap2/dss/dss.c
+++ b/drivers/video/fbdev/omap2/dss/dss.c
@@ -70,7 +70,9 @@ struct dss_features {
u8 fck_div_max;
u8 dss_fck_multiplier;
const char *parent_clk_name;
- int (*dpi_select_source)(enum omap_channel channel);
+ enum omap_display_type *ports;
+ int num_ports;
+ int (*dpi_select_source)(int port, enum omap_channel channel);
};
static struct {
@@ -294,7 +296,6 @@ static void dss_dump_regs(struct seq_file *s)
static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
{
- struct platform_device *dsidev;
int b;
u8 start, end;
@@ -304,13 +305,9 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
break;
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
b = 1;
- dsidev = dsi_get_dsidev_from_id(0);
- dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
b = 2;
- dsidev = dsi_get_dsidev_from_id(1);
- dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
default:
BUG();
@@ -327,7 +324,6 @@ static void dss_select_dispc_clk_source(enum omap_dss_clk_source clk_src)
void dss_select_dsi_clk_source(int dsi_module,
enum omap_dss_clk_source clk_src)
{
- struct platform_device *dsidev;
int b, pos;
switch (clk_src) {
@@ -337,14 +333,10 @@ void dss_select_dsi_clk_source(int dsi_module,
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DSI:
BUG_ON(dsi_module != 0);
b = 1;
- dsidev = dsi_get_dsidev_from_id(0);
- dsi_wait_pll_hsdiv_dsi_active(dsidev);
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DSI:
BUG_ON(dsi_module != 1);
b = 1;
- dsidev = dsi_get_dsidev_from_id(1);
- dsi_wait_pll_hsdiv_dsi_active(dsidev);
break;
default:
BUG();
@@ -360,7 +352,6 @@ void dss_select_dsi_clk_source(int dsi_module,
void dss_select_lcd_clk_source(enum omap_channel channel,
enum omap_dss_clk_source clk_src)
{
- struct platform_device *dsidev;
int b, ix, pos;
if (!dss_has_feature(FEAT_LCD_CLK_SRC)) {
@@ -375,15 +366,11 @@ void dss_select_lcd_clk_source(enum omap_channel channel,
case OMAP_DSS_CLK_SRC_DSI_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD);
b = 1;
- dsidev = dsi_get_dsidev_from_id(0);
- dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
case OMAP_DSS_CLK_SRC_DSI2_PLL_HSDIV_DISPC:
BUG_ON(channel != OMAP_DSS_CHANNEL_LCD2 &&
channel != OMAP_DSS_CHANNEL_LCD3);
b = 1;
- dsidev = dsi_get_dsidev_from_id(1);
- dsi_wait_pll_hsdiv_dispc_active(dsidev);
break;
default:
BUG();
@@ -564,7 +551,7 @@ enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void)
return REG_GET(DSS_CONTROL, 15, 15);
}
-static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
+static int dss_dpi_select_source_omap2_omap3(int port, enum omap_channel channel)
{
if (channel != OMAP_DSS_CHANNEL_LCD)
return -EINVAL;
@@ -572,7 +559,7 @@ static int dss_dpi_select_source_omap2_omap3(enum omap_channel channel)
return 0;
}
-static int dss_dpi_select_source_omap4(enum omap_channel channel)
+static int dss_dpi_select_source_omap4(int port, enum omap_channel channel)
{
int val;
@@ -592,7 +579,7 @@ static int dss_dpi_select_source_omap4(enum omap_channel channel)
return 0;
}
-static int dss_dpi_select_source_omap5(enum omap_channel channel)
+static int dss_dpi_select_source_omap5(int port, enum omap_channel channel)
{
int val;
@@ -618,9 +605,9 @@ static int dss_dpi_select_source_omap5(enum omap_channel channel)
return 0;
}
-int dss_dpi_select_source(enum omap_channel channel)
+int dss_dpi_select_source(int port, enum omap_channel channel)
{
- return dss.feat->dpi_select_source(channel);
+ return dss.feat->dpi_select_source(port, channel);
}
static int dss_get_clocks(void)
@@ -689,6 +676,16 @@ void dss_debug_dump_clocks(struct seq_file *s)
}
#endif
+
+static enum omap_display_type omap2plus_ports[] = {
+ OMAP_DISPLAY_TYPE_DPI,
+};
+
+static enum omap_display_type omap34xx_ports[] = {
+ OMAP_DISPLAY_TYPE_DPI,
+ OMAP_DISPLAY_TYPE_SDI,
+};
+
static const struct dss_features omap24xx_dss_feats __initconst = {
/*
* fck div max is really 16, but the divider range has gaps. The range
@@ -698,6 +695,8 @@ static const struct dss_features omap24xx_dss_feats __initconst = {
.dss_fck_multiplier = 2,
.parent_clk_name = "core_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features omap34xx_dss_feats __initconst = {
@@ -705,6 +704,8 @@ static const struct dss_features omap34xx_dss_feats __initconst = {
.dss_fck_multiplier = 2,
.parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap34xx_ports,
+ .num_ports = ARRAY_SIZE(omap34xx_ports),
};
static const struct dss_features omap3630_dss_feats __initconst = {
@@ -712,6 +713,8 @@ static const struct dss_features omap3630_dss_feats __initconst = {
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll4_ck",
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features omap44xx_dss_feats __initconst = {
@@ -719,6 +722,8 @@ static const struct dss_features omap44xx_dss_feats __initconst = {
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap4,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features omap54xx_dss_feats __initconst = {
@@ -726,6 +731,8 @@ static const struct dss_features omap54xx_dss_feats __initconst = {
.dss_fck_multiplier = 1,
.parent_clk_name = "dpll_per_x2_ck",
.dpi_select_source = &dss_dpi_select_source_omap5,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
};
static const struct dss_features am43xx_dss_feats __initconst = {
@@ -733,6 +740,8 @@ static const struct dss_features am43xx_dss_feats __initconst = {
.dss_fck_multiplier = 0,
.parent_clk_name = NULL,
.dpi_select_source = &dss_dpi_select_source_omap2_omap3,
+ .ports = omap2plus_ports,
+ .num_ports = ARRAY_SIZE(omap2plus_ports),
};
static int __init dss_init_features(struct platform_device *pdev)
@@ -798,37 +807,77 @@ static int __init dss_init_ports(struct platform_device *pdev)
if (!port)
return 0;
+ if (dss.feat->num_ports == 0)
+ return 0;
+
do {
+ enum omap_display_type port_type;
u32 reg;
r = of_property_read_u32(port, "reg", &reg);
if (r)
reg = 0;
-#ifdef CONFIG_OMAP2_DSS_DPI
- if (reg == 0)
- dpi_init_port(pdev, port);
-#endif
+ if (reg >= dss.feat->num_ports)
+ continue;
-#ifdef CONFIG_OMAP2_DSS_SDI
- if (reg == 1)
- sdi_init_port(pdev, port);
-#endif
+ port_type = dss.feat->ports[reg];
+ switch (port_type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ dpi_init_port(pdev, port);
+ break;
+ case OMAP_DISPLAY_TYPE_SDI:
+ sdi_init_port(pdev, port);
+ break;
+ default:
+ break;
+ }
} while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
return 0;
}
-static void __exit dss_uninit_ports(void)
+static void __exit dss_uninit_ports(struct platform_device *pdev)
{
-#ifdef CONFIG_OMAP2_DSS_DPI
- dpi_uninit_port();
-#endif
+ struct device_node *parent = pdev->dev.of_node;
+ struct device_node *port;
-#ifdef CONFIG_OMAP2_DSS_SDI
- sdi_uninit_port();
-#endif
+ if (parent == NULL)
+ return;
+
+ port = omapdss_of_get_next_port(parent, NULL);
+ if (!port)
+ return;
+
+ if (dss.feat->num_ports == 0)
+ return;
+
+ do {
+ enum omap_display_type port_type;
+ u32 reg;
+ int r;
+
+ r = of_property_read_u32(port, "reg", &reg);
+ if (r)
+ reg = 0;
+
+ if (reg >= dss.feat->num_ports)
+ continue;
+
+ port_type = dss.feat->ports[reg];
+
+ switch (port_type) {
+ case OMAP_DISPLAY_TYPE_DPI:
+ dpi_uninit_port(port);
+ break;
+ case OMAP_DISPLAY_TYPE_SDI:
+ sdi_uninit_port(port);
+ break;
+ default:
+ break;
+ }
+ } while ((port = omapdss_of_get_next_port(parent, port)) != NULL);
}
/* DSS HW IP initialisation */
@@ -910,7 +959,7 @@ err_setup_clocks:
static int __exit omap_dsshw_remove(struct platform_device *pdev)
{
- dss_uninit_ports();
+ dss_uninit_ports(pdev);
pm_runtime_disable(&pdev->dev);
diff --git a/drivers/video/fbdev/omap2/dss/dss.h b/drivers/video/fbdev/omap2/dss/dss.h
index 8ff22c1..14fb0c2 100644
--- a/drivers/video/fbdev/omap2/dss/dss.h
+++ b/drivers/video/fbdev/omap2/dss/dss.h
@@ -100,35 +100,77 @@ enum dss_writeback_channel {
DSS_WB_LCD3_MGR = 7,
};
-struct dispc_clock_info {
+struct dss_pll;
+
+#define DSS_PLL_MAX_HSDIVS 4
+
+/*
+ * Type-A PLLs: clkout[]/mX[] refer to hsdiv outputs m4, m5, m6, m7.
+ * Type-B PLLs: clkout[0] refers to m2.
+ */
+struct dss_pll_clock_info {
/* rates that we get with dividers below */
- unsigned long lck;
- unsigned long pck;
+ unsigned long fint;
+ unsigned long clkdco;
+ unsigned long clkout[DSS_PLL_MAX_HSDIVS];
/* dividers */
- u16 lck_div;
- u16 pck_div;
+ u16 n;
+ u16 m;
+ u32 mf;
+ u16 mX[DSS_PLL_MAX_HSDIVS];
+ u16 sd;
+};
+
+struct dss_pll_ops {
+ int (*enable)(struct dss_pll *pll);
+ void (*disable)(struct dss_pll *pll);
+ int (*set_config)(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+};
+
+struct dss_pll_hw {
+ unsigned n_max;
+ unsigned m_min;
+ unsigned m_max;
+ unsigned mX_max;
+
+ unsigned long fint_min, fint_max;
+ unsigned long clkdco_min, clkdco_low, clkdco_max;
+
+ u8 n_msb, n_lsb;
+ u8 m_msb, m_lsb;
+ u8 mX_msb[DSS_PLL_MAX_HSDIVS], mX_lsb[DSS_PLL_MAX_HSDIVS];
+
+ bool has_stopmode;
+ bool has_freqsel;
+ bool has_selfreqdco;
+ bool has_refsel;
};
-struct dsi_clock_info {
+struct dss_pll {
+ const char *name;
+
+ struct clk *clkin;
+ struct regulator *regulator;
+
+ void __iomem *base;
+
+ const struct dss_pll_hw *hw;
+
+ const struct dss_pll_ops *ops;
+
+ struct dss_pll_clock_info cinfo;
+};
+
+struct dispc_clock_info {
/* rates that we get with dividers below */
- unsigned long fint;
- unsigned long clkin4ddr;
- unsigned long clkin;
- unsigned long dsi_pll_hsdiv_dispc_clk; /* OMAP3: DSI1_PLL_CLK
- * OMAP4: PLLx_CLK1 */
- unsigned long dsi_pll_hsdiv_dsi_clk; /* OMAP3: DSI2_PLL_CLK
- * OMAP4: PLLx_CLK2 */
- unsigned long lp_clk;
+ unsigned long lck;
+ unsigned long pck;
/* dividers */
- u16 regn;
- u16 regm;
- u16 regm_dispc; /* OMAP3: REGM3
- * OMAP4: REGM4 */
- u16 regm_dsi; /* OMAP3: REGM4
- * OMAP4: REGM5 */
- u16 lp_clk_div;
+ u16 lck_div;
+ u16 pck_div;
};
struct dss_lcd_mgr_config {
@@ -209,12 +251,16 @@ int dss_init_platform_driver(void) __init;
void dss_uninit_platform_driver(void);
unsigned long dss_get_dispc_clk_rate(void);
-int dss_dpi_select_source(enum omap_channel channel);
+int dss_dpi_select_source(int port, enum omap_channel channel);
void dss_select_hdmi_venc_clk_source(enum dss_hdmi_venc_clk_source_select);
enum dss_hdmi_venc_clk_source_select dss_get_hdmi_venc_clk_source(void);
const char *dss_get_generic_clk_source_name(enum omap_dss_clk_source clk_src);
void dss_dump_clocks(struct seq_file *s);
+/* dss-of */
+struct device_node *dss_of_port_get_parent_device(struct device_node *port);
+u32 dss_of_port_get_port_number(struct device_node *port);
+
#if defined(CONFIG_OMAP2_DSS_DEBUGFS)
void dss_debug_dump_clocks(struct seq_file *s);
#endif
@@ -244,16 +290,22 @@ bool dss_div_calc(unsigned long pck, unsigned long fck_min,
int sdi_init_platform_driver(void) __init;
void sdi_uninit_platform_driver(void) __exit;
+#ifdef CONFIG_OMAP2_DSS_SDI
int sdi_init_port(struct platform_device *pdev, struct device_node *port) __init;
-void sdi_uninit_port(void) __exit;
+void sdi_uninit_port(struct device_node *port) __exit;
+#else
+static inline int __init sdi_init_port(struct platform_device *pdev,
+ struct device_node *port)
+{
+ return 0;
+}
+static inline void __exit sdi_uninit_port(struct device_node *port)
+{
+}
+#endif
/* DSI */
-typedef bool (*dsi_pll_calc_func)(int regn, int regm, unsigned long fint,
- unsigned long pll, void *data);
-typedef bool (*dsi_hsdiv_calc_func)(int regm_dispc, unsigned long dispc,
- void *data);
-
#ifdef CONFIG_OMAP2_DSS_DSI
struct dentry;
@@ -262,104 +314,36 @@ struct file_operations;
int dsi_init_platform_driver(void) __init;
void dsi_uninit_platform_driver(void) __exit;
-int dsi_runtime_get(struct platform_device *dsidev);
-void dsi_runtime_put(struct platform_device *dsidev);
-
void dsi_dump_clocks(struct seq_file *s);
void dsi_irq_handler(void);
u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt);
-unsigned long dsi_get_pll_clkin(struct platform_device *dsidev);
-
-bool dsi_hsdiv_calc(struct platform_device *dsidev, unsigned long pll,
- unsigned long out_min, dsi_hsdiv_calc_func func, void *data);
-bool dsi_pll_calc(struct platform_device *dsidev, unsigned long clkin,
- unsigned long pll_min, unsigned long pll_max,
- dsi_pll_calc_func func, void *data);
-
-unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev);
-int dsi_pll_set_clock_div(struct platform_device *dsidev,
- struct dsi_clock_info *cinfo);
-int dsi_pll_init(struct platform_device *dsidev, bool enable_hsclk,
- bool enable_hsdiv);
-void dsi_pll_uninit(struct platform_device *dsidev, bool disconnect_lanes);
-void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev);
-void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev);
-struct platform_device *dsi_get_dsidev_from_id(int module);
#else
-static inline int dsi_runtime_get(struct platform_device *dsidev)
-{
- return 0;
-}
-static inline void dsi_runtime_put(struct platform_device *dsidev)
-{
-}
static inline u8 dsi_get_pixel_size(enum omap_dss_dsi_pixel_format fmt)
{
WARN("%s: DSI not compiled in, returning pixel_size as 0\n", __func__);
return 0;
}
-static inline unsigned long dsi_get_pll_hsdiv_dispc_rate(struct platform_device *dsidev)
-{
- WARN("%s: DSI not compiled in, returning rate as 0\n", __func__);
- return 0;
-}
-static inline int dsi_pll_set_clock_div(struct platform_device *dsidev,
- struct dsi_clock_info *cinfo)
-{
- WARN("%s: DSI not compiled in\n", __func__);
- return -ENODEV;
-}
-static inline int dsi_pll_init(struct platform_device *dsidev,
- bool enable_hsclk, bool enable_hsdiv)
-{
- WARN("%s: DSI not compiled in\n", __func__);
- return -ENODEV;
-}
-static inline void dsi_pll_uninit(struct platform_device *dsidev,
- bool disconnect_lanes)
-{
-}
-static inline void dsi_wait_pll_hsdiv_dispc_active(struct platform_device *dsidev)
-{
-}
-static inline void dsi_wait_pll_hsdiv_dsi_active(struct platform_device *dsidev)
-{
-}
-static inline struct platform_device *dsi_get_dsidev_from_id(int module)
-{
- return NULL;
-}
-
-static inline unsigned long dsi_get_pll_clkin(struct platform_device *dsidev)
-{
- return 0;
-}
-
-static inline bool dsi_hsdiv_calc(struct platform_device *dsidev,
- unsigned long pll, unsigned long out_min,
- dsi_hsdiv_calc_func func, void *data)
-{
- return false;
-}
-
-static inline bool dsi_pll_calc(struct platform_device *dsidev,
- unsigned long clkin,
- unsigned long pll_min, unsigned long pll_max,
- dsi_pll_calc_func func, void *data)
-{
- return false;
-}
-
#endif
/* DPI */
int dpi_init_platform_driver(void) __init;
void dpi_uninit_platform_driver(void) __exit;
+#ifdef CONFIG_OMAP2_DSS_DPI
int dpi_init_port(struct platform_device *pdev, struct device_node *port) __init;
-void dpi_uninit_port(void) __exit;
+void dpi_uninit_port(struct device_node *port) __exit;
+#else
+static inline int __init dpi_init_port(struct platform_device *pdev,
+ struct device_node *port)
+{
+ return 0;
+}
+static inline void __exit dpi_uninit_port(struct device_node *port)
+{
+}
+#endif
/* DISPC */
int dispc_init_platform_driver(void) __init;
@@ -438,4 +422,29 @@ static inline void dss_collect_irq_stats(u32 irqstatus, unsigned *irq_arr)
}
#endif
+/* PLL */
+typedef bool (*dss_pll_calc_func)(int n, int m, unsigned long fint,
+ unsigned long clkdco, void *data);
+typedef bool (*dss_hsdiv_calc_func)(int m_dispc, unsigned long dispc,
+ void *data);
+
+int dss_pll_register(struct dss_pll *pll);
+void dss_pll_unregister(struct dss_pll *pll);
+struct dss_pll *dss_pll_find(const char *name);
+int dss_pll_enable(struct dss_pll *pll);
+void dss_pll_disable(struct dss_pll *pll);
+int dss_pll_set_config(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+
+bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
+ unsigned long out_min, unsigned long out_max,
+ dss_hsdiv_calc_func func, void *data);
+bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dss_pll_calc_func func, void *data);
+int dss_pll_write_config_type_a(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+int dss_pll_write_config_type_b(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo);
+
#endif
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.c b/drivers/video/fbdev/omap2/dss/dss_features.c
index 15088df..0e3da80 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.c
+++ b/drivers/video/fbdev/omap2/dss/dss_features.c
@@ -72,10 +72,6 @@ static const struct dss_reg_field omap2_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
[FEAT_REG_VERTICALACCU] = { 25, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGN] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGM] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 0, 0 },
};
static const struct dss_reg_field omap3_dss_reg_fields[] = {
@@ -87,10 +83,6 @@ static const struct dss_reg_field omap3_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 9, 0 },
[FEAT_REG_VERTICALACCU] = { 25, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 0, 0 },
- [FEAT_REG_DSIPLL_REGN] = { 7, 1 },
- [FEAT_REG_DSIPLL_REGM] = { 18, 8 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 22, 19 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 26, 23 },
};
static const struct dss_reg_field am43xx_dss_reg_fields[] = {
@@ -113,10 +105,6 @@ static const struct dss_reg_field omap4_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 8 },
- [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
- [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
static const struct dss_reg_field omap5_dss_reg_fields[] = {
@@ -128,10 +116,6 @@ static const struct dss_reg_field omap5_dss_reg_fields[] = {
[FEAT_REG_HORIZONTALACCU] = { 10, 0 },
[FEAT_REG_VERTICALACCU] = { 26, 16 },
[FEAT_REG_DISPC_CLK_SWITCH] = { 9, 7 },
- [FEAT_REG_DSIPLL_REGN] = { 8, 1 },
- [FEAT_REG_DSIPLL_REGM] = { 20, 9 },
- [FEAT_REG_DSIPLL_REGM_DISPC] = { 25, 21 },
- [FEAT_REG_DSIPLL_REGM_DSI] = { 30, 26 },
};
static const enum omap_display_type omap2_dss_supported_displays[] = {
@@ -437,12 +421,6 @@ static const char * const omap5_dss_clk_source_names[] = {
static const struct dss_param_range omap2_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 133000000 },
[FEAT_PARAM_DSS_PCD] = { 2, 255 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_FINT] = { 0, 0 },
- [FEAT_PARAM_DSIPLL_LPDIV] = { 0, 0 },
[FEAT_PARAM_DOWNSCALE] = { 1, 2 },
/*
* Assuming the line width buffer to be 768 pixels as OMAP2 DISPC
@@ -454,11 +432,6 @@ static const struct dss_param_range omap2_dss_param_range[] = {
static const struct dss_param_range omap3_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 173000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 7) - 1 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 11) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 4) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 4) - 1 },
- [FEAT_PARAM_DSIPLL_FINT] = { 750000, 2100000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 1, (1 << 13) - 1},
[FEAT_PARAM_DSI_FCK] = { 0, 173000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
@@ -475,11 +448,6 @@ static const struct dss_param_range am43xx_dss_param_range[] = {
static const struct dss_param_range omap4_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 186000000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_FINT] = { 500000, 2500000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 170000000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
@@ -489,11 +457,6 @@ static const struct dss_param_range omap4_dss_param_range[] = {
static const struct dss_param_range omap5_dss_param_range[] = {
[FEAT_PARAM_DSS_FCK] = { 0, 209250000 },
[FEAT_PARAM_DSS_PCD] = { 1, 255 },
- [FEAT_PARAM_DSIPLL_REGN] = { 0, (1 << 8) - 1 },
- [FEAT_PARAM_DSIPLL_REGM] = { 0, (1 << 12) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DISPC] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_REGM_DSI] = { 0, (1 << 5) - 1 },
- [FEAT_PARAM_DSIPLL_FINT] = { 150000, 52000000 },
[FEAT_PARAM_DSIPLL_LPDIV] = { 0, (1 << 13) - 1 },
[FEAT_PARAM_DSI_FCK] = { 0, 209250000 },
[FEAT_PARAM_DOWNSCALE] = { 1, 4 },
@@ -517,7 +480,6 @@ static const enum dss_feat_id omap3430_dss_feat_list[] = {
FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
- FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR,
@@ -537,7 +499,6 @@ static const enum dss_feat_id am35xx_dss_feat_list[] = {
FEAT_LINEBUFFERSPLIT,
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
- FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_REVERSE_TXCLKESC,
FEAT_VENC_REQUIRES_TV_DAC_CLK,
FEAT_CPR,
@@ -572,7 +533,6 @@ static const enum dss_feat_id omap3630_dss_feat_list[] = {
FEAT_ROWREPEATENABLE,
FEAT_RESIZECONF,
FEAT_DSI_PLL_PWR_BUG,
- FEAT_DSI_PLL_FREQSEL,
FEAT_CPR,
FEAT_PRELOAD,
FEAT_FIR_COEF_V,
@@ -654,8 +614,6 @@ static const enum dss_feat_id omap5_dss_feat_list[] = {
FEAT_ALPHA_FREE_ZORDER,
FEAT_FIFO_MERGE,
FEAT_BURST_2D,
- FEAT_DSI_PLL_SELFREQDCO,
- FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC,
FEAT_MFLAG,
};
diff --git a/drivers/video/fbdev/omap2/dss/dss_features.h b/drivers/video/fbdev/omap2/dss/dss_features.h
index e3ef3b7..100f7a2 100644
--- a/drivers/video/fbdev/omap2/dss/dss_features.h
+++ b/drivers/video/fbdev/omap2/dss/dss_features.h
@@ -41,7 +41,6 @@ enum dss_feat_id {
FEAT_LCD_CLK_SRC,
/* DSI-PLL power command 0x3 is not working */
FEAT_DSI_PLL_PWR_BUG,
- FEAT_DSI_PLL_FREQSEL,
FEAT_DSI_DCS_CMD_CONFIG_VC,
FEAT_DSI_VC_OCP_WIDTH,
FEAT_DSI_REVERSE_TXCLKESC,
@@ -61,8 +60,6 @@ enum dss_feat_id {
/* An unknown HW bug causing the normal FIFO thresholds not to work */
FEAT_OMAP3_DSI_FIFO_BUG,
FEAT_BURST_2D,
- FEAT_DSI_PLL_SELFREQDCO,
- FEAT_DSI_PLL_REFSEL,
FEAT_DSI_PHY_DCC,
FEAT_MFLAG,
};
@@ -77,20 +74,11 @@ enum dss_feat_reg_field {
FEAT_REG_HORIZONTALACCU,
FEAT_REG_VERTICALACCU,
FEAT_REG_DISPC_CLK_SWITCH,
- FEAT_REG_DSIPLL_REGN,
- FEAT_REG_DSIPLL_REGM,
- FEAT_REG_DSIPLL_REGM_DISPC,
- FEAT_REG_DSIPLL_REGM_DSI,
};
enum dss_range_param {
FEAT_PARAM_DSS_FCK,
FEAT_PARAM_DSS_PCD,
- FEAT_PARAM_DSIPLL_REGN,
- FEAT_PARAM_DSIPLL_REGM,
- FEAT_PARAM_DSIPLL_REGM_DISPC,
- FEAT_PARAM_DSIPLL_REGM_DSI,
- FEAT_PARAM_DSIPLL_FINT,
FEAT_PARAM_DSIPLL_LPDIV,
FEAT_PARAM_DSI_FCK,
FEAT_PARAM_DOWNSCALE,
diff --git a/drivers/video/fbdev/omap2/dss/hdmi.h b/drivers/video/fbdev/omap2/dss/hdmi.h
index 262771b..e4a32fe 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi.h
@@ -101,13 +101,6 @@ enum hdmi_core_hdmi_dvi {
HDMI_HDMI = 1
};
-enum hdmi_clk_refsel {
- HDMI_REFSEL_PCLK = 0,
- HDMI_REFSEL_REF1 = 1,
- HDMI_REFSEL_REF2 = 2,
- HDMI_REFSEL_SYSCLK = 3
-};
-
enum hdmi_packing_mode {
HDMI_PACK_10b_RGB_YUV444 = 0,
HDMI_PACK_24b_RGB_YUV444_YUV422 = 1,
@@ -160,7 +153,8 @@ enum hdmi_audio_blk_strt_end_sig {
enum hdmi_core_audio_layout {
HDMI_AUDIO_LAYOUT_2CH = 0,
- HDMI_AUDIO_LAYOUT_8CH = 1
+ HDMI_AUDIO_LAYOUT_8CH = 1,
+ HDMI_AUDIO_LAYOUT_6CH = 2
};
enum hdmi_core_cts_mode {
@@ -191,17 +185,6 @@ struct hdmi_config {
enum hdmi_core_hdmi_dvi hdmi_dvi_mode;
};
-/* HDMI PLL structure */
-struct hdmi_pll_info {
- u16 regn;
- u16 regm;
- u32 regmf;
- u16 regm2;
- u16 regsd;
- u16 dcofreq;
- enum hdmi_clk_refsel refsel;
-};
-
struct hdmi_audio_format {
enum hdmi_stereo_channels stereo_channels;
u8 active_chnnls_msk;
@@ -249,12 +232,15 @@ struct hdmi_core_audio_config {
struct hdmi_wp_data {
void __iomem *base;
+ phys_addr_t phys_base;
};
struct hdmi_pll_data {
+ struct dss_pll pll;
+
void __iomem *base;
- struct hdmi_pll_info info;
+ struct hdmi_wp_data *wp;
};
struct hdmi_phy_data {
@@ -316,16 +302,19 @@ void hdmi_wp_video_config_timing(struct hdmi_wp_data *wp,
void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
struct omap_video_timings *timings, struct hdmi_config *param);
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp);
+phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp);
/* HDMI PLL funcs */
-int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
-void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp);
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s);
-void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy);
-int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll);
+void hdmi_pll_compute(struct hdmi_pll_data *pll,
+ unsigned long target_tmds, struct dss_pll_clock_info *pi);
+int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
+ struct hdmi_wp_data *wp);
+void hdmi_pll_uninit(struct hdmi_pll_data *hpll);
/* HDMI PHY funcs */
-int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg);
+int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
+ unsigned long lfbitclk);
void hdmi_phy_dump(struct hdmi_phy_data *phy, struct seq_file *s);
int hdmi_phy_init(struct platform_device *pdev, struct hdmi_phy_data *phy);
int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
@@ -334,7 +323,7 @@ int hdmi_phy_parse_lanes(struct hdmi_phy_data *phy, const u32 *lanes);
int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
struct hdmi_phy_data *phy);
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
+/* Audio funcs */
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts);
int hdmi_wp_audio_enable(struct hdmi_wp_data *wp, bool enable);
int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable);
@@ -342,9 +331,33 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt);
void hdmi_wp_audio_config_dma(struct hdmi_wp_data *wp,
struct hdmi_audio_dma *aud_dma);
-static inline bool hdmi_mode_has_audio(int mode)
+static inline bool hdmi_mode_has_audio(struct hdmi_config *cfg)
{
- return mode == HDMI_HDMI ? true : false;
+ return cfg->hdmi_dvi_mode == HDMI_HDMI ? true : false;
}
-#endif
+
+/* HDMI DRV data */
+struct omap_hdmi {
+ struct mutex lock;
+ struct platform_device *pdev;
+
+ struct hdmi_wp_data wp;
+ struct hdmi_pll_data pll;
+ struct hdmi_phy_data phy;
+ struct hdmi_core_data core;
+
+ struct hdmi_config cfg;
+
+ struct regulator *vdda_reg;
+
+ bool core_enabled;
+ bool display_enabled;
+
+ struct omap_dss_device output;
+
+ struct platform_device *audio_pdev;
+ void (*audio_abort_cb)(struct device *dev);
+ int wp_idlemode;
+};
+
#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4.c b/drivers/video/fbdev/omap2/dss/hdmi4.c
index 9a8713c..f1a02bf 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4.c
@@ -33,29 +33,14 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
+#include <sound/omap-hdmi-audio.h>
#include "hdmi4_core.h"
#include "dss.h"
#include "dss_features.h"
+#include "hdmi.h"
-static struct {
- struct mutex lock;
- struct platform_device *pdev;
-
- struct hdmi_wp_data wp;
- struct hdmi_pll_data pll;
- struct hdmi_phy_data phy;
- struct hdmi_core_data core;
-
- struct hdmi_config cfg;
-
- struct clk *sys_clk;
- struct regulator *vdda_hdmi_dac_reg;
-
- bool core_enabled;
-
- struct omap_dss_device output;
-} hdmi;
+static struct omap_hdmi hdmi;
static int hdmi_runtime_get(void)
{
@@ -117,7 +102,7 @@ static int hdmi_init_regulator(void)
int r;
struct regulator *reg;
- if (hdmi.vdda_hdmi_dac_reg != NULL)
+ if (hdmi.vdda_reg != NULL)
return 0;
reg = devm_regulator_get(&hdmi.pdev->dev, "vdda");
@@ -137,7 +122,7 @@ static int hdmi_init_regulator(void)
}
}
- hdmi.vdda_hdmi_dac_reg = reg;
+ hdmi.vdda_reg = reg;
return 0;
}
@@ -146,7 +131,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
{
int r;
- r = regulator_enable(hdmi.vdda_hdmi_dac_reg);
+ r = regulator_enable(hdmi.vdda_reg);
if (r)
return r;
@@ -162,7 +147,7 @@ static int hdmi_power_on_core(struct omap_dss_device *dssdev)
return 0;
err_runtime_get:
- regulator_disable(hdmi.vdda_hdmi_dac_reg);
+ regulator_disable(hdmi.vdda_reg);
return r;
}
@@ -172,7 +157,7 @@ static void hdmi_power_off_core(struct omap_dss_device *dssdev)
hdmi.core_enabled = false;
hdmi_runtime_put();
- regulator_disable(hdmi.vdda_hdmi_dac_reg);
+ regulator_disable(hdmi.vdda_reg);
}
static int hdmi_power_on_full(struct omap_dss_device *dssdev)
@@ -180,8 +165,8 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
int r;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager;
- unsigned long phy;
struct hdmi_wp_data *wp = &hdmi.wp;
+ struct dss_pll_clock_info hdmi_cinfo = { 0 };
r = hdmi_power_on_core(dssdev);
if (r)
@@ -195,19 +180,22 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
- /* the functions below use kHz pixel clock. TODO: change to Hz */
- phy = p->pixelclock / 1000;
-
- hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
+ hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
- /* config the PLL and PHY hdmi_set_pll_pwrfirst */
- r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
+ r = dss_pll_enable(&hdmi.pll.pll);
if (r) {
- DSSDBG("Failed to lock PLL\n");
+ DSSERR("Failed to enable PLL\n");
goto err_pll_enable;
}
- r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
+ r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
+ if (r) {
+ DSSERR("Failed to configure PLL\n");
+ goto err_pll_cfg;
+ }
+
+ r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
+ hdmi_cinfo.clkout[0]);
if (r) {
DSSDBG("Failed to configure PHY\n");
goto err_phy_cfg;
@@ -244,7 +232,8 @@ err_vid_enable:
err_phy_cfg:
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
- hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+err_pll_cfg:
+ dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
hdmi_power_off_core(dssdev);
return -EIO;
@@ -262,7 +251,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
- hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+ dss_pll_disable(&hdmi.pll.pll);
hdmi_power_off_core(dssdev);
}
@@ -352,6 +341,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
+ hdmi.display_enabled = true;
+
mutex_unlock(&hdmi.lock);
return 0;
@@ -366,8 +357,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
+ if (hdmi.audio_pdev && hdmi.audio_abort_cb)
+ hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
+
hdmi_power_off_full(dssdev);
+ hdmi.display_enabled = false;
+
mutex_unlock(&hdmi.lock);
}
@@ -404,21 +400,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
-static int hdmi_get_clocks(struct platform_device *pdev)
-{
- struct clk *clk;
-
- clk = devm_clk_get(&pdev->dev, "sys_clk");
- if (IS_ERR(clk)) {
- DSSERR("can't get sys_clk\n");
- return PTR_ERR(clk);
- }
-
- hdmi.sys_clk = clk;
-
- return 0;
-}
-
static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
@@ -484,112 +465,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
return r;
}
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
- int r;
-
- mutex_lock(&hdmi.lock);
-
- if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
- r = -EPERM;
- goto err;
- }
-
- r = hdmi_wp_audio_enable(&hdmi.wp, true);
- if (r)
- goto err;
-
- mutex_unlock(&hdmi.lock);
- return 0;
-
-err:
- mutex_unlock(&hdmi.lock);
- return r;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
- hdmi_wp_audio_enable(&hdmi.wp, false);
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
- return hdmi4_audio_start(&hdmi.core, &hdmi.wp);
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
- hdmi4_audio_stop(&hdmi.core, &hdmi.wp);
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
- bool r;
-
- mutex_lock(&hdmi.lock);
-
- r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
-
- mutex_unlock(&hdmi.lock);
- return r;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio)
-{
- int r;
- u32 pclk = hdmi.cfg.timings.pixelclock;
-
- mutex_lock(&hdmi.lock);
-
- if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
- r = -EPERM;
- goto err;
- }
-
- r = hdmi4_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
- if (r)
- goto err;
-
- mutex_unlock(&hdmi.lock);
- return 0;
-
-err:
- mutex_unlock(&hdmi.lock);
- return r;
-}
-#else
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
- return -EPERM;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
- return -EPERM;
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
- return false;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio)
-{
- return -EPERM;
-}
-#endif
-
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
@@ -618,13 +493,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
.read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
-
- .audio_enable = hdmi_audio_enable,
- .audio_disable = hdmi_audio_disable,
- .audio_start = hdmi_audio_start,
- .audio_stop = hdmi_audio_stop,
- .audio_supported = hdmi_audio_supported,
- .audio_config = hdmi_audio_config,
};
static void hdmi_init_output(struct platform_device *pdev)
@@ -642,7 +510,7 @@ static void hdmi_init_output(struct platform_device *pdev)
omapdss_register_output(out);
}
-static void __exit hdmi_uninit_output(struct platform_device *pdev)
+static void hdmi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &hdmi.output;
@@ -671,6 +539,112 @@ err:
return r;
}
+/* Audio callbacks */
+static int hdmi_audio_startup(struct device *dev,
+ void (*abort_cb)(struct device *dev))
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ hd->audio_abort_cb = abort_cb;
+
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static int hdmi_audio_shutdown(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ mutex_lock(&hd->lock);
+ hd->audio_abort_cb = NULL;
+ mutex_unlock(&hd->lock);
+
+ return 0;
+}
+
+static int hdmi_audio_start(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+ WARN_ON(!hd->display_enabled);
+
+ hdmi_wp_audio_enable(&hd->wp, true);
+ hdmi4_audio_start(&hd->core, &hd->wp);
+
+ return 0;
+}
+
+static void hdmi_audio_stop(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+ WARN_ON(!hd->display_enabled);
+
+ hdmi4_audio_stop(&hd->core, &hd->wp);
+ hdmi_wp_audio_enable(&hd->wp, false);
+}
+
+static int hdmi_audio_config(struct device *dev,
+ struct omap_dss_audio *dss_audio)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ ret = hdmi4_audio_config(&hd->core, &hd->wp, dss_audio,
+ hd->cfg.timings.pixelclock);
+
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
+ .audio_startup = hdmi_audio_startup,
+ .audio_shutdown = hdmi_audio_shutdown,
+ .audio_start = hdmi_audio_start,
+ .audio_stop = hdmi_audio_stop,
+ .audio_config = hdmi_audio_config,
+};
+
+static int hdmi_audio_register(struct device *dev)
+{
+ struct omap_hdmi_audio_pdata pdata = {
+ .dev = dev,
+ .dss_version = omapdss_get_version(),
+ .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
+ .ops = &hdmi_audio_ops,
+ };
+
+ hdmi.audio_pdev = platform_device_register_data(
+ dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
+ &pdata, sizeof(pdata));
+
+ if (IS_ERR(hdmi.audio_pdev))
+ return PTR_ERR(hdmi.audio_pdev);
+
+ return 0;
+}
+
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
@@ -678,6 +652,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
int irq;
hdmi.pdev = pdev;
+ dev_set_drvdata(&pdev->dev, &hdmi);
mutex_init(&hdmi.lock);
@@ -691,28 +666,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
if (r)
return r;
- r = hdmi_pll_init(pdev, &hdmi.pll);
+ r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
if (r)
return r;
r = hdmi_phy_init(pdev, &hdmi.phy);
if (r)
- return r;
+ goto err;
r = hdmi4_core_init(pdev, &hdmi.core);
if (r)
- return r;
-
- r = hdmi_get_clocks(pdev);
- if (r) {
- DSSERR("can't get clocks\n");
- return r;
- }
+ goto err;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
- return -ENODEV;
+ r = -ENODEV;
+ goto err;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
@@ -720,22 +690,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
if (r) {
DSSERR("HDMI IRQ request failed\n");
- return r;
+ goto err;
}
pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev);
+ r = hdmi_audio_register(&pdev->dev);
+ if (r) {
+ DSSERR("Registering HDMI audio failed\n");
+ hdmi_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
+
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
return 0;
+err:
+ hdmi_pll_uninit(&hdmi.pll);
+ return r;
}
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
+ if (hdmi.audio_pdev)
+ platform_device_unregister(hdmi.audio_pdev);
+
hdmi_uninit_output(pdev);
+ hdmi_pll_uninit(&hdmi.pll);
+
pm_runtime_disable(&pdev->dev);
return 0;
@@ -743,8 +729,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
static int hdmi_runtime_suspend(struct device *dev)
{
- clk_disable_unprepare(hdmi.sys_clk);
-
dispc_runtime_put();
return 0;
@@ -758,8 +742,6 @@ static int hdmi_runtime_resume(struct device *dev)
if (r < 0)
return r;
- clk_prepare_enable(hdmi.sys_clk);
-
return 0;
}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.c b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
index 4ad39cf..7eafea5 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.c
@@ -31,10 +31,8 @@
#include <linux/platform_device.h>
#include <linux/string.h>
#include <linux/seq_file.h>
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
#include <sound/asound.h>
#include <sound/asoundef.h>
-#endif
#include "hdmi4_core.h"
#include "dss_features.h"
@@ -530,7 +528,6 @@ void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s)
DUMPCOREAV(HDMI_CORE_AV_CEC_ADDR_ID);
}
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
static void hdmi_core_audio_config(struct hdmi_core_data *core,
struct hdmi_core_audio_config *cfg)
{
@@ -877,17 +874,6 @@ void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp)
hdmi_wp_audio_core_req_enable(wp, false);
}
-int hdmi4_audio_get_dma_port(u32 *offset, u32 *size)
-{
- if (!offset || !size)
- return -EINVAL;
- *offset = HDMI_WP_AUDIO_DATA;
- *size = 4;
- return 0;
-}
-
-#endif
-
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{
struct resource *res;
diff --git a/drivers/video/fbdev/omap2/dss/hdmi4_core.h b/drivers/video/fbdev/omap2/dss/hdmi4_core.h
index 827909e..a069f96 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi4_core.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi4_core.h
@@ -266,12 +266,8 @@ void hdmi4_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
void hdmi4_core_dump(struct hdmi_core_data *core, struct seq_file *s);
int hdmi4_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi4_audio_start(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
void hdmi4_audio_stop(struct hdmi_core_data *core, struct hdmi_wp_data *wp);
int hdmi4_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct omap_dss_audio *audio, u32 pclk);
-int hdmi4_audio_get_dma_port(u32 *offset, u32 *size);
-#endif
-
#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5.c b/drivers/video/fbdev/omap2/dss/hdmi5.c
index 169b764..d9d0d78 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5.c
@@ -38,29 +38,13 @@
#include <linux/gpio.h>
#include <linux/regulator/consumer.h>
#include <video/omapdss.h>
+#include <sound/omap-hdmi-audio.h>
#include "hdmi5_core.h"
#include "dss.h"
#include "dss_features.h"
-static struct {
- struct mutex lock;
- struct platform_device *pdev;
-
- struct hdmi_wp_data wp;
- struct hdmi_pll_data pll;
- struct hdmi_phy_data phy;
- struct hdmi_core_data core;
-
- struct hdmi_config cfg;
-
- struct clk *sys_clk;
- struct regulator *vdda_reg;
-
- bool core_enabled;
-
- struct omap_dss_device output;
-} hdmi;
+static struct omap_hdmi hdmi;
static int hdmi_runtime_get(void)
{
@@ -198,7 +182,7 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
int r;
struct omap_video_timings *p;
struct omap_overlay_manager *mgr = hdmi.output.manager;
- unsigned long phy;
+ struct dss_pll_clock_info hdmi_cinfo = { 0 };
r = hdmi_power_on_core(dssdev);
if (r)
@@ -208,24 +192,27 @@ static int hdmi_power_on_full(struct omap_dss_device *dssdev)
DSSDBG("hdmi_power_on x_res= %d y_res = %d\n", p->x_res, p->y_res);
- /* the functions below use kHz pixel clock. TODO: change to Hz */
- phy = p->pixelclock / 1000;
-
- hdmi_pll_compute(&hdmi.pll, clk_get_rate(hdmi.sys_clk), phy);
+ hdmi_pll_compute(&hdmi.pll, p->pixelclock, &hdmi_cinfo);
/* disable and clear irqs */
hdmi_wp_clear_irqenable(&hdmi.wp, 0xffffffff);
hdmi_wp_set_irqstatus(&hdmi.wp,
hdmi_wp_get_irqstatus(&hdmi.wp));
- /* config the PLL and PHY hdmi_set_pll_pwrfirst */
- r = hdmi_pll_enable(&hdmi.pll, &hdmi.wp);
+ r = dss_pll_enable(&hdmi.pll.pll);
if (r) {
- DSSDBG("Failed to lock PLL\n");
+ DSSERR("Failed to enable PLL\n");
goto err_pll_enable;
}
- r = hdmi_phy_configure(&hdmi.phy, &hdmi.cfg);
+ r = dss_pll_set_config(&hdmi.pll.pll, &hdmi_cinfo);
+ if (r) {
+ DSSERR("Failed to configure PLL\n");
+ goto err_pll_cfg;
+ }
+
+ r = hdmi_phy_configure(&hdmi.phy, hdmi_cinfo.clkdco,
+ hdmi_cinfo.clkout[0]);
if (r) {
DSSDBG("Failed to start PHY\n");
goto err_phy_cfg;
@@ -262,7 +249,8 @@ err_vid_enable:
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
err_phy_pwr:
err_phy_cfg:
- hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+err_pll_cfg:
+ dss_pll_disable(&hdmi.pll.pll);
err_pll_enable:
hdmi_power_off_core(dssdev);
return -EIO;
@@ -280,7 +268,7 @@ static void hdmi_power_off_full(struct omap_dss_device *dssdev)
hdmi_wp_set_phy_pwr(&hdmi.wp, HDMI_PHYPWRCMD_OFF);
- hdmi_pll_disable(&hdmi.pll, &hdmi.wp);
+ dss_pll_disable(&hdmi.pll.pll);
hdmi_power_off_core(dssdev);
}
@@ -290,6 +278,10 @@ static int hdmi_display_check_timing(struct omap_dss_device *dssdev,
{
struct omap_dss_device *out = &hdmi.output;
+ /* TODO: proper interlace support */
+ if (timings->interlace)
+ return -EINVAL;
+
if (!dispc_mgr_timings_ok(out->dispc_channel, timings))
return -EINVAL;
@@ -377,6 +369,8 @@ static int hdmi_display_enable(struct omap_dss_device *dssdev)
goto err0;
}
+ hdmi.display_enabled = true;
+
mutex_unlock(&hdmi.lock);
return 0;
@@ -391,8 +385,13 @@ static void hdmi_display_disable(struct omap_dss_device *dssdev)
mutex_lock(&hdmi.lock);
+ if (hdmi.audio_pdev && hdmi.audio_abort_cb)
+ hdmi.audio_abort_cb(&hdmi.audio_pdev->dev);
+
hdmi_power_off_full(dssdev);
+ hdmi.display_enabled = false;
+
mutex_unlock(&hdmi.lock);
}
@@ -429,21 +428,6 @@ static void hdmi_core_disable(struct omap_dss_device *dssdev)
mutex_unlock(&hdmi.lock);
}
-static int hdmi_get_clocks(struct platform_device *pdev)
-{
- struct clk *clk;
-
- clk = devm_clk_get(&pdev->dev, "sys_clk");
- if (IS_ERR(clk)) {
- DSSERR("can't get sys_clk\n");
- return PTR_ERR(clk);
- }
-
- hdmi.sys_clk = clk;
-
- return 0;
-}
-
static int hdmi_connect(struct omap_dss_device *dssdev,
struct omap_dss_device *dst)
{
@@ -509,112 +493,6 @@ static int hdmi_read_edid(struct omap_dss_device *dssdev,
return r;
}
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
- int r;
-
- mutex_lock(&hdmi.lock);
-
- if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
- r = -EPERM;
- goto err;
- }
-
- r = hdmi_wp_audio_enable(&hdmi.wp, true);
- if (r)
- goto err;
-
- mutex_unlock(&hdmi.lock);
- return 0;
-
-err:
- mutex_unlock(&hdmi.lock);
- return r;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
- hdmi_wp_audio_enable(&hdmi.wp, false);
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
- return hdmi_wp_audio_core_req_enable(&hdmi.wp, true);
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
- hdmi_wp_audio_core_req_enable(&hdmi.wp, false);
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
- bool r;
-
- mutex_lock(&hdmi.lock);
-
- r = hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode);
-
- mutex_unlock(&hdmi.lock);
- return r;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio)
-{
- int r;
- u32 pclk = hdmi.cfg.timings.pixelclock;
-
- mutex_lock(&hdmi.lock);
-
- if (!hdmi_mode_has_audio(hdmi.cfg.hdmi_dvi_mode)) {
- r = -EPERM;
- goto err;
- }
-
- r = hdmi5_audio_config(&hdmi.core, &hdmi.wp, audio, pclk);
- if (r)
- goto err;
-
- mutex_unlock(&hdmi.lock);
- return 0;
-
-err:
- mutex_unlock(&hdmi.lock);
- return r;
-}
-#else
-static int hdmi_audio_enable(struct omap_dss_device *dssdev)
-{
- return -EPERM;
-}
-
-static void hdmi_audio_disable(struct omap_dss_device *dssdev)
-{
-}
-
-static int hdmi_audio_start(struct omap_dss_device *dssdev)
-{
- return -EPERM;
-}
-
-static void hdmi_audio_stop(struct omap_dss_device *dssdev)
-{
-}
-
-static bool hdmi_audio_supported(struct omap_dss_device *dssdev)
-{
- return false;
-}
-
-static int hdmi_audio_config(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio)
-{
- return -EPERM;
-}
-#endif
-
static int hdmi_set_infoframe(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi)
{
@@ -643,13 +521,6 @@ static const struct omapdss_hdmi_ops hdmi_ops = {
.read_edid = hdmi_read_edid,
.set_infoframe = hdmi_set_infoframe,
.set_hdmi_mode = hdmi_set_hdmi_mode,
-
- .audio_enable = hdmi_audio_enable,
- .audio_disable = hdmi_audio_disable,
- .audio_start = hdmi_audio_start,
- .audio_stop = hdmi_audio_stop,
- .audio_supported = hdmi_audio_supported,
- .audio_config = hdmi_audio_config,
};
static void hdmi_init_output(struct platform_device *pdev)
@@ -667,7 +538,7 @@ static void hdmi_init_output(struct platform_device *pdev)
omapdss_register_output(out);
}
-static void __exit hdmi_uninit_output(struct platform_device *pdev)
+static void hdmi_uninit_output(struct platform_device *pdev)
{
struct omap_dss_device *out = &hdmi.output;
@@ -696,6 +567,119 @@ err:
return r;
}
+/* Audio callbacks */
+static int hdmi_audio_startup(struct device *dev,
+ void (*abort_cb)(struct device *dev))
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret = 0;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ hd->audio_abort_cb = abort_cb;
+
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static int hdmi_audio_shutdown(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ mutex_lock(&hd->lock);
+ hd->audio_abort_cb = NULL;
+ mutex_unlock(&hd->lock);
+
+ return 0;
+}
+
+static int hdmi_audio_start(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+ WARN_ON(!hd->display_enabled);
+
+ /* No-idle while playing audio, store the old value */
+ hd->wp_idlemode = REG_GET(hdmi.wp.base, HDMI_WP_SYSCONFIG, 3, 2);
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, 1, 3, 2);
+
+ hdmi_wp_audio_enable(&hd->wp, true);
+ hdmi_wp_audio_core_req_enable(&hd->wp, true);
+
+ return 0;
+}
+
+static void hdmi_audio_stop(struct device *dev)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+
+ WARN_ON(!hdmi_mode_has_audio(&hd->cfg));
+ WARN_ON(!hd->display_enabled);
+
+ hdmi_wp_audio_core_req_enable(&hd->wp, false);
+ hdmi_wp_audio_enable(&hd->wp, false);
+
+ /* Playback stopped, restore original idlemode */
+ REG_FLD_MOD(hdmi.wp.base, HDMI_WP_SYSCONFIG, hd->wp_idlemode, 3, 2);
+}
+
+static int hdmi_audio_config(struct device *dev,
+ struct omap_dss_audio *dss_audio)
+{
+ struct omap_hdmi *hd = dev_get_drvdata(dev);
+ int ret;
+
+ mutex_lock(&hd->lock);
+
+ if (!hdmi_mode_has_audio(&hd->cfg) || !hd->display_enabled) {
+ ret = -EPERM;
+ goto out;
+ }
+
+ ret = hdmi5_audio_config(&hd->core, &hd->wp, dss_audio,
+ hd->cfg.timings.pixelclock);
+
+out:
+ mutex_unlock(&hd->lock);
+
+ return ret;
+}
+
+static const struct omap_hdmi_audio_ops hdmi_audio_ops = {
+ .audio_startup = hdmi_audio_startup,
+ .audio_shutdown = hdmi_audio_shutdown,
+ .audio_start = hdmi_audio_start,
+ .audio_stop = hdmi_audio_stop,
+ .audio_config = hdmi_audio_config,
+};
+
+static int hdmi_audio_register(struct device *dev)
+{
+ struct omap_hdmi_audio_pdata pdata = {
+ .dev = dev,
+ .dss_version = omapdss_get_version(),
+ .audio_dma_addr = hdmi_wp_get_audio_dma_addr(&hdmi.wp),
+ .ops = &hdmi_audio_ops,
+ };
+
+ hdmi.audio_pdev = platform_device_register_data(
+ dev, "omap-hdmi-audio", PLATFORM_DEVID_AUTO,
+ &pdata, sizeof(pdata));
+
+ if (IS_ERR(hdmi.audio_pdev))
+ return PTR_ERR(hdmi.audio_pdev);
+
+ return 0;
+}
+
/* HDMI HW IP initialisation */
static int omapdss_hdmihw_probe(struct platform_device *pdev)
{
@@ -703,6 +687,7 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
int irq;
hdmi.pdev = pdev;
+ dev_set_drvdata(&pdev->dev, &hdmi);
mutex_init(&hdmi.lock);
@@ -716,28 +701,23 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
if (r)
return r;
- r = hdmi_pll_init(pdev, &hdmi.pll);
+ r = hdmi_pll_init(pdev, &hdmi.pll, &hdmi.wp);
if (r)
return r;
r = hdmi_phy_init(pdev, &hdmi.phy);
if (r)
- return r;
+ goto err;
r = hdmi5_core_init(pdev, &hdmi.core);
if (r)
- return r;
-
- r = hdmi_get_clocks(pdev);
- if (r) {
- DSSERR("can't get clocks\n");
- return r;
- }
+ goto err;
irq = platform_get_irq(pdev, 0);
if (irq < 0) {
DSSERR("platform_get_irq failed\n");
- return -ENODEV;
+ r = -ENODEV;
+ goto err;
}
r = devm_request_threaded_irq(&pdev->dev, irq,
@@ -745,22 +725,38 @@ static int omapdss_hdmihw_probe(struct platform_device *pdev)
IRQF_ONESHOT, "OMAP HDMI", &hdmi.wp);
if (r) {
DSSERR("HDMI IRQ request failed\n");
- return r;
+ goto err;
}
pm_runtime_enable(&pdev->dev);
hdmi_init_output(pdev);
+ r = hdmi_audio_register(&pdev->dev);
+ if (r) {
+ DSSERR("Registering HDMI audio failed %d\n", r);
+ hdmi_uninit_output(pdev);
+ pm_runtime_disable(&pdev->dev);
+ return r;
+ }
+
dss_debugfs_create_file("hdmi", hdmi_dump_regs);
return 0;
+err:
+ hdmi_pll_uninit(&hdmi.pll);
+ return r;
}
static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
{
+ if (hdmi.audio_pdev)
+ platform_device_unregister(hdmi.audio_pdev);
+
hdmi_uninit_output(pdev);
+ hdmi_pll_uninit(&hdmi.pll);
+
pm_runtime_disable(&pdev->dev);
return 0;
@@ -768,8 +764,6 @@ static int __exit omapdss_hdmihw_remove(struct platform_device *pdev)
static int hdmi_runtime_suspend(struct device *dev)
{
- clk_disable_unprepare(hdmi.sys_clk);
-
dispc_runtime_put();
return 0;
@@ -783,8 +777,6 @@ static int hdmi_runtime_resume(struct device *dev)
if (r < 0)
return r;
- clk_prepare_enable(hdmi.sys_clk);
-
return 0;
}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.c b/drivers/video/fbdev/omap2/dss/hdmi5_core.c
index 83acbf7..a3cfe3d 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5_core.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.c
@@ -30,10 +30,8 @@
#include <linux/string.h>
#include <linux/seq_file.h>
#include <drm/drm_edid.h>
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
#include <sound/asound.h>
#include <sound/asoundef.h>
-#endif
#include "hdmi5_core.h"
@@ -644,9 +642,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
hdmi_core_enable_interrupts(core);
}
-
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
-
static void hdmi5_core_audio_config(struct hdmi_core_data *core,
struct hdmi_core_audio_config *cfg)
{
@@ -721,7 +716,7 @@ static void hdmi5_core_audio_config(struct hdmi_core_data *core,
/* Source number */
val = cfg->iec60958_cfg->status[2] & IEC958_AES2_CON_SOURCE;
- REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 4);
+ REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(2), val, 3, 0);
/* Channel number right 0 */
REG_FLD_MOD(base, HDMI_CORE_FC_AUDSCHNLS(3), 2, 3, 0);
@@ -879,6 +874,9 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
/* only LPCM atm */
audio_format.type = HDMI_AUDIO_TYPE_LPCM;
+ /* only allowed option */
+ audio_format.sample_order = HDMI_AUDIO_SAMPLE_LEFT_FIRST;
+
/* disable start/stop signals of IEC 60958 blocks */
audio_format.en_sig_blk_strt_end = HDMI_AUDIO_BLOCK_SIG_STARTEND_ON;
@@ -894,7 +892,6 @@ int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
return 0;
}
-#endif
int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core)
{
diff --git a/drivers/video/fbdev/omap2/dss/hdmi5_core.h b/drivers/video/fbdev/omap2/dss/hdmi5_core.h
index ce7e9f3..f2f1022 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi5_core.h
+++ b/drivers/video/fbdev/omap2/dss/hdmi5_core.h
@@ -299,8 +299,6 @@ void hdmi5_configure(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct hdmi_config *cfg);
int hdmi5_core_init(struct platform_device *pdev, struct hdmi_core_data *core);
-#if defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
int hdmi5_audio_config(struct hdmi_core_data *core, struct hdmi_wp_data *wp,
struct omap_dss_audio *audio, u32 pclk);
#endif
-#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_common.c b/drivers/video/fbdev/omap2/dss/hdmi_common.c
index 7d5f103..1b8fcc6 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_common.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_common.c
@@ -48,7 +48,6 @@ int hdmi_parse_lanes_of(struct platform_device *pdev, struct device_node *ep,
return 0;
}
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO)
int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
{
u32 deep_color;
@@ -147,4 +146,3 @@ int hdmi_compute_acr(u32 pclk, u32 sample_freq, u32 *n, u32 *cts)
return 0;
}
-#endif
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_phy.c b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
index e007ac8..bc9e07d 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_phy.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_phy.c
@@ -20,9 +20,7 @@
struct hdmi_phy_features {
bool bist_ctrl;
- bool calc_freqout;
bool ldo_voltage;
- unsigned long dcofreq_min;
unsigned long max_phy;
};
@@ -132,7 +130,8 @@ static void hdmi_phy_configure_lanes(struct hdmi_phy_data *phy)
REG_FLD_MOD(phy->base, HDMI_TXPHY_PAD_CFG_CTRL, pol_val, 30, 27);
}
-int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
+int hdmi_phy_configure(struct hdmi_phy_data *phy, unsigned long hfbitclk,
+ unsigned long lfbitclk)
{
u8 freqout;
@@ -149,20 +148,16 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
if (phy_feat->bist_ctrl)
REG_FLD_MOD(phy->base, HDMI_TXPHY_BIST_CONTROL, 1, 11, 11);
- if (phy_feat->calc_freqout) {
- /* DCOCLK/10 is pixel clock, compare pclk with DCOCLK_MIN/10 */
- u32 dco_min = phy_feat->dcofreq_min / 10;
- u32 pclk = cfg->timings.pixelclock;
-
- if (pclk < dco_min)
- freqout = 0;
- else if ((pclk >= dco_min) && (pclk < phy_feat->max_phy))
- freqout = 1;
- else
- freqout = 2;
- } else {
+ /*
+ * If the hfbitclk != lfbitclk, it means the lfbitclk was configured
+ * to be used for TMDS.
+ */
+ if (hfbitclk != lfbitclk)
+ freqout = 0;
+ else if (hfbitclk / 10 < phy_feat->max_phy)
freqout = 1;
- }
+ else
+ freqout = 2;
/*
* Write to phy address 0 to configure the clock
@@ -184,17 +179,13 @@ int hdmi_phy_configure(struct hdmi_phy_data *phy, struct hdmi_config *cfg)
static const struct hdmi_phy_features omap44xx_phy_feats = {
.bist_ctrl = false,
- .calc_freqout = false,
.ldo_voltage = true,
- .dcofreq_min = 500000000,
.max_phy = 185675000,
};
static const struct hdmi_phy_features omap54xx_phy_feats = {
.bist_ctrl = true,
- .calc_freqout = true,
.ldo_voltage = false,
- .dcofreq_min = 750000000,
.max_phy = 186000000,
};
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_pll.c b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
index 6d92bb3..87accdb 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_pll.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_pll.c
@@ -15,26 +15,13 @@
#include <linux/err.h>
#include <linux/io.h>
#include <linux/platform_device.h>
+#include <linux/clk.h>
+
#include <video/omapdss.h>
#include "dss.h"
#include "hdmi.h"
-#define HDMI_DEFAULT_REGN 16
-#define HDMI_DEFAULT_REGM2 1
-
-struct hdmi_pll_features {
- bool sys_reset;
- /* this is a hack, need to replace it with a better computation of M2 */
- bool bound_dcofreq;
- unsigned long fint_min, fint_max;
- u16 regm_max;
- unsigned long dcofreq_low_min, dcofreq_low_max;
- unsigned long dcofreq_high_min, dcofreq_high_max;
-};
-
-static const struct hdmi_pll_features *pll_feat;
-
void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
{
#define DUMPPLL(r) seq_printf(s, "%-35s %08x\n", #r,\
@@ -51,228 +38,189 @@ void hdmi_pll_dump(struct hdmi_pll_data *pll, struct seq_file *s)
DUMPPLL(PLLCTRL_CFG4);
}
-void hdmi_pll_compute(struct hdmi_pll_data *pll, unsigned long clkin, int phy)
+void hdmi_pll_compute(struct hdmi_pll_data *pll,
+ unsigned long target_tmds, struct dss_pll_clock_info *pi)
{
- struct hdmi_pll_info *pi = &pll->info;
- unsigned long refclk;
- u32 mf;
+ unsigned long fint, clkdco, clkout;
+ unsigned long target_bitclk, target_clkdco;
+ unsigned long min_dco;
+ unsigned n, m, mf, m2, sd;
+ unsigned long clkin;
+ const struct dss_pll_hw *hw = pll->pll.hw;
- /* use our funky units */
- clkin /= 10000;
+ clkin = clk_get_rate(pll->pll.clkin);
- /*
- * Input clock is predivided by N + 1
- * out put of which is reference clk
- */
+ DSSDBG("clkin %lu, target tmds %lu\n", clkin, target_tmds);
- pi->regn = HDMI_DEFAULT_REGN;
+ target_bitclk = target_tmds * 10;
- refclk = clkin / pi->regn;
+ /* Fint */
+ n = DIV_ROUND_UP(clkin, hw->fint_max);
+ fint = clkin / n;
- /* temorary hack to make sure DCO freq isn't calculated too low */
- if (pll_feat->bound_dcofreq && phy <= 65000)
- pi->regm2 = 3;
- else
- pi->regm2 = HDMI_DEFAULT_REGM2;
-
- /*
- * multiplier is pixel_clk/ref_clk
- * Multiplying by 100 to avoid fractional part removal
- */
- pi->regm = phy * pi->regm2 / refclk;
-
- /*
- * fractional multiplier is remainder of the difference between
- * multiplier and actual phy(required pixel clock thus should be
- * multiplied by 2^18(262144) divided by the reference clock
- */
- mf = (phy - pi->regm / pi->regm2 * refclk) * 262144;
- pi->regmf = pi->regm2 * mf / refclk;
-
- /*
- * Dcofreq should be set to 1 if required pixel clock
- * is greater than 1000MHz
- */
- pi->dcofreq = phy > 1000 * 100;
- pi->regsd = ((pi->regm * clkin / 10) / (pi->regn * 250) + 5) / 10;
-
- /* Set the reference clock to sysclk reference */
- pi->refsel = HDMI_REFSEL_SYSCLK;
-
- DSSDBG("M = %d Mf = %d\n", pi->regm, pi->regmf);
- DSSDBG("range = %d sd = %d\n", pi->dcofreq, pi->regsd);
-}
+ /* adjust m2 so that the clkdco will be high enough */
+ min_dco = roundup(hw->clkdco_min, fint);
+ m2 = DIV_ROUND_UP(min_dco, target_bitclk);
+ if (m2 == 0)
+ m2 = 1;
+ target_clkdco = target_bitclk * m2;
+ m = target_clkdco / fint;
-static int hdmi_pll_config(struct hdmi_pll_data *pll)
-{
- u32 r;
- struct hdmi_pll_info *fmt = &pll->info;
+ clkdco = fint * m;
- /* PLL start always use manual mode */
- REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, 0x0, 0, 0);
-
- r = hdmi_read_reg(pll->base, PLLCTRL_CFG1);
- r = FLD_MOD(r, fmt->regm, 20, 9); /* CFG1_PLL_REGM */
- r = FLD_MOD(r, fmt->regn - 1, 8, 1); /* CFG1_PLL_REGN */
- hdmi_write_reg(pll->base, PLLCTRL_CFG1, r);
-
- r = hdmi_read_reg(pll->base, PLLCTRL_CFG2);
-
- r = FLD_MOD(r, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
- r = FLD_MOD(r, 0x1, 13, 13); /* PLL_REFEN */
- r = FLD_MOD(r, 0x0, 14, 14); /* PHY_CLKINEN de-assert during locking */
- r = FLD_MOD(r, fmt->refsel, 22, 21); /* REFSEL */
-
- if (fmt->dcofreq)
- r = FLD_MOD(r, 0x4, 3, 1); /* 1000MHz and 2000MHz */
+ /* adjust clkdco with fractional mf */
+ if (WARN_ON(target_clkdco - clkdco > fint))
+ mf = 0;
else
- r = FLD_MOD(r, 0x2, 3, 1); /* 500MHz and 1000MHz */
-
- hdmi_write_reg(pll->base, PLLCTRL_CFG2, r);
-
- REG_FLD_MOD(pll->base, PLLCTRL_CFG3, fmt->regsd, 17, 10);
+ mf = (u32)div_u64(262144ull * (target_clkdco - clkdco), fint);
- r = hdmi_read_reg(pll->base, PLLCTRL_CFG4);
- r = FLD_MOD(r, fmt->regm2, 24, 18);
- r = FLD_MOD(r, fmt->regmf, 17, 0);
- hdmi_write_reg(pll->base, PLLCTRL_CFG4, r);
+ if (mf > 0)
+ clkdco += (u32)div_u64((u64)mf * fint, 262144);
- /* go now */
- REG_FLD_MOD(pll->base, PLLCTRL_PLL_GO, 0x1, 0, 0);
+ clkout = clkdco / m2;
- /* wait for bit change */
- if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_GO,
- 0, 0, 0) != 0) {
- DSSERR("PLL GO bit not clearing\n");
- return -ETIMEDOUT;
- }
+ /* sigma-delta */
+ sd = DIV_ROUND_UP(fint * m, 250000000);
- /* Wait till the lock bit is set in PLL status */
- if (hdmi_wait_for_bit_change(pll->base,
- PLLCTRL_PLL_STATUS, 1, 1, 1) != 1) {
- DSSERR("cannot lock PLL\n");
- DSSERR("CFG1 0x%x\n",
- hdmi_read_reg(pll->base, PLLCTRL_CFG1));
- DSSERR("CFG2 0x%x\n",
- hdmi_read_reg(pll->base, PLLCTRL_CFG2));
- DSSERR("CFG4 0x%x\n",
- hdmi_read_reg(pll->base, PLLCTRL_CFG4));
- return -ETIMEDOUT;
- }
+ DSSDBG("N = %u, M = %u, M.f = %u, M2 = %u, SD = %u\n",
+ n, m, mf, m2, sd);
+ DSSDBG("Fint %lu, clkdco %lu, clkout %lu\n", fint, clkdco, clkout);
- DSSDBG("PLL locked!\n");
+ pi->n = n;
+ pi->m = m;
+ pi->mf = mf;
+ pi->mX[0] = m2;
+ pi->sd = sd;
- return 0;
+ pi->fint = fint;
+ pi->clkdco = clkdco;
+ pi->clkout[0] = clkout;
}
-static int hdmi_pll_reset(struct hdmi_pll_data *pll)
-{
- /* SYSRESET controlled by power FSM */
- REG_FLD_MOD(pll->base, PLLCTRL_PLL_CONTROL, pll_feat->sys_reset, 3, 3);
-
- /* READ 0x0 reset is in progress */
- if (hdmi_wait_for_bit_change(pll->base, PLLCTRL_PLL_STATUS, 0, 0, 1)
- != 1) {
- DSSERR("Failed to sysreset PLL\n");
- return -ETIMEDOUT;
- }
-
- return 0;
-}
-
-int hdmi_pll_enable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
+static int hdmi_pll_enable(struct dss_pll *dsspll)
{
+ struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
+ struct hdmi_wp_data *wp = pll->wp;
u16 r = 0;
- r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
- if (r)
- return r;
-
r = hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_BOTHON_ALLCLKS);
if (r)
return r;
- r = hdmi_pll_reset(pll);
- if (r)
- return r;
-
- r = hdmi_pll_config(pll);
- if (r)
- return r;
-
return 0;
}
-void hdmi_pll_disable(struct hdmi_pll_data *pll, struct hdmi_wp_data *wp)
+static void hdmi_pll_disable(struct dss_pll *dsspll)
{
+ struct hdmi_pll_data *pll = container_of(dsspll, struct hdmi_pll_data, pll);
+ struct hdmi_wp_data *wp = pll->wp;
+
hdmi_wp_set_pll_pwr(wp, HDMI_PLLPWRCMD_ALLOFF);
}
-static const struct hdmi_pll_features omap44xx_pll_feats = {
- .sys_reset = false,
- .bound_dcofreq = false,
- .fint_min = 500000,
- .fint_max = 2500000,
- .regm_max = 4095,
- .dcofreq_low_min = 500000000,
- .dcofreq_low_max = 1000000000,
- .dcofreq_high_min = 1000000000,
- .dcofreq_high_max = 2000000000,
+static const struct dss_pll_ops dsi_pll_ops = {
+ .enable = hdmi_pll_enable,
+ .disable = hdmi_pll_disable,
+ .set_config = dss_pll_write_config_type_b,
};
-static const struct hdmi_pll_features omap54xx_pll_feats = {
- .sys_reset = true,
- .bound_dcofreq = true,
- .fint_min = 620000,
- .fint_max = 2500000,
- .regm_max = 2046,
- .dcofreq_low_min = 750000000,
- .dcofreq_low_max = 1500000000,
- .dcofreq_high_min = 1250000000,
- .dcofreq_high_max = 2500000000UL,
+static const struct dss_pll_hw dss_omap4_hdmi_pll_hw = {
+ .n_max = 255,
+ .m_min = 20,
+ .m_max = 4095,
+ .mX_max = 127,
+ .fint_min = 500000,
+ .fint_max = 2500000,
+ .clkdco_max = 1800000000,
+
+ .clkdco_min = 500000000,
+ .clkdco_low = 1000000000,
+ .clkdco_max = 2000000000,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 24,
+ .mX_lsb[0] = 18,
+
+ .has_selfreqdco = true,
};
-static int hdmi_pll_init_features(struct platform_device *pdev)
+static const struct dss_pll_hw dss_omap5_hdmi_pll_hw = {
+ .n_max = 255,
+ .m_min = 20,
+ .m_max = 2045,
+ .mX_max = 127,
+ .fint_min = 620000,
+ .fint_max = 2500000,
+ .clkdco_max = 1800000000,
+
+ .clkdco_min = 750000000,
+ .clkdco_low = 1500000000,
+ .clkdco_max = 2500000000UL,
+
+ .n_msb = 8,
+ .n_lsb = 1,
+ .m_msb = 20,
+ .m_lsb = 9,
+
+ .mX_msb[0] = 24,
+ .mX_lsb[0] = 18,
+
+ .has_selfreqdco = true,
+ .has_refsel = true,
+};
+
+static int dsi_init_pll_data(struct platform_device *pdev, struct hdmi_pll_data *hpll)
{
- struct hdmi_pll_features *dst;
- const struct hdmi_pll_features *src;
+ struct dss_pll *pll = &hpll->pll;
+ struct clk *clk;
+ int r;
- dst = devm_kzalloc(&pdev->dev, sizeof(*dst), GFP_KERNEL);
- if (!dst) {
- dev_err(&pdev->dev, "Failed to allocate HDMI PHY Features\n");
- return -ENOMEM;
+ clk = devm_clk_get(&pdev->dev, "sys_clk");
+ if (IS_ERR(clk)) {
+ DSSERR("can't get sys_clk\n");
+ return PTR_ERR(clk);
}
+ pll->name = "hdmi";
+ pll->base = hpll->base;
+ pll->clkin = clk;
+
switch (omapdss_get_version()) {
case OMAPDSS_VER_OMAP4430_ES1:
case OMAPDSS_VER_OMAP4430_ES2:
case OMAPDSS_VER_OMAP4:
- src = &omap44xx_pll_feats;
+ pll->hw = &dss_omap4_hdmi_pll_hw;
break;
case OMAPDSS_VER_OMAP5:
- src = &omap54xx_pll_feats;
+ pll->hw = &dss_omap5_hdmi_pll_hw;
break;
default:
return -ENODEV;
}
- memcpy(dst, src, sizeof(*dst));
- pll_feat = dst;
+ pll->ops = &dsi_pll_ops;
+
+ r = dss_pll_register(pll);
+ if (r)
+ return r;
return 0;
}
-int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
+int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll,
+ struct hdmi_wp_data *wp)
{
int r;
struct resource *res;
- r = hdmi_pll_init_features(pdev);
- if (r)
- return r;
+ pll->wp = wp;
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "pll");
if (!res) {
@@ -286,5 +234,18 @@ int hdmi_pll_init(struct platform_device *pdev, struct hdmi_pll_data *pll)
return PTR_ERR(pll->base);
}
+ r = dsi_init_pll_data(pdev, pll);
+ if (r) {
+ DSSERR("failed to init HDMI PLL\n");
+ return r;
+ }
+
return 0;
}
+
+void hdmi_pll_uninit(struct hdmi_pll_data *hpll)
+{
+ struct dss_pll *pll = &hpll->pll;
+
+ dss_pll_unregister(pll);
+}
diff --git a/drivers/video/fbdev/omap2/dss/hdmi_wp.c b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
index 496327e..c15377e 100644
--- a/drivers/video/fbdev/omap2/dss/hdmi_wp.c
+++ b/drivers/video/fbdev/omap2/dss/hdmi_wp.c
@@ -185,7 +185,6 @@ void hdmi_wp_init_vid_fmt_timings(struct hdmi_video_format *video_fmt,
timings->interlace = param->timings.interlace;
}
-#if defined(CONFIG_OMAP4_DSS_HDMI_AUDIO) || defined(CONFIG_OMAP5_DSS_HDMI_AUDIO)
void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
struct hdmi_audio_format *aud_fmt)
{
@@ -194,8 +193,12 @@ void hdmi_wp_audio_config_format(struct hdmi_wp_data *wp,
DSSDBG("Enter hdmi_wp_audio_config_format\n");
r = hdmi_read_reg(wp->base, HDMI_WP_AUDIO_CFG);
- r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
- r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+ if (omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES1 ||
+ omapdss_get_version() == OMAPDSS_VER_OMAP4430_ES2 ||
+ omapdss_get_version() == OMAPDSS_VER_OMAP4) {
+ r = FLD_MOD(r, aud_fmt->stereo_channels, 26, 24);
+ r = FLD_MOD(r, aud_fmt->active_chnnls_msk, 23, 16);
+ }
r = FLD_MOD(r, aud_fmt->en_sig_blk_strt_end, 5, 5);
r = FLD_MOD(r, aud_fmt->type, 4, 4);
r = FLD_MOD(r, aud_fmt->justification, 3, 3);
@@ -236,7 +239,6 @@ int hdmi_wp_audio_core_req_enable(struct hdmi_wp_data *wp, bool enable)
return 0;
}
-#endif
int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
{
@@ -247,6 +249,7 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
DSSERR("can't get WP mem resource\n");
return -EINVAL;
}
+ wp->phys_base = res->start;
wp->base = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(wp->base)) {
@@ -256,3 +259,8 @@ int hdmi_wp_init(struct platform_device *pdev, struct hdmi_wp_data *wp)
return 0;
}
+
+phys_addr_t hdmi_wp_get_audio_dma_addr(struct hdmi_wp_data *wp)
+{
+ return wp->phys_base + HDMI_WP_AUDIO_DATA;
+}
diff --git a/drivers/video/fbdev/omap2/dss/output.c b/drivers/video/fbdev/omap2/dss/output.c
index 2ab3afa..1607215 100644
--- a/drivers/video/fbdev/omap2/dss/output.c
+++ b/drivers/video/fbdev/omap2/dss/output.c
@@ -19,6 +19,7 @@
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/slab.h>
+#include <linux/of.h>
#include <video/omapdss.h>
@@ -131,18 +132,30 @@ struct omap_dss_device *omap_dss_find_output(const char *name)
}
EXPORT_SYMBOL(omap_dss_find_output);
-struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node)
+struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port)
{
+ struct device_node *src_node;
struct omap_dss_device *out;
+ u32 reg;
+
+ src_node = dss_of_port_get_parent_device(port);
+ if (!src_node)
+ return NULL;
+
+ reg = dss_of_port_get_port_number(port);
list_for_each_entry(out, &output_list, list) {
- if (out->dev->of_node == node)
+ if (out->dev->of_node == src_node && out->port_num == reg) {
+ of_node_put(src_node);
return omap_dss_get_device(out);
+ }
}
+ of_node_put(src_node);
+
return NULL;
}
-EXPORT_SYMBOL(omap_dss_find_output_by_node);
+EXPORT_SYMBOL(omap_dss_find_output_by_port_node);
struct omap_dss_device *omapdss_find_output_from_display(struct omap_dss_device *dssdev)
{
diff --git a/drivers/video/fbdev/omap2/dss/pll.c b/drivers/video/fbdev/omap2/dss/pll.c
new file mode 100644
index 0000000..50bc62c5
--- /dev/null
+++ b/drivers/video/fbdev/omap2/dss/pll.c
@@ -0,0 +1,378 @@
+/*
+ * Copyright (C) 2014 Texas Instruments Incorporated
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 as published by
+ * the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#define DSS_SUBSYS_NAME "PLL"
+
+#include <linux/clk.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/regulator/consumer.h>
+#include <linux/sched.h>
+
+#include <video/omapdss.h>
+
+#include "dss.h"
+
+#define PLL_CONTROL 0x0000
+#define PLL_STATUS 0x0004
+#define PLL_GO 0x0008
+#define PLL_CONFIGURATION1 0x000C
+#define PLL_CONFIGURATION2 0x0010
+#define PLL_CONFIGURATION3 0x0014
+#define PLL_SSC_CONFIGURATION1 0x0018
+#define PLL_SSC_CONFIGURATION2 0x001C
+#define PLL_CONFIGURATION4 0x0020
+
+static struct dss_pll *dss_plls[4];
+
+int dss_pll_register(struct dss_pll *pll)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+ if (!dss_plls[i]) {
+ dss_plls[i] = pll;
+ return 0;
+ }
+ }
+
+ return -EBUSY;
+}
+
+void dss_pll_unregister(struct dss_pll *pll)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+ if (dss_plls[i] == pll) {
+ dss_plls[i] = NULL;
+ return;
+ }
+ }
+}
+
+struct dss_pll *dss_pll_find(const char *name)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dss_plls); ++i) {
+ if (dss_plls[i] && strcmp(dss_plls[i]->name, name) == 0)
+ return dss_plls[i];
+ }
+
+ return NULL;
+}
+
+int dss_pll_enable(struct dss_pll *pll)
+{
+ int r;
+
+ r = clk_prepare_enable(pll->clkin);
+ if (r)
+ return r;
+
+ if (pll->regulator) {
+ r = regulator_enable(pll->regulator);
+ if (r)
+ goto err_reg;
+ }
+
+ r = pll->ops->enable(pll);
+ if (r)
+ goto err_enable;
+
+ return 0;
+
+err_enable:
+ regulator_disable(pll->regulator);
+err_reg:
+ clk_disable_unprepare(pll->clkin);
+ return r;
+}
+
+void dss_pll_disable(struct dss_pll *pll)
+{
+ pll->ops->disable(pll);
+
+ if (pll->regulator)
+ regulator_disable(pll->regulator);
+
+ clk_disable_unprepare(pll->clkin);
+
+ memset(&pll->cinfo, 0, sizeof(pll->cinfo));
+}
+
+int dss_pll_set_config(struct dss_pll *pll, const struct dss_pll_clock_info *cinfo)
+{
+ int r;
+
+ r = pll->ops->set_config(pll, cinfo);
+ if (r)
+ return r;
+
+ pll->cinfo = *cinfo;
+
+ return 0;
+}
+
+bool dss_pll_hsdiv_calc(const struct dss_pll *pll, unsigned long clkdco,
+ unsigned long out_min, unsigned long out_max,
+ dss_hsdiv_calc_func func, void *data)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ int m, m_start, m_stop;
+ unsigned long out;
+
+ out_min = out_min ? out_min : 1;
+ out_max = out_max ? out_max : ULONG_MAX;
+
+ m_start = max(DIV_ROUND_UP(clkdco, out_max), 1ul);
+
+ m_stop = min((unsigned)(clkdco / out_min), hw->mX_max);
+
+ for (m = m_start; m <= m_stop; ++m) {
+ out = clkdco / m;
+
+ if (func(m, out, data))
+ return true;
+ }
+
+ return false;
+}
+
+bool dss_pll_calc(const struct dss_pll *pll, unsigned long clkin,
+ unsigned long pll_min, unsigned long pll_max,
+ dss_pll_calc_func func, void *data)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ int n, n_start, n_stop;
+ int m, m_start, m_stop;
+ unsigned long fint, clkdco;
+ unsigned long pll_hw_max;
+ unsigned long fint_hw_min, fint_hw_max;
+
+ pll_hw_max = hw->clkdco_max;
+
+ fint_hw_min = hw->fint_min;
+ fint_hw_max = hw->fint_max;
+
+ n_start = max(DIV_ROUND_UP(clkin, fint_hw_max), 1ul);
+ n_stop = min((unsigned)(clkin / fint_hw_min), hw->n_max);
+
+ pll_max = pll_max ? pll_max : ULONG_MAX;
+
+ for (n = n_start; n <= n_stop; ++n) {
+ fint = clkin / n;
+
+ m_start = max(DIV_ROUND_UP(DIV_ROUND_UP(pll_min, fint), 2),
+ 1ul);
+ m_stop = min3((unsigned)(pll_max / fint / 2),
+ (unsigned)(pll_hw_max / fint / 2),
+ hw->m_max);
+
+ for (m = m_start; m <= m_stop; ++m) {
+ clkdco = 2 * m * fint;
+
+ if (func(n, m, fint, clkdco, data))
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static int wait_for_bit_change(void __iomem *reg, int bitnum, int value)
+{
+ unsigned long timeout;
+ ktime_t wait;
+ int t;
+
+ /* first busyloop to see if the bit changes right away */
+ t = 100;
+ while (t-- > 0) {
+ if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
+ return value;
+ }
+
+ /* then loop for 500ms, sleeping for 1ms in between */
+ timeout = jiffies + msecs_to_jiffies(500);
+ while (time_before(jiffies, timeout)) {
+ if (FLD_GET(readl_relaxed(reg), bitnum, bitnum) == value)
+ return value;
+
+ wait = ns_to_ktime(1000 * 1000);
+ set_current_state(TASK_UNINTERRUPTIBLE);
+ schedule_hrtimeout(&wait, HRTIMER_MODE_REL);
+ }
+
+ return !value;
+}
+
+static int dss_wait_hsdiv_ack(struct dss_pll *pll, u32 hsdiv_ack_mask)
+{
+ int t = 100;
+
+ while (t-- > 0) {
+ u32 v = readl_relaxed(pll->base + PLL_STATUS);
+ v &= hsdiv_ack_mask;
+ if (v == hsdiv_ack_mask)
+ return 0;
+ }
+
+ return -ETIMEDOUT;
+}
+
+int dss_pll_write_config_type_a(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ void __iomem *base = pll->base;
+ int r = 0;
+ u32 l;
+
+ l = 0;
+ if (hw->has_stopmode)
+ l = FLD_MOD(l, 1, 0, 0); /* PLL_STOPMODE */
+ l = FLD_MOD(l, cinfo->n - 1, hw->n_msb, hw->n_lsb); /* PLL_REGN */
+ l = FLD_MOD(l, cinfo->m, hw->m_msb, hw->m_lsb); /* PLL_REGM */
+ /* M4 */
+ l = FLD_MOD(l, cinfo->mX[0] ? cinfo->mX[0] - 1 : 0,
+ hw->mX_msb[0], hw->mX_lsb[0]);
+ /* M5 */
+ l = FLD_MOD(l, cinfo->mX[1] ? cinfo->mX[1] - 1 : 0,
+ hw->mX_msb[1], hw->mX_lsb[1]);
+ writel_relaxed(l, base + PLL_CONFIGURATION1);
+
+ l = 0;
+ /* M6 */
+ l = FLD_MOD(l, cinfo->mX[2] ? cinfo->mX[2] - 1 : 0,
+ hw->mX_msb[2], hw->mX_lsb[2]);
+ /* M7 */
+ l = FLD_MOD(l, cinfo->mX[3] ? cinfo->mX[3] - 1 : 0,
+ hw->mX_msb[3], hw->mX_lsb[3]);
+ writel_relaxed(l, base + PLL_CONFIGURATION3);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION2);
+ if (hw->has_freqsel) {
+ u32 f = cinfo->fint < 1000000 ? 0x3 :
+ cinfo->fint < 1250000 ? 0x4 :
+ cinfo->fint < 1500000 ? 0x5 :
+ cinfo->fint < 1750000 ? 0x6 :
+ 0x7;
+
+ l = FLD_MOD(l, f, 4, 1); /* PLL_FREQSEL */
+ } else if (hw->has_selfreqdco) {
+ u32 f = cinfo->clkdco < hw->clkdco_low ? 0x2 : 0x4;
+
+ l = FLD_MOD(l, f, 3, 1); /* PLL_SELFREQDCO */
+ }
+ l = FLD_MOD(l, 1, 13, 13); /* PLL_REFEN */
+ l = FLD_MOD(l, 0, 14, 14); /* PHY_CLKINEN */
+ l = FLD_MOD(l, 0, 16, 16); /* M4_CLOCK_EN */
+ l = FLD_MOD(l, 0, 18, 18); /* M5_CLOCK_EN */
+ l = FLD_MOD(l, 1, 20, 20); /* HSDIVBYPASS */
+ if (hw->has_refsel)
+ l = FLD_MOD(l, 3, 22, 21); /* REFSEL = sysclk */
+ l = FLD_MOD(l, 0, 23, 23); /* M6_CLOCK_EN */
+ l = FLD_MOD(l, 0, 25, 25); /* M7_CLOCK_EN */
+ writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+ writel_relaxed(1, base + PLL_GO); /* PLL_GO */
+
+ if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+ DSSERR("DSS DPLL GO bit not going down.\n");
+ r = -EIO;
+ goto err;
+ }
+
+ if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+ DSSERR("cannot lock DSS DPLL\n");
+ r = -EIO;
+ goto err;
+ }
+
+ l = readl_relaxed(base + PLL_CONFIGURATION2);
+ l = FLD_MOD(l, 1, 14, 14); /* PHY_CLKINEN */
+ l = FLD_MOD(l, cinfo->mX[0] ? 1 : 0, 16, 16); /* M4_CLOCK_EN */
+ l = FLD_MOD(l, cinfo->mX[1] ? 1 : 0, 18, 18); /* M5_CLOCK_EN */
+ l = FLD_MOD(l, 0, 20, 20); /* HSDIVBYPASS */
+ l = FLD_MOD(l, cinfo->mX[2] ? 1 : 0, 23, 23); /* M6_CLOCK_EN */
+ l = FLD_MOD(l, cinfo->mX[3] ? 1 : 0, 25, 25); /* M7_CLOCK_EN */
+ writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+ r = dss_wait_hsdiv_ack(pll,
+ (cinfo->mX[0] ? BIT(7) : 0) |
+ (cinfo->mX[1] ? BIT(8) : 0) |
+ (cinfo->mX[2] ? BIT(10) : 0) |
+ (cinfo->mX[3] ? BIT(11) : 0));
+ if (r) {
+ DSSERR("failed to enable HSDIV clocks\n");
+ goto err;
+ }
+
+err:
+ return r;
+}
+
+int dss_pll_write_config_type_b(struct dss_pll *pll,
+ const struct dss_pll_clock_info *cinfo)
+{
+ const struct dss_pll_hw *hw = pll->hw;
+ void __iomem *base = pll->base;
+ u32 l;
+
+ l = 0;
+ l = FLD_MOD(l, cinfo->m, 20, 9); /* PLL_REGM */
+ l = FLD_MOD(l, cinfo->n - 1, 8, 1); /* PLL_REGN */
+ writel_relaxed(l, base + PLL_CONFIGURATION1);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION2);
+ l = FLD_MOD(l, 0x0, 12, 12); /* PLL_HIGHFREQ divide by 2 */
+ l = FLD_MOD(l, 0x1, 13, 13); /* PLL_REFEN */
+ l = FLD_MOD(l, 0x0, 14, 14); /* PHY_CLKINEN */
+ if (hw->has_refsel)
+ l = FLD_MOD(l, 0x3, 22, 21); /* REFSEL = SYSCLK */
+
+ /* PLL_SELFREQDCO */
+ if (cinfo->clkdco > hw->clkdco_low)
+ l = FLD_MOD(l, 0x4, 3, 1);
+ else
+ l = FLD_MOD(l, 0x2, 3, 1);
+ writel_relaxed(l, base + PLL_CONFIGURATION2);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION3);
+ l = FLD_MOD(l, cinfo->sd, 17, 10); /* PLL_REGSD */
+ writel_relaxed(l, base + PLL_CONFIGURATION3);
+
+ l = readl_relaxed(base + PLL_CONFIGURATION4);
+ l = FLD_MOD(l, cinfo->mX[0], 24, 18); /* PLL_REGM2 */
+ l = FLD_MOD(l, cinfo->mf, 17, 0); /* PLL_REGM_F */
+ writel_relaxed(l, base + PLL_CONFIGURATION4);
+
+ writel_relaxed(1, base + PLL_GO); /* PLL_GO */
+
+ if (wait_for_bit_change(base + PLL_GO, 0, 0) != 0) {
+ DSSERR("DSS DPLL GO bit not going down.\n");
+ return -EIO;
+ }
+
+ if (wait_for_bit_change(base + PLL_STATUS, 1, 1) != 1) {
+ DSSERR("cannot lock DSS DPLL\n");
+ return -ETIMEDOUT;
+ }
+
+ return 0;
+}
diff --git a/drivers/video/fbdev/omap2/dss/sdi.c b/drivers/video/fbdev/omap2/dss/sdi.c
index 4c9c46d..d9b10f2 100644
--- a/drivers/video/fbdev/omap2/dss/sdi.c
+++ b/drivers/video/fbdev/omap2/dss/sdi.c
@@ -425,7 +425,7 @@ err_datapairs:
return r;
}
-void __exit sdi_uninit_port(void)
+void __exit sdi_uninit_port(struct device_node *port)
{
if (!sdi.port_initialized)
return;
diff --git a/drivers/video/fbdev/s3fb.c b/drivers/video/fbdev/s3fb.c
index c43b969..f0ae61a 100644
--- a/drivers/video/fbdev/s3fb.c
+++ b/drivers/video/fbdev/s3fb.c
@@ -1182,7 +1182,7 @@ static int s3_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
- par->state.vgabase = (void __iomem *) vga_res.start;
+ par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
/* Unlock regs */
cr38 = vga_rcrt(par->state.vgabase, 0x38);
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index 2bcc84a..cfde21d 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -2181,8 +2181,7 @@ sh_mobile_lcdc_channel_fb_cleanup(struct sh_mobile_lcdc_chan *ch)
if (!info || !info->device)
return;
- if (ch->sglist)
- vfree(ch->sglist);
+ vfree(ch->sglist);
fb_dealloc_cmap(&info->cmap);
framebuffer_release(info);
diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index 210f3a0..b2ae925 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -26,6 +26,8 @@
#include <linux/module.h>
#include <linux/platform_data/simplefb.h>
#include <linux/platform_device.h>
+#include <linux/clk-provider.h>
+#include <linux/of_platform.h>
static struct fb_fix_screeninfo simplefb_fix = {
.id = "simple",
@@ -41,6 +43,8 @@ static struct fb_var_screeninfo simplefb_var = {
.vmode = FB_VMODE_NONINTERLACED,
};
+#define PSEUDO_PALETTE_SIZE 16
+
static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u_int transp, struct fb_info *info)
{
@@ -50,7 +54,7 @@ static int simplefb_setcolreg(u_int regno, u_int red, u_int green, u_int blue,
u32 cb = blue >> (16 - info->var.blue.length);
u32 value;
- if (regno >= 16)
+ if (regno >= PSEUDO_PALETTE_SIZE)
return -EINVAL;
value = (cr << info->var.red.offset) |
@@ -163,11 +167,113 @@ static int simplefb_parse_pd(struct platform_device *pdev,
return 0;
}
+struct simplefb_par {
+ u32 palette[PSEUDO_PALETTE_SIZE];
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+ int clk_count;
+ struct clk **clks;
+#endif
+};
+
+#if defined CONFIG_OF && defined CONFIG_COMMON_CLK
+/*
+ * Clock handling code.
+ *
+ * Here we handle the clocks property of our "simple-framebuffer" dt node.
+ * This is necessary so that we can make sure that any clocks needed by
+ * the display engine that the bootloader set up for us (and for which it
+ * provided a simplefb dt node), stay up, for the life of the simplefb
+ * driver.
+ *
+ * When the driver unloads, we cleanly disable, and then release the clocks.
+ *
+ * We only complain about errors here, no action is taken as the most likely
+ * error can only happen due to a mismatch between the bootloader which set
+ * up simplefb, and the clock definitions in the device tree. Chances are
+ * that there are no adverse effects, and if there are, a clean teardown of
+ * the fb probe will not help us much either. So just complain and carry on,
+ * and hope that the user actually gets a working fb at the end of things.
+ */
+static int simplefb_clocks_init(struct simplefb_par *par,
+ struct platform_device *pdev)
+{
+ struct device_node *np = pdev->dev.of_node;
+ struct clk *clock;
+ int i, ret;
+
+ if (dev_get_platdata(&pdev->dev) || !np)
+ return 0;
+
+ par->clk_count = of_clk_get_parent_count(np);
+ if (par->clk_count <= 0)
+ return 0;
+
+ par->clks = kcalloc(par->clk_count, sizeof(struct clk *), GFP_KERNEL);
+ if (!par->clks)
+ return -ENOMEM;
+
+ for (i = 0; i < par->clk_count; i++) {
+ clock = of_clk_get(np, i);
+ if (IS_ERR(clock)) {
+ if (PTR_ERR(clock) == -EPROBE_DEFER) {
+ while (--i >= 0) {
+ if (par->clks[i])
+ clk_put(par->clks[i]);
+ }
+ kfree(par->clks);
+ return -EPROBE_DEFER;
+ }
+ dev_err(&pdev->dev, "%s: clock %d not found: %ld\n",
+ __func__, i, PTR_ERR(clock));
+ continue;
+ }
+ par->clks[i] = clock;
+ }
+
+ for (i = 0; i < par->clk_count; i++) {
+ if (par->clks[i]) {
+ ret = clk_prepare_enable(par->clks[i]);
+ if (ret) {
+ dev_err(&pdev->dev,
+ "%s: failed to enable clock %d: %d\n",
+ __func__, i, ret);
+ clk_put(par->clks[i]);
+ par->clks[i] = NULL;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void simplefb_clocks_destroy(struct simplefb_par *par)
+{
+ int i;
+
+ if (!par->clks)
+ return;
+
+ for (i = 0; i < par->clk_count; i++) {
+ if (par->clks[i]) {
+ clk_disable_unprepare(par->clks[i]);
+ clk_put(par->clks[i]);
+ }
+ }
+
+ kfree(par->clks);
+}
+#else
+static int simplefb_clocks_init(struct simplefb_par *par,
+ struct platform_device *pdev) { return 0; }
+static void simplefb_clocks_destroy(struct simplefb_par *par) { }
+#endif
+
static int simplefb_probe(struct platform_device *pdev)
{
int ret;
struct simplefb_params params;
struct fb_info *info;
+ struct simplefb_par *par;
struct resource *mem;
if (fb_get_options("simplefb", NULL))
@@ -188,11 +294,13 @@ static int simplefb_probe(struct platform_device *pdev)
return -EINVAL;
}
- info = framebuffer_alloc(sizeof(u32) * 16, &pdev->dev);
+ info = framebuffer_alloc(sizeof(struct simplefb_par), &pdev->dev);
if (!info)
return -ENOMEM;
platform_set_drvdata(pdev, info);
+ par = info->par;
+
info->fix = simplefb_fix;
info->fix.smem_start = mem->start;
info->fix.smem_len = resource_size(mem);
@@ -211,8 +319,8 @@ static int simplefb_probe(struct platform_device *pdev)
info->apertures = alloc_apertures(1);
if (!info->apertures) {
- framebuffer_release(info);
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto error_fb_release;
}
info->apertures->ranges[0].base = info->fix.smem_start;
info->apertures->ranges[0].size = info->fix.smem_len;
@@ -222,10 +330,14 @@ static int simplefb_probe(struct platform_device *pdev)
info->screen_base = ioremap_wc(info->fix.smem_start,
info->fix.smem_len);
if (!info->screen_base) {
- framebuffer_release(info);
- return -ENODEV;
+ ret = -ENOMEM;
+ goto error_fb_release;
}
- info->pseudo_palette = (void *)(info + 1);
+ info->pseudo_palette = par->palette;
+
+ ret = simplefb_clocks_init(par, pdev);
+ if (ret < 0)
+ goto error_unmap;
dev_info(&pdev->dev, "framebuffer at 0x%lx, 0x%x bytes, mapped to 0x%p\n",
info->fix.smem_start, info->fix.smem_len,
@@ -238,21 +350,29 @@ static int simplefb_probe(struct platform_device *pdev)
ret = register_framebuffer(info);
if (ret < 0) {
dev_err(&pdev->dev, "Unable to register simplefb: %d\n", ret);
- iounmap(info->screen_base);
- framebuffer_release(info);
- return ret;
+ goto error_clocks;
}
dev_info(&pdev->dev, "fb%d: simplefb registered!\n", info->node);
return 0;
+
+error_clocks:
+ simplefb_clocks_destroy(par);
+error_unmap:
+ iounmap(info->screen_base);
+error_fb_release:
+ framebuffer_release(info);
+ return ret;
}
static int simplefb_remove(struct platform_device *pdev)
{
struct fb_info *info = platform_get_drvdata(pdev);
+ struct simplefb_par *par = info->par;
unregister_framebuffer(info);
+ simplefb_clocks_destroy(par);
framebuffer_release(info);
return 0;
@@ -273,7 +393,27 @@ static struct platform_driver simplefb_driver = {
.probe = simplefb_probe,
.remove = simplefb_remove,
};
-module_platform_driver(simplefb_driver);
+
+static int __init simplefb_init(void)
+{
+ int ret;
+ struct device_node *np;
+
+ ret = platform_driver_register(&simplefb_driver);
+ if (ret)
+ return ret;
+
+ if (IS_ENABLED(CONFIG_OF) && of_chosen) {
+ for_each_child_of_node(of_chosen, np) {
+ if (of_device_is_compatible(np, "simple-framebuffer"))
+ of_platform_device_create(np, NULL, NULL);
+ }
+ }
+
+ return 0;
+}
+
+fs_initcall(simplefb_init);
MODULE_AUTHOR("Stephen Warren <swarren@wwwdotorg.org>");
MODULE_DESCRIPTION("Simple framebuffer driver");
diff --git a/drivers/video/fbdev/sis/sis_main.c b/drivers/video/fbdev/sis/sis_main.c
index e5d11b1..fcf610e 100644
--- a/drivers/video/fbdev/sis/sis_main.c
+++ b/drivers/video/fbdev/sis/sis_main.c
@@ -5989,7 +5989,7 @@ static int sisfb_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if(!ivideo->sisvga_enabled) {
if(pci_enable_device(pdev)) {
- if(ivideo->nbridge) pci_dev_put(ivideo->nbridge);
+ pci_dev_put(ivideo->nbridge);
framebuffer_release(sis_fb_info);
return -EIO;
}
@@ -6202,10 +6202,8 @@ error_0: iounmap(ivideo->video_vbase);
error_1: release_mem_region(ivideo->video_base, ivideo->video_size);
error_2: release_mem_region(ivideo->mmio_base, ivideo->mmio_size);
error_3: vfree(ivideo->bios_abase);
- if(ivideo->lpcdev)
- pci_dev_put(ivideo->lpcdev);
- if(ivideo->nbridge)
- pci_dev_put(ivideo->nbridge);
+ pci_dev_put(ivideo->lpcdev);
+ pci_dev_put(ivideo->nbridge);
if(!ivideo->sisvga_enabled)
pci_disable_device(pdev);
framebuffer_release(sis_fb_info);
@@ -6505,11 +6503,9 @@ static void sisfb_remove(struct pci_dev *pdev)
vfree(ivideo->bios_abase);
- if(ivideo->lpcdev)
- pci_dev_put(ivideo->lpcdev);
+ pci_dev_put(ivideo->lpcdev);
- if(ivideo->nbridge)
- pci_dev_put(ivideo->nbridge);
+ pci_dev_put(ivideo->nbridge);
#ifdef CONFIG_MTRR
/* Release MTRR region */
diff --git a/drivers/video/fbdev/sm501fb.c b/drivers/video/fbdev/sm501fb.c
index 9e74e8f..8b98b01 100644
--- a/drivers/video/fbdev/sm501fb.c
+++ b/drivers/video/fbdev/sm501fb.c
@@ -1988,6 +1988,7 @@ static int sm501fb_probe(struct platform_device *pdev)
if (info->fb[HEAD_PANEL] == NULL &&
info->fb[HEAD_CRT] == NULL) {
dev_err(dev, "no framebuffers found\n");
+ ret = -ENODEV;
goto err_alloc;
}
diff --git a/drivers/video/fbdev/smscufx.c b/drivers/video/fbdev/smscufx.c
index d513ed6..9279e5f 100644
--- a/drivers/video/fbdev/smscufx.c
+++ b/drivers/video/fbdev/smscufx.c
@@ -1142,8 +1142,7 @@ static void ufx_free_framebuffer_work(struct work_struct *work)
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
fb_destroy_modedb(info->monspecs.modedb);
- if (info->screen_base)
- vfree(info->screen_base);
+ vfree(info->screen_base);
fb_destroy_modelist(&info->modelist);
@@ -1743,8 +1742,7 @@ error:
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
fb_destroy_modedb(info->monspecs.modedb);
- if (info->screen_base)
- vfree(info->screen_base);
+ vfree(info->screen_base);
fb_destroy_modelist(&info->modelist);
diff --git a/drivers/video/fbdev/udlfb.c b/drivers/video/fbdev/udlfb.c
index 046d51d..ff2b873 100644
--- a/drivers/video/fbdev/udlfb.c
+++ b/drivers/video/fbdev/udlfb.c
@@ -922,8 +922,7 @@ static void dlfb_free(struct kref *kref)
{
struct dlfb_data *dev = container_of(kref, struct dlfb_data, kref);
- if (dev->backing_buffer)
- vfree(dev->backing_buffer);
+ vfree(dev->backing_buffer);
kfree(dev->edid);
@@ -953,8 +952,7 @@ static void dlfb_free_framebuffer(struct dlfb_data *dev)
fb_dealloc_cmap(&info->cmap);
if (info->monspecs.modedb)
fb_destroy_modedb(info->monspecs.modedb);
- if (info->screen_base)
- vfree(info->screen_base);
+ vfree(info->screen_base);
fb_destroy_modelist(&info->modelist);
@@ -1203,8 +1201,7 @@ static int dlfb_realloc_framebuffer(struct dlfb_data *dev, struct fb_info *info)
if (!new_back)
pr_info("No shadow/backing buffer allocated\n");
else {
- if (dev->backing_buffer)
- vfree(dev->backing_buffer);
+ vfree(dev->backing_buffer);
dev->backing_buffer = new_back;
}
}
diff --git a/drivers/video/fbdev/uvesafb.c b/drivers/video/fbdev/uvesafb.c
index 509d452..d32d1c4 100644
--- a/drivers/video/fbdev/uvesafb.c
+++ b/drivers/video/fbdev/uvesafb.c
@@ -1219,8 +1219,7 @@ static int uvesafb_release(struct fb_info *info, int user)
uvesafb_vbe_state_restore(par, par->vbe_state_orig);
out:
atomic_dec(&par->ref_count);
- if (task)
- uvesafb_free(task);
+ uvesafb_free(task);
return 0;
}
@@ -1923,8 +1922,7 @@ static int uvesafb_init(void)
err = -ENOMEM;
if (err) {
- if (uvesafb_device)
- platform_device_put(uvesafb_device);
+ platform_device_put(uvesafb_device);
platform_driver_unregister(&uvesafb_driver);
cn_del_callback(&uvesafb_cn_id);
return err;
diff --git a/drivers/video/fbdev/vermilion/vermilion.c b/drivers/video/fbdev/vermilion/vermilion.c
index 5f930ae..6b70d7f 100644
--- a/drivers/video/fbdev/vermilion/vermilion.c
+++ b/drivers/video/fbdev/vermilion/vermilion.c
@@ -1003,13 +1003,15 @@ static int vmlfb_mmap(struct fb_info *info, struct vm_area_struct *vma)
struct vml_info *vinfo = container_of(info, struct vml_info, info);
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
int ret;
+ unsigned long prot;
ret = vmlfb_vram_offset(vinfo, offset);
if (ret)
return -EINVAL;
- pgprot_val(vma->vm_page_prot) |= _PAGE_PCD;
- pgprot_val(vma->vm_page_prot) &= ~_PAGE_PWT;
+ prot = pgprot_val(vma->vm_page_prot) & ~_PAGE_CACHE_MASK;
+ pgprot_val(vma->vm_page_prot) =
+ prot | cachemode2protval(_PAGE_CACHE_MODE_UC_MINUS);
return vm_iomap_memory(vma, vinfo->vram_start,
vinfo->vram_contig_size);
diff --git a/drivers/video/fbdev/via/viafbdev.c b/drivers/video/fbdev/via/viafbdev.c
index 325c43c..f9718f0 100644
--- a/drivers/video/fbdev/via/viafbdev.c
+++ b/drivers/video/fbdev/via/viafbdev.c
@@ -1937,8 +1937,7 @@ out_fb1_unreg_lcd_cle266:
out_dealloc_cmap:
fb_dealloc_cmap(&viafbinfo->cmap);
out_fb1_release:
- if (viafbinfo1)
- framebuffer_release(viafbinfo1);
+ framebuffer_release(viafbinfo1);
out_fb_release:
i2c_bus_free(viaparinfo->shared);
framebuffer_release(viafbinfo);
diff --git a/drivers/video/fbdev/vt8623fb.c b/drivers/video/fbdev/vt8623fb.c
index 5c7cbc6..ea7f056 100644
--- a/drivers/video/fbdev/vt8623fb.c
+++ b/drivers/video/fbdev/vt8623fb.c
@@ -731,7 +731,7 @@ static int vt8623_pci_probe(struct pci_dev *dev, const struct pci_device_id *id)
pcibios_bus_to_resource(dev->bus, &vga_res, &bus_reg);
- par->state.vgabase = (void __iomem *) vga_res.start;
+ par->state.vgabase = (void __iomem *) (unsigned long) vga_res.start;
/* Find how many physical memory there is on card */
memsize1 = (vga_rseq(par->state.vgabase, 0x34) + 1) >> 1;
diff --git a/drivers/virtio/Makefile b/drivers/virtio/Makefile
index 9076635..bf5104b 100644
--- a/drivers/virtio/Makefile
+++ b/drivers/virtio/Makefile
@@ -1,4 +1,5 @@
obj-$(CONFIG_VIRTIO) += virtio.o virtio_ring.o
obj-$(CONFIG_VIRTIO_MMIO) += virtio_mmio.o
obj-$(CONFIG_VIRTIO_PCI) += virtio_pci.o
+virtio_pci-y := virtio_pci_legacy.o virtio_pci_common.o
obj-$(CONFIG_VIRTIO_BALLOON) += virtio_balloon.o
diff --git a/drivers/virtio/virtio.c b/drivers/virtio/virtio.c
index df598dd..f226658 100644
--- a/drivers/virtio/virtio.c
+++ b/drivers/virtio/virtio.c
@@ -3,6 +3,7 @@
#include <linux/virtio_config.h>
#include <linux/module.h>
#include <linux/idr.h>
+#include <uapi/linux/virtio_ids.h>
/* Unique numbering for virtio devices. */
static DEFINE_IDA(virtio_index_ida);
@@ -49,9 +50,9 @@ static ssize_t features_show(struct device *_d,
/* We actually represent this as a bitstring, as it could be
* arbitrary length in future. */
- for (i = 0; i < ARRAY_SIZE(dev->features)*BITS_PER_LONG; i++)
+ for (i = 0; i < sizeof(dev->features)*8; i++)
len += sprintf(buf+len, "%c",
- test_bit(i, dev->features) ? '1' : '0');
+ __virtio_test_bit(dev, i) ? '1' : '0');
len += sprintf(buf+len, "\n");
return len;
}
@@ -113,6 +114,13 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
for (i = 0; i < drv->feature_table_size; i++)
if (drv->feature_table[i] == fbit)
return;
+
+ if (drv->feature_table_legacy) {
+ for (i = 0; i < drv->feature_table_size_legacy; i++)
+ if (drv->feature_table_legacy[i] == fbit)
+ return;
+ }
+
BUG();
}
EXPORT_SYMBOL_GPL(virtio_check_driver_offered_feature);
@@ -159,7 +167,10 @@ static int virtio_dev_probe(struct device *_d)
int err, i;
struct virtio_device *dev = dev_to_virtio(_d);
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
- u32 device_features;
+ u64 device_features;
+ u64 driver_features;
+ u64 driver_features_legacy;
+ unsigned status;
/* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
@@ -167,34 +178,66 @@ static int virtio_dev_probe(struct device *_d)
/* Figure out what features the device supports. */
device_features = dev->config->get_features(dev);
- /* Features supported by both device and driver into dev->features. */
- memset(dev->features, 0, sizeof(dev->features));
+ /* Figure out what features the driver supports. */
+ driver_features = 0;
for (i = 0; i < drv->feature_table_size; i++) {
unsigned int f = drv->feature_table[i];
- BUG_ON(f >= 32);
- if (device_features & (1 << f))
- set_bit(f, dev->features);
+ BUG_ON(f >= 64);
+ driver_features |= (1ULL << f);
+ }
+
+ /* Some drivers have a separate feature table for virtio v1.0 */
+ if (drv->feature_table_legacy) {
+ driver_features_legacy = 0;
+ for (i = 0; i < drv->feature_table_size_legacy; i++) {
+ unsigned int f = drv->feature_table_legacy[i];
+ BUG_ON(f >= 64);
+ driver_features_legacy |= (1ULL << f);
+ }
+ } else {
+ driver_features_legacy = driver_features;
}
+ if (device_features & (1ULL << VIRTIO_F_VERSION_1))
+ dev->features = driver_features & device_features;
+ else
+ dev->features = driver_features_legacy & device_features;
+
/* Transport features always preserved to pass to finalize_features. */
for (i = VIRTIO_TRANSPORT_F_START; i < VIRTIO_TRANSPORT_F_END; i++)
- if (device_features & (1 << i))
- set_bit(i, dev->features);
+ if (device_features & (1ULL << i))
+ __virtio_set_bit(dev, i);
- dev->config->finalize_features(dev);
+ err = dev->config->finalize_features(dev);
+ if (err)
+ goto err;
+
+ if (virtio_has_feature(dev, VIRTIO_F_VERSION_1)) {
+ add_status(dev, VIRTIO_CONFIG_S_FEATURES_OK);
+ status = dev->config->get_status(dev);
+ if (!(status & VIRTIO_CONFIG_S_FEATURES_OK)) {
+ dev_err(_d, "virtio: device refuses features: %x\n",
+ status);
+ err = -ENODEV;
+ goto err;
+ }
+ }
err = drv->probe(dev);
if (err)
- add_status(dev, VIRTIO_CONFIG_S_FAILED);
- else {
- add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
- if (drv->scan)
- drv->scan(dev);
+ goto err;
- virtio_config_enable(dev);
- }
+ add_status(dev, VIRTIO_CONFIG_S_DRIVER_OK);
+ if (drv->scan)
+ drv->scan(dev);
+
+ virtio_config_enable(dev);
+ return 0;
+err:
+ add_status(dev, VIRTIO_CONFIG_S_FAILED);
return err;
+
}
static int virtio_dev_remove(struct device *_d)
@@ -223,6 +266,12 @@ static struct bus_type virtio_bus = {
.remove = virtio_dev_remove,
};
+bool virtio_device_is_legacy_only(struct virtio_device_id id)
+{
+ return id.device == VIRTIO_ID_BALLOON;
+}
+EXPORT_SYMBOL_GPL(virtio_device_is_legacy_only);
+
int register_virtio_driver(struct virtio_driver *driver)
{
/* Catch this early. */
@@ -303,6 +352,7 @@ EXPORT_SYMBOL_GPL(virtio_device_freeze);
int virtio_device_restore(struct virtio_device *dev)
{
struct virtio_driver *drv = drv_to_virtio(dev->dev.driver);
+ int ret;
/* We always start by resetting the device, in case a previous
* driver messed it up. */
@@ -322,14 +372,14 @@ int virtio_device_restore(struct virtio_device *dev)
/* We have a driver! */
add_status(dev, VIRTIO_CONFIG_S_DRIVER);
- dev->config->finalize_features(dev);
+ ret = dev->config->finalize_features(dev);
+ if (ret)
+ goto err;
if (drv->restore) {
- int ret = drv->restore(dev);
- if (ret) {
- add_status(dev, VIRTIO_CONFIG_S_FAILED);
- return ret;
- }
+ ret = drv->restore(dev);
+ if (ret)
+ goto err;
}
/* Finally, tell the device we're all set */
@@ -338,6 +388,10 @@ int virtio_device_restore(struct virtio_device *dev)
virtio_config_enable(dev);
return 0;
+
+err:
+ add_status(dev, VIRTIO_CONFIG_S_FAILED);
+ return ret;
}
EXPORT_SYMBOL_GPL(virtio_device_restore);
#endif
diff --git a/drivers/virtio/virtio_mmio.c b/drivers/virtio/virtio_mmio.c
index ef9a165..5219210 100644
--- a/drivers/virtio/virtio_mmio.c
+++ b/drivers/virtio/virtio_mmio.c
@@ -142,7 +142,7 @@ struct virtio_mmio_vq_info {
/* Configuration interface */
-static u32 vm_get_features(struct virtio_device *vdev)
+static u64 vm_get_features(struct virtio_device *vdev)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
@@ -152,19 +152,20 @@ static u32 vm_get_features(struct virtio_device *vdev)
return readl(vm_dev->base + VIRTIO_MMIO_HOST_FEATURES);
}
-static void vm_finalize_features(struct virtio_device *vdev)
+static int vm_finalize_features(struct virtio_device *vdev)
{
struct virtio_mmio_device *vm_dev = to_virtio_mmio_device(vdev);
- int i;
/* Give virtio_ring a chance to accept features. */
vring_transport_features(vdev);
- for (i = 0; i < ARRAY_SIZE(vdev->features); i++) {
- writel(i, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL);
- writel(vdev->features[i],
- vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES);
- }
+ /* Make sure we don't have any features > 32 bits! */
+ BUG_ON((u32)vdev->features != vdev->features);
+
+ writel(0, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES_SEL);
+ writel(vdev->features, vm_dev->base + VIRTIO_MMIO_GUEST_FEATURES);
+
+ return 0;
}
static void vm_get(struct virtio_device *vdev, unsigned offset,
diff --git a/drivers/virtio/virtio_pci.c b/drivers/virtio/virtio_pci.c
deleted file mode 100644
index d34ebfa..0000000
--- a/drivers/virtio/virtio_pci.c
+++ /dev/null
@@ -1,802 +0,0 @@
-/*
- * Virtio PCI driver
- *
- * This module allows virtio devices to be used over a virtual PCI device.
- * This can be used with QEMU based VMMs like KVM or Xen.
- *
- * Copyright IBM Corp. 2007
- *
- * Authors:
- * Anthony Liguori <aliguori@us.ibm.com>
- *
- * This work is licensed under the terms of the GNU GPL, version 2 or later.
- * See the COPYING file in the top-level directory.
- *
- */
-
-#include <linux/module.h>
-#include <linux/list.h>
-#include <linux/pci.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/virtio.h>
-#include <linux/virtio_config.h>
-#include <linux/virtio_ring.h>
-#include <linux/virtio_pci.h>
-#include <linux/highmem.h>
-#include <linux/spinlock.h>
-
-MODULE_AUTHOR("Anthony Liguori <aliguori@us.ibm.com>");
-MODULE_DESCRIPTION("virtio-pci");
-MODULE_LICENSE("GPL");
-MODULE_VERSION("1");
-
-/* Our device structure */
-struct virtio_pci_device
-{
- struct virtio_device vdev;
- struct pci_dev *pci_dev;
-
- /* the IO mapping for the PCI config space */
- void __iomem *ioaddr;
-
- /* a list of queues so we can dispatch IRQs */
- spinlock_t lock;
- struct list_head virtqueues;
-
- /* MSI-X support */
- int msix_enabled;
- int intx_enabled;
- struct msix_entry *msix_entries;
- cpumask_var_t *msix_affinity_masks;
- /* Name strings for interrupts. This size should be enough,
- * and I'm too lazy to allocate each name separately. */
- char (*msix_names)[256];
- /* Number of available vectors */
- unsigned msix_vectors;
- /* Vectors allocated, excluding per-vq vectors if any */
- unsigned msix_used_vectors;
-
- /* Whether we have vector per vq */
- bool per_vq_vectors;
-};
-
-/* Constants for MSI-X */
-/* Use first vector for configuration changes, second and the rest for
- * virtqueues Thus, we need at least 2 vectors for MSI. */
-enum {
- VP_MSIX_CONFIG_VECTOR = 0,
- VP_MSIX_VQ_VECTOR = 1,
-};
-
-struct virtio_pci_vq_info
-{
- /* the actual virtqueue */
- struct virtqueue *vq;
-
- /* the number of entries in the queue */
- int num;
-
- /* the virtual address of the ring queue */
- void *queue;
-
- /* the list node for the virtqueues list */
- struct list_head node;
-
- /* MSI-X vector (or none) */
- unsigned msix_vector;
-};
-
-/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
-static const struct pci_device_id virtio_pci_id_table[] = {
- { PCI_DEVICE(0x1af4, PCI_ANY_ID) },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
-
-/* Convert a generic virtio device to our structure */
-static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
-{
- return container_of(vdev, struct virtio_pci_device, vdev);
-}
-
-/* virtio config->get_features() implementation */
-static u32 vp_get_features(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
- /* When someone needs more than 32 feature bits, we'll need to
- * steal a bit to indicate that the rest are somewhere else. */
- return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
-}
-
-/* virtio config->finalize_features() implementation */
-static void vp_finalize_features(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
- /* Give virtio_ring a chance to accept features. */
- vring_transport_features(vdev);
-
- /* We only support 32 feature bits. */
- BUILD_BUG_ON(ARRAY_SIZE(vdev->features) != 1);
- iowrite32(vdev->features[0], vp_dev->ioaddr+VIRTIO_PCI_GUEST_FEATURES);
-}
-
-/* virtio config->get() implementation */
-static void vp_get(struct virtio_device *vdev, unsigned offset,
- void *buf, unsigned len)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- void __iomem *ioaddr = vp_dev->ioaddr +
- VIRTIO_PCI_CONFIG(vp_dev) + offset;
- u8 *ptr = buf;
- int i;
-
- for (i = 0; i < len; i++)
- ptr[i] = ioread8(ioaddr + i);
-}
-
-/* the config->set() implementation. it's symmetric to the config->get()
- * implementation */
-static void vp_set(struct virtio_device *vdev, unsigned offset,
- const void *buf, unsigned len)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- void __iomem *ioaddr = vp_dev->ioaddr +
- VIRTIO_PCI_CONFIG(vp_dev) + offset;
- const u8 *ptr = buf;
- int i;
-
- for (i = 0; i < len; i++)
- iowrite8(ptr[i], ioaddr + i);
-}
-
-/* config->{get,set}_status() implementations */
-static u8 vp_get_status(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- return ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);
-}
-
-static void vp_set_status(struct virtio_device *vdev, u8 status)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- /* We should never be setting status to 0. */
- BUG_ON(status == 0);
- iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
-}
-
-/* wait for pending irq handlers */
-static void vp_synchronize_vectors(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- int i;
-
- if (vp_dev->intx_enabled)
- synchronize_irq(vp_dev->pci_dev->irq);
-
- for (i = 0; i < vp_dev->msix_vectors; ++i)
- synchronize_irq(vp_dev->msix_entries[i].vector);
-}
-
-static void vp_reset(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- /* 0 status means a reset. */
- iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
- /* Flush out the status write, and flush in device writes,
- * including MSi-X interrupts, if any. */
- ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);
- /* Flush pending VQ/configuration callbacks. */
- vp_synchronize_vectors(vdev);
-}
-
-/* the notify function used when creating a virt queue */
-static bool vp_notify(struct virtqueue *vq)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
-
- /* we write the queue's selector into the notification register to
- * signal the other end */
- iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY);
- return true;
-}
-
-/* Handle a configuration change: Tell driver if it wants to know. */
-static irqreturn_t vp_config_changed(int irq, void *opaque)
-{
- struct virtio_pci_device *vp_dev = opaque;
-
- virtio_config_changed(&vp_dev->vdev);
- return IRQ_HANDLED;
-}
-
-/* Notify all virtqueues on an interrupt. */
-static irqreturn_t vp_vring_interrupt(int irq, void *opaque)
-{
- struct virtio_pci_device *vp_dev = opaque;
- struct virtio_pci_vq_info *info;
- irqreturn_t ret = IRQ_NONE;
- unsigned long flags;
-
- spin_lock_irqsave(&vp_dev->lock, flags);
- list_for_each_entry(info, &vp_dev->virtqueues, node) {
- if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
- ret = IRQ_HANDLED;
- }
- spin_unlock_irqrestore(&vp_dev->lock, flags);
-
- return ret;
-}
-
-/* A small wrapper to also acknowledge the interrupt when it's handled.
- * I really need an EIO hook for the vring so I can ack the interrupt once we
- * know that we'll be handling the IRQ but before we invoke the callback since
- * the callback may notify the host which results in the host attempting to
- * raise an interrupt that we would then mask once we acknowledged the
- * interrupt. */
-static irqreturn_t vp_interrupt(int irq, void *opaque)
-{
- struct virtio_pci_device *vp_dev = opaque;
- u8 isr;
-
- /* reading the ISR has the effect of also clearing it so it's very
- * important to save off the value. */
- isr = ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
-
- /* It's definitely not us if the ISR was not high */
- if (!isr)
- return IRQ_NONE;
-
- /* Configuration change? Tell driver if it wants to know. */
- if (isr & VIRTIO_PCI_ISR_CONFIG)
- vp_config_changed(irq, opaque);
-
- return vp_vring_interrupt(irq, opaque);
-}
-
-static void vp_free_vectors(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- int i;
-
- if (vp_dev->intx_enabled) {
- free_irq(vp_dev->pci_dev->irq, vp_dev);
- vp_dev->intx_enabled = 0;
- }
-
- for (i = 0; i < vp_dev->msix_used_vectors; ++i)
- free_irq(vp_dev->msix_entries[i].vector, vp_dev);
-
- for (i = 0; i < vp_dev->msix_vectors; i++)
- if (vp_dev->msix_affinity_masks[i])
- free_cpumask_var(vp_dev->msix_affinity_masks[i]);
-
- if (vp_dev->msix_enabled) {
- /* Disable the vector used for configuration */
- iowrite16(VIRTIO_MSI_NO_VECTOR,
- vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
- /* Flush the write out to device */
- ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
-
- pci_disable_msix(vp_dev->pci_dev);
- vp_dev->msix_enabled = 0;
- }
-
- vp_dev->msix_vectors = 0;
- vp_dev->msix_used_vectors = 0;
- kfree(vp_dev->msix_names);
- vp_dev->msix_names = NULL;
- kfree(vp_dev->msix_entries);
- vp_dev->msix_entries = NULL;
- kfree(vp_dev->msix_affinity_masks);
- vp_dev->msix_affinity_masks = NULL;
-}
-
-static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
- bool per_vq_vectors)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- const char *name = dev_name(&vp_dev->vdev.dev);
- unsigned i, v;
- int err = -ENOMEM;
-
- vp_dev->msix_vectors = nvectors;
-
- vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
- GFP_KERNEL);
- if (!vp_dev->msix_entries)
- goto error;
- vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
- GFP_KERNEL);
- if (!vp_dev->msix_names)
- goto error;
- vp_dev->msix_affinity_masks
- = kzalloc(nvectors * sizeof *vp_dev->msix_affinity_masks,
- GFP_KERNEL);
- if (!vp_dev->msix_affinity_masks)
- goto error;
- for (i = 0; i < nvectors; ++i)
- if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i],
- GFP_KERNEL))
- goto error;
-
- for (i = 0; i < nvectors; ++i)
- vp_dev->msix_entries[i].entry = i;
-
- err = pci_enable_msix_exact(vp_dev->pci_dev,
- vp_dev->msix_entries, nvectors);
- if (err)
- goto error;
- vp_dev->msix_enabled = 1;
-
- /* Set the vector used for configuration */
- v = vp_dev->msix_used_vectors;
- snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
- "%s-config", name);
- err = request_irq(vp_dev->msix_entries[v].vector,
- vp_config_changed, 0, vp_dev->msix_names[v],
- vp_dev);
- if (err)
- goto error;
- ++vp_dev->msix_used_vectors;
-
- iowrite16(v, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
- /* Verify we had enough resources to assign the vector */
- v = ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
- if (v == VIRTIO_MSI_NO_VECTOR) {
- err = -EBUSY;
- goto error;
- }
-
- if (!per_vq_vectors) {
- /* Shared vector for all VQs */
- v = vp_dev->msix_used_vectors;
- snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
- "%s-virtqueues", name);
- err = request_irq(vp_dev->msix_entries[v].vector,
- vp_vring_interrupt, 0, vp_dev->msix_names[v],
- vp_dev);
- if (err)
- goto error;
- ++vp_dev->msix_used_vectors;
- }
- return 0;
-error:
- vp_free_vectors(vdev);
- return err;
-}
-
-static int vp_request_intx(struct virtio_device *vdev)
-{
- int err;
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
- err = request_irq(vp_dev->pci_dev->irq, vp_interrupt,
- IRQF_SHARED, dev_name(&vdev->dev), vp_dev);
- if (!err)
- vp_dev->intx_enabled = 1;
- return err;
-}
-
-static struct virtqueue *setup_vq(struct virtio_device *vdev, unsigned index,
- void (*callback)(struct virtqueue *vq),
- const char *name,
- u16 msix_vec)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- struct virtio_pci_vq_info *info;
- struct virtqueue *vq;
- unsigned long flags, size;
- u16 num;
- int err;
-
- /* Select the queue we're interested in */
- iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
-
- /* Check if queue is either not available or already active. */
- num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
- if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
- return ERR_PTR(-ENOENT);
-
- /* allocate and fill out our structure the represents an active
- * queue */
- info = kmalloc(sizeof(struct virtio_pci_vq_info), GFP_KERNEL);
- if (!info)
- return ERR_PTR(-ENOMEM);
-
- info->num = num;
- info->msix_vector = msix_vec;
-
- size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
- info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
- if (info->queue == NULL) {
- err = -ENOMEM;
- goto out_info;
- }
-
- /* activate the queue */
- iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,
- vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
-
- /* create the vring */
- vq = vring_new_virtqueue(index, info->num, VIRTIO_PCI_VRING_ALIGN, vdev,
- true, info->queue, vp_notify, callback, name);
- if (!vq) {
- err = -ENOMEM;
- goto out_activate_queue;
- }
-
- vq->priv = info;
- info->vq = vq;
-
- if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
- iowrite16(msix_vec, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
- msix_vec = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
- if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
- err = -EBUSY;
- goto out_assign;
- }
- }
-
- if (callback) {
- spin_lock_irqsave(&vp_dev->lock, flags);
- list_add(&info->node, &vp_dev->virtqueues);
- spin_unlock_irqrestore(&vp_dev->lock, flags);
- } else {
- INIT_LIST_HEAD(&info->node);
- }
-
- return vq;
-
-out_assign:
- vring_del_virtqueue(vq);
-out_activate_queue:
- iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
- free_pages_exact(info->queue, size);
-out_info:
- kfree(info);
- return ERR_PTR(err);
-}
-
-static void vp_del_vq(struct virtqueue *vq)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
- struct virtio_pci_vq_info *info = vq->priv;
- unsigned long flags, size;
-
- spin_lock_irqsave(&vp_dev->lock, flags);
- list_del(&info->node);
- spin_unlock_irqrestore(&vp_dev->lock, flags);
-
- iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
-
- if (vp_dev->msix_enabled) {
- iowrite16(VIRTIO_MSI_NO_VECTOR,
- vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
- /* Flush the write out to device */
- ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
- }
-
- vring_del_virtqueue(vq);
-
- /* Select and deactivate the queue */
- iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
-
- size = PAGE_ALIGN(vring_size(info->num, VIRTIO_PCI_VRING_ALIGN));
- free_pages_exact(info->queue, size);
- kfree(info);
-}
-
-/* the config->del_vqs() implementation */
-static void vp_del_vqs(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- struct virtqueue *vq, *n;
- struct virtio_pci_vq_info *info;
-
- list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
- info = vq->priv;
- if (vp_dev->per_vq_vectors &&
- info->msix_vector != VIRTIO_MSI_NO_VECTOR)
- free_irq(vp_dev->msix_entries[info->msix_vector].vector,
- vq);
- vp_del_vq(vq);
- }
- vp_dev->per_vq_vectors = false;
-
- vp_free_vectors(vdev);
-}
-
-static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
- struct virtqueue *vqs[],
- vq_callback_t *callbacks[],
- const char *names[],
- bool use_msix,
- bool per_vq_vectors)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- u16 msix_vec;
- int i, err, nvectors, allocated_vectors;
-
- if (!use_msix) {
- /* Old style: one normal interrupt for change and all vqs. */
- err = vp_request_intx(vdev);
- if (err)
- goto error_request;
- } else {
- if (per_vq_vectors) {
- /* Best option: one for change interrupt, one per vq. */
- nvectors = 1;
- for (i = 0; i < nvqs; ++i)
- if (callbacks[i])
- ++nvectors;
- } else {
- /* Second best: one for change, shared for all vqs. */
- nvectors = 2;
- }
-
- err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors);
- if (err)
- goto error_request;
- }
-
- vp_dev->per_vq_vectors = per_vq_vectors;
- allocated_vectors = vp_dev->msix_used_vectors;
- for (i = 0; i < nvqs; ++i) {
- if (!names[i]) {
- vqs[i] = NULL;
- continue;
- } else if (!callbacks[i] || !vp_dev->msix_enabled)
- msix_vec = VIRTIO_MSI_NO_VECTOR;
- else if (vp_dev->per_vq_vectors)
- msix_vec = allocated_vectors++;
- else
- msix_vec = VP_MSIX_VQ_VECTOR;
- vqs[i] = setup_vq(vdev, i, callbacks[i], names[i], msix_vec);
- if (IS_ERR(vqs[i])) {
- err = PTR_ERR(vqs[i]);
- goto error_find;
- }
-
- if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR)
- continue;
-
- /* allocate per-vq irq if available and necessary */
- snprintf(vp_dev->msix_names[msix_vec],
- sizeof *vp_dev->msix_names,
- "%s-%s",
- dev_name(&vp_dev->vdev.dev), names[i]);
- err = request_irq(vp_dev->msix_entries[msix_vec].vector,
- vring_interrupt, 0,
- vp_dev->msix_names[msix_vec],
- vqs[i]);
- if (err) {
- vp_del_vq(vqs[i]);
- goto error_find;
- }
- }
- return 0;
-
-error_find:
- vp_del_vqs(vdev);
-
-error_request:
- return err;
-}
-
-/* the config->find_vqs() implementation */
-static int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
- struct virtqueue *vqs[],
- vq_callback_t *callbacks[],
- const char *names[])
-{
- int err;
-
- /* Try MSI-X with one vector per queue. */
- err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names, true, true);
- if (!err)
- return 0;
- /* Fallback: MSI-X with one vector for config, one shared for queues. */
- err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names,
- true, false);
- if (!err)
- return 0;
- /* Finally fall back to regular interrupts. */
- return vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names,
- false, false);
-}
-
-static const char *vp_bus_name(struct virtio_device *vdev)
-{
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
-
- return pci_name(vp_dev->pci_dev);
-}
-
-/* Setup the affinity for a virtqueue:
- * - force the affinity for per vq vector
- * - OR over all affinities for shared MSI
- * - ignore the affinity request if we're using INTX
- */
-static int vp_set_vq_affinity(struct virtqueue *vq, int cpu)
-{
- struct virtio_device *vdev = vq->vdev;
- struct virtio_pci_device *vp_dev = to_vp_device(vdev);
- struct virtio_pci_vq_info *info = vq->priv;
- struct cpumask *mask;
- unsigned int irq;
-
- if (!vq->callback)
- return -EINVAL;
-
- if (vp_dev->msix_enabled) {
- mask = vp_dev->msix_affinity_masks[info->msix_vector];
- irq = vp_dev->msix_entries[info->msix_vector].vector;
- if (cpu == -1)
- irq_set_affinity_hint(irq, NULL);
- else {
- cpumask_set_cpu(cpu, mask);
- irq_set_affinity_hint(irq, mask);
- }
- }
- return 0;
-}
-
-static const struct virtio_config_ops virtio_pci_config_ops = {
- .get = vp_get,
- .set = vp_set,
- .get_status = vp_get_status,
- .set_status = vp_set_status,
- .reset = vp_reset,
- .find_vqs = vp_find_vqs,
- .del_vqs = vp_del_vqs,
- .get_features = vp_get_features,
- .finalize_features = vp_finalize_features,
- .bus_name = vp_bus_name,
- .set_vq_affinity = vp_set_vq_affinity,
-};
-
-static void virtio_pci_release_dev(struct device *_d)
-{
- /*
- * No need for a release method as we allocate/free
- * all devices together with the pci devices.
- * Provide an empty one to avoid getting a warning from core.
- */
-}
-
-/* the PCI probing function */
-static int virtio_pci_probe(struct pci_dev *pci_dev,
- const struct pci_device_id *id)
-{
- struct virtio_pci_device *vp_dev;
- int err;
-
- /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
- if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)
- return -ENODEV;
-
- if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION) {
- printk(KERN_ERR "virtio_pci: expected ABI version %d, got %d\n",
- VIRTIO_PCI_ABI_VERSION, pci_dev->revision);
- return -ENODEV;
- }
-
- /* allocate our structure and fill it out */
- vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
- if (vp_dev == NULL)
- return -ENOMEM;
-
- vp_dev->vdev.dev.parent = &pci_dev->dev;
- vp_dev->vdev.dev.release = virtio_pci_release_dev;
- vp_dev->vdev.config = &virtio_pci_config_ops;
- vp_dev->pci_dev = pci_dev;
- INIT_LIST_HEAD(&vp_dev->virtqueues);
- spin_lock_init(&vp_dev->lock);
-
- /* Disable MSI/MSIX to bring device to a known good state. */
- pci_msi_off(pci_dev);
-
- /* enable the device */
- err = pci_enable_device(pci_dev);
- if (err)
- goto out;
-
- err = pci_request_regions(pci_dev, "virtio-pci");
- if (err)
- goto out_enable_device;
-
- vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0);
- if (vp_dev->ioaddr == NULL) {
- err = -ENOMEM;
- goto out_req_regions;
- }
-
- pci_set_drvdata(pci_dev, vp_dev);
- pci_set_master(pci_dev);
-
- /* we use the subsystem vendor/device id as the virtio vendor/device
- * id. this allows us to use the same PCI vendor/device id for all
- * virtio devices and to identify the particular virtio driver by
- * the subsystem ids */
- vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
- vp_dev->vdev.id.device = pci_dev->subsystem_device;
-
- /* finally register the virtio device */
- err = register_virtio_device(&vp_dev->vdev);
- if (err)
- goto out_set_drvdata;
-
- return 0;
-
-out_set_drvdata:
- pci_iounmap(pci_dev, vp_dev->ioaddr);
-out_req_regions:
- pci_release_regions(pci_dev);
-out_enable_device:
- pci_disable_device(pci_dev);
-out:
- kfree(vp_dev);
- return err;
-}
-
-static void virtio_pci_remove(struct pci_dev *pci_dev)
-{
- struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
-
- unregister_virtio_device(&vp_dev->vdev);
-
- vp_del_vqs(&vp_dev->vdev);
- pci_iounmap(pci_dev, vp_dev->ioaddr);
- pci_release_regions(pci_dev);
- pci_disable_device(pci_dev);
- kfree(vp_dev);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int virtio_pci_freeze(struct device *dev)
-{
- struct pci_dev *pci_dev = to_pci_dev(dev);
- struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
- int ret;
-
- ret = virtio_device_freeze(&vp_dev->vdev);
-
- if (!ret)
- pci_disable_device(pci_dev);
- return ret;
-}
-
-static int virtio_pci_restore(struct device *dev)
-{
- struct pci_dev *pci_dev = to_pci_dev(dev);
- struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
- int ret;
-
- ret = pci_enable_device(pci_dev);
- if (ret)
- return ret;
-
- pci_set_master(pci_dev);
- return virtio_device_restore(&vp_dev->vdev);
-}
-
-static const struct dev_pm_ops virtio_pci_pm_ops = {
- SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore)
-};
-#endif
-
-static struct pci_driver virtio_pci_driver = {
- .name = "virtio-pci",
- .id_table = virtio_pci_id_table,
- .probe = virtio_pci_probe,
- .remove = virtio_pci_remove,
-#ifdef CONFIG_PM_SLEEP
- .driver.pm = &virtio_pci_pm_ops,
-#endif
-};
-
-module_pci_driver(virtio_pci_driver);
diff --git a/drivers/virtio/virtio_pci_common.c b/drivers/virtio/virtio_pci_common.c
new file mode 100644
index 0000000..953057d
--- /dev/null
+++ b/drivers/virtio/virtio_pci_common.c
@@ -0,0 +1,464 @@
+/*
+ * Virtio PCI driver - common functionality for all device versions
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ * Copyright Red Hat, Inc. 2014
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Rusty Russell <rusty@rustcorp.com.au>
+ * Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio_pci_common.h"
+
+/* wait for pending irq handlers */
+void vp_synchronize_vectors(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ int i;
+
+ if (vp_dev->intx_enabled)
+ synchronize_irq(vp_dev->pci_dev->irq);
+
+ for (i = 0; i < vp_dev->msix_vectors; ++i)
+ synchronize_irq(vp_dev->msix_entries[i].vector);
+}
+
+/* the notify function used when creating a virt queue */
+bool vp_notify(struct virtqueue *vq)
+{
+ /* we write the queue's selector into the notification register to
+ * signal the other end */
+ iowrite16(vq->index, (void __iomem *)vq->priv);
+ return true;
+}
+
+/* Handle a configuration change: Tell driver if it wants to know. */
+static irqreturn_t vp_config_changed(int irq, void *opaque)
+{
+ struct virtio_pci_device *vp_dev = opaque;
+
+ virtio_config_changed(&vp_dev->vdev);
+ return IRQ_HANDLED;
+}
+
+/* Notify all virtqueues on an interrupt. */
+static irqreturn_t vp_vring_interrupt(int irq, void *opaque)
+{
+ struct virtio_pci_device *vp_dev = opaque;
+ struct virtio_pci_vq_info *info;
+ irqreturn_t ret = IRQ_NONE;
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp_dev->lock, flags);
+ list_for_each_entry(info, &vp_dev->virtqueues, node) {
+ if (vring_interrupt(irq, info->vq) == IRQ_HANDLED)
+ ret = IRQ_HANDLED;
+ }
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+ return ret;
+}
+
+/* A small wrapper to also acknowledge the interrupt when it's handled.
+ * I really need an EIO hook for the vring so I can ack the interrupt once we
+ * know that we'll be handling the IRQ but before we invoke the callback since
+ * the callback may notify the host which results in the host attempting to
+ * raise an interrupt that we would then mask once we acknowledged the
+ * interrupt. */
+static irqreturn_t vp_interrupt(int irq, void *opaque)
+{
+ struct virtio_pci_device *vp_dev = opaque;
+ u8 isr;
+
+ /* reading the ISR has the effect of also clearing it so it's very
+ * important to save off the value. */
+ isr = ioread8(vp_dev->isr);
+
+ /* It's definitely not us if the ISR was not high */
+ if (!isr)
+ return IRQ_NONE;
+
+ /* Configuration change? Tell driver if it wants to know. */
+ if (isr & VIRTIO_PCI_ISR_CONFIG)
+ vp_config_changed(irq, opaque);
+
+ return vp_vring_interrupt(irq, opaque);
+}
+
+static void vp_free_vectors(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ int i;
+
+ if (vp_dev->intx_enabled) {
+ free_irq(vp_dev->pci_dev->irq, vp_dev);
+ vp_dev->intx_enabled = 0;
+ }
+
+ for (i = 0; i < vp_dev->msix_used_vectors; ++i)
+ free_irq(vp_dev->msix_entries[i].vector, vp_dev);
+
+ for (i = 0; i < vp_dev->msix_vectors; i++)
+ if (vp_dev->msix_affinity_masks[i])
+ free_cpumask_var(vp_dev->msix_affinity_masks[i]);
+
+ if (vp_dev->msix_enabled) {
+ /* Disable the vector used for configuration */
+ vp_dev->config_vector(vp_dev, VIRTIO_MSI_NO_VECTOR);
+
+ pci_disable_msix(vp_dev->pci_dev);
+ vp_dev->msix_enabled = 0;
+ }
+
+ vp_dev->msix_vectors = 0;
+ vp_dev->msix_used_vectors = 0;
+ kfree(vp_dev->msix_names);
+ vp_dev->msix_names = NULL;
+ kfree(vp_dev->msix_entries);
+ vp_dev->msix_entries = NULL;
+ kfree(vp_dev->msix_affinity_masks);
+ vp_dev->msix_affinity_masks = NULL;
+}
+
+static int vp_request_msix_vectors(struct virtio_device *vdev, int nvectors,
+ bool per_vq_vectors)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ const char *name = dev_name(&vp_dev->vdev.dev);
+ unsigned i, v;
+ int err = -ENOMEM;
+
+ vp_dev->msix_vectors = nvectors;
+
+ vp_dev->msix_entries = kmalloc(nvectors * sizeof *vp_dev->msix_entries,
+ GFP_KERNEL);
+ if (!vp_dev->msix_entries)
+ goto error;
+ vp_dev->msix_names = kmalloc(nvectors * sizeof *vp_dev->msix_names,
+ GFP_KERNEL);
+ if (!vp_dev->msix_names)
+ goto error;
+ vp_dev->msix_affinity_masks
+ = kzalloc(nvectors * sizeof *vp_dev->msix_affinity_masks,
+ GFP_KERNEL);
+ if (!vp_dev->msix_affinity_masks)
+ goto error;
+ for (i = 0; i < nvectors; ++i)
+ if (!alloc_cpumask_var(&vp_dev->msix_affinity_masks[i],
+ GFP_KERNEL))
+ goto error;
+
+ for (i = 0; i < nvectors; ++i)
+ vp_dev->msix_entries[i].entry = i;
+
+ err = pci_enable_msix_exact(vp_dev->pci_dev,
+ vp_dev->msix_entries, nvectors);
+ if (err)
+ goto error;
+ vp_dev->msix_enabled = 1;
+
+ /* Set the vector used for configuration */
+ v = vp_dev->msix_used_vectors;
+ snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+ "%s-config", name);
+ err = request_irq(vp_dev->msix_entries[v].vector,
+ vp_config_changed, 0, vp_dev->msix_names[v],
+ vp_dev);
+ if (err)
+ goto error;
+ ++vp_dev->msix_used_vectors;
+
+ v = vp_dev->config_vector(vp_dev, v);
+ /* Verify we had enough resources to assign the vector */
+ if (v == VIRTIO_MSI_NO_VECTOR) {
+ err = -EBUSY;
+ goto error;
+ }
+
+ if (!per_vq_vectors) {
+ /* Shared vector for all VQs */
+ v = vp_dev->msix_used_vectors;
+ snprintf(vp_dev->msix_names[v], sizeof *vp_dev->msix_names,
+ "%s-virtqueues", name);
+ err = request_irq(vp_dev->msix_entries[v].vector,
+ vp_vring_interrupt, 0, vp_dev->msix_names[v],
+ vp_dev);
+ if (err)
+ goto error;
+ ++vp_dev->msix_used_vectors;
+ }
+ return 0;
+error:
+ vp_free_vectors(vdev);
+ return err;
+}
+
+static int vp_request_intx(struct virtio_device *vdev)
+{
+ int err;
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ err = request_irq(vp_dev->pci_dev->irq, vp_interrupt,
+ IRQF_SHARED, dev_name(&vdev->dev), vp_dev);
+ if (!err)
+ vp_dev->intx_enabled = 1;
+ return err;
+}
+
+static struct virtqueue *vp_setup_vq(struct virtio_device *vdev, unsigned index,
+ void (*callback)(struct virtqueue *vq),
+ const char *name,
+ u16 msix_vec)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_vq_info *info = kmalloc(sizeof *info, GFP_KERNEL);
+ struct virtqueue *vq;
+ unsigned long flags;
+
+ /* fill out our structure that represents an active queue */
+ if (!info)
+ return ERR_PTR(-ENOMEM);
+
+ vq = vp_dev->setup_vq(vp_dev, info, index, callback, name, msix_vec);
+ if (IS_ERR(vq))
+ goto out_info;
+
+ info->vq = vq;
+ if (callback) {
+ spin_lock_irqsave(&vp_dev->lock, flags);
+ list_add(&info->node, &vp_dev->virtqueues);
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
+ } else {
+ INIT_LIST_HEAD(&info->node);
+ }
+
+ vp_dev->vqs[index] = info;
+ return vq;
+
+out_info:
+ kfree(info);
+ return vq;
+}
+
+static void vp_del_vq(struct virtqueue *vq)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+ struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
+ unsigned long flags;
+
+ spin_lock_irqsave(&vp_dev->lock, flags);
+ list_del(&info->node);
+ spin_unlock_irqrestore(&vp_dev->lock, flags);
+
+ vp_dev->del_vq(info);
+ kfree(info);
+}
+
+/* the config->del_vqs() implementation */
+void vp_del_vqs(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtqueue *vq, *n;
+ struct virtio_pci_vq_info *info;
+
+ list_for_each_entry_safe(vq, n, &vdev->vqs, list) {
+ info = vp_dev->vqs[vq->index];
+ if (vp_dev->per_vq_vectors &&
+ info->msix_vector != VIRTIO_MSI_NO_VECTOR)
+ free_irq(vp_dev->msix_entries[info->msix_vector].vector,
+ vq);
+ vp_del_vq(vq);
+ }
+ vp_dev->per_vq_vectors = false;
+
+ vp_free_vectors(vdev);
+ kfree(vp_dev->vqs);
+}
+
+static int vp_try_to_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[],
+ bool use_msix,
+ bool per_vq_vectors)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ u16 msix_vec;
+ int i, err, nvectors, allocated_vectors;
+
+ vp_dev->vqs = kmalloc(nvqs * sizeof *vp_dev->vqs, GFP_KERNEL);
+ if (!vp_dev->vqs)
+ return -ENOMEM;
+
+ if (!use_msix) {
+ /* Old style: one normal interrupt for change and all vqs. */
+ err = vp_request_intx(vdev);
+ if (err)
+ goto error_find;
+ } else {
+ if (per_vq_vectors) {
+ /* Best option: one for change interrupt, one per vq. */
+ nvectors = 1;
+ for (i = 0; i < nvqs; ++i)
+ if (callbacks[i])
+ ++nvectors;
+ } else {
+ /* Second best: one for change, shared for all vqs. */
+ nvectors = 2;
+ }
+
+ err = vp_request_msix_vectors(vdev, nvectors, per_vq_vectors);
+ if (err)
+ goto error_find;
+ }
+
+ vp_dev->per_vq_vectors = per_vq_vectors;
+ allocated_vectors = vp_dev->msix_used_vectors;
+ for (i = 0; i < nvqs; ++i) {
+ if (!names[i]) {
+ vqs[i] = NULL;
+ continue;
+ } else if (!callbacks[i] || !vp_dev->msix_enabled)
+ msix_vec = VIRTIO_MSI_NO_VECTOR;
+ else if (vp_dev->per_vq_vectors)
+ msix_vec = allocated_vectors++;
+ else
+ msix_vec = VP_MSIX_VQ_VECTOR;
+ vqs[i] = vp_setup_vq(vdev, i, callbacks[i], names[i], msix_vec);
+ if (IS_ERR(vqs[i])) {
+ err = PTR_ERR(vqs[i]);
+ goto error_find;
+ }
+
+ if (!vp_dev->per_vq_vectors || msix_vec == VIRTIO_MSI_NO_VECTOR)
+ continue;
+
+ /* allocate per-vq irq if available and necessary */
+ snprintf(vp_dev->msix_names[msix_vec],
+ sizeof *vp_dev->msix_names,
+ "%s-%s",
+ dev_name(&vp_dev->vdev.dev), names[i]);
+ err = request_irq(vp_dev->msix_entries[msix_vec].vector,
+ vring_interrupt, 0,
+ vp_dev->msix_names[msix_vec],
+ vqs[i]);
+ if (err) {
+ vp_del_vq(vqs[i]);
+ goto error_find;
+ }
+ }
+ return 0;
+
+error_find:
+ vp_del_vqs(vdev);
+ return err;
+}
+
+/* the config->find_vqs() implementation */
+int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[])
+{
+ int err;
+
+ /* Try MSI-X with one vector per queue. */
+ err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names, true, true);
+ if (!err)
+ return 0;
+ /* Fallback: MSI-X with one vector for config, one shared for queues. */
+ err = vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names,
+ true, false);
+ if (!err)
+ return 0;
+ /* Finally fall back to regular interrupts. */
+ return vp_try_to_find_vqs(vdev, nvqs, vqs, callbacks, names,
+ false, false);
+}
+
+const char *vp_bus_name(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ return pci_name(vp_dev->pci_dev);
+}
+
+/* Setup the affinity for a virtqueue:
+ * - force the affinity for per vq vector
+ * - OR over all affinities for shared MSI
+ * - ignore the affinity request if we're using INTX
+ */
+int vp_set_vq_affinity(struct virtqueue *vq, int cpu)
+{
+ struct virtio_device *vdev = vq->vdev;
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ struct virtio_pci_vq_info *info = vp_dev->vqs[vq->index];
+ struct cpumask *mask;
+ unsigned int irq;
+
+ if (!vq->callback)
+ return -EINVAL;
+
+ if (vp_dev->msix_enabled) {
+ mask = vp_dev->msix_affinity_masks[info->msix_vector];
+ irq = vp_dev->msix_entries[info->msix_vector].vector;
+ if (cpu == -1)
+ irq_set_affinity_hint(irq, NULL);
+ else {
+ cpumask_set_cpu(cpu, mask);
+ irq_set_affinity_hint(irq, mask);
+ }
+ }
+ return 0;
+}
+
+void virtio_pci_release_dev(struct device *_d)
+{
+ /*
+ * No need for a release method as we allocate/free
+ * all devices together with the pci devices.
+ * Provide an empty one to avoid getting a warning from core.
+ */
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int virtio_pci_freeze(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+ int ret;
+
+ ret = virtio_device_freeze(&vp_dev->vdev);
+
+ if (!ret)
+ pci_disable_device(pci_dev);
+ return ret;
+}
+
+static int virtio_pci_restore(struct device *dev)
+{
+ struct pci_dev *pci_dev = to_pci_dev(dev);
+ struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+ int ret;
+
+ ret = pci_enable_device(pci_dev);
+ if (ret)
+ return ret;
+
+ pci_set_master(pci_dev);
+ return virtio_device_restore(&vp_dev->vdev);
+}
+
+const struct dev_pm_ops virtio_pci_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(virtio_pci_freeze, virtio_pci_restore)
+};
+#endif
diff --git a/drivers/virtio/virtio_pci_common.h b/drivers/virtio/virtio_pci_common.h
new file mode 100644
index 0000000..d840dad
--- /dev/null
+++ b/drivers/virtio/virtio_pci_common.h
@@ -0,0 +1,136 @@
+#ifndef _DRIVERS_VIRTIO_VIRTIO_PCI_COMMON_H
+#define _DRIVERS_VIRTIO_VIRTIO_PCI_COMMON_H
+/*
+ * Virtio PCI driver - APIs for common functionality for all device versions
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ * Copyright Red Hat, Inc. 2014
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Rusty Russell <rusty@rustcorp.com.au>
+ * Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/slab.h>
+#include <linux/interrupt.h>
+#include <linux/virtio.h>
+#include <linux/virtio_config.h>
+#include <linux/virtio_ring.h>
+#define VIRTIO_PCI_NO_LEGACY
+#include <linux/virtio_pci.h>
+#include <linux/highmem.h>
+#include <linux/spinlock.h>
+
+struct virtio_pci_vq_info {
+ /* the actual virtqueue */
+ struct virtqueue *vq;
+
+ /* the number of entries in the queue */
+ int num;
+
+ /* the virtual address of the ring queue */
+ void *queue;
+
+ /* the list node for the virtqueues list */
+ struct list_head node;
+
+ /* MSI-X vector (or none) */
+ unsigned msix_vector;
+};
+
+/* Our device structure */
+struct virtio_pci_device {
+ struct virtio_device vdev;
+ struct pci_dev *pci_dev;
+
+ /* the IO mapping for the PCI config space */
+ void __iomem *ioaddr;
+
+ /* the IO mapping for ISR operation */
+ void __iomem *isr;
+
+ /* a list of queues so we can dispatch IRQs */
+ spinlock_t lock;
+ struct list_head virtqueues;
+
+ /* array of all queues for house-keeping */
+ struct virtio_pci_vq_info **vqs;
+
+ /* MSI-X support */
+ int msix_enabled;
+ int intx_enabled;
+ struct msix_entry *msix_entries;
+ cpumask_var_t *msix_affinity_masks;
+ /* Name strings for interrupts. This size should be enough,
+ * and I'm too lazy to allocate each name separately. */
+ char (*msix_names)[256];
+ /* Number of available vectors */
+ unsigned msix_vectors;
+ /* Vectors allocated, excluding per-vq vectors if any */
+ unsigned msix_used_vectors;
+
+ /* Whether we have vector per vq */
+ bool per_vq_vectors;
+
+ struct virtqueue *(*setup_vq)(struct virtio_pci_device *vp_dev,
+ struct virtio_pci_vq_info *info,
+ unsigned idx,
+ void (*callback)(struct virtqueue *vq),
+ const char *name,
+ u16 msix_vec);
+ void (*del_vq)(struct virtio_pci_vq_info *info);
+
+ u16 (*config_vector)(struct virtio_pci_device *vp_dev, u16 vector);
+};
+
+/* Constants for MSI-X */
+/* Use first vector for configuration changes, second and the rest for
+ * virtqueues Thus, we need at least 2 vectors for MSI. */
+enum {
+ VP_MSIX_CONFIG_VECTOR = 0,
+ VP_MSIX_VQ_VECTOR = 1,
+};
+
+/* Convert a generic virtio device to our structure */
+static struct virtio_pci_device *to_vp_device(struct virtio_device *vdev)
+{
+ return container_of(vdev, struct virtio_pci_device, vdev);
+}
+
+/* wait for pending irq handlers */
+void vp_synchronize_vectors(struct virtio_device *vdev);
+/* the notify function used when creating a virt queue */
+bool vp_notify(struct virtqueue *vq);
+/* the config->del_vqs() implementation */
+void vp_del_vqs(struct virtio_device *vdev);
+/* the config->find_vqs() implementation */
+int vp_find_vqs(struct virtio_device *vdev, unsigned nvqs,
+ struct virtqueue *vqs[],
+ vq_callback_t *callbacks[],
+ const char *names[]);
+const char *vp_bus_name(struct virtio_device *vdev);
+
+/* Setup the affinity for a virtqueue:
+ * - force the affinity for per vq vector
+ * - OR over all affinities for shared MSI
+ * - ignore the affinity request if we're using INTX
+ */
+int vp_set_vq_affinity(struct virtqueue *vq, int cpu);
+void virtio_pci_release_dev(struct device *);
+
+#ifdef CONFIG_PM_SLEEP
+extern const struct dev_pm_ops virtio_pci_pm_ops;
+#endif
+
+#endif
diff --git a/drivers/virtio/virtio_pci_legacy.c b/drivers/virtio/virtio_pci_legacy.c
new file mode 100644
index 0000000..2588252
--- /dev/null
+++ b/drivers/virtio/virtio_pci_legacy.c
@@ -0,0 +1,326 @@
+/*
+ * Virtio PCI driver - legacy device support
+ *
+ * This module allows virtio devices to be used over a virtual PCI device.
+ * This can be used with QEMU based VMMs like KVM or Xen.
+ *
+ * Copyright IBM Corp. 2007
+ * Copyright Red Hat, Inc. 2014
+ *
+ * Authors:
+ * Anthony Liguori <aliguori@us.ibm.com>
+ * Rusty Russell <rusty@rustcorp.com.au>
+ * Michael S. Tsirkin <mst@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+
+#include "virtio_pci_common.h"
+
+/* Qumranet donated their vendor ID for devices 0x1000 thru 0x10FF. */
+static const struct pci_device_id virtio_pci_id_table[] = {
+ { PCI_DEVICE(0x1af4, PCI_ANY_ID) },
+ { 0 }
+};
+
+MODULE_DEVICE_TABLE(pci, virtio_pci_id_table);
+
+/* virtio config->get_features() implementation */
+static u64 vp_get_features(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ /* When someone needs more than 32 feature bits, we'll need to
+ * steal a bit to indicate that the rest are somewhere else. */
+ return ioread32(vp_dev->ioaddr + VIRTIO_PCI_HOST_FEATURES);
+}
+
+/* virtio config->finalize_features() implementation */
+static int vp_finalize_features(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+
+ /* Give virtio_ring a chance to accept features. */
+ vring_transport_features(vdev);
+
+ /* Make sure we don't have any features > 32 bits! */
+ BUG_ON((u32)vdev->features != vdev->features);
+
+ /* We only support 32 feature bits. */
+ iowrite32(vdev->features, vp_dev->ioaddr + VIRTIO_PCI_GUEST_FEATURES);
+
+ return 0;
+}
+
+/* virtio config->get() implementation */
+static void vp_get(struct virtio_device *vdev, unsigned offset,
+ void *buf, unsigned len)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ void __iomem *ioaddr = vp_dev->ioaddr +
+ VIRTIO_PCI_CONFIG(vp_dev) + offset;
+ u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ ptr[i] = ioread8(ioaddr + i);
+}
+
+/* the config->set() implementation. it's symmetric to the config->get()
+ * implementation */
+static void vp_set(struct virtio_device *vdev, unsigned offset,
+ const void *buf, unsigned len)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ void __iomem *ioaddr = vp_dev->ioaddr +
+ VIRTIO_PCI_CONFIG(vp_dev) + offset;
+ const u8 *ptr = buf;
+ int i;
+
+ for (i = 0; i < len; i++)
+ iowrite8(ptr[i], ioaddr + i);
+}
+
+/* config->{get,set}_status() implementations */
+static u8 vp_get_status(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ return ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static void vp_set_status(struct virtio_device *vdev, u8 status)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ /* We should never be setting status to 0. */
+ BUG_ON(status == 0);
+ iowrite8(status, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+}
+
+static void vp_reset(struct virtio_device *vdev)
+{
+ struct virtio_pci_device *vp_dev = to_vp_device(vdev);
+ /* 0 status means a reset. */
+ iowrite8(0, vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ /* Flush out the status write, and flush in device writes,
+ * including MSi-X interrupts, if any. */
+ ioread8(vp_dev->ioaddr + VIRTIO_PCI_STATUS);
+ /* Flush pending VQ/configuration callbacks. */
+ vp_synchronize_vectors(vdev);
+}
+
+static u16 vp_config_vector(struct virtio_pci_device *vp_dev, u16 vector)
+{
+ /* Setup the vector used for configuration events */
+ iowrite16(vector, vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+ /* Verify we had enough resources to assign the vector */
+ /* Will also flush the write out to device */
+ return ioread16(vp_dev->ioaddr + VIRTIO_MSI_CONFIG_VECTOR);
+}
+
+static struct virtqueue *setup_vq(struct virtio_pci_device *vp_dev,
+ struct virtio_pci_vq_info *info,
+ unsigned index,
+ void (*callback)(struct virtqueue *vq),
+ const char *name,
+ u16 msix_vec)
+{
+ struct virtqueue *vq;
+ unsigned long size;
+ u16 num;
+ int err;
+
+ /* Select the queue we're interested in */
+ iowrite16(index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ /* Check if queue is either not available or already active. */
+ num = ioread16(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NUM);
+ if (!num || ioread32(vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN))
+ return ERR_PTR(-ENOENT);
+
+ info->num = num;
+ info->msix_vector = msix_vec;
+
+ size = PAGE_ALIGN(vring_size(num, VIRTIO_PCI_VRING_ALIGN));
+ info->queue = alloc_pages_exact(size, GFP_KERNEL|__GFP_ZERO);
+ if (info->queue == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ /* activate the queue */
+ iowrite32(virt_to_phys(info->queue) >> VIRTIO_PCI_QUEUE_ADDR_SHIFT,
+ vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ /* create the vring */
+ vq = vring_new_virtqueue(index, info->num,
+ VIRTIO_PCI_VRING_ALIGN, &vp_dev->vdev,
+ true, info->queue, vp_notify, callback, name);
+ if (!vq) {
+ err = -ENOMEM;
+ goto out_activate_queue;
+ }
+
+ vq->priv = (void __force *)vp_dev->ioaddr + VIRTIO_PCI_QUEUE_NOTIFY;
+
+ if (msix_vec != VIRTIO_MSI_NO_VECTOR) {
+ iowrite16(msix_vec, vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+ msix_vec = ioread16(vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+ if (msix_vec == VIRTIO_MSI_NO_VECTOR) {
+ err = -EBUSY;
+ goto out_assign;
+ }
+ }
+
+ return vq;
+
+out_assign:
+ vring_del_virtqueue(vq);
+out_activate_queue:
+ iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+ free_pages_exact(info->queue, size);
+ return ERR_PTR(err);
+}
+
+static void del_vq(struct virtio_pci_vq_info *info)
+{
+ struct virtqueue *vq = info->vq;
+ struct virtio_pci_device *vp_dev = to_vp_device(vq->vdev);
+ unsigned long size;
+
+ iowrite16(vq->index, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_SEL);
+
+ if (vp_dev->msix_enabled) {
+ iowrite16(VIRTIO_MSI_NO_VECTOR,
+ vp_dev->ioaddr + VIRTIO_MSI_QUEUE_VECTOR);
+ /* Flush the write out to device */
+ ioread8(vp_dev->ioaddr + VIRTIO_PCI_ISR);
+ }
+
+ vring_del_virtqueue(vq);
+
+ /* Select and deactivate the queue */
+ iowrite32(0, vp_dev->ioaddr + VIRTIO_PCI_QUEUE_PFN);
+
+ size = PAGE_ALIGN(vring_size(info->num, VIRTIO_PCI_VRING_ALIGN));
+ free_pages_exact(info->queue, size);
+}
+
+static const struct virtio_config_ops virtio_pci_config_ops = {
+ .get = vp_get,
+ .set = vp_set,
+ .get_status = vp_get_status,
+ .set_status = vp_set_status,
+ .reset = vp_reset,
+ .find_vqs = vp_find_vqs,
+ .del_vqs = vp_del_vqs,
+ .get_features = vp_get_features,
+ .finalize_features = vp_finalize_features,
+ .bus_name = vp_bus_name,
+ .set_vq_affinity = vp_set_vq_affinity,
+};
+
+/* the PCI probing function */
+static int virtio_pci_probe(struct pci_dev *pci_dev,
+ const struct pci_device_id *id)
+{
+ struct virtio_pci_device *vp_dev;
+ int err;
+
+ /* We only own devices >= 0x1000 and <= 0x103f: leave the rest. */
+ if (pci_dev->device < 0x1000 || pci_dev->device > 0x103f)
+ return -ENODEV;
+
+ if (pci_dev->revision != VIRTIO_PCI_ABI_VERSION) {
+ printk(KERN_ERR "virtio_pci: expected ABI version %d, got %d\n",
+ VIRTIO_PCI_ABI_VERSION, pci_dev->revision);
+ return -ENODEV;
+ }
+
+ /* allocate our structure and fill it out */
+ vp_dev = kzalloc(sizeof(struct virtio_pci_device), GFP_KERNEL);
+ if (vp_dev == NULL)
+ return -ENOMEM;
+
+ vp_dev->vdev.dev.parent = &pci_dev->dev;
+ vp_dev->vdev.dev.release = virtio_pci_release_dev;
+ vp_dev->vdev.config = &virtio_pci_config_ops;
+ vp_dev->pci_dev = pci_dev;
+ INIT_LIST_HEAD(&vp_dev->virtqueues);
+ spin_lock_init(&vp_dev->lock);
+
+ /* Disable MSI/MSIX to bring device to a known good state. */
+ pci_msi_off(pci_dev);
+
+ /* enable the device */
+ err = pci_enable_device(pci_dev);
+ if (err)
+ goto out;
+
+ err = pci_request_regions(pci_dev, "virtio-pci");
+ if (err)
+ goto out_enable_device;
+
+ vp_dev->ioaddr = pci_iomap(pci_dev, 0, 0);
+ if (vp_dev->ioaddr == NULL) {
+ err = -ENOMEM;
+ goto out_req_regions;
+ }
+
+ vp_dev->isr = vp_dev->ioaddr + VIRTIO_PCI_ISR;
+
+ pci_set_drvdata(pci_dev, vp_dev);
+ pci_set_master(pci_dev);
+
+ /* we use the subsystem vendor/device id as the virtio vendor/device
+ * id. this allows us to use the same PCI vendor/device id for all
+ * virtio devices and to identify the particular virtio driver by
+ * the subsystem ids */
+ vp_dev->vdev.id.vendor = pci_dev->subsystem_vendor;
+ vp_dev->vdev.id.device = pci_dev->subsystem_device;
+
+ vp_dev->config_vector = vp_config_vector;
+ vp_dev->setup_vq = setup_vq;
+ vp_dev->del_vq = del_vq;
+
+ /* finally register the virtio device */
+ err = register_virtio_device(&vp_dev->vdev);
+ if (err)
+ goto out_set_drvdata;
+
+ return 0;
+
+out_set_drvdata:
+ pci_iounmap(pci_dev, vp_dev->ioaddr);
+out_req_regions:
+ pci_release_regions(pci_dev);
+out_enable_device:
+ pci_disable_device(pci_dev);
+out:
+ kfree(vp_dev);
+ return err;
+}
+
+static void virtio_pci_remove(struct pci_dev *pci_dev)
+{
+ struct virtio_pci_device *vp_dev = pci_get_drvdata(pci_dev);
+
+ unregister_virtio_device(&vp_dev->vdev);
+
+ vp_del_vqs(&vp_dev->vdev);
+ pci_iounmap(pci_dev, vp_dev->ioaddr);
+ pci_release_regions(pci_dev);
+ pci_disable_device(pci_dev);
+ kfree(vp_dev);
+}
+
+static struct pci_driver virtio_pci_driver = {
+ .name = "virtio-pci",
+ .id_table = virtio_pci_id_table,
+ .probe = virtio_pci_probe,
+ .remove = virtio_pci_remove,
+#ifdef CONFIG_PM_SLEEP
+ .driver.pm = &virtio_pci_pm_ops,
+#endif
+};
+
+module_pci_driver(virtio_pci_driver);
diff --git a/drivers/virtio/virtio_ring.c b/drivers/virtio/virtio_ring.c
index 3b1f89b..00ec6b3 100644
--- a/drivers/virtio/virtio_ring.c
+++ b/drivers/virtio/virtio_ring.c
@@ -99,7 +99,8 @@ struct vring_virtqueue
#define to_vvq(_vq) container_of(_vq, struct vring_virtqueue, vq)
-static struct vring_desc *alloc_indirect(unsigned int total_sg, gfp_t gfp)
+static struct vring_desc *alloc_indirect(struct virtqueue *_vq,
+ unsigned int total_sg, gfp_t gfp)
{
struct vring_desc *desc;
unsigned int i;
@@ -116,7 +117,7 @@ static struct vring_desc *alloc_indirect(unsigned int total_sg, gfp_t gfp)
return NULL;
for (i = 0; i < total_sg; i++)
- desc[i].next = i+1;
+ desc[i].next = cpu_to_virtio16(_vq->vdev, i + 1);
return desc;
}
@@ -165,17 +166,17 @@ static inline int virtqueue_add(struct virtqueue *_vq,
/* If the host supports indirect descriptor tables, and we have multiple
* buffers, then go indirect. FIXME: tune this threshold */
if (vq->indirect && total_sg > 1 && vq->vq.num_free)
- desc = alloc_indirect(total_sg, gfp);
+ desc = alloc_indirect(_vq, total_sg, gfp);
else
desc = NULL;
if (desc) {
/* Use a single buffer which doesn't continue */
- vq->vring.desc[head].flags = VRING_DESC_F_INDIRECT;
- vq->vring.desc[head].addr = virt_to_phys(desc);
+ vq->vring.desc[head].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_INDIRECT);
+ vq->vring.desc[head].addr = cpu_to_virtio64(_vq->vdev, virt_to_phys(desc));
/* avoid kmemleak false positive (hidden by virt_to_phys) */
kmemleak_ignore(desc);
- vq->vring.desc[head].len = total_sg * sizeof(struct vring_desc);
+ vq->vring.desc[head].len = cpu_to_virtio32(_vq->vdev, total_sg * sizeof(struct vring_desc));
/* Set up rest to use this indirect table. */
i = 0;
@@ -205,28 +206,28 @@ static inline int virtqueue_add(struct virtqueue *_vq,
for (n = 0; n < out_sgs; n++) {
for (sg = sgs[n]; sg; sg = sg_next(sg)) {
- desc[i].flags = VRING_DESC_F_NEXT;
- desc[i].addr = sg_phys(sg);
- desc[i].len = sg->length;
+ desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT);
+ desc[i].addr = cpu_to_virtio64(_vq->vdev, sg_phys(sg));
+ desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length);
prev = i;
- i = desc[i].next;
+ i = virtio16_to_cpu(_vq->vdev, desc[i].next);
}
}
for (; n < (out_sgs + in_sgs); n++) {
for (sg = sgs[n]; sg; sg = sg_next(sg)) {
- desc[i].flags = VRING_DESC_F_NEXT|VRING_DESC_F_WRITE;
- desc[i].addr = sg_phys(sg);
- desc[i].len = sg->length;
+ desc[i].flags = cpu_to_virtio16(_vq->vdev, VRING_DESC_F_NEXT | VRING_DESC_F_WRITE);
+ desc[i].addr = cpu_to_virtio64(_vq->vdev, sg_phys(sg));
+ desc[i].len = cpu_to_virtio32(_vq->vdev, sg->length);
prev = i;
- i = desc[i].next;
+ i = virtio16_to_cpu(_vq->vdev, desc[i].next);
}
}
/* Last one doesn't continue. */
- desc[prev].flags &= ~VRING_DESC_F_NEXT;
+ desc[prev].flags &= cpu_to_virtio16(_vq->vdev, ~VRING_DESC_F_NEXT);
/* Update free pointer */
if (indirect)
- vq->free_head = vq->vring.desc[head].next;
+ vq->free_head = virtio16_to_cpu(_vq->vdev, vq->vring.desc[head].next);
else
vq->free_head = i;
@@ -235,13 +236,13 @@ static inline int virtqueue_add(struct virtqueue *_vq,
/* Put entry in available array (but don't update avail->idx until they
* do sync). */
- avail = (vq->vring.avail->idx & (vq->vring.num-1));
- vq->vring.avail->ring[avail] = head;
+ avail = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) & (vq->vring.num - 1);
+ vq->vring.avail->ring[avail] = cpu_to_virtio16(_vq->vdev, head);
/* Descriptors and available array need to be set before we expose the
* new available array entries. */
virtio_wmb(vq->weak_barriers);
- vq->vring.avail->idx++;
+ vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) + 1);
vq->num_added++;
/* This is very unlikely, but theoretically possible. Kick
@@ -354,8 +355,8 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
* event. */
virtio_mb(vq->weak_barriers);
- old = vq->vring.avail->idx - vq->num_added;
- new = vq->vring.avail->idx;
+ old = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->num_added;
+ new = virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx);
vq->num_added = 0;
#ifdef DEBUG
@@ -367,10 +368,10 @@ bool virtqueue_kick_prepare(struct virtqueue *_vq)
#endif
if (vq->event) {
- needs_kick = vring_need_event(vring_avail_event(&vq->vring),
+ needs_kick = vring_need_event(virtio16_to_cpu(_vq->vdev, vring_avail_event(&vq->vring)),
new, old);
} else {
- needs_kick = !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY);
+ needs_kick = !(vq->vring.used->flags & cpu_to_virtio16(_vq->vdev, VRING_USED_F_NO_NOTIFY));
}
END_USE(vq);
return needs_kick;
@@ -432,15 +433,15 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
i = head;
/* Free the indirect table */
- if (vq->vring.desc[i].flags & VRING_DESC_F_INDIRECT)
- kfree(phys_to_virt(vq->vring.desc[i].addr));
+ if (vq->vring.desc[i].flags & cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_INDIRECT))
+ kfree(phys_to_virt(virtio64_to_cpu(vq->vq.vdev, vq->vring.desc[i].addr)));
- while (vq->vring.desc[i].flags & VRING_DESC_F_NEXT) {
- i = vq->vring.desc[i].next;
+ while (vq->vring.desc[i].flags & cpu_to_virtio16(vq->vq.vdev, VRING_DESC_F_NEXT)) {
+ i = virtio16_to_cpu(vq->vq.vdev, vq->vring.desc[i].next);
vq->vq.num_free++;
}
- vq->vring.desc[i].next = vq->free_head;
+ vq->vring.desc[i].next = cpu_to_virtio16(vq->vq.vdev, vq->free_head);
vq->free_head = head;
/* Plus final descriptor */
vq->vq.num_free++;
@@ -448,7 +449,7 @@ static void detach_buf(struct vring_virtqueue *vq, unsigned int head)
static inline bool more_used(const struct vring_virtqueue *vq)
{
- return vq->last_used_idx != vq->vring.used->idx;
+ return vq->last_used_idx != virtio16_to_cpu(vq->vq.vdev, vq->vring.used->idx);
}
/**
@@ -491,8 +492,8 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
virtio_rmb(vq->weak_barriers);
last_used = (vq->last_used_idx & (vq->vring.num - 1));
- i = vq->vring.used->ring[last_used].id;
- *len = vq->vring.used->ring[last_used].len;
+ i = virtio32_to_cpu(_vq->vdev, vq->vring.used->ring[last_used].id);
+ *len = virtio32_to_cpu(_vq->vdev, vq->vring.used->ring[last_used].len);
if (unlikely(i >= vq->vring.num)) {
BAD_RING(vq, "id %u out of range\n", i);
@@ -510,8 +511,8 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
/* If we expect an interrupt for the next entry, tell host
* by writing event index and flush out the write before
* the read in the next get_buf call. */
- if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
- vring_used_event(&vq->vring) = vq->last_used_idx;
+ if (!(vq->vring.avail->flags & cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT))) {
+ vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx);
virtio_mb(vq->weak_barriers);
}
@@ -537,7 +538,7 @@ void virtqueue_disable_cb(struct virtqueue *_vq)
{
struct vring_virtqueue *vq = to_vvq(_vq);
- vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags |= cpu_to_virtio16(_vq->vdev, VRING_AVAIL_F_NO_INTERRUPT);
}
EXPORT_SYMBOL_GPL(virtqueue_disable_cb);
@@ -565,8 +566,8 @@ unsigned virtqueue_enable_cb_prepare(struct virtqueue *_vq)
/* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
* either clear the flags bit or point the event index at the next
* entry. Always do both to keep code simple. */
- vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
- vring_used_event(&vq->vring) = last_used_idx = vq->last_used_idx;
+ vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT);
+ vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, last_used_idx = vq->last_used_idx);
END_USE(vq);
return last_used_idx;
}
@@ -586,7 +587,7 @@ bool virtqueue_poll(struct virtqueue *_vq, unsigned last_used_idx)
struct vring_virtqueue *vq = to_vvq(_vq);
virtio_mb(vq->weak_barriers);
- return (u16)last_used_idx != vq->vring.used->idx;
+ return (u16)last_used_idx != virtio16_to_cpu(_vq->vdev, vq->vring.used->idx);
}
EXPORT_SYMBOL_GPL(virtqueue_poll);
@@ -633,12 +634,12 @@ bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
/* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
* either clear the flags bit or point the event index at the next
* entry. Always do both to keep code simple. */
- vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags &= cpu_to_virtio16(_vq->vdev, ~VRING_AVAIL_F_NO_INTERRUPT);
/* TODO: tune this threshold */
- bufs = (u16)(vq->vring.avail->idx - vq->last_used_idx) * 3 / 4;
- vring_used_event(&vq->vring) = vq->last_used_idx + bufs;
+ bufs = (u16)(virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - vq->last_used_idx) * 3 / 4;
+ vring_used_event(&vq->vring) = cpu_to_virtio16(_vq->vdev, vq->last_used_idx + bufs);
virtio_mb(vq->weak_barriers);
- if (unlikely((u16)(vq->vring.used->idx - vq->last_used_idx) > bufs)) {
+ if (unlikely((u16)(virtio16_to_cpu(_vq->vdev, vq->vring.used->idx) - vq->last_used_idx) > bufs)) {
END_USE(vq);
return false;
}
@@ -670,7 +671,7 @@ void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
/* detach_buf clears data, so grab it now. */
buf = vq->data[i];
detach_buf(vq, i);
- vq->vring.avail->idx--;
+ vq->vring.avail->idx = cpu_to_virtio16(_vq->vdev, virtio16_to_cpu(_vq->vdev, vq->vring.avail->idx) - 1);
END_USE(vq);
return buf;
}
@@ -747,12 +748,12 @@ struct virtqueue *vring_new_virtqueue(unsigned int index,
/* No callback? Tell other side not to bother us. */
if (!callback)
- vq->vring.avail->flags |= VRING_AVAIL_F_NO_INTERRUPT;
+ vq->vring.avail->flags |= cpu_to_virtio16(vdev, VRING_AVAIL_F_NO_INTERRUPT);
/* Put everything in free lists. */
vq->free_head = 0;
for (i = 0; i < num-1; i++) {
- vq->vring.desc[i].next = i+1;
+ vq->vring.desc[i].next = cpu_to_virtio16(vdev, i + 1);
vq->data[i] = NULL;
}
vq->data[i] = NULL;
@@ -779,9 +780,11 @@ void vring_transport_features(struct virtio_device *vdev)
break;
case VIRTIO_RING_F_EVENT_IDX:
break;
+ case VIRTIO_F_VERSION_1:
+ break;
default:
/* We don't understand this bit. */
- clear_bit(i, vdev->features);
+ __virtio_clear_bit(vdev, i);
}
}
}
@@ -826,4 +829,20 @@ void virtio_break_device(struct virtio_device *dev)
}
EXPORT_SYMBOL_GPL(virtio_break_device);
+void *virtqueue_get_avail(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ return vq->vring.avail;
+}
+EXPORT_SYMBOL_GPL(virtqueue_get_avail);
+
+void *virtqueue_get_used(struct virtqueue *_vq)
+{
+ struct vring_virtqueue *vq = to_vvq(_vq);
+
+ return vq->vring.used;
+}
+EXPORT_SYMBOL_GPL(virtqueue_get_used);
+
MODULE_LICENSE("GPL");
diff --git a/drivers/w1/masters/omap_hdq.c b/drivers/w1/masters/omap_hdq.c
index 9900e8e..03321d6 100644
--- a/drivers/w1/masters/omap_hdq.c
+++ b/drivers/w1/masters/omap_hdq.c
@@ -72,11 +72,18 @@ struct hdq_data {
static int omap_hdq_probe(struct platform_device *pdev);
static int omap_hdq_remove(struct platform_device *pdev);
+static struct of_device_id omap_hdq_dt_ids[] = {
+ { .compatible = "ti,omap3-1w" },
+ {}
+};
+MODULE_DEVICE_TABLE(of, omap_hdq_dt_ids);
+
static struct platform_driver omap_hdq_driver = {
.probe = omap_hdq_probe,
.remove = omap_hdq_remove,
.driver = {
.name = "omap_hdq",
+ .of_match_table = omap_hdq_dt_ids,
},
};
diff --git a/drivers/watchdog/Kconfig b/drivers/watchdog/Kconfig
index d0107d4..08f41ad 100644
--- a/drivers/watchdog/Kconfig
+++ b/drivers/watchdog/Kconfig
@@ -154,14 +154,14 @@ config ARM_SP805_WATCHDOG
config AT91RM9200_WATCHDOG
tristate "AT91RM9200 watchdog"
- depends on ARCH_AT91RM9200
+ depends on SOC_AT91RM9200
help
Watchdog timer embedded into AT91RM9200 chips. This will reboot your
system when the timeout is reached.
config AT91SAM9X_WATCHDOG
tristate "AT91SAM9X / AT91CAP9 watchdog"
- depends on ARCH_AT91 && !ARCH_AT91RM9200
+ depends on ARCH_AT91
select WATCHDOG_CORE
help
Watchdog timer embedded into AT91SAM9X and AT91CAP9 chips. This will
diff --git a/drivers/watchdog/orion_wdt.c b/drivers/watchdog/orion_wdt.c
index 00d0741..8cb1ff3 100644
--- a/drivers/watchdog/orion_wdt.c
+++ b/drivers/watchdog/orion_wdt.c
@@ -114,6 +114,46 @@ static int armada370_wdt_clock_init(struct platform_device *pdev,
return 0;
}
+static int armada375_wdt_clock_init(struct platform_device *pdev,
+ struct orion_watchdog *dev)
+{
+ int ret;
+
+ dev->clk = of_clk_get_by_name(pdev->dev.of_node, "fixed");
+ if (!IS_ERR(dev->clk)) {
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ clk_put(dev->clk);
+ return ret;
+ }
+
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_AXP_FIXED_ENABLE_BIT,
+ WDT_AXP_FIXED_ENABLE_BIT);
+ dev->clk_rate = clk_get_rate(dev->clk);
+
+ return 0;
+ }
+
+ /* Mandatory fallback for proper devicetree backward compatibility */
+ dev->clk = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(dev->clk))
+ return PTR_ERR(dev->clk);
+
+ ret = clk_prepare_enable(dev->clk);
+ if (ret) {
+ clk_put(dev->clk);
+ return ret;
+ }
+
+ atomic_io_modify(dev->reg + TIMER_CTRL,
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT),
+ WDT_A370_RATIO_MASK(WDT_A370_RATIO_SHIFT));
+ dev->clk_rate = clk_get_rate(dev->clk) / WDT_A370_RATIO;
+
+ return 0;
+}
+
static int armadaxp_wdt_clock_init(struct platform_device *pdev,
struct orion_watchdog *dev)
{
@@ -394,7 +434,7 @@ static const struct orion_watchdog_data armada375_data = {
.rstout_mask_bit = BIT(10),
.wdt_enable_bit = BIT(8),
.wdt_counter_offset = 0x34,
- .clock_init = armada370_wdt_clock_init,
+ .clock_init = armada375_wdt_clock_init,
.enabled = armada375_enabled,
.start = armada375_start,
.stop = armada375_stop,
diff --git a/drivers/watchdog/s3c2410_wdt.c b/drivers/watchdog/s3c2410_wdt.c
index 8532c3e..1626dc6 100644
--- a/drivers/watchdog/s3c2410_wdt.c
+++ b/drivers/watchdog/s3c2410_wdt.c
@@ -161,7 +161,7 @@ static const struct s3c2410_wdt_variant drv_data_exynos5420 = {
static const struct s3c2410_wdt_variant drv_data_exynos7 = {
.disable_reg = EXYNOS5_WDT_DISABLE_REG_OFFSET,
.mask_reset_reg = EXYNOS5_WDT_MASK_RESET_REG_OFFSET,
- .mask_bit = 0,
+ .mask_bit = 23,
.rst_stat_reg = EXYNOS5_RST_STAT_REG_OFFSET,
.rst_stat_bit = 23, /* A57 WDTRESET */
.quirks = QUIRK_HAS_PMU_CONFIG | QUIRK_HAS_RST_STAT,
diff --git a/drivers/xen/efi.c b/drivers/xen/efi.c
index 1f850c9..f745db2 100644
--- a/drivers/xen/efi.c
+++ b/drivers/xen/efi.c
@@ -294,6 +294,7 @@ static const struct efi efi_xen __initconst = {
.acpi = EFI_INVALID_TABLE_ADDR,
.acpi20 = EFI_INVALID_TABLE_ADDR,
.smbios = EFI_INVALID_TABLE_ADDR,
+ .smbios3 = EFI_INVALID_TABLE_ADDR,
.sal_systab = EFI_INVALID_TABLE_ADDR,
.boot_info = EFI_INVALID_TABLE_ADDR,
.hcdp = EFI_INVALID_TABLE_ADDR,
diff --git a/drivers/xen/xen-scsiback.c b/drivers/xen/xen-scsiback.c
index 3e32146..50610a6 100644
--- a/drivers/xen/xen-scsiback.c
+++ b/drivers/xen/xen-scsiback.c
@@ -274,10 +274,6 @@ static void scsiback_print_status(char *sense_buffer, int errors,
tpg->tport->tport_name, pending_req->v2p->lun,
pending_req->cmnd[0], status_byte(errors), msg_byte(errors),
host_byte(errors), driver_byte(errors));
-
- if (CHECK_CONDITION & status_byte(errors))
- __scsi_print_sense("xen-pvscsi", sense_buffer,
- SCSI_SENSE_BUFFERSIZE);
}
static void scsiback_fast_flush_area(struct vscsibk_pend *req)
diff --git a/fs/9p/vfs_inode.c b/fs/9p/vfs_inode.c
index 296482f..9ee5343 100644
--- a/fs/9p/vfs_inode.c
+++ b/fs/9p/vfs_inode.c
@@ -832,7 +832,7 @@ struct dentry *v9fs_vfs_lookup(struct inode *dir, struct dentry *dentry,
* moved b under k and client parallely did a lookup for
* k/b.
*/
- res = d_materialise_unique(dentry, inode);
+ res = d_splice_alias(inode, dentry);
if (!res)
v9fs_fid_add(dentry, fid);
else if (!IS_ERR(res))
diff --git a/fs/9p/vfs_inode_dotl.c b/fs/9p/vfs_inode_dotl.c
index 02b64f4..6054c16b 100644
--- a/fs/9p/vfs_inode_dotl.c
+++ b/fs/9p/vfs_inode_dotl.c
@@ -826,8 +826,8 @@ v9fs_vfs_mknod_dotl(struct inode *dir, struct dentry *dentry, umode_t omode,
struct dentry *dir_dentry;
struct posix_acl *dacl = NULL, *pacl = NULL;
- p9_debug(P9_DEBUG_VFS, " %lu,%s mode: %hx MAJOR: %u MINOR: %u\n",
- dir->i_ino, dentry->d_name.name, omode,
+ p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
+ dir->i_ino, dentry, omode,
MAJOR(rdev), MINOR(rdev));
if (!new_valid_dev(rdev))
diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c
index abc8539..937ce87 100644
--- a/fs/affs/amigaffs.c
+++ b/fs/affs/amigaffs.c
@@ -125,7 +125,7 @@ affs_fix_dcache(struct inode *inode, u32 entry_ino)
{
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (entry_ino == (u32)(long)dentry->d_fsdata) {
dentry->d_fsdata = (void *)inode->i_ino;
break;
diff --git a/fs/affs/inode.c b/fs/affs/inode.c
index e217c51..d0609a2 100644
--- a/fs/affs/inode.c
+++ b/fs/affs/inode.c
@@ -348,9 +348,9 @@ affs_add_entry(struct inode *dir, struct inode *inode, struct dentry *dentry, s3
u32 block = 0;
int retval;
- pr_debug("%s(dir=%u, inode=%u, \"%*s\", type=%d)\n",
+ pr_debug("%s(dir=%u, inode=%u, \"%pd\", type=%d)\n",
__func__, (u32)dir->i_ino,
- (u32)inode->i_ino, (int)dentry->d_name.len, dentry->d_name.name, type);
+ (u32)inode->i_ino, dentry, type);
retval = -EIO;
bh = affs_bread(sb, inode->i_ino);
diff --git a/fs/affs/namei.c b/fs/affs/namei.c
index 035bd31..bbc3853 100644
--- a/fs/affs/namei.c
+++ b/fs/affs/namei.c
@@ -190,8 +190,7 @@ affs_find_entry(struct inode *dir, struct dentry *dentry)
toupper_t toupper = affs_get_toupper(sb);
u32 key;
- pr_debug("%s(\"%.*s\")\n",
- __func__, (int)dentry->d_name.len, dentry->d_name.name);
+ pr_debug("%s(\"%pd\")\n", __func__, dentry);
bh = affs_bread(sb, dir->i_ino);
if (!bh)
@@ -219,8 +218,7 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
struct buffer_head *bh;
struct inode *inode = NULL;
- pr_debug("%s(\"%.*s\")\n",
- __func__, (int)dentry->d_name.len, dentry->d_name.name);
+ pr_debug("%s(\"%pd\")\n", __func__, dentry);
affs_lock_dir(dir);
bh = affs_find_entry(dir, dentry);
@@ -250,9 +248,9 @@ affs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
int
affs_unlink(struct inode *dir, struct dentry *dentry)
{
- pr_debug("%s(dir=%d, %lu \"%.*s\")\n",
+ pr_debug("%s(dir=%d, %lu \"%pd\")\n",
__func__, (u32)dir->i_ino, dentry->d_inode->i_ino,
- (int)dentry->d_name.len, dentry->d_name.name);
+ dentry);
return affs_remove_header(dentry);
}
@@ -264,9 +262,8 @@ affs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
struct inode *inode;
int error;
- pr_debug("%s(%lu,\"%.*s\",0%ho)\n",
- __func__, dir->i_ino, (int)dentry->d_name.len,
- dentry->d_name.name,mode);
+ pr_debug("%s(%lu,\"%pd\",0%ho)\n",
+ __func__, dir->i_ino, dentry, mode);
inode = affs_new_inode(dir);
if (!inode)
@@ -294,9 +291,8 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
struct inode *inode;
int error;
- pr_debug("%s(%lu,\"%.*s\",0%ho)\n",
- __func__, dir->i_ino, (int)dentry->d_name.len,
- dentry->d_name.name, mode);
+ pr_debug("%s(%lu,\"%pd\",0%ho)\n",
+ __func__, dir->i_ino, dentry, mode);
inode = affs_new_inode(dir);
if (!inode)
@@ -321,9 +317,9 @@ affs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
int
affs_rmdir(struct inode *dir, struct dentry *dentry)
{
- pr_debug("%s(dir=%u, %lu \"%.*s\")\n",
+ pr_debug("%s(dir=%u, %lu \"%pd\")\n",
__func__, (u32)dir->i_ino, dentry->d_inode->i_ino,
- (int)dentry->d_name.len, dentry->d_name.name);
+ dentry);
return affs_remove_header(dentry);
}
@@ -338,9 +334,8 @@ affs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
int i, maxlen, error;
char c, lc;
- pr_debug("%s(%lu,\"%.*s\" -> \"%s\")\n",
- __func__, dir->i_ino, (int)dentry->d_name.len,
- dentry->d_name.name, symname);
+ pr_debug("%s(%lu,\"%pd\" -> \"%s\")\n",
+ __func__, dir->i_ino, dentry, symname);
maxlen = AFFS_SB(sb)->s_hashsize * sizeof(u32) - 1;
inode = affs_new_inode(dir);
@@ -409,9 +404,9 @@ affs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *dentry)
{
struct inode *inode = old_dentry->d_inode;
- pr_debug("%s(%u, %u, \"%.*s\")\n",
+ pr_debug("%s(%u, %u, \"%pd\")\n",
__func__, (u32)inode->i_ino, (u32)dir->i_ino,
- (int)dentry->d_name.len,dentry->d_name.name);
+ dentry);
return affs_add_entry(dir, inode, dentry, ST_LINKFILE);
}
@@ -424,10 +419,9 @@ affs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct buffer_head *bh = NULL;
int retval;
- pr_debug("%s(old=%u,\"%*s\" to new=%u,\"%*s\")\n",
- __func__, (u32)old_dir->i_ino, (int)old_dentry->d_name.len,
- old_dentry->d_name.name, (u32)new_dir->i_ino,
- (int)new_dentry->d_name.len, new_dentry->d_name.name);
+ pr_debug("%s(old=%u,\"%pd\" to new=%u,\"%pd\")\n",
+ __func__, (u32)old_dir->i_ino, old_dentry,
+ (u32)new_dir->i_ino, new_dentry);
retval = affs_check_name(new_dentry->d_name.name,
new_dentry->d_name.len,
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index a1645b8..4ec35e9 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -26,7 +26,7 @@ static int afs_readdir(struct file *file, struct dir_context *ctx);
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
static int afs_d_delete(const struct dentry *dentry);
static void afs_d_release(struct dentry *dentry);
-static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
+static int afs_lookup_filldir(struct dir_context *ctx, const char *name, int nlen,
loff_t fpos, u64 ino, unsigned dtype);
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
bool excl);
@@ -391,10 +391,11 @@ static int afs_readdir(struct file *file, struct dir_context *ctx)
* - if afs_dir_iterate_block() spots this function, it'll pass the FID
* uniquifier through dtype
*/
-static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
- loff_t fpos, u64 ino, unsigned dtype)
+static int afs_lookup_filldir(struct dir_context *ctx, const char *name,
+ int nlen, loff_t fpos, u64 ino, unsigned dtype)
{
- struct afs_lookup_cookie *cookie = _cookie;
+ struct afs_lookup_cookie *cookie =
+ container_of(ctx, struct afs_lookup_cookie, ctx);
_enter("{%s,%u},%s,%u,,%llu,%u",
cookie->name.name, cookie->name.len, name, nlen,
@@ -433,7 +434,7 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
};
int ret;
- _enter("{%lu},%p{%s},", dir->i_ino, dentry, dentry->d_name.name);
+ _enter("{%lu},%p{%pd},", dir->i_ino, dentry, dentry);
/* search the directory */
ret = afs_dir_iterate(dir, &cookie.ctx, key);
@@ -465,8 +466,8 @@ static struct inode *afs_try_auto_mntpt(
struct afs_vnode *vnode = AFS_FS_I(dir);
struct inode *inode;
- _enter("%d, %p{%s}, {%x:%u}, %p",
- ret, dentry, devname, vnode->fid.vid, vnode->fid.vnode, key);
+ _enter("%d, %p{%pd}, {%x:%u}, %p",
+ ret, dentry, dentry, vnode->fid.vid, vnode->fid.vnode, key);
if (ret != -ENOENT ||
!test_bit(AFS_VNODE_AUTOCELL, &vnode->flags))
@@ -501,8 +502,8 @@ static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
vnode = AFS_FS_I(dir);
- _enter("{%x:%u},%p{%s},",
- vnode->fid.vid, vnode->fid.vnode, dentry, dentry->d_name.name);
+ _enter("{%x:%u},%p{%pd},",
+ vnode->fid.vid, vnode->fid.vnode, dentry, dentry);
ASSERTCMP(dentry->d_inode, ==, NULL);
@@ -588,11 +589,11 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
vnode = AFS_FS_I(dentry->d_inode);
if (dentry->d_inode)
- _enter("{v={%x:%u} n=%s fl=%lx},",
- vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+ _enter("{v={%x:%u} n=%pd fl=%lx},",
+ vnode->fid.vid, vnode->fid.vnode, dentry,
vnode->flags);
else
- _enter("{neg n=%s}", dentry->d_name.name);
+ _enter("{neg n=%pd}", dentry);
key = afs_request_key(AFS_FS_S(dentry->d_sb)->volume->cell);
if (IS_ERR(key))
@@ -607,7 +608,7 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
afs_validate(dir, key);
if (test_bit(AFS_VNODE_DELETED, &dir->flags)) {
- _debug("%s: parent dir deleted", dentry->d_name.name);
+ _debug("%pd: parent dir deleted", dentry);
goto out_bad;
}
@@ -625,16 +626,16 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
if (!dentry->d_inode)
goto out_bad;
if (is_bad_inode(dentry->d_inode)) {
- printk("kAFS: afs_d_revalidate: %s/%s has bad inode\n",
- parent->d_name.name, dentry->d_name.name);
+ printk("kAFS: afs_d_revalidate: %pd2 has bad inode\n",
+ dentry);
goto out_bad;
}
/* if the vnode ID has changed, then the dirent points to a
* different file */
if (fid.vnode != vnode->fid.vnode) {
- _debug("%s: dirent changed [%u != %u]",
- dentry->d_name.name, fid.vnode,
+ _debug("%pd: dirent changed [%u != %u]",
+ dentry, fid.vnode,
vnode->fid.vnode);
goto not_found;
}
@@ -643,8 +644,8 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
* been deleted and replaced, and the original vnode ID has
* been reused */
if (fid.unique != vnode->fid.unique) {
- _debug("%s: file deleted (uq %u -> %u I:%u)",
- dentry->d_name.name, fid.unique,
+ _debug("%pd: file deleted (uq %u -> %u I:%u)",
+ dentry, fid.unique,
vnode->fid.unique,
dentry->d_inode->i_generation);
spin_lock(&vnode->lock);
@@ -656,14 +657,14 @@ static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
case -ENOENT:
/* the filename is unknown */
- _debug("%s: dirent not found", dentry->d_name.name);
+ _debug("%pd: dirent not found", dentry);
if (dentry->d_inode)
goto not_found;
goto out_valid;
default:
- _debug("failed to iterate dir %s: %d",
- parent->d_name.name, ret);
+ _debug("failed to iterate dir %pd: %d",
+ parent, ret);
goto out_bad;
}
@@ -681,8 +682,7 @@ not_found:
spin_unlock(&dentry->d_lock);
out_bad:
- _debug("dropping dentry %s/%s",
- parent->d_name.name, dentry->d_name.name);
+ _debug("dropping dentry %pd2", dentry);
dput(parent);
key_put(key);
@@ -698,7 +698,7 @@ out_bad:
*/
static int afs_d_delete(const struct dentry *dentry)
{
- _enter("%s", dentry->d_name.name);
+ _enter("%pd", dentry);
if (dentry->d_flags & DCACHE_NFSFS_RENAMED)
goto zap;
@@ -721,7 +721,7 @@ zap:
*/
static void afs_d_release(struct dentry *dentry)
{
- _enter("%s", dentry->d_name.name);
+ _enter("%pd", dentry);
}
/*
@@ -740,8 +740,8 @@ static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
dvnode = AFS_FS_I(dir);
- _enter("{%x:%u},{%s},%ho",
- dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
+ _enter("{%x:%u},{%pd},%ho",
+ dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
key = afs_request_key(dvnode->volume->cell);
if (IS_ERR(key)) {
@@ -801,8 +801,8 @@ static int afs_rmdir(struct inode *dir, struct dentry *dentry)
dvnode = AFS_FS_I(dir);
- _enter("{%x:%u},{%s}",
- dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
+ _enter("{%x:%u},{%pd}",
+ dvnode->fid.vid, dvnode->fid.vnode, dentry);
key = afs_request_key(dvnode->volume->cell);
if (IS_ERR(key)) {
@@ -843,8 +843,8 @@ static int afs_unlink(struct inode *dir, struct dentry *dentry)
dvnode = AFS_FS_I(dir);
- _enter("{%x:%u},{%s}",
- dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name);
+ _enter("{%x:%u},{%pd}",
+ dvnode->fid.vid, dvnode->fid.vnode, dentry);
ret = -ENAMETOOLONG;
if (dentry->d_name.len >= AFSNAMEMAX)
@@ -917,8 +917,8 @@ static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
dvnode = AFS_FS_I(dir);
- _enter("{%x:%u},{%s},%ho,",
- dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name, mode);
+ _enter("{%x:%u},{%pd},%ho,",
+ dvnode->fid.vid, dvnode->fid.vnode, dentry, mode);
key = afs_request_key(dvnode->volume->cell);
if (IS_ERR(key)) {
@@ -980,10 +980,10 @@ static int afs_link(struct dentry *from, struct inode *dir,
vnode = AFS_FS_I(from->d_inode);
dvnode = AFS_FS_I(dir);
- _enter("{%x:%u},{%x:%u},{%s}",
+ _enter("{%x:%u},{%x:%u},{%pd}",
vnode->fid.vid, vnode->fid.vnode,
dvnode->fid.vid, dvnode->fid.vnode,
- dentry->d_name.name);
+ dentry);
key = afs_request_key(dvnode->volume->cell);
if (IS_ERR(key)) {
@@ -1025,8 +1025,8 @@ static int afs_symlink(struct inode *dir, struct dentry *dentry,
dvnode = AFS_FS_I(dir);
- _enter("{%x:%u},{%s},%s",
- dvnode->fid.vid, dvnode->fid.vnode, dentry->d_name.name,
+ _enter("{%x:%u},{%pd},%s",
+ dvnode->fid.vid, dvnode->fid.vnode, dentry,
content);
ret = -EINVAL;
@@ -1093,11 +1093,11 @@ static int afs_rename(struct inode *old_dir, struct dentry *old_dentry,
orig_dvnode = AFS_FS_I(old_dir);
new_dvnode = AFS_FS_I(new_dir);
- _enter("{%x:%u},{%x:%u},{%x:%u},{%s}",
+ _enter("{%x:%u},{%x:%u},{%x:%u},{%pd}",
orig_dvnode->fid.vid, orig_dvnode->fid.vnode,
vnode->fid.vid, vnode->fid.vnode,
new_dvnode->fid.vid, new_dvnode->fid.vnode,
- new_dentry->d_name.name);
+ new_dentry);
key = afs_request_key(orig_dvnode->volume->cell);
if (IS_ERR(key)) {
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 2946712..8a1d38e 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -462,8 +462,8 @@ int afs_setattr(struct dentry *dentry, struct iattr *attr)
struct key *key;
int ret;
- _enter("{%x:%u},{n=%s},%x",
- vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+ _enter("{%x:%u},{n=%pd},%x",
+ vnode->fid.vid, vnode->fid.vnode, dentry,
attr->ia_valid);
if (!(attr->ia_valid & (ATTR_SIZE | ATTR_MODE | ATTR_UID | ATTR_GID |
diff --git a/fs/afs/mntpt.c b/fs/afs/mntpt.c
index 9682c33..938c5ab 100644
--- a/fs/afs/mntpt.c
+++ b/fs/afs/mntpt.c
@@ -106,14 +106,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
struct dentry *dentry,
unsigned int flags)
{
- _enter("%p,%p{%p{%s},%s}",
- dir,
- dentry,
- dentry->d_parent,
- dentry->d_parent ?
- dentry->d_parent->d_name.name : (const unsigned char *) "",
- dentry->d_name.name);
-
+ _enter("%p,%p{%pd2}", dir, dentry, dentry);
return ERR_PTR(-EREMOTE);
}
@@ -122,14 +115,7 @@ static struct dentry *afs_mntpt_lookup(struct inode *dir,
*/
static int afs_mntpt_open(struct inode *inode, struct file *file)
{
- _enter("%p,%p{%p{%s},%s}",
- inode, file,
- file->f_path.dentry->d_parent,
- file->f_path.dentry->d_parent ?
- file->f_path.dentry->d_parent->d_name.name :
- (const unsigned char *) "",
- file->f_path.dentry->d_name.name);
-
+ _enter("%p,%p{%pD2}", inode, file, file);
return -EREMOTE;
}
@@ -146,7 +132,7 @@ static struct vfsmount *afs_mntpt_do_automount(struct dentry *mntpt)
bool rwpath = false;
int ret;
- _enter("{%s}", mntpt->d_name.name);
+ _enter("{%pd}", mntpt);
BUG_ON(!mntpt->d_inode);
@@ -242,7 +228,7 @@ struct vfsmount *afs_d_automount(struct path *path)
{
struct vfsmount *newmnt;
- _enter("{%s}", path->dentry->d_name.name);
+ _enter("{%pd}", path->dentry);
newmnt = afs_mntpt_do_automount(path->dentry);
if (IS_ERR(newmnt))
diff --git a/fs/afs/write.c b/fs/afs/write.c
index ab6adfd..c13cb08 100644
--- a/fs/afs/write.c
+++ b/fs/afs/write.c
@@ -682,14 +682,13 @@ int afs_writeback_all(struct afs_vnode *vnode)
*/
int afs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = file->f_mapping->host;
+ struct inode *inode = file_inode(file);
struct afs_writeback *wb, *xwb;
- struct afs_vnode *vnode = AFS_FS_I(dentry->d_inode);
+ struct afs_vnode *vnode = AFS_FS_I(inode);
int ret;
- _enter("{%x:%u},{n=%s},%d",
- vnode->fid.vid, vnode->fid.vnode, dentry->d_name.name,
+ _enter("{%x:%u},{n=%pD},%d",
+ vnode->fid.vid, vnode->fid.vnode, file,
datasync);
ret = filemap_write_and_wait_range(inode->i_mapping, start, end);
diff --git a/fs/autofs4/expire.c b/fs/autofs4/expire.c
index 683a5b9..bfdbaba 100644
--- a/fs/autofs4/expire.c
+++ b/fs/autofs4/expire.c
@@ -41,8 +41,7 @@ static int autofs4_mount_busy(struct vfsmount *mnt, struct dentry *dentry)
struct path path = {.mnt = mnt, .dentry = dentry};
int status = 1;
- DPRINTK("dentry %p %.*s",
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("dentry %p %pd", dentry, dentry);
path_get(&path);
@@ -85,7 +84,7 @@ static struct dentry *get_next_positive_subdir(struct dentry *prev,
spin_lock(&root->d_lock);
if (prev)
- next = prev->d_u.d_child.next;
+ next = prev->d_child.next;
else {
prev = dget_dlock(root);
next = prev->d_subdirs.next;
@@ -99,13 +98,13 @@ cont:
return NULL;
}
- q = list_entry(next, struct dentry, d_u.d_child);
+ q = list_entry(next, struct dentry, d_child);
spin_lock_nested(&q->d_lock, DENTRY_D_LOCK_NESTED);
/* Already gone or negative dentry (under construction) - try next */
if (!d_count(q) || !simple_positive(q)) {
spin_unlock(&q->d_lock);
- next = q->d_u.d_child.next;
+ next = q->d_child.next;
goto cont;
}
dget_dlock(q);
@@ -155,13 +154,13 @@ again:
goto relock;
}
spin_unlock(&p->d_lock);
- next = p->d_u.d_child.next;
+ next = p->d_child.next;
p = parent;
if (next != &parent->d_subdirs)
break;
}
}
- ret = list_entry(next, struct dentry, d_u.d_child);
+ ret = list_entry(next, struct dentry, d_child);
spin_lock_nested(&ret->d_lock, DENTRY_D_LOCK_NESTED);
/* Negative dentry - try next */
@@ -192,8 +191,7 @@ static int autofs4_direct_busy(struct vfsmount *mnt,
unsigned long timeout,
int do_now)
{
- DPRINTK("top %p %.*s",
- top, (int) top->d_name.len, top->d_name.name);
+ DPRINTK("top %p %pd", top, top);
/* If it's busy update the expiry counters */
if (!may_umount_tree(mnt)) {
@@ -221,8 +219,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
struct autofs_info *top_ino = autofs4_dentry_ino(top);
struct dentry *p;
- DPRINTK("top %p %.*s",
- top, (int)top->d_name.len, top->d_name.name);
+ DPRINTK("top %p %pd", top, top);
/* Negative dentry - give up */
if (!simple_positive(top))
@@ -230,8 +227,7 @@ static int autofs4_tree_busy(struct vfsmount *mnt,
p = NULL;
while ((p = get_next_positive_dentry(p, top))) {
- DPRINTK("dentry %p %.*s",
- p, (int) p->d_name.len, p->d_name.name);
+ DPRINTK("dentry %p %pd", p, p);
/*
* Is someone visiting anywhere in the subtree ?
@@ -277,13 +273,11 @@ static struct dentry *autofs4_check_leaves(struct vfsmount *mnt,
{
struct dentry *p;
- DPRINTK("parent %p %.*s",
- parent, (int)parent->d_name.len, parent->d_name.name);
+ DPRINTK("parent %p %pd", parent, parent);
p = NULL;
while ((p = get_next_positive_dentry(p, parent))) {
- DPRINTK("dentry %p %.*s",
- p, (int) p->d_name.len, p->d_name.name);
+ DPRINTK("dentry %p %pd", p, p);
if (d_mountpoint(p)) {
/* Can we umount this guy */
@@ -368,8 +362,7 @@ static struct dentry *should_expire(struct dentry *dentry,
* offset (autofs-5.0+).
*/
if (d_mountpoint(dentry)) {
- DPRINTK("checking mountpoint %p %.*s",
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("checking mountpoint %p %pd", dentry, dentry);
/* Can we umount this guy */
if (autofs4_mount_busy(mnt, dentry))
@@ -382,8 +375,7 @@ static struct dentry *should_expire(struct dentry *dentry,
}
if (dentry->d_inode && S_ISLNK(dentry->d_inode->i_mode)) {
- DPRINTK("checking symlink %p %.*s",
- dentry, (int)dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("checking symlink %p %pd", dentry, dentry);
/*
* A symlink can't be "busy" in the usual sense so
* just check last used for expire timeout.
@@ -479,8 +471,7 @@ struct dentry *autofs4_expire_indirect(struct super_block *sb,
return NULL;
found:
- DPRINTK("returning %p %.*s",
- expired, (int)expired->d_name.len, expired->d_name.name);
+ DPRINTK("returning %p %pd", expired, expired);
ino->flags |= AUTOFS_INF_EXPIRING;
smp_mb();
ino->flags &= ~AUTOFS_INF_NO_RCU;
@@ -489,7 +480,7 @@ found:
spin_lock(&sbi->lookup_lock);
spin_lock(&expired->d_parent->d_lock);
spin_lock_nested(&expired->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&expired->d_parent->d_subdirs, &expired->d_u.d_child);
+ list_move(&expired->d_parent->d_subdirs, &expired->d_child);
spin_unlock(&expired->d_lock);
spin_unlock(&expired->d_parent->d_lock);
spin_unlock(&sbi->lookup_lock);
@@ -512,8 +503,7 @@ int autofs4_expire_wait(struct dentry *dentry, int rcu_walk)
if (ino->flags & AUTOFS_INF_EXPIRING) {
spin_unlock(&sbi->fs_lock);
- DPRINTK("waiting for expire %p name=%.*s",
- dentry, dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("waiting for expire %p name=%pd", dentry, dentry);
status = autofs4_wait(sbi, dentry, NFY_NONE);
wait_for_completion(&ino->expire_complete);
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index d76d083..dbb5b72 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -108,8 +108,7 @@ static int autofs4_dir_open(struct inode *inode, struct file *file)
struct dentry *dentry = file->f_path.dentry;
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
- DPRINTK("file=%p dentry=%p %.*s",
- file, dentry, dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("file=%p dentry=%p %pD", file, dentry, dentry);
if (autofs4_oz_mode(sbi))
goto out;
@@ -279,8 +278,7 @@ static int autofs4_mount_wait(struct dentry *dentry, bool rcu_walk)
if (ino->flags & AUTOFS_INF_PENDING) {
if (rcu_walk)
return -ECHILD;
- DPRINTK("waiting for mount name=%.*s",
- dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("waiting for mount name=%pd", dentry);
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
DPRINTK("mount wait done status=%d", status);
}
@@ -340,8 +338,7 @@ static struct vfsmount *autofs4_d_automount(struct path *path)
struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status;
- DPRINTK("dentry=%p %.*s",
- dentry, dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("dentry=%p %pd", dentry, dentry);
/* The daemon never triggers a mount. */
if (autofs4_oz_mode(sbi))
@@ -428,8 +425,7 @@ static int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
struct autofs_info *ino = autofs4_dentry_ino(dentry);
int status;
- DPRINTK("dentry=%p %.*s",
- dentry, dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("dentry=%p %pd", dentry, dentry);
/* The daemon never waits. */
if (autofs4_oz_mode(sbi)) {
@@ -504,7 +500,7 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, u
struct autofs_info *ino;
struct dentry *active;
- DPRINTK("name = %.*s", dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("name = %pd", dentry);
/* File name too long to exist */
if (dentry->d_name.len > NAME_MAX)
@@ -558,8 +554,7 @@ static int autofs4_dir_symlink(struct inode *dir,
size_t size = strlen(symname);
char *cp;
- DPRINTK("%s <- %.*s", symname,
- dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("%s <- %pd", symname, dentry);
if (!autofs4_oz_mode(sbi))
return -EACCES;
@@ -687,7 +682,7 @@ static void autofs_clear_leaf_automount_flags(struct dentry *dentry)
/* only consider parents below dentrys in the root */
if (IS_ROOT(parent->d_parent))
return;
- d_child = &dentry->d_u.d_child;
+ d_child = &dentry->d_child;
/* Set parent managed if it's becoming empty */
if (d_child->next == &parent->d_subdirs &&
d_child->prev == &parent->d_subdirs)
@@ -701,8 +696,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
struct autofs_info *ino = autofs4_dentry_ino(dentry);
struct autofs_info *p_ino;
- DPRINTK("dentry %p, removing %.*s",
- dentry, dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("dentry %p, removing %pd", dentry, dentry);
if (!autofs4_oz_mode(sbi))
return -EACCES;
@@ -744,8 +738,7 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, umode_t m
if (!autofs4_oz_mode(sbi))
return -EACCES;
- DPRINTK("dentry %p, creating %.*s",
- dentry, dentry->d_name.len, dentry->d_name.name);
+ DPRINTK("dentry %p, creating %pd", dentry, dentry);
BUG_ON(!ino);
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 4cf61ec..b94d1cc 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -172,8 +172,8 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
char *utfname;
const char *name = dentry->d_name.name;
- befs_debug(sb, "---> %s name %s inode %ld", __func__,
- dentry->d_name.name, dir->i_ino);
+ befs_debug(sb, "---> %s name %pd inode %ld", __func__,
+ dentry, dir->i_ino);
/* Convert to UTF-8 */
if (BEFS_SB(sb)->nls) {
@@ -191,8 +191,7 @@ befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
}
if (ret == BEFS_BT_NOT_FOUND) {
- befs_debug(sb, "<--- %s %s not found", __func__,
- dentry->d_name.name);
+ befs_debug(sb, "<--- %s %pd not found", __func__, dentry);
return ERR_PTR(-ENOENT);
} else if (ret != BEFS_OK || offset == 0) {
@@ -222,10 +221,9 @@ befs_readdir(struct file *file, struct dir_context *ctx)
size_t keysize;
unsigned char d_type;
char keybuf[BEFS_NAME_LEN + 1];
- const char *dirname = file->f_path.dentry->d_name.name;
- befs_debug(sb, "---> %s name %s, inode %ld, ctx->pos %lld",
- __func__, dirname, inode->i_ino, ctx->pos);
+ befs_debug(sb, "---> %s name %pD, inode %ld, ctx->pos %lld",
+ __func__, file, inode->i_ino, ctx->pos);
more:
result = befs_btree_read(sb, ds, ctx->pos, BEFS_NAME_LEN + 1,
@@ -233,8 +231,8 @@ more:
if (result == BEFS_ERR) {
befs_debug(sb, "<--- %s ERROR", __func__);
- befs_error(sb, "IO error reading %s (inode %lu)",
- dirname, inode->i_ino);
+ befs_error(sb, "IO error reading %pD (inode %lu)",
+ file, inode->i_ino);
return -EIO;
} else if (result == BEFS_BT_END) {
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index 929dec0..4c55668 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -292,8 +292,8 @@ static int load_aout_binary(struct linux_binprm * bprm)
if ((fd_offset & ~PAGE_MASK) != 0 && printk_ratelimit())
{
printk(KERN_WARNING
- "fd_offset is not page aligned. Please convert program: %s\n",
- bprm->file->f_path.dentry->d_name.name);
+ "fd_offset is not page aligned. Please convert program: %pD\n",
+ bprm->file);
}
if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
@@ -375,8 +375,8 @@ static int load_aout_library(struct file *file)
if (printk_ratelimit())
{
printk(KERN_WARNING
- "N_TXTOFF is not page aligned. Please convert library: %s\n",
- file->f_path.dentry->d_name.name);
+ "N_TXTOFF is not page aligned. Please convert library: %pD\n",
+ file);
}
vm_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index d8fc060..3a6175f 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1994,18 +1994,6 @@ static void fill_extnum_info(struct elfhdr *elf, struct elf_shdr *shdr4extnum,
shdr4extnum->sh_info = segs;
}
-static size_t elf_core_vma_data_size(struct vm_area_struct *gate_vma,
- unsigned long mm_flags)
-{
- struct vm_area_struct *vma;
- size_t size = 0;
-
- for (vma = first_vma(current, gate_vma); vma != NULL;
- vma = next_vma(vma, gate_vma))
- size += vma_dump_size(vma, mm_flags);
- return size;
-}
-
/*
* Actual dumper
*
@@ -2017,7 +2005,8 @@ static int elf_core_dump(struct coredump_params *cprm)
{
int has_dumped = 0;
mm_segment_t fs;
- int segs;
+ int segs, i;
+ size_t vma_data_size = 0;
struct vm_area_struct *vma, *gate_vma;
struct elfhdr *elf = NULL;
loff_t offset = 0, dataoff;
@@ -2026,6 +2015,7 @@ static int elf_core_dump(struct coredump_params *cprm)
struct elf_shdr *shdr4extnum = NULL;
Elf_Half e_phnum;
elf_addr_t e_shoff;
+ elf_addr_t *vma_filesz = NULL;
/*
* We no longer stop all VM operations.
@@ -2093,7 +2083,20 @@ static int elf_core_dump(struct coredump_params *cprm)
dataoff = offset = roundup(offset, ELF_EXEC_PAGESIZE);
- offset += elf_core_vma_data_size(gate_vma, cprm->mm_flags);
+ vma_filesz = kmalloc_array(segs - 1, sizeof(*vma_filesz), GFP_KERNEL);
+ if (!vma_filesz)
+ goto end_coredump;
+
+ for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
+ vma = next_vma(vma, gate_vma)) {
+ unsigned long dump_size;
+
+ dump_size = vma_dump_size(vma, cprm->mm_flags);
+ vma_filesz[i++] = dump_size;
+ vma_data_size += dump_size;
+ }
+
+ offset += vma_data_size;
offset += elf_core_extra_data_size();
e_shoff = offset;
@@ -2113,7 +2116,7 @@ static int elf_core_dump(struct coredump_params *cprm)
goto end_coredump;
/* Write program headers for segments dump */
- for (vma = first_vma(current, gate_vma); vma != NULL;
+ for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
struct elf_phdr phdr;
@@ -2121,7 +2124,7 @@ static int elf_core_dump(struct coredump_params *cprm)
phdr.p_offset = offset;
phdr.p_vaddr = vma->vm_start;
phdr.p_paddr = 0;
- phdr.p_filesz = vma_dump_size(vma, cprm->mm_flags);
+ phdr.p_filesz = vma_filesz[i++];
phdr.p_memsz = vma->vm_end - vma->vm_start;
offset += phdr.p_filesz;
phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0;
@@ -2149,12 +2152,12 @@ static int elf_core_dump(struct coredump_params *cprm)
if (!dump_skip(cprm, dataoff - cprm->written))
goto end_coredump;
- for (vma = first_vma(current, gate_vma); vma != NULL;
+ for (i = 0, vma = first_vma(current, gate_vma); vma != NULL;
vma = next_vma(vma, gate_vma)) {
unsigned long addr;
unsigned long end;
- end = vma->vm_start + vma_dump_size(vma, cprm->mm_flags);
+ end = vma->vm_start + vma_filesz[i++];
for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
@@ -2187,6 +2190,7 @@ end_coredump:
cleanup:
free_note_info(&info);
kfree(shdr4extnum);
+ kfree(vma_filesz);
kfree(phdr4note);
kfree(elf);
out:
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index fd8beb9..70789e1 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -1,21 +1,14 @@
/*
- * binfmt_misc.c
+ * binfmt_misc.c
*
- * Copyright (C) 1997 Richard Günther
+ * Copyright (C) 1997 Richard Günther
*
- * binfmt_misc detects binaries via a magic or filename extension and invokes
- * a specified wrapper. This should obsolete binfmt_java, binfmt_em86 and
- * binfmt_mz.
- *
- * 1997-04-25 first version
- * [...]
- * 1997-05-19 cleanup
- * 1997-06-26 hpa: pass the real filename rather than argv[0]
- * 1997-06-30 minor cleanup
- * 1997-08-09 removed extension stripping, locking cleanup
- * 2001-02-28 AV: rewritten into something that resembles C. Original didn't.
+ * binfmt_misc detects binaries via a magic or filename extension and invokes
+ * a specified wrapper. See Documentation/binfmt_misc.txt for more details.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
@@ -30,8 +23,13 @@
#include <linux/mount.h>
#include <linux/syscalls.h>
#include <linux/fs.h>
+#include <linux/uaccess.h>
-#include <asm/uaccess.h>
+#ifdef DEBUG
+# define USE_DEBUG 1
+#else
+# define USE_DEBUG 0
+#endif
enum {
VERBOSE_STATUS = 1 /* make it zero to save 400 bytes kernel memory */
@@ -41,9 +39,9 @@ static LIST_HEAD(entries);
static int enabled = 1;
enum {Enabled, Magic};
-#define MISC_FMT_PRESERVE_ARGV0 (1<<31)
-#define MISC_FMT_OPEN_BINARY (1<<30)
-#define MISC_FMT_CREDENTIALS (1<<29)
+#define MISC_FMT_PRESERVE_ARGV0 (1 << 31)
+#define MISC_FMT_OPEN_BINARY (1 << 30)
+#define MISC_FMT_CREDENTIALS (1 << 29)
typedef struct {
struct list_head list;
@@ -87,20 +85,24 @@ static Node *check_file(struct linux_binprm *bprm)
char *p = strrchr(bprm->interp, '.');
struct list_head *l;
+ /* Walk all the registered handlers. */
list_for_each(l, &entries) {
Node *e = list_entry(l, Node, list);
char *s;
int j;
+ /* Make sure this one is currently enabled. */
if (!test_bit(Enabled, &e->flags))
continue;
+ /* Do matching based on extension if applicable. */
if (!test_bit(Magic, &e->flags)) {
if (p && !strcmp(e->magic, p + 1))
return e;
continue;
}
+ /* Do matching based on magic & mask. */
s = bprm->buf + e->offset;
if (e->mask) {
for (j = 0; j < e->size; j++)
@@ -123,7 +125,7 @@ static Node *check_file(struct linux_binprm *bprm)
static int load_misc_binary(struct linux_binprm *bprm)
{
Node *fmt;
- struct file * interp_file = NULL;
+ struct file *interp_file = NULL;
char iname[BINPRM_BUF_SIZE];
const char *iname_addr = iname;
int retval;
@@ -131,7 +133,7 @@ static int load_misc_binary(struct linux_binprm *bprm)
retval = -ENOEXEC;
if (!enabled)
- goto _ret;
+ goto ret;
/* to keep locking time low, we copy the interpreter string */
read_lock(&entries_lock);
@@ -140,25 +142,26 @@ static int load_misc_binary(struct linux_binprm *bprm)
strlcpy(iname, fmt->interpreter, BINPRM_BUF_SIZE);
read_unlock(&entries_lock);
if (!fmt)
- goto _ret;
+ goto ret;
if (!(fmt->flags & MISC_FMT_PRESERVE_ARGV0)) {
retval = remove_arg_zero(bprm);
if (retval)
- goto _ret;
+ goto ret;
}
if (fmt->flags & MISC_FMT_OPEN_BINARY) {
/* if the binary should be opened on behalf of the
* interpreter than keep it open and assign descriptor
- * to it */
- fd_binary = get_unused_fd();
- if (fd_binary < 0) {
- retval = fd_binary;
- goto _ret;
- }
- fd_install(fd_binary, bprm->file);
+ * to it
+ */
+ fd_binary = get_unused_fd_flags(0);
+ if (fd_binary < 0) {
+ retval = fd_binary;
+ goto ret;
+ }
+ fd_install(fd_binary, bprm->file);
/* if the binary is not readable than enforce mm->dumpable=0
regardless of the interpreter's permissions */
@@ -171,32 +174,32 @@ static int load_misc_binary(struct linux_binprm *bprm)
bprm->interp_flags |= BINPRM_FLAGS_EXECFD;
bprm->interp_data = fd_binary;
- } else {
- allow_write_access(bprm->file);
- fput(bprm->file);
- bprm->file = NULL;
- }
+ } else {
+ allow_write_access(bprm->file);
+ fput(bprm->file);
+ bprm->file = NULL;
+ }
/* make argv[1] be the path to the binary */
- retval = copy_strings_kernel (1, &bprm->interp, bprm);
+ retval = copy_strings_kernel(1, &bprm->interp, bprm);
if (retval < 0)
- goto _error;
+ goto error;
bprm->argc++;
/* add the interp as argv[0] */
- retval = copy_strings_kernel (1, &iname_addr, bprm);
+ retval = copy_strings_kernel(1, &iname_addr, bprm);
if (retval < 0)
- goto _error;
- bprm->argc ++;
+ goto error;
+ bprm->argc++;
/* Update interp in case binfmt_script needs it. */
retval = bprm_change_interp(iname, bprm);
if (retval < 0)
- goto _error;
+ goto error;
- interp_file = open_exec (iname);
- retval = PTR_ERR (interp_file);
- if (IS_ERR (interp_file))
- goto _error;
+ interp_file = open_exec(iname);
+ retval = PTR_ERR(interp_file);
+ if (IS_ERR(interp_file))
+ goto error;
bprm->file = interp_file;
if (fmt->flags & MISC_FMT_CREDENTIALS) {
@@ -207,23 +210,23 @@ static int load_misc_binary(struct linux_binprm *bprm)
memset(bprm->buf, 0, BINPRM_BUF_SIZE);
retval = kernel_read(bprm->file, 0, bprm->buf, BINPRM_BUF_SIZE);
} else
- retval = prepare_binprm (bprm);
+ retval = prepare_binprm(bprm);
if (retval < 0)
- goto _error;
+ goto error;
retval = search_binary_handler(bprm);
if (retval < 0)
- goto _error;
+ goto error;
-_ret:
+ret:
return retval;
-_error:
+error:
if (fd_binary > 0)
sys_close(fd_binary);
bprm->interp_flags = 0;
bprm->interp_data = 0;
- goto _ret;
+ goto ret;
}
/* Command parsers */
@@ -250,36 +253,40 @@ static char *scanarg(char *s, char del)
return s;
}
-static char * check_special_flags (char * sfs, Node * e)
+static char *check_special_flags(char *sfs, Node *e)
{
- char * p = sfs;
+ char *p = sfs;
int cont = 1;
/* special flags */
while (cont) {
switch (*p) {
- case 'P':
- p++;
- e->flags |= MISC_FMT_PRESERVE_ARGV0;
- break;
- case 'O':
- p++;
- e->flags |= MISC_FMT_OPEN_BINARY;
- break;
- case 'C':
- p++;
- /* this flags also implies the
- open-binary flag */
- e->flags |= (MISC_FMT_CREDENTIALS |
- MISC_FMT_OPEN_BINARY);
- break;
- default:
- cont = 0;
+ case 'P':
+ pr_debug("register: flag: P (preserve argv0)\n");
+ p++;
+ e->flags |= MISC_FMT_PRESERVE_ARGV0;
+ break;
+ case 'O':
+ pr_debug("register: flag: O (open binary)\n");
+ p++;
+ e->flags |= MISC_FMT_OPEN_BINARY;
+ break;
+ case 'C':
+ pr_debug("register: flag: C (preserve creds)\n");
+ p++;
+ /* this flags also implies the
+ open-binary flag */
+ e->flags |= (MISC_FMT_CREDENTIALS |
+ MISC_FMT_OPEN_BINARY);
+ break;
+ default:
+ cont = 0;
}
}
return p;
}
+
/*
* This registers a new binary format, it recognises the syntax
* ':name:type:offset:magic:mask:interpreter:flags'
@@ -292,6 +299,8 @@ static Node *create_entry(const char __user *buffer, size_t count)
char *buf, *p;
char del;
+ pr_debug("register: received %zu bytes\n", count);
+
/* some sanity checks */
err = -EINVAL;
if ((count < 11) || (count > MAX_REGISTER_LENGTH))
@@ -299,7 +308,7 @@ static Node *create_entry(const char __user *buffer, size_t count)
err = -ENOMEM;
memsize = sizeof(Node) + count + 8;
- e = kmalloc(memsize, GFP_USER);
+ e = kmalloc(memsize, GFP_KERNEL);
if (!e)
goto out;
@@ -307,98 +316,175 @@ static Node *create_entry(const char __user *buffer, size_t count)
memset(e, 0, sizeof(Node));
if (copy_from_user(buf, buffer, count))
- goto Efault;
+ goto efault;
del = *p++; /* delimeter */
- memset(buf+count, del, 8);
+ pr_debug("register: delim: %#x {%c}\n", del, del);
+
+ /* Pad the buffer with the delim to simplify parsing below. */
+ memset(buf + count, del, 8);
+ /* Parse the 'name' field. */
e->name = p;
p = strchr(p, del);
if (!p)
- goto Einval;
+ goto einval;
*p++ = '\0';
if (!e->name[0] ||
!strcmp(e->name, ".") ||
!strcmp(e->name, "..") ||
strchr(e->name, '/'))
- goto Einval;
+ goto einval;
+
+ pr_debug("register: name: {%s}\n", e->name);
+
+ /* Parse the 'type' field. */
switch (*p++) {
- case 'E': e->flags = 1<<Enabled; break;
- case 'M': e->flags = (1<<Enabled) | (1<<Magic); break;
- default: goto Einval;
+ case 'E':
+ pr_debug("register: type: E (extension)\n");
+ e->flags = 1 << Enabled;
+ break;
+ case 'M':
+ pr_debug("register: type: M (magic)\n");
+ e->flags = (1 << Enabled) | (1 << Magic);
+ break;
+ default:
+ goto einval;
}
if (*p++ != del)
- goto Einval;
+ goto einval;
+
if (test_bit(Magic, &e->flags)) {
- char *s = strchr(p, del);
+ /* Handle the 'M' (magic) format. */
+ char *s;
+
+ /* Parse the 'offset' field. */
+ s = strchr(p, del);
if (!s)
- goto Einval;
+ goto einval;
*s++ = '\0';
e->offset = simple_strtoul(p, &p, 10);
if (*p++)
- goto Einval;
+ goto einval;
+ pr_debug("register: offset: %#x\n", e->offset);
+
+ /* Parse the 'magic' field. */
e->magic = p;
p = scanarg(p, del);
if (!p)
- goto Einval;
+ goto einval;
p[-1] = '\0';
- if (!e->magic[0])
- goto Einval;
+ if (p == e->magic)
+ goto einval;
+ if (USE_DEBUG)
+ print_hex_dump_bytes(
+ KBUILD_MODNAME ": register: magic[raw]: ",
+ DUMP_PREFIX_NONE, e->magic, p - e->magic);
+
+ /* Parse the 'mask' field. */
e->mask = p;
p = scanarg(p, del);
if (!p)
- goto Einval;
+ goto einval;
p[-1] = '\0';
- if (!e->mask[0])
+ if (p == e->mask) {
e->mask = NULL;
+ pr_debug("register: mask[raw]: none\n");
+ } else if (USE_DEBUG)
+ print_hex_dump_bytes(
+ KBUILD_MODNAME ": register: mask[raw]: ",
+ DUMP_PREFIX_NONE, e->mask, p - e->mask);
+
+ /*
+ * Decode the magic & mask fields.
+ * Note: while we might have accepted embedded NUL bytes from
+ * above, the unescape helpers here will stop at the first one
+ * it encounters.
+ */
e->size = string_unescape_inplace(e->magic, UNESCAPE_HEX);
if (e->mask &&
string_unescape_inplace(e->mask, UNESCAPE_HEX) != e->size)
- goto Einval;
+ goto einval;
if (e->size + e->offset > BINPRM_BUF_SIZE)
- goto Einval;
+ goto einval;
+ pr_debug("register: magic/mask length: %i\n", e->size);
+ if (USE_DEBUG) {
+ print_hex_dump_bytes(
+ KBUILD_MODNAME ": register: magic[decoded]: ",
+ DUMP_PREFIX_NONE, e->magic, e->size);
+
+ if (e->mask) {
+ int i;
+ char *masked = kmalloc(e->size, GFP_KERNEL);
+
+ print_hex_dump_bytes(
+ KBUILD_MODNAME ": register: mask[decoded]: ",
+ DUMP_PREFIX_NONE, e->mask, e->size);
+
+ if (masked) {
+ for (i = 0; i < e->size; ++i)
+ masked[i] = e->magic[i] & e->mask[i];
+ print_hex_dump_bytes(
+ KBUILD_MODNAME ": register: magic[masked]: ",
+ DUMP_PREFIX_NONE, masked, e->size);
+
+ kfree(masked);
+ }
+ }
+ }
} else {
+ /* Handle the 'E' (extension) format. */
+
+ /* Skip the 'offset' field. */
p = strchr(p, del);
if (!p)
- goto Einval;
+ goto einval;
*p++ = '\0';
+
+ /* Parse the 'magic' field. */
e->magic = p;
p = strchr(p, del);
if (!p)
- goto Einval;
+ goto einval;
*p++ = '\0';
if (!e->magic[0] || strchr(e->magic, '/'))
- goto Einval;
+ goto einval;
+ pr_debug("register: extension: {%s}\n", e->magic);
+
+ /* Skip the 'mask' field. */
p = strchr(p, del);
if (!p)
- goto Einval;
+ goto einval;
*p++ = '\0';
}
+
+ /* Parse the 'interpreter' field. */
e->interpreter = p;
p = strchr(p, del);
if (!p)
- goto Einval;
+ goto einval;
*p++ = '\0';
if (!e->interpreter[0])
- goto Einval;
-
-
- p = check_special_flags (p, e);
+ goto einval;
+ pr_debug("register: interpreter: {%s}\n", e->interpreter);
+ /* Parse the 'flags' field. */
+ p = check_special_flags(p, e);
if (*p == '\n')
p++;
if (p != buf + count)
- goto Einval;
+ goto einval;
+
return e;
out:
return ERR_PTR(err);
-Efault:
+efault:
kfree(e);
return ERR_PTR(-EFAULT);
-Einval:
+einval:
kfree(e);
return ERR_PTR(-EINVAL);
}
@@ -417,7 +503,7 @@ static int parse_command(const char __user *buffer, size_t count)
return -EFAULT;
if (!count)
return 0;
- if (s[count-1] == '\n')
+ if (s[count - 1] == '\n')
count--;
if (count == 1 && s[0] == '0')
return 1;
@@ -434,7 +520,7 @@ static void entry_status(Node *e, char *page)
{
char *dp;
char *status = "disabled";
- const char * flags = "flags: ";
+ const char *flags = "flags: ";
if (test_bit(Enabled, &e->flags))
status = "enabled";
@@ -448,19 +534,15 @@ static void entry_status(Node *e, char *page)
dp = page + strlen(page);
/* print the special flags */
- sprintf (dp, "%s", flags);
- dp += strlen (flags);
- if (e->flags & MISC_FMT_PRESERVE_ARGV0) {
- *dp ++ = 'P';
- }
- if (e->flags & MISC_FMT_OPEN_BINARY) {
- *dp ++ = 'O';
- }
- if (e->flags & MISC_FMT_CREDENTIALS) {
- *dp ++ = 'C';
- }
- *dp ++ = '\n';
-
+ sprintf(dp, "%s", flags);
+ dp += strlen(flags);
+ if (e->flags & MISC_FMT_PRESERVE_ARGV0)
+ *dp++ = 'P';
+ if (e->flags & MISC_FMT_OPEN_BINARY)
+ *dp++ = 'O';
+ if (e->flags & MISC_FMT_CREDENTIALS)
+ *dp++ = 'C';
+ *dp++ = '\n';
if (!test_bit(Magic, &e->flags)) {
sprintf(dp, "extension .%s\n", e->magic);
@@ -488,7 +570,7 @@ static void entry_status(Node *e, char *page)
static struct inode *bm_get_inode(struct super_block *sb, int mode)
{
- struct inode * inode = new_inode(sb);
+ struct inode *inode = new_inode(sb);
if (inode) {
inode->i_ino = get_next_ino();
@@ -528,13 +610,14 @@ static void kill_node(Node *e)
/* /<entry> */
static ssize_t
-bm_entry_read(struct file * file, char __user * buf, size_t nbytes, loff_t *ppos)
+bm_entry_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
{
Node *e = file_inode(file)->i_private;
ssize_t res;
char *page;
- if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+ page = (char *) __get_free_page(GFP_KERNEL);
+ if (!page)
return -ENOMEM;
entry_status(e, page);
@@ -553,20 +636,28 @@ static ssize_t bm_entry_write(struct file *file, const char __user *buffer,
int res = parse_command(buffer, count);
switch (res) {
- case 1: clear_bit(Enabled, &e->flags);
- break;
- case 2: set_bit(Enabled, &e->flags);
- break;
- case 3: root = dget(file->f_path.dentry->d_sb->s_root);
- mutex_lock(&root->d_inode->i_mutex);
-
- kill_node(e);
-
- mutex_unlock(&root->d_inode->i_mutex);
- dput(root);
- break;
- default: return res;
+ case 1:
+ /* Disable this handler. */
+ clear_bit(Enabled, &e->flags);
+ break;
+ case 2:
+ /* Enable this handler. */
+ set_bit(Enabled, &e->flags);
+ break;
+ case 3:
+ /* Delete this handler. */
+ root = dget(file->f_path.dentry->d_sb->s_root);
+ mutex_lock(&root->d_inode->i_mutex);
+
+ kill_node(e);
+
+ mutex_unlock(&root->d_inode->i_mutex);
+ dput(root);
+ break;
+ default:
+ return res;
}
+
return count;
}
@@ -654,26 +745,36 @@ bm_status_read(struct file *file, char __user *buf, size_t nbytes, loff_t *ppos)
return simple_read_from_buffer(buf, nbytes, ppos, s, strlen(s));
}
-static ssize_t bm_status_write(struct file * file, const char __user * buffer,
+static ssize_t bm_status_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
int res = parse_command(buffer, count);
struct dentry *root;
switch (res) {
- case 1: enabled = 0; break;
- case 2: enabled = 1; break;
- case 3: root = dget(file->f_path.dentry->d_sb->s_root);
- mutex_lock(&root->d_inode->i_mutex);
-
- while (!list_empty(&entries))
- kill_node(list_entry(entries.next, Node, list));
-
- mutex_unlock(&root->d_inode->i_mutex);
- dput(root);
- break;
- default: return res;
+ case 1:
+ /* Disable all handlers. */
+ enabled = 0;
+ break;
+ case 2:
+ /* Enable all handlers. */
+ enabled = 1;
+ break;
+ case 3:
+ /* Delete all handlers. */
+ root = dget(file->f_path.dentry->d_sb->s_root);
+ mutex_lock(&root->d_inode->i_mutex);
+
+ while (!list_empty(&entries))
+ kill_node(list_entry(entries.next, Node, list));
+
+ mutex_unlock(&root->d_inode->i_mutex);
+ dput(root);
+ break;
+ default:
+ return res;
}
+
return count;
}
@@ -690,14 +791,16 @@ static const struct super_operations s_ops = {
.evict_inode = bm_evict_inode,
};
-static int bm_fill_super(struct super_block * sb, void * data, int silent)
+static int bm_fill_super(struct super_block *sb, void *data, int silent)
{
+ int err;
static struct tree_descr bm_files[] = {
[2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO},
[3] = {"register", &bm_register_operations, S_IWUSR},
/* last one */ {""}
};
- int err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
+
+ err = simple_fill_super(sb, BINFMTFS_MAGIC, bm_files);
if (!err)
sb->s_op = &s_ops;
return err;
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 1d9c9f3..b48c41b 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -235,7 +235,10 @@ struct super_block *freeze_bdev(struct block_device *bdev)
sb = get_active_super(bdev);
if (!sb)
goto out;
- error = freeze_super(sb);
+ if (sb->s_op->freeze_super)
+ error = sb->s_op->freeze_super(sb);
+ else
+ error = freeze_super(sb);
if (error) {
deactivate_super(sb);
bdev->bd_fsfreeze_count--;
@@ -272,7 +275,10 @@ int thaw_bdev(struct block_device *bdev, struct super_block *sb)
if (!sb)
goto out;
- error = thaw_super(sb);
+ if (sb->s_op->thaw_super)
+ error = sb->s_op->thaw_super(sb);
+ else
+ error = thaw_super(sb);
if (error) {
bdev->bd_fsfreeze_count++;
mutex_unlock(&bdev->bd_fsfreeze_mutex);
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index d23362f..ff0dcc0 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -5303,7 +5303,7 @@ static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
return ERR_CAST(inode);
}
- return d_materialise_unique(dentry, inode);
+ return d_splice_alias(inode, dentry);
}
unsigned char btrfs_filetype_table[] = {
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 4399f0c..080fe66 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -5296,7 +5296,7 @@ long btrfs_ioctl(struct file *file, unsigned int
ret = btrfs_start_delalloc_roots(root->fs_info, 0, -1);
if (ret)
return ret;
- ret = btrfs_sync_fs(file->f_dentry->d_sb, 1);
+ ret = btrfs_sync_fs(file_inode(file)->i_sb, 1);
/*
* The transaction thread may want to do more work,
* namely it pokes the cleaner ktread that will start
diff --git a/fs/cachefiles/namei.c b/fs/cachefiles/namei.c
index e12f189..7f8e83f 100644
--- a/fs/cachefiles/namei.c
+++ b/fs/cachefiles/namei.c
@@ -102,8 +102,7 @@ static void cachefiles_mark_object_buried(struct cachefiles_cache *cache,
struct cachefiles_object *object;
struct rb_node *p;
- _enter(",'%*.*s'",
- dentry->d_name.len, dentry->d_name.len, dentry->d_name.name);
+ _enter(",'%pd'", dentry);
write_lock(&cache->active_lock);
@@ -273,9 +272,7 @@ static int cachefiles_bury_object(struct cachefiles_cache *cache,
char nbuffer[8 + 8 + 1];
int ret;
- _enter(",'%*.*s','%*.*s'",
- dir->d_name.len, dir->d_name.len, dir->d_name.name,
- rep->d_name.len, rep->d_name.len, rep->d_name.name);
+ _enter(",'%pd','%pd'", dir, rep);
_debug("remove %p from %p", rep, dir);
@@ -597,8 +594,7 @@ lookup_again:
/* if we've found that the terminal object exists, then we need to
* check its attributes and delete it if it's out of date */
if (!object->new) {
- _debug("validate '%*.*s'",
- next->d_name.len, next->d_name.len, next->d_name.name);
+ _debug("validate '%pd'", next);
ret = cachefiles_check_object_xattr(object, auxdata);
if (ret == -ESTALE) {
@@ -827,8 +823,8 @@ static struct dentry *cachefiles_check_active(struct cachefiles_cache *cache,
unsigned long start;
int ret;
- //_enter(",%*.*s/,%s",
- // dir->d_name.len, dir->d_name.len, dir->d_name.name, filename);
+ //_enter(",%pd/,%s",
+ // dir, filename);
/* look up the victim */
mutex_lock_nested(&dir->d_inode->i_mutex, I_MUTEX_PARENT);
@@ -910,8 +906,7 @@ int cachefiles_cull(struct cachefiles_cache *cache, struct dentry *dir,
struct dentry *victim;
int ret;
- _enter(",%*.*s/,%s",
- dir->d_name.len, dir->d_name.len, dir->d_name.name, filename);
+ _enter(",%pd/,%s", dir, filename);
victim = cachefiles_check_active(cache, dir, filename);
if (IS_ERR(victim))
@@ -969,8 +964,8 @@ int cachefiles_check_in_use(struct cachefiles_cache *cache, struct dentry *dir,
{
struct dentry *victim;
- //_enter(",%*.*s/,%s",
- // dir->d_name.len, dir->d_name.len, dir->d_name.name, filename);
+ //_enter(",%pd/,%s",
+ // dir, filename);
victim = cachefiles_check_active(cache, dir, filename);
if (IS_ERR(victim))
diff --git a/fs/cachefiles/xattr.c b/fs/cachefiles/xattr.c
index acbc1f0..a8a6874 100644
--- a/fs/cachefiles/xattr.c
+++ b/fs/cachefiles/xattr.c
@@ -51,9 +51,8 @@ int cachefiles_check_object_type(struct cachefiles_object *object)
}
if (ret != -EEXIST) {
- pr_err("Can't set xattr on %*.*s [%lu] (err %d)\n",
- dentry->d_name.len, dentry->d_name.len,
- dentry->d_name.name, dentry->d_inode->i_ino,
+ pr_err("Can't set xattr on %pd [%lu] (err %d)\n",
+ dentry, dentry->d_inode->i_ino,
-ret);
goto error;
}
@@ -64,9 +63,8 @@ int cachefiles_check_object_type(struct cachefiles_object *object)
if (ret == -ERANGE)
goto bad_type_length;
- pr_err("Can't read xattr on %*.*s [%lu] (err %d)\n",
- dentry->d_name.len, dentry->d_name.len,
- dentry->d_name.name, dentry->d_inode->i_ino,
+ pr_err("Can't read xattr on %pd [%lu] (err %d)\n",
+ dentry, dentry->d_inode->i_ino,
-ret);
goto error;
}
@@ -92,9 +90,8 @@ bad_type_length:
bad_type:
xtype[2] = 0;
- pr_err("Cache object %*.*s [%lu] type %s not %s\n",
- dentry->d_name.len, dentry->d_name.len,
- dentry->d_name.name, dentry->d_inode->i_ino,
+ pr_err("Cache object %pd [%lu] type %s not %s\n",
+ dentry, dentry->d_inode->i_ino,
xtype, type);
ret = -EIO;
goto error;
diff --git a/fs/ceph/debugfs.c b/fs/ceph/debugfs.c
index 5d5a4c8..1b23551 100644
--- a/fs/ceph/debugfs.c
+++ b/fs/ceph/debugfs.c
@@ -83,10 +83,9 @@ static int mdsc_show(struct seq_file *s, void *p)
if (IS_ERR(path))
path = NULL;
spin_lock(&req->r_dentry->d_lock);
- seq_printf(s, " #%llx/%.*s (%s)",
+ seq_printf(s, " #%llx/%pd (%s)",
ceph_ino(req->r_dentry->d_parent->d_inode),
- req->r_dentry->d_name.len,
- req->r_dentry->d_name.name,
+ req->r_dentry,
path ? path : "");
spin_unlock(&req->r_dentry->d_lock);
kfree(path);
@@ -103,11 +102,10 @@ static int mdsc_show(struct seq_file *s, void *p)
if (IS_ERR(path))
path = NULL;
spin_lock(&req->r_old_dentry->d_lock);
- seq_printf(s, " #%llx/%.*s (%s)",
+ seq_printf(s, " #%llx/%pd (%s)",
req->r_old_dentry_dir ?
ceph_ino(req->r_old_dentry_dir) : 0,
- req->r_old_dentry->d_name.len,
- req->r_old_dentry->d_name.name,
+ req->r_old_dentry,
path ? path : "");
spin_unlock(&req->r_old_dentry->d_lock);
kfree(path);
@@ -150,8 +148,8 @@ static int dentry_lru_show(struct seq_file *s, void *ptr)
spin_lock(&mdsc->dentry_lru_lock);
list_for_each_entry(di, &mdsc->dentry_lru, lru) {
struct dentry *dentry = di->dentry;
- seq_printf(s, "%p %p\t%.*s\n",
- di, dentry, dentry->d_name.len, dentry->d_name.name);
+ seq_printf(s, "%p %p\t%pd\n",
+ di, dentry, dentry);
}
spin_unlock(&mdsc->dentry_lru_lock);
diff --git a/fs/ceph/dir.c b/fs/ceph/dir.c
index e6d63f8..681a853 100644
--- a/fs/ceph/dir.c
+++ b/fs/ceph/dir.c
@@ -111,7 +111,7 @@ static int fpos_cmp(loff_t l, loff_t r)
/*
* When possible, we try to satisfy a readdir by peeking at the
* dcache. We make this work by carefully ordering dentries on
- * d_u.d_child when we initially get results back from the MDS, and
+ * d_child when we initially get results back from the MDS, and
* falling back to a "normal" sync readdir if any dentries in the dir
* are dropped.
*
@@ -123,7 +123,7 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx,
u32 shared_gen)
{
struct ceph_file_info *fi = file->private_data;
- struct dentry *parent = file->f_dentry;
+ struct dentry *parent = file->f_path.dentry;
struct inode *dir = parent->d_inode;
struct list_head *p;
struct dentry *dentry, *last;
@@ -147,11 +147,11 @@ static int __dcache_readdir(struct file *file, struct dir_context *ctx,
p = parent->d_subdirs.prev;
dout(" initial p %p/%p\n", p->prev, p->next);
} else {
- p = last->d_u.d_child.prev;
+ p = last->d_child.prev;
}
more:
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
while (1) {
dout(" p %p/%p %s d_subdirs %p/%p\n", p->prev, p->next,
@@ -168,13 +168,13 @@ more:
ceph_ino(dentry->d_inode) != CEPH_INO_CEPH &&
fpos_cmp(ctx->pos, di->offset) <= 0)
break;
- dout(" skipping %p %.*s at %llu (%llu)%s%s\n", dentry,
- dentry->d_name.len, dentry->d_name.name, di->offset,
+ dout(" skipping %p %pd at %llu (%llu)%s%s\n", dentry,
+ dentry, di->offset,
ctx->pos, d_unhashed(dentry) ? " unhashed" : "",
!dentry->d_inode ? " null" : "");
spin_unlock(&dentry->d_lock);
p = p->prev;
- dentry = list_entry(p, struct dentry, d_u.d_child);
+ dentry = list_entry(p, struct dentry, d_child);
di = ceph_dentry(dentry);
}
@@ -190,8 +190,8 @@ more:
goto out;
}
- dout(" %llu (%llu) dentry %p %.*s %p\n", di->offset, ctx->pos,
- dentry, dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+ dout(" %llu (%llu) dentry %p %pd %p\n", di->offset, ctx->pos,
+ dentry, dentry, dentry->d_inode);
if (!dir_emit(ctx, dentry->d_name.name,
dentry->d_name.len,
ceph_translate_ino(dentry->d_sb, dentry->d_inode->i_ino),
@@ -274,7 +274,7 @@ static int ceph_readdir(struct file *file, struct dir_context *ctx)
off = 1;
}
if (ctx->pos == 1) {
- ino_t ino = parent_ino(file->f_dentry);
+ ino_t ino = parent_ino(file->f_path.dentry);
dout("readdir off 1 -> '..'\n");
if (!dir_emit(ctx, "..", 2,
ceph_translate_ino(inode->i_sb, ino),
@@ -337,7 +337,7 @@ more:
}
req->r_inode = inode;
ihold(inode);
- req->r_dentry = dget(file->f_dentry);
+ req->r_dentry = dget(file->f_path.dentry);
/* hints to request -> mds selection code */
req->r_direct_mode = USE_AUTH_MDS;
req->r_direct_hash = ceph_frag_value(frag);
@@ -538,8 +538,8 @@ int ceph_handle_snapdir(struct ceph_mds_request *req,
strcmp(dentry->d_name.name,
fsc->mount_options->snapdir_name) == 0) {
struct inode *inode = ceph_get_snapdir(parent);
- dout("ENOENT on snapdir %p '%.*s', linking to snapdir %p\n",
- dentry, dentry->d_name.len, dentry->d_name.name, inode);
+ dout("ENOENT on snapdir %p '%pd', linking to snapdir %p\n",
+ dentry, dentry, inode);
BUG_ON(!d_unhashed(dentry));
d_add(dentry, inode);
err = 0;
@@ -603,8 +603,8 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
int op;
int err;
- dout("lookup %p dentry %p '%.*s'\n",
- dir, dentry, dentry->d_name.len, dentry->d_name.name);
+ dout("lookup %p dentry %p '%pd'\n",
+ dir, dentry, dentry);
if (dentry->d_name.len > NAME_MAX)
return ERR_PTR(-ENAMETOOLONG);
@@ -774,8 +774,8 @@ static int ceph_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
if (ceph_snap(dir) == CEPH_SNAPDIR) {
/* mkdir .snap/foo is a MKSNAP */
op = CEPH_MDS_OP_MKSNAP;
- dout("mksnap dir %p snap '%.*s' dn %p\n", dir,
- dentry->d_name.len, dentry->d_name.name, dentry);
+ dout("mksnap dir %p snap '%pd' dn %p\n", dir,
+ dentry, dentry);
} else if (ceph_snap(dir) == CEPH_NOSNAP) {
dout("mkdir dir %p dn %p mode 0%ho\n", dir, dentry, mode);
op = CEPH_MDS_OP_MKDIR;
@@ -888,8 +888,7 @@ static int ceph_unlink(struct inode *dir, struct dentry *dentry)
if (ceph_snap(dir) == CEPH_SNAPDIR) {
/* rmdir .snap/foo is RMSNAP */
- dout("rmsnap dir %p '%.*s' dn %p\n", dir, dentry->d_name.len,
- dentry->d_name.name, dentry);
+ dout("rmsnap dir %p '%pd' dn %p\n", dir, dentry, dentry);
op = CEPH_MDS_OP_RMSNAP;
} else if (ceph_snap(dir) == CEPH_NOSNAP) {
dout("unlink/rmdir dir %p dn %p inode %p\n",
@@ -1063,16 +1062,15 @@ static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
if (flags & LOOKUP_RCU)
return -ECHILD;
- dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
- dentry->d_name.len, dentry->d_name.name, dentry->d_inode,
- ceph_dentry(dentry)->offset);
+ dout("d_revalidate %p '%pd' inode %p offset %lld\n", dentry,
+ dentry, dentry->d_inode, ceph_dentry(dentry)->offset);
dir = ceph_get_dentry_parent_inode(dentry);
/* always trust cached snapped dentries, snapdir dentry */
if (ceph_snap(dir) != CEPH_NOSNAP) {
- dout("d_revalidate %p '%.*s' inode %p is SNAPPED\n", dentry,
- dentry->d_name.len, dentry->d_name.name, dentry->d_inode);
+ dout("d_revalidate %p '%pd' inode %p is SNAPPED\n", dentry,
+ dentry, dentry->d_inode);
valid = 1;
} else if (dentry->d_inode &&
ceph_snap(dentry->d_inode) == CEPH_SNAPDIR) {
@@ -1265,8 +1263,7 @@ void ceph_dentry_lru_add(struct dentry *dn)
struct ceph_dentry_info *di = ceph_dentry(dn);
struct ceph_mds_client *mdsc;
- dout("dentry_lru_add %p %p '%.*s'\n", di, dn,
- dn->d_name.len, dn->d_name.name);
+ dout("dentry_lru_add %p %p '%pd'\n", di, dn, dn);
mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
spin_lock(&mdsc->dentry_lru_lock);
list_add_tail(&di->lru, &mdsc->dentry_lru);
@@ -1279,8 +1276,8 @@ void ceph_dentry_lru_touch(struct dentry *dn)
struct ceph_dentry_info *di = ceph_dentry(dn);
struct ceph_mds_client *mdsc;
- dout("dentry_lru_touch %p %p '%.*s' (offset %lld)\n", di, dn,
- dn->d_name.len, dn->d_name.name, di->offset);
+ dout("dentry_lru_touch %p %p '%pd' (offset %lld)\n", di, dn, dn,
+ di->offset);
mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
spin_lock(&mdsc->dentry_lru_lock);
list_move_tail(&di->lru, &mdsc->dentry_lru);
@@ -1292,8 +1289,7 @@ void ceph_dentry_lru_del(struct dentry *dn)
struct ceph_dentry_info *di = ceph_dentry(dn);
struct ceph_mds_client *mdsc;
- dout("dentry_lru_del %p %p '%.*s'\n", di, dn,
- dn->d_name.len, dn->d_name.name);
+ dout("dentry_lru_del %p %p '%pd'\n", di, dn, dn);
mdsc = ceph_sb_to_client(dn->d_sb)->mdsc;
spin_lock(&mdsc->dentry_lru_lock);
list_del_init(&di->lru);
diff --git a/fs/ceph/file.c b/fs/ceph/file.c
index d7e0da8..9f8e357 100644
--- a/fs/ceph/file.c
+++ b/fs/ceph/file.c
@@ -211,7 +211,7 @@ int ceph_open(struct inode *inode, struct file *file)
req->r_num_caps = 1;
if (flags & O_CREAT)
- parent_inode = ceph_get_dentry_parent_inode(file->f_dentry);
+ parent_inode = ceph_get_dentry_parent_inode(file->f_path.dentry);
err = ceph_mdsc_do_request(mdsc, parent_inode, req);
iput(parent_inode);
if (!err)
@@ -238,8 +238,8 @@ int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
struct ceph_acls_info acls = {};
int err;
- dout("atomic_open %p dentry %p '%.*s' %s flags %d mode 0%o\n",
- dir, dentry, dentry->d_name.len, dentry->d_name.name,
+ dout("atomic_open %p dentry %p '%pd' %s flags %d mode 0%o\n",
+ dir, dentry, dentry,
d_unhashed(dentry) ? "unhashed" : "hashed", flags, mode);
if (dentry->d_name.len > NAME_MAX)
diff --git a/fs/ceph/inode.c b/fs/ceph/inode.c
index 7b61390..a5593d5 100644
--- a/fs/ceph/inode.c
+++ b/fs/ceph/inode.c
@@ -967,7 +967,7 @@ static struct dentry *splice_dentry(struct dentry *dn, struct inode *in,
/* dn must be unhashed */
if (!d_unhashed(dn))
d_drop(dn);
- realdn = d_materialise_unique(dn, in);
+ realdn = d_splice_alias(in, dn);
if (IS_ERR(realdn)) {
pr_err("splice_dentry error %ld %p inode %p ino %llx.%llx\n",
PTR_ERR(realdn), dn, in, ceph_vinop(in));
@@ -1186,20 +1186,18 @@ retry_lookup:
struct inode *olddir = req->r_old_dentry_dir;
BUG_ON(!olddir);
- dout(" src %p '%.*s' dst %p '%.*s'\n",
+ dout(" src %p '%pd' dst %p '%pd'\n",
req->r_old_dentry,
- req->r_old_dentry->d_name.len,
- req->r_old_dentry->d_name.name,
- dn, dn->d_name.len, dn->d_name.name);
+ req->r_old_dentry,
+ dn, dn);
dout("fill_trace doing d_move %p -> %p\n",
req->r_old_dentry, dn);
d_move(req->r_old_dentry, dn);
- dout(" src %p '%.*s' dst %p '%.*s'\n",
+ dout(" src %p '%pd' dst %p '%pd'\n",
+ req->r_old_dentry,
req->r_old_dentry,
- req->r_old_dentry->d_name.len,
- req->r_old_dentry->d_name.name,
- dn, dn->d_name.len, dn->d_name.name);
+ dn, dn);
/* ensure target dentry is invalidated, despite
rehashing bug in vfs_rename_dir */
@@ -1399,7 +1397,7 @@ retry_lookup:
/* reorder parent's d_subdirs */
spin_lock(&parent->d_lock);
spin_lock_nested(&dn->d_lock, DENTRY_D_LOCK_NESTED);
- list_move(&dn->d_u.d_child, &parent->d_subdirs);
+ list_move(&dn->d_child, &parent->d_subdirs);
spin_unlock(&dn->d_lock);
spin_unlock(&parent->d_lock);
}
diff --git a/fs/char_dev.c b/fs/char_dev.c
index f77f770..67b2007 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -117,7 +117,6 @@ __register_chrdev_region(unsigned int major, unsigned int baseminor,
goto out;
}
major = i;
- ret = major;
}
cd->major = major;
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 44ec726..9c56ef7 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -34,27 +34,9 @@
void
cifs_dump_mem(char *label, void *data, int length)
{
- int i, j;
- int *intptr = data;
- char *charptr = data;
- char buf[10], line[80];
-
- printk(KERN_DEBUG "%s: dump of %d bytes of data at 0x%p\n",
- label, length, data);
- for (i = 0; i < length; i += 16) {
- line[0] = 0;
- for (j = 0; (j < 4) && (i + j * 4 < length); j++) {
- sprintf(buf, " %08x", intptr[i / 4 + j]);
- strcat(line, buf);
- }
- buf[0] = ' ';
- buf[2] = 0;
- for (j = 0; (j < 16) && (i + j < length); j++) {
- buf[1] = isprint(charptr[i + j]) ? charptr[i + j] : '.';
- strcat(line, buf);
- }
- printk(KERN_DEBUG "%s\n", line);
- }
+ pr_debug("%s: dump of %d bytes of data at 0x%p\n", label, length, data);
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_OFFSET, 16, 4,
+ data, length, true);
}
#ifdef CONFIG_CIFS_DEBUG
@@ -68,7 +50,7 @@ void cifs_vfs_err(const char *fmt, ...)
vaf.fmt = fmt;
vaf.va = &args;
- printk(KERN_ERR "CIFS VFS: %pV", &vaf);
+ pr_err("CIFS VFS: %pV", &vaf);
va_end(args);
}
@@ -274,6 +256,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
+ bool bv;
int rc;
struct list_head *tmp1, *tmp2, *tmp3;
struct TCP_Server_Info *server;
@@ -284,7 +267,7 @@ static ssize_t cifs_stats_proc_write(struct file *file,
if (rc)
return rc;
- if (c == '1' || c == 'y' || c == 'Y' || c == '0') {
+ if (strtobool(&c, &bv) == 0) {
#ifdef CONFIG_CIFS_STATS2
atomic_set(&totBufAllocCount, 0);
atomic_set(&totSmBufAllocCount, 0);
@@ -451,15 +434,14 @@ static ssize_t cifsFYI_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char c;
+ bool bv;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
- if (c == '0' || c == 'n' || c == 'N')
- cifsFYI = 0;
- else if (c == '1' || c == 'y' || c == 'Y')
- cifsFYI = 1;
+ if (strtobool(&c, &bv) == 0)
+ cifsFYI = bv;
else if ((c > '1') && (c <= '9'))
cifsFYI = (int) (c - '0'); /* see cifs_debug.h for meanings */
@@ -490,15 +472,18 @@ static ssize_t cifs_linux_ext_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
+ bool bv;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
- if (c == '0' || c == 'n' || c == 'N')
- linuxExtEnabled = 0;
- else if (c == '1' || c == 'y' || c == 'Y')
- linuxExtEnabled = 1;
+
+ rc = strtobool(&c, &bv);
+ if (rc)
+ return rc;
+
+ linuxExtEnabled = bv;
return count;
}
@@ -527,15 +512,18 @@ static ssize_t cifs_lookup_cache_proc_write(struct file *file,
const char __user *buffer, size_t count, loff_t *ppos)
{
char c;
+ bool bv;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
- if (c == '0' || c == 'n' || c == 'N')
- lookupCacheEnabled = 0;
- else if (c == '1' || c == 'y' || c == 'Y')
- lookupCacheEnabled = 1;
+
+ rc = strtobool(&c, &bv);
+ if (rc)
+ return rc;
+
+ lookupCacheEnabled = bv;
return count;
}
@@ -564,15 +552,18 @@ static ssize_t traceSMB_proc_write(struct file *file, const char __user *buffer,
size_t count, loff_t *ppos)
{
char c;
+ bool bv;
int rc;
rc = get_user(c, buffer);
if (rc)
return rc;
- if (c == '0' || c == 'n' || c == 'N')
- traceSMB = 0;
- else if (c == '1' || c == 'y' || c == 'Y')
- traceSMB = 1;
+
+ rc = strtobool(&c, &bv);
+ if (rc)
+ return rc;
+
+ traceSMB = bv;
return count;
}
@@ -630,6 +621,7 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
unsigned int flags;
char flags_string[12];
char c;
+ bool bv;
if ((count < 1) || (count > 11))
return -EINVAL;
@@ -642,11 +634,8 @@ static ssize_t cifs_security_flags_proc_write(struct file *file,
if (count < 3) {
/* single char or single char followed by null */
c = flags_string[0];
- if (c == '0' || c == 'n' || c == 'N') {
- global_secflags = CIFSSEC_DEF; /* default */
- return count;
- } else if (c == '1' || c == 'y' || c == 'Y') {
- global_secflags = CIFSSEC_MAX;
+ if (strtobool(&c, &bv) == 0) {
+ global_secflags = bv ? CIFSSEC_MAX : CIFSSEC_DEF;
return count;
} else if (!isdigit(c)) {
cifs_dbg(VFS, "Invalid SecurityFlags: %s\n",
diff --git a/fs/cifs/cifs_debug.h b/fs/cifs/cifs_debug.h
index c99b40f..f40fbac 100644
--- a/fs/cifs/cifs_debug.h
+++ b/fs/cifs/cifs_debug.h
@@ -53,13 +53,12 @@ __printf(1, 2) void cifs_vfs_err(const char *fmt, ...);
do { \
if (type == FYI) { \
if (cifsFYI & CIFS_INFO) { \
- printk(KERN_DEBUG "%s: " fmt, \
- __FILE__, ##__VA_ARGS__); \
+ pr_debug("%s: " fmt, __FILE__, ##__VA_ARGS__); \
} \
} else if (type == VFS) { \
cifs_vfs_err(fmt, ##__VA_ARGS__); \
} else if (type == NOISY && type != 0) { \
- printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
+ pr_debug(fmt, ##__VA_ARGS__); \
} \
} while (0)
@@ -71,7 +70,7 @@ do { \
#define cifs_dbg(type, fmt, ...) \
do { \
if (0) \
- printk(KERN_DEBUG fmt, ##__VA_ARGS__); \
+ pr_debug(fmt, ##__VA_ARGS__); \
} while (0)
#endif
diff --git a/fs/cifs/cifsacl.c b/fs/cifs/cifsacl.c
index 6d00c41..1ea780b 100644
--- a/fs/cifs/cifsacl.c
+++ b/fs/cifs/cifsacl.c
@@ -38,7 +38,7 @@ static const struct cifs_sid sid_everyone = {
1, 1, {0, 0, 0, 0, 0, 1}, {0} };
/* security id for Authenticated Users system group */
static const struct cifs_sid sid_authusers = {
- 1, 1, {0, 0, 0, 0, 0, 5}, {__constant_cpu_to_le32(11)} };
+ 1, 1, {0, 0, 0, 0, 0, 5}, {cpu_to_le32(11)} };
/* group users */
static const struct cifs_sid sid_user = {1, 2 , {0, 0, 0, 0, 0, 5}, {} };
diff --git a/fs/cifs/cifsfs.c b/fs/cifs/cifsfs.c
index 9d7996e..d72fe37 100644
--- a/fs/cifs/cifsfs.c
+++ b/fs/cifs/cifsfs.c
@@ -209,8 +209,7 @@ cifs_statfs(struct dentry *dentry, struct kstatfs *buf)
static long cifs_fallocate(struct file *file, int mode, loff_t off, loff_t len)
{
- struct super_block *sb = file->f_path.dentry->d_sb;
- struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+ struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
struct cifs_tcon *tcon = cifs_sb_master_tcon(cifs_sb);
struct TCP_Server_Info *server = tcon->ses->server;
diff --git a/fs/cifs/cifsfs.h b/fs/cifs/cifsfs.h
index 002e0c1..252f5c1 100644
--- a/fs/cifs/cifsfs.h
+++ b/fs/cifs/cifsfs.h
@@ -136,5 +136,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
extern const struct export_operations cifs_export_ops;
#endif /* CONFIG_CIFS_NFSD_EXPORT */
-#define CIFS_VERSION "2.05"
+#define CIFS_VERSION "2.06"
#endif /* _CIFSFS_H */
diff --git a/fs/cifs/cifsglob.h b/fs/cifs/cifsglob.h
index 02a33e5..6e13911 100644
--- a/fs/cifs/cifsglob.h
+++ b/fs/cifs/cifsglob.h
@@ -1168,6 +1168,12 @@ CIFS_SB(struct super_block *sb)
return sb->s_fs_info;
}
+static inline struct cifs_sb_info *
+CIFS_FILE_SB(struct file *file)
+{
+ return CIFS_SB(file_inode(file)->i_sb);
+}
+
static inline char CIFS_DIR_SEP(const struct cifs_sb_info *cifs_sb)
{
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)
diff --git a/fs/cifs/cifssmb.c b/fs/cifs/cifssmb.c
index 61d00a6..fa13d5e 100644
--- a/fs/cifs/cifssmb.c
+++ b/fs/cifs/cifssmb.c
@@ -2477,14 +2477,14 @@ CIFSSMBPosixLock(const unsigned int xid, struct cifs_tcon *tcon,
}
parm_data = (struct cifs_posix_lock *)
((char *)&pSMBr->hdr.Protocol + data_offset);
- if (parm_data->lock_type == __constant_cpu_to_le16(CIFS_UNLCK))
+ if (parm_data->lock_type == cpu_to_le16(CIFS_UNLCK))
pLockData->fl_type = F_UNLCK;
else {
if (parm_data->lock_type ==
- __constant_cpu_to_le16(CIFS_RDLCK))
+ cpu_to_le16(CIFS_RDLCK))
pLockData->fl_type = F_RDLCK;
else if (parm_data->lock_type ==
- __constant_cpu_to_le16(CIFS_WRLCK))
+ cpu_to_le16(CIFS_WRLCK))
pLockData->fl_type = F_WRLCK;
pLockData->fl_start = le64_to_cpu(parm_data->start);
@@ -3276,25 +3276,25 @@ CIFSSMB_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
pSMB->compression_state = cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
pSMB->TotalParameterCount = 0;
- pSMB->TotalDataCount = __constant_cpu_to_le32(2);
+ pSMB->TotalDataCount = cpu_to_le32(2);
pSMB->MaxParameterCount = 0;
pSMB->MaxDataCount = 0;
pSMB->MaxSetupCount = 4;
pSMB->Reserved = 0;
pSMB->ParameterOffset = 0;
- pSMB->DataCount = __constant_cpu_to_le32(2);
+ pSMB->DataCount = cpu_to_le32(2);
pSMB->DataOffset =
cpu_to_le32(offsetof(struct smb_com_transaction_compr_ioctl_req,
compression_state) - 4); /* 84 */
pSMB->SetupCount = 4;
- pSMB->SubCommand = __constant_cpu_to_le16(NT_TRANSACT_IOCTL);
+ pSMB->SubCommand = cpu_to_le16(NT_TRANSACT_IOCTL);
pSMB->ParameterCount = 0;
- pSMB->FunctionCode = __constant_cpu_to_le32(FSCTL_SET_COMPRESSION);
+ pSMB->FunctionCode = cpu_to_le32(FSCTL_SET_COMPRESSION);
pSMB->IsFsctl = 1; /* FSCTL */
pSMB->IsRootFlag = 0;
pSMB->Fid = fid; /* file handle always le */
/* 3 byte pad, followed by 2 byte compress state */
- pSMB->ByteCount = __constant_cpu_to_le16(5);
+ pSMB->ByteCount = cpu_to_le16(5);
inc_rfc1001_len(pSMB, 5);
rc = SendReceive(xid, tcon->ses, (struct smb_hdr *) pSMB,
@@ -3430,10 +3430,10 @@ static __u16 ACL_to_cifs_posix(char *parm_data, const char *pACL,
cifs_acl->version = cpu_to_le16(1);
if (acl_type == ACL_TYPE_ACCESS) {
cifs_acl->access_entry_count = cpu_to_le16(count);
- cifs_acl->default_entry_count = __constant_cpu_to_le16(0xFFFF);
+ cifs_acl->default_entry_count = cpu_to_le16(0xFFFF);
} else if (acl_type == ACL_TYPE_DEFAULT) {
cifs_acl->default_entry_count = cpu_to_le16(count);
- cifs_acl->access_entry_count = __constant_cpu_to_le16(0xFFFF);
+ cifs_acl->access_entry_count = cpu_to_le16(0xFFFF);
} else {
cifs_dbg(FYI, "unknown ACL type %d\n", acl_type);
return 0;
diff --git a/fs/cifs/connect.c b/fs/cifs/connect.c
index 24fa08d..2a772da 100644
--- a/fs/cifs/connect.c
+++ b/fs/cifs/connect.c
@@ -1466,9 +1466,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->seal = 1;
break;
case Opt_noac:
- printk(KERN_WARNING "CIFS: Mount option noac not "
- "supported. Instead set "
- "/proc/fs/cifs/LookupCacheEnabled to 0\n");
+ pr_warn("CIFS: Mount option noac not supported. Instead set /proc/fs/cifs/LookupCacheEnabled to 0\n");
break;
case Opt_fsc:
#ifndef CONFIG_CIFS_FSCACHE
@@ -1598,7 +1596,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (strnlen(string, CIFS_MAX_USERNAME_LEN) >
CIFS_MAX_USERNAME_LEN) {
- printk(KERN_WARNING "CIFS: username too long\n");
+ pr_warn("CIFS: username too long\n");
goto cifs_parse_mount_err;
}
vol->username = kstrdup(string, GFP_KERNEL);
@@ -1662,8 +1660,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
temp_len = strlen(value);
vol->password = kzalloc(temp_len+1, GFP_KERNEL);
if (vol->password == NULL) {
- printk(KERN_WARNING "CIFS: no memory "
- "for password\n");
+ pr_warn("CIFS: no memory for password\n");
goto cifs_parse_mount_err;
}
@@ -1687,8 +1684,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (!cifs_convert_address(dstaddr, string,
strlen(string))) {
- printk(KERN_ERR "CIFS: bad ip= option (%s).\n",
- string);
+ pr_err("CIFS: bad ip= option (%s).\n", string);
goto cifs_parse_mount_err;
}
got_ip = true;
@@ -1700,15 +1696,13 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (strnlen(string, CIFS_MAX_DOMAINNAME_LEN)
== CIFS_MAX_DOMAINNAME_LEN) {
- printk(KERN_WARNING "CIFS: domain name too"
- " long\n");
+ pr_warn("CIFS: domain name too long\n");
goto cifs_parse_mount_err;
}
vol->domainname = kstrdup(string, GFP_KERNEL);
if (!vol->domainname) {
- printk(KERN_WARNING "CIFS: no memory "
- "for domainname\n");
+ pr_warn("CIFS: no memory for domainname\n");
goto cifs_parse_mount_err;
}
cifs_dbg(FYI, "Domain name set\n");
@@ -1721,8 +1715,8 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (!cifs_convert_address(
(struct sockaddr *)&vol->srcaddr,
string, strlen(string))) {
- printk(KERN_WARNING "CIFS: Could not parse"
- " srcaddr: %s\n", string);
+ pr_warn("CIFS: Could not parse srcaddr: %s\n",
+ string);
goto cifs_parse_mount_err;
}
break;
@@ -1732,8 +1726,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
goto out_nomem;
if (strnlen(string, 1024) >= 65) {
- printk(KERN_WARNING "CIFS: iocharset name "
- "too long.\n");
+ pr_warn("CIFS: iocharset name too long.\n");
goto cifs_parse_mount_err;
}
@@ -1741,8 +1734,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
vol->iocharset = kstrdup(string,
GFP_KERNEL);
if (!vol->iocharset) {
- printk(KERN_WARNING "CIFS: no memory"
- "for charset\n");
+ pr_warn("CIFS: no memory for charset\n");
goto cifs_parse_mount_err;
}
}
@@ -1773,9 +1765,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
* set at top of the function
*/
if (i == RFC1001_NAME_LEN && string[i] != 0)
- printk(KERN_WARNING "CIFS: netbiosname"
- " longer than 15 truncated.\n");
-
+ pr_warn("CIFS: netbiosname longer than 15 truncated.\n");
break;
case Opt_servern:
/* servernetbiosname specified override *SMBSERVER */
@@ -1801,8 +1791,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
/* The string has 16th byte zero still from
set at top of the function */
if (i == RFC1001_NAME_LEN && string[i] != 0)
- printk(KERN_WARNING "CIFS: server net"
- "biosname longer than 15 truncated.\n");
+ pr_warn("CIFS: server netbiosname longer than 15 truncated.\n");
break;
case Opt_ver:
string = match_strdup(args);
@@ -1814,8 +1803,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
break;
}
/* For all other value, error */
- printk(KERN_WARNING "CIFS: Invalid version"
- " specified\n");
+ pr_warn("CIFS: Invalid version specified\n");
goto cifs_parse_mount_err;
case Opt_vers:
string = match_strdup(args);
@@ -1856,7 +1844,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
}
if (!sloppy && invalid) {
- printk(KERN_ERR "CIFS: Unknown mount option \"%s\"\n", invalid);
+ pr_err("CIFS: Unknown mount option \"%s\"\n", invalid);
goto cifs_parse_mount_err;
}
@@ -1882,8 +1870,7 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
/* No ip= option specified? Try to get it from UNC */
if (!cifs_convert_address(dstaddr, &vol->UNC[2],
strlen(&vol->UNC[2]))) {
- printk(KERN_ERR "Unable to determine destination "
- "address.\n");
+ pr_err("Unable to determine destination address.\n");
goto cifs_parse_mount_err;
}
}
@@ -1894,20 +1881,18 @@ cifs_parse_mount_options(const char *mountdata, const char *devname,
if (uid_specified)
vol->override_uid = override_uid;
else if (override_uid == 1)
- printk(KERN_NOTICE "CIFS: ignoring forceuid mount option "
- "specified with no uid= option.\n");
+ pr_notice("CIFS: ignoring forceuid mount option specified with no uid= option.\n");
if (gid_specified)
vol->override_gid = override_gid;
else if (override_gid == 1)
- printk(KERN_NOTICE "CIFS: ignoring forcegid mount option "
- "specified with no gid= option.\n");
+ pr_notice("CIFS: ignoring forcegid mount option specified with no gid= option.\n");
kfree(mountdata_copy);
return 0;
out_nomem:
- printk(KERN_WARNING "Could not allocate temporary buffer\n");
+ pr_warn("Could not allocate temporary buffer\n");
cifs_parse_mount_err:
kfree(string);
kfree(mountdata_copy);
diff --git a/fs/cifs/file.c b/fs/cifs/file.c
index 3e4d00a..96b7e9b 100644
--- a/fs/cifs/file.c
+++ b/fs/cifs/file.c
@@ -1066,7 +1066,7 @@ cifs_push_mandatory_locks(struct cifsFileInfo *cfile)
max_num = (max_buf - sizeof(struct smb_hdr)) /
sizeof(LOCKING_ANDX_RANGE);
- buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
+ buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
if (!buf) {
free_xid(xid);
return -ENOMEM;
@@ -1401,7 +1401,7 @@ cifs_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
max_num = (max_buf - sizeof(struct smb_hdr)) /
sizeof(LOCKING_ANDX_RANGE);
- buf = kzalloc(max_num * sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
+ buf = kcalloc(max_num, sizeof(LOCKING_ANDX_RANGE), GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -1586,7 +1586,7 @@ int cifs_lock(struct file *file, int cmd, struct file_lock *flock)
cifs_read_flock(flock, &type, &lock, &unlock, &wait_flag,
tcon->ses->server);
- cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ cifs_sb = CIFS_FILE_SB(file);
netfid = cfile->fid.netfid;
cinode = CIFS_I(file_inode(file));
@@ -2305,7 +2305,7 @@ int cifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
struct cifsFileInfo *smbfile = file->private_data;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
struct inode *inode = file->f_mapping->host;
rc = filemap_write_and_wait_range(inode->i_mapping, start, end);
@@ -2585,7 +2585,7 @@ cifs_iovec_write(struct file *file, struct iov_iter *from, loff_t *poffset)
iov_iter_truncate(from, len);
INIT_LIST_HEAD(&wdata_list);
- cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ cifs_sb = CIFS_FILE_SB(file);
open_file = file->private_data;
tcon = tlink_tcon(open_file->tlink);
@@ -3010,7 +3010,7 @@ ssize_t cifs_user_readv(struct kiocb *iocb, struct iov_iter *to)
return 0;
INIT_LIST_HEAD(&rdata_list);
- cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ cifs_sb = CIFS_FILE_SB(file);
open_file = file->private_data;
tcon = tlink_tcon(open_file->tlink);
@@ -3155,7 +3155,7 @@ cifs_read(struct file *file, char *read_data, size_t read_size, loff_t *offset)
__u32 pid;
xid = get_xid();
- cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ cifs_sb = CIFS_FILE_SB(file);
/* FIXME: set up handlers for larger reads and/or convert to async */
rsize = min_t(unsigned int, cifs_sb->rsize, CIFSMaxBufSize);
@@ -3462,7 +3462,7 @@ static int cifs_readpages(struct file *file, struct address_space *mapping,
int rc;
struct list_head tmplist;
struct cifsFileInfo *open_file = file->private_data;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
struct TCP_Server_Info *server;
pid_t pid;
diff --git a/fs/cifs/inode.c b/fs/cifs/inode.c
index 197cb50..0c3ce464 100644
--- a/fs/cifs/inode.c
+++ b/fs/cifs/inode.c
@@ -895,7 +895,7 @@ inode_has_hashed_dentries(struct inode *inode)
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
spin_unlock(&inode->i_lock);
return true;
diff --git a/fs/cifs/misc.c b/fs/cifs/misc.c
index b7415d5..3379463 100644
--- a/fs/cifs/misc.c
+++ b/fs/cifs/misc.c
@@ -513,39 +513,11 @@ is_valid_oplock_break(char *buffer, struct TCP_Server_Info *srv)
void
dump_smb(void *buf, int smb_buf_length)
{
- int i, j;
- char debug_line[17];
- unsigned char *buffer = buf;
-
if (traceSMB == 0)
return;
- for (i = 0, j = 0; i < smb_buf_length; i++, j++) {
- if (i % 8 == 0) {
- /* have reached the beginning of line */
- printk(KERN_DEBUG "| ");
- j = 0;
- }
- printk("%0#4x ", buffer[i]);
- debug_line[2 * j] = ' ';
- if (isprint(buffer[i]))
- debug_line[1 + (2 * j)] = buffer[i];
- else
- debug_line[1 + (2 * j)] = '_';
-
- if (i % 8 == 7) {
- /* reached end of line, time to print ascii */
- debug_line[16] = 0;
- printk(" | %s\n", debug_line);
- }
- }
- for (; j < 8; j++) {
- printk(" ");
- debug_line[2 * j] = ' ';
- debug_line[1 + (2 * j)] = ' ';
- }
- printk(" | %s\n", debug_line);
- return;
+ print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, 8, 2, buf,
+ smb_buf_length, true);
}
void
diff --git a/fs/cifs/readdir.c b/fs/cifs/readdir.c
index 8fd2a95..8eaf20a 100644
--- a/fs/cifs/readdir.c
+++ b/fs/cifs/readdir.c
@@ -123,7 +123,7 @@ cifs_prime_dcache(struct dentry *parent, struct qstr *name,
if (!inode)
goto out;
- alias = d_materialise_unique(dentry, inode);
+ alias = d_splice_alias(inode, dentry);
if (alias && !IS_ERR(alias))
dput(alias);
out:
@@ -261,7 +261,7 @@ initiate_cifs_search(const unsigned int xid, struct file *file)
int rc = 0;
char *full_path = NULL;
struct cifsFileInfo *cifsFile;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
struct tcon_link *tlink = NULL;
struct cifs_tcon *tcon;
struct TCP_Server_Info *server;
@@ -561,7 +561,7 @@ find_cifs_entry(const unsigned int xid, struct cifs_tcon *tcon, loff_t pos,
loff_t first_entry_in_buffer;
loff_t index_to_find = pos;
struct cifsFileInfo *cfile = file->private_data;
- struct cifs_sb_info *cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
+ struct cifs_sb_info *cifs_sb = CIFS_FILE_SB(file);
struct TCP_Server_Info *server = tcon->ses->server;
/* check if index in the buffer */
@@ -679,7 +679,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
char *scratch_buf, unsigned int max_len)
{
struct cifsFileInfo *file_info = file->private_data;
- struct super_block *sb = file->f_path.dentry->d_sb;
+ struct super_block *sb = file_inode(file)->i_sb;
struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
struct cifs_dirent de = { NULL, };
struct cifs_fattr fattr;
@@ -753,7 +753,7 @@ static int cifs_filldir(char *find_entry, struct file *file,
*/
fattr.cf_flags |= CIFS_FATTR_NEED_REVAL;
- cifs_prime_dcache(file->f_dentry, &name, &fattr);
+ cifs_prime_dcache(file->f_path.dentry, &name, &fattr);
ino = cifs_uniqueid_to_ino_t(fattr.cf_uniqueid);
return !dir_emit(ctx, name.name, name.len, ino, fattr.cf_dtype);
@@ -794,10 +794,6 @@ int cifs_readdir(struct file *file, struct dir_context *ctx)
if it before then restart search
if after then keep searching till find it */
- if (file->private_data == NULL) {
- rc = -EINVAL;
- goto rddir2_exit;
- }
cifsFile = file->private_data;
if (cifsFile->srch_inf.endOfSearch) {
if (cifsFile->srch_inf.emptyDir) {
diff --git a/fs/cifs/sess.c b/fs/cifs/sess.c
index 57db63f..bce6fdc 100644
--- a/fs/cifs/sess.c
+++ b/fs/cifs/sess.c
@@ -46,7 +46,7 @@ static __u32 cifs_ssetup_hdr(struct cifs_ses *ses, SESSION_SETUP_ANDX *pSMB)
CIFSMaxBufSize + MAX_CIFS_HDR_SIZE - 4,
USHRT_MAX));
pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
- pSMB->req.VcNumber = __constant_cpu_to_le16(1);
+ pSMB->req.VcNumber = cpu_to_le16(1);
/* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
@@ -1303,6 +1303,11 @@ sess_auth_rawntlmssp_authenticate(struct sess_data *sess_data)
if (le16_to_cpu(pSMB->resp.Action) & GUEST_LOGIN)
cifs_dbg(FYI, "Guest login\n"); /* BB mark SesInfo struct? */
+ if (ses->Suid != smb_buf->Uid) {
+ ses->Suid = smb_buf->Uid;
+ cifs_dbg(FYI, "UID changed! new UID = %llu\n", ses->Suid);
+ }
+
bytes_remaining = get_bcc(smb_buf);
bcc_ptr = pByteArea(smb_buf);
blob_len = le16_to_cpu(pSMB->resp.SecurityBlobLength);
diff --git a/fs/cifs/smb2file.c b/fs/cifs/smb2file.c
index 4599294..7198eac 100644
--- a/fs/cifs/smb2file.c
+++ b/fs/cifs/smb2file.c
@@ -111,7 +111,7 @@ smb2_unlock_range(struct cifsFileInfo *cfile, struct file_lock *flock,
return -EINVAL;
max_num = max_buf / sizeof(struct smb2_lock_element);
- buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
+ buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
if (!buf)
return -ENOMEM;
@@ -247,7 +247,7 @@ smb2_push_mandatory_locks(struct cifsFileInfo *cfile)
}
max_num = max_buf / sizeof(struct smb2_lock_element);
- buf = kzalloc(max_num * sizeof(struct smb2_lock_element), GFP_KERNEL);
+ buf = kcalloc(max_num, sizeof(struct smb2_lock_element), GFP_KERNEL);
if (!buf) {
free_xid(xid);
return -ENOMEM;
diff --git a/fs/cifs/smb2misc.c b/fs/cifs/smb2misc.c
index 1a08a34..f1cefc9 100644
--- a/fs/cifs/smb2misc.c
+++ b/fs/cifs/smb2misc.c
@@ -67,27 +67,27 @@ check_smb2_hdr(struct smb2_hdr *hdr, __u64 mid)
* indexed by command in host byte order
*/
static const __le16 smb2_rsp_struct_sizes[NUMBER_OF_SMB2_COMMANDS] = {
- /* SMB2_NEGOTIATE */ __constant_cpu_to_le16(65),
- /* SMB2_SESSION_SETUP */ __constant_cpu_to_le16(9),
- /* SMB2_LOGOFF */ __constant_cpu_to_le16(4),
- /* SMB2_TREE_CONNECT */ __constant_cpu_to_le16(16),
- /* SMB2_TREE_DISCONNECT */ __constant_cpu_to_le16(4),
- /* SMB2_CREATE */ __constant_cpu_to_le16(89),
- /* SMB2_CLOSE */ __constant_cpu_to_le16(60),
- /* SMB2_FLUSH */ __constant_cpu_to_le16(4),
- /* SMB2_READ */ __constant_cpu_to_le16(17),
- /* SMB2_WRITE */ __constant_cpu_to_le16(17),
- /* SMB2_LOCK */ __constant_cpu_to_le16(4),
- /* SMB2_IOCTL */ __constant_cpu_to_le16(49),
+ /* SMB2_NEGOTIATE */ cpu_to_le16(65),
+ /* SMB2_SESSION_SETUP */ cpu_to_le16(9),
+ /* SMB2_LOGOFF */ cpu_to_le16(4),
+ /* SMB2_TREE_CONNECT */ cpu_to_le16(16),
+ /* SMB2_TREE_DISCONNECT */ cpu_to_le16(4),
+ /* SMB2_CREATE */ cpu_to_le16(89),
+ /* SMB2_CLOSE */ cpu_to_le16(60),
+ /* SMB2_FLUSH */ cpu_to_le16(4),
+ /* SMB2_READ */ cpu_to_le16(17),
+ /* SMB2_WRITE */ cpu_to_le16(17),
+ /* SMB2_LOCK */ cpu_to_le16(4),
+ /* SMB2_IOCTL */ cpu_to_le16(49),
/* BB CHECK this ... not listed in documentation */
- /* SMB2_CANCEL */ __constant_cpu_to_le16(0),
- /* SMB2_ECHO */ __constant_cpu_to_le16(4),
- /* SMB2_QUERY_DIRECTORY */ __constant_cpu_to_le16(9),
- /* SMB2_CHANGE_NOTIFY */ __constant_cpu_to_le16(9),
- /* SMB2_QUERY_INFO */ __constant_cpu_to_le16(9),
- /* SMB2_SET_INFO */ __constant_cpu_to_le16(2),
+ /* SMB2_CANCEL */ cpu_to_le16(0),
+ /* SMB2_ECHO */ cpu_to_le16(4),
+ /* SMB2_QUERY_DIRECTORY */ cpu_to_le16(9),
+ /* SMB2_CHANGE_NOTIFY */ cpu_to_le16(9),
+ /* SMB2_QUERY_INFO */ cpu_to_le16(9),
+ /* SMB2_SET_INFO */ cpu_to_le16(2),
/* BB FIXME can also be 44 for lease break */
- /* SMB2_OPLOCK_BREAK */ __constant_cpu_to_le16(24)
+ /* SMB2_OPLOCK_BREAK */ cpu_to_le16(24)
};
int
diff --git a/fs/cifs/smb2ops.c b/fs/cifs/smb2ops.c
index c5f521b..93fd058 100644
--- a/fs/cifs/smb2ops.c
+++ b/fs/cifs/smb2ops.c
@@ -600,7 +600,7 @@ smb2_clone_range(const unsigned int xid,
goto cchunk_out;
/* For now array only one chunk long, will make more flexible later */
- pcchunk->ChunkCount = __constant_cpu_to_le32(1);
+ pcchunk->ChunkCount = cpu_to_le32(1);
pcchunk->Reserved = 0;
pcchunk->Reserved2 = 0;
@@ -1102,6 +1102,64 @@ static long smb3_punch_hole(struct file *file, struct cifs_tcon *tcon,
return rc;
}
+static long smb3_simple_falloc(struct file *file, struct cifs_tcon *tcon,
+ loff_t off, loff_t len, bool keep_size)
+{
+ struct inode *inode;
+ struct cifsInodeInfo *cifsi;
+ struct cifsFileInfo *cfile = file->private_data;
+ long rc = -EOPNOTSUPP;
+ unsigned int xid;
+
+ xid = get_xid();
+
+ inode = cfile->dentry->d_inode;
+ cifsi = CIFS_I(inode);
+
+ /* if file not oplocked can't be sure whether asking to extend size */
+ if (!CIFS_CACHE_READ(cifsi))
+ if (keep_size == false)
+ return -EOPNOTSUPP;
+
+ /*
+ * Files are non-sparse by default so falloc may be a no-op
+ * Must check if file sparse. If not sparse, and not extending
+ * then no need to do anything since file already allocated
+ */
+ if ((cifsi->cifsAttrs & FILE_ATTRIBUTE_SPARSE_FILE) == 0) {
+ if (keep_size == true)
+ return 0;
+ /* check if extending file */
+ else if (i_size_read(inode) >= off + len)
+ /* not extending file and already not sparse */
+ return 0;
+ /* BB: in future add else clause to extend file */
+ else
+ return -EOPNOTSUPP;
+ }
+
+ if ((keep_size == true) || (i_size_read(inode) >= off + len)) {
+ /*
+ * Check if falloc starts within first few pages of file
+ * and ends within a few pages of the end of file to
+ * ensure that most of file is being forced to be
+ * fallocated now. If so then setting whole file sparse
+ * ie potentially making a few extra pages at the beginning
+ * or end of the file non-sparse via set_sparse is harmless.
+ */
+ if ((off > 8192) || (off + len + 8192 < i_size_read(inode)))
+ return -EOPNOTSUPP;
+
+ rc = smb2_set_sparse(xid, tcon, cfile, inode, false);
+ }
+ /* BB: else ... in future add code to extend file and set sparse */
+
+
+ free_xid(xid);
+ return rc;
+}
+
+
static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
loff_t off, loff_t len)
{
@@ -1112,7 +1170,10 @@ static long smb3_fallocate(struct file *file, struct cifs_tcon *tcon, int mode,
if (mode & FALLOC_FL_KEEP_SIZE)
return smb3_zero_range(file, tcon, off, len, true);
return smb3_zero_range(file, tcon, off, len, false);
- }
+ } else if (mode == FALLOC_FL_KEEP_SIZE)
+ return smb3_simple_falloc(file, tcon, off, len, true);
+ else if (mode == 0)
+ return smb3_simple_falloc(file, tcon, off, len, false);
return -EOPNOTSUPP;
}
diff --git a/fs/cifs/smb2pdu.c b/fs/cifs/smb2pdu.c
index 8f1672b..3417340 100644
--- a/fs/cifs/smb2pdu.c
+++ b/fs/cifs/smb2pdu.c
@@ -431,8 +431,7 @@ SMB2_negotiate(const unsigned int xid, struct cifs_ses *ses)
if (rc)
goto neg_exit;
if (blob_length)
- rc = decode_neg_token_init(security_blob, blob_length,
- &server->sec_type);
+ rc = decode_negTokenInit(security_blob, blob_length, server);
if (rc == 1)
rc = 0;
else if (rc == 0) {
@@ -1359,7 +1358,7 @@ SMB2_set_compression(const unsigned int xid, struct cifs_tcon *tcon,
char *ret_data = NULL;
fsctl_input.CompressionState =
- __constant_cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
+ cpu_to_le16(COMPRESSION_FORMAT_DEFAULT);
rc = SMB2_ioctl(xid, tcon, persistent_fid, volatile_fid,
FSCTL_SET_COMPRESSION, true /* is_fsctl */,
diff --git a/fs/cifs/smb2pdu.h b/fs/cifs/smb2pdu.h
index e3188ab..ce85847 100644
--- a/fs/cifs/smb2pdu.h
+++ b/fs/cifs/smb2pdu.h
@@ -85,7 +85,7 @@
/* BB FIXME - analyze following length BB */
#define MAX_SMB2_HDR_SIZE 0x78 /* 4 len + 64 hdr + (2*24 wct) + 2 bct + 2 pad */
-#define SMB2_PROTO_NUMBER __constant_cpu_to_le32(0x424d53fe)
+#define SMB2_PROTO_NUMBER cpu_to_le32(0x424d53fe)
/*
* SMB2 Header Definition
@@ -96,7 +96,7 @@
*
*/
-#define SMB2_HEADER_STRUCTURE_SIZE __constant_cpu_to_le16(64)
+#define SMB2_HEADER_STRUCTURE_SIZE cpu_to_le16(64)
struct smb2_hdr {
__be32 smb2_buf_length; /* big endian on wire */
@@ -137,16 +137,16 @@ struct smb2_transform_hdr {
} __packed;
/* Encryption Algorithms */
-#define SMB2_ENCRYPTION_AES128_CCM __constant_cpu_to_le16(0x0001)
+#define SMB2_ENCRYPTION_AES128_CCM cpu_to_le16(0x0001)
/*
* SMB2 flag definitions
*/
-#define SMB2_FLAGS_SERVER_TO_REDIR __constant_cpu_to_le32(0x00000001)
-#define SMB2_FLAGS_ASYNC_COMMAND __constant_cpu_to_le32(0x00000002)
-#define SMB2_FLAGS_RELATED_OPERATIONS __constant_cpu_to_le32(0x00000004)
-#define SMB2_FLAGS_SIGNED __constant_cpu_to_le32(0x00000008)
-#define SMB2_FLAGS_DFS_OPERATIONS __constant_cpu_to_le32(0x10000000)
+#define SMB2_FLAGS_SERVER_TO_REDIR cpu_to_le32(0x00000001)
+#define SMB2_FLAGS_ASYNC_COMMAND cpu_to_le32(0x00000002)
+#define SMB2_FLAGS_RELATED_OPERATIONS cpu_to_le32(0x00000004)
+#define SMB2_FLAGS_SIGNED cpu_to_le32(0x00000008)
+#define SMB2_FLAGS_DFS_OPERATIONS cpu_to_le32(0x10000000)
/*
* Definitions for SMB2 Protocol Data Units (network frames)
@@ -157,7 +157,7 @@ struct smb2_transform_hdr {
*
*/
-#define SMB2_ERROR_STRUCTURE_SIZE2 __constant_cpu_to_le16(9)
+#define SMB2_ERROR_STRUCTURE_SIZE2 cpu_to_le16(9)
struct smb2_err_rsp {
struct smb2_hdr hdr;
@@ -502,12 +502,12 @@ struct create_context {
#define SMB2_LEASE_HANDLE_CACHING_HE 0x02
#define SMB2_LEASE_WRITE_CACHING_HE 0x04
-#define SMB2_LEASE_NONE __constant_cpu_to_le32(0x00)
-#define SMB2_LEASE_READ_CACHING __constant_cpu_to_le32(0x01)
-#define SMB2_LEASE_HANDLE_CACHING __constant_cpu_to_le32(0x02)
-#define SMB2_LEASE_WRITE_CACHING __constant_cpu_to_le32(0x04)
+#define SMB2_LEASE_NONE cpu_to_le32(0x00)
+#define SMB2_LEASE_READ_CACHING cpu_to_le32(0x01)
+#define SMB2_LEASE_HANDLE_CACHING cpu_to_le32(0x02)
+#define SMB2_LEASE_WRITE_CACHING cpu_to_le32(0x04)
-#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS __constant_cpu_to_le32(0x02)
+#define SMB2_LEASE_FLAG_BREAK_IN_PROGRESS cpu_to_le32(0x02)
#define SMB2_LEASE_KEY_SIZE 16
@@ -836,6 +836,25 @@ struct smb2_query_directory_rsp {
#define SMB2_O_INFO_SECURITY 0x03
#define SMB2_O_INFO_QUOTA 0x04
+/* Security info type additionalinfo flags. See MS-SMB2 (2.2.37) or MS-DTYP */
+#define OWNER_SECINFO 0x00000001
+#define GROUP_SECINFO 0x00000002
+#define DACL_SECINFO 0x00000004
+#define SACL_SECINFO 0x00000008
+#define LABEL_SECINFO 0x00000010
+#define ATTRIBUTE_SECINFO 0x00000020
+#define SCOPE_SECINFO 0x00000040
+#define BACKUP_SECINFO 0x00010000
+#define UNPROTECTED_SACL_SECINFO 0x10000000
+#define UNPROTECTED_DACL_SECINFO 0x20000000
+#define PROTECTED_SACL_SECINFO 0x40000000
+#define PROTECTED_DACL_SECINFO 0x80000000
+
+/* Flags used for FileFullEAinfo */
+#define SL_RESTART_SCAN 0x00000001
+#define SL_RETURN_SINGLE_ENTRY 0x00000002
+#define SL_INDEX_SPECIFIED 0x00000004
+
struct smb2_query_info_req {
struct smb2_hdr hdr;
__le16 StructureSize; /* Must be 41 */
diff --git a/fs/cifs/transport.c b/fs/cifs/transport.c
index 9d087f4..126f46b 100644
--- a/fs/cifs/transport.c
+++ b/fs/cifs/transport.c
@@ -99,9 +99,9 @@ DeleteMidQEntry(struct mid_q_entry *midEntry)
something is wrong, unless it is quite a slow link or server */
if ((now - midEntry->when_alloc) > HZ) {
if ((cifsFYI & CIFS_TIMER) && (midEntry->command != command)) {
- printk(KERN_DEBUG " CIFS slow rsp: cmd %d mid %llu",
+ pr_debug(" CIFS slow rsp: cmd %d mid %llu",
midEntry->command, midEntry->mid);
- printk(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
+ pr_info(" A: 0x%lx S: 0x%lx R: 0x%lx\n",
now - midEntry->when_alloc,
now - midEntry->when_sent,
now - midEntry->when_received);
diff --git a/fs/coda/cache.c b/fs/coda/cache.c
index 278f8fd..46ee6f2 100644
--- a/fs/coda/cache.c
+++ b/fs/coda/cache.c
@@ -92,7 +92,7 @@ static void coda_flag_children(struct dentry *parent, int flag)
struct dentry *de;
spin_lock(&parent->d_lock);
- list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(de, &parent->d_subdirs, d_child) {
/* don't know what to do with negative dentries */
if (de->d_inode )
coda_flag_inode(de->d_inode, flag);
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 1326d38..f1714cf 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -40,12 +40,6 @@ int coda_iscontrol(const char *name, size_t length)
(strncmp(name, CODA_CONTROL, CODA_CONTROLLEN) == 0));
}
-/* recognize /coda inode */
-int coda_isroot(struct inode *i)
-{
- return ( i->i_sb->s_root->d_inode == i );
-}
-
unsigned short coda_flags_to_cflags(unsigned short flags)
{
unsigned short coda_flags = 0;
diff --git a/fs/coda/coda_linux.h b/fs/coda/coda_linux.h
index d42b725..d6f7a76 100644
--- a/fs/coda/coda_linux.h
+++ b/fs/coda/coda_linux.h
@@ -52,7 +52,6 @@ int coda_setattr(struct dentry *, struct iattr *);
/* this file: heloers */
char *coda_f2s(struct CodaFid *f);
-int coda_isroot(struct inode *i);
int coda_iscontrol(const char *name, size_t length);
void coda_vattr_to_iattr(struct inode *, struct coda_vattr *);
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index 9c3dedc..7ff0259 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -107,7 +107,7 @@ static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsig
}
/* control object, create inode on the fly */
- if (coda_isroot(dir) && coda_iscontrol(name, length)) {
+ if (is_root_inode(dir) && coda_iscontrol(name, length)) {
inode = coda_cnode_makectl(sb);
type = CODA_NOCACHE;
} else {
@@ -195,7 +195,7 @@ static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool
struct CodaFid newfid;
struct coda_vattr attrs;
- if (coda_isroot(dir) && coda_iscontrol(name, length))
+ if (is_root_inode(dir) && coda_iscontrol(name, length))
return -EPERM;
error = venus_create(dir->i_sb, coda_i2f(dir), name, length,
@@ -227,7 +227,7 @@ static int coda_mkdir(struct inode *dir, struct dentry *de, umode_t mode)
int error;
struct CodaFid newfid;
- if (coda_isroot(dir) && coda_iscontrol(name, len))
+ if (is_root_inode(dir) && coda_iscontrol(name, len))
return -EPERM;
attrs.va_mode = mode;
@@ -261,7 +261,7 @@ static int coda_link(struct dentry *source_de, struct inode *dir_inode,
int len = de->d_name.len;
int error;
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+ if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
error = venus_link(dir_inode->i_sb, coda_i2f(inode),
@@ -287,7 +287,7 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
int symlen;
int error;
- if (coda_isroot(dir_inode) && coda_iscontrol(name, len))
+ if (is_root_inode(dir_inode) && coda_iscontrol(name, len))
return -EPERM;
symlen = strlen(symname);
@@ -507,7 +507,7 @@ static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
return -ECHILD;
inode = de->d_inode;
- if (!inode || coda_isroot(inode))
+ if (!inode || is_root_inode(inode))
goto out;
if (is_bad_inode(inode))
goto bad;
diff --git a/fs/compat.c b/fs/compat.c
index b13df99..6fd272d 100644
--- a/fs/compat.c
+++ b/fs/compat.c
@@ -847,10 +847,12 @@ struct compat_readdir_callback {
int result;
};
-static int compat_fillonedir(void *__buf, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
+static int compat_fillonedir(struct dir_context *ctx, const char *name,
+ int namlen, loff_t offset, u64 ino,
+ unsigned int d_type)
{
- struct compat_readdir_callback *buf = __buf;
+ struct compat_readdir_callback *buf =
+ container_of(ctx, struct compat_readdir_callback, ctx);
struct compat_old_linux_dirent __user *dirent;
compat_ulong_t d_ino;
@@ -915,11 +917,12 @@ struct compat_getdents_callback {
int error;
};
-static int compat_filldir(void *__buf, const char *name, int namlen,
+static int compat_filldir(struct dir_context *ctx, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
struct compat_linux_dirent __user * dirent;
- struct compat_getdents_callback *buf = __buf;
+ struct compat_getdents_callback *buf =
+ container_of(ctx, struct compat_getdents_callback, ctx);
compat_ulong_t d_ino;
int reclen = ALIGN(offsetof(struct compat_linux_dirent, d_name) +
namlen + 2, sizeof(compat_long_t));
@@ -1001,11 +1004,13 @@ struct compat_getdents_callback64 {
int error;
};
-static int compat_filldir64(void * __buf, const char * name, int namlen, loff_t offset,
- u64 ino, unsigned int d_type)
+static int compat_filldir64(struct dir_context *ctx, const char *name,
+ int namlen, loff_t offset, u64 ino,
+ unsigned int d_type)
{
struct linux_dirent64 __user *dirent;
- struct compat_getdents_callback64 *buf = __buf;
+ struct compat_getdents_callback64 *buf =
+ container_of(ctx, struct compat_getdents_callback64, ctx);
int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
sizeof(u64));
u64 off;
diff --git a/fs/configfs/dir.c b/fs/configfs/dir.c
index 668dcab..c9c298b 100644
--- a/fs/configfs/dir.c
+++ b/fs/configfs/dir.c
@@ -386,7 +386,7 @@ static void remove_dir(struct dentry * d)
if (d->d_inode)
simple_rmdir(parent->d_inode,d);
- pr_debug(" o %s removing done (%d)\n",d->d_name.name, d_count(d));
+ pr_debug(" o %pd removing done (%d)\n", d, d_count(d));
dput(parent);
}
diff --git a/fs/dcache.c b/fs/dcache.c
index 5bc72b0..e368d4f 100644
--- a/fs/dcache.c
+++ b/fs/dcache.c
@@ -44,7 +44,7 @@
/*
* Usage:
* dcache->d_inode->i_lock protects:
- * - i_dentry, d_alias, d_inode of aliases
+ * - i_dentry, d_u.d_alias, d_inode of aliases
* dcache_hash_bucket lock protects:
* - the dcache hash table
* s_anon bl list spinlock protects:
@@ -59,7 +59,7 @@
* - d_unhashed()
* - d_parent and d_subdirs
* - childrens' d_child and d_parent
- * - d_alias, d_inode
+ * - d_u.d_alias, d_inode
*
* Ordering:
* dentry->d_inode->i_lock
@@ -252,14 +252,12 @@ static void __d_free(struct rcu_head *head)
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
- WARN_ON(!hlist_unhashed(&dentry->d_alias));
kmem_cache_free(dentry_cache, dentry);
}
static void __d_free_external(struct rcu_head *head)
{
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
- WARN_ON(!hlist_unhashed(&dentry->d_alias));
kfree(external_name(dentry));
kmem_cache_free(dentry_cache, dentry);
}
@@ -271,6 +269,7 @@ static inline int dname_external(const struct dentry *dentry)
static void dentry_free(struct dentry *dentry)
{
+ WARN_ON(!hlist_unhashed(&dentry->d_u.d_alias));
if (unlikely(dname_external(dentry))) {
struct external_name *p = external_name(dentry);
if (likely(atomic_dec_and_test(&p->u.count))) {
@@ -311,7 +310,7 @@ static void dentry_iput(struct dentry * dentry)
struct inode *inode = dentry->d_inode;
if (inode) {
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
if (!inode->i_nlink)
@@ -336,7 +335,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
struct inode *inode = dentry->d_inode;
__d_clear_type(dentry);
dentry->d_inode = NULL;
- hlist_del_init(&dentry->d_alias);
+ hlist_del_init(&dentry->d_u.d_alias);
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
spin_unlock(&inode->i_lock);
@@ -496,7 +495,7 @@ static void __dentry_kill(struct dentry *dentry)
}
/* if it was on the hash then remove it */
__d_drop(dentry);
- list_del(&dentry->d_u.d_child);
+ __list_del_entry(&dentry->d_child);
/*
* Inform d_walk() that we are no longer attached to the
* dentry tree
@@ -722,7 +721,7 @@ static struct dentry *__d_find_alias(struct inode *inode)
again:
discon_alias = NULL;
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
spin_lock(&alias->d_lock);
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
if (IS_ROOT(alias) &&
@@ -772,7 +771,7 @@ void d_prune_aliases(struct inode *inode)
struct dentry *dentry;
restart:
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (!dentry->d_lockref.count) {
struct dentry *parent = lock_parent(dentry);
@@ -1051,7 +1050,7 @@ repeat:
resume:
while (next != &this_parent->d_subdirs) {
struct list_head *tmp = next;
- struct dentry *dentry = list_entry(tmp, struct dentry, d_u.d_child);
+ struct dentry *dentry = list_entry(tmp, struct dentry, d_child);
next = tmp->next;
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
@@ -1083,33 +1082,31 @@ resume:
/*
* All done at this level ... ascend and resume the search.
*/
+ rcu_read_lock();
+ascend:
if (this_parent != parent) {
struct dentry *child = this_parent;
this_parent = child->d_parent;
- rcu_read_lock();
spin_unlock(&child->d_lock);
spin_lock(&this_parent->d_lock);
- /*
- * might go back up the wrong parent if we have had a rename
- * or deletion
- */
- if (this_parent != child->d_parent ||
- (child->d_flags & DCACHE_DENTRY_KILLED) ||
- need_seqretry(&rename_lock, seq)) {
- spin_unlock(&this_parent->d_lock);
- rcu_read_unlock();
+ /* might go back up the wrong parent if we have had a rename. */
+ if (need_seqretry(&rename_lock, seq))
goto rename_retry;
+ next = child->d_child.next;
+ while (unlikely(child->d_flags & DCACHE_DENTRY_KILLED)) {
+ if (next == &this_parent->d_subdirs)
+ goto ascend;
+ child = list_entry(next, struct dentry, d_child);
+ next = next->next;
}
rcu_read_unlock();
- next = child->d_u.d_child.next;
goto resume;
}
- if (need_seqretry(&rename_lock, seq)) {
- spin_unlock(&this_parent->d_lock);
+ if (need_seqretry(&rename_lock, seq))
goto rename_retry;
- }
+ rcu_read_unlock();
if (finish)
finish(data);
@@ -1119,6 +1116,9 @@ out_unlock:
return;
rename_retry:
+ spin_unlock(&this_parent->d_lock);
+ rcu_read_unlock();
+ BUG_ON(seq & 1);
if (!retry)
return;
seq = 1;
@@ -1455,8 +1455,8 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
INIT_HLIST_BL_NODE(&dentry->d_hash);
INIT_LIST_HEAD(&dentry->d_lru);
INIT_LIST_HEAD(&dentry->d_subdirs);
- INIT_HLIST_NODE(&dentry->d_alias);
- INIT_LIST_HEAD(&dentry->d_u.d_child);
+ INIT_HLIST_NODE(&dentry->d_u.d_alias);
+ INIT_LIST_HEAD(&dentry->d_child);
d_set_d_op(dentry, dentry->d_sb->s_d_op);
this_cpu_inc(nr_dentry);
@@ -1486,7 +1486,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
*/
__dget_dlock(parent);
dentry->d_parent = parent;
- list_add(&dentry->d_u.d_child, &parent->d_subdirs);
+ list_add(&dentry->d_child, &parent->d_subdirs);
spin_unlock(&parent->d_lock);
return dentry;
@@ -1579,7 +1579,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
spin_lock(&dentry->d_lock);
__d_set_type(dentry, add_flags);
if (inode)
- hlist_add_head(&dentry->d_alias, &inode->i_dentry);
+ hlist_add_head(&dentry->d_u.d_alias, &inode->i_dentry);
dentry->d_inode = inode;
dentry_rcuwalk_barrier(dentry);
spin_unlock(&dentry->d_lock);
@@ -1603,7 +1603,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
void d_instantiate(struct dentry *entry, struct inode * inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
__d_instantiate(entry, inode);
@@ -1642,7 +1642,7 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
return NULL;
}
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
/*
* Don't need alias->d_lock here, because aliases with
* d_parent == entry->d_parent are not subject to name or
@@ -1668,7 +1668,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
{
struct dentry *result;
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
if (inode)
spin_lock(&inode->i_lock);
@@ -1699,7 +1699,7 @@ EXPORT_SYMBOL(d_instantiate_unique);
*/
int d_instantiate_no_diralias(struct dentry *entry, struct inode *inode)
{
- BUG_ON(!hlist_unhashed(&entry->d_alias));
+ BUG_ON(!hlist_unhashed(&entry->d_u.d_alias));
spin_lock(&inode->i_lock);
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry)) {
@@ -1738,7 +1738,7 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
if (hlist_empty(&inode->i_dentry))
return NULL;
- alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ alias = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
__dget(alias);
return alias;
}
@@ -1800,7 +1800,7 @@ static struct dentry *__d_obtain_alias(struct inode *inode, int disconnected)
spin_lock(&tmp->d_lock);
tmp->d_inode = inode;
tmp->d_flags |= add_flags;
- hlist_add_head(&tmp->d_alias, &inode->i_dentry);
+ hlist_add_head(&tmp->d_u.d_alias, &inode->i_dentry);
hlist_bl_lock(&tmp->d_sb->s_anon);
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
hlist_bl_unlock(&tmp->d_sb->s_anon);
@@ -1889,51 +1889,19 @@ struct dentry *d_add_ci(struct dentry *dentry, struct inode *inode,
* if not go ahead and create it now.
*/
found = d_hash_and_lookup(dentry->d_parent, name);
- if (unlikely(IS_ERR(found)))
- goto err_out;
if (!found) {
new = d_alloc(dentry->d_parent, name);
if (!new) {
found = ERR_PTR(-ENOMEM);
- goto err_out;
- }
-
- found = d_splice_alias(inode, new);
- if (found) {
- dput(new);
- return found;
- }
- return new;
- }
-
- /*
- * If a matching dentry exists, and it's not negative use it.
- *
- * Decrement the reference count to balance the iget() done
- * earlier on.
- */
- if (found->d_inode) {
- if (unlikely(found->d_inode != inode)) {
- /* This can't happen because bad inodes are unhashed. */
- BUG_ON(!is_bad_inode(inode));
- BUG_ON(!is_bad_inode(found->d_inode));
+ } else {
+ found = d_splice_alias(inode, new);
+ if (found) {
+ dput(new);
+ return found;
+ }
+ return new;
}
- iput(inode);
- return found;
}
-
- /*
- * Negative dentry: instantiate it unless the inode is a directory and
- * already has a dentry.
- */
- new = d_splice_alias(inode, found);
- if (new) {
- dput(found);
- found = new;
- }
- return found;
-
-err_out:
iput(inode);
return found;
}
@@ -2235,7 +2203,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)
struct dentry *child;
spin_lock(&dparent->d_lock);
- list_for_each_entry(child, &dparent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dparent->d_subdirs, d_child) {
if (dentry == child) {
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
__dget_dlock(dentry);
@@ -2393,6 +2361,8 @@ static void swap_names(struct dentry *dentry, struct dentry *target)
*/
unsigned int i;
BUILD_BUG_ON(!IS_ALIGNED(DNAME_INLINE_LEN, sizeof(long)));
+ kmemcheck_mark_initialized(dentry->d_iname, DNAME_INLINE_LEN);
+ kmemcheck_mark_initialized(target->d_iname, DNAME_INLINE_LEN);
for (i = 0; i < DNAME_INLINE_LEN / sizeof(long); i++) {
swap(((long *) &dentry->d_iname)[i],
((long *) &target->d_iname)[i]);
@@ -2526,13 +2496,13 @@ static void __d_move(struct dentry *dentry, struct dentry *target,
/* splicing a tree */
dentry->d_parent = target->d_parent;
target->d_parent = target;
- list_del_init(&target->d_u.d_child);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_del_init(&target->d_child);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
} else {
/* swapping two dentries */
swap(dentry->d_parent, target->d_parent);
- list_move(&target->d_u.d_child, &target->d_parent->d_subdirs);
- list_move(&dentry->d_u.d_child, &dentry->d_parent->d_subdirs);
+ list_move(&target->d_child, &target->d_parent->d_subdirs);
+ list_move(&dentry->d_child, &dentry->d_parent->d_subdirs);
if (exchange)
fsnotify_d_move(target);
fsnotify_d_move(dentry);
@@ -2608,11 +2578,11 @@ struct dentry *d_ancestor(struct dentry *p1, struct dentry *p2)
* Note: If ever the locking in lock_rename() changes, then please
* remember to update this too...
*/
-static struct dentry *__d_unalias(struct inode *inode,
+static int __d_unalias(struct inode *inode,
struct dentry *dentry, struct dentry *alias)
{
struct mutex *m1 = NULL, *m2 = NULL;
- struct dentry *ret = ERR_PTR(-EBUSY);
+ int ret = -EBUSY;
/* If alias and dentry share a parent, then no extra locks required */
if (alias->d_parent == dentry->d_parent)
@@ -2627,7 +2597,7 @@ static struct dentry *__d_unalias(struct inode *inode,
m2 = &alias->d_parent->d_inode->i_mutex;
out_unalias:
__d_move(alias, dentry, false);
- ret = alias;
+ ret = 0;
out_err:
spin_unlock(&inode->i_lock);
if (m2)
@@ -2662,130 +2632,57 @@ out_err:
*/
struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
{
- struct dentry *new = NULL;
-
if (IS_ERR(inode))
return ERR_CAST(inode);
- if (inode && S_ISDIR(inode->i_mode)) {
- spin_lock(&inode->i_lock);
- new = __d_find_any_alias(inode);
- if (new) {
- if (!IS_ROOT(new)) {
- spin_unlock(&inode->i_lock);
- dput(new);
- iput(inode);
- return ERR_PTR(-EIO);
- }
- if (d_ancestor(new, dentry)) {
- spin_unlock(&inode->i_lock);
- dput(new);
- iput(inode);
- return ERR_PTR(-EIO);
- }
- write_seqlock(&rename_lock);
- __d_move(new, dentry, false);
- write_sequnlock(&rename_lock);
- spin_unlock(&inode->i_lock);
- security_d_instantiate(new, inode);
- iput(inode);
- } else {
- /* already taking inode->i_lock, so d_add() by hand */
- __d_instantiate(dentry, inode);
- spin_unlock(&inode->i_lock);
- security_d_instantiate(dentry, inode);
- d_rehash(dentry);
- }
- } else {
- d_instantiate(dentry, inode);
- if (d_unhashed(dentry))
- d_rehash(dentry);
- }
- return new;
-}
-EXPORT_SYMBOL(d_splice_alias);
-
-/**
- * d_materialise_unique - introduce an inode into the tree
- * @dentry: candidate dentry
- * @inode: inode to bind to the dentry, to which aliases may be attached
- *
- * Introduces an dentry into the tree, substituting an extant disconnected
- * root directory alias in its place if there is one. Caller must hold the
- * i_mutex of the parent directory.
- */
-struct dentry *d_materialise_unique(struct dentry *dentry, struct inode *inode)
-{
- struct dentry *actual;
-
BUG_ON(!d_unhashed(dentry));
if (!inode) {
- actual = dentry;
__d_instantiate(dentry, NULL);
- d_rehash(actual);
- goto out_nolock;
+ goto out;
}
-
spin_lock(&inode->i_lock);
-
if (S_ISDIR(inode->i_mode)) {
- struct dentry *alias;
-
- /* Does an aliased dentry already exist? */
- alias = __d_find_alias(inode);
- if (alias) {
- actual = alias;
+ struct dentry *new = __d_find_any_alias(inode);
+ if (unlikely(new)) {
write_seqlock(&rename_lock);
-
- if (d_ancestor(alias, dentry)) {
- /* Check for loops */
- actual = ERR_PTR(-ELOOP);
+ if (unlikely(d_ancestor(new, dentry))) {
+ write_sequnlock(&rename_lock);
spin_unlock(&inode->i_lock);
- } else if (IS_ROOT(alias)) {
- /* Is this an anonymous mountpoint that we
- * could splice into our tree? */
- __d_move(alias, dentry, false);
+ dput(new);
+ new = ERR_PTR(-ELOOP);
+ pr_warn_ratelimited(
+ "VFS: Lookup of '%s' in %s %s"
+ " would have caused loop\n",
+ dentry->d_name.name,
+ inode->i_sb->s_type->name,
+ inode->i_sb->s_id);
+ } else if (!IS_ROOT(new)) {
+ int err = __d_unalias(inode, dentry, new);
write_sequnlock(&rename_lock);
- goto found;
+ if (err) {
+ dput(new);
+ new = ERR_PTR(err);
+ }
} else {
- /* Nope, but we must(!) avoid directory
- * aliasing. This drops inode->i_lock */
- actual = __d_unalias(inode, dentry, alias);
- }
- write_sequnlock(&rename_lock);
- if (IS_ERR(actual)) {
- if (PTR_ERR(actual) == -ELOOP)
- pr_warn_ratelimited(
- "VFS: Lookup of '%s' in %s %s"
- " would have caused loop\n",
- dentry->d_name.name,
- inode->i_sb->s_type->name,
- inode->i_sb->s_id);
- dput(alias);
+ __d_move(new, dentry, false);
+ write_sequnlock(&rename_lock);
+ spin_unlock(&inode->i_lock);
+ security_d_instantiate(new, inode);
}
- goto out_nolock;
+ iput(inode);
+ return new;
}
}
-
- /* Add a unique reference */
- actual = __d_instantiate_unique(dentry, inode);
- if (!actual)
- actual = dentry;
-
- d_rehash(actual);
-found:
+ /* already taking inode->i_lock, so d_add() by hand */
+ __d_instantiate(dentry, inode);
spin_unlock(&inode->i_lock);
-out_nolock:
- if (actual == dentry) {
- security_d_instantiate(dentry, inode);
- return NULL;
- }
-
- iput(inode);
- return actual;
+out:
+ security_d_instantiate(dentry, inode);
+ d_rehash(dentry);
+ return NULL;
}
-EXPORT_SYMBOL_GPL(d_materialise_unique);
+EXPORT_SYMBOL(d_splice_alias);
static int prepend(char **buffer, int *buflen, const char *str, int namelen)
{
@@ -3321,7 +3218,7 @@ void d_tmpfile(struct dentry *dentry, struct inode *inode)
{
inode_dec_link_count(inode);
BUG_ON(dentry->d_name.name != dentry->d_iname ||
- !hlist_unhashed(&dentry->d_alias) ||
+ !hlist_unhashed(&dentry->d_u.d_alias) ||
!d_unlinked(dentry));
spin_lock(&dentry->d_parent->d_lock);
spin_lock_nested(&dentry->d_lock, DENTRY_D_LOCK_NESTED);
diff --git a/fs/debugfs/file.c b/fs/debugfs/file.c
index 76c08c2..8e0f2f4 100644
--- a/fs/debugfs/file.c
+++ b/fs/debugfs/file.c
@@ -692,18 +692,19 @@ EXPORT_SYMBOL_GPL(debugfs_create_u32_array);
* because some peripherals have several blocks of identical registers,
* for example configuration of dma channels
*/
-int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
- int nregs, void __iomem *base, char *prefix)
+void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
+ int nregs, void __iomem *base, char *prefix)
{
- int i, ret = 0;
+ int i;
for (i = 0; i < nregs; i++, regs++) {
if (prefix)
- ret += seq_printf(s, "%s", prefix);
- ret += seq_printf(s, "%s = 0x%08x\n", regs->name,
- readl(base + regs->offset));
+ seq_printf(s, "%s", prefix);
+ seq_printf(s, "%s = 0x%08x\n", regs->name,
+ readl(base + regs->offset));
+ if (seq_has_overflowed(s))
+ break;
}
- return ret;
}
EXPORT_SYMBOL_GPL(debugfs_print_regs32);
diff --git a/fs/debugfs/inode.c b/fs/debugfs/inode.c
index 1e3b99d..05f2960 100644
--- a/fs/debugfs/inode.c
+++ b/fs/debugfs/inode.c
@@ -553,7 +553,7 @@ void debugfs_remove_recursive(struct dentry *dentry)
* use the d_u.d_child as the rcu head and corrupt this list.
*/
spin_lock(&parent->d_lock);
- list_for_each_entry(child, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &parent->d_subdirs, d_child) {
if (!debugfs_positive(child))
continue;
diff --git a/fs/dlm/debug_fs.c b/fs/dlm/debug_fs.c
index 1323c56..eea6491 100644
--- a/fs/dlm/debug_fs.c
+++ b/fs/dlm/debug_fs.c
@@ -48,8 +48,8 @@ static char *print_lockmode(int mode)
}
}
-static int print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,
- struct dlm_rsb *res)
+static void print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,
+ struct dlm_rsb *res)
{
seq_printf(s, "%08x %s", lkb->lkb_id, print_lockmode(lkb->lkb_grmode));
@@ -68,21 +68,17 @@ static int print_format1_lock(struct seq_file *s, struct dlm_lkb *lkb,
if (lkb->lkb_wait_type)
seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
- return seq_puts(s, "\n");
+ seq_puts(s, "\n");
}
-static int print_format1(struct dlm_rsb *res, struct seq_file *s)
+static void print_format1(struct dlm_rsb *res, struct seq_file *s)
{
struct dlm_lkb *lkb;
int i, lvblen = res->res_ls->ls_lvblen, recover_list, root_list;
- int rv;
lock_rsb(res);
- rv = seq_printf(s, "\nResource %p Name (len=%d) \"",
- res, res->res_length);
- if (rv)
- goto out;
+ seq_printf(s, "\nResource %p Name (len=%d) \"", res, res->res_length);
for (i = 0; i < res->res_length; i++) {
if (isprint(res->res_name[i]))
@@ -92,17 +88,16 @@ static int print_format1(struct dlm_rsb *res, struct seq_file *s)
}
if (res->res_nodeid > 0)
- rv = seq_printf(s, "\"\nLocal Copy, Master is node %d\n",
- res->res_nodeid);
+ seq_printf(s, "\"\nLocal Copy, Master is node %d\n",
+ res->res_nodeid);
else if (res->res_nodeid == 0)
- rv = seq_puts(s, "\"\nMaster Copy\n");
+ seq_puts(s, "\"\nMaster Copy\n");
else if (res->res_nodeid == -1)
- rv = seq_printf(s, "\"\nLooking up master (lkid %x)\n",
- res->res_first_lkid);
+ seq_printf(s, "\"\nLooking up master (lkid %x)\n",
+ res->res_first_lkid);
else
- rv = seq_printf(s, "\"\nInvalid master %d\n",
- res->res_nodeid);
- if (rv)
+ seq_printf(s, "\"\nInvalid master %d\n", res->res_nodeid);
+ if (seq_has_overflowed(s))
goto out;
/* Print the LVB: */
@@ -116,8 +111,8 @@ static int print_format1(struct dlm_rsb *res, struct seq_file *s)
}
if (rsb_flag(res, RSB_VALNOTVALID))
seq_puts(s, " (INVALID)");
- rv = seq_puts(s, "\n");
- if (rv)
+ seq_puts(s, "\n");
+ if (seq_has_overflowed(s))
goto out;
}
@@ -125,32 +120,30 @@ static int print_format1(struct dlm_rsb *res, struct seq_file *s)
recover_list = !list_empty(&res->res_recover_list);
if (root_list || recover_list) {
- rv = seq_printf(s, "Recovery: root %d recover %d flags %lx "
- "count %d\n", root_list, recover_list,
- res->res_flags, res->res_recover_locks_count);
- if (rv)
- goto out;
+ seq_printf(s, "Recovery: root %d recover %d flags %lx count %d\n",
+ root_list, recover_list,
+ res->res_flags, res->res_recover_locks_count);
}
/* Print the locks attached to this resource */
seq_puts(s, "Granted Queue\n");
list_for_each_entry(lkb, &res->res_grantqueue, lkb_statequeue) {
- rv = print_format1_lock(s, lkb, res);
- if (rv)
+ print_format1_lock(s, lkb, res);
+ if (seq_has_overflowed(s))
goto out;
}
seq_puts(s, "Conversion Queue\n");
list_for_each_entry(lkb, &res->res_convertqueue, lkb_statequeue) {
- rv = print_format1_lock(s, lkb, res);
- if (rv)
+ print_format1_lock(s, lkb, res);
+ if (seq_has_overflowed(s))
goto out;
}
seq_puts(s, "Waiting Queue\n");
list_for_each_entry(lkb, &res->res_waitqueue, lkb_statequeue) {
- rv = print_format1_lock(s, lkb, res);
- if (rv)
+ print_format1_lock(s, lkb, res);
+ if (seq_has_overflowed(s))
goto out;
}
@@ -159,23 +152,23 @@ static int print_format1(struct dlm_rsb *res, struct seq_file *s)
seq_puts(s, "Lookup Queue\n");
list_for_each_entry(lkb, &res->res_lookup, lkb_rsb_lookup) {
- rv = seq_printf(s, "%08x %s", lkb->lkb_id,
- print_lockmode(lkb->lkb_rqmode));
+ seq_printf(s, "%08x %s",
+ lkb->lkb_id, print_lockmode(lkb->lkb_rqmode));
if (lkb->lkb_wait_type)
seq_printf(s, " wait_type: %d", lkb->lkb_wait_type);
- rv = seq_puts(s, "\n");
+ seq_puts(s, "\n");
+ if (seq_has_overflowed(s))
+ goto out;
}
out:
unlock_rsb(res);
- return rv;
}
-static int print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,
- struct dlm_rsb *r)
+static void print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,
+ struct dlm_rsb *r)
{
u64 xid = 0;
u64 us;
- int rv;
if (lkb->lkb_flags & DLM_IFL_USER) {
if (lkb->lkb_ua)
@@ -188,103 +181,97 @@ static int print_format2_lock(struct seq_file *s, struct dlm_lkb *lkb,
/* id nodeid remid pid xid exflags flags sts grmode rqmode time_us
r_nodeid r_len r_name */
- rv = seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n",
- lkb->lkb_id,
- lkb->lkb_nodeid,
- lkb->lkb_remid,
- lkb->lkb_ownpid,
- (unsigned long long)xid,
- lkb->lkb_exflags,
- lkb->lkb_flags,
- lkb->lkb_status,
- lkb->lkb_grmode,
- lkb->lkb_rqmode,
- (unsigned long long)us,
- r->res_nodeid,
- r->res_length,
- r->res_name);
- return rv;
+ seq_printf(s, "%x %d %x %u %llu %x %x %d %d %d %llu %u %d \"%s\"\n",
+ lkb->lkb_id,
+ lkb->lkb_nodeid,
+ lkb->lkb_remid,
+ lkb->lkb_ownpid,
+ (unsigned long long)xid,
+ lkb->lkb_exflags,
+ lkb->lkb_flags,
+ lkb->lkb_status,
+ lkb->lkb_grmode,
+ lkb->lkb_rqmode,
+ (unsigned long long)us,
+ r->res_nodeid,
+ r->res_length,
+ r->res_name);
}
-static int print_format2(struct dlm_rsb *r, struct seq_file *s)
+static void print_format2(struct dlm_rsb *r, struct seq_file *s)
{
struct dlm_lkb *lkb;
- int rv = 0;
lock_rsb(r);
list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
- rv = print_format2_lock(s, lkb, r);
- if (rv)
+ print_format2_lock(s, lkb, r);
+ if (seq_has_overflowed(s))
goto out;
}
list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
- rv = print_format2_lock(s, lkb, r);
- if (rv)
+ print_format2_lock(s, lkb, r);
+ if (seq_has_overflowed(s))
goto out;
}
list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
- rv = print_format2_lock(s, lkb, r);
- if (rv)
+ print_format2_lock(s, lkb, r);
+ if (seq_has_overflowed(s))
goto out;
}
out:
unlock_rsb(r);
- return rv;
}
-static int print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
+static void print_format3_lock(struct seq_file *s, struct dlm_lkb *lkb,
int rsb_lookup)
{
u64 xid = 0;
- int rv;
if (lkb->lkb_flags & DLM_IFL_USER) {
if (lkb->lkb_ua)
xid = lkb->lkb_ua->xid;
}
- rv = seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n",
- lkb->lkb_id,
- lkb->lkb_nodeid,
- lkb->lkb_remid,
- lkb->lkb_ownpid,
- (unsigned long long)xid,
- lkb->lkb_exflags,
- lkb->lkb_flags,
- lkb->lkb_status,
- lkb->lkb_grmode,
- lkb->lkb_rqmode,
- lkb->lkb_last_bast.mode,
- rsb_lookup,
- lkb->lkb_wait_type,
- lkb->lkb_lvbseq,
- (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
- (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time));
- return rv;
+ seq_printf(s, "lkb %x %d %x %u %llu %x %x %d %d %d %d %d %d %u %llu %llu\n",
+ lkb->lkb_id,
+ lkb->lkb_nodeid,
+ lkb->lkb_remid,
+ lkb->lkb_ownpid,
+ (unsigned long long)xid,
+ lkb->lkb_exflags,
+ lkb->lkb_flags,
+ lkb->lkb_status,
+ lkb->lkb_grmode,
+ lkb->lkb_rqmode,
+ lkb->lkb_last_bast.mode,
+ rsb_lookup,
+ lkb->lkb_wait_type,
+ lkb->lkb_lvbseq,
+ (unsigned long long)ktime_to_ns(lkb->lkb_timestamp),
+ (unsigned long long)ktime_to_ns(lkb->lkb_last_bast_time));
}
-static int print_format3(struct dlm_rsb *r, struct seq_file *s)
+static void print_format3(struct dlm_rsb *r, struct seq_file *s)
{
struct dlm_lkb *lkb;
int i, lvblen = r->res_ls->ls_lvblen;
int print_name = 1;
- int rv;
lock_rsb(r);
- rv = seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ",
- r,
- r->res_nodeid,
- r->res_first_lkid,
- r->res_flags,
- !list_empty(&r->res_root_list),
- !list_empty(&r->res_recover_list),
- r->res_recover_locks_count,
- r->res_length);
- if (rv)
+ seq_printf(s, "rsb %p %d %x %lx %d %d %u %d ",
+ r,
+ r->res_nodeid,
+ r->res_first_lkid,
+ r->res_flags,
+ !list_empty(&r->res_root_list),
+ !list_empty(&r->res_recover_list),
+ r->res_recover_locks_count,
+ r->res_length);
+ if (seq_has_overflowed(s))
goto out;
for (i = 0; i < r->res_length; i++) {
@@ -292,7 +279,7 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s)
print_name = 0;
}
- seq_printf(s, "%s", print_name ? "str " : "hex");
+ seq_puts(s, print_name ? "str " : "hex");
for (i = 0; i < r->res_length; i++) {
if (print_name)
@@ -300,8 +287,8 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s)
else
seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
}
- rv = seq_puts(s, "\n");
- if (rv)
+ seq_puts(s, "\n");
+ if (seq_has_overflowed(s))
goto out;
if (!r->res_lvbptr)
@@ -311,65 +298,62 @@ static int print_format3(struct dlm_rsb *r, struct seq_file *s)
for (i = 0; i < lvblen; i++)
seq_printf(s, " %02x", (unsigned char)r->res_lvbptr[i]);
- rv = seq_puts(s, "\n");
- if (rv)
+ seq_puts(s, "\n");
+ if (seq_has_overflowed(s))
goto out;
do_locks:
list_for_each_entry(lkb, &r->res_grantqueue, lkb_statequeue) {
- rv = print_format3_lock(s, lkb, 0);
- if (rv)
+ print_format3_lock(s, lkb, 0);
+ if (seq_has_overflowed(s))
goto out;
}
list_for_each_entry(lkb, &r->res_convertqueue, lkb_statequeue) {
- rv = print_format3_lock(s, lkb, 0);
- if (rv)
+ print_format3_lock(s, lkb, 0);
+ if (seq_has_overflowed(s))
goto out;
}
list_for_each_entry(lkb, &r->res_waitqueue, lkb_statequeue) {
- rv = print_format3_lock(s, lkb, 0);
- if (rv)
+ print_format3_lock(s, lkb, 0);
+ if (seq_has_overflowed(s))
goto out;
}
list_for_each_entry(lkb, &r->res_lookup, lkb_rsb_lookup) {
- rv = print_format3_lock(s, lkb, 1);
- if (rv)
+ print_format3_lock(s, lkb, 1);
+ if (seq_has_overflowed(s))
goto out;
}
out:
unlock_rsb(r);
- return rv;
}
-static int print_format4(struct dlm_rsb *r, struct seq_file *s)
+static void print_format4(struct dlm_rsb *r, struct seq_file *s)
{
int our_nodeid = dlm_our_nodeid();
int print_name = 1;
- int i, rv;
+ int i;
lock_rsb(r);
- rv = seq_printf(s, "rsb %p %d %d %d %d %lu %lx %d ",
- r,
- r->res_nodeid,
- r->res_master_nodeid,
- r->res_dir_nodeid,
- our_nodeid,
- r->res_toss_time,
- r->res_flags,
- r->res_length);
- if (rv)
- goto out;
+ seq_printf(s, "rsb %p %d %d %d %d %lu %lx %d ",
+ r,
+ r->res_nodeid,
+ r->res_master_nodeid,
+ r->res_dir_nodeid,
+ our_nodeid,
+ r->res_toss_time,
+ r->res_flags,
+ r->res_length);
for (i = 0; i < r->res_length; i++) {
if (!isascii(r->res_name[i]) || !isprint(r->res_name[i]))
print_name = 0;
}
- seq_printf(s, "%s", print_name ? "str " : "hex");
+ seq_puts(s, print_name ? "str " : "hex");
for (i = 0; i < r->res_length; i++) {
if (print_name)
@@ -377,10 +361,9 @@ static int print_format4(struct dlm_rsb *r, struct seq_file *s)
else
seq_printf(s, " %02x", (unsigned char)r->res_name[i]);
}
- rv = seq_puts(s, "\n");
- out:
+ seq_puts(s, "\n");
+
unlock_rsb(r);
- return rv;
}
struct rsbtbl_iter {
@@ -390,47 +373,45 @@ struct rsbtbl_iter {
int header;
};
-/* seq_printf returns -1 if the buffer is full, and 0 otherwise.
- If the buffer is full, seq_printf can be called again, but it
- does nothing and just returns -1. So, the these printing routines
- periodically check the return value to avoid wasting too much time
- trying to print to a full buffer. */
+/*
+ * If the buffer is full, seq_printf can be called again, but it
+ * does nothing. So, the these printing routines periodically check
+ * seq_has_overflowed to avoid wasting too much time trying to print to
+ * a full buffer.
+ */
static int table_seq_show(struct seq_file *seq, void *iter_ptr)
{
struct rsbtbl_iter *ri = iter_ptr;
- int rv = 0;
switch (ri->format) {
case 1:
- rv = print_format1(ri->rsb, seq);
+ print_format1(ri->rsb, seq);
break;
case 2:
if (ri->header) {
- seq_printf(seq, "id nodeid remid pid xid exflags "
- "flags sts grmode rqmode time_ms "
- "r_nodeid r_len r_name\n");
+ seq_puts(seq, "id nodeid remid pid xid exflags flags sts grmode rqmode time_ms r_nodeid r_len r_name\n");
ri->header = 0;
}
- rv = print_format2(ri->rsb, seq);
+ print_format2(ri->rsb, seq);
break;
case 3:
if (ri->header) {
- seq_printf(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n");
+ seq_puts(seq, "version rsb 1.1 lvb 1.1 lkb 1.1\n");
ri->header = 0;
}
- rv = print_format3(ri->rsb, seq);
+ print_format3(ri->rsb, seq);
break;
case 4:
if (ri->header) {
- seq_printf(seq, "version 4 rsb 2\n");
+ seq_puts(seq, "version 4 rsb 2\n");
ri->header = 0;
}
- rv = print_format4(ri->rsb, seq);
+ print_format4(ri->rsb, seq);
break;
}
- return rv;
+ return 0;
}
static const struct seq_operations format1_seq_ops;
diff --git a/fs/dlm/lock.c b/fs/dlm/lock.c
index 83f3d55..35502d4 100644
--- a/fs/dlm/lock.c
+++ b/fs/dlm/lock.c
@@ -5886,6 +5886,78 @@ int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
return error;
}
+/*
+ * The caller asks for an orphan lock on a given resource with a given mode.
+ * If a matching lock exists, it's moved to the owner's list of locks and
+ * the lkid is returned.
+ */
+
+int dlm_user_adopt_orphan(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ int mode, uint32_t flags, void *name, unsigned int namelen,
+ unsigned long timeout_cs, uint32_t *lkid)
+{
+ struct dlm_lkb *lkb;
+ struct dlm_user_args *ua;
+ int found_other_mode = 0;
+ int found = 0;
+ int rv = 0;
+
+ mutex_lock(&ls->ls_orphans_mutex);
+ list_for_each_entry(lkb, &ls->ls_orphans, lkb_ownqueue) {
+ if (lkb->lkb_resource->res_length != namelen)
+ continue;
+ if (memcmp(lkb->lkb_resource->res_name, name, namelen))
+ continue;
+ if (lkb->lkb_grmode != mode) {
+ found_other_mode = 1;
+ continue;
+ }
+
+ found = 1;
+ list_del_init(&lkb->lkb_ownqueue);
+ lkb->lkb_flags &= ~DLM_IFL_ORPHAN;
+ *lkid = lkb->lkb_id;
+ break;
+ }
+ mutex_unlock(&ls->ls_orphans_mutex);
+
+ if (!found && found_other_mode) {
+ rv = -EAGAIN;
+ goto out;
+ }
+
+ if (!found) {
+ rv = -ENOENT;
+ goto out;
+ }
+
+ lkb->lkb_exflags = flags;
+ lkb->lkb_ownpid = (int) current->pid;
+
+ ua = lkb->lkb_ua;
+
+ ua->proc = ua_tmp->proc;
+ ua->xid = ua_tmp->xid;
+ ua->castparam = ua_tmp->castparam;
+ ua->castaddr = ua_tmp->castaddr;
+ ua->bastparam = ua_tmp->bastparam;
+ ua->bastaddr = ua_tmp->bastaddr;
+ ua->user_lksb = ua_tmp->user_lksb;
+
+ /*
+ * The lkb reference from the ls_orphans list was not
+ * removed above, and is now considered the reference
+ * for the proc locks list.
+ */
+
+ spin_lock(&ua->proc->locks_spin);
+ list_add_tail(&lkb->lkb_ownqueue, &ua->proc->locks);
+ spin_unlock(&ua->proc->locks_spin);
+ out:
+ kfree(ua_tmp);
+ return rv;
+}
+
int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
uint32_t flags, uint32_t lkid, char *lvb_in)
{
@@ -6029,7 +6101,7 @@ static int orphan_proc_lock(struct dlm_ls *ls, struct dlm_lkb *lkb)
struct dlm_args args;
int error;
- hold_lkb(lkb);
+ hold_lkb(lkb); /* reference for the ls_orphans list */
mutex_lock(&ls->ls_orphans_mutex);
list_add_tail(&lkb->lkb_ownqueue, &ls->ls_orphans);
mutex_unlock(&ls->ls_orphans_mutex);
@@ -6217,7 +6289,7 @@ int dlm_user_purge(struct dlm_ls *ls, struct dlm_user_proc *proc,
{
int error = 0;
- if (nodeid != dlm_our_nodeid()) {
+ if (nodeid && (nodeid != dlm_our_nodeid())) {
error = send_purge(ls, nodeid, pid);
} else {
dlm_lock_recovery(ls);
diff --git a/fs/dlm/lock.h b/fs/dlm/lock.h
index 5e0c72e..ed8ebd3 100644
--- a/fs/dlm/lock.h
+++ b/fs/dlm/lock.h
@@ -49,6 +49,9 @@ int dlm_user_request(struct dlm_ls *ls, struct dlm_user_args *ua, int mode,
int dlm_user_convert(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
int mode, uint32_t flags, uint32_t lkid, char *lvb_in,
unsigned long timeout_cs);
+int dlm_user_adopt_orphan(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
+ int mode, uint32_t flags, void *name, unsigned int namelen,
+ unsigned long timeout_cs, uint32_t *lkid);
int dlm_user_unlock(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
uint32_t flags, uint32_t lkid, char *lvb_in);
int dlm_user_cancel(struct dlm_ls *ls, struct dlm_user_args *ua_tmp,
diff --git a/fs/dlm/user.c b/fs/dlm/user.c
index 142e2165..fb85f32 100644
--- a/fs/dlm/user.c
+++ b/fs/dlm/user.c
@@ -238,6 +238,7 @@ static int device_user_lock(struct dlm_user_proc *proc,
{
struct dlm_ls *ls;
struct dlm_user_args *ua;
+ uint32_t lkid;
int error = -ENOMEM;
ls = dlm_find_lockspace_local(proc->lockspace);
@@ -260,12 +261,20 @@ static int device_user_lock(struct dlm_user_proc *proc,
ua->bastaddr = params->bastaddr;
ua->xid = params->xid;
- if (params->flags & DLM_LKF_CONVERT)
+ if (params->flags & DLM_LKF_CONVERT) {
error = dlm_user_convert(ls, ua,
params->mode, params->flags,
params->lkid, params->lvb,
(unsigned long) params->timeout);
- else {
+ } else if (params->flags & DLM_LKF_ORPHAN) {
+ error = dlm_user_adopt_orphan(ls, ua,
+ params->mode, params->flags,
+ params->name, params->namelen,
+ (unsigned long) params->timeout,
+ &lkid);
+ if (!error)
+ error = lkid;
+ } else {
error = dlm_user_request(ls, ua,
params->mode, params->flags,
params->name, params->namelen,
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index 2f6735d..c2d6604 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -1373,7 +1373,7 @@ out:
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode)
{
struct dentry *lower_dentry =
- ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;
+ ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_path.dentry;
ssize_t size;
int rc = 0;
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index f5bce90..80154ec 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -75,11 +75,11 @@ struct ecryptfs_getdents_callback {
/* Inspired by generic filldir in fs/readdir.c */
static int
-ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,
- loff_t offset, u64 ino, unsigned int d_type)
+ecryptfs_filldir(struct dir_context *ctx, const char *lower_name,
+ int lower_namelen, loff_t offset, u64 ino, unsigned int d_type)
{
struct ecryptfs_getdents_callback *buf =
- (struct ecryptfs_getdents_callback *)dirent;
+ container_of(ctx, struct ecryptfs_getdents_callback, ctx);
size_t name_size;
char *name;
int rc;
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 564a1fa..4626976 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -419,7 +419,7 @@ static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)
ssize_t size;
void *xattr_virt;
struct dentry *lower_dentry =
- ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;
+ ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_path.dentry;
struct inode *lower_inode = lower_dentry->d_inode;
int rc;
diff --git a/fs/efivarfs/file.c b/fs/efivarfs/file.c
index cdb2971..90001da 100644
--- a/fs/efivarfs/file.c
+++ b/fs/efivarfs/file.c
@@ -47,8 +47,8 @@ static ssize_t efivarfs_file_write(struct file *file,
if (bytes == -ENOENT) {
drop_nlink(inode);
- d_delete(file->f_dentry);
- dput(file->f_dentry);
+ d_delete(file->f_path.dentry);
+ dput(file->f_path.dentry);
} else {
mutex_lock(&inode->i_mutex);
i_size_write(inode, datasize + sizeof(attributes));
diff --git a/fs/efivarfs/super.c b/fs/efivarfs/super.c
index 0a48886..6dad117 100644
--- a/fs/efivarfs/super.c
+++ b/fs/efivarfs/super.c
@@ -236,6 +236,7 @@ static void efivarfs_kill_sb(struct super_block *sb)
}
static struct file_system_type efivarfs_type = {
+ .owner = THIS_MODULE,
.name = "efivarfs",
.mount = efivarfs_mount,
.kill_sb = efivarfs_kill_sb,
@@ -244,17 +245,23 @@ static struct file_system_type efivarfs_type = {
static __init int efivarfs_init(void)
{
if (!efi_enabled(EFI_RUNTIME_SERVICES))
- return 0;
+ return -ENODEV;
if (!efivars_kobject())
- return 0;
+ return -ENODEV;
return register_filesystem(&efivarfs_type);
}
+static __exit void efivarfs_exit(void)
+{
+ unregister_filesystem(&efivarfs_type);
+}
+
MODULE_AUTHOR("Matthew Garrett, Jeremy Kerr");
MODULE_DESCRIPTION("EFI Variable Filesystem");
MODULE_LICENSE("GPL");
MODULE_ALIAS_FS("efivarfs");
module_init(efivarfs_init);
+module_exit(efivarfs_exit);
diff --git a/fs/eventfd.c b/fs/eventfd.c
index d6a88e7..4b0a226 100644
--- a/fs/eventfd.c
+++ b/fs/eventfd.c
@@ -287,17 +287,14 @@ static ssize_t eventfd_write(struct file *file, const char __user *buf, size_t c
}
#ifdef CONFIG_PROC_FS
-static int eventfd_show_fdinfo(struct seq_file *m, struct file *f)
+static void eventfd_show_fdinfo(struct seq_file *m, struct file *f)
{
struct eventfd_ctx *ctx = f->private_data;
- int ret;
spin_lock_irq(&ctx->wqh.lock);
- ret = seq_printf(m, "eventfd-count: %16llx\n",
- (unsigned long long)ctx->count);
+ seq_printf(m, "eventfd-count: %16llx\n",
+ (unsigned long long)ctx->count);
spin_unlock_irq(&ctx->wqh.lock);
-
- return ret;
}
#endif
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index 7bcfff9..d77f944 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -870,25 +870,22 @@ static unsigned int ep_eventpoll_poll(struct file *file, poll_table *wait)
}
#ifdef CONFIG_PROC_FS
-static int ep_show_fdinfo(struct seq_file *m, struct file *f)
+static void ep_show_fdinfo(struct seq_file *m, struct file *f)
{
struct eventpoll *ep = f->private_data;
struct rb_node *rbp;
- int ret = 0;
mutex_lock(&ep->mtx);
for (rbp = rb_first(&ep->rbr); rbp; rbp = rb_next(rbp)) {
struct epitem *epi = rb_entry(rbp, struct epitem, rbn);
- ret = seq_printf(m, "tfd: %8d events: %8x data: %16llx\n",
- epi->ffd.fd, epi->event.events,
- (long long)epi->event.data);
- if (ret)
+ seq_printf(m, "tfd: %8d events: %8x data: %16llx\n",
+ epi->ffd.fd, epi->event.events,
+ (long long)epi->event.data);
+ if (seq_has_overflowed(m))
break;
}
mutex_unlock(&ep->mtx);
-
- return ret;
}
#endif
diff --git a/fs/exec.c b/fs/exec.c
index 7302b75..01aebe3 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -277,6 +277,7 @@ static int __bprm_mm_init(struct linux_binprm *bprm)
goto err;
mm->stack_vm = mm->total_vm = 1;
+ arch_bprm_mm_init(mm, vma);
up_write(&mm->mmap_sem);
bprm->p = vma->vm_end - sizeof(void *);
return 0;
diff --git a/fs/exportfs/expfs.c b/fs/exportfs/expfs.c
index b01fbfb..fdfd206 100644
--- a/fs/exportfs/expfs.c
+++ b/fs/exportfs/expfs.c
@@ -50,7 +50,7 @@ find_acceptable_alias(struct dentry *result,
inode = result->d_inode;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
dget(dentry);
spin_unlock(&inode->i_lock);
if (toput)
@@ -241,10 +241,11 @@ struct getdents_callback {
* A rather strange filldir function to capture
* the name matching the specified inode number.
*/
-static int filldir_one(void * __buf, const char * name, int len,
+static int filldir_one(struct dir_context *ctx, const char *name, int len,
loff_t pos, u64 ino, unsigned int d_type)
{
- struct getdents_callback *buf = __buf;
+ struct getdents_callback *buf =
+ container_of(ctx, struct getdents_callback, ctx);
int result = 0;
buf->sequence++;
diff --git a/fs/ext2/ext2.h b/fs/ext2/ext2.h
index d9a17d0..e4279ea 100644
--- a/fs/ext2/ext2.h
+++ b/fs/ext2/ext2.h
@@ -689,6 +689,9 @@ struct ext2_inode_info {
struct mutex truncate_mutex;
struct inode vfs_inode;
struct list_head i_orphan; /* unlinked but open inodes */
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+#endif
};
/*
diff --git a/fs/ext2/super.c b/fs/ext2/super.c
index 170dc41..ae55fdd 100644
--- a/fs/ext2/super.c
+++ b/fs/ext2/super.c
@@ -166,6 +166,10 @@ static struct inode *ext2_alloc_inode(struct super_block *sb)
return NULL;
ei->i_block_alloc_info = NULL;
ei->vfs_inode.i_version = 1;
+#ifdef CONFIG_QUOTA
+ memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
+#endif
+
return &ei->vfs_inode;
}
@@ -303,6 +307,10 @@ static int ext2_show_options(struct seq_file *seq, struct dentry *root)
#ifdef CONFIG_QUOTA
static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off);
static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off);
+static struct dquot **ext2_get_dquots(struct inode *inode)
+{
+ return EXT2_I(inode)->i_dquot;
+}
#endif
static const struct super_operations ext2_sops = {
@@ -320,6 +328,7 @@ static const struct super_operations ext2_sops = {
#ifdef CONFIG_QUOTA
.quota_read = ext2_quota_read,
.quota_write = ext2_quota_write,
+ .get_dquots = ext2_get_dquots,
#endif
};
@@ -1090,6 +1099,7 @@ static int ext2_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_QUOTA
sb->dq_op = &dquot_operations;
sb->s_qcop = &dquot_quotactl_ops;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
#endif
root = ext2_iget(sb, EXT2_ROOT_INO);
diff --git a/fs/ext3/ext3.h b/fs/ext3/ext3.h
index fc3cdcf..f483a80 100644
--- a/fs/ext3/ext3.h
+++ b/fs/ext3/ext3.h
@@ -615,6 +615,10 @@ struct ext3_inode_info {
atomic_t i_sync_tid;
atomic_t i_datasync_tid;
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+#endif
+
struct inode vfs_inode;
};
diff --git a/fs/ext3/super.c b/fs/ext3/super.c
index eb742d0..9b4e7d7 100644
--- a/fs/ext3/super.c
+++ b/fs/ext3/super.c
@@ -485,6 +485,10 @@ static struct inode *ext3_alloc_inode(struct super_block *sb)
ei->vfs_inode.i_version = 1;
atomic_set(&ei->i_datasync_tid, 0);
atomic_set(&ei->i_sync_tid, 0);
+#ifdef CONFIG_QUOTA
+ memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
+#endif
+
return &ei->vfs_inode;
}
@@ -764,6 +768,10 @@ static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data,
size_t len, loff_t off);
static ssize_t ext3_quota_write(struct super_block *sb, int type,
const char *data, size_t len, loff_t off);
+static struct dquot **ext3_get_dquots(struct inode *inode)
+{
+ return EXT3_I(inode)->i_dquot;
+}
static const struct dquot_operations ext3_quota_operations = {
.write_dquot = ext3_write_dquot,
@@ -803,6 +811,7 @@ static const struct super_operations ext3_sops = {
#ifdef CONFIG_QUOTA
.quota_read = ext3_quota_read,
.quota_write = ext3_quota_write,
+ .get_dquots = ext3_get_dquots,
#endif
.bdev_try_to_free_page = bdev_try_to_free_page,
};
@@ -2001,6 +2010,7 @@ static int ext3_fill_super (struct super_block *sb, void *data, int silent)
#ifdef CONFIG_QUOTA
sb->s_qcop = &ext3_qctl_operations;
sb->dq_op = &ext3_quota_operations;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
#endif
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */
diff --git a/fs/ext4/ext4.h b/fs/ext4/ext4.h
index c55a1fa..db3f772 100644
--- a/fs/ext4/ext4.h
+++ b/fs/ext4/ext4.h
@@ -941,6 +941,10 @@ struct ext4_inode_info {
tid_t i_sync_tid;
tid_t i_datasync_tid;
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+#endif
+
/* Precomputed uuid+inum+igen checksum for seeding inode checksums */
__u32 i_csum_seed;
};
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 2c9e686..63e802b 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -892,6 +892,7 @@ static struct inode *ext4_alloc_inode(struct super_block *sb)
spin_lock_init(&(ei->i_block_reservation_lock));
#ifdef CONFIG_QUOTA
ei->i_reserved_quota = 0;
+ memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
#endif
ei->jinode = NULL;
INIT_LIST_HEAD(&ei->i_rsv_conversion_list);
@@ -1068,6 +1069,11 @@ static int ext4_quota_enable(struct super_block *sb, int type, int format_id,
unsigned int flags);
static int ext4_enable_quotas(struct super_block *sb);
+static struct dquot **ext4_get_dquots(struct inode *inode)
+{
+ return EXT4_I(inode)->i_dquot;
+}
+
static const struct dquot_operations ext4_quota_operations = {
.get_reserved_space = ext4_get_reserved_space,
.write_dquot = ext4_write_dquot,
@@ -1117,6 +1123,7 @@ static const struct super_operations ext4_sops = {
#ifdef CONFIG_QUOTA
.quota_read = ext4_quota_read,
.quota_write = ext4_quota_write,
+ .get_dquots = ext4_get_dquots,
#endif
.bdev_try_to_free_page = bdev_try_to_free_page,
};
@@ -3932,6 +3939,7 @@ static int ext4_fill_super(struct super_block *sb, void *data, int silent)
sb->s_qcop = &ext4_qctl_sysfile_operations;
else
sb->s_qcop = &ext4_qctl_operations;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
#endif
memcpy(sb->s_uuid, es->s_uuid, sizeof(es->s_uuid));
diff --git a/fs/f2fs/acl.c b/fs/f2fs/acl.c
index 83b9b5a..1ccb26b 100644
--- a/fs/f2fs/acl.c
+++ b/fs/f2fs/acl.c
@@ -162,7 +162,8 @@ fail:
return ERR_PTR(-EINVAL);
}
-struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
+static struct posix_acl *__f2fs_get_acl(struct inode *inode, int type,
+ struct page *dpage)
{
int name_index = F2FS_XATTR_INDEX_POSIX_ACL_DEFAULT;
void *value = NULL;
@@ -172,12 +173,13 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
if (type == ACL_TYPE_ACCESS)
name_index = F2FS_XATTR_INDEX_POSIX_ACL_ACCESS;
- retval = f2fs_getxattr(inode, name_index, "", NULL, 0);
+ retval = f2fs_getxattr(inode, name_index, "", NULL, 0, dpage);
if (retval > 0) {
value = kmalloc(retval, GFP_F2FS_ZERO);
if (!value)
return ERR_PTR(-ENOMEM);
- retval = f2fs_getxattr(inode, name_index, "", value, retval);
+ retval = f2fs_getxattr(inode, name_index, "", value,
+ retval, dpage);
}
if (retval > 0)
@@ -194,6 +196,11 @@ struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
return acl;
}
+struct posix_acl *f2fs_get_acl(struct inode *inode, int type)
+{
+ return __f2fs_get_acl(inode, type, NULL);
+}
+
static int __f2fs_set_acl(struct inode *inode, int type,
struct posix_acl *acl, struct page *ipage)
{
@@ -229,7 +236,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
if (acl) {
value = f2fs_acl_to_disk(acl, &size);
if (IS_ERR(value)) {
- cond_clear_inode_flag(fi, FI_ACL_MODE);
+ clear_inode_flag(fi, FI_ACL_MODE);
return (int)PTR_ERR(value);
}
}
@@ -240,7 +247,7 @@ static int __f2fs_set_acl(struct inode *inode, int type,
if (!error)
set_cached_acl(inode, type, acl);
- cond_clear_inode_flag(fi, FI_ACL_MODE);
+ clear_inode_flag(fi, FI_ACL_MODE);
return error;
}
@@ -249,12 +256,137 @@ int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type)
return __f2fs_set_acl(inode, type, acl, NULL);
}
-int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage)
+/*
+ * Most part of f2fs_acl_clone, f2fs_acl_create_masq, f2fs_acl_create
+ * are copied from posix_acl.c
+ */
+static struct posix_acl *f2fs_acl_clone(const struct posix_acl *acl,
+ gfp_t flags)
+{
+ struct posix_acl *clone = NULL;
+
+ if (acl) {
+ int size = sizeof(struct posix_acl) + acl->a_count *
+ sizeof(struct posix_acl_entry);
+ clone = kmemdup(acl, size, flags);
+ if (clone)
+ atomic_set(&clone->a_refcount, 1);
+ }
+ return clone;
+}
+
+static int f2fs_acl_create_masq(struct posix_acl *acl, umode_t *mode_p)
+{
+ struct posix_acl_entry *pa, *pe;
+ struct posix_acl_entry *group_obj = NULL, *mask_obj = NULL;
+ umode_t mode = *mode_p;
+ int not_equiv = 0;
+
+ /* assert(atomic_read(acl->a_refcount) == 1); */
+
+ FOREACH_ACL_ENTRY(pa, acl, pe) {
+ switch(pa->e_tag) {
+ case ACL_USER_OBJ:
+ pa->e_perm &= (mode >> 6) | ~S_IRWXO;
+ mode &= (pa->e_perm << 6) | ~S_IRWXU;
+ break;
+
+ case ACL_USER:
+ case ACL_GROUP:
+ not_equiv = 1;
+ break;
+
+ case ACL_GROUP_OBJ:
+ group_obj = pa;
+ break;
+
+ case ACL_OTHER:
+ pa->e_perm &= mode | ~S_IRWXO;
+ mode &= pa->e_perm | ~S_IRWXO;
+ break;
+
+ case ACL_MASK:
+ mask_obj = pa;
+ not_equiv = 1;
+ break;
+
+ default:
+ return -EIO;
+ }
+ }
+
+ if (mask_obj) {
+ mask_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
+ mode &= (mask_obj->e_perm << 3) | ~S_IRWXG;
+ } else {
+ if (!group_obj)
+ return -EIO;
+ group_obj->e_perm &= (mode >> 3) | ~S_IRWXO;
+ mode &= (group_obj->e_perm << 3) | ~S_IRWXG;
+ }
+
+ *mode_p = (*mode_p & ~S_IRWXUGO) | mode;
+ return not_equiv;
+}
+
+static int f2fs_acl_create(struct inode *dir, umode_t *mode,
+ struct posix_acl **default_acl, struct posix_acl **acl,
+ struct page *dpage)
+{
+ struct posix_acl *p;
+ int ret;
+
+ if (S_ISLNK(*mode) || !IS_POSIXACL(dir))
+ goto no_acl;
+
+ p = __f2fs_get_acl(dir, ACL_TYPE_DEFAULT, dpage);
+ if (IS_ERR(p)) {
+ if (p == ERR_PTR(-EOPNOTSUPP))
+ goto apply_umask;
+ return PTR_ERR(p);
+ }
+
+ if (!p)
+ goto apply_umask;
+
+ *acl = f2fs_acl_clone(p, GFP_NOFS);
+ if (!*acl)
+ return -ENOMEM;
+
+ ret = f2fs_acl_create_masq(*acl, mode);
+ if (ret < 0) {
+ posix_acl_release(*acl);
+ return -ENOMEM;
+ }
+
+ if (ret == 0) {
+ posix_acl_release(*acl);
+ *acl = NULL;
+ }
+
+ if (!S_ISDIR(*mode)) {
+ posix_acl_release(p);
+ *default_acl = NULL;
+ } else {
+ *default_acl = p;
+ }
+ return 0;
+
+apply_umask:
+ *mode &= ~current_umask();
+no_acl:
+ *default_acl = NULL;
+ *acl = NULL;
+ return 0;
+}
+
+int f2fs_init_acl(struct inode *inode, struct inode *dir, struct page *ipage,
+ struct page *dpage)
{
- struct posix_acl *default_acl, *acl;
+ struct posix_acl *default_acl = NULL, *acl = NULL;
int error = 0;
- error = posix_acl_create(dir, &inode->i_mode, &default_acl, &acl);
+ error = f2fs_acl_create(dir, &inode->i_mode, &default_acl, &acl, dpage);
if (error)
return error;
diff --git a/fs/f2fs/acl.h b/fs/f2fs/acl.h
index e086465..997ca8e 100644
--- a/fs/f2fs/acl.h
+++ b/fs/f2fs/acl.h
@@ -38,14 +38,15 @@ struct f2fs_acl_header {
extern struct posix_acl *f2fs_get_acl(struct inode *, int);
extern int f2fs_set_acl(struct inode *inode, struct posix_acl *acl, int type);
-extern int f2fs_init_acl(struct inode *, struct inode *, struct page *);
+extern int f2fs_init_acl(struct inode *, struct inode *, struct page *,
+ struct page *);
#else
#define f2fs_check_acl NULL
#define f2fs_get_acl NULL
#define f2fs_set_acl NULL
static inline int f2fs_init_acl(struct inode *inode, struct inode *dir,
- struct page *page)
+ struct page *ipage, struct page *dpage)
{
return 0;
}
diff --git a/fs/f2fs/checkpoint.c b/fs/f2fs/checkpoint.c
index dd10a03..e6c271f 100644
--- a/fs/f2fs/checkpoint.c
+++ b/fs/f2fs/checkpoint.c
@@ -72,36 +72,36 @@ out:
return page;
}
-struct page *get_meta_page_ra(struct f2fs_sb_info *sbi, pgoff_t index)
-{
- bool readahead = false;
- struct page *page;
-
- page = find_get_page(META_MAPPING(sbi), index);
- if (!page || (page && !PageUptodate(page)))
- readahead = true;
- f2fs_put_page(page, 0);
-
- if (readahead)
- ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR);
- return get_meta_page(sbi, index);
-}
-
-static inline block_t get_max_meta_blks(struct f2fs_sb_info *sbi, int type)
+static inline bool is_valid_blkaddr(struct f2fs_sb_info *sbi,
+ block_t blkaddr, int type)
{
switch (type) {
case META_NAT:
- return NM_I(sbi)->max_nid / NAT_ENTRY_PER_BLOCK;
+ break;
case META_SIT:
- return SIT_BLK_CNT(sbi);
+ if (unlikely(blkaddr >= SIT_BLK_CNT(sbi)))
+ return false;
+ break;
case META_SSA:
+ if (unlikely(blkaddr >= MAIN_BLKADDR(sbi) ||
+ blkaddr < SM_I(sbi)->ssa_blkaddr))
+ return false;
+ break;
case META_CP:
- return 0;
+ if (unlikely(blkaddr >= SIT_I(sbi)->sit_base_addr ||
+ blkaddr < __start_cp_addr(sbi)))
+ return false;
+ break;
case META_POR:
- return MAX_BLKADDR(sbi);
+ if (unlikely(blkaddr >= MAX_BLKADDR(sbi) ||
+ blkaddr < MAIN_BLKADDR(sbi)))
+ return false;
+ break;
default:
BUG();
}
+
+ return true;
}
/*
@@ -112,7 +112,6 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
block_t prev_blk_addr = 0;
struct page *page;
block_t blkno = start;
- block_t max_blks = get_max_meta_blks(sbi, type);
struct f2fs_io_info fio = {
.type = META,
@@ -122,18 +121,20 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
for (; nrpages-- > 0; blkno++) {
block_t blk_addr;
+ if (!is_valid_blkaddr(sbi, blkno, type))
+ goto out;
+
switch (type) {
case META_NAT:
- /* get nat block addr */
- if (unlikely(blkno >= max_blks))
+ if (unlikely(blkno >=
+ NAT_BLOCK_OFFSET(NM_I(sbi)->max_nid)))
blkno = 0;
+ /* get nat block addr */
blk_addr = current_nat_addr(sbi,
blkno * NAT_ENTRY_PER_BLOCK);
break;
case META_SIT:
/* get sit block addr */
- if (unlikely(blkno >= max_blks))
- goto out;
blk_addr = current_sit_addr(sbi,
blkno * SIT_ENTRY_PER_BLOCK);
if (blkno != start && prev_blk_addr + 1 != blk_addr)
@@ -143,10 +144,6 @@ int ra_meta_pages(struct f2fs_sb_info *sbi, block_t start, int nrpages, int type
case META_SSA:
case META_CP:
case META_POR:
- if (unlikely(blkno >= max_blks))
- goto out;
- if (unlikely(blkno < SEG0_BLKADDR(sbi)))
- goto out;
blk_addr = blkno;
break;
default:
@@ -169,6 +166,20 @@ out:
return blkno - start;
}
+void ra_meta_pages_cond(struct f2fs_sb_info *sbi, pgoff_t index)
+{
+ struct page *page;
+ bool readahead = false;
+
+ page = find_get_page(META_MAPPING(sbi), index);
+ if (!page || (page && !PageUptodate(page)))
+ readahead = true;
+ f2fs_put_page(page, 0);
+
+ if (readahead)
+ ra_meta_pages(sbi, index, MAX_BIO_BLOCKS(sbi), META_POR);
+}
+
static int f2fs_write_meta_page(struct page *page,
struct writeback_control *wbc)
{
@@ -178,7 +189,7 @@ static int f2fs_write_meta_page(struct page *page,
if (unlikely(sbi->por_doing))
goto redirty_out;
- if (wbc->for_reclaim)
+ if (wbc->for_reclaim && page->index < GET_SUM_BLOCK(sbi, 0))
goto redirty_out;
if (unlikely(f2fs_cp_error(sbi)))
goto redirty_out;
@@ -187,6 +198,9 @@ static int f2fs_write_meta_page(struct page *page,
write_meta_page(sbi, page);
dec_page_count(sbi, F2FS_DIRTY_META);
unlock_page(page);
+
+ if (wbc->for_reclaim)
+ f2fs_submit_merged_bio(sbi, META, WRITE);
return 0;
redirty_out:
@@ -298,46 +312,57 @@ const struct address_space_operations f2fs_meta_aops = {
static void __add_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
+ struct inode_management *im = &sbi->im[type];
struct ino_entry *e;
retry:
- spin_lock(&sbi->ino_lock[type]);
+ if (radix_tree_preload(GFP_NOFS)) {
+ cond_resched();
+ goto retry;
+ }
+
+ spin_lock(&im->ino_lock);
- e = radix_tree_lookup(&sbi->ino_root[type], ino);
+ e = radix_tree_lookup(&im->ino_root, ino);
if (!e) {
e = kmem_cache_alloc(ino_entry_slab, GFP_ATOMIC);
if (!e) {
- spin_unlock(&sbi->ino_lock[type]);
+ spin_unlock(&im->ino_lock);
+ radix_tree_preload_end();
goto retry;
}
- if (radix_tree_insert(&sbi->ino_root[type], ino, e)) {
- spin_unlock(&sbi->ino_lock[type]);
+ if (radix_tree_insert(&im->ino_root, ino, e)) {
+ spin_unlock(&im->ino_lock);
kmem_cache_free(ino_entry_slab, e);
+ radix_tree_preload_end();
goto retry;
}
memset(e, 0, sizeof(struct ino_entry));
e->ino = ino;
- list_add_tail(&e->list, &sbi->ino_list[type]);
+ list_add_tail(&e->list, &im->ino_list);
+ if (type != ORPHAN_INO)
+ im->ino_num++;
}
- spin_unlock(&sbi->ino_lock[type]);
+ spin_unlock(&im->ino_lock);
+ radix_tree_preload_end();
}
static void __remove_ino_entry(struct f2fs_sb_info *sbi, nid_t ino, int type)
{
+ struct inode_management *im = &sbi->im[type];
struct ino_entry *e;
- spin_lock(&sbi->ino_lock[type]);
- e = radix_tree_lookup(&sbi->ino_root[type], ino);
+ spin_lock(&im->ino_lock);
+ e = radix_tree_lookup(&im->ino_root, ino);
if (e) {
list_del(&e->list);
- radix_tree_delete(&sbi->ino_root[type], ino);
- if (type == ORPHAN_INO)
- sbi->n_orphans--;
- spin_unlock(&sbi->ino_lock[type]);
+ radix_tree_delete(&im->ino_root, ino);
+ im->ino_num--;
+ spin_unlock(&im->ino_lock);
kmem_cache_free(ino_entry_slab, e);
return;
}
- spin_unlock(&sbi->ino_lock[type]);
+ spin_unlock(&im->ino_lock);
}
void add_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
@@ -355,10 +380,12 @@ void remove_dirty_inode(struct f2fs_sb_info *sbi, nid_t ino, int type)
/* mode should be APPEND_INO or UPDATE_INO */
bool exist_written_data(struct f2fs_sb_info *sbi, nid_t ino, int mode)
{
+ struct inode_management *im = &sbi->im[mode];
struct ino_entry *e;
- spin_lock(&sbi->ino_lock[mode]);
- e = radix_tree_lookup(&sbi->ino_root[mode], ino);
- spin_unlock(&sbi->ino_lock[mode]);
+
+ spin_lock(&im->ino_lock);
+ e = radix_tree_lookup(&im->ino_root, ino);
+ spin_unlock(&im->ino_lock);
return e ? true : false;
}
@@ -368,36 +395,42 @@ void release_dirty_inode(struct f2fs_sb_info *sbi)
int i;
for (i = APPEND_INO; i <= UPDATE_INO; i++) {
- spin_lock(&sbi->ino_lock[i]);
- list_for_each_entry_safe(e, tmp, &sbi->ino_list[i], list) {
+ struct inode_management *im = &sbi->im[i];
+
+ spin_lock(&im->ino_lock);
+ list_for_each_entry_safe(e, tmp, &im->ino_list, list) {
list_del(&e->list);
- radix_tree_delete(&sbi->ino_root[i], e->ino);
+ radix_tree_delete(&im->ino_root, e->ino);
kmem_cache_free(ino_entry_slab, e);
+ im->ino_num--;
}
- spin_unlock(&sbi->ino_lock[i]);
+ spin_unlock(&im->ino_lock);
}
}
int acquire_orphan_inode(struct f2fs_sb_info *sbi)
{
+ struct inode_management *im = &sbi->im[ORPHAN_INO];
int err = 0;
- spin_lock(&sbi->ino_lock[ORPHAN_INO]);
- if (unlikely(sbi->n_orphans >= sbi->max_orphans))
+ spin_lock(&im->ino_lock);
+ if (unlikely(im->ino_num >= sbi->max_orphans))
err = -ENOSPC;
else
- sbi->n_orphans++;
- spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
+ im->ino_num++;
+ spin_unlock(&im->ino_lock);
return err;
}
void release_orphan_inode(struct f2fs_sb_info *sbi)
{
- spin_lock(&sbi->ino_lock[ORPHAN_INO]);
- f2fs_bug_on(sbi, sbi->n_orphans == 0);
- sbi->n_orphans--;
- spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
+ struct inode_management *im = &sbi->im[ORPHAN_INO];
+
+ spin_lock(&im->ino_lock);
+ f2fs_bug_on(sbi, im->ino_num == 0);
+ im->ino_num--;
+ spin_unlock(&im->ino_lock);
}
void add_orphan_inode(struct f2fs_sb_info *sbi, nid_t ino)
@@ -460,17 +493,19 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
struct f2fs_orphan_block *orphan_blk = NULL;
unsigned int nentries = 0;
unsigned short index;
- unsigned short orphan_blocks =
- (unsigned short)GET_ORPHAN_BLOCKS(sbi->n_orphans);
+ unsigned short orphan_blocks;
struct page *page = NULL;
struct ino_entry *orphan = NULL;
+ struct inode_management *im = &sbi->im[ORPHAN_INO];
+
+ orphan_blocks = GET_ORPHAN_BLOCKS(im->ino_num);
for (index = 0; index < orphan_blocks; index++)
grab_meta_page(sbi, start_blk + index);
index = 1;
- spin_lock(&sbi->ino_lock[ORPHAN_INO]);
- head = &sbi->ino_list[ORPHAN_INO];
+ spin_lock(&im->ino_lock);
+ head = &im->ino_list;
/* loop for each orphan inode entry and write them in Jornal block */
list_for_each_entry(orphan, head, list) {
@@ -510,7 +545,7 @@ static void write_orphan_inodes(struct f2fs_sb_info *sbi, block_t start_blk)
f2fs_put_page(page, 1);
}
- spin_unlock(&sbi->ino_lock[ORPHAN_INO]);
+ spin_unlock(&im->ino_lock);
}
static struct page *validate_checkpoint(struct f2fs_sb_info *sbi,
@@ -731,6 +766,9 @@ void sync_dirty_dir_inodes(struct f2fs_sb_info *sbi)
struct dir_inode_entry *entry;
struct inode *inode;
retry:
+ if (unlikely(f2fs_cp_error(sbi)))
+ return;
+
spin_lock(&sbi->dir_inode_lock);
head = &sbi->dir_inode_list;
@@ -830,6 +868,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
struct f2fs_checkpoint *ckpt = F2FS_CKPT(sbi);
struct curseg_info *curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
struct f2fs_nm_info *nm_i = NM_I(sbi);
+ unsigned long orphan_num = sbi->im[ORPHAN_INO].ino_num;
nid_t last_nid = nm_i->next_scan_nid;
block_t start_blk;
struct page *cp_page;
@@ -889,7 +928,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
else
clear_ckpt_flags(ckpt, CP_COMPACT_SUM_FLAG);
- orphan_blocks = GET_ORPHAN_BLOCKS(sbi->n_orphans);
+ orphan_blocks = GET_ORPHAN_BLOCKS(orphan_num);
ckpt->cp_pack_start_sum = cpu_to_le32(1 + cp_payload_blks +
orphan_blocks);
@@ -905,7 +944,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
orphan_blocks);
}
- if (sbi->n_orphans)
+ if (orphan_num)
set_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
else
clear_ckpt_flags(ckpt, CP_ORPHAN_PRESENT_FLAG);
@@ -940,7 +979,7 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
f2fs_put_page(cp_page, 1);
}
- if (sbi->n_orphans) {
+ if (orphan_num) {
write_orphan_inodes(sbi, start_blk);
start_blk += orphan_blocks;
}
@@ -975,6 +1014,9 @@ static void do_checkpoint(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* Here, we only have one bio having CP pack */
sync_meta_pages(sbi, META_FLUSH, LONG_MAX);
+ /* wait for previous submitted meta pages writeback */
+ wait_on_all_pages_writeback(sbi);
+
release_dirty_inode(sbi);
if (unlikely(f2fs_cp_error(sbi)))
@@ -1036,9 +1078,12 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
int i;
for (i = 0; i < MAX_INO_ENTRY; i++) {
- INIT_RADIX_TREE(&sbi->ino_root[i], GFP_ATOMIC);
- spin_lock_init(&sbi->ino_lock[i]);
- INIT_LIST_HEAD(&sbi->ino_list[i]);
+ struct inode_management *im = &sbi->im[i];
+
+ INIT_RADIX_TREE(&im->ino_root, GFP_ATOMIC);
+ spin_lock_init(&im->ino_lock);
+ INIT_LIST_HEAD(&im->ino_list);
+ im->ino_num = 0;
}
/*
@@ -1047,7 +1092,6 @@ void init_ino_entry_info(struct f2fs_sb_info *sbi)
* orphan entries with the limitation one reserved segment
* for cp pack we can have max 1020*504 orphan entries
*/
- sbi->n_orphans = 0;
sbi->max_orphans = (sbi->blocks_per_seg - F2FS_CP_PACKS -
NR_CURSEG_TYPE) * F2FS_ORPHANS_PER_BLOCK;
}
diff --git a/fs/f2fs/data.c b/fs/f2fs/data.c
index 8e58c4c..7ec697b 100644
--- a/fs/f2fs/data.c
+++ b/fs/f2fs/data.c
@@ -61,11 +61,6 @@ static void f2fs_write_end_io(struct bio *bio, int err)
dec_page_count(sbi, F2FS_WRITEBACK);
}
- if (sbi->wait_io) {
- complete(sbi->wait_io);
- sbi->wait_io = NULL;
- }
-
if (!get_pages(sbi, F2FS_WRITEBACK) &&
!list_empty(&sbi->cp_wait.task_list))
wake_up(&sbi->cp_wait);
@@ -95,34 +90,18 @@ static struct bio *__bio_alloc(struct f2fs_sb_info *sbi, block_t blk_addr,
static void __submit_merged_bio(struct f2fs_bio_info *io)
{
struct f2fs_io_info *fio = &io->fio;
- int rw;
if (!io->bio)
return;
- rw = fio->rw;
-
- if (is_read_io(rw)) {
- trace_f2fs_submit_read_bio(io->sbi->sb, rw,
- fio->type, io->bio);
- submit_bio(rw, io->bio);
- } else {
- trace_f2fs_submit_write_bio(io->sbi->sb, rw,
- fio->type, io->bio);
- /*
- * META_FLUSH is only from the checkpoint procedure, and we
- * should wait this metadata bio for FS consistency.
- */
- if (fio->type == META_FLUSH) {
- DECLARE_COMPLETION_ONSTACK(wait);
- io->sbi->wait_io = &wait;
- submit_bio(rw, io->bio);
- wait_for_completion(&wait);
- } else {
- submit_bio(rw, io->bio);
- }
- }
+ if (is_read_io(fio->rw))
+ trace_f2fs_submit_read_bio(io->sbi->sb, fio->rw,
+ fio->type, io->bio);
+ else
+ trace_f2fs_submit_write_bio(io->sbi->sb, fio->rw,
+ fio->type, io->bio);
+ submit_bio(fio->rw, io->bio);
io->bio = NULL;
}
@@ -257,9 +236,6 @@ int f2fs_reserve_block(struct dnode_of_data *dn, pgoff_t index)
bool need_put = dn->inode_page ? false : true;
int err;
- /* if inode_page exists, index should be zero */
- f2fs_bug_on(F2FS_I_SB(dn->inode), !need_put && index);
-
err = get_dnode_of_data(dn, index, ALLOC_NODE);
if (err)
return err;
@@ -740,14 +716,14 @@ int f2fs_fiemap(struct inode *inode, struct fiemap_extent_info *fieinfo,
static int f2fs_read_data_page(struct file *file, struct page *page)
{
struct inode *inode = page->mapping->host;
- int ret;
+ int ret = -EAGAIN;
trace_f2fs_readpage(page, DATA);
/* If the file has inline data, try to read it directly */
if (f2fs_has_inline_data(inode))
ret = f2fs_read_inline_data(inode, page);
- else
+ if (ret == -EAGAIN)
ret = mpage_readpage(page, get_data_block);
return ret;
@@ -859,10 +835,11 @@ write:
else if (has_not_enough_free_secs(sbi, 0))
goto redirty_out;
+ err = -EAGAIN;
f2fs_lock_op(sbi);
- if (f2fs_has_inline_data(inode) || f2fs_may_inline(inode))
- err = f2fs_write_inline_data(inode, page, offset);
- else
+ if (f2fs_has_inline_data(inode))
+ err = f2fs_write_inline_data(inode, page);
+ if (err == -EAGAIN)
err = do_write_data_page(page, &fio);
f2fs_unlock_op(sbi);
done:
@@ -951,7 +928,7 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
{
struct inode *inode = mapping->host;
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
- struct page *page;
+ struct page *page, *ipage;
pgoff_t index = ((unsigned long long) pos) >> PAGE_CACHE_SHIFT;
struct dnode_of_data dn;
int err = 0;
@@ -959,45 +936,60 @@ static int f2fs_write_begin(struct file *file, struct address_space *mapping,
trace_f2fs_write_begin(inode, pos, len, flags);
f2fs_balance_fs(sbi);
-repeat:
- err = f2fs_convert_inline_data(inode, pos + len, NULL);
- if (err)
- goto fail;
+ /*
+ * We should check this at this moment to avoid deadlock on inode page
+ * and #0 page. The locking rule for inline_data conversion should be:
+ * lock_page(page #0) -> lock_page(inode_page)
+ */
+ if (index != 0) {
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ goto fail;
+ }
+repeat:
page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) {
err = -ENOMEM;
goto fail;
}
- /* to avoid latency during memory pressure */
- unlock_page(page);
-
*pagep = page;
- if (f2fs_has_inline_data(inode) && (pos + len) <= MAX_INLINE_DATA)
- goto inline_data;
-
f2fs_lock_op(sbi);
- set_new_dnode(&dn, inode, NULL, NULL, 0);
- err = f2fs_reserve_block(&dn, index);
- f2fs_unlock_op(sbi);
- if (err) {
- f2fs_put_page(page, 0);
- goto fail;
- }
-inline_data:
- lock_page(page);
- if (unlikely(page->mapping != mapping)) {
- f2fs_put_page(page, 1);
- goto repeat;
+
+ /* check inline_data */
+ ipage = get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(ipage)) {
+ err = PTR_ERR(ipage);
+ goto unlock_fail;
}
- f2fs_wait_on_page_writeback(page, DATA);
+ set_new_dnode(&dn, inode, ipage, ipage, 0);
+
+ if (f2fs_has_inline_data(inode)) {
+ if (pos + len <= MAX_INLINE_DATA) {
+ read_inline_data(page, ipage);
+ set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
+ sync_inode_page(&dn);
+ goto put_next;
+ }
+ err = f2fs_convert_inline_page(&dn, page);
+ if (err)
+ goto put_fail;
+ }
+ err = f2fs_reserve_block(&dn, index);
+ if (err)
+ goto put_fail;
+put_next:
+ f2fs_put_dnode(&dn);
+ f2fs_unlock_op(sbi);
if ((len == PAGE_CACHE_SIZE) || PageUptodate(page))
return 0;
+ f2fs_wait_on_page_writeback(page, DATA);
+
if ((pos & PAGE_CACHE_MASK) >= i_size_read(inode)) {
unsigned start = pos & (PAGE_CACHE_SIZE - 1);
unsigned end = start + len;
@@ -1010,18 +1002,10 @@ inline_data:
if (dn.data_blkaddr == NEW_ADDR) {
zero_user_segment(page, 0, PAGE_CACHE_SIZE);
} else {
- if (f2fs_has_inline_data(inode)) {
- err = f2fs_read_inline_data(inode, page);
- if (err) {
- page_cache_release(page);
- goto fail;
- }
- } else {
- err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
- READ_SYNC);
- if (err)
- goto fail;
- }
+ err = f2fs_submit_page_bio(sbi, page, dn.data_blkaddr,
+ READ_SYNC);
+ if (err)
+ goto fail;
lock_page(page);
if (unlikely(!PageUptodate(page))) {
@@ -1038,6 +1022,12 @@ out:
SetPageUptodate(page);
clear_cold_data(page);
return 0;
+
+put_fail:
+ f2fs_put_dnode(&dn);
+unlock_fail:
+ f2fs_unlock_op(sbi);
+ f2fs_put_page(page, 1);
fail:
f2fs_write_failed(mapping, pos + len);
return err;
@@ -1052,10 +1042,7 @@ static int f2fs_write_end(struct file *file,
trace_f2fs_write_end(inode, pos, len, copied);
- if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
- register_inmem_page(inode, page);
- else
- set_page_dirty(page);
+ set_page_dirty(page);
if (pos + copied > i_size_read(inode)) {
i_size_write(inode, pos + copied);
@@ -1093,9 +1080,12 @@ static ssize_t f2fs_direct_IO(int rw, struct kiocb *iocb,
size_t count = iov_iter_count(iter);
int err;
- /* Let buffer I/O handle the inline data case. */
- if (f2fs_has_inline_data(inode))
- return 0;
+ /* we don't need to use inline_data strictly */
+ if (f2fs_has_inline_data(inode)) {
+ err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
+ }
if (check_direct_IO(inode, rw, iter, offset))
return 0;
@@ -1119,6 +1109,9 @@ static void f2fs_invalidate_data_page(struct page *page, unsigned int offset,
if (offset % PAGE_CACHE_SIZE || length != PAGE_CACHE_SIZE)
return;
+ if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
+ invalidate_inmem_page(inode, page);
+
if (PageDirty(page))
inode_dec_dirty_pages(inode);
ClearPagePrivate(page);
@@ -1138,6 +1131,12 @@ static int f2fs_set_data_page_dirty(struct page *page)
trace_f2fs_set_page_dirty(page, DATA);
SetPageUptodate(page);
+
+ if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode)) {
+ register_inmem_page(inode, page);
+ return 1;
+ }
+
mark_inode_dirty(inode);
if (!PageDirty(page)) {
@@ -1152,9 +1151,12 @@ static sector_t f2fs_bmap(struct address_space *mapping, sector_t block)
{
struct inode *inode = mapping->host;
- if (f2fs_has_inline_data(inode))
- return 0;
-
+ /* we don't need to use inline_data strictly */
+ if (f2fs_has_inline_data(inode)) {
+ int err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
+ }
return generic_block_bmap(mapping, block, get_data_block);
}
diff --git a/fs/f2fs/debug.c b/fs/f2fs/debug.c
index 0a91ab8..91e8f69 100644
--- a/fs/f2fs/debug.c
+++ b/fs/f2fs/debug.c
@@ -39,13 +39,15 @@ static void update_general_status(struct f2fs_sb_info *sbi)
si->ndirty_dent = get_pages(sbi, F2FS_DIRTY_DENTS);
si->ndirty_dirs = sbi->n_dirty_dirs;
si->ndirty_meta = get_pages(sbi, F2FS_DIRTY_META);
+ si->inmem_pages = get_pages(sbi, F2FS_INMEM_PAGES);
si->total_count = (int)sbi->user_block_count / sbi->blocks_per_seg;
si->rsvd_segs = reserved_segments(sbi);
si->overp_segs = overprovision_segments(sbi);
si->valid_count = valid_user_blocks(sbi);
si->valid_node_count = valid_node_count(sbi);
si->valid_inode_count = valid_inode_count(sbi);
- si->inline_inode = sbi->inline_inode;
+ si->inline_inode = atomic_read(&sbi->inline_inode);
+ si->inline_dir = atomic_read(&sbi->inline_dir);
si->utilization = utilization(sbi);
si->free_segs = free_segments(sbi);
@@ -118,6 +120,7 @@ static void update_mem_info(struct f2fs_sb_info *sbi)
{
struct f2fs_stat_info *si = F2FS_STAT(sbi);
unsigned npages;
+ int i;
if (si->base_mem)
goto get_cache;
@@ -167,8 +170,9 @@ get_cache:
si->cache_mem += npages << PAGE_CACHE_SHIFT;
npages = META_MAPPING(sbi)->nrpages;
si->cache_mem += npages << PAGE_CACHE_SHIFT;
- si->cache_mem += sbi->n_orphans * sizeof(struct ino_entry);
si->cache_mem += sbi->n_dirty_dirs * sizeof(struct dir_inode_entry);
+ for (i = 0; i <= UPDATE_INO; i++)
+ si->cache_mem += sbi->im[i].ino_num * sizeof(struct ino_entry);
}
static int stat_show(struct seq_file *s, void *v)
@@ -200,6 +204,8 @@ static int stat_show(struct seq_file *s, void *v)
si->valid_count - si->valid_node_count);
seq_printf(s, " - Inline_data Inode: %u\n",
si->inline_inode);
+ seq_printf(s, " - Inline_dentry Inode: %u\n",
+ si->inline_dir);
seq_printf(s, "\nMain area: %d segs, %d secs %d zones\n",
si->main_area_segs, si->main_area_sections,
si->main_area_zones);
@@ -244,6 +250,8 @@ static int stat_show(struct seq_file *s, void *v)
seq_printf(s, "\nExtent Hit Ratio: %d / %d\n",
si->hit_ext, si->total_ext);
seq_puts(s, "\nBalancing F2FS Async:\n");
+ seq_printf(s, " - inmem: %4d\n",
+ si->inmem_pages);
seq_printf(s, " - nodes: %4d in %4d\n",
si->ndirty_node, si->node_pages);
seq_printf(s, " - dents: %4d in dirs:%4d\n",
@@ -321,6 +329,9 @@ int f2fs_build_stats(struct f2fs_sb_info *sbi)
si->sbi = sbi;
sbi->stat_info = si;
+ atomic_set(&sbi->inline_inode, 0);
+ atomic_set(&sbi->inline_dir, 0);
+
mutex_lock(&f2fs_stat_mutex);
list_add_tail(&si->stat_list, &f2fs_stat_list);
mutex_unlock(&f2fs_stat_mutex);
diff --git a/fs/f2fs/dir.c b/fs/f2fs/dir.c
index b54f871..b1a7d57 100644
--- a/fs/f2fs/dir.c
+++ b/fs/f2fs/dir.c
@@ -37,7 +37,7 @@ static unsigned int bucket_blocks(unsigned int level)
return 4;
}
-static unsigned char f2fs_filetype_table[F2FS_FT_MAX] = {
+unsigned char f2fs_filetype_table[F2FS_FT_MAX] = {
[F2FS_FT_UNKNOWN] = DT_UNKNOWN,
[F2FS_FT_REG_FILE] = DT_REG,
[F2FS_FT_DIR] = DT_DIR,
@@ -59,7 +59,7 @@ static unsigned char f2fs_type_by_mode[S_IFMT >> S_SHIFT] = {
[S_IFLNK >> S_SHIFT] = F2FS_FT_SYMLINK,
};
-static void set_de_type(struct f2fs_dir_entry *de, struct inode *inode)
+void set_de_type(struct f2fs_dir_entry *de, struct inode *inode)
{
umode_t mode = inode->i_mode;
de->file_type = f2fs_type_by_mode[(mode & S_IFMT) >> S_SHIFT];
@@ -90,51 +90,70 @@ static bool early_match_name(size_t namelen, f2fs_hash_t namehash,
}
static struct f2fs_dir_entry *find_in_block(struct page *dentry_page,
- struct qstr *name, int *max_slots,
- f2fs_hash_t namehash, struct page **res_page)
+ struct qstr *name, int *max_slots,
+ struct page **res_page)
+{
+ struct f2fs_dentry_block *dentry_blk;
+ struct f2fs_dir_entry *de;
+ struct f2fs_dentry_ptr d;
+
+ dentry_blk = (struct f2fs_dentry_block *)kmap(dentry_page);
+
+ make_dentry_ptr(&d, (void *)dentry_blk, 1);
+ de = find_target_dentry(name, max_slots, &d);
+
+ if (de)
+ *res_page = dentry_page;
+ else
+ kunmap(dentry_page);
+
+ /*
+ * For the most part, it should be a bug when name_len is zero.
+ * We stop here for figuring out where the bugs has occurred.
+ */
+ f2fs_bug_on(F2FS_P_SB(dentry_page), d.max < 0);
+ return de;
+}
+
+struct f2fs_dir_entry *find_target_dentry(struct qstr *name, int *max_slots,
+ struct f2fs_dentry_ptr *d)
{
struct f2fs_dir_entry *de;
unsigned long bit_pos = 0;
- struct f2fs_dentry_block *dentry_blk = kmap(dentry_page);
- const void *dentry_bits = &dentry_blk->dentry_bitmap;
+ f2fs_hash_t namehash = f2fs_dentry_hash(name);
int max_len = 0;
- while (bit_pos < NR_DENTRY_IN_BLOCK) {
- if (!test_bit_le(bit_pos, dentry_bits)) {
+ if (max_slots)
+ *max_slots = 0;
+ while (bit_pos < d->max) {
+ if (!test_bit_le(bit_pos, d->bitmap)) {
if (bit_pos == 0)
max_len = 1;
- else if (!test_bit_le(bit_pos - 1, dentry_bits))
+ else if (!test_bit_le(bit_pos - 1, d->bitmap))
max_len++;
bit_pos++;
continue;
}
- de = &dentry_blk->dentry[bit_pos];
- if (early_match_name(name->len, namehash, de)) {
- if (!memcmp(dentry_blk->filename[bit_pos],
- name->name,
- name->len)) {
- *res_page = dentry_page;
- goto found;
- }
- }
- if (max_len > *max_slots) {
+ de = &d->dentry[bit_pos];
+ if (early_match_name(name->len, namehash, de) &&
+ !memcmp(d->filename[bit_pos], name->name, name->len))
+ goto found;
+
+ if (max_slots && *max_slots >= 0 && max_len > *max_slots) {
*max_slots = max_len;
max_len = 0;
}
- /*
- * For the most part, it should be a bug when name_len is zero.
- * We stop here for figuring out where the bugs has occurred.
- */
- f2fs_bug_on(F2FS_P_SB(dentry_page), !de->name_len);
+ /* remain bug on condition */
+ if (unlikely(!de->name_len))
+ d->max = -1;
bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
}
de = NULL;
- kunmap(dentry_page);
found:
- if (max_len > *max_slots)
+ if (max_slots && max_len > *max_slots)
*max_slots = max_len;
return de;
}
@@ -149,7 +168,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
struct page *dentry_page;
struct f2fs_dir_entry *de = NULL;
bool room = false;
- int max_slots = 0;
+ int max_slots;
f2fs_bug_on(F2FS_I_SB(dir), level > MAX_DIR_HASH_DEPTH);
@@ -168,8 +187,7 @@ static struct f2fs_dir_entry *find_in_level(struct inode *dir,
continue;
}
- de = find_in_block(dentry_page, name, &max_slots,
- namehash, res_page);
+ de = find_in_block(dentry_page, name, &max_slots, res_page);
if (de)
break;
@@ -201,6 +219,9 @@ struct f2fs_dir_entry *f2fs_find_entry(struct inode *dir,
unsigned int max_depth;
unsigned int level;
+ if (f2fs_has_inline_dentry(dir))
+ return find_in_inline_dir(dir, child, res_page);
+
if (npages == 0)
return NULL;
@@ -227,6 +248,9 @@ struct f2fs_dir_entry *f2fs_parent_dir(struct inode *dir, struct page **p)
struct f2fs_dir_entry *de;
struct f2fs_dentry_block *dentry_blk;
+ if (f2fs_has_inline_dentry(dir))
+ return f2fs_parent_inline_dir(dir, p);
+
page = get_lock_data_page(dir, 0);
if (IS_ERR(page))
return NULL;
@@ -247,7 +271,7 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
de = f2fs_find_entry(dir, qstr, &page);
if (de) {
res = le32_to_cpu(de->ino);
- kunmap(page);
+ f2fs_dentry_kunmap(dir, page);
f2fs_put_page(page, 0);
}
@@ -257,11 +281,13 @@ ino_t f2fs_inode_by_name(struct inode *dir, struct qstr *qstr)
void f2fs_set_link(struct inode *dir, struct f2fs_dir_entry *de,
struct page *page, struct inode *inode)
{
+ enum page_type type = f2fs_has_inline_dentry(dir) ? NODE : DATA;
lock_page(page);
- f2fs_wait_on_page_writeback(page, DATA);
+ f2fs_wait_on_page_writeback(page, type);
de->ino = cpu_to_le32(inode->i_ino);
set_de_type(de, inode);
- kunmap(page);
+ if (!f2fs_has_inline_dentry(dir))
+ kunmap(page);
set_page_dirty(page);
dir->i_mtime = dir->i_ctime = CURRENT_TIME;
mark_inode_dirty(dir);
@@ -296,36 +322,48 @@ int update_dent_inode(struct inode *inode, const struct qstr *name)
return 0;
}
-static int make_empty_dir(struct inode *inode,
- struct inode *parent, struct page *page)
+void do_make_empty_dir(struct inode *inode, struct inode *parent,
+ struct f2fs_dentry_ptr *d)
{
- struct page *dentry_page;
- struct f2fs_dentry_block *dentry_blk;
struct f2fs_dir_entry *de;
- dentry_page = get_new_data_page(inode, page, 0, true);
- if (IS_ERR(dentry_page))
- return PTR_ERR(dentry_page);
-
-
- dentry_blk = kmap_atomic(dentry_page);
-
- de = &dentry_blk->dentry[0];
+ de = &d->dentry[0];
de->name_len = cpu_to_le16(1);
de->hash_code = 0;
de->ino = cpu_to_le32(inode->i_ino);
- memcpy(dentry_blk->filename[0], ".", 1);
+ memcpy(d->filename[0], ".", 1);
set_de_type(de, inode);
- de = &dentry_blk->dentry[1];
+ de = &d->dentry[1];
de->hash_code = 0;
de->name_len = cpu_to_le16(2);
de->ino = cpu_to_le32(parent->i_ino);
- memcpy(dentry_blk->filename[1], "..", 2);
+ memcpy(d->filename[1], "..", 2);
set_de_type(de, inode);
- test_and_set_bit_le(0, &dentry_blk->dentry_bitmap);
- test_and_set_bit_le(1, &dentry_blk->dentry_bitmap);
+ test_and_set_bit_le(0, (void *)d->bitmap);
+ test_and_set_bit_le(1, (void *)d->bitmap);
+}
+
+static int make_empty_dir(struct inode *inode,
+ struct inode *parent, struct page *page)
+{
+ struct page *dentry_page;
+ struct f2fs_dentry_block *dentry_blk;
+ struct f2fs_dentry_ptr d;
+
+ if (f2fs_has_inline_dentry(inode))
+ return make_empty_inline_dir(inode, parent, page);
+
+ dentry_page = get_new_data_page(inode, page, 0, true);
+ if (IS_ERR(dentry_page))
+ return PTR_ERR(dentry_page);
+
+ dentry_blk = kmap_atomic(dentry_page);
+
+ make_dentry_ptr(&d, (void *)dentry_blk, 1);
+ do_make_empty_dir(inode, parent, &d);
+
kunmap_atomic(dentry_blk);
set_page_dirty(dentry_page);
@@ -333,8 +371,8 @@ static int make_empty_dir(struct inode *inode,
return 0;
}
-static struct page *init_inode_metadata(struct inode *inode,
- struct inode *dir, const struct qstr *name)
+struct page *init_inode_metadata(struct inode *inode, struct inode *dir,
+ const struct qstr *name, struct page *dpage)
{
struct page *page;
int err;
@@ -350,7 +388,7 @@ static struct page *init_inode_metadata(struct inode *inode,
goto error;
}
- err = f2fs_init_acl(inode, dir, page);
+ err = f2fs_init_acl(inode, dir, page, dpage);
if (err)
goto put_error;
@@ -395,7 +433,7 @@ error:
return ERR_PTR(err);
}
-static void update_parent_metadata(struct inode *dir, struct inode *inode,
+void update_parent_metadata(struct inode *dir, struct inode *inode,
unsigned int current_depth)
{
if (is_inode_flag_set(F2FS_I(inode), FI_NEW_INODE)) {
@@ -417,27 +455,23 @@ static void update_parent_metadata(struct inode *dir, struct inode *inode,
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
}
-static int room_for_filename(struct f2fs_dentry_block *dentry_blk, int slots)
+int room_for_filename(const void *bitmap, int slots, int max_slots)
{
int bit_start = 0;
int zero_start, zero_end;
next:
- zero_start = find_next_zero_bit_le(&dentry_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK,
- bit_start);
- if (zero_start >= NR_DENTRY_IN_BLOCK)
- return NR_DENTRY_IN_BLOCK;
+ zero_start = find_next_zero_bit_le(bitmap, max_slots, bit_start);
+ if (zero_start >= max_slots)
+ return max_slots;
- zero_end = find_next_bit_le(&dentry_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK,
- zero_start);
+ zero_end = find_next_bit_le(bitmap, max_slots, zero_start);
if (zero_end - zero_start >= slots)
return zero_start;
bit_start = zero_end + 1;
- if (zero_end + 1 >= NR_DENTRY_IN_BLOCK)
- return NR_DENTRY_IN_BLOCK;
+ if (zero_end + 1 >= max_slots)
+ return max_slots;
goto next;
}
@@ -463,6 +497,14 @@ int __f2fs_add_link(struct inode *dir, const struct qstr *name,
int err = 0;
int i;
+ if (f2fs_has_inline_dentry(dir)) {
+ err = f2fs_add_inline_entry(dir, name, inode);
+ if (!err || err != -EAGAIN)
+ return err;
+ else
+ err = 0;
+ }
+
dentry_hash = f2fs_dentry_hash(name);
level = 0;
current_depth = F2FS_I(dir)->i_current_depth;
@@ -491,7 +533,8 @@ start:
return PTR_ERR(dentry_page);
dentry_blk = kmap(dentry_page);
- bit_pos = room_for_filename(dentry_blk, slots);
+ bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
+ slots, NR_DENTRY_IN_BLOCK);
if (bit_pos < NR_DENTRY_IN_BLOCK)
goto add_dentry;
@@ -506,7 +549,7 @@ add_dentry:
f2fs_wait_on_page_writeback(dentry_page, DATA);
down_write(&F2FS_I(inode)->i_sem);
- page = init_inode_metadata(inode, dir, name);
+ page = init_inode_metadata(inode, dir, name, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
@@ -545,7 +588,7 @@ int f2fs_do_tmpfile(struct inode *inode, struct inode *dir)
int err = 0;
down_write(&F2FS_I(inode)->i_sem);
- page = init_inode_metadata(inode, dir, NULL);
+ page = init_inode_metadata(inode, dir, NULL, NULL);
if (IS_ERR(page)) {
err = PTR_ERR(page);
goto fail;
@@ -560,26 +603,57 @@ fail:
return err;
}
+void f2fs_drop_nlink(struct inode *dir, struct inode *inode, struct page *page)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+
+ down_write(&F2FS_I(inode)->i_sem);
+
+ if (S_ISDIR(inode->i_mode)) {
+ drop_nlink(dir);
+ if (page)
+ update_inode(dir, page);
+ else
+ update_inode_page(dir);
+ }
+ inode->i_ctime = CURRENT_TIME;
+
+ drop_nlink(inode);
+ if (S_ISDIR(inode->i_mode)) {
+ drop_nlink(inode);
+ i_size_write(inode, 0);
+ }
+ up_write(&F2FS_I(inode)->i_sem);
+ update_inode_page(inode);
+
+ if (inode->i_nlink == 0)
+ add_orphan_inode(sbi, inode->i_ino);
+ else
+ release_orphan_inode(sbi);
+}
+
/*
* It only removes the dentry from the dentry page, corresponding name
* entry in name page does not need to be touched during deletion.
*/
void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
- struct inode *inode)
+ struct inode *dir, struct inode *inode)
{
struct f2fs_dentry_block *dentry_blk;
unsigned int bit_pos;
- struct inode *dir = page->mapping->host;
int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
int i;
+ if (f2fs_has_inline_dentry(dir))
+ return f2fs_delete_inline_entry(dentry, page, dir, inode);
+
lock_page(page);
f2fs_wait_on_page_writeback(page, DATA);
dentry_blk = page_address(page);
bit_pos = dentry - dentry_blk->dentry;
for (i = 0; i < slots; i++)
- test_and_clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
+ clear_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
/* Let's check and deallocate this dentry page */
bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
@@ -590,29 +664,8 @@ void f2fs_delete_entry(struct f2fs_dir_entry *dentry, struct page *page,
dir->i_ctime = dir->i_mtime = CURRENT_TIME;
- if (inode) {
- struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
-
- down_write(&F2FS_I(inode)->i_sem);
-
- if (S_ISDIR(inode->i_mode)) {
- drop_nlink(dir);
- update_inode_page(dir);
- }
- inode->i_ctime = CURRENT_TIME;
- drop_nlink(inode);
- if (S_ISDIR(inode->i_mode)) {
- drop_nlink(inode);
- i_size_write(inode, 0);
- }
- up_write(&F2FS_I(inode)->i_sem);
- update_inode_page(inode);
-
- if (inode->i_nlink == 0)
- add_orphan_inode(sbi, inode->i_ino);
- else
- release_orphan_inode(sbi);
- }
+ if (inode)
+ f2fs_drop_nlink(dir, inode, NULL);
if (bit_pos == NR_DENTRY_IN_BLOCK) {
truncate_hole(dir, page->index, page->index + 1);
@@ -628,9 +681,12 @@ bool f2fs_empty_dir(struct inode *dir)
unsigned long bidx;
struct page *dentry_page;
unsigned int bit_pos;
- struct f2fs_dentry_block *dentry_blk;
+ struct f2fs_dentry_block *dentry_blk;
unsigned long nblock = dir_blocks(dir);
+ if (f2fs_has_inline_dentry(dir))
+ return f2fs_empty_inline_dir(dir);
+
for (bidx = 0; bidx < nblock; bidx++) {
dentry_page = get_lock_data_page(dir, bidx);
if (IS_ERR(dentry_page)) {
@@ -640,7 +696,6 @@ bool f2fs_empty_dir(struct inode *dir)
return false;
}
-
dentry_blk = kmap_atomic(dentry_page);
if (bidx == 0)
bit_pos = 2;
@@ -659,19 +714,48 @@ bool f2fs_empty_dir(struct inode *dir)
return true;
}
+bool f2fs_fill_dentries(struct dir_context *ctx, struct f2fs_dentry_ptr *d,
+ unsigned int start_pos)
+{
+ unsigned char d_type = DT_UNKNOWN;
+ unsigned int bit_pos;
+ struct f2fs_dir_entry *de = NULL;
+
+ bit_pos = ((unsigned long)ctx->pos % d->max);
+
+ while (bit_pos < d->max) {
+ bit_pos = find_next_bit_le(d->bitmap, d->max, bit_pos);
+ if (bit_pos >= d->max)
+ break;
+
+ de = &d->dentry[bit_pos];
+ if (de->file_type < F2FS_FT_MAX)
+ d_type = f2fs_filetype_table[de->file_type];
+ else
+ d_type = DT_UNKNOWN;
+ if (!dir_emit(ctx, d->filename[bit_pos],
+ le16_to_cpu(de->name_len),
+ le32_to_cpu(de->ino), d_type))
+ return true;
+
+ bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
+ ctx->pos = start_pos + bit_pos;
+ }
+ return false;
+}
+
static int f2fs_readdir(struct file *file, struct dir_context *ctx)
{
struct inode *inode = file_inode(file);
unsigned long npages = dir_blocks(inode);
- unsigned int bit_pos = 0;
struct f2fs_dentry_block *dentry_blk = NULL;
- struct f2fs_dir_entry *de = NULL;
struct page *dentry_page = NULL;
struct file_ra_state *ra = &file->f_ra;
unsigned int n = ((unsigned long)ctx->pos / NR_DENTRY_IN_BLOCK);
- unsigned char d_type = DT_UNKNOWN;
+ struct f2fs_dentry_ptr d;
- bit_pos = ((unsigned long)ctx->pos % NR_DENTRY_IN_BLOCK);
+ if (f2fs_has_inline_dentry(inode))
+ return f2fs_read_inline_dir(file, ctx);
/* readahead for multi pages of dir */
if (npages - n > 1 && !ra_has_index(ra, n))
@@ -684,28 +768,12 @@ static int f2fs_readdir(struct file *file, struct dir_context *ctx)
continue;
dentry_blk = kmap(dentry_page);
- while (bit_pos < NR_DENTRY_IN_BLOCK) {
- bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
- NR_DENTRY_IN_BLOCK,
- bit_pos);
- if (bit_pos >= NR_DENTRY_IN_BLOCK)
- break;
-
- de = &dentry_blk->dentry[bit_pos];
- if (de->file_type < F2FS_FT_MAX)
- d_type = f2fs_filetype_table[de->file_type];
- else
- d_type = DT_UNKNOWN;
- if (!dir_emit(ctx,
- dentry_blk->filename[bit_pos],
- le16_to_cpu(de->name_len),
- le32_to_cpu(de->ino), d_type))
- goto stop;
- bit_pos += GET_DENTRY_SLOTS(le16_to_cpu(de->name_len));
- ctx->pos = n * NR_DENTRY_IN_BLOCK + bit_pos;
- }
- bit_pos = 0;
+ make_dentry_ptr(&d, (void *)dentry_blk, 1);
+
+ if (f2fs_fill_dentries(ctx, &d, n * NR_DENTRY_IN_BLOCK))
+ goto stop;
+
ctx->pos = (n + 1) * NR_DENTRY_IN_BLOCK;
kunmap(dentry_page);
f2fs_put_page(dentry_page, 1);
diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h
index 8171e80..ec58bb2 100644
--- a/fs/f2fs/f2fs.h
+++ b/fs/f2fs/f2fs.h
@@ -46,8 +46,10 @@
#define F2FS_MOUNT_DISABLE_EXT_IDENTIFY 0x00000040
#define F2FS_MOUNT_INLINE_XATTR 0x00000080
#define F2FS_MOUNT_INLINE_DATA 0x00000100
-#define F2FS_MOUNT_FLUSH_MERGE 0x00000200
-#define F2FS_MOUNT_NOBARRIER 0x00000400
+#define F2FS_MOUNT_INLINE_DENTRY 0x00000200
+#define F2FS_MOUNT_FLUSH_MERGE 0x00000400
+#define F2FS_MOUNT_NOBARRIER 0x00000800
+#define F2FS_MOUNT_FASTBOOT 0x00001000
#define clear_opt(sbi, option) (sbi->mount_opt.opt &= ~F2FS_MOUNT_##option)
#define set_opt(sbi, option) (sbi->mount_opt.opt |= F2FS_MOUNT_##option)
@@ -211,6 +213,32 @@ static inline bool __has_cursum_space(struct f2fs_summary_block *sum, int size,
/*
* For INODE and NODE manager
*/
+/* for directory operations */
+struct f2fs_dentry_ptr {
+ const void *bitmap;
+ struct f2fs_dir_entry *dentry;
+ __u8 (*filename)[F2FS_SLOT_LEN];
+ int max;
+};
+
+static inline void make_dentry_ptr(struct f2fs_dentry_ptr *d,
+ void *src, int type)
+{
+ if (type == 1) {
+ struct f2fs_dentry_block *t = (struct f2fs_dentry_block *)src;
+ d->max = NR_DENTRY_IN_BLOCK;
+ d->bitmap = &t->dentry_bitmap;
+ d->dentry = t->dentry;
+ d->filename = t->filename;
+ } else {
+ struct f2fs_inline_dentry *t = (struct f2fs_inline_dentry *)src;
+ d->max = NR_INLINE_DENTRY;
+ d->bitmap = &t->dentry_bitmap;
+ d->dentry = t->dentry;
+ d->filename = t->filename;
+ }
+}
+
/*
* XATTR_NODE_OFFSET stores xattrs to one node block per file keeping -1
* as its node offset to distinguish from index node blocks.
@@ -269,6 +297,7 @@ struct f2fs_inode_info {
struct extent_info ext; /* in-memory extent cache entry */
struct dir_inode_entry *dirty_dir; /* the pointer of dirty dir */
+ struct radix_tree_root inmem_root; /* radix tree for inmem pages */
struct list_head inmem_pages; /* inmemory pages managed by f2fs */
struct mutex inmem_lock; /* lock for inmemory pages */
};
@@ -303,7 +332,7 @@ struct f2fs_nm_info {
/* NAT cache management */
struct radix_tree_root nat_root;/* root of the nat entry cache */
struct radix_tree_root nat_set_root;/* root of the nat set cache */
- rwlock_t nat_tree_lock; /* protect nat_tree_lock */
+ struct rw_semaphore nat_tree_lock; /* protect nat_tree_lock */
struct list_head nat_entries; /* cached nat entry list (clean) */
unsigned int nat_cnt; /* the # of cached nat entries */
unsigned int dirty_nat_cnt; /* total num of nat entries in set */
@@ -433,6 +462,7 @@ enum count_type {
F2FS_DIRTY_DENTS,
F2FS_DIRTY_NODES,
F2FS_DIRTY_META,
+ F2FS_INMEM_PAGES,
NR_COUNT_TYPE,
};
@@ -470,6 +500,14 @@ struct f2fs_bio_info {
struct rw_semaphore io_rwsem; /* blocking op for bio */
};
+/* for inner inode cache management */
+struct inode_management {
+ struct radix_tree_root ino_root; /* ino entry array */
+ spinlock_t ino_lock; /* for ino entry lock */
+ struct list_head ino_list; /* inode list head */
+ unsigned long ino_num; /* number of entries */
+};
+
struct f2fs_sb_info {
struct super_block *sb; /* pointer to VFS super block */
struct proc_dir_entry *s_proc; /* proc entry */
@@ -488,7 +526,6 @@ struct f2fs_sb_info {
/* for bio operations */
struct f2fs_bio_info read_io; /* for read bios */
struct f2fs_bio_info write_io[NR_PAGE_TYPE]; /* for write bios */
- struct completion *wait_io; /* for completion bios */
/* for checkpoint */
struct f2fs_checkpoint *ckpt; /* raw checkpoint pointer */
@@ -500,13 +537,9 @@ struct f2fs_sb_info {
bool por_doing; /* recovery is doing or not */
wait_queue_head_t cp_wait;
- /* for inode management */
- struct radix_tree_root ino_root[MAX_INO_ENTRY]; /* ino entry array */
- spinlock_t ino_lock[MAX_INO_ENTRY]; /* for ino entry lock */
- struct list_head ino_list[MAX_INO_ENTRY]; /* inode list head */
+ struct inode_management im[MAX_INO_ENTRY]; /* manage inode cache */
/* for orphan inode, use 0'th array */
- unsigned int n_orphans; /* # of orphan inodes */
unsigned int max_orphans; /* max orphan inodes */
/* for directory inode management */
@@ -557,7 +590,8 @@ struct f2fs_sb_info {
unsigned int segment_count[2]; /* # of allocated segments */
unsigned int block_count[2]; /* # of allocated blocks */
int total_hit_ext, read_hit_ext; /* extent cache hit ratio */
- int inline_inode; /* # of inline_data inodes */
+ atomic_t inline_inode; /* # of inline_data inodes */
+ atomic_t inline_dir; /* # of inline_dentry inodes */
int bg_gc; /* background gc calls */
unsigned int n_dirty_dirs; /* # of dir inodes */
#endif
@@ -988,6 +1022,13 @@ retry:
return entry;
}
+static inline void f2fs_radix_tree_insert(struct radix_tree_root *root,
+ unsigned long index, void *item)
+{
+ while (radix_tree_insert(root, index, item))
+ cond_resched();
+}
+
#define RAW_IS_INODE(p) ((p)->footer.nid == (p)->footer.ino)
static inline bool IS_INODE(struct page *page)
@@ -1020,7 +1061,7 @@ static inline int f2fs_test_bit(unsigned int nr, char *addr)
return mask & *addr;
}
-static inline int f2fs_set_bit(unsigned int nr, char *addr)
+static inline int f2fs_test_and_set_bit(unsigned int nr, char *addr)
{
int mask;
int ret;
@@ -1032,7 +1073,7 @@ static inline int f2fs_set_bit(unsigned int nr, char *addr)
return ret;
}
-static inline int f2fs_clear_bit(unsigned int nr, char *addr)
+static inline int f2fs_test_and_clear_bit(unsigned int nr, char *addr)
{
int mask;
int ret;
@@ -1044,6 +1085,15 @@ static inline int f2fs_clear_bit(unsigned int nr, char *addr)
return ret;
}
+static inline void f2fs_change_bit(unsigned int nr, char *addr)
+{
+ int mask;
+
+ addr += (nr >> 3);
+ mask = 1 << (7 - (nr & 0x07));
+ *addr ^= mask;
+}
+
/* used for f2fs_inode_info->flags */
enum {
FI_NEW_INODE, /* indicate newly allocated inode */
@@ -1057,11 +1107,13 @@ enum {
FI_NO_EXTENT, /* not to use the extent cache */
FI_INLINE_XATTR, /* used for inline xattr */
FI_INLINE_DATA, /* used for inline data*/
+ FI_INLINE_DENTRY, /* used for inline dentry */
FI_APPEND_WRITE, /* inode has appended data */
FI_UPDATE_WRITE, /* inode has in-place-update data */
FI_NEED_IPU, /* used for ipu per file */
FI_ATOMIC_FILE, /* indicate atomic file */
FI_VOLATILE_FILE, /* indicate volatile file */
+ FI_DATA_EXIST, /* indicate data exists */
};
static inline void set_inode_flag(struct f2fs_inode_info *fi, int flag)
@@ -1087,15 +1139,6 @@ static inline void set_acl_inode(struct f2fs_inode_info *fi, umode_t mode)
set_inode_flag(fi, FI_ACL_MODE);
}
-static inline int cond_clear_inode_flag(struct f2fs_inode_info *fi, int flag)
-{
- if (is_inode_flag_set(fi, FI_ACL_MODE)) {
- clear_inode_flag(fi, FI_ACL_MODE);
- return 1;
- }
- return 0;
-}
-
static inline void get_inline_info(struct f2fs_inode_info *fi,
struct f2fs_inode *ri)
{
@@ -1103,6 +1146,10 @@ static inline void get_inline_info(struct f2fs_inode_info *fi,
set_inode_flag(fi, FI_INLINE_XATTR);
if (ri->i_inline & F2FS_INLINE_DATA)
set_inode_flag(fi, FI_INLINE_DATA);
+ if (ri->i_inline & F2FS_INLINE_DENTRY)
+ set_inode_flag(fi, FI_INLINE_DENTRY);
+ if (ri->i_inline & F2FS_DATA_EXIST)
+ set_inode_flag(fi, FI_DATA_EXIST);
}
static inline void set_raw_inline(struct f2fs_inode_info *fi,
@@ -1114,6 +1161,10 @@ static inline void set_raw_inline(struct f2fs_inode_info *fi,
ri->i_inline |= F2FS_INLINE_XATTR;
if (is_inode_flag_set(fi, FI_INLINE_DATA))
ri->i_inline |= F2FS_INLINE_DATA;
+ if (is_inode_flag_set(fi, FI_INLINE_DENTRY))
+ ri->i_inline |= F2FS_INLINE_DENTRY;
+ if (is_inode_flag_set(fi, FI_DATA_EXIST))
+ ri->i_inline |= F2FS_DATA_EXIST;
}
static inline int f2fs_has_inline_xattr(struct inode *inode)
@@ -1148,6 +1199,17 @@ static inline int f2fs_has_inline_data(struct inode *inode)
return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DATA);
}
+static inline void f2fs_clear_inline_inode(struct inode *inode)
+{
+ clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
+ clear_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
+}
+
+static inline int f2fs_exist_data(struct inode *inode)
+{
+ return is_inode_flag_set(F2FS_I(inode), FI_DATA_EXIST);
+}
+
static inline bool f2fs_is_atomic_file(struct inode *inode)
{
return is_inode_flag_set(F2FS_I(inode), FI_ATOMIC_FILE);
@@ -1164,6 +1226,23 @@ static inline void *inline_data_addr(struct page *page)
return (void *)&(ri->i_addr[1]);
}
+static inline int f2fs_has_inline_dentry(struct inode *inode)
+{
+ return is_inode_flag_set(F2FS_I(inode), FI_INLINE_DENTRY);
+}
+
+static inline void *inline_dentry_addr(struct page *page)
+{
+ struct f2fs_inode *ri = F2FS_INODE(page);
+ return (void *)&(ri->i_addr[1]);
+}
+
+static inline void f2fs_dentry_kunmap(struct inode *dir, struct page *page)
+{
+ if (!f2fs_has_inline_dentry(dir))
+ kunmap(page);
+}
+
static inline int f2fs_readonly(struct super_block *sb)
{
return sb->s_flags & MS_RDONLY;
@@ -1224,6 +1303,19 @@ struct dentry *f2fs_get_parent(struct dentry *child);
/*
* dir.c
*/
+extern unsigned char f2fs_filetype_table[F2FS_FT_MAX];
+void set_de_type(struct f2fs_dir_entry *, struct inode *);
+struct f2fs_dir_entry *find_target_dentry(struct qstr *, int *,
+ struct f2fs_dentry_ptr *);
+bool f2fs_fill_dentries(struct dir_context *, struct f2fs_dentry_ptr *,
+ unsigned int);
+void do_make_empty_dir(struct inode *, struct inode *,
+ struct f2fs_dentry_ptr *);
+struct page *init_inode_metadata(struct inode *, struct inode *,
+ const struct qstr *, struct page *);
+void update_parent_metadata(struct inode *, struct inode *, unsigned int);
+int room_for_filename(const void *, int, int);
+void f2fs_drop_nlink(struct inode *, struct inode *, struct page *);
struct f2fs_dir_entry *f2fs_find_entry(struct inode *, struct qstr *,
struct page **);
struct f2fs_dir_entry *f2fs_parent_dir(struct inode *, struct page **);
@@ -1232,7 +1324,8 @@ void f2fs_set_link(struct inode *, struct f2fs_dir_entry *,
struct page *, struct inode *);
int update_dent_inode(struct inode *, const struct qstr *);
int __f2fs_add_link(struct inode *, const struct qstr *, struct inode *);
-void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *);
+void f2fs_delete_entry(struct f2fs_dir_entry *, struct page *, struct inode *,
+ struct inode *);
int f2fs_do_tmpfile(struct inode *, struct inode *);
int f2fs_make_empty(struct inode *, struct inode *);
bool f2fs_empty_dir(struct inode *);
@@ -1296,6 +1389,7 @@ void destroy_node_manager_caches(void);
* segment.c
*/
void register_inmem_page(struct inode *, struct page *);
+void invalidate_inmem_page(struct inode *, struct page *);
void commit_inmem_pages(struct inode *, bool);
void f2fs_balance_fs(struct f2fs_sb_info *);
void f2fs_balance_fs_bg(struct f2fs_sb_info *);
@@ -1337,8 +1431,8 @@ void destroy_segment_manager_caches(void);
*/
struct page *grab_meta_page(struct f2fs_sb_info *, pgoff_t);
struct page *get_meta_page(struct f2fs_sb_info *, pgoff_t);
-struct page *get_meta_page_ra(struct f2fs_sb_info *, pgoff_t);
int ra_meta_pages(struct f2fs_sb_info *, block_t, int, int);
+void ra_meta_pages_cond(struct f2fs_sb_info *, pgoff_t);
long sync_meta_pages(struct f2fs_sb_info *, enum page_type, long);
void add_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
void remove_dirty_inode(struct f2fs_sb_info *, nid_t, int type);
@@ -1405,7 +1499,7 @@ struct f2fs_stat_info {
int ndirty_node, ndirty_dent, ndirty_dirs, ndirty_meta;
int nats, sits, fnids;
int total_count, utilization;
- int bg_gc, inline_inode;
+ int bg_gc, inline_inode, inline_dir, inmem_pages;
unsigned int valid_count, valid_node_count, valid_inode_count;
unsigned int bimodal, avg_vblocks;
int util_free, util_valid, util_invalid;
@@ -1438,14 +1532,23 @@ static inline struct f2fs_stat_info *F2FS_STAT(struct f2fs_sb_info *sbi)
#define stat_inc_inline_inode(inode) \
do { \
if (f2fs_has_inline_data(inode)) \
- ((F2FS_I_SB(inode))->inline_inode++); \
+ (atomic_inc(&F2FS_I_SB(inode)->inline_inode)); \
} while (0)
#define stat_dec_inline_inode(inode) \
do { \
if (f2fs_has_inline_data(inode)) \
- ((F2FS_I_SB(inode))->inline_inode--); \
+ (atomic_dec(&F2FS_I_SB(inode)->inline_inode)); \
+ } while (0)
+#define stat_inc_inline_dir(inode) \
+ do { \
+ if (f2fs_has_inline_dentry(inode)) \
+ (atomic_inc(&F2FS_I_SB(inode)->inline_dir)); \
+ } while (0)
+#define stat_dec_inline_dir(inode) \
+ do { \
+ if (f2fs_has_inline_dentry(inode)) \
+ (atomic_dec(&F2FS_I_SB(inode)->inline_dir)); \
} while (0)
-
#define stat_inc_seg_type(sbi, curseg) \
((sbi)->segment_count[(curseg)->alloc_type]++)
#define stat_inc_block_count(sbi, curseg) \
@@ -1492,6 +1595,8 @@ void f2fs_destroy_root_stats(void);
#define stat_inc_read_hit(sb)
#define stat_inc_inline_inode(inode)
#define stat_dec_inline_inode(inode)
+#define stat_inc_inline_dir(inode)
+#define stat_dec_inline_dir(inode)
#define stat_inc_seg_type(sbi, curseg)
#define stat_inc_block_count(sbi, curseg)
#define stat_inc_seg_count(si, type)
@@ -1519,9 +1624,20 @@ extern const struct inode_operations f2fs_special_inode_operations;
* inline.c
*/
bool f2fs_may_inline(struct inode *);
+void read_inline_data(struct page *, struct page *);
int f2fs_read_inline_data(struct inode *, struct page *);
-int f2fs_convert_inline_data(struct inode *, pgoff_t, struct page *);
-int f2fs_write_inline_data(struct inode *, struct page *, unsigned int);
-void truncate_inline_data(struct inode *, u64);
+int f2fs_convert_inline_page(struct dnode_of_data *, struct page *);
+int f2fs_convert_inline_inode(struct inode *);
+int f2fs_write_inline_data(struct inode *, struct page *);
+void truncate_inline_data(struct page *, u64);
bool recover_inline_data(struct inode *, struct page *);
+struct f2fs_dir_entry *find_in_inline_dir(struct inode *, struct qstr *,
+ struct page **);
+struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *, struct page **);
+int make_empty_inline_dir(struct inode *inode, struct inode *, struct page *);
+int f2fs_add_inline_entry(struct inode *, const struct qstr *, struct inode *);
+void f2fs_delete_inline_entry(struct f2fs_dir_entry *, struct page *,
+ struct inode *, struct inode *);
+bool f2fs_empty_inline_dir(struct inode *);
+int f2fs_read_inline_dir(struct file *, struct dir_context *);
#endif
diff --git a/fs/f2fs/file.c b/fs/f2fs/file.c
index 8e68bb6..3c27e0e 100644
--- a/fs/f2fs/file.c
+++ b/fs/f2fs/file.c
@@ -41,18 +41,18 @@ static int f2fs_vm_page_mkwrite(struct vm_area_struct *vma,
sb_start_pagefault(inode->i_sb);
- /* force to convert with normal data indices */
- err = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, page);
- if (err)
- goto out;
+ f2fs_bug_on(sbi, f2fs_has_inline_data(inode));
/* block allocation */
f2fs_lock_op(sbi);
set_new_dnode(&dn, inode, NULL, NULL, 0);
err = f2fs_reserve_block(&dn, page->index);
- f2fs_unlock_op(sbi);
- if (err)
+ if (err) {
+ f2fs_unlock_op(sbi);
goto out;
+ }
+ f2fs_put_dnode(&dn);
+ f2fs_unlock_op(sbi);
file_update_time(vma->vm_file);
lock_page(page);
@@ -130,10 +130,45 @@ static inline bool need_do_checkpoint(struct inode *inode)
need_cp = true;
else if (F2FS_I(inode)->xattr_ver == cur_cp_version(F2FS_CKPT(sbi)))
need_cp = true;
+ else if (test_opt(sbi, FASTBOOT))
+ need_cp = true;
+ else if (sbi->active_logs == 2)
+ need_cp = true;
return need_cp;
}
+static bool need_inode_page_update(struct f2fs_sb_info *sbi, nid_t ino)
+{
+ struct page *i = find_get_page(NODE_MAPPING(sbi), ino);
+ bool ret = false;
+ /* But we need to avoid that there are some inode updates */
+ if ((i && PageDirty(i)) || need_inode_block_update(sbi, ino))
+ ret = true;
+ f2fs_put_page(i, 0);
+ return ret;
+}
+
+static void try_to_fix_pino(struct inode *inode)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ nid_t pino;
+
+ down_write(&fi->i_sem);
+ fi->xattr_ver = 0;
+ if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
+ get_parent_ino(inode, &pino)) {
+ fi->i_pino = pino;
+ file_got_pino(inode);
+ up_write(&fi->i_sem);
+
+ mark_inode_dirty_sync(inode);
+ f2fs_write_inode(inode, NULL);
+ } else {
+ up_write(&fi->i_sem);
+ }
+}
+
int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
{
struct inode *inode = file->f_mapping->host;
@@ -164,19 +199,21 @@ int f2fs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
return ret;
}
+ /* if the inode is dirty, let's recover all the time */
+ if (!datasync && is_inode_flag_set(fi, FI_DIRTY_INODE)) {
+ update_inode_page(inode);
+ goto go_write;
+ }
+
/*
* if there is no written data, don't waste time to write recovery info.
*/
if (!is_inode_flag_set(fi, FI_APPEND_WRITE) &&
!exist_written_data(sbi, ino, APPEND_INO)) {
- struct page *i = find_get_page(NODE_MAPPING(sbi), ino);
- /* But we need to avoid that there are some inode updates */
- if ((i && PageDirty(i)) || need_inode_block_update(sbi, ino)) {
- f2fs_put_page(i, 0);
+ /* it may call write_inode just prior to fsync */
+ if (need_inode_page_update(sbi, ino))
goto go_write;
- }
- f2fs_put_page(i, 0);
if (is_inode_flag_set(fi, FI_UPDATE_WRITE) ||
exist_written_data(sbi, ino, UPDATE_INO))
@@ -196,49 +233,36 @@ go_write:
up_read(&fi->i_sem);
if (need_cp) {
- nid_t pino;
-
/* all the dirty node pages should be flushed for POR */
ret = f2fs_sync_fs(inode->i_sb, 1);
- down_write(&fi->i_sem);
- F2FS_I(inode)->xattr_ver = 0;
- if (file_wrong_pino(inode) && inode->i_nlink == 1 &&
- get_parent_ino(inode, &pino)) {
- F2FS_I(inode)->i_pino = pino;
- file_got_pino(inode);
- up_write(&fi->i_sem);
- mark_inode_dirty_sync(inode);
- ret = f2fs_write_inode(inode, NULL);
- if (ret)
- goto out;
- } else {
- up_write(&fi->i_sem);
- }
- } else {
+ /*
+ * We've secured consistency through sync_fs. Following pino
+ * will be used only for fsynced inodes after checkpoint.
+ */
+ try_to_fix_pino(inode);
+ goto out;
+ }
sync_nodes:
- sync_node_pages(sbi, ino, &wbc);
-
- if (need_inode_block_update(sbi, ino)) {
- mark_inode_dirty_sync(inode);
- ret = f2fs_write_inode(inode, NULL);
- if (ret)
- goto out;
- goto sync_nodes;
- }
+ sync_node_pages(sbi, ino, &wbc);
- ret = wait_on_node_pages_writeback(sbi, ino);
- if (ret)
- goto out;
+ if (need_inode_block_update(sbi, ino)) {
+ mark_inode_dirty_sync(inode);
+ f2fs_write_inode(inode, NULL);
+ goto sync_nodes;
+ }
+
+ ret = wait_on_node_pages_writeback(sbi, ino);
+ if (ret)
+ goto out;
- /* once recovery info is written, don't need to tack this */
- remove_dirty_inode(sbi, ino, APPEND_INO);
- clear_inode_flag(fi, FI_APPEND_WRITE);
+ /* once recovery info is written, don't need to tack this */
+ remove_dirty_inode(sbi, ino, APPEND_INO);
+ clear_inode_flag(fi, FI_APPEND_WRITE);
flush_out:
- remove_dirty_inode(sbi, ino, UPDATE_INO);
- clear_inode_flag(fi, FI_UPDATE_WRITE);
- ret = f2fs_issue_flush(F2FS_I_SB(inode));
- }
+ remove_dirty_inode(sbi, ino, UPDATE_INO);
+ clear_inode_flag(fi, FI_UPDATE_WRITE);
+ ret = f2fs_issue_flush(sbi);
out:
trace_f2fs_sync_file_exit(inode, need_cp, datasync, ret);
return ret;
@@ -296,7 +320,7 @@ static loff_t f2fs_seek_block(struct file *file, loff_t offset, int whence)
goto fail;
/* handle inline data case */
- if (f2fs_has_inline_data(inode)) {
+ if (f2fs_has_inline_data(inode) || f2fs_has_inline_dentry(inode)) {
if (whence == SEEK_HOLE)
data_ofs = isize;
goto found;
@@ -374,6 +398,15 @@ static loff_t f2fs_llseek(struct file *file, loff_t offset, int whence)
static int f2fs_file_mmap(struct file *file, struct vm_area_struct *vma)
{
+ struct inode *inode = file_inode(file);
+
+ /* we don't need to use inline_data strictly */
+ if (f2fs_has_inline_data(inode)) {
+ int err = f2fs_convert_inline_inode(inode);
+ if (err)
+ return err;
+ }
+
file_accessed(file);
vma->vm_ops = &f2fs_file_vm_ops;
return 0;
@@ -415,20 +448,17 @@ void truncate_data_blocks(struct dnode_of_data *dn)
truncate_data_blocks_range(dn, ADDRS_PER_BLOCK);
}
-static void truncate_partial_data_page(struct inode *inode, u64 from)
+static int truncate_partial_data_page(struct inode *inode, u64 from)
{
unsigned offset = from & (PAGE_CACHE_SIZE - 1);
struct page *page;
- if (f2fs_has_inline_data(inode))
- return truncate_inline_data(inode, from);
-
if (!offset)
- return;
+ return 0;
page = find_data_page(inode, from >> PAGE_CACHE_SHIFT, false);
if (IS_ERR(page))
- return;
+ return 0;
lock_page(page);
if (unlikely(!PageUptodate(page) ||
@@ -438,9 +468,9 @@ static void truncate_partial_data_page(struct inode *inode, u64 from)
f2fs_wait_on_page_writeback(page, DATA);
zero_user(page, offset, PAGE_CACHE_SIZE - offset);
set_page_dirty(page);
-
out:
f2fs_put_page(page, 1);
+ return 0;
}
int truncate_blocks(struct inode *inode, u64 from, bool lock)
@@ -450,27 +480,33 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
struct dnode_of_data dn;
pgoff_t free_from;
int count = 0, err = 0;
+ struct page *ipage;
trace_f2fs_truncate_blocks_enter(inode, from);
- if (f2fs_has_inline_data(inode))
- goto done;
-
free_from = (pgoff_t)
- ((from + blocksize - 1) >> (sbi->log_blocksize));
+ ((from + blocksize - 1) >> (sbi->log_blocksize));
if (lock)
f2fs_lock_op(sbi);
- set_new_dnode(&dn, inode, NULL, NULL, 0);
+ ipage = get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(ipage)) {
+ err = PTR_ERR(ipage);
+ goto out;
+ }
+
+ if (f2fs_has_inline_data(inode)) {
+ f2fs_put_page(ipage, 1);
+ goto out;
+ }
+
+ set_new_dnode(&dn, inode, ipage, NULL, 0);
err = get_dnode_of_data(&dn, free_from, LOOKUP_NODE);
if (err) {
if (err == -ENOENT)
goto free_next;
- if (lock)
- f2fs_unlock_op(sbi);
- trace_f2fs_truncate_blocks_exit(inode, err);
- return err;
+ goto out;
}
count = ADDRS_PER_PAGE(dn.node_page, F2FS_I(inode));
@@ -486,11 +522,13 @@ int truncate_blocks(struct inode *inode, u64 from, bool lock)
f2fs_put_dnode(&dn);
free_next:
err = truncate_inode_blocks(inode, free_from);
+out:
if (lock)
f2fs_unlock_op(sbi);
-done:
+
/* lastly zero out the first data page */
- truncate_partial_data_page(inode, from);
+ if (!err)
+ err = truncate_partial_data_page(inode, from);
trace_f2fs_truncate_blocks_exit(inode, err);
return err;
@@ -504,6 +542,12 @@ void f2fs_truncate(struct inode *inode)
trace_f2fs_truncate(inode);
+ /* we should check inline_data size */
+ if (f2fs_has_inline_data(inode) && !f2fs_may_inline(inode)) {
+ if (f2fs_convert_inline_inode(inode))
+ return;
+ }
+
if (!truncate_blocks(inode, i_size_read(inode), true)) {
inode->i_mtime = inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(inode);
@@ -561,10 +605,6 @@ int f2fs_setattr(struct dentry *dentry, struct iattr *attr)
return err;
if (attr->ia_valid & ATTR_SIZE) {
- err = f2fs_convert_inline_data(inode, attr->ia_size, NULL);
- if (err)
- return err;
-
if (attr->ia_size != i_size_read(inode)) {
truncate_setsize(inode, attr->ia_size);
f2fs_truncate(inode);
@@ -665,9 +705,11 @@ static int punch_hole(struct inode *inode, loff_t offset, loff_t len)
if (offset >= inode->i_size)
return ret;
- ret = f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, NULL);
- if (ret)
- return ret;
+ if (f2fs_has_inline_data(inode)) {
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
+ }
pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
@@ -721,9 +763,11 @@ static int expand_inode_data(struct inode *inode, loff_t offset,
if (ret)
return ret;
- ret = f2fs_convert_inline_data(inode, offset + len, NULL);
- if (ret)
- return ret;
+ if (f2fs_has_inline_data(inode)) {
+ ret = f2fs_convert_inline_inode(inode);
+ if (ret)
+ return ret;
+ }
pg_start = ((unsigned long long) offset) >> PAGE_CACHE_SHIFT;
pg_end = ((unsigned long long) offset + len) >> PAGE_CACHE_SHIFT;
@@ -874,7 +918,15 @@ static int f2fs_ioc_start_atomic_write(struct file *filp)
set_inode_flag(F2FS_I(inode), FI_ATOMIC_FILE);
- return f2fs_convert_inline_data(inode, MAX_INLINE_DATA + 1, NULL);
+ return f2fs_convert_inline_inode(inode);
+}
+
+static int f2fs_release_file(struct inode *inode, struct file *filp)
+{
+ /* some remained atomic pages should discarded */
+ if (f2fs_is_atomic_file(inode) || f2fs_is_volatile_file(inode))
+ commit_inmem_pages(inode, true);
+ return 0;
}
static int f2fs_ioc_commit_atomic_write(struct file *filp)
@@ -908,7 +960,8 @@ static int f2fs_ioc_start_volatile_write(struct file *filp)
return -EACCES;
set_inode_flag(F2FS_I(inode), FI_VOLATILE_FILE);
- return 0;
+
+ return f2fs_convert_inline_inode(inode);
}
static int f2fs_ioc_fitrim(struct file *filp, unsigned long arg)
@@ -985,6 +1038,7 @@ const struct file_operations f2fs_file_operations = {
.read_iter = generic_file_read_iter,
.write_iter = generic_file_write_iter,
.open = generic_file_open,
+ .release = f2fs_release_file,
.mmap = f2fs_file_mmap,
.fsync = f2fs_sync_file,
.fallocate = f2fs_fallocate,
diff --git a/fs/f2fs/gc.c b/fs/f2fs/gc.c
index 2a8f4ac..eec0933 100644
--- a/fs/f2fs/gc.c
+++ b/fs/f2fs/gc.c
@@ -96,8 +96,6 @@ int start_gc_thread(struct f2fs_sb_info *sbi)
dev_t dev = sbi->sb->s_bdev->bd_dev;
int err = 0;
- if (!test_opt(sbi, BG_GC))
- goto out;
gc_th = kmalloc(sizeof(struct f2fs_gc_kthread), GFP_KERNEL);
if (!gc_th) {
err = -ENOMEM;
@@ -340,34 +338,39 @@ static const struct victim_selection default_v_ops = {
.get_victim = get_victim_by_default,
};
-static struct inode *find_gc_inode(nid_t ino, struct list_head *ilist)
+static struct inode *find_gc_inode(struct gc_inode_list *gc_list, nid_t ino)
{
struct inode_entry *ie;
- list_for_each_entry(ie, ilist, list)
- if (ie->inode->i_ino == ino)
- return ie->inode;
+ ie = radix_tree_lookup(&gc_list->iroot, ino);
+ if (ie)
+ return ie->inode;
return NULL;
}
-static void add_gc_inode(struct inode *inode, struct list_head *ilist)
+static void add_gc_inode(struct gc_inode_list *gc_list, struct inode *inode)
{
struct inode_entry *new_ie;
- if (inode == find_gc_inode(inode->i_ino, ilist)) {
+ if (inode == find_gc_inode(gc_list, inode->i_ino)) {
iput(inode);
return;
}
-
new_ie = f2fs_kmem_cache_alloc(winode_slab, GFP_NOFS);
new_ie->inode = inode;
- list_add_tail(&new_ie->list, ilist);
+retry:
+ if (radix_tree_insert(&gc_list->iroot, inode->i_ino, new_ie)) {
+ cond_resched();
+ goto retry;
+ }
+ list_add_tail(&new_ie->list, &gc_list->ilist);
}
-static void put_gc_inode(struct list_head *ilist)
+static void put_gc_inode(struct gc_inode_list *gc_list)
{
struct inode_entry *ie, *next_ie;
- list_for_each_entry_safe(ie, next_ie, ilist, list) {
+ list_for_each_entry_safe(ie, next_ie, &gc_list->ilist, list) {
+ radix_tree_delete(&gc_list->iroot, ie->inode->i_ino);
iput(ie->inode);
list_del(&ie->list);
kmem_cache_free(winode_slab, ie);
@@ -553,7 +556,7 @@ out:
* the victim data block is ignored.
*/
static void gc_data_segment(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
- struct list_head *ilist, unsigned int segno, int gc_type)
+ struct gc_inode_list *gc_list, unsigned int segno, int gc_type)
{
struct super_block *sb = sbi->sb;
struct f2fs_summary *entry;
@@ -605,27 +608,27 @@ next_step:
data_page = find_data_page(inode,
start_bidx + ofs_in_node, false);
- if (IS_ERR(data_page))
- goto next_iput;
+ if (IS_ERR(data_page)) {
+ iput(inode);
+ continue;
+ }
f2fs_put_page(data_page, 0);
- add_gc_inode(inode, ilist);
- } else {
- inode = find_gc_inode(dni.ino, ilist);
- if (inode) {
- start_bidx = start_bidx_of_node(nofs,
- F2FS_I(inode));
- data_page = get_lock_data_page(inode,
+ add_gc_inode(gc_list, inode);
+ continue;
+ }
+
+ /* phase 3 */
+ inode = find_gc_inode(gc_list, dni.ino);
+ if (inode) {
+ start_bidx = start_bidx_of_node(nofs, F2FS_I(inode));
+ data_page = get_lock_data_page(inode,
start_bidx + ofs_in_node);
- if (IS_ERR(data_page))
- continue;
- move_data_page(inode, data_page, gc_type);
- stat_inc_data_blk_count(sbi, 1);
- }
+ if (IS_ERR(data_page))
+ continue;
+ move_data_page(inode, data_page, gc_type);
+ stat_inc_data_blk_count(sbi, 1);
}
- continue;
-next_iput:
- iput(inode);
}
if (++phase < 4)
@@ -646,18 +649,20 @@ next_iput:
}
static int __get_victim(struct f2fs_sb_info *sbi, unsigned int *victim,
- int gc_type, int type)
+ int gc_type)
{
struct sit_info *sit_i = SIT_I(sbi);
int ret;
+
mutex_lock(&sit_i->sentry_lock);
- ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type, type, LFS);
+ ret = DIRTY_I(sbi)->v_ops->get_victim(sbi, victim, gc_type,
+ NO_CHECK_TYPE, LFS);
mutex_unlock(&sit_i->sentry_lock);
return ret;
}
static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
- struct list_head *ilist, int gc_type)
+ struct gc_inode_list *gc_list, int gc_type)
{
struct page *sum_page;
struct f2fs_summary_block *sum;
@@ -675,7 +680,7 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
gc_node_segment(sbi, sum->entries, segno, gc_type);
break;
case SUM_TYPE_DATA:
- gc_data_segment(sbi, sum->entries, ilist, segno, gc_type);
+ gc_data_segment(sbi, sum->entries, gc_list, segno, gc_type);
break;
}
blk_finish_plug(&plug);
@@ -688,16 +693,18 @@ static void do_garbage_collect(struct f2fs_sb_info *sbi, unsigned int segno,
int f2fs_gc(struct f2fs_sb_info *sbi)
{
- struct list_head ilist;
unsigned int segno, i;
int gc_type = BG_GC;
int nfree = 0;
int ret = -1;
- struct cp_control cpc = {
- .reason = CP_SYNC,
+ struct cp_control cpc;
+ struct gc_inode_list gc_list = {
+ .ilist = LIST_HEAD_INIT(gc_list.ilist),
+ .iroot = RADIX_TREE_INIT(GFP_NOFS),
};
- INIT_LIST_HEAD(&ilist);
+ cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC;
+
gc_more:
if (unlikely(!(sbi->sb->s_flags & MS_ACTIVE)))
goto stop;
@@ -709,7 +716,7 @@ gc_more:
write_checkpoint(sbi, &cpc);
}
- if (!__get_victim(sbi, &segno, gc_type, NO_CHECK_TYPE))
+ if (!__get_victim(sbi, &segno, gc_type))
goto stop;
ret = 0;
@@ -719,7 +726,7 @@ gc_more:
META_SSA);
for (i = 0; i < sbi->segs_per_sec; i++)
- do_garbage_collect(sbi, segno + i, &ilist, gc_type);
+ do_garbage_collect(sbi, segno + i, &gc_list, gc_type);
if (gc_type == FG_GC) {
sbi->cur_victim_sec = NULL_SEGNO;
@@ -735,7 +742,7 @@ gc_more:
stop:
mutex_unlock(&sbi->gc_mutex);
- put_gc_inode(&ilist);
+ put_gc_inode(&gc_list);
return ret;
}
diff --git a/fs/f2fs/gc.h b/fs/f2fs/gc.h
index 16f0b2b..6ff7ad3 100644
--- a/fs/f2fs/gc.h
+++ b/fs/f2fs/gc.h
@@ -40,6 +40,11 @@ struct inode_entry {
struct inode *inode;
};
+struct gc_inode_list {
+ struct list_head ilist;
+ struct radix_tree_root iroot;
+};
+
/*
* inline functions
*/
diff --git a/fs/f2fs/inline.c b/fs/f2fs/inline.c
index 88036fd..f2d3c58 100644
--- a/fs/f2fs/inline.c
+++ b/fs/f2fs/inline.c
@@ -15,35 +15,44 @@
bool f2fs_may_inline(struct inode *inode)
{
- block_t nr_blocks;
- loff_t i_size;
-
if (!test_opt(F2FS_I_SB(inode), INLINE_DATA))
return false;
if (f2fs_is_atomic_file(inode))
return false;
- nr_blocks = F2FS_I(inode)->i_xattr_nid ? 3 : 2;
- if (inode->i_blocks > nr_blocks)
+ if (!S_ISREG(inode->i_mode))
return false;
- i_size = i_size_read(inode);
- if (i_size > MAX_INLINE_DATA)
+ if (i_size_read(inode) > MAX_INLINE_DATA)
return false;
return true;
}
-int f2fs_read_inline_data(struct inode *inode, struct page *page)
+void read_inline_data(struct page *page, struct page *ipage)
{
- struct page *ipage;
void *src_addr, *dst_addr;
- if (page->index) {
- zero_user_segment(page, 0, PAGE_CACHE_SIZE);
- goto out;
- }
+ if (PageUptodate(page))
+ return;
+
+ f2fs_bug_on(F2FS_P_SB(page), page->index);
+
+ zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
+
+ /* Copy the whole inline data block */
+ src_addr = inline_data_addr(ipage);
+ dst_addr = kmap_atomic(page);
+ memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+ flush_dcache_page(page);
+ kunmap_atomic(dst_addr);
+ SetPageUptodate(page);
+}
+
+int f2fs_read_inline_data(struct inode *inode, struct page *page)
+{
+ struct page *ipage;
ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
if (IS_ERR(ipage)) {
@@ -51,112 +60,116 @@ int f2fs_read_inline_data(struct inode *inode, struct page *page)
return PTR_ERR(ipage);
}
- zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
+ if (!f2fs_has_inline_data(inode)) {
+ f2fs_put_page(ipage, 1);
+ return -EAGAIN;
+ }
- /* Copy the whole inline data block */
- src_addr = inline_data_addr(ipage);
- dst_addr = kmap(page);
- memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
- kunmap(page);
- f2fs_put_page(ipage, 1);
+ if (page->index)
+ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+ else
+ read_inline_data(page, ipage);
-out:
SetPageUptodate(page);
+ f2fs_put_page(ipage, 1);
unlock_page(page);
-
return 0;
}
-static int __f2fs_convert_inline_data(struct inode *inode, struct page *page)
+int f2fs_convert_inline_page(struct dnode_of_data *dn, struct page *page)
{
- int err = 0;
- struct page *ipage;
- struct dnode_of_data dn;
void *src_addr, *dst_addr;
block_t new_blk_addr;
- struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_io_info fio = {
.type = DATA,
.rw = WRITE_SYNC | REQ_PRIO,
};
+ int dirty, err;
- f2fs_lock_op(sbi);
- ipage = get_node_page(sbi, inode->i_ino);
- if (IS_ERR(ipage)) {
- err = PTR_ERR(ipage);
- goto out;
- }
+ f2fs_bug_on(F2FS_I_SB(dn->inode), page->index);
- /* someone else converted inline_data already */
- if (!f2fs_has_inline_data(inode))
- goto out;
+ if (!f2fs_exist_data(dn->inode))
+ goto clear_out;
- /*
- * i_addr[0] is not used for inline data,
- * so reserving new block will not destroy inline data
- */
- set_new_dnode(&dn, inode, ipage, NULL, 0);
- err = f2fs_reserve_block(&dn, 0);
+ err = f2fs_reserve_block(dn, 0);
if (err)
- goto out;
+ return err;
f2fs_wait_on_page_writeback(page, DATA);
+
+ if (PageUptodate(page))
+ goto no_update;
+
zero_user_segment(page, MAX_INLINE_DATA, PAGE_CACHE_SIZE);
/* Copy the whole inline data block */
- src_addr = inline_data_addr(ipage);
- dst_addr = kmap(page);
+ src_addr = inline_data_addr(dn->inode_page);
+ dst_addr = kmap_atomic(page);
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
- kunmap(page);
+ flush_dcache_page(page);
+ kunmap_atomic(dst_addr);
SetPageUptodate(page);
+no_update:
+ /* clear dirty state */
+ dirty = clear_page_dirty_for_io(page);
/* write data page to try to make data consistent */
set_page_writeback(page);
- write_data_page(page, &dn, &new_blk_addr, &fio);
- update_extent_cache(new_blk_addr, &dn);
+
+ write_data_page(page, dn, &new_blk_addr, &fio);
+ update_extent_cache(new_blk_addr, dn);
f2fs_wait_on_page_writeback(page, DATA);
+ if (dirty)
+ inode_dec_dirty_pages(dn->inode);
- /* clear inline data and flag after data writeback */
- zero_user_segment(ipage, INLINE_DATA_OFFSET,
- INLINE_DATA_OFFSET + MAX_INLINE_DATA);
- clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
- stat_dec_inline_inode(inode);
+ /* this converted inline_data should be recovered. */
+ set_inode_flag(F2FS_I(dn->inode), FI_APPEND_WRITE);
- sync_inode_page(&dn);
- f2fs_put_dnode(&dn);
-out:
- f2fs_unlock_op(sbi);
- return err;
+ /* clear inline data and flag after data writeback */
+ truncate_inline_data(dn->inode_page, 0);
+clear_out:
+ stat_dec_inline_inode(dn->inode);
+ f2fs_clear_inline_inode(dn->inode);
+ sync_inode_page(dn);
+ f2fs_put_dnode(dn);
+ return 0;
}
-int f2fs_convert_inline_data(struct inode *inode, pgoff_t to_size,
- struct page *page)
+int f2fs_convert_inline_inode(struct inode *inode)
{
- struct page *new_page = page;
- int err;
+ struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
+ struct dnode_of_data dn;
+ struct page *ipage, *page;
+ int err = 0;
- if (!f2fs_has_inline_data(inode))
- return 0;
- else if (to_size <= MAX_INLINE_DATA)
- return 0;
+ page = grab_cache_page(inode->i_mapping, 0);
+ if (!page)
+ return -ENOMEM;
+
+ f2fs_lock_op(sbi);
- if (!page || page->index != 0) {
- new_page = grab_cache_page(inode->i_mapping, 0);
- if (!new_page)
- return -ENOMEM;
+ ipage = get_node_page(sbi, inode->i_ino);
+ if (IS_ERR(ipage)) {
+ err = PTR_ERR(ipage);
+ goto out;
}
- err = __f2fs_convert_inline_data(inode, new_page);
- if (!page || page->index != 0)
- f2fs_put_page(new_page, 1);
+ set_new_dnode(&dn, inode, ipage, ipage, 0);
+
+ if (f2fs_has_inline_data(inode))
+ err = f2fs_convert_inline_page(&dn, page);
+
+ f2fs_put_dnode(&dn);
+out:
+ f2fs_unlock_op(sbi);
+
+ f2fs_put_page(page, 1);
return err;
}
-int f2fs_write_inline_data(struct inode *inode,
- struct page *page, unsigned size)
+int f2fs_write_inline_data(struct inode *inode, struct page *page)
{
void *src_addr, *dst_addr;
- struct page *ipage;
struct dnode_of_data dn;
int err;
@@ -164,47 +177,39 @@ int f2fs_write_inline_data(struct inode *inode,
err = get_dnode_of_data(&dn, 0, LOOKUP_NODE);
if (err)
return err;
- ipage = dn.inode_page;
- f2fs_wait_on_page_writeback(ipage, NODE);
- zero_user_segment(ipage, INLINE_DATA_OFFSET,
- INLINE_DATA_OFFSET + MAX_INLINE_DATA);
- src_addr = kmap(page);
- dst_addr = inline_data_addr(ipage);
- memcpy(dst_addr, src_addr, size);
- kunmap(page);
-
- /* Release the first data block if it is allocated */
if (!f2fs_has_inline_data(inode)) {
- truncate_data_blocks_range(&dn, 1);
- set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
- stat_inc_inline_inode(inode);
+ f2fs_put_dnode(&dn);
+ return -EAGAIN;
}
+ f2fs_bug_on(F2FS_I_SB(inode), page->index);
+
+ f2fs_wait_on_page_writeback(dn.inode_page, NODE);
+ src_addr = kmap_atomic(page);
+ dst_addr = inline_data_addr(dn.inode_page);
+ memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+ kunmap_atomic(src_addr);
+
set_inode_flag(F2FS_I(inode), FI_APPEND_WRITE);
+ set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
+
sync_inode_page(&dn);
f2fs_put_dnode(&dn);
-
return 0;
}
-void truncate_inline_data(struct inode *inode, u64 from)
+void truncate_inline_data(struct page *ipage, u64 from)
{
- struct page *ipage;
+ void *addr;
if (from >= MAX_INLINE_DATA)
return;
- ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
- if (IS_ERR(ipage))
- return;
-
f2fs_wait_on_page_writeback(ipage, NODE);
- zero_user_segment(ipage, INLINE_DATA_OFFSET + from,
- INLINE_DATA_OFFSET + MAX_INLINE_DATA);
- set_page_dirty(ipage);
- f2fs_put_page(ipage, 1);
+ addr = inline_data_addr(ipage);
+ memset(addr + from, 0, MAX_INLINE_DATA - from);
}
bool recover_inline_data(struct inode *inode, struct page *npage)
@@ -236,6 +241,10 @@ process_inline:
src_addr = inline_data_addr(npage);
dst_addr = inline_data_addr(ipage);
memcpy(dst_addr, src_addr, MAX_INLINE_DATA);
+
+ set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
+ set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
+
update_inode(inode, ipage);
f2fs_put_page(ipage, 1);
return true;
@@ -244,16 +253,279 @@ process_inline:
if (f2fs_has_inline_data(inode)) {
ipage = get_node_page(sbi, inode->i_ino);
f2fs_bug_on(sbi, IS_ERR(ipage));
- f2fs_wait_on_page_writeback(ipage, NODE);
- zero_user_segment(ipage, INLINE_DATA_OFFSET,
- INLINE_DATA_OFFSET + MAX_INLINE_DATA);
- clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
+ truncate_inline_data(ipage, 0);
+ f2fs_clear_inline_inode(inode);
update_inode(inode, ipage);
f2fs_put_page(ipage, 1);
} else if (ri && (ri->i_inline & F2FS_INLINE_DATA)) {
truncate_blocks(inode, 0, false);
- set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
goto process_inline;
}
return false;
}
+
+struct f2fs_dir_entry *find_in_inline_dir(struct inode *dir,
+ struct qstr *name, struct page **res_page)
+{
+ struct f2fs_sb_info *sbi = F2FS_SB(dir->i_sb);
+ struct f2fs_inline_dentry *inline_dentry;
+ struct f2fs_dir_entry *de;
+ struct f2fs_dentry_ptr d;
+ struct page *ipage;
+
+ ipage = get_node_page(sbi, dir->i_ino);
+ if (IS_ERR(ipage))
+ return NULL;
+
+ inline_dentry = inline_data_addr(ipage);
+
+ make_dentry_ptr(&d, (void *)inline_dentry, 2);
+ de = find_target_dentry(name, NULL, &d);
+
+ unlock_page(ipage);
+ if (de)
+ *res_page = ipage;
+ else
+ f2fs_put_page(ipage, 0);
+
+ /*
+ * For the most part, it should be a bug when name_len is zero.
+ * We stop here for figuring out where the bugs has occurred.
+ */
+ f2fs_bug_on(sbi, d.max < 0);
+ return de;
+}
+
+struct f2fs_dir_entry *f2fs_parent_inline_dir(struct inode *dir,
+ struct page **p)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+ struct page *ipage;
+ struct f2fs_dir_entry *de;
+ struct f2fs_inline_dentry *dentry_blk;
+
+ ipage = get_node_page(sbi, dir->i_ino);
+ if (IS_ERR(ipage))
+ return NULL;
+
+ dentry_blk = inline_data_addr(ipage);
+ de = &dentry_blk->dentry[1];
+ *p = ipage;
+ unlock_page(ipage);
+ return de;
+}
+
+int make_empty_inline_dir(struct inode *inode, struct inode *parent,
+ struct page *ipage)
+{
+ struct f2fs_inline_dentry *dentry_blk;
+ struct f2fs_dentry_ptr d;
+
+ dentry_blk = inline_data_addr(ipage);
+
+ make_dentry_ptr(&d, (void *)dentry_blk, 2);
+ do_make_empty_dir(inode, parent, &d);
+
+ set_page_dirty(ipage);
+
+ /* update i_size to MAX_INLINE_DATA */
+ if (i_size_read(inode) < MAX_INLINE_DATA) {
+ i_size_write(inode, MAX_INLINE_DATA);
+ set_inode_flag(F2FS_I(inode), FI_UPDATE_DIR);
+ }
+ return 0;
+}
+
+static int f2fs_convert_inline_dir(struct inode *dir, struct page *ipage,
+ struct f2fs_inline_dentry *inline_dentry)
+{
+ struct page *page;
+ struct dnode_of_data dn;
+ struct f2fs_dentry_block *dentry_blk;
+ int err;
+
+ page = grab_cache_page(dir->i_mapping, 0);
+ if (!page)
+ return -ENOMEM;
+
+ set_new_dnode(&dn, dir, ipage, NULL, 0);
+ err = f2fs_reserve_block(&dn, 0);
+ if (err)
+ goto out;
+
+ f2fs_wait_on_page_writeback(page, DATA);
+ zero_user_segment(page, 0, PAGE_CACHE_SIZE);
+
+ dentry_blk = kmap_atomic(page);
+
+ /* copy data from inline dentry block to new dentry block */
+ memcpy(dentry_blk->dentry_bitmap, inline_dentry->dentry_bitmap,
+ INLINE_DENTRY_BITMAP_SIZE);
+ memcpy(dentry_blk->dentry, inline_dentry->dentry,
+ sizeof(struct f2fs_dir_entry) * NR_INLINE_DENTRY);
+ memcpy(dentry_blk->filename, inline_dentry->filename,
+ NR_INLINE_DENTRY * F2FS_SLOT_LEN);
+
+ kunmap_atomic(dentry_blk);
+ SetPageUptodate(page);
+ set_page_dirty(page);
+
+ /* clear inline dir and flag after data writeback */
+ truncate_inline_data(ipage, 0);
+
+ stat_dec_inline_dir(dir);
+ clear_inode_flag(F2FS_I(dir), FI_INLINE_DENTRY);
+
+ if (i_size_read(dir) < PAGE_CACHE_SIZE) {
+ i_size_write(dir, PAGE_CACHE_SIZE);
+ set_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
+ }
+
+ sync_inode_page(&dn);
+out:
+ f2fs_put_page(page, 1);
+ return err;
+}
+
+int f2fs_add_inline_entry(struct inode *dir, const struct qstr *name,
+ struct inode *inode)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+ struct page *ipage;
+ unsigned int bit_pos;
+ f2fs_hash_t name_hash;
+ struct f2fs_dir_entry *de;
+ size_t namelen = name->len;
+ struct f2fs_inline_dentry *dentry_blk = NULL;
+ int slots = GET_DENTRY_SLOTS(namelen);
+ struct page *page;
+ int err = 0;
+ int i;
+
+ name_hash = f2fs_dentry_hash(name);
+
+ ipage = get_node_page(sbi, dir->i_ino);
+ if (IS_ERR(ipage))
+ return PTR_ERR(ipage);
+
+ dentry_blk = inline_data_addr(ipage);
+ bit_pos = room_for_filename(&dentry_blk->dentry_bitmap,
+ slots, NR_INLINE_DENTRY);
+ if (bit_pos >= NR_INLINE_DENTRY) {
+ err = f2fs_convert_inline_dir(dir, ipage, dentry_blk);
+ if (!err)
+ err = -EAGAIN;
+ goto out;
+ }
+
+ down_write(&F2FS_I(inode)->i_sem);
+ page = init_inode_metadata(inode, dir, name, ipage);
+ if (IS_ERR(page)) {
+ err = PTR_ERR(page);
+ goto fail;
+ }
+
+ f2fs_wait_on_page_writeback(ipage, NODE);
+ de = &dentry_blk->dentry[bit_pos];
+ de->hash_code = name_hash;
+ de->name_len = cpu_to_le16(namelen);
+ memcpy(dentry_blk->filename[bit_pos], name->name, name->len);
+ de->ino = cpu_to_le32(inode->i_ino);
+ set_de_type(de, inode);
+ for (i = 0; i < slots; i++)
+ test_and_set_bit_le(bit_pos + i, &dentry_blk->dentry_bitmap);
+ set_page_dirty(ipage);
+
+ /* we don't need to mark_inode_dirty now */
+ F2FS_I(inode)->i_pino = dir->i_ino;
+ update_inode(inode, page);
+ f2fs_put_page(page, 1);
+
+ update_parent_metadata(dir, inode, 0);
+fail:
+ up_write(&F2FS_I(inode)->i_sem);
+
+ if (is_inode_flag_set(F2FS_I(dir), FI_UPDATE_DIR)) {
+ update_inode(dir, ipage);
+ clear_inode_flag(F2FS_I(dir), FI_UPDATE_DIR);
+ }
+out:
+ f2fs_put_page(ipage, 1);
+ return err;
+}
+
+void f2fs_delete_inline_entry(struct f2fs_dir_entry *dentry, struct page *page,
+ struct inode *dir, struct inode *inode)
+{
+ struct f2fs_inline_dentry *inline_dentry;
+ int slots = GET_DENTRY_SLOTS(le16_to_cpu(dentry->name_len));
+ unsigned int bit_pos;
+ int i;
+
+ lock_page(page);
+ f2fs_wait_on_page_writeback(page, NODE);
+
+ inline_dentry = inline_data_addr(page);
+ bit_pos = dentry - inline_dentry->dentry;
+ for (i = 0; i < slots; i++)
+ test_and_clear_bit_le(bit_pos + i,
+ &inline_dentry->dentry_bitmap);
+
+ set_page_dirty(page);
+
+ dir->i_ctime = dir->i_mtime = CURRENT_TIME;
+
+ if (inode)
+ f2fs_drop_nlink(dir, inode, page);
+
+ f2fs_put_page(page, 1);
+}
+
+bool f2fs_empty_inline_dir(struct inode *dir)
+{
+ struct f2fs_sb_info *sbi = F2FS_I_SB(dir);
+ struct page *ipage;
+ unsigned int bit_pos = 2;
+ struct f2fs_inline_dentry *dentry_blk;
+
+ ipage = get_node_page(sbi, dir->i_ino);
+ if (IS_ERR(ipage))
+ return false;
+
+ dentry_blk = inline_data_addr(ipage);
+ bit_pos = find_next_bit_le(&dentry_blk->dentry_bitmap,
+ NR_INLINE_DENTRY,
+ bit_pos);
+
+ f2fs_put_page(ipage, 1);
+
+ if (bit_pos < NR_INLINE_DENTRY)
+ return false;
+
+ return true;
+}
+
+int f2fs_read_inline_dir(struct file *file, struct dir_context *ctx)
+{
+ struct inode *inode = file_inode(file);
+ struct f2fs_inline_dentry *inline_dentry = NULL;
+ struct page *ipage = NULL;
+ struct f2fs_dentry_ptr d;
+
+ if (ctx->pos == NR_INLINE_DENTRY)
+ return 0;
+
+ ipage = get_node_page(F2FS_I_SB(inode), inode->i_ino);
+ if (IS_ERR(ipage))
+ return PTR_ERR(ipage);
+
+ inline_dentry = inline_data_addr(ipage);
+
+ make_dentry_ptr(&d, (void *)inline_dentry, 2);
+
+ if (!f2fs_fill_dentries(ctx, &d, 0))
+ ctx->pos = NR_INLINE_DENTRY;
+
+ f2fs_put_page(ipage, 1);
+ return 0;
+}
diff --git a/fs/f2fs/inode.c b/fs/f2fs/inode.c
index 0deead4..196cc78 100644
--- a/fs/f2fs/inode.c
+++ b/fs/f2fs/inode.c
@@ -67,12 +67,38 @@ static void __set_inode_rdev(struct inode *inode, struct f2fs_inode *ri)
}
}
+static int __recover_inline_status(struct inode *inode, struct page *ipage)
+{
+ void *inline_data = inline_data_addr(ipage);
+ struct f2fs_inode *ri;
+ void *zbuf;
+
+ zbuf = kzalloc(MAX_INLINE_DATA, GFP_NOFS);
+ if (!zbuf)
+ return -ENOMEM;
+
+ if (!memcmp(zbuf, inline_data, MAX_INLINE_DATA)) {
+ kfree(zbuf);
+ return 0;
+ }
+ kfree(zbuf);
+
+ f2fs_wait_on_page_writeback(ipage, NODE);
+ set_inode_flag(F2FS_I(inode), FI_DATA_EXIST);
+
+ ri = F2FS_INODE(ipage);
+ set_raw_inline(F2FS_I(inode), ri);
+ set_page_dirty(ipage);
+ return 0;
+}
+
static int do_read_inode(struct inode *inode)
{
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
struct f2fs_inode_info *fi = F2FS_I(inode);
struct page *node_page;
struct f2fs_inode *ri;
+ int err = 0;
/* Check if ino is within scope */
if (check_nid_range(sbi, inode->i_ino)) {
@@ -114,11 +140,19 @@ static int do_read_inode(struct inode *inode)
get_extent_info(&fi->ext, ri->i_ext);
get_inline_info(fi, ri);
+ /* check data exist */
+ if (f2fs_has_inline_data(inode) && !f2fs_exist_data(inode))
+ err = __recover_inline_status(inode, node_page);
+
/* get rdev by using inline_info */
__get_inode_rdev(inode, ri);
f2fs_put_page(node_page, 1);
- return 0;
+
+ stat_inc_inline_inode(inode);
+ stat_inc_inline_dir(inode);
+
+ return err;
}
struct inode *f2fs_iget(struct super_block *sb, unsigned long ino)
@@ -156,7 +190,7 @@ make_now:
inode->i_op = &f2fs_dir_inode_operations;
inode->i_fop = &f2fs_dir_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops;
- mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_ZERO);
+ mapping_set_gfp_mask(inode->i_mapping, GFP_F2FS_HIGH_ZERO);
} else if (S_ISLNK(inode->i_mode)) {
inode->i_op = &f2fs_symlink_inode_operations;
inode->i_mapping->a_ops = &f2fs_dblock_aops;
@@ -295,11 +329,12 @@ void f2fs_evict_inode(struct inode *inode)
f2fs_lock_op(sbi);
remove_inode_page(inode);
- stat_dec_inline_inode(inode);
f2fs_unlock_op(sbi);
sb_end_intwrite(inode->i_sb);
no_delete:
+ stat_dec_inline_dir(inode);
+ stat_dec_inline_inode(inode);
invalidate_mapping_pages(NODE_MAPPING(sbi), inode->i_ino, inode->i_ino);
if (xnid)
invalidate_mapping_pages(NODE_MAPPING(sbi), xnid, xnid);
@@ -325,8 +360,9 @@ void handle_failed_inode(struct inode *inode)
f2fs_truncate(inode);
remove_inode_page(inode);
- stat_dec_inline_inode(inode);
+ clear_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
+ clear_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
alloc_nid_failed(sbi, inode->i_ino);
f2fs_unlock_op(sbi);
diff --git a/fs/f2fs/namei.c b/fs/f2fs/namei.c
index 0d2526e..547a2de 100644
--- a/fs/f2fs/namei.c
+++ b/fs/f2fs/namei.c
@@ -54,6 +54,12 @@ static struct inode *f2fs_new_inode(struct inode *dir, umode_t mode)
nid_free = true;
goto out;
}
+
+ if (f2fs_may_inline(inode))
+ set_inode_flag(F2FS_I(inode), FI_INLINE_DATA);
+ if (test_opt(sbi, INLINE_DENTRY) && S_ISDIR(inode->i_mode))
+ set_inode_flag(F2FS_I(inode), FI_INLINE_DENTRY);
+
trace_f2fs_new_inode(inode, 0);
mark_inode_dirty(inode);
return inode;
@@ -129,8 +135,12 @@ static int f2fs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
alloc_nid_done(sbi, ino);
+ stat_inc_inline_inode(inode);
d_instantiate(dentry, inode);
unlock_new_inode(inode);
+
+ if (IS_DIRSYNC(dir))
+ f2fs_sync_fs(sbi->sb, 1);
return 0;
out:
handle_failed_inode(inode);
@@ -157,6 +167,9 @@ static int f2fs_link(struct dentry *old_dentry, struct inode *dir,
f2fs_unlock_op(sbi);
d_instantiate(dentry, inode);
+
+ if (IS_DIRSYNC(dir))
+ f2fs_sync_fs(sbi->sb, 1);
return 0;
out:
clear_inode_flag(F2FS_I(inode), FI_INC_LINK);
@@ -187,14 +200,12 @@ static struct dentry *f2fs_lookup(struct inode *dir, struct dentry *dentry,
de = f2fs_find_entry(dir, &dentry->d_name, &page);
if (de) {
nid_t ino = le32_to_cpu(de->ino);
- kunmap(page);
+ f2fs_dentry_kunmap(dir, page);
f2fs_put_page(page, 0);
inode = f2fs_iget(dir->i_sb, ino);
if (IS_ERR(inode))
return ERR_CAST(inode);
-
- stat_inc_inline_inode(inode);
}
return d_splice_alias(inode, dentry);
@@ -219,15 +230,18 @@ static int f2fs_unlink(struct inode *dir, struct dentry *dentry)
err = acquire_orphan_inode(sbi);
if (err) {
f2fs_unlock_op(sbi);
- kunmap(page);
+ f2fs_dentry_kunmap(dir, page);
f2fs_put_page(page, 0);
goto fail;
}
- f2fs_delete_entry(de, page, inode);
+ f2fs_delete_entry(de, page, dir, inode);
f2fs_unlock_op(sbi);
/* In order to evict this inode, we set it dirty */
mark_inode_dirty(inode);
+
+ if (IS_DIRSYNC(dir))
+ f2fs_sync_fs(sbi->sb, 1);
fail:
trace_f2fs_unlink_exit(inode, err);
return err;
@@ -261,6 +275,9 @@ static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
d_instantiate(dentry, inode);
unlock_new_inode(inode);
+
+ if (IS_DIRSYNC(dir))
+ f2fs_sync_fs(sbi->sb, 1);
return err;
out:
handle_failed_inode(inode);
@@ -291,11 +308,14 @@ static int f2fs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
goto out_fail;
f2fs_unlock_op(sbi);
+ stat_inc_inline_dir(inode);
alloc_nid_done(sbi, inode->i_ino);
d_instantiate(dentry, inode);
unlock_new_inode(inode);
+ if (IS_DIRSYNC(dir))
+ f2fs_sync_fs(sbi->sb, 1);
return 0;
out_fail:
@@ -338,8 +358,12 @@ static int f2fs_mknod(struct inode *dir, struct dentry *dentry,
f2fs_unlock_op(sbi);
alloc_nid_done(sbi, inode->i_ino);
+
d_instantiate(dentry, inode);
unlock_new_inode(inode);
+
+ if (IS_DIRSYNC(dir))
+ f2fs_sync_fs(sbi->sb, 1);
return 0;
out:
handle_failed_inode(inode);
@@ -435,7 +459,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
old_inode->i_ctime = CURRENT_TIME;
mark_inode_dirty(old_inode);
- f2fs_delete_entry(old_entry, old_page, NULL);
+ f2fs_delete_entry(old_entry, old_page, old_dir, NULL);
if (old_dir_entry) {
if (old_dir != new_dir) {
@@ -443,7 +467,7 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
old_dir_page, new_dir);
update_inode_page(old_inode);
} else {
- kunmap(old_dir_page);
+ f2fs_dentry_kunmap(old_inode, old_dir_page);
f2fs_put_page(old_dir_page, 0);
}
drop_nlink(old_dir);
@@ -452,19 +476,22 @@ static int f2fs_rename(struct inode *old_dir, struct dentry *old_dentry,
}
f2fs_unlock_op(sbi);
+
+ if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
+ f2fs_sync_fs(sbi->sb, 1);
return 0;
put_out_dir:
f2fs_unlock_op(sbi);
- kunmap(new_page);
+ f2fs_dentry_kunmap(new_dir, new_page);
f2fs_put_page(new_page, 0);
out_dir:
if (old_dir_entry) {
- kunmap(old_dir_page);
+ f2fs_dentry_kunmap(old_inode, old_dir_page);
f2fs_put_page(old_dir_page, 0);
}
out_old:
- kunmap(old_page);
+ f2fs_dentry_kunmap(old_dir, old_page);
f2fs_put_page(old_page, 0);
out:
return err;
@@ -588,6 +615,9 @@ static int f2fs_cross_rename(struct inode *old_dir, struct dentry *old_dentry,
update_inode_page(new_dir);
f2fs_unlock_op(sbi);
+
+ if (IS_DIRSYNC(old_dir) || IS_DIRSYNC(new_dir))
+ f2fs_sync_fs(sbi->sb, 1);
return 0;
out_undo:
/* Still we may fail to recover name info of f2fs_inode here */
@@ -596,19 +626,19 @@ out_unlock:
f2fs_unlock_op(sbi);
out_new_dir:
if (new_dir_entry) {
- kunmap(new_dir_page);
+ f2fs_dentry_kunmap(new_inode, new_dir_page);
f2fs_put_page(new_dir_page, 0);
}
out_old_dir:
if (old_dir_entry) {
- kunmap(old_dir_page);
+ f2fs_dentry_kunmap(old_inode, old_dir_page);
f2fs_put_page(old_dir_page, 0);
}
out_new:
- kunmap(new_page);
+ f2fs_dentry_kunmap(new_dir, new_page);
f2fs_put_page(new_page, 0);
out_old:
- kunmap(old_page);
+ f2fs_dentry_kunmap(old_dir, old_page);
f2fs_put_page(old_page, 0);
out:
return err;
diff --git a/fs/f2fs/node.c b/fs/f2fs/node.c
index 44b8afe..f83326c 100644
--- a/fs/f2fs/node.c
+++ b/fs/f2fs/node.c
@@ -31,22 +31,38 @@ bool available_free_memory(struct f2fs_sb_info *sbi, int type)
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct sysinfo val;
+ unsigned long avail_ram;
unsigned long mem_size = 0;
bool res = false;
si_meminfo(&val);
- /* give 25%, 25%, 50% memory for each components respectively */
+
+ /* only uses low memory */
+ avail_ram = val.totalram - val.totalhigh;
+
+ /* give 25%, 25%, 50%, 50% memory for each components respectively */
if (type == FREE_NIDS) {
- mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >> 12;
- res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
+ mem_size = (nm_i->fcnt * sizeof(struct free_nid)) >>
+ PAGE_CACHE_SHIFT;
+ res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
} else if (type == NAT_ENTRIES) {
- mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >> 12;
- res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 2);
+ mem_size = (nm_i->nat_cnt * sizeof(struct nat_entry)) >>
+ PAGE_CACHE_SHIFT;
+ res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 2);
} else if (type == DIRTY_DENTS) {
if (sbi->sb->s_bdi->dirty_exceeded)
return false;
mem_size = get_pages(sbi, F2FS_DIRTY_DENTS);
- res = mem_size < ((val.totalram * nm_i->ram_thresh / 100) >> 1);
+ res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
+ } else if (type == INO_ENTRIES) {
+ int i;
+
+ if (sbi->sb->s_bdi->dirty_exceeded)
+ return false;
+ for (i = 0; i <= UPDATE_INO; i++)
+ mem_size += (sbi->im[i].ino_num *
+ sizeof(struct ino_entry)) >> PAGE_CACHE_SHIFT;
+ res = mem_size < ((avail_ram * nm_i->ram_thresh / 100) >> 1);
}
return res;
}
@@ -131,7 +147,7 @@ static void __set_nat_cache_dirty(struct f2fs_nm_info *nm_i,
if (get_nat_flag(ne, IS_DIRTY))
return;
-retry:
+
head = radix_tree_lookup(&nm_i->nat_set_root, set);
if (!head) {
head = f2fs_kmem_cache_alloc(nat_entry_set_slab, GFP_ATOMIC);
@@ -140,11 +156,7 @@ retry:
INIT_LIST_HEAD(&head->set_list);
head->set = set;
head->entry_cnt = 0;
-
- if (radix_tree_insert(&nm_i->nat_set_root, set, head)) {
- cond_resched();
- goto retry;
- }
+ f2fs_radix_tree_insert(&nm_i->nat_set_root, set, head);
}
list_move_tail(&ne->list, &head->entry_list);
nm_i->dirty_nat_cnt++;
@@ -155,7 +167,7 @@ retry:
static void __clear_nat_cache_dirty(struct f2fs_nm_info *nm_i,
struct nat_entry *ne)
{
- nid_t set = ne->ni.nid / NAT_ENTRY_PER_BLOCK;
+ nid_t set = NAT_BLOCK_OFFSET(ne->ni.nid);
struct nat_entry_set *head;
head = radix_tree_lookup(&nm_i->nat_set_root, set);
@@ -180,11 +192,11 @@ bool is_checkpointed_node(struct f2fs_sb_info *sbi, nid_t nid)
struct nat_entry *e;
bool is_cp = true;
- read_lock(&nm_i->nat_tree_lock);
+ down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, nid);
if (e && !get_nat_flag(e, IS_CHECKPOINTED))
is_cp = false;
- read_unlock(&nm_i->nat_tree_lock);
+ up_read(&nm_i->nat_tree_lock);
return is_cp;
}
@@ -194,11 +206,11 @@ bool has_fsynced_inode(struct f2fs_sb_info *sbi, nid_t ino)
struct nat_entry *e;
bool fsynced = false;
- read_lock(&nm_i->nat_tree_lock);
+ down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ino);
if (e && get_nat_flag(e, HAS_FSYNCED_INODE))
fsynced = true;
- read_unlock(&nm_i->nat_tree_lock);
+ up_read(&nm_i->nat_tree_lock);
return fsynced;
}
@@ -208,13 +220,13 @@ bool need_inode_block_update(struct f2fs_sb_info *sbi, nid_t ino)
struct nat_entry *e;
bool need_update = true;
- read_lock(&nm_i->nat_tree_lock);
+ down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ino);
if (e && get_nat_flag(e, HAS_LAST_FSYNC) &&
(get_nat_flag(e, IS_CHECKPOINTED) ||
get_nat_flag(e, HAS_FSYNCED_INODE)))
need_update = false;
- read_unlock(&nm_i->nat_tree_lock);
+ up_read(&nm_i->nat_tree_lock);
return need_update;
}
@@ -222,13 +234,8 @@ static struct nat_entry *grab_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid)
{
struct nat_entry *new;
- new = kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC);
- if (!new)
- return NULL;
- if (radix_tree_insert(&nm_i->nat_root, nid, new)) {
- kmem_cache_free(nat_entry_slab, new);
- return NULL;
- }
+ new = f2fs_kmem_cache_alloc(nat_entry_slab, GFP_ATOMIC);
+ f2fs_radix_tree_insert(&nm_i->nat_root, nid, new);
memset(new, 0, sizeof(struct nat_entry));
nat_set_nid(new, nid);
nat_reset_flag(new);
@@ -241,18 +248,14 @@ static void cache_nat_entry(struct f2fs_nm_info *nm_i, nid_t nid,
struct f2fs_nat_entry *ne)
{
struct nat_entry *e;
-retry:
- write_lock(&nm_i->nat_tree_lock);
+
+ down_write(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, nid);
if (!e) {
e = grab_nat_entry(nm_i, nid);
- if (!e) {
- write_unlock(&nm_i->nat_tree_lock);
- goto retry;
- }
node_info_from_raw_nat(&e->ni, ne);
}
- write_unlock(&nm_i->nat_tree_lock);
+ up_write(&nm_i->nat_tree_lock);
}
static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
@@ -260,15 +263,11 @@ static void set_node_addr(struct f2fs_sb_info *sbi, struct node_info *ni,
{
struct f2fs_nm_info *nm_i = NM_I(sbi);
struct nat_entry *e;
-retry:
- write_lock(&nm_i->nat_tree_lock);
+
+ down_write(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, ni->nid);
if (!e) {
e = grab_nat_entry(nm_i, ni->nid);
- if (!e) {
- write_unlock(&nm_i->nat_tree_lock);
- goto retry;
- }
e->ni = *ni;
f2fs_bug_on(sbi, ni->blk_addr == NEW_ADDR);
} else if (new_blkaddr == NEW_ADDR) {
@@ -310,7 +309,7 @@ retry:
set_nat_flag(e, HAS_FSYNCED_INODE, true);
set_nat_flag(e, HAS_LAST_FSYNC, fsync_done);
}
- write_unlock(&nm_i->nat_tree_lock);
+ up_write(&nm_i->nat_tree_lock);
}
int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
@@ -320,7 +319,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
if (available_free_memory(sbi, NAT_ENTRIES))
return 0;
- write_lock(&nm_i->nat_tree_lock);
+ down_write(&nm_i->nat_tree_lock);
while (nr_shrink && !list_empty(&nm_i->nat_entries)) {
struct nat_entry *ne;
ne = list_first_entry(&nm_i->nat_entries,
@@ -328,7 +327,7 @@ int try_to_free_nats(struct f2fs_sb_info *sbi, int nr_shrink)
__del_from_nat_cache(nm_i, ne);
nr_shrink--;
}
- write_unlock(&nm_i->nat_tree_lock);
+ up_write(&nm_i->nat_tree_lock);
return nr_shrink;
}
@@ -351,14 +350,14 @@ void get_node_info(struct f2fs_sb_info *sbi, nid_t nid, struct node_info *ni)
ni->nid = nid;
/* Check nat cache */
- read_lock(&nm_i->nat_tree_lock);
+ down_read(&nm_i->nat_tree_lock);
e = __lookup_nat_cache(nm_i, nid);
if (e) {
ni->ino = nat_get_ino(e);
ni->blk_addr = nat_get_blkaddr(e);
ni->version = nat_get_version(e);
}
- read_unlock(&nm_i->nat_tree_lock);
+ up_read(&nm_i->nat_tree_lock);
if (e)
return;
@@ -1298,16 +1297,22 @@ static int f2fs_write_node_page(struct page *page,
return 0;
}
- if (wbc->for_reclaim)
- goto redirty_out;
-
- down_read(&sbi->node_write);
+ if (wbc->for_reclaim) {
+ if (!down_read_trylock(&sbi->node_write))
+ goto redirty_out;
+ } else {
+ down_read(&sbi->node_write);
+ }
set_page_writeback(page);
write_node_page(sbi, page, &fio, nid, ni.blk_addr, &new_addr);
set_node_addr(sbi, &ni, new_addr, is_fsync_dnode(page));
dec_page_count(sbi, F2FS_DIRTY_NODES);
up_read(&sbi->node_write);
unlock_page(page);
+
+ if (wbc->for_reclaim)
+ f2fs_submit_merged_bio(sbi, NODE, WRITE);
+
return 0;
redirty_out:
@@ -1410,13 +1415,13 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
if (build) {
/* do not add allocated nids */
- read_lock(&nm_i->nat_tree_lock);
+ down_read(&nm_i->nat_tree_lock);
ne = __lookup_nat_cache(nm_i, nid);
if (ne &&
(!get_nat_flag(ne, IS_CHECKPOINTED) ||
nat_get_blkaddr(ne) != NULL_ADDR))
allocated = true;
- read_unlock(&nm_i->nat_tree_lock);
+ up_read(&nm_i->nat_tree_lock);
if (allocated)
return 0;
}
@@ -1425,15 +1430,22 @@ static int add_free_nid(struct f2fs_sb_info *sbi, nid_t nid, bool build)
i->nid = nid;
i->state = NID_NEW;
+ if (radix_tree_preload(GFP_NOFS)) {
+ kmem_cache_free(free_nid_slab, i);
+ return 0;
+ }
+
spin_lock(&nm_i->free_nid_list_lock);
if (radix_tree_insert(&nm_i->free_nid_root, i->nid, i)) {
spin_unlock(&nm_i->free_nid_list_lock);
+ radix_tree_preload_end();
kmem_cache_free(free_nid_slab, i);
return 0;
}
list_add_tail(&i->list, &nm_i->free_nid_list);
nm_i->fcnt++;
spin_unlock(&nm_i->free_nid_list_lock);
+ radix_tree_preload_end();
return 1;
}
@@ -1804,21 +1816,15 @@ static void remove_nats_in_journal(struct f2fs_sb_info *sbi)
nid_t nid = le32_to_cpu(nid_in_journal(sum, i));
raw_ne = nat_in_journal(sum, i);
-retry:
- write_lock(&nm_i->nat_tree_lock);
- ne = __lookup_nat_cache(nm_i, nid);
- if (ne)
- goto found;
- ne = grab_nat_entry(nm_i, nid);
+ down_write(&nm_i->nat_tree_lock);
+ ne = __lookup_nat_cache(nm_i, nid);
if (!ne) {
- write_unlock(&nm_i->nat_tree_lock);
- goto retry;
+ ne = grab_nat_entry(nm_i, nid);
+ node_info_from_raw_nat(&ne->ni, &raw_ne);
}
- node_info_from_raw_nat(&ne->ni, &raw_ne);
-found:
__set_nat_cache_dirty(nm_i, ne);
- write_unlock(&nm_i->nat_tree_lock);
+ up_write(&nm_i->nat_tree_lock);
}
update_nats_in_cursum(sum, -i);
mutex_unlock(&curseg->curseg_mutex);
@@ -1889,10 +1895,10 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
}
raw_nat_from_node_info(raw_ne, &ne->ni);
- write_lock(&NM_I(sbi)->nat_tree_lock);
+ down_write(&NM_I(sbi)->nat_tree_lock);
nat_reset_flag(ne);
__clear_nat_cache_dirty(NM_I(sbi), ne);
- write_unlock(&NM_I(sbi)->nat_tree_lock);
+ up_write(&NM_I(sbi)->nat_tree_lock);
if (nat_get_blkaddr(ne) == NULL_ADDR)
add_free_nid(sbi, nid, false);
@@ -1903,10 +1909,10 @@ static void __flush_nat_entry_set(struct f2fs_sb_info *sbi,
else
f2fs_put_page(page, 1);
- if (!set->entry_cnt) {
- radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
- kmem_cache_free(nat_entry_set_slab, set);
- }
+ f2fs_bug_on(sbi, set->entry_cnt);
+
+ radix_tree_delete(&NM_I(sbi)->nat_set_root, set->set);
+ kmem_cache_free(nat_entry_set_slab, set);
}
/*
@@ -1923,6 +1929,8 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
nid_t set_idx = 0;
LIST_HEAD(sets);
+ if (!nm_i->dirty_nat_cnt)
+ return;
/*
* if there are no enough space in journal to store dirty nat
* entries, remove all entries from journal and merge them
@@ -1931,9 +1939,6 @@ void flush_nat_entries(struct f2fs_sb_info *sbi)
if (!__has_cursum_space(sum, nm_i->dirty_nat_cnt, NAT_JOURNAL))
remove_nats_in_journal(sbi);
- if (!nm_i->dirty_nat_cnt)
- return;
-
while ((found = __gang_lookup_nat_set(nm_i,
set_idx, NATVEC_SIZE, setvec))) {
unsigned idx;
@@ -1973,13 +1978,13 @@ static int init_node_manager(struct f2fs_sb_info *sbi)
INIT_RADIX_TREE(&nm_i->free_nid_root, GFP_ATOMIC);
INIT_LIST_HEAD(&nm_i->free_nid_list);
- INIT_RADIX_TREE(&nm_i->nat_root, GFP_ATOMIC);
- INIT_RADIX_TREE(&nm_i->nat_set_root, GFP_ATOMIC);
+ INIT_RADIX_TREE(&nm_i->nat_root, GFP_NOIO);
+ INIT_RADIX_TREE(&nm_i->nat_set_root, GFP_NOIO);
INIT_LIST_HEAD(&nm_i->nat_entries);
mutex_init(&nm_i->build_lock);
spin_lock_init(&nm_i->free_nid_list_lock);
- rwlock_init(&nm_i->nat_tree_lock);
+ init_rwsem(&nm_i->nat_tree_lock);
nm_i->next_scan_nid = le32_to_cpu(sbi->ckpt->next_free_nid);
nm_i->bitmap_size = __bitmap_size(sbi, NAT_BITMAP);
@@ -2035,7 +2040,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
spin_unlock(&nm_i->free_nid_list_lock);
/* destroy nat cache */
- write_lock(&nm_i->nat_tree_lock);
+ down_write(&nm_i->nat_tree_lock);
while ((found = __gang_lookup_nat_cache(nm_i,
nid, NATVEC_SIZE, natvec))) {
unsigned idx;
@@ -2044,7 +2049,7 @@ void destroy_node_manager(struct f2fs_sb_info *sbi)
__del_from_nat_cache(nm_i, natvec[idx]);
}
f2fs_bug_on(sbi, nm_i->nat_cnt);
- write_unlock(&nm_i->nat_tree_lock);
+ up_write(&nm_i->nat_tree_lock);
kfree(nm_i->nat_bitmap);
sbi->nm_info = NULL;
@@ -2061,17 +2066,17 @@ int __init create_node_manager_caches(void)
free_nid_slab = f2fs_kmem_cache_create("free_nid",
sizeof(struct free_nid));
if (!free_nid_slab)
- goto destory_nat_entry;
+ goto destroy_nat_entry;
nat_entry_set_slab = f2fs_kmem_cache_create("nat_entry_set",
sizeof(struct nat_entry_set));
if (!nat_entry_set_slab)
- goto destory_free_nid;
+ goto destroy_free_nid;
return 0;
-destory_free_nid:
+destroy_free_nid:
kmem_cache_destroy(free_nid_slab);
-destory_nat_entry:
+destroy_nat_entry:
kmem_cache_destroy(nat_entry_slab);
fail:
return -ENOMEM;
diff --git a/fs/f2fs/node.h b/fs/f2fs/node.h
index 8d5e6e0d..d10b644 100644
--- a/fs/f2fs/node.h
+++ b/fs/f2fs/node.h
@@ -106,7 +106,8 @@ static inline void raw_nat_from_node_info(struct f2fs_nat_entry *raw_ne,
enum mem_type {
FREE_NIDS, /* indicates the free nid list */
NAT_ENTRIES, /* indicates the cached nat entry */
- DIRTY_DENTS /* indicates dirty dentry pages */
+ DIRTY_DENTS, /* indicates dirty dentry pages */
+ INO_ENTRIES, /* indicates inode entries */
};
struct nat_entry_set {
@@ -192,10 +193,7 @@ static inline void set_to_next_nat(struct f2fs_nm_info *nm_i, nid_t start_nid)
{
unsigned int block_off = NAT_BLOCK_OFFSET(start_nid);
- if (f2fs_test_bit(block_off, nm_i->nat_bitmap))
- f2fs_clear_bit(block_off, nm_i->nat_bitmap);
- else
- f2fs_set_bit(block_off, nm_i->nat_bitmap);
+ f2fs_change_bit(block_off, nm_i->nat_bitmap);
}
static inline void fill_node_footer(struct page *page, nid_t nid,
diff --git a/fs/f2fs/recovery.c b/fs/f2fs/recovery.c
index ebd0132..9160a37 100644
--- a/fs/f2fs/recovery.c
+++ b/fs/f2fs/recovery.c
@@ -111,7 +111,7 @@ retry:
iput(einode);
goto out_unmap_put;
}
- f2fs_delete_entry(de, page, einode);
+ f2fs_delete_entry(de, page, dir, einode);
iput(einode);
goto retry;
}
@@ -129,7 +129,7 @@ retry:
goto out;
out_unmap_put:
- kunmap(page);
+ f2fs_dentry_kunmap(dir, page);
f2fs_put_page(page, 0);
out_err:
iput(dir);
@@ -170,13 +170,15 @@ static int find_fsync_dnodes(struct f2fs_sb_info *sbi, struct list_head *head)
curseg = CURSEG_I(sbi, CURSEG_WARM_NODE);
blkaddr = NEXT_FREE_BLKADDR(sbi, curseg);
+ ra_meta_pages(sbi, blkaddr, 1, META_POR);
+
while (1) {
struct fsync_inode_entry *entry;
if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
return 0;
- page = get_meta_page_ra(sbi, blkaddr);
+ page = get_meta_page(sbi, blkaddr);
if (cp_ver != cpver_of_node(page))
break;
@@ -227,6 +229,8 @@ next:
/* check next segment */
blkaddr = next_blkaddr_of_node(page);
f2fs_put_page(page, 1);
+
+ ra_meta_pages_cond(sbi, blkaddr);
}
f2fs_put_page(page, 1);
return err;
@@ -436,7 +440,9 @@ static int recover_data(struct f2fs_sb_info *sbi,
if (blkaddr < MAIN_BLKADDR(sbi) || blkaddr >= MAX_BLKADDR(sbi))
break;
- page = get_meta_page_ra(sbi, blkaddr);
+ ra_meta_pages_cond(sbi, blkaddr);
+
+ page = get_meta_page(sbi, blkaddr);
if (cp_ver != cpver_of_node(page)) {
f2fs_put_page(page, 1);
diff --git a/fs/f2fs/segment.c b/fs/f2fs/segment.c
index 923cb76..42607a6 100644
--- a/fs/f2fs/segment.c
+++ b/fs/f2fs/segment.c
@@ -178,17 +178,47 @@ void register_inmem_page(struct inode *inode, struct page *page)
{
struct f2fs_inode_info *fi = F2FS_I(inode);
struct inmem_pages *new;
+ int err;
+
+ SetPagePrivate(page);
new = f2fs_kmem_cache_alloc(inmem_entry_slab, GFP_NOFS);
/* add atomic page indices to the list */
new->page = page;
INIT_LIST_HEAD(&new->list);
-
+retry:
/* increase reference count with clean state */
mutex_lock(&fi->inmem_lock);
+ err = radix_tree_insert(&fi->inmem_root, page->index, new);
+ if (err == -EEXIST) {
+ mutex_unlock(&fi->inmem_lock);
+ kmem_cache_free(inmem_entry_slab, new);
+ return;
+ } else if (err) {
+ mutex_unlock(&fi->inmem_lock);
+ goto retry;
+ }
get_page(page);
list_add_tail(&new->list, &fi->inmem_pages);
+ inc_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
+ mutex_unlock(&fi->inmem_lock);
+}
+
+void invalidate_inmem_page(struct inode *inode, struct page *page)
+{
+ struct f2fs_inode_info *fi = F2FS_I(inode);
+ struct inmem_pages *cur;
+
+ mutex_lock(&fi->inmem_lock);
+ cur = radix_tree_lookup(&fi->inmem_root, page->index);
+ if (cur) {
+ radix_tree_delete(&fi->inmem_root, cur->page->index);
+ f2fs_put_page(cur->page, 0);
+ list_del(&cur->list);
+ kmem_cache_free(inmem_entry_slab, cur);
+ dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
+ }
mutex_unlock(&fi->inmem_lock);
}
@@ -203,7 +233,16 @@ void commit_inmem_pages(struct inode *inode, bool abort)
.rw = WRITE_SYNC,
};
- f2fs_balance_fs(sbi);
+ /*
+ * The abort is true only when f2fs_evict_inode is called.
+ * Basically, the f2fs_evict_inode doesn't produce any data writes, so
+ * that we don't need to call f2fs_balance_fs.
+ * Otherwise, f2fs_gc in f2fs_balance_fs can wait forever until this
+ * inode becomes free by iget_locked in f2fs_iget.
+ */
+ if (!abort)
+ f2fs_balance_fs(sbi);
+
f2fs_lock_op(sbi);
mutex_lock(&fi->inmem_lock);
@@ -216,9 +255,11 @@ void commit_inmem_pages(struct inode *inode, bool abort)
do_write_data_page(cur->page, &fio);
submit_bio = true;
}
+ radix_tree_delete(&fi->inmem_root, cur->page->index);
f2fs_put_page(cur->page, 1);
list_del(&cur->list);
kmem_cache_free(inmem_entry_slab, cur);
+ dec_page_count(F2FS_I_SB(inode), F2FS_INMEM_PAGES);
}
if (submit_bio)
f2fs_submit_merged_bio(sbi, DATA, WRITE);
@@ -248,7 +289,8 @@ void f2fs_balance_fs_bg(struct f2fs_sb_info *sbi)
{
/* check the # of cached NAT entries and prefree segments */
if (try_to_free_nats(sbi, NAT_ENTRY_PER_BLOCK) ||
- excess_prefree_segs(sbi))
+ excess_prefree_segs(sbi) ||
+ available_free_memory(sbi, INO_ENTRIES))
f2fs_sync_fs(sbi->sb, true);
}
@@ -441,10 +483,33 @@ void discard_next_dnode(struct f2fs_sb_info *sbi, block_t blkaddr)
}
}
-static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+static void __add_discard_entry(struct f2fs_sb_info *sbi,
+ struct cp_control *cpc, unsigned int start, unsigned int end)
{
struct list_head *head = &SM_I(sbi)->discard_list;
- struct discard_entry *new;
+ struct discard_entry *new, *last;
+
+ if (!list_empty(head)) {
+ last = list_last_entry(head, struct discard_entry, list);
+ if (START_BLOCK(sbi, cpc->trim_start) + start ==
+ last->blkaddr + last->len) {
+ last->len += end - start;
+ goto done;
+ }
+ }
+
+ new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
+ INIT_LIST_HEAD(&new->list);
+ new->blkaddr = START_BLOCK(sbi, cpc->trim_start) + start;
+ new->len = end - start;
+ list_add_tail(&new->list, head);
+done:
+ SM_I(sbi)->nr_discards += end - start;
+ cpc->trimmed += end - start;
+}
+
+static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
+{
int entries = SIT_VBLOCK_MAP_SIZE / sizeof(unsigned long);
int max_blocks = sbi->blocks_per_seg;
struct seg_entry *se = get_seg_entry(sbi, cpc->trim_start);
@@ -473,13 +538,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
}
mutex_unlock(&dirty_i->seglist_lock);
- new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
- INIT_LIST_HEAD(&new->list);
- new->blkaddr = START_BLOCK(sbi, cpc->trim_start);
- new->len = sbi->blocks_per_seg;
- list_add_tail(&new->list, head);
- SM_I(sbi)->nr_discards += sbi->blocks_per_seg;
- cpc->trimmed += sbi->blocks_per_seg;
+ __add_discard_entry(sbi, cpc, 0, sbi->blocks_per_seg);
return;
}
@@ -489,7 +548,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
/* SIT_VBLOCK_MAP_SIZE should be multiple of sizeof(unsigned long) */
for (i = 0; i < entries; i++)
- dmap[i] = (cur_map[i] ^ ckpt_map[i]) & ckpt_map[i];
+ dmap[i] = ~(cur_map[i] | ckpt_map[i]);
while (force || SM_I(sbi)->nr_discards <= SM_I(sbi)->max_discards) {
start = __find_rev_next_bit(dmap, max_blocks, end + 1);
@@ -501,14 +560,7 @@ static void add_discard_addrs(struct f2fs_sb_info *sbi, struct cp_control *cpc)
if (end - start < cpc->trim_minlen)
continue;
- new = f2fs_kmem_cache_alloc(discard_entry_slab, GFP_NOFS);
- INIT_LIST_HEAD(&new->list);
- new->blkaddr = START_BLOCK(sbi, cpc->trim_start) + start;
- new->len = end - start;
- cpc->trimmed += end - start;
-
- list_add_tail(&new->list, head);
- SM_I(sbi)->nr_discards += end - start;
+ __add_discard_entry(sbi, cpc, start, end);
}
}
@@ -620,10 +672,10 @@ static void update_sit_entry(struct f2fs_sb_info *sbi, block_t blkaddr, int del)
/* Update valid block bitmap */
if (del > 0) {
- if (f2fs_set_bit(offset, se->cur_valid_map))
+ if (f2fs_test_and_set_bit(offset, se->cur_valid_map))
f2fs_bug_on(sbi, 1);
} else {
- if (!f2fs_clear_bit(offset, se->cur_valid_map))
+ if (!f2fs_test_and_clear_bit(offset, se->cur_valid_map))
f2fs_bug_on(sbi, 1);
}
if (!f2fs_test_bit(offset, se->ckpt_valid_map))
@@ -1004,6 +1056,7 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
range->len < sbi->blocksize)
return -EINVAL;
+ cpc.trimmed = 0;
if (end <= MAIN_BLKADDR(sbi))
goto out;
@@ -1015,10 +1068,11 @@ int f2fs_trim_fs(struct f2fs_sb_info *sbi, struct fstrim_range *range)
cpc.trim_start = start_segno;
cpc.trim_end = end_segno;
cpc.trim_minlen = range->minlen >> sbi->log_blocksize;
- cpc.trimmed = 0;
/* do checkpoint to issue discard commands safely */
+ mutex_lock(&sbi->gc_mutex);
write_checkpoint(sbi, &cpc);
+ mutex_unlock(&sbi->gc_mutex);
out:
range->len = cpc.trimmed << sbi->log_blocksize;
return 0;
@@ -1050,8 +1104,8 @@ static int __get_segment_type_4(struct page *page, enum page_type p_type)
else
return CURSEG_COLD_DATA;
} else {
- if (IS_DNODE(page) && !is_cold_node(page))
- return CURSEG_HOT_NODE;
+ if (IS_DNODE(page) && is_cold_node(page))
+ return CURSEG_WARM_NODE;
else
return CURSEG_COLD_NODE;
}
@@ -1524,17 +1578,7 @@ int lookup_journal_in_cursum(struct f2fs_summary_block *sum, int type,
static struct page *get_current_sit_page(struct f2fs_sb_info *sbi,
unsigned int segno)
{
- struct sit_info *sit_i = SIT_I(sbi);
- unsigned int offset = SIT_BLOCK_OFFSET(segno);
- block_t blk_addr = sit_i->sit_base_addr + offset;
-
- check_seg_range(sbi, segno);
-
- /* calculate sit block address */
- if (f2fs_test_bit(offset, sit_i->sit_bitmap))
- blk_addr += sit_i->sit_blocks;
-
- return get_meta_page(sbi, blk_addr);
+ return get_meta_page(sbi, current_sit_addr(sbi, segno));
}
static struct page *get_next_sit_page(struct f2fs_sb_info *sbi,
@@ -1687,7 +1731,7 @@ void flush_sit_entries(struct f2fs_sb_info *sbi, struct cp_control *cpc)
* #2, flush sit entries to sit page.
*/
list_for_each_entry_safe(ses, tmp, head, set_list) {
- struct page *page;
+ struct page *page = NULL;
struct f2fs_sit_block *raw_sit = NULL;
unsigned int start_segno = ses->start_segno;
unsigned int end = min(start_segno + SIT_ENTRY_PER_BLOCK,
@@ -2200,7 +2244,7 @@ int __init create_segment_manager_caches(void)
goto fail;
sit_entry_set_slab = f2fs_kmem_cache_create("sit_entry_set",
- sizeof(struct nat_entry_set));
+ sizeof(struct sit_entry_set));
if (!sit_entry_set_slab)
goto destory_discard_entry;
diff --git a/fs/f2fs/segment.h b/fs/f2fs/segment.h
index 2495bec..7f327c0 100644
--- a/fs/f2fs/segment.h
+++ b/fs/f2fs/segment.h
@@ -657,10 +657,7 @@ static inline void set_to_next_sit(struct sit_info *sit_i, unsigned int start)
{
unsigned int block_off = SIT_BLOCK_OFFSET(start);
- if (f2fs_test_bit(block_off, sit_i->sit_bitmap))
- f2fs_clear_bit(block_off, sit_i->sit_bitmap);
- else
- f2fs_set_bit(block_off, sit_i->sit_bitmap);
+ f2fs_change_bit(block_off, sit_i->sit_bitmap);
}
static inline unsigned long long get_mtime(struct f2fs_sb_info *sbi)
@@ -714,6 +711,9 @@ static inline unsigned int max_hw_blocks(struct f2fs_sb_info *sbi)
*/
static inline int nr_pages_to_skip(struct f2fs_sb_info *sbi, int type)
{
+ if (sbi->sb->s_bdi->dirty_exceeded)
+ return 0;
+
if (type == DATA)
return sbi->blocks_per_seg;
else if (type == NODE)
diff --git a/fs/f2fs/super.c b/fs/f2fs/super.c
index 41d6f70..f71421d 100644
--- a/fs/f2fs/super.c
+++ b/fs/f2fs/super.c
@@ -51,8 +51,10 @@ enum {
Opt_disable_ext_identify,
Opt_inline_xattr,
Opt_inline_data,
+ Opt_inline_dentry,
Opt_flush_merge,
Opt_nobarrier,
+ Opt_fastboot,
Opt_err,
};
@@ -69,8 +71,10 @@ static match_table_t f2fs_tokens = {
{Opt_disable_ext_identify, "disable_ext_identify"},
{Opt_inline_xattr, "inline_xattr"},
{Opt_inline_data, "inline_data"},
+ {Opt_inline_dentry, "inline_dentry"},
{Opt_flush_merge, "flush_merge"},
{Opt_nobarrier, "nobarrier"},
+ {Opt_fastboot, "fastboot"},
{Opt_err, NULL},
};
@@ -340,12 +344,18 @@ static int parse_options(struct super_block *sb, char *options)
case Opt_inline_data:
set_opt(sbi, INLINE_DATA);
break;
+ case Opt_inline_dentry:
+ set_opt(sbi, INLINE_DENTRY);
+ break;
case Opt_flush_merge:
set_opt(sbi, FLUSH_MERGE);
break;
case Opt_nobarrier:
set_opt(sbi, NOBARRIER);
break;
+ case Opt_fastboot:
+ set_opt(sbi, FASTBOOT);
+ break;
default:
f2fs_msg(sb, KERN_ERR,
"Unrecognized mount option \"%s\" or missing value",
@@ -373,6 +383,7 @@ static struct inode *f2fs_alloc_inode(struct super_block *sb)
fi->i_advise = 0;
rwlock_init(&fi->ext.ext_lock);
init_rwsem(&fi->i_sem);
+ INIT_RADIX_TREE(&fi->inmem_root, GFP_NOFS);
INIT_LIST_HEAD(&fi->inmem_pages);
mutex_init(&fi->inmem_lock);
@@ -473,9 +484,9 @@ int f2fs_sync_fs(struct super_block *sb, int sync)
trace_f2fs_sync_fs(sb, sync);
if (sync) {
- struct cp_control cpc = {
- .reason = CP_SYNC,
- };
+ struct cp_control cpc;
+
+ cpc.reason = test_opt(sbi, FASTBOOT) ? CP_UMOUNT : CP_SYNC;
mutex_lock(&sbi->gc_mutex);
write_checkpoint(sbi, &cpc);
mutex_unlock(&sbi->gc_mutex);
@@ -562,10 +573,14 @@ static int f2fs_show_options(struct seq_file *seq, struct dentry *root)
seq_puts(seq, ",disable_ext_identify");
if (test_opt(sbi, INLINE_DATA))
seq_puts(seq, ",inline_data");
+ if (test_opt(sbi, INLINE_DENTRY))
+ seq_puts(seq, ",inline_dentry");
if (!f2fs_readonly(sbi->sb) && test_opt(sbi, FLUSH_MERGE))
seq_puts(seq, ",flush_merge");
if (test_opt(sbi, NOBARRIER))
seq_puts(seq, ",nobarrier");
+ if (test_opt(sbi, FASTBOOT))
+ seq_puts(seq, ",fastboot");
seq_printf(seq, ",active_logs=%u", sbi->active_logs);
return 0;
@@ -654,7 +669,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
f2fs_sync_fs(sb, 1);
need_restart_gc = true;
}
- } else if (test_opt(sbi, BG_GC) && !sbi->gc_thread) {
+ } else if (!sbi->gc_thread) {
err = start_gc_thread(sbi);
if (err)
goto restore_opts;
@@ -667,7 +682,7 @@ static int f2fs_remount(struct super_block *sb, int *flags, char *data)
*/
if ((*flags & MS_RDONLY) || !test_opt(sbi, FLUSH_MERGE)) {
destroy_flush_cmd_control(sbi);
- } else if (test_opt(sbi, FLUSH_MERGE) && !SM_I(sbi)->cmd_control_info) {
+ } else if (!SM_I(sbi)->cmd_control_info) {
err = create_flush_cmd_control(sbi);
if (err)
goto restore_gc;
@@ -922,7 +937,7 @@ retry:
static int f2fs_fill_super(struct super_block *sb, void *data, int silent)
{
struct f2fs_sb_info *sbi;
- struct f2fs_super_block *raw_super;
+ struct f2fs_super_block *raw_super = NULL;
struct buffer_head *raw_super_buf;
struct inode *root;
long err = -EINVAL;
@@ -1123,7 +1138,7 @@ try_onemore:
* If filesystem is not mounted as read-only then
* do start the gc_thread.
*/
- if (!f2fs_readonly(sb)) {
+ if (test_opt(sbi, BG_GC) && !f2fs_readonly(sb)) {
/* After POR, we can run background GC thread.*/
err = start_gc_thread(sbi);
if (err)
diff --git a/fs/f2fs/xattr.c b/fs/f2fs/xattr.c
index deca872..5072bf9 100644
--- a/fs/f2fs/xattr.c
+++ b/fs/f2fs/xattr.c
@@ -83,7 +83,7 @@ static int f2fs_xattr_generic_get(struct dentry *dentry, const char *name,
}
if (strcmp(name, "") == 0)
return -EINVAL;
- return f2fs_getxattr(dentry->d_inode, type, name, buffer, size);
+ return f2fs_getxattr(dentry->d_inode, type, name, buffer, size, NULL);
}
static int f2fs_xattr_generic_set(struct dentry *dentry, const char *name,
@@ -398,7 +398,7 @@ static inline int write_all_xattrs(struct inode *inode, __u32 hsize,
}
int f2fs_getxattr(struct inode *inode, int index, const char *name,
- void *buffer, size_t buffer_size)
+ void *buffer, size_t buffer_size, struct page *ipage)
{
struct f2fs_xattr_entry *entry;
void *base_addr;
@@ -412,7 +412,7 @@ int f2fs_getxattr(struct inode *inode, int index, const char *name,
if (len > F2FS_NAME_LEN)
return -ERANGE;
- base_addr = read_all_xattrs(inode, NULL);
+ base_addr = read_all_xattrs(inode, ipage);
if (!base_addr)
return -ENOMEM;
diff --git a/fs/f2fs/xattr.h b/fs/f2fs/xattr.h
index 34ab7db..969d792 100644
--- a/fs/f2fs/xattr.h
+++ b/fs/f2fs/xattr.h
@@ -115,7 +115,8 @@ extern const struct xattr_handler *f2fs_xattr_handlers[];
extern int f2fs_setxattr(struct inode *, int, const char *,
const void *, size_t, struct page *, int);
-extern int f2fs_getxattr(struct inode *, int, const char *, void *, size_t);
+extern int f2fs_getxattr(struct inode *, int, const char *, void *,
+ size_t, struct page *);
extern ssize_t f2fs_listxattr(struct dentry *, char *, size_t);
#else
@@ -126,7 +127,8 @@ static inline int f2fs_setxattr(struct inode *inode, int index,
return -EOPNOTSUPP;
}
static inline int f2fs_getxattr(struct inode *inode, int index,
- const char *name, void *buffer, size_t buffer_size)
+ const char *name, void *buffer,
+ size_t buffer_size, struct page *dpage)
{
return -EOPNOTSUPP;
}
diff --git a/fs/fat/dir.c b/fs/fat/dir.c
index 3963ede..c5d6bb9 100644
--- a/fs/fat/dir.c
+++ b/fs/fat/dir.c
@@ -702,10 +702,11 @@ static int fat_readdir(struct file *file, struct dir_context *ctx)
}
#define FAT_IOCTL_FILLDIR_FUNC(func, dirent_type) \
-static int func(void *__buf, const char *name, int name_len, \
+static int func(struct dir_context *ctx, const char *name, int name_len, \
loff_t offset, u64 ino, unsigned int d_type) \
{ \
- struct fat_ioctl_filldir_callback *buf = __buf; \
+ struct fat_ioctl_filldir_callback *buf = \
+ container_of(ctx, struct fat_ioctl_filldir_callback, ctx); \
struct dirent_type __user *d1 = buf->dirent; \
struct dirent_type __user *d2 = d1 + 1; \
\
diff --git a/fs/file.c b/fs/file.c
index ab3eb6a..ee738ea 100644
--- a/fs/file.c
+++ b/fs/file.c
@@ -869,7 +869,7 @@ SYSCALL_DEFINE1(dup, unsigned int, fildes)
struct file *file = fget_raw(fildes);
if (file) {
- ret = get_unused_fd();
+ ret = get_unused_fd_flags(0);
if (ret >= 0)
fd_install(ret, file);
else
diff --git a/fs/fuse/dir.c b/fs/fuse/dir.c
index dbab798..df562cc 100644
--- a/fs/fuse/dir.c
+++ b/fs/fuse/dir.c
@@ -372,7 +372,7 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
if (inode && get_node_id(inode) == FUSE_ROOT_ID)
goto out_iput;
- newent = d_materialise_unique(entry, inode);
+ newent = d_splice_alias(inode, entry);
err = PTR_ERR(newent);
if (IS_ERR(newent))
goto out_err;
@@ -1320,7 +1320,7 @@ static int fuse_direntplus_link(struct file *file,
if (!inode)
goto out;
- alias = d_materialise_unique(dentry, inode);
+ alias = d_splice_alias(inode, dentry);
err = PTR_ERR(alias);
if (IS_ERR(alias))
goto out;
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index caa8d95..bf50259 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1988,7 +1988,7 @@ static int fuse_write_begin(struct file *file, struct address_space *mapping,
struct page **pagep, void **fsdata)
{
pgoff_t index = pos >> PAGE_CACHE_SHIFT;
- struct fuse_conn *fc = get_fuse_conn(file->f_dentry->d_inode);
+ struct fuse_conn *fc = get_fuse_conn(file_inode(file));
struct page *page;
loff_t fsize;
int err = -ENOMEM;
diff --git a/fs/gfs2/dir.c b/fs/gfs2/dir.c
index 5d4261ff5..c5a34f0 100644
--- a/fs/gfs2/dir.c
+++ b/fs/gfs2/dir.c
@@ -365,23 +365,17 @@ static __be64 *gfs2_dir_get_hash_table(struct gfs2_inode *ip)
ret = gfs2_dir_read_data(ip, hc, hsize);
if (ret < 0) {
- if (is_vmalloc_addr(hc))
- vfree(hc);
- else
- kfree(hc);
+ kvfree(hc);
return ERR_PTR(ret);
}
spin_lock(&inode->i_lock);
- if (ip->i_hash_cache) {
- if (is_vmalloc_addr(hc))
- vfree(hc);
- else
- kfree(hc);
- } else {
+ if (likely(!ip->i_hash_cache)) {
ip->i_hash_cache = hc;
+ hc = NULL;
}
spin_unlock(&inode->i_lock);
+ kvfree(hc);
return ip->i_hash_cache;
}
@@ -396,10 +390,7 @@ void gfs2_dir_hash_inval(struct gfs2_inode *ip)
{
__be64 *hc = ip->i_hash_cache;
ip->i_hash_cache = NULL;
- if (is_vmalloc_addr(hc))
- vfree(hc);
- else
- kfree(hc);
+ kvfree(hc);
}
static inline int gfs2_dirent_sentinel(const struct gfs2_dirent *dent)
@@ -1168,10 +1159,7 @@ fail:
gfs2_dinode_out(dip, dibh->b_data);
brelse(dibh);
out_kfree:
- if (is_vmalloc_addr(hc2))
- vfree(hc2);
- else
- kfree(hc2);
+ kvfree(hc2);
return error;
}
@@ -1302,14 +1290,6 @@ static void *gfs2_alloc_sort_buffer(unsigned size)
return ptr;
}
-static void gfs2_free_sort_buffer(void *ptr)
-{
- if (is_vmalloc_addr(ptr))
- vfree(ptr);
- else
- kfree(ptr);
-}
-
static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
int *copied, unsigned *depth,
u64 leaf_no)
@@ -1393,7 +1373,7 @@ static int gfs2_dir_read_leaf(struct inode *inode, struct dir_context *ctx,
out_free:
for(i = 0; i < leaf; i++)
brelse(larr[i]);
- gfs2_free_sort_buffer(larr);
+ kvfree(larr);
out:
return error;
}
@@ -2004,10 +1984,7 @@ out_rlist:
gfs2_rlist_free(&rlist);
gfs2_quota_unhold(dip);
out:
- if (is_vmalloc_addr(ht))
- vfree(ht);
- else
- kfree(ht);
+ kvfree(ht);
return error;
}
diff --git a/fs/gfs2/export.c b/fs/gfs2/export.c
index 8b9b377..c41d255 100644
--- a/fs/gfs2/export.c
+++ b/fs/gfs2/export.c
@@ -69,10 +69,12 @@ struct get_name_filldir {
char *name;
};
-static int get_name_filldir(void *opaque, const char *name, int length,
- loff_t offset, u64 inum, unsigned int type)
+static int get_name_filldir(struct dir_context *ctx, const char *name,
+ int length, loff_t offset, u64 inum,
+ unsigned int type)
{
- struct get_name_filldir *gnfd = opaque;
+ struct get_name_filldir *gnfd =
+ container_of(ctx, struct get_name_filldir, ctx);
if (inum != gnfd->inum.no_addr)
return 0;
diff --git a/fs/gfs2/file.c b/fs/gfs2/file.c
index 80dd44d..6e600ab 100644
--- a/fs/gfs2/file.c
+++ b/fs/gfs2/file.c
@@ -337,7 +337,8 @@ static void gfs2_size_hint(struct file *filep, loff_t offset, size_t size)
size_t blks = (size + sdp->sd_sb.sb_bsize - 1) >> sdp->sd_sb.sb_bsize_shift;
int hint = min_t(size_t, INT_MAX, blks);
- atomic_set(&ip->i_res->rs_sizehint, hint);
+ if (hint > atomic_read(&ip->i_res->rs_sizehint))
+ atomic_set(&ip->i_res->rs_sizehint, hint);
}
/**
@@ -728,7 +729,6 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
struct gfs2_inode *ip = GFS2_I(inode);
struct buffer_head *dibh;
int error;
- loff_t size = len;
unsigned int nr_blks;
sector_t lblock = offset >> inode->i_blkbits;
@@ -762,11 +762,6 @@ static int fallocate_chunk(struct inode *inode, loff_t offset, loff_t len,
goto out;
}
}
- if (offset + size > inode->i_size && !(mode & FALLOC_FL_KEEP_SIZE))
- i_size_write(inode, offset + size);
-
- mark_inode_dirty(inode);
-
out:
brelse(dibh);
return error;
@@ -796,8 +791,7 @@ static void calc_max_reserv(struct gfs2_inode *ip, loff_t max, loff_t *len,
}
}
-static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
- loff_t len)
+static long __gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
{
struct inode *inode = file_inode(file);
struct gfs2_sbd *sdp = GFS2_SB(inode);
@@ -811,14 +805,9 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
loff_t bsize_mask = ~((loff_t)sdp->sd_sb.sb_bsize - 1);
loff_t next = (offset + len - 1) >> sdp->sd_sb.sb_bsize_shift;
loff_t max_chunk_size = UINT_MAX & bsize_mask;
- struct gfs2_holder gh;
next = (next + 1) << sdp->sd_sb.sb_bsize_shift;
- /* We only support the FALLOC_FL_KEEP_SIZE mode */
- if (mode & ~FALLOC_FL_KEEP_SIZE)
- return -EOPNOTSUPP;
-
offset &= bsize_mask;
len = next - offset;
@@ -829,17 +818,6 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
if (bytes == 0)
bytes = sdp->sd_sb.sb_bsize;
- error = gfs2_rs_alloc(ip);
- if (error)
- return error;
-
- mutex_lock(&inode->i_mutex);
-
- gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
- error = gfs2_glock_nq(&gh);
- if (unlikely(error))
- goto out_uninit;
-
gfs2_size_hint(file, offset, len);
while (len > 0) {
@@ -852,8 +830,7 @@ static long gfs2_fallocate(struct file *file, int mode, loff_t offset,
}
error = gfs2_quota_lock_check(ip);
if (error)
- goto out_unlock;
-
+ return error;
retry:
gfs2_write_calc_reserv(ip, bytes, &data_blocks, &ind_blocks);
@@ -895,20 +872,64 @@ retry:
gfs2_quota_unlock(ip);
}
- if (error == 0)
- error = generic_write_sync(file, pos, count);
- goto out_unlock;
+ if (!(mode & FALLOC_FL_KEEP_SIZE) && (pos + count) > inode->i_size) {
+ i_size_write(inode, pos + count);
+ /* Marks the inode as dirty */
+ file_update_time(file);
+ }
+
+ return generic_write_sync(file, pos, count);
out_trans_fail:
gfs2_inplace_release(ip);
out_qunlock:
gfs2_quota_unlock(ip);
+ return error;
+}
+
+static long gfs2_fallocate(struct file *file, int mode, loff_t offset, loff_t len)
+{
+ struct inode *inode = file_inode(file);
+ struct gfs2_inode *ip = GFS2_I(inode);
+ struct gfs2_holder gh;
+ int ret;
+
+ if (mode & ~FALLOC_FL_KEEP_SIZE)
+ return -EOPNOTSUPP;
+
+ mutex_lock(&inode->i_mutex);
+
+ gfs2_holder_init(ip->i_gl, LM_ST_EXCLUSIVE, 0, &gh);
+ ret = gfs2_glock_nq(&gh);
+ if (ret)
+ goto out_uninit;
+
+ if (!(mode & FALLOC_FL_KEEP_SIZE) &&
+ (offset + len) > inode->i_size) {
+ ret = inode_newsize_ok(inode, offset + len);
+ if (ret)
+ goto out_unlock;
+ }
+
+ ret = get_write_access(inode);
+ if (ret)
+ goto out_unlock;
+
+ ret = gfs2_rs_alloc(ip);
+ if (ret)
+ goto out_putw;
+
+ ret = __gfs2_fallocate(file, mode, offset, len);
+ if (ret)
+ gfs2_rs_deltree(ip->i_res);
+out_putw:
+ put_write_access(inode);
out_unlock:
gfs2_glock_dq(&gh);
out_uninit:
gfs2_holder_uninit(&gh);
mutex_unlock(&inode->i_mutex);
- return error;
+ return ret;
}
#ifdef CONFIG_GFS2_FS_LOCKING_DLM
diff --git a/fs/gfs2/glock.c b/fs/gfs2/glock.c
index 8f0c19d..a23524a 100644
--- a/fs/gfs2/glock.c
+++ b/fs/gfs2/glock.c
@@ -836,8 +836,7 @@ void gfs2_holder_reinit(unsigned int state, unsigned flags, struct gfs2_holder *
gh->gh_flags = flags;
gh->gh_iflags = 0;
gh->gh_ip = _RET_IP_;
- if (gh->gh_owner_pid)
- put_pid(gh->gh_owner_pid);
+ put_pid(gh->gh_owner_pid);
gh->gh_owner_pid = get_pid(task_pid(current));
}
diff --git a/fs/gfs2/glops.c b/fs/gfs2/glops.c
index 1cc0bba..fe91951 100644
--- a/fs/gfs2/glops.c
+++ b/fs/gfs2/glops.c
@@ -28,6 +28,8 @@
#include "trans.h"
#include "dir.h"
+struct workqueue_struct *gfs2_freeze_wq;
+
static void gfs2_ail_error(struct gfs2_glock *gl, const struct buffer_head *bh)
{
fs_err(gl->gl_sbd, "AIL buffer %p: blocknr %llu state 0x%08lx mapping %p page state 0x%lx\n",
@@ -94,11 +96,8 @@ static void gfs2_ail_empty_gl(struct gfs2_glock *gl)
* on the stack */
tr.tr_reserved = 1 + gfs2_struct2blk(sdp, tr.tr_revokes, sizeof(u64));
tr.tr_ip = _RET_IP_;
- sb_start_intwrite(sdp->sd_vfs);
- if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0) {
- sb_end_intwrite(sdp->sd_vfs);
+ if (gfs2_log_reserve(sdp, tr.tr_reserved) < 0)
return;
- }
WARN_ON_ONCE(current->journal_info);
current->journal_info = &tr;
@@ -469,20 +468,19 @@ static void inode_go_dump(struct seq_file *seq, const struct gfs2_glock *gl)
static void freeze_go_sync(struct gfs2_glock *gl)
{
+ int error = 0;
struct gfs2_sbd *sdp = gl->gl_sbd;
- DEFINE_WAIT(wait);
if (gl->gl_state == LM_ST_SHARED &&
test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags)) {
- atomic_set(&sdp->sd_log_freeze, 1);
- wake_up(&sdp->sd_logd_waitq);
- do {
- prepare_to_wait(&sdp->sd_log_frozen_wait, &wait,
- TASK_UNINTERRUPTIBLE);
- if (atomic_read(&sdp->sd_log_freeze))
- io_schedule();
- } while(atomic_read(&sdp->sd_log_freeze));
- finish_wait(&sdp->sd_log_frozen_wait, &wait);
+ atomic_set(&sdp->sd_freeze_state, SFS_STARTING_FREEZE);
+ error = freeze_super(sdp->sd_vfs);
+ if (error) {
+ printk(KERN_INFO "GFS2: couldn't freeze filesystem: %d\n", error);
+ gfs2_assert_withdraw(sdp, 0);
+ }
+ queue_work(gfs2_freeze_wq, &sdp->sd_freeze_work);
+ gfs2_log_flush(sdp, NULL, FREEZE_FLUSH);
}
}
diff --git a/fs/gfs2/glops.h b/fs/gfs2/glops.h
index 7455d26..8ed1857 100644
--- a/fs/gfs2/glops.h
+++ b/fs/gfs2/glops.h
@@ -12,6 +12,8 @@
#include "incore.h"
+extern struct workqueue_struct *gfs2_freeze_wq;
+
extern const struct gfs2_glock_operations gfs2_meta_glops;
extern const struct gfs2_glock_operations gfs2_inode_glops;
extern const struct gfs2_glock_operations gfs2_rgrp_glops;
diff --git a/fs/gfs2/incore.h b/fs/gfs2/incore.h
index 39e7e99..7a2dbbc 100644
--- a/fs/gfs2/incore.h
+++ b/fs/gfs2/incore.h
@@ -97,6 +97,7 @@ struct gfs2_rgrpd {
#define GFS2_RDF_CHECK 0x10000000 /* check for unlinked inodes */
#define GFS2_RDF_UPTODATE 0x20000000 /* rg is up to date */
#define GFS2_RDF_ERROR 0x40000000 /* error in rg */
+#define GFS2_RDF_PREFERRED 0x80000000 /* This rgrp is preferred */
#define GFS2_RDF_MASK 0xf0000000 /* mask for internal flags */
spinlock_t rd_rsspin; /* protects reservation related vars */
struct rb_root rd_rstree; /* multi-block reservation tree */
@@ -587,6 +588,12 @@ enum {
SDF_SKIP_DLM_UNLOCK = 8,
};
+enum gfs2_freeze_state {
+ SFS_UNFROZEN = 0,
+ SFS_STARTING_FREEZE = 1,
+ SFS_FROZEN = 2,
+};
+
#define GFS2_FSNAME_LEN 256
struct gfs2_inum_host {
@@ -684,6 +691,7 @@ struct gfs2_sbd {
struct gfs2_holder sd_live_gh;
struct gfs2_glock *sd_rename_gl;
struct gfs2_glock *sd_freeze_gl;
+ struct work_struct sd_freeze_work;
wait_queue_head_t sd_glock_wait;
atomic_t sd_glock_disposal;
struct completion sd_locking_init;
@@ -788,6 +796,9 @@ struct gfs2_sbd {
wait_queue_head_t sd_log_flush_wait;
int sd_log_error;
+ atomic_t sd_reserving_log;
+ wait_queue_head_t sd_reserving_log_wait;
+
unsigned int sd_log_flush_head;
u64 sd_log_flush_wrapped;
@@ -797,12 +808,8 @@ struct gfs2_sbd {
/* For quiescing the filesystem */
struct gfs2_holder sd_freeze_gh;
- struct gfs2_holder sd_freeze_root_gh;
- struct gfs2_holder sd_thaw_gh;
- atomic_t sd_log_freeze;
- atomic_t sd_frozen_root;
- wait_queue_head_t sd_frozen_root_wait;
- wait_queue_head_t sd_log_frozen_wait;
+ atomic_t sd_freeze_state;
+ struct mutex sd_freeze_mutex;
char sd_fsname[GFS2_FSNAME_LEN];
char sd_table_name[GFS2_FSNAME_LEN];
diff --git a/fs/gfs2/inode.c b/fs/gfs2/inode.c
index c4ed823..9054002 100644
--- a/fs/gfs2/inode.c
+++ b/fs/gfs2/inode.c
@@ -596,7 +596,6 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
struct gfs2_inode *dip = GFS2_I(dir), *ip;
struct gfs2_sbd *sdp = GFS2_SB(&dip->i_inode);
struct gfs2_glock *io_gl;
- struct dentry *d;
int error, free_vfs_inode = 0;
u32 aflags = 0;
unsigned blocks = 1;
@@ -624,22 +623,18 @@ static int gfs2_create_inode(struct inode *dir, struct dentry *dentry,
inode = gfs2_dir_search(dir, &dentry->d_name, !S_ISREG(mode) || excl);
error = PTR_ERR(inode);
if (!IS_ERR(inode)) {
- d = d_splice_alias(inode, dentry);
- error = PTR_ERR(d);
- if (IS_ERR(d)) {
- inode = ERR_CAST(d);
+ if (S_ISDIR(inode->i_mode)) {
+ iput(inode);
+ inode = ERR_PTR(-EISDIR);
goto fail_gunlock;
}
+ d_instantiate(dentry, inode);
error = 0;
if (file) {
- if (S_ISREG(inode->i_mode)) {
- WARN_ON(d != NULL);
+ if (S_ISREG(inode->i_mode))
error = finish_open(file, dentry, gfs2_open_common, opened);
- } else {
- error = finish_no_open(file, d);
- }
- } else {
- dput(d);
+ else
+ error = finish_no_open(file, NULL);
}
gfs2_glock_dq_uninit(ghs);
return error;
@@ -1045,11 +1040,7 @@ static int gfs2_unlink_ok(struct gfs2_inode *dip, const struct qstr *name,
if (error)
return error;
- error = gfs2_dir_check(&dip->i_inode, name, ip);
- if (error)
- return error;
-
- return 0;
+ return gfs2_dir_check(&dip->i_inode, name, ip);
}
/**
@@ -1254,11 +1245,8 @@ static int gfs2_atomic_open(struct inode *dir, struct dentry *dentry,
if (d != NULL)
dentry = d;
if (dentry->d_inode) {
- if (!(*opened & FILE_OPENED)) {
- if (d == NULL)
- dget(dentry);
- return finish_no_open(file, dentry);
- }
+ if (!(*opened & FILE_OPENED))
+ return finish_no_open(file, d);
dput(d);
return 0;
}
@@ -1622,26 +1610,18 @@ int gfs2_permission(struct inode *inode, int mask)
{
struct gfs2_inode *ip;
struct gfs2_holder i_gh;
- struct gfs2_sbd *sdp = GFS2_SB(inode);
int error;
int unlock = 0;
- int frozen_root = 0;
ip = GFS2_I(inode);
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
- if (unlikely(gfs2_glock_is_held_excl(sdp->sd_freeze_gl) &&
- inode == sdp->sd_root_dir->d_inode &&
- atomic_inc_not_zero(&sdp->sd_frozen_root)))
- frozen_root = 1;
- else {
- if (mask & MAY_NOT_BLOCK)
- return -ECHILD;
- error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
- if (error)
- return error;
- unlock = 1;
- }
+ if (mask & MAY_NOT_BLOCK)
+ return -ECHILD;
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &i_gh);
+ if (error)
+ return error;
+ unlock = 1;
}
if ((mask & MAY_WRITE) && IS_IMMUTABLE(inode))
@@ -1650,8 +1630,6 @@ int gfs2_permission(struct inode *inode, int mask)
error = generic_permission(inode, mask);
if (unlock)
gfs2_glock_dq_uninit(&i_gh);
- else if (frozen_root && atomic_dec_and_test(&sdp->sd_frozen_root))
- wake_up(&sdp->sd_frozen_root_wait);
return error;
}
@@ -1824,29 +1802,19 @@ static int gfs2_getattr(struct vfsmount *mnt, struct dentry *dentry,
struct inode *inode = dentry->d_inode;
struct gfs2_inode *ip = GFS2_I(inode);
struct gfs2_holder gh;
- struct gfs2_sbd *sdp = GFS2_SB(inode);
int error;
int unlock = 0;
- int frozen_root = 0;
if (gfs2_glock_is_locked_by_me(ip->i_gl) == NULL) {
- if (unlikely(gfs2_glock_is_held_excl(sdp->sd_freeze_gl) &&
- inode == sdp->sd_root_dir->d_inode &&
- atomic_inc_not_zero(&sdp->sd_frozen_root)))
- frozen_root = 1;
- else {
- error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
- if (error)
- return error;
- unlock = 1;
- }
+ error = gfs2_glock_nq_init(ip->i_gl, LM_ST_SHARED, LM_FLAG_ANY, &gh);
+ if (error)
+ return error;
+ unlock = 1;
}
generic_fillattr(inode, stat);
if (unlock)
gfs2_glock_dq_uninit(&gh);
- else if (frozen_root && atomic_dec_and_test(&sdp->sd_frozen_root))
- wake_up(&sdp->sd_frozen_root_wait);
return 0;
}
diff --git a/fs/gfs2/log.c b/fs/gfs2/log.c
index 3966fad..536e7a6 100644
--- a/fs/gfs2/log.c
+++ b/fs/gfs2/log.c
@@ -339,6 +339,7 @@ void gfs2_log_release(struct gfs2_sbd *sdp, unsigned int blks)
int gfs2_log_reserve(struct gfs2_sbd *sdp, unsigned int blks)
{
+ int ret = 0;
unsigned reserved_blks = 7 * (4096 / sdp->sd_vfs->s_blocksize);
unsigned wanted = blks + reserved_blks;
DEFINE_WAIT(wait);
@@ -362,9 +363,13 @@ retry:
} while(free_blocks <= wanted);
finish_wait(&sdp->sd_log_waitq, &wait);
}
+ atomic_inc(&sdp->sd_reserving_log);
if (atomic_cmpxchg(&sdp->sd_log_blks_free, free_blocks,
- free_blocks - blks) != free_blocks)
+ free_blocks - blks) != free_blocks) {
+ if (atomic_dec_and_test(&sdp->sd_reserving_log))
+ wake_up(&sdp->sd_reserving_log_wait);
goto retry;
+ }
trace_gfs2_log_blocks(sdp, -blks);
/*
@@ -377,9 +382,11 @@ retry:
down_read(&sdp->sd_log_flush_lock);
if (unlikely(!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))) {
gfs2_log_release(sdp, blks);
- return -EROFS;
+ ret = -EROFS;
}
- return 0;
+ if (atomic_dec_and_test(&sdp->sd_reserving_log))
+ wake_up(&sdp->sd_reserving_log_wait);
+ return ret;
}
/**
@@ -652,9 +659,12 @@ static void log_write_header(struct gfs2_sbd *sdp, u32 flags)
u32 hash;
int rw = WRITE_FLUSH_FUA | REQ_META;
struct page *page = mempool_alloc(gfs2_page_pool, GFP_NOIO);
+ enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
lh = page_address(page);
clear_page(lh);
+ gfs2_assert_withdraw(sdp, (state != SFS_FROZEN));
+
tail = current_tail(sdp);
lh->lh_header.mh_magic = cpu_to_be32(GFS2_MAGIC);
@@ -695,6 +705,7 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
enum gfs2_flush_type type)
{
struct gfs2_trans *tr;
+ enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
down_write(&sdp->sd_log_flush_lock);
@@ -713,8 +724,12 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
INIT_LIST_HEAD(&tr->tr_ail1_list);
INIT_LIST_HEAD(&tr->tr_ail2_list);
tr->tr_first = sdp->sd_log_flush_head;
+ if (unlikely (state == SFS_FROZEN))
+ gfs2_assert_withdraw(sdp, !tr->tr_num_buf_new && !tr->tr_num_databuf_new);
}
+ if (unlikely(state == SFS_FROZEN))
+ gfs2_assert_withdraw(sdp, !sdp->sd_log_num_revoke);
gfs2_assert_withdraw(sdp,
sdp->sd_log_num_revoke == sdp->sd_log_commited_revoke);
@@ -745,8 +760,6 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
spin_unlock(&sdp->sd_ail_lock);
gfs2_log_unlock(sdp);
- if (atomic_read(&sdp->sd_log_freeze))
- type = FREEZE_FLUSH;
if (type != NORMAL_FLUSH) {
if (!sdp->sd_log_idle) {
for (;;) {
@@ -763,21 +776,8 @@ void gfs2_log_flush(struct gfs2_sbd *sdp, struct gfs2_glock *gl,
}
if (type == SHUTDOWN_FLUSH || type == FREEZE_FLUSH)
gfs2_log_shutdown(sdp);
- if (type == FREEZE_FLUSH) {
- int error;
-
- atomic_set(&sdp->sd_log_freeze, 0);
- wake_up(&sdp->sd_log_frozen_wait);
- error = gfs2_glock_nq_init(sdp->sd_freeze_gl,
- LM_ST_SHARED, 0,
- &sdp->sd_thaw_gh);
- if (error) {
- printk(KERN_INFO "GFS2: couln't get freeze lock : %d\n", error);
- gfs2_assert_withdraw(sdp, 0);
- }
- else
- gfs2_glock_dq_uninit(&sdp->sd_thaw_gh);
- }
+ if (type == FREEZE_FLUSH)
+ atomic_set(&sdp->sd_freeze_state, SFS_FROZEN);
}
trace_gfs2_log_flush(sdp, 0);
@@ -888,7 +888,7 @@ void gfs2_log_shutdown(struct gfs2_sbd *sdp)
static inline int gfs2_jrnl_flush_reqd(struct gfs2_sbd *sdp)
{
- return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1) || atomic_read(&sdp->sd_log_freeze));
+ return (atomic_read(&sdp->sd_log_pinned) >= atomic_read(&sdp->sd_log_thresh1));
}
static inline int gfs2_ail_flush_reqd(struct gfs2_sbd *sdp)
diff --git a/fs/gfs2/main.c b/fs/gfs2/main.c
index 82b6ac8..241a399 100644
--- a/fs/gfs2/main.c
+++ b/fs/gfs2/main.c
@@ -30,6 +30,7 @@
#include "quota.h"
#include "recovery.h"
#include "dir.h"
+#include "glops.h"
struct workqueue_struct *gfs2_control_wq;
@@ -161,9 +162,14 @@ static int __init init_gfs2_fs(void)
if (!gfs2_control_wq)
goto fail_recovery;
+ gfs2_freeze_wq = alloc_workqueue("freeze_workqueue", 0, 0);
+
+ if (!gfs2_freeze_wq)
+ goto fail_control;
+
gfs2_page_pool = mempool_create_page_pool(64, 0);
if (!gfs2_page_pool)
- goto fail_control;
+ goto fail_freeze;
gfs2_register_debugfs();
@@ -171,6 +177,8 @@ static int __init init_gfs2_fs(void)
return 0;
+fail_freeze:
+ destroy_workqueue(gfs2_freeze_wq);
fail_control:
destroy_workqueue(gfs2_control_wq);
fail_recovery:
@@ -224,6 +232,7 @@ static void __exit exit_gfs2_fs(void)
unregister_filesystem(&gfs2meta_fs_type);
destroy_workqueue(gfs_recovery_wq);
destroy_workqueue(gfs2_control_wq);
+ destroy_workqueue(gfs2_freeze_wq);
list_lru_destroy(&gfs2_qd_lru);
rcu_barrier();
diff --git a/fs/gfs2/ops_fstype.c b/fs/gfs2/ops_fstype.c
index d3eae24..8633ad3 100644
--- a/fs/gfs2/ops_fstype.c
+++ b/fs/gfs2/ops_fstype.c
@@ -129,11 +129,11 @@ static struct gfs2_sbd *init_sbd(struct super_block *sb)
init_rwsem(&sdp->sd_log_flush_lock);
atomic_set(&sdp->sd_log_in_flight, 0);
+ atomic_set(&sdp->sd_reserving_log, 0);
+ init_waitqueue_head(&sdp->sd_reserving_log_wait);
init_waitqueue_head(&sdp->sd_log_flush_wait);
- init_waitqueue_head(&sdp->sd_log_frozen_wait);
- atomic_set(&sdp->sd_log_freeze, 0);
- atomic_set(&sdp->sd_frozen_root, 0);
- init_waitqueue_head(&sdp->sd_frozen_root_wait);
+ atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
+ mutex_init(&sdp->sd_freeze_mutex);
return sdp;
}
@@ -760,15 +760,7 @@ static int init_journal(struct gfs2_sbd *sdp, int undo)
set_bit(SDF_JOURNAL_CHECKED, &sdp->sd_flags);
gfs2_glock_dq_uninit(&ji_gh);
jindex = 0;
- if (!sdp->sd_args.ar_spectator) {
- error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
- &sdp->sd_thaw_gh);
- if (error) {
- fs_err(sdp, "can't acquire freeze glock: %d\n", error);
- goto fail_jinode_gh;
- }
- }
- gfs2_glock_dq_uninit(&sdp->sd_thaw_gh);
+ INIT_WORK(&sdp->sd_freeze_work, gfs2_freeze_func);
return 0;
fail_jinode_gh:
@@ -1082,6 +1074,7 @@ static int fill_super(struct super_block *sb, struct gfs2_args *args, int silent
sb->s_export_op = &gfs2_export_ops;
sb->s_xattr = gfs2_xattr_handlers;
sb->s_qcop = &gfs2_quotactl_ops;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
sb_dqopt(sb)->flags |= DQUOT_QUOTA_SYS_FILE;
sb->s_time_gran = 1;
sb->s_maxbytes = MAX_LFS_FILESIZE;
diff --git a/fs/gfs2/quota.c b/fs/gfs2/quota.c
index 64b29f7..c8b148b 100644
--- a/fs/gfs2/quota.c
+++ b/fs/gfs2/quota.c
@@ -1360,13 +1360,8 @@ void gfs2_quota_cleanup(struct gfs2_sbd *sdp)
gfs2_assert_warn(sdp, !atomic_read(&sdp->sd_quota_count));
- if (sdp->sd_quota_bitmap) {
- if (is_vmalloc_addr(sdp->sd_quota_bitmap))
- vfree(sdp->sd_quota_bitmap);
- else
- kfree(sdp->sd_quota_bitmap);
- sdp->sd_quota_bitmap = NULL;
- }
+ kvfree(sdp->sd_quota_bitmap);
+ sdp->sd_quota_bitmap = NULL;
}
static void quotad_error(struct gfs2_sbd *sdp, const char *msg, int error)
diff --git a/fs/gfs2/rgrp.c b/fs/gfs2/rgrp.c
index 7474c41..9150207 100644
--- a/fs/gfs2/rgrp.c
+++ b/fs/gfs2/rgrp.c
@@ -936,7 +936,7 @@ static int read_rindex_entry(struct gfs2_inode *ip)
rgd->rd_gl->gl_vm.start = rgd->rd_addr * bsize;
rgd->rd_gl->gl_vm.end = rgd->rd_gl->gl_vm.start + (rgd->rd_length * bsize) - 1;
rgd->rd_rgl = (struct gfs2_rgrp_lvb *)rgd->rd_gl->gl_lksb.sb_lvbptr;
- rgd->rd_flags &= ~GFS2_RDF_UPTODATE;
+ rgd->rd_flags &= ~(GFS2_RDF_UPTODATE | GFS2_RDF_PREFERRED);
if (rgd->rd_data > sdp->sd_max_rg_data)
sdp->sd_max_rg_data = rgd->rd_data;
spin_lock(&sdp->sd_rindex_spin);
@@ -955,6 +955,36 @@ fail:
}
/**
+ * set_rgrp_preferences - Run all the rgrps, selecting some we prefer to use
+ * @sdp: the GFS2 superblock
+ *
+ * The purpose of this function is to select a subset of the resource groups
+ * and mark them as PREFERRED. We do it in such a way that each node prefers
+ * to use a unique set of rgrps to minimize glock contention.
+ */
+static void set_rgrp_preferences(struct gfs2_sbd *sdp)
+{
+ struct gfs2_rgrpd *rgd, *first;
+ int i;
+
+ /* Skip an initial number of rgrps, based on this node's journal ID.
+ That should start each node out on its own set. */
+ rgd = gfs2_rgrpd_get_first(sdp);
+ for (i = 0; i < sdp->sd_lockstruct.ls_jid; i++)
+ rgd = gfs2_rgrpd_get_next(rgd);
+ first = rgd;
+
+ do {
+ rgd->rd_flags |= GFS2_RDF_PREFERRED;
+ for (i = 0; i < sdp->sd_journals; i++) {
+ rgd = gfs2_rgrpd_get_next(rgd);
+ if (rgd == first)
+ break;
+ }
+ } while (rgd != first);
+}
+
+/**
* gfs2_ri_update - Pull in a new resource index from the disk
* @ip: pointer to the rindex inode
*
@@ -973,6 +1003,8 @@ static int gfs2_ri_update(struct gfs2_inode *ip)
if (error < 0)
return error;
+ set_rgrp_preferences(sdp);
+
sdp->sd_rindex_uptodate = 1;
return 0;
}
@@ -1891,6 +1923,25 @@ static bool gfs2_select_rgrp(struct gfs2_rgrpd **pos, const struct gfs2_rgrpd *b
}
/**
+ * fast_to_acquire - determine if a resource group will be fast to acquire
+ *
+ * If this is one of our preferred rgrps, it should be quicker to acquire,
+ * because we tried to set ourselves up as dlm lock master.
+ */
+static inline int fast_to_acquire(struct gfs2_rgrpd *rgd)
+{
+ struct gfs2_glock *gl = rgd->rd_gl;
+
+ if (gl->gl_state != LM_ST_UNLOCKED && list_empty(&gl->gl_holders) &&
+ !test_bit(GLF_DEMOTE_IN_PROGRESS, &gl->gl_flags) &&
+ !test_bit(GLF_DEMOTE, &gl->gl_flags))
+ return 1;
+ if (rgd->rd_flags & GFS2_RDF_PREFERRED)
+ return 1;
+ return 0;
+}
+
+/**
* gfs2_inplace_reserve - Reserve space in the filesystem
* @ip: the inode to reserve space for
* @ap: the allocation parameters
@@ -1932,10 +1983,15 @@ int gfs2_inplace_reserve(struct gfs2_inode *ip, const struct gfs2_alloc_parms *a
rg_locked = 0;
if (skip && skip--)
goto next_rgrp;
- if (!gfs2_rs_active(rs) && (loops < 2) &&
- gfs2_rgrp_used_recently(rs, 1000) &&
- gfs2_rgrp_congested(rs->rs_rbm.rgd, loops))
- goto next_rgrp;
+ if (!gfs2_rs_active(rs)) {
+ if (loops == 0 &&
+ !fast_to_acquire(rs->rs_rbm.rgd))
+ goto next_rgrp;
+ if ((loops < 2) &&
+ gfs2_rgrp_used_recently(rs, 1000) &&
+ gfs2_rgrp_congested(rs->rs_rbm.rgd, loops))
+ goto next_rgrp;
+ }
error = gfs2_glock_nq_init(rs->rs_rbm.rgd->rd_gl,
LM_ST_EXCLUSIVE, flags,
&rs->rs_rgd_gh);
@@ -2195,6 +2251,9 @@ static void gfs2_adjust_reservation(struct gfs2_inode *ip,
trace_gfs2_rs(rs, TRACE_RS_CLAIM);
if (rs->rs_free && !ret)
goto out;
+ /* We used up our block reservation, so we should
+ reserve more blocks next time. */
+ atomic_add(RGRP_RSRV_ADDBLKS, &rs->rs_sizehint);
}
__rs_deltree(rs);
}
diff --git a/fs/gfs2/rgrp.h b/fs/gfs2/rgrp.h
index 5d8f085..b104f4a 100644
--- a/fs/gfs2/rgrp.h
+++ b/fs/gfs2/rgrp.h
@@ -20,6 +20,7 @@
*/
#define RGRP_RSRV_MINBYTES 8
#define RGRP_RSRV_MINBLKS ((u32)(RGRP_RSRV_MINBYTES * GFS2_NBBY))
+#define RGRP_RSRV_ADDBLKS 64
struct gfs2_rgrpd;
struct gfs2_sbd;
diff --git a/fs/gfs2/super.c b/fs/gfs2/super.c
index a346f56..5b327f8 100644
--- a/fs/gfs2/super.c
+++ b/fs/gfs2/super.c
@@ -26,6 +26,7 @@
#include <linux/wait.h>
#include <linux/writeback.h>
#include <linux/backing-dev.h>
+#include <linux/kernel.h>
#include "gfs2.h"
#include "incore.h"
@@ -399,7 +400,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
{
struct gfs2_inode *ip = GFS2_I(sdp->sd_jdesc->jd_inode);
struct gfs2_glock *j_gl = ip->i_gl;
- struct gfs2_holder thaw_gh;
+ struct gfs2_holder freeze_gh;
struct gfs2_log_header_host head;
int error;
@@ -408,7 +409,7 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
return error;
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
- &thaw_gh);
+ &freeze_gh);
if (error)
goto fail_threads;
@@ -434,13 +435,13 @@ int gfs2_make_fs_rw(struct gfs2_sbd *sdp)
set_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
- gfs2_glock_dq_uninit(&thaw_gh);
+ gfs2_glock_dq_uninit(&freeze_gh);
return 0;
fail:
- thaw_gh.gh_flags |= GL_NOCACHE;
- gfs2_glock_dq_uninit(&thaw_gh);
+ freeze_gh.gh_flags |= GL_NOCACHE;
+ gfs2_glock_dq_uninit(&freeze_gh);
fail_threads:
kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process);
@@ -580,14 +581,15 @@ int gfs2_statfs_sync(struct super_block *sb, int type)
struct buffer_head *m_bh, *l_bh;
int error;
+ sb_start_write(sb);
error = gfs2_glock_nq_init(m_ip->i_gl, LM_ST_EXCLUSIVE, GL_NOCACHE,
&gh);
if (error)
- return error;
+ goto out;
error = gfs2_meta_inode_buffer(m_ip, &m_bh);
if (error)
- goto out;
+ goto out_unlock;
spin_lock(&sdp->sd_statfs_spin);
gfs2_statfs_change_in(m_sc, m_bh->b_data +
@@ -615,8 +617,10 @@ out_bh2:
brelse(l_bh);
out_bh:
brelse(m_bh);
-out:
+out_unlock:
gfs2_glock_dq_uninit(&gh);
+out:
+ sb_end_write(sb);
return error;
}
@@ -643,14 +647,8 @@ static int gfs2_lock_fs_check_clean(struct gfs2_sbd *sdp,
struct lfcc *lfcc;
LIST_HEAD(list);
struct gfs2_log_header_host lh;
- struct gfs2_inode *dip = GFS2_I(sdp->sd_root_dir->d_inode);
int error;
- error = gfs2_glock_nq_init(dip->i_gl, LM_ST_SHARED, 0,
- &sdp->sd_freeze_root_gh);
- if (error)
- return error;
- atomic_set(&sdp->sd_frozen_root, 1);
list_for_each_entry(jd, &sdp->sd_jindex_list, jd_list) {
lfcc = kmalloc(sizeof(struct lfcc), GFP_KERNEL);
if (!lfcc) {
@@ -692,11 +690,6 @@ out:
gfs2_glock_dq_uninit(&lfcc->gh);
kfree(lfcc);
}
- if (error) {
- atomic_dec(&sdp->sd_frozen_root);
- wait_event(sdp->sd_frozen_root_wait, atomic_read(&sdp->sd_frozen_root) == 0);
- gfs2_glock_dq_uninit(&sdp->sd_freeze_root_gh);
- }
return error;
}
@@ -834,18 +827,14 @@ out:
static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
{
- struct gfs2_holder thaw_gh;
+ struct gfs2_holder freeze_gh;
int error;
error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, GL_NOCACHE,
- &thaw_gh);
+ &freeze_gh);
if (error && !test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
return error;
- down_write(&sdp->sd_log_flush_lock);
- clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
- up_write(&sdp->sd_log_flush_lock);
-
kthread_stop(sdp->sd_quotad_process);
kthread_stop(sdp->sd_logd_process);
@@ -853,11 +842,16 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
gfs2_quota_sync(sdp->sd_vfs, 0);
gfs2_statfs_sync(sdp->sd_vfs, 0);
+ down_write(&sdp->sd_log_flush_lock);
+ clear_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags);
+ up_write(&sdp->sd_log_flush_lock);
+
gfs2_log_flush(sdp, NULL, SHUTDOWN_FLUSH);
+ wait_event(sdp->sd_reserving_log_wait, atomic_read(&sdp->sd_reserving_log) == 0);
gfs2_assert_warn(sdp, atomic_read(&sdp->sd_log_blks_free) == sdp->sd_jdesc->jd_blocks);
- if (thaw_gh.gh_gl)
- gfs2_glock_dq_uninit(&thaw_gh);
+ if (freeze_gh.gh_gl)
+ gfs2_glock_dq_uninit(&freeze_gh);
gfs2_quota_cleanup(sdp);
@@ -943,11 +937,41 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
struct gfs2_sbd *sdp = sb->s_fs_info;
gfs2_quota_sync(sb, -1);
- if (wait && sdp && !atomic_read(&sdp->sd_log_freeze))
+ if (wait && sdp)
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
return 0;
}
+void gfs2_freeze_func(struct work_struct *work)
+{
+ int error;
+ struct gfs2_holder freeze_gh;
+ struct gfs2_sbd *sdp = container_of(work, struct gfs2_sbd, sd_freeze_work);
+ struct super_block *sb = sdp->sd_vfs;
+
+ atomic_inc(&sb->s_active);
+ error = gfs2_glock_nq_init(sdp->sd_freeze_gl, LM_ST_SHARED, 0,
+ &freeze_gh);
+ if (error) {
+ printk(KERN_INFO "GFS2: couln't get freeze lock : %d\n", error);
+ gfs2_assert_withdraw(sdp, 0);
+ }
+ else {
+ atomic_set(&sdp->sd_freeze_state, SFS_UNFROZEN);
+ error = thaw_super(sb);
+ if (error) {
+ printk(KERN_INFO "GFS2: couldn't thaw filesystem: %d\n",
+ error);
+ gfs2_assert_withdraw(sdp, 0);
+ }
+ if (!test_bit(SDF_JOURNAL_LIVE, &sdp->sd_flags))
+ freeze_gh.gh_flags |= GL_NOCACHE;
+ gfs2_glock_dq_uninit(&freeze_gh);
+ }
+ deactivate_super(sb);
+ return;
+}
+
/**
* gfs2_freeze - prevent further writes to the filesystem
* @sb: the VFS structure for the filesystem
@@ -957,10 +981,16 @@ static int gfs2_sync_fs(struct super_block *sb, int wait)
static int gfs2_freeze(struct super_block *sb)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
- int error;
+ int error = 0;
- if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags))
- return -EINVAL;
+ mutex_lock(&sdp->sd_freeze_mutex);
+ if (atomic_read(&sdp->sd_freeze_state) != SFS_UNFROZEN)
+ goto out;
+
+ if (test_bit(SDF_SHUTDOWN, &sdp->sd_flags)) {
+ error = -EINVAL;
+ goto out;
+ }
for (;;) {
error = gfs2_lock_fs_check_clean(sdp, &sdp->sd_freeze_gh);
@@ -980,7 +1010,10 @@ static int gfs2_freeze(struct super_block *sb)
fs_err(sdp, "retrying...\n");
msleep(1000);
}
- return 0;
+ error = 0;
+out:
+ mutex_unlock(&sdp->sd_freeze_mutex);
+ return error;
}
/**
@@ -993,10 +1026,15 @@ static int gfs2_unfreeze(struct super_block *sb)
{
struct gfs2_sbd *sdp = sb->s_fs_info;
+ mutex_lock(&sdp->sd_freeze_mutex);
+ if (atomic_read(&sdp->sd_freeze_state) != SFS_FROZEN ||
+ sdp->sd_freeze_gh.gh_gl == NULL) {
+ mutex_unlock(&sdp->sd_freeze_mutex);
+ return 0;
+ }
+
gfs2_glock_dq_uninit(&sdp->sd_freeze_gh);
- atomic_dec(&sdp->sd_frozen_root);
- wait_event(sdp->sd_frozen_root_wait, atomic_read(&sdp->sd_frozen_root) == 0);
- gfs2_glock_dq_uninit(&sdp->sd_freeze_root_gh);
+ mutex_unlock(&sdp->sd_freeze_mutex);
return 0;
}
@@ -1618,8 +1656,8 @@ const struct super_operations gfs2_super_ops = {
.evict_inode = gfs2_evict_inode,
.put_super = gfs2_put_super,
.sync_fs = gfs2_sync_fs,
- .freeze_fs = gfs2_freeze,
- .unfreeze_fs = gfs2_unfreeze,
+ .freeze_super = gfs2_freeze,
+ .thaw_super = gfs2_unfreeze,
.statfs = gfs2_statfs,
.remount_fs = gfs2_remount_fs,
.drop_inode = gfs2_drop_inode,
diff --git a/fs/gfs2/super.h b/fs/gfs2/super.h
index 90e3322..73c97dc 100644
--- a/fs/gfs2/super.h
+++ b/fs/gfs2/super.h
@@ -45,6 +45,7 @@ extern void gfs2_statfs_change_in(struct gfs2_statfs_change_host *sc,
extern void update_statfs(struct gfs2_sbd *sdp, struct buffer_head *m_bh,
struct buffer_head *l_bh);
extern int gfs2_statfs_sync(struct super_block *sb, int type);
+extern void gfs2_freeze_func(struct work_struct *work);
extern struct file_system_type gfs2_fs_type;
extern struct file_system_type gfs2meta_fs_type;
diff --git a/fs/gfs2/trans.c b/fs/gfs2/trans.c
index 42bfd336..88bff24 100644
--- a/fs/gfs2/trans.c
+++ b/fs/gfs2/trans.c
@@ -89,14 +89,17 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
{
struct gfs2_trans *tr = current->journal_info;
s64 nbuf;
+ int alloced = tr->tr_alloced;
+
BUG_ON(!tr);
current->journal_info = NULL;
if (!tr->tr_touched) {
gfs2_log_release(sdp, tr->tr_reserved);
- if (tr->tr_alloced)
+ if (alloced) {
kfree(tr);
- sb_end_intwrite(sdp->sd_vfs);
+ sb_end_intwrite(sdp->sd_vfs);
+ }
return;
}
@@ -109,13 +112,14 @@ void gfs2_trans_end(struct gfs2_sbd *sdp)
gfs2_print_trans(tr);
gfs2_log_commit(sdp, tr);
- if (tr->tr_alloced && !tr->tr_attached)
+ if (alloced && !tr->tr_attached)
kfree(tr);
up_read(&sdp->sd_log_flush_lock);
if (sdp->sd_vfs->s_flags & MS_SYNCHRONOUS)
gfs2_log_flush(sdp, NULL, NORMAL_FLUSH);
- sb_end_intwrite(sdp->sd_vfs);
+ if (alloced)
+ sb_end_intwrite(sdp->sd_vfs);
}
static struct gfs2_bufdata *gfs2_alloc_bufdata(struct gfs2_glock *gl,
@@ -192,6 +196,7 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
{
struct gfs2_meta_header *mh;
struct gfs2_trans *tr;
+ enum gfs2_freeze_state state = atomic_read(&sdp->sd_freeze_state);
tr = current->journal_info;
tr->tr_touched = 1;
@@ -205,6 +210,10 @@ static void meta_lo_add(struct gfs2_sbd *sdp, struct gfs2_bufdata *bd)
(unsigned long long)bd->bd_bh->b_blocknr);
BUG();
}
+ if (unlikely(state == SFS_FROZEN)) {
+ printk(KERN_INFO "GFS2:adding buf while frozen\n");
+ gfs2_assert_withdraw(sdp, 0);
+ }
gfs2_pin(sdp, bd->bd_bh);
mh->__pad0 = cpu_to_be64(0);
mh->mh_jid = cpu_to_be32(sdp->sd_jdesc->jd_jid);
diff --git a/fs/hfs/catalog.c b/fs/hfs/catalog.c
index ff0316b..db458ee 100644
--- a/fs/hfs/catalog.c
+++ b/fs/hfs/catalog.c
@@ -162,14 +162,16 @@ err2:
*/
int hfs_cat_keycmp(const btree_key *key1, const btree_key *key2)
{
- int retval;
+ __be32 k1p, k2p;
- retval = be32_to_cpu(key1->cat.ParID) - be32_to_cpu(key2->cat.ParID);
- if (!retval)
- retval = hfs_strcmp(key1->cat.CName.name, key1->cat.CName.len,
- key2->cat.CName.name, key2->cat.CName.len);
+ k1p = key1->cat.ParID;
+ k2p = key2->cat.ParID;
- return retval;
+ if (k1p != k2p)
+ return be32_to_cpu(k1p) < be32_to_cpu(k2p) ? -1 : 1;
+
+ return hfs_strcmp(key1->cat.CName.name, key1->cat.CName.len,
+ key2->cat.CName.name, key2->cat.CName.len);
}
/* Try to get a catalog entry for given catalog id */
diff --git a/fs/hppfs/hppfs.c b/fs/hppfs/hppfs.c
index 4338ff3..5f27551 100644
--- a/fs/hppfs/hppfs.c
+++ b/fs/hppfs/hppfs.c
@@ -548,10 +548,11 @@ struct hppfs_dirent {
struct dentry *dentry;
};
-static int hppfs_filldir(void *d, const char *name, int size,
+static int hppfs_filldir(struct dir_context *ctx, const char *name, int size,
loff_t offset, u64 inode, unsigned int type)
{
- struct hppfs_dirent *dirent = d;
+ struct hppfs_dirent *dirent =
+ container_of(ctx, struct hppfs_dirent, ctx);
if (file_removed(dirent->dentry, name))
return 0;
diff --git a/fs/inode.c b/fs/inode.c
index 26753ba..2ed95f7 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -143,9 +143,6 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
inode->i_blocks = 0;
inode->i_bytes = 0;
inode->i_generation = 0;
-#ifdef CONFIG_QUOTA
- memset(&inode->i_dquot, 0, sizeof(inode->i_dquot));
-#endif
inode->i_pipe = NULL;
inode->i_bdev = NULL;
inode->i_cdev = NULL;
diff --git a/fs/ioctl.c b/fs/ioctl.c
index 8ac3fad..77c9a78 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -518,10 +518,12 @@ static int ioctl_fsfreeze(struct file *filp)
return -EPERM;
/* If filesystem doesn't support freeze feature, return. */
- if (sb->s_op->freeze_fs == NULL)
+ if (sb->s_op->freeze_fs == NULL && sb->s_op->freeze_super == NULL)
return -EOPNOTSUPP;
/* Freeze */
+ if (sb->s_op->freeze_super)
+ return sb->s_op->freeze_super(sb);
return freeze_super(sb);
}
@@ -533,6 +535,8 @@ static int ioctl_fsthaw(struct file *filp)
return -EPERM;
/* Thaw */
+ if (sb->s_op->thaw_super)
+ return sb->s_op->thaw_super(sb);
return thaw_super(sb);
}
diff --git a/fs/jbd/journal.c b/fs/jbd/journal.c
index aab8549..c46a79a 100644
--- a/fs/jbd/journal.c
+++ b/fs/jbd/journal.c
@@ -1373,8 +1373,7 @@ int journal_destroy(journal_t *journal)
}
mutex_unlock(&journal->j_checkpoint_mutex);
- if (journal->j_inode)
- iput(journal->j_inode);
+ iput(journal->j_inode);
if (journal->j_revoke)
journal_destroy_revoke(journal);
kfree(journal->j_wbuf);
diff --git a/fs/jfs/jfs_incore.h b/fs/jfs/jfs_incore.h
index cf47f09..fa7e795 100644
--- a/fs/jfs/jfs_incore.h
+++ b/fs/jfs/jfs_incore.h
@@ -94,6 +94,9 @@ struct jfs_inode_info {
unchar _inline_ea[128]; /* 128: inline extended attr */
} link;
} u;
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+#endif
u32 dev; /* will die when we get wide dev_t */
struct inode vfs_inode;
};
diff --git a/fs/jfs/namei.c b/fs/jfs/namei.c
index d59c7de..38fdc53 100644
--- a/fs/jfs/namei.c
+++ b/fs/jfs/namei.c
@@ -84,7 +84,7 @@ static int jfs_create(struct inode *dip, struct dentry *dentry, umode_t mode,
struct inode *iplist[2];
struct tblock *tblk;
- jfs_info("jfs_create: dip:0x%p name:%s", dip, dentry->d_name.name);
+ jfs_info("jfs_create: dip:0x%p name:%pd", dip, dentry);
dquot_initialize(dip);
@@ -216,7 +216,7 @@ static int jfs_mkdir(struct inode *dip, struct dentry *dentry, umode_t mode)
struct inode *iplist[2];
struct tblock *tblk;
- jfs_info("jfs_mkdir: dip:0x%p name:%s", dip, dentry->d_name.name);
+ jfs_info("jfs_mkdir: dip:0x%p name:%pd", dip, dentry);
dquot_initialize(dip);
@@ -352,7 +352,7 @@ static int jfs_rmdir(struct inode *dip, struct dentry *dentry)
struct inode *iplist[2];
struct tblock *tblk;
- jfs_info("jfs_rmdir: dip:0x%p name:%s", dip, dentry->d_name.name);
+ jfs_info("jfs_rmdir: dip:0x%p name:%pd", dip, dentry);
/* Init inode for quota operations. */
dquot_initialize(dip);
@@ -480,7 +480,7 @@ static int jfs_unlink(struct inode *dip, struct dentry *dentry)
s64 new_size = 0;
int commit_flag;
- jfs_info("jfs_unlink: dip:0x%p name:%s", dip, dentry->d_name.name);
+ jfs_info("jfs_unlink: dip:0x%p name:%pd", dip, dentry);
/* Init inode for quota operations. */
dquot_initialize(dip);
@@ -797,8 +797,7 @@ static int jfs_link(struct dentry *old_dentry,
struct btstack btstack;
struct inode *iplist[2];
- jfs_info("jfs_link: %s %s", old_dentry->d_name.name,
- dentry->d_name.name);
+ jfs_info("jfs_link: %pd %pd", old_dentry, dentry);
dquot_initialize(dir);
@@ -1082,8 +1081,7 @@ static int jfs_rename(struct inode *old_dir, struct dentry *old_dentry,
int commit_flag;
- jfs_info("jfs_rename: %s %s", old_dentry->d_name.name,
- new_dentry->d_name.name);
+ jfs_info("jfs_rename: %pd %pd", old_dentry, new_dentry);
dquot_initialize(old_dir);
dquot_initialize(new_dir);
@@ -1355,7 +1353,7 @@ static int jfs_mknod(struct inode *dir, struct dentry *dentry,
if (!new_valid_dev(rdev))
return -EINVAL;
- jfs_info("jfs_mknod: %s", dentry->d_name.name);
+ jfs_info("jfs_mknod: %pd", dentry);
dquot_initialize(dir);
@@ -1444,7 +1442,7 @@ static struct dentry *jfs_lookup(struct inode *dip, struct dentry *dentry, unsig
struct component_name key;
int rc;
- jfs_info("jfs_lookup: name = %s", dentry->d_name.name);
+ jfs_info("jfs_lookup: name = %pd", dentry);
if ((rc = get_UCSname(&key, dentry)))
return ERR_PTR(rc);
diff --git a/fs/jfs/super.c b/fs/jfs/super.c
index 93e897e..16c3a955 100644
--- a/fs/jfs/super.c
+++ b/fs/jfs/super.c
@@ -117,6 +117,9 @@ static struct inode *jfs_alloc_inode(struct super_block *sb)
jfs_inode = kmem_cache_alloc(jfs_inode_cachep, GFP_NOFS);
if (!jfs_inode)
return NULL;
+#ifdef CONFIG_QUOTA
+ memset(&jfs_inode->i_dquot, 0, sizeof(jfs_inode->i_dquot));
+#endif
return &jfs_inode->vfs_inode;
}
@@ -537,6 +540,7 @@ static int jfs_fill_super(struct super_block *sb, void *data, int silent)
#ifdef CONFIG_QUOTA
sb->dq_op = &dquot_operations;
sb->s_qcop = &dquot_quotactl_ops;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
#endif
/*
@@ -836,6 +840,10 @@ out:
return len - towrite;
}
+static struct dquot **jfs_get_dquots(struct inode *inode)
+{
+ return JFS_IP(inode)->i_dquot;
+}
#endif
static const struct super_operations jfs_super_operations = {
@@ -854,6 +862,7 @@ static const struct super_operations jfs_super_operations = {
#ifdef CONFIG_QUOTA
.quota_read = jfs_quota_read,
.quota_write = jfs_quota_write,
+ .get_dquots = jfs_get_dquots,
#endif
};
diff --git a/fs/kernfs/dir.c b/fs/kernfs/dir.c
index 1c771931..37989f0 100644
--- a/fs/kernfs/dir.c
+++ b/fs/kernfs/dir.c
@@ -807,7 +807,7 @@ static struct dentry *kernfs_iop_lookup(struct inode *dir,
}
/* instantiate and hash dentry */
- ret = d_materialise_unique(dentry, inode);
+ ret = d_splice_alias(inode, dentry);
out_unlock:
mutex_unlock(&kernfs_mutex);
return ret;
diff --git a/fs/libfs.c b/fs/libfs.c
index 171d284..005843c 100644
--- a/fs/libfs.c
+++ b/fs/libfs.c
@@ -114,18 +114,18 @@ loff_t dcache_dir_lseek(struct file *file, loff_t offset, int whence)
spin_lock(&dentry->d_lock);
/* d_lock not required for cursor */
- list_del(&cursor->d_u.d_child);
+ list_del(&cursor->d_child);
p = dentry->d_subdirs.next;
while (n && p != &dentry->d_subdirs) {
struct dentry *next;
- next = list_entry(p, struct dentry, d_u.d_child);
+ next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(next))
n--;
spin_unlock(&next->d_lock);
p = p->next;
}
- list_add_tail(&cursor->d_u.d_child, p);
+ list_add_tail(&cursor->d_child, p);
spin_unlock(&dentry->d_lock);
}
}
@@ -150,7 +150,7 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
{
struct dentry *dentry = file->f_path.dentry;
struct dentry *cursor = file->private_data;
- struct list_head *p, *q = &cursor->d_u.d_child;
+ struct list_head *p, *q = &cursor->d_child;
if (!dir_emit_dots(file, ctx))
return 0;
@@ -159,7 +159,7 @@ int dcache_readdir(struct file *file, struct dir_context *ctx)
list_move(q, &dentry->d_subdirs);
for (p = q->next; p != &dentry->d_subdirs; p = p->next) {
- struct dentry *next = list_entry(p, struct dentry, d_u.d_child);
+ struct dentry *next = list_entry(p, struct dentry, d_child);
spin_lock_nested(&next->d_lock, DENTRY_D_LOCK_NESTED);
if (!simple_positive(next)) {
spin_unlock(&next->d_lock);
@@ -287,7 +287,7 @@ int simple_empty(struct dentry *dentry)
int ret = 0;
spin_lock(&dentry->d_lock);
- list_for_each_entry(child, &dentry->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dentry->d_subdirs, d_child) {
spin_lock_nested(&child->d_lock, DENTRY_D_LOCK_NESTED);
if (simple_positive(child)) {
spin_unlock(&child->d_lock);
diff --git a/fs/lockd/svclock.c b/fs/lockd/svclock.c
index 13db95f..5659874 100644
--- a/fs/lockd/svclock.c
+++ b/fs/lockd/svclock.c
@@ -53,7 +53,7 @@ static const struct rpc_call_ops nlmsvc_grant_ops;
static LIST_HEAD(nlm_blocked);
static DEFINE_SPINLOCK(nlm_blocked_lock);
-#ifdef LOCKD_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static const char *nlmdbg_cookie2a(const struct nlm_cookie *cookie)
{
/*
diff --git a/fs/lockd/svcsubs.c b/fs/lockd/svcsubs.c
index b6f3b84..d12ff4e 100644
--- a/fs/lockd/svcsubs.c
+++ b/fs/lockd/svcsubs.c
@@ -408,7 +408,7 @@ nlmsvc_match_sb(void *datap, struct nlm_file *file)
{
struct super_block *sb = datap;
- return sb == file->f_file->f_path.dentry->d_sb;
+ return sb == file_inode(file->f_file)->i_sb;
}
/**
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
index 7cb751d..0089601 100644
--- a/fs/ncpfs/dir.c
+++ b/fs/ncpfs/dir.c
@@ -198,8 +198,8 @@ ncp_single_volume(struct ncp_server *server)
static inline int ncp_is_server_root(struct inode *inode)
{
- return (!ncp_single_volume(NCP_SERVER(inode)) &&
- inode == inode->i_sb->s_root->d_inode);
+ return !ncp_single_volume(NCP_SERVER(inode)) &&
+ is_root_inode(inode);
}
@@ -403,7 +403,7 @@ ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos)
/* If a pointer is invalid, we search the dentry. */
spin_lock(&parent->d_lock);
- list_for_each_entry(dent, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(dent, &parent->d_subdirs, d_child) {
if ((unsigned long)dent->d_fsdata == fpos) {
if (dent->d_inode)
dget(dent);
@@ -685,8 +685,7 @@ static void
ncp_read_volume_list(struct file *file, struct dir_context *ctx,
struct ncp_cache_control *ctl)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file_inode(file);
struct ncp_server *server = NCP_SERVER(inode);
struct ncp_volume_info info;
struct ncp_entry_info entry;
@@ -721,8 +720,7 @@ static void
ncp_do_readdir(struct file *file, struct dir_context *ctx,
struct ncp_cache_control *ctl)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *dir = dentry->d_inode;
+ struct inode *dir = file_inode(file);
struct ncp_server *server = NCP_SERVER(dir);
struct nw_search_sequence seq;
struct ncp_entry_info entry;
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
index 77640a8..1dd7007 100644
--- a/fs/ncpfs/file.c
+++ b/fs/ncpfs/file.c
@@ -100,8 +100,7 @@ out:
static ssize_t
ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file_inode(file);
size_t already_read = 0;
off_t pos;
size_t bufsize;
@@ -109,7 +108,7 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
void* freepage;
size_t freelen;
- ncp_dbg(1, "enter %pd2\n", dentry);
+ ncp_dbg(1, "enter %pD2\n", file);
pos = *ppos;
@@ -167,7 +166,7 @@ ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos)
file_accessed(file);
- ncp_dbg(1, "exit %pd2\n", dentry);
+ ncp_dbg(1, "exit %pD2\n", file);
outrel:
ncp_inode_close(inode);
return already_read ? already_read : error;
@@ -176,15 +175,14 @@ outrel:
static ssize_t
ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos)
{
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file_inode(file);
size_t already_written = 0;
off_t pos;
size_t bufsize;
int errno;
void* bouncebuffer;
- ncp_dbg(1, "enter %pd2\n", dentry);
+ ncp_dbg(1, "enter %pD2\n", file);
if ((ssize_t) count < 0)
return -EINVAL;
pos = *ppos;
@@ -263,7 +261,7 @@ ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *
i_size_write(inode, pos);
mutex_unlock(&inode->i_mutex);
}
- ncp_dbg(1, "exit %pd2\n", dentry);
+ ncp_dbg(1, "exit %pD2\n", file);
outrel:
ncp_inode_close(inode);
return already_written ? already_written : errno;
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
index d5659d9..cf7e043 100644
--- a/fs/ncpfs/ioctl.c
+++ b/fs/ncpfs/ioctl.c
@@ -447,7 +447,6 @@ static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg
result = -EIO;
}
}
- result = 0;
}
mutex_unlock(&server->root_setup_lock);
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
index b359d12..33b873b 100644
--- a/fs/ncpfs/mmap.c
+++ b/fs/ncpfs/mmap.c
@@ -30,9 +30,7 @@
static int ncp_file_mmap_fault(struct vm_area_struct *area,
struct vm_fault *vmf)
{
- struct file *file = area->vm_file;
- struct dentry *dentry = file->f_path.dentry;
- struct inode *inode = dentry->d_inode;
+ struct inode *inode = file_inode(area->vm_file);
char *pg_addr;
unsigned int already_read;
unsigned int count;
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
index 52cb19d..b785f74 100644
--- a/fs/ncpfs/ncplib_kernel.h
+++ b/fs/ncpfs/ncplib_kernel.h
@@ -191,7 +191,7 @@ ncp_renew_dentries(struct dentry *parent)
struct dentry *dentry;
spin_lock(&parent->d_lock);
- list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
if (dentry->d_fsdata == NULL)
ncp_age_dentry(server, dentry);
else
@@ -207,7 +207,7 @@ ncp_invalidate_dircache_entries(struct dentry *parent)
struct dentry *dentry;
spin_lock(&parent->d_lock);
- list_for_each_entry(dentry, &parent->d_subdirs, d_u.d_child) {
+ list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
dentry->d_fsdata = NULL;
ncp_age_dentry(server, dentry);
}
diff --git a/fs/nfs/blocklayout/blocklayout.c b/fs/nfs/blocklayout/blocklayout.c
index 4f46f7a..77fec6a 100644
--- a/fs/nfs/blocklayout/blocklayout.c
+++ b/fs/nfs/blocklayout/blocklayout.c
@@ -812,7 +812,7 @@ static u64 pnfs_num_cont_bytes(struct inode *inode, pgoff_t idx)
/* Optimize common case that writes from 0 to end of file */
end = DIV_ROUND_UP(i_size_read(inode), PAGE_CACHE_SIZE);
- if (end != NFS_I(inode)->npages) {
+ if (end != inode->i_mapping->nrpages) {
rcu_read_lock();
end = page_cache_next_hole(mapping, idx + 1, ULONG_MAX);
rcu_read_unlock();
diff --git a/fs/nfs/blocklayout/rpc_pipefs.c b/fs/nfs/blocklayout/rpc_pipefs.c
index acbf9ca..dbe5839 100644
--- a/fs/nfs/blocklayout/rpc_pipefs.c
+++ b/fs/nfs/blocklayout/rpc_pipefs.c
@@ -112,7 +112,7 @@ out_unlock:
static ssize_t bl_pipe_downcall(struct file *filp, const char __user *src,
size_t mlen)
{
- struct nfs_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
+ struct nfs_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
nfs_net_id);
if (mlen != sizeof (struct bl_dev_msg))
diff --git a/fs/nfs/callback_proc.c b/fs/nfs/callback_proc.c
index 73466b9..e36a9d7 100644
--- a/fs/nfs/callback_proc.c
+++ b/fs/nfs/callback_proc.c
@@ -49,7 +49,7 @@ __be32 nfs4_callback_getattr(struct cb_getattrargs *args,
goto out_iput;
res->size = i_size_read(inode);
res->change_attr = delegation->change_attr;
- if (nfsi->npages != 0)
+ if (nfsi->nrequests != 0)
res->change_attr++;
res->ctime = inode->i_ctime;
res->mtime = inode->i_mtime;
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index 6e62155..9b0c55c 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -133,7 +133,7 @@ out:
static int
nfs_closedir(struct inode *inode, struct file *filp)
{
- put_nfs_open_dir_context(filp->f_path.dentry->d_inode, filp->private_data);
+ put_nfs_open_dir_context(file_inode(filp), filp->private_data);
return 0;
}
@@ -499,7 +499,7 @@ void nfs_prime_dcache(struct dentry *parent, struct nfs_entry *entry)
if (IS_ERR(inode))
goto out;
- alias = d_materialise_unique(dentry, inode);
+ alias = d_splice_alias(inode, dentry);
if (IS_ERR(alias))
goto out;
else if (alias) {
@@ -1393,7 +1393,7 @@ struct dentry *nfs_lookup(struct inode *dir, struct dentry * dentry, unsigned in
nfs_advise_use_readdirplus(dir);
no_entry:
- res = d_materialise_unique(dentry, inode);
+ res = d_splice_alias(inode, dentry);
if (res != NULL) {
if (IS_ERR(res))
goto out_unblock_sillyrename;
diff --git a/fs/nfs/filelayout/filelayoutdev.c b/fs/nfs/filelayout/filelayoutdev.c
index 9bb806a..bfecac7 100644
--- a/fs/nfs/filelayout/filelayoutdev.c
+++ b/fs/nfs/filelayout/filelayoutdev.c
@@ -204,8 +204,7 @@ destroy_ds(struct nfs4_pnfs_ds *ds)
ifdebug(FACILITY)
print_ds(ds);
- if (ds->ds_clp)
- nfs_put_client(ds->ds_clp);
+ nfs_put_client(ds->ds_clp);
while (!list_empty(&ds->ds_addrs)) {
da = list_first_entry(&ds->ds_addrs,
diff --git a/fs/nfs/fscache.c b/fs/nfs/fscache.c
index 3ef01f0..d63bea8 100644
--- a/fs/nfs/fscache.c
+++ b/fs/nfs/fscache.c
@@ -269,8 +269,8 @@ int nfs_fscache_release_page(struct page *page, gfp_t gfp)
if (!fscache_maybe_release_page(cookie, page, gfp))
return 0;
- nfs_add_fscache_stats(page->mapping->host,
- NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
+ nfs_inc_fscache_stats(page->mapping->host,
+ NFSIOS_FSCACHE_PAGES_UNCACHED);
}
return 1;
@@ -293,8 +293,8 @@ void __nfs_fscache_invalidate_page(struct page *page, struct inode *inode)
BUG_ON(!PageLocked(page));
fscache_uncache_page(cookie, page);
- nfs_add_fscache_stats(page->mapping->host,
- NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
+ nfs_inc_fscache_stats(page->mapping->host,
+ NFSIOS_FSCACHE_PAGES_UNCACHED);
}
/*
@@ -343,19 +343,19 @@ int __nfs_readpage_from_fscache(struct nfs_open_context *ctx,
case 0: /* read BIO submitted (page in fscache) */
dfprintk(FSCACHE,
"NFS: readpage_from_fscache: BIO submitted\n");
- nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK, 1);
+ nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_OK);
return ret;
case -ENOBUFS: /* inode not in cache */
case -ENODATA: /* page not in cache */
- nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1);
+ nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL);
dfprintk(FSCACHE,
"NFS: readpage_from_fscache %d\n", ret);
return 1;
default:
dfprintk(FSCACHE, "NFS: readpage_from_fscache %d\n", ret);
- nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL, 1);
+ nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_READ_FAIL);
}
return ret;
}
@@ -429,11 +429,11 @@ void __nfs_readpage_to_fscache(struct inode *inode, struct page *page, int sync)
if (ret != 0) {
fscache_uncache_page(nfs_i_fscache(inode), page);
- nfs_add_fscache_stats(inode,
- NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL, 1);
- nfs_add_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED, 1);
+ nfs_inc_fscache_stats(inode,
+ NFSIOS_FSCACHE_PAGES_WRITTEN_FAIL);
+ nfs_inc_fscache_stats(inode, NFSIOS_FSCACHE_PAGES_UNCACHED);
} else {
- nfs_add_fscache_stats(inode,
- NFSIOS_FSCACHE_PAGES_WRITTEN_OK, 1);
+ nfs_inc_fscache_stats(inode,
+ NFSIOS_FSCACHE_PAGES_WRITTEN_OK);
}
}
diff --git a/fs/nfs/getroot.c b/fs/nfs/getroot.c
index 880618a..9ac3846 100644
--- a/fs/nfs/getroot.c
+++ b/fs/nfs/getroot.c
@@ -51,14 +51,14 @@ static int nfs_superblock_set_dummy_root(struct super_block *sb, struct inode *i
/*
* Ensure that this dentry is invisible to d_find_alias().
* Otherwise, it may be spliced into the tree by
- * d_materialise_unique if a parent directory from the same
+ * d_splice_alias if a parent directory from the same
* filesystem gets mounted at a later time.
* This again causes shrink_dcache_for_umount_subtree() to
* Oops, since the test for IS_ROOT() will fail.
*/
spin_lock(&sb->s_root->d_inode->i_lock);
spin_lock(&sb->s_root->d_lock);
- hlist_del_init(&sb->s_root->d_alias);
+ hlist_del_init(&sb->s_root->d_u.d_alias);
spin_unlock(&sb->s_root->d_lock);
spin_unlock(&sb->s_root->d_inode->i_lock);
}
diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c
index 00689a8..4bffe63 100644
--- a/fs/nfs/inode.c
+++ b/fs/nfs/inode.c
@@ -192,6 +192,7 @@ void nfs_zap_caches(struct inode *inode)
nfs_zap_caches_locked(inode);
spin_unlock(&inode->i_lock);
}
+EXPORT_SYMBOL_GPL(nfs_zap_caches);
void nfs_zap_mapping(struct inode *inode, struct address_space *mapping)
{
@@ -1149,7 +1150,7 @@ static unsigned long nfs_wcc_update_inode(struct inode *inode, struct nfs_fattr
if ((fattr->valid & NFS_ATTR_FATTR_PRESIZE)
&& (fattr->valid & NFS_ATTR_FATTR_SIZE)
&& i_size_read(inode) == nfs_size_to_loff_t(fattr->pre_size)
- && nfsi->npages == 0) {
+ && nfsi->nrequests == 0) {
i_size_write(inode, nfs_size_to_loff_t(fattr->size));
ret |= NFS_INO_INVALID_ATTR;
}
@@ -1192,7 +1193,7 @@ static int nfs_check_inode_attributes(struct inode *inode, struct nfs_fattr *fat
if (fattr->valid & NFS_ATTR_FATTR_SIZE) {
cur_size = i_size_read(inode);
new_isize = nfs_size_to_loff_t(fattr->size);
- if (cur_size != new_isize && nfsi->npages == 0)
+ if (cur_size != new_isize && nfsi->nrequests == 0)
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE;
}
@@ -1619,7 +1620,7 @@ static int nfs_update_inode(struct inode *inode, struct nfs_fattr *fattr)
if (new_isize != cur_isize) {
/* Do we perhaps have any outstanding writes, or has
* the file grown beyond our last write? */
- if ((nfsi->npages == 0) || new_isize > cur_isize) {
+ if ((nfsi->nrequests == 0) || new_isize > cur_isize) {
i_size_write(inode, new_isize);
invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_DATA;
invalid &= ~NFS_INO_REVAL_PAGECACHE;
@@ -1784,7 +1785,7 @@ static void init_once(void *foo)
INIT_LIST_HEAD(&nfsi->access_cache_entry_lru);
INIT_LIST_HEAD(&nfsi->access_cache_inode_lru);
INIT_LIST_HEAD(&nfsi->commit_info.list);
- nfsi->npages = 0;
+ nfsi->nrequests = 0;
nfsi->commit_info.ncommit = 0;
atomic_set(&nfsi->commit_info.rpcs_out, 0);
atomic_set(&nfsi->silly_count, 1);
diff --git a/fs/nfs/iostat.h b/fs/nfs/iostat.h
index c583248..0cb806f 100644
--- a/fs/nfs/iostat.h
+++ b/fs/nfs/iostat.h
@@ -55,6 +55,11 @@ static inline void nfs_add_fscache_stats(struct inode *inode,
{
this_cpu_add(NFS_SERVER(inode)->io_stats->fscache[stat], addend);
}
+static inline void nfs_inc_fscache_stats(struct inode *inode,
+ enum nfs_stat_fscachecounters stat)
+{
+ this_cpu_inc(NFS_SERVER(inode)->io_stats->fscache[stat]);
+}
#endif
static inline struct nfs_iostats __percpu *nfs_alloc_iostats(void)
diff --git a/fs/nfs/nfs42.h b/fs/nfs/nfs42.h
index d10333a..7afb894 100644
--- a/fs/nfs/nfs42.h
+++ b/fs/nfs/nfs42.h
@@ -6,6 +6,8 @@
#define __LINUX_FS_NFS_NFS4_2_H
/* nfs4.2proc.c */
+int nfs42_proc_allocate(struct file *, loff_t, loff_t);
+int nfs42_proc_deallocate(struct file *, loff_t, loff_t);
loff_t nfs42_proc_llseek(struct file *, loff_t, int);
/* nfs4.2xdr.h */
diff --git a/fs/nfs/nfs42proc.c b/fs/nfs/nfs42proc.c
index 0886f1d..cb17072 100644
--- a/fs/nfs/nfs42proc.c
+++ b/fs/nfs/nfs42proc.c
@@ -32,6 +32,81 @@ static int nfs42_set_rw_stateid(nfs4_stateid *dst, struct file *file,
return ret;
}
+static int _nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
+ loff_t offset, loff_t len)
+{
+ struct inode *inode = file_inode(filep);
+ struct nfs42_falloc_args args = {
+ .falloc_fh = NFS_FH(inode),
+ .falloc_offset = offset,
+ .falloc_length = len,
+ };
+ struct nfs42_falloc_res res;
+ struct nfs_server *server = NFS_SERVER(inode);
+ int status;
+
+ msg->rpc_argp = &args;
+ msg->rpc_resp = &res;
+
+ status = nfs42_set_rw_stateid(&args.falloc_stateid, filep, FMODE_WRITE);
+ if (status)
+ return status;
+
+ return nfs4_call_sync(server->client, server, msg,
+ &args.seq_args, &res.seq_res, 0);
+}
+
+static int nfs42_proc_fallocate(struct rpc_message *msg, struct file *filep,
+ loff_t offset, loff_t len)
+{
+ struct nfs_server *server = NFS_SERVER(file_inode(filep));
+ struct nfs4_exception exception = { };
+ int err;
+
+ do {
+ err = _nfs42_proc_fallocate(msg, filep, offset, len);
+ if (err == -ENOTSUPP)
+ return -EOPNOTSUPP;
+ err = nfs4_handle_exception(server, err, &exception);
+ } while (exception.retry);
+
+ return err;
+}
+
+int nfs42_proc_allocate(struct file *filep, loff_t offset, loff_t len)
+{
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_ALLOCATE],
+ };
+ struct inode *inode = file_inode(filep);
+ int err;
+
+ if (!nfs_server_capable(inode, NFS_CAP_ALLOCATE))
+ return -EOPNOTSUPP;
+
+ err = nfs42_proc_fallocate(&msg, filep, offset, len);
+ if (err == -EOPNOTSUPP)
+ NFS_SERVER(inode)->caps &= ~NFS_CAP_ALLOCATE;
+ return err;
+}
+
+int nfs42_proc_deallocate(struct file *filep, loff_t offset, loff_t len)
+{
+ struct rpc_message msg = {
+ .rpc_proc = &nfs4_procedures[NFSPROC4_CLNT_DEALLOCATE],
+ };
+ struct inode *inode = file_inode(filep);
+ int err;
+
+ if (!nfs_server_capable(inode, NFS_CAP_DEALLOCATE))
+ return -EOPNOTSUPP;
+
+ err = nfs42_proc_fallocate(&msg, filep, offset, len);
+ if (err == -EOPNOTSUPP)
+ NFS_SERVER(inode)->caps &= ~NFS_CAP_DEALLOCATE;
+ return err;
+}
+
loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
{
struct inode *inode = file_inode(filep);
@@ -50,7 +125,7 @@ loff_t nfs42_proc_llseek(struct file *filep, loff_t offset, int whence)
struct nfs_server *server = NFS_SERVER(inode);
int status;
- if (!(server->caps & NFS_CAP_SEEK))
+ if (!nfs_server_capable(inode, NFS_CAP_SEEK))
return -ENOTSUPP;
status = nfs42_set_rw_stateid(&args.sa_stateid, filep, FMODE_READ);
diff --git a/fs/nfs/nfs42xdr.c b/fs/nfs/nfs42xdr.c
index c90469b..038a7e15 100644
--- a/fs/nfs/nfs42xdr.c
+++ b/fs/nfs/nfs42xdr.c
@@ -4,6 +4,15 @@
#ifndef __LINUX_FS_NFS_NFS4_2XDR_H
#define __LINUX_FS_NFS_NFS4_2XDR_H
+#define encode_fallocate_maxsz (encode_stateid_maxsz + \
+ 2 /* offset */ + \
+ 2 /* length */)
+#define encode_allocate_maxsz (op_encode_hdr_maxsz + \
+ encode_fallocate_maxsz)
+#define decode_allocate_maxsz (op_decode_hdr_maxsz)
+#define encode_deallocate_maxsz (op_encode_hdr_maxsz + \
+ encode_fallocate_maxsz)
+#define decode_deallocate_maxsz (op_decode_hdr_maxsz)
#define encode_seek_maxsz (op_encode_hdr_maxsz + \
encode_stateid_maxsz + \
2 /* offset */ + \
@@ -14,6 +23,18 @@
2 /* offset */ + \
2 /* length */)
+#define NFS4_enc_allocate_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_allocate_maxsz)
+#define NFS4_dec_allocate_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_allocate_maxsz)
+#define NFS4_enc_deallocate_sz (compound_encode_hdr_maxsz + \
+ encode_putfh_maxsz + \
+ encode_deallocate_maxsz)
+#define NFS4_dec_deallocate_sz (compound_decode_hdr_maxsz + \
+ decode_putfh_maxsz + \
+ decode_deallocate_maxsz)
#define NFS4_enc_seek_sz (compound_encode_hdr_maxsz + \
encode_putfh_maxsz + \
encode_seek_maxsz)
@@ -22,6 +43,30 @@
decode_seek_maxsz)
+static void encode_fallocate(struct xdr_stream *xdr,
+ struct nfs42_falloc_args *args)
+{
+ encode_nfs4_stateid(xdr, &args->falloc_stateid);
+ encode_uint64(xdr, args->falloc_offset);
+ encode_uint64(xdr, args->falloc_length);
+}
+
+static void encode_allocate(struct xdr_stream *xdr,
+ struct nfs42_falloc_args *args,
+ struct compound_hdr *hdr)
+{
+ encode_op_hdr(xdr, OP_ALLOCATE, decode_allocate_maxsz, hdr);
+ encode_fallocate(xdr, args);
+}
+
+static void encode_deallocate(struct xdr_stream *xdr,
+ struct nfs42_falloc_args *args,
+ struct compound_hdr *hdr)
+{
+ encode_op_hdr(xdr, OP_DEALLOCATE, decode_deallocate_maxsz, hdr);
+ encode_fallocate(xdr, args);
+}
+
static void encode_seek(struct xdr_stream *xdr,
struct nfs42_seek_args *args,
struct compound_hdr *hdr)
@@ -33,6 +78,42 @@ static void encode_seek(struct xdr_stream *xdr,
}
/*
+ * Encode ALLOCATE request
+ */
+static void nfs4_xdr_enc_allocate(struct rpc_rqst *req,
+ struct xdr_stream *xdr,
+ struct nfs42_falloc_args *args)
+{
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+ };
+
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->seq_args, &hdr);
+ encode_putfh(xdr, args->falloc_fh, &hdr);
+ encode_allocate(xdr, args, &hdr);
+ encode_nops(&hdr);
+}
+
+/*
+ * Encode DEALLOCATE request
+ */
+static void nfs4_xdr_enc_deallocate(struct rpc_rqst *req,
+ struct xdr_stream *xdr,
+ struct nfs42_falloc_args *args)
+{
+ struct compound_hdr hdr = {
+ .minorversion = nfs4_xdr_minorversion(&args->seq_args),
+ };
+
+ encode_compound_hdr(xdr, req, &hdr);
+ encode_sequence(xdr, &args->seq_args, &hdr);
+ encode_putfh(xdr, args->falloc_fh, &hdr);
+ encode_deallocate(xdr, args, &hdr);
+ encode_nops(&hdr);
+}
+
+/*
* Encode SEEK request
*/
static void nfs4_xdr_enc_seek(struct rpc_rqst *req,
@@ -50,6 +131,16 @@ static void nfs4_xdr_enc_seek(struct rpc_rqst *req,
encode_nops(&hdr);
}
+static int decode_allocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
+{
+ return decode_op_hdr(xdr, OP_ALLOCATE);
+}
+
+static int decode_deallocate(struct xdr_stream *xdr, struct nfs42_falloc_res *res)
+{
+ return decode_op_hdr(xdr, OP_DEALLOCATE);
+}
+
static int decode_seek(struct xdr_stream *xdr, struct nfs42_seek_res *res)
{
int status;
@@ -73,6 +164,54 @@ out_overflow:
}
/*
+ * Decode ALLOCATE request
+ */
+static int nfs4_xdr_dec_allocate(struct rpc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ struct nfs42_falloc_res *res)
+{
+ struct compound_hdr hdr;
+ int status;
+
+ status = decode_compound_hdr(xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(xdr, &res->seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_allocate(xdr, res);
+out:
+ return status;
+}
+
+/*
+ * Decode DEALLOCATE request
+ */
+static int nfs4_xdr_dec_deallocate(struct rpc_rqst *rqstp,
+ struct xdr_stream *xdr,
+ struct nfs42_falloc_res *res)
+{
+ struct compound_hdr hdr;
+ int status;
+
+ status = decode_compound_hdr(xdr, &hdr);
+ if (status)
+ goto out;
+ status = decode_sequence(xdr, &res->seq_res, rqstp);
+ if (status)
+ goto out;
+ status = decode_putfh(xdr);
+ if (status)
+ goto out;
+ status = decode_deallocate(xdr, res);
+out:
+ return status;
+}
+
+/*
* Decode SEEK request
*/
static int nfs4_xdr_dec_seek(struct rpc_rqst *rqstp,
diff --git a/fs/nfs/nfs4_fs.h b/fs/nfs/nfs4_fs.h
index be6cac3..a081787 100644
--- a/fs/nfs/nfs4_fs.h
+++ b/fs/nfs/nfs4_fs.h
@@ -226,6 +226,7 @@ int nfs4_replace_transport(struct nfs_server *server,
const struct nfs4_fs_locations *locations);
/* nfs4proc.c */
+extern int nfs4_handle_exception(struct nfs_server *, int, struct nfs4_exception *);
extern int nfs4_call_sync(struct rpc_clnt *, struct nfs_server *,
struct rpc_message *, struct nfs4_sequence_args *,
struct nfs4_sequence_res *, int);
diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c
index ffdb28d..0331125 100644
--- a/fs/nfs/nfs4client.c
+++ b/fs/nfs/nfs4client.c
@@ -241,28 +241,25 @@ void nfs4_free_client(struct nfs_client *clp)
*/
static int nfs4_init_callback(struct nfs_client *clp)
{
+ struct rpc_xprt *xprt;
int error;
- if (clp->rpc_ops->version == 4) {
- struct rpc_xprt *xprt;
+ xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
- xprt = rcu_dereference_raw(clp->cl_rpcclient->cl_xprt);
-
- if (nfs4_has_session(clp)) {
- error = xprt_setup_backchannel(xprt,
- NFS41_BC_MIN_CALLBACKS);
- if (error < 0)
- return error;
- }
-
- error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
- if (error < 0) {
- dprintk("%s: failed to start callback. Error = %d\n",
- __func__, error);
+ if (nfs4_has_session(clp)) {
+ error = xprt_setup_backchannel(xprt, NFS41_BC_MIN_CALLBACKS);
+ if (error < 0)
return error;
- }
- __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
}
+
+ error = nfs_callback_up(clp->cl_mvops->minor_version, xprt);
+ if (error < 0) {
+ dprintk("%s: failed to start callback. Error = %d\n",
+ __func__, error);
+ return error;
+ }
+ __set_bit(NFS_CS_CALLBACK, &clp->cl_res_state);
+
return 0;
}
@@ -498,8 +495,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock);
- if (prev)
- nfs_put_client(prev);
+ nfs_put_client(prev);
prev = pos;
status = nfs_wait_client_init_complete(pos);
@@ -517,8 +513,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock);
- if (prev)
- nfs_put_client(prev);
+ nfs_put_client(prev);
prev = pos;
status = nfs4_proc_setclientid_confirm(pos, &clid, cred);
@@ -549,8 +544,7 @@ int nfs40_walk_client_list(struct nfs_client *new,
/* No match found. The server lost our clientid */
out:
- if (prev)
- nfs_put_client(prev);
+ nfs_put_client(prev);
dprintk("NFS: <-- %s status = %d\n", __func__, status);
return status;
}
@@ -641,8 +635,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
atomic_inc(&pos->cl_count);
spin_unlock(&nn->nfs_client_lock);
- if (prev)
- nfs_put_client(prev);
+ nfs_put_client(prev);
prev = pos;
status = nfs_wait_client_init_complete(pos);
@@ -675,8 +668,7 @@ int nfs41_walk_client_list(struct nfs_client *new,
/* No matching nfs_client found. */
spin_unlock(&nn->nfs_client_lock);
dprintk("NFS: <-- %s status = %d\n", __func__, status);
- if (prev)
- nfs_put_client(prev);
+ nfs_put_client(prev);
return status;
}
#endif /* CONFIG_NFS_V4_1 */
diff --git a/fs/nfs/nfs4file.c b/fs/nfs/nfs4file.c
index c51fb4d..8b46389 100644
--- a/fs/nfs/nfs4file.c
+++ b/fs/nfs/nfs4file.c
@@ -3,6 +3,8 @@
*
* Copyright (C) 1992 Rick Sladkey
*/
+#include <linux/fs.h>
+#include <linux/falloc.h>
#include <linux/nfs_fs.h>
#include "internal.h"
#include "fscache.h"
@@ -134,6 +136,32 @@ static loff_t nfs4_file_llseek(struct file *filep, loff_t offset, int whence)
return nfs_file_llseek(filep, offset, whence);
}
}
+
+static long nfs42_fallocate(struct file *filep, int mode, loff_t offset, loff_t len)
+{
+ struct inode *inode = file_inode(filep);
+ long ret;
+
+ if (!S_ISREG(inode->i_mode))
+ return -EOPNOTSUPP;
+
+ if ((mode != 0) && (mode != (FALLOC_FL_PUNCH_HOLE | FALLOC_FL_KEEP_SIZE)))
+ return -EOPNOTSUPP;
+
+ ret = inode_newsize_ok(inode, offset + len);
+ if (ret < 0)
+ return ret;
+
+ mutex_lock(&inode->i_mutex);
+ if (mode & FALLOC_FL_PUNCH_HOLE)
+ ret = nfs42_proc_deallocate(filep, offset, len);
+ else
+ ret = nfs42_proc_allocate(filep, offset, len);
+ mutex_unlock(&inode->i_mutex);
+
+ nfs_zap_caches(inode);
+ return ret;
+}
#endif /* CONFIG_NFS_V4_2 */
const struct file_operations nfs4_file_operations = {
@@ -155,6 +183,9 @@ const struct file_operations nfs4_file_operations = {
.flock = nfs_flock,
.splice_read = nfs_file_splice_read,
.splice_write = iter_file_splice_write,
+#ifdef CONFIG_NFS_V4_2
+ .fallocate = nfs42_fallocate,
+#endif /* CONFIG_NFS_V4_2 */
.check_flags = nfs_check_flags,
.setlease = simple_nosetlease,
};
diff --git a/fs/nfs/nfs4proc.c b/fs/nfs/nfs4proc.c
index 69dc20a..e7f8d5f 100644
--- a/fs/nfs/nfs4proc.c
+++ b/fs/nfs/nfs4proc.c
@@ -158,8 +158,6 @@ static int nfs4_map_errors(int err)
return -EACCES;
case -NFS4ERR_MINOR_VERS_MISMATCH:
return -EPROTONOSUPPORT;
- case -NFS4ERR_ACCESS:
- return -EACCES;
case -NFS4ERR_FILE_OPEN:
return -EBUSY;
default:
@@ -344,7 +342,7 @@ static int nfs4_delay(struct rpc_clnt *clnt, long *timeout)
/* This is the error handling routine for processes that are allowed
* to sleep.
*/
-static int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
+int nfs4_handle_exception(struct nfs_server *server, int errorcode, struct nfs4_exception *exception)
{
struct nfs_client *clp = server->nfs_client;
struct nfs4_state *state = exception->state;
@@ -7704,6 +7702,9 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
dprintk("--> %s\n", __func__);
+ /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
+ pnfs_get_layout_hdr(NFS_I(inode)->layout);
+
lgp->args.layout.pages = nfs4_alloc_pages(max_pages, gfp_flags);
if (!lgp->args.layout.pages) {
nfs4_layoutget_release(lgp);
@@ -7716,9 +7717,6 @@ nfs4_proc_layoutget(struct nfs4_layoutget *lgp, gfp_t gfp_flags)
lgp->res.seq_res.sr_slot = NULL;
nfs4_init_sequence(&lgp->args.seq_args, &lgp->res.seq_res, 0);
- /* nfs4_layoutget_release calls pnfs_put_layout_hdr */
- pnfs_get_layout_hdr(NFS_I(inode)->layout);
-
task = rpc_run_task(&task_setup_data);
if (IS_ERR(task))
return ERR_CAST(task);
@@ -8426,6 +8424,8 @@ static const struct nfs4_minor_version_ops nfs_v4_2_minor_ops = {
| NFS_CAP_POSIX_LOCK
| NFS_CAP_STATEID_NFSV41
| NFS_CAP_ATOMIC_OPEN_V1
+ | NFS_CAP_ALLOCATE
+ | NFS_CAP_DEALLOCATE
| NFS_CAP_SEEK,
.init_client = nfs41_init_client,
.shutdown_client = nfs41_shutdown_client,
diff --git a/fs/nfs/nfs4xdr.c b/fs/nfs/nfs4xdr.c
index 206c08a..cb4376b 100644
--- a/fs/nfs/nfs4xdr.c
+++ b/fs/nfs/nfs4xdr.c
@@ -141,13 +141,15 @@ static int nfs4_stat_to_errno(int);
XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
XDR_QUADLEN(NFS4_SETCLIENTID_NAMELEN) + \
1 /* sc_prog */ + \
- XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
- XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
+ 1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
+ 1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN) + \
1) /* sc_cb_ident */
#define decode_setclientid_maxsz \
(op_decode_hdr_maxsz + \
- 2 + \
- 1024) /* large value for CLID_INUSE */
+ 2 /* clientid */ + \
+ XDR_QUADLEN(NFS4_VERIFIER_SIZE) + \
+ 1 + XDR_QUADLEN(RPCBIND_MAXNETIDLEN) + \
+ 1 + XDR_QUADLEN(RPCBIND_MAXUADDRLEN))
#define encode_setclientid_confirm_maxsz \
(op_encode_hdr_maxsz + \
3 + (NFS4_VERIFIER_SIZE >> 2))
@@ -7394,6 +7396,8 @@ struct rpc_procinfo nfs4_procedures[] = {
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
PROC(SEEK, enc_seek, dec_seek),
+ PROC(ALLOCATE, enc_allocate, dec_allocate),
+ PROC(DEALLOCATE, enc_deallocate, dec_deallocate),
#endif /* CONFIG_NFS_V4_2 */
};
diff --git a/fs/nfs/pagelist.c b/fs/nfs/pagelist.c
index ed0db61..2b5e769 100644
--- a/fs/nfs/pagelist.c
+++ b/fs/nfs/pagelist.c
@@ -258,6 +258,7 @@ bool nfs_page_group_sync_on_bit(struct nfs_page *req, unsigned int bit)
static inline void
nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)
{
+ struct inode *inode;
WARN_ON_ONCE(prev == req);
if (!prev) {
@@ -276,12 +277,16 @@ nfs_page_group_init(struct nfs_page *req, struct nfs_page *prev)
* nfs_page_group_destroy is called */
kref_get(&req->wb_head->wb_kref);
- /* grab extra ref if head request has extra ref from
- * the write/commit path to handle handoff between write
- * and commit lists */
+ /* grab extra ref and bump the request count if head request
+ * has extra ref from the write/commit path to handle handoff
+ * between write and commit lists. */
if (test_bit(PG_INODE_REF, &prev->wb_head->wb_flags)) {
+ inode = page_file_mapping(req->wb_page)->host;
set_bit(PG_INODE_REF, &req->wb_flags);
kref_get(&req->wb_kref);
+ spin_lock(&inode->i_lock);
+ NFS_I(inode)->nrequests++;
+ spin_unlock(&inode->i_lock);
}
}
}
diff --git a/fs/nfs/read.c b/fs/nfs/read.c
index beff276..c91a479 100644
--- a/fs/nfs/read.c
+++ b/fs/nfs/read.c
@@ -269,7 +269,7 @@ int nfs_readpage(struct file *file, struct page *page)
dprintk("NFS: nfs_readpage (%p %ld@%lu)\n",
page, PAGE_CACHE_SIZE, page_file_index(page));
nfs_inc_stats(inode, NFSIOS_VFSREADPAGE);
- nfs_add_stats(inode, NFSIOS_READPAGES, 1);
+ nfs_inc_stats(inode, NFSIOS_READPAGES);
/*
* Try to flush any pending writes to the file..
diff --git a/fs/nfs/write.c b/fs/nfs/write.c
index f83b02d..af3af68 100644
--- a/fs/nfs/write.c
+++ b/fs/nfs/write.c
@@ -575,7 +575,7 @@ static int nfs_do_writepage(struct page *page, struct writeback_control *wbc, st
int ret;
nfs_inc_stats(inode, NFSIOS_VFSWRITEPAGE);
- nfs_add_stats(inode, NFSIOS_WRITEPAGES, 1);
+ nfs_inc_stats(inode, NFSIOS_WRITEPAGES);
nfs_pageio_cond_complete(pgio, page_file_index(page));
ret = nfs_page_async_flush(pgio, page, wbc->sync_mode == WB_SYNC_NONE);
@@ -670,7 +670,8 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
nfs_lock_request(req);
spin_lock(&inode->i_lock);
- if (!nfsi->npages && NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
+ if (!nfsi->nrequests &&
+ NFS_PROTO(inode)->have_delegation(inode, FMODE_WRITE))
inode->i_version++;
/*
* Swap-space should not get truncated. Hence no need to plug the race
@@ -681,9 +682,11 @@ static void nfs_inode_add_request(struct inode *inode, struct nfs_page *req)
SetPagePrivate(req->wb_page);
set_page_private(req->wb_page, (unsigned long)req);
}
- nfsi->npages++;
+ nfsi->nrequests++;
/* this a head request for a page group - mark it as having an
- * extra reference so sub groups can follow suit */
+ * extra reference so sub groups can follow suit.
+ * This flag also informs pgio layer when to bump nrequests when
+ * adding subrequests. */
WARN_ON(test_and_set_bit(PG_INODE_REF, &req->wb_flags));
kref_get(&req->wb_kref);
spin_unlock(&inode->i_lock);
@@ -709,7 +712,11 @@ static void nfs_inode_remove_request(struct nfs_page *req)
wake_up_page(head->wb_page, PG_private);
clear_bit(PG_MAPPED, &head->wb_flags);
}
- nfsi->npages--;
+ nfsi->nrequests--;
+ spin_unlock(&inode->i_lock);
+ } else {
+ spin_lock(&inode->i_lock);
+ nfsi->nrequests--;
spin_unlock(&inode->i_lock);
}
@@ -1735,7 +1742,7 @@ static int nfs_commit_unstable_pages(struct inode *inode, struct writeback_contr
/* Don't commit yet if this is a non-blocking flush and there
* are a lot of outstanding writes for this mapping.
*/
- if (nfsi->commit_info.ncommit <= (nfsi->npages >> 1))
+ if (nfsi->commit_info.ncommit <= (nfsi->nrequests >> 1))
goto out_mark_dirty;
/* don't wait for the COMMIT response */
diff --git a/fs/nfsd/nfs4recover.c b/fs/nfsd/nfs4recover.c
index a25490a..cc6a760 100644
--- a/fs/nfsd/nfs4recover.c
+++ b/fs/nfsd/nfs4recover.c
@@ -245,10 +245,11 @@ struct nfs4_dir_ctx {
};
static int
-nfsd4_build_namelist(void *arg, const char *name, int namlen,
+nfsd4_build_namelist(struct dir_context *__ctx, const char *name, int namlen,
loff_t offset, u64 ino, unsigned int d_type)
{
- struct nfs4_dir_ctx *ctx = arg;
+ struct nfs4_dir_ctx *ctx =
+ container_of(__ctx, struct nfs4_dir_ctx, ctx);
struct name_list *entry;
if (namlen != HEXDIR_LEN - 1)
@@ -704,7 +705,7 @@ cld_pipe_downcall(struct file *filp, const char __user *src, size_t mlen)
struct cld_upcall *tmp, *cup;
struct cld_msg __user *cmsg = (struct cld_msg __user *)src;
uint32_t xid;
- struct nfsd_net *nn = net_generic(filp->f_dentry->d_sb->s_fs_info,
+ struct nfsd_net *nn = net_generic(file_inode(filp)->i_sb->s_fs_info,
nfsd_net_id);
struct cld_net *cn = nn->cld_net;
diff --git a/fs/nfsd/nfs4xdr.c b/fs/nfsd/nfs4xdr.c
index eeea7a9..b1eed4d 100644
--- a/fs/nfsd/nfs4xdr.c
+++ b/fs/nfsd/nfs4xdr.c
@@ -1886,7 +1886,7 @@ static __be32 nfsd4_encode_path(struct xdr_stream *xdr,
goto out_free;
}
p = xdr_encode_opaque(p, dentry->d_name.name, len);
- dprintk("/%s", dentry->d_name.name);
+ dprintk("/%pd", dentry);
spin_unlock(&dentry->d_lock);
dput(dentry);
ncomponents--;
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index ca73ca7..9506ea5 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -231,6 +231,10 @@ static struct file_operations reply_cache_stats_operations = {
* payload - write methods
*/
+static inline struct net *netns(struct file *file)
+{
+ return file_inode(file)->i_sb->s_fs_info;
+}
/**
* write_unlock_ip - Release all locks used by a client
@@ -252,7 +256,7 @@ static ssize_t write_unlock_ip(struct file *file, char *buf, size_t size)
struct sockaddr *sap = (struct sockaddr *)&address;
size_t salen = sizeof(address);
char *fo_path;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
+ struct net *net = netns(file);
/* sanity check */
if (size == 0)
@@ -350,7 +354,6 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
int len;
struct auth_domain *dom;
struct knfsd_fh fh;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
if (size == 0)
return -EINVAL;
@@ -385,7 +388,7 @@ static ssize_t write_filehandle(struct file *file, char *buf, size_t size)
if (!dom)
return -ENOMEM;
- len = exp_rootfh(net, dom, path, &fh, maxsize);
+ len = exp_rootfh(netns(file), dom, path, &fh, maxsize);
auth_domain_put(dom);
if (len)
return len;
@@ -429,7 +432,7 @@ static ssize_t write_threads(struct file *file, char *buf, size_t size)
{
char *mesg = buf;
int rv;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
+ struct net *net = netns(file);
if (size > 0) {
int newthreads;
@@ -480,7 +483,7 @@ static ssize_t write_pool_threads(struct file *file, char *buf, size_t size)
int len;
int npools;
int *nthreads;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
+ struct net *net = netns(file);
mutex_lock(&nfsd_mutex);
npools = nfsd_nrpools(net);
@@ -543,8 +546,7 @@ static ssize_t __write_versions(struct file *file, char *buf, size_t size)
unsigned minor;
ssize_t tlen = 0;
char *sep;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
if (size>0) {
if (nn->nfsd_serv)
@@ -830,10 +832,9 @@ static ssize_t __write_ports(struct file *file, char *buf, size_t size,
static ssize_t write_ports(struct file *file, char *buf, size_t size)
{
ssize_t rv;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
mutex_lock(&nfsd_mutex);
- rv = __write_ports(file, buf, size, net);
+ rv = __write_ports(file, buf, size, netns(file));
mutex_unlock(&nfsd_mutex);
return rv;
}
@@ -865,8 +866,7 @@ int nfsd_max_blksize;
static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
{
char *mesg = buf;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
if (size > 0) {
int bsize;
@@ -915,8 +915,7 @@ static ssize_t write_maxblksize(struct file *file, char *buf, size_t size)
static ssize_t write_maxconn(struct file *file, char *buf, size_t size)
{
char *mesg = buf;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
unsigned int maxconn = nn->max_connections;
if (size > 0) {
@@ -997,8 +996,7 @@ static ssize_t nfsd4_write_time(struct file *file, char *buf, size_t size,
*/
static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
{
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
return nfsd4_write_time(file, buf, size, &nn->nfsd4_lease, nn);
}
@@ -1014,8 +1012,7 @@ static ssize_t write_leasetime(struct file *file, char *buf, size_t size)
*/
static ssize_t write_gracetime(struct file *file, char *buf, size_t size)
{
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
return nfsd4_write_time(file, buf, size, &nn->nfsd4_grace, nn);
}
@@ -1071,8 +1068,7 @@ static ssize_t __write_recoverydir(struct file *file, char *buf, size_t size,
static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
{
ssize_t rv;
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
mutex_lock(&nfsd_mutex);
rv = __write_recoverydir(file, buf, size, nn);
@@ -1102,8 +1098,7 @@ static ssize_t write_recoverydir(struct file *file, char *buf, size_t size)
*/
static ssize_t write_v4_end_grace(struct file *file, char *buf, size_t size)
{
- struct net *net = file->f_dentry->d_sb->s_fs_info;
- struct nfsd_net *nn = net_generic(net, nfsd_net_id);
+ struct nfsd_net *nn = net_generic(netns(file), nfsd_net_id);
if (size > 0) {
switch(buf[0]) {
diff --git a/fs/nfsd/vfs.c b/fs/nfsd/vfs.c
index 989129e..0a82e3c 100644
--- a/fs/nfsd/vfs.c
+++ b/fs/nfsd/vfs.c
@@ -930,7 +930,6 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
unsigned long *cnt, int *stablep)
{
struct svc_export *exp;
- struct dentry *dentry;
struct inode *inode;
mm_segment_t oldfs;
__be32 err = 0;
@@ -949,8 +948,7 @@ nfsd_vfs_write(struct svc_rqst *rqstp, struct svc_fh *fhp, struct file *file,
*/
current->flags |= PF_LESS_THROTTLE;
- dentry = file->f_path.dentry;
- inode = dentry->d_inode;
+ inode = file_inode(file);
exp = fhp->fh_export;
use_wgather = (rqstp->rq_vers == 2) && EX_WGATHER(exp);
@@ -1819,10 +1817,12 @@ struct readdir_data {
int full;
};
-static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
- loff_t offset, u64 ino, unsigned int d_type)
+static int nfsd_buffered_filldir(struct dir_context *ctx, const char *name,
+ int namlen, loff_t offset, u64 ino,
+ unsigned int d_type)
{
- struct readdir_data *buf = __buf;
+ struct readdir_data *buf =
+ container_of(ctx, struct readdir_data, ctx);
struct buffered_dirent *de = (void *)(buf->dirent + buf->used);
unsigned int reclen;
@@ -1842,7 +1842,7 @@ static int nfsd_buffered_filldir(void *__buf, const char *name, int namlen,
return 0;
}
-static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
+static __be32 nfsd_buffered_readdir(struct file *file, nfsd_filldir_t func,
struct readdir_cd *cdp, loff_t *offsetp)
{
struct buffered_dirent *de;
@@ -1926,7 +1926,7 @@ static __be32 nfsd_buffered_readdir(struct file *file, filldir_t func,
*/
__be32
nfsd_readdir(struct svc_rqst *rqstp, struct svc_fh *fhp, loff_t *offsetp,
- struct readdir_cd *cdp, filldir_t func)
+ struct readdir_cd *cdp, nfsd_filldir_t func)
{
__be32 err;
struct file *file;
diff --git a/fs/nfsd/vfs.h b/fs/nfsd/vfs.h
index c2ff3f1..b1796d6 100644
--- a/fs/nfsd/vfs.h
+++ b/fs/nfsd/vfs.h
@@ -36,7 +36,7 @@
/*
* Callback function for readdir
*/
-typedef int (*nfsd_dirop_t)(struct inode *, struct dentry *, int, int);
+typedef int (*nfsd_filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
/* nfsd/vfs.c */
int nfsd_racache_init(int);
@@ -95,7 +95,7 @@ __be32 nfsd_rename(struct svc_rqst *,
__be32 nfsd_unlink(struct svc_rqst *, struct svc_fh *, int type,
char *name, int len);
__be32 nfsd_readdir(struct svc_rqst *, struct svc_fh *,
- loff_t *, struct readdir_cd *, filldir_t);
+ loff_t *, struct readdir_cd *, nfsd_filldir_t);
__be32 nfsd_statfs(struct svc_rqst *, struct svc_fh *,
struct kstatfs *, int access);
diff --git a/fs/nilfs2/file.c b/fs/nilfs2/file.c
index e9e3325..3a03e0a 100644
--- a/fs/nilfs2/file.c
+++ b/fs/nilfs2/file.c
@@ -39,21 +39,15 @@ int nilfs_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
*/
struct the_nilfs *nilfs;
struct inode *inode = file->f_mapping->host;
- int err;
-
- err = filemap_write_and_wait_range(inode->i_mapping, start, end);
- if (err)
- return err;
- mutex_lock(&inode->i_mutex);
+ int err = 0;
if (nilfs_inode_dirty(inode)) {
if (datasync)
err = nilfs_construct_dsync_segment(inode->i_sb, inode,
- 0, LLONG_MAX);
+ start, end);
else
err = nilfs_construct_segment(inode->i_sb);
}
- mutex_unlock(&inode->i_mutex);
nilfs = inode->i_sb->s_fs_info;
if (!err)
diff --git a/fs/nilfs2/inode.c b/fs/nilfs2/inode.c
index e1fa69b..8b59695 100644
--- a/fs/nilfs2/inode.c
+++ b/fs/nilfs2/inode.c
@@ -49,6 +49,8 @@ struct nilfs_iget_args {
int for_gc;
};
+static int nilfs_iget_test(struct inode *inode, void *opaque);
+
void nilfs_inode_add_blocks(struct inode *inode, int n)
{
struct nilfs_root *root = NILFS_I(inode)->i_root;
@@ -348,6 +350,17 @@ const struct address_space_operations nilfs_aops = {
.is_partially_uptodate = block_is_partially_uptodate,
};
+static int nilfs_insert_inode_locked(struct inode *inode,
+ struct nilfs_root *root,
+ unsigned long ino)
+{
+ struct nilfs_iget_args args = {
+ .ino = ino, .root = root, .cno = 0, .for_gc = 0
+ };
+
+ return insert_inode_locked4(inode, ino, nilfs_iget_test, &args);
+}
+
struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
{
struct super_block *sb = dir->i_sb;
@@ -383,7 +396,7 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
if (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode)) {
err = nilfs_bmap_read(ii->i_bmap, NULL);
if (err < 0)
- goto failed_bmap;
+ goto failed_after_creation;
set_bit(NILFS_I_BMAP, &ii->i_state);
/* No lock is needed; iget() ensures it. */
@@ -399,21 +412,24 @@ struct inode *nilfs_new_inode(struct inode *dir, umode_t mode)
spin_lock(&nilfs->ns_next_gen_lock);
inode->i_generation = nilfs->ns_next_generation++;
spin_unlock(&nilfs->ns_next_gen_lock);
- insert_inode_hash(inode);
+ if (nilfs_insert_inode_locked(inode, root, ino) < 0) {
+ err = -EIO;
+ goto failed_after_creation;
+ }
err = nilfs_init_acl(inode, dir);
if (unlikely(err))
- goto failed_acl; /* never occur. When supporting
+ goto failed_after_creation; /* never occur. When supporting
nilfs_init_acl(), proper cancellation of
above jobs should be considered */
return inode;
- failed_acl:
- failed_bmap:
+ failed_after_creation:
clear_nlink(inode);
+ unlock_new_inode(inode);
iput(inode); /* raw_inode will be deleted through
- generic_delete_inode() */
+ nilfs_evict_inode() */
goto failed;
failed_ifile_create_inode:
@@ -461,8 +477,8 @@ int nilfs_read_inode_common(struct inode *inode,
inode->i_atime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
inode->i_ctime.tv_nsec = le32_to_cpu(raw_inode->i_ctime_nsec);
inode->i_mtime.tv_nsec = le32_to_cpu(raw_inode->i_mtime_nsec);
- if (inode->i_nlink == 0 && inode->i_mode == 0)
- return -EINVAL; /* this inode is deleted */
+ if (inode->i_nlink == 0)
+ return -ESTALE; /* this inode is deleted */
inode->i_blocks = le64_to_cpu(raw_inode->i_blocks);
ii->i_flags = le32_to_cpu(raw_inode->i_flags);
diff --git a/fs/nilfs2/namei.c b/fs/nilfs2/namei.c
index 9de78f0..0f84b25 100644
--- a/fs/nilfs2/namei.c
+++ b/fs/nilfs2/namei.c
@@ -51,9 +51,11 @@ static inline int nilfs_add_nondir(struct dentry *dentry, struct inode *inode)
int err = nilfs_add_link(dentry, inode);
if (!err) {
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
return 0;
}
inode_dec_link_count(inode);
+ unlock_new_inode(inode);
iput(inode);
return err;
}
@@ -182,6 +184,7 @@ out:
out_fail:
drop_nlink(inode);
nilfs_mark_inode_dirty(inode);
+ unlock_new_inode(inode);
iput(inode);
goto out;
}
@@ -201,11 +204,15 @@ static int nilfs_link(struct dentry *old_dentry, struct inode *dir,
inode_inc_link_count(inode);
ihold(inode);
- err = nilfs_add_nondir(dentry, inode);
- if (!err)
+ err = nilfs_add_link(dentry, inode);
+ if (!err) {
+ d_instantiate(dentry, inode);
err = nilfs_transaction_commit(dir->i_sb);
- else
+ } else {
+ inode_dec_link_count(inode);
+ iput(inode);
nilfs_transaction_abort(dir->i_sb);
+ }
return err;
}
@@ -243,6 +250,7 @@ static int nilfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
nilfs_mark_inode_dirty(inode);
d_instantiate(dentry, inode);
+ unlock_new_inode(inode);
out:
if (!err)
err = nilfs_transaction_commit(dir->i_sb);
@@ -255,6 +263,7 @@ out_fail:
drop_nlink(inode);
drop_nlink(inode);
nilfs_mark_inode_dirty(inode);
+ unlock_new_inode(inode);
iput(inode);
out_dir:
drop_nlink(dir);
diff --git a/fs/nilfs2/the_nilfs.c b/fs/nilfs2/the_nilfs.c
index 9da25fe..69bd801 100644
--- a/fs/nilfs2/the_nilfs.c
+++ b/fs/nilfs2/the_nilfs.c
@@ -808,8 +808,7 @@ void nilfs_put_root(struct nilfs_root *root)
spin_lock(&nilfs->ns_cptree_lock);
rb_erase(&root->rb_node, &nilfs->ns_cptree);
spin_unlock(&nilfs->ns_cptree_lock);
- if (root->ifile)
- iput(root->ifile);
+ iput(root->ifile);
kfree(root);
}
diff --git a/fs/notify/fdinfo.c b/fs/notify/fdinfo.c
index 9d7e2b9..6ffd220 100644
--- a/fs/notify/fdinfo.c
+++ b/fs/notify/fdinfo.c
@@ -20,25 +20,24 @@
#if defined(CONFIG_INOTIFY_USER) || defined(CONFIG_FANOTIFY)
-static int show_fdinfo(struct seq_file *m, struct file *f,
- int (*show)(struct seq_file *m, struct fsnotify_mark *mark))
+static void show_fdinfo(struct seq_file *m, struct file *f,
+ void (*show)(struct seq_file *m,
+ struct fsnotify_mark *mark))
{
struct fsnotify_group *group = f->private_data;
struct fsnotify_mark *mark;
- int ret = 0;
mutex_lock(&group->mark_mutex);
list_for_each_entry(mark, &group->marks_list, g_list) {
- ret = show(m, mark);
- if (ret)
+ show(m, mark);
+ if (seq_has_overflowed(m))
break;
}
mutex_unlock(&group->mark_mutex);
- return ret;
}
#if defined(CONFIG_EXPORTFS)
-static int show_mark_fhandle(struct seq_file *m, struct inode *inode)
+static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
{
struct {
struct file_handle handle;
@@ -52,71 +51,62 @@ static int show_mark_fhandle(struct seq_file *m, struct inode *inode)
ret = exportfs_encode_inode_fh(inode, (struct fid *)f.handle.f_handle, &size, 0);
if ((ret == FILEID_INVALID) || (ret < 0)) {
WARN_ONCE(1, "Can't encode file handler for inotify: %d\n", ret);
- return 0;
+ return;
}
f.handle.handle_type = ret;
f.handle.handle_bytes = size * sizeof(u32);
- ret = seq_printf(m, "fhandle-bytes:%x fhandle-type:%x f_handle:",
- f.handle.handle_bytes, f.handle.handle_type);
+ seq_printf(m, "fhandle-bytes:%x fhandle-type:%x f_handle:",
+ f.handle.handle_bytes, f.handle.handle_type);
for (i = 0; i < f.handle.handle_bytes; i++)
- ret |= seq_printf(m, "%02x", (int)f.handle.f_handle[i]);
-
- return ret;
+ seq_printf(m, "%02x", (int)f.handle.f_handle[i]);
}
#else
-static int show_mark_fhandle(struct seq_file *m, struct inode *inode)
+static void show_mark_fhandle(struct seq_file *m, struct inode *inode)
{
- return 0;
}
#endif
#ifdef CONFIG_INOTIFY_USER
-static int inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
+static void inotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
{
struct inotify_inode_mark *inode_mark;
struct inode *inode;
- int ret = 0;
if (!(mark->flags & (FSNOTIFY_MARK_FLAG_ALIVE | FSNOTIFY_MARK_FLAG_INODE)))
- return 0;
+ return;
inode_mark = container_of(mark, struct inotify_inode_mark, fsn_mark);
inode = igrab(mark->i.inode);
if (inode) {
- ret = seq_printf(m, "inotify wd:%x ino:%lx sdev:%x "
- "mask:%x ignored_mask:%x ",
- inode_mark->wd, inode->i_ino,
- inode->i_sb->s_dev,
- mark->mask, mark->ignored_mask);
- ret |= show_mark_fhandle(m, inode);
- ret |= seq_putc(m, '\n');
+ seq_printf(m, "inotify wd:%x ino:%lx sdev:%x mask:%x ignored_mask:%x ",
+ inode_mark->wd, inode->i_ino, inode->i_sb->s_dev,
+ mark->mask, mark->ignored_mask);
+ show_mark_fhandle(m, inode);
+ seq_putc(m, '\n');
iput(inode);
}
-
- return ret;
}
-int inotify_show_fdinfo(struct seq_file *m, struct file *f)
+void inotify_show_fdinfo(struct seq_file *m, struct file *f)
{
- return show_fdinfo(m, f, inotify_fdinfo);
+ show_fdinfo(m, f, inotify_fdinfo);
}
#endif /* CONFIG_INOTIFY_USER */
#ifdef CONFIG_FANOTIFY
-static int fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
+static void fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
{
unsigned int mflags = 0;
struct inode *inode;
- int ret = 0;
if (!(mark->flags & FSNOTIFY_MARK_FLAG_ALIVE))
- return 0;
+ return;
if (mark->flags & FSNOTIFY_MARK_FLAG_IGNORED_SURV_MODIFY)
mflags |= FAN_MARK_IGNORED_SURV_MODIFY;
@@ -124,26 +114,22 @@ static int fanotify_fdinfo(struct seq_file *m, struct fsnotify_mark *mark)
if (mark->flags & FSNOTIFY_MARK_FLAG_INODE) {
inode = igrab(mark->i.inode);
if (!inode)
- goto out;
- ret = seq_printf(m, "fanotify ino:%lx sdev:%x "
- "mflags:%x mask:%x ignored_mask:%x ",
- inode->i_ino, inode->i_sb->s_dev,
- mflags, mark->mask, mark->ignored_mask);
- ret |= show_mark_fhandle(m, inode);
- ret |= seq_putc(m, '\n');
+ return;
+ seq_printf(m, "fanotify ino:%lx sdev:%x mflags:%x mask:%x ignored_mask:%x ",
+ inode->i_ino, inode->i_sb->s_dev,
+ mflags, mark->mask, mark->ignored_mask);
+ show_mark_fhandle(m, inode);
+ seq_putc(m, '\n');
iput(inode);
} else if (mark->flags & FSNOTIFY_MARK_FLAG_VFSMOUNT) {
struct mount *mnt = real_mount(mark->m.mnt);
- ret = seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x "
- "ignored_mask:%x\n", mnt->mnt_id, mflags,
- mark->mask, mark->ignored_mask);
+ seq_printf(m, "fanotify mnt_id:%x mflags:%x mask:%x ignored_mask:%x\n",
+ mnt->mnt_id, mflags, mark->mask, mark->ignored_mask);
}
-out:
- return ret;
}
-int fanotify_show_fdinfo(struct seq_file *m, struct file *f)
+void fanotify_show_fdinfo(struct seq_file *m, struct file *f)
{
struct fsnotify_group *group = f->private_data;
unsigned int flags = 0;
@@ -169,7 +155,7 @@ int fanotify_show_fdinfo(struct seq_file *m, struct file *f)
seq_printf(m, "fanotify flags:%x event-flags:%x\n",
flags, group->fanotify_data.f_flags);
- return show_fdinfo(m, f, fanotify_fdinfo);
+ show_fdinfo(m, f, fanotify_fdinfo);
}
#endif /* CONFIG_FANOTIFY */
diff --git a/fs/notify/fdinfo.h b/fs/notify/fdinfo.h
index 556afda..9664c49 100644
--- a/fs/notify/fdinfo.h
+++ b/fs/notify/fdinfo.h
@@ -10,11 +10,11 @@ struct file;
#ifdef CONFIG_PROC_FS
#ifdef CONFIG_INOTIFY_USER
-extern int inotify_show_fdinfo(struct seq_file *m, struct file *f);
+void inotify_show_fdinfo(struct seq_file *m, struct file *f);
#endif
#ifdef CONFIG_FANOTIFY
-extern int fanotify_show_fdinfo(struct seq_file *m, struct file *f);
+void fanotify_show_fdinfo(struct seq_file *m, struct file *f);
#endif
#else /* CONFIG_PROC_FS */
diff --git a/fs/notify/fsnotify.c b/fs/notify/fsnotify.c
index 89326ac..41e39102 100644
--- a/fs/notify/fsnotify.c
+++ b/fs/notify/fsnotify.c
@@ -63,14 +63,14 @@ void __fsnotify_update_child_dentry_flags(struct inode *inode)
spin_lock(&inode->i_lock);
/* run all of the dentries associated with this inode. Since this is a
* directory, there damn well better only be one item on this list */
- hlist_for_each_entry(alias, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(alias, &inode->i_dentry, d_u.d_alias) {
struct dentry *child;
/* run all of the children of the original inode and fix their
* d_flags to indicate parental interest (their parent is the
* original inode) */
spin_lock(&alias->d_lock);
- list_for_each_entry(child, &alias->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &alias->d_subdirs, d_child) {
if (!child->d_inode)
continue;
diff --git a/fs/notify/inotify/inotify_user.c b/fs/notify/inotify/inotify_user.c
index daf7665..283aa31 100644
--- a/fs/notify/inotify/inotify_user.c
+++ b/fs/notify/inotify/inotify_user.c
@@ -227,14 +227,13 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
struct fsnotify_event *kevent;
char __user *start;
int ret;
- DEFINE_WAIT(wait);
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
start = buf;
group = file->private_data;
+ add_wait_queue(&group->notification_waitq, &wait);
while (1) {
- prepare_to_wait(&group->notification_waitq, &wait, TASK_INTERRUPTIBLE);
-
mutex_lock(&group->notification_mutex);
kevent = get_one_event(group, count);
mutex_unlock(&group->notification_mutex);
@@ -264,10 +263,10 @@ static ssize_t inotify_read(struct file *file, char __user *buf,
if (start != buf)
break;
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
+ remove_wait_queue(&group->notification_waitq, &wait);
- finish_wait(&group->notification_waitq, &wait);
if (start != buf && ret != -EFAULT)
ret = buf - start;
return ret;
diff --git a/fs/ntfs/namei.c b/fs/ntfs/namei.c
index 436f360..b3973c2 100644
--- a/fs/ntfs/namei.c
+++ b/fs/ntfs/namei.c
@@ -111,8 +111,8 @@ static struct dentry *ntfs_lookup(struct inode *dir_ino, struct dentry *dent,
unsigned long dent_ino;
int uname_len;
- ntfs_debug("Looking up %s in directory inode 0x%lx.",
- dent->d_name.name, dir_ino->i_ino);
+ ntfs_debug("Looking up %pd in directory inode 0x%lx.",
+ dent, dir_ino->i_ino);
/* Convert the name of the dentry to Unicode. */
uname_len = ntfs_nlstoucs(vol, dent->d_name.name, dent->d_name.len,
&uname);
diff --git a/fs/ocfs2/aops.c b/fs/ocfs2/aops.c
index 1ef547e..d9f2229 100644
--- a/fs/ocfs2/aops.c
+++ b/fs/ocfs2/aops.c
@@ -1251,7 +1251,7 @@ static int ocfs2_write_cluster(struct address_space *mapping,
ret = ocfs2_extent_map_get_blocks(inode, v_blkno, &p_blkno, NULL,
NULL);
if (ret < 0) {
- ocfs2_error(inode->i_sb, "Corrupting extend for inode %llu, "
+ mlog(ML_ERROR, "Get physical blkno failed for inode %llu, "
"at logical block %llu",
(unsigned long long)OCFS2_I(inode)->ip_blkno,
(unsigned long long)v_blkno);
diff --git a/fs/ocfs2/cluster/heartbeat.c b/fs/ocfs2/cluster/heartbeat.c
index eb9d487..16eff45 100644
--- a/fs/ocfs2/cluster/heartbeat.c
+++ b/fs/ocfs2/cluster/heartbeat.c
@@ -1127,10 +1127,10 @@ static int o2hb_thread(void *data)
elapsed_msec = o2hb_elapsed_msecs(&before_hb, &after_hb);
mlog(ML_HEARTBEAT,
- "start = %lu.%lu, end = %lu.%lu, msec = %u\n",
+ "start = %lu.%lu, end = %lu.%lu, msec = %u, ret = %d\n",
before_hb.tv_sec, (unsigned long) before_hb.tv_usec,
after_hb.tv_sec, (unsigned long) after_hb.tv_usec,
- elapsed_msec);
+ elapsed_msec, ret);
if (!kthread_should_stop() &&
elapsed_msec < reg->hr_timeout_ms) {
diff --git a/fs/ocfs2/cluster/tcp.c b/fs/ocfs2/cluster/tcp.c
index a960440..2e355e0 100644
--- a/fs/ocfs2/cluster/tcp.c
+++ b/fs/ocfs2/cluster/tcp.c
@@ -1736,7 +1736,7 @@ static void o2net_connect_expired(struct work_struct *work)
o2net_idle_timeout() / 1000,
o2net_idle_timeout() % 1000);
- o2net_set_nn_state(nn, NULL, 0, -ENOTCONN);
+ o2net_set_nn_state(nn, NULL, 0, 0);
}
spin_unlock(&nn->nn_lock);
}
diff --git a/fs/ocfs2/dcache.c b/fs/ocfs2/dcache.c
index e2e05a1..4fda7a5 100644
--- a/fs/ocfs2/dcache.c
+++ b/fs/ocfs2/dcache.c
@@ -172,7 +172,7 @@ struct dentry *ocfs2_find_local_alias(struct inode *inode,
struct dentry *dentry;
spin_lock(&inode->i_lock);
- hlist_for_each_entry(dentry, &inode->i_dentry, d_alias) {
+ hlist_for_each_entry(dentry, &inode->i_dentry, d_u.d_alias) {
spin_lock(&dentry->d_lock);
if (ocfs2_match_dentry(dentry, parent_blkno, skip_unhashed)) {
trace_ocfs2_find_local_alias(dentry->d_name.len,
@@ -251,8 +251,8 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
if (dl) {
mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno,
- " \"%.*s\": old parent: %llu, new: %llu\n",
- dentry->d_name.len, dentry->d_name.name,
+ " \"%pd\": old parent: %llu, new: %llu\n",
+ dentry,
(unsigned long long)parent_blkno,
(unsigned long long)dl->dl_parent_blkno);
return 0;
@@ -277,8 +277,8 @@ int ocfs2_dentry_attach_lock(struct dentry *dentry,
(unsigned long long)OCFS2_I(inode)->ip_blkno);
mlog_bug_on_msg(dl->dl_parent_blkno != parent_blkno,
- " \"%.*s\": old parent: %llu, new: %llu\n",
- dentry->d_name.len, dentry->d_name.name,
+ " \"%pd\": old parent: %llu, new: %llu\n",
+ dentry,
(unsigned long long)parent_blkno,
(unsigned long long)dl->dl_parent_blkno);
@@ -406,17 +406,15 @@ static void ocfs2_dentry_iput(struct dentry *dentry, struct inode *inode)
if (inode)
ino = (unsigned long long)OCFS2_I(inode)->ip_blkno;
mlog(ML_ERROR, "Dentry is missing cluster lock. "
- "inode: %llu, d_flags: 0x%x, d_name: %.*s\n",
- ino, dentry->d_flags, dentry->d_name.len,
- dentry->d_name.name);
+ "inode: %llu, d_flags: 0x%x, d_name: %pd\n",
+ ino, dentry->d_flags, dentry);
}
goto out;
}
- mlog_bug_on_msg(dl->dl_count == 0, "dentry: %.*s, count: %u\n",
- dentry->d_name.len, dentry->d_name.name,
- dl->dl_count);
+ mlog_bug_on_msg(dl->dl_count == 0, "dentry: %pd, count: %u\n",
+ dentry, dl->dl_count);
ocfs2_dentry_lock_put(OCFS2_SB(dentry->d_sb), dl);
diff --git a/fs/ocfs2/dir.c b/fs/ocfs2/dir.c
index 0717662..79d56dc 100644
--- a/fs/ocfs2/dir.c
+++ b/fs/ocfs2/dir.c
@@ -744,7 +744,7 @@ restart:
if (ocfs2_read_dir_block(dir, block, &bh, 0)) {
/* read error, skip block & hope for the best.
* ocfs2_read_dir_block() has released the bh. */
- ocfs2_error(dir->i_sb, "reading directory %llu, "
+ mlog(ML_ERROR, "reading directory %llu, "
"offset %lu\n",
(unsigned long long)OCFS2_I(dir)->ip_blkno,
block);
@@ -2073,10 +2073,12 @@ struct ocfs2_empty_dir_priv {
unsigned seen_other;
unsigned dx_dir;
};
-static int ocfs2_empty_dir_filldir(void *priv, const char *name, int name_len,
- loff_t pos, u64 ino, unsigned type)
+static int ocfs2_empty_dir_filldir(struct dir_context *ctx, const char *name,
+ int name_len, loff_t pos, u64 ino,
+ unsigned type)
{
- struct ocfs2_empty_dir_priv *p = priv;
+ struct ocfs2_empty_dir_priv *p =
+ container_of(ctx, struct ocfs2_empty_dir_priv, ctx);
/*
* Check the positions of "." and ".." records to be sure
diff --git a/fs/ocfs2/dlm/dlmdomain.c b/fs/ocfs2/dlm/dlmdomain.c
index 02d315f..50a59d2 100644
--- a/fs/ocfs2/dlm/dlmdomain.c
+++ b/fs/ocfs2/dlm/dlmdomain.c
@@ -877,7 +877,7 @@ static int dlm_query_join_handler(struct o2net_msg *msg, u32 len, void *data,
* to be put in someone's domain map.
* Also, explicitly disallow joining at certain troublesome
* times (ie. during recovery). */
- if (dlm && dlm->dlm_state != DLM_CTXT_LEAVING) {
+ if (dlm->dlm_state != DLM_CTXT_LEAVING) {
int bit = query->node_idx;
spin_lock(&dlm->spinlock);
diff --git a/fs/ocfs2/dlm/dlmmaster.c b/fs/ocfs2/dlm/dlmmaster.c
index 215e41a..3689b35 100644
--- a/fs/ocfs2/dlm/dlmmaster.c
+++ b/fs/ocfs2/dlm/dlmmaster.c
@@ -1460,6 +1460,18 @@ way_up_top:
/* take care of the easy cases up front */
spin_lock(&res->spinlock);
+
+ /*
+ * Right after dlm spinlock was released, dlm_thread could have
+ * purged the lockres. Check if lockres got unhashed. If so
+ * start over.
+ */
+ if (hlist_unhashed(&res->hash_node)) {
+ spin_unlock(&res->spinlock);
+ dlm_lockres_put(res);
+ goto way_up_top;
+ }
+
if (res->state & (DLM_LOCK_RES_RECOVERING|
DLM_LOCK_RES_MIGRATING)) {
spin_unlock(&res->spinlock);
diff --git a/fs/ocfs2/dlm/dlmrecovery.c b/fs/ocfs2/dlm/dlmrecovery.c
index 3365839..79b5af5 100644
--- a/fs/ocfs2/dlm/dlmrecovery.c
+++ b/fs/ocfs2/dlm/dlmrecovery.c
@@ -1656,14 +1656,18 @@ int dlm_do_master_requery(struct dlm_ctxt *dlm, struct dlm_lock_resource *res,
req.namelen = res->lockname.len;
memcpy(req.name, res->lockname.name, res->lockname.len);
+resend:
ret = o2net_send_message(DLM_MASTER_REQUERY_MSG, dlm->key,
&req, sizeof(req), nodenum, &status);
- /* XXX: negative status not handled properly here. */
if (ret < 0)
mlog(ML_ERROR, "Error %d when sending message %u (key "
"0x%x) to node %u\n", ret, DLM_MASTER_REQUERY_MSG,
dlm->key, nodenum);
- else {
+ else if (status == -ENOMEM) {
+ mlog_errno(status);
+ msleep(50);
+ goto resend;
+ } else {
BUG_ON(status < 0);
BUG_ON(status > DLM_LOCK_RES_OWNER_UNKNOWN);
*real_master = (u8) (status & 0xff);
@@ -1705,9 +1709,13 @@ int dlm_master_requery_handler(struct o2net_msg *msg, u32 len, void *data,
int ret = dlm_dispatch_assert_master(dlm, res,
0, 0, flags);
if (ret < 0) {
- mlog_errno(-ENOMEM);
- /* retry!? */
- BUG();
+ mlog_errno(ret);
+ spin_unlock(&res->spinlock);
+ dlm_lockres_put(res);
+ spin_unlock(&dlm->spinlock);
+ dlm_put(dlm);
+ /* sender will take care of this and retry */
+ return ret;
} else
__dlm_lockres_grab_inflight_worker(dlm, res);
spin_unlock(&res->spinlock);
diff --git a/fs/ocfs2/dlmfs/dlmfs.c b/fs/ocfs2/dlmfs/dlmfs.c
index 09b7d9d..57c40e3 100644
--- a/fs/ocfs2/dlmfs/dlmfs.c
+++ b/fs/ocfs2/dlmfs/dlmfs.c
@@ -565,8 +565,8 @@ static int dlmfs_unlink(struct inode *dir,
* to acquire a lock, this basically destroys our lockres. */
status = user_dlm_destroy_lock(&DLMFS_I(inode)->ip_lockres);
if (status < 0) {
- mlog(ML_ERROR, "unlink %.*s, error %d from destroy\n",
- dentry->d_name.len, dentry->d_name.name, status);
+ mlog(ML_ERROR, "unlink %pd, error %d from destroy\n",
+ dentry, status);
goto bail;
}
status = simple_unlink(dir, dentry);
diff --git a/fs/ocfs2/dlmglue.c b/fs/ocfs2/dlmglue.c
index 21262f2..1c423af 100644
--- a/fs/ocfs2/dlmglue.c
+++ b/fs/ocfs2/dlmglue.c
@@ -861,8 +861,13 @@ static inline void ocfs2_generic_handle_convert_action(struct ocfs2_lock_res *lo
* We set the OCFS2_LOCK_UPCONVERT_FINISHING flag before clearing
* the OCFS2_LOCK_BUSY flag to prevent the dc thread from
* downconverting the lock before the upconvert has fully completed.
+ * Do not prevent the dc thread from downconverting if NONBLOCK lock
+ * had already returned.
*/
- lockres_or_flags(lockres, OCFS2_LOCK_UPCONVERT_FINISHING);
+ if (!(lockres->l_flags & OCFS2_LOCK_NONBLOCK_FINISHED))
+ lockres_or_flags(lockres, OCFS2_LOCK_UPCONVERT_FINISHING);
+ else
+ lockres_clear_flags(lockres, OCFS2_LOCK_NONBLOCK_FINISHED);
lockres_clear_flags(lockres, OCFS2_LOCK_BUSY);
}
@@ -1324,13 +1329,12 @@ static void lockres_add_mask_waiter(struct ocfs2_lock_res *lockres,
/* returns 0 if the mw that was removed was already satisfied, -EBUSY
* if the mask still hadn't reached its goal */
-static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
+static int __lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
struct ocfs2_mask_waiter *mw)
{
- unsigned long flags;
int ret = 0;
- spin_lock_irqsave(&lockres->l_lock, flags);
+ assert_spin_locked(&lockres->l_lock);
if (!list_empty(&mw->mw_item)) {
if ((lockres->l_flags & mw->mw_mask) != mw->mw_goal)
ret = -EBUSY;
@@ -1338,6 +1342,18 @@ static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
list_del_init(&mw->mw_item);
init_completion(&mw->mw_complete);
}
+
+ return ret;
+}
+
+static int lockres_remove_mask_waiter(struct ocfs2_lock_res *lockres,
+ struct ocfs2_mask_waiter *mw)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ ret = __lockres_remove_mask_waiter(lockres, mw);
spin_unlock_irqrestore(&lockres->l_lock, flags);
return ret;
@@ -1373,6 +1389,7 @@ static int __ocfs2_cluster_lock(struct ocfs2_super *osb,
unsigned long flags;
unsigned int gen;
int noqueue_attempted = 0;
+ int dlm_locked = 0;
ocfs2_init_mask_waiter(&mw);
@@ -1481,6 +1498,7 @@ again:
ocfs2_recover_from_dlm_error(lockres, 1);
goto out;
}
+ dlm_locked = 1;
mlog(0, "lock %s, successful return from ocfs2_dlm_lock\n",
lockres->l_name);
@@ -1514,10 +1532,17 @@ out:
if (wait && arg_flags & OCFS2_LOCK_NONBLOCK &&
mw.mw_mask & (OCFS2_LOCK_BUSY|OCFS2_LOCK_BLOCKED)) {
wait = 0;
- if (lockres_remove_mask_waiter(lockres, &mw))
+ spin_lock_irqsave(&lockres->l_lock, flags);
+ if (__lockres_remove_mask_waiter(lockres, &mw)) {
+ if (dlm_locked)
+ lockres_or_flags(lockres,
+ OCFS2_LOCK_NONBLOCK_FINISHED);
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
ret = -EAGAIN;
- else
+ } else {
+ spin_unlock_irqrestore(&lockres->l_lock, flags);
goto again;
+ }
}
if (wait) {
ret = ocfs2_wait_for_mask(&mw);
@@ -3725,8 +3750,7 @@ static int ocfs2_dentry_convert_worker(struct ocfs2_lock_res *lockres,
break;
spin_unlock(&dentry_attach_lock);
- mlog(0, "d_delete(%.*s);\n", dentry->d_name.len,
- dentry->d_name.name);
+ mlog(0, "d_delete(%pd);\n", dentry);
/*
* The following dcache calls may do an
diff --git a/fs/ocfs2/file.c b/fs/ocfs2/file.c
index 324dc93..69fb9f7 100644
--- a/fs/ocfs2/file.c
+++ b/fs/ocfs2/file.c
@@ -2381,9 +2381,7 @@ out_dio:
if (ret < 0)
written = ret;
- if (!ret && ((old_size != i_size_read(inode)) ||
- (old_clusters != OCFS2_I(inode)->ip_clusters) ||
- has_refcount)) {
+ if (!ret) {
ret = jbd2_journal_force_commit(osb->journal->j_journal);
if (ret < 0)
written = ret;
diff --git a/fs/ocfs2/inode.c b/fs/ocfs2/inode.c
index 437de7f..c8b25de 100644
--- a/fs/ocfs2/inode.c
+++ b/fs/ocfs2/inode.c
@@ -540,8 +540,7 @@ bail:
if (status < 0)
make_bad_inode(inode);
- if (args && bh)
- brelse(bh);
+ brelse(bh);
return status;
}
diff --git a/fs/ocfs2/inode.h b/fs/ocfs2/inode.h
index a9b76de..ca3431e 100644
--- a/fs/ocfs2/inode.h
+++ b/fs/ocfs2/inode.h
@@ -80,6 +80,8 @@ struct ocfs2_inode_info
*/
tid_t i_sync_tid;
tid_t i_datasync_tid;
+
+ struct dquot *i_dquot[MAXQUOTAS];
};
/*
diff --git a/fs/ocfs2/journal.c b/fs/ocfs2/journal.c
index 4b0c688..4f502382 100644
--- a/fs/ocfs2/journal.c
+++ b/fs/ocfs2/journal.c
@@ -1982,10 +1982,12 @@ struct ocfs2_orphan_filldir_priv {
struct ocfs2_super *osb;
};
-static int ocfs2_orphan_filldir(void *priv, const char *name, int name_len,
- loff_t pos, u64 ino, unsigned type)
+static int ocfs2_orphan_filldir(struct dir_context *ctx, const char *name,
+ int name_len, loff_t pos, u64 ino,
+ unsigned type)
{
- struct ocfs2_orphan_filldir_priv *p = priv;
+ struct ocfs2_orphan_filldir_priv *p =
+ container_of(ctx, struct ocfs2_orphan_filldir_priv, ctx);
struct inode *iter;
if (name_len == 1 && !strncmp(".", name, 1))
diff --git a/fs/ocfs2/move_extents.c b/fs/ocfs2/move_extents.c
index 74caffe..56a768d 100644
--- a/fs/ocfs2/move_extents.c
+++ b/fs/ocfs2/move_extents.c
@@ -904,9 +904,6 @@ static int ocfs2_move_extents(struct ocfs2_move_extents_context *context)
struct buffer_head *di_bh = NULL;
struct ocfs2_super *osb = OCFS2_SB(inode->i_sb);
- if (!inode)
- return -ENOENT;
-
if (ocfs2_is_hard_readonly(osb) || ocfs2_is_soft_readonly(osb))
return -EROFS;
diff --git a/fs/ocfs2/ocfs2.h b/fs/ocfs2/ocfs2.h
index bbec539..7d6b7d0 100644
--- a/fs/ocfs2/ocfs2.h
+++ b/fs/ocfs2/ocfs2.h
@@ -144,6 +144,12 @@ enum ocfs2_unlock_action {
* before the upconvert
* has completed */
+#define OCFS2_LOCK_NONBLOCK_FINISHED (0x00001000) /* NONBLOCK cluster
+ * lock has already
+ * returned, do not block
+ * dc thread from
+ * downconverting */
+
struct ocfs2_lock_res_ops;
typedef void (*ocfs2_lock_callback)(int status, unsigned long data);
diff --git a/fs/ocfs2/slot_map.c b/fs/ocfs2/slot_map.c
index a88b2a4..d5493e3 100644
--- a/fs/ocfs2/slot_map.c
+++ b/fs/ocfs2/slot_map.c
@@ -306,7 +306,7 @@ int ocfs2_slot_to_node_num_locked(struct ocfs2_super *osb, int slot_num,
assert_spin_locked(&osb->osb_lock);
BUG_ON(slot_num < 0);
- BUG_ON(slot_num > osb->max_slots);
+ BUG_ON(slot_num >= osb->max_slots);
if (!si->si_slots[slot_num].sl_valid)
return -ENOENT;
diff --git a/fs/ocfs2/super.c b/fs/ocfs2/super.c
index 93c85bc..8372317 100644
--- a/fs/ocfs2/super.c
+++ b/fs/ocfs2/super.c
@@ -143,6 +143,11 @@ static int ocfs2_susp_quotas(struct ocfs2_super *osb, int unsuspend);
static int ocfs2_enable_quotas(struct ocfs2_super *osb);
static void ocfs2_disable_quotas(struct ocfs2_super *osb);
+static struct dquot **ocfs2_get_dquots(struct inode *inode)
+{
+ return OCFS2_I(inode)->i_dquot;
+}
+
static const struct super_operations ocfs2_sops = {
.statfs = ocfs2_statfs,
.alloc_inode = ocfs2_alloc_inode,
@@ -155,6 +160,7 @@ static const struct super_operations ocfs2_sops = {
.show_options = ocfs2_show_options,
.quota_read = ocfs2_quota_read,
.quota_write = ocfs2_quota_write,
+ .get_dquots = ocfs2_get_dquots,
};
enum {
@@ -563,6 +569,7 @@ static struct inode *ocfs2_alloc_inode(struct super_block *sb)
oi->i_sync_tid = 0;
oi->i_datasync_tid = 0;
+ memset(&oi->i_dquot, 0, sizeof(oi->i_dquot));
jbd2_journal_init_jbd_inode(&oi->ip_jinode, &oi->vfs_inode);
return &oi->vfs_inode;
@@ -1622,8 +1629,9 @@ static int __init ocfs2_init(void)
ocfs2_debugfs_root = debugfs_create_dir("ocfs2", NULL);
if (!ocfs2_debugfs_root) {
- status = -EFAULT;
+ status = -ENOMEM;
mlog(ML_ERROR, "Unable to create ocfs2 debugfs root.\n");
+ goto out4;
}
ocfs2_set_locking_protocol();
@@ -2073,6 +2081,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
sb->s_export_op = &ocfs2_export_ops;
sb->s_qcop = &ocfs2_quotactl_ops;
sb->dq_op = &ocfs2_quota_operations;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
sb->s_xattr = ocfs2_xattr_handlers;
sb->s_time_gran = 1;
sb->s_flags |= MS_NOATIME;
diff --git a/fs/ocfs2/xattr.c b/fs/ocfs2/xattr.c
index 016f01d..662f8de 100644
--- a/fs/ocfs2/xattr.c
+++ b/fs/ocfs2/xattr.c
@@ -1284,7 +1284,7 @@ int ocfs2_xattr_get_nolock(struct inode *inode,
return -EOPNOTSUPP;
if (!(oi->ip_dyn_features & OCFS2_HAS_XATTR_FL))
- ret = -ENODATA;
+ return -ENODATA;
xis.inode_bh = xbs.inode_bh = di_bh;
di = (struct ocfs2_dinode *)di_bh->b_data;
diff --git a/fs/open.c b/fs/open.c
index de92c13..b1bf3d5 100644
--- a/fs/open.c
+++ b/fs/open.c
@@ -516,7 +516,7 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd, umode_t, mode)
int err = -EBADF;
if (f.file) {
- audit_inode(NULL, f.file->f_path.dentry, 0);
+ audit_file(f.file);
err = chmod_common(&f.file->f_path, mode);
fdput(f);
}
@@ -642,7 +642,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd, uid_t, user, gid_t, group)
error = mnt_want_write_file(f.file);
if (error)
goto out_fput;
- audit_inode(NULL, f.file->f_path.dentry, 0);
+ audit_file(f.file);
error = chown_common(&f.file->f_path, user, group);
mnt_drop_write_file(f.file);
out_fput:
diff --git a/fs/overlayfs/readdir.c b/fs/overlayfs/readdir.c
index ab1e3dc..c020599 100644
--- a/fs/overlayfs/readdir.c
+++ b/fs/overlayfs/readdir.c
@@ -180,10 +180,12 @@ static void ovl_cache_put(struct ovl_dir_file *od, struct dentry *dentry)
}
}
-static int ovl_fill_merge(void *buf, const char *name, int namelen,
- loff_t offset, u64 ino, unsigned int d_type)
+static int ovl_fill_merge(struct dir_context *ctx, const char *name,
+ int namelen, loff_t offset, u64 ino,
+ unsigned int d_type)
{
- struct ovl_readdir_data *rdd = buf;
+ struct ovl_readdir_data *rdd =
+ container_of(ctx, struct ovl_readdir_data, ctx);
rdd->count++;
if (!rdd->is_merge)
diff --git a/fs/proc/array.c b/fs/proc/array.c
index cd3653e..bd117d0 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -157,20 +157,29 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
struct user_namespace *user_ns = seq_user_ns(m);
struct group_info *group_info;
int g;
- struct fdtable *fdt = NULL;
+ struct task_struct *tracer;
const struct cred *cred;
- pid_t ppid, tpid;
+ pid_t ppid, tpid = 0, tgid, ngid;
+ unsigned int max_fds = 0;
rcu_read_lock();
ppid = pid_alive(p) ?
task_tgid_nr_ns(rcu_dereference(p->real_parent), ns) : 0;
- tpid = 0;
- if (pid_alive(p)) {
- struct task_struct *tracer = ptrace_parent(p);
- if (tracer)
- tpid = task_pid_nr_ns(tracer, ns);
- }
+
+ tracer = ptrace_parent(p);
+ if (tracer)
+ tpid = task_pid_nr_ns(tracer, ns);
+
+ tgid = task_tgid_nr_ns(p, ns);
+ ngid = task_numa_group_id(p);
cred = get_task_cred(p);
+
+ task_lock(p);
+ if (p->files)
+ max_fds = files_fdtable(p->files)->max_fds;
+ task_unlock(p);
+ rcu_read_unlock();
+
seq_printf(m,
"State:\t%s\n"
"Tgid:\t%d\n"
@@ -179,12 +188,10 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
"PPid:\t%d\n"
"TracerPid:\t%d\n"
"Uid:\t%d\t%d\t%d\t%d\n"
- "Gid:\t%d\t%d\t%d\t%d\n",
+ "Gid:\t%d\t%d\t%d\t%d\n"
+ "FDSize:\t%d\nGroups:\t",
get_task_state(p),
- task_tgid_nr_ns(p, ns),
- task_numa_group_id(p),
- pid_nr_ns(pid, ns),
- ppid, tpid,
+ tgid, ngid, pid_nr_ns(pid, ns), ppid, tpid,
from_kuid_munged(user_ns, cred->uid),
from_kuid_munged(user_ns, cred->euid),
from_kuid_munged(user_ns, cred->suid),
@@ -192,20 +199,10 @@ static inline void task_state(struct seq_file *m, struct pid_namespace *ns,
from_kgid_munged(user_ns, cred->gid),
from_kgid_munged(user_ns, cred->egid),
from_kgid_munged(user_ns, cred->sgid),
- from_kgid_munged(user_ns, cred->fsgid));
-
- task_lock(p);
- if (p->files)
- fdt = files_fdtable(p->files);
- seq_printf(m,
- "FDSize:\t%d\n"
- "Groups:\t",
- fdt ? fdt->max_fds : 0);
- rcu_read_unlock();
+ from_kgid_munged(user_ns, cred->fsgid),
+ max_fds);
group_info = cred->group_info;
- task_unlock(p);
-
for (g = 0; g < group_info->ngroups; g++)
seq_printf(m, "%d ",
from_kgid_munged(user_ns, GROUP_AT(group_info, g)));
diff --git a/fs/proc/base.c b/fs/proc/base.c
index 772efa4..590aeda 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -2618,6 +2618,9 @@ static void proc_flush_task_mnt(struct vfsmount *mnt, pid_t pid, pid_t tgid)
dput(dentry);
}
+ if (pid == tgid)
+ return;
+
name.name = buf;
name.len = snprintf(buf, sizeof(buf), "%d", tgid);
leader = d_hash_and_lookup(mnt->mnt_root, &name);
@@ -2789,7 +2792,7 @@ retry:
int proc_pid_readdir(struct file *file, struct dir_context *ctx)
{
struct tgid_iter iter;
- struct pid_namespace *ns = file->f_dentry->d_sb->s_fs_info;
+ struct pid_namespace *ns = file_inode(file)->i_sb->s_fs_info;
loff_t pos = ctx->pos;
if (pos >= PID_MAX_LIMIT + TGID_OFFSET)
@@ -3095,7 +3098,7 @@ static int proc_task_readdir(struct file *file, struct dir_context *ctx)
/* f_version caches the tgid value that the last readdir call couldn't
* return. lseek aka telldir automagically resets f_version to 0.
*/
- ns = file->f_dentry->d_sb->s_fs_info;
+ ns = inode->i_sb->s_fs_info;
tid = (int)file->f_version;
file->f_version = 0;
for (task = first_tid(proc_pid(inode), tid, ctx->pos - 2, ns);
diff --git a/fs/proc/fd.c b/fs/proc/fd.c
index e11d7c5..8e5ad83 100644
--- a/fs/proc/fd.c
+++ b/fs/proc/fd.c
@@ -53,7 +53,8 @@ static int seq_show(struct seq_file *m, void *v)
(long long)file->f_pos, f_flags,
real_mount(file->f_path.mnt)->mnt_id);
if (file->f_op->show_fdinfo)
- ret = file->f_op->show_fdinfo(m, file);
+ file->f_op->show_fdinfo(m, file);
+ ret = seq_has_overflowed(m);
fput(file);
}
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index 317b726..7fea132 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -31,9 +31,73 @@ static DEFINE_SPINLOCK(proc_subdir_lock);
static int proc_match(unsigned int len, const char *name, struct proc_dir_entry *de)
{
- if (de->namelen != len)
- return 0;
- return !memcmp(name, de->name, len);
+ if (len < de->namelen)
+ return -1;
+ if (len > de->namelen)
+ return 1;
+
+ return memcmp(name, de->name, len);
+}
+
+static struct proc_dir_entry *pde_subdir_first(struct proc_dir_entry *dir)
+{
+ return rb_entry_safe(rb_first(&dir->subdir), struct proc_dir_entry,
+ subdir_node);
+}
+
+static struct proc_dir_entry *pde_subdir_next(struct proc_dir_entry *dir)
+{
+ return rb_entry_safe(rb_next(&dir->subdir_node), struct proc_dir_entry,
+ subdir_node);
+}
+
+static struct proc_dir_entry *pde_subdir_find(struct proc_dir_entry *dir,
+ const char *name,
+ unsigned int len)
+{
+ struct rb_node *node = dir->subdir.rb_node;
+
+ while (node) {
+ struct proc_dir_entry *de = container_of(node,
+ struct proc_dir_entry,
+ subdir_node);
+ int result = proc_match(len, name, de);
+
+ if (result < 0)
+ node = node->rb_left;
+ else if (result > 0)
+ node = node->rb_right;
+ else
+ return de;
+ }
+ return NULL;
+}
+
+static bool pde_subdir_insert(struct proc_dir_entry *dir,
+ struct proc_dir_entry *de)
+{
+ struct rb_root *root = &dir->subdir;
+ struct rb_node **new = &root->rb_node, *parent = NULL;
+
+ /* Figure out where to put new node */
+ while (*new) {
+ struct proc_dir_entry *this =
+ container_of(*new, struct proc_dir_entry, subdir_node);
+ int result = proc_match(de->namelen, de->name, this);
+
+ parent = *new;
+ if (result < 0)
+ new = &(*new)->rb_left;
+ else if (result > 0)
+ new = &(*new)->rb_right;
+ else
+ return false;
+ }
+
+ /* Add new node and rebalance tree. */
+ rb_link_node(&de->subdir_node, parent, new);
+ rb_insert_color(&de->subdir_node, root);
+ return true;
}
static int proc_notify_change(struct dentry *dentry, struct iattr *iattr)
@@ -92,10 +156,7 @@ static int __xlate_proc_name(const char *name, struct proc_dir_entry **ret,
break;
len = next - cp;
- for (de = de->subdir; de ; de = de->next) {
- if (proc_match(len, cp, de))
- break;
- }
+ de = pde_subdir_find(de, cp, len);
if (!de) {
WARN(1, "name '%s'\n", name);
return -ENOENT;
@@ -183,19 +244,16 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir,
struct inode *inode;
spin_lock(&proc_subdir_lock);
- for (de = de->subdir; de ; de = de->next) {
- if (de->namelen != dentry->d_name.len)
- continue;
- if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
- pde_get(de);
- spin_unlock(&proc_subdir_lock);
- inode = proc_get_inode(dir->i_sb, de);
- if (!inode)
- return ERR_PTR(-ENOMEM);
- d_set_d_op(dentry, &simple_dentry_operations);
- d_add(dentry, inode);
- return NULL;
- }
+ de = pde_subdir_find(de, dentry->d_name.name, dentry->d_name.len);
+ if (de) {
+ pde_get(de);
+ spin_unlock(&proc_subdir_lock);
+ inode = proc_get_inode(dir->i_sb, de);
+ if (!inode)
+ return ERR_PTR(-ENOMEM);
+ d_set_d_op(dentry, &simple_dentry_operations);
+ d_add(dentry, inode);
+ return NULL;
}
spin_unlock(&proc_subdir_lock);
return ERR_PTR(-ENOENT);
@@ -225,7 +283,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
return 0;
spin_lock(&proc_subdir_lock);
- de = de->subdir;
+ de = pde_subdir_first(de);
i = ctx->pos - 2;
for (;;) {
if (!de) {
@@ -234,7 +292,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
}
if (!i)
break;
- de = de->next;
+ de = pde_subdir_next(de);
i--;
}
@@ -249,7 +307,7 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *file,
}
spin_lock(&proc_subdir_lock);
ctx->pos++;
- next = de->next;
+ next = pde_subdir_next(de);
pde_put(de);
de = next;
} while (de);
@@ -286,9 +344,8 @@ static const struct inode_operations proc_dir_inode_operations = {
static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp)
{
- struct proc_dir_entry *tmp;
int ret;
-
+
ret = proc_alloc_inum(&dp->low_ino);
if (ret)
return ret;
@@ -304,21 +361,21 @@ static int proc_register(struct proc_dir_entry * dir, struct proc_dir_entry * dp
dp->proc_iops = &proc_file_inode_operations;
} else {
WARN_ON(1);
+ proc_free_inum(dp->low_ino);
return -EINVAL;
}
spin_lock(&proc_subdir_lock);
-
- for (tmp = dir->subdir; tmp; tmp = tmp->next)
- if (strcmp(tmp->name, dp->name) == 0) {
- WARN(1, "proc_dir_entry '%s/%s' already registered\n",
- dir->name, dp->name);
- break;
- }
-
- dp->next = dir->subdir;
dp->parent = dir;
- dir->subdir = dp;
+ if (pde_subdir_insert(dir, dp) == false) {
+ WARN(1, "proc_dir_entry '%s/%s' already registered\n",
+ dir->name, dp->name);
+ spin_unlock(&proc_subdir_lock);
+ if (S_ISDIR(dp->mode))
+ dir->nlink--;
+ proc_free_inum(dp->low_ino);
+ return -EEXIST;
+ }
spin_unlock(&proc_subdir_lock);
return 0;
@@ -354,6 +411,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
ent->namelen = qstr.len;
ent->mode = mode;
ent->nlink = nlink;
+ ent->subdir = RB_ROOT;
atomic_set(&ent->count, 1);
spin_lock_init(&ent->pde_unload_lock);
INIT_LIST_HEAD(&ent->pde_openers);
@@ -485,7 +543,6 @@ void pde_put(struct proc_dir_entry *pde)
*/
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
- struct proc_dir_entry **p;
struct proc_dir_entry *de = NULL;
const char *fn = name;
unsigned int len;
@@ -497,14 +554,9 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
}
len = strlen(fn);
- for (p = &parent->subdir; *p; p=&(*p)->next ) {
- if (proc_match(len, fn, *p)) {
- de = *p;
- *p = de->next;
- de->next = NULL;
- break;
- }
- }
+ de = pde_subdir_find(parent, fn, len);
+ if (de)
+ rb_erase(&de->subdir_node, &parent->subdir);
spin_unlock(&proc_subdir_lock);
if (!de) {
WARN(1, "name '%s'\n", name);
@@ -516,16 +568,15 @@ void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
if (S_ISDIR(de->mode))
parent->nlink--;
de->nlink = 0;
- WARN(de->subdir, "%s: removing non-empty directory "
- "'%s/%s', leaking at least '%s'\n", __func__,
- de->parent->name, de->name, de->subdir->name);
+ WARN(pde_subdir_first(de),
+ "%s: removing non-empty directory '%s/%s', leaking at least '%s'\n",
+ __func__, de->parent->name, de->name, pde_subdir_first(de)->name);
pde_put(de);
}
EXPORT_SYMBOL(remove_proc_entry);
int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
{
- struct proc_dir_entry **p;
struct proc_dir_entry *root = NULL, *de, *next;
const char *fn = name;
unsigned int len;
@@ -537,24 +588,18 @@ int remove_proc_subtree(const char *name, struct proc_dir_entry *parent)
}
len = strlen(fn);
- for (p = &parent->subdir; *p; p=&(*p)->next ) {
- if (proc_match(len, fn, *p)) {
- root = *p;
- *p = root->next;
- root->next = NULL;
- break;
- }
- }
+ root = pde_subdir_find(parent, fn, len);
if (!root) {
spin_unlock(&proc_subdir_lock);
return -ENOENT;
}
+ rb_erase(&root->subdir_node, &parent->subdir);
+
de = root;
while (1) {
- next = de->subdir;
+ next = pde_subdir_first(de);
if (next) {
- de->subdir = next->next;
- next->next = NULL;
+ rb_erase(&next->subdir_node, &de->subdir);
de = next;
continue;
}
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index aa7a0ee..7fb1a48 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -24,10 +24,9 @@ struct mempolicy;
* tree) of these proc_dir_entries, so that we can dynamically
* add new files to /proc.
*
- * The "next" pointer creates a linked list of one /proc directory,
- * while parent/subdir create the directory structure (every
- * /proc file has a parent, but "subdir" is NULL for all
- * non-directory entries).
+ * parent/subdir are used for the directory structure (every /proc file has a
+ * parent, but "subdir" is empty for all non-directory entries).
+ * subdir_node is used to build the rb tree "subdir" of the parent.
*/
struct proc_dir_entry {
unsigned int low_ino;
@@ -38,7 +37,9 @@ struct proc_dir_entry {
loff_t size;
const struct inode_operations *proc_iops;
const struct file_operations *proc_fops;
- struct proc_dir_entry *next, *parent, *subdir;
+ struct proc_dir_entry *parent;
+ struct rb_root subdir;
+ struct rb_node subdir_node;
void *data;
atomic_t count; /* use count */
atomic_t in_use; /* number of callers into module in progress; */
diff --git a/fs/proc/proc_net.c b/fs/proc/proc_net.c
index a63af3e..1bde894 100644
--- a/fs/proc/proc_net.c
+++ b/fs/proc/proc_net.c
@@ -192,6 +192,7 @@ static __net_init int proc_net_ns_init(struct net *net)
if (!netd)
goto out;
+ netd->subdir = RB_ROOT;
netd->data = net;
netd->nlink = 2;
netd->namelen = 3;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 094e44d..e74ac9f 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -251,6 +251,7 @@ struct proc_dir_entry proc_root = {
.proc_iops = &proc_root_inode_operations,
.proc_fops = &proc_root_operations,
.parent = &proc_root,
+ .subdir = RB_ROOT,
.name = "/proc",
};
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 4e0388c..246eae8 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -447,59 +447,92 @@ struct mem_size_stats {
u64 pss;
};
+static void smaps_account(struct mem_size_stats *mss, struct page *page,
+ unsigned long size, bool young, bool dirty)
+{
+ int mapcount;
+
+ if (PageAnon(page))
+ mss->anonymous += size;
-static void smaps_pte_entry(pte_t ptent, unsigned long addr,
- unsigned long ptent_size, struct mm_walk *walk)
+ mss->resident += size;
+ /* Accumulate the size in pages that have been accessed. */
+ if (young || PageReferenced(page))
+ mss->referenced += size;
+ mapcount = page_mapcount(page);
+ if (mapcount >= 2) {
+ u64 pss_delta;
+
+ if (dirty || PageDirty(page))
+ mss->shared_dirty += size;
+ else
+ mss->shared_clean += size;
+ pss_delta = (u64)size << PSS_SHIFT;
+ do_div(pss_delta, mapcount);
+ mss->pss += pss_delta;
+ } else {
+ if (dirty || PageDirty(page))
+ mss->private_dirty += size;
+ else
+ mss->private_clean += size;
+ mss->pss += (u64)size << PSS_SHIFT;
+ }
+}
+
+static void smaps_pte_entry(pte_t *pte, unsigned long addr,
+ struct mm_walk *walk)
{
struct mem_size_stats *mss = walk->private;
struct vm_area_struct *vma = mss->vma;
pgoff_t pgoff = linear_page_index(vma, addr);
struct page *page = NULL;
- int mapcount;
- if (pte_present(ptent)) {
- page = vm_normal_page(vma, addr, ptent);
- } else if (is_swap_pte(ptent)) {
- swp_entry_t swpent = pte_to_swp_entry(ptent);
+ if (pte_present(*pte)) {
+ page = vm_normal_page(vma, addr, *pte);
+ } else if (is_swap_pte(*pte)) {
+ swp_entry_t swpent = pte_to_swp_entry(*pte);
if (!non_swap_entry(swpent))
- mss->swap += ptent_size;
+ mss->swap += PAGE_SIZE;
else if (is_migration_entry(swpent))
page = migration_entry_to_page(swpent);
- } else if (pte_file(ptent)) {
- if (pte_to_pgoff(ptent) != pgoff)
- mss->nonlinear += ptent_size;
+ } else if (pte_file(*pte)) {
+ if (pte_to_pgoff(*pte) != pgoff)
+ mss->nonlinear += PAGE_SIZE;
}
if (!page)
return;
- if (PageAnon(page))
- mss->anonymous += ptent_size;
-
if (page->index != pgoff)
- mss->nonlinear += ptent_size;
+ mss->nonlinear += PAGE_SIZE;
- mss->resident += ptent_size;
- /* Accumulate the size in pages that have been accessed. */
- if (pte_young(ptent) || PageReferenced(page))
- mss->referenced += ptent_size;
- mapcount = page_mapcount(page);
- if (mapcount >= 2) {
- if (pte_dirty(ptent) || PageDirty(page))
- mss->shared_dirty += ptent_size;
- else
- mss->shared_clean += ptent_size;
- mss->pss += (ptent_size << PSS_SHIFT) / mapcount;
- } else {
- if (pte_dirty(ptent) || PageDirty(page))
- mss->private_dirty += ptent_size;
- else
- mss->private_clean += ptent_size;
- mss->pss += (ptent_size << PSS_SHIFT);
- }
+ smaps_account(mss, page, PAGE_SIZE, pte_young(*pte), pte_dirty(*pte));
}
+#ifdef CONFIG_TRANSPARENT_HUGEPAGE
+static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
+ struct mm_walk *walk)
+{
+ struct mem_size_stats *mss = walk->private;
+ struct vm_area_struct *vma = mss->vma;
+ struct page *page;
+
+ /* FOLL_DUMP will return -EFAULT on huge zero page */
+ page = follow_trans_huge_pmd(vma, addr, pmd, FOLL_DUMP);
+ if (IS_ERR_OR_NULL(page))
+ return;
+ mss->anonymous_thp += HPAGE_PMD_SIZE;
+ smaps_account(mss, page, HPAGE_PMD_SIZE,
+ pmd_young(*pmd), pmd_dirty(*pmd));
+}
+#else
+static void smaps_pmd_entry(pmd_t *pmd, unsigned long addr,
+ struct mm_walk *walk)
+{
+}
+#endif
+
static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
struct mm_walk *walk)
{
@@ -509,9 +542,8 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
spinlock_t *ptl;
if (pmd_trans_huge_lock(pmd, vma, &ptl) == 1) {
- smaps_pte_entry(*(pte_t *)pmd, addr, HPAGE_PMD_SIZE, walk);
+ smaps_pmd_entry(pmd, addr, walk);
spin_unlock(ptl);
- mss->anonymous_thp += HPAGE_PMD_SIZE;
return 0;
}
@@ -524,7 +556,7 @@ static int smaps_pte_range(pmd_t *pmd, unsigned long addr, unsigned long end,
*/
pte = pte_offset_map_lock(vma->vm_mm, pmd, addr, &ptl);
for (; addr != end; pte++, addr += PAGE_SIZE)
- smaps_pte_entry(*pte, addr, PAGE_SIZE, walk);
+ smaps_pte_entry(pte, addr, walk);
pte_unmap_unlock(pte - 1, ptl);
cond_resched();
return 0;
@@ -552,6 +584,9 @@ static void show_smap_vma_flags(struct seq_file *m, struct vm_area_struct *vma)
[ilog2(VM_GROWSDOWN)] = "gd",
[ilog2(VM_PFNMAP)] = "pf",
[ilog2(VM_DENYWRITE)] = "dw",
+#ifdef CONFIG_X86_INTEL_MPX
+ [ilog2(VM_MPX)] = "mp",
+#endif
[ilog2(VM_LOCKED)] = "lo",
[ilog2(VM_IO)] = "io",
[ilog2(VM_SEQ_READ)] = "sr",
diff --git a/fs/pstore/inode.c b/fs/pstore/inode.c
index fafb7a0..5041660 100644
--- a/fs/pstore/inode.c
+++ b/fs/pstore/inode.c
@@ -36,6 +36,7 @@
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/uaccess.h>
+#include <linux/syslog.h>
#include "internal.h"
@@ -120,6 +121,18 @@ static const struct seq_operations pstore_ftrace_seq_ops = {
.show = pstore_ftrace_seq_show,
};
+static int pstore_check_syslog_permissions(struct pstore_private *ps)
+{
+ switch (ps->type) {
+ case PSTORE_TYPE_DMESG:
+ case PSTORE_TYPE_CONSOLE:
+ return check_syslog_permissions(SYSLOG_ACTION_READ_ALL,
+ SYSLOG_FROM_READER);
+ default:
+ return 0;
+ }
+}
+
static ssize_t pstore_file_read(struct file *file, char __user *userbuf,
size_t count, loff_t *ppos)
{
@@ -138,6 +151,10 @@ static int pstore_file_open(struct inode *inode, struct file *file)
int err;
const struct seq_operations *sops = NULL;
+ err = pstore_check_syslog_permissions(ps);
+ if (err)
+ return err;
+
if (ps->type == PSTORE_TYPE_FTRACE)
sops = &pstore_ftrace_seq_ops;
@@ -174,6 +191,11 @@ static const struct file_operations pstore_file_operations = {
static int pstore_unlink(struct inode *dir, struct dentry *dentry)
{
struct pstore_private *p = dentry->d_inode->i_private;
+ int err;
+
+ err = pstore_check_syslog_permissions(p);
+ if (err)
+ return err;
if (p->psi->erase)
p->psi->erase(p->type, p->id, p->count,
diff --git a/fs/pstore/ram.c b/fs/pstore/ram.c
index 3b57443..ec881b3 100644
--- a/fs/pstore/ram.c
+++ b/fs/pstore/ram.c
@@ -135,25 +135,27 @@ ramoops_get_next_prz(struct persistent_ram_zone *przs[], uint *c, uint max,
return prz;
}
-static void ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
+static int ramoops_read_kmsg_hdr(char *buffer, struct timespec *time,
bool *compressed)
{
char data_type;
+ int header_length = 0;
- if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n",
- &time->tv_sec, &time->tv_nsec, &data_type) == 3) {
+ if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu-%c\n%n", &time->tv_sec,
+ &time->tv_nsec, &data_type, &header_length) == 3) {
if (data_type == 'C')
*compressed = true;
else
*compressed = false;
- } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu\n",
- &time->tv_sec, &time->tv_nsec) == 2) {
+ } else if (sscanf(buffer, RAMOOPS_KERNMSG_HDR "%lu.%lu\n%n",
+ &time->tv_sec, &time->tv_nsec, &header_length) == 2) {
*compressed = false;
} else {
time->tv_sec = 0;
time->tv_nsec = 0;
*compressed = false;
}
+ return header_length;
}
static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
@@ -165,6 +167,7 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
ssize_t ecc_notice_size;
struct ramoops_context *cxt = psi->data;
struct persistent_ram_zone *prz;
+ int header_length;
prz = ramoops_get_next_prz(cxt->przs, &cxt->dump_read_cnt,
cxt->max_dump_cnt, id, type,
@@ -178,7 +181,13 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
if (!prz)
return 0;
+ if (!persistent_ram_old(prz))
+ return 0;
+
size = persistent_ram_old_size(prz);
+ header_length = ramoops_read_kmsg_hdr(persistent_ram_old(prz), time,
+ compressed);
+ size -= header_length;
/* ECC correction notice */
ecc_notice_size = persistent_ram_ecc_string(prz, NULL, 0);
@@ -187,8 +196,7 @@ static ssize_t ramoops_pstore_read(u64 *id, enum pstore_type_id *type,
if (*buf == NULL)
return -ENOMEM;
- memcpy(*buf, persistent_ram_old(prz), size);
- ramoops_read_kmsg_hdr(*buf, time, compressed);
+ memcpy(*buf, (char *)persistent_ram_old(prz) + header_length, size);
persistent_ram_ecc_string(prz, *buf + size, ecc_notice_size + 1);
return size + ecc_notice_size;
diff --git a/fs/quota/dquot.c b/fs/quota/dquot.c
index 6b45272..8f0acef 100644
--- a/fs/quota/dquot.c
+++ b/fs/quota/dquot.c
@@ -893,6 +893,11 @@ out:
}
EXPORT_SYMBOL(dqget);
+static inline struct dquot **i_dquot(struct inode *inode)
+{
+ return inode->i_sb->s_op->get_dquots(inode);
+}
+
static int dqinit_needed(struct inode *inode, int type)
{
int cnt;
@@ -900,9 +905,9 @@ static int dqinit_needed(struct inode *inode, int type)
if (IS_NOQUOTA(inode))
return 0;
if (type != -1)
- return !inode->i_dquot[type];
+ return !i_dquot(inode)[type];
for (cnt = 0; cnt < MAXQUOTAS; cnt++)
- if (!inode->i_dquot[cnt])
+ if (!i_dquot(inode)[cnt])
return 1;
return 0;
}
@@ -965,9 +970,9 @@ static void add_dquot_ref(struct super_block *sb, int type)
static void remove_inode_dquot_ref(struct inode *inode, int type,
struct list_head *tofree_head)
{
- struct dquot *dquot = inode->i_dquot[type];
+ struct dquot *dquot = i_dquot(inode)[type];
- inode->i_dquot[type] = NULL;
+ i_dquot(inode)[type] = NULL;
if (!dquot)
return;
@@ -1402,7 +1407,7 @@ static void __dquot_initialize(struct inode *inode, int type)
* we check it without locking here to avoid unnecessary
* dqget()/dqput() calls.
*/
- if (inode->i_dquot[cnt])
+ if (i_dquot(inode)[cnt])
continue;
init_needed = 1;
@@ -1433,8 +1438,8 @@ static void __dquot_initialize(struct inode *inode, int type)
/* We could race with quotaon or dqget() could have failed */
if (!got[cnt])
continue;
- if (!inode->i_dquot[cnt]) {
- inode->i_dquot[cnt] = got[cnt];
+ if (!i_dquot(inode)[cnt]) {
+ i_dquot(inode)[cnt] = got[cnt];
got[cnt] = NULL;
/*
* Make quota reservation system happy if someone
@@ -1442,7 +1447,7 @@ static void __dquot_initialize(struct inode *inode, int type)
*/
rsv = inode_get_rsv_space(inode);
if (unlikely(rsv))
- dquot_resv_space(inode->i_dquot[cnt], rsv);
+ dquot_resv_space(i_dquot(inode)[cnt], rsv);
}
}
out_err:
@@ -1472,8 +1477,8 @@ static void __dquot_drop(struct inode *inode)
spin_lock(&dq_data_lock);
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- put[cnt] = inode->i_dquot[cnt];
- inode->i_dquot[cnt] = NULL;
+ put[cnt] = i_dquot(inode)[cnt];
+ i_dquot(inode)[cnt] = NULL;
}
spin_unlock(&dq_data_lock);
dqput_all(put);
@@ -1494,7 +1499,7 @@ void dquot_drop(struct inode *inode)
* add quota pointers back anyway.
*/
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- if (inode->i_dquot[cnt])
+ if (i_dquot(inode)[cnt])
break;
}
@@ -1595,7 +1600,7 @@ int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags)
{
int cnt, ret = 0, index;
struct dquot_warn warn[MAXQUOTAS];
- struct dquot **dquots = inode->i_dquot;
+ struct dquot **dquots = i_dquot(inode);
int reserve = flags & DQUOT_SPACE_RESERVE;
if (!dquot_active(inode)) {
@@ -1643,11 +1648,11 @@ EXPORT_SYMBOL(__dquot_alloc_space);
/*
* This operation can block, but only after everything is updated
*/
-int dquot_alloc_inode(const struct inode *inode)
+int dquot_alloc_inode(struct inode *inode)
{
int cnt, ret = 0, index;
struct dquot_warn warn[MAXQUOTAS];
- struct dquot * const *dquots = inode->i_dquot;
+ struct dquot * const *dquots = i_dquot(inode);
if (!dquot_active(inode))
return 0;
@@ -1696,14 +1701,14 @@ int dquot_claim_space_nodirty(struct inode *inode, qsize_t number)
spin_lock(&dq_data_lock);
/* Claim reserved quotas to allocated quotas */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- if (inode->i_dquot[cnt])
- dquot_claim_reserved_space(inode->i_dquot[cnt],
+ if (i_dquot(inode)[cnt])
+ dquot_claim_reserved_space(i_dquot(inode)[cnt],
number);
}
/* Update inode bytes */
inode_claim_rsv_space(inode, number);
spin_unlock(&dq_data_lock);
- mark_all_dquot_dirty(inode->i_dquot);
+ mark_all_dquot_dirty(i_dquot(inode));
srcu_read_unlock(&dquot_srcu, index);
return 0;
}
@@ -1725,14 +1730,14 @@ void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number)
spin_lock(&dq_data_lock);
/* Claim reserved quotas to allocated quotas */
for (cnt = 0; cnt < MAXQUOTAS; cnt++) {
- if (inode->i_dquot[cnt])
- dquot_reclaim_reserved_space(inode->i_dquot[cnt],
+ if (i_dquot(inode)[cnt])
+ dquot_reclaim_reserved_space(i_dquot(inode)[cnt],
number);
}
/* Update inode bytes */
inode_reclaim_rsv_space(inode, number);
spin_unlock(&dq_data_lock);
- mark_all_dquot_dirty(inode->i_dquot);
+ mark_all_dquot_dirty(i_dquot(inode));
srcu_read_unlock(&dquot_srcu, index);
return;
}
@@ -1745,7 +1750,7 @@ void __dquot_free_space(struct inode *inode, qsize_t number, int flags)
{
unsigned int cnt;
struct dquot_warn warn[MAXQUOTAS];
- struct dquot **dquots = inode->i_dquot;
+ struct dquot **dquots = i_dquot(inode);
int reserve = flags & DQUOT_SPACE_RESERVE, index;
if (!dquot_active(inode)) {
@@ -1784,11 +1789,11 @@ EXPORT_SYMBOL(__dquot_free_space);
/*
* This operation can block, but only after everything is updated
*/
-void dquot_free_inode(const struct inode *inode)
+void dquot_free_inode(struct inode *inode)
{
unsigned int cnt;
struct dquot_warn warn[MAXQUOTAS];
- struct dquot * const *dquots = inode->i_dquot;
+ struct dquot * const *dquots = i_dquot(inode);
int index;
if (!dquot_active(inode))
@@ -1865,7 +1870,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
if (!sb_has_quota_active(inode->i_sb, cnt))
continue;
is_valid[cnt] = 1;
- transfer_from[cnt] = inode->i_dquot[cnt];
+ transfer_from[cnt] = i_dquot(inode)[cnt];
ret = check_idq(transfer_to[cnt], 1, &warn_to[cnt]);
if (ret)
goto over_quota;
@@ -1901,7 +1906,7 @@ int __dquot_transfer(struct inode *inode, struct dquot **transfer_to)
dquot_incr_space(transfer_to[cnt], cur_space);
dquot_resv_space(transfer_to[cnt], rsv_space);
- inode->i_dquot[cnt] = transfer_to[cnt];
+ i_dquot(inode)[cnt] = transfer_to[cnt];
}
spin_unlock(&dq_data_lock);
@@ -2743,8 +2748,8 @@ static int __init dquot_init(void)
for (i = 0; i < nr_hash; i++)
INIT_HLIST_HEAD(dquot_hash + i);
- printk("Dquot-cache hash table entries: %ld (order %ld, %ld bytes)\n",
- nr_hash, order, (PAGE_SIZE << order));
+ pr_info("VFS: Dquot-cache hash table entries: %ld (order %ld,"
+ " %ld bytes)\n", nr_hash, order, (PAGE_SIZE << order));
register_shrinker(&dqcache_shrinker);
diff --git a/fs/quota/quota.c b/fs/quota/quota.c
index 7562164..2aa4151 100644
--- a/fs/quota/quota.c
+++ b/fs/quota/quota.c
@@ -47,8 +47,11 @@ static int check_quotactl_permission(struct super_block *sb, int type, int cmd,
static void quota_sync_one(struct super_block *sb, void *arg)
{
- if (sb->s_qcop && sb->s_qcop->quota_sync)
- sb->s_qcop->quota_sync(sb, *(int *)arg);
+ int type = *(int *)arg;
+
+ if (sb->s_qcop && sb->s_qcop->quota_sync &&
+ (sb->s_quota_types & (1 << type)))
+ sb->s_qcop->quota_sync(sb, type);
}
static int quota_sync_all(int type)
@@ -297,8 +300,14 @@ static int do_quotactl(struct super_block *sb, int type, int cmd, qid_t id,
if (type >= (XQM_COMMAND(cmd) ? XQM_MAXQUOTAS : MAXQUOTAS))
return -EINVAL;
+ /*
+ * Quota not supported on this fs? Check this before s_quota_types
+ * since they needn't be set if quota is not supported at all.
+ */
if (!sb->s_qcop)
return -ENOSYS;
+ if (!(sb->s_quota_types & (1 << type)))
+ return -EINVAL;
ret = check_quotactl_permission(sb, type, cmd, id);
if (ret < 0)
diff --git a/fs/readdir.c b/fs/readdir.c
index 33fd922..ced6791 100644
--- a/fs/readdir.c
+++ b/fs/readdir.c
@@ -74,10 +74,11 @@ struct readdir_callback {
int result;
};
-static int fillonedir(void * __buf, const char * name, int namlen, loff_t offset,
- u64 ino, unsigned int d_type)
+static int fillonedir(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
- struct readdir_callback *buf = (struct readdir_callback *) __buf;
+ struct readdir_callback *buf =
+ container_of(ctx, struct readdir_callback, ctx);
struct old_linux_dirent __user * dirent;
unsigned long d_ino;
@@ -148,11 +149,12 @@ struct getdents_callback {
int error;
};
-static int filldir(void * __buf, const char * name, int namlen, loff_t offset,
- u64 ino, unsigned int d_type)
+static int filldir(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct linux_dirent __user * dirent;
- struct getdents_callback * buf = (struct getdents_callback *) __buf;
+ struct getdents_callback *buf =
+ container_of(ctx, struct getdents_callback, ctx);
unsigned long d_ino;
int reclen = ALIGN(offsetof(struct linux_dirent, d_name) + namlen + 2,
sizeof(long));
@@ -232,11 +234,12 @@ struct getdents_callback64 {
int error;
};
-static int filldir64(void * __buf, const char * name, int namlen, loff_t offset,
- u64 ino, unsigned int d_type)
+static int filldir64(struct dir_context *ctx, const char *name, int namlen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
struct linux_dirent64 __user *dirent;
- struct getdents_callback64 * buf = (struct getdents_callback64 *) __buf;
+ struct getdents_callback64 *buf =
+ container_of(ctx, struct getdents_callback64, ctx);
int reclen = ALIGN(offsetof(struct linux_dirent64, d_name) + namlen + 1,
sizeof(u64));
diff --git a/fs/reiserfs/reiserfs.h b/fs/reiserfs/reiserfs.h
index 1894d96..bb79cdd 100644
--- a/fs/reiserfs/reiserfs.h
+++ b/fs/reiserfs/reiserfs.h
@@ -97,6 +97,10 @@ struct reiserfs_inode_info {
#ifdef CONFIG_REISERFS_FS_XATTR
struct rw_semaphore i_xattr_sem;
#endif
+#ifdef CONFIG_QUOTA
+ struct dquot *i_dquot[MAXQUOTAS];
+#endif
+
struct inode vfs_inode;
};
diff --git a/fs/reiserfs/super.c b/fs/reiserfs/super.c
index f1376c9..ea63ab1 100644
--- a/fs/reiserfs/super.c
+++ b/fs/reiserfs/super.c
@@ -594,6 +594,10 @@ static struct inode *reiserfs_alloc_inode(struct super_block *sb)
return NULL;
atomic_set(&ei->openers, 0);
mutex_init(&ei->tailpack);
+#ifdef CONFIG_QUOTA
+ memset(&ei->i_dquot, 0, sizeof(ei->i_dquot));
+#endif
+
return &ei->vfs_inode;
}
@@ -750,6 +754,11 @@ static ssize_t reiserfs_quota_write(struct super_block *, int, const char *,
size_t, loff_t);
static ssize_t reiserfs_quota_read(struct super_block *, int, char *, size_t,
loff_t);
+
+static struct dquot **reiserfs_get_dquots(struct inode *inode)
+{
+ return REISERFS_I(inode)->i_dquot;
+}
#endif
static const struct super_operations reiserfs_sops = {
@@ -768,6 +777,7 @@ static const struct super_operations reiserfs_sops = {
#ifdef CONFIG_QUOTA
.quota_read = reiserfs_quota_read,
.quota_write = reiserfs_quota_write,
+ .get_dquots = reiserfs_get_dquots,
#endif
};
@@ -1633,6 +1643,7 @@ static int read_super_block(struct super_block *s, int offset)
#ifdef CONFIG_QUOTA
s->s_qcop = &reiserfs_qctl_operations;
s->dq_op = &reiserfs_quota_operations;
+ s->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP;
#endif
/*
diff --git a/fs/reiserfs/xattr.c b/fs/reiserfs/xattr.c
index 7c36898..04b0614 100644
--- a/fs/reiserfs/xattr.c
+++ b/fs/reiserfs/xattr.c
@@ -188,10 +188,11 @@ struct reiserfs_dentry_buf {
};
static int
-fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
- u64 ino, unsigned int d_type)
+fill_with_dentries(struct dir_context *ctx, const char *name, int namelen,
+ loff_t offset, u64 ino, unsigned int d_type)
{
- struct reiserfs_dentry_buf *dbuf = buf;
+ struct reiserfs_dentry_buf *dbuf =
+ container_of(ctx, struct reiserfs_dentry_buf, ctx);
struct dentry *dentry;
WARN_ON_ONCE(!mutex_is_locked(&dbuf->xadir->d_inode->i_mutex));
@@ -209,9 +210,9 @@ fill_with_dentries(void *buf, const char *name, int namelen, loff_t offset,
} else if (!dentry->d_inode) {
/* A directory entry exists, but no file? */
reiserfs_error(dentry->d_sb, "xattr-20003",
- "Corrupted directory: xattr %s listed but "
- "not found for file %s.\n",
- dentry->d_name.name, dbuf->xadir->d_name.name);
+ "Corrupted directory: xattr %pd listed but "
+ "not found for file %pd.\n",
+ dentry, dbuf->xadir);
dput(dentry);
return -EIO;
}
@@ -824,10 +825,12 @@ struct listxattr_buf {
struct dentry *dentry;
};
-static int listxattr_filler(void *buf, const char *name, int namelen,
- loff_t offset, u64 ino, unsigned int d_type)
+static int listxattr_filler(struct dir_context *ctx, const char *name,
+ int namelen, loff_t offset, u64 ino,
+ unsigned int d_type)
{
- struct listxattr_buf *b = (struct listxattr_buf *)buf;
+ struct listxattr_buf *b =
+ container_of(ctx, struct listxattr_buf, ctx);
size_t size;
if (name[0] != '.' ||
diff --git a/fs/seq_file.c b/fs/seq_file.c
index 3857b72..353948b 100644
--- a/fs/seq_file.c
+++ b/fs/seq_file.c
@@ -16,17 +16,6 @@
#include <asm/uaccess.h>
#include <asm/page.h>
-
-/*
- * seq_files have a buffer which can may overflow. When this happens a larger
- * buffer is reallocated and all the data will be printed again.
- * The overflow state is true when m->count == m->size.
- */
-static bool seq_overflow(struct seq_file *m)
-{
- return m->count == m->size;
-}
-
static void seq_set_overflow(struct seq_file *m)
{
m->count = m->size;
@@ -124,7 +113,7 @@ static int traverse(struct seq_file *m, loff_t offset)
error = 0;
m->count = 0;
}
- if (seq_overflow(m))
+ if (seq_has_overflowed(m))
goto Eoverflow;
if (pos + m->count > offset) {
m->from = offset - pos;
@@ -267,7 +256,7 @@ Fill:
break;
}
err = m->op->show(m, p);
- if (seq_overflow(m) || err) {
+ if (seq_has_overflowed(m) || err) {
m->count = offs;
if (likely(err <= 0))
break;
diff --git a/fs/signalfd.c b/fs/signalfd.c
index 424b7b6..7e412ad 100644
--- a/fs/signalfd.c
+++ b/fs/signalfd.c
@@ -230,7 +230,7 @@ static ssize_t signalfd_read(struct file *file, char __user *buf, size_t count,
}
#ifdef CONFIG_PROC_FS
-static int signalfd_show_fdinfo(struct seq_file *m, struct file *f)
+static void signalfd_show_fdinfo(struct seq_file *m, struct file *f)
{
struct signalfd_ctx *ctx = f->private_data;
sigset_t sigmask;
@@ -238,8 +238,6 @@ static int signalfd_show_fdinfo(struct seq_file *m, struct file *f)
sigmask = ctx->sigmask;
signotset(&sigmask);
render_sigset_t(m, "sigmask:\t", &sigmask);
-
- return 0;
}
#endif
diff --git a/fs/sync.c b/fs/sync.c
index bdc729d..01d9f18 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -154,7 +154,7 @@ SYSCALL_DEFINE1(syncfs, int, fd)
if (!f.file)
return -EBADF;
- sb = f.file->f_dentry->d_sb;
+ sb = f.file->f_path.dentry->d_sb;
down_read(&sb->s_umount);
ret = sync_filesystem(sb);
diff --git a/fs/timerfd.c b/fs/timerfd.c
index b46ffa9..b94fa6c 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -288,7 +288,7 @@ static ssize_t timerfd_read(struct file *file, char __user *buf, size_t count,
}
#ifdef CONFIG_PROC_FS
-static int timerfd_show(struct seq_file *m, struct file *file)
+static void timerfd_show(struct seq_file *m, struct file *file)
{
struct timerfd_ctx *ctx = file->private_data;
struct itimerspec t;
@@ -298,18 +298,19 @@ static int timerfd_show(struct seq_file *m, struct file *file)
t.it_interval = ktime_to_timespec(ctx->tintv);
spin_unlock_irq(&ctx->wqh.lock);
- return seq_printf(m,
- "clockid: %d\n"
- "ticks: %llu\n"
- "settime flags: 0%o\n"
- "it_value: (%llu, %llu)\n"
- "it_interval: (%llu, %llu)\n",
- ctx->clockid, (unsigned long long)ctx->ticks,
- ctx->settime_flags,
- (unsigned long long)t.it_value.tv_sec,
- (unsigned long long)t.it_value.tv_nsec,
- (unsigned long long)t.it_interval.tv_sec,
- (unsigned long long)t.it_interval.tv_nsec);
+ seq_printf(m,
+ "clockid: %d\n"
+ "ticks: %llu\n"
+ "settime flags: 0%o\n"
+ "it_value: (%llu, %llu)\n"
+ "it_interval: (%llu, %llu)\n",
+ ctx->clockid,
+ (unsigned long long)ctx->ticks,
+ ctx->settime_flags,
+ (unsigned long long)t.it_value.tv_sec,
+ (unsigned long long)t.it_value.tv_nsec,
+ (unsigned long long)t.it_interval.tv_sec,
+ (unsigned long long)t.it_interval.tv_nsec);
}
#else
#define timerfd_show NULL
diff --git a/fs/udf/super.c b/fs/udf/super.c
index e229315..3ccb2f1 100644
--- a/fs/udf/super.c
+++ b/fs/udf/super.c
@@ -2082,12 +2082,12 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
mutex_init(&sbi->s_alloc_mutex);
if (!udf_parse_options((char *)options, &uopt, false))
- goto error_out;
+ goto parse_options_failure;
if (uopt.flags & (1 << UDF_FLAG_UTF8) &&
uopt.flags & (1 << UDF_FLAG_NLS_MAP)) {
udf_err(sb, "utf8 cannot be combined with iocharset\n");
- goto error_out;
+ goto parse_options_failure;
}
#ifdef CONFIG_UDF_NLS
if ((uopt.flags & (1 << UDF_FLAG_NLS_MAP)) && !uopt.nls_map) {
@@ -2237,8 +2237,8 @@ static int udf_fill_super(struct super_block *sb, void *options, int silent)
return 0;
error_out:
- if (sbi->s_vat_inode)
- iput(sbi->s_vat_inode);
+ iput(sbi->s_vat_inode);
+parse_options_failure:
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map);
@@ -2291,8 +2291,7 @@ static void udf_put_super(struct super_block *sb)
sbi = UDF_SB(sb);
- if (sbi->s_vat_inode)
- iput(sbi->s_vat_inode);
+ iput(sbi->s_vat_inode);
#ifdef CONFIG_UDF_NLS
if (UDF_QUERY_FLAG(sb, UDF_FLAG_NLS_MAP))
unload_nls(sbi->s_nls_map);
diff --git a/fs/xattr.c b/fs/xattr.c
index 64e83ef..4ef6985 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -405,16 +405,14 @@ SYSCALL_DEFINE5(fsetxattr, int, fd, const char __user *, name,
const void __user *,value, size_t, size, int, flags)
{
struct fd f = fdget(fd);
- struct dentry *dentry;
int error = -EBADF;
if (!f.file)
return error;
- dentry = f.file->f_path.dentry;
- audit_inode(NULL, dentry, 0);
+ audit_file(f.file);
error = mnt_want_write_file(f.file);
if (!error) {
- error = setxattr(dentry, name, value, size, flags);
+ error = setxattr(f.file->f_path.dentry, name, value, size, flags);
mnt_drop_write_file(f.file);
}
fdput(f);
@@ -509,7 +507,7 @@ SYSCALL_DEFINE4(fgetxattr, int, fd, const char __user *, name,
if (!f.file)
return error;
- audit_inode(NULL, f.file->f_path.dentry, 0);
+ audit_file(f.file);
error = getxattr(f.file->f_path.dentry, name, value, size);
fdput(f);
return error;
@@ -590,7 +588,7 @@ SYSCALL_DEFINE3(flistxattr, int, fd, char __user *, list, size_t, size)
if (!f.file)
return error;
- audit_inode(NULL, f.file->f_path.dentry, 0);
+ audit_file(f.file);
error = listxattr(f.file->f_path.dentry, list, size);
fdput(f);
return error;
@@ -651,16 +649,14 @@ SYSCALL_DEFINE2(lremovexattr, const char __user *, pathname,
SYSCALL_DEFINE2(fremovexattr, int, fd, const char __user *, name)
{
struct fd f = fdget(fd);
- struct dentry *dentry;
int error = -EBADF;
if (!f.file)
return error;
- dentry = f.file->f_path.dentry;
- audit_inode(NULL, dentry, 0);
+ audit_file(f.file);
error = mnt_want_write_file(f.file);
if (!error) {
- error = removexattr(dentry, name);
+ error = removexattr(f.file->f_path.dentry, name);
mnt_drop_write_file(f.file);
}
fdput(f);
diff --git a/fs/xfs/xfs_super.c b/fs/xfs/xfs_super.c
index 9f622fe..206b97f 100644
--- a/fs/xfs/xfs_super.c
+++ b/fs/xfs/xfs_super.c
@@ -1425,6 +1425,7 @@ xfs_fs_fill_super(
sb->s_export_op = &xfs_export_operations;
#ifdef CONFIG_XFS_QUOTA
sb->s_qcop = &xfs_quotactl_operations;
+ sb->s_quota_types = QTYPE_MASK_USR | QTYPE_MASK_GRP | QTYPE_MASK_PRJ;
#endif
sb->s_op = &xfs_super_operations;
diff --git a/include/acpi/acbuffer.h b/include/acpi/acbuffer.h
index 88cb477..d5ec6c8 100644
--- a/include/acpi/acbuffer.h
+++ b/include/acpi/acbuffer.h
@@ -111,7 +111,9 @@ struct acpi_gtm_info {
struct acpi_pld_info {
u8 revision;
u8 ignore_color;
- u32 color;
+ u8 red;
+ u8 green;
+ u8 blue;
u16 width;
u16 height;
u8 user_visible;
@@ -155,8 +157,14 @@ struct acpi_pld_info {
#define ACPI_PLD_GET_IGNORE_COLOR(dword) ACPI_GET_BITS (dword, 7, ACPI_1BIT_MASK)
#define ACPI_PLD_SET_IGNORE_COLOR(dword,value) ACPI_SET_BITS (dword, 7, ACPI_1BIT_MASK, value) /* Offset 7, Len 1 */
-#define ACPI_PLD_GET_COLOR(dword) ACPI_GET_BITS (dword, 8, ACPI_24BIT_MASK)
-#define ACPI_PLD_SET_COLOR(dword,value) ACPI_SET_BITS (dword, 8, ACPI_24BIT_MASK, value) /* Offset 8, Len 24 */
+#define ACPI_PLD_GET_RED(dword) ACPI_GET_BITS (dword, 8, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_RED(dword,value) ACPI_SET_BITS (dword, 8, ACPI_8BIT_MASK, value) /* Offset 8, Len 8 */
+
+#define ACPI_PLD_GET_GREEN(dword) ACPI_GET_BITS (dword, 16, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_GREEN(dword,value) ACPI_SET_BITS (dword, 16, ACPI_8BIT_MASK, value) /* Offset 16, Len 8 */
+
+#define ACPI_PLD_GET_BLUE(dword) ACPI_GET_BITS (dword, 24, ACPI_8BIT_MASK)
+#define ACPI_PLD_SET_BLUE(dword,value) ACPI_SET_BITS (dword, 24, ACPI_8BIT_MASK, value) /* Offset 24, Len 8 */
/* Second 32-bit dword, bits 33:63 */
diff --git a/include/acpi/acpi_bus.h b/include/acpi/acpi_bus.h
index f34a083..7581518e3 100644
--- a/include/acpi/acpi_bus.h
+++ b/include/acpi/acpi_bus.h
@@ -27,6 +27,7 @@
#define __ACPI_BUS_H__
#include <linux/device.h>
+#include <linux/property.h>
/* TBD: Make dynamic */
#define ACPI_MAX_HANDLES 10
@@ -337,10 +338,20 @@ struct acpi_device_physical_node {
bool put_online:1;
};
+/* ACPI Device Specific Data (_DSD) */
+struct acpi_device_data {
+ const union acpi_object *pointer;
+ const union acpi_object *properties;
+ const union acpi_object *of_compatible;
+};
+
+struct acpi_gpio_mapping;
+
/* Device */
struct acpi_device {
int device_type;
acpi_handle handle; /* no handle for fixed hardware */
+ struct fwnode_handle fwnode;
struct acpi_device *parent;
struct list_head children;
struct list_head node;
@@ -353,17 +364,35 @@ struct acpi_device {
struct acpi_device_wakeup wakeup;
struct acpi_device_perf performance;
struct acpi_device_dir dir;
+ struct acpi_device_data data;
struct acpi_scan_handler *handler;
struct acpi_hotplug_context *hp;
struct acpi_driver *driver;
+ const struct acpi_gpio_mapping *driver_gpios;
void *driver_data;
struct device dev;
unsigned int physical_node_count;
+ unsigned int dep_unmet;
struct list_head physical_node_list;
struct mutex physical_node_lock;
void (*remove)(struct acpi_device *);
};
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_ACPI;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct acpi_device, fwnode) : NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+ return &adev->fwnode;
+}
+
static inline void *acpi_driver_data(struct acpi_device *d)
{
return d->driver_data;
@@ -516,6 +545,7 @@ acpi_status acpi_add_pm_notifier(struct acpi_device *adev, struct device *dev,
void (*work_func)(struct work_struct *work));
acpi_status acpi_remove_pm_notifier(struct acpi_device *adev);
int acpi_pm_device_sleep_state(struct device *, int *, int);
+int acpi_pm_device_run_wake(struct device *, bool);
#else
static inline acpi_status acpi_add_pm_notifier(struct acpi_device *adev,
struct device *dev,
@@ -535,11 +565,6 @@ static inline int acpi_pm_device_sleep_state(struct device *d, int *p, int m)
return (m >= ACPI_STATE_D0 && m <= ACPI_STATE_D3_COLD) ?
m : ACPI_STATE_D0;
}
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-int acpi_pm_device_run_wake(struct device *, bool);
-#else
static inline int acpi_pm_device_run_wake(struct device *dev, bool enable)
{
return -ENODEV;
diff --git a/include/acpi/acpixf.h b/include/acpi/acpixf.h
index ab2acf6..5ba7846 100644
--- a/include/acpi/acpixf.h
+++ b/include/acpi/acpixf.h
@@ -46,7 +46,7 @@
/* Current ACPICA subsystem version in YYYYMMDD format */
-#define ACPI_CA_VERSION 0x20140926
+#define ACPI_CA_VERSION 0x20141107
#include <acpi/acconfig.h>
#include <acpi/actypes.h>
diff --git a/include/acpi/actypes.h b/include/acpi/actypes.h
index 7000e66..bbef173 100644
--- a/include/acpi/actypes.h
+++ b/include/acpi/actypes.h
@@ -736,6 +736,10 @@ typedef u32 acpi_event_status;
#define ACPI_GPE_ENABLE 0
#define ACPI_GPE_DISABLE 1
#define ACPI_GPE_CONDITIONAL_ENABLE 2
+#define ACPI_GPE_SAVE_MASK 4
+
+#define ACPI_GPE_ENABLE_SAVE (ACPI_GPE_ENABLE | ACPI_GPE_SAVE_MASK)
+#define ACPI_GPE_DISABLE_SAVE (ACPI_GPE_DISABLE | ACPI_GPE_SAVE_MASK)
/*
* GPE info flags - Per GPE
diff --git a/include/acpi/processor.h b/include/acpi/processor.h
index 9b9b6f2..3ca9b75 100644
--- a/include/acpi/processor.h
+++ b/include/acpi/processor.h
@@ -67,9 +67,6 @@ struct acpi_processor_cx {
};
struct acpi_processor_power {
- struct acpi_processor_cx *state;
- unsigned long bm_check_timestamp;
- u32 default_state;
int count;
struct acpi_processor_cx states[ACPI_PROCESSOR_MAX_POWER];
int timer_broadcast_on_state;
@@ -313,11 +310,13 @@ static inline int acpi_processor_get_bios_limit(int cpu, unsigned int *limit)
#endif /* CONFIG_CPU_FREQ */
/* in processor_core.c */
-void acpi_processor_set_pdc(acpi_handle handle);
int acpi_get_apicid(acpi_handle, int type, u32 acpi_id);
int acpi_map_cpuid(int apic_id, u32 acpi_id);
int acpi_get_cpuid(acpi_handle, int type, u32 acpi_id);
+/* in processor_pdc.c */
+void acpi_processor_set_pdc(acpi_handle handle);
+
/* in processor_throttling.c */
int acpi_processor_tstate_has_changed(struct acpi_processor *pr);
int acpi_processor_get_throttling_info(struct acpi_processor *pr);
diff --git a/include/asm-generic/futex.h b/include/asm-generic/futex.h
index 01f227e..b59b5a5 100644
--- a/include/asm-generic/futex.h
+++ b/include/asm-generic/futex.h
@@ -5,6 +5,119 @@
#include <linux/uaccess.h>
#include <asm/errno.h>
+#ifndef CONFIG_SMP
+/*
+ * The following implementation only for uniprocessor machines.
+ * For UP, it's relies on the fact that pagefault_disable() also disables
+ * preemption to ensure mutual exclusion.
+ *
+ */
+
+/**
+ * futex_atomic_op_inuser() - Atomic arithmetic operation with constant
+ * argument and comparison of the previous
+ * futex value with another constant.
+ *
+ * @encoded_op: encoded operation to execute
+ * @uaddr: pointer to user space address
+ *
+ * Return:
+ * 0 - On success
+ * <0 - On error
+ */
+static inline int
+futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr)
+{
+ int op = (encoded_op >> 28) & 7;
+ int cmp = (encoded_op >> 24) & 15;
+ int oparg = (encoded_op << 8) >> 20;
+ int cmparg = (encoded_op << 20) >> 20;
+ int oldval, ret;
+ u32 tmp;
+
+ if (encoded_op & (FUTEX_OP_OPARG_SHIFT << 28))
+ oparg = 1 << oparg;
+
+ pagefault_disable();
+
+ ret = -EFAULT;
+ if (unlikely(get_user(oldval, uaddr) != 0))
+ goto out_pagefault_enable;
+
+ ret = 0;
+ tmp = oldval;
+
+ switch (op) {
+ case FUTEX_OP_SET:
+ tmp = oparg;
+ break;
+ case FUTEX_OP_ADD:
+ tmp += oparg;
+ break;
+ case FUTEX_OP_OR:
+ tmp |= oparg;
+ break;
+ case FUTEX_OP_ANDN:
+ tmp &= ~oparg;
+ break;
+ case FUTEX_OP_XOR:
+ tmp ^= oparg;
+ break;
+ default:
+ ret = -ENOSYS;
+ }
+
+ if (ret == 0 && unlikely(put_user(tmp, uaddr) != 0))
+ ret = -EFAULT;
+
+out_pagefault_enable:
+ pagefault_enable();
+
+ if (ret == 0) {
+ switch (cmp) {
+ case FUTEX_OP_CMP_EQ: ret = (oldval == cmparg); break;
+ case FUTEX_OP_CMP_NE: ret = (oldval != cmparg); break;
+ case FUTEX_OP_CMP_LT: ret = (oldval < cmparg); break;
+ case FUTEX_OP_CMP_GE: ret = (oldval >= cmparg); break;
+ case FUTEX_OP_CMP_LE: ret = (oldval <= cmparg); break;
+ case FUTEX_OP_CMP_GT: ret = (oldval > cmparg); break;
+ default: ret = -ENOSYS;
+ }
+ }
+ return ret;
+}
+
+/**
+ * futex_atomic_cmpxchg_inatomic() - Compare and exchange the content of the
+ * uaddr with newval if the current value is
+ * oldval.
+ * @uval: pointer to store content of @uaddr
+ * @uaddr: pointer to user space address
+ * @oldval: old value
+ * @newval: new value to store to @uaddr
+ *
+ * Return:
+ * 0 - On success
+ * <0 - On error
+ */
+static inline int
+futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
+ u32 oldval, u32 newval)
+{
+ u32 val;
+
+ if (unlikely(get_user(val, uaddr) != 0))
+ return -EFAULT;
+
+ if (val == oldval && unlikely(put_user(newval, uaddr) != 0))
+ return -EFAULT;
+
+ *uval = val;
+
+ return 0;
+}
+
+#else
static inline int
futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr)
{
@@ -54,4 +167,5 @@ futex_atomic_cmpxchg_inatomic(u32 *uval, u32 __user *uaddr,
return -ENOSYS;
}
+#endif /* CONFIG_SMP */
#endif
diff --git a/include/asm-generic/io.h b/include/asm-generic/io.h
index b8fdc57..9db0423 100644
--- a/include/asm-generic/io.h
+++ b/include/asm-generic/io.h
@@ -12,6 +12,7 @@
#define __ASM_GENERIC_IO_H
#include <asm/page.h> /* I/O is all done through memory accesses */
+#include <linux/string.h> /* for memset() and memcpy() */
#include <linux/types.h>
#ifdef CONFIG_GENERIC_IOMAP
@@ -24,260 +25,691 @@
#define mmiowb() do {} while (0)
#endif
-/*****************************************************************************/
/*
- * readX/writeX() are used to access memory mapped devices. On some
- * architectures the memory mapped IO stuff needs to be accessed
- * differently. On the simple architectures, we just read/write the
- * memory location directly.
+ * __raw_{read,write}{b,w,l,q}() access memory in native endianness.
+ *
+ * On some architectures memory mapped IO needs to be accessed differently.
+ * On the simple architectures, we just read/write the memory location
+ * directly.
*/
+
#ifndef __raw_readb
+#define __raw_readb __raw_readb
static inline u8 __raw_readb(const volatile void __iomem *addr)
{
- return *(const volatile u8 __force *) addr;
+ return *(const volatile u8 __force *)addr;
}
#endif
#ifndef __raw_readw
+#define __raw_readw __raw_readw
static inline u16 __raw_readw(const volatile void __iomem *addr)
{
- return *(const volatile u16 __force *) addr;
+ return *(const volatile u16 __force *)addr;
}
#endif
#ifndef __raw_readl
+#define __raw_readl __raw_readl
static inline u32 __raw_readl(const volatile void __iomem *addr)
{
- return *(const volatile u32 __force *) addr;
+ return *(const volatile u32 __force *)addr;
}
#endif
-#define readb __raw_readb
-
-#define readw readw
-static inline u16 readw(const volatile void __iomem *addr)
-{
- return __le16_to_cpu(__raw_readw(addr));
-}
-
-#define readl readl
-static inline u32 readl(const volatile void __iomem *addr)
+#ifdef CONFIG_64BIT
+#ifndef __raw_readq
+#define __raw_readq __raw_readq
+static inline u64 __raw_readq(const volatile void __iomem *addr)
{
- return __le32_to_cpu(__raw_readl(addr));
+ return *(const volatile u64 __force *)addr;
}
+#endif
+#endif /* CONFIG_64BIT */
#ifndef __raw_writeb
-static inline void __raw_writeb(u8 b, volatile void __iomem *addr)
+#define __raw_writeb __raw_writeb
+static inline void __raw_writeb(u8 value, volatile void __iomem *addr)
{
- *(volatile u8 __force *) addr = b;
+ *(volatile u8 __force *)addr = value;
}
#endif
#ifndef __raw_writew
-static inline void __raw_writew(u16 b, volatile void __iomem *addr)
+#define __raw_writew __raw_writew
+static inline void __raw_writew(u16 value, volatile void __iomem *addr)
{
- *(volatile u16 __force *) addr = b;
+ *(volatile u16 __force *)addr = value;
}
#endif
#ifndef __raw_writel
-static inline void __raw_writel(u32 b, volatile void __iomem *addr)
+#define __raw_writel __raw_writel
+static inline void __raw_writel(u32 value, volatile void __iomem *addr)
{
- *(volatile u32 __force *) addr = b;
+ *(volatile u32 __force *)addr = value;
}
#endif
-#define writeb __raw_writeb
-#define writew(b,addr) __raw_writew(__cpu_to_le16(b),addr)
-#define writel(b,addr) __raw_writel(__cpu_to_le32(b),addr)
-
#ifdef CONFIG_64BIT
-#ifndef __raw_readq
-static inline u64 __raw_readq(const volatile void __iomem *addr)
+#ifndef __raw_writeq
+#define __raw_writeq __raw_writeq
+static inline void __raw_writeq(u64 value, volatile void __iomem *addr)
{
- return *(const volatile u64 __force *) addr;
+ *(volatile u64 __force *)addr = value;
}
#endif
+#endif /* CONFIG_64BIT */
-#define readq readq
-static inline u64 readq(const volatile void __iomem *addr)
-{
- return __le64_to_cpu(__raw_readq(addr));
-}
+/*
+ * {read,write}{b,w,l,q}() access little endian memory and return result in
+ * native endianness.
+ */
-#ifndef __raw_writeq
-static inline void __raw_writeq(u64 b, volatile void __iomem *addr)
+#ifndef readb
+#define readb readb
+static inline u8 readb(const volatile void __iomem *addr)
{
- *(volatile u64 __force *) addr = b;
+ return __raw_readb(addr);
}
#endif
-#define writeq(b, addr) __raw_writeq(__cpu_to_le64(b), addr)
-#endif /* CONFIG_64BIT */
-
-#ifndef PCI_IOBASE
-#define PCI_IOBASE ((void __iomem *) 0)
+#ifndef readw
+#define readw readw
+static inline u16 readw(const volatile void __iomem *addr)
+{
+ return __le16_to_cpu(__raw_readw(addr));
+}
#endif
-/*****************************************************************************/
-/*
- * traditional input/output functions
- */
-
-static inline u8 inb(unsigned long addr)
+#ifndef readl
+#define readl readl
+static inline u32 readl(const volatile void __iomem *addr)
{
- return readb(addr + PCI_IOBASE);
+ return __le32_to_cpu(__raw_readl(addr));
}
+#endif
-static inline u16 inw(unsigned long addr)
+#ifdef CONFIG_64BIT
+#ifndef readq
+#define readq readq
+static inline u64 readq(const volatile void __iomem *addr)
{
- return readw(addr + PCI_IOBASE);
+ return __le64_to_cpu(__raw_readq(addr));
}
+#endif
+#endif /* CONFIG_64BIT */
-static inline u32 inl(unsigned long addr)
+#ifndef writeb
+#define writeb writeb
+static inline void writeb(u8 value, volatile void __iomem *addr)
{
- return readl(addr + PCI_IOBASE);
+ __raw_writeb(value, addr);
}
+#endif
-static inline void outb(u8 b, unsigned long addr)
+#ifndef writew
+#define writew writew
+static inline void writew(u16 value, volatile void __iomem *addr)
{
- writeb(b, addr + PCI_IOBASE);
+ __raw_writew(cpu_to_le16(value), addr);
}
+#endif
-static inline void outw(u16 b, unsigned long addr)
+#ifndef writel
+#define writel writel
+static inline void writel(u32 value, volatile void __iomem *addr)
{
- writew(b, addr + PCI_IOBASE);
+ __raw_writel(__cpu_to_le32(value), addr);
}
+#endif
-static inline void outl(u32 b, unsigned long addr)
+#ifdef CONFIG_64BIT
+#ifndef writeq
+#define writeq writeq
+static inline void writeq(u64 value, volatile void __iomem *addr)
{
- writel(b, addr + PCI_IOBASE);
+ __raw_writeq(__cpu_to_le64(value), addr);
}
+#endif
+#endif /* CONFIG_64BIT */
+
+/*
+ * {read,write}{b,w,l,q}_relaxed() are like the regular version, but
+ * are not guaranteed to provide ordering against spinlocks or memory
+ * accesses.
+ */
+#ifndef readb_relaxed
+#define readb_relaxed readb
+#endif
-#define inb_p(addr) inb(addr)
-#define inw_p(addr) inw(addr)
-#define inl_p(addr) inl(addr)
-#define outb_p(x, addr) outb((x), (addr))
-#define outw_p(x, addr) outw((x), (addr))
-#define outl_p(x, addr) outl((x), (addr))
+#ifndef readw_relaxed
+#define readw_relaxed readw
+#endif
-#ifndef insb
-static inline void insb(unsigned long addr, void *buffer, int count)
+#ifndef readl_relaxed
+#define readl_relaxed readl
+#endif
+
+#ifndef readq_relaxed
+#define readq_relaxed readq
+#endif
+
+#ifndef writeb_relaxed
+#define writeb_relaxed writeb
+#endif
+
+#ifndef writew_relaxed
+#define writew_relaxed writew
+#endif
+
+#ifndef writel_relaxed
+#define writel_relaxed writel
+#endif
+
+#ifndef writeq_relaxed
+#define writeq_relaxed writeq
+#endif
+
+/*
+ * {read,write}s{b,w,l,q}() repeatedly access the same memory address in
+ * native endianness in 8-, 16-, 32- or 64-bit chunks (@count times).
+ */
+#ifndef readsb
+#define readsb readsb
+static inline void readsb(const volatile void __iomem *addr, void *buffer,
+ unsigned int count)
{
if (count) {
u8 *buf = buffer;
+
do {
- u8 x = __raw_readb(addr + PCI_IOBASE);
+ u8 x = __raw_readb(addr);
*buf++ = x;
} while (--count);
}
}
#endif
-#ifndef insw
-static inline void insw(unsigned long addr, void *buffer, int count)
+#ifndef readsw
+#define readsw readsw
+static inline void readsw(const volatile void __iomem *addr, void *buffer,
+ unsigned int count)
{
if (count) {
u16 *buf = buffer;
+
do {
- u16 x = __raw_readw(addr + PCI_IOBASE);
+ u16 x = __raw_readw(addr);
*buf++ = x;
} while (--count);
}
}
#endif
-#ifndef insl
-static inline void insl(unsigned long addr, void *buffer, int count)
+#ifndef readsl
+#define readsl readsl
+static inline void readsl(const volatile void __iomem *addr, void *buffer,
+ unsigned int count)
{
if (count) {
u32 *buf = buffer;
+
do {
- u32 x = __raw_readl(addr + PCI_IOBASE);
+ u32 x = __raw_readl(addr);
*buf++ = x;
} while (--count);
}
}
#endif
-#ifndef outsb
-static inline void outsb(unsigned long addr, const void *buffer, int count)
+#ifdef CONFIG_64BIT
+#ifndef readsq
+#define readsq readsq
+static inline void readsq(const volatile void __iomem *addr, void *buffer,
+ unsigned int count)
+{
+ if (count) {
+ u64 *buf = buffer;
+
+ do {
+ u64 x = __raw_readq(addr);
+ *buf++ = x;
+ } while (--count);
+ }
+}
+#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef writesb
+#define writesb writesb
+static inline void writesb(volatile void __iomem *addr, const void *buffer,
+ unsigned int count)
{
if (count) {
const u8 *buf = buffer;
+
do {
- __raw_writeb(*buf++, addr + PCI_IOBASE);
+ __raw_writeb(*buf++, addr);
} while (--count);
}
}
#endif
-#ifndef outsw
-static inline void outsw(unsigned long addr, const void *buffer, int count)
+#ifndef writesw
+#define writesw writesw
+static inline void writesw(volatile void __iomem *addr, const void *buffer,
+ unsigned int count)
{
if (count) {
const u16 *buf = buffer;
+
do {
- __raw_writew(*buf++, addr + PCI_IOBASE);
+ __raw_writew(*buf++, addr);
} while (--count);
}
}
#endif
-#ifndef outsl
-static inline void outsl(unsigned long addr, const void *buffer, int count)
+#ifndef writesl
+#define writesl writesl
+static inline void writesl(volatile void __iomem *addr, const void *buffer,
+ unsigned int count)
{
if (count) {
const u32 *buf = buffer;
+
do {
- __raw_writel(*buf++, addr + PCI_IOBASE);
+ __raw_writel(*buf++, addr);
} while (--count);
}
}
#endif
-#ifndef CONFIG_GENERIC_IOMAP
-#define ioread8(addr) readb(addr)
-#define ioread16(addr) readw(addr)
-#define ioread16be(addr) __be16_to_cpu(__raw_readw(addr))
-#define ioread32(addr) readl(addr)
-#define ioread32be(addr) __be32_to_cpu(__raw_readl(addr))
-
-#define iowrite8(v, addr) writeb((v), (addr))
-#define iowrite16(v, addr) writew((v), (addr))
-#define iowrite16be(v, addr) __raw_writew(__cpu_to_be16(v), addr)
-#define iowrite32(v, addr) writel((v), (addr))
-#define iowrite32be(v, addr) __raw_writel(__cpu_to_be32(v), addr)
-
-#define ioread8_rep(p, dst, count) \
- insb((unsigned long) (p), (dst), (count))
-#define ioread16_rep(p, dst, count) \
- insw((unsigned long) (p), (dst), (count))
-#define ioread32_rep(p, dst, count) \
- insl((unsigned long) (p), (dst), (count))
-
-#define iowrite8_rep(p, src, count) \
- outsb((unsigned long) (p), (src), (count))
-#define iowrite16_rep(p, src, count) \
- outsw((unsigned long) (p), (src), (count))
-#define iowrite32_rep(p, src, count) \
- outsl((unsigned long) (p), (src), (count))
-#endif /* CONFIG_GENERIC_IOMAP */
+#ifdef CONFIG_64BIT
+#ifndef writesq
+#define writesq writesq
+static inline void writesq(volatile void __iomem *addr, const void *buffer,
+ unsigned int count)
+{
+ if (count) {
+ const u64 *buf = buffer;
+
+ do {
+ __raw_writeq(*buf++, addr);
+ } while (--count);
+ }
+}
+#endif
+#endif /* CONFIG_64BIT */
+
+#ifndef PCI_IOBASE
+#define PCI_IOBASE ((void __iomem *)0)
+#endif
#ifndef IO_SPACE_LIMIT
#define IO_SPACE_LIMIT 0xffff
#endif
+/*
+ * {in,out}{b,w,l}() access little endian I/O. {in,out}{b,w,l}_p() can be
+ * implemented on hardware that needs an additional delay for I/O accesses to
+ * take effect.
+ */
+
+#ifndef inb
+#define inb inb
+static inline u8 inb(unsigned long addr)
+{
+ return readb(PCI_IOBASE + addr);
+}
+#endif
+
+#ifndef inw
+#define inw inw
+static inline u16 inw(unsigned long addr)
+{
+ return readw(PCI_IOBASE + addr);
+}
+#endif
+
+#ifndef inl
+#define inl inl
+static inline u32 inl(unsigned long addr)
+{
+ return readl(PCI_IOBASE + addr);
+}
+#endif
+
+#ifndef outb
+#define outb outb
+static inline void outb(u8 value, unsigned long addr)
+{
+ writeb(value, PCI_IOBASE + addr);
+}
+#endif
+
+#ifndef outw
+#define outw outw
+static inline void outw(u16 value, unsigned long addr)
+{
+ writew(value, PCI_IOBASE + addr);
+}
+#endif
+
+#ifndef outl
+#define outl outl
+static inline void outl(u32 value, unsigned long addr)
+{
+ writel(value, PCI_IOBASE + addr);
+}
+#endif
+
+#ifndef inb_p
+#define inb_p inb_p
+static inline u8 inb_p(unsigned long addr)
+{
+ return inb(addr);
+}
+#endif
+
+#ifndef inw_p
+#define inw_p inw_p
+static inline u16 inw_p(unsigned long addr)
+{
+ return inw(addr);
+}
+#endif
+
+#ifndef inl_p
+#define inl_p inl_p
+static inline u32 inl_p(unsigned long addr)
+{
+ return inl(addr);
+}
+#endif
+
+#ifndef outb_p
+#define outb_p outb_p
+static inline void outb_p(u8 value, unsigned long addr)
+{
+ outb(value, addr);
+}
+#endif
+
+#ifndef outw_p
+#define outw_p outw_p
+static inline void outw_p(u16 value, unsigned long addr)
+{
+ outw(value, addr);
+}
+#endif
+
+#ifndef outl_p
+#define outl_p outl_p
+static inline void outl_p(u32 value, unsigned long addr)
+{
+ outl(value, addr);
+}
+#endif
+
+/*
+ * {in,out}s{b,w,l}{,_p}() are variants of the above that repeatedly access a
+ * single I/O port multiple times.
+ */
+
+#ifndef insb
+#define insb insb
+static inline void insb(unsigned long addr, void *buffer, unsigned int count)
+{
+ readsb(PCI_IOBASE + addr, buffer, count);
+}
+#endif
+
+#ifndef insw
+#define insw insw
+static inline void insw(unsigned long addr, void *buffer, unsigned int count)
+{
+ readsw(PCI_IOBASE + addr, buffer, count);
+}
+#endif
+
+#ifndef insl
+#define insl insl
+static inline void insl(unsigned long addr, void *buffer, unsigned int count)
+{
+ readsl(PCI_IOBASE + addr, buffer, count);
+}
+#endif
+
+#ifndef outsb
+#define outsb outsb
+static inline void outsb(unsigned long addr, const void *buffer,
+ unsigned int count)
+{
+ writesb(PCI_IOBASE + addr, buffer, count);
+}
+#endif
+
+#ifndef outsw
+#define outsw outsw
+static inline void outsw(unsigned long addr, const void *buffer,
+ unsigned int count)
+{
+ writesw(PCI_IOBASE + addr, buffer, count);
+}
+#endif
+
+#ifndef outsl
+#define outsl outsl
+static inline void outsl(unsigned long addr, const void *buffer,
+ unsigned int count)
+{
+ writesl(PCI_IOBASE + addr, buffer, count);
+}
+#endif
+
+#ifndef insb_p
+#define insb_p insb_p
+static inline void insb_p(unsigned long addr, void *buffer, unsigned int count)
+{
+ insb(addr, buffer, count);
+}
+#endif
+
+#ifndef insw_p
+#define insw_p insw_p
+static inline void insw_p(unsigned long addr, void *buffer, unsigned int count)
+{
+ insw(addr, buffer, count);
+}
+#endif
+
+#ifndef insl_p
+#define insl_p insl_p
+static inline void insl_p(unsigned long addr, void *buffer, unsigned int count)
+{
+ insl(addr, buffer, count);
+}
+#endif
+
+#ifndef outsb_p
+#define outsb_p outsb_p
+static inline void outsb_p(unsigned long addr, const void *buffer,
+ unsigned int count)
+{
+ outsb(addr, buffer, count);
+}
+#endif
+
+#ifndef outsw_p
+#define outsw_p outsw_p
+static inline void outsw_p(unsigned long addr, const void *buffer,
+ unsigned int count)
+{
+ outsw(addr, buffer, count);
+}
+#endif
+
+#ifndef outsl_p
+#define outsl_p outsl_p
+static inline void outsl_p(unsigned long addr, const void *buffer,
+ unsigned int count)
+{
+ outsl(addr, buffer, count);
+}
+#endif
+
+#ifndef CONFIG_GENERIC_IOMAP
+#ifndef ioread8
+#define ioread8 ioread8
+static inline u8 ioread8(const volatile void __iomem *addr)
+{
+ return readb(addr);
+}
+#endif
+
+#ifndef ioread16
+#define ioread16 ioread16
+static inline u16 ioread16(const volatile void __iomem *addr)
+{
+ return readw(addr);
+}
+#endif
+
+#ifndef ioread32
+#define ioread32 ioread32
+static inline u32 ioread32(const volatile void __iomem *addr)
+{
+ return readl(addr);
+}
+#endif
+
+#ifndef iowrite8
+#define iowrite8 iowrite8
+static inline void iowrite8(u8 value, volatile void __iomem *addr)
+{
+ writeb(value, addr);
+}
+#endif
+
+#ifndef iowrite16
+#define iowrite16 iowrite16
+static inline void iowrite16(u16 value, volatile void __iomem *addr)
+{
+ writew(value, addr);
+}
+#endif
+
+#ifndef iowrite32
+#define iowrite32 iowrite32
+static inline void iowrite32(u32 value, volatile void __iomem *addr)
+{
+ writel(value, addr);
+}
+#endif
+
+#ifndef ioread16be
+#define ioread16be ioread16be
+static inline u16 ioread16be(const volatile void __iomem *addr)
+{
+ return __be16_to_cpu(__raw_readw(addr));
+}
+#endif
+
+#ifndef ioread32be
+#define ioread32be ioread32be
+static inline u32 ioread32be(const volatile void __iomem *addr)
+{
+ return __be32_to_cpu(__raw_readl(addr));
+}
+#endif
+
+#ifndef iowrite16be
+#define iowrite16be iowrite16be
+static inline void iowrite16be(u16 value, void volatile __iomem *addr)
+{
+ __raw_writew(__cpu_to_be16(value), addr);
+}
+#endif
+
+#ifndef iowrite32be
+#define iowrite32be iowrite32be
+static inline void iowrite32be(u32 value, volatile void __iomem *addr)
+{
+ __raw_writel(__cpu_to_be32(value), addr);
+}
+#endif
+
+#ifndef ioread8_rep
+#define ioread8_rep ioread8_rep
+static inline void ioread8_rep(const volatile void __iomem *addr, void *buffer,
+ unsigned int count)
+{
+ readsb(addr, buffer, count);
+}
+#endif
+
+#ifndef ioread16_rep
+#define ioread16_rep ioread16_rep
+static inline void ioread16_rep(const volatile void __iomem *addr,
+ void *buffer, unsigned int count)
+{
+ readsw(addr, buffer, count);
+}
+#endif
+
+#ifndef ioread32_rep
+#define ioread32_rep ioread32_rep
+static inline void ioread32_rep(const volatile void __iomem *addr,
+ void *buffer, unsigned int count)
+{
+ readsl(addr, buffer, count);
+}
+#endif
+
+#ifndef iowrite8_rep
+#define iowrite8_rep iowrite8_rep
+static inline void iowrite8_rep(volatile void __iomem *addr,
+ const void *buffer,
+ unsigned int count)
+{
+ writesb(addr, buffer, count);
+}
+#endif
+
+#ifndef iowrite16_rep
+#define iowrite16_rep iowrite16_rep
+static inline void iowrite16_rep(volatile void __iomem *addr,
+ const void *buffer,
+ unsigned int count)
+{
+ writesw(addr, buffer, count);
+}
+#endif
+
+#ifndef iowrite32_rep
+#define iowrite32_rep iowrite32_rep
+static inline void iowrite32_rep(volatile void __iomem *addr,
+ const void *buffer,
+ unsigned int count)
+{
+ writesl(addr, buffer, count);
+}
+#endif
+#endif /* CONFIG_GENERIC_IOMAP */
+
#ifdef __KERNEL__
#include <linux/vmalloc.h>
-#define __io_virt(x) ((void __force *) (x))
+#define __io_virt(x) ((void __force *)(x))
#ifndef CONFIG_GENERIC_IOMAP
struct pci_dev;
extern void __iomem *pci_iomap(struct pci_dev *dev, int bar, unsigned long max);
#ifndef pci_iounmap
+#define pci_iounmap pci_iounmap
static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
{
}
@@ -289,11 +721,15 @@ static inline void pci_iounmap(struct pci_dev *dev, void __iomem *p)
* These are pretty trivial
*/
#ifndef virt_to_phys
+#define virt_to_phys virt_to_phys
static inline unsigned long virt_to_phys(volatile void *address)
{
return __pa((unsigned long)address);
}
+#endif
+#ifndef phys_to_virt
+#define phys_to_virt phys_to_virt
static inline void *phys_to_virt(unsigned long address)
{
return __va(address);
@@ -306,37 +742,65 @@ static inline void *phys_to_virt(unsigned long address)
* This implementation is for the no-MMU case only... if you have an MMU
* you'll need to provide your own definitions.
*/
+
#ifndef CONFIG_MMU
-static inline void __iomem *ioremap(phys_addr_t offset, unsigned long size)
+#ifndef ioremap
+#define ioremap ioremap
+static inline void __iomem *ioremap(phys_addr_t offset, size_t size)
{
- return (void __iomem*) (unsigned long)offset;
+ return (void __iomem *)(unsigned long)offset;
}
+#endif
-#define __ioremap(offset, size, flags) ioremap(offset, size)
+#ifndef __ioremap
+#define __ioremap __ioremap
+static inline void __iomem *__ioremap(phys_addr_t offset, size_t size,
+ unsigned long flags)
+{
+ return ioremap(offset, size);
+}
+#endif
#ifndef ioremap_nocache
-#define ioremap_nocache ioremap
+#define ioremap_nocache ioremap_nocache
+static inline void __iomem *ioremap_nocache(phys_addr_t offset, size_t size)
+{
+ return ioremap(offset, size);
+}
#endif
#ifndef ioremap_wc
-#define ioremap_wc ioremap_nocache
+#define ioremap_wc ioremap_wc
+static inline void __iomem *ioremap_wc(phys_addr_t offset, size_t size)
+{
+ return ioremap_nocache(offset, size);
+}
#endif
+#ifndef iounmap
+#define iounmap iounmap
static inline void iounmap(void __iomem *addr)
{
}
+#endif
#endif /* CONFIG_MMU */
#ifdef CONFIG_HAS_IOPORT_MAP
#ifndef CONFIG_GENERIC_IOMAP
+#ifndef ioport_map
+#define ioport_map ioport_map
static inline void __iomem *ioport_map(unsigned long port, unsigned int nr)
{
return PCI_IOBASE + (port & IO_SPACE_LIMIT);
}
+#endif
+#ifndef ioport_unmap
+#define ioport_unmap ioport_unmap
static inline void ioport_unmap(void __iomem *p)
{
}
+#endif
#else /* CONFIG_GENERIC_IOMAP */
extern void __iomem *ioport_map(unsigned long port, unsigned int nr);
extern void ioport_unmap(void __iomem *p);
@@ -344,35 +808,68 @@ extern void ioport_unmap(void __iomem *p);
#endif /* CONFIG_HAS_IOPORT_MAP */
#ifndef xlate_dev_kmem_ptr
-#define xlate_dev_kmem_ptr(p) p
+#define xlate_dev_kmem_ptr xlate_dev_kmem_ptr
+static inline void *xlate_dev_kmem_ptr(void *addr)
+{
+ return addr;
+}
#endif
+
#ifndef xlate_dev_mem_ptr
-#define xlate_dev_mem_ptr(p) __va(p)
+#define xlate_dev_mem_ptr xlate_dev_mem_ptr
+static inline void *xlate_dev_mem_ptr(phys_addr_t addr)
+{
+ return __va(addr);
+}
+#endif
+
+#ifndef unxlate_dev_mem_ptr
+#define unxlate_dev_mem_ptr unxlate_dev_mem_ptr
+static inline void unxlate_dev_mem_ptr(phys_addr_t phys, void *addr)
+{
+}
#endif
#ifdef CONFIG_VIRT_TO_BUS
#ifndef virt_to_bus
-static inline unsigned long virt_to_bus(volatile void *address)
+static inline unsigned long virt_to_bus(void *address)
{
- return ((unsigned long) address);
+ return (unsigned long)address;
}
static inline void *bus_to_virt(unsigned long address)
{
- return (void *) address;
+ return (void *)address;
}
#endif
#endif
#ifndef memset_io
-#define memset_io(a, b, c) memset(__io_virt(a), (b), (c))
+#define memset_io memset_io
+static inline void memset_io(volatile void __iomem *addr, int value,
+ size_t size)
+{
+ memset(__io_virt(addr), value, size);
+}
#endif
#ifndef memcpy_fromio
-#define memcpy_fromio(a, b, c) memcpy((a), __io_virt(b), (c))
+#define memcpy_fromio memcpy_fromio
+static inline void memcpy_fromio(void *buffer,
+ const volatile void __iomem *addr,
+ size_t size)
+{
+ memcpy(buffer, __io_virt(addr), size);
+}
#endif
+
#ifndef memcpy_toio
-#define memcpy_toio(a, b, c) memcpy(__io_virt(a), (b), (c))
+#define memcpy_toio memcpy_toio
+static inline void memcpy_toio(volatile void __iomem *addr, const void *buffer,
+ size_t size)
+{
+ memcpy(__io_virt(addr), buffer, size);
+}
#endif
#endif /* __KERNEL__ */
diff --git a/include/asm-generic/mm_hooks.h b/include/asm-generic/mm_hooks.h
index 67dea81..866aa46 100644
--- a/include/asm-generic/mm_hooks.h
+++ b/include/asm-generic/mm_hooks.h
@@ -1,7 +1,7 @@
/*
- * Define generic no-op hooks for arch_dup_mmap and arch_exit_mmap, to
- * be included in asm-FOO/mmu_context.h for any arch FOO which doesn't
- * need to hook these.
+ * Define generic no-op hooks for arch_dup_mmap, arch_exit_mmap
+ * and arch_unmap to be included in asm-FOO/mmu_context.h for any
+ * arch FOO which doesn't need to hook these.
*/
#ifndef _ASM_GENERIC_MM_HOOKS_H
#define _ASM_GENERIC_MM_HOOKS_H
@@ -15,4 +15,15 @@ static inline void arch_exit_mmap(struct mm_struct *mm)
{
}
+static inline void arch_unmap(struct mm_struct *mm,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+}
+
+static inline void arch_bprm_mm_init(struct mm_struct *mm,
+ struct vm_area_struct *vma)
+{
+}
+
#endif /* _ASM_GENERIC_MM_HOOKS_H */
diff --git a/include/asm-generic/msi.h b/include/asm-generic/msi.h
new file mode 100644
index 0000000..61c58d8
--- /dev/null
+++ b/include/asm-generic/msi.h
@@ -0,0 +1,32 @@
+#ifndef __ASM_GENERIC_MSI_H
+#define __ASM_GENERIC_MSI_H
+
+#include <linux/types.h>
+
+#ifndef NUM_MSI_ALLOC_SCRATCHPAD_REGS
+# define NUM_MSI_ALLOC_SCRATCHPAD_REGS 2
+#endif
+
+struct msi_desc;
+
+/**
+ * struct msi_alloc_info - Default structure for MSI interrupt allocation.
+ * @desc: Pointer to msi descriptor
+ * @hwirq: Associated hw interrupt number in the domain
+ * @scratchpad: Storage for implementation specific scratch data
+ *
+ * Architectures can provide their own implementation by not including
+ * asm-generic/msi.h into their arch specific header file.
+ */
+typedef struct msi_alloc_info {
+ struct msi_desc *desc;
+ irq_hw_number_t hwirq;
+ union {
+ unsigned long ul;
+ void *ptr;
+ } scratchpad[NUM_MSI_ALLOC_SCRATCHPAD_REGS];
+} msi_alloc_info_t;
+
+#define GENERIC_MSI_DOMAIN_OPS 1
+
+#endif
diff --git a/include/asm-generic/preempt.h b/include/asm-generic/preempt.h
index 1cd3f5d..eb6f9e6 100644
--- a/include/asm-generic/preempt.h
+++ b/include/asm-generic/preempt.h
@@ -23,9 +23,6 @@ static __always_inline void preempt_count_set(int pc)
/*
* must be macros to avoid header recursion hell
*/
-#define task_preempt_count(p) \
- (task_thread_info(p)->preempt_count & ~PREEMPT_NEED_RESCHED)
-
#define init_task_preempt_count(p) do { \
task_thread_info(p)->preempt_count = PREEMPT_DISABLED; \
} while (0)
diff --git a/include/asm-generic/seccomp.h b/include/asm-generic/seccomp.h
new file mode 100644
index 0000000..9fa1f65
--- /dev/null
+++ b/include/asm-generic/seccomp.h
@@ -0,0 +1,30 @@
+/*
+ * include/asm-generic/seccomp.h
+ *
+ * Copyright (C) 2014 Linaro Limited
+ * Author: AKASHI Takahiro <takahiro.akashi@linaro.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef _ASM_GENERIC_SECCOMP_H
+#define _ASM_GENERIC_SECCOMP_H
+
+#include <linux/unistd.h>
+
+#if defined(CONFIG_COMPAT) && !defined(__NR_seccomp_read_32)
+#define __NR_seccomp_read_32 __NR_read
+#define __NR_seccomp_write_32 __NR_write
+#define __NR_seccomp_exit_32 __NR_exit
+#define __NR_seccomp_sigreturn_32 __NR_rt_sigreturn
+#endif /* CONFIG_COMPAT && ! already defined */
+
+#define __NR_seccomp_read __NR_read
+#define __NR_seccomp_write __NR_write
+#define __NR_seccomp_exit __NR_exit
+#ifndef __NR_seccomp_sigreturn
+#define __NR_seccomp_sigreturn __NR_rt_sigreturn
+#endif
+
+#endif /* _ASM_GENERIC_SECCOMP_H */
diff --git a/include/asm-generic/tlb.h b/include/asm-generic/tlb.h
index 5672d7e..0884805 100644
--- a/include/asm-generic/tlb.h
+++ b/include/asm-generic/tlb.h
@@ -96,10 +96,9 @@ struct mmu_gather {
#endif
unsigned long start;
unsigned long end;
- unsigned int need_flush : 1, /* Did free PTEs */
/* we are in the middle of an operation to clear
* a full mm and can make some optimizations */
- fullmm : 1,
+ unsigned int fullmm : 1,
/* we have performed an operation which
* requires a complete flush of the tlb */
need_flush_all : 1;
@@ -128,16 +127,54 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
tlb_flush_mmu(tlb);
}
+static inline void __tlb_adjust_range(struct mmu_gather *tlb,
+ unsigned long address)
+{
+ tlb->start = min(tlb->start, address);
+ tlb->end = max(tlb->end, address + PAGE_SIZE);
+}
+
+static inline void __tlb_reset_range(struct mmu_gather *tlb)
+{
+ tlb->start = TASK_SIZE;
+ tlb->end = 0;
+}
+
+/*
+ * In the case of tlb vma handling, we can optimise these away in the
+ * case where we're doing a full MM flush. When we're doing a munmap,
+ * the vmas are adjusted to only cover the region to be torn down.
+ */
+#ifndef tlb_start_vma
+#define tlb_start_vma(tlb, vma) do { } while (0)
+#endif
+
+#define __tlb_end_vma(tlb, vma) \
+ do { \
+ if (!tlb->fullmm && tlb->end) { \
+ tlb_flush(tlb); \
+ __tlb_reset_range(tlb); \
+ } \
+ } while (0)
+
+#ifndef tlb_end_vma
+#define tlb_end_vma __tlb_end_vma
+#endif
+
+#ifndef __tlb_remove_tlb_entry
+#define __tlb_remove_tlb_entry(tlb, ptep, address) do { } while (0)
+#endif
+
/**
* tlb_remove_tlb_entry - remember a pte unmapping for later tlb invalidation.
*
- * Record the fact that pte's were really umapped in ->need_flush, so we can
- * later optimise away the tlb invalidate. This helps when userspace is
- * unmapping already-unmapped pages, which happens quite a lot.
+ * Record the fact that pte's were really unmapped by updating the range,
+ * so we can later optimise away the tlb invalidate. This helps when
+ * userspace is unmapping already-unmapped pages, which happens quite a lot.
*/
#define tlb_remove_tlb_entry(tlb, ptep, address) \
do { \
- tlb->need_flush = 1; \
+ __tlb_adjust_range(tlb, address); \
__tlb_remove_tlb_entry(tlb, ptep, address); \
} while (0)
@@ -151,27 +188,27 @@ static inline void tlb_remove_page(struct mmu_gather *tlb, struct page *page)
#define tlb_remove_pmd_tlb_entry(tlb, pmdp, address) \
do { \
- tlb->need_flush = 1; \
+ __tlb_adjust_range(tlb, address); \
__tlb_remove_pmd_tlb_entry(tlb, pmdp, address); \
} while (0)
#define pte_free_tlb(tlb, ptep, address) \
do { \
- tlb->need_flush = 1; \
+ __tlb_adjust_range(tlb, address); \
__pte_free_tlb(tlb, ptep, address); \
} while (0)
#ifndef __ARCH_HAS_4LEVEL_HACK
#define pud_free_tlb(tlb, pudp, address) \
do { \
- tlb->need_flush = 1; \
+ __tlb_adjust_range(tlb, address); \
__pud_free_tlb(tlb, pudp, address); \
} while (0)
#endif
#define pmd_free_tlb(tlb, pmdp, address) \
do { \
- tlb->need_flush = 1; \
+ __tlb_adjust_range(tlb, address); \
__pmd_free_tlb(tlb, pmdp, address); \
} while (0)
diff --git a/include/dt-bindings/arm/ux500_pm_domains.h b/include/dt-bindings/arm/ux500_pm_domains.h
new file mode 100644
index 0000000..398a6c0
--- /dev/null
+++ b/include/dt-bindings/arm/ux500_pm_domains.h
@@ -0,0 +1,15 @@
+/*
+ * Copyright (C) 2014 Linaro Ltd.
+ *
+ * Author: Ulf Hansson <ulf.hansson@linaro.org>
+ * License terms: GNU General Public License (GPL) version 2
+ */
+#ifndef _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H
+#define _DT_BINDINGS_ARM_UX500_PM_DOMAINS_H
+
+#define DOMAIN_VAPE 0
+
+/* Number of PM domains. */
+#define NR_DOMAINS (DOMAIN_VAPE + 1)
+
+#endif
diff --git a/include/dt-bindings/clock/imx5-clock.h b/include/dt-bindings/clock/imx5-clock.h
index 5f2667ec..f4b7478 100644
--- a/include/dt-bindings/clock/imx5-clock.h
+++ b/include/dt-bindings/clock/imx5-clock.h
@@ -198,6 +198,9 @@
#define IMX5_CLK_OCRAM 186
#define IMX5_CLK_SAHARA_IPG_GATE 187
#define IMX5_CLK_SATA_REF 188
-#define IMX5_CLK_END 189
+#define IMX5_CLK_STEP_SEL 189
+#define IMX5_CLK_CPU_PODF_SEL 190
+#define IMX5_CLK_ARM 191
+#define IMX5_CLK_END 192
#endif /* __DT_BINDINGS_CLOCK_IMX5_H */
diff --git a/include/dt-bindings/clock/r8a7740-clock.h b/include/dt-bindings/clock/r8a7740-clock.h
index f6b4b0f..476135d 100644
--- a/include/dt-bindings/clock/r8a7740-clock.h
+++ b/include/dt-bindings/clock/r8a7740-clock.h
@@ -40,6 +40,7 @@
/* MSTP2 */
#define R8A7740_CLK_SCIFA6 30
+#define R8A7740_CLK_INTCA 29
#define R8A7740_CLK_SCIFA7 22
#define R8A7740_CLK_DMAC1 18
#define R8A7740_CLK_DMAC2 17
diff --git a/include/dt-bindings/clock/r8a7790-clock.h b/include/dt-bindings/clock/r8a7790-clock.h
index 8ea7ab0..c27b3b5 100644
--- a/include/dt-bindings/clock/r8a7790-clock.h
+++ b/include/dt-bindings/clock/r8a7790-clock.h
@@ -26,8 +26,18 @@
#define R8A7790_CLK_MSIOF0 0
/* MSTP1 */
-#define R8A7790_CLK_JPU 6
+#define R8A7790_CLK_VCP1 0
+#define R8A7790_CLK_VCP0 1
+#define R8A7790_CLK_VPC1 2
+#define R8A7790_CLK_VPC0 3
+#define R8A7790_CLK_JPU 6
+#define R8A7790_CLK_SSP1 9
#define R8A7790_CLK_TMU1 11
+#define R8A7790_CLK_3DG 12
+#define R8A7790_CLK_2DDMAC 15
+#define R8A7790_CLK_FDP1_2 17
+#define R8A7790_CLK_FDP1_1 18
+#define R8A7790_CLK_FDP1_0 19
#define R8A7790_CLK_TMU3 21
#define R8A7790_CLK_TMU2 22
#define R8A7790_CLK_CMT0 24
@@ -68,6 +78,8 @@
#define R8A7790_CLK_USBDMAC1 31
/* MSTP5 */
+#define R8A7790_CLK_AUDIO_DMAC1 1
+#define R8A7790_CLK_AUDIO_DMAC0 2
#define R8A7790_CLK_THERMAL 22
#define R8A7790_CLK_PWM 23
diff --git a/include/dt-bindings/clock/r8a7791-clock.h b/include/dt-bindings/clock/r8a7791-clock.h
index 58c3f49..3ea2bbc 100644
--- a/include/dt-bindings/clock/r8a7791-clock.h
+++ b/include/dt-bindings/clock/r8a7791-clock.h
@@ -25,8 +25,15 @@
#define R8A7791_CLK_MSIOF0 0
/* MSTP1 */
-#define R8A7791_CLK_JPU 6
+#define R8A7791_CLK_VCP0 1
+#define R8A7791_CLK_VPC0 3
+#define R8A7791_CLK_JPU 6
+#define R8A7791_CLK_SSP1 9
#define R8A7791_CLK_TMU1 11
+#define R8A7791_CLK_3DG 12
+#define R8A7791_CLK_2DDMAC 15
+#define R8A7791_CLK_FDP1_1 18
+#define R8A7791_CLK_FDP1_0 19
#define R8A7791_CLK_TMU3 21
#define R8A7791_CLK_TMU2 22
#define R8A7791_CLK_CMT0 24
@@ -62,6 +69,8 @@
#define R8A7791_CLK_USBDMAC1 31
/* MSTP5 */
+#define R8A7791_CLK_AUDIO_DMAC1 1
+#define R8A7791_CLK_AUDIO_DMAC0 2
#define R8A7791_CLK_THERMAL 22
#define R8A7791_CLK_PWM 23
diff --git a/include/dt-bindings/clock/r8a7794-clock.h b/include/dt-bindings/clock/r8a7794-clock.h
index 9ac1043..aa9c286e 100644
--- a/include/dt-bindings/clock/r8a7794-clock.h
+++ b/include/dt-bindings/clock/r8a7794-clock.h
@@ -26,11 +26,18 @@
#define R8A7794_CLK_MSIOF0 0
/* MSTP1 */
+#define R8A7794_CLK_VCP0 1
+#define R8A7794_CLK_VPC0 3
#define R8A7794_CLK_TMU1 11
+#define R8A7794_CLK_3DG 12
+#define R8A7794_CLK_2DDMAC 15
+#define R8A7794_CLK_FDP1_0 19
#define R8A7794_CLK_TMU3 21
#define R8A7794_CLK_TMU2 22
#define R8A7794_CLK_CMT0 24
#define R8A7794_CLK_TMU0 25
+#define R8A7794_CLK_VSP1_DU0 28
+#define R8A7794_CLK_VSP1_S 31
/* MSTP2 */
#define R8A7794_CLK_SCIFA2 2
@@ -61,6 +68,8 @@
#define R8A7794_CLK_SCIF0 21
/* MSTP8 */
+#define R8A7794_CLK_VIN1 10
+#define R8A7794_CLK_VIN0 11
#define R8A7794_CLK_ETHER 13
/* MSTP9 */
diff --git a/include/dt-bindings/clock/stih407-clks.h b/include/dt-bindings/clock/stih407-clks.h
new file mode 100644
index 0000000..7af2b71
--- /dev/null
+++ b/include/dt-bindings/clock/stih407-clks.h
@@ -0,0 +1,86 @@
+/*
+ * This header provides constants clk index STMicroelectronics
+ * STiH407 SoC.
+ */
+#ifndef _DT_BINDINGS_CLK_STIH407
+#define _DT_BINDINGS_CLK_STIH407
+
+/* CLOCKGEN C0 */
+#define CLK_ICN_GPU 0
+#define CLK_FDMA 1
+#define CLK_NAND 2
+#define CLK_HVA 3
+#define CLK_PROC_STFE 4
+#define CLK_PROC_TP 5
+#define CLK_RX_ICN_DMU 6
+#define CLK_RX_ICN_DISP_0 6
+#define CLK_RX_ICN_DISP_1 6
+#define CLK_RX_ICN_HVA 7
+#define CLK_RX_ICN_TS 7
+#define CLK_ICN_CPU 8
+#define CLK_TX_ICN_DMU 9
+#define CLK_TX_ICN_HVA 9
+#define CLK_TX_ICN_TS 9
+#define CLK_ICN_COMPO 9
+#define CLK_MMC_0 10
+#define CLK_MMC_1 11
+#define CLK_JPEGDEC 12
+#define CLK_ICN_REG 13
+#define CLK_TRACE_A9 13
+#define CLK_PTI_STM 13
+#define CLK_EXT2F_A9 13
+#define CLK_IC_BDISP_0 14
+#define CLK_IC_BDISP_1 15
+#define CLK_PP_DMU 16
+#define CLK_VID_DMU 17
+#define CLK_DSS_LPC 18
+#define CLK_ST231_AUD_0 19
+#define CLK_ST231_GP_0 19
+#define CLK_ST231_GP_1 20
+#define CLK_ST231_DMU 21
+#define CLK_ICN_LMI 22
+#define CLK_TX_ICN_DISP_0 23
+#define CLK_TX_ICN_DISP_1 23
+#define CLK_ICN_SBC 24
+#define CLK_STFE_FRC2 25
+#define CLK_ETH_PHY 26
+#define CLK_ETH_REF_PHYCLK 27
+#define CLK_FLASH_PROMIP 28
+#define CLK_MAIN_DISP 29
+#define CLK_AUX_DISP 30
+#define CLK_COMPO_DVP 31
+
+/* CLOCKGEN D0 */
+#define CLK_PCM_0 0
+#define CLK_PCM_1 1
+#define CLK_PCM_2 2
+#define CLK_SPDIFF 3
+
+/* CLOCKGEN D2 */
+#define CLK_PIX_MAIN_DISP 0
+#define CLK_PIX_PIP 1
+#define CLK_PIX_GDP1 2
+#define CLK_PIX_GDP2 3
+#define CLK_PIX_GDP3 4
+#define CLK_PIX_GDP4 5
+#define CLK_PIX_AUX_DISP 6
+#define CLK_DENC 7
+#define CLK_PIX_HDDAC 8
+#define CLK_HDDAC 9
+#define CLK_SDDAC 10
+#define CLK_PIX_DVO 11
+#define CLK_DVO 12
+#define CLK_PIX_HDMI 13
+#define CLK_TMDS_HDMI 14
+#define CLK_REF_HDMIPHY 15
+
+/* CLOCKGEN D3 */
+#define CLK_STFE_FRC1 0
+#define CLK_TSOUT_0 1
+#define CLK_TSOUT_1 2
+#define CLK_MCHI 3
+#define CLK_VSENS_COMPO 4
+#define CLK_FRC1_REMOTE 5
+#define CLK_LPC_0 6
+#define CLK_LPC_1 7
+#endif
diff --git a/include/dt-bindings/clock/stih410-clks.h b/include/dt-bindings/clock/stih410-clks.h
new file mode 100644
index 0000000..2097a4b
--- /dev/null
+++ b/include/dt-bindings/clock/stih410-clks.h
@@ -0,0 +1,25 @@
+/*
+ * This header provides constants clk index STMicroelectronics
+ * STiH410 SoC.
+ */
+#ifndef _DT_BINDINGS_CLK_STIH410
+#define _DT_BINDINGS_CLK_STIH410
+
+#include "stih407-clks.h"
+
+/* STiH410 introduces new clock outputs compared to STiH407 */
+
+/* CLOCKGEN C0 */
+#define CLK_TX_ICN_HADES 32
+#define CLK_RX_ICN_HADES 33
+#define CLK_ICN_REG_16 34
+#define CLK_PP_HADES 35
+#define CLK_CLUST_HADES 36
+#define CLK_HWPE_HADES 37
+#define CLK_FC_HADES 38
+
+/* CLOCKGEN D0 */
+#define CLK_PCMR10_MASTER 4
+#define CLK_USB2_PHY 5
+
+#endif
diff --git a/include/dt-bindings/clock/tegra114-car.h b/include/dt-bindings/clock/tegra114-car.h
index fc12621..534c03f 100644
--- a/include/dt-bindings/clock/tegra114-car.h
+++ b/include/dt-bindings/clock/tegra114-car.h
@@ -49,7 +49,7 @@
#define TEGRA114_CLK_I2S0 30
/* 31 */
-/* 32 */
+#define TEGRA114_CLK_MC 32
/* 33 */
#define TEGRA114_CLK_APBDMA 34
/* 35 */
diff --git a/include/dt-bindings/clock/tegra124-car.h b/include/dt-bindings/clock/tegra124-car.h
index 6bac637..af9bc9a 100644
--- a/include/dt-bindings/clock/tegra124-car.h
+++ b/include/dt-bindings/clock/tegra124-car.h
@@ -48,7 +48,7 @@
#define TEGRA124_CLK_I2S0 30
/* 31 */
-/* 32 */
+#define TEGRA124_CLK_MC 32
/* 33 */
#define TEGRA124_CLK_APBDMA 34
/* 35 */
diff --git a/include/dt-bindings/clock/tegra20-car.h b/include/dt-bindings/clock/tegra20-car.h
index 9406207..04500b2 100644
--- a/include/dt-bindings/clock/tegra20-car.h
+++ b/include/dt-bindings/clock/tegra20-car.h
@@ -49,7 +49,7 @@
/* 30 */
#define TEGRA20_CLK_CACHE2 31
-#define TEGRA20_CLK_MEM 32
+#define TEGRA20_CLK_MC 32
#define TEGRA20_CLK_AHBDMA 33
#define TEGRA20_CLK_APBDMA 34
/* 35 */
diff --git a/include/dt-bindings/memory/tegra114-mc.h b/include/dt-bindings/memory/tegra114-mc.h
new file mode 100644
index 0000000..8f48985
--- /dev/null
+++ b/include/dt-bindings/memory/tegra114-mc.h
@@ -0,0 +1,25 @@
+#ifndef DT_BINDINGS_MEMORY_TEGRA114_MC_H
+#define DT_BINDINGS_MEMORY_TEGRA114_MC_H
+
+#define TEGRA_SWGROUP_PTC 0
+#define TEGRA_SWGROUP_DC 1
+#define TEGRA_SWGROUP_DCB 2
+#define TEGRA_SWGROUP_EPP 3
+#define TEGRA_SWGROUP_G2 4
+#define TEGRA_SWGROUP_AVPC 5
+#define TEGRA_SWGROUP_NV 6
+#define TEGRA_SWGROUP_HDA 7
+#define TEGRA_SWGROUP_HC 8
+#define TEGRA_SWGROUP_MSENC 9
+#define TEGRA_SWGROUP_PPCS 10
+#define TEGRA_SWGROUP_VDE 11
+#define TEGRA_SWGROUP_MPCORELP 12
+#define TEGRA_SWGROUP_MPCORE 13
+#define TEGRA_SWGROUP_VI 14
+#define TEGRA_SWGROUP_ISP 15
+#define TEGRA_SWGROUP_XUSB_HOST 16
+#define TEGRA_SWGROUP_XUSB_DEV 17
+#define TEGRA_SWGROUP_EMUCIF 18
+#define TEGRA_SWGROUP_TSEC 19
+
+#endif
diff --git a/include/dt-bindings/memory/tegra124-mc.h b/include/dt-bindings/memory/tegra124-mc.h
new file mode 100644
index 0000000..7d8ee79
--- /dev/null
+++ b/include/dt-bindings/memory/tegra124-mc.h
@@ -0,0 +1,31 @@
+#ifndef DT_BINDINGS_MEMORY_TEGRA124_MC_H
+#define DT_BINDINGS_MEMORY_TEGRA124_MC_H
+
+#define TEGRA_SWGROUP_PTC 0
+#define TEGRA_SWGROUP_DC 1
+#define TEGRA_SWGROUP_DCB 2
+#define TEGRA_SWGROUP_AFI 3
+#define TEGRA_SWGROUP_AVPC 4
+#define TEGRA_SWGROUP_HDA 5
+#define TEGRA_SWGROUP_HC 6
+#define TEGRA_SWGROUP_MSENC 7
+#define TEGRA_SWGROUP_PPCS 8
+#define TEGRA_SWGROUP_SATA 9
+#define TEGRA_SWGROUP_VDE 10
+#define TEGRA_SWGROUP_MPCORELP 11
+#define TEGRA_SWGROUP_MPCORE 12
+#define TEGRA_SWGROUP_ISP2 13
+#define TEGRA_SWGROUP_XUSB_HOST 14
+#define TEGRA_SWGROUP_XUSB_DEV 15
+#define TEGRA_SWGROUP_ISP2B 16
+#define TEGRA_SWGROUP_TSEC 17
+#define TEGRA_SWGROUP_A9AVP 18
+#define TEGRA_SWGROUP_GPU 19
+#define TEGRA_SWGROUP_SDMMC1A 20
+#define TEGRA_SWGROUP_SDMMC2A 21
+#define TEGRA_SWGROUP_SDMMC3A 22
+#define TEGRA_SWGROUP_SDMMC4A 23
+#define TEGRA_SWGROUP_VIC 24
+#define TEGRA_SWGROUP_VI 25
+
+#endif
diff --git a/include/dt-bindings/memory/tegra30-mc.h b/include/dt-bindings/memory/tegra30-mc.h
new file mode 100644
index 0000000..502beb0
--- /dev/null
+++ b/include/dt-bindings/memory/tegra30-mc.h
@@ -0,0 +1,24 @@
+#ifndef DT_BINDINGS_MEMORY_TEGRA30_MC_H
+#define DT_BINDINGS_MEMORY_TEGRA30_MC_H
+
+#define TEGRA_SWGROUP_PTC 0
+#define TEGRA_SWGROUP_DC 1
+#define TEGRA_SWGROUP_DCB 2
+#define TEGRA_SWGROUP_EPP 3
+#define TEGRA_SWGROUP_G2 4
+#define TEGRA_SWGROUP_MPE 5
+#define TEGRA_SWGROUP_VI 6
+#define TEGRA_SWGROUP_AFI 7
+#define TEGRA_SWGROUP_AVPC 8
+#define TEGRA_SWGROUP_NV 9
+#define TEGRA_SWGROUP_NV2 10
+#define TEGRA_SWGROUP_HDA 11
+#define TEGRA_SWGROUP_HC 12
+#define TEGRA_SWGROUP_PPCS 13
+#define TEGRA_SWGROUP_SATA 14
+#define TEGRA_SWGROUP_VDE 15
+#define TEGRA_SWGROUP_MPCORELP 16
+#define TEGRA_SWGROUP_MPCORE 17
+#define TEGRA_SWGROUP_ISP 18
+
+#endif
diff --git a/include/dt-bindings/pinctrl/qcom,pmic-gpio.h b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h
new file mode 100644
index 0000000..fa74d7c
--- /dev/null
+++ b/include/dt-bindings/pinctrl/qcom,pmic-gpio.h
@@ -0,0 +1,142 @@
+/*
+ * This header provides constants for the Qualcomm PMIC GPIO binding.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_QCOM_PMIC_GPIO_H
+#define _DT_BINDINGS_PINCTRL_QCOM_PMIC_GPIO_H
+
+#define PMIC_GPIO_PULL_UP_30 0
+#define PMIC_GPIO_PULL_UP_1P5 1
+#define PMIC_GPIO_PULL_UP_31P5 2
+#define PMIC_GPIO_PULL_UP_1P5_30 3
+
+#define PMIC_GPIO_STRENGTH_NO 0
+#define PMIC_GPIO_STRENGTH_HIGH 1
+#define PMIC_GPIO_STRENGTH_MED 2
+#define PMIC_GPIO_STRENGTH_LOW 3
+
+/*
+ * Note: PM8018 GPIO3 and GPIO4 are supporting
+ * only S3 and L2 options (1.8V)
+ */
+#define PM8018_GPIO_L6 0
+#define PM8018_GPIO_L5 1
+#define PM8018_GPIO_S3 2
+#define PM8018_GPIO_L14 3
+#define PM8018_GPIO_L2 4
+#define PM8018_GPIO_L4 5
+#define PM8018_GPIO_VDD 6
+
+/*
+ * Note: PM8038 GPIO7 and GPIO8 are supporting
+ * only L11 and L4 options (1.8V)
+ */
+#define PM8038_GPIO_VPH 0
+#define PM8038_GPIO_BB 1
+#define PM8038_GPIO_L11 2
+#define PM8038_GPIO_L15 3
+#define PM8038_GPIO_L4 4
+#define PM8038_GPIO_L3 5
+#define PM8038_GPIO_L17 6
+
+#define PM8058_GPIO_VPH 0
+#define PM8058_GPIO_BB 1
+#define PM8058_GPIO_S3 2
+#define PM8058_GPIO_L3 3
+#define PM8058_GPIO_L7 4
+#define PM8058_GPIO_L6 5
+#define PM8058_GPIO_L5 6
+#define PM8058_GPIO_L2 7
+
+#define PM8917_GPIO_VPH 0
+#define PM8917_GPIO_S4 2
+#define PM8917_GPIO_L15 3
+#define PM8917_GPIO_L4 4
+#define PM8917_GPIO_L3 5
+#define PM8917_GPIO_L17 6
+
+#define PM8921_GPIO_VPH 0
+#define PM8921_GPIO_BB 1
+#define PM8921_GPIO_S4 2
+#define PM8921_GPIO_L15 3
+#define PM8921_GPIO_L4 4
+#define PM8921_GPIO_L3 5
+#define PM8921_GPIO_L17 6
+
+/*
+ * Note: PM8941 gpios from 15 to 18 are supporting
+ * only S3 and L6 options (1.8V)
+ */
+#define PM8941_GPIO_VPH 0
+#define PM8941_GPIO_L1 1
+#define PM8941_GPIO_S3 2
+#define PM8941_GPIO_L6 3
+
+/*
+ * Note: PMA8084 gpios from 15 to 18 are supporting
+ * only S4 and L6 options (1.8V)
+ */
+#define PMA8084_GPIO_VPH 0
+#define PMA8084_GPIO_L1 1
+#define PMA8084_GPIO_S4 2
+#define PMA8084_GPIO_L6 3
+
+/* To be used with "function" */
+#define PMIC_GPIO_FUNC_NORMAL "normal"
+#define PMIC_GPIO_FUNC_PAIRED "paired"
+#define PMIC_GPIO_FUNC_FUNC1 "func1"
+#define PMIC_GPIO_FUNC_FUNC2 "func2"
+#define PMIC_GPIO_FUNC_DTEST1 "dtest1"
+#define PMIC_GPIO_FUNC_DTEST2 "dtest2"
+#define PMIC_GPIO_FUNC_DTEST3 "dtest3"
+#define PMIC_GPIO_FUNC_DTEST4 "dtest4"
+
+#define PM8038_GPIO1_2_LPG_DRV PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO3_5V_BOOST_EN PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO4_SSBI_ALT_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO5_6_EXT_REG_EN PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO10_11_EXT_REG_EN PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO6_7_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO9_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1
+#define PM8038_GPIO6_12_KYPD_DRV PMIC_GPIO_FUNC_FUNC2
+
+#define PM8058_GPIO7_8_MP3_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO7_8_BCLK_19P2MHZ PMIC_GPIO_FUNC_FUNC2
+#define PM8058_GPIO9_26_KYPD_DRV PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO21_23_UART_TX PMIC_GPIO_FUNC_FUNC2
+#define PM8058_GPIO24_26_LPG_DRV PMIC_GPIO_FUNC_FUNC2
+#define PM8058_GPIO33_BCLK_19P2MHZ PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO34_35_MP3_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO36_BCLK_19P2MHZ PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO37_UPL_OUT PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO37_UART_M_RX PMIC_GPIO_FUNC_FUNC2
+#define PM8058_GPIO38_XO_SLEEP_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO38_39_CLK_32KHZ PMIC_GPIO_FUNC_FUNC2
+#define PM8058_GPIO39_MP3_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8058_GPIO40_EXT_BB_EN PMIC_GPIO_FUNC_FUNC1
+
+#define PM8917_GPIO9_18_KEYP_DRV PMIC_GPIO_FUNC_FUNC1
+#define PM8917_GPIO20_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1
+#define PM8917_GPIO21_23_UART_TX PMIC_GPIO_FUNC_FUNC2
+#define PM8917_GPIO25_26_EXT_REG_EN PMIC_GPIO_FUNC_FUNC1
+#define PM8917_GPIO37_38_XO_SLEEP_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8917_GPIO37_38_MP3_CLK PMIC_GPIO_FUNC_FUNC2
+
+#define PM8941_GPIO9_14_KYPD_DRV PMIC_GPIO_FUNC_FUNC1
+#define PM8941_GPIO15_18_DIV_CLK PMIC_GPIO_FUNC_FUNC1
+#define PM8941_GPIO15_18_SLEEP_CLK PMIC_GPIO_FUNC_FUNC2
+#define PM8941_GPIO23_26_KYPD_DRV PMIC_GPIO_FUNC_FUNC1
+#define PM8941_GPIO23_26_LPG_DRV_HI PMIC_GPIO_FUNC_FUNC2
+#define PM8941_GPIO31_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1
+#define PM8941_GPIO33_36_LPG_DRV_3D PMIC_GPIO_FUNC_FUNC1
+#define PM8941_GPIO33_36_LPG_DRV_HI PMIC_GPIO_FUNC_FUNC2
+
+#define PMA8084_GPIO4_5_LPG_DRV PMIC_GPIO_FUNC_FUNC1
+#define PMA8084_GPIO7_10_LPG_DRV PMIC_GPIO_FUNC_FUNC1
+#define PMA8084_GPIO5_14_KEYP_DRV PMIC_GPIO_FUNC_FUNC2
+#define PMA8084_GPIO19_21_KEYP_DRV PMIC_GPIO_FUNC_FUNC2
+#define PMA8084_GPIO15_18_DIV_CLK PMIC_GPIO_FUNC_FUNC1
+#define PMA8084_GPIO15_18_SLEEP_CLK PMIC_GPIO_FUNC_FUNC2
+#define PMA8084_GPIO22_BAT_ALRM_OUT PMIC_GPIO_FUNC_FUNC1
+
+#endif
diff --git a/include/dt-bindings/pinctrl/qcom,pmic-mpp.h b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h
new file mode 100644
index 0000000..d2c7dab
--- /dev/null
+++ b/include/dt-bindings/pinctrl/qcom,pmic-mpp.h
@@ -0,0 +1,44 @@
+/*
+ * This header provides constants for the Qualcomm PMIC's
+ * Multi-Purpose Pin binding.
+ */
+
+#ifndef _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H
+#define _DT_BINDINGS_PINCTRL_QCOM_PMIC_MPP_H
+
+/* power-source */
+#define PM8841_MPP_VPH 0
+#define PM8841_MPP_S3 2
+
+#define PM8941_MPP_VPH 0
+#define PM8941_MPP_L1 1
+#define PM8941_MPP_S3 2
+#define PM8941_MPP_L6 3
+
+#define PMA8084_MPP_VPH 0
+#define PMA8084_MPP_L1 1
+#define PMA8084_MPP_S4 2
+#define PMA8084_MPP_L6 3
+
+/*
+ * Analog Input - Set the source for analog input.
+ * To be used with "qcom,amux-route" property
+ */
+#define PMIC_MPP_AMUX_ROUTE_CH5 0
+#define PMIC_MPP_AMUX_ROUTE_CH6 1
+#define PMIC_MPP_AMUX_ROUTE_CH7 2
+#define PMIC_MPP_AMUX_ROUTE_CH8 3
+#define PMIC_MPP_AMUX_ROUTE_ABUS1 4
+#define PMIC_MPP_AMUX_ROUTE_ABUS2 5
+#define PMIC_MPP_AMUX_ROUTE_ABUS3 6
+#define PMIC_MPP_AMUX_ROUTE_ABUS4 7
+
+/* To be used with "function" */
+#define PMIC_MPP_FUNC_NORMAL "normal"
+#define PMIC_MPP_FUNC_PAIRED "paired"
+#define PMIC_MPP_FUNC_DTEST1 "dtest1"
+#define PMIC_MPP_FUNC_DTEST2 "dtest2"
+#define PMIC_MPP_FUNC_DTEST3 "dtest3"
+#define PMIC_MPP_FUNC_DTEST4 "dtest4"
+
+#endif
diff --git a/include/dt-bindings/regulator/maxim,max77802.h b/include/dt-bindings/regulator/maxim,max77802.h
new file mode 100644
index 0000000..cf28631
--- /dev/null
+++ b/include/dt-bindings/regulator/maxim,max77802.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright (C) 2014 Google, 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.
+ *
+ * Device Tree binding constants for the Maxim 77802 PMIC regulators
+ */
+
+#ifndef _DT_BINDINGS_REGULATOR_MAXIM_MAX77802_H
+#define _DT_BINDINGS_REGULATOR_MAXIM_MAX77802_H
+
+/* Regulator operating modes */
+#define MAX77802_OPMODE_LP 1
+#define MAX77802_OPMODE_NORMAL 3
+
+#endif /* _DT_BINDINGS_REGULATOR_MAXIM_MAX77802_H */
diff --git a/include/dt-bindings/reset-controller/stih407-resets.h b/include/dt-bindings/reset-controller/stih407-resets.h
new file mode 100644
index 0000000..02d4328
--- /dev/null
+++ b/include/dt-bindings/reset-controller/stih407-resets.h
@@ -0,0 +1,61 @@
+/*
+ * This header provides constants for the reset controller
+ * based peripheral powerdown requests on the STMicroelectronics
+ * STiH407 SoC.
+ */
+#ifndef _DT_BINDINGS_RESET_CONTROLLER_STIH407
+#define _DT_BINDINGS_RESET_CONTROLLER_STIH407
+
+/* Powerdown requests control 0 */
+#define STIH407_EMISS_POWERDOWN 0
+#define STIH407_NAND_POWERDOWN 1
+
+/* Synp GMAC PowerDown */
+#define STIH407_ETH1_POWERDOWN 2
+
+/* Powerdown requests control 1 */
+#define STIH407_USB3_POWERDOWN 3
+#define STIH407_USB2_PORT1_POWERDOWN 4
+#define STIH407_USB2_PORT0_POWERDOWN 5
+#define STIH407_PCIE1_POWERDOWN 6
+#define STIH407_PCIE0_POWERDOWN 7
+#define STIH407_SATA1_POWERDOWN 8
+#define STIH407_SATA0_POWERDOWN 9
+
+/* Reset defines */
+#define STIH407_ETH1_SOFTRESET 0
+#define STIH407_MMC1_SOFTRESET 1
+#define STIH407_PICOPHY_SOFTRESET 2
+#define STIH407_IRB_SOFTRESET 3
+#define STIH407_PCIE0_SOFTRESET 4
+#define STIH407_PCIE1_SOFTRESET 5
+#define STIH407_SATA0_SOFTRESET 6
+#define STIH407_SATA1_SOFTRESET 7
+#define STIH407_MIPHY0_SOFTRESET 8
+#define STIH407_MIPHY1_SOFTRESET 9
+#define STIH407_MIPHY2_SOFTRESET 10
+#define STIH407_SATA0_PWR_SOFTRESET 11
+#define STIH407_SATA1_PWR_SOFTRESET 12
+#define STIH407_DELTA_SOFTRESET 13
+#define STIH407_BLITTER_SOFTRESET 14
+#define STIH407_HDTVOUT_SOFTRESET 15
+#define STIH407_HDQVDP_SOFTRESET 16
+#define STIH407_VDP_AUX_SOFTRESET 17
+#define STIH407_COMPO_SOFTRESET 18
+#define STIH407_HDMI_TX_PHY_SOFTRESET 19
+#define STIH407_JPEG_DEC_SOFTRESET 20
+#define STIH407_VP8_DEC_SOFTRESET 21
+#define STIH407_GPU_SOFTRESET 22
+#define STIH407_HVA_SOFTRESET 23
+#define STIH407_ERAM_HVA_SOFTRESET 24
+#define STIH407_LPM_SOFTRESET 25
+#define STIH407_KEYSCAN_SOFTRESET 26
+#define STIH407_USB2_PORT0_SOFTRESET 27
+#define STIH407_USB2_PORT1_SOFTRESET 28
+
+/* Picophy reset defines */
+#define STIH407_PICOPHY0_RESET 0
+#define STIH407_PICOPHY1_RESET 1
+#define STIH407_PICOPHY2_RESET 2
+
+#endif /* _DT_BINDINGS_RESET_CONTROLLER_STIH407 */
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index 407a12f..6bff83b 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -28,6 +28,7 @@
#include <linux/errno.h>
#include <linux/ioport.h> /* for struct resource */
#include <linux/device.h>
+#include <linux/property.h>
#ifndef _LINUX
#define _LINUX
@@ -123,6 +124,10 @@ int acpi_numa_init (void);
int acpi_table_init (void);
int acpi_table_parse(char *id, acpi_tbl_table_handler handler);
+int __init acpi_parse_entries(char *id, unsigned long table_size,
+ acpi_tbl_entry_handler handler,
+ struct acpi_table_header *table_header,
+ int entry_id, unsigned int max_entries);
int __init acpi_table_parse_entries(char *id, unsigned long table_size,
int entry_id,
acpi_tbl_entry_handler handler,
@@ -423,14 +428,11 @@ extern int acpi_nvs_for_each_region(int (*func)(__u64, __u64, void *),
const struct acpi_device_id *acpi_match_device(const struct acpi_device_id *ids,
const struct device *dev);
-static inline bool acpi_driver_match_device(struct device *dev,
- const struct device_driver *drv)
-{
- return !!acpi_match_device(drv->acpi_match_table, dev);
-}
-
+extern bool acpi_driver_match_device(struct device *dev,
+ const struct device_driver *drv);
int acpi_device_uevent_modalias(struct device *, struct kobj_uevent_env *);
int acpi_device_modalias(struct device *, char *, int);
+void acpi_walk_dep_device_list(acpi_handle handle);
struct platform_device *acpi_create_platform_device(struct acpi_device *);
#define ACPI_PTR(_ptr) (_ptr)
@@ -443,6 +445,23 @@ struct platform_device *acpi_create_platform_device(struct acpi_device *);
#define ACPI_COMPANION_SET(dev, adev) do { } while (0)
#define ACPI_HANDLE(dev) (NULL)
+struct fwnode_handle;
+
+static inline bool is_acpi_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct acpi_device *acpi_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
+static inline struct fwnode_handle *acpi_fwnode_handle(struct acpi_device *adev)
+{
+ return NULL;
+}
+
static inline const char *acpi_dev_name(struct acpi_device *adev)
{
return NULL;
@@ -553,16 +572,26 @@ static inline void arch_reserve_mem_area(acpi_physical_address addr,
#define acpi_os_set_prepare_sleep(func, pm1a_ctrl, pm1b_ctrl) do { } while (0)
#endif
-#if defined(CONFIG_ACPI) && defined(CONFIG_PM_RUNTIME)
+#if defined(CONFIG_ACPI) && defined(CONFIG_PM)
int acpi_dev_runtime_suspend(struct device *dev);
int acpi_dev_runtime_resume(struct device *dev);
int acpi_subsys_runtime_suspend(struct device *dev);
int acpi_subsys_runtime_resume(struct device *dev);
+struct acpi_device *acpi_dev_pm_get_node(struct device *dev);
+int acpi_dev_pm_attach(struct device *dev, bool power_on);
#else
static inline int acpi_dev_runtime_suspend(struct device *dev) { return 0; }
static inline int acpi_dev_runtime_resume(struct device *dev) { return 0; }
static inline int acpi_subsys_runtime_suspend(struct device *dev) { return 0; }
static inline int acpi_subsys_runtime_resume(struct device *dev) { return 0; }
+static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
+{
+ return NULL;
+}
+static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
+{
+ return -ENODEV;
+}
#endif
#if defined(CONFIG_ACPI) && defined(CONFIG_PM_SLEEP)
@@ -585,20 +614,6 @@ static inline int acpi_subsys_suspend(struct device *dev) { return 0; }
static inline int acpi_subsys_freeze(struct device *dev) { return 0; }
#endif
-#if defined(CONFIG_ACPI) && defined(CONFIG_PM)
-struct acpi_device *acpi_dev_pm_get_node(struct device *dev);
-int acpi_dev_pm_attach(struct device *dev, bool power_on);
-#else
-static inline struct acpi_device *acpi_dev_pm_get_node(struct device *dev)
-{
- return NULL;
-}
-static inline int acpi_dev_pm_attach(struct device *dev, bool power_on)
-{
- return -ENODEV;
-}
-#endif
-
#ifdef CONFIG_ACPI
__printf(3, 4)
void acpi_handle_printk(const char *level, acpi_handle handle,
@@ -659,4 +674,114 @@ do { \
#endif
#endif
+struct acpi_gpio_params {
+ unsigned int crs_entry_index;
+ unsigned int line_index;
+ bool active_low;
+};
+
+struct acpi_gpio_mapping {
+ const char *name;
+ const struct acpi_gpio_params *data;
+ unsigned int size;
+};
+
+#if defined(CONFIG_ACPI) && defined(CONFIG_GPIOLIB)
+int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios);
+
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev)
+{
+ if (adev)
+ adev->driver_gpios = NULL;
+}
+#else
+static inline int acpi_dev_add_driver_gpios(struct acpi_device *adev,
+ const struct acpi_gpio_mapping *gpios)
+{
+ return -ENXIO;
+}
+static inline void acpi_dev_remove_driver_gpios(struct acpi_device *adev) {}
+#endif
+
+/* Device properties */
+
+#define MAX_ACPI_REFERENCE_ARGS 8
+struct acpi_reference_args {
+ struct acpi_device *adev;
+ size_t nargs;
+ u64 args[MAX_ACPI_REFERENCE_ARGS];
+};
+
+#ifdef CONFIG_ACPI
+int acpi_dev_get_property(struct acpi_device *adev, const char *name,
+ acpi_object_type type, const union acpi_object **obj);
+int acpi_dev_get_property_array(struct acpi_device *adev, const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj);
+int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, size_t index,
+ struct acpi_reference_args *args);
+
+int acpi_dev_prop_get(struct acpi_device *adev, const char *propname,
+ void **valptr);
+int acpi_dev_prop_read_single(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val);
+int acpi_dev_prop_read(struct acpi_device *adev, const char *propname,
+ enum dev_prop_type proptype, void *val, size_t nval);
+
+struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child);
+#else
+static inline int acpi_dev_get_property(struct acpi_device *adev,
+ const char *name, acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_array(struct acpi_device *adev,
+ const char *name,
+ acpi_object_type type,
+ const union acpi_object **obj)
+{
+ return -ENXIO;
+}
+static inline int acpi_dev_get_property_reference(struct acpi_device *adev,
+ const char *name, const char *cells_name,
+ size_t index, struct acpi_reference_args *args)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_get(struct acpi_device *adev,
+ const char *propname,
+ void **valptr)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read_single(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val)
+{
+ return -ENXIO;
+}
+
+static inline int acpi_dev_prop_read(struct acpi_device *adev,
+ const char *propname,
+ enum dev_prop_type proptype,
+ void *val, size_t nval)
+{
+ return -ENXIO;
+}
+
+static inline struct acpi_device *acpi_get_next_child(struct device *dev,
+ struct acpi_device *child)
+{
+ return NULL;
+}
+
+#endif
+
#endif /*_LINUX_ACPI_H*/
diff --git a/include/linux/atmel-mci.h b/include/linux/atmel-mci.h
index 91b77f8..9177947 100644
--- a/include/linux/atmel-mci.h
+++ b/include/linux/atmel-mci.h
@@ -11,6 +11,7 @@
* @detect_pin: GPIO pin wired to the card detect switch
* @wp_pin: GPIO pin wired to the write protect sensor
* @detect_is_active_high: The state of the detect pin when it is active
+ * @non_removable: The slot is not removable, only detect once
*
* If a given slot is not present on the board, @bus_width should be
* set to 0. The other fields are ignored in this case.
@@ -26,6 +27,7 @@ struct mci_slot_pdata {
int detect_pin;
int wp_pin;
bool detect_is_active_high;
+ bool non_removable;
};
/**
diff --git a/include/linux/audit.h b/include/linux/audit.h
index e58fe7d..0c04917 100644
--- a/include/linux/audit.h
+++ b/include/linux/audit.h
@@ -130,6 +130,7 @@ extern void audit_putname(struct filename *name);
#define AUDIT_INODE_HIDDEN 2 /* audit record should be hidden */
extern void __audit_inode(struct filename *name, const struct dentry *dentry,
unsigned int flags);
+extern void __audit_file(const struct file *);
extern void __audit_inode_child(const struct inode *parent,
const struct dentry *dentry,
const unsigned char type);
@@ -183,6 +184,11 @@ static inline void audit_inode(struct filename *name,
__audit_inode(name, dentry, flags);
}
}
+static inline void audit_file(struct file *file)
+{
+ if (unlikely(!audit_dummy_context()))
+ __audit_file(file);
+}
static inline void audit_inode_parent_hidden(struct filename *name,
const struct dentry *dentry)
{
@@ -357,6 +363,9 @@ static inline void audit_inode(struct filename *name,
const struct dentry *dentry,
unsigned int parent)
{ }
+static inline void audit_file(struct file *file)
+{
+}
static inline void audit_inode_parent_hidden(struct filename *name,
const struct dentry *dentry)
{ }
diff --git a/include/linux/blk-mq.h b/include/linux/blk-mq.h
index c9be158..15f7034a 100644
--- a/include/linux/blk-mq.h
+++ b/include/linux/blk-mq.h
@@ -167,6 +167,23 @@ struct request *blk_mq_alloc_request(struct request_queue *q, int rw,
gfp_t gfp, bool reserved);
struct request *blk_mq_tag_to_rq(struct blk_mq_tags *tags, unsigned int tag);
+enum {
+ BLK_MQ_UNIQUE_TAG_BITS = 16,
+ BLK_MQ_UNIQUE_TAG_MASK = (1 << BLK_MQ_UNIQUE_TAG_BITS) - 1,
+};
+
+u32 blk_mq_unique_tag(struct request *rq);
+
+static inline u16 blk_mq_unique_tag_to_hwq(u32 unique_tag)
+{
+ return unique_tag >> BLK_MQ_UNIQUE_TAG_BITS;
+}
+
+static inline u16 blk_mq_unique_tag_to_tag(u32 unique_tag)
+{
+ return unique_tag & BLK_MQ_UNIQUE_TAG_MASK;
+}
+
struct blk_mq_hw_ctx *blk_mq_map_queue(struct request_queue *, const int ctx_index);
struct blk_mq_hw_ctx *blk_mq_alloc_single_hw_queue(struct blk_mq_tag_set *, unsigned int, int);
diff --git a/include/linux/blkdev.h b/include/linux/blkdev.h
index aac0f9e..0495e38 100644
--- a/include/linux/blkdev.h
+++ b/include/linux/blkdev.h
@@ -398,7 +398,7 @@ struct request_queue {
*/
struct kobject mq_kobj;
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
struct device *dev;
int rpm_status;
unsigned int nr_pending;
@@ -1057,7 +1057,7 @@ extern void blk_put_queue(struct request_queue *);
/*
* block layer runtime pm functions
*/
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
extern void blk_pm_runtime_init(struct request_queue *q, struct device *dev);
extern int blk_pre_runtime_suspend(struct request_queue *q);
extern void blk_post_runtime_suspend(struct request_queue *q, int err);
@@ -1136,7 +1136,6 @@ static inline bool blk_needs_flush_plug(struct task_struct *tsk)
/*
* tag stuff
*/
-#define blk_rq_tagged(rq) ((rq)->cmd_flags & REQ_QUEUED)
extern int blk_queue_start_tag(struct request_queue *, struct request *);
extern struct request *blk_queue_find_tag(struct request_queue *, int);
extern void blk_queue_end_tag(struct request_queue *, struct request *);
diff --git a/include/linux/cgroup.h b/include/linux/cgroup.h
index 1d51968..641e564 100644
--- a/include/linux/cgroup.h
+++ b/include/linux/cgroup.h
@@ -113,6 +113,19 @@ static inline void css_get(struct cgroup_subsys_state *css)
}
/**
+ * css_get_many - obtain references on the specified css
+ * @css: target css
+ * @n: number of references to get
+ *
+ * The caller must already have a reference.
+ */
+static inline void css_get_many(struct cgroup_subsys_state *css, unsigned int n)
+{
+ if (!(css->flags & CSS_NO_REF))
+ percpu_ref_get_many(&css->refcnt, n);
+}
+
+/**
* css_tryget - try to obtain a reference on the specified css
* @css: target css
*
@@ -159,6 +172,19 @@ static inline void css_put(struct cgroup_subsys_state *css)
percpu_ref_put(&css->refcnt);
}
+/**
+ * css_put_many - put css references
+ * @css: target css
+ * @n: number of references to put
+ *
+ * Put references obtained via css_get() and css_tryget_online().
+ */
+static inline void css_put_many(struct cgroup_subsys_state *css, unsigned int n)
+{
+ if (!(css->flags & CSS_NO_REF))
+ percpu_ref_put_many(&css->refcnt, n);
+}
+
/* bits in struct cgroup flags field */
enum {
/* Control Group requires release notifications to userspace */
@@ -367,8 +393,8 @@ struct css_set {
* struct cftype: handler definitions for cgroup control files
*
* When reading/writing to a file:
- * - the cgroup to use is file->f_dentry->d_parent->d_fsdata
- * - the 'cftype' of the file is file->f_dentry->d_fsdata
+ * - the cgroup to use is file->f_path.dentry->d_parent->d_fsdata
+ * - the 'cftype' of the file is file->f_path.dentry->d_fsdata
*/
/* cftype->flags */
diff --git a/include/linux/clk/ti.h b/include/linux/clk/ti.h
index f75acbf..74e5341 100644
--- a/include/linux/clk/ti.h
+++ b/include/linux/clk/ti.h
@@ -254,13 +254,26 @@ extern const struct clk_ops ti_clk_mux_ops;
void omap2_init_clk_hw_omap_clocks(struct clk *clk);
int omap3_noncore_dpll_enable(struct clk_hw *hw);
void omap3_noncore_dpll_disable(struct clk_hw *hw);
+int omap3_noncore_dpll_set_parent(struct clk_hw *hw, u8 index);
int omap3_noncore_dpll_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate);
+int omap3_noncore_dpll_set_rate_and_parent(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long parent_rate,
+ u8 index);
+long omap3_noncore_dpll_determine_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk);
unsigned long omap4_dpll_regm4xen_recalc(struct clk_hw *hw,
unsigned long parent_rate);
long omap4_dpll_regm4xen_round_rate(struct clk_hw *hw,
unsigned long target_rate,
unsigned long *parent_rate);
+long omap4_dpll_regm4xen_determine_rate(struct clk_hw *hw,
+ unsigned long rate,
+ unsigned long *best_parent_rate,
+ struct clk **best_parent_clk);
u8 omap2_init_dpll_parent(struct clk_hw *hw);
unsigned long omap3_dpll_recalc(struct clk_hw *hw, unsigned long parent_rate);
long omap2_dpll_round_rate(struct clk_hw *hw, unsigned long target_rate,
@@ -278,6 +291,8 @@ int omap2_clk_disable_autoidle_all(void);
void omap2_clk_enable_init_clocks(const char **clk_names, u8 num_clocks);
int omap3_dpll4_set_rate(struct clk_hw *clk, unsigned long rate,
unsigned long parent_rate);
+int omap3_dpll4_set_rate_and_parent(struct clk_hw *hw, unsigned long rate,
+ unsigned long parent_rate, u8 index);
int omap2_dflt_clk_enable(struct clk_hw *hw);
void omap2_dflt_clk_disable(struct clk_hw *hw);
int omap2_dflt_clk_is_enabled(struct clk_hw *hw);
diff --git a/include/linux/compaction.h b/include/linux/compaction.h
index 60bdf8d..3238ffa 100644
--- a/include/linux/compaction.h
+++ b/include/linux/compaction.h
@@ -33,10 +33,11 @@ extern int fragmentation_index(struct zone *zone, unsigned int order);
extern unsigned long try_to_compact_pages(struct zonelist *zonelist,
int order, gfp_t gfp_mask, nodemask_t *mask,
enum migrate_mode mode, int *contended,
- struct zone **candidate_zone);
+ int alloc_flags, int classzone_idx);
extern void compact_pgdat(pg_data_t *pgdat, int order);
extern void reset_isolation_suitable(pg_data_t *pgdat);
-extern unsigned long compaction_suitable(struct zone *zone, int order);
+extern unsigned long compaction_suitable(struct zone *zone, int order,
+ int alloc_flags, int classzone_idx);
/* Do not skip compaction more than 64 times */
#define COMPACT_MAX_DEFER_SHIFT 6
@@ -103,7 +104,7 @@ static inline bool compaction_restarting(struct zone *zone, int order)
static inline unsigned long try_to_compact_pages(struct zonelist *zonelist,
int order, gfp_t gfp_mask, nodemask_t *nodemask,
enum migrate_mode mode, int *contended,
- struct zone **candidate_zone)
+ int alloc_flags, int classzone_idx)
{
return COMPACT_CONTINUE;
}
@@ -116,7 +117,8 @@ static inline void reset_isolation_suitable(pg_data_t *pgdat)
{
}
-static inline unsigned long compaction_suitable(struct zone *zone, int order)
+static inline unsigned long compaction_suitable(struct zone *zone, int order,
+ int alloc_flags, int classzone_idx)
{
return COMPACT_SKIPPED;
}
diff --git a/include/linux/cpufreq.h b/include/linux/cpufreq.h
index 503b085..4d078ce 100644
--- a/include/linux/cpufreq.h
+++ b/include/linux/cpufreq.h
@@ -217,26 +217,26 @@ __ATTR(_name, 0644, show_##_name, store_##_name)
struct cpufreq_driver {
- char name[CPUFREQ_NAME_LEN];
- u8 flags;
- void *driver_data;
+ char name[CPUFREQ_NAME_LEN];
+ u8 flags;
+ void *driver_data;
/* needed by all drivers */
- int (*init) (struct cpufreq_policy *policy);
- int (*verify) (struct cpufreq_policy *policy);
+ int (*init)(struct cpufreq_policy *policy);
+ int (*verify)(struct cpufreq_policy *policy);
/* define one out of two */
- int (*setpolicy) (struct cpufreq_policy *policy);
+ int (*setpolicy)(struct cpufreq_policy *policy);
/*
* On failure, should always restore frequency to policy->restore_freq
* (i.e. old freq).
*/
- int (*target) (struct cpufreq_policy *policy, /* Deprecated */
- unsigned int target_freq,
- unsigned int relation);
- int (*target_index) (struct cpufreq_policy *policy,
- unsigned int index);
+ int (*target)(struct cpufreq_policy *policy,
+ unsigned int target_freq,
+ unsigned int relation); /* Deprecated */
+ int (*target_index)(struct cpufreq_policy *policy,
+ unsigned int index);
/*
* Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION
* unset.
@@ -252,27 +252,31 @@ struct cpufreq_driver {
* wish to switch to intermediate frequency for some target frequency.
* In that case core will directly call ->target_index().
*/
- unsigned int (*get_intermediate)(struct cpufreq_policy *policy,
- unsigned int index);
- int (*target_intermediate)(struct cpufreq_policy *policy,
- unsigned int index);
+ unsigned int (*get_intermediate)(struct cpufreq_policy *policy,
+ unsigned int index);
+ int (*target_intermediate)(struct cpufreq_policy *policy,
+ unsigned int index);
/* should be defined, if possible */
- unsigned int (*get) (unsigned int cpu);
+ unsigned int (*get)(unsigned int cpu);
/* optional */
- int (*bios_limit) (int cpu, unsigned int *limit);
+ int (*bios_limit)(int cpu, unsigned int *limit);
+
+ int (*exit)(struct cpufreq_policy *policy);
+ void (*stop_cpu)(struct cpufreq_policy *policy);
+ int (*suspend)(struct cpufreq_policy *policy);
+ int (*resume)(struct cpufreq_policy *policy);
+
+ /* Will be called after the driver is fully initialized */
+ void (*ready)(struct cpufreq_policy *policy);
- int (*exit) (struct cpufreq_policy *policy);
- void (*stop_cpu) (struct cpufreq_policy *policy);
- int (*suspend) (struct cpufreq_policy *policy);
- int (*resume) (struct cpufreq_policy *policy);
- struct freq_attr **attr;
+ struct freq_attr **attr;
/* platform specific boost support code */
- bool boost_supported;
- bool boost_enabled;
- int (*set_boost) (int state);
+ bool boost_supported;
+ bool boost_enabled;
+ int (*set_boost)(int state);
};
/* flags */
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 25e0df6..a07e087 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -53,7 +53,7 @@ struct cpuidle_state {
};
/* Idle State Flags */
-#define CPUIDLE_FLAG_TIME_VALID (0x01) /* is residency time measurable? */
+#define CPUIDLE_FLAG_TIME_INVALID (0x01) /* is residency time measurable? */
#define CPUIDLE_FLAG_COUPLED (0x02) /* state applies to multiple cpus */
#define CPUIDLE_FLAG_TIMER_STOP (0x04) /* timer is stopped on this state */
@@ -90,7 +90,7 @@ DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev);
* cpuidle_get_last_residency - retrieves the last state's residency time
* @dev: the target CPU
*
- * NOTE: this value is invalid if CPUIDLE_FLAG_TIME_VALID isn't set
+ * NOTE: this value is invalid if CPUIDLE_FLAG_TIME_INVALID is set
*/
static inline int cpuidle_get_last_residency(struct cpuidle_device *dev)
{
diff --git a/include/linux/dcache.h b/include/linux/dcache.h
index b2a2a08..5a81398 100644
--- a/include/linux/dcache.h
+++ b/include/linux/dcache.h
@@ -124,15 +124,15 @@ struct dentry {
void *d_fsdata; /* fs-specific data */
struct list_head d_lru; /* LRU list */
+ struct list_head d_child; /* child of parent list */
+ struct list_head d_subdirs; /* our children */
/*
- * d_child and d_rcu can share memory
+ * d_alias and d_rcu can share memory
*/
union {
- struct list_head d_child; /* child of parent list */
+ struct hlist_node d_alias; /* inode alias list */
struct rcu_head d_rcu;
} d_u;
- struct list_head d_subdirs; /* our children */
- struct hlist_node d_alias; /* inode alias list */
};
/*
@@ -230,7 +230,6 @@ extern seqlock_t rename_lock;
*/
extern void d_instantiate(struct dentry *, struct inode *);
extern struct dentry * d_instantiate_unique(struct dentry *, struct inode *);
-extern struct dentry * d_materialise_unique(struct dentry *, struct inode *);
extern int d_instantiate_no_diralias(struct dentry *, struct inode *);
extern void __d_drop(struct dentry *dentry);
extern void d_drop(struct dentry *dentry);
diff --git a/include/linux/debugfs.h b/include/linux/debugfs.h
index 4d0b4d1..d84f8c2 100644
--- a/include/linux/debugfs.h
+++ b/include/linux/debugfs.h
@@ -92,8 +92,8 @@ struct dentry *debugfs_create_regset32(const char *name, umode_t mode,
struct dentry *parent,
struct debugfs_regset32 *regset);
-int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
- int nregs, void __iomem *base, char *prefix);
+void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
+ int nregs, void __iomem *base, char *prefix);
struct dentry *debugfs_create_u32_array(const char *name, umode_t mode,
struct dentry *parent,
@@ -233,10 +233,9 @@ static inline struct dentry *debugfs_create_regset32(const char *name,
return ERR_PTR(-ENODEV);
}
-static inline int debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
+static inline void debugfs_print_regs32(struct seq_file *s, const struct debugfs_reg32 *regs,
int nregs, void __iomem *base, char *prefix)
{
- return 0;
}
static inline bool debugfs_initialized(void)
diff --git a/include/linux/device-mapper.h b/include/linux/device-mapper.h
index e1707de..ca6d2ac 100644
--- a/include/linux/device-mapper.h
+++ b/include/linux/device-mapper.h
@@ -64,6 +64,7 @@ typedef int (*dm_request_endio_fn) (struct dm_target *ti,
union map_info *map_context);
typedef void (*dm_presuspend_fn) (struct dm_target *ti);
+typedef void (*dm_presuspend_undo_fn) (struct dm_target *ti);
typedef void (*dm_postsuspend_fn) (struct dm_target *ti);
typedef int (*dm_preresume_fn) (struct dm_target *ti);
typedef void (*dm_resume_fn) (struct dm_target *ti);
@@ -145,6 +146,7 @@ struct target_type {
dm_endio_fn end_io;
dm_request_endio_fn rq_end_io;
dm_presuspend_fn presuspend;
+ dm_presuspend_undo_fn presuspend_undo;
dm_postsuspend_fn postsuspend;
dm_preresume_fn preresume;
dm_resume_fn resume;
diff --git a/include/linux/edac.h b/include/linux/edac.h
index e1e68da..da3b72e 100644
--- a/include/linux/edac.h
+++ b/include/linux/edac.h
@@ -194,7 +194,8 @@ static inline char *mc_event_error_type(const unsigned int err_type)
* @MEM_DDR3: DDR3 RAM
* @MEM_RDDR3: Registered DDR3 RAM
* This is a variant of the DDR3 memories.
- * @MEM_DDR4: DDR4 RAM
+ * @MEM_LRDDR3 Load-Reduced DDR3 memory.
+ * @MEM_DDR4: Unbuffered DDR4 RAM
* @MEM_RDDR4: Registered DDR4 RAM
* This is a variant of the DDR4 memories.
*/
@@ -216,6 +217,7 @@ enum mem_type {
MEM_XDR,
MEM_DDR3,
MEM_RDDR3,
+ MEM_LRDDR3,
MEM_DDR4,
MEM_RDDR4,
};
diff --git a/include/linux/eeprom_93cx6.h b/include/linux/eeprom_93cx6.h
index e50f98b..eb0b198 100644
--- a/include/linux/eeprom_93cx6.h
+++ b/include/linux/eeprom_93cx6.h
@@ -75,6 +75,10 @@ extern void eeprom_93cx6_read(struct eeprom_93cx6 *eeprom,
const u8 word, u16 *data);
extern void eeprom_93cx6_multiread(struct eeprom_93cx6 *eeprom,
const u8 word, __le16 *data, const u16 words);
+extern void eeprom_93cx6_readb(struct eeprom_93cx6 *eeprom,
+ const u8 byte, u8 *data);
+extern void eeprom_93cx6_multireadb(struct eeprom_93cx6 *eeprom,
+ const u8 byte, u8 *data, const u16 bytes);
extern void eeprom_93cx6_wren(struct eeprom_93cx6 *eeprom, bool enable);
diff --git a/include/linux/efi.h b/include/linux/efi.h
index 0949f9c..0238d61 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -547,6 +547,9 @@ void efi_native_runtime_setup(void);
#define SMBIOS_TABLE_GUID \
EFI_GUID( 0xeb9d2d31, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
+#define SMBIOS3_TABLE_GUID \
+ EFI_GUID( 0xf2fd1544, 0x9794, 0x4a2c, 0x99, 0x2e, 0xe5, 0xbb, 0xcf, 0x20, 0xe3, 0x94 )
+
#define SAL_SYSTEM_TABLE_GUID \
EFI_GUID( 0xeb9d2d32, 0x2d88, 0x11d3, 0x9a, 0x16, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d )
@@ -810,7 +813,8 @@ extern struct efi {
unsigned long mps; /* MPS table */
unsigned long acpi; /* ACPI table (IA64 ext 0.71) */
unsigned long acpi20; /* ACPI table (ACPI 2.0) */
- unsigned long smbios; /* SM BIOS table */
+ unsigned long smbios; /* SMBIOS table (32 bit entry point) */
+ unsigned long smbios3; /* SMBIOS table (64 bit entry point) */
unsigned long sal_systab; /* SAL system table */
unsigned long boot_info; /* boot info table */
unsigned long hcdp; /* HCDP table */
diff --git a/include/linux/f2fs_fs.h b/include/linux/f2fs_fs.h
index 860313a..87f14e9 100644
--- a/include/linux/f2fs_fs.h
+++ b/include/linux/f2fs_fs.h
@@ -33,7 +33,8 @@
#define F2FS_META_INO(sbi) (sbi->meta_ino_num)
/* This flag is used by node and meta inodes, and by recovery */
-#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO)
+#define GFP_F2FS_ZERO (GFP_NOFS | __GFP_ZERO)
+#define GFP_F2FS_HIGH_ZERO (GFP_NOFS | __GFP_ZERO | __GFP_HIGHMEM)
/*
* For further optimization on multi-head logs, on-disk layout supports maximum
@@ -170,14 +171,12 @@ struct f2fs_extent {
#define F2FS_INLINE_XATTR 0x01 /* file inline xattr flag */
#define F2FS_INLINE_DATA 0x02 /* file inline data flag */
+#define F2FS_INLINE_DENTRY 0x04 /* file inline dentry flag */
+#define F2FS_DATA_EXIST 0x08 /* file inline data exist flag */
#define MAX_INLINE_DATA (sizeof(__le32) * (DEF_ADDRS_PER_INODE - \
F2FS_INLINE_XATTR_ADDRS - 1))
-#define INLINE_DATA_OFFSET (PAGE_CACHE_SIZE - sizeof(struct node_footer) -\
- sizeof(__le32) * (DEF_ADDRS_PER_INODE + \
- DEF_NIDS_PER_INODE - 1))
-
struct f2fs_inode {
__le16 i_mode; /* file mode */
__u8 i_advise; /* file hints */
@@ -435,6 +434,24 @@ struct f2fs_dentry_block {
__u8 filename[NR_DENTRY_IN_BLOCK][F2FS_SLOT_LEN];
} __packed;
+/* for inline dir */
+#define NR_INLINE_DENTRY (MAX_INLINE_DATA * BITS_PER_BYTE / \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ BITS_PER_BYTE + 1))
+#define INLINE_DENTRY_BITMAP_SIZE ((NR_INLINE_DENTRY + \
+ BITS_PER_BYTE - 1) / BITS_PER_BYTE)
+#define INLINE_RESERVED_SIZE (MAX_INLINE_DATA - \
+ ((SIZE_OF_DIR_ENTRY + F2FS_SLOT_LEN) * \
+ NR_INLINE_DENTRY + INLINE_DENTRY_BITMAP_SIZE))
+
+/* inline directory entry structure */
+struct f2fs_inline_dentry {
+ __u8 dentry_bitmap[INLINE_DENTRY_BITMAP_SIZE];
+ __u8 reserved[INLINE_RESERVED_SIZE];
+ struct f2fs_dir_entry dentry[NR_INLINE_DENTRY];
+ __u8 filename[NR_INLINE_DENTRY][F2FS_SLOT_LEN];
+} __packed;
+
/* file types used in inode_info->flags */
enum {
F2FS_FT_UNKNOWN,
diff --git a/include/linux/file.h b/include/linux/file.h
index 4d69123..f87d308 100644
--- a/include/linux/file.h
+++ b/include/linux/file.h
@@ -66,7 +66,6 @@ extern void set_close_on_exec(unsigned int fd, int flag);
extern bool get_close_on_exec(unsigned int fd);
extern void put_filp(struct file *);
extern int get_unused_fd_flags(unsigned flags);
-#define get_unused_fd() get_unused_fd_flags(0)
extern void put_unused_fd(unsigned int fd);
extern void fd_install(unsigned int fd, struct file *file);
diff --git a/include/linux/freezer.h b/include/linux/freezer.h
index 7fd81b8..6b7fd9c 100644
--- a/include/linux/freezer.h
+++ b/include/linux/freezer.h
@@ -246,15 +246,6 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
* defined in <linux/wait.h>
*/
-#define wait_event_freezekillable(wq, condition) \
-({ \
- int __retval; \
- freezer_do_not_count(); \
- __retval = wait_event_killable(wq, (condition)); \
- freezer_count(); \
- __retval; \
-})
-
/* DO NOT ADD ANY NEW CALLERS OF THIS FUNCTION */
#define wait_event_freezekillable_unsafe(wq, condition) \
({ \
@@ -265,35 +256,6 @@ static inline int freezable_schedule_hrtimeout_range(ktime_t *expires,
__retval; \
})
-#define wait_event_freezable(wq, condition) \
-({ \
- int __retval; \
- freezer_do_not_count(); \
- __retval = wait_event_interruptible(wq, (condition)); \
- freezer_count(); \
- __retval; \
-})
-
-#define wait_event_freezable_timeout(wq, condition, timeout) \
-({ \
- long __retval = timeout; \
- freezer_do_not_count(); \
- __retval = wait_event_interruptible_timeout(wq, (condition), \
- __retval); \
- freezer_count(); \
- __retval; \
-})
-
-#define wait_event_freezable_exclusive(wq, condition) \
-({ \
- int __retval; \
- freezer_do_not_count(); \
- __retval = wait_event_interruptible_exclusive(wq, condition); \
- freezer_count(); \
- __retval; \
-})
-
-
#else /* !CONFIG_FREEZER */
static inline bool frozen(struct task_struct *p) { return false; }
static inline bool freezing(struct task_struct *p) { return false; }
@@ -331,18 +293,6 @@ static inline void set_freezable(void) {}
#define freezable_schedule_hrtimeout_range(expires, delta, mode) \
schedule_hrtimeout_range(expires, delta, mode)
-#define wait_event_freezable(wq, condition) \
- wait_event_interruptible(wq, condition)
-
-#define wait_event_freezable_timeout(wq, condition, timeout) \
- wait_event_interruptible_timeout(wq, condition, timeout)
-
-#define wait_event_freezable_exclusive(wq, condition) \
- wait_event_interruptible_exclusive(wq, condition)
-
-#define wait_event_freezekillable(wq, condition) \
- wait_event_killable(wq, condition)
-
#define wait_event_freezekillable_unsafe(wq, condition) \
wait_event_killable(wq, condition)
diff --git a/include/linux/fs.h b/include/linux/fs.h
index 9ab779e..bb29b02 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -606,9 +606,6 @@ struct inode {
const struct file_operations *i_fop; /* former ->i_op->default_file_ops */
struct file_lock *i_flock;
struct address_space i_data;
-#ifdef CONFIG_QUOTA
- struct dquot *i_dquot[MAXQUOTAS];
-#endif
struct list_head i_devices;
union {
struct pipe_inode_info *i_pipe;
@@ -789,7 +786,6 @@ struct file {
struct rcu_head fu_rcuhead;
} f_u;
struct path f_path;
-#define f_dentry f_path.dentry
struct inode *f_inode; /* cached value */
const struct file_operations *f_op;
@@ -1224,6 +1220,7 @@ struct super_block {
struct backing_dev_info *s_bdi;
struct mtd_info *s_mtd;
struct hlist_node s_instances;
+ unsigned int s_quota_types; /* Bitmask of supported quota types */
struct quota_info s_dquot; /* Diskquota specific options */
struct sb_writers s_writers;
@@ -1467,7 +1464,10 @@ int fiemap_check_flags(struct fiemap_extent_info *fieinfo, u32 fs_flags);
* This allows the kernel to read directories into kernel space or
* to have different dirent layouts depending on the binary type.
*/
-typedef int (*filldir_t)(void *, const char *, int, loff_t, u64, unsigned);
+struct dir_context;
+typedef int (*filldir_t)(struct dir_context *, const char *, int, loff_t, u64,
+ unsigned);
+
struct dir_context {
const filldir_t actor;
loff_t pos;
@@ -1513,7 +1513,7 @@ struct file_operations {
int (*setlease)(struct file *, long, struct file_lock **, void **);
long (*fallocate)(struct file *file, int mode, loff_t offset,
loff_t len);
- int (*show_fdinfo)(struct seq_file *m, struct file *f);
+ void (*show_fdinfo)(struct seq_file *m, struct file *f);
};
struct inode_operations {
@@ -1577,7 +1577,9 @@ struct super_operations {
void (*evict_inode) (struct inode *);
void (*put_super) (struct super_block *);
int (*sync_fs)(struct super_block *sb, int wait);
+ int (*freeze_super) (struct super_block *);
int (*freeze_fs) (struct super_block *);
+ int (*thaw_super) (struct super_block *);
int (*unfreeze_fs) (struct super_block *);
int (*statfs) (struct dentry *, struct kstatfs *);
int (*remount_fs) (struct super_block *, int *, char *);
@@ -1590,6 +1592,7 @@ struct super_operations {
#ifdef CONFIG_QUOTA
ssize_t (*quota_read)(struct super_block *, int, char *, size_t, loff_t);
ssize_t (*quota_write)(struct super_block *, int, const char *, size_t, loff_t);
+ struct dquot **(*get_dquots)(struct inode *);
#endif
int (*bdev_try_to_free_page)(struct super_block*, struct page*, gfp_t);
long (*nr_cached_objects)(struct super_block *, int);
@@ -2786,6 +2789,11 @@ static inline void inode_has_no_xattr(struct inode *inode)
inode->i_flags |= S_NOSEC;
}
+static inline bool is_root_inode(struct inode *inode)
+{
+ return inode == inode->i_sb->s_root->d_inode;
+}
+
static inline bool dir_emit(struct dir_context *ctx,
const char *name, int namelen,
u64 ino, unsigned type)
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 662697b..ed50195 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -61,6 +61,11 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
/*
* FTRACE_OPS_FL_* bits denote the state of ftrace_ops struct and are
* set in the flags member.
+ * CONTROL, SAVE_REGS, SAVE_REGS_IF_SUPPORTED, RECURSION_SAFE, STUB and
+ * IPMODIFY are a kind of attribute flags which can be set only before
+ * registering the ftrace_ops, and can not be modified while registered.
+ * Changing those attribute flags after regsitering ftrace_ops will
+ * cause unexpected results.
*
* ENABLED - set/unset when ftrace_ops is registered/unregistered
* DYNAMIC - set when ftrace_ops is registered to denote dynamically
@@ -94,6 +99,17 @@ ftrace_func_t ftrace_ops_get_func(struct ftrace_ops *ops);
* ADDING - The ops is in the process of being added.
* REMOVING - The ops is in the process of being removed.
* MODIFYING - The ops is in the process of changing its filter functions.
+ * ALLOC_TRAMP - A dynamic trampoline was allocated by the core code.
+ * The arch specific code sets this flag when it allocated a
+ * trampoline. This lets the arch know that it can update the
+ * trampoline in case the callback function changes.
+ * The ftrace_ops trampoline can be set by the ftrace users, and
+ * in such cases the arch must not modify it. Only the arch ftrace
+ * core code should set this flag.
+ * IPMODIFY - The ops can modify the IP register. This can only be set with
+ * SAVE_REGS. If another ops with this flag set is already registered
+ * for any of the functions that this ops will be registered for, then
+ * this ops will fail to register or set_filter_ip.
*/
enum {
FTRACE_OPS_FL_ENABLED = 1 << 0,
@@ -108,6 +124,8 @@ enum {
FTRACE_OPS_FL_ADDING = 1 << 9,
FTRACE_OPS_FL_REMOVING = 1 << 10,
FTRACE_OPS_FL_MODIFYING = 1 << 11,
+ FTRACE_OPS_FL_ALLOC_TRAMP = 1 << 12,
+ FTRACE_OPS_FL_IPMODIFY = 1 << 13,
};
#ifdef CONFIG_DYNAMIC_FTRACE
@@ -142,6 +160,7 @@ struct ftrace_ops {
struct ftrace_ops_hash *func_hash;
struct ftrace_ops_hash old_hash;
unsigned long trampoline;
+ unsigned long trampoline_size;
#endif
};
@@ -255,7 +274,9 @@ struct ftrace_func_command {
int ftrace_arch_code_modify_prepare(void);
int ftrace_arch_code_modify_post_process(void);
-void ftrace_bug(int err, unsigned long ip);
+struct dyn_ftrace;
+
+void ftrace_bug(int err, struct dyn_ftrace *rec);
struct seq_file;
@@ -287,6 +308,8 @@ extern int ftrace_text_reserved(const void *start, const void *end);
extern int ftrace_nr_registered_ops(void);
+bool is_ftrace_trampoline(unsigned long addr);
+
/*
* The dyn_ftrace record's flags field is split into two parts.
* the first part which is '0-FTRACE_REF_MAX' is a counter of
@@ -297,6 +320,7 @@ extern int ftrace_nr_registered_ops(void);
* ENABLED - the function is being traced
* REGS - the record wants the function to save regs
* REGS_EN - the function is set up to save regs.
+ * IPMODIFY - the record allows for the IP address to be changed.
*
* When a new ftrace_ops is registered and wants a function to save
* pt_regs, the rec->flag REGS is set. When the function has been
@@ -310,10 +334,11 @@ enum {
FTRACE_FL_REGS_EN = (1UL << 29),
FTRACE_FL_TRAMP = (1UL << 28),
FTRACE_FL_TRAMP_EN = (1UL << 27),
+ FTRACE_FL_IPMODIFY = (1UL << 26),
};
-#define FTRACE_REF_MAX_SHIFT 27
-#define FTRACE_FL_BITS 5
+#define FTRACE_REF_MAX_SHIFT 26
+#define FTRACE_FL_BITS 6
#define FTRACE_FL_MASKED_BITS ((1UL << FTRACE_FL_BITS) - 1)
#define FTRACE_FL_MASK (FTRACE_FL_MASKED_BITS << FTRACE_REF_MAX_SHIFT)
#define FTRACE_REF_MAX ((1UL << FTRACE_REF_MAX_SHIFT) - 1)
@@ -586,6 +611,11 @@ static inline ssize_t ftrace_notrace_write(struct file *file, const char __user
size_t cnt, loff_t *ppos) { return -ENODEV; }
static inline int
ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; }
+
+static inline bool is_ftrace_trampoline(unsigned long addr)
+{
+ return false;
+}
#endif /* CONFIG_DYNAMIC_FTRACE */
/* totally disable ftrace - can not re-enable after this */
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 28672e8..0bebb5c 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -138,6 +138,17 @@ enum print_line_t {
TRACE_TYPE_NO_CONSUME = 3 /* Handled but ask to not consume */
};
+/*
+ * Several functions return TRACE_TYPE_PARTIAL_LINE if the trace_seq
+ * overflowed, and TRACE_TYPE_HANDLED otherwise. This helper function
+ * simplifies those functions and keeps them in sync.
+ */
+static inline enum print_line_t trace_handle_return(struct trace_seq *s)
+{
+ return trace_seq_has_overflowed(s) ?
+ TRACE_TYPE_PARTIAL_LINE : TRACE_TYPE_HANDLED;
+}
+
void tracing_generic_entry_update(struct trace_entry *entry,
unsigned long flags,
int pc);
diff --git a/include/linux/gfp.h b/include/linux/gfp.h
index 41b30fd..07d2699 100644
--- a/include/linux/gfp.h
+++ b/include/linux/gfp.h
@@ -381,8 +381,8 @@ extern void free_kmem_pages(unsigned long addr, unsigned int order);
void page_alloc_init(void);
void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp);
-void drain_all_pages(void);
-void drain_local_pages(void *dummy);
+void drain_all_pages(struct zone *zone);
+void drain_local_pages(struct zone *zone);
/*
* gfp_allowed_mask is set to GFP_BOOT_MASK during early boot to restrict what
diff --git a/include/linux/gpio/consumer.h b/include/linux/gpio/consumer.h
index 12f146f..00b1b70 100644
--- a/include/linux/gpio/consumer.h
+++ b/include/linux/gpio/consumer.h
@@ -94,6 +94,13 @@ int gpiod_to_irq(const struct gpio_desc *desc);
struct gpio_desc *gpio_to_desc(unsigned gpio);
int desc_to_gpio(const struct gpio_desc *desc);
+/* Child properties interface */
+struct fwnode_handle;
+
+struct gpio_desc *fwnode_get_named_gpiod(struct fwnode_handle *fwnode,
+ const char *propname);
+struct gpio_desc *devm_get_gpiod_from_child(struct device *dev,
+ struct fwnode_handle *child);
#else /* CONFIG_GPIOLIB */
static inline struct gpio_desc *__must_check __gpiod_get(struct device *dev,
diff --git a/include/linux/gpio_keys.h b/include/linux/gpio_keys.h
index 8b62246..ee2d8c6 100644
--- a/include/linux/gpio_keys.h
+++ b/include/linux/gpio_keys.h
@@ -2,6 +2,7 @@
#define _GPIO_KEYS_H
struct device;
+struct gpio_desc;
/**
* struct gpio_keys_button - configuration parameters
@@ -17,6 +18,7 @@ struct device;
* disable button via sysfs
* @value: axis value for %EV_ABS
* @irq: Irq number in case of interrupt keys
+ * @gpiod: GPIO descriptor
*/
struct gpio_keys_button {
unsigned int code;
@@ -29,6 +31,7 @@ struct gpio_keys_button {
bool can_disable;
int value;
unsigned int irq;
+ struct gpio_desc *gpiod;
};
/**
diff --git a/include/linux/hugetlb.h b/include/linux/hugetlb.h
index 6e6d338..cdd149c 100644
--- a/include/linux/hugetlb.h
+++ b/include/linux/hugetlb.h
@@ -311,7 +311,8 @@ static inline struct hstate *hstate_sizelog(int page_size_log)
{
if (!page_size_log)
return &default_hstate;
- return size_to_hstate(1 << page_size_log);
+
+ return size_to_hstate(1UL << page_size_log);
}
static inline struct hstate *hstate_vma(struct vm_area_struct *vma)
diff --git a/include/linux/hugetlb_cgroup.h b/include/linux/hugetlb_cgroup.h
index 0129f89..bcc853e 100644
--- a/include/linux/hugetlb_cgroup.h
+++ b/include/linux/hugetlb_cgroup.h
@@ -16,7 +16,6 @@
#define _LINUX_HUGETLB_CGROUP_H
#include <linux/mmdebug.h>
-#include <linux/res_counter.h>
struct hugetlb_cgroup;
/*
diff --git a/include/linux/i2c/pmbus.h b/include/linux/i2c/pmbus.h
index 69280db..ee3c2ab 100644
--- a/include/linux/i2c/pmbus.h
+++ b/include/linux/i2c/pmbus.h
@@ -40,6 +40,10 @@
struct pmbus_platform_data {
u32 flags; /* Device specific flags */
+
+ /* regulator support */
+ int num_regulators;
+ struct regulator_init_data *reg_init_data;
};
#endif /* _PMBUS_H_ */
diff --git a/include/linux/init_task.h b/include/linux/init_task.h
index 77fc43f..3037fc0 100644
--- a/include/linux/init_task.h
+++ b/include/linux/init_task.h
@@ -102,7 +102,7 @@ extern struct group_info init_groups;
#define INIT_IDS
#endif
-#ifdef CONFIG_TREE_PREEMPT_RCU
+#ifdef CONFIG_PREEMPT_RCU
#define INIT_TASK_RCU_TREE_PREEMPT() \
.rcu_blocked_node = NULL,
#else
@@ -166,6 +166,15 @@ extern struct task_group root_task_group;
# define INIT_RT_MUTEXES(tsk)
#endif
+#ifdef CONFIG_NUMA_BALANCING
+# define INIT_NUMA_BALANCING(tsk) \
+ .numa_preferred_nid = -1, \
+ .numa_group = NULL, \
+ .numa_faults = NULL,
+#else
+# define INIT_NUMA_BALANCING(tsk)
+#endif
+
/*
* INIT_TASK is used to set up the first task table, touch at
* your own risk!. Base=0, limit=0x1fffff (=2MB)
@@ -237,6 +246,7 @@ extern struct task_group root_task_group;
INIT_CPUSET_SEQ(tsk) \
INIT_RT_MUTEXES(tsk) \
INIT_VTIME(tsk) \
+ INIT_NUMA_BALANCING(tsk) \
}
diff --git a/include/linux/iommu.h b/include/linux/iommu.h
index e6a7c9f..b29a598 100644
--- a/include/linux/iommu.h
+++ b/include/linux/iommu.h
@@ -22,6 +22,7 @@
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/types.h>
+#include <linux/scatterlist.h>
#include <trace/events/iommu.h>
#define IOMMU_READ (1 << 0)
@@ -97,6 +98,8 @@ enum iommu_attr {
* @detach_dev: detach device from an iommu domain
* @map: map a physically contiguous memory region to an iommu domain
* @unmap: unmap a physically contiguous memory region from an iommu domain
+ * @map_sg: map a scatter-gather list of physically contiguous memory chunks
+ * to an iommu domain
* @iova_to_phys: translate iova to physical address
* @add_device: add device to iommu grouping
* @remove_device: remove device from iommu grouping
@@ -114,6 +117,8 @@ struct iommu_ops {
phys_addr_t paddr, size_t size, int prot);
size_t (*unmap)(struct iommu_domain *domain, unsigned long iova,
size_t size);
+ size_t (*map_sg)(struct iommu_domain *domain, unsigned long iova,
+ struct scatterlist *sg, unsigned int nents, int prot);
phys_addr_t (*iova_to_phys)(struct iommu_domain *domain, dma_addr_t iova);
int (*add_device)(struct device *dev);
void (*remove_device)(struct device *dev);
@@ -156,6 +161,9 @@ extern int iommu_map(struct iommu_domain *domain, unsigned long iova,
phys_addr_t paddr, size_t size, int prot);
extern size_t iommu_unmap(struct iommu_domain *domain, unsigned long iova,
size_t size);
+extern size_t default_iommu_map_sg(struct iommu_domain *domain, unsigned long iova,
+ struct scatterlist *sg,unsigned int nents,
+ int prot);
extern phys_addr_t iommu_iova_to_phys(struct iommu_domain *domain, dma_addr_t iova);
extern void iommu_set_fault_handler(struct iommu_domain *domain,
iommu_fault_handler_t handler, void *token);
@@ -241,6 +249,13 @@ static inline int report_iommu_fault(struct iommu_domain *domain,
return ret;
}
+static inline size_t iommu_map_sg(struct iommu_domain *domain,
+ unsigned long iova, struct scatterlist *sg,
+ unsigned int nents, int prot)
+{
+ return domain->ops->map_sg(domain, iova, sg, nents, prot);
+}
+
#else /* CONFIG_IOMMU_API */
struct iommu_ops {};
@@ -293,6 +308,13 @@ static inline int iommu_unmap(struct iommu_domain *domain, unsigned long iova,
return -ENODEV;
}
+static inline size_t iommu_map_sg(struct iommu_domain *domain,
+ unsigned long iova, struct scatterlist *sg,
+ unsigned int nents, int prot)
+{
+ return -ENODEV;
+}
+
static inline int iommu_domain_window_enable(struct iommu_domain *domain,
u32 wnd_nr, phys_addr_t paddr,
u64 size, int prot)
diff --git a/include/linux/irq.h b/include/linux/irq.h
index 03f48d9..d09ec7a 100644
--- a/include/linux/irq.h
+++ b/include/linux/irq.h
@@ -15,11 +15,13 @@
#include <linux/spinlock.h>
#include <linux/cpumask.h>
#include <linux/gfp.h>
+#include <linux/irqhandler.h>
#include <linux/irqreturn.h>
#include <linux/irqnr.h>
#include <linux/errno.h>
#include <linux/topology.h>
#include <linux/wait.h>
+#include <linux/io.h>
#include <asm/irq.h>
#include <asm/ptrace.h>
@@ -27,11 +29,7 @@
struct seq_file;
struct module;
-struct irq_desc;
-struct irq_data;
-typedef void (*irq_flow_handler_t)(unsigned int irq,
- struct irq_desc *desc);
-typedef void (*irq_preflow_handler_t)(struct irq_data *data);
+struct msi_msg;
/*
* IRQ line status.
@@ -113,10 +111,14 @@ enum {
*
* IRQ_SET_MASK_OK - OK, core updates irq_data.affinity
* IRQ_SET_MASK_NOCPY - OK, chip did update irq_data.affinity
+ * IRQ_SET_MASK_OK_DONE - Same as IRQ_SET_MASK_OK for core. Special code to
+ * support stacked irqchips, which indicates skipping
+ * all descendent irqchips.
*/
enum {
IRQ_SET_MASK_OK = 0,
IRQ_SET_MASK_OK_NOCOPY,
+ IRQ_SET_MASK_OK_DONE,
};
struct msi_desc;
@@ -133,6 +135,8 @@ struct irq_domain;
* @chip: low level interrupt hardware access
* @domain: Interrupt translation domain; responsible for mapping
* between hwirq number and linux irq number.
+ * @parent_data: pointer to parent struct irq_data to support hierarchy
+ * irq_domain
* @handler_data: per-IRQ data for the irq_chip methods
* @chip_data: platform-specific per-chip private data for the chip
* methods, to allow shared chip implementations
@@ -151,6 +155,9 @@ struct irq_data {
unsigned int state_use_accessors;
struct irq_chip *chip;
struct irq_domain *domain;
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ struct irq_data *parent_data;
+#endif
void *handler_data;
void *chip_data;
struct msi_desc *msi_desc;
@@ -315,6 +322,8 @@ static inline irq_hw_number_t irqd_to_hwirq(struct irq_data *d)
* any other callback related to this irq
* @irq_release_resources: optional to release resources acquired with
* irq_request_resources
+ * @irq_compose_msi_msg: optional to compose message content for MSI
+ * @irq_write_msi_msg: optional to write message content for MSI
* @flags: chip specific flags
*/
struct irq_chip {
@@ -351,6 +360,9 @@ struct irq_chip {
int (*irq_request_resources)(struct irq_data *data);
void (*irq_release_resources)(struct irq_data *data);
+ void (*irq_compose_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+ void (*irq_write_msi_msg)(struct irq_data *data, struct msi_msg *msg);
+
unsigned long flags;
};
@@ -438,6 +450,18 @@ extern void handle_percpu_devid_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_bad_irq(unsigned int irq, struct irq_desc *desc);
extern void handle_nested_irq(unsigned int irq);
+extern int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg);
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+extern void irq_chip_ack_parent(struct irq_data *data);
+extern int irq_chip_retrigger_hierarchy(struct irq_data *data);
+extern void irq_chip_mask_parent(struct irq_data *data);
+extern void irq_chip_unmask_parent(struct irq_data *data);
+extern void irq_chip_eoi_parent(struct irq_data *data);
+extern int irq_chip_set_affinity_parent(struct irq_data *data,
+ const struct cpumask *dest,
+ bool force);
+#endif
+
/* Handling of unhandled and spurious interrupts: */
extern void note_interrupt(unsigned int irq, struct irq_desc *desc,
irqreturn_t action_ret);
@@ -639,13 +663,6 @@ void arch_teardown_hwirq(unsigned int irq);
void irq_init_desc(unsigned int irq);
#endif
-#ifndef irq_reg_writel
-# define irq_reg_writel(val, addr) writel(val, addr)
-#endif
-#ifndef irq_reg_readl
-# define irq_reg_readl(addr) readl(addr)
-#endif
-
/**
* struct irq_chip_regs - register offsets for struct irq_gci
* @enable: Enable register offset to reg_base
@@ -692,6 +709,8 @@ struct irq_chip_type {
* struct irq_chip_generic - Generic irq chip data structure
* @lock: Lock to protect register and cache data access
* @reg_base: Register base address (virtual)
+ * @reg_readl: Alternate I/O accessor (defaults to readl if NULL)
+ * @reg_writel: Alternate I/O accessor (defaults to writel if NULL)
* @irq_base: Interrupt base nr for this chip
* @irq_cnt: Number of interrupts handled by this chip
* @mask_cache: Cached mask register shared between all chip types
@@ -716,6 +735,8 @@ struct irq_chip_type {
struct irq_chip_generic {
raw_spinlock_t lock;
void __iomem *reg_base;
+ u32 (*reg_readl)(void __iomem *addr);
+ void (*reg_writel)(u32 val, void __iomem *addr);
unsigned int irq_base;
unsigned int irq_cnt;
u32 mask_cache;
@@ -740,12 +761,14 @@ struct irq_chip_generic {
* the parent irq. Usually GPIO implementations
* @IRQ_GC_MASK_CACHE_PER_TYPE: Mask cache is chip type private
* @IRQ_GC_NO_MASK: Do not calculate irq_data->mask
+ * @IRQ_GC_BE_IO: Use big-endian register accesses (default: LE)
*/
enum irq_gc_flags {
IRQ_GC_INIT_MASK_CACHE = 1 << 0,
IRQ_GC_INIT_NESTED_LOCK = 1 << 1,
IRQ_GC_MASK_CACHE_PER_TYPE = 1 << 2,
IRQ_GC_NO_MASK = 1 << 3,
+ IRQ_GC_BE_IO = 1 << 4,
};
/*
@@ -821,4 +844,22 @@ static inline void irq_gc_lock(struct irq_chip_generic *gc) { }
static inline void irq_gc_unlock(struct irq_chip_generic *gc) { }
#endif
+static inline void irq_reg_writel(struct irq_chip_generic *gc,
+ u32 val, int reg_offset)
+{
+ if (gc->reg_writel)
+ gc->reg_writel(val, gc->reg_base + reg_offset);
+ else
+ writel(val, gc->reg_base + reg_offset);
+}
+
+static inline u32 irq_reg_readl(struct irq_chip_generic *gc,
+ int reg_offset)
+{
+ if (gc->reg_readl)
+ return gc->reg_readl(gc->reg_base + reg_offset);
+ else
+ return readl(gc->reg_base + reg_offset);
+}
+
#endif /* _LINUX_IRQ_H */
diff --git a/include/linux/irqdomain.h b/include/linux/irqdomain.h
index b0f9d16..676d730 100644
--- a/include/linux/irqdomain.h
+++ b/include/linux/irqdomain.h
@@ -33,11 +33,14 @@
#define _LINUX_IRQDOMAIN_H
#include <linux/types.h>
+#include <linux/irqhandler.h>
#include <linux/radix-tree.h>
struct device_node;
struct irq_domain;
struct of_device_id;
+struct irq_chip;
+struct irq_data;
/* Number of irqs reserved for a legacy isa controller */
#define NUM_ISA_INTERRUPTS 16
@@ -64,6 +67,16 @@ struct irq_domain_ops {
int (*xlate)(struct irq_domain *d, struct device_node *node,
const u32 *intspec, unsigned int intsize,
unsigned long *out_hwirq, unsigned int *out_type);
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ /* extended V2 interfaces to support hierarchy irq_domains */
+ int (*alloc)(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs, void *arg);
+ void (*free)(struct irq_domain *d, unsigned int virq,
+ unsigned int nr_irqs);
+ void (*activate)(struct irq_domain *d, struct irq_data *irq_data);
+ void (*deactivate)(struct irq_domain *d, struct irq_data *irq_data);
+#endif
};
extern struct irq_domain_ops irq_generic_chip_ops;
@@ -77,6 +90,7 @@ struct irq_domain_chip_generic;
* @ops: pointer to irq_domain methods
* @host_data: private data pointer for use by owner. Not touched by irq_domain
* core code.
+ * @flags: host per irq_domain flags
*
* Optional elements
* @of_node: Pointer to device tree nodes associated with the irq_domain. Used
@@ -84,6 +98,7 @@ struct irq_domain_chip_generic;
* @gc: Pointer to a list of generic chips. There is a helper function for
* setting up one or more generic chips for interrupt controllers
* drivers using the generic chip library which uses this pointer.
+ * @parent: Pointer to parent irq_domain to support hierarchy irq_domains
*
* Revmap data, used internally by irq_domain
* @revmap_direct_max_irq: The largest hwirq that can be set for controllers that
@@ -97,10 +112,14 @@ struct irq_domain {
const char *name;
const struct irq_domain_ops *ops;
void *host_data;
+ unsigned int flags;
/* Optional data */
struct device_node *of_node;
struct irq_domain_chip_generic *gc;
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ struct irq_domain *parent;
+#endif
/* reverse map data. The linear map gets appended to the irq_domain */
irq_hw_number_t hwirq_max;
@@ -110,6 +129,22 @@ struct irq_domain {
unsigned int linear_revmap[];
};
+/* Irq domain flags */
+enum {
+ /* Irq domain is hierarchical */
+ IRQ_DOMAIN_FLAG_HIERARCHY = (1 << 0),
+
+ /* Core calls alloc/free recursive through the domain hierarchy. */
+ IRQ_DOMAIN_FLAG_AUTO_RECURSIVE = (1 << 1),
+
+ /*
+ * Flags starting from IRQ_DOMAIN_FLAG_NONCORE are reserved
+ * for implementation specific purposes and ignored by the
+ * core code.
+ */
+ IRQ_DOMAIN_FLAG_NONCORE = (1 << 16),
+};
+
#ifdef CONFIG_IRQ_DOMAIN
struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
irq_hw_number_t hwirq_max, int direct_max,
@@ -220,8 +255,74 @@ int irq_domain_xlate_onetwocell(struct irq_domain *d, struct device_node *ctrlr,
const u32 *intspec, unsigned int intsize,
irq_hw_number_t *out_hwirq, unsigned int *out_type);
+/* V2 interfaces to support hierarchy IRQ domains. */
+extern struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
+ unsigned int virq);
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+extern struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent,
+ unsigned int flags, unsigned int size,
+ struct device_node *node,
+ const struct irq_domain_ops *ops, void *host_data);
+extern int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
+ unsigned int nr_irqs, int node, void *arg,
+ bool realloc);
+extern void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs);
+extern void irq_domain_activate_irq(struct irq_data *irq_data);
+extern void irq_domain_deactivate_irq(struct irq_data *irq_data);
+
+static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
+ unsigned int nr_irqs, int node, void *arg)
+{
+ return __irq_domain_alloc_irqs(domain, -1, nr_irqs, node, arg, false);
+}
+
+extern int irq_domain_set_hwirq_and_chip(struct irq_domain *domain,
+ unsigned int virq,
+ irq_hw_number_t hwirq,
+ struct irq_chip *chip,
+ void *chip_data);
+extern void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+ irq_hw_number_t hwirq, struct irq_chip *chip,
+ void *chip_data, irq_flow_handler_t handler,
+ void *handler_data, const char *handler_name);
+extern void irq_domain_reset_irq_data(struct irq_data *irq_data);
+extern void irq_domain_free_irqs_common(struct irq_domain *domain,
+ unsigned int virq,
+ unsigned int nr_irqs);
+extern void irq_domain_free_irqs_top(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs);
+
+extern int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
+ unsigned int irq_base,
+ unsigned int nr_irqs, void *arg);
+
+extern void irq_domain_free_irqs_parent(struct irq_domain *domain,
+ unsigned int irq_base,
+ unsigned int nr_irqs);
+
+static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_HIERARCHY;
+}
+#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
+static inline void irq_domain_activate_irq(struct irq_data *data) { }
+static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
+static inline int irq_domain_alloc_irqs(struct irq_domain *domain,
+ unsigned int nr_irqs, int node, void *arg)
+{
+ return -1;
+}
+
+static inline bool irq_domain_is_hierarchy(struct irq_domain *domain)
+{
+ return false;
+}
+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
+
#else /* CONFIG_IRQ_DOMAIN */
static inline void irq_dispose_mapping(unsigned int virq) { }
+static inline void irq_domain_activate_irq(struct irq_data *data) { }
+static inline void irq_domain_deactivate_irq(struct irq_data *data) { }
#endif /* !CONFIG_IRQ_DOMAIN */
#endif /* _LINUX_IRQDOMAIN_H */
diff --git a/include/linux/irqhandler.h b/include/linux/irqhandler.h
new file mode 100644
index 0000000..62d5430
--- /dev/null
+++ b/include/linux/irqhandler.h
@@ -0,0 +1,14 @@
+#ifndef _LINUX_IRQHANDLER_H
+#define _LINUX_IRQHANDLER_H
+
+/*
+ * Interrupt flow handler typedefs are defined here to avoid circular
+ * include dependencies.
+ */
+
+struct irq_desc;
+struct irq_data;
+typedef void (*irq_flow_handler_t)(unsigned int irq, struct irq_desc *desc);
+typedef void (*irq_preflow_handler_t)(struct irq_data *data);
+
+#endif
diff --git a/include/linux/kern_levels.h b/include/linux/kern_levels.h
index 866caaa..c2ce155 100644
--- a/include/linux/kern_levels.h
+++ b/include/linux/kern_levels.h
@@ -22,4 +22,17 @@
*/
#define KERN_CONT ""
+/* integer equivalents of KERN_<LEVEL> */
+#define LOGLEVEL_SCHED -2 /* Deferred messages from sched code
+ * are set to this special level */
+#define LOGLEVEL_DEFAULT -1 /* default (or last) loglevel */
+#define LOGLEVEL_EMERG 0 /* system is unusable */
+#define LOGLEVEL_ALERT 1 /* action must be taken immediately */
+#define LOGLEVEL_CRIT 2 /* critical conditions */
+#define LOGLEVEL_ERR 3 /* error conditions */
+#define LOGLEVEL_WARNING 4 /* warning conditions */
+#define LOGLEVEL_NOTICE 5 /* normal but significant condition */
+#define LOGLEVEL_INFO 6 /* informational */
+#define LOGLEVEL_DEBUG 7 /* debug-level messages */
+
#endif
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 3d770f55..233ea81 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -162,6 +162,7 @@ extern int _cond_resched(void);
#endif
#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
+ void ___might_sleep(const char *file, int line, int preempt_offset);
void __might_sleep(const char *file, int line, int preempt_offset);
/**
* might_sleep - annotation for functions that can sleep
@@ -175,10 +176,14 @@ extern int _cond_resched(void);
*/
# define might_sleep() \
do { __might_sleep(__FILE__, __LINE__, 0); might_resched(); } while (0)
+# define sched_annotate_sleep() __set_current_state(TASK_RUNNING)
#else
+ static inline void ___might_sleep(const char *file, int line,
+ int preempt_offset) { }
static inline void __might_sleep(const char *file, int line,
int preempt_offset) { }
# define might_sleep() do { might_resched(); } while (0)
+# define sched_annotate_sleep() do { } while (0)
#endif
#define might_sleep_if(cond) do { if (cond) might_sleep(); } while (0)
@@ -422,6 +427,7 @@ extern int panic_timeout;
extern int panic_on_oops;
extern int panic_on_unrecovered_nmi;
extern int panic_on_io_nmi;
+extern int panic_on_warn;
extern int sysctl_panic_on_stackoverflow;
/*
* Only to be used by arch init code. If the user over-wrote the default
diff --git a/include/linux/leds.h b/include/linux/leds.h
index a57611d..361101f 100644
--- a/include/linux/leds.h
+++ b/include/linux/leds.h
@@ -261,6 +261,7 @@ struct gpio_led {
unsigned retain_state_suspended : 1;
unsigned default_state : 2;
/* default_state should be one of LEDS_GPIO_DEFSTATE_(ON|OFF|KEEP) */
+ struct gpio_desc *gpiod;
};
#define LEDS_GPIO_DEFSTATE_OFF 0
#define LEDS_GPIO_DEFSTATE_ON 1
@@ -273,7 +274,7 @@ struct gpio_led_platform_data {
#define GPIO_LED_NO_BLINK_LOW 0 /* No blink GPIO state low */
#define GPIO_LED_NO_BLINK_HIGH 1 /* No blink GPIO state high */
#define GPIO_LED_BLINK 2 /* Please, blink */
- int (*gpio_blink_set)(unsigned gpio, int state,
+ int (*gpio_blink_set)(struct gpio_desc *desc, int state,
unsigned long *delay_on,
unsigned long *delay_off);
};
diff --git a/include/linux/libata.h b/include/linux/libata.h
index bd5fefe..bfbc817 100644
--- a/include/linux/libata.h
+++ b/include/linux/libata.h
@@ -1191,9 +1191,9 @@ extern void ata_scsi_unlock_native_capacity(struct scsi_device *sdev);
extern int ata_scsi_slave_config(struct scsi_device *sdev);
extern void ata_scsi_slave_destroy(struct scsi_device *sdev);
extern int ata_scsi_change_queue_depth(struct scsi_device *sdev,
- int queue_depth, int reason);
+ int queue_depth);
extern int __ata_change_queue_depth(struct ata_port *ap, struct scsi_device *sdev,
- int queue_depth, int reason);
+ int queue_depth);
extern struct ata_device *ata_dev_pair(struct ata_device *adev);
extern int ata_do_set_mode(struct ata_link *link, struct ata_device **r_failed_dev);
extern void ata_scsi_port_error_handler(struct Scsi_Host *host, struct ata_port *ap);
diff --git a/include/linux/lockd/debug.h b/include/linux/lockd/debug.h
index 257d377..0ca8109 100644
--- a/include/linux/lockd/debug.h
+++ b/include/linux/lockd/debug.h
@@ -17,12 +17,8 @@
* Enable lockd debugging.
* Requires RPC_DEBUG.
*/
-#ifdef RPC_DEBUG
-# define LOCKD_DEBUG 1
-#endif
-
#undef ifdebug
-#if defined(RPC_DEBUG) && defined(LOCKD_DEBUG)
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define ifdebug(flag) if (unlikely(nlm_debug & NLMDBG_##flag))
#else
# define ifdebug(flag) if (0)
diff --git a/include/linux/mailbox_client.h b/include/linux/mailbox_client.h
index 307d9ca..1726ccb 100644
--- a/include/linux/mailbox_client.h
+++ b/include/linux/mailbox_client.h
@@ -25,6 +25,8 @@ struct mbox_chan;
* if the client receives some ACK packet for transmission.
* Unused if the controller already has TX_Done/RTR IRQ.
* @rx_callback: Atomic callback to provide client the data received
+ * @tx_prepare: Atomic callback to ask client to prepare the payload
+ * before initiating the transmission if required.
* @tx_done: Atomic callback to tell client of data transmission
*/
struct mbox_client {
@@ -34,6 +36,7 @@ struct mbox_client {
bool knows_txdone;
void (*rx_callback)(struct mbox_client *cl, void *mssg);
+ void (*tx_prepare)(struct mbox_client *cl, void *mssg);
void (*tx_done)(struct mbox_client *cl, void *mssg, int r);
};
diff --git a/include/linux/mbus.h b/include/linux/mbus.h
index 550c88f..611b69f 100644
--- a/include/linux/mbus.h
+++ b/include/linux/mbus.h
@@ -61,6 +61,7 @@ static inline const struct mbus_dram_target_info *mv_mbus_dram_info(void)
}
#endif
+int mvebu_mbus_save_cpu_target(u32 *store_addr);
void mvebu_mbus_get_pcie_mem_aperture(struct resource *res);
void mvebu_mbus_get_pcie_io_aperture(struct resource *res);
int mvebu_mbus_add_window_remap_by_id(unsigned int target,
diff --git a/include/linux/memcontrol.h b/include/linux/memcontrol.h
index 6b75640..6ea9f91 100644
--- a/include/linux/memcontrol.h
+++ b/include/linux/memcontrol.h
@@ -25,7 +25,6 @@
#include <linux/jump_label.h>
struct mem_cgroup;
-struct page_cgroup;
struct page;
struct mm_struct;
struct kmem_cache;
@@ -68,10 +67,9 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage,
struct lruvec *mem_cgroup_zone_lruvec(struct zone *, struct mem_cgroup *);
struct lruvec *mem_cgroup_page_lruvec(struct page *, struct zone *);
-bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
- struct mem_cgroup *memcg);
-bool task_in_mem_cgroup(struct task_struct *task,
- const struct mem_cgroup *memcg);
+bool mem_cgroup_is_descendant(struct mem_cgroup *memcg,
+ struct mem_cgroup *root);
+bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg);
extern struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page);
extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
@@ -79,15 +77,16 @@ extern struct mem_cgroup *mem_cgroup_from_task(struct task_struct *p);
extern struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg);
extern struct mem_cgroup *mem_cgroup_from_css(struct cgroup_subsys_state *css);
-static inline
-bool mm_match_cgroup(const struct mm_struct *mm, const struct mem_cgroup *memcg)
+static inline bool mm_match_cgroup(struct mm_struct *mm,
+ struct mem_cgroup *memcg)
{
struct mem_cgroup *task_memcg;
- bool match;
+ bool match = false;
rcu_read_lock();
task_memcg = mem_cgroup_from_task(rcu_dereference(mm->owner));
- match = __mem_cgroup_same_or_subtree(memcg, task_memcg);
+ if (task_memcg)
+ match = mem_cgroup_is_descendant(task_memcg, memcg);
rcu_read_unlock();
return match;
}
@@ -141,8 +140,8 @@ static inline bool mem_cgroup_disabled(void)
struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page, bool *locked,
unsigned long *flags);
-void mem_cgroup_end_page_stat(struct mem_cgroup *memcg, bool locked,
- unsigned long flags);
+void mem_cgroup_end_page_stat(struct mem_cgroup *memcg, bool *locked,
+ unsigned long *flags);
void mem_cgroup_update_page_stat(struct mem_cgroup *memcg,
enum mem_cgroup_stat_index idx, int val);
@@ -174,10 +173,6 @@ static inline void mem_cgroup_count_vm_event(struct mm_struct *mm,
void mem_cgroup_split_huge_fixup(struct page *head);
#endif
-#ifdef CONFIG_DEBUG_VM
-bool mem_cgroup_bad_page_check(struct page *page);
-void mem_cgroup_print_bad_page(struct page *page);
-#endif
#else /* CONFIG_MEMCG */
struct mem_cgroup;
@@ -297,7 +292,7 @@ static inline struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page,
}
static inline void mem_cgroup_end_page_stat(struct mem_cgroup *memcg,
- bool locked, unsigned long flags)
+ bool *locked, unsigned long *flags)
{
}
@@ -347,19 +342,6 @@ void mem_cgroup_count_vm_event(struct mm_struct *mm, enum vm_event_item idx)
}
#endif /* CONFIG_MEMCG */
-#if !defined(CONFIG_MEMCG) || !defined(CONFIG_DEBUG_VM)
-static inline bool
-mem_cgroup_bad_page_check(struct page *page)
-{
- return false;
-}
-
-static inline void
-mem_cgroup_print_bad_page(struct page *page)
-{
-}
-#endif
-
enum {
UNDER_LIMIT,
SOFT_LIMIT,
@@ -447,9 +429,8 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order)
/*
* __GFP_NOFAIL allocations will move on even if charging is not
* possible. Therefore we don't even try, and have this allocation
- * unaccounted. We could in theory charge it with
- * res_counter_charge_nofail, but we hope those allocations are rare,
- * and won't be worth the trouble.
+ * unaccounted. We could in theory charge it forcibly, but we hope
+ * those allocations are rare, and won't be worth the trouble.
*/
if (gfp & __GFP_NOFAIL)
return true;
@@ -467,8 +448,6 @@ memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **memcg, int order)
* memcg_kmem_uncharge_pages: uncharge pages from memcg
* @page: pointer to struct page being freed
* @order: allocation order.
- *
- * there is no need to specify memcg here, since it is embedded in page_cgroup
*/
static inline void
memcg_kmem_uncharge_pages(struct page *page, int order)
@@ -485,8 +464,7 @@ memcg_kmem_uncharge_pages(struct page *page, int order)
*
* Needs to be called after memcg_kmem_newpage_charge, regardless of success or
* failure of the allocation. if @page is NULL, this function will revert the
- * charges. Otherwise, it will commit the memcg given by @memcg to the
- * corresponding page_cgroup.
+ * charges. Otherwise, it will commit @page to @memcg.
*/
static inline void
memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg, int order)
diff --git a/include/linux/mfd/abx500/ab8500-sysctrl.h b/include/linux/mfd/abx500/ab8500-sysctrl.h
index adba89d..6893127 100644
--- a/include/linux/mfd/abx500/ab8500-sysctrl.h
+++ b/include/linux/mfd/abx500/ab8500-sysctrl.h
@@ -12,7 +12,6 @@
int ab8500_sysctrl_read(u16 reg, u8 *value);
int ab8500_sysctrl_write(u16 reg, u8 mask, u8 value);
-void ab8500_restart(char mode, const char *cmd);
#else
diff --git a/include/linux/mfd/arizona/core.h b/include/linux/mfd/arizona/core.h
index f34723f..910e3aa 100644
--- a/include/linux/mfd/arizona/core.h
+++ b/include/linux/mfd/arizona/core.h
@@ -141,6 +141,7 @@ struct arizona {
uint16_t dac_comp_coeff;
uint8_t dac_comp_enabled;
+ struct mutex dac_comp_lock;
};
int arizona_clk32k_enable(struct arizona *arizona);
diff --git a/include/linux/mfd/arizona/registers.h b/include/linux/mfd/arizona/registers.h
index c0b075f..aacc10d 100644
--- a/include/linux/mfd/arizona/registers.h
+++ b/include/linux/mfd/arizona/registers.h
@@ -125,6 +125,8 @@
#define ARIZONA_MIC_BIAS_CTRL_1 0x218
#define ARIZONA_MIC_BIAS_CTRL_2 0x219
#define ARIZONA_MIC_BIAS_CTRL_3 0x21A
+#define ARIZONA_HP_CTRL_1L 0x225
+#define ARIZONA_HP_CTRL_1R 0x226
#define ARIZONA_ACCESSORY_DETECT_MODE_1 0x293
#define ARIZONA_HEADPHONE_DETECT_1 0x29B
#define ARIZONA_HEADPHONE_DETECT_2 0x29C
@@ -279,8 +281,16 @@
#define ARIZONA_AIF2_FRAME_CTRL_2 0x548
#define ARIZONA_AIF2_FRAME_CTRL_3 0x549
#define ARIZONA_AIF2_FRAME_CTRL_4 0x54A
+#define ARIZONA_AIF2_FRAME_CTRL_5 0x54B
+#define ARIZONA_AIF2_FRAME_CTRL_6 0x54C
+#define ARIZONA_AIF2_FRAME_CTRL_7 0x54D
+#define ARIZONA_AIF2_FRAME_CTRL_8 0x54E
#define ARIZONA_AIF2_FRAME_CTRL_11 0x551
#define ARIZONA_AIF2_FRAME_CTRL_12 0x552
+#define ARIZONA_AIF2_FRAME_CTRL_13 0x553
+#define ARIZONA_AIF2_FRAME_CTRL_14 0x554
+#define ARIZONA_AIF2_FRAME_CTRL_15 0x555
+#define ARIZONA_AIF2_FRAME_CTRL_16 0x556
#define ARIZONA_AIF2_TX_ENABLES 0x559
#define ARIZONA_AIF2_RX_ENABLES 0x55A
#define ARIZONA_AIF2_FORCE_WRITE 0x55B
@@ -2245,6 +2255,46 @@
#define ARIZONA_MICB3_ENA_WIDTH 1 /* MICB3_ENA */
/*
+ * R549 (0x225) - HP Ctrl 1L
+ */
+#define ARIZONA_RMV_SHRT_HP1L 0x4000 /* RMV_SHRT_HP1L */
+#define ARIZONA_RMV_SHRT_HP1L_MASK 0x4000 /* RMV_SHRT_HP1L */
+#define ARIZONA_RMV_SHRT_HP1L_SHIFT 14 /* RMV_SHRT_HP1L */
+#define ARIZONA_RMV_SHRT_HP1L_WIDTH 1 /* RMV_SHRT_HP1L */
+#define ARIZONA_HP1L_FLWR 0x0004 /* HP1L_FLWR */
+#define ARIZONA_HP1L_FLWR_MASK 0x0004 /* HP1L_FLWR */
+#define ARIZONA_HP1L_FLWR_SHIFT 2 /* HP1L_FLWR */
+#define ARIZONA_HP1L_FLWR_WIDTH 1 /* HP1L_FLWR */
+#define ARIZONA_HP1L_SHRTI 0x0002 /* HP1L_SHRTI */
+#define ARIZONA_HP1L_SHRTI_MASK 0x0002 /* HP1L_SHRTI */
+#define ARIZONA_HP1L_SHRTI_SHIFT 1 /* HP1L_SHRTI */
+#define ARIZONA_HP1L_SHRTI_WIDTH 1 /* HP1L_SHRTI */
+#define ARIZONA_HP1L_SHRTO 0x0001 /* HP1L_SHRTO */
+#define ARIZONA_HP1L_SHRTO_MASK 0x0001 /* HP1L_SHRTO */
+#define ARIZONA_HP1L_SHRTO_SHIFT 0 /* HP1L_SHRTO */
+#define ARIZONA_HP1L_SHRTO_WIDTH 1 /* HP1L_SHRTO */
+
+/*
+ * R550 (0x226) - HP Ctrl 1R
+ */
+#define ARIZONA_RMV_SHRT_HP1R 0x4000 /* RMV_SHRT_HP1R */
+#define ARIZONA_RMV_SHRT_HP1R_MASK 0x4000 /* RMV_SHRT_HP1R */
+#define ARIZONA_RMV_SHRT_HP1R_SHIFT 14 /* RMV_SHRT_HP1R */
+#define ARIZONA_RMV_SHRT_HP1R_WIDTH 1 /* RMV_SHRT_HP1R */
+#define ARIZONA_HP1R_FLWR 0x0004 /* HP1R_FLWR */
+#define ARIZONA_HP1R_FLWR_MASK 0x0004 /* HP1R_FLWR */
+#define ARIZONA_HP1R_FLWR_SHIFT 2 /* HP1R_FLWR */
+#define ARIZONA_HP1R_FLWR_WIDTH 1 /* HP1R_FLWR */
+#define ARIZONA_HP1R_SHRTI 0x0002 /* HP1R_SHRTI */
+#define ARIZONA_HP1R_SHRTI_MASK 0x0002 /* HP1R_SHRTI */
+#define ARIZONA_HP1R_SHRTI_SHIFT 1 /* HP1R_SHRTI */
+#define ARIZONA_HP1R_SHRTI_WIDTH 1 /* HP1R_SHRTI */
+#define ARIZONA_HP1R_SHRTO 0x0001 /* HP1R_SHRTO */
+#define ARIZONA_HP1R_SHRTO_MASK 0x0001 /* HP1R_SHRTO */
+#define ARIZONA_HP1R_SHRTO_SHIFT 0 /* HP1R_SHRTO */
+#define ARIZONA_HP1R_SHRTO_WIDTH 1 /* HP1R_SHRTO */
+
+/*
* R659 (0x293) - Accessory Detect Mode 1
*/
#define ARIZONA_ACCDET_SRC 0x2000 /* ACCDET_SRC */
diff --git a/include/linux/mfd/atmel-hlcdc.h b/include/linux/mfd/atmel-hlcdc.h
new file mode 100644
index 0000000..1279ab1
--- /dev/null
+++ b/include/linux/mfd/atmel-hlcdc.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2014 Free Electrons
+ * Copyright (C) 2014 Atmel
+ *
+ * Author: Boris BREZILLON <boris.brezillon@free-electrons.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License 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 __LINUX_MFD_HLCDC_H
+#define __LINUX_MFD_HLCDC_H
+
+#include <linux/clk.h>
+#include <linux/regmap.h>
+
+#define ATMEL_HLCDC_CFG(i) ((i) * 0x4)
+#define ATMEL_HLCDC_SIG_CFG LCDCFG(5)
+#define ATMEL_HLCDC_HSPOL BIT(0)
+#define ATMEL_HLCDC_VSPOL BIT(1)
+#define ATMEL_HLCDC_VSPDLYS BIT(2)
+#define ATMEL_HLCDC_VSPDLYE BIT(3)
+#define ATMEL_HLCDC_DISPPOL BIT(4)
+#define ATMEL_HLCDC_DITHER BIT(6)
+#define ATMEL_HLCDC_DISPDLY BIT(7)
+#define ATMEL_HLCDC_MODE_MASK GENMASK(9, 8)
+#define ATMEL_HLCDC_PP BIT(10)
+#define ATMEL_HLCDC_VSPSU BIT(12)
+#define ATMEL_HLCDC_VSPHO BIT(13)
+#define ATMEL_HLCDC_GUARDTIME_MASK GENMASK(20, 16)
+
+#define ATMEL_HLCDC_EN 0x20
+#define ATMEL_HLCDC_DIS 0x24
+#define ATMEL_HLCDC_SR 0x28
+#define ATMEL_HLCDC_IER 0x2c
+#define ATMEL_HLCDC_IDR 0x30
+#define ATMEL_HLCDC_IMR 0x34
+#define ATMEL_HLCDC_ISR 0x38
+
+#define ATMEL_HLCDC_CLKPOL BIT(0)
+#define ATMEL_HLCDC_CLKSEL BIT(2)
+#define ATMEL_HLCDC_CLKPWMSEL BIT(3)
+#define ATMEL_HLCDC_CGDIS(i) BIT(8 + (i))
+#define ATMEL_HLCDC_CLKDIV_SHFT 16
+#define ATMEL_HLCDC_CLKDIV_MASK GENMASK(23, 16)
+#define ATMEL_HLCDC_CLKDIV(div) ((div - 2) << ATMEL_HLCDC_CLKDIV_SHFT)
+
+#define ATMEL_HLCDC_PIXEL_CLK BIT(0)
+#define ATMEL_HLCDC_SYNC BIT(1)
+#define ATMEL_HLCDC_DISP BIT(2)
+#define ATMEL_HLCDC_PWM BIT(3)
+#define ATMEL_HLCDC_SIP BIT(4)
+
+#define ATMEL_HLCDC_SOF BIT(0)
+#define ATMEL_HLCDC_SYNCDIS BIT(1)
+#define ATMEL_HLCDC_FIFOERR BIT(4)
+#define ATMEL_HLCDC_LAYER_STATUS(x) BIT((x) + 8)
+
+/**
+ * Structure shared by the MFD device and its subdevices.
+ *
+ * @regmap: register map used to access HLCDC IP registers
+ * @periph_clk: the hlcdc peripheral clock
+ * @sys_clk: the hlcdc system clock
+ * @slow_clk: the system slow clk
+ * @irq: the hlcdc irq
+ */
+struct atmel_hlcdc {
+ struct regmap *regmap;
+ struct clk *periph_clk;
+ struct clk *sys_clk;
+ struct clk *slow_clk;
+ int irq;
+};
+
+#endif /* __LINUX_MFD_HLCDC_H */
diff --git a/include/linux/mfd/axp20x.h b/include/linux/mfd/axp20x.h
index d0e31a2..81589d1 100644
--- a/include/linux/mfd/axp20x.h
+++ b/include/linux/mfd/axp20x.h
@@ -14,6 +14,8 @@
enum {
AXP202_ID = 0,
AXP209_ID,
+ AXP288_ID,
+ NR_AXP20X_VARIANTS,
};
#define AXP20X_DATACACHE(m) (0x04 + (m))
@@ -49,11 +51,13 @@ enum {
#define AXP20X_IRQ3_EN 0x42
#define AXP20X_IRQ4_EN 0x43
#define AXP20X_IRQ5_EN 0x44
+#define AXP20X_IRQ6_EN 0x45
#define AXP20X_IRQ1_STATE 0x48
#define AXP20X_IRQ2_STATE 0x49
#define AXP20X_IRQ3_STATE 0x4a
#define AXP20X_IRQ4_STATE 0x4b
#define AXP20X_IRQ5_STATE 0x4c
+#define AXP20X_IRQ6_STATE 0x4d
/* ADC */
#define AXP20X_ACIN_V_ADC_H 0x56
@@ -116,6 +120,15 @@ enum {
#define AXP20X_CC_CTRL 0xb8
#define AXP20X_FG_RES 0xb9
+/* AXP288 specific registers */
+#define AXP288_PMIC_ADC_H 0x56
+#define AXP288_PMIC_ADC_L 0x57
+#define AXP288_ADC_TS_PIN_CTRL 0x84
+
+#define AXP288_PMIC_ADC_EN 0x84
+#define AXP288_FG_TUNE5 0xed
+
+
/* Regulators IDs */
enum {
AXP20X_LDO1 = 0,
@@ -169,12 +182,58 @@ enum {
AXP20X_IRQ_GPIO0_INPUT,
};
+enum axp288_irqs {
+ AXP288_IRQ_VBUS_FALL = 2,
+ AXP288_IRQ_VBUS_RISE,
+ AXP288_IRQ_OV,
+ AXP288_IRQ_FALLING_ALT,
+ AXP288_IRQ_RISING_ALT,
+ AXP288_IRQ_OV_ALT,
+ AXP288_IRQ_DONE = 10,
+ AXP288_IRQ_CHARGING,
+ AXP288_IRQ_SAFE_QUIT,
+ AXP288_IRQ_SAFE_ENTER,
+ AXP288_IRQ_ABSENT,
+ AXP288_IRQ_APPEND,
+ AXP288_IRQ_QWBTU,
+ AXP288_IRQ_WBTU,
+ AXP288_IRQ_QWBTO,
+ AXP288_IRQ_WBTO,
+ AXP288_IRQ_QCBTU,
+ AXP288_IRQ_CBTU,
+ AXP288_IRQ_QCBTO,
+ AXP288_IRQ_CBTO,
+ AXP288_IRQ_WL2,
+ AXP288_IRQ_WL1,
+ AXP288_IRQ_GPADC,
+ AXP288_IRQ_OT = 31,
+ AXP288_IRQ_GPIO0,
+ AXP288_IRQ_GPIO1,
+ AXP288_IRQ_POKO,
+ AXP288_IRQ_POKL,
+ AXP288_IRQ_POKS,
+ AXP288_IRQ_POKN,
+ AXP288_IRQ_POKP,
+ AXP288_IRQ_TIMER,
+ AXP288_IRQ_MV_CHNG,
+ AXP288_IRQ_BC_USB_CHNG,
+};
+
+#define AXP288_TS_ADC_H 0x58
+#define AXP288_TS_ADC_L 0x59
+#define AXP288_GP_ADC_H 0x5a
+#define AXP288_GP_ADC_L 0x5b
+
struct axp20x_dev {
struct device *dev;
struct i2c_client *i2c_client;
struct regmap *regmap;
struct regmap_irq_chip_data *regmap_irqc;
long variant;
+ int nr_cells;
+ struct mfd_cell *cells;
+ const struct regmap_config *regmap_cfg;
+ const struct regmap_irq_chip *regmap_irq_chip;
};
#endif /* __LINUX_MFD_AXP20X_H */
diff --git a/include/linux/mfd/core.h b/include/linux/mfd/core.h
index 73e1709..a76bc10 100644
--- a/include/linux/mfd/core.h
+++ b/include/linux/mfd/core.h
@@ -111,6 +111,13 @@ extern int mfd_add_devices(struct device *parent, int id,
struct resource *mem_base,
int irq_base, struct irq_domain *irq_domain);
+static inline int mfd_add_hotplug_devices(struct device *parent,
+ const struct mfd_cell *cells, int n_devs)
+{
+ return mfd_add_devices(parent, PLATFORM_DEVID_AUTO, cells, n_devs,
+ NULL, 0, NULL);
+}
+
extern void mfd_remove_devices(struct device *parent);
#endif
diff --git a/include/linux/mfd/davinci_voicecodec.h b/include/linux/mfd/davinci_voicecodec.h
index cb01496..8e1cdbe 100644
--- a/include/linux/mfd/davinci_voicecodec.h
+++ b/include/linux/mfd/davinci_voicecodec.h
@@ -99,12 +99,6 @@ struct davinci_vcif {
dma_addr_t dma_rx_addr;
};
-struct cq93vc {
- struct platform_device *pdev;
- struct snd_soc_codec *codec;
- u32 sysclk;
-};
-
struct davinci_vc;
struct davinci_vc {
@@ -122,7 +116,6 @@ struct davinci_vc {
/* Client devices */
struct davinci_vcif davinci_vcif;
- struct cq93vc cq93vc;
};
#endif
diff --git a/include/linux/mfd/dln2.h b/include/linux/mfd/dln2.h
new file mode 100644
index 0000000..004b245
--- /dev/null
+++ b/include/linux/mfd/dln2.h
@@ -0,0 +1,103 @@
+#ifndef __LINUX_USB_DLN2_H
+#define __LINUX_USB_DLN2_H
+
+#define DLN2_CMD(cmd, id) ((cmd) | ((id) << 8))
+
+struct dln2_platform_data {
+ u16 handle; /* sub-driver handle (internally used only) */
+ u8 port; /* I2C/SPI port */
+};
+
+/**
+ * dln2_event_cb_t - event callback function signature
+ *
+ * @pdev - the sub-device that registered this callback
+ * @echo - the echo header field received in the message
+ * @data - the data payload
+ * @len - the data payload length
+ *
+ * The callback function is called in interrupt context and the data payload is
+ * only valid during the call. If the user needs later access of the data, it
+ * must copy it.
+ */
+
+typedef void (*dln2_event_cb_t)(struct platform_device *pdev, u16 echo,
+ const void *data, int len);
+
+/**
+ * dl2n_register_event_cb - register a callback function for an event
+ *
+ * @pdev - the sub-device that registers the callback
+ * @event - the event for which to register a callback
+ * @event_cb - the callback function
+ *
+ * @return 0 in case of success, negative value in case of error
+ */
+int dln2_register_event_cb(struct platform_device *pdev, u16 event,
+ dln2_event_cb_t event_cb);
+
+/**
+ * dln2_unregister_event_cb - unregister the callback function for an event
+ *
+ * @pdev - the sub-device that registered the callback
+ * @event - the event for which to register a callback
+ */
+void dln2_unregister_event_cb(struct platform_device *pdev, u16 event);
+
+/**
+ * dln2_transfer - issue a DLN2 command and wait for a response and the
+ * associated data
+ *
+ * @pdev - the sub-device which is issuing this transfer
+ * @cmd - the command to be sent to the device
+ * @obuf - the buffer to be sent to the device; it can be NULL if the user
+ * doesn't need to transmit data with this command
+ * @obuf_len - the size of the buffer to be sent to the device
+ * @ibuf - any data associated with the response will be copied here; it can be
+ * NULL if the user doesn't need the response data
+ * @ibuf_len - must be initialized to the input buffer size; it will be modified
+ * to indicate the actual data transferred;
+ *
+ * @return 0 for success, negative value for errors
+ */
+int dln2_transfer(struct platform_device *pdev, u16 cmd,
+ const void *obuf, unsigned obuf_len,
+ void *ibuf, unsigned *ibuf_len);
+
+/**
+ * dln2_transfer_rx - variant of @dln2_transfer() where TX buffer is not needed
+ *
+ * @pdev - the sub-device which is issuing this transfer
+ * @cmd - the command to be sent to the device
+ * @ibuf - any data associated with the response will be copied here; it can be
+ * NULL if the user doesn't need the response data
+ * @ibuf_len - must be initialized to the input buffer size; it will be modified
+ * to indicate the actual data transferred;
+ *
+ * @return 0 for success, negative value for errors
+ */
+
+static inline int dln2_transfer_rx(struct platform_device *pdev, u16 cmd,
+ void *ibuf, unsigned *ibuf_len)
+{
+ return dln2_transfer(pdev, cmd, NULL, 0, ibuf, ibuf_len);
+}
+
+/**
+ * dln2_transfer_tx - variant of @dln2_transfer() where RX buffer is not needed
+ *
+ * @pdev - the sub-device which is issuing this transfer
+ * @cmd - the command to be sent to the device
+ * @obuf - the buffer to be sent to the device; it can be NULL if the
+ * user doesn't need to transmit data with this command
+ * @obuf_len - the size of the buffer to be sent to the device
+ *
+ * @return 0 for success, negative value for errors
+ */
+static inline int dln2_transfer_tx(struct platform_device *pdev, u16 cmd,
+ const void *obuf, unsigned obuf_len)
+{
+ return dln2_transfer(pdev, cmd, obuf, obuf_len, NULL, NULL);
+}
+
+#endif
diff --git a/include/linux/mfd/max77686.h b/include/linux/mfd/max77686.h
index 7e6dc4b..553f7d0 100644
--- a/include/linux/mfd/max77686.h
+++ b/include/linux/mfd/max77686.h
@@ -131,13 +131,6 @@ enum max77686_opmode {
MAX77686_OPMODE_STANDBY,
};
-enum max77802_opmode {
- MAX77802_OPMODE_OFF,
- MAX77802_OPMODE_STANDBY,
- MAX77802_OPMODE_LP,
- MAX77802_OPMODE_NORMAL,
-};
-
struct max77686_opmode_data {
int id;
int mode;
diff --git a/include/linux/mfd/max77693-private.h b/include/linux/mfd/max77693-private.h
index 582e67f..08dae01 100644
--- a/include/linux/mfd/max77693-private.h
+++ b/include/linux/mfd/max77693-private.h
@@ -26,7 +26,6 @@
#include <linux/i2c.h>
-#define MAX77693_NUM_IRQ_MUIC_REGS 3
#define MAX77693_REG_INVALID (0xff)
/* Slave addr = 0xCC: PMIC, Charger, Flash LED */
diff --git a/include/linux/mfd/rtsx_pci.h b/include/linux/mfd/rtsx_pci.h
index 74346d5..0c12628 100644
--- a/include/linux/mfd/rtsx_pci.h
+++ b/include/linux/mfd/rtsx_pci.h
@@ -558,6 +558,7 @@
#define SD_SAMPLE_POINT_CTL 0xFDA7
#define SD_PUSH_POINT_CTL 0xFDA8
#define SD_CMD0 0xFDA9
+#define SD_CMD_START 0x40
#define SD_CMD1 0xFDAA
#define SD_CMD2 0xFDAB
#define SD_CMD3 0xFDAC
@@ -707,6 +708,14 @@
#define PM_CTRL1 0xFF44
#define PM_CTRL2 0xFF45
#define PM_CTRL3 0xFF46
+#define SDIO_SEND_PME_EN 0x80
+#define FORCE_RC_MODE_ON 0x40
+#define FORCE_RX50_LINK_ON 0x20
+#define D3_DELINK_MODE_EN 0x10
+#define USE_PESRTB_CTL_DELINK 0x08
+#define DELAY_PIN_WAKE 0x04
+#define RESET_PIN_WAKE 0x02
+#define PM_WAKE_EN 0x01
#define PM_CTRL4 0xFF47
/* Memory mapping */
@@ -752,6 +761,14 @@
#define PHY_DUM_REG 0x1F
#define LCTLR 0x80
+#define LCTLR_EXT_SYNC 0x80
+#define LCTLR_COMMON_CLOCK_CFG 0x40
+#define LCTLR_RETRAIN_LINK 0x20
+#define LCTLR_LINK_DISABLE 0x10
+#define LCTLR_RCB 0x08
+#define LCTLR_RESERVED 0x04
+#define LCTLR_ASPM_CTL_MASK 0x03
+
#define PCR_SETTING_REG1 0x724
#define PCR_SETTING_REG2 0x814
#define PCR_SETTING_REG3 0x747
@@ -967,4 +984,24 @@ static inline u8 *rtsx_pci_get_cmd_data(struct rtsx_pcr *pcr)
return (u8 *)(pcr->host_cmds_ptr);
}
+static inline int rtsx_pci_update_cfg_byte(struct rtsx_pcr *pcr, int addr,
+ u8 mask, u8 append)
+{
+ int err;
+ u8 val;
+
+ err = pci_read_config_byte(pcr->pci, addr, &val);
+ if (err < 0)
+ return err;
+ return pci_write_config_byte(pcr->pci, addr, (val & mask) | append);
+}
+
+static inline void rtsx_pci_write_be32(struct rtsx_pcr *pcr, u16 reg, u32 val)
+{
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg, 0xFF, val >> 24);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 1, 0xFF, val >> 16);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 2, 0xFF, val >> 8);
+ rtsx_pci_add_cmd(pcr, WRITE_REG_CMD, reg + 3, 0xFF, val);
+}
+
#endif
diff --git a/include/linux/mfd/samsung/core.h b/include/linux/mfd/samsung/core.h
index 1825eda..3fdb7cfb 100644
--- a/include/linux/mfd/samsung/core.h
+++ b/include/linux/mfd/samsung/core.h
@@ -28,6 +28,7 @@
#define MIN_800_MV 800000
#define MIN_750_MV 750000
#define MIN_600_MV 600000
+#define MIN_500_MV 500000
/* Macros to represent steps for LDO/BUCK */
#define STEP_50_MV 50000
@@ -41,6 +42,7 @@ enum sec_device_type {
S5M8767X,
S2MPA01,
S2MPS11X,
+ S2MPS13X,
S2MPS14X,
S2MPU02,
};
diff --git a/include/linux/mfd/samsung/s2mps13.h b/include/linux/mfd/samsung/s2mps13.h
new file mode 100644
index 0000000..ce5dda8
--- /dev/null
+++ b/include/linux/mfd/samsung/s2mps13.h
@@ -0,0 +1,186 @@
+/*
+ * s2mps13.h
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd
+ * http://www.samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifndef __LINUX_MFD_S2MPS13_H
+#define __LINUX_MFD_S2MPS13_H
+
+/* S2MPS13 registers */
+enum s2mps13_reg {
+ S2MPS13_REG_ID,
+ S2MPS13_REG_INT1,
+ S2MPS13_REG_INT2,
+ S2MPS13_REG_INT3,
+ S2MPS13_REG_INT1M,
+ S2MPS13_REG_INT2M,
+ S2MPS13_REG_INT3M,
+ S2MPS13_REG_ST1,
+ S2MPS13_REG_ST2,
+ S2MPS13_REG_PWRONSRC,
+ S2MPS13_REG_OFFSRC,
+ S2MPS13_REG_BU_CHG,
+ S2MPS13_REG_RTCCTRL,
+ S2MPS13_REG_CTRL1,
+ S2MPS13_REG_CTRL2,
+ S2MPS13_REG_RSVD1,
+ S2MPS13_REG_RSVD2,
+ S2MPS13_REG_RSVD3,
+ S2MPS13_REG_RSVD4,
+ S2MPS13_REG_RSVD5,
+ S2MPS13_REG_RSVD6,
+ S2MPS13_REG_CTRL3,
+ S2MPS13_REG_RSVD7,
+ S2MPS13_REG_RSVD8,
+ S2MPS13_REG_WRSTBI,
+ S2MPS13_REG_B1CTRL,
+ S2MPS13_REG_B1OUT,
+ S2MPS13_REG_B2CTRL,
+ S2MPS13_REG_B2OUT,
+ S2MPS13_REG_B3CTRL,
+ S2MPS13_REG_B3OUT,
+ S2MPS13_REG_B4CTRL,
+ S2MPS13_REG_B4OUT,
+ S2MPS13_REG_B5CTRL,
+ S2MPS13_REG_B5OUT,
+ S2MPS13_REG_B6CTRL,
+ S2MPS13_REG_B6OUT,
+ S2MPS13_REG_B7CTRL,
+ S2MPS13_REG_B7OUT,
+ S2MPS13_REG_B8CTRL,
+ S2MPS13_REG_B8OUT,
+ S2MPS13_REG_B9CTRL,
+ S2MPS13_REG_B9OUT,
+ S2MPS13_REG_B10CTRL,
+ S2MPS13_REG_B10OUT,
+ S2MPS13_REG_BB1CTRL,
+ S2MPS13_REG_BB1OUT,
+ S2MPS13_REG_BUCK_RAMP1,
+ S2MPS13_REG_BUCK_RAMP2,
+ S2MPS13_REG_LDO_DVS1,
+ S2MPS13_REG_LDO_DVS2,
+ S2MPS13_REG_LDO_DVS3,
+ S2MPS13_REG_B6OUT2,
+ S2MPS13_REG_L1CTRL,
+ S2MPS13_REG_L2CTRL,
+ S2MPS13_REG_L3CTRL,
+ S2MPS13_REG_L4CTRL,
+ S2MPS13_REG_L5CTRL,
+ S2MPS13_REG_L6CTRL,
+ S2MPS13_REG_L7CTRL,
+ S2MPS13_REG_L8CTRL,
+ S2MPS13_REG_L9CTRL,
+ S2MPS13_REG_L10CTRL,
+ S2MPS13_REG_L11CTRL,
+ S2MPS13_REG_L12CTRL,
+ S2MPS13_REG_L13CTRL,
+ S2MPS13_REG_L14CTRL,
+ S2MPS13_REG_L15CTRL,
+ S2MPS13_REG_L16CTRL,
+ S2MPS13_REG_L17CTRL,
+ S2MPS13_REG_L18CTRL,
+ S2MPS13_REG_L19CTRL,
+ S2MPS13_REG_L20CTRL,
+ S2MPS13_REG_L21CTRL,
+ S2MPS13_REG_L22CTRL,
+ S2MPS13_REG_L23CTRL,
+ S2MPS13_REG_L24CTRL,
+ S2MPS13_REG_L25CTRL,
+ S2MPS13_REG_L26CTRL,
+ S2MPS13_REG_L27CTRL,
+ S2MPS13_REG_L28CTRL,
+ S2MPS13_REG_L30CTRL,
+ S2MPS13_REG_L31CTRL,
+ S2MPS13_REG_L32CTRL,
+ S2MPS13_REG_L33CTRL,
+ S2MPS13_REG_L34CTRL,
+ S2MPS13_REG_L35CTRL,
+ S2MPS13_REG_L36CTRL,
+ S2MPS13_REG_L37CTRL,
+ S2MPS13_REG_L38CTRL,
+ S2MPS13_REG_L39CTRL,
+ S2MPS13_REG_L40CTRL,
+ S2MPS13_REG_LDODSCH1,
+ S2MPS13_REG_LDODSCH2,
+ S2MPS13_REG_LDODSCH3,
+ S2MPS13_REG_LDODSCH4,
+ S2MPS13_REG_LDODSCH5,
+};
+
+/* regulator ids */
+enum s2mps13_regulators {
+ S2MPS13_LDO1,
+ S2MPS13_LDO2,
+ S2MPS13_LDO3,
+ S2MPS13_LDO4,
+ S2MPS13_LDO5,
+ S2MPS13_LDO6,
+ S2MPS13_LDO7,
+ S2MPS13_LDO8,
+ S2MPS13_LDO9,
+ S2MPS13_LDO10,
+ S2MPS13_LDO11,
+ S2MPS13_LDO12,
+ S2MPS13_LDO13,
+ S2MPS13_LDO14,
+ S2MPS13_LDO15,
+ S2MPS13_LDO16,
+ S2MPS13_LDO17,
+ S2MPS13_LDO18,
+ S2MPS13_LDO19,
+ S2MPS13_LDO20,
+ S2MPS13_LDO21,
+ S2MPS13_LDO22,
+ S2MPS13_LDO23,
+ S2MPS13_LDO24,
+ S2MPS13_LDO25,
+ S2MPS13_LDO26,
+ S2MPS13_LDO27,
+ S2MPS13_LDO28,
+ S2MPS13_LDO29,
+ S2MPS13_LDO30,
+ S2MPS13_LDO31,
+ S2MPS13_LDO32,
+ S2MPS13_LDO33,
+ S2MPS13_LDO34,
+ S2MPS13_LDO35,
+ S2MPS13_LDO36,
+ S2MPS13_LDO37,
+ S2MPS13_LDO38,
+ S2MPS13_LDO39,
+ S2MPS13_LDO40,
+ S2MPS13_BUCK1,
+ S2MPS13_BUCK2,
+ S2MPS13_BUCK3,
+ S2MPS13_BUCK4,
+ S2MPS13_BUCK5,
+ S2MPS13_BUCK6,
+ S2MPS13_BUCK7,
+ S2MPS13_BUCK8,
+ S2MPS13_BUCK9,
+ S2MPS13_BUCK10,
+
+ S2MPS13_REGULATOR_MAX,
+};
+
+/*
+ * Default ramp delay in uv/us. Datasheet says that ramp delay can be
+ * controlled however it does not specify which register is used for that.
+ * Let's assume that default value will be set.
+ */
+#define S2MPS13_BUCK_RAMP_DELAY 12500
+
+#endif /* __LINUX_MFD_S2MPS13_H */
diff --git a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
index ff44374..c877cad 100644
--- a/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
+++ b/include/linux/mfd/syscon/imx6q-iomuxc-gpr.h
@@ -395,4 +395,43 @@
#define IMX6SL_GPR1_FEC_CLOCK_MUX1_SEL_MASK (0x3 << 17)
#define IMX6SL_GPR1_FEC_CLOCK_MUX2_SEL_MASK (0x1 << 14)
+/* For imx6sx iomux gpr register field define */
+#define IMX6SX_GPR1_VDEC_SW_RST_MASK (0x1 << 20)
+#define IMX6SX_GPR1_VDEC_SW_RST_RESET (0x1 << 20)
+#define IMX6SX_GPR1_VDEC_SW_RST_RELEASE (0x0 << 20)
+#define IMX6SX_GPR1_VADC_SW_RST_MASK (0x1 << 19)
+#define IMX6SX_GPR1_VADC_SW_RST_RESET (0x1 << 19)
+#define IMX6SX_GPR1_VADC_SW_RST_RELEASE (0x0 << 19)
+#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_MASK (0x3 << 13)
+#define IMX6SX_GPR1_FEC_CLOCK_PAD_DIR_MASK (0x3 << 17)
+#define IMX6SX_GPR1_FEC_CLOCK_MUX_SEL_EXT (0x3 << 13)
+
+#define IMX6SX_GPR4_FEC_ENET1_STOP_REQ (0x1 << 3)
+#define IMX6SX_GPR4_FEC_ENET2_STOP_REQ (0x1 << 4)
+
+#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_MASK (0x1 << 3)
+#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF1 (0x0 << 3)
+#define IMX6SX_GPR5_DISP_MUX_LDB_CTRL_LCDIF2 (0x1 << 3)
+
+#define IMX6SX_GPR5_CSI2_MUX_CTRL_MASK (0x3 << 27)
+#define IMX6SX_GPR5_CSI2_MUX_CTRL_EXT_PIN (0x0 << 27)
+#define IMX6SX_GPR5_CSI2_MUX_CTRL_CVD (0x1 << 27)
+#define IMX6SX_GPR5_CSI2_MUX_CTRL_VDAC_TO_CSI (0x2 << 27)
+#define IMX6SX_GPR5_CSI2_MUX_CTRL_GND (0x3 << 27)
+#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_MASK (0x1 << 26)
+#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_ENABLE (0x1 << 26)
+#define IMX6SX_GPR5_VADC_TO_CSI_CAPTURE_EN_DISABLE (0x0 << 26)
+#define IMX6SX_GPR5_CSI1_MUX_CTRL_MASK (0x3 << 4)
+#define IMX6SX_GPR5_CSI1_MUX_CTRL_EXT_PIN (0x0 << 4)
+#define IMX6SX_GPR5_CSI1_MUX_CTRL_CVD (0x1 << 4)
+#define IMX6SX_GPR5_CSI1_MUX_CTRL_VDAC_TO_CSI (0x2 << 4)
+#define IMX6SX_GPR5_CSI1_MUX_CTRL_GND (0x3 << 4)
+
+#define IMX6SX_GPR5_DISP_MUX_DCIC2_LCDIF2 (0x0 << 2)
+#define IMX6SX_GPR5_DISP_MUX_DCIC2_LVDS (0x1 << 2)
+#define IMX6SX_GPR5_DISP_MUX_DCIC2_MASK (0x1 << 2)
+#define IMX6SX_GPR5_DISP_MUX_DCIC1_LCDIF1 (0x0 << 1)
+#define IMX6SX_GPR5_DISP_MUX_DCIC1_LVDS (0x1 << 1)
+#define IMX6SX_GPR5_DISP_MUX_DCIC1_MASK (0x1 << 1)
+
#endif /* __LINUX_IMX6Q_IOMUXC_GPR_H */
diff --git a/include/linux/mfd/tc3589x.h b/include/linux/mfd/tc3589x.h
index e6088c2..e1c12d8 100644
--- a/include/linux/mfd/tc3589x.h
+++ b/include/linux/mfd/tc3589x.h
@@ -164,13 +164,10 @@ struct tc3589x_keypad_platform_data {
/**
* struct tc3589x_gpio_platform_data - TC3589x GPIO platform data
- * @gpio_base: first gpio number assigned to TC3589x. A maximum of
- * %TC3589x_NR_GPIOS GPIOs will be allocated.
* @setup: callback for board-specific initialization
* @remove: callback for board-specific teardown
*/
struct tc3589x_gpio_platform_data {
- int gpio_base;
void (*setup)(struct tc3589x *tc3589x, unsigned gpio_base);
void (*remove)(struct tc3589x *tc3589x, unsigned gpio_base);
};
@@ -178,18 +175,13 @@ struct tc3589x_gpio_platform_data {
/**
* struct tc3589x_platform_data - TC3589x platform data
* @block: bitmask of blocks to enable (use TC3589x_BLOCK_*)
- * @irq_base: base IRQ number. %TC3589x_NR_IRQS irqs will be used.
* @gpio: GPIO-specific platform data
* @keypad: keypad-specific platform data
*/
struct tc3589x_platform_data {
unsigned int block;
- int irq_base;
struct tc3589x_gpio_platform_data *gpio;
const struct tc3589x_keypad_platform_data *keypad;
};
-#define TC3589x_NR_GPIOS 24
-#define TC3589x_NR_IRQS TC3589x_INT_GPIO(TC3589x_NR_GPIOS)
-
#endif
diff --git a/include/linux/mm.h b/include/linux/mm.h
index b464611..f7606d3 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -128,6 +128,7 @@ extern unsigned int kobjsize(const void *objp);
#define VM_HUGETLB 0x00400000 /* Huge TLB Page VM */
#define VM_NONLINEAR 0x00800000 /* Is non-linear (remap_file_pages) */
#define VM_ARCH_1 0x01000000 /* Architecture-specific flag */
+#define VM_ARCH_2 0x02000000
#define VM_DONTDUMP 0x04000000 /* Do not include in the core dump */
#ifdef CONFIG_MEM_SOFT_DIRTY
@@ -155,6 +156,11 @@ extern unsigned int kobjsize(const void *objp);
# define VM_MAPPED_COPY VM_ARCH_1 /* T if mapped copy of data (nommu mmap) */
#endif
+#if defined(CONFIG_X86)
+/* MPX specific bounds table or bounds directory */
+# define VM_MPX VM_ARCH_2
+#endif
+
#ifndef VM_GROWSUP
# define VM_GROWSUP VM_NONE
#endif
diff --git a/include/linux/mm_types.h b/include/linux/mm_types.h
index 6e0b286..bf9f575 100644
--- a/include/linux/mm_types.h
+++ b/include/linux/mm_types.h
@@ -22,6 +22,7 @@
#define AT_VECTOR_SIZE (2*(AT_VECTOR_SIZE_ARCH + AT_VECTOR_SIZE_BASE + 1))
struct address_space;
+struct mem_cgroup;
#define USE_SPLIT_PTE_PTLOCKS (NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS)
#define USE_SPLIT_PMD_PTLOCKS (USE_SPLIT_PTE_PTLOCKS && \
@@ -167,6 +168,10 @@ struct page {
struct page *first_page; /* Compound tail pages */
};
+#ifdef CONFIG_MEMCG
+ struct mem_cgroup *mem_cgroup;
+#endif
+
/*
* On machines where all RAM is mapped into kernel address space,
* we can simply calculate the virtual address. On machines with
@@ -454,6 +459,10 @@ struct mm_struct {
bool tlb_flush_pending;
#endif
struct uprobes_state uprobes_state;
+#ifdef CONFIG_X86_INTEL_MPX
+ /* address of the bounds directory */
+ void __user *bd_addr;
+#endif
};
static inline void mm_init_cpumask(struct mm_struct *mm)
diff --git a/include/linux/mmc/card.h b/include/linux/mmc/card.h
index b0692d2..4d69c00 100644
--- a/include/linux/mmc/card.h
+++ b/include/linux/mmc/card.h
@@ -88,6 +88,9 @@ struct mmc_ext_csd {
unsigned int data_tag_unit_size; /* DATA TAG UNIT size */
unsigned int boot_ro_lock; /* ro lock support */
bool boot_ro_lockable;
+ bool ffu_capable; /* Firmware upgrade support */
+#define MMC_FIRMWARE_LEN 8
+ u8 fwrev[MMC_FIRMWARE_LEN]; /* FW version */
u8 raw_exception_status; /* 54 */
u8 raw_partition_support; /* 160 */
u8 raw_rpmb_size_mult; /* 168 */
@@ -509,24 +512,8 @@ static inline int mmc_card_broken_irq_polling(const struct mmc_card *c)
#define mmc_dev_to_card(d) container_of(d, struct mmc_card, dev)
-#define mmc_list_to_card(l) container_of(l, struct mmc_card, node)
-#define mmc_get_drvdata(c) dev_get_drvdata(&(c)->dev)
-#define mmc_set_drvdata(c,d) dev_set_drvdata(&(c)->dev, d)
-
-/*
- * MMC device driver (e.g., Flash card, I/O card...)
- */
-struct mmc_driver {
- struct device_driver drv;
- int (*probe)(struct mmc_card *);
- void (*remove)(struct mmc_card *);
- int (*suspend)(struct mmc_card *);
- int (*resume)(struct mmc_card *);
- void (*shutdown)(struct mmc_card *);
-};
-
-extern int mmc_register_driver(struct mmc_driver *);
-extern void mmc_unregister_driver(struct mmc_driver *);
+extern int mmc_register_driver(struct device_driver *);
+extern void mmc_unregister_driver(struct device_driver *);
extern void mmc_fixup_device(struct mmc_card *card,
const struct mmc_fixup *table);
diff --git a/include/linux/mmc/core.h b/include/linux/mmc/core.h
index f206e29..cb2b040 100644
--- a/include/linux/mmc/core.h
+++ b/include/linux/mmc/core.h
@@ -154,7 +154,8 @@ extern void mmc_start_bkops(struct mmc_card *card, bool from_exception);
extern int __mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int, bool,
bool, bool);
extern int mmc_switch(struct mmc_card *, u8, u8, u8, unsigned int);
-extern int mmc_send_ext_csd(struct mmc_card *card, u8 *ext_csd);
+extern int mmc_send_tuning(struct mmc_host *host);
+extern int mmc_get_ext_csd(struct mmc_card *card, u8 **new_ext_csd);
#define MMC_ERASE_ARG 0x00000000
#define MMC_SECURE_ERASE_ARG 0x80000000
diff --git a/include/linux/mmc/dw_mmc.h b/include/linux/mmc/dw_mmc.h
index 0013669..42b724e 100644
--- a/include/linux/mmc/dw_mmc.h
+++ b/include/linux/mmc/dw_mmc.h
@@ -54,6 +54,7 @@ struct mmc_data;
* transfer is in progress.
* @use_dma: Whether DMA channel is initialized or not.
* @using_dma: Whether DMA is in use for the current transfer.
+ * @dma_64bit_address: Whether DMA supports 64-bit address mode or not.
* @sg_dma: Bus address of DMA buffer.
* @sg_cpu: Virtual address of DMA buffer.
* @dma_ops: Pointer to platform-specific DMA callbacks.
@@ -96,6 +97,7 @@ struct mmc_data;
* @quirks: Set of quirks that apply to specific versions of the IP.
* @irq_flags: The flags to be passed to request_irq.
* @irq: The irq value to be passed to request_irq.
+ * @sdio_id0: Number of slot0 in the SDIO interrupt registers.
*
* Locking
* =======
@@ -135,11 +137,11 @@ struct dw_mci {
struct mmc_command stop_abort;
unsigned int prev_blksz;
unsigned char timing;
- struct workqueue_struct *card_workqueue;
/* DMA interface members*/
int use_dma;
int using_dma;
+ int dma_64bit_address;
dma_addr_t sg_dma;
void *sg_cpu;
@@ -154,7 +156,6 @@ struct dw_mci {
u32 stop_cmdr;
u32 dir_status;
struct tasklet_struct tasklet;
- struct work_struct card_work;
unsigned long pending_events;
unsigned long completed_events;
enum dw_mci_state state;
@@ -193,6 +194,8 @@ struct dw_mci {
bool vqmmc_enabled;
unsigned long irq_flags; /* IRQ flags */
int irq;
+
+ int sdio_id0;
};
/* DMA ops for Internal/External DMAC interface */
diff --git a/include/linux/mmc/host.h b/include/linux/mmc/host.h
index df0c153..9f32270 100644
--- a/include/linux/mmc/host.h
+++ b/include/linux/mmc/host.h
@@ -289,6 +289,7 @@ struct mmc_host {
#define MMC_CAP2_HS400_1_2V (1 << 16) /* Can support HS400 1.2V */
#define MMC_CAP2_HS400 (MMC_CAP2_HS400_1_8V | \
MMC_CAP2_HS400_1_2V)
+#define MMC_CAP2_HSX00_1_2V (MMC_CAP2_HS200_1_2V_SDR | MMC_CAP2_HS400_1_2V)
#define MMC_CAP2_SDIO_IRQ_NOTHREAD (1 << 17)
mmc_pm_flag_t pm_caps; /* supported pm features */
diff --git a/include/linux/mmc/mmc.h b/include/linux/mmc/mmc.h
index 1cd00b3..49ad7a9 100644
--- a/include/linux/mmc/mmc.h
+++ b/include/linux/mmc/mmc.h
@@ -296,6 +296,7 @@ struct _mmc_csd {
#define EXT_CSD_SANITIZE_START 165 /* W */
#define EXT_CSD_WR_REL_PARAM 166 /* RO */
#define EXT_CSD_RPMB_MULT 168 /* RO */
+#define EXT_CSD_FW_CONFIG 169 /* R/W */
#define EXT_CSD_BOOT_WP 173 /* R/W */
#define EXT_CSD_ERASE_GROUP_DEF 175 /* R/W */
#define EXT_CSD_PART_CONFIG 179 /* R/W */
@@ -332,6 +333,8 @@ struct _mmc_csd {
#define EXT_CSD_GENERIC_CMD6_TIME 248 /* RO */
#define EXT_CSD_CACHE_SIZE 249 /* RO, 4 bytes */
#define EXT_CSD_PWR_CL_DDR_200_360 253 /* RO */
+#define EXT_CSD_FIRMWARE_VERSION 254 /* RO, 8 bytes */
+#define EXT_CSD_SUPPORTED_MODE 493 /* RO */
#define EXT_CSD_TAG_UNIT_SIZE 498 /* RO */
#define EXT_CSD_DATA_TAG_SUPPORT 499 /* RO */
#define EXT_CSD_MAX_PACKED_WRITES 500 /* RO */
diff --git a/include/linux/mmc/sdhci.h b/include/linux/mmc/sdhci.h
index dba793e..375af80 100644
--- a/include/linux/mmc/sdhci.h
+++ b/include/linux/mmc/sdhci.h
@@ -100,6 +100,12 @@ struct sdhci_host {
#define SDHCI_QUIRK2_BROKEN_DDR50 (1<<7)
/* Stop command (CMD12) can set Transfer Complete when not using MMC_RSP_BUSY */
#define SDHCI_QUIRK2_STOP_WITH_TC (1<<8)
+/* Controller does not support 64-bit DMA */
+#define SDHCI_QUIRK2_BROKEN_64_BIT_DMA (1<<9)
+/* need clear transfer mode register before send cmd */
+#define SDHCI_QUIRK2_CLEAR_TRANSFERMODE_REG_BEFORE_CMD (1<<10)
+/* Capability register bit-63 indicates HS400 support */
+#define SDHCI_QUIRK2_CAPS_BIT63_FOR_HS400 (1<<11)
int irq; /* Device IRQ */
void __iomem *ioaddr; /* Mapped address */
@@ -130,6 +136,7 @@ struct sdhci_host {
#define SDHCI_SDIO_IRQ_ENABLED (1<<9) /* SDIO irq enabled */
#define SDHCI_SDR104_NEEDS_TUNING (1<<10) /* SDR104/HS200 needs tuning */
#define SDHCI_USING_RETUNING_TIMER (1<<11) /* Host is using a retuning timer for the card */
+#define SDHCI_USE_64_BIT_DMA (1<<12) /* Use 64-bit DMA */
unsigned int version; /* SDHCI spec. version */
@@ -155,12 +162,19 @@ struct sdhci_host {
int sg_count; /* Mapped sg entries */
- u8 *adma_desc; /* ADMA descriptor table */
- u8 *align_buffer; /* Bounce buffer */
+ void *adma_table; /* ADMA descriptor table */
+ void *align_buffer; /* Bounce buffer */
+
+ size_t adma_table_sz; /* ADMA descriptor table size */
+ size_t align_buffer_sz; /* Bounce buffer size */
dma_addr_t adma_addr; /* Mapped ADMA descr. table */
dma_addr_t align_addr; /* Mapped bounce buffer */
+ unsigned int desc_sz; /* ADMA descriptor size */
+ unsigned int align_sz; /* ADMA alignment */
+ unsigned int align_mask; /* ADMA alignment mask */
+
struct tasklet_struct finish_tasklet; /* Tasklet structures */
struct timer_list timer; /* Timer for timeouts */
diff --git a/include/linux/mmc/sdio_func.h b/include/linux/mmc/sdio_func.h
index 50f0bc9..aab032a 100644
--- a/include/linux/mmc/sdio_func.h
+++ b/include/linux/mmc/sdio_func.h
@@ -84,8 +84,6 @@ struct sdio_driver {
struct device_driver drv;
};
-#define to_sdio_driver(d) container_of(d, struct sdio_driver, drv)
-
/**
* SDIO_DEVICE - macro used to describe a specific SDIO device
* @vend: the 16 bit manufacturer code
diff --git a/include/linux/mmzone.h b/include/linux/mmzone.h
index ffe66e3..3879d76 100644
--- a/include/linux/mmzone.h
+++ b/include/linux/mmzone.h
@@ -722,9 +722,6 @@ typedef struct pglist_data {
int nr_zones;
#ifdef CONFIG_FLAT_NODE_MEM_MAP /* means !SPARSEMEM */
struct page *node_mem_map;
-#ifdef CONFIG_MEMCG
- struct page_cgroup *node_page_cgroup;
-#endif
#endif
#ifndef CONFIG_NO_BOOTMEM
struct bootmem_data *bdata;
@@ -1078,7 +1075,6 @@ static inline unsigned long early_pfn_to_nid(unsigned long pfn)
#define SECTION_ALIGN_DOWN(pfn) ((pfn) & PAGE_SECTION_MASK)
struct page;
-struct page_cgroup;
struct mem_section {
/*
* This is, logically, a pointer to an array of struct
@@ -1096,14 +1092,6 @@ struct mem_section {
/* See declaration of similar field in struct zone */
unsigned long *pageblock_flags;
-#ifdef CONFIG_MEMCG
- /*
- * If !SPARSEMEM, pgdat doesn't have page_cgroup pointer. We use
- * section. (see memcontrol.h/page_cgroup.h about this.)
- */
- struct page_cgroup *page_cgroup;
- unsigned long pad;
-#endif
/*
* WARNING: mem_section must be a power-of-2 in size for the
* calculation and use of SECTION_ROOT_MASK to make sense.
diff --git a/include/linux/msi.h b/include/linux/msi.h
index 44f4746..8ac4a68 100644
--- a/include/linux/msi.h
+++ b/include/linux/msi.h
@@ -10,17 +10,12 @@ struct msi_msg {
u32 data; /* 16 bits of msi message data */
};
+extern int pci_msi_ignore_mask;
/* Helper functions */
struct irq_data;
struct msi_desc;
-void mask_msi_irq(struct irq_data *data);
-void unmask_msi_irq(struct irq_data *data);
-void __read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
-void read_msi_msg(unsigned int irq, struct msi_msg *msg);
void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg);
-void write_msi_msg(unsigned int irq, struct msi_msg *msg);
struct msi_desc {
struct {
@@ -48,6 +43,52 @@ struct msi_desc {
struct msi_msg msg;
};
+/* Helpers to hide struct msi_desc implementation details */
+#define msi_desc_to_dev(desc) (&(desc)->dev.dev)
+#define dev_to_msi_list(dev) (&to_pci_dev((dev))->msi_list)
+#define first_msi_entry(dev) \
+ list_first_entry(dev_to_msi_list((dev)), struct msi_desc, list)
+#define for_each_msi_entry(desc, dev) \
+ list_for_each_entry((desc), dev_to_msi_list((dev)), list)
+
+#ifdef CONFIG_PCI_MSI
+#define first_pci_msi_entry(pdev) first_msi_entry(&(pdev)->dev)
+#define for_each_pci_msi_entry(desc, pdev) \
+ for_each_msi_entry((desc), &(pdev)->dev)
+
+static inline struct pci_dev *msi_desc_to_pci_dev(struct msi_desc *desc)
+{
+ return desc->dev;
+}
+#endif /* CONFIG_PCI_MSI */
+
+void __pci_read_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void __pci_write_msi_msg(struct msi_desc *entry, struct msi_msg *msg);
+void pci_write_msi_msg(unsigned int irq, struct msi_msg *msg);
+
+u32 __pci_msix_desc_mask_irq(struct msi_desc *desc, u32 flag);
+u32 __pci_msi_desc_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
+void pci_msi_mask_irq(struct irq_data *data);
+void pci_msi_unmask_irq(struct irq_data *data);
+
+/* Conversion helpers. Should be removed after merging */
+static inline void __write_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+{
+ __pci_write_msi_msg(entry, msg);
+}
+static inline void write_msi_msg(int irq, struct msi_msg *msg)
+{
+ pci_write_msi_msg(irq, msg);
+}
+static inline void mask_msi_irq(struct irq_data *data)
+{
+ pci_msi_mask_irq(data);
+}
+static inline void unmask_msi_irq(struct irq_data *data)
+{
+ pci_msi_unmask_irq(data);
+}
+
/*
* The arch hooks to setup up msi irqs. Those functions are
* implemented as weak symbols so that they /can/ be overriden by
@@ -61,18 +102,142 @@ void arch_restore_msi_irqs(struct pci_dev *dev);
void default_teardown_msi_irqs(struct pci_dev *dev);
void default_restore_msi_irqs(struct pci_dev *dev);
-u32 default_msi_mask_irq(struct msi_desc *desc, u32 mask, u32 flag);
-u32 default_msix_mask_irq(struct msi_desc *desc, u32 flag);
-struct msi_chip {
+struct msi_controller {
struct module *owner;
struct device *dev;
struct device_node *of_node;
struct list_head list;
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+ struct irq_domain *domain;
+#endif
- int (*setup_irq)(struct msi_chip *chip, struct pci_dev *dev,
+ int (*setup_irq)(struct msi_controller *chip, struct pci_dev *dev,
struct msi_desc *desc);
- void (*teardown_irq)(struct msi_chip *chip, unsigned int irq);
+ void (*teardown_irq)(struct msi_controller *chip, unsigned int irq);
+};
+
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+
+#include <linux/irqhandler.h>
+#include <asm/msi.h>
+
+struct irq_domain;
+struct irq_chip;
+struct device_node;
+struct msi_domain_info;
+
+/**
+ * struct msi_domain_ops - MSI interrupt domain callbacks
+ * @get_hwirq: Retrieve the resulting hw irq number
+ * @msi_init: Domain specific init function for MSI interrupts
+ * @msi_free: Domain specific function to free a MSI interrupts
+ * @msi_check: Callback for verification of the domain/info/dev data
+ * @msi_prepare: Prepare the allocation of the interrupts in the domain
+ * @msi_finish: Optional callbacl to finalize the allocation
+ * @set_desc: Set the msi descriptor for an interrupt
+ * @handle_error: Optional error handler if the allocation fails
+ *
+ * @get_hwirq, @msi_init and @msi_free are callbacks used by
+ * msi_create_irq_domain() and related interfaces
+ *
+ * @msi_check, @msi_prepare, @msi_finish, @set_desc and @handle_error
+ * are callbacks used by msi_irq_domain_alloc_irqs() and related
+ * interfaces which are based on msi_desc.
+ */
+struct msi_domain_ops {
+ irq_hw_number_t (*get_hwirq)(struct msi_domain_info *info,
+ msi_alloc_info_t *arg);
+ int (*msi_init)(struct irq_domain *domain,
+ struct msi_domain_info *info,
+ unsigned int virq, irq_hw_number_t hwirq,
+ msi_alloc_info_t *arg);
+ void (*msi_free)(struct irq_domain *domain,
+ struct msi_domain_info *info,
+ unsigned int virq);
+ int (*msi_check)(struct irq_domain *domain,
+ struct msi_domain_info *info,
+ struct device *dev);
+ int (*msi_prepare)(struct irq_domain *domain,
+ struct device *dev, int nvec,
+ msi_alloc_info_t *arg);
+ void (*msi_finish)(msi_alloc_info_t *arg, int retval);
+ void (*set_desc)(msi_alloc_info_t *arg,
+ struct msi_desc *desc);
+ int (*handle_error)(struct irq_domain *domain,
+ struct msi_desc *desc, int error);
+};
+
+/**
+ * struct msi_domain_info - MSI interrupt domain data
+ * @flags: Flags to decribe features and capabilities
+ * @ops: The callback data structure
+ * @chip: Optional: associated interrupt chip
+ * @chip_data: Optional: associated interrupt chip data
+ * @handler: Optional: associated interrupt flow handler
+ * @handler_data: Optional: associated interrupt flow handler data
+ * @handler_name: Optional: associated interrupt flow handler name
+ * @data: Optional: domain specific data
+ */
+struct msi_domain_info {
+ u32 flags;
+ struct msi_domain_ops *ops;
+ struct irq_chip *chip;
+ void *chip_data;
+ irq_flow_handler_t handler;
+ void *handler_data;
+ const char *handler_name;
+ void *data;
+};
+
+/* Flags for msi_domain_info */
+enum {
+ /*
+ * Init non implemented ops callbacks with default MSI domain
+ * callbacks.
+ */
+ MSI_FLAG_USE_DEF_DOM_OPS = (1 << 0),
+ /*
+ * Init non implemented chip callbacks with default MSI chip
+ * callbacks.
+ */
+ MSI_FLAG_USE_DEF_CHIP_OPS = (1 << 1),
+ /* Build identity map between hwirq and irq */
+ MSI_FLAG_IDENTITY_MAP = (1 << 2),
+ /* Support multiple PCI MSI interrupts */
+ MSI_FLAG_MULTI_PCI_MSI = (1 << 3),
+ /* Support PCI MSIX interrupts */
+ MSI_FLAG_PCI_MSIX = (1 << 4),
};
+int msi_domain_set_affinity(struct irq_data *data, const struct cpumask *mask,
+ bool force);
+
+struct irq_domain *msi_create_irq_domain(struct device_node *of_node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent);
+int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
+ int nvec);
+void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev);
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain);
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
+
+#ifdef CONFIG_PCI_MSI_IRQ_DOMAIN
+void pci_msi_domain_write_msg(struct irq_data *irq_data, struct msi_msg *msg);
+struct irq_domain *pci_msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent);
+int pci_msi_domain_alloc_irqs(struct irq_domain *domain, struct pci_dev *dev,
+ int nvec, int type);
+void pci_msi_domain_free_irqs(struct irq_domain *domain, struct pci_dev *dev);
+struct irq_domain *pci_msi_create_default_irq_domain(struct device_node *node,
+ struct msi_domain_info *info, struct irq_domain *parent);
+
+irq_hw_number_t pci_msi_domain_calc_hwirq(struct pci_dev *dev,
+ struct msi_desc *desc);
+int pci_msi_domain_check_cap(struct irq_domain *domain,
+ struct msi_domain_info *info, struct device *dev);
+#endif /* CONFIG_PCI_MSI_IRQ_DOMAIN */
+
#endif /* LINUX_MSI_H */
diff --git a/include/linux/nfs4.h b/include/linux/nfs4.h
index 356acc2..022b761 100644
--- a/include/linux/nfs4.h
+++ b/include/linux/nfs4.h
@@ -490,6 +490,8 @@ enum {
/* nfs42 */
NFSPROC4_CLNT_SEEK,
+ NFSPROC4_CLNT_ALLOCATE,
+ NFSPROC4_CLNT_DEALLOCATE,
};
/* nfs41 types */
diff --git a/include/linux/nfs_fs.h b/include/linux/nfs_fs.h
index c72d1ad..6d627b9 100644
--- a/include/linux/nfs_fs.h
+++ b/include/linux/nfs_fs.h
@@ -163,7 +163,7 @@ struct nfs_inode {
*/
__be32 cookieverf[2];
- unsigned long npages;
+ unsigned long nrequests;
struct nfs_mds_commit_info commit_info;
/* Open contexts for shared mmap writes */
@@ -520,7 +520,7 @@ extern void nfs_commit_free(struct nfs_commit_data *data);
static inline int
nfs_have_writebacks(struct inode *inode)
{
- return NFS_I(inode)->npages != 0;
+ return NFS_I(inode)->nrequests != 0;
}
/*
diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h
index a32ba0d..1e37fbb 100644
--- a/include/linux/nfs_fs_sb.h
+++ b/include/linux/nfs_fs_sb.h
@@ -231,5 +231,7 @@ struct nfs_server {
#define NFS_CAP_ATOMIC_OPEN_V1 (1U << 17)
#define NFS_CAP_SECURITY_LABEL (1U << 18)
#define NFS_CAP_SEEK (1U << 19)
+#define NFS_CAP_ALLOCATE (1U << 20)
+#define NFS_CAP_DEALLOCATE (1U << 21)
#endif
diff --git a/include/linux/nfs_xdr.h b/include/linux/nfs_xdr.h
index 47ebb4f..467c84e 100644
--- a/include/linux/nfs_xdr.h
+++ b/include/linux/nfs_xdr.h
@@ -1243,6 +1243,20 @@ nfs_free_pnfs_ds_cinfo(struct pnfs_ds_commit_info *cinfo)
#endif /* CONFIG_NFS_V4_1 */
#ifdef CONFIG_NFS_V4_2
+struct nfs42_falloc_args {
+ struct nfs4_sequence_args seq_args;
+
+ struct nfs_fh *falloc_fh;
+ nfs4_stateid falloc_stateid;
+ u64 falloc_offset;
+ u64 falloc_length;
+};
+
+struct nfs42_falloc_res {
+ struct nfs4_sequence_res seq_res;
+ unsigned int status;
+};
+
struct nfs42_seek_args {
struct nfs4_sequence_args seq_args;
diff --git a/include/linux/of.h b/include/linux/of.h
index 29f0adc..dfde07e 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -23,6 +23,8 @@
#include <linux/spinlock.h>
#include <linux/topology.h>
#include <linux/notifier.h>
+#include <linux/property.h>
+#include <linux/list.h>
#include <asm/byteorder.h>
#include <asm/errno.h>
@@ -49,14 +51,13 @@ struct device_node {
const char *type;
phandle phandle;
const char *full_name;
+ struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
- struct device_node *next; /* next device of same type */
- struct device_node *allnext; /* next in list of all nodes */
struct kobject kobj;
unsigned long _flags;
void *data;
@@ -74,11 +75,18 @@ struct of_phandle_args {
uint32_t args[MAX_PHANDLE_ARGS];
};
+struct of_reconfig_data {
+ struct device_node *dn;
+ struct property *prop;
+ struct property *old_prop;
+};
+
/* initialize a node */
extern struct kobj_type of_node_ktype;
static inline void of_node_init(struct device_node *node)
{
kobject_init(&node->kobj, &of_node_ktype);
+ node->fwnode.type = FWNODE_OF;
}
/* true when node is initialized */
@@ -105,18 +113,27 @@ static inline struct device_node *of_node_get(struct device_node *node)
static inline void of_node_put(struct device_node *node) { }
#endif /* !CONFIG_OF_DYNAMIC */
-#ifdef CONFIG_OF
-
/* Pointer for first entry in chain of all nodes. */
-extern struct device_node *of_allnodes;
+extern struct device_node *of_root;
extern struct device_node *of_chosen;
extern struct device_node *of_aliases;
extern struct device_node *of_stdout;
extern raw_spinlock_t devtree_lock;
+#ifdef CONFIG_OF
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode && fwnode->type == FWNODE_OF;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return fwnode ? container_of(fwnode, struct device_node, fwnode) : NULL;
+}
+
static inline bool of_have_populated_dt(void)
{
- return of_allnodes != NULL;
+ return of_root != NULL;
}
static inline bool of_node_is_root(const struct device_node *node)
@@ -160,6 +177,7 @@ static inline void of_property_clear_flag(struct property *p, unsigned long flag
clear_bit(flag, &p->_flags);
}
+extern struct device_node *__of_find_all_nodes(struct device_node *prev);
extern struct device_node *of_find_all_nodes(struct device_node *prev);
/*
@@ -215,8 +233,9 @@ static inline const char *of_node_full_name(const struct device_node *np)
return np ? np->full_name : "<no-node>";
}
-#define for_each_of_allnodes(dn) \
- for (dn = of_allnodes; dn; dn = dn->allnext)
+#define for_each_of_allnodes_from(from, dn) \
+ for (dn = __of_find_all_nodes(from); dn; dn = __of_find_all_nodes(dn))
+#define for_each_of_allnodes(dn) for_each_of_allnodes_from(NULL, dn)
extern struct device_node *of_find_node_by_name(struct device_node *from,
const char *name);
extern struct device_node *of_find_node_by_type(struct device_node *from,
@@ -228,7 +247,13 @@ extern struct device_node *of_find_matching_node_and_match(
const struct of_device_id *matches,
const struct of_device_id **match);
-extern struct device_node *of_find_node_by_path(const char *path);
+extern struct device_node *of_find_node_opts_by_path(const char *path,
+ const char **opts);
+static inline struct device_node *of_find_node_by_path(const char *path)
+{
+ return of_find_node_opts_by_path(path, NULL);
+}
+
extern struct device_node *of_find_node_by_phandle(phandle handle);
extern struct device_node *of_get_parent(const struct device_node *node);
extern struct device_node *of_get_next_parent(struct device_node *node);
@@ -263,6 +288,10 @@ extern int of_property_read_u32_array(const struct device_node *np,
size_t sz);
extern int of_property_read_u64(const struct device_node *np,
const char *propname, u64 *out_value);
+extern int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values,
+ size_t sz);
extern int of_property_read_string(struct device_node *np,
const char *propname,
@@ -275,7 +304,7 @@ extern int of_property_read_string_helper(struct device_node *np,
const char **out_strs, size_t sz, int index);
extern int of_device_is_compatible(const struct device_node *device,
const char *);
-extern int of_device_is_available(const struct device_node *device);
+extern bool of_device_is_available(const struct device_node *device);
extern const void *of_get_property(const struct device_node *node,
const char *name,
int *lenp);
@@ -317,16 +346,6 @@ extern int of_update_property(struct device_node *np, struct property *newprop);
#define OF_RECONFIG_REMOVE_PROPERTY 0x0004
#define OF_RECONFIG_UPDATE_PROPERTY 0x0005
-struct of_prop_reconfig {
- struct device_node *dn;
- struct property *prop;
- struct property *old_prop;
-};
-
-extern int of_reconfig_notifier_register(struct notifier_block *);
-extern int of_reconfig_notifier_unregister(struct notifier_block *);
-extern int of_reconfig_notify(unsigned long, void *);
-
extern int of_attach_node(struct device_node *);
extern int of_detach_node(struct device_node *);
@@ -355,6 +374,16 @@ bool of_console_check(struct device_node *dn, char *name, int index);
#else /* CONFIG_OF */
+static inline bool is_of_node(struct fwnode_handle *fwnode)
+{
+ return false;
+}
+
+static inline struct device_node *of_node(struct fwnode_handle *fwnode)
+{
+ return NULL;
+}
+
static inline const char* of_node_full_name(const struct device_node *np)
{
return "<no-node>";
@@ -385,6 +414,12 @@ static inline struct device_node *of_find_node_by_path(const char *path)
return NULL;
}
+static inline struct device_node *of_find_node_opts_by_path(const char *path,
+ const char **opts)
+{
+ return NULL;
+}
+
static inline struct device_node *of_get_parent(const struct device_node *node)
{
return NULL;
@@ -426,9 +461,9 @@ static inline int of_device_is_compatible(const struct device_node *device,
return 0;
}
-static inline int of_device_is_available(const struct device_node *device)
+static inline bool of_device_is_available(const struct device_node *device)
{
- return 0;
+ return false;
}
static inline struct property *of_find_property(const struct device_node *np,
@@ -477,6 +512,13 @@ static inline int of_property_read_u32_array(const struct device_node *np,
return -ENOSYS;
}
+static inline int of_property_read_u64_array(const struct device_node *np,
+ const char *propname,
+ u64 *out_values, size_t sz)
+{
+ return -ENOSYS;
+}
+
static inline int of_property_read_string(struct device_node *np,
const char *propname,
const char **out_string)
@@ -760,6 +802,13 @@ static inline int of_property_read_u32(const struct device_node *np,
return of_property_read_u32_array(np, propname, out_value, 1);
}
+static inline int of_property_read_s32(const struct device_node *np,
+ const char *propname,
+ s32 *out_value)
+{
+ return of_property_read_u32(np, propname, (u32*) out_value);
+}
+
#define of_property_for_each_u32(np, propname, prop, p, u) \
for (prop = of_find_property(np, propname, NULL), \
p = of_prop_next_u32(prop, NULL, &u); \
@@ -828,7 +877,7 @@ static inline int of_get_available_child_count(const struct device_node *np)
= { .compatible = compat, \
.data = (fn == (fn_type)NULL) ? fn : fn }
#else
-#define _OF_DECLARE(table, name, compat, fn, fn_type) \
+#define _OF_DECLARE(table, name, compat, fn, fn_type) \
static const struct of_device_id __of_table_##name \
__attribute__((unused)) \
= { .compatible = compat, \
@@ -879,7 +928,19 @@ struct of_changeset {
struct list_head entries;
};
+enum of_reconfig_change {
+ OF_RECONFIG_NO_CHANGE = 0,
+ OF_RECONFIG_CHANGE_ADD,
+ OF_RECONFIG_CHANGE_REMOVE,
+};
+
#ifdef CONFIG_OF_DYNAMIC
+extern int of_reconfig_notifier_register(struct notifier_block *);
+extern int of_reconfig_notifier_unregister(struct notifier_block *);
+extern int of_reconfig_notify(unsigned long, struct of_reconfig_data *rd);
+extern int of_reconfig_get_state_change(unsigned long action,
+ struct of_reconfig_data *arg);
+
extern void of_changeset_init(struct of_changeset *ocs);
extern void of_changeset_destroy(struct of_changeset *ocs);
extern int of_changeset_apply(struct of_changeset *ocs);
@@ -917,9 +978,69 @@ static inline int of_changeset_update_property(struct of_changeset *ocs,
{
return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
}
-#endif
+#else /* CONFIG_OF_DYNAMIC */
+static inline int of_reconfig_notifier_register(struct notifier_block *nb)
+{
+ return -EINVAL;
+}
+static inline int of_reconfig_notifier_unregister(struct notifier_block *nb)
+{
+ return -EINVAL;
+}
+static inline int of_reconfig_notify(unsigned long action,
+ struct of_reconfig_data *arg)
+{
+ return -EINVAL;
+}
+static inline int of_reconfig_get_state_change(unsigned long action,
+ struct of_reconfig_data *arg)
+{
+ return -EINVAL;
+}
+#endif /* CONFIG_OF_DYNAMIC */
/* CONFIG_OF_RESOLVE api */
extern int of_resolve_phandles(struct device_node *tree);
+/**
+ * of_device_is_system_power_controller - Tells if system-power-controller is found for device_node
+ * @np: Pointer to the given device_node
+ *
+ * return true if present false otherwise
+ */
+static inline bool of_device_is_system_power_controller(const struct device_node *np)
+{
+ return of_property_read_bool(np, "system-power-controller");
+}
+
+/**
+ * Overlay support
+ */
+
+#ifdef CONFIG_OF_OVERLAY
+
+/* ID based overlays; the API for external users */
+int of_overlay_create(struct device_node *tree);
+int of_overlay_destroy(int id);
+int of_overlay_destroy_all(void);
+
+#else
+
+static inline int of_overlay_create(struct device_node *tree)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_overlay_destroy(int id)
+{
+ return -ENOTSUPP;
+}
+
+static inline int of_overlay_destroy_all(void)
+{
+ return -ENOTSUPP;
+}
+
+#endif
+
#endif /* _LINUX_OF_H */
diff --git a/include/linux/of_address.h b/include/linux/of_address.h
index 8cb14eb..d88e81b 100644
--- a/include/linux/of_address.h
+++ b/include/linux/of_address.h
@@ -106,7 +106,7 @@ extern int of_address_to_resource(struct device_node *dev, int index,
struct resource *r);
void __iomem *of_iomap(struct device_node *node, int index);
void __iomem *of_io_request_and_map(struct device_node *device,
- int index, char *name);
+ int index, const char *name);
#else
#include <linux/io.h>
@@ -123,7 +123,7 @@ static inline void __iomem *of_iomap(struct device_node *device, int index)
}
static inline void __iomem *of_io_request_and_map(struct device_node *device,
- int index, char *name)
+ int index, const char *name)
{
return IOMEM_ERR_PTR(-EINVAL);
}
diff --git a/include/linux/of_pci.h b/include/linux/of_pci.h
index 1fd207e..ce0e5ab 100644
--- a/include/linux/of_pci.h
+++ b/include/linux/of_pci.h
@@ -59,13 +59,13 @@ int of_pci_get_host_bridge_resources(struct device_node *dev,
#endif
#if defined(CONFIG_OF) && defined(CONFIG_PCI_MSI)
-int of_pci_msi_chip_add(struct msi_chip *chip);
-void of_pci_msi_chip_remove(struct msi_chip *chip);
-struct msi_chip *of_pci_find_msi_chip_by_node(struct device_node *of_node);
+int of_pci_msi_chip_add(struct msi_controller *chip);
+void of_pci_msi_chip_remove(struct msi_controller *chip);
+struct msi_controller *of_pci_find_msi_chip_by_node(struct device_node *of_node);
#else
-static inline int of_pci_msi_chip_add(struct msi_chip *chip) { return -EINVAL; }
-static inline void of_pci_msi_chip_remove(struct msi_chip *chip) { }
-static inline struct msi_chip *
+static inline int of_pci_msi_chip_add(struct msi_controller *chip) { return -EINVAL; }
+static inline void of_pci_msi_chip_remove(struct msi_controller *chip) { }
+static inline struct msi_controller *
of_pci_find_msi_chip_by_node(struct device_node *of_node) { return NULL; }
#endif
diff --git a/include/linux/of_pdt.h b/include/linux/of_pdt.h
index c65a18a..7e09244 100644
--- a/include/linux/of_pdt.h
+++ b/include/linux/of_pdt.h
@@ -39,7 +39,6 @@ extern void *prom_early_alloc(unsigned long size);
/* for building the device tree */
extern void of_pdt_build_devicetree(phandle root_node, struct of_pdt_ops *ops);
-extern void (*of_pdt_build_more)(struct device_node *dp,
- struct device_node ***nextp);
+extern void (*of_pdt_build_more)(struct device_node *dp);
#endif /* _LINUX_OF_PDT_H */
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h
index c2b0627..8a860f0 100644
--- a/include/linux/of_platform.h
+++ b/include/linux/of_platform.h
@@ -84,4 +84,10 @@ static inline int of_platform_populate(struct device_node *root,
static inline void of_platform_depopulate(struct device *parent) { }
#endif
+#ifdef CONFIG_OF_DYNAMIC
+extern void of_platform_register_reconfig_notifier(void);
+#else
+static inline void of_platform_register_reconfig_notifier(void) { }
+#endif
+
#endif /* _LINUX_OF_PLATFORM_H */
diff --git a/include/linux/omap-gpmc.h b/include/linux/omap-gpmc.h
new file mode 100644
index 0000000..c2080ee
--- /dev/null
+++ b/include/linux/omap-gpmc.h
@@ -0,0 +1,199 @@
+/*
+ * OMAP GPMC (General Purpose Memory Controller) defines
+ *
+ * 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.
+ */
+
+/* Maximum Number of Chip Selects */
+#define GPMC_CS_NUM 8
+
+#define GPMC_CONFIG_WP 0x00000005
+
+#define GPMC_IRQ_FIFOEVENTENABLE 0x01
+#define GPMC_IRQ_COUNT_EVENT 0x02
+
+#define GPMC_BURST_4 4 /* 4 word burst */
+#define GPMC_BURST_8 8 /* 8 word burst */
+#define GPMC_BURST_16 16 /* 16 word burst */
+#define GPMC_DEVWIDTH_8BIT 1 /* 8-bit device width */
+#define GPMC_DEVWIDTH_16BIT 2 /* 16-bit device width */
+#define GPMC_MUX_AAD 1 /* Addr-Addr-Data multiplex */
+#define GPMC_MUX_AD 2 /* Addr-Data multiplex */
+
+/* bool type time settings */
+struct gpmc_bool_timings {
+ bool cycle2cyclediffcsen;
+ bool cycle2cyclesamecsen;
+ bool we_extra_delay;
+ bool oe_extra_delay;
+ bool adv_extra_delay;
+ bool cs_extra_delay;
+ bool time_para_granularity;
+};
+
+/*
+ * Note that all values in this struct are in nanoseconds except sync_clk
+ * (which is in picoseconds), while the register values are in gpmc_fck cycles.
+ */
+struct gpmc_timings {
+ /* Minimum clock period for synchronous mode (in picoseconds) */
+ u32 sync_clk;
+
+ /* Chip-select signal timings corresponding to GPMC_CS_CONFIG2 */
+ u32 cs_on; /* Assertion time */
+ u32 cs_rd_off; /* Read deassertion time */
+ u32 cs_wr_off; /* Write deassertion time */
+
+ /* ADV signal timings corresponding to GPMC_CONFIG3 */
+ u32 adv_on; /* Assertion time */
+ u32 adv_rd_off; /* Read deassertion time */
+ u32 adv_wr_off; /* Write deassertion time */
+
+ /* WE signals timings corresponding to GPMC_CONFIG4 */
+ u32 we_on; /* WE assertion time */
+ u32 we_off; /* WE deassertion time */
+
+ /* OE signals timings corresponding to GPMC_CONFIG4 */
+ u32 oe_on; /* OE assertion time */
+ u32 oe_off; /* OE deassertion time */
+
+ /* Access time and cycle time timings corresponding to GPMC_CONFIG5 */
+ u32 page_burst_access; /* Multiple access word delay */
+ u32 access; /* Start-cycle to first data valid delay */
+ u32 rd_cycle; /* Total read cycle time */
+ u32 wr_cycle; /* Total write cycle time */
+
+ u32 bus_turnaround;
+ u32 cycle2cycle_delay;
+
+ u32 wait_monitoring;
+ u32 clk_activation;
+
+ /* The following are only on OMAP3430 */
+ u32 wr_access; /* WRACCESSTIME */
+ u32 wr_data_mux_bus; /* WRDATAONADMUXBUS */
+
+ struct gpmc_bool_timings bool_timings;
+};
+
+/* Device timings in picoseconds */
+struct gpmc_device_timings {
+ u32 t_ceasu; /* address setup to CS valid */
+ u32 t_avdasu; /* address setup to ADV valid */
+ /* XXX: try to combine t_avdp_r & t_avdp_w. Issue is
+ * of tusb using these timings even for sync whilst
+ * ideally for adv_rd/(wr)_off it should have considered
+ * t_avdh instead. This indirectly necessitates r/w
+ * variations of t_avdp as it is possible to have one
+ * sync & other async
+ */
+ u32 t_avdp_r; /* ADV low time (what about t_cer ?) */
+ u32 t_avdp_w;
+ u32 t_aavdh; /* address hold time */
+ u32 t_oeasu; /* address setup to OE valid */
+ u32 t_aa; /* access time from ADV assertion */
+ u32 t_iaa; /* initial access time */
+ u32 t_oe; /* access time from OE assertion */
+ u32 t_ce; /* access time from CS asertion */
+ u32 t_rd_cycle; /* read cycle time */
+ u32 t_cez_r; /* read CS deassertion to high Z */
+ u32 t_cez_w; /* write CS deassertion to high Z */
+ u32 t_oez; /* OE deassertion to high Z */
+ u32 t_weasu; /* address setup to WE valid */
+ u32 t_wpl; /* write assertion time */
+ u32 t_wph; /* write deassertion time */
+ u32 t_wr_cycle; /* write cycle time */
+
+ u32 clk;
+ u32 t_bacc; /* burst access valid clock to output delay */
+ u32 t_ces; /* CS setup time to clk */
+ u32 t_avds; /* ADV setup time to clk */
+ u32 t_avdh; /* ADV hold time from clk */
+ u32 t_ach; /* address hold time from clk */
+ u32 t_rdyo; /* clk to ready valid */
+
+ u32 t_ce_rdyz; /* XXX: description ?, or use t_cez instead */
+ u32 t_ce_avd; /* CS on to ADV on delay */
+
+ /* XXX: check the possibility of combining
+ * cyc_aavhd_oe & cyc_aavdh_we
+ */
+ u8 cyc_aavdh_oe;/* read address hold time in cycles */
+ u8 cyc_aavdh_we;/* write address hold time in cycles */
+ u8 cyc_oe; /* access time from OE assertion in cycles */
+ u8 cyc_wpl; /* write deassertion time in cycles */
+ u32 cyc_iaa; /* initial access time in cycles */
+
+ /* extra delays */
+ bool ce_xdelay;
+ bool avd_xdelay;
+ bool oe_xdelay;
+ bool we_xdelay;
+};
+
+struct gpmc_settings {
+ bool burst_wrap; /* enables wrap bursting */
+ bool burst_read; /* enables read page/burst mode */
+ bool burst_write; /* enables write page/burst mode */
+ bool device_nand; /* device is NAND */
+ bool sync_read; /* enables synchronous reads */
+ bool sync_write; /* enables synchronous writes */
+ bool wait_on_read; /* monitor wait on reads */
+ bool wait_on_write; /* monitor wait on writes */
+ u32 burst_len; /* page/burst length */
+ u32 device_width; /* device bus width (8 or 16 bit) */
+ u32 mux_add_data; /* multiplex address & data */
+ u32 wait_pin; /* wait-pin to be used */
+};
+
+extern int gpmc_calc_timings(struct gpmc_timings *gpmc_t,
+ struct gpmc_settings *gpmc_s,
+ struct gpmc_device_timings *dev_t);
+
+struct gpmc_nand_regs;
+struct device_node;
+
+extern void gpmc_update_nand_reg(struct gpmc_nand_regs *reg, int cs);
+extern int gpmc_get_client_irq(unsigned irq_config);
+
+extern unsigned int gpmc_ticks_to_ns(unsigned int ticks);
+
+extern void gpmc_cs_write_reg(int cs, int idx, u32 val);
+extern int gpmc_calc_divider(unsigned int sync_clk);
+extern int gpmc_cs_set_timings(int cs, const struct gpmc_timings *t);
+extern int gpmc_cs_program_settings(int cs, struct gpmc_settings *p);
+extern int gpmc_cs_request(int cs, unsigned long size, unsigned long *base);
+extern void gpmc_cs_free(int cs);
+extern int gpmc_configure(int cmd, int wval);
+extern void gpmc_read_settings_dt(struct device_node *np,
+ struct gpmc_settings *p);
+
+extern void omap3_gpmc_save_context(void);
+extern void omap3_gpmc_restore_context(void);
+
+struct gpmc_timings;
+struct omap_nand_platform_data;
+struct omap_onenand_platform_data;
+
+#if IS_ENABLED(CONFIG_MTD_NAND_OMAP2)
+extern int gpmc_nand_init(struct omap_nand_platform_data *d,
+ struct gpmc_timings *gpmc_t);
+#else
+static inline int gpmc_nand_init(struct omap_nand_platform_data *d,
+ struct gpmc_timings *gpmc_t)
+{
+ return 0;
+}
+#endif
+
+#if IS_ENABLED(CONFIG_MTD_ONENAND_OMAP2)
+extern void gpmc_onenand_init(struct omap_onenand_platform_data *d);
+#else
+#define board_onenand_data NULL
+static inline void gpmc_onenand_init(struct omap_onenand_platform_data *d)
+{
+}
+#endif
diff --git a/include/linux/omap-mailbox.h b/include/linux/omap-mailbox.h
index f8322d9..587bbdd 100644
--- a/include/linux/omap-mailbox.h
+++ b/include/linux/omap-mailbox.h
@@ -10,20 +10,20 @@
#define OMAP_MAILBOX_H
typedef u32 mbox_msg_t;
-struct omap_mbox;
typedef int __bitwise omap_mbox_irq_t;
#define IRQ_TX ((__force omap_mbox_irq_t) 1)
#define IRQ_RX ((__force omap_mbox_irq_t) 2)
-int omap_mbox_msg_send(struct omap_mbox *, mbox_msg_t msg);
+struct mbox_chan;
+struct mbox_client;
-struct omap_mbox *omap_mbox_get(const char *, struct notifier_block *nb);
-void omap_mbox_put(struct omap_mbox *mbox, struct notifier_block *nb);
+struct mbox_chan *omap_mbox_request_channel(struct mbox_client *cl,
+ const char *chan_name);
-void omap_mbox_save_ctx(struct omap_mbox *mbox);
-void omap_mbox_restore_ctx(struct omap_mbox *mbox);
-void omap_mbox_enable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
-void omap_mbox_disable_irq(struct omap_mbox *mbox, omap_mbox_irq_t irq);
+void omap_mbox_save_ctx(struct mbox_chan *chan);
+void omap_mbox_restore_ctx(struct mbox_chan *chan);
+void omap_mbox_enable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq);
+void omap_mbox_disable_irq(struct mbox_chan *chan, omap_mbox_irq_t irq);
#endif /* OMAP_MAILBOX_H */
diff --git a/include/linux/page_cgroup.h b/include/linux/page_cgroup.h
deleted file mode 100644
index 5c831f1..0000000
--- a/include/linux/page_cgroup.h
+++ /dev/null
@@ -1,105 +0,0 @@
-#ifndef __LINUX_PAGE_CGROUP_H
-#define __LINUX_PAGE_CGROUP_H
-
-enum {
- /* flags for mem_cgroup */
- PCG_USED = 0x01, /* This page is charged to a memcg */
- PCG_MEM = 0x02, /* This page holds a memory charge */
- PCG_MEMSW = 0x04, /* This page holds a memory+swap charge */
-};
-
-struct pglist_data;
-
-#ifdef CONFIG_MEMCG
-struct mem_cgroup;
-
-/*
- * Page Cgroup can be considered as an extended mem_map.
- * A page_cgroup page is associated with every page descriptor. The
- * page_cgroup helps us identify information about the cgroup
- * All page cgroups are allocated at boot or memory hotplug event,
- * then the page cgroup for pfn always exists.
- */
-struct page_cgroup {
- unsigned long flags;
- struct mem_cgroup *mem_cgroup;
-};
-
-extern void pgdat_page_cgroup_init(struct pglist_data *pgdat);
-
-#ifdef CONFIG_SPARSEMEM
-static inline void page_cgroup_init_flatmem(void)
-{
-}
-extern void page_cgroup_init(void);
-#else
-extern void page_cgroup_init_flatmem(void);
-static inline void page_cgroup_init(void)
-{
-}
-#endif
-
-struct page_cgroup *lookup_page_cgroup(struct page *page);
-
-static inline int PageCgroupUsed(struct page_cgroup *pc)
-{
- return !!(pc->flags & PCG_USED);
-}
-#else /* !CONFIG_MEMCG */
-struct page_cgroup;
-
-static inline void pgdat_page_cgroup_init(struct pglist_data *pgdat)
-{
-}
-
-static inline struct page_cgroup *lookup_page_cgroup(struct page *page)
-{
- return NULL;
-}
-
-static inline void page_cgroup_init(void)
-{
-}
-
-static inline void page_cgroup_init_flatmem(void)
-{
-}
-#endif /* CONFIG_MEMCG */
-
-#include <linux/swap.h>
-
-#ifdef CONFIG_MEMCG_SWAP
-extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
- unsigned short old, unsigned short new);
-extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
-extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
-extern int swap_cgroup_swapon(int type, unsigned long max_pages);
-extern void swap_cgroup_swapoff(int type);
-#else
-
-static inline
-unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
-{
- return 0;
-}
-
-static inline
-unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
-{
- return 0;
-}
-
-static inline int
-swap_cgroup_swapon(int type, unsigned long max_pages)
-{
- return 0;
-}
-
-static inline void swap_cgroup_swapoff(int type)
-{
- return;
-}
-
-#endif /* CONFIG_MEMCG_SWAP */
-
-#endif /* __LINUX_PAGE_CGROUP_H */
diff --git a/include/linux/page_counter.h b/include/linux/page_counter.h
new file mode 100644
index 0000000..9554215
--- /dev/null
+++ b/include/linux/page_counter.h
@@ -0,0 +1,51 @@
+#ifndef _LINUX_PAGE_COUNTER_H
+#define _LINUX_PAGE_COUNTER_H
+
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <asm/page.h>
+
+struct page_counter {
+ atomic_long_t count;
+ unsigned long limit;
+ struct page_counter *parent;
+
+ /* legacy */
+ unsigned long watermark;
+ unsigned long failcnt;
+};
+
+#if BITS_PER_LONG == 32
+#define PAGE_COUNTER_MAX LONG_MAX
+#else
+#define PAGE_COUNTER_MAX (LONG_MAX / PAGE_SIZE)
+#endif
+
+static inline void page_counter_init(struct page_counter *counter,
+ struct page_counter *parent)
+{
+ atomic_long_set(&counter->count, 0);
+ counter->limit = PAGE_COUNTER_MAX;
+ counter->parent = parent;
+}
+
+static inline unsigned long page_counter_read(struct page_counter *counter)
+{
+ return atomic_long_read(&counter->count);
+}
+
+void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages);
+void page_counter_charge(struct page_counter *counter, unsigned long nr_pages);
+int page_counter_try_charge(struct page_counter *counter,
+ unsigned long nr_pages,
+ struct page_counter **fail);
+void page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages);
+int page_counter_limit(struct page_counter *counter, unsigned long limit);
+int page_counter_memparse(const char *buf, unsigned long *nr_pages);
+
+static inline void page_counter_reset_watermark(struct page_counter *counter)
+{
+ counter->watermark = page_counter_read(counter);
+}
+
+#endif /* _LINUX_PAGE_COUNTER_H */
diff --git a/include/linux/pci.h b/include/linux/pci.h
index 4c8ac5f..a523cee 100644
--- a/include/linux/pci.h
+++ b/include/linux/pci.h
@@ -450,7 +450,7 @@ struct pci_bus {
struct resource busn_res; /* bus numbers routed to this bus */
struct pci_ops *ops; /* configuration access functions */
- struct msi_chip *msi; /* MSI controller */
+ struct msi_controller *msi; /* MSI controller */
void *sysdata; /* hook for sys-specific extension */
struct proc_dir_entry *procdir; /* directory entry in /proc/bus/pci */
diff --git a/include/linux/pci_hotplug.h b/include/linux/pci_hotplug.h
index 2706ee9..8c78950 100644
--- a/include/linux/pci_hotplug.h
+++ b/include/linux/pci_hotplug.h
@@ -109,7 +109,6 @@ struct hotplug_slot {
struct list_head slot_list;
struct pci_slot *pci_slot;
};
-#define to_hotplug_slot(n) container_of(n, struct hotplug_slot, kobj)
static inline const char *hotplug_slot_name(const struct hotplug_slot *slot)
{
diff --git a/include/linux/pci_ids.h b/include/linux/pci_ids.h
index 1fa99a3..97fb9f6 100644
--- a/include/linux/pci_ids.h
+++ b/include/linux/pci_ids.h
@@ -522,6 +522,8 @@
#define PCI_DEVICE_ID_AMD_15H_M10H_F3 0x1403
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F3 0x141d
#define PCI_DEVICE_ID_AMD_15H_M30H_NB_F4 0x141e
+#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F3 0x1573
+#define PCI_DEVICE_ID_AMD_15H_M60H_NB_F4 0x1574
#define PCI_DEVICE_ID_AMD_15H_NB_F0 0x1600
#define PCI_DEVICE_ID_AMD_15H_NB_F1 0x1601
#define PCI_DEVICE_ID_AMD_15H_NB_F2 0x1602
diff --git a/include/linux/percpu-refcount.h b/include/linux/percpu-refcount.h
index 51ce60c..530b249 100644
--- a/include/linux/percpu-refcount.h
+++ b/include/linux/percpu-refcount.h
@@ -147,28 +147,42 @@ static inline bool __ref_is_percpu(struct percpu_ref *ref,
}
/**
- * percpu_ref_get - increment a percpu refcount
+ * percpu_ref_get_many - increment a percpu refcount
* @ref: percpu_ref to get
+ * @nr: number of references to get
*
- * Analagous to atomic_long_inc().
+ * Analogous to atomic_long_add().
*
* This function is safe to call as long as @ref is between init and exit.
*/
-static inline void percpu_ref_get(struct percpu_ref *ref)
+static inline void percpu_ref_get_many(struct percpu_ref *ref, unsigned long nr)
{
unsigned long __percpu *percpu_count;
rcu_read_lock_sched();
if (__ref_is_percpu(ref, &percpu_count))
- this_cpu_inc(*percpu_count);
+ this_cpu_add(*percpu_count, nr);
else
- atomic_long_inc(&ref->count);
+ atomic_long_add(nr, &ref->count);
rcu_read_unlock_sched();
}
/**
+ * percpu_ref_get - increment a percpu refcount
+ * @ref: percpu_ref to get
+ *
+ * Analagous to atomic_long_inc().
+ *
+ * This function is safe to call as long as @ref is between init and exit.
+ */
+static inline void percpu_ref_get(struct percpu_ref *ref)
+{
+ percpu_ref_get_many(ref, 1);
+}
+
+/**
* percpu_ref_tryget - try to increment a percpu refcount
* @ref: percpu_ref to try-get
*
@@ -231,29 +245,44 @@ static inline bool percpu_ref_tryget_live(struct percpu_ref *ref)
}
/**
- * percpu_ref_put - decrement a percpu refcount
+ * percpu_ref_put_many - decrement a percpu refcount
* @ref: percpu_ref to put
+ * @nr: number of references to put
*
* Decrement the refcount, and if 0, call the release function (which was passed
* to percpu_ref_init())
*
* This function is safe to call as long as @ref is between init and exit.
*/
-static inline void percpu_ref_put(struct percpu_ref *ref)
+static inline void percpu_ref_put_many(struct percpu_ref *ref, unsigned long nr)
{
unsigned long __percpu *percpu_count;
rcu_read_lock_sched();
if (__ref_is_percpu(ref, &percpu_count))
- this_cpu_dec(*percpu_count);
- else if (unlikely(atomic_long_dec_and_test(&ref->count)))
+ this_cpu_sub(*percpu_count, nr);
+ else if (unlikely(atomic_long_sub_and_test(nr, &ref->count)))
ref->release(ref);
rcu_read_unlock_sched();
}
/**
+ * percpu_ref_put - decrement a percpu refcount
+ * @ref: percpu_ref to put
+ *
+ * Decrement the refcount, and if 0, call the release function (which was passed
+ * to percpu_ref_init())
+ *
+ * This function is safe to call as long as @ref is between init and exit.
+ */
+static inline void percpu_ref_put(struct percpu_ref *ref)
+{
+ percpu_ref_put_many(ref, 1);
+}
+
+/**
* percpu_ref_is_zero - test whether a percpu refcount reached zero
* @ref: percpu_ref to test
*
diff --git a/include/linux/percpu.h b/include/linux/percpu.h
index a3aa63e..caebf2a 100644
--- a/include/linux/percpu.h
+++ b/include/linux/percpu.h
@@ -5,6 +5,7 @@
#include <linux/preempt.h>
#include <linux/smp.h>
#include <linux/cpumask.h>
+#include <linux/printk.h>
#include <linux/pfn.h>
#include <linux/init.h>
@@ -134,4 +135,7 @@ extern phys_addr_t per_cpu_ptr_to_phys(void *addr);
(typeof(type) __percpu *)__alloc_percpu(sizeof(type), \
__alignof__(type))
+/* To avoid include hell, as printk can not declare this, we declare it here */
+DECLARE_PER_CPU(printk_func_t, printk_func);
+
#endif /* __LINUX_PERCPU_H */
diff --git a/include/linux/perf_event.h b/include/linux/perf_event.h
index 893a0d0..486e84c 100644
--- a/include/linux/perf_event.h
+++ b/include/linux/perf_event.h
@@ -79,7 +79,7 @@ struct perf_branch_stack {
struct perf_branch_entry entries[0];
};
-struct perf_regs_user {
+struct perf_regs {
__u64 abi;
struct pt_regs *regs;
};
@@ -580,34 +580,40 @@ extern u64 perf_event_read_value(struct perf_event *event,
struct perf_sample_data {
- u64 type;
+ /*
+ * Fields set by perf_sample_data_init(), group so as to
+ * minimize the cachelines touched.
+ */
+ u64 addr;
+ struct perf_raw_record *raw;
+ struct perf_branch_stack *br_stack;
+ u64 period;
+ u64 weight;
+ u64 txn;
+ union perf_mem_data_src data_src;
+ /*
+ * The other fields, optionally {set,used} by
+ * perf_{prepare,output}_sample().
+ */
+ u64 type;
u64 ip;
struct {
u32 pid;
u32 tid;
} tid_entry;
u64 time;
- u64 addr;
u64 id;
u64 stream_id;
struct {
u32 cpu;
u32 reserved;
} cpu_entry;
- u64 period;
- union perf_mem_data_src data_src;
struct perf_callchain_entry *callchain;
- struct perf_raw_record *raw;
- struct perf_branch_stack *br_stack;
- struct perf_regs_user regs_user;
+ struct perf_regs regs_user;
+ struct perf_regs regs_intr;
u64 stack_user_size;
- u64 weight;
- /*
- * Transaction flags for abort events:
- */
- u64 txn;
-};
+} ____cacheline_aligned;
/* default value for data source */
#define PERF_MEM_NA (PERF_MEM_S(OP, NA) |\
@@ -624,9 +630,6 @@ static inline void perf_sample_data_init(struct perf_sample_data *data,
data->raw = NULL;
data->br_stack = NULL;
data->period = period;
- data->regs_user.abi = PERF_SAMPLE_REGS_ABI_NONE;
- data->regs_user.regs = NULL;
- data->stack_user_size = 0;
data->weight = 0;
data->data_src.val = PERF_MEM_NA;
data->txn = 0;
diff --git a/include/linux/platform_data/asoc-s3c.h b/include/linux/platform_data/asoc-s3c.h
index a6591c6..5e0bc77 100644
--- a/include/linux/platform_data/asoc-s3c.h
+++ b/include/linux/platform_data/asoc-s3c.h
@@ -27,6 +27,7 @@ struct samsung_i2s {
#define QUIRK_NO_MUXPSR (1 << 2)
#define QUIRK_NEED_RSTCLR (1 << 3)
#define QUIRK_SUPPORTS_TDM (1 << 4)
+#define QUIRK_SUPPORTS_IDMA (1 << 5)
/* Quirks of the I2S controller */
u32 quirks;
dma_addr_t idma_addr;
diff --git a/include/linux/platform_data/hsmmc-omap.h b/include/linux/platform_data/hsmmc-omap.h
new file mode 100644
index 0000000..67bbcf0
--- /dev/null
+++ b/include/linux/platform_data/hsmmc-omap.h
@@ -0,0 +1,90 @@
+/*
+ * MMC definitions for OMAP2
+ *
+ * Copyright (C) 2006 Nokia 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.
+ */
+
+/*
+ * struct omap_hsmmc_dev_attr.flags possibilities
+ *
+ * OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can
+ * operate with either 1.8Vdc or 3.0Vdc card voltages; this flag
+ * should be set if this is the case. See for example Section 22.5.3
+ * "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia
+ * Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R).
+ *
+ * OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers
+ * don't work correctly on some MMC controller instances on some
+ * OMAP3 SoCs; this flag should be set if this is the case. See
+ * for example Advisory 2.1.1.128 "MMC: Multiple Block Read
+ * Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_
+ * Revision F (October 2010) (SPRZ278F).
+ */
+#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
+#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1)
+#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2)
+
+struct omap_hsmmc_dev_attr {
+ u8 flags;
+};
+
+struct mmc_card;
+
+struct omap_hsmmc_platform_data {
+ /* back-link to device */
+ struct device *dev;
+
+ /* set if your board has components or wiring that limits the
+ * maximum frequency on the MMC bus */
+ unsigned int max_freq;
+
+ /* Integrating attributes from the omap_hwmod layer */
+ u8 controller_flags;
+
+ /* Register offset deviation */
+ u16 reg_offset;
+
+ /*
+ * 4/8 wires and any additional host capabilities
+ * need to OR'd all capabilities (ref. linux/mmc/host.h)
+ */
+ u32 caps; /* Used for the MMC driver on 2430 and later */
+ u32 pm_caps; /* PM capabilities of the mmc */
+
+ /* switch pin can be for card detect (default) or card cover */
+ unsigned cover:1;
+
+ /* use the internal clock */
+ unsigned internal_clock:1;
+
+ /* nonremovable e.g. eMMC */
+ unsigned nonremovable:1;
+
+ /* eMMC does not handle power off when not in sleep state */
+ unsigned no_regulator_off_init:1;
+
+ /* we can put the features above into this variable */
+#define HSMMC_HAS_PBIAS (1 << 0)
+#define HSMMC_HAS_UPDATED_RESET (1 << 1)
+#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
+ unsigned features;
+
+ int switch_pin; /* gpio (card detect) */
+ int gpio_wp; /* gpio (write protect) */
+
+ int (*set_power)(struct device *dev, int power_on, int vdd);
+ void (*remux)(struct device *dev, int power_on);
+ /* Call back before enabling / disabling regulators */
+ void (*before_set_reg)(struct device *dev, int power_on, int vdd);
+ /* Call back after enabling / disabling regulators */
+ void (*after_set_reg)(struct device *dev, int power_on, int vdd);
+ /* if we have special card, init it using this callback */
+ void (*init_card)(struct mmc_card *card);
+
+ const char *name;
+ u32 ocr_mask;
+};
diff --git a/include/linux/platform_data/lp855x.h b/include/linux/platform_data/lp855x.h
index 1b2ba24..9c7fd1e 100644
--- a/include/linux/platform_data/lp855x.h
+++ b/include/linux/platform_data/lp855x.h
@@ -136,6 +136,7 @@ struct lp855x_rom_data {
Only valid when mode is PWM_BASED.
* @size_program : total size of lp855x_rom_data
* @rom_data : list of new eeprom/eprom registers
+ * @supply : regulator that supplies 3V input
*/
struct lp855x_platform_data {
const char *name;
@@ -144,6 +145,7 @@ struct lp855x_platform_data {
unsigned int period_ns;
int size_program;
struct lp855x_rom_data *rom_data;
+ struct regulator *supply;
};
#endif
diff --git a/arch/arm/mach-at91/include/mach/atmel-mci.h b/include/linux/platform_data/mmc-atmel-mci.h
index 3069e41..399a2d5 100644
--- a/arch/arm/mach-at91/include/mach/atmel-mci.h
+++ b/include/linux/platform_data/mmc-atmel-mci.h
@@ -1,17 +1,22 @@
-#ifndef __MACH_ATMEL_MCI_H
-#define __MACH_ATMEL_MCI_H
+#ifndef __MMC_ATMEL_MCI_H
+#define __MMC_ATMEL_MCI_H
#include <linux/platform_data/dma-atmel.h>
+#include <linux/platform_data/dma-dw.h>
/**
* struct mci_dma_data - DMA data for MCI interface
*/
struct mci_dma_data {
- struct at_dma_slave sdata;
+#ifdef CONFIG_ARM
+ struct at_dma_slave sdata;
+#else
+ struct dw_dma_slave sdata;
+#endif
};
/* accessor macros */
#define slave_data_ptr(s) (&(s)->sdata)
#define find_slave_dev(s) ((s)->sdata.dma_dev)
-#endif /* __MACH_ATMEL_MCI_H */
+#endif /* __MMC_ATMEL_MCI_H */
diff --git a/include/linux/platform_data/mmc-omap.h b/include/linux/platform_data/mmc-omap.h
index 51e70cf..5c188f4 100644
--- a/include/linux/platform_data/mmc-omap.h
+++ b/include/linux/platform_data/mmc-omap.h
@@ -10,32 +10,8 @@
#define OMAP_MMC_MAX_SLOTS 2
-/*
- * struct omap_mmc_dev_attr.flags possibilities
- *
- * OMAP_HSMMC_SUPPORTS_DUAL_VOLT: Some HSMMC controller instances can
- * operate with either 1.8Vdc or 3.0Vdc card voltages; this flag
- * should be set if this is the case. See for example Section 22.5.3
- * "MMC/SD/SDIO1 Bus Voltage Selection" of the OMAP34xx Multimedia
- * Device Silicon Revision 3.1.x Revision ZR (July 2011) (SWPU223R).
- *
- * OMAP_HSMMC_BROKEN_MULTIBLOCK_READ: Multiple-block read transfers
- * don't work correctly on some MMC controller instances on some
- * OMAP3 SoCs; this flag should be set if this is the case. See
- * for example Advisory 2.1.1.128 "MMC: Multiple Block Read
- * Operation Issue" in _OMAP3530/3525/3515/3503 Silicon Errata_
- * Revision F (October 2010) (SPRZ278F).
- */
-#define OMAP_HSMMC_SUPPORTS_DUAL_VOLT BIT(0)
-#define OMAP_HSMMC_BROKEN_MULTIBLOCK_READ BIT(1)
-#define OMAP_HSMMC_SWAKEUP_MISSING BIT(2)
-
struct mmc_card;
-struct omap_mmc_dev_attr {
- u8 flags;
-};
-
struct omap_mmc_platform_data {
/* back-link to device */
struct device *dev;
@@ -106,9 +82,6 @@ struct omap_mmc_platform_data {
unsigned vcc_aux_disable_is_sleep:1;
/* we can put the features above into this variable */
-#define HSMMC_HAS_PBIAS (1 << 0)
-#define HSMMC_HAS_UPDATED_RESET (1 << 1)
-#define HSMMC_HAS_HSPE_SUPPORT (1 << 2)
#define MMC_OMAP7XX (1 << 3)
#define MMC_OMAP15XX (1 << 4)
#define MMC_OMAP16XX (1 << 5)
diff --git a/include/linux/platform_data/pxa_sdhci.h b/include/linux/platform_data/pxa_sdhci.h
index 27d3156..9e20c2f 100644
--- a/include/linux/platform_data/pxa_sdhci.h
+++ b/include/linux/platform_data/pxa_sdhci.h
@@ -55,9 +55,4 @@ struct sdhci_pxa_platdata {
unsigned int quirks2;
unsigned int pm_caps;
};
-
-struct sdhci_pxa {
- u8 clk_enable;
- u8 power_mode;
-};
#endif /* _PXA_SDHCI_H_ */
diff --git a/include/linux/platform_data/serial-omap.h b/include/linux/platform_data/serial-omap.h
index c860c1b..d09275f 100644
--- a/include/linux/platform_data/serial-omap.h
+++ b/include/linux/platform_data/serial-omap.h
@@ -38,9 +38,6 @@ struct omap_uart_port_info {
unsigned int dma_rx_timeout;
unsigned int autosuspend_timeout;
unsigned int dma_rx_poll_rate;
- int DTR_gpio;
- int DTR_inverted;
- int DTR_present;
int (*get_context_loss_count)(struct device *);
void (*enable_wakeup)(struct device *, bool);
diff --git a/include/linux/pm.h b/include/linux/pm.h
index 383fd68..66a656e 100644
--- a/include/linux/pm.h
+++ b/include/linux/pm.h
@@ -342,7 +342,7 @@ struct dev_pm_ops {
#define SET_LATE_SYSTEM_SLEEP_PM_OPS(suspend_fn, resume_fn)
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
.runtime_suspend = suspend_fn, \
.runtime_resume = resume_fn, \
@@ -351,14 +351,7 @@ struct dev_pm_ops {
#define SET_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
#endif
-#ifdef CONFIG_PM
-#define SET_PM_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn) \
- .runtime_suspend = suspend_fn, \
- .runtime_resume = resume_fn, \
- .runtime_idle = idle_fn,
-#else
-#define SET_PM_RUNTIME_PM_OPS(suspend_fn, resume_fn, idle_fn)
-#endif
+#define SET_PM_RUNTIME_PM_OPS SET_RUNTIME_PM_OPS
/*
* Use this if you want to use the same suspend and resume callbacks for suspend
@@ -538,11 +531,7 @@ enum rpm_request {
};
struct wakeup_source;
-
-struct pm_domain_data {
- struct list_head list_node;
- struct device *dev;
-};
+struct pm_domain_data;
struct pm_subsys_data {
spinlock_t lock;
@@ -576,7 +565,7 @@ struct dev_pm_info {
#else
unsigned int should_wakeup:1;
#endif
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
struct timer_list suspend_timer;
unsigned long timer_expires;
struct work_struct work;
diff --git a/include/linux/pm_clock.h b/include/linux/pm_clock.h
index 8348866..0b00396 100644
--- a/include/linux/pm_clock.h
+++ b/include/linux/pm_clock.h
@@ -18,6 +18,8 @@ struct pm_clk_notifier_block {
char *con_ids[];
};
+struct clk;
+
#ifdef CONFIG_PM_CLK
static inline bool pm_clk_no_clocks(struct device *dev)
{
@@ -29,6 +31,7 @@ extern void pm_clk_init(struct device *dev);
extern int pm_clk_create(struct device *dev);
extern void pm_clk_destroy(struct device *dev);
extern int pm_clk_add(struct device *dev, const char *con_id);
+extern int pm_clk_add_clk(struct device *dev, struct clk *clk);
extern void pm_clk_remove(struct device *dev, const char *con_id);
extern int pm_clk_suspend(struct device *dev);
extern int pm_clk_resume(struct device *dev);
@@ -51,6 +54,11 @@ static inline int pm_clk_add(struct device *dev, const char *con_id)
{
return -EINVAL;
}
+
+static inline int pm_clk_add_clk(struct device *dev, struct clk *clk)
+{
+ return -EINVAL;
+}
static inline void pm_clk_remove(struct device *dev, const char *con_id)
{
}
diff --git a/include/linux/pm_domain.h b/include/linux/pm_domain.h
index 2e0e06d..6cd20d5 100644
--- a/include/linux/pm_domain.h
+++ b/include/linux/pm_domain.h
@@ -17,6 +17,9 @@
#include <linux/notifier.h>
#include <linux/cpuidle.h>
+/* Defines used for the flags field in the struct generic_pm_domain */
+#define GENPD_FLAG_PM_CLK (1U << 0) /* PM domain uses PM clk */
+
enum gpd_status {
GPD_STATE_ACTIVE = 0, /* PM domain is active */
GPD_STATE_WAIT_MASTER, /* PM domain's master is being waited for */
@@ -76,6 +79,7 @@ struct generic_pm_domain {
struct device *dev);
void (*detach_dev)(struct generic_pm_domain *domain,
struct device *dev);
+ unsigned int flags; /* Bit field of configs for genpd */
};
static inline struct generic_pm_domain *pd_to_genpd(struct dev_pm_domain *pd)
@@ -100,6 +104,11 @@ struct gpd_timing_data {
bool cached_stop_ok;
};
+struct pm_domain_data {
+ struct list_head list_node;
+ struct device *dev;
+};
+
struct generic_pm_domain_data {
struct pm_domain_data base;
struct gpd_timing_data td;
@@ -147,6 +156,7 @@ extern void pm_genpd_init(struct generic_pm_domain *genpd,
extern int pm_genpd_poweron(struct generic_pm_domain *genpd);
extern int pm_genpd_name_poweron(const char *domain_name);
+extern void pm_genpd_poweroff_unused(void);
extern struct dev_power_governor simple_qos_governor;
extern struct dev_power_governor pm_domain_always_on_gov;
@@ -221,6 +231,7 @@ static inline int pm_genpd_name_poweron(const char *domain_name)
{
return -ENOSYS;
}
+static inline void pm_genpd_poweroff_unused(void) {}
#define simple_qos_governor NULL
#define pm_domain_always_on_gov NULL
#endif
@@ -237,12 +248,6 @@ static inline int pm_genpd_name_add_device(const char *domain_name,
return __pm_genpd_name_add_device(domain_name, dev, NULL);
}
-#ifdef CONFIG_PM_GENERIC_DOMAINS_RUNTIME
-extern void pm_genpd_poweroff_unused(void);
-#else
-static inline void pm_genpd_poweroff_unused(void) {}
-#endif
-
#ifdef CONFIG_PM_GENERIC_DOMAINS_SLEEP
extern void pm_genpd_syscore_poweroff(struct device *dev);
extern void pm_genpd_syscore_poweron(struct device *dev);
diff --git a/include/linux/pm_opp.h b/include/linux/pm_opp.h
index 0330217..cec2d45 100644
--- a/include/linux/pm_opp.h
+++ b/include/linux/pm_opp.h
@@ -21,7 +21,7 @@ struct dev_pm_opp;
struct device;
enum dev_pm_opp_event {
- OPP_EVENT_ADD, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
+ OPP_EVENT_ADD, OPP_EVENT_REMOVE, OPP_EVENT_ENABLE, OPP_EVENT_DISABLE,
};
#if defined(CONFIG_PM_OPP)
@@ -44,6 +44,7 @@ struct dev_pm_opp *dev_pm_opp_find_freq_ceil(struct device *dev,
int dev_pm_opp_add(struct device *dev, unsigned long freq,
unsigned long u_volt);
+void dev_pm_opp_remove(struct device *dev, unsigned long freq);
int dev_pm_opp_enable(struct device *dev, unsigned long freq);
@@ -90,6 +91,10 @@ static inline int dev_pm_opp_add(struct device *dev, unsigned long freq,
return -EINVAL;
}
+static inline void dev_pm_opp_remove(struct device *dev, unsigned long freq)
+{
+}
+
static inline int dev_pm_opp_enable(struct device *dev, unsigned long freq)
{
return 0;
@@ -109,11 +114,16 @@ static inline struct srcu_notifier_head *dev_pm_opp_get_notifier(
#if defined(CONFIG_PM_OPP) && defined(CONFIG_OF)
int of_init_opp_table(struct device *dev);
+void of_free_opp_table(struct device *dev);
#else
static inline int of_init_opp_table(struct device *dev)
{
return -EINVAL;
}
+
+static inline void of_free_opp_table(struct device *dev)
+{
+}
#endif
#endif /* __LINUX_OPP_H__ */
diff --git a/include/linux/pm_qos.h b/include/linux/pm_qos.h
index 636e828..7b3ae0c 100644
--- a/include/linux/pm_qos.h
+++ b/include/linux/pm_qos.h
@@ -154,6 +154,23 @@ void dev_pm_qos_constraints_destroy(struct device *dev);
int dev_pm_qos_add_ancestor_request(struct device *dev,
struct dev_pm_qos_request *req,
enum dev_pm_qos_req_type type, s32 value);
+int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value);
+void dev_pm_qos_hide_latency_limit(struct device *dev);
+int dev_pm_qos_expose_flags(struct device *dev, s32 value);
+void dev_pm_qos_hide_flags(struct device *dev);
+int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set);
+s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev);
+int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val);
+
+static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
+{
+ return dev->power.qos->resume_latency_req->data.pnode.prio;
+}
+
+static inline s32 dev_pm_qos_requested_flags(struct device *dev)
+{
+ return dev->power.qos->flags_req->data.flr.flags;
+}
#else
static inline enum pm_qos_flags_status __dev_pm_qos_flags(struct device *dev,
s32 mask)
@@ -200,27 +217,6 @@ static inline int dev_pm_qos_add_ancestor_request(struct device *dev,
enum dev_pm_qos_req_type type,
s32 value)
{ return 0; }
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
-int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value);
-void dev_pm_qos_hide_latency_limit(struct device *dev);
-int dev_pm_qos_expose_flags(struct device *dev, s32 value);
-void dev_pm_qos_hide_flags(struct device *dev);
-int dev_pm_qos_update_flags(struct device *dev, s32 mask, bool set);
-s32 dev_pm_qos_get_user_latency_tolerance(struct device *dev);
-int dev_pm_qos_update_user_latency_tolerance(struct device *dev, s32 val);
-
-static inline s32 dev_pm_qos_requested_resume_latency(struct device *dev)
-{
- return dev->power.qos->resume_latency_req->data.pnode.prio;
-}
-
-static inline s32 dev_pm_qos_requested_flags(struct device *dev)
-{
- return dev->power.qos->flags_req->data.flr.flags;
-}
-#else
static inline int dev_pm_qos_expose_latency_limit(struct device *dev, s32 value)
{ return 0; }
static inline void dev_pm_qos_hide_latency_limit(struct device *dev) {}
diff --git a/include/linux/pm_runtime.h b/include/linux/pm_runtime.h
index 367f49b..eda4fee 100644
--- a/include/linux/pm_runtime.h
+++ b/include/linux/pm_runtime.h
@@ -35,16 +35,6 @@ extern int pm_generic_runtime_suspend(struct device *dev);
extern int pm_generic_runtime_resume(struct device *dev);
extern int pm_runtime_force_suspend(struct device *dev);
extern int pm_runtime_force_resume(struct device *dev);
-#else
-static inline bool queue_pm_work(struct work_struct *work) { return false; }
-
-static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
-static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
-static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
-static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
-#endif
-
-#ifdef CONFIG_PM_RUNTIME
extern int __pm_runtime_idle(struct device *dev, int rpmflags);
extern int __pm_runtime_suspend(struct device *dev, int rpmflags);
@@ -128,7 +118,14 @@ static inline void pm_runtime_mark_last_busy(struct device *dev)
ACCESS_ONCE(dev->power.last_busy) = jiffies;
}
-#else /* !CONFIG_PM_RUNTIME */
+#else /* !CONFIG_PM */
+
+static inline bool queue_pm_work(struct work_struct *work) { return false; }
+
+static inline int pm_generic_runtime_suspend(struct device *dev) { return 0; }
+static inline int pm_generic_runtime_resume(struct device *dev) { return 0; }
+static inline int pm_runtime_force_suspend(struct device *dev) { return 0; }
+static inline int pm_runtime_force_resume(struct device *dev) { return 0; }
static inline int __pm_runtime_idle(struct device *dev, int rpmflags)
{
@@ -179,7 +176,7 @@ static inline unsigned long pm_runtime_autosuspend_expiration(
static inline void pm_runtime_set_memalloc_noio(struct device *dev,
bool enable){}
-#endif /* !CONFIG_PM_RUNTIME */
+#endif /* !CONFIG_PM */
static inline int pm_runtime_idle(struct device *dev)
{
diff --git a/include/linux/printk.h b/include/linux/printk.h
index d78125f..c8f1703 100644
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -118,12 +118,13 @@ int no_printk(const char *fmt, ...)
#ifdef CONFIG_EARLY_PRINTK
extern asmlinkage __printf(1, 2)
void early_printk(const char *fmt, ...);
-void early_vprintk(const char *fmt, va_list ap);
#else
static inline __printf(1, 2) __cold
void early_printk(const char *s, ...) { }
#endif
+typedef int(*printk_func_t)(const char *fmt, va_list args);
+
#ifdef CONFIG_PRINTK
asmlinkage __printf(5, 0)
int vprintk_emit(int facility, int level,
diff --git a/include/linux/property.h b/include/linux/property.h
new file mode 100644
index 0000000..a6a3d98
--- /dev/null
+++ b/include/linux/property.h
@@ -0,0 +1,143 @@
+/*
+ * property.h - Unified device property interface.
+ *
+ * Copyright (C) 2014, Intel Corporation
+ * Authors: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+ * Mika Westerberg <mika.westerberg@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.
+ */
+
+#ifndef _LINUX_PROPERTY_H_
+#define _LINUX_PROPERTY_H_
+
+#include <linux/types.h>
+
+struct device;
+
+enum dev_prop_type {
+ DEV_PROP_U8,
+ DEV_PROP_U16,
+ DEV_PROP_U32,
+ DEV_PROP_U64,
+ DEV_PROP_STRING,
+ DEV_PROP_MAX,
+};
+
+bool device_property_present(struct device *dev, const char *propname);
+int device_property_read_u8_array(struct device *dev, const char *propname,
+ u8 *val, size_t nval);
+int device_property_read_u16_array(struct device *dev, const char *propname,
+ u16 *val, size_t nval);
+int device_property_read_u32_array(struct device *dev, const char *propname,
+ u32 *val, size_t nval);
+int device_property_read_u64_array(struct device *dev, const char *propname,
+ u64 *val, size_t nval);
+int device_property_read_string_array(struct device *dev, const char *propname,
+ const char **val, size_t nval);
+int device_property_read_string(struct device *dev, const char *propname,
+ const char **val);
+
+enum fwnode_type {
+ FWNODE_INVALID = 0,
+ FWNODE_OF,
+ FWNODE_ACPI,
+};
+
+struct fwnode_handle {
+ enum fwnode_type type;
+};
+
+bool fwnode_property_present(struct fwnode_handle *fwnode, const char *propname);
+int fwnode_property_read_u8_array(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val,
+ size_t nval);
+int fwnode_property_read_u16_array(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val,
+ size_t nval);
+int fwnode_property_read_u32_array(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val,
+ size_t nval);
+int fwnode_property_read_u64_array(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val,
+ size_t nval);
+int fwnode_property_read_string_array(struct fwnode_handle *fwnode,
+ const char *propname, const char **val,
+ size_t nval);
+int fwnode_property_read_string(struct fwnode_handle *fwnode,
+ const char *propname, const char **val);
+
+struct fwnode_handle *device_get_next_child_node(struct device *dev,
+ struct fwnode_handle *child);
+
+#define device_for_each_child_node(dev, child) \
+ for (child = device_get_next_child_node(dev, NULL); child; \
+ child = device_get_next_child_node(dev, child))
+
+void fwnode_handle_put(struct fwnode_handle *fwnode);
+
+unsigned int device_get_child_node_count(struct device *dev);
+
+static inline bool device_property_read_bool(struct device *dev,
+ const char *propname)
+{
+ return device_property_present(dev, propname);
+}
+
+static inline int device_property_read_u8(struct device *dev,
+ const char *propname, u8 *val)
+{
+ return device_property_read_u8_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u16(struct device *dev,
+ const char *propname, u16 *val)
+{
+ return device_property_read_u16_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u32(struct device *dev,
+ const char *propname, u32 *val)
+{
+ return device_property_read_u32_array(dev, propname, val, 1);
+}
+
+static inline int device_property_read_u64(struct device *dev,
+ const char *propname, u64 *val)
+{
+ return device_property_read_u64_array(dev, propname, val, 1);
+}
+
+static inline bool fwnode_property_read_bool(struct fwnode_handle *fwnode,
+ const char *propname)
+{
+ return fwnode_property_present(fwnode, propname);
+}
+
+static inline int fwnode_property_read_u8(struct fwnode_handle *fwnode,
+ const char *propname, u8 *val)
+{
+ return fwnode_property_read_u8_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u16(struct fwnode_handle *fwnode,
+ const char *propname, u16 *val)
+{
+ return fwnode_property_read_u16_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u32(struct fwnode_handle *fwnode,
+ const char *propname, u32 *val)
+{
+ return fwnode_property_read_u32_array(fwnode, propname, val, 1);
+}
+
+static inline int fwnode_property_read_u64(struct fwnode_handle *fwnode,
+ const char *propname, u64 *val)
+{
+ return fwnode_property_read_u64_array(fwnode, propname, val, 1);
+}
+
+#endif /* _LINUX_PROPERTY_H_ */
diff --git a/include/linux/ptrace.h b/include/linux/ptrace.h
index cc79eff..987a73a 100644
--- a/include/linux/ptrace.h
+++ b/include/linux/ptrace.h
@@ -52,7 +52,7 @@ extern void ptrace_notify(int exit_code);
extern void __ptrace_link(struct task_struct *child,
struct task_struct *new_parent);
extern void __ptrace_unlink(struct task_struct *child);
-extern void exit_ptrace(struct task_struct *tracer);
+extern void exit_ptrace(struct task_struct *tracer, struct list_head *dead);
#define PTRACE_MODE_READ 0x01
#define PTRACE_MODE_ATTACH 0x02
#define PTRACE_MODE_NOAUDIT 0x04
diff --git a/include/linux/pxa2xx_ssp.h b/include/linux/pxa2xx_ssp.h
index f2b4051..77aed9e 100644
--- a/include/linux/pxa2xx_ssp.h
+++ b/include/linux/pxa2xx_ssp.h
@@ -108,6 +108,25 @@
#define SSCR1_RxTresh(x) (((x) - 1) << 10) /* level [1..4] */
#endif
+/* QUARK_X1000 SSCR0 bit definition */
+#define QUARK_X1000_SSCR0_DSS (0x1F) /* Data Size Select (mask) */
+#define QUARK_X1000_SSCR0_DataSize(x) ((x) - 1) /* Data Size Select [4..32] */
+#define QUARK_X1000_SSCR0_FRF (0x3 << 5) /* FRame Format (mask) */
+#define QUARK_X1000_SSCR0_Motorola (0x0 << 5) /* Motorola's Serial Peripheral Interface (SPI) */
+
+#define RX_THRESH_QUARK_X1000_DFLT 1
+#define TX_THRESH_QUARK_X1000_DFLT 16
+
+#define QUARK_X1000_SSSR_TFL_MASK (0x1F << 8) /* Transmit FIFO Level mask */
+#define QUARK_X1000_SSSR_RFL_MASK (0x1F << 13) /* Receive FIFO Level mask */
+
+#define QUARK_X1000_SSCR1_TFT (0x1F << 6) /* Transmit FIFO Threshold (mask) */
+#define QUARK_X1000_SSCR1_TxTresh(x) (((x) - 1) << 6) /* level [1..32] */
+#define QUARK_X1000_SSCR1_RFT (0x1F << 11) /* Receive FIFO Threshold (mask) */
+#define QUARK_X1000_SSCR1_RxTresh(x) (((x) - 1) << 11) /* level [1..32] */
+#define QUARK_X1000_SSCR1_STRF (1 << 17) /* Select FIFO or EFWR */
+#define QUARK_X1000_SSCR1_EFWR (1 << 16) /* Enable FIFO Write/Read */
+
/* extra bits in PXA255, PXA26x and PXA27x SSP ports */
#define SSCR0_TISSP (1 << 4) /* TI Sync Serial Protocol */
#define SSCR0_PSP (3 << 4) /* PSP - Programmable Serial Protocol */
@@ -175,6 +194,7 @@ enum pxa_ssp_type {
PXA910_SSP,
CE4100_SSP,
LPSS_SSP,
+ QUARK_X1000_SSP,
};
struct ssp_device {
diff --git a/include/linux/quota.h b/include/linux/quota.h
index 80d345a..50978b7 100644
--- a/include/linux/quota.h
+++ b/include/linux/quota.h
@@ -56,6 +56,11 @@ enum quota_type {
PRJQUOTA = 2, /* element used for project quotas */
};
+/* Masks for quota types when used as a bitmask */
+#define QTYPE_MASK_USR (1 << USRQUOTA)
+#define QTYPE_MASK_GRP (1 << GRPQUOTA)
+#define QTYPE_MASK_PRJ (1 << PRJQUOTA)
+
typedef __kernel_uid32_t qid_t; /* Type in which we store ids in memory */
typedef long long qsize_t; /* Type in which we store sizes */
diff --git a/include/linux/quotaops.h b/include/linux/quotaops.h
index 1d3eee5..f23538a 100644
--- a/include/linux/quotaops.h
+++ b/include/linux/quotaops.h
@@ -64,10 +64,10 @@ void dquot_destroy(struct dquot *dquot);
int __dquot_alloc_space(struct inode *inode, qsize_t number, int flags);
void __dquot_free_space(struct inode *inode, qsize_t number, int flags);
-int dquot_alloc_inode(const struct inode *inode);
+int dquot_alloc_inode(struct inode *inode);
int dquot_claim_space_nodirty(struct inode *inode, qsize_t number);
-void dquot_free_inode(const struct inode *inode);
+void dquot_free_inode(struct inode *inode);
void dquot_reclaim_space_nodirty(struct inode *inode, qsize_t number);
int dquot_disable(struct super_block *sb, int type, unsigned int flags);
@@ -213,12 +213,12 @@ static inline void dquot_drop(struct inode *inode)
{
}
-static inline int dquot_alloc_inode(const struct inode *inode)
+static inline int dquot_alloc_inode(struct inode *inode)
{
return 0;
}
-static inline void dquot_free_inode(const struct inode *inode)
+static inline void dquot_free_inode(struct inode *inode)
{
}
diff --git a/include/linux/rcupdate.h b/include/linux/rcupdate.h
index 53ff1a7..ed4f593 100644
--- a/include/linux/rcupdate.h
+++ b/include/linux/rcupdate.h
@@ -57,7 +57,7 @@ enum rcutorture_type {
INVALID_RCU_FLAVOR
};
-#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
void rcutorture_get_gp_data(enum rcutorture_type test_type, int *flags,
unsigned long *gpnum, unsigned long *completed);
void rcutorture_record_test_transition(void);
@@ -260,7 +260,7 @@ static inline int rcu_preempt_depth(void)
void rcu_init(void);
void rcu_sched_qs(void);
void rcu_bh_qs(void);
-void rcu_check_callbacks(int cpu, int user);
+void rcu_check_callbacks(int user);
struct notifier_block;
void rcu_idle_enter(void);
void rcu_idle_exit(void);
@@ -348,8 +348,8 @@ extern struct srcu_struct tasks_rcu_exit_srcu;
*/
#define cond_resched_rcu_qs() \
do { \
- rcu_note_voluntary_context_switch(current); \
- cond_resched(); \
+ if (!cond_resched()) \
+ rcu_note_voluntary_context_switch(current); \
} while (0)
#if defined(CONFIG_DEBUG_LOCK_ALLOC) || defined(CONFIG_RCU_TRACE) || defined(CONFIG_SMP)
@@ -365,7 +365,7 @@ typedef void call_rcu_func_t(struct rcu_head *head,
void (*func)(struct rcu_head *head));
void wait_rcu_gp(call_rcu_func_t crf);
-#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
#include <linux/rcutree.h>
#elif defined(CONFIG_TINY_RCU)
#include <linux/rcutiny.h>
@@ -867,7 +867,7 @@ static inline void rcu_preempt_sleep_check(void)
*
* In non-preemptible RCU implementations (TREE_RCU and TINY_RCU),
* it is illegal to block while in an RCU read-side critical section.
- * In preemptible RCU implementations (TREE_PREEMPT_RCU) in CONFIG_PREEMPT
+ * In preemptible RCU implementations (PREEMPT_RCU) in CONFIG_PREEMPT
* kernel builds, RCU read-side critical sections may be preempted,
* but explicit blocking is illegal. Finally, in preemptible RCU
* implementations in real-time (with -rt patchset) kernel builds, RCU
@@ -902,7 +902,9 @@ static inline void rcu_read_lock(void)
* Unfortunately, this function acquires the scheduler's runqueue and
* priority-inheritance spinlocks. This means that deadlock could result
* if the caller of rcu_read_unlock() already holds one of these locks or
- * any lock that is ever acquired while holding them.
+ * any lock that is ever acquired while holding them; or any lock which
+ * can be taken from interrupt context because rcu_boost()->rt_mutex_lock()
+ * does not disable irqs while taking ->wait_lock.
*
* That said, RCU readers are never priority boosted unless they were
* preempted. Therefore, one way to avoid deadlock is to make sure
@@ -1062,6 +1064,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
*/
#define RCU_INIT_POINTER(p, v) \
do { \
+ rcu_dereference_sparse(p, __rcu); \
p = RCU_INITIALIZER(v); \
} while (0)
@@ -1118,7 +1121,7 @@ static inline notrace void rcu_read_unlock_sched_notrace(void)
__kfree_rcu(&((ptr)->rcu_head), offsetof(typeof(*(ptr)), rcu_head))
#if defined(CONFIG_TINY_RCU) || defined(CONFIG_RCU_NOCB_CPU_ALL)
-static inline int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
+static inline int rcu_needs_cpu(unsigned long *delta_jiffies)
{
*delta_jiffies = ULONG_MAX;
return 0;
diff --git a/include/linux/rcutiny.h b/include/linux/rcutiny.h
index 38cc5b1..0e53662 100644
--- a/include/linux/rcutiny.h
+++ b/include/linux/rcutiny.h
@@ -78,7 +78,7 @@ static inline void kfree_call_rcu(struct rcu_head *head,
call_rcu(head, func);
}
-static inline void rcu_note_context_switch(int cpu)
+static inline void rcu_note_context_switch(void)
{
rcu_sched_qs();
}
diff --git a/include/linux/rcutree.h b/include/linux/rcutree.h
index 3e2f5d4..5295379 100644
--- a/include/linux/rcutree.h
+++ b/include/linux/rcutree.h
@@ -30,9 +30,9 @@
#ifndef __LINUX_RCUTREE_H
#define __LINUX_RCUTREE_H
-void rcu_note_context_switch(int cpu);
+void rcu_note_context_switch(void);
#ifndef CONFIG_RCU_NOCB_CPU_ALL
-int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies);
+int rcu_needs_cpu(unsigned long *delta_jiffies);
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
void rcu_cpu_stall_reset(void);
@@ -43,7 +43,7 @@ void rcu_cpu_stall_reset(void);
*/
static inline void rcu_virt_note_context_switch(int cpu)
{
- rcu_note_context_switch(cpu);
+ rcu_note_context_switch();
}
void synchronize_rcu_bh(void);
diff --git a/include/linux/regmap.h b/include/linux/regmap.h
index c5ed83f..4419b99 100644
--- a/include/linux/regmap.h
+++ b/include/linux/regmap.h
@@ -27,6 +27,7 @@ struct spmi_device;
struct regmap;
struct regmap_range_cfg;
struct regmap_field;
+struct snd_ac97;
/* An enum of all the supported cache types */
enum regcache_type {
@@ -340,6 +341,8 @@ struct regmap *regmap_init_spmi_ext(struct spmi_device *dev,
struct regmap *regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs,
const struct regmap_config *config);
+struct regmap *regmap_init_ac97(struct snd_ac97 *ac97,
+ const struct regmap_config *config);
struct regmap *devm_regmap_init(struct device *dev,
const struct regmap_bus *bus,
@@ -356,6 +359,10 @@ struct regmap *devm_regmap_init_spmi_ext(struct spmi_device *dev,
struct regmap *devm_regmap_init_mmio_clk(struct device *dev, const char *clk_id,
void __iomem *regs,
const struct regmap_config *config);
+struct regmap *devm_regmap_init_ac97(struct snd_ac97 *ac97,
+ const struct regmap_config *config);
+
+bool regmap_ac97_default_volatile(struct device *dev, unsigned int reg);
/**
* regmap_init_mmio(): Initialise register map
diff --git a/include/linux/regulator/consumer.h b/include/linux/regulator/consumer.h
index f540b14..d17e1ff 100644
--- a/include/linux/regulator/consumer.h
+++ b/include/linux/regulator/consumer.h
@@ -101,6 +101,8 @@ struct regmap;
* Data passed is "struct pre_voltage_change_data"
* ABORT_VOLTAGE_CHANGE Regulator voltage change failed for some reason.
* Data passed is old voltage cast to (void *).
+ * PRE_DISABLE Regulator is about to be disabled
+ * ABORT_DISABLE Regulator disable failed for some reason
*
* NOTE: These events can be OR'ed together when passed into handler.
*/
@@ -115,6 +117,8 @@ struct regmap;
#define REGULATOR_EVENT_DISABLE 0x80
#define REGULATOR_EVENT_PRE_VOLTAGE_CHANGE 0x100
#define REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE 0x200
+#define REGULATOR_EVENT_PRE_DISABLE 0x400
+#define REGULATOR_EVENT_ABORT_DISABLE 0x800
/**
* struct pre_voltage_change_data - Data sent with PRE_VOLTAGE_CHANGE event
@@ -284,7 +288,7 @@ devm_regulator_get(struct device *dev, const char *id)
static inline struct regulator *__must_check
regulator_get_exclusive(struct device *dev, const char *id)
{
- return NULL;
+ return ERR_PTR(-ENODEV);
}
static inline struct regulator *__must_check
diff --git a/include/linux/regulator/driver.h b/include/linux/regulator/driver.h
index fc0ee0c..5f1e9ca 100644
--- a/include/linux/regulator/driver.h
+++ b/include/linux/regulator/driver.h
@@ -243,6 +243,8 @@ enum regulator_type {
*
* @enable_time: Time taken for initial enable of regulator (in uS).
* @off_on_delay: guard time (in uS), before re-enabling a regulator
+ *
+ * @of_map_mode: Maps a hardware mode defined in a DeviceTree to a standard mode
*/
struct regulator_desc {
const char *name;
@@ -285,6 +287,8 @@ struct regulator_desc {
unsigned int enable_time;
unsigned int off_on_delay;
+
+ unsigned int (*of_map_mode)(unsigned int mode);
};
/**
@@ -301,6 +305,9 @@ struct regulator_desc {
* NULL).
* @regmap: regmap to use for core regmap helpers if dev_get_regulator() is
* insufficient.
+ * @ena_gpio_initialized: GPIO controlling regulator enable was properly
+ * initialized, meaning that >= 0 is a valid gpio
+ * identifier and < 0 is a non existent gpio.
* @ena_gpio: GPIO controlling regulator enable.
* @ena_gpio_invert: Sense for GPIO enable control.
* @ena_gpio_flags: Flags to use when calling gpio_request_one()
@@ -312,6 +319,7 @@ struct regulator_config {
struct device_node *of_node;
struct regmap *regmap;
+ bool ena_gpio_initialized;
int ena_gpio;
unsigned int ena_gpio_invert:1;
unsigned int ena_gpio_flags;
diff --git a/include/linux/regulator/of_regulator.h b/include/linux/regulator/of_regulator.h
index f921796..763953f 100644
--- a/include/linux/regulator/of_regulator.h
+++ b/include/linux/regulator/of_regulator.h
@@ -6,24 +6,29 @@
#ifndef __LINUX_OF_REG_H
#define __LINUX_OF_REG_H
+struct regulator_desc;
+
struct of_regulator_match {
const char *name;
void *driver_data;
struct regulator_init_data *init_data;
struct device_node *of_node;
+ const struct regulator_desc *desc;
};
#if defined(CONFIG_OF)
extern struct regulator_init_data
*of_get_regulator_init_data(struct device *dev,
- struct device_node *node);
+ struct device_node *node,
+ const struct regulator_desc *desc);
extern int of_regulator_match(struct device *dev, struct device_node *node,
struct of_regulator_match *matches,
unsigned int num_matches);
#else
static inline struct regulator_init_data
*of_get_regulator_init_data(struct device *dev,
- struct device_node *node)
+ struct device_node *node,
+ const struct regulator_desc *desc)
{
return NULL;
}
diff --git a/include/linux/res_counter.h b/include/linux/res_counter.h
deleted file mode 100644
index 56b7bc3..0000000
--- a/include/linux/res_counter.h
+++ /dev/null
@@ -1,223 +0,0 @@
-#ifndef __RES_COUNTER_H__
-#define __RES_COUNTER_H__
-
-/*
- * Resource Counters
- * Contain common data types and routines for resource accounting
- *
- * Copyright 2007 OpenVZ SWsoft Inc
- *
- * Author: Pavel Emelianov <xemul@openvz.org>
- *
- * See Documentation/cgroups/resource_counter.txt for more
- * info about what this counter is.
- */
-
-#include <linux/spinlock.h>
-#include <linux/errno.h>
-
-/*
- * The core object. the cgroup that wishes to account for some
- * resource may include this counter into its structures and use
- * the helpers described beyond
- */
-
-struct res_counter {
- /*
- * the current resource consumption level
- */
- unsigned long long usage;
- /*
- * the maximal value of the usage from the counter creation
- */
- unsigned long long max_usage;
- /*
- * the limit that usage cannot exceed
- */
- unsigned long long limit;
- /*
- * the limit that usage can be exceed
- */
- unsigned long long soft_limit;
- /*
- * the number of unsuccessful attempts to consume the resource
- */
- unsigned long long failcnt;
- /*
- * the lock to protect all of the above.
- * the routines below consider this to be IRQ-safe
- */
- spinlock_t lock;
- /*
- * Parent counter, used for hierarchial resource accounting
- */
- struct res_counter *parent;
-};
-
-#define RES_COUNTER_MAX ULLONG_MAX
-
-/**
- * Helpers to interact with userspace
- * res_counter_read_u64() - returns the value of the specified member.
- * res_counter_read/_write - put/get the specified fields from the
- * res_counter struct to/from the user
- *
- * @counter: the counter in question
- * @member: the field to work with (see RES_xxx below)
- * @buf: the buffer to opeate on,...
- * @nbytes: its size...
- * @pos: and the offset.
- */
-
-u64 res_counter_read_u64(struct res_counter *counter, int member);
-
-ssize_t res_counter_read(struct res_counter *counter, int member,
- const char __user *buf, size_t nbytes, loff_t *pos,
- int (*read_strategy)(unsigned long long val, char *s));
-
-int res_counter_memparse_write_strategy(const char *buf,
- unsigned long long *res);
-
-/*
- * the field descriptors. one for each member of res_counter
- */
-
-enum {
- RES_USAGE,
- RES_MAX_USAGE,
- RES_LIMIT,
- RES_FAILCNT,
- RES_SOFT_LIMIT,
-};
-
-/*
- * helpers for accounting
- */
-
-void res_counter_init(struct res_counter *counter, struct res_counter *parent);
-
-/*
- * charge - try to consume more resource.
- *
- * @counter: the counter
- * @val: the amount of the resource. each controller defines its own
- * units, e.g. numbers, bytes, Kbytes, etc
- *
- * returns 0 on success and <0 if the counter->usage will exceed the
- * counter->limit
- *
- * charge_nofail works the same, except that it charges the resource
- * counter unconditionally, and returns < 0 if the after the current
- * charge we are over limit.
- */
-
-int __must_check res_counter_charge(struct res_counter *counter,
- unsigned long val, struct res_counter **limit_fail_at);
-int res_counter_charge_nofail(struct res_counter *counter,
- unsigned long val, struct res_counter **limit_fail_at);
-
-/*
- * uncharge - tell that some portion of the resource is released
- *
- * @counter: the counter
- * @val: the amount of the resource
- *
- * these calls check for usage underflow and show a warning on the console
- *
- * returns the total charges still present in @counter.
- */
-
-u64 res_counter_uncharge(struct res_counter *counter, unsigned long val);
-
-u64 res_counter_uncharge_until(struct res_counter *counter,
- struct res_counter *top,
- unsigned long val);
-/**
- * res_counter_margin - calculate chargeable space of a counter
- * @cnt: the counter
- *
- * Returns the difference between the hard limit and the current usage
- * of resource counter @cnt.
- */
-static inline unsigned long long res_counter_margin(struct res_counter *cnt)
-{
- unsigned long long margin;
- unsigned long flags;
-
- spin_lock_irqsave(&cnt->lock, flags);
- if (cnt->limit > cnt->usage)
- margin = cnt->limit - cnt->usage;
- else
- margin = 0;
- spin_unlock_irqrestore(&cnt->lock, flags);
- return margin;
-}
-
-/**
- * Get the difference between the usage and the soft limit
- * @cnt: The counter
- *
- * Returns 0 if usage is less than or equal to soft limit
- * The difference between usage and soft limit, otherwise.
- */
-static inline unsigned long long
-res_counter_soft_limit_excess(struct res_counter *cnt)
-{
- unsigned long long excess;
- unsigned long flags;
-
- spin_lock_irqsave(&cnt->lock, flags);
- if (cnt->usage <= cnt->soft_limit)
- excess = 0;
- else
- excess = cnt->usage - cnt->soft_limit;
- spin_unlock_irqrestore(&cnt->lock, flags);
- return excess;
-}
-
-static inline void res_counter_reset_max(struct res_counter *cnt)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cnt->lock, flags);
- cnt->max_usage = cnt->usage;
- spin_unlock_irqrestore(&cnt->lock, flags);
-}
-
-static inline void res_counter_reset_failcnt(struct res_counter *cnt)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cnt->lock, flags);
- cnt->failcnt = 0;
- spin_unlock_irqrestore(&cnt->lock, flags);
-}
-
-static inline int res_counter_set_limit(struct res_counter *cnt,
- unsigned long long limit)
-{
- unsigned long flags;
- int ret = -EBUSY;
-
- spin_lock_irqsave(&cnt->lock, flags);
- if (cnt->usage <= limit) {
- cnt->limit = limit;
- ret = 0;
- }
- spin_unlock_irqrestore(&cnt->lock, flags);
- return ret;
-}
-
-static inline int
-res_counter_set_soft_limit(struct res_counter *cnt,
- unsigned long long soft_limit)
-{
- unsigned long flags;
-
- spin_lock_irqsave(&cnt->lock, flags);
- cnt->soft_limit = soft_limit;
- spin_unlock_irqrestore(&cnt->lock, flags);
- return 0;
-}
-
-#endif
diff --git a/include/linux/reset-controller.h b/include/linux/reset-controller.h
index 41a4695f..ce6b962 100644
--- a/include/linux/reset-controller.h
+++ b/include/linux/reset-controller.h
@@ -12,11 +12,13 @@ struct reset_controller_dev;
* things to reset the device
* @assert: manually assert the reset line, if supported
* @deassert: manually deassert the reset line, if supported
+ * @status: return the status of the reset line, if supported
*/
struct reset_control_ops {
int (*reset)(struct reset_controller_dev *rcdev, unsigned long id);
int (*assert)(struct reset_controller_dev *rcdev, unsigned long id);
int (*deassert)(struct reset_controller_dev *rcdev, unsigned long id);
+ int (*status)(struct reset_controller_dev *rcdev, unsigned long id);
};
struct module;
diff --git a/include/linux/reset.h b/include/linux/reset.h
index 349f150..da5602b 100644
--- a/include/linux/reset.h
+++ b/include/linux/reset.h
@@ -10,6 +10,7 @@ struct reset_control;
int reset_control_reset(struct reset_control *rstc);
int reset_control_assert(struct reset_control *rstc);
int reset_control_deassert(struct reset_control *rstc);
+int reset_control_status(struct reset_control *rstc);
struct reset_control *reset_control_get(struct device *dev, const char *id);
void reset_control_put(struct reset_control *rstc);
@@ -57,6 +58,12 @@ static inline int reset_control_deassert(struct reset_control *rstc)
return 0;
}
+static inline int reset_control_status(struct reset_control *rstc)
+{
+ WARN_ON(1);
+ return 0;
+}
+
static inline void reset_control_put(struct reset_control *rstc)
{
WARN_ON(1);
diff --git a/include/linux/rtc.h b/include/linux/rtc.h
index c2c2897..6d6be09 100644
--- a/include/linux/rtc.h
+++ b/include/linux/rtc.h
@@ -19,11 +19,28 @@
extern int rtc_month_days(unsigned int month, unsigned int year);
extern int rtc_year_days(unsigned int day, unsigned int month, unsigned int year);
extern int rtc_valid_tm(struct rtc_time *tm);
-extern int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time);
-extern void rtc_time_to_tm(unsigned long time, struct rtc_time *tm);
+extern time64_t rtc_tm_to_time64(struct rtc_time *tm);
+extern void rtc_time64_to_tm(time64_t time, struct rtc_time *tm);
ktime_t rtc_tm_to_ktime(struct rtc_time tm);
struct rtc_time rtc_ktime_to_tm(ktime_t kt);
+/**
+ * Deprecated. Use rtc_time64_to_tm().
+ */
+static inline void rtc_time_to_tm(unsigned long time, struct rtc_time *tm)
+{
+ rtc_time64_to_tm(time, tm);
+}
+
+/**
+ * Deprecated. Use rtc_tm_to_time64().
+ */
+static inline int rtc_tm_to_time(struct rtc_time *tm, unsigned long *time)
+{
+ *time = rtc_tm_to_time64(tm);
+
+ return 0;
+}
#include <linux/device.h>
#include <linux/seq_file.h>
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 5e344bb..55f5ee7 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -243,6 +243,43 @@ extern char ___assert_task_state[1 - 2*!!(
((task->state & TASK_UNINTERRUPTIBLE) != 0 && \
(task->flags & PF_FROZEN) == 0)
+#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
+
+#define __set_task_state(tsk, state_value) \
+ do { \
+ (tsk)->task_state_change = _THIS_IP_; \
+ (tsk)->state = (state_value); \
+ } while (0)
+#define set_task_state(tsk, state_value) \
+ do { \
+ (tsk)->task_state_change = _THIS_IP_; \
+ set_mb((tsk)->state, (state_value)); \
+ } while (0)
+
+/*
+ * set_current_state() includes a barrier so that the write of current->state
+ * is correctly serialised wrt the caller's subsequent test of whether to
+ * actually sleep:
+ *
+ * set_current_state(TASK_UNINTERRUPTIBLE);
+ * if (do_i_need_to_sleep())
+ * schedule();
+ *
+ * If the caller does not need such serialisation then use __set_current_state()
+ */
+#define __set_current_state(state_value) \
+ do { \
+ current->task_state_change = _THIS_IP_; \
+ current->state = (state_value); \
+ } while (0)
+#define set_current_state(state_value) \
+ do { \
+ current->task_state_change = _THIS_IP_; \
+ set_mb(current->state, (state_value)); \
+ } while (0)
+
+#else
+
#define __set_task_state(tsk, state_value) \
do { (tsk)->state = (state_value); } while (0)
#define set_task_state(tsk, state_value) \
@@ -259,11 +296,13 @@ extern char ___assert_task_state[1 - 2*!!(
*
* If the caller does not need such serialisation then use __set_current_state()
*/
-#define __set_current_state(state_value) \
+#define __set_current_state(state_value) \
do { current->state = (state_value); } while (0)
-#define set_current_state(state_value) \
+#define set_current_state(state_value) \
set_mb(current->state, (state_value))
+#endif
+
/* Task command name length */
#define TASK_COMM_LEN 16
@@ -1278,9 +1317,9 @@ struct task_struct {
union rcu_special rcu_read_unlock_special;
struct list_head rcu_node_entry;
#endif /* #ifdef CONFIG_PREEMPT_RCU */
-#ifdef CONFIG_TREE_PREEMPT_RCU
+#ifdef CONFIG_PREEMPT_RCU
struct rcu_node *rcu_blocked_node;
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_TASKS_RCU
unsigned long rcu_tasks_nvcsw;
bool rcu_tasks_holdout;
@@ -1558,28 +1597,23 @@ struct task_struct {
struct numa_group *numa_group;
/*
- * Exponential decaying average of faults on a per-node basis.
- * Scheduling placement decisions are made based on the these counts.
- * The values remain static for the duration of a PTE scan
+ * numa_faults is an array split into four regions:
+ * faults_memory, faults_cpu, faults_memory_buffer, faults_cpu_buffer
+ * in this precise order.
+ *
+ * faults_memory: Exponential decaying average of faults on a per-node
+ * basis. Scheduling placement decisions are made based on these
+ * counts. The values remain static for the duration of a PTE scan.
+ * faults_cpu: Track the nodes the process was running on when a NUMA
+ * hinting fault was incurred.
+ * faults_memory_buffer and faults_cpu_buffer: Record faults per node
+ * during the current scan window. When the scan completes, the counts
+ * in faults_memory and faults_cpu decay and these values are copied.
*/
- unsigned long *numa_faults_memory;
+ unsigned long *numa_faults;
unsigned long total_numa_faults;
/*
- * numa_faults_buffer records faults per node during the current
- * scan window. When the scan completes, the counts in
- * numa_faults_memory decay and these values are copied.
- */
- unsigned long *numa_faults_buffer_memory;
-
- /*
- * Track the nodes the process was running on when a NUMA hinting
- * fault was incurred.
- */
- unsigned long *numa_faults_cpu;
- unsigned long *numa_faults_buffer_cpu;
-
- /*
* numa_faults_locality tracks if faults recorded during the last
* scan window were remote/local. The task scan period is adapted
* based on the locality of the faults with different weights
@@ -1661,6 +1695,9 @@ struct task_struct {
unsigned int sequential_io;
unsigned int sequential_io_avg;
#endif
+#ifdef CONFIG_DEBUG_ATOMIC_SLEEP
+ unsigned long task_state_change;
+#endif
};
/* Future-safe accessor for struct task_struct's cpus_allowed. */
@@ -2052,6 +2089,10 @@ static inline void tsk_restore_flags(struct task_struct *task,
task->flags |= orig_flags & flags;
}
+extern int cpuset_cpumask_can_shrink(const struct cpumask *cur,
+ const struct cpumask *trial);
+extern int task_can_attach(struct task_struct *p,
+ const struct cpumask *cs_cpus_allowed);
#ifdef CONFIG_SMP
extern void do_set_cpus_allowed(struct task_struct *p,
const struct cpumask *new_mask);
@@ -2760,7 +2801,7 @@ static inline int signal_pending_state(long state, struct task_struct *p)
extern int _cond_resched(void);
#define cond_resched() ({ \
- __might_sleep(__FILE__, __LINE__, 0); \
+ ___might_sleep(__FILE__, __LINE__, 0); \
_cond_resched(); \
})
@@ -2773,14 +2814,14 @@ extern int __cond_resched_lock(spinlock_t *lock);
#endif
#define cond_resched_lock(lock) ({ \
- __might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET); \
+ ___might_sleep(__FILE__, __LINE__, PREEMPT_LOCK_OFFSET);\
__cond_resched_lock(lock); \
})
extern int __cond_resched_softirq(void);
#define cond_resched_softirq() ({ \
- __might_sleep(__FILE__, __LINE__, SOFTIRQ_DISABLE_OFFSET); \
+ ___might_sleep(__FILE__, __LINE__, SOFTIRQ_DISABLE_OFFSET); \
__cond_resched_softirq(); \
})
diff --git a/include/linux/seq_buf.h b/include/linux/seq_buf.h
new file mode 100644
index 0000000..9aafe0e
--- /dev/null
+++ b/include/linux/seq_buf.h
@@ -0,0 +1,136 @@
+#ifndef _LINUX_SEQ_BUF_H
+#define _LINUX_SEQ_BUF_H
+
+#include <linux/fs.h>
+
+/*
+ * Trace sequences are used to allow a function to call several other functions
+ * to create a string of data to use.
+ */
+
+/**
+ * seq_buf - seq buffer structure
+ * @buffer: pointer to the buffer
+ * @size: size of the buffer
+ * @len: the amount of data inside the buffer
+ * @readpos: The next position to read in the buffer.
+ */
+struct seq_buf {
+ char *buffer;
+ size_t size;
+ size_t len;
+ loff_t readpos;
+};
+
+static inline void seq_buf_clear(struct seq_buf *s)
+{
+ s->len = 0;
+ s->readpos = 0;
+}
+
+static inline void
+seq_buf_init(struct seq_buf *s, unsigned char *buf, unsigned int size)
+{
+ s->buffer = buf;
+ s->size = size;
+ seq_buf_clear(s);
+}
+
+/*
+ * seq_buf have a buffer that might overflow. When this happens
+ * the len and size are set to be equal.
+ */
+static inline bool
+seq_buf_has_overflowed(struct seq_buf *s)
+{
+ return s->len > s->size;
+}
+
+static inline void
+seq_buf_set_overflow(struct seq_buf *s)
+{
+ s->len = s->size + 1;
+}
+
+/*
+ * How much buffer is left on the seq_buf?
+ */
+static inline unsigned int
+seq_buf_buffer_left(struct seq_buf *s)
+{
+ if (seq_buf_has_overflowed(s))
+ return 0;
+
+ return s->size - s->len;
+}
+
+/* How much buffer was written? */
+static inline unsigned int seq_buf_used(struct seq_buf *s)
+{
+ return min(s->len, s->size);
+}
+
+/**
+ * seq_buf_get_buf - get buffer to write arbitrary data to
+ * @s: the seq_buf handle
+ * @bufp: the beginning of the buffer is stored here
+ *
+ * Return the number of bytes available in the buffer, or zero if
+ * there's no space.
+ */
+static inline size_t seq_buf_get_buf(struct seq_buf *s, char **bufp)
+{
+ WARN_ON(s->len > s->size + 1);
+
+ if (s->len < s->size) {
+ *bufp = s->buffer + s->len;
+ return s->size - s->len;
+ }
+
+ *bufp = NULL;
+ return 0;
+}
+
+/**
+ * seq_buf_commit - commit data to the buffer
+ * @s: the seq_buf handle
+ * @num: the number of bytes to commit
+ *
+ * Commit @num bytes of data written to a buffer previously acquired
+ * by seq_buf_get. To signal an error condition, or that the data
+ * didn't fit in the available space, pass a negative @num value.
+ */
+static inline void seq_buf_commit(struct seq_buf *s, int num)
+{
+ if (num < 0) {
+ seq_buf_set_overflow(s);
+ } else {
+ /* num must be negative on overflow */
+ BUG_ON(s->len + num > s->size);
+ s->len += num;
+ }
+}
+
+extern __printf(2, 3)
+int seq_buf_printf(struct seq_buf *s, const char *fmt, ...);
+extern __printf(2, 0)
+int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args);
+extern int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s);
+extern int seq_buf_to_user(struct seq_buf *s, char __user *ubuf,
+ int cnt);
+extern int seq_buf_puts(struct seq_buf *s, const char *str);
+extern int seq_buf_putc(struct seq_buf *s, unsigned char c);
+extern int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len);
+extern int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
+ unsigned int len);
+extern int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc);
+
+extern int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
+ int nmaskbits);
+
+#ifdef CONFIG_BINARY_PRINTF
+extern int
+seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary);
+#endif
+
+#endif /* _LINUX_SEQ_BUF_H */
diff --git a/include/linux/seq_file.h b/include/linux/seq_file.h
index 52e0097..cf6a9da 100644
--- a/include/linux/seq_file.h
+++ b/include/linux/seq_file.h
@@ -43,6 +43,21 @@ struct seq_operations {
#define SEQ_SKIP 1
/**
+ * seq_has_overflowed - check if the buffer has overflowed
+ * @m: the seq_file handle
+ *
+ * seq_files have a buffer which may overflow. When this happens a larger
+ * buffer is reallocated and all the data will be printed again.
+ * The overflow state is true when m->count == m->size.
+ *
+ * Returns true if the buffer received more than it can hold.
+ */
+static inline bool seq_has_overflowed(struct seq_file *m)
+{
+ return m->count == m->size;
+}
+
+/**
* seq_get_buf - get buffer to write arbitrary data to
* @m: the seq_file handle
* @bufp: the beginning of the buffer is stored here
diff --git a/include/linux/slab.h b/include/linux/slab.h
index c265bec..8a2457d 100644
--- a/include/linux/slab.h
+++ b/include/linux/slab.h
@@ -513,10 +513,6 @@ struct memcg_cache_params {
int memcg_update_all_caches(int num_memcgs);
-struct seq_file;
-int cache_show(struct kmem_cache *s, struct seq_file *m);
-void print_slabinfo_header(struct seq_file *m);
-
/**
* kmalloc_array - allocate memory for an array.
* @n: number of elements.
diff --git a/include/linux/spi/spi.h b/include/linux/spi/spi.h
index 46d188a..a6ef2a8 100644
--- a/include/linux/spi/spi.h
+++ b/include/linux/spi/spi.h
@@ -1049,4 +1049,10 @@ spi_unregister_device(struct spi_device *spi)
extern const struct spi_device_id *
spi_get_device_id(const struct spi_device *sdev);
+static inline bool
+spi_transfer_is_last(struct spi_master *master, struct spi_transfer *xfer)
+{
+ return list_is_last(&xfer->transfer_list, &master->cur_msg->transfers);
+}
+
#endif /* __LINUX_SPI_H */
diff --git a/include/linux/sunrpc/auth.h b/include/linux/sunrpc/auth.h
index 8e03007..a7cbb57 100644
--- a/include/linux/sunrpc/auth.h
+++ b/include/linux/sunrpc/auth.h
@@ -53,7 +53,7 @@ struct rpc_cred {
struct rcu_head cr_rcu;
struct rpc_auth * cr_auth;
const struct rpc_credops *cr_ops;
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
unsigned long cr_magic; /* 0x0f4aa4f0 */
#endif
unsigned long cr_expire; /* when to gc */
diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h
index 70736b9..d86acc6 100644
--- a/include/linux/sunrpc/clnt.h
+++ b/include/linux/sunrpc/clnt.h
@@ -63,6 +63,9 @@ struct rpc_clnt {
struct rpc_rtt cl_rtt_default;
struct rpc_timeout cl_timeout_default;
const struct rpc_program *cl_program;
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
+ struct dentry *cl_debugfs; /* debugfs directory */
+#endif
};
/*
@@ -176,5 +179,6 @@ size_t rpc_peeraddr(struct rpc_clnt *, struct sockaddr *, size_t);
const char *rpc_peeraddr2str(struct rpc_clnt *, enum rpc_display_format_t);
int rpc_localaddr(struct rpc_clnt *, struct sockaddr *, size_t);
+const char *rpc_proc_name(const struct rpc_task *task);
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_CLNT_H */
diff --git a/include/linux/sunrpc/debug.h b/include/linux/sunrpc/debug.h
index 9385bd7..c57d8ea 100644
--- a/include/linux/sunrpc/debug.h
+++ b/include/linux/sunrpc/debug.h
@@ -10,22 +10,10 @@
#include <uapi/linux/sunrpc/debug.h>
-
-/*
- * Enable RPC debugging/profiling.
- */
-#ifdef CONFIG_SUNRPC_DEBUG
-#define RPC_DEBUG
-#endif
-#ifdef CONFIG_TRACEPOINTS
-#define RPC_TRACEPOINTS
-#endif
-/* #define RPC_PROFILE */
-
/*
* Debugging macros etc
*/
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
extern unsigned int rpc_debug;
extern unsigned int nfs_debug;
extern unsigned int nfsd_debug;
@@ -36,7 +24,7 @@ extern unsigned int nlm_debug;
#define dprintk_rcu(args...) dfprintk_rcu(FACILITY, ## args)
#undef ifdebug
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define ifdebug(fac) if (unlikely(rpc_debug & RPCDBG_##fac))
# define dfprintk(fac, args...) \
@@ -65,9 +53,55 @@ extern unsigned int nlm_debug;
/*
* Sysctl interface for RPC debugging
*/
-#ifdef RPC_DEBUG
+
+struct rpc_clnt;
+struct rpc_xprt;
+
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
void rpc_register_sysctl(void);
void rpc_unregister_sysctl(void);
+int sunrpc_debugfs_init(void);
+void sunrpc_debugfs_exit(void);
+int rpc_clnt_debugfs_register(struct rpc_clnt *);
+void rpc_clnt_debugfs_unregister(struct rpc_clnt *);
+int rpc_xprt_debugfs_register(struct rpc_xprt *);
+void rpc_xprt_debugfs_unregister(struct rpc_xprt *);
+#else
+static inline int
+sunrpc_debugfs_init(void)
+{
+ return 0;
+}
+
+static inline void
+sunrpc_debugfs_exit(void)
+{
+ return;
+}
+
+static inline int
+rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
+{
+ return 0;
+}
+
+static inline void
+rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
+{
+ return;
+}
+
+static inline int
+rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
+{
+ return 0;
+}
+
+static inline void
+rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt)
+{
+ return;
+}
#endif
#endif /* _LINUX_SUNRPC_DEBUG_H_ */
diff --git a/include/linux/sunrpc/metrics.h b/include/linux/sunrpc/metrics.h
index 1565bbe..eecb5a7 100644
--- a/include/linux/sunrpc/metrics.h
+++ b/include/linux/sunrpc/metrics.h
@@ -27,10 +27,13 @@
#include <linux/seq_file.h>
#include <linux/ktime.h>
+#include <linux/spinlock.h>
#define RPC_IOSTATS_VERS "1.0"
struct rpc_iostats {
+ spinlock_t om_lock;
+
/*
* These counters give an idea about how many request
* transmissions are required, on average, to complete that
diff --git a/include/linux/sunrpc/sched.h b/include/linux/sunrpc/sched.h
index 1a89599..5f1e6bd 100644
--- a/include/linux/sunrpc/sched.h
+++ b/include/linux/sunrpc/sched.h
@@ -79,7 +79,7 @@ struct rpc_task {
unsigned short tk_flags; /* misc flags */
unsigned short tk_timeouts; /* maj timeouts */
-#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
unsigned short tk_pid; /* debugging aid */
#endif
unsigned char tk_priority : 2,/* Task priority */
@@ -187,7 +187,7 @@ struct rpc_wait_queue {
unsigned char nr; /* # tasks remaining for cookie */
unsigned short qlen; /* total # tasks waiting in queue */
struct rpc_timer timer_list;
-#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
const char * name;
#endif
};
@@ -237,7 +237,7 @@ void rpc_free(void *);
int rpciod_up(void);
void rpciod_down(void);
int __rpc_wait_for_completion_task(struct rpc_task *task, wait_bit_action_f *);
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
struct net;
void rpc_show_tasks(struct net *);
#endif
@@ -251,7 +251,7 @@ static inline int rpc_wait_for_completion_task(struct rpc_task *task)
return __rpc_wait_for_completion_task(task, NULL);
}
-#if defined(RPC_DEBUG) || defined (RPC_TRACEPOINTS)
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
static inline const char * rpc_qname(const struct rpc_wait_queue *q)
{
return ((q && q->name) ? q->name : "unknown");
diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h
index cf391ee..9d27ac4 100644
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -239,6 +239,9 @@ struct rpc_xprt {
struct net *xprt_net;
const char *servername;
const char *address_strings[RPC_DISPLAY_MAX];
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
+ struct dentry *debugfs; /* debugfs directory */
+#endif
};
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
diff --git a/include/linux/sunrpc/xprtsock.h b/include/linux/sunrpc/xprtsock.h
index 1ad36cc..7591788 100644
--- a/include/linux/sunrpc/xprtsock.h
+++ b/include/linux/sunrpc/xprtsock.h
@@ -17,6 +17,65 @@ void cleanup_socket_xprt(void);
#define RPC_DEF_MIN_RESVPORT (665U)
#define RPC_DEF_MAX_RESVPORT (1023U)
+struct sock_xprt {
+ struct rpc_xprt xprt;
+
+ /*
+ * Network layer
+ */
+ struct socket * sock;
+ struct sock * inet;
+
+ /*
+ * State of TCP reply receive
+ */
+ __be32 tcp_fraghdr,
+ tcp_xid,
+ tcp_calldir;
+
+ u32 tcp_offset,
+ tcp_reclen;
+
+ unsigned long tcp_copied,
+ tcp_flags;
+
+ /*
+ * Connection of transports
+ */
+ struct delayed_work connect_worker;
+ struct sockaddr_storage srcaddr;
+ unsigned short srcport;
+
+ /*
+ * UDP socket buffer size parameters
+ */
+ size_t rcvsize,
+ sndsize;
+
+ /*
+ * Saved socket callback addresses
+ */
+ void (*old_data_ready)(struct sock *);
+ void (*old_state_change)(struct sock *);
+ void (*old_write_space)(struct sock *);
+ void (*old_error_report)(struct sock *);
+};
+
+/*
+ * TCP receive state flags
+ */
+#define TCP_RCV_LAST_FRAG (1UL << 0)
+#define TCP_RCV_COPY_FRAGHDR (1UL << 1)
+#define TCP_RCV_COPY_XID (1UL << 2)
+#define TCP_RCV_COPY_DATA (1UL << 3)
+#define TCP_RCV_READ_CALLDIR (1UL << 4)
+#define TCP_RCV_COPY_CALLDIR (1UL << 5)
+
+/*
+ * TCP RPC flags
+ */
+#define TCP_RPC_REPLY (1UL << 6)
+
#endif /* __KERNEL__ */
#endif /* _LINUX_SUNRPC_XPRTSOCK_H */
diff --git a/include/linux/swap_cgroup.h b/include/linux/swap_cgroup.h
new file mode 100644
index 0000000..145306b
--- /dev/null
+++ b/include/linux/swap_cgroup.h
@@ -0,0 +1,42 @@
+#ifndef __LINUX_SWAP_CGROUP_H
+#define __LINUX_SWAP_CGROUP_H
+
+#include <linux/swap.h>
+
+#ifdef CONFIG_MEMCG_SWAP
+
+extern unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
+ unsigned short old, unsigned short new);
+extern unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id);
+extern unsigned short lookup_swap_cgroup_id(swp_entry_t ent);
+extern int swap_cgroup_swapon(int type, unsigned long max_pages);
+extern void swap_cgroup_swapoff(int type);
+
+#else
+
+static inline
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
+{
+ return 0;
+}
+
+static inline
+unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
+{
+ return 0;
+}
+
+static inline int
+swap_cgroup_swapon(int type, unsigned long max_pages)
+{
+ return 0;
+}
+
+static inline void swap_cgroup_swapoff(int type)
+{
+ return;
+}
+
+#endif /* CONFIG_MEMCG_SWAP */
+
+#endif /* __LINUX_SWAP_CGROUP_H */
diff --git a/include/linux/syslog.h b/include/linux/syslog.h
index 98a3153..4b7b875 100644
--- a/include/linux/syslog.h
+++ b/include/linux/syslog.h
@@ -49,4 +49,13 @@
int do_syslog(int type, char __user *buf, int count, bool from_file);
+#ifdef CONFIG_PRINTK
+int check_syslog_permissions(int type, bool from_file);
+#else
+static inline int check_syslog_permissions(int type, bool from_file)
+{
+ return 0;
+}
+#endif
+
#endif /* _LINUX_SYSLOG_H */
diff --git a/include/linux/time.h b/include/linux/time.h
index 8c42cf8..203c2ad 100644
--- a/include/linux/time.h
+++ b/include/linux/time.h
@@ -39,9 +39,20 @@ static inline int timeval_compare(const struct timeval *lhs, const struct timeva
return lhs->tv_usec - rhs->tv_usec;
}
-extern unsigned long mktime(const unsigned int year, const unsigned int mon,
- const unsigned int day, const unsigned int hour,
- const unsigned int min, const unsigned int sec);
+extern time64_t mktime64(const unsigned int year, const unsigned int mon,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec);
+
+/**
+ * Deprecated. Use mktime64().
+ */
+static inline unsigned long mktime(const unsigned int year,
+ const unsigned int mon, const unsigned int day,
+ const unsigned int hour, const unsigned int min,
+ const unsigned int sec)
+{
+ return mktime64(year, mon, day, hour, min, sec);
+}
extern void set_normalized_timespec(struct timespec *ts, time_t sec, s64 nsec);
diff --git a/include/linux/timekeeper_internal.h b/include/linux/timekeeper_internal.h
index 95640dc..05af9a3 100644
--- a/include/linux/timekeeper_internal.h
+++ b/include/linux/timekeeper_internal.h
@@ -42,6 +42,7 @@ struct tk_read_base {
* struct timekeeper - Structure holding internal timekeeping values.
* @tkr: The readout base structure
* @xtime_sec: Current CLOCK_REALTIME time in seconds
+ * @ktime_sec: Current CLOCK_MONOTONIC time in seconds
* @wall_to_monotonic: CLOCK_REALTIME to CLOCK_MONOTONIC offset
* @offs_real: Offset clock monotonic -> clock realtime
* @offs_boot: Offset clock monotonic -> clock boottime
@@ -77,6 +78,7 @@ struct tk_read_base {
struct timekeeper {
struct tk_read_base tkr;
u64 xtime_sec;
+ unsigned long ktime_sec;
struct timespec64 wall_to_monotonic;
ktime_t offs_real;
ktime_t offs_boot;
diff --git a/include/linux/timekeeping.h b/include/linux/timekeeping.h
index 1caa6b0..9b63d13 100644
--- a/include/linux/timekeeping.h
+++ b/include/linux/timekeeping.h
@@ -10,7 +10,7 @@ extern int timekeeping_suspended;
* Get and set timeofday
*/
extern void do_gettimeofday(struct timeval *tv);
-extern int do_settimeofday(const struct timespec *tv);
+extern int do_settimeofday64(const struct timespec64 *ts);
extern int do_sys_settimeofday(const struct timespec *tv,
const struct timezone *tz);
@@ -25,14 +25,24 @@ struct timespec __current_kernel_time(void);
/*
* timespec based interfaces
*/
-struct timespec get_monotonic_coarse(void);
-extern void getrawmonotonic(struct timespec *ts);
+struct timespec64 get_monotonic_coarse64(void);
+extern void getrawmonotonic64(struct timespec64 *ts);
extern void ktime_get_ts64(struct timespec64 *ts);
+extern time64_t ktime_get_seconds(void);
+extern time64_t ktime_get_real_seconds(void);
extern int __getnstimeofday64(struct timespec64 *tv);
extern void getnstimeofday64(struct timespec64 *tv);
#if BITS_PER_LONG == 64
+/**
+ * Deprecated. Use do_settimeofday64().
+ */
+static inline int do_settimeofday(const struct timespec *ts)
+{
+ return do_settimeofday64(ts);
+}
+
static inline int __getnstimeofday(struct timespec *ts)
{
return __getnstimeofday64(ts);
@@ -53,7 +63,27 @@ static inline void ktime_get_real_ts(struct timespec *ts)
getnstimeofday64(ts);
}
+static inline void getrawmonotonic(struct timespec *ts)
+{
+ getrawmonotonic64(ts);
+}
+
+static inline struct timespec get_monotonic_coarse(void)
+{
+ return get_monotonic_coarse64();
+}
#else
+/**
+ * Deprecated. Use do_settimeofday64().
+ */
+static inline int do_settimeofday(const struct timespec *ts)
+{
+ struct timespec64 ts64;
+
+ ts64 = timespec_to_timespec64(*ts);
+ return do_settimeofday64(&ts64);
+}
+
static inline int __getnstimeofday(struct timespec *ts)
{
struct timespec64 ts64;
@@ -86,6 +116,19 @@ static inline void ktime_get_real_ts(struct timespec *ts)
getnstimeofday64(&ts64);
*ts = timespec64_to_timespec(ts64);
}
+
+static inline void getrawmonotonic(struct timespec *ts)
+{
+ struct timespec64 ts64;
+
+ getrawmonotonic64(&ts64);
+ *ts = timespec64_to_timespec(ts64);
+}
+
+static inline struct timespec get_monotonic_coarse(void)
+{
+ return timespec64_to_timespec(get_monotonic_coarse64());
+}
#endif
extern void getboottime(struct timespec *ts);
@@ -182,7 +225,7 @@ static inline void timekeeping_clocktai(struct timespec *ts)
/*
* RTC specific
*/
-extern void timekeeping_inject_sleeptime(struct timespec *delta);
+extern void timekeeping_inject_sleeptime64(struct timespec64 *delta);
/*
* PPS accessor
diff --git a/include/linux/trace_seq.h b/include/linux/trace_seq.h
index ea6c9de..cfaf5a1 100644
--- a/include/linux/trace_seq.h
+++ b/include/linux/trace_seq.h
@@ -1,7 +1,7 @@
#ifndef _LINUX_TRACE_SEQ_H
#define _LINUX_TRACE_SEQ_H
-#include <linux/fs.h>
+#include <linux/seq_buf.h>
#include <asm/page.h>
@@ -12,20 +12,36 @@
struct trace_seq {
unsigned char buffer[PAGE_SIZE];
- unsigned int len;
- unsigned int readpos;
+ struct seq_buf seq;
int full;
};
static inline void
trace_seq_init(struct trace_seq *s)
{
- s->len = 0;
- s->readpos = 0;
+ seq_buf_init(&s->seq, s->buffer, PAGE_SIZE);
s->full = 0;
}
/**
+ * trace_seq_used - amount of actual data written to buffer
+ * @s: trace sequence descriptor
+ *
+ * Returns the amount of data written to the buffer.
+ *
+ * IMPORTANT!
+ *
+ * Use this instead of @s->seq.len if you need to pass the amount
+ * of data from the buffer to another buffer (userspace, or what not).
+ * The @s->seq.len on overflow is bigger than the buffer size and
+ * using it can cause access to undefined memory.
+ */
+static inline int trace_seq_used(struct trace_seq *s)
+{
+ return seq_buf_used(&s->seq);
+}
+
+/**
* trace_seq_buffer_ptr - return pointer to next location in buffer
* @s: trace sequence descriptor
*
@@ -37,7 +53,19 @@ trace_seq_init(struct trace_seq *s)
static inline unsigned char *
trace_seq_buffer_ptr(struct trace_seq *s)
{
- return s->buffer + s->len;
+ return s->buffer + seq_buf_used(&s->seq);
+}
+
+/**
+ * trace_seq_has_overflowed - return true if the trace_seq took too much
+ * @s: trace sequence descriptor
+ *
+ * Returns true if too much data was added to the trace_seq and it is
+ * now full and will not take anymore.
+ */
+static inline bool trace_seq_has_overflowed(struct trace_seq *s)
+{
+ return s->full || seq_buf_has_overflowed(&s->seq);
}
/*
@@ -45,40 +73,37 @@ trace_seq_buffer_ptr(struct trace_seq *s)
*/
#ifdef CONFIG_TRACING
extern __printf(2, 3)
-int trace_seq_printf(struct trace_seq *s, const char *fmt, ...);
+void trace_seq_printf(struct trace_seq *s, const char *fmt, ...);
extern __printf(2, 0)
-int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args);
-extern int
+void trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args);
+extern void
trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary);
extern int trace_print_seq(struct seq_file *m, struct trace_seq *s);
extern int trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
int cnt);
-extern int trace_seq_puts(struct trace_seq *s, const char *str);
-extern int trace_seq_putc(struct trace_seq *s, unsigned char c);
-extern int trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len);
-extern int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
+extern void trace_seq_puts(struct trace_seq *s, const char *str);
+extern void trace_seq_putc(struct trace_seq *s, unsigned char c);
+extern void trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len);
+extern void trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
unsigned int len);
extern int trace_seq_path(struct trace_seq *s, const struct path *path);
-extern int trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
+extern void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
int nmaskbits);
#else /* CONFIG_TRACING */
-static inline int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+static inline void trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
{
- return 0;
}
-static inline int
+static inline void
trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
{
- return 0;
}
-static inline int
+static inline void
trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
int nmaskbits)
{
- return 0;
}
static inline int trace_print_seq(struct seq_file *m, struct trace_seq *s)
@@ -90,23 +115,19 @@ static inline int trace_seq_to_user(struct trace_seq *s, char __user *ubuf,
{
return 0;
}
-static inline int trace_seq_puts(struct trace_seq *s, const char *str)
+static inline void trace_seq_puts(struct trace_seq *s, const char *str)
{
- return 0;
}
-static inline int trace_seq_putc(struct trace_seq *s, unsigned char c)
+static inline void trace_seq_putc(struct trace_seq *s, unsigned char c)
{
- return 0;
}
-static inline int
+static inline void
trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len)
{
- return 0;
}
-static inline int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
+static inline void trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
unsigned int len)
{
- return 0;
}
static inline int trace_seq_path(struct trace_seq *s, const struct path *path)
{
diff --git a/include/linux/usb.h b/include/linux/usb.h
index 447a7e2..f89c24a 100644
--- a/include/linux/usb.h
+++ b/include/linux/usb.h
@@ -637,7 +637,7 @@ static inline bool usb_acpi_power_manageable(struct usb_device *hdev, int index)
#endif
/* USB autosuspend and autoresume */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
extern void usb_enable_autosuspend(struct usb_device *udev);
extern void usb_disable_autosuspend(struct usb_device *udev);
diff --git a/include/linux/usb/hcd.h b/include/linux/usb/hcd.h
index cd96a2b..668898e 100644
--- a/include/linux/usb/hcd.h
+++ b/include/linux/usb/hcd.h
@@ -93,7 +93,7 @@ struct usb_hcd {
struct timer_list rh_timer; /* drives root-hub polling */
struct urb *status_urb; /* the current status urb */
-#ifdef CONFIG_PM_RUNTIME
+#ifdef CONFIG_PM
struct work_struct wakeup_work; /* for remote wakeup */
#endif
@@ -625,16 +625,13 @@ extern int usb_find_interface_driver(struct usb_device *dev,
extern void usb_root_hub_lost_power(struct usb_device *rhdev);
extern int hcd_bus_suspend(struct usb_device *rhdev, pm_message_t msg);
extern int hcd_bus_resume(struct usb_device *rhdev, pm_message_t msg);
-#endif /* CONFIG_PM */
-
-#ifdef CONFIG_PM_RUNTIME
extern void usb_hcd_resume_root_hub(struct usb_hcd *hcd);
#else
static inline void usb_hcd_resume_root_hub(struct usb_hcd *hcd)
{
return;
}
-#endif /* CONFIG_PM_RUNTIME */
+#endif /* CONFIG_PM */
/*-------------------------------------------------------------------------*/
diff --git a/include/linux/vexpress.h b/include/linux/vexpress.h
index a4c9547..f8e76e0 100644
--- a/include/linux/vexpress.h
+++ b/include/linux/vexpress.h
@@ -15,8 +15,6 @@
#define _LINUX_VEXPRESS_H
#include <linux/device.h>
-#include <linux/platform_device.h>
-#include <linux/reboot.h>
#include <linux/regmap.h>
#define VEXPRESS_SITE_MB 0
@@ -24,13 +22,6 @@
#define VEXPRESS_SITE_DB2 2
#define VEXPRESS_SITE_MASTER 0xf
-#define VEXPRESS_RES_FUNC(_site, _func) \
-{ \
- .start = (_site), \
- .end = (_func), \
- .flags = IORESOURCE_BUS, \
-}
-
/* Config infrastructure */
void vexpress_config_set_master(u32 site);
@@ -58,16 +49,6 @@ struct regmap *devm_regmap_init_vexpress_config(struct device *dev);
/* Platform control */
-unsigned int vexpress_get_mci_cardin(struct device *dev);
-u32 vexpress_get_procid(int site);
-void *vexpress_get_24mhz_clock_base(void);
void vexpress_flags_set(u32 data);
-void vexpress_sysreg_early_init(void __iomem *base);
-int vexpress_syscfg_device_register(struct platform_device *pdev);
-
-/* Clocks */
-
-void vexpress_clk_init(void __iomem *sp810_base);
-
#endif
diff --git a/include/linux/virtio.h b/include/linux/virtio.h
index 65261a7..d09e093 100644
--- a/include/linux/virtio.h
+++ b/include/linux/virtio.h
@@ -75,6 +75,9 @@ unsigned int virtqueue_get_vring_size(struct virtqueue *vq);
bool virtqueue_is_broken(struct virtqueue *vq);
+void *virtqueue_get_avail(struct virtqueue *vq);
+void *virtqueue_get_used(struct virtqueue *vq);
+
/**
* virtio_device - representation of a device using virtio
* @index: unique position on the virtio bus
@@ -101,11 +104,12 @@ struct virtio_device {
const struct virtio_config_ops *config;
const struct vringh_config_ops *vringh_config;
struct list_head vqs;
- /* Note that this is a Linux set_bit-style bitmap. */
- unsigned long features[1];
+ u64 features;
void *priv;
};
+bool virtio_device_is_legacy_only(struct virtio_device_id id);
+
static inline struct virtio_device *dev_to_virtio(struct device *_dev)
{
return container_of(_dev, struct virtio_device, dev);
@@ -128,6 +132,8 @@ int virtio_device_restore(struct virtio_device *dev);
* @id_table: the ids serviced by this driver.
* @feature_table: an array of feature numbers supported by this driver.
* @feature_table_size: number of entries in the feature table array.
+ * @feature_table_legacy: same as feature_table but when working in legacy mode.
+ * @feature_table_size_legacy: number of entries in feature table legacy array.
* @probe: the function to call when a device is found. Returns 0 or -errno.
* @remove: the function to call when a device is removed.
* @config_changed: optional function to call when the device configuration
@@ -138,6 +144,8 @@ struct virtio_driver {
const struct virtio_device_id *id_table;
const unsigned int *feature_table;
unsigned int feature_table_size;
+ const unsigned int *feature_table_legacy;
+ unsigned int feature_table_size_legacy;
int (*probe)(struct virtio_device *dev);
void (*scan)(struct virtio_device *dev);
void (*remove)(struct virtio_device *dev);
diff --git a/include/linux/virtio_byteorder.h b/include/linux/virtio_byteorder.h
new file mode 100644
index 0000000..51865d0
--- /dev/null
+++ b/include/linux/virtio_byteorder.h
@@ -0,0 +1,59 @@
+#ifndef _LINUX_VIRTIO_BYTEORDER_H
+#define _LINUX_VIRTIO_BYTEORDER_H
+#include <linux/types.h>
+#include <uapi/linux/virtio_types.h>
+
+/*
+ * Low-level memory accessors for handling virtio in modern little endian and in
+ * compatibility native endian format.
+ */
+
+static inline u16 __virtio16_to_cpu(bool little_endian, __virtio16 val)
+{
+ if (little_endian)
+ return le16_to_cpu((__force __le16)val);
+ else
+ return (__force u16)val;
+}
+
+static inline __virtio16 __cpu_to_virtio16(bool little_endian, u16 val)
+{
+ if (little_endian)
+ return (__force __virtio16)cpu_to_le16(val);
+ else
+ return (__force __virtio16)val;
+}
+
+static inline u32 __virtio32_to_cpu(bool little_endian, __virtio32 val)
+{
+ if (little_endian)
+ return le32_to_cpu((__force __le32)val);
+ else
+ return (__force u32)val;
+}
+
+static inline __virtio32 __cpu_to_virtio32(bool little_endian, u32 val)
+{
+ if (little_endian)
+ return (__force __virtio32)cpu_to_le32(val);
+ else
+ return (__force __virtio32)val;
+}
+
+static inline u64 __virtio64_to_cpu(bool little_endian, __virtio64 val)
+{
+ if (little_endian)
+ return le64_to_cpu((__force __le64)val);
+ else
+ return (__force u64)val;
+}
+
+static inline __virtio64 __cpu_to_virtio64(bool little_endian, u64 val)
+{
+ if (little_endian)
+ return (__force __virtio64)cpu_to_le64(val);
+ else
+ return (__force __virtio64)val;
+}
+
+#endif /* _LINUX_VIRTIO_BYTEORDER */
diff --git a/include/linux/virtio_config.h b/include/linux/virtio_config.h
index 7f4ef66..7979f85 100644
--- a/include/linux/virtio_config.h
+++ b/include/linux/virtio_config.h
@@ -4,6 +4,7 @@
#include <linux/err.h>
#include <linux/bug.h>
#include <linux/virtio.h>
+#include <linux/virtio_byteorder.h>
#include <uapi/linux/virtio_config.h>
/**
@@ -46,6 +47,7 @@
* vdev: the virtio_device
* This gives the final feature bits for the device: it can change
* the dev->feature bits if it wants.
+ * Returns 0 on success or error status
* @bus_name: return the bus name associated with the device
* vdev: the virtio_device
* This returns a pointer to the bus name a la pci_name from which
@@ -66,8 +68,8 @@ struct virtio_config_ops {
vq_callback_t *callbacks[],
const char *names[]);
void (*del_vqs)(struct virtio_device *);
- u32 (*get_features)(struct virtio_device *vdev);
- void (*finalize_features)(struct virtio_device *vdev);
+ u64 (*get_features)(struct virtio_device *vdev);
+ int (*finalize_features)(struct virtio_device *vdev);
const char *(*bus_name)(struct virtio_device *vdev);
int (*set_vq_affinity)(struct virtqueue *vq, int cpu);
};
@@ -77,23 +79,70 @@ void virtio_check_driver_offered_feature(const struct virtio_device *vdev,
unsigned int fbit);
/**
- * virtio_has_feature - helper to determine if this device has this feature.
+ * __virtio_test_bit - helper to test feature bits. For use by transports.
+ * Devices should normally use virtio_has_feature,
+ * which includes more checks.
* @vdev: the device
* @fbit: the feature bit
*/
-static inline bool virtio_has_feature(const struct virtio_device *vdev,
+static inline bool __virtio_test_bit(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ /* Did you forget to fix assumptions on max features? */
+ if (__builtin_constant_p(fbit))
+ BUILD_BUG_ON(fbit >= 64);
+ else
+ BUG_ON(fbit >= 64);
+
+ return vdev->features & BIT_ULL(fbit);
+}
+
+/**
+ * __virtio_set_bit - helper to set feature bits. For use by transports.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline void __virtio_set_bit(struct virtio_device *vdev,
+ unsigned int fbit)
+{
+ /* Did you forget to fix assumptions on max features? */
+ if (__builtin_constant_p(fbit))
+ BUILD_BUG_ON(fbit >= 64);
+ else
+ BUG_ON(fbit >= 64);
+
+ vdev->features |= BIT_ULL(fbit);
+}
+
+/**
+ * __virtio_clear_bit - helper to clear feature bits. For use by transports.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline void __virtio_clear_bit(struct virtio_device *vdev,
unsigned int fbit)
{
/* Did you forget to fix assumptions on max features? */
if (__builtin_constant_p(fbit))
- BUILD_BUG_ON(fbit >= 32);
+ BUILD_BUG_ON(fbit >= 64);
else
- BUG_ON(fbit >= 32);
+ BUG_ON(fbit >= 64);
+ vdev->features &= ~BIT_ULL(fbit);
+}
+
+/**
+ * virtio_has_feature - helper to determine if this device has this feature.
+ * @vdev: the device
+ * @fbit: the feature bit
+ */
+static inline bool virtio_has_feature(const struct virtio_device *vdev,
+ unsigned int fbit)
+{
if (fbit < VIRTIO_TRANSPORT_F_START)
virtio_check_driver_offered_feature(vdev, fbit);
- return test_bit(fbit, vdev->features);
+ return __virtio_test_bit(vdev, fbit);
}
static inline
@@ -152,6 +201,37 @@ int virtqueue_set_affinity(struct virtqueue *vq, int cpu)
return 0;
}
+/* Memory accessors */
+static inline u16 virtio16_to_cpu(struct virtio_device *vdev, __virtio16 val)
+{
+ return __virtio16_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio16 cpu_to_virtio16(struct virtio_device *vdev, u16 val)
+{
+ return __cpu_to_virtio16(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline u32 virtio32_to_cpu(struct virtio_device *vdev, __virtio32 val)
+{
+ return __virtio32_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio32 cpu_to_virtio32(struct virtio_device *vdev, u32 val)
+{
+ return __cpu_to_virtio32(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline u64 virtio64_to_cpu(struct virtio_device *vdev, __virtio64 val)
+{
+ return __virtio64_to_cpu(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
+static inline __virtio64 cpu_to_virtio64(struct virtio_device *vdev, u64 val)
+{
+ return __cpu_to_virtio64(virtio_has_feature(vdev, VIRTIO_F_VERSION_1), val);
+}
+
/* Config space accessors. */
#define virtio_cread(vdev, structname, member, ptr) \
do { \
@@ -239,12 +319,13 @@ static inline u16 virtio_cread16(struct virtio_device *vdev,
{
u16 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
- return ret;
+ return virtio16_to_cpu(vdev, (__force __virtio16)ret);
}
static inline void virtio_cwrite16(struct virtio_device *vdev,
unsigned int offset, u16 val)
{
+ val = (__force u16)cpu_to_virtio16(vdev, val);
vdev->config->set(vdev, offset, &val, sizeof(val));
}
@@ -253,12 +334,13 @@ static inline u32 virtio_cread32(struct virtio_device *vdev,
{
u32 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
- return ret;
+ return virtio32_to_cpu(vdev, (__force __virtio32)ret);
}
static inline void virtio_cwrite32(struct virtio_device *vdev,
unsigned int offset, u32 val)
{
+ val = (__force u32)cpu_to_virtio32(vdev, val);
vdev->config->set(vdev, offset, &val, sizeof(val));
}
@@ -267,12 +349,13 @@ static inline u64 virtio_cread64(struct virtio_device *vdev,
{
u64 ret;
vdev->config->get(vdev, offset, &ret, sizeof(ret));
- return ret;
+ return virtio64_to_cpu(vdev, (__force __virtio64)ret);
}
static inline void virtio_cwrite64(struct virtio_device *vdev,
unsigned int offset, u64 val)
{
+ val = (__force u64)cpu_to_virtio64(vdev, val);
vdev->config->set(vdev, offset, &val, sizeof(val));
}
diff --git a/include/linux/wait.h b/include/linux/wait.h
index e4a8eb9..2232ed1 100644
--- a/include/linux/wait.h
+++ b/include/linux/wait.h
@@ -13,9 +13,12 @@ typedef struct __wait_queue wait_queue_t;
typedef int (*wait_queue_func_t)(wait_queue_t *wait, unsigned mode, int flags, void *key);
int default_wake_function(wait_queue_t *wait, unsigned mode, int flags, void *key);
+/* __wait_queue::flags */
+#define WQ_FLAG_EXCLUSIVE 0x01
+#define WQ_FLAG_WOKEN 0x02
+
struct __wait_queue {
unsigned int flags;
-#define WQ_FLAG_EXCLUSIVE 0x01
void *private;
wait_queue_func_t func;
struct list_head task_list;
@@ -258,11 +261,37 @@ __out: __ret; \
*/
#define wait_event(wq, condition) \
do { \
+ might_sleep(); \
if (condition) \
break; \
__wait_event(wq, condition); \
} while (0)
+#define __wait_event_freezable(wq, condition) \
+ ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 0, 0, \
+ schedule(); try_to_freeze())
+
+/**
+ * wait_event - sleep (or freeze) until a condition gets true
+ * @wq: the waitqueue to wait on
+ * @condition: a C expression for the event to wait for
+ *
+ * The process is put to sleep (TASK_INTERRUPTIBLE -- so as not to contribute
+ * to system load) until the @condition evaluates to true. The
+ * @condition is checked each time the waitqueue @wq is woken up.
+ *
+ * wake_up() has to be called after changing any variable that could
+ * change the result of the wait condition.
+ */
+#define wait_event_freezable(wq, condition) \
+({ \
+ int __ret = 0; \
+ might_sleep(); \
+ if (!(condition)) \
+ __ret = __wait_event_freezable(wq, condition); \
+ __ret; \
+})
+
#define __wait_event_timeout(wq, condition, timeout) \
___wait_event(wq, ___wait_cond_timeout(condition), \
TASK_UNINTERRUPTIBLE, 0, timeout, \
@@ -290,11 +319,30 @@ do { \
#define wait_event_timeout(wq, condition, timeout) \
({ \
long __ret = timeout; \
+ might_sleep(); \
if (!___wait_cond_timeout(condition)) \
__ret = __wait_event_timeout(wq, condition, timeout); \
__ret; \
})
+#define __wait_event_freezable_timeout(wq, condition, timeout) \
+ ___wait_event(wq, ___wait_cond_timeout(condition), \
+ TASK_INTERRUPTIBLE, 0, timeout, \
+ __ret = schedule_timeout(__ret); try_to_freeze())
+
+/*
+ * like wait_event_timeout() -- except it uses TASK_INTERRUPTIBLE to avoid
+ * increasing load and is freezable.
+ */
+#define wait_event_freezable_timeout(wq, condition, timeout) \
+({ \
+ long __ret = timeout; \
+ might_sleep(); \
+ if (!___wait_cond_timeout(condition)) \
+ __ret = __wait_event_freezable_timeout(wq, condition, timeout); \
+ __ret; \
+})
+
#define __wait_event_cmd(wq, condition, cmd1, cmd2) \
(void)___wait_event(wq, condition, TASK_UNINTERRUPTIBLE, 0, 0, \
cmd1; schedule(); cmd2)
@@ -315,6 +363,7 @@ do { \
*/
#define wait_event_cmd(wq, condition, cmd1, cmd2) \
do { \
+ might_sleep(); \
if (condition) \
break; \
__wait_event_cmd(wq, condition, cmd1, cmd2); \
@@ -342,6 +391,7 @@ do { \
#define wait_event_interruptible(wq, condition) \
({ \
int __ret = 0; \
+ might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible(wq, condition); \
__ret; \
@@ -375,6 +425,7 @@ do { \
#define wait_event_interruptible_timeout(wq, condition, timeout) \
({ \
long __ret = timeout; \
+ might_sleep(); \
if (!___wait_cond_timeout(condition)) \
__ret = __wait_event_interruptible_timeout(wq, \
condition, timeout); \
@@ -425,6 +476,7 @@ do { \
#define wait_event_hrtimeout(wq, condition, timeout) \
({ \
int __ret = 0; \
+ might_sleep(); \
if (!(condition)) \
__ret = __wait_event_hrtimeout(wq, condition, timeout, \
TASK_UNINTERRUPTIBLE); \
@@ -450,6 +502,7 @@ do { \
#define wait_event_interruptible_hrtimeout(wq, condition, timeout) \
({ \
long __ret = 0; \
+ might_sleep(); \
if (!(condition)) \
__ret = __wait_event_hrtimeout(wq, condition, timeout, \
TASK_INTERRUPTIBLE); \
@@ -463,12 +516,27 @@ do { \
#define wait_event_interruptible_exclusive(wq, condition) \
({ \
int __ret = 0; \
+ might_sleep(); \
if (!(condition)) \
__ret = __wait_event_interruptible_exclusive(wq, condition);\
__ret; \
})
+#define __wait_event_freezable_exclusive(wq, condition) \
+ ___wait_event(wq, condition, TASK_INTERRUPTIBLE, 1, 0, \
+ schedule(); try_to_freeze())
+
+#define wait_event_freezable_exclusive(wq, condition) \
+({ \
+ int __ret = 0; \
+ might_sleep(); \
+ if (!(condition)) \
+ __ret = __wait_event_freezable_exclusive(wq, condition);\
+ __ret; \
+})
+
+
#define __wait_event_interruptible_locked(wq, condition, exclusive, irq) \
({ \
int __ret = 0; \
@@ -637,6 +705,7 @@ do { \
#define wait_event_killable(wq, condition) \
({ \
int __ret = 0; \
+ might_sleep(); \
if (!(condition)) \
__ret = __wait_event_killable(wq, condition); \
__ret; \
@@ -830,6 +899,8 @@ void prepare_to_wait_exclusive(wait_queue_head_t *q, wait_queue_t *wait, int sta
long prepare_to_wait_event(wait_queue_head_t *q, wait_queue_t *wait, int state);
void finish_wait(wait_queue_head_t *q, wait_queue_t *wait);
void abort_exclusive_wait(wait_queue_head_t *q, wait_queue_t *wait, unsigned int mode, void *key);
+long wait_woken(wait_queue_t *wait, unsigned mode, long timeout);
+int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *key);
@@ -886,6 +957,7 @@ extern int bit_wait_io_timeout(struct wait_bit_key *);
static inline int
wait_on_bit(void *word, int bit, unsigned mode)
{
+ might_sleep();
if (!test_bit(bit, word))
return 0;
return out_of_line_wait_on_bit(word, bit,
@@ -910,6 +982,7 @@ wait_on_bit(void *word, int bit, unsigned mode)
static inline int
wait_on_bit_io(void *word, int bit, unsigned mode)
{
+ might_sleep();
if (!test_bit(bit, word))
return 0;
return out_of_line_wait_on_bit(word, bit,
@@ -936,6 +1009,7 @@ wait_on_bit_io(void *word, int bit, unsigned mode)
static inline int
wait_on_bit_action(void *word, int bit, wait_bit_action_f *action, unsigned mode)
{
+ might_sleep();
if (!test_bit(bit, word))
return 0;
return out_of_line_wait_on_bit(word, bit, action, mode);
@@ -963,6 +1037,7 @@ wait_on_bit_action(void *word, int bit, wait_bit_action_f *action, unsigned mode
static inline int
wait_on_bit_lock(void *word, int bit, unsigned mode)
{
+ might_sleep();
if (!test_and_set_bit(bit, word))
return 0;
return out_of_line_wait_on_bit_lock(word, bit, bit_wait, mode);
@@ -986,6 +1061,7 @@ wait_on_bit_lock(void *word, int bit, unsigned mode)
static inline int
wait_on_bit_lock_io(void *word, int bit, unsigned mode)
{
+ might_sleep();
if (!test_and_set_bit(bit, word))
return 0;
return out_of_line_wait_on_bit_lock(word, bit, bit_wait_io, mode);
@@ -1011,6 +1087,7 @@ wait_on_bit_lock_io(void *word, int bit, unsigned mode)
static inline int
wait_on_bit_lock_action(void *word, int bit, wait_bit_action_f *action, unsigned mode)
{
+ might_sleep();
if (!test_and_set_bit(bit, word))
return 0;
return out_of_line_wait_on_bit_lock(word, bit, action, mode);
@@ -1029,6 +1106,7 @@ wait_on_bit_lock_action(void *word, int bit, wait_bit_action_f *action, unsigned
static inline
int wait_on_atomic_t(atomic_t *val, int (*action)(atomic_t *), unsigned mode)
{
+ might_sleep();
if (atomic_read(val) == 0)
return 0;
return out_of_line_wait_on_atomic_t(val, action, mode);
diff --git a/include/media/davinci/vpbe.h b/include/media/davinci/vpbe.h
index 57585c7..4376bee 100644
--- a/include/media/davinci/vpbe.h
+++ b/include/media/davinci/vpbe.h
@@ -63,7 +63,7 @@ struct vpbe_output {
* output basis. If per mode is needed, we may have to move this to
* mode_info structure
*/
- enum v4l2_mbus_pixelcode if_params;
+ u32 if_params;
};
/* encoder configuration info */
diff --git a/include/media/davinci/vpbe_display.h b/include/media/davinci/vpbe_display.h
index 637749a..fa0247a 100644
--- a/include/media/davinci/vpbe_display.h
+++ b/include/media/davinci/vpbe_display.h
@@ -70,8 +70,6 @@ struct vpbe_disp_buffer {
/* vpbe display object structure */
struct vpbe_layer {
- /* number of buffers in fbuffers */
- unsigned int numbuffers;
/* Pointer to the vpbe_display */
struct vpbe_display *disp_dev;
/* Pointer pointing to current v4l2_buffer */
@@ -91,10 +89,6 @@ struct vpbe_layer {
/* V4l2 specific parameters */
/* Identifies video device for this layer */
struct video_device video_dev;
- /* This field keeps track of type of buffer exchange mechanism user
- * has selected
- */
- enum v4l2_memory memory;
/* Used to store pixel format */
struct v4l2_pix_format pix_fmt;
enum v4l2_field buf_field;
@@ -106,12 +100,8 @@ struct vpbe_layer {
unsigned char window_enable;
/* number of open instances of the layer */
unsigned int usrs;
- /* number of users performing IO */
- unsigned int io_usrs;
/* Indicates id of the field which is being displayed */
unsigned int field_id;
- /* Indicates whether streaming started */
- unsigned char started;
/* Identifies device object */
enum vpbe_display_device_id device_id;
/* facilitation of ioctl ops lock by v4l2*/
@@ -131,17 +121,6 @@ struct vpbe_display {
struct osd_state *osd_device;
};
-/* File handle structure */
-struct vpbe_fh {
- struct v4l2_fh fh;
- /* vpbe device structure */
- struct vpbe_display *disp_dev;
- /* pointer to layer object for opened device */
- struct vpbe_layer *layer;
- /* Indicates whether this file handle is doing IO */
- unsigned char io_allowed;
-};
-
struct buf_config_params {
unsigned char min_numbuffers;
unsigned char numbuffers[VPBE_DISPLAY_MAX_DEVICES];
diff --git a/include/media/davinci/vpbe_venc.h b/include/media/davinci/vpbe_venc.h
index 476fafc..3dbd200 100644
--- a/include/media/davinci/vpbe_venc.h
+++ b/include/media/davinci/vpbe_venc.h
@@ -30,11 +30,10 @@
#define VENC_SECOND_FIELD BIT(2)
struct venc_platform_data {
- int (*setup_pinmux)(enum v4l2_mbus_pixelcode if_type,
- int field);
+ int (*setup_pinmux)(u32 if_type, int field);
int (*setup_clock)(enum vpbe_enc_timings_type type,
unsigned int pixclock);
- int (*setup_if_config)(enum v4l2_mbus_pixelcode pixcode);
+ int (*setup_if_config)(u32 pixcode);
/* Number of LCD outputs supported */
int num_lcd_outputs;
struct vpbe_if_params *lcd_if_params;
diff --git a/include/media/exynos-fimc.h b/include/media/exynos-fimc.h
index aa44660..69bcd2a 100644
--- a/include/media/exynos-fimc.h
+++ b/include/media/exynos-fimc.h
@@ -101,7 +101,7 @@ struct fimc_source_info {
* @flags: flags indicating which operation mode format applies to
*/
struct fimc_fmt {
- enum v4l2_mbus_pixelcode mbus_code;
+ u32 mbus_code;
char *name;
u32 fourcc;
u32 color;
diff --git a/include/media/lirc_dev.h b/include/media/lirc_dev.h
index 78f0637..05e7ad5 100644
--- a/include/media/lirc_dev.h
+++ b/include/media/lirc_dev.h
@@ -29,14 +29,13 @@ struct lirc_buffer {
/* Using chunks instead of bytes pretends to simplify boundary checking
* And should allow for some performance fine tunning later */
struct kfifo fifo;
- u8 fifo_initialized;
};
static inline void lirc_buffer_clear(struct lirc_buffer *buf)
{
unsigned long flags;
- if (buf->fifo_initialized) {
+ if (kfifo_initialized(&buf->fifo)) {
spin_lock_irqsave(&buf->fifo_lock, flags);
kfifo_reset(&buf->fifo);
spin_unlock_irqrestore(&buf->fifo_lock, flags);
@@ -56,17 +55,14 @@ static inline int lirc_buffer_init(struct lirc_buffer *buf,
buf->chunk_size = chunk_size;
buf->size = size;
ret = kfifo_alloc(&buf->fifo, size * chunk_size, GFP_KERNEL);
- if (ret == 0)
- buf->fifo_initialized = 1;
return ret;
}
static inline void lirc_buffer_free(struct lirc_buffer *buf)
{
- if (buf->fifo_initialized) {
+ if (kfifo_initialized(&buf->fifo)) {
kfifo_free(&buf->fifo);
- buf->fifo_initialized = 0;
} else
WARN(1, "calling %s on an uninitialized lirc_buffer\n",
__func__);
diff --git a/include/media/radio-si4713.h b/include/media/radio-si4713.h
deleted file mode 100644
index f6aae29..0000000
--- a/include/media/radio-si4713.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * include/media/radio-si4713.h
- *
- * Board related data definitions for Si4713 radio transmitter chip.
- *
- * Copyright (c) 2009 Nokia Corporation
- * Contact: Eduardo Valentin <eduardo.valentin@nokia.com>
- *
- * This file is licensed under the terms of the GNU General Public License
- * version 2. This program is licensed "as is" without any warranty of any
- * kind, whether express or implied.
- *
- */
-
-#ifndef RADIO_SI4713_H
-#define RADIO_SI4713_H
-
-#include <linux/i2c.h>
-
-#define SI4713_NAME "radio-si4713"
-
-/*
- * Platform dependent definition
- */
-struct radio_si4713_platform_data {
- int i2c_bus;
- struct i2c_board_info *subdev_board_info;
-};
-
-#endif /* ifndef RADIO_SI4713_H*/
diff --git a/include/media/si4713.h b/include/media/si4713.h
index f98a0a7..be4f58e 100644
--- a/include/media/si4713.h
+++ b/include/media/si4713.h
@@ -23,9 +23,7 @@
* Platform dependent definition
*/
struct si4713_platform_data {
- const char * const *supply_names;
- unsigned supplies;
- int gpio_reset; /* < 0 if not used */
+ bool is_platform_device;
};
/*
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
index 865246b..2f6261f 100644
--- a/include/media/soc_camera.h
+++ b/include/media/soc_camera.h
@@ -296,7 +296,7 @@ const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
* format setup.
*/
struct soc_camera_format_xlate {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
const struct soc_mbus_pixelfmt *host_fmt;
};
diff --git a/include/media/soc_mediabus.h b/include/media/soc_mediabus.h
index d33f6d0..2ff7737 100644
--- a/include/media/soc_mediabus.h
+++ b/include/media/soc_mediabus.h
@@ -91,16 +91,16 @@ struct soc_mbus_pixelfmt {
* @fmt: pixel format description
*/
struct soc_mbus_lookup {
- enum v4l2_mbus_pixelcode code;
+ u32 code;
struct soc_mbus_pixelfmt fmt;
};
const struct soc_mbus_pixelfmt *soc_mbus_find_fmtdesc(
- enum v4l2_mbus_pixelcode code,
+ u32 code,
const struct soc_mbus_lookup *lookup,
int n);
const struct soc_mbus_pixelfmt *soc_mbus_get_fmtdesc(
- enum v4l2_mbus_pixelcode code);
+ u32 code);
s32 soc_mbus_bytes_per_line(u32 width, const struct soc_mbus_pixelfmt *mf);
s32 soc_mbus_image_size(const struct soc_mbus_pixelfmt *mf,
u32 bytes_per_line, u32 height);
diff --git a/include/media/v4l2-common.h b/include/media/v4l2-common.h
index 48f9748..1cc0c5b 100644
--- a/include/media/v4l2-common.h
+++ b/include/media/v4l2-common.h
@@ -80,24 +80,9 @@
/* ------------------------------------------------------------------------- */
-/* Control helper functions */
+/* Control helper function */
-int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
- const char * const *menu_items);
-const char *v4l2_ctrl_get_name(u32 id);
-const char * const *v4l2_ctrl_get_menu(u32 id);
-const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len);
int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def);
-int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu,
- struct v4l2_queryctrl *qctrl, const char * const *menu_items);
-#define V4L2_CTRL_MENU_IDS_END (0xffffffff)
-int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids);
-
-/* Note: ctrl_classes points to an array of u32 pointers. Each u32 array is a
- 0-terminated array of control IDs. Each array must be sorted low to high
- and belong to the same control class. The array of u32 pointers must also
- be sorted, from low class IDs to high class IDs. */
-u32 v4l2_ctrl_next(const u32 * const *ctrl_classes, u32 id);
/* ------------------------------------------------------------------------- */
diff --git a/include/media/v4l2-ctrls.h b/include/media/v4l2-ctrls.h
index b7cd7a6..911f3e5 100644
--- a/include/media/v4l2-ctrls.h
+++ b/include/media/v4l2-ctrls.h
@@ -670,6 +670,31 @@ static inline int v4l2_ctrl_modify_range(struct v4l2_ctrl *ctrl,
*/
void v4l2_ctrl_notify(struct v4l2_ctrl *ctrl, v4l2_ctrl_notify_fnc notify, void *priv);
+/** v4l2_ctrl_get_name() - Get the name of the control
+ * @id: The control ID.
+ *
+ * This function returns the name of the given control ID or NULL if it isn't
+ * a known control.
+ */
+const char *v4l2_ctrl_get_name(u32 id);
+
+/** v4l2_ctrl_get_menu() - Get the menu string array of the control
+ * @id: The control ID.
+ *
+ * This function returns the NULL-terminated menu string array name of the
+ * given control ID or NULL if it isn't a known menu control.
+ */
+const char * const *v4l2_ctrl_get_menu(u32 id);
+
+/** v4l2_ctrl_get_int_menu() - Get the integer menu array of the control
+ * @id: The control ID.
+ * @len: The size of the integer array.
+ *
+ * This function returns the integer array of the given control ID or NULL if it
+ * if it isn't a known integer menu control.
+ */
+const s64 *v4l2_ctrl_get_int_menu(u32 id, u32 *len);
+
/** v4l2_ctrl_g_ctrl() - Helper function to get the control's value from within a driver.
* @ctrl: The control.
*
diff --git a/include/media/v4l2-image-sizes.h b/include/media/v4l2-image-sizes.h
index 10daf92..a07d7a6 100644
--- a/include/media/v4l2-image-sizes.h
+++ b/include/media/v4l2-image-sizes.h
@@ -25,10 +25,19 @@
#define QVGA_WIDTH 320
#define QVGA_HEIGHT 240
+#define SVGA_WIDTH 800
+#define SVGA_HEIGHT 600
+
#define SXGA_WIDTH 1280
#define SXGA_HEIGHT 1024
#define VGA_WIDTH 640
#define VGA_HEIGHT 480
+#define UXGA_WIDTH 1600
+#define UXGA_HEIGHT 1200
+
+#define XGA_WIDTH 1024
+#define XGA_HEIGHT 768
+
#endif /* _IMAGE_SIZES_H */
diff --git a/include/media/v4l2-mediabus.h b/include/media/v4l2-mediabus.h
index 395c4a9..38d960d 100644
--- a/include/media/v4l2-mediabus.h
+++ b/include/media/v4l2-mediabus.h
@@ -94,16 +94,20 @@ static inline void v4l2_fill_pix_format(struct v4l2_pix_format *pix_fmt,
pix_fmt->height = mbus_fmt->height;
pix_fmt->field = mbus_fmt->field;
pix_fmt->colorspace = mbus_fmt->colorspace;
+ pix_fmt->ycbcr_enc = mbus_fmt->ycbcr_enc;
+ pix_fmt->quantization = mbus_fmt->quantization;
}
static inline void v4l2_fill_mbus_format(struct v4l2_mbus_framefmt *mbus_fmt,
const struct v4l2_pix_format *pix_fmt,
- enum v4l2_mbus_pixelcode code)
+ u32 code)
{
mbus_fmt->width = pix_fmt->width;
mbus_fmt->height = pix_fmt->height;
mbus_fmt->field = pix_fmt->field;
mbus_fmt->colorspace = pix_fmt->colorspace;
+ mbus_fmt->ycbcr_enc = pix_fmt->ycbcr_enc;
+ mbus_fmt->quantization = pix_fmt->quantization;
mbus_fmt->code = code;
}
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index d746572..5860292 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -341,7 +341,7 @@ struct v4l2_subdev_video_ops {
int (*query_dv_timings)(struct v4l2_subdev *sd,
struct v4l2_dv_timings *timings);
int (*enum_mbus_fmt)(struct v4l2_subdev *sd, unsigned int index,
- enum v4l2_mbus_pixelcode *code);
+ u32 *code);
int (*enum_mbus_fsizes)(struct v4l2_subdev *sd,
struct v4l2_frmsizeenum *fsize);
int (*g_mbus_fmt)(struct v4l2_subdev *sd,
diff --git a/include/media/videobuf2-core.h b/include/media/videobuf2-core.h
index 6ef2d01..bd2cec2 100644
--- a/include/media/videobuf2-core.h
+++ b/include/media/videobuf2-core.h
@@ -82,19 +82,23 @@ struct vb2_threadio_data;
* unmap_dmabuf.
*/
struct vb2_mem_ops {
- void *(*alloc)(void *alloc_ctx, unsigned long size, gfp_t gfp_flags);
+ void *(*alloc)(void *alloc_ctx, unsigned long size,
+ enum dma_data_direction dma_dir,
+ gfp_t gfp_flags);
void (*put)(void *buf_priv);
struct dma_buf *(*get_dmabuf)(void *buf_priv, unsigned long flags);
void *(*get_userptr)(void *alloc_ctx, unsigned long vaddr,
- unsigned long size, int write);
+ unsigned long size,
+ enum dma_data_direction dma_dir);
void (*put_userptr)(void *buf_priv);
void (*prepare)(void *buf_priv);
void (*finish)(void *buf_priv);
void *(*attach_dmabuf)(void *alloc_ctx, struct dma_buf *dbuf,
- unsigned long size, int write);
+ unsigned long size,
+ enum dma_data_direction dma_dir);
void (*detach_dmabuf)(void *buf_priv);
int (*map_dmabuf)(void *buf_priv);
void (*unmap_dmabuf)(void *buf_priv);
@@ -270,22 +274,24 @@ struct vb2_buffer {
* queue setup from completing successfully; optional.
* @buf_prepare: called every time the buffer is queued from userspace
* and from the VIDIOC_PREPARE_BUF ioctl; drivers may
- * perform any initialization required before each hardware
- * operation in this callback; drivers that support
- * VIDIOC_CREATE_BUFS must also validate the buffer size;
- * if an error is returned, the buffer will not be queued
- * in driver; optional.
+ * perform any initialization required before each
+ * hardware operation in this callback; drivers can
+ * access/modify the buffer here as it is still synced for
+ * the CPU; drivers that support VIDIOC_CREATE_BUFS must
+ * also validate the buffer size; if an error is returned,
+ * the buffer will not be queued in driver; optional.
* @buf_finish: called before every dequeue of the buffer back to
- * userspace; drivers may perform any operations required
- * before userspace accesses the buffer; optional. The
- * buffer state can be one of the following: DONE and
- * ERROR occur while streaming is in progress, and the
- * PREPARED state occurs when the queue has been canceled
- * and all pending buffers are being returned to their
- * default DEQUEUED state. Typically you only have to do
- * something if the state is VB2_BUF_STATE_DONE, since in
- * all other cases the buffer contents will be ignored
- * anyway.
+ * userspace; the buffer is synced for the CPU, so drivers
+ * can access/modify the buffer contents; drivers may
+ * perform any operations required before userspace
+ * accesses the buffer; optional. The buffer state can be
+ * one of the following: DONE and ERROR occur while
+ * streaming is in progress, and the PREPARED state occurs
+ * when the queue has been canceled and all pending
+ * buffers are being returned to their default DEQUEUED
+ * state. Typically you only have to do something if the
+ * state is VB2_BUF_STATE_DONE, since in all other cases
+ * the buffer contents will be ignored anyway.
* @buf_cleanup: called once before the buffer is freed; drivers may
* perform any additional cleanup; optional.
* @start_streaming: called once to enter 'streaming' state; the driver may
diff --git a/include/media/videobuf2-dma-sg.h b/include/media/videobuf2-dma-sg.h
index 7b89852..14ce306 100644
--- a/include/media/videobuf2-dma-sg.h
+++ b/include/media/videobuf2-dma-sg.h
@@ -21,6 +21,9 @@ static inline struct sg_table *vb2_dma_sg_plane_desc(
return (struct sg_table *)vb2_plane_cookie(vb, plane_no);
}
+void *vb2_dma_sg_init_ctx(struct device *dev);
+void vb2_dma_sg_cleanup_ctx(void *alloc_ctx);
+
extern const struct vb2_mem_ops vb2_dma_sg_memops;
#endif
diff --git a/include/net/netfilter/nf_conntrack_core.h b/include/net/netfilter/nf_conntrack_core.h
index cc0c188..f2f0fa3 100644
--- a/include/net/netfilter/nf_conntrack_core.h
+++ b/include/net/netfilter/nf_conntrack_core.h
@@ -72,7 +72,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
return ret;
}
-int
+void
print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_l4proto *proto);
diff --git a/include/net/netfilter/nf_conntrack_l3proto.h b/include/net/netfilter/nf_conntrack_l3proto.h
index adc1fa3..cdc920b 100644
--- a/include/net/netfilter/nf_conntrack_l3proto.h
+++ b/include/net/netfilter/nf_conntrack_l3proto.h
@@ -38,8 +38,8 @@ struct nf_conntrack_l3proto {
const struct nf_conntrack_tuple *orig);
/* Print out the per-protocol part of the tuple. */
- int (*print_tuple)(struct seq_file *s,
- const struct nf_conntrack_tuple *);
+ void (*print_tuple)(struct seq_file *s,
+ const struct nf_conntrack_tuple *);
/*
* Called before tracking.
diff --git a/include/net/netfilter/nf_conntrack_l4proto.h b/include/net/netfilter/nf_conntrack_l4proto.h
index 4c8d573..1f70613 100644
--- a/include/net/netfilter/nf_conntrack_l4proto.h
+++ b/include/net/netfilter/nf_conntrack_l4proto.h
@@ -56,11 +56,11 @@ struct nf_conntrack_l4proto {
u_int8_t pf, unsigned int hooknum);
/* Print out the per-protocol part of the tuple. Return like seq_* */
- int (*print_tuple)(struct seq_file *s,
- const struct nf_conntrack_tuple *);
+ void (*print_tuple)(struct seq_file *s,
+ const struct nf_conntrack_tuple *);
/* Print out the private part of the conntrack. */
- int (*print_conntrack)(struct seq_file *s, struct nf_conn *);
+ void (*print_conntrack)(struct seq_file *s, struct nf_conn *);
/* Return the array of timeouts for this protocol. */
unsigned int *(*get_timeouts)(struct net *net);
diff --git a/include/net/sock.h b/include/net/sock.h
index df9b89b..c3e83c9 100644
--- a/include/net/sock.h
+++ b/include/net/sock.h
@@ -54,8 +54,8 @@
#include <linux/security.h>
#include <linux/slab.h>
#include <linux/uaccess.h>
+#include <linux/page_counter.h>
#include <linux/memcontrol.h>
-#include <linux/res_counter.h>
#include <linux/static_key.h>
#include <linux/aio.h>
#include <linux/sched.h>
@@ -909,6 +909,7 @@ static inline void sock_rps_reset_rxhash(struct sock *sk)
if (!__rc) { \
*(__timeo) = schedule_timeout(*(__timeo)); \
} \
+ sched_annotate_sleep(); \
lock_sock(__sk); \
__rc = __condition; \
__rc; \
@@ -1073,7 +1074,7 @@ enum cg_proto_flags {
};
struct cg_proto {
- struct res_counter memory_allocated; /* Current allocated memory. */
+ struct page_counter memory_allocated; /* Current allocated memory. */
struct percpu_counter sockets_allocated; /* Current number of sockets. */
int memory_pressure;
long sysctl_mem[3];
@@ -1225,34 +1226,26 @@ static inline void memcg_memory_allocated_add(struct cg_proto *prot,
unsigned long amt,
int *parent_status)
{
- struct res_counter *fail;
- int ret;
+ page_counter_charge(&prot->memory_allocated, amt);
- ret = res_counter_charge_nofail(&prot->memory_allocated,
- amt << PAGE_SHIFT, &fail);
- if (ret < 0)
+ if (page_counter_read(&prot->memory_allocated) >
+ prot->memory_allocated.limit)
*parent_status = OVER_LIMIT;
}
static inline void memcg_memory_allocated_sub(struct cg_proto *prot,
unsigned long amt)
{
- res_counter_uncharge(&prot->memory_allocated, amt << PAGE_SHIFT);
-}
-
-static inline u64 memcg_memory_allocated_read(struct cg_proto *prot)
-{
- u64 ret;
- ret = res_counter_read_u64(&prot->memory_allocated, RES_USAGE);
- return ret >> PAGE_SHIFT;
+ page_counter_uncharge(&prot->memory_allocated, amt);
}
static inline long
sk_memory_allocated(const struct sock *sk)
{
struct proto *prot = sk->sk_prot;
+
if (mem_cgroup_sockets_enabled && sk->sk_cgrp)
- return memcg_memory_allocated_read(sk->sk_cgrp);
+ return page_counter_read(&sk->sk_cgrp->memory_allocated);
return atomic_long_read(prot->memory_allocated);
}
@@ -1266,7 +1259,7 @@ sk_memory_allocated_add(struct sock *sk, int amt, int *parent_status)
memcg_memory_allocated_add(sk->sk_cgrp, amt, parent_status);
/* update the root cgroup regardless */
atomic_long_add_return(amt, prot->memory_allocated);
- return memcg_memory_allocated_read(sk->sk_cgrp);
+ return page_counter_read(&sk->sk_cgrp->memory_allocated);
}
return atomic_long_add_return(amt, prot->memory_allocated);
diff --git a/include/scsi/libfc.h b/include/scsi/libfc.h
index 52beadf..93d14da 100644
--- a/include/scsi/libfc.h
+++ b/include/scsi/libfc.h
@@ -1105,8 +1105,6 @@ int fc_eh_abort(struct scsi_cmnd *);
int fc_eh_device_reset(struct scsi_cmnd *);
int fc_eh_host_reset(struct scsi_cmnd *);
int fc_slave_alloc(struct scsi_device *);
-int fc_change_queue_depth(struct scsi_device *, int qdepth, int reason);
-int fc_change_queue_type(struct scsi_device *, int tag_type);
/*
* ELS/CT interface
diff --git a/include/scsi/libiscsi.h b/include/scsi/libiscsi.h
index 728c9ad..4d1c46a 100644
--- a/include/scsi/libiscsi.h
+++ b/include/scsi/libiscsi.h
@@ -378,8 +378,6 @@ struct iscsi_host {
/*
* scsi host template
*/
-extern int iscsi_change_queue_depth(struct scsi_device *sdev, int depth,
- int reason);
extern int iscsi_eh_abort(struct scsi_cmnd *sc);
extern int iscsi_eh_recover_target(struct scsi_cmnd *sc);
extern int iscsi_eh_session_reset(struct scsi_cmnd *sc);
diff --git a/include/scsi/libsas.h b/include/scsi/libsas.h
index ef7872c..832dcc9 100644
--- a/include/scsi/libsas.h
+++ b/include/scsi/libsas.h
@@ -365,12 +365,6 @@ struct asd_sas_phy {
struct scsi_core {
struct Scsi_Host *shost;
- struct mutex task_queue_flush;
- spinlock_t task_queue_lock;
- struct list_head task_queue;
- int task_queue_size;
-
- struct task_struct *queue_thread;
};
struct sas_ha_event {
@@ -422,9 +416,6 @@ struct sas_ha_struct {
struct asd_sas_port **sas_port; /* array of valid pointers, must be set */
int num_phys; /* must be set, gt 0, static */
- /* The class calls this to send a task for execution. */
- int lldd_max_execute_num;
- int lldd_queue_size;
int strict_wide_ports; /* both sas_addr and attached_sas_addr must match
* their siblings when forming wide ports */
@@ -612,7 +603,6 @@ struct sas_ssp_task {
struct sas_task {
struct domain_device *dev;
- struct list_head list;
spinlock_t task_state_lock;
unsigned task_state_flags;
@@ -665,8 +655,7 @@ struct sas_domain_function_template {
int (*lldd_dev_found)(struct domain_device *);
void (*lldd_dev_gone)(struct domain_device *);
- int (*lldd_execute_task)(struct sas_task *, int num,
- gfp_t gfp_flags);
+ int (*lldd_execute_task)(struct sas_task *, gfp_t gfp_flags);
/* Task Management Functions. Must be called from process context. */
int (*lldd_abort_task)(struct sas_task *);
@@ -700,12 +689,10 @@ extern void sas_suspend_ha(struct sas_ha_struct *sas_ha);
int sas_set_phy_speed(struct sas_phy *phy,
struct sas_phy_linkrates *rates);
int sas_phy_reset(struct sas_phy *phy, int hard_reset);
-int sas_queue_up(struct sas_task *task);
extern int sas_queuecommand(struct Scsi_Host * ,struct scsi_cmnd *);
extern int sas_target_alloc(struct scsi_target *);
extern int sas_slave_configure(struct scsi_device *);
-extern int sas_change_queue_depth(struct scsi_device *, int new_depth,
- int reason);
+extern int sas_change_queue_depth(struct scsi_device *, int new_depth);
extern int sas_change_queue_type(struct scsi_device *, int qt);
extern int sas_bios_param(struct scsi_device *,
struct block_device *,
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h
index d17178e..8a7f8ad 100644
--- a/include/scsi/scsi.h
+++ b/include/scsi/scsi.h
@@ -128,8 +128,10 @@ enum scsi_timeouts {
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
+#define SERVICE_ACTION_OUT_12 0xa9
#define WRITE_12 0xaa
-#define READ_MEDIA_SERIAL_NUMBER 0xab
+#define READ_MEDIA_SERIAL_NUMBER 0xab /* Obsolete with SPC-2 */
+#define SERVICE_ACTION_IN_12 0xab
#define WRITE_VERIFY_12 0xae
#define VERIFY_12 0xaf
#define SEARCH_HIGH_12 0xb0
@@ -151,7 +153,9 @@ enum scsi_timeouts {
#define VERIFY_16 0x8f
#define SYNCHRONIZE_CACHE_16 0x91
#define WRITE_SAME_16 0x93
-#define SERVICE_ACTION_IN 0x9e
+#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
+#define SERVICE_ACTION_IN_16 0x9e
+#define SERVICE_ACTION_OUT_16 0x9f
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
#define SAI_GET_LBA_STATUS 0x12
@@ -165,8 +169,8 @@ enum scsi_timeouts {
#define MI_REPORT_ALIASES 0x0b
#define MI_REPORT_SUPPORTED_OPERATION_CODES 0x0c
#define MI_REPORT_SUPPORTED_TASK_MANAGEMENT_FUNCTIONS 0x0d
-#define MI_REPORT_PRIORITY 0x0e
-#define MI_REPORT_TIMESTAMP 0x0f
+#define MI_REPORT_PRIORITY 0x0e
+#define MI_REPORT_TIMESTAMP 0x0f
#define MI_MANAGEMENT_PROTOCOL_IN 0x10
/* value for MI_REPORT_TARGET_PGS ext header */
#define MI_EXT_HDR_PARAM_FMT 0x20
diff --git a/include/scsi/scsi_cmnd.h b/include/scsi/scsi_cmnd.h
index 522a5f27..9fc1aec 100644
--- a/include/scsi/scsi_cmnd.h
+++ b/include/scsi/scsi_cmnd.h
@@ -53,6 +53,9 @@ struct scsi_pointer {
volatile int phase;
};
+/* for scmd->flags */
+#define SCMD_TAGGED (1 << 0)
+
struct scsi_cmnd {
struct scsi_device *device;
struct list_head list; /* scsi_cmnd participates in queue lists */
@@ -132,6 +135,7 @@ struct scsi_cmnd {
* to be at an address < 16Mb). */
int result; /* Status code from lower level driver */
+ int flags; /* Command flags */
unsigned char tag; /* SCSI-II queued command tag */
};
@@ -159,7 +163,7 @@ extern void *scsi_kmap_atomic_sg(struct scatterlist *sg, int sg_count,
size_t *offset, size_t *len);
extern void scsi_kunmap_atomic_sg(void *virt);
-extern int scsi_init_io(struct scsi_cmnd *cmd, gfp_t gfp_mask);
+extern int scsi_init_io(struct scsi_cmnd *cmd);
extern int scsi_dma_map(struct scsi_cmnd *cmd);
extern void scsi_dma_unmap(struct scsi_cmnd *cmd);
diff --git a/include/scsi/scsi_dbg.h b/include/scsi/scsi_dbg.h
index e89844c..7982795 100644
--- a/include/scsi/scsi_dbg.h
+++ b/include/scsi/scsi_dbg.h
@@ -2,23 +2,27 @@
#define _SCSI_SCSI_DBG_H
struct scsi_cmnd;
+struct scsi_device;
struct scsi_sense_hdr;
extern void scsi_print_command(struct scsi_cmnd *);
-extern void __scsi_print_command(unsigned char *);
-extern void scsi_show_extd_sense(unsigned char, unsigned char);
-extern void scsi_show_sense_hdr(struct scsi_sense_hdr *);
-extern void scsi_print_sense_hdr(const char *, struct scsi_sense_hdr *);
-extern void scsi_cmd_print_sense_hdr(struct scsi_cmnd *, const char *,
- struct scsi_sense_hdr *);
-extern void scsi_print_sense(char *, struct scsi_cmnd *);
-extern void __scsi_print_sense(const char *name,
+extern void __scsi_print_command(const unsigned char *, size_t);
+extern void scsi_show_extd_sense(const struct scsi_device *, const char *,
+ unsigned char, unsigned char);
+extern void scsi_show_sense_hdr(const struct scsi_device *, const char *,
+ const struct scsi_sense_hdr *);
+extern void scsi_print_sense_hdr(const struct scsi_device *, const char *,
+ const struct scsi_sense_hdr *);
+extern void scsi_print_sense(const struct scsi_cmnd *);
+extern void __scsi_print_sense(const struct scsi_device *, const char *name,
const unsigned char *sense_buffer,
int sense_len);
-extern void scsi_show_result(int);
-extern void scsi_print_result(struct scsi_cmnd *);
-extern void scsi_print_status(unsigned char);
+extern void scsi_print_result(struct scsi_cmnd *, const char *, int);
+extern const char *scsi_hostbyte_string(int);
+extern const char *scsi_driverbyte_string(int);
+extern const char *scsi_mlreturn_string(int);
extern const char *scsi_sense_key_string(unsigned char);
-extern const char *scsi_extd_sense_format(unsigned char, unsigned char);
+extern const char *scsi_extd_sense_format(unsigned char, unsigned char,
+ const char **);
#endif /* _SCSI_SCSI_DBG_H */
diff --git a/include/scsi/scsi_device.h b/include/scsi/scsi_device.h
index 27ecee7..6364e23 100644
--- a/include/scsi/scsi_device.h
+++ b/include/scsi/scsi_device.h
@@ -141,7 +141,6 @@ struct scsi_device {
unsigned ppr:1; /* Device supports PPR messages */
unsigned tagged_supported:1; /* Supports SCSI-II tagged queuing */
unsigned simple_tags:1; /* simple queue tag messages are enabled */
- unsigned ordered_tags:1;/* ordered queue tag messages are enabled */
unsigned was_reset:1; /* There was a bus reset on the bus for
* this device */
unsigned expecting_cc_ua:1; /* Expecting a CHECK_CONDITION/UNIT_ATTN
@@ -201,11 +200,6 @@ struct scsi_device {
unsigned long sdev_data[0];
} __attribute__((aligned(sizeof(unsigned long))));
-struct scsi_dh_devlist {
- char *vendor;
- char *model;
-};
-
typedef void (*activate_complete)(void *, int);
struct scsi_device_handler {
/* Used by the infrastructure */
@@ -214,9 +208,8 @@ struct scsi_device_handler {
/* Filled by the hardware handler */
struct module *module;
const char *name;
- const struct scsi_dh_devlist *devlist;
int (*check_sense)(struct scsi_device *, struct scsi_sense_hdr *);
- int (*attach)(struct scsi_device *);
+ struct scsi_dh_data *(*attach)(struct scsi_device *);
void (*detach)(struct scsi_device *);
int (*activate)(struct scsi_device *, activate_complete, void *);
int (*prep_fn)(struct scsi_device *, struct request *);
@@ -228,7 +221,6 @@ struct scsi_dh_data {
struct scsi_device_handler *scsi_dh;
struct scsi_device *sdev;
struct kref kref;
- char buf[0];
};
#define to_scsi_device(d) \
@@ -244,6 +236,15 @@ struct scsi_dh_data {
#define sdev_dbg(sdev, fmt, a...) \
dev_dbg(&(sdev)->sdev_gendev, fmt, ##a)
+/*
+ * like scmd_printk, but the device name is passed in
+ * as a string pointer
+ */
+#define sdev_prefix_printk(l, sdev, p, fmt, a...) \
+ (p) ? \
+ sdev_printk(l, sdev, "[%s] " fmt, p, ##a) : \
+ sdev_printk(l, sdev, fmt, ##a)
+
#define scmd_printk(prefix, scmd, fmt, a...) \
(scmd)->request->rq_disk ? \
sdev_printk(prefix, (scmd)->device, "[%s] " fmt, \
@@ -379,7 +380,7 @@ extern struct scsi_device *__scsi_iterate_devices(struct Scsi_Host *,
#define __shost_for_each_device(sdev, shost) \
list_for_each_entry((sdev), &((shost)->__devices), siblings)
-extern void scsi_adjust_queue_depth(struct scsi_device *, int, int);
+extern int scsi_change_queue_depth(struct scsi_device *, int);
extern int scsi_track_queue_full(struct scsi_device *, int);
extern int scsi_set_medium_removal(struct scsi_device *, char);
diff --git a/include/scsi/scsi_driver.h b/include/scsi/scsi_driver.h
index c2b7598..891a658 100644
--- a/include/scsi/scsi_driver.h
+++ b/include/scsi/scsi_driver.h
@@ -9,7 +9,6 @@ struct scsi_cmnd;
struct scsi_device;
struct scsi_driver {
- struct module *owner;
struct device_driver gendrv;
void (*rescan)(struct device *);
diff --git a/include/scsi/scsi_eh.h b/include/scsi/scsi_eh.h
index 06a8790..1e1421b 100644
--- a/include/scsi/scsi_eh.h
+++ b/include/scsi/scsi_eh.h
@@ -27,10 +27,10 @@ struct scsi_sense_hdr { /* See SPC-3 section 4.5 */
u8 additional_length; /* always 0 for fixed sense format */
};
-static inline int scsi_sense_valid(struct scsi_sense_hdr *sshdr)
+static inline bool scsi_sense_valid(const struct scsi_sense_hdr *sshdr)
{
if (!sshdr)
- return 0;
+ return false;
return (sshdr->response_code & 0x70) == 0x70;
}
@@ -42,12 +42,12 @@ extern void scsi_eh_flush_done_q(struct list_head *done_q);
extern void scsi_report_bus_reset(struct Scsi_Host *, int);
extern void scsi_report_device_reset(struct Scsi_Host *, int, int);
extern int scsi_block_when_processing_errors(struct scsi_device *);
-extern int scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
- struct scsi_sense_hdr *sshdr);
-extern int scsi_command_normalize_sense(struct scsi_cmnd *cmd,
- struct scsi_sense_hdr *sshdr);
+extern bool scsi_normalize_sense(const u8 *sense_buffer, int sb_len,
+ struct scsi_sense_hdr *sshdr);
+extern bool scsi_command_normalize_sense(const struct scsi_cmnd *cmd,
+ struct scsi_sense_hdr *sshdr);
-static inline int scsi_sense_is_deferred(struct scsi_sense_hdr *sshdr)
+static inline bool scsi_sense_is_deferred(const struct scsi_sense_hdr *sshdr)
{
return ((sshdr->response_code >= 0x70) && (sshdr->response_code & 1));
}
@@ -60,15 +60,7 @@ extern int scsi_get_sense_info_fld(const u8 * sense_buffer, int sb_len,
extern void scsi_build_sense_buffer(int desc, u8 *buf, u8 key, u8 asc, u8 ascq);
-/*
- * Reset request from external source
- */
-#define SCSI_TRY_RESET_DEVICE 1
-#define SCSI_TRY_RESET_BUS 2
-#define SCSI_TRY_RESET_HOST 3
-#define SCSI_TRY_RESET_TARGET 4
-
-extern int scsi_reset_provider(struct scsi_device *, int);
+extern int scsi_ioctl_reset(struct scsi_device *, int __user *);
struct scsi_eh_save {
/* saved state */
diff --git a/include/scsi/scsi_host.h b/include/scsi/scsi_host.h
index 5e36248..c8a462e 100644
--- a/include/scsi/scsi_host.h
+++ b/include/scsi/scsi_host.h
@@ -46,12 +46,6 @@ struct blk_queue_tags;
#define DISABLE_CLUSTERING 0
#define ENABLE_CLUSTERING 1
-enum {
- SCSI_QDEPTH_DEFAULT, /* default requested change, e.g. from sysfs */
- SCSI_QDEPTH_QFULL, /* scsi-ml requested due to queue full */
- SCSI_QDEPTH_RAMP_UP, /* scsi-ml requested due to threshold event */
-};
-
struct scsi_host_template {
struct module *module;
const char *name;
@@ -195,7 +189,7 @@ struct scsi_host_template {
* Things currently recommended to be handled at this time include:
*
* 1. Setting the device queue depth. Proper setting of this is
- * described in the comments for scsi_adjust_queue_depth.
+ * described in the comments for scsi_change_queue_depth.
* 2. Determining if the device supports the various synchronous
* negotiation protocols. The device struct will already have
* responded to INQUIRY and the results of the standard items
@@ -281,7 +275,7 @@ struct scsi_host_template {
*
* Status: OPTIONAL
*/
- int (* change_queue_depth)(struct scsi_device *, int, int);
+ int (* change_queue_depth)(struct scsi_device *, int);
/*
* Fill in this function to allow the changing of tag types
@@ -422,6 +416,16 @@ struct scsi_host_template {
unsigned char present;
/*
+ * Let the block layer assigns tags to all commands.
+ */
+ unsigned use_blk_tags:1;
+
+ /*
+ * Track QUEUE_FULL events and reduce queue depth on demand.
+ */
+ unsigned track_queue_depth:1;
+
+ /*
* This specifies the mode that a LLD supports.
*/
unsigned supported_mode:2;
@@ -451,11 +455,6 @@ struct scsi_host_template {
*/
unsigned skip_settle_delay:1;
- /*
- * True if we are using ordered write support.
- */
- unsigned ordered_tag:1;
-
/* True if the controller does not support WRITE SAME */
unsigned no_write_same:1;
@@ -638,6 +637,14 @@ struct Scsi_Host {
short unsigned int sg_prot_tablesize;
unsigned int max_sectors;
unsigned long dma_boundary;
+ /*
+ * In scsi-mq mode, the number of hardware queues supported by the LLD.
+ *
+ * Note: it is assumed that each hardware queue has a queue depth of
+ * can_queue. In other words, the total queue depth per host
+ * is nr_hw_queues * can_queue.
+ */
+ unsigned nr_hw_queues;
/*
* Used to assign serial numbers to the cmds.
* Protected by the host lock.
@@ -647,7 +654,6 @@ struct Scsi_Host {
unsigned active_mode:2;
unsigned unchecked_isa_dma:1;
unsigned use_clustering:1;
- unsigned use_blk_tcq:1;
/*
* Host has requested that no further requests come through for the
@@ -662,11 +668,6 @@ struct Scsi_Host {
*/
unsigned reverse_ordering:1;
- /*
- * Ordered write support
- */
- unsigned ordered_tag:1;
-
/* Task mgmt function in progress */
unsigned tmf_in_progress:1;
diff --git a/include/scsi/scsi_ioctl.h b/include/scsi/scsi_ioctl.h
index b900684..8d19d1d 100644
--- a/include/scsi/scsi_ioctl.h
+++ b/include/scsi/scsi_ioctl.h
@@ -40,9 +40,9 @@ typedef struct scsi_fctargaddress {
unsigned char host_wwn[8]; // include NULL term.
} Scsi_FCTargAddress;
+int scsi_ioctl_block_when_processing_errors(struct scsi_device *sdev,
+ int cmd, bool ndelay);
extern int scsi_ioctl(struct scsi_device *, int, void __user *);
-extern int scsi_nonblockable_ioctl(struct scsi_device *sdev, int cmd,
- void __user *arg, int ndelay);
#endif /* __KERNEL__ */
#endif /* _SCSI_IOCTL_H */
diff --git a/include/scsi/scsi_tcq.h b/include/scsi/scsi_tcq.h
index 56ed843..fe4a702 100644
--- a/include/scsi/scsi_tcq.h
+++ b/include/scsi/scsi_tcq.h
@@ -16,20 +16,16 @@
#ifdef CONFIG_BLOCK
+int scsi_change_queue_type(struct scsi_device *sdev, int tag_type);
+
/**
* scsi_get_tag_type - get the type of tag the device supports
* @sdev: the scsi device
- *
- * Notes:
- * If the drive only supports simple tags, returns MSG_SIMPLE_TAG
- * if it supports all tag types, returns MSG_ORDERED_TAG.
*/
static inline int scsi_get_tag_type(struct scsi_device *sdev)
{
if (!sdev->tagged_supported)
return 0;
- if (sdev->ordered_tags)
- return MSG_ORDERED_TAG;
if (sdev->simple_tags)
return MSG_SIMPLE_TAG;
return 0;
@@ -39,90 +35,33 @@ static inline void scsi_set_tag_type(struct scsi_device *sdev, int tag)
{
switch (tag) {
case MSG_ORDERED_TAG:
- sdev->ordered_tags = 1;
- /* fall through */
case MSG_SIMPLE_TAG:
sdev->simple_tags = 1;
break;
case 0:
/* fall through */
default:
- sdev->ordered_tags = 0;
sdev->simple_tags = 0;
break;
}
}
-/**
- * scsi_activate_tcq - turn on tag command queueing
- * @SDpnt: device to turn on TCQ for
- * @depth: queue depth
- *
- * Notes:
- * Eventually, I hope depth would be the maximum depth
- * the device could cope with and the real queue depth
- * would be adjustable from 0 to depth.
- **/
-static inline void scsi_activate_tcq(struct scsi_device *sdev, int depth)
-{
- if (!sdev->tagged_supported)
- return;
-
- if (shost_use_blk_mq(sdev->host))
- queue_flag_set_unlocked(QUEUE_FLAG_QUEUED, sdev->request_queue);
- else if (!blk_queue_tagged(sdev->request_queue))
- blk_queue_init_tags(sdev->request_queue, depth,
- sdev->host->bqt);
-
- scsi_adjust_queue_depth(sdev, scsi_get_tag_type(sdev), depth);
-}
-
-/**
- * scsi_deactivate_tcq - turn off tag command queueing
- * @SDpnt: device to turn off TCQ for
- **/
-static inline void scsi_deactivate_tcq(struct scsi_device *sdev, int depth)
-{
- if (blk_queue_tagged(sdev->request_queue))
- blk_queue_free_tags(sdev->request_queue);
- scsi_adjust_queue_depth(sdev, 0, depth);
-}
-
-/**
- * scsi_populate_tag_msg - place a tag message in a buffer
- * @SCpnt: pointer to the Scsi_Cmnd for the tag
- * @msg: pointer to the area to place the tag
- *
- * Notes:
- * designed to create the correct type of tag message for the
- * particular request. Returns the size of the tag message.
- * May return 0 if TCQ is disabled for this device.
- **/
-static inline int scsi_populate_tag_msg(struct scsi_cmnd *cmd, char *msg)
-{
- struct request *req = cmd->request;
-
- if (blk_rq_tagged(req)) {
- *msg++ = MSG_SIMPLE_TAG;
- *msg++ = req->tag;
- return 2;
- }
-
- return 0;
-}
static inline struct scsi_cmnd *scsi_mq_find_tag(struct Scsi_Host *shost,
- unsigned int hw_ctx, int tag)
+ int unique_tag)
{
- struct request *req;
+ u16 hwq = blk_mq_unique_tag_to_hwq(unique_tag);
+ struct request *req = NULL;
- req = blk_mq_tag_to_rq(shost->tag_set.tags[hw_ctx], tag);
+ if (hwq < shost->tag_set.nr_hw_queues)
+ req = blk_mq_tag_to_rq(shost->tag_set.tags[hwq],
+ blk_mq_unique_tag_to_tag(unique_tag));
return req ? (struct scsi_cmnd *)req->special : NULL;
}
/**
* scsi_find_tag - find a tagged command by device
* @SDpnt: pointer to the ScSI device
- * @tag: the tag number
+ * @tag: tag generated by blk_mq_unique_tag()
*
* Notes:
* Only works with tags allocated by the generic blk layer.
@@ -133,9 +72,9 @@ static inline struct scsi_cmnd *scsi_find_tag(struct scsi_device *sdev, int tag)
if (tag != SCSI_NO_TAG) {
if (shost_use_blk_mq(sdev->host))
- return scsi_mq_find_tag(sdev->host, 0, tag);
+ return scsi_mq_find_tag(sdev->host, tag);
- req = blk_queue_find_tag(sdev->request_queue, tag);
+ req = blk_queue_find_tag(sdev->request_queue, tag);
return req ? (struct scsi_cmnd *)req->special : NULL;
}
@@ -174,7 +113,7 @@ static inline int scsi_init_shared_tag_map(struct Scsi_Host *shost, int depth)
/**
* scsi_host_find_tag - find the tagged command by host
* @shost: pointer to scsi_host
- * @tag: tag of the scsi_cmnd
+ * @tag: tag generated by blk_mq_unique_tag()
*
* Notes:
* Only works with tags allocated by the generic blk layer.
@@ -186,7 +125,7 @@ static inline struct scsi_cmnd *scsi_host_find_tag(struct Scsi_Host *shost,
if (tag != SCSI_NO_TAG) {
if (shost_use_blk_mq(shost))
- return scsi_mq_find_tag(shost, 0, tag);
+ return scsi_mq_find_tag(shost, tag);
req = blk_map_queue_find_tag(shost->bqt, tag);
return req ? (struct scsi_cmnd *)req->special : NULL;
}
diff --git a/include/scsi/scsi_transport_spi.h b/include/scsi/scsi_transport_spi.h
index 7497a38..a4fa52b 100644
--- a/include/scsi/scsi_transport_spi.h
+++ b/include/scsi/scsi_transport_spi.h
@@ -157,5 +157,6 @@ int spi_populate_width_msg(unsigned char *msg, int width);
int spi_populate_sync_msg(unsigned char *msg, int period, int offset);
int spi_populate_ppr_msg(unsigned char *msg, int period, int offset, int width,
int options);
+int spi_populate_tag_msg(unsigned char *msg, struct scsi_cmnd *cmd);
#endif /* SCSI_TRANSPORT_SPI_H */
diff --git a/include/scsi/sg.h b/include/scsi/sg.h
index 750e5db..3afec70 100644
--- a/include/scsi/sg.h
+++ b/include/scsi/sg.h
@@ -164,12 +164,15 @@ typedef struct sg_req_info { /* used by SG_GET_REQUEST_TABLE ioctl() */
/* Returns -EBUSY if occupied. 3rd argument pointer to int (see next) */
#define SG_SCSI_RESET 0x2284
-/* Associated values that can be given to SG_SCSI_RESET follow */
+/* Associated values that can be given to SG_SCSI_RESET follow.
+ * SG_SCSI_RESET_NO_ESCALATE may be OR-ed to the _DEVICE, _TARGET, _BUS
+ * or _HOST reset value so only that action is attempted. */
#define SG_SCSI_RESET_NOTHING 0
#define SG_SCSI_RESET_DEVICE 1
#define SG_SCSI_RESET_BUS 2
#define SG_SCSI_RESET_HOST 3
#define SG_SCSI_RESET_TARGET 4
+#define SG_SCSI_RESET_NO_ESCALATE 0x100
/* synchronous SCSI command ioctl, (only in version 3 interface) */
#define SG_IO 0x2285 /* similar effect as write() followed by read() */
diff --git a/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h b/include/soc/at91/at91rm9200_sdramc.h
index aa047f45..aa047f45 100644
--- a/arch/arm/mach-at91/include/mach/at91rm9200_sdramc.h
+++ b/include/soc/at91/at91rm9200_sdramc.h
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h b/include/soc/at91/at91sam9_ddrsdr.h
index 0210797..0210797 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9_ddrsdr.h
+++ b/include/soc/at91/at91sam9_ddrsdr.h
diff --git a/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h b/include/soc/at91/at91sam9_sdramc.h
index 3d085a9..3d085a9 100644
--- a/arch/arm/mach-at91/include/mach/at91sam9_sdramc.h
+++ b/include/soc/at91/at91sam9_sdramc.h
diff --git a/include/soc/tegra/mc.h b/include/soc/tegra/mc.h
new file mode 100644
index 0000000..63deb8d
--- /dev/null
+++ b/include/soc/tegra/mc.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 2014 NVIDIA 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 __SOC_TEGRA_MC_H__
+#define __SOC_TEGRA_MC_H__
+
+#include <linux/types.h>
+
+struct clk;
+struct device;
+struct page;
+
+struct tegra_smmu_enable {
+ unsigned int reg;
+ unsigned int bit;
+};
+
+/* latency allowance */
+struct tegra_mc_la {
+ unsigned int reg;
+ unsigned int shift;
+ unsigned int mask;
+ unsigned int def;
+};
+
+struct tegra_mc_client {
+ unsigned int id;
+ const char *name;
+ unsigned int swgroup;
+
+ unsigned int fifo_size;
+
+ struct tegra_smmu_enable smmu;
+ struct tegra_mc_la la;
+};
+
+struct tegra_smmu_swgroup {
+ unsigned int swgroup;
+ unsigned int reg;
+};
+
+struct tegra_smmu_ops {
+ void (*flush_dcache)(struct page *page, unsigned long offset,
+ size_t size);
+};
+
+struct tegra_smmu_soc {
+ const struct tegra_mc_client *clients;
+ unsigned int num_clients;
+
+ const struct tegra_smmu_swgroup *swgroups;
+ unsigned int num_swgroups;
+
+ bool supports_round_robin_arbitration;
+ bool supports_request_limit;
+
+ unsigned int num_asids;
+
+ const struct tegra_smmu_ops *ops;
+};
+
+struct tegra_mc;
+struct tegra_smmu;
+
+#ifdef CONFIG_TEGRA_IOMMU_SMMU
+struct tegra_smmu *tegra_smmu_probe(struct device *dev,
+ const struct tegra_smmu_soc *soc,
+ struct tegra_mc *mc);
+#else
+static inline struct tegra_smmu *
+tegra_smmu_probe(struct device *dev, const struct tegra_smmu_soc *soc,
+ struct tegra_mc *mc)
+{
+ return NULL;
+}
+#endif
+
+struct tegra_mc_soc {
+ const struct tegra_mc_client *clients;
+ unsigned int num_clients;
+
+ const unsigned int *emem_regs;
+ unsigned int num_emem_regs;
+
+ unsigned int num_address_bits;
+ unsigned int atom_size;
+
+ const struct tegra_smmu_soc *smmu;
+};
+
+struct tegra_mc {
+ struct device *dev;
+ struct tegra_smmu *smmu;
+ void __iomem *regs;
+ struct clk *clk;
+ int irq;
+
+ const struct tegra_mc_soc *soc;
+ unsigned long tick;
+};
+
+#endif /* __SOC_TEGRA_MC_H__ */
diff --git a/include/sound/compress_driver.h b/include/sound/compress_driver.h
index ae6c3b8..396e8f7 100644
--- a/include/sound/compress_driver.h
+++ b/include/sound/compress_driver.h
@@ -42,12 +42,11 @@ struct snd_compr_ops;
* @buffer_size: size of the above buffer
* @fragment_size: size of buffer fragment in bytes
* @fragments: number of such fragments
- * @hw_pointer: offset of last location in buffer where DSP copied data
- * @app_pointer: offset of last location in buffer where app wrote data
* @total_bytes_available: cumulative number of bytes made available in
* the ring buffer
* @total_bytes_transferred: cumulative bytes transferred by offload DSP
* @sleep: poll sleep
+ * @private_data: driver private data pointer
*/
struct snd_compr_runtime {
snd_pcm_state_t state;
@@ -94,6 +93,8 @@ struct snd_compr_stream {
* This can be called in during stream creation only to set codec params
* and the stream properties
* @get_params: retrieve the codec parameters, mandatory
+ * @set_metadata: Set the metadata values for a stream
+ * @get_metadata: retreives the requested metadata values from stream
* @trigger: Trigger operations like start, pause, resume, drain, stop.
* This callback is mandatory
* @pointer: Retrieve current h/w pointer information. Mandatory
diff --git a/include/sound/jack.h b/include/sound/jack.h
index 5891657..2182350 100644
--- a/include/sound/jack.h
+++ b/include/sound/jack.h
@@ -28,8 +28,23 @@
struct input_dev;
/**
- * Jack types which can be reported. These values are used as a
- * bitmask.
+ * enum snd_jack_types - Jack types which can be reported
+ * @SND_JACK_HEADPHONE: Headphone
+ * @SND_JACK_MICROPHONE: Microphone
+ * @SND_JACK_HEADSET: Headset
+ * @SND_JACK_LINEOUT: Line out
+ * @SND_JACK_MECHANICAL: Mechanical switch
+ * @SND_JACK_VIDEOOUT: Video out
+ * @SND_JACK_AVOUT: AV (Audio Video) out
+ * @SND_JACK_LINEIN: Line in
+ * @SND_JACK_BTN_0: Button 0
+ * @SND_JACK_BTN_1: Button 1
+ * @SND_JACK_BTN_2: Button 2
+ * @SND_JACK_BTN_3: Button 3
+ * @SND_JACK_BTN_4: Button 4
+ * @SND_JACK_BTN_5: Button 5
+ *
+ * These values are used as a bitmask.
*
* Note that this must be kept in sync with the lookup table in
* sound/core/jack.c.
@@ -90,6 +105,13 @@ static inline void snd_jack_set_parent(struct snd_jack *jack,
{
}
+static inline int snd_jack_set_key(struct snd_jack *jack,
+ enum snd_jack_types type,
+ int keytype)
+{
+ return 0;
+}
+
static inline void snd_jack_report(struct snd_jack *jack, int status)
{
}
diff --git a/include/sound/omap-hdmi-audio.h b/include/sound/omap-hdmi-audio.h
new file mode 100644
index 0000000..afdb416
--- /dev/null
+++ b/include/sound/omap-hdmi-audio.h
@@ -0,0 +1,43 @@
+/*
+ * hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <video/omapdss.h>
+
+#ifndef __OMAP_HDMI_AUDIO_H__
+#define __OMAP_HDMI_AUDIO_H__
+
+struct omap_hdmi_audio_ops {
+ int (*audio_startup)(struct device *dev,
+ void (*abort_cb)(struct device *dev));
+ int (*audio_shutdown)(struct device *dev);
+ int (*audio_start)(struct device *dev);
+ void (*audio_stop)(struct device *dev);
+ int (*audio_config)(struct device *dev,
+ struct omap_dss_audio *dss_audio);
+};
+
+/* HDMI audio initalization data */
+struct omap_hdmi_audio_pdata {
+ struct device *dev;
+ enum omapdss_version dss_version;
+ phys_addr_t audio_dma_addr;
+
+ const struct omap_hdmi_audio_ops *ops;
+};
+
+#endif /* __OMAP_HDMI_AUDIO_H__ */
diff --git a/include/sound/pcm.h b/include/sound/pcm.h
index 8bb00a2..1e7f74a 100644
--- a/include/sound/pcm.h
+++ b/include/sound/pcm.h
@@ -418,7 +418,10 @@ struct snd_pcm_substream {
struct snd_info_entry *proc_status_entry;
struct snd_info_entry *proc_prealloc_entry;
struct snd_info_entry *proc_prealloc_max_entry;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ struct snd_info_entry *proc_xrun_injection_entry;
#endif
+#endif /* CONFIG_SND_VERBOSE_PROCFS */
/* misc flags */
unsigned int hw_opened: 1;
};
@@ -505,6 +508,7 @@ int snd_pcm_status(struct snd_pcm_substream *substream,
int snd_pcm_start(struct snd_pcm_substream *substream);
int snd_pcm_stop(struct snd_pcm_substream *substream, snd_pcm_state_t status);
int snd_pcm_drain_done(struct snd_pcm_substream *substream);
+int snd_pcm_stop_xrun(struct snd_pcm_substream *substream);
#ifdef CONFIG_PM
int snd_pcm_suspend(struct snd_pcm_substream *substream);
int snd_pcm_suspend_all(struct snd_pcm *pcm);
@@ -535,6 +539,12 @@ snd_pcm_debug_name(struct snd_pcm_substream *substream, char *buf, size_t size)
* PCM library
*/
+/**
+ * snd_pcm_stream_linked - Check whether the substream is linked with others
+ * @substream: substream to check
+ *
+ * Returns true if the given substream is being linked with others.
+ */
static inline int snd_pcm_stream_linked(struct snd_pcm_substream *substream)
{
return substream->group != &substream->self_group;
@@ -545,6 +555,16 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream);
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream);
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream);
unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
+
+/**
+ * snd_pcm_stream_lock_irqsave - Lock the PCM stream
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock() but with the local
+ * IRQ (only when nonatomic is false). In nonatomic case, this is identical
+ * as snd_pcm_stream_lock().
+ */
#define snd_pcm_stream_lock_irqsave(substream, flags) \
do { \
typecheck(unsigned long, flags); \
@@ -553,9 +573,25 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream);
void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
unsigned long flags);
+/**
+ * snd_pcm_group_for_each_entry - iterate over the linked substreams
+ * @s: the iterator
+ * @substream: the substream
+ *
+ * Iterate over the all linked substreams to the given @substream.
+ * When @substream isn't linked with any others, this gives returns @substream
+ * itself once.
+ */
#define snd_pcm_group_for_each_entry(s, substream) \
list_for_each_entry(s, &substream->group->substreams, link_list)
+/**
+ * snd_pcm_running - Check whether the substream is in a running state
+ * @substream: substream to check
+ *
+ * Returns true if the given substream is in the state RUNNING, or in the
+ * state DRAINING for playback.
+ */
static inline int snd_pcm_running(struct snd_pcm_substream *substream)
{
return (substream->runtime->status->state == SNDRV_PCM_STATE_RUNNING ||
@@ -563,45 +599,81 @@ static inline int snd_pcm_running(struct snd_pcm_substream *substream)
substream->stream == SNDRV_PCM_STREAM_PLAYBACK));
}
+/**
+ * bytes_to_samples - Unit conversion of the size from bytes to samples
+ * @runtime: PCM runtime instance
+ * @size: size in bytes
+ */
static inline ssize_t bytes_to_samples(struct snd_pcm_runtime *runtime, ssize_t size)
{
return size * 8 / runtime->sample_bits;
}
+/**
+ * bytes_to_frames - Unit conversion of the size from bytes to frames
+ * @runtime: PCM runtime instance
+ * @size: size in bytes
+ */
static inline snd_pcm_sframes_t bytes_to_frames(struct snd_pcm_runtime *runtime, ssize_t size)
{
return size * 8 / runtime->frame_bits;
}
+/**
+ * samples_to_bytes - Unit conversion of the size from samples to bytes
+ * @runtime: PCM runtime instance
+ * @size: size in samples
+ */
static inline ssize_t samples_to_bytes(struct snd_pcm_runtime *runtime, ssize_t size)
{
return size * runtime->sample_bits / 8;
}
+/**
+ * frames_to_bytes - Unit conversion of the size from frames to bytes
+ * @runtime: PCM runtime instance
+ * @size: size in frames
+ */
static inline ssize_t frames_to_bytes(struct snd_pcm_runtime *runtime, snd_pcm_sframes_t size)
{
return size * runtime->frame_bits / 8;
}
+/**
+ * frame_aligned - Check whether the byte size is aligned to frames
+ * @runtime: PCM runtime instance
+ * @bytes: size in bytes
+ */
static inline int frame_aligned(struct snd_pcm_runtime *runtime, ssize_t bytes)
{
return bytes % runtime->byte_align == 0;
}
+/**
+ * snd_pcm_lib_buffer_bytes - Get the buffer size of the current PCM in bytes
+ * @substream: PCM substream
+ */
static inline size_t snd_pcm_lib_buffer_bytes(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
return frames_to_bytes(runtime, runtime->buffer_size);
}
+/**
+ * snd_pcm_lib_period_bytes - Get the period size of the current PCM in bytes
+ * @substream: PCM substream
+ */
static inline size_t snd_pcm_lib_period_bytes(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
return frames_to_bytes(runtime, runtime->period_size);
}
-/*
- * result is: 0 ... (boundary - 1)
+/**
+ * snd_pcm_playback_avail - Get the available (writable) space for playback
+ * @runtime: PCM runtime instance
+ *
+ * Result is between 0 ... (boundary - 1)
*/
static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *runtime)
{
@@ -613,8 +685,11 @@ static inline snd_pcm_uframes_t snd_pcm_playback_avail(struct snd_pcm_runtime *r
return avail;
}
-/*
- * result is: 0 ... (boundary - 1)
+/**
+ * snd_pcm_playback_avail - Get the available (readable) space for capture
+ * @runtime: PCM runtime instance
+ *
+ * Result is between 0 ... (boundary - 1)
*/
static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *runtime)
{
@@ -624,11 +699,19 @@ static inline snd_pcm_uframes_t snd_pcm_capture_avail(struct snd_pcm_runtime *ru
return avail;
}
+/**
+ * snd_pcm_playback_hw_avail - Get the queued space for playback
+ * @runtime: PCM runtime instance
+ */
static inline snd_pcm_sframes_t snd_pcm_playback_hw_avail(struct snd_pcm_runtime *runtime)
{
return runtime->buffer_size - snd_pcm_playback_avail(runtime);
}
+/**
+ * snd_pcm_capture_hw_avail - Get the free space for capture
+ * @runtime: PCM runtime instance
+ */
static inline snd_pcm_sframes_t snd_pcm_capture_hw_avail(struct snd_pcm_runtime *runtime)
{
return runtime->buffer_size - snd_pcm_capture_avail(runtime);
@@ -708,6 +791,20 @@ static inline int snd_pcm_capture_empty(struct snd_pcm_substream *substream)
return snd_pcm_capture_avail(runtime) == 0;
}
+/**
+ * snd_pcm_trigger_done - Mark the master substream
+ * @substream: the pcm substream instance
+ * @master: the linked master substream
+ *
+ * When multiple substreams of the same card are linked and the hardware
+ * supports the single-shot operation, the driver calls this in the loop
+ * in snd_pcm_group_for_each_entry() for marking the substream as "done".
+ * Then most of trigger operations are performed only to the given master
+ * substream.
+ *
+ * The trigger_master mark is cleared at timestamp updates at the end
+ * of trigger operations.
+ */
static inline void snd_pcm_trigger_done(struct snd_pcm_substream *substream,
struct snd_pcm_substream *master)
{
@@ -750,18 +847,59 @@ static inline const struct snd_interval *hw_param_interval_c(const struct snd_pc
return &params->intervals[var - SNDRV_PCM_HW_PARAM_FIRST_INTERVAL];
}
-#define params_channels(p) \
- (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_CHANNELS)->min)
-#define params_rate(p) \
- (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_RATE)->min)
-#define params_period_size(p) \
- (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min)
-#define params_periods(p) \
- (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_PERIODS)->min)
-#define params_buffer_size(p) \
- (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min)
-#define params_buffer_bytes(p) \
- (hw_param_interval_c((p), SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min)
+/**
+ * params_channels - Get the number of channels from the hw params
+ * @p: hw params
+ */
+static inline unsigned int params_channels(const struct snd_pcm_hw_params *p)
+{
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_CHANNELS)->min;
+}
+
+/**
+ * params_channels - Get the sample rate from the hw params
+ * @p: hw params
+ */
+static inline unsigned int params_rate(const struct snd_pcm_hw_params *p)
+{
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_RATE)->min;
+}
+
+/**
+ * params_channels - Get the period size (in frames) from the hw params
+ * @p: hw params
+ */
+static inline unsigned int params_period_size(const struct snd_pcm_hw_params *p)
+{
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIOD_SIZE)->min;
+}
+
+/**
+ * params_channels - Get the number of periods from the hw params
+ * @p: hw params
+ */
+static inline unsigned int params_periods(const struct snd_pcm_hw_params *p)
+{
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_PERIODS)->min;
+}
+
+/**
+ * params_channels - Get the buffer size (in frames) from the hw params
+ * @p: hw params
+ */
+static inline unsigned int params_buffer_size(const struct snd_pcm_hw_params *p)
+{
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_BUFFER_SIZE)->min;
+}
+
+/**
+ * params_channels - Get the buffer size (in bytes) from the hw params
+ * @p: hw params
+ */
+static inline unsigned int params_buffer_bytes(const struct snd_pcm_hw_params *p)
+{
+ return hw_param_interval_c(p, SNDRV_PCM_HW_PARAM_BUFFER_BYTES)->min;
+}
int snd_interval_refine(struct snd_interval *i, const struct snd_interval *v);
void snd_interval_mul(const struct snd_interval *a, const struct snd_interval *b, struct snd_interval *c);
@@ -883,6 +1021,14 @@ unsigned int snd_pcm_rate_bit_to_rate(unsigned int rate_bit);
unsigned int snd_pcm_rate_mask_intersect(unsigned int rates_a,
unsigned int rates_b);
+/**
+ * snd_pcm_set_runtime_buffer - Set the PCM runtime buffer
+ * @substream: PCM substream to set
+ * @bufp: the buffer information, NULL to clear
+ *
+ * Copy the buffer information to runtime->dma_buffer when @bufp is non-NULL.
+ * Otherwise it clears the current buffer information.
+ */
static inline void snd_pcm_set_runtime_buffer(struct snd_pcm_substream *substream,
struct snd_dma_buffer *bufp)
{
@@ -908,6 +1054,11 @@ void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream);
void snd_pcm_timer_init(struct snd_pcm_substream *substream);
void snd_pcm_timer_done(struct snd_pcm_substream *substream);
+/**
+ * snd_pcm_gettime - Fill the timespec depending on the timestamp mode
+ * @runtime: PCM runtime instance
+ * @tv: timespec to fill
+ */
static inline void snd_pcm_gettime(struct snd_pcm_runtime *runtime,
struct timespec *tv)
{
@@ -944,7 +1095,6 @@ int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream);
struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
unsigned long offset);
-#if 0 /* for kernel-doc */
/**
* snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer
* @substream: the substream to allocate the buffer to
@@ -957,8 +1107,13 @@ struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
* Return: 1 if the buffer was changed, 0 if not changed, or a negative error
* code.
*/
-static int snd_pcm_lib_alloc_vmalloc_buffer
- (struct snd_pcm_substream *substream, size_t size);
+static inline int snd_pcm_lib_alloc_vmalloc_buffer
+ (struct snd_pcm_substream *substream, size_t size)
+{
+ return _snd_pcm_lib_alloc_vmalloc_buffer(substream, size,
+ GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
+}
+
/**
* snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer
* @substream: the substream to allocate the buffer to
@@ -970,15 +1125,12 @@ static int snd_pcm_lib_alloc_vmalloc_buffer
* Return: 1 if the buffer was changed, 0 if not changed, or a negative error
* code.
*/
-static int snd_pcm_lib_alloc_vmalloc_32_buffer
- (struct snd_pcm_substream *substream, size_t size);
-#endif
-#define snd_pcm_lib_alloc_vmalloc_buffer(subs, size) \
- _snd_pcm_lib_alloc_vmalloc_buffer \
- (subs, size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO)
-#define snd_pcm_lib_alloc_vmalloc_32_buffer(subs, size) \
- _snd_pcm_lib_alloc_vmalloc_buffer \
- (subs, size, GFP_KERNEL | GFP_DMA32 | __GFP_ZERO)
+static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
+ (struct snd_pcm_substream *substream, size_t size)
+{
+ return _snd_pcm_lib_alloc_vmalloc_buffer(substream, size,
+ GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
+}
#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
@@ -998,18 +1150,35 @@ struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
#define snd_pcm_sgbuf_ops_page NULL
#endif /* SND_DMA_SGBUF */
+/**
+ * snd_pcm_sgbuf_get_addr - Get the DMA address at the corresponding offset
+ * @substream: PCM substream
+ * @ofs: byte offset
+ */
static inline dma_addr_t
snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
{
return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs);
}
+/**
+ * snd_pcm_sgbuf_get_ptr - Get the virtual address at the corresponding offset
+ * @substream: PCM substream
+ * @ofs: byte offset
+ */
static inline void *
snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
{
return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);
}
+/**
+ * snd_pcm_sgbuf_chunk_size - Compute the max size that fits within the contig.
+ * page from the given size
+ * @substream: PCM substream
+ * @ofs: byte offset
+ * @size: byte size to examine
+ */
static inline unsigned int
snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
unsigned int ofs, unsigned int size)
@@ -1017,13 +1186,24 @@ snd_pcm_sgbuf_get_chunk_size(struct snd_pcm_substream *substream,
return snd_sgbuf_get_chunk_size(snd_pcm_get_dma_buf(substream), ofs, size);
}
-/* handle mmap counter - PCM mmap callback should handle this counter properly */
+/**
+ * snd_pcm_mmap_data_open - increase the mmap counter
+ * @area: VMA
+ *
+ * PCM mmap callback should handle this counter properly
+ */
static inline void snd_pcm_mmap_data_open(struct vm_area_struct *area)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
atomic_inc(&substream->mmap_count);
}
+/**
+ * snd_pcm_mmap_data_close - decrease the mmap counter
+ * @area: VMA
+ *
+ * PCM mmap callback should handle this counter properly
+ */
static inline void snd_pcm_mmap_data_close(struct vm_area_struct *area)
{
struct snd_pcm_substream *substream = (struct snd_pcm_substream *)area->vm_private_data;
@@ -1043,6 +1223,11 @@ int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream, struct vm_area_s
#define snd_pcm_lib_mmap_vmalloc NULL
+/**
+ * snd_pcm_limit_isa_dma_size - Get the max size fitting with ISA DMA transfer
+ * @dma: DMA number
+ * @max: pointer to store the max size
+ */
static inline void snd_pcm_limit_isa_dma_size(int dma, size_t *max)
{
*max = dma < 4 ? 64 * 1024 : 128 * 1024;
@@ -1095,7 +1280,11 @@ struct snd_pcm_chmap {
void *private_data; /* optional: private data pointer */
};
-/* get the PCM substream assigned to the given chmap info */
+/**
+ * snd_pcm_chmap_substream - get the PCM substream assigned to the given chmap info
+ * @info: chmap information
+ * @idx: the substream number index
+ */
static inline struct snd_pcm_substream *
snd_pcm_chmap_substream(struct snd_pcm_chmap *info, unsigned int idx)
{
@@ -1122,7 +1311,10 @@ int snd_pcm_add_chmap_ctls(struct snd_pcm *pcm, int stream,
unsigned long private_value,
struct snd_pcm_chmap **info_ret);
-/* Strong-typed conversion of pcm_format to bitwise */
+/**
+ * pcm_format_to_bits - Strong-typed conversion of pcm_format to bitwise
+ * @pcm_format: PCM format
+ */
static inline u64 pcm_format_to_bits(snd_pcm_format_t pcm_format)
{
return 1ULL << (__force int) pcm_format;
diff --git a/include/sound/rcar_snd.h b/include/sound/rcar_snd.h
index d76412b..83284ca 100644
--- a/include/sound/rcar_snd.h
+++ b/include/sound/rcar_snd.h
@@ -36,14 +36,14 @@
#define RSND_SSI_CLK_PIN_SHARE (1 << 31)
#define RSND_SSI_NO_BUSIF (1 << 30) /* SSI+DMA without BUSIF */
-#define RSND_SSI(_dma_id, _pio_irq, _flags) \
-{ .dma_id = _dma_id, .pio_irq = _pio_irq, .flags = _flags }
+#define RSND_SSI(_dma_id, _irq, _flags) \
+{ .dma_id = _dma_id, .irq = _irq, .flags = _flags }
#define RSND_SSI_UNUSED \
-{ .dma_id = -1, .pio_irq = -1, .flags = 0 }
+{ .dma_id = -1, .irq = -1, .flags = 0 }
struct rsnd_ssi_platform_info {
int dma_id;
- int pio_irq;
+ int irq;
u32 flags;
};
diff --git a/include/sound/rt5645.h b/include/sound/rt5645.h
index a535271..120d961 100644
--- a/include/sound/rt5645.h
+++ b/include/sound/rt5645.h
@@ -23,6 +23,10 @@ struct rt5645_platform_data {
unsigned int hp_det_gpio;
bool gpio_hp_det_active_high;
+
+ /* true if codec's jd function is used */
+ bool en_jd_func;
+ unsigned int jd_mode;
};
#endif
diff --git a/include/sound/rt5677.h b/include/sound/rt5677.h
index 082670e..d9eb7d8 100644
--- a/include/sound/rt5677.h
+++ b/include/sound/rt5677.h
@@ -27,6 +27,16 @@ struct rt5677_platform_data {
bool lout3_diff;
/* DMIC2 clock source selection */
enum rt5677_dmic2_clk dmic2_clk_pin;
+
+ /* configures GPIO, 0 - floating, 1 - pulldown, 2 - pullup */
+ u8 gpio_config[6];
+
+ /* jd1 can select 0 ~ 3 as OFF, GPIO1, GPIO2 and GPIO3 respectively */
+ unsigned int jd1_gpio;
+ /* jd2 and jd3 can select 0 ~ 3 as
+ OFF, GPIO4, GPIO5 and GPIO6 respectively */
+ unsigned int jd2_gpio;
+ unsigned int jd3_gpio;
};
#endif
diff --git a/include/sound/seq_kernel.h b/include/sound/seq_kernel.h
index 2398521..eea5400 100644
--- a/include/sound/seq_kernel.h
+++ b/include/sound/seq_kernel.h
@@ -108,9 +108,13 @@ int snd_seq_event_port_detach(int client, int port);
#ifdef CONFIG_MODULES
void snd_seq_autoload_lock(void);
void snd_seq_autoload_unlock(void);
+void snd_seq_autoload_init(void);
+#define snd_seq_autoload_exit() snd_seq_autoload_lock()
#else
#define snd_seq_autoload_lock()
#define snd_seq_autoload_unlock()
+#define snd_seq_autoload_init()
+#define snd_seq_autoload_exit()
#endif
#endif /* __SOUND_SEQ_KERNEL_H */
diff --git a/include/sound/soc-dai.h b/include/sound/soc-dai.h
index e8b3080..2df96b1 100644
--- a/include/sound/soc-dai.h
+++ b/include/sound/soc-dai.h
@@ -206,7 +206,6 @@ struct snd_soc_dai_driver {
/* DAI description */
const char *name;
unsigned int id;
- int ac97_control;
unsigned int base;
/* DAI driver callbacks */
@@ -216,6 +215,8 @@ struct snd_soc_dai_driver {
int (*resume)(struct snd_soc_dai *dai);
/* compress dai */
bool compress_dai;
+ /* DAI is also used for the control bus */
+ bool bus_control;
/* ops */
const struct snd_soc_dai_ops *ops;
@@ -241,7 +242,6 @@ struct snd_soc_dai {
const char *name;
int id;
struct device *dev;
- void *ac97_pdata; /* platform_data for the ac97 codec */
/* driver ops */
struct snd_soc_dai_driver *driver;
@@ -268,7 +268,6 @@ struct snd_soc_dai {
unsigned int sample_bits;
/* parent platform/codec */
- struct snd_soc_platform *platform;
struct snd_soc_codec *codec;
struct snd_soc_component *component;
@@ -276,8 +275,6 @@ struct snd_soc_dai {
unsigned int tx_mask;
unsigned int rx_mask;
- struct snd_soc_card *card;
-
struct list_head list;
};
diff --git a/include/sound/soc-dapm.h b/include/sound/soc-dapm.h
index 3a4d7da..89823cf 100644
--- a/include/sound/soc-dapm.h
+++ b/include/sound/soc-dapm.h
@@ -435,7 +435,7 @@ void snd_soc_dapm_auto_nc_pins(struct snd_soc_card *card);
unsigned int dapm_kcontrol_get_value(const struct snd_kcontrol *kcontrol);
/* Mostly internal - should not normally be used */
-void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm);
+void dapm_mark_endpoints_dirty(struct snd_soc_card *card);
/* dapm path query */
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
@@ -508,9 +508,9 @@ struct snd_soc_dapm_path {
/* status */
u32 connect:1; /* source and sink widgets are connected */
- u32 walked:1; /* path has been walked */
u32 walking:1; /* path is in the process of being walked */
u32 weak:1; /* path ignored for power management */
+ u32 is_supply:1; /* At least one of the connected widgets is a supply */
int (*connected)(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink);
@@ -544,11 +544,13 @@ struct snd_soc_dapm_widget {
unsigned char active:1; /* active stream on DAC, ADC's */
unsigned char connected:1; /* connected codec pin */
unsigned char new:1; /* cnew complete */
- unsigned char ext:1; /* has external widgets */
unsigned char force:1; /* force state */
unsigned char ignore_suspend:1; /* kept enabled over suspend */
unsigned char new_power:1; /* power from this run */
unsigned char power_checked:1; /* power checked this run */
+ unsigned char is_supply:1; /* Widget is a supply type widget */
+ unsigned char is_sink:1; /* Widget is a sink type widget */
+ unsigned char is_source:1; /* Widget is a source type widget */
int subseq; /* sort within widget type */
int (*power_check)(struct snd_soc_dapm_widget *w);
@@ -567,6 +569,7 @@ struct snd_soc_dapm_widget {
struct list_head sinks;
/* used during DAPM updates */
+ struct list_head work_list;
struct list_head power_list;
struct list_head dirty;
int inputs;
diff --git a/include/sound/soc.h b/include/sound/soc.h
index 7ba7130..b4fca9a 100644
--- a/include/sound/soc.h
+++ b/include/sound/soc.h
@@ -36,6 +36,11 @@
{.reg = xreg, .rreg = xreg, .shift = shift_left, \
.rshift = shift_right, .max = xmax, .platform_max = xmax, \
.invert = xinvert, .autodisable = xautodisable})
+#define SOC_DOUBLE_S_VALUE(xreg, shift_left, shift_right, xmin, xmax, xsign_bit, xinvert, xautodisable) \
+ ((unsigned long)&(struct soc_mixer_control) \
+ {.reg = xreg, .rreg = xreg, .shift = shift_left, \
+ .rshift = shift_right, .min = xmin, .max = xmax, .platform_max = xmax, \
+ .sign_bit = xsign_bit, .invert = xinvert, .autodisable = xautodisable})
#define SOC_SINGLE_VALUE(xreg, xshift, xmax, xinvert, xautodisable) \
SOC_DOUBLE_VALUE(xreg, xshift, xshift, xmax, xinvert, xautodisable)
#define SOC_SINGLE_VALUE_EXT(xreg, xmax, xinvert) \
@@ -171,11 +176,9 @@
.access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
SNDRV_CTL_ELEM_ACCESS_READWRITE, \
.tlv.p = (tlv_array), \
- .info = snd_soc_info_volsw_s8, .get = snd_soc_get_volsw_s8, \
- .put = snd_soc_put_volsw_s8, \
- .private_value = (unsigned long)&(struct soc_mixer_control) \
- {.reg = xreg, .min = xmin, .max = xmax, \
- .platform_max = xmax} }
+ .info = snd_soc_info_volsw, .get = snd_soc_get_volsw,\
+ .put = snd_soc_put_volsw, \
+ .private_value = SOC_DOUBLE_S_VALUE(xreg, 0, 8, xmin, xmax, 7, 0, 0) }
#define SOC_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xitems, xtexts) \
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
.items = xitems, .texts = xtexts, \
@@ -366,8 +369,6 @@ struct snd_soc_jack_gpio;
typedef int (*hw_write_t)(void *,const char* ,int);
-extern struct snd_ac97_bus_ops *soc_ac97_ops;
-
enum snd_soc_pcm_subclass {
SND_SOC_PCM_CLASS_PCM = 0,
SND_SOC_PCM_CLASS_BE = 1,
@@ -409,13 +410,9 @@ int devm_snd_soc_register_component(struct device *dev,
const struct snd_soc_component_driver *cmpnt_drv,
struct snd_soc_dai_driver *dai_drv, int num_dai);
void snd_soc_unregister_component(struct device *dev);
-int snd_soc_cache_sync(struct snd_soc_codec *codec);
int snd_soc_cache_init(struct snd_soc_codec *codec);
int snd_soc_cache_exit(struct snd_soc_codec *codec);
-int snd_soc_cache_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value);
-int snd_soc_cache_read(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int *value);
+
int snd_soc_platform_read(struct snd_soc_platform *platform,
unsigned int reg);
int snd_soc_platform_write(struct snd_soc_platform *platform,
@@ -500,14 +497,28 @@ int snd_soc_update_bits_locked(struct snd_soc_codec *codec,
int snd_soc_test_bits(struct snd_soc_codec *codec, unsigned int reg,
unsigned int mask, unsigned int value);
-int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
- struct snd_ac97_bus_ops *ops, int num);
-void snd_soc_free_ac97_codec(struct snd_soc_codec *codec);
+#ifdef CONFIG_SND_SOC_AC97_BUS
+struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec);
+void snd_soc_free_ac97_codec(struct snd_ac97 *ac97);
int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops);
int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
struct platform_device *pdev);
+extern struct snd_ac97_bus_ops *soc_ac97_ops;
+#else
+static inline int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+ struct platform_device *pdev)
+{
+ return 0;
+}
+
+static inline int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
+{
+ return 0;
+}
+#endif
+
/*
*Controls
*/
@@ -545,12 +556,6 @@ int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol);
-int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo);
-int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
-int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol);
int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo);
int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
@@ -780,24 +785,18 @@ struct snd_soc_codec {
struct device *dev;
const struct snd_soc_codec_driver *driver;
- struct mutex mutex;
struct list_head list;
struct list_head card_list;
/* runtime */
- struct snd_ac97 *ac97; /* for ad-hoc ac97 devices */
unsigned int cache_bypass:1; /* Suppress access to the cache */
unsigned int suspended:1; /* Codec is in suspend PM state */
- unsigned int ac97_registered:1; /* Codec has been AC97 registered */
- unsigned int ac97_created:1; /* Codec has been created by SoC */
unsigned int cache_init:1; /* codec cache has been initialized */
- u32 cache_sync; /* Cache needs to be synced to hardware */
/* codec IO */
void *control_data; /* codec control (i2c/3wire) data */
hw_write_t hw_write;
void *reg_cache;
- struct mutex cache_rw_mutex;
/* component */
struct snd_soc_component component;
@@ -860,8 +859,6 @@ struct snd_soc_platform_driver {
int (*probe)(struct snd_soc_platform *);
int (*remove)(struct snd_soc_platform *);
- int (*suspend)(struct snd_soc_dai *dai);
- int (*resume)(struct snd_soc_dai *dai);
struct snd_soc_component_driver component_driver;
/* pcm creation and destruction */
@@ -886,7 +883,7 @@ struct snd_soc_platform_driver {
struct snd_soc_dai_link_component {
const char *name;
- const struct device_node *of_node;
+ struct device_node *of_node;
const char *dai_name;
};
@@ -894,8 +891,6 @@ struct snd_soc_platform {
struct device *dev;
const struct snd_soc_platform_driver *driver;
- unsigned int suspended:1; /* platform is suspended */
-
struct list_head list;
struct snd_soc_component component;
@@ -990,7 +985,7 @@ struct snd_soc_codec_conf {
* DT/OF node, but not both.
*/
const char *dev_name;
- const struct device_node *of_node;
+ struct device_node *of_node;
/*
* optional map of kcontrol, widget and path name prefixes that are
@@ -1007,7 +1002,7 @@ struct snd_soc_aux_dev {
* DT/OF node, but not both.
*/
const char *codec_name;
- const struct device_node *codec_of_node;
+ struct device_node *codec_of_node;
/* codec/machine specific init - e.g. add machine controls */
int (*init)(struct snd_soc_component *component);
@@ -1264,6 +1259,17 @@ unsigned int snd_soc_read(struct snd_soc_codec *codec, unsigned int reg);
int snd_soc_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val);
+/**
+ * snd_soc_cache_sync() - Sync the register cache with the hardware
+ * @codec: CODEC to sync
+ *
+ * Note: This function will call regcache_sync()
+ */
+static inline int snd_soc_cache_sync(struct snd_soc_codec *codec)
+{
+ return regcache_sync(codec->component.regmap);
+}
+
/* component IO */
int snd_soc_component_read(struct snd_soc_component *component,
unsigned int reg, unsigned int *val);
@@ -1277,6 +1283,45 @@ void snd_soc_component_async_complete(struct snd_soc_component *component);
int snd_soc_component_test_bits(struct snd_soc_component *component,
unsigned int reg, unsigned int mask, unsigned int value);
+#ifdef CONFIG_REGMAP
+
+void snd_soc_component_init_regmap(struct snd_soc_component *component,
+ struct regmap *regmap);
+void snd_soc_component_exit_regmap(struct snd_soc_component *component);
+
+/**
+ * snd_soc_codec_init_regmap() - Initialize regmap instance for the CODEC
+ * @codec: The CODEC for which to initialize the regmap instance
+ * @regmap: The regmap instance that should be used by the CODEC
+ *
+ * This function allows deferred assignment of the regmap instance that is
+ * associated with the CODEC. Only use this if the regmap instance is not yet
+ * ready when the CODEC is registered. The function must also be called before
+ * the first IO attempt of the CODEC.
+ */
+static inline void snd_soc_codec_init_regmap(struct snd_soc_codec *codec,
+ struct regmap *regmap)
+{
+ snd_soc_component_init_regmap(&codec->component, regmap);
+}
+
+/**
+ * snd_soc_codec_exit_regmap() - De-initialize regmap instance for the CODEC
+ * @codec: The CODEC for which to de-initialize the regmap instance
+ *
+ * Calls regmap_exit() on the regmap instance associated to the CODEC and
+ * removes the regmap instance from the CODEC.
+ *
+ * This function should only be used if snd_soc_codec_init_regmap() was used to
+ * initialize the regmap instance.
+ */
+static inline void snd_soc_codec_exit_regmap(struct snd_soc_codec *codec)
+{
+ snd_soc_component_exit_regmap(&codec->component);
+}
+
+#endif
+
/* device driver data */
static inline void snd_soc_card_set_drvdata(struct snd_soc_card *card,
@@ -1451,6 +1496,9 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
struct device_node **framemaster);
int snd_soc_of_get_dai_name(struct device_node *of_node,
const char **dai_name);
+int snd_soc_of_get_dai_link_codecs(struct device *dev,
+ struct device_node *of_node,
+ struct snd_soc_dai_link *dai_link);
#include <sound/soc-dai.h>
diff --git a/include/sound/uda134x.h b/include/sound/uda134x.h
index e475659b..509efb0 100644
--- a/include/sound/uda134x.h
+++ b/include/sound/uda134x.h
@@ -18,18 +18,6 @@ struct uda134x_platform_data {
struct l3_pins l3;
void (*power) (int);
int model;
- /*
- ALSA SOC usually puts the device in standby mode when it's not used
- for sometime. If you unset is_powered_on_standby the driver will
- turn off the ADC/DAC when this callback is invoked and turn it back
- on when needed. Unfortunately this will result in a very light bump
- (it can be audible only with good earphones). If this bothers you
- set is_powered_on_standby, you will have slightly higher power
- consumption. Please note that sending the L3 command for ADC is
- enough to make the bump, so it doesn't make difference if you
- completely take off power from the codec.
- */
- int is_powered_on_standby;
#define UDA134X_UDA1340 1
#define UDA134X_UDA1341 2
#define UDA134X_UDA1344 3
diff --git a/include/trace/events/asoc.h b/include/trace/events/asoc.h
index b04ee7e..88cf39d 100644
--- a/include/trace/events/asoc.h
+++ b/include/trace/events/asoc.h
@@ -288,31 +288,6 @@ TRACE_EVENT(snd_soc_jack_notify,
TP_printk("jack=%s %x", __get_str(name), (int)__entry->val)
);
-TRACE_EVENT(snd_soc_cache_sync,
-
- TP_PROTO(struct snd_soc_codec *codec, const char *type,
- const char *status),
-
- TP_ARGS(codec, type, status),
-
- TP_STRUCT__entry(
- __string( name, codec->component.name)
- __string( status, status )
- __string( type, type )
- __field( int, id )
- ),
-
- TP_fast_assign(
- __assign_str(name, codec->component.name);
- __assign_str(status, status);
- __assign_str(type, type);
- __entry->id = codec->component.id;
- ),
-
- TP_printk("codec=%s.%d type=%s status=%s", __get_str(name),
- (int)__entry->id, __get_str(type), __get_str(status))
-);
-
#endif /* _TRACE_ASOC_H */
/* This part must be outside protection */
diff --git a/include/trace/events/rcu.h b/include/trace/events/rcu.h
index e335e7d..c78e88c 100644
--- a/include/trace/events/rcu.h
+++ b/include/trace/events/rcu.h
@@ -36,7 +36,7 @@ TRACE_EVENT(rcu_utilization,
#ifdef CONFIG_RCU_TRACE
-#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU)
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU)
/*
* Tracepoint for grace-period events. Takes a string identifying the
@@ -345,7 +345,7 @@ TRACE_EVENT(rcu_fqs,
__entry->cpu, __entry->qsevent)
);
-#endif /* #if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) */
+#endif /* #if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) */
/*
* Tracepoint for dyntick-idle entry/exit events. These take a string
diff --git a/include/trace/events/sched.h b/include/trace/events/sched.h
index 0a68d5a..30fedaf 100644
--- a/include/trace/events/sched.h
+++ b/include/trace/events/sched.h
@@ -97,16 +97,19 @@ static inline long __trace_sched_switch_state(struct task_struct *p)
long state = p->state;
#ifdef CONFIG_PREEMPT
+#ifdef CONFIG_SCHED_DEBUG
+ BUG_ON(p != current);
+#endif /* CONFIG_SCHED_DEBUG */
/*
* For all intents and purposes a preempted task is a running task.
*/
- if (task_preempt_count(p) & PREEMPT_ACTIVE)
+ if (preempt_count() & PREEMPT_ACTIVE)
state = TASK_RUNNING | TASK_STATE_MAX;
-#endif
+#endif /* CONFIG_PREEMPT */
return state;
}
-#endif
+#endif /* CREATE_TRACE_POINTS */
/*
* Tracepoint for task switches, performed by the scheduler:
diff --git a/include/trace/events/scsi.h b/include/trace/events/scsi.h
index db6c935..079bd10 100644
--- a/include/trace/events/scsi.h
+++ b/include/trace/events/scsi.h
@@ -94,7 +94,7 @@
scsi_opcode_name(WRITE_16), \
scsi_opcode_name(VERIFY_16), \
scsi_opcode_name(WRITE_SAME_16), \
- scsi_opcode_name(SERVICE_ACTION_IN), \
+ scsi_opcode_name(SERVICE_ACTION_IN_16), \
scsi_opcode_name(SAI_READ_CAPACITY_16), \
scsi_opcode_name(SAI_GET_LBA_STATUS), \
scsi_opcode_name(MI_REPORT_TARGET_PGS), \
diff --git a/include/trace/events/sunrpc.h b/include/trace/events/sunrpc.h
index 1fef3e6..171ca4f 100644
--- a/include/trace/events/sunrpc.h
+++ b/include/trace/events/sunrpc.h
@@ -6,6 +6,8 @@
#include <linux/sunrpc/sched.h>
#include <linux/sunrpc/clnt.h>
+#include <linux/sunrpc/svc.h>
+#include <linux/sunrpc/xprtsock.h>
#include <net/tcp_states.h>
#include <linux/net.h>
#include <linux/tracepoint.h>
@@ -306,6 +308,164 @@ DEFINE_RPC_SOCKET_EVENT_DONE(rpc_socket_reset_connection);
DEFINE_RPC_SOCKET_EVENT(rpc_socket_close);
DEFINE_RPC_SOCKET_EVENT(rpc_socket_shutdown);
+DECLARE_EVENT_CLASS(rpc_xprt_event,
+ TP_PROTO(struct rpc_xprt *xprt, __be32 xid, int status),
+
+ TP_ARGS(xprt, xid, status),
+
+ TP_STRUCT__entry(
+ __field(__be32, xid)
+ __field(int, status)
+ __string(addr, xprt->address_strings[RPC_DISPLAY_ADDR])
+ __string(port, xprt->address_strings[RPC_DISPLAY_PORT])
+ ),
+
+ TP_fast_assign(
+ __entry->xid = xid;
+ __entry->status = status;
+ __assign_str(addr, xprt->address_strings[RPC_DISPLAY_ADDR]);
+ __assign_str(port, xprt->address_strings[RPC_DISPLAY_PORT]);
+ ),
+
+ TP_printk("peer=[%s]:%s xid=0x%x status=%d", __get_str(addr),
+ __get_str(port), be32_to_cpu(__entry->xid),
+ __entry->status)
+);
+
+DEFINE_EVENT(rpc_xprt_event, xprt_lookup_rqst,
+ TP_PROTO(struct rpc_xprt *xprt, __be32 xid, int status),
+ TP_ARGS(xprt, xid, status));
+
+DEFINE_EVENT(rpc_xprt_event, xprt_transmit,
+ TP_PROTO(struct rpc_xprt *xprt, __be32 xid, int status),
+ TP_ARGS(xprt, xid, status));
+
+DEFINE_EVENT(rpc_xprt_event, xprt_complete_rqst,
+ TP_PROTO(struct rpc_xprt *xprt, __be32 xid, int status),
+ TP_ARGS(xprt, xid, status));
+
+TRACE_EVENT(xs_tcp_data_ready,
+ TP_PROTO(struct rpc_xprt *xprt, int err, unsigned int total),
+
+ TP_ARGS(xprt, err, total),
+
+ TP_STRUCT__entry(
+ __field(int, err)
+ __field(unsigned int, total)
+ __string(addr, xprt ? xprt->address_strings[RPC_DISPLAY_ADDR] :
+ "(null)")
+ __string(port, xprt ? xprt->address_strings[RPC_DISPLAY_PORT] :
+ "(null)")
+ ),
+
+ TP_fast_assign(
+ __entry->err = err;
+ __entry->total = total;
+ __assign_str(addr, xprt ?
+ xprt->address_strings[RPC_DISPLAY_ADDR] : "(null)");
+ __assign_str(port, xprt ?
+ xprt->address_strings[RPC_DISPLAY_PORT] : "(null)");
+ ),
+
+ TP_printk("peer=[%s]:%s err=%d total=%u", __get_str(addr),
+ __get_str(port), __entry->err, __entry->total)
+);
+
+#define rpc_show_sock_xprt_flags(flags) \
+ __print_flags(flags, "|", \
+ { TCP_RCV_LAST_FRAG, "TCP_RCV_LAST_FRAG" }, \
+ { TCP_RCV_COPY_FRAGHDR, "TCP_RCV_COPY_FRAGHDR" }, \
+ { TCP_RCV_COPY_XID, "TCP_RCV_COPY_XID" }, \
+ { TCP_RCV_COPY_DATA, "TCP_RCV_COPY_DATA" }, \
+ { TCP_RCV_READ_CALLDIR, "TCP_RCV_READ_CALLDIR" }, \
+ { TCP_RCV_COPY_CALLDIR, "TCP_RCV_COPY_CALLDIR" }, \
+ { TCP_RPC_REPLY, "TCP_RPC_REPLY" })
+
+TRACE_EVENT(xs_tcp_data_recv,
+ TP_PROTO(struct sock_xprt *xs),
+
+ TP_ARGS(xs),
+
+ TP_STRUCT__entry(
+ __string(addr, xs->xprt.address_strings[RPC_DISPLAY_ADDR])
+ __string(port, xs->xprt.address_strings[RPC_DISPLAY_PORT])
+ __field(__be32, xid)
+ __field(unsigned long, flags)
+ __field(unsigned long, copied)
+ __field(unsigned int, reclen)
+ __field(unsigned long, offset)
+ ),
+
+ TP_fast_assign(
+ __assign_str(addr, xs->xprt.address_strings[RPC_DISPLAY_ADDR]);
+ __assign_str(port, xs->xprt.address_strings[RPC_DISPLAY_PORT]);
+ __entry->xid = xs->tcp_xid;
+ __entry->flags = xs->tcp_flags;
+ __entry->copied = xs->tcp_copied;
+ __entry->reclen = xs->tcp_reclen;
+ __entry->offset = xs->tcp_offset;
+ ),
+
+ TP_printk("peer=[%s]:%s xid=0x%x flags=%s copied=%lu reclen=%u offset=%lu",
+ __get_str(addr), __get_str(port), be32_to_cpu(__entry->xid),
+ rpc_show_sock_xprt_flags(__entry->flags),
+ __entry->copied, __entry->reclen, __entry->offset)
+);
+
+TRACE_EVENT(svc_recv,
+ TP_PROTO(struct svc_rqst *rqst, int status),
+
+ TP_ARGS(rqst, status),
+
+ TP_STRUCT__entry(
+ __field(struct sockaddr *, addr)
+ __field(__be32, xid)
+ __field(int, status)
+ ),
+
+ TP_fast_assign(
+ __entry->addr = (struct sockaddr *)&rqst->rq_addr;
+ __entry->xid = status > 0 ? rqst->rq_xid : 0;
+ __entry->status = status;
+ ),
+
+ TP_printk("addr=%pIScp xid=0x%x status=%d", __entry->addr,
+ be32_to_cpu(__entry->xid), __entry->status)
+);
+
+DECLARE_EVENT_CLASS(svc_rqst_status,
+
+ TP_PROTO(struct svc_rqst *rqst, int status),
+
+ TP_ARGS(rqst, status),
+
+ TP_STRUCT__entry(
+ __field(struct sockaddr *, addr)
+ __field(__be32, xid)
+ __field(int, dropme)
+ __field(int, status)
+ ),
+
+ TP_fast_assign(
+ __entry->addr = (struct sockaddr *)&rqst->rq_addr;
+ __entry->xid = rqst->rq_xid;
+ __entry->dropme = (int)rqst->rq_dropme;
+ __entry->status = status;
+ ),
+
+ TP_printk("addr=%pIScp rq_xid=0x%x dropme=%d status=%d",
+ __entry->addr, be32_to_cpu(__entry->xid), __entry->dropme,
+ __entry->status)
+);
+
+DEFINE_EVENT(svc_rqst_status, svc_process,
+ TP_PROTO(struct svc_rqst *rqst, int status),
+ TP_ARGS(rqst, status));
+
+DEFINE_EVENT(svc_rqst_status, svc_send,
+ TP_PROTO(struct svc_rqst *rqst, int status),
+ TP_ARGS(rqst, status));
+
#endif /* _TRACE_SUNRPC_H */
#include <trace/define_trace.h>
diff --git a/include/trace/events/target.h b/include/trace/events/target.h
index da9cc0f..4540344 100644
--- a/include/trace/events/target.h
+++ b/include/trace/events/target.h
@@ -96,7 +96,7 @@
scsi_opcode_name(WRITE_16), \
scsi_opcode_name(VERIFY_16), \
scsi_opcode_name(WRITE_SAME_16), \
- scsi_opcode_name(SERVICE_ACTION_IN), \
+ scsi_opcode_name(SERVICE_ACTION_IN_16), \
scsi_opcode_name(SAI_READ_CAPACITY_16), \
scsi_opcode_name(SAI_GET_LBA_STATUS), \
scsi_opcode_name(MI_REPORT_TARGET_PGS), \
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 26b4f2e..139b506 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -277,14 +277,12 @@ ftrace_raw_output_##call(struct trace_iterator *iter, int flags, \
field = (typeof(field))iter->ent; \
\
ret = ftrace_raw_output_prep(iter, trace_event); \
- if (ret) \
+ if (ret != TRACE_TYPE_HANDLED) \
return ret; \
\
- ret = trace_seq_printf(s, print); \
- if (!ret) \
- return TRACE_TYPE_PARTIAL_LINE; \
+ trace_seq_printf(s, print); \
\
- return TRACE_TYPE_HANDLED; \
+ return trace_handle_return(s); \
} \
static struct trace_event_functions ftrace_event_type_funcs_##call = { \
.trace = ftrace_raw_output_##call, \
diff --git a/include/uapi/asm-generic/siginfo.h b/include/uapi/asm-generic/siginfo.h
index ba5be7f..1e35520 100644
--- a/include/uapi/asm-generic/siginfo.h
+++ b/include/uapi/asm-generic/siginfo.h
@@ -91,6 +91,10 @@ typedef struct siginfo {
int _trapno; /* TRAP # which caused the signal */
#endif
short _addr_lsb; /* LSB of the reported address */
+ struct {
+ void __user *_lower;
+ void __user *_upper;
+ } _addr_bnd;
} _sigfault;
/* SIGPOLL */
@@ -131,6 +135,8 @@ typedef struct siginfo {
#define si_trapno _sifields._sigfault._trapno
#endif
#define si_addr_lsb _sifields._sigfault._addr_lsb
+#define si_lower _sifields._sigfault._addr_bnd._lower
+#define si_upper _sifields._sigfault._addr_bnd._upper
#define si_band _sifields._sigpoll._band
#define si_fd _sifields._sigpoll._fd
#ifdef __ARCH_SIGSYS
@@ -199,7 +205,8 @@ typedef struct siginfo {
*/
#define SEGV_MAPERR (__SI_FAULT|1) /* address not mapped to object */
#define SEGV_ACCERR (__SI_FAULT|2) /* invalid permissions for mapped object */
-#define NSIGSEGV 2
+#define SEGV_BNDERR (__SI_FAULT|3) /* failed address bound checks */
+#define NSIGSEGV 3
/*
* SIGBUS si_codes
diff --git a/include/uapi/linux/Kbuild b/include/uapi/linux/Kbuild
index 5b6a36c..d8e1716 100644
--- a/include/uapi/linux/Kbuild
+++ b/include/uapi/linux/Kbuild
@@ -244,6 +244,7 @@ header-y += map_to_7segment.h
header-y += matroxfb.h
header-y += mdio.h
header-y += media.h
+header-y += media-bus-format.h
header-y += mei.h
header-y += memfd.h
header-y += mempolicy.h
@@ -429,6 +430,8 @@ header-y += virtio_net.h
header-y += virtio_pci.h
header-y += virtio_ring.h
header-y += virtio_rng.h
+header-y += virtio_scsi.h
+header-y += virtio_types.h
header-y += vm_sockets.h
header-y += vt.h
header-y += wait.h
diff --git a/include/uapi/linux/dlmconstants.h b/include/uapi/linux/dlmconstants.h
index 47bf08d..2857bdc 100644
--- a/include/uapi/linux/dlmconstants.h
+++ b/include/uapi/linux/dlmconstants.h
@@ -114,7 +114,7 @@
*
* DLM_LKF_ORPHAN
*
- * not yet implemented
+ * Acquire an orphan lock.
*
* DLM_LKF_ALTPR
*
diff --git a/include/uapi/linux/dm-ioctl.h b/include/uapi/linux/dm-ioctl.h
index 3315ab2..a570d7b 100644
--- a/include/uapi/linux/dm-ioctl.h
+++ b/include/uapi/linux/dm-ioctl.h
@@ -267,9 +267,9 @@ enum {
#define DM_DEV_SET_GEOMETRY _IOWR(DM_IOCTL, DM_DEV_SET_GEOMETRY_CMD, struct dm_ioctl)
#define DM_VERSION_MAJOR 4
-#define DM_VERSION_MINOR 28
+#define DM_VERSION_MINOR 29
#define DM_VERSION_PATCHLEVEL 0
-#define DM_VERSION_EXTRA "-ioctl (2014-09-17)"
+#define DM_VERSION_EXTRA "-ioctl (2014-10-28)"
/* Status bits */
#define DM_READONLY_FLAG (1 << 0) /* In/Out */
@@ -352,4 +352,9 @@ enum {
*/
#define DM_DEFERRED_REMOVE (1 << 17) /* In/Out */
+/*
+ * If set, the device is suspended internally.
+ */
+#define DM_INTERNAL_SUSPEND_FLAG (1 << 18) /* Out */
+
#endif /* _LINUX_DM_IOCTL_H */
diff --git a/include/uapi/linux/elf-em.h b/include/uapi/linux/elf-em.h
index aa90bc9..ae99f77 100644
--- a/include/uapi/linux/elf-em.h
+++ b/include/uapi/linux/elf-em.h
@@ -34,6 +34,7 @@
#define EM_MN10300 89 /* Panasonic/MEI MN10300, AM33 */
#define EM_OPENRISC 92 /* OpenRISC 32-bit embedded processor */
#define EM_BLACKFIN 106 /* ADI Blackfin Processor */
+#define EM_ALTERA_NIOS2 113 /* Altera Nios II soft-core processor */
#define EM_TI_C6000 140 /* TI C6X DSPs */
#define EM_AARCH64 183 /* ARM 64 bit */
#define EM_FRV 0x5441 /* Fujitsu FR-V */
diff --git a/include/uapi/linux/elf.h b/include/uapi/linux/elf.h
index ea9bf25..71e1d0e 100644
--- a/include/uapi/linux/elf.h
+++ b/include/uapi/linux/elf.h
@@ -397,6 +397,7 @@ typedef struct elf64_shdr {
#define NT_ARM_TLS 0x401 /* ARM TLS register */
#define NT_ARM_HW_BREAK 0x402 /* ARM hardware breakpoint registers */
#define NT_ARM_HW_WATCH 0x403 /* ARM hardware watchpoint registers */
+#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
#define NT_METAG_CBUF 0x500 /* Metag catch buffer registers */
#define NT_METAG_RPIPE 0x501 /* Metag read pipeline state */
#define NT_METAG_TLS 0x502 /* Metag TLS pointer */
diff --git a/include/uapi/linux/if_tun.h b/include/uapi/linux/if_tun.h
index e9502dd..18b2403 100644
--- a/include/uapi/linux/if_tun.h
+++ b/include/uapi/linux/if_tun.h
@@ -22,21 +22,11 @@
/* Read queue size */
#define TUN_READQ_SIZE 500
-
-/* TUN device flags */
-#define TUN_TUN_DEV 0x0001
-#define TUN_TAP_DEV 0x0002
+/* TUN device type flags: deprecated. Use IFF_TUN/IFF_TAP instead. */
+#define TUN_TUN_DEV IFF_TUN
+#define TUN_TAP_DEV IFF_TAP
#define TUN_TYPE_MASK 0x000f
-#define TUN_FASYNC 0x0010
-#define TUN_NOCHECKSUM 0x0020
-#define TUN_NO_PI 0x0040
-/* This flag has no real effect */
-#define TUN_ONE_QUEUE 0x0080
-#define TUN_PERSIST 0x0100
-#define TUN_VNET_HDR 0x0200
-#define TUN_TAP_MQ 0x0400
-
/* Ioctl defines */
#define TUNSETNOCSUM _IOW('T', 200, int)
#define TUNSETDEBUG _IOW('T', 201, int)
@@ -67,6 +57,7 @@
#define IFF_ONE_QUEUE 0x2000
#define IFF_VNET_HDR 0x4000
#define IFF_TUN_EXCL 0x8000
+#define IFF_VNET_LE 0x10000
#define IFF_MULTI_QUEUE 0x0100
#define IFF_ATTACH_QUEUE 0x0200
#define IFF_DETACH_QUEUE 0x0400
diff --git a/include/uapi/linux/media-bus-format.h b/include/uapi/linux/media-bus-format.h
new file mode 100644
index 0000000..23b4090
--- /dev/null
+++ b/include/uapi/linux/media-bus-format.h
@@ -0,0 +1,125 @@
+/*
+ * Media Bus API header
+ *
+ * Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __LINUX_MEDIA_BUS_FORMAT_H
+#define __LINUX_MEDIA_BUS_FORMAT_H
+
+/*
+ * These bus formats uniquely identify data formats on the data bus. Format 0
+ * is reserved, MEDIA_BUS_FMT_FIXED shall be used by host-client pairs, where
+ * the data format is fixed. Additionally, "2X8" means that one pixel is
+ * transferred in two 8-bit samples, "BE" or "LE" specify in which order those
+ * samples are transferred over the bus: "LE" means that the least significant
+ * bits are transferred first, "BE" means that the most significant bits are
+ * transferred first, and "PADHI" and "PADLO" define which bits - low or high,
+ * in the incomplete high byte, are filled with padding bits.
+ *
+ * The bus formats are grouped by type, bus_width, bits per component, samples
+ * per pixel and order of subsamples. Numerical values are sorted using generic
+ * numerical sort order (8 thus comes before 10).
+ *
+ * As their value can't change when a new bus format is inserted in the
+ * enumeration, the bus formats are explicitly given a numerical value. The next
+ * free values for each category are listed below, update them when inserting
+ * new pixel codes.
+ */
+
+#define MEDIA_BUS_FMT_FIXED 0x0001
+
+/* RGB - next is 0x100e */
+#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_BE 0x1001
+#define MEDIA_BUS_FMT_RGB444_2X8_PADHI_LE 0x1002
+#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_BE 0x1003
+#define MEDIA_BUS_FMT_RGB555_2X8_PADHI_LE 0x1004
+#define MEDIA_BUS_FMT_BGR565_2X8_BE 0x1005
+#define MEDIA_BUS_FMT_BGR565_2X8_LE 0x1006
+#define MEDIA_BUS_FMT_RGB565_2X8_BE 0x1007
+#define MEDIA_BUS_FMT_RGB565_2X8_LE 0x1008
+#define MEDIA_BUS_FMT_RGB666_1X18 0x1009
+#define MEDIA_BUS_FMT_RGB888_1X24 0x100a
+#define MEDIA_BUS_FMT_RGB888_2X12_BE 0x100b
+#define MEDIA_BUS_FMT_RGB888_2X12_LE 0x100c
+#define MEDIA_BUS_FMT_ARGB8888_1X32 0x100d
+
+/* YUV (including grey) - next is 0x2024 */
+#define MEDIA_BUS_FMT_Y8_1X8 0x2001
+#define MEDIA_BUS_FMT_UV8_1X8 0x2015
+#define MEDIA_BUS_FMT_UYVY8_1_5X8 0x2002
+#define MEDIA_BUS_FMT_VYUY8_1_5X8 0x2003
+#define MEDIA_BUS_FMT_YUYV8_1_5X8 0x2004
+#define MEDIA_BUS_FMT_YVYU8_1_5X8 0x2005
+#define MEDIA_BUS_FMT_UYVY8_2X8 0x2006
+#define MEDIA_BUS_FMT_VYUY8_2X8 0x2007
+#define MEDIA_BUS_FMT_YUYV8_2X8 0x2008
+#define MEDIA_BUS_FMT_YVYU8_2X8 0x2009
+#define MEDIA_BUS_FMT_Y10_1X10 0x200a
+#define MEDIA_BUS_FMT_UYVY10_2X10 0x2018
+#define MEDIA_BUS_FMT_VYUY10_2X10 0x2019
+#define MEDIA_BUS_FMT_YUYV10_2X10 0x200b
+#define MEDIA_BUS_FMT_YVYU10_2X10 0x200c
+#define MEDIA_BUS_FMT_Y12_1X12 0x2013
+#define MEDIA_BUS_FMT_UYVY8_1X16 0x200f
+#define MEDIA_BUS_FMT_VYUY8_1X16 0x2010
+#define MEDIA_BUS_FMT_YUYV8_1X16 0x2011
+#define MEDIA_BUS_FMT_YVYU8_1X16 0x2012
+#define MEDIA_BUS_FMT_YDYUYDYV8_1X16 0x2014
+#define MEDIA_BUS_FMT_UYVY10_1X20 0x201a
+#define MEDIA_BUS_FMT_VYUY10_1X20 0x201b
+#define MEDIA_BUS_FMT_YUYV10_1X20 0x200d
+#define MEDIA_BUS_FMT_YVYU10_1X20 0x200e
+#define MEDIA_BUS_FMT_YUV10_1X30 0x2016
+#define MEDIA_BUS_FMT_AYUV8_1X32 0x2017
+#define MEDIA_BUS_FMT_UYVY12_2X12 0x201c
+#define MEDIA_BUS_FMT_VYUY12_2X12 0x201d
+#define MEDIA_BUS_FMT_YUYV12_2X12 0x201e
+#define MEDIA_BUS_FMT_YVYU12_2X12 0x201f
+#define MEDIA_BUS_FMT_UYVY12_1X24 0x2020
+#define MEDIA_BUS_FMT_VYUY12_1X24 0x2021
+#define MEDIA_BUS_FMT_YUYV12_1X24 0x2022
+#define MEDIA_BUS_FMT_YVYU12_1X24 0x2023
+
+/* Bayer - next is 0x3019 */
+#define MEDIA_BUS_FMT_SBGGR8_1X8 0x3001
+#define MEDIA_BUS_FMT_SGBRG8_1X8 0x3013
+#define MEDIA_BUS_FMT_SGRBG8_1X8 0x3002
+#define MEDIA_BUS_FMT_SRGGB8_1X8 0x3014
+#define MEDIA_BUS_FMT_SBGGR10_ALAW8_1X8 0x3015
+#define MEDIA_BUS_FMT_SGBRG10_ALAW8_1X8 0x3016
+#define MEDIA_BUS_FMT_SGRBG10_ALAW8_1X8 0x3017
+#define MEDIA_BUS_FMT_SRGGB10_ALAW8_1X8 0x3018
+#define MEDIA_BUS_FMT_SBGGR10_DPCM8_1X8 0x300b
+#define MEDIA_BUS_FMT_SGBRG10_DPCM8_1X8 0x300c
+#define MEDIA_BUS_FMT_SGRBG10_DPCM8_1X8 0x3009
+#define MEDIA_BUS_FMT_SRGGB10_DPCM8_1X8 0x300d
+#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_BE 0x3003
+#define MEDIA_BUS_FMT_SBGGR10_2X8_PADHI_LE 0x3004
+#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_BE 0x3005
+#define MEDIA_BUS_FMT_SBGGR10_2X8_PADLO_LE 0x3006
+#define MEDIA_BUS_FMT_SBGGR10_1X10 0x3007
+#define MEDIA_BUS_FMT_SGBRG10_1X10 0x300e
+#define MEDIA_BUS_FMT_SGRBG10_1X10 0x300a
+#define MEDIA_BUS_FMT_SRGGB10_1X10 0x300f
+#define MEDIA_BUS_FMT_SBGGR12_1X12 0x3008
+#define MEDIA_BUS_FMT_SGBRG12_1X12 0x3010
+#define MEDIA_BUS_FMT_SGRBG12_1X12 0x3011
+#define MEDIA_BUS_FMT_SRGGB12_1X12 0x3012
+
+/* JPEG compressed formats - next is 0x4002 */
+#define MEDIA_BUS_FMT_JPEG_1X8 0x4001
+
+/* Vendor specific formats - next is 0x5002 */
+
+/* S5C73M3 sensor specific interleaved UYVY and JPEG */
+#define MEDIA_BUS_FMT_S5C_UYVY_JPEG_1X8 0x5001
+
+/* HSV - next is 0x6002 */
+#define MEDIA_BUS_FMT_AHSV8888_1X32 0x6001
+
+#endif /* __LINUX_MEDIA_BUS_FORMAT_H */
diff --git a/include/uapi/linux/nfsd/debug.h b/include/uapi/linux/nfsd/debug.h
index a6f453c..1fdc95b 100644
--- a/include/uapi/linux/nfsd/debug.h
+++ b/include/uapi/linux/nfsd/debug.h
@@ -15,7 +15,7 @@
* Enable debugging for nfsd.
* Requires RPC_DEBUG.
*/
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define NFSD_DEBUG 1
#endif
diff --git a/include/uapi/linux/perf_event.h b/include/uapi/linux/perf_event.h
index 9d84540..9b79abb 100644
--- a/include/uapi/linux/perf_event.h
+++ b/include/uapi/linux/perf_event.h
@@ -137,8 +137,9 @@ enum perf_event_sample_format {
PERF_SAMPLE_DATA_SRC = 1U << 15,
PERF_SAMPLE_IDENTIFIER = 1U << 16,
PERF_SAMPLE_TRANSACTION = 1U << 17,
+ PERF_SAMPLE_REGS_INTR = 1U << 18,
- PERF_SAMPLE_MAX = 1U << 18, /* non-ABI */
+ PERF_SAMPLE_MAX = 1U << 19, /* non-ABI */
};
/*
@@ -238,6 +239,7 @@ enum perf_event_read_format {
#define PERF_ATTR_SIZE_VER2 80 /* add: branch_sample_type */
#define PERF_ATTR_SIZE_VER3 96 /* add: sample_regs_user */
/* add: sample_stack_user */
+#define PERF_ATTR_SIZE_VER4 104 /* add: sample_regs_intr */
/*
* Hardware event_id to monitor via a performance monitoring event:
@@ -334,6 +336,15 @@ struct perf_event_attr {
/* Align to u64. */
__u32 __reserved_2;
+ /*
+ * Defines set of regs to dump for each sample
+ * state captured on:
+ * - precise = 0: PMU interrupt
+ * - precise > 0: sampled instruction
+ *
+ * See asm/perf_regs.h for details.
+ */
+ __u64 sample_regs_intr;
};
#define perf_flags(attr) (*(&(attr)->read_format + 1))
@@ -686,6 +697,8 @@ enum perf_event_type {
* { u64 weight; } && PERF_SAMPLE_WEIGHT
* { u64 data_src; } && PERF_SAMPLE_DATA_SRC
* { u64 transaction; } && PERF_SAMPLE_TRANSACTION
+ * { u64 abi; # enum perf_sample_regs_abi
+ * u64 regs[weight(mask)]; } && PERF_SAMPLE_REGS_INTR
* };
*/
PERF_RECORD_SAMPLE = 9,
diff --git a/include/uapi/linux/prctl.h b/include/uapi/linux/prctl.h
index 513df75..89f6350 100644
--- a/include/uapi/linux/prctl.h
+++ b/include/uapi/linux/prctl.h
@@ -179,4 +179,10 @@ struct prctl_mm_map {
#define PR_SET_THP_DISABLE 41
#define PR_GET_THP_DISABLE 42
+/*
+ * Tell the kernel to start/stop helping userspace manage bounds tables.
+ */
+#define PR_MPX_ENABLE_MANAGEMENT 43
+#define PR_MPX_DISABLE_MANAGEMENT 44
+
#endif /* _LINUX_PRCTL_H */
diff --git a/include/uapi/linux/sched.h b/include/uapi/linux/sched.h
index b932be9..cc89dde 100644
--- a/include/uapi/linux/sched.h
+++ b/include/uapi/linux/sched.h
@@ -23,8 +23,8 @@
#define CLONE_CHILD_SETTID 0x01000000 /* set the TID in the child */
/* 0x02000000 was previously the unused CLONE_STOPPED (Start in stopped state)
and is now available for re-use. */
-#define CLONE_NEWUTS 0x04000000 /* New utsname group? */
-#define CLONE_NEWIPC 0x08000000 /* New ipcs */
+#define CLONE_NEWUTS 0x04000000 /* New utsname namespace */
+#define CLONE_NEWIPC 0x08000000 /* New ipc namespace */
#define CLONE_NEWUSER 0x10000000 /* New user namespace */
#define CLONE_NEWPID 0x20000000 /* New pid namespace */
#define CLONE_NEWNET 0x40000000 /* New network namespace */
diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h
index 43aaba1..0956373 100644
--- a/include/uapi/linux/sysctl.h
+++ b/include/uapi/linux/sysctl.h
@@ -153,6 +153,7 @@ enum
KERN_MAX_LOCK_DEPTH=74, /* int: rtmutex's maximum lock depth */
KERN_NMI_WATCHDOG=75, /* int: enable/disable nmi watchdog */
KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */
+ KERN_PANIC_ON_WARN=77, /* int: call panic() in WARN() functions */
};
diff --git a/include/uapi/linux/v4l2-common.h b/include/uapi/linux/v4l2-common.h
index 2f6f8ca..1527398 100644
--- a/include/uapi/linux/v4l2-common.h
+++ b/include/uapi/linux/v4l2-common.h
@@ -43,6 +43,8 @@
#define V4L2_SEL_TGT_CROP_DEFAULT 0x0001
/* Cropping bounds */
#define V4L2_SEL_TGT_CROP_BOUNDS 0x0002
+/* Native frame size */
+#define V4L2_SEL_TGT_NATIVE_SIZE 0x0003
/* Current composing area */
#define V4L2_SEL_TGT_COMPOSE 0x0100
/* Default composing area */
diff --git a/include/uapi/linux/v4l2-mediabus.h b/include/uapi/linux/v4l2-mediabus.h
index 1445e85..5a86d8e 100644
--- a/include/uapi/linux/v4l2-mediabus.h
+++ b/include/uapi/linux/v4l2-mediabus.h
@@ -11,122 +11,10 @@
#ifndef __LINUX_V4L2_MEDIABUS_H
#define __LINUX_V4L2_MEDIABUS_H
+#include <linux/media-bus-format.h>
#include <linux/types.h>
#include <linux/videodev2.h>
-/*
- * These pixel codes uniquely identify data formats on the media bus. Mostly
- * they correspond to similarly named V4L2_PIX_FMT_* formats, format 0 is
- * reserved, V4L2_MBUS_FMT_FIXED shall be used by host-client pairs, where the
- * data format is fixed. Additionally, "2X8" means that one pixel is transferred
- * in two 8-bit samples, "BE" or "LE" specify in which order those samples are
- * transferred over the bus: "LE" means that the least significant bits are
- * transferred first, "BE" means that the most significant bits are transferred
- * first, and "PADHI" and "PADLO" define which bits - low or high, in the
- * incomplete high byte, are filled with padding bits.
- *
- * The pixel codes are grouped by type, bus_width, bits per component, samples
- * per pixel and order of subsamples. Numerical values are sorted using generic
- * numerical sort order (8 thus comes before 10).
- *
- * As their value can't change when a new pixel code is inserted in the
- * enumeration, the pixel codes are explicitly given a numerical value. The next
- * free values for each category are listed below, update them when inserting
- * new pixel codes.
- */
-enum v4l2_mbus_pixelcode {
- V4L2_MBUS_FMT_FIXED = 0x0001,
-
- /* RGB - next is 0x100e */
- V4L2_MBUS_FMT_RGB444_2X8_PADHI_BE = 0x1001,
- V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE = 0x1002,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE = 0x1003,
- V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE = 0x1004,
- V4L2_MBUS_FMT_BGR565_2X8_BE = 0x1005,
- V4L2_MBUS_FMT_BGR565_2X8_LE = 0x1006,
- V4L2_MBUS_FMT_RGB565_2X8_BE = 0x1007,
- V4L2_MBUS_FMT_RGB565_2X8_LE = 0x1008,
- V4L2_MBUS_FMT_RGB666_1X18 = 0x1009,
- V4L2_MBUS_FMT_RGB888_1X24 = 0x100a,
- V4L2_MBUS_FMT_RGB888_2X12_BE = 0x100b,
- V4L2_MBUS_FMT_RGB888_2X12_LE = 0x100c,
- V4L2_MBUS_FMT_ARGB8888_1X32 = 0x100d,
-
- /* YUV (including grey) - next is 0x2024 */
- V4L2_MBUS_FMT_Y8_1X8 = 0x2001,
- V4L2_MBUS_FMT_UV8_1X8 = 0x2015,
- V4L2_MBUS_FMT_UYVY8_1_5X8 = 0x2002,
- V4L2_MBUS_FMT_VYUY8_1_5X8 = 0x2003,
- V4L2_MBUS_FMT_YUYV8_1_5X8 = 0x2004,
- V4L2_MBUS_FMT_YVYU8_1_5X8 = 0x2005,
- V4L2_MBUS_FMT_UYVY8_2X8 = 0x2006,
- V4L2_MBUS_FMT_VYUY8_2X8 = 0x2007,
- V4L2_MBUS_FMT_YUYV8_2X8 = 0x2008,
- V4L2_MBUS_FMT_YVYU8_2X8 = 0x2009,
- V4L2_MBUS_FMT_Y10_1X10 = 0x200a,
- V4L2_MBUS_FMT_UYVY10_2X10 = 0x2018,
- V4L2_MBUS_FMT_VYUY10_2X10 = 0x2019,
- V4L2_MBUS_FMT_YUYV10_2X10 = 0x200b,
- V4L2_MBUS_FMT_YVYU10_2X10 = 0x200c,
- V4L2_MBUS_FMT_Y12_1X12 = 0x2013,
- V4L2_MBUS_FMT_UYVY8_1X16 = 0x200f,
- V4L2_MBUS_FMT_VYUY8_1X16 = 0x2010,
- V4L2_MBUS_FMT_YUYV8_1X16 = 0x2011,
- V4L2_MBUS_FMT_YVYU8_1X16 = 0x2012,
- V4L2_MBUS_FMT_YDYUYDYV8_1X16 = 0x2014,
- V4L2_MBUS_FMT_UYVY10_1X20 = 0x201a,
- V4L2_MBUS_FMT_VYUY10_1X20 = 0x201b,
- V4L2_MBUS_FMT_YUYV10_1X20 = 0x200d,
- V4L2_MBUS_FMT_YVYU10_1X20 = 0x200e,
- V4L2_MBUS_FMT_YUV10_1X30 = 0x2016,
- V4L2_MBUS_FMT_AYUV8_1X32 = 0x2017,
- V4L2_MBUS_FMT_UYVY12_2X12 = 0x201c,
- V4L2_MBUS_FMT_VYUY12_2X12 = 0x201d,
- V4L2_MBUS_FMT_YUYV12_2X12 = 0x201e,
- V4L2_MBUS_FMT_YVYU12_2X12 = 0x201f,
- V4L2_MBUS_FMT_UYVY12_1X24 = 0x2020,
- V4L2_MBUS_FMT_VYUY12_1X24 = 0x2021,
- V4L2_MBUS_FMT_YUYV12_1X24 = 0x2022,
- V4L2_MBUS_FMT_YVYU12_1X24 = 0x2023,
-
- /* Bayer - next is 0x3019 */
- V4L2_MBUS_FMT_SBGGR8_1X8 = 0x3001,
- V4L2_MBUS_FMT_SGBRG8_1X8 = 0x3013,
- V4L2_MBUS_FMT_SGRBG8_1X8 = 0x3002,
- V4L2_MBUS_FMT_SRGGB8_1X8 = 0x3014,
- V4L2_MBUS_FMT_SBGGR10_ALAW8_1X8 = 0x3015,
- V4L2_MBUS_FMT_SGBRG10_ALAW8_1X8 = 0x3016,
- V4L2_MBUS_FMT_SGRBG10_ALAW8_1X8 = 0x3017,
- V4L2_MBUS_FMT_SRGGB10_ALAW8_1X8 = 0x3018,
- V4L2_MBUS_FMT_SBGGR10_DPCM8_1X8 = 0x300b,
- V4L2_MBUS_FMT_SGBRG10_DPCM8_1X8 = 0x300c,
- V4L2_MBUS_FMT_SGRBG10_DPCM8_1X8 = 0x3009,
- V4L2_MBUS_FMT_SRGGB10_DPCM8_1X8 = 0x300d,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_BE = 0x3003,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE = 0x3004,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_BE = 0x3005,
- V4L2_MBUS_FMT_SBGGR10_2X8_PADLO_LE = 0x3006,
- V4L2_MBUS_FMT_SBGGR10_1X10 = 0x3007,
- V4L2_MBUS_FMT_SGBRG10_1X10 = 0x300e,
- V4L2_MBUS_FMT_SGRBG10_1X10 = 0x300a,
- V4L2_MBUS_FMT_SRGGB10_1X10 = 0x300f,
- V4L2_MBUS_FMT_SBGGR12_1X12 = 0x3008,
- V4L2_MBUS_FMT_SGBRG12_1X12 = 0x3010,
- V4L2_MBUS_FMT_SGRBG12_1X12 = 0x3011,
- V4L2_MBUS_FMT_SRGGB12_1X12 = 0x3012,
-
- /* JPEG compressed formats - next is 0x4002 */
- V4L2_MBUS_FMT_JPEG_1X8 = 0x4001,
-
- /* Vendor specific formats - next is 0x5002 */
-
- /* S5C73M3 sensor specific interleaved UYVY and JPEG */
- V4L2_MBUS_FMT_S5C_UYVY_JPEG_1X8 = 0x5001,
-
- /* HSV - next is 0x6002 */
- V4L2_MBUS_FMT_AHSV8888_1X32 = 0x6001,
-};
-
/**
* struct v4l2_mbus_framefmt - frame format on the media bus
* @width: frame width
@@ -134,6 +22,8 @@ enum v4l2_mbus_pixelcode {
* @code: data format code (from enum v4l2_mbus_pixelcode)
* @field: used interlacing type (from enum v4l2_field)
* @colorspace: colorspace of the data (from enum v4l2_colorspace)
+ * @ycbcr_enc: YCbCr encoding of the data (from enum v4l2_ycbcr_encoding)
+ * @quantization: quantization of the data (from enum v4l2_quantization)
*/
struct v4l2_mbus_framefmt {
__u32 width;
@@ -141,7 +31,108 @@ struct v4l2_mbus_framefmt {
__u32 code;
__u32 field;
__u32 colorspace;
- __u32 reserved[7];
+ __u32 ycbcr_enc;
+ __u32 quantization;
+ __u32 reserved[5];
+};
+
+#ifndef __KERNEL__
+/*
+ * enum v4l2_mbus_pixelcode and its definitions are now deprecated, and
+ * MEDIA_BUS_FMT_ definitions (defined in media-bus-format.h) should be
+ * used instead.
+ *
+ * New defines should only be added to media-bus-format.h. The
+ * v4l2_mbus_pixelcode enum is frozen.
+ */
+
+#define V4L2_MBUS_FROM_MEDIA_BUS_FMT(name) \
+ V4L2_MBUS_FMT_ ## name = MEDIA_BUS_FMT_ ## name
+
+enum v4l2_mbus_pixelcode {
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(FIXED),
+
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB444_2X8_PADHI_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB444_2X8_PADHI_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB555_2X8_PADHI_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB555_2X8_PADHI_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(BGR565_2X8_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(BGR565_2X8_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB565_2X8_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB565_2X8_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB666_1X18),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB888_1X24),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB888_2X12_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(RGB888_2X12_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(ARGB8888_1X32),
+
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(Y8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UV8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY8_1_5X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY8_1_5X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV8_1_5X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU8_1_5X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY8_2X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY8_2X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV8_2X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU8_2X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(Y10_1X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY10_2X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY10_2X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV10_2X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU10_2X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(Y12_1X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY8_1X16),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY8_1X16),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV8_1X16),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU8_1X16),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YDYUYDYV8_1X16),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY10_1X20),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY10_1X20),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV10_1X20),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU10_1X20),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUV10_1X30),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(AYUV8_1X32),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY12_2X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY12_2X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV12_2X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU12_2X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(UYVY12_1X24),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(VYUY12_1X24),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YUYV12_1X24),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(YVYU12_1X24),
+
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGBRG8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGRBG8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SRGGB8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_ALAW8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGBRG10_ALAW8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGRBG10_ALAW8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SRGGB10_ALAW8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_DPCM8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGBRG10_DPCM8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGRBG10_DPCM8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SRGGB10_DPCM8_1X8),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_2X8_PADHI_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_2X8_PADHI_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_2X8_PADLO_BE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_2X8_PADLO_LE),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR10_1X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGBRG10_1X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGRBG10_1X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SRGGB10_1X10),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SBGGR12_1X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGBRG12_1X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SGRBG12_1X12),
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(SRGGB12_1X12),
+
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(JPEG_1X8),
+
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(S5C_UYVY_JPEG_1X8),
+
+ V4L2_MBUS_FROM_MEDIA_BUS_FMT(AHSV8888_1X32),
};
+#endif /* __KERNEL__ */
#endif
diff --git a/include/uapi/linux/v4l2-subdev.h b/include/uapi/linux/v4l2-subdev.h
index a619cdd..e0a7e3d 100644
--- a/include/uapi/linux/v4l2-subdev.h
+++ b/include/uapi/linux/v4l2-subdev.h
@@ -68,7 +68,7 @@ struct v4l2_subdev_crop {
* struct v4l2_subdev_mbus_code_enum - Media bus format enumeration
* @pad: pad number, as reported by the media API
* @index: format index during enumeration
- * @code: format code (from enum v4l2_mbus_pixelcode)
+ * @code: format code (MEDIA_BUS_FMT_ definitions)
*/
struct v4l2_subdev_mbus_code_enum {
__u32 pad;
@@ -81,7 +81,7 @@ struct v4l2_subdev_mbus_code_enum {
* struct v4l2_subdev_frame_size_enum - Media bus format enumeration
* @pad: pad number, as reported by the media API
* @index: format index during enumeration
- * @code: format code (from enum v4l2_mbus_pixelcode)
+ * @code: format code (MEDIA_BUS_FMT_ definitions)
*/
struct v4l2_subdev_frame_size_enum {
__u32 index;
@@ -109,7 +109,7 @@ struct v4l2_subdev_frame_interval {
* struct v4l2_subdev_frame_interval_enum - Frame interval enumeration
* @pad: pad number, as reported by the media API
* @index: frame interval index during enumeration
- * @code: format code (from enum v4l2_mbus_pixelcode)
+ * @code: format code (MEDIA_BUS_FMT_ definitions)
* @width: frame width in pixels
* @height: frame height in pixels
* @interval: frame interval in seconds
diff --git a/include/uapi/linux/videodev2.h b/include/uapi/linux/videodev2.h
index 1c2f84f..d279c1b 100644
--- a/include/uapi/linux/videodev2.h
+++ b/include/uapi/linux/videodev2.h
@@ -178,30 +178,103 @@ enum v4l2_memory {
/* see also http://vektor.theorem.ca/graphics/ycbcr/ */
enum v4l2_colorspace {
- /* ITU-R 601 -- broadcast NTSC/PAL */
+ /* SMPTE 170M: used for broadcast NTSC/PAL SDTV */
V4L2_COLORSPACE_SMPTE170M = 1,
- /* 1125-Line (US) HDTV */
+ /* Obsolete pre-1998 SMPTE 240M HDTV standard, superseded by Rec 709 */
V4L2_COLORSPACE_SMPTE240M = 2,
- /* HD and modern captures. */
+ /* Rec.709: used for HDTV */
V4L2_COLORSPACE_REC709 = 3,
- /* broken BT878 extents (601, luma range 16-253 instead of 16-235) */
+ /*
+ * Deprecated, do not use. No driver will ever return this. This was
+ * based on a misunderstanding of the bt878 datasheet.
+ */
V4L2_COLORSPACE_BT878 = 4,
- /* These should be useful. Assume 601 extents. */
+ /*
+ * NTSC 1953 colorspace. This only makes sense when dealing with
+ * really, really old NTSC recordings. Superseded by SMPTE 170M.
+ */
V4L2_COLORSPACE_470_SYSTEM_M = 5,
+
+ /*
+ * EBU Tech 3213 PAL/SECAM colorspace. This only makes sense when
+ * dealing with really old PAL/SECAM recordings. Superseded by
+ * SMPTE 170M.
+ */
V4L2_COLORSPACE_470_SYSTEM_BG = 6,
- /* I know there will be cameras that send this. So, this is
- * unspecified chromaticities and full 0-255 on each of the
- * Y'CbCr components
+ /*
+ * Effectively shorthand for V4L2_COLORSPACE_SRGB, V4L2_YCBCR_ENC_601
+ * and V4L2_QUANTIZATION_FULL_RANGE. To be used for (Motion-)JPEG.
*/
V4L2_COLORSPACE_JPEG = 7,
- /* For RGB colourspaces, this is probably a good start. */
+ /* For RGB colorspaces such as produces by most webcams. */
V4L2_COLORSPACE_SRGB = 8,
+
+ /* AdobeRGB colorspace */
+ V4L2_COLORSPACE_ADOBERGB = 9,
+
+ /* BT.2020 colorspace, used for UHDTV. */
+ V4L2_COLORSPACE_BT2020 = 10,
+};
+
+enum v4l2_ycbcr_encoding {
+ /*
+ * Mapping of V4L2_YCBCR_ENC_DEFAULT to actual encodings for the
+ * various colorspaces:
+ *
+ * V4L2_COLORSPACE_SMPTE170M, V4L2_COLORSPACE_470_SYSTEM_M,
+ * V4L2_COLORSPACE_470_SYSTEM_BG, V4L2_COLORSPACE_ADOBERGB and
+ * V4L2_COLORSPACE_JPEG: V4L2_YCBCR_ENC_601
+ *
+ * V4L2_COLORSPACE_REC709: V4L2_YCBCR_ENC_709
+ *
+ * V4L2_COLORSPACE_SRGB: V4L2_YCBCR_ENC_SYCC
+ *
+ * V4L2_COLORSPACE_BT2020: V4L2_YCBCR_ENC_BT2020
+ *
+ * V4L2_COLORSPACE_SMPTE240M: V4L2_YCBCR_ENC_SMPTE240M
+ */
+ V4L2_YCBCR_ENC_DEFAULT = 0,
+
+ /* ITU-R 601 -- SDTV */
+ V4L2_YCBCR_ENC_601 = 1,
+
+ /* Rec. 709 -- HDTV */
+ V4L2_YCBCR_ENC_709 = 2,
+
+ /* ITU-R 601/EN 61966-2-4 Extended Gamut -- SDTV */
+ V4L2_YCBCR_ENC_XV601 = 3,
+
+ /* Rec. 709/EN 61966-2-4 Extended Gamut -- HDTV */
+ V4L2_YCBCR_ENC_XV709 = 4,
+
+ /* sYCC (Y'CbCr encoding of sRGB) */
+ V4L2_YCBCR_ENC_SYCC = 5,
+
+ /* BT.2020 Non-constant Luminance Y'CbCr */
+ V4L2_YCBCR_ENC_BT2020 = 6,
+
+ /* BT.2020 Constant Luminance Y'CbcCrc */
+ V4L2_YCBCR_ENC_BT2020_CONST_LUM = 7,
+
+ /* SMPTE 240M -- Obsolete HDTV */
+ V4L2_YCBCR_ENC_SMPTE240M = 8,
+};
+
+enum v4l2_quantization {
+ /*
+ * The default for R'G'B' quantization is always full range. For
+ * Y'CbCr the quantization is always limited range, except for
+ * SYCC, XV601, XV709 or JPEG: those are full range.
+ */
+ V4L2_QUANTIZATION_DEFAULT = 0,
+ V4L2_QUANTIZATION_FULL_RANGE = 1,
+ V4L2_QUANTIZATION_LIM_RANGE = 2,
};
enum v4l2_priority {
@@ -294,6 +367,8 @@ struct v4l2_pix_format {
__u32 colorspace; /* enum v4l2_colorspace */
__u32 priv; /* private data, depends on pixelformat */
__u32 flags; /* format flags (V4L2_PIX_FMT_FLAG_*) */
+ __u32 ycbcr_enc; /* enum v4l2_ycbcr_encoding */
+ __u32 quantization; /* enum v4l2_quantization */
};
/* Pixel format FOURCC depth Description */
@@ -1249,6 +1324,7 @@ struct v4l2_input {
#define V4L2_IN_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */
#define V4L2_IN_CAP_CUSTOM_TIMINGS V4L2_IN_CAP_DV_TIMINGS /* For compatibility */
#define V4L2_IN_CAP_STD 0x00000004 /* Supports S_STD */
+#define V4L2_IN_CAP_NATIVE_SIZE 0x00000008 /* Supports setting native size */
/*
* V I D E O O U T P U T S
@@ -1272,6 +1348,7 @@ struct v4l2_output {
#define V4L2_OUT_CAP_DV_TIMINGS 0x00000002 /* Supports S_DV_TIMINGS */
#define V4L2_OUT_CAP_CUSTOM_TIMINGS V4L2_OUT_CAP_DV_TIMINGS /* For compatibility */
#define V4L2_OUT_CAP_STD 0x00000004 /* Supports S_STD */
+#define V4L2_OUT_CAP_NATIVE_SIZE 0x00000008 /* Supports setting native size */
/*
* C O N T R O L S
@@ -1777,6 +1854,8 @@ struct v4l2_plane_pix_format {
* @plane_fmt: per-plane information
* @num_planes: number of planes for this format
* @flags: format flags (V4L2_PIX_FMT_FLAG_*)
+ * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization: enum v4l2_quantization, colorspace quantization
*/
struct v4l2_pix_format_mplane {
__u32 width;
@@ -1788,7 +1867,9 @@ struct v4l2_pix_format_mplane {
struct v4l2_plane_pix_format plane_fmt[VIDEO_MAX_PLANES];
__u8 num_planes;
__u8 flags;
- __u8 reserved[10];
+ __u8 ycbcr_enc;
+ __u8 quantization;
+ __u8 reserved[8];
} __attribute__ ((packed));
/**
diff --git a/include/uapi/linux/virtio_blk.h b/include/uapi/linux/virtio_blk.h
index 9ad67b2..247c8ba 100644
--- a/include/uapi/linux/virtio_blk.h
+++ b/include/uapi/linux/virtio_blk.h
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/virtio_types.h>
/* Feature bits */
#define VIRTIO_BLK_F_BARRIER 0 /* Does host support barriers? */
@@ -114,18 +115,18 @@ struct virtio_blk_config {
/* This is the first element of the read scatter-gather list. */
struct virtio_blk_outhdr {
/* VIRTIO_BLK_T* */
- __u32 type;
+ __virtio32 type;
/* io priority. */
- __u32 ioprio;
+ __virtio32 ioprio;
/* Sector (ie. 512 byte offset) */
- __u64 sector;
+ __virtio64 sector;
};
struct virtio_scsi_inhdr {
- __u32 errors;
- __u32 data_len;
- __u32 sense_len;
- __u32 residual;
+ __virtio32 errors;
+ __virtio32 data_len;
+ __virtio32 sense_len;
+ __virtio32 residual;
};
/* And this is the final byte of the write scatter-gather list. */
diff --git a/include/uapi/linux/virtio_config.h b/include/uapi/linux/virtio_config.h
index 3ce768c..a6d0cde 100644
--- a/include/uapi/linux/virtio_config.h
+++ b/include/uapi/linux/virtio_config.h
@@ -38,14 +38,16 @@
#define VIRTIO_CONFIG_S_DRIVER 2
/* Driver has used its parts of the config, and is happy */
#define VIRTIO_CONFIG_S_DRIVER_OK 4
+/* Driver has finished configuring features */
+#define VIRTIO_CONFIG_S_FEATURES_OK 8
/* We've given up on this device. */
#define VIRTIO_CONFIG_S_FAILED 0x80
-/* Some virtio feature bits (currently bits 28 through 31) are reserved for the
+/* Some virtio feature bits (currently bits 28 through 32) are reserved for the
* transport being used (eg. virtio_ring), the rest are per-device feature
* bits. */
#define VIRTIO_TRANSPORT_F_START 28
-#define VIRTIO_TRANSPORT_F_END 32
+#define VIRTIO_TRANSPORT_F_END 33
/* Do we get callbacks when the ring is completely used, even if we've
* suppressed them? */
@@ -54,4 +56,7 @@
/* Can the device handle any descriptor layout? */
#define VIRTIO_F_ANY_LAYOUT 27
+/* v1.0 compliant. */
+#define VIRTIO_F_VERSION_1 32
+
#endif /* _UAPI_LINUX_VIRTIO_CONFIG_H */
diff --git a/include/uapi/linux/virtio_console.h b/include/uapi/linux/virtio_console.h
index ba260dd..b7fb108 100644
--- a/include/uapi/linux/virtio_console.h
+++ b/include/uapi/linux/virtio_console.h
@@ -32,6 +32,7 @@
#ifndef _UAPI_LINUX_VIRTIO_CONSOLE_H
#define _UAPI_LINUX_VIRTIO_CONSOLE_H
#include <linux/types.h>
+#include <linux/virtio_types.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
@@ -58,9 +59,9 @@ struct virtio_console_config {
* particular port.
*/
struct virtio_console_control {
- __u32 id; /* Port number */
- __u16 event; /* The kind of control event (see below) */
- __u16 value; /* Extra information for the key */
+ __virtio32 id; /* Port number */
+ __virtio16 event; /* The kind of control event (see below) */
+ __virtio16 value; /* Extra information for the key */
};
/* Some events for control messages */
diff --git a/include/uapi/linux/virtio_net.h b/include/uapi/linux/virtio_net.h
index 172a7f0..b5f1677 100644
--- a/include/uapi/linux/virtio_net.h
+++ b/include/uapi/linux/virtio_net.h
@@ -28,6 +28,7 @@
#include <linux/types.h>
#include <linux/virtio_ids.h>
#include <linux/virtio_config.h>
+#include <linux/virtio_types.h>
#include <linux/if_ether.h>
/* The feature bitmap for virtio net */
@@ -84,17 +85,17 @@ struct virtio_net_hdr {
#define VIRTIO_NET_HDR_GSO_TCPV6 4 // GSO frame, IPv6 TCP
#define VIRTIO_NET_HDR_GSO_ECN 0x80 // TCP has ECN set
__u8 gso_type;
- __u16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
- __u16 gso_size; /* Bytes to append to hdr_len per frame */
- __u16 csum_start; /* Position to start checksumming from */
- __u16 csum_offset; /* Offset after that to place checksum */
+ __virtio16 hdr_len; /* Ethernet + IP + tcp/udp hdrs */
+ __virtio16 gso_size; /* Bytes to append to hdr_len per frame */
+ __virtio16 csum_start; /* Position to start checksumming from */
+ __virtio16 csum_offset; /* Offset after that to place checksum */
};
/* This is the version of the header to use when the MRG_RXBUF
* feature has been negotiated. */
struct virtio_net_hdr_mrg_rxbuf {
struct virtio_net_hdr hdr;
- __u16 num_buffers; /* Number of merged rx buffers */
+ __virtio16 num_buffers; /* Number of merged rx buffers */
};
/*
@@ -149,7 +150,7 @@ typedef __u8 virtio_net_ctrl_ack;
* VIRTIO_NET_F_CTRL_MAC_ADDR feature is available.
*/
struct virtio_net_ctrl_mac {
- __u32 entries;
+ __virtio32 entries;
__u8 macs[][ETH_ALEN];
} __attribute__((packed));
@@ -193,7 +194,7 @@ struct virtio_net_ctrl_mac {
* specified.
*/
struct virtio_net_ctrl_mq {
- __u16 virtqueue_pairs;
+ __virtio16 virtqueue_pairs;
};
#define VIRTIO_NET_CTRL_MQ 4
diff --git a/include/uapi/linux/virtio_ring.h b/include/uapi/linux/virtio_ring.h
index a99f9b7..61c818a 100644
--- a/include/uapi/linux/virtio_ring.h
+++ b/include/uapi/linux/virtio_ring.h
@@ -32,6 +32,7 @@
*
* Copyright Rusty Russell IBM Corporation 2007. */
#include <linux/types.h>
+#include <linux/virtio_types.h>
/* This marks a buffer as continuing via the next field. */
#define VRING_DESC_F_NEXT 1
@@ -61,32 +62,32 @@
/* Virtio ring descriptors: 16 bytes. These can chain together via "next". */
struct vring_desc {
/* Address (guest-physical). */
- __u64 addr;
+ __virtio64 addr;
/* Length. */
- __u32 len;
+ __virtio32 len;
/* The flags as indicated above. */
- __u16 flags;
+ __virtio16 flags;
/* We chain unused descriptors via this, too */
- __u16 next;
+ __virtio16 next;
};
struct vring_avail {
- __u16 flags;
- __u16 idx;
- __u16 ring[];
+ __virtio16 flags;
+ __virtio16 idx;
+ __virtio16 ring[];
};
/* u32 is used here for ids for padding reasons. */
struct vring_used_elem {
/* Index of start of used descriptor chain. */
- __u32 id;
+ __virtio32 id;
/* Total length of the descriptor chain which was used (written to) */
- __u32 len;
+ __virtio32 len;
};
struct vring_used {
- __u16 flags;
- __u16 idx;
+ __virtio16 flags;
+ __virtio16 idx;
struct vring_used_elem ring[];
};
@@ -109,25 +110,25 @@ struct vring {
* struct vring_desc desc[num];
*
* // A ring of available descriptor heads with free-running index.
- * __u16 avail_flags;
- * __u16 avail_idx;
- * __u16 available[num];
- * __u16 used_event_idx;
+ * __virtio16 avail_flags;
+ * __virtio16 avail_idx;
+ * __virtio16 available[num];
+ * __virtio16 used_event_idx;
*
* // Padding to the next align boundary.
* char pad[];
*
* // A ring of used descriptor heads with free-running index.
- * __u16 used_flags;
- * __u16 used_idx;
+ * __virtio16 used_flags;
+ * __virtio16 used_idx;
* struct vring_used_elem used[num];
- * __u16 avail_event_idx;
+ * __virtio16 avail_event_idx;
* };
*/
/* We publish the used event index at the end of the available ring, and vice
* versa. They are at the end for backwards compatibility. */
#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
-#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
+#define vring_avail_event(vr) (*(__virtio16 *)&(vr)->used->ring[(vr)->num])
static inline void vring_init(struct vring *vr, unsigned int num, void *p,
unsigned long align)
@@ -135,15 +136,15 @@ static inline void vring_init(struct vring *vr, unsigned int num, void *p,
vr->num = num;
vr->desc = p;
vr->avail = p + num*sizeof(struct vring_desc);
- vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__u16)
+ vr->used = (void *)(((unsigned long)&vr->avail->ring[num] + sizeof(__virtio16)
+ align-1) & ~(align - 1));
}
static inline unsigned vring_size(unsigned int num, unsigned long align)
{
- return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (3 + num)
+ return ((sizeof(struct vring_desc) * num + sizeof(__virtio16) * (3 + num)
+ align - 1) & ~(align - 1))
- + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
+ + sizeof(__virtio16) * 3 + sizeof(struct vring_used_elem) * num;
}
/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
diff --git a/include/linux/virtio_scsi.h b/include/uapi/linux/virtio_scsi.h
index de429d1..42b9370 100644
--- a/include/linux/virtio_scsi.h
+++ b/include/uapi/linux/virtio_scsi.h
@@ -27,83 +27,85 @@
#ifndef _LINUX_VIRTIO_SCSI_H
#define _LINUX_VIRTIO_SCSI_H
+#include <linux/virtio_types.h>
+
#define VIRTIO_SCSI_CDB_SIZE 32
#define VIRTIO_SCSI_SENSE_SIZE 96
/* SCSI command request, followed by data-out */
struct virtio_scsi_cmd_req {
- u8 lun[8]; /* Logical Unit Number */
- u64 tag; /* Command identifier */
- u8 task_attr; /* Task attribute */
- u8 prio; /* SAM command priority field */
- u8 crn;
- u8 cdb[VIRTIO_SCSI_CDB_SIZE];
-} __packed;
+ __u8 lun[8]; /* Logical Unit Number */
+ __virtio64 tag; /* Command identifier */
+ __u8 task_attr; /* Task attribute */
+ __u8 prio; /* SAM command priority field */
+ __u8 crn;
+ __u8 cdb[VIRTIO_SCSI_CDB_SIZE];
+} __attribute__((packed));
/* SCSI command request, followed by protection information */
struct virtio_scsi_cmd_req_pi {
- u8 lun[8]; /* Logical Unit Number */
- u64 tag; /* Command identifier */
- u8 task_attr; /* Task attribute */
- u8 prio; /* SAM command priority field */
- u8 crn;
- u32 pi_bytesout; /* DataOUT PI Number of bytes */
- u32 pi_bytesin; /* DataIN PI Number of bytes */
- u8 cdb[VIRTIO_SCSI_CDB_SIZE];
-} __packed;
+ __u8 lun[8]; /* Logical Unit Number */
+ __virtio64 tag; /* Command identifier */
+ __u8 task_attr; /* Task attribute */
+ __u8 prio; /* SAM command priority field */
+ __u8 crn;
+ __virtio32 pi_bytesout; /* DataOUT PI Number of bytes */
+ __virtio32 pi_bytesin; /* DataIN PI Number of bytes */
+ __u8 cdb[VIRTIO_SCSI_CDB_SIZE];
+} __attribute__((packed));
/* Response, followed by sense data and data-in */
struct virtio_scsi_cmd_resp {
- u32 sense_len; /* Sense data length */
- u32 resid; /* Residual bytes in data buffer */
- u16 status_qualifier; /* Status qualifier */
- u8 status; /* Command completion status */
- u8 response; /* Response values */
- u8 sense[VIRTIO_SCSI_SENSE_SIZE];
-} __packed;
+ __virtio32 sense_len; /* Sense data length */
+ __virtio32 resid; /* Residual bytes in data buffer */
+ __virtio16 status_qualifier; /* Status qualifier */
+ __u8 status; /* Command completion status */
+ __u8 response; /* Response values */
+ __u8 sense[VIRTIO_SCSI_SENSE_SIZE];
+} __attribute__((packed));
/* Task Management Request */
struct virtio_scsi_ctrl_tmf_req {
- u32 type;
- u32 subtype;
- u8 lun[8];
- u64 tag;
-} __packed;
+ __virtio32 type;
+ __virtio32 subtype;
+ __u8 lun[8];
+ __virtio64 tag;
+} __attribute__((packed));
struct virtio_scsi_ctrl_tmf_resp {
- u8 response;
-} __packed;
+ __u8 response;
+} __attribute__((packed));
/* Asynchronous notification query/subscription */
struct virtio_scsi_ctrl_an_req {
- u32 type;
- u8 lun[8];
- u32 event_requested;
-} __packed;
+ __virtio32 type;
+ __u8 lun[8];
+ __virtio32 event_requested;
+} __attribute__((packed));
struct virtio_scsi_ctrl_an_resp {
- u32 event_actual;
- u8 response;
-} __packed;
+ __virtio32 event_actual;
+ __u8 response;
+} __attribute__((packed));
struct virtio_scsi_event {
- u32 event;
- u8 lun[8];
- u32 reason;
-} __packed;
+ __virtio32 event;
+ __u8 lun[8];
+ __virtio32 reason;
+} __attribute__((packed));
struct virtio_scsi_config {
- u32 num_queues;
- u32 seg_max;
- u32 max_sectors;
- u32 cmd_per_lun;
- u32 event_info_size;
- u32 sense_size;
- u32 cdb_size;
- u16 max_channel;
- u16 max_target;
- u32 max_lun;
-} __packed;
+ __u32 num_queues;
+ __u32 seg_max;
+ __u32 max_sectors;
+ __u32 cmd_per_lun;
+ __u32 event_info_size;
+ __u32 sense_size;
+ __u32 cdb_size;
+ __u16 max_channel;
+ __u16 max_target;
+ __u32 max_lun;
+} __attribute__((packed));
/* Feature Bits */
#define VIRTIO_SCSI_F_INOUT 0
diff --git a/include/uapi/linux/virtio_types.h b/include/uapi/linux/virtio_types.h
new file mode 100644
index 0000000..e845e8c
--- /dev/null
+++ b/include/uapi/linux/virtio_types.h
@@ -0,0 +1,46 @@
+#ifndef _UAPI_LINUX_VIRTIO_TYPES_H
+#define _UAPI_LINUX_VIRTIO_TYPES_H
+/* Type definitions for virtio implementations.
+ *
+ * This header is BSD licensed so anyone can use the definitions to implement
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * Copyright (C) 2014 Red Hat, Inc.
+ * Author: Michael S. Tsirkin <mst@redhat.com>
+ */
+#include <linux/types.h>
+
+/*
+ * __virtio{16,32,64} have the following meaning:
+ * - __u{16,32,64} for virtio devices in legacy mode, accessed in native endian
+ * - __le{16,32,64} for standard-compliant virtio devices
+ */
+
+typedef __u16 __bitwise__ __virtio16;
+typedef __u32 __bitwise__ __virtio32;
+typedef __u64 __bitwise__ __virtio64;
+
+#endif /* _UAPI_LINUX_VIRTIO_TYPES_H */
diff --git a/include/uapi/sound/asound.h b/include/uapi/sound/asound.h
index 941d32f..1f23cd6 100644
--- a/include/uapi/sound/asound.h
+++ b/include/uapi/sound/asound.h
@@ -96,9 +96,10 @@ enum {
SNDRV_HWDEP_IFACE_FW_DICE, /* TC DICE FireWire device */
SNDRV_HWDEP_IFACE_FW_FIREWORKS, /* Echo Audio Fireworks based device */
SNDRV_HWDEP_IFACE_FW_BEBOB, /* BridgeCo BeBoB based device */
+ SNDRV_HWDEP_IFACE_FW_OXFW, /* Oxford OXFW970/971 based device */
/* Don't forget to change the following: */
- SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_BEBOB
+ SNDRV_HWDEP_IFACE_LAST = SNDRV_HWDEP_IFACE_FW_OXFW
};
struct snd_hwdep_info {
diff --git a/include/uapi/sound/compress_offload.h b/include/uapi/sound/compress_offload.h
index 1964026..22ed8cb 100644
--- a/include/uapi/sound/compress_offload.h
+++ b/include/uapi/sound/compress_offload.h
@@ -32,7 +32,7 @@
#define SNDRV_COMPRESS_VERSION SNDRV_PROTOCOL_VERSION(0, 1, 2)
/**
- * struct snd_compressed_buffer: compressed buffer
+ * struct snd_compressed_buffer - compressed buffer
* @fragment_size: size of buffer fragment in bytes
* @fragments: number of such fragments
*/
@@ -42,7 +42,7 @@ struct snd_compressed_buffer {
} __attribute__((packed, aligned(4)));
/**
- * struct snd_compr_params: compressed stream params
+ * struct snd_compr_params - compressed stream params
* @buffer: buffer description
* @codec: codec parameters
* @no_wake_mode: dont wake on fragment elapsed
@@ -54,7 +54,7 @@ struct snd_compr_params {
} __attribute__((packed, aligned(4)));
/**
- * struct snd_compr_tstamp: timestamp descriptor
+ * struct snd_compr_tstamp - timestamp descriptor
* @byte_offset: Byte offset in ring buffer to DSP
* @copied_total: Total number of bytes copied from/to ring buffer to/by DSP
* @pcm_frames: Frames decoded or encoded by DSP. This field will evolve by
@@ -73,7 +73,7 @@ struct snd_compr_tstamp {
} __attribute__((packed, aligned(4)));
/**
- * struct snd_compr_avail: avail descriptor
+ * struct snd_compr_avail - avail descriptor
* @avail: Number of bytes available in ring buffer for writing/reading
* @tstamp: timestamp infomation
*/
@@ -88,7 +88,7 @@ enum snd_compr_direction {
};
/**
- * struct snd_compr_caps: caps descriptor
+ * struct snd_compr_caps - caps descriptor
* @codecs: pointer to array of codecs
* @direction: direction supported. Of type snd_compr_direction
* @min_fragment_size: minimum fragment supported by DSP
@@ -110,7 +110,7 @@ struct snd_compr_caps {
} __attribute__((packed, aligned(4)));
/**
- * struct snd_compr_codec_caps: query capability of codec
+ * struct snd_compr_codec_caps - query capability of codec
* @codec: codec for which capability is queried
* @num_descriptors: number of codec descriptors
* @descriptor: array of codec capability descriptor
@@ -122,18 +122,19 @@ struct snd_compr_codec_caps {
} __attribute__((packed, aligned(4)));
/**
+ * enum sndrv_compress_encoder
* @SNDRV_COMPRESS_ENCODER_PADDING: no of samples appended by the encoder at the
* end of the track
* @SNDRV_COMPRESS_ENCODER_DELAY: no of samples inserted by the encoder at the
* beginning of the track
*/
-enum {
+enum sndrv_compress_encoder {
SNDRV_COMPRESS_ENCODER_PADDING = 1,
SNDRV_COMPRESS_ENCODER_DELAY = 2,
};
/**
- * struct snd_compr_metadata: compressed stream metadata
+ * struct snd_compr_metadata - compressed stream metadata
* @key: key id
* @value: key value
*/
diff --git a/include/uapi/sound/firewire.h b/include/uapi/sound/firewire.h
index af4bd13..49122df 100644
--- a/include/uapi/sound/firewire.h
+++ b/include/uapi/sound/firewire.h
@@ -55,7 +55,8 @@ union snd_firewire_event {
#define SNDRV_FIREWIRE_TYPE_DICE 1
#define SNDRV_FIREWIRE_TYPE_FIREWORKS 2
#define SNDRV_FIREWIRE_TYPE_BEBOB 3
-/* AV/C, RME, MOTU, ... */
+#define SNDRV_FIREWIRE_TYPE_OXFW 4
+/* RME, MOTU, ... */
struct snd_firewire_get_info {
unsigned int type; /* SNDRV_FIREWIRE_TYPE_xxx */
diff --git a/include/uapi/sound/hdspm.h b/include/uapi/sound/hdspm.h
index d956c35..b357f1a5 100644
--- a/include/uapi/sound/hdspm.h
+++ b/include/uapi/sound/hdspm.h
@@ -74,14 +74,14 @@ struct hdspm_config {
#define SNDRV_HDSPM_IOCTL_GET_CONFIG \
_IOR('H', 0x41, struct hdspm_config)
-/**
+/*
* If there's a TCO (TimeCode Option) board installed,
* there are further options and status data available.
* The hdspm_ltc structure contains the current SMPTE
* timecode and some status information and can be
* obtained via SNDRV_HDSPM_IOCTL_GET_LTC or in the
* hdspm_status struct.
- **/
+ */
enum hdspm_ltc_format {
format_invalid,
@@ -113,11 +113,11 @@ struct hdspm_ltc {
#define SNDRV_HDSPM_IOCTL_GET_LTC _IOR('H', 0x46, struct hdspm_ltc)
-/**
+/*
* The status data reflects the device's current state
* as determined by the card's configuration and
* connection status.
- **/
+ */
enum hdspm_sync {
hdspm_sync_no_lock = 0,
@@ -171,9 +171,9 @@ struct hdspm_status {
#define SNDRV_HDSPM_IOCTL_GET_STATUS \
_IOR('H', 0x47, struct hdspm_status)
-/**
+/*
* Get information about the card and its add-ons.
- **/
+ */
#define HDSPM_ADDON_TCO 1
diff --git a/include/video/omapdss.h b/include/video/omapdss.h
index 069dfca..6a84498 100644
--- a/include/video/omapdss.h
+++ b/include/video/omapdss.h
@@ -166,13 +166,6 @@ enum omap_dss_display_state {
OMAP_DSS_DISPLAY_ACTIVE,
};
-enum omap_dss_audio_state {
- OMAP_DSS_AUDIO_DISABLED = 0,
- OMAP_DSS_AUDIO_ENABLED,
- OMAP_DSS_AUDIO_CONFIGURED,
- OMAP_DSS_AUDIO_PLAYING,
-};
-
struct omap_dss_audio {
struct snd_aes_iec958 *iec;
struct snd_cea_861_aud_if *cea;
@@ -635,19 +628,6 @@ struct omapdss_hdmi_ops {
int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
int (*set_infoframe)(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi);
-
- /*
- * Note: These functions might sleep. Do not call while
- * holding a spinlock/readlock.
- */
- int (*audio_enable)(struct omap_dss_device *dssdev);
- void (*audio_disable)(struct omap_dss_device *dssdev);
- bool (*audio_supported)(struct omap_dss_device *dssdev);
- int (*audio_config)(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio);
- /* Note: These functions may not sleep */
- int (*audio_start)(struct omap_dss_device *dssdev);
- void (*audio_stop)(struct omap_dss_device *dssdev);
};
struct omapdss_dsi_ops {
@@ -783,8 +763,6 @@ struct omap_dss_device {
enum omap_dss_display_state state;
- enum omap_dss_audio_state audio_state;
-
/* OMAP DSS output specific fields */
struct list_head list;
@@ -795,6 +773,9 @@ struct omap_dss_device {
/* output instance */
enum omap_dss_output_id id;
+ /* the port number in the DT node */
+ int port_num;
+
/* dynamic fields */
struct omap_overlay_manager *manager;
@@ -858,24 +839,6 @@ struct omap_dss_driver {
int (*set_hdmi_mode)(struct omap_dss_device *dssdev, bool hdmi_mode);
int (*set_hdmi_infoframe)(struct omap_dss_device *dssdev,
const struct hdmi_avi_infoframe *avi);
-
- /*
- * For display drivers that support audio. This encompasses
- * HDMI and DisplayPort at the moment.
- */
- /*
- * Note: These functions might sleep. Do not call while
- * holding a spinlock/readlock.
- */
- int (*audio_enable)(struct omap_dss_device *dssdev);
- void (*audio_disable)(struct omap_dss_device *dssdev);
- bool (*audio_supported)(struct omap_dss_device *dssdev);
- int (*audio_config)(struct omap_dss_device *dssdev,
- struct omap_dss_audio *audio);
- /* Note: These functions may not sleep */
- int (*audio_start)(struct omap_dss_device *dssdev);
- void (*audio_stop)(struct omap_dss_device *dssdev);
-
};
enum omapdss_version omapdss_get_version(void);
@@ -918,7 +881,7 @@ int omapdss_register_output(struct omap_dss_device *output);
void omapdss_unregister_output(struct omap_dss_device *output);
struct omap_dss_device *omap_dss_get_output(enum omap_dss_output_id id);
struct omap_dss_device *omap_dss_find_output(const char *name);
-struct omap_dss_device *omap_dss_find_output_by_node(struct device_node *node);
+struct omap_dss_device *omap_dss_find_output_by_port_node(struct device_node *port);
int omapdss_output_set_device(struct omap_dss_device *out,
struct omap_dss_device *dssdev);
int omapdss_output_unset_device(struct omap_dss_device *out);
diff --git a/init/Kconfig b/init/Kconfig
index 2081a4d..9afb971 100644
--- a/init/Kconfig
+++ b/init/Kconfig
@@ -477,7 +477,7 @@ config TREE_RCU
thousands of CPUs. It also scales down nicely to
smaller systems.
-config TREE_PREEMPT_RCU
+config PREEMPT_RCU
bool "Preemptible tree-based hierarchical RCU"
depends on PREEMPT
select IRQ_WORK
@@ -501,12 +501,6 @@ config TINY_RCU
endchoice
-config PREEMPT_RCU
- def_bool TREE_PREEMPT_RCU
- help
- This option enables preemptible-RCU code that is common between
- TREE_PREEMPT_RCU and, in the old days, TINY_PREEMPT_RCU.
-
config TASKS_RCU
bool "Task_based RCU implementation using voluntary context switch"
default n
@@ -518,7 +512,7 @@ config TASKS_RCU
If unsure, say N.
config RCU_STALL_COMMON
- def_bool ( TREE_RCU || TREE_PREEMPT_RCU || RCU_TRACE )
+ def_bool ( TREE_RCU || PREEMPT_RCU || RCU_TRACE )
help
This option enables RCU CPU stall code that is common between
the TINY and TREE variants of RCU. The purpose is to allow
@@ -576,7 +570,7 @@ config RCU_FANOUT
int "Tree-based hierarchical RCU fanout value"
range 2 64 if 64BIT
range 2 32 if !64BIT
- depends on TREE_RCU || TREE_PREEMPT_RCU
+ depends on TREE_RCU || PREEMPT_RCU
default 64 if 64BIT
default 32 if !64BIT
help
@@ -596,7 +590,7 @@ config RCU_FANOUT_LEAF
int "Tree-based hierarchical RCU leaf-level fanout value"
range 2 RCU_FANOUT if 64BIT
range 2 RCU_FANOUT if !64BIT
- depends on TREE_RCU || TREE_PREEMPT_RCU
+ depends on TREE_RCU || PREEMPT_RCU
default 16
help
This option controls the leaf-level fanout of hierarchical
@@ -621,7 +615,7 @@ config RCU_FANOUT_LEAF
config RCU_FANOUT_EXACT
bool "Disable tree-based hierarchical RCU auto-balancing"
- depends on TREE_RCU || TREE_PREEMPT_RCU
+ depends on TREE_RCU || PREEMPT_RCU
default n
help
This option forces use of the exact RCU_FANOUT value specified,
@@ -652,11 +646,11 @@ config RCU_FAST_NO_HZ
Say N if you are unsure.
config TREE_RCU_TRACE
- def_bool RCU_TRACE && ( TREE_RCU || TREE_PREEMPT_RCU )
+ def_bool RCU_TRACE && ( TREE_RCU || PREEMPT_RCU )
select DEBUG_FS
help
This option provides tracing for the TREE_RCU and
- TREE_PREEMPT_RCU implementations, permitting Makefile to
+ PREEMPT_RCU implementations, permitting Makefile to
trivially select kernel/rcutree_trace.c.
config RCU_BOOST
@@ -672,30 +666,31 @@ config RCU_BOOST
Say Y here if you are working with real-time apps or heavy loads
Say N here if you are unsure.
-config RCU_BOOST_PRIO
- int "Real-time priority to boost RCU readers to"
+config RCU_KTHREAD_PRIO
+ int "Real-time priority to use for RCU worker threads"
range 1 99
depends on RCU_BOOST
default 1
help
- This option specifies the real-time priority to which long-term
- preempted RCU readers are to be boosted. If you are working
- with a real-time application that has one or more CPU-bound
- threads running at a real-time priority level, you should set
- RCU_BOOST_PRIO to a priority higher then the highest-priority
- real-time CPU-bound thread. The default RCU_BOOST_PRIO value
- of 1 is appropriate in the common case, which is real-time
+ This option specifies the SCHED_FIFO priority value that will be
+ assigned to the rcuc/n and rcub/n threads and is also the value
+ used for RCU_BOOST (if enabled). If you are working with a
+ real-time application that has one or more CPU-bound threads
+ running at a real-time priority level, you should set
+ RCU_KTHREAD_PRIO to a priority higher than the highest-priority
+ real-time CPU-bound application thread. The default RCU_KTHREAD_PRIO
+ value of 1 is appropriate in the common case, which is real-time
applications that do not have any CPU-bound threads.
Some real-time applications might not have a single real-time
thread that saturates a given CPU, but instead might have
multiple real-time threads that, taken together, fully utilize
- that CPU. In this case, you should set RCU_BOOST_PRIO to
+ that CPU. In this case, you should set RCU_KTHREAD_PRIO to
a priority higher than the lowest-priority thread that is
conspiring to prevent the CPU from running any non-real-time
tasks. For example, if one thread at priority 10 and another
thread at priority 5 are between themselves fully consuming
- the CPU time on a given CPU, then RCU_BOOST_PRIO should be
+ the CPU time on a given CPU, then RCU_KTHREAD_PRIO should be
set to priority 6 or higher.
Specify the real-time priority, or take the default if unsure.
@@ -715,7 +710,7 @@ config RCU_BOOST_DELAY
config RCU_NOCB_CPU
bool "Offload RCU callback processing from boot-selected CPUs"
- depends on TREE_RCU || TREE_PREEMPT_RCU
+ depends on TREE_RCU || PREEMPT_RCU
default n
help
Use this option to reduce OS jitter for aggressive HPC or
@@ -739,6 +734,7 @@ config RCU_NOCB_CPU
choice
prompt "Build-forced no-CBs CPUs"
default RCU_NOCB_CPU_NONE
+ depends on RCU_NOCB_CPU
help
This option allows no-CBs CPUs (whose RCU callbacks are invoked
from kthreads rather than from softirq context) to be specified
@@ -747,7 +743,6 @@ choice
config RCU_NOCB_CPU_NONE
bool "No build_forced no-CBs CPUs"
- depends on RCU_NOCB_CPU
help
This option does not force any of the CPUs to be no-CBs CPUs.
Only CPUs designated by the rcu_nocbs= boot parameter will be
@@ -761,7 +756,6 @@ config RCU_NOCB_CPU_NONE
config RCU_NOCB_CPU_ZERO
bool "CPU 0 is a build_forced no-CBs CPU"
- depends on RCU_NOCB_CPU
help
This option forces CPU 0 to be a no-CBs CPU, so that its RCU
callbacks are invoked by a per-CPU kthread whose name begins
@@ -776,7 +770,6 @@ config RCU_NOCB_CPU_ZERO
config RCU_NOCB_CPU_ALL
bool "All CPUs are build_forced no-CBs CPUs"
- depends on RCU_NOCB_CPU
help
This option forces all CPUs to be no-CBs CPUs. The rcu_nocbs=
boot parameter will be ignored. All CPUs' RCU callbacks will
@@ -900,14 +893,6 @@ config ARCH_SUPPORTS_INT128
config ARCH_WANT_NUMA_VARIABLE_LOCALITY
bool
-config NUMA_BALANCING_DEFAULT_ENABLED
- bool "Automatically enable NUMA aware memory/task placement"
- default y
- depends on NUMA_BALANCING
- help
- If set, automatic NUMA balancing will be enabled if running on a NUMA
- machine.
-
config NUMA_BALANCING
bool "Memory placement aware NUMA scheduler"
depends on ARCH_SUPPORTS_NUMA_BALANCING
@@ -920,6 +905,14 @@ config NUMA_BALANCING
This system will be inactive on UMA systems.
+config NUMA_BALANCING_DEFAULT_ENABLED
+ bool "Automatically enable NUMA aware memory/task placement"
+ default y
+ depends on NUMA_BALANCING
+ help
+ If set, automatic NUMA balancing will be enabled if running on a NUMA
+ machine.
+
menuconfig CGROUPS
boolean "Control Group support"
select KERNFS
@@ -979,32 +972,17 @@ config CGROUP_CPUACCT
Provides a simple Resource Controller for monitoring the
total CPU consumed by the tasks in a cgroup.
-config RESOURCE_COUNTERS
- bool "Resource counters"
- help
- This option enables controller independent resource accounting
- infrastructure that works with cgroups.
+config PAGE_COUNTER
+ bool
config MEMCG
bool "Memory Resource Controller for Control Groups"
- depends on RESOURCE_COUNTERS
+ select PAGE_COUNTER
select EVENTFD
help
Provides a memory resource controller that manages both anonymous
memory and page cache. (See Documentation/cgroups/memory.txt)
- Note that setting this option increases fixed memory overhead
- associated with each page of memory in the system. By this,
- 8(16)bytes/PAGE_SIZE on 32(64)bit system will be occupied by memory
- usage tracking struct at boot. Total amount of this is printed out
- at boot.
-
- Only enable when you're ok with these trade offs and really
- sure you need the memory resource controller. Even when you enable
- this, you can set "cgroup_disable=memory" at your boot option to
- disable memory resource controller and you can avoid overheads.
- (and lose benefits of memory resource controller)
-
config MEMCG_SWAP
bool "Memory Resource Controller Swap Extension"
depends on MEMCG && SWAP
@@ -1055,7 +1033,8 @@ config MEMCG_KMEM
config CGROUP_HUGETLB
bool "HugeTLB Resource Controller for Control Groups"
- depends on RESOURCE_COUNTERS && HUGETLB_PAGE
+ depends on HUGETLB_PAGE
+ select PAGE_COUNTER
default n
help
Provides a cgroup Resource Controller for HugeTLB pages.
@@ -1301,6 +1280,22 @@ source "usr/Kconfig"
endif
+config INIT_FALLBACK
+ bool "Fall back to defaults if init= parameter is bad"
+ default y
+ help
+ If enabled, the kernel will try the default init binaries if an
+ explicit request from the init= parameter fails.
+
+ This can have unexpected effects. For example, booting
+ with init=/sbin/kiosk_app will run /sbin/init or even /bin/sh
+ if /sbin/kiosk_app cannot be executed.
+
+ The default value of Y is consistent with historical behavior.
+ Selecting N is likely to be more appropriate for most uses,
+ especially on kiosks and on kernels that are intended to be
+ run under the control of a script.
+
config CC_OPTIMIZE_FOR_SIZE
bool "Optimize for size"
help
diff --git a/init/main.c b/init/main.c
index 321d0ce..ca380ec 100644
--- a/init/main.c
+++ b/init/main.c
@@ -51,7 +51,6 @@
#include <linux/mempolicy.h>
#include <linux/key.h>
#include <linux/buffer_head.h>
-#include <linux/page_cgroup.h>
#include <linux/debug_locks.h>
#include <linux/debugobjects.h>
#include <linux/lockdep.h>
@@ -485,11 +484,6 @@ void __init __weak thread_info_cache_init(void)
*/
static void __init mm_init(void)
{
- /*
- * page_cgroup requires contiguous pages,
- * bigger than MAX_ORDER unless SPARSEMEM.
- */
- page_cgroup_init_flatmem();
mem_init();
kmem_cache_init();
percpu_init_late();
@@ -627,7 +621,6 @@ asmlinkage __visible void __init start_kernel(void)
initrd_start = 0;
}
#endif
- page_cgroup_init();
debug_objects_mem_init();
kmemleak_init();
setup_per_cpu_pageset();
@@ -959,8 +952,13 @@ static int __ref kernel_init(void *unused)
ret = run_init_process(execute_command);
if (!ret)
return 0;
+#ifndef CONFIG_INIT_FALLBACK
+ panic("Requested init %s failed (error %d).",
+ execute_command, ret);
+#else
pr_err("Failed to execute %s (error %d). Attempting defaults...\n",
- execute_command, ret);
+ execute_command, ret);
+#endif
}
if (!try_to_run_init_process("/sbin/init") ||
!try_to_run_init_process("/etc/init") ||
diff --git a/ipc/mqueue.c b/ipc/mqueue.c
index 4fcf39a..7635a1c 100644
--- a/ipc/mqueue.c
+++ b/ipc/mqueue.c
@@ -990,7 +990,7 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
goto out_fput;
}
info = MQUEUE_I(inode);
- audit_inode(NULL, f.file->f_path.dentry, 0);
+ audit_file(f.file);
if (unlikely(!(f.file->f_mode & FMODE_WRITE))) {
ret = -EBADF;
@@ -1106,7 +1106,7 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
goto out_fput;
}
info = MQUEUE_I(inode);
- audit_inode(NULL, f.file->f_path.dentry, 0);
+ audit_file(f.file);
if (unlikely(!(f.file->f_mode & FMODE_READ))) {
ret = -EBADF;
diff --git a/kernel/Makefile b/kernel/Makefile
index 17ea6d4..a59481a 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -57,7 +57,6 @@ obj-$(CONFIG_UTS_NS) += utsname.o
obj-$(CONFIG_USER_NS) += user_namespace.o
obj-$(CONFIG_PID_NS) += pid_namespace.o
obj-$(CONFIG_IKCONFIG) += configs.o
-obj-$(CONFIG_RESOURCE_COUNTERS) += res_counter.o
obj-$(CONFIG_SMP) += stop_machine.o
obj-$(CONFIG_KPROBES_SANITY_TEST) += test_kprobes.o
obj-$(CONFIG_AUDIT) += audit.o auditfilter.o
diff --git a/kernel/audit.c b/kernel/audit.c
index cebb11d..1f37f151 100644
--- a/kernel/audit.c
+++ b/kernel/audit.c
@@ -499,7 +499,6 @@ static int kauditd_thread(void *dummy)
set_freezable();
while (!kthread_should_stop()) {
struct sk_buff *skb;
- DECLARE_WAITQUEUE(wait, current);
flush_hold_queue();
@@ -514,16 +513,8 @@ static int kauditd_thread(void *dummy)
audit_printk_skb(skb);
continue;
}
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&kauditd_wait, &wait);
- if (!skb_queue_len(&audit_skb_queue)) {
- try_to_freeze();
- schedule();
- }
-
- __set_current_state(TASK_RUNNING);
- remove_wait_queue(&kauditd_wait, &wait);
+ wait_event_freezable(kauditd_wait, skb_queue_len(&audit_skb_queue));
}
return 0;
}
diff --git a/kernel/auditsc.c b/kernel/auditsc.c
index e420a0c..c75522a 100644
--- a/kernel/auditsc.c
+++ b/kernel/auditsc.c
@@ -1897,6 +1897,11 @@ out:
audit_copy_inode(n, dentry, inode);
}
+void __audit_file(const struct file *file)
+{
+ __audit_inode(NULL, file->f_path.dentry, 0);
+}
+
/**
* __audit_inode_child - collect inode info for created/removed objects
* @parent: inode of dentry parent
@@ -2373,7 +2378,7 @@ int __audit_log_bprm_fcaps(struct linux_binprm *bprm,
ax->d.next = context->aux;
context->aux = (void *)ax;
- dentry = dget(bprm->file->f_dentry);
+ dentry = dget(bprm->file->f_path.dentry);
get_vfs_caps_from_disk(dentry, &vcaps);
dput(dentry);
diff --git a/kernel/cpu.c b/kernel/cpu.c
index 90a3d01..5d22023 100644
--- a/kernel/cpu.c
+++ b/kernel/cpu.c
@@ -86,6 +86,16 @@ static struct {
#define cpuhp_lock_acquire() lock_map_acquire(&cpu_hotplug.dep_map)
#define cpuhp_lock_release() lock_map_release(&cpu_hotplug.dep_map)
+static void apply_puts_pending(int max)
+{
+ int delta;
+
+ if (atomic_read(&cpu_hotplug.puts_pending) >= max) {
+ delta = atomic_xchg(&cpu_hotplug.puts_pending, 0);
+ cpu_hotplug.refcount -= delta;
+ }
+}
+
void get_online_cpus(void)
{
might_sleep();
@@ -93,6 +103,7 @@ void get_online_cpus(void)
return;
cpuhp_lock_acquire_read();
mutex_lock(&cpu_hotplug.lock);
+ apply_puts_pending(65536);
cpu_hotplug.refcount++;
mutex_unlock(&cpu_hotplug.lock);
}
@@ -105,6 +116,7 @@ bool try_get_online_cpus(void)
if (!mutex_trylock(&cpu_hotplug.lock))
return false;
cpuhp_lock_acquire_tryread();
+ apply_puts_pending(65536);
cpu_hotplug.refcount++;
mutex_unlock(&cpu_hotplug.lock);
return true;
@@ -161,12 +173,7 @@ void cpu_hotplug_begin(void)
cpuhp_lock_acquire();
for (;;) {
mutex_lock(&cpu_hotplug.lock);
- if (atomic_read(&cpu_hotplug.puts_pending)) {
- int delta;
-
- delta = atomic_xchg(&cpu_hotplug.puts_pending, 0);
- cpu_hotplug.refcount -= delta;
- }
+ apply_puts_pending(1);
if (likely(!cpu_hotplug.refcount))
break;
__set_current_state(TASK_UNINTERRUPTIBLE);
diff --git a/kernel/cpuset.c b/kernel/cpuset.c
index 1f107c7..723cfc9 100644
--- a/kernel/cpuset.c
+++ b/kernel/cpuset.c
@@ -506,6 +506,16 @@ static int validate_change(struct cpuset *cur, struct cpuset *trial)
goto out;
}
+ /*
+ * We can't shrink if we won't have enough room for SCHED_DEADLINE
+ * tasks.
+ */
+ ret = -EBUSY;
+ if (is_cpu_exclusive(cur) &&
+ !cpuset_cpumask_can_shrink(cur->cpus_allowed,
+ trial->cpus_allowed))
+ goto out;
+
ret = 0;
out:
rcu_read_unlock();
@@ -1429,17 +1439,8 @@ static int cpuset_can_attach(struct cgroup_subsys_state *css,
goto out_unlock;
cgroup_taskset_for_each(task, tset) {
- /*
- * Kthreads which disallow setaffinity shouldn't be moved
- * to a new cpuset; we don't want to change their cpu
- * affinity and isolating such threads by their set of
- * allowed nodes is unnecessary. Thus, cpusets are not
- * applicable for such threads. This prevents checking for
- * success of set_cpus_allowed_ptr() on all attached tasks
- * before cpus_allowed may be changed.
- */
- ret = -EINVAL;
- if (task->flags & PF_NO_SETAFFINITY)
+ ret = task_can_attach(task, cs->cpus_allowed);
+ if (ret)
goto out_unlock;
ret = security_task_setscheduler(task);
if (ret)
diff --git a/kernel/events/core.c b/kernel/events/core.c
index 1cd5eef..113b837 100644
--- a/kernel/events/core.c
+++ b/kernel/events/core.c
@@ -614,7 +614,7 @@ static inline int perf_cgroup_connect(int fd, struct perf_event *event,
if (!f.file)
return -EBADF;
- css = css_tryget_online_from_dir(f.file->f_dentry,
+ css = css_tryget_online_from_dir(f.file->f_path.dentry,
&perf_event_cgrp_subsys);
if (IS_ERR(css)) {
ret = PTR_ERR(css);
@@ -4460,7 +4460,7 @@ perf_output_sample_regs(struct perf_output_handle *handle,
}
}
-static void perf_sample_regs_user(struct perf_regs_user *regs_user,
+static void perf_sample_regs_user(struct perf_regs *regs_user,
struct pt_regs *regs)
{
if (!user_mode(regs)) {
@@ -4471,11 +4471,22 @@ static void perf_sample_regs_user(struct perf_regs_user *regs_user,
}
if (regs) {
- regs_user->regs = regs;
regs_user->abi = perf_reg_abi(current);
+ regs_user->regs = regs;
+ } else {
+ regs_user->abi = PERF_SAMPLE_REGS_ABI_NONE;
+ regs_user->regs = NULL;
}
}
+static void perf_sample_regs_intr(struct perf_regs *regs_intr,
+ struct pt_regs *regs)
+{
+ regs_intr->regs = regs;
+ regs_intr->abi = perf_reg_abi(current);
+}
+
+
/*
* Get remaining task size from user stack pointer.
*
@@ -4857,6 +4868,23 @@ void perf_output_sample(struct perf_output_handle *handle,
if (sample_type & PERF_SAMPLE_TRANSACTION)
perf_output_put(handle, data->txn);
+ if (sample_type & PERF_SAMPLE_REGS_INTR) {
+ u64 abi = data->regs_intr.abi;
+ /*
+ * If there are no regs to dump, notice it through
+ * first u64 being zero (PERF_SAMPLE_REGS_ABI_NONE).
+ */
+ perf_output_put(handle, abi);
+
+ if (abi) {
+ u64 mask = event->attr.sample_regs_intr;
+
+ perf_output_sample_regs(handle,
+ data->regs_intr.regs,
+ mask);
+ }
+ }
+
if (!event->attr.watermark) {
int wakeup_events = event->attr.wakeup_events;
@@ -4922,12 +4950,13 @@ void perf_prepare_sample(struct perf_event_header *header,
header->size += size;
}
+ if (sample_type & (PERF_SAMPLE_REGS_USER | PERF_SAMPLE_STACK_USER))
+ perf_sample_regs_user(&data->regs_user, regs);
+
if (sample_type & PERF_SAMPLE_REGS_USER) {
/* regs dump ABI info */
int size = sizeof(u64);
- perf_sample_regs_user(&data->regs_user, regs);
-
if (data->regs_user.regs) {
u64 mask = event->attr.sample_regs_user;
size += hweight64(mask) * sizeof(u64);
@@ -4943,15 +4972,11 @@ void perf_prepare_sample(struct perf_event_header *header,
* in case new sample type is added, because we could eat
* up the rest of the sample size.
*/
- struct perf_regs_user *uregs = &data->regs_user;
u16 stack_size = event->attr.sample_stack_user;
u16 size = sizeof(u64);
- if (!uregs->abi)
- perf_sample_regs_user(uregs, regs);
-
stack_size = perf_sample_ustack_size(stack_size, header->size,
- uregs->regs);
+ data->regs_user.regs);
/*
* If there is something to dump, add space for the dump
@@ -4964,6 +4989,21 @@ void perf_prepare_sample(struct perf_event_header *header,
data->stack_user_size = stack_size;
header->size += size;
}
+
+ if (sample_type & PERF_SAMPLE_REGS_INTR) {
+ /* regs dump ABI info */
+ int size = sizeof(u64);
+
+ perf_sample_regs_intr(&data->regs_intr, regs);
+
+ if (data->regs_intr.regs) {
+ u64 mask = event->attr.sample_regs_intr;
+
+ size += hweight64(mask) * sizeof(u64);
+ }
+
+ header->size += size;
+ }
}
static void perf_event_output(struct perf_event *event,
@@ -7151,6 +7191,8 @@ static int perf_copy_attr(struct perf_event_attr __user *uattr,
ret = -EINVAL;
}
+ if (attr->sample_type & PERF_SAMPLE_REGS_INTR)
+ ret = perf_reg_validate(attr->sample_regs_intr);
out:
return ret;
diff --git a/kernel/exit.c b/kernel/exit.c
index 5d30019..8714e5d 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -118,13 +118,10 @@ static void __exit_signal(struct task_struct *tsk)
}
/*
- * Accumulate here the counters for all threads but the group leader
- * as they die, so they can be added into the process-wide totals
- * when those are taken. The group leader stays around as a zombie as
- * long as there are other threads. When it gets reaped, the exit.c
- * code will add its counts into these totals. We won't ever get here
- * for the group leader, since it will have been the last reference on
- * the signal_struct.
+ * Accumulate here the counters for all threads as they die. We could
+ * skip the group leader because it is the last user of signal_struct,
+ * but we want to avoid the race with thread_group_cputime() which can
+ * see the empty ->thread_head list.
*/
task_cputime(tsk, &utime, &stime);
write_seqlock(&sig->stats_lock);
@@ -462,6 +459,44 @@ static void exit_mm(struct task_struct *tsk)
clear_thread_flag(TIF_MEMDIE);
}
+static struct task_struct *find_alive_thread(struct task_struct *p)
+{
+ struct task_struct *t;
+
+ for_each_thread(p, t) {
+ if (!(t->flags & PF_EXITING))
+ return t;
+ }
+ return NULL;
+}
+
+static struct task_struct *find_child_reaper(struct task_struct *father)
+ __releases(&tasklist_lock)
+ __acquires(&tasklist_lock)
+{
+ struct pid_namespace *pid_ns = task_active_pid_ns(father);
+ struct task_struct *reaper = pid_ns->child_reaper;
+
+ if (likely(reaper != father))
+ return reaper;
+
+ reaper = find_alive_thread(father);
+ if (reaper) {
+ pid_ns->child_reaper = reaper;
+ return reaper;
+ }
+
+ write_unlock_irq(&tasklist_lock);
+ if (unlikely(pid_ns == &init_pid_ns)) {
+ panic("Attempted to kill init! exitcode=0x%08x\n",
+ father->signal->group_exit_code ?: father->exit_code);
+ }
+ zap_pid_ns_processes(pid_ns);
+ write_lock_irq(&tasklist_lock);
+
+ return father;
+}
+
/*
* When we die, we re-parent all our children, and try to:
* 1. give them to another thread in our thread group, if such a member exists
@@ -469,58 +504,36 @@ static void exit_mm(struct task_struct *tsk)
* child_subreaper for its children (like a service manager)
* 3. give it to the init process (PID 1) in our pid namespace
*/
-static struct task_struct *find_new_reaper(struct task_struct *father)
- __releases(&tasklist_lock)
- __acquires(&tasklist_lock)
+static struct task_struct *find_new_reaper(struct task_struct *father,
+ struct task_struct *child_reaper)
{
- struct pid_namespace *pid_ns = task_active_pid_ns(father);
- struct task_struct *thread;
+ struct task_struct *thread, *reaper;
- thread = father;
- while_each_thread(father, thread) {
- if (thread->flags & PF_EXITING)
- continue;
- if (unlikely(pid_ns->child_reaper == father))
- pid_ns->child_reaper = thread;
+ thread = find_alive_thread(father);
+ if (thread)
return thread;
- }
-
- if (unlikely(pid_ns->child_reaper == father)) {
- write_unlock_irq(&tasklist_lock);
- if (unlikely(pid_ns == &init_pid_ns)) {
- panic("Attempted to kill init! exitcode=0x%08x\n",
- father->signal->group_exit_code ?:
- father->exit_code);
- }
-
- zap_pid_ns_processes(pid_ns);
- write_lock_irq(&tasklist_lock);
- } else if (father->signal->has_child_subreaper) {
- struct task_struct *reaper;
+ if (father->signal->has_child_subreaper) {
/*
- * Find the first ancestor marked as child_subreaper.
- * Note that the code below checks same_thread_group(reaper,
- * pid_ns->child_reaper). This is what we need to DTRT in a
- * PID namespace. However we still need the check above, see
- * http://marc.info/?l=linux-kernel&m=131385460420380
+ * Find the first ->is_child_subreaper ancestor in our pid_ns.
+ * We start from father to ensure we can not look into another
+ * namespace, this is safe because all its threads are dead.
*/
- for (reaper = father->real_parent;
- reaper != &init_task;
+ for (reaper = father;
+ !same_thread_group(reaper, child_reaper);
reaper = reaper->real_parent) {
- if (same_thread_group(reaper, pid_ns->child_reaper))
+ /* call_usermodehelper() descendants need this check */
+ if (reaper == &init_task)
break;
if (!reaper->signal->is_child_subreaper)
continue;
- thread = reaper;
- do {
- if (!(thread->flags & PF_EXITING))
- return reaper;
- } while_each_thread(reaper, thread);
+ thread = find_alive_thread(reaper);
+ if (thread)
+ return thread;
}
}
- return pid_ns->child_reaper;
+ return child_reaper;
}
/*
@@ -529,15 +542,7 @@ static struct task_struct *find_new_reaper(struct task_struct *father)
static void reparent_leader(struct task_struct *father, struct task_struct *p,
struct list_head *dead)
{
- list_move_tail(&p->sibling, &p->real_parent->children);
-
- if (p->exit_state == EXIT_DEAD)
- return;
- /*
- * If this is a threaded reparent there is no need to
- * notify anyone anything has happened.
- */
- if (same_thread_group(p->real_parent, father))
+ if (unlikely(p->exit_state == EXIT_DEAD))
return;
/* We don't want people slaying init. */
@@ -548,49 +553,53 @@ static void reparent_leader(struct task_struct *father, struct task_struct *p,
p->exit_state == EXIT_ZOMBIE && thread_group_empty(p)) {
if (do_notify_parent(p, p->exit_signal)) {
p->exit_state = EXIT_DEAD;
- list_move_tail(&p->sibling, dead);
+ list_add(&p->ptrace_entry, dead);
}
}
kill_orphaned_pgrp(p, father);
}
-static void forget_original_parent(struct task_struct *father)
+/*
+ * This does two things:
+ *
+ * A. Make init inherit all the child processes
+ * B. Check to see if any process groups have become orphaned
+ * as a result of our exiting, and if they have any stopped
+ * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
+ */
+static void forget_original_parent(struct task_struct *father,
+ struct list_head *dead)
{
- struct task_struct *p, *n, *reaper;
- LIST_HEAD(dead_children);
+ struct task_struct *p, *t, *reaper;
- write_lock_irq(&tasklist_lock);
- /*
- * Note that exit_ptrace() and find_new_reaper() might
- * drop tasklist_lock and reacquire it.
- */
- exit_ptrace(father);
- reaper = find_new_reaper(father);
+ if (unlikely(!list_empty(&father->ptraced)))
+ exit_ptrace(father, dead);
- list_for_each_entry_safe(p, n, &father->children, sibling) {
- struct task_struct *t = p;
+ /* Can drop and reacquire tasklist_lock */
+ reaper = find_child_reaper(father);
+ if (list_empty(&father->children))
+ return;
- do {
+ reaper = find_new_reaper(father, reaper);
+ list_for_each_entry(p, &father->children, sibling) {
+ for_each_thread(p, t) {
t->real_parent = reaper;
- if (t->parent == father) {
- BUG_ON(t->ptrace);
+ BUG_ON((!t->ptrace) != (t->parent == father));
+ if (likely(!t->ptrace))
t->parent = t->real_parent;
- }
if (t->pdeath_signal)
group_send_sig_info(t->pdeath_signal,
SEND_SIG_NOINFO, t);
- } while_each_thread(p, t);
- reparent_leader(father, p, &dead_children);
- }
- write_unlock_irq(&tasklist_lock);
-
- BUG_ON(!list_empty(&father->children));
-
- list_for_each_entry_safe(p, n, &dead_children, sibling) {
- list_del_init(&p->sibling);
- release_task(p);
+ }
+ /*
+ * If this is a threaded reparent there is no need to
+ * notify anyone anything has happened.
+ */
+ if (!same_thread_group(reaper, father))
+ reparent_leader(father, p, dead);
}
+ list_splice_tail_init(&father->children, &reaper->children);
}
/*
@@ -600,18 +609,12 @@ static void forget_original_parent(struct task_struct *father)
static void exit_notify(struct task_struct *tsk, int group_dead)
{
bool autoreap;
-
- /*
- * This does two things:
- *
- * A. Make init inherit all the child processes
- * B. Check to see if any process groups have become orphaned
- * as a result of our exiting, and if they have any stopped
- * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2)
- */
- forget_original_parent(tsk);
+ struct task_struct *p, *n;
+ LIST_HEAD(dead);
write_lock_irq(&tasklist_lock);
+ forget_original_parent(tsk, &dead);
+
if (group_dead)
kill_orphaned_pgrp(tsk->group_leader, NULL);
@@ -629,15 +632,18 @@ static void exit_notify(struct task_struct *tsk, int group_dead)
}
tsk->exit_state = autoreap ? EXIT_DEAD : EXIT_ZOMBIE;
+ if (tsk->exit_state == EXIT_DEAD)
+ list_add(&tsk->ptrace_entry, &dead);
/* mt-exec, de_thread() is waiting for group leader */
if (unlikely(tsk->signal->notify_count < 0))
wake_up_process(tsk->signal->group_exit_task);
write_unlock_irq(&tasklist_lock);
- /* If the process is dead, release it - nobody will wait for it */
- if (autoreap)
- release_task(tsk);
+ list_for_each_entry_safe(p, n, &dead, ptrace_entry) {
+ list_del_init(&p->ptrace_entry);
+ release_task(p);
+ }
}
#ifdef CONFIG_DEBUG_STACK_USAGE
@@ -982,8 +988,7 @@ static int wait_noreap_copyout(struct wait_opts *wo, struct task_struct *p,
*/
static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
{
- unsigned long state;
- int retval, status, traced;
+ int state, retval, status;
pid_t pid = task_pid_vnr(p);
uid_t uid = from_kuid_munged(current_user_ns(), task_uid(p));
struct siginfo __user *infop;
@@ -997,6 +1002,8 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
get_task_struct(p);
read_unlock(&tasklist_lock);
+ sched_annotate_sleep();
+
if ((exit_code & 0x7f) == 0) {
why = CLD_EXITED;
status = exit_code >> 8;
@@ -1006,21 +1013,25 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
}
return wait_noreap_copyout(wo, p, pid, uid, why, status);
}
-
- traced = ptrace_reparented(p);
/*
* Move the task's state to DEAD/TRACE, only one thread can do this.
*/
- state = traced && thread_group_leader(p) ? EXIT_TRACE : EXIT_DEAD;
+ state = (ptrace_reparented(p) && thread_group_leader(p)) ?
+ EXIT_TRACE : EXIT_DEAD;
if (cmpxchg(&p->exit_state, EXIT_ZOMBIE, state) != EXIT_ZOMBIE)
return 0;
/*
- * It can be ptraced but not reparented, check
- * thread_group_leader() to filter out sub-threads.
+ * We own this thread, nobody else can reap it.
*/
- if (likely(!traced) && thread_group_leader(p)) {
- struct signal_struct *psig;
- struct signal_struct *sig;
+ read_unlock(&tasklist_lock);
+ sched_annotate_sleep();
+
+ /*
+ * Check thread_group_leader() to exclude the traced sub-threads.
+ */
+ if (state == EXIT_DEAD && thread_group_leader(p)) {
+ struct signal_struct *sig = p->signal;
+ struct signal_struct *psig = current->signal;
unsigned long maxrss;
cputime_t tgutime, tgstime;
@@ -1032,21 +1043,20 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
* accumulate in the parent's signal_struct c* fields.
*
* We don't bother to take a lock here to protect these
- * p->signal fields, because they are only touched by
- * __exit_signal, which runs with tasklist_lock
- * write-locked anyway, and so is excluded here. We do
- * need to protect the access to parent->signal fields,
- * as other threads in the parent group can be right
- * here reaping other children at the same time.
+ * p->signal fields because the whole thread group is dead
+ * and nobody can change them.
+ *
+ * psig->stats_lock also protects us from our sub-theads
+ * which can reap other children at the same time. Until
+ * we change k_getrusage()-like users to rely on this lock
+ * we have to take ->siglock as well.
*
* We use thread_group_cputime_adjusted() to get times for
* the thread group, which consolidates times for all threads
* in the group including the group leader.
*/
thread_group_cputime_adjusted(p, &tgutime, &tgstime);
- spin_lock_irq(&p->real_parent->sighand->siglock);
- psig = p->real_parent->signal;
- sig = p->signal;
+ spin_lock_irq(&current->sighand->siglock);
write_seqlock(&psig->stats_lock);
psig->cutime += tgutime + sig->cutime;
psig->cstime += tgstime + sig->cstime;
@@ -1071,15 +1081,9 @@ static int wait_task_zombie(struct wait_opts *wo, struct task_struct *p)
task_io_accounting_add(&psig->ioac, &p->ioac);
task_io_accounting_add(&psig->ioac, &sig->ioac);
write_sequnlock(&psig->stats_lock);
- spin_unlock_irq(&p->real_parent->sighand->siglock);
+ spin_unlock_irq(&current->sighand->siglock);
}
- /*
- * Now we are sure this task is interesting, and no other
- * thread can reap it because we its state == DEAD/TRACE.
- */
- read_unlock(&tasklist_lock);
-
retval = wo->wo_rusage
? getrusage(p, RUSAGE_BOTH, wo->wo_rusage) : 0;
status = (p->signal->flags & SIGNAL_GROUP_EXIT)
@@ -1210,6 +1214,7 @@ unlock_sig:
pid = task_pid_vnr(p);
why = ptrace ? CLD_TRAPPED : CLD_STOPPED;
read_unlock(&tasklist_lock);
+ sched_annotate_sleep();
if (unlikely(wo->wo_flags & WNOWAIT))
return wait_noreap_copyout(wo, p, pid, uid, why, exit_code);
@@ -1272,6 +1277,7 @@ static int wait_task_continued(struct wait_opts *wo, struct task_struct *p)
pid = task_pid_vnr(p);
get_task_struct(p);
read_unlock(&tasklist_lock);
+ sched_annotate_sleep();
if (!wo->wo_info) {
retval = wo->wo_rusage
diff --git a/kernel/extable.c b/kernel/extable.c
index d8a6446..c98f926 100644
--- a/kernel/extable.c
+++ b/kernel/extable.c
@@ -18,6 +18,7 @@
#include <linux/ftrace.h>
#include <linux/memory.h>
#include <linux/module.h>
+#include <linux/ftrace.h>
#include <linux/mutex.h>
#include <linux/init.h>
@@ -102,6 +103,8 @@ int __kernel_text_address(unsigned long addr)
return 1;
if (is_module_text_address(addr))
return 1;
+ if (is_ftrace_trampoline(addr))
+ return 1;
/*
* There might be init symbols in saved stacktraces.
* Give those symbols a chance to be printed in
@@ -119,7 +122,9 @@ int kernel_text_address(unsigned long addr)
{
if (core_kernel_text(addr))
return 1;
- return is_module_text_address(addr);
+ if (is_module_text_address(addr))
+ return 1;
+ return is_ftrace_trampoline(addr);
}
/*
diff --git a/kernel/fork.c b/kernel/fork.c
index 9b7d746..9ca8418 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -1022,11 +1022,14 @@ void __cleanup_sighand(struct sighand_struct *sighand)
{
if (atomic_dec_and_test(&sighand->count)) {
signalfd_cleanup(sighand);
+ /*
+ * sighand_cachep is SLAB_DESTROY_BY_RCU so we can free it
+ * without an RCU grace period, see __lock_task_sighand().
+ */
kmem_cache_free(sighand_cachep, sighand);
}
}
-
/*
* Initialize POSIX timer handling for a thread group.
*/
diff --git a/kernel/irq/Kconfig b/kernel/irq/Kconfig
index 225086b..9a76e3b 100644
--- a/kernel/irq/Kconfig
+++ b/kernel/irq/Kconfig
@@ -55,6 +55,21 @@ config GENERIC_IRQ_CHIP
config IRQ_DOMAIN
bool
+# Support for hierarchical irq domains
+config IRQ_DOMAIN_HIERARCHY
+ bool
+ select IRQ_DOMAIN
+
+# Generic MSI interrupt support
+config GENERIC_MSI_IRQ
+ bool
+
+# Generic MSI hierarchical interrupt domain support
+config GENERIC_MSI_IRQ_DOMAIN
+ bool
+ select IRQ_DOMAIN_HIERARCHY
+ select GENERIC_MSI_IRQ
+
config HANDLE_DOMAIN_IRQ
bool
diff --git a/kernel/irq/Makefile b/kernel/irq/Makefile
index fff1738..d121235 100644
--- a/kernel/irq/Makefile
+++ b/kernel/irq/Makefile
@@ -6,3 +6,4 @@ obj-$(CONFIG_IRQ_DOMAIN) += irqdomain.o
obj-$(CONFIG_PROC_FS) += proc.o
obj-$(CONFIG_GENERIC_PENDING_IRQ) += migration.o
obj-$(CONFIG_PM_SLEEP) += pm.o
+obj-$(CONFIG_GENERIC_MSI_IRQ) += msi.o
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index e5202f0..6f1c7a5 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -15,6 +15,7 @@
#include <linux/module.h>
#include <linux/interrupt.h>
#include <linux/kernel_stat.h>
+#include <linux/irqdomain.h>
#include <trace/events/irq.h>
@@ -178,6 +179,7 @@ int irq_startup(struct irq_desc *desc, bool resend)
irq_state_clr_disabled(desc);
desc->depth = 0;
+ irq_domain_activate_irq(&desc->irq_data);
if (desc->irq_data.chip->irq_startup) {
ret = desc->irq_data.chip->irq_startup(&desc->irq_data);
irq_state_clr_masked(desc);
@@ -199,6 +201,7 @@ void irq_shutdown(struct irq_desc *desc)
desc->irq_data.chip->irq_disable(&desc->irq_data);
else
desc->irq_data.chip->irq_mask(&desc->irq_data);
+ irq_domain_deactivate_irq(&desc->irq_data);
irq_state_set_masked(desc);
}
@@ -728,7 +731,30 @@ __irq_set_handler(unsigned int irq, irq_flow_handler_t handle, int is_chained,
if (!handle) {
handle = handle_bad_irq;
} else {
- if (WARN_ON(desc->irq_data.chip == &no_irq_chip))
+ struct irq_data *irq_data = &desc->irq_data;
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ /*
+ * With hierarchical domains we might run into a
+ * situation where the outermost chip is not yet set
+ * up, but the inner chips are there. Instead of
+ * bailing we install the handler, but obviously we
+ * cannot enable/startup the interrupt at this point.
+ */
+ while (irq_data) {
+ if (irq_data->chip != &no_irq_chip)
+ break;
+ /*
+ * Bail out if the outer chip is not set up
+ * and the interrrupt supposed to be started
+ * right away.
+ */
+ if (WARN_ON(is_chained))
+ goto out;
+ /* Try the parent */
+ irq_data = irq_data->parent_data;
+ }
+#endif
+ if (WARN_ON(!irq_data || irq_data->chip == &no_irq_chip))
goto out;
}
@@ -847,3 +873,105 @@ void irq_cpu_offline(void)
raw_spin_unlock_irqrestore(&desc->lock, flags);
}
}
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+/**
+ * irq_chip_ack_parent - Acknowledge the parent interrupt
+ * @data: Pointer to interrupt specific data
+ */
+void irq_chip_ack_parent(struct irq_data *data)
+{
+ data = data->parent_data;
+ data->chip->irq_ack(data);
+}
+
+/**
+ * irq_chip_mask_parent - Mask the parent interrupt
+ * @data: Pointer to interrupt specific data
+ */
+void irq_chip_mask_parent(struct irq_data *data)
+{
+ data = data->parent_data;
+ data->chip->irq_mask(data);
+}
+
+/**
+ * irq_chip_unmask_parent - Unmask the parent interrupt
+ * @data: Pointer to interrupt specific data
+ */
+void irq_chip_unmask_parent(struct irq_data *data)
+{
+ data = data->parent_data;
+ data->chip->irq_unmask(data);
+}
+
+/**
+ * irq_chip_eoi_parent - Invoke EOI on the parent interrupt
+ * @data: Pointer to interrupt specific data
+ */
+void irq_chip_eoi_parent(struct irq_data *data)
+{
+ data = data->parent_data;
+ data->chip->irq_eoi(data);
+}
+
+/**
+ * irq_chip_set_affinity_parent - Set affinity on the parent interrupt
+ * @data: Pointer to interrupt specific data
+ * @dest: The affinity mask to set
+ * @force: Flag to enforce setting (disable online checks)
+ *
+ * Conditinal, as the underlying parent chip might not implement it.
+ */
+int irq_chip_set_affinity_parent(struct irq_data *data,
+ const struct cpumask *dest, bool force)
+{
+ data = data->parent_data;
+ if (data->chip->irq_set_affinity)
+ return data->chip->irq_set_affinity(data, dest, force);
+
+ return -ENOSYS;
+}
+
+/**
+ * irq_chip_retrigger_hierarchy - Retrigger an interrupt in hardware
+ * @data: Pointer to interrupt specific data
+ *
+ * Iterate through the domain hierarchy of the interrupt and check
+ * whether a hw retrigger function exists. If yes, invoke it.
+ */
+int irq_chip_retrigger_hierarchy(struct irq_data *data)
+{
+ for (data = data->parent_data; data; data = data->parent_data)
+ if (data->chip && data->chip->irq_retrigger)
+ return data->chip->irq_retrigger(data);
+
+ return -ENOSYS;
+}
+#endif
+
+/**
+ * irq_chip_compose_msi_msg - Componse msi message for a irq chip
+ * @data: Pointer to interrupt specific data
+ * @msg: Pointer to the MSI message
+ *
+ * For hierarchical domains we find the first chip in the hierarchy
+ * which implements the irq_compose_msi_msg callback. For non
+ * hierarchical we use the top level chip.
+ */
+int irq_chip_compose_msi_msg(struct irq_data *data, struct msi_msg *msg)
+{
+ struct irq_data *pos = NULL;
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+ for (; data; data = data->parent_data)
+#endif
+ if (data->chip && data->chip->irq_compose_msi_msg)
+ pos = data;
+ if (!pos)
+ return -ENOSYS;
+
+ pos->chip->irq_compose_msi_msg(pos, msg);
+
+ return 0;
+}
diff --git a/kernel/irq/generic-chip.c b/kernel/irq/generic-chip.c
index cf80e7b..61024e8 100644
--- a/kernel/irq/generic-chip.c
+++ b/kernel/irq/generic-chip.c
@@ -39,7 +39,7 @@ void irq_gc_mask_disable_reg(struct irq_data *d)
u32 mask = d->mask;
irq_gc_lock(gc);
- irq_reg_writel(mask, gc->reg_base + ct->regs.disable);
+ irq_reg_writel(gc, mask, ct->regs.disable);
*ct->mask_cache &= ~mask;
irq_gc_unlock(gc);
}
@@ -59,7 +59,7 @@ void irq_gc_mask_set_bit(struct irq_data *d)
irq_gc_lock(gc);
*ct->mask_cache |= mask;
- irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask);
+ irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
irq_gc_unlock(gc);
}
EXPORT_SYMBOL_GPL(irq_gc_mask_set_bit);
@@ -79,7 +79,7 @@ void irq_gc_mask_clr_bit(struct irq_data *d)
irq_gc_lock(gc);
*ct->mask_cache &= ~mask;
- irq_reg_writel(*ct->mask_cache, gc->reg_base + ct->regs.mask);
+ irq_reg_writel(gc, *ct->mask_cache, ct->regs.mask);
irq_gc_unlock(gc);
}
EXPORT_SYMBOL_GPL(irq_gc_mask_clr_bit);
@@ -98,7 +98,7 @@ void irq_gc_unmask_enable_reg(struct irq_data *d)
u32 mask = d->mask;
irq_gc_lock(gc);
- irq_reg_writel(mask, gc->reg_base + ct->regs.enable);
+ irq_reg_writel(gc, mask, ct->regs.enable);
*ct->mask_cache |= mask;
irq_gc_unlock(gc);
}
@@ -114,7 +114,7 @@ void irq_gc_ack_set_bit(struct irq_data *d)
u32 mask = d->mask;
irq_gc_lock(gc);
- irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
+ irq_reg_writel(gc, mask, ct->regs.ack);
irq_gc_unlock(gc);
}
EXPORT_SYMBOL_GPL(irq_gc_ack_set_bit);
@@ -130,7 +130,7 @@ void irq_gc_ack_clr_bit(struct irq_data *d)
u32 mask = ~d->mask;
irq_gc_lock(gc);
- irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
+ irq_reg_writel(gc, mask, ct->regs.ack);
irq_gc_unlock(gc);
}
@@ -145,8 +145,8 @@ void irq_gc_mask_disable_reg_and_ack(struct irq_data *d)
u32 mask = d->mask;
irq_gc_lock(gc);
- irq_reg_writel(mask, gc->reg_base + ct->regs.mask);
- irq_reg_writel(mask, gc->reg_base + ct->regs.ack);
+ irq_reg_writel(gc, mask, ct->regs.mask);
+ irq_reg_writel(gc, mask, ct->regs.ack);
irq_gc_unlock(gc);
}
@@ -161,7 +161,7 @@ void irq_gc_eoi(struct irq_data *d)
u32 mask = d->mask;
irq_gc_lock(gc);
- irq_reg_writel(mask, gc->reg_base + ct->regs.eoi);
+ irq_reg_writel(gc, mask, ct->regs.eoi);
irq_gc_unlock(gc);
}
@@ -191,6 +191,16 @@ int irq_gc_set_wake(struct irq_data *d, unsigned int on)
return 0;
}
+static u32 irq_readl_be(void __iomem *addr)
+{
+ return ioread32be(addr);
+}
+
+static void irq_writel_be(u32 val, void __iomem *addr)
+{
+ iowrite32be(val, addr);
+}
+
static void
irq_init_generic_chip(struct irq_chip_generic *gc, const char *name,
int num_ct, unsigned int irq_base,
@@ -245,7 +255,7 @@ irq_gc_init_mask_cache(struct irq_chip_generic *gc, enum irq_gc_flags flags)
}
ct[i].mask_cache = mskptr;
if (flags & IRQ_GC_INIT_MASK_CACHE)
- *mskptr = irq_reg_readl(gc->reg_base + mskreg);
+ *mskptr = irq_reg_readl(gc, mskreg);
}
}
@@ -300,7 +310,13 @@ int irq_alloc_domain_generic_chips(struct irq_domain *d, int irqs_per_chip,
dgc->gc[i] = gc = tmp;
irq_init_generic_chip(gc, name, num_ct, i * irqs_per_chip,
NULL, handler);
+
gc->domain = d;
+ if (gcflags & IRQ_GC_BE_IO) {
+ gc->reg_readl = &irq_readl_be;
+ gc->reg_writel = &irq_writel_be;
+ }
+
raw_spin_lock_irqsave(&gc_lock, flags);
list_add_tail(&gc->list, &gc_list);
raw_spin_unlock_irqrestore(&gc_lock, flags);
diff --git a/kernel/irq/irqdomain.c b/kernel/irq/irqdomain.c
index 6534ff6..7fac311 100644
--- a/kernel/irq/irqdomain.c
+++ b/kernel/irq/irqdomain.c
@@ -23,6 +23,10 @@ static DEFINE_MUTEX(irq_domain_mutex);
static DEFINE_MUTEX(revmap_trees_mutex);
static struct irq_domain *irq_default_domain;
+static int irq_domain_alloc_descs(int virq, unsigned int nr_irqs,
+ irq_hw_number_t hwirq, int node);
+static void irq_domain_check_hierarchy(struct irq_domain *domain);
+
/**
* __irq_domain_add() - Allocate a new irq_domain data structure
* @of_node: optional device-tree node of the interrupt controller
@@ -30,7 +34,7 @@ static struct irq_domain *irq_default_domain;
* @hwirq_max: Maximum number of interrupts supported by controller
* @direct_max: Maximum value of direct maps; Use ~0 for no limit; 0 for no
* direct mapping
- * @ops: map/unmap domain callbacks
+ * @ops: domain callbacks
* @host_data: Controller private data pointer
*
* Allocates and initialize and irq_domain structure.
@@ -56,6 +60,7 @@ struct irq_domain *__irq_domain_add(struct device_node *of_node, int size,
domain->hwirq_max = hwirq_max;
domain->revmap_size = size;
domain->revmap_direct_max_irq = direct_max;
+ irq_domain_check_hierarchy(domain);
mutex_lock(&irq_domain_mutex);
list_add(&domain->link, &irq_domain_list);
@@ -109,7 +114,7 @@ EXPORT_SYMBOL_GPL(irq_domain_remove);
* @first_irq: first number of irq block assigned to the domain,
* pass zero to assign irqs on-the-fly. If first_irq is non-zero, then
* pre-map all of the irqs in the domain to virqs starting at first_irq.
- * @ops: map/unmap domain callbacks
+ * @ops: domain callbacks
* @host_data: Controller private data pointer
*
* Allocates an irq_domain, and optionally if first_irq is positive then also
@@ -174,10 +179,8 @@ struct irq_domain *irq_domain_add_legacy(struct device_node *of_node,
domain = __irq_domain_add(of_node, first_hwirq + size,
first_hwirq + size, 0, ops, host_data);
- if (!domain)
- return NULL;
-
- irq_domain_associate_many(domain, first_irq, first_hwirq, size);
+ if (domain)
+ irq_domain_associate_many(domain, first_irq, first_hwirq, size);
return domain;
}
@@ -388,7 +391,6 @@ EXPORT_SYMBOL_GPL(irq_create_direct_mapping);
unsigned int irq_create_mapping(struct irq_domain *domain,
irq_hw_number_t hwirq)
{
- unsigned int hint;
int virq;
pr_debug("irq_create_mapping(0x%p, 0x%lx)\n", domain, hwirq);
@@ -410,12 +412,8 @@ unsigned int irq_create_mapping(struct irq_domain *domain,
}
/* Allocate a virtual interrupt number */
- hint = hwirq % nr_irqs;
- if (hint == 0)
- hint++;
- virq = irq_alloc_desc_from(hint, of_node_to_nid(domain->of_node));
- if (virq <= 0)
- virq = irq_alloc_desc_from(1, of_node_to_nid(domain->of_node));
+ virq = irq_domain_alloc_descs(-1, 1, hwirq,
+ of_node_to_nid(domain->of_node));
if (virq <= 0) {
pr_debug("-> virq allocation failed\n");
return 0;
@@ -471,7 +469,7 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
struct irq_domain *domain;
irq_hw_number_t hwirq;
unsigned int type = IRQ_TYPE_NONE;
- unsigned int virq;
+ int virq;
domain = irq_data->np ? irq_find_host(irq_data->np) : irq_default_domain;
if (!domain) {
@@ -489,10 +487,24 @@ unsigned int irq_create_of_mapping(struct of_phandle_args *irq_data)
return 0;
}
- /* Create mapping */
- virq = irq_create_mapping(domain, hwirq);
- if (!virq)
- return virq;
+ if (irq_domain_is_hierarchy(domain)) {
+ /*
+ * If we've already configured this interrupt,
+ * don't do it again, or hell will break loose.
+ */
+ virq = irq_find_mapping(domain, hwirq);
+ if (virq)
+ return virq;
+
+ virq = irq_domain_alloc_irqs(domain, 1, NUMA_NO_NODE, irq_data);
+ if (virq <= 0)
+ return 0;
+ } else {
+ /* Create mapping */
+ virq = irq_create_mapping(domain, hwirq);
+ if (!virq)
+ return virq;
+ }
/* Set type if specified and different than the current one */
if (type != IRQ_TYPE_NONE &&
@@ -540,8 +552,8 @@ unsigned int irq_find_mapping(struct irq_domain *domain,
return 0;
if (hwirq < domain->revmap_direct_max_irq) {
- data = irq_get_irq_data(hwirq);
- if (data && (data->domain == domain) && (data->hwirq == hwirq))
+ data = irq_domain_get_irq_data(domain, hwirq);
+ if (data && data->hwirq == hwirq)
return hwirq;
}
@@ -709,3 +721,518 @@ const struct irq_domain_ops irq_domain_simple_ops = {
.xlate = irq_domain_xlate_onetwocell,
};
EXPORT_SYMBOL_GPL(irq_domain_simple_ops);
+
+static int irq_domain_alloc_descs(int virq, unsigned int cnt,
+ irq_hw_number_t hwirq, int node)
+{
+ unsigned int hint;
+
+ if (virq >= 0) {
+ virq = irq_alloc_descs(virq, virq, cnt, node);
+ } else {
+ hint = hwirq % nr_irqs;
+ if (hint == 0)
+ hint++;
+ virq = irq_alloc_descs_from(hint, cnt, node);
+ if (virq <= 0 && hint > 1)
+ virq = irq_alloc_descs_from(1, cnt, node);
+ }
+
+ return virq;
+}
+
+#ifdef CONFIG_IRQ_DOMAIN_HIERARCHY
+/**
+ * irq_domain_add_hierarchy - Add a irqdomain into the hierarchy
+ * @parent: Parent irq domain to associate with the new domain
+ * @flags: Irq domain flags associated to the domain
+ * @size: Size of the domain. See below
+ * @node: Optional device-tree node of the interrupt controller
+ * @ops: Pointer to the interrupt domain callbacks
+ * @host_data: Controller private data pointer
+ *
+ * If @size is 0 a tree domain is created, otherwise a linear domain.
+ *
+ * If successful the parent is associated to the new domain and the
+ * domain flags are set.
+ * Returns pointer to IRQ domain, or NULL on failure.
+ */
+struct irq_domain *irq_domain_add_hierarchy(struct irq_domain *parent,
+ unsigned int flags,
+ unsigned int size,
+ struct device_node *node,
+ const struct irq_domain_ops *ops,
+ void *host_data)
+{
+ struct irq_domain *domain;
+
+ if (size)
+ domain = irq_domain_add_linear(node, size, ops, host_data);
+ else
+ domain = irq_domain_add_tree(node, ops, host_data);
+ if (domain) {
+ domain->parent = parent;
+ domain->flags |= flags;
+ }
+
+ return domain;
+}
+
+static void irq_domain_insert_irq(int virq)
+{
+ struct irq_data *data;
+
+ for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
+ struct irq_domain *domain = data->domain;
+ irq_hw_number_t hwirq = data->hwirq;
+
+ if (hwirq < domain->revmap_size) {
+ domain->linear_revmap[hwirq] = virq;
+ } else {
+ mutex_lock(&revmap_trees_mutex);
+ radix_tree_insert(&domain->revmap_tree, hwirq, data);
+ mutex_unlock(&revmap_trees_mutex);
+ }
+
+ /* If not already assigned, give the domain the chip's name */
+ if (!domain->name && data->chip)
+ domain->name = data->chip->name;
+ }
+
+ irq_clear_status_flags(virq, IRQ_NOREQUEST);
+}
+
+static void irq_domain_remove_irq(int virq)
+{
+ struct irq_data *data;
+
+ irq_set_status_flags(virq, IRQ_NOREQUEST);
+ irq_set_chip_and_handler(virq, NULL, NULL);
+ synchronize_irq(virq);
+ smp_mb();
+
+ for (data = irq_get_irq_data(virq); data; data = data->parent_data) {
+ struct irq_domain *domain = data->domain;
+ irq_hw_number_t hwirq = data->hwirq;
+
+ if (hwirq < domain->revmap_size) {
+ domain->linear_revmap[hwirq] = 0;
+ } else {
+ mutex_lock(&revmap_trees_mutex);
+ radix_tree_delete(&domain->revmap_tree, hwirq);
+ mutex_unlock(&revmap_trees_mutex);
+ }
+ }
+}
+
+static struct irq_data *irq_domain_insert_irq_data(struct irq_domain *domain,
+ struct irq_data *child)
+{
+ struct irq_data *irq_data;
+
+ irq_data = kzalloc_node(sizeof(*irq_data), GFP_KERNEL, child->node);
+ if (irq_data) {
+ child->parent_data = irq_data;
+ irq_data->irq = child->irq;
+ irq_data->node = child->node;
+ irq_data->domain = domain;
+ }
+
+ return irq_data;
+}
+
+static void irq_domain_free_irq_data(unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *irq_data, *tmp;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_get_irq_data(virq + i);
+ tmp = irq_data->parent_data;
+ irq_data->parent_data = NULL;
+ irq_data->domain = NULL;
+
+ while (tmp) {
+ irq_data = tmp;
+ tmp = tmp->parent_data;
+ kfree(irq_data);
+ }
+ }
+}
+
+static int irq_domain_alloc_irq_data(struct irq_domain *domain,
+ unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *irq_data;
+ struct irq_domain *parent;
+ int i;
+
+ /* The outermost irq_data is embedded in struct irq_desc */
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_get_irq_data(virq + i);
+ irq_data->domain = domain;
+
+ for (parent = domain->parent; parent; parent = parent->parent) {
+ irq_data = irq_domain_insert_irq_data(parent, irq_data);
+ if (!irq_data) {
+ irq_domain_free_irq_data(virq, i + 1);
+ return -ENOMEM;
+ }
+ }
+ }
+
+ return 0;
+}
+
+/**
+ * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
+ * @domain: domain to match
+ * @virq: IRQ number to get irq_data
+ */
+struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
+ unsigned int virq)
+{
+ struct irq_data *irq_data;
+
+ for (irq_data = irq_get_irq_data(virq); irq_data;
+ irq_data = irq_data->parent_data)
+ if (irq_data->domain == domain)
+ return irq_data;
+
+ return NULL;
+}
+
+/**
+ * irq_domain_set_hwirq_and_chip - Set hwirq and irqchip of @virq at @domain
+ * @domain: Interrupt domain to match
+ * @virq: IRQ number
+ * @hwirq: The hwirq number
+ * @chip: The associated interrupt chip
+ * @chip_data: The associated chip data
+ */
+int irq_domain_set_hwirq_and_chip(struct irq_domain *domain, unsigned int virq,
+ irq_hw_number_t hwirq, struct irq_chip *chip,
+ void *chip_data)
+{
+ struct irq_data *irq_data = irq_domain_get_irq_data(domain, virq);
+
+ if (!irq_data)
+ return -ENOENT;
+
+ irq_data->hwirq = hwirq;
+ irq_data->chip = chip ? chip : &no_irq_chip;
+ irq_data->chip_data = chip_data;
+
+ return 0;
+}
+
+/**
+ * irq_domain_set_info - Set the complete data for a @virq in @domain
+ * @domain: Interrupt domain to match
+ * @virq: IRQ number
+ * @hwirq: The hardware interrupt number
+ * @chip: The associated interrupt chip
+ * @chip_data: The associated interrupt chip data
+ * @handler: The interrupt flow handler
+ * @handler_data: The interrupt flow handler data
+ * @handler_name: The interrupt handler name
+ */
+void irq_domain_set_info(struct irq_domain *domain, unsigned int virq,
+ irq_hw_number_t hwirq, struct irq_chip *chip,
+ void *chip_data, irq_flow_handler_t handler,
+ void *handler_data, const char *handler_name)
+{
+ irq_domain_set_hwirq_and_chip(domain, virq, hwirq, chip, chip_data);
+ __irq_set_handler(virq, handler, 0, handler_name);
+ irq_set_handler_data(virq, handler_data);
+}
+
+/**
+ * irq_domain_reset_irq_data - Clear hwirq, chip and chip_data in @irq_data
+ * @irq_data: The pointer to irq_data
+ */
+void irq_domain_reset_irq_data(struct irq_data *irq_data)
+{
+ irq_data->hwirq = 0;
+ irq_data->chip = &no_irq_chip;
+ irq_data->chip_data = NULL;
+}
+
+/**
+ * irq_domain_free_irqs_common - Clear irq_data and free the parent
+ * @domain: Interrupt domain to match
+ * @virq: IRQ number to start with
+ * @nr_irqs: The number of irqs to free
+ */
+void irq_domain_free_irqs_common(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct irq_data *irq_data;
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_data = irq_domain_get_irq_data(domain, virq + i);
+ if (irq_data)
+ irq_domain_reset_irq_data(irq_data);
+ }
+ irq_domain_free_irqs_parent(domain, virq, nr_irqs);
+}
+
+/**
+ * irq_domain_free_irqs_top - Clear handler and handler data, clear irqdata and free parent
+ * @domain: Interrupt domain to match
+ * @virq: IRQ number to start with
+ * @nr_irqs: The number of irqs to free
+ */
+void irq_domain_free_irqs_top(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ int i;
+
+ for (i = 0; i < nr_irqs; i++) {
+ irq_set_handler_data(virq + i, NULL);
+ irq_set_handler(virq + i, NULL);
+ }
+ irq_domain_free_irqs_common(domain, virq, nr_irqs);
+}
+
+static bool irq_domain_is_auto_recursive(struct irq_domain *domain)
+{
+ return domain->flags & IRQ_DOMAIN_FLAG_AUTO_RECURSIVE;
+}
+
+static void irq_domain_free_irqs_recursive(struct irq_domain *domain,
+ unsigned int irq_base,
+ unsigned int nr_irqs)
+{
+ domain->ops->free(domain, irq_base, nr_irqs);
+ if (irq_domain_is_auto_recursive(domain)) {
+ BUG_ON(!domain->parent);
+ irq_domain_free_irqs_recursive(domain->parent, irq_base,
+ nr_irqs);
+ }
+}
+
+static int irq_domain_alloc_irqs_recursive(struct irq_domain *domain,
+ unsigned int irq_base,
+ unsigned int nr_irqs, void *arg)
+{
+ int ret = 0;
+ struct irq_domain *parent = domain->parent;
+ bool recursive = irq_domain_is_auto_recursive(domain);
+
+ BUG_ON(recursive && !parent);
+ if (recursive)
+ ret = irq_domain_alloc_irqs_recursive(parent, irq_base,
+ nr_irqs, arg);
+ if (ret >= 0)
+ ret = domain->ops->alloc(domain, irq_base, nr_irqs, arg);
+ if (ret < 0 && recursive)
+ irq_domain_free_irqs_recursive(parent, irq_base, nr_irqs);
+
+ return ret;
+}
+
+/**
+ * __irq_domain_alloc_irqs - Allocate IRQs from domain
+ * @domain: domain to allocate from
+ * @irq_base: allocate specified IRQ nubmer if irq_base >= 0
+ * @nr_irqs: number of IRQs to allocate
+ * @node: NUMA node id for memory allocation
+ * @arg: domain specific argument
+ * @realloc: IRQ descriptors have already been allocated if true
+ *
+ * Allocate IRQ numbers and initialized all data structures to support
+ * hierarchy IRQ domains.
+ * Parameter @realloc is mainly to support legacy IRQs.
+ * Returns error code or allocated IRQ number
+ *
+ * The whole process to setup an IRQ has been split into two steps.
+ * The first step, __irq_domain_alloc_irqs(), is to allocate IRQ
+ * descriptor and required hardware resources. The second step,
+ * irq_domain_activate_irq(), is to program hardwares with preallocated
+ * resources. In this way, it's easier to rollback when failing to
+ * allocate resources.
+ */
+int __irq_domain_alloc_irqs(struct irq_domain *domain, int irq_base,
+ unsigned int nr_irqs, int node, void *arg,
+ bool realloc)
+{
+ int i, ret, virq;
+
+ if (domain == NULL) {
+ domain = irq_default_domain;
+ if (WARN(!domain, "domain is NULL; cannot allocate IRQ\n"))
+ return -EINVAL;
+ }
+
+ if (!domain->ops->alloc) {
+ pr_debug("domain->ops->alloc() is NULL\n");
+ return -ENOSYS;
+ }
+
+ if (realloc && irq_base >= 0) {
+ virq = irq_base;
+ } else {
+ virq = irq_domain_alloc_descs(irq_base, nr_irqs, 0, node);
+ if (virq < 0) {
+ pr_debug("cannot allocate IRQ(base %d, count %d)\n",
+ irq_base, nr_irqs);
+ return virq;
+ }
+ }
+
+ if (irq_domain_alloc_irq_data(domain, virq, nr_irqs)) {
+ pr_debug("cannot allocate memory for IRQ%d\n", virq);
+ ret = -ENOMEM;
+ goto out_free_desc;
+ }
+
+ mutex_lock(&irq_domain_mutex);
+ ret = irq_domain_alloc_irqs_recursive(domain, virq, nr_irqs, arg);
+ if (ret < 0) {
+ mutex_unlock(&irq_domain_mutex);
+ goto out_free_irq_data;
+ }
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_insert_irq(virq + i);
+ mutex_unlock(&irq_domain_mutex);
+
+ return virq;
+
+out_free_irq_data:
+ irq_domain_free_irq_data(virq, nr_irqs);
+out_free_desc:
+ irq_free_descs(virq, nr_irqs);
+ return ret;
+}
+
+/**
+ * irq_domain_free_irqs - Free IRQ number and associated data structures
+ * @virq: base IRQ number
+ * @nr_irqs: number of IRQs to free
+ */
+void irq_domain_free_irqs(unsigned int virq, unsigned int nr_irqs)
+{
+ struct irq_data *data = irq_get_irq_data(virq);
+ int i;
+
+ if (WARN(!data || !data->domain || !data->domain->ops->free,
+ "NULL pointer, cannot free irq\n"))
+ return;
+
+ mutex_lock(&irq_domain_mutex);
+ for (i = 0; i < nr_irqs; i++)
+ irq_domain_remove_irq(virq + i);
+ irq_domain_free_irqs_recursive(data->domain, virq, nr_irqs);
+ mutex_unlock(&irq_domain_mutex);
+
+ irq_domain_free_irq_data(virq, nr_irqs);
+ irq_free_descs(virq, nr_irqs);
+}
+
+/**
+ * irq_domain_alloc_irqs_parent - Allocate interrupts from parent domain
+ * @irq_base: Base IRQ number
+ * @nr_irqs: Number of IRQs to allocate
+ * @arg: Allocation data (arch/domain specific)
+ *
+ * Check whether the domain has been setup recursive. If not allocate
+ * through the parent domain.
+ */
+int irq_domain_alloc_irqs_parent(struct irq_domain *domain,
+ unsigned int irq_base, unsigned int nr_irqs,
+ void *arg)
+{
+ /* irq_domain_alloc_irqs_recursive() has called parent's alloc() */
+ if (irq_domain_is_auto_recursive(domain))
+ return 0;
+
+ domain = domain->parent;
+ if (domain)
+ return irq_domain_alloc_irqs_recursive(domain, irq_base,
+ nr_irqs, arg);
+ return -ENOSYS;
+}
+
+/**
+ * irq_domain_free_irqs_parent - Free interrupts from parent domain
+ * @irq_base: Base IRQ number
+ * @nr_irqs: Number of IRQs to free
+ *
+ * Check whether the domain has been setup recursive. If not free
+ * through the parent domain.
+ */
+void irq_domain_free_irqs_parent(struct irq_domain *domain,
+ unsigned int irq_base, unsigned int nr_irqs)
+{
+ /* irq_domain_free_irqs_recursive() will call parent's free */
+ if (!irq_domain_is_auto_recursive(domain) && domain->parent)
+ irq_domain_free_irqs_recursive(domain->parent, irq_base,
+ nr_irqs);
+}
+
+/**
+ * irq_domain_activate_irq - Call domain_ops->activate recursively to activate
+ * interrupt
+ * @irq_data: outermost irq_data associated with interrupt
+ *
+ * This is the second step to call domain_ops->activate to program interrupt
+ * controllers, so the interrupt could actually get delivered.
+ */
+void irq_domain_activate_irq(struct irq_data *irq_data)
+{
+ if (irq_data && irq_data->domain) {
+ struct irq_domain *domain = irq_data->domain;
+
+ if (irq_data->parent_data)
+ irq_domain_activate_irq(irq_data->parent_data);
+ if (domain->ops->activate)
+ domain->ops->activate(domain, irq_data);
+ }
+}
+
+/**
+ * irq_domain_deactivate_irq - Call domain_ops->deactivate recursively to
+ * deactivate interrupt
+ * @irq_data: outermost irq_data associated with interrupt
+ *
+ * It calls domain_ops->deactivate to program interrupt controllers to disable
+ * interrupt delivery.
+ */
+void irq_domain_deactivate_irq(struct irq_data *irq_data)
+{
+ if (irq_data && irq_data->domain) {
+ struct irq_domain *domain = irq_data->domain;
+
+ if (domain->ops->deactivate)
+ domain->ops->deactivate(domain, irq_data);
+ if (irq_data->parent_data)
+ irq_domain_deactivate_irq(irq_data->parent_data);
+ }
+}
+
+static void irq_domain_check_hierarchy(struct irq_domain *domain)
+{
+ /* Hierarchy irq_domains must implement callback alloc() */
+ if (domain->ops->alloc)
+ domain->flags |= IRQ_DOMAIN_FLAG_HIERARCHY;
+}
+#else /* CONFIG_IRQ_DOMAIN_HIERARCHY */
+/**
+ * irq_domain_get_irq_data - Get irq_data associated with @virq and @domain
+ * @domain: domain to match
+ * @virq: IRQ number to get irq_data
+ */
+struct irq_data *irq_domain_get_irq_data(struct irq_domain *domain,
+ unsigned int virq)
+{
+ struct irq_data *irq_data = irq_get_irq_data(virq);
+
+ return (irq_data && irq_data->domain == domain) ? irq_data : NULL;
+}
+
+static void irq_domain_check_hierarchy(struct irq_domain *domain)
+{
+}
+#endif /* CONFIG_IRQ_DOMAIN_HIERARCHY */
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 0a9104b..8069237 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -183,6 +183,7 @@ int irq_do_set_affinity(struct irq_data *data, const struct cpumask *mask,
ret = chip->irq_set_affinity(data, mask, force);
switch (ret) {
case IRQ_SET_MASK_OK:
+ case IRQ_SET_MASK_OK_DONE:
cpumask_copy(data->affinity, mask);
case IRQ_SET_MASK_OK_NOCOPY:
irq_set_thread_affinity(desc);
@@ -600,6 +601,7 @@ int __irq_set_trigger(struct irq_desc *desc, unsigned int irq,
switch (ret) {
case IRQ_SET_MASK_OK:
+ case IRQ_SET_MASK_OK_DONE:
irqd_clear(&desc->irq_data, IRQD_TRIGGER_MASK);
irqd_set(&desc->irq_data, flags);
diff --git a/kernel/irq/msi.c b/kernel/irq/msi.c
new file mode 100644
index 0000000..3e18163
--- /dev/null
+++ b/kernel/irq/msi.c
@@ -0,0 +1,330 @@
+/*
+ * linux/kernel/irq/msi.c
+ *
+ * Copyright (C) 2014 Intel Corp.
+ * Author: Jiang Liu <jiang.liu@linux.intel.com>
+ *
+ * This file is licensed under GPLv2.
+ *
+ * This file contains common code to support Message Signalled Interrupt for
+ * PCI compatible and non PCI compatible devices.
+ */
+#include <linux/types.h>
+#include <linux/device.h>
+#include <linux/irq.h>
+#include <linux/irqdomain.h>
+#include <linux/msi.h>
+
+/* Temparory solution for building, will be removed later */
+#include <linux/pci.h>
+
+void __get_cached_msi_msg(struct msi_desc *entry, struct msi_msg *msg)
+{
+ *msg = entry->msg;
+}
+
+void get_cached_msi_msg(unsigned int irq, struct msi_msg *msg)
+{
+ struct msi_desc *entry = irq_get_msi_desc(irq);
+
+ __get_cached_msi_msg(entry, msg);
+}
+EXPORT_SYMBOL_GPL(get_cached_msi_msg);
+
+#ifdef CONFIG_GENERIC_MSI_IRQ_DOMAIN
+static inline void irq_chip_write_msi_msg(struct irq_data *data,
+ struct msi_msg *msg)
+{
+ data->chip->irq_write_msi_msg(data, msg);
+}
+
+/**
+ * msi_domain_set_affinity - Generic affinity setter function for MSI domains
+ * @irq_data: The irq data associated to the interrupt
+ * @mask: The affinity mask to set
+ * @force: Flag to enforce setting (disable online checks)
+ *
+ * Intended to be used by MSI interrupt controllers which are
+ * implemented with hierarchical domains.
+ */
+int msi_domain_set_affinity(struct irq_data *irq_data,
+ const struct cpumask *mask, bool force)
+{
+ struct irq_data *parent = irq_data->parent_data;
+ struct msi_msg msg;
+ int ret;
+
+ ret = parent->chip->irq_set_affinity(parent, mask, force);
+ if (ret >= 0 && ret != IRQ_SET_MASK_OK_DONE) {
+ BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
+ irq_chip_write_msi_msg(irq_data, &msg);
+ }
+
+ return ret;
+}
+
+static void msi_domain_activate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct msi_msg msg;
+
+ BUG_ON(irq_chip_compose_msi_msg(irq_data, &msg));
+ irq_chip_write_msi_msg(irq_data, &msg);
+}
+
+static void msi_domain_deactivate(struct irq_domain *domain,
+ struct irq_data *irq_data)
+{
+ struct msi_msg msg;
+
+ memset(&msg, 0, sizeof(msg));
+ irq_chip_write_msi_msg(irq_data, &msg);
+}
+
+static int msi_domain_alloc(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs, void *arg)
+{
+ struct msi_domain_info *info = domain->host_data;
+ struct msi_domain_ops *ops = info->ops;
+ irq_hw_number_t hwirq = ops->get_hwirq(info, arg);
+ int i, ret;
+
+ if (irq_find_mapping(domain, hwirq) > 0)
+ return -EEXIST;
+
+ ret = irq_domain_alloc_irqs_parent(domain, virq, nr_irqs, arg);
+ if (ret < 0)
+ return ret;
+
+ for (i = 0; i < nr_irqs; i++) {
+ ret = ops->msi_init(domain, info, virq + i, hwirq + i, arg);
+ if (ret < 0) {
+ if (ops->msi_free) {
+ for (i--; i > 0; i--)
+ ops->msi_free(domain, info, virq + i);
+ }
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
+static void msi_domain_free(struct irq_domain *domain, unsigned int virq,
+ unsigned int nr_irqs)
+{
+ struct msi_domain_info *info = domain->host_data;
+ int i;
+
+ if (info->ops->msi_free) {
+ for (i = 0; i < nr_irqs; i++)
+ info->ops->msi_free(domain, info, virq + i);
+ }
+ irq_domain_free_irqs_top(domain, virq, nr_irqs);
+}
+
+static struct irq_domain_ops msi_domain_ops = {
+ .alloc = msi_domain_alloc,
+ .free = msi_domain_free,
+ .activate = msi_domain_activate,
+ .deactivate = msi_domain_deactivate,
+};
+
+#ifdef GENERIC_MSI_DOMAIN_OPS
+static irq_hw_number_t msi_domain_ops_get_hwirq(struct msi_domain_info *info,
+ msi_alloc_info_t *arg)
+{
+ return arg->hwirq;
+}
+
+static int msi_domain_ops_prepare(struct irq_domain *domain, struct device *dev,
+ int nvec, msi_alloc_info_t *arg)
+{
+ memset(arg, 0, sizeof(*arg));
+ return 0;
+}
+
+static void msi_domain_ops_set_desc(msi_alloc_info_t *arg,
+ struct msi_desc *desc)
+{
+ arg->desc = desc;
+}
+#else
+#define msi_domain_ops_get_hwirq NULL
+#define msi_domain_ops_prepare NULL
+#define msi_domain_ops_set_desc NULL
+#endif /* !GENERIC_MSI_DOMAIN_OPS */
+
+static int msi_domain_ops_init(struct irq_domain *domain,
+ struct msi_domain_info *info,
+ unsigned int virq, irq_hw_number_t hwirq,
+ msi_alloc_info_t *arg)
+{
+ irq_domain_set_hwirq_and_chip(domain, virq, hwirq, info->chip,
+ info->chip_data);
+ if (info->handler && info->handler_name) {
+ __irq_set_handler(virq, info->handler, 0, info->handler_name);
+ if (info->handler_data)
+ irq_set_handler_data(virq, info->handler_data);
+ }
+ return 0;
+}
+
+static int msi_domain_ops_check(struct irq_domain *domain,
+ struct msi_domain_info *info,
+ struct device *dev)
+{
+ return 0;
+}
+
+static struct msi_domain_ops msi_domain_ops_default = {
+ .get_hwirq = msi_domain_ops_get_hwirq,
+ .msi_init = msi_domain_ops_init,
+ .msi_check = msi_domain_ops_check,
+ .msi_prepare = msi_domain_ops_prepare,
+ .set_desc = msi_domain_ops_set_desc,
+};
+
+static void msi_domain_update_dom_ops(struct msi_domain_info *info)
+{
+ struct msi_domain_ops *ops = info->ops;
+
+ if (ops == NULL) {
+ info->ops = &msi_domain_ops_default;
+ return;
+ }
+
+ if (ops->get_hwirq == NULL)
+ ops->get_hwirq = msi_domain_ops_default.get_hwirq;
+ if (ops->msi_init == NULL)
+ ops->msi_init = msi_domain_ops_default.msi_init;
+ if (ops->msi_check == NULL)
+ ops->msi_check = msi_domain_ops_default.msi_check;
+ if (ops->msi_prepare == NULL)
+ ops->msi_prepare = msi_domain_ops_default.msi_prepare;
+ if (ops->set_desc == NULL)
+ ops->set_desc = msi_domain_ops_default.set_desc;
+}
+
+static void msi_domain_update_chip_ops(struct msi_domain_info *info)
+{
+ struct irq_chip *chip = info->chip;
+
+ BUG_ON(!chip);
+ if (!chip->irq_mask)
+ chip->irq_mask = pci_msi_mask_irq;
+ if (!chip->irq_unmask)
+ chip->irq_unmask = pci_msi_unmask_irq;
+ if (!chip->irq_set_affinity)
+ chip->irq_set_affinity = msi_domain_set_affinity;
+}
+
+/**
+ * msi_create_irq_domain - Create a MSI interrupt domain
+ * @of_node: Optional device-tree node of the interrupt controller
+ * @info: MSI domain info
+ * @parent: Parent irq domain
+ */
+struct irq_domain *msi_create_irq_domain(struct device_node *node,
+ struct msi_domain_info *info,
+ struct irq_domain *parent)
+{
+ if (info->flags & MSI_FLAG_USE_DEF_DOM_OPS)
+ msi_domain_update_dom_ops(info);
+ if (info->flags & MSI_FLAG_USE_DEF_CHIP_OPS)
+ msi_domain_update_chip_ops(info);
+
+ return irq_domain_add_hierarchy(parent, 0, 0, node, &msi_domain_ops,
+ info);
+}
+
+/**
+ * msi_domain_alloc_irqs - Allocate interrupts from a MSI interrupt domain
+ * @domain: The domain to allocate from
+ * @dev: Pointer to device struct of the device for which the interrupts
+ * are allocated
+ * @nvec: The number of interrupts to allocate
+ *
+ * Returns 0 on success or an error code.
+ */
+int msi_domain_alloc_irqs(struct irq_domain *domain, struct device *dev,
+ int nvec)
+{
+ struct msi_domain_info *info = domain->host_data;
+ struct msi_domain_ops *ops = info->ops;
+ msi_alloc_info_t arg;
+ struct msi_desc *desc;
+ int i, ret, virq = -1;
+
+ ret = ops->msi_check(domain, info, dev);
+ if (ret == 0)
+ ret = ops->msi_prepare(domain, dev, nvec, &arg);
+ if (ret)
+ return ret;
+
+ for_each_msi_entry(desc, dev) {
+ ops->set_desc(&arg, desc);
+ if (info->flags & MSI_FLAG_IDENTITY_MAP)
+ virq = (int)ops->get_hwirq(info, &arg);
+ else
+ virq = -1;
+
+ virq = __irq_domain_alloc_irqs(domain, virq, desc->nvec_used,
+ dev_to_node(dev), &arg, false);
+ if (virq < 0) {
+ ret = -ENOSPC;
+ if (ops->handle_error)
+ ret = ops->handle_error(domain, desc, ret);
+ if (ops->msi_finish)
+ ops->msi_finish(&arg, ret);
+ return ret;
+ }
+
+ for (i = 0; i < desc->nvec_used; i++)
+ irq_set_msi_desc_off(virq, i, desc);
+ }
+
+ if (ops->msi_finish)
+ ops->msi_finish(&arg, 0);
+
+ for_each_msi_entry(desc, dev) {
+ if (desc->nvec_used == 1)
+ dev_dbg(dev, "irq %d for MSI\n", virq);
+ else
+ dev_dbg(dev, "irq [%d-%d] for MSI\n",
+ virq, virq + desc->nvec_used - 1);
+ }
+
+ return 0;
+}
+
+/**
+ * msi_domain_free_irqs - Free interrupts from a MSI interrupt @domain associated tp @dev
+ * @domain: The domain to managing the interrupts
+ * @dev: Pointer to device struct of the device for which the interrupts
+ * are free
+ */
+void msi_domain_free_irqs(struct irq_domain *domain, struct device *dev)
+{
+ struct msi_desc *desc;
+
+ for_each_msi_entry(desc, dev) {
+ irq_domain_free_irqs(desc->irq, desc->nvec_used);
+ desc->irq = 0;
+ }
+}
+
+/**
+ * msi_get_domain_info - Get the MSI interrupt domain info for @domain
+ * @domain: The interrupt domain to retrieve data from
+ *
+ * Returns the pointer to the msi_domain_info stored in
+ * @domain->host_data.
+ */
+struct msi_domain_info *msi_get_domain_info(struct irq_domain *domain)
+{
+ return (struct msi_domain_info *)domain->host_data;
+}
+
+#endif /* CONFIG_GENERIC_MSI_IRQ_DOMAIN */
diff --git a/kernel/kmod.c b/kernel/kmod.c
index 80f7a6d..2777f40 100644
--- a/kernel/kmod.c
+++ b/kernel/kmod.c
@@ -47,13 +47,6 @@ extern int max_threads;
static struct workqueue_struct *khelper_wq;
-/*
- * kmod_thread_locker is used for deadlock avoidance. There is no explicit
- * locking to protect this global - it is private to the singleton khelper
- * thread and should only ever be modified by that thread.
- */
-static const struct task_struct *kmod_thread_locker;
-
#define CAP_BSET (void *)1
#define CAP_PI (void *)2
@@ -223,7 +216,6 @@ static void umh_complete(struct subprocess_info *sub_info)
static int ____call_usermodehelper(void *data)
{
struct subprocess_info *sub_info = data;
- int wait = sub_info->wait & ~UMH_KILLABLE;
struct cred *new;
int retval;
@@ -267,20 +259,13 @@ static int ____call_usermodehelper(void *data)
out:
sub_info->retval = retval;
/* wait_for_helper() will call umh_complete if UHM_WAIT_PROC. */
- if (wait != UMH_WAIT_PROC)
+ if (!(sub_info->wait & UMH_WAIT_PROC))
umh_complete(sub_info);
if (!retval)
return 0;
do_exit(0);
}
-static int call_helper(void *data)
-{
- /* Worker thread started blocking khelper thread. */
- kmod_thread_locker = current;
- return ____call_usermodehelper(data);
-}
-
/* Keventd can't block, but this (a child) can. */
static int wait_for_helper(void *data)
{
@@ -323,21 +308,14 @@ static void __call_usermodehelper(struct work_struct *work)
{
struct subprocess_info *sub_info =
container_of(work, struct subprocess_info, work);
- int wait = sub_info->wait & ~UMH_KILLABLE;
pid_t pid;
- /* CLONE_VFORK: wait until the usermode helper has execve'd
- * successfully We need the data structures to stay around
- * until that is done. */
- if (wait == UMH_WAIT_PROC)
+ if (sub_info->wait & UMH_WAIT_PROC)
pid = kernel_thread(wait_for_helper, sub_info,
CLONE_FS | CLONE_FILES | SIGCHLD);
- else {
- pid = kernel_thread(call_helper, sub_info,
- CLONE_VFORK | SIGCHLD);
- /* Worker thread stopped blocking khelper thread. */
- kmod_thread_locker = NULL;
- }
+ else
+ pid = kernel_thread(____call_usermodehelper, sub_info,
+ SIGCHLD);
if (pid < 0) {
sub_info->retval = pid;
@@ -571,17 +549,6 @@ int call_usermodehelper_exec(struct subprocess_info *sub_info, int wait)
goto out;
}
/*
- * Worker thread must not wait for khelper thread at below
- * wait_for_completion() if the thread was created with CLONE_VFORK
- * flag, for khelper thread is already waiting for the thread at
- * wait_for_completion() in do_fork().
- */
- if (wait != UMH_NO_WAIT && current == kmod_thread_locker) {
- retval = -EBUSY;
- goto out;
- }
-
- /*
* Set the completion pointer only if there is a waiter.
* This makes it possible to use umh_complete to free
* the data structure in case of UMH_NO_WAIT.
diff --git a/kernel/kprobes.c b/kernel/kprobes.c
index 3995f54..831978c 100644
--- a/kernel/kprobes.c
+++ b/kernel/kprobes.c
@@ -915,7 +915,7 @@ static struct kprobe *alloc_aggr_kprobe(struct kprobe *p)
#ifdef CONFIG_KPROBES_ON_FTRACE
static struct ftrace_ops kprobe_ftrace_ops __read_mostly = {
.func = kprobe_ftrace_handler,
- .flags = FTRACE_OPS_FL_SAVE_REGS,
+ .flags = FTRACE_OPS_FL_SAVE_REGS | FTRACE_OPS_FL_IPMODIFY,
};
static int kprobe_ftrace_enabled;
diff --git a/kernel/locking/mutex.c b/kernel/locking/mutex.c
index dadbf88..4541951 100644
--- a/kernel/locking/mutex.c
+++ b/kernel/locking/mutex.c
@@ -378,8 +378,14 @@ done:
* reschedule now, before we try-lock the mutex. This avoids getting
* scheduled out right after we obtained the mutex.
*/
- if (need_resched())
+ if (need_resched()) {
+ /*
+ * We _should_ have TASK_RUNNING here, but just in case
+ * we do not, make it so, otherwise we might get stuck.
+ */
+ __set_current_state(TASK_RUNNING);
schedule_preempt_disabled();
+ }
return false;
}
diff --git a/kernel/module.c b/kernel/module.c
index 88cec1d..e52a873 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -3097,6 +3097,32 @@ static int may_init_module(void)
}
/*
+ * Can't use wait_event_interruptible() because our condition
+ * 'finished_loading()' contains a blocking primitive itself (mutex_lock).
+ */
+static int wait_finished_loading(struct module *mod)
+{
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ int ret = 0;
+
+ add_wait_queue(&module_wq, &wait);
+ for (;;) {
+ if (finished_loading(mod->name))
+ break;
+
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
+ }
+ remove_wait_queue(&module_wq, &wait);
+
+ return ret;
+}
+
+/*
* We try to place it in the list now to make sure it's unique before
* we dedicate too many resources. In particular, temporary percpu
* memory exhaustion.
@@ -3116,8 +3142,8 @@ again:
|| old->state == MODULE_STATE_UNFORMED) {
/* Wait in case it fails to load. */
mutex_unlock(&module_mutex);
- err = wait_event_interruptible(module_wq,
- finished_loading(mod->name));
+
+ err = wait_finished_loading(mod);
if (err)
goto out_unlocked;
goto again;
diff --git a/kernel/panic.c b/kernel/panic.c
index cf80672..4d8d6f9 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -33,6 +33,7 @@ static int pause_on_oops;
static int pause_on_oops_flag;
static DEFINE_SPINLOCK(pause_on_oops_lock);
static bool crash_kexec_post_notifiers;
+int panic_on_warn __read_mostly;
int panic_timeout = CONFIG_PANIC_TIMEOUT;
EXPORT_SYMBOL_GPL(panic_timeout);
@@ -428,6 +429,17 @@ static void warn_slowpath_common(const char *file, int line, void *caller,
if (args)
vprintk(args->fmt, args->args);
+ if (panic_on_warn) {
+ /*
+ * This thread may hit another WARN() in the panic path.
+ * Resetting this prevents additional WARN() from panicking the
+ * system on this thread. Other threads are blocked by the
+ * panic_mutex in panic().
+ */
+ panic_on_warn = 0;
+ panic("panic_on_warn set ...\n");
+ }
+
print_modules();
dump_stack();
print_oops_end_marker();
@@ -485,6 +497,7 @@ EXPORT_SYMBOL(__stack_chk_fail);
core_param(panic, panic_timeout, int, 0644);
core_param(pause_on_oops, pause_on_oops, int, 0644);
+core_param(panic_on_warn, panic_on_warn, int, 0644);
static int __init setup_crash_kexec_post_notifiers(char *s)
{
diff --git a/kernel/pid.c b/kernel/pid.c
index 9b9a266..82430c8 100644
--- a/kernel/pid.c
+++ b/kernel/pid.c
@@ -341,6 +341,8 @@ out:
out_unlock:
spin_unlock_irq(&pidmap_lock);
+ put_pid_ns(ns);
+
out_free:
while (++i <= ns->level)
free_pidmap(pid->numbers + i);
diff --git a/kernel/pid_namespace.c b/kernel/pid_namespace.c
index db95d8e..bc6d6a8 100644
--- a/kernel/pid_namespace.c
+++ b/kernel/pid_namespace.c
@@ -190,7 +190,11 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
/* Don't allow any more processes into the pid namespace */
disable_pid_allocation(pid_ns);
- /* Ignore SIGCHLD causing any terminated children to autoreap */
+ /*
+ * Ignore SIGCHLD causing any terminated children to autoreap.
+ * This speeds up the namespace shutdown, plus see the comment
+ * below.
+ */
spin_lock_irq(&me->sighand->siglock);
me->sighand->action[SIGCHLD - 1].sa.sa_handler = SIG_IGN;
spin_unlock_irq(&me->sighand->siglock);
@@ -223,15 +227,31 @@ void zap_pid_ns_processes(struct pid_namespace *pid_ns)
}
read_unlock(&tasklist_lock);
- /* Firstly reap the EXIT_ZOMBIE children we may have. */
+ /*
+ * Reap the EXIT_ZOMBIE children we had before we ignored SIGCHLD.
+ * sys_wait4() will also block until our children traced from the
+ * parent namespace are detached and become EXIT_DEAD.
+ */
do {
clear_thread_flag(TIF_SIGPENDING);
rc = sys_wait4(-1, NULL, __WALL, NULL);
} while (rc != -ECHILD);
/*
- * sys_wait4() above can't reap the TASK_DEAD children.
- * Make sure they all go away, see free_pid().
+ * sys_wait4() above can't reap the EXIT_DEAD children but we do not
+ * really care, we could reparent them to the global init. We could
+ * exit and reap ->child_reaper even if it is not the last thread in
+ * this pid_ns, free_pid(nr_hashed == 0) calls proc_cleanup_work(),
+ * pid_ns can not go away until proc_kill_sb() drops the reference.
+ *
+ * But this ns can also have other tasks injected by setns()+fork().
+ * Again, ignoring the user visible semantics we do not really need
+ * to wait until they are all reaped, but they can be reparented to
+ * us and thus we need to ensure that pid->child_reaper stays valid
+ * until they all go away. See free_pid()->wake_up_process().
+ *
+ * We rely on ignored SIGCHLD, an injected zombie must be autoreaped
+ * if reparented.
*/
for (;;) {
set_current_state(TASK_UNINTERRUPTIBLE);
diff --git a/kernel/power/Kconfig b/kernel/power/Kconfig
index bbef57f..6e7708c 100644
--- a/kernel/power/Kconfig
+++ b/kernel/power/Kconfig
@@ -94,6 +94,7 @@ config PM_STD_PARTITION
config PM_SLEEP
def_bool y
depends on SUSPEND || HIBERNATE_CALLBACKS
+ select PM_RUNTIME
config PM_SLEEP_SMP
def_bool y
@@ -131,7 +132,6 @@ config PM_WAKELOCKS_GC
config PM_RUNTIME
bool "Run-time PM core functionality"
- depends on !IA64_HP_SIM
---help---
Enable functionality allowing I/O devices to be put into energy-saving
(low power) states at run time (or autosuspended) after a specified
@@ -298,14 +298,9 @@ config PM_GENERIC_DOMAINS_SLEEP
def_bool y
depends on PM_SLEEP && PM_GENERIC_DOMAINS
-config PM_GENERIC_DOMAINS_RUNTIME
- def_bool y
- depends on PM_RUNTIME && PM_GENERIC_DOMAINS
-
config PM_GENERIC_DOMAINS_OF
def_bool y
depends on PM_GENERIC_DOMAINS && OF
config CPU_PM
bool
- depends on SUSPEND || CPU_IDLE
diff --git a/kernel/power/hibernate.c b/kernel/power/hibernate.c
index 1f35a34..2329daa 100644
--- a/kernel/power/hibernate.c
+++ b/kernel/power/hibernate.c
@@ -28,6 +28,7 @@
#include <linux/syscore_ops.h>
#include <linux/ctype.h>
#include <linux/genhd.h>
+#include <linux/ktime.h>
#include <trace/events/power.h>
#include "power.h"
@@ -232,20 +233,17 @@ static void platform_recover(int platform_mode)
* @nr_pages: Number of memory pages processed between @start and @stop.
* @msg: Additional diagnostic message to print.
*/
-void swsusp_show_speed(struct timeval *start, struct timeval *stop,
- unsigned nr_pages, char *msg)
+void swsusp_show_speed(ktime_t start, ktime_t stop,
+ unsigned nr_pages, char *msg)
{
+ ktime_t diff;
u64 elapsed_centisecs64;
unsigned int centisecs;
unsigned int k;
unsigned int kps;
- elapsed_centisecs64 = timeval_to_ns(stop) - timeval_to_ns(start);
- /*
- * If "(s64)elapsed_centisecs64 < 0", it will print long elapsed time,
- * it is obvious enough for what went wrong.
- */
- do_div(elapsed_centisecs64, NSEC_PER_SEC / 100);
+ diff = ktime_sub(stop, start);
+ elapsed_centisecs64 = ktime_divns(diff, 10*NSEC_PER_MSEC);
centisecs = elapsed_centisecs64;
if (centisecs == 0)
centisecs = 1; /* avoid div-by-zero */
diff --git a/kernel/power/power.h b/kernel/power/power.h
index 2df883a..ce9b832 100644
--- a/kernel/power/power.h
+++ b/kernel/power/power.h
@@ -174,8 +174,7 @@ extern int hib_wait_on_bio_chain(struct bio **bio_chain);
struct timeval;
/* kernel/power/swsusp.c */
-extern void swsusp_show_speed(struct timeval *, struct timeval *,
- unsigned int, char *);
+extern void swsusp_show_speed(ktime_t, ktime_t, unsigned int, char *);
#ifdef CONFIG_SUSPEND
/* kernel/power/suspend.c */
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index 791a618..0c40c16 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -28,6 +28,7 @@
#include <linux/list.h>
#include <linux/slab.h>
#include <linux/compiler.h>
+#include <linux/ktime.h>
#include <asm/uaccess.h>
#include <asm/mmu_context.h>
@@ -1576,11 +1577,11 @@ int hibernate_preallocate_memory(void)
struct zone *zone;
unsigned long saveable, size, max_size, count, highmem, pages = 0;
unsigned long alloc, save_highmem, pages_highmem, avail_normal;
- struct timeval start, stop;
+ ktime_t start, stop;
int error;
printk(KERN_INFO "PM: Preallocating image memory... ");
- do_gettimeofday(&start);
+ start = ktime_get();
error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
if (error)
@@ -1709,9 +1710,9 @@ int hibernate_preallocate_memory(void)
free_unnecessary_pages();
out:
- do_gettimeofday(&stop);
+ stop = ktime_get();
printk(KERN_CONT "done (allocated %lu pages)\n", pages);
- swsusp_show_speed(&start, &stop, pages, "Allocated");
+ swsusp_show_speed(start, stop, pages, "Allocated");
return 0;
diff --git a/kernel/power/swap.c b/kernel/power/swap.c
index aaa3261..570aff8 100644
--- a/kernel/power/swap.c
+++ b/kernel/power/swap.c
@@ -30,6 +30,7 @@
#include <linux/atomic.h>
#include <linux/kthread.h>
#include <linux/crc32.h>
+#include <linux/ktime.h>
#include "power.h"
@@ -445,8 +446,8 @@ static int save_image(struct swap_map_handle *handle,
int nr_pages;
int err2;
struct bio *bio;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
printk(KERN_INFO "PM: Saving image data pages (%u pages)...\n",
nr_to_write);
@@ -455,7 +456,7 @@ static int save_image(struct swap_map_handle *handle,
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
while (1) {
ret = snapshot_read_next(snapshot);
if (ret <= 0)
@@ -469,12 +470,12 @@ static int save_image(struct swap_map_handle *handle,
nr_pages++;
}
err2 = hib_wait_on_bio_chain(&bio);
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret)
ret = err2;
if (!ret)
printk(KERN_INFO "PM: Image saving done.\n");
- swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+ swsusp_show_speed(start, stop, nr_to_write, "Wrote");
return ret;
}
@@ -580,8 +581,8 @@ static int save_image_lzo(struct swap_map_handle *handle,
int nr_pages;
int err2;
struct bio *bio;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
size_t off;
unsigned thr, run_threads, nr_threads;
unsigned char *page = NULL;
@@ -674,7 +675,7 @@ static int save_image_lzo(struct swap_map_handle *handle,
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
for (;;) {
for (thr = 0; thr < nr_threads; thr++) {
for (off = 0; off < LZO_UNC_SIZE; off += PAGE_SIZE) {
@@ -759,12 +760,12 @@ static int save_image_lzo(struct swap_map_handle *handle,
out_finish:
err2 = hib_wait_on_bio_chain(&bio);
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret)
ret = err2;
if (!ret)
printk(KERN_INFO "PM: Image saving done.\n");
- swsusp_show_speed(&start, &stop, nr_to_write, "Wrote");
+ swsusp_show_speed(start, stop, nr_to_write, "Wrote");
out_clean:
if (crc) {
if (crc->thr)
@@ -965,8 +966,8 @@ static int load_image(struct swap_map_handle *handle,
{
unsigned int m;
int ret = 0;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
struct bio *bio;
int err2;
unsigned nr_pages;
@@ -978,7 +979,7 @@ static int load_image(struct swap_map_handle *handle,
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
for ( ; ; ) {
ret = snapshot_write_next(snapshot);
if (ret <= 0)
@@ -996,7 +997,7 @@ static int load_image(struct swap_map_handle *handle,
nr_pages++;
}
err2 = hib_wait_on_bio_chain(&bio);
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret)
ret = err2;
if (!ret) {
@@ -1005,7 +1006,7 @@ static int load_image(struct swap_map_handle *handle,
if (!snapshot_image_loaded(snapshot))
ret = -ENODATA;
}
- swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+ swsusp_show_speed(start, stop, nr_to_read, "Read");
return ret;
}
@@ -1067,8 +1068,8 @@ static int load_image_lzo(struct swap_map_handle *handle,
int ret = 0;
int eof = 0;
struct bio *bio;
- struct timeval start;
- struct timeval stop;
+ ktime_t start;
+ ktime_t stop;
unsigned nr_pages;
size_t off;
unsigned i, thr, run_threads, nr_threads;
@@ -1190,7 +1191,7 @@ static int load_image_lzo(struct swap_map_handle *handle,
m = 1;
nr_pages = 0;
bio = NULL;
- do_gettimeofday(&start);
+ start = ktime_get();
ret = snapshot_write_next(snapshot);
if (ret <= 0)
@@ -1343,7 +1344,7 @@ out_finish:
wait_event(crc->done, atomic_read(&crc->stop));
atomic_set(&crc->stop, 0);
}
- do_gettimeofday(&stop);
+ stop = ktime_get();
if (!ret) {
printk(KERN_INFO "PM: Image loading done.\n");
snapshot_write_finalize(snapshot);
@@ -1359,7 +1360,7 @@ out_finish:
}
}
}
- swsusp_show_speed(&start, &stop, nr_to_read, "Read");
+ swsusp_show_speed(start, stop, nr_to_read, "Read");
out_clean:
for (i = 0; i < ring_size; i++)
free_page((unsigned long)page[i]);
@@ -1374,7 +1375,7 @@ out_clean:
kthread_stop(data[thr].thr);
vfree(data);
}
- if (page) vfree(page);
+ vfree(page);
return ret;
}
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
index ced2b84..f900dc9 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -62,9 +62,6 @@ int console_printk[4] = {
CONSOLE_LOGLEVEL_DEFAULT, /* default_console_loglevel */
};
-/* Deferred messaged from sched code are marked by this special level */
-#define SCHED_MESSAGE_LOGLEVEL -2
-
/*
* Low level drivers may need that to know if they can schedule in
* their unblank() callback or not. So let's export it.
@@ -480,7 +477,7 @@ static int syslog_action_restricted(int type)
type != SYSLOG_ACTION_SIZE_BUFFER;
}
-static int check_syslog_permissions(int type, bool from_file)
+int check_syslog_permissions(int type, bool from_file)
{
/*
* If this is from /proc/kmsg and we've already opened it, then we've
@@ -1259,7 +1256,7 @@ static int syslog_print_all(char __user *buf, int size, bool clear)
int do_syslog(int type, char __user *buf, int len, bool from_file)
{
bool clear = false;
- static int saved_console_loglevel = -1;
+ static int saved_console_loglevel = LOGLEVEL_DEFAULT;
int error;
error = check_syslog_permissions(type, from_file);
@@ -1316,15 +1313,15 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
break;
/* Disable logging to console */
case SYSLOG_ACTION_CONSOLE_OFF:
- if (saved_console_loglevel == -1)
+ if (saved_console_loglevel == LOGLEVEL_DEFAULT)
saved_console_loglevel = console_loglevel;
console_loglevel = minimum_console_loglevel;
break;
/* Enable logging to console */
case SYSLOG_ACTION_CONSOLE_ON:
- if (saved_console_loglevel != -1) {
+ if (saved_console_loglevel != LOGLEVEL_DEFAULT) {
console_loglevel = saved_console_loglevel;
- saved_console_loglevel = -1;
+ saved_console_loglevel = LOGLEVEL_DEFAULT;
}
break;
/* Set level of messages printed to console */
@@ -1336,7 +1333,7 @@ int do_syslog(int type, char __user *buf, int len, bool from_file)
len = minimum_console_loglevel;
console_loglevel = len;
/* Implicitly re-enable logging to console */
- saved_console_loglevel = -1;
+ saved_console_loglevel = LOGLEVEL_DEFAULT;
error = 0;
break;
/* Number of chars in the log buffer */
@@ -1627,10 +1624,10 @@ asmlinkage int vprintk_emit(int facility, int level,
int printed_len = 0;
bool in_sched = false;
/* cpu currently holding logbuf_lock in this function */
- static volatile unsigned int logbuf_cpu = UINT_MAX;
+ static unsigned int logbuf_cpu = UINT_MAX;
- if (level == SCHED_MESSAGE_LOGLEVEL) {
- level = -1;
+ if (level == LOGLEVEL_SCHED) {
+ level = LOGLEVEL_DEFAULT;
in_sched = true;
}
@@ -1695,8 +1692,9 @@ asmlinkage int vprintk_emit(int facility, int level,
const char *end_of_header = printk_skip_level(text);
switch (kern_level) {
case '0' ... '7':
- if (level == -1)
+ if (level == LOGLEVEL_DEFAULT)
level = kern_level - '0';
+ /* fallthrough */
case 'd': /* KERN_DEFAULT */
lflags |= LOG_PREFIX;
}
@@ -1710,7 +1708,7 @@ asmlinkage int vprintk_emit(int facility, int level,
}
}
- if (level == -1)
+ if (level == LOGLEVEL_DEFAULT)
level = default_message_loglevel;
if (dict)
@@ -1788,7 +1786,7 @@ EXPORT_SYMBOL(vprintk_emit);
asmlinkage int vprintk(const char *fmt, va_list args)
{
- return vprintk_emit(0, -1, NULL, 0, fmt, args);
+ return vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
}
EXPORT_SYMBOL(vprintk);
@@ -1807,6 +1805,30 @@ asmlinkage int printk_emit(int facility, int level,
}
EXPORT_SYMBOL(printk_emit);
+int vprintk_default(const char *fmt, va_list args)
+{
+ int r;
+
+#ifdef CONFIG_KGDB_KDB
+ if (unlikely(kdb_trap_printk)) {
+ r = vkdb_printf(fmt, args);
+ return r;
+ }
+#endif
+ r = vprintk_emit(0, LOGLEVEL_DEFAULT, NULL, 0, fmt, args);
+
+ return r;
+}
+EXPORT_SYMBOL_GPL(vprintk_default);
+
+/*
+ * This allows printk to be diverted to another function per cpu.
+ * This is useful for calling printk functions from within NMI
+ * without worrying about race conditions that can lock up the
+ * box.
+ */
+DEFINE_PER_CPU(printk_func_t, printk_func) = vprintk_default;
+
/**
* printk - print a kernel message
* @fmt: format string
@@ -1830,19 +1852,15 @@ EXPORT_SYMBOL(printk_emit);
*/
asmlinkage __visible int printk(const char *fmt, ...)
{
+ printk_func_t vprintk_func;
va_list args;
int r;
-#ifdef CONFIG_KGDB_KDB
- if (unlikely(kdb_trap_printk)) {
- va_start(args, fmt);
- r = vkdb_printf(fmt, args);
- va_end(args);
- return r;
- }
-#endif
va_start(args, fmt);
- r = vprintk_emit(0, -1, NULL, 0, fmt, args);
+ preempt_disable();
+ vprintk_func = this_cpu_read(printk_func);
+ r = vprintk_func(fmt, args);
+ preempt_enable();
va_end(args);
return r;
@@ -1876,28 +1894,28 @@ static size_t msg_print_text(const struct printk_log *msg, enum log_flags prev,
bool syslog, char *buf, size_t size) { return 0; }
static size_t cont_print_text(char *text, size_t size) { return 0; }
+/* Still needs to be defined for users */
+DEFINE_PER_CPU(printk_func_t, printk_func);
+
#endif /* CONFIG_PRINTK */
#ifdef CONFIG_EARLY_PRINTK
struct console *early_console;
-void early_vprintk(const char *fmt, va_list ap)
-{
- if (early_console) {
- char buf[512];
- int n = vscnprintf(buf, sizeof(buf), fmt, ap);
-
- early_console->write(early_console, buf, n);
- }
-}
-
asmlinkage __visible void early_printk(const char *fmt, ...)
{
va_list ap;
+ char buf[512];
+ int n;
+
+ if (!early_console)
+ return;
va_start(ap, fmt);
- early_vprintk(fmt, ap);
+ n = vscnprintf(buf, sizeof(buf), fmt, ap);
va_end(ap);
+
+ early_console->write(early_console, buf, n);
}
#endif
@@ -2634,7 +2652,7 @@ int printk_deferred(const char *fmt, ...)
preempt_disable();
va_start(args, fmt);
- r = vprintk_emit(0, SCHED_MESSAGE_LOGLEVEL, NULL, 0, fmt, args);
+ r = vprintk_emit(0, LOGLEVEL_SCHED, NULL, 0, fmt, args);
va_end(args);
__this_cpu_or(printk_pending, PRINTK_PENDING_OUTPUT);
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index 54e7522..1eb9d90 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -485,36 +485,19 @@ static int ptrace_detach(struct task_struct *child, unsigned int data)
/*
* Detach all tasks we were using ptrace on. Called with tasklist held
- * for writing, and returns with it held too. But note it can release
- * and reacquire the lock.
+ * for writing.
*/
-void exit_ptrace(struct task_struct *tracer)
- __releases(&tasklist_lock)
- __acquires(&tasklist_lock)
+void exit_ptrace(struct task_struct *tracer, struct list_head *dead)
{
struct task_struct *p, *n;
- LIST_HEAD(ptrace_dead);
-
- if (likely(list_empty(&tracer->ptraced)))
- return;
list_for_each_entry_safe(p, n, &tracer->ptraced, ptrace_entry) {
if (unlikely(p->ptrace & PT_EXITKILL))
send_sig_info(SIGKILL, SEND_SIG_FORCED, p);
if (__ptrace_detach(tracer, p))
- list_add(&p->ptrace_entry, &ptrace_dead);
- }
-
- write_unlock_irq(&tasklist_lock);
- BUG_ON(!list_empty(&tracer->ptraced));
-
- list_for_each_entry_safe(p, n, &ptrace_dead, ptrace_entry) {
- list_del_init(&p->ptrace_entry);
- release_task(p);
+ list_add(&p->ptrace_entry, dead);
}
-
- write_lock_irq(&tasklist_lock);
}
int ptrace_readdata(struct task_struct *tsk, unsigned long src, char __user *dst, int len)
diff --git a/kernel/rcu/Makefile b/kernel/rcu/Makefile
index 807ccfb..e6fae50 100644
--- a/kernel/rcu/Makefile
+++ b/kernel/rcu/Makefile
@@ -1,6 +1,6 @@
obj-y += update.o srcu.o
obj-$(CONFIG_RCU_TORTURE_TEST) += rcutorture.o
obj-$(CONFIG_TREE_RCU) += tree.o
-obj-$(CONFIG_TREE_PREEMPT_RCU) += tree.o
+obj-$(CONFIG_PREEMPT_RCU) += tree.o
obj-$(CONFIG_TREE_RCU_TRACE) += tree_trace.o
obj-$(CONFIG_TINY_RCU) += tiny.o
diff --git a/kernel/rcu/rcu.h b/kernel/rcu/rcu.h
index ff1a6de..07bb02e 100644
--- a/kernel/rcu/rcu.h
+++ b/kernel/rcu/rcu.h
@@ -135,4 +135,6 @@ int rcu_jiffies_till_stall_check(void);
*/
#define TPS(x) tracepoint_string(x)
+void rcu_early_boot_tests(void);
+
#endif /* __LINUX_RCU_H */
diff --git a/kernel/rcu/rcutorture.c b/kernel/rcu/rcutorture.c
index 240fa90..4d559ba 100644
--- a/kernel/rcu/rcutorture.c
+++ b/kernel/rcu/rcutorture.c
@@ -812,6 +812,7 @@ rcu_torture_cbflood(void *arg)
cur_ops->cb_barrier();
stutter_wait("rcu_torture_cbflood");
} while (!torture_must_stop());
+ vfree(rhp);
torture_kthread_stopping("rcu_torture_cbflood");
return 0;
}
diff --git a/kernel/rcu/tiny.c b/kernel/rcu/tiny.c
index c0623fc..0db5649 100644
--- a/kernel/rcu/tiny.c
+++ b/kernel/rcu/tiny.c
@@ -247,7 +247,7 @@ void rcu_bh_qs(void)
* be called from hardirq context. It is normally called from the
* scheduling-clock interrupt.
*/
-void rcu_check_callbacks(int cpu, int user)
+void rcu_check_callbacks(int user)
{
RCU_TRACE(check_cpu_stalls());
if (user || rcu_is_cpu_rrupt_from_idle())
@@ -380,7 +380,9 @@ void call_rcu_bh(struct rcu_head *head, void (*func)(struct rcu_head *rcu))
}
EXPORT_SYMBOL_GPL(call_rcu_bh);
-void rcu_init(void)
+void __init rcu_init(void)
{
open_softirq(RCU_SOFTIRQ, rcu_process_callbacks);
+
+ rcu_early_boot_tests();
}
diff --git a/kernel/rcu/tree.c b/kernel/rcu/tree.c
index 9815447..7680fc2 100644
--- a/kernel/rcu/tree.c
+++ b/kernel/rcu/tree.c
@@ -105,7 +105,7 @@ struct rcu_state sname##_state = { \
.name = RCU_STATE_NAME(sname), \
.abbr = sabbr, \
}; \
-DEFINE_PER_CPU(struct rcu_data, sname##_data)
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rcu_data, sname##_data)
RCU_STATE_INITIALIZER(rcu_sched, 's', call_rcu_sched);
RCU_STATE_INITIALIZER(rcu_bh, 'b', call_rcu_bh);
@@ -152,19 +152,6 @@ EXPORT_SYMBOL_GPL(rcu_scheduler_active);
*/
static int rcu_scheduler_fully_active __read_mostly;
-#ifdef CONFIG_RCU_BOOST
-
-/*
- * Control variables for per-CPU and per-rcu_node kthreads. These
- * handle all flavors of RCU.
- */
-static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
-DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
-DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
-DEFINE_PER_CPU(char, rcu_cpu_has_work);
-
-#endif /* #ifdef CONFIG_RCU_BOOST */
-
static void rcu_boost_kthread_setaffinity(struct rcu_node *rnp, int outgoingcpu);
static void invoke_rcu_core(void);
static void invoke_rcu_callbacks(struct rcu_state *rsp, struct rcu_data *rdp);
@@ -286,11 +273,11 @@ static void rcu_momentary_dyntick_idle(void)
* and requires special handling for preemptible RCU.
* The caller must have disabled preemption.
*/
-void rcu_note_context_switch(int cpu)
+void rcu_note_context_switch(void)
{
trace_rcu_utilization(TPS("Start context switch"));
rcu_sched_qs();
- rcu_preempt_note_context_switch(cpu);
+ rcu_preempt_note_context_switch();
if (unlikely(raw_cpu_read(rcu_sched_qs_mask)))
rcu_momentary_dyntick_idle();
trace_rcu_utilization(TPS("End context switch"));
@@ -325,7 +312,7 @@ static void force_qs_rnp(struct rcu_state *rsp,
unsigned long *maxj),
bool *isidle, unsigned long *maxj);
static void force_quiescent_state(struct rcu_state *rsp);
-static int rcu_pending(int cpu);
+static int rcu_pending(void);
/*
* Return the number of RCU-sched batches processed thus far for debug & stats.
@@ -510,11 +497,11 @@ cpu_needs_another_gp(struct rcu_state *rsp, struct rcu_data *rdp)
* we really have entered idle, and must do the appropriate accounting.
* The caller must have disabled interrupts.
*/
-static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
- bool user)
+static void rcu_eqs_enter_common(long long oldval, bool user)
{
struct rcu_state *rsp;
struct rcu_data *rdp;
+ struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
trace_rcu_dyntick(TPS("Start"), oldval, rdtp->dynticks_nesting);
if (!user && !is_idle_task(current)) {
@@ -531,7 +518,7 @@ static void rcu_eqs_enter_common(struct rcu_dynticks *rdtp, long long oldval,
rdp = this_cpu_ptr(rsp->rda);
do_nocb_deferred_wakeup(rdp);
}
- rcu_prepare_for_idle(smp_processor_id());
+ rcu_prepare_for_idle();
/* CPUs seeing atomic_inc() must see prior RCU read-side crit sects */
smp_mb__before_atomic(); /* See above. */
atomic_inc(&rdtp->dynticks);
@@ -565,7 +552,7 @@ static void rcu_eqs_enter(bool user)
WARN_ON_ONCE((oldval & DYNTICK_TASK_NEST_MASK) == 0);
if ((oldval & DYNTICK_TASK_NEST_MASK) == DYNTICK_TASK_NEST_VALUE) {
rdtp->dynticks_nesting = 0;
- rcu_eqs_enter_common(rdtp, oldval, user);
+ rcu_eqs_enter_common(oldval, user);
} else {
rdtp->dynticks_nesting -= DYNTICK_TASK_NEST_VALUE;
}
@@ -589,7 +576,7 @@ void rcu_idle_enter(void)
local_irq_save(flags);
rcu_eqs_enter(false);
- rcu_sysidle_enter(this_cpu_ptr(&rcu_dynticks), 0);
+ rcu_sysidle_enter(0);
local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(rcu_idle_enter);
@@ -639,8 +626,8 @@ void rcu_irq_exit(void)
if (rdtp->dynticks_nesting)
trace_rcu_dyntick(TPS("--="), oldval, rdtp->dynticks_nesting);
else
- rcu_eqs_enter_common(rdtp, oldval, true);
- rcu_sysidle_enter(rdtp, 1);
+ rcu_eqs_enter_common(oldval, true);
+ rcu_sysidle_enter(1);
local_irq_restore(flags);
}
@@ -651,16 +638,17 @@ void rcu_irq_exit(void)
* we really have exited idle, and must do the appropriate accounting.
* The caller must have disabled interrupts.
*/
-static void rcu_eqs_exit_common(struct rcu_dynticks *rdtp, long long oldval,
- int user)
+static void rcu_eqs_exit_common(long long oldval, int user)
{
+ struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
+
rcu_dynticks_task_exit();
smp_mb__before_atomic(); /* Force ordering w/previous sojourn. */
atomic_inc(&rdtp->dynticks);
/* CPUs seeing atomic_inc() must see later RCU read-side crit sects */
smp_mb__after_atomic(); /* See above. */
WARN_ON_ONCE(!(atomic_read(&rdtp->dynticks) & 0x1));
- rcu_cleanup_after_idle(smp_processor_id());
+ rcu_cleanup_after_idle();
trace_rcu_dyntick(TPS("End"), oldval, rdtp->dynticks_nesting);
if (!user && !is_idle_task(current)) {
struct task_struct *idle __maybe_unused =
@@ -691,7 +679,7 @@ static void rcu_eqs_exit(bool user)
rdtp->dynticks_nesting += DYNTICK_TASK_NEST_VALUE;
} else {
rdtp->dynticks_nesting = DYNTICK_TASK_EXIT_IDLE;
- rcu_eqs_exit_common(rdtp, oldval, user);
+ rcu_eqs_exit_common(oldval, user);
}
}
@@ -712,7 +700,7 @@ void rcu_idle_exit(void)
local_irq_save(flags);
rcu_eqs_exit(false);
- rcu_sysidle_exit(this_cpu_ptr(&rcu_dynticks), 0);
+ rcu_sysidle_exit(0);
local_irq_restore(flags);
}
EXPORT_SYMBOL_GPL(rcu_idle_exit);
@@ -763,8 +751,8 @@ void rcu_irq_enter(void)
if (oldval)
trace_rcu_dyntick(TPS("++="), oldval, rdtp->dynticks_nesting);
else
- rcu_eqs_exit_common(rdtp, oldval, true);
- rcu_sysidle_exit(rdtp, 1);
+ rcu_eqs_exit_common(oldval, true);
+ rcu_sysidle_exit(1);
local_irq_restore(flags);
}
@@ -2387,7 +2375,7 @@ static void rcu_do_batch(struct rcu_state *rsp, struct rcu_data *rdp)
* invoked from the scheduling-clock interrupt. If rcu_pending returns
* false, there is no point in invoking rcu_check_callbacks().
*/
-void rcu_check_callbacks(int cpu, int user)
+void rcu_check_callbacks(int user)
{
trace_rcu_utilization(TPS("Start scheduler-tick"));
increment_cpu_stall_ticks();
@@ -2419,8 +2407,8 @@ void rcu_check_callbacks(int cpu, int user)
rcu_bh_qs();
}
- rcu_preempt_check_callbacks(cpu);
- if (rcu_pending(cpu))
+ rcu_preempt_check_callbacks();
+ if (rcu_pending())
invoke_rcu_core();
if (user)
rcu_note_voluntary_context_switch(current);
@@ -2963,6 +2951,9 @@ static int synchronize_sched_expedited_cpu_stop(void *data)
*/
void synchronize_sched_expedited(void)
{
+ cpumask_var_t cm;
+ bool cma = false;
+ int cpu;
long firstsnap, s, snap;
int trycount = 0;
struct rcu_state *rsp = &rcu_sched_state;
@@ -2997,11 +2988,26 @@ void synchronize_sched_expedited(void)
}
WARN_ON_ONCE(cpu_is_offline(raw_smp_processor_id()));
+ /* Offline CPUs, idle CPUs, and any CPU we run on are quiescent. */
+ cma = zalloc_cpumask_var(&cm, GFP_KERNEL);
+ if (cma) {
+ cpumask_copy(cm, cpu_online_mask);
+ cpumask_clear_cpu(raw_smp_processor_id(), cm);
+ for_each_cpu(cpu, cm) {
+ struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+
+ if (!(atomic_add_return(0, &rdtp->dynticks) & 0x1))
+ cpumask_clear_cpu(cpu, cm);
+ }
+ if (cpumask_weight(cm) == 0)
+ goto all_cpus_idle;
+ }
+
/*
* Each pass through the following loop attempts to force a
* context switch on each CPU.
*/
- while (try_stop_cpus(cpu_online_mask,
+ while (try_stop_cpus(cma ? cm : cpu_online_mask,
synchronize_sched_expedited_cpu_stop,
NULL) == -EAGAIN) {
put_online_cpus();
@@ -3013,6 +3019,7 @@ void synchronize_sched_expedited(void)
/* ensure test happens before caller kfree */
smp_mb__before_atomic(); /* ^^^ */
atomic_long_inc(&rsp->expedited_workdone1);
+ free_cpumask_var(cm);
return;
}
@@ -3022,6 +3029,7 @@ void synchronize_sched_expedited(void)
} else {
wait_rcu_gp(call_rcu_sched);
atomic_long_inc(&rsp->expedited_normal);
+ free_cpumask_var(cm);
return;
}
@@ -3031,6 +3039,7 @@ void synchronize_sched_expedited(void)
/* ensure test happens before caller kfree */
smp_mb__before_atomic(); /* ^^^ */
atomic_long_inc(&rsp->expedited_workdone2);
+ free_cpumask_var(cm);
return;
}
@@ -3045,6 +3054,7 @@ void synchronize_sched_expedited(void)
/* CPU hotplug operation in flight, use normal GP. */
wait_rcu_gp(call_rcu_sched);
atomic_long_inc(&rsp->expedited_normal);
+ free_cpumask_var(cm);
return;
}
snap = atomic_long_read(&rsp->expedited_start);
@@ -3052,6 +3062,9 @@ void synchronize_sched_expedited(void)
}
atomic_long_inc(&rsp->expedited_stoppedcpus);
+all_cpus_idle:
+ free_cpumask_var(cm);
+
/*
* Everyone up to our most recent fetch is covered by our grace
* period. Update the counter, but only if our work is still
@@ -3143,12 +3156,12 @@ static int __rcu_pending(struct rcu_state *rsp, struct rcu_data *rdp)
* by the current CPU, returning 1 if so. This function is part of the
* RCU implementation; it is -not- an exported member of the RCU API.
*/
-static int rcu_pending(int cpu)
+static int rcu_pending(void)
{
struct rcu_state *rsp;
for_each_rcu_flavor(rsp)
- if (__rcu_pending(rsp, per_cpu_ptr(rsp->rda, cpu)))
+ if (__rcu_pending(rsp, this_cpu_ptr(rsp->rda)))
return 1;
return 0;
}
@@ -3158,7 +3171,7 @@ static int rcu_pending(int cpu)
* non-NULL, store an indication of whether all callbacks are lazy.
* (If there are no callbacks, all of them are deemed to be lazy.)
*/
-static int __maybe_unused rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
+static int __maybe_unused rcu_cpu_has_callbacks(bool *all_lazy)
{
bool al = true;
bool hc = false;
@@ -3166,7 +3179,7 @@ static int __maybe_unused rcu_cpu_has_callbacks(int cpu, bool *all_lazy)
struct rcu_state *rsp;
for_each_rcu_flavor(rsp) {
- rdp = per_cpu_ptr(rsp->rda, cpu);
+ rdp = this_cpu_ptr(rsp->rda);
if (!rdp->nxtlist)
continue;
hc = true;
@@ -3485,8 +3498,10 @@ static int rcu_cpu_notify(struct notifier_block *self,
case CPU_DEAD_FROZEN:
case CPU_UP_CANCELED:
case CPU_UP_CANCELED_FROZEN:
- for_each_rcu_flavor(rsp)
+ for_each_rcu_flavor(rsp) {
rcu_cleanup_dead_cpu(cpu, rsp);
+ do_nocb_deferred_wakeup(per_cpu_ptr(rsp->rda, cpu));
+ }
break;
default:
break;
@@ -3766,6 +3781,8 @@ void __init rcu_init(void)
pm_notifier(rcu_pm_notify, 0);
for_each_online_cpu(cpu)
rcu_cpu_notify(NULL, CPU_UP_PREPARE, (void *)(long)cpu);
+
+ rcu_early_boot_tests();
}
#include "tree_plugin.h"
diff --git a/kernel/rcu/tree.h b/kernel/rcu/tree.h
index bbdc45d..8e7b184 100644
--- a/kernel/rcu/tree.h
+++ b/kernel/rcu/tree.h
@@ -139,7 +139,7 @@ struct rcu_node {
unsigned long expmask; /* Groups that have ->blkd_tasks */
/* elements that need to drain to allow the */
/* current expedited grace period to */
- /* complete (only for TREE_PREEMPT_RCU). */
+ /* complete (only for PREEMPT_RCU). */
unsigned long qsmaskinit;
/* Per-GP initial value for qsmask & expmask. */
unsigned long grpmask; /* Mask to apply to parent qsmask. */
@@ -530,10 +530,10 @@ DECLARE_PER_CPU(struct rcu_data, rcu_sched_data);
extern struct rcu_state rcu_bh_state;
DECLARE_PER_CPU(struct rcu_data, rcu_bh_data);
-#ifdef CONFIG_TREE_PREEMPT_RCU
+#ifdef CONFIG_PREEMPT_RCU
extern struct rcu_state rcu_preempt_state;
DECLARE_PER_CPU(struct rcu_data, rcu_preempt_data);
-#endif /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+#endif /* #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_RCU_BOOST
DECLARE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
@@ -547,7 +547,7 @@ DECLARE_PER_CPU(char, rcu_cpu_has_work);
/* Forward declarations for rcutree_plugin.h */
static void rcu_bootup_announce(void);
long rcu_batches_completed(void);
-static void rcu_preempt_note_context_switch(int cpu);
+static void rcu_preempt_note_context_switch(void);
static int rcu_preempt_blocked_readers_cgp(struct rcu_node *rnp);
#ifdef CONFIG_HOTPLUG_CPU
static void rcu_report_unblock_qs_rnp(struct rcu_node *rnp,
@@ -561,12 +561,12 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
struct rcu_node *rnp,
struct rcu_data *rdp);
#endif /* #ifdef CONFIG_HOTPLUG_CPU */
-static void rcu_preempt_check_callbacks(int cpu);
+static void rcu_preempt_check_callbacks(void);
void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *rcu));
-#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU)
+#if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PREEMPT_RCU)
static void rcu_report_exp_rnp(struct rcu_state *rsp, struct rcu_node *rnp,
bool wake);
-#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_TREE_PREEMPT_RCU) */
+#endif /* #if defined(CONFIG_HOTPLUG_CPU) || defined(CONFIG_PREEMPT_RCU) */
static void __init __rcu_init_preempt(void);
static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags);
static void rcu_preempt_boost_start_gp(struct rcu_node *rnp);
@@ -579,8 +579,8 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
#endif /* #ifdef CONFIG_RCU_BOOST */
static void __init rcu_spawn_boost_kthreads(void);
static void rcu_prepare_kthreads(int cpu);
-static void rcu_cleanup_after_idle(int cpu);
-static void rcu_prepare_for_idle(int cpu);
+static void rcu_cleanup_after_idle(void);
+static void rcu_prepare_for_idle(void);
static void rcu_idle_count_callbacks_posted(void);
static void print_cpu_stall_info_begin(void);
static void print_cpu_stall_info(struct rcu_state *rsp, int cpu);
@@ -606,8 +606,8 @@ static void __init rcu_organize_nocb_kthreads(struct rcu_state *rsp);
#endif /* #ifdef CONFIG_RCU_NOCB_CPU */
static void __maybe_unused rcu_kick_nohz_cpu(int cpu);
static bool init_nocb_callback_list(struct rcu_data *rdp);
-static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq);
-static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq);
+static void rcu_sysidle_enter(int irq);
+static void rcu_sysidle_exit(int irq);
static void rcu_sysidle_check_cpu(struct rcu_data *rdp, bool *isidle,
unsigned long *maxj);
static bool is_sysidle_rcu_state(struct rcu_state *rsp);
diff --git a/kernel/rcu/tree_plugin.h b/kernel/rcu/tree_plugin.h
index c1d7f27..3ec85cb 100644
--- a/kernel/rcu/tree_plugin.h
+++ b/kernel/rcu/tree_plugin.h
@@ -30,14 +30,24 @@
#include <linux/smpboot.h>
#include "../time/tick-internal.h"
-#define RCU_KTHREAD_PRIO 1
-
#ifdef CONFIG_RCU_BOOST
+
#include "../locking/rtmutex_common.h"
-#define RCU_BOOST_PRIO CONFIG_RCU_BOOST_PRIO
-#else
-#define RCU_BOOST_PRIO RCU_KTHREAD_PRIO
-#endif
+
+/* rcuc/rcub kthread realtime priority */
+static int kthread_prio = CONFIG_RCU_KTHREAD_PRIO;
+module_param(kthread_prio, int, 0644);
+
+/*
+ * Control variables for per-CPU and per-rcu_node kthreads. These
+ * handle all flavors of RCU.
+ */
+static DEFINE_PER_CPU(struct task_struct *, rcu_cpu_kthread_task);
+DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_status);
+DEFINE_PER_CPU(unsigned int, rcu_cpu_kthread_loops);
+DEFINE_PER_CPU(char, rcu_cpu_has_work);
+
+#endif /* #ifdef CONFIG_RCU_BOOST */
#ifdef CONFIG_RCU_NOCB_CPU
static cpumask_var_t rcu_nocb_mask; /* CPUs to have callbacks offloaded. */
@@ -72,9 +82,6 @@ static void __init rcu_bootup_announce_oddness(void)
#ifdef CONFIG_RCU_TORTURE_TEST_RUNNABLE
pr_info("\tRCU torture testing starts during boot.\n");
#endif
-#if defined(CONFIG_TREE_PREEMPT_RCU) && !defined(CONFIG_RCU_CPU_STALL_VERBOSE)
- pr_info("\tDump stacks of tasks blocking RCU-preempt GP.\n");
-#endif
#if defined(CONFIG_RCU_CPU_STALL_INFO)
pr_info("\tAdditional per-CPU info printed with stalls.\n");
#endif
@@ -85,9 +92,12 @@ static void __init rcu_bootup_announce_oddness(void)
pr_info("\tBoot-time adjustment of leaf fanout to %d.\n", rcu_fanout_leaf);
if (nr_cpu_ids != NR_CPUS)
pr_info("\tRCU restricting CPUs from NR_CPUS=%d to nr_cpu_ids=%d.\n", NR_CPUS, nr_cpu_ids);
+#ifdef CONFIG_RCU_BOOST
+ pr_info("\tRCU kthread priority: %d.\n", kthread_prio);
+#endif
}
-#ifdef CONFIG_TREE_PREEMPT_RCU
+#ifdef CONFIG_PREEMPT_RCU
RCU_STATE_INITIALIZER(rcu_preempt, 'p', call_rcu);
static struct rcu_state *rcu_state_p = &rcu_preempt_state;
@@ -156,7 +166,7 @@ static void rcu_preempt_qs(void)
*
* Caller must disable preemption.
*/
-static void rcu_preempt_note_context_switch(int cpu)
+static void rcu_preempt_note_context_switch(void)
{
struct task_struct *t = current;
unsigned long flags;
@@ -167,7 +177,7 @@ static void rcu_preempt_note_context_switch(int cpu)
!t->rcu_read_unlock_special.b.blocked) {
/* Possibly blocking in an RCU read-side critical section. */
- rdp = per_cpu_ptr(rcu_preempt_state.rda, cpu);
+ rdp = this_cpu_ptr(rcu_preempt_state.rda);
rnp = rdp->mynode;
raw_spin_lock_irqsave(&rnp->lock, flags);
smp_mb__after_unlock_lock();
@@ -415,8 +425,6 @@ void rcu_read_unlock_special(struct task_struct *t)
}
}
-#ifdef CONFIG_RCU_CPU_STALL_VERBOSE
-
/*
* Dump detailed information for all tasks blocking the current RCU
* grace period on the specified rcu_node structure.
@@ -451,14 +459,6 @@ static void rcu_print_detail_task_stall(struct rcu_state *rsp)
rcu_print_detail_task_stall_rnp(rnp);
}
-#else /* #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */
-
-static void rcu_print_detail_task_stall(struct rcu_state *rsp)
-{
-}
-
-#endif /* #else #ifdef CONFIG_RCU_CPU_STALL_VERBOSE */
-
#ifdef CONFIG_RCU_CPU_STALL_INFO
static void rcu_print_task_stall_begin(struct rcu_node *rnp)
@@ -621,7 +621,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
*
* Caller must disable hard irqs.
*/
-static void rcu_preempt_check_callbacks(int cpu)
+static void rcu_preempt_check_callbacks(void)
{
struct task_struct *t = current;
@@ -630,8 +630,8 @@ static void rcu_preempt_check_callbacks(int cpu)
return;
}
if (t->rcu_read_lock_nesting > 0 &&
- per_cpu(rcu_preempt_data, cpu).qs_pending &&
- !per_cpu(rcu_preempt_data, cpu).passed_quiesce)
+ __this_cpu_read(rcu_preempt_data.qs_pending) &&
+ !__this_cpu_read(rcu_preempt_data.passed_quiesce))
t->rcu_read_unlock_special.b.need_qs = true;
}
@@ -919,7 +919,7 @@ void exit_rcu(void)
__rcu_read_unlock();
}
-#else /* #ifdef CONFIG_TREE_PREEMPT_RCU */
+#else /* #ifdef CONFIG_PREEMPT_RCU */
static struct rcu_state *rcu_state_p = &rcu_sched_state;
@@ -945,7 +945,7 @@ EXPORT_SYMBOL_GPL(rcu_batches_completed);
* Because preemptible RCU does not exist, we never have to check for
* CPUs being in quiescent states.
*/
-static void rcu_preempt_note_context_switch(int cpu)
+static void rcu_preempt_note_context_switch(void)
{
}
@@ -1017,7 +1017,7 @@ static int rcu_preempt_offline_tasks(struct rcu_state *rsp,
* Because preemptible RCU does not exist, it never has any callbacks
* to check.
*/
-static void rcu_preempt_check_callbacks(int cpu)
+static void rcu_preempt_check_callbacks(void)
{
}
@@ -1070,7 +1070,7 @@ void exit_rcu(void)
{
}
-#endif /* #else #ifdef CONFIG_TREE_PREEMPT_RCU */
+#endif /* #else #ifdef CONFIG_PREEMPT_RCU */
#ifdef CONFIG_RCU_BOOST
@@ -1326,7 +1326,7 @@ static int rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
smp_mb__after_unlock_lock();
rnp->boost_kthread_task = t;
raw_spin_unlock_irqrestore(&rnp->lock, flags);
- sp.sched_priority = RCU_BOOST_PRIO;
+ sp.sched_priority = kthread_prio;
sched_setscheduler_nocheck(t, SCHED_FIFO, &sp);
wake_up_process(t); /* get to TASK_INTERRUPTIBLE quickly. */
return 0;
@@ -1343,7 +1343,7 @@ static void rcu_cpu_kthread_setup(unsigned int cpu)
{
struct sched_param sp;
- sp.sched_priority = RCU_KTHREAD_PRIO;
+ sp.sched_priority = kthread_prio;
sched_setscheduler_nocheck(current, SCHED_FIFO, &sp);
}
@@ -1512,10 +1512,10 @@ static void rcu_prepare_kthreads(int cpu)
* any flavor of RCU.
*/
#ifndef CONFIG_RCU_NOCB_CPU_ALL
-int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
+int rcu_needs_cpu(unsigned long *delta_jiffies)
{
*delta_jiffies = ULONG_MAX;
- return rcu_cpu_has_callbacks(cpu, NULL);
+ return rcu_cpu_has_callbacks(NULL);
}
#endif /* #ifndef CONFIG_RCU_NOCB_CPU_ALL */
@@ -1523,7 +1523,7 @@ int rcu_needs_cpu(int cpu, unsigned long *delta_jiffies)
* Because we do not have RCU_FAST_NO_HZ, don't bother cleaning up
* after it.
*/
-static void rcu_cleanup_after_idle(int cpu)
+static void rcu_cleanup_after_idle(void)
{
}
@@ -1531,7 +1531,7 @@ static void rcu_cleanup_after_idle(int cpu)
* Do the idle-entry grace-period work, which, because CONFIG_RCU_FAST_NO_HZ=n,
* is nothing.
*/
-static void rcu_prepare_for_idle(int cpu)
+static void rcu_prepare_for_idle(void)
{
}
@@ -1624,15 +1624,15 @@ static bool __maybe_unused rcu_try_advance_all_cbs(void)
* The caller must have disabled interrupts.
*/
#ifndef CONFIG_RCU_NOCB_CPU_ALL
-int rcu_needs_cpu(int cpu, unsigned long *dj)
+int rcu_needs_cpu(unsigned long *dj)
{
- struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+ struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
/* Snapshot to detect later posting of non-lazy callback. */
rdtp->nonlazy_posted_snap = rdtp->nonlazy_posted;
/* If no callbacks, RCU doesn't need the CPU. */
- if (!rcu_cpu_has_callbacks(cpu, &rdtp->all_lazy)) {
+ if (!rcu_cpu_has_callbacks(&rdtp->all_lazy)) {
*dj = ULONG_MAX;
return 0;
}
@@ -1666,12 +1666,12 @@ int rcu_needs_cpu(int cpu, unsigned long *dj)
*
* The caller must have disabled interrupts.
*/
-static void rcu_prepare_for_idle(int cpu)
+static void rcu_prepare_for_idle(void)
{
#ifndef CONFIG_RCU_NOCB_CPU_ALL
bool needwake;
struct rcu_data *rdp;
- struct rcu_dynticks *rdtp = &per_cpu(rcu_dynticks, cpu);
+ struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
struct rcu_node *rnp;
struct rcu_state *rsp;
int tne;
@@ -1679,7 +1679,7 @@ static void rcu_prepare_for_idle(int cpu)
/* Handle nohz enablement switches conservatively. */
tne = ACCESS_ONCE(tick_nohz_active);
if (tne != rdtp->tick_nohz_enabled_snap) {
- if (rcu_cpu_has_callbacks(cpu, NULL))
+ if (rcu_cpu_has_callbacks(NULL))
invoke_rcu_core(); /* force nohz to see update. */
rdtp->tick_nohz_enabled_snap = tne;
return;
@@ -1688,7 +1688,7 @@ static void rcu_prepare_for_idle(int cpu)
return;
/* If this is a no-CBs CPU, no callbacks, just return. */
- if (rcu_is_nocb_cpu(cpu))
+ if (rcu_is_nocb_cpu(smp_processor_id()))
return;
/*
@@ -1712,7 +1712,7 @@ static void rcu_prepare_for_idle(int cpu)
return;
rdtp->last_accelerate = jiffies;
for_each_rcu_flavor(rsp) {
- rdp = per_cpu_ptr(rsp->rda, cpu);
+ rdp = this_cpu_ptr(rsp->rda);
if (!*rdp->nxttail[RCU_DONE_TAIL])
continue;
rnp = rdp->mynode;
@@ -1731,10 +1731,10 @@ static void rcu_prepare_for_idle(int cpu)
* any grace periods that elapsed while the CPU was idle, and if any
* callbacks are now ready to invoke, initiate invocation.
*/
-static void rcu_cleanup_after_idle(int cpu)
+static void rcu_cleanup_after_idle(void)
{
#ifndef CONFIG_RCU_NOCB_CPU_ALL
- if (rcu_is_nocb_cpu(cpu))
+ if (rcu_is_nocb_cpu(smp_processor_id()))
return;
if (rcu_try_advance_all_cbs())
invoke_rcu_core();
@@ -2573,9 +2573,13 @@ static void rcu_spawn_one_nocb_kthread(struct rcu_state *rsp, int cpu)
rdp->nocb_leader = rdp_spawn;
if (rdp_last && rdp != rdp_spawn)
rdp_last->nocb_next_follower = rdp;
- rdp_last = rdp;
- rdp = rdp->nocb_next_follower;
- rdp_last->nocb_next_follower = NULL;
+ if (rdp == rdp_spawn) {
+ rdp = rdp->nocb_next_follower;
+ } else {
+ rdp_last = rdp;
+ rdp = rdp->nocb_next_follower;
+ rdp_last->nocb_next_follower = NULL;
+ }
} while (rdp);
rdp_spawn->nocb_next_follower = rdp_old_leader;
}
@@ -2761,9 +2765,10 @@ static int full_sysidle_state; /* Current system-idle state. */
* to detect full-system idle states, not RCU quiescent states and grace
* periods. The caller must have disabled interrupts.
*/
-static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
+static void rcu_sysidle_enter(int irq)
{
unsigned long j;
+ struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
/* If there are no nohz_full= CPUs, no need to track this. */
if (!tick_nohz_full_enabled())
@@ -2832,8 +2837,10 @@ void rcu_sysidle_force_exit(void)
* usermode execution does -not- count as idle here! The caller must
* have disabled interrupts.
*/
-static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
+static void rcu_sysidle_exit(int irq)
{
+ struct rcu_dynticks *rdtp = this_cpu_ptr(&rcu_dynticks);
+
/* If there are no nohz_full= CPUs, no need to track this. */
if (!tick_nohz_full_enabled())
return;
@@ -3127,11 +3134,11 @@ static void rcu_sysidle_init_percpu_data(struct rcu_dynticks *rdtp)
#else /* #ifdef CONFIG_NO_HZ_FULL_SYSIDLE */
-static void rcu_sysidle_enter(struct rcu_dynticks *rdtp, int irq)
+static void rcu_sysidle_enter(int irq)
{
}
-static void rcu_sysidle_exit(struct rcu_dynticks *rdtp, int irq)
+static void rcu_sysidle_exit(int irq)
{
}
diff --git a/kernel/rcu/update.c b/kernel/rcu/update.c
index 3ef8ba5..e0d31a345 100644
--- a/kernel/rcu/update.c
+++ b/kernel/rcu/update.c
@@ -306,7 +306,7 @@ struct debug_obj_descr rcuhead_debug_descr = {
EXPORT_SYMBOL_GPL(rcuhead_debug_descr);
#endif /* #ifdef CONFIG_DEBUG_OBJECTS_RCU_HEAD */
-#if defined(CONFIG_TREE_RCU) || defined(CONFIG_TREE_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE)
+#if defined(CONFIG_TREE_RCU) || defined(CONFIG_PREEMPT_RCU) || defined(CONFIG_RCU_TRACE)
void do_trace_rcu_torture_read(const char *rcutorturename, struct rcu_head *rhp,
unsigned long secs,
unsigned long c_old, unsigned long c)
@@ -531,7 +531,8 @@ static int __noreturn rcu_tasks_kthread(void *arg)
struct rcu_head *next;
LIST_HEAD(rcu_tasks_holdouts);
- /* FIXME: Add housekeeping affinity. */
+ /* Run on housekeeping CPUs by default. Sysadm can move if desired. */
+ housekeeping_affine(current);
/*
* Each pass through the following loop makes one check for
@@ -690,3 +691,87 @@ static void rcu_spawn_tasks_kthread(void)
}
#endif /* #ifdef CONFIG_TASKS_RCU */
+
+#ifdef CONFIG_PROVE_RCU
+
+/*
+ * Early boot self test parameters, one for each flavor
+ */
+static bool rcu_self_test;
+static bool rcu_self_test_bh;
+static bool rcu_self_test_sched;
+
+module_param(rcu_self_test, bool, 0444);
+module_param(rcu_self_test_bh, bool, 0444);
+module_param(rcu_self_test_sched, bool, 0444);
+
+static int rcu_self_test_counter;
+
+static void test_callback(struct rcu_head *r)
+{
+ rcu_self_test_counter++;
+ pr_info("RCU test callback executed %d\n", rcu_self_test_counter);
+}
+
+static void early_boot_test_call_rcu(void)
+{
+ static struct rcu_head head;
+
+ call_rcu(&head, test_callback);
+}
+
+static void early_boot_test_call_rcu_bh(void)
+{
+ static struct rcu_head head;
+
+ call_rcu_bh(&head, test_callback);
+}
+
+static void early_boot_test_call_rcu_sched(void)
+{
+ static struct rcu_head head;
+
+ call_rcu_sched(&head, test_callback);
+}
+
+void rcu_early_boot_tests(void)
+{
+ pr_info("Running RCU self tests\n");
+
+ if (rcu_self_test)
+ early_boot_test_call_rcu();
+ if (rcu_self_test_bh)
+ early_boot_test_call_rcu_bh();
+ if (rcu_self_test_sched)
+ early_boot_test_call_rcu_sched();
+}
+
+static int rcu_verify_early_boot_tests(void)
+{
+ int ret = 0;
+ int early_boot_test_counter = 0;
+
+ if (rcu_self_test) {
+ early_boot_test_counter++;
+ rcu_barrier();
+ }
+ if (rcu_self_test_bh) {
+ early_boot_test_counter++;
+ rcu_barrier_bh();
+ }
+ if (rcu_self_test_sched) {
+ early_boot_test_counter++;
+ rcu_barrier_sched();
+ }
+
+ if (rcu_self_test_counter != early_boot_test_counter) {
+ WARN_ON(1);
+ ret = -1;
+ }
+
+ return ret;
+}
+late_initcall(rcu_verify_early_boot_tests);
+#else
+void rcu_early_boot_tests(void) {}
+#endif /* CONFIG_PROVE_RCU */
diff --git a/kernel/res_counter.c b/kernel/res_counter.c
deleted file mode 100644
index e791130..0000000
--- a/kernel/res_counter.c
+++ /dev/null
@@ -1,211 +0,0 @@
-/*
- * resource cgroups
- *
- * Copyright 2007 OpenVZ SWsoft Inc
- *
- * Author: Pavel Emelianov <xemul@openvz.org>
- *
- */
-
-#include <linux/types.h>
-#include <linux/parser.h>
-#include <linux/fs.h>
-#include <linux/res_counter.h>
-#include <linux/uaccess.h>
-#include <linux/mm.h>
-
-void res_counter_init(struct res_counter *counter, struct res_counter *parent)
-{
- spin_lock_init(&counter->lock);
- counter->limit = RES_COUNTER_MAX;
- counter->soft_limit = RES_COUNTER_MAX;
- counter->parent = parent;
-}
-
-static u64 res_counter_uncharge_locked(struct res_counter *counter,
- unsigned long val)
-{
- if (WARN_ON(counter->usage < val))
- val = counter->usage;
-
- counter->usage -= val;
- return counter->usage;
-}
-
-static int res_counter_charge_locked(struct res_counter *counter,
- unsigned long val, bool force)
-{
- int ret = 0;
-
- if (counter->usage + val > counter->limit) {
- counter->failcnt++;
- ret = -ENOMEM;
- if (!force)
- return ret;
- }
-
- counter->usage += val;
- if (counter->usage > counter->max_usage)
- counter->max_usage = counter->usage;
- return ret;
-}
-
-static int __res_counter_charge(struct res_counter *counter, unsigned long val,
- struct res_counter **limit_fail_at, bool force)
-{
- int ret, r;
- unsigned long flags;
- struct res_counter *c, *u;
-
- r = ret = 0;
- *limit_fail_at = NULL;
- local_irq_save(flags);
- for (c = counter; c != NULL; c = c->parent) {
- spin_lock(&c->lock);
- r = res_counter_charge_locked(c, val, force);
- spin_unlock(&c->lock);
- if (r < 0 && !ret) {
- ret = r;
- *limit_fail_at = c;
- if (!force)
- break;
- }
- }
-
- if (ret < 0 && !force) {
- for (u = counter; u != c; u = u->parent) {
- spin_lock(&u->lock);
- res_counter_uncharge_locked(u, val);
- spin_unlock(&u->lock);
- }
- }
- local_irq_restore(flags);
-
- return ret;
-}
-
-int res_counter_charge(struct res_counter *counter, unsigned long val,
- struct res_counter **limit_fail_at)
-{
- return __res_counter_charge(counter, val, limit_fail_at, false);
-}
-
-int res_counter_charge_nofail(struct res_counter *counter, unsigned long val,
- struct res_counter **limit_fail_at)
-{
- return __res_counter_charge(counter, val, limit_fail_at, true);
-}
-
-u64 res_counter_uncharge_until(struct res_counter *counter,
- struct res_counter *top,
- unsigned long val)
-{
- unsigned long flags;
- struct res_counter *c;
- u64 ret = 0;
-
- local_irq_save(flags);
- for (c = counter; c != top; c = c->parent) {
- u64 r;
- spin_lock(&c->lock);
- r = res_counter_uncharge_locked(c, val);
- if (c == counter)
- ret = r;
- spin_unlock(&c->lock);
- }
- local_irq_restore(flags);
- return ret;
-}
-
-u64 res_counter_uncharge(struct res_counter *counter, unsigned long val)
-{
- return res_counter_uncharge_until(counter, NULL, val);
-}
-
-static inline unsigned long long *
-res_counter_member(struct res_counter *counter, int member)
-{
- switch (member) {
- case RES_USAGE:
- return &counter->usage;
- case RES_MAX_USAGE:
- return &counter->max_usage;
- case RES_LIMIT:
- return &counter->limit;
- case RES_FAILCNT:
- return &counter->failcnt;
- case RES_SOFT_LIMIT:
- return &counter->soft_limit;
- };
-
- BUG();
- return NULL;
-}
-
-ssize_t res_counter_read(struct res_counter *counter, int member,
- const char __user *userbuf, size_t nbytes, loff_t *pos,
- int (*read_strategy)(unsigned long long val, char *st_buf))
-{
- unsigned long long *val;
- char buf[64], *s;
-
- s = buf;
- val = res_counter_member(counter, member);
- if (read_strategy)
- s += read_strategy(*val, s);
- else
- s += sprintf(s, "%llu\n", *val);
- return simple_read_from_buffer((void __user *)userbuf, nbytes,
- pos, buf, s - buf);
-}
-
-#if BITS_PER_LONG == 32
-u64 res_counter_read_u64(struct res_counter *counter, int member)
-{
- unsigned long flags;
- u64 ret;
-
- spin_lock_irqsave(&counter->lock, flags);
- ret = *res_counter_member(counter, member);
- spin_unlock_irqrestore(&counter->lock, flags);
-
- return ret;
-}
-#else
-u64 res_counter_read_u64(struct res_counter *counter, int member)
-{
- return *res_counter_member(counter, member);
-}
-#endif
-
-int res_counter_memparse_write_strategy(const char *buf,
- unsigned long long *resp)
-{
- char *end;
- unsigned long long res;
-
- /* return RES_COUNTER_MAX(unlimited) if "-1" is specified */
- if (*buf == '-') {
- int rc = kstrtoull(buf + 1, 10, &res);
-
- if (rc)
- return rc;
- if (res != 1)
- return -EINVAL;
- *resp = RES_COUNTER_MAX;
- return 0;
- }
-
- res = memparse(buf, &end);
- if (*end != '\0')
- return -EINVAL;
-
- if (PAGE_ALIGN(res) >= res)
- res = PAGE_ALIGN(res);
- else
- res = RES_COUNTER_MAX;
-
- *resp = res;
-
- return 0;
-}
diff --git a/kernel/sched/completion.c b/kernel/sched/completion.c
index a63f4dc..607f852 100644
--- a/kernel/sched/completion.c
+++ b/kernel/sched/completion.c
@@ -148,7 +148,7 @@ EXPORT_SYMBOL(wait_for_completion_timeout);
*
* This waits to be signaled for completion of a specific task. It is NOT
* interruptible and there is no timeout. The caller is accounted as waiting
- * for IO.
+ * for IO (which traditionally means blkio only).
*/
void __sched wait_for_completion_io(struct completion *x)
{
@@ -163,7 +163,8 @@ EXPORT_SYMBOL(wait_for_completion_io);
*
* This waits for either a completion of a specific task to be signaled or for a
* specified timeout to expire. The timeout is in jiffies. It is not
- * interruptible. The caller is accounted as waiting for IO.
+ * interruptible. The caller is accounted as waiting for IO (which traditionally
+ * means blkio only).
*
* Return: 0 if timed out, and positive (at least 1, or number of jiffies left
* till timeout) if completed.
diff --git a/kernel/sched/core.c b/kernel/sched/core.c
index 89e7283..b5797b7 100644
--- a/kernel/sched/core.c
+++ b/kernel/sched/core.c
@@ -1008,6 +1008,9 @@ inline int task_curr(const struct task_struct *p)
return cpu_curr(task_cpu(p)) == p;
}
+/*
+ * Can drop rq->lock because from sched_class::switched_from() methods drop it.
+ */
static inline void check_class_changed(struct rq *rq, struct task_struct *p,
const struct sched_class *prev_class,
int oldprio)
@@ -1015,6 +1018,7 @@ static inline void check_class_changed(struct rq *rq, struct task_struct *p,
if (prev_class != p->sched_class) {
if (prev_class->switched_from)
prev_class->switched_from(rq, p);
+ /* Possble rq->lock 'hole'. */
p->sched_class->switched_to(rq, p);
} else if (oldprio != p->prio || dl_task(p))
p->sched_class->prio_changed(rq, p, oldprio);
@@ -1054,7 +1058,7 @@ void set_task_cpu(struct task_struct *p, unsigned int new_cpu)
* ttwu() will sort out the placement.
*/
WARN_ON_ONCE(p->state != TASK_RUNNING && p->state != TASK_WAKING &&
- !(task_preempt_count(p) & PREEMPT_ACTIVE));
+ !p->on_rq);
#ifdef CONFIG_LOCKDEP
/*
@@ -1407,7 +1411,8 @@ out:
static inline
int select_task_rq(struct task_struct *p, int cpu, int sd_flags, int wake_flags)
{
- cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags);
+ if (p->nr_cpus_allowed > 1)
+ cpu = p->sched_class->select_task_rq(p, cpu, sd_flags, wake_flags);
/*
* In order not to call set_task_cpu() on a blocking task we need
@@ -1623,8 +1628,10 @@ void wake_up_if_idle(int cpu)
struct rq *rq = cpu_rq(cpu);
unsigned long flags;
- if (!is_idle_task(rq->curr))
- return;
+ rcu_read_lock();
+
+ if (!is_idle_task(rcu_dereference(rq->curr)))
+ goto out;
if (set_nr_if_polling(rq->idle)) {
trace_sched_wake_idle_without_ipi(cpu);
@@ -1635,6 +1642,9 @@ void wake_up_if_idle(int cpu)
/* Else cpu is not in idle, do nothing here */
raw_spin_unlock_irqrestore(&rq->lock, flags);
}
+
+out:
+ rcu_read_unlock();
}
bool cpus_share_cache(int this_cpu, int that_cpu)
@@ -1853,12 +1863,10 @@ static void __sched_fork(unsigned long clone_flags, struct task_struct *p)
p->numa_scan_seq = p->mm ? p->mm->numa_scan_seq : 0;
p->numa_scan_period = sysctl_numa_balancing_scan_delay;
p->numa_work.next = &p->numa_work;
- p->numa_faults_memory = NULL;
- p->numa_faults_buffer_memory = NULL;
+ p->numa_faults = NULL;
p->last_task_numa_placement = 0;
p->last_sum_exec_runtime = 0;
- INIT_LIST_HEAD(&p->numa_entry);
p->numa_group = NULL;
#endif /* CONFIG_NUMA_BALANCING */
}
@@ -2034,25 +2042,6 @@ static inline int dl_bw_cpus(int i)
}
#endif
-static inline
-void __dl_clear(struct dl_bw *dl_b, u64 tsk_bw)
-{
- dl_b->total_bw -= tsk_bw;
-}
-
-static inline
-void __dl_add(struct dl_bw *dl_b, u64 tsk_bw)
-{
- dl_b->total_bw += tsk_bw;
-}
-
-static inline
-bool __dl_overflow(struct dl_bw *dl_b, int cpus, u64 old_bw, u64 new_bw)
-{
- return dl_b->bw != -1 &&
- dl_b->bw * cpus < dl_b->total_bw - old_bw + new_bw;
-}
-
/*
* We must be sure that accepting a new task (or allowing changing the
* parameters of an existing one) is consistent with the bandwidth
@@ -2220,7 +2209,6 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
/**
* finish_task_switch - clean up after a task-switch
- * @rq: runqueue associated with task-switch
* @prev: the thread we just switched away from.
*
* finish_task_switch must be called after the context switch, paired
@@ -2232,10 +2220,16 @@ prepare_task_switch(struct rq *rq, struct task_struct *prev,
* so, we finish that here outside of the runqueue lock. (Doing it
* with the lock held can cause deadlocks; see schedule() for
* details.)
+ *
+ * The context switch have flipped the stack from under us and restored the
+ * local variables which were saved when this task called schedule() in the
+ * past. prev == current is still correct but we need to recalculate this_rq
+ * because prev may have moved to another CPU.
*/
-static void finish_task_switch(struct rq *rq, struct task_struct *prev)
+static struct rq *finish_task_switch(struct task_struct *prev)
__releases(rq->lock)
{
+ struct rq *rq = this_rq();
struct mm_struct *mm = rq->prev_mm;
long prev_state;
@@ -2275,6 +2269,7 @@ static void finish_task_switch(struct rq *rq, struct task_struct *prev)
}
tick_nohz_task_switch(current);
+ return rq;
}
#ifdef CONFIG_SMP
@@ -2309,25 +2304,22 @@ static inline void post_schedule(struct rq *rq)
asmlinkage __visible void schedule_tail(struct task_struct *prev)
__releases(rq->lock)
{
- struct rq *rq = this_rq();
-
- finish_task_switch(rq, prev);
+ struct rq *rq;
- /*
- * FIXME: do we need to worry about rq being invalidated by the
- * task_switch?
- */
+ /* finish_task_switch() drops rq->lock and enables preemtion */
+ preempt_disable();
+ rq = finish_task_switch(prev);
post_schedule(rq);
+ preempt_enable();
if (current->set_child_tid)
put_user(task_pid_vnr(current), current->set_child_tid);
}
/*
- * context_switch - switch to the new MM and the new
- * thread's register state.
+ * context_switch - switch to the new MM and the new thread's register state.
*/
-static inline void
+static inline struct rq *
context_switch(struct rq *rq, struct task_struct *prev,
struct task_struct *next)
{
@@ -2366,14 +2358,9 @@ context_switch(struct rq *rq, struct task_struct *prev,
context_tracking_task_switch(prev, next);
/* Here we just switch the register state and the stack. */
switch_to(prev, next, prev);
-
barrier();
- /*
- * this_rq must be evaluated again because prev may have moved
- * CPUs since it called schedule(), thus the 'rq' on its stack
- * frame will be invalid.
- */
- finish_task_switch(this_rq(), prev);
+
+ return finish_task_switch(prev);
}
/*
@@ -2773,7 +2760,7 @@ need_resched:
preempt_disable();
cpu = smp_processor_id();
rq = cpu_rq(cpu);
- rcu_note_context_switch(cpu);
+ rcu_note_context_switch();
prev = rq->curr;
schedule_debug(prev);
@@ -2826,15 +2813,8 @@ need_resched:
rq->curr = next;
++*switch_count;
- context_switch(rq, prev, next); /* unlocks the rq */
- /*
- * The context switch have flipped the stack from under us
- * and restored the local variables which were saved when
- * this task called schedule() in the past. prev == current
- * is still correct, but it can be moved to another cpu/rq.
- */
- cpu = smp_processor_id();
- rq = cpu_rq(cpu);
+ rq = context_switch(rq, prev, next); /* unlocks the rq */
+ cpu = cpu_of(rq);
} else
raw_spin_unlock_irq(&rq->lock);
@@ -4547,8 +4527,10 @@ void sched_show_task(struct task_struct *p)
#ifdef CONFIG_DEBUG_STACK_USAGE
free = stack_not_used(p);
#endif
+ ppid = 0;
rcu_read_lock();
- ppid = task_pid_nr(rcu_dereference(p->real_parent));
+ if (pid_alive(p))
+ ppid = task_pid_nr(rcu_dereference(p->real_parent));
rcu_read_unlock();
printk(KERN_CONT "%5lu %5d %6d 0x%08lx\n", free,
task_pid_nr(p), ppid,
@@ -4653,6 +4635,81 @@ void init_idle(struct task_struct *idle, int cpu)
#endif
}
+int cpuset_cpumask_can_shrink(const struct cpumask *cur,
+ const struct cpumask *trial)
+{
+ int ret = 1, trial_cpus;
+ struct dl_bw *cur_dl_b;
+ unsigned long flags;
+
+ rcu_read_lock_sched();
+ cur_dl_b = dl_bw_of(cpumask_any(cur));
+ trial_cpus = cpumask_weight(trial);
+
+ raw_spin_lock_irqsave(&cur_dl_b->lock, flags);
+ if (cur_dl_b->bw != -1 &&
+ cur_dl_b->bw * trial_cpus < cur_dl_b->total_bw)
+ ret = 0;
+ raw_spin_unlock_irqrestore(&cur_dl_b->lock, flags);
+ rcu_read_unlock_sched();
+
+ return ret;
+}
+
+int task_can_attach(struct task_struct *p,
+ const struct cpumask *cs_cpus_allowed)
+{
+ int ret = 0;
+
+ /*
+ * Kthreads which disallow setaffinity shouldn't be moved
+ * to a new cpuset; we don't want to change their cpu
+ * affinity and isolating such threads by their set of
+ * allowed nodes is unnecessary. Thus, cpusets are not
+ * applicable for such threads. This prevents checking for
+ * success of set_cpus_allowed_ptr() on all attached tasks
+ * before cpus_allowed may be changed.
+ */
+ if (p->flags & PF_NO_SETAFFINITY) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+#ifdef CONFIG_SMP
+ if (dl_task(p) && !cpumask_intersects(task_rq(p)->rd->span,
+ cs_cpus_allowed)) {
+ unsigned int dest_cpu = cpumask_any_and(cpu_active_mask,
+ cs_cpus_allowed);
+ struct dl_bw *dl_b;
+ bool overflow;
+ int cpus;
+ unsigned long flags;
+
+ rcu_read_lock_sched();
+ dl_b = dl_bw_of(dest_cpu);
+ raw_spin_lock_irqsave(&dl_b->lock, flags);
+ cpus = dl_bw_cpus(dest_cpu);
+ overflow = __dl_overflow(dl_b, cpus, 0, p->dl.dl_bw);
+ if (overflow)
+ ret = -EBUSY;
+ else {
+ /*
+ * We reserve space for this task in the destination
+ * root_domain, as we can't fail after this point.
+ * We will free resources in the source root_domain
+ * later on (see set_cpus_allowed_dl()).
+ */
+ __dl_add(dl_b, p->dl.dl_bw);
+ }
+ raw_spin_unlock_irqrestore(&dl_b->lock, flags);
+ rcu_read_unlock_sched();
+
+ }
+#endif
+out:
+ return ret;
+}
+
#ifdef CONFIG_SMP
/*
* move_queued_task - move a queued task to new rq.
@@ -6103,7 +6160,9 @@ static void claim_allocations(int cpu, struct sched_domain *sd)
#ifdef CONFIG_NUMA
static int sched_domains_numa_levels;
+enum numa_topology_type sched_numa_topology_type;
static int *sched_domains_numa_distance;
+int sched_max_numa_distance;
static struct cpumask ***sched_domains_numa_masks;
static int sched_domains_curr_level;
#endif
@@ -6275,7 +6334,7 @@ static void sched_numa_warn(const char *str)
printk(KERN_WARNING "\n");
}
-static bool find_numa_distance(int distance)
+bool find_numa_distance(int distance)
{
int i;
@@ -6290,6 +6349,56 @@ static bool find_numa_distance(int distance)
return false;
}
+/*
+ * A system can have three types of NUMA topology:
+ * NUMA_DIRECT: all nodes are directly connected, or not a NUMA system
+ * NUMA_GLUELESS_MESH: some nodes reachable through intermediary nodes
+ * NUMA_BACKPLANE: nodes can reach other nodes through a backplane
+ *
+ * The difference between a glueless mesh topology and a backplane
+ * topology lies in whether communication between not directly
+ * connected nodes goes through intermediary nodes (where programs
+ * could run), or through backplane controllers. This affects
+ * placement of programs.
+ *
+ * The type of topology can be discerned with the following tests:
+ * - If the maximum distance between any nodes is 1 hop, the system
+ * is directly connected.
+ * - If for two nodes A and B, located N > 1 hops away from each other,
+ * there is an intermediary node C, which is < N hops away from both
+ * nodes A and B, the system is a glueless mesh.
+ */
+static void init_numa_topology_type(void)
+{
+ int a, b, c, n;
+
+ n = sched_max_numa_distance;
+
+ if (n <= 1)
+ sched_numa_topology_type = NUMA_DIRECT;
+
+ for_each_online_node(a) {
+ for_each_online_node(b) {
+ /* Find two nodes furthest removed from each other. */
+ if (node_distance(a, b) < n)
+ continue;
+
+ /* Is there an intermediary node between a and b? */
+ for_each_online_node(c) {
+ if (node_distance(a, c) < n &&
+ node_distance(b, c) < n) {
+ sched_numa_topology_type =
+ NUMA_GLUELESS_MESH;
+ return;
+ }
+ }
+
+ sched_numa_topology_type = NUMA_BACKPLANE;
+ return;
+ }
+ }
+}
+
static void sched_init_numa(void)
{
int next_distance, curr_distance = node_distance(0, 0);
@@ -6426,6 +6535,9 @@ static void sched_init_numa(void)
sched_domain_topology = tl;
sched_domains_numa_levels = level;
+ sched_max_numa_distance = sched_domains_numa_distance[level - 1];
+
+ init_numa_topology_type();
}
static void sched_domains_numa_masks_set(int cpu)
@@ -7178,6 +7290,25 @@ static inline int preempt_count_equals(int preempt_offset)
void __might_sleep(const char *file, int line, int preempt_offset)
{
+ /*
+ * Blocking primitives will set (and therefore destroy) current->state,
+ * since we will exit with TASK_RUNNING make sure we enter with it,
+ * otherwise we will destroy state.
+ */
+ if (WARN_ONCE(current->state != TASK_RUNNING,
+ "do not call blocking ops when !TASK_RUNNING; "
+ "state=%lx set at [<%p>] %pS\n",
+ current->state,
+ (void *)current->task_state_change,
+ (void *)current->task_state_change))
+ __set_current_state(TASK_RUNNING);
+
+ ___might_sleep(file, line, preempt_offset);
+}
+EXPORT_SYMBOL(__might_sleep);
+
+void ___might_sleep(const char *file, int line, int preempt_offset)
+{
static unsigned long prev_jiffy; /* ratelimiting */
rcu_sleep_check(); /* WARN_ON_ONCE() by default, no rate limit reqd. */
@@ -7209,7 +7340,7 @@ void __might_sleep(const char *file, int line, int preempt_offset)
#endif
dump_stack();
}
-EXPORT_SYMBOL(__might_sleep);
+EXPORT_SYMBOL(___might_sleep);
#endif
#ifdef CONFIG_MAGIC_SYSRQ
diff --git a/kernel/sched/cpudeadline.h b/kernel/sched/cpudeadline.h
index 538c979..020039b 100644
--- a/kernel/sched/cpudeadline.h
+++ b/kernel/sched/cpudeadline.h
@@ -25,9 +25,6 @@ int cpudl_find(struct cpudl *cp, struct task_struct *p,
void cpudl_set(struct cpudl *cp, int cpu, u64 dl, int is_valid);
int cpudl_init(struct cpudl *cp);
void cpudl_cleanup(struct cpudl *cp);
-#else
-#define cpudl_set(cp, cpu, dl) do { } while (0)
-#define cpudl_init() do { } while (0)
#endif /* CONFIG_SMP */
#endif /* _LINUX_CPUDL_H */
diff --git a/kernel/sched/cpupri.h b/kernel/sched/cpupri.h
index 6b03334..63cbb9c 100644
--- a/kernel/sched/cpupri.h
+++ b/kernel/sched/cpupri.h
@@ -26,9 +26,6 @@ int cpupri_find(struct cpupri *cp,
void cpupri_set(struct cpupri *cp, int cpu, int pri);
int cpupri_init(struct cpupri *cp);
void cpupri_cleanup(struct cpupri *cp);
-#else
-#define cpupri_set(cp, cpu, pri) do { } while (0)
-#define cpupri_init() do { } while (0)
#endif
#endif /* _LINUX_CPUPRI_H */
diff --git a/kernel/sched/deadline.c b/kernel/sched/deadline.c
index 28fa9d9..e5db8c6 100644
--- a/kernel/sched/deadline.c
+++ b/kernel/sched/deadline.c
@@ -563,11 +563,6 @@ void init_dl_task_timer(struct sched_dl_entity *dl_se)
{
struct hrtimer *timer = &dl_se->dl_timer;
- if (hrtimer_active(timer)) {
- hrtimer_try_to_cancel(timer);
- return;
- }
-
hrtimer_init(timer, CLOCK_MONOTONIC, HRTIMER_MODE_REL);
timer->function = dl_task_timer;
}
@@ -633,7 +628,7 @@ static void update_curr_dl(struct rq *rq)
sched_rt_avg_update(rq, delta_exec);
- dl_se->runtime -= delta_exec;
+ dl_se->runtime -= dl_se->dl_yielded ? 0 : delta_exec;
if (dl_runtime_exceeded(rq, dl_se)) {
__dequeue_task_dl(rq, curr, 0);
if (likely(start_dl_timer(dl_se, curr->dl.dl_boosted)))
@@ -933,7 +928,7 @@ select_task_rq_dl(struct task_struct *p, int cpu, int sd_flag, int flags)
struct task_struct *curr;
struct rq *rq;
- if (sd_flag != SD_BALANCE_WAKE && sd_flag != SD_BALANCE_FORK)
+ if (sd_flag != SD_BALANCE_WAKE)
goto out;
rq = cpu_rq(cpu);
@@ -1018,6 +1013,10 @@ static void start_hrtick_dl(struct rq *rq, struct task_struct *p)
{
hrtick_start(rq, p->dl.runtime);
}
+#else /* !CONFIG_SCHED_HRTICK */
+static void start_hrtick_dl(struct rq *rq, struct task_struct *p)
+{
+}
#endif
static struct sched_dl_entity *pick_next_dl_entity(struct rq *rq,
@@ -1071,10 +1070,8 @@ struct task_struct *pick_next_task_dl(struct rq *rq, struct task_struct *prev)
/* Running task will never be pushed. */
dequeue_pushable_dl_task(rq, p);
-#ifdef CONFIG_SCHED_HRTICK
if (hrtick_enabled(rq))
start_hrtick_dl(rq, p);
-#endif
set_post_schedule(rq);
@@ -1093,10 +1090,8 @@ static void task_tick_dl(struct rq *rq, struct task_struct *p, int queued)
{
update_curr_dl(rq);
-#ifdef CONFIG_SCHED_HRTICK
if (hrtick_enabled(rq) && queued && p->dl.runtime > 0)
start_hrtick_dl(rq, p);
-#endif
}
static void task_fork_dl(struct task_struct *p)
@@ -1333,6 +1328,7 @@ static int push_dl_task(struct rq *rq)
{
struct task_struct *next_task;
struct rq *later_rq;
+ int ret = 0;
if (!rq->dl.overloaded)
return 0;
@@ -1378,7 +1374,6 @@ retry:
* The task is still there. We don't try
* again, some other cpu will pull it when ready.
*/
- dequeue_pushable_dl_task(rq, next_task);
goto out;
}
@@ -1394,6 +1389,7 @@ retry:
deactivate_task(rq, next_task, 0);
set_task_cpu(next_task, later_rq->cpu);
activate_task(later_rq, next_task, 0);
+ ret = 1;
resched_curr(later_rq);
@@ -1402,7 +1398,7 @@ retry:
out:
put_task_struct(next_task);
- return 1;
+ return ret;
}
static void push_dl_tasks(struct rq *rq)
@@ -1508,7 +1504,7 @@ static void task_woken_dl(struct rq *rq, struct task_struct *p)
p->nr_cpus_allowed > 1 &&
dl_task(rq->curr) &&
(rq->curr->nr_cpus_allowed < 2 ||
- dl_entity_preempt(&rq->curr->dl, &p->dl))) {
+ !dl_entity_preempt(&p->dl, &rq->curr->dl))) {
push_dl_tasks(rq);
}
}
@@ -1517,10 +1513,33 @@ static void set_cpus_allowed_dl(struct task_struct *p,
const struct cpumask *new_mask)
{
struct rq *rq;
+ struct root_domain *src_rd;
int weight;
BUG_ON(!dl_task(p));
+ rq = task_rq(p);
+ src_rd = rq->rd;
+ /*
+ * Migrating a SCHED_DEADLINE task between exclusive
+ * cpusets (different root_domains) entails a bandwidth
+ * update. We already made space for us in the destination
+ * domain (see cpuset_can_attach()).
+ */
+ if (!cpumask_intersects(src_rd->span, new_mask)) {
+ struct dl_bw *src_dl_b;
+
+ src_dl_b = dl_bw_of(cpu_of(rq));
+ /*
+ * We now free resources of the root_domain we are migrating
+ * off. In the worst case, sched_setattr() may temporary fail
+ * until we complete the update.
+ */
+ raw_spin_lock(&src_dl_b->lock);
+ __dl_clear(src_dl_b, p->dl.dl_bw);
+ raw_spin_unlock(&src_dl_b->lock);
+ }
+
/*
* Update only if the task is actually running (i.e.,
* it is on the rq AND it is not throttled).
@@ -1537,8 +1556,6 @@ static void set_cpus_allowed_dl(struct task_struct *p,
if ((p->nr_cpus_allowed > 1) == (weight > 1))
return;
- rq = task_rq(p);
-
/*
* The process used to be able to migrate OR it can now migrate
*/
@@ -1586,22 +1603,48 @@ void init_sched_dl_class(void)
#endif /* CONFIG_SMP */
+/*
+ * Ensure p's dl_timer is cancelled. May drop rq->lock for a while.
+ */
+static void cancel_dl_timer(struct rq *rq, struct task_struct *p)
+{
+ struct hrtimer *dl_timer = &p->dl.dl_timer;
+
+ /* Nobody will change task's class if pi_lock is held */
+ lockdep_assert_held(&p->pi_lock);
+
+ if (hrtimer_active(dl_timer)) {
+ int ret = hrtimer_try_to_cancel(dl_timer);
+
+ if (unlikely(ret == -1)) {
+ /*
+ * Note, p may migrate OR new deadline tasks
+ * may appear in rq when we are unlocking it.
+ * A caller of us must be fine with that.
+ */
+ raw_spin_unlock(&rq->lock);
+ hrtimer_cancel(dl_timer);
+ raw_spin_lock(&rq->lock);
+ }
+ }
+}
+
static void switched_from_dl(struct rq *rq, struct task_struct *p)
{
- if (hrtimer_active(&p->dl.dl_timer) && !dl_policy(p->policy))
- hrtimer_try_to_cancel(&p->dl.dl_timer);
+ cancel_dl_timer(rq, p);
__dl_clear_params(p);
-#ifdef CONFIG_SMP
/*
* Since this might be the only -deadline task on the rq,
* this is the right place to try to pull some other one
* from an overloaded cpu, if any.
*/
- if (!rq->dl.dl_nr_running)
- pull_dl_task(rq);
-#endif
+ if (!task_on_rq_queued(p) || rq->dl.dl_nr_running)
+ return;
+
+ if (pull_dl_task(rq))
+ resched_curr(rq);
}
/*
@@ -1622,7 +1665,8 @@ static void switched_to_dl(struct rq *rq, struct task_struct *p)
if (task_on_rq_queued(p) && rq->curr != p) {
#ifdef CONFIG_SMP
- if (rq->dl.overloaded && push_dl_task(rq) && rq != task_rq(p))
+ if (p->nr_cpus_allowed > 1 && rq->dl.overloaded &&
+ push_dl_task(rq) && rq != task_rq(p))
/* Only reschedule if pushing failed */
check_resched = 0;
#endif /* CONFIG_SMP */
@@ -1704,3 +1748,12 @@ const struct sched_class dl_sched_class = {
.update_curr = update_curr_dl,
};
+
+#ifdef CONFIG_SCHED_DEBUG
+extern void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq);
+
+void print_dl_stats(struct seq_file *m, int cpu)
+{
+ print_dl_rq(m, cpu, &cpu_rq(cpu)->dl);
+}
+#endif /* CONFIG_SCHED_DEBUG */
diff --git a/kernel/sched/debug.c b/kernel/sched/debug.c
index ce33780..92cc520 100644
--- a/kernel/sched/debug.c
+++ b/kernel/sched/debug.c
@@ -261,6 +261,12 @@ void print_rt_rq(struct seq_file *m, int cpu, struct rt_rq *rt_rq)
#undef P
}
+void print_dl_rq(struct seq_file *m, int cpu, struct dl_rq *dl_rq)
+{
+ SEQ_printf(m, "\ndl_rq[%d]:\n", cpu);
+ SEQ_printf(m, " .%-30s: %ld\n", "dl_nr_running", dl_rq->dl_nr_running);
+}
+
extern __read_mostly int sched_clock_running;
static void print_cpu(struct seq_file *m, int cpu)
@@ -329,6 +335,7 @@ do { \
spin_lock_irqsave(&sched_debug_lock, flags);
print_cfs_stats(m, cpu);
print_rt_stats(m, cpu);
+ print_dl_stats(m, cpu);
print_rq(m, rq, cpu);
spin_unlock_irqrestore(&sched_debug_lock, flags);
@@ -528,8 +535,8 @@ static void sched_show_numa(struct task_struct *p, struct seq_file *m)
unsigned long nr_faults = -1;
int cpu_current, home_node;
- if (p->numa_faults_memory)
- nr_faults = p->numa_faults_memory[2*node + i];
+ if (p->numa_faults)
+ nr_faults = p->numa_faults[2*node + i];
cpu_current = !i ? (task_node(p) == node) :
(pol && node_isset(node, pol->v.nodes));
diff --git a/kernel/sched/fair.c b/kernel/sched/fair.c
index ef2b104..df2cdf7 100644
--- a/kernel/sched/fair.c
+++ b/kernel/sched/fair.c
@@ -873,7 +873,6 @@ struct numa_group {
spinlock_t lock; /* nr_tasks, tasks */
int nr_tasks;
pid_t gid;
- struct list_head task_list;
struct rcu_head rcu;
nodemask_t active_nodes;
@@ -901,18 +900,24 @@ pid_t task_numa_group_id(struct task_struct *p)
return p->numa_group ? p->numa_group->gid : 0;
}
-static inline int task_faults_idx(int nid, int priv)
+/*
+ * The averaged statistics, shared & private, memory & cpu,
+ * occupy the first half of the array. The second half of the
+ * array is for current counters, which are averaged into the
+ * first set by task_numa_placement.
+ */
+static inline int task_faults_idx(enum numa_faults_stats s, int nid, int priv)
{
- return NR_NUMA_HINT_FAULT_TYPES * nid + priv;
+ return NR_NUMA_HINT_FAULT_TYPES * (s * nr_node_ids + nid) + priv;
}
static inline unsigned long task_faults(struct task_struct *p, int nid)
{
- if (!p->numa_faults_memory)
+ if (!p->numa_faults)
return 0;
- return p->numa_faults_memory[task_faults_idx(nid, 0)] +
- p->numa_faults_memory[task_faults_idx(nid, 1)];
+ return p->numa_faults[task_faults_idx(NUMA_MEM, nid, 0)] +
+ p->numa_faults[task_faults_idx(NUMA_MEM, nid, 1)];
}
static inline unsigned long group_faults(struct task_struct *p, int nid)
@@ -920,14 +925,79 @@ static inline unsigned long group_faults(struct task_struct *p, int nid)
if (!p->numa_group)
return 0;
- return p->numa_group->faults[task_faults_idx(nid, 0)] +
- p->numa_group->faults[task_faults_idx(nid, 1)];
+ return p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 0)] +
+ p->numa_group->faults[task_faults_idx(NUMA_MEM, nid, 1)];
}
static inline unsigned long group_faults_cpu(struct numa_group *group, int nid)
{
- return group->faults_cpu[task_faults_idx(nid, 0)] +
- group->faults_cpu[task_faults_idx(nid, 1)];
+ return group->faults_cpu[task_faults_idx(NUMA_MEM, nid, 0)] +
+ group->faults_cpu[task_faults_idx(NUMA_MEM, nid, 1)];
+}
+
+/* Handle placement on systems where not all nodes are directly connected. */
+static unsigned long score_nearby_nodes(struct task_struct *p, int nid,
+ int maxdist, bool task)
+{
+ unsigned long score = 0;
+ int node;
+
+ /*
+ * All nodes are directly connected, and the same distance
+ * from each other. No need for fancy placement algorithms.
+ */
+ if (sched_numa_topology_type == NUMA_DIRECT)
+ return 0;
+
+ /*
+ * This code is called for each node, introducing N^2 complexity,
+ * which should be ok given the number of nodes rarely exceeds 8.
+ */
+ for_each_online_node(node) {
+ unsigned long faults;
+ int dist = node_distance(nid, node);
+
+ /*
+ * The furthest away nodes in the system are not interesting
+ * for placement; nid was already counted.
+ */
+ if (dist == sched_max_numa_distance || node == nid)
+ continue;
+
+ /*
+ * On systems with a backplane NUMA topology, compare groups
+ * of nodes, and move tasks towards the group with the most
+ * memory accesses. When comparing two nodes at distance
+ * "hoplimit", only nodes closer by than "hoplimit" are part
+ * of each group. Skip other nodes.
+ */
+ if (sched_numa_topology_type == NUMA_BACKPLANE &&
+ dist > maxdist)
+ continue;
+
+ /* Add up the faults from nearby nodes. */
+ if (task)
+ faults = task_faults(p, node);
+ else
+ faults = group_faults(p, node);
+
+ /*
+ * On systems with a glueless mesh NUMA topology, there are
+ * no fixed "groups of nodes". Instead, nodes that are not
+ * directly connected bounce traffic through intermediate
+ * nodes; a numa_group can occupy any set of nodes.
+ * The further away a node is, the less the faults count.
+ * This seems to result in good task placement.
+ */
+ if (sched_numa_topology_type == NUMA_GLUELESS_MESH) {
+ faults *= (sched_max_numa_distance - dist);
+ faults /= (sched_max_numa_distance - LOCAL_DISTANCE);
+ }
+
+ score += faults;
+ }
+
+ return score;
}
/*
@@ -936,11 +1006,12 @@ static inline unsigned long group_faults_cpu(struct numa_group *group, int nid)
* larger multiplier, in order to group tasks together that are almost
* evenly spread out between numa nodes.
*/
-static inline unsigned long task_weight(struct task_struct *p, int nid)
+static inline unsigned long task_weight(struct task_struct *p, int nid,
+ int dist)
{
- unsigned long total_faults;
+ unsigned long faults, total_faults;
- if (!p->numa_faults_memory)
+ if (!p->numa_faults)
return 0;
total_faults = p->total_numa_faults;
@@ -948,15 +1019,29 @@ static inline unsigned long task_weight(struct task_struct *p, int nid)
if (!total_faults)
return 0;
- return 1000 * task_faults(p, nid) / total_faults;
+ faults = task_faults(p, nid);
+ faults += score_nearby_nodes(p, nid, dist, true);
+
+ return 1000 * faults / total_faults;
}
-static inline unsigned long group_weight(struct task_struct *p, int nid)
+static inline unsigned long group_weight(struct task_struct *p, int nid,
+ int dist)
{
- if (!p->numa_group || !p->numa_group->total_faults)
+ unsigned long faults, total_faults;
+
+ if (!p->numa_group)
return 0;
- return 1000 * group_faults(p, nid) / p->numa_group->total_faults;
+ total_faults = p->numa_group->total_faults;
+
+ if (!total_faults)
+ return 0;
+
+ faults = group_faults(p, nid);
+ faults += score_nearby_nodes(p, nid, dist, false);
+
+ return 1000 * faults / total_faults;
}
bool should_numa_migrate_memory(struct task_struct *p, struct page * page,
@@ -1089,6 +1174,7 @@ struct task_numa_env {
struct numa_stats src_stats, dst_stats;
int imbalance_pct;
+ int dist;
struct task_struct *best_task;
long best_imp;
@@ -1168,6 +1254,7 @@ static void task_numa_compare(struct task_numa_env *env,
long load;
long imp = env->p->numa_group ? groupimp : taskimp;
long moveimp = imp;
+ int dist = env->dist;
rcu_read_lock();
@@ -1208,8 +1295,8 @@ static void task_numa_compare(struct task_numa_env *env,
* in any group then look only at task weights.
*/
if (cur->numa_group == env->p->numa_group) {
- imp = taskimp + task_weight(cur, env->src_nid) -
- task_weight(cur, env->dst_nid);
+ imp = taskimp + task_weight(cur, env->src_nid, dist) -
+ task_weight(cur, env->dst_nid, dist);
/*
* Add some hysteresis to prevent swapping the
* tasks within a group over tiny differences.
@@ -1223,11 +1310,11 @@ static void task_numa_compare(struct task_numa_env *env,
* instead.
*/
if (cur->numa_group)
- imp += group_weight(cur, env->src_nid) -
- group_weight(cur, env->dst_nid);
+ imp += group_weight(cur, env->src_nid, dist) -
+ group_weight(cur, env->dst_nid, dist);
else
- imp += task_weight(cur, env->src_nid) -
- task_weight(cur, env->dst_nid);
+ imp += task_weight(cur, env->src_nid, dist) -
+ task_weight(cur, env->dst_nid, dist);
}
}
@@ -1326,7 +1413,7 @@ static int task_numa_migrate(struct task_struct *p)
};
struct sched_domain *sd;
unsigned long taskweight, groupweight;
- int nid, ret;
+ int nid, ret, dist;
long taskimp, groupimp;
/*
@@ -1354,29 +1441,45 @@ static int task_numa_migrate(struct task_struct *p)
return -EINVAL;
}
- taskweight = task_weight(p, env.src_nid);
- groupweight = group_weight(p, env.src_nid);
- update_numa_stats(&env.src_stats, env.src_nid);
env.dst_nid = p->numa_preferred_nid;
- taskimp = task_weight(p, env.dst_nid) - taskweight;
- groupimp = group_weight(p, env.dst_nid) - groupweight;
+ dist = env.dist = node_distance(env.src_nid, env.dst_nid);
+ taskweight = task_weight(p, env.src_nid, dist);
+ groupweight = group_weight(p, env.src_nid, dist);
+ update_numa_stats(&env.src_stats, env.src_nid);
+ taskimp = task_weight(p, env.dst_nid, dist) - taskweight;
+ groupimp = group_weight(p, env.dst_nid, dist) - groupweight;
update_numa_stats(&env.dst_stats, env.dst_nid);
/* Try to find a spot on the preferred nid. */
task_numa_find_cpu(&env, taskimp, groupimp);
- /* No space available on the preferred nid. Look elsewhere. */
- if (env.best_cpu == -1) {
+ /*
+ * Look at other nodes in these cases:
+ * - there is no space available on the preferred_nid
+ * - the task is part of a numa_group that is interleaved across
+ * multiple NUMA nodes; in order to better consolidate the group,
+ * we need to check other locations.
+ */
+ if (env.best_cpu == -1 || (p->numa_group &&
+ nodes_weight(p->numa_group->active_nodes) > 1)) {
for_each_online_node(nid) {
if (nid == env.src_nid || nid == p->numa_preferred_nid)
continue;
+ dist = node_distance(env.src_nid, env.dst_nid);
+ if (sched_numa_topology_type == NUMA_BACKPLANE &&
+ dist != env.dist) {
+ taskweight = task_weight(p, env.src_nid, dist);
+ groupweight = group_weight(p, env.src_nid, dist);
+ }
+
/* Only consider nodes where both task and groups benefit */
- taskimp = task_weight(p, nid) - taskweight;
- groupimp = group_weight(p, nid) - groupweight;
+ taskimp = task_weight(p, nid, dist) - taskweight;
+ groupimp = group_weight(p, nid, dist) - groupweight;
if (taskimp < 0 && groupimp < 0)
continue;
+ env.dist = dist;
env.dst_nid = nid;
update_numa_stats(&env.dst_stats, env.dst_nid);
task_numa_find_cpu(&env, taskimp, groupimp);
@@ -1431,7 +1534,7 @@ static void numa_migrate_preferred(struct task_struct *p)
unsigned long interval = HZ;
/* This task has no NUMA fault statistics yet */
- if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults_memory))
+ if (unlikely(p->numa_preferred_nid == -1 || !p->numa_faults))
return;
/* Periodically retry migrating the task to the preferred node */
@@ -1580,6 +1683,92 @@ static u64 numa_get_avg_runtime(struct task_struct *p, u64 *period)
return delta;
}
+/*
+ * Determine the preferred nid for a task in a numa_group. This needs to
+ * be done in a way that produces consistent results with group_weight,
+ * otherwise workloads might not converge.
+ */
+static int preferred_group_nid(struct task_struct *p, int nid)
+{
+ nodemask_t nodes;
+ int dist;
+
+ /* Direct connections between all NUMA nodes. */
+ if (sched_numa_topology_type == NUMA_DIRECT)
+ return nid;
+
+ /*
+ * On a system with glueless mesh NUMA topology, group_weight
+ * scores nodes according to the number of NUMA hinting faults on
+ * both the node itself, and on nearby nodes.
+ */
+ if (sched_numa_topology_type == NUMA_GLUELESS_MESH) {
+ unsigned long score, max_score = 0;
+ int node, max_node = nid;
+
+ dist = sched_max_numa_distance;
+
+ for_each_online_node(node) {
+ score = group_weight(p, node, dist);
+ if (score > max_score) {
+ max_score = score;
+ max_node = node;
+ }
+ }
+ return max_node;
+ }
+
+ /*
+ * Finding the preferred nid in a system with NUMA backplane
+ * interconnect topology is more involved. The goal is to locate
+ * tasks from numa_groups near each other in the system, and
+ * untangle workloads from different sides of the system. This requires
+ * searching down the hierarchy of node groups, recursively searching
+ * inside the highest scoring group of nodes. The nodemask tricks
+ * keep the complexity of the search down.
+ */
+ nodes = node_online_map;
+ for (dist = sched_max_numa_distance; dist > LOCAL_DISTANCE; dist--) {
+ unsigned long max_faults = 0;
+ nodemask_t max_group;
+ int a, b;
+
+ /* Are there nodes at this distance from each other? */
+ if (!find_numa_distance(dist))
+ continue;
+
+ for_each_node_mask(a, nodes) {
+ unsigned long faults = 0;
+ nodemask_t this_group;
+ nodes_clear(this_group);
+
+ /* Sum group's NUMA faults; includes a==b case. */
+ for_each_node_mask(b, nodes) {
+ if (node_distance(a, b) < dist) {
+ faults += group_faults(p, b);
+ node_set(b, this_group);
+ node_clear(b, nodes);
+ }
+ }
+
+ /* Remember the top group. */
+ if (faults > max_faults) {
+ max_faults = faults;
+ max_group = this_group;
+ /*
+ * subtle: at the smallest distance there is
+ * just one node left in each "group", the
+ * winner is the preferred nid.
+ */
+ nid = a;
+ }
+ }
+ /* Next round, evaluate the nodes within max_group. */
+ nodes = max_group;
+ }
+ return nid;
+}
+
static void task_numa_placement(struct task_struct *p)
{
int seq, nid, max_nid = -1, max_group_nid = -1;
@@ -1607,18 +1796,23 @@ static void task_numa_placement(struct task_struct *p)
/* Find the node with the highest number of faults */
for_each_online_node(nid) {
+ /* Keep track of the offsets in numa_faults array */
+ int mem_idx, membuf_idx, cpu_idx, cpubuf_idx;
unsigned long faults = 0, group_faults = 0;
- int priv, i;
+ int priv;
for (priv = 0; priv < NR_NUMA_HINT_FAULT_TYPES; priv++) {
long diff, f_diff, f_weight;
- i = task_faults_idx(nid, priv);
+ mem_idx = task_faults_idx(NUMA_MEM, nid, priv);
+ membuf_idx = task_faults_idx(NUMA_MEMBUF, nid, priv);
+ cpu_idx = task_faults_idx(NUMA_CPU, nid, priv);
+ cpubuf_idx = task_faults_idx(NUMA_CPUBUF, nid, priv);
/* Decay existing window, copy faults since last scan */
- diff = p->numa_faults_buffer_memory[i] - p->numa_faults_memory[i] / 2;
- fault_types[priv] += p->numa_faults_buffer_memory[i];
- p->numa_faults_buffer_memory[i] = 0;
+ diff = p->numa_faults[membuf_idx] - p->numa_faults[mem_idx] / 2;
+ fault_types[priv] += p->numa_faults[membuf_idx];
+ p->numa_faults[membuf_idx] = 0;
/*
* Normalize the faults_from, so all tasks in a group
@@ -1628,21 +1822,27 @@ static void task_numa_placement(struct task_struct *p)
* faults are less important.
*/
f_weight = div64_u64(runtime << 16, period + 1);
- f_weight = (f_weight * p->numa_faults_buffer_cpu[i]) /
+ f_weight = (f_weight * p->numa_faults[cpubuf_idx]) /
(total_faults + 1);
- f_diff = f_weight - p->numa_faults_cpu[i] / 2;
- p->numa_faults_buffer_cpu[i] = 0;
+ f_diff = f_weight - p->numa_faults[cpu_idx] / 2;
+ p->numa_faults[cpubuf_idx] = 0;
- p->numa_faults_memory[i] += diff;
- p->numa_faults_cpu[i] += f_diff;
- faults += p->numa_faults_memory[i];
+ p->numa_faults[mem_idx] += diff;
+ p->numa_faults[cpu_idx] += f_diff;
+ faults += p->numa_faults[mem_idx];
p->total_numa_faults += diff;
if (p->numa_group) {
- /* safe because we can only change our own group */
- p->numa_group->faults[i] += diff;
- p->numa_group->faults_cpu[i] += f_diff;
+ /*
+ * safe because we can only change our own group
+ *
+ * mem_idx represents the offset for a given
+ * nid and priv in a specific region because it
+ * is at the beginning of the numa_faults array.
+ */
+ p->numa_group->faults[mem_idx] += diff;
+ p->numa_group->faults_cpu[mem_idx] += f_diff;
p->numa_group->total_faults += diff;
- group_faults += p->numa_group->faults[i];
+ group_faults += p->numa_group->faults[mem_idx];
}
}
@@ -1662,7 +1862,7 @@ static void task_numa_placement(struct task_struct *p)
if (p->numa_group) {
update_numa_active_node_mask(p->numa_group);
spin_unlock_irq(group_lock);
- max_nid = max_group_nid;
+ max_nid = preferred_group_nid(p, max_group_nid);
}
if (max_faults) {
@@ -1705,7 +1905,6 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
atomic_set(&grp->refcount, 1);
spin_lock_init(&grp->lock);
- INIT_LIST_HEAD(&grp->task_list);
grp->gid = p->pid;
/* Second half of the array tracks nids where faults happen */
grp->faults_cpu = grp->faults + NR_NUMA_HINT_FAULT_TYPES *
@@ -1714,11 +1913,10 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
node_set(task_node(current), grp->active_nodes);
for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
- grp->faults[i] = p->numa_faults_memory[i];
+ grp->faults[i] = p->numa_faults[i];
grp->total_faults = p->total_numa_faults;
- list_add(&p->numa_entry, &grp->task_list);
grp->nr_tasks++;
rcu_assign_pointer(p->numa_group, grp);
}
@@ -1773,13 +1971,12 @@ static void task_numa_group(struct task_struct *p, int cpupid, int flags,
double_lock_irq(&my_grp->lock, &grp->lock);
for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++) {
- my_grp->faults[i] -= p->numa_faults_memory[i];
- grp->faults[i] += p->numa_faults_memory[i];
+ my_grp->faults[i] -= p->numa_faults[i];
+ grp->faults[i] += p->numa_faults[i];
}
my_grp->total_faults -= p->total_numa_faults;
grp->total_faults += p->total_numa_faults;
- list_move(&p->numa_entry, &grp->task_list);
my_grp->nr_tasks--;
grp->nr_tasks++;
@@ -1799,27 +1996,23 @@ no_join:
void task_numa_free(struct task_struct *p)
{
struct numa_group *grp = p->numa_group;
- void *numa_faults = p->numa_faults_memory;
+ void *numa_faults = p->numa_faults;
unsigned long flags;
int i;
if (grp) {
spin_lock_irqsave(&grp->lock, flags);
for (i = 0; i < NR_NUMA_HINT_FAULT_STATS * nr_node_ids; i++)
- grp->faults[i] -= p->numa_faults_memory[i];
+ grp->faults[i] -= p->numa_faults[i];
grp->total_faults -= p->total_numa_faults;
- list_del(&p->numa_entry);
grp->nr_tasks--;
spin_unlock_irqrestore(&grp->lock, flags);
RCU_INIT_POINTER(p->numa_group, NULL);
put_numa_group(grp);
}
- p->numa_faults_memory = NULL;
- p->numa_faults_buffer_memory = NULL;
- p->numa_faults_cpu= NULL;
- p->numa_faults_buffer_cpu = NULL;
+ p->numa_faults = NULL;
kfree(numa_faults);
}
@@ -1842,24 +2035,14 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
return;
/* Allocate buffer to track faults on a per-node basis */
- if (unlikely(!p->numa_faults_memory)) {
- int size = sizeof(*p->numa_faults_memory) *
+ if (unlikely(!p->numa_faults)) {
+ int size = sizeof(*p->numa_faults) *
NR_NUMA_HINT_FAULT_BUCKETS * nr_node_ids;
- p->numa_faults_memory = kzalloc(size, GFP_KERNEL|__GFP_NOWARN);
- if (!p->numa_faults_memory)
+ p->numa_faults = kzalloc(size, GFP_KERNEL|__GFP_NOWARN);
+ if (!p->numa_faults)
return;
- BUG_ON(p->numa_faults_buffer_memory);
- /*
- * The averaged statistics, shared & private, memory & cpu,
- * occupy the first half of the array. The second half of the
- * array is for current counters, which are averaged into the
- * first set by task_numa_placement.
- */
- p->numa_faults_cpu = p->numa_faults_memory + (2 * nr_node_ids);
- p->numa_faults_buffer_memory = p->numa_faults_memory + (4 * nr_node_ids);
- p->numa_faults_buffer_cpu = p->numa_faults_memory + (6 * nr_node_ids);
p->total_numa_faults = 0;
memset(p->numa_faults_locality, 0, sizeof(p->numa_faults_locality));
}
@@ -1899,8 +2082,8 @@ void task_numa_fault(int last_cpupid, int mem_node, int pages, int flags)
if (migrated)
p->numa_pages_migrated += pages;
- p->numa_faults_buffer_memory[task_faults_idx(mem_node, priv)] += pages;
- p->numa_faults_buffer_cpu[task_faults_idx(cpu_node, priv)] += pages;
+ p->numa_faults[task_faults_idx(NUMA_MEMBUF, mem_node, priv)] += pages;
+ p->numa_faults[task_faults_idx(NUMA_CPUBUF, cpu_node, priv)] += pages;
p->numa_faults_locality[local] += pages;
}
@@ -4469,7 +4652,7 @@ find_idlest_cpu(struct sched_group *group, struct task_struct *p, int this_cpu)
latest_idle_timestamp = rq->idle_stamp;
shallowest_idle_cpu = i;
}
- } else {
+ } else if (shallowest_idle_cpu == -1) {
load = weighted_cpuload(i);
if (load < min_load || (load == min_load && i == this_cpu)) {
min_load = load;
@@ -4547,9 +4730,6 @@ select_task_rq_fair(struct task_struct *p, int prev_cpu, int sd_flag, int wake_f
int want_affine = 0;
int sync = wake_flags & WF_SYNC;
- if (p->nr_cpus_allowed == 1)
- return prev_cpu;
-
if (sd_flag & SD_BALANCE_WAKE)
want_affine = cpumask_test_cpu(cpu, tsk_cpus_allowed(p));
@@ -5189,7 +5369,7 @@ static bool migrate_improves_locality(struct task_struct *p, struct lb_env *env)
struct numa_group *numa_group = rcu_dereference(p->numa_group);
int src_nid, dst_nid;
- if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults_memory ||
+ if (!sched_feat(NUMA_FAVOUR_HIGHER) || !p->numa_faults ||
!(env->sd->flags & SD_NUMA)) {
return false;
}
@@ -5228,7 +5408,7 @@ static bool migrate_degrades_locality(struct task_struct *p, struct lb_env *env)
if (!sched_feat(NUMA) || !sched_feat(NUMA_RESIST_LOWER))
return false;
- if (!p->numa_faults_memory || !(env->sd->flags & SD_NUMA))
+ if (!p->numa_faults || !(env->sd->flags & SD_NUMA))
return false;
src_nid = cpu_to_node(env->src_cpu);
@@ -6172,8 +6352,10 @@ static inline void update_sd_lb_stats(struct lb_env *env, struct sd_lb_stats *sd
* with a large weight task outweighs the tasks on the system).
*/
if (prefer_sibling && sds->local &&
- sds->local_stat.group_has_free_capacity)
+ sds->local_stat.group_has_free_capacity) {
sgs->group_capacity_factor = min(sgs->group_capacity_factor, 1U);
+ sgs->group_type = group_classify(sg, sgs);
+ }
if (update_sd_pick_busiest(env, sds, sg, sgs)) {
sds->busiest = sg;
diff --git a/kernel/sched/rt.c b/kernel/sched/rt.c
index 20bca39..ee15f5a 100644
--- a/kernel/sched/rt.c
+++ b/kernel/sched/rt.c
@@ -1301,9 +1301,6 @@ select_task_rq_rt(struct task_struct *p, int cpu, int sd_flag, int flags)
struct task_struct *curr;
struct rq *rq;
- if (p->nr_cpus_allowed == 1)
- goto out;
-
/* For anything but wake ups, just return the task_cpu */
if (sd_flag != SD_BALANCE_WAKE && sd_flag != SD_BALANCE_FORK)
goto out;
@@ -1351,16 +1348,22 @@ out:
static void check_preempt_equal_prio(struct rq *rq, struct task_struct *p)
{
- if (rq->curr->nr_cpus_allowed == 1)
+ /*
+ * Current can't be migrated, useless to reschedule,
+ * let's hope p can move out.
+ */
+ if (rq->curr->nr_cpus_allowed == 1 ||
+ !cpupri_find(&rq->rd->cpupri, rq->curr, NULL))
return;
+ /*
+ * p is migratable, so let's not schedule it and
+ * see if it is pushed or pulled somewhere else.
+ */
if (p->nr_cpus_allowed != 1
&& cpupri_find(&rq->rd->cpupri, p, NULL))
return;
- if (!cpupri_find(&rq->rd->cpupri, rq->curr, NULL))
- return;
-
/*
* There appears to be other cpus that can accept
* current and none to run 'p', so lets reschedule
diff --git a/kernel/sched/sched.h b/kernel/sched/sched.h
index 2df8ef0..9a2a45c 100644
--- a/kernel/sched/sched.h
+++ b/kernel/sched/sched.h
@@ -176,6 +176,25 @@ struct dl_bw {
u64 bw, total_bw;
};
+static inline
+void __dl_clear(struct dl_bw *dl_b, u64 tsk_bw)
+{
+ dl_b->total_bw -= tsk_bw;
+}
+
+static inline
+void __dl_add(struct dl_bw *dl_b, u64 tsk_bw)
+{
+ dl_b->total_bw += tsk_bw;
+}
+
+static inline
+bool __dl_overflow(struct dl_bw *dl_b, int cpus, u64 old_bw, u64 new_bw)
+{
+ return dl_b->bw != -1 &&
+ dl_b->bw * cpus < dl_b->total_bw - old_bw + new_bw;
+}
+
extern struct mutex sched_domains_mutex;
#ifdef CONFIG_CGROUP_SCHED
@@ -678,7 +697,25 @@ static inline u64 rq_clock_task(struct rq *rq)
return rq->clock_task;
}
+#ifdef CONFIG_NUMA
+enum numa_topology_type {
+ NUMA_DIRECT,
+ NUMA_GLUELESS_MESH,
+ NUMA_BACKPLANE,
+};
+extern enum numa_topology_type sched_numa_topology_type;
+extern int sched_max_numa_distance;
+extern bool find_numa_distance(int distance);
+#endif
+
#ifdef CONFIG_NUMA_BALANCING
+/* The regions in numa_faults array from task_struct */
+enum numa_faults_stats {
+ NUMA_MEM = 0,
+ NUMA_CPU,
+ NUMA_MEMBUF,
+ NUMA_CPUBUF
+};
extern void sched_setnuma(struct task_struct *p, int node);
extern int migrate_task_to(struct task_struct *p, int cpu);
extern int migrate_swap(struct task_struct *, struct task_struct *);
@@ -1127,6 +1164,11 @@ struct sched_class {
void (*task_fork) (struct task_struct *p);
void (*task_dead) (struct task_struct *p);
+ /*
+ * The switched_from() call is allowed to drop rq->lock, therefore we
+ * cannot assume the switched_from/switched_to pair is serliazed by
+ * rq->lock. They are however serialized by p->pi_lock.
+ */
void (*switched_from) (struct rq *this_rq, struct task_struct *task);
void (*switched_to) (struct rq *this_rq, struct task_struct *task);
void (*prio_changed) (struct rq *this_rq, struct task_struct *task,
@@ -1504,6 +1546,7 @@ extern struct sched_entity *__pick_first_entity(struct cfs_rq *cfs_rq);
extern struct sched_entity *__pick_last_entity(struct cfs_rq *cfs_rq);
extern void print_cfs_stats(struct seq_file *m, int cpu);
extern void print_rt_stats(struct seq_file *m, int cpu);
+extern void print_dl_stats(struct seq_file *m, int cpu);
extern void init_cfs_rq(struct cfs_rq *cfs_rq);
extern void init_rt_rq(struct rt_rq *rt_rq, struct rq *rq);
diff --git a/kernel/sched/wait.c b/kernel/sched/wait.c
index 5a62915..852143a 100644
--- a/kernel/sched/wait.c
+++ b/kernel/sched/wait.c
@@ -9,6 +9,7 @@
#include <linux/mm.h>
#include <linux/wait.h>
#include <linux/hash.h>
+#include <linux/kthread.h>
void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
@@ -297,6 +298,71 @@ int autoremove_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *
}
EXPORT_SYMBOL(autoremove_wake_function);
+static inline bool is_kthread_should_stop(void)
+{
+ return (current->flags & PF_KTHREAD) && kthread_should_stop();
+}
+
+/*
+ * DEFINE_WAIT_FUNC(wait, woken_wake_func);
+ *
+ * add_wait_queue(&wq, &wait);
+ * for (;;) {
+ * if (condition)
+ * break;
+ *
+ * p->state = mode; condition = true;
+ * smp_mb(); // A smp_wmb(); // C
+ * if (!wait->flags & WQ_FLAG_WOKEN) wait->flags |= WQ_FLAG_WOKEN;
+ * schedule() try_to_wake_up();
+ * p->state = TASK_RUNNING; ~~~~~~~~~~~~~~~~~~
+ * wait->flags &= ~WQ_FLAG_WOKEN; condition = true;
+ * smp_mb() // B smp_wmb(); // C
+ * wait->flags |= WQ_FLAG_WOKEN;
+ * }
+ * remove_wait_queue(&wq, &wait);
+ *
+ */
+long wait_woken(wait_queue_t *wait, unsigned mode, long timeout)
+{
+ set_current_state(mode); /* A */
+ /*
+ * The above implies an smp_mb(), which matches with the smp_wmb() from
+ * woken_wake_function() such that if we observe WQ_FLAG_WOKEN we must
+ * also observe all state before the wakeup.
+ */
+ if (!(wait->flags & WQ_FLAG_WOKEN) && !is_kthread_should_stop())
+ timeout = schedule_timeout(timeout);
+ __set_current_state(TASK_RUNNING);
+
+ /*
+ * The below implies an smp_mb(), it too pairs with the smp_wmb() from
+ * woken_wake_function() such that we must either observe the wait
+ * condition being true _OR_ WQ_FLAG_WOKEN such that we will not miss
+ * an event.
+ */
+ set_mb(wait->flags, wait->flags & ~WQ_FLAG_WOKEN); /* B */
+
+ return timeout;
+}
+EXPORT_SYMBOL(wait_woken);
+
+int woken_wake_function(wait_queue_t *wait, unsigned mode, int sync, void *key)
+{
+ /*
+ * Although this function is called under waitqueue lock, LOCK
+ * doesn't imply write barrier and the users expects write
+ * barrier semantics on wakeup functions. The following
+ * smp_wmb() is equivalent to smp_wmb() in try_to_wake_up()
+ * and is paired with set_mb() in wait_woken().
+ */
+ smp_wmb(); /* C */
+ wait->flags |= WQ_FLAG_WOKEN;
+
+ return default_wake_function(wait, mode, sync, key);
+}
+EXPORT_SYMBOL(woken_wake_function);
+
int wake_bit_function(wait_queue_t *wait, unsigned mode, int sync, void *arg)
{
struct wait_bit_key *key = arg;
diff --git a/kernel/signal.c b/kernel/signal.c
index 8f0876f..16a3052 100644
--- a/kernel/signal.c
+++ b/kernel/signal.c
@@ -1275,7 +1275,17 @@ struct sighand_struct *__lock_task_sighand(struct task_struct *tsk,
local_irq_restore(*flags);
break;
}
-
+ /*
+ * This sighand can be already freed and even reused, but
+ * we rely on SLAB_DESTROY_BY_RCU and sighand_ctor() which
+ * initializes ->siglock: this slab can't go away, it has
+ * the same object type, ->siglock can't be reinitialized.
+ *
+ * We need to ensure that tsk->sighand is still the same
+ * after we take the lock, we can race with de_thread() or
+ * __exit_signal(). In the latter case the next iteration
+ * must see ->sighand == NULL.
+ */
spin_lock(&sighand->siglock);
if (likely(sighand == tsk->sighand)) {
rcu_read_unlock();
@@ -1331,23 +1341,21 @@ int kill_pid_info(int sig, struct siginfo *info, struct pid *pid)
int error = -ESRCH;
struct task_struct *p;
- rcu_read_lock();
-retry:
- p = pid_task(pid, PIDTYPE_PID);
- if (p) {
- error = group_send_sig_info(sig, info, p);
- if (unlikely(error == -ESRCH))
- /*
- * The task was unhashed in between, try again.
- * If it is dead, pid_task() will return NULL,
- * if we race with de_thread() it will find the
- * new leader.
- */
- goto retry;
- }
- rcu_read_unlock();
+ for (;;) {
+ rcu_read_lock();
+ p = pid_task(pid, PIDTYPE_PID);
+ if (p)
+ error = group_send_sig_info(sig, info, p);
+ rcu_read_unlock();
+ if (likely(!p || error != -ESRCH))
+ return error;
- return error;
+ /*
+ * The task was unhashed in between, try again. If it
+ * is dead, pid_task() will return NULL, if we race with
+ * de_thread() it will find the new leader.
+ */
+ }
}
int kill_proc_info(int sig, struct siginfo *info, pid_t pid)
@@ -2748,6 +2756,10 @@ int copy_siginfo_to_user(siginfo_t __user *to, const siginfo_t *from)
if (from->si_code == BUS_MCEERR_AR || from->si_code == BUS_MCEERR_AO)
err |= __put_user(from->si_addr_lsb, &to->si_addr_lsb);
#endif
+#ifdef SEGV_BNDERR
+ err |= __put_user(from->si_lower, &to->si_lower);
+ err |= __put_user(from->si_upper, &to->si_upper);
+#endif
break;
case __SI_CHLD:
err |= __put_user(from->si_pid, &to->si_pid);
diff --git a/kernel/smpboot.c b/kernel/smpboot.c
index eb89e18..f032fb5 100644
--- a/kernel/smpboot.c
+++ b/kernel/smpboot.c
@@ -110,7 +110,7 @@ static int smpboot_thread_fn(void *data)
set_current_state(TASK_INTERRUPTIBLE);
preempt_disable();
if (kthread_should_stop()) {
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
preempt_enable();
if (ht->cleanup)
ht->cleanup(td->cpu, cpu_online(td->cpu));
@@ -136,26 +136,27 @@ static int smpboot_thread_fn(void *data)
/* Check for state change setup */
switch (td->status) {
case HP_THREAD_NONE:
+ __set_current_state(TASK_RUNNING);
preempt_enable();
if (ht->setup)
ht->setup(td->cpu);
td->status = HP_THREAD_ACTIVE;
- preempt_disable();
- break;
+ continue;
+
case HP_THREAD_PARKED:
+ __set_current_state(TASK_RUNNING);
preempt_enable();
if (ht->unpark)
ht->unpark(td->cpu);
td->status = HP_THREAD_ACTIVE;
- preempt_disable();
- break;
+ continue;
}
if (!ht->thread_should_run(td->cpu)) {
- preempt_enable();
+ preempt_enable_no_resched();
schedule();
} else {
- set_current_state(TASK_RUNNING);
+ __set_current_state(TASK_RUNNING);
preempt_enable();
ht->thread_fn(td->cpu);
}
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 0699add..501baa9 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -656,7 +656,7 @@ static void run_ksoftirqd(unsigned int cpu)
* in the task stack here.
*/
__do_softirq();
- rcu_note_context_switch(cpu);
+ rcu_note_context_switch();
local_irq_enable();
cond_resched();
return;
diff --git a/kernel/sys.c b/kernel/sys.c
index 1eaa2f0..a8c9f5a 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -91,6 +91,12 @@
#ifndef SET_TSC_CTL
# define SET_TSC_CTL(a) (-EINVAL)
#endif
+#ifndef MPX_ENABLE_MANAGEMENT
+# define MPX_ENABLE_MANAGEMENT(a) (-EINVAL)
+#endif
+#ifndef MPX_DISABLE_MANAGEMENT
+# define MPX_DISABLE_MANAGEMENT(a) (-EINVAL)
+#endif
/*
* this is where the system-wide overflow UID and GID are defined, for
@@ -2203,6 +2209,12 @@ SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
me->mm->def_flags &= ~VM_NOHUGEPAGE;
up_write(&me->mm->mmap_sem);
break;
+ case PR_MPX_ENABLE_MANAGEMENT:
+ error = MPX_ENABLE_MANAGEMENT(me);
+ break;
+ case PR_MPX_DISABLE_MANAGEMENT:
+ error = MPX_DISABLE_MANAGEMENT(me);
+ break;
default:
error = -EINVAL;
break;
diff --git a/kernel/sysctl.c b/kernel/sysctl.c
index 15f2511..7c54ff7 100644
--- a/kernel/sysctl.c
+++ b/kernel/sysctl.c
@@ -1104,6 +1104,15 @@ static struct ctl_table kern_table[] = {
.proc_handler = proc_dointvec,
},
#endif
+ {
+ .procname = "panic_on_warn",
+ .data = &panic_on_warn,
+ .maxlen = sizeof(int),
+ .mode = 0644,
+ .proc_handler = proc_dointvec_minmax,
+ .extra1 = &zero,
+ .extra2 = &one,
+ },
{ }
};
diff --git a/kernel/sysctl_binary.c b/kernel/sysctl_binary.c
index 9a4f750..7e7746a 100644
--- a/kernel/sysctl_binary.c
+++ b/kernel/sysctl_binary.c
@@ -137,6 +137,7 @@ static const struct bin_table bin_kern_table[] = {
{ CTL_INT, KERN_COMPAT_LOG, "compat-log" },
{ CTL_INT, KERN_MAX_LOCK_DEPTH, "max_lock_depth" },
{ CTL_INT, KERN_PANIC_ON_NMI, "panic_on_unrecovered_nmi" },
+ { CTL_INT, KERN_PANIC_ON_WARN, "panic_on_warn" },
{}
};
diff --git a/kernel/taskstats.c b/kernel/taskstats.c
index b312fcc7..670fff8 100644
--- a/kernel/taskstats.c
+++ b/kernel/taskstats.c
@@ -459,7 +459,7 @@ static int cgroupstats_user_cmd(struct sk_buff *skb, struct genl_info *info)
stats = nla_data(na);
memset(stats, 0, sizeof(*stats));
- rc = cgroupstats_build(stats, f.file->f_dentry);
+ rc = cgroupstats_build(stats, f.file->f_path.dentry);
if (rc < 0) {
nlmsg_free(rep_skb);
goto err;
diff --git a/kernel/time/Makefile b/kernel/time/Makefile
index 7347426..f622cf2 100644
--- a/kernel/time/Makefile
+++ b/kernel/time/Makefile
@@ -13,7 +13,7 @@ obj-$(CONFIG_TICK_ONESHOT) += tick-oneshot.o
obj-$(CONFIG_TICK_ONESHOT) += tick-sched.o
obj-$(CONFIG_TIMER_STATS) += timer_stats.o
obj-$(CONFIG_DEBUG_FS) += timekeeping_debug.o
-obj-$(CONFIG_TEST_UDELAY) += udelay_test.o
+obj-$(CONFIG_TEST_UDELAY) += test_udelay.o
$(obj)/time.o: $(obj)/timeconst.h
diff --git a/kernel/time/udelay_test.c b/kernel/time/test_udelay.c
index e622ba3..e622ba3 100644
--- a/kernel/time/udelay_test.c
+++ b/kernel/time/test_udelay.c
diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c
index 7b5741f..1f43560 100644
--- a/kernel/time/tick-sched.c
+++ b/kernel/time/tick-sched.c
@@ -585,7 +585,7 @@ static ktime_t tick_nohz_stop_sched_tick(struct tick_sched *ts,
last_jiffies = jiffies;
} while (read_seqretry(&jiffies_lock, seq));
- if (rcu_needs_cpu(cpu, &rcu_delta_jiffies) ||
+ if (rcu_needs_cpu(&rcu_delta_jiffies) ||
arch_needs_cpu() || irq_work_needs_cpu()) {
next_jiffies = last_jiffies + 1;
delta_jiffies = 1;
diff --git a/kernel/time/time.c b/kernel/time/time.c
index a9ae20f..65015ff 100644
--- a/kernel/time/time.c
+++ b/kernel/time/time.c
@@ -304,7 +304,9 @@ struct timespec timespec_trunc(struct timespec t, unsigned gran)
}
EXPORT_SYMBOL(timespec_trunc);
-/* Converts Gregorian date to seconds since 1970-01-01 00:00:00.
+/*
+ * mktime64 - Converts date to seconds.
+ * Converts Gregorian date to seconds since 1970-01-01 00:00:00.
* Assumes input in normal date format, i.e. 1980-12-31 23:59:59
* => year=1980, mon=12, day=31, hour=23, min=59, sec=59.
*
@@ -314,15 +316,10 @@ EXPORT_SYMBOL(timespec_trunc);
* -year/100+year/400 terms, and add 10.]
*
* This algorithm was first published by Gauss (I think).
- *
- * WARNING: this function will overflow on 2106-02-07 06:28:16 on
- * machines where long is 32-bit! (However, as time_t is signed, we
- * will already get problems at other places on 2038-01-19 03:14:08)
*/
-unsigned long
-mktime(const unsigned int year0, const unsigned int mon0,
- const unsigned int day, const unsigned int hour,
- const unsigned int min, const unsigned int sec)
+time64_t mktime64(const unsigned int year0, const unsigned int mon0,
+ const unsigned int day, const unsigned int hour,
+ const unsigned int min, const unsigned int sec)
{
unsigned int mon = mon0, year = year0;
@@ -332,15 +329,14 @@ mktime(const unsigned int year0, const unsigned int mon0,
year -= 1;
}
- return ((((unsigned long)
+ return ((((time64_t)
(year/4 - year/100 + year/400 + 367*mon/12 + day) +
year*365 - 719499
)*24 + hour /* now have hours */
)*60 + min /* now have minutes */
)*60 + sec; /* finally seconds */
}
-
-EXPORT_SYMBOL(mktime);
+EXPORT_SYMBOL(mktime64);
/**
* set_normalized_timespec - set timespec sec and nsec parts and normalize
diff --git a/kernel/time/timekeeping.c b/kernel/time/timekeeping.c
index ec1791f..6a93185 100644
--- a/kernel/time/timekeeping.c
+++ b/kernel/time/timekeeping.c
@@ -417,7 +417,8 @@ EXPORT_SYMBOL_GPL(pvclock_gtod_unregister_notifier);
*/
static inline void tk_update_ktime_data(struct timekeeper *tk)
{
- s64 nsec;
+ u64 seconds;
+ u32 nsec;
/*
* The xtime based monotonic readout is:
@@ -426,13 +427,22 @@ static inline void tk_update_ktime_data(struct timekeeper *tk)
* nsec = base_mono + now();
* ==> base_mono = (xtime_sec + wtm_sec) * 1e9 + wtm_nsec
*/
- nsec = (s64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
- nsec *= NSEC_PER_SEC;
- nsec += tk->wall_to_monotonic.tv_nsec;
- tk->tkr.base_mono = ns_to_ktime(nsec);
+ seconds = (u64)(tk->xtime_sec + tk->wall_to_monotonic.tv_sec);
+ nsec = (u32) tk->wall_to_monotonic.tv_nsec;
+ tk->tkr.base_mono = ns_to_ktime(seconds * NSEC_PER_SEC + nsec);
/* Update the monotonic raw base */
tk->base_raw = timespec64_to_ktime(tk->raw_time);
+
+ /*
+ * The sum of the nanoseconds portions of xtime and
+ * wall_to_monotonic can be greater/equal one second. Take
+ * this into account before updating tk->ktime_sec.
+ */
+ nsec += (u32)(tk->tkr.xtime_nsec >> tk->tkr.shift);
+ if (nsec >= NSEC_PER_SEC)
+ seconds++;
+ tk->ktime_sec = seconds;
}
/* must hold timekeeper_lock */
@@ -519,9 +529,9 @@ EXPORT_SYMBOL(__getnstimeofday64);
/**
* getnstimeofday64 - Returns the time of day in a timespec64.
- * @ts: pointer to the timespec to be set
+ * @ts: pointer to the timespec64 to be set
*
- * Returns the time of day in a timespec (WARN if suspended).
+ * Returns the time of day in a timespec64 (WARN if suspended).
*/
void getnstimeofday64(struct timespec64 *ts)
{
@@ -623,7 +633,7 @@ EXPORT_SYMBOL_GPL(ktime_get_raw);
*
* The function calculates the monotonic clock from the realtime
* clock and the wall_to_monotonic offset and stores the result
- * in normalized timespec format in the variable pointed to by @ts.
+ * in normalized timespec64 format in the variable pointed to by @ts.
*/
void ktime_get_ts64(struct timespec64 *ts)
{
@@ -648,6 +658,54 @@ void ktime_get_ts64(struct timespec64 *ts)
}
EXPORT_SYMBOL_GPL(ktime_get_ts64);
+/**
+ * ktime_get_seconds - Get the seconds portion of CLOCK_MONOTONIC
+ *
+ * Returns the seconds portion of CLOCK_MONOTONIC with a single non
+ * serialized read. tk->ktime_sec is of type 'unsigned long' so this
+ * works on both 32 and 64 bit systems. On 32 bit systems the readout
+ * covers ~136 years of uptime which should be enough to prevent
+ * premature wrap arounds.
+ */
+time64_t ktime_get_seconds(void)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+
+ WARN_ON(timekeeping_suspended);
+ return tk->ktime_sec;
+}
+EXPORT_SYMBOL_GPL(ktime_get_seconds);
+
+/**
+ * ktime_get_real_seconds - Get the seconds portion of CLOCK_REALTIME
+ *
+ * Returns the wall clock seconds since 1970. This replaces the
+ * get_seconds() interface which is not y2038 safe on 32bit systems.
+ *
+ * For 64bit systems the fast access to tk->xtime_sec is preserved. On
+ * 32bit systems the access must be protected with the sequence
+ * counter to provide "atomic" access to the 64bit tk->xtime_sec
+ * value.
+ */
+time64_t ktime_get_real_seconds(void)
+{
+ struct timekeeper *tk = &tk_core.timekeeper;
+ time64_t seconds;
+ unsigned int seq;
+
+ if (IS_ENABLED(CONFIG_64BIT))
+ return tk->xtime_sec;
+
+ do {
+ seq = read_seqcount_begin(&tk_core.seq);
+ seconds = tk->xtime_sec;
+
+ } while (read_seqcount_retry(&tk_core.seq, seq));
+
+ return seconds;
+}
+EXPORT_SYMBOL_GPL(ktime_get_real_seconds);
+
#ifdef CONFIG_NTP_PPS
/**
@@ -703,18 +761,18 @@ void do_gettimeofday(struct timeval *tv)
EXPORT_SYMBOL(do_gettimeofday);
/**
- * do_settimeofday - Sets the time of day
- * @tv: pointer to the timespec variable containing the new time
+ * do_settimeofday64 - Sets the time of day.
+ * @ts: pointer to the timespec64 variable containing the new time
*
* Sets the time of day to the new time and update NTP and notify hrtimers
*/
-int do_settimeofday(const struct timespec *tv)
+int do_settimeofday64(const struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
- struct timespec64 ts_delta, xt, tmp;
+ struct timespec64 ts_delta, xt;
unsigned long flags;
- if (!timespec_valid_strict(tv))
+ if (!timespec64_valid_strict(ts))
return -EINVAL;
raw_spin_lock_irqsave(&timekeeper_lock, flags);
@@ -723,13 +781,12 @@ int do_settimeofday(const struct timespec *tv)
timekeeping_forward_now(tk);
xt = tk_xtime(tk);
- ts_delta.tv_sec = tv->tv_sec - xt.tv_sec;
- ts_delta.tv_nsec = tv->tv_nsec - xt.tv_nsec;
+ ts_delta.tv_sec = ts->tv_sec - xt.tv_sec;
+ ts_delta.tv_nsec = ts->tv_nsec - xt.tv_nsec;
tk_set_wall_to_mono(tk, timespec64_sub(tk->wall_to_monotonic, ts_delta));
- tmp = timespec_to_timespec64(*tv);
- tk_set_xtime(tk, &tmp);
+ tk_set_xtime(tk, ts);
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
@@ -741,7 +798,7 @@ int do_settimeofday(const struct timespec *tv)
return 0;
}
-EXPORT_SYMBOL(do_settimeofday);
+EXPORT_SYMBOL(do_settimeofday64);
/**
* timekeeping_inject_offset - Adds or subtracts from the current time.
@@ -895,12 +952,12 @@ int timekeeping_notify(struct clocksource *clock)
}
/**
- * getrawmonotonic - Returns the raw monotonic time in a timespec
- * @ts: pointer to the timespec to be set
+ * getrawmonotonic64 - Returns the raw monotonic time in a timespec
+ * @ts: pointer to the timespec64 to be set
*
* Returns the raw monotonic time (completely un-modified by ntp)
*/
-void getrawmonotonic(struct timespec *ts)
+void getrawmonotonic64(struct timespec64 *ts)
{
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 ts64;
@@ -915,9 +972,10 @@ void getrawmonotonic(struct timespec *ts)
} while (read_seqcount_retry(&tk_core.seq, seq));
timespec64_add_ns(&ts64, nsecs);
- *ts = timespec64_to_timespec(ts64);
+ *ts = ts64;
}
-EXPORT_SYMBOL(getrawmonotonic);
+EXPORT_SYMBOL(getrawmonotonic64);
+
/**
* timekeeping_valid_for_hres - Check if timekeeping is suitable for hres
@@ -1068,8 +1126,8 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
}
/**
- * timekeeping_inject_sleeptime - Adds suspend interval to timeekeeping values
- * @delta: pointer to a timespec delta value
+ * timekeeping_inject_sleeptime64 - Adds suspend interval to timeekeeping values
+ * @delta: pointer to a timespec64 delta value
*
* This hook is for architectures that cannot support read_persistent_clock
* because their RTC/persistent clock is only accessible when irqs are enabled.
@@ -1077,10 +1135,9 @@ static void __timekeeping_inject_sleeptime(struct timekeeper *tk,
* This function should only be called by rtc_resume(), and allows
* a suspend offset to be injected into the timekeeping values.
*/
-void timekeeping_inject_sleeptime(struct timespec *delta)
+void timekeeping_inject_sleeptime64(struct timespec64 *delta)
{
struct timekeeper *tk = &tk_core.timekeeper;
- struct timespec64 tmp;
unsigned long flags;
/*
@@ -1095,8 +1152,7 @@ void timekeeping_inject_sleeptime(struct timespec *delta)
timekeeping_forward_now(tk);
- tmp = timespec_to_timespec64(*delta);
- __timekeeping_inject_sleeptime(tk, &tmp);
+ __timekeeping_inject_sleeptime(tk, delta);
timekeeping_update(tk, TK_CLEAR_NTP | TK_MIRROR | TK_CLOCK_WAS_SET);
@@ -1332,6 +1388,12 @@ static __always_inline void timekeeping_apply_adjustment(struct timekeeper *tk,
*
* XXX - TODO: Doc ntp_error calculation.
*/
+ if ((mult_adj > 0) && (tk->tkr.mult + mult_adj < mult_adj)) {
+ /* NTP adjustment caused clocksource mult overflow */
+ WARN_ON_ONCE(1);
+ return;
+ }
+
tk->tkr.mult += mult_adj;
tk->xtime_interval += interval;
tk->tkr.xtime_nsec -= offset;
@@ -1397,7 +1459,8 @@ static void timekeeping_adjust(struct timekeeper *tk, s64 offset)
}
if (unlikely(tk->tkr.clock->maxadj &&
- (tk->tkr.mult > tk->tkr.clock->mult + tk->tkr.clock->maxadj))) {
+ (abs(tk->tkr.mult - tk->tkr.clock->mult)
+ > tk->tkr.clock->maxadj))) {
printk_once(KERN_WARNING
"Adjusting %s more than 11%% (%ld vs %ld)\n",
tk->tkr.clock->name, (long)tk->tkr.mult,
@@ -1646,7 +1709,7 @@ struct timespec current_kernel_time(void)
}
EXPORT_SYMBOL(current_kernel_time);
-struct timespec get_monotonic_coarse(void)
+struct timespec64 get_monotonic_coarse64(void)
{
struct timekeeper *tk = &tk_core.timekeeper;
struct timespec64 now, mono;
@@ -1662,7 +1725,7 @@ struct timespec get_monotonic_coarse(void)
set_normalized_timespec64(&now, now.tv_sec + mono.tv_sec,
now.tv_nsec + mono.tv_nsec);
- return timespec64_to_timespec(now);
+ return now;
}
/*
diff --git a/kernel/time/timer.c b/kernel/time/timer.c
index 3260ffd..2d3f5c5 100644
--- a/kernel/time/timer.c
+++ b/kernel/time/timer.c
@@ -1377,12 +1377,11 @@ unsigned long get_next_timer_interrupt(unsigned long now)
void update_process_times(int user_tick)
{
struct task_struct *p = current;
- int cpu = smp_processor_id();
/* Note: this timer irq context must be accounted for as well. */
account_process_tick(p, user_tick);
run_local_timers();
- rcu_check_callbacks(cpu, user_tick);
+ rcu_check_callbacks(user_tick);
#ifdef CONFIG_IRQ_WORK
if (in_irq())
irq_work_tick();
diff --git a/kernel/trace/blktrace.c b/kernel/trace/blktrace.c
index c1bd4ad..11b9cb3 100644
--- a/kernel/trace/blktrace.c
+++ b/kernel/trace/blktrace.c
@@ -1142,9 +1142,9 @@ static void get_pdu_remap(const struct trace_entry *ent,
r->sector_from = be64_to_cpu(sector_from);
}
-typedef int (blk_log_action_t) (struct trace_iterator *iter, const char *act);
+typedef void (blk_log_action_t) (struct trace_iterator *iter, const char *act);
-static int blk_log_action_classic(struct trace_iterator *iter, const char *act)
+static void blk_log_action_classic(struct trace_iterator *iter, const char *act)
{
char rwbs[RWBS_LEN];
unsigned long long ts = iter->ts;
@@ -1154,33 +1154,33 @@ static int blk_log_action_classic(struct trace_iterator *iter, const char *act)
fill_rwbs(rwbs, t);
- return trace_seq_printf(&iter->seq,
- "%3d,%-3d %2d %5d.%09lu %5u %2s %3s ",
- MAJOR(t->device), MINOR(t->device), iter->cpu,
- secs, nsec_rem, iter->ent->pid, act, rwbs);
+ trace_seq_printf(&iter->seq,
+ "%3d,%-3d %2d %5d.%09lu %5u %2s %3s ",
+ MAJOR(t->device), MINOR(t->device), iter->cpu,
+ secs, nsec_rem, iter->ent->pid, act, rwbs);
}
-static int blk_log_action(struct trace_iterator *iter, const char *act)
+static void blk_log_action(struct trace_iterator *iter, const char *act)
{
char rwbs[RWBS_LEN];
const struct blk_io_trace *t = te_blk_io_trace(iter->ent);
fill_rwbs(rwbs, t);
- return trace_seq_printf(&iter->seq, "%3d,%-3d %2s %3s ",
- MAJOR(t->device), MINOR(t->device), act, rwbs);
+ trace_seq_printf(&iter->seq, "%3d,%-3d %2s %3s ",
+ MAJOR(t->device), MINOR(t->device), act, rwbs);
}
-static int blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent)
{
const unsigned char *pdu_buf;
int pdu_len;
- int i, end, ret;
+ int i, end;
pdu_buf = pdu_start(ent);
pdu_len = te_blk_io_trace(ent)->pdu_len;
if (!pdu_len)
- return 1;
+ return;
/* find the last zero that needs to be printed */
for (end = pdu_len - 1; end >= 0; end--)
@@ -1188,119 +1188,107 @@ static int blk_log_dump_pdu(struct trace_seq *s, const struct trace_entry *ent)
break;
end++;
- if (!trace_seq_putc(s, '('))
- return 0;
+ trace_seq_putc(s, '(');
for (i = 0; i < pdu_len; i++) {
- ret = trace_seq_printf(s, "%s%02x",
- i == 0 ? "" : " ", pdu_buf[i]);
- if (!ret)
- return ret;
+ trace_seq_printf(s, "%s%02x",
+ i == 0 ? "" : " ", pdu_buf[i]);
/*
* stop when the rest is just zeroes and indicate so
* with a ".." appended
*/
- if (i == end && end != pdu_len - 1)
- return trace_seq_puts(s, " ..) ");
+ if (i == end && end != pdu_len - 1) {
+ trace_seq_puts(s, " ..) ");
+ return;
+ }
}
- return trace_seq_puts(s, ") ");
+ trace_seq_puts(s, ") ");
}
-static int blk_log_generic(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_generic(struct trace_seq *s, const struct trace_entry *ent)
{
char cmd[TASK_COMM_LEN];
trace_find_cmdline(ent->pid, cmd);
if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) {
- int ret;
-
- ret = trace_seq_printf(s, "%u ", t_bytes(ent));
- if (!ret)
- return 0;
- ret = blk_log_dump_pdu(s, ent);
- if (!ret)
- return 0;
- return trace_seq_printf(s, "[%s]\n", cmd);
+ trace_seq_printf(s, "%u ", t_bytes(ent));
+ blk_log_dump_pdu(s, ent);
+ trace_seq_printf(s, "[%s]\n", cmd);
} else {
if (t_sec(ent))
- return trace_seq_printf(s, "%llu + %u [%s]\n",
+ trace_seq_printf(s, "%llu + %u [%s]\n",
t_sector(ent), t_sec(ent), cmd);
- return trace_seq_printf(s, "[%s]\n", cmd);
+ else
+ trace_seq_printf(s, "[%s]\n", cmd);
}
}
-static int blk_log_with_error(struct trace_seq *s,
+static void blk_log_with_error(struct trace_seq *s,
const struct trace_entry *ent)
{
if (t_action(ent) & BLK_TC_ACT(BLK_TC_PC)) {
- int ret;
-
- ret = blk_log_dump_pdu(s, ent);
- if (ret)
- return trace_seq_printf(s, "[%d]\n", t_error(ent));
- return 0;
+ blk_log_dump_pdu(s, ent);
+ trace_seq_printf(s, "[%d]\n", t_error(ent));
} else {
if (t_sec(ent))
- return trace_seq_printf(s, "%llu + %u [%d]\n",
- t_sector(ent),
- t_sec(ent), t_error(ent));
- return trace_seq_printf(s, "%llu [%d]\n",
- t_sector(ent), t_error(ent));
+ trace_seq_printf(s, "%llu + %u [%d]\n",
+ t_sector(ent),
+ t_sec(ent), t_error(ent));
+ else
+ trace_seq_printf(s, "%llu [%d]\n",
+ t_sector(ent), t_error(ent));
}
}
-static int blk_log_remap(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_remap(struct trace_seq *s, const struct trace_entry *ent)
{
struct blk_io_trace_remap r = { .device_from = 0, };
get_pdu_remap(ent, &r);
- return trace_seq_printf(s, "%llu + %u <- (%d,%d) %llu\n",
- t_sector(ent), t_sec(ent),
- MAJOR(r.device_from), MINOR(r.device_from),
- (unsigned long long)r.sector_from);
+ trace_seq_printf(s, "%llu + %u <- (%d,%d) %llu\n",
+ t_sector(ent), t_sec(ent),
+ MAJOR(r.device_from), MINOR(r.device_from),
+ (unsigned long long)r.sector_from);
}
-static int blk_log_plug(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_plug(struct trace_seq *s, const struct trace_entry *ent)
{
char cmd[TASK_COMM_LEN];
trace_find_cmdline(ent->pid, cmd);
- return trace_seq_printf(s, "[%s]\n", cmd);
+ trace_seq_printf(s, "[%s]\n", cmd);
}
-static int blk_log_unplug(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_unplug(struct trace_seq *s, const struct trace_entry *ent)
{
char cmd[TASK_COMM_LEN];
trace_find_cmdline(ent->pid, cmd);
- return trace_seq_printf(s, "[%s] %llu\n", cmd, get_pdu_int(ent));
+ trace_seq_printf(s, "[%s] %llu\n", cmd, get_pdu_int(ent));
}
-static int blk_log_split(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_split(struct trace_seq *s, const struct trace_entry *ent)
{
char cmd[TASK_COMM_LEN];
trace_find_cmdline(ent->pid, cmd);
- return trace_seq_printf(s, "%llu / %llu [%s]\n", t_sector(ent),
- get_pdu_int(ent), cmd);
+ trace_seq_printf(s, "%llu / %llu [%s]\n", t_sector(ent),
+ get_pdu_int(ent), cmd);
}
-static int blk_log_msg(struct trace_seq *s, const struct trace_entry *ent)
+static void blk_log_msg(struct trace_seq *s, const struct trace_entry *ent)
{
- int ret;
const struct blk_io_trace *t = te_blk_io_trace(ent);
- ret = trace_seq_putmem(s, t + 1, t->pdu_len);
- if (ret)
- return trace_seq_putc(s, '\n');
- return ret;
+ trace_seq_putmem(s, t + 1, t->pdu_len);
+ trace_seq_putc(s, '\n');
}
/*
@@ -1339,7 +1327,7 @@ static void blk_tracer_reset(struct trace_array *tr)
static const struct {
const char *act[2];
- int (*print)(struct trace_seq *s, const struct trace_entry *ent);
+ void (*print)(struct trace_seq *s, const struct trace_entry *ent);
} what2act[] = {
[__BLK_TA_QUEUE] = {{ "Q", "queue" }, blk_log_generic },
[__BLK_TA_BACKMERGE] = {{ "M", "backmerge" }, blk_log_generic },
@@ -1364,7 +1352,6 @@ static enum print_line_t print_one_line(struct trace_iterator *iter,
struct trace_seq *s = &iter->seq;
const struct blk_io_trace *t;
u16 what;
- int ret;
bool long_act;
blk_log_action_t *log_action;
@@ -1374,21 +1361,18 @@ static enum print_line_t print_one_line(struct trace_iterator *iter,
log_action = classic ? &blk_log_action_classic : &blk_log_action;
if (t->action == BLK_TN_MESSAGE) {
- ret = log_action(iter, long_act ? "message" : "m");
- if (ret)
- ret = blk_log_msg(s, iter->ent);
- goto out;
+ log_action(iter, long_act ? "message" : "m");
+ blk_log_msg(s, iter->ent);
}
if (unlikely(what == 0 || what >= ARRAY_SIZE(what2act)))
- ret = trace_seq_printf(s, "Unknown action %x\n", what);
+ trace_seq_printf(s, "Unknown action %x\n", what);
else {
- ret = log_action(iter, what2act[what].act[long_act]);
- if (ret)
- ret = what2act[what].print(s, iter->ent);
+ log_action(iter, what2act[what].act[long_act]);
+ what2act[what].print(s, iter->ent);
}
-out:
- return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
+
+ return trace_handle_return(s);
}
static enum print_line_t blk_trace_event_print(struct trace_iterator *iter,
@@ -1397,7 +1381,7 @@ static enum print_line_t blk_trace_event_print(struct trace_iterator *iter,
return print_one_line(iter, false);
}
-static int blk_trace_synthesize_old_trace(struct trace_iterator *iter)
+static void blk_trace_synthesize_old_trace(struct trace_iterator *iter)
{
struct trace_seq *s = &iter->seq;
struct blk_io_trace *t = (struct blk_io_trace *)iter->ent;
@@ -1407,18 +1391,18 @@ static int blk_trace_synthesize_old_trace(struct trace_iterator *iter)
.time = iter->ts,
};
- if (!trace_seq_putmem(s, &old, offset))
- return 0;
- return trace_seq_putmem(s, &t->sector,
- sizeof(old) - offset + t->pdu_len);
+ trace_seq_putmem(s, &old, offset);
+ trace_seq_putmem(s, &t->sector,
+ sizeof(old) - offset + t->pdu_len);
}
static enum print_line_t
blk_trace_event_print_binary(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
- return blk_trace_synthesize_old_trace(iter) ?
- TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
+ blk_trace_synthesize_old_trace(iter);
+
+ return trace_handle_return(&iter->seq);
}
static enum print_line_t blk_tracer_print_line(struct trace_iterator *iter)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 31c90fe..929a733d 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -387,6 +387,8 @@ static int remove_ftrace_list_ops(struct ftrace_ops **list,
return ret;
}
+static void ftrace_update_trampoline(struct ftrace_ops *ops);
+
static int __register_ftrace_function(struct ftrace_ops *ops)
{
if (ops->flags & FTRACE_OPS_FL_DELETED)
@@ -416,9 +418,13 @@ static int __register_ftrace_function(struct ftrace_ops *ops)
if (control_ops_alloc(ops))
return -ENOMEM;
add_ftrace_list_ops(&ftrace_control_list, &control_ops, ops);
+ /* The control_ops needs the trampoline update */
+ ops = &control_ops;
} else
add_ftrace_ops(&ftrace_ops_list, ops);
+ ftrace_update_trampoline(ops);
+
if (ftrace_enabled)
update_ftrace_function();
@@ -565,13 +571,13 @@ static int function_stat_cmp(void *p1, void *p2)
static int function_stat_headers(struct seq_file *m)
{
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- seq_printf(m, " Function "
- "Hit Time Avg s^2\n"
- " -------- "
- "--- ---- --- ---\n");
+ seq_puts(m, " Function "
+ "Hit Time Avg s^2\n"
+ " -------- "
+ "--- ---- --- ---\n");
#else
- seq_printf(m, " Function Hit\n"
- " -------- ---\n");
+ seq_puts(m, " Function Hit\n"
+ " -------- ---\n");
#endif
return 0;
}
@@ -598,7 +604,7 @@ static int function_stat_show(struct seq_file *m, void *v)
seq_printf(m, " %-30.30s %10lu", str, rec->counter);
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
- seq_printf(m, " ");
+ seq_puts(m, " ");
avg = rec->time;
do_div(avg, rec->counter);
@@ -1111,6 +1117,43 @@ static struct ftrace_ops global_ops = {
FTRACE_OPS_FL_INITIALIZED,
};
+/*
+ * This is used by __kernel_text_address() to return true if the
+ * address is on a dynamically allocated trampoline that would
+ * not return true for either core_kernel_text() or
+ * is_module_text_address().
+ */
+bool is_ftrace_trampoline(unsigned long addr)
+{
+ struct ftrace_ops *op;
+ bool ret = false;
+
+ /*
+ * Some of the ops may be dynamically allocated,
+ * they are freed after a synchronize_sched().
+ */
+ preempt_disable_notrace();
+
+ do_for_each_ftrace_op(op, ftrace_ops_list) {
+ /*
+ * This is to check for dynamically allocated trampolines.
+ * Trampolines that are in kernel text will have
+ * core_kernel_text() return true.
+ */
+ if (op->trampoline && op->trampoline_size)
+ if (addr >= op->trampoline &&
+ addr < op->trampoline + op->trampoline_size) {
+ ret = true;
+ goto out;
+ }
+ } while_for_each_ftrace_op(op);
+
+ out:
+ preempt_enable_notrace();
+
+ return ret;
+}
+
struct ftrace_page {
struct ftrace_page *next;
struct dyn_ftrace *records;
@@ -1315,6 +1358,9 @@ ftrace_hash_rec_disable_modify(struct ftrace_ops *ops, int filter_hash);
static void
ftrace_hash_rec_enable_modify(struct ftrace_ops *ops, int filter_hash);
+static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops,
+ struct ftrace_hash *new_hash);
+
static int
ftrace_hash_move(struct ftrace_ops *ops, int enable,
struct ftrace_hash **dst, struct ftrace_hash *src)
@@ -1325,8 +1371,13 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
struct ftrace_hash *new_hash;
int size = src->count;
int bits = 0;
+ int ret;
int i;
+ /* Reject setting notrace hash on IPMODIFY ftrace_ops */
+ if (ops->flags & FTRACE_OPS_FL_IPMODIFY && !enable)
+ return -EINVAL;
+
/*
* If the new source is empty, just free dst and assign it
* the empty_hash.
@@ -1360,6 +1411,16 @@ ftrace_hash_move(struct ftrace_ops *ops, int enable,
}
update:
+ /* Make sure this can be applied if it is IPMODIFY ftrace_ops */
+ if (enable) {
+ /* IPMODIFY should be updated only when filter_hash updating */
+ ret = ftrace_hash_ipmodify_update(ops, new_hash);
+ if (ret < 0) {
+ free_ftrace_hash(new_hash);
+ return ret;
+ }
+ }
+
/*
* Remove the current set, update the hash and add
* them back.
@@ -1724,6 +1785,114 @@ static void ftrace_hash_rec_enable_modify(struct ftrace_ops *ops,
ftrace_hash_rec_update_modify(ops, filter_hash, 1);
}
+/*
+ * Try to update IPMODIFY flag on each ftrace_rec. Return 0 if it is OK
+ * or no-needed to update, -EBUSY if it detects a conflict of the flag
+ * on a ftrace_rec, and -EINVAL if the new_hash tries to trace all recs.
+ * Note that old_hash and new_hash has below meanings
+ * - If the hash is NULL, it hits all recs (if IPMODIFY is set, this is rejected)
+ * - If the hash is EMPTY_HASH, it hits nothing
+ * - Anything else hits the recs which match the hash entries.
+ */
+static int __ftrace_hash_update_ipmodify(struct ftrace_ops *ops,
+ struct ftrace_hash *old_hash,
+ struct ftrace_hash *new_hash)
+{
+ struct ftrace_page *pg;
+ struct dyn_ftrace *rec, *end = NULL;
+ int in_old, in_new;
+
+ /* Only update if the ops has been registered */
+ if (!(ops->flags & FTRACE_OPS_FL_ENABLED))
+ return 0;
+
+ if (!(ops->flags & FTRACE_OPS_FL_IPMODIFY))
+ return 0;
+
+ /*
+ * Since the IPMODIFY is a very address sensitive action, we do not
+ * allow ftrace_ops to set all functions to new hash.
+ */
+ if (!new_hash || !old_hash)
+ return -EINVAL;
+
+ /* Update rec->flags */
+ do_for_each_ftrace_rec(pg, rec) {
+ /* We need to update only differences of filter_hash */
+ in_old = !!ftrace_lookup_ip(old_hash, rec->ip);
+ in_new = !!ftrace_lookup_ip(new_hash, rec->ip);
+ if (in_old == in_new)
+ continue;
+
+ if (in_new) {
+ /* New entries must ensure no others are using it */
+ if (rec->flags & FTRACE_FL_IPMODIFY)
+ goto rollback;
+ rec->flags |= FTRACE_FL_IPMODIFY;
+ } else /* Removed entry */
+ rec->flags &= ~FTRACE_FL_IPMODIFY;
+ } while_for_each_ftrace_rec();
+
+ return 0;
+
+rollback:
+ end = rec;
+
+ /* Roll back what we did above */
+ do_for_each_ftrace_rec(pg, rec) {
+ if (rec == end)
+ goto err_out;
+
+ in_old = !!ftrace_lookup_ip(old_hash, rec->ip);
+ in_new = !!ftrace_lookup_ip(new_hash, rec->ip);
+ if (in_old == in_new)
+ continue;
+
+ if (in_new)
+ rec->flags &= ~FTRACE_FL_IPMODIFY;
+ else
+ rec->flags |= FTRACE_FL_IPMODIFY;
+ } while_for_each_ftrace_rec();
+
+err_out:
+ return -EBUSY;
+}
+
+static int ftrace_hash_ipmodify_enable(struct ftrace_ops *ops)
+{
+ struct ftrace_hash *hash = ops->func_hash->filter_hash;
+
+ if (ftrace_hash_empty(hash))
+ hash = NULL;
+
+ return __ftrace_hash_update_ipmodify(ops, EMPTY_HASH, hash);
+}
+
+/* Disabling always succeeds */
+static void ftrace_hash_ipmodify_disable(struct ftrace_ops *ops)
+{
+ struct ftrace_hash *hash = ops->func_hash->filter_hash;
+
+ if (ftrace_hash_empty(hash))
+ hash = NULL;
+
+ __ftrace_hash_update_ipmodify(ops, hash, EMPTY_HASH);
+}
+
+static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops,
+ struct ftrace_hash *new_hash)
+{
+ struct ftrace_hash *old_hash = ops->func_hash->filter_hash;
+
+ if (ftrace_hash_empty(old_hash))
+ old_hash = NULL;
+
+ if (ftrace_hash_empty(new_hash))
+ new_hash = NULL;
+
+ return __ftrace_hash_update_ipmodify(ops, old_hash, new_hash);
+}
+
static void print_ip_ins(const char *fmt, unsigned char *p)
{
int i;
@@ -1734,10 +1903,13 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
printk(KERN_CONT "%s%02x", i ? ":" : "", p[i]);
}
+static struct ftrace_ops *
+ftrace_find_tramp_ops_any(struct dyn_ftrace *rec);
+
/**
* ftrace_bug - report and shutdown function tracer
* @failed: The failed type (EFAULT, EINVAL, EPERM)
- * @ip: The address that failed
+ * @rec: The record that failed
*
* The arch code that enables or disables the function tracing
* can call ftrace_bug() when it has detected a problem in
@@ -1746,8 +1918,10 @@ static void print_ip_ins(const char *fmt, unsigned char *p)
* EINVAL - if what is read at @ip is not what was expected
* EPERM - if the problem happens on writting to the @ip address
*/
-void ftrace_bug(int failed, unsigned long ip)
+void ftrace_bug(int failed, struct dyn_ftrace *rec)
{
+ unsigned long ip = rec ? rec->ip : 0;
+
switch (failed) {
case -EFAULT:
FTRACE_WARN_ON_ONCE(1);
@@ -1759,7 +1933,7 @@ void ftrace_bug(int failed, unsigned long ip)
pr_info("ftrace failed to modify ");
print_ip_sym(ip);
print_ip_ins(" actual: ", (unsigned char *)ip);
- printk(KERN_CONT "\n");
+ pr_cont("\n");
break;
case -EPERM:
FTRACE_WARN_ON_ONCE(1);
@@ -1771,6 +1945,24 @@ void ftrace_bug(int failed, unsigned long ip)
pr_info("ftrace faulted on unknown error ");
print_ip_sym(ip);
}
+ if (rec) {
+ struct ftrace_ops *ops = NULL;
+
+ pr_info("ftrace record flags: %lx\n", rec->flags);
+ pr_cont(" (%ld)%s", ftrace_rec_count(rec),
+ rec->flags & FTRACE_FL_REGS ? " R" : " ");
+ if (rec->flags & FTRACE_FL_TRAMP_EN) {
+ ops = ftrace_find_tramp_ops_any(rec);
+ if (ops)
+ pr_cont("\ttramp: %pS",
+ (void *)ops->trampoline);
+ else
+ pr_cont("\ttramp: ERROR!");
+
+ }
+ ip = ftrace_get_addr_curr(rec);
+ pr_cont(" expected tramp: %lx\n", ip);
+ }
}
static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)
@@ -2093,7 +2285,7 @@ void __weak ftrace_replace_code(int enable)
do_for_each_ftrace_rec(pg, rec) {
failed = __ftrace_replace_code(rec, enable);
if (failed) {
- ftrace_bug(failed, rec->ip);
+ ftrace_bug(failed, rec);
/* Stop processing */
return;
}
@@ -2175,17 +2367,14 @@ struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter)
static int
ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)
{
- unsigned long ip;
int ret;
- ip = rec->ip;
-
if (unlikely(ftrace_disabled))
return 0;
ret = ftrace_make_nop(mod, rec, MCOUNT_ADDR);
if (ret) {
- ftrace_bug(ret, ip);
+ ftrace_bug(ret, rec);
return 0;
}
return 1;
@@ -2320,6 +2509,10 @@ static void ftrace_run_modify_code(struct ftrace_ops *ops, int command,
static ftrace_func_t saved_ftrace_func;
static int ftrace_start_up;
+void __weak arch_ftrace_trampoline_free(struct ftrace_ops *ops)
+{
+}
+
static void control_ops_free(struct ftrace_ops *ops)
{
free_percpu(ops->disabled);
@@ -2369,6 +2562,15 @@ static int ftrace_startup(struct ftrace_ops *ops, int command)
*/
ops->flags |= FTRACE_OPS_FL_ENABLED | FTRACE_OPS_FL_ADDING;
+ ret = ftrace_hash_ipmodify_enable(ops);
+ if (ret < 0) {
+ /* Rollback registration process */
+ __unregister_ftrace_function(ops);
+ ftrace_start_up--;
+ ops->flags &= ~FTRACE_OPS_FL_ENABLED;
+ return ret;
+ }
+
ftrace_hash_rec_enable(ops, 1);
ftrace_startup_enable(command);
@@ -2397,6 +2599,8 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
*/
WARN_ON_ONCE(ftrace_start_up < 0);
+ /* Disabling ipmodify never fails */
+ ftrace_hash_ipmodify_disable(ops);
ftrace_hash_rec_disable(ops, 1);
ops->flags &= ~FTRACE_OPS_FL_ENABLED;
@@ -2471,6 +2675,8 @@ static int ftrace_shutdown(struct ftrace_ops *ops, int command)
if (ops->flags & (FTRACE_OPS_FL_DYNAMIC | FTRACE_OPS_FL_CONTROL)) {
schedule_on_each_cpu(ftrace_sync);
+ arch_ftrace_trampoline_free(ops);
+
if (ops->flags & FTRACE_OPS_FL_CONTROL)
control_ops_free(ops);
}
@@ -2623,7 +2829,7 @@ static int ftrace_update_code(struct module *mod, struct ftrace_page *new_pgs)
if (ftrace_start_up && cnt) {
int failed = __ftrace_replace_code(p, 1);
if (failed)
- ftrace_bug(failed, p->ip);
+ ftrace_bug(failed, p);
}
}
}
@@ -2948,6 +3154,22 @@ static void t_stop(struct seq_file *m, void *p)
mutex_unlock(&ftrace_lock);
}
+void * __weak
+arch_ftrace_trampoline_func(struct ftrace_ops *ops, struct dyn_ftrace *rec)
+{
+ return NULL;
+}
+
+static void add_trampoline_func(struct seq_file *m, struct ftrace_ops *ops,
+ struct dyn_ftrace *rec)
+{
+ void *ptr;
+
+ ptr = arch_ftrace_trampoline_func(ops, rec);
+ if (ptr)
+ seq_printf(m, " ->%pS", ptr);
+}
+
static int t_show(struct seq_file *m, void *v)
{
struct ftrace_iterator *iter = m->private;
@@ -2958,9 +3180,9 @@ static int t_show(struct seq_file *m, void *v)
if (iter->flags & FTRACE_ITER_PRINTALL) {
if (iter->flags & FTRACE_ITER_NOTRACE)
- seq_printf(m, "#### no functions disabled ####\n");
+ seq_puts(m, "#### no functions disabled ####\n");
else
- seq_printf(m, "#### all functions enabled ####\n");
+ seq_puts(m, "#### all functions enabled ####\n");
return 0;
}
@@ -2971,22 +3193,25 @@ static int t_show(struct seq_file *m, void *v)
seq_printf(m, "%ps", (void *)rec->ip);
if (iter->flags & FTRACE_ITER_ENABLED) {
- seq_printf(m, " (%ld)%s",
+ struct ftrace_ops *ops = NULL;
+
+ seq_printf(m, " (%ld)%s%s",
ftrace_rec_count(rec),
- rec->flags & FTRACE_FL_REGS ? " R" : " ");
+ rec->flags & FTRACE_FL_REGS ? " R" : " ",
+ rec->flags & FTRACE_FL_IPMODIFY ? " I" : " ");
if (rec->flags & FTRACE_FL_TRAMP_EN) {
- struct ftrace_ops *ops;
-
ops = ftrace_find_tramp_ops_any(rec);
if (ops)
seq_printf(m, "\ttramp: %pS",
(void *)ops->trampoline);
else
- seq_printf(m, "\ttramp: ERROR!");
+ seq_puts(m, "\ttramp: ERROR!");
+
}
+ add_trampoline_func(m, ops, rec);
}
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
@@ -3020,9 +3245,6 @@ ftrace_enabled_open(struct inode *inode, struct file *file)
{
struct ftrace_iterator *iter;
- if (unlikely(ftrace_disabled))
- return -ENODEV;
-
iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter));
if (iter) {
iter->pg = ftrace_pages_start;
@@ -3975,6 +4197,9 @@ static char ftrace_graph_buf[FTRACE_FILTER_SIZE] __initdata;
static char ftrace_graph_notrace_buf[FTRACE_FILTER_SIZE] __initdata;
static int ftrace_set_func(unsigned long *array, int *idx, int size, char *buffer);
+static unsigned long save_global_trampoline;
+static unsigned long save_global_flags;
+
static int __init set_graph_function(char *str)
{
strlcpy(ftrace_graph_buf, str, FTRACE_FILTER_SIZE);
@@ -4183,9 +4408,9 @@ static int g_show(struct seq_file *m, void *v)
struct ftrace_graph_data *fgd = m->private;
if (fgd->table == ftrace_graph_funcs)
- seq_printf(m, "#### all functions enabled ####\n");
+ seq_puts(m, "#### all functions enabled ####\n");
else
- seq_printf(m, "#### no functions disabled ####\n");
+ seq_puts(m, "#### no functions disabled ####\n");
return 0;
}
@@ -4696,6 +4921,32 @@ void __init ftrace_init(void)
ftrace_disabled = 1;
}
+/* Do nothing if arch does not support this */
+void __weak arch_ftrace_update_trampoline(struct ftrace_ops *ops)
+{
+}
+
+static void ftrace_update_trampoline(struct ftrace_ops *ops)
+{
+
+/*
+ * Currently there's no safe way to free a trampoline when the kernel
+ * is configured with PREEMPT. That is because a task could be preempted
+ * when it jumped to the trampoline, it may be preempted for a long time
+ * depending on the system load, and currently there's no way to know
+ * when it will be off the trampoline. If the trampoline is freed
+ * too early, when the task runs again, it will be executing on freed
+ * memory and crash.
+ */
+#ifdef CONFIG_PREEMPT
+ /* Currently, only non dynamic ops can have a trampoline */
+ if (ops->flags & FTRACE_OPS_FL_DYNAMIC)
+ return;
+#endif
+
+ arch_ftrace_update_trampoline(ops);
+}
+
#else
static struct ftrace_ops global_ops = {
@@ -4738,6 +4989,10 @@ ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)
return 1;
}
+static void ftrace_update_trampoline(struct ftrace_ops *ops)
+{
+}
+
#endif /* CONFIG_DYNAMIC_FTRACE */
__init void ftrace_init_global_array_ops(struct trace_array *tr)
@@ -5075,12 +5330,12 @@ static int fpid_show(struct seq_file *m, void *v)
const struct ftrace_pid *fpid = list_entry(v, struct ftrace_pid, list);
if (v == (void *)1) {
- seq_printf(m, "no pid\n");
+ seq_puts(m, "no pid\n");
return 0;
}
if (fpid->pid == ftrace_swapper_pid)
- seq_printf(m, "swapper tasks\n");
+ seq_puts(m, "swapper tasks\n");
else
seq_printf(m, "%u\n", pid_vnr(fpid->pid));
@@ -5293,6 +5548,7 @@ static struct ftrace_ops graph_ops = {
FTRACE_OPS_FL_STUB,
#ifdef FTRACE_GRAPH_TRAMP_ADDR
.trampoline = FTRACE_GRAPH_TRAMP_ADDR,
+ /* trampoline_size is only needed for dynamically allocated tramps */
#endif
ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)
};
@@ -5522,7 +5778,6 @@ int register_ftrace_graph(trace_func_graph_ret_t retfunc,
update_function_graph_func();
ret = ftrace_startup(&graph_ops, FTRACE_START_FUNC_RET);
-
out:
mutex_unlock(&ftrace_lock);
return ret;
@@ -5543,6 +5798,17 @@ void unregister_ftrace_graph(void)
unregister_pm_notifier(&ftrace_suspend_notifier);
unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);
+#ifdef CONFIG_DYNAMIC_FTRACE
+ /*
+ * Function graph does not allocate the trampoline, but
+ * other global_ops do. We need to reset the ALLOC_TRAMP flag
+ * if one was used.
+ */
+ global_ops.trampoline = save_global_trampoline;
+ if (save_global_flags & FTRACE_OPS_FL_ALLOC_TRAMP)
+ global_ops.flags |= FTRACE_OPS_FL_ALLOC_TRAMP;
+#endif
+
out:
mutex_unlock(&ftrace_lock);
}
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index a56e07c..7a4104c 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -34,21 +34,19 @@ static void update_pages_handler(struct work_struct *work);
*/
int ring_buffer_print_entry_header(struct trace_seq *s)
{
- int ret;
-
- ret = trace_seq_puts(s, "# compressed entry header\n");
- ret = trace_seq_puts(s, "\ttype_len : 5 bits\n");
- ret = trace_seq_puts(s, "\ttime_delta : 27 bits\n");
- ret = trace_seq_puts(s, "\tarray : 32 bits\n");
- ret = trace_seq_putc(s, '\n');
- ret = trace_seq_printf(s, "\tpadding : type == %d\n",
- RINGBUF_TYPE_PADDING);
- ret = trace_seq_printf(s, "\ttime_extend : type == %d\n",
- RINGBUF_TYPE_TIME_EXTEND);
- ret = trace_seq_printf(s, "\tdata max type_len == %d\n",
- RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
+ trace_seq_puts(s, "# compressed entry header\n");
+ trace_seq_puts(s, "\ttype_len : 5 bits\n");
+ trace_seq_puts(s, "\ttime_delta : 27 bits\n");
+ trace_seq_puts(s, "\tarray : 32 bits\n");
+ trace_seq_putc(s, '\n');
+ trace_seq_printf(s, "\tpadding : type == %d\n",
+ RINGBUF_TYPE_PADDING);
+ trace_seq_printf(s, "\ttime_extend : type == %d\n",
+ RINGBUF_TYPE_TIME_EXTEND);
+ trace_seq_printf(s, "\tdata max type_len == %d\n",
+ RINGBUF_TYPE_DATA_TYPE_LEN_MAX);
- return ret;
+ return !trace_seq_has_overflowed(s);
}
/*
@@ -419,32 +417,31 @@ static inline int test_time_stamp(u64 delta)
int ring_buffer_print_page_header(struct trace_seq *s)
{
struct buffer_data_page field;
- int ret;
-
- ret = trace_seq_printf(s, "\tfield: u64 timestamp;\t"
- "offset:0;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)sizeof(field.time_stamp),
- (unsigned int)is_signed_type(u64));
-
- ret = trace_seq_printf(s, "\tfield: local_t commit;\t"
- "offset:%u;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)offsetof(typeof(field), commit),
- (unsigned int)sizeof(field.commit),
- (unsigned int)is_signed_type(long));
-
- ret = trace_seq_printf(s, "\tfield: int overwrite;\t"
- "offset:%u;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)offsetof(typeof(field), commit),
- 1,
- (unsigned int)is_signed_type(long));
-
- ret = trace_seq_printf(s, "\tfield: char data;\t"
- "offset:%u;\tsize:%u;\tsigned:%u;\n",
- (unsigned int)offsetof(typeof(field), data),
- (unsigned int)BUF_PAGE_SIZE,
- (unsigned int)is_signed_type(char));
- return ret;
+ trace_seq_printf(s, "\tfield: u64 timestamp;\t"
+ "offset:0;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)sizeof(field.time_stamp),
+ (unsigned int)is_signed_type(u64));
+
+ trace_seq_printf(s, "\tfield: local_t commit;\t"
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)offsetof(typeof(field), commit),
+ (unsigned int)sizeof(field.commit),
+ (unsigned int)is_signed_type(long));
+
+ trace_seq_printf(s, "\tfield: int overwrite;\t"
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)offsetof(typeof(field), commit),
+ 1,
+ (unsigned int)is_signed_type(long));
+
+ trace_seq_printf(s, "\tfield: char data;\t"
+ "offset:%u;\tsize:%u;\tsigned:%u;\n",
+ (unsigned int)offsetof(typeof(field), data),
+ (unsigned int)BUF_PAGE_SIZE,
+ (unsigned int)is_signed_type(char));
+
+ return !trace_seq_has_overflowed(s);
}
struct rb_irq_work {
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index 92f4a6c..1af4f8f 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -155,10 +155,11 @@ __setup("ftrace_dump_on_oops", set_ftrace_dump_on_oops);
static int __init stop_trace_on_warning(char *str)
{
- __disable_trace_on_warning = 1;
+ if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0))
+ __disable_trace_on_warning = 1;
return 1;
}
-__setup("traceoff_on_warning=", stop_trace_on_warning);
+__setup("traceoff_on_warning", stop_trace_on_warning);
static int __init boot_alloc_snapshot(char *str)
{
@@ -938,19 +939,20 @@ out:
return ret;
}
+/* TODO add a seq_buf_to_buffer() */
static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
{
int len;
- if (s->len <= s->readpos)
+ if (trace_seq_used(s) <= s->seq.readpos)
return -EBUSY;
- len = s->len - s->readpos;
+ len = trace_seq_used(s) - s->seq.readpos;
if (cnt > len)
cnt = len;
- memcpy(buf, s->buffer + s->readpos, cnt);
+ memcpy(buf, s->buffer + s->seq.readpos, cnt);
- s->readpos += cnt;
+ s->seq.readpos += cnt;
return cnt;
}
@@ -2158,9 +2160,7 @@ __trace_array_vprintk(struct ring_buffer *buffer,
goto out;
}
- len = vsnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
- if (len > TRACE_BUF_SIZE)
- goto out;
+ len = vscnprintf(tbuffer, TRACE_BUF_SIZE, fmt, args);
local_save_flags(flags);
size = sizeof(*entry) + len + 1;
@@ -2171,8 +2171,7 @@ __trace_array_vprintk(struct ring_buffer *buffer,
entry = ring_buffer_event_data(event);
entry->ip = ip;
- memcpy(&entry->buf, tbuffer, len);
- entry->buf[len] = '\0';
+ memcpy(&entry->buf, tbuffer, len + 1);
if (!call_filter_check_discard(call, entry, buffer, event)) {
__buffer_unlock_commit(buffer, event);
ftrace_trace_stack(buffer, flags, 6, pc);
@@ -2509,14 +2508,14 @@ get_total_entries(struct trace_buffer *buf,
static void print_lat_help_header(struct seq_file *m)
{
- seq_puts(m, "# _------=> CPU# \n");
- seq_puts(m, "# / _-----=> irqs-off \n");
- seq_puts(m, "# | / _----=> need-resched \n");
- seq_puts(m, "# || / _---=> hardirq/softirq \n");
- seq_puts(m, "# ||| / _--=> preempt-depth \n");
- seq_puts(m, "# |||| / delay \n");
- seq_puts(m, "# cmd pid ||||| time | caller \n");
- seq_puts(m, "# \\ / ||||| \\ | / \n");
+ seq_puts(m, "# _------=> CPU# \n"
+ "# / _-----=> irqs-off \n"
+ "# | / _----=> need-resched \n"
+ "# || / _---=> hardirq/softirq \n"
+ "# ||| / _--=> preempt-depth \n"
+ "# |||| / delay \n"
+ "# cmd pid ||||| time | caller \n"
+ "# \\ / ||||| \\ | / \n");
}
static void print_event_info(struct trace_buffer *buf, struct seq_file *m)
@@ -2533,20 +2532,20 @@ static void print_event_info(struct trace_buffer *buf, struct seq_file *m)
static void print_func_help_header(struct trace_buffer *buf, struct seq_file *m)
{
print_event_info(buf, m);
- seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n");
- seq_puts(m, "# | | | | |\n");
+ seq_puts(m, "# TASK-PID CPU# TIMESTAMP FUNCTION\n"
+ "# | | | | |\n");
}
static void print_func_help_header_irq(struct trace_buffer *buf, struct seq_file *m)
{
print_event_info(buf, m);
- seq_puts(m, "# _-----=> irqs-off\n");
- seq_puts(m, "# / _----=> need-resched\n");
- seq_puts(m, "# | / _---=> hardirq/softirq\n");
- seq_puts(m, "# || / _--=> preempt-depth\n");
- seq_puts(m, "# ||| / delay\n");
- seq_puts(m, "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n");
- seq_puts(m, "# | | | |||| | |\n");
+ seq_puts(m, "# _-----=> irqs-off\n"
+ "# / _----=> need-resched\n"
+ "# | / _---=> hardirq/softirq\n"
+ "# || / _--=> preempt-depth\n"
+ "# ||| / delay\n"
+ "# TASK-PID CPU# |||| TIMESTAMP FUNCTION\n"
+ "# | | | |||| | |\n");
}
void
@@ -2649,24 +2648,21 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
event = ftrace_find_event(entry->type);
if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
- if (iter->iter_flags & TRACE_FILE_LAT_FMT) {
- if (!trace_print_lat_context(iter))
- goto partial;
- } else {
- if (!trace_print_context(iter))
- goto partial;
- }
+ if (iter->iter_flags & TRACE_FILE_LAT_FMT)
+ trace_print_lat_context(iter);
+ else
+ trace_print_context(iter);
}
+ if (trace_seq_has_overflowed(s))
+ return TRACE_TYPE_PARTIAL_LINE;
+
if (event)
return event->funcs->trace(iter, sym_flags, event);
- if (!trace_seq_printf(s, "Unknown type %d\n", entry->type))
- goto partial;
+ trace_seq_printf(s, "Unknown type %d\n", entry->type);
- return TRACE_TYPE_HANDLED;
-partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
@@ -2677,22 +2673,20 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
entry = iter->ent;
- if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
- if (!trace_seq_printf(s, "%d %d %llu ",
- entry->pid, iter->cpu, iter->ts))
- goto partial;
- }
+ if (trace_flags & TRACE_ITER_CONTEXT_INFO)
+ trace_seq_printf(s, "%d %d %llu ",
+ entry->pid, iter->cpu, iter->ts);
+
+ if (trace_seq_has_overflowed(s))
+ return TRACE_TYPE_PARTIAL_LINE;
event = ftrace_find_event(entry->type);
if (event)
return event->funcs->raw(iter, 0, event);
- if (!trace_seq_printf(s, "%d ?\n", entry->type))
- goto partial;
+ trace_seq_printf(s, "%d ?\n", entry->type);
- return TRACE_TYPE_HANDLED;
-partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
@@ -2705,9 +2699,11 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
entry = iter->ent;
if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
- SEQ_PUT_HEX_FIELD_RET(s, entry->pid);
- SEQ_PUT_HEX_FIELD_RET(s, iter->cpu);
- SEQ_PUT_HEX_FIELD_RET(s, iter->ts);
+ SEQ_PUT_HEX_FIELD(s, entry->pid);
+ SEQ_PUT_HEX_FIELD(s, iter->cpu);
+ SEQ_PUT_HEX_FIELD(s, iter->ts);
+ if (trace_seq_has_overflowed(s))
+ return TRACE_TYPE_PARTIAL_LINE;
}
event = ftrace_find_event(entry->type);
@@ -2717,9 +2713,9 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
return ret;
}
- SEQ_PUT_FIELD_RET(s, newline);
+ SEQ_PUT_FIELD(s, newline);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
@@ -2731,9 +2727,11 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
entry = iter->ent;
if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
- SEQ_PUT_FIELD_RET(s, entry->pid);
- SEQ_PUT_FIELD_RET(s, iter->cpu);
- SEQ_PUT_FIELD_RET(s, iter->ts);
+ SEQ_PUT_FIELD(s, entry->pid);
+ SEQ_PUT_FIELD(s, iter->cpu);
+ SEQ_PUT_FIELD(s, iter->ts);
+ if (trace_seq_has_overflowed(s))
+ return TRACE_TYPE_PARTIAL_LINE;
}
event = ftrace_find_event(entry->type);
@@ -2779,10 +2777,12 @@ enum print_line_t print_trace_line(struct trace_iterator *iter)
{
enum print_line_t ret;
- if (iter->lost_events &&
- !trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n",
- iter->cpu, iter->lost_events))
- return TRACE_TYPE_PARTIAL_LINE;
+ if (iter->lost_events) {
+ trace_seq_printf(&iter->seq, "CPU:%d [LOST %lu EVENTS]\n",
+ iter->cpu, iter->lost_events);
+ if (trace_seq_has_overflowed(&iter->seq))
+ return TRACE_TYPE_PARTIAL_LINE;
+ }
if (iter->trace && iter->trace->print_line) {
ret = iter->trace->print_line(iter);
@@ -2860,44 +2860,44 @@ static void test_ftrace_alive(struct seq_file *m)
{
if (!ftrace_is_dead())
return;
- seq_printf(m, "# WARNING: FUNCTION TRACING IS CORRUPTED\n");
- seq_printf(m, "# MAY BE MISSING FUNCTION EVENTS\n");
+ seq_puts(m, "# WARNING: FUNCTION TRACING IS CORRUPTED\n"
+ "# MAY BE MISSING FUNCTION EVENTS\n");
}
#ifdef CONFIG_TRACER_MAX_TRACE
static void show_snapshot_main_help(struct seq_file *m)
{
- seq_printf(m, "# echo 0 > snapshot : Clears and frees snapshot buffer\n");
- seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
- seq_printf(m, "# Takes a snapshot of the main buffer.\n");
- seq_printf(m, "# echo 2 > snapshot : Clears snapshot buffer (but does not allocate or free)\n");
- seq_printf(m, "# (Doesn't have to be '2' works with any number that\n");
- seq_printf(m, "# is not a '0' or '1')\n");
+ seq_puts(m, "# echo 0 > snapshot : Clears and frees snapshot buffer\n"
+ "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n"
+ "# Takes a snapshot of the main buffer.\n"
+ "# echo 2 > snapshot : Clears snapshot buffer (but does not allocate or free)\n"
+ "# (Doesn't have to be '2' works with any number that\n"
+ "# is not a '0' or '1')\n");
}
static void show_snapshot_percpu_help(struct seq_file *m)
{
- seq_printf(m, "# echo 0 > snapshot : Invalid for per_cpu snapshot file.\n");
+ seq_puts(m, "# echo 0 > snapshot : Invalid for per_cpu snapshot file.\n");
#ifdef CONFIG_RING_BUFFER_ALLOW_SWAP
- seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
- seq_printf(m, "# Takes a snapshot of the main buffer for this cpu.\n");
+ seq_puts(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n"
+ "# Takes a snapshot of the main buffer for this cpu.\n");
#else
- seq_printf(m, "# echo 1 > snapshot : Not supported with this kernel.\n");
- seq_printf(m, "# Must use main snapshot file to allocate.\n");
+ seq_puts(m, "# echo 1 > snapshot : Not supported with this kernel.\n"
+ "# Must use main snapshot file to allocate.\n");
#endif
- seq_printf(m, "# echo 2 > snapshot : Clears this cpu's snapshot buffer (but does not allocate)\n");
- seq_printf(m, "# (Doesn't have to be '2' works with any number that\n");
- seq_printf(m, "# is not a '0' or '1')\n");
+ seq_puts(m, "# echo 2 > snapshot : Clears this cpu's snapshot buffer (but does not allocate)\n"
+ "# (Doesn't have to be '2' works with any number that\n"
+ "# is not a '0' or '1')\n");
}
static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
{
if (iter->tr->allocated_snapshot)
- seq_printf(m, "#\n# * Snapshot is allocated *\n#\n");
+ seq_puts(m, "#\n# * Snapshot is allocated *\n#\n");
else
- seq_printf(m, "#\n# * Snapshot is freed *\n#\n");
+ seq_puts(m, "#\n# * Snapshot is freed *\n#\n");
- seq_printf(m, "# Snapshot commands:\n");
+ seq_puts(m, "# Snapshot commands:\n");
if (iter->cpu_file == RING_BUFFER_ALL_CPUS)
show_snapshot_main_help(m);
else
@@ -3251,7 +3251,7 @@ static int t_show(struct seq_file *m, void *v)
if (!t)
return 0;
- seq_printf(m, "%s", t->name);
+ seq_puts(m, t->name);
if (t->next)
seq_putc(m, ' ');
else
@@ -4314,6 +4314,8 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
goto out;
}
+ trace_seq_init(&iter->seq);
+
/*
* We make a copy of the current tracer to avoid concurrent
* changes on it while we are reading.
@@ -4507,18 +4509,18 @@ waitagain:
trace_access_lock(iter->cpu_file);
while (trace_find_next_entry_inc(iter) != NULL) {
enum print_line_t ret;
- int len = iter->seq.len;
+ int save_len = iter->seq.seq.len;
ret = print_trace_line(iter);
if (ret == TRACE_TYPE_PARTIAL_LINE) {
/* don't print partial lines */
- iter->seq.len = len;
+ iter->seq.seq.len = save_len;
break;
}
if (ret != TRACE_TYPE_NO_CONSUME)
trace_consume(iter);
- if (iter->seq.len >= cnt)
+ if (trace_seq_used(&iter->seq) >= cnt)
break;
/*
@@ -4534,7 +4536,7 @@ waitagain:
/* Now copy what we have to the user */
sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
- if (iter->seq.readpos >= iter->seq.len)
+ if (iter->seq.seq.readpos >= trace_seq_used(&iter->seq))
trace_seq_init(&iter->seq);
/*
@@ -4568,20 +4570,33 @@ static size_t
tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)
{
size_t count;
+ int save_len;
int ret;
/* Seq buffer is page-sized, exactly what we need. */
for (;;) {
- count = iter->seq.len;
+ save_len = iter->seq.seq.len;
ret = print_trace_line(iter);
- count = iter->seq.len - count;
- if (rem < count) {
- rem = 0;
- iter->seq.len -= count;
+
+ if (trace_seq_has_overflowed(&iter->seq)) {
+ iter->seq.seq.len = save_len;
break;
}
+
+ /*
+ * This should not be hit, because it should only
+ * be set if the iter->seq overflowed. But check it
+ * anyway to be safe.
+ */
if (ret == TRACE_TYPE_PARTIAL_LINE) {
- iter->seq.len -= count;
+ iter->seq.seq.len = save_len;
+ break;
+ }
+
+ count = trace_seq_used(&iter->seq) - save_len;
+ if (rem < count) {
+ rem = 0;
+ iter->seq.seq.len = save_len;
break;
}
@@ -4662,13 +4677,13 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
/* Copy the data into the page, so we can start over. */
ret = trace_seq_to_buffer(&iter->seq,
page_address(spd.pages[i]),
- iter->seq.len);
+ trace_seq_used(&iter->seq));
if (ret < 0) {
__free_page(spd.pages[i]);
break;
}
spd.partial[i].offset = 0;
- spd.partial[i].len = iter->seq.len;
+ spd.partial[i].len = trace_seq_used(&iter->seq);
trace_seq_init(&iter->seq);
}
@@ -5668,7 +5683,8 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
cnt = ring_buffer_read_events_cpu(trace_buf->buffer, cpu);
trace_seq_printf(s, "read events: %ld\n", cnt);
- count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
+ count = simple_read_from_buffer(ubuf, count, ppos,
+ s->buffer, trace_seq_used(s));
kfree(s);
@@ -5749,10 +5765,10 @@ ftrace_snapshot_print(struct seq_file *m, unsigned long ip,
seq_printf(m, "%ps:", (void *)ip);
- seq_printf(m, "snapshot");
+ seq_puts(m, "snapshot");
if (count == -1)
- seq_printf(m, ":unlimited\n");
+ seq_puts(m, ":unlimited\n");
else
seq_printf(m, ":count=%ld\n", count);
@@ -6417,7 +6433,7 @@ static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t m
int ret;
/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;
@@ -6444,7 +6460,7 @@ static int instance_rmdir(struct inode *inode, struct dentry *dentry)
int ret;
/* Paranoid: Make sure the parent is the "instances" directory */
- parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+ parent = hlist_entry(inode->i_dentry.first, struct dentry, d_u.d_alias);
if (WARN_ON_ONCE(parent != trace_instance_dir))
return -ENOENT;
@@ -6631,11 +6647,19 @@ void
trace_printk_seq(struct trace_seq *s)
{
/* Probably should print a warning here. */
- if (s->len >= TRACE_MAX_PRINT)
- s->len = TRACE_MAX_PRINT;
+ if (s->seq.len >= TRACE_MAX_PRINT)
+ s->seq.len = TRACE_MAX_PRINT;
+
+ /*
+ * More paranoid code. Although the buffer size is set to
+ * PAGE_SIZE, and TRACE_MAX_PRINT is 1000, this is just
+ * an extra layer of protection.
+ */
+ if (WARN_ON_ONCE(s->seq.len >= s->seq.size))
+ s->seq.len = s->seq.size - 1;
/* should be zero ended, but we are paranoid. */
- s->buffer[s->len] = 0;
+ s->buffer[s->seq.len] = 0;
printk(KERN_TRACE "%s", s->buffer);
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 385391f..3255dfb 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -14,6 +14,7 @@
#include <linux/trace_seq.h>
#include <linux/ftrace_event.h>
#include <linux/compiler.h>
+#include <linux/trace_seq.h>
#ifdef CONFIG_FTRACE_SYSCALLS
#include <asm/unistd.h> /* For NR_SYSCALLS */
@@ -569,15 +570,6 @@ void trace_init_global_iter(struct trace_iterator *iter);
void tracing_iter_reset(struct trace_iterator *iter, int cpu);
-void tracing_sched_switch_trace(struct trace_array *tr,
- struct task_struct *prev,
- struct task_struct *next,
- unsigned long flags, int pc);
-
-void tracing_sched_wakeup_trace(struct trace_array *tr,
- struct task_struct *wakee,
- struct task_struct *cur,
- unsigned long flags, int pc);
void trace_function(struct trace_array *tr,
unsigned long ip,
unsigned long parent_ip,
@@ -597,9 +589,6 @@ void set_graph_array(struct trace_array *tr);
void tracing_start_cmdline_record(void);
void tracing_stop_cmdline_record(void);
-void tracing_sched_switch_assign_trace(struct trace_array *tr);
-void tracing_stop_sched_switch_record(void);
-void tracing_start_sched_switch_record(void);
int register_tracer(struct tracer *type);
int is_tracing_stopped(void);
@@ -719,6 +708,8 @@ enum print_line_t print_trace_line(struct trace_iterator *iter);
extern unsigned long trace_flags;
+extern char trace_find_mark(unsigned long long duration);
+
/* Standard output formatting function used for function return traces */
#ifdef CONFIG_FUNCTION_GRAPH_TRACER
@@ -737,7 +728,7 @@ extern unsigned long trace_flags;
extern enum print_line_t
print_graph_function_flags(struct trace_iterator *iter, u32 flags);
extern void print_graph_headers_flags(struct seq_file *s, u32 flags);
-extern enum print_line_t
+extern void
trace_print_graph_duration(unsigned long long duration, struct trace_seq *s);
extern void graph_trace_open(struct trace_iterator *iter);
extern void graph_trace_close(struct trace_iterator *iter);
diff --git a/kernel/trace/trace_branch.c b/kernel/trace/trace_branch.c
index 697fb9b..7d6e2af 100644
--- a/kernel/trace/trace_branch.c
+++ b/kernel/trace/trace_branch.c
@@ -151,22 +151,21 @@ static enum print_line_t trace_branch_print(struct trace_iterator *iter,
trace_assign_type(field, iter->ent);
- if (trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n",
- field->correct ? " ok " : " MISS ",
- field->func,
- field->file,
- field->line))
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_printf(&iter->seq, "[%s] %s:%s:%d\n",
+ field->correct ? " ok " : " MISS ",
+ field->func,
+ field->file,
+ field->line);
+
+ return trace_handle_return(&iter->seq);
}
static void branch_print_header(struct seq_file *s)
{
seq_puts(s, "# TASK-PID CPU# TIMESTAMP CORRECT"
- " FUNC:FILE:LINE\n");
- seq_puts(s, "# | | | | | "
- " |\n");
+ " FUNC:FILE:LINE\n"
+ "# | | | | | "
+ " |\n");
}
static struct trace_event_functions trace_branch_funcs = {
@@ -233,12 +232,12 @@ extern unsigned long __stop_annotated_branch_profile[];
static int annotated_branch_stat_headers(struct seq_file *m)
{
- seq_printf(m, " correct incorrect %% ");
- seq_printf(m, " Function "
- " File Line\n"
- " ------- --------- - "
- " -------- "
- " ---- ----\n");
+ seq_puts(m, " correct incorrect % "
+ " Function "
+ " File Line\n"
+ " ------- --------- - "
+ " -------- "
+ " ---- ----\n");
return 0;
}
@@ -274,7 +273,7 @@ static int branch_stat_show(struct seq_file *m, void *v)
seq_printf(m, "%8lu %8lu ", p->correct, p->incorrect);
if (percent < 0)
- seq_printf(m, " X ");
+ seq_puts(m, " X ");
else
seq_printf(m, "%3ld ", percent);
seq_printf(m, "%-30.30s %-20.20s %d\n", p->func, f, p->line);
@@ -362,12 +361,12 @@ extern unsigned long __stop_branch_profile[];
static int all_branch_stat_headers(struct seq_file *m)
{
- seq_printf(m, " miss hit %% ");
- seq_printf(m, " Function "
- " File Line\n"
- " ------- --------- - "
- " -------- "
- " ---- ----\n");
+ seq_puts(m, " miss hit % "
+ " Function "
+ " File Line\n"
+ " ------- --------- - "
+ " -------- "
+ " ---- ----\n");
return 0;
}
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 0cc51ed..d0e4f92 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -461,7 +461,7 @@ static void remove_event_file_dir(struct ftrace_event_file *file)
if (dir) {
spin_lock(&dir->d_lock); /* probably unneeded */
- list_for_each_entry(child, &dir->d_subdirs, d_u.d_child) {
+ list_for_each_entry(child, &dir->d_subdirs, d_child) {
if (child->d_inode) /* probably unneeded */
child->d_inode->i_private = NULL;
}
@@ -918,7 +918,7 @@ static int f_show(struct seq_file *m, void *v)
case FORMAT_HEADER:
seq_printf(m, "name: %s\n", ftrace_event_name(call));
seq_printf(m, "ID: %d\n", call->event.type);
- seq_printf(m, "format:\n");
+ seq_puts(m, "format:\n");
return 0;
case FORMAT_FIELD_SEPERATOR:
@@ -1044,7 +1044,8 @@ event_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
mutex_unlock(&event_mutex);
if (file)
- r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+ r = simple_read_from_buffer(ubuf, cnt, ppos,
+ s->buffer, trace_seq_used(s));
kfree(s);
@@ -1210,7 +1211,8 @@ subsystem_filter_read(struct file *filp, char __user *ubuf, size_t cnt,
trace_seq_init(s);
print_subsystem_event_filter(system, s);
- r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+ r = simple_read_from_buffer(ubuf, cnt, ppos,
+ s->buffer, trace_seq_used(s));
kfree(s);
@@ -1265,7 +1267,8 @@ show_header(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppos)
trace_seq_init(s);
func(s);
- r = simple_read_from_buffer(ubuf, cnt, ppos, s->buffer, s->len);
+ r = simple_read_from_buffer(ubuf, cnt, ppos,
+ s->buffer, trace_seq_used(s));
kfree(s);
@@ -1988,7 +1991,7 @@ event_enable_print(struct seq_file *m, unsigned long ip,
ftrace_event_name(data->file->event_call));
if (data->count == -1)
- seq_printf(m, ":unlimited\n");
+ seq_puts(m, ":unlimited\n");
else
seq_printf(m, ":count=%ld\n", data->count);
diff --git a/kernel/trace/trace_events_filter.c b/kernel/trace/trace_events_filter.c
index 7a8c152..ced69da 100644
--- a/kernel/trace/trace_events_filter.c
+++ b/kernel/trace/trace_events_filter.c
@@ -45,6 +45,7 @@ enum filter_op_ids
OP_GT,
OP_GE,
OP_BAND,
+ OP_NOT,
OP_NONE,
OP_OPEN_PAREN,
};
@@ -67,6 +68,7 @@ static struct filter_op filter_ops[] = {
{ OP_GT, ">", 5 },
{ OP_GE, ">=", 5 },
{ OP_BAND, "&", 6 },
+ { OP_NOT, "!", 6 },
{ OP_NONE, "OP_NONE", 0 },
{ OP_OPEN_PAREN, "(", 0 },
};
@@ -85,6 +87,7 @@ enum {
FILT_ERR_MISSING_FIELD,
FILT_ERR_INVALID_FILTER,
FILT_ERR_IP_FIELD_ONLY,
+ FILT_ERR_ILLEGAL_NOT_OP,
};
static char *err_text[] = {
@@ -101,6 +104,7 @@ static char *err_text[] = {
"Missing field name and/or value",
"Meaningless filter expression",
"Only 'ip' field is supported for function trace",
+ "Illegal use of '!'",
};
struct opstack_op {
@@ -139,6 +143,7 @@ struct pred_stack {
int index;
};
+/* If not of not match is equal to not of not, then it is a match */
#define DEFINE_COMPARISON_PRED(type) \
static int filter_pred_##type(struct filter_pred *pred, void *event) \
{ \
@@ -166,7 +171,7 @@ static int filter_pred_##type(struct filter_pred *pred, void *event) \
break; \
} \
\
- return match; \
+ return !!match == !pred->not; \
}
#define DEFINE_EQUALITY_PRED(size) \
@@ -484,9 +489,10 @@ static int process_ops(struct filter_pred *preds,
if (!WARN_ON_ONCE(!pred->fn))
match = pred->fn(pred, rec);
if (!!match == type)
- return match;
+ break;
}
- return match;
+ /* If not of not match is equal to not of not, then it is a match */
+ return !!match == !op->not;
}
struct filter_match_preds_data {
@@ -735,10 +741,10 @@ static int filter_set_pred(struct event_filter *filter,
* then this op can be folded.
*/
if (left->index & FILTER_PRED_FOLD &&
- (left->op == dest->op ||
+ ((left->op == dest->op && !left->not) ||
left->left == FILTER_PRED_INVALID) &&
right->index & FILTER_PRED_FOLD &&
- (right->op == dest->op ||
+ ((right->op == dest->op && !right->not) ||
right->left == FILTER_PRED_INVALID))
dest->index |= FILTER_PRED_FOLD;
@@ -1028,7 +1034,7 @@ static int init_pred(struct filter_parse_state *ps,
}
if (pred->op == OP_NE)
- pred->not = 1;
+ pred->not ^= 1;
pred->fn = fn;
return 0;
@@ -1590,6 +1596,17 @@ static int replace_preds(struct ftrace_event_call *call,
continue;
}
+ if (elt->op == OP_NOT) {
+ if (!n_preds || operand1 || operand2) {
+ parse_error(ps, FILT_ERR_ILLEGAL_NOT_OP, 0);
+ err = -EINVAL;
+ goto fail;
+ }
+ if (!dry_run)
+ filter->preds[n_preds - 1].not ^= 1;
+ continue;
+ }
+
if (WARN_ON(n_preds++ == MAX_FILTER_PRED)) {
parse_error(ps, FILT_ERR_TOO_MANY_PREDS, 0);
err = -ENOSPC;
diff --git a/kernel/trace/trace_events_trigger.c b/kernel/trace/trace_events_trigger.c
index 4747b47..8712df9 100644
--- a/kernel/trace/trace_events_trigger.c
+++ b/kernel/trace/trace_events_trigger.c
@@ -373,7 +373,7 @@ event_trigger_print(const char *name, struct seq_file *m,
{
long count = (long)data;
- seq_printf(m, "%s", name);
+ seq_puts(m, name);
if (count == -1)
seq_puts(m, ":unlimited");
@@ -383,7 +383,7 @@ event_trigger_print(const char *name, struct seq_file *m,
if (filter_str)
seq_printf(m, " if %s\n", filter_str);
else
- seq_puts(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
@@ -1105,7 +1105,7 @@ event_enable_trigger_print(struct seq_file *m, struct event_trigger_ops *ops,
if (data->filter_str)
seq_printf(m, " if %s\n", data->filter_str);
else
- seq_puts(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index 57f0ec9..fcd41a1 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -261,37 +261,74 @@ static struct tracer function_trace __tracer_data =
};
#ifdef CONFIG_DYNAMIC_FTRACE
-static int update_count(void **data)
+static void update_traceon_count(void **data, bool on)
{
- unsigned long *count = (long *)data;
+ long *count = (long *)data;
+ long old_count = *count;
- if (!*count)
- return 0;
+ /*
+ * Tracing gets disabled (or enabled) once per count.
+ * This function can be called at the same time on multiple CPUs.
+ * It is fine if both disable (or enable) tracing, as disabling
+ * (or enabling) the second time doesn't do anything as the
+ * state of the tracer is already disabled (or enabled).
+ * What needs to be synchronized in this case is that the count
+ * only gets decremented once, even if the tracer is disabled
+ * (or enabled) twice, as the second one is really a nop.
+ *
+ * The memory barriers guarantee that we only decrement the
+ * counter once. First the count is read to a local variable
+ * and a read barrier is used to make sure that it is loaded
+ * before checking if the tracer is in the state we want.
+ * If the tracer is not in the state we want, then the count
+ * is guaranteed to be the old count.
+ *
+ * Next the tracer is set to the state we want (disabled or enabled)
+ * then a write memory barrier is used to make sure that
+ * the new state is visible before changing the counter by
+ * one minus the old counter. This guarantees that another CPU
+ * executing this code will see the new state before seeing
+ * the new counter value, and would not do anything if the new
+ * counter is seen.
+ *
+ * Note, there is no synchronization between this and a user
+ * setting the tracing_on file. But we currently don't care
+ * about that.
+ */
+ if (!old_count)
+ return;
- if (*count != -1)
- (*count)--;
+ /* Make sure we see count before checking tracing state */
+ smp_rmb();
- return 1;
+ if (on == !!tracing_is_on())
+ return;
+
+ if (on)
+ tracing_on();
+ else
+ tracing_off();
+
+ /* unlimited? */
+ if (old_count == -1)
+ return;
+
+ /* Make sure tracing state is visible before updating count */
+ smp_wmb();
+
+ *count = old_count - 1;
}
static void
ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, void **data)
{
- if (tracing_is_on())
- return;
-
- if (update_count(data))
- tracing_on();
+ update_traceon_count(data, 1);
}
static void
ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, void **data)
{
- if (!tracing_is_on())
- return;
-
- if (update_count(data))
- tracing_off();
+ update_traceon_count(data, 0);
}
static void
@@ -330,11 +367,49 @@ ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data)
static void
ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data)
{
- if (!tracing_is_on())
- return;
+ long *count = (long *)data;
+ long old_count;
+ long new_count;
- if (update_count(data))
- trace_dump_stack(STACK_SKIP);
+ /*
+ * Stack traces should only execute the number of times the
+ * user specified in the counter.
+ */
+ do {
+
+ if (!tracing_is_on())
+ return;
+
+ old_count = *count;
+
+ if (!old_count)
+ return;
+
+ /* unlimited? */
+ if (old_count == -1) {
+ trace_dump_stack(STACK_SKIP);
+ return;
+ }
+
+ new_count = old_count - 1;
+ new_count = cmpxchg(count, old_count, new_count);
+ if (new_count == old_count)
+ trace_dump_stack(STACK_SKIP);
+
+ } while (new_count != old_count);
+}
+
+static int update_count(void **data)
+{
+ unsigned long *count = (long *)data;
+
+ if (!*count)
+ return 0;
+
+ if (*count != -1)
+ (*count)--;
+
+ return 1;
}
static void
@@ -361,7 +436,7 @@ ftrace_probe_print(const char *name, struct seq_file *m,
seq_printf(m, "%ps:%s", (void *)ip, name);
if (count == -1)
- seq_printf(m, ":unlimited\n");
+ seq_puts(m, ":unlimited\n");
else
seq_printf(m, ":count=%ld\n", count);
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index f0a0c98..ba47600 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -107,7 +107,7 @@ enum {
FLAGS_FILL_END = 3 << TRACE_GRAPH_PRINT_FILL_SHIFT,
};
-static enum print_line_t
+static void
print_graph_duration(unsigned long long duration, struct trace_seq *s,
u32 flags);
@@ -483,33 +483,24 @@ static int graph_trace_update_thresh(struct trace_array *tr)
static int max_bytes_for_cpu;
-static enum print_line_t
-print_graph_cpu(struct trace_seq *s, int cpu)
+static void print_graph_cpu(struct trace_seq *s, int cpu)
{
- int ret;
-
/*
* Start with a space character - to make it stand out
* to the right a bit when trace output is pasted into
* email:
*/
- ret = trace_seq_printf(s, " %*d) ", max_bytes_for_cpu, cpu);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_printf(s, " %*d) ", max_bytes_for_cpu, cpu);
}
#define TRACE_GRAPH_PROCINFO_LENGTH 14
-static enum print_line_t
-print_graph_proc(struct trace_seq *s, pid_t pid)
+static void print_graph_proc(struct trace_seq *s, pid_t pid)
{
char comm[TASK_COMM_LEN];
/* sign + log10(MAX_INT) + '\0' */
char pid_str[11];
int spaces = 0;
- int ret;
int len;
int i;
@@ -524,56 +515,43 @@ print_graph_proc(struct trace_seq *s, pid_t pid)
spaces = TRACE_GRAPH_PROCINFO_LENGTH - len;
/* First spaces to align center */
- for (i = 0; i < spaces / 2; i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ for (i = 0; i < spaces / 2; i++)
+ trace_seq_putc(s, ' ');
- ret = trace_seq_printf(s, "%s-%s", comm, pid_str);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%s-%s", comm, pid_str);
/* Last spaces to align center */
- for (i = 0; i < spaces - (spaces / 2); i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
- return TRACE_TYPE_HANDLED;
+ for (i = 0; i < spaces - (spaces / 2); i++)
+ trace_seq_putc(s, ' ');
}
-static enum print_line_t
-print_graph_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
+static void print_graph_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
{
- if (!trace_seq_putc(s, ' '))
- return 0;
-
- return trace_print_lat_fmt(s, entry);
+ trace_seq_putc(s, ' ');
+ trace_print_lat_fmt(s, entry);
}
/* If the pid changed since the last trace, output this event */
-static enum print_line_t
+static void
verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
{
pid_t prev_pid;
pid_t *last_pid;
- int ret;
if (!data)
- return TRACE_TYPE_HANDLED;
+ return;
last_pid = &(per_cpu_ptr(data->cpu_data, cpu)->last_pid);
if (*last_pid == pid)
- return TRACE_TYPE_HANDLED;
+ return;
prev_pid = *last_pid;
*last_pid = pid;
if (prev_pid == -1)
- return TRACE_TYPE_HANDLED;
+ return;
/*
* Context-switch trace line:
@@ -582,33 +560,12 @@ verif_pid(struct trace_seq *s, pid_t pid, int cpu, struct fgraph_data *data)
------------------------------------------
*/
- ret = trace_seq_puts(s,
- " ------------------------------------------\n");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = print_graph_cpu(s, cpu);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = print_graph_proc(s, prev_pid);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = trace_seq_puts(s, " => ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = print_graph_proc(s, pid);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = trace_seq_puts(s,
- "\n ------------------------------------------\n\n");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_puts(s, " ------------------------------------------\n");
+ print_graph_cpu(s, cpu);
+ print_graph_proc(s, prev_pid);
+ trace_seq_puts(s, " => ");
+ print_graph_proc(s, pid);
+ trace_seq_puts(s, "\n ------------------------------------------\n\n");
}
static struct ftrace_graph_ret_entry *
@@ -682,175 +639,122 @@ get_return_for_leaf(struct trace_iterator *iter,
return next;
}
-static int print_graph_abs_time(u64 t, struct trace_seq *s)
+static void print_graph_abs_time(u64 t, struct trace_seq *s)
{
unsigned long usecs_rem;
usecs_rem = do_div(t, NSEC_PER_SEC);
usecs_rem /= 1000;
- return trace_seq_printf(s, "%5lu.%06lu | ",
- (unsigned long)t, usecs_rem);
+ trace_seq_printf(s, "%5lu.%06lu | ",
+ (unsigned long)t, usecs_rem);
}
-static enum print_line_t
+static void
print_graph_irq(struct trace_iterator *iter, unsigned long addr,
enum trace_type type, int cpu, pid_t pid, u32 flags)
{
- int ret;
struct trace_seq *s = &iter->seq;
+ struct trace_entry *ent = iter->ent;
if (addr < (unsigned long)__irqentry_text_start ||
addr >= (unsigned long)__irqentry_text_end)
- return TRACE_TYPE_UNHANDLED;
+ return;
if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
/* Absolute time */
- if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
- ret = print_graph_abs_time(iter->ts, s);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
+ print_graph_abs_time(iter->ts, s);
/* Cpu */
- if (flags & TRACE_GRAPH_PRINT_CPU) {
- ret = print_graph_cpu(s, cpu);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (flags & TRACE_GRAPH_PRINT_CPU)
+ print_graph_cpu(s, cpu);
/* Proc */
if (flags & TRACE_GRAPH_PRINT_PROC) {
- ret = print_graph_proc(s, pid);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
- ret = trace_seq_puts(s, " | ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_proc(s, pid);
+ trace_seq_puts(s, " | ");
}
+
+ /* Latency format */
+ if (trace_flags & TRACE_ITER_LATENCY_FMT)
+ print_graph_lat_fmt(s, ent);
}
/* No overhead */
- ret = print_graph_duration(0, s, flags | FLAGS_FILL_START);
- if (ret != TRACE_TYPE_HANDLED)
- return ret;
+ print_graph_duration(0, s, flags | FLAGS_FILL_START);
if (type == TRACE_GRAPH_ENT)
- ret = trace_seq_puts(s, "==========>");
+ trace_seq_puts(s, "==========>");
else
- ret = trace_seq_puts(s, "<==========");
-
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = print_graph_duration(0, s, flags | FLAGS_FILL_END);
- if (ret != TRACE_TYPE_HANDLED)
- return ret;
-
- ret = trace_seq_putc(s, '\n');
+ trace_seq_puts(s, "<==========");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- return TRACE_TYPE_HANDLED;
+ print_graph_duration(0, s, flags | FLAGS_FILL_END);
+ trace_seq_putc(s, '\n');
}
-enum print_line_t
+void
trace_print_graph_duration(unsigned long long duration, struct trace_seq *s)
{
unsigned long nsecs_rem = do_div(duration, 1000);
/* log10(ULONG_MAX) + '\0' */
- char msecs_str[21];
+ char usecs_str[21];
char nsecs_str[5];
- int ret, len;
+ int len;
int i;
- sprintf(msecs_str, "%lu", (unsigned long) duration);
+ sprintf(usecs_str, "%lu", (unsigned long) duration);
/* Print msecs */
- ret = trace_seq_printf(s, "%s", msecs_str);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%s", usecs_str);
- len = strlen(msecs_str);
+ len = strlen(usecs_str);
/* Print nsecs (we don't want to exceed 7 numbers) */
if (len < 7) {
size_t slen = min_t(size_t, sizeof(nsecs_str), 8UL - len);
snprintf(nsecs_str, slen, "%03lu", nsecs_rem);
- ret = trace_seq_printf(s, ".%s", nsecs_str);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, ".%s", nsecs_str);
len += strlen(nsecs_str);
}
- ret = trace_seq_puts(s, " us ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, " us ");
/* Print remaining spaces to fit the row's width */
- for (i = len; i < 7; i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
- return TRACE_TYPE_HANDLED;
+ for (i = len; i < 7; i++)
+ trace_seq_putc(s, ' ');
}
-static enum print_line_t
+static void
print_graph_duration(unsigned long long duration, struct trace_seq *s,
u32 flags)
{
- int ret = -1;
-
if (!(flags & TRACE_GRAPH_PRINT_DURATION) ||
!(trace_flags & TRACE_ITER_CONTEXT_INFO))
- return TRACE_TYPE_HANDLED;
+ return;
/* No real adata, just filling the column with spaces */
switch (flags & TRACE_GRAPH_PRINT_FILL_MASK) {
case FLAGS_FILL_FULL:
- ret = trace_seq_puts(s, " | ");
- return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, " | ");
+ return;
case FLAGS_FILL_START:
- ret = trace_seq_puts(s, " ");
- return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, " ");
+ return;
case FLAGS_FILL_END:
- ret = trace_seq_puts(s, " |");
- return ret ? TRACE_TYPE_HANDLED : TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, " |");
+ return;
}
/* Signal a overhead of time execution to the output */
- if (flags & TRACE_GRAPH_PRINT_OVERHEAD) {
- /* Duration exceeded 100 msecs */
- if (duration > 100000ULL)
- ret = trace_seq_puts(s, "! ");
- /* Duration exceeded 10 msecs */
- else if (duration > 10000ULL)
- ret = trace_seq_puts(s, "+ ");
- }
-
- /*
- * The -1 means we either did not exceed the duration tresholds
- * or we dont want to print out the overhead. Either way we need
- * to fill out the space.
- */
- if (ret == -1)
- ret = trace_seq_puts(s, " ");
-
- /* Catching here any failure happenned above */
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = trace_print_graph_duration(duration, s);
- if (ret != TRACE_TYPE_HANDLED)
- return ret;
-
- ret = trace_seq_puts(s, "| ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ if (flags & TRACE_GRAPH_PRINT_OVERHEAD)
+ trace_seq_printf(s, "%c ", trace_find_mark(duration));
+ else
+ trace_seq_puts(s, " ");
- return TRACE_TYPE_HANDLED;
+ trace_print_graph_duration(duration, s);
+ trace_seq_puts(s, "| ");
}
/* Case of a leaf function on its call entry */
@@ -864,7 +768,6 @@ print_graph_entry_leaf(struct trace_iterator *iter,
struct ftrace_graph_ret *graph_ret;
struct ftrace_graph_ent *call;
unsigned long long duration;
- int ret;
int i;
graph_ret = &ret_entry->ret;
@@ -890,22 +793,15 @@ print_graph_entry_leaf(struct trace_iterator *iter,
}
/* Overhead and duration */
- ret = print_graph_duration(duration, s, flags);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_duration(duration, s, flags);
/* Function */
- for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)
+ trace_seq_putc(s, ' ');
- ret = trace_seq_printf(s, "%ps();\n", (void *)call->func);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%ps();\n", (void *)call->func);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t
@@ -915,7 +811,6 @@ print_graph_entry_nested(struct trace_iterator *iter,
{
struct ftrace_graph_ent *call = &entry->graph_ent;
struct fgraph_data *data = iter->private;
- int ret;
int i;
if (data) {
@@ -931,19 +826,15 @@ print_graph_entry_nested(struct trace_iterator *iter,
}
/* No time */
- ret = print_graph_duration(0, s, flags | FLAGS_FILL_FULL);
- if (ret != TRACE_TYPE_HANDLED)
- return ret;
+ print_graph_duration(0, s, flags | FLAGS_FILL_FULL);
/* Function */
- for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ for (i = 0; i < call->depth * TRACE_GRAPH_INDENT; i++)
+ trace_seq_putc(s, ' ');
+
+ trace_seq_printf(s, "%ps() {\n", (void *)call->func);
- ret = trace_seq_printf(s, "%ps() {\n", (void *)call->func);
- if (!ret)
+ if (trace_seq_has_overflowed(s))
return TRACE_TYPE_PARTIAL_LINE;
/*
@@ -953,62 +844,43 @@ print_graph_entry_nested(struct trace_iterator *iter,
return TRACE_TYPE_NO_CONSUME;
}
-static enum print_line_t
+static void
print_graph_prologue(struct trace_iterator *iter, struct trace_seq *s,
int type, unsigned long addr, u32 flags)
{
struct fgraph_data *data = iter->private;
struct trace_entry *ent = iter->ent;
int cpu = iter->cpu;
- int ret;
/* Pid */
- if (verif_pid(s, ent->pid, cpu, data) == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
+ verif_pid(s, ent->pid, cpu, data);
- if (type) {
+ if (type)
/* Interrupt */
- ret = print_graph_irq(iter, addr, type, cpu, ent->pid, flags);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ print_graph_irq(iter, addr, type, cpu, ent->pid, flags);
if (!(trace_flags & TRACE_ITER_CONTEXT_INFO))
- return 0;
+ return;
/* Absolute time */
- if (flags & TRACE_GRAPH_PRINT_ABS_TIME) {
- ret = print_graph_abs_time(iter->ts, s);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
+ print_graph_abs_time(iter->ts, s);
/* Cpu */
- if (flags & TRACE_GRAPH_PRINT_CPU) {
- ret = print_graph_cpu(s, cpu);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (flags & TRACE_GRAPH_PRINT_CPU)
+ print_graph_cpu(s, cpu);
/* Proc */
if (flags & TRACE_GRAPH_PRINT_PROC) {
- ret = print_graph_proc(s, ent->pid);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = trace_seq_puts(s, " | ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_proc(s, ent->pid);
+ trace_seq_puts(s, " | ");
}
/* Latency format */
- if (trace_flags & TRACE_ITER_LATENCY_FMT) {
- ret = print_graph_lat_fmt(s, ent);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (trace_flags & TRACE_ITER_LATENCY_FMT)
+ print_graph_lat_fmt(s, ent);
- return 0;
+ return;
}
/*
@@ -1126,8 +998,7 @@ print_graph_entry(struct ftrace_graph_ent_entry *field, struct trace_seq *s,
if (check_irq_entry(iter, flags, call->func, call->depth))
return TRACE_TYPE_HANDLED;
- if (print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags))
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_prologue(iter, s, TRACE_GRAPH_ENT, call->func, flags);
leaf_ret = get_return_for_leaf(iter, field);
if (leaf_ret)
@@ -1160,7 +1031,6 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
pid_t pid = ent->pid;
int cpu = iter->cpu;
int func_match = 1;
- int ret;
int i;
if (check_irq_return(iter, flags, trace->depth))
@@ -1186,20 +1056,14 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
}
}
- if (print_graph_prologue(iter, s, 0, 0, flags))
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_prologue(iter, s, 0, 0, flags);
/* Overhead and duration */
- ret = print_graph_duration(duration, s, flags);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_duration(duration, s, flags);
/* Closing brace */
- for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ for (i = 0; i < trace->depth * TRACE_GRAPH_INDENT; i++)
+ trace_seq_putc(s, ' ');
/*
* If the return function does not have a matching entry,
@@ -1208,30 +1072,20 @@ print_graph_return(struct ftrace_graph_ret *trace, struct trace_seq *s,
* belongs to, write out the function name. Always do
* that if the funcgraph-tail option is enabled.
*/
- if (func_match && !(flags & TRACE_GRAPH_PRINT_TAIL)) {
- ret = trace_seq_puts(s, "}\n");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- } else {
- ret = trace_seq_printf(s, "} /* %ps */\n", (void *)trace->func);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (func_match && !(flags & TRACE_GRAPH_PRINT_TAIL))
+ trace_seq_puts(s, "}\n");
+ else
+ trace_seq_printf(s, "} /* %ps */\n", (void *)trace->func);
/* Overrun */
- if (flags & TRACE_GRAPH_PRINT_OVERRUN) {
- ret = trace_seq_printf(s, " (Overruns: %lu)\n",
- trace->overrun);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (flags & TRACE_GRAPH_PRINT_OVERRUN)
+ trace_seq_printf(s, " (Overruns: %lu)\n",
+ trace->overrun);
- ret = print_graph_irq(iter, trace->func, TRACE_GRAPH_RET,
- cpu, pid, flags);
- if (ret == TRACE_TYPE_PARTIAL_LINE)
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_irq(iter, trace->func, TRACE_GRAPH_RET,
+ cpu, pid, flags);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t
@@ -1248,26 +1102,18 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
if (data)
depth = per_cpu_ptr(data->cpu_data, iter->cpu)->depth;
- if (print_graph_prologue(iter, s, 0, 0, flags))
- return TRACE_TYPE_PARTIAL_LINE;
+ print_graph_prologue(iter, s, 0, 0, flags);
/* No time */
- ret = print_graph_duration(0, s, flags | FLAGS_FILL_FULL);
- if (ret != TRACE_TYPE_HANDLED)
- return ret;
+ print_graph_duration(0, s, flags | FLAGS_FILL_FULL);
/* Indentation */
if (depth > 0)
- for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++) {
- ret = trace_seq_putc(s, ' ');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ for (i = 0; i < (depth + 1) * TRACE_GRAPH_INDENT; i++)
+ trace_seq_putc(s, ' ');
/* The comment */
- ret = trace_seq_puts(s, "/* ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, "/* ");
switch (iter->ent->type) {
case TRACE_BPRINT:
@@ -1290,17 +1136,18 @@ print_graph_comment(struct trace_seq *s, struct trace_entry *ent,
return ret;
}
+ if (trace_seq_has_overflowed(s))
+ goto out;
+
/* Strip ending newline */
- if (s->buffer[s->len - 1] == '\n') {
- s->buffer[s->len - 1] = '\0';
- s->len--;
+ if (s->buffer[s->seq.len - 1] == '\n') {
+ s->buffer[s->seq.len - 1] = '\0';
+ s->seq.len--;
}
- ret = trace_seq_puts(s, " */\n");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_puts(s, " */\n");
+ out:
+ return trace_handle_return(s);
}
@@ -1407,32 +1254,32 @@ static void __print_graph_headers_flags(struct seq_file *s, u32 flags)
print_lat_header(s, flags);
/* 1st line */
- seq_printf(s, "#");
+ seq_putc(s, '#');
if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
- seq_printf(s, " TIME ");
+ seq_puts(s, " TIME ");
if (flags & TRACE_GRAPH_PRINT_CPU)
- seq_printf(s, " CPU");
+ seq_puts(s, " CPU");
if (flags & TRACE_GRAPH_PRINT_PROC)
- seq_printf(s, " TASK/PID ");
+ seq_puts(s, " TASK/PID ");
if (lat)
- seq_printf(s, "||||");
+ seq_puts(s, "||||");
if (flags & TRACE_GRAPH_PRINT_DURATION)
- seq_printf(s, " DURATION ");
- seq_printf(s, " FUNCTION CALLS\n");
+ seq_puts(s, " DURATION ");
+ seq_puts(s, " FUNCTION CALLS\n");
/* 2nd line */
- seq_printf(s, "#");
+ seq_putc(s, '#');
if (flags & TRACE_GRAPH_PRINT_ABS_TIME)
- seq_printf(s, " | ");
+ seq_puts(s, " | ");
if (flags & TRACE_GRAPH_PRINT_CPU)
- seq_printf(s, " | ");
+ seq_puts(s, " | ");
if (flags & TRACE_GRAPH_PRINT_PROC)
- seq_printf(s, " | | ");
+ seq_puts(s, " | | ");
if (lat)
- seq_printf(s, "||||");
+ seq_puts(s, "||||");
if (flags & TRACE_GRAPH_PRINT_DURATION)
- seq_printf(s, " | | ");
- seq_printf(s, " | | | |\n");
+ seq_puts(s, " | | ");
+ seq_puts(s, " | | | |\n");
}
static void print_graph_headers(struct seq_file *s)
diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c
index bd90e1b..b0b1c44 100644
--- a/kernel/trace/trace_kdb.c
+++ b/kernel/trace/trace_kdb.c
@@ -20,10 +20,12 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
{
/* use static because iter can be a bit big for the stack */
static struct trace_iterator iter;
+ static struct ring_buffer_iter *buffer_iter[CONFIG_NR_CPUS];
unsigned int old_userobj;
int cnt = 0, cpu;
trace_init_global_iter(&iter);
+ iter.buffer_iter = buffer_iter;
for_each_tracing_cpu(cpu) {
atomic_inc(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
@@ -57,19 +59,19 @@ static void ftrace_dump_buf(int skip_lines, long cpu_file)
ring_buffer_read_start(iter.buffer_iter[cpu_file]);
tracing_iter_reset(&iter, cpu_file);
}
- if (!trace_empty(&iter))
- trace_find_next_entry_inc(&iter);
- while (!trace_empty(&iter)) {
+
+ while (trace_find_next_entry_inc(&iter)) {
if (!cnt)
kdb_printf("---------------------------------\n");
cnt++;
- if (trace_find_next_entry_inc(&iter) != NULL && !skip_lines)
+ if (!skip_lines) {
print_trace_line(&iter);
- if (!skip_lines)
trace_printk_seq(&iter.seq);
- else
+ } else {
skip_lines--;
+ }
+
if (KDB_FLAG(CMD_INTERRUPT))
goto out;
}
@@ -86,9 +88,12 @@ out:
atomic_dec(&per_cpu_ptr(iter.trace_buffer->data, cpu)->disabled);
}
- for_each_tracing_cpu(cpu)
- if (iter.buffer_iter[cpu])
+ for_each_tracing_cpu(cpu) {
+ if (iter.buffer_iter[cpu]) {
ring_buffer_read_finish(iter.buffer_iter[cpu]);
+ iter.buffer_iter[cpu] = NULL;
+ }
+ }
}
/*
diff --git a/kernel/trace/trace_kprobe.c b/kernel/trace/trace_kprobe.c
index 282f6e4..5edb518 100644
--- a/kernel/trace/trace_kprobe.c
+++ b/kernel/trace/trace_kprobe.c
@@ -826,7 +826,7 @@ static int probes_seq_show(struct seq_file *m, void *v)
struct trace_kprobe *tk = v;
int i;
- seq_printf(m, "%c", trace_kprobe_is_return(tk) ? 'r' : 'p');
+ seq_putc(m, trace_kprobe_is_return(tk) ? 'r' : 'p');
seq_printf(m, ":%s/%s", tk->tp.call.class->system,
ftrace_event_name(&tk->tp.call));
@@ -840,7 +840,7 @@ static int probes_seq_show(struct seq_file *m, void *v)
for (i = 0; i < tk->tp.nr_args; i++)
seq_printf(m, " %s=%s", tk->tp.args[i].name, tk->tp.args[i].comm);
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
@@ -1024,27 +1024,22 @@ print_kprobe_event(struct trace_iterator *iter, int flags,
field = (struct kprobe_trace_entry_head *)iter->ent;
tp = container_of(event, struct trace_probe, call.event);
- if (!trace_seq_printf(s, "%s: (", ftrace_event_name(&tp->call)))
- goto partial;
+ trace_seq_printf(s, "%s: (", ftrace_event_name(&tp->call));
if (!seq_print_ip_sym(s, field->ip, flags | TRACE_ITER_SYM_OFFSET))
- goto partial;
+ goto out;
- if (!trace_seq_puts(s, ")"))
- goto partial;
+ trace_seq_putc(s, ')');
data = (u8 *)&field[1];
for (i = 0; i < tp->nr_args; i++)
if (!tp->args[i].type->print(s, tp->args[i].name,
data + tp->args[i].offset, field))
- goto partial;
-
- if (!trace_seq_puts(s, "\n"))
- goto partial;
+ goto out;
- return TRACE_TYPE_HANDLED;
-partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_putc(s, '\n');
+ out:
+ return trace_handle_return(s);
}
static enum print_line_t
@@ -1060,33 +1055,28 @@ print_kretprobe_event(struct trace_iterator *iter, int flags,
field = (struct kretprobe_trace_entry_head *)iter->ent;
tp = container_of(event, struct trace_probe, call.event);
- if (!trace_seq_printf(s, "%s: (", ftrace_event_name(&tp->call)))
- goto partial;
+ trace_seq_printf(s, "%s: (", ftrace_event_name(&tp->call));
if (!seq_print_ip_sym(s, field->ret_ip, flags | TRACE_ITER_SYM_OFFSET))
- goto partial;
+ goto out;
- if (!trace_seq_puts(s, " <- "))
- goto partial;
+ trace_seq_puts(s, " <- ");
if (!seq_print_ip_sym(s, field->func, flags & ~TRACE_ITER_SYM_OFFSET))
- goto partial;
+ goto out;
- if (!trace_seq_puts(s, ")"))
- goto partial;
+ trace_seq_putc(s, ')');
data = (u8 *)&field[1];
for (i = 0; i < tp->nr_args; i++)
if (!tp->args[i].type->print(s, tp->args[i].name,
data + tp->args[i].offset, field))
- goto partial;
+ goto out;
- if (!trace_seq_puts(s, "\n"))
- goto partial;
+ trace_seq_putc(s, '\n');
- return TRACE_TYPE_HANDLED;
-partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ out:
+ return trace_handle_return(s);
}
diff --git a/kernel/trace/trace_mmiotrace.c b/kernel/trace/trace_mmiotrace.c
index 0abd9b8..7a9ba62 100644
--- a/kernel/trace/trace_mmiotrace.c
+++ b/kernel/trace/trace_mmiotrace.c
@@ -59,17 +59,15 @@ static void mmio_trace_start(struct trace_array *tr)
mmio_reset_data(tr);
}
-static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
+static void mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
{
- int ret = 0;
int i;
resource_size_t start, end;
const struct pci_driver *drv = pci_dev_driver(dev);
- /* XXX: incomplete checks for trace_seq_printf() return value */
- ret += trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x",
- dev->bus->number, dev->devfn,
- dev->vendor, dev->device, dev->irq);
+ trace_seq_printf(s, "PCIDEV %02x%02x %04x%04x %x",
+ dev->bus->number, dev->devfn,
+ dev->vendor, dev->device, dev->irq);
/*
* XXX: is pci_resource_to_user() appropriate, since we are
* supposed to interpret the __ioremap() phys_addr argument based on
@@ -77,21 +75,20 @@ static int mmio_print_pcidev(struct trace_seq *s, const struct pci_dev *dev)
*/
for (i = 0; i < 7; i++) {
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
- ret += trace_seq_printf(s, " %llx",
+ trace_seq_printf(s, " %llx",
(unsigned long long)(start |
(dev->resource[i].flags & PCI_REGION_FLAG_MASK)));
}
for (i = 0; i < 7; i++) {
pci_resource_to_user(dev, i, &dev->resource[i], &start, &end);
- ret += trace_seq_printf(s, " %llx",
+ trace_seq_printf(s, " %llx",
dev->resource[i].start < dev->resource[i].end ?
(unsigned long long)(end - start) + 1 : 0);
}
if (drv)
- ret += trace_seq_printf(s, " %s\n", drv->name);
+ trace_seq_printf(s, " %s\n", drv->name);
else
- ret += trace_seq_puts(s, " \n");
- return ret;
+ trace_seq_puts(s, " \n");
}
static void destroy_header_iter(struct header_iter *hiter)
@@ -179,28 +176,27 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
unsigned long long t = ns2usecs(iter->ts);
unsigned long usec_rem = do_div(t, USEC_PER_SEC);
unsigned secs = (unsigned long)t;
- int ret = 1;
trace_assign_type(field, entry);
rw = &field->rw;
switch (rw->opcode) {
case MMIO_READ:
- ret = trace_seq_printf(s,
+ trace_seq_printf(s,
"R %d %u.%06lu %d 0x%llx 0x%lx 0x%lx %d\n",
rw->width, secs, usec_rem, rw->map_id,
(unsigned long long)rw->phys,
rw->value, rw->pc, 0);
break;
case MMIO_WRITE:
- ret = trace_seq_printf(s,
+ trace_seq_printf(s,
"W %d %u.%06lu %d 0x%llx 0x%lx 0x%lx %d\n",
rw->width, secs, usec_rem, rw->map_id,
(unsigned long long)rw->phys,
rw->value, rw->pc, 0);
break;
case MMIO_UNKNOWN_OP:
- ret = trace_seq_printf(s,
+ trace_seq_printf(s,
"UNKNOWN %u.%06lu %d 0x%llx %02lx,%02lx,"
"%02lx 0x%lx %d\n",
secs, usec_rem, rw->map_id,
@@ -209,12 +205,11 @@ static enum print_line_t mmio_print_rw(struct trace_iterator *iter)
(rw->value >> 0) & 0xff, rw->pc, 0);
break;
default:
- ret = trace_seq_puts(s, "rw what?\n");
+ trace_seq_puts(s, "rw what?\n");
break;
}
- if (ret)
- return TRACE_TYPE_HANDLED;
- return TRACE_TYPE_PARTIAL_LINE;
+
+ return trace_handle_return(s);
}
static enum print_line_t mmio_print_map(struct trace_iterator *iter)
@@ -226,31 +221,29 @@ static enum print_line_t mmio_print_map(struct trace_iterator *iter)
unsigned long long t = ns2usecs(iter->ts);
unsigned long usec_rem = do_div(t, USEC_PER_SEC);
unsigned secs = (unsigned long)t;
- int ret;
trace_assign_type(field, entry);
m = &field->map;
switch (m->opcode) {
case MMIO_PROBE:
- ret = trace_seq_printf(s,
+ trace_seq_printf(s,
"MAP %u.%06lu %d 0x%llx 0x%lx 0x%lx 0x%lx %d\n",
secs, usec_rem, m->map_id,
(unsigned long long)m->phys, m->virt, m->len,
0UL, 0);
break;
case MMIO_UNPROBE:
- ret = trace_seq_printf(s,
+ trace_seq_printf(s,
"UNMAP %u.%06lu %d 0x%lx %d\n",
secs, usec_rem, m->map_id, 0UL, 0);
break;
default:
- ret = trace_seq_puts(s, "map what?\n");
+ trace_seq_puts(s, "map what?\n");
break;
}
- if (ret)
- return TRACE_TYPE_HANDLED;
- return TRACE_TYPE_PARTIAL_LINE;
+
+ return trace_handle_return(s);
}
static enum print_line_t mmio_print_mark(struct trace_iterator *iter)
@@ -262,14 +255,11 @@ static enum print_line_t mmio_print_mark(struct trace_iterator *iter)
unsigned long long t = ns2usecs(iter->ts);
unsigned long usec_rem = do_div(t, USEC_PER_SEC);
unsigned secs = (unsigned long)t;
- int ret;
/* The trailing newline must be in the message. */
- ret = trace_seq_printf(s, "MARK %u.%06lu %s", secs, usec_rem, msg);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "MARK %u.%06lu %s", secs, usec_rem, msg);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t mmio_print_line(struct trace_iterator *iter)
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index c6977d5..b77b9a6 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -25,15 +25,12 @@ enum print_line_t trace_print_bputs_msg_only(struct trace_iterator *iter)
struct trace_seq *s = &iter->seq;
struct trace_entry *entry = iter->ent;
struct bputs_entry *field;
- int ret;
trace_assign_type(field, entry);
- ret = trace_seq_puts(s, field->str);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, field->str);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
@@ -41,15 +38,12 @@ enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
struct trace_seq *s = &iter->seq;
struct trace_entry *entry = iter->ent;
struct bprint_entry *field;
- int ret;
trace_assign_type(field, entry);
- ret = trace_seq_bprintf(s, field->fmt, field->buf);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_bprintf(s, field->fmt, field->buf);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
@@ -57,15 +51,12 @@ enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
struct trace_seq *s = &iter->seq;
struct trace_entry *entry = iter->ent;
struct print_entry *field;
- int ret;
trace_assign_type(field, entry);
- ret = trace_seq_puts(s, field->buf);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_puts(s, field->buf);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
const char *
@@ -124,7 +115,7 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
if (ret == (const char *)(trace_seq_buffer_ptr(p)))
trace_seq_printf(p, "0x%lx", val);
-
+
trace_seq_putc(p, 0);
return ret;
@@ -193,7 +184,6 @@ int ftrace_raw_output_prep(struct trace_iterator *iter,
struct trace_seq *s = &iter->seq;
struct trace_seq *p = &iter->tmp_seq;
struct trace_entry *entry;
- int ret;
event = container_of(trace_event, struct ftrace_event_call, event);
entry = iter->ent;
@@ -204,11 +194,9 @@ int ftrace_raw_output_prep(struct trace_iterator *iter,
}
trace_seq_init(p);
- ret = trace_seq_printf(s, "%s: ", ftrace_event_name(event));
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%s: ", ftrace_event_name(event));
- return 0;
+ return trace_handle_return(s);
}
EXPORT_SYMBOL(ftrace_raw_output_prep);
@@ -216,18 +204,11 @@ static int ftrace_output_raw(struct trace_iterator *iter, char *name,
char *fmt, va_list ap)
{
struct trace_seq *s = &iter->seq;
- int ret;
-
- ret = trace_seq_printf(s, "%s: ", name);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
- ret = trace_seq_vprintf(s, fmt, ap);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%s: ", name);
+ trace_seq_vprintf(s, fmt, ap);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
int ftrace_output_call(struct trace_iterator *iter, char *name, char *fmt, ...)
@@ -260,7 +241,7 @@ static inline const char *kretprobed(const char *name)
}
#endif /* CONFIG_KRETPROBES */
-static int
+static void
seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
{
#ifdef CONFIG_KALLSYMS
@@ -271,12 +252,11 @@ seq_print_sym_short(struct trace_seq *s, const char *fmt, unsigned long address)
name = kretprobed(str);
- return trace_seq_printf(s, fmt, name);
+ trace_seq_printf(s, fmt, name);
#endif
- return 1;
}
-static int
+static void
seq_print_sym_offset(struct trace_seq *s, const char *fmt,
unsigned long address)
{
@@ -287,9 +267,8 @@ seq_print_sym_offset(struct trace_seq *s, const char *fmt,
sprint_symbol(str, address);
name = kretprobed(str);
- return trace_seq_printf(s, fmt, name);
+ trace_seq_printf(s, fmt, name);
#endif
- return 1;
}
#ifndef CONFIG_64BIT
@@ -320,14 +299,14 @@ int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
if (file) {
ret = trace_seq_path(s, &file->f_path);
if (ret)
- ret = trace_seq_printf(s, "[+0x%lx]",
- ip - vmstart);
+ trace_seq_printf(s, "[+0x%lx]",
+ ip - vmstart);
}
up_read(&mm->mmap_sem);
}
if (ret && ((sym_flags & TRACE_ITER_SYM_ADDR) || !file))
- ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
- return ret;
+ trace_seq_printf(s, " <" IP_FMT ">", ip);
+ return !trace_seq_has_overflowed(s);
}
int
@@ -335,7 +314,6 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
unsigned long sym_flags)
{
struct mm_struct *mm = NULL;
- int ret = 1;
unsigned int i;
if (trace_flags & TRACE_ITER_SYM_USEROBJ) {
@@ -354,48 +332,45 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
unsigned long ip = entry->caller[i];
- if (ip == ULONG_MAX || !ret)
+ if (ip == ULONG_MAX || trace_seq_has_overflowed(s))
break;
- if (ret)
- ret = trace_seq_puts(s, " => ");
+
+ trace_seq_puts(s, " => ");
+
if (!ip) {
- if (ret)
- ret = trace_seq_puts(s, "??");
- if (ret)
- ret = trace_seq_putc(s, '\n');
+ trace_seq_puts(s, "??");
+ trace_seq_putc(s, '\n');
continue;
}
- if (!ret)
- break;
- if (ret)
- ret = seq_print_user_ip(s, mm, ip, sym_flags);
- ret = trace_seq_putc(s, '\n');
+
+ seq_print_user_ip(s, mm, ip, sym_flags);
+ trace_seq_putc(s, '\n');
}
if (mm)
mmput(mm);
- return ret;
+
+ return !trace_seq_has_overflowed(s);
}
int
seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
{
- int ret;
-
- if (!ip)
- return trace_seq_putc(s, '0');
+ if (!ip) {
+ trace_seq_putc(s, '0');
+ goto out;
+ }
if (sym_flags & TRACE_ITER_SYM_OFFSET)
- ret = seq_print_sym_offset(s, "%s", ip);
+ seq_print_sym_offset(s, "%s", ip);
else
- ret = seq_print_sym_short(s, "%s", ip);
-
- if (!ret)
- return 0;
+ seq_print_sym_short(s, "%s", ip);
if (sym_flags & TRACE_ITER_SYM_ADDR)
- ret = trace_seq_printf(s, " <" IP_FMT ">", ip);
- return ret;
+ trace_seq_printf(s, " <" IP_FMT ">", ip);
+
+ out:
+ return !trace_seq_has_overflowed(s);
}
/**
@@ -413,7 +388,6 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
char irqs_off;
int hardirq;
int softirq;
- int ret;
hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
@@ -445,16 +419,15 @@ int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
softirq ? 's' :
'.';
- if (!trace_seq_printf(s, "%c%c%c",
- irqs_off, need_resched, hardsoft_irq))
- return 0;
+ trace_seq_printf(s, "%c%c%c",
+ irqs_off, need_resched, hardsoft_irq);
if (entry->preempt_count)
- ret = trace_seq_printf(s, "%x", entry->preempt_count);
+ trace_seq_printf(s, "%x", entry->preempt_count);
else
- ret = trace_seq_putc(s, '.');
+ trace_seq_putc(s, '.');
- return ret;
+ return !trace_seq_has_overflowed(s);
}
static int
@@ -464,14 +437,38 @@ lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
trace_find_cmdline(entry->pid, comm);
- if (!trace_seq_printf(s, "%8.8s-%-5d %3d",
- comm, entry->pid, cpu))
- return 0;
+ trace_seq_printf(s, "%8.8s-%-5d %3d",
+ comm, entry->pid, cpu);
return trace_print_lat_fmt(s, entry);
}
-static unsigned long preempt_mark_thresh_us = 100;
+#undef MARK
+#define MARK(v, s) {.val = v, .sym = s}
+/* trace overhead mark */
+static const struct trace_mark {
+ unsigned long long val; /* unit: nsec */
+ char sym;
+} mark[] = {
+ MARK(1000000000ULL , '$'), /* 1 sec */
+ MARK(1000000ULL , '#'), /* 1000 usecs */
+ MARK(100000ULL , '!'), /* 100 usecs */
+ MARK(10000ULL , '+'), /* 10 usecs */
+};
+#undef MARK
+
+char trace_find_mark(unsigned long long d)
+{
+ int i;
+ int size = ARRAY_SIZE(mark);
+
+ for (i = 0; i < size; i++) {
+ if (d >= mark[i].val)
+ break;
+ }
+
+ return (i == size) ? ' ' : mark[i].sym;
+}
static int
lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
@@ -493,24 +490,28 @@ lat_print_timestamp(struct trace_iterator *iter, u64 next_ts)
unsigned long rel_usec = do_div(rel_ts, USEC_PER_MSEC);
unsigned long rel_msec = (unsigned long)rel_ts;
- return trace_seq_printf(
- s, "[%08llx] %ld.%03ldms (+%ld.%03ldms): ",
- ns2usecs(iter->ts),
- abs_msec, abs_usec,
- rel_msec, rel_usec);
+ trace_seq_printf(
+ s, "[%08llx] %ld.%03ldms (+%ld.%03ldms): ",
+ ns2usecs(iter->ts),
+ abs_msec, abs_usec,
+ rel_msec, rel_usec);
+
} else if (verbose && !in_ns) {
- return trace_seq_printf(
- s, "[%016llx] %lld (+%lld): ",
- iter->ts, abs_ts, rel_ts);
+ trace_seq_printf(
+ s, "[%016llx] %lld (+%lld): ",
+ iter->ts, abs_ts, rel_ts);
+
} else if (!verbose && in_ns) {
- return trace_seq_printf(
- s, " %4lldus%c: ",
- abs_ts,
- rel_ts > preempt_mark_thresh_us ? '!' :
- rel_ts > 1 ? '+' : ' ');
+ trace_seq_printf(
+ s, " %4lldus%c: ",
+ abs_ts,
+ trace_find_mark(rel_ts * NSEC_PER_USEC));
+
} else { /* !verbose && !in_ns */
- return trace_seq_printf(s, " %4lld: ", abs_ts);
+ trace_seq_printf(s, " %4lld: ", abs_ts);
}
+
+ return !trace_seq_has_overflowed(s);
}
int trace_print_context(struct trace_iterator *iter)
@@ -520,34 +521,29 @@ int trace_print_context(struct trace_iterator *iter)
unsigned long long t;
unsigned long secs, usec_rem;
char comm[TASK_COMM_LEN];
- int ret;
trace_find_cmdline(entry->pid, comm);
- ret = trace_seq_printf(s, "%16s-%-5d [%03d] ",
+ trace_seq_printf(s, "%16s-%-5d [%03d] ",
comm, entry->pid, iter->cpu);
- if (!ret)
- return 0;
- if (trace_flags & TRACE_ITER_IRQ_INFO) {
- ret = trace_print_lat_fmt(s, entry);
- if (!ret)
- return 0;
- }
+ if (trace_flags & TRACE_ITER_IRQ_INFO)
+ trace_print_lat_fmt(s, entry);
if (iter->iter_flags & TRACE_FILE_TIME_IN_NS) {
t = ns2usecs(iter->ts);
usec_rem = do_div(t, USEC_PER_SEC);
secs = (unsigned long)t;
- return trace_seq_printf(s, " %5lu.%06lu: ", secs, usec_rem);
+ trace_seq_printf(s, " %5lu.%06lu: ", secs, usec_rem);
} else
- return trace_seq_printf(s, " %12llu: ", iter->ts);
+ trace_seq_printf(s, " %12llu: ", iter->ts);
+
+ return !trace_seq_has_overflowed(s);
}
int trace_print_lat_context(struct trace_iterator *iter)
{
u64 next_ts;
- int ret;
/* trace_find_next_entry will reset ent_size */
int ent_size = iter->ent_size;
struct trace_seq *s = &iter->seq;
@@ -567,18 +563,17 @@ int trace_print_lat_context(struct trace_iterator *iter)
trace_find_cmdline(entry->pid, comm);
- ret = trace_seq_printf(
- s, "%16s %5d %3d %d %08x %08lx ",
- comm, entry->pid, iter->cpu, entry->flags,
- entry->preempt_count, iter->idx);
+ trace_seq_printf(
+ s, "%16s %5d %3d %d %08x %08lx ",
+ comm, entry->pid, iter->cpu, entry->flags,
+ entry->preempt_count, iter->idx);
} else {
- ret = lat_print_generic(s, entry, iter->cpu);
+ lat_print_generic(s, entry, iter->cpu);
}
- if (ret)
- ret = lat_print_timestamp(iter, next_ts);
+ lat_print_timestamp(iter, next_ts);
- return ret;
+ return !trace_seq_has_overflowed(s);
}
static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
@@ -692,7 +687,7 @@ int register_ftrace_event(struct trace_event *event)
goto out;
} else {
-
+
event->type = next_event_type++;
list = &ftrace_event_list;
}
@@ -764,10 +759,9 @@ EXPORT_SYMBOL_GPL(unregister_ftrace_event);
enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags,
struct trace_event *event)
{
- if (!trace_seq_printf(&iter->seq, "type: %d\n", iter->ent->type))
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(&iter->seq, "type: %d\n", iter->ent->type);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(&iter->seq);
}
/* TRACE_FN */
@@ -779,24 +773,16 @@ static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- if (!seq_print_ip_sym(s, field->ip, flags))
- goto partial;
+ seq_print_ip_sym(s, field->ip, flags);
if ((flags & TRACE_ITER_PRINT_PARENT) && field->parent_ip) {
- if (!trace_seq_puts(s, " <-"))
- goto partial;
- if (!seq_print_ip_sym(s,
- field->parent_ip,
- flags))
- goto partial;
+ trace_seq_puts(s, " <-");
+ seq_print_ip_sym(s, field->parent_ip, flags);
}
- if (!trace_seq_putc(s, '\n'))
- goto partial;
- return TRACE_TYPE_HANDLED;
+ trace_seq_putc(s, '\n');
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags,
@@ -806,12 +792,11 @@ static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- if (!trace_seq_printf(&iter->seq, "%lx %lx\n",
- field->ip,
- field->parent_ip))
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(&iter->seq, "%lx %lx\n",
+ field->ip,
+ field->parent_ip);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(&iter->seq);
}
static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags,
@@ -822,10 +807,10 @@ static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- SEQ_PUT_HEX_FIELD_RET(s, field->ip);
- SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
+ SEQ_PUT_HEX_FIELD(s, field->ip);
+ SEQ_PUT_HEX_FIELD(s, field->parent_ip);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags,
@@ -836,10 +821,10 @@ static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- SEQ_PUT_FIELD_RET(s, field->ip);
- SEQ_PUT_FIELD_RET(s, field->parent_ip);
+ SEQ_PUT_FIELD(s, field->ip);
+ SEQ_PUT_FIELD(s, field->parent_ip);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static struct trace_event_functions trace_fn_funcs = {
@@ -868,18 +853,17 @@ static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
T = task_state_char(field->next_state);
S = task_state_char(field->prev_state);
trace_find_cmdline(field->next_pid, comm);
- if (!trace_seq_printf(&iter->seq,
- " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
- field->prev_pid,
- field->prev_prio,
- S, delim,
- field->next_cpu,
- field->next_pid,
- field->next_prio,
- T, comm))
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_printf(&iter->seq,
+ " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
+ field->prev_pid,
+ field->prev_prio,
+ S, delim,
+ field->next_cpu,
+ field->next_pid,
+ field->next_prio,
+ T, comm);
+
+ return trace_handle_return(&iter->seq);
}
static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags,
@@ -904,17 +888,16 @@ static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
if (!S)
S = task_state_char(field->prev_state);
T = task_state_char(field->next_state);
- if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
- field->prev_pid,
- field->prev_prio,
- S,
- field->next_cpu,
- field->next_pid,
- field->next_prio,
- T))
- return TRACE_TYPE_PARTIAL_LINE;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
+ field->prev_pid,
+ field->prev_prio,
+ S,
+ field->next_cpu,
+ field->next_pid,
+ field->next_prio,
+ T);
+
+ return trace_handle_return(&iter->seq);
}
static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags,
@@ -942,15 +925,15 @@ static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
S = task_state_char(field->prev_state);
T = task_state_char(field->next_state);
- SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
- SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
- SEQ_PUT_HEX_FIELD_RET(s, S);
- SEQ_PUT_HEX_FIELD_RET(s, field->next_cpu);
- SEQ_PUT_HEX_FIELD_RET(s, field->next_pid);
- SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
- SEQ_PUT_HEX_FIELD_RET(s, T);
+ SEQ_PUT_HEX_FIELD(s, field->prev_pid);
+ SEQ_PUT_HEX_FIELD(s, field->prev_prio);
+ SEQ_PUT_HEX_FIELD(s, S);
+ SEQ_PUT_HEX_FIELD(s, field->next_cpu);
+ SEQ_PUT_HEX_FIELD(s, field->next_pid);
+ SEQ_PUT_HEX_FIELD(s, field->next_prio);
+ SEQ_PUT_HEX_FIELD(s, T);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags,
@@ -973,14 +956,15 @@ static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
trace_assign_type(field, iter->ent);
- SEQ_PUT_FIELD_RET(s, field->prev_pid);
- SEQ_PUT_FIELD_RET(s, field->prev_prio);
- SEQ_PUT_FIELD_RET(s, field->prev_state);
- SEQ_PUT_FIELD_RET(s, field->next_pid);
- SEQ_PUT_FIELD_RET(s, field->next_prio);
- SEQ_PUT_FIELD_RET(s, field->next_state);
+ SEQ_PUT_FIELD(s, field->prev_pid);
+ SEQ_PUT_FIELD(s, field->prev_prio);
+ SEQ_PUT_FIELD(s, field->prev_state);
+ SEQ_PUT_FIELD(s, field->next_cpu);
+ SEQ_PUT_FIELD(s, field->next_pid);
+ SEQ_PUT_FIELD(s, field->next_prio);
+ SEQ_PUT_FIELD(s, field->next_state);
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static struct trace_event_functions trace_ctx_funcs = {
@@ -1020,23 +1004,19 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
trace_assign_type(field, iter->ent);
end = (unsigned long *)((long)iter->ent + iter->ent_size);
- if (!trace_seq_puts(s, "<stack trace>\n"))
- goto partial;
+ trace_seq_puts(s, "<stack trace>\n");
for (p = field->caller; p && *p != ULONG_MAX && p < end; p++) {
- if (!trace_seq_puts(s, " => "))
- goto partial;
- if (!seq_print_ip_sym(s, *p, flags))
- goto partial;
- if (!trace_seq_putc(s, '\n'))
- goto partial;
- }
+ if (trace_seq_has_overflowed(s))
+ break;
- return TRACE_TYPE_HANDLED;
+ trace_seq_puts(s, " => ");
+ seq_print_ip_sym(s, *p, flags);
+ trace_seq_putc(s, '\n');
+ }
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static struct trace_event_functions trace_stack_funcs = {
@@ -1057,16 +1037,10 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
trace_assign_type(field, iter->ent);
- if (!trace_seq_puts(s, "<user stack trace>\n"))
- goto partial;
-
- if (!seq_print_userip_objs(field, s, flags))
- goto partial;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_puts(s, "<user stack trace>\n");
+ seq_print_userip_objs(field, s, flags);
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static struct trace_event_functions trace_user_stack_funcs = {
@@ -1089,19 +1063,11 @@ trace_bputs_print(struct trace_iterator *iter, int flags,
trace_assign_type(field, entry);
- if (!seq_print_ip_sym(s, field->ip, flags))
- goto partial;
+ seq_print_ip_sym(s, field->ip, flags);
+ trace_seq_puts(s, ": ");
+ trace_seq_puts(s, field->str);
- if (!trace_seq_puts(s, ": "))
- goto partial;
-
- if (!trace_seq_puts(s, field->str))
- goto partial;
-
- return TRACE_TYPE_HANDLED;
-
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
@@ -1114,16 +1080,10 @@ trace_bputs_raw(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- if (!trace_seq_printf(s, ": %lx : ", field->ip))
- goto partial;
-
- if (!trace_seq_puts(s, field->str))
- goto partial;
+ trace_seq_printf(s, ": %lx : ", field->ip);
+ trace_seq_puts(s, field->str);
- return TRACE_TYPE_HANDLED;
-
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static struct trace_event_functions trace_bputs_funcs = {
@@ -1147,19 +1107,11 @@ trace_bprint_print(struct trace_iterator *iter, int flags,
trace_assign_type(field, entry);
- if (!seq_print_ip_sym(s, field->ip, flags))
- goto partial;
-
- if (!trace_seq_puts(s, ": "))
- goto partial;
-
- if (!trace_seq_bprintf(s, field->fmt, field->buf))
- goto partial;
+ seq_print_ip_sym(s, field->ip, flags);
+ trace_seq_puts(s, ": ");
+ trace_seq_bprintf(s, field->fmt, field->buf);
- return TRACE_TYPE_HANDLED;
-
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
@@ -1172,16 +1124,10 @@ trace_bprint_raw(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- if (!trace_seq_printf(s, ": %lx : ", field->ip))
- goto partial;
-
- if (!trace_seq_bprintf(s, field->fmt, field->buf))
- goto partial;
+ trace_seq_printf(s, ": %lx : ", field->ip);
+ trace_seq_bprintf(s, field->fmt, field->buf);
- return TRACE_TYPE_HANDLED;
-
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static struct trace_event_functions trace_bprint_funcs = {
@@ -1203,16 +1149,10 @@ static enum print_line_t trace_print_print(struct trace_iterator *iter,
trace_assign_type(field, iter->ent);
- if (!seq_print_ip_sym(s, field->ip, flags))
- goto partial;
-
- if (!trace_seq_printf(s, ": %s", field->buf))
- goto partial;
+ seq_print_ip_sym(s, field->ip, flags);
+ trace_seq_printf(s, ": %s", field->buf);
- return TRACE_TYPE_HANDLED;
-
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(s);
}
static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags,
@@ -1222,13 +1162,9 @@ static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags,
trace_assign_type(field, iter->ent);
- if (!trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf))
- goto partial;
-
- return TRACE_TYPE_HANDLED;
+ trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf);
- partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ return trace_handle_return(&iter->seq);
}
static struct trace_event_functions trace_print_funcs = {
diff --git a/kernel/trace/trace_output.h b/kernel/trace/trace_output.h
index 80b25b5..8ef2c40 100644
--- a/kernel/trace/trace_output.h
+++ b/kernel/trace/trace_output.h
@@ -35,17 +35,11 @@ trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry);
extern int __unregister_ftrace_event(struct trace_event *event);
extern struct rw_semaphore trace_event_sem;
-#define SEQ_PUT_FIELD_RET(s, x) \
-do { \
- if (!trace_seq_putmem(s, &(x), sizeof(x))) \
- return TRACE_TYPE_PARTIAL_LINE; \
-} while (0)
-
-#define SEQ_PUT_HEX_FIELD_RET(s, x) \
-do { \
- if (!trace_seq_putmem_hex(s, &(x), sizeof(x))) \
- return TRACE_TYPE_PARTIAL_LINE; \
-} while (0)
+#define SEQ_PUT_FIELD(s, x) \
+ trace_seq_putmem(s, &(x), sizeof(x))
+
+#define SEQ_PUT_HEX_FIELD(s, x) \
+ trace_seq_putmem_hex(s, &(x), sizeof(x))
#endif
diff --git a/kernel/trace/trace_printk.c b/kernel/trace/trace_printk.c
index 2900817..c4e70b6 100644
--- a/kernel/trace/trace_printk.c
+++ b/kernel/trace/trace_printk.c
@@ -305,7 +305,7 @@ static int t_show(struct seq_file *m, void *v)
seq_puts(m, "\\t");
break;
case '\\':
- seq_puts(m, "\\");
+ seq_putc(m, '\\');
break;
case '"':
seq_puts(m, "\\\"");
diff --git a/kernel/trace/trace_probe.c b/kernel/trace/trace_probe.c
index d4b9fc2..b983b2f 100644
--- a/kernel/trace/trace_probe.c
+++ b/kernel/trace/trace_probe.c
@@ -40,7 +40,8 @@ const char *reserved_field_names[] = {
int PRINT_TYPE_FUNC_NAME(type)(struct trace_seq *s, const char *name, \
void *data, void *ent) \
{ \
- return trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \
+ trace_seq_printf(s, " %s=" fmt, name, *(type *)data); \
+ return !trace_seq_has_overflowed(s); \
} \
const char PRINT_TYPE_FMT_NAME(type)[] = fmt; \
NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(type));
@@ -61,10 +62,11 @@ int PRINT_TYPE_FUNC_NAME(string)(struct trace_seq *s, const char *name,
int len = *(u32 *)data >> 16;
if (!len)
- return trace_seq_printf(s, " %s=(fault)", name);
+ trace_seq_printf(s, " %s=(fault)", name);
else
- return trace_seq_printf(s, " %s=\"%s\"", name,
- (const char *)get_loc_data(data, ent));
+ trace_seq_printf(s, " %s=\"%s\"", name,
+ (const char *)get_loc_data(data, ent));
+ return !trace_seq_has_overflowed(s);
}
NOKPROBE_SYMBOL(PRINT_TYPE_FUNC_NAME(string));
diff --git a/kernel/trace/trace_sched_switch.c b/kernel/trace/trace_sched_switch.c
index 3f34dc9..2e293be 100644
--- a/kernel/trace/trace_sched_switch.c
+++ b/kernel/trace/trace_sched_switch.c
@@ -14,122 +14,26 @@
#include "trace.h"
-static struct trace_array *ctx_trace;
-static int __read_mostly tracer_enabled;
static int sched_ref;
static DEFINE_MUTEX(sched_register_mutex);
-static int sched_stopped;
-
-
-void
-tracing_sched_switch_trace(struct trace_array *tr,
- struct task_struct *prev,
- struct task_struct *next,
- unsigned long flags, int pc)
-{
- struct ftrace_event_call *call = &event_context_switch;
- struct ring_buffer *buffer = tr->trace_buffer.buffer;
- struct ring_buffer_event *event;
- struct ctx_switch_entry *entry;
-
- event = trace_buffer_lock_reserve(buffer, TRACE_CTX,
- sizeof(*entry), flags, pc);
- if (!event)
- return;
- entry = ring_buffer_event_data(event);
- entry->prev_pid = prev->pid;
- entry->prev_prio = prev->prio;
- entry->prev_state = prev->state;
- entry->next_pid = next->pid;
- entry->next_prio = next->prio;
- entry->next_state = next->state;
- entry->next_cpu = task_cpu(next);
-
- if (!call_filter_check_discard(call, entry, buffer, event))
- trace_buffer_unlock_commit(buffer, event, flags, pc);
-}
static void
probe_sched_switch(void *ignore, struct task_struct *prev, struct task_struct *next)
{
- struct trace_array_cpu *data;
- unsigned long flags;
- int cpu;
- int pc;
-
if (unlikely(!sched_ref))
return;
tracing_record_cmdline(prev);
tracing_record_cmdline(next);
-
- if (!tracer_enabled || sched_stopped)
- return;
-
- pc = preempt_count();
- local_irq_save(flags);
- cpu = raw_smp_processor_id();
- data = per_cpu_ptr(ctx_trace->trace_buffer.data, cpu);
-
- if (likely(!atomic_read(&data->disabled)))
- tracing_sched_switch_trace(ctx_trace, prev, next, flags, pc);
-
- local_irq_restore(flags);
-}
-
-void
-tracing_sched_wakeup_trace(struct trace_array *tr,
- struct task_struct *wakee,
- struct task_struct *curr,
- unsigned long flags, int pc)
-{
- struct ftrace_event_call *call = &event_wakeup;
- struct ring_buffer_event *event;
- struct ctx_switch_entry *entry;
- struct ring_buffer *buffer = tr->trace_buffer.buffer;
-
- event = trace_buffer_lock_reserve(buffer, TRACE_WAKE,
- sizeof(*entry), flags, pc);
- if (!event)
- return;
- entry = ring_buffer_event_data(event);
- entry->prev_pid = curr->pid;
- entry->prev_prio = curr->prio;
- entry->prev_state = curr->state;
- entry->next_pid = wakee->pid;
- entry->next_prio = wakee->prio;
- entry->next_state = wakee->state;
- entry->next_cpu = task_cpu(wakee);
-
- if (!call_filter_check_discard(call, entry, buffer, event))
- trace_buffer_unlock_commit(buffer, event, flags, pc);
}
static void
probe_sched_wakeup(void *ignore, struct task_struct *wakee, int success)
{
- struct trace_array_cpu *data;
- unsigned long flags;
- int cpu, pc;
-
if (unlikely(!sched_ref))
return;
tracing_record_cmdline(current);
-
- if (!tracer_enabled || sched_stopped)
- return;
-
- pc = preempt_count();
- local_irq_save(flags);
- cpu = raw_smp_processor_id();
- data = per_cpu_ptr(ctx_trace->trace_buffer.data, cpu);
-
- if (likely(!atomic_read(&data->disabled)))
- tracing_sched_wakeup_trace(ctx_trace, wakee, current,
- flags, pc);
-
- local_irq_restore(flags);
}
static int tracing_sched_register(void)
@@ -197,51 +101,3 @@ void tracing_stop_cmdline_record(void)
{
tracing_stop_sched_switch();
}
-
-/**
- * tracing_start_sched_switch_record - start tracing context switches
- *
- * Turns on context switch tracing for a tracer.
- */
-void tracing_start_sched_switch_record(void)
-{
- if (unlikely(!ctx_trace)) {
- WARN_ON(1);
- return;
- }
-
- tracing_start_sched_switch();
-
- mutex_lock(&sched_register_mutex);
- tracer_enabled++;
- mutex_unlock(&sched_register_mutex);
-}
-
-/**
- * tracing_stop_sched_switch_record - start tracing context switches
- *
- * Turns off context switch tracing for a tracer.
- */
-void tracing_stop_sched_switch_record(void)
-{
- mutex_lock(&sched_register_mutex);
- tracer_enabled--;
- WARN_ON(tracer_enabled < 0);
- mutex_unlock(&sched_register_mutex);
-
- tracing_stop_sched_switch();
-}
-
-/**
- * tracing_sched_switch_assign_trace - assign a trace array for ctx switch
- * @tr: trace array pointer to assign
- *
- * Some tracers might want to record the context switches in their
- * trace. This function lets those tracers assign the trace array
- * to use.
- */
-void tracing_sched_switch_assign_trace(struct trace_array *tr)
-{
- ctx_trace = tr;
-}
-
diff --git a/kernel/trace/trace_sched_wakeup.c b/kernel/trace/trace_sched_wakeup.c
index 19bd892..8fb84b3 100644
--- a/kernel/trace/trace_sched_wakeup.c
+++ b/kernel/trace/trace_sched_wakeup.c
@@ -365,6 +365,62 @@ probe_wakeup_migrate_task(void *ignore, struct task_struct *task, int cpu)
wakeup_current_cpu = cpu;
}
+static void
+tracing_sched_switch_trace(struct trace_array *tr,
+ struct task_struct *prev,
+ struct task_struct *next,
+ unsigned long flags, int pc)
+{
+ struct ftrace_event_call *call = &event_context_switch;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
+ struct ring_buffer_event *event;
+ struct ctx_switch_entry *entry;
+
+ event = trace_buffer_lock_reserve(buffer, TRACE_CTX,
+ sizeof(*entry), flags, pc);
+ if (!event)
+ return;
+ entry = ring_buffer_event_data(event);
+ entry->prev_pid = prev->pid;
+ entry->prev_prio = prev->prio;
+ entry->prev_state = prev->state;
+ entry->next_pid = next->pid;
+ entry->next_prio = next->prio;
+ entry->next_state = next->state;
+ entry->next_cpu = task_cpu(next);
+
+ if (!call_filter_check_discard(call, entry, buffer, event))
+ trace_buffer_unlock_commit(buffer, event, flags, pc);
+}
+
+static void
+tracing_sched_wakeup_trace(struct trace_array *tr,
+ struct task_struct *wakee,
+ struct task_struct *curr,
+ unsigned long flags, int pc)
+{
+ struct ftrace_event_call *call = &event_wakeup;
+ struct ring_buffer_event *event;
+ struct ctx_switch_entry *entry;
+ struct ring_buffer *buffer = tr->trace_buffer.buffer;
+
+ event = trace_buffer_lock_reserve(buffer, TRACE_WAKE,
+ sizeof(*entry), flags, pc);
+ if (!event)
+ return;
+ entry = ring_buffer_event_data(event);
+ entry->prev_pid = curr->pid;
+ entry->prev_prio = curr->prio;
+ entry->prev_state = curr->state;
+ entry->next_pid = wakee->pid;
+ entry->next_prio = wakee->prio;
+ entry->next_state = wakee->state;
+ entry->next_cpu = task_cpu(wakee);
+
+ if (!call_filter_check_discard(call, entry, buffer, event))
+ trace_buffer_unlock_commit(buffer, event, flags, pc);
+}
+
static void notrace
probe_wakeup_sched_switch(void *ignore,
struct task_struct *prev, struct task_struct *next)
diff --git a/kernel/trace/trace_seq.c b/kernel/trace/trace_seq.c
index 1f24ed9..f8b45d8 100644
--- a/kernel/trace/trace_seq.c
+++ b/kernel/trace/trace_seq.c
@@ -27,10 +27,19 @@
#include <linux/trace_seq.h>
/* How much buffer is left on the trace_seq? */
-#define TRACE_SEQ_BUF_LEFT(s) ((PAGE_SIZE - 1) - (s)->len)
+#define TRACE_SEQ_BUF_LEFT(s) seq_buf_buffer_left(&(s)->seq)
/* How much buffer is written? */
-#define TRACE_SEQ_BUF_USED(s) min((s)->len, (unsigned int)(PAGE_SIZE - 1))
+#define TRACE_SEQ_BUF_USED(s) seq_buf_used(&(s)->seq)
+
+/*
+ * trace_seq should work with being initialized with 0s.
+ */
+static inline void __trace_seq_init(struct trace_seq *s)
+{
+ if (unlikely(!s->seq.size))
+ trace_seq_init(s);
+}
/**
* trace_print_seq - move the contents of trace_seq into a seq_file
@@ -43,10 +52,11 @@
*/
int trace_print_seq(struct seq_file *m, struct trace_seq *s)
{
- unsigned int len = TRACE_SEQ_BUF_USED(s);
int ret;
- ret = seq_write(m, s->buffer, len);
+ __trace_seq_init(s);
+
+ ret = seq_buf_print_seq(m, &s->seq);
/*
* Only reset this buffer if we successfully wrote to the
@@ -69,34 +79,26 @@ int trace_print_seq(struct seq_file *m, struct trace_seq *s)
* trace_seq_printf() is used to store strings into a special
* buffer (@s). Then the output may be either used by
* the sequencer or pulled into another buffer.
- *
- * Returns 1 if we successfully written all the contents to
- * the buffer.
- * Returns 0 if we the length to write is bigger than the
- * reserved buffer space. In this case, nothing gets written.
*/
-int trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
+void trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
{
- unsigned int len = TRACE_SEQ_BUF_LEFT(s);
+ unsigned int save_len = s->seq.len;
va_list ap;
- int ret;
- if (s->full || !len)
- return 0;
+ if (s->full)
+ return;
+
+ __trace_seq_init(s);
va_start(ap, fmt);
- ret = vsnprintf(s->buffer + s->len, len, fmt, ap);
+ seq_buf_vprintf(&s->seq, fmt, ap);
va_end(ap);
/* If we can't write it all, don't bother writing anything */
- if (ret >= len) {
+ if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+ s->seq.len = save_len;
s->full = 1;
- return 0;
}
-
- s->len += ret;
-
- return 1;
}
EXPORT_SYMBOL_GPL(trace_seq_printf);
@@ -107,25 +109,23 @@ EXPORT_SYMBOL_GPL(trace_seq_printf);
* @nmaskbits: The number of bits that are valid in @maskp
*
* Writes a ASCII representation of a bitmask string into @s.
- *
- * Returns 1 if we successfully written all the contents to
- * the buffer.
- * Returns 0 if we the length to write is bigger than the
- * reserved buffer space. In this case, nothing gets written.
*/
-int trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
+void trace_seq_bitmask(struct trace_seq *s, const unsigned long *maskp,
int nmaskbits)
{
- unsigned int len = TRACE_SEQ_BUF_LEFT(s);
- int ret;
+ unsigned int save_len = s->seq.len;
- if (s->full || !len)
- return 0;
+ if (s->full)
+ return;
- ret = bitmap_scnprintf(s->buffer, len, maskp, nmaskbits);
- s->len += ret;
+ __trace_seq_init(s);
- return 1;
+ seq_buf_bitmask(&s->seq, maskp, nmaskbits);
+
+ if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+ s->seq.len = save_len;
+ s->full = 1;
+ }
}
EXPORT_SYMBOL_GPL(trace_seq_bitmask);
@@ -139,28 +139,23 @@ EXPORT_SYMBOL_GPL(trace_seq_bitmask);
* trace_seq_printf is used to store strings into a special
* buffer (@s). Then the output may be either used by
* the sequencer or pulled into another buffer.
- *
- * Returns how much it wrote to the buffer.
*/
-int trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+void trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
{
- unsigned int len = TRACE_SEQ_BUF_LEFT(s);
- int ret;
+ unsigned int save_len = s->seq.len;
- if (s->full || !len)
- return 0;
+ if (s->full)
+ return;
- ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+ __trace_seq_init(s);
+
+ seq_buf_vprintf(&s->seq, fmt, args);
/* If we can't write it all, don't bother writing anything */
- if (ret >= len) {
+ if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+ s->seq.len = save_len;
s->full = 1;
- return 0;
}
-
- s->len += ret;
-
- return len;
}
EXPORT_SYMBOL_GPL(trace_seq_vprintf);
@@ -178,28 +173,24 @@ EXPORT_SYMBOL_GPL(trace_seq_vprintf);
*
* This function will take the format and the binary array and finish
* the conversion into the ASCII string within the buffer.
- *
- * Returns how much it wrote to the buffer.
*/
-int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
+void trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
{
- unsigned int len = TRACE_SEQ_BUF_LEFT(s);
- int ret;
+ unsigned int save_len = s->seq.len;
- if (s->full || !len)
- return 0;
+ if (s->full)
+ return;
+
+ __trace_seq_init(s);
- ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
+ seq_buf_bprintf(&s->seq, fmt, binary);
/* If we can't write it all, don't bother writing anything */
- if (ret >= len) {
+ if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+ s->seq.len = save_len;
s->full = 1;
- return 0;
+ return;
}
-
- s->len += ret;
-
- return len;
}
EXPORT_SYMBOL_GPL(trace_seq_bprintf);
@@ -212,25 +203,22 @@ EXPORT_SYMBOL_GPL(trace_seq_bprintf);
* copy to user routines. This function records a simple string
* into a special buffer (@s) for later retrieval by a sequencer
* or other mechanism.
- *
- * Returns how much it wrote to the buffer.
*/
-int trace_seq_puts(struct trace_seq *s, const char *str)
+void trace_seq_puts(struct trace_seq *s, const char *str)
{
unsigned int len = strlen(str);
if (s->full)
- return 0;
+ return;
+
+ __trace_seq_init(s);
if (len > TRACE_SEQ_BUF_LEFT(s)) {
s->full = 1;
- return 0;
+ return;
}
- memcpy(s->buffer + s->len, str, len);
- s->len += len;
-
- return len;
+ seq_buf_putmem(&s->seq, str, len);
}
EXPORT_SYMBOL_GPL(trace_seq_puts);
@@ -243,22 +231,20 @@ EXPORT_SYMBOL_GPL(trace_seq_puts);
* copy to user routines. This function records a simple charater
* into a special buffer (@s) for later retrieval by a sequencer
* or other mechanism.
- *
- * Returns how much it wrote to the buffer.
*/
-int trace_seq_putc(struct trace_seq *s, unsigned char c)
+void trace_seq_putc(struct trace_seq *s, unsigned char c)
{
if (s->full)
- return 0;
+ return;
+
+ __trace_seq_init(s);
if (TRACE_SEQ_BUF_LEFT(s) < 1) {
s->full = 1;
- return 0;
+ return;
}
- s->buffer[s->len++] = c;
-
- return 1;
+ seq_buf_putc(&s->seq, c);
}
EXPORT_SYMBOL_GPL(trace_seq_putc);
@@ -271,29 +257,23 @@ EXPORT_SYMBOL_GPL(trace_seq_putc);
* There may be cases where raw memory needs to be written into the
* buffer and a strcpy() would not work. Using this function allows
* for such cases.
- *
- * Returns how much it wrote to the buffer.
*/
-int trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len)
+void trace_seq_putmem(struct trace_seq *s, const void *mem, unsigned int len)
{
if (s->full)
- return 0;
+ return;
+
+ __trace_seq_init(s);
if (len > TRACE_SEQ_BUF_LEFT(s)) {
s->full = 1;
- return 0;
+ return;
}
- memcpy(s->buffer + s->len, mem, len);
- s->len += len;
-
- return len;
+ seq_buf_putmem(&s->seq, mem, len);
}
EXPORT_SYMBOL_GPL(trace_seq_putmem);
-#define MAX_MEMHEX_BYTES 8U
-#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
-
/**
* trace_seq_putmem_hex - write raw memory into the buffer in ASCII hex
* @s: trace sequence descriptor
@@ -303,41 +283,31 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem);
* This is similar to trace_seq_putmem() except instead of just copying the
* raw memory into the buffer it writes its ASCII representation of it
* in hex characters.
- *
- * Returns how much it wrote to the buffer.
*/
-int trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
+void trace_seq_putmem_hex(struct trace_seq *s, const void *mem,
unsigned int len)
{
- unsigned char hex[HEX_CHARS];
- const unsigned char *data = mem;
- unsigned int start_len;
- int i, j;
- int cnt = 0;
+ unsigned int save_len = s->seq.len;
if (s->full)
- return 0;
+ return;
- while (len) {
- start_len = min(len, HEX_CHARS - 1);
-#ifdef __BIG_ENDIAN
- for (i = 0, j = 0; i < start_len; i++) {
-#else
- for (i = start_len-1, j = 0; i >= 0; i--) {
-#endif
- hex[j++] = hex_asc_hi(data[i]);
- hex[j++] = hex_asc_lo(data[i]);
- }
- if (WARN_ON_ONCE(j == 0 || j/2 > len))
- break;
-
- /* j increments twice per loop */
- len -= j / 2;
- hex[j++] = ' ';
-
- cnt += trace_seq_putmem(s, hex, j);
+ __trace_seq_init(s);
+
+ /* Each byte is represented by two chars */
+ if (len * 2 > TRACE_SEQ_BUF_LEFT(s)) {
+ s->full = 1;
+ return;
+ }
+
+ /* The added spaces can still cause an overflow */
+ seq_buf_putmem_hex(&s->seq, mem, len);
+
+ if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+ s->seq.len = save_len;
+ s->full = 1;
+ return;
}
- return cnt;
}
EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);
@@ -355,30 +325,27 @@ EXPORT_SYMBOL_GPL(trace_seq_putmem_hex);
*/
int trace_seq_path(struct trace_seq *s, const struct path *path)
{
- unsigned char *p;
+ unsigned int save_len = s->seq.len;
if (s->full)
return 0;
+ __trace_seq_init(s);
+
if (TRACE_SEQ_BUF_LEFT(s) < 1) {
s->full = 1;
return 0;
}
- p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
- if (!IS_ERR(p)) {
- p = mangle_path(s->buffer + s->len, p, "\n");
- if (p) {
- s->len = p - s->buffer;
- return 1;
- }
- } else {
- s->buffer[s->len++] = '?';
- return 1;
+ seq_buf_path(&s->seq, path, "\n");
+
+ if (unlikely(seq_buf_has_overflowed(&s->seq))) {
+ s->seq.len = save_len;
+ s->full = 1;
+ return 0;
}
- s->full = 1;
- return 0;
+ return 1;
}
EXPORT_SYMBOL_GPL(trace_seq_path);
@@ -404,25 +371,7 @@ EXPORT_SYMBOL_GPL(trace_seq_path);
*/
int trace_seq_to_user(struct trace_seq *s, char __user *ubuf, int cnt)
{
- int len;
- int ret;
-
- if (!cnt)
- return 0;
-
- if (s->len <= s->readpos)
- return -EBUSY;
-
- len = s->len - s->readpos;
- if (cnt > len)
- cnt = len;
- ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
- if (ret == cnt)
- return -EFAULT;
-
- cnt -= ret;
-
- s->readpos += cnt;
- return cnt;
+ __trace_seq_init(s);
+ return seq_buf_to_user(&s->seq, ubuf, cnt);
}
EXPORT_SYMBOL_GPL(trace_seq_to_user);
diff --git a/kernel/trace/trace_syscalls.c b/kernel/trace/trace_syscalls.c
index 29228c4..dfe00a4 100644
--- a/kernel/trace/trace_syscalls.c
+++ b/kernel/trace/trace_syscalls.c
@@ -114,7 +114,7 @@ print_syscall_enter(struct trace_iterator *iter, int flags,
struct trace_entry *ent = iter->ent;
struct syscall_trace_enter *trace;
struct syscall_metadata *entry;
- int i, ret, syscall;
+ int i, syscall;
trace = (typeof(trace))ent;
syscall = trace->nr;
@@ -128,35 +128,28 @@ print_syscall_enter(struct trace_iterator *iter, int flags,
goto end;
}
- ret = trace_seq_printf(s, "%s(", entry->name);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%s(", entry->name);
for (i = 0; i < entry->nb_args; i++) {
+
+ if (trace_seq_has_overflowed(s))
+ goto end;
+
/* parameter types */
- if (trace_flags & TRACE_ITER_VERBOSE) {
- ret = trace_seq_printf(s, "%s ", entry->types[i]);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- }
+ if (trace_flags & TRACE_ITER_VERBOSE)
+ trace_seq_printf(s, "%s ", entry->types[i]);
+
/* parameter values */
- ret = trace_seq_printf(s, "%s: %lx%s", entry->args[i],
- trace->args[i],
- i == entry->nb_args - 1 ? "" : ", ");
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_printf(s, "%s: %lx%s", entry->args[i],
+ trace->args[i],
+ i == entry->nb_args - 1 ? "" : ", ");
}
- ret = trace_seq_putc(s, ')');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
-
+ trace_seq_putc(s, ')');
end:
- ret = trace_seq_putc(s, '\n');
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
+ trace_seq_putc(s, '\n');
- return TRACE_TYPE_HANDLED;
+ return trace_handle_return(s);
}
static enum print_line_t
@@ -168,7 +161,6 @@ print_syscall_exit(struct trace_iterator *iter, int flags,
struct syscall_trace_exit *trace;
int syscall;
struct syscall_metadata *entry;
- int ret;
trace = (typeof(trace))ent;
syscall = trace->nr;
@@ -176,7 +168,7 @@ print_syscall_exit(struct trace_iterator *iter, int flags,
if (!entry) {
trace_seq_putc(s, '\n');
- return TRACE_TYPE_HANDLED;
+ goto out;
}
if (entry->exit_event->event.type != ent->type) {
@@ -184,12 +176,11 @@ print_syscall_exit(struct trace_iterator *iter, int flags,
return TRACE_TYPE_UNHANDLED;
}
- ret = trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
+ trace_seq_printf(s, "%s -> 0x%lx\n", entry->name,
trace->ret);
- if (!ret)
- return TRACE_TYPE_PARTIAL_LINE;
- return TRACE_TYPE_HANDLED;
+ out:
+ return trace_handle_return(s);
}
extern char *__bad_type_size(void);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 33ff6a2..8520acc 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -552,8 +552,7 @@ error:
return ret;
fail_address_parse:
- if (inode)
- iput(inode);
+ iput(inode);
pr_info("Failed to parse address or file.\n");
@@ -606,7 +605,7 @@ static int probes_seq_show(struct seq_file *m, void *v)
for (i = 0; i < tu->tp.nr_args; i++)
seq_printf(m, " %s=%s", tu->tp.args[i].name, tu->tp.args[i].comm);
- seq_printf(m, "\n");
+ seq_putc(m, '\n');
return 0;
}
@@ -852,16 +851,14 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
tu = container_of(event, struct trace_uprobe, tp.call.event);
if (is_ret_probe(tu)) {
- if (!trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
- ftrace_event_name(&tu->tp.call),
- entry->vaddr[1], entry->vaddr[0]))
- goto partial;
+ trace_seq_printf(s, "%s: (0x%lx <- 0x%lx)",
+ ftrace_event_name(&tu->tp.call),
+ entry->vaddr[1], entry->vaddr[0]);
data = DATAOF_TRACE_ENTRY(entry, true);
} else {
- if (!trace_seq_printf(s, "%s: (0x%lx)",
- ftrace_event_name(&tu->tp.call),
- entry->vaddr[0]))
- goto partial;
+ trace_seq_printf(s, "%s: (0x%lx)",
+ ftrace_event_name(&tu->tp.call),
+ entry->vaddr[0]);
data = DATAOF_TRACE_ENTRY(entry, false);
}
@@ -869,14 +866,13 @@ print_uprobe_event(struct trace_iterator *iter, int flags, struct trace_event *e
struct probe_arg *parg = &tu->tp.args[i];
if (!parg->type->print(s, parg->name, data + parg->offset, entry))
- goto partial;
+ goto out;
}
- if (trace_seq_puts(s, "\n"))
- return TRACE_TYPE_HANDLED;
+ trace_seq_putc(s, '\n');
-partial:
- return TRACE_TYPE_PARTIAL_LINE;
+ out:
+ return trace_handle_return(s);
}
typedef bool (*filter_func_t)(struct uprobe_consumer *self,
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 4e35a5d..d780351 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -1238,21 +1238,9 @@ config RCU_CPU_STALL_TIMEOUT
RCU grace period persists, additional CPU stall warnings are
printed at more widely spaced intervals.
-config RCU_CPU_STALL_VERBOSE
- bool "Print additional per-task information for RCU_CPU_STALL_DETECTOR"
- depends on TREE_PREEMPT_RCU
- default y
- help
- This option causes RCU to printk detailed per-task information
- for any tasks that are stalling the current RCU grace period.
-
- Say N if you are unsure.
-
- Say Y if you want to enable such checks.
-
config RCU_CPU_STALL_INFO
bool "Print additional diagnostics on RCU CPU stall"
- depends on (TREE_RCU || TREE_PREEMPT_RCU) && DEBUG_KERNEL
+ depends on (TREE_RCU || PREEMPT_RCU) && DEBUG_KERNEL
default n
help
For each stalled CPU that is aware of the current RCU grace
diff --git a/lib/Makefile b/lib/Makefile
index 4b9baa4..3c3b30b 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -13,7 +13,7 @@ lib-y := ctype.o string.o vsprintf.o cmdline.o \
sha1.o md5.o irq_regs.o argv_split.o \
proportions.o flex_proportions.o ratelimit.o show_mem.o \
is_single_threaded.o plist.o decompress.o kobject_uevent.o \
- earlycpio.o
+ earlycpio.o seq_buf.o
obj-$(CONFIG_ARCH_HAS_DEBUG_STRICT_USER_COPY_CHECKS) += usercopy.o
lib-$(CONFIG_MMU) += ioremap.o
diff --git a/lib/dma-debug.c b/lib/dma-debug.c
index add80cc..9722bd2 100644
--- a/lib/dma-debug.c
+++ b/lib/dma-debug.c
@@ -102,6 +102,14 @@ static DEFINE_SPINLOCK(free_entries_lock);
/* Global disable flag - will be set in case of an error */
static u32 global_disable __read_mostly;
+/* Early initialization disable flag, set at the end of dma_debug_init */
+static bool dma_debug_initialized __read_mostly;
+
+static inline bool dma_debug_disabled(void)
+{
+ return global_disable || !dma_debug_initialized;
+}
+
/* Global error count */
static u32 error_count;
@@ -945,7 +953,7 @@ static int dma_debug_device_change(struct notifier_block *nb, unsigned long acti
struct dma_debug_entry *uninitialized_var(entry);
int count;
- if (global_disable)
+ if (dma_debug_disabled())
return 0;
switch (action) {
@@ -973,7 +981,7 @@ void dma_debug_add_bus(struct bus_type *bus)
{
struct notifier_block *nb;
- if (global_disable)
+ if (dma_debug_disabled())
return;
nb = kzalloc(sizeof(struct notifier_block), GFP_KERNEL);
@@ -994,6 +1002,9 @@ void dma_debug_init(u32 num_entries)
{
int i;
+ /* Do not use dma_debug_initialized here, since we really want to be
+ * called to set dma_debug_initialized
+ */
if (global_disable)
return;
@@ -1021,6 +1032,8 @@ void dma_debug_init(u32 num_entries)
nr_total_entries = num_free_entries;
+ dma_debug_initialized = true;
+
pr_info("DMA-API: debugging enabled by kernel config\n");
}
@@ -1243,7 +1256,7 @@ void debug_dma_map_page(struct device *dev, struct page *page, size_t offset,
{
struct dma_debug_entry *entry;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
if (dma_mapping_error(dev, dma_addr))
@@ -1283,7 +1296,7 @@ void debug_dma_mapping_error(struct device *dev, dma_addr_t dma_addr)
struct hash_bucket *bucket;
unsigned long flags;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
ref.dev = dev;
@@ -1325,7 +1338,7 @@ void debug_dma_unmap_page(struct device *dev, dma_addr_t addr,
.direction = direction,
};
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
if (map_single)
@@ -1342,7 +1355,7 @@ void debug_dma_map_sg(struct device *dev, struct scatterlist *sg,
struct scatterlist *s;
int i;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
for_each_sg(sg, s, mapped_ents, i) {
@@ -1395,7 +1408,7 @@ void debug_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
struct scatterlist *s;
int mapped_ents = 0, i;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
for_each_sg(sglist, s, nelems, i) {
@@ -1427,7 +1440,7 @@ void debug_dma_alloc_coherent(struct device *dev, size_t size,
{
struct dma_debug_entry *entry;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
if (unlikely(virt == NULL))
@@ -1462,7 +1475,7 @@ void debug_dma_free_coherent(struct device *dev, size_t size,
.direction = DMA_BIDIRECTIONAL,
};
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
check_unmap(&ref);
@@ -1474,7 +1487,7 @@ void debug_dma_sync_single_for_cpu(struct device *dev, dma_addr_t dma_handle,
{
struct dma_debug_entry ref;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
ref.type = dma_debug_single;
@@ -1494,7 +1507,7 @@ void debug_dma_sync_single_for_device(struct device *dev,
{
struct dma_debug_entry ref;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
ref.type = dma_debug_single;
@@ -1515,7 +1528,7 @@ void debug_dma_sync_single_range_for_cpu(struct device *dev,
{
struct dma_debug_entry ref;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
ref.type = dma_debug_single;
@@ -1536,7 +1549,7 @@ void debug_dma_sync_single_range_for_device(struct device *dev,
{
struct dma_debug_entry ref;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
ref.type = dma_debug_single;
@@ -1556,7 +1569,7 @@ void debug_dma_sync_sg_for_cpu(struct device *dev, struct scatterlist *sg,
struct scatterlist *s;
int mapped_ents = 0, i;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
for_each_sg(sg, s, nelems, i) {
@@ -1589,7 +1602,7 @@ void debug_dma_sync_sg_for_device(struct device *dev, struct scatterlist *sg,
struct scatterlist *s;
int mapped_ents = 0, i;
- if (unlikely(global_disable))
+ if (unlikely(dma_debug_disabled()))
return;
for_each_sg(sg, s, nelems, i) {
diff --git a/lib/dynamic_debug.c b/lib/dynamic_debug.c
index dfba055..527799d 100644
--- a/lib/dynamic_debug.c
+++ b/lib/dynamic_debug.c
@@ -576,7 +576,7 @@ void __dynamic_dev_dbg(struct _ddebug *descriptor,
} else {
char buf[PREFIX_SIZE];
- dev_printk_emit(7, dev, "%s%s %s: %pV",
+ dev_printk_emit(LOGLEVEL_DEBUG, dev, "%s%s %s: %pV",
dynamic_emit_prefix(descriptor, buf),
dev_driver_string(dev), dev_name(dev),
&vaf);
@@ -605,7 +605,7 @@ void __dynamic_netdev_dbg(struct _ddebug *descriptor,
if (dev && dev->dev.parent) {
char buf[PREFIX_SIZE];
- dev_printk_emit(7, dev->dev.parent,
+ dev_printk_emit(LOGLEVEL_DEBUG, dev->dev.parent,
"%s%s %s %s%s: %pV",
dynamic_emit_prefix(descriptor, buf),
dev_driver_string(dev->dev.parent),
diff --git a/lib/lcm.c b/lib/lcm.c
index b9c8de4..51cc6b1 100644
--- a/lib/lcm.c
+++ b/lib/lcm.c
@@ -7,10 +7,8 @@
unsigned long lcm(unsigned long a, unsigned long b)
{
if (a && b)
- return (a * b) / gcd(a, b);
- else if (b)
- return b;
-
- return a;
+ return (a / gcd(a, b)) * b;
+ else
+ return 0;
}
EXPORT_SYMBOL_GPL(lcm);
diff --git a/lib/seq_buf.c b/lib/seq_buf.c
new file mode 100644
index 0000000..4eedfed
--- /dev/null
+++ b/lib/seq_buf.c
@@ -0,0 +1,359 @@
+/*
+ * seq_buf.c
+ *
+ * Copyright (C) 2014 Red Hat Inc, Steven Rostedt <srostedt@redhat.com>
+ *
+ * The seq_buf is a handy tool that allows you to pass a descriptor around
+ * to a buffer that other functions can write to. It is similar to the
+ * seq_file functionality but has some differences.
+ *
+ * To use it, the seq_buf must be initialized with seq_buf_init().
+ * This will set up the counters within the descriptor. You can call
+ * seq_buf_init() more than once to reset the seq_buf to start
+ * from scratch.
+ */
+#include <linux/uaccess.h>
+#include <linux/seq_file.h>
+#include <linux/seq_buf.h>
+
+/**
+ * seq_buf_can_fit - can the new data fit in the current buffer?
+ * @s: the seq_buf descriptor
+ * @len: The length to see if it can fit in the current buffer
+ *
+ * Returns true if there's enough unused space in the seq_buf buffer
+ * to fit the amount of new data according to @len.
+ */
+static bool seq_buf_can_fit(struct seq_buf *s, size_t len)
+{
+ return s->len + len <= s->size;
+}
+
+/**
+ * seq_buf_print_seq - move the contents of seq_buf into a seq_file
+ * @m: the seq_file descriptor that is the destination
+ * @s: the seq_buf descriptor that is the source.
+ *
+ * Returns zero on success, non zero otherwise
+ */
+int seq_buf_print_seq(struct seq_file *m, struct seq_buf *s)
+{
+ unsigned int len = seq_buf_used(s);
+
+ return seq_write(m, s->buffer, len);
+}
+
+/**
+ * seq_buf_vprintf - sequence printing of information.
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ * @args: va_list of arguments from a printf() type function
+ *
+ * Writes a vnprintf() format into the sequencce buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_vprintf(struct seq_buf *s, const char *fmt, va_list args)
+{
+ int len;
+
+ WARN_ON(s->size == 0);
+
+ if (s->len < s->size) {
+ len = vsnprintf(s->buffer + s->len, s->size - s->len, fmt, args);
+ if (seq_buf_can_fit(s, len)) {
+ s->len += len;
+ return 0;
+ }
+ }
+ seq_buf_set_overflow(s);
+ return -1;
+}
+
+/**
+ * seq_buf_printf - sequence printing of information
+ * @s: seq_buf descriptor
+ * @fmt: printf format string
+ *
+ * Writes a printf() format into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_printf(struct seq_buf *s, const char *fmt, ...)
+{
+ va_list ap;
+ int ret;
+
+ va_start(ap, fmt);
+ ret = seq_buf_vprintf(s, fmt, ap);
+ va_end(ap);
+
+ return ret;
+}
+
+/**
+ * seq_buf_bitmask - write a bitmask array in its ASCII representation
+ * @s: seq_buf descriptor
+ * @maskp: points to an array of unsigned longs that represent a bitmask
+ * @nmaskbits: The number of bits that are valid in @maskp
+ *
+ * Writes a ASCII representation of a bitmask string into @s.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_bitmask(struct seq_buf *s, const unsigned long *maskp,
+ int nmaskbits)
+{
+ unsigned int len = seq_buf_buffer_left(s);
+ int ret;
+
+ WARN_ON(s->size == 0);
+
+ /*
+ * Note, because bitmap_scnprintf() only returns the number of bytes
+ * written and not the number that would be written, we use the last
+ * byte of the buffer to let us know if we overflowed. There's a small
+ * chance that the bitmap could have fit exactly inside the buffer, but
+ * it's not that critical if that does happen.
+ */
+ if (len > 1) {
+ ret = bitmap_scnprintf(s->buffer + s->len, len, maskp, nmaskbits);
+ if (ret < len) {
+ s->len += ret;
+ return 0;
+ }
+ }
+ seq_buf_set_overflow(s);
+ return -1;
+}
+
+#ifdef CONFIG_BINARY_PRINTF
+/**
+ * seq_buf_bprintf - Write the printf string from binary arguments
+ * @s: seq_buf descriptor
+ * @fmt: The format string for the @binary arguments
+ * @binary: The binary arguments for @fmt.
+ *
+ * When recording in a fast path, a printf may be recorded with just
+ * saving the format and the arguments as they were passed to the
+ * function, instead of wasting cycles converting the arguments into
+ * ASCII characters. Instead, the arguments are saved in a 32 bit
+ * word array that is defined by the format string constraints.
+ *
+ * This function will take the format and the binary array and finish
+ * the conversion into the ASCII string within the buffer.
+ *
+ * Returns zero on success, -1 on overflow.
+ */
+int seq_buf_bprintf(struct seq_buf *s, const char *fmt, const u32 *binary)
+{
+ unsigned int len = seq_buf_buffer_left(s);
+ int ret;
+
+ WARN_ON(s->size == 0);
+
+ if (s->len < s->size) {
+ ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
+ if (seq_buf_can_fit(s, ret)) {
+ s->len += ret;
+ return 0;
+ }
+ }
+ seq_buf_set_overflow(s);
+ return -1;
+}
+#endif /* CONFIG_BINARY_PRINTF */
+
+/**
+ * seq_buf_puts - sequence printing of simple string
+ * @s: seq_buf descriptor
+ * @str: simple string to record
+ *
+ * Copy a simple string into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_puts(struct seq_buf *s, const char *str)
+{
+ unsigned int len = strlen(str);
+
+ WARN_ON(s->size == 0);
+
+ if (seq_buf_can_fit(s, len)) {
+ memcpy(s->buffer + s->len, str, len);
+ s->len += len;
+ return 0;
+ }
+ seq_buf_set_overflow(s);
+ return -1;
+}
+
+/**
+ * seq_buf_putc - sequence printing of simple character
+ * @s: seq_buf descriptor
+ * @c: simple character to record
+ *
+ * Copy a single character into the sequence buffer.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_putc(struct seq_buf *s, unsigned char c)
+{
+ WARN_ON(s->size == 0);
+
+ if (seq_buf_can_fit(s, 1)) {
+ s->buffer[s->len++] = c;
+ return 0;
+ }
+ seq_buf_set_overflow(s);
+ return -1;
+}
+
+/**
+ * seq_buf_putmem - write raw data into the sequenc buffer
+ * @s: seq_buf descriptor
+ * @mem: The raw memory to copy into the buffer
+ * @len: The length of the raw memory to copy (in bytes)
+ *
+ * There may be cases where raw memory needs to be written into the
+ * buffer and a strcpy() would not work. Using this function allows
+ * for such cases.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_putmem(struct seq_buf *s, const void *mem, unsigned int len)
+{
+ WARN_ON(s->size == 0);
+
+ if (seq_buf_can_fit(s, len)) {
+ memcpy(s->buffer + s->len, mem, len);
+ s->len += len;
+ return 0;
+ }
+ seq_buf_set_overflow(s);
+ return -1;
+}
+
+#define MAX_MEMHEX_BYTES 8U
+#define HEX_CHARS (MAX_MEMHEX_BYTES*2 + 1)
+
+/**
+ * seq_buf_putmem_hex - write raw memory into the buffer in ASCII hex
+ * @s: seq_buf descriptor
+ * @mem: The raw memory to write its hex ASCII representation of
+ * @len: The length of the raw memory to copy (in bytes)
+ *
+ * This is similar to seq_buf_putmem() except instead of just copying the
+ * raw memory into the buffer it writes its ASCII representation of it
+ * in hex characters.
+ *
+ * Returns zero on success, -1 on overflow
+ */
+int seq_buf_putmem_hex(struct seq_buf *s, const void *mem,
+ unsigned int len)
+{
+ unsigned char hex[HEX_CHARS];
+ const unsigned char *data = mem;
+ unsigned int start_len;
+ int i, j;
+
+ WARN_ON(s->size == 0);
+
+ while (len) {
+ start_len = min(len, HEX_CHARS - 1);
+#ifdef __BIG_ENDIAN
+ for (i = 0, j = 0; i < start_len; i++) {
+#else
+ for (i = start_len-1, j = 0; i >= 0; i--) {
+#endif
+ hex[j++] = hex_asc_hi(data[i]);
+ hex[j++] = hex_asc_lo(data[i]);
+ }
+ if (WARN_ON_ONCE(j == 0 || j/2 > len))
+ break;
+
+ /* j increments twice per loop */
+ len -= j / 2;
+ hex[j++] = ' ';
+
+ seq_buf_putmem(s, hex, j);
+ if (seq_buf_has_overflowed(s))
+ return -1;
+ }
+ return 0;
+}
+
+/**
+ * seq_buf_path - copy a path into the sequence buffer
+ * @s: seq_buf descriptor
+ * @path: path to write into the sequence buffer.
+ * @esc: set of characters to escape in the output
+ *
+ * Write a path name into the sequence buffer.
+ *
+ * Returns the number of written bytes on success, -1 on overflow
+ */
+int seq_buf_path(struct seq_buf *s, const struct path *path, const char *esc)
+{
+ char *buf;
+ size_t size = seq_buf_get_buf(s, &buf);
+ int res = -1;
+
+ WARN_ON(s->size == 0);
+
+ if (size) {
+ char *p = d_path(path, buf, size);
+ if (!IS_ERR(p)) {
+ char *end = mangle_path(buf, p, esc);
+ if (end)
+ res = end - buf;
+ }
+ }
+ seq_buf_commit(s, res);
+
+ return res;
+}
+
+/**
+ * seq_buf_to_user - copy the squence buffer to user space
+ * @s: seq_buf descriptor
+ * @ubuf: The userspace memory location to copy to
+ * @cnt: The amount to copy
+ *
+ * Copies the sequence buffer into the userspace memory pointed to
+ * by @ubuf. It starts from the last read position (@s->readpos)
+ * and writes up to @cnt characters or till it reaches the end of
+ * the content in the buffer (@s->len), which ever comes first.
+ *
+ * On success, it returns a positive number of the number of bytes
+ * it copied.
+ *
+ * On failure it returns -EBUSY if all of the content in the
+ * sequence has been already read, which includes nothing in the
+ * sequence (@s->len == @s->readpos).
+ *
+ * Returns -EFAULT if the copy to userspace fails.
+ */
+int seq_buf_to_user(struct seq_buf *s, char __user *ubuf, int cnt)
+{
+ int len;
+ int ret;
+
+ if (!cnt)
+ return 0;
+
+ if (s->len <= s->readpos)
+ return -EBUSY;
+
+ len = seq_buf_used(s) - s->readpos;
+ if (cnt > len)
+ cnt = len;
+ ret = copy_to_user(ubuf, s->buffer + s->readpos, cnt);
+ if (ret == cnt)
+ return -EFAULT;
+
+ cnt -= ret;
+
+ s->readpos += cnt;
+ return cnt;
+}
diff --git a/mm/Makefile b/mm/Makefile
index 8405eb0..b3c6ce9 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -55,7 +55,9 @@ obj-$(CONFIG_FS_XIP) += filemap_xip.o
obj-$(CONFIG_MIGRATION) += migrate.o
obj-$(CONFIG_QUICKLIST) += quicklist.o
obj-$(CONFIG_TRANSPARENT_HUGEPAGE) += huge_memory.o
-obj-$(CONFIG_MEMCG) += memcontrol.o page_cgroup.o vmpressure.o
+obj-$(CONFIG_PAGE_COUNTER) += page_counter.o
+obj-$(CONFIG_MEMCG) += memcontrol.o vmpressure.o
+obj-$(CONFIG_MEMCG_SWAP) += swap_cgroup.o
obj-$(CONFIG_CGROUP_HUGETLB) += hugetlb_cgroup.o
obj-$(CONFIG_MEMORY_FAILURE) += memory-failure.o
obj-$(CONFIG_HWPOISON_INJECT) += hwpoison-inject.o
diff --git a/mm/cma.c b/mm/cma.c
index fde706e..8e9ec13 100644
--- a/mm/cma.c
+++ b/mm/cma.c
@@ -215,9 +215,21 @@ int __init cma_declare_contiguous(phys_addr_t base,
bool fixed, struct cma **res_cma)
{
phys_addr_t memblock_end = memblock_end_of_DRAM();
- phys_addr_t highmem_start = __pa(high_memory);
+ phys_addr_t highmem_start;
int ret = 0;
+#ifdef CONFIG_X86
+ /*
+ * high_memory isn't direct mapped memory so retrieving its physical
+ * address isn't appropriate. But it would be useful to check the
+ * physical address of the highmem boundary so it's justfiable to get
+ * the physical address from it. On x86 there is a validation check for
+ * this case, so the following workaround is needed to avoid it.
+ */
+ highmem_start = __pa_nodebug(high_memory);
+#else
+ highmem_start = __pa(high_memory);
+#endif
pr_debug("%s(size %pa, base %pa, limit %pa alignment %pa)\n",
__func__, &size, &base, &limit, &alignment);
diff --git a/mm/compaction.c b/mm/compaction.c
index f9792ba..546e571 100644
--- a/mm/compaction.c
+++ b/mm/compaction.c
@@ -41,15 +41,17 @@ static inline void count_compact_events(enum vm_event_item item, long delta)
static unsigned long release_freepages(struct list_head *freelist)
{
struct page *page, *next;
- unsigned long count = 0;
+ unsigned long high_pfn = 0;
list_for_each_entry_safe(page, next, freelist, lru) {
+ unsigned long pfn = page_to_pfn(page);
list_del(&page->lru);
__free_page(page);
- count++;
+ if (pfn > high_pfn)
+ high_pfn = pfn;
}
- return count;
+ return high_pfn;
}
static void map_pages(struct list_head *list)
@@ -195,16 +197,12 @@ static void update_pageblock_skip(struct compact_control *cc,
/* Update where async and sync compaction should restart */
if (migrate_scanner) {
- if (cc->finished_update_migrate)
- return;
if (pfn > zone->compact_cached_migrate_pfn[0])
zone->compact_cached_migrate_pfn[0] = pfn;
if (cc->mode != MIGRATE_ASYNC &&
pfn > zone->compact_cached_migrate_pfn[1])
zone->compact_cached_migrate_pfn[1] = pfn;
} else {
- if (cc->finished_update_free)
- return;
if (pfn < zone->compact_cached_free_pfn)
zone->compact_cached_free_pfn = pfn;
}
@@ -715,7 +713,6 @@ isolate_migratepages_block(struct compact_control *cc, unsigned long low_pfn,
del_page_from_lru_list(page, lruvec, page_lru(page));
isolate_success:
- cc->finished_update_migrate = true;
list_add(&page->lru, migratelist);
cc->nr_migratepages++;
nr_isolated++;
@@ -889,15 +886,6 @@ static void isolate_freepages(struct compact_control *cc)
block_start_pfn - pageblock_nr_pages;
/*
- * Set a flag that we successfully isolated in this pageblock.
- * In the next loop iteration, zone->compact_cached_free_pfn
- * will not be updated and thus it will effectively contain the
- * highest pageblock we isolated pages from.
- */
- if (isolated)
- cc->finished_update_free = true;
-
- /*
* isolate_freepages_block() might have aborted due to async
* compaction being contended
*/
@@ -1086,9 +1074,9 @@ static int compact_finished(struct zone *zone, struct compact_control *cc,
/* Compaction run is not finished if the watermark is not met */
watermark = low_wmark_pages(zone);
- watermark += (1 << cc->order);
- if (!zone_watermark_ok(zone, cc->order, watermark, 0, 0))
+ if (!zone_watermark_ok(zone, cc->order, watermark, cc->classzone_idx,
+ cc->alloc_flags))
return COMPACT_CONTINUE;
/* Direct compactor: Is a suitable page free? */
@@ -1114,7 +1102,8 @@ static int compact_finished(struct zone *zone, struct compact_control *cc,
* COMPACT_PARTIAL - If the allocation would succeed without compaction
* COMPACT_CONTINUE - If compaction should run now
*/
-unsigned long compaction_suitable(struct zone *zone, int order)
+unsigned long compaction_suitable(struct zone *zone, int order,
+ int alloc_flags, int classzone_idx)
{
int fragindex;
unsigned long watermark;
@@ -1126,21 +1115,30 @@ unsigned long compaction_suitable(struct zone *zone, int order)
if (order == -1)
return COMPACT_CONTINUE;
+ watermark = low_wmark_pages(zone);
+ /*
+ * If watermarks for high-order allocation are already met, there
+ * should be no need for compaction at all.
+ */
+ if (zone_watermark_ok(zone, order, watermark, classzone_idx,
+ alloc_flags))
+ return COMPACT_PARTIAL;
+
/*
* Watermarks for order-0 must be met for compaction. Note the 2UL.
* This is because during migration, copies of pages need to be
* allocated and for a short time, the footprint is higher
*/
- watermark = low_wmark_pages(zone) + (2UL << order);
- if (!zone_watermark_ok(zone, 0, watermark, 0, 0))
+ watermark += (2UL << order);
+ if (!zone_watermark_ok(zone, 0, watermark, classzone_idx, alloc_flags))
return COMPACT_SKIPPED;
/*
* fragmentation index determines if allocation failures are due to
* low memory or external fragmentation
*
- * index of -1000 implies allocations might succeed depending on
- * watermarks
+ * index of -1000 would imply allocations might succeed depending on
+ * watermarks, but we already failed the high-order watermark check
* index towards 0 implies failure is due to lack of memory
* index towards 1000 implies failure is due to fragmentation
*
@@ -1150,10 +1148,6 @@ unsigned long compaction_suitable(struct zone *zone, int order)
if (fragindex >= 0 && fragindex <= sysctl_extfrag_threshold)
return COMPACT_SKIPPED;
- if (fragindex == -1000 && zone_watermark_ok(zone, order, watermark,
- 0, 0))
- return COMPACT_PARTIAL;
-
return COMPACT_CONTINUE;
}
@@ -1164,8 +1158,10 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
unsigned long end_pfn = zone_end_pfn(zone);
const int migratetype = gfpflags_to_migratetype(cc->gfp_mask);
const bool sync = cc->mode != MIGRATE_ASYNC;
+ unsigned long last_migrated_pfn = 0;
- ret = compaction_suitable(zone, cc->order);
+ ret = compaction_suitable(zone, cc->order, cc->alloc_flags,
+ cc->classzone_idx);
switch (ret) {
case COMPACT_PARTIAL:
case COMPACT_SKIPPED:
@@ -1208,6 +1204,7 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
while ((ret = compact_finished(zone, cc, migratetype)) ==
COMPACT_CONTINUE) {
int err;
+ unsigned long isolate_start_pfn = cc->migrate_pfn;
switch (isolate_migratepages(zone, cc)) {
case ISOLATE_ABORT:
@@ -1216,7 +1213,12 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
cc->nr_migratepages = 0;
goto out;
case ISOLATE_NONE:
- continue;
+ /*
+ * We haven't isolated and migrated anything, but
+ * there might still be unflushed migrations from
+ * previous cc->order aligned block.
+ */
+ goto check_drain;
case ISOLATE_SUCCESS:
;
}
@@ -1241,12 +1243,61 @@ static int compact_zone(struct zone *zone, struct compact_control *cc)
goto out;
}
}
+
+ /*
+ * Record where we could have freed pages by migration and not
+ * yet flushed them to buddy allocator. We use the pfn that
+ * isolate_migratepages() started from in this loop iteration
+ * - this is the lowest page that could have been isolated and
+ * then freed by migration.
+ */
+ if (!last_migrated_pfn)
+ last_migrated_pfn = isolate_start_pfn;
+
+check_drain:
+ /*
+ * Has the migration scanner moved away from the previous
+ * cc->order aligned block where we migrated from? If yes,
+ * flush the pages that were freed, so that they can merge and
+ * compact_finished() can detect immediately if allocation
+ * would succeed.
+ */
+ if (cc->order > 0 && last_migrated_pfn) {
+ int cpu;
+ unsigned long current_block_start =
+ cc->migrate_pfn & ~((1UL << cc->order) - 1);
+
+ if (last_migrated_pfn < current_block_start) {
+ cpu = get_cpu();
+ lru_add_drain_cpu(cpu);
+ drain_local_pages(zone);
+ put_cpu();
+ /* No more flushing until we migrate again */
+ last_migrated_pfn = 0;
+ }
+ }
+
}
out:
- /* Release free pages and check accounting */
- cc->nr_freepages -= release_freepages(&cc->freepages);
- VM_BUG_ON(cc->nr_freepages != 0);
+ /*
+ * Release free pages and update where the free scanner should restart,
+ * so we don't leave any returned pages behind in the next attempt.
+ */
+ if (cc->nr_freepages > 0) {
+ unsigned long free_pfn = release_freepages(&cc->freepages);
+
+ cc->nr_freepages = 0;
+ VM_BUG_ON(free_pfn == 0);
+ /* The cached pfn is always the first in a pageblock */
+ free_pfn &= ~(pageblock_nr_pages-1);
+ /*
+ * Only go back, not forward. The cached pfn might have been
+ * already reset to zone end in compact_finished()
+ */
+ if (free_pfn > zone->compact_cached_free_pfn)
+ zone->compact_cached_free_pfn = free_pfn;
+ }
trace_mm_compaction_end(ret);
@@ -1254,7 +1305,8 @@ out:
}
static unsigned long compact_zone_order(struct zone *zone, int order,
- gfp_t gfp_mask, enum migrate_mode mode, int *contended)
+ gfp_t gfp_mask, enum migrate_mode mode, int *contended,
+ int alloc_flags, int classzone_idx)
{
unsigned long ret;
struct compact_control cc = {
@@ -1264,6 +1316,8 @@ static unsigned long compact_zone_order(struct zone *zone, int order,
.gfp_mask = gfp_mask,
.zone = zone,
.mode = mode,
+ .alloc_flags = alloc_flags,
+ .classzone_idx = classzone_idx,
};
INIT_LIST_HEAD(&cc.freepages);
INIT_LIST_HEAD(&cc.migratepages);
@@ -1288,14 +1342,13 @@ int sysctl_extfrag_threshold = 500;
* @mode: The migration mode for async, sync light, or sync migration
* @contended: Return value that determines if compaction was aborted due to
* need_resched() or lock contention
- * @candidate_zone: Return the zone where we think allocation should succeed
*
* This is the main entry point for direct page compaction.
*/
unsigned long try_to_compact_pages(struct zonelist *zonelist,
int order, gfp_t gfp_mask, nodemask_t *nodemask,
enum migrate_mode mode, int *contended,
- struct zone **candidate_zone)
+ int alloc_flags, int classzone_idx)
{
enum zone_type high_zoneidx = gfp_zone(gfp_mask);
int may_enter_fs = gfp_mask & __GFP_FS;
@@ -1303,7 +1356,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
struct zoneref *z;
struct zone *zone;
int rc = COMPACT_DEFERRED;
- int alloc_flags = 0;
int all_zones_contended = COMPACT_CONTENDED_LOCK; /* init for &= op */
*contended = COMPACT_CONTENDED_NONE;
@@ -1312,10 +1364,6 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
if (!order || !may_enter_fs || !may_perform_io)
return COMPACT_SKIPPED;
-#ifdef CONFIG_CMA
- if (gfpflags_to_migratetype(gfp_mask) == MIGRATE_MOVABLE)
- alloc_flags |= ALLOC_CMA;
-#endif
/* Compact each zone in the list */
for_each_zone_zonelist_nodemask(zone, z, zonelist, high_zoneidx,
nodemask) {
@@ -1326,7 +1374,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
continue;
status = compact_zone_order(zone, order, gfp_mask, mode,
- &zone_contended);
+ &zone_contended, alloc_flags, classzone_idx);
rc = max(status, rc);
/*
* It takes at least one zone that wasn't lock contended
@@ -1335,9 +1383,8 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
all_zones_contended &= zone_contended;
/* If a normal allocation would succeed, stop compacting */
- if (zone_watermark_ok(zone, order, low_wmark_pages(zone), 0,
- alloc_flags)) {
- *candidate_zone = zone;
+ if (zone_watermark_ok(zone, order, low_wmark_pages(zone),
+ classzone_idx, alloc_flags)) {
/*
* We think the allocation will succeed in this zone,
* but it is not certain, hence the false. The caller
@@ -1359,7 +1406,7 @@ unsigned long try_to_compact_pages(struct zonelist *zonelist,
goto break_loop;
}
- if (mode != MIGRATE_ASYNC) {
+ if (mode != MIGRATE_ASYNC && status == COMPACT_COMPLETE) {
/*
* We think that allocation won't succeed in this zone
* so we defer compaction there. If it ends up
diff --git a/mm/debug.c b/mm/debug.c
index 5ce45c9..0e58f32 100644
--- a/mm/debug.c
+++ b/mm/debug.c
@@ -95,7 +95,10 @@ void dump_page_badflags(struct page *page, const char *reason,
dump_flags(page->flags & badflags,
pageflag_names, ARRAY_SIZE(pageflag_names));
}
- mem_cgroup_print_bad_page(page);
+#ifdef CONFIG_MEMCG
+ if (page->mem_cgroup)
+ pr_alert("page->mem_cgroup:%p\n", page->mem_cgroup);
+#endif
}
void dump_page(struct page *page, const char *reason)
diff --git a/mm/frontswap.c b/mm/frontswap.c
index f2a3571..8d82809 100644
--- a/mm/frontswap.c
+++ b/mm/frontswap.c
@@ -182,7 +182,7 @@ void __frontswap_init(unsigned type, unsigned long *map)
if (frontswap_ops)
frontswap_ops->init(type);
else {
- BUG_ON(type > MAX_SWAPFILES);
+ BUG_ON(type >= MAX_SWAPFILES);
set_bit(type, need_init);
}
}
diff --git a/mm/huge_memory.c b/mm/huge_memory.c
index de98415..5b2c687 100644
--- a/mm/huge_memory.c
+++ b/mm/huge_memory.c
@@ -784,7 +784,6 @@ static bool set_huge_zero_page(pgtable_t pgtable, struct mm_struct *mm,
if (!pmd_none(*pmd))
return false;
entry = mk_pmd(zero_page, vma->vm_page_prot);
- entry = pmd_wrprotect(entry);
entry = pmd_mkhuge(entry);
pgtable_trans_huge_deposit(mm, pmd, pgtable);
set_pmd_at(mm, haddr, pmd, entry);
diff --git a/mm/hugetlb.c b/mm/hugetlb.c
index 9fd7227..30cd968 100644
--- a/mm/hugetlb.c
+++ b/mm/hugetlb.c
@@ -2638,8 +2638,9 @@ void __unmap_hugepage_range(struct mmu_gather *tlb, struct vm_area_struct *vma,
tlb_start_vma(tlb, vma);
mmu_notifier_invalidate_range_start(mm, mmun_start, mmun_end);
+ address = start;
again:
- for (address = start; address < end; address += sz) {
+ for (; address < end; address += sz) {
ptep = huge_pte_offset(mm, address);
if (!ptep)
continue;
@@ -2686,6 +2687,7 @@ again:
page_remove_rmap(page);
force_flush = !__tlb_remove_page(tlb, page);
if (force_flush) {
+ address += sz;
spin_unlock(ptl);
break;
}
diff --git a/mm/hugetlb_cgroup.c b/mm/hugetlb_cgroup.c
index a67c26e..037e1c0 100644
--- a/mm/hugetlb_cgroup.c
+++ b/mm/hugetlb_cgroup.c
@@ -14,6 +14,7 @@
*/
#include <linux/cgroup.h>
+#include <linux/page_counter.h>
#include <linux/slab.h>
#include <linux/hugetlb.h>
#include <linux/hugetlb_cgroup.h>
@@ -23,7 +24,7 @@ struct hugetlb_cgroup {
/*
* the counter to account for hugepages from hugetlb.
*/
- struct res_counter hugepage[HUGE_MAX_HSTATE];
+ struct page_counter hugepage[HUGE_MAX_HSTATE];
};
#define MEMFILE_PRIVATE(x, val) (((x) << 16) | (val))
@@ -60,7 +61,7 @@ static inline bool hugetlb_cgroup_have_usage(struct hugetlb_cgroup *h_cg)
int idx;
for (idx = 0; idx < hugetlb_max_hstate; idx++) {
- if ((res_counter_read_u64(&h_cg->hugepage[idx], RES_USAGE)) > 0)
+ if (page_counter_read(&h_cg->hugepage[idx]))
return true;
}
return false;
@@ -79,12 +80,12 @@ hugetlb_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
if (parent_h_cgroup) {
for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
- res_counter_init(&h_cgroup->hugepage[idx],
- &parent_h_cgroup->hugepage[idx]);
+ page_counter_init(&h_cgroup->hugepage[idx],
+ &parent_h_cgroup->hugepage[idx]);
} else {
root_h_cgroup = h_cgroup;
for (idx = 0; idx < HUGE_MAX_HSTATE; idx++)
- res_counter_init(&h_cgroup->hugepage[idx], NULL);
+ page_counter_init(&h_cgroup->hugepage[idx], NULL);
}
return &h_cgroup->css;
}
@@ -108,9 +109,8 @@ static void hugetlb_cgroup_css_free(struct cgroup_subsys_state *css)
static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg,
struct page *page)
{
- int csize;
- struct res_counter *counter;
- struct res_counter *fail_res;
+ unsigned int nr_pages;
+ struct page_counter *counter;
struct hugetlb_cgroup *page_hcg;
struct hugetlb_cgroup *parent = parent_hugetlb_cgroup(h_cg);
@@ -123,15 +123,15 @@ static void hugetlb_cgroup_move_parent(int idx, struct hugetlb_cgroup *h_cg,
if (!page_hcg || page_hcg != h_cg)
goto out;
- csize = PAGE_SIZE << compound_order(page);
+ nr_pages = 1 << compound_order(page);
if (!parent) {
parent = root_h_cgroup;
/* root has no limit */
- res_counter_charge_nofail(&parent->hugepage[idx],
- csize, &fail_res);
+ page_counter_charge(&parent->hugepage[idx], nr_pages);
}
counter = &h_cg->hugepage[idx];
- res_counter_uncharge_until(counter, counter->parent, csize);
+ /* Take the pages off the local counter */
+ page_counter_cancel(counter, nr_pages);
set_hugetlb_cgroup(page, parent);
out:
@@ -166,9 +166,8 @@ int hugetlb_cgroup_charge_cgroup(int idx, unsigned long nr_pages,
struct hugetlb_cgroup **ptr)
{
int ret = 0;
- struct res_counter *fail_res;
+ struct page_counter *counter;
struct hugetlb_cgroup *h_cg = NULL;
- unsigned long csize = nr_pages * PAGE_SIZE;
if (hugetlb_cgroup_disabled())
goto done;
@@ -187,7 +186,7 @@ again:
}
rcu_read_unlock();
- ret = res_counter_charge(&h_cg->hugepage[idx], csize, &fail_res);
+ ret = page_counter_try_charge(&h_cg->hugepage[idx], nr_pages, &counter);
css_put(&h_cg->css);
done:
*ptr = h_cg;
@@ -213,7 +212,6 @@ void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
struct page *page)
{
struct hugetlb_cgroup *h_cg;
- unsigned long csize = nr_pages * PAGE_SIZE;
if (hugetlb_cgroup_disabled())
return;
@@ -222,61 +220,76 @@ void hugetlb_cgroup_uncharge_page(int idx, unsigned long nr_pages,
if (unlikely(!h_cg))
return;
set_hugetlb_cgroup(page, NULL);
- res_counter_uncharge(&h_cg->hugepage[idx], csize);
+ page_counter_uncharge(&h_cg->hugepage[idx], nr_pages);
return;
}
void hugetlb_cgroup_uncharge_cgroup(int idx, unsigned long nr_pages,
struct hugetlb_cgroup *h_cg)
{
- unsigned long csize = nr_pages * PAGE_SIZE;
-
if (hugetlb_cgroup_disabled() || !h_cg)
return;
if (huge_page_order(&hstates[idx]) < HUGETLB_CGROUP_MIN_ORDER)
return;
- res_counter_uncharge(&h_cg->hugepage[idx], csize);
+ page_counter_uncharge(&h_cg->hugepage[idx], nr_pages);
return;
}
+enum {
+ RES_USAGE,
+ RES_LIMIT,
+ RES_MAX_USAGE,
+ RES_FAILCNT,
+};
+
static u64 hugetlb_cgroup_read_u64(struct cgroup_subsys_state *css,
struct cftype *cft)
{
- int idx, name;
+ struct page_counter *counter;
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(css);
- idx = MEMFILE_IDX(cft->private);
- name = MEMFILE_ATTR(cft->private);
+ counter = &h_cg->hugepage[MEMFILE_IDX(cft->private)];
- return res_counter_read_u64(&h_cg->hugepage[idx], name);
+ switch (MEMFILE_ATTR(cft->private)) {
+ case RES_USAGE:
+ return (u64)page_counter_read(counter) * PAGE_SIZE;
+ case RES_LIMIT:
+ return (u64)counter->limit * PAGE_SIZE;
+ case RES_MAX_USAGE:
+ return (u64)counter->watermark * PAGE_SIZE;
+ case RES_FAILCNT:
+ return counter->failcnt;
+ default:
+ BUG();
+ }
}
+static DEFINE_MUTEX(hugetlb_limit_mutex);
+
static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
- int idx, name, ret;
- unsigned long long val;
+ int ret, idx;
+ unsigned long nr_pages;
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
+ if (hugetlb_cgroup_is_root(h_cg)) /* Can't set limit on root */
+ return -EINVAL;
+
buf = strstrip(buf);
+ ret = page_counter_memparse(buf, &nr_pages);
+ if (ret)
+ return ret;
+
idx = MEMFILE_IDX(of_cft(of)->private);
- name = MEMFILE_ATTR(of_cft(of)->private);
- switch (name) {
+ switch (MEMFILE_ATTR(of_cft(of)->private)) {
case RES_LIMIT:
- if (hugetlb_cgroup_is_root(h_cg)) {
- /* Can't set limit on root */
- ret = -EINVAL;
- break;
- }
- /* This function does all necessary parse...reuse it */
- ret = res_counter_memparse_write_strategy(buf, &val);
- if (ret)
- break;
- val = ALIGN(val, 1ULL << huge_page_shift(&hstates[idx]));
- ret = res_counter_set_limit(&h_cg->hugepage[idx], val);
+ mutex_lock(&hugetlb_limit_mutex);
+ ret = page_counter_limit(&h_cg->hugepage[idx], nr_pages);
+ mutex_unlock(&hugetlb_limit_mutex);
break;
default:
ret = -EINVAL;
@@ -288,18 +301,18 @@ static ssize_t hugetlb_cgroup_write(struct kernfs_open_file *of,
static ssize_t hugetlb_cgroup_reset(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
- int idx, name, ret = 0;
+ int ret = 0;
+ struct page_counter *counter;
struct hugetlb_cgroup *h_cg = hugetlb_cgroup_from_css(of_css(of));
- idx = MEMFILE_IDX(of_cft(of)->private);
- name = MEMFILE_ATTR(of_cft(of)->private);
+ counter = &h_cg->hugepage[MEMFILE_IDX(of_cft(of)->private)];
- switch (name) {
+ switch (MEMFILE_ATTR(of_cft(of)->private)) {
case RES_MAX_USAGE:
- res_counter_reset_max(&h_cg->hugepage[idx]);
+ page_counter_reset_watermark(counter);
break;
case RES_FAILCNT:
- res_counter_reset_failcnt(&h_cg->hugepage[idx]);
+ counter->failcnt = 0;
break;
default:
ret = -EINVAL;
diff --git a/mm/internal.h b/mm/internal.h
index a4f90ba..efad241 100644
--- a/mm/internal.h
+++ b/mm/internal.h
@@ -161,13 +161,10 @@ struct compact_control {
unsigned long migrate_pfn; /* isolate_migratepages search base */
enum migrate_mode mode; /* Async or sync migration mode */
bool ignore_skip_hint; /* Scan blocks even if marked skip */
- bool finished_update_free; /* True when the zone cached pfns are
- * no longer being updated
- */
- bool finished_update_migrate;
-
int order; /* order a direct compactor needs */
const gfp_t gfp_mask; /* gfp mask of a direct compactor */
+ const int alloc_flags; /* alloc flags of a direct compactor */
+ const int classzone_idx; /* zone index of a direct compactor */
struct zone *zone;
int contended; /* Signal need_sched() or lock
* contention detected during
diff --git a/mm/memcontrol.c b/mm/memcontrol.c
index d6ac0e3..85df503 100644
--- a/mm/memcontrol.c
+++ b/mm/memcontrol.c
@@ -25,7 +25,7 @@
* GNU General Public License for more details.
*/
-#include <linux/res_counter.h>
+#include <linux/page_counter.h>
#include <linux/memcontrol.h>
#include <linux/cgroup.h>
#include <linux/mm.h>
@@ -51,7 +51,7 @@
#include <linux/seq_file.h>
#include <linux/vmpressure.h>
#include <linux/mm_inline.h>
-#include <linux/page_cgroup.h>
+#include <linux/swap_cgroup.h>
#include <linux/cpu.h>
#include <linux/oom.h>
#include <linux/lockdep.h>
@@ -143,14 +143,8 @@ struct mem_cgroup_stat_cpu {
unsigned long targets[MEM_CGROUP_NTARGETS];
};
-struct mem_cgroup_reclaim_iter {
- /*
- * last scanned hierarchy member. Valid only if last_dead_count
- * matches memcg->dead_count of the hierarchy root group.
- */
- struct mem_cgroup *last_visited;
- int last_dead_count;
-
+struct reclaim_iter {
+ struct mem_cgroup *position;
/* scan generation, increased every round-trip */
unsigned int generation;
};
@@ -162,10 +156,10 @@ struct mem_cgroup_per_zone {
struct lruvec lruvec;
unsigned long lru_size[NR_LRU_LISTS];
- struct mem_cgroup_reclaim_iter reclaim_iter[DEF_PRIORITY + 1];
+ struct reclaim_iter iter[DEF_PRIORITY + 1];
struct rb_node tree_node; /* RB tree node */
- unsigned long long usage_in_excess;/* Set to the value by which */
+ unsigned long usage_in_excess;/* Set to the value by which */
/* the soft limit is exceeded*/
bool on_tree;
struct mem_cgroup *memcg; /* Back pointer, we cannot */
@@ -198,7 +192,7 @@ static struct mem_cgroup_tree soft_limit_tree __read_mostly;
struct mem_cgroup_threshold {
struct eventfd_ctx *eventfd;
- u64 threshold;
+ unsigned long threshold;
};
/* For threshold */
@@ -284,10 +278,13 @@ static void mem_cgroup_oom_notify(struct mem_cgroup *memcg);
*/
struct mem_cgroup {
struct cgroup_subsys_state css;
- /*
- * the counter to account for memory usage
- */
- struct res_counter res;
+
+ /* Accounted resources */
+ struct page_counter memory;
+ struct page_counter memsw;
+ struct page_counter kmem;
+
+ unsigned long soft_limit;
/* vmpressure notifications */
struct vmpressure vmpressure;
@@ -296,15 +293,6 @@ struct mem_cgroup {
int initialized;
/*
- * the counter to account for mem+swap usage.
- */
- struct res_counter memsw;
-
- /*
- * the counter to account for kernel memory usage.
- */
- struct res_counter kmem;
- /*
* Should the accounting and control be hierarchical, per subtree?
*/
bool use_hierarchy;
@@ -352,7 +340,6 @@ struct mem_cgroup {
struct mem_cgroup_stat_cpu nocpu_base;
spinlock_t pcp_counter_lock;
- atomic_t dead_count;
#if defined(CONFIG_MEMCG_KMEM) && defined(CONFIG_INET)
struct cg_proto tcp_mem;
#endif
@@ -382,7 +369,6 @@ struct mem_cgroup {
/* internal only representation about the status of kmem accounting. */
enum {
KMEM_ACCOUNTED_ACTIVE, /* accounted by this cgroup itself */
- KMEM_ACCOUNTED_DEAD, /* dead memcg with pending kmem charges */
};
#ifdef CONFIG_MEMCG_KMEM
@@ -396,22 +382,6 @@ static bool memcg_kmem_is_active(struct mem_cgroup *memcg)
return test_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags);
}
-static void memcg_kmem_mark_dead(struct mem_cgroup *memcg)
-{
- /*
- * Our caller must use css_get() first, because memcg_uncharge_kmem()
- * will call css_put() if it sees the memcg is dead.
- */
- smp_wmb();
- if (test_bit(KMEM_ACCOUNTED_ACTIVE, &memcg->kmem_account_flags))
- set_bit(KMEM_ACCOUNTED_DEAD, &memcg->kmem_account_flags);
-}
-
-static bool memcg_kmem_test_and_clear_dead(struct mem_cgroup *memcg)
-{
- return test_and_clear_bit(KMEM_ACCOUNTED_DEAD,
- &memcg->kmem_account_flags);
-}
#endif
/* Stuffs for move charges at task migration. */
@@ -650,7 +620,7 @@ static void disarm_kmem_keys(struct mem_cgroup *memcg)
* This check can't live in kmem destruction function,
* since the charges will outlive the cgroup
*/
- WARN_ON(res_counter_read_u64(&memcg->kmem, RES_USAGE) != 0);
+ WARN_ON(page_counter_read(&memcg->kmem));
}
#else
static void disarm_kmem_keys(struct mem_cgroup *memcg)
@@ -664,8 +634,6 @@ static void disarm_static_keys(struct mem_cgroup *memcg)
disarm_kmem_keys(memcg);
}
-static void drain_all_stock_async(struct mem_cgroup *memcg);
-
static struct mem_cgroup_per_zone *
mem_cgroup_zone_zoneinfo(struct mem_cgroup *memcg, struct zone *zone)
{
@@ -706,7 +674,7 @@ soft_limit_tree_from_page(struct page *page)
static void __mem_cgroup_insert_exceeded(struct mem_cgroup_per_zone *mz,
struct mem_cgroup_tree_per_zone *mctz,
- unsigned long long new_usage_in_excess)
+ unsigned long new_usage_in_excess)
{
struct rb_node **p = &mctz->rb_root.rb_node;
struct rb_node *parent = NULL;
@@ -755,10 +723,21 @@ static void mem_cgroup_remove_exceeded(struct mem_cgroup_per_zone *mz,
spin_unlock_irqrestore(&mctz->lock, flags);
}
+static unsigned long soft_limit_excess(struct mem_cgroup *memcg)
+{
+ unsigned long nr_pages = page_counter_read(&memcg->memory);
+ unsigned long soft_limit = ACCESS_ONCE(memcg->soft_limit);
+ unsigned long excess = 0;
+
+ if (nr_pages > soft_limit)
+ excess = nr_pages - soft_limit;
+
+ return excess;
+}
static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
{
- unsigned long long excess;
+ unsigned long excess;
struct mem_cgroup_per_zone *mz;
struct mem_cgroup_tree_per_zone *mctz;
@@ -769,7 +748,7 @@ static void mem_cgroup_update_tree(struct mem_cgroup *memcg, struct page *page)
*/
for (; memcg; memcg = parent_mem_cgroup(memcg)) {
mz = mem_cgroup_page_zoneinfo(memcg, page);
- excess = res_counter_soft_limit_excess(&memcg->res);
+ excess = soft_limit_excess(memcg);
/*
* We have to update the tree if mz is on RB-tree or
* mem is over its softlimit.
@@ -825,7 +804,7 @@ retry:
* position in the tree.
*/
__mem_cgroup_remove_exceeded(mz, mctz);
- if (!res_counter_soft_limit_excess(&mz->memcg->res) ||
+ if (!soft_limit_excess(mz->memcg) ||
!css_tryget_online(&mz->memcg->css))
goto retry;
done:
@@ -1062,122 +1041,6 @@ static struct mem_cgroup *get_mem_cgroup_from_mm(struct mm_struct *mm)
return memcg;
}
-/*
- * Returns a next (in a pre-order walk) alive memcg (with elevated css
- * ref. count) or NULL if the whole root's subtree has been visited.
- *
- * helper function to be used by mem_cgroup_iter
- */
-static struct mem_cgroup *__mem_cgroup_iter_next(struct mem_cgroup *root,
- struct mem_cgroup *last_visited)
-{
- struct cgroup_subsys_state *prev_css, *next_css;
-
- prev_css = last_visited ? &last_visited->css : NULL;
-skip_node:
- next_css = css_next_descendant_pre(prev_css, &root->css);
-
- /*
- * Even if we found a group we have to make sure it is
- * alive. css && !memcg means that the groups should be
- * skipped and we should continue the tree walk.
- * last_visited css is safe to use because it is
- * protected by css_get and the tree walk is rcu safe.
- *
- * We do not take a reference on the root of the tree walk
- * because we might race with the root removal when it would
- * be the only node in the iterated hierarchy and mem_cgroup_iter
- * would end up in an endless loop because it expects that at
- * least one valid node will be returned. Root cannot disappear
- * because caller of the iterator should hold it already so
- * skipping css reference should be safe.
- */
- if (next_css) {
- struct mem_cgroup *memcg = mem_cgroup_from_css(next_css);
-
- if (next_css == &root->css)
- return memcg;
-
- if (css_tryget_online(next_css)) {
- /*
- * Make sure the memcg is initialized:
- * mem_cgroup_css_online() orders the the
- * initialization against setting the flag.
- */
- if (smp_load_acquire(&memcg->initialized))
- return memcg;
- css_put(next_css);
- }
-
- prev_css = next_css;
- goto skip_node;
- }
-
- return NULL;
-}
-
-static void mem_cgroup_iter_invalidate(struct mem_cgroup *root)
-{
- /*
- * When a group in the hierarchy below root is destroyed, the
- * hierarchy iterator can no longer be trusted since it might
- * have pointed to the destroyed group. Invalidate it.
- */
- atomic_inc(&root->dead_count);
-}
-
-static struct mem_cgroup *
-mem_cgroup_iter_load(struct mem_cgroup_reclaim_iter *iter,
- struct mem_cgroup *root,
- int *sequence)
-{
- struct mem_cgroup *position = NULL;
- /*
- * A cgroup destruction happens in two stages: offlining and
- * release. They are separated by a RCU grace period.
- *
- * If the iterator is valid, we may still race with an
- * offlining. The RCU lock ensures the object won't be
- * released, tryget will fail if we lost the race.
- */
- *sequence = atomic_read(&root->dead_count);
- if (iter->last_dead_count == *sequence) {
- smp_rmb();
- position = iter->last_visited;
-
- /*
- * We cannot take a reference to root because we might race
- * with root removal and returning NULL would end up in
- * an endless loop on the iterator user level when root
- * would be returned all the time.
- */
- if (position && position != root &&
- !css_tryget_online(&position->css))
- position = NULL;
- }
- return position;
-}
-
-static void mem_cgroup_iter_update(struct mem_cgroup_reclaim_iter *iter,
- struct mem_cgroup *last_visited,
- struct mem_cgroup *new_position,
- struct mem_cgroup *root,
- int sequence)
-{
- /* root reference counting symmetric to mem_cgroup_iter_load */
- if (last_visited && last_visited != root)
- css_put(&last_visited->css);
- /*
- * We store the sequence count from the time @last_visited was
- * loaded successfully instead of rereading it here so that we
- * don't lose destruction events in between. We could have
- * raced with the destruction of @new_position after all.
- */
- iter->last_visited = new_position;
- smp_wmb();
- iter->last_dead_count = sequence;
-}
-
/**
* mem_cgroup_iter - iterate over memory cgroup hierarchy
* @root: hierarchy root
@@ -1199,8 +1062,10 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
struct mem_cgroup *prev,
struct mem_cgroup_reclaim_cookie *reclaim)
{
+ struct reclaim_iter *uninitialized_var(iter);
+ struct cgroup_subsys_state *css = NULL;
struct mem_cgroup *memcg = NULL;
- struct mem_cgroup *last_visited = NULL;
+ struct mem_cgroup *pos = NULL;
if (mem_cgroup_disabled())
return NULL;
@@ -1209,50 +1074,101 @@ struct mem_cgroup *mem_cgroup_iter(struct mem_cgroup *root,
root = root_mem_cgroup;
if (prev && !reclaim)
- last_visited = prev;
+ pos = prev;
if (!root->use_hierarchy && root != root_mem_cgroup) {
if (prev)
- goto out_css_put;
+ goto out;
return root;
}
rcu_read_lock();
- while (!memcg) {
- struct mem_cgroup_reclaim_iter *uninitialized_var(iter);
- int uninitialized_var(seq);
-
- if (reclaim) {
- struct mem_cgroup_per_zone *mz;
-
- mz = mem_cgroup_zone_zoneinfo(root, reclaim->zone);
- iter = &mz->reclaim_iter[reclaim->priority];
- if (prev && reclaim->generation != iter->generation) {
- iter->last_visited = NULL;
- goto out_unlock;
- }
- last_visited = mem_cgroup_iter_load(iter, root, &seq);
+ if (reclaim) {
+ struct mem_cgroup_per_zone *mz;
+
+ mz = mem_cgroup_zone_zoneinfo(root, reclaim->zone);
+ iter = &mz->iter[reclaim->priority];
+
+ if (prev && reclaim->generation != iter->generation)
+ goto out_unlock;
+
+ do {
+ pos = ACCESS_ONCE(iter->position);
+ /*
+ * A racing update may change the position and
+ * put the last reference, hence css_tryget(),
+ * or retry to see the updated position.
+ */
+ } while (pos && !css_tryget(&pos->css));
+ }
+
+ if (pos)
+ css = &pos->css;
+
+ for (;;) {
+ css = css_next_descendant_pre(css, &root->css);
+ if (!css) {
+ /*
+ * Reclaimers share the hierarchy walk, and a
+ * new one might jump in right at the end of
+ * the hierarchy - make sure they see at least
+ * one group and restart from the beginning.
+ */
+ if (!prev)
+ continue;
+ break;
}
- memcg = __mem_cgroup_iter_next(root, last_visited);
+ /*
+ * Verify the css and acquire a reference. The root
+ * is provided by the caller, so we know it's alive
+ * and kicking, and don't take an extra reference.
+ */
+ memcg = mem_cgroup_from_css(css);
+
+ if (css == &root->css)
+ break;
- if (reclaim) {
- mem_cgroup_iter_update(iter, last_visited, memcg, root,
- seq);
+ if (css_tryget(css)) {
+ /*
+ * Make sure the memcg is initialized:
+ * mem_cgroup_css_online() orders the the
+ * initialization against setting the flag.
+ */
+ if (smp_load_acquire(&memcg->initialized))
+ break;
- if (!memcg)
- iter->generation++;
- else if (!prev && memcg)
- reclaim->generation = iter->generation;
+ css_put(css);
}
- if (prev && !memcg)
- goto out_unlock;
+ memcg = NULL;
+ }
+
+ if (reclaim) {
+ if (cmpxchg(&iter->position, pos, memcg) == pos) {
+ if (memcg)
+ css_get(&memcg->css);
+ if (pos)
+ css_put(&pos->css);
+ }
+
+ /*
+ * pairs with css_tryget when dereferencing iter->position
+ * above.
+ */
+ if (pos)
+ css_put(&pos->css);
+
+ if (!memcg)
+ iter->generation++;
+ else if (!prev)
+ reclaim->generation = iter->generation;
}
+
out_unlock:
rcu_read_unlock();
-out_css_put:
+out:
if (prev && prev != root)
css_put(&prev->css);
@@ -1346,15 +1262,18 @@ out:
}
/**
- * mem_cgroup_page_lruvec - return lruvec for adding an lru page
+ * mem_cgroup_page_lruvec - return lruvec for isolating/putting an LRU page
* @page: the page
* @zone: zone of the page
+ *
+ * This function is only safe when following the LRU page isolation
+ * and putback protocol: the LRU lock must be held, and the page must
+ * either be PageLRU() or the caller must have isolated/allocated it.
*/
struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
{
struct mem_cgroup_per_zone *mz;
struct mem_cgroup *memcg;
- struct page_cgroup *pc;
struct lruvec *lruvec;
if (mem_cgroup_disabled()) {
@@ -1362,20 +1281,13 @@ struct lruvec *mem_cgroup_page_lruvec(struct page *page, struct zone *zone)
goto out;
}
- pc = lookup_page_cgroup(page);
- memcg = pc->mem_cgroup;
-
+ memcg = page->mem_cgroup;
/*
- * Surreptitiously switch any uncharged offlist page to root:
- * an uncharged page off lru does nothing to secure
- * its former mem_cgroup from sudden removal.
- *
- * Our caller holds lru_lock, and PageCgroupUsed is updated
- * under page_cgroup lock: between them, they make all uses
- * of pc->mem_cgroup safe.
+ * Swapcache readahead pages are added to the LRU - and
+ * possibly migrated - before they are charged.
*/
- if (!PageLRU(page) && !PageCgroupUsed(pc) && memcg != root_mem_cgroup)
- pc->mem_cgroup = memcg = root_mem_cgroup;
+ if (!memcg)
+ memcg = root_mem_cgroup;
mz = mem_cgroup_page_zoneinfo(memcg, page);
lruvec = &mz->lruvec;
@@ -1414,41 +1326,24 @@ void mem_cgroup_update_lru_size(struct lruvec *lruvec, enum lru_list lru,
VM_BUG_ON((long)(*lru_size) < 0);
}
-/*
- * Checks whether given mem is same or in the root_mem_cgroup's
- * hierarchy subtree
- */
-bool __mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
- struct mem_cgroup *memcg)
+bool mem_cgroup_is_descendant(struct mem_cgroup *memcg, struct mem_cgroup *root)
{
- if (root_memcg == memcg)
+ if (root == memcg)
return true;
- if (!root_memcg->use_hierarchy || !memcg)
+ if (!root->use_hierarchy)
return false;
- return cgroup_is_descendant(memcg->css.cgroup, root_memcg->css.cgroup);
-}
-
-static bool mem_cgroup_same_or_subtree(const struct mem_cgroup *root_memcg,
- struct mem_cgroup *memcg)
-{
- bool ret;
-
- rcu_read_lock();
- ret = __mem_cgroup_same_or_subtree(root_memcg, memcg);
- rcu_read_unlock();
- return ret;
+ return cgroup_is_descendant(memcg->css.cgroup, root->css.cgroup);
}
-bool task_in_mem_cgroup(struct task_struct *task,
- const struct mem_cgroup *memcg)
+bool task_in_mem_cgroup(struct task_struct *task, struct mem_cgroup *memcg)
{
- struct mem_cgroup *curr = NULL;
+ struct mem_cgroup *task_memcg;
struct task_struct *p;
bool ret;
p = find_lock_task_mm(task);
if (p) {
- curr = get_mem_cgroup_from_mm(p->mm);
+ task_memcg = get_mem_cgroup_from_mm(p->mm);
task_unlock(p);
} else {
/*
@@ -1457,19 +1352,12 @@ bool task_in_mem_cgroup(struct task_struct *task,
* killed to prevent needlessly killing additional tasks.
*/
rcu_read_lock();
- curr = mem_cgroup_from_task(task);
- if (curr)
- css_get(&curr->css);
+ task_memcg = mem_cgroup_from_task(task);
+ css_get(&task_memcg->css);
rcu_read_unlock();
}
- /*
- * We should check use_hierarchy of "memcg" not "curr". Because checking
- * use_hierarchy of "curr" here make this function true if hierarchy is
- * enabled in "curr" and "curr" is a child of "memcg" in *cgroup*
- * hierarchy(even if use_hierarchy is disabled in "memcg").
- */
- ret = mem_cgroup_same_or_subtree(memcg, curr);
- css_put(&curr->css);
+ ret = mem_cgroup_is_descendant(task_memcg, memcg);
+ css_put(&task_memcg->css);
return ret;
}
@@ -1492,7 +1380,7 @@ int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec)
return inactive * inactive_ratio < active;
}
-#define mem_cgroup_from_res_counter(counter, member) \
+#define mem_cgroup_from_counter(counter, member) \
container_of(counter, struct mem_cgroup, member)
/**
@@ -1504,12 +1392,23 @@ int mem_cgroup_inactive_anon_is_low(struct lruvec *lruvec)
*/
static unsigned long mem_cgroup_margin(struct mem_cgroup *memcg)
{
- unsigned long long margin;
+ unsigned long margin = 0;
+ unsigned long count;
+ unsigned long limit;
- margin = res_counter_margin(&memcg->res);
- if (do_swap_account)
- margin = min(margin, res_counter_margin(&memcg->memsw));
- return margin >> PAGE_SHIFT;
+ count = page_counter_read(&memcg->memory);
+ limit = ACCESS_ONCE(memcg->memory.limit);
+ if (count < limit)
+ margin = limit - count;
+
+ if (do_swap_account) {
+ count = page_counter_read(&memcg->memsw);
+ limit = ACCESS_ONCE(memcg->memsw.limit);
+ if (count <= limit)
+ margin = min(margin, limit - count);
+ }
+
+ return margin;
}
int mem_cgroup_swappiness(struct mem_cgroup *memcg)
@@ -1522,37 +1421,6 @@ int mem_cgroup_swappiness(struct mem_cgroup *memcg)
}
/*
- * memcg->moving_account is used for checking possibility that some thread is
- * calling move_account(). When a thread on CPU-A starts moving pages under
- * a memcg, other threads should check memcg->moving_account under
- * rcu_read_lock(), like this:
- *
- * CPU-A CPU-B
- * rcu_read_lock()
- * memcg->moving_account+1 if (memcg->mocing_account)
- * take heavy locks.
- * synchronize_rcu() update something.
- * rcu_read_unlock()
- * start move here.
- */
-
-static void mem_cgroup_start_move(struct mem_cgroup *memcg)
-{
- atomic_inc(&memcg->moving_account);
- synchronize_rcu();
-}
-
-static void mem_cgroup_end_move(struct mem_cgroup *memcg)
-{
- /*
- * Now, mem_cgroup_clear_mc() may call this function with NULL.
- * We check NULL in callee rather than caller.
- */
- if (memcg)
- atomic_dec(&memcg->moving_account);
-}
-
-/*
* A routine for checking "mem" is under move_account() or not.
*
* Checking a cgroup is mc.from or mc.to or under hierarchy of
@@ -1574,8 +1442,8 @@ static bool mem_cgroup_under_move(struct mem_cgroup *memcg)
if (!from)
goto unlock;
- ret = mem_cgroup_same_or_subtree(memcg, from)
- || mem_cgroup_same_or_subtree(memcg, to);
+ ret = mem_cgroup_is_descendant(from, memcg) ||
+ mem_cgroup_is_descendant(to, memcg);
unlock:
spin_unlock(&mc.lock);
return ret;
@@ -1597,23 +1465,6 @@ static bool mem_cgroup_wait_acct_move(struct mem_cgroup *memcg)
return false;
}
-/*
- * Take this lock when
- * - a code tries to modify page's memcg while it's USED.
- * - a code tries to modify page state accounting in a memcg.
- */
-static void move_lock_mem_cgroup(struct mem_cgroup *memcg,
- unsigned long *flags)
-{
- spin_lock_irqsave(&memcg->move_lock, *flags);
-}
-
-static void move_unlock_mem_cgroup(struct mem_cgroup *memcg,
- unsigned long *flags)
-{
- spin_unlock_irqrestore(&memcg->move_lock, *flags);
-}
-
#define K(x) ((x) << (PAGE_SHIFT-10))
/**
* mem_cgroup_print_oom_info: Print OOM information relevant to memory controller.
@@ -1644,18 +1495,15 @@ void mem_cgroup_print_oom_info(struct mem_cgroup *memcg, struct task_struct *p)
rcu_read_unlock();
- pr_info("memory: usage %llukB, limit %llukB, failcnt %llu\n",
- res_counter_read_u64(&memcg->res, RES_USAGE) >> 10,
- res_counter_read_u64(&memcg->res, RES_LIMIT) >> 10,
- res_counter_read_u64(&memcg->res, RES_FAILCNT));
- pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %llu\n",
- res_counter_read_u64(&memcg->memsw, RES_USAGE) >> 10,
- res_counter_read_u64(&memcg->memsw, RES_LIMIT) >> 10,
- res_counter_read_u64(&memcg->memsw, RES_FAILCNT));
- pr_info("kmem: usage %llukB, limit %llukB, failcnt %llu\n",
- res_counter_read_u64(&memcg->kmem, RES_USAGE) >> 10,
- res_counter_read_u64(&memcg->kmem, RES_LIMIT) >> 10,
- res_counter_read_u64(&memcg->kmem, RES_FAILCNT));
+ pr_info("memory: usage %llukB, limit %llukB, failcnt %lu\n",
+ K((u64)page_counter_read(&memcg->memory)),
+ K((u64)memcg->memory.limit), memcg->memory.failcnt);
+ pr_info("memory+swap: usage %llukB, limit %llukB, failcnt %lu\n",
+ K((u64)page_counter_read(&memcg->memsw)),
+ K((u64)memcg->memsw.limit), memcg->memsw.failcnt);
+ pr_info("kmem: usage %llukB, limit %llukB, failcnt %lu\n",
+ K((u64)page_counter_read(&memcg->kmem)),
+ K((u64)memcg->kmem.limit), memcg->kmem.failcnt);
for_each_mem_cgroup_tree(iter, memcg) {
pr_info("Memory cgroup stats for ");
@@ -1695,28 +1543,17 @@ static int mem_cgroup_count_children(struct mem_cgroup *memcg)
/*
* Return the memory (and swap, if configured) limit for a memcg.
*/
-static u64 mem_cgroup_get_limit(struct mem_cgroup *memcg)
+static unsigned long mem_cgroup_get_limit(struct mem_cgroup *memcg)
{
- u64 limit;
-
- limit = res_counter_read_u64(&memcg->res, RES_LIMIT);
+ unsigned long limit;
- /*
- * Do not consider swap space if we cannot swap due to swappiness
- */
+ limit = memcg->memory.limit;
if (mem_cgroup_swappiness(memcg)) {
- u64 memsw;
+ unsigned long memsw_limit;
- limit += total_swap_pages << PAGE_SHIFT;
- memsw = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
-
- /*
- * If memsw is finite and limits the amount of swap space
- * available to this memcg, return that limit.
- */
- limit = min(limit, memsw);
+ memsw_limit = memcg->memsw.limit;
+ limit = min(limit + total_swap_pages, memsw_limit);
}
-
return limit;
}
@@ -1740,7 +1577,7 @@ static void mem_cgroup_out_of_memory(struct mem_cgroup *memcg, gfp_t gfp_mask,
}
check_panic_on_oom(CONSTRAINT_MEMCG, gfp_mask, order, NULL);
- totalpages = mem_cgroup_get_limit(memcg) >> PAGE_SHIFT ? : 1;
+ totalpages = mem_cgroup_get_limit(memcg) ? : 1;
for_each_mem_cgroup_tree(iter, memcg) {
struct css_task_iter it;
struct task_struct *task;
@@ -1880,52 +1717,11 @@ int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
memcg->last_scanned_node = node;
return node;
}
-
-/*
- * Check all nodes whether it contains reclaimable pages or not.
- * For quick scan, we make use of scan_nodes. This will allow us to skip
- * unused nodes. But scan_nodes is lazily updated and may not cotain
- * enough new information. We need to do double check.
- */
-static bool mem_cgroup_reclaimable(struct mem_cgroup *memcg, bool noswap)
-{
- int nid;
-
- /*
- * quick check...making use of scan_node.
- * We can skip unused nodes.
- */
- if (!nodes_empty(memcg->scan_nodes)) {
- for (nid = first_node(memcg->scan_nodes);
- nid < MAX_NUMNODES;
- nid = next_node(nid, memcg->scan_nodes)) {
-
- if (test_mem_cgroup_node_reclaimable(memcg, nid, noswap))
- return true;
- }
- }
- /*
- * Check rest of nodes.
- */
- for_each_node_state(nid, N_MEMORY) {
- if (node_isset(nid, memcg->scan_nodes))
- continue;
- if (test_mem_cgroup_node_reclaimable(memcg, nid, noswap))
- return true;
- }
- return false;
-}
-
#else
int mem_cgroup_select_victim_node(struct mem_cgroup *memcg)
{
return 0;
}
-
-static bool mem_cgroup_reclaimable(struct mem_cgroup *memcg, bool noswap)
-{
- return test_mem_cgroup_node_reclaimable(memcg, 0, noswap);
-}
#endif
static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
@@ -1943,7 +1739,7 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
.priority = 0,
};
- excess = res_counter_soft_limit_excess(&root_memcg->res) >> PAGE_SHIFT;
+ excess = soft_limit_excess(root_memcg);
while (1) {
victim = mem_cgroup_iter(root_memcg, victim, &reclaim);
@@ -1969,12 +1765,10 @@ static int mem_cgroup_soft_reclaim(struct mem_cgroup *root_memcg,
}
continue;
}
- if (!mem_cgroup_reclaimable(victim, false))
- continue;
total += mem_cgroup_shrink_node_zone(victim, gfp_mask, false,
zone, &nr_scanned);
*total_scanned += nr_scanned;
- if (!res_counter_soft_limit_excess(&root_memcg->res))
+ if (!soft_limit_excess(root_memcg))
break;
}
mem_cgroup_iter_break(root_memcg, victim);
@@ -2081,12 +1875,8 @@ static int memcg_oom_wake_function(wait_queue_t *wait,
oom_wait_info = container_of(wait, struct oom_wait_info, wait);
oom_wait_memcg = oom_wait_info->memcg;
- /*
- * Both of oom_wait_info->memcg and wake_memcg are stable under us.
- * Then we can use css_is_ancestor without taking care of RCU.
- */
- if (!mem_cgroup_same_or_subtree(oom_wait_memcg, wake_memcg)
- && !mem_cgroup_same_or_subtree(wake_memcg, oom_wait_memcg))
+ if (!mem_cgroup_is_descendant(wake_memcg, oom_wait_memcg) &&
+ !mem_cgroup_is_descendant(oom_wait_memcg, wake_memcg))
return 0;
return autoremove_wake_function(wait, mode, sync, arg);
}
@@ -2228,26 +2018,23 @@ struct mem_cgroup *mem_cgroup_begin_page_stat(struct page *page,
unsigned long *flags)
{
struct mem_cgroup *memcg;
- struct page_cgroup *pc;
rcu_read_lock();
if (mem_cgroup_disabled())
return NULL;
-
- pc = lookup_page_cgroup(page);
again:
- memcg = pc->mem_cgroup;
- if (unlikely(!memcg || !PageCgroupUsed(pc)))
+ memcg = page->mem_cgroup;
+ if (unlikely(!memcg))
return NULL;
*locked = false;
if (atomic_read(&memcg->moving_account) <= 0)
return memcg;
- move_lock_mem_cgroup(memcg, flags);
- if (memcg != pc->mem_cgroup || !PageCgroupUsed(pc)) {
- move_unlock_mem_cgroup(memcg, flags);
+ spin_lock_irqsave(&memcg->move_lock, *flags);
+ if (memcg != page->mem_cgroup) {
+ spin_unlock_irqrestore(&memcg->move_lock, *flags);
goto again;
}
*locked = true;
@@ -2261,11 +2048,11 @@ again:
* @locked: value received from mem_cgroup_begin_page_stat()
* @flags: value received from mem_cgroup_begin_page_stat()
*/
-void mem_cgroup_end_page_stat(struct mem_cgroup *memcg, bool locked,
- unsigned long flags)
+void mem_cgroup_end_page_stat(struct mem_cgroup *memcg, bool *locked,
+ unsigned long *flags)
{
- if (memcg && locked)
- move_unlock_mem_cgroup(memcg, &flags);
+ if (memcg && *locked)
+ spin_unlock_irqrestore(&memcg->move_lock, *flags);
rcu_read_unlock();
}
@@ -2316,33 +2103,32 @@ static DEFINE_MUTEX(percpu_charge_mutex);
static bool consume_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
{
struct memcg_stock_pcp *stock;
- bool ret = true;
+ bool ret = false;
if (nr_pages > CHARGE_BATCH)
- return false;
+ return ret;
stock = &get_cpu_var(memcg_stock);
- if (memcg == stock->cached && stock->nr_pages >= nr_pages)
+ if (memcg == stock->cached && stock->nr_pages >= nr_pages) {
stock->nr_pages -= nr_pages;
- else /* need to call res_counter_charge */
- ret = false;
+ ret = true;
+ }
put_cpu_var(memcg_stock);
return ret;
}
/*
- * Returns stocks cached in percpu to res_counter and reset cached information.
+ * Returns stocks cached in percpu and reset cached information.
*/
static void drain_stock(struct memcg_stock_pcp *stock)
{
struct mem_cgroup *old = stock->cached;
if (stock->nr_pages) {
- unsigned long bytes = stock->nr_pages * PAGE_SIZE;
-
- res_counter_uncharge(&old->res, bytes);
+ page_counter_uncharge(&old->memory, stock->nr_pages);
if (do_swap_account)
- res_counter_uncharge(&old->memsw, bytes);
+ page_counter_uncharge(&old->memsw, stock->nr_pages);
+ css_put_many(&old->css, stock->nr_pages);
stock->nr_pages = 0;
}
stock->cached = NULL;
@@ -2371,7 +2157,7 @@ static void __init memcg_stock_init(void)
}
/*
- * Cache charges(val) which is from res_counter, to local per_cpu area.
+ * Cache charges(val) to local per_cpu area.
* This will be consumed by consume_stock() function, later.
*/
static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
@@ -2388,13 +2174,15 @@ static void refill_stock(struct mem_cgroup *memcg, unsigned int nr_pages)
/*
* Drains all per-CPU charge caches for given root_memcg resp. subtree
- * of the hierarchy under it. sync flag says whether we should block
- * until the work is done.
+ * of the hierarchy under it.
*/
-static void drain_all_stock(struct mem_cgroup *root_memcg, bool sync)
+static void drain_all_stock(struct mem_cgroup *root_memcg)
{
int cpu, curcpu;
+ /* If someone's already draining, avoid adding running more workers. */
+ if (!mutex_trylock(&percpu_charge_mutex))
+ return;
/* Notify other cpus that system-wide "drain" is running */
get_online_cpus();
curcpu = get_cpu();
@@ -2405,7 +2193,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg, bool sync)
memcg = stock->cached;
if (!memcg || !stock->nr_pages)
continue;
- if (!mem_cgroup_same_or_subtree(root_memcg, memcg))
+ if (!mem_cgroup_is_descendant(memcg, root_memcg))
continue;
if (!test_and_set_bit(FLUSHING_CACHED_CHARGE, &stock->flags)) {
if (cpu == curcpu)
@@ -2415,42 +2203,7 @@ static void drain_all_stock(struct mem_cgroup *root_memcg, bool sync)
}
}
put_cpu();
-
- if (!sync)
- goto out;
-
- for_each_online_cpu(cpu) {
- struct memcg_stock_pcp *stock = &per_cpu(memcg_stock, cpu);
- if (test_bit(FLUSHING_CACHED_CHARGE, &stock->flags))
- flush_work(&stock->work);
- }
-out:
put_online_cpus();
-}
-
-/*
- * Tries to drain stocked charges in other cpus. This function is asynchronous
- * and just put a work per cpu for draining localy on each cpu. Caller can
- * expects some charges will be back to res_counter later but cannot wait for
- * it.
- */
-static void drain_all_stock_async(struct mem_cgroup *root_memcg)
-{
- /*
- * If someone calls draining, avoid adding more kworker runs.
- */
- if (!mutex_trylock(&percpu_charge_mutex))
- return;
- drain_all_stock(root_memcg, false);
- mutex_unlock(&percpu_charge_mutex);
-}
-
-/* This is a synchronous drain interface. */
-static void drain_all_stock_sync(struct mem_cgroup *root_memcg)
-{
- /* called when force_empty is called */
- mutex_lock(&percpu_charge_mutex);
- drain_all_stock(root_memcg, true);
mutex_unlock(&percpu_charge_mutex);
}
@@ -2506,9 +2259,8 @@ static int try_charge(struct mem_cgroup *memcg, gfp_t gfp_mask,
unsigned int batch = max(CHARGE_BATCH, nr_pages);
int nr_retries = MEM_CGROUP_RECLAIM_RETRIES;
struct mem_cgroup *mem_over_limit;
- struct res_counter *fail_res;
+ struct page_counter *counter;
unsigned long nr_reclaimed;
- unsigned long long size;
bool may_swap = true;
bool drained = false;
int ret = 0;
@@ -2519,16 +2271,15 @@ retry:
if (consume_stock(memcg, nr_pages))
goto done;
- size = batch * PAGE_SIZE;
if (!do_swap_account ||
- !res_counter_charge(&memcg->memsw, size, &fail_res)) {
- if (!res_counter_charge(&memcg->res, size, &fail_res))
+ !page_counter_try_charge(&memcg->memsw, batch, &counter)) {
+ if (!page_counter_try_charge(&memcg->memory, batch, &counter))
goto done_restock;
if (do_swap_account)
- res_counter_uncharge(&memcg->memsw, size);
- mem_over_limit = mem_cgroup_from_res_counter(fail_res, res);
+ page_counter_uncharge(&memcg->memsw, batch);
+ mem_over_limit = mem_cgroup_from_counter(counter, memory);
} else {
- mem_over_limit = mem_cgroup_from_res_counter(fail_res, memsw);
+ mem_over_limit = mem_cgroup_from_counter(counter, memsw);
may_swap = false;
}
@@ -2561,7 +2312,7 @@ retry:
goto retry;
if (!drained) {
- drain_all_stock_async(mem_over_limit);
+ drain_all_stock(mem_over_limit);
drained = true;
goto retry;
}
@@ -2603,6 +2354,7 @@ bypass:
return -EINTR;
done_restock:
+ css_get_many(&memcg->css, batch);
if (batch > nr_pages)
refill_stock(memcg, batch - nr_pages);
done:
@@ -2611,32 +2363,14 @@ done:
static void cancel_charge(struct mem_cgroup *memcg, unsigned int nr_pages)
{
- unsigned long bytes = nr_pages * PAGE_SIZE;
-
if (mem_cgroup_is_root(memcg))
return;
- res_counter_uncharge(&memcg->res, bytes);
+ page_counter_uncharge(&memcg->memory, nr_pages);
if (do_swap_account)
- res_counter_uncharge(&memcg->memsw, bytes);
-}
-
-/*
- * Cancel chrages in this cgroup....doesn't propagate to parent cgroup.
- * This is useful when moving usage to parent cgroup.
- */
-static void __mem_cgroup_cancel_local_charge(struct mem_cgroup *memcg,
- unsigned int nr_pages)
-{
- unsigned long bytes = nr_pages * PAGE_SIZE;
-
- if (mem_cgroup_is_root(memcg))
- return;
+ page_counter_uncharge(&memcg->memsw, nr_pages);
- res_counter_uncharge_until(&memcg->res, memcg->res.parent, bytes);
- if (do_swap_account)
- res_counter_uncharge_until(&memcg->memsw,
- memcg->memsw.parent, bytes);
+ css_put_many(&memcg->css, nr_pages);
}
/*
@@ -2665,17 +2399,15 @@ static struct mem_cgroup *mem_cgroup_lookup(unsigned short id)
*/
struct mem_cgroup *try_get_mem_cgroup_from_page(struct page *page)
{
- struct mem_cgroup *memcg = NULL;
- struct page_cgroup *pc;
+ struct mem_cgroup *memcg;
unsigned short id;
swp_entry_t ent;
VM_BUG_ON_PAGE(!PageLocked(page), page);
- pc = lookup_page_cgroup(page);
- if (PageCgroupUsed(pc)) {
- memcg = pc->mem_cgroup;
- if (memcg && !css_tryget_online(&memcg->css))
+ memcg = page->mem_cgroup;
+ if (memcg) {
+ if (!css_tryget_online(&memcg->css))
memcg = NULL;
} else if (PageSwapCache(page)) {
ent.val = page_private(page);
@@ -2723,14 +2455,9 @@ static void unlock_page_lru(struct page *page, int isolated)
static void commit_charge(struct page *page, struct mem_cgroup *memcg,
bool lrucare)
{
- struct page_cgroup *pc = lookup_page_cgroup(page);
int isolated;
- VM_BUG_ON_PAGE(PageCgroupUsed(pc), page);
- /*
- * we don't need page_cgroup_lock about tail pages, becase they are not
- * accessed by any other context at this point.
- */
+ VM_BUG_ON_PAGE(page->mem_cgroup, page);
/*
* In some cases, SwapCache and FUSE(splice_buf->radixtree), the page
@@ -2741,7 +2468,7 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg,
/*
* Nobody should be changing or seriously looking at
- * pc->mem_cgroup and pc->flags at this point:
+ * page->mem_cgroup at this point:
*
* - the page is uncharged
*
@@ -2753,15 +2480,12 @@ static void commit_charge(struct page *page, struct mem_cgroup *memcg,
* - a page cache insertion, a swapin fault, or a migration
* have the page locked
*/
- pc->mem_cgroup = memcg;
- pc->flags = PCG_USED | PCG_MEM | (do_swap_account ? PCG_MEMSW : 0);
+ page->mem_cgroup = memcg;
if (lrucare)
unlock_page_lru(page, isolated);
}
-static DEFINE_MUTEX(set_limit_mutex);
-
#ifdef CONFIG_MEMCG_KMEM
/*
* The memcg_slab_mutex is held whenever a per memcg kmem cache is created or
@@ -2769,8 +2493,6 @@ static DEFINE_MUTEX(set_limit_mutex);
*/
static DEFINE_MUTEX(memcg_slab_mutex);
-static DEFINE_MUTEX(activate_kmem_mutex);
-
/*
* This is a bit cumbersome, but it is rarely used and avoids a backpointer
* in the memcg_cache_params struct.
@@ -2784,36 +2506,17 @@ static struct kmem_cache *memcg_params_to_cache(struct memcg_cache_params *p)
return cache_from_memcg_idx(cachep, memcg_cache_id(p->memcg));
}
-#ifdef CONFIG_SLABINFO
-static int mem_cgroup_slabinfo_read(struct seq_file *m, void *v)
-{
- struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
- struct memcg_cache_params *params;
-
- if (!memcg_kmem_is_active(memcg))
- return -EIO;
-
- print_slabinfo_header(m);
-
- mutex_lock(&memcg_slab_mutex);
- list_for_each_entry(params, &memcg->memcg_slab_caches, list)
- cache_show(memcg_params_to_cache(params), m);
- mutex_unlock(&memcg_slab_mutex);
-
- return 0;
-}
-#endif
-
-static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size)
+static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp,
+ unsigned long nr_pages)
{
- struct res_counter *fail_res;
+ struct page_counter *counter;
int ret = 0;
- ret = res_counter_charge(&memcg->kmem, size, &fail_res);
- if (ret)
+ ret = page_counter_try_charge(&memcg->kmem, nr_pages, &counter);
+ if (ret < 0)
return ret;
- ret = try_charge(memcg, gfp, size >> PAGE_SHIFT);
+ ret = try_charge(memcg, gfp, nr_pages);
if (ret == -EINTR) {
/*
* try_charge() chose to bypass to root due to OOM kill or
@@ -2830,37 +2533,27 @@ static int memcg_charge_kmem(struct mem_cgroup *memcg, gfp_t gfp, u64 size)
* when the allocation triggers should have been already
* directed to the root cgroup in memcontrol.h
*/
- res_counter_charge_nofail(&memcg->res, size, &fail_res);
+ page_counter_charge(&memcg->memory, nr_pages);
if (do_swap_account)
- res_counter_charge_nofail(&memcg->memsw, size,
- &fail_res);
+ page_counter_charge(&memcg->memsw, nr_pages);
+ css_get_many(&memcg->css, nr_pages);
ret = 0;
} else if (ret)
- res_counter_uncharge(&memcg->kmem, size);
+ page_counter_uncharge(&memcg->kmem, nr_pages);
return ret;
}
-static void memcg_uncharge_kmem(struct mem_cgroup *memcg, u64 size)
+static void memcg_uncharge_kmem(struct mem_cgroup *memcg,
+ unsigned long nr_pages)
{
- res_counter_uncharge(&memcg->res, size);
+ page_counter_uncharge(&memcg->memory, nr_pages);
if (do_swap_account)
- res_counter_uncharge(&memcg->memsw, size);
+ page_counter_uncharge(&memcg->memsw, nr_pages);
- /* Not down to 0 */
- if (res_counter_uncharge(&memcg->kmem, size))
- return;
+ page_counter_uncharge(&memcg->kmem, nr_pages);
- /*
- * Releases a reference taken in kmem_cgroup_css_offline in case
- * this last uncharge is racing with the offlining code or it is
- * outliving the memcg existence.
- *
- * The memory barrier imposed by test&clear is paired with the
- * explicit one in memcg_kmem_mark_dead().
- */
- if (memcg_kmem_test_and_clear_dead(memcg))
- css_put(&memcg->css);
+ css_put_many(&memcg->css, nr_pages);
}
/*
@@ -3124,19 +2817,21 @@ static void memcg_schedule_register_cache(struct mem_cgroup *memcg,
int __memcg_charge_slab(struct kmem_cache *cachep, gfp_t gfp, int order)
{
+ unsigned int nr_pages = 1 << order;
int res;
- res = memcg_charge_kmem(cachep->memcg_params->memcg, gfp,
- PAGE_SIZE << order);
+ res = memcg_charge_kmem(cachep->memcg_params->memcg, gfp, nr_pages);
if (!res)
- atomic_add(1 << order, &cachep->memcg_params->nr_pages);
+ atomic_add(nr_pages, &cachep->memcg_params->nr_pages);
return res;
}
void __memcg_uncharge_slab(struct kmem_cache *cachep, int order)
{
- memcg_uncharge_kmem(cachep->memcg_params->memcg, PAGE_SIZE << order);
- atomic_sub(1 << order, &cachep->memcg_params->nr_pages);
+ unsigned int nr_pages = 1 << order;
+
+ memcg_uncharge_kmem(cachep->memcg_params->memcg, nr_pages);
+ atomic_sub(nr_pages, &cachep->memcg_params->nr_pages);
}
/*
@@ -3257,7 +2952,7 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order)
return true;
}
- ret = memcg_charge_kmem(memcg, gfp, PAGE_SIZE << order);
+ ret = memcg_charge_kmem(memcg, gfp, 1 << order);
if (!ret)
*_memcg = memcg;
@@ -3268,46 +2963,27 @@ __memcg_kmem_newpage_charge(gfp_t gfp, struct mem_cgroup **_memcg, int order)
void __memcg_kmem_commit_charge(struct page *page, struct mem_cgroup *memcg,
int order)
{
- struct page_cgroup *pc;
-
VM_BUG_ON(mem_cgroup_is_root(memcg));
/* The page allocation failed. Revert */
if (!page) {
- memcg_uncharge_kmem(memcg, PAGE_SIZE << order);
+ memcg_uncharge_kmem(memcg, 1 << order);
return;
}
- /*
- * The page is freshly allocated and not visible to any
- * outside callers yet. Set up pc non-atomically.
- */
- pc = lookup_page_cgroup(page);
- pc->mem_cgroup = memcg;
- pc->flags = PCG_USED;
+ page->mem_cgroup = memcg;
}
void __memcg_kmem_uncharge_pages(struct page *page, int order)
{
- struct mem_cgroup *memcg = NULL;
- struct page_cgroup *pc;
-
+ struct mem_cgroup *memcg = page->mem_cgroup;
- pc = lookup_page_cgroup(page);
- if (!PageCgroupUsed(pc))
- return;
-
- memcg = pc->mem_cgroup;
- pc->flags = 0;
-
- /*
- * We trust that only if there is a memcg associated with the page, it
- * is a valid allocation
- */
if (!memcg)
return;
VM_BUG_ON_PAGE(mem_cgroup_is_root(memcg), page);
- memcg_uncharge_kmem(memcg, PAGE_SIZE << order);
+
+ memcg_uncharge_kmem(memcg, 1 << order);
+ page->mem_cgroup = NULL;
}
#else
static inline void memcg_unregister_all_caches(struct mem_cgroup *memcg)
@@ -3325,21 +3001,15 @@ static inline void memcg_unregister_all_caches(struct mem_cgroup *memcg)
*/
void mem_cgroup_split_huge_fixup(struct page *head)
{
- struct page_cgroup *head_pc = lookup_page_cgroup(head);
- struct page_cgroup *pc;
- struct mem_cgroup *memcg;
int i;
if (mem_cgroup_disabled())
return;
- memcg = head_pc->mem_cgroup;
- for (i = 1; i < HPAGE_PMD_NR; i++) {
- pc = head_pc + i;
- pc->mem_cgroup = memcg;
- pc->flags = head_pc->flags;
- }
- __this_cpu_sub(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE],
+ for (i = 1; i < HPAGE_PMD_NR; i++)
+ head[i].mem_cgroup = head->mem_cgroup;
+
+ __this_cpu_sub(head->mem_cgroup->stat->count[MEM_CGROUP_STAT_RSS_HUGE],
HPAGE_PMD_NR);
}
#endif /* CONFIG_TRANSPARENT_HUGEPAGE */
@@ -3348,7 +3018,6 @@ void mem_cgroup_split_huge_fixup(struct page *head)
* mem_cgroup_move_account - move account of the page
* @page: the page
* @nr_pages: number of regular pages (>1 for huge pages)
- * @pc: page_cgroup of the page.
* @from: mem_cgroup which the page is moved from.
* @to: mem_cgroup which the page is moved to. @from != @to.
*
@@ -3361,7 +3030,6 @@ void mem_cgroup_split_huge_fixup(struct page *head)
*/
static int mem_cgroup_move_account(struct page *page,
unsigned int nr_pages,
- struct page_cgroup *pc,
struct mem_cgroup *from,
struct mem_cgroup *to)
{
@@ -3381,7 +3049,7 @@ static int mem_cgroup_move_account(struct page *page,
goto out;
/*
- * Prevent mem_cgroup_migrate() from looking at pc->mem_cgroup
+ * Prevent mem_cgroup_migrate() from looking at page->mem_cgroup
* of its source page while we change it: page migration takes
* both pages off the LRU, but page cache replacement doesn't.
*/
@@ -3389,10 +3057,10 @@ static int mem_cgroup_move_account(struct page *page,
goto out;
ret = -EINVAL;
- if (!PageCgroupUsed(pc) || pc->mem_cgroup != from)
+ if (page->mem_cgroup != from)
goto out_unlock;
- move_lock_mem_cgroup(from, &flags);
+ spin_lock_irqsave(&from->move_lock, flags);
if (!PageAnon(page) && page_mapped(page)) {
__this_cpu_sub(from->stat->count[MEM_CGROUP_STAT_FILE_MAPPED],
@@ -3409,14 +3077,15 @@ static int mem_cgroup_move_account(struct page *page,
}
/*
- * It is safe to change pc->mem_cgroup here because the page
+ * It is safe to change page->mem_cgroup here because the page
* is referenced, charged, and isolated - we can't race with
* uncharging, charging, migration, or LRU putback.
*/
/* caller should have done css_get */
- pc->mem_cgroup = to;
- move_unlock_mem_cgroup(from, &flags);
+ page->mem_cgroup = to;
+ spin_unlock_irqrestore(&from->move_lock, flags);
+
ret = 0;
local_irq_disable();
@@ -3431,72 +3100,6 @@ out:
return ret;
}
-/**
- * mem_cgroup_move_parent - moves page to the parent group
- * @page: the page to move
- * @pc: page_cgroup of the page
- * @child: page's cgroup
- *
- * move charges to its parent or the root cgroup if the group has no
- * parent (aka use_hierarchy==0).
- * Although this might fail (get_page_unless_zero, isolate_lru_page or
- * mem_cgroup_move_account fails) the failure is always temporary and
- * it signals a race with a page removal/uncharge or migration. In the
- * first case the page is on the way out and it will vanish from the LRU
- * on the next attempt and the call should be retried later.
- * Isolation from the LRU fails only if page has been isolated from
- * the LRU since we looked at it and that usually means either global
- * reclaim or migration going on. The page will either get back to the
- * LRU or vanish.
- * Finaly mem_cgroup_move_account fails only if the page got uncharged
- * (!PageCgroupUsed) or moved to a different group. The page will
- * disappear in the next attempt.
- */
-static int mem_cgroup_move_parent(struct page *page,
- struct page_cgroup *pc,
- struct mem_cgroup *child)
-{
- struct mem_cgroup *parent;
- unsigned int nr_pages;
- unsigned long uninitialized_var(flags);
- int ret;
-
- VM_BUG_ON(mem_cgroup_is_root(child));
-
- ret = -EBUSY;
- if (!get_page_unless_zero(page))
- goto out;
- if (isolate_lru_page(page))
- goto put;
-
- nr_pages = hpage_nr_pages(page);
-
- parent = parent_mem_cgroup(child);
- /*
- * If no parent, move charges to root cgroup.
- */
- if (!parent)
- parent = root_mem_cgroup;
-
- if (nr_pages > 1) {
- VM_BUG_ON_PAGE(!PageTransHuge(page), page);
- flags = compound_lock_irqsave(page);
- }
-
- ret = mem_cgroup_move_account(page, nr_pages,
- pc, child, parent);
- if (!ret)
- __mem_cgroup_cancel_local_charge(child, nr_pages);
-
- if (nr_pages > 1)
- compound_unlock_irqrestore(page, flags);
- putback_lru_page(page);
-put:
- put_page(page);
-out:
- return ret;
-}
-
#ifdef CONFIG_MEMCG_SWAP
static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
bool charge)
@@ -3516,7 +3119,7 @@ static void mem_cgroup_swap_statistics(struct mem_cgroup *memcg,
*
* Returns 0 on success, -EINVAL on failure.
*
- * The caller must have charged to @to, IOW, called res_counter_charge() about
+ * The caller must have charged to @to, IOW, called page_counter_charge() about
* both res and memsw, and called css_get().
*/
static int mem_cgroup_move_swap_account(swp_entry_t entry,
@@ -3532,7 +3135,7 @@ static int mem_cgroup_move_swap_account(swp_entry_t entry,
mem_cgroup_swap_statistics(to, true);
/*
* This function is only called from task migration context now.
- * It postpones res_counter and refcount handling till the end
+ * It postpones page_counter and refcount handling till the end
* of task migration(mem_cgroup_clear_mc()) for performance
* improvement. But we cannot postpone css_get(to) because if
* the process that has been moved to @to does swap-in, the
@@ -3554,96 +3157,57 @@ static inline int mem_cgroup_move_swap_account(swp_entry_t entry,
}
#endif
-#ifdef CONFIG_DEBUG_VM
-static struct page_cgroup *lookup_page_cgroup_used(struct page *page)
-{
- struct page_cgroup *pc;
-
- pc = lookup_page_cgroup(page);
- /*
- * Can be NULL while feeding pages into the page allocator for
- * the first time, i.e. during boot or memory hotplug;
- * or when mem_cgroup_disabled().
- */
- if (likely(pc) && PageCgroupUsed(pc))
- return pc;
- return NULL;
-}
-
-bool mem_cgroup_bad_page_check(struct page *page)
-{
- if (mem_cgroup_disabled())
- return false;
-
- return lookup_page_cgroup_used(page) != NULL;
-}
-
-void mem_cgroup_print_bad_page(struct page *page)
-{
- struct page_cgroup *pc;
-
- pc = lookup_page_cgroup_used(page);
- if (pc) {
- pr_alert("pc:%p pc->flags:%lx pc->mem_cgroup:%p\n",
- pc, pc->flags, pc->mem_cgroup);
- }
-}
-#endif
+static DEFINE_MUTEX(memcg_limit_mutex);
static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
- unsigned long long val)
+ unsigned long limit)
{
+ unsigned long curusage;
+ unsigned long oldusage;
+ bool enlarge = false;
int retry_count;
- int ret = 0;
- int children = mem_cgroup_count_children(memcg);
- u64 curusage, oldusage;
- int enlarge;
+ int ret;
/*
* For keeping hierarchical_reclaim simple, how long we should retry
* is depends on callers. We set our retry-count to be function
* of # of children which we should visit in this loop.
*/
- retry_count = MEM_CGROUP_RECLAIM_RETRIES * children;
+ retry_count = MEM_CGROUP_RECLAIM_RETRIES *
+ mem_cgroup_count_children(memcg);
- oldusage = res_counter_read_u64(&memcg->res, RES_USAGE);
+ oldusage = page_counter_read(&memcg->memory);
- enlarge = 0;
- while (retry_count) {
+ do {
if (signal_pending(current)) {
ret = -EINTR;
break;
}
- /*
- * Rather than hide all in some function, I do this in
- * open coded manner. You see what this really does.
- * We have to guarantee memcg->res.limit <= memcg->memsw.limit.
- */
- mutex_lock(&set_limit_mutex);
- if (res_counter_read_u64(&memcg->memsw, RES_LIMIT) < val) {
+
+ mutex_lock(&memcg_limit_mutex);
+ if (limit > memcg->memsw.limit) {
+ mutex_unlock(&memcg_limit_mutex);
ret = -EINVAL;
- mutex_unlock(&set_limit_mutex);
break;
}
-
- if (res_counter_read_u64(&memcg->res, RES_LIMIT) < val)
- enlarge = 1;
-
- ret = res_counter_set_limit(&memcg->res, val);
- mutex_unlock(&set_limit_mutex);
+ if (limit > memcg->memory.limit)
+ enlarge = true;
+ ret = page_counter_limit(&memcg->memory, limit);
+ mutex_unlock(&memcg_limit_mutex);
if (!ret)
break;
try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL, true);
- curusage = res_counter_read_u64(&memcg->res, RES_USAGE);
+ curusage = page_counter_read(&memcg->memory);
/* Usage is reduced ? */
if (curusage >= oldusage)
retry_count--;
else
oldusage = curusage;
- }
+ } while (retry_count);
+
if (!ret && enlarge)
memcg_oom_recover(memcg);
@@ -3651,52 +3215,53 @@ static int mem_cgroup_resize_limit(struct mem_cgroup *memcg,
}
static int mem_cgroup_resize_memsw_limit(struct mem_cgroup *memcg,
- unsigned long long val)
+ unsigned long limit)
{
+ unsigned long curusage;
+ unsigned long oldusage;
+ bool enlarge = false;
int retry_count;
- u64 oldusage, curusage;
- int children = mem_cgroup_count_children(memcg);
- int ret = -EBUSY;
- int enlarge = 0;
+ int ret;
/* see mem_cgroup_resize_res_limit */
- retry_count = children * MEM_CGROUP_RECLAIM_RETRIES;
- oldusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
- while (retry_count) {
+ retry_count = MEM_CGROUP_RECLAIM_RETRIES *
+ mem_cgroup_count_children(memcg);
+
+ oldusage = page_counter_read(&memcg->memsw);
+
+ do {
if (signal_pending(current)) {
ret = -EINTR;
break;
}
- /*
- * Rather than hide all in some function, I do this in
- * open coded manner. You see what this really does.
- * We have to guarantee memcg->res.limit <= memcg->memsw.limit.
- */
- mutex_lock(&set_limit_mutex);
- if (res_counter_read_u64(&memcg->res, RES_LIMIT) > val) {
+
+ mutex_lock(&memcg_limit_mutex);
+ if (limit < memcg->memory.limit) {
+ mutex_unlock(&memcg_limit_mutex);
ret = -EINVAL;
- mutex_unlock(&set_limit_mutex);
break;
}
- if (res_counter_read_u64(&memcg->memsw, RES_LIMIT) < val)
- enlarge = 1;
- ret = res_counter_set_limit(&memcg->memsw, val);
- mutex_unlock(&set_limit_mutex);
+ if (limit > memcg->memsw.limit)
+ enlarge = true;
+ ret = page_counter_limit(&memcg->memsw, limit);
+ mutex_unlock(&memcg_limit_mutex);
if (!ret)
break;
try_to_free_mem_cgroup_pages(memcg, 1, GFP_KERNEL, false);
- curusage = res_counter_read_u64(&memcg->memsw, RES_USAGE);
+ curusage = page_counter_read(&memcg->memsw);
/* Usage is reduced ? */
if (curusage >= oldusage)
retry_count--;
else
oldusage = curusage;
- }
+ } while (retry_count);
+
if (!ret && enlarge)
memcg_oom_recover(memcg);
+
return ret;
}
@@ -3709,7 +3274,7 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
unsigned long reclaimed;
int loop = 0;
struct mem_cgroup_tree_per_zone *mctz;
- unsigned long long excess;
+ unsigned long excess;
unsigned long nr_scanned;
if (order > 0)
@@ -3735,35 +3300,17 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
nr_reclaimed += reclaimed;
*total_scanned += nr_scanned;
spin_lock_irq(&mctz->lock);
+ __mem_cgroup_remove_exceeded(mz, mctz);
/*
* If we failed to reclaim anything from this memory cgroup
* it is time to move on to the next cgroup
*/
next_mz = NULL;
- if (!reclaimed) {
- do {
- /*
- * Loop until we find yet another one.
- *
- * By the time we get the soft_limit lock
- * again, someone might have aded the
- * group back on the RB tree. Iterate to
- * make sure we get a different mem.
- * mem_cgroup_largest_soft_limit_node returns
- * NULL if no other cgroup is present on
- * the tree
- */
- next_mz =
- __mem_cgroup_largest_soft_limit_node(mctz);
- if (next_mz == mz)
- css_put(&next_mz->memcg->css);
- else /* next_mz == NULL or other memcg */
- break;
- } while (1);
- }
- __mem_cgroup_remove_exceeded(mz, mctz);
- excess = res_counter_soft_limit_excess(&mz->memcg->res);
+ if (!reclaimed)
+ next_mz = __mem_cgroup_largest_soft_limit_node(mctz);
+
+ excess = soft_limit_excess(mz->memcg);
/*
* One school of thought says that we should not add
* back the node to the tree if reclaim returns 0.
@@ -3792,107 +3339,6 @@ unsigned long mem_cgroup_soft_limit_reclaim(struct zone *zone, int order,
return nr_reclaimed;
}
-/**
- * mem_cgroup_force_empty_list - clears LRU of a group
- * @memcg: group to clear
- * @node: NUMA node
- * @zid: zone id
- * @lru: lru to to clear
- *
- * Traverse a specified page_cgroup list and try to drop them all. This doesn't
- * reclaim the pages page themselves - pages are moved to the parent (or root)
- * group.
- */
-static void mem_cgroup_force_empty_list(struct mem_cgroup *memcg,
- int node, int zid, enum lru_list lru)
-{
- struct lruvec *lruvec;
- unsigned long flags;
- struct list_head *list;
- struct page *busy;
- struct zone *zone;
-
- zone = &NODE_DATA(node)->node_zones[zid];
- lruvec = mem_cgroup_zone_lruvec(zone, memcg);
- list = &lruvec->lists[lru];
-
- busy = NULL;
- do {
- struct page_cgroup *pc;
- struct page *page;
-
- spin_lock_irqsave(&zone->lru_lock, flags);
- if (list_empty(list)) {
- spin_unlock_irqrestore(&zone->lru_lock, flags);
- break;
- }
- page = list_entry(list->prev, struct page, lru);
- if (busy == page) {
- list_move(&page->lru, list);
- busy = NULL;
- spin_unlock_irqrestore(&zone->lru_lock, flags);
- continue;
- }
- spin_unlock_irqrestore(&zone->lru_lock, flags);
-
- pc = lookup_page_cgroup(page);
-
- if (mem_cgroup_move_parent(page, pc, memcg)) {
- /* found lock contention or "pc" is obsolete. */
- busy = page;
- } else
- busy = NULL;
- cond_resched();
- } while (!list_empty(list));
-}
-
-/*
- * make mem_cgroup's charge to be 0 if there is no task by moving
- * all the charges and pages to the parent.
- * This enables deleting this mem_cgroup.
- *
- * Caller is responsible for holding css reference on the memcg.
- */
-static void mem_cgroup_reparent_charges(struct mem_cgroup *memcg)
-{
- int node, zid;
- u64 usage;
-
- do {
- /* This is for making all *used* pages to be on LRU. */
- lru_add_drain_all();
- drain_all_stock_sync(memcg);
- mem_cgroup_start_move(memcg);
- for_each_node_state(node, N_MEMORY) {
- for (zid = 0; zid < MAX_NR_ZONES; zid++) {
- enum lru_list lru;
- for_each_lru(lru) {
- mem_cgroup_force_empty_list(memcg,
- node, zid, lru);
- }
- }
- }
- mem_cgroup_end_move(memcg);
- memcg_oom_recover(memcg);
- cond_resched();
-
- /*
- * Kernel memory may not necessarily be trackable to a specific
- * process. So they are not migrated, and therefore we can't
- * expect their value to drop to 0 here.
- * Having res filled up with kmem only is enough.
- *
- * This is a safety check because mem_cgroup_force_empty_list
- * could have raced with mem_cgroup_replace_page_cache callers
- * so the lru seemed empty but the page could have been added
- * right after the check. RES_USAGE should be safe as we always
- * charge before adding to the LRU.
- */
- usage = res_counter_read_u64(&memcg->res, RES_USAGE) -
- res_counter_read_u64(&memcg->kmem, RES_USAGE);
- } while (usage > 0);
-}
-
/*
* Test whether @memcg has children, dead or alive. Note that this
* function doesn't care whether @memcg has use_hierarchy enabled and
@@ -3930,7 +3376,7 @@ static int mem_cgroup_force_empty(struct mem_cgroup *memcg)
/* we call try-to-free pages for make this cgroup empty */
lru_add_drain_all();
/* try to free all pages in this cgroup */
- while (nr_retries && res_counter_read_u64(&memcg->res, RES_USAGE) > 0) {
+ while (nr_retries && page_counter_read(&memcg->memory)) {
int progress;
if (signal_pending(current))
@@ -4001,8 +3447,8 @@ out:
return retval;
}
-static unsigned long mem_cgroup_recursive_stat(struct mem_cgroup *memcg,
- enum mem_cgroup_stat_index idx)
+static unsigned long tree_stat(struct mem_cgroup *memcg,
+ enum mem_cgroup_stat_index idx)
{
struct mem_cgroup *iter;
long val = 0;
@@ -4020,55 +3466,71 @@ static inline u64 mem_cgroup_usage(struct mem_cgroup *memcg, bool swap)
{
u64 val;
- if (!mem_cgroup_is_root(memcg)) {
+ if (mem_cgroup_is_root(memcg)) {
+ val = tree_stat(memcg, MEM_CGROUP_STAT_CACHE);
+ val += tree_stat(memcg, MEM_CGROUP_STAT_RSS);
+ if (swap)
+ val += tree_stat(memcg, MEM_CGROUP_STAT_SWAP);
+ } else {
if (!swap)
- return res_counter_read_u64(&memcg->res, RES_USAGE);
+ val = page_counter_read(&memcg->memory);
else
- return res_counter_read_u64(&memcg->memsw, RES_USAGE);
+ val = page_counter_read(&memcg->memsw);
}
-
- /*
- * Transparent hugepages are still accounted for in MEM_CGROUP_STAT_RSS
- * as well as in MEM_CGROUP_STAT_RSS_HUGE.
- */
- val = mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_CACHE);
- val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_RSS);
-
- if (swap)
- val += mem_cgroup_recursive_stat(memcg, MEM_CGROUP_STAT_SWAP);
-
return val << PAGE_SHIFT;
}
+enum {
+ RES_USAGE,
+ RES_LIMIT,
+ RES_MAX_USAGE,
+ RES_FAILCNT,
+ RES_SOFT_LIMIT,
+};
static u64 mem_cgroup_read_u64(struct cgroup_subsys_state *css,
struct cftype *cft)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
- enum res_type type = MEMFILE_TYPE(cft->private);
- int name = MEMFILE_ATTR(cft->private);
+ struct page_counter *counter;
- switch (type) {
+ switch (MEMFILE_TYPE(cft->private)) {
case _MEM:
- if (name == RES_USAGE)
- return mem_cgroup_usage(memcg, false);
- return res_counter_read_u64(&memcg->res, name);
+ counter = &memcg->memory;
+ break;
case _MEMSWAP:
- if (name == RES_USAGE)
- return mem_cgroup_usage(memcg, true);
- return res_counter_read_u64(&memcg->memsw, name);
+ counter = &memcg->memsw;
+ break;
case _KMEM:
- return res_counter_read_u64(&memcg->kmem, name);
+ counter = &memcg->kmem;
break;
default:
BUG();
}
+
+ switch (MEMFILE_ATTR(cft->private)) {
+ case RES_USAGE:
+ if (counter == &memcg->memory)
+ return mem_cgroup_usage(memcg, false);
+ if (counter == &memcg->memsw)
+ return mem_cgroup_usage(memcg, true);
+ return (u64)page_counter_read(counter) * PAGE_SIZE;
+ case RES_LIMIT:
+ return (u64)counter->limit * PAGE_SIZE;
+ case RES_MAX_USAGE:
+ return (u64)counter->watermark * PAGE_SIZE;
+ case RES_FAILCNT:
+ return counter->failcnt;
+ case RES_SOFT_LIMIT:
+ return (u64)memcg->soft_limit * PAGE_SIZE;
+ default:
+ BUG();
+ }
}
#ifdef CONFIG_MEMCG_KMEM
-/* should be called with activate_kmem_mutex held */
-static int __memcg_activate_kmem(struct mem_cgroup *memcg,
- unsigned long long limit)
+static int memcg_activate_kmem(struct mem_cgroup *memcg,
+ unsigned long nr_pages)
{
int err = 0;
int memcg_id;
@@ -4115,7 +3577,7 @@ static int __memcg_activate_kmem(struct mem_cgroup *memcg,
* We couldn't have accounted to this cgroup, because it hasn't got the
* active bit set yet, so this should succeed.
*/
- err = res_counter_set_limit(&memcg->kmem, limit);
+ err = page_counter_limit(&memcg->kmem, nr_pages);
VM_BUG_ON(err);
static_key_slow_inc(&memcg_kmem_enabled_key);
@@ -4130,26 +3592,17 @@ out:
return err;
}
-static int memcg_activate_kmem(struct mem_cgroup *memcg,
- unsigned long long limit)
-{
- int ret;
-
- mutex_lock(&activate_kmem_mutex);
- ret = __memcg_activate_kmem(memcg, limit);
- mutex_unlock(&activate_kmem_mutex);
- return ret;
-}
-
static int memcg_update_kmem_limit(struct mem_cgroup *memcg,
- unsigned long long val)
+ unsigned long limit)
{
int ret;
+ mutex_lock(&memcg_limit_mutex);
if (!memcg_kmem_is_active(memcg))
- ret = memcg_activate_kmem(memcg, val);
+ ret = memcg_activate_kmem(memcg, limit);
else
- ret = res_counter_set_limit(&memcg->kmem, val);
+ ret = page_counter_limit(&memcg->kmem, limit);
+ mutex_unlock(&memcg_limit_mutex);
return ret;
}
@@ -4161,19 +3614,19 @@ static int memcg_propagate_kmem(struct mem_cgroup *memcg)
if (!parent)
return 0;
- mutex_lock(&activate_kmem_mutex);
+ mutex_lock(&memcg_limit_mutex);
/*
* If the parent cgroup is not kmem-active now, it cannot be activated
* after this point, because it has at least one child already.
*/
if (memcg_kmem_is_active(parent))
- ret = __memcg_activate_kmem(memcg, RES_COUNTER_MAX);
- mutex_unlock(&activate_kmem_mutex);
+ ret = memcg_activate_kmem(memcg, PAGE_COUNTER_MAX);
+ mutex_unlock(&memcg_limit_mutex);
return ret;
}
#else
static int memcg_update_kmem_limit(struct mem_cgroup *memcg,
- unsigned long long val)
+ unsigned long limit)
{
return -EINVAL;
}
@@ -4187,110 +3640,69 @@ static ssize_t mem_cgroup_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
- enum res_type type;
- int name;
- unsigned long long val;
+ unsigned long nr_pages;
int ret;
buf = strstrip(buf);
- type = MEMFILE_TYPE(of_cft(of)->private);
- name = MEMFILE_ATTR(of_cft(of)->private);
+ ret = page_counter_memparse(buf, &nr_pages);
+ if (ret)
+ return ret;
- switch (name) {
+ switch (MEMFILE_ATTR(of_cft(of)->private)) {
case RES_LIMIT:
if (mem_cgroup_is_root(memcg)) { /* Can't set limit on root */
ret = -EINVAL;
break;
}
- /* This function does all necessary parse...reuse it */
- ret = res_counter_memparse_write_strategy(buf, &val);
- if (ret)
+ switch (MEMFILE_TYPE(of_cft(of)->private)) {
+ case _MEM:
+ ret = mem_cgroup_resize_limit(memcg, nr_pages);
break;
- if (type == _MEM)
- ret = mem_cgroup_resize_limit(memcg, val);
- else if (type == _MEMSWAP)
- ret = mem_cgroup_resize_memsw_limit(memcg, val);
- else if (type == _KMEM)
- ret = memcg_update_kmem_limit(memcg, val);
- else
- return -EINVAL;
- break;
- case RES_SOFT_LIMIT:
- ret = res_counter_memparse_write_strategy(buf, &val);
- if (ret)
+ case _MEMSWAP:
+ ret = mem_cgroup_resize_memsw_limit(memcg, nr_pages);
break;
- /*
- * For memsw, soft limits are hard to implement in terms
- * of semantics, for now, we support soft limits for
- * control without swap
- */
- if (type == _MEM)
- ret = res_counter_set_soft_limit(&memcg->res, val);
- else
- ret = -EINVAL;
+ case _KMEM:
+ ret = memcg_update_kmem_limit(memcg, nr_pages);
+ break;
+ }
break;
- default:
- ret = -EINVAL; /* should be BUG() ? */
+ case RES_SOFT_LIMIT:
+ memcg->soft_limit = nr_pages;
+ ret = 0;
break;
}
return ret ?: nbytes;
}
-static void memcg_get_hierarchical_limit(struct mem_cgroup *memcg,
- unsigned long long *mem_limit, unsigned long long *memsw_limit)
-{
- unsigned long long min_limit, min_memsw_limit, tmp;
-
- min_limit = res_counter_read_u64(&memcg->res, RES_LIMIT);
- min_memsw_limit = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
- if (!memcg->use_hierarchy)
- goto out;
-
- while (memcg->css.parent) {
- memcg = mem_cgroup_from_css(memcg->css.parent);
- if (!memcg->use_hierarchy)
- break;
- tmp = res_counter_read_u64(&memcg->res, RES_LIMIT);
- min_limit = min(min_limit, tmp);
- tmp = res_counter_read_u64(&memcg->memsw, RES_LIMIT);
- min_memsw_limit = min(min_memsw_limit, tmp);
- }
-out:
- *mem_limit = min_limit;
- *memsw_limit = min_memsw_limit;
-}
-
static ssize_t mem_cgroup_reset(struct kernfs_open_file *of, char *buf,
size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
- int name;
- enum res_type type;
+ struct page_counter *counter;
- type = MEMFILE_TYPE(of_cft(of)->private);
- name = MEMFILE_ATTR(of_cft(of)->private);
+ switch (MEMFILE_TYPE(of_cft(of)->private)) {
+ case _MEM:
+ counter = &memcg->memory;
+ break;
+ case _MEMSWAP:
+ counter = &memcg->memsw;
+ break;
+ case _KMEM:
+ counter = &memcg->kmem;
+ break;
+ default:
+ BUG();
+ }
- switch (name) {
+ switch (MEMFILE_ATTR(of_cft(of)->private)) {
case RES_MAX_USAGE:
- if (type == _MEM)
- res_counter_reset_max(&memcg->res);
- else if (type == _MEMSWAP)
- res_counter_reset_max(&memcg->memsw);
- else if (type == _KMEM)
- res_counter_reset_max(&memcg->kmem);
- else
- return -EINVAL;
+ page_counter_reset_watermark(counter);
break;
case RES_FAILCNT:
- if (type == _MEM)
- res_counter_reset_failcnt(&memcg->res);
- else if (type == _MEMSWAP)
- res_counter_reset_failcnt(&memcg->memsw);
- else if (type == _KMEM)
- res_counter_reset_failcnt(&memcg->kmem);
- else
- return -EINVAL;
+ counter->failcnt = 0;
break;
+ default:
+ BUG();
}
return nbytes;
@@ -4387,6 +3799,7 @@ static inline void mem_cgroup_lru_names_not_uptodate(void)
static int memcg_stat_show(struct seq_file *m, void *v)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
+ unsigned long memory, memsw;
struct mem_cgroup *mi;
unsigned int i;
@@ -4406,14 +3819,16 @@ static int memcg_stat_show(struct seq_file *m, void *v)
mem_cgroup_nr_lru_pages(memcg, BIT(i)) * PAGE_SIZE);
/* Hierarchical information */
- {
- unsigned long long limit, memsw_limit;
- memcg_get_hierarchical_limit(memcg, &limit, &memsw_limit);
- seq_printf(m, "hierarchical_memory_limit %llu\n", limit);
- if (do_swap_account)
- seq_printf(m, "hierarchical_memsw_limit %llu\n",
- memsw_limit);
+ memory = memsw = PAGE_COUNTER_MAX;
+ for (mi = memcg; mi; mi = parent_mem_cgroup(mi)) {
+ memory = min(memory, mi->memory.limit);
+ memsw = min(memsw, mi->memsw.limit);
}
+ seq_printf(m, "hierarchical_memory_limit %llu\n",
+ (u64)memory * PAGE_SIZE);
+ if (do_swap_account)
+ seq_printf(m, "hierarchical_memsw_limit %llu\n",
+ (u64)memsw * PAGE_SIZE);
for (i = 0; i < MEM_CGROUP_STAT_NSTATS; i++) {
long long val = 0;
@@ -4497,7 +3912,7 @@ static int mem_cgroup_swappiness_write(struct cgroup_subsys_state *css,
static void __mem_cgroup_threshold(struct mem_cgroup *memcg, bool swap)
{
struct mem_cgroup_threshold_ary *t;
- u64 usage;
+ unsigned long usage;
int i;
rcu_read_lock();
@@ -4596,10 +4011,11 @@ static int __mem_cgroup_usage_register_event(struct mem_cgroup *memcg,
{
struct mem_cgroup_thresholds *thresholds;
struct mem_cgroup_threshold_ary *new;
- u64 threshold, usage;
+ unsigned long threshold;
+ unsigned long usage;
int i, size, ret;
- ret = res_counter_memparse_write_strategy(args, &threshold);
+ ret = page_counter_memparse(args, &threshold);
if (ret)
return ret;
@@ -4689,7 +4105,7 @@ static void __mem_cgroup_usage_unregister_event(struct mem_cgroup *memcg,
{
struct mem_cgroup_thresholds *thresholds;
struct mem_cgroup_threshold_ary *new;
- u64 usage;
+ unsigned long usage;
int i, j, size;
mutex_lock(&memcg->thresholds_lock);
@@ -4855,40 +4271,6 @@ static void memcg_destroy_kmem(struct mem_cgroup *memcg)
{
mem_cgroup_sockets_destroy(memcg);
}
-
-static void kmem_cgroup_css_offline(struct mem_cgroup *memcg)
-{
- if (!memcg_kmem_is_active(memcg))
- return;
-
- /*
- * kmem charges can outlive the cgroup. In the case of slab
- * pages, for instance, a page contain objects from various
- * processes. As we prevent from taking a reference for every
- * such allocation we have to be careful when doing uncharge
- * (see memcg_uncharge_kmem) and here during offlining.
- *
- * The idea is that that only the _last_ uncharge which sees
- * the dead memcg will drop the last reference. An additional
- * reference is taken here before the group is marked dead
- * which is then paired with css_put during uncharge resp. here.
- *
- * Although this might sound strange as this path is called from
- * css_offline() when the referencemight have dropped down to 0 and
- * shouldn't be incremented anymore (css_tryget_online() would
- * fail) we do not have other options because of the kmem
- * allocations lifetime.
- */
- css_get(&memcg->css);
-
- memcg_kmem_mark_dead(memcg);
-
- if (res_counter_read_u64(&memcg->kmem, RES_USAGE) != 0)
- return;
-
- if (memcg_kmem_test_and_clear_dead(memcg))
- css_put(&memcg->css);
-}
#else
static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
@@ -4898,10 +4280,6 @@ static int memcg_init_kmem(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
static void memcg_destroy_kmem(struct mem_cgroup *memcg)
{
}
-
-static void kmem_cgroup_css_offline(struct mem_cgroup *memcg)
-{
-}
#endif
/*
@@ -5064,7 +4442,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
*
* DO NOT ADD NEW FILES.
*/
- name = cfile.file->f_dentry->d_name.name;
+ name = cfile.file->f_path.dentry->d_name.name;
if (!strcmp(name, "memory.usage_in_bytes")) {
event->register_event = mem_cgroup_usage_register_event;
@@ -5088,7 +4466,7 @@ static ssize_t memcg_write_event_control(struct kernfs_open_file *of,
* automatically removed on cgroup destruction but the removal is
* asynchronous, so take an extra ref on @css.
*/
- cfile_css = css_tryget_online_from_dir(cfile.file->f_dentry->d_parent,
+ cfile_css = css_tryget_online_from_dir(cfile.file->f_path.dentry->d_parent,
&memory_cgrp_subsys);
ret = -EINVAL;
if (IS_ERR(cfile_css))
@@ -5228,7 +4606,10 @@ static struct cftype mem_cgroup_files[] = {
#ifdef CONFIG_SLABINFO
{
.name = "kmem.slabinfo",
- .seq_show = mem_cgroup_slabinfo_read,
+ .seq_start = slab_start,
+ .seq_next = slab_next,
+ .seq_stop = slab_stop,
+ .seq_show = memcg_slab_show,
},
#endif
#endif
@@ -5363,9 +4744,9 @@ static void __mem_cgroup_free(struct mem_cgroup *memcg)
*/
struct mem_cgroup *parent_mem_cgroup(struct mem_cgroup *memcg)
{
- if (!memcg->res.parent)
+ if (!memcg->memory.parent)
return NULL;
- return mem_cgroup_from_res_counter(memcg->res.parent, res);
+ return mem_cgroup_from_counter(memcg->memory.parent, memory);
}
EXPORT_SYMBOL(parent_mem_cgroup);
@@ -5410,9 +4791,9 @@ mem_cgroup_css_alloc(struct cgroup_subsys_state *parent_css)
/* root ? */
if (parent_css == NULL) {
root_mem_cgroup = memcg;
- res_counter_init(&memcg->res, NULL);
- res_counter_init(&memcg->memsw, NULL);
- res_counter_init(&memcg->kmem, NULL);
+ page_counter_init(&memcg->memory, NULL);
+ page_counter_init(&memcg->memsw, NULL);
+ page_counter_init(&memcg->kmem, NULL);
}
memcg->last_scanned_node = MAX_NUMNODES;
@@ -5451,18 +4832,18 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
memcg->swappiness = mem_cgroup_swappiness(parent);
if (parent->use_hierarchy) {
- res_counter_init(&memcg->res, &parent->res);
- res_counter_init(&memcg->memsw, &parent->memsw);
- res_counter_init(&memcg->kmem, &parent->kmem);
+ page_counter_init(&memcg->memory, &parent->memory);
+ page_counter_init(&memcg->memsw, &parent->memsw);
+ page_counter_init(&memcg->kmem, &parent->kmem);
/*
* No need to take a reference to the parent because cgroup
* core guarantees its existence.
*/
} else {
- res_counter_init(&memcg->res, NULL);
- res_counter_init(&memcg->memsw, NULL);
- res_counter_init(&memcg->kmem, NULL);
+ page_counter_init(&memcg->memory, NULL);
+ page_counter_init(&memcg->memsw, NULL);
+ page_counter_init(&memcg->kmem, NULL);
/*
* Deeper hierachy with use_hierarchy == false doesn't make
* much sense so let cgroup subsystem know about this
@@ -5487,29 +4868,10 @@ mem_cgroup_css_online(struct cgroup_subsys_state *css)
return 0;
}
-/*
- * Announce all parents that a group from their hierarchy is gone.
- */
-static void mem_cgroup_invalidate_reclaim_iterators(struct mem_cgroup *memcg)
-{
- struct mem_cgroup *parent = memcg;
-
- while ((parent = parent_mem_cgroup(parent)))
- mem_cgroup_iter_invalidate(parent);
-
- /*
- * if the root memcg is not hierarchical we have to check it
- * explicitely.
- */
- if (!root_mem_cgroup->use_hierarchy)
- mem_cgroup_iter_invalidate(root_mem_cgroup);
-}
-
static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
struct mem_cgroup_event *event, *tmp;
- struct cgroup_subsys_state *iter;
/*
* Unregister events and notify userspace.
@@ -5523,17 +4885,6 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
}
spin_unlock(&memcg->event_list_lock);
- kmem_cgroup_css_offline(memcg);
-
- mem_cgroup_invalidate_reclaim_iterators(memcg);
-
- /*
- * This requires that offlining is serialized. Right now that is
- * guaranteed because css_killed_work_fn() holds the cgroup_mutex.
- */
- css_for_each_descendant_post(iter, css)
- mem_cgroup_reparent_charges(mem_cgroup_from_css(iter));
-
memcg_unregister_all_caches(memcg);
vmpressure_cleanup(&memcg->vmpressure);
}
@@ -5541,42 +4892,6 @@ static void mem_cgroup_css_offline(struct cgroup_subsys_state *css)
static void mem_cgroup_css_free(struct cgroup_subsys_state *css)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
- /*
- * XXX: css_offline() would be where we should reparent all
- * memory to prepare the cgroup for destruction. However,
- * memcg does not do css_tryget_online() and res_counter charging
- * under the same RCU lock region, which means that charging
- * could race with offlining. Offlining only happens to
- * cgroups with no tasks in them but charges can show up
- * without any tasks from the swapin path when the target
- * memcg is looked up from the swapout record and not from the
- * current task as it usually is. A race like this can leak
- * charges and put pages with stale cgroup pointers into
- * circulation:
- *
- * #0 #1
- * lookup_swap_cgroup_id()
- * rcu_read_lock()
- * mem_cgroup_lookup()
- * css_tryget_online()
- * rcu_read_unlock()
- * disable css_tryget_online()
- * call_rcu()
- * offline_css()
- * reparent_charges()
- * res_counter_charge()
- * css_put()
- * css_free()
- * pc->mem_cgroup = dead memcg
- * add page to lru
- *
- * The bulk of the charges are still moved in offline_css() to
- * avoid pinning a lot of pages in case a long-term reference
- * like a swapout record is deferring the css_free() to long
- * after offlining. But this makes sure we catch any charges
- * made after offlining:
- */
- mem_cgroup_reparent_charges(memcg);
memcg_destroy_kmem(memcg);
__mem_cgroup_free(memcg);
@@ -5599,10 +4914,10 @@ static void mem_cgroup_css_reset(struct cgroup_subsys_state *css)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
- mem_cgroup_resize_limit(memcg, ULLONG_MAX);
- mem_cgroup_resize_memsw_limit(memcg, ULLONG_MAX);
- memcg_update_kmem_limit(memcg, ULLONG_MAX);
- res_counter_set_soft_limit(&memcg->res, ULLONG_MAX);
+ mem_cgroup_resize_limit(memcg, PAGE_COUNTER_MAX);
+ mem_cgroup_resize_memsw_limit(memcg, PAGE_COUNTER_MAX);
+ memcg_update_kmem_limit(memcg, PAGE_COUNTER_MAX);
+ memcg->soft_limit = 0;
}
#ifdef CONFIG_MMU
@@ -5758,7 +5073,6 @@ static enum mc_target_type get_mctgt_type(struct vm_area_struct *vma,
unsigned long addr, pte_t ptent, union mc_target *target)
{
struct page *page = NULL;
- struct page_cgroup *pc;
enum mc_target_type ret = MC_TARGET_NONE;
swp_entry_t ent = { .val = 0 };
@@ -5772,13 +5086,12 @@ static enum mc_target_type get_mctgt_type(struct vm_area_struct *vma,
if (!page && !ent.val)
return ret;
if (page) {
- pc = lookup_page_cgroup(page);
/*
* Do only loose check w/o serialization.
- * mem_cgroup_move_account() checks the pc is valid or
+ * mem_cgroup_move_account() checks the page is valid or
* not under LRU exclusion.
*/
- if (PageCgroupUsed(pc) && pc->mem_cgroup == mc.from) {
+ if (page->mem_cgroup == mc.from) {
ret = MC_TARGET_PAGE;
if (target)
target->page = page;
@@ -5806,15 +5119,13 @@ static enum mc_target_type get_mctgt_type_thp(struct vm_area_struct *vma,
unsigned long addr, pmd_t pmd, union mc_target *target)
{
struct page *page = NULL;
- struct page_cgroup *pc;
enum mc_target_type ret = MC_TARGET_NONE;
page = pmd_page(pmd);
VM_BUG_ON_PAGE(!page || !PageHead(page), page);
if (!move_anon())
return ret;
- pc = lookup_page_cgroup(page);
- if (PageCgroupUsed(pc) && pc->mem_cgroup == mc.from) {
+ if (page->mem_cgroup == mc.from) {
ret = MC_TARGET_PAGE;
if (target) {
get_page(page);
@@ -5897,7 +5208,6 @@ static void __mem_cgroup_clear_mc(void)
{
struct mem_cgroup *from = mc.from;
struct mem_cgroup *to = mc.to;
- int i;
/* we must uncharge all the leftover precharges from mc.to */
if (mc.precharge) {
@@ -5916,19 +5226,17 @@ static void __mem_cgroup_clear_mc(void)
if (mc.moved_swap) {
/* uncharge swap account from the old cgroup */
if (!mem_cgroup_is_root(mc.from))
- res_counter_uncharge(&mc.from->memsw,
- PAGE_SIZE * mc.moved_swap);
-
- for (i = 0; i < mc.moved_swap; i++)
- css_put(&mc.from->css);
+ page_counter_uncharge(&mc.from->memsw, mc.moved_swap);
/*
- * we charged both to->res and to->memsw, so we should
- * uncharge to->res.
+ * we charged both to->memory and to->memsw, so we
+ * should uncharge to->memory.
*/
if (!mem_cgroup_is_root(mc.to))
- res_counter_uncharge(&mc.to->res,
- PAGE_SIZE * mc.moved_swap);
+ page_counter_uncharge(&mc.to->memory, mc.moved_swap);
+
+ css_put_many(&mc.from->css, mc.moved_swap);
+
/* we've already done css_get(mc.to) */
mc.moved_swap = 0;
}
@@ -5939,8 +5247,6 @@ static void __mem_cgroup_clear_mc(void)
static void mem_cgroup_clear_mc(void)
{
- struct mem_cgroup *from = mc.from;
-
/*
* we must clear moving_task before waking up waiters at the end of
* task migration.
@@ -5951,7 +5257,6 @@ static void mem_cgroup_clear_mc(void)
mc.from = NULL;
mc.to = NULL;
spin_unlock(&mc.lock);
- mem_cgroup_end_move(from);
}
static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
@@ -5984,7 +5289,7 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
VM_BUG_ON(mc.precharge);
VM_BUG_ON(mc.moved_charge);
VM_BUG_ON(mc.moved_swap);
- mem_cgroup_start_move(from);
+
spin_lock(&mc.lock);
mc.from = from;
mc.to = memcg;
@@ -6004,7 +5309,8 @@ static int mem_cgroup_can_attach(struct cgroup_subsys_state *css,
static void mem_cgroup_cancel_attach(struct cgroup_subsys_state *css,
struct cgroup_taskset *tset)
{
- mem_cgroup_clear_mc();
+ if (mc.to)
+ mem_cgroup_clear_mc();
}
static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
@@ -6018,7 +5324,6 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
enum mc_target_type target_type;
union mc_target target;
struct page *page;
- struct page_cgroup *pc;
/*
* We don't take compound_lock() here but no race with splitting thp
@@ -6039,9 +5344,8 @@ static int mem_cgroup_move_charge_pte_range(pmd_t *pmd,
if (target_type == MC_TARGET_PAGE) {
page = target.page;
if (!isolate_lru_page(page)) {
- pc = lookup_page_cgroup(page);
if (!mem_cgroup_move_account(page, HPAGE_PMD_NR,
- pc, mc.from, mc.to)) {
+ mc.from, mc.to)) {
mc.precharge -= HPAGE_PMD_NR;
mc.moved_charge += HPAGE_PMD_NR;
}
@@ -6069,9 +5373,7 @@ retry:
page = target.page;
if (isolate_lru_page(page))
goto put;
- pc = lookup_page_cgroup(page);
- if (!mem_cgroup_move_account(page, 1, pc,
- mc.from, mc.to)) {
+ if (!mem_cgroup_move_account(page, 1, mc.from, mc.to)) {
mc.precharge--;
/* we uncharge from mc.from later. */
mc.moved_charge++;
@@ -6115,6 +5417,13 @@ static void mem_cgroup_move_charge(struct mm_struct *mm)
struct vm_area_struct *vma;
lru_add_drain_all();
+ /*
+ * Signal mem_cgroup_begin_page_stat() to take the memcg's
+ * move_lock while we're moving its pages to another memcg.
+ * Then wait for already started RCU-only updates to finish.
+ */
+ atomic_inc(&mc.from->moving_account);
+ synchronize_rcu();
retry:
if (unlikely(!down_read_trylock(&mm->mmap_sem))) {
/*
@@ -6147,6 +5456,7 @@ retry:
break;
}
up_read(&mm->mmap_sem);
+ atomic_dec(&mc.from->moving_account);
}
static void mem_cgroup_move_task(struct cgroup_subsys_state *css,
@@ -6250,7 +5560,7 @@ static void __init enable_swap_cgroup(void)
*/
void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
{
- struct page_cgroup *pc;
+ struct mem_cgroup *memcg;
unsigned short oldid;
VM_BUG_ON_PAGE(PageLRU(page), page);
@@ -6259,20 +5569,26 @@ void mem_cgroup_swapout(struct page *page, swp_entry_t entry)
if (!do_swap_account)
return;
- pc = lookup_page_cgroup(page);
+ memcg = page->mem_cgroup;
/* Readahead page, never charged */
- if (!PageCgroupUsed(pc))
+ if (!memcg)
return;
- VM_BUG_ON_PAGE(!(pc->flags & PCG_MEMSW), page);
-
- oldid = swap_cgroup_record(entry, mem_cgroup_id(pc->mem_cgroup));
+ oldid = swap_cgroup_record(entry, mem_cgroup_id(memcg));
VM_BUG_ON_PAGE(oldid, page);
+ mem_cgroup_swap_statistics(memcg, true);
+
+ page->mem_cgroup = NULL;
- pc->flags &= ~PCG_MEMSW;
- css_get(&pc->mem_cgroup->css);
- mem_cgroup_swap_statistics(pc->mem_cgroup, true);
+ if (!mem_cgroup_is_root(memcg))
+ page_counter_uncharge(&memcg->memory, 1);
+
+ /* XXX: caller holds IRQ-safe mapping->tree_lock */
+ VM_BUG_ON(!irqs_disabled());
+
+ mem_cgroup_charge_statistics(memcg, page, -1);
+ memcg_check_events(memcg, page);
}
/**
@@ -6294,7 +5610,7 @@ void mem_cgroup_uncharge_swap(swp_entry_t entry)
memcg = mem_cgroup_lookup(id);
if (memcg) {
if (!mem_cgroup_is_root(memcg))
- res_counter_uncharge(&memcg->memsw, PAGE_SIZE);
+ page_counter_uncharge(&memcg->memsw, 1);
mem_cgroup_swap_statistics(memcg, false);
css_put(&memcg->css);
}
@@ -6330,7 +5646,6 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
goto out;
if (PageSwapCache(page)) {
- struct page_cgroup *pc = lookup_page_cgroup(page);
/*
* Every swap fault against a single page tries to charge the
* page, bail as early as possible. shmem_unuse() encounters
@@ -6338,7 +5653,7 @@ int mem_cgroup_try_charge(struct page *page, struct mm_struct *mm,
* the page lock, which serializes swap cache removal, which
* in turn serializes uncharging.
*/
- if (PageCgroupUsed(pc))
+ if (page->mem_cgroup)
goto out;
}
@@ -6452,19 +5767,16 @@ void mem_cgroup_cancel_charge(struct page *page, struct mem_cgroup *memcg)
}
static void uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout,
- unsigned long nr_mem, unsigned long nr_memsw,
unsigned long nr_anon, unsigned long nr_file,
unsigned long nr_huge, struct page *dummy_page)
{
+ unsigned long nr_pages = nr_anon + nr_file;
unsigned long flags;
if (!mem_cgroup_is_root(memcg)) {
- if (nr_mem)
- res_counter_uncharge(&memcg->res,
- nr_mem * PAGE_SIZE);
- if (nr_memsw)
- res_counter_uncharge(&memcg->memsw,
- nr_memsw * PAGE_SIZE);
+ page_counter_uncharge(&memcg->memory, nr_pages);
+ if (do_swap_account)
+ page_counter_uncharge(&memcg->memsw, nr_pages);
memcg_oom_recover(memcg);
}
@@ -6473,27 +5785,27 @@ static void uncharge_batch(struct mem_cgroup *memcg, unsigned long pgpgout,
__this_cpu_sub(memcg->stat->count[MEM_CGROUP_STAT_CACHE], nr_file);
__this_cpu_sub(memcg->stat->count[MEM_CGROUP_STAT_RSS_HUGE], nr_huge);
__this_cpu_add(memcg->stat->events[MEM_CGROUP_EVENTS_PGPGOUT], pgpgout);
- __this_cpu_add(memcg->stat->nr_page_events, nr_anon + nr_file);
+ __this_cpu_add(memcg->stat->nr_page_events, nr_pages);
memcg_check_events(memcg, dummy_page);
local_irq_restore(flags);
+
+ if (!mem_cgroup_is_root(memcg))
+ css_put_many(&memcg->css, nr_pages);
}
static void uncharge_list(struct list_head *page_list)
{
struct mem_cgroup *memcg = NULL;
- unsigned long nr_memsw = 0;
unsigned long nr_anon = 0;
unsigned long nr_file = 0;
unsigned long nr_huge = 0;
unsigned long pgpgout = 0;
- unsigned long nr_mem = 0;
struct list_head *next;
struct page *page;
next = page_list->next;
do {
unsigned int nr_pages = 1;
- struct page_cgroup *pc;
page = list_entry(next, struct page, lru);
next = page->lru.next;
@@ -6501,24 +5813,22 @@ static void uncharge_list(struct list_head *page_list)
VM_BUG_ON_PAGE(PageLRU(page), page);
VM_BUG_ON_PAGE(page_count(page), page);
- pc = lookup_page_cgroup(page);
- if (!PageCgroupUsed(pc))
+ if (!page->mem_cgroup)
continue;
/*
* Nobody should be changing or seriously looking at
- * pc->mem_cgroup and pc->flags at this point, we have
- * fully exclusive access to the page.
+ * page->mem_cgroup at this point, we have fully
+ * exclusive access to the page.
*/
- if (memcg != pc->mem_cgroup) {
+ if (memcg != page->mem_cgroup) {
if (memcg) {
- uncharge_batch(memcg, pgpgout, nr_mem, nr_memsw,
- nr_anon, nr_file, nr_huge, page);
- pgpgout = nr_mem = nr_memsw = 0;
- nr_anon = nr_file = nr_huge = 0;
+ uncharge_batch(memcg, pgpgout, nr_anon, nr_file,
+ nr_huge, page);
+ pgpgout = nr_anon = nr_file = nr_huge = 0;
}
- memcg = pc->mem_cgroup;
+ memcg = page->mem_cgroup;
}
if (PageTransHuge(page)) {
@@ -6532,18 +5842,14 @@ static void uncharge_list(struct list_head *page_list)
else
nr_file += nr_pages;
- if (pc->flags & PCG_MEM)
- nr_mem += nr_pages;
- if (pc->flags & PCG_MEMSW)
- nr_memsw += nr_pages;
- pc->flags = 0;
+ page->mem_cgroup = NULL;
pgpgout++;
} while (next != page_list);
if (memcg)
- uncharge_batch(memcg, pgpgout, nr_mem, nr_memsw,
- nr_anon, nr_file, nr_huge, page);
+ uncharge_batch(memcg, pgpgout, nr_anon, nr_file,
+ nr_huge, page);
}
/**
@@ -6555,14 +5861,11 @@ static void uncharge_list(struct list_head *page_list)
*/
void mem_cgroup_uncharge(struct page *page)
{
- struct page_cgroup *pc;
-
if (mem_cgroup_disabled())
return;
/* Don't touch page->lru of any random page, pre-check: */
- pc = lookup_page_cgroup(page);
- if (!PageCgroupUsed(pc))
+ if (!page->mem_cgroup)
return;
INIT_LIST_HEAD(&page->lru);
@@ -6598,7 +5901,7 @@ void mem_cgroup_uncharge_list(struct list_head *page_list)
void mem_cgroup_migrate(struct page *oldpage, struct page *newpage,
bool lrucare)
{
- struct page_cgroup *pc;
+ struct mem_cgroup *memcg;
int isolated;
VM_BUG_ON_PAGE(!PageLocked(oldpage), oldpage);
@@ -6613,27 +5916,28 @@ void mem_cgroup_migrate(struct page *oldpage, struct page *newpage,
return;
/* Page cache replacement: new page already charged? */
- pc = lookup_page_cgroup(newpage);
- if (PageCgroupUsed(pc))
+ if (newpage->mem_cgroup)
return;
- /* Re-entrant migration: old page already uncharged? */
- pc = lookup_page_cgroup(oldpage);
- if (!PageCgroupUsed(pc))
+ /*
+ * Swapcache readahead pages can get migrated before being
+ * charged, and migration from compaction can happen to an
+ * uncharged page when the PFN walker finds a page that
+ * reclaim just put back on the LRU but has not released yet.
+ */
+ memcg = oldpage->mem_cgroup;
+ if (!memcg)
return;
- VM_BUG_ON_PAGE(!(pc->flags & PCG_MEM), oldpage);
- VM_BUG_ON_PAGE(do_swap_account && !(pc->flags & PCG_MEMSW), oldpage);
-
if (lrucare)
lock_page_lru(oldpage, &isolated);
- pc->flags = 0;
+ oldpage->mem_cgroup = NULL;
if (lrucare)
unlock_page_lru(oldpage, isolated);
- commit_charge(newpage, pc->mem_cgroup, lrucare);
+ commit_charge(newpage, memcg, lrucare);
}
/*
diff --git a/mm/memory-failure.c b/mm/memory-failure.c
index 8639f6b..e5ee0ca 100644
--- a/mm/memory-failure.c
+++ b/mm/memory-failure.c
@@ -233,7 +233,7 @@ void shake_page(struct page *p, int access)
lru_add_drain_all();
if (PageLRU(p))
return;
- drain_all_pages();
+ drain_all_pages(page_zone(p));
if (PageLRU(p) || is_free_buddy_page(p))
return;
}
@@ -860,7 +860,6 @@ static int page_action(struct page_state *ps, struct page *p,
int count;
result = ps->action(p, pfn);
- action_result(pfn, ps->msg, result);
count = page_count(p) - 1;
if (ps->action == me_swapcache_dirty && result == DELAYED)
@@ -871,6 +870,7 @@ static int page_action(struct page_state *ps, struct page *p,
pfn, ps->msg, count);
result = FAILED;
}
+ action_result(pfn, ps->msg, result);
/* Could do more checks here if page looks ok */
/*
@@ -1661,7 +1661,7 @@ static int __soft_offline_page(struct page *page, int flags)
if (!is_free_buddy_page(page))
lru_add_drain_all();
if (!is_free_buddy_page(page))
- drain_all_pages();
+ drain_all_pages(page_zone(page));
SetPageHWPoison(page);
if (!is_free_buddy_page(page))
pr_info("soft offline: %#lx: page leaked\n",
diff --git a/mm/memory.c b/mm/memory.c
index d5f2ae9..0b3f6c7 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -220,9 +220,6 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long
/* Is it from 0 to ~0? */
tlb->fullmm = !(start | (end+1));
tlb->need_flush_all = 0;
- tlb->start = start;
- tlb->end = end;
- tlb->need_flush = 0;
tlb->local.next = NULL;
tlb->local.nr = 0;
tlb->local.max = ARRAY_SIZE(tlb->__pages);
@@ -232,15 +229,20 @@ void tlb_gather_mmu(struct mmu_gather *tlb, struct mm_struct *mm, unsigned long
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
tlb->batch = NULL;
#endif
+
+ __tlb_reset_range(tlb);
}
static void tlb_flush_mmu_tlbonly(struct mmu_gather *tlb)
{
- tlb->need_flush = 0;
+ if (!tlb->end)
+ return;
+
tlb_flush(tlb);
#ifdef CONFIG_HAVE_RCU_TABLE_FREE
tlb_table_flush(tlb);
#endif
+ __tlb_reset_range(tlb);
}
static void tlb_flush_mmu_free(struct mmu_gather *tlb)
@@ -256,8 +258,6 @@ static void tlb_flush_mmu_free(struct mmu_gather *tlb)
void tlb_flush_mmu(struct mmu_gather *tlb)
{
- if (!tlb->need_flush)
- return;
tlb_flush_mmu_tlbonly(tlb);
tlb_flush_mmu_free(tlb);
}
@@ -292,7 +292,7 @@ int __tlb_remove_page(struct mmu_gather *tlb, struct page *page)
{
struct mmu_gather_batch *batch;
- VM_BUG_ON(!tlb->need_flush);
+ VM_BUG_ON(!tlb->end);
batch = tlb->active;
batch->pages[batch->nr++] = page;
@@ -359,8 +359,6 @@ void tlb_remove_table(struct mmu_gather *tlb, void *table)
{
struct mmu_table_batch **batch = &tlb->batch;
- tlb->need_flush = 1;
-
/*
* When there's less then two users of this mm there cannot be a
* concurrent page-table walk.
@@ -1186,20 +1184,8 @@ again:
arch_leave_lazy_mmu_mode();
/* Do the actual TLB flush before dropping ptl */
- if (force_flush) {
- unsigned long old_end;
-
- /*
- * Flush the TLB just for the previous segment,
- * then update the range to be the remaining
- * TLB range.
- */
- old_end = tlb->end;
- tlb->end = addr;
+ if (force_flush)
tlb_flush_mmu_tlbonly(tlb);
- tlb->start = addr;
- tlb->end = old_end;
- }
pte_unmap_unlock(start_pte, ptl);
/*
diff --git a/mm/memory_hotplug.c b/mm/memory_hotplug.c
index 1bf4807..9fab107 100644
--- a/mm/memory_hotplug.c
+++ b/mm/memory_hotplug.c
@@ -1725,7 +1725,7 @@ repeat:
if (drain) {
lru_add_drain_all();
cond_resched();
- drain_all_pages();
+ drain_all_pages(zone);
}
pfn = scan_movable_pages(start_pfn, end_pfn);
@@ -1747,7 +1747,7 @@ repeat:
lru_add_drain_all();
yield();
/* drain pcp pages, this is synchronous. */
- drain_all_pages();
+ drain_all_pages(zone);
/*
* dissolve free hugepages in the memory block before doing offlining
* actually in order to make hugetlbfs's object counting consistent.
diff --git a/mm/mmap.c b/mm/mmap.c
index ae91989..b6c0a77 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -2601,6 +2601,8 @@ int do_munmap(struct mm_struct *mm, unsigned long start, size_t len)
detach_vmas_to_be_unmapped(mm, vma, prev, end);
unmap_region(mm, vma, prev, start, end);
+ arch_unmap(mm, vma, start, end);
+
/* Fix up all other VM information */
remove_vma_list(mm, vma);
diff --git a/mm/oom_kill.c b/mm/oom_kill.c
index 5340f6b..3b014d3 100644
--- a/mm/oom_kill.c
+++ b/mm/oom_kill.c
@@ -119,7 +119,7 @@ found:
/* return true if the task is not adequate as candidate victim task. */
static bool oom_unkillable_task(struct task_struct *p,
- const struct mem_cgroup *memcg, const nodemask_t *nodemask)
+ struct mem_cgroup *memcg, const nodemask_t *nodemask)
{
if (is_global_init(p))
return true;
@@ -353,7 +353,7 @@ static struct task_struct *select_bad_process(unsigned int *ppoints,
* State information includes task's pid, uid, tgid, vm size, rss, nr_ptes,
* swapents, oom_score_adj value, and name.
*/
-static void dump_tasks(const struct mem_cgroup *memcg, const nodemask_t *nodemask)
+static void dump_tasks(struct mem_cgroup *memcg, const nodemask_t *nodemask)
{
struct task_struct *p;
struct task_struct *task;
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 19ceae8..d5d81f5 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2357,7 +2357,7 @@ int test_clear_page_writeback(struct page *page)
dec_zone_page_state(page, NR_WRITEBACK);
inc_zone_page_state(page, NR_WRITTEN);
}
- mem_cgroup_end_page_stat(memcg, locked, memcg_flags);
+ mem_cgroup_end_page_stat(memcg, &locked, &memcg_flags);
return ret;
}
@@ -2399,7 +2399,7 @@ int __test_set_page_writeback(struct page *page, bool keep_write)
mem_cgroup_inc_page_stat(memcg, MEM_CGROUP_STAT_WRITEBACK);
inc_zone_page_state(page, NR_WRITEBACK);
}
- mem_cgroup_end_page_stat(memcg, locked, memcg_flags);
+ mem_cgroup_end_page_stat(memcg, &locked, &memcg_flags);
return ret;
}
diff --git a/mm/page_alloc.c b/mm/page_alloc.c
index 616a2c9..a7198c0 100644
--- a/mm/page_alloc.c
+++ b/mm/page_alloc.c
@@ -48,7 +48,6 @@
#include <linux/backing-dev.h>
#include <linux/fault-inject.h>
#include <linux/page-isolation.h>
-#include <linux/page_cgroup.h>
#include <linux/debugobjects.h>
#include <linux/kmemleak.h>
#include <linux/compaction.h>
@@ -641,8 +640,10 @@ static inline int free_pages_check(struct page *page)
bad_reason = "PAGE_FLAGS_CHECK_AT_FREE flag(s) set";
bad_flags = PAGE_FLAGS_CHECK_AT_FREE;
}
- if (unlikely(mem_cgroup_bad_page_check(page)))
- bad_reason = "cgroup check failed";
+#ifdef CONFIG_MEMCG
+ if (unlikely(page->mem_cgroup))
+ bad_reason = "page still charged to cgroup";
+#endif
if (unlikely(bad_reason)) {
bad_page(page, bad_reason, bad_flags);
return 1;
@@ -741,6 +742,9 @@ static bool free_pages_prepare(struct page *page, unsigned int order)
int i;
int bad = 0;
+ VM_BUG_ON_PAGE(PageTail(page), page);
+ VM_BUG_ON_PAGE(PageHead(page) && compound_order(page) != order, page);
+
trace_mm_page_free(page, order);
kmemcheck_free_shadow(page, order);
@@ -898,8 +902,10 @@ static inline int check_new_page(struct page *page)
bad_reason = "PAGE_FLAGS_CHECK_AT_PREP flag set";
bad_flags = PAGE_FLAGS_CHECK_AT_PREP;
}
- if (unlikely(mem_cgroup_bad_page_check(page)))
- bad_reason = "cgroup check failed";
+#ifdef CONFIG_MEMCG
+ if (unlikely(page->mem_cgroup))
+ bad_reason = "page still charged to cgroup";
+#endif
if (unlikely(bad_reason)) {
bad_page(page, bad_reason, bad_flags);
return 1;
@@ -1267,55 +1273,75 @@ void drain_zone_pages(struct zone *zone, struct per_cpu_pages *pcp)
#endif
/*
- * Drain pages of the indicated processor.
+ * Drain pcplists of the indicated processor and zone.
*
* The processor must either be the current processor and the
* thread pinned to the current processor or a processor that
* is not online.
*/
-static void drain_pages(unsigned int cpu)
+static void drain_pages_zone(unsigned int cpu, struct zone *zone)
{
unsigned long flags;
- struct zone *zone;
+ struct per_cpu_pageset *pset;
+ struct per_cpu_pages *pcp;
- for_each_populated_zone(zone) {
- struct per_cpu_pageset *pset;
- struct per_cpu_pages *pcp;
+ local_irq_save(flags);
+ pset = per_cpu_ptr(zone->pageset, cpu);
- local_irq_save(flags);
- pset = per_cpu_ptr(zone->pageset, cpu);
+ pcp = &pset->pcp;
+ if (pcp->count) {
+ free_pcppages_bulk(zone, pcp->count, pcp);
+ pcp->count = 0;
+ }
+ local_irq_restore(flags);
+}
- pcp = &pset->pcp;
- if (pcp->count) {
- free_pcppages_bulk(zone, pcp->count, pcp);
- pcp->count = 0;
- }
- local_irq_restore(flags);
+/*
+ * Drain pcplists of all zones on the indicated processor.
+ *
+ * The processor must either be the current processor and the
+ * thread pinned to the current processor or a processor that
+ * is not online.
+ */
+static void drain_pages(unsigned int cpu)
+{
+ struct zone *zone;
+
+ for_each_populated_zone(zone) {
+ drain_pages_zone(cpu, zone);
}
}
/*
* Spill all of this CPU's per-cpu pages back into the buddy allocator.
+ *
+ * The CPU has to be pinned. When zone parameter is non-NULL, spill just
+ * the single zone's pages.
*/
-void drain_local_pages(void *arg)
+void drain_local_pages(struct zone *zone)
{
- drain_pages(smp_processor_id());
+ int cpu = smp_processor_id();
+
+ if (zone)
+ drain_pages_zone(cpu, zone);
+ else
+ drain_pages(cpu);
}
/*
* Spill all the per-cpu pages from all CPUs back into the buddy allocator.
*
+ * When zone parameter is non-NULL, spill just the single zone's pages.
+ *
* Note that this code is protected against sending an IPI to an offline
* CPU but does not guarantee sending an IPI to newly hotplugged CPUs:
* on_each_cpu_mask() blocks hotplug and won't talk to offlined CPUs but
* nothing keeps CPUs from showing up after we populated the cpumask and
* before the call to on_each_cpu_mask().
*/
-void drain_all_pages(void)
+void drain_all_pages(struct zone *zone)
{
int cpu;
- struct per_cpu_pageset *pcp;
- struct zone *zone;
/*
* Allocate in the BSS so we wont require allocation in
@@ -1330,20 +1356,31 @@ void drain_all_pages(void)
* disables preemption as part of its processing
*/
for_each_online_cpu(cpu) {
+ struct per_cpu_pageset *pcp;
+ struct zone *z;
bool has_pcps = false;
- for_each_populated_zone(zone) {
+
+ if (zone) {
pcp = per_cpu_ptr(zone->pageset, cpu);
- if (pcp->pcp.count) {
+ if (pcp->pcp.count)
has_pcps = true;
- break;
+ } else {
+ for_each_populated_zone(z) {
+ pcp = per_cpu_ptr(z->pageset, cpu);
+ if (pcp->pcp.count) {
+ has_pcps = true;
+ break;
+ }
}
}
+
if (has_pcps)
cpumask_set_cpu(cpu, &cpus_with_pcps);
else
cpumask_clear_cpu(cpu, &cpus_with_pcps);
}
- on_each_cpu_mask(&cpus_with_pcps, drain_local_pages, NULL, 1);
+ on_each_cpu_mask(&cpus_with_pcps, (smp_call_func_t) drain_local_pages,
+ zone, 1);
}
#ifdef CONFIG_HIBERNATION
@@ -1705,7 +1742,7 @@ static bool __zone_watermark_ok(struct zone *z, unsigned int order,
unsigned long mark, int classzone_idx, int alloc_flags,
long free_pages)
{
- /* free_pages my go negative - that's OK */
+ /* free_pages may go negative - that's OK */
long min = mark;
int o;
long free_cma = 0;
@@ -2296,7 +2333,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
int classzone_idx, int migratetype, enum migrate_mode mode,
int *contended_compaction, bool *deferred_compaction)
{
- struct zone *last_compact_zone = NULL;
unsigned long compact_result;
struct page *page;
@@ -2307,7 +2343,7 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
compact_result = try_to_compact_pages(zonelist, order, gfp_mask,
nodemask, mode,
contended_compaction,
- &last_compact_zone);
+ alloc_flags, classzone_idx);
current->flags &= ~PF_MEMALLOC;
switch (compact_result) {
@@ -2326,10 +2362,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
*/
count_vm_event(COMPACTSTALL);
- /* Page migration frees to the PCP lists but we want merging */
- drain_pages(get_cpu());
- put_cpu();
-
page = get_page_from_freelist(gfp_mask, nodemask,
order, zonelist, high_zoneidx,
alloc_flags & ~ALLOC_NO_WATERMARKS,
@@ -2345,14 +2377,6 @@ __alloc_pages_direct_compact(gfp_t gfp_mask, unsigned int order,
}
/*
- * last_compact_zone is where try_to_compact_pages thought allocation
- * should succeed, so it did not defer compaction. But here we know
- * that it didn't succeed, so we do the defer.
- */
- if (last_compact_zone && mode != MIGRATE_ASYNC)
- defer_compaction(last_compact_zone, order);
-
- /*
* It's bad if compaction run occurs and fails. The most likely reason
* is that pages exist, but not enough to satisfy watermarks.
*/
@@ -2433,7 +2457,7 @@ retry:
* pages are pinned on the per-cpu lists. Drain them and try again
*/
if (!page && !drained) {
- drain_all_pages();
+ drain_all_pages(NULL);
drained = true;
goto retry;
}
@@ -3893,14 +3917,14 @@ void __ref build_all_zonelists(pg_data_t *pgdat, struct zone *zone)
else
page_group_by_mobility_disabled = 0;
- printk("Built %i zonelists in %s order, mobility grouping %s. "
+ pr_info("Built %i zonelists in %s order, mobility grouping %s. "
"Total pages: %ld\n",
nr_online_nodes,
zonelist_order_name[current_zonelist_order],
page_group_by_mobility_disabled ? "off" : "on",
vm_total_pages);
#ifdef CONFIG_NUMA
- printk("Policy zone: %s\n", zone_names[policy_zone]);
+ pr_info("Policy zone: %s\n", zone_names[policy_zone]);
#endif
}
@@ -4832,7 +4856,6 @@ static void __paginginit free_area_init_core(struct pglist_data *pgdat,
#endif
init_waitqueue_head(&pgdat->kswapd_wait);
init_waitqueue_head(&pgdat->pfmemalloc_wait);
- pgdat_page_cgroup_init(pgdat);
for (j = 0; j < MAX_NR_ZONES; j++) {
struct zone *zone = pgdat->node_zones + j;
@@ -5334,33 +5357,33 @@ void __init free_area_init_nodes(unsigned long *max_zone_pfn)
find_zone_movable_pfns_for_nodes();
/* Print out the zone ranges */
- printk("Zone ranges:\n");
+ pr_info("Zone ranges:\n");
for (i = 0; i < MAX_NR_ZONES; i++) {
if (i == ZONE_MOVABLE)
continue;
- printk(KERN_CONT " %-8s ", zone_names[i]);
+ pr_info(" %-8s ", zone_names[i]);
if (arch_zone_lowest_possible_pfn[i] ==
arch_zone_highest_possible_pfn[i])
- printk(KERN_CONT "empty\n");
+ pr_cont("empty\n");
else
- printk(KERN_CONT "[mem %0#10lx-%0#10lx]\n",
+ pr_cont("[mem %0#10lx-%0#10lx]\n",
arch_zone_lowest_possible_pfn[i] << PAGE_SHIFT,
(arch_zone_highest_possible_pfn[i]
<< PAGE_SHIFT) - 1);
}
/* Print out the PFNs ZONE_MOVABLE begins at in each node */
- printk("Movable zone start for each node\n");
+ pr_info("Movable zone start for each node\n");
for (i = 0; i < MAX_NUMNODES; i++) {
if (zone_movable_pfn[i])
- printk(" Node %d: %#010lx\n", i,
+ pr_info(" Node %d: %#010lx\n", i,
zone_movable_pfn[i] << PAGE_SHIFT);
}
/* Print out the early node map */
- printk("Early memory node ranges\n");
+ pr_info("Early memory node ranges\n");
for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid)
- printk(" node %3d: [mem %#010lx-%#010lx]\n", nid,
+ pr_info(" node %3d: [mem %#010lx-%#010lx]\n", nid,
start_pfn << PAGE_SHIFT, (end_pfn << PAGE_SHIFT) - 1);
/* Initialise every node */
@@ -5496,7 +5519,7 @@ void __init mem_init_print_info(const char *str)
#undef adj_init_size
- printk("Memory: %luK/%luK available "
+ pr_info("Memory: %luK/%luK available "
"(%luK kernel code, %luK rwdata, %luK rodata, "
"%luK init, %luK bss, %luK reserved"
#ifdef CONFIG_HIGHMEM
@@ -6385,7 +6408,7 @@ int alloc_contig_range(unsigned long start, unsigned long end,
*/
lru_add_drain_all();
- drain_all_pages();
+ drain_all_pages(cc.zone);
order = 0;
outer_start = start;
diff --git a/mm/page_cgroup.c b/mm/page_cgroup.c
deleted file mode 100644
index 5331c2b..0000000
--- a/mm/page_cgroup.c
+++ /dev/null
@@ -1,530 +0,0 @@
-#include <linux/mm.h>
-#include <linux/mmzone.h>
-#include <linux/bootmem.h>
-#include <linux/bit_spinlock.h>
-#include <linux/page_cgroup.h>
-#include <linux/hash.h>
-#include <linux/slab.h>
-#include <linux/memory.h>
-#include <linux/vmalloc.h>
-#include <linux/cgroup.h>
-#include <linux/swapops.h>
-#include <linux/kmemleak.h>
-
-static unsigned long total_usage;
-
-#if !defined(CONFIG_SPARSEMEM)
-
-
-void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
-{
- pgdat->node_page_cgroup = NULL;
-}
-
-struct page_cgroup *lookup_page_cgroup(struct page *page)
-{
- unsigned long pfn = page_to_pfn(page);
- unsigned long offset;
- struct page_cgroup *base;
-
- base = NODE_DATA(page_to_nid(page))->node_page_cgroup;
-#ifdef CONFIG_DEBUG_VM
- /*
- * The sanity checks the page allocator does upon freeing a
- * page can reach here before the page_cgroup arrays are
- * allocated when feeding a range of pages to the allocator
- * for the first time during bootup or memory hotplug.
- */
- if (unlikely(!base))
- return NULL;
-#endif
- offset = pfn - NODE_DATA(page_to_nid(page))->node_start_pfn;
- return base + offset;
-}
-
-static int __init alloc_node_page_cgroup(int nid)
-{
- struct page_cgroup *base;
- unsigned long table_size;
- unsigned long nr_pages;
-
- nr_pages = NODE_DATA(nid)->node_spanned_pages;
- if (!nr_pages)
- return 0;
-
- table_size = sizeof(struct page_cgroup) * nr_pages;
-
- base = memblock_virt_alloc_try_nid_nopanic(
- table_size, PAGE_SIZE, __pa(MAX_DMA_ADDRESS),
- BOOTMEM_ALLOC_ACCESSIBLE, nid);
- if (!base)
- return -ENOMEM;
- NODE_DATA(nid)->node_page_cgroup = base;
- total_usage += table_size;
- return 0;
-}
-
-void __init page_cgroup_init_flatmem(void)
-{
-
- int nid, fail;
-
- if (mem_cgroup_disabled())
- return;
-
- for_each_online_node(nid) {
- fail = alloc_node_page_cgroup(nid);
- if (fail)
- goto fail;
- }
- printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage);
- printk(KERN_INFO "please try 'cgroup_disable=memory' option if you"
- " don't want memory cgroups\n");
- return;
-fail:
- printk(KERN_CRIT "allocation of page_cgroup failed.\n");
- printk(KERN_CRIT "please try 'cgroup_disable=memory' boot option\n");
- panic("Out of memory");
-}
-
-#else /* CONFIG_FLAT_NODE_MEM_MAP */
-
-struct page_cgroup *lookup_page_cgroup(struct page *page)
-{
- unsigned long pfn = page_to_pfn(page);
- struct mem_section *section = __pfn_to_section(pfn);
-#ifdef CONFIG_DEBUG_VM
- /*
- * The sanity checks the page allocator does upon freeing a
- * page can reach here before the page_cgroup arrays are
- * allocated when feeding a range of pages to the allocator
- * for the first time during bootup or memory hotplug.
- */
- if (!section->page_cgroup)
- return NULL;
-#endif
- return section->page_cgroup + pfn;
-}
-
-static void *__meminit alloc_page_cgroup(size_t size, int nid)
-{
- gfp_t flags = GFP_KERNEL | __GFP_ZERO | __GFP_NOWARN;
- void *addr = NULL;
-
- addr = alloc_pages_exact_nid(nid, size, flags);
- if (addr) {
- kmemleak_alloc(addr, size, 1, flags);
- return addr;
- }
-
- if (node_state(nid, N_HIGH_MEMORY))
- addr = vzalloc_node(size, nid);
- else
- addr = vzalloc(size);
-
- return addr;
-}
-
-static int __meminit init_section_page_cgroup(unsigned long pfn, int nid)
-{
- struct mem_section *section;
- struct page_cgroup *base;
- unsigned long table_size;
-
- section = __pfn_to_section(pfn);
-
- if (section->page_cgroup)
- return 0;
-
- table_size = sizeof(struct page_cgroup) * PAGES_PER_SECTION;
- base = alloc_page_cgroup(table_size, nid);
-
- /*
- * The value stored in section->page_cgroup is (base - pfn)
- * and it does not point to the memory block allocated above,
- * causing kmemleak false positives.
- */
- kmemleak_not_leak(base);
-
- if (!base) {
- printk(KERN_ERR "page cgroup allocation failure\n");
- return -ENOMEM;
- }
-
- /*
- * The passed "pfn" may not be aligned to SECTION. For the calculation
- * we need to apply a mask.
- */
- pfn &= PAGE_SECTION_MASK;
- section->page_cgroup = base - pfn;
- total_usage += table_size;
- return 0;
-}
-#ifdef CONFIG_MEMORY_HOTPLUG
-static void free_page_cgroup(void *addr)
-{
- if (is_vmalloc_addr(addr)) {
- vfree(addr);
- } else {
- struct page *page = virt_to_page(addr);
- size_t table_size =
- sizeof(struct page_cgroup) * PAGES_PER_SECTION;
-
- BUG_ON(PageReserved(page));
- kmemleak_free(addr);
- free_pages_exact(addr, table_size);
- }
-}
-
-static void __free_page_cgroup(unsigned long pfn)
-{
- struct mem_section *ms;
- struct page_cgroup *base;
-
- ms = __pfn_to_section(pfn);
- if (!ms || !ms->page_cgroup)
- return;
- base = ms->page_cgroup + pfn;
- free_page_cgroup(base);
- ms->page_cgroup = NULL;
-}
-
-static int __meminit online_page_cgroup(unsigned long start_pfn,
- unsigned long nr_pages,
- int nid)
-{
- unsigned long start, end, pfn;
- int fail = 0;
-
- start = SECTION_ALIGN_DOWN(start_pfn);
- end = SECTION_ALIGN_UP(start_pfn + nr_pages);
-
- if (nid == -1) {
- /*
- * In this case, "nid" already exists and contains valid memory.
- * "start_pfn" passed to us is a pfn which is an arg for
- * online__pages(), and start_pfn should exist.
- */
- nid = pfn_to_nid(start_pfn);
- VM_BUG_ON(!node_state(nid, N_ONLINE));
- }
-
- for (pfn = start; !fail && pfn < end; pfn += PAGES_PER_SECTION) {
- if (!pfn_present(pfn))
- continue;
- fail = init_section_page_cgroup(pfn, nid);
- }
- if (!fail)
- return 0;
-
- /* rollback */
- for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION)
- __free_page_cgroup(pfn);
-
- return -ENOMEM;
-}
-
-static int __meminit offline_page_cgroup(unsigned long start_pfn,
- unsigned long nr_pages, int nid)
-{
- unsigned long start, end, pfn;
-
- start = SECTION_ALIGN_DOWN(start_pfn);
- end = SECTION_ALIGN_UP(start_pfn + nr_pages);
-
- for (pfn = start; pfn < end; pfn += PAGES_PER_SECTION)
- __free_page_cgroup(pfn);
- return 0;
-
-}
-
-static int __meminit page_cgroup_callback(struct notifier_block *self,
- unsigned long action, void *arg)
-{
- struct memory_notify *mn = arg;
- int ret = 0;
- switch (action) {
- case MEM_GOING_ONLINE:
- ret = online_page_cgroup(mn->start_pfn,
- mn->nr_pages, mn->status_change_nid);
- break;
- case MEM_OFFLINE:
- offline_page_cgroup(mn->start_pfn,
- mn->nr_pages, mn->status_change_nid);
- break;
- case MEM_CANCEL_ONLINE:
- offline_page_cgroup(mn->start_pfn,
- mn->nr_pages, mn->status_change_nid);
- break;
- case MEM_GOING_OFFLINE:
- break;
- case MEM_ONLINE:
- case MEM_CANCEL_OFFLINE:
- break;
- }
-
- return notifier_from_errno(ret);
-}
-
-#endif
-
-void __init page_cgroup_init(void)
-{
- unsigned long pfn;
- int nid;
-
- if (mem_cgroup_disabled())
- return;
-
- for_each_node_state(nid, N_MEMORY) {
- unsigned long start_pfn, end_pfn;
-
- start_pfn = node_start_pfn(nid);
- end_pfn = node_end_pfn(nid);
- /*
- * start_pfn and end_pfn may not be aligned to SECTION and the
- * page->flags of out of node pages are not initialized. So we
- * scan [start_pfn, the biggest section's pfn < end_pfn) here.
- */
- for (pfn = start_pfn;
- pfn < end_pfn;
- pfn = ALIGN(pfn + 1, PAGES_PER_SECTION)) {
-
- if (!pfn_valid(pfn))
- continue;
- /*
- * Nodes's pfns can be overlapping.
- * We know some arch can have a nodes layout such as
- * -------------pfn-------------->
- * N0 | N1 | N2 | N0 | N1 | N2|....
- */
- if (pfn_to_nid(pfn) != nid)
- continue;
- if (init_section_page_cgroup(pfn, nid))
- goto oom;
- }
- }
- hotplug_memory_notifier(page_cgroup_callback, 0);
- printk(KERN_INFO "allocated %ld bytes of page_cgroup\n", total_usage);
- printk(KERN_INFO "please try 'cgroup_disable=memory' option if you "
- "don't want memory cgroups\n");
- return;
-oom:
- printk(KERN_CRIT "try 'cgroup_disable=memory' boot option\n");
- panic("Out of memory");
-}
-
-void __meminit pgdat_page_cgroup_init(struct pglist_data *pgdat)
-{
- return;
-}
-
-#endif
-
-
-#ifdef CONFIG_MEMCG_SWAP
-
-static DEFINE_MUTEX(swap_cgroup_mutex);
-struct swap_cgroup_ctrl {
- struct page **map;
- unsigned long length;
- spinlock_t lock;
-};
-
-static struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
-
-struct swap_cgroup {
- unsigned short id;
-};
-#define SC_PER_PAGE (PAGE_SIZE/sizeof(struct swap_cgroup))
-
-/*
- * SwapCgroup implements "lookup" and "exchange" operations.
- * In typical usage, this swap_cgroup is accessed via memcg's charge/uncharge
- * against SwapCache. At swap_free(), this is accessed directly from swap.
- *
- * This means,
- * - we have no race in "exchange" when we're accessed via SwapCache because
- * SwapCache(and its swp_entry) is under lock.
- * - When called via swap_free(), there is no user of this entry and no race.
- * Then, we don't need lock around "exchange".
- *
- * TODO: we can push these buffers out to HIGHMEM.
- */
-
-/*
- * allocate buffer for swap_cgroup.
- */
-static int swap_cgroup_prepare(int type)
-{
- struct page *page;
- struct swap_cgroup_ctrl *ctrl;
- unsigned long idx, max;
-
- ctrl = &swap_cgroup_ctrl[type];
-
- for (idx = 0; idx < ctrl->length; idx++) {
- page = alloc_page(GFP_KERNEL | __GFP_ZERO);
- if (!page)
- goto not_enough_page;
- ctrl->map[idx] = page;
- }
- return 0;
-not_enough_page:
- max = idx;
- for (idx = 0; idx < max; idx++)
- __free_page(ctrl->map[idx]);
-
- return -ENOMEM;
-}
-
-static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
- struct swap_cgroup_ctrl **ctrlp)
-{
- pgoff_t offset = swp_offset(ent);
- struct swap_cgroup_ctrl *ctrl;
- struct page *mappage;
- struct swap_cgroup *sc;
-
- ctrl = &swap_cgroup_ctrl[swp_type(ent)];
- if (ctrlp)
- *ctrlp = ctrl;
-
- mappage = ctrl->map[offset / SC_PER_PAGE];
- sc = page_address(mappage);
- return sc + offset % SC_PER_PAGE;
-}
-
-/**
- * swap_cgroup_cmpxchg - cmpxchg mem_cgroup's id for this swp_entry.
- * @ent: swap entry to be cmpxchged
- * @old: old id
- * @new: new id
- *
- * Returns old id at success, 0 at failure.
- * (There is no mem_cgroup using 0 as its id)
- */
-unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
- unsigned short old, unsigned short new)
-{
- struct swap_cgroup_ctrl *ctrl;
- struct swap_cgroup *sc;
- unsigned long flags;
- unsigned short retval;
-
- sc = lookup_swap_cgroup(ent, &ctrl);
-
- spin_lock_irqsave(&ctrl->lock, flags);
- retval = sc->id;
- if (retval == old)
- sc->id = new;
- else
- retval = 0;
- spin_unlock_irqrestore(&ctrl->lock, flags);
- return retval;
-}
-
-/**
- * swap_cgroup_record - record mem_cgroup for this swp_entry.
- * @ent: swap entry to be recorded into
- * @id: mem_cgroup to be recorded
- *
- * Returns old value at success, 0 at failure.
- * (Of course, old value can be 0.)
- */
-unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
-{
- struct swap_cgroup_ctrl *ctrl;
- struct swap_cgroup *sc;
- unsigned short old;
- unsigned long flags;
-
- sc = lookup_swap_cgroup(ent, &ctrl);
-
- spin_lock_irqsave(&ctrl->lock, flags);
- old = sc->id;
- sc->id = id;
- spin_unlock_irqrestore(&ctrl->lock, flags);
-
- return old;
-}
-
-/**
- * lookup_swap_cgroup_id - lookup mem_cgroup id tied to swap entry
- * @ent: swap entry to be looked up.
- *
- * Returns ID of mem_cgroup at success. 0 at failure. (0 is invalid ID)
- */
-unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
-{
- return lookup_swap_cgroup(ent, NULL)->id;
-}
-
-int swap_cgroup_swapon(int type, unsigned long max_pages)
-{
- void *array;
- unsigned long array_size;
- unsigned long length;
- struct swap_cgroup_ctrl *ctrl;
-
- if (!do_swap_account)
- return 0;
-
- length = DIV_ROUND_UP(max_pages, SC_PER_PAGE);
- array_size = length * sizeof(void *);
-
- array = vzalloc(array_size);
- if (!array)
- goto nomem;
-
- ctrl = &swap_cgroup_ctrl[type];
- mutex_lock(&swap_cgroup_mutex);
- ctrl->length = length;
- ctrl->map = array;
- spin_lock_init(&ctrl->lock);
- if (swap_cgroup_prepare(type)) {
- /* memory shortage */
- ctrl->map = NULL;
- ctrl->length = 0;
- mutex_unlock(&swap_cgroup_mutex);
- vfree(array);
- goto nomem;
- }
- mutex_unlock(&swap_cgroup_mutex);
-
- return 0;
-nomem:
- printk(KERN_INFO "couldn't allocate enough memory for swap_cgroup.\n");
- printk(KERN_INFO
- "swap_cgroup can be disabled by swapaccount=0 boot option\n");
- return -ENOMEM;
-}
-
-void swap_cgroup_swapoff(int type)
-{
- struct page **map;
- unsigned long i, length;
- struct swap_cgroup_ctrl *ctrl;
-
- if (!do_swap_account)
- return;
-
- mutex_lock(&swap_cgroup_mutex);
- ctrl = &swap_cgroup_ctrl[type];
- map = ctrl->map;
- length = ctrl->length;
- ctrl->map = NULL;
- ctrl->length = 0;
- mutex_unlock(&swap_cgroup_mutex);
-
- if (map) {
- for (i = 0; i < length; i++) {
- struct page *page = map[i];
- if (page)
- __free_page(page);
- }
- vfree(map);
- }
-}
-
-#endif
diff --git a/mm/page_counter.c b/mm/page_counter.c
new file mode 100644
index 0000000..a009574
--- /dev/null
+++ b/mm/page_counter.c
@@ -0,0 +1,192 @@
+/*
+ * Lockless hierarchical page accounting & limiting
+ *
+ * Copyright (C) 2014 Red Hat, Inc., Johannes Weiner
+ */
+
+#include <linux/page_counter.h>
+#include <linux/atomic.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/bug.h>
+#include <asm/page.h>
+
+/**
+ * page_counter_cancel - take pages out of the local counter
+ * @counter: counter
+ * @nr_pages: number of pages to cancel
+ */
+void page_counter_cancel(struct page_counter *counter, unsigned long nr_pages)
+{
+ long new;
+
+ new = atomic_long_sub_return(nr_pages, &counter->count);
+ /* More uncharges than charges? */
+ WARN_ON_ONCE(new < 0);
+}
+
+/**
+ * page_counter_charge - hierarchically charge pages
+ * @counter: counter
+ * @nr_pages: number of pages to charge
+ *
+ * NOTE: This does not consider any configured counter limits.
+ */
+void page_counter_charge(struct page_counter *counter, unsigned long nr_pages)
+{
+ struct page_counter *c;
+
+ for (c = counter; c; c = c->parent) {
+ long new;
+
+ new = atomic_long_add_return(nr_pages, &c->count);
+ /*
+ * This is indeed racy, but we can live with some
+ * inaccuracy in the watermark.
+ */
+ if (new > c->watermark)
+ c->watermark = new;
+ }
+}
+
+/**
+ * page_counter_try_charge - try to hierarchically charge pages
+ * @counter: counter
+ * @nr_pages: number of pages to charge
+ * @fail: points first counter to hit its limit, if any
+ *
+ * Returns 0 on success, or -ENOMEM and @fail if the counter or one of
+ * its ancestors has hit its configured limit.
+ */
+int page_counter_try_charge(struct page_counter *counter,
+ unsigned long nr_pages,
+ struct page_counter **fail)
+{
+ struct page_counter *c;
+
+ for (c = counter; c; c = c->parent) {
+ long new;
+ /*
+ * Charge speculatively to avoid an expensive CAS. If
+ * a bigger charge fails, it might falsely lock out a
+ * racing smaller charge and send it into reclaim
+ * early, but the error is limited to the difference
+ * between the two sizes, which is less than 2M/4M in
+ * case of a THP locking out a regular page charge.
+ *
+ * The atomic_long_add_return() implies a full memory
+ * barrier between incrementing the count and reading
+ * the limit. When racing with page_counter_limit(),
+ * we either see the new limit or the setter sees the
+ * counter has changed and retries.
+ */
+ new = atomic_long_add_return(nr_pages, &c->count);
+ if (new > c->limit) {
+ atomic_long_sub(nr_pages, &c->count);
+ /*
+ * This is racy, but we can live with some
+ * inaccuracy in the failcnt.
+ */
+ c->failcnt++;
+ *fail = c;
+ goto failed;
+ }
+ /*
+ * Just like with failcnt, we can live with some
+ * inaccuracy in the watermark.
+ */
+ if (new > c->watermark)
+ c->watermark = new;
+ }
+ return 0;
+
+failed:
+ for (c = counter; c != *fail; c = c->parent)
+ page_counter_cancel(c, nr_pages);
+
+ return -ENOMEM;
+}
+
+/**
+ * page_counter_uncharge - hierarchically uncharge pages
+ * @counter: counter
+ * @nr_pages: number of pages to uncharge
+ */
+void page_counter_uncharge(struct page_counter *counter, unsigned long nr_pages)
+{
+ struct page_counter *c;
+
+ for (c = counter; c; c = c->parent)
+ page_counter_cancel(c, nr_pages);
+}
+
+/**
+ * page_counter_limit - limit the number of pages allowed
+ * @counter: counter
+ * @limit: limit to set
+ *
+ * Returns 0 on success, -EBUSY if the current number of pages on the
+ * counter already exceeds the specified limit.
+ *
+ * The caller must serialize invocations on the same counter.
+ */
+int page_counter_limit(struct page_counter *counter, unsigned long limit)
+{
+ for (;;) {
+ unsigned long old;
+ long count;
+
+ /*
+ * Update the limit while making sure that it's not
+ * below the concurrently-changing counter value.
+ *
+ * The xchg implies two full memory barriers before
+ * and after, so the read-swap-read is ordered and
+ * ensures coherency with page_counter_try_charge():
+ * that function modifies the count before checking
+ * the limit, so if it sees the old limit, we see the
+ * modified counter and retry.
+ */
+ count = atomic_long_read(&counter->count);
+
+ if (count > limit)
+ return -EBUSY;
+
+ old = xchg(&counter->limit, limit);
+
+ if (atomic_long_read(&counter->count) <= count)
+ return 0;
+
+ counter->limit = old;
+ cond_resched();
+ }
+}
+
+/**
+ * page_counter_memparse - memparse() for page counter limits
+ * @buf: string to parse
+ * @nr_pages: returns the result in number of pages
+ *
+ * Returns -EINVAL, or 0 and @nr_pages on success. @nr_pages will be
+ * limited to %PAGE_COUNTER_MAX.
+ */
+int page_counter_memparse(const char *buf, unsigned long *nr_pages)
+{
+ char unlimited[] = "-1";
+ char *end;
+ u64 bytes;
+
+ if (!strncmp(buf, unlimited, sizeof(unlimited))) {
+ *nr_pages = PAGE_COUNTER_MAX;
+ return 0;
+ }
+
+ bytes = memparse(buf, &end);
+ if (*end != '\0')
+ return -EINVAL;
+
+ *nr_pages = min(bytes / PAGE_SIZE, (u64)PAGE_COUNTER_MAX);
+
+ return 0;
+}
diff --git a/mm/page_isolation.c b/mm/page_isolation.c
index c8778f7..72f5ac3 100644
--- a/mm/page_isolation.c
+++ b/mm/page_isolation.c
@@ -68,7 +68,7 @@ out:
spin_unlock_irqrestore(&zone->lock, flags);
if (!ret)
- drain_all_pages();
+ drain_all_pages(zone);
return ret;
}
diff --git a/mm/rmap.c b/mm/rmap.c
index 3e4c721..45eba36 100644
--- a/mm/rmap.c
+++ b/mm/rmap.c
@@ -1053,7 +1053,7 @@ void page_add_file_rmap(struct page *page)
__inc_zone_page_state(page, NR_FILE_MAPPED);
mem_cgroup_inc_page_stat(memcg, MEM_CGROUP_STAT_FILE_MAPPED);
}
- mem_cgroup_end_page_stat(memcg, locked, flags);
+ mem_cgroup_end_page_stat(memcg, &locked, &flags);
}
static void page_remove_file_rmap(struct page *page)
@@ -1083,7 +1083,7 @@ static void page_remove_file_rmap(struct page *page)
if (unlikely(PageMlocked(page)))
clear_page_mlock(page);
out:
- mem_cgroup_end_page_stat(memcg, locked, flags);
+ mem_cgroup_end_page_stat(memcg, &locked, &flags);
}
/**
diff --git a/mm/slab.c b/mm/slab.c
index f34e053..79e15f0 100644
--- a/mm/slab.c
+++ b/mm/slab.c
@@ -2590,7 +2590,10 @@ static int cache_grow(struct kmem_cache *cachep,
* Be lazy and only check for valid flags here, keeping it out of the
* critical path in kmem_cache_alloc().
*/
- BUG_ON(flags & GFP_SLAB_BUG_MASK);
+ if (unlikely(flags & GFP_SLAB_BUG_MASK)) {
+ pr_emerg("gfp: %u\n", flags & GFP_SLAB_BUG_MASK);
+ BUG();
+ }
local_flags = flags & (GFP_CONSTRAINT_MASK|GFP_RECLAIM_MASK);
/* Take the node list lock to change the colour_next on this node */
@@ -3580,11 +3583,11 @@ static int alloc_kmem_cache_node(struct kmem_cache *cachep, gfp_t gfp)
for_each_online_node(node) {
- if (use_alien_caches) {
- new_alien = alloc_alien_cache(node, cachep->limit, gfp);
- if (!new_alien)
- goto fail;
- }
+ if (use_alien_caches) {
+ new_alien = alloc_alien_cache(node, cachep->limit, gfp);
+ if (!new_alien)
+ goto fail;
+ }
new_shared = NULL;
if (cachep->shared) {
@@ -4043,12 +4046,6 @@ ssize_t slabinfo_write(struct file *file, const char __user *buffer,
#ifdef CONFIG_DEBUG_SLAB_LEAK
-static void *leaks_start(struct seq_file *m, loff_t *pos)
-{
- mutex_lock(&slab_mutex);
- return seq_list_start(&slab_caches, *pos);
-}
-
static inline int add_caller(unsigned long *n, unsigned long v)
{
unsigned long *p;
@@ -4170,7 +4167,7 @@ static int leaks_show(struct seq_file *m, void *p)
}
static const struct seq_operations slabstats_op = {
- .start = leaks_start,
+ .start = slab_start,
.next = slab_next,
.stop = slab_stop,
.show = leaks_show,
diff --git a/mm/slab.h b/mm/slab.h
index ab019e6..1cf40054 100644
--- a/mm/slab.h
+++ b/mm/slab.h
@@ -209,15 +209,15 @@ cache_from_memcg_idx(struct kmem_cache *s, int idx)
rcu_read_lock();
params = rcu_dereference(s->memcg_params);
- cachep = params->memcg_caches[idx];
- rcu_read_unlock();
/*
* Make sure we will access the up-to-date value. The code updating
* memcg_caches issues a write barrier to match this (see
* memcg_register_cache()).
*/
- smp_read_barrier_depends();
+ cachep = lockless_dereference(params->memcg_caches[idx]);
+ rcu_read_unlock();
+
return cachep;
}
@@ -357,7 +357,9 @@ static inline struct kmem_cache_node *get_node(struct kmem_cache *s, int node)
#endif
+void *slab_start(struct seq_file *m, loff_t *pos);
void *slab_next(struct seq_file *m, void *p, loff_t *pos);
void slab_stop(struct seq_file *m, void *p);
+int memcg_slab_show(struct seq_file *m, void *p);
#endif /* MM_SLAB_H */
diff --git a/mm/slab_common.c b/mm/slab_common.c
index dcdab81..e03dd6f 100644
--- a/mm/slab_common.c
+++ b/mm/slab_common.c
@@ -240,7 +240,7 @@ struct kmem_cache *find_mergeable(size_t size, size_t align,
size = ALIGN(size, align);
flags = kmem_cache_flags(size, flags, name, NULL);
- list_for_each_entry(s, &slab_caches, list) {
+ list_for_each_entry_reverse(s, &slab_caches, list) {
if (slab_unmergeable(s))
continue;
@@ -811,7 +811,7 @@ EXPORT_SYMBOL(kmalloc_order_trace);
#define SLABINFO_RIGHTS S_IRUSR
#endif
-void print_slabinfo_header(struct seq_file *m)
+static void print_slabinfo_header(struct seq_file *m)
{
/*
* Output format version, so at least we can change it
@@ -834,14 +834,9 @@ void print_slabinfo_header(struct seq_file *m)
seq_putc(m, '\n');
}
-static void *s_start(struct seq_file *m, loff_t *pos)
+void *slab_start(struct seq_file *m, loff_t *pos)
{
- loff_t n = *pos;
-
mutex_lock(&slab_mutex);
- if (!n)
- print_slabinfo_header(m);
-
return seq_list_start(&slab_caches, *pos);
}
@@ -881,7 +876,7 @@ memcg_accumulate_slabinfo(struct kmem_cache *s, struct slabinfo *info)
}
}
-int cache_show(struct kmem_cache *s, struct seq_file *m)
+static void cache_show(struct kmem_cache *s, struct seq_file *m)
{
struct slabinfo sinfo;
@@ -900,17 +895,32 @@ int cache_show(struct kmem_cache *s, struct seq_file *m)
sinfo.active_slabs, sinfo.num_slabs, sinfo.shared_avail);
slabinfo_show_stats(m, s);
seq_putc(m, '\n');
+}
+
+static int slab_show(struct seq_file *m, void *p)
+{
+ struct kmem_cache *s = list_entry(p, struct kmem_cache, list);
+
+ if (p == slab_caches.next)
+ print_slabinfo_header(m);
+ if (is_root_cache(s))
+ cache_show(s, m);
return 0;
}
-static int s_show(struct seq_file *m, void *p)
+#ifdef CONFIG_MEMCG_KMEM
+int memcg_slab_show(struct seq_file *m, void *p)
{
struct kmem_cache *s = list_entry(p, struct kmem_cache, list);
+ struct mem_cgroup *memcg = mem_cgroup_from_css(seq_css(m));
- if (!is_root_cache(s))
- return 0;
- return cache_show(s, m);
+ if (p == slab_caches.next)
+ print_slabinfo_header(m);
+ if (!is_root_cache(s) && s->memcg_params->memcg == memcg)
+ cache_show(s, m);
+ return 0;
}
+#endif
/*
* slabinfo_op - iterator that generates /proc/slabinfo
@@ -926,10 +936,10 @@ static int s_show(struct seq_file *m, void *p)
* + further values on SMP and with statistics enabled
*/
static const struct seq_operations slabinfo_op = {
- .start = s_start,
+ .start = slab_start,
.next = slab_next,
.stop = slab_stop,
- .show = s_show,
+ .show = slab_show,
};
static int slabinfo_open(struct inode *inode, struct file *file)
diff --git a/mm/slub.c b/mm/slub.c
index ae7b9f1..386bbed 100644
--- a/mm/slub.c
+++ b/mm/slub.c
@@ -849,12 +849,12 @@ static int check_slab(struct kmem_cache *s, struct page *page)
maxobj = order_objects(compound_order(page), s->size, s->reserved);
if (page->objects > maxobj) {
slab_err(s, page, "objects %u > max %u",
- s->name, page->objects, maxobj);
+ page->objects, maxobj);
return 0;
}
if (page->inuse > page->objects) {
slab_err(s, page, "inuse %u > max %u",
- s->name, page->inuse, page->objects);
+ page->inuse, page->objects);
return 0;
}
/* Slab_pad_check fixes things up after itself */
@@ -871,7 +871,7 @@ static int on_freelist(struct kmem_cache *s, struct page *page, void *search)
int nr = 0;
void *fp;
void *object = NULL;
- unsigned long max_objects;
+ int max_objects;
fp = page->freelist;
while (fp && nr <= page->objects) {
@@ -1377,7 +1377,10 @@ static struct page *new_slab(struct kmem_cache *s, gfp_t flags, int node)
int order;
int idx;
- BUG_ON(flags & GFP_SLAB_BUG_MASK);
+ if (unlikely(flags & GFP_SLAB_BUG_MASK)) {
+ pr_emerg("gfp: %u\n", flags & GFP_SLAB_BUG_MASK);
+ BUG();
+ }
page = allocate_slab(s,
flags & (GFP_RECLAIM_MASK | GFP_CONSTRAINT_MASK), node);
@@ -2554,7 +2557,7 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
} else { /* Needs to be taken off a list */
- n = get_node(s, page_to_nid(page));
+ n = get_node(s, page_to_nid(page));
/*
* Speculatively acquire the list_lock.
* If the cmpxchg does not succeed then we may
@@ -2587,10 +2590,10 @@ static void __slab_free(struct kmem_cache *s, struct page *page,
* The list lock was not taken therefore no list
* activity can be necessary.
*/
- if (was_frozen)
- stat(s, FREE_FROZEN);
- return;
- }
+ if (was_frozen)
+ stat(s, FREE_FROZEN);
+ return;
+ }
if (unlikely(!new.inuse && n->nr_partial >= s->min_partial))
goto slab_empty;
diff --git a/mm/swap_cgroup.c b/mm/swap_cgroup.c
new file mode 100644
index 0000000..b5f7f24
--- /dev/null
+++ b/mm/swap_cgroup.c
@@ -0,0 +1,208 @@
+#include <linux/swap_cgroup.h>
+#include <linux/vmalloc.h>
+#include <linux/mm.h>
+
+#include <linux/swapops.h> /* depends on mm.h include */
+
+static DEFINE_MUTEX(swap_cgroup_mutex);
+struct swap_cgroup_ctrl {
+ struct page **map;
+ unsigned long length;
+ spinlock_t lock;
+};
+
+static struct swap_cgroup_ctrl swap_cgroup_ctrl[MAX_SWAPFILES];
+
+struct swap_cgroup {
+ unsigned short id;
+};
+#define SC_PER_PAGE (PAGE_SIZE/sizeof(struct swap_cgroup))
+
+/*
+ * SwapCgroup implements "lookup" and "exchange" operations.
+ * In typical usage, this swap_cgroup is accessed via memcg's charge/uncharge
+ * against SwapCache. At swap_free(), this is accessed directly from swap.
+ *
+ * This means,
+ * - we have no race in "exchange" when we're accessed via SwapCache because
+ * SwapCache(and its swp_entry) is under lock.
+ * - When called via swap_free(), there is no user of this entry and no race.
+ * Then, we don't need lock around "exchange".
+ *
+ * TODO: we can push these buffers out to HIGHMEM.
+ */
+
+/*
+ * allocate buffer for swap_cgroup.
+ */
+static int swap_cgroup_prepare(int type)
+{
+ struct page *page;
+ struct swap_cgroup_ctrl *ctrl;
+ unsigned long idx, max;
+
+ ctrl = &swap_cgroup_ctrl[type];
+
+ for (idx = 0; idx < ctrl->length; idx++) {
+ page = alloc_page(GFP_KERNEL | __GFP_ZERO);
+ if (!page)
+ goto not_enough_page;
+ ctrl->map[idx] = page;
+ }
+ return 0;
+not_enough_page:
+ max = idx;
+ for (idx = 0; idx < max; idx++)
+ __free_page(ctrl->map[idx]);
+
+ return -ENOMEM;
+}
+
+static struct swap_cgroup *lookup_swap_cgroup(swp_entry_t ent,
+ struct swap_cgroup_ctrl **ctrlp)
+{
+ pgoff_t offset = swp_offset(ent);
+ struct swap_cgroup_ctrl *ctrl;
+ struct page *mappage;
+ struct swap_cgroup *sc;
+
+ ctrl = &swap_cgroup_ctrl[swp_type(ent)];
+ if (ctrlp)
+ *ctrlp = ctrl;
+
+ mappage = ctrl->map[offset / SC_PER_PAGE];
+ sc = page_address(mappage);
+ return sc + offset % SC_PER_PAGE;
+}
+
+/**
+ * swap_cgroup_cmpxchg - cmpxchg mem_cgroup's id for this swp_entry.
+ * @ent: swap entry to be cmpxchged
+ * @old: old id
+ * @new: new id
+ *
+ * Returns old id at success, 0 at failure.
+ * (There is no mem_cgroup using 0 as its id)
+ */
+unsigned short swap_cgroup_cmpxchg(swp_entry_t ent,
+ unsigned short old, unsigned short new)
+{
+ struct swap_cgroup_ctrl *ctrl;
+ struct swap_cgroup *sc;
+ unsigned long flags;
+ unsigned short retval;
+
+ sc = lookup_swap_cgroup(ent, &ctrl);
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+ retval = sc->id;
+ if (retval == old)
+ sc->id = new;
+ else
+ retval = 0;
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+ return retval;
+}
+
+/**
+ * swap_cgroup_record - record mem_cgroup for this swp_entry.
+ * @ent: swap entry to be recorded into
+ * @id: mem_cgroup to be recorded
+ *
+ * Returns old value at success, 0 at failure.
+ * (Of course, old value can be 0.)
+ */
+unsigned short swap_cgroup_record(swp_entry_t ent, unsigned short id)
+{
+ struct swap_cgroup_ctrl *ctrl;
+ struct swap_cgroup *sc;
+ unsigned short old;
+ unsigned long flags;
+
+ sc = lookup_swap_cgroup(ent, &ctrl);
+
+ spin_lock_irqsave(&ctrl->lock, flags);
+ old = sc->id;
+ sc->id = id;
+ spin_unlock_irqrestore(&ctrl->lock, flags);
+
+ return old;
+}
+
+/**
+ * lookup_swap_cgroup_id - lookup mem_cgroup id tied to swap entry
+ * @ent: swap entry to be looked up.
+ *
+ * Returns ID of mem_cgroup at success. 0 at failure. (0 is invalid ID)
+ */
+unsigned short lookup_swap_cgroup_id(swp_entry_t ent)
+{
+ return lookup_swap_cgroup(ent, NULL)->id;
+}
+
+int swap_cgroup_swapon(int type, unsigned long max_pages)
+{
+ void *array;
+ unsigned long array_size;
+ unsigned long length;
+ struct swap_cgroup_ctrl *ctrl;
+
+ if (!do_swap_account)
+ return 0;
+
+ length = DIV_ROUND_UP(max_pages, SC_PER_PAGE);
+ array_size = length * sizeof(void *);
+
+ array = vzalloc(array_size);
+ if (!array)
+ goto nomem;
+
+ ctrl = &swap_cgroup_ctrl[type];
+ mutex_lock(&swap_cgroup_mutex);
+ ctrl->length = length;
+ ctrl->map = array;
+ spin_lock_init(&ctrl->lock);
+ if (swap_cgroup_prepare(type)) {
+ /* memory shortage */
+ ctrl->map = NULL;
+ ctrl->length = 0;
+ mutex_unlock(&swap_cgroup_mutex);
+ vfree(array);
+ goto nomem;
+ }
+ mutex_unlock(&swap_cgroup_mutex);
+
+ return 0;
+nomem:
+ printk(KERN_INFO "couldn't allocate enough memory for swap_cgroup.\n");
+ printk(KERN_INFO
+ "swap_cgroup can be disabled by swapaccount=0 boot option\n");
+ return -ENOMEM;
+}
+
+void swap_cgroup_swapoff(int type)
+{
+ struct page **map;
+ unsigned long i, length;
+ struct swap_cgroup_ctrl *ctrl;
+
+ if (!do_swap_account)
+ return;
+
+ mutex_lock(&swap_cgroup_mutex);
+ ctrl = &swap_cgroup_ctrl[type];
+ map = ctrl->map;
+ length = ctrl->length;
+ ctrl->map = NULL;
+ ctrl->length = 0;
+ mutex_unlock(&swap_cgroup_mutex);
+
+ if (map) {
+ for (i = 0; i < length; i++) {
+ struct page *page = map[i];
+ if (page)
+ __free_page(page);
+ }
+ vfree(map);
+ }
+}
diff --git a/mm/swap_state.c b/mm/swap_state.c
index 1544449..9711342 100644
--- a/mm/swap_state.c
+++ b/mm/swap_state.c
@@ -17,7 +17,6 @@
#include <linux/blkdev.h>
#include <linux/pagevec.h>
#include <linux/migrate.h>
-#include <linux/page_cgroup.h>
#include <asm/pgtable.h>
diff --git a/mm/swapfile.c b/mm/swapfile.c
index 8798b2e..63f55cc 100644
--- a/mm/swapfile.c
+++ b/mm/swapfile.c
@@ -38,7 +38,7 @@
#include <asm/pgtable.h>
#include <asm/tlbflush.h>
#include <linux/swapops.h>
-#include <linux/page_cgroup.h>
+#include <linux/swap_cgroup.h>
static bool swap_count_continued(struct swap_info_struct *, pgoff_t,
unsigned char);
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
index 90520af..8a18196 100644
--- a/mm/vmalloc.c
+++ b/mm/vmalloc.c
@@ -463,8 +463,7 @@ overflow:
goto retry;
}
if (printk_ratelimit())
- printk(KERN_WARNING
- "vmap allocation for size %lu failed: "
+ pr_warn("vmap allocation for size %lu failed: "
"use vmalloc=<size> to increase size.\n", size);
kfree(va);
return ERR_PTR(-EBUSY);
diff --git a/mm/vmscan.c b/mm/vmscan.c
index dcb4707..4636d9e 100644
--- a/mm/vmscan.c
+++ b/mm/vmscan.c
@@ -260,8 +260,7 @@ shrink_slab_node(struct shrink_control *shrinkctl, struct shrinker *shrinker,
do_div(delta, lru_pages + 1);
total_scan += delta;
if (total_scan < 0) {
- printk(KERN_ERR
- "shrink_slab: %pF negative objects to delete nr=%ld\n",
+ pr_err("shrink_slab: %pF negative objects to delete nr=%ld\n",
shrinker->scan_objects, total_scan);
total_scan = freeable;
}
@@ -875,7 +874,8 @@ static unsigned long shrink_page_list(struct list_head *page_list,
* end of the LRU a second time.
*/
mapping = page_mapping(page);
- if ((mapping && bdi_write_congested(mapping->backing_dev_info)) ||
+ if (((dirty || writeback) && mapping &&
+ bdi_write_congested(mapping->backing_dev_info)) ||
(writeback && PageReclaim(page)))
nr_congested++;
@@ -2249,7 +2249,7 @@ static inline bool should_continue_reclaim(struct zone *zone,
return true;
/* If compaction would go ahead or the allocation would succeed, stop */
- switch (compaction_suitable(zone, sc->order)) {
+ switch (compaction_suitable(zone, sc->order, 0, 0)) {
case COMPACT_PARTIAL:
case COMPACT_CONTINUE:
return false;
@@ -2346,7 +2346,7 @@ static inline bool compaction_ready(struct zone *zone, int order)
* If compaction is not ready to start and allocation is not likely
* to succeed without it, then keep reclaiming.
*/
- if (compaction_suitable(zone, order) == COMPACT_SKIPPED)
+ if (compaction_suitable(zone, order, 0, 0) == COMPACT_SKIPPED)
return false;
return watermark_ok;
@@ -2824,8 +2824,8 @@ static bool zone_balanced(struct zone *zone, int order,
balance_gap, classzone_idx, 0))
return false;
- if (IS_ENABLED(CONFIG_COMPACTION) && order &&
- compaction_suitable(zone, order) == COMPACT_SKIPPED)
+ if (IS_ENABLED(CONFIG_COMPACTION) && order && compaction_suitable(zone,
+ order, 0, classzone_idx) == COMPACT_SKIPPED)
return false;
return true;
@@ -2952,8 +2952,8 @@ static bool kswapd_shrink_zone(struct zone *zone,
* from memory. Do not reclaim more than needed for compaction.
*/
if (IS_ENABLED(CONFIG_COMPACTION) && sc->order &&
- compaction_suitable(zone, sc->order) !=
- COMPACT_SKIPPED)
+ compaction_suitable(zone, sc->order, 0, classzone_idx)
+ != COMPACT_SKIPPED)
testorder = 0;
/*
diff --git a/net/bluetooth/rfcomm/core.c b/net/bluetooth/rfcomm/core.c
index 64e20dd..73f8c75 100644
--- a/net/bluetooth/rfcomm/core.c
+++ b/net/bluetooth/rfcomm/core.c
@@ -103,11 +103,11 @@ static struct rfcomm_session *rfcomm_session_del(struct rfcomm_session *s);
#define __get_rpn_stop_bits(line) (((line) >> 2) & 0x1)
#define __get_rpn_parity(line) (((line) >> 3) & 0x7)
+static DECLARE_WAIT_QUEUE_HEAD(rfcomm_wq);
+
static void rfcomm_schedule(void)
{
- if (!rfcomm_thread)
- return;
- wake_up_process(rfcomm_thread);
+ wake_up_all(&rfcomm_wq);
}
/* ---- RFCOMM FCS computation ---- */
@@ -2088,24 +2088,22 @@ static void rfcomm_kill_listener(void)
static int rfcomm_run(void *unused)
{
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
BT_DBG("");
set_user_nice(current, -10);
rfcomm_add_listener(BDADDR_ANY);
- while (1) {
- set_current_state(TASK_INTERRUPTIBLE);
-
- if (kthread_should_stop())
- break;
+ add_wait_queue(&rfcomm_wq, &wait);
+ while (!kthread_should_stop()) {
/* Process stuff */
rfcomm_process_sessions();
- schedule();
+ wait_woken(&wait, TASK_INTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- __set_current_state(TASK_RUNNING);
+ remove_wait_queue(&rfcomm_wq, &wait);
rfcomm_kill_listener();
diff --git a/net/core/dev.c b/net/core/dev.c
index 80f798d..f411c28 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -7266,11 +7266,10 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
*/
struct net *net;
bool unregistering;
- DEFINE_WAIT(wait);
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ add_wait_queue(&netdev_unregistering_wq, &wait);
for (;;) {
- prepare_to_wait(&netdev_unregistering_wq, &wait,
- TASK_UNINTERRUPTIBLE);
unregistering = false;
rtnl_lock();
list_for_each_entry(net, net_list, exit_list) {
@@ -7282,9 +7281,10 @@ static void __net_exit rtnl_lock_unregistering(struct list_head *net_list)
if (!unregistering)
break;
__rtnl_unlock();
- schedule();
+
+ wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- finish_wait(&netdev_unregistering_wq, &wait);
+ remove_wait_queue(&netdev_unregistering_wq, &wait);
}
static void __net_exit default_device_exit_batch(struct list_head *net_list)
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index 1ad61a2..d06107d 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -367,11 +367,10 @@ static void rtnl_lock_unregistering_all(void)
{
struct net *net;
bool unregistering;
- DEFINE_WAIT(wait);
+ DEFINE_WAIT_FUNC(wait, woken_wake_function);
+ add_wait_queue(&netdev_unregistering_wq, &wait);
for (;;) {
- prepare_to_wait(&netdev_unregistering_wq, &wait,
- TASK_UNINTERRUPTIBLE);
unregistering = false;
rtnl_lock();
for_each_net(net) {
@@ -383,9 +382,10 @@ static void rtnl_lock_unregistering_all(void)
if (!unregistering)
break;
__rtnl_unlock();
- schedule();
+
+ wait_woken(&wait, TASK_UNINTERRUPTIBLE, MAX_SCHEDULE_TIMEOUT);
}
- finish_wait(&netdev_unregistering_wq, &wait);
+ remove_wait_queue(&netdev_unregistering_wq, &wait);
}
/**
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
index a054fe0..5c61328 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4.c
@@ -56,11 +56,11 @@ static bool ipv4_invert_tuple(struct nf_conntrack_tuple *tuple,
return true;
}
-static int ipv4_print_tuple(struct seq_file *s,
+static void ipv4_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "src=%pI4 dst=%pI4 ",
- &tuple->src.u3.ip, &tuple->dst.u3.ip);
+ seq_printf(s, "src=%pI4 dst=%pI4 ",
+ &tuple->src.u3.ip, &tuple->dst.u3.ip);
}
static int ipv4_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
diff --git a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
index 4c48e43..a460a87 100644
--- a/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
+++ b/net/ipv4/netfilter/nf_conntrack_l3proto_ipv4_compat.c
@@ -94,7 +94,7 @@ static void ct_seq_stop(struct seq_file *s, void *v)
}
#ifdef CONFIG_NF_CONNTRACK_SECMARK
-static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
{
int ret;
u32 len;
@@ -102,17 +102,15 @@ static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
if (ret)
- return 0;
+ return;
- ret = seq_printf(s, "secctx=%s ", secctx);
+ seq_printf(s, "secctx=%s ", secctx);
security_release_secctx(secctx, len);
- return ret;
}
#else
-static inline int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
{
- return 0;
}
#endif
@@ -141,47 +139,52 @@ static int ct_seq_show(struct seq_file *s, void *v)
NF_CT_ASSERT(l4proto);
ret = -ENOSPC;
- if (seq_printf(s, "%-8s %u %ld ",
- l4proto->name, nf_ct_protonum(ct),
- timer_pending(&ct->timeout)
- ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
- goto release;
+ seq_printf(s, "%-8s %u %ld ",
+ l4proto->name, nf_ct_protonum(ct),
+ timer_pending(&ct->timeout)
+ ? (long)(ct->timeout.expires - jiffies)/HZ : 0);
+
+ if (l4proto->print_conntrack)
+ l4proto->print_conntrack(s, ct);
- if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct))
+ if (seq_has_overflowed(s))
goto release;
- if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
- l3proto, l4proto))
+ print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+ l3proto, l4proto);
+
+ if (seq_has_overflowed(s))
goto release;
if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
goto release;
if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
- if (seq_printf(s, "[UNREPLIED] "))
- goto release;
+ seq_printf(s, "[UNREPLIED] ");
- if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
- l3proto, l4proto))
+ print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
+ l3proto, l4proto);
+
+ if (seq_has_overflowed(s))
goto release;
if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
goto release;
if (test_bit(IPS_ASSURED_BIT, &ct->status))
- if (seq_printf(s, "[ASSURED] "))
- goto release;
+ seq_printf(s, "[ASSURED] ");
#ifdef CONFIG_NF_CONNTRACK_MARK
- if (seq_printf(s, "mark=%u ", ct->mark))
- goto release;
+ seq_printf(s, "mark=%u ", ct->mark);
#endif
- if (ct_show_secctx(s, ct))
- goto release;
+ ct_show_secctx(s, ct);
- if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
+ seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
+
+ if (seq_has_overflowed(s))
goto release;
+
ret = 0;
release:
nf_ct_put(ct);
diff --git a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
index b91b264..80d5554 100644
--- a/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
+++ b/net/ipv4/netfilter/nf_conntrack_proto_icmp.c
@@ -72,13 +72,13 @@ static bool icmp_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int icmp_print_tuple(struct seq_file *s,
+static void icmp_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "type=%u code=%u id=%u ",
- tuple->dst.u.icmp.type,
- tuple->dst.u.icmp.code,
- ntohs(tuple->src.u.icmp.id));
+ seq_printf(s, "type=%u code=%u id=%u ",
+ tuple->dst.u.icmp.type,
+ tuple->dst.u.icmp.code,
+ ntohs(tuple->src.u.icmp.id));
}
static unsigned int *icmp_get_timeouts(struct net *net)
diff --git a/net/ipv4/tcp_memcontrol.c b/net/ipv4/tcp_memcontrol.c
index 1d19135..27232713 100644
--- a/net/ipv4/tcp_memcontrol.c
+++ b/net/ipv4/tcp_memcontrol.c
@@ -9,13 +9,13 @@
int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
{
/*
- * The root cgroup does not use res_counters, but rather,
+ * The root cgroup does not use page_counters, but rather,
* rely on the data already collected by the network
* subsystem
*/
- struct res_counter *res_parent = NULL;
- struct cg_proto *cg_proto, *parent_cg;
struct mem_cgroup *parent = parent_mem_cgroup(memcg);
+ struct page_counter *counter_parent = NULL;
+ struct cg_proto *cg_proto, *parent_cg;
cg_proto = tcp_prot.proto_cgroup(memcg);
if (!cg_proto)
@@ -29,9 +29,9 @@ int tcp_init_cgroup(struct mem_cgroup *memcg, struct cgroup_subsys *ss)
parent_cg = tcp_prot.proto_cgroup(parent);
if (parent_cg)
- res_parent = &parent_cg->memory_allocated;
+ counter_parent = &parent_cg->memory_allocated;
- res_counter_init(&cg_proto->memory_allocated, res_parent);
+ page_counter_init(&cg_proto->memory_allocated, counter_parent);
percpu_counter_init(&cg_proto->sockets_allocated, 0, GFP_KERNEL);
return 0;
@@ -50,7 +50,7 @@ void tcp_destroy_cgroup(struct mem_cgroup *memcg)
}
EXPORT_SYMBOL(tcp_destroy_cgroup);
-static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
+static int tcp_update_limit(struct mem_cgroup *memcg, unsigned long nr_pages)
{
struct cg_proto *cg_proto;
int i;
@@ -60,20 +60,17 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
if (!cg_proto)
return -EINVAL;
- if (val > RES_COUNTER_MAX)
- val = RES_COUNTER_MAX;
-
- ret = res_counter_set_limit(&cg_proto->memory_allocated, val);
+ ret = page_counter_limit(&cg_proto->memory_allocated, nr_pages);
if (ret)
return ret;
for (i = 0; i < 3; i++)
- cg_proto->sysctl_mem[i] = min_t(long, val >> PAGE_SHIFT,
+ cg_proto->sysctl_mem[i] = min_t(long, nr_pages,
sysctl_tcp_mem[i]);
- if (val == RES_COUNTER_MAX)
+ if (nr_pages == PAGE_COUNTER_MAX)
clear_bit(MEMCG_SOCK_ACTIVE, &cg_proto->flags);
- else if (val != RES_COUNTER_MAX) {
+ else {
/*
* The active bit needs to be written after the static_key
* update. This is what guarantees that the socket activation
@@ -102,11 +99,20 @@ static int tcp_update_limit(struct mem_cgroup *memcg, u64 val)
return 0;
}
+enum {
+ RES_USAGE,
+ RES_LIMIT,
+ RES_MAX_USAGE,
+ RES_FAILCNT,
+};
+
+static DEFINE_MUTEX(tcp_limit_mutex);
+
static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
char *buf, size_t nbytes, loff_t off)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(of_css(of));
- unsigned long long val;
+ unsigned long nr_pages;
int ret = 0;
buf = strstrip(buf);
@@ -114,10 +120,12 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
switch (of_cft(of)->private) {
case RES_LIMIT:
/* see memcontrol.c */
- ret = res_counter_memparse_write_strategy(buf, &val);
+ ret = page_counter_memparse(buf, &nr_pages);
if (ret)
break;
- ret = tcp_update_limit(memcg, val);
+ mutex_lock(&tcp_limit_mutex);
+ ret = tcp_update_limit(memcg, nr_pages);
+ mutex_unlock(&tcp_limit_mutex);
break;
default:
ret = -EINVAL;
@@ -126,43 +134,36 @@ static ssize_t tcp_cgroup_write(struct kernfs_open_file *of,
return ret ?: nbytes;
}
-static u64 tcp_read_stat(struct mem_cgroup *memcg, int type, u64 default_val)
-{
- struct cg_proto *cg_proto;
-
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
- return default_val;
-
- return res_counter_read_u64(&cg_proto->memory_allocated, type);
-}
-
-static u64 tcp_read_usage(struct mem_cgroup *memcg)
-{
- struct cg_proto *cg_proto;
-
- cg_proto = tcp_prot.proto_cgroup(memcg);
- if (!cg_proto)
- return atomic_long_read(&tcp_memory_allocated) << PAGE_SHIFT;
-
- return res_counter_read_u64(&cg_proto->memory_allocated, RES_USAGE);
-}
-
static u64 tcp_cgroup_read(struct cgroup_subsys_state *css, struct cftype *cft)
{
struct mem_cgroup *memcg = mem_cgroup_from_css(css);
+ struct cg_proto *cg_proto = tcp_prot.proto_cgroup(memcg);
u64 val;
switch (cft->private) {
case RES_LIMIT:
- val = tcp_read_stat(memcg, RES_LIMIT, RES_COUNTER_MAX);
+ if (!cg_proto)
+ return PAGE_COUNTER_MAX;
+ val = cg_proto->memory_allocated.limit;
+ val *= PAGE_SIZE;
break;
case RES_USAGE:
- val = tcp_read_usage(memcg);
+ if (!cg_proto)
+ val = atomic_long_read(&tcp_memory_allocated);
+ else
+ val = page_counter_read(&cg_proto->memory_allocated);
+ val *= PAGE_SIZE;
break;
case RES_FAILCNT:
+ if (!cg_proto)
+ return 0;
+ val = cg_proto->memory_allocated.failcnt;
+ break;
case RES_MAX_USAGE:
- val = tcp_read_stat(memcg, cft->private, 0);
+ if (!cg_proto)
+ return 0;
+ val = cg_proto->memory_allocated.watermark;
+ val *= PAGE_SIZE;
break;
default:
BUG();
@@ -183,10 +184,10 @@ static ssize_t tcp_cgroup_reset(struct kernfs_open_file *of,
switch (of_cft(of)->private) {
case RES_MAX_USAGE:
- res_counter_reset_max(&cg_proto->memory_allocated);
+ page_counter_reset_watermark(&cg_proto->memory_allocated);
break;
case RES_FAILCNT:
- res_counter_reset_failcnt(&cg_proto->memory_allocated);
+ cg_proto->memory_allocated.failcnt = 0;
break;
}
diff --git a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
index 4cbc6b2..b68d0e5 100644
--- a/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_l3proto_ipv6.c
@@ -60,11 +60,11 @@ static bool ipv6_invert_tuple(struct nf_conntrack_tuple *tuple,
return true;
}
-static int ipv6_print_tuple(struct seq_file *s,
+static void ipv6_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "src=%pI6 dst=%pI6 ",
- tuple->src.u3.ip6, tuple->dst.u3.ip6);
+ seq_printf(s, "src=%pI6 dst=%pI6 ",
+ tuple->src.u3.ip6, tuple->dst.u3.ip6);
}
static int ipv6_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
diff --git a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
index b3807c5..90388d6 100644
--- a/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
+++ b/net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
@@ -84,13 +84,13 @@ static bool icmpv6_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int icmpv6_print_tuple(struct seq_file *s,
+static void icmpv6_print_tuple(struct seq_file *s,
const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "type=%u code=%u id=%u ",
- tuple->dst.u.icmp.type,
- tuple->dst.u.icmp.code,
- ntohs(tuple->src.u.icmp.id));
+ seq_printf(s, "type=%u code=%u id=%u ",
+ tuple->dst.u.icmp.type,
+ tuple->dst.u.icmp.code,
+ ntohs(tuple->src.u.icmp.id));
}
static unsigned int *icmpv6_get_timeouts(struct net *net)
diff --git a/net/netfilter/nf_conntrack_l3proto_generic.c b/net/netfilter/nf_conntrack_l3proto_generic.c
index e7eb807..cf9ace7 100644
--- a/net/netfilter/nf_conntrack_l3proto_generic.c
+++ b/net/netfilter/nf_conntrack_l3proto_generic.c
@@ -49,10 +49,9 @@ static bool generic_invert_tuple(struct nf_conntrack_tuple *tuple,
return true;
}
-static int generic_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void generic_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return 0;
}
static int generic_get_l4proto(const struct sk_buff *skb, unsigned int nhoff,
diff --git a/net/netfilter/nf_conntrack_proto_dccp.c b/net/netfilter/nf_conntrack_proto_dccp.c
index cb372f9..6dd995c 100644
--- a/net/netfilter/nf_conntrack_proto_dccp.c
+++ b/net/netfilter/nf_conntrack_proto_dccp.c
@@ -618,17 +618,17 @@ out_invalid:
return -NF_ACCEPT;
}
-static int dccp_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void dccp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.dccp.port),
- ntohs(tuple->dst.u.dccp.port));
+ seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.dccp.port),
+ ntohs(tuple->dst.u.dccp.port));
}
-static int dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
+static void dccp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
{
- return seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
+ seq_printf(s, "%s ", dccp_state_names[ct->proto.dccp.state]);
}
#if IS_ENABLED(CONFIG_NF_CT_NETLINK)
diff --git a/net/netfilter/nf_conntrack_proto_generic.c b/net/netfilter/nf_conntrack_proto_generic.c
index 957c1db..60865f1 100644
--- a/net/netfilter/nf_conntrack_proto_generic.c
+++ b/net/netfilter/nf_conntrack_proto_generic.c
@@ -63,10 +63,9 @@ static bool generic_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int generic_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void generic_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return 0;
}
static unsigned int *generic_get_timeouts(struct net *net)
diff --git a/net/netfilter/nf_conntrack_proto_gre.c b/net/netfilter/nf_conntrack_proto_gre.c
index d566573..7648674 100644
--- a/net/netfilter/nf_conntrack_proto_gre.c
+++ b/net/netfilter/nf_conntrack_proto_gre.c
@@ -226,20 +226,20 @@ static bool gre_pkt_to_tuple(const struct sk_buff *skb, unsigned int dataoff,
}
/* print gre part of tuple */
-static int gre_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void gre_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "srckey=0x%x dstkey=0x%x ",
- ntohs(tuple->src.u.gre.key),
- ntohs(tuple->dst.u.gre.key));
+ seq_printf(s, "srckey=0x%x dstkey=0x%x ",
+ ntohs(tuple->src.u.gre.key),
+ ntohs(tuple->dst.u.gre.key));
}
/* print private data for conntrack */
-static int gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
+static void gre_print_conntrack(struct seq_file *s, struct nf_conn *ct)
{
- return seq_printf(s, "timeout=%u, stream_timeout=%u ",
- (ct->proto.gre.timeout / HZ),
- (ct->proto.gre.stream_timeout / HZ));
+ seq_printf(s, "timeout=%u, stream_timeout=%u ",
+ (ct->proto.gre.timeout / HZ),
+ (ct->proto.gre.stream_timeout / HZ));
}
static unsigned int *gre_get_timeouts(struct net *net)
diff --git a/net/netfilter/nf_conntrack_proto_sctp.c b/net/netfilter/nf_conntrack_proto_sctp.c
index 1314d33..b45da90 100644
--- a/net/netfilter/nf_conntrack_proto_sctp.c
+++ b/net/netfilter/nf_conntrack_proto_sctp.c
@@ -166,16 +166,16 @@ static bool sctp_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int sctp_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void sctp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.sctp.port),
- ntohs(tuple->dst.u.sctp.port));
+ seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.sctp.port),
+ ntohs(tuple->dst.u.sctp.port));
}
/* Print out the private part of the conntrack. */
-static int sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
+static void sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
{
enum sctp_conntrack state;
@@ -183,7 +183,7 @@ static int sctp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
state = ct->proto.sctp.state;
spin_unlock_bh(&ct->lock);
- return seq_printf(s, "%s ", sctp_conntrack_names[state]);
+ seq_printf(s, "%s ", sctp_conntrack_names[state]);
}
#define for_each_sctp_chunk(skb, sch, _sch, offset, dataoff, count) \
diff --git a/net/netfilter/nf_conntrack_proto_tcp.c b/net/netfilter/nf_conntrack_proto_tcp.c
index d87b642..5caa0c4 100644
--- a/net/netfilter/nf_conntrack_proto_tcp.c
+++ b/net/netfilter/nf_conntrack_proto_tcp.c
@@ -302,16 +302,16 @@ static bool tcp_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int tcp_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void tcp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.tcp.port),
- ntohs(tuple->dst.u.tcp.port));
+ seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.tcp.port),
+ ntohs(tuple->dst.u.tcp.port));
}
/* Print out the private part of the conntrack. */
-static int tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
+static void tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
{
enum tcp_conntrack state;
@@ -319,7 +319,7 @@ static int tcp_print_conntrack(struct seq_file *s, struct nf_conn *ct)
state = ct->proto.tcp.state;
spin_unlock_bh(&ct->lock);
- return seq_printf(s, "%s ", tcp_conntrack_names[state]);
+ seq_printf(s, "%s ", tcp_conntrack_names[state]);
}
static unsigned int get_conntrack_index(const struct tcphdr *tcph)
diff --git a/net/netfilter/nf_conntrack_proto_udp.c b/net/netfilter/nf_conntrack_proto_udp.c
index 9d7721c..6957281 100644
--- a/net/netfilter/nf_conntrack_proto_udp.c
+++ b/net/netfilter/nf_conntrack_proto_udp.c
@@ -63,12 +63,12 @@ static bool udp_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int udp_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void udp_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.udp.port),
- ntohs(tuple->dst.u.udp.port));
+ seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.udp.port),
+ ntohs(tuple->dst.u.udp.port));
}
static unsigned int *udp_get_timeouts(struct net *net)
diff --git a/net/netfilter/nf_conntrack_proto_udplite.c b/net/netfilter/nf_conntrack_proto_udplite.c
index 2750e6c..c5903d1 100644
--- a/net/netfilter/nf_conntrack_proto_udplite.c
+++ b/net/netfilter/nf_conntrack_proto_udplite.c
@@ -71,12 +71,12 @@ static bool udplite_invert_tuple(struct nf_conntrack_tuple *tuple,
}
/* Print out the per-protocol part of the tuple. */
-static int udplite_print_tuple(struct seq_file *s,
- const struct nf_conntrack_tuple *tuple)
+static void udplite_print_tuple(struct seq_file *s,
+ const struct nf_conntrack_tuple *tuple)
{
- return seq_printf(s, "sport=%hu dport=%hu ",
- ntohs(tuple->src.u.udp.port),
- ntohs(tuple->dst.u.udp.port));
+ seq_printf(s, "sport=%hu dport=%hu ",
+ ntohs(tuple->src.u.udp.port),
+ ntohs(tuple->dst.u.udp.port));
}
static unsigned int *udplite_get_timeouts(struct net *net)
diff --git a/net/netfilter/nf_conntrack_standalone.c b/net/netfilter/nf_conntrack_standalone.c
index cf65a1e..fc823fa 100644
--- a/net/netfilter/nf_conntrack_standalone.c
+++ b/net/netfilter/nf_conntrack_standalone.c
@@ -36,12 +36,13 @@
MODULE_LICENSE("GPL");
#ifdef CONFIG_NF_CONNTRACK_PROCFS
-int
+void
print_tuple(struct seq_file *s, const struct nf_conntrack_tuple *tuple,
const struct nf_conntrack_l3proto *l3proto,
const struct nf_conntrack_l4proto *l4proto)
{
- return l3proto->print_tuple(s, tuple) || l4proto->print_tuple(s, tuple);
+ l3proto->print_tuple(s, tuple);
+ l4proto->print_tuple(s, tuple);
}
EXPORT_SYMBOL_GPL(print_tuple);
@@ -119,7 +120,7 @@ static void ct_seq_stop(struct seq_file *s, void *v)
}
#ifdef CONFIG_NF_CONNTRACK_SECMARK
-static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+static void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
{
int ret;
u32 len;
@@ -127,22 +128,20 @@ static int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
ret = security_secid_to_secctx(ct->secmark, &secctx, &len);
if (ret)
- return 0;
+ return;
- ret = seq_printf(s, "secctx=%s ", secctx);
+ seq_printf(s, "secctx=%s ", secctx);
security_release_secctx(secctx, len);
- return ret;
}
#else
-static inline int ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
+static inline void ct_show_secctx(struct seq_file *s, const struct nf_conn *ct)
{
- return 0;
}
#endif
#ifdef CONFIG_NF_CONNTRACK_TIMESTAMP
-static int ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
+static void ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
{
struct ct_iter_state *st = s->private;
struct nf_conn_tstamp *tstamp;
@@ -156,16 +155,15 @@ static int ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
else
delta_time = 0;
- return seq_printf(s, "delta-time=%llu ",
- (unsigned long long)delta_time);
+ seq_printf(s, "delta-time=%llu ",
+ (unsigned long long)delta_time);
}
- return 0;
+ return;
}
#else
-static inline int
+static inline void
ct_show_delta_time(struct seq_file *s, const struct nf_conn *ct)
{
- return 0;
}
#endif
@@ -192,55 +190,54 @@ static int ct_seq_show(struct seq_file *s, void *v)
NF_CT_ASSERT(l4proto);
ret = -ENOSPC;
- if (seq_printf(s, "%-8s %u %-8s %u %ld ",
- l3proto->name, nf_ct_l3num(ct),
- l4proto->name, nf_ct_protonum(ct),
- timer_pending(&ct->timeout)
- ? (long)(ct->timeout.expires - jiffies)/HZ : 0) != 0)
- goto release;
+ seq_printf(s, "%-8s %u %-8s %u %ld ",
+ l3proto->name, nf_ct_l3num(ct),
+ l4proto->name, nf_ct_protonum(ct),
+ timer_pending(&ct->timeout)
+ ? (long)(ct->timeout.expires - jiffies)/HZ : 0);
- if (l4proto->print_conntrack && l4proto->print_conntrack(s, ct))
- goto release;
+ if (l4proto->print_conntrack)
+ l4proto->print_conntrack(s, ct);
+
+ print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
+ l3proto, l4proto);
- if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple,
- l3proto, l4proto))
+ if (seq_has_overflowed(s))
goto release;
if (seq_print_acct(s, ct, IP_CT_DIR_ORIGINAL))
goto release;
if (!(test_bit(IPS_SEEN_REPLY_BIT, &ct->status)))
- if (seq_printf(s, "[UNREPLIED] "))
- goto release;
+ seq_printf(s, "[UNREPLIED] ");
- if (print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
- l3proto, l4proto))
- goto release;
+ print_tuple(s, &ct->tuplehash[IP_CT_DIR_REPLY].tuple,
+ l3proto, l4proto);
if (seq_print_acct(s, ct, IP_CT_DIR_REPLY))
goto release;
if (test_bit(IPS_ASSURED_BIT, &ct->status))
- if (seq_printf(s, "[ASSURED] "))
- goto release;
+ seq_printf(s, "[ASSURED] ");
-#if defined(CONFIG_NF_CONNTRACK_MARK)
- if (seq_printf(s, "mark=%u ", ct->mark))
+ if (seq_has_overflowed(s))
goto release;
+
+#if defined(CONFIG_NF_CONNTRACK_MARK)
+ seq_printf(s, "mark=%u ", ct->mark);
#endif
- if (ct_show_secctx(s, ct))
- goto release;
+ ct_show_secctx(s, ct);
#ifdef CONFIG_NF_CONNTRACK_ZONES
- if (seq_printf(s, "zone=%u ", nf_ct_zone(ct)))
- goto release;
+ seq_printf(s, "zone=%u ", nf_ct_zone(ct));
#endif
- if (ct_show_delta_time(s, ct))
- goto release;
+ ct_show_delta_time(s, ct);
+
+ seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use));
- if (seq_printf(s, "use=%u\n", atomic_read(&ct->ct_general.use)))
+ if (seq_has_overflowed(s))
goto release;
ret = 0;
diff --git a/net/netfilter/nf_log.c b/net/netfilter/nf_log.c
index 49a6417..43c926c 100644
--- a/net/netfilter/nf_log.c
+++ b/net/netfilter/nf_log.c
@@ -303,35 +303,37 @@ static int seq_show(struct seq_file *s, void *v)
{
loff_t *pos = v;
const struct nf_logger *logger;
- int i, ret;
+ int i;
struct net *net = seq_file_net(s);
logger = nft_log_dereference(net->nf.nf_loggers[*pos]);
if (!logger)
- ret = seq_printf(s, "%2lld NONE (", *pos);
+ seq_printf(s, "%2lld NONE (", *pos);
else
- ret = seq_printf(s, "%2lld %s (", *pos, logger->name);
+ seq_printf(s, "%2lld %s (", *pos, logger->name);
- if (ret < 0)
- return ret;
+ if (seq_has_overflowed(s))
+ return -ENOSPC;
for (i = 0; i < NF_LOG_TYPE_MAX; i++) {
if (loggers[*pos][i] == NULL)
continue;
logger = nft_log_dereference(loggers[*pos][i]);
- ret = seq_printf(s, "%s", logger->name);
- if (ret < 0)
- return ret;
- if (i == 0 && loggers[*pos][i + 1] != NULL) {
- ret = seq_printf(s, ",");
- if (ret < 0)
- return ret;
- }
+ seq_printf(s, "%s", logger->name);
+ if (i == 0 && loggers[*pos][i + 1] != NULL)
+ seq_printf(s, ",");
+
+ if (seq_has_overflowed(s))
+ return -ENOSPC;
}
- return seq_printf(s, ")\n");
+ seq_printf(s, ")\n");
+
+ if (seq_has_overflowed(s))
+ return -ENOSPC;
+ return 0;
}
static const struct seq_operations nflog_seq_ops = {
diff --git a/net/netfilter/nfnetlink_queue_core.c b/net/netfilter/nfnetlink_queue_core.c
index 7c60ccd..0db8515 100644
--- a/net/netfilter/nfnetlink_queue_core.c
+++ b/net/netfilter/nfnetlink_queue_core.c
@@ -1242,12 +1242,13 @@ static int seq_show(struct seq_file *s, void *v)
{
const struct nfqnl_instance *inst = v;
- return seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n",
- inst->queue_num,
- inst->peer_portid, inst->queue_total,
- inst->copy_mode, inst->copy_range,
- inst->queue_dropped, inst->queue_user_dropped,
- inst->id_sequence, 1);
+ seq_printf(s, "%5d %6d %5d %1d %5d %5d %5d %8d %2d\n",
+ inst->queue_num,
+ inst->peer_portid, inst->queue_total,
+ inst->copy_mode, inst->copy_range,
+ inst->queue_dropped, inst->queue_user_dropped,
+ inst->id_sequence, 1);
+ return seq_has_overflowed(s);
}
static const struct seq_operations nfqnl_seq_ops = {
diff --git a/net/netfilter/x_tables.c b/net/netfilter/x_tables.c
index 133eb47..51a459c 100644
--- a/net/netfilter/x_tables.c
+++ b/net/netfilter/x_tables.c
@@ -947,9 +947,10 @@ static int xt_table_seq_show(struct seq_file *seq, void *v)
{
struct xt_table *table = list_entry(v, struct xt_table, list);
- if (strlen(table->name))
- return seq_printf(seq, "%s\n", table->name);
- else
+ if (strlen(table->name)) {
+ seq_printf(seq, "%s\n", table->name);
+ return seq_has_overflowed(seq);
+ } else
return 0;
}
@@ -1086,8 +1087,10 @@ static int xt_match_seq_show(struct seq_file *seq, void *v)
if (trav->curr == trav->head)
return 0;
match = list_entry(trav->curr, struct xt_match, list);
- return (*match->name == '\0') ? 0 :
- seq_printf(seq, "%s\n", match->name);
+ if (*match->name == '\0')
+ return 0;
+ seq_printf(seq, "%s\n", match->name);
+ return seq_has_overflowed(seq);
}
return 0;
}
@@ -1139,8 +1142,10 @@ static int xt_target_seq_show(struct seq_file *seq, void *v)
if (trav->curr == trav->head)
return 0;
target = list_entry(trav->curr, struct xt_target, list);
- return (*target->name == '\0') ? 0 :
- seq_printf(seq, "%s\n", target->name);
+ if (*target->name == '\0')
+ return 0;
+ seq_printf(seq, "%s\n", target->name);
+ return seq_has_overflowed(seq);
}
return 0;
}
diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c
index 05fbc2a..1786968 100644
--- a/net/netfilter/xt_hashlimit.c
+++ b/net/netfilter/xt_hashlimit.c
@@ -789,7 +789,6 @@ static void dl_seq_stop(struct seq_file *s, void *v)
static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
struct seq_file *s)
{
- int res;
const struct xt_hashlimit_htable *ht = s->private;
spin_lock(&ent->lock);
@@ -798,33 +797,32 @@ static int dl_seq_real_show(struct dsthash_ent *ent, u_int8_t family,
switch (family) {
case NFPROTO_IPV4:
- res = seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n",
- (long)(ent->expires - jiffies)/HZ,
- &ent->dst.ip.src,
- ntohs(ent->dst.src_port),
- &ent->dst.ip.dst,
- ntohs(ent->dst.dst_port),
- ent->rateinfo.credit, ent->rateinfo.credit_cap,
- ent->rateinfo.cost);
+ seq_printf(s, "%ld %pI4:%u->%pI4:%u %u %u %u\n",
+ (long)(ent->expires - jiffies)/HZ,
+ &ent->dst.ip.src,
+ ntohs(ent->dst.src_port),
+ &ent->dst.ip.dst,
+ ntohs(ent->dst.dst_port),
+ ent->rateinfo.credit, ent->rateinfo.credit_cap,
+ ent->rateinfo.cost);
break;
#if IS_ENABLED(CONFIG_IP6_NF_IPTABLES)
case NFPROTO_IPV6:
- res = seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n",
- (long)(ent->expires - jiffies)/HZ,
- &ent->dst.ip6.src,
- ntohs(ent->dst.src_port),
- &ent->dst.ip6.dst,
- ntohs(ent->dst.dst_port),
- ent->rateinfo.credit, ent->rateinfo.credit_cap,
- ent->rateinfo.cost);
+ seq_printf(s, "%ld %pI6:%u->%pI6:%u %u %u %u\n",
+ (long)(ent->expires - jiffies)/HZ,
+ &ent->dst.ip6.src,
+ ntohs(ent->dst.src_port),
+ &ent->dst.ip6.dst,
+ ntohs(ent->dst.dst_port),
+ ent->rateinfo.credit, ent->rateinfo.credit_cap,
+ ent->rateinfo.cost);
break;
#endif
default:
BUG();
- res = 0;
}
spin_unlock(&ent->lock);
- return res;
+ return seq_has_overflowed(s);
}
static int dl_seq_show(struct seq_file *s, void *v)
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c
index ed2e620..e52a447 100644
--- a/net/packet/af_packet.c
+++ b/net/packet/af_packet.c
@@ -2453,13 +2453,15 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
goto out_unlock;
if ((vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) &&
- (vnet_hdr.csum_start + vnet_hdr.csum_offset + 2 >
- vnet_hdr.hdr_len))
- vnet_hdr.hdr_len = vnet_hdr.csum_start +
- vnet_hdr.csum_offset + 2;
+ (__virtio16_to_cpu(false, vnet_hdr.csum_start) +
+ __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2 >
+ __virtio16_to_cpu(false, vnet_hdr.hdr_len)))
+ vnet_hdr.hdr_len = __cpu_to_virtio16(false,
+ __virtio16_to_cpu(false, vnet_hdr.csum_start) +
+ __virtio16_to_cpu(false, vnet_hdr.csum_offset) + 2);
err = -EINVAL;
- if (vnet_hdr.hdr_len > len)
+ if (__virtio16_to_cpu(false, vnet_hdr.hdr_len) > len)
goto out_unlock;
if (vnet_hdr.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
@@ -2501,7 +2503,8 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
err = -ENOBUFS;
hlen = LL_RESERVED_SPACE(dev);
tlen = dev->needed_tailroom;
- skb = packet_alloc_skb(sk, hlen + tlen, hlen, len, vnet_hdr.hdr_len,
+ skb = packet_alloc_skb(sk, hlen + tlen, hlen, len,
+ __virtio16_to_cpu(false, vnet_hdr.hdr_len),
msg->msg_flags & MSG_DONTWAIT, &err);
if (skb == NULL)
goto out_unlock;
@@ -2548,14 +2551,16 @@ static int packet_snd(struct socket *sock, struct msghdr *msg, size_t len)
if (po->has_vnet_hdr) {
if (vnet_hdr.flags & VIRTIO_NET_HDR_F_NEEDS_CSUM) {
- if (!skb_partial_csum_set(skb, vnet_hdr.csum_start,
- vnet_hdr.csum_offset)) {
+ u16 s = __virtio16_to_cpu(false, vnet_hdr.csum_start);
+ u16 o = __virtio16_to_cpu(false, vnet_hdr.csum_offset);
+ if (!skb_partial_csum_set(skb, s, o)) {
err = -EINVAL;
goto out_free;
}
}
- skb_shinfo(skb)->gso_size = vnet_hdr.gso_size;
+ skb_shinfo(skb)->gso_size =
+ __virtio16_to_cpu(false, vnet_hdr.gso_size);
skb_shinfo(skb)->gso_type = gso_type;
/* Header must be checked, and gso_segs computed. */
@@ -2926,8 +2931,10 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
struct skb_shared_info *sinfo = skb_shinfo(skb);
/* This is a hint as to how much should be linear. */
- vnet_hdr.hdr_len = skb_headlen(skb);
- vnet_hdr.gso_size = sinfo->gso_size;
+ vnet_hdr.hdr_len =
+ __cpu_to_virtio16(false, skb_headlen(skb));
+ vnet_hdr.gso_size =
+ __cpu_to_virtio16(false, sinfo->gso_size);
if (sinfo->gso_type & SKB_GSO_TCPV4)
vnet_hdr.gso_type = VIRTIO_NET_HDR_GSO_TCPV4;
else if (sinfo->gso_type & SKB_GSO_TCPV6)
@@ -2945,8 +2952,10 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
if (skb->ip_summed == CHECKSUM_PARTIAL) {
vnet_hdr.flags = VIRTIO_NET_HDR_F_NEEDS_CSUM;
- vnet_hdr.csum_start = skb_checksum_start_offset(skb);
- vnet_hdr.csum_offset = skb->csum_offset;
+ vnet_hdr.csum_start = __cpu_to_virtio16(false,
+ skb_checksum_start_offset(skb));
+ vnet_hdr.csum_offset = __cpu_to_virtio16(false,
+ skb->csum_offset);
} else if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
vnet_hdr.flags = VIRTIO_NET_HDR_F_DATA_VALID;
} /* else everything is zero */
diff --git a/net/rfkill/rfkill-gpio.c b/net/rfkill/rfkill-gpio.c
index 0f62326..2a47179 100644
--- a/net/rfkill/rfkill-gpio.c
+++ b/net/rfkill/rfkill-gpio.c
@@ -63,6 +63,15 @@ static const struct rfkill_ops rfkill_gpio_ops = {
.set_block = rfkill_gpio_set_power,
};
+static const struct acpi_gpio_params reset_gpios = { 0, 0, false };
+static const struct acpi_gpio_params shutdown_gpios = { 1, 0, false };
+
+static const struct acpi_gpio_mapping acpi_rfkill_default_gpios[] = {
+ { "reset-gpios", &reset_gpios, 1 },
+ { "shutdown-gpios", &shutdown_gpios, 1 },
+ { },
+};
+
static int rfkill_gpio_acpi_probe(struct device *dev,
struct rfkill_gpio_data *rfkill)
{
@@ -75,7 +84,8 @@ static int rfkill_gpio_acpi_probe(struct device *dev,
rfkill->name = dev_name(dev);
rfkill->type = (unsigned)id->driver_data;
- return 0;
+ return acpi_dev_add_driver_gpios(ACPI_COMPANION(dev),
+ acpi_rfkill_default_gpios);
}
static int rfkill_gpio_probe(struct platform_device *pdev)
@@ -102,7 +112,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->clk = devm_clk_get(&pdev->dev, NULL);
- gpio = devm_gpiod_get_index(&pdev->dev, "reset", 0);
+ gpio = devm_gpiod_get(&pdev->dev, "reset");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
@@ -110,7 +120,7 @@ static int rfkill_gpio_probe(struct platform_device *pdev)
rfkill->reset_gpio = gpio;
}
- gpio = devm_gpiod_get_index(&pdev->dev, "shutdown", 1);
+ gpio = devm_gpiod_get(&pdev->dev, "shutdown");
if (!IS_ERR(gpio)) {
ret = gpiod_direction_output(gpio, 0);
if (ret)
@@ -150,6 +160,8 @@ static int rfkill_gpio_remove(struct platform_device *pdev)
rfkill_unregister(rfkill->rfkill_dev);
rfkill_destroy(rfkill->rfkill_dev);
+ acpi_dev_remove_driver_gpios(ACPI_COMPANION(&pdev->dev));
+
return 0;
}
diff --git a/net/sunrpc/Kconfig b/net/sunrpc/Kconfig
index 0754d0f..fb78117 100644
--- a/net/sunrpc/Kconfig
+++ b/net/sunrpc/Kconfig
@@ -35,6 +35,7 @@ config RPCSEC_GSS_KRB5
config SUNRPC_DEBUG
bool "RPC: Enable dprintk debugging"
depends on SUNRPC && SYSCTL
+ select DEBUG_FS
help
This option enables a sysctl-based debugging interface
that is be used by the 'rpcdebug' utility to turn on or off
diff --git a/net/sunrpc/Makefile b/net/sunrpc/Makefile
index e5a7a1c..15e6f6c 100644
--- a/net/sunrpc/Makefile
+++ b/net/sunrpc/Makefile
@@ -14,6 +14,7 @@ sunrpc-y := clnt.o xprt.o socklib.o xprtsock.o sched.o \
addr.o rpcb_clnt.o timer.o xdr.o \
sunrpc_syms.o cache.o rpc_pipe.o \
svc_xprt.o
+sunrpc-$(CONFIG_SUNRPC_DEBUG) += debugfs.o
sunrpc-$(CONFIG_SUNRPC_BACKCHANNEL) += backchannel_rqst.o bc_svc.o
sunrpc-$(CONFIG_PROC_FS) += stats.o
sunrpc-$(CONFIG_SYSCTL) += sysctl.o
diff --git a/net/sunrpc/auth.c b/net/sunrpc/auth.c
index 383eb91..47f38be 100644
--- a/net/sunrpc/auth.c
+++ b/net/sunrpc/auth.c
@@ -16,7 +16,7 @@
#include <linux/sunrpc/gss_api.h>
#include <linux/spinlock.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
@@ -646,7 +646,7 @@ rpcauth_init_cred(struct rpc_cred *cred, const struct auth_cred *acred,
cred->cr_auth = auth;
cred->cr_ops = ops;
cred->cr_expire = jiffies;
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
cred->cr_magic = RPCAUTH_CRED_MAGIC;
#endif
cred->cr_uid = acred->uid;
diff --git a/net/sunrpc/auth_generic.c b/net/sunrpc/auth_generic.c
index 6f6b829..41248b1 100644
--- a/net/sunrpc/auth_generic.c
+++ b/net/sunrpc/auth_generic.c
@@ -14,7 +14,7 @@
#include <linux/sunrpc/debug.h>
#include <linux/sunrpc/sched.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/auth_gss.c b/net/sunrpc/auth_gss/auth_gss.c
index 53ed8d3..dace13d 100644
--- a/net/sunrpc/auth_gss/auth_gss.c
+++ b/net/sunrpc/auth_gss/auth_gss.c
@@ -66,7 +66,7 @@ static unsigned int gss_expired_cred_retry_delay = GSS_RETRY_EXPIRED;
#define GSS_KEY_EXPIRE_TIMEO 240
static unsigned int gss_key_expire_timeo = GSS_KEY_EXPIRE_TIMEO;
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_generic_token.c b/net/sunrpc/auth_gss/gss_generic_token.c
index c586e92..254defe 100644
--- a/net/sunrpc/auth_gss/gss_generic_token.c
+++ b/net/sunrpc/auth_gss/gss_generic_token.c
@@ -38,7 +38,7 @@
#include <linux/sunrpc/gss_asn1.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_crypto.c b/net/sunrpc/auth_gss/gss_krb5_crypto.c
index f5ed9f6..b5408e8 100644
--- a/net/sunrpc/auth_gss/gss_krb5_crypto.c
+++ b/net/sunrpc/auth_gss/gss_krb5_crypto.c
@@ -45,7 +45,7 @@
#include <linux/sunrpc/gss_krb5.h>
#include <linux/sunrpc/xdr.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_keys.c b/net/sunrpc/auth_gss/gss_krb5_keys.c
index 24589bd..234fa8d 100644
--- a/net/sunrpc/auth_gss/gss_krb5_keys.c
+++ b/net/sunrpc/auth_gss/gss_krb5_keys.c
@@ -61,7 +61,7 @@
#include <linux/sunrpc/xdr.h>
#include <linux/lcm.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_mech.c b/net/sunrpc/auth_gss/gss_krb5_mech.c
index 0d3c158..28db442 100644
--- a/net/sunrpc/auth_gss/gss_krb5_mech.c
+++ b/net/sunrpc/auth_gss/gss_krb5_mech.c
@@ -45,7 +45,7 @@
#include <linux/crypto.h>
#include <linux/sunrpc/gss_krb5_enctypes.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_seal.c b/net/sunrpc/auth_gss/gss_krb5_seal.c
index 42768e5..1d74d65 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seal.c
@@ -64,7 +64,7 @@
#include <linux/random.h>
#include <linux/crypto.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_seqnum.c b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
index 62ac90c..20d55c7 100644
--- a/net/sunrpc/auth_gss/gss_krb5_seqnum.c
+++ b/net/sunrpc/auth_gss/gss_krb5_seqnum.c
@@ -35,7 +35,7 @@
#include <linux/sunrpc/gss_krb5.h>
#include <linux/crypto.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_unseal.c b/net/sunrpc/auth_gss/gss_krb5_unseal.c
index 6c981dd..dcf9515 100644
--- a/net/sunrpc/auth_gss/gss_krb5_unseal.c
+++ b/net/sunrpc/auth_gss/gss_krb5_unseal.c
@@ -62,7 +62,7 @@
#include <linux/sunrpc/gss_krb5.h>
#include <linux/crypto.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_krb5_wrap.c b/net/sunrpc/auth_gss/gss_krb5_wrap.c
index 4b614c6..ca7e92a 100644
--- a/net/sunrpc/auth_gss/gss_krb5_wrap.c
+++ b/net/sunrpc/auth_gss/gss_krb5_wrap.c
@@ -35,7 +35,7 @@
#include <linux/pagemap.h>
#include <linux/crypto.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_mech_switch.c b/net/sunrpc/auth_gss/gss_mech_switch.c
index 92d5ab9..7063d85 100644
--- a/net/sunrpc/auth_gss/gss_mech_switch.c
+++ b/net/sunrpc/auth_gss/gss_mech_switch.c
@@ -46,7 +46,7 @@
#include <linux/sunrpc/gss_api.h>
#include <linux/sunrpc/clnt.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/gss_rpc_xdr.h b/net/sunrpc/auth_gss/gss_rpc_xdr.h
index 685a688..9d88c62 100644
--- a/net/sunrpc/auth_gss/gss_rpc_xdr.h
+++ b/net/sunrpc/auth_gss/gss_rpc_xdr.h
@@ -25,7 +25,7 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/xprtsock.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_gss/svcauth_gss.c b/net/sunrpc/auth_gss/svcauth_gss.c
index c548ab2..de856dd 100644
--- a/net/sunrpc/auth_gss/svcauth_gss.c
+++ b/net/sunrpc/auth_gss/svcauth_gss.c
@@ -51,7 +51,7 @@
#include "gss_rpc_upcall.h"
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/auth_null.c b/net/sunrpc/auth_null.c
index 712c123..c2a2b58 100644
--- a/net/sunrpc/auth_null.c
+++ b/net/sunrpc/auth_null.c
@@ -10,7 +10,7 @@
#include <linux/module.h>
#include <linux/sunrpc/clnt.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
@@ -138,7 +138,7 @@ struct rpc_cred null_cred = {
.cr_ops = &null_credops,
.cr_count = ATOMIC_INIT(1),
.cr_flags = 1UL << RPCAUTH_CRED_UPTODATE,
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
.cr_magic = RPCAUTH_CRED_MAGIC,
#endif
};
diff --git a/net/sunrpc/auth_unix.c b/net/sunrpc/auth_unix.c
index d5d6923..4feda2d 100644
--- a/net/sunrpc/auth_unix.c
+++ b/net/sunrpc/auth_unix.c
@@ -25,7 +25,7 @@ struct unx_cred {
#define UNX_WRITESLACK (21 + (UNX_MAXNODENAME >> 2))
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_AUTH
#endif
diff --git a/net/sunrpc/backchannel_rqst.c b/net/sunrpc/backchannel_rqst.c
index 9761a0d..651f49a 100644
--- a/net/sunrpc/backchannel_rqst.c
+++ b/net/sunrpc/backchannel_rqst.c
@@ -27,7 +27,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include <linux/export.h>
#include <linux/sunrpc/bc_xprt.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
#define RPCDBG_FACILITY RPCDBG_TRANS
#endif
diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c
index 9acd6ce..05da12a 100644
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -42,7 +42,7 @@
#include "sunrpc.h"
#include "netns.h"
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_CALL
#endif
@@ -305,6 +305,10 @@ static int rpc_client_register(struct rpc_clnt *clnt,
struct super_block *pipefs_sb;
int err;
+ err = rpc_clnt_debugfs_register(clnt);
+ if (err)
+ return err;
+
pipefs_sb = rpc_get_sb_net(net);
if (pipefs_sb) {
err = rpc_setup_pipedir(pipefs_sb, clnt);
@@ -331,6 +335,7 @@ err_auth:
out:
if (pipefs_sb)
rpc_put_sb_net(net);
+ rpc_clnt_debugfs_unregister(clnt);
return err;
}
@@ -670,6 +675,7 @@ int rpc_switch_client_transport(struct rpc_clnt *clnt,
rpc_unregister_client(clnt);
__rpc_clnt_remove_pipedir(clnt);
+ rpc_clnt_debugfs_unregister(clnt);
/*
* A new transport was created. "clnt" therefore
@@ -771,6 +777,7 @@ rpc_free_client(struct rpc_clnt *clnt)
rcu_dereference(clnt->cl_xprt)->servername);
if (clnt->cl_parent != clnt)
parent = clnt->cl_parent;
+ rpc_clnt_debugfs_unregister(clnt);
rpc_clnt_remove_pipedir(clnt);
rpc_unregister_client(clnt);
rpc_free_iostats(clnt->cl_metrics);
@@ -1396,8 +1403,9 @@ rpc_restart_call(struct rpc_task *task)
}
EXPORT_SYMBOL_GPL(rpc_restart_call);
-#ifdef RPC_DEBUG
-static const char *rpc_proc_name(const struct rpc_task *task)
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
+const char
+*rpc_proc_name(const struct rpc_task *task)
{
const struct rpc_procinfo *proc = task->tk_msg.rpc_proc;
@@ -2421,7 +2429,7 @@ struct rpc_task *rpc_call_null(struct rpc_clnt *clnt, struct rpc_cred *cred, int
}
EXPORT_SYMBOL_GPL(rpc_call_null);
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static void rpc_show_header(void)
{
printk(KERN_INFO "-pid- flgs status -client- --rqstp- "
diff --git a/net/sunrpc/debugfs.c b/net/sunrpc/debugfs.c
new file mode 100644
index 0000000..e811f39
--- /dev/null
+++ b/net/sunrpc/debugfs.c
@@ -0,0 +1,292 @@
+/**
+ * debugfs interface for sunrpc
+ *
+ * (c) 2014 Jeff Layton <jlayton@primarydata.com>
+ */
+
+#include <linux/debugfs.h>
+#include <linux/sunrpc/sched.h>
+#include <linux/sunrpc/clnt.h>
+#include "netns.h"
+
+static struct dentry *topdir;
+static struct dentry *rpc_clnt_dir;
+static struct dentry *rpc_xprt_dir;
+
+struct rpc_clnt_iter {
+ struct rpc_clnt *clnt;
+ loff_t pos;
+};
+
+static int
+tasks_show(struct seq_file *f, void *v)
+{
+ u32 xid = 0;
+ struct rpc_task *task = v;
+ struct rpc_clnt *clnt = task->tk_client;
+ const char *rpc_waitq = "none";
+
+ if (RPC_IS_QUEUED(task))
+ rpc_waitq = rpc_qname(task->tk_waitqueue);
+
+ if (task->tk_rqstp)
+ xid = be32_to_cpu(task->tk_rqstp->rq_xid);
+
+ seq_printf(f, "%5u %04x %6d 0x%x 0x%x %8ld %ps %sv%u %s a:%ps q:%s\n",
+ task->tk_pid, task->tk_flags, task->tk_status,
+ clnt->cl_clid, xid, task->tk_timeout, task->tk_ops,
+ clnt->cl_program->name, clnt->cl_vers, rpc_proc_name(task),
+ task->tk_action, rpc_waitq);
+ return 0;
+}
+
+static void *
+tasks_start(struct seq_file *f, loff_t *ppos)
+ __acquires(&clnt->cl_lock)
+{
+ struct rpc_clnt_iter *iter = f->private;
+ loff_t pos = *ppos;
+ struct rpc_clnt *clnt = iter->clnt;
+ struct rpc_task *task;
+
+ iter->pos = pos + 1;
+ spin_lock(&clnt->cl_lock);
+ list_for_each_entry(task, &clnt->cl_tasks, tk_task)
+ if (pos-- == 0)
+ return task;
+ return NULL;
+}
+
+static void *
+tasks_next(struct seq_file *f, void *v, loff_t *pos)
+{
+ struct rpc_clnt_iter *iter = f->private;
+ struct rpc_clnt *clnt = iter->clnt;
+ struct rpc_task *task = v;
+ struct list_head *next = task->tk_task.next;
+
+ ++iter->pos;
+ ++*pos;
+
+ /* If there's another task on list, return it */
+ if (next == &clnt->cl_tasks)
+ return NULL;
+ return list_entry(next, struct rpc_task, tk_task);
+}
+
+static void
+tasks_stop(struct seq_file *f, void *v)
+ __releases(&clnt->cl_lock)
+{
+ struct rpc_clnt_iter *iter = f->private;
+ struct rpc_clnt *clnt = iter->clnt;
+
+ spin_unlock(&clnt->cl_lock);
+}
+
+static const struct seq_operations tasks_seq_operations = {
+ .start = tasks_start,
+ .next = tasks_next,
+ .stop = tasks_stop,
+ .show = tasks_show,
+};
+
+static int tasks_open(struct inode *inode, struct file *filp)
+{
+ int ret = seq_open_private(filp, &tasks_seq_operations,
+ sizeof(struct rpc_clnt_iter));
+
+ if (!ret) {
+ struct seq_file *seq = filp->private_data;
+ struct rpc_clnt_iter *iter = seq->private;
+
+ iter->clnt = inode->i_private;
+
+ if (!atomic_inc_not_zero(&iter->clnt->cl_count)) {
+ seq_release_private(inode, filp);
+ ret = -EINVAL;
+ }
+ }
+
+ return ret;
+}
+
+static int
+tasks_release(struct inode *inode, struct file *filp)
+{
+ struct seq_file *seq = filp->private_data;
+ struct rpc_clnt_iter *iter = seq->private;
+
+ rpc_release_client(iter->clnt);
+ return seq_release_private(inode, filp);
+}
+
+static const struct file_operations tasks_fops = {
+ .owner = THIS_MODULE,
+ .open = tasks_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = tasks_release,
+};
+
+int
+rpc_clnt_debugfs_register(struct rpc_clnt *clnt)
+{
+ int len, err;
+ char name[24]; /* enough for "../../rpc_xprt/ + 8 hex digits + NULL */
+
+ /* Already registered? */
+ if (clnt->cl_debugfs)
+ return 0;
+
+ len = snprintf(name, sizeof(name), "%x", clnt->cl_clid);
+ if (len >= sizeof(name))
+ return -EINVAL;
+
+ /* make the per-client dir */
+ clnt->cl_debugfs = debugfs_create_dir(name, rpc_clnt_dir);
+ if (!clnt->cl_debugfs)
+ return -ENOMEM;
+
+ /* make tasks file */
+ err = -ENOMEM;
+ if (!debugfs_create_file("tasks", S_IFREG | S_IRUSR, clnt->cl_debugfs,
+ clnt, &tasks_fops))
+ goto out_err;
+
+ err = -EINVAL;
+ rcu_read_lock();
+ len = snprintf(name, sizeof(name), "../../rpc_xprt/%s",
+ rcu_dereference(clnt->cl_xprt)->debugfs->d_name.name);
+ rcu_read_unlock();
+ if (len >= sizeof(name))
+ goto out_err;
+
+ err = -ENOMEM;
+ if (!debugfs_create_symlink("xprt", clnt->cl_debugfs, name))
+ goto out_err;
+
+ return 0;
+out_err:
+ debugfs_remove_recursive(clnt->cl_debugfs);
+ clnt->cl_debugfs = NULL;
+ return err;
+}
+
+void
+rpc_clnt_debugfs_unregister(struct rpc_clnt *clnt)
+{
+ debugfs_remove_recursive(clnt->cl_debugfs);
+ clnt->cl_debugfs = NULL;
+}
+
+static int
+xprt_info_show(struct seq_file *f, void *v)
+{
+ struct rpc_xprt *xprt = f->private;
+
+ seq_printf(f, "netid: %s\n", xprt->address_strings[RPC_DISPLAY_NETID]);
+ seq_printf(f, "addr: %s\n", xprt->address_strings[RPC_DISPLAY_ADDR]);
+ seq_printf(f, "port: %s\n", xprt->address_strings[RPC_DISPLAY_PORT]);
+ seq_printf(f, "state: 0x%lx\n", xprt->state);
+ return 0;
+}
+
+static int
+xprt_info_open(struct inode *inode, struct file *filp)
+{
+ int ret;
+ struct rpc_xprt *xprt = inode->i_private;
+
+ ret = single_open(filp, xprt_info_show, xprt);
+
+ if (!ret) {
+ if (!xprt_get(xprt)) {
+ single_release(inode, filp);
+ ret = -EINVAL;
+ }
+ }
+ return ret;
+}
+
+static int
+xprt_info_release(struct inode *inode, struct file *filp)
+{
+ struct rpc_xprt *xprt = inode->i_private;
+
+ xprt_put(xprt);
+ return single_release(inode, filp);
+}
+
+static const struct file_operations xprt_info_fops = {
+ .owner = THIS_MODULE,
+ .open = xprt_info_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = xprt_info_release,
+};
+
+int
+rpc_xprt_debugfs_register(struct rpc_xprt *xprt)
+{
+ int len, id;
+ static atomic_t cur_id;
+ char name[9]; /* 8 hex digits + NULL term */
+
+ id = (unsigned int)atomic_inc_return(&cur_id);
+
+ len = snprintf(name, sizeof(name), "%x", id);
+ if (len >= sizeof(name))
+ return -EINVAL;
+
+ /* make the per-client dir */
+ xprt->debugfs = debugfs_create_dir(name, rpc_xprt_dir);
+ if (!xprt->debugfs)
+ return -ENOMEM;
+
+ /* make tasks file */
+ if (!debugfs_create_file("info", S_IFREG | S_IRUSR, xprt->debugfs,
+ xprt, &xprt_info_fops)) {
+ debugfs_remove_recursive(xprt->debugfs);
+ xprt->debugfs = NULL;
+ return -ENOMEM;
+ }
+
+ return 0;
+}
+
+void
+rpc_xprt_debugfs_unregister(struct rpc_xprt *xprt)
+{
+ debugfs_remove_recursive(xprt->debugfs);
+ xprt->debugfs = NULL;
+}
+
+void __exit
+sunrpc_debugfs_exit(void)
+{
+ debugfs_remove_recursive(topdir);
+}
+
+int __init
+sunrpc_debugfs_init(void)
+{
+ topdir = debugfs_create_dir("sunrpc", NULL);
+ if (!topdir)
+ goto out;
+
+ rpc_clnt_dir = debugfs_create_dir("rpc_clnt", topdir);
+ if (!rpc_clnt_dir)
+ goto out_remove;
+
+ rpc_xprt_dir = debugfs_create_dir("rpc_xprt", topdir);
+ if (!rpc_xprt_dir)
+ goto out_remove;
+
+ return 0;
+out_remove:
+ debugfs_remove_recursive(topdir);
+ topdir = NULL;
+out:
+ return -ENOMEM;
+}
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c
index 1891a10..0520201 100644
--- a/net/sunrpc/rpcb_clnt.c
+++ b/net/sunrpc/rpcb_clnt.c
@@ -32,7 +32,7 @@
#include "netns.h"
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_BIND
#endif
diff --git a/net/sunrpc/sched.c b/net/sunrpc/sched.c
index fe3441a..d20f232 100644
--- a/net/sunrpc/sched.c
+++ b/net/sunrpc/sched.c
@@ -24,7 +24,7 @@
#include "sunrpc.h"
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
#define RPCDBG_FACILITY RPCDBG_SCHED
#endif
@@ -258,7 +258,7 @@ static int rpc_wait_bit_killable(struct wait_bit_key *key)
return 0;
}
-#if defined(RPC_DEBUG) || defined(RPC_TRACEPOINTS)
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG) || IS_ENABLED(CONFIG_TRACEPOINTS)
static void rpc_task_set_debuginfo(struct rpc_task *task)
{
static atomic_t rpc_pid;
diff --git a/net/sunrpc/stats.c b/net/sunrpc/stats.c
index 5453049..9711a15 100644
--- a/net/sunrpc/stats.c
+++ b/net/sunrpc/stats.c
@@ -116,7 +116,15 @@ EXPORT_SYMBOL_GPL(svc_seq_show);
*/
struct rpc_iostats *rpc_alloc_iostats(struct rpc_clnt *clnt)
{
- return kcalloc(clnt->cl_maxproc, sizeof(struct rpc_iostats), GFP_KERNEL);
+ struct rpc_iostats *stats;
+ int i;
+
+ stats = kcalloc(clnt->cl_maxproc, sizeof(*stats), GFP_KERNEL);
+ if (stats) {
+ for (i = 0; i < clnt->cl_maxproc; i++)
+ spin_lock_init(&stats[i].om_lock);
+ }
+ return stats;
}
EXPORT_SYMBOL_GPL(rpc_alloc_iostats);
@@ -135,20 +143,21 @@ EXPORT_SYMBOL_GPL(rpc_free_iostats);
* rpc_count_iostats - tally up per-task stats
* @task: completed rpc_task
* @stats: array of stat structures
- *
- * Relies on the caller for serialization.
*/
void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
{
struct rpc_rqst *req = task->tk_rqstp;
struct rpc_iostats *op_metrics;
- ktime_t delta;
+ ktime_t delta, now;
if (!stats || !req)
return;
+ now = ktime_get();
op_metrics = &stats[task->tk_msg.rpc_proc->p_statidx];
+ spin_lock(&op_metrics->om_lock);
+
op_metrics->om_ops++;
op_metrics->om_ntrans += req->rq_ntrans;
op_metrics->om_timeouts += task->tk_timeouts;
@@ -161,8 +170,10 @@ void rpc_count_iostats(const struct rpc_task *task, struct rpc_iostats *stats)
op_metrics->om_rtt = ktime_add(op_metrics->om_rtt, req->rq_rtt);
- delta = ktime_sub(ktime_get(), task->tk_start);
+ delta = ktime_sub(now, task->tk_start);
op_metrics->om_execute = ktime_add(op_metrics->om_execute, delta);
+
+ spin_unlock(&op_metrics->om_lock);
}
EXPORT_SYMBOL_GPL(rpc_count_iostats);
diff --git a/net/sunrpc/sunrpc_syms.c b/net/sunrpc/sunrpc_syms.c
index cd30120..e37fbed 100644
--- a/net/sunrpc/sunrpc_syms.c
+++ b/net/sunrpc/sunrpc_syms.c
@@ -97,13 +97,20 @@ init_sunrpc(void)
err = register_rpc_pipefs();
if (err)
goto out4;
-#ifdef RPC_DEBUG
+
+ err = sunrpc_debugfs_init();
+ if (err)
+ goto out5;
+
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
rpc_register_sysctl();
#endif
svc_init_xprt_sock(); /* svc sock transport */
init_socket_xprt(); /* clnt sock transport */
return 0;
+out5:
+ unregister_rpc_pipefs();
out4:
unregister_pernet_subsys(&sunrpc_net_ops);
out3:
@@ -120,10 +127,11 @@ cleanup_sunrpc(void)
rpcauth_remove_module();
cleanup_socket_xprt();
svc_cleanup_xprt_sock();
+ sunrpc_debugfs_exit();
unregister_rpc_pipefs();
rpc_destroy_mempool();
unregister_pernet_subsys(&sunrpc_net_ops);
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
rpc_unregister_sysctl();
#endif
rcu_barrier(); /* Wait for completion of call_rcu()'s */
diff --git a/net/sunrpc/svc.c b/net/sunrpc/svc.c
index ca8a795..2783fd8 100644
--- a/net/sunrpc/svc.c
+++ b/net/sunrpc/svc.c
@@ -28,6 +28,8 @@
#include <linux/sunrpc/clnt.h>
#include <linux/sunrpc/bc_xprt.h>
+#include <trace/events/sunrpc.h>
+
#define RPCDBG_FACILITY RPCDBG_SVCDSP
static void svc_unregister(const struct svc_serv *serv, struct net *net);
@@ -1040,7 +1042,7 @@ static void svc_unregister(const struct svc_serv *serv, struct net *net)
/*
* dprintk the given error with the address of the client that caused it.
*/
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static __printf(2, 3)
void svc_printk(struct svc_rqst *rqstp, const char *fmt, ...)
{
@@ -1314,24 +1316,25 @@ svc_process(struct svc_rqst *rqstp)
rqstp->rq_res.tail[0].iov_base = NULL;
rqstp->rq_res.tail[0].iov_len = 0;
- rqstp->rq_xid = svc_getu32(argv);
-
dir = svc_getnl(argv);
if (dir != 0) {
/* direction != CALL */
svc_printk(rqstp, "bad direction %d, dropping request\n", dir);
serv->sv_stats->rpcbadfmt++;
- svc_drop(rqstp);
- return 0;
+ goto out_drop;
}
/* Returns 1 for send, 0 for drop */
- if (svc_process_common(rqstp, argv, resv))
- return svc_send(rqstp);
- else {
- svc_drop(rqstp);
- return 0;
+ if (likely(svc_process_common(rqstp, argv, resv))) {
+ int ret = svc_send(rqstp);
+
+ trace_svc_process(rqstp, ret);
+ return ret;
}
+out_drop:
+ trace_svc_process(rqstp, 0);
+ svc_drop(rqstp);
+ return 0;
}
#if defined(CONFIG_SUNRPC_BACKCHANNEL)
diff --git a/net/sunrpc/svc_xprt.c b/net/sunrpc/svc_xprt.c
index c179ca2..bbb3b04 100644
--- a/net/sunrpc/svc_xprt.c
+++ b/net/sunrpc/svc_xprt.c
@@ -15,6 +15,7 @@
#include <linux/sunrpc/svcsock.h>
#include <linux/sunrpc/xprt.h>
#include <linux/module.h>
+#include <trace/events/sunrpc.h>
#define RPCDBG_FACILITY RPCDBG_SVCXPRT
@@ -773,35 +774,43 @@ int svc_recv(struct svc_rqst *rqstp, long timeout)
err = svc_alloc_arg(rqstp);
if (err)
- return err;
+ goto out;
try_to_freeze();
cond_resched();
+ err = -EINTR;
if (signalled() || kthread_should_stop())
- return -EINTR;
+ goto out;
xprt = svc_get_next_xprt(rqstp, timeout);
- if (IS_ERR(xprt))
- return PTR_ERR(xprt);
+ if (IS_ERR(xprt)) {
+ err = PTR_ERR(xprt);
+ goto out;
+ }
len = svc_handle_xprt(rqstp, xprt);
/* No data, incomplete (TCP) read, or accept() */
+ err = -EAGAIN;
if (len <= 0)
- goto out;
+ goto out_release;
clear_bit(XPT_OLD, &xprt->xpt_flags);
rqstp->rq_secure = xprt->xpt_ops->xpo_secure_port(rqstp);
rqstp->rq_chandle.defer = svc_defer;
+ rqstp->rq_xid = svc_getu32(&rqstp->rq_arg.head[0]);
if (serv->sv_stats)
serv->sv_stats->netcnt++;
+ trace_svc_recv(rqstp, len);
return len;
-out:
+out_release:
rqstp->rq_res.len = 0;
svc_xprt_release(rqstp);
- return -EAGAIN;
+out:
+ trace_svc_recv(rqstp, err);
+ return err;
}
EXPORT_SYMBOL_GPL(svc_recv);
@@ -821,12 +830,12 @@ EXPORT_SYMBOL_GPL(svc_drop);
int svc_send(struct svc_rqst *rqstp)
{
struct svc_xprt *xprt;
- int len;
+ int len = -EFAULT;
struct xdr_buf *xb;
xprt = rqstp->rq_xprt;
if (!xprt)
- return -EFAULT;
+ goto out;
/* release the receive skb before sending the reply */
rqstp->rq_xprt->xpt_ops->xpo_release_rqst(rqstp);
@@ -849,7 +858,9 @@ int svc_send(struct svc_rqst *rqstp)
svc_xprt_release(rqstp);
if (len == -ECONNREFUSED || len == -ENOTCONN || len == -EAGAIN)
- return 0;
+ len = 0;
+out:
+ trace_svc_send(rqstp, len);
return len;
}
diff --git a/net/sunrpc/sysctl.c b/net/sunrpc/sysctl.c
index c99c58e..887f018 100644
--- a/net/sunrpc/sysctl.c
+++ b/net/sunrpc/sysctl.c
@@ -37,7 +37,7 @@ EXPORT_SYMBOL_GPL(nfsd_debug);
unsigned int nlm_debug;
EXPORT_SYMBOL_GPL(nlm_debug);
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static struct ctl_table_header *sunrpc_table_header;
static struct ctl_table sunrpc_table[];
diff --git a/net/sunrpc/xprt.c b/net/sunrpc/xprt.c
index 56e4e15..ebbefad 100644
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -49,13 +49,15 @@
#include <linux/sunrpc/metrics.h>
#include <linux/sunrpc/bc_xprt.h>
+#include <trace/events/sunrpc.h>
+
#include "sunrpc.h"
/*
* Local variables
*/
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_XPRT
#endif
@@ -772,11 +774,14 @@ struct rpc_rqst *xprt_lookup_rqst(struct rpc_xprt *xprt, __be32 xid)
struct rpc_rqst *entry;
list_for_each_entry(entry, &xprt->recv, rq_list)
- if (entry->rq_xid == xid)
+ if (entry->rq_xid == xid) {
+ trace_xprt_lookup_rqst(xprt, xid, 0);
return entry;
+ }
dprintk("RPC: xprt_lookup_rqst did not find xid %08x\n",
ntohl(xid));
+ trace_xprt_lookup_rqst(xprt, xid, -ENOENT);
xprt->stat.bad_xids++;
return NULL;
}
@@ -810,6 +815,7 @@ void xprt_complete_rqst(struct rpc_task *task, int copied)
dprintk("RPC: %5u xid %08x complete (%d bytes received)\n",
task->tk_pid, ntohl(req->rq_xid), copied);
+ trace_xprt_complete_rqst(xprt, req->rq_xid, copied);
xprt->stat.recvs++;
req->rq_rtt = ktime_sub(ktime_get(), req->rq_xtime);
@@ -926,6 +932,7 @@ void xprt_transmit(struct rpc_task *task)
req->rq_xtime = ktime_get();
status = xprt->ops->send_request(task);
+ trace_xprt_transmit(xprt, req->rq_xid, status);
if (status != 0) {
task->tk_status = status;
return;
@@ -1296,6 +1303,7 @@ static void xprt_init(struct rpc_xprt *xprt, struct net *net)
*/
struct rpc_xprt *xprt_create_transport(struct xprt_create *args)
{
+ int err;
struct rpc_xprt *xprt;
struct xprt_class *t;
@@ -1336,6 +1344,12 @@ found:
return ERR_PTR(-ENOMEM);
}
+ err = rpc_xprt_debugfs_register(xprt);
+ if (err) {
+ xprt_destroy(xprt);
+ return ERR_PTR(err);
+ }
+
dprintk("RPC: created transport %p with %u slots\n", xprt,
xprt->max_reqs);
out:
@@ -1352,6 +1366,7 @@ static void xprt_destroy(struct rpc_xprt *xprt)
dprintk("RPC: destroying transport %p\n", xprt);
del_timer_sync(&xprt->timer);
+ rpc_xprt_debugfs_unregister(xprt);
rpc_destroy_wait_queue(&xprt->binding);
rpc_destroy_wait_queue(&xprt->pending);
rpc_destroy_wait_queue(&xprt->sending);
diff --git a/net/sunrpc/xprtrdma/rpc_rdma.c b/net/sunrpc/xprtrdma/rpc_rdma.c
index 6166c98..df01d12 100644
--- a/net/sunrpc/xprtrdma/rpc_rdma.c
+++ b/net/sunrpc/xprtrdma/rpc_rdma.c
@@ -49,11 +49,11 @@
#include <linux/highmem.h>
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_TRANS
#endif
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static const char transfertypes[][12] = {
"pure inline", /* no chunks */
" read chunk", /* some argument via rdma read */
diff --git a/net/sunrpc/xprtrdma/transport.c b/net/sunrpc/xprtrdma/transport.c
index 6a4615d..bbd6155 100644
--- a/net/sunrpc/xprtrdma/transport.c
+++ b/net/sunrpc/xprtrdma/transport.c
@@ -55,7 +55,7 @@
#include "xprt_rdma.h"
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_TRANS
#endif
@@ -73,9 +73,9 @@ static unsigned int xprt_rdma_max_inline_read = RPCRDMA_DEF_INLINE;
static unsigned int xprt_rdma_max_inline_write = RPCRDMA_DEF_INLINE;
static unsigned int xprt_rdma_inline_write_padding;
static unsigned int xprt_rdma_memreg_strategy = RPCRDMA_FRMR;
- int xprt_rdma_pad_optimize = 0;
+ int xprt_rdma_pad_optimize = 1;
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static unsigned int min_slot_table_size = RPCRDMA_MIN_SLOT_TABLE;
static unsigned int max_slot_table_size = RPCRDMA_MAX_SLOT_TABLE;
@@ -599,7 +599,7 @@ xprt_rdma_send_request(struct rpc_task *task)
if (req->rl_niovs == 0)
rc = rpcrdma_marshal_req(rqst);
- else if (r_xprt->rx_ia.ri_memreg_strategy == RPCRDMA_FRMR)
+ else if (r_xprt->rx_ia.ri_memreg_strategy != RPCRDMA_ALLPHYSICAL)
rc = rpcrdma_marshal_chunks(rqst, 0);
if (rc < 0)
goto failed_marshal;
@@ -705,7 +705,7 @@ static void __exit xprt_rdma_cleanup(void)
int rc;
dprintk("RPCRDMA Module Removed, deregister RPC RDMA transport\n");
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
if (sunrpc_table_header) {
unregister_sysctl_table(sunrpc_table_header);
sunrpc_table_header = NULL;
@@ -736,7 +736,7 @@ static int __init xprt_rdma_init(void)
dprintk("\tPadding %d\n\tMemreg %d\n",
xprt_rdma_inline_write_padding, xprt_rdma_memreg_strategy);
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
if (!sunrpc_table_header)
sunrpc_table_header = register_sysctl_table(sunrpc_table);
#endif
diff --git a/net/sunrpc/xprtrdma/verbs.c b/net/sunrpc/xprtrdma/verbs.c
index 61c4129..c98e406 100644
--- a/net/sunrpc/xprtrdma/verbs.c
+++ b/net/sunrpc/xprtrdma/verbs.c
@@ -57,11 +57,12 @@
* Globals/Macros
*/
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# define RPCDBG_FACILITY RPCDBG_TRANS
#endif
static void rpcrdma_reset_frmrs(struct rpcrdma_ia *);
+static void rpcrdma_reset_fmrs(struct rpcrdma_ia *);
/*
* internal functions
@@ -105,13 +106,51 @@ rpcrdma_run_tasklet(unsigned long data)
static DECLARE_TASKLET(rpcrdma_tasklet_g, rpcrdma_run_tasklet, 0UL);
+static const char * const async_event[] = {
+ "CQ error",
+ "QP fatal error",
+ "QP request error",
+ "QP access error",
+ "communication established",
+ "send queue drained",
+ "path migration successful",
+ "path mig error",
+ "device fatal error",
+ "port active",
+ "port error",
+ "LID change",
+ "P_key change",
+ "SM change",
+ "SRQ error",
+ "SRQ limit reached",
+ "last WQE reached",
+ "client reregister",
+ "GID change",
+};
+
+#define ASYNC_MSG(status) \
+ ((status) < ARRAY_SIZE(async_event) ? \
+ async_event[(status)] : "unknown async error")
+
+static void
+rpcrdma_schedule_tasklet(struct list_head *sched_list)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
+ list_splice_tail(sched_list, &rpcrdma_tasklets_g);
+ spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
+ tasklet_schedule(&rpcrdma_tasklet_g);
+}
+
static void
rpcrdma_qp_async_error_upcall(struct ib_event *event, void *context)
{
struct rpcrdma_ep *ep = context;
- dprintk("RPC: %s: QP error %X on device %s ep %p\n",
- __func__, event->event, event->device->name, context);
+ pr_err("RPC: %s: %s on device %s ep %p\n",
+ __func__, ASYNC_MSG(event->event),
+ event->device->name, context);
if (ep->rep_connected == 1) {
ep->rep_connected = -EIO;
ep->rep_func(ep);
@@ -124,8 +163,9 @@ rpcrdma_cq_async_error_upcall(struct ib_event *event, void *context)
{
struct rpcrdma_ep *ep = context;
- dprintk("RPC: %s: CQ error %X on device %s ep %p\n",
- __func__, event->event, event->device->name, context);
+ pr_err("RPC: %s: %s on device %s ep %p\n",
+ __func__, ASYNC_MSG(event->event),
+ event->device->name, context);
if (ep->rep_connected == 1) {
ep->rep_connected = -EIO;
ep->rep_func(ep);
@@ -243,7 +283,6 @@ rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
struct list_head sched_list;
struct ib_wc *wcs;
int budget, count, rc;
- unsigned long flags;
INIT_LIST_HEAD(&sched_list);
budget = RPCRDMA_WC_BUDGET / RPCRDMA_POLLSIZE;
@@ -261,10 +300,7 @@ rpcrdma_recvcq_poll(struct ib_cq *cq, struct rpcrdma_ep *ep)
rc = 0;
out_schedule:
- spin_lock_irqsave(&rpcrdma_tk_lock_g, flags);
- list_splice_tail(&sched_list, &rpcrdma_tasklets_g);
- spin_unlock_irqrestore(&rpcrdma_tk_lock_g, flags);
- tasklet_schedule(&rpcrdma_tasklet_g);
+ rpcrdma_schedule_tasklet(&sched_list);
return rc;
}
@@ -309,11 +345,18 @@ rpcrdma_recvcq_upcall(struct ib_cq *cq, void *cq_context)
static void
rpcrdma_flush_cqs(struct rpcrdma_ep *ep)
{
- rpcrdma_recvcq_upcall(ep->rep_attr.recv_cq, ep);
- rpcrdma_sendcq_upcall(ep->rep_attr.send_cq, ep);
+ struct ib_wc wc;
+ LIST_HEAD(sched_list);
+
+ while (ib_poll_cq(ep->rep_attr.recv_cq, 1, &wc) > 0)
+ rpcrdma_recvcq_process_wc(&wc, &sched_list);
+ if (!list_empty(&sched_list))
+ rpcrdma_schedule_tasklet(&sched_list);
+ while (ib_poll_cq(ep->rep_attr.send_cq, 1, &wc) > 0)
+ rpcrdma_sendcq_process_wc(&wc);
}
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static const char * const conn[] = {
"address resolved",
"address error",
@@ -344,7 +387,7 @@ rpcrdma_conn_upcall(struct rdma_cm_id *id, struct rdma_cm_event *event)
struct rpcrdma_xprt *xprt = id->context;
struct rpcrdma_ia *ia = &xprt->rx_ia;
struct rpcrdma_ep *ep = &xprt->rx_ep;
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
struct sockaddr_in *addr = (struct sockaddr_in *) &ep->rep_remote_addr;
#endif
struct ib_qp_attr attr;
@@ -408,7 +451,7 @@ connected:
break;
}
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
if (connstate == 1) {
int ird = attr.max_dest_rd_atomic;
int tird = ep->rep_remote_cma.responder_resources;
@@ -733,7 +776,9 @@ rpcrdma_ep_create(struct rpcrdma_ep *ep, struct rpcrdma_ia *ia,
/* set trigger for requesting send completion */
ep->rep_cqinit = ep->rep_attr.cap.max_send_wr/2 - 1;
- if (ep->rep_cqinit <= 2)
+ if (ep->rep_cqinit > RPCRDMA_MAX_UNSIGNALED_SENDS)
+ ep->rep_cqinit = RPCRDMA_MAX_UNSIGNALED_SENDS;
+ else if (ep->rep_cqinit <= 2)
ep->rep_cqinit = 0;
INIT_CQCOUNT(ep);
ep->rep_ia = ia;
@@ -866,8 +911,19 @@ retry:
rpcrdma_ep_disconnect(ep, ia);
rpcrdma_flush_cqs(ep);
- if (ia->ri_memreg_strategy == RPCRDMA_FRMR)
+ switch (ia->ri_memreg_strategy) {
+ case RPCRDMA_FRMR:
rpcrdma_reset_frmrs(ia);
+ break;
+ case RPCRDMA_MTHCAFMR:
+ rpcrdma_reset_fmrs(ia);
+ break;
+ case RPCRDMA_ALLPHYSICAL:
+ break;
+ default:
+ rc = -EIO;
+ goto out;
+ }
xprt = container_of(ia, struct rpcrdma_xprt, rx_ia);
id = rpcrdma_create_id(xprt, ia,
@@ -1287,6 +1343,34 @@ rpcrdma_buffer_destroy(struct rpcrdma_buffer *buf)
kfree(buf->rb_pool);
}
+/* After a disconnect, unmap all FMRs.
+ *
+ * This is invoked only in the transport connect worker in order
+ * to serialize with rpcrdma_register_fmr_external().
+ */
+static void
+rpcrdma_reset_fmrs(struct rpcrdma_ia *ia)
+{
+ struct rpcrdma_xprt *r_xprt =
+ container_of(ia, struct rpcrdma_xprt, rx_ia);
+ struct rpcrdma_buffer *buf = &r_xprt->rx_buf;
+ struct list_head *pos;
+ struct rpcrdma_mw *r;
+ LIST_HEAD(l);
+ int rc;
+
+ list_for_each(pos, &buf->rb_all) {
+ r = list_entry(pos, struct rpcrdma_mw, mw_all);
+
+ INIT_LIST_HEAD(&l);
+ list_add(&r->r.fmr->list, &l);
+ rc = ib_unmap_fmr(&l);
+ if (rc)
+ dprintk("RPC: %s: ib_unmap_fmr failed %i\n",
+ __func__, rc);
+ }
+}
+
/* After a disconnect, a flushed FAST_REG_MR can leave an FRMR in
* an unusable state. Find FRMRs in this state and dereg / reg
* each. FRMRs that are VALID and attached to an rpcrdma_req are
@@ -1918,10 +2002,10 @@ rpcrdma_register_external(struct rpcrdma_mr_seg *seg,
break;
default:
- return -1;
+ return -EIO;
}
if (rc)
- return -1;
+ return rc;
return nsegs;
}
diff --git a/net/sunrpc/xprtrdma/xprt_rdma.h b/net/sunrpc/xprtrdma/xprt_rdma.h
index ac7fc9a..b799041 100644
--- a/net/sunrpc/xprtrdma/xprt_rdma.h
+++ b/net/sunrpc/xprtrdma/xprt_rdma.h
@@ -97,6 +97,12 @@ struct rpcrdma_ep {
struct ib_wc rep_recv_wcs[RPCRDMA_POLLSIZE];
};
+/*
+ * Force a signaled SEND Work Request every so often,
+ * in case the provider needs to do some housekeeping.
+ */
+#define RPCRDMA_MAX_UNSIGNALED_SENDS (32)
+
#define INIT_CQCOUNT(ep) atomic_set(&(ep)->rep_cqcount, (ep)->rep_cqinit)
#define DECR_CQCOUNT(ep) atomic_sub_return(1, &(ep)->rep_cqcount)
diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c
index 3b305ab..87ce7e8 100644
--- a/net/sunrpc/xprtsock.c
+++ b/net/sunrpc/xprtsock.c
@@ -75,7 +75,7 @@ static unsigned int xs_tcp_fin_timeout __read_mostly = XS_TCP_LINGER_TO;
* someone else's file names!
*/
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
static unsigned int min_slot_table_size = RPC_MIN_SLOT_TABLE;
static unsigned int max_slot_table_size = RPC_MAX_SLOT_TABLE;
@@ -186,7 +186,7 @@ static struct ctl_table sunrpc_table[] = {
*/
#define XS_IDLE_DISC_TO (5U * 60 * HZ)
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
# undef RPC_DEBUG_DATA
# define RPCDBG_FACILITY RPCDBG_TRANS
#endif
@@ -216,65 +216,6 @@ static inline void xs_pktdump(char *msg, u32 *packet, unsigned int count)
}
#endif
-struct sock_xprt {
- struct rpc_xprt xprt;
-
- /*
- * Network layer
- */
- struct socket * sock;
- struct sock * inet;
-
- /*
- * State of TCP reply receive
- */
- __be32 tcp_fraghdr,
- tcp_xid,
- tcp_calldir;
-
- u32 tcp_offset,
- tcp_reclen;
-
- unsigned long tcp_copied,
- tcp_flags;
-
- /*
- * Connection of transports
- */
- struct delayed_work connect_worker;
- struct sockaddr_storage srcaddr;
- unsigned short srcport;
-
- /*
- * UDP socket buffer size parameters
- */
- size_t rcvsize,
- sndsize;
-
- /*
- * Saved socket callback addresses
- */
- void (*old_data_ready)(struct sock *);
- void (*old_state_change)(struct sock *);
- void (*old_write_space)(struct sock *);
- void (*old_error_report)(struct sock *);
-};
-
-/*
- * TCP receive state flags
- */
-#define TCP_RCV_LAST_FRAG (1UL << 0)
-#define TCP_RCV_COPY_FRAGHDR (1UL << 1)
-#define TCP_RCV_COPY_XID (1UL << 2)
-#define TCP_RCV_COPY_DATA (1UL << 3)
-#define TCP_RCV_READ_CALLDIR (1UL << 4)
-#define TCP_RCV_COPY_CALLDIR (1UL << 5)
-
-/*
- * TCP RPC flags
- */
-#define TCP_RPC_REPLY (1UL << 6)
-
static inline struct rpc_xprt *xprt_from_sock(struct sock *sk)
{
return (struct rpc_xprt *) sk->sk_user_data;
@@ -1415,6 +1356,7 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns
dprintk("RPC: xs_tcp_data_recv started\n");
do {
+ trace_xs_tcp_data_recv(transport);
/* Read in a new fragment marker if necessary */
/* Can we ever really expect to get completely empty fragments? */
if (transport->tcp_flags & TCP_RCV_COPY_FRAGHDR) {
@@ -1439,6 +1381,7 @@ static int xs_tcp_data_recv(read_descriptor_t *rd_desc, struct sk_buff *skb, uns
/* Skip over any trailing bytes on short reads */
xs_tcp_read_discard(transport, &desc);
} while (desc.count);
+ trace_xs_tcp_data_recv(transport);
dprintk("RPC: xs_tcp_data_recv done\n");
return len - desc.count;
}
@@ -1454,12 +1397,15 @@ static void xs_tcp_data_ready(struct sock *sk)
struct rpc_xprt *xprt;
read_descriptor_t rd_desc;
int read;
+ unsigned long total = 0;
dprintk("RPC: xs_tcp_data_ready...\n");
read_lock_bh(&sk->sk_callback_lock);
- if (!(xprt = xprt_from_sock(sk)))
+ if (!(xprt = xprt_from_sock(sk))) {
+ read = 0;
goto out;
+ }
/* Any data means we had a useful conversation, so
* the we don't need to delay the next reconnect
*/
@@ -1471,8 +1417,11 @@ static void xs_tcp_data_ready(struct sock *sk)
do {
rd_desc.count = 65536;
read = tcp_read_sock(sk, &rd_desc, xs_tcp_data_recv);
+ if (read > 0)
+ total += read;
} while (read > 0);
out:
+ trace_xs_tcp_data_ready(xprt, read, total);
read_unlock_bh(&sk->sk_callback_lock);
}
@@ -3042,7 +2991,7 @@ static struct xprt_class xs_bc_tcp_transport = {
*/
int init_socket_xprt(void)
{
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
if (!sunrpc_table_header)
sunrpc_table_header = register_sysctl_table(sunrpc_table);
#endif
@@ -3061,7 +3010,7 @@ int init_socket_xprt(void)
*/
void cleanup_socket_xprt(void)
{
-#ifdef RPC_DEBUG
+#if IS_ENABLED(CONFIG_SUNRPC_DEBUG)
if (sunrpc_table_header) {
unregister_sysctl_table(sunrpc_table_header);
sunrpc_table_header = NULL;
diff --git a/scripts/Kbuild.include b/scripts/Kbuild.include
index 65e7b08..5374b1b 100644
--- a/scripts/Kbuild.include
+++ b/scripts/Kbuild.include
@@ -179,6 +179,12 @@ build := -f $(srctree)/scripts/Makefile.build obj
# $(Q)$(MAKE) $(modbuiltin)=dir
modbuiltin := -f $(srctree)/scripts/Makefile.modbuiltin obj
+###
+# Shorthand for $(Q)$(MAKE) -f scripts/Makefile.dtbinst obj=
+# Usage:
+# $(Q)$(MAKE) $(dtbinst)=dir
+dtbinst := -f $(if $(KBUILD_SRC),$(srctree)/)scripts/Makefile.dtbinst obj
+
# Prefix -I with $(srctree) if it is not an absolute path.
# skip if -I has no parameter
addtree = $(if $(patsubst -I%,%,$(1)), \
diff --git a/scripts/Makefile.dtbinst b/scripts/Makefile.dtbinst
new file mode 100644
index 0000000..909ed7a
--- /dev/null
+++ b/scripts/Makefile.dtbinst
@@ -0,0 +1,51 @@
+# ==========================================================================
+# Installing dtb files
+#
+# Installs all dtb files listed in $(dtb-y) either in the
+# INSTALL_DTBS_PATH directory or the default location:
+#
+# $INSTALL_PATH/dtbs/$KERNELRELEASE
+#
+# Traverse through subdirectories listed in $(dts-dirs).
+# ==========================================================================
+
+src := $(obj)
+
+PHONY := __dtbs_install
+__dtbs_install:
+
+export dtbinst-root ?= $(obj)
+
+include include/config/auto.conf
+include scripts/Kbuild.include
+include $(srctree)/$(obj)/Makefile
+
+PHONY += __dtbs_install_prep
+__dtbs_install_prep:
+ifeq ("$(dtbinst-root)", "$(obj)")
+ $(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
+ $(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
+ $(Q)mkdir -p $(INSTALL_DTBS_PATH)
+endif
+
+dtbinst-files := $(dtb-y)
+dtbinst-dirs := $(dts-dirs)
+
+# Helper targets for Installing DTBs into the boot directory
+quiet_cmd_dtb_install = INSTALL $<
+ cmd_dtb_install = mkdir -p $(2); cp $< $(2)
+
+install-dir = $(patsubst $(dtbinst-root)%,$(INSTALL_DTBS_PATH)%,$(obj))
+
+$(dtbinst-files) $(dtbinst-dirs): | __dtbs_install_prep
+
+$(dtbinst-files): %.dtb: $(obj)/%.dtb
+ $(call cmd,dtb_install,$(install-dir))
+
+$(dtbinst-dirs):
+ $(Q)$(MAKE) $(dtbinst)=$(obj)/$@
+
+PHONY += $(dtbinst-files) $(dtbinst-dirs)
+__dtbs_install: $(dtbinst-files) $(dtbinst-dirs)
+
+.PHONY: $(PHONY)
diff --git a/scripts/Makefile.lib b/scripts/Makefile.lib
index 54be19a..5117552 100644
--- a/scripts/Makefile.lib
+++ b/scripts/Makefile.lib
@@ -283,18 +283,6 @@ $(obj)/%.dtb: $(src)/%.dts FORCE
dtc-tmp = $(subst $(comma),_,$(dot-target).dts.tmp)
-# Helper targets for Installing DTBs into the boot directory
-quiet_cmd_dtb_install = INSTALL $<
- cmd_dtb_install = cp $< $(2)
-
-_dtbinst_pre_:
- $(Q)if [ -d $(INSTALL_DTBS_PATH).old ]; then rm -rf $(INSTALL_DTBS_PATH).old; fi
- $(Q)if [ -d $(INSTALL_DTBS_PATH) ]; then mv $(INSTALL_DTBS_PATH) $(INSTALL_DTBS_PATH).old; fi
- $(Q)mkdir -p $(INSTALL_DTBS_PATH)
-
-%.dtb_dtbinst_: $(obj)/%.dtb _dtbinst_pre_
- $(call cmd,dtb_install,$(INSTALL_DTBS_PATH))
-
# Bzip2
# ---------------------------------------------------------------------------
diff --git a/scripts/checkpatch.pl b/scripts/checkpatch.pl
index 374abf4..f0bb6d6 100755
--- a/scripts/checkpatch.pl
+++ b/scripts/checkpatch.pl
@@ -7,10 +7,11 @@
use strict;
use POSIX;
+use File::Basename;
+use Cwd 'abs_path';
my $P = $0;
-$P =~ s@(.*)/@@g;
-my $D = $1;
+my $D = dirname(abs_path($P));
my $V = '0.32';
@@ -438,26 +439,29 @@ our $allowed_asm_includes = qr{(?x:
# Load common spelling mistakes and build regular expression list.
my $misspellings;
-my @spelling_list;
my %spelling_fix;
-open(my $spelling, '<', $spelling_file)
- or die "$P: Can't open $spelling_file for reading: $!\n";
-while (<$spelling>) {
- my $line = $_;
- $line =~ s/\s*\n?$//g;
- $line =~ s/^\s*//g;
+if (open(my $spelling, '<', $spelling_file)) {
+ my @spelling_list;
+ while (<$spelling>) {
+ my $line = $_;
- next if ($line =~ m/^\s*#/);
- next if ($line =~ m/^\s*$/);
+ $line =~ s/\s*\n?$//g;
+ $line =~ s/^\s*//g;
- my ($suspect, $fix) = split(/\|\|/, $line);
+ next if ($line =~ m/^\s*#/);
+ next if ($line =~ m/^\s*$/);
- push(@spelling_list, $suspect);
- $spelling_fix{$suspect} = $fix;
+ my ($suspect, $fix) = split(/\|\|/, $line);
+
+ push(@spelling_list, $suspect);
+ $spelling_fix{$suspect} = $fix;
+ }
+ close($spelling);
+ $misspellings = join("|", @spelling_list);
+} else {
+ warn "No typos will be found - file '$spelling_file': $!\n";
}
-close($spelling);
-$misspellings = join("|", @spelling_list);
sub build_types {
my $mods = "(?x: \n" . join("|\n ", @modifierList) . "\n)";
@@ -942,7 +946,7 @@ sub sanitise_line {
sub get_quoted_string {
my ($line, $rawline) = @_;
- return "" if ($line !~ m/(\"[X]+\")/g);
+ return "" if ($line !~ m/(\"[X\t]+\")/g);
return substr($rawline, $-[0], $+[0] - $-[0]);
}
@@ -1843,6 +1847,7 @@ sub process {
my $non_utf8_charset = 0;
my $last_blank_line = 0;
+ my $last_coalesced_string_linenr = -1;
our @report = ();
our $cnt_lines = 0;
@@ -2078,6 +2083,12 @@ sub process {
$in_commit_log = 0;
}
+# Check if MAINTAINERS is being updated. If so, there's probably no need to
+# emit the "does MAINTAINERS need updating?" message on file add/move/delete
+ if ($line =~ /^\s*MAINTAINERS\s*\|/) {
+ $reported_maintainer_file = 1;
+ }
+
# Check signature styles
if (!$in_header_lines &&
$line =~ /^(\s*)([a-z0-9_-]+by:|$signature_tags)(\s*)(.*)/i) {
@@ -2246,7 +2257,7 @@ sub process {
}
# Check for various typo / spelling mistakes
- if ($in_commit_log || $line =~ /^\+/) {
+ if (defined($misspellings) && ($in_commit_log || $line =~ /^\+/)) {
while ($rawline =~ /(?:^|[^a-z@])($misspellings)(?:$|[^a-z@])/gi) {
my $typo = $1;
my $typo_fix = $spelling_fix{lc($typo)};
@@ -2403,33 +2414,6 @@ sub process {
"line over $max_line_length characters\n" . $herecurr);
}
-# Check for user-visible strings broken across lines, which breaks the ability
-# to grep for the string. Make exceptions when the previous string ends in a
-# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{'
-# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value
- if ($line =~ /^\+\s*"/ &&
- $prevline =~ /"\s*$/ &&
- $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) {
- WARN("SPLIT_STRING",
- "quoted string split across lines\n" . $hereprev);
- }
-
-# check for missing a space in a string concatination
- if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) {
- WARN('MISSING_SPACE',
- "break quoted strings at a space character\n" . $hereprev);
- }
-
-# check for spaces before a quoted newline
- if ($rawline =~ /^.*\".*\s\\n/) {
- if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
- "unnecessary whitespace before a quoted newline\n" . $herecurr) &&
- $fix) {
- $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/;
- }
-
- }
-
# check for adding lines without a newline.
if ($line =~ /^\+/ && defined $lines[$linenr] && $lines[$linenr] =~ /^\\ No newline at end of file/) {
WARN("MISSING_EOF_NEWLINE",
@@ -2515,7 +2499,8 @@ sub process {
}
}
- if ($line =~ /^\+.*\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic|{)/) {
+ if ($line =~ /^\+.*(\w+\s*)?\(\s*$Type\s*\)[ \t]+(?!$Assignment|$Arithmetic|[,;\({\[\<\>])/ &&
+ (!defined($1) || $1 !~ /sizeof\s*/)) {
if (CHK("SPACING",
"No space is necessary after a cast\n" . $herecurr) &&
$fix) {
@@ -3563,14 +3548,33 @@ sub process {
}
}
- # , must have a space on the right.
+ # , must not have a space before and must have a space on the right.
} elsif ($op eq ',') {
+ my $rtrim_before = 0;
+ my $space_after = 0;
+ if ($ctx =~ /Wx./) {
+ if (ERROR("SPACING",
+ "space prohibited before that '$op' $at\n" . $hereptr)) {
+ $line_fixed = 1;
+ $rtrim_before = 1;
+ }
+ }
if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
if (ERROR("SPACING",
"space required after that '$op' $at\n" . $hereptr)) {
- $good = $fix_elements[$n] . trim($fix_elements[$n + 1]) . " ";
$line_fixed = 1;
$last_after = $n;
+ $space_after = 1;
+ }
+ }
+ if ($rtrim_before || $space_after) {
+ if ($rtrim_before) {
+ $good = rtrim($fix_elements[$n]) . trim($fix_elements[$n + 1]);
+ } else {
+ $good = $fix_elements[$n] . trim($fix_elements[$n + 1]);
+ }
+ if ($space_after) {
+ $good .= " ";
}
}
@@ -3814,9 +3818,27 @@ sub process {
# ie: &(foo->bar) should be &foo->bar and *(foo->bar) should be *foo->bar
while ($line =~ /(?:[^&]&\s*|\*)\(\s*($Ident\s*(?:$Member\s*)+)\s*\)/g) {
- CHK("UNNECESSARY_PARENTHESES",
- "Unnecessary parentheses around $1\n" . $herecurr);
- }
+ my $var = $1;
+ if (CHK("UNNECESSARY_PARENTHESES",
+ "Unnecessary parentheses around $var\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/\(\s*\Q$var\E\s*\)/$var/;
+ }
+ }
+
+# check for unnecessary parentheses around function pointer uses
+# ie: (foo->bar)(); should be foo->bar();
+# but not "if (foo->bar) (" to avoid some false positives
+ if ($line =~ /(\bif\s*|)(\(\s*$Ident\s*(?:$Member\s*)+\))[ \t]*\(/ && $1 !~ /^if/) {
+ my $var = $2;
+ if (CHK("UNNECESSARY_PARENTHESES",
+ "Unnecessary parentheses around function pointer $var\n" . $herecurr) &&
+ $fix) {
+ my $var2 = deparenthesize($var);
+ $var2 =~ s/\s//g;
+ $fixed[$fixlinenr] =~ s/\Q$var\E/$var2/;
+ }
+ }
#goto labels aren't indented, allow a single space however
if ($line=~/^.\s+[A-Za-z\d_]+:(?![0-9]+)/ and
@@ -4056,7 +4078,9 @@ sub process {
#Ignore Page<foo> variants
$var !~ /^(?:Clear|Set|TestClear|TestSet|)Page[A-Z]/ &&
#Ignore SI style variants like nS, mV and dB (ie: max_uV, regulator_min_uA_show)
- $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/) {
+ $var !~ /^(?:[a-z_]*?)_?[a-z][A-Z](?:_[a-z_]+)?$/ &&
+#Ignore some three character SI units explicitly, like MiB and KHz
+ $var !~ /^(?:[a-z_]*?)_?(?:[KMGT]iB|[KMGT]?Hz)(?:_[a-z_]+)?$/) {
while ($var =~ m{($Ident)}g) {
my $word = $1;
next if ($word !~ /[A-Z][a-z]|[a-z][A-Z]/);
@@ -4408,12 +4432,85 @@ sub process {
"Use of volatile is usually wrong: see Documentation/volatile-considered-harmful.txt\n" . $herecurr);
}
+# Check for user-visible strings broken across lines, which breaks the ability
+# to grep for the string. Make exceptions when the previous string ends in a
+# newline (multiple lines in one string constant) or '\t', '\r', ';', or '{'
+# (common in inline assembly) or is a octal \123 or hexadecimal \xaf value
+ if ($line =~ /^\+\s*"[X\t]*"/ &&
+ $prevline =~ /"\s*$/ &&
+ $prevrawline !~ /(?:\\(?:[ntr]|[0-7]{1,3}|x[0-9a-fA-F]{1,2})|;\s*|\{\s*)"\s*$/) {
+ if (WARN("SPLIT_STRING",
+ "quoted string split across lines\n" . $hereprev) &&
+ $fix &&
+ $prevrawline =~ /^\+.*"\s*$/ &&
+ $last_coalesced_string_linenr != $linenr - 1) {
+ my $extracted_string = get_quoted_string($line, $rawline);
+ my $comma_close = "";
+ if ($rawline =~ /\Q$extracted_string\E(\s*\)\s*;\s*$|\s*,\s*)/) {
+ $comma_close = $1;
+ }
+
+ fix_delete_line($fixlinenr - 1, $prevrawline);
+ fix_delete_line($fixlinenr, $rawline);
+ my $fixedline = $prevrawline;
+ $fixedline =~ s/"\s*$//;
+ $fixedline .= substr($extracted_string, 1) . trim($comma_close);
+ fix_insert_line($fixlinenr - 1, $fixedline);
+ $fixedline = $rawline;
+ $fixedline =~ s/\Q$extracted_string\E\Q$comma_close\E//;
+ if ($fixedline !~ /\+\s*$/) {
+ fix_insert_line($fixlinenr, $fixedline);
+ }
+ $last_coalesced_string_linenr = $linenr;
+ }
+ }
+
+# check for missing a space in a string concatenation
+ if ($prevrawline =~ /[^\\]\w"$/ && $rawline =~ /^\+[\t ]+"\w/) {
+ WARN('MISSING_SPACE',
+ "break quoted strings at a space character\n" . $hereprev);
+ }
+
+# check for spaces before a quoted newline
+ if ($rawline =~ /^.*\".*\s\\n/) {
+ if (WARN("QUOTED_WHITESPACE_BEFORE_NEWLINE",
+ "unnecessary whitespace before a quoted newline\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/^(\+.*\".*)\s+\\n/$1\\n/;
+ }
+
+ }
+
# concatenated string without spaces between elements
if ($line =~ /"X+"[A-Z_]+/ || $line =~ /[A-Z_]+"X+"/) {
CHK("CONCATENATED_STRING",
"Concatenated strings should use spaces between elements\n" . $herecurr);
}
+# uncoalesced string fragments
+ if ($line =~ /"X*"\s*"/) {
+ WARN("STRING_FRAGMENTS",
+ "Consecutive strings are generally better as a single string\n" . $herecurr);
+ }
+
+# check for %L{u,d,i} in strings
+ my $string;
+ while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
+ $string = substr($rawline, $-[1], $+[1] - $-[1]);
+ $string =~ s/%%/__/g;
+ if ($string =~ /(?<!%)%L[udi]/) {
+ WARN("PRINTF_L",
+ "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
+ last;
+ }
+ }
+
+# check for line continuations in quoted strings with odd counts of "
+ if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
+ WARN("LINE_CONTINUATIONS",
+ "Avoid line continuations in quoted strings\n" . $herecurr);
+ }
+
# warn about #if 0
if ($line =~ /^.\s*\#\s*if\s+0\b/) {
CHK("REDUNDANT_CODE",
@@ -4426,7 +4523,7 @@ sub process {
my $expr = '\s*\(\s*' . quotemeta($1) . '\s*\)\s*;';
if ($line =~ /\b(kfree|usb_free_urb|debugfs_remove(?:_recursive)?)$expr/) {
WARN('NEEDLESS_IF',
- "$1(NULL) is safe this check is probably not required\n" . $hereprev);
+ "$1(NULL) is safe and this check is probably not required\n" . $hereprev);
}
}
@@ -4458,6 +4555,28 @@ sub process {
}
}
+# check for mask then right shift without a parentheses
+ if ($^V && $^V ge 5.10.0 &&
+ $line =~ /$LvalOrFunc\s*\&\s*($LvalOrFunc)\s*>>/ &&
+ $4 !~ /^\&/) { # $LvalOrFunc may be &foo, ignore if so
+ WARN("MASK_THEN_SHIFT",
+ "Possible precedence defect with mask then right shift - may need parentheses\n" . $herecurr);
+ }
+
+# check for pointer comparisons to NULL
+ if ($^V && $^V ge 5.10.0) {
+ while ($line =~ /\b$LvalOrFunc\s*(==|\!=)\s*NULL\b/g) {
+ my $val = $1;
+ my $equal = "!";
+ $equal = "" if ($4 eq "!=");
+ if (CHK("COMPARISON_TO_NULL",
+ "Comparison to NULL could be written \"${equal}${val}\"\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/\b\Q$val\E\s*(?:==|\!=)\s*NULL\b/$equal$val/;
+ }
+ }
+ }
+
# check for bad placement of section $InitAttribute (e.g.: __initdata)
if ($line =~ /(\b$InitAttribute\b)/) {
my $attr = $1;
@@ -4652,6 +4771,15 @@ sub process {
}
}
+# Check for __attribute__ weak, or __weak declarations (may have link issues)
+ if ($^V && $^V ge 5.10.0 &&
+ $line =~ /(?:$Declare|$DeclareMisordered)\s*$Ident\s*$balanced_parens\s*(?:$Attribute)?\s*;/ &&
+ ($line =~ /\b__attribute__\s*\(\s*\(.*\bweak\b/ ||
+ $line =~ /\b__weak\b/)) {
+ ERROR("WEAK_DECLARATION",
+ "Using weak declarations can have unintended link defects\n" . $herecurr);
+ }
+
# check for sizeof(&)
if ($line =~ /\bsizeof\s*\(\s*\&/) {
WARN("SIZEOF_ADDRESS",
@@ -4667,12 +4795,6 @@ sub process {
}
}
-# check for line continuations in quoted strings with odd counts of "
- if ($rawline =~ /\\$/ && $rawline =~ tr/"/"/ % 2) {
- WARN("LINE_CONTINUATIONS",
- "Avoid line continuations in quoted strings\n" . $herecurr);
- }
-
# check for struct spinlock declarations
if ($line =~ /^.\s*\bstruct\s+spinlock\s+\w+\s*;/) {
WARN("USE_SPINLOCK_T",
@@ -4908,6 +5030,17 @@ sub process {
}
}
+# check for #defines like: 1 << <digit> that could be BIT(digit)
+ if ($line =~ /#\s*define\s+\w+\s+\(?\s*1\s*([ulUL]*)\s*\<\<\s*(?:\d+|$Ident)\s*\)?/) {
+ my $ull = "";
+ $ull = "_ULL" if (defined($1) && $1 =~ /ll/i);
+ if (CHK("BIT_MACRO",
+ "Prefer using the BIT$ull macro\n" . $herecurr) &&
+ $fix) {
+ $fixed[$fixlinenr] =~ s/\(?\s*1\s*[ulUL]*\s*<<\s*(\d+|$Ident)\s*\)?/BIT${ull}($1)/;
+ }
+ }
+
# check for case / default statements not preceded by break/fallthrough/switch
if ($line =~ /^.\s*(?:case\s+(?:$Ident|$Constant)\s*|default):/) {
my $has_break = 0;
@@ -5071,18 +5204,6 @@ sub process {
"#define of '$1' is wrong - use Kconfig variables or standard guards instead\n" . $herecurr);
}
-# check for %L{u,d,i} in strings
- my $string;
- while ($line =~ /(?:^|")([X\t]*)(?:"|$)/g) {
- $string = substr($rawline, $-[1], $+[1] - $-[1]);
- $string =~ s/%%/__/g;
- if ($string =~ /(?<!%)%L[udi]/) {
- WARN("PRINTF_L",
- "\%Ld/%Lu are not-standard C, use %lld/%llu\n" . $herecurr);
- last;
- }
- }
-
# whine mightly about in_atomic
if ($line =~ /\bin_atomic\s*\(/) {
if ($realfile =~ m@^drivers/@) {
diff --git a/scripts/kernel-doc b/scripts/kernel-doc
index 70bea94..9922e66 100755
--- a/scripts/kernel-doc
+++ b/scripts/kernel-doc
@@ -1753,7 +1753,7 @@ sub dump_struct($$) {
# strip kmemcheck_bitfield_{begin,end}.*;
$members =~ s/kmemcheck_bitfield_.*?;//gos;
# strip attributes
- $members =~ s/__aligned\s*\(.+\)//gos;
+ $members =~ s/__aligned\s*\([^;]*\)//gos;
create_parameterlist($members, ';', $file);
check_sections($file, $declaration_name, "struct", $sectcheck, $struct_actual, $nested);
diff --git a/security/commoncap.c b/security/commoncap.c
index bab0611..2915d85 100644
--- a/security/commoncap.c
+++ b/security/commoncap.c
@@ -446,7 +446,7 @@ static int get_file_caps(struct linux_binprm *bprm, bool *effective, bool *has_c
if (bprm->file->f_path.mnt->mnt_flags & MNT_NOSUID)
return 0;
- dentry = dget(bprm->file->f_dentry);
+ dentry = dget(bprm->file->f_path.dentry);
rc = get_vfs_caps_from_disk(dentry, &vcaps);
if (rc < 0) {
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 8688597..f92be1b 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -196,7 +196,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
{
const char *audit_cause = "failed";
struct inode *inode = file_inode(file);
- const char *filename = file->f_dentry->d_name.name;
+ const char *filename = file->f_path.dentry->d_name.name;
int result = 0;
struct {
struct ima_digest_data hdr;
@@ -204,7 +204,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
} hash;
if (xattr_value)
- *xattr_len = ima_read_xattr(file->f_dentry, xattr_value);
+ *xattr_len = ima_read_xattr(file->f_path.dentry, xattr_value);
if (!(iint->flags & IMA_COLLECTED)) {
u64 i_version = file_inode(file)->i_version;
diff --git a/security/integrity/ima/ima_appraise.c b/security/integrity/ima/ima_appraise.c
index 7c8f41e..fffcdb0 100644
--- a/security/integrity/ima/ima_appraise.c
+++ b/security/integrity/ima/ima_appraise.c
@@ -189,7 +189,7 @@ int ima_appraise_measurement(int func, struct integrity_iint_cache *iint,
{
static const char op[] = "appraise_data";
char *cause = "unknown";
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
struct inode *inode = dentry->d_inode;
enum integrity_status status = INTEGRITY_UNKNOWN;
int rc = xattr_len, hash_start = 0;
@@ -289,7 +289,7 @@ out:
*/
void ima_update_xattr(struct integrity_iint_cache *iint, struct file *file)
{
- struct dentry *dentry = file->f_dentry;
+ struct dentry *dentry = file->f_path.dentry;
int rc = 0;
/* do not collect and update hash for digital signatures */
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c
index 1506f02..bcfc36c 100644
--- a/security/integrity/ima/ima_template_lib.c
+++ b/security/integrity/ima/ima_template_lib.c
@@ -284,7 +284,7 @@ static int ima_eventname_init_common(struct integrity_iint_cache *iint,
}
if (file) {
- cur_filename = file->f_dentry->d_name.name;
+ cur_filename = file->f_path.dentry->d_name.name;
cur_filename_len = strlen(cur_filename);
} else
/*
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index c71737f..33db1ad 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1200,7 +1200,7 @@ static void sel_remove_entries(struct dentry *de)
spin_lock(&de->d_lock);
node = de->d_subdirs.next;
while (node != &de->d_subdirs) {
- struct dentry *d = list_entry(node, struct dentry, d_u.d_child);
+ struct dentry *d = list_entry(node, struct dentry, d_child);
spin_lock_nested(&d->d_lock, DENTRY_D_LOCK_NESTED);
list_del_init(node);
@@ -1674,12 +1674,12 @@ static void sel_remove_classes(void)
list_for_each(class_node, &class_dir->d_subdirs) {
struct dentry *class_subdir = list_entry(class_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
struct list_head *class_subdir_node;
list_for_each(class_subdir_node, &class_subdir->d_subdirs) {
struct dentry *d = list_entry(class_subdir_node,
- struct dentry, d_u.d_child);
+ struct dentry, d_child);
if (d->d_inode)
if (d->d_inode->i_mode & S_IFDIR)
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index d515ec2..433ae61 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -166,9 +166,9 @@ static int smk_bu_file(struct file *file, int mode, int rc)
return rc;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+ pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
sskp->smk_known, (char *)file->f_security, acc,
- inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+ inode->i_sb->s_id, inode->i_ino, file,
current->comm);
return 0;
}
@@ -189,9 +189,9 @@ static int smk_bu_credfile(const struct cred *cred, struct file *file,
return rc;
smk_bu_mode(mode, acc);
- pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %s) %s\n",
+ pr_info("Smack Bringup: (%s %s %s) file=(%s %ld %pD) %s\n",
sskp->smk_known, smk_of_inode(inode)->smk_known, acc,
- inode->i_sb->s_id, inode->i_ino, file->f_dentry->d_name.name,
+ inode->i_sb->s_id, inode->i_ino, file,
current->comm);
return 0;
}
diff --git a/sound/aoa/codecs/onyx.c b/sound/aoa/codecs/onyx.c
index 401107b..23c371ec 100644
--- a/sound/aoa/codecs/onyx.c
+++ b/sound/aoa/codecs/onyx.c
@@ -243,13 +243,7 @@ static int onyx_snd_capture_source_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[] = { "Line-In", "Microphone" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int onyx_snd_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/aoa/codecs/tas.c b/sound/aoa/codecs/tas.c
index cf3c630..364c7c4 100644
--- a/sound/aoa/codecs/tas.c
+++ b/sound/aoa/codecs/tas.c
@@ -478,15 +478,9 @@ static struct snd_kcontrol_new drc_switch_control = {
static int tas_snd_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Line-In", "Microphone" };
+ static const char * const texts[] = { "Line-In", "Microphone" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int tas_snd_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/aoa/soundbus/i2sbus/core.c b/sound/aoa/soundbus/i2sbus/core.c
index a80d5ea..4e2b4fb 100644
--- a/sound/aoa/soundbus/i2sbus/core.c
+++ b/sound/aoa/soundbus/i2sbus/core.c
@@ -79,8 +79,7 @@ static void i2sbus_release_dev(struct device *dev)
if (i2sdev->out.dbdma) iounmap(i2sdev->out.dbdma);
if (i2sdev->in.dbdma) iounmap(i2sdev->in.dbdma);
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
- if (i2sdev->allocated_resource[i])
- release_and_free_resource(i2sdev->allocated_resource[i]);
+ release_and_free_resource(i2sdev->allocated_resource[i]);
free_dbdma_descriptor_ring(i2sdev, &i2sdev->out.dbdma_ring);
free_dbdma_descriptor_ring(i2sdev, &i2sdev->in.dbdma_ring);
for (i = aoa_resource_i2smmio; i <= aoa_resource_rxdbdma; i++)
@@ -323,8 +322,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
if (dev->out.dbdma) iounmap(dev->out.dbdma);
if (dev->in.dbdma) iounmap(dev->in.dbdma);
for (i=0;i<3;i++)
- if (dev->allocated_resource[i])
- release_and_free_resource(dev->allocated_resource[i]);
+ release_and_free_resource(dev->allocated_resource[i]);
mutex_destroy(&dev->lock);
kfree(dev);
return 0;
diff --git a/sound/arm/pxa2xx-pcm-lib.c b/sound/arm/pxa2xx-pcm-lib.c
index a61d7a9..01f8fdc 100644
--- a/sound/arm/pxa2xx-pcm-lib.c
+++ b/sound/arm/pxa2xx-pcm-lib.c
@@ -200,9 +200,7 @@ void pxa2xx_pcm_dma_irq(int dma_ch, void *dev_id)
} else {
printk(KERN_ERR "DMA error on channel %d (DCSR=%#x)\n",
dma_ch, dcsr);
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(substream);
+ snd_pcm_stop_xrun(substream);
}
}
EXPORT_SYMBOL(pxa2xx_pcm_dma_irq);
diff --git a/sound/atmel/abdac.c b/sound/atmel/abdac.c
index 31061e3..0231405 100644
--- a/sound/atmel/abdac.c
+++ b/sound/atmel/abdac.c
@@ -242,7 +242,7 @@ static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE: /* fall through */
case SNDRV_PCM_TRIGGER_RESUME: /* fall through */
case SNDRV_PCM_TRIGGER_START:
- clk_enable(dac->sample_clk);
+ clk_prepare_enable(dac->sample_clk);
retval = dw_dma_cyclic_start(dac->dma.chan);
if (retval)
goto out;
@@ -254,7 +254,7 @@ static int atmel_abdac_trigger(struct snd_pcm_substream *substream, int cmd)
dw_dma_cyclic_stop(dac->dma.chan);
dac_writel(dac, DATA, 0);
dac_writel(dac, CTRL, 0);
- clk_disable(dac->sample_clk);
+ clk_disable_unprepare(dac->sample_clk);
break;
default:
retval = -EINVAL;
@@ -429,7 +429,7 @@ static int atmel_abdac_probe(struct platform_device *pdev)
retval = PTR_ERR(sample_clk);
goto out_put_pclk;
}
- clk_enable(pclk);
+ clk_prepare_enable(pclk);
retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
@@ -528,7 +528,7 @@ out_free_card:
snd_card_free(card);
out_put_sample_clk:
clk_put(sample_clk);
- clk_disable(pclk);
+ clk_disable_unprepare(pclk);
out_put_pclk:
clk_put(pclk);
return retval;
@@ -541,8 +541,8 @@ static int atmel_abdac_suspend(struct device *pdev)
struct atmel_abdac *dac = card->private_data;
dw_dma_cyclic_stop(dac->dma.chan);
- clk_disable(dac->sample_clk);
- clk_disable(dac->pclk);
+ clk_disable_unprepare(dac->sample_clk);
+ clk_disable_unprepare(dac->pclk);
return 0;
}
@@ -552,8 +552,8 @@ static int atmel_abdac_resume(struct device *pdev)
struct snd_card *card = dev_get_drvdata(pdev);
struct atmel_abdac *dac = card->private_data;
- clk_enable(dac->pclk);
- clk_enable(dac->sample_clk);
+ clk_prepare_enable(dac->pclk);
+ clk_prepare_enable(dac->sample_clk);
if (test_bit(DMA_READY, &dac->flags))
dw_dma_cyclic_start(dac->dma.chan);
@@ -572,7 +572,7 @@ static int atmel_abdac_remove(struct platform_device *pdev)
struct atmel_abdac *dac = get_dac(card);
clk_put(dac->sample_clk);
- clk_disable(dac->pclk);
+ clk_disable_unprepare(dac->pclk);
clk_put(dac->pclk);
dma_release_channel(dac->dma.chan);
diff --git a/sound/atmel/ac97c.c b/sound/atmel/ac97c.c
index b59427d..cb44c74 100644
--- a/sound/atmel/ac97c.c
+++ b/sound/atmel/ac97c.c
@@ -773,7 +773,7 @@ static int atmel_ac97c_pcm_new(struct atmel_ac97c *chip)
return err;
}
retval = snd_pcm_new(chip->card, chip->card->shortname,
- chip->pdev->id, playback, capture, &pcm);
+ 0, playback, capture, &pcm);
if (retval)
return retval;
@@ -944,7 +944,7 @@ static int atmel_ac97c_probe(struct platform_device *pdev)
dev_dbg(&pdev->dev, "no peripheral clock\n");
return PTR_ERR(pclk);
}
- clk_enable(pclk);
+ clk_prepare_enable(pclk);
retval = snd_card_new(&pdev->dev, SNDRV_DEFAULT_IDX1,
SNDRV_DEFAULT_STR1, THIS_MODULE,
@@ -1122,7 +1122,7 @@ err_ioremap:
err_request_irq:
snd_card_free(card);
err_snd_card_new:
- clk_disable(pclk);
+ clk_disable_unprepare(pclk);
clk_put(pclk);
return retval;
}
@@ -1139,7 +1139,7 @@ static int atmel_ac97c_suspend(struct device *pdev)
if (test_bit(DMA_TX_READY, &chip->flags))
dw_dma_cyclic_stop(chip->dma.tx_chan);
}
- clk_disable(chip->pclk);
+ clk_disable_unprepare(chip->pclk);
return 0;
}
@@ -1149,7 +1149,7 @@ static int atmel_ac97c_resume(struct device *pdev)
struct snd_card *card = dev_get_drvdata(pdev);
struct atmel_ac97c *chip = card->private_data;
- clk_enable(chip->pclk);
+ clk_prepare_enable(chip->pclk);
if (cpu_is_at32ap7000()) {
if (test_bit(DMA_RX_READY, &chip->flags))
dw_dma_cyclic_start(chip->dma.rx_chan);
@@ -1177,7 +1177,7 @@ static int atmel_ac97c_remove(struct platform_device *pdev)
ac97c_writel(chip, COMR, 0);
ac97c_writel(chip, MR, 0);
- clk_disable(chip->pclk);
+ clk_disable_unprepare(chip->pclk);
clk_put(chip->pclk);
iounmap(chip->regs);
free_irq(chip->irq, chip);
diff --git a/sound/core/Makefile b/sound/core/Makefile
index 394a389..4daf2f5 100644
--- a/sound/core/Makefile
+++ b/sound/core/Makefile
@@ -14,6 +14,9 @@ snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
pcm_memory.o memalloc.o
snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
+# for trace-points
+CFLAGS_pcm_lib.o := -I$(src)
+
snd-pcm-dmaengine-objs := pcm_dmaengine.o
snd-rawmidi-objs := rawmidi.o
diff --git a/sound/core/control.c b/sound/core/control.c
index b961134..bb96a46 100644
--- a/sound/core/control.c
+++ b/sound/core/control.c
@@ -141,6 +141,16 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
return 0;
}
+/**
+ * snd_ctl_notify - Send notification to user-space for a control change
+ * @card: the card to send notification
+ * @mask: the event mask, SNDRV_CTL_EVENT_*
+ * @id: the ctl element id to send notification
+ *
+ * This function adds an event record with the given id and mask, appends
+ * to the list and wakes up the user-space for notification. This can be
+ * called in the atomic context.
+ */
void snd_ctl_notify(struct snd_card *card, unsigned int mask,
struct snd_ctl_elem_id *id)
{
@@ -179,7 +189,6 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
}
read_unlock(&card->ctl_files_rwlock);
}
-
EXPORT_SYMBOL(snd_ctl_notify);
/**
@@ -261,7 +270,6 @@ struct snd_kcontrol *snd_ctl_new1(const struct snd_kcontrol_new *ncontrol,
kctl.private_data = private_data;
return snd_ctl_new(&kctl, access);
}
-
EXPORT_SYMBOL(snd_ctl_new1);
/**
@@ -280,7 +288,6 @@ void snd_ctl_free_one(struct snd_kcontrol *kcontrol)
kfree(kcontrol);
}
}
-
EXPORT_SYMBOL(snd_ctl_free_one);
static bool snd_ctl_remove_numid_conflict(struct snd_card *card,
@@ -376,7 +383,6 @@ int snd_ctl_add(struct snd_card *card, struct snd_kcontrol *kcontrol)
snd_ctl_free_one(kcontrol);
return err;
}
-
EXPORT_SYMBOL(snd_ctl_add);
/**
@@ -471,7 +477,6 @@ int snd_ctl_remove(struct snd_card *card, struct snd_kcontrol *kcontrol)
snd_ctl_free_one(kcontrol);
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_remove);
/**
@@ -499,7 +504,6 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
up_write(&card->controls_rwsem);
return ret;
}
-
EXPORT_SYMBOL(snd_ctl_remove_id);
/**
@@ -568,7 +572,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
ret = -ENOENT;
goto unlock;
}
- index_offset = snd_ctl_get_ioff(kctl, &kctl->id);
+ index_offset = snd_ctl_get_ioff(kctl, id);
vd = &kctl->vd[index_offset];
ret = 0;
if (active) {
@@ -617,7 +621,6 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
up_write(&card->controls_rwsem);
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_rename_id);
/**
@@ -645,7 +648,6 @@ struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numi
}
return NULL;
}
-
EXPORT_SYMBOL(snd_ctl_find_numid);
/**
@@ -687,7 +689,6 @@ struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
}
return NULL;
}
-
EXPORT_SYMBOL(snd_ctl_find_id);
static int snd_ctl_card_info(struct snd_card *card, struct snd_ctl_file * ctl,
@@ -1526,19 +1527,28 @@ static int _snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn, struct list_head *
return 0;
}
+/**
+ * snd_ctl_register_ioctl - register the device-specific control-ioctls
+ * @fcn: ioctl callback function
+ *
+ * called from each device manager like pcm.c, hwdep.c, etc.
+ */
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_register_ioctl);
#ifdef CONFIG_COMPAT
+/**
+ * snd_ctl_register_ioctl_compat - register the device-specific 32bit compat
+ * control-ioctls
+ * @fcn: ioctl callback function
+ */
int snd_ctl_register_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_register_ioctl(fcn, &snd_control_compat_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_register_ioctl_compat);
#endif
@@ -1566,19 +1576,26 @@ static int _snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn,
return -EINVAL;
}
+/**
+ * snd_ctl_unregister_ioctl - de-register the device-specific control-ioctls
+ * @fcn: ioctl callback function to unregister
+ */
int snd_ctl_unregister_ioctl(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_unregister_ioctl(fcn, &snd_control_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_unregister_ioctl);
#ifdef CONFIG_COMPAT
+/**
+ * snd_ctl_unregister_ioctl - de-register the device-specific compat 32bit
+ * control-ioctls
+ * @fcn: ioctl callback function to unregister
+ */
int snd_ctl_unregister_ioctl_compat(snd_kctl_ioctl_func_t fcn)
{
return _snd_ctl_unregister_ioctl(fcn, &snd_control_compat_ioctls);
}
-
EXPORT_SYMBOL(snd_ctl_unregister_ioctl_compat);
#endif
@@ -1702,6 +1719,16 @@ int snd_ctl_create(struct snd_card *card)
/*
* Frequently used control callbacks/helpers
*/
+
+/**
+ * snd_ctl_boolean_mono_info - Helper function for a standard boolean info
+ * callback with a mono channel
+ * @kcontrol: the kcontrol instance
+ * @uinfo: info to store
+ *
+ * This is a function that can be used as info callback for a standard
+ * boolean control with a single mono channel.
+ */
int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1711,9 +1738,17 @@ int snd_ctl_boolean_mono_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 1;
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_boolean_mono_info);
+/**
+ * snd_ctl_boolean_stereo_info - Helper function for a standard boolean info
+ * callback with stereo two channels
+ * @kcontrol: the kcontrol instance
+ * @uinfo: info to store
+ *
+ * This is a function that can be used as info callback for a standard
+ * boolean control with stereo two channels.
+ */
int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -1723,7 +1758,6 @@ int snd_ctl_boolean_stereo_info(struct snd_kcontrol *kcontrol,
uinfo->value.integer.max = 1;
return 0;
}
-
EXPORT_SYMBOL(snd_ctl_boolean_stereo_info);
/**
@@ -1745,8 +1779,13 @@ int snd_ctl_enum_info(struct snd_ctl_elem_info *info, unsigned int channels,
info->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
info->count = channels;
info->value.enumerated.items = items;
+ if (!items)
+ return 0;
if (info->value.enumerated.item >= items)
info->value.enumerated.item = items - 1;
+ WARN(strlen(names[info->value.enumerated.item]) >= sizeof(info->value.enumerated.name),
+ "ALSA: too long item name '%s'\n",
+ names[info->value.enumerated.item]);
strlcpy(info->value.enumerated.name,
names[info->value.enumerated.item],
sizeof(info->value.enumerated.name));
diff --git a/sound/core/init.c b/sound/core/init.c
index 7bdfd19..074875d 100644
--- a/sound/core/init.c
+++ b/sound/core/init.c
@@ -438,17 +438,6 @@ int snd_card_disconnect(struct snd_card *card)
EXPORT_SYMBOL(snd_card_disconnect);
-/**
- * snd_card_free - frees given soundcard structure
- * @card: soundcard structure
- *
- * This function releases the soundcard structure and the all assigned
- * devices automatically. That is, you don't have to release the devices
- * by yourself.
- *
- * Return: Zero. Frees all associated devices and frees the control
- * interface associated to given soundcard.
- */
static int snd_card_do_free(struct snd_card *card)
{
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
@@ -469,6 +458,15 @@ static int snd_card_do_free(struct snd_card *card)
return 0;
}
+/**
+ * snd_card_free_when_closed - Disconnect the card, free it later eventually
+ * @card: soundcard structure
+ *
+ * Unlike snd_card_free(), this function doesn't try to release the card
+ * resource immediately, but tries to disconnect at first. When the card
+ * is still in use, the function returns before freeing the resources.
+ * The card resources will be freed when the refcount gets to zero.
+ */
int snd_card_free_when_closed(struct snd_card *card)
{
int ret = snd_card_disconnect(card);
@@ -479,6 +477,19 @@ int snd_card_free_when_closed(struct snd_card *card)
}
EXPORT_SYMBOL(snd_card_free_when_closed);
+/**
+ * snd_card_free - frees given soundcard structure
+ * @card: soundcard structure
+ *
+ * This function releases the soundcard structure and the all assigned
+ * devices automatically. That is, you don't have to release the devices
+ * by yourself.
+ *
+ * This function waits until the all resources are properly released.
+ *
+ * Return: Zero. Frees all associated devices and frees the control
+ * interface associated to given soundcard.
+ */
int snd_card_free(struct snd_card *card)
{
struct completion released;
diff --git a/sound/core/pcm.c b/sound/core/pcm.c
index c6ff94a..cfc56c8 100644
--- a/sound/core/pcm.c
+++ b/sound/core/pcm.c
@@ -220,6 +220,10 @@ static char *snd_pcm_format_names[] = {
FORMAT(DSD_U32_BE),
};
+/**
+ * snd_pcm_format_name - Return a name string for the given PCM format
+ * @format: PCM format
+ */
const char *snd_pcm_format_name(snd_pcm_format_t format)
{
if ((__force unsigned int)format >= ARRAY_SIZE(snd_pcm_format_names))
@@ -481,6 +485,19 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+static void snd_pcm_xrun_injection_write(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_pcm_substream *substream = entry->private_data;
+ struct snd_pcm_runtime *runtime;
+
+ snd_pcm_stream_lock_irq(substream);
+ runtime = substream->runtime;
+ if (runtime && runtime->status->state == SNDRV_PCM_STATE_RUNNING)
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irq(substream);
+}
+
static void snd_pcm_xrun_debug_read(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
@@ -612,6 +629,22 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream)
}
substream->proc_status_entry = entry;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ entry = snd_info_create_card_entry(card, "xrun_injection",
+ substream->proc_root);
+ if (entry) {
+ entry->private_data = substream;
+ entry->c.text.read = NULL;
+ entry->c.text.write = snd_pcm_xrun_injection_write;
+ entry->mode = S_IFREG | S_IWUSR;
+ if (snd_info_register(entry) < 0) {
+ snd_info_free_entry(entry);
+ entry = NULL;
+ }
+ }
+ substream->proc_xrun_injection_entry = entry;
+#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
+
return 0;
}
@@ -625,6 +658,10 @@ static int snd_pcm_substream_proc_done(struct snd_pcm_substream *substream)
substream->proc_sw_params_entry = NULL;
snd_info_free_entry(substream->proc_status_entry);
substream->proc_status_entry = NULL;
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+ snd_info_free_entry(substream->proc_xrun_injection_entry);
+ substream->proc_xrun_injection_entry = NULL;
+#endif
snd_info_free_entry(substream->proc_root);
substream->proc_root = NULL;
return 0;
@@ -709,7 +746,6 @@ int snd_pcm_new_stream(struct snd_pcm *pcm, int stream, int substream_count)
}
return 0;
}
-
EXPORT_SYMBOL(snd_pcm_new_stream);
static int _snd_pcm_new(struct snd_card *card, const char *id, int device,
@@ -1157,6 +1193,15 @@ static int snd_pcm_dev_disconnect(struct snd_device *device)
return 0;
}
+/**
+ * snd_pcm_notify - Add/remove the notify list
+ * @notify: PCM notify list
+ * @nfree: 0 = register, 1 = unregister
+ *
+ * This adds the given notifier to the global list so that the callback is
+ * called for each registered PCM devices. This exists only for PCM OSS
+ * emulation, so far.
+ */
int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
{
struct snd_pcm *pcm;
@@ -1179,7 +1224,6 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
mutex_unlock(&register_mutex);
return 0;
}
-
EXPORT_SYMBOL(snd_pcm_notify);
#ifdef CONFIG_PROC_FS
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c
index dfc2854..ec9e786 100644
--- a/sound/core/pcm_lib.c
+++ b/sound/core/pcm_lib.c
@@ -32,6 +32,15 @@
#include <sound/pcm_params.h>
#include <sound/timer.h>
+#ifdef CONFIG_SND_PCM_XRUN_DEBUG
+#define CREATE_TRACE_POINTS
+#include "pcm_trace.h"
+#else
+#define trace_hwptr(substream, pos, in_interrupt)
+#define trace_xrun(substream)
+#define trace_hw_ptr_error(substream, reason)
+#endif
+
/*
* fill ring buffer with silence
* runtime->silence_start: starting pointer to silence area
@@ -146,10 +155,6 @@ EXPORT_SYMBOL(snd_pcm_debug_name);
#define XRUN_DEBUG_BASIC (1<<0)
#define XRUN_DEBUG_STACK (1<<1) /* dump also stack */
#define XRUN_DEBUG_JIFFIESCHECK (1<<2) /* do jiffies check */
-#define XRUN_DEBUG_PERIODUPDATE (1<<3) /* full period update info */
-#define XRUN_DEBUG_HWPTRUPDATE (1<<4) /* full hwptr update info */
-#define XRUN_DEBUG_LOG (1<<5) /* show last 10 positions on err */
-#define XRUN_DEBUG_LOGONCE (1<<6) /* do above only once */
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
@@ -168,6 +173,7 @@ static void xrun(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
+ trace_xrun(substream);
if (runtime->tstamp_mode == SNDRV_PCM_TSTAMP_ENABLE)
snd_pcm_gettime(runtime, (struct timespec *)&runtime->status->tstamp);
snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
@@ -180,97 +186,19 @@ static void xrun(struct snd_pcm_substream *substream)
}
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
-#define hw_ptr_error(substream, fmt, args...) \
+#define hw_ptr_error(substream, in_interrupt, reason, fmt, args...) \
do { \
+ trace_hw_ptr_error(substream, reason); \
if (xrun_debug(substream, XRUN_DEBUG_BASIC)) { \
- xrun_log_show(substream); \
- pr_err_ratelimited("ALSA: PCM: " fmt, ##args); \
+ pr_err_ratelimited("ALSA: PCM: [%c] " reason ": " fmt, \
+ (in_interrupt) ? 'Q' : 'P', ##args); \
dump_stack_on_xrun(substream); \
} \
} while (0)
-#define XRUN_LOG_CNT 10
-
-struct hwptr_log_entry {
- unsigned int in_interrupt;
- unsigned long jiffies;
- snd_pcm_uframes_t pos;
- snd_pcm_uframes_t period_size;
- snd_pcm_uframes_t buffer_size;
- snd_pcm_uframes_t old_hw_ptr;
- snd_pcm_uframes_t hw_ptr_base;
-};
-
-struct snd_pcm_hwptr_log {
- unsigned int idx;
- unsigned int hit: 1;
- struct hwptr_log_entry entries[XRUN_LOG_CNT];
-};
-
-static void xrun_log(struct snd_pcm_substream *substream,
- snd_pcm_uframes_t pos, int in_interrupt)
-{
- struct snd_pcm_runtime *runtime = substream->runtime;
- struct snd_pcm_hwptr_log *log = runtime->hwptr_log;
- struct hwptr_log_entry *entry;
-
- if (log == NULL) {
- log = kzalloc(sizeof(*log), GFP_ATOMIC);
- if (log == NULL)
- return;
- runtime->hwptr_log = log;
- } else {
- if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
- return;
- }
- entry = &log->entries[log->idx];
- entry->in_interrupt = in_interrupt;
- entry->jiffies = jiffies;
- entry->pos = pos;
- entry->period_size = runtime->period_size;
- entry->buffer_size = runtime->buffer_size;
- entry->old_hw_ptr = runtime->status->hw_ptr;
- entry->hw_ptr_base = runtime->hw_ptr_base;
- log->idx = (log->idx + 1) % XRUN_LOG_CNT;
-}
-
-static void xrun_log_show(struct snd_pcm_substream *substream)
-{
- struct snd_pcm_hwptr_log *log = substream->runtime->hwptr_log;
- struct hwptr_log_entry *entry;
- char name[16];
- unsigned int idx;
- int cnt;
-
- if (log == NULL)
- return;
- if (xrun_debug(substream, XRUN_DEBUG_LOGONCE) && log->hit)
- return;
- snd_pcm_debug_name(substream, name, sizeof(name));
- for (cnt = 0, idx = log->idx; cnt < XRUN_LOG_CNT; cnt++) {
- entry = &log->entries[idx];
- if (entry->period_size == 0)
- break;
- pr_info("hwptr log: %s: %sj=%lu, pos=%ld/%ld/%ld, "
- "hwptr=%ld/%ld\n",
- name, entry->in_interrupt ? "[Q] " : "",
- entry->jiffies,
- (unsigned long)entry->pos,
- (unsigned long)entry->period_size,
- (unsigned long)entry->buffer_size,
- (unsigned long)entry->old_hw_ptr,
- (unsigned long)entry->hw_ptr_base);
- idx++;
- idx %= XRUN_LOG_CNT;
- }
- log->hit = 1;
-}
-
#else /* ! CONFIG_SND_PCM_XRUN_DEBUG */
#define hw_ptr_error(substream, fmt, args...) do { } while (0)
-#define xrun_log(substream, pos, in_interrupt) do { } while (0)
-#define xrun_log_show(substream) do { } while (0)
#endif
@@ -343,17 +271,15 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
if (printk_ratelimit()) {
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- xrun_log_show(substream);
pcm_err(substream->pcm,
- "XRUN: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
+ "BUG: %s, pos = %ld, buffer size = %ld, period size = %ld\n",
name, pos, runtime->buffer_size,
runtime->period_size);
}
pos = 0;
}
pos -= pos % runtime->min_align;
- if (xrun_debug(substream, XRUN_DEBUG_LOG))
- xrun_log(substream, pos, in_interrupt);
+ trace_hwptr(substream, pos, in_interrupt);
hw_base = runtime->hw_ptr_base;
new_hw_ptr = hw_base + pos;
if (in_interrupt) {
@@ -388,22 +314,6 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
delta = new_hw_ptr - old_hw_ptr;
if (delta < 0)
delta += runtime->boundary;
- if (xrun_debug(substream, in_interrupt ?
- XRUN_DEBUG_PERIODUPDATE : XRUN_DEBUG_HWPTRUPDATE)) {
- char name[16];
- snd_pcm_debug_name(substream, name, sizeof(name));
- pcm_dbg(substream->pcm,
- "%s_update: %s: pos=%u/%u/%u, hwptr=%ld/%ld/%ld/%ld\n",
- in_interrupt ? "period" : "hwptr",
- name,
- (unsigned int)pos,
- (unsigned int)runtime->period_size,
- (unsigned int)runtime->buffer_size,
- (unsigned long)delta,
- (unsigned long)old_hw_ptr,
- (unsigned long)new_hw_ptr,
- (unsigned long)runtime->hw_ptr_base);
- }
if (runtime->no_period_wakeup) {
snd_pcm_sframes_t xrun_threshold;
@@ -431,13 +341,10 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
/* something must be really wrong */
if (delta >= runtime->buffer_size + runtime->period_size) {
- hw_ptr_error(substream,
- "Unexpected hw_pointer value %s"
- "(stream=%i, pos=%ld, new_hw_ptr=%ld, "
- "old_hw_ptr=%ld)\n",
- in_interrupt ? "[Q] " : "[P]",
- substream->stream, (long)pos,
- (long)new_hw_ptr, (long)old_hw_ptr);
+ hw_ptr_error(substream, in_interrupt, "Unexpected hw_ptr",
+ "(stream=%i, pos=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n",
+ substream->stream, (long)pos,
+ (long)new_hw_ptr, (long)old_hw_ptr);
return 0;
}
@@ -474,11 +381,8 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
delta--;
}
/* align hw_base to buffer_size */
- hw_ptr_error(substream,
- "hw_ptr skipping! %s"
- "(pos=%ld, delta=%ld, period=%ld, "
- "jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
- in_interrupt ? "[Q] " : "",
+ hw_ptr_error(substream, in_interrupt, "hw_ptr skipping",
+ "(pos=%ld, delta=%ld, period=%ld, jdelta=%lu/%lu/%lu, hw_ptr=%ld/%ld)\n",
(long)pos, (long)hdelta,
(long)runtime->period_size, jdelta,
((hdelta * HZ) / runtime->rate), hw_base,
@@ -490,11 +394,9 @@ static int snd_pcm_update_hw_ptr0(struct snd_pcm_substream *substream,
}
no_jiffies_check:
if (delta > runtime->period_size + runtime->period_size / 2) {
- hw_ptr_error(substream,
- "Lost interrupts? %s"
- "(stream=%i, delta=%ld, new_hw_ptr=%ld, "
- "old_hw_ptr=%ld)\n",
- in_interrupt ? "[Q] " : "",
+ hw_ptr_error(substream, in_interrupt,
+ "Lost interrupts?",
+ "(stream=%i, delta=%ld, new_hw_ptr=%ld, old_hw_ptr=%ld)\n",
substream->stream, (long)delta,
(long)new_hw_ptr,
(long)old_hw_ptr);
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c
index 166d59c..095d957 100644
--- a/sound/core/pcm_native.c
+++ b/sound/core/pcm_native.c
@@ -35,9 +35,6 @@
#include <sound/timer.h>
#include <sound/minors.h>
#include <asm/io.h>
-#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
-#include <dma-coherence.h>
-#endif
/*
* Compatibility
@@ -77,6 +74,14 @@ static int snd_pcm_open(struct file *file, struct snd_pcm *pcm, int stream);
static DEFINE_RWLOCK(snd_pcm_link_rwlock);
static DECLARE_RWSEM(snd_pcm_link_rwsem);
+/**
+ * snd_pcm_stream_lock - Lock the PCM stream
+ * @substream: PCM substream
+ *
+ * This locks the PCM stream's spinlock or mutex depending on the nonatomic
+ * flag of the given substream. This also takes the global link rw lock
+ * (or rw sem), too, for avoiding the race with linked streams.
+ */
void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
{
if (substream->pcm->nonatomic) {
@@ -89,6 +94,12 @@ void snd_pcm_stream_lock(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock);
+/**
+ * snd_pcm_stream_lock - Unlock the PCM stream
+ * @substream: PCM substream
+ *
+ * This unlocks the PCM stream that has been locked via snd_pcm_stream_lock().
+ */
void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
{
if (substream->pcm->nonatomic) {
@@ -101,6 +112,14 @@ void snd_pcm_stream_unlock(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock);
+/**
+ * snd_pcm_stream_lock_irq - Lock the PCM stream
+ * @substream: PCM substream
+ *
+ * This locks the PCM stream like snd_pcm_stream_lock() and disables the local
+ * IRQ (only when nonatomic is false). In nonatomic case, this is identical
+ * as snd_pcm_stream_lock().
+ */
void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
{
if (!substream->pcm->nonatomic)
@@ -109,6 +128,12 @@ void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq);
+/**
+ * snd_pcm_stream_unlock_irq - Unlock the PCM stream
+ * @substream: PCM substream
+ *
+ * This is a counter-part of snd_pcm_stream_lock_irq().
+ */
void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream)
{
snd_pcm_stream_unlock(substream);
@@ -127,6 +152,13 @@ unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream)
}
EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave);
+/**
+ * snd_pcm_stream_unlock_irqrestore - Unlock the PCM stream
+ * @substream: PCM substream
+ * @flags: irq flags
+ *
+ * This is a counter-part of snd_pcm_stream_lock_irqsave().
+ */
void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream,
unsigned long flags)
{
@@ -195,6 +227,21 @@ int snd_pcm_info_user(struct snd_pcm_substream *substream,
return err;
}
+static bool hw_support_mmap(struct snd_pcm_substream *substream)
+{
+ if (!(substream->runtime->hw.info & SNDRV_PCM_INFO_MMAP))
+ return false;
+ /* check architectures that return -EINVAL from dma_mmap_coherent() */
+ /* FIXME: this should be some global flag */
+#if defined(CONFIG_C6X) || defined(CONFIG_FRV) || defined(CONFIG_MN10300) ||\
+ defined(CONFIG_PARISC) || defined(CONFIG_XTENSA)
+ if (!substream->ops->mmap &&
+ substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
+ return false;
+#endif
+ return true;
+}
+
#undef RULES_DEBUG
#ifdef RULES_DEBUG
@@ -372,8 +419,12 @@ int snd_pcm_hw_refine(struct snd_pcm_substream *substream,
}
hw = &substream->runtime->hw;
- if (!params->info)
+ if (!params->info) {
params->info = hw->info & ~SNDRV_PCM_INFO_FIFO_IN_FRAMES;
+ if (!hw_support_mmap(substream))
+ params->info &= ~(SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID);
+ }
if (!params->fifo_size) {
m = hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT);
i = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
@@ -849,14 +900,19 @@ static int snd_pcm_action_single(struct action_ops *ops,
return res;
}
-/* call in mutex-protected context */
-static int snd_pcm_action_mutex(struct action_ops *ops,
- struct snd_pcm_substream *substream,
- int state)
+/*
+ * Note: call with stream lock
+ */
+static int snd_pcm_action(struct action_ops *ops,
+ struct snd_pcm_substream *substream,
+ int state)
{
int res;
- if (snd_pcm_stream_linked(substream)) {
+ if (!snd_pcm_stream_linked(substream))
+ return snd_pcm_action_single(ops, substream, state);
+
+ if (substream->pcm->nonatomic) {
if (!mutex_trylock(&substream->group->mutex)) {
mutex_unlock(&substream->self_group.mutex);
mutex_lock(&substream->group->mutex);
@@ -865,24 +921,6 @@ static int snd_pcm_action_mutex(struct action_ops *ops,
res = snd_pcm_action_group(ops, substream, state, 1);
mutex_unlock(&substream->group->mutex);
} else {
- res = snd_pcm_action_single(ops, substream, state);
- }
- return res;
-}
-
-/*
- * Note: call with stream lock
- */
-static int snd_pcm_action(struct action_ops *ops,
- struct snd_pcm_substream *substream,
- int state)
-{
- int res;
-
- if (substream->pcm->nonatomic)
- return snd_pcm_action_mutex(ops, substream, state);
-
- if (snd_pcm_stream_linked(substream)) {
if (!spin_trylock(&substream->group->lock)) {
spin_unlock(&substream->self_group.lock);
spin_lock(&substream->group->lock);
@@ -890,34 +928,10 @@ static int snd_pcm_action(struct action_ops *ops,
}
res = snd_pcm_action_group(ops, substream, state, 1);
spin_unlock(&substream->group->lock);
- } else {
- res = snd_pcm_action_single(ops, substream, state);
}
return res;
}
-static int snd_pcm_action_lock_mutex(struct action_ops *ops,
- struct snd_pcm_substream *substream,
- int state)
-{
- int res;
-
- down_read(&snd_pcm_link_rwsem);
- if (snd_pcm_stream_linked(substream)) {
- mutex_lock(&substream->group->mutex);
- mutex_lock(&substream->self_group.mutex);
- res = snd_pcm_action_group(ops, substream, state, 1);
- mutex_unlock(&substream->self_group.mutex);
- mutex_unlock(&substream->group->mutex);
- } else {
- mutex_lock(&substream->self_group.mutex);
- res = snd_pcm_action_single(ops, substream, state);
- mutex_unlock(&substream->self_group.mutex);
- }
- up_read(&snd_pcm_link_rwsem);
- return res;
-}
-
/*
* Note: don't use any locks before
*/
@@ -927,22 +941,9 @@ static int snd_pcm_action_lock_irq(struct action_ops *ops,
{
int res;
- if (substream->pcm->nonatomic)
- return snd_pcm_action_lock_mutex(ops, substream, state);
-
- read_lock_irq(&snd_pcm_link_rwlock);
- if (snd_pcm_stream_linked(substream)) {
- spin_lock(&substream->group->lock);
- spin_lock(&substream->self_group.lock);
- res = snd_pcm_action_group(ops, substream, state, 1);
- spin_unlock(&substream->self_group.lock);
- spin_unlock(&substream->group->lock);
- } else {
- spin_lock(&substream->self_group.lock);
- res = snd_pcm_action_single(ops, substream, state);
- spin_unlock(&substream->self_group.lock);
- }
- read_unlock_irq(&snd_pcm_link_rwlock);
+ snd_pcm_stream_lock_irq(substream);
+ res = snd_pcm_action(ops, substream, state);
+ snd_pcm_stream_unlock_irq(substream);
return res;
}
@@ -1051,10 +1052,10 @@ static void snd_pcm_post_stop(struct snd_pcm_substream *substream, int state)
struct snd_pcm_runtime *runtime = substream->runtime;
if (runtime->status->state != state) {
snd_pcm_trigger_tstamp(substream);
+ runtime->status->state = state;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSTOP,
&runtime->trigger_tstamp);
- runtime->status->state = state;
}
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
@@ -1097,6 +1098,28 @@ int snd_pcm_drain_done(struct snd_pcm_substream *substream)
SNDRV_PCM_STATE_SETUP);
}
+/**
+ * snd_pcm_stop_xrun - stop the running streams as XRUN
+ * @substream: the PCM substream instance
+ *
+ * This stops the given running substream (and all linked substreams) as XRUN.
+ * Unlike snd_pcm_stop(), this function takes the substream lock by itself.
+ *
+ * Return: Zero if successful, or a negative error code.
+ */
+int snd_pcm_stop_xrun(struct snd_pcm_substream *substream)
+{
+ unsigned long flags;
+ int ret = 0;
+
+ snd_pcm_stream_lock_irqsave(substream, flags);
+ if (snd_pcm_running(substream))
+ ret = snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irqrestore(substream, flags);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_pcm_stop_xrun);
+
/*
* pause callbacks
*/
@@ -1203,11 +1226,11 @@ static void snd_pcm_post_suspend(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
+ runtime->status->suspended_state = runtime->status->state;
+ runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MSUSPEND,
&runtime->trigger_tstamp);
- runtime->status->suspended_state = runtime->status->state;
- runtime->status->state = SNDRV_PCM_STATE_SUSPENDED;
wake_up(&runtime->sleep);
wake_up(&runtime->tsleep);
}
@@ -1310,10 +1333,10 @@ static void snd_pcm_post_resume(struct snd_pcm_substream *substream, int state)
{
struct snd_pcm_runtime *runtime = substream->runtime;
snd_pcm_trigger_tstamp(substream);
+ runtime->status->state = runtime->status->suspended_state;
if (substream->timer)
snd_timer_notify(substream->timer, SNDRV_TIMER_EVENT_MRESUME,
&runtime->trigger_tstamp);
- runtime->status->state = runtime->status->suspended_state;
}
static struct action_ops snd_pcm_action_resume = {
@@ -2070,7 +2093,7 @@ int snd_pcm_hw_constraints_complete(struct snd_pcm_substream *substream)
mask |= 1 << SNDRV_PCM_ACCESS_RW_INTERLEAVED;
if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
mask |= 1 << SNDRV_PCM_ACCESS_RW_NONINTERLEAVED;
- if (hw->info & SNDRV_PCM_INFO_MMAP) {
+ if (hw_support_mmap(substream)) {
if (hw->info & SNDRV_PCM_INFO_INTERLEAVED)
mask |= 1 << SNDRV_PCM_ACCESS_MMAP_INTERLEAVED;
if (hw->info & SNDRV_PCM_INFO_NONINTERLEAVED)
@@ -3249,20 +3272,6 @@ static inline struct page *
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
{
void *vaddr = substream->runtime->dma_area + ofs;
-#if defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
- return virt_to_page(CAC_ADDR(vaddr));
-#endif
-#if defined(CONFIG_PPC32) && defined(CONFIG_NOT_COHERENT_CACHE)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV) {
- dma_addr_t addr = substream->runtime->dma_addr + ofs;
- addr -= get_dma_offset(substream->dma_buffer.dev.dev);
- /* assume dma_handle set via pfn_to_phys() in
- * mm/dma-noncoherent.c
- */
- return pfn_to_page(addr >> PAGE_SHIFT);
- }
-#endif
return virt_to_page(vaddr);
}
@@ -3307,16 +3316,18 @@ static const struct vm_operations_struct snd_pcm_vm_ops_data_fault = {
.fault = snd_pcm_mmap_data_fault,
};
-#ifndef ARCH_HAS_DMA_MMAP_COHERENT
-/* This should be defined / handled globally! */
-#if defined(CONFIG_ARM) || defined(CONFIG_ARM64)
-#define ARCH_HAS_DMA_MMAP_COHERENT
-#endif
-#endif
-
/*
* mmap the DMA buffer on RAM
*/
+
+/**
+ * snd_pcm_lib_default_mmap - Default PCM data mmap function
+ * @substream: PCM substream
+ * @area: VMA
+ *
+ * This is the default mmap handler for PCM data. When mmap pcm_ops is NULL,
+ * this function is invoked implicitly.
+ */
int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
@@ -3329,7 +3340,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
area->vm_end - area->vm_start, area->vm_page_prot);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
-#ifdef ARCH_HAS_DMA_MMAP_COHERENT
+#ifndef CONFIG_X86 /* for avoiding warnings arch/x86/mm/pat.c */
if (!substream->ops->page &&
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV)
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
@@ -3337,11 +3348,7 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
substream->runtime->dma_area,
substream->runtime->dma_addr,
area->vm_end - area->vm_start);
-#elif defined(CONFIG_MIPS) && defined(CONFIG_DMA_NONCOHERENT)
- if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV &&
- !plat_device_is_coherent(substream->dma_buffer.dev.dev))
- area->vm_page_prot = pgprot_noncached(area->vm_page_prot);
-#endif /* ARCH_HAS_DMA_MMAP_COHERENT */
+#endif /* CONFIG_X86 */
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;
@@ -3352,6 +3359,15 @@ EXPORT_SYMBOL_GPL(snd_pcm_lib_default_mmap);
* mmap the DMA buffer on I/O memory area
*/
#if SNDRV_PCM_INFO_MMAP_IOMEM
+/**
+ * snd_pcm_lib_mmap_iomem - Default PCM data mmap function for I/O mem
+ * @substream: PCM substream
+ * @area: VMA
+ *
+ * When your hardware uses the iomapped pages as the hardware buffer and
+ * wants to mmap it, pass this function as mmap pcm_ops. Note that this
+ * is supposed to work only on limited architectures.
+ */
int snd_pcm_lib_mmap_iomem(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
diff --git a/sound/core/pcm_trace.h b/sound/core/pcm_trace.h
new file mode 100644
index 0000000..b63b654
--- /dev/null
+++ b/sound/core/pcm_trace.h
@@ -0,0 +1,110 @@
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM snd_pcm
+#define TRACE_INCLUDE_FILE pcm_trace
+
+#if !defined(_PCM_TRACE_H) || defined(TRACE_HEADER_MULTI_READ)
+#define _PCM_TRACE_H
+
+#include <linux/tracepoint.h>
+
+TRACE_EVENT(hwptr,
+ TP_PROTO(struct snd_pcm_substream *substream, snd_pcm_uframes_t pos, bool irq),
+ TP_ARGS(substream, pos, irq),
+ TP_STRUCT__entry(
+ __field( bool, in_interrupt )
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( snd_pcm_uframes_t, pos )
+ __field( snd_pcm_uframes_t, period_size )
+ __field( snd_pcm_uframes_t, buffer_size )
+ __field( snd_pcm_uframes_t, old_hw_ptr )
+ __field( snd_pcm_uframes_t, hw_ptr_base )
+ ),
+ TP_fast_assign(
+ __entry->in_interrupt = (irq);
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->pos = (pos);
+ __entry->period_size = (substream)->runtime->period_size;
+ __entry->buffer_size = (substream)->runtime->buffer_size;
+ __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
+ __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
+ ),
+ TP_printk("pcmC%dD%d%c/sub%d: %s: pos=%lu, old=%lu, base=%lu, period=%lu, buf=%lu",
+ __entry->card, __entry->device,
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->number,
+ __entry->in_interrupt ? "IRQ" : "POS",
+ (unsigned long)__entry->pos,
+ (unsigned long)__entry->old_hw_ptr,
+ (unsigned long)__entry->hw_ptr_base,
+ (unsigned long)__entry->period_size,
+ (unsigned long)__entry->buffer_size)
+);
+
+TRACE_EVENT(xrun,
+ TP_PROTO(struct snd_pcm_substream *substream),
+ TP_ARGS(substream),
+ TP_STRUCT__entry(
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( snd_pcm_uframes_t, period_size )
+ __field( snd_pcm_uframes_t, buffer_size )
+ __field( snd_pcm_uframes_t, old_hw_ptr )
+ __field( snd_pcm_uframes_t, hw_ptr_base )
+ ),
+ TP_fast_assign(
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->period_size = (substream)->runtime->period_size;
+ __entry->buffer_size = (substream)->runtime->buffer_size;
+ __entry->old_hw_ptr = (substream)->runtime->status->hw_ptr;
+ __entry->hw_ptr_base = (substream)->runtime->hw_ptr_base;
+ ),
+ TP_printk("pcmC%dD%d%c/sub%d: XRUN: old=%lu, base=%lu, period=%lu, buf=%lu",
+ __entry->card, __entry->device,
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->number,
+ (unsigned long)__entry->old_hw_ptr,
+ (unsigned long)__entry->hw_ptr_base,
+ (unsigned long)__entry->period_size,
+ (unsigned long)__entry->buffer_size)
+);
+
+TRACE_EVENT(hw_ptr_error,
+ TP_PROTO(struct snd_pcm_substream *substream, const char *why),
+ TP_ARGS(substream, why),
+ TP_STRUCT__entry(
+ __field( unsigned int, card )
+ __field( unsigned int, device )
+ __field( unsigned int, number )
+ __field( unsigned int, stream )
+ __field( const char *, reason )
+ ),
+ TP_fast_assign(
+ __entry->card = (substream)->pcm->card->number;
+ __entry->device = (substream)->pcm->device;
+ __entry->number = (substream)->number;
+ __entry->stream = (substream)->stream;
+ __entry->reason = (why);
+ ),
+ TP_printk("pcmC%dD%d%c/sub%d: ERROR: %s",
+ __entry->card, __entry->device,
+ __entry->stream == SNDRV_PCM_STREAM_PLAYBACK ? 'p' : 'c',
+ __entry->number, __entry->reason)
+);
+
+#endif /* _PCM_TRACE_H */
+
+/* This part must be outside protection */
+#undef TRACE_INCLUDE_PATH
+#define TRACE_INCLUDE_PATH .
+#include <trace/define_trace.h>
diff --git a/sound/core/seq/oss/seq_oss_init.c b/sound/core/seq/oss/seq_oss_init.c
index b9184d2..b0e32e1 100644
--- a/sound/core/seq/oss/seq_oss_init.c
+++ b/sound/core/seq/oss/seq_oss_init.c
@@ -403,14 +403,11 @@ free_devinfo(void *private)
{
struct seq_oss_devinfo *dp = (struct seq_oss_devinfo *)private;
- if (dp->timer)
- snd_seq_oss_timer_delete(dp->timer);
+ snd_seq_oss_timer_delete(dp->timer);
- if (dp->writeq)
- snd_seq_oss_writeq_delete(dp->writeq);
+ snd_seq_oss_writeq_delete(dp->writeq);
- if (dp->readq)
- snd_seq_oss_readq_delete(dp->readq);
+ snd_seq_oss_readq_delete(dp->readq);
kfree(dp);
}
diff --git a/sound/core/seq/seq.c b/sound/core/seq/seq.c
index 7121105..7e0aabb 100644
--- a/sound/core/seq/seq.c
+++ b/sound/core/seq/seq.c
@@ -86,7 +86,6 @@ static int __init alsa_seq_init(void)
{
int err;
- snd_seq_autoload_lock();
if ((err = client_init_data()) < 0)
goto error;
@@ -110,8 +109,8 @@ static int __init alsa_seq_init(void)
if ((err = snd_seq_system_client_init()) < 0)
goto error;
+ snd_seq_autoload_init();
error:
- snd_seq_autoload_unlock();
return err;
}
@@ -131,6 +130,8 @@ static void __exit alsa_seq_exit(void)
/* release event memory */
snd_sequencer_memory_done();
+
+ snd_seq_autoload_exit();
}
module_init(alsa_seq_init)
diff --git a/sound/core/seq/seq_device.c b/sound/core/seq/seq_device.c
index 91a786a..0631bda 100644
--- a/sound/core/seq/seq_device.c
+++ b/sound/core/seq/seq_device.c
@@ -56,6 +56,7 @@ MODULE_LICENSE("GPL");
#define DRIVER_LOADED (1<<0)
#define DRIVER_REQUESTED (1<<1)
#define DRIVER_LOCKED (1<<2)
+#define DRIVER_REQUESTING (1<<3)
struct ops_list {
char id[ID_LEN]; /* driver id */
@@ -127,42 +128,82 @@ static void snd_seq_device_info(struct snd_info_entry *entry,
#ifdef CONFIG_MODULES
/* avoid auto-loading during module_init() */
-static int snd_seq_in_init;
+static atomic_t snd_seq_in_init = ATOMIC_INIT(1); /* blocked as default */
void snd_seq_autoload_lock(void)
{
- snd_seq_in_init++;
+ atomic_inc(&snd_seq_in_init);
}
void snd_seq_autoload_unlock(void)
{
- snd_seq_in_init--;
+ atomic_dec(&snd_seq_in_init);
}
-#endif
-void snd_seq_device_load_drivers(void)
+static void autoload_drivers(void)
{
-#ifdef CONFIG_MODULES
- struct ops_list *ops;
+ /* avoid reentrance */
+ if (atomic_inc_return(&snd_seq_in_init) == 1) {
+ struct ops_list *ops;
+
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list) {
+ if ((ops->driver & DRIVER_REQUESTING) &&
+ !(ops->driver & DRIVER_REQUESTED)) {
+ ops->used++;
+ mutex_unlock(&ops_mutex);
+ ops->driver |= DRIVER_REQUESTED;
+ request_module("snd-%s", ops->id);
+ mutex_lock(&ops_mutex);
+ ops->used--;
+ }
+ }
+ mutex_unlock(&ops_mutex);
+ }
+ atomic_dec(&snd_seq_in_init);
+}
- /* Calling request_module during module_init()
- * may cause blocking.
- */
- if (snd_seq_in_init)
- return;
+static void call_autoload(struct work_struct *work)
+{
+ autoload_drivers();
+}
- mutex_lock(&ops_mutex);
- list_for_each_entry(ops, &opslist, list) {
- if (! (ops->driver & DRIVER_LOADED) &&
- ! (ops->driver & DRIVER_REQUESTED)) {
- ops->used++;
- mutex_unlock(&ops_mutex);
- ops->driver |= DRIVER_REQUESTED;
- request_module("snd-%s", ops->id);
- mutex_lock(&ops_mutex);
- ops->used--;
- }
+static DECLARE_WORK(autoload_work, call_autoload);
+
+static void try_autoload(struct ops_list *ops)
+{
+ if (!ops->driver) {
+ ops->driver |= DRIVER_REQUESTING;
+ schedule_work(&autoload_work);
}
+}
+
+static void queue_autoload_drivers(void)
+{
+ struct ops_list *ops;
+
+ mutex_lock(&ops_mutex);
+ list_for_each_entry(ops, &opslist, list)
+ try_autoload(ops);
mutex_unlock(&ops_mutex);
+}
+
+void snd_seq_autoload_init(void)
+{
+ atomic_dec(&snd_seq_in_init);
+#ifdef CONFIG_SND_SEQUENCER_MODULE
+ /* initial autoload only when snd-seq is a module */
+ queue_autoload_drivers();
+#endif
+}
+#else
+#define try_autoload(ops) /* NOP */
+#endif
+
+void snd_seq_device_load_drivers(void)
+{
+#ifdef CONFIG_MODULES
+ queue_autoload_drivers();
+ flush_work(&autoload_work);
#endif
}
@@ -214,13 +255,14 @@ int snd_seq_device_new(struct snd_card *card, int device, char *id, int argsize,
ops->num_devices++;
mutex_unlock(&ops->reg_mutex);
- unlock_driver(ops);
-
if ((err = snd_device_new(card, SNDRV_DEV_SEQUENCER, dev, &dops)) < 0) {
snd_seq_device_free(dev);
return err;
}
+ try_autoload(ops);
+ unlock_driver(ops);
+
if (result)
*result = dev;
@@ -318,16 +360,12 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
entry->init_device == NULL || entry->free_device == NULL)
return -EINVAL;
- snd_seq_autoload_lock();
ops = find_driver(id, 1);
- if (ops == NULL) {
- snd_seq_autoload_unlock();
+ if (ops == NULL)
return -ENOMEM;
- }
if (ops->driver & DRIVER_LOADED) {
pr_warn("ALSA: seq: driver_register: driver '%s' already exists\n", id);
unlock_driver(ops);
- snd_seq_autoload_unlock();
return -EBUSY;
}
@@ -344,7 +382,6 @@ int snd_seq_device_register_driver(char *id, struct snd_seq_dev_ops *entry,
mutex_unlock(&ops->reg_mutex);
unlock_driver(ops);
- snd_seq_autoload_unlock();
return 0;
}
@@ -554,6 +591,9 @@ static int __init alsa_seq_device_init(void)
static void __exit alsa_seq_device_exit(void)
{
+#ifdef CONFIG_MODULES
+ cancel_work_sync(&autoload_work);
+#endif
remove_drivers();
#ifdef CONFIG_PROC_FS
snd_info_free_entry(info_entry);
@@ -570,6 +610,7 @@ EXPORT_SYMBOL(snd_seq_device_new);
EXPORT_SYMBOL(snd_seq_device_register_driver);
EXPORT_SYMBOL(snd_seq_device_unregister_driver);
#ifdef CONFIG_MODULES
+EXPORT_SYMBOL(snd_seq_autoload_init);
EXPORT_SYMBOL(snd_seq_autoload_lock);
EXPORT_SYMBOL(snd_seq_autoload_unlock);
#endif
diff --git a/sound/core/sgbuf.c b/sound/core/sgbuf.c
index 0a41850..84fffab 100644
--- a/sound/core/sgbuf.c
+++ b/sound/core/sgbuf.c
@@ -39,8 +39,7 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
if (! sgbuf)
return -EINVAL;
- if (dmab->area)
- vunmap(dmab->area);
+ vunmap(dmab->area);
dmab->area = NULL;
tmpb.dev.type = SNDRV_DMA_TYPE_DEV;
diff --git a/sound/core/sound.c b/sound/core/sound.c
index 38ad1a0..f133306 100644
--- a/sound/core/sound.c
+++ b/sound/core/sound.c
@@ -355,8 +355,13 @@ int snd_unregister_device(int type, struct snd_card *card, int dev)
EXPORT_SYMBOL(snd_unregister_device);
-/* get the assigned device to the given type and device number;
- * the caller needs to release it via put_device() after using it
+/**
+ * snd_get_device - get the assigned device to the given type and device number
+ * @type: the device type, SNDRV_DEVICE_TYPE_XXX
+ * @card:the card instance
+ * @dev: the device index
+ *
+ * The caller needs to release it via put_device() after using it.
*/
struct device *snd_get_device(int type, struct snd_card *card, int dev)
{
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c
index f5fd448..0388fbb 100644
--- a/sound/drivers/mts64.c
+++ b/sound/drivers/mts64.c
@@ -604,21 +604,11 @@ static struct snd_kcontrol_new mts64_ctl_smpte_time_frames = {
static int snd_mts64_ctl_smpte_fps_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = { "24",
- "25",
- "29.97",
- "30D",
- "30" };
+ static const char * const texts[5] = {
+ "24", "25", "29.97", "30D", "30"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_mts64_ctl_smpte_fps_get(struct snd_kcontrol *kctl,
diff --git a/sound/drivers/virmidi.c b/sound/drivers/virmidi.c
index b17872429..d28d870 100644
--- a/sound/drivers/virmidi.c
+++ b/sound/drivers/virmidi.c
@@ -99,30 +99,33 @@ static int snd_virmidi_probe(struct platform_device *devptr)
if (midi_devs[dev] > MAX_MIDI_DEVICES) {
snd_printk(KERN_WARNING
- "too much midi devices for virmidi %d: "
- "force to use %d\n", dev, MAX_MIDI_DEVICES);
+ "too much midi devices for virmidi %d: force to use %d\n",
+ dev, MAX_MIDI_DEVICES);
midi_devs[dev] = MAX_MIDI_DEVICES;
}
for (idx = 0; idx < midi_devs[dev]; idx++) {
struct snd_rawmidi *rmidi;
struct snd_virmidi_dev *rdev;
- if ((err = snd_virmidi_new(card, idx, &rmidi)) < 0)
+
+ err = snd_virmidi_new(card, idx, &rmidi);
+ if (err < 0)
goto __nodev;
rdev = rmidi->private_data;
vmidi->midi[idx] = rmidi;
strcpy(rmidi->name, "Virtual Raw MIDI");
rdev->seq_mode = SNDRV_VIRMIDI_SEQ_DISPATCH;
}
-
+
strcpy(card->driver, "VirMIDI");
strcpy(card->shortname, "VirMIDI");
sprintf(card->longname, "Virtual MIDI Card %i", dev + 1);
- if ((err = snd_card_register(card)) == 0) {
+ err = snd_card_register(card);
+ if (!err) {
platform_set_drvdata(devptr, card);
return 0;
}
- __nodev:
+__nodev:
snd_card_free(card);
return err;
}
@@ -157,13 +160,15 @@ static int __init alsa_card_virmidi_init(void)
{
int i, cards, err;
- if ((err = platform_driver_register(&snd_virmidi_driver)) < 0)
+ err = platform_driver_register(&snd_virmidi_driver);
+ if (err < 0)
return err;
cards = 0;
for (i = 0; i < SNDRV_CARDS; i++) {
struct platform_device *device;
- if (! enable[i])
+
+ if (!enable[i])
continue;
device = platform_device_register_simple(SND_VIRMIDI_DRIVER,
i, NULL, 0);
diff --git a/sound/drivers/vx/vx_core.c b/sound/drivers/vx/vx_core.c
index e8cc169..fc05a37 100644
--- a/sound/drivers/vx/vx_core.c
+++ b/sound/drivers/vx/vx_core.c
@@ -416,6 +416,7 @@ int vx_send_rih(struct vx_core *chip, int cmd)
/**
* snd_vx_boot_xilinx - boot up the xilinx interface
+ * @chip: VX core instance
* @boot: the boot record to load
*/
int snd_vx_load_boot_image(struct vx_core *chip, const struct firmware *boot)
@@ -538,6 +539,8 @@ EXPORT_SYMBOL(snd_vx_threaded_irq_handler);
/**
* snd_vx_irq_handler - interrupt handler
+ * @irq: irq number
+ * @dev: VX core instance
*/
irqreturn_t snd_vx_irq_handler(int irq, void *dev)
{
@@ -649,6 +652,8 @@ static void vx_proc_init(struct vx_core *chip)
/**
* snd_vx_dsp_boot - load the DSP boot
+ * @chip: VX core instance
+ * @boot: firmware data
*/
int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot)
{
@@ -669,6 +674,8 @@ EXPORT_SYMBOL(snd_vx_dsp_boot);
/**
* snd_vx_dsp_load - load the DSP image
+ * @chip: VX core instance
+ * @dsp: firmware data
*/
int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
{
@@ -768,7 +775,10 @@ EXPORT_SYMBOL(snd_vx_resume);
/**
* snd_vx_create - constructor for struct vx_core
+ * @card: card instance
* @hw: hardware specific record
+ * @ops: VX ops pointer
+ * @extra_size: extra byte size to allocate appending to chip
*
* this function allocates the instance and prepare for the hardware
* initialization.
diff --git a/sound/drivers/vx/vx_mixer.c b/sound/drivers/vx/vx_mixer.c
index 3b6823f..be9477e 100644
--- a/sound/drivers/vx/vx_mixer.c
+++ b/sound/drivers/vx/vx_mixer.c
@@ -471,30 +471,18 @@ static struct snd_kcontrol_new vx_control_output_level = {
*/
static int vx_audio_src_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts_mic[3] = {
+ static const char * const texts_mic[3] = {
"Digital", "Line", "Mic"
};
- static char *texts_vx2[2] = {
+ static const char * const texts_vx2[2] = {
"Digital", "Analog"
};
struct vx_core *chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- if (chip->type >= VX_TYPE_VXPOCKET) {
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts_mic[uinfo->value.enumerated.item]);
- } else {
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts_vx2[uinfo->value.enumerated.item]);
- }
- return 0;
+ if (chip->type >= VX_TYPE_VXPOCKET)
+ return snd_ctl_enum_info(uinfo, 1, 3, texts_mic);
+ else
+ return snd_ctl_enum_info(uinfo, 1, 2, texts_vx2);
}
static int vx_audio_src_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -539,18 +527,11 @@ static struct snd_kcontrol_new vx_control_audio_src = {
*/
static int vx_clock_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Auto", "Internal", "External"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int vx_clock_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/firewire/Kconfig b/sound/firewire/Kconfig
index 46dff64..ecec547 100644
--- a/sound/firewire/Kconfig
+++ b/sound/firewire/Kconfig
@@ -13,28 +13,34 @@ config SND_FIREWIRE_LIB
select SND_RAWMIDI
config SND_DICE
- tristate "DICE-based DACs (EXPERIMENTAL)"
+ tristate "DICE-based DACs support"
select SND_HWDEP
select SND_FIREWIRE_LIB
help
Say Y here to include support for many DACs based on the DICE
- chip family (DICE-II/Jr/Mini) from TC Applied Technologies.
-
- At the moment, this driver supports playback only. If you
- want to use devices that support capturing, use FFADO instead.
+ chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces.
To compile this driver as a module, choose M here: the module
will be called snd-dice.
-config SND_FIREWIRE_SPEAKERS
- tristate "FireWire speakers"
+config SND_OXFW
+ tristate "Oxford Semiconductor FW970/971 chipset support"
select SND_FIREWIRE_LIB
+ select SND_HWDEP
help
- Say Y here to include support for the Griffin FireWave Surround
- and the LaCie FireWire Speakers.
+ Say Y here to include support for FireWire devices based on
+ Oxford Semiconductor FW970/971 chipset.
+ * Griffin Firewave
+ * LaCie Firewire Speakers
+ * Behringer F-Control Audio 202
+ * Mackie(Loud) Onyx-i series (former models)
+ * Mackie(Loud) Onyx Satellite
+ * Mackie(Loud) Tapco Link.Firewire
+ * Mackie(Loud) d.2 pro/d.4 pro
+ * Mackie(Loud) U.420/U.420d
To compile this driver as a module, choose M here: the module
- will be called snd-firewire-speakers.
+ will be called snd-oxfw.
config SND_ISIGHT
tristate "Apple iSight microphone"
diff --git a/sound/firewire/Makefile b/sound/firewire/Makefile
index fad8d49..8b37f08 100644
--- a/sound/firewire/Makefile
+++ b/sound/firewire/Makefile
@@ -1,13 +1,12 @@
snd-firewire-lib-objs := lib.o iso-resources.o packets-buffer.o \
fcp.o cmp.o amdtp.o
-snd-dice-objs := dice.o
-snd-firewire-speakers-objs := speakers.o
+snd-oxfw-objs := oxfw.o
snd-isight-objs := isight.o
snd-scs1x-objs := scs1x.o
obj-$(CONFIG_SND_FIREWIRE_LIB) += snd-firewire-lib.o
-obj-$(CONFIG_SND_DICE) += snd-dice.o
-obj-$(CONFIG_SND_FIREWIRE_SPEAKERS) += snd-firewire-speakers.o
+obj-$(CONFIG_SND_DICE) += dice/
+obj-$(CONFIG_SND_OXFW) += oxfw/
obj-$(CONFIG_SND_ISIGHT) += snd-isight.o
obj-$(CONFIG_SND_SCS1X) += snd-scs1x.o
obj-$(CONFIG_SND_FIREWORKS) += fireworks/
diff --git a/sound/firewire/amdtp.c b/sound/firewire/amdtp.c
index 95fc2eaf..3badc70 100644
--- a/sound/firewire/amdtp.c
+++ b/sound/firewire/amdtp.c
@@ -1006,11 +1006,7 @@ void amdtp_stream_pcm_abort(struct amdtp_stream *s)
struct snd_pcm_substream *pcm;
pcm = ACCESS_ONCE(s->pcm);
- if (pcm) {
- snd_pcm_stream_lock_irq(pcm);
- if (snd_pcm_running(pcm))
- snd_pcm_stop(pcm, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irq(pcm);
- }
+ if (pcm)
+ snd_pcm_stop_xrun(pcm);
}
EXPORT_SYMBOL(amdtp_stream_pcm_abort);
diff --git a/sound/firewire/amdtp.h b/sound/firewire/amdtp.h
index 4823c08..e6e8926 100644
--- a/sound/firewire/amdtp.h
+++ b/sound/firewire/amdtp.h
@@ -23,7 +23,7 @@
* corresponds to the end of event in the packet. Out of IEC 61883.
* @CIP_WRONG_DBS: Only for in-stream. The value of dbs is wrong in in-packets.
* The value of data_block_quadlets is used instead of reported value.
- * @SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is
+ * @CIP_SKIP_DBC_ZERO_CHECK: Only for in-stream. Packets with zero in dbc is
* skipped for detecting discontinuity.
* @CIP_SKIP_INIT_DBC_CHECK: Only for in-stream. The value of dbc in first
* packet is not continuous from an initial value.
@@ -43,7 +43,27 @@ enum cip_flags {
};
/**
- * enum cip_sfc - a stream's sample rate
+ * enum cip_sfc - supported Sampling Frequency Codes (SFCs)
+ * @CIP_SFC_32000: 32,000 data blocks
+ * @CIP_SFC_44100: 44,100 data blocks
+ * @CIP_SFC_48000: 48,000 data blocks
+ * @CIP_SFC_88200: 88,200 data blocks
+ * @CIP_SFC_96000: 96,000 data blocks
+ * @CIP_SFC_176400: 176,400 data blocks
+ * @CIP_SFC_192000: 192,000 data blocks
+ * @CIP_SFC_COUNT: the number of supported SFCs
+ *
+ * These values are used to show nominal Sampling Frequency Code in
+ * Format Dependent Field (FDF) of AMDTP packet header. In IEC 61883-6:2002,
+ * this code means the number of events per second. Actually the code
+ * represents the number of data blocks transferred per second in an AMDTP
+ * stream.
+ *
+ * In IEC 61883-6:2005, some extensions were added to support more types of
+ * data such as 'One Bit LInear Audio', therefore the meaning of SFC became
+ * different depending on the types.
+ *
+ * Currently our implementation is compatible with IEC 61883-6:2002.
*/
enum cip_sfc {
CIP_SFC_32000 = 0,
diff --git a/sound/firewire/bebob/bebob.h b/sound/firewire/bebob/bebob.h
index e13eef9..dfbcd23 100644
--- a/sound/firewire/bebob/bebob.h
+++ b/sound/firewire/bebob/bebob.h
@@ -52,7 +52,7 @@ extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES];
#define SND_BEBOB_CLOCK_INTERNAL "Internal"
struct snd_bebob_clock_spec {
unsigned int num;
- char *const *labels;
+ const char *const *labels;
int (*get)(struct snd_bebob *bebob, unsigned int *id);
};
struct snd_bebob_rate_spec {
@@ -61,7 +61,7 @@ struct snd_bebob_rate_spec {
};
struct snd_bebob_meter_spec {
unsigned int num;
- char *const *labels;
+ const char *const *labels;
int (*get)(struct snd_bebob *bebob, u32 *target, unsigned int size);
};
struct snd_bebob_spec {
diff --git a/sound/firewire/bebob/bebob_focusrite.c b/sound/firewire/bebob/bebob_focusrite.c
index 3b052ed..fc67c1b 100644
--- a/sound/firewire/bebob/bebob_focusrite.c
+++ b/sound/firewire/bebob/bebob_focusrite.c
@@ -103,10 +103,10 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)
&data, sizeof(__be32), 0);
}
-static char *const saffirepro_10_clk_src_labels[] = {
+static const char *const saffirepro_10_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock"
};
-static char *const saffirepro_26_clk_src_labels[] = {
+static const char *const saffirepro_26_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock"
};
/* Value maps between registers and labels for SaffirePro 10/26. */
@@ -195,7 +195,7 @@ end:
}
struct snd_bebob_spec saffire_le_spec;
-static char *const saffire_both_clk_src_labels[] = {
+static const char *const saffire_both_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF"
};
static int
@@ -210,12 +210,12 @@ saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
return err;
};
-static char *const saffire_le_meter_labels[] = {
+static const char *const saffire_le_meter_labels[] = {
ANA_IN, ANA_IN, DIG_IN,
ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
STM_IN, STM_IN
};
-static char *const saffire_meter_labels[] = {
+static const char *const saffire_meter_labels[] = {
ANA_IN, ANA_IN,
STM_IN, STM_IN, STM_IN, STM_IN, STM_IN,
};
diff --git a/sound/firewire/bebob/bebob_maudio.c b/sound/firewire/bebob/bebob_maudio.c
index 70faa3a..a422aaa 100644
--- a/sound/firewire/bebob/bebob_maudio.c
+++ b/sound/firewire/bebob/bebob_maudio.c
@@ -340,7 +340,7 @@ end:
}
/* Clock source control for special firmware */
-static char *const special_clk_labels[] = {
+static const char *const special_clk_labels[] = {
SND_BEBOB_CLOCK_INTERNAL " with Digital Mute", "Digital",
"Word Clock", SND_BEBOB_CLOCK_INTERNAL};
static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
@@ -352,17 +352,8 @@ static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
static int special_clk_ctl_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *einf)
{
- einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- einf->count = 1;
- einf->value.enumerated.items = ARRAY_SIZE(special_clk_labels);
-
- if (einf->value.enumerated.item >= einf->value.enumerated.items)
- einf->value.enumerated.item = einf->value.enumerated.items - 1;
-
- strcpy(einf->value.enumerated.name,
- special_clk_labels[einf->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(einf, 1, ARRAY_SIZE(special_clk_labels),
+ special_clk_labels);
}
static int special_clk_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -438,23 +429,15 @@ static struct snd_kcontrol_new special_sync_ctl = {
};
/* Digital input interface control for special firmware */
-static char *const special_dig_in_iface_labels[] = {
+static const char *const special_dig_in_iface_labels[] = {
"S/PDIF Optical", "S/PDIF Coaxial", "ADAT Optical"
};
static int special_dig_in_iface_ctl_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *einf)
{
- einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- einf->count = 1;
- einf->value.enumerated.items = ARRAY_SIZE(special_dig_in_iface_labels);
-
- if (einf->value.enumerated.item >= einf->value.enumerated.items)
- einf->value.enumerated.item = einf->value.enumerated.items - 1;
-
- strcpy(einf->value.enumerated.name,
- special_dig_in_iface_labels[einf->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(einf, 1,
+ ARRAY_SIZE(special_dig_in_iface_labels),
+ special_dig_in_iface_labels);
}
static int special_dig_in_iface_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -539,23 +522,15 @@ static struct snd_kcontrol_new special_dig_in_iface_ctl = {
};
/* Digital output interface control for special firmware */
-static char *const special_dig_out_iface_labels[] = {
+static const char *const special_dig_out_iface_labels[] = {
"S/PDIF Optical and Coaxial", "ADAT Optical"
};
static int special_dig_out_iface_ctl_info(struct snd_kcontrol *kctl,
struct snd_ctl_elem_info *einf)
{
- einf->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- einf->count = 1;
- einf->value.enumerated.items = ARRAY_SIZE(special_dig_out_iface_labels);
-
- if (einf->value.enumerated.item >= einf->value.enumerated.items)
- einf->value.enumerated.item = einf->value.enumerated.items - 1;
-
- strcpy(einf->value.enumerated.name,
- special_dig_out_iface_labels[einf->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(einf, 1,
+ ARRAY_SIZE(special_dig_out_iface_labels),
+ special_dig_out_iface_labels);
}
static int special_dig_out_iface_ctl_get(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *uval)
@@ -631,7 +606,7 @@ end:
}
/* Hardware metering for special firmware */
-static char *const special_meter_labels[] = {
+static const char *const special_meter_labels[] = {
ANA_IN, ANA_IN, ANA_IN, ANA_IN,
SPDIF_IN,
ADAT_IN, ADAT_IN, ADAT_IN, ADAT_IN,
@@ -671,30 +646,30 @@ end:
}
/* last 4 bytes are omitted because it's clock info. */
-static char *const fw410_meter_labels[] = {
+static const char *const fw410_meter_labels[] = {
ANA_IN, DIG_IN,
ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT, DIG_OUT,
HP_OUT
};
-static char *const audiophile_meter_labels[] = {
+static const char *const audiophile_meter_labels[] = {
ANA_IN, DIG_IN,
ANA_OUT, ANA_OUT, DIG_OUT,
HP_OUT, AUX_OUT,
};
-static char *const solo_meter_labels[] = {
+static const char *const solo_meter_labels[] = {
ANA_IN, DIG_IN,
STRM_IN, STRM_IN,
ANA_OUT, DIG_OUT
};
/* no clock info */
-static char *const ozonic_meter_labels[] = {
+static const char *const ozonic_meter_labels[] = {
ANA_IN, ANA_IN,
STRM_IN, STRM_IN,
ANA_OUT, ANA_OUT
};
/* TODO: need testers. these positions are based on authour's assumption */
-static char *const nrv10_meter_labels[] = {
+static const char *const nrv10_meter_labels[] = {
ANA_IN, ANA_IN, ANA_IN, ANA_IN,
DIG_IN,
ANA_OUT, ANA_OUT, ANA_OUT, ANA_OUT,
diff --git a/sound/firewire/bebob/bebob_terratec.c b/sound/firewire/bebob/bebob_terratec.c
index 9940611..ad63500 100644
--- a/sound/firewire/bebob/bebob_terratec.c
+++ b/sound/firewire/bebob/bebob_terratec.c
@@ -8,7 +8,7 @@
#include "./bebob.h"
-static char *const phase88_rack_clk_src_labels[] = {
+static const char *const phase88_rack_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "Digital In", "Word Clock"
};
static int
@@ -34,7 +34,7 @@ end:
return err;
}
-static char *const phase24_series_clk_src_labels[] = {
+static const char *const phase24_series_clk_src_labels[] = {
SND_BEBOB_CLOCK_INTERNAL, "Digital In"
};
static int
diff --git a/sound/firewire/bebob/bebob_yamaha.c b/sound/firewire/bebob/bebob_yamaha.c
index 9b7e798..ef1fe38 100644
--- a/sound/firewire/bebob/bebob_yamaha.c
+++ b/sound/firewire/bebob/bebob_yamaha.c
@@ -28,7 +28,7 @@
* reccomend users to close ffado-mixer at 192.0kHz if mixer is needless.
*/
-static char *const clk_src_labels[] = {SND_BEBOB_CLOCK_INTERNAL, "SPDIF"};
+static const char *const clk_src_labels[] = {SND_BEBOB_CLOCK_INTERNAL, "SPDIF"};
static int
clk_src_get(struct snd_bebob *bebob, unsigned int *id)
{
diff --git a/sound/firewire/cmp.c b/sound/firewire/cmp.c
index ba8df5a..ae3bc19 100644
--- a/sound/firewire/cmp.c
+++ b/sound/firewire/cmp.c
@@ -114,6 +114,7 @@ static int pcr_modify(struct cmp_connection *c,
* cmp_connection_init - initializes a connection manager
* @c: the connection manager to initialize
* @unit: a unit of the target device
+ * @direction: input or output
* @pcr_index: the index of the iPCR/oPCR on the target device
*/
int cmp_connection_init(struct cmp_connection *c,
@@ -154,6 +155,7 @@ EXPORT_SYMBOL(cmp_connection_init);
/**
* cmp_connection_check_used - check connection is already esablished or not
* @c: the connection manager to be checked
+ * @used: the pointer to store the result of checking the connection
*/
int cmp_connection_check_used(struct cmp_connection *c, bool *used)
{
diff --git a/sound/firewire/dice.c b/sound/firewire/dice.c
deleted file mode 100644
index e3a04d6..0000000
--- a/sound/firewire/dice.c
+++ /dev/null
@@ -1,1511 +0,0 @@
-/*
- * TC Applied Technologies Digital Interface Communications Engine driver
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/compat.h>
-#include <linux/completion.h>
-#include <linux/delay.h>
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/jiffies.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <linux/spinlock.h>
-#include <linux/wait.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/firewire.h>
-#include <sound/hwdep.h>
-#include <sound/info.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include "amdtp.h"
-#include "iso-resources.h"
-#include "lib.h"
-#include "dice-interface.h"
-
-
-struct dice {
- struct snd_card *card;
- struct fw_unit *unit;
- spinlock_t lock;
- struct mutex mutex;
- unsigned int global_offset;
- unsigned int rx_offset;
- unsigned int clock_caps;
- unsigned int rx_channels[3];
- unsigned int rx_midi_ports[3];
- struct fw_address_handler notification_handler;
- int owner_generation;
- int dev_lock_count; /* > 0 driver, < 0 userspace */
- bool dev_lock_changed;
- bool global_enabled;
- struct completion clock_accepted;
- wait_queue_head_t hwdep_wait;
- u32 notification_bits;
- struct fw_iso_resources resources;
- struct amdtp_stream stream;
-};
-
-MODULE_DESCRIPTION("DICE driver");
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
-
-static const unsigned int dice_rates[] = {
- /* mode 0 */
- [0] = 32000,
- [1] = 44100,
- [2] = 48000,
- /* mode 1 */
- [3] = 88200,
- [4] = 96000,
- /* mode 2 */
- [5] = 176400,
- [6] = 192000,
-};
-
-static unsigned int rate_to_index(unsigned int rate)
-{
- unsigned int i;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
- if (dice_rates[i] == rate)
- return i;
-
- return 0;
-}
-
-static unsigned int rate_index_to_mode(unsigned int rate_index)
-{
- return ((int)rate_index - 1) / 2;
-}
-
-static void dice_lock_changed(struct dice *dice)
-{
- dice->dev_lock_changed = true;
- wake_up(&dice->hwdep_wait);
-}
-
-static int dice_try_lock(struct dice *dice)
-{
- int err;
-
- spin_lock_irq(&dice->lock);
-
- if (dice->dev_lock_count < 0) {
- err = -EBUSY;
- goto out;
- }
-
- if (dice->dev_lock_count++ == 0)
- dice_lock_changed(dice);
- err = 0;
-
-out:
- spin_unlock_irq(&dice->lock);
-
- return err;
-}
-
-static void dice_unlock(struct dice *dice)
-{
- spin_lock_irq(&dice->lock);
-
- if (WARN_ON(dice->dev_lock_count <= 0))
- goto out;
-
- if (--dice->dev_lock_count == 0)
- dice_lock_changed(dice);
-
-out:
- spin_unlock_irq(&dice->lock);
-}
-
-static inline u64 global_address(struct dice *dice, unsigned int offset)
-{
- return DICE_PRIVATE_SPACE + dice->global_offset + offset;
-}
-
-// TODO: rx index
-static inline u64 rx_address(struct dice *dice, unsigned int offset)
-{
- return DICE_PRIVATE_SPACE + dice->rx_offset + offset;
-}
-
-static int dice_owner_set(struct dice *dice)
-{
- struct fw_device *device = fw_parent_device(dice->unit);
- __be64 *buffer;
- int err, errors = 0;
-
- buffer = kmalloc(2 * 8, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- for (;;) {
- buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
- buffer[1] = cpu_to_be64(
- ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
- dice->notification_handler.offset);
-
- dice->owner_generation = device->generation;
- smp_rmb(); /* node_id vs. generation */
- err = snd_fw_transaction(dice->unit,
- TCODE_LOCK_COMPARE_SWAP,
- global_address(dice, GLOBAL_OWNER),
- buffer, 2 * 8,
- FW_FIXED_GENERATION |
- dice->owner_generation);
-
- if (err == 0) {
- if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
- dev_err(&dice->unit->device,
- "device is already in use\n");
- err = -EBUSY;
- }
- break;
- }
- if (err != -EAGAIN || ++errors >= 3)
- break;
-
- msleep(20);
- }
-
- kfree(buffer);
-
- return err;
-}
-
-static int dice_owner_update(struct dice *dice)
-{
- struct fw_device *device = fw_parent_device(dice->unit);
- __be64 *buffer;
- int err;
-
- if (dice->owner_generation == -1)
- return 0;
-
- buffer = kmalloc(2 * 8, GFP_KERNEL);
- if (!buffer)
- return -ENOMEM;
-
- buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
- buffer[1] = cpu_to_be64(
- ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
- dice->notification_handler.offset);
-
- dice->owner_generation = device->generation;
- smp_rmb(); /* node_id vs. generation */
- err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
- global_address(dice, GLOBAL_OWNER),
- buffer, 2 * 8,
- FW_FIXED_GENERATION | dice->owner_generation);
-
- if (err == 0) {
- if (buffer[0] != cpu_to_be64(OWNER_NO_OWNER)) {
- dev_err(&dice->unit->device,
- "device is already in use\n");
- err = -EBUSY;
- }
- } else if (err == -EAGAIN) {
- err = 0; /* try again later */
- }
-
- kfree(buffer);
-
- if (err < 0)
- dice->owner_generation = -1;
-
- return err;
-}
-
-static void dice_owner_clear(struct dice *dice)
-{
- struct fw_device *device = fw_parent_device(dice->unit);
- __be64 *buffer;
-
- buffer = kmalloc(2 * 8, GFP_KERNEL);
- if (!buffer)
- return;
-
- buffer[0] = cpu_to_be64(
- ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
- dice->notification_handler.offset);
- buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
- snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
- global_address(dice, GLOBAL_OWNER),
- buffer, 2 * 8, FW_QUIET |
- FW_FIXED_GENERATION | dice->owner_generation);
-
- kfree(buffer);
-
- dice->owner_generation = -1;
-}
-
-static int dice_enable_set(struct dice *dice)
-{
- __be32 value;
- int err;
-
- value = cpu_to_be32(1);
- err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_ENABLE),
- &value, 4,
- FW_FIXED_GENERATION | dice->owner_generation);
- if (err < 0)
- return err;
-
- dice->global_enabled = true;
-
- return 0;
-}
-
-static void dice_enable_clear(struct dice *dice)
-{
- __be32 value;
-
- if (!dice->global_enabled)
- return;
-
- value = 0;
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_ENABLE),
- &value, 4, FW_QUIET |
- FW_FIXED_GENERATION | dice->owner_generation);
-
- dice->global_enabled = false;
-}
-
-static void dice_notification(struct fw_card *card, struct fw_request *request,
- int tcode, int destination, int source,
- int generation, unsigned long long offset,
- void *data, size_t length, void *callback_data)
-{
- struct dice *dice = callback_data;
- u32 bits;
- unsigned long flags;
-
- if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
- fw_send_response(card, request, RCODE_TYPE_ERROR);
- return;
- }
- if ((offset & 3) != 0) {
- fw_send_response(card, request, RCODE_ADDRESS_ERROR);
- return;
- }
-
- bits = be32_to_cpup(data);
-
- spin_lock_irqsave(&dice->lock, flags);
- dice->notification_bits |= bits;
- spin_unlock_irqrestore(&dice->lock, flags);
-
- fw_send_response(card, request, RCODE_COMPLETE);
-
- if (bits & NOTIFY_CLOCK_ACCEPTED)
- complete(&dice->clock_accepted);
- wake_up(&dice->hwdep_wait);
-}
-
-static int dice_rate_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- struct dice *dice = rule->private;
- const struct snd_interval *channels =
- hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval allowed_rates = {
- .min = UINT_MAX, .max = 0, .integer = 1
- };
- unsigned int i, mode;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i) {
- mode = rate_index_to_mode(i);
- if ((dice->clock_caps & (1 << i)) &&
- snd_interval_test(channels, dice->rx_channels[mode])) {
- allowed_rates.min = min(allowed_rates.min,
- dice_rates[i]);
- allowed_rates.max = max(allowed_rates.max,
- dice_rates[i]);
- }
- }
-
- return snd_interval_refine(rate, &allowed_rates);
-}
-
-static int dice_channels_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- struct dice *dice = rule->private;
- const struct snd_interval *rate =
- hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_interval allowed_channels = {
- .min = UINT_MAX, .max = 0, .integer = 1
- };
- unsigned int i, mode;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
- if ((dice->clock_caps & (1 << i)) &&
- snd_interval_test(rate, dice_rates[i])) {
- mode = rate_index_to_mode(i);
- allowed_channels.min = min(allowed_channels.min,
- dice->rx_channels[mode]);
- allowed_channels.max = max(allowed_channels.max,
- dice->rx_channels[mode]);
- }
-
- return snd_interval_refine(channels, &allowed_channels);
-}
-
-static int dice_open(struct snd_pcm_substream *substream)
-{
- static const struct snd_pcm_hardware hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = AMDTP_OUT_PCM_FORMAT_BITS,
- .channels_min = UINT_MAX,
- .channels_max = 0,
- .buffer_bytes_max = 16 * 1024 * 1024,
- .period_bytes_min = 1,
- .period_bytes_max = UINT_MAX,
- .periods_min = 1,
- .periods_max = UINT_MAX,
- };
- struct dice *dice = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
- unsigned int i;
- int err;
-
- err = dice_try_lock(dice);
- if (err < 0)
- goto error;
-
- runtime->hw = hardware;
-
- for (i = 0; i < ARRAY_SIZE(dice_rates); ++i)
- if (dice->clock_caps & (1 << i))
- runtime->hw.rates |=
- snd_pcm_rate_to_rate_bit(dice_rates[i]);
- snd_pcm_limit_hw_rates(runtime);
-
- for (i = 0; i < 3; ++i)
- if (dice->rx_channels[i]) {
- runtime->hw.channels_min = min(runtime->hw.channels_min,
- dice->rx_channels[i]);
- runtime->hw.channels_max = max(runtime->hw.channels_max,
- dice->rx_channels[i]);
- }
-
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- dice_rate_constraint, dice,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- if (err < 0)
- goto err_lock;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- dice_channels_constraint, dice,
- SNDRV_PCM_HW_PARAM_RATE, -1);
- if (err < 0)
- goto err_lock;
-
- err = amdtp_stream_add_pcm_hw_constraints(&dice->stream, runtime);
- if (err < 0)
- goto err_lock;
-
- return 0;
-
-err_lock:
- dice_unlock(dice);
-error:
- return err;
-}
-
-static int dice_close(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
-
- dice_unlock(dice);
-
- return 0;
-}
-
-static int dice_stream_start_packets(struct dice *dice)
-{
- int err;
-
- if (amdtp_stream_running(&dice->stream))
- return 0;
-
- err = amdtp_stream_start(&dice->stream, dice->resources.channel,
- fw_parent_device(dice->unit)->max_speed);
- if (err < 0)
- return err;
-
- err = dice_enable_set(dice);
- if (err < 0) {
- amdtp_stream_stop(&dice->stream);
- return err;
- }
-
- return 0;
-}
-
-static int dice_stream_start(struct dice *dice)
-{
- __be32 channel;
- int err;
-
- if (!dice->resources.allocated) {
- err = fw_iso_resources_allocate(&dice->resources,
- amdtp_stream_get_max_payload(&dice->stream),
- fw_parent_device(dice->unit)->max_speed);
- if (err < 0)
- goto error;
-
- channel = cpu_to_be32(dice->resources.channel);
- err = snd_fw_transaction(dice->unit,
- TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS),
- &channel, 4, 0);
- if (err < 0)
- goto err_resources;
- }
-
- err = dice_stream_start_packets(dice);
- if (err < 0)
- goto err_rx_channel;
-
- return 0;
-
-err_rx_channel:
- channel = cpu_to_be32((u32)-1);
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
-err_resources:
- fw_iso_resources_free(&dice->resources);
-error:
- return err;
-}
-
-static void dice_stream_stop_packets(struct dice *dice)
-{
- if (amdtp_stream_running(&dice->stream)) {
- dice_enable_clear(dice);
- amdtp_stream_stop(&dice->stream);
- }
-}
-
-static void dice_stream_stop(struct dice *dice)
-{
- __be32 channel;
-
- dice_stream_stop_packets(dice);
-
- if (!dice->resources.allocated)
- return;
-
- channel = cpu_to_be32((u32)-1);
- snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- rx_address(dice, RX_ISOCHRONOUS), &channel, 4, 0);
-
- fw_iso_resources_free(&dice->resources);
-}
-
-static int dice_change_rate(struct dice *dice, unsigned int clock_rate)
-{
- __be32 value;
- int err;
-
- reinit_completion(&dice->clock_accepted);
-
- value = cpu_to_be32(clock_rate | CLOCK_SOURCE_ARX1);
- err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_SELECT),
- &value, 4, 0);
- if (err < 0)
- return err;
-
- if (!wait_for_completion_timeout(&dice->clock_accepted,
- msecs_to_jiffies(100)))
- dev_warn(&dice->unit->device, "clock change timed out\n");
-
- return 0;
-}
-
-static int dice_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct dice *dice = substream->private_data;
- unsigned int rate_index, mode, rate, channels, i;
- int err;
-
- mutex_lock(&dice->mutex);
- dice_stream_stop(dice);
- mutex_unlock(&dice->mutex);
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- return err;
-
- rate = params_rate(hw_params);
- rate_index = rate_to_index(rate);
- err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
- if (err < 0)
- return err;
-
- /*
- * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
- * one data block of AMDTP packet. Thus sampling transfer frequency is
- * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
- * transferred on AMDTP packets at 96 kHz. Two successive samples of a
- * channel are stored consecutively in the packet. This quirk is called
- * as 'Dual Wire'.
- * For this quirk, blocking mode is required and PCM buffer size should
- * be aligned to SYT_INTERVAL.
- */
- channels = params_channels(hw_params);
- if (rate_index > 4) {
- if (channels > AMDTP_MAX_CHANNELS_FOR_PCM / 2) {
- err = -ENOSYS;
- return err;
- }
-
- rate /= 2;
- channels *= 2;
- dice->stream.double_pcm_frames = true;
- } else {
- dice->stream.double_pcm_frames = false;
- }
-
- mode = rate_index_to_mode(rate_index);
- amdtp_stream_set_parameters(&dice->stream, rate, channels,
- dice->rx_midi_ports[mode]);
- if (rate_index > 4) {
- channels /= 2;
-
- for (i = 0; i < channels; i++) {
- dice->stream.pcm_positions[i] = i * 2;
- dice->stream.pcm_positions[i + channels] = i * 2 + 1;
- }
- }
-
- amdtp_stream_set_pcm_format(&dice->stream,
- params_format(hw_params));
-
- return 0;
-}
-
-static int dice_hw_free(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
-
- mutex_lock(&dice->mutex);
- dice_stream_stop(dice);
- mutex_unlock(&dice->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int dice_prepare(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
- int err;
-
- mutex_lock(&dice->mutex);
-
- if (amdtp_streaming_error(&dice->stream))
- dice_stream_stop_packets(dice);
-
- err = dice_stream_start(dice);
- if (err < 0) {
- mutex_unlock(&dice->mutex);
- return err;
- }
-
- mutex_unlock(&dice->mutex);
-
- amdtp_stream_pcm_prepare(&dice->stream);
-
- return 0;
-}
-
-static int dice_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct dice *dice = substream->private_data;
- struct snd_pcm_substream *pcm;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- pcm = substream;
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- pcm = NULL;
- break;
- default:
- return -EINVAL;
- }
- amdtp_stream_pcm_trigger(&dice->stream, pcm);
-
- return 0;
-}
-
-static snd_pcm_uframes_t dice_pointer(struct snd_pcm_substream *substream)
-{
- struct dice *dice = substream->private_data;
-
- return amdtp_stream_pcm_pointer(&dice->stream);
-}
-
-static int dice_create_pcm(struct dice *dice)
-{
- static struct snd_pcm_ops ops = {
- .open = dice_open,
- .close = dice_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = dice_hw_params,
- .hw_free = dice_hw_free,
- .prepare = dice_prepare,
- .trigger = dice_trigger,
- .pointer = dice_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
- };
- struct snd_pcm *pcm;
- int err;
-
- err = snd_pcm_new(dice->card, "DICE", 0, 1, 0, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = dice;
- strcpy(pcm->name, dice->card->shortname);
- pcm->streams[SNDRV_PCM_STREAM_PLAYBACK].substream->ops = &ops;
-
- return 0;
-}
-
-static long dice_hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
- long count, loff_t *offset)
-{
- struct dice *dice = hwdep->private_data;
- DEFINE_WAIT(wait);
- union snd_firewire_event event;
-
- spin_lock_irq(&dice->lock);
-
- while (!dice->dev_lock_changed && dice->notification_bits == 0) {
- prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
- spin_unlock_irq(&dice->lock);
- schedule();
- finish_wait(&dice->hwdep_wait, &wait);
- if (signal_pending(current))
- return -ERESTARTSYS;
- spin_lock_irq(&dice->lock);
- }
-
- memset(&event, 0, sizeof(event));
- if (dice->dev_lock_changed) {
- event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
- event.lock_status.status = dice->dev_lock_count > 0;
- dice->dev_lock_changed = false;
-
- count = min(count, (long)sizeof(event.lock_status));
- } else {
- event.dice_notification.type = SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
- event.dice_notification.notification = dice->notification_bits;
- dice->notification_bits = 0;
-
- count = min(count, (long)sizeof(event.dice_notification));
- }
-
- spin_unlock_irq(&dice->lock);
-
- if (copy_to_user(buf, &event, count))
- return -EFAULT;
-
- return count;
-}
-
-static unsigned int dice_hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
- poll_table *wait)
-{
- struct dice *dice = hwdep->private_data;
- unsigned int events;
-
- poll_wait(file, &dice->hwdep_wait, wait);
-
- spin_lock_irq(&dice->lock);
- if (dice->dev_lock_changed || dice->notification_bits != 0)
- events = POLLIN | POLLRDNORM;
- else
- events = 0;
- spin_unlock_irq(&dice->lock);
-
- return events;
-}
-
-static int dice_hwdep_get_info(struct dice *dice, void __user *arg)
-{
- struct fw_device *dev = fw_parent_device(dice->unit);
- struct snd_firewire_get_info info;
-
- memset(&info, 0, sizeof(info));
- info.type = SNDRV_FIREWIRE_TYPE_DICE;
- info.card = dev->card->index;
- *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
- *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
- strlcpy(info.device_name, dev_name(&dev->device),
- sizeof(info.device_name));
-
- if (copy_to_user(arg, &info, sizeof(info)))
- return -EFAULT;
-
- return 0;
-}
-
-static int dice_hwdep_lock(struct dice *dice)
-{
- int err;
-
- spin_lock_irq(&dice->lock);
-
- if (dice->dev_lock_count == 0) {
- dice->dev_lock_count = -1;
- err = 0;
- } else {
- err = -EBUSY;
- }
-
- spin_unlock_irq(&dice->lock);
-
- return err;
-}
-
-static int dice_hwdep_unlock(struct dice *dice)
-{
- int err;
-
- spin_lock_irq(&dice->lock);
-
- if (dice->dev_lock_count == -1) {
- dice->dev_lock_count = 0;
- err = 0;
- } else {
- err = -EBADFD;
- }
-
- spin_unlock_irq(&dice->lock);
-
- return err;
-}
-
-static int dice_hwdep_release(struct snd_hwdep *hwdep, struct file *file)
-{
- struct dice *dice = hwdep->private_data;
-
- spin_lock_irq(&dice->lock);
- if (dice->dev_lock_count == -1)
- dice->dev_lock_count = 0;
- spin_unlock_irq(&dice->lock);
-
- return 0;
-}
-
-static int dice_hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct dice *dice = hwdep->private_data;
-
- switch (cmd) {
- case SNDRV_FIREWIRE_IOCTL_GET_INFO:
- return dice_hwdep_get_info(dice, (void __user *)arg);
- case SNDRV_FIREWIRE_IOCTL_LOCK:
- return dice_hwdep_lock(dice);
- case SNDRV_FIREWIRE_IOCTL_UNLOCK:
- return dice_hwdep_unlock(dice);
- default:
- return -ENOIOCTLCMD;
- }
-}
-
-#ifdef CONFIG_COMPAT
-static int dice_hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return dice_hwdep_ioctl(hwdep, file, cmd,
- (unsigned long)compat_ptr(arg));
-}
-#else
-#define dice_hwdep_compat_ioctl NULL
-#endif
-
-static int dice_create_hwdep(struct dice *dice)
-{
- static const struct snd_hwdep_ops ops = {
- .read = dice_hwdep_read,
- .release = dice_hwdep_release,
- .poll = dice_hwdep_poll,
- .ioctl = dice_hwdep_ioctl,
- .ioctl_compat = dice_hwdep_compat_ioctl,
- };
- struct snd_hwdep *hwdep;
- int err;
-
- err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
- if (err < 0)
- return err;
- strcpy(hwdep->name, "DICE");
- hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
- hwdep->ops = ops;
- hwdep->private_data = dice;
- hwdep->exclusive = true;
-
- return 0;
-}
-
-static int dice_proc_read_mem(struct dice *dice, void *buffer,
- unsigned int offset_q, unsigned int quadlets)
-{
- unsigned int i;
- int err;
-
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE + 4 * offset_q,
- buffer, 4 * quadlets, 0);
- if (err < 0)
- return err;
-
- for (i = 0; i < quadlets; ++i)
- be32_to_cpus(&((u32 *)buffer)[i]);
-
- return 0;
-}
-
-static const char *str_from_array(const char *const strs[], unsigned int count,
- unsigned int i)
-{
- if (i < count)
- return strs[i];
- else
- return "(unknown)";
-}
-
-static void dice_proc_fixup_string(char *s, unsigned int size)
-{
- unsigned int i;
-
- for (i = 0; i < size; i += 4)
- cpu_to_le32s((u32 *)(s + i));
-
- for (i = 0; i < size - 2; ++i) {
- if (s[i] == '\0')
- return;
- if (s[i] == '\\' && s[i + 1] == '\\') {
- s[i + 2] = '\0';
- return;
- }
- }
- s[size - 1] = '\0';
-}
-
-static void dice_proc_read(struct snd_info_entry *entry,
- struct snd_info_buffer *buffer)
-{
- static const char *const section_names[5] = {
- "global", "tx", "rx", "ext_sync", "unused2"
- };
- static const char *const clock_sources[] = {
- "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
- "wc", "arx1", "arx2", "arx3", "arx4", "internal"
- };
- static const char *const rates[] = {
- "32000", "44100", "48000", "88200", "96000", "176400", "192000",
- "any low", "any mid", "any high", "none"
- };
- struct dice *dice = entry->private_data;
- u32 sections[ARRAY_SIZE(section_names) * 2];
- struct {
- u32 number;
- u32 size;
- } tx_rx_header;
- union {
- struct {
- u32 owner_hi, owner_lo;
- u32 notification;
- char nick_name[NICK_NAME_SIZE];
- u32 clock_select;
- u32 enable;
- u32 status;
- u32 extended_status;
- u32 sample_rate;
- u32 version;
- u32 clock_caps;
- char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
- } global;
- struct {
- u32 iso;
- u32 number_audio;
- u32 number_midi;
- u32 speed;
- char names[TX_NAMES_SIZE];
- u32 ac3_caps;
- u32 ac3_enable;
- } tx;
- struct {
- u32 iso;
- u32 seq_start;
- u32 number_audio;
- u32 number_midi;
- char names[RX_NAMES_SIZE];
- u32 ac3_caps;
- u32 ac3_enable;
- } rx;
- struct {
- u32 clock_source;
- u32 locked;
- u32 rate;
- u32 adat_user_data;
- } ext_sync;
- } buf;
- unsigned int quadlets, stream, i;
-
- if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
- return;
- snd_iprintf(buffer, "sections:\n");
- for (i = 0; i < ARRAY_SIZE(section_names); ++i)
- snd_iprintf(buffer, " %s: offset %u, size %u\n",
- section_names[i],
- sections[i * 2], sections[i * 2 + 1]);
-
- quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
- if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
- return;
- snd_iprintf(buffer, "global:\n");
- snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
- buf.global.owner_hi >> 16,
- buf.global.owner_hi & 0xffff, buf.global.owner_lo);
- snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
- dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
- snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
- snd_iprintf(buffer, " clock select: %s %s\n",
- str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
- buf.global.clock_select & CLOCK_SOURCE_MASK),
- str_from_array(rates, ARRAY_SIZE(rates),
- (buf.global.clock_select & CLOCK_RATE_MASK)
- >> CLOCK_RATE_SHIFT));
- snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
- snd_iprintf(buffer, " status: %slocked %s\n",
- buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
- str_from_array(rates, ARRAY_SIZE(rates),
- (buf.global.status &
- STATUS_NOMINAL_RATE_MASK)
- >> CLOCK_RATE_SHIFT));
- snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
- snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
- snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
- (buf.global.version >> 24) & 0xff,
- (buf.global.version >> 16) & 0xff,
- (buf.global.version >> 8) & 0xff,
- (buf.global.version >> 0) & 0xff);
- if (quadlets >= 90) {
- snd_iprintf(buffer, " clock caps:");
- for (i = 0; i <= 6; ++i)
- if (buf.global.clock_caps & (1 << i))
- snd_iprintf(buffer, " %s", rates[i]);
- for (i = 0; i <= 12; ++i)
- if (buf.global.clock_caps & (1 << (16 + i)))
- snd_iprintf(buffer, " %s", clock_sources[i]);
- snd_iprintf(buffer, "\n");
- dice_proc_fixup_string(buf.global.clock_source_names,
- CLOCK_SOURCE_NAMES_SIZE);
- snd_iprintf(buffer, " clock source names: %s\n",
- buf.global.clock_source_names);
- }
-
- if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
- return;
- quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
- for (stream = 0; stream < tx_rx_header.number; ++stream) {
- if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
- stream * tx_rx_header.size,
- quadlets) < 0)
- break;
- snd_iprintf(buffer, "tx %u:\n", stream);
- snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
- snd_iprintf(buffer, " audio channels: %u\n",
- buf.tx.number_audio);
- snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
- snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
- if (quadlets >= 68) {
- dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
- snd_iprintf(buffer, " names: %s\n", buf.tx.names);
- }
- if (quadlets >= 70) {
- snd_iprintf(buffer, " ac3 caps: %08x\n",
- buf.tx.ac3_caps);
- snd_iprintf(buffer, " ac3 enable: %08x\n",
- buf.tx.ac3_enable);
- }
- }
-
- if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
- return;
- quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
- for (stream = 0; stream < tx_rx_header.number; ++stream) {
- if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
- stream * tx_rx_header.size,
- quadlets) < 0)
- break;
- snd_iprintf(buffer, "rx %u:\n", stream);
- snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
- snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start);
- snd_iprintf(buffer, " audio channels: %u\n",
- buf.rx.number_audio);
- snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
- if (quadlets >= 68) {
- dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
- snd_iprintf(buffer, " names: %s\n", buf.rx.names);
- }
- if (quadlets >= 70) {
- snd_iprintf(buffer, " ac3 caps: %08x\n",
- buf.rx.ac3_caps);
- snd_iprintf(buffer, " ac3 enable: %08x\n",
- buf.rx.ac3_enable);
- }
- }
-
- quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
- if (quadlets >= 4) {
- if (dice_proc_read_mem(dice, &buf.ext_sync,
- sections[6], 4) < 0)
- return;
- snd_iprintf(buffer, "ext status:\n");
- snd_iprintf(buffer, " clock source: %s\n",
- str_from_array(clock_sources,
- ARRAY_SIZE(clock_sources),
- buf.ext_sync.clock_source));
- snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
- snd_iprintf(buffer, " rate: %s\n",
- str_from_array(rates, ARRAY_SIZE(rates),
- buf.ext_sync.rate));
- snd_iprintf(buffer, " adat user data: ");
- if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
- snd_iprintf(buffer, "-\n");
- else
- snd_iprintf(buffer, "%x\n",
- buf.ext_sync.adat_user_data);
- }
-}
-
-static void dice_create_proc(struct dice *dice)
-{
- struct snd_info_entry *entry;
-
- if (!snd_card_proc_new(dice->card, "dice", &entry))
- snd_info_set_text_ops(entry, dice, dice_proc_read);
-}
-
-static void dice_card_free(struct snd_card *card)
-{
- struct dice *dice = card->private_data;
-
- amdtp_stream_destroy(&dice->stream);
- fw_core_remove_address_handler(&dice->notification_handler);
- mutex_destroy(&dice->mutex);
-}
-
-#define OUI_WEISS 0x001c6a
-
-#define DICE_CATEGORY_ID 0x04
-#define WEISS_CATEGORY_ID 0x00
-
-static int dice_interface_check(struct fw_unit *unit)
-{
- static const int min_values[10] = {
- 10, 0x64 / 4,
- 10, 0x18 / 4,
- 10, 0x18 / 4,
- 0, 0,
- 0, 0,
- };
- struct fw_device *device = fw_parent_device(unit);
- struct fw_csr_iterator it;
- int key, value, vendor = -1, model = -1, err;
- unsigned int category, i;
- __be32 pointers[ARRAY_SIZE(min_values)];
- __be32 tx_data[4];
- __be32 version;
-
- /*
- * Check that GUID and unit directory are constructed according to DICE
- * rules, i.e., that the specifier ID is the GUID's OUI, and that the
- * GUID chip ID consists of the 8-bit category ID, the 10-bit product
- * ID, and a 22-bit serial number.
- */
- fw_csr_iterator_init(&it, unit->directory);
- while (fw_csr_iterator_next(&it, &key, &value)) {
- switch (key) {
- case CSR_SPECIFIER_ID:
- vendor = value;
- break;
- case CSR_MODEL:
- model = value;
- break;
- }
- }
- if (vendor == OUI_WEISS)
- category = WEISS_CATEGORY_ID;
- else
- category = DICE_CATEGORY_ID;
- if (device->config_rom[3] != ((vendor << 8) | category) ||
- device->config_rom[4] >> 22 != model)
- return -ENODEV;
-
- /*
- * Check that the sub address spaces exist and are located inside the
- * private address space. The minimum values are chosen so that all
- * minimally required registers are included.
- */
- err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE,
- pointers, sizeof(pointers), 0);
- if (err < 0)
- return -ENODEV;
- for (i = 0; i < ARRAY_SIZE(pointers); ++i) {
- value = be32_to_cpu(pointers[i]);
- if (value < min_values[i] || value >= 0x40000)
- return -ENODEV;
- }
-
- /* We support playback only. Let capture devices be handled by FFADO. */
- err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE +
- be32_to_cpu(pointers[2]) * 4,
- tx_data, sizeof(tx_data), 0);
- if (err < 0 || (tx_data[0] && tx_data[3]))
- return -ENODEV;
-
- /*
- * Check that the implemented DICE driver specification major version
- * number matches.
- */
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- DICE_PRIVATE_SPACE +
- be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
- &version, 4, 0);
- if (err < 0)
- return -ENODEV;
- if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
- dev_err(&unit->device,
- "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
- return -ENODEV;
- }
-
- return 0;
-}
-
-static int highest_supported_mode_rate(struct dice *dice, unsigned int mode)
-{
- int i;
-
- for (i = ARRAY_SIZE(dice_rates) - 1; i >= 0; --i)
- if ((dice->clock_caps & (1 << i)) &&
- rate_index_to_mode(i) == mode)
- return i;
-
- return -1;
-}
-
-static int dice_read_mode_params(struct dice *dice, unsigned int mode)
-{
- __be32 values[2];
- int rate_index, err;
-
- rate_index = highest_supported_mode_rate(dice, mode);
- if (rate_index < 0) {
- dice->rx_channels[mode] = 0;
- dice->rx_midi_ports[mode] = 0;
- return 0;
- }
-
- err = dice_change_rate(dice, rate_index << CLOCK_RATE_SHIFT);
- if (err < 0)
- return err;
-
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- rx_address(dice, RX_NUMBER_AUDIO),
- values, 2 * 4, 0);
- if (err < 0)
- return err;
-
- dice->rx_channels[mode] = be32_to_cpu(values[0]);
- dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
-
- return 0;
-}
-
-static int dice_read_params(struct dice *dice)
-{
- __be32 pointers[6];
- __be32 value;
- int mode, err;
-
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- DICE_PRIVATE_SPACE,
- pointers, sizeof(pointers), 0);
- if (err < 0)
- return err;
-
- dice->global_offset = be32_to_cpu(pointers[0]) * 4;
- dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
-
- /* some very old firmwares don't tell about their clock support */
- if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) {
- err = snd_fw_transaction(
- dice->unit, TCODE_READ_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_CAPABILITIES),
- &value, 4, 0);
- if (err < 0)
- return err;
- dice->clock_caps = be32_to_cpu(value);
- } else {
- /* this should be supported by any device */
- dice->clock_caps = CLOCK_CAP_RATE_44100 |
- CLOCK_CAP_RATE_48000 |
- CLOCK_CAP_SOURCE_ARX1 |
- CLOCK_CAP_SOURCE_INTERNAL;
- }
-
- for (mode = 2; mode >= 0; --mode) {
- err = dice_read_mode_params(dice, mode);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static void dice_card_strings(struct dice *dice)
-{
- struct snd_card *card = dice->card;
- struct fw_device *dev = fw_parent_device(dice->unit);
- char vendor[32], model[32];
- unsigned int i;
- int err;
-
- strcpy(card->driver, "DICE");
-
- strcpy(card->shortname, "DICE");
- BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
- err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
- global_address(dice, GLOBAL_NICK_NAME),
- card->shortname, sizeof(card->shortname), 0);
- if (err >= 0) {
- /* DICE strings are returned in "always-wrong" endianness */
- BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
- for (i = 0; i < sizeof(card->shortname); i += 4)
- swab32s((u32 *)&card->shortname[i]);
- card->shortname[sizeof(card->shortname) - 1] = '\0';
- }
-
- strcpy(vendor, "?");
- fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
- strcpy(model, "?");
- fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
- snprintf(card->longname, sizeof(card->longname),
- "%s %s (serial %u) at %s, S%d",
- vendor, model, dev->config_rom[4] & 0x3fffff,
- dev_name(&dice->unit->device), 100 << dev->max_speed);
-
- strcpy(card->mixername, "DICE");
-}
-
-static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
-{
- struct snd_card *card;
- struct dice *dice;
- __be32 clock_sel;
- int err;
-
- err = dice_interface_check(unit);
- if (err < 0)
- return err;
-
- err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
- sizeof(*dice), &card);
- if (err < 0)
- return err;
-
- dice = card->private_data;
- dice->card = card;
- spin_lock_init(&dice->lock);
- mutex_init(&dice->mutex);
- dice->unit = unit;
- init_completion(&dice->clock_accepted);
- init_waitqueue_head(&dice->hwdep_wait);
-
- dice->notification_handler.length = 4;
- dice->notification_handler.address_callback = dice_notification;
- dice->notification_handler.callback_data = dice;
- err = fw_core_add_address_handler(&dice->notification_handler,
- &fw_high_memory_region);
- if (err < 0)
- goto err_mutex;
-
- err = dice_owner_set(dice);
- if (err < 0)
- goto err_notification_handler;
-
- err = dice_read_params(dice);
- if (err < 0)
- goto err_owner;
-
- err = fw_iso_resources_init(&dice->resources, unit);
- if (err < 0)
- goto err_owner;
- dice->resources.channels_mask = 0x00000000ffffffffuLL;
-
- err = amdtp_stream_init(&dice->stream, unit, AMDTP_OUT_STREAM,
- CIP_BLOCKING);
- if (err < 0)
- goto err_resources;
-
- card->private_free = dice_card_free;
-
- dice_card_strings(dice);
-
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_SELECT),
- &clock_sel, 4, 0);
- if (err < 0)
- goto error;
- clock_sel &= cpu_to_be32(~CLOCK_SOURCE_MASK);
- clock_sel |= cpu_to_be32(CLOCK_SOURCE_ARX1);
- err = snd_fw_transaction(unit, TCODE_WRITE_QUADLET_REQUEST,
- global_address(dice, GLOBAL_CLOCK_SELECT),
- &clock_sel, 4, 0);
- if (err < 0)
- goto error;
-
- err = dice_create_pcm(dice);
- if (err < 0)
- goto error;
-
- err = dice_create_hwdep(dice);
- if (err < 0)
- goto error;
-
- dice_create_proc(dice);
-
- err = snd_card_register(card);
- if (err < 0)
- goto error;
-
- dev_set_drvdata(&unit->device, dice);
-
- return 0;
-
-err_resources:
- fw_iso_resources_destroy(&dice->resources);
-err_owner:
- dice_owner_clear(dice);
-err_notification_handler:
- fw_core_remove_address_handler(&dice->notification_handler);
-err_mutex:
- mutex_destroy(&dice->mutex);
-error:
- snd_card_free(card);
- return err;
-}
-
-static void dice_remove(struct fw_unit *unit)
-{
- struct dice *dice = dev_get_drvdata(&unit->device);
-
- amdtp_stream_pcm_abort(&dice->stream);
-
- snd_card_disconnect(dice->card);
-
- mutex_lock(&dice->mutex);
-
- dice_stream_stop(dice);
- dice_owner_clear(dice);
-
- mutex_unlock(&dice->mutex);
-
- snd_card_free_when_closed(dice->card);
-}
-
-static void dice_bus_reset(struct fw_unit *unit)
-{
- struct dice *dice = dev_get_drvdata(&unit->device);
-
- /*
- * On a bus reset, the DICE firmware disables streaming and then goes
- * off contemplating its own navel for hundreds of milliseconds before
- * it can react to any of our attempts to reenable streaming. This
- * means that we lose synchronization anyway, so we force our streams
- * to stop so that the application can restart them in an orderly
- * manner.
- */
- amdtp_stream_pcm_abort(&dice->stream);
-
- mutex_lock(&dice->mutex);
-
- dice->global_enabled = false;
- dice_stream_stop_packets(dice);
-
- dice_owner_update(dice);
-
- fw_iso_resources_update(&dice->resources);
-
- mutex_unlock(&dice->mutex);
-}
-
-#define DICE_INTERFACE 0x000001
-
-static const struct ieee1394_device_id dice_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_VERSION,
- .version = DICE_INTERFACE,
- },
- { }
-};
-MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
-
-static struct fw_driver dice_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = KBUILD_MODNAME,
- .bus = &fw_bus_type,
- },
- .probe = dice_probe,
- .update = dice_bus_reset,
- .remove = dice_remove,
- .id_table = dice_id_table,
-};
-
-static int __init alsa_dice_init(void)
-{
- return driver_register(&dice_driver.driver);
-}
-
-static void __exit alsa_dice_exit(void)
-{
- driver_unregister(&dice_driver.driver);
-}
-
-module_init(alsa_dice_init);
-module_exit(alsa_dice_exit);
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile
new file mode 100644
index 0000000..9ef228e
--- /dev/null
+++ b/sound/firewire/dice/Makefile
@@ -0,0 +1,3 @@
+snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \
+ dice-pcm.o dice-hwdep.o dice.o
+obj-m += snd-dice.o
diff --git a/sound/firewire/dice/dice-hwdep.c b/sound/firewire/dice/dice-hwdep.c
new file mode 100644
index 0000000..a4dc02a
--- /dev/null
+++ b/sound/firewire/dice/dice-hwdep.c
@@ -0,0 +1,190 @@
+/*
+ * dice_hwdep.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf,
+ long count, loff_t *offset)
+{
+ struct snd_dice *dice = hwdep->private_data;
+ DEFINE_WAIT(wait);
+ union snd_firewire_event event;
+
+ spin_lock_irq(&dice->lock);
+
+ while (!dice->dev_lock_changed && dice->notification_bits == 0) {
+ prepare_to_wait(&dice->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&dice->lock);
+ schedule();
+ finish_wait(&dice->hwdep_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ spin_lock_irq(&dice->lock);
+ }
+
+ memset(&event, 0, sizeof(event));
+ if (dice->dev_lock_changed) {
+ event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+ event.lock_status.status = dice->dev_lock_count > 0;
+ dice->dev_lock_changed = false;
+
+ count = min_t(long, count, sizeof(event.lock_status));
+ } else {
+ event.dice_notification.type =
+ SNDRV_FIREWIRE_EVENT_DICE_NOTIFICATION;
+ event.dice_notification.notification = dice->notification_bits;
+ dice->notification_bits = 0;
+
+ count = min_t(long, count, sizeof(event.dice_notification));
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+ poll_table *wait)
+{
+ struct snd_dice *dice = hwdep->private_data;
+ unsigned int events;
+
+ poll_wait(file, &dice->hwdep_wait, wait);
+
+ spin_lock_irq(&dice->lock);
+ if (dice->dev_lock_changed || dice->notification_bits != 0)
+ events = POLLIN | POLLRDNORM;
+ else
+ events = 0;
+ spin_unlock_irq(&dice->lock);
+
+ return events;
+}
+
+static int hwdep_get_info(struct snd_dice *dice, void __user *arg)
+{
+ struct fw_device *dev = fw_parent_device(dice->unit);
+ struct snd_firewire_get_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.type = SNDRV_FIREWIRE_TYPE_DICE;
+ info.card = dev->card->index;
+ *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+ *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+ strlcpy(info.device_name, dev_name(&dev->device),
+ sizeof(info.device_name));
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int hwdep_lock(struct snd_dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count == 0) {
+ dice->dev_lock_count = -1;
+ err = 0;
+ } else {
+ err = -EBUSY;
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static int hwdep_unlock(struct snd_dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count == -1) {
+ dice->dev_lock_count = 0;
+ err = 0;
+ } else {
+ err = -EBADFD;
+ }
+
+ spin_unlock_irq(&dice->lock);
+
+ return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+ struct snd_dice *dice = hwdep->private_data;
+
+ spin_lock_irq(&dice->lock);
+ if (dice->dev_lock_count == -1)
+ dice->dev_lock_count = 0;
+ spin_unlock_irq(&dice->lock);
+
+ return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct snd_dice *dice = hwdep->private_data;
+
+ switch (cmd) {
+ case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+ return hwdep_get_info(dice, (void __user *)arg);
+ case SNDRV_FIREWIRE_IOCTL_LOCK:
+ return hwdep_lock(dice);
+ case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+ return hwdep_unlock(dice);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return hwdep_ioctl(hwdep, file, cmd,
+ (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+int snd_dice_create_hwdep(struct snd_dice *dice)
+{
+ static const struct snd_hwdep_ops ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
+ struct snd_hwdep *hwdep;
+ int err;
+
+ err = snd_hwdep_new(dice->card, "DICE", 0, &hwdep);
+ if (err < 0)
+ return err;
+ strcpy(hwdep->name, "DICE");
+ hwdep->iface = SNDRV_HWDEP_IFACE_FW_DICE;
+ hwdep->ops = ops;
+ hwdep->private_data = dice;
+ hwdep->exclusive = true;
+
+ return 0;
+}
diff --git a/sound/firewire/dice-interface.h b/sound/firewire/dice/dice-interface.h
index 27b044f..27b044f 100644
--- a/sound/firewire/dice-interface.h
+++ b/sound/firewire/dice/dice-interface.h
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c
new file mode 100644
index 0000000..fe43ce7
--- /dev/null
+++ b/sound/firewire/dice/dice-midi.c
@@ -0,0 +1,157 @@
+/*
+ * dice_midi.c - a part of driver for Dice based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+#include "dice.h"
+
+static int midi_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_dice *dice = substream->rmidi->private_data;
+ int err;
+
+ err = snd_dice_stream_lock_try(dice);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&dice->mutex);
+
+ dice->substreams_counter++;
+ err = snd_dice_stream_start_duplex(dice, 0);
+
+ mutex_unlock(&dice->mutex);
+
+ if (err < 0)
+ snd_dice_stream_lock_release(dice);
+
+ return err;
+}
+
+static int midi_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_dice *dice = substream->rmidi->private_data;
+
+ mutex_lock(&dice->mutex);
+
+ dice->substreams_counter--;
+ snd_dice_stream_stop_duplex(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ snd_dice_stream_lock_release(dice);
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_dice *dice = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dice->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&dice->tx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&dice->tx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&dice->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_dice *dice = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dice->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&dice->rx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&dice->rx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&dice->lock, flags);
+}
+
+static struct snd_rawmidi_ops capture_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_capture_trigger,
+};
+
+static struct snd_rawmidi_ops playback_ops = {
+ .open = midi_open,
+ .close = midi_close,
+ .trigger = midi_playback_trigger,
+};
+
+static void set_midi_substream_names(struct snd_dice *dice,
+ struct snd_rawmidi_str *str)
+{
+ struct snd_rawmidi_substream *subs;
+
+ list_for_each_entry(subs, &str->substreams, list) {
+ snprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d", dice->card->shortname, subs->number + 1);
+ }
+}
+
+int snd_dice_create_midi(struct snd_dice *dice)
+{
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_str *str;
+ unsigned int i, midi_in_ports, midi_out_ports;
+ int err;
+
+ midi_in_ports = midi_out_ports = 0;
+ for (i = 0; i < 3; i++) {
+ midi_in_ports = max(dice->tx_midi_ports[i], midi_in_ports);
+ midi_out_ports = max(dice->rx_midi_ports[i], midi_out_ports);
+ }
+
+ if (midi_in_ports + midi_out_ports == 0)
+ return 0;
+
+ /* create midi ports */
+ err = snd_rawmidi_new(dice->card, dice->card->driver, 0,
+ midi_out_ports, midi_in_ports,
+ &rmidi);
+ if (err < 0)
+ return err;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", dice->card->shortname);
+ rmidi->private_data = dice;
+
+ if (midi_in_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &capture_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+
+ set_midi_substream_names(dice, str);
+ }
+
+ if (midi_out_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &playback_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+
+ set_midi_substream_names(dice, str);
+ }
+
+ if ((midi_out_ports > 0) && (midi_in_ports > 0))
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c
new file mode 100644
index 0000000..f7771451
--- /dev/null
+++ b/sound/firewire/dice/dice-pcm.c
@@ -0,0 +1,422 @@
+/*
+ * dice_pcm.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+static int dice_rate_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_substream *substream = rule->private;
+ struct snd_dice *dice = substream->private_data;
+
+ const struct snd_interval *c =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval rates = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, rate, mode, *pcm_channels;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm_channels = dice->tx_channels;
+ else
+ pcm_channels = dice->rx_channels;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
+ rate = snd_dice_rates[i];
+ if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
+ continue;
+
+ if (!snd_interval_test(c, pcm_channels[mode]))
+ continue;
+
+ rates.min = min(rates.min, rate);
+ rates.max = max(rates.max, rate);
+ }
+
+ return snd_interval_refine(r, &rates);
+}
+
+static int dice_channels_constraint(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ struct snd_pcm_substream *substream = rule->private;
+ struct snd_dice *dice = substream->private_data;
+
+ const struct snd_interval *r =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval channels = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ unsigned int i, rate, mode, *pcm_channels;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ pcm_channels = dice->tx_channels;
+ else
+ pcm_channels = dice->rx_channels;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
+ rate = snd_dice_rates[i];
+ if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
+ continue;
+
+ if (!snd_interval_test(r, rate))
+ continue;
+
+ channels.min = min(channels.min, pcm_channels[mode]);
+ channels.max = max(channels.max, pcm_channels[mode]);
+ }
+
+ return snd_interval_refine(c, &channels);
+}
+
+static void limit_channels_and_rates(struct snd_dice *dice,
+ struct snd_pcm_runtime *runtime,
+ unsigned int *pcm_channels)
+{
+ struct snd_pcm_hardware *hw = &runtime->hw;
+ unsigned int i, rate, mode;
+
+ hw->channels_min = UINT_MAX;
+ hw->channels_max = 0;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) {
+ rate = snd_dice_rates[i];
+ if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0)
+ continue;
+ hw->rates |= snd_pcm_rate_to_rate_bit(rate);
+
+ if (pcm_channels[mode] == 0)
+ continue;
+ hw->channels_min = min(hw->channels_min, pcm_channels[mode]);
+ hw->channels_max = max(hw->channels_max, pcm_channels[mode]);
+ }
+
+ snd_pcm_limit_hw_rates(runtime);
+}
+
+static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
+{
+ hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */
+ hw->periods_max = UINT_MAX;
+
+ hw->period_bytes_min = 4 * hw->channels_max; /* byte for a frame */
+
+ /* Just to prevent from allocating much pages. */
+ hw->period_bytes_max = hw->period_bytes_min * 2048;
+ hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
+}
+
+static int init_hw_info(struct snd_dice *dice,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ struct snd_pcm_hardware *hw = &runtime->hw;
+ struct amdtp_stream *stream;
+ unsigned int *pcm_channels;
+ int err;
+
+ hw->info = SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID |
+ SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ hw->formats = AMDTP_IN_PCM_FORMAT_BITS;
+ stream = &dice->tx_stream;
+ pcm_channels = dice->tx_channels;
+ } else {
+ hw->formats = AMDTP_OUT_PCM_FORMAT_BITS;
+ stream = &dice->rx_stream;
+ pcm_channels = dice->rx_channels;
+ }
+
+ limit_channels_and_rates(dice, runtime, pcm_channels);
+ limit_period_and_buffer(hw);
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ dice_rate_constraint, substream,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto end;
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ dice_channels_constraint, substream,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+end:
+ return err;
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+ unsigned int source, rate;
+ bool internal;
+ int err;
+
+ err = snd_dice_stream_lock_try(dice);
+ if (err < 0)
+ goto end;
+
+ err = init_hw_info(dice, substream);
+ if (err < 0)
+ goto err_locked;
+
+ err = snd_dice_transaction_get_clock_source(dice, &source);
+ if (err < 0)
+ goto err_locked;
+ switch (source) {
+ case CLOCK_SOURCE_AES1:
+ case CLOCK_SOURCE_AES2:
+ case CLOCK_SOURCE_AES3:
+ case CLOCK_SOURCE_AES4:
+ case CLOCK_SOURCE_AES_ANY:
+ case CLOCK_SOURCE_ADAT:
+ case CLOCK_SOURCE_TDIF:
+ case CLOCK_SOURCE_WC:
+ internal = false;
+ break;
+ default:
+ internal = true;
+ break;
+ }
+
+ /*
+ * When source of clock is not internal or any PCM streams are running,
+ * available sampling rate is limited at current sampling rate.
+ */
+ if (!internal ||
+ amdtp_stream_pcm_running(&dice->tx_stream) ||
+ amdtp_stream_pcm_running(&dice->rx_stream)) {
+ err = snd_dice_transaction_get_rate(dice, &rate);
+ if (err < 0)
+ goto err_locked;
+ substream->runtime->hw.rate_min = rate;
+ substream->runtime->hw.rate_max = rate;
+ }
+
+ snd_pcm_set_sync(substream);
+end:
+ return err;
+err_locked:
+ snd_dice_stream_lock_release(dice);
+ return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ snd_dice_stream_lock_release(dice);
+
+ return 0;
+}
+
+static int capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&dice->mutex);
+ dice->substreams_counter++;
+ mutex_unlock(&dice->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&dice->tx_stream,
+ params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+static int playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&dice->mutex);
+ dice->substreams_counter++;
+ mutex_unlock(&dice->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&dice->rx_stream,
+ params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ mutex_lock(&dice->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ dice->substreams_counter--;
+
+ snd_dice_stream_stop_duplex(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int playback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ mutex_lock(&dice->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ dice->substreams_counter--;
+
+ snd_dice_stream_stop_duplex(dice);
+
+ mutex_unlock(&dice->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+ int err;
+
+ mutex_lock(&dice->mutex);
+ err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+ mutex_unlock(&dice->mutex);
+ if (err >= 0)
+ amdtp_stream_pcm_prepare(&dice->tx_stream);
+
+ return 0;
+}
+static int playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+ int err;
+
+ mutex_lock(&dice->mutex);
+ err = snd_dice_stream_start_duplex(dice, substream->runtime->rate);
+ mutex_unlock(&dice->mutex);
+ if (err >= 0)
+ amdtp_stream_pcm_prepare(&dice->rx_stream);
+
+ return err;
+}
+
+static int capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ amdtp_stream_pcm_trigger(&dice->tx_stream, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ amdtp_stream_pcm_trigger(&dice->tx_stream, NULL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+static int playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ amdtp_stream_pcm_trigger(&dice->rx_stream, substream);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ amdtp_stream_pcm_trigger(&dice->rx_stream, NULL);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static snd_pcm_uframes_t capture_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ return amdtp_stream_pcm_pointer(&dice->tx_stream);
+}
+static snd_pcm_uframes_t playback_pointer(struct snd_pcm_substream *substream)
+{
+ struct snd_dice *dice = substream->private_data;
+
+ return amdtp_stream_pcm_pointer(&dice->rx_stream);
+}
+
+int snd_dice_create_pcm(struct snd_dice *dice)
+{
+ static struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = capture_hw_params,
+ .hw_free = capture_hw_free,
+ .prepare = capture_prepare,
+ .trigger = capture_trigger,
+ .pointer = capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ static struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = playback_hw_params,
+ .hw_free = playback_hw_free,
+ .prepare = playback_prepare,
+ .trigger = playback_trigger,
+ .pointer = playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ unsigned int i, capture, playback;
+ int err;
+
+ capture = playback = 0;
+ for (i = 0; i < 3; i++) {
+ if (dice->tx_channels[i] > 0)
+ capture = 1;
+ if (dice->rx_channels[i] > 0)
+ playback = 1;
+ }
+
+ err = snd_pcm_new(dice->card, "DICE", 0, playback, capture, &pcm);
+ if (err < 0)
+ return err;
+ pcm->private_data = dice;
+ strcpy(pcm->name, dice->card->shortname);
+
+ if (capture > 0)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
+
+ if (playback > 0)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+
+ return 0;
+}
diff --git a/sound/firewire/dice/dice-proc.c b/sound/firewire/dice/dice-proc.c
new file mode 100644
index 0000000..f5c1d1b
--- /dev/null
+++ b/sound/firewire/dice/dice-proc.c
@@ -0,0 +1,252 @@
+/*
+ * dice_proc.c - a part of driver for Dice based devices
+ *
+ * Copyright (c) Clemens Ladisch
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+static int dice_proc_read_mem(struct snd_dice *dice, void *buffer,
+ unsigned int offset_q, unsigned int quadlets)
+{
+ unsigned int i;
+ int err;
+
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE + 4 * offset_q,
+ buffer, 4 * quadlets, 0);
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < quadlets; ++i)
+ be32_to_cpus(&((u32 *)buffer)[i]);
+
+ return 0;
+}
+
+static const char *str_from_array(const char *const strs[], unsigned int count,
+ unsigned int i)
+{
+ if (i < count)
+ return strs[i];
+
+ return "(unknown)";
+}
+
+static void dice_proc_fixup_string(char *s, unsigned int size)
+{
+ unsigned int i;
+
+ for (i = 0; i < size; i += 4)
+ cpu_to_le32s((u32 *)(s + i));
+
+ for (i = 0; i < size - 2; ++i) {
+ if (s[i] == '\0')
+ return;
+ if (s[i] == '\\' && s[i + 1] == '\\') {
+ s[i + 2] = '\0';
+ return;
+ }
+ }
+ s[size - 1] = '\0';
+}
+
+static void dice_proc_read(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ static const char *const section_names[5] = {
+ "global", "tx", "rx", "ext_sync", "unused2"
+ };
+ static const char *const clock_sources[] = {
+ "aes1", "aes2", "aes3", "aes4", "aes", "adat", "tdif",
+ "wc", "arx1", "arx2", "arx3", "arx4", "internal"
+ };
+ static const char *const rates[] = {
+ "32000", "44100", "48000", "88200", "96000", "176400", "192000",
+ "any low", "any mid", "any high", "none"
+ };
+ struct snd_dice *dice = entry->private_data;
+ u32 sections[ARRAY_SIZE(section_names) * 2];
+ struct {
+ u32 number;
+ u32 size;
+ } tx_rx_header;
+ union {
+ struct {
+ u32 owner_hi, owner_lo;
+ u32 notification;
+ char nick_name[NICK_NAME_SIZE];
+ u32 clock_select;
+ u32 enable;
+ u32 status;
+ u32 extended_status;
+ u32 sample_rate;
+ u32 version;
+ u32 clock_caps;
+ char clock_source_names[CLOCK_SOURCE_NAMES_SIZE];
+ } global;
+ struct {
+ u32 iso;
+ u32 number_audio;
+ u32 number_midi;
+ u32 speed;
+ char names[TX_NAMES_SIZE];
+ u32 ac3_caps;
+ u32 ac3_enable;
+ } tx;
+ struct {
+ u32 iso;
+ u32 seq_start;
+ u32 number_audio;
+ u32 number_midi;
+ char names[RX_NAMES_SIZE];
+ u32 ac3_caps;
+ u32 ac3_enable;
+ } rx;
+ struct {
+ u32 clock_source;
+ u32 locked;
+ u32 rate;
+ u32 adat_user_data;
+ } ext_sync;
+ } buf;
+ unsigned int quadlets, stream, i;
+
+ if (dice_proc_read_mem(dice, sections, 0, ARRAY_SIZE(sections)) < 0)
+ return;
+ snd_iprintf(buffer, "sections:\n");
+ for (i = 0; i < ARRAY_SIZE(section_names); ++i)
+ snd_iprintf(buffer, " %s: offset %u, size %u\n",
+ section_names[i],
+ sections[i * 2], sections[i * 2 + 1]);
+
+ quadlets = min_t(u32, sections[1], sizeof(buf.global) / 4);
+ if (dice_proc_read_mem(dice, &buf.global, sections[0], quadlets) < 0)
+ return;
+ snd_iprintf(buffer, "global:\n");
+ snd_iprintf(buffer, " owner: %04x:%04x%08x\n",
+ buf.global.owner_hi >> 16,
+ buf.global.owner_hi & 0xffff, buf.global.owner_lo);
+ snd_iprintf(buffer, " notification: %08x\n", buf.global.notification);
+ dice_proc_fixup_string(buf.global.nick_name, NICK_NAME_SIZE);
+ snd_iprintf(buffer, " nick name: %s\n", buf.global.nick_name);
+ snd_iprintf(buffer, " clock select: %s %s\n",
+ str_from_array(clock_sources, ARRAY_SIZE(clock_sources),
+ buf.global.clock_select & CLOCK_SOURCE_MASK),
+ str_from_array(rates, ARRAY_SIZE(rates),
+ (buf.global.clock_select & CLOCK_RATE_MASK)
+ >> CLOCK_RATE_SHIFT));
+ snd_iprintf(buffer, " enable: %u\n", buf.global.enable);
+ snd_iprintf(buffer, " status: %slocked %s\n",
+ buf.global.status & STATUS_SOURCE_LOCKED ? "" : "un",
+ str_from_array(rates, ARRAY_SIZE(rates),
+ (buf.global.status &
+ STATUS_NOMINAL_RATE_MASK)
+ >> CLOCK_RATE_SHIFT));
+ snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status);
+ snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate);
+ snd_iprintf(buffer, " version: %u.%u.%u.%u\n",
+ (buf.global.version >> 24) & 0xff,
+ (buf.global.version >> 16) & 0xff,
+ (buf.global.version >> 8) & 0xff,
+ (buf.global.version >> 0) & 0xff);
+ if (quadlets >= 90) {
+ snd_iprintf(buffer, " clock caps:");
+ for (i = 0; i <= 6; ++i)
+ if (buf.global.clock_caps & (1 << i))
+ snd_iprintf(buffer, " %s", rates[i]);
+ for (i = 0; i <= 12; ++i)
+ if (buf.global.clock_caps & (1 << (16 + i)))
+ snd_iprintf(buffer, " %s", clock_sources[i]);
+ snd_iprintf(buffer, "\n");
+ dice_proc_fixup_string(buf.global.clock_source_names,
+ CLOCK_SOURCE_NAMES_SIZE);
+ snd_iprintf(buffer, " clock source names: %s\n",
+ buf.global.clock_source_names);
+ }
+
+ if (dice_proc_read_mem(dice, &tx_rx_header, sections[2], 2) < 0)
+ return;
+ quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.tx) / 4);
+ for (stream = 0; stream < tx_rx_header.number; ++stream) {
+ if (dice_proc_read_mem(dice, &buf.tx, sections[2] + 2 +
+ stream * tx_rx_header.size,
+ quadlets) < 0)
+ break;
+ snd_iprintf(buffer, "tx %u:\n", stream);
+ snd_iprintf(buffer, " iso channel: %d\n", (int)buf.tx.iso);
+ snd_iprintf(buffer, " audio channels: %u\n",
+ buf.tx.number_audio);
+ snd_iprintf(buffer, " midi ports: %u\n", buf.tx.number_midi);
+ snd_iprintf(buffer, " speed: S%u\n", 100u << buf.tx.speed);
+ if (quadlets >= 68) {
+ dice_proc_fixup_string(buf.tx.names, TX_NAMES_SIZE);
+ snd_iprintf(buffer, " names: %s\n", buf.tx.names);
+ }
+ if (quadlets >= 70) {
+ snd_iprintf(buffer, " ac3 caps: %08x\n",
+ buf.tx.ac3_caps);
+ snd_iprintf(buffer, " ac3 enable: %08x\n",
+ buf.tx.ac3_enable);
+ }
+ }
+
+ if (dice_proc_read_mem(dice, &tx_rx_header, sections[4], 2) < 0)
+ return;
+ quadlets = min_t(u32, tx_rx_header.size, sizeof(buf.rx) / 4);
+ for (stream = 0; stream < tx_rx_header.number; ++stream) {
+ if (dice_proc_read_mem(dice, &buf.rx, sections[4] + 2 +
+ stream * tx_rx_header.size,
+ quadlets) < 0)
+ break;
+ snd_iprintf(buffer, "rx %u:\n", stream);
+ snd_iprintf(buffer, " iso channel: %d\n", (int)buf.rx.iso);
+ snd_iprintf(buffer, " sequence start: %u\n", buf.rx.seq_start);
+ snd_iprintf(buffer, " audio channels: %u\n",
+ buf.rx.number_audio);
+ snd_iprintf(buffer, " midi ports: %u\n", buf.rx.number_midi);
+ if (quadlets >= 68) {
+ dice_proc_fixup_string(buf.rx.names, RX_NAMES_SIZE);
+ snd_iprintf(buffer, " names: %s\n", buf.rx.names);
+ }
+ if (quadlets >= 70) {
+ snd_iprintf(buffer, " ac3 caps: %08x\n",
+ buf.rx.ac3_caps);
+ snd_iprintf(buffer, " ac3 enable: %08x\n",
+ buf.rx.ac3_enable);
+ }
+ }
+
+ quadlets = min_t(u32, sections[7], sizeof(buf.ext_sync) / 4);
+ if (quadlets >= 4) {
+ if (dice_proc_read_mem(dice, &buf.ext_sync,
+ sections[6], 4) < 0)
+ return;
+ snd_iprintf(buffer, "ext status:\n");
+ snd_iprintf(buffer, " clock source: %s\n",
+ str_from_array(clock_sources,
+ ARRAY_SIZE(clock_sources),
+ buf.ext_sync.clock_source));
+ snd_iprintf(buffer, " locked: %u\n", buf.ext_sync.locked);
+ snd_iprintf(buffer, " rate: %s\n",
+ str_from_array(rates, ARRAY_SIZE(rates),
+ buf.ext_sync.rate));
+ snd_iprintf(buffer, " adat user data: ");
+ if (buf.ext_sync.adat_user_data & ADAT_USER_DATA_NO_DATA)
+ snd_iprintf(buffer, "-\n");
+ else
+ snd_iprintf(buffer, "%x\n",
+ buf.ext_sync.adat_user_data);
+ }
+}
+
+void snd_dice_create_proc(struct snd_dice *dice)
+{
+ struct snd_info_entry *entry;
+
+ if (!snd_card_proc_new(dice->card, "dice", &entry))
+ snd_info_set_text_ops(entry, dice, dice_proc_read);
+}
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c
new file mode 100644
index 0000000..fa9cf76
--- /dev/null
+++ b/sound/firewire/dice/dice-stream.c
@@ -0,0 +1,407 @@
+/*
+ * dice_stream.c - a part of driver for DICE based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Copyright (c) 2014 Takashi Sakamoto <o-takashi@sakamocchi.jp>
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+#define CALLBACK_TIMEOUT 200
+
+const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = {
+ /* mode 0 */
+ [0] = 32000,
+ [1] = 44100,
+ [2] = 48000,
+ /* mode 1 */
+ [3] = 88200,
+ [4] = 96000,
+ /* mode 2 */
+ [5] = 176400,
+ [6] = 192000,
+};
+
+int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate,
+ unsigned int *mode)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
+ if (!(dice->clock_caps & BIT(i)))
+ continue;
+ if (snd_dice_rates[i] != rate)
+ continue;
+
+ *mode = (i - 1) / 2;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static void release_resources(struct snd_dice *dice,
+ struct fw_iso_resources *resources)
+{
+ unsigned int channel;
+
+ /* Reset channel number */
+ channel = cpu_to_be32((u32)-1);
+ if (resources == &dice->tx_resources)
+ snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
+ &channel, 4);
+ else
+ snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
+ &channel, 4);
+
+ fw_iso_resources_free(resources);
+}
+
+static int keep_resources(struct snd_dice *dice,
+ struct fw_iso_resources *resources,
+ unsigned int max_payload_bytes)
+{
+ unsigned int channel;
+ int err;
+
+ err = fw_iso_resources_allocate(resources, max_payload_bytes,
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ goto end;
+
+ /* Set channel number */
+ channel = cpu_to_be32(resources->channel);
+ if (resources == &dice->tx_resources)
+ err = snd_dice_transaction_write_tx(dice, TX_ISOCHRONOUS,
+ &channel, 4);
+ else
+ err = snd_dice_transaction_write_rx(dice, RX_ISOCHRONOUS,
+ &channel, 4);
+ if (err < 0)
+ release_resources(dice, resources);
+end:
+ return err;
+}
+
+static void stop_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+{
+ amdtp_stream_pcm_abort(stream);
+ amdtp_stream_stop(stream);
+
+ if (stream == &dice->tx_stream)
+ release_resources(dice, &dice->tx_resources);
+ else
+ release_resources(dice, &dice->rx_resources);
+}
+
+static int start_stream(struct snd_dice *dice, struct amdtp_stream *stream,
+ unsigned int rate)
+{
+ struct fw_iso_resources *resources;
+ unsigned int i, mode, pcm_chs, midi_ports;
+ int err;
+
+ err = snd_dice_stream_get_rate_mode(dice, rate, &mode);
+ if (err < 0)
+ goto end;
+ if (stream == &dice->tx_stream) {
+ resources = &dice->tx_resources;
+ pcm_chs = dice->tx_channels[mode];
+ midi_ports = dice->tx_midi_ports[mode];
+ } else {
+ resources = &dice->rx_resources;
+ pcm_chs = dice->rx_channels[mode];
+ midi_ports = dice->rx_midi_ports[mode];
+ }
+
+ /*
+ * At 176.4/192.0 kHz, Dice has a quirk to transfer two PCM frames in
+ * one data block of AMDTP packet. Thus sampling transfer frequency is
+ * a half of PCM sampling frequency, i.e. PCM frames at 192.0 kHz are
+ * transferred on AMDTP packets at 96 kHz. Two successive samples of a
+ * channel are stored consecutively in the packet. This quirk is called
+ * as 'Dual Wire'.
+ * For this quirk, blocking mode is required and PCM buffer size should
+ * be aligned to SYT_INTERVAL.
+ */
+ if (mode > 1) {
+ rate /= 2;
+ pcm_chs *= 2;
+ stream->double_pcm_frames = true;
+ } else {
+ stream->double_pcm_frames = false;
+ }
+
+ amdtp_stream_set_parameters(stream, rate, pcm_chs, midi_ports);
+ if (mode > 1) {
+ pcm_chs /= 2;
+
+ for (i = 0; i < pcm_chs; i++) {
+ stream->pcm_positions[i] = i * 2;
+ stream->pcm_positions[i + pcm_chs] = i * 2 + 1;
+ }
+ }
+
+ err = keep_resources(dice, resources,
+ amdtp_stream_get_max_payload(stream));
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to keep isochronous resources\n");
+ goto end;
+ }
+
+ err = amdtp_stream_start(stream, resources->channel,
+ fw_parent_device(dice->unit)->max_speed);
+ if (err < 0)
+ release_resources(dice, resources);
+end:
+ return err;
+}
+
+static int get_sync_mode(struct snd_dice *dice, enum cip_flags *sync_mode)
+{
+ u32 source;
+ int err;
+
+ err = snd_dice_transaction_get_clock_source(dice, &source);
+ if (err < 0)
+ goto end;
+
+ switch (source) {
+ /* So-called 'SYT Match' modes, sync_to_syt value of packets received */
+ case CLOCK_SOURCE_ARX4: /* in 4th stream */
+ case CLOCK_SOURCE_ARX3: /* in 3rd stream */
+ case CLOCK_SOURCE_ARX2: /* in 2nd stream */
+ err = -ENOSYS;
+ break;
+ case CLOCK_SOURCE_ARX1: /* in 1st stream, which this driver uses */
+ *sync_mode = 0;
+ break;
+ default:
+ *sync_mode = CIP_SYNC_TO_DEVICE;
+ break;
+ }
+end:
+ return err;
+}
+
+int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate)
+{
+ struct amdtp_stream *master, *slave;
+ unsigned int curr_rate;
+ enum cip_flags sync_mode;
+ int err = 0;
+
+ if (dice->substreams_counter == 0)
+ goto end;
+
+ err = get_sync_mode(dice, &sync_mode);
+ if (err < 0)
+ goto end;
+ if (sync_mode == CIP_SYNC_TO_DEVICE) {
+ master = &dice->tx_stream;
+ slave = &dice->rx_stream;
+ } else {
+ master = &dice->rx_stream;
+ slave = &dice->tx_stream;
+ }
+
+ /* Some packet queueing errors. */
+ if (amdtp_streaming_error(master) || amdtp_streaming_error(slave))
+ stop_stream(dice, master);
+
+ /* Stop stream if rate is different. */
+ err = snd_dice_transaction_get_rate(dice, &curr_rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to get sampling rate\n");
+ goto end;
+ }
+ if (rate == 0)
+ rate = curr_rate;
+ if (rate != curr_rate)
+ stop_stream(dice, master);
+
+ if (!amdtp_stream_running(master)) {
+ stop_stream(dice, slave);
+ snd_dice_transaction_clear_enable(dice);
+
+ amdtp_stream_set_sync(sync_mode, master, slave);
+
+ err = snd_dice_transaction_set_rate(dice, rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to set sampling rate\n");
+ goto end;
+ }
+
+ /* Start both streams. */
+ err = start_stream(dice, master, rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to start AMDTP master stream\n");
+ goto end;
+ }
+ err = start_stream(dice, slave, rate);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to start AMDTP slave stream\n");
+ stop_stream(dice, master);
+ goto end;
+ }
+ err = snd_dice_transaction_set_enable(dice);
+ if (err < 0) {
+ dev_err(&dice->unit->device,
+ "fail to enable interface\n");
+ stop_stream(dice, master);
+ stop_stream(dice, slave);
+ goto end;
+ }
+
+ /* Wait first callbacks */
+ if (!amdtp_stream_wait_callback(master, CALLBACK_TIMEOUT) ||
+ !amdtp_stream_wait_callback(slave, CALLBACK_TIMEOUT)) {
+ snd_dice_transaction_clear_enable(dice);
+ stop_stream(dice, master);
+ stop_stream(dice, slave);
+ err = -ETIMEDOUT;
+ }
+ }
+end:
+ return err;
+}
+
+void snd_dice_stream_stop_duplex(struct snd_dice *dice)
+{
+ if (dice->substreams_counter > 0)
+ return;
+
+ snd_dice_transaction_clear_enable(dice);
+
+ stop_stream(dice, &dice->tx_stream);
+ stop_stream(dice, &dice->rx_stream);
+}
+
+static int init_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+{
+ int err;
+ struct fw_iso_resources *resources;
+ enum amdtp_stream_direction dir;
+
+ if (stream == &dice->tx_stream) {
+ resources = &dice->tx_resources;
+ dir = AMDTP_IN_STREAM;
+ } else {
+ resources = &dice->rx_resources;
+ dir = AMDTP_OUT_STREAM;
+ }
+
+ err = fw_iso_resources_init(resources, dice->unit);
+ if (err < 0)
+ goto end;
+ resources->channels_mask = 0x00000000ffffffffuLL;
+
+ err = amdtp_stream_init(stream, dice->unit, dir, CIP_BLOCKING);
+ if (err < 0) {
+ amdtp_stream_destroy(stream);
+ fw_iso_resources_destroy(resources);
+ }
+end:
+ return err;
+}
+
+static void destroy_stream(struct snd_dice *dice, struct amdtp_stream *stream)
+{
+ amdtp_stream_destroy(stream);
+
+ if (stream == &dice->tx_stream)
+ fw_iso_resources_destroy(&dice->tx_resources);
+ else
+ fw_iso_resources_destroy(&dice->rx_resources);
+}
+
+int snd_dice_stream_init_duplex(struct snd_dice *dice)
+{
+ int err;
+
+ dice->substreams_counter = 0;
+
+ err = init_stream(dice, &dice->tx_stream);
+ if (err < 0)
+ goto end;
+
+ err = init_stream(dice, &dice->rx_stream);
+end:
+ return err;
+}
+
+void snd_dice_stream_destroy_duplex(struct snd_dice *dice)
+{
+ snd_dice_transaction_clear_enable(dice);
+
+ stop_stream(dice, &dice->tx_stream);
+ destroy_stream(dice, &dice->tx_stream);
+
+ stop_stream(dice, &dice->rx_stream);
+ destroy_stream(dice, &dice->rx_stream);
+
+ dice->substreams_counter = 0;
+}
+
+void snd_dice_stream_update_duplex(struct snd_dice *dice)
+{
+ /*
+ * On a bus reset, the DICE firmware disables streaming and then goes
+ * off contemplating its own navel for hundreds of milliseconds before
+ * it can react to any of our attempts to reenable streaming. This
+ * means that we lose synchronization anyway, so we force our streams
+ * to stop so that the application can restart them in an orderly
+ * manner.
+ */
+ dice->global_enabled = false;
+
+ stop_stream(dice, &dice->rx_stream);
+ stop_stream(dice, &dice->tx_stream);
+
+ fw_iso_resources_update(&dice->rx_resources);
+ fw_iso_resources_update(&dice->tx_resources);
+}
+
+static void dice_lock_changed(struct snd_dice *dice)
+{
+ dice->dev_lock_changed = true;
+ wake_up(&dice->hwdep_wait);
+}
+
+int snd_dice_stream_lock_try(struct snd_dice *dice)
+{
+ int err;
+
+ spin_lock_irq(&dice->lock);
+
+ if (dice->dev_lock_count < 0) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (dice->dev_lock_count++ == 0)
+ dice_lock_changed(dice);
+ err = 0;
+out:
+ spin_unlock_irq(&dice->lock);
+ return err;
+}
+
+void snd_dice_stream_lock_release(struct snd_dice *dice)
+{
+ spin_lock_irq(&dice->lock);
+
+ if (WARN_ON(dice->dev_lock_count <= 0))
+ goto out;
+
+ if (--dice->dev_lock_count == 0)
+ dice_lock_changed(dice);
+out:
+ spin_unlock_irq(&dice->lock);
+}
diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c
new file mode 100644
index 0000000..aee7461
--- /dev/null
+++ b/sound/firewire/dice/dice-transaction.c
@@ -0,0 +1,382 @@
+/*
+ * dice_transaction.c - a part of driver for Dice based devices
+ *
+ * Copyright (c) Clemens Ladisch
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+#define NOTIFICATION_TIMEOUT_MS 100
+
+static u64 get_subaddr(struct snd_dice *dice, enum snd_dice_addr_type type,
+ u64 offset)
+{
+ switch (type) {
+ case SND_DICE_ADDR_TYPE_TX:
+ offset += dice->tx_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_RX:
+ offset += dice->rx_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_SYNC:
+ offset += dice->sync_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_RSRV:
+ offset += dice->rsrv_offset;
+ break;
+ case SND_DICE_ADDR_TYPE_GLOBAL:
+ default:
+ offset += dice->global_offset;
+ break;
+ }
+ offset += DICE_PRIVATE_SPACE;
+ return offset;
+}
+
+int snd_dice_transaction_write(struct snd_dice *dice,
+ enum snd_dice_addr_type type,
+ unsigned int offset, void *buf, unsigned int len)
+{
+ return snd_fw_transaction(dice->unit,
+ (len == 4) ? TCODE_WRITE_QUADLET_REQUEST :
+ TCODE_WRITE_BLOCK_REQUEST,
+ get_subaddr(dice, type, offset), buf, len, 0);
+}
+
+int snd_dice_transaction_read(struct snd_dice *dice,
+ enum snd_dice_addr_type type, unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_fw_transaction(dice->unit,
+ (len == 4) ? TCODE_READ_QUADLET_REQUEST :
+ TCODE_READ_BLOCK_REQUEST,
+ get_subaddr(dice, type, offset), buf, len, 0);
+}
+
+static unsigned int get_clock_info(struct snd_dice *dice, __be32 *info)
+{
+ return snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT,
+ info, 4);
+}
+
+static int set_clock_info(struct snd_dice *dice,
+ unsigned int rate, unsigned int source)
+{
+ unsigned int retries = 3;
+ unsigned int i;
+ __be32 info;
+ u32 mask;
+ u32 clock;
+ int err;
+retry:
+ err = get_clock_info(dice, &info);
+ if (err < 0)
+ goto end;
+
+ clock = be32_to_cpu(info);
+ if (source != UINT_MAX) {
+ mask = CLOCK_SOURCE_MASK;
+ clock &= ~mask;
+ clock |= source;
+ }
+ if (rate != UINT_MAX) {
+ for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) {
+ if (snd_dice_rates[i] == rate)
+ break;
+ }
+ if (i == ARRAY_SIZE(snd_dice_rates)) {
+ err = -EINVAL;
+ goto end;
+ }
+
+ mask = CLOCK_RATE_MASK;
+ clock &= ~mask;
+ clock |= i << CLOCK_RATE_SHIFT;
+ }
+ info = cpu_to_be32(clock);
+
+ if (completion_done(&dice->clock_accepted))
+ reinit_completion(&dice->clock_accepted);
+
+ err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT,
+ &info, 4);
+ if (err < 0)
+ goto end;
+
+ /* Timeout means it's invalid request, probably bus reset occurred. */
+ if (wait_for_completion_timeout(&dice->clock_accepted,
+ msecs_to_jiffies(NOTIFICATION_TIMEOUT_MS)) == 0) {
+ if (retries-- == 0) {
+ err = -ETIMEDOUT;
+ goto end;
+ }
+
+ err = snd_dice_transaction_reinit(dice);
+ if (err < 0)
+ goto end;
+
+ msleep(500); /* arbitrary */
+ goto retry;
+ }
+end:
+ return err;
+}
+
+int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
+ unsigned int *source)
+{
+ __be32 info;
+ int err;
+
+ err = get_clock_info(dice, &info);
+ if (err >= 0)
+ *source = be32_to_cpu(info) & CLOCK_SOURCE_MASK;
+
+ return err;
+}
+
+int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate)
+{
+ __be32 info;
+ unsigned int index;
+ int err;
+
+ err = get_clock_info(dice, &info);
+ if (err < 0)
+ goto end;
+
+ index = (be32_to_cpu(info) & CLOCK_RATE_MASK) >> CLOCK_RATE_SHIFT;
+ if (index >= SND_DICE_RATES_COUNT) {
+ err = -ENOSYS;
+ goto end;
+ }
+
+ *rate = snd_dice_rates[index];
+end:
+ return err;
+}
+int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate)
+{
+ return set_clock_info(dice, rate, UINT_MAX);
+}
+
+int snd_dice_transaction_set_enable(struct snd_dice *dice)
+{
+ __be32 value;
+ int err = 0;
+
+ if (dice->global_enabled)
+ goto end;
+
+ value = cpu_to_be32(1);
+ err = snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_ENABLE),
+ &value, 4,
+ FW_FIXED_GENERATION | dice->owner_generation);
+ if (err < 0)
+ goto end;
+
+ dice->global_enabled = true;
+end:
+ return err;
+}
+
+void snd_dice_transaction_clear_enable(struct snd_dice *dice)
+{
+ __be32 value;
+
+ value = 0;
+ snd_fw_transaction(dice->unit, TCODE_WRITE_QUADLET_REQUEST,
+ get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_ENABLE),
+ &value, 4, FW_QUIET |
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ dice->global_enabled = false;
+}
+
+static void dice_notification(struct fw_card *card, struct fw_request *request,
+ int tcode, int destination, int source,
+ int generation, unsigned long long offset,
+ void *data, size_t length, void *callback_data)
+{
+ struct snd_dice *dice = callback_data;
+ u32 bits;
+ unsigned long flags;
+
+ if (tcode != TCODE_WRITE_QUADLET_REQUEST) {
+ fw_send_response(card, request, RCODE_TYPE_ERROR);
+ return;
+ }
+ if ((offset & 3) != 0) {
+ fw_send_response(card, request, RCODE_ADDRESS_ERROR);
+ return;
+ }
+
+ bits = be32_to_cpup(data);
+
+ spin_lock_irqsave(&dice->lock, flags);
+ dice->notification_bits |= bits;
+ spin_unlock_irqrestore(&dice->lock, flags);
+
+ fw_send_response(card, request, RCODE_COMPLETE);
+
+ if (bits & NOTIFY_CLOCK_ACCEPTED)
+ complete(&dice->clock_accepted);
+ wake_up(&dice->hwdep_wait);
+}
+
+static int register_notification_address(struct snd_dice *dice, bool retry)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+ unsigned int retries;
+ int err;
+
+ retries = (retry) ? 3 : 0;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (!buffer)
+ return -ENOMEM;
+
+ for (;;) {
+ buffer[0] = cpu_to_be64(OWNER_NO_OWNER);
+ buffer[1] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+
+ dice->owner_generation = device->generation;
+ smp_rmb(); /* node_id vs. generation */
+ err = snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
+ get_subaddr(dice,
+ SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_OWNER),
+ buffer, 2 * 8,
+ FW_FIXED_GENERATION |
+ dice->owner_generation);
+ if (err == 0) {
+ /* success */
+ if (buffer[0] == cpu_to_be64(OWNER_NO_OWNER))
+ break;
+ /* The address seems to be already registered. */
+ if (buffer[0] == buffer[1])
+ break;
+
+ dev_err(&dice->unit->device,
+ "device is already in use\n");
+ err = -EBUSY;
+ }
+ if (err != -EAGAIN || retries-- > 0)
+ break;
+
+ msleep(20);
+ }
+
+ kfree(buffer);
+
+ if (err < 0)
+ dice->owner_generation = -1;
+
+ return err;
+}
+
+static void unregister_notification_address(struct snd_dice *dice)
+{
+ struct fw_device *device = fw_parent_device(dice->unit);
+ __be64 *buffer;
+
+ buffer = kmalloc(2 * 8, GFP_KERNEL);
+ if (buffer == NULL)
+ return;
+
+ buffer[0] = cpu_to_be64(
+ ((u64)device->card->node_id << OWNER_NODE_SHIFT) |
+ dice->notification_handler.offset);
+ buffer[1] = cpu_to_be64(OWNER_NO_OWNER);
+ snd_fw_transaction(dice->unit, TCODE_LOCK_COMPARE_SWAP,
+ get_subaddr(dice, SND_DICE_ADDR_TYPE_GLOBAL,
+ GLOBAL_OWNER),
+ buffer, 2 * 8, FW_QUIET |
+ FW_FIXED_GENERATION | dice->owner_generation);
+
+ kfree(buffer);
+
+ dice->owner_generation = -1;
+}
+
+void snd_dice_transaction_destroy(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+
+ if (handler->callback_data == NULL)
+ return;
+
+ unregister_notification_address(dice);
+
+ fw_core_remove_address_handler(handler);
+ handler->callback_data = NULL;
+}
+
+int snd_dice_transaction_reinit(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+
+ if (handler->callback_data == NULL)
+ return -EINVAL;
+
+ return register_notification_address(dice, false);
+}
+
+int snd_dice_transaction_init(struct snd_dice *dice)
+{
+ struct fw_address_handler *handler = &dice->notification_handler;
+ __be32 *pointers;
+ int err;
+
+ /* Use the same way which dice_interface_check() does. */
+ pointers = kmalloc(sizeof(__be32) * 10, GFP_KERNEL);
+ if (pointers == NULL)
+ return -ENOMEM;
+
+ /* Get offsets for sub-addresses */
+ err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE,
+ pointers, sizeof(__be32) * 10, 0);
+ if (err < 0)
+ goto end;
+
+ /* Allocation callback in address space over host controller */
+ handler->length = 4;
+ handler->address_callback = dice_notification;
+ handler->callback_data = dice;
+ err = fw_core_add_address_handler(handler, &fw_high_memory_region);
+ if (err < 0) {
+ handler->callback_data = NULL;
+ goto end;
+ }
+
+ /* Register the address space */
+ err = register_notification_address(dice, true);
+ if (err < 0) {
+ fw_core_remove_address_handler(handler);
+ handler->callback_data = NULL;
+ goto end;
+ }
+
+ dice->global_offset = be32_to_cpu(pointers[0]) * 4;
+ dice->tx_offset = be32_to_cpu(pointers[2]) * 4;
+ dice->rx_offset = be32_to_cpu(pointers[4]) * 4;
+ dice->sync_offset = be32_to_cpu(pointers[6]) * 4;
+ dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4;
+
+ /* Set up later. */
+ if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4)
+ dice->clock_caps = 1;
+end:
+ kfree(pointers);
+ return err;
+}
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c
new file mode 100644
index 0000000..90d8f40
--- /dev/null
+++ b/sound/firewire/dice/dice.c
@@ -0,0 +1,361 @@
+/*
+ * TC Applied Technologies Digital Interface Communications Engine driver
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "dice.h"
+
+MODULE_DESCRIPTION("DICE driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+
+#define OUI_WEISS 0x001c6a
+
+#define DICE_CATEGORY_ID 0x04
+#define WEISS_CATEGORY_ID 0x00
+
+static int dice_interface_check(struct fw_unit *unit)
+{
+ static const int min_values[10] = {
+ 10, 0x64 / 4,
+ 10, 0x18 / 4,
+ 10, 0x18 / 4,
+ 0, 0,
+ 0, 0,
+ };
+ struct fw_device *device = fw_parent_device(unit);
+ struct fw_csr_iterator it;
+ int key, val, vendor = -1, model = -1, err;
+ unsigned int category, i;
+ __be32 *pointers, value;
+ __be32 version;
+
+ pointers = kmalloc_array(ARRAY_SIZE(min_values), sizeof(__be32),
+ GFP_KERNEL);
+ if (pointers == NULL)
+ return -ENOMEM;
+
+ /*
+ * Check that GUID and unit directory are constructed according to DICE
+ * rules, i.e., that the specifier ID is the GUID's OUI, and that the
+ * GUID chip ID consists of the 8-bit category ID, the 10-bit product
+ * ID, and a 22-bit serial number.
+ */
+ fw_csr_iterator_init(&it, unit->directory);
+ while (fw_csr_iterator_next(&it, &key, &val)) {
+ switch (key) {
+ case CSR_SPECIFIER_ID:
+ vendor = val;
+ break;
+ case CSR_MODEL:
+ model = val;
+ break;
+ }
+ }
+ if (vendor == OUI_WEISS)
+ category = WEISS_CATEGORY_ID;
+ else
+ category = DICE_CATEGORY_ID;
+ if (device->config_rom[3] != ((vendor << 8) | category) ||
+ device->config_rom[4] >> 22 != model) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ /*
+ * Check that the sub address spaces exist and are located inside the
+ * private address space. The minimum values are chosen so that all
+ * minimally required registers are included.
+ */
+ err = snd_fw_transaction(unit, TCODE_READ_BLOCK_REQUEST,
+ DICE_PRIVATE_SPACE, pointers,
+ sizeof(__be32) * ARRAY_SIZE(min_values), 0);
+ if (err < 0) {
+ err = -ENODEV;
+ goto end;
+ }
+ for (i = 0; i < ARRAY_SIZE(min_values); ++i) {
+ value = be32_to_cpu(pointers[i]);
+ if (value < min_values[i] || value >= 0x40000) {
+ err = -ENODEV;
+ goto end;
+ }
+ }
+
+ /*
+ * Check that the implemented DICE driver specification major version
+ * number matches.
+ */
+ err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
+ DICE_PRIVATE_SPACE +
+ be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION,
+ &version, 4, 0);
+ if (err < 0) {
+ err = -ENODEV;
+ goto end;
+ }
+ if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) {
+ dev_err(&unit->device,
+ "unknown DICE version: 0x%08x\n", be32_to_cpu(version));
+ err = -ENODEV;
+ goto end;
+ }
+end:
+ return err;
+}
+
+static int highest_supported_mode_rate(struct snd_dice *dice,
+ unsigned int mode, unsigned int *rate)
+{
+ unsigned int i, m;
+
+ for (i = ARRAY_SIZE(snd_dice_rates); i > 0; i--) {
+ *rate = snd_dice_rates[i - 1];
+ if (snd_dice_stream_get_rate_mode(dice, *rate, &m) < 0)
+ continue;
+ if (mode == m)
+ break;
+ }
+ if (i == 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int dice_read_mode_params(struct snd_dice *dice, unsigned int mode)
+{
+ __be32 values[2];
+ unsigned int rate;
+ int err;
+
+ if (highest_supported_mode_rate(dice, mode, &rate) < 0) {
+ dice->tx_channels[mode] = 0;
+ dice->tx_midi_ports[mode] = 0;
+ dice->rx_channels[mode] = 0;
+ dice->rx_midi_ports[mode] = 0;
+ return 0;
+ }
+
+ err = snd_dice_transaction_set_rate(dice, rate);
+ if (err < 0)
+ return err;
+
+ err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO,
+ values, sizeof(values));
+ if (err < 0)
+ return err;
+
+ dice->tx_channels[mode] = be32_to_cpu(values[0]);
+ dice->tx_midi_ports[mode] = be32_to_cpu(values[1]);
+
+ err = snd_dice_transaction_read_rx(dice, RX_NUMBER_AUDIO,
+ values, sizeof(values));
+ if (err < 0)
+ return err;
+
+ dice->rx_channels[mode] = be32_to_cpu(values[0]);
+ dice->rx_midi_ports[mode] = be32_to_cpu(values[1]);
+
+ return 0;
+}
+
+static int dice_read_params(struct snd_dice *dice)
+{
+ __be32 value;
+ int mode, err;
+
+ /* some very old firmwares don't tell about their clock support */
+ if (dice->clock_caps > 0) {
+ err = snd_dice_transaction_read_global(dice,
+ GLOBAL_CLOCK_CAPABILITIES,
+ &value, 4);
+ if (err < 0)
+ return err;
+ dice->clock_caps = be32_to_cpu(value);
+ } else {
+ /* this should be supported by any device */
+ dice->clock_caps = CLOCK_CAP_RATE_44100 |
+ CLOCK_CAP_RATE_48000 |
+ CLOCK_CAP_SOURCE_ARX1 |
+ CLOCK_CAP_SOURCE_INTERNAL;
+ }
+
+ for (mode = 2; mode >= 0; --mode) {
+ err = dice_read_mode_params(dice, mode);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+
+static void dice_card_strings(struct snd_dice *dice)
+{
+ struct snd_card *card = dice->card;
+ struct fw_device *dev = fw_parent_device(dice->unit);
+ char vendor[32], model[32];
+ unsigned int i;
+ int err;
+
+ strcpy(card->driver, "DICE");
+
+ strcpy(card->shortname, "DICE");
+ BUILD_BUG_ON(NICK_NAME_SIZE < sizeof(card->shortname));
+ err = snd_dice_transaction_read_global(dice, GLOBAL_NICK_NAME,
+ card->shortname,
+ sizeof(card->shortname));
+ if (err >= 0) {
+ /* DICE strings are returned in "always-wrong" endianness */
+ BUILD_BUG_ON(sizeof(card->shortname) % 4 != 0);
+ for (i = 0; i < sizeof(card->shortname); i += 4)
+ swab32s((u32 *)&card->shortname[i]);
+ card->shortname[sizeof(card->shortname) - 1] = '\0';
+ }
+
+ strcpy(vendor, "?");
+ fw_csr_string(dev->config_rom + 5, CSR_VENDOR, vendor, sizeof(vendor));
+ strcpy(model, "?");
+ fw_csr_string(dice->unit->directory, CSR_MODEL, model, sizeof(model));
+ snprintf(card->longname, sizeof(card->longname),
+ "%s %s (serial %u) at %s, S%d",
+ vendor, model, dev->config_rom[4] & 0x3fffff,
+ dev_name(&dice->unit->device), 100 << dev->max_speed);
+
+ strcpy(card->mixername, "DICE");
+}
+
+static void dice_card_free(struct snd_card *card)
+{
+ struct snd_dice *dice = card->private_data;
+
+ snd_dice_transaction_destroy(dice);
+ mutex_destroy(&dice->mutex);
+}
+
+static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id)
+{
+ struct snd_card *card;
+ struct snd_dice *dice;
+ int err;
+
+ err = dice_interface_check(unit);
+ if (err < 0)
+ goto end;
+
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*dice), &card);
+ if (err < 0)
+ goto end;
+
+ dice = card->private_data;
+ dice->card = card;
+ dice->unit = unit;
+ card->private_free = dice_card_free;
+
+ spin_lock_init(&dice->lock);
+ mutex_init(&dice->mutex);
+ init_completion(&dice->clock_accepted);
+ init_waitqueue_head(&dice->hwdep_wait);
+
+ err = snd_dice_transaction_init(dice);
+ if (err < 0)
+ goto error;
+
+ err = dice_read_params(dice);
+ if (err < 0)
+ goto error;
+
+ dice_card_strings(dice);
+
+ err = snd_dice_create_pcm(dice);
+ if (err < 0)
+ goto error;
+
+ err = snd_dice_create_hwdep(dice);
+ if (err < 0)
+ goto error;
+
+ snd_dice_create_proc(dice);
+
+ err = snd_dice_create_midi(dice);
+ if (err < 0)
+ goto error;
+
+ err = snd_dice_stream_init_duplex(dice);
+ if (err < 0)
+ goto error;
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_dice_stream_destroy_duplex(dice);
+ goto error;
+ }
+
+ dev_set_drvdata(&unit->device, dice);
+end:
+ return err;
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static void dice_remove(struct fw_unit *unit)
+{
+ struct snd_dice *dice = dev_get_drvdata(&unit->device);
+
+ snd_card_disconnect(dice->card);
+
+ snd_dice_stream_destroy_duplex(dice);
+
+ snd_card_free_when_closed(dice->card);
+}
+
+static void dice_bus_reset(struct fw_unit *unit)
+{
+ struct snd_dice *dice = dev_get_drvdata(&unit->device);
+
+ /* The handler address register becomes initialized. */
+ snd_dice_transaction_reinit(dice);
+
+ mutex_lock(&dice->mutex);
+ snd_dice_stream_update_duplex(dice);
+ mutex_unlock(&dice->mutex);
+}
+
+#define DICE_INTERFACE 0x000001
+
+static const struct ieee1394_device_id dice_id_table[] = {
+ {
+ .match_flags = IEEE1394_MATCH_VERSION,
+ .version = DICE_INTERFACE,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, dice_id_table);
+
+static struct fw_driver dice_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ },
+ .probe = dice_probe,
+ .update = dice_bus_reset,
+ .remove = dice_remove,
+ .id_table = dice_id_table,
+};
+
+static int __init alsa_dice_init(void)
+{
+ return driver_register(&dice_driver.driver);
+}
+
+static void __exit alsa_dice_exit(void)
+{
+ driver_unregister(&dice_driver.driver);
+}
+
+module_init(alsa_dice_init);
+module_exit(alsa_dice_exit);
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h
new file mode 100644
index 0000000..ecf5dc8
--- /dev/null
+++ b/sound/firewire/dice/dice.h
@@ -0,0 +1,189 @@
+/*
+ * dice.h - a part of driver for Dice based devices
+ *
+ * Copyright (c) Clemens Ladisch
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#ifndef SOUND_DICE_H_INCLUDED
+#define SOUND_DICE_H_INCLUDED
+
+#include <linux/compat.h>
+#include <linux/completion.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/jiffies.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/spinlock.h>
+#include <linux/wait.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+#include <sound/info.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/rawmidi.h>
+
+#include "../amdtp.h"
+#include "../iso-resources.h"
+#include "../lib.h"
+#include "dice-interface.h"
+
+struct snd_dice {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ spinlock_t lock;
+ struct mutex mutex;
+
+ /* Offsets for sub-addresses */
+ unsigned int global_offset;
+ unsigned int rx_offset;
+ unsigned int tx_offset;
+ unsigned int sync_offset;
+ unsigned int rsrv_offset;
+
+ unsigned int clock_caps;
+ unsigned int tx_channels[3];
+ unsigned int rx_channels[3];
+ unsigned int tx_midi_ports[3];
+ unsigned int rx_midi_ports[3];
+
+ struct fw_address_handler notification_handler;
+ int owner_generation;
+ u32 notification_bits;
+
+ /* For uapi */
+ int dev_lock_count; /* > 0 driver, < 0 userspace */
+ bool dev_lock_changed;
+ wait_queue_head_t hwdep_wait;
+
+ /* For streaming */
+ struct fw_iso_resources tx_resources;
+ struct fw_iso_resources rx_resources;
+ struct amdtp_stream tx_stream;
+ struct amdtp_stream rx_stream;
+ bool global_enabled;
+ struct completion clock_accepted;
+ unsigned int substreams_counter;
+};
+
+enum snd_dice_addr_type {
+ SND_DICE_ADDR_TYPE_PRIVATE,
+ SND_DICE_ADDR_TYPE_GLOBAL,
+ SND_DICE_ADDR_TYPE_TX,
+ SND_DICE_ADDR_TYPE_RX,
+ SND_DICE_ADDR_TYPE_SYNC,
+ SND_DICE_ADDR_TYPE_RSRV,
+};
+
+int snd_dice_transaction_write(struct snd_dice *dice,
+ enum snd_dice_addr_type type,
+ unsigned int offset,
+ void *buf, unsigned int len);
+int snd_dice_transaction_read(struct snd_dice *dice,
+ enum snd_dice_addr_type type, unsigned int offset,
+ void *buf, unsigned int len);
+
+static inline int snd_dice_transaction_write_global(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice,
+ SND_DICE_ADDR_TYPE_GLOBAL, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_global(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice,
+ SND_DICE_ADDR_TYPE_GLOBAL, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_write_tx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_TX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_tx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_TX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_write_rx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_RX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_rx(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_RX, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_write_sync(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_write(dice, SND_DICE_ADDR_TYPE_SYNC, offset,
+ buf, len);
+}
+static inline int snd_dice_transaction_read_sync(struct snd_dice *dice,
+ unsigned int offset,
+ void *buf, unsigned int len)
+{
+ return snd_dice_transaction_read(dice, SND_DICE_ADDR_TYPE_SYNC, offset,
+ buf, len);
+}
+
+int snd_dice_transaction_get_clock_source(struct snd_dice *dice,
+ unsigned int *source);
+int snd_dice_transaction_set_rate(struct snd_dice *dice, unsigned int rate);
+int snd_dice_transaction_get_rate(struct snd_dice *dice, unsigned int *rate);
+int snd_dice_transaction_set_enable(struct snd_dice *dice);
+void snd_dice_transaction_clear_enable(struct snd_dice *dice);
+int snd_dice_transaction_init(struct snd_dice *dice);
+int snd_dice_transaction_reinit(struct snd_dice *dice);
+void snd_dice_transaction_destroy(struct snd_dice *dice);
+
+#define SND_DICE_RATES_COUNT 7
+extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT];
+
+int snd_dice_stream_get_rate_mode(struct snd_dice *dice,
+ unsigned int rate, unsigned int *mode);
+
+int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate);
+void snd_dice_stream_stop_duplex(struct snd_dice *dice);
+int snd_dice_stream_init_duplex(struct snd_dice *dice);
+void snd_dice_stream_destroy_duplex(struct snd_dice *dice);
+void snd_dice_stream_update_duplex(struct snd_dice *dice);
+
+int snd_dice_stream_lock_try(struct snd_dice *dice);
+void snd_dice_stream_lock_release(struct snd_dice *dice);
+
+int snd_dice_create_pcm(struct snd_dice *dice);
+
+int snd_dice_create_hwdep(struct snd_dice *dice);
+
+void snd_dice_create_proc(struct snd_dice *dice);
+
+int snd_dice_create_midi(struct snd_dice *dice);
+
+#endif
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c
index 7ac9443..48d6dca 100644
--- a/sound/firewire/isight.c
+++ b/sound/firewire/isight.c
@@ -131,14 +131,8 @@ static void isight_samples(struct isight *isight,
static void isight_pcm_abort(struct isight *isight)
{
- unsigned long flags;
-
- if (ACCESS_ONCE(isight->pcm_active)) {
- snd_pcm_stream_lock_irqsave(isight->pcm, flags);
- if (snd_pcm_running(isight->pcm))
- snd_pcm_stop(isight->pcm, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(isight->pcm, flags);
- }
+ if (ACCESS_ONCE(isight->pcm_active))
+ snd_pcm_stop_xrun(isight->pcm);
}
static void isight_dropped_samples(struct isight *isight, unsigned int total)
diff --git a/sound/firewire/oxfw/Makefile b/sound/firewire/oxfw/Makefile
new file mode 100644
index 0000000..a926850
--- /dev/null
+++ b/sound/firewire/oxfw/Makefile
@@ -0,0 +1,3 @@
+snd-oxfw-objs := oxfw-command.o oxfw-stream.o oxfw-control.o oxfw-pcm.o \
+ oxfw-proc.o oxfw-midi.o oxfw-hwdep.o oxfw.o
+obj-m += snd-oxfw.o
diff --git a/sound/firewire/oxfw/oxfw-command.c b/sound/firewire/oxfw/oxfw-command.c
new file mode 100644
index 0000000..12ef325
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-command.c
@@ -0,0 +1,153 @@
+/*
+ * oxfw_command.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir,
+ unsigned int pid, u8 *format, unsigned int len)
+{
+ u8 *buf;
+ int err;
+
+ buf = kmalloc(len + 10, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf[0] = 0x00; /* CONTROL */
+ buf[1] = 0xff; /* UNIT */
+ buf[2] = 0xbf; /* EXTENDED STREAM FORMAT INFORMATION */
+ buf[3] = 0xc0; /* SINGLE subfunction */
+ buf[4] = dir; /* Plug Direction */
+ buf[5] = 0x00; /* UNIT */
+ buf[6] = 0x00; /* PCR (Isochronous Plug) */
+ buf[7] = 0xff & pid; /* Plug ID */
+ buf[8] = 0xff; /* Padding */
+ buf[9] = 0xff; /* Support status in response */
+ memcpy(buf + 10, format, len);
+
+ /* do transaction and check buf[1-8] are the same against command */
+ err = fcp_avc_transaction(unit, buf, len + 10, buf, len + 10,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+ BIT(6) | BIT(7) | BIT(8));
+ if ((err > 0) && (err < len + 10))
+ err = -EIO;
+ else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+ err = -ENOSYS;
+ else if (buf[0] == 0x0a) /* REJECTED */
+ err = -EINVAL;
+ else
+ err = 0;
+
+ kfree(buf);
+
+ return err;
+}
+
+int avc_stream_get_format(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len, unsigned int eid)
+{
+ unsigned int subfunc;
+ int err;
+
+ if (eid == 0xff)
+ subfunc = 0xc0; /* SINGLE */
+ else
+ subfunc = 0xc1; /* LIST */
+
+ buf[0] = 0x01; /* STATUS */
+ buf[1] = 0xff; /* UNIT */
+ buf[2] = 0xbf; /* EXTENDED STREAM FORMAT INFORMATION */
+ buf[3] = subfunc; /* SINGLE or LIST */
+ buf[4] = dir; /* Plug Direction */
+ buf[5] = 0x00; /* Unit */
+ buf[6] = 0x00; /* PCR (Isochronous Plug) */
+ buf[7] = 0xff & pid; /* Plug ID */
+ buf[8] = 0xff; /* Padding */
+ buf[9] = 0xff; /* support status in response */
+ buf[10] = 0xff & eid; /* entry ID for LIST subfunction */
+ buf[11] = 0xff; /* padding */
+
+ /* do transaction and check buf[1-7] are the same against command */
+ err = fcp_avc_transaction(unit, buf, 12, buf, *len,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5) |
+ BIT(6) | BIT(7));
+ if ((err > 0) && (err < 10))
+ err = -EIO;
+ else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+ err = -ENOSYS;
+ else if (buf[0] == 0x0a) /* REJECTED */
+ err = -EINVAL;
+ else if (buf[0] == 0x0b) /* IN TRANSITION */
+ err = -EAGAIN;
+ /* LIST subfunction has entry ID */
+ else if ((subfunc == 0xc1) && (buf[10] != eid))
+ err = -EIO;
+ if (err < 0)
+ goto end;
+
+ /* keep just stream format information */
+ if (subfunc == 0xc0) {
+ memmove(buf, buf + 10, err - 10);
+ *len = err - 10;
+ } else {
+ memmove(buf, buf + 11, err - 11);
+ *len = err - 11;
+ }
+
+ err = 0;
+end:
+ return err;
+}
+
+int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
+ enum avc_general_plug_dir dir,
+ unsigned short pid)
+{
+ unsigned int sfc;
+ u8 *buf;
+ int err;
+
+ for (sfc = 0; sfc < CIP_SFC_COUNT; sfc++) {
+ if (amdtp_rate_table[sfc] == rate)
+ break;
+ }
+ if (sfc == CIP_SFC_COUNT)
+ return -EINVAL;
+
+ buf = kzalloc(8, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ buf[0] = 0x02; /* SPECIFIC INQUIRY */
+ buf[1] = 0xff; /* UNIT */
+ if (dir == AVC_GENERAL_PLUG_DIR_IN)
+ buf[2] = 0x19; /* INPUT PLUG SIGNAL FORMAT */
+ else
+ buf[2] = 0x18; /* OUTPUT PLUG SIGNAL FORMAT */
+ buf[3] = 0xff & pid; /* plug id */
+ buf[4] = 0x90; /* EOH_1, Form_1, FMT. AM824 */
+ buf[5] = 0x07 & sfc; /* FDF-hi. AM824, frequency */
+ buf[6] = 0xff; /* FDF-mid. AM824, SYT hi (not used) */
+ buf[7] = 0xff; /* FDF-low. AM824, SYT lo (not used) */
+
+ /* do transaction and check buf[1-5] are the same against command */
+ err = fcp_avc_transaction(unit, buf, 8, buf, 8,
+ BIT(1) | BIT(2) | BIT(3) | BIT(4) | BIT(5));
+ if ((err > 0) && (err < 8))
+ err = -EIO;
+ else if (buf[0] == 0x08) /* NOT IMPLEMENTED */
+ err = -ENOSYS;
+ if (err < 0)
+ goto end;
+
+ err = 0;
+end:
+ kfree(buf);
+ return err;
+}
diff --git a/sound/firewire/oxfw/oxfw-control.c b/sound/firewire/oxfw/oxfw-control.c
new file mode 100644
index 0000000..02a1cb9
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-control.c
@@ -0,0 +1,283 @@
+/*
+ * oxfw_stream.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+enum control_action { CTL_READ, CTL_WRITE };
+enum control_attribute {
+ CTL_MIN = 0x02,
+ CTL_MAX = 0x03,
+ CTL_CURRENT = 0x10,
+};
+
+static int oxfw_mute_command(struct snd_oxfw *oxfw, bool *value,
+ enum control_action action)
+{
+ u8 *buf;
+ u8 response_ok;
+ int err;
+
+ buf = kmalloc(11, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (action == CTL_READ) {
+ buf[0] = 0x01; /* AV/C, STATUS */
+ response_ok = 0x0c; /* STABLE */
+ } else {
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ response_ok = 0x09; /* ACCEPTED */
+ }
+ buf[1] = 0x08; /* audio unit 0 */
+ buf[2] = 0xb8; /* FUNCTION BLOCK */
+ buf[3] = 0x81; /* function block type: feature */
+ buf[4] = oxfw->device_info->mute_fb_id; /* function block ID */
+ buf[5] = 0x10; /* control attribute: current */
+ buf[6] = 0x02; /* selector length */
+ buf[7] = 0x00; /* audio channel number */
+ buf[8] = 0x01; /* control selector: mute */
+ buf[9] = 0x01; /* control data length */
+ if (action == CTL_READ)
+ buf[10] = 0xff;
+ else
+ buf[10] = *value ? 0x70 : 0x60;
+
+ err = fcp_avc_transaction(oxfw->unit, buf, 11, buf, 11, 0x3fe);
+ if (err < 0)
+ goto error;
+ if (err < 11) {
+ dev_err(&oxfw->unit->device, "short FCP response\n");
+ err = -EIO;
+ goto error;
+ }
+ if (buf[0] != response_ok) {
+ dev_err(&oxfw->unit->device, "mute command failed\n");
+ err = -EIO;
+ goto error;
+ }
+ if (action == CTL_READ)
+ *value = buf[10] == 0x70;
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int oxfw_volume_command(struct snd_oxfw *oxfw, s16 *value,
+ unsigned int channel,
+ enum control_attribute attribute,
+ enum control_action action)
+{
+ u8 *buf;
+ u8 response_ok;
+ int err;
+
+ buf = kmalloc(12, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (action == CTL_READ) {
+ buf[0] = 0x01; /* AV/C, STATUS */
+ response_ok = 0x0c; /* STABLE */
+ } else {
+ buf[0] = 0x00; /* AV/C, CONTROL */
+ response_ok = 0x09; /* ACCEPTED */
+ }
+ buf[1] = 0x08; /* audio unit 0 */
+ buf[2] = 0xb8; /* FUNCTION BLOCK */
+ buf[3] = 0x81; /* function block type: feature */
+ buf[4] = oxfw->device_info->volume_fb_id; /* function block ID */
+ buf[5] = attribute; /* control attribute */
+ buf[6] = 0x02; /* selector length */
+ buf[7] = channel; /* audio channel number */
+ buf[8] = 0x02; /* control selector: volume */
+ buf[9] = 0x02; /* control data length */
+ if (action == CTL_READ) {
+ buf[10] = 0xff;
+ buf[11] = 0xff;
+ } else {
+ buf[10] = *value >> 8;
+ buf[11] = *value;
+ }
+
+ err = fcp_avc_transaction(oxfw->unit, buf, 12, buf, 12, 0x3fe);
+ if (err < 0)
+ goto error;
+ if (err < 12) {
+ dev_err(&oxfw->unit->device, "short FCP response\n");
+ err = -EIO;
+ goto error;
+ }
+ if (buf[0] != response_ok) {
+ dev_err(&oxfw->unit->device, "volume command failed\n");
+ err = -EIO;
+ goto error;
+ }
+ if (action == CTL_READ)
+ *value = (buf[10] << 8) | buf[11];
+
+ err = 0;
+
+error:
+ kfree(buf);
+
+ return err;
+}
+
+static int oxfw_mute_get(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+
+ value->value.integer.value[0] = !oxfw->mute;
+
+ return 0;
+}
+
+static int oxfw_mute_put(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+ bool mute;
+ int err;
+
+ mute = !value->value.integer.value[0];
+
+ if (mute == oxfw->mute)
+ return 0;
+
+ err = oxfw_mute_command(oxfw, &mute, CTL_WRITE);
+ if (err < 0)
+ return err;
+ oxfw->mute = mute;
+
+ return 1;
+}
+
+static int oxfw_volume_info(struct snd_kcontrol *control,
+ struct snd_ctl_elem_info *info)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+
+ info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ info->count = oxfw->device_info->mixer_channels;
+ info->value.integer.min = oxfw->volume_min;
+ info->value.integer.max = oxfw->volume_max;
+
+ return 0;
+}
+
+static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
+
+static int oxfw_volume_get(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+ unsigned int i;
+
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
+ value->value.integer.value[channel_map[i]] = oxfw->volume[i];
+
+ return 0;
+}
+
+static int oxfw_volume_put(struct snd_kcontrol *control,
+ struct snd_ctl_elem_value *value)
+{
+ struct snd_oxfw *oxfw = control->private_data;
+ unsigned int i, changed_channels;
+ bool equal_values = true;
+ s16 volume;
+ int err;
+
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
+ if (value->value.integer.value[i] < oxfw->volume_min ||
+ value->value.integer.value[i] > oxfw->volume_max)
+ return -EINVAL;
+ if (value->value.integer.value[i] !=
+ value->value.integer.value[0])
+ equal_values = false;
+ }
+
+ changed_channels = 0;
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i)
+ if (value->value.integer.value[channel_map[i]] !=
+ oxfw->volume[i])
+ changed_channels |= 1 << (i + 1);
+
+ if (equal_values && changed_channels != 0)
+ changed_channels = 1 << 0;
+
+ for (i = 0; i <= oxfw->device_info->mixer_channels; ++i) {
+ volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
+ if (changed_channels & (1 << i)) {
+ err = oxfw_volume_command(oxfw, &volume, i,
+ CTL_CURRENT, CTL_WRITE);
+ if (err < 0)
+ return err;
+ }
+ if (i > 0)
+ oxfw->volume[i - 1] = volume;
+ }
+
+ return changed_channels != 0;
+}
+
+int snd_oxfw_create_mixer(struct snd_oxfw *oxfw)
+{
+ static const struct snd_kcontrol_new controls[] = {
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Switch",
+ .info = snd_ctl_boolean_mono_info,
+ .get = oxfw_mute_get,
+ .put = oxfw_mute_put,
+ },
+ {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "PCM Playback Volume",
+ .info = oxfw_volume_info,
+ .get = oxfw_volume_get,
+ .put = oxfw_volume_put,
+ },
+ };
+ unsigned int i, first_ch;
+ int err;
+
+ err = oxfw_volume_command(oxfw, &oxfw->volume_min,
+ 0, CTL_MIN, CTL_READ);
+ if (err < 0)
+ return err;
+ err = oxfw_volume_command(oxfw, &oxfw->volume_max,
+ 0, CTL_MAX, CTL_READ);
+ if (err < 0)
+ return err;
+
+ err = oxfw_mute_command(oxfw, &oxfw->mute, CTL_READ);
+ if (err < 0)
+ return err;
+
+ first_ch = oxfw->device_info->mixer_channels == 1 ? 0 : 1;
+ for (i = 0; i < oxfw->device_info->mixer_channels; ++i) {
+ err = oxfw_volume_command(oxfw, &oxfw->volume[i],
+ first_ch + i, CTL_CURRENT, CTL_READ);
+ if (err < 0)
+ return err;
+ }
+
+ for (i = 0; i < ARRAY_SIZE(controls); ++i) {
+ err = snd_ctl_add(oxfw->card,
+ snd_ctl_new1(&controls[i], oxfw));
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw-hwdep.c b/sound/firewire/oxfw/oxfw-hwdep.c
new file mode 100644
index 0000000..ff2687a
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-hwdep.c
@@ -0,0 +1,190 @@
+/*
+ * oxfw_hwdep.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+/*
+ * This codes give three functionality.
+ *
+ * 1.get firewire node information
+ * 2.get notification about starting/stopping stream
+ * 3.lock/unlock stream
+ */
+
+#include "oxfw.h"
+
+static long hwdep_read(struct snd_hwdep *hwdep, char __user *buf, long count,
+ loff_t *offset)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+ DEFINE_WAIT(wait);
+ union snd_firewire_event event;
+
+ spin_lock_irq(&oxfw->lock);
+
+ while (!oxfw->dev_lock_changed) {
+ prepare_to_wait(&oxfw->hwdep_wait, &wait, TASK_INTERRUPTIBLE);
+ spin_unlock_irq(&oxfw->lock);
+ schedule();
+ finish_wait(&oxfw->hwdep_wait, &wait);
+ if (signal_pending(current))
+ return -ERESTARTSYS;
+ spin_lock_irq(&oxfw->lock);
+ }
+
+ memset(&event, 0, sizeof(event));
+ if (oxfw->dev_lock_changed) {
+ event.lock_status.type = SNDRV_FIREWIRE_EVENT_LOCK_STATUS;
+ event.lock_status.status = (oxfw->dev_lock_count > 0);
+ oxfw->dev_lock_changed = false;
+
+ count = min_t(long, count, sizeof(event.lock_status));
+ }
+
+ spin_unlock_irq(&oxfw->lock);
+
+ if (copy_to_user(buf, &event, count))
+ return -EFAULT;
+
+ return count;
+}
+
+static unsigned int hwdep_poll(struct snd_hwdep *hwdep, struct file *file,
+ poll_table *wait)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+ unsigned int events;
+
+ poll_wait(file, &oxfw->hwdep_wait, wait);
+
+ spin_lock_irq(&oxfw->lock);
+ if (oxfw->dev_lock_changed)
+ events = POLLIN | POLLRDNORM;
+ else
+ events = 0;
+ spin_unlock_irq(&oxfw->lock);
+
+ return events;
+}
+
+static int hwdep_get_info(struct snd_oxfw *oxfw, void __user *arg)
+{
+ struct fw_device *dev = fw_parent_device(oxfw->unit);
+ struct snd_firewire_get_info info;
+
+ memset(&info, 0, sizeof(info));
+ info.type = SNDRV_FIREWIRE_TYPE_OXFW;
+ info.card = dev->card->index;
+ *(__be32 *)&info.guid[0] = cpu_to_be32(dev->config_rom[3]);
+ *(__be32 *)&info.guid[4] = cpu_to_be32(dev->config_rom[4]);
+ strlcpy(info.device_name, dev_name(&dev->device),
+ sizeof(info.device_name));
+
+ if (copy_to_user(arg, &info, sizeof(info)))
+ return -EFAULT;
+
+ return 0;
+}
+
+static int hwdep_lock(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ spin_lock_irq(&oxfw->lock);
+
+ if (oxfw->dev_lock_count == 0) {
+ oxfw->dev_lock_count = -1;
+ err = 0;
+ } else {
+ err = -EBUSY;
+ }
+
+ spin_unlock_irq(&oxfw->lock);
+
+ return err;
+}
+
+static int hwdep_unlock(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ spin_lock_irq(&oxfw->lock);
+
+ if (oxfw->dev_lock_count == -1) {
+ oxfw->dev_lock_count = 0;
+ err = 0;
+ } else {
+ err = -EBADFD;
+ }
+
+ spin_unlock_irq(&oxfw->lock);
+
+ return err;
+}
+
+static int hwdep_release(struct snd_hwdep *hwdep, struct file *file)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+
+ spin_lock_irq(&oxfw->lock);
+ if (oxfw->dev_lock_count == -1)
+ oxfw->dev_lock_count = 0;
+ spin_unlock_irq(&oxfw->lock);
+
+ return 0;
+}
+
+static int hwdep_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ struct snd_oxfw *oxfw = hwdep->private_data;
+
+ switch (cmd) {
+ case SNDRV_FIREWIRE_IOCTL_GET_INFO:
+ return hwdep_get_info(oxfw, (void __user *)arg);
+ case SNDRV_FIREWIRE_IOCTL_LOCK:
+ return hwdep_lock(oxfw);
+ case SNDRV_FIREWIRE_IOCTL_UNLOCK:
+ return hwdep_unlock(oxfw);
+ default:
+ return -ENOIOCTLCMD;
+ }
+}
+
+#ifdef CONFIG_COMPAT
+static int hwdep_compat_ioctl(struct snd_hwdep *hwdep, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return hwdep_ioctl(hwdep, file, cmd,
+ (unsigned long)compat_ptr(arg));
+}
+#else
+#define hwdep_compat_ioctl NULL
+#endif
+
+int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw)
+{
+ static const struct snd_hwdep_ops hwdep_ops = {
+ .read = hwdep_read,
+ .release = hwdep_release,
+ .poll = hwdep_poll,
+ .ioctl = hwdep_ioctl,
+ .ioctl_compat = hwdep_compat_ioctl,
+ };
+ struct snd_hwdep *hwdep;
+ int err;
+
+ err = snd_hwdep_new(oxfw->card, oxfw->card->driver, 0, &hwdep);
+ if (err < 0)
+ goto end;
+ strcpy(hwdep->name, oxfw->card->driver);
+ hwdep->iface = SNDRV_HWDEP_IFACE_FW_OXFW;
+ hwdep->ops = hwdep_ops;
+ hwdep->private_data = oxfw;
+ hwdep->exclusive = true;
+end:
+ return err;
+}
diff --git a/sound/firewire/oxfw/oxfw-midi.c b/sound/firewire/oxfw/oxfw-midi.c
new file mode 100644
index 0000000..540a303
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-midi.c
@@ -0,0 +1,207 @@
+/*
+ * oxfw_midi.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+static int midi_capture_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+ int err;
+
+ err = snd_oxfw_stream_lock_try(oxfw);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->capture_substreams++;
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream, 0, 0);
+
+ mutex_unlock(&oxfw->mutex);
+
+ if (err < 0)
+ snd_oxfw_stream_lock_release(oxfw);
+
+ return err;
+}
+
+static int midi_playback_open(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+ int err;
+
+ err = snd_oxfw_stream_lock_try(oxfw);
+ if (err < 0)
+ return err;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->playback_substreams++;
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream, 0, 0);
+
+ mutex_unlock(&oxfw->mutex);
+
+ if (err < 0)
+ snd_oxfw_stream_lock_release(oxfw);
+
+ return err;
+}
+
+static int midi_capture_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->capture_substreams--;
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ snd_oxfw_stream_lock_release(oxfw);
+ return 0;
+}
+
+static int midi_playback_close(struct snd_rawmidi_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->rmidi->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ oxfw->playback_substreams--;
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ snd_oxfw_stream_lock_release(oxfw);
+ return 0;
+}
+
+static void midi_capture_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_oxfw *oxfw = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oxfw->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&oxfw->tx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&oxfw->tx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&oxfw->lock, flags);
+}
+
+static void midi_playback_trigger(struct snd_rawmidi_substream *substrm, int up)
+{
+ struct snd_oxfw *oxfw = substrm->rmidi->private_data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&oxfw->lock, flags);
+
+ if (up)
+ amdtp_stream_midi_trigger(&oxfw->rx_stream,
+ substrm->number, substrm);
+ else
+ amdtp_stream_midi_trigger(&oxfw->rx_stream,
+ substrm->number, NULL);
+
+ spin_unlock_irqrestore(&oxfw->lock, flags);
+}
+
+static struct snd_rawmidi_ops midi_capture_ops = {
+ .open = midi_capture_open,
+ .close = midi_capture_close,
+ .trigger = midi_capture_trigger,
+};
+
+static struct snd_rawmidi_ops midi_playback_ops = {
+ .open = midi_playback_open,
+ .close = midi_playback_close,
+ .trigger = midi_playback_trigger,
+};
+
+static void set_midi_substream_names(struct snd_oxfw *oxfw,
+ struct snd_rawmidi_str *str)
+{
+ struct snd_rawmidi_substream *subs;
+
+ list_for_each_entry(subs, &str->substreams, list) {
+ snprintf(subs->name, sizeof(subs->name),
+ "%s MIDI %d",
+ oxfw->card->shortname, subs->number + 1);
+ }
+}
+
+int snd_oxfw_create_midi(struct snd_oxfw *oxfw)
+{
+ struct snd_oxfw_stream_formation formation;
+ struct snd_rawmidi *rmidi;
+ struct snd_rawmidi_str *str;
+ u8 *format;
+ int i, err;
+
+ /* If its stream has MIDI conformant data channel, add one MIDI port */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ format = oxfw->tx_stream_formats[i];
+ if (format != NULL) {
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err >= 0 && formation.midi > 0)
+ oxfw->midi_input_ports = 1;
+ }
+
+ format = oxfw->rx_stream_formats[i];
+ if (format != NULL) {
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err >= 0 && formation.midi > 0)
+ oxfw->midi_output_ports = 1;
+ }
+ }
+ if ((oxfw->midi_input_ports == 0) && (oxfw->midi_output_ports == 0))
+ return 0;
+
+ /* create midi ports */
+ err = snd_rawmidi_new(oxfw->card, oxfw->card->driver, 0,
+ oxfw->midi_output_ports, oxfw->midi_input_ports,
+ &rmidi);
+ if (err < 0)
+ return err;
+
+ snprintf(rmidi->name, sizeof(rmidi->name),
+ "%s MIDI", oxfw->card->shortname);
+ rmidi->private_data = oxfw;
+
+ if (oxfw->midi_input_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_INPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_INPUT,
+ &midi_capture_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_INPUT];
+
+ set_midi_substream_names(oxfw, str);
+ }
+
+ if (oxfw->midi_output_ports > 0) {
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT;
+
+ snd_rawmidi_set_ops(rmidi, SNDRV_RAWMIDI_STREAM_OUTPUT,
+ &midi_playback_ops);
+
+ str = &rmidi->streams[SNDRV_RAWMIDI_STREAM_OUTPUT];
+
+ set_midi_substream_names(oxfw, str);
+ }
+
+ if ((oxfw->midi_output_ports > 0) && (oxfw->midi_input_ports > 0))
+ rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
+
+ return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw-pcm.c b/sound/firewire/oxfw/oxfw-pcm.c
new file mode 100644
index 0000000..9bc556b
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-pcm.c
@@ -0,0 +1,424 @@
+/*
+ * oxfw_pcm.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+static int hw_rule_rate(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ u8 **formats = rule->private;
+ struct snd_interval *r =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
+ const struct snd_interval *c =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ struct snd_interval t = {
+ .min = UINT_MAX, .max = 0, .integer = 1
+ };
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, err;
+
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ continue;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ continue;
+ if (!snd_interval_test(c, formation.pcm))
+ continue;
+
+ t.min = min(t.min, formation.rate);
+ t.max = max(t.max, formation.rate);
+
+ }
+ return snd_interval_refine(r, &t);
+}
+
+static int hw_rule_channels(struct snd_pcm_hw_params *params,
+ struct snd_pcm_hw_rule *rule)
+{
+ u8 **formats = rule->private;
+ struct snd_interval *c =
+ hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
+ const struct snd_interval *r =
+ hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, j, err;
+ unsigned int count, list[SND_OXFW_STREAM_FORMAT_ENTRIES] = {0};
+
+ count = 0;
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ continue;
+ if (!snd_interval_test(r, formation.rate))
+ continue;
+ if (list[count] == formation.pcm)
+ continue;
+
+ for (j = 0; j < ARRAY_SIZE(list); j++) {
+ if (list[j] == formation.pcm)
+ break;
+ }
+ if (j == ARRAY_SIZE(list)) {
+ list[count] = formation.pcm;
+ if (++count == ARRAY_SIZE(list))
+ break;
+ }
+ }
+
+ return snd_interval_list(c, count, list, 0);
+}
+
+static void limit_channels_and_rates(struct snd_pcm_hardware *hw, u8 **formats)
+{
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, err;
+
+ hw->channels_min = UINT_MAX;
+ hw->channels_max = 0;
+
+ hw->rate_min = UINT_MAX;
+ hw->rate_max = 0;
+ hw->rates = 0;
+
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ continue;
+
+ hw->channels_min = min(hw->channels_min, formation.pcm);
+ hw->channels_max = max(hw->channels_max, formation.pcm);
+
+ hw->rate_min = min(hw->rate_min, formation.rate);
+ hw->rate_max = max(hw->rate_max, formation.rate);
+ hw->rates |= snd_pcm_rate_to_rate_bit(formation.rate);
+ }
+}
+
+static void limit_period_and_buffer(struct snd_pcm_hardware *hw)
+{
+ hw->periods_min = 2; /* SNDRV_PCM_INFO_BATCH */
+ hw->periods_max = UINT_MAX;
+
+ hw->period_bytes_min = 4 * hw->channels_max; /* bytes for a frame */
+
+ /* Just to prevent from allocating much pages. */
+ hw->period_bytes_max = hw->period_bytes_min * 2048;
+ hw->buffer_bytes_max = hw->period_bytes_max * hw->periods_min;
+}
+
+static int init_hw_params(struct snd_oxfw *oxfw,
+ struct snd_pcm_substream *substream)
+{
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ u8 **formats;
+ struct amdtp_stream *stream;
+ int err;
+
+ runtime->hw.info = SNDRV_PCM_INFO_BATCH |
+ SNDRV_PCM_INFO_BLOCK_TRANSFER |
+ SNDRV_PCM_INFO_INTERLEAVED |
+ SNDRV_PCM_INFO_JOINT_DUPLEX |
+ SNDRV_PCM_INFO_MMAP |
+ SNDRV_PCM_INFO_MMAP_VALID;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) {
+ runtime->hw.formats = AMDTP_IN_PCM_FORMAT_BITS;
+ stream = &oxfw->tx_stream;
+ formats = oxfw->tx_stream_formats;
+ } else {
+ runtime->hw.formats = AMDTP_OUT_PCM_FORMAT_BITS;
+ stream = &oxfw->rx_stream;
+ formats = oxfw->rx_stream_formats;
+ }
+
+ limit_channels_and_rates(&runtime->hw, formats);
+ limit_period_and_buffer(&runtime->hw);
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
+ hw_rule_channels, formats,
+ SNDRV_PCM_HW_PARAM_RATE, -1);
+ if (err < 0)
+ goto end;
+
+ err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
+ hw_rule_rate, formats,
+ SNDRV_PCM_HW_PARAM_CHANNELS, -1);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_add_pcm_hw_constraints(stream, runtime);
+end:
+ return err;
+}
+
+static int limit_to_current_params(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ int err;
+
+ if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ else
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+
+ err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
+ if (err < 0)
+ goto end;
+
+ substream->runtime->hw.channels_min = formation.pcm;
+ substream->runtime->hw.channels_max = formation.pcm;
+ substream->runtime->hw.rate_min = formation.rate;
+ substream->runtime->hw.rate_max = formation.rate;
+end:
+ return err;
+}
+
+static int pcm_open(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ int err;
+
+ err = snd_oxfw_stream_lock_try(oxfw);
+ if (err < 0)
+ goto end;
+
+ err = init_hw_params(oxfw, substream);
+ if (err < 0)
+ goto err_locked;
+
+ /*
+ * When any PCM streams are already running, the available sampling
+ * rate is limited at current value.
+ */
+ if (amdtp_stream_pcm_running(&oxfw->tx_stream) ||
+ amdtp_stream_pcm_running(&oxfw->rx_stream)) {
+ err = limit_to_current_params(substream);
+ if (err < 0)
+ goto end;
+ }
+
+ snd_pcm_set_sync(substream);
+end:
+ return err;
+err_locked:
+ snd_oxfw_stream_lock_release(oxfw);
+ return err;
+}
+
+static int pcm_close(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ snd_oxfw_stream_lock_release(oxfw);
+ return 0;
+}
+
+static int pcm_capture_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&oxfw->mutex);
+ oxfw->capture_substreams++;
+ mutex_unlock(&oxfw->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&oxfw->tx_stream, params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+static int pcm_playback_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *hw_params)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN) {
+ mutex_lock(&oxfw->mutex);
+ oxfw->playback_substreams++;
+ mutex_unlock(&oxfw->mutex);
+ }
+
+ amdtp_stream_set_pcm_format(&oxfw->rx_stream, params_format(hw_params));
+
+ return snd_pcm_lib_alloc_vmalloc_buffer(substream,
+ params_buffer_bytes(hw_params));
+}
+
+static int pcm_capture_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ oxfw->capture_substreams--;
+
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->tx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+static int pcm_playback_hw_free(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+
+ mutex_lock(&oxfw->mutex);
+
+ if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
+ oxfw->playback_substreams--;
+
+ snd_oxfw_stream_stop_simplex(oxfw, &oxfw->rx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+
+ return snd_pcm_lib_free_vmalloc_buffer(substream);
+}
+
+static int pcm_capture_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ mutex_lock(&oxfw->mutex);
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->tx_stream,
+ runtime->rate, runtime->channels);
+ mutex_unlock(&oxfw->mutex);
+ if (err < 0)
+ goto end;
+
+ amdtp_stream_pcm_prepare(&oxfw->tx_stream);
+end:
+ return err;
+}
+static int pcm_playback_prepare(struct snd_pcm_substream *substream)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_runtime *runtime = substream->runtime;
+ int err;
+
+ mutex_lock(&oxfw->mutex);
+ err = snd_oxfw_stream_start_simplex(oxfw, &oxfw->rx_stream,
+ runtime->rate, runtime->channels);
+ mutex_unlock(&oxfw->mutex);
+ if (err < 0)
+ goto end;
+
+ amdtp_stream_pcm_prepare(&oxfw->rx_stream);
+end:
+ return err;
+}
+
+static int pcm_capture_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_substream *pcm;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pcm = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pcm = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amdtp_stream_pcm_trigger(&oxfw->tx_stream, pcm);
+ return 0;
+}
+static int pcm_playback_trigger(struct snd_pcm_substream *substream, int cmd)
+{
+ struct snd_oxfw *oxfw = substream->private_data;
+ struct snd_pcm_substream *pcm;
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ pcm = substream;
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ pcm = NULL;
+ break;
+ default:
+ return -EINVAL;
+ }
+ amdtp_stream_pcm_trigger(&oxfw->rx_stream, pcm);
+ return 0;
+}
+
+static snd_pcm_uframes_t pcm_capture_pointer(struct snd_pcm_substream *sbstm)
+{
+ struct snd_oxfw *oxfw = sbstm->private_data;
+
+ return amdtp_stream_pcm_pointer(&oxfw->tx_stream);
+}
+static snd_pcm_uframes_t pcm_playback_pointer(struct snd_pcm_substream *sbstm)
+{
+ struct snd_oxfw *oxfw = sbstm->private_data;
+
+ return amdtp_stream_pcm_pointer(&oxfw->rx_stream);
+}
+
+int snd_oxfw_create_pcm(struct snd_oxfw *oxfw)
+{
+ static struct snd_pcm_ops capture_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_capture_hw_params,
+ .hw_free = pcm_capture_hw_free,
+ .prepare = pcm_capture_prepare,
+ .trigger = pcm_capture_trigger,
+ .pointer = pcm_capture_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ static struct snd_pcm_ops playback_ops = {
+ .open = pcm_open,
+ .close = pcm_close,
+ .ioctl = snd_pcm_lib_ioctl,
+ .hw_params = pcm_playback_hw_params,
+ .hw_free = pcm_playback_hw_free,
+ .prepare = pcm_playback_prepare,
+ .trigger = pcm_playback_trigger,
+ .pointer = pcm_playback_pointer,
+ .page = snd_pcm_lib_get_vmalloc_page,
+ .mmap = snd_pcm_lib_mmap_vmalloc,
+ };
+ struct snd_pcm *pcm;
+ unsigned int cap = 0;
+ int err;
+
+ if (oxfw->has_output)
+ cap = 1;
+
+ err = snd_pcm_new(oxfw->card, oxfw->card->driver, 0, 1, cap, &pcm);
+ if (err < 0)
+ return err;
+
+ pcm->private_data = oxfw;
+ strcpy(pcm->name, oxfw->card->shortname);
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &playback_ops);
+ if (cap > 0)
+ snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &capture_ops);
+
+ return 0;
+}
diff --git a/sound/firewire/oxfw/oxfw-proc.c b/sound/firewire/oxfw/oxfw-proc.c
new file mode 100644
index 0000000..604808e
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-proc.c
@@ -0,0 +1,113 @@
+/*
+ * oxfw_proc.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "./oxfw.h"
+
+static void proc_read_formation(struct snd_info_entry *entry,
+ struct snd_info_buffer *buffer)
+{
+ struct snd_oxfw *oxfw = entry->private_data;
+ struct snd_oxfw_stream_formation formation, curr;
+ u8 *format;
+ char flag;
+ unsigned int i, err;
+
+ /* Show input. */
+ err = snd_oxfw_stream_get_current_formation(oxfw,
+ AVC_GENERAL_PLUG_DIR_IN,
+ &curr);
+ if (err < 0)
+ return;
+
+ snd_iprintf(buffer, "Input Stream to device:\n");
+ snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ format = oxfw->rx_stream_formats[i];
+ if (format == NULL)
+ continue;
+
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err < 0)
+ continue;
+
+ if (memcmp(&formation, &curr, sizeof(curr)) == 0)
+ flag = '*';
+ else
+ flag = ' ';
+
+ snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
+ formation.rate, formation.pcm, formation.midi);
+ }
+
+ if (!oxfw->has_output)
+ return;
+
+ /* Show output. */
+ err = snd_oxfw_stream_get_current_formation(oxfw,
+ AVC_GENERAL_PLUG_DIR_OUT,
+ &curr);
+ if (err < 0)
+ return;
+
+ snd_iprintf(buffer, "Output Stream from device:\n");
+ snd_iprintf(buffer, "\tRate\tPCM\tMIDI\n");
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ format = oxfw->tx_stream_formats[i];
+ if (format == NULL)
+ continue;
+
+ err = snd_oxfw_stream_parse_format(format, &formation);
+ if (err < 0)
+ continue;
+
+ if (memcmp(&formation, &curr, sizeof(curr)) == 0)
+ flag = '*';
+ else
+ flag = ' ';
+
+ snd_iprintf(buffer, "%c\t%d\t%d\t%d\n", flag,
+ formation.rate, formation.pcm, formation.midi);
+ }
+}
+
+static void add_node(struct snd_oxfw *oxfw, struct snd_info_entry *root,
+ const char *name,
+ void (*op)(struct snd_info_entry *e,
+ struct snd_info_buffer *b))
+{
+ struct snd_info_entry *entry;
+
+ entry = snd_info_create_card_entry(oxfw->card, name, root);
+ if (entry == NULL)
+ return;
+
+ snd_info_set_text_ops(entry, oxfw, op);
+ if (snd_info_register(entry) < 0)
+ snd_info_free_entry(entry);
+}
+
+void snd_oxfw_proc_init(struct snd_oxfw *oxfw)
+{
+ struct snd_info_entry *root;
+
+ /*
+ * All nodes are automatically removed at snd_card_disconnect(),
+ * by following to link list.
+ */
+ root = snd_info_create_card_entry(oxfw->card, "firewire",
+ oxfw->card->proc_root);
+ if (root == NULL)
+ return;
+ root->mode = S_IFDIR | S_IRUGO | S_IXUGO;
+ if (snd_info_register(root) < 0) {
+ snd_info_free_entry(root);
+ return;
+ }
+
+ add_node(oxfw, root, "formation", proc_read_formation);
+}
diff --git a/sound/firewire/oxfw/oxfw-stream.c b/sound/firewire/oxfw/oxfw-stream.c
new file mode 100644
index 0000000..b77cf80
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw-stream.c
@@ -0,0 +1,685 @@
+/*
+ * oxfw_stream.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) 2014 Takashi Sakamoto
+ *
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+#include <linux/delay.h>
+
+#define AVC_GENERIC_FRAME_MAXIMUM_BYTES 512
+#define CALLBACK_TIMEOUT 200
+
+/*
+ * According to datasheet of Oxford Semiconductor:
+ * OXFW970: 32.0/44.1/48.0/96.0 Khz, 8 audio channels I/O
+ * OXFW971: 32.0/44.1/48.0/88.2/96.0/192.0 kHz, 16 audio channels I/O, MIDI I/O
+ */
+static const unsigned int oxfw_rate_table[] = {
+ [0] = 32000,
+ [1] = 44100,
+ [2] = 48000,
+ [3] = 88200,
+ [4] = 96000,
+ [5] = 192000,
+};
+
+/*
+ * See Table 5.7 – Sampling frequency for Multi-bit Audio
+ * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
+ */
+static const unsigned int avc_stream_rate_table[] = {
+ [0] = 0x02,
+ [1] = 0x03,
+ [2] = 0x04,
+ [3] = 0x0a,
+ [4] = 0x05,
+ [5] = 0x07,
+};
+
+static int set_rate(struct snd_oxfw *oxfw, unsigned int rate)
+{
+ int err;
+
+ err = avc_general_set_sig_fmt(oxfw->unit, rate,
+ AVC_GENERAL_PLUG_DIR_IN, 0);
+ if (err < 0)
+ goto end;
+
+ if (oxfw->has_output)
+ err = avc_general_set_sig_fmt(oxfw->unit, rate,
+ AVC_GENERAL_PLUG_DIR_OUT, 0);
+end:
+ return err;
+}
+
+static int set_stream_format(struct snd_oxfw *oxfw, struct amdtp_stream *s,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ u8 **formats;
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ unsigned int i, err, len;
+
+ if (s == &oxfw->tx_stream) {
+ formats = oxfw->tx_stream_formats;
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ } else {
+ formats = oxfw->rx_stream_formats;
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+ }
+
+ /* Seek stream format for requirements. */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ return err;
+
+ if ((formation.rate == rate) && (formation.pcm == pcm_channels))
+ break;
+ }
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES)
+ return -EINVAL;
+
+ /* If assumed, just change rate. */
+ if (oxfw->assumed)
+ return set_rate(oxfw, rate);
+
+ /* Calculate format length. */
+ len = 5 + formats[i][4] * 2;
+
+ err = avc_stream_set_format(oxfw->unit, dir, 0, formats[i], len);
+ if (err < 0)
+ return err;
+
+ /* Some requests just after changing format causes freezing. */
+ msleep(100);
+
+ return 0;
+}
+
+static void stop_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream)
+{
+ amdtp_stream_pcm_abort(stream);
+ amdtp_stream_stop(stream);
+
+ if (stream == &oxfw->tx_stream)
+ cmp_connection_break(&oxfw->out_conn);
+ else
+ cmp_connection_break(&oxfw->in_conn);
+}
+
+static int start_stream(struct snd_oxfw *oxfw, struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ u8 **formats;
+ struct cmp_connection *conn;
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, midi_ports;
+ int err;
+
+ if (stream == &oxfw->rx_stream) {
+ formats = oxfw->rx_stream_formats;
+ conn = &oxfw->in_conn;
+ } else {
+ formats = oxfw->tx_stream_formats;
+ conn = &oxfw->out_conn;
+ }
+
+ /* Get stream format */
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ if (formats[i] == NULL)
+ break;
+
+ err = snd_oxfw_stream_parse_format(formats[i], &formation);
+ if (err < 0)
+ goto end;
+ if (rate != formation.rate)
+ continue;
+ if (pcm_channels == 0 || pcm_channels == formation.pcm)
+ break;
+ }
+ if (i == SND_OXFW_STREAM_FORMAT_ENTRIES) {
+ err = -EINVAL;
+ goto end;
+ }
+
+ pcm_channels = formation.pcm;
+ midi_ports = DIV_ROUND_UP(formation.midi, 8);
+
+ /* The stream should have one pcm channels at least */
+ if (pcm_channels == 0) {
+ err = -EINVAL;
+ goto end;
+ }
+ amdtp_stream_set_parameters(stream, rate, pcm_channels, midi_ports);
+
+ err = cmp_connection_establish(conn,
+ amdtp_stream_get_max_payload(stream));
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_start(stream,
+ conn->resources.channel,
+ conn->speed);
+ if (err < 0) {
+ cmp_connection_break(conn);
+ goto end;
+ }
+
+ /* Wait first packet */
+ err = amdtp_stream_wait_callback(stream, CALLBACK_TIMEOUT);
+ if (err < 0)
+ stop_stream(oxfw, stream);
+end:
+ return err;
+}
+
+static int check_connection_used_by_others(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+ bool used;
+ int err;
+
+ if (stream == &oxfw->tx_stream)
+ conn = &oxfw->out_conn;
+ else
+ conn = &oxfw->in_conn;
+
+ err = cmp_connection_check_used(conn, &used);
+ if ((err >= 0) && used && !amdtp_stream_running(stream)) {
+ dev_err(&oxfw->unit->device,
+ "Connection established by others: %cPCR[%d]\n",
+ (conn->direction == CMP_OUTPUT) ? 'o' : 'i',
+ conn->pcr_index);
+ err = -EBUSY;
+ }
+
+ return err;
+}
+
+int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+ enum cmp_direction c_dir;
+ enum amdtp_stream_direction s_dir;
+ int err;
+
+ if (stream == &oxfw->tx_stream) {
+ conn = &oxfw->out_conn;
+ c_dir = CMP_OUTPUT;
+ s_dir = AMDTP_IN_STREAM;
+ } else {
+ conn = &oxfw->in_conn;
+ c_dir = CMP_INPUT;
+ s_dir = AMDTP_OUT_STREAM;
+ }
+
+ err = cmp_connection_init(conn, oxfw->unit, c_dir, 0);
+ if (err < 0)
+ goto end;
+
+ err = amdtp_stream_init(stream, oxfw->unit, s_dir, CIP_NONBLOCKING);
+ if (err < 0) {
+ amdtp_stream_destroy(stream);
+ cmp_connection_destroy(conn);
+ goto end;
+ }
+
+ /* OXFW starts to transmit packets with non-zero dbc. */
+ if (stream == &oxfw->tx_stream)
+ oxfw->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK;
+end:
+ return err;
+}
+
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels)
+{
+ struct amdtp_stream *opposite;
+ struct snd_oxfw_stream_formation formation;
+ enum avc_general_plug_dir dir;
+ unsigned int substreams, opposite_substreams;
+ int err = 0;
+
+ if (stream == &oxfw->tx_stream) {
+ substreams = oxfw->capture_substreams;
+ opposite = &oxfw->rx_stream;
+ opposite_substreams = oxfw->playback_substreams;
+ dir = AVC_GENERAL_PLUG_DIR_OUT;
+ } else {
+ substreams = oxfw->playback_substreams;
+ opposite_substreams = oxfw->capture_substreams;
+
+ if (oxfw->has_output)
+ opposite = &oxfw->rx_stream;
+ else
+ opposite = NULL;
+
+ dir = AVC_GENERAL_PLUG_DIR_IN;
+ }
+
+ if (substreams == 0)
+ goto end;
+
+ /*
+ * Considering JACK/FFADO streaming:
+ * TODO: This can be removed hwdep functionality becomes popular.
+ */
+ err = check_connection_used_by_others(oxfw, stream);
+ if (err < 0)
+ goto end;
+
+ /* packet queueing error */
+ if (amdtp_streaming_error(stream))
+ stop_stream(oxfw, stream);
+
+ err = snd_oxfw_stream_get_current_formation(oxfw, dir, &formation);
+ if (err < 0)
+ goto end;
+ if (rate == 0)
+ rate = formation.rate;
+ if (pcm_channels == 0)
+ pcm_channels = formation.pcm;
+
+ if ((formation.rate != rate) || (formation.pcm != pcm_channels)) {
+ if (opposite != NULL) {
+ err = check_connection_used_by_others(oxfw, opposite);
+ if (err < 0)
+ goto end;
+ stop_stream(oxfw, opposite);
+ }
+ stop_stream(oxfw, stream);
+
+ err = set_stream_format(oxfw, stream, rate, pcm_channels);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to set stream format: %d\n", err);
+ goto end;
+ }
+
+ /* Start opposite stream if needed. */
+ if (opposite && !amdtp_stream_running(opposite) &&
+ (opposite_substreams > 0)) {
+ err = start_stream(oxfw, opposite, rate, 0);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to restart stream: %d\n", err);
+ goto end;
+ }
+ }
+ }
+
+ /* Start requested stream. */
+ if (!amdtp_stream_running(stream)) {
+ err = start_stream(oxfw, stream, rate, pcm_channels);
+ if (err < 0)
+ dev_err(&oxfw->unit->device,
+ "fail to start stream: %d\n", err);
+ }
+end:
+ return err;
+}
+
+void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ if (((stream == &oxfw->tx_stream) && (oxfw->capture_substreams > 0)) ||
+ ((stream == &oxfw->rx_stream) && (oxfw->playback_substreams > 0)))
+ return;
+
+ stop_stream(oxfw, stream);
+}
+
+void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+
+ if (stream == &oxfw->tx_stream)
+ conn = &oxfw->out_conn;
+ else
+ conn = &oxfw->in_conn;
+
+ stop_stream(oxfw, stream);
+
+ amdtp_stream_destroy(stream);
+ cmp_connection_destroy(conn);
+}
+
+void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream)
+{
+ struct cmp_connection *conn;
+
+ if (stream == &oxfw->tx_stream)
+ conn = &oxfw->out_conn;
+ else
+ conn = &oxfw->in_conn;
+
+ if (cmp_connection_update(conn) < 0)
+ stop_stream(oxfw, stream);
+ else
+ amdtp_stream_update(stream);
+}
+
+int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
+ enum avc_general_plug_dir dir,
+ struct snd_oxfw_stream_formation *formation)
+{
+ u8 *format;
+ unsigned int len;
+ int err;
+
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ format = kmalloc(len, GFP_KERNEL);
+ if (format == NULL)
+ return -ENOMEM;
+
+ err = avc_stream_get_format_single(oxfw->unit, dir, 0, format, &len);
+ if (err < 0)
+ goto end;
+ if (len < 3) {
+ err = -EIO;
+ goto end;
+ }
+
+ err = snd_oxfw_stream_parse_format(format, formation);
+end:
+ kfree(format);
+ return err;
+}
+
+/*
+ * See Table 6.16 - AM824 Stream Format
+ * Figure 6.19 - format_information field for AM824 Compound
+ * in AV/C Stream Format Information Specification 1.1 (Apr 2005, 1394TA)
+ * Also 'Clause 12 AM824 sequence adaption layers' in IEC 61883-6:2005
+ */
+int snd_oxfw_stream_parse_format(u8 *format,
+ struct snd_oxfw_stream_formation *formation)
+{
+ unsigned int i, e, channels, type;
+
+ memset(formation, 0, sizeof(struct snd_oxfw_stream_formation));
+
+ /*
+ * this module can support a hierarchy combination that:
+ * Root: Audio and Music (0x90)
+ * Level 1: AM824 Compound (0x40)
+ */
+ if ((format[0] != 0x90) || (format[1] != 0x40))
+ return -ENOSYS;
+
+ /* check the sampling rate */
+ for (i = 0; i < ARRAY_SIZE(avc_stream_rate_table); i++) {
+ if (format[2] == avc_stream_rate_table[i])
+ break;
+ }
+ if (i == ARRAY_SIZE(avc_stream_rate_table))
+ return -ENOSYS;
+
+ formation->rate = oxfw_rate_table[i];
+
+ for (e = 0; e < format[4]; e++) {
+ channels = format[5 + e * 2];
+ type = format[6 + e * 2];
+
+ switch (type) {
+ /* IEC 60958 Conformant, currently handled as MBLA */
+ case 0x00:
+ /* Multi Bit Linear Audio (Raw) */
+ case 0x06:
+ formation->pcm += channels;
+ break;
+ /* MIDI Conformant */
+ case 0x0d:
+ formation->midi = channels;
+ break;
+ /* IEC 61937-3 to 7 */
+ case 0x01:
+ case 0x02:
+ case 0x03:
+ case 0x04:
+ case 0x05:
+ /* Multi Bit Linear Audio */
+ case 0x07: /* DVD-Audio */
+ case 0x0c: /* High Precision */
+ /* One Bit Audio */
+ case 0x08: /* (Plain) Raw */
+ case 0x09: /* (Plain) SACD */
+ case 0x0a: /* (Encoded) Raw */
+ case 0x0b: /* (Encoded) SACD */
+ /* SMPTE Time-Code conformant */
+ case 0x0e:
+ /* Sample Count */
+ case 0x0f:
+ /* Anciliary Data */
+ case 0x10:
+ /* Synchronization Stream (Stereo Raw audio) */
+ case 0x40:
+ /* Don't care */
+ case 0xff:
+ default:
+ return -ENOSYS; /* not supported */
+ }
+ }
+
+ if (formation->pcm > AMDTP_MAX_CHANNELS_FOR_PCM ||
+ formation->midi > AMDTP_MAX_CHANNELS_FOR_MIDI)
+ return -ENOSYS;
+
+ return 0;
+}
+
+static int
+assume_stream_formats(struct snd_oxfw *oxfw, enum avc_general_plug_dir dir,
+ unsigned int pid, u8 *buf, unsigned int *len,
+ u8 **formats)
+{
+ struct snd_oxfw_stream_formation formation;
+ unsigned int i, eid;
+ int err;
+
+ /* get format at current sampling rate */
+ err = avc_stream_get_format_single(oxfw->unit, dir, pid, buf, len);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get current stream format for isoc %s plug %d:%d\n",
+ (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
+ pid, err);
+ goto end;
+ }
+
+ /* parse and set stream format */
+ eid = 0;
+ err = snd_oxfw_stream_parse_format(buf, &formation);
+ if (err < 0)
+ goto end;
+
+ formats[eid] = kmalloc(*len, GFP_KERNEL);
+ if (formats[eid] == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
+ memcpy(formats[eid], buf, *len);
+
+ /* apply the format for each available sampling rate */
+ for (i = 0; i < ARRAY_SIZE(oxfw_rate_table); i++) {
+ if (formation.rate == oxfw_rate_table[i])
+ continue;
+
+ err = avc_general_inquiry_sig_fmt(oxfw->unit,
+ oxfw_rate_table[i],
+ dir, pid);
+ if (err < 0)
+ continue;
+
+ eid++;
+ formats[eid] = kmalloc(*len, GFP_KERNEL);
+ if (formats[eid] == NULL) {
+ err = -ENOMEM;
+ goto end;
+ }
+ memcpy(formats[eid], buf, *len);
+ formats[eid][2] = avc_stream_rate_table[i];
+ }
+
+ err = 0;
+ oxfw->assumed = true;
+end:
+ return err;
+}
+
+static int fill_stream_formats(struct snd_oxfw *oxfw,
+ enum avc_general_plug_dir dir,
+ unsigned short pid)
+{
+ u8 *buf, **formats;
+ unsigned int len, eid = 0;
+ struct snd_oxfw_stream_formation dummy;
+ int err;
+
+ buf = kmalloc(AVC_GENERIC_FRAME_MAXIMUM_BYTES, GFP_KERNEL);
+ if (buf == NULL)
+ return -ENOMEM;
+
+ if (dir == AVC_GENERAL_PLUG_DIR_OUT)
+ formats = oxfw->tx_stream_formats;
+ else
+ formats = oxfw->rx_stream_formats;
+
+ /* get first entry */
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ err = avc_stream_get_format_list(oxfw->unit, dir, 0, buf, &len, 0);
+ if (err == -ENOSYS) {
+ /* LIST subfunction is not implemented */
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ err = assume_stream_formats(oxfw, dir, pid, buf, &len,
+ formats);
+ goto end;
+ } else if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get stream format %d for isoc %s plug %d:%d\n",
+ eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" : "out",
+ pid, err);
+ goto end;
+ }
+
+ /* LIST subfunction is implemented */
+ while (eid < SND_OXFW_STREAM_FORMAT_ENTRIES) {
+ /* The format is too short. */
+ if (len < 3) {
+ err = -EIO;
+ break;
+ }
+
+ /* parse and set stream format */
+ err = snd_oxfw_stream_parse_format(buf, &dummy);
+ if (err < 0)
+ break;
+
+ formats[eid] = kmalloc(len, GFP_KERNEL);
+ if (formats[eid] == NULL) {
+ err = -ENOMEM;
+ break;
+ }
+ memcpy(formats[eid], buf, len);
+
+ /* get next entry */
+ len = AVC_GENERIC_FRAME_MAXIMUM_BYTES;
+ err = avc_stream_get_format_list(oxfw->unit, dir, 0,
+ buf, &len, ++eid);
+ /* No entries remained. */
+ if (err == -EINVAL) {
+ err = 0;
+ break;
+ } else if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get stream format %d for isoc %s plug %d:%d\n",
+ eid, (dir == AVC_GENERAL_PLUG_DIR_IN) ? "in" :
+ "out",
+ pid, err);
+ break;
+ }
+ }
+end:
+ kfree(buf);
+ return err;
+}
+
+int snd_oxfw_stream_discover(struct snd_oxfw *oxfw)
+{
+ u8 plugs[AVC_PLUG_INFO_BUF_BYTES];
+ int err;
+
+ /* the number of plugs for isoc in/out, ext in/out */
+ err = avc_general_get_plug_info(oxfw->unit, 0x1f, 0x07, 0x00, plugs);
+ if (err < 0) {
+ dev_err(&oxfw->unit->device,
+ "fail to get info for isoc/external in/out plugs: %d\n",
+ err);
+ goto end;
+ } else if ((plugs[0] == 0) && (plugs[1] == 0)) {
+ err = -ENOSYS;
+ goto end;
+ }
+
+ /* use oPCR[0] if exists */
+ if (plugs[1] > 0) {
+ err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_OUT, 0);
+ if (err < 0)
+ goto end;
+ oxfw->has_output = true;
+ }
+
+ /* use iPCR[0] if exists */
+ if (plugs[0] > 0)
+ err = fill_stream_formats(oxfw, AVC_GENERAL_PLUG_DIR_IN, 0);
+end:
+ return err;
+}
+
+void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw)
+{
+ oxfw->dev_lock_changed = true;
+ wake_up(&oxfw->hwdep_wait);
+}
+
+int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw)
+{
+ int err;
+
+ spin_lock_irq(&oxfw->lock);
+
+ /* user land lock this */
+ if (oxfw->dev_lock_count < 0) {
+ err = -EBUSY;
+ goto end;
+ }
+
+ /* this is the first time */
+ if (oxfw->dev_lock_count++ == 0)
+ snd_oxfw_stream_lock_changed(oxfw);
+ err = 0;
+end:
+ spin_unlock_irq(&oxfw->lock);
+ return err;
+}
+
+void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw)
+{
+ spin_lock_irq(&oxfw->lock);
+
+ if (WARN_ON(oxfw->dev_lock_count <= 0))
+ goto end;
+ if (--oxfw->dev_lock_count == 0)
+ snd_oxfw_stream_lock_changed(oxfw);
+end:
+ spin_unlock_irq(&oxfw->lock);
+}
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c
new file mode 100644
index 0000000..cf1d0b5
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw.c
@@ -0,0 +1,317 @@
+/*
+ * oxfw.c - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include "oxfw.h"
+
+#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
+/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
+
+#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020)
+#define OXFORD_HARDWARE_ID_OXFW970 0x39443841
+#define OXFORD_HARDWARE_ID_OXFW971 0x39373100
+
+#define VENDOR_LOUD 0x000ff2
+#define VENDOR_GRIFFIN 0x001292
+#define VENDOR_BEHRINGER 0x001564
+#define VENDOR_LACIE 0x00d04b
+
+#define SPECIFIER_1394TA 0x00a02d
+#define VERSION_AVC 0x010001
+
+MODULE_DESCRIPTION("Oxford Semiconductor FW970/971 driver");
+MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("snd-firewire-speakers");
+
+static bool detect_loud_models(struct fw_unit *unit)
+{
+ const char *const models[] = {
+ "Onyxi",
+ "Onyx-i",
+ "d.Pro",
+ "Mackie Onyx Satellite",
+ "Tapco LINK.firewire 4x6",
+ "U.420"};
+ char model[32];
+ unsigned int i;
+ int err;
+
+ err = fw_csr_string(unit->directory, CSR_MODEL,
+ model, sizeof(model));
+ if (err < 0)
+ return err;
+
+ for (i = 0; i < ARRAY_SIZE(models); i++) {
+ if (strcmp(models[i], model) == 0)
+ break;
+ }
+
+ return (i < ARRAY_SIZE(models));
+}
+
+static int name_card(struct snd_oxfw *oxfw)
+{
+ struct fw_device *fw_dev = fw_parent_device(oxfw->unit);
+ char vendor[24];
+ char model[32];
+ const char *d, *v, *m;
+ u32 firmware;
+ int err;
+
+ /* get vendor name from root directory */
+ err = fw_csr_string(fw_dev->config_rom + 5, CSR_VENDOR,
+ vendor, sizeof(vendor));
+ if (err < 0)
+ goto end;
+
+ /* get model name from unit directory */
+ err = fw_csr_string(oxfw->unit->directory, CSR_MODEL,
+ model, sizeof(model));
+ if (err < 0)
+ goto end;
+
+ err = snd_fw_transaction(oxfw->unit, TCODE_READ_QUADLET_REQUEST,
+ OXFORD_FIRMWARE_ID_ADDRESS, &firmware, 4, 0);
+ if (err < 0)
+ goto end;
+ be32_to_cpus(&firmware);
+
+ /* to apply card definitions */
+ if (oxfw->device_info) {
+ d = oxfw->device_info->driver_name;
+ v = oxfw->device_info->vendor_name;
+ m = oxfw->device_info->model_name;
+ } else {
+ d = "OXFW";
+ v = vendor;
+ m = model;
+ }
+
+ strcpy(oxfw->card->driver, d);
+ strcpy(oxfw->card->mixername, m);
+ strcpy(oxfw->card->shortname, m);
+
+ snprintf(oxfw->card->longname, sizeof(oxfw->card->longname),
+ "%s %s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
+ v, m, firmware >> 20, firmware & 0xffff,
+ fw_dev->config_rom[3], fw_dev->config_rom[4],
+ dev_name(&oxfw->unit->device), 100 << fw_dev->max_speed);
+end:
+ return err;
+}
+
+static void oxfw_card_free(struct snd_card *card)
+{
+ struct snd_oxfw *oxfw = card->private_data;
+ unsigned int i;
+
+ for (i = 0; i < SND_OXFW_STREAM_FORMAT_ENTRIES; i++) {
+ kfree(oxfw->tx_stream_formats[i]);
+ kfree(oxfw->rx_stream_formats[i]);
+ }
+
+ mutex_destroy(&oxfw->mutex);
+}
+
+static int oxfw_probe(struct fw_unit *unit,
+ const struct ieee1394_device_id *id)
+{
+ struct snd_card *card;
+ struct snd_oxfw *oxfw;
+ int err;
+
+ if ((id->vendor_id == VENDOR_LOUD) && !detect_loud_models(unit))
+ return -ENODEV;
+
+ err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
+ sizeof(*oxfw), &card);
+ if (err < 0)
+ return err;
+
+ card->private_free = oxfw_card_free;
+ oxfw = card->private_data;
+ oxfw->card = card;
+ mutex_init(&oxfw->mutex);
+ oxfw->unit = unit;
+ oxfw->device_info = (const struct device_info *)id->driver_data;
+ spin_lock_init(&oxfw->lock);
+ init_waitqueue_head(&oxfw->hwdep_wait);
+
+ err = snd_oxfw_stream_discover(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = name_card(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = snd_oxfw_create_pcm(oxfw);
+ if (err < 0)
+ goto error;
+
+ if (oxfw->device_info) {
+ err = snd_oxfw_create_mixer(oxfw);
+ if (err < 0)
+ goto error;
+ }
+
+ snd_oxfw_proc_init(oxfw);
+
+ err = snd_oxfw_create_midi(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = snd_oxfw_create_hwdep(oxfw);
+ if (err < 0)
+ goto error;
+
+ err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->rx_stream);
+ if (err < 0)
+ goto error;
+ if (oxfw->has_output) {
+ err = snd_oxfw_stream_init_simplex(oxfw, &oxfw->tx_stream);
+ if (err < 0)
+ goto error;
+ }
+
+ err = snd_card_register(card);
+ if (err < 0) {
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+ goto error;
+ }
+ dev_set_drvdata(&unit->device, oxfw);
+
+ return 0;
+error:
+ snd_card_free(card);
+ return err;
+}
+
+static void oxfw_bus_reset(struct fw_unit *unit)
+{
+ struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
+
+ fcp_bus_reset(oxfw->unit);
+
+ mutex_lock(&oxfw->mutex);
+
+ snd_oxfw_stream_update_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_update_simplex(oxfw, &oxfw->tx_stream);
+
+ mutex_unlock(&oxfw->mutex);
+}
+
+static void oxfw_remove(struct fw_unit *unit)
+{
+ struct snd_oxfw *oxfw = dev_get_drvdata(&unit->device);
+
+ snd_card_disconnect(oxfw->card);
+
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->rx_stream);
+ if (oxfw->has_output)
+ snd_oxfw_stream_destroy_simplex(oxfw, &oxfw->tx_stream);
+
+ snd_card_free_when_closed(oxfw->card);
+}
+
+static const struct device_info griffin_firewave = {
+ .driver_name = "FireWave",
+ .vendor_name = "Griffin",
+ .model_name = "FireWave",
+ .mixer_channels = 6,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x02,
+};
+
+static const struct device_info lacie_speakers = {
+ .driver_name = "FWSpeakers",
+ .vendor_name = "LaCie",
+ .model_name = "FireWire Speakers",
+ .mixer_channels = 1,
+ .mute_fb_id = 0x01,
+ .volume_fb_id = 0x01,
+};
+
+static const struct ieee1394_device_id oxfw_id_table[] = {
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_GRIFFIN,
+ .model_id = 0x00f970,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ .driver_data = (kernel_ulong_t)&griffin_firewave,
+ },
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_LACIE,
+ .model_id = 0x00f970,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ .driver_data = (kernel_ulong_t)&lacie_speakers,
+ },
+ /* Behringer,F-Control Audio 202 */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_MODEL_ID,
+ .vendor_id = VENDOR_BEHRINGER,
+ .model_id = 0x00fc22,
+ },
+ /*
+ * Any Mackie(Loud) models (name string/model id):
+ * Onyx-i series (former models): 0x081216
+ * Mackie Onyx Satellite: 0x00200f
+ * Tapco LINK.firewire 4x6: 0x000460
+ * d.2 pro: Unknown
+ * d.4 pro: Unknown
+ * U.420: Unknown
+ * U.420d: Unknown
+ */
+ {
+ .match_flags = IEEE1394_MATCH_VENDOR_ID |
+ IEEE1394_MATCH_SPECIFIER_ID |
+ IEEE1394_MATCH_VERSION,
+ .vendor_id = VENDOR_LOUD,
+ .specifier_id = SPECIFIER_1394TA,
+ .version = VERSION_AVC,
+ },
+ { }
+};
+MODULE_DEVICE_TABLE(ieee1394, oxfw_id_table);
+
+static struct fw_driver oxfw_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = KBUILD_MODNAME,
+ .bus = &fw_bus_type,
+ },
+ .probe = oxfw_probe,
+ .update = oxfw_bus_reset,
+ .remove = oxfw_remove,
+ .id_table = oxfw_id_table,
+};
+
+static int __init snd_oxfw_init(void)
+{
+ return driver_register(&oxfw_driver.driver);
+}
+
+static void __exit snd_oxfw_exit(void)
+{
+ driver_unregister(&oxfw_driver.driver);
+}
+
+module_init(snd_oxfw_init);
+module_exit(snd_oxfw_exit);
diff --git a/sound/firewire/oxfw/oxfw.h b/sound/firewire/oxfw/oxfw.h
new file mode 100644
index 0000000..cace5ad
--- /dev/null
+++ b/sound/firewire/oxfw/oxfw.h
@@ -0,0 +1,146 @@
+/*
+ * oxfw.h - a part of driver for OXFW970/971 based devices
+ *
+ * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
+ * Licensed under the terms of the GNU General Public License, version 2.
+ */
+
+#include <linux/device.h>
+#include <linux/firewire.h>
+#include <linux/firewire-constants.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/compat.h>
+
+#include <sound/control.h>
+#include <sound/core.h>
+#include <sound/initval.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/info.h>
+#include <sound/rawmidi.h>
+#include <sound/firewire.h>
+#include <sound/hwdep.h>
+
+#include "../lib.h"
+#include "../fcp.h"
+#include "../packets-buffer.h"
+#include "../iso-resources.h"
+#include "../amdtp.h"
+#include "../cmp.h"
+
+struct device_info {
+ const char *driver_name;
+ const char *vendor_name;
+ const char *model_name;
+ unsigned int mixer_channels;
+ u8 mute_fb_id;
+ u8 volume_fb_id;
+};
+
+/* This is an arbitrary number for convinience. */
+#define SND_OXFW_STREAM_FORMAT_ENTRIES 10
+struct snd_oxfw {
+ struct snd_card *card;
+ struct fw_unit *unit;
+ const struct device_info *device_info;
+ struct mutex mutex;
+ spinlock_t lock;
+
+ bool has_output;
+ u8 *tx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
+ u8 *rx_stream_formats[SND_OXFW_STREAM_FORMAT_ENTRIES];
+ bool assumed;
+ struct cmp_connection out_conn;
+ struct cmp_connection in_conn;
+ struct amdtp_stream tx_stream;
+ struct amdtp_stream rx_stream;
+ unsigned int capture_substreams;
+ unsigned int playback_substreams;
+
+ unsigned int midi_input_ports;
+ unsigned int midi_output_ports;
+
+ bool mute;
+ s16 volume[6];
+ s16 volume_min;
+ s16 volume_max;
+
+ int dev_lock_count;
+ bool dev_lock_changed;
+ wait_queue_head_t hwdep_wait;
+};
+
+/*
+ * AV/C Stream Format Information Specification 1.1 Working Draft
+ * (Apr 2005, 1394TA)
+ */
+int avc_stream_set_format(struct fw_unit *unit, enum avc_general_plug_dir dir,
+ unsigned int pid, u8 *format, unsigned int len);
+int avc_stream_get_format(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len, unsigned int eid);
+static inline int
+avc_stream_get_format_single(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len)
+{
+ return avc_stream_get_format(unit, dir, pid, buf, len, 0xff);
+}
+static inline int
+avc_stream_get_format_list(struct fw_unit *unit,
+ enum avc_general_plug_dir dir, unsigned int pid,
+ u8 *buf, unsigned int *len,
+ unsigned int eid)
+{
+ return avc_stream_get_format(unit, dir, pid, buf, len, eid);
+}
+
+/*
+ * AV/C Digital Interface Command Set General Specification 4.2
+ * (Sep 2004, 1394TA)
+ */
+int avc_general_inquiry_sig_fmt(struct fw_unit *unit, unsigned int rate,
+ enum avc_general_plug_dir dir,
+ unsigned short pid);
+
+int snd_oxfw_stream_init_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+int snd_oxfw_stream_start_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream,
+ unsigned int rate, unsigned int pcm_channels);
+void snd_oxfw_stream_stop_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+void snd_oxfw_stream_destroy_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+void snd_oxfw_stream_update_simplex(struct snd_oxfw *oxfw,
+ struct amdtp_stream *stream);
+
+struct snd_oxfw_stream_formation {
+ unsigned int rate;
+ unsigned int pcm;
+ unsigned int midi;
+};
+int snd_oxfw_stream_parse_format(u8 *format,
+ struct snd_oxfw_stream_formation *formation);
+int snd_oxfw_stream_get_current_formation(struct snd_oxfw *oxfw,
+ enum avc_general_plug_dir dir,
+ struct snd_oxfw_stream_formation *formation);
+
+int snd_oxfw_stream_discover(struct snd_oxfw *oxfw);
+
+void snd_oxfw_stream_lock_changed(struct snd_oxfw *oxfw);
+int snd_oxfw_stream_lock_try(struct snd_oxfw *oxfw);
+void snd_oxfw_stream_lock_release(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_pcm(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_mixer(struct snd_oxfw *oxfw);
+
+void snd_oxfw_proc_init(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_midi(struct snd_oxfw *oxfw);
+
+int snd_oxfw_create_hwdep(struct snd_oxfw *oxfw);
diff --git a/sound/firewire/speakers.c b/sound/firewire/speakers.c
deleted file mode 100644
index 768d40d..0000000
--- a/sound/firewire/speakers.c
+++ /dev/null
@@ -1,792 +0,0 @@
-/*
- * OXFW970-based speakers driver
- *
- * Copyright (c) Clemens Ladisch <clemens@ladisch.de>
- * Licensed under the terms of the GNU General Public License, version 2.
- */
-
-#include <linux/device.h>
-#include <linux/firewire.h>
-#include <linux/firewire-constants.h>
-#include <linux/module.h>
-#include <linux/mod_devicetable.h>
-#include <linux/mutex.h>
-#include <linux/slab.h>
-#include <sound/control.h>
-#include <sound/core.h>
-#include <sound/initval.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include "cmp.h"
-#include "fcp.h"
-#include "amdtp.h"
-#include "lib.h"
-
-#define OXFORD_FIRMWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x50000)
-/* 0x970?vvvv or 0x971?vvvv, where vvvv = firmware version */
-
-#define OXFORD_HARDWARE_ID_ADDRESS (CSR_REGISTER_BASE + 0x90020)
-#define OXFORD_HARDWARE_ID_OXFW970 0x39443841
-#define OXFORD_HARDWARE_ID_OXFW971 0x39373100
-
-#define VENDOR_GRIFFIN 0x001292
-#define VENDOR_LACIE 0x00d04b
-
-#define SPECIFIER_1394TA 0x00a02d
-#define VERSION_AVC 0x010001
-
-struct device_info {
- const char *driver_name;
- const char *short_name;
- const char *long_name;
- int (*pcm_constraints)(struct snd_pcm_runtime *runtime);
- unsigned int mixer_channels;
- u8 mute_fb_id;
- u8 volume_fb_id;
-};
-
-struct fwspk {
- struct snd_card *card;
- struct fw_unit *unit;
- const struct device_info *device_info;
- struct mutex mutex;
- struct cmp_connection connection;
- struct amdtp_stream stream;
- bool mute;
- s16 volume[6];
- s16 volume_min;
- s16 volume_max;
-};
-
-MODULE_DESCRIPTION("FireWire speakers driver");
-MODULE_AUTHOR("Clemens Ladisch <clemens@ladisch.de>");
-MODULE_LICENSE("GPL v2");
-
-static int firewave_rate_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- static unsigned int stereo_rates[] = { 48000, 96000 };
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
-
- /* two channels work only at 48/96 kHz */
- if (snd_interval_max(channels) < 6)
- return snd_interval_list(rate, 2, stereo_rates, 0);
- return 0;
-}
-
-static int firewave_channels_constraint(struct snd_pcm_hw_params *params,
- struct snd_pcm_hw_rule *rule)
-{
- static const struct snd_interval all_channels = { .min = 6, .max = 6 };
- struct snd_interval *rate =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
- struct snd_interval *channels =
- hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
-
- /* 32/44.1 kHz work only with all six channels */
- if (snd_interval_max(rate) < 48000)
- return snd_interval_refine(channels, &all_channels);
- return 0;
-}
-
-static int firewave_constraints(struct snd_pcm_runtime *runtime)
-{
- static unsigned int channels_list[] = { 2, 6 };
- static struct snd_pcm_hw_constraint_list channels_list_constraint = {
- .count = 2,
- .list = channels_list,
- };
- int err;
-
- runtime->hw.rates = SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_96000;
- runtime->hw.channels_max = 6;
-
- err = snd_pcm_hw_constraint_list(runtime, 0,
- SNDRV_PCM_HW_PARAM_CHANNELS,
- &channels_list_constraint);
- if (err < 0)
- return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
- firewave_rate_constraint, NULL,
- SNDRV_PCM_HW_PARAM_CHANNELS, -1);
- if (err < 0)
- return err;
- err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
- firewave_channels_constraint, NULL,
- SNDRV_PCM_HW_PARAM_RATE, -1);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int lacie_speakers_constraints(struct snd_pcm_runtime *runtime)
-{
- runtime->hw.rates = SNDRV_PCM_RATE_32000 |
- SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000 |
- SNDRV_PCM_RATE_88200 |
- SNDRV_PCM_RATE_96000;
-
- return 0;
-}
-
-static int fwspk_open(struct snd_pcm_substream *substream)
-{
- static const struct snd_pcm_hardware hardware = {
- .info = SNDRV_PCM_INFO_MMAP |
- SNDRV_PCM_INFO_MMAP_VALID |
- SNDRV_PCM_INFO_BATCH |
- SNDRV_PCM_INFO_INTERLEAVED |
- SNDRV_PCM_INFO_BLOCK_TRANSFER,
- .formats = AMDTP_OUT_PCM_FORMAT_BITS,
- .channels_min = 2,
- .channels_max = 2,
- .buffer_bytes_max = 4 * 1024 * 1024,
- .period_bytes_min = 1,
- .period_bytes_max = UINT_MAX,
- .periods_min = 1,
- .periods_max = UINT_MAX,
- };
- struct fwspk *fwspk = substream->private_data;
- struct snd_pcm_runtime *runtime = substream->runtime;
- int err;
-
- runtime->hw = hardware;
-
- err = fwspk->device_info->pcm_constraints(runtime);
- if (err < 0)
- return err;
- err = snd_pcm_limit_hw_rates(runtime);
- if (err < 0)
- return err;
-
- err = amdtp_stream_add_pcm_hw_constraints(&fwspk->stream, runtime);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int fwspk_close(struct snd_pcm_substream *substream)
-{
- return 0;
-}
-
-static void fwspk_stop_stream(struct fwspk *fwspk)
-{
- if (amdtp_stream_running(&fwspk->stream)) {
- amdtp_stream_stop(&fwspk->stream);
- cmp_connection_break(&fwspk->connection);
- }
-}
-
-static int fwspk_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *hw_params)
-{
- struct fwspk *fwspk = substream->private_data;
- int err;
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- err = snd_pcm_lib_alloc_vmalloc_buffer(substream,
- params_buffer_bytes(hw_params));
- if (err < 0)
- goto error;
-
- amdtp_stream_set_parameters(&fwspk->stream,
- params_rate(hw_params),
- params_channels(hw_params),
- 0);
-
- amdtp_stream_set_pcm_format(&fwspk->stream,
- params_format(hw_params));
-
- err = avc_general_set_sig_fmt(fwspk->unit, params_rate(hw_params),
- AVC_GENERAL_PLUG_DIR_IN, 0);
- if (err < 0) {
- dev_err(&fwspk->unit->device, "failed to set sample rate\n");
- goto err_buffer;
- }
-
- return 0;
-
-err_buffer:
- snd_pcm_lib_free_vmalloc_buffer(substream);
-error:
- return err;
-}
-
-static int fwspk_hw_free(struct snd_pcm_substream *substream)
-{
- struct fwspk *fwspk = substream->private_data;
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- return snd_pcm_lib_free_vmalloc_buffer(substream);
-}
-
-static int fwspk_prepare(struct snd_pcm_substream *substream)
-{
- struct fwspk *fwspk = substream->private_data;
- int err;
-
- mutex_lock(&fwspk->mutex);
-
- if (amdtp_streaming_error(&fwspk->stream))
- fwspk_stop_stream(fwspk);
-
- if (!amdtp_stream_running(&fwspk->stream)) {
- err = cmp_connection_establish(&fwspk->connection,
- amdtp_stream_get_max_payload(&fwspk->stream));
- if (err < 0)
- goto err_mutex;
-
- err = amdtp_stream_start(&fwspk->stream,
- fwspk->connection.resources.channel,
- fwspk->connection.speed);
- if (err < 0)
- goto err_connection;
- }
-
- mutex_unlock(&fwspk->mutex);
-
- amdtp_stream_pcm_prepare(&fwspk->stream);
-
- return 0;
-
-err_connection:
- cmp_connection_break(&fwspk->connection);
-err_mutex:
- mutex_unlock(&fwspk->mutex);
-
- return err;
-}
-
-static int fwspk_trigger(struct snd_pcm_substream *substream, int cmd)
-{
- struct fwspk *fwspk = substream->private_data;
- struct snd_pcm_substream *pcm;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- pcm = substream;
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- pcm = NULL;
- break;
- default:
- return -EINVAL;
- }
- amdtp_stream_pcm_trigger(&fwspk->stream, pcm);
- return 0;
-}
-
-static snd_pcm_uframes_t fwspk_pointer(struct snd_pcm_substream *substream)
-{
- struct fwspk *fwspk = substream->private_data;
-
- return amdtp_stream_pcm_pointer(&fwspk->stream);
-}
-
-static int fwspk_create_pcm(struct fwspk *fwspk)
-{
- static struct snd_pcm_ops ops = {
- .open = fwspk_open,
- .close = fwspk_close,
- .ioctl = snd_pcm_lib_ioctl,
- .hw_params = fwspk_hw_params,
- .hw_free = fwspk_hw_free,
- .prepare = fwspk_prepare,
- .trigger = fwspk_trigger,
- .pointer = fwspk_pointer,
- .page = snd_pcm_lib_get_vmalloc_page,
- .mmap = snd_pcm_lib_mmap_vmalloc,
- };
- struct snd_pcm *pcm;
- int err;
-
- err = snd_pcm_new(fwspk->card, "OXFW970", 0, 1, 0, &pcm);
- if (err < 0)
- return err;
- pcm->private_data = fwspk;
- strcpy(pcm->name, fwspk->device_info->short_name);
- snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &ops);
- return 0;
-}
-
-enum control_action { CTL_READ, CTL_WRITE };
-enum control_attribute {
- CTL_MIN = 0x02,
- CTL_MAX = 0x03,
- CTL_CURRENT = 0x10,
-};
-
-static int fwspk_mute_command(struct fwspk *fwspk, bool *value,
- enum control_action action)
-{
- u8 *buf;
- u8 response_ok;
- int err;
-
- buf = kmalloc(11, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (action == CTL_READ) {
- buf[0] = 0x01; /* AV/C, STATUS */
- response_ok = 0x0c; /* STABLE */
- } else {
- buf[0] = 0x00; /* AV/C, CONTROL */
- response_ok = 0x09; /* ACCEPTED */
- }
- buf[1] = 0x08; /* audio unit 0 */
- buf[2] = 0xb8; /* FUNCTION BLOCK */
- buf[3] = 0x81; /* function block type: feature */
- buf[4] = fwspk->device_info->mute_fb_id; /* function block ID */
- buf[5] = 0x10; /* control attribute: current */
- buf[6] = 0x02; /* selector length */
- buf[7] = 0x00; /* audio channel number */
- buf[8] = 0x01; /* control selector: mute */
- buf[9] = 0x01; /* control data length */
- if (action == CTL_READ)
- buf[10] = 0xff;
- else
- buf[10] = *value ? 0x70 : 0x60;
-
- err = fcp_avc_transaction(fwspk->unit, buf, 11, buf, 11, 0x3fe);
- if (err < 0)
- goto error;
- if (err < 11) {
- dev_err(&fwspk->unit->device, "short FCP response\n");
- err = -EIO;
- goto error;
- }
- if (buf[0] != response_ok) {
- dev_err(&fwspk->unit->device, "mute command failed\n");
- err = -EIO;
- goto error;
- }
- if (action == CTL_READ)
- *value = buf[10] == 0x70;
-
- err = 0;
-
-error:
- kfree(buf);
-
- return err;
-}
-
-static int fwspk_volume_command(struct fwspk *fwspk, s16 *value,
- unsigned int channel,
- enum control_attribute attribute,
- enum control_action action)
-{
- u8 *buf;
- u8 response_ok;
- int err;
-
- buf = kmalloc(12, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- if (action == CTL_READ) {
- buf[0] = 0x01; /* AV/C, STATUS */
- response_ok = 0x0c; /* STABLE */
- } else {
- buf[0] = 0x00; /* AV/C, CONTROL */
- response_ok = 0x09; /* ACCEPTED */
- }
- buf[1] = 0x08; /* audio unit 0 */
- buf[2] = 0xb8; /* FUNCTION BLOCK */
- buf[3] = 0x81; /* function block type: feature */
- buf[4] = fwspk->device_info->volume_fb_id; /* function block ID */
- buf[5] = attribute; /* control attribute */
- buf[6] = 0x02; /* selector length */
- buf[7] = channel; /* audio channel number */
- buf[8] = 0x02; /* control selector: volume */
- buf[9] = 0x02; /* control data length */
- if (action == CTL_READ) {
- buf[10] = 0xff;
- buf[11] = 0xff;
- } else {
- buf[10] = *value >> 8;
- buf[11] = *value;
- }
-
- err = fcp_avc_transaction(fwspk->unit, buf, 12, buf, 12, 0x3fe);
- if (err < 0)
- goto error;
- if (err < 12) {
- dev_err(&fwspk->unit->device, "short FCP response\n");
- err = -EIO;
- goto error;
- }
- if (buf[0] != response_ok) {
- dev_err(&fwspk->unit->device, "volume command failed\n");
- err = -EIO;
- goto error;
- }
- if (action == CTL_READ)
- *value = (buf[10] << 8) | buf[11];
-
- err = 0;
-
-error:
- kfree(buf);
-
- return err;
-}
-
-static int fwspk_mute_get(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
-
- value->value.integer.value[0] = !fwspk->mute;
-
- return 0;
-}
-
-static int fwspk_mute_put(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
- bool mute;
- int err;
-
- mute = !value->value.integer.value[0];
-
- if (mute == fwspk->mute)
- return 0;
-
- err = fwspk_mute_command(fwspk, &mute, CTL_WRITE);
- if (err < 0)
- return err;
- fwspk->mute = mute;
-
- return 1;
-}
-
-static int fwspk_volume_info(struct snd_kcontrol *control,
- struct snd_ctl_elem_info *info)
-{
- struct fwspk *fwspk = control->private_data;
-
- info->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- info->count = fwspk->device_info->mixer_channels;
- info->value.integer.min = fwspk->volume_min;
- info->value.integer.max = fwspk->volume_max;
-
- return 0;
-}
-
-static const u8 channel_map[6] = { 0, 1, 4, 5, 2, 3 };
-
-static int fwspk_volume_get(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
- unsigned int i;
-
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i)
- value->value.integer.value[channel_map[i]] = fwspk->volume[i];
-
- return 0;
-}
-
-static int fwspk_volume_put(struct snd_kcontrol *control,
- struct snd_ctl_elem_value *value)
-{
- struct fwspk *fwspk = control->private_data;
- unsigned int i, changed_channels;
- bool equal_values = true;
- s16 volume;
- int err;
-
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i) {
- if (value->value.integer.value[i] < fwspk->volume_min ||
- value->value.integer.value[i] > fwspk->volume_max)
- return -EINVAL;
- if (value->value.integer.value[i] !=
- value->value.integer.value[0])
- equal_values = false;
- }
-
- changed_channels = 0;
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i)
- if (value->value.integer.value[channel_map[i]] !=
- fwspk->volume[i])
- changed_channels |= 1 << (i + 1);
-
- if (equal_values && changed_channels != 0)
- changed_channels = 1 << 0;
-
- for (i = 0; i <= fwspk->device_info->mixer_channels; ++i) {
- volume = value->value.integer.value[channel_map[i ? i - 1 : 0]];
- if (changed_channels & (1 << i)) {
- err = fwspk_volume_command(fwspk, &volume, i,
- CTL_CURRENT, CTL_WRITE);
- if (err < 0)
- return err;
- }
- if (i > 0)
- fwspk->volume[i - 1] = volume;
- }
-
- return changed_channels != 0;
-}
-
-static int fwspk_create_mixer(struct fwspk *fwspk)
-{
- static const struct snd_kcontrol_new controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Switch",
- .info = snd_ctl_boolean_mono_info,
- .get = fwspk_mute_get,
- .put = fwspk_mute_put,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "PCM Playback Volume",
- .info = fwspk_volume_info,
- .get = fwspk_volume_get,
- .put = fwspk_volume_put,
- },
- };
- unsigned int i, first_ch;
- int err;
-
- err = fwspk_volume_command(fwspk, &fwspk->volume_min,
- 0, CTL_MIN, CTL_READ);
- if (err < 0)
- return err;
- err = fwspk_volume_command(fwspk, &fwspk->volume_max,
- 0, CTL_MAX, CTL_READ);
- if (err < 0)
- return err;
-
- err = fwspk_mute_command(fwspk, &fwspk->mute, CTL_READ);
- if (err < 0)
- return err;
-
- first_ch = fwspk->device_info->mixer_channels == 1 ? 0 : 1;
- for (i = 0; i < fwspk->device_info->mixer_channels; ++i) {
- err = fwspk_volume_command(fwspk, &fwspk->volume[i],
- first_ch + i, CTL_CURRENT, CTL_READ);
- if (err < 0)
- return err;
- }
-
- for (i = 0; i < ARRAY_SIZE(controls); ++i) {
- err = snd_ctl_add(fwspk->card,
- snd_ctl_new1(&controls[i], fwspk));
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-
-static u32 fwspk_read_firmware_version(struct fw_unit *unit)
-{
- __be32 data;
- int err;
-
- err = snd_fw_transaction(unit, TCODE_READ_QUADLET_REQUEST,
- OXFORD_FIRMWARE_ID_ADDRESS, &data, 4, 0);
- return err >= 0 ? be32_to_cpu(data) : 0;
-}
-
-static void fwspk_card_free(struct snd_card *card)
-{
- struct fwspk *fwspk = card->private_data;
-
- amdtp_stream_destroy(&fwspk->stream);
- cmp_connection_destroy(&fwspk->connection);
- fw_unit_put(fwspk->unit);
- mutex_destroy(&fwspk->mutex);
-}
-
-static int fwspk_probe(struct fw_unit *unit,
- const struct ieee1394_device_id *id)
-{
- struct fw_device *fw_dev = fw_parent_device(unit);
- struct snd_card *card;
- struct fwspk *fwspk;
- u32 firmware;
- int err;
-
- err = snd_card_new(&unit->device, -1, NULL, THIS_MODULE,
- sizeof(*fwspk), &card);
- if (err < 0)
- return err;
-
- fwspk = card->private_data;
- fwspk->card = card;
- mutex_init(&fwspk->mutex);
- fwspk->unit = fw_unit_get(unit);
- fwspk->device_info = (const struct device_info *)id->driver_data;
-
- err = cmp_connection_init(&fwspk->connection, unit, CMP_INPUT, 0);
- if (err < 0)
- goto err_unit;
-
- err = amdtp_stream_init(&fwspk->stream, unit, AMDTP_OUT_STREAM,
- CIP_NONBLOCKING);
- if (err < 0)
- goto err_connection;
-
- card->private_free = fwspk_card_free;
-
- strcpy(card->driver, fwspk->device_info->driver_name);
- strcpy(card->shortname, fwspk->device_info->short_name);
- firmware = fwspk_read_firmware_version(unit);
- snprintf(card->longname, sizeof(card->longname),
- "%s (OXFW%x %04x), GUID %08x%08x at %s, S%d",
- fwspk->device_info->long_name,
- firmware >> 20, firmware & 0xffff,
- fw_dev->config_rom[3], fw_dev->config_rom[4],
- dev_name(&unit->device), 100 << fw_dev->max_speed);
- strcpy(card->mixername, "OXFW970");
-
- err = fwspk_create_pcm(fwspk);
- if (err < 0)
- goto error;
-
- err = fwspk_create_mixer(fwspk);
- if (err < 0)
- goto error;
-
- err = snd_card_register(card);
- if (err < 0)
- goto error;
-
- dev_set_drvdata(&unit->device, fwspk);
-
- return 0;
-
-err_connection:
- cmp_connection_destroy(&fwspk->connection);
-err_unit:
- fw_unit_put(fwspk->unit);
- mutex_destroy(&fwspk->mutex);
-error:
- snd_card_free(card);
- return err;
-}
-
-static void fwspk_bus_reset(struct fw_unit *unit)
-{
- struct fwspk *fwspk = dev_get_drvdata(&unit->device);
-
- fcp_bus_reset(fwspk->unit);
-
- if (cmp_connection_update(&fwspk->connection) < 0) {
- amdtp_stream_pcm_abort(&fwspk->stream);
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
- return;
- }
-
- amdtp_stream_update(&fwspk->stream);
-}
-
-static void fwspk_remove(struct fw_unit *unit)
-{
- struct fwspk *fwspk = dev_get_drvdata(&unit->device);
-
- amdtp_stream_pcm_abort(&fwspk->stream);
- snd_card_disconnect(fwspk->card);
-
- mutex_lock(&fwspk->mutex);
- fwspk_stop_stream(fwspk);
- mutex_unlock(&fwspk->mutex);
-
- snd_card_free_when_closed(fwspk->card);
-}
-
-static const struct device_info griffin_firewave = {
- .driver_name = "FireWave",
- .short_name = "FireWave",
- .long_name = "Griffin FireWave Surround",
- .pcm_constraints = firewave_constraints,
- .mixer_channels = 6,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x02,
-};
-
-static const struct device_info lacie_speakers = {
- .driver_name = "FWSpeakers",
- .short_name = "FireWire Speakers",
- .long_name = "LaCie FireWire Speakers",
- .pcm_constraints = lacie_speakers_constraints,
- .mixer_channels = 1,
- .mute_fb_id = 0x01,
- .volume_fb_id = 0x01,
-};
-
-static const struct ieee1394_device_id fwspk_id_table[] = {
- {
- .match_flags = IEEE1394_MATCH_VENDOR_ID |
- IEEE1394_MATCH_MODEL_ID |
- IEEE1394_MATCH_SPECIFIER_ID |
- IEEE1394_MATCH_VERSION,
- .vendor_id = VENDOR_GRIFFIN,
- .model_id = 0x00f970,
- .specifier_id = SPECIFIER_1394TA,
- .version = VERSION_AVC,
- .driver_data = (kernel_ulong_t)&griffin_firewave,
- },
- {
- .match_flags = IEEE1394_MATCH_VENDOR_ID |
- IEEE1394_MATCH_MODEL_ID |
- IEEE1394_MATCH_SPECIFIER_ID |
- IEEE1394_MATCH_VERSION,
- .vendor_id = VENDOR_LACIE,
- .model_id = 0x00f970,
- .specifier_id = SPECIFIER_1394TA,
- .version = VERSION_AVC,
- .driver_data = (kernel_ulong_t)&lacie_speakers,
- },
- { }
-};
-MODULE_DEVICE_TABLE(ieee1394, fwspk_id_table);
-
-static struct fw_driver fwspk_driver = {
- .driver = {
- .owner = THIS_MODULE,
- .name = KBUILD_MODNAME,
- .bus = &fw_bus_type,
- },
- .probe = fwspk_probe,
- .update = fwspk_bus_reset,
- .remove = fwspk_remove,
- .id_table = fwspk_id_table,
-};
-
-static int __init alsa_fwspk_init(void)
-{
- return driver_register(&fwspk_driver.driver);
-}
-
-static void __exit alsa_fwspk_exit(void)
-{
- driver_unregister(&fwspk_driver.driver);
-}
-
-module_init(alsa_fwspk_init);
-module_exit(alsa_fwspk_exit);
diff --git a/sound/i2c/other/ak4xxx-adda.c b/sound/i2c/other/ak4xxx-adda.c
index f3735e6..67dbfde 100644
--- a/sound/i2c/other/ak4xxx-adda.c
+++ b/sound/i2c/other/ak4xxx-adda.c
@@ -465,17 +465,10 @@ static int snd_akm4xxx_stereo_volume_put(struct snd_kcontrol *kcontrol,
static int snd_akm4xxx_deemphasis_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"44.1kHz", "Off", "48kHz", "32kHz",
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= 4)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_akm4xxx_deemphasis_get(struct snd_kcontrol *kcontrol,
@@ -570,22 +563,13 @@ static int ak4xxx_capture_source_info(struct snd_kcontrol *kcontrol,
{
struct snd_akm4xxx *ak = snd_kcontrol_chip(kcontrol);
int mixer_ch = AK_GET_SHIFT(kcontrol->private_value);
- const char **input_names;
- unsigned int num_names, idx;
+ unsigned int num_names;
num_names = ak4xxx_capture_num_inputs(ak, mixer_ch);
if (!num_names)
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = num_names;
- idx = uinfo->value.enumerated.item;
- if (idx >= num_names)
- return -EINVAL;
- input_names = ak->adc_info[mixer_ch].input_names;
- strlcpy(uinfo->value.enumerated.name, input_names[idx],
- sizeof(uinfo->value.enumerated.name));
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_names,
+ ak->adc_info[mixer_ch].input_names);
}
static int ak4xxx_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/isa/ad1816a/ad1816a_lib.c b/sound/isa/ad1816a/ad1816a_lib.c
index f0fd98e..01a0798 100644
--- a/sound/isa/ad1816a/ad1816a_lib.c
+++ b/sound/isa/ad1816a/ad1816a_lib.c
@@ -731,18 +731,12 @@ int snd_ad1816a_timer(struct snd_ad1816a *chip, int device,
static int snd_ad1816a_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static const char * const texts[8] = {
"Line", "Mix", "CD", "Synth", "Video",
"Mic", "Phone",
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item > 6)
- uinfo->value.enumerated.item = 6;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 7, texts);
}
static int snd_ad1816a_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/isa/es1688/es1688_lib.c b/sound/isa/es1688/es1688_lib.c
index b3b4f15..b545014 100644
--- a/sound/isa/es1688/es1688_lib.c
+++ b/sound/isa/es1688/es1688_lib.c
@@ -614,8 +614,7 @@ static int snd_es1688_free(struct snd_es1688 *chip)
{
if (chip->hardware != ES1688_HW_UNDEF)
snd_es1688_init(chip, 0);
- if (chip->res_port)
- release_and_free_resource(chip->res_port);
+ release_and_free_resource(chip->res_port);
if (chip->irq >= 0)
free_irq(chip->irq, (void *) chip);
if (chip->dma8 >= 0) {
@@ -762,18 +761,12 @@ int snd_es1688_pcm(struct snd_card *card, struct snd_es1688 *chip,
static int snd_es1688_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[9] = {
+ static const char * const texts[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_es1688_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/isa/es18xx.c b/sound/isa/es18xx.c
index 6faaac6..b481bb8 100644
--- a/sound/isa/es18xx.c
+++ b/sound/isa/es18xx.c
@@ -156,6 +156,7 @@ struct snd_es18xx {
#define ES18XX_I2S 0x0200 /* I2S mixer control */
#define ES18XX_MUTEREC 0x0400 /* Record source can be muted */
#define ES18XX_CONTROL 0x0800 /* Has control ports */
+#define ES18XX_GPO_2BIT 0x1000 /* GPO0,1 controlled by PM port */
/* Power Management */
#define ES18XX_PM 0x07
@@ -964,44 +965,28 @@ static int snd_es18xx_capture_close(struct snd_pcm_substream *substream)
static int snd_es18xx_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts5Source[5] = {
+ static const char * const texts5Source[5] = {
"Mic", "CD", "Line", "Master", "Mix"
};
- static char *texts8Source[8] = {
+ static const char * const texts8Source[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
struct snd_es18xx *chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
switch (chip->version) {
case 0x1868:
case 0x1878:
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts5Source[uinfo->value.enumerated.item]);
- break;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts5Source);
case 0x1887:
case 0x1888:
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts5Source[uinfo->value.enumerated.item]);
- break;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts5Source);
case 0x1869: /* DS somewhat contradictory for 1869: could be be 5 or 8 */
case 0x1879:
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts8Source[uinfo->value.enumerated.item]);
- break;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts8Source);
default:
return -EINVAL;
}
- return 0;
}
static int snd_es18xx_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1136,11 +1121,14 @@ static int snd_es18xx_reg_read(struct snd_es18xx *chip, unsigned char reg)
return snd_es18xx_read(chip, reg);
}
-#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, invert) \
+#define ES18XX_SINGLE(xname, xindex, reg, shift, mask, flags) \
{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, .index = xindex, \
.info = snd_es18xx_info_single, \
.get = snd_es18xx_get_single, .put = snd_es18xx_put_single, \
- .private_value = reg | (shift << 8) | (mask << 16) | (invert << 24) }
+ .private_value = reg | (shift << 8) | (mask << 16) | (flags << 24) }
+
+#define ES18XX_FL_INVERT (1 << 0)
+#define ES18XX_FL_PMPORT (1 << 1)
static int snd_es18xx_info_single(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
@@ -1159,10 +1147,14 @@ static int snd_es18xx_get_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
+ int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
int val;
-
- val = snd_es18xx_reg_read(chip, reg);
+
+ if (pm_port)
+ val = inb(chip->port + ES18XX_PM);
+ else
+ val = snd_es18xx_reg_read(chip, reg);
ucontrol->value.integer.value[0] = (val >> shift) & mask;
if (invert)
ucontrol->value.integer.value[0] = mask - ucontrol->value.integer.value[0];
@@ -1175,7 +1167,8 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
int reg = kcontrol->private_value & 0xff;
int shift = (kcontrol->private_value >> 8) & 0xff;
int mask = (kcontrol->private_value >> 16) & 0xff;
- int invert = (kcontrol->private_value >> 24) & 0xff;
+ int invert = (kcontrol->private_value >> 24) & ES18XX_FL_INVERT;
+ int pm_port = (kcontrol->private_value >> 24) & ES18XX_FL_PMPORT;
unsigned char val;
val = (ucontrol->value.integer.value[0] & mask);
@@ -1183,6 +1176,15 @@ static int snd_es18xx_put_single(struct snd_kcontrol *kcontrol, struct snd_ctl_e
val = mask - val;
mask <<= shift;
val <<= shift;
+ if (pm_port) {
+ unsigned char cur = inb(chip->port + ES18XX_PM);
+
+ if ((cur & mask) == val)
+ return 0;
+ outb((cur & ~mask) | val, chip->port + ES18XX_PM);
+ return 1;
+ }
+
return snd_es18xx_reg_bits(chip, reg, mask, val) != val;
}
@@ -1304,7 +1306,7 @@ static struct snd_kcontrol_new snd_es18xx_opt_speaker =
ES18XX_SINGLE("Beep Playback Volume", 0, 0x3c, 0, 7, 0);
static struct snd_kcontrol_new snd_es18xx_opt_1869[] = {
-ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, 1),
+ES18XX_SINGLE("Capture Switch", 0, 0x1c, 4, 1, ES18XX_FL_INVERT),
ES18XX_SINGLE("Video Playback Switch", 0, 0x7f, 0, 1, 0),
ES18XX_DOUBLE("Mono Playback Volume", 0, 0x6d, 0x6d, 4, 0, 15, 0),
ES18XX_DOUBLE("Mono Capture Volume", 0, 0x6f, 0x6f, 4, 0, 15, 0)
@@ -1363,6 +1365,11 @@ static struct snd_kcontrol_new snd_es18xx_hw_volume_controls[] = {
ES18XX_SINGLE("Hardware Master Volume Split", 0, 0x64, 7, 1, 0),
};
+static struct snd_kcontrol_new snd_es18xx_opt_gpo_2bit[] = {
+ES18XX_SINGLE("GPO0 Switch", 0, ES18XX_PM, 0, 1, ES18XX_FL_PMPORT),
+ES18XX_SINGLE("GPO1 Switch", 0, ES18XX_PM, 1, 1, ES18XX_FL_PMPORT),
+};
+
static int snd_es18xx_config_read(struct snd_es18xx *chip, unsigned char reg)
{
int data;
@@ -1629,10 +1636,10 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
switch (chip->version) {
case 0x1868:
- chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL;
+ chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_CONTROL | ES18XX_GPO_2BIT;
break;
case 0x1869:
- chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV;
+ chip->caps = ES18XX_PCM2 | ES18XX_SPATIALIZER | ES18XX_RECMIX | ES18XX_NEW_RATE | ES18XX_AUXB | ES18XX_MONO | ES18XX_MUTEREC | ES18XX_CONTROL | ES18XX_HWV | ES18XX_GPO_2BIT;
break;
case 0x1878:
chip->caps = ES18XX_DUPLEX_MONO | ES18XX_DUPLEX_SAME | ES18XX_I2S | ES18XX_CONTROL;
@@ -1642,7 +1649,7 @@ static int snd_es18xx_probe(struct snd_es18xx *chip,
break;
case 0x1887:
case 0x1888:
- chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME;
+ chip->caps = ES18XX_PCM2 | ES18XX_RECMIX | ES18XX_AUXB | ES18XX_DUPLEX_SAME | ES18XX_GPO_2BIT;
break;
default:
snd_printk(KERN_ERR "[0x%lx] unsupported chip ES%x\n",
@@ -1944,6 +1951,15 @@ static int snd_es18xx_mixer(struct snd_card *card)
return err;
}
}
+ if (chip->caps & ES18XX_GPO_2BIT) {
+ for (idx = 0; idx < ARRAY_SIZE(snd_es18xx_opt_gpo_2bit); idx++) {
+ err = snd_ctl_add(card,
+ snd_ctl_new1(&snd_es18xx_opt_gpo_2bit[idx],
+ chip));
+ if (err < 0)
+ return err;
+ }
+ }
return 0;
}
diff --git a/sound/isa/msnd/msnd_pinnacle_mixer.c b/sound/isa/msnd/msnd_pinnacle_mixer.c
index 031dc69..17e49a0 100644
--- a/sound/isa/msnd/msnd_pinnacle_mixer.c
+++ b/sound/isa/msnd/msnd_pinnacle_mixer.c
@@ -55,20 +55,13 @@
static int snd_msndmix_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Analog", "MASS", "SPDIF",
};
struct snd_msnd *chip = snd_kcontrol_chip(kcontrol);
unsigned items = test_bit(F_HAVEDIGITAL, &chip->flags) ? 3 : 2;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = items;
- if (uinfo->value.enumerated.item >= items)
- uinfo->value.enumerated.item = items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, items, texts);
}
static int snd_msndmix_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/isa/sb/emu8000_synth.c b/sound/isa/sb/emu8000_synth.c
index 4e3fcfb..95b39be 100644
--- a/sound/isa/sb/emu8000_synth.c
+++ b/sound/isa/sb/emu8000_synth.c
@@ -105,8 +105,7 @@ static int snd_emu8000_delete_device(struct snd_seq_device *dev)
snd_device_free(dev->card, hw->pcm);
if (hw->emu)
snd_emux_free(hw->emu);
- if (hw->memhdr)
- snd_util_memhdr_free(hw->memhdr);
+ snd_util_memhdr_free(hw->memhdr);
hw->emu = NULL;
hw->memhdr = NULL;
return 0;
diff --git a/sound/isa/sb/sb16_main.c b/sound/isa/sb/sb16_main.c
index 0bbcd47..72b10f4 100644
--- a/sound/isa/sb/sb16_main.c
+++ b/sound/isa/sb/sb16_main.c
@@ -702,17 +702,11 @@ static int snd_sb16_get_dma_mode(struct snd_sb *chip)
static int snd_sb16_dma_control_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Auto", "Playback", "Capture"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_sb16_dma_control_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/isa/sb/sb_common.c b/sound/isa/sb/sb_common.c
index 3ef9906..f22b448 100644
--- a/sound/isa/sb/sb_common.c
+++ b/sound/isa/sb/sb_common.c
@@ -184,8 +184,7 @@ static int snd_sbdsp_probe(struct snd_sb * chip)
static int snd_sbdsp_free(struct snd_sb *chip)
{
- if (chip->res_port)
- release_and_free_resource(chip->res_port);
+ release_and_free_resource(chip->res_port);
if (chip->irq >= 0)
free_irq(chip->irq, (void *) chip);
#ifdef CONFIG_ISA
diff --git a/sound/isa/sb/sb_mixer.c b/sound/isa/sb/sb_mixer.c
index 1ff78ec..e403334 100644
--- a/sound/isa/sb/sb_mixer.c
+++ b/sound/isa/sb/sb_mixer.c
@@ -182,17 +182,11 @@ static int snd_sbmixer_put_double(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int snd_dt019x_input_sw_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[5] = {
+ static const char * const texts[5] = {
"CD", "Mic", "Line", "Synth", "Master"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_dt019x_input_sw_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -275,18 +269,11 @@ static int snd_dt019x_input_sw_put(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_als4k_mono_capture_route_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[3] = {
+ static const char * const texts[3] = {
"L chan only", "R chan only", "L ch/2 + R ch/2"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_als4k_mono_capture_route_get(struct snd_kcontrol *kcontrol,
@@ -335,17 +322,11 @@ static int snd_als4k_mono_capture_route_put(struct snd_kcontrol *kcontrol,
static int snd_sb8mixer_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[3] = {
+ static const char * const texts[3] = {
"Mic", "CD", "Line"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
diff --git a/sound/isa/wss/wss_lib.c b/sound/isa/wss/wss_lib.c
index 360b08b..347bb1b 100644
--- a/sound/isa/wss/wss_lib.c
+++ b/sound/isa/wss/wss_lib.c
@@ -1993,25 +1993,20 @@ EXPORT_SYMBOL(snd_wss_timer);
static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"Line", "Aux", "Mic", "Mix"
};
- static char *opl3sa_texts[4] = {
+ static const char * const opl3sa_texts[4] = {
"Line", "CD", "Mic", "Mix"
};
- static char *gusmax_texts[4] = {
+ static const char * const gusmax_texts[4] = {
"Line", "Synth", "Mic", "Mix"
};
- char **ptexts = texts;
+ const char * const *ptexts = texts;
struct snd_wss *chip = snd_kcontrol_chip(kcontrol);
if (snd_BUG_ON(!chip->card))
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
if (!strcmp(chip->card->driver, "GUS MAX"))
ptexts = gusmax_texts;
switch (chip->hardware) {
@@ -2023,8 +2018,7 @@ static int snd_wss_info_mux(struct snd_kcontrol *kcontrol,
ptexts = opl3sa_texts;
break;
}
- strcpy(uinfo->value.enumerated.name, ptexts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 4, ptexts);
}
static int snd_wss_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/mips/sgio2audio.c b/sound/mips/sgio2audio.c
index 04bb06c..33b08fc 100644
--- a/sound/mips/sgio2audio.c
+++ b/sound/mips/sgio2audio.c
@@ -201,17 +201,10 @@ static int sgio2audio_gain_put(struct snd_kcontrol *kcontrol,
static int sgio2audio_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[3] = {
+ static const char * const texts[3] = {
"Cam Mic", "Mic", "Line"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= 3)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int sgio2audio_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/oss/uart401.c b/sound/oss/uart401.c
index 279bc56..dae4d43 100644
--- a/sound/oss/uart401.c
+++ b/sound/oss/uart401.c
@@ -412,13 +412,10 @@ void unload_uart401(struct address_info *hw_config)
if (!devc->share_irq)
free_irq(devc->irq, devc);
- if (devc)
- {
- kfree(midi_devs[devc->my_dev]->converter);
- kfree(midi_devs[devc->my_dev]);
- kfree(devc);
- devc = NULL;
- }
+ kfree(midi_devs[devc->my_dev]->converter);
+ kfree(midi_devs[devc->my_dev]);
+ kfree(devc);
+
/* This kills midi_devs[x] */
sound_unload_mididev(hw_config->slots[4]);
}
diff --git a/sound/parisc/harmony.c b/sound/parisc/harmony.c
index 4b20be7..29604a2 100644
--- a/sound/parisc/harmony.c
+++ b/sound/parisc/harmony.c
@@ -776,15 +776,9 @@ static int
snd_harmony_captureroute_info(struct snd_kcontrol *kc,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Line", "Mic" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char * const texts[2] = { "Line", "Mic" };
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int
diff --git a/sound/pci/ac97/ac97_codec.c b/sound/pci/ac97/ac97_codec.c
index 14ad54b..5ee2f17 100644
--- a/sound/pci/ac97/ac97_codec.c
+++ b/sound/pci/ac97/ac97_codec.c
@@ -463,14 +463,8 @@ static int snd_ac97_info_enum_double(struct snd_kcontrol *kcontrol,
{
struct ac97_enum *e = (struct ac97_enum *)kcontrol->private_value;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
- uinfo->value.enumerated.items = e->mask;
-
- if (uinfo->value.enumerated.item > e->mask - 1)
- uinfo->value.enumerated.item = e->mask - 1;
- strcpy(uinfo->value.enumerated.name, e->texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2,
+ e->mask, e->texts);
}
static int snd_ac97_get_enum_double(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ac97/ac97_patch.c b/sound/pci/ac97/ac97_patch.c
index 9917622..ceaac1c 100644
--- a/sound/pci/ac97/ac97_patch.c
+++ b/sound/pci/ac97/ac97_patch.c
@@ -33,7 +33,8 @@
static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
const char *name);
static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
- const unsigned int *tlv, const char **slaves);
+ const unsigned int *tlv,
+ const char * const *slaves);
/*
* Chip specific initialization
@@ -81,22 +82,11 @@ static int ac97_update_bits_page(struct snd_ac97 *ac97, unsigned short reg, unsi
/*
* shared line-in/mic controls
*/
-static int ac97_enum_text_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo,
- const char **texts, unsigned int nums)
-{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = nums;
- if (uinfo->value.enumerated.item > nums - 1)
- uinfo->value.enumerated.item = nums - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-}
-
static int ac97_surround_jack_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[] = { "Shared", "Independent" };
- return ac97_enum_text_info(kcontrol, uinfo, texts, 2);
+ static const char * const texts[] = { "Shared", "Independent" };
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int ac97_surround_jack_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -123,9 +113,9 @@ static int ac97_surround_jack_mode_put(struct snd_kcontrol *kcontrol, struct snd
static int ac97_channel_mode_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[] = { "2ch", "4ch", "6ch", "8ch" };
- return ac97_enum_text_info(kcontrol, uinfo, texts,
- kcontrol->private_value);
+ static const char * const texts[] = { "2ch", "4ch", "6ch", "8ch" };
+
+ return snd_ctl_enum_info(uinfo, 1, kcontrol->private_value, texts);
}
static int ac97_channel_mode_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -240,17 +230,11 @@ static inline int alc850_is_aux_back_surround(struct snd_ac97 *ac97)
static int snd_ac97_ymf7x3_info_speaker(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {
+ static const char * const texts[3] = {
"Standard", "Small", "Smaller"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_ymf7x3_get_speaker(struct snd_kcontrol *kcontrol,
@@ -293,15 +277,9 @@ static const struct snd_kcontrol_new snd_ac97_ymf7x3_controls_speaker =
static int snd_ac97_ymf7x3_spdif_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "AC-Link", "A/D Converter" };
+ static const char * const texts[2] = { "AC-Link", "A/D Converter" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ac97_ymf7x3_spdif_source_get(struct snd_kcontrol *kcontrol,
@@ -401,15 +379,9 @@ static int patch_yamaha_ymf743(struct snd_ac97 *ac97)
There is also a bit to mute S/PDIF output in a vendor-specific register. */
static int snd_ac97_ymf753_spdif_output_pin_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = { "Disabled", "Pin 43", "Pin 48" };
+ static const char * const texts[3] = { "Disabled", "Pin 43", "Pin 48" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_ymf753_spdif_output_pin_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1103,16 +1075,11 @@ static int patch_sigmatel_stac9756(struct snd_ac97 * ac97)
static int snd_ac97_stac9758_output_jack_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = { "Input/Disabled", "Front Output",
+ static const char * const texts[5] = {
+ "Input/Disabled", "Front Output",
"Rear Output", "Center/LFE Output", "Mixer Output" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_ac97_stac9758_output_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1147,16 +1114,11 @@ static int snd_ac97_stac9758_output_jack_put(struct snd_kcontrol *kcontrol, stru
static int snd_ac97_stac9758_input_jack_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[7] = { "Mic2 Jack", "Mic1 Jack", "Line In Jack",
+ static const char * const texts[7] = {
+ "Mic2 Jack", "Mic1 Jack", "Line In Jack",
"Front Jack", "Rear Jack", "Center/LFE Jack", "Mute" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item > 6)
- uinfo->value.enumerated.item = 6;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 7, texts);
}
static int snd_ac97_stac9758_input_jack_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1181,15 +1143,11 @@ static int snd_ac97_stac9758_input_jack_put(struct snd_kcontrol *kcontrol, struc
static int snd_ac97_stac9758_phonesel_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = { "None", "Front Jack", "Rear Jack" };
+ static const char * const texts[3] = {
+ "None", "Front Jack", "Rear Jack"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_stac9758_phonesel_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1804,15 +1762,9 @@ static int patch_ad1886(struct snd_ac97 * ac97)
static int snd_ac97_ad198x_spdif_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "AC-Link", "A/D Converter" };
+ static const char * const texts[2] = { "AC-Link", "A/D Converter" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ac97_ad198x_spdif_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1994,15 +1946,9 @@ static int snd_ac97_ad1888_lohpsel_put(struct snd_kcontrol *kcontrol, struct snd
static int snd_ac97_ad1888_downmix_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"Off", "6 -> 4", "6 -> 2"};
+ static const char * const texts[3] = {"Off", "6 -> 4", "6 -> 2"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_ac97_ad1888_downmix_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2153,16 +2099,11 @@ static int patch_ad1980(struct snd_ac97 * ac97)
static int snd_ac97_ad1985_vrefout_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"High-Z", "3.7 V", "2.25 V", "0 V"};
+ static const char * const texts[4] = {
+ "High-Z", "3.7 V", "2.25 V", "0 V"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_ac97_ad1985_vrefout_get(struct snd_kcontrol *kcontrol,
@@ -2756,20 +2697,18 @@ static const struct snd_kcontrol_new snd_ac97_controls_alc655[] = {
static int alc655_iec958_route_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts_655[3] = { "PCM", "Analog In", "IEC958 In" };
- static char *texts_658[4] = { "PCM", "Analog1 In", "Analog2 In", "IEC958 In" };
+ static const char * const texts_655[3] = {
+ "PCM", "Analog In", "IEC958 In"
+ };
+ static const char * const texts_658[4] = {
+ "PCM", "Analog1 In", "Analog2 In", "IEC958 In"
+ };
struct snd_ac97 *ac97 = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ac97->spec.dev_flags ? 4 : 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- ac97->spec.dev_flags ?
- texts_658[uinfo->value.enumerated.item] :
- texts_655[uinfo->value.enumerated.item]);
- return 0;
+ if (ac97->spec.dev_flags)
+ return snd_ctl_enum_info(uinfo, 1, 4, texts_658);
+ else
+ return snd_ctl_enum_info(uinfo, 1, 3, texts_655);
}
static int alc655_iec958_route_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -3055,15 +2994,9 @@ static int patch_cm9738(struct snd_ac97 * ac97)
static int snd_ac97_cmedia_spdif_playback_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "Analog", "Digital" };
+ static const char * const texts[] = { "Analog", "Digital" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ac97_cmedia_spdif_playback_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -3235,15 +3168,9 @@ static const struct snd_kcontrol_new snd_ac97_cm9761_controls[] = {
static int cm9761_spdif_out_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = { "AC-Link", "ADC", "SPDIF-In" };
+ static const char * const texts[] = { "AC-Link", "ADC", "SPDIF-In" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int cm9761_spdif_out_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -3270,7 +3197,9 @@ static int cm9761_spdif_out_source_put(struct snd_kcontrol *kcontrol, struct snd
ucontrol->value.enumerated.item[0] == 1 ? 0x2 : 0);
}
-static const char *cm9761_dac_clock[] = { "AC-Link", "SPDIF-In", "Both" };
+static const char * const cm9761_dac_clock[] = {
+ "AC-Link", "SPDIF-In", "Both"
+};
static const struct ac97_enum cm9761_dac_clock_enum =
AC97_ENUM_SINGLE(AC97_CM9761_SPDIF_CTRL, 9, 3, cm9761_dac_clock);
@@ -3384,7 +3313,9 @@ static int patch_cm9761(struct snd_ac97 *ac97)
#define AC97_CM9780_MULTI_CHAN 0x66
#define AC97_CM9780_SPDIF 0x6c
-static const char *cm9780_ch_select[] = { "Front", "Side", "Center/LFE", "Rear" };
+static const char * const cm9780_ch_select[] = {
+ "Front", "Side", "Center/LFE", "Rear"
+};
static const struct ac97_enum cm9780_ch_select_enum =
AC97_ENUM_SINGLE(AC97_CM9780_MULTI_CHAN, 6, 4, cm9780_ch_select);
static const struct snd_kcontrol_new cm9780_controls[] = {
@@ -3430,7 +3361,7 @@ AC97_SINGLE("Downmix LFE and Center to Front", 0x5a, 12, 1, 0),
AC97_SINGLE("Downmix Surround to Front", 0x5a, 11, 1, 0),
};
-static const char *slave_vols_vt1616[] = {
+static const char * const slave_vols_vt1616[] = {
"Front Playback Volume",
"Surround Playback Volume",
"Center Playback Volume",
@@ -3438,7 +3369,7 @@ static const char *slave_vols_vt1616[] = {
NULL
};
-static const char *slave_sws_vt1616[] = {
+static const char * const slave_sws_vt1616[] = {
"Front Playback Switch",
"Surround Playback Switch",
"Center Playback Switch",
@@ -3459,10 +3390,11 @@ static struct snd_kcontrol *snd_ac97_find_mixer_ctl(struct snd_ac97 *ac97,
/* create a virtual master control and add slaves */
static int snd_ac97_add_vmaster(struct snd_ac97 *ac97, char *name,
- const unsigned int *tlv, const char **slaves)
+ const unsigned int *tlv,
+ const char * const *slaves)
{
struct snd_kcontrol *kctl;
- const char **s;
+ const char * const *s;
int err;
kctl = snd_ctl_make_virtual_master(name, tlv);
@@ -3552,11 +3484,12 @@ static int snd_ac97_vt1617a_smart51_info(struct snd_kcontrol *kcontrol,
* is SM51EN *AND* it's Bit14, not Bit15 so the table is very
* counter-intuitive */
- static const char* texts[] = { "LineIn Mic1", "LineIn Mic1 Mic3",
+ static const char * const texts[] = {"LineIn Mic1", "LineIn Mic1 Mic3",
"Surr LFE/C Mic3", "LineIn LFE/C Mic3",
"LineIn Mic2", "LineIn Mic2 Mic1",
"Surr LFE Mic1", "Surr LFE Mic1 Mic2"};
- return ac97_enum_text_info(kcontrol, uinfo, texts, 8);
+
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_ac97_vt1617a_smart51_get(struct snd_kcontrol *kcontrol,
@@ -3685,7 +3618,7 @@ static int patch_vt1617a(struct snd_ac97 * ac97)
struct vt1618_uaj_item {
unsigned short mask;
unsigned short shift;
- const char *items[4];
+ const char * const items[4];
};
/* This list reflects the vt1618 docs for Vendor Defined Register 0x60. */
@@ -3720,9 +3653,8 @@ static struct vt1618_uaj_item vt1618_uaj[3] = {
static int snd_ac97_vt1618_UAJ_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- return ac97_enum_text_info(kcontrol, uinfo,
- vt1618_uaj[kcontrol->private_value].items,
- 4);
+ return snd_ctl_enum_info(uinfo, 1, 4,
+ vt1618_uaj[kcontrol->private_value].items);
}
/* All of the vt1618 Universal Audio Jack twiddlers are on
@@ -3767,9 +3699,9 @@ static int snd_ac97_vt1618_UAJ_put(struct snd_kcontrol *kcontrol,
static int snd_ac97_vt1618_aux_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *txt_aux[] = {"Aux In", "Back Surr Out"};
+ static const char * const txt_aux[] = {"Aux In", "Back Surr Out"};
- return ac97_enum_text_info(kcontrol, uinfo, txt_aux, 2);
+ return snd_ctl_enum_info(uinfo, 1, 2, txt_aux);
}
static int snd_ac97_vt1618_aux_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ac97/ac97_patch.h b/sound/pci/ac97/ac97_patch.h
index 47bf8df..d1ce151 100644
--- a/sound/pci/ac97/ac97_patch.h
+++ b/sound/pci/ac97/ac97_patch.h
@@ -49,7 +49,7 @@ struct ac97_enum {
unsigned char shift_l;
unsigned char shift_r;
unsigned short mask;
- const char **texts;
+ const char * const *texts;
};
#define AC97_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xtexts) \
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c
index 5017176..e9273fb 100644
--- a/sound/pci/asihpi/asihpi.c
+++ b/sound/pci/asihpi/asihpi.c
@@ -1,6 +1,6 @@
/*
* Asihpi soundcard
- * Copyright (c) by AudioScience Inc <alsa@audioscience.com>
+ * Copyright (c) by AudioScience Inc <support@audioscience.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
@@ -28,7 +28,6 @@
#include "hpioctl.h"
#include "hpicmn.h"
-
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/jiffies.h>
@@ -47,7 +46,7 @@
MODULE_LICENSE("GPL");
MODULE_AUTHOR("AudioScience inc. <support@audioscience.com>");
-MODULE_DESCRIPTION("AudioScience ALSA ASI5000 ASI6000 ASI87xx ASI89xx "
+MODULE_DESCRIPTION("AudioScience ALSA ASI5xxx ASI6xxx ASI87xx ASI89xx "
HPI_VER_STRING);
#if defined CONFIG_SND_DEBUG_VERBOSE
@@ -87,11 +86,11 @@ MODULE_PARM_DESC(enable_hpi_hwdep,
#ifdef KERNEL_ALSA_BUILD
static char *build_info = "Built using headers from kernel source";
module_param(build_info, charp, S_IRUGO);
-MODULE_PARM_DESC(build_info, "built using headers from kernel source");
+MODULE_PARM_DESC(build_info, "Built using headers from kernel source");
#else
static char *build_info = "Built within ALSA source";
module_param(build_info, charp, S_IRUGO);
-MODULE_PARM_DESC(build_info, "built within ALSA source");
+MODULE_PARM_DESC(build_info, "Built within ALSA source");
#endif
/* set to 1 to dump every control from adapter to log */
@@ -110,7 +109,7 @@ static int adapter_fs = DEFAULT_SAMPLERATE;
struct clk_source {
int source;
int index;
- char *name;
+ const char *name;
};
struct clk_cache {
@@ -125,6 +124,16 @@ struct snd_card_asihpi {
struct pci_dev *pci;
struct hpi_adapter *hpi;
+ /* In low latency mode there is only one stream, a pointer to its
+ * private data is stored here on trigger and cleared on stop.
+ * The interrupt handler uses it as a parameter when calling
+ * snd_card_asihpi_timer_function().
+ */
+ struct snd_card_asihpi_pcm *llmode_streampriv;
+ struct tasklet_struct t;
+ void (*pcm_start)(struct snd_pcm_substream *substream);
+ void (*pcm_stop)(struct snd_pcm_substream *substream);
+
u32 h_mixer;
struct clk_cache cc;
@@ -289,21 +298,17 @@ static void print_hwparams(struct snd_pcm_substream *substream,
{
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printd("%s HWPARAMS\n", name);
- snd_printd(" samplerate %d Hz\n", params_rate(p));
- snd_printd(" channels %d\n", params_channels(p));
- snd_printd(" format %d\n", params_format(p));
- snd_printd(" subformat %d\n", params_subformat(p));
- snd_printd(" buffer %d B\n", params_buffer_bytes(p));
- snd_printd(" period %d B\n", params_period_bytes(p));
- snd_printd(" access %d\n", params_access(p));
- snd_printd(" period_size %d\n", params_period_size(p));
- snd_printd(" periods %d\n", params_periods(p));
- snd_printd(" buffer_size %d\n", params_buffer_size(p));
- snd_printd(" %d B/s\n", params_rate(p) *
- params_channels(p) *
+ snd_printdd("%s HWPARAMS\n", name);
+ snd_printdd(" samplerate=%dHz channels=%d format=%d subformat=%d\n",
+ params_rate(p), params_channels(p),
+ params_format(p), params_subformat(p));
+ snd_printdd(" buffer=%dB period=%dB period_size=%dB periods=%d\n",
+ params_buffer_bytes(p), params_period_bytes(p),
+ params_period_size(p), params_periods(p));
+ snd_printdd(" buffer_size=%d access=%d data_rate=%dB/s\n",
+ params_buffer_size(p), params_access(p),
+ params_rate(p) * params_channels(p) *
snd_pcm_format_width(params_format(p)) / 8);
-
}
static snd_pcm_format_t hpi_to_alsa_formats[] = {
@@ -375,7 +380,7 @@ static void snd_card_asihpi_pcm_samplerates(struct snd_card_asihpi *asihpi,
HPI_SOURCENODE_CLOCK_SOURCE, 0, 0, 0,
HPI_CONTROL_SAMPLECLOCK, &h_control);
if (err) {
- snd_printk(KERN_ERR
+ dev_err(&asihpi->pci->dev,
"No local sampleclock, err %d\n", err);
}
@@ -481,7 +486,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
params_buffer_bytes(params), runtime->dma_addr);
if (err == 0) {
snd_printdd(
- "stream_host_buffer_attach succeeded %u %lu\n",
+ "stream_host_buffer_attach success %u %lu\n",
params_buffer_bytes(params),
(unsigned long)runtime->dma_addr);
} else {
@@ -491,12 +496,7 @@ static int snd_card_asihpi_pcm_hw_params(struct snd_pcm_substream *substream,
}
err = hpi_stream_get_info_ex(dpcm->h_stream, NULL,
- &dpcm->hpi_buffer_attached,
- NULL, NULL, NULL);
-
- snd_printdd("stream_host_buffer_attach status 0x%x\n",
- dpcm->hpi_buffer_attached);
-
+ &dpcm->hpi_buffer_attached, NULL, NULL, NULL);
}
bytes_per_sec = params_rate(params) * params_channels(params);
width = snd_pcm_format_width(params_format(params));
@@ -538,7 +538,7 @@ static void snd_card_asihpi_pcm_timer_start(struct snd_pcm_substream *
int expiry;
expiry = HZ / 200;
- /*? (dpcm->period_bytes * HZ / dpcm->bytes_per_sec); */
+
expiry = max(expiry, 1); /* don't let it be zero! */
dpcm->timer.expires = jiffies + expiry;
dpcm->respawn_timer = 1;
@@ -554,6 +554,48 @@ static void snd_card_asihpi_pcm_timer_stop(struct snd_pcm_substream *substream)
del_timer(&dpcm->timer);
}
+static void snd_card_asihpi_pcm_int_start(struct snd_pcm_substream *substream)
+{
+ struct snd_card_asihpi_pcm *dpcm;
+ struct snd_card_asihpi *card;
+
+ BUG_ON(!substream);
+
+ dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data;
+ card = snd_pcm_substream_chip(substream);
+
+ BUG_ON(in_interrupt());
+ tasklet_disable(&card->t);
+ card->llmode_streampriv = dpcm;
+ tasklet_enable(&card->t);
+
+ hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
+ HPI_ADAPTER_PROPERTY_IRQ_RATE,
+ card->update_interval_frames, 0));
+}
+
+static void snd_card_asihpi_pcm_int_stop(struct snd_pcm_substream *substream)
+{
+ struct snd_card_asihpi_pcm *dpcm;
+ struct snd_card_asihpi *card;
+
+ BUG_ON(!substream);
+
+ dpcm = (struct snd_card_asihpi_pcm *)substream->runtime->private_data;
+ card = snd_pcm_substream_chip(substream);
+
+ hpi_handle_error(hpi_adapter_set_property(card->hpi->adapter->index,
+ HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
+
+ if (in_interrupt())
+ card->llmode_streampriv = NULL;
+ else {
+ tasklet_disable(&card->t);
+ card->llmode_streampriv = NULL;
+ tasklet_enable(&card->t);
+ }
+}
+
static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
int cmd)
{
@@ -564,10 +606,10 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
char name[16];
snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printdd("%s trigger\n", name);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
+ snd_printdd("%s trigger start\n", name);
snd_pcm_group_for_each_entry(s, substream) {
struct snd_pcm_runtime *runtime = s->runtime;
struct snd_card_asihpi_pcm *ds = runtime->private_data;
@@ -588,7 +630,7 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
* data??
*/
unsigned int preload = ds->period_bytes * 1;
- snd_printddd("%d preload x%x\n", s->number, preload);
+ snd_printddd("%d preload %d\n", s->number, preload);
hpi_handle_error(hpi_outstream_write_buf(
ds->h_stream,
&runtime->dma_area[0],
@@ -611,16 +653,16 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
} else
break;
}
- snd_printdd("start\n");
/* start the master stream */
- snd_card_asihpi_pcm_timer_start(substream);
+ card->pcm_start(substream);
if ((substream->stream == SNDRV_PCM_STREAM_CAPTURE) ||
!card->can_dma)
hpi_handle_error(hpi_stream_start(dpcm->h_stream));
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_card_asihpi_pcm_timer_stop(substream);
+ snd_printdd("%s trigger stop\n", name);
+ card->pcm_stop(substream);
snd_pcm_group_for_each_entry(s, substream) {
if (snd_pcm_substream_chip(s) != card)
continue;
@@ -638,7 +680,6 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
} else
break;
}
- snd_printdd("stop\n");
/* _prepare and _hwparams reset the stream */
hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
@@ -651,13 +692,13 @@ static int snd_card_asihpi_trigger(struct snd_pcm_substream *substream,
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- snd_printdd("pause release\n");
+ snd_printdd("%s trigger pause release\n", name);
+ card->pcm_start(substream);
hpi_handle_error(hpi_stream_start(dpcm->h_stream));
- snd_card_asihpi_pcm_timer_start(substream);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- snd_printdd("pause\n");
- snd_card_asihpi_pcm_timer_stop(substream);
+ snd_printdd("%s trigger pause push\n", name);
+ card->pcm_stop(substream);
hpi_handle_error(hpi_stream_stop(dpcm->h_stream));
break;
default:
@@ -729,9 +770,8 @@ static void snd_card_asihpi_timer_function(unsigned long data)
u32 buffer_size, bytes_avail, samples_played, on_card_bytes;
char name[16];
- snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printdd("%s snd_card_asihpi_timer_function\n", name);
+ snd_pcm_debug_name(substream, name, sizeof(name));
/* find minimum newdata and buffer pos in group */
snd_pcm_group_for_each_entry(s, substream) {
@@ -769,10 +809,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
s->number);
ds->drained_count++;
if (ds->drained_count > 20) {
- unsigned long flags;
- snd_pcm_stream_lock_irqsave(s, flags);
- snd_pcm_stop(s, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(s, flags);
+ snd_pcm_stop_xrun(s);
continue;
}
} else {
@@ -794,19 +831,21 @@ static void snd_card_asihpi_timer_function(unsigned long data)
newdata);
}
- snd_printdd("hw_ptr 0x%04lX, appl_ptr 0x%04lX\n",
+ snd_printddd(
+ "timer1, %s, %d, S=%d, elap=%d, rw=%d, dsp=%d, left=%d, aux=%d, space=%d, hw_ptr=%ld, appl_ptr=%ld\n",
+ name, s->number, state,
+ ds->pcm_buf_elapsed_dma_ofs,
+ ds->pcm_buf_host_rw_ofs,
+ pcm_buf_dma_ofs,
+ (int)bytes_avail,
+
+ (int)on_card_bytes,
+ buffer_size-bytes_avail,
(unsigned long)frames_to_bytes(runtime,
runtime->status->hw_ptr),
(unsigned long)frames_to_bytes(runtime,
- runtime->control->appl_ptr));
-
- snd_printdd("%d S=%d, "
- "rw=0x%04X, dma=0x%04X, left=0x%04X, "
- "aux=0x%04X space=0x%04X\n",
- s->number, state,
- ds->pcm_buf_host_rw_ofs, pcm_buf_dma_ofs,
- (int)bytes_avail,
- (int)on_card_bytes, buffer_size-bytes_avail);
+ runtime->control->appl_ptr)
+ );
loops++;
}
pcm_buf_dma_ofs = min_buf_pos;
@@ -824,16 +863,18 @@ static void snd_card_asihpi_timer_function(unsigned long data)
next_jiffies = max(next_jiffies, 1U);
dpcm->timer.expires = jiffies + next_jiffies;
- snd_printdd("jif %d buf pos 0x%04X newdata 0x%04X xfer 0x%04X\n",
+ snd_printddd("timer2, jif=%d, buf_pos=%d, newdata=%d, xfer=%d\n",
next_jiffies, pcm_buf_dma_ofs, newdata, xfercount);
snd_pcm_group_for_each_entry(s, substream) {
struct snd_card_asihpi_pcm *ds = s->runtime->private_data;
+ runtime = s->runtime;
/* don't link Cap and Play */
if (substream->stream != s->stream)
continue;
+ /* Store dma offset for use by pointer callback */
ds->pcm_buf_dma_ofs = pcm_buf_dma_ofs;
if (xfercount &&
@@ -856,7 +897,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
}
if (s->stream == SNDRV_PCM_STREAM_PLAYBACK) {
- snd_printddd("P%d write1 0x%04X 0x%04X\n",
+ snd_printddd("write1, P=%d, xfer=%d, buf_ofs=%d\n",
s->number, xfer1, buf_ofs);
hpi_handle_error(
hpi_outstream_write_buf(
@@ -866,7 +907,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
if (xfer2) {
pd = s->runtime->dma_area;
- snd_printddd("P%d write2 0x%04X 0x%04X\n",
+ snd_printddd("write2, P=%d, xfer=%d, buf_ofs=%d\n",
s->number,
xfercount - xfer1, buf_ofs);
hpi_handle_error(
@@ -876,7 +917,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
&ds->format));
}
} else {
- snd_printddd("C%d read1 0x%04x\n",
+ snd_printddd("read1, C=%d, xfer=%d\n",
s->number, xfer1);
hpi_handle_error(
hpi_instream_read_buf(
@@ -884,7 +925,7 @@ static void snd_card_asihpi_timer_function(unsigned long data)
pd, xfer1));
if (xfer2) {
pd = s->runtime->dma_area;
- snd_printddd("C%d read2 0x%04x\n",
+ snd_printddd("read2, C=%d, xfer=%d\n",
s->number, xfer2);
hpi_handle_error(
hpi_instream_read_buf(
@@ -892,16 +933,38 @@ static void snd_card_asihpi_timer_function(unsigned long data)
pd, xfer2));
}
}
+ /* ? host_rw_ofs always ahead of elapsed_dma_ofs by preload size? */
ds->pcm_buf_host_rw_ofs += xfercount;
ds->pcm_buf_elapsed_dma_ofs += xfercount;
snd_pcm_period_elapsed(s);
}
}
- if (dpcm->respawn_timer)
+ if (!card->hpi->interrupt_mode && dpcm->respawn_timer)
add_timer(&dpcm->timer);
}
+static void snd_card_asihpi_int_task(unsigned long data)
+{
+ struct hpi_adapter *a = (struct hpi_adapter *)data;
+ struct snd_card_asihpi *asihpi;
+
+ WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
+ asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
+ if (asihpi->llmode_streampriv)
+ snd_card_asihpi_timer_function(
+ (unsigned long)asihpi->llmode_streampriv);
+}
+
+static void snd_card_asihpi_isr(struct hpi_adapter *a)
+{
+ struct snd_card_asihpi *asihpi;
+
+ WARN_ON(!a || !a->snd_card || !a->snd_card->private_data);
+ asihpi = (struct snd_card_asihpi *)a->snd_card->private_data;
+ tasklet_schedule(&asihpi->t);
+}
+
/***************************** PLAYBACK OPS ****************/
static int snd_card_asihpi_playback_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
@@ -937,7 +1000,7 @@ snd_card_asihpi_playback_pointer(struct snd_pcm_substream *substream)
snd_pcm_debug_name(substream, name, sizeof(name));
ptr = bytes_to_frames(runtime, dpcm->pcm_buf_dma_ofs % dpcm->buffer_bytes);
- snd_printddd("%s pointer = 0x%04lx\n", name, (unsigned long)ptr);
+ snd_printddd("%s, pointer=%ld\n", name, (unsigned long)ptr);
return ptr;
}
@@ -1009,13 +1072,22 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_card_asihpi_runtime_free;
memset(&snd_card_asihpi_playback, 0, sizeof(snd_card_asihpi_playback));
- snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
- snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;
- /*?snd_card_asihpi_playback.period_bytes_min =
- card->out_max_chans * 4096; */
- snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
- snd_card_asihpi_playback.periods_min = PERIODS_MIN;
- snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ if (!card->hpi->interrupt_mode) {
+ snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_playback.period_bytes_min = PERIOD_BYTES_MIN;
+ snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_playback.periods_min = PERIODS_MIN;
+ snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ } else {
+ size_t pbmin = card->update_interval_frames *
+ card->out_max_chans;
+ snd_card_asihpi_playback.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_playback.period_bytes_min = pbmin;
+ snd_card_asihpi_playback.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_playback.periods_min = PERIODS_MIN;
+ snd_card_asihpi_playback.periods_max = BUFFER_BYTES_MAX / pbmin;
+ }
+
/* snd_card_asihpi_playback.fifo_size = 0; */
snd_card_asihpi_playback.channels_max = card->out_max_chans;
snd_card_asihpi_playback.channels_min = card->out_min_chans;
@@ -1050,7 +1122,7 @@ static int snd_card_asihpi_playback_open(struct snd_pcm_substream *substream)
card->update_interval_frames);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- card->update_interval_frames * 2, UINT_MAX);
+ card->update_interval_frames, UINT_MAX);
snd_printdd("playback open\n");
@@ -1085,9 +1157,10 @@ snd_card_asihpi_capture_pointer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime = substream->runtime;
struct snd_card_asihpi_pcm *dpcm = runtime->private_data;
+ char name[16];
+ snd_pcm_debug_name(substream, name, sizeof(name));
- snd_printddd("capture pointer %d=%d\n",
- substream->number, dpcm->pcm_buf_dma_ofs);
+ snd_printddd("%s, pointer=%d\n", name, dpcm->pcm_buf_dma_ofs);
/* NOTE Unlike playback can't use actual samples_played
for the capture position, because those samples aren't yet in
the local buffer available for reading.
@@ -1115,8 +1188,6 @@ static int snd_card_asihpi_capture_prepare(struct snd_pcm_substream *substream)
return 0;
}
-
-
static u64 snd_card_asihpi_capture_formats(struct snd_card_asihpi *asihpi,
u32 h_stream)
{
@@ -1183,11 +1254,21 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
runtime->private_free = snd_card_asihpi_runtime_free;
memset(&snd_card_asihpi_capture, 0, sizeof(snd_card_asihpi_capture));
- snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
- snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;
- snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
- snd_card_asihpi_capture.periods_min = PERIODS_MIN;
- snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ if (!card->hpi->interrupt_mode) {
+ snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_capture.period_bytes_min = PERIOD_BYTES_MIN;
+ snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_capture.periods_min = PERIODS_MIN;
+ snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / PERIOD_BYTES_MIN;
+ } else {
+ size_t pbmin = card->update_interval_frames *
+ card->out_max_chans;
+ snd_card_asihpi_capture.buffer_bytes_max = BUFFER_BYTES_MAX;
+ snd_card_asihpi_capture.period_bytes_min = pbmin;
+ snd_card_asihpi_capture.period_bytes_max = BUFFER_BYTES_MAX / PERIODS_MIN;
+ snd_card_asihpi_capture.periods_min = PERIODS_MIN;
+ snd_card_asihpi_capture.periods_max = BUFFER_BYTES_MAX / pbmin;
+ }
/* snd_card_asihpi_capture.fifo_size = 0; */
snd_card_asihpi_capture.channels_max = card->in_max_chans;
snd_card_asihpi_capture.channels_min = card->in_min_chans;
@@ -1212,7 +1293,7 @@ static int snd_card_asihpi_capture_open(struct snd_pcm_substream *substream)
snd_pcm_hw_constraint_step(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
card->update_interval_frames);
snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_SIZE,
- card->update_interval_frames * 2, UINT_MAX);
+ card->update_interval_frames, UINT_MAX);
snd_pcm_set_sync(substream);
@@ -1296,8 +1377,9 @@ static const char * const asihpi_tuner_band_names[] = {
"TV PAL I",
"TV PAL DK",
"TV SECAM",
+ "TV DAB",
};
-
+/* Number of strings must match the enumerations for HPI_TUNER_BAND in hpi.h */
compile_time_assert(
(ARRAY_SIZE(asihpi_tuner_band_names) ==
(HPI_TUNER_BAND_LAST+1)),
@@ -1317,9 +1399,11 @@ static const char * const asihpi_src_names[] = {
"Analog",
"Adapter",
"RTP",
- "Internal"
+ "Internal",
+ "AVB",
+ "BLU-Link"
};
-
+/* Number of strings must match the enumerations for HPI_SOURCENODES in hpi.h */
compile_time_assert(
(ARRAY_SIZE(asihpi_src_names) ==
(HPI_SOURCENODE_LAST_INDEX-HPI_SOURCENODE_NONE+1)),
@@ -1335,8 +1419,11 @@ static const char * const asihpi_dst_names[] = {
"Net",
"Analog",
"RTP",
+ "AVB",
+ "Internal",
+ "BLU-Link"
};
-
+/* Number of strings must match the enumerations for HPI_DESTNODES in hpi.h */
compile_time_assert(
(ARRAY_SIZE(asihpi_dst_names) ==
(HPI_DESTNODE_LAST_INDEX-HPI_DESTNODE_NONE+1)),
@@ -1351,7 +1438,7 @@ static inline int ctl_add(struct snd_card *card, struct snd_kcontrol_new *ctl,
if (err < 0)
return err;
else if (mixer_dump)
- snd_printk(KERN_INFO "added %s(%d)\n", ctl->name, ctl->index);
+ dev_info(&asihpi->pci->dev, "added %s(%d)\n", ctl->name, ctl->index);
return 0;
}
@@ -1625,18 +1712,7 @@ static const char * const asihpi_aesebu_format_names[] = {
static int snd_asihpi_aesebu_format_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
-
- strcpy(uinfo->value.enumerated.name,
- asihpi_aesebu_format_names[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, asihpi_aesebu_format_names);
}
static int snd_asihpi_aesebu_format_get(struct snd_kcontrol *kcontrol,
@@ -1863,22 +1939,7 @@ static int snd_asihpi_tuner_band_info(struct snd_kcontrol *kcontrol,
if (num_bands < 0)
return num_bands;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = num_bands;
-
- if (num_bands > 0) {
- if (uinfo->value.enumerated.item >=
- uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
-
- strcpy(uinfo->value.enumerated.name,
- asihpi_tuner_band_names[
- tuner_bands[uinfo->value.enumerated.item]]);
-
- }
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_bands, asihpi_tuner_band_names);
}
static int snd_asihpi_tuner_band_get(struct snd_kcontrol *kcontrol,
@@ -2253,7 +2314,7 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
u32 h_control = kcontrol->private_value;
u16 mode;
int i;
- u16 mode_map[6];
+ const char *mapped_names[6];
int valid_modes = 0;
/* HPI channel mode values can be from 1 to 6
@@ -2262,24 +2323,14 @@ static int snd_asihpi_cmode_info(struct snd_kcontrol *kcontrol,
for (i = 0; i < HPI_CHANNEL_MODE_LAST; i++)
if (!hpi_channel_mode_query_mode(
h_control, i, &mode)) {
- mode_map[valid_modes] = mode;
+ mapped_names[valid_modes] = mode_names[mode];
valid_modes++;
}
if (!valid_modes)
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = valid_modes;
-
- if (uinfo->value.enumerated.item >= valid_modes)
- uinfo->value.enumerated.item = valid_modes - 1;
-
- strcpy(uinfo->value.enumerated.name,
- mode_names[mode_map[uinfo->value.enumerated.item]]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, valid_modes, mapped_names);
}
static int snd_asihpi_cmode_get(struct snd_kcontrol *kcontrol,
@@ -2328,13 +2379,18 @@ static int snd_asihpi_cmode_add(struct snd_card_asihpi *asihpi,
/*------------------------------------------------------------
Sampleclock source controls
------------------------------------------------------------*/
-static char *sampleclock_sources[MAX_CLOCKSOURCES] = {
+static const char const *sampleclock_sources[] = {
"N/A", "Local PLL", "Digital Sync", "Word External", "Word Header",
"SMPTE", "Digital1", "Auto", "Network", "Invalid",
- "Prev Module",
+ "Prev Module", "BLU-Link",
"Digital2", "Digital3", "Digital4", "Digital5",
"Digital6", "Digital7", "Digital8"};
+ /* Number of strings must match expected enumerated values */
+ compile_time_assert(
+ (ARRAY_SIZE(sampleclock_sources) == MAX_CLOCKSOURCES),
+ assert_sampleclock_sources_size);
+
static int snd_asihpi_clksrc_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -2482,15 +2538,19 @@ static int snd_asihpi_clkrate_get(struct snd_kcontrol *kcontrol,
static int snd_asihpi_sampleclock_add(struct snd_card_asihpi *asihpi,
struct hpi_control *hpi_ctl)
{
- struct snd_card *card = asihpi->card;
+ struct snd_card *card;
struct snd_kcontrol_new snd_control;
- struct clk_cache *clkcache = &asihpi->cc;
+ struct clk_cache *clkcache;
u32 hSC = hpi_ctl->h_control;
int has_aes_in = 0;
int i, j;
u16 source;
+ if (snd_BUG_ON(!asihpi))
+ return -EINVAL;
+ card = asihpi->card;
+ clkcache = &asihpi->cc;
snd_control.private_value = hpi_ctl->h_control;
clkcache->has_local = 0;
@@ -2592,7 +2652,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (err) {
if (err == HPI_ERROR_CONTROL_DISABLED) {
if (mixer_dump)
- snd_printk(KERN_INFO
+ dev_info(&asihpi->pci->dev,
"Disabled HPI Control(%d)\n",
idx);
continue;
@@ -2657,9 +2717,8 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
case HPI_CONTROL_COMPANDER:
default:
if (mixer_dump)
- snd_printk(KERN_INFO
- "Untranslated HPI Control"
- "(%d) %d %d %d %d %d\n",
+ dev_info(&asihpi->pci->dev,
+ "Untranslated HPI Control (%d) %d %d %d %d %d\n",
idx,
hpi_ctl.control_type,
hpi_ctl.src_node_type,
@@ -2674,7 +2733,7 @@ static int snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi)
if (HPI_ERROR_INVALID_OBJ_INDEX != err)
hpi_handle_error(err);
- snd_printk(KERN_INFO "%d mixer controls found\n", idx);
+ dev_info(&asihpi->pci->dev, "%d mixer controls found\n", idx);
return 0;
}
@@ -2837,8 +2896,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
&card);
if (err < 0)
return err;
- snd_printk(KERN_WARNING
- "**** WARNING **** Adapter index %d->ALSA index %d\n",
+ dev_warn(&pci_dev->dev, "Adapter index %d->ALSA index %d\n",
adapter_index, card->number);
}
@@ -2846,9 +2904,7 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
asihpi->card = card;
asihpi->pci = pci_dev;
asihpi->hpi = hpi;
-
- snd_printk(KERN_INFO "adapter ID=%4X index=%d\n",
- asihpi->hpi->adapter->type, adapter_index);
+ hpi->snd_card = card;
err = hpi_adapter_get_property(adapter_index,
HPI_ADAPTER_PROPERTY_CAPS1,
@@ -2868,8 +2924,16 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
if (err)
asihpi->update_interval_frames = 512;
- if (!asihpi->can_dma)
- asihpi->update_interval_frames *= 2;
+ if (hpi->interrupt_mode) {
+ asihpi->pcm_start = snd_card_asihpi_pcm_int_start;
+ asihpi->pcm_stop = snd_card_asihpi_pcm_int_stop;
+ tasklet_init(&asihpi->t, snd_card_asihpi_int_task,
+ (unsigned long)hpi);
+ hpi->interrupt_callback = snd_card_asihpi_isr;
+ } else {
+ asihpi->pcm_start = snd_card_asihpi_pcm_timer_start;
+ asihpi->pcm_stop = snd_card_asihpi_pcm_timer_stop;
+ }
hpi_handle_error(hpi_instream_open(adapter_index,
0, &h_stream));
@@ -2879,6 +2943,9 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
hpi_handle_error(hpi_instream_close(h_stream));
+ if (!asihpi->can_dma)
+ asihpi->update_interval_frames *= 2;
+
err = hpi_adapter_get_property(adapter_index,
HPI_ADAPTER_PROPERTY_CURCHANNELS,
&asihpi->in_max_chans, &asihpi->out_max_chans);
@@ -2896,20 +2963,21 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
asihpi->in_min_chans = 1;
}
- snd_printk(KERN_INFO "Has dma:%d, grouping:%d, mrx:%d\n",
+ dev_info(&pci_dev->dev, "Has dma:%d, grouping:%d, mrx:%d, uif:%d\n",
asihpi->can_dma,
asihpi->support_grouping,
- asihpi->support_mrx
+ asihpi->support_mrx,
+ asihpi->update_interval_frames
);
err = snd_card_asihpi_pcm_new(asihpi, 0);
if (err < 0) {
- snd_printk(KERN_ERR "pcm_new failed\n");
+ dev_err(&pci_dev->dev, "pcm_new failed\n");
goto __nodev;
}
err = snd_card_asihpi_mixer_new(asihpi);
if (err < 0) {
- snd_printk(KERN_ERR "mixer_new failed\n");
+ dev_err(&pci_dev->dev, "mixer_new failed\n");
goto __nodev;
}
@@ -2936,13 +3004,12 @@ static int snd_asihpi_probe(struct pci_dev *pci_dev,
err = snd_card_register(card);
if (!err) {
- hpi->snd_card = card;
dev++;
return 0;
}
__nodev:
snd_card_free(card);
- snd_printk(KERN_ERR "snd_asihpi_probe error %d\n", err);
+ dev_err(&pci_dev->dev, "snd_asihpi_probe error %d\n", err);
return err;
}
@@ -2950,6 +3017,16 @@ __nodev:
static void snd_asihpi_remove(struct pci_dev *pci_dev)
{
struct hpi_adapter *hpi = pci_get_drvdata(pci_dev);
+ struct snd_card_asihpi *asihpi = hpi->snd_card->private_data;
+
+ /* Stop interrupts */
+ if (hpi->interrupt_mode) {
+ hpi->interrupt_callback = NULL;
+ hpi_handle_error(hpi_adapter_set_property(hpi->adapter->index,
+ HPI_ADAPTER_PROPERTY_IRQ_RATE, 0, 0));
+ tasklet_kill(&asihpi->t);
+ }
+
snd_card_free(hpi->snd_card);
hpi->snd_card = NULL;
asihpi_adapter_remove(pci_dev);
@@ -2971,10 +3048,6 @@ static struct pci_driver driver = {
.id_table = asihpi_pci_tbl,
.probe = snd_asihpi_probe,
.remove = snd_asihpi_remove,
-#ifdef CONFIG_PM_SLEEP
-/* .suspend = snd_asihpi_suspend,
- .resume = snd_asihpi_resume, */
-#endif
};
static int __init snd_asihpi_init(void)
diff --git a/sound/pci/asihpi/hpi.h b/sound/pci/asihpi/hpi.h
index 2088724..4466bd2 100644
--- a/sound/pci/asihpi/hpi.h
+++ b/sound/pci/asihpi/hpi.h
@@ -196,8 +196,10 @@ enum HPI_SOURCENODES {
packets of RTP audio samples from other devices. */
HPI_SOURCENODE_RTP_DESTINATION = 112,
HPI_SOURCENODE_INTERNAL = 113, /**< node internal to the device. */
+ HPI_SOURCENODE_AVB = 114, /**< AVB input stream */
+ HPI_SOURCENODE_BLULINK = 115, /**< BLU-link input channel */
/* !!!Update this AND hpidebug.h if you add a new sourcenode type!!! */
- HPI_SOURCENODE_LAST_INDEX = 113 /**< largest ID */
+ HPI_SOURCENODE_LAST_INDEX = 115 /**< largest ID */
/* AX6 max sourcenode types = 15 */
};
@@ -224,8 +226,11 @@ enum HPI_DESTNODES {
/** RTP stream output node - This node is a source for
packets of RTP audio samples that are sent to other devices. */
HPI_DESTNODE_RTP_SOURCE = 208,
+ HPI_DESTNODE_AVB = 209, /**< AVB output stream */
+ HPI_DESTNODE_INTERNAL = 210, /**< node internal to the device. */
+ HPI_DESTNODE_BLULINK = 211, /**< BLU-link output channel. */
/* !!!Update this AND hpidebug.h if you add a new destnode type!!! */
- HPI_DESTNODE_LAST_INDEX = 208 /**< largest ID */
+ HPI_DESTNODE_LAST_INDEX = 211 /**< largest ID */
/* AX6 max destnode types = 15 */
};
@@ -752,7 +757,8 @@ enum HPI_TUNER_BAND {
HPI_TUNER_BAND_TV_PAL_I = 7, /**< PAL-I TV band*/
HPI_TUNER_BAND_TV_PAL_DK = 8, /**< PAL-D/K TV band*/
HPI_TUNER_BAND_TV_SECAM_L = 9, /**< SECAM-L TV band*/
- HPI_TUNER_BAND_LAST = 9 /**< the index of the last tuner band. */
+ HPI_TUNER_BAND_DAB = 10,
+ HPI_TUNER_BAND_LAST = 10 /**< the index of the last tuner band. */
};
/** Tuner mode attributes
@@ -842,8 +848,10 @@ enum HPI_SAMPLECLOCK_SOURCES {
HPI_SAMPLECLOCK_SOURCE_NETWORK = 8,
/** From previous adjacent module (ASI2416 only)*/
HPI_SAMPLECLOCK_SOURCE_PREV_MODULE = 10,
+/** Blu link sample clock*/
+ HPI_SAMPLECLOCK_SOURCE_BLULINK = 11,
/*! Update this if you add a new clock source.*/
- HPI_SAMPLECLOCK_SOURCE_LAST = 10
+ HPI_SAMPLECLOCK_SOURCE_LAST = 11
};
/** Equalizer filter types. Used by HPI_ParametricEq_SetBand()
diff --git a/sound/pci/asihpi/hpi6205.c b/sound/pci/asihpi/hpi6205.c
index 4f28738..8d5abfa 100644
--- a/sound/pci/asihpi/hpi6205.c
+++ b/sound/pci/asihpi/hpi6205.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -163,6 +163,9 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
static void delete_adapter_obj(struct hpi_adapter_obj *pao);
+static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
+ u32 message);
+
static void outstream_host_buffer_allocate(struct hpi_adapter_obj *pao,
struct hpi_message *phm, struct hpi_response *phr);
@@ -283,7 +286,6 @@ static void adapter_message(struct hpi_adapter_obj *pao,
case HPI_ADAPTER_DELETE:
adapter_delete(pao, phm, phr);
break;
-
default:
hw_message(pao, phm, phr);
break;
@@ -673,6 +675,12 @@ static u16 create_adapter_obj(struct hpi_adapter_obj *pao,
HPI_DEBUG_LOG(INFO, "bootload DSP OK\n");
+ pao->irq_query_and_clear = adapter_irq_query_and_clear;
+ pao->instream_host_buffer_status =
+ phw->p_interface_buffer->instream_host_buffer_status;
+ pao->outstream_host_buffer_status =
+ phw->p_interface_buffer->outstream_host_buffer_status;
+
return hpi_add_adapter(pao);
}
@@ -713,6 +721,21 @@ static void delete_adapter_obj(struct hpi_adapter_obj *pao)
/*****************************************************************************/
/* Adapter functions */
+static int adapter_irq_query_and_clear(struct hpi_adapter_obj *pao,
+ u32 message)
+{
+ struct hpi_hw_obj *phw = pao->priv;
+ u32 hsr = 0;
+
+ hsr = ioread32(phw->prHSR);
+ if (hsr & C6205_HSR_INTSRC) {
+ /* reset the interrupt from the DSP */
+ iowrite32(C6205_HSR_INTSRC, phw->prHSR);
+ return HPI_IRQ_MIXER;
+ }
+
+ return HPI_IRQ_NONE;
+}
/*****************************************************************************/
/* OutStream Host buffer functions */
@@ -1331,17 +1354,21 @@ static u16 adapter_boot_load_dsp(struct hpi_adapter_obj *pao,
if (boot_code_id[1] != 0) {
/* DSP 1 is a C6713 */
/* CLKX0 <- '1' release the C6205 bootmode pulldowns */
- boot_loader_write_mem32(pao, 0, (0x018C0024L), 0x00002202);
+ boot_loader_write_mem32(pao, 0, 0x018C0024, 0x00002202);
hpios_delay_micro_seconds(100);
/* Reset the 6713 #1 - revB */
boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 0);
-
- /* dummy read every 4 words for 6205 advisory 1.4.4 */
- boot_loader_read_mem32(pao, 0, 0);
-
+ /* value of bit 3 is unknown after DSP reset, other bits shoudl be 0 */
+ if (0 != (boot_loader_read_mem32(pao, 0,
+ (C6205_BAR0_TIMER1_CTL)) & ~8))
+ return HPI6205_ERROR_6205_REG;
hpios_delay_micro_seconds(100);
+
/* Release C6713 from reset - revB */
boot_loader_write_mem32(pao, 0, C6205_BAR0_TIMER1_CTL, 4);
+ if (4 != (boot_loader_read_mem32(pao, 0,
+ (C6205_BAR0_TIMER1_CTL)) & ~8))
+ return HPI6205_ERROR_6205_REG;
hpios_delay_micro_seconds(100);
}
@@ -2089,7 +2116,7 @@ static u16 message_response_sequence(struct hpi_adapter_obj *pao,
return 0;
}
- /* Assume buffer of type struct bus_master_interface
+ /* Assume buffer of type struct bus_master_interface_62
is allocated "noncacheable" */
if (!wait_dsp_ack(phw, H620_HIF_IDLE, HPI6205_TIMEOUT)) {
diff --git a/sound/pci/asihpi/hpi_internal.h b/sound/pci/asihpi/hpi_internal.h
index bc86cb7..48380ce 100644
--- a/sound/pci/asihpi/hpi_internal.h
+++ b/sound/pci/asihpi/hpi_internal.h
@@ -554,17 +554,21 @@ struct hpi_pci {
struct pci_dev *pci_dev;
};
+/** Adapter specification resource */
+struct hpi_adapter_specification {
+ u32 type;
+ u8 modules[4];
+};
+
struct hpi_resource {
union {
const struct hpi_pci *pci;
const char *net_if;
+ struct hpi_adapter_specification adapter_spec;
+ const void *sw_if;
} r;
-#ifndef HPI64BIT /* keep structure size constant */
- u32 pad_to64;
-#endif
u16 bus_type; /* HPI_BUS_PNPISA, _PCI, _USB etc */
u16 padding;
-
};
/** Format info used inside struct hpi_message
@@ -582,7 +586,7 @@ struct hpi_msg_format {
struct hpi_msg_data {
struct hpi_msg_format format;
u8 *pb_data;
-#ifndef HPI64BIT
+#ifndef CONFIG_64BIT
u32 padding;
#endif
u32 data_size;
@@ -595,7 +599,7 @@ struct hpi_data_legacy32 {
u32 data_size;
};
-#ifdef HPI64BIT
+#ifdef CONFIG_64BIT
/* Compatibility version of struct hpi_data*/
struct hpi_data_compat32 {
struct hpi_msg_format format;
@@ -682,8 +686,8 @@ union hpi_adapterx_msg {
u16 value;
} test_assert;
struct {
- u32 yes;
- } irq_query;
+ u32 message;
+ } irq;
u32 pad[3];
};
diff --git a/sound/pci/asihpi/hpicmn.c b/sound/pci/asihpi/hpicmn.c
index 7ed5c26..c775124 100644
--- a/sound/pci/asihpi/hpicmn.c
+++ b/sound/pci/asihpi/hpicmn.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -206,6 +206,14 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
struct hpi_control_cache_info *info =
(struct hpi_control_cache_info *)
&p_master_cache[byte_count];
+ u16 control_index = info->control_index;
+
+ if (control_index >= pC->control_count) {
+ HPI_DEBUG_LOG(INFO,
+ "adap %d control index %d out of range, cache not ready?\n",
+ pC->adap_idx, control_index);
+ return 0;
+ }
if (!info->size_in32bit_words) {
if (!i) {
@@ -225,10 +233,10 @@ static unsigned int control_cache_alloc_check(struct hpi_control_cache *pC)
}
if (info->control_type) {
- pC->p_info[info->control_index] = info;
+ pC->p_info[control_index] = info;
cached++;
} else { /* dummy cache entry */
- pC->p_info[info->control_index] = NULL;
+ pC->p_info[control_index] = NULL;
}
byte_count += info->size_in32bit_words * 4;
@@ -309,35 +317,18 @@ static const struct pad_ofs_size pad_desc[] = {
/** CheckControlCache checks the cache and fills the struct hpi_response
* accordingly. It returns one if a cache hit occurred, zero otherwise.
*/
-short hpi_check_control_cache(struct hpi_control_cache *p_cache,
+short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
struct hpi_message *phm, struct hpi_response *phr)
{
- short found = 1;
- struct hpi_control_cache_info *pI;
- struct hpi_control_cache_single *pC;
size_t response_size;
- if (!find_control(phm->obj_index, p_cache, &pI)) {
- HPI_DEBUG_LOG(VERBOSE,
- "HPICMN find_control() failed for adap %d\n",
- phm->adapter_index);
- return 0;
- }
-
- phr->error = 0;
- phr->specific_error = 0;
- phr->version = 0;
+ short found = 1;
/* set the default response size */
response_size =
sizeof(struct hpi_response_header) +
sizeof(struct hpi_control_res);
- /* pC is the default cached control strucure. May be cast to
- something else in the following switch statement.
- */
- pC = (struct hpi_control_cache_single *)pI;
-
- switch (pI->control_type) {
+ switch (pC->u.i.control_type) {
case HPI_CONTROL_METER:
if (phm->u.c.attribute == HPI_METER_PEAK) {
@@ -467,7 +458,7 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
break;
case HPI_CONTROL_PAD:{
struct hpi_control_cache_pad *p_pad;
- p_pad = (struct hpi_control_cache_pad *)pI;
+ p_pad = (struct hpi_control_cache_pad *)pC;
if (!(p_pad->field_valid_flags & (1 <<
HPI_CTL_ATTR_INDEX(phm->u.c.
@@ -531,7 +522,8 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
HPI_DEBUG_LOG(VERBOSE, "%s Adap %d, Ctl %d, Type %d, Attr %d\n",
found ? "Cached" : "Uncached", phm->adapter_index,
- pI->control_index, pI->control_type, phm->u.c.attribute);
+ pC->u.i.control_index, pC->u.i.control_type,
+ phm->u.c.attribute);
if (found) {
phr->size = (u16)response_size;
@@ -543,34 +535,36 @@ short hpi_check_control_cache(struct hpi_control_cache *p_cache,
return found;
}
-/** Updates the cache with Set values.
-
-Only update if no error.
-Volume and Level return the limited values in the response, so use these
-Multiplexer does so use sent values
-*/
-void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
+short hpi_check_control_cache(struct hpi_control_cache *p_cache,
struct hpi_message *phm, struct hpi_response *phr)
{
- struct hpi_control_cache_single *pC;
struct hpi_control_cache_info *pI;
- if (phr->error)
- return;
-
if (!find_control(phm->obj_index, p_cache, &pI)) {
HPI_DEBUG_LOG(VERBOSE,
"HPICMN find_control() failed for adap %d\n",
phm->adapter_index);
- return;
+ return 0;
}
- /* pC is the default cached control strucure.
- May be cast to something else in the following switch statement.
- */
- pC = (struct hpi_control_cache_single *)pI;
+ phr->error = 0;
+ phr->specific_error = 0;
+ phr->version = 0;
+
+ return hpi_check_control_cache_single((struct hpi_control_cache_single
+ *)pI, phm, phr);
+}
+
+/** Updates the cache with Set values.
- switch (pI->control_type) {
+Only update if no error.
+Volume and Level return the limited values in the response, so use these
+Multiplexer does so use sent values
+*/
+void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
+ *pC, struct hpi_message *phm, struct hpi_response *phr)
+{
+ switch (pC->u.i.control_type) {
case HPI_CONTROL_VOLUME:
if (phm->u.c.attribute == HPI_VOLUME_GAIN) {
pC->u.vol.an_log[0] = phr->u.c.an_log_value[0];
@@ -625,6 +619,30 @@ void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
}
}
+void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *p_cache,
+ struct hpi_message *phm, struct hpi_response *phr)
+{
+ struct hpi_control_cache_single *pC;
+ struct hpi_control_cache_info *pI;
+
+ if (phr->error)
+ return;
+
+ if (!find_control(phm->obj_index, p_cache, &pI)) {
+ HPI_DEBUG_LOG(VERBOSE,
+ "HPICMN find_control() failed for adap %d\n",
+ phm->adapter_index);
+ return;
+ }
+
+ /* pC is the default cached control strucure.
+ May be cast to something else in the following switch statement.
+ */
+ pC = (struct hpi_control_cache_single *)pI;
+
+ hpi_cmn_control_cache_sync_to_msg_single(pC, phm, phr);
+}
+
/** Allocate control cache.
\return Cache pointer, or NULL if allocation fails.
@@ -637,12 +655,13 @@ struct hpi_control_cache *hpi_alloc_control_cache(const u32 control_count,
if (!p_cache)
return NULL;
- p_cache->p_info = kcalloc(control_count, sizeof(*p_cache->p_info),
- GFP_KERNEL);
+ p_cache->p_info =
+ kcalloc(control_count, sizeof(*p_cache->p_info), GFP_KERNEL);
if (!p_cache->p_info) {
kfree(p_cache);
return NULL;
}
+
p_cache->cache_size_in_bytes = size_in_bytes;
p_cache->control_count = control_count;
p_cache->p_cache = p_dsp_control_buffer;
diff --git a/sound/pci/asihpi/hpicmn.h b/sound/pci/asihpi/hpicmn.h
index e441212..46629c2 100644
--- a/sound/pci/asihpi/hpicmn.h
+++ b/sound/pci/asihpi/hpicmn.h
@@ -1,7 +1,7 @@
/**
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -21,7 +21,11 @@
struct hpi_adapter_obj;
/* a function that takes an adapter obj and returns an int */
-typedef int adapter_int_func(struct hpi_adapter_obj *pao);
+typedef int adapter_int_func(struct hpi_adapter_obj *pao, u32 message);
+
+#define HPI_IRQ_NONE (0)
+#define HPI_IRQ_MESSAGE (1)
+#define HPI_IRQ_MIXER (2)
struct hpi_adapter_obj {
struct hpi_pci pci; /* PCI info - bus#,dev#,address etc */
@@ -33,6 +37,9 @@ struct hpi_adapter_obj {
u16 dsp_crashed;
u16 has_control_cache;
void *priv;
+ adapter_int_func *irq_query_and_clear;
+ struct hpi_hostbuffer_status *instream_host_buffer_status;
+ struct hpi_hostbuffer_status *outstream_host_buffer_status;
};
struct hpi_control_cache {
@@ -55,13 +62,21 @@ void hpi_delete_adapter(struct hpi_adapter_obj *pao);
short hpi_check_control_cache(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
+
+short hpi_check_control_cache_single(struct hpi_control_cache_single *pC,
+ struct hpi_message *phm, struct hpi_response *phr);
+
struct hpi_control_cache *hpi_alloc_control_cache(const u32
number_of_controls, const u32 size_in_bytes, u8 *pDSP_control_buffer);
+
void hpi_free_control_cache(struct hpi_control_cache *p_cache);
void hpi_cmn_control_cache_sync_to_msg(struct hpi_control_cache *pC,
struct hpi_message *phm, struct hpi_response *phr);
+void hpi_cmn_control_cache_sync_to_msg_single(struct hpi_control_cache_single
+ *pC, struct hpi_message *phm, struct hpi_response *phr);
+
u16 hpi_validate_response(struct hpi_message *phm, struct hpi_response *phr);
hpi_handler_func HPI_COMMON;
diff --git a/sound/pci/asihpi/hpimsginit.c b/sound/pci/asihpi/hpimsginit.c
index 032d563..7eb6171 100644
--- a/sound/pci/asihpi/hpimsginit.c
+++ b/sound/pci/asihpi/hpimsginit.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -37,11 +37,15 @@ static u16 gwSSX2_bypass;
static void hpi_init_message(struct hpi_message *phm, u16 object,
u16 function)
{
- memset(phm, 0, sizeof(*phm));
+ u16 size;
+
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
- phm->size = msg_size[object];
+ size = msg_size[object];
else
- phm->size = sizeof(*phm);
+ size = sizeof(*phm);
+
+ memset(phm, 0, size);
+ phm->size = size;
if (gwSSX2_bypass)
phm->type = HPI_TYPE_SSX2BYPASS_MESSAGE;
@@ -60,12 +64,16 @@ static void hpi_init_message(struct hpi_message *phm, u16 object,
void hpi_init_response(struct hpi_response *phr, u16 object, u16 function,
u16 error)
{
- memset(phr, 0, sizeof(*phr));
- phr->type = HPI_TYPE_RESPONSE;
+ u16 size;
+
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX))
- phr->size = res_size[object];
+ size = res_size[object];
else
- phr->size = sizeof(*phr);
+ size = sizeof(*phr);
+
+ memset(phr, 0, sizeof(*phr));
+ phr->size = size;
+ phr->type = HPI_TYPE_RESPONSE;
phr->object = object;
phr->function = function;
phr->error = error;
@@ -86,7 +94,7 @@ void hpi_init_message_response(struct hpi_message *phm,
static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
u16 object, u16 function)
{
- memset(phm, 0, sizeof(*phm));
+ memset(phm, 0, size);
if ((object > 0) && (object <= HPI_OBJ_MAXINDEX)) {
phm->size = size;
phm->type = HPI_TYPE_REQUEST;
@@ -100,7 +108,9 @@ static void hpi_init_messageV1(struct hpi_message_header *phm, u16 size,
void hpi_init_responseV1(struct hpi_response_header *phr, u16 size,
u16 object, u16 function)
{
- memset(phr, 0, sizeof(*phr));
+ (void)object;
+ (void)function;
+ memset(phr, 0, size);
phr->size = size;
phr->version = 1;
phr->type = HPI_TYPE_RESPONSE;
diff --git a/sound/pci/asihpi/hpimsgx.c b/sound/pci/asihpi/hpimsgx.c
index d4790dd..736f453 100644
--- a/sound/pci/asihpi/hpimsgx.c
+++ b/sound/pci/asihpi/hpimsgx.c
@@ -1,7 +1,7 @@
/******************************************************************************
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -35,6 +35,7 @@ static struct pci_device_id asihpi_pci_tbl[] = {
static struct hpios_spinlock msgx_lock;
static hpi_handler_func *hpi_entry_points[HPI_MAX_ADAPTERS];
+static int logging_enabled = 1;
static hpi_handler_func *hpi_lookup_entry_point_function(const struct hpi_pci
*pci_info)
@@ -312,7 +313,9 @@ static void instream_message(struct hpi_message *phm,
void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
void *h_owner)
{
- HPI_DEBUG_MESSAGE(DEBUG, phm);
+
+ if (logging_enabled)
+ HPI_DEBUG_MESSAGE(DEBUG, phm);
if (phm->type != HPI_TYPE_REQUEST) {
hpi_init_response(phr, phm->object, phm->function,
@@ -352,8 +355,14 @@ void hpi_send_recv_ex(struct hpi_message *phm, struct hpi_response *phr,
hw_entry_point(phm, phr);
break;
}
- HPI_DEBUG_RESPONSE(phr);
+ if (logging_enabled)
+ HPI_DEBUG_RESPONSE(phr);
+
+ if (phr->error >= HPI_ERROR_DSP_COMMUNICATION) {
+ hpi_debug_level_set(HPI_DEBUG_LEVEL_ERROR);
+ logging_enabled = 0;
+ }
}
static void adapter_open(struct hpi_message *phm, struct hpi_response *phr)
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c
index 7f02720..6aa677e 100644
--- a/sound/pci/asihpi/hpioctl.c
+++ b/sound/pci/asihpi/hpioctl.c
@@ -1,7 +1,8 @@
/*******************************************************************************
-
AudioScience HPI driver
- Copyright (C) 1997-2011 AudioScience Inc. <support@audioscience.com>
+ Common Linux HPI ioctl and module probe/remove functions
+
+ Copyright (C) 1997-2014 AudioScience Inc. <support@audioscience.com>
This program is free software; you can redistribute it and/or modify
it under the terms of version 2 of the GNU General Public License as
@@ -12,11 +13,6 @@
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
-
-Common Linux HPI ioctl and module probe/remove functions
*******************************************************************************/
#define SOURCEFILE_NAME "hpioctl.c"
@@ -29,6 +25,7 @@ Common Linux HPI ioctl and module probe/remove functions
#include "hpicmn.h"
#include <linux/fs.h>
+#include <linux/interrupt.h>
#include <linux/slab.h>
#include <linux/moduleparam.h>
#include <asm/uaccess.h>
@@ -307,10 +304,38 @@ out:
return err;
}
+static int asihpi_irq_count;
+
+static irqreturn_t asihpi_isr(int irq, void *dev_id)
+{
+ struct hpi_adapter *a = dev_id;
+ int handled;
+
+ if (!a->adapter->irq_query_and_clear) {
+ pr_err("asihpi_isr ASI%04X:%d no handler\n", a->adapter->type,
+ a->adapter->index);
+ return IRQ_NONE;
+ }
+
+ handled = a->adapter->irq_query_and_clear(a->adapter, 0);
+
+ if (!handled)
+ return IRQ_NONE;
+
+ asihpi_irq_count++;
+ /* printk(KERN_INFO "asihpi_isr %d ASI%04X:%d irq handled\n",
+ asihpi_irq_count, a->adapter->type, a->adapter->index); */
+
+ if (a->interrupt_callback)
+ a->interrupt_callback(a);
+
+ return IRQ_HANDLED;
+}
+
int asihpi_adapter_probe(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
- int idx, nm;
+ int idx, nm, low_latency_mode = 0, irq_supported = 0;
int adapter_index;
unsigned int memlen;
struct hpi_message hm;
@@ -388,8 +413,38 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
hm.adapter_index = adapter.adapter->index;
hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
- if (hr.error)
+ if (hr.error) {
+ HPI_DEBUG_LOG(ERROR, "HPI_ADAPTER_OPEN failed, aborting\n");
goto err;
+ }
+
+ /* Check if current mode == Low Latency mode */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_GET_MODE);
+ hm.adapter_index = adapter.adapter->index;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+
+ if (!hr.error
+ && hr.u.ax.mode.adapter_mode == HPI_ADAPTER_MODE_LOW_LATENCY)
+ low_latency_mode = 1;
+ else
+ dev_info(&pci_dev->dev,
+ "Adapter at index %d is not in low latency mode\n",
+ adapter.adapter->index);
+
+ /* Check if IRQs are supported */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_GET_PROPERTY);
+ hm.adapter_index = adapter.adapter->index;
+ hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_SUPPORTS_IRQ;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+ if (hr.error || !hr.u.ax.property_get.parameter1) {
+ dev_info(&pci_dev->dev,
+ "IRQs not supported by adapter at index %d\n",
+ adapter.adapter->index);
+ } else {
+ irq_supported = 1;
+ }
/* WARNING can't init mutex in 'adapter'
* and then copy it to adapters[] ?!?!
@@ -398,6 +453,44 @@ int asihpi_adapter_probe(struct pci_dev *pci_dev,
mutex_init(&adapters[adapter_index].mutex);
pci_set_drvdata(pci_dev, &adapters[adapter_index]);
+ if (low_latency_mode && irq_supported) {
+ if (!adapter.adapter->irq_query_and_clear) {
+ dev_err(&pci_dev->dev,
+ "no IRQ handler for adapter %d, aborting\n",
+ adapter.adapter->index);
+ goto err;
+ }
+
+ /* Disable IRQ generation on DSP side by setting the rate to 0 */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_SET_PROPERTY);
+ hm.adapter_index = adapter.adapter->index;
+ hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE;
+ hm.u.ax.property_set.parameter1 = 0;
+ hm.u.ax.property_set.parameter2 = 0;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+ if (hr.error) {
+ HPI_DEBUG_LOG(ERROR,
+ "HPI_ADAPTER_GET_MODE failed, aborting\n");
+ goto err;
+ }
+
+ /* Note: request_irq calls asihpi_isr here */
+ if (request_irq(pci_dev->irq, asihpi_isr, IRQF_SHARED,
+ "asihpi", &adapters[adapter_index])) {
+ dev_err(&pci_dev->dev, "request_irq(%d) failed\n",
+ pci_dev->irq);
+ goto err;
+ }
+
+ adapters[adapter_index].interrupt_mode = 1;
+
+ dev_info(&pci_dev->dev, "using irq %d\n", pci_dev->irq);
+ adapters[adapter_index].irq = pci_dev->irq;
+ } else {
+ dev_info(&pci_dev->dev, "using polled mode\n");
+ }
+
dev_info(&pci_dev->dev, "probe succeeded for ASI%04X HPI index %d\n",
adapter.adapter->type, adapter_index);
@@ -431,6 +524,15 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
pa = pci_get_drvdata(pci_dev);
pci = pa->adapter->pci;
+ /* Disable IRQ generation on DSP side */
+ hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
+ HPI_ADAPTER_SET_PROPERTY);
+ hm.adapter_index = pa->adapter->index;
+ hm.u.ax.property_set.property = HPI_ADAPTER_PROPERTY_IRQ_RATE;
+ hm.u.ax.property_set.parameter1 = 0;
+ hm.u.ax.property_set.parameter2 = 0;
+ hpi_send_recv_ex(&hm, &hr, HOWNER_KERNEL);
+
hpi_init_message_response(&hm, &hr, HPI_OBJ_ADAPTER,
HPI_ADAPTER_DELETE);
hm.adapter_index = pa->adapter->index;
@@ -442,8 +544,10 @@ void asihpi_adapter_remove(struct pci_dev *pci_dev)
iounmap(pci.ap_mem_base[idx]);
}
- if (pa->p_buffer)
- vfree(pa->p_buffer);
+ if (pa->irq)
+ free_irq(pa->irq, pa);
+
+ vfree(pa->p_buffer);
if (1)
dev_info(&pci_dev->dev,
diff --git a/sound/pci/asihpi/hpios.h b/sound/pci/asihpi/hpios.h
index d3fbd0d..4e38360 100644
--- a/sound/pci/asihpi/hpios.h
+++ b/sound/pci/asihpi/hpios.h
@@ -41,10 +41,6 @@ HPI Operating System Specific macros for Linux Kernel driver
#define HPI_NO_OS_FILE_OPS
-#ifdef CONFIG_64BIT
-#define HPI64BIT
-#endif
-
/** Details of a memory area allocated with pci_alloc_consistent
Need all info for parameters to pci_free_consistent
*/
@@ -155,6 +151,10 @@ struct hpi_adapter {
struct hpi_adapter_obj *adapter;
struct snd_card *snd_card;
+ int irq;
+ int interrupt_mode;
+ void (*interrupt_callback) (struct hpi_adapter *);
+
/* mutex prevents contention for one card
between multiple user programs (via ioctl) */
struct mutex mutex;
diff --git a/sound/pci/atiixp.c b/sound/pci/atiixp.c
index 7895c5d..9c1c445 100644
--- a/sound/pci/atiixp.c
+++ b/sound/pci/atiixp.c
@@ -688,9 +688,7 @@ static void snd_atiixp_xrun_dma(struct atiixp *chip, struct atiixp_dma *dma)
if (! dma->substream || ! dma->running)
return;
dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
- snd_pcm_stream_lock(dma->substream);
- snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(dma->substream);
+ snd_pcm_stop_xrun(dma->substream);
}
/*
diff --git a/sound/pci/atiixp_modem.c b/sound/pci/atiixp_modem.c
index 3c32413..b2f63e0 100644
--- a/sound/pci/atiixp_modem.c
+++ b/sound/pci/atiixp_modem.c
@@ -638,9 +638,7 @@ static void snd_atiixp_xrun_dma(struct atiixp_modem *chip,
if (! dma->substream || ! dma->running)
return;
dev_dbg(chip->card->dev, "XRUN detected (DMA %d)\n", dma->ops->type);
- snd_pcm_stream_lock(dma->substream);
- snd_pcm_stop(dma->substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(dma->substream);
+ snd_pcm_stop_xrun(dma->substream);
}
/*
diff --git a/sound/pci/au88x0/au88x0.c b/sound/pci/au88x0/au88x0.c
index 21ce31f..9963691 100644
--- a/sound/pci/au88x0/au88x0.c
+++ b/sound/pci/au88x0/au88x0.c
@@ -48,11 +48,10 @@ static void vortex_fix_latency(struct pci_dev *vortex)
{
int rc;
if (!(rc = pci_write_config_byte(vortex, 0x40, 0xff))) {
- pr_info( CARD_NAME
- ": vortex latency is 0xff\n");
+ dev_info(&vortex->dev, "vortex latency is 0xff\n");
} else {
- pr_warn( CARD_NAME
- ": could not set vortex latency: pci error 0x%x\n", rc);
+ dev_warn(&vortex->dev,
+ "could not set vortex latency: pci error 0x%x\n", rc);
}
}
@@ -70,11 +69,10 @@ static void vortex_fix_agp_bridge(struct pci_dev *via)
if (!(rc = pci_read_config_byte(via, 0x42, &value))
&& ((value & 0x10)
|| !(rc = pci_write_config_byte(via, 0x42, value | 0x10)))) {
- pr_info( CARD_NAME
- ": bridge config is 0x%x\n", value | 0x10);
+ dev_info(&via->dev, "bridge config is 0x%x\n", value | 0x10);
} else {
- pr_warn( CARD_NAME
- ": could not set vortex latency: pci error 0x%x\n", rc);
+ dev_warn(&via->dev,
+ "could not set vortex latency: pci error 0x%x\n", rc);
}
}
@@ -97,7 +95,8 @@ static void snd_vortex_workaround(struct pci_dev *vortex, int fix)
PCI_DEVICE_ID_AMD_FE_GATE_7007, NULL);
}
if (via) {
- pr_info( CARD_NAME ": Activating latency workaround...\n");
+ dev_info(&vortex->dev,
+ "Activating latency workaround...\n");
vortex_fix_latency(vortex);
vortex_fix_agp_bridge(via);
}
@@ -153,7 +152,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
return err;
if (pci_set_dma_mask(pci, DMA_BIT_MASK(32)) < 0 ||
pci_set_consistent_dma_mask(pci, DMA_BIT_MASK(32)) < 0) {
- pr_err( "error to set DMA mask\n");
+ dev_err(card->dev, "error to set DMA mask\n");
pci_disable_device(pci);
return -ENXIO;
}
@@ -182,7 +181,7 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
chip->mmio = pci_ioremap_bar(pci, 0);
if (!chip->mmio) {
- pr_err( "MMIO area remap failed.\n");
+ dev_err(card->dev, "MMIO area remap failed.\n");
err = -ENOMEM;
goto ioremap_out;
}
@@ -191,14 +190,14 @@ snd_vortex_create(struct snd_card *card, struct pci_dev *pci, vortex_t ** rchip)
* This must be done before we do request_irq otherwise we can get spurious
* interrupts that we do not handle properly and make a mess of things */
if ((err = vortex_core_init(chip)) != 0) {
- pr_err( "hw core init failed\n");
+ dev_err(card->dev, "hw core init failed\n");
goto core_out;
}
if ((err = request_irq(pci->irq, vortex_interrupt,
IRQF_SHARED, KBUILD_MODNAME,
chip)) != 0) {
- pr_err( "cannot grab irq\n");
+ dev_err(card->dev, "cannot grab irq\n");
goto irq_out;
}
chip->irq = pci->irq;
@@ -315,7 +314,7 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
if (snd_seq_device_new(card, 1, SNDRV_SEQ_DEV_ID_VORTEX_SYNTH,
sizeof(snd_vortex_synth_arg_t), &wave) < 0
|| wave == NULL) {
- snd_printk(KERN_ERR "Can't initialize Aureal wavetable synth\n");
+ dev_err(card->dev, "Can't initialize Aureal wavetable synth\n");
} else {
snd_vortex_synth_arg_t *arg;
@@ -342,11 +341,11 @@ snd_vortex_probe(struct pci_dev *pci, const struct pci_device_id *pci_id)
chip->rev = pci->revision;
#ifdef CHIP_AU8830
if ((chip->rev) != 0xfe && (chip->rev) != 0xfa) {
- pr_alert(
- "vortex: The revision (%x) of your card has not been seen before.\n",
+ dev_alert(card->dev,
+ "The revision (%x) of your card has not been seen before.\n",
chip->rev);
- pr_alert(
- "vortex: Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
+ dev_alert(card->dev,
+ "Please email the results of 'lspci -vv' to openvortex-dev@nongnu.org.\n");
snd_card_free(card);
err = -ENODEV;
return err;
diff --git a/sound/pci/au88x0/au88x0.h b/sound/pci/au88x0/au88x0.h
index 466a5c8..3a8fefe 100644
--- a/sound/pci/au88x0/au88x0.h
+++ b/sound/pci/au88x0/au88x0.h
@@ -243,7 +243,7 @@ static int vortex_core_init(vortex_t * card);
static int vortex_core_shutdown(vortex_t * card);
static void vortex_enable_int(vortex_t * card);
static irqreturn_t vortex_interrupt(int irq, void *dev_id);
-static int vortex_alsafmt_aspfmt(int alsafmt);
+static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v);
/* Connection stuff. */
static void vortex_connect_default(vortex_t * vortex, int en);
@@ -278,7 +278,7 @@ static void vortex_mix_setvolumebyte(vortex_t * vortex, unsigned char mix,
static void vortex_Vort3D_enable(vortex_t * v);
static void vortex_Vort3D_disable(vortex_t * v);
static void vortex_Vort3D_connect(vortex_t * vortex, int en);
-static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en);
+static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v);
#endif
/* Driver stuff. */
diff --git a/sound/pci/au88x0/au88x0_a3d.c b/sound/pci/au88x0/au88x0_a3d.c
index 30f760e..ab0f8731 100644
--- a/sound/pci/au88x0/au88x0_a3d.c
+++ b/sound/pci/au88x0/au88x0_a3d.c
@@ -484,12 +484,13 @@ static void a3dsrc_ZeroState(a3dsrc_t * a)
}
/* Reset entire A3D engine */
-static void a3dsrc_ZeroStateA3D(a3dsrc_t * a)
+static void a3dsrc_ZeroStateA3D(a3dsrc_t *a, vortex_t *v)
{
int i, var, var2;
if ((a->vortex) == NULL) {
- pr_err( "vortex: ZeroStateA3D: ERROR: a->vortex is NULL\n");
+ dev_err(v->card->dev,
+ "ZeroStateA3D: ERROR: a->vortex is NULL\n");
return;
}
@@ -601,7 +602,7 @@ static void vortex_Vort3D_enable(vortex_t *v)
Vort3DRend_Initialize(v, XT_HEADPHONE);
for (i = 0; i < NR_A3D; i++) {
vortex_A3dSourceHw_Initialize(v, i % 4, i >> 2);
- a3dsrc_ZeroStateA3D(&(v->a3d[0]));
+ a3dsrc_ZeroStateA3D(&v->a3d[0], v);
}
/* Register ALSA controls */
vortex_a3d_register_controls(v);
@@ -628,15 +629,15 @@ static void vortex_Vort3D_connect(vortex_t * v, int en)
v->mixxtlk[0] =
vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
if (v->mixxtlk[0] < 0) {
- pr_warn
- ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+ dev_warn(v->card->dev,
+ "vortex_Vort3D: ERROR: not enough free mixer resources.\n");
return;
}
v->mixxtlk[1] =
vortex_adb_checkinout(v, v->fixed_res, en, VORTEX_RESOURCE_MIXIN);
if (v->mixxtlk[1] < 0) {
- pr_warn
- ("vortex: vortex_Vort3D: ERROR: not enough free mixer resources.\n");
+ dev_warn(v->card->dev,
+ "vortex_Vort3D: ERROR: not enough free mixer resources.\n");
return;
}
#endif
@@ -676,11 +677,11 @@ static void vortex_Vort3D_connect(vortex_t * v, int en)
}
/* Initialize one single A3D source. */
-static void vortex_Vort3D_InitializeSource(a3dsrc_t * a, int en)
+static void vortex_Vort3D_InitializeSource(a3dsrc_t *a, int en, vortex_t *v)
{
if (a->vortex == NULL) {
- pr_warn
- ("vortex: Vort3D_InitializeSource: A3D source not initialized\n");
+ dev_warn(v->card->dev,
+ "Vort3D_InitializeSource: A3D source not initialized\n");
return;
}
if (en) {
diff --git a/sound/pci/au88x0/au88x0_core.c b/sound/pci/au88x0/au88x0_core.c
index 72e8128..4667c32 100644
--- a/sound/pci/au88x0/au88x0_core.c
+++ b/sound/pci/au88x0/au88x0_core.c
@@ -285,8 +285,8 @@ vortex_mixer_addWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
temp = hwread(vortex->mmio, prev);
//printk(KERN_INFO "vortex: mixAddWTD: while addr=%x, val=%x\n", prev, temp);
if ((++lifeboat) > 0xf) {
- pr_err(
- "vortex_mixer_addWTD: lifeboat overflow\n");
+ dev_err(vortex->card->dev,
+ "vortex_mixer_addWTD: lifeboat overflow\n");
return 0;
}
}
@@ -303,7 +303,7 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
eax = hwread(vortex->mmio, VORTEX_MIXER_SR);
if (((1 << ch) & eax) == 0) {
- pr_err( "mix ALARM %x\n", eax);
+ dev_err(vortex->card->dev, "mix ALARM %x\n", eax);
return 0;
}
ebp = VORTEX_MIXER_CHNBASE + (ch << 2);
@@ -324,8 +324,8 @@ vortex_mixer_delWTD(vortex_t * vortex, unsigned char mix, unsigned char ch)
//printk(KERN_INFO "vortex: mixdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
while ((edx & 0xf) != mix) {
if ((esi) > 0xf) {
- pr_err(
- "vortex: mixdelWTD: error lifeboat overflow\n");
+ dev_err(vortex->card->dev,
+ "mixdelWTD: error lifeboat overflow\n");
return 0;
}
esp14 = ebx;
@@ -492,7 +492,7 @@ vortex_src_persist_convratio(vortex_t * vortex, unsigned char src, int ratio)
hwwrite(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2), ratio);
temp = hwread(vortex->mmio, VORTEX_SRC_CONVRATIO + (src << 2));
if ((++lifeboat) > 0x9) {
- pr_err( "Vortex: Src cvr fail\n");
+ dev_err(vortex->card->dev, "Src cvr fail\n");
break;
}
}
@@ -684,8 +684,8 @@ vortex_src_addWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
temp = hwread(vortex->mmio, prev);
//printk(KERN_INFO "vortex: srcAddWTD: while addr=%x, val=%x\n", prev, temp);
if ((++lifeboat) > 0xf) {
- pr_err(
- "vortex_src_addWTD: lifeboat overflow\n");
+ dev_err(vortex->card->dev,
+ "vortex_src_addWTD: lifeboat overflow\n");
return 0;
}
}
@@ -703,7 +703,7 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
eax = hwread(vortex->mmio, VORTEX_SRCBLOCK_SR);
if (((1 << ch) & eax) == 0) {
- pr_err( "src alarm\n");
+ dev_err(vortex->card->dev, "src alarm\n");
return 0;
}
ebp = VORTEX_SRC_CHNBASE + (ch << 2);
@@ -724,8 +724,8 @@ vortex_src_delWTD(vortex_t * vortex, unsigned char src, unsigned char ch)
//printk(KERN_INFO "vortex: srcdelWTD: 1 addr=%x, val=%x, src=%x\n", ebx, edx, src);
while ((edx & 0xf) != src) {
if ((esi) > 0xf) {
- pr_warn
- ("vortex: srcdelWTD: error, lifeboat overflow\n");
+ dev_warn(vortex->card->dev,
+ "srcdelWTD: error, lifeboat overflow\n");
return 0;
}
esp14 = ebx;
@@ -819,8 +819,8 @@ vortex_fifo_setadbctrl(vortex_t * vortex, int fifo, int stereo, int priority,
do {
temp = hwread(vortex->mmio, VORTEX_FIFO_ADBCTRL + (fifo << 2));
if (lifeboat++ > 0xbb8) {
- pr_err(
- "Vortex: vortex_fifo_setadbctrl fail\n");
+ dev_err(vortex->card->dev,
+ "vortex_fifo_setadbctrl fail\n");
break;
}
}
@@ -915,7 +915,8 @@ vortex_fifo_setwtctrl(vortex_t * vortex, int fifo, int ctrl, int priority,
do {
temp = hwread(vortex->mmio, VORTEX_FIFO_WTCTRL + (fifo << 2));
if (lifeboat++ > 0xbb8) {
- pr_err( "Vortex: vortex_fifo_setwtctrl fail\n");
+ dev_err(vortex->card->dev,
+ "vortex_fifo_setwtctrl fail\n");
break;
}
}
@@ -1042,7 +1043,7 @@ static void vortex_fifo_init(vortex_t * vortex)
for (x = NR_ADB - 1; x >= 0; x--) {
hwwrite(vortex->mmio, addr, (FIFO_U0 | FIFO_U1));
if (hwread(vortex->mmio, addr) != (FIFO_U0 | FIFO_U1))
- pr_err( "bad adb fifo reset!");
+ dev_err(vortex->card->dev, "bad adb fifo reset!");
vortex_fifo_clearadbdata(vortex, x, FIFO_SIZE);
addr -= 4;
}
@@ -1053,9 +1054,9 @@ static void vortex_fifo_init(vortex_t * vortex)
for (x = NR_WT - 1; x >= 0; x--) {
hwwrite(vortex->mmio, addr, FIFO_U0);
if (hwread(vortex->mmio, addr) != FIFO_U0)
- pr_err(
- "bad wt fifo reset (0x%08x, 0x%08x)!\n",
- addr, hwread(vortex->mmio, addr));
+ dev_err(vortex->card->dev,
+ "bad wt fifo reset (0x%08x, 0x%08x)!\n",
+ addr, hwread(vortex->mmio, addr));
vortex_fifo_clearwtdata(vortex, x, FIFO_SIZE);
addr -= 4;
}
@@ -1213,8 +1214,9 @@ static int vortex_adbdma_bufshift(vortex_t * vortex, int adbdma)
if (dma->period_virt >= dma->nr_periods)
dma->period_virt -= dma->nr_periods;
if (delta != 1)
- pr_info( "vortex: %d virt=%d, real=%d, delta=%d\n",
- adbdma, dma->period_virt, dma->period_real, delta);
+ dev_info(vortex->card->dev,
+ "%d virt=%d, real=%d, delta=%d\n",
+ adbdma, dma->period_virt, dma->period_real, delta);
return delta;
}
@@ -1482,8 +1484,8 @@ static int vortex_wtdma_bufshift(vortex_t * vortex, int wtdma)
dma->period_real = page;
if (delta != 1)
- pr_warn( "vortex: wt virt = %d, delta = %d\n",
- dma->period_virt, delta);
+ dev_warn(vortex->card->dev, "wt virt = %d, delta = %d\n",
+ dma->period_virt, delta);
return delta;
}
@@ -1667,9 +1669,9 @@ vortex_adb_addroutes(vortex_t * vortex, unsigned char channel,
hwread(vortex->mmio,
VORTEX_ADB_RTBASE + (temp << 2)) & ADB_MASK;
if ((lifeboat++) > ADB_MASK) {
- pr_err(
- "vortex_adb_addroutes: unending route! 0x%x\n",
- *route);
+ dev_err(vortex->card->dev,
+ "vortex_adb_addroutes: unending route! 0x%x\n",
+ *route);
return;
}
}
@@ -1703,9 +1705,9 @@ vortex_adb_delroutes(vortex_t * vortex, unsigned char channel,
hwread(vortex->mmio,
VORTEX_ADB_RTBASE + (prev << 2)) & ADB_MASK;
if (((lifeboat++) > ADB_MASK) || (temp == ADB_MASK)) {
- pr_err(
- "vortex_adb_delroutes: route not found! 0x%x\n",
- route0);
+ dev_err(vortex->card->dev,
+ "vortex_adb_delroutes: route not found! 0x%x\n",
+ route0);
return;
}
}
@@ -2045,7 +2047,9 @@ vortex_adb_checkinout(vortex_t * vortex, int resmap[], int out, int restype)
}
}
}
- pr_err( "vortex: FATAL: ResManager: resource type %d exhausted.\n", restype);
+ dev_err(vortex->card->dev,
+ "FATAL: ResManager: resource type %d exhausted.\n",
+ restype);
return -ENOMEM;
}
@@ -2173,11 +2177,13 @@ vortex_adb_allocroute(vortex_t *vortex, int dma, int nr_ch, int dir,
memset(stream->resources, 0,
sizeof(unsigned char) *
VORTEX_RESOURCE_LAST);
- pr_err( "vortex: out of A3D sources. Sorry\n");
+ dev_err(vortex->card->dev,
+ "out of A3D sources. Sorry\n");
return -EBUSY;
}
/* (De)Initialize A3D hardware source. */
- vortex_Vort3D_InitializeSource(&(vortex->a3d[a3d]), en);
+ vortex_Vort3D_InitializeSource(&vortex->a3d[a3d], en,
+ vortex);
}
/* Make SPDIF out exclusive to "spdif" device when in use. */
if ((stream->type == VORTEX_PCM_SPDIF) && (en)) {
@@ -2421,7 +2427,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
hwread(vortex->mmio, VORTEX_IRQ_SOURCE);
// Is at least one IRQ flag set?
if (source == 0) {
- pr_err( "vortex: missing irq source\n");
+ dev_err(vortex->card->dev, "missing irq source\n");
return IRQ_NONE;
}
@@ -2429,19 +2435,19 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
// Attend every interrupt source.
if (unlikely(source & IRQ_ERR_MASK)) {
if (source & IRQ_FATAL) {
- pr_err( "vortex: IRQ fatal error\n");
+ dev_err(vortex->card->dev, "IRQ fatal error\n");
}
if (source & IRQ_PARITY) {
- pr_err( "vortex: IRQ parity error\n");
+ dev_err(vortex->card->dev, "IRQ parity error\n");
}
if (source & IRQ_REG) {
- pr_err( "vortex: IRQ reg error\n");
+ dev_err(vortex->card->dev, "IRQ reg error\n");
}
if (source & IRQ_FIFO) {
- pr_err( "vortex: IRQ fifo error\n");
+ dev_err(vortex->card->dev, "IRQ fifo error\n");
}
if (source & IRQ_DMA) {
- pr_err( "vortex: IRQ dma error\n");
+ dev_err(vortex->card->dev, "IRQ dma error\n");
}
handled = 1;
}
@@ -2489,7 +2495,7 @@ static irqreturn_t vortex_interrupt(int irq, void *dev_id)
}
if (!handled) {
- pr_err( "vortex: unknown irq source %x\n", source);
+ dev_err(vortex->card->dev, "unknown irq source %x\n", source);
}
return IRQ_RETVAL(handled);
}
@@ -2546,7 +2552,7 @@ vortex_codec_write(struct snd_ac97 * codec, unsigned short addr, unsigned short
while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
udelay(100);
if (lifeboat++ > POLL_COUNT) {
- pr_err( "vortex: ac97 codec stuck busy\n");
+ dev_err(card->card->dev, "ac97 codec stuck busy\n");
return;
}
}
@@ -2572,7 +2578,7 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short
while (!(hwread(card->mmio, VORTEX_CODEC_CTRL) & 0x100)) {
udelay(100);
if (lifeboat++ > POLL_COUNT) {
- pr_err( "vortex: ac97 codec stuck busy\n");
+ dev_err(card->card->dev, "ac97 codec stuck busy\n");
return 0xffff;
}
}
@@ -2586,7 +2592,8 @@ static unsigned short vortex_codec_read(struct snd_ac97 * codec, unsigned short
udelay(100);
data = hwread(card->mmio, VORTEX_CODEC_IO);
if (lifeboat++ > POLL_COUNT) {
- pr_err( "vortex: ac97 address never arrived\n");
+ dev_err(card->card->dev,
+ "ac97 address never arrived\n");
return 0xffff;
}
} while ((data & VORTEX_CODEC_ADDMASK) !=
@@ -2683,7 +2690,7 @@ static void vortex_spdif_init(vortex_t * vortex, int spdif_sr, int spdif_mode)
static int vortex_core_init(vortex_t *vortex)
{
- pr_info( "Vortex: init.... ");
+ dev_info(vortex->card->dev, "init started\n");
/* Hardware Init. */
hwwrite(vortex->mmio, VORTEX_CTRL, 0xffffffff);
msleep(5);
@@ -2728,7 +2735,7 @@ static int vortex_core_init(vortex_t *vortex)
//vortex_enable_timer_int(vortex);
//vortex_disable_timer_int(vortex);
- pr_info( "done.\n");
+ dev_info(vortex->card->dev, "init.... done.\n");
spin_lock_init(&vortex->lock);
return 0;
@@ -2737,7 +2744,7 @@ static int vortex_core_init(vortex_t *vortex)
static int vortex_core_shutdown(vortex_t * vortex)
{
- pr_info( "Vortex: shutdown...");
+ dev_info(vortex->card->dev, "shutdown started\n");
#ifndef CHIP_AU8820
vortex_eq_free(vortex);
vortex_Vort3D_disable(vortex);
@@ -2759,13 +2766,13 @@ static int vortex_core_shutdown(vortex_t * vortex)
msleep(5);
hwwrite(vortex->mmio, VORTEX_IRQ_SOURCE, 0xffff);
- pr_info( "done.\n");
+ dev_info(vortex->card->dev, "shutdown.... done.\n");
return 0;
}
/* Alsa support. */
-static int vortex_alsafmt_aspfmt(int alsafmt)
+static int vortex_alsafmt_aspfmt(int alsafmt, vortex_t *v)
{
int fmt;
@@ -2793,7 +2800,8 @@ static int vortex_alsafmt_aspfmt(int alsafmt)
break;
default:
fmt = 0x8;
- pr_err( "vortex: format unsupported %d\n", alsafmt);
+ dev_err(v->card->dev,
+ "format unsupported %d\n", alsafmt);
break;
}
return fmt;
diff --git a/sound/pci/au88x0/au88x0_eq.c b/sound/pci/au88x0/au88x0_eq.c
index 9404ba7..9585c5c 100644
--- a/sound/pci/au88x0/au88x0_eq.c
+++ b/sound/pci/au88x0/au88x0_eq.c
@@ -845,7 +845,8 @@ snd_vortex_peaks_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *u
vortex_Eqlzr_GetAllPeaks(vortex, peaks, &count);
if (count != 20) {
- pr_err( "vortex: peak count error 20 != %d \n", count);
+ dev_err(vortex->card->dev,
+ "peak count error 20 != %d\n", count);
return -1;
}
for (i = 0; i < 20; i++)
diff --git a/sound/pci/au88x0/au88x0_game.c b/sound/pci/au88x0/au88x0_game.c
index 72daf6c..151815b 100644
--- a/sound/pci/au88x0/au88x0_game.c
+++ b/sound/pci/au88x0/au88x0_game.c
@@ -98,7 +98,8 @@ static int vortex_gameport_register(vortex_t *vortex)
vortex->gameport = gp = gameport_allocate_port();
if (!gp) {
- pr_err( "vortex: cannot allocate memory for gameport\n");
+ dev_err(vortex->card->dev,
+ "cannot allocate memory for gameport\n");
return -ENOMEM;
}
diff --git a/sound/pci/au88x0/au88x0_mpu401.c b/sound/pci/au88x0/au88x0_mpu401.c
index 328c194..1025e55 100644
--- a/sound/pci/au88x0/au88x0_mpu401.c
+++ b/sound/pci/au88x0/au88x0_mpu401.c
@@ -73,7 +73,7 @@ static int snd_vortex_midi(vortex_t *vortex)
/* Check if anything is OK. */
temp = hwread(vortex->mmio, VORTEX_MIDI_DATA);
if (temp != MPU401_ACK /*0xfe */ ) {
- pr_err( "midi port doesn't acknowledge!\n");
+ dev_err(vortex->card->dev, "midi port doesn't acknowledge!\n");
return -ENODEV;
}
/* Enable MPU401 interrupts. */
diff --git a/sound/pci/au88x0/au88x0_pcm.c b/sound/pci/au88x0/au88x0_pcm.c
index 5adc6b9..a6d6d8d 100644
--- a/sound/pci/au88x0/au88x0_pcm.c
+++ b/sound/pci/au88x0/au88x0_pcm.c
@@ -227,7 +227,7 @@ snd_vortex_pcm_hw_params(struct snd_pcm_substream *substream,
err =
snd_pcm_lib_malloc_pages(substream, params_buffer_bytes(hw_params));
if (err < 0) {
- pr_err( "Vortex: pcm page alloc failed!\n");
+ dev_err(chip->card->dev, "Vortex: pcm page alloc failed!\n");
return err;
}
/*
@@ -332,7 +332,7 @@ static int snd_vortex_pcm_prepare(struct snd_pcm_substream *substream)
dir = 1;
else
dir = 0;
- fmt = vortex_alsafmt_aspfmt(runtime->format);
+ fmt = vortex_alsafmt_aspfmt(runtime->format, chip);
spin_lock_irq(&chip->lock);
if (VORTEX_PCM_TYPE(substream->pcm) != VORTEX_PCM_WT) {
vortex_adbdma_setmode(chip, dma, 1, dir, fmt,
@@ -371,7 +371,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
}
#ifndef CHIP_AU8810
else {
- pr_info( "vortex: wt start %d\n", dma);
+ dev_info(chip->card->dev, "wt start %d\n", dma);
vortex_wtdma_startfifo(chip, dma);
}
#endif
@@ -384,7 +384,7 @@ static int snd_vortex_pcm_trigger(struct snd_pcm_substream *substream, int cmd)
vortex_adbdma_stopfifo(chip, dma);
#ifndef CHIP_AU8810
else {
- pr_info( "vortex: wt stop %d\n", dma);
+ dev_info(chip->card->dev, "wt stop %d\n", dma);
vortex_wtdma_stopfifo(chip, dma);
}
#endif
diff --git a/sound/pci/au88x0/au88x0_synth.c b/sound/pci/au88x0/au88x0_synth.c
index f094bac..78e12f4 100644
--- a/sound/pci/au88x0/au88x0_synth.c
+++ b/sound/pci/au88x0/au88x0_synth.c
@@ -90,7 +90,7 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0);
temp = hwread(vortex->mmio, WT_PARM(wt, 3));
- pr_debug( "vortex: WT PARM3: %x\n", temp);
+ dev_dbg(vortex->card->dev, "WT PARM3: %x\n", temp);
//hwwrite(vortex->mmio, WT_PARM(wt, 3), temp);
hwwrite(vortex->mmio, WT_DELAY(wt, 0), 0);
@@ -98,7 +98,8 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
hwwrite(vortex->mmio, WT_DELAY(wt, 2), 0);
hwwrite(vortex->mmio, WT_DELAY(wt, 3), 0);
- pr_debug( "vortex: WT GMODE: %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+ dev_dbg(vortex->card->dev, "WT GMODE: %x\n",
+ hwread(vortex->mmio, WT_GMODE(wt)));
hwwrite(vortex->mmio, WT_PARM(wt, 2), 0xffffffff);
hwwrite(vortex->mmio, WT_PARM(wt, 3), 0xcff1c810);
@@ -106,7 +107,8 @@ static int vortex_wt_allocroute(vortex_t * vortex, int wt, int nr_ch)
voice->parm0 = voice->parm1 = 0xcfb23e2f;
hwwrite(vortex->mmio, WT_PARM(wt, 0), voice->parm0);
hwwrite(vortex->mmio, WT_PARM(wt, 1), voice->parm1);
- pr_debug( "vortex: WT GMODE 2 : %x\n", hwread(vortex->mmio, WT_GMODE(wt)));
+ dev_dbg(vortex->card->dev, "WT GMODE 2 : %x\n",
+ hwread(vortex->mmio, WT_GMODE(wt)));
return 0;
}
@@ -196,14 +198,15 @@ vortex_wt_SetReg(vortex_t * vortex, unsigned char reg, int wt,
if ((reg == 5) || ((reg >= 7) && (reg <= 10)) || (reg == 0xc)) {
if (wt >= (NR_WT / NR_WT_PB)) {
- pr_warn
- ("vortex: WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
- reg, wt);
+ dev_warn(vortex->card->dev,
+ "WT SetReg: bank out of range. reg=0x%x, wt=%d\n",
+ reg, wt);
return 0;
}
} else {
if (wt >= NR_WT) {
- pr_err( "vortex: WT SetReg: voice out of range\n");
+ dev_err(vortex->card->dev,
+ "WT SetReg: voice out of range\n");
return 0;
}
}
diff --git a/sound/pci/aw2/aw2-alsa.c b/sound/pci/aw2/aw2-alsa.c
index 3878cf5..e1cf019 100644
--- a/sound/pci/aw2/aw2-alsa.c
+++ b/sound/pci/aw2/aw2-alsa.c
@@ -725,19 +725,10 @@ static int snd_aw2_new_pcm(struct aw2 *chip)
static int snd_aw2_control_switch_capture_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Analog", "Digital"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items) {
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- }
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_aw2_control_switch_capture_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/azt3328.c b/sound/pci/azt3328.c
index 5a69e26..fdbb9c0 100644
--- a/sound/pci/azt3328.c
+++ b/sound/pci/azt3328.c
@@ -1034,11 +1034,6 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
const char * const *p = NULL;
snd_azf3328_mixer_reg_decode(&reg, kcontrol->private_value);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1;
- uinfo->value.enumerated.items = reg.enum_c;
- if (uinfo->value.enumerated.item > reg.enum_c - 1U)
- uinfo->value.enumerated.item = reg.enum_c - 1U;
if (reg.reg == IDX_MIXER_ADVCTL2) {
switch(reg.lchan_shift) {
case 8: /* modem out sel */
@@ -1051,12 +1046,12 @@ snd_azf3328_info_mixer_enum(struct snd_kcontrol *kcontrol,
p = texts4;
break;
}
- } else
- if (reg.reg == IDX_MIXER_REC_SELECT)
+ } else if (reg.reg == IDX_MIXER_REC_SELECT)
p = texts3;
- strcpy(uinfo->value.enumerated.name, p[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo,
+ (reg.reg == IDX_MIXER_REC_SELECT) ? 2 : 1,
+ reg.enum_c, p);
}
static int
diff --git a/sound/pci/ca0106/ca0106_mixer.c b/sound/pci/ca0106/ca0106_mixer.c
index 27de0de..68c0eb0 100644
--- a/sound/pci/ca0106/ca0106_mixer.c
+++ b/sound/pci/ca0106/ca0106_mixer.c
@@ -185,17 +185,11 @@ static int snd_ca0106_shared_spdif_put(struct snd_kcontrol *kcontrol,
static int snd_ca0106_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[6] = {
+ static const char * const texts[6] = {
"IEC958 out", "i2s mixer out", "IEC958 in", "i2s in", "AC97 in", "SRC out"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 6;
- if (uinfo->value.enumerated.item > 5)
- uinfo->value.enumerated.item = 5;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 6, texts);
}
static int snd_ca0106_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -228,17 +222,11 @@ static int snd_ca0106_capture_source_put(struct snd_kcontrol *kcontrol,
static int snd_ca0106_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[6] = {
+ static const char * const texts[4] = {
"Phone", "Mic", "Line in", "Aux"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_ca0106_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -273,29 +261,17 @@ static int snd_ca0106_i2c_capture_source_put(struct snd_kcontrol *kcontrol,
static int snd_ca0106_capture_line_in_side_out_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Side out", "Line in" };
+ static const char * const texts[2] = { "Side out", "Line in" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ca0106_capture_mic_line_in_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = { "Line in", "Mic in" };
+ static const char * const texts[2] = { "Line in", "Mic in" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ca0106_capture_mic_line_in_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ctxfi/ctatc.c b/sound/pci/ctxfi/ctatc.c
index 4546590..977a598 100644
--- a/sound/pci/ctxfi/ctatc.c
+++ b/sound/pci/ctxfi/ctatc.c
@@ -438,7 +438,9 @@ atc_pcm_playback_position(struct ct_atc *atc, struct ct_atc_pcm *apcm)
position = src->ops->get_ca(src);
if (position < apcm->vm_block->addr) {
- snd_printdd("ctxfi: bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n", position, apcm->vm_block->addr, apcm->vm_block->size);
+ dev_dbg(atc->card->dev,
+ "bad ca - ca=0x%08x, vba=0x%08x, vbs=0x%08x\n",
+ position, apcm->vm_block->addr, apcm->vm_block->size);
position = apcm->vm_block->addr;
}
@@ -1145,7 +1147,6 @@ static int atc_release_resources(struct ct_atc *atc)
int i;
struct daio_mgr *daio_mgr = NULL;
struct dao *dao = NULL;
- struct dai *dai = NULL;
struct daio *daio = NULL;
struct sum_mgr *sum_mgr = NULL;
struct src_mgr *src_mgr = NULL;
@@ -1172,9 +1173,6 @@ static int atc_release_resources(struct ct_atc *atc)
dao = container_of(daio, struct dao, daio);
dao->ops->clear_left_input(dao);
dao->ops->clear_right_input(dao);
- } else {
- dai = container_of(daio, struct dai, daio);
- /* some thing to do for dai ... */
}
daio_mgr->put_daio(daio_mgr, daio);
}
@@ -1299,7 +1297,7 @@ static int atc_identify_card(struct ct_atc *atc, unsigned int ssid)
atc->model = CT20K2_UNKNOWN;
}
atc->model_name = ct_subsys_name[atc->model];
- snd_printd("ctxfi: chip %s model %s (%04x:%04x) is found\n",
+ dev_info(atc->card->dev, "chip %s model %s (%04x:%04x) is found\n",
atc->chip_name, atc->model_name,
vendor_id, device_id);
return 0;
diff --git a/sound/pci/ctxfi/ctdaio.c b/sound/pci/ctxfi/ctdaio.c
index c1c3f88..9b87dd2 100644
--- a/sound/pci/ctxfi/ctdaio.c
+++ b/sound/pci/ctxfi/ctdaio.c
@@ -528,8 +528,6 @@ static int get_daio_rsc(struct daio_mgr *mgr,
struct daio **rdaio)
{
int err;
- struct dai *dai = NULL;
- struct dao *dao = NULL;
unsigned long flags;
*rdaio = NULL;
@@ -544,27 +542,30 @@ static int get_daio_rsc(struct daio_mgr *mgr,
return err;
}
+ err = -ENOMEM;
/* Allocate mem for daio resource */
if (desc->type <= DAIO_OUT_MAX) {
- dao = kzalloc(sizeof(*dao), GFP_KERNEL);
- if (!dao) {
- err = -ENOMEM;
+ struct dao *dao = kzalloc(sizeof(*dao), GFP_KERNEL);
+ if (!dao)
goto error;
- }
+
err = dao_rsc_init(dao, desc, mgr);
- if (err)
+ if (err) {
+ kfree(dao);
goto error;
+ }
*rdaio = &dao->daio;
} else {
- dai = kzalloc(sizeof(*dai), GFP_KERNEL);
- if (!dai) {
- err = -ENOMEM;
+ struct dai *dai = kzalloc(sizeof(*dai), GFP_KERNEL);
+ if (!dai)
goto error;
- }
+
err = dai_rsc_init(dai, desc, mgr);
- if (err)
+ if (err) {
+ kfree(dai);
goto error;
+ }
*rdaio = &dai->daio;
}
@@ -575,11 +576,6 @@ static int get_daio_rsc(struct daio_mgr *mgr,
return 0;
error:
- if (dao)
- kfree(dao);
- else if (dai)
- kfree(dai);
-
spin_lock_irqsave(&mgr->mgr_lock, flags);
daio_mgr_put_rsc(&mgr->mgr, desc->type);
spin_unlock_irqrestore(&mgr->mgr_lock, flags);
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c
index 03fb909..a5d4604 100644
--- a/sound/pci/ctxfi/cttimer.c
+++ b/sound/pci/ctxfi/cttimer.c
@@ -421,12 +421,12 @@ struct ct_timer *ct_timer_new(struct ct_atc *atc)
atimer->atc = atc;
hw = atc->hw;
if (!use_system_timer && hw->set_timer_irq) {
- snd_printd(KERN_INFO "ctxfi: Use xfi-native timer\n");
+ dev_info(atc->card->dev, "Use xfi-native timer\n");
atimer->ops = &ct_xfitimer_ops;
hw->irq_callback_data = atimer;
hw->irq_callback = ct_timer_interrupt;
} else {
- snd_printd(KERN_INFO "ctxfi: Use system timer\n");
+ dev_info(atc->card->dev, "Use system timer\n");
atimer->ops = &ct_systimer_ops;
}
return atimer;
diff --git a/sound/pci/echoaudio/darla20_dsp.c b/sound/pci/echoaudio/darla20_dsp.c
index 20c7cbc..febee5b 100644
--- a/sound/pci/echoaudio/darla20_dsp.c
+++ b/sound/pci/echoaudio/darla20_dsp.c
@@ -33,12 +33,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Darla20\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA20))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw: could not initialize DSP comm page\n");
return err;
}
@@ -57,7 +57,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/darla24_dsp.c b/sound/pci/echoaudio/darla24_dsp.c
index 6da6663..7b4f6fd 100644
--- a/sound/pci/echoaudio/darla24_dsp.c
+++ b/sound/pci/echoaudio/darla24_dsp.c
@@ -33,12 +33,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Darla24\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != DARLA24))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw: could not initialize DSP comm page\n");
return err;
}
@@ -56,7 +56,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -128,15 +127,17 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
clock = GD24_8000;
break;
default:
- DE_ACT(("set_sample_rate: Error, invalid sample rate %d\n",
- rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: Error, invalid sample rate %d\n",
+ rate);
return -EINVAL;
}
if (wait_handshake(chip))
return -EIO;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, clock);
chip->sample_rate = rate;
/* Override the sample rate if this card is set to Echo sync. */
diff --git a/sound/pci/echoaudio/echo3g_dsp.c b/sound/pci/echoaudio/echo3g_dsp.c
index 3cdc2ee..ae11ce1 100644
--- a/sound/pci/echoaudio/echo3g_dsp.c
+++ b/sound/pci/echoaudio/echo3g_dsp.c
@@ -46,12 +46,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
int err;
local_irq_enable();
- DE_INIT(("init_hw() - Echo3G\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != ECHO3G))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -98,7 +98,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
ECHOCAPS_HAS_DIGITAL_MODE_SPDIF_OPTICAL |
ECHOCAPS_HAS_DIGITAL_MODE_ADAT;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c
index 631aaa4..21228ad 100644
--- a/sound/pci/echoaudio/echoaudio.c
+++ b/sound/pci/echoaudio/echoaudio.c
@@ -48,13 +48,16 @@ static int get_firmware(const struct firmware **fw_entry,
#ifdef CONFIG_PM_SLEEP
if (chip->fw_cache[fw_index]) {
- DE_ACT(("firmware requested: %s is cached\n", card_fw[fw_index].data));
+ dev_dbg(chip->card->dev,
+ "firmware requested: %s is cached\n",
+ card_fw[fw_index].data);
*fw_entry = chip->fw_cache[fw_index];
return 0;
}
#endif
- DE_ACT(("firmware requested: %s\n", card_fw[fw_index].data));
+ dev_dbg(chip->card->dev,
+ "firmware requested: %s\n", card_fw[fw_index].data);
snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data);
err = request_firmware(fw_entry, name, pci_device(chip));
if (err < 0)
@@ -69,13 +72,13 @@ static int get_firmware(const struct firmware **fw_entry,
-static void free_firmware(const struct firmware *fw_entry)
+static void free_firmware(const struct firmware *fw_entry,
+ struct echoaudio *chip)
{
#ifdef CONFIG_PM_SLEEP
- DE_ACT(("firmware not released (kept in cache)\n"));
+ dev_dbg(chip->card->dev, "firmware not released (kept in cache)\n");
#else
release_firmware(fw_entry);
- DE_ACT(("firmware released\n"));
#endif
}
@@ -89,10 +92,9 @@ static void free_firmware_cache(struct echoaudio *chip)
for (i = 0; i < 8 ; i++)
if (chip->fw_cache[i]) {
release_firmware(chip->fw_cache[i]);
- DE_ACT(("release_firmware(%d)\n", i));
+ dev_dbg(chip->card->dev, "release_firmware(%d)\n", i);
}
- DE_ACT(("firmware_cache released\n"));
#endif
}
@@ -286,7 +288,7 @@ static int pcm_open(struct snd_pcm_substream *substream,
/* Set up hw capabilities and contraints */
memcpy(&pipe->hw, &pcm_hardware_skel, sizeof(struct snd_pcm_hardware));
- DE_HWP(("max_channels=%d\n", max_channels));
+ dev_dbg(chip->card->dev, "max_channels=%d\n", max_channels);
pipe->constr.list = channels_list;
pipe->constr.mask = 0;
for (i = 0; channels_list[i] <= max_channels; i++);
@@ -336,7 +338,7 @@ static int pcm_open(struct snd_pcm_substream *substream,
if ((err = snd_dma_alloc_pages(SNDRV_DMA_TYPE_DEV,
snd_dma_pci_data(chip->pci),
PAGE_SIZE, &pipe->sgpage)) < 0) {
- DE_HWP(("s-g list allocation failed\n"));
+ dev_err(chip->card->dev, "s-g list allocation failed\n");
return err;
}
@@ -350,7 +352,6 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err;
- DE_ACT(("pcm_analog_in_open\n"));
if ((err = pcm_open(substream, num_analog_busses_in(chip) -
substream->number)) < 0)
return err;
@@ -367,9 +368,9 @@ static int pcm_analog_in_open(struct snd_pcm_substream *substream)
atomic_inc(&chip->opencount);
if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
chip->can_set_rate=0;
- DE_HWP(("pcm_analog_in_open cs=%d oc=%d r=%d\n",
+ dev_dbg(chip->card->dev, "pcm_analog_in_open cs=%d oc=%d r=%d\n",
chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate));
+ chip->sample_rate);
return 0;
}
@@ -385,7 +386,6 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream)
#else
max_channels = num_analog_busses_out(chip);
#endif
- DE_ACT(("pcm_analog_out_open\n"));
if ((err = pcm_open(substream, max_channels - substream->number)) < 0)
return err;
if ((err = snd_pcm_hw_rule_add(substream->runtime, 0,
@@ -403,9 +403,9 @@ static int pcm_analog_out_open(struct snd_pcm_substream *substream)
atomic_inc(&chip->opencount);
if (atomic_read(&chip->opencount) > 1 && chip->rate_set)
chip->can_set_rate=0;
- DE_HWP(("pcm_analog_out_open cs=%d oc=%d r=%d\n",
+ dev_dbg(chip->card->dev, "pcm_analog_out_open cs=%d oc=%d r=%d\n",
chip->can_set_rate, atomic_read(&chip->opencount),
- chip->sample_rate));
+ chip->sample_rate);
return 0;
}
@@ -418,7 +418,6 @@ static int pcm_digital_in_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err, max_channels;
- DE_ACT(("pcm_digital_in_open\n"));
max_channels = num_digital_busses_in(chip) - substream->number;
mutex_lock(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
@@ -460,7 +459,6 @@ static int pcm_digital_out_open(struct snd_pcm_substream *substream)
struct echoaudio *chip = snd_pcm_substream_chip(substream);
int err, max_channels;
- DE_ACT(("pcm_digital_out_open\n"));
max_channels = num_digital_busses_out(chip) - substream->number;
mutex_lock(&chip->mode_mutex);
if (chip->digital_mode == DIGITAL_MODE_ADAT)
@@ -507,18 +505,17 @@ static int pcm_close(struct snd_pcm_substream *substream)
/* Nothing to do here. Audio is already off and pipe will be
* freed by its callback
*/
- DE_ACT(("pcm_close\n"));
atomic_dec(&chip->opencount);
oc = atomic_read(&chip->opencount);
- DE_ACT(("pcm_close oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate, chip->rate_set));
+ dev_dbg(chip->card->dev, "pcm_close oc=%d cs=%d rs=%d\n", oc,
+ chip->can_set_rate, chip->rate_set);
if (oc < 2)
chip->can_set_rate = 1;
if (oc == 0)
chip->rate_set = 0;
- DE_ACT(("pcm_close2 oc=%d cs=%d rs=%d\n", oc,
- chip->can_set_rate,chip->rate_set));
+ dev_dbg(chip->card->dev, "pcm_close2 oc=%d cs=%d rs=%d\n", oc,
+ chip->can_set_rate, chip->rate_set);
return 0;
}
@@ -542,7 +539,7 @@ static int init_engine(struct snd_pcm_substream *substream,
*/
spin_lock_irq(&chip->lock);
if (pipe->index >= 0) {
- DE_HWP(("hwp_ie free(%d)\n", pipe->index));
+ dev_dbg(chip->card->dev, "hwp_ie free(%d)\n", pipe->index);
err = free_pipes(chip, pipe);
snd_BUG_ON(err);
chip->substream[pipe->index] = NULL;
@@ -551,16 +548,17 @@ static int init_engine(struct snd_pcm_substream *substream,
err = allocate_pipes(chip, pipe, pipe_index, interleave);
if (err < 0) {
spin_unlock_irq(&chip->lock);
- DE_ACT((KERN_NOTICE "allocate_pipes(%d) err=%d\n",
- pipe_index, err));
+ dev_err(chip->card->dev, "allocate_pipes(%d) err=%d\n",
+ pipe_index, err);
return err;
}
spin_unlock_irq(&chip->lock);
- DE_ACT((KERN_NOTICE "allocate_pipes()=%d\n", pipe_index));
+ dev_dbg(chip->card->dev, "allocate_pipes()=%d\n", pipe_index);
- DE_HWP(("pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
+ dev_dbg(chip->card->dev,
+ "pcm_hw_params (bufsize=%dB periods=%d persize=%dB)\n",
params_buffer_bytes(hw_params), params_periods(hw_params),
- params_period_bytes(hw_params)));
+ params_period_bytes(hw_params));
err = snd_pcm_lib_malloc_pages(substream,
params_buffer_bytes(hw_params));
if (err < 0) {
@@ -615,7 +613,6 @@ static int init_engine(struct snd_pcm_substream *substream,
spin_lock_irq(&chip->lock);
set_sample_rate(chip, hw_params->rate_num / hw_params->rate_den);
spin_unlock_irq(&chip->lock);
- DE_HWP(("pcm_hw_params ok\n"));
return 0;
}
@@ -679,14 +676,13 @@ static int pcm_hw_free(struct snd_pcm_substream *substream)
spin_lock_irq(&chip->lock);
if (pipe->index >= 0) {
- DE_HWP(("pcm_hw_free(%d)\n", pipe->index));
+ dev_dbg(chip->card->dev, "pcm_hw_free(%d)\n", pipe->index);
free_pipes(chip, pipe);
chip->substream[pipe->index] = NULL;
pipe->index = -1;
}
spin_unlock_irq(&chip->lock);
- DE_HWP(("pcm_hw_freed\n"));
snd_pcm_lib_free_pages(substream);
return 0;
}
@@ -700,8 +696,8 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
struct audioformat format;
int pipe_index = ((struct audiopipe *)runtime->private_data)->index;
- DE_HWP(("Prepare rate=%d format=%d channels=%d\n",
- runtime->rate, runtime->format, runtime->channels));
+ dev_dbg(chip->card->dev, "Prepare rate=%d format=%d channels=%d\n",
+ runtime->rate, runtime->format, runtime->channels);
format.interleave = runtime->channels;
format.data_are_bigendian = 0;
format.mono_to_stereo = 0;
@@ -721,8 +717,9 @@ static int pcm_prepare(struct snd_pcm_substream *substream)
format.bits_per_sample = 32;
break;
default:
- DE_HWP(("Prepare error: unsupported format %d\n",
- runtime->format));
+ dev_err(chip->card->dev,
+ "Prepare error: unsupported format %d\n",
+ runtime->format);
return -EINVAL;
}
@@ -757,10 +754,8 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
spin_lock(&chip->lock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_RESUME:
- DE_ACT(("pcm_trigger resume\n"));
case SNDRV_PCM_TRIGGER_START:
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- DE_ACT(("pcm_trigger start\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
if (channelmask & (1 << i)) {
pipe = chip->substream[i]->runtime->private_data;
@@ -782,9 +777,7 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
chip->pipe_cyclic_mask);
break;
case SNDRV_PCM_TRIGGER_SUSPEND:
- DE_ACT(("pcm_trigger suspend\n"));
case SNDRV_PCM_TRIGGER_STOP:
- DE_ACT(("pcm_trigger stop\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
if (channelmask & (1 << i)) {
pipe = chip->substream[i]->runtime->private_data;
@@ -794,7 +787,6 @@ static int pcm_trigger(struct snd_pcm_substream *substream, int cmd)
err = stop_transport(chip, channelmask);
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- DE_ACT(("pcm_trigger pause\n"));
for (i = 0; i < DSP_MAXPIPES; i++) {
if (channelmask & (1 << i)) {
pipe = chip->substream[i]->runtime->private_data;
@@ -931,7 +923,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Analog PCM ok\n"));
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital inputs, no outputs */
@@ -944,7 +935,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Digital PCM ok\n"));
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#else /* ECHOCARD_HAS_VMIXER */
@@ -966,7 +956,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &analog_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Analog PCM ok\n"));
#ifdef ECHOCARD_HAS_DIGITAL_IO
/* PCM#1 Digital i/o */
@@ -981,7 +970,6 @@ static int snd_echo_new_pcm(struct echoaudio *chip)
snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &digital_capture_ops);
if ((err = snd_echo_preallocate_pages(pcm, snd_dma_pci_data(chip->pci))) < 0)
return err;
- DE_INIT(("Digital PCM ok\n"));
#endif /* ECHOCARD_HAS_DIGITAL_IO */
#endif /* ECHOCARD_HAS_VMIXER */
@@ -1416,21 +1404,14 @@ static struct snd_kcontrol_new snd_echo_vmixer = {
static int snd_echo_digital_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *names[4] = {
+ static const char * const names[4] = {
"S/PDIF Coaxial", "S/PDIF Optical", "ADAT Optical",
"S/PDIF Cdrom"
};
struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = chip->num_digital_modes;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= chip->num_digital_modes)
- uinfo->value.enumerated.item = chip->num_digital_modes - 1;
- strcpy(uinfo->value.enumerated.name, names[
- chip->digital_mode_list[uinfo->value.enumerated.item]]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, chip->num_digital_modes, names);
}
static int snd_echo_digital_mode_get(struct snd_kcontrol *kcontrol,
@@ -1481,7 +1462,8 @@ static int snd_echo_digital_mode_put(struct snd_kcontrol *kcontrol,
snd_ctl_notify(chip->card,
SNDRV_CTL_EVENT_MASK_VALUE,
&chip->clock_src_ctl->id);
- DE_ACT(("SDM() =%d\n", changed));
+ dev_dbg(chip->card->dev,
+ "SDM() =%d\n", changed);
}
if (changed >= 0)
changed = 1; /* No errors */
@@ -1509,16 +1491,9 @@ static struct snd_kcontrol_new snd_echo_digital_mode_switch = {
static int snd_echo_spdif_mode_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *names[2] = {"Consumer", "Professional"};
+ static const char * const names[2] = {"Consumer", "Professional"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = 2;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- names[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, names);
}
static int snd_echo_spdif_mode_get(struct snd_kcontrol *kcontrol,
@@ -1566,21 +1541,14 @@ static struct snd_kcontrol_new snd_echo_spdif_mode_switch = {
static int snd_echo_clock_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *names[8] = {
+ static const char * const names[8] = {
"Internal", "Word", "Super", "S/PDIF", "ADAT", "ESync",
"ESync96", "MTC"
};
struct echoaudio *chip;
chip = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->value.enumerated.items = chip->num_clock_sources;
- uinfo->count = 1;
- if (uinfo->value.enumerated.item >= chip->num_clock_sources)
- uinfo->value.enumerated.item = chip->num_clock_sources - 1;
- strcpy(uinfo->value.enumerated.name, names[
- chip->clock_source_list[uinfo->value.enumerated.item]]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, chip->num_clock_sources, names);
}
static int snd_echo_clock_source_get(struct snd_kcontrol *kcontrol,
@@ -1622,7 +1590,8 @@ static int snd_echo_clock_source_put(struct snd_kcontrol *kcontrol,
}
if (changed < 0)
- DE_ACT(("seticlk val%d err 0x%x\n", dclock, changed));
+ dev_dbg(chip->card->dev,
+ "seticlk val%d err 0x%x\n", dclock, changed);
return changed;
}
@@ -1879,7 +1848,7 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
#ifdef ECHOCARD_HAS_MIDI
if (st > 0 && chip->midi_in) {
snd_rawmidi_receive(chip->midi_in, chip->midi_buffer, st);
- DE_MID(("rawmidi_iread=%d\n", st));
+ dev_dbg(chip->card->dev, "rawmidi_iread=%d\n", st);
}
#endif
return IRQ_HANDLED;
@@ -1894,10 +1863,8 @@ static irqreturn_t snd_echo_interrupt(int irq, void *dev_id)
static int snd_echo_free(struct echoaudio *chip)
{
- DE_INIT(("Stop DSP...\n"));
if (chip->comm_page)
rest_in_peace(chip);
- DE_INIT(("Stopped.\n"));
if (chip->irq >= 0)
free_irq(chip->irq, chip);
@@ -1908,17 +1875,14 @@ static int snd_echo_free(struct echoaudio *chip)
if (chip->dsp_registers)
iounmap(chip->dsp_registers);
- if (chip->iores)
- release_and_free_resource(chip->iores);
+ release_and_free_resource(chip->iores);
- DE_INIT(("MMIO freed.\n"));
pci_disable_device(chip->pci);
/* release chip data */
free_firmware_cache(chip);
kfree(chip);
- DE_INIT(("Chip freed.\n"));
return 0;
}
@@ -1928,7 +1892,6 @@ static int snd_echo_dev_free(struct snd_device *device)
{
struct echoaudio *chip = device->device_data;
- DE_INIT(("snd_echo_dev_free()...\n"));
return snd_echo_free(chip);
}
@@ -1961,7 +1924,7 @@ static int snd_echo_create(struct snd_card *card,
pci_disable_device(pci);
return -ENOMEM;
}
- DE_INIT(("chip=%p\n", chip));
+ dev_dbg(card->dev, "chip=%p\n", chip);
spin_lock_init(&chip->lock);
chip->card = card;
chip->pci = pci;
@@ -1998,8 +1961,8 @@ static int snd_echo_create(struct snd_card *card,
return -EBUSY;
}
chip->irq = pci->irq;
- DE_INIT(("pci=%p irq=%d subdev=%04x Init hardware...\n",
- chip->pci, chip->irq, chip->pci->subsystem_device));
+ dev_dbg(card->dev, "pci=%p irq=%d subdev=%04x Init hardware...\n",
+ chip->pci, chip->irq, chip->pci->subsystem_device);
/* Create the DSP comm page - this is the area of memory used for most
of the communication with the DSP, which accesses it via bus mastering */
@@ -2017,11 +1980,10 @@ static int snd_echo_create(struct snd_card *card,
if (err >= 0)
err = set_mixer_defaults(chip);
if (err < 0) {
- DE_INIT(("init_hw err=%d\n", err));
+ dev_err(card->dev, "init_hw err=%d\n", err);
snd_echo_free(chip);
return err;
}
- DE_INIT(("Card init OK\n"));
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) {
snd_echo_free(chip);
@@ -2051,7 +2013,6 @@ static int snd_echo_probe(struct pci_dev *pci,
return -ENOENT;
}
- DE_INIT(("Echoaudio driver starting...\n"));
i = 0;
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
@@ -2204,7 +2165,6 @@ static int snd_echo_suspend(struct device *dev)
struct pci_dev *pci = to_pci_dev(dev);
struct echoaudio *chip = dev_get_drvdata(dev);
- DE_INIT(("suspend start\n"));
snd_pcm_suspend_all(chip->analog_pcm);
snd_pcm_suspend_all(chip->digital_pcm);
@@ -2231,7 +2191,6 @@ static int snd_echo_suspend(struct device *dev)
pci_save_state(pci);
pci_disable_device(pci);
- DE_INIT(("suspend done\n"));
return 0;
}
@@ -2245,7 +2204,6 @@ static int snd_echo_resume(struct device *dev)
u32 pipe_alloc_mask;
int err;
- DE_INIT(("resume start\n"));
pci_restore_state(pci);
commpage_bak = kmalloc(sizeof(struct echoaudio), GFP_KERNEL);
if (commpage_bak == NULL)
@@ -2256,11 +2214,10 @@ static int snd_echo_resume(struct device *dev)
err = init_hw(chip, chip->pci->device, chip->pci->subsystem_device);
if (err < 0) {
kfree(commpage_bak);
- DE_INIT(("resume init_hw err=%d\n", err));
+ dev_err(dev, "resume init_hw err=%d\n", err);
snd_echo_free(chip);
return err;
}
- DE_INIT(("resume init OK\n"));
/* Temporarily set chip->pipe_alloc_mask=0 otherwise
* restore_dsp_settings() fails.
@@ -2273,7 +2230,6 @@ static int snd_echo_resume(struct device *dev)
kfree(commpage_bak);
return err;
}
- DE_INIT(("resume restore OK\n"));
memcpy(&commpage->audio_format, &commpage_bak->audio_format,
sizeof(commpage->audio_format));
@@ -2290,7 +2246,7 @@ static int snd_echo_resume(struct device *dev)
return -EBUSY;
}
chip->irq = pci->irq;
- DE_INIT(("resume irq=%d\n", chip->irq));
+ dev_dbg(dev, "resume irq=%d\n", chip->irq);
#ifdef ECHOCARD_HAS_MIDI
if (chip->midi_input_enabled)
@@ -2299,7 +2255,6 @@ static int snd_echo_resume(struct device *dev)
snd_echo_midi_output_trigger(chip->midi_out, 1);
#endif
- DE_INIT(("resume done\n"));
return 0;
}
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h
index b86b88d..3251522 100644
--- a/sound/pci/echoaudio/echoaudio.h
+++ b/sound/pci/echoaudio/echoaudio.h
@@ -295,34 +295,6 @@
#define PIPE_STATE_PENDING 3 /* Pipe has pending start */
-/* Debug initialization */
-#ifdef CONFIG_SND_DEBUG
-#define DE_INIT(x) snd_printk x
-#else
-#define DE_INIT(x)
-#endif
-
-/* Debug hw_params callbacks */
-#ifdef CONFIG_SND_DEBUG
-#define DE_HWP(x) snd_printk x
-#else
-#define DE_HWP(x)
-#endif
-
-/* Debug normal activity (open, start, stop...) */
-#ifdef CONFIG_SND_DEBUG
-#define DE_ACT(x) snd_printk x
-#else
-#define DE_ACT(x)
-#endif
-
-/* Debug midi activity */
-#ifdef CONFIG_SND_DEBUG
-#define DE_MID(x) snd_printk x
-#else
-#define DE_MID(x)
-#endif
-
struct audiopipe {
volatile u32 *dma_counter; /* Commpage register that contains
@@ -468,7 +440,8 @@ static int wait_handshake(struct echoaudio *chip);
static int send_vector(struct echoaudio *chip, u32 command);
static int get_firmware(const struct firmware **fw_entry,
struct echoaudio *chip, const short fw_index);
-static void free_firmware(const struct firmware *fw_entry);
+static void free_firmware(const struct firmware *fw_entry,
+ struct echoaudio *chip);
#ifdef ECHOCARD_HAS_MIDI
static int enable_midi_input(struct echoaudio *chip, char enable);
diff --git a/sound/pci/echoaudio/echoaudio_3g.c b/sound/pci/echoaudio/echoaudio_3g.c
index 658db44..2fa66dc 100644
--- a/sound/pci/echoaudio/echoaudio_3g.c
+++ b/sound/pci/echoaudio/echoaudio_3g.c
@@ -51,7 +51,7 @@ static int check_asic_status(struct echoaudio *chip)
}
box_status = le32_to_cpu(chip->comm_page->ext_box_status);
- DE_INIT(("box_status=%x\n", box_status));
+ dev_dbg(chip->card->dev, "box_status=%x\n", box_status);
if (box_status == E3G_ASIC_NOT_LOADED)
return -ENODEV;
@@ -76,7 +76,8 @@ static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
if (wait_handshake(chip))
return -EIO;
- DE_ACT(("WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq));
+ dev_dbg(chip->card->dev,
+ "WriteControlReg: Setting 0x%x, 0x%x\n", ctl, frq);
ctl = cpu_to_le32(ctl);
frq = cpu_to_le32(frq);
@@ -89,7 +90,7 @@ static int write_control_reg(struct echoaudio *chip, u32 ctl, u32 frq,
return send_vector(chip, DSP_VC_WRITE_CONTROL_REG);
}
- DE_ACT(("WriteControlReg: not written, no change\n"));
+ dev_dbg(chip->card->dev, "WriteControlReg: not written, no change\n");
return 0;
}
@@ -258,8 +259,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -313,7 +314,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
chip->sample_rate = rate;
- DE_ACT(("SetSampleRate: %d clock %x\n", rate, control_reg));
+ dev_dbg(chip->card->dev,
+ "SetSampleRate: %d clock %x\n", rate, control_reg);
/* Tell the DSP about it - DSP reads both control reg & freq reg */
return write_control_reg(chip, control_reg, frq_reg, 0);
@@ -326,7 +328,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
{
u32 control_reg, clocks_from_dsp;
- DE_ACT(("set_input_clock:\n"));
/* Mask off the clock select bits */
control_reg = le32_to_cpu(chip->comm_page->control_register) &
@@ -335,13 +336,11 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Echo3G clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
if (chip->digital_mode == DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Echo3G clock to SPDIF\n"));
control_reg |= E3G_SPDIF_CLOCK;
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_SPDIF96)
control_reg |= E3G_DOUBLE_SPEED_MODE;
@@ -351,12 +350,10 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
case ECHO_CLOCK_ADAT:
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Echo3G clock to ADAT\n"));
control_reg |= E3G_ADAT_CLOCK;
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_WORD:
- DE_ACT(("Set Echo3G clock to WORD\n"));
control_reg |= E3G_WORD_CLOCK;
if (clocks_from_dsp & E3G_CLOCK_DETECT_BIT_WORD96)
control_reg |= E3G_DOUBLE_SPEED_MODE;
@@ -364,7 +361,8 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg &= ~E3G_DOUBLE_SPEED_MODE;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Echo3G\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Echo3G\n", clock);
return -EINVAL;
}
@@ -392,7 +390,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
incompatible_clock = TRUE;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -427,6 +426,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode(%d)\n", chip->digital_mode));
+ dev_dbg(chip->card->dev, "set_digital_mode(%d)\n", chip->digital_mode);
return incompatible_clock;
}
diff --git a/sound/pci/echoaudio/echoaudio_dsp.c b/sound/pci/echoaudio/echoaudio_dsp.c
index 5a6a217..1a9427a 100644
--- a/sound/pci/echoaudio/echoaudio_dsp.c
+++ b/sound/pci/echoaudio/echoaudio_dsp.c
@@ -80,7 +80,7 @@ static int send_vector(struct echoaudio *chip, u32 command)
udelay(1);
}
- DE_ACT((KERN_ERR "timeout on send_vector\n"));
+ dev_err(chip->card->dev, "timeout on send_vector\n");
return -EBUSY;
}
@@ -104,7 +104,7 @@ static int write_dsp(struct echoaudio *chip, u32 data)
}
chip->bad_board = TRUE; /* Set TRUE until DSP re-loaded */
- DE_ACT((KERN_ERR "write_dsp: Set bad_board to TRUE\n"));
+ dev_dbg(chip->card->dev, "write_dsp: Set bad_board to TRUE\n");
return -EIO;
}
@@ -127,7 +127,7 @@ static int read_dsp(struct echoaudio *chip, u32 *data)
}
chip->bad_board = TRUE; /* Set TRUE until DSP re-loaded */
- DE_INIT((KERN_ERR "read_dsp: Set bad_board to TRUE\n"));
+ dev_err(chip->card->dev, "read_dsp: Set bad_board to TRUE\n");
return -EIO;
}
@@ -154,8 +154,9 @@ static int read_sn(struct echoaudio *chip)
return -EIO;
}
}
- DE_INIT(("Read serial number %08x %08x %08x %08x %08x\n",
- sn[0], sn[1], sn[2], sn[3], sn[4]));
+ dev_dbg(chip->card->dev,
+ "Read serial number %08x %08x %08x %08x %08x\n",
+ sn[0], sn[1], sn[2], sn[3], sn[4]);
return 0;
}
@@ -205,13 +206,12 @@ static int load_asic_generic(struct echoaudio *chip, u32 cmd, short asic)
goto la_error;
}
- DE_INIT(("ASIC loaded\n"));
- free_firmware(fw);
+ free_firmware(fw, chip);
return 0;
la_error:
- DE_INIT(("failed on write_dsp\n"));
- free_firmware(fw);
+ dev_err(chip->card->dev, "failed on write_dsp\n");
+ free_firmware(fw, chip);
return -EIO;
}
@@ -241,8 +241,9 @@ static int install_resident_loader(struct echoaudio *chip)
loader is already installed, host flag 5 will be on. */
status = get_dsp_register(chip, CHI32_STATUS_REG);
if (status & CHI32_STATUS_REG_HF5) {
- DE_INIT(("Resident loader already installed; status is 0x%x\n",
- status));
+ dev_dbg(chip->card->dev,
+ "Resident loader already installed; status is 0x%x\n",
+ status);
return 0;
}
@@ -283,12 +284,14 @@ static int install_resident_loader(struct echoaudio *chip)
/* Write the count to the DSP */
if (write_dsp(chip, words)) {
- DE_INIT(("install_resident_loader: Failed to write word count!\n"));
+ dev_err(chip->card->dev,
+ "install_resident_loader: Failed to write word count!\n");
goto irl_error;
}
/* Write the DSP address */
if (write_dsp(chip, address)) {
- DE_INIT(("install_resident_loader: Failed to write DSP address!\n"));
+ dev_err(chip->card->dev,
+ "install_resident_loader: Failed to write DSP address!\n");
goto irl_error;
}
/* Write out this block of code to the DSP */
@@ -297,7 +300,8 @@ static int install_resident_loader(struct echoaudio *chip)
data = ((u32)code[index] << 16) + code[index + 1];
if (write_dsp(chip, data)) {
- DE_INIT(("install_resident_loader: Failed to write DSP code\n"));
+ dev_err(chip->card->dev,
+ "install_resident_loader: Failed to write DSP code\n");
goto irl_error;
}
index += 2;
@@ -312,16 +316,16 @@ static int install_resident_loader(struct echoaudio *chip)
}
if (i == 200) {
- DE_INIT(("Resident loader failed to set HF5\n"));
+ dev_err(chip->card->dev, "Resident loader failed to set HF5\n");
goto irl_error;
}
- DE_INIT(("Resident loader successfully installed\n"));
- free_firmware(fw);
+ dev_dbg(chip->card->dev, "Resident loader successfully installed\n");
+ free_firmware(fw, chip);
return 0;
irl_error:
- free_firmware(fw);
+ free_firmware(fw, chip);
return -EIO;
}
@@ -334,14 +338,14 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
int index, words, i;
if (chip->dsp_code == code) {
- DE_INIT(("DSP is already loaded!\n"));
+ dev_warn(chip->card->dev, "DSP is already loaded!\n");
return 0;
}
chip->bad_board = TRUE; /* Set TRUE until DSP loaded */
chip->dsp_code = NULL; /* Current DSP code not loaded */
chip->asic_loaded = FALSE; /* Loading the DSP code will reset the ASIC */
- DE_INIT(("load_dsp: Set bad_board to TRUE\n"));
+ dev_dbg(chip->card->dev, "load_dsp: Set bad_board to TRUE\n");
/* If this board requires a resident loader, install it. */
#ifdef DSP_56361
@@ -351,7 +355,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
/* Send software reset command */
if (send_vector(chip, DSP_VC_RESET) < 0) {
- DE_INIT(("LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n"));
+ dev_err(chip->card->dev,
+ "LoadDsp: send_vector DSP_VC_RESET failed, Critical Failure\n");
return -EIO;
}
/* Delay 10us */
@@ -366,7 +371,8 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
}
if (i == 1000) {
- DE_INIT(("load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Timeout waiting for CHI32_STATUS_REG_HF3\n");
return -EIO;
}
@@ -403,29 +409,34 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
index += 2;
if (write_dsp(chip, words) < 0) {
- DE_INIT(("load_dsp: failed to write number of DSP words\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write number of DSP words\n");
return -EIO;
}
if (write_dsp(chip, address) < 0) {
- DE_INIT(("load_dsp: failed to write DSP address\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write DSP address\n");
return -EIO;
}
if (write_dsp(chip, mem_type) < 0) {
- DE_INIT(("load_dsp: failed to write DSP memory type\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write DSP memory type\n");
return -EIO;
}
/* Code */
for (i = 0; i < words; i++, index+=2) {
data = ((u32)code[index] << 16) + code[index + 1];
if (write_dsp(chip, data) < 0) {
- DE_INIT(("load_dsp: failed to write DSP data\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: failed to write DSP data\n");
return -EIO;
}
}
}
if (write_dsp(chip, 0) < 0) { /* We're done!!! */
- DE_INIT(("load_dsp: Failed to write final zero\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to write final zero\n");
return -EIO;
}
udelay(10);
@@ -438,12 +449,14 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
get_dsp_register(chip, CHI32_CONTROL_REG) & ~0x1b00);
if (write_dsp(chip, DSP_FNC_SET_COMMPAGE_ADDR) < 0) {
- DE_INIT(("load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to write DSP_FNC_SET_COMMPAGE_ADDR\n");
return -EIO;
}
if (write_dsp(chip, chip->comm_page_phys) < 0) {
- DE_INIT(("load_dsp: Failed to write comm page address\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to write comm page address\n");
return -EIO;
}
@@ -452,19 +465,20 @@ static int load_dsp(struct echoaudio *chip, u16 *code)
We don't actually use the serial number but we have to
get it as part of the DSP init voodoo. */
if (read_sn(chip) < 0) {
- DE_INIT(("load_dsp: Failed to read serial number\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: Failed to read serial number\n");
return -EIO;
}
chip->dsp_code = code; /* Show which DSP code loaded */
chip->bad_board = FALSE; /* DSP OK */
- DE_INIT(("load_dsp: OK!\n"));
return 0;
}
udelay(100);
}
- DE_INIT(("load_dsp: DSP load timed out waiting for HF4\n"));
+ dev_err(chip->card->dev,
+ "load_dsp: DSP load timed out waiting for HF4\n");
return -EIO;
}
@@ -491,7 +505,7 @@ static int load_firmware(struct echoaudio *chip)
if (err < 0)
return err;
err = load_dsp(chip, (u16 *)fw->data);
- free_firmware(fw);
+ free_firmware(fw, chip);
if (err < 0)
return err;
@@ -658,7 +672,6 @@ static void get_audio_meters(struct echoaudio *chip, long *meters)
static int restore_dsp_rettings(struct echoaudio *chip)
{
int i, o, err;
- DE_INIT(("restore_dsp_settings\n"));
if ((err = check_asic_status(chip)) < 0)
return err;
@@ -755,7 +768,6 @@ static int restore_dsp_rettings(struct echoaudio *chip)
if (send_vector(chip, DSP_VC_UPDATE_FLAGS) < 0)
return -EIO;
- DE_INIT(("restore_dsp_rettings done\n"));
return 0;
}
@@ -835,7 +847,8 @@ static void set_audio_format(struct echoaudio *chip, u16 pipe_index,
break;
}
}
- DE_ACT(("set_audio_format[%d] = %x\n", pipe_index, dsp_format));
+ dev_dbg(chip->card->dev,
+ "set_audio_format[%d] = %x\n", pipe_index, dsp_format);
chip->comm_page->audio_format[pipe_index] = cpu_to_le16(dsp_format);
}
@@ -848,7 +861,6 @@ Same thing for pause_ and stop_ -trasport below. */
static int start_transport(struct echoaudio *chip, u32 channel_mask,
u32 cyclic_mask)
{
- DE_ACT(("start_transport %x\n", channel_mask));
if (wait_handshake(chip))
return -EIO;
@@ -866,7 +878,7 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask,
return 0;
}
- DE_ACT(("start_transport: No pipes to start!\n"));
+ dev_err(chip->card->dev, "start_transport: No pipes to start!\n");
return -EINVAL;
}
@@ -874,7 +886,6 @@ static int start_transport(struct echoaudio *chip, u32 channel_mask,
static int pause_transport(struct echoaudio *chip, u32 channel_mask)
{
- DE_ACT(("pause_transport %x\n", channel_mask));
if (wait_handshake(chip))
return -EIO;
@@ -893,7 +904,7 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask)
return 0;
}
- DE_ACT(("pause_transport: No pipes to stop!\n"));
+ dev_warn(chip->card->dev, "pause_transport: No pipes to stop!\n");
return 0;
}
@@ -901,7 +912,6 @@ static int pause_transport(struct echoaudio *chip, u32 channel_mask)
static int stop_transport(struct echoaudio *chip, u32 channel_mask)
{
- DE_ACT(("stop_transport %x\n", channel_mask));
if (wait_handshake(chip))
return -EIO;
@@ -920,7 +930,7 @@ static int stop_transport(struct echoaudio *chip, u32 channel_mask)
return 0;
}
- DE_ACT(("stop_transport: No pipes to stop!\n"));
+ dev_warn(chip->card->dev, "stop_transport: No pipes to stop!\n");
return 0;
}
@@ -937,7 +947,6 @@ static inline int is_pipe_allocated(struct echoaudio *chip, u16 pipe_index)
stopped and unallocated. */
static int rest_in_peace(struct echoaudio *chip)
{
- DE_ACT(("rest_in_peace() open=%x\n", chip->pipe_alloc_mask));
/* Stops all active pipes (just to be sure) */
stop_transport(chip, chip->active_mask);
@@ -965,7 +974,8 @@ static int init_dsp_comm_page(struct echoaudio *chip)
{
/* Check if the compiler added extra padding inside the structure */
if (offsetof(struct comm_page, midi_output) != 0xbe0) {
- DE_INIT(("init_dsp_comm_page() - Invalid struct comm_page structure\n"));
+ dev_err(chip->card->dev,
+ "init_dsp_comm_page() - Invalid struct comm_page structure\n");
return -EPERM;
}
@@ -999,7 +1009,6 @@ static int init_dsp_comm_page(struct echoaudio *chip)
*/
static int init_line_levels(struct echoaudio *chip)
{
- DE_INIT(("init_line_levels\n"));
memset(chip->output_gain, ECHOGAIN_MUTED, sizeof(chip->output_gain));
memset(chip->input_gain, ECHOGAIN_MUTED, sizeof(chip->input_gain));
memset(chip->monitor_gain, ECHOGAIN_MUTED, sizeof(chip->monitor_gain));
@@ -1051,7 +1060,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
u32 channel_mask;
char is_cyclic;
- DE_ACT(("allocate_pipes: ch=%d int=%d\n", pipe_index, interleave));
+ dev_dbg(chip->card->dev,
+ "allocate_pipes: ch=%d int=%d\n", pipe_index, interleave);
if (chip->bad_board)
return -EIO;
@@ -1061,7 +1071,8 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
for (channel_mask = i = 0; i < interleave; i++)
channel_mask |= 1 << (pipe_index + i);
if (chip->pipe_alloc_mask & channel_mask) {
- DE_ACT(("allocate_pipes: channel already open\n"));
+ dev_err(chip->card->dev,
+ "allocate_pipes: channel already open\n");
return -EAGAIN;
}
@@ -1078,7 +1089,6 @@ static int allocate_pipes(struct echoaudio *chip, struct audiopipe *pipe,
it moves data. The DMA counter is in units of bytes, not samples. */
pipe->dma_counter = &chip->comm_page->position[pipe_index];
*pipe->dma_counter = 0;
- DE_ACT(("allocate_pipes: ok\n"));
return pipe_index;
}
@@ -1089,7 +1099,6 @@ static int free_pipes(struct echoaudio *chip, struct audiopipe *pipe)
u32 channel_mask;
int i;
- DE_ACT(("free_pipes: Pipe %d\n", pipe->index));
if (snd_BUG_ON(!is_pipe_allocated(chip, pipe->index)))
return -EINVAL;
if (snd_BUG_ON(pipe->state != PIPE_STATE_STOPPED))
@@ -1131,7 +1140,7 @@ static int sglist_add_mapping(struct echoaudio *chip, struct audiopipe *pipe,
list[head].size = cpu_to_le32(length);
pipe->sglist_head++;
} else {
- DE_ACT(("SGlist: too many fragments\n"));
+ dev_err(chip->card->dev, "SGlist: too many fragments\n");
return -ENOMEM;
}
return 0;
diff --git a/sound/pci/echoaudio/echoaudio_gml.c b/sound/pci/echoaudio/echoaudio_gml.c
index afa2733..23a0994 100644
--- a/sound/pci/echoaudio/echoaudio_gml.c
+++ b/sound/pci/echoaudio/echoaudio_gml.c
@@ -46,7 +46,8 @@ static int check_asic_status(struct echoaudio *chip)
/* The DSP will return a value to indicate whether or not the
ASIC is currently loaded */
if (read_dsp(chip, &asic_status) < 0) {
- DE_INIT(("check_asic_status: failed on read_dsp\n"));
+ dev_err(chip->card->dev,
+ "check_asic_status: failed on read_dsp\n");
chip->asic_loaded = FALSE;
return -EIO;
}
@@ -68,7 +69,7 @@ static int write_control_reg(struct echoaudio *chip, u32 value, char force)
else
value &= ~GML_DIGITAL_IN_AUTO_MUTE;
- DE_ACT(("write_control_reg: 0x%x\n", value));
+ dev_dbg(chip->card->dev, "write_control_reg: 0x%x\n", value);
/* Write the control register */
value = cpu_to_le32(value);
@@ -91,7 +92,7 @@ If the auto-mute is disabled, the digital inputs are enabled regardless of
what the input clock is set or what is connected. */
static int set_input_auto_mute(struct echoaudio *chip, int automute)
{
- DE_ACT(("set_input_auto_mute %d\n", automute));
+ dev_dbg(chip->card->dev, "set_input_auto_mute %d\n", automute);
chip->digital_in_automute = automute;
@@ -194,7 +195,7 @@ static int set_professional_spdif(struct echoaudio *chip, char prof)
if ((err = write_control_reg(chip, control_reg, FALSE)))
return err;
chip->professional_spdif = prof;
- DE_ACT(("set_professional_spdif to %s\n",
- prof ? "Professional" : "Consumer"));
+ dev_dbg(chip->card->dev, "set_professional_spdif to %s\n",
+ prof ? "Professional" : "Consumer");
return 0;
}
diff --git a/sound/pci/echoaudio/gina20_dsp.c b/sound/pci/echoaudio/gina20_dsp.c
index d1615a0..5dafe92 100644
--- a/sound/pci/echoaudio/gina20_dsp.c
+++ b/sound/pci/echoaudio/gina20_dsp.c
@@ -37,12 +37,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Gina20\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA20))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -62,7 +62,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -149,7 +148,6 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
static int set_input_clock(struct echoaudio *chip, u16 clock)
{
- DE_ACT(("set_input_clock:\n"));
switch (clock) {
case ECHO_CLOCK_INTERNAL:
@@ -158,7 +156,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
chip->spdif_status = GD_SPDIF_STATUS_UNDEF;
set_sample_rate(chip, chip->sample_rate);
chip->input_clock = clock;
- DE_ACT(("Set Gina clock to INTERNAL\n"));
break;
case ECHO_CLOCK_SPDIF:
chip->comm_page->gd_clock_state = GD_CLOCK_SPDIFIN;
@@ -166,7 +163,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
clear_handshake(chip);
send_vector(chip, DSP_VC_SET_GD_AUDIO_STATE);
chip->clock_state = GD_CLOCK_SPDIFIN;
- DE_ACT(("Set Gina20 clock to SPDIF\n"));
chip->input_clock = clock;
break;
default:
@@ -208,7 +204,6 @@ static int update_flags(struct echoaudio *chip)
static int set_professional_spdif(struct echoaudio *chip, char prof)
{
- DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
diff --git a/sound/pci/echoaudio/gina24_dsp.c b/sound/pci/echoaudio/gina24_dsp.c
index 98f7cfa..6971766 100644
--- a/sound/pci/echoaudio/gina24_dsp.c
+++ b/sound/pci/echoaudio/gina24_dsp.c
@@ -41,12 +41,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Gina24\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != GINA24))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -78,7 +78,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -155,7 +154,6 @@ static int load_asic(struct echoaudio *chip)
control_reg = GML_CONVERTER_ENABLE | GML_48KHZ;
err = write_control_reg(chip, control_reg, TRUE);
}
- DE_INIT(("load_asic() done\n"));
return err;
}
@@ -171,8 +169,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -217,7 +215,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
clock = GML_8KHZ;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -225,7 +224,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
chip->sample_rate = rate;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev, "set_sample_rate: %d clock %d\n", rate, clock);
return write_control_reg(chip, control_reg, FALSE);
}
@@ -236,7 +235,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
{
u32 control_reg, clocks_from_dsp;
- DE_ACT(("set_input_clock:\n"));
/* Mask off the clock select bits */
control_reg = le32_to_cpu(chip->comm_page->control_register) &
@@ -245,13 +243,11 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Gina24 clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
if (chip->digital_mode == DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Gina24 clock to SPDIF\n"));
control_reg |= GML_SPDIF_CLOCK;
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
control_reg |= GML_DOUBLE_SPEED_MODE;
@@ -261,21 +257,19 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
case ECHO_CLOCK_ADAT:
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
- DE_ACT(("Set Gina24 clock to ADAT\n"));
control_reg |= GML_ADAT_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_ESYNC:
- DE_ACT(("Set Gina24 clock to ESYNC\n"));
control_reg |= GML_ESYNC_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_ESYNC96:
- DE_ACT(("Set Gina24 clock to ESYNC96\n"));
control_reg |= GML_ESYNC_CLOCK | GML_DOUBLE_SPEED_MODE;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Gina24\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Gina24\n", clock);
return -EINVAL;
}
@@ -304,7 +298,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
incompatible_clock = TRUE;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -344,6 +339,7 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode to %d\n", chip->digital_mode));
+ dev_dbg(chip->card->dev,
+ "set_digital_mode to %d\n", chip->digital_mode);
return incompatible_clock;
}
diff --git a/sound/pci/echoaudio/indigo_dsp.c b/sound/pci/echoaudio/indigo_dsp.c
index 5e85f14..54edd67 100644
--- a/sound/pci/echoaudio/indigo_dsp.c
+++ b/sound/pci/echoaudio/indigo_dsp.c
@@ -38,12 +38,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -60,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -109,7 +108,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg = MIA_32000;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -147,7 +147,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigo_express_dsp.c b/sound/pci/echoaudio/indigo_express_dsp.c
index 2e4ab3e..ceda2d7 100644
--- a/sound/pci/echoaudio/indigo_express_dsp.c
+++ b/sound/pci/echoaudio/indigo_express_dsp.c
@@ -61,7 +61,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg |= clock;
if (control_reg != old_control_reg) {
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, clock);
chip->comm_page->control_register = cpu_to_le32(control_reg);
chip->sample_rate = rate;
clear_handshake(chip);
@@ -89,7 +90,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigodj_dsp.c b/sound/pci/echoaudio/indigodj_dsp.c
index 68f3c8c..2cf5cc0 100644
--- a/sound/pci/echoaudio/indigodj_dsp.c
+++ b/sound/pci/echoaudio/indigodj_dsp.c
@@ -38,12 +38,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo DJ\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJ))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -60,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -109,7 +108,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg = MIA_32000;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -147,7 +147,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigodjx_dsp.c b/sound/pci/echoaudio/indigodjx_dsp.c
index bb9632c7..5252863 100644
--- a/sound/pci/echoaudio/indigodjx_dsp.c
+++ b/sound/pci/echoaudio/indigodjx_dsp.c
@@ -35,13 +35,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo DJx\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_DJX))
return -ENODEV;
err = init_dsp_comm_page(chip);
if (err < 0) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -59,7 +59,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/indigoio_dsp.c b/sound/pci/echoaudio/indigoio_dsp.c
index beb9a5b6..4e81787 100644
--- a/sound/pci/echoaudio/indigoio_dsp.c
+++ b/sound/pci/echoaudio/indigoio_dsp.c
@@ -38,12 +38,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo IO\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IO))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -60,7 +60,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -118,7 +117,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
diff --git a/sound/pci/echoaudio/indigoiox_dsp.c b/sound/pci/echoaudio/indigoiox_dsp.c
index 394c6e76..6de3f9b 100644
--- a/sound/pci/echoaudio/indigoiox_dsp.c
+++ b/sound/pci/echoaudio/indigoiox_dsp.c
@@ -35,13 +35,13 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Indigo IOx\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != INDIGO_IOX))
return -ENODEV;
err = init_dsp_comm_page(chip);
if (err < 0) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -59,7 +59,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
diff --git a/sound/pci/echoaudio/layla20_dsp.c b/sound/pci/echoaudio/layla20_dsp.c
index 53ce946..f2024a3 100644
--- a/sound/pci/echoaudio/layla20_dsp.c
+++ b/sound/pci/echoaudio/layla20_dsp.c
@@ -40,12 +40,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Layla20\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA20))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -64,7 +64,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -121,7 +120,8 @@ static int check_asic_status(struct echoaudio *chip)
/* The DSP will return a value to indicate whether or not
the ASIC is currently loaded */
if (read_dsp(chip, &asic_status) < 0) {
- DE_ACT(("check_asic_status: failed on read_dsp\n"));
+ dev_err(chip->card->dev,
+ "check_asic_status: failed on read_dsp\n");
return -EIO;
}
@@ -164,8 +164,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. Do not return failure,
simply treat it as a non-event. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
return 0;
@@ -174,7 +174,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
if (wait_handshake(chip))
return -EIO;
- DE_ACT(("set_sample_rate(%d)\n", rate));
+ dev_dbg(chip->card->dev, "set_sample_rate(%d)\n", rate);
chip->sample_rate = rate;
chip->comm_page->sample_rate = cpu_to_le32(rate);
clear_handshake(chip);
@@ -188,29 +188,25 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source)
u16 clock;
u32 rate;
- DE_ACT(("set_input_clock:\n"));
rate = 0;
switch (clock_source) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Layla20 clock to INTERNAL\n"));
rate = chip->sample_rate;
clock = LAYLA20_CLOCK_INTERNAL;
break;
case ECHO_CLOCK_SPDIF:
- DE_ACT(("Set Layla20 clock to SPDIF\n"));
clock = LAYLA20_CLOCK_SPDIF;
break;
case ECHO_CLOCK_WORD:
- DE_ACT(("Set Layla20 clock to WORD\n"));
clock = LAYLA20_CLOCK_WORD;
break;
case ECHO_CLOCK_SUPER:
- DE_ACT(("Set Layla20 clock to SUPER\n"));
clock = LAYLA20_CLOCK_SUPER;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Layla24\n",
- clock_source));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Layla24\n",
+ clock_source);
return -EINVAL;
}
chip->input_clock = clock_source;
@@ -229,7 +225,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock_source)
static int set_output_clock(struct echoaudio *chip, u16 clock)
{
- DE_ACT(("set_output_clock: %d\n", clock));
switch (clock) {
case ECHO_CLOCK_SUPER:
clock = LAYLA20_OUTPUT_CLOCK_SUPER;
@@ -238,7 +233,7 @@ static int set_output_clock(struct echoaudio *chip, u16 clock)
clock = LAYLA20_OUTPUT_CLOCK_WORD;
break;
default:
- DE_ACT(("set_output_clock wrong clock\n"));
+ dev_err(chip->card->dev, "set_output_clock wrong clock\n");
return -EINVAL;
}
@@ -283,7 +278,6 @@ static int update_flags(struct echoaudio *chip)
static int set_professional_spdif(struct echoaudio *chip, char prof)
{
- DE_ACT(("set_professional_spdif %d\n", prof));
if (prof)
chip->comm_page->flags |=
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
diff --git a/sound/pci/echoaudio/layla24_dsp.c b/sound/pci/echoaudio/layla24_dsp.c
index 8c04164..4f11e81 100644
--- a/sound/pci/echoaudio/layla24_dsp.c
+++ b/sound/pci/echoaudio/layla24_dsp.c
@@ -40,12 +40,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Layla24\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != LAYLA24))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -69,7 +69,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
if ((err = init_line_levels(chip)) < 0)
return err;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -117,7 +116,6 @@ static int load_asic(struct echoaudio *chip)
if (chip->asic_loaded)
return 1;
- DE_INIT(("load_asic\n"));
/* Give the DSP a few milliseconds to settle down */
mdelay(10);
@@ -151,7 +149,6 @@ static int load_asic(struct echoaudio *chip)
err = write_control_reg(chip, GML_CONVERTER_ENABLE | GML_48KHZ,
TRUE);
- DE_INIT(("load_asic() done\n"));
return err;
}
@@ -167,8 +164,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_warn(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -241,7 +238,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP ? */
chip->sample_rate = rate;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, control_reg));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, control_reg);
return write_control_reg(chip, control_reg, FALSE);
}
@@ -260,7 +258,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
/* Pick the new clock */
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Layla24 clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
@@ -269,7 +266,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg |= GML_SPDIF_CLOCK;
/* Layla24 doesn't support 96KHz S/PDIF */
control_reg &= ~GML_DOUBLE_SPEED_MODE;
- DE_ACT(("Set Layla24 clock to SPDIF\n"));
break;
case ECHO_CLOCK_WORD:
control_reg |= GML_WORD_CLOCK;
@@ -277,17 +273,16 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg |= GML_DOUBLE_SPEED_MODE;
else
control_reg &= ~GML_DOUBLE_SPEED_MODE;
- DE_ACT(("Set Layla24 clock to WORD\n"));
break;
case ECHO_CLOCK_ADAT:
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
control_reg |= GML_ADAT_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
- DE_ACT(("Set Layla24 clock to ADAT\n"));
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Layla24\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Layla24\n", clock);
return -EINVAL;
}
@@ -353,7 +348,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
asic = FW_LAYLA24_2A_ASIC;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -393,6 +389,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode to %d\n", mode));
+ dev_dbg(chip->card->dev, "set_digital_mode to %d\n", mode);
return incompatible_clock;
}
diff --git a/sound/pci/echoaudio/mia_dsp.c b/sound/pci/echoaudio/mia_dsp.c
index 6ebfa6e..fdad079 100644
--- a/sound/pci/echoaudio/mia_dsp.c
+++ b/sound/pci/echoaudio/mia_dsp.c
@@ -41,12 +41,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Mia\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != MIA))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -66,7 +66,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -126,7 +125,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
control_reg = MIA_32000;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -153,7 +153,7 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
static int set_input_clock(struct echoaudio *chip, u16 clock)
{
- DE_ACT(("set_input_clock(%d)\n", clock));
+ dev_dbg(chip->card->dev, "set_input_clock(%d)\n", clock);
if (snd_BUG_ON(clock != ECHO_CLOCK_INTERNAL &&
clock != ECHO_CLOCK_SPDIF))
return -EINVAL;
@@ -181,7 +181,8 @@ static int set_vmixer_gain(struct echoaudio *chip, u16 output, u16 pipe,
index = output * num_pipes_out(chip) + pipe;
chip->comm_page->vmixer[index] = gain;
- DE_ACT(("set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain));
+ dev_dbg(chip->card->dev,
+ "set_vmixer_gain: pipe %d, out %d = %d\n", pipe, output, gain);
return 0;
}
@@ -211,7 +212,7 @@ static int update_flags(struct echoaudio *chip)
static int set_professional_spdif(struct echoaudio *chip, char prof)
{
- DE_ACT(("set_professional_spdif %d\n", prof));
+ dev_dbg(chip->card->dev, "set_professional_spdif %d\n", prof);
if (prof)
chip->comm_page->flags |=
cpu_to_le32(DSP_FLAG_PROFESSIONAL_SPDIF);
diff --git a/sound/pci/echoaudio/midi.c b/sound/pci/echoaudio/midi.c
index 7f4dfae..d913749 100644
--- a/sound/pci/echoaudio/midi.c
+++ b/sound/pci/echoaudio/midi.c
@@ -36,7 +36,7 @@
/* Start and stop Midi input */
static int enable_midi_input(struct echoaudio *chip, char enable)
{
- DE_MID(("enable_midi_input(%d)\n", enable));
+ dev_dbg(chip->card->dev, "enable_midi_input(%d)\n", enable);
if (wait_handshake(chip))
return -EIO;
@@ -74,7 +74,7 @@ static int write_midi(struct echoaudio *chip, u8 *data, int bytes)
chip->comm_page->midi_out_free_count = 0;
clear_handshake(chip);
send_vector(chip, DSP_VC_MIDI_WRITE);
- DE_MID(("write_midi: %d\n", bytes));
+ dev_dbg(chip->card->dev, "write_midi: %d\n", bytes);
return bytes;
}
@@ -157,7 +157,6 @@ static int snd_echo_midi_input_open(struct snd_rawmidi_substream *substream)
struct echoaudio *chip = substream->rmidi->private_data;
chip->midi_in = substream;
- DE_MID(("rawmidi_iopen\n"));
return 0;
}
@@ -183,7 +182,6 @@ static int snd_echo_midi_input_close(struct snd_rawmidi_substream *substream)
struct echoaudio *chip = substream->rmidi->private_data;
chip->midi_in = NULL;
- DE_MID(("rawmidi_iclose\n"));
return 0;
}
@@ -196,7 +194,6 @@ static int snd_echo_midi_output_open(struct snd_rawmidi_substream *substream)
chip->tinuse = 0;
chip->midi_full = 0;
chip->midi_out = substream;
- DE_MID(("rawmidi_oopen\n"));
return 0;
}
@@ -209,7 +206,6 @@ static void snd_echo_midi_output_write(unsigned long data)
int bytes, sent, time;
unsigned char buf[MIDI_OUT_BUFFER_SIZE - 1];
- DE_MID(("snd_echo_midi_output_write\n"));
/* No interrupts are involved: we have to check at regular intervals
if the card's output buffer has room for new data. */
sent = bytes = 0;
@@ -218,7 +214,7 @@ static void snd_echo_midi_output_write(unsigned long data)
if (!snd_rawmidi_transmit_empty(chip->midi_out)) {
bytes = snd_rawmidi_transmit_peek(chip->midi_out, buf,
MIDI_OUT_BUFFER_SIZE - 1);
- DE_MID(("Try to send %d bytes...\n", bytes));
+ dev_dbg(chip->card->dev, "Try to send %d bytes...\n", bytes);
sent = write_midi(chip, buf, bytes);
if (sent < 0) {
dev_err(chip->card->dev,
@@ -227,12 +223,12 @@ static void snd_echo_midi_output_write(unsigned long data)
sent = 9000;
chip->midi_full = 1;
} else if (sent > 0) {
- DE_MID(("%d bytes sent\n", sent));
+ dev_dbg(chip->card->dev, "%d bytes sent\n", sent);
snd_rawmidi_transmit_ack(chip->midi_out, sent);
} else {
/* Buffer is full. DSP's internal buffer is 64 (128 ?)
bytes long. Let's wait until half of them are sent */
- DE_MID(("Full\n"));
+ dev_dbg(chip->card->dev, "Full\n");
sent = 32;
chip->midi_full = 1;
}
@@ -244,7 +240,8 @@ static void snd_echo_midi_output_write(unsigned long data)
sent */
time = (sent << 3) / 25 + 1; /* 8/25=0.32ms to send a byte */
mod_timer(&chip->timer, jiffies + (time * HZ + 999) / 1000);
- DE_MID(("Timer armed(%d)\n", ((time * HZ + 999) / 1000)));
+ dev_dbg(chip->card->dev,
+ "Timer armed(%d)\n", ((time * HZ + 999) / 1000));
}
spin_unlock_irqrestore(&chip->lock, flags);
}
@@ -256,7 +253,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
{
struct echoaudio *chip = substream->rmidi->private_data;
- DE_MID(("snd_echo_midi_output_trigger(%d)\n", up));
+ dev_dbg(chip->card->dev, "snd_echo_midi_output_trigger(%d)\n", up);
spin_lock_irq(&chip->lock);
if (up) {
if (!chip->tinuse) {
@@ -270,7 +267,7 @@ static void snd_echo_midi_output_trigger(struct snd_rawmidi_substream *substream
chip->tinuse = 0;
spin_unlock_irq(&chip->lock);
del_timer_sync(&chip->timer);
- DE_MID(("Timer removed\n"));
+ dev_dbg(chip->card->dev, "Timer removed\n");
return;
}
}
@@ -287,7 +284,6 @@ static int snd_echo_midi_output_close(struct snd_rawmidi_substream *substream)
struct echoaudio *chip = substream->rmidi->private_data;
chip->midi_out = NULL;
- DE_MID(("rawmidi_oclose\n"));
return 0;
}
@@ -327,6 +323,5 @@ static int snd_echo_midi_create(struct snd_card *card,
chip->rmidi->info_flags |= SNDRV_RAWMIDI_INFO_OUTPUT |
SNDRV_RAWMIDI_INFO_INPUT | SNDRV_RAWMIDI_INFO_DUPLEX;
- DE_INIT(("MIDI ok\n"));
return 0;
}
diff --git a/sound/pci/echoaudio/mona_dsp.c b/sound/pci/echoaudio/mona_dsp.c
index 6e6a7eb..843c7a5 100644
--- a/sound/pci/echoaudio/mona_dsp.c
+++ b/sound/pci/echoaudio/mona_dsp.c
@@ -41,12 +41,12 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
{
int err;
- DE_INIT(("init_hw() - Mona\n"));
if (snd_BUG_ON((subdevice_id & 0xfff0) != MONA))
return -ENODEV;
if ((err = init_dsp_comm_page(chip))) {
- DE_INIT(("init_hw - could not initialize DSP comm page\n"));
+ dev_err(chip->card->dev,
+ "init_hw - could not initialize DSP comm page\n");
return err;
}
@@ -71,7 +71,6 @@ static int init_hw(struct echoaudio *chip, u16 device_id, u16 subdevice_id)
return err;
chip->bad_board = FALSE;
- DE_INIT(("init_hw done\n"));
return err;
}
@@ -202,8 +201,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
/* Only set the clock for internal mode. */
if (chip->input_clock != ECHO_CLOCK_INTERNAL) {
- DE_ACT(("set_sample_rate: Cannot set sample rate - "
- "clock not set to CLK_CLOCKININTERNAL\n"));
+ dev_dbg(chip->card->dev,
+ "Cannot set sample rate - clock not set to CLK_CLOCKININTERNAL\n");
/* Save the rate anyhow */
chip->comm_page->sample_rate = cpu_to_le32(rate);
chip->sample_rate = rate;
@@ -279,7 +278,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
clock = GML_8KHZ;
break;
default:
- DE_ACT(("set_sample_rate: %d invalid!\n", rate));
+ dev_err(chip->card->dev,
+ "set_sample_rate: %d invalid!\n", rate);
return -EINVAL;
}
@@ -287,7 +287,8 @@ static int set_sample_rate(struct echoaudio *chip, u32 rate)
chip->comm_page->sample_rate = cpu_to_le32(rate); /* ignored by the DSP */
chip->sample_rate = rate;
- DE_ACT(("set_sample_rate: %d clock %d\n", rate, clock));
+ dev_dbg(chip->card->dev,
+ "set_sample_rate: %d clock %d\n", rate, clock);
return write_control_reg(chip, control_reg, force_write);
}
@@ -299,7 +300,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
u32 control_reg, clocks_from_dsp;
int err;
- DE_ACT(("set_input_clock:\n"));
/* Prevent two simultaneous calls to switch_asic() */
if (atomic_read(&chip->opencount))
@@ -312,7 +312,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
switch (clock) {
case ECHO_CLOCK_INTERNAL:
- DE_ACT(("Set Mona clock to INTERNAL\n"));
chip->input_clock = ECHO_CLOCK_INTERNAL;
return set_sample_rate(chip, chip->sample_rate);
case ECHO_CLOCK_SPDIF:
@@ -324,7 +323,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
spin_lock_irq(&chip->lock);
if (err < 0)
return err;
- DE_ACT(("Set Mona clock to SPDIF\n"));
control_reg |= GML_SPDIF_CLOCK;
if (clocks_from_dsp & GML_CLOCK_DETECT_BIT_SPDIF96)
control_reg |= GML_DOUBLE_SPEED_MODE;
@@ -332,7 +330,6 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_WORD:
- DE_ACT(("Set Mona clock to WORD\n"));
spin_unlock_irq(&chip->lock);
err = switch_asic(chip, clocks_from_dsp &
GML_CLOCK_DETECT_BIT_WORD96);
@@ -346,14 +343,15 @@ static int set_input_clock(struct echoaudio *chip, u16 clock)
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
case ECHO_CLOCK_ADAT:
- DE_ACT(("Set Mona clock to ADAT\n"));
+ dev_dbg(chip->card->dev, "Set Mona clock to ADAT\n");
if (chip->digital_mode != DIGITAL_MODE_ADAT)
return -EAGAIN;
control_reg |= GML_ADAT_CLOCK;
control_reg &= ~GML_DOUBLE_SPEED_MODE;
break;
default:
- DE_ACT(("Input clock 0x%x not supported for Mona\n", clock));
+ dev_err(chip->card->dev,
+ "Input clock 0x%x not supported for Mona\n", clock);
return -EINVAL;
}
@@ -381,7 +379,8 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
incompatible_clock = TRUE;
break;
default:
- DE_ACT(("Digital mode not supported: %d\n", mode));
+ dev_err(chip->card->dev,
+ "Digital mode not supported: %d\n", mode);
return -EINVAL;
}
@@ -422,6 +421,6 @@ static int dsp_set_digital_mode(struct echoaudio *chip, u8 mode)
return err;
chip->digital_mode = mode;
- DE_ACT(("set_digital_mode to %d\n", mode));
+ dev_dbg(chip->card->dev, "set_digital_mode to %d\n", mode);
return incompatible_clock;
}
diff --git a/sound/pci/emu10k1/emu10k1_main.c b/sound/pci/emu10k1/emu10k1_main.c
index 2292697..b4458a6 100644
--- a/sound/pci/emu10k1/emu10k1_main.c
+++ b/sound/pci/emu10k1/emu10k1_main.c
@@ -1289,10 +1289,8 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
}
if (emu->emu1010.firmware_thread)
kthread_stop(emu->emu1010.firmware_thread);
- if (emu->firmware)
- release_firmware(emu->firmware);
- if (emu->dock_fw)
- release_firmware(emu->dock_fw);
+ release_firmware(emu->firmware);
+ release_firmware(emu->dock_fw);
if (emu->irq >= 0)
free_irq(emu->irq, emu);
/* remove reserved page */
@@ -1301,8 +1299,7 @@ static int snd_emu10k1_free(struct snd_emu10k1 *emu)
(struct snd_util_memblk *)emu->reserved_page);
emu->reserved_page = NULL;
}
- if (emu->memhdr)
- snd_util_memhdr_free(emu->memhdr);
+ snd_util_memhdr_free(emu->memhdr);
if (emu->silent_page.area)
snd_dma_free_pages(&emu->silent_page);
if (emu->ptb_pages.area)
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c
index e223de1..15933f9 100644
--- a/sound/pci/emu10k1/emu10k1x.c
+++ b/sound/pci/emu10k1/emu10k1x.c
@@ -180,7 +180,7 @@ MODULE_PARM_DESC(enable, "Enable the EMU10K1X soundcard.");
/* From 0x50 - 0x5f, last samples captured */
-/**
+/*
* The hardware has 3 channels for playback and 1 for capture.
* - channel 0 is the front channel
* - channel 1 is the rear channel
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c
index 745f062..eb5c0ab 100644
--- a/sound/pci/emu10k1/emufx.c
+++ b/sound/pci/emu10k1/emufx.c
@@ -777,8 +777,7 @@ static void snd_emu10k1_ctl_private_free(struct snd_kcontrol *kctl)
kctl->private_value = 0;
list_del(&ctl->list);
kfree(ctl);
- if (kctl->tlv.p)
- kfree(kctl->tlv.p);
+ kfree(kctl->tlv.p);
}
static int snd_emu10k1_add_controls(struct snd_emu10k1 *emu,
diff --git a/sound/pci/emu10k1/emumixer.c b/sound/pci/emu10k1/emumixer.c
index c5ae2a2..1de3302 100644
--- a/sound/pci/emu10k1/emumixer.c
+++ b/sound/pci/emu10k1/emumixer.c
@@ -83,7 +83,7 @@ static int snd_emu10k1_spdif_get_mask(struct snd_kcontrol *kcontrol,
* Items labels in enum mixer controls assigning source data to
* each destination
*/
-static char *emu1010_src_texts[] = {
+static const char * const emu1010_src_texts[] = {
"Silence",
"Dock Mic A",
"Dock Mic B",
@@ -141,7 +141,7 @@ static char *emu1010_src_texts[] = {
/* 1616(m) cardbus */
-static char *emu1616_src_texts[] = {
+static const char * const emu1616_src_texts[] = {
"Silence",
"Dock Mic A",
"Dock Mic B",
@@ -393,23 +393,11 @@ static int snd_emu1010_input_output_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct snd_emu10k1 *emu = snd_kcontrol_chip(kcontrol);
- char **items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616) {
- uinfo->value.enumerated.items = 49;
- items = emu1616_src_texts;
- } else {
- uinfo->value.enumerated.items = 53;
- items = emu1010_src_texts;
- }
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- items[uinfo->value.enumerated.item]);
- return 0;
+ if (emu->card_capabilities->emu_model == EMU_MODEL_EMU1616)
+ return snd_ctl_enum_info(uinfo, 1, 49, emu1616_src_texts);
+ else
+ return snd_ctl_enum_info(uinfo, 1, 53, emu1010_src_texts);
}
static int snd_emu1010_output_source_get(struct snd_kcontrol *kcontrol,
@@ -699,19 +687,11 @@ static struct snd_kcontrol_new snd_emu1010_dac_pads[] = {
static int snd_emu1010_internal_clock_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"44100", "48000", "SPDIF", "ADAT"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
-
-
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_emu1010_internal_clock_get(struct snd_kcontrol *kcontrol,
@@ -830,21 +810,15 @@ static int snd_audigy_i2c_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
#if 0
- static char *texts[4] = {
+ static const char * const texts[4] = {
"Unknown1", "Unknown2", "Mic", "Line"
};
#endif
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Mic", "Line"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_audigy_i2c_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -997,15 +971,9 @@ static struct snd_kcontrol_new snd_audigy_i2c_volume_ctls[] = {
#if 0
static int snd_audigy_spdif_output_rate_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"44100", "48000", "96000"};
+ static const char * const texts[] = {"44100", "48000", "96000"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_audigy_spdif_output_rate_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/emu10k1/p16v.c b/sound/pci/emu10k1/p16v.c
index a4fe7f0..7ef3898 100644
--- a/sound/pci/emu10k1/p16v.c
+++ b/sound/pci/emu10k1/p16v.c
@@ -757,18 +757,12 @@ static int snd_p16v_volume_put(struct snd_kcontrol *kcontrol,
static int snd_p16v_capture_source_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static const char * const texts[8] = {
"SPDIF", "I2S", "SRC48", "SRCMulti_SPDIF", "SRCMulti_I2S",
"CDIF", "FX", "AC97"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_p16v_capture_source_get(struct snd_kcontrol *kcontrol,
@@ -805,15 +799,9 @@ static int snd_p16v_capture_source_put(struct snd_kcontrol *kcontrol,
static int snd_p16v_capture_channel_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "0", "1", "2", "3", };
+ static const char * const texts[4] = { "0", "1", "2", "3", };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_p16v_capture_channel_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/es1938.c b/sound/pci/es1938.c
index 6399624..0fc46eb 100644
--- a/sound/pci/es1938.c
+++ b/sound/pci/es1938.c
@@ -1045,18 +1045,12 @@ static int snd_es1938_new_pcm(struct es1938 *chip, int device)
static int snd_es1938_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[8] = {
+ static const char * const texts[8] = {
"Mic", "Mic Master", "CD", "AOUT",
"Mic1", "Mix", "Line", "Master"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 8, texts);
}
static int snd_es1938_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/es1968.c b/sound/pci/es1968.c
index a9956a7..6039700 100644
--- a/sound/pci/es1968.c
+++ b/sound/pci/es1968.c
@@ -1710,7 +1710,8 @@ static void es1968_measure_clock(struct es1968 *chip)
int i, apu;
unsigned int pa, offset, t;
struct esm_memory *memory;
- struct timeval start_time, stop_time;
+ ktime_t start_time, stop_time;
+ ktime_t diff;
if (chip->clock == 0)
chip->clock = 48000; /* default clock value */
@@ -1761,12 +1762,12 @@ static void es1968_measure_clock(struct es1968 *chip)
snd_es1968_bob_inc(chip, ESM_BOB_FREQ);
__apu_set_register(chip, apu, 5, pa & 0xffff);
snd_es1968_trigger_apu(chip, apu, ESM_APU_16BITLINEAR);
- do_gettimeofday(&start_time);
+ start_time = ktime_get();
spin_unlock_irq(&chip->reg_lock);
msleep(50);
spin_lock_irq(&chip->reg_lock);
offset = __apu_get_register(chip, apu, 5);
- do_gettimeofday(&stop_time);
+ stop_time = ktime_get();
snd_es1968_trigger_apu(chip, apu, 0); /* stop */
snd_es1968_bob_dec(chip);
chip->in_measurement = 0;
@@ -1777,12 +1778,8 @@ static void es1968_measure_clock(struct es1968 *chip)
offset &= 0xfffe;
offset += chip->measure_count * (CLOCK_MEASURE_BUFSIZE/2);
- t = stop_time.tv_sec - start_time.tv_sec;
- t *= 1000000;
- if (stop_time.tv_usec < start_time.tv_usec)
- t -= start_time.tv_usec - stop_time.tv_usec;
- else
- t += stop_time.tv_usec - start_time.tv_usec;
+ diff = ktime_sub(stop_time, start_time);
+ t = ktime_to_us(diff);
if (t == 0) {
dev_err(chip->card->dev, "?? calculation error..\n");
} else {
diff --git a/sound/pci/fm801.c b/sound/pci/fm801.c
index c503830..d167aff 100644
--- a/sound/pci/fm801.c
+++ b/sound/pci/fm801.c
@@ -958,17 +958,11 @@ static int snd_fm801_put_double(struct snd_kcontrol *kcontrol,
static int snd_fm801_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[5] = {
+ static const char * const texts[5] = {
"AC97 Primary", "FM", "I2S", "PCM", "AC97 Secondary"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item > 4)
- uinfo->value.enumerated.item = 4;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static int snd_fm801_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c
index fcc5e47..1ede822 100644
--- a/sound/pci/hda/hda_auto_parser.c
+++ b/sound/pci/hda/hda_auto_parser.c
@@ -441,6 +441,13 @@ int snd_hda_parse_pin_defcfg(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_parse_pin_defcfg);
+/**
+ * snd_hda_get_input_pin_attr - Get the input pin attribute from pin config
+ * @def_conf: pin configuration value
+ *
+ * Guess the input pin attribute (INPUT_PIN_ATTR_XXX) from the given
+ * default pin configuration value.
+ */
int snd_hda_get_input_pin_attr(unsigned int def_conf)
{
unsigned int loc = get_defcfg_location(def_conf);
@@ -464,12 +471,15 @@ EXPORT_SYMBOL_GPL(snd_hda_get_input_pin_attr);
/**
* hda_get_input_pin_label - Give a label for the given input pin
+ * @codec: the HDA codec
+ * @item: ping config item to refer
+ * @pin: the pin NID
+ * @check_location: flag to add the jack location prefix
*
- * When check_location is true, the function checks the pin location
+ * When @check_location is true, the function checks the pin location
* for mic and line-in pins, and set an appropriate prefix like "Front",
* "Rear", "Internal".
*/
-
static const char *hda_get_input_pin_label(struct hda_codec *codec,
const struct auto_pin_cfg_item *item,
hda_nid_t pin, bool check_location)
@@ -550,6 +560,9 @@ static int check_mic_location_need(struct hda_codec *codec,
/**
* hda_get_autocfg_input_label - Get a label for the given input
+ * @codec: the HDA codec
+ * @cfg: the parsed pin configuration
+ * @input: the input index number
*
* Get a label for the given input pin defined by the autocfg item.
* Unlike hda_get_input_pin_label(), this function checks all inputs
@@ -677,6 +690,12 @@ static int fill_audio_out_name(struct hda_codec *codec, hda_nid_t nid,
/**
* snd_hda_get_pin_label - Get a label for the given I/O pin
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @cfg: the parsed pin configuration
+ * @label: the string buffer to store
+ * @maxlen: the max length of string buffer (including termination)
+ * @indexp: the pointer to return the index number (for multiple ctls)
*
* Get a label for the given pin. This function works for both input and
* output pins. When @cfg is given as non-NULL, the function tries to get
@@ -748,6 +767,14 @@ int snd_hda_get_pin_label(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_get_pin_label);
+/**
+ * snd_hda_add_verbs - Add verbs to the init list
+ * @codec: the HDA codec
+ * @list: zero-terminated verb list to add
+ *
+ * Append the given verb list to the execution list. The verbs will be
+ * performed at init and resume time via snd_hda_apply_verbs().
+ */
int snd_hda_add_verbs(struct hda_codec *codec,
const struct hda_verb *list)
{
@@ -760,6 +787,10 @@ int snd_hda_add_verbs(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_add_verbs);
+/**
+ * snd_hda_apply_verbs - Execute the init verb lists
+ * @codec: the HDA codec
+ */
void snd_hda_apply_verbs(struct hda_codec *codec)
{
int i;
@@ -770,6 +801,11 @@ void snd_hda_apply_verbs(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_apply_verbs);
+/**
+ * snd_hda_apply_pincfgs - Set each pin config in the given list
+ * @codec: the HDA codec
+ * @cfg: NULL-terminated pin config table
+ */
void snd_hda_apply_pincfgs(struct hda_codec *codec,
const struct hda_pintbl *cfg)
{
@@ -837,6 +873,11 @@ static void apply_fixup(struct hda_codec *codec, int id, int action, int depth)
}
}
+/**
+ * snd_hda_apply_fixup - Apply the fixup chain with the given action
+ * @codec: the HDA codec
+ * @action: fixup action (HDA_FIXUP_ACT_XXX)
+ */
void snd_hda_apply_fixup(struct hda_codec *codec, int action)
{
if (codec->fixup_list)
@@ -855,6 +896,12 @@ static bool pin_config_match(struct hda_codec *codec,
return true;
}
+/**
+ * snd_hda_pick_pin_fixup - Pick up a fixup matching with the pin quirk list
+ * @codec: the HDA codec
+ * @pin_quirk: zero-terminated pin quirk list
+ * @fixlist: the fixup list
+ */
void snd_hda_pick_pin_fixup(struct hda_codec *codec,
const struct snd_hda_pin_quirk *pin_quirk,
const struct hda_fixup *fixlist)
@@ -881,6 +928,21 @@ void snd_hda_pick_pin_fixup(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_pick_pin_fixup);
+/**
+ * snd_hda_pick_fixup - Pick up a fixup matching with PCI/codec SSID or model string
+ * @codec: the HDA codec
+ * @models: NULL-terminated model string list
+ * @quirk: zero-terminated PCI/codec SSID quirk list
+ * @fixlist: the fixup list
+ *
+ * Pick up a fixup entry matching with the given model string or SSID.
+ * If a fixup was already set beforehand, the function doesn't do anything.
+ * When a special model string "nofixup" is given, also no fixup is applied.
+ *
+ * The function tries to find the matching model name at first, if given.
+ * If nothing matched, try to look up the PCI SSID.
+ * If still nothing matched, try to look up the codec SSID.
+ */
void snd_hda_pick_fixup(struct hda_codec *codec,
const struct hda_model_fixup *models,
const struct snd_pci_quirk *quirk,
diff --git a/sound/pci/hda/hda_beep.c b/sound/pci/hda/hda_beep.c
index 8c6c50a..1e7de08 100644
--- a/sound/pci/hda/hda_beep.c
+++ b/sound/pci/hda/hda_beep.c
@@ -175,6 +175,11 @@ static int snd_hda_do_attach(struct hda_beep *beep)
return 0;
}
+/**
+ * snd_hda_enable_beep_device - Turn on/off beep sound
+ * @codec: the HDA codec
+ * @enable: flag to turn on/off
+ */
int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
{
struct hda_beep *beep = codec->beep;
@@ -191,6 +196,20 @@ int snd_hda_enable_beep_device(struct hda_codec *codec, int enable)
}
EXPORT_SYMBOL_GPL(snd_hda_enable_beep_device);
+/**
+ * snd_hda_attach_beep_device - Attach a beep input device
+ * @codec: the HDA codec
+ * @nid: beep NID
+ *
+ * Attach a beep object to the given widget. If beep hint is turned off
+ * explicitly or beep_mode of the codec is turned off, this doesn't nothing.
+ *
+ * The attached beep device has to be registered via
+ * snd_hda_register_beep_device() and released via snd_hda_detach_beep_device()
+ * appropriately.
+ *
+ * Currently, only one beep device is allowed to each codec.
+ */
int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
{
struct hda_beep *beep;
@@ -228,6 +247,10 @@ int snd_hda_attach_beep_device(struct hda_codec *codec, int nid)
}
EXPORT_SYMBOL_GPL(snd_hda_attach_beep_device);
+/**
+ * snd_hda_detach_beep_device - Detach the beep device
+ * @codec: the HDA codec
+ */
void snd_hda_detach_beep_device(struct hda_codec *codec)
{
struct hda_beep *beep = codec->beep;
@@ -240,6 +263,10 @@ void snd_hda_detach_beep_device(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_detach_beep_device);
+/**
+ * snd_hda_register_beep_device - Register the beep device
+ * @codec: the HDA codec
+ */
int snd_hda_register_beep_device(struct hda_codec *codec)
{
struct hda_beep *beep = codec->beep;
@@ -269,6 +296,12 @@ static bool ctl_has_mute(struct snd_kcontrol *kcontrol)
}
/* get/put callbacks for beep mute mixer switches */
+
+/**
+ * snd_hda_mixer_amp_switch_get_beep - Get callback for beep controls
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
+ */
int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
@@ -283,6 +316,11 @@ int snd_hda_mixer_amp_switch_get_beep(struct snd_kcontrol *kcontrol,
}
EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get_beep);
+/**
+ * snd_hda_mixer_amp_switch_put_beep - Put callback for beep controls
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
+ */
int snd_hda_mixer_amp_switch_put_beep(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c
index 15e0089..2fe86d2 100644
--- a/sound/pci/hda/hda_codec.c
+++ b/sound/pci/hda/hda_codec.c
@@ -77,6 +77,10 @@ static struct hda_vendor_id hda_vendor_ids[] = {
static DEFINE_MUTEX(preset_mutex);
static LIST_HEAD(hda_preset_tables);
+/**
+ * snd_hda_add_codec_preset - Add a codec preset to the chain
+ * @preset: codec preset table to add
+ */
int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
{
mutex_lock(&preset_mutex);
@@ -86,6 +90,10 @@ int snd_hda_add_codec_preset(struct hda_codec_preset_list *preset)
}
EXPORT_SYMBOL_GPL(snd_hda_add_codec_preset);
+/**
+ * snd_hda_delete_codec_preset - Delete a codec preset from the chain
+ * @preset: codec preset table to delete
+ */
int snd_hda_delete_codec_preset(struct hda_codec_preset_list *preset)
{
mutex_lock(&preset_mutex);
@@ -338,8 +346,10 @@ int snd_hda_get_sub_nodes(struct hda_codec *codec, hda_nid_t nid,
unsigned int parm;
parm = snd_hda_param_read(codec, nid, AC_PAR_NODE_COUNT);
- if (parm == -1)
+ if (parm == -1) {
+ *start_id = 0;
return 0;
+ }
*start_id = (parm >> 16) & 0x7fff;
return (int)(parm & 0x7fff);
}
@@ -416,7 +426,6 @@ static int read_and_add_raw_conns(struct hda_codec *codec, hda_nid_t nid)
* snd_hda_get_conn_list - get connection list
* @codec: the HDA codec
* @nid: NID to parse
- * @len: number of connection list entries
* @listp: the pointer to store NID list
*
* Parses the connection list of the given widget and stores the pointer
@@ -827,8 +836,7 @@ static void snd_hda_bus_free(struct hda_bus *bus)
WARN_ON(!list_empty(&bus->codec_list));
if (bus->workq)
flush_workqueue(bus->workq);
- if (bus->unsol)
- kfree(bus->unsol);
+ kfree(bus->unsol);
if (bus->ops.private_free)
bus->ops.private_free(bus);
if (bus->workq)
@@ -966,14 +974,12 @@ find_codec_preset(struct hda_codec *codec)
mutex_unlock(&preset_mutex);
if (mod_requested < HDA_MODREQ_MAX_COUNT) {
- char name[32];
if (!mod_requested)
- snprintf(name, sizeof(name), "snd-hda-codec-id:%08x",
- codec->vendor_id);
+ request_module("snd-hda-codec-id:%08x",
+ codec->vendor_id);
else
- snprintf(name, sizeof(name), "snd-hda-codec-id:%04x*",
- (codec->vendor_id >> 16) & 0xffff);
- request_module(name);
+ request_module("snd-hda-codec-id:%04x*",
+ (codec->vendor_id >> 16) & 0xffff);
mod_requested++;
goto again;
}
@@ -1190,7 +1196,16 @@ unsigned int snd_hda_codec_get_pincfg(struct hda_codec *codec, hda_nid_t nid)
}
EXPORT_SYMBOL_GPL(snd_hda_codec_get_pincfg);
-/* remember the current pinctl target value */
+/**
+ * snd_hda_codec_set_pin_target - remember the current pinctl target value
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @val: assigned pinctl value
+ *
+ * This function stores the given value to a pinctl target value in the
+ * pincfg table. This isn't always as same as the actually written value
+ * but can be referred at any time via snd_hda_codec_get_pin_target().
+ */
int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
unsigned int val)
{
@@ -1204,7 +1219,11 @@ int snd_hda_codec_set_pin_target(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_set_pin_target);
-/* return the current pinctl target value */
+/**
+ * snd_hda_codec_get_pin_target - return the current pinctl target value
+ * @codec: the HDA codec
+ * @nid: pin NID
+ */
int snd_hda_codec_get_pin_target(struct hda_codec *codec, hda_nid_t nid)
{
struct hda_pincfg *pin;
@@ -1576,6 +1595,13 @@ int snd_hda_codec_new(struct hda_bus *bus,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_new);
+/**
+ * snd_hda_codec_update_widgets - Refresh widget caps and pin defaults
+ * @codec: the HDA codec
+ *
+ * Forcibly refresh the all widget caps and the init pin configurations of
+ * the given codec.
+ */
int snd_hda_codec_update_widgets(struct hda_codec *codec)
{
hda_nid_t fg;
@@ -2006,6 +2032,7 @@ EXPORT_SYMBOL_GPL(query_amp_caps);
* @codec: the HD-audio codec
* @nid: the NID to query
* @dir: either #HDA_INPUT or #HDA_OUTPUT
+ * @bits: bit mask to check the result
*
* Check whether the widget has the given amp capability for the direction.
*/
@@ -2025,7 +2052,7 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_caps);
* snd_hda_override_amp_caps - Override the AMP capabilities
* @codec: the CODEC to clean up
* @nid: the NID to clean up
- * @direction: either #HDA_INPUT or #HDA_OUTPUT
+ * @dir: either #HDA_INPUT or #HDA_OUTPUT
* @caps: the capability bits to set
*
* Override the cached AMP caps bits value by the given one.
@@ -2241,7 +2268,17 @@ int snd_hda_codec_amp_stereo(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_amp_stereo);
-/* Works like snd_hda_codec_amp_update() but it writes the value only at
+/**
+ * snd_hda_codec_amp_init - initialize the AMP value
+ * @codec: the HDA codec
+ * @nid: NID to read the AMP value
+ * @ch: channel (left=0 or right=1)
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Works like snd_hda_codec_amp_update() but it writes the value only at
* the first access. If the amp was already initialized / updated beforehand,
* this does nothing.
*/
@@ -2252,6 +2289,17 @@ int snd_hda_codec_amp_init(struct hda_codec *codec, hda_nid_t nid, int ch,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_amp_init);
+/**
+ * snd_hda_codec_amp_init_stereo - initialize the stereo AMP value
+ * @codec: the HDA codec
+ * @nid: NID to read the AMP value
+ * @dir: #HDA_INPUT or #HDA_OUTPUT
+ * @idx: the index value (only for input direction)
+ * @mask: bit mask to set
+ * @val: the bits value to set
+ *
+ * Call snd_hda_codec_amp_init() for both stereo channels.
+ */
int snd_hda_codec_amp_init_stereo(struct hda_codec *codec, hda_nid_t nid,
int dir, int idx, int mask, int val)
{
@@ -2322,6 +2370,8 @@ static u32 get_amp_max_value(struct hda_codec *codec, hda_nid_t nid, int dir,
/**
* snd_hda_mixer_amp_volume_info - Info callback for a standard AMP mixer
+ * @kcontrol: referred ctl element
+ * @uinfo: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2383,6 +2433,8 @@ update_amp_value(struct hda_codec *codec, hda_nid_t nid,
/**
* snd_hda_mixer_amp_volume_get - Get callback for a standard AMP mixer volume
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2408,6 +2460,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_get);
/**
* snd_hda_mixer_amp_volume_put - Put callback for a standard AMP mixer volume
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2438,6 +2492,10 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_volume_put);
/**
* snd_hda_mixer_amp_volume_put - TLV callback for a standard AMP mixer volume
+ * @kcontrol: ctl element
+ * @op_flag: operation flag
+ * @size: byte size of input TLV
+ * @_tlv: TLV data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -2636,7 +2694,10 @@ void snd_hda_ctls_clear(struct hda_codec *codec)
snd_array_free(&codec->nids);
}
-/* pseudo device locking
+/**
+ * snd_hda_lock_devices - pseudo device locking
+ * @bus: the BUS
+ *
* toggle card->shutdown to allow/disallow the device access (as a hack)
*/
int snd_hda_lock_devices(struct hda_bus *bus)
@@ -2673,6 +2734,10 @@ int snd_hda_lock_devices(struct hda_bus *bus)
}
EXPORT_SYMBOL_GPL(snd_hda_lock_devices);
+/**
+ * snd_hda_unlock_devices - pseudo device unlocking
+ * @bus: the BUS
+ */
void snd_hda_unlock_devices(struct hda_bus *bus)
{
struct snd_card *card = bus->card;
@@ -2859,7 +2924,7 @@ static int add_slave(struct hda_codec *codec,
}
/**
- * snd_hda_add_vmaster - create a virtual master control and add slaves
+ * __snd_hda_add_vmaster - create a virtual master control and add slaves
* @codec: HD-audio codec
* @name: vmaster control name
* @tlv: TLV data (optional)
@@ -2927,16 +2992,8 @@ static int vmaster_mute_mode_info(struct snd_kcontrol *kcontrol,
static const char * const texts[] = {
"On", "Off", "Follow Master"
};
- unsigned int index;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- index = uinfo->value.enumerated.item;
- if (index >= 3)
- index = 2;
- strcpy(uinfo->value.enumerated.name, texts[index]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int vmaster_mute_mode_get(struct snd_kcontrol *kcontrol,
@@ -2970,10 +3027,15 @@ static struct snd_kcontrol_new vmaster_mute_mode = {
.put = vmaster_mute_mode_put,
};
-/*
- * Add a mute-LED hook with the given vmaster switch kctl
- * "Mute-LED Mode" control is automatically created and associated with
- * the given hook.
+/**
+ * snd_hda_add_vmaster_hook - Add a vmaster hook for mute-LED
+ * @codec: the HDA codec
+ * @hook: the vmaster hook object
+ * @expose_enum_ctl: flag to create an enum ctl
+ *
+ * Add a mute-LED hook with the given vmaster switch kctl.
+ * When @expose_enum_ctl is set, "Mute-LED Mode" control is automatically
+ * created and associated with the given hook.
*/
int snd_hda_add_vmaster_hook(struct hda_codec *codec,
struct hda_vmaster_mute_hook *hook,
@@ -2995,9 +3057,12 @@ int snd_hda_add_vmaster_hook(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_add_vmaster_hook);
-/*
- * Call the hook with the current value for synchronization
- * Should be called in init callback
+/**
+ * snd_hda_sync_vmaster_hook - Sync vmaster hook
+ * @hook: the vmaster hook
+ *
+ * Call the hook with the current value for synchronization.
+ * Should be called in init callback.
*/
void snd_hda_sync_vmaster_hook(struct hda_vmaster_mute_hook *hook)
{
@@ -3022,6 +3087,8 @@ EXPORT_SYMBOL_GPL(snd_hda_sync_vmaster_hook);
/**
* snd_hda_mixer_amp_switch_info - Info callback for a standard AMP mixer switch
+ * @kcontrol: referred ctl element
+ * @uinfo: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -3041,6 +3108,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_info);
/**
* snd_hda_mixer_amp_switch_get - Get callback for a standard AMP mixer switch
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -3067,6 +3136,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_get);
/**
* snd_hda_mixer_amp_switch_put - Put callback for a standard AMP mixer switch
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_COMPOSE_AMP_VAL*() or related macros.
@@ -3110,6 +3181,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_amp_switch_put);
/**
* snd_hda_mixer_bind_switch_get - Get callback for a bound volume control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_MUTE*() macros.
@@ -3133,6 +3206,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_get);
/**
* snd_hda_mixer_bind_switch_put - Put callback for a bound volume control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_MUTE*() macros.
@@ -3163,6 +3238,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_switch_put);
/**
* snd_hda_mixer_bind_ctls_info - Info callback for a generic bound control
+ * @kcontrol: referred ctl element
+ * @uinfo: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
@@ -3186,6 +3263,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_info);
/**
* snd_hda_mixer_bind_ctls_get - Get callback for a generic bound control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
@@ -3209,6 +3288,8 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_get);
/**
* snd_hda_mixer_bind_ctls_put - Put callback for a generic bound control
+ * @kcontrol: ctl element
+ * @ucontrol: pointer to get/store the data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() or HDA_BIND_SW() macros.
@@ -3238,6 +3319,10 @@ EXPORT_SYMBOL_GPL(snd_hda_mixer_bind_ctls_put);
/**
* snd_hda_mixer_bind_tlv - TLV callback for a generic bound control
+ * @kcontrol: ctl element
+ * @op_flag: operation flag
+ * @size: byte size of input TLV
+ * @tlv: TLV data
*
* The control element is supposed to have the private_value field
* set up via HDA_BIND_VOL() macro.
@@ -3579,7 +3664,11 @@ int snd_hda_create_dig_out_ctls(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls);
-/* get the hda_spdif_out entry from the given NID
+/**
+ * snd_hda_spdif_out_of_nid - get the hda_spdif_out entry from the given NID
+ * @codec: the HDA codec
+ * @nid: widget NID
+ *
* call within spdif_mutex lock
*/
struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
@@ -3596,6 +3685,13 @@ struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_spdif_out_of_nid);
+/**
+ * snd_hda_spdif_ctls_unassign - Unassign the given SPDIF ctl
+ * @codec: the HDA codec
+ * @idx: the SPDIF ctl index
+ *
+ * Unassign the widget from the given SPDIF control.
+ */
void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
{
struct hda_spdif_out *spdif;
@@ -3607,6 +3703,14 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx)
}
EXPORT_SYMBOL_GPL(snd_hda_spdif_ctls_unassign);
+/**
+ * snd_hda_spdif_ctls_assign - Assign the SPDIF controls to the given NID
+ * @codec: the HDA codec
+ * @idx: the SPDIF ctl idx
+ * @nid: widget NID
+ *
+ * Assign the widget to the SPDIF control with the given index.
+ */
void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid)
{
struct hda_spdif_out *spdif;
@@ -3926,6 +4030,16 @@ void snd_hda_codec_flush_cache(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_codec_flush_cache);
+/**
+ * snd_hda_codec_set_power_to_all - Set the power state to all widgets
+ * @codec: the HDA codec
+ * @fg: function group (not used now)
+ * @power_state: the power state to set (AC_PWRST_*)
+ *
+ * Set the given power state to all widgets that have the power control.
+ * If the codec has power_filter set, it evaluates the power state and
+ * filter out if it's unchanged as D3.
+ */
void snd_hda_codec_set_power_to_all(struct hda_codec *codec, hda_nid_t fg,
unsigned int power_state)
{
@@ -3990,7 +4104,15 @@ static unsigned int hda_sync_power_state(struct hda_codec *codec,
return state;
}
-/* don't power down the widget if it controls eapd and EAPD_BTLENABLE is set */
+/**
+ * snd_hda_codec_eapd_power_filter - A power filter callback for EAPD
+ * @codec: the HDA codec
+ * @nid: widget NID
+ * @power_state: power state to evalue
+ *
+ * Don't power down the widget if it controls eapd and EAPD_BTLENABLE is set.
+ * This can be used a codec power_filter callback.
+ */
unsigned int snd_hda_codec_eapd_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
@@ -4315,6 +4437,7 @@ static struct hda_rate_tbl rate_bits[] = {
* @channels: the number of channels
* @format: the PCM format (SNDRV_PCM_FORMAT_XXX)
* @maxbps: the max. bps
+ * @spdif_ctls: HD-audio SPDIF status bits (0 if irrelevant)
*
* Calculate the format bitset from the given rate, channels and th PCM format.
*
@@ -4650,6 +4773,17 @@ static int set_pcm_default_values(struct hda_codec *codec,
/*
* codec prepare/cleanup entries
*/
+/**
+ * snd_hda_codec_prepare - Prepare a stream
+ * @codec: the HDA codec
+ * @hinfo: PCM information
+ * @stream: stream tag to assign
+ * @format: format id to assign
+ * @substream: PCM substream to assign
+ *
+ * Calls the prepare callback set by the codec with the given arguments.
+ * Clean up the inactive streams when successful.
+ */
int snd_hda_codec_prepare(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
unsigned int stream,
@@ -4666,6 +4800,14 @@ int snd_hda_codec_prepare(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_codec_prepare);
+/**
+ * snd_hda_codec_cleanup - Prepare a stream
+ * @codec: the HDA codec
+ * @hinfo: PCM information
+ * @substream: PCM substream
+ *
+ * Calls the cleanup callback set by the codec with the given arguments.
+ */
void snd_hda_codec_cleanup(struct hda_codec *codec,
struct hda_pcm_stream *hinfo,
struct snd_pcm_substream *substream)
@@ -4990,6 +5132,7 @@ static void __snd_hda_power_down(struct hda_codec *codec)
* snd_hda_power_save - Power-up/down/sync the codec
* @codec: HD-audio codec
* @delta: the counter delta to change
+ * @d3wait: sync for D3 transition complete
*
* Change the power-up counter via @delta, and power up or down the hardware
* appropriately. For the power-down, queue to the delayed action.
@@ -5065,6 +5208,10 @@ EXPORT_SYMBOL_GPL(snd_hda_check_amp_list_power);
/**
* snd_hda_ch_mode_info - Info callback helper for the channel mode enum
+ * @codec: the HDA codec
+ * @uinfo: pointer to get/store the data
+ * @chmode: channel mode array
+ * @num_chmodes: channel mode array size
*/
int snd_hda_ch_mode_info(struct hda_codec *codec,
struct snd_ctl_elem_info *uinfo,
@@ -5084,6 +5231,11 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_info);
/**
* snd_hda_ch_mode_get - Get callback helper for the channel mode enum
+ * @codec: the HDA codec
+ * @ucontrol: pointer to get/store the data
+ * @chmode: channel mode array
+ * @num_chmodes: channel mode array size
+ * @max_channels: max number of channels
*/
int snd_hda_ch_mode_get(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol,
@@ -5105,6 +5257,11 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_get);
/**
* snd_hda_ch_mode_put - Put callback helper for the channel mode enum
+ * @codec: the HDA codec
+ * @ucontrol: pointer to get/store the data
+ * @chmode: channel mode array
+ * @num_chmodes: channel mode array size
+ * @max_channelsp: pointer to store the max channels
*/
int snd_hda_ch_mode_put(struct hda_codec *codec,
struct snd_ctl_elem_value *ucontrol,
@@ -5133,6 +5290,8 @@ EXPORT_SYMBOL_GPL(snd_hda_ch_mode_put);
/**
* snd_hda_input_mux_info_info - Info callback helper for the input-mux enum
+ * @imux: imux helper object
+ * @uinfo: pointer to get/store the data
*/
int snd_hda_input_mux_info(const struct hda_input_mux *imux,
struct snd_ctl_elem_info *uinfo)
@@ -5154,6 +5313,11 @@ EXPORT_SYMBOL_GPL(snd_hda_input_mux_info);
/**
* snd_hda_input_mux_info_put - Put callback helper for the input-mux enum
+ * @codec: the HDA codec
+ * @imux: imux helper object
+ * @ucontrol: pointer to get/store the data
+ * @nid: input mux NID
+ * @cur_val: pointer to get/store the current imux value
*/
int snd_hda_input_mux_put(struct hda_codec *codec,
const struct hda_input_mux *imux,
@@ -5178,7 +5342,13 @@ int snd_hda_input_mux_put(struct hda_codec *codec,
EXPORT_SYMBOL_GPL(snd_hda_input_mux_put);
-/*
+/**
+ * snd_hda_enum_helper_info - Helper for simple enum ctls
+ * @kcontrol: ctl element
+ * @uinfo: pointer to get/store the data
+ * @num_items: number of enum items
+ * @texts: enum item string array
+ *
* process kcontrol info callback of a simple string enum array
* when @num_items is 0 or @texts is NULL, assume a boolean enum array
*/
@@ -5195,14 +5365,7 @@ int snd_hda_enum_helper_info(struct snd_kcontrol *kcontrol,
texts = texts_default;
}
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = num_items;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
EXPORT_SYMBOL_GPL(snd_hda_enum_helper_info);
@@ -5274,6 +5437,8 @@ EXPORT_SYMBOL_GPL(snd_hda_bus_reboot_notify);
/**
* snd_hda_multi_out_dig_open - open the digital out in the exclusive mode
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_dig_open(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5290,6 +5455,11 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_open);
/**
* snd_hda_multi_out_dig_prepare - prepare the digital out stream
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
+ * @stream_tag: stream tag to assign
+ * @format: format id to assign
+ * @substream: PCM substream to assign
*/
int snd_hda_multi_out_dig_prepare(struct hda_codec *codec,
struct hda_multi_out *mout,
@@ -5306,6 +5476,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_prepare);
/**
* snd_hda_multi_out_dig_cleanup - clean-up the digital out stream
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_dig_cleanup(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5319,6 +5491,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_cleanup);
/**
* snd_hda_multi_out_dig_close - release the digital out stream
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_dig_close(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5332,6 +5506,10 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_dig_close);
/**
* snd_hda_multi_out_analog_open - open analog outputs
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
+ * @substream: PCM substream to assign
+ * @hinfo: PCM information to assign
*
* Open analog outputs and set up the hw-constraints.
* If the digital outputs can be opened as slave, open the digital
@@ -5382,6 +5560,11 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_open);
/**
* snd_hda_multi_out_analog_prepare - Preapre the analog outputs.
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
+ * @stream_tag: stream tag to assign
+ * @format: format id to assign
+ * @substream: PCM substream to assign
*
* Set up the i/o for analog out.
* When the digital out is available, copy the front out to digital out, too.
@@ -5459,6 +5642,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_prepare);
/**
* snd_hda_multi_out_analog_cleanup - clean up the setting for analog out
+ * @codec: the HDA codec
+ * @mout: hda_multi_out object
*/
int snd_hda_multi_out_analog_cleanup(struct hda_codec *codec,
struct hda_multi_out *mout)
@@ -5490,6 +5675,8 @@ EXPORT_SYMBOL_GPL(snd_hda_multi_out_analog_cleanup);
/**
* snd_hda_get_default_vref - Get the default (mic) VREF pin bits
+ * @codec: the HDA codec
+ * @pin: referred pin NID
*
* Guess the suitable VREF pin bits to be set as the pin-control value.
* Note: the function doesn't set the AC_PINCTL_IN_EN bit.
@@ -5515,7 +5702,12 @@ unsigned int snd_hda_get_default_vref(struct hda_codec *codec, hda_nid_t pin)
}
EXPORT_SYMBOL_GPL(snd_hda_get_default_vref);
-/* correct the pin ctl value for matching with the pin cap */
+/**
+ * snd_hda_correct_pin_ctl - correct the pin ctl value for matching with the pin cap
+ * @codec: the HDA codec
+ * @pin: referred pin NID
+ * @val: pin ctl value to audit
+ */
unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
hda_nid_t pin, unsigned int val)
{
@@ -5566,6 +5758,19 @@ unsigned int snd_hda_correct_pin_ctl(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_correct_pin_ctl);
+/**
+ * _snd_hda_pin_ctl - Helper to set pin ctl value
+ * @codec: the HDA codec
+ * @pin: referred pin NID
+ * @val: pin control value to set
+ * @cached: access over codec pinctl cache or direct write
+ *
+ * This function is a helper to set a pin ctl value more safely.
+ * It corrects the pin ctl value via snd_hda_correct_pin_ctl(), stores the
+ * value in pin target array via snd_hda_codec_set_pin_target(), then
+ * actually writes the value via either snd_hda_codec_update_cache() or
+ * snd_hda_codec_write() depending on @cached flag.
+ */
int _snd_hda_set_pin_ctl(struct hda_codec *codec, hda_nid_t pin,
unsigned int val, bool cached)
{
@@ -5582,6 +5787,11 @@ EXPORT_SYMBOL_GPL(_snd_hda_set_pin_ctl);
/**
* snd_hda_add_imux_item - Add an item to input_mux
+ * @codec: the HDA codec
+ * @imux: imux helper object
+ * @label: the name of imux item to assign
+ * @index: index number of imux item to assign
+ * @type_idx: pointer to store the resultant label index
*
* When the same label is used already in the existing items, the number
* suffix is appended to the label. This label index number is stored
diff --git a/sound/pci/hda/hda_eld.c b/sound/pci/hda/hda_eld.c
index e1cd34d..0e6d753 100644
--- a/sound/pci/hda/hda_eld.c
+++ b/sound/pci/hda/hda_eld.c
@@ -371,7 +371,7 @@ error:
return ret;
}
-/**
+/*
* SNDRV_PCM_RATE_* and AC_PAR_PCM values don't match, print correct rates with
* hdmi-specific routine.
*/
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c
index 64220c0..63b69f7 100644
--- a/sound/pci/hda/hda_generic.c
+++ b/sound/pci/hda/hda_generic.c
@@ -40,7 +40,12 @@
#include "hda_generic.h"
-/* initialize hda_gen_spec struct */
+/**
+ * snd_hda_gen_spec_init - initialize hda_gen_spec struct
+ * @spec: hda_gen_spec object to initialize
+ *
+ * Initialize the given hda_gen_spec object.
+ */
int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
{
snd_array_init(&spec->kctls, sizeof(struct snd_kcontrol_new), 32);
@@ -51,6 +56,17 @@ int snd_hda_gen_spec_init(struct hda_gen_spec *spec)
}
EXPORT_SYMBOL_GPL(snd_hda_gen_spec_init);
+/**
+ * snd_hda_gen_add_kctl - Add a new kctl_new struct from the template
+ * @spec: hda_gen_spec object
+ * @name: name string to override the template, NULL if unchanged
+ * @temp: template for the new kctl
+ *
+ * Add a new kctl (actually snd_kcontrol_new to be instantiated later)
+ * element based on the given snd_kcontrol_new template @temp and the
+ * name string @name to the list in @spec.
+ * Returns the newly created object or NULL as error.
+ */
struct snd_kcontrol_new *
snd_hda_gen_add_kctl(struct hda_gen_spec *spec, const char *name,
const struct snd_kcontrol_new *temp)
@@ -259,8 +275,14 @@ static struct nid_path *get_nid_path(struct hda_codec *codec,
return NULL;
}
-/* get the path between the given NIDs;
- * passing 0 to either @pin or @dac behaves as a wildcard
+/**
+ * snd_hda_get_nid_path - get the path between the given NIDs
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ *
+ * Return the found nid_path object or NULL for error.
+ * Passing 0 to either @from_nid or @to_nid behaves as a wildcard.
*/
struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
hda_nid_t from_nid, hda_nid_t to_nid)
@@ -269,8 +291,14 @@ struct nid_path *snd_hda_get_nid_path(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_get_nid_path);
-/* get the index number corresponding to the path instance;
- * the index starts from 1, for easier checking the invalid value
+/**
+ * snd_hda_get_path_idx - get the index number corresponding to the path
+ * instance
+ * @codec: the HDA codec
+ * @path: nid_path object
+ *
+ * The returned index starts from 1, i.e. the actual array index with offset 1,
+ * and zero is handled as an invalid path
*/
int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
{
@@ -287,7 +315,12 @@ int snd_hda_get_path_idx(struct hda_codec *codec, struct nid_path *path)
}
EXPORT_SYMBOL_GPL(snd_hda_get_path_idx);
-/* get the path instance corresponding to the given index number */
+/**
+ * snd_hda_get_path_from_idx - get the path instance corresponding to the
+ * given index number
+ * @codec: the HDA codec
+ * @idx: the path index
+ */
struct nid_path *snd_hda_get_path_from_idx(struct hda_codec *codec, int idx)
{
struct hda_gen_spec *spec = codec->spec;
@@ -415,7 +448,18 @@ static bool __parse_nid_path(struct hda_codec *codec,
return true;
}
-/* parse the widget path from the given nid to the target nid;
+/**
+ * snd_hda_parse_nid_path - parse the widget path from the given nid to
+ * the target nid
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ * @anchor_nid: the anchor indication
+ * @path: the path object to store the result
+ *
+ * Returns true if a matching path is found.
+ *
+ * The parsing behavior depends on parameters:
* when @from_nid is 0, try to find an empty DAC;
* when @anchor_nid is set to a positive value, only paths through the widget
* with the given value are evaluated.
@@ -436,9 +480,15 @@ bool snd_hda_parse_nid_path(struct hda_codec *codec, hda_nid_t from_nid,
}
EXPORT_SYMBOL_GPL(snd_hda_parse_nid_path);
-/*
- * parse the path between the given NIDs and add to the path list.
- * if no valid path is found, return NULL
+/**
+ * snd_hda_add_new_path - parse the path between the given NIDs and
+ * add to the path list
+ * @codec: the HDA codec
+ * @from_nid: the NID where the path start from
+ * @to_nid: the NID where the path ends at
+ * @anchor_nid: the anchor indication, see snd_hda_parse_nid_path()
+ *
+ * If no valid path is found, returns NULL.
*/
struct nid_path *
snd_hda_add_new_path(struct hda_codec *codec, hda_nid_t from_nid,
@@ -724,8 +774,14 @@ static void activate_amp_in(struct hda_codec *codec, struct nid_path *path,
}
}
-/* activate or deactivate the given path
- * if @add_aamix is set, enable the input from aa-mix NID as well (if any)
+/**
+ * snd_hda_activate_path - activate or deactivate the given path
+ * @codec: the HDA codec
+ * @path: the path to activate/deactivate
+ * @enable: flag to activate or not
+ * @add_aamix: enable the input from aamix NID
+ *
+ * If @add_aamix is set, enable the input from aa-mix NID as well (if any).
*/
void snd_hda_activate_path(struct hda_codec *codec, struct nid_path *path,
bool enable, bool add_aamix)
@@ -1038,11 +1094,24 @@ static const char *get_line_out_pfx(struct hda_codec *codec, int ch,
break;
*index = ch;
return "Headphone";
+ case AUTO_PIN_LINE_OUT:
+ /* This deals with the case where we have two DACs and
+ * one LO, one HP and one Speaker */
+ if (!ch && cfg->speaker_outs && cfg->hp_outs) {
+ bool hp_lo_shared = !path_has_mixer(codec, spec->hp_paths[0], ctl_type);
+ bool spk_lo_shared = !path_has_mixer(codec, spec->speaker_paths[0], ctl_type);
+ if (hp_lo_shared && spk_lo_shared)
+ return spec->vmaster_mute.hook ? "PCM" : "Master";
+ if (hp_lo_shared)
+ return "Headphone+LO";
+ if (spk_lo_shared)
+ return "Speaker+LO";
+ }
}
/* for a single channel output, we don't have to name the channel */
if (cfg->line_outs == 1 && !spec->multi_ios)
- return "PCM";
+ return "Line Out";
if (ch >= ARRAY_SIZE(channel_name)) {
snd_BUG();
@@ -3870,7 +3939,12 @@ static void do_automute(struct hda_codec *codec, int num_pins, hda_nid_t *pins,
}
}
-/* Toggle outputs muting */
+/**
+ * snd_hda_gen_update_outputs - Toggle outputs muting
+ * @codec: the HDA codec
+ *
+ * Update the mute status of all outputs based on the current jack states.
+ */
void snd_hda_gen_update_outputs(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
@@ -3931,7 +4005,11 @@ static void call_update_outputs(struct hda_codec *codec)
snd_ctl_sync_vmaster(spec->vmaster_mute.sw_kctl, false);
}
-/* standard HP-automute helper */
+/**
+ * snd_hda_gen_hp_automute - standard HP-automute helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
void snd_hda_gen_hp_automute(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@@ -3952,7 +4030,11 @@ void snd_hda_gen_hp_automute(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_gen_hp_automute);
-/* standard line-out-automute helper */
+/**
+ * snd_hda_gen_line_automute - standard line-out-automute helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
void snd_hda_gen_line_automute(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@@ -3973,7 +4055,11 @@ void snd_hda_gen_line_automute(struct hda_codec *codec,
}
EXPORT_SYMBOL_GPL(snd_hda_gen_line_automute);
-/* standard mic auto-switch helper */
+/**
+ * snd_hda_gen_mic_autoswitch - standard mic auto-switch helper
+ * @codec: the HDA codec
+ * @jack: jack object, NULL for the whole
+ */
void snd_hda_gen_mic_autoswitch(struct hda_codec *codec,
struct hda_jack_callback *jack)
{
@@ -4305,7 +4391,13 @@ static int check_auto_mic_availability(struct hda_codec *codec)
return 0;
}
-/* power_filter hook; make inactive widgets into power down */
+/**
+ * snd_hda_gen_path_power_filter - power_filter hook to make inactive widgets
+ * into power down
+ * @codec: the HDA codec
+ * @nid: NID to evalute
+ * @power_state: target power state
+ */
unsigned int snd_hda_gen_path_power_filter(struct hda_codec *codec,
hda_nid_t nid,
unsigned int power_state)
@@ -4341,8 +4433,11 @@ static void mute_all_mixer_nid(struct hda_codec *codec, hda_nid_t mix)
}
}
-/*
- * Parse the given BIOS configuration and set up the hda_gen_spec
+/**
+ * snd_hda_gen_parse_auto_config - Parse the given BIOS configuration and
+ * set up the hda_gen_spec
+ * @codec: the HDA codec
+ * @cfg: Parsed pin configuration
*
* return 1 if successful, 0 if the proper config is not found,
* or a negative error code
@@ -4524,10 +4619,16 @@ static const char * const slave_pfxs[] = {
"CLFE", "Bass Speaker", "PCM",
"Speaker Front", "Speaker Surround", "Speaker CLFE", "Speaker Side",
"Headphone Front", "Headphone Surround", "Headphone CLFE",
- "Headphone Side",
+ "Headphone Side", "Headphone+LO", "Speaker+LO",
NULL,
};
+/**
+ * snd_hda_gen_build_controls - Build controls from the parsed results
+ * @codec: the HDA codec
+ *
+ * Pass this to build_controls patch_ops.
+ */
int snd_hda_gen_build_controls(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
@@ -5005,7 +5106,12 @@ static void fill_pcm_stream_name(char *str, size_t len, const char *sfx,
strlcat(str, sfx, len);
}
-/* build PCM streams based on the parsed results */
+/**
+ * snd_hda_gen_build_pcms - build PCM streams based on the parsed results
+ * @codec: the HDA codec
+ *
+ * Pass this to build_pcms patch_ops.
+ */
int snd_hda_gen_build_pcms(struct hda_codec *codec)
{
struct hda_gen_spec *spec = codec->spec;
@@ -5300,9 +5406,11 @@ static void clear_unsol_on_unused_pins(struct hda_codec *codec)
}
}
-/*
- * initialize the generic spec;
- * this can be put as patch_ops.init function
+/**
+ * snd_hda_gen_init - initialize the generic spec
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops init function.
*/
int snd_hda_gen_init(struct hda_codec *codec)
{
@@ -5338,9 +5446,11 @@ int snd_hda_gen_init(struct hda_codec *codec)
}
EXPORT_SYMBOL_GPL(snd_hda_gen_init);
-/*
- * free the generic spec;
- * this can be put as patch_ops.free function
+/**
+ * snd_hda_gen_free - free the generic spec
+ * @codec: the HDA codec
+ *
+ * This can be put as patch_ops free function.
*/
void snd_hda_gen_free(struct hda_codec *codec)
{
@@ -5352,9 +5462,12 @@ void snd_hda_gen_free(struct hda_codec *codec)
EXPORT_SYMBOL_GPL(snd_hda_gen_free);
#ifdef CONFIG_PM
-/*
- * check the loopback power save state;
- * this can be put as patch_ops.check_power_status function
+/**
+ * snd_hda_gen_check_power_status - check the loopback power save state
+ * @codec: the HDA codec
+ * @nid: NID to inspect
+ *
+ * This can be put as patch_ops check_power_status function.
*/
int snd_hda_gen_check_power_status(struct hda_codec *codec, hda_nid_t nid)
{
@@ -5380,6 +5493,12 @@ static const struct hda_codec_ops generic_patch_ops = {
#endif
};
+/**
+ * snd_hda_parse_generic_codec - Generic codec parser
+ * @codec: the HDA codec
+ *
+ * This should be called from the HDA codec core.
+ */
int snd_hda_parse_generic_codec(struct hda_codec *codec)
{
struct hda_gen_spec *spec;
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c
index 48b6c5a..5ac0d39 100644
--- a/sound/pci/hda/hda_intel.c
+++ b/sound/pci/hda/hda_intel.c
@@ -196,8 +196,8 @@ MODULE_PARM_DESC(align_buffer_size,
"Force buffer and period sizes to be multiple of 128 bytes.");
#ifdef CONFIG_X86
-static bool hda_snoop = true;
-module_param_named(snoop, hda_snoop, bool, 0444);
+static int hda_snoop = -1;
+module_param_named(snoop, hda_snoop, bint, 0444);
MODULE_PARM_DESC(snoop, "Enable/disable snooping");
#else
#define hda_snoop true
@@ -272,43 +272,56 @@ enum {
AZX_NUM_DRIVERS, /* keep this as last entry */
};
+#define azx_get_snoop_type(chip) \
+ (((chip)->driver_caps & AZX_DCAPS_SNOOP_MASK) >> 10)
+#define AZX_DCAPS_SNOOP_TYPE(type) ((AZX_SNOOP_TYPE_ ## type) << 10)
+
+/* quirks for old Intel chipsets */
+#define AZX_DCAPS_INTEL_ICH \
+ (AZX_DCAPS_OLD_SSYNC | AZX_DCAPS_NO_ALIGN_BUFSIZE)
+
/* quirks for Intel PCH */
#define AZX_DCAPS_INTEL_PCH_NOPM \
- (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_BUFSIZE | \
- AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_REVERSE_ASSIGN)
+ (AZX_DCAPS_NO_ALIGN_BUFSIZE | AZX_DCAPS_COUNT_LPIB_DELAY |\
+ AZX_DCAPS_REVERSE_ASSIGN | AZX_DCAPS_SNOOP_TYPE(SCH))
#define AZX_DCAPS_INTEL_PCH \
(AZX_DCAPS_INTEL_PCH_NOPM | AZX_DCAPS_PM_RUNTIME)
#define AZX_DCAPS_INTEL_HASWELL \
- (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \
- AZX_DCAPS_COUNT_LPIB_DELAY | AZX_DCAPS_PM_RUNTIME | \
- AZX_DCAPS_I915_POWERWELL)
+ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_COUNT_LPIB_DELAY |\
+ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
+ AZX_DCAPS_SNOOP_TYPE(SCH))
/* Broadwell HDMI can't use position buffer reliably, force to use LPIB */
#define AZX_DCAPS_INTEL_BROADWELL \
- (AZX_DCAPS_SCH_SNOOP | AZX_DCAPS_ALIGN_BUFSIZE | \
- AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_PM_RUNTIME | \
- AZX_DCAPS_I915_POWERWELL)
+ (/*AZX_DCAPS_ALIGN_BUFSIZE |*/ AZX_DCAPS_POSFIX_LPIB |\
+ AZX_DCAPS_PM_RUNTIME | AZX_DCAPS_I915_POWERWELL |\
+ AZX_DCAPS_SNOOP_TYPE(SCH))
/* quirks for ATI SB / AMD Hudson */
#define AZX_DCAPS_PRESET_ATI_SB \
- (AZX_DCAPS_ATI_SNOOP | AZX_DCAPS_NO_TCSEL | \
- AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB)
+ (AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB |\
+ AZX_DCAPS_SNOOP_TYPE(ATI))
/* quirks for ATI/AMD HDMI */
#define AZX_DCAPS_PRESET_ATI_HDMI \
(AZX_DCAPS_NO_TCSEL | AZX_DCAPS_SYNC_WRITE | AZX_DCAPS_POSFIX_LPIB|\
AZX_DCAPS_NO_MSI64)
+/* quirks for ATI HDMI with snoop off */
+#define AZX_DCAPS_PRESET_ATI_HDMI_NS \
+ (AZX_DCAPS_PRESET_ATI_HDMI | AZX_DCAPS_SNOOP_OFF)
+
/* quirks for Nvidia */
#define AZX_DCAPS_PRESET_NVIDIA \
- (AZX_DCAPS_NVIDIA_SNOOP | AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI |\
- AZX_DCAPS_ALIGN_BUFSIZE | AZX_DCAPS_NO_64BIT |\
- AZX_DCAPS_CORBRP_SELF_CLEAR)
+ (AZX_DCAPS_RIRB_DELAY | AZX_DCAPS_NO_MSI | /*AZX_DCAPS_ALIGN_BUFSIZE |*/ \
+ AZX_DCAPS_NO_64BIT | AZX_DCAPS_CORBRP_SELF_CLEAR |\
+ AZX_DCAPS_SNOOP_TYPE(NVIDIA))
#define AZX_DCAPS_PRESET_CTHDA \
- (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_4K_BDLE_BOUNDARY)
+ (AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB |\
+ AZX_DCAPS_4K_BDLE_BOUNDARY | AZX_DCAPS_SNOOP_OFF)
/*
* VGA-switcher support
@@ -437,6 +450,8 @@ static void update_pci_byte(struct pci_dev *pci, unsigned int reg,
static void azx_init_pci(struct azx *chip)
{
+ int snoop_type = azx_get_snoop_type(chip);
+
/* Clear bits 0-2 of PCI register TCSEL (at offset 0x44)
* TCSEL == Traffic Class Select Register, which sets PCI express QOS
* Ensuring these bits are 0 clears playback static on some HD Audio
@@ -451,7 +466,7 @@ static void azx_init_pci(struct azx *chip)
/* For ATI SB450/600/700/800/900 and AMD Hudson azalia HD audio,
* we need to enable snoop.
*/
- if (chip->driver_caps & AZX_DCAPS_ATI_SNOOP) {
+ if (snoop_type == AZX_SNOOP_TYPE_ATI) {
dev_dbg(chip->card->dev, "Setting ATI snoop: %d\n",
azx_snoop(chip));
update_pci_byte(chip->pci,
@@ -460,7 +475,7 @@ static void azx_init_pci(struct azx *chip)
}
/* For NVIDIA HDA, enable snoop */
- if (chip->driver_caps & AZX_DCAPS_NVIDIA_SNOOP) {
+ if (snoop_type == AZX_SNOOP_TYPE_NVIDIA) {
dev_dbg(chip->card->dev, "Setting Nvidia snoop: %d\n",
azx_snoop(chip));
update_pci_byte(chip->pci,
@@ -475,7 +490,7 @@ static void azx_init_pci(struct azx *chip)
}
/* Enable SCH/PCH snoop if needed */
- if (chip->driver_caps & AZX_DCAPS_SCH_SNOOP) {
+ if (snoop_type == AZX_SNOOP_TYPE_SCH) {
unsigned short snoop;
pci_read_config_word(chip->pci, INTEL_SCH_HDA_DEVC, &snoop);
if ((!azx_snoop(chip) && !(snoop & INTEL_SCH_HDA_DEVC_NOSNOOP)) ||
@@ -1132,8 +1147,7 @@ static int azx_free(struct azx *chip)
pci_disable_device(chip->pci);
kfree(chip->azx_dev);
#ifdef CONFIG_SND_HDA_PATCH_LOADER
- if (chip->fw)
- release_firmware(chip->fw);
+ release_firmware(chip->fw);
#endif
if (chip->driver_caps & AZX_DCAPS_I915_POWERWELL) {
hda_display_power(false);
@@ -1361,35 +1375,33 @@ static void check_msi(struct azx *chip)
/* check the snoop mode availability */
static void azx_check_snoop_available(struct azx *chip)
{
- bool snoop = chip->snoop;
+ int snoop = hda_snoop;
- switch (chip->driver_type) {
- case AZX_DRIVER_VIA:
+ if (snoop >= 0) {
+ dev_info(chip->card->dev, "Force to %s mode by module option\n",
+ snoop ? "snoop" : "non-snoop");
+ chip->snoop = snoop;
+ return;
+ }
+
+ snoop = true;
+ if (azx_get_snoop_type(chip) == AZX_SNOOP_TYPE_NONE &&
+ chip->driver_type == AZX_DRIVER_VIA) {
/* force to non-snoop mode for a new VIA controller
* when BIOS is set
*/
- if (snoop) {
- u8 val;
- pci_read_config_byte(chip->pci, 0x42, &val);
- if (!(val & 0x80) && chip->pci->revision == 0x30)
- snoop = false;
- }
- break;
- case AZX_DRIVER_ATIHDMI_NS:
- /* new ATI HDMI requires non-snoop */
- snoop = false;
- break;
- case AZX_DRIVER_CTHDA:
- case AZX_DRIVER_CMEDIA:
- snoop = false;
- break;
+ u8 val;
+ pci_read_config_byte(chip->pci, 0x42, &val);
+ if (!(val & 0x80) && chip->pci->revision == 0x30)
+ snoop = false;
}
- if (snoop != chip->snoop) {
- dev_info(chip->card->dev, "Force to %s mode\n",
- snoop ? "snoop" : "non-snoop");
- chip->snoop = snoop;
- }
+ if (chip->driver_caps & AZX_DCAPS_SNOOP_OFF)
+ snoop = false;
+
+ chip->snoop = snoop;
+ if (!snoop)
+ dev_info(chip->card->dev, "Force to non-snoop mode\n");
}
static void azx_probe_work(struct work_struct *work)
@@ -1449,7 +1461,6 @@ static int azx_create(struct snd_card *card, struct pci_dev *pci,
check_probe_mask(chip, dev);
chip->single_cmd = single_cmd;
- chip->snoop = hda_snoop;
azx_check_snoop_available(chip);
if (bdl_pos_adj[dev] < 0) {
@@ -1557,10 +1568,8 @@ static int azx_first_init(struct azx *chip)
if (align_buffer_size >= 0)
chip->align_buffer_size = !!align_buffer_size;
else {
- if (chip->driver_caps & AZX_DCAPS_BUFSIZE)
+ if (chip->driver_caps & AZX_DCAPS_NO_ALIGN_BUFSIZE)
chip->align_buffer_size = 0;
- else if (chip->driver_caps & AZX_DCAPS_ALIGN_BUFSIZE)
- chip->align_buffer_size = 1;
else
chip->align_buffer_size = 1;
}
@@ -2047,36 +2056,35 @@ static const struct pci_device_id azx_ids[] = {
/* Braswell */
{ PCI_DEVICE(0x8086, 0x2284),
.driver_data = AZX_DRIVER_PCH | AZX_DCAPS_INTEL_PCH },
- /* ICH */
+ /* ICH6 */
{ PCI_DEVICE(0x8086, 0x2668),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH6 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH7 */
{ PCI_DEVICE(0x8086, 0x27d8),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH7 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ESB2 */
{ PCI_DEVICE(0x8086, 0x269a),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ESB2 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH8 */
{ PCI_DEVICE(0x8086, 0x284b),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH8 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH9 */
{ PCI_DEVICE(0x8086, 0x293e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH9 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH9 */
{ PCI_DEVICE(0x8086, 0x293f),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH9 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH10 */
{ PCI_DEVICE(0x8086, 0x3a3e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH10 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
+ /* ICH10 */
{ PCI_DEVICE(0x8086, 0x3a6e),
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_OLD_SSYNC |
- AZX_DCAPS_BUFSIZE }, /* ICH10 */
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_INTEL_ICH },
/* Generic Intel */
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_ANY_ID),
.class = PCI_CLASS_MULTIMEDIA_HD_AUDIO << 8,
.class_mask = 0xffffff,
- .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_BUFSIZE },
+ .driver_data = AZX_DRIVER_ICH | AZX_DCAPS_NO_ALIGN_BUFSIZE },
/* ATI SB 450/600/700/800/900 */
{ PCI_DEVICE(0x1002, 0x437b),
.driver_data = AZX_DRIVER_ATI | AZX_DCAPS_PRESET_ATI_SB },
@@ -2131,13 +2139,13 @@ static const struct pci_device_id azx_ids[] = {
{ PCI_DEVICE(0x1002, 0xaa98),
.driver_data = AZX_DRIVER_ATIHDMI | AZX_DCAPS_PRESET_ATI_HDMI },
{ PCI_DEVICE(0x1002, 0x9902),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaaa0),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaaa8),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
{ PCI_DEVICE(0x1002, 0xaab0),
- .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI },
+ .driver_data = AZX_DRIVER_ATIHDMI_NS | AZX_DCAPS_PRESET_ATI_HDMI_NS },
/* VIA VT8251/VT8237A */
{ PCI_DEVICE(0x1106, 0x3288),
.driver_data = AZX_DRIVER_VIA | AZX_DCAPS_POSFIX_VIA },
@@ -2184,7 +2192,7 @@ static const struct pci_device_id azx_ids[] = {
/* CM8888 */
{ PCI_DEVICE(0x13f6, 0x5011),
.driver_data = AZX_DRIVER_CMEDIA |
- AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB },
+ AZX_DCAPS_NO_MSI | AZX_DCAPS_POSFIX_LPIB | AZX_DCAPS_SNOOP_OFF },
/* Vortex86MX */
{ PCI_DEVICE(0x17f3, 0x3010), .driver_data = AZX_DRIVER_GENERIC },
/* VMware HDAudio */
diff --git a/sound/pci/hda/hda_jack.c b/sound/pci/hda/hda_jack.c
index f56765a..e664307 100644
--- a/sound/pci/hda/hda_jack.c
+++ b/sound/pci/hda/hda_jack.c
@@ -20,6 +20,16 @@
#include "hda_auto_parser.h"
#include "hda_jack.h"
+/**
+ * is_jack_detectable - Check whether the given pin is jack-detectable
+ * @codec: the HDA codec
+ * @nid: pin NID
+ *
+ * Check whether the given pin is capable to report the jack detection.
+ * The jack detection might not work by various reasons, e.g. the jack
+ * detection is prohibited in the codec level, the pin config has
+ * AC_DEFCFG_MISC_NO_PRESENCE bit, no unsol support, etc.
+ */
bool is_jack_detectable(struct hda_codec *codec, hda_nid_t nid)
{
if (codec->no_jack_detect)
@@ -57,6 +67,8 @@ static u32 read_pin_sense(struct hda_codec *codec, hda_nid_t nid)
/**
* snd_hda_jack_tbl_get - query the jack-table entry for the given NID
+ * @codec: the HDA codec
+ * @nid: pin NID to refer to
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_get(struct hda_codec *codec, hda_nid_t nid)
@@ -75,6 +87,8 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get);
/**
* snd_hda_jack_tbl_get_from_tag - query the jack-table entry for the given tag
+ * @codec: the HDA codec
+ * @tag: tag value to refer to
*/
struct hda_jack_tbl *
snd_hda_jack_tbl_get_from_tag(struct hda_codec *codec, unsigned char tag)
@@ -93,6 +107,8 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_tbl_get_from_tag);
/**
* snd_hda_jack_tbl_new - create a jack-table entry for the given NID
+ * @codec: the HDA codec
+ * @nid: pin NID to assign
*/
static struct hda_jack_tbl *
snd_hda_jack_tbl_new(struct hda_codec *codec, hda_nid_t nid)
@@ -162,6 +178,7 @@ static void jack_detect_update(struct hda_codec *codec,
/**
* snd_hda_set_dirty_all - Mark all the cached as dirty
+ * @codec: the HDA codec
*
* This function sets the dirty flag to all entries of jack table.
* It's called from the resume path in hda_codec.c.
@@ -218,6 +235,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_state);
/**
* snd_hda_jack_detect_enable - enable the jack-detection
+ * @codec: the HDA codec
+ * @nid: pin NID to enable
+ * @func: callback function to register
*
* In the case of error, the return value will be a pointer embedded with
* errno. Check and handle the return value appropriately with standard
@@ -258,6 +278,14 @@ snd_hda_jack_detect_enable_callback(struct hda_codec *codec, hda_nid_t nid,
}
EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable_callback);
+/**
+ * snd_hda_jack_detect_enable - Enable the jack detection on the given pin
+ * @codec: the HDA codec
+ * @nid: pin NID to enable jack detection
+ *
+ * Enable the jack detection with the default callback. Returns zero if
+ * successful or a negative error code.
+ */
int snd_hda_jack_detect_enable(struct hda_codec *codec, hda_nid_t nid)
{
return PTR_ERR_OR_ZERO(snd_hda_jack_detect_enable_callback(codec, nid, NULL));
@@ -266,6 +294,9 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_detect_enable);
/**
* snd_hda_jack_set_gating_jack - Set gating jack.
+ * @codec: the HDA codec
+ * @gated_nid: gated pin NID
+ * @gating_nid: gating pin NID
*
* Indicates the gated jack is only valid when the gating jack is plugged.
*/
@@ -287,6 +318,7 @@ EXPORT_SYMBOL_GPL(snd_hda_jack_set_gating_jack);
/**
* snd_hda_jack_report_sync - sync the states of all jacks and report if changed
+ * @codec: the HDA codec
*/
void snd_hda_jack_report_sync(struct hda_codec *codec)
{
@@ -349,6 +381,11 @@ static void hda_free_jack_priv(struct snd_jack *jack)
/**
* snd_hda_jack_add_kctl - Add a kctl for the given pin
+ * @codec: the HDA codec
+ * @nid: pin NID to assign
+ * @name: string name for the jack
+ * @idx: index number for the jack
+ * @phantom_jack: flag to deal as a phantom jack
*
* This assigns a jack-detection kctl to the given pin. The kcontrol
* will have the given name and index.
@@ -391,6 +428,15 @@ static int __snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
return 0;
}
+/**
+ * snd_hda_jack_add_kctl - Add a jack kctl for the given pin
+ * @codec: the HDA codec
+ * @nid: pin NID
+ * @name: the name string for the jack ctl
+ * @idx: the ctl index for the jack ctl
+ *
+ * This is a simple helper calling __snd_hda_jack_add_kctl().
+ */
int snd_hda_jack_add_kctl(struct hda_codec *codec, hda_nid_t nid,
const char *name, int idx)
{
@@ -456,6 +502,8 @@ static int add_jack_kctl(struct hda_codec *codec, hda_nid_t nid,
/**
* snd_hda_jack_add_kctls - Add kctls for all pins included in the given pincfg
+ * @codec: the HDA codec
+ * @cfg: pin config table to parse
*/
int snd_hda_jack_add_kctls(struct hda_codec *codec,
const struct auto_pin_cfg *cfg)
@@ -531,6 +579,11 @@ static void call_jack_callback(struct hda_codec *codec,
}
}
+/**
+ * snd_hda_jack_unsol_event - Handle an unsolicited event
+ * @codec: the HDA codec
+ * @res: the unsolicited event data
+ */
void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
{
struct hda_jack_tbl *event;
@@ -546,6 +599,13 @@ void snd_hda_jack_unsol_event(struct hda_codec *codec, unsigned int res)
}
EXPORT_SYMBOL_GPL(snd_hda_jack_unsol_event);
+/**
+ * snd_hda_jack_poll_all - Poll all jacks
+ * @codec: the HDA codec
+ *
+ * Poll all detectable jacks with dirty flag, update the status, call
+ * callbacks and call snd_hda_jack_report_sync() if any changes are found.
+ */
void snd_hda_jack_poll_all(struct hda_codec *codec)
{
struct hda_jack_tbl *jack = codec->jacktbl.list;
diff --git a/sound/pci/hda/hda_jack.h b/sound/pci/hda/hda_jack.h
index 13cb375..b279e32 100644
--- a/sound/pci/hda/hda_jack.h
+++ b/sound/pci/hda/hda_jack.h
@@ -72,6 +72,11 @@ enum {
int snd_hda_jack_detect_state(struct hda_codec *codec, hda_nid_t nid);
+/**
+ * snd_hda_jack_detect - Detect the jack
+ * @codec: the HDA codec
+ * @nid: pin NID to check jack detection
+ */
static inline bool snd_hda_jack_detect(struct hda_codec *codec, hda_nid_t nid)
{
return snd_hda_jack_detect_state(codec, nid) != HDA_JACK_NOT_PRESENT;
diff --git a/sound/pci/hda/hda_priv.h b/sound/pci/hda/hda_priv.h
index 5016014..aa484fd 100644
--- a/sound/pci/hda/hda_priv.h
+++ b/sound/pci/hda/hda_priv.h
@@ -152,9 +152,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
/* bits 0-7 are used for indicating driver type */
#define AZX_DCAPS_NO_TCSEL (1 << 8) /* No Intel TCSEL bit */
#define AZX_DCAPS_NO_MSI (1 << 9) /* No MSI support */
-#define AZX_DCAPS_ATI_SNOOP (1 << 10) /* ATI snoop enable */
-#define AZX_DCAPS_NVIDIA_SNOOP (1 << 11) /* Nvidia snoop enable */
-#define AZX_DCAPS_SCH_SNOOP (1 << 12) /* SCH/PCH snoop enable */
+#define AZX_DCAPS_SNOOP_MASK (3 << 10) /* snoop type mask */
+#define AZX_DCAPS_SNOOP_OFF (1 << 12) /* snoop default off */
#define AZX_DCAPS_RIRB_DELAY (1 << 13) /* Long delay in read loop */
#define AZX_DCAPS_RIRB_PRE_DELAY (1 << 14) /* Put a delay before read */
#define AZX_DCAPS_CTX_WORKAROUND (1 << 15) /* X-Fi workaround */
@@ -163,8 +162,8 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_DCAPS_NO_64BIT (1 << 18) /* No 64bit address */
#define AZX_DCAPS_SYNC_WRITE (1 << 19) /* sync each cmd write */
#define AZX_DCAPS_OLD_SSYNC (1 << 20) /* Old SSYNC reg for ICH */
-#define AZX_DCAPS_BUFSIZE (1 << 21) /* no buffer size alignment */
-#define AZX_DCAPS_ALIGN_BUFSIZE (1 << 22) /* buffer size alignment */
+#define AZX_DCAPS_NO_ALIGN_BUFSIZE (1 << 21) /* no buffer size alignment */
+/* 22 unused */
#define AZX_DCAPS_4K_BDLE_BOUNDARY (1 << 23) /* BDLE in 4k boundary */
#define AZX_DCAPS_REVERSE_ASSIGN (1 << 24) /* Assign devices in reverse order */
#define AZX_DCAPS_COUNT_LPIB_DELAY (1 << 25) /* Take LPIB as delay */
@@ -173,6 +172,13 @@ enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
#define AZX_DCAPS_CORBRP_SELF_CLEAR (1 << 28) /* CORBRP clears itself after reset */
#define AZX_DCAPS_NO_MSI64 (1 << 29) /* Stick to 32-bit MSIs */
+enum {
+ AZX_SNOOP_TYPE_NONE ,
+ AZX_SNOOP_TYPE_SCH,
+ AZX_SNOOP_TYPE_ATI,
+ AZX_SNOOP_TYPE_NVIDIA,
+};
+
/* HD Audio class code */
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c
index 9b49f15..bef7215 100644
--- a/sound/pci/hda/hda_sysfs.c
+++ b/sound/pci/hda/hda_sysfs.c
@@ -417,8 +417,13 @@ static DEVICE_ATTR_RW(user_pin_configs);
static DEVICE_ATTR_WO(reconfig);
static DEVICE_ATTR_WO(clear);
-/*
- * Look for hint string
+/**
+ * snd_hda_get_hint - Look for hint string
+ * @codec: the HDA codec
+ * @key: the hint key string
+ *
+ * Look for a hint key/value pair matching with the given key string
+ * and returns the value string. If nothing found, returns NULL.
*/
const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
{
@@ -427,6 +432,15 @@ const char *snd_hda_get_hint(struct hda_codec *codec, const char *key)
}
EXPORT_SYMBOL_GPL(snd_hda_get_hint);
+/**
+ * snd_hda_get_bool_hint - Get a boolean hint value
+ * @codec: the HDA codec
+ * @key: the hint key string
+ *
+ * Look for a hint key/value pair matching with the given key string
+ * and returns a boolean value parsed from the value. If no matching
+ * key is found, return a negative value.
+ */
int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
{
const char *p;
@@ -453,6 +467,16 @@ int snd_hda_get_bool_hint(struct hda_codec *codec, const char *key)
}
EXPORT_SYMBOL_GPL(snd_hda_get_bool_hint);
+/**
+ * snd_hda_get_bool_hint - Get a boolean hint value
+ * @codec: the HDA codec
+ * @key: the hint key string
+ * @valp: pointer to store a value
+ *
+ * Look for a hint key/value pair matching with the given key string
+ * and stores the integer value to @valp. If no matching key is found,
+ * return a negative error code. Otherwise it returns zero.
+ */
int snd_hda_get_int_hint(struct hda_codec *codec, const char *key, int *valp)
{
const char *p;
@@ -690,8 +714,11 @@ static int get_line_from_fw(char *buf, int size, size_t *fw_size_p,
return 1;
}
-/*
- * load a "patch" firmware file and parse it
+/**
+ * snd_hda_load_patch - load a "patch" firmware file and parse it
+ * @bus: HD-audio bus
+ * @fw_size: the firmware byte size
+ * @fw_buf: the firmware data
*/
int snd_hda_load_patch(struct hda_bus *bus, size_t fw_size, const void *fw_buf)
{
diff --git a/sound/pci/hda/patch_analog.c b/sound/pci/hda/patch_analog.c
index 06275f8..c81b715 100644
--- a/sound/pci/hda/patch_analog.c
+++ b/sound/pci/hda/patch_analog.c
@@ -332,6 +332,7 @@ static const struct hda_fixup ad1986a_fixups[] = {
static const struct snd_pci_quirk ad1986a_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x30af, "HP B2800", AD1986A_FIXUP_LAPTOP_IMIC),
+ SND_PCI_QUIRK(0x1043, 0x1443, "ASUS Z99He", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK(0x1043, 0x1447, "ASUS A8JN", AD1986A_FIXUP_EAPD),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8100, "ASUS P5", AD1986A_FIXUP_3STACK),
SND_PCI_QUIRK_MASK(0x1043, 0xff00, 0x8200, "ASUS M2", AD1986A_FIXUP_3STACK),
@@ -351,6 +352,7 @@ static const struct hda_model_fixup ad1986a_fixup_models[] = {
{ .id = AD1986A_FIXUP_LAPTOP, .name = "laptop" },
{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-imic" },
{ .id = AD1986A_FIXUP_LAPTOP_IMIC, .name = "laptop-eapd" }, /* alias */
+ { .id = AD1986A_FIXUP_EAPD, .name = "eapd" },
{}
};
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c
index 4f7ffa8..e0383ee 100644
--- a/sound/pci/hda/patch_ca0132.c
+++ b/sound/pci/hda/patch_ca0132.c
@@ -2417,7 +2417,7 @@ static int dspxfr_one_seg(struct hda_codec *codec,
* @reloc: Relocation address for loading single-segment overlays, or 0 for
* no relocation
* @sample_rate: sampling rate of the stream used for DSP download
- * @number_channels: channels of the stream used for DSP download
+ * @channels: channels of the stream used for DSP download
* @ovly: TRUE if overlay format is required
*
* Returns zero or a negative error code.
@@ -2556,10 +2556,7 @@ static void dspload_post_setup(struct hda_codec *codec)
}
/**
- * Download DSP from a DSP Image Fast Load structure. This structure is a
- * linear, non-constant sized element array of structures, each of which
- * contain the count of the data to be loaded, the data itself, and the
- * corresponding starting chip address of the starting data location.
+ * dspload_image - Download DSP from a DSP Image Fast Load structure.
*
* @codec: the HDA codec
* @fls: pointer to a fast load image
@@ -2570,6 +2567,10 @@ static void dspload_post_setup(struct hda_codec *codec)
* @router_chans: number of audio router channels to be allocated (0 means use
* internal defaults; max is 32)
*
+ * Download DSP from a DSP Image Fast Load structure. This structure is a
+ * linear, non-constant sized element array of structures, each of which
+ * contain the count of the data to be loaded, the data itself, and the
+ * corresponding starting chip address of the starting data location.
* Returns zero or a negative error code.
*/
static int dspload_image(struct hda_codec *codec,
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c
index 14f16be..a722067 100644
--- a/sound/pci/hda/patch_realtek.c
+++ b/sound/pci/hda/patch_realtek.c
@@ -96,6 +96,8 @@ struct alc_spec {
hda_nid_t cap_mute_led_nid;
unsigned int gpio_led; /* used for alc269_fixup_hp_gpio_led() */
+ unsigned int gpio_mute_led_mask;
+ unsigned int gpio_mic_led_mask;
hda_nid_t headset_mic_pin;
hda_nid_t headphone_mic_pin;
@@ -3310,41 +3312,45 @@ static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec,
}
}
-/* turn on/off mute LED per vmaster hook */
-static void alc269_fixup_hp_gpio_mute_hook(void *private_data, int enabled)
+/* update LED status via GPIO */
+static void alc_update_gpio_led(struct hda_codec *codec, unsigned int mask,
+ bool enabled)
{
- struct hda_codec *codec = private_data;
struct alc_spec *spec = codec->spec;
unsigned int oldval = spec->gpio_led;
+ if (spec->mute_led_polarity)
+ enabled = !enabled;
+
if (enabled)
- spec->gpio_led &= ~0x08;
+ spec->gpio_led &= ~mask;
else
- spec->gpio_led |= 0x08;
+ spec->gpio_led |= mask;
if (spec->gpio_led != oldval)
snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
spec->gpio_led);
}
-/* turn on/off mic-mute LED per capture hook */
-static void alc269_fixup_hp_gpio_mic_mute_hook(struct hda_codec *codec,
- struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+/* turn on/off mute LED via GPIO per vmaster hook */
+static void alc_fixup_gpio_mute_hook(void *private_data, int enabled)
{
+ struct hda_codec *codec = private_data;
struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_led;
- if (!ucontrol)
- return;
+ alc_update_gpio_led(codec, spec->gpio_mute_led_mask, enabled);
+}
- if (ucontrol->value.integer.value[0] ||
- ucontrol->value.integer.value[1])
- spec->gpio_led &= ~0x10;
- else
- spec->gpio_led |= 0x10;
- if (spec->gpio_led != oldval)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
+/* turn on/off mic-mute LED via GPIO per capture hook */
+static void alc_fixup_gpio_mic_mute_hook(struct hda_codec *codec,
+ struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct alc_spec *spec = codec->spec;
+
+ if (ucontrol)
+ alc_update_gpio_led(codec, spec->gpio_mic_led_mask,
+ ucontrol->value.integer.value[0] ||
+ ucontrol->value.integer.value[1]);
}
static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
@@ -3358,9 +3364,33 @@ static void alc269_fixup_hp_gpio_led(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
- spec->gen.cap_sync_hook = alc269_fixup_hp_gpio_mic_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
+ spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
+ spec->gpio_mic_led_mask = 0x10;
+ snd_hda_add_verbs(codec, gpio_init);
+ }
+}
+
+static void alc286_fixup_hp_gpio_led(struct hda_codec *codec,
+ const struct hda_fixup *fix, int action)
+{
+ struct alc_spec *spec = codec->spec;
+ static const struct hda_verb gpio_init[] = {
+ { 0x01, AC_VERB_SET_GPIO_MASK, 0x22 },
+ { 0x01, AC_VERB_SET_GPIO_DIRECTION, 0x22 },
+ {}
+ };
+
+ if (action == HDA_FIXUP_ACT_PRE_PROBE) {
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
+ spec->gen.cap_sync_hook = alc_fixup_gpio_mic_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x02;
+ spec->gpio_mic_led_mask = 0x20;
snd_hda_add_verbs(codec, gpio_init);
}
}
@@ -3402,9 +3432,11 @@ static void alc269_fixup_hp_gpio_mic1_led(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
spec->cap_mute_led_nid = 0x18;
snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = led_power_filter;
@@ -3423,9 +3455,11 @@ static void alc280_fixup_hp_gpio4(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc269_fixup_hp_gpio_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
spec->gen.cap_sync_hook = alc269_fixup_hp_cap_mic_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 0;
+ spec->gpio_mute_led_mask = 0x08;
spec->cap_mute_led_nid = 0x18;
snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = led_power_filter;
@@ -4300,6 +4334,7 @@ enum {
ALC255_FIXUP_DELL_WMI_MIC_MUTE_LED,
ALC282_FIXUP_ASPIRE_V5_PINS,
ALC280_FIXUP_HP_GPIO4,
+ ALC286_FIXUP_HP_GPIO_LED,
};
static const struct hda_fixup alc269_fixups[] = {
@@ -4769,6 +4804,10 @@ static const struct hda_fixup alc269_fixups[] = {
.type = HDA_FIXUP_FUNC,
.v.func = alc280_fixup_hp_gpio4,
},
+ [ALC286_FIXUP_HP_GPIO_LED] = {
+ .type = HDA_FIXUP_FUNC,
+ .v.func = alc286_fixup_hp_gpio_led,
+ },
};
static const struct snd_pci_quirk alc269_fixup_tbl[] = {
@@ -4790,6 +4829,8 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x1028, 0x0638, "Dell Inspiron 5439", ALC290_FIXUP_MONO_SPEAKERS_HSJACK),
SND_PCI_QUIRK(0x1028, 0x064a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x064b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x06d9, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
+ SND_PCI_QUIRK(0x1028, 0x06da, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164a, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x1028, 0x164b, "Dell", ALC293_FIXUP_DELL1_MIC_NO_PRESENCE),
SND_PCI_QUIRK(0x103c, 0x1586, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC2),
@@ -4807,6 +4848,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x103c, 0x226a, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x226b, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x226e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
+ SND_PCI_QUIRK(0x103c, 0x2271, "HP", ALC286_FIXUP_HP_GPIO_LED),
SND_PCI_QUIRK(0x103c, 0x229e, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x22b2, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
SND_PCI_QUIRK(0x103c, 0x22b7, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1),
@@ -4885,6 +4927,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = {
SND_PCI_QUIRK(0x17aa, 0x2212, "Thinkpad T440", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2214, "Thinkpad X240", ALC292_FIXUP_TPT440_DOCK),
SND_PCI_QUIRK(0x17aa, 0x2215, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
+ SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC),
SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP),
SND_PCI_QUIRK(0x17aa, 0x5013, "Thinkpad", ALC269_FIXUP_LIMIT_INT_MIC_BOOST),
SND_PCI_QUIRK(0x17aa, 0x501a, "Thinkpad", ALC283_FIXUP_INT_MIC),
@@ -5695,22 +5738,6 @@ static void alc_fixup_bass_chmap(struct hda_codec *codec,
}
}
-/* turn on/off mute LED per vmaster hook */
-static void alc662_led_gpio1_mute_hook(void *private_data, int enabled)
-{
- struct hda_codec *codec = private_data;
- struct alc_spec *spec = codec->spec;
- unsigned int oldval = spec->gpio_led;
-
- if (enabled)
- spec->gpio_led |= 0x01;
- else
- spec->gpio_led &= ~0x01;
- if (spec->gpio_led != oldval)
- snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA,
- spec->gpio_led);
-}
-
/* avoid D3 for keeping GPIO up */
static unsigned int gpio_led_power_filter(struct hda_codec *codec,
hda_nid_t nid,
@@ -5733,8 +5760,10 @@ static void alc662_fixup_led_gpio1(struct hda_codec *codec,
};
if (action == HDA_FIXUP_ACT_PRE_PROBE) {
- spec->gen.vmaster_mute.hook = alc662_led_gpio1_mute_hook;
+ spec->gen.vmaster_mute.hook = alc_fixup_gpio_mute_hook;
spec->gpio_led = 0;
+ spec->mute_led_polarity = 1;
+ spec->gpio_mute_led_mask = 0x01;
snd_hda_add_verbs(codec, gpio_init);
codec->power_filter = gpio_led_power_filter;
}
diff --git a/sound/pci/ice1712/aureon.c b/sound/pci/ice1712/aureon.c
index 3b3cf4a..c9411df 100644
--- a/sound/pci/ice1712/aureon.c
+++ b/sound/pci/ice1712/aureon.c
@@ -205,13 +205,7 @@ static int aureon_universe_inmux_info(struct snd_kcontrol *kcontrol,
static const char * const texts[3] =
{"Internal Aux", "Wavetable", "Rear Line-In"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int aureon_universe_inmux_get(struct snd_kcontrol *kcontrol,
@@ -1106,20 +1100,10 @@ static int wm_adc_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_in
};
struct snd_ice1712 *ice = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE) {
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, universe_texts[uinfo->value.enumerated.item]);
- } else {
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- }
- return 0;
+ if (ice->eeprom.subvendor == VT1724_SUBDEVICE_AUREON71_UNIVERSE)
+ return snd_ctl_enum_info(uinfo, 2, 8, universe_texts);
+ else
+ return snd_ctl_enum_info(uinfo, 2, 5, texts);
}
static int wm_adc_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1167,16 +1151,10 @@ static int aureon_cs8415_mux_info(struct snd_kcontrol *kcontrol, struct snd_ctl_
"CD",
"Coax"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
if (ice->eeprom.subvendor == VT1724_SUBDEVICE_PRODIGY71)
- strcpy(uinfo->value.enumerated.name, prodigy_texts[uinfo->value.enumerated.item]);
+ return snd_ctl_enum_info(uinfo, 1, 2, prodigy_texts);
else
- strcpy(uinfo->value.enumerated.name, aureon_texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, aureon_texts);
}
static int aureon_cs8415_mux_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1392,15 +1370,7 @@ static int aureon_oversampling_info(struct snd_kcontrol *k, struct snd_ctl_elem_
{
static const char * const texts[2] = { "128x", "64x" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int aureon_oversampling_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/ice1712/ews.c b/sound/pci/ice1712/ews.c
index 817a1bc..5cb587c 100644
--- a/sound/pci/ice1712/ews.c
+++ b/sound/pci/ice1712/ews.c
@@ -580,13 +580,7 @@ static int snd_ice1712_ewx_io_sense_info(struct snd_kcontrol *kcontrol, struct s
static const char * const texts[2] = {
"+4dBu", "-10dBV",
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= 2)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_ice1712_ewx_io_sense_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -903,13 +897,7 @@ static int snd_ice1712_6fire_select_input_info(struct snd_kcontrol *kcontrol, st
static const char * const texts[4] = {
"Internal", "Front Input", "Rear Input", "Wave Table"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= 4)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_ice1712_6fire_select_input_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/ice1712/hoontech.c b/sound/pci/ice1712/hoontech.c
index 59e37c5..a40001c 100644
--- a/sound/pci/ice1712/hoontech.c
+++ b/sound/pci/ice1712/hoontech.c
@@ -309,11 +309,7 @@ static int snd_ice1712_value_init(struct snd_ice1712 *ice)
return err;
/* ak4524 controls */
- err = snd_ice1712_akm4xxx_build_controls(ice);
- if (err < 0)
- return err;
-
- return 0;
+ return snd_ice1712_akm4xxx_build_controls(ice);
}
static int snd_ice1712_ez8_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/ice1712.c b/sound/pci/ice1712/ice1712.c
index 206ed2c..b039b46 100644
--- a/sound/pci/ice1712/ice1712.c
+++ b/sound/pci/ice1712/ice1712.c
@@ -620,10 +620,9 @@ static int snd_ice1712_playback_ds_prepare(struct snd_pcm_substream *substream)
{
struct snd_ice1712 *ice = snd_pcm_substream_chip(substream);
struct snd_pcm_runtime *runtime = substream->runtime;
- u32 period_size, buf_size, rate, tmp, chn;
+ u32 period_size, rate, tmp, chn;
period_size = snd_pcm_lib_period_bytes(substream) - 1;
- buf_size = snd_pcm_lib_buffer_bytes(substream) - 1;
tmp = 0x0064;
if (snd_pcm_format_width(runtime->format) == 16)
tmp &= ~0x04;
@@ -1295,10 +1294,7 @@ static int snd_ice1712_pcm_profi(struct snd_ice1712 *ice, int device, struct snd
return err;
}
- err = snd_ice1712_build_pro_mixer(ice);
- if (err < 0)
- return err;
- return 0;
+ return snd_ice1712_build_pro_mixer(ice);
}
/*
@@ -1545,10 +1541,9 @@ static int snd_ice1712_ac97_mixer(struct snd_ice1712 *ice)
dev_warn(ice->card->dev,
"cannot initialize ac97 for consumer, skipped\n");
else {
- err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97, ice));
- if (err < 0)
- return err;
- return 0;
+ return snd_ctl_add(ice->card,
+ snd_ctl_new1(&snd_ice1712_mixer_digmix_route_ac97,
+ ice));
}
}
@@ -1839,13 +1834,7 @@ static int snd_ice1712_pro_internal_clock_info(struct snd_kcontrol *kcontrol,
"96000", /* 12: 7 */
"IEC958 Input", /* 13: -- */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 14;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 14, texts);
}
static int snd_ice1712_pro_internal_clock_get(struct snd_kcontrol *kcontrol,
@@ -1930,13 +1919,7 @@ static int snd_ice1712_pro_internal_clock_default_info(struct snd_kcontrol *kcon
"96000", /* 12: 7 */
/* "IEC958 Input", 13: -- */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 13;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 13, texts);
}
static int snd_ice1712_pro_internal_clock_default_get(struct snd_kcontrol *kcontrol,
@@ -2057,15 +2040,8 @@ static int snd_ice1712_pro_route_info(struct snd_kcontrol *kcontrol,
"IEC958 In L", "IEC958 In R", /* 9-10 */
"Digital Mixer", /* 11 - optional */
};
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items =
- snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ int num_items = snd_ctl_get_ioffidx(kcontrol, &uinfo->id) < 2 ? 12 : 11;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int snd_ice1712_pro_route_analog_get(struct snd_kcontrol *kcontrol,
@@ -2516,11 +2492,8 @@ static int snd_ice1712_build_controls(struct snd_ice1712 *ice)
err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_volume_rate, ice));
if (err < 0)
return err;
- err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
- if (err < 0)
- return err;
-
- return 0;
+ return snd_ctl_add(ice->card,
+ snd_ctl_new1(&snd_ice1712_mixer_pro_peak, ice));
}
static int snd_ice1712_free(struct snd_ice1712 *ice)
@@ -2905,8 +2878,7 @@ static int snd_ice1712_resume(struct device *dev)
outw(ice->pm_saved_spdif_ctrl, ICEMT(ice, ROUTE_SPDOUT));
outw(ice->pm_saved_route, ICEMT(ice, ROUTE_PSDOUT03));
- if (ice->ac97)
- snd_ac97_resume(ice->ac97);
+ snd_ac97_resume(ice->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
diff --git a/sound/pci/ice1712/ice1724.c b/sound/pci/ice1712/ice1724.c
index 08cb08a..d73da15 100644
--- a/sound/pci/ice1712/ice1724.c
+++ b/sound/pci/ice1712/ice1724.c
@@ -2049,13 +2049,7 @@ static int snd_vt1724_pro_route_info(struct snd_kcontrol *kcontrol,
"IEC958 In L", "IEC958 In R", /* 3-4 */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
static inline int analog_route_shift(int idx)
@@ -2503,11 +2497,8 @@ static int snd_vt1724_build_controls(struct snd_ice1712 *ice)
return err;
}
- err = snd_ctl_add(ice->card, snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice));
- if (err < 0)
- return err;
-
- return 0;
+ return snd_ctl_add(ice->card,
+ snd_ctl_new1(&snd_vt1724_mixer_pro_peak, ice));
}
static int snd_vt1724_free(struct snd_ice1712 *ice)
@@ -2884,8 +2875,7 @@ static int snd_vt1724_resume(struct device *dev)
outb(ice->pm_saved_spdif_cfg, ICEREG1724(ice, SPDIF_CFG));
outl(ice->pm_saved_route, ICEMT1724(ice, ROUTE_PLAYBACK));
- if (ice->ac97)
- snd_ac97_resume(ice->ac97);
+ snd_ac97_resume(ice->ac97);
snd_power_change_state(card, SNDRV_CTL_POWER_D0);
return 0;
diff --git a/sound/pci/ice1712/juli.c b/sound/pci/ice1712/juli.c
index 7a6c078..a1536c1 100644
--- a/sound/pci/ice1712/juli.c
+++ b/sound/pci/ice1712/juli.c
@@ -475,11 +475,8 @@ static int juli_add_controls(struct snd_ice1712 *ice)
return err;
/* only capture SPDIF over AK4114 */
- err = snd_ak4114_build(spec->ak4114, NULL,
+ return snd_ak4114_build(spec->ak4114, NULL,
ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
- if (err < 0)
- return err;
- return 0;
}
/*
diff --git a/sound/pci/ice1712/maya44.c b/sound/pci/ice1712/maya44.c
index 63aa39f..7de25c4 100644
--- a/sound/pci/ice1712/maya44.c
+++ b/sound/pci/ice1712/maya44.c
@@ -359,15 +359,7 @@ static int maya_rec_src_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[] = { "Line", "Mic" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(texts);
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int maya_rec_src_get(struct snd_kcontrol *kcontrol,
@@ -411,15 +403,7 @@ static int maya_pb_route_info(struct snd_kcontrol *kcontrol,
"Input 1", "Input 2", "Input 3", "Input 4"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(texts);
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int maya_pb_route_shift(int idx)
diff --git a/sound/pci/ice1712/phase.c b/sound/pci/ice1712/phase.c
index 0011e04..e9ca89c 100644
--- a/sound/pci/ice1712/phase.c
+++ b/sound/pci/ice1712/phase.c
@@ -723,17 +723,7 @@ static int phase28_oversampling_info(struct snd_kcontrol *k,
{
static const char * const texts[2] = { "128x", "64x" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items -
- 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int phase28_oversampling_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c
index 5555eb4..5101f40 100644
--- a/sound/pci/ice1712/pontis.c
+++ b/sound/pci/ice1712/pontis.c
@@ -417,13 +417,7 @@ static int cs_source_info(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_inf
"Optical", /* RXP1 */
"CD", /* RXP2 */
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int cs_source_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/ice1712/prodigy192.c b/sound/pci/ice1712/prodigy192.c
index f3b491a..3919aed 100644
--- a/sound/pci/ice1712/prodigy192.c
+++ b/sound/pci/ice1712/prodigy192.c
@@ -284,15 +284,7 @@ static int stac9460_mic_sw_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[2] = { "Line In", "Mic" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
@@ -563,13 +555,7 @@ static int ak4114_input_sw_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[2] = { "Toslink", "Coax" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
@@ -772,10 +758,8 @@ static int prodigy192_init(struct snd_ice1712 *ice)
"AK4114 initialized with status %d\n", err);
} else
dev_dbg(ice->card->dev, "AK4114 not found\n");
- if (err < 0)
- return err;
- return 0;
+ return err;
}
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c
index 2261d1e..2697402 100644
--- a/sound/pci/ice1712/prodigy_hifi.c
+++ b/sound/pci/ice1712/prodigy_hifi.c
@@ -537,7 +537,7 @@ static int wm_master_vol_put(struct snd_kcontrol *kcontrol,
static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char* texts[32] = {
+ static const char * const texts[32] = {
"NULL", WM_AIN1, WM_AIN2, WM_AIN1 "+" WM_AIN2,
WM_AIN3, WM_AIN1 "+" WM_AIN3, WM_AIN2 "+" WM_AIN3,
WM_AIN1 "+" WM_AIN2 "+" WM_AIN3,
@@ -560,14 +560,7 @@ static int wm_adc_mux_enum_info(struct snd_kcontrol *kcontrol,
WM_AIN1 "+" WM_AIN2 "+" WM_AIN3 "+" WM_AIN4 "+" WM_AIN5
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 32;
- if (uinfo->value.enumerated.item > 31)
- uinfo->value.enumerated.item = 31;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 32, texts);
}
static int wm_adc_mux_enum_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/ice1712/quartet.c b/sound/pci/ice1712/quartet.c
index 2c2df4b..6f55e02 100644
--- a/sound/pci/ice1712/quartet.c
+++ b/sound/pci/ice1712/quartet.c
@@ -46,7 +46,7 @@ struct qtet_kcontrol_private {
unsigned int bit;
void (*set_register)(struct snd_ice1712 *ice, unsigned int val);
unsigned int (*get_register)(struct snd_ice1712 *ice);
- unsigned char * const texts[2];
+ const char * const texts[2];
};
enum {
@@ -554,17 +554,7 @@ static int qtet_ain12_enum_info(struct snd_kcontrol *kcontrol,
{
static const char * const texts[3] =
{"Line In 1/2", "Mic", "Mic + Low-cut"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(texts);
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int qtet_ain12_sw_get(struct snd_kcontrol *kcontrol,
@@ -706,17 +696,8 @@ static int qtet_enum_info(struct snd_kcontrol *kcontrol,
{
struct qtet_kcontrol_private private =
qtet_privates[kcontrol->private_value];
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ARRAY_SIZE(private.texts);
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name,
- private.texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(private.texts),
+ private.texts);
}
static int qtet_sw_get(struct snd_kcontrol *kcontrol,
@@ -852,11 +833,8 @@ static int qtet_add_controls(struct snd_ice1712 *ice)
if (err < 0)
return err;
/* only capture SPDIF over AK4113 */
- err = snd_ak4113_build(spec->ak4113,
+ return snd_ak4113_build(spec->ak4113,
ice->pcm->streams[SNDRV_PCM_STREAM_CAPTURE].substream);
- if (err < 0)
- return err;
- return 0;
}
static inline int qtet_is_spdif_master(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/revo.c b/sound/pci/ice1712/revo.c
index 1112ec1..1d81ae6 100644
--- a/sound/pci/ice1712/revo.c
+++ b/sound/pci/ice1712/revo.c
@@ -494,11 +494,13 @@ static int ap192_ak4114_init(struct snd_ice1712 *ice)
ap192_ak4114_write,
ak4114_init_vals, ak4114_init_txcsb,
ice, &spec->ak4114);
+ if (err < 0)
+ return err;
/* AK4114 in Revo cannot detect external rate correctly.
* No reason to stop capture stream due to incorrect checks */
spec->ak4114->check_flags = AK4114_CHECK_NO_RATE;
- return 0; /* error ignored; it's no fatal error */
+ return 0;
}
static int revo_init(struct snd_ice1712 *ice)
diff --git a/sound/pci/ice1712/se.c b/sound/pci/ice1712/se.c
index ffd894b..1c5d5b2 100644
--- a/sound/pci/ice1712/se.c
+++ b/sound/pci/ice1712/se.c
@@ -452,14 +452,7 @@ static int se200pci_cont_enum_info(struct snd_kcontrol *kc,
c = se200pci_get_enum_count(n);
if (!c)
return -EINVAL;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = c;
- if (uinfo->value.enumerated.item >= c)
- uinfo->value.enumerated.item = c - 1;
- strcpy(uinfo->value.enumerated.name,
- se200pci_cont[n].member[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, c, se200pci_cont[n].member);
}
static int se200pci_cont_volume_get(struct snd_kcontrol *kc,
diff --git a/sound/pci/korg1212/korg1212.c b/sound/pci/korg1212/korg1212.c
index 9fe549b..59d21c9 100644
--- a/sound/pci/korg1212/korg1212.c
+++ b/sound/pci/korg1212/korg1212.c
@@ -444,9 +444,9 @@ static char *stateName[] = {
"Invalid"
};
-static char *clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" };
+static const char * const clockSourceTypeName[] = { "ADAT", "S/PDIF", "local" };
-static char *clockSourceName[] = {
+static const char * const clockSourceName[] = {
"ADAT at 44.1 kHz",
"ADAT at 48 kHz",
"S/PDIF at 44.1 kHz",
@@ -455,7 +455,7 @@ static char *clockSourceName[] = {
"local clock at 48 kHz"
};
-static char *channelName[] = {
+static const char * const channelName[] = {
"ADAT-1",
"ADAT-2",
"ADAT-3",
@@ -1844,14 +1844,9 @@ static int snd_korg1212_control_volume_put(struct snd_kcontrol *kcontrol,
static int snd_korg1212_control_route_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = (kcontrol->private_value >= 8) ? 2 : 1;
- uinfo->value.enumerated.items = kAudioChannels;
- if (uinfo->value.enumerated.item > kAudioChannels-1) {
- uinfo->value.enumerated.item = kAudioChannels-1;
- }
- strcpy(uinfo->value.enumerated.name, channelName[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo,
+ (kcontrol->private_value >= 8) ? 2 : 1,
+ kAudioChannels, channelName);
}
static int snd_korg1212_control_route_get(struct snd_kcontrol *kcontrol,
@@ -1961,14 +1956,7 @@ static int snd_korg1212_control_put(struct snd_kcontrol *kcontrol,
static int snd_korg1212_control_sync_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2) {
- uinfo->value.enumerated.item = 2;
- }
- strcpy(uinfo->value.enumerated.name, clockSourceTypeName[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, clockSourceTypeName);
}
static int snd_korg1212_control_sync_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/lola/lola.c b/sound/pci/lola/lola.c
index a75c8dc..4cf4be5 100644
--- a/sound/pci/lola/lola.c
+++ b/sound/pci/lola/lola.c
@@ -719,7 +719,7 @@ static int lola_probe(struct pci_dev *pci,
err = snd_card_new(&pci->dev, index[dev], id[dev], THIS_MODULE,
0, &card);
if (err < 0) {
- dev_err(card->dev, "Error creating card!\n");
+ dev_err(&pci->dev, "Error creating card!\n");
return err;
}
diff --git a/sound/pci/lola/lola_mixer.c b/sound/pci/lola/lola_mixer.c
index 782f4d8..e7fe15d 100644
--- a/sound/pci/lola/lola_mixer.c
+++ b/sound/pci/lola/lola_mixer.c
@@ -108,8 +108,7 @@ int lola_init_pins(struct lola *chip, int dir, int *nidp)
void lola_free_mixer(struct lola *chip)
{
- if (chip->mixer.array_saved)
- vfree(chip->mixer.array_saved);
+ vfree(chip->mixer.array_saved);
}
int lola_init_mixer_widget(struct lola *chip, int nid)
diff --git a/sound/pci/lx6464es/lx_defs.h b/sound/pci/lx6464es/lx_defs.h
index 49d36bd..469bcc6 100644
--- a/sound/pci/lx6464es/lx_defs.h
+++ b/sound/pci/lx6464es/lx_defs.h
@@ -175,7 +175,7 @@ enum buffer_flags {
BF_ZERO = 0x00, /* no flags (init).*/
};
-/**
+/*
* Stream Flags definitions
*/
enum stream_flags {
diff --git a/sound/pci/mixart/mixart_hwdep.c b/sound/pci/mixart/mixart_hwdep.c
index 581e1e7..9996a4d 100644
--- a/sound/pci/mixart/mixart_hwdep.c
+++ b/sound/pci/mixart/mixart_hwdep.c
@@ -37,10 +37,11 @@
/**
* wait for a value on a peudo register, exit with a timeout
*
- * @param mgr pointer to miXart manager structure
- * @param offset unsigned pseudo_register base + offset of value
- * @param value value
- * @param timeout timeout in centisenconds
+ * @mgr: pointer to miXart manager structure
+ * @offset: unsigned pseudo_register base + offset of value
+ * @is_egal: wait for the equal value
+ * @value: value
+ * @timeout: timeout in centisenconds
*/
static int mixart_wait_nice_for_register_value(struct mixart_mgr *mgr,
u32 offset, int is_egal,
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c
index b854fc5..c6092e4 100644
--- a/sound/pci/pcxhr/pcxhr.c
+++ b/sound/pci/pcxhr/pcxhr.c
@@ -501,10 +501,10 @@ int pcxhr_get_external_clock(struct pcxhr_mgr *mgr,
/*
* start or stop playback/capture substream
*/
-static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
+static int pcxhr_set_stream_state(struct snd_pcxhr *chip,
+ struct pcxhr_stream *stream)
{
int err;
- struct snd_pcxhr *chip;
struct pcxhr_rmh rmh;
int stream_mask, start;
@@ -512,8 +512,8 @@ static int pcxhr_set_stream_state(struct pcxhr_stream *stream)
start = 1;
else {
if (stream->status != PCXHR_STREAM_STATUS_SCHEDULE_STOP) {
- snd_printk(KERN_ERR "ERROR pcxhr_set_stream_state "
- "CANNOT be stopped\n");
+ dev_err(chip->card->dev,
+ "pcxhr_set_stream_state CANNOT be stopped\n");
return -EINVAL;
}
start = 0;
@@ -560,6 +560,7 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
struct pcxhr_rmh rmh;
unsigned int header;
+ chip = snd_pcm_substream_chip(stream->substream);
switch (stream->format) {
case SNDRV_PCM_FORMAT_U8:
header = HEADER_FMT_BASE_LIN;
@@ -582,11 +583,10 @@ static int pcxhr_set_format(struct pcxhr_stream *stream)
header = HEADER_FMT_BASE_FLOAT | HEADER_FMT_INTEL;
break;
default:
- snd_printk(KERN_ERR
- "error pcxhr_set_format() : unknown format\n");
+ dev_err(chip->card->dev,
+ "error pcxhr_set_format() : unknown format\n");
return -EINVAL;
}
- chip = snd_pcm_substream_chip(stream->substream);
sample_rate = chip->mgr->sample_rate;
if (sample_rate <= 32000 && sample_rate !=0) {
@@ -643,11 +643,11 @@ static int pcxhr_update_r_buffer(struct pcxhr_stream *stream)
is_capture = (subs->stream == SNDRV_PCM_STREAM_CAPTURE);
stream_num = is_capture ? 0 : subs->number;
- snd_printdd("pcxhr_update_r_buffer(pcm%c%d) : "
- "addr(%p) bytes(%zx) subs(%d)\n",
- is_capture ? 'c' : 'p',
- chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
- subs->runtime->dma_bytes, subs->number);
+ dev_dbg(chip->card->dev,
+ "pcxhr_update_r_buffer(pcm%c%d) : addr(%p) bytes(%zx) subs(%d)\n",
+ is_capture ? 'c' : 'p',
+ chip->chip_idx, (void *)(long)subs->runtime->dma_addr,
+ subs->runtime->dma_bytes, subs->number);
pcxhr_init_rmh(&rmh, CMD_UPDATE_R_BUFFERS);
pcxhr_set_pipe_cmd_params(&rmh, is_capture, stream->pipe->first_audio,
@@ -687,7 +687,7 @@ static int pcxhr_pipe_sample_count(struct pcxhr_stream *stream,
*sample_count = ((snd_pcm_uframes_t)rmh.stat[0]) << 24;
*sample_count += (snd_pcm_uframes_t)rmh.stat[1];
}
- snd_printdd("PIPE_SAMPLE_COUNT = %lx\n", *sample_count);
+ dev_dbg(chip->card->dev, "PIPE_SAMPLE_COUNT = %lx\n", *sample_count);
return err;
}
#endif
@@ -711,8 +711,9 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
int playback_mask = 0;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- struct timeval my_tv1, my_tv2;
- do_gettimeofday(&my_tv1);
+ ktime_t start_time, stop_time, diff_time;
+
+ start_time = ktime_get();
#endif
mutex_lock(&mgr->setup_mutex);
@@ -778,12 +779,12 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
for (j = 0; j < chip->nb_streams_capt; j++) {
stream = &chip->capture_stream[j];
if (pcxhr_stream_scheduled_get_pipe(stream, &pipe))
- err = pcxhr_set_stream_state(stream);
+ err = pcxhr_set_stream_state(chip, stream);
}
for (j = 0; j < chip->nb_streams_play; j++) {
stream = &chip->playback_stream[j];
if (pcxhr_stream_scheduled_get_pipe(stream, &pipe))
- err = pcxhr_set_stream_state(stream);
+ err = pcxhr_set_stream_state(chip, stream);
}
}
@@ -823,9 +824,10 @@ static void pcxhr_start_linked_stream(struct pcxhr_mgr *mgr)
mutex_unlock(&mgr->setup_mutex);
#ifdef CONFIG_SND_DEBUG_VERBOSE
- do_gettimeofday(&my_tv2);
+ stop_time = ktime_get();
+ diff_time = ktime_sub(stop_time, start_time);
dev_dbg(&mgr->pci->dev, "***TRIGGER START*** TIME = %ld (err = %x)\n",
- (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
+ (long)(ktime_to_ns(diff_time)), err);
#endif
}
@@ -837,12 +839,12 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
{
struct pcxhr_stream *stream;
struct snd_pcm_substream *s;
+ struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- snd_printdd("SNDRV_PCM_TRIGGER_START\n");
+ dev_dbg(chip->card->dev, "SNDRV_PCM_TRIGGER_START\n");
if (snd_pcm_stream_linked(subs)) {
- struct snd_pcxhr *chip = snd_pcm_substream_chip(subs);
snd_pcm_group_for_each_entry(s, subs) {
if (snd_pcm_substream_chip(s) != chip)
continue;
@@ -854,7 +856,7 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
pcxhr_start_linked_stream(chip->mgr);
} else {
stream = subs->runtime->private_data;
- snd_printdd("Only one Substream %c %d\n",
+ dev_dbg(chip->card->dev, "Only one Substream %c %d\n",
stream->pipe->is_capture ? 'C' : 'P',
stream->pipe->first_audio);
if (pcxhr_set_format(stream))
@@ -863,17 +865,17 @@ static int pcxhr_trigger(struct snd_pcm_substream *subs, int cmd)
return -EINVAL;
stream->status = PCXHR_STREAM_STATUS_SCHEDULE_RUN;
- if (pcxhr_set_stream_state(stream))
+ if (pcxhr_set_stream_state(chip, stream))
return -EINVAL;
stream->status = PCXHR_STREAM_STATUS_RUNNING;
}
break;
case SNDRV_PCM_TRIGGER_STOP:
- snd_printdd("SNDRV_PCM_TRIGGER_STOP\n");
+ dev_dbg(chip->card->dev, "SNDRV_PCM_TRIGGER_STOP\n");
snd_pcm_group_for_each_entry(s, subs) {
stream = s->runtime->private_data;
stream->status = PCXHR_STREAM_STATUS_SCHEDULE_STOP;
- if (pcxhr_set_stream_state(stream))
+ if (pcxhr_set_stream_state(chip, stream))
return -EINVAL;
snd_pcm_trigger_done(s, subs);
}
@@ -1636,7 +1638,7 @@ static int pcxhr_probe(struct pci_dev *pci,
0, &card);
if (err < 0) {
- dev_err(card->dev, "cannot allocate the card %d\n", i);
+ dev_err(&pci->dev, "cannot allocate the card %d\n", i);
pcxhr_free(mgr);
return err;
}
diff --git a/sound/pci/pcxhr/pcxhr_core.c b/sound/pci/pcxhr/pcxhr_core.c
index a584acb..181f772 100644
--- a/sound/pci/pcxhr/pcxhr_core.c
+++ b/sound/pci/pcxhr/pcxhr_core.c
@@ -910,8 +910,9 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
int audio_mask;
#ifdef CONFIG_SND_DEBUG_VERBOSE
- struct timeval my_tv1, my_tv2;
- do_gettimeofday(&my_tv1);
+ ktime_t start_time, stop_time, diff_time;
+
+ start_time = ktime_get();
#endif
audio_mask = (playback_mask |
(capture_mask << PCXHR_PIPE_STATE_CAPTURE_OFFSET));
@@ -960,9 +961,10 @@ int pcxhr_set_pipe_state(struct pcxhr_mgr *mgr, int playback_mask,
return err;
}
#ifdef CONFIG_SND_DEBUG_VERBOSE
- do_gettimeofday(&my_tv2);
+ stop_time = ktime_get();
+ diff_time = ktime_sub(stop_time, start_time);
dev_dbg(&mgr->pci->dev, "***SET PIPE STATE*** TIME = %ld (err = %x)\n",
- (long)(my_tv2.tv_usec - my_tv1.tv_usec), err);
+ (long)(ktime_to_ns(diff_time)), err);
#endif
return 0;
}
diff --git a/sound/pci/pcxhr/pcxhr_mixer.c b/sound/pci/pcxhr/pcxhr_mixer.c
index 95c9571..63136c4 100644
--- a/sound/pci/pcxhr/pcxhr_mixer.c
+++ b/sound/pci/pcxhr/pcxhr_mixer.c
@@ -660,14 +660,7 @@ static int pcxhr_audio_src_info(struct snd_kcontrol *kcontrol,
if (chip->mgr->board_has_mic)
i = 5; /* Mic and MicroMix available */
}
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = i;
- if (uinfo->value.enumerated.item > (i-1))
- uinfo->value.enumerated.item = i-1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, i, texts);
}
static int pcxhr_audio_src_get(struct snd_kcontrol *kcontrol,
@@ -756,14 +749,7 @@ static int pcxhr_clock_type_info(struct snd_kcontrol *kcontrol,
texts = textsPCXHR;
snd_BUG_ON(clock_items > (PCXHR_CLOCK_TYPE_MAX+1));
}
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = clock_items;
- if (uinfo->value.enumerated.item >= clock_items)
- uinfo->value.enumerated.item = clock_items-1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, clock_items, texts);
}
static int pcxhr_clock_type_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/rme32.c b/sound/pci/rme32.c
index 4afd3ca..6c60dcd 100644
--- a/sound/pci/rme32.c
+++ b/sound/pci/rme32.c
@@ -1608,30 +1608,24 @@ snd_rme32_info_inputtype_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
struct rme32 *rme32 = snd_kcontrol_chip(kcontrol);
- static char *texts[4] = { "Optical", "Coaxial", "Internal", "XLR" };
+ static const char * const texts[4] = {
+ "Optical", "Coaxial", "Internal", "XLR"
+ };
+ int num_items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
switch (rme32->pci->device) {
case PCI_DEVICE_ID_RME_DIGI32:
case PCI_DEVICE_ID_RME_DIGI32_8:
- uinfo->value.enumerated.items = 3;
+ num_items = 3;
break;
case PCI_DEVICE_ID_RME_DIGI32_PRO:
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
break;
default:
snd_BUG();
- break;
- }
- if (uinfo->value.enumerated.item >
- uinfo->value.enumerated.items - 1) {
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
+ return -EINVAL;
}
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int
snd_rme32_get_inputtype_control(struct snd_kcontrol *kcontrol,
@@ -1695,20 +1689,12 @@ static int
snd_rme32_info_clockmode_control(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "AutoSync",
+ static const char * const texts[4] = { "AutoSync",
"Internal 32.0kHz",
"Internal 44.1kHz",
"Internal 48.0kHz" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3) {
- uinfo->value.enumerated.item = 3;
- }
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int
snd_rme32_get_clockmode_control(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/rme96.c b/sound/pci/rme96.c
index 5a395c8..2f1a851 100644
--- a/sound/pci/rme96.c
+++ b/sound/pci/rme96.c
@@ -1884,39 +1884,38 @@ snd_rme96_put_loopback_control(struct snd_kcontrol *kcontrol, struct snd_ctl_ele
static int
snd_rme96_info_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *_texts[5] = { "Optical", "Coaxial", "Internal", "XLR", "Analog" };
+ static const char * const _texts[5] = {
+ "Optical", "Coaxial", "Internal", "XLR", "Analog"
+ };
struct rme96 *rme96 = snd_kcontrol_chip(kcontrol);
- char *texts[5] = { _texts[0], _texts[1], _texts[2], _texts[3], _texts[4] };
+ const char *texts[5] = {
+ _texts[0], _texts[1], _texts[2], _texts[3], _texts[4]
+ };
+ int num_items;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
switch (rme96->pci->device) {
case PCI_DEVICE_ID_RME_DIGI96:
case PCI_DEVICE_ID_RME_DIGI96_8:
- uinfo->value.enumerated.items = 3;
+ num_items = 3;
break;
case PCI_DEVICE_ID_RME_DIGI96_8_PRO:
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
break;
case PCI_DEVICE_ID_RME_DIGI96_8_PAD_OR_PST:
if (rme96->rev > 4) {
/* PST */
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
texts[3] = _texts[4]; /* Analog instead of XLR */
} else {
/* PAD */
- uinfo->value.enumerated.items = 5;
+ num_items = 5;
}
break;
default:
snd_BUG();
- break;
- }
- if (uinfo->value.enumerated.item > uinfo->value.enumerated.items - 1) {
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
+ return -EINVAL;
}
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int
snd_rme96_get_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2002,16 +2001,9 @@ snd_rme96_put_inputtype_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int
snd_rme96_info_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = { "AutoSync", "Internal", "Word" };
+ static const char * const texts[3] = { "AutoSync", "Internal", "Word" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2) {
- uinfo->value.enumerated.item = 2;
- }
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int
snd_rme96_get_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2041,16 +2033,11 @@ snd_rme96_put_clockmode_control(struct snd_kcontrol *kcontrol, struct snd_ctl_el
static int
snd_rme96_info_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "0 dB", "-6 dB", "-12 dB", "-18 dB" };
+ static const char * const texts[4] = {
+ "0 dB", "-6 dB", "-12 dB", "-18 dB"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3) {
- uinfo->value.enumerated.item = 3;
- }
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int
snd_rme96_get_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2081,16 +2068,9 @@ snd_rme96_put_attenuation_control(struct snd_kcontrol *kcontrol, struct snd_ctl_
static int
snd_rme96_info_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = { "1+2", "3+4", "5+6", "7+8" };
+ static const char * const texts[4] = { "1+2", "3+4", "5+6", "7+8" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3) {
- uinfo->value.enumerated.item = 3;
- }
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int
snd_rme96_get_montracks_control(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/rme9652/hdsp.c b/sound/pci/rme9652/hdsp.c
index 7646ba1..cf5a6c8 100644
--- a/sound/pci/rme9652/hdsp.c
+++ b/sound/pci/rme9652/hdsp.c
@@ -1680,16 +1680,13 @@ static int hdsp_set_spdif_input(struct hdsp *hdsp, int in)
static int snd_hdsp_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"Optical", "Coaxial", "Internal", "AES"};
+ static const char * const texts[4] = {
+ "Optical", "Coaxial", "Internal", "AES"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = ((hdsp->io_type == H9632) ? 4 : 3);
- if (uinfo->value.enumerated.item > ((hdsp->io_type == H9632) ? 3 : 2))
- uinfo->value.enumerated.item = ((hdsp->io_type == H9632) ? 3 : 2);
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 4 : 3,
+ texts);
}
static int snd_hdsp_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1786,16 +1783,14 @@ static int snd_hdsp_put_toggle_setting(struct snd_kcontrol *kcontrol,
static int snd_hdsp_info_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
+ static const char * const texts[] = {
+ "32000", "44100", "48000", "64000", "88200", "96000",
+ "None", "128000", "176400", "192000"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
+ texts);
}
static int snd_hdsp_get_spdif_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1872,14 +1867,13 @@ static int snd_hdsp_get_system_sample_rate(struct snd_kcontrol *kcontrol, struct
static int snd_hdsp_info_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- static char *texts[] = {"32000", "44100", "48000", "64000", "88200", "96000", "None", "128000", "176400", "192000"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = (hdsp->io_type == H9632) ? 10 : 7 ;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char * const texts[] = {
+ "32000", "44100", "48000", "64000", "88200", "96000",
+ "None", "128000", "176400", "192000"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
+ texts);
}
static int snd_hdsp_get_autosync_sample_rate(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1940,15 +1934,9 @@ static int hdsp_system_clock_mode(struct hdsp *hdsp)
static int snd_hdsp_info_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Master", "Slave" };
+ static const char * const texts[] = {"Master", "Slave" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_hdsp_get_system_clock_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2049,19 +2037,16 @@ static int hdsp_set_clock_source(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz", "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz", "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz", "Internal 192.0 KHz" };
+ static const char * const texts[] = {
+ "AutoSync", "Internal 32.0 kHz", "Internal 44.1 kHz",
+ "Internal 48.0 kHz", "Internal 64.0 kHz", "Internal 88.2 kHz",
+ "Internal 96.0 kHz", "Internal 128 kHz", "Internal 176.4 kHz",
+ "Internal 192.0 KHz"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- if (hdsp->io_type == H9632)
- uinfo->value.enumerated.items = 10;
- else
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, (hdsp->io_type == H9632) ? 10 : 7,
+ texts);
}
static int snd_hdsp_get_clock_source(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2165,15 +2150,9 @@ static int hdsp_set_da_gain(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
+ static const char * const texts[] = {"Hi Gain", "+4 dBu", "-10 dbV"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_hdsp_get_da_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2250,15 +2229,9 @@ static int hdsp_set_ad_gain(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
+ static const char * const texts[] = {"-10 dBV", "+4 dBu", "Lo Gain"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_hdsp_get_ad_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2335,15 +2308,9 @@ static int hdsp_set_phone_gain(struct hdsp *hdsp, int mode)
static int snd_hdsp_info_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"0 dB", "-6 dB", "-12 dB"};
+ static const char * const texts[] = {"0 dB", "-6 dB", "-12 dB"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_hdsp_get_phone_gain(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2439,31 +2406,28 @@ static int hdsp_set_pref_sync_ref(struct hdsp *hdsp, int pref)
static int snd_hdsp_info_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3" };
+ static const char * const texts[] = {
+ "Word", "IEC958", "ADAT1", "ADAT Sync", "ADAT2", "ADAT3"
+ };
struct hdsp *hdsp = snd_kcontrol_chip(kcontrol);
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
+ int num_items;
switch (hdsp->io_type) {
case Digiface:
case H9652:
- uinfo->value.enumerated.items = 6;
+ num_items = 6;
break;
case Multiface:
- uinfo->value.enumerated.items = 4;
+ num_items = 4;
break;
case H9632:
- uinfo->value.enumerated.items = 3;
+ num_items = 3;
break;
default:
return -EINVAL;
}
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, num_items, texts);
}
static int snd_hdsp_get_pref_sync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2543,15 +2507,11 @@ static int hdsp_autosync_ref(struct hdsp *hdsp)
static int snd_hdsp_info_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3" };
+ static const char * const texts[] = {
+ "Word", "ADAT Sync", "IEC958", "None", "ADAT1", "ADAT2", "ADAT3"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 7, texts);
}
static int snd_hdsp_get_autosync_ref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -2738,14 +2698,9 @@ static int snd_hdsp_put_mixer(struct snd_kcontrol *kcontrol, struct snd_ctl_elem
static int snd_hdsp_info_sync_check(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"No Lock", "Lock", "Sync" };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ static const char * const texts[] = {"No Lock", "Lock", "Sync" };
+
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int hdsp_wc_sync_check(struct hdsp *hdsp)
@@ -3101,15 +3056,11 @@ static int snd_hdsp_put_rpm_input12(struct snd_kcontrol *kcontrol, struct snd_ct
static int snd_hdsp_info_rpm_input(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"};
+ static const char * const texts[] = {
+ "Phono +6dB", "Phono 0dB", "Phono -6dB", "Line 0dB", "Line -6dB"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 5;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 5, texts);
}
@@ -3234,15 +3185,9 @@ static int snd_hdsp_put_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl
static int snd_hdsp_info_rpm_bypass(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"On", "Off"};
+ static const char * const texts[] = {"On", "Off"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
@@ -3291,15 +3236,9 @@ static int snd_hdsp_put_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd
static int snd_hdsp_info_rpm_disconnect(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[] = {"On", "Off"};
+ static const char * const texts[] = {"On", "Off"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static struct snd_kcontrol_new snd_hdsp_rpm_controls[] = {
@@ -5368,8 +5307,7 @@ static int snd_hdsp_free(struct hdsp *hdsp)
snd_hdsp_free_buffers(hdsp);
- if (hdsp->firmware)
- release_firmware(hdsp->firmware);
+ release_firmware(hdsp->firmware);
vfree(hdsp->fw_uploaded);
if (hdsp->iobase)
diff --git a/sound/pci/rme9652/hdspm.c b/sound/pci/rme9652/hdspm.c
index 52d86af..3342705 100644
--- a/sound/pci/rme9652/hdspm.c
+++ b/sound/pci/rme9652/hdspm.c
@@ -1257,14 +1257,13 @@ static int hdspm_rate_multiplier(struct hdspm *hdspm, int rate)
/* check for external sample rate, returns the sample rate in Hz*/
static int hdspm_external_sample_rate(struct hdspm *hdspm)
{
- unsigned int status, status2, timecode;
+ unsigned int status, status2;
int syncref, rate = 0, rate_bits;
switch (hdspm->io_type) {
case AES32:
status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
status = hdspm_read(hdspm, HDSPM_statusRegister);
- timecode = hdspm_read(hdspm, HDSPM_timecodeRegister);
syncref = hdspm_autosync_ref(hdspm);
switch (syncref) {
@@ -2202,10 +2201,10 @@ static inline int hdspm_get_pll_freq(struct hdspm *hdspm)
return rate;
}
-/**
+/*
* Calculate the real sample rate from the
* current DDS value.
- **/
+ */
static int hdspm_get_system_sample_rate(struct hdspm *hdspm)
{
unsigned int rate;
@@ -2271,9 +2270,9 @@ static int snd_hdspm_put_system_sample_rate(struct snd_kcontrol *kcontrol,
}
-/**
+/*
* Returns the WordClock sample rate class for the given card.
- **/
+ */
static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
{
int status;
@@ -2296,9 +2295,9 @@ static int hdspm_get_wc_sample_rate(struct hdspm *hdspm)
}
-/**
+/*
* Returns the TCO sample rate class for the given card.
- **/
+ */
static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
{
int status;
@@ -2322,9 +2321,9 @@ static int hdspm_get_tco_sample_rate(struct hdspm *hdspm)
}
-/**
+/*
* Returns the SYNC_IN sample rate class for the given card.
- **/
+ */
static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
{
int status;
@@ -2344,9 +2343,9 @@ static int hdspm_get_sync_in_sample_rate(struct hdspm *hdspm)
return 0;
}
-/**
+/*
* Returns the AES sample rate class for the given card.
- **/
+ */
static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
{
int timecode;
@@ -2362,10 +2361,10 @@ static int hdspm_get_aes_sample_rate(struct hdspm *hdspm, int index)
return 0;
}
-/**
+/*
* Returns the sample rate class for input source <idx> for
* 'new style' cards like the AIO and RayDAT.
- **/
+ */
static int hdspm_get_s1_sample_rate(struct hdspm *hdspm, unsigned int idx)
{
int status = hdspm_read(hdspm, HDSPM_RD_STATUS_2);
@@ -2513,10 +2512,10 @@ static int snd_hdspm_get_autosync_sample_rate(struct snd_kcontrol *kcontrol,
}
-/**
+/*
* Returns the system clock mode for the given card.
* @returns 0 - master, 1 - slave
- **/
+ */
static int hdspm_system_clock_mode(struct hdspm *hdspm)
{
switch (hdspm->io_type) {
@@ -2535,10 +2534,10 @@ static int hdspm_system_clock_mode(struct hdspm *hdspm)
}
-/**
+/*
* Sets the system clock mode.
* @param mode 0 - master, 1 - slave
- **/
+ */
static void hdspm_set_system_clock_mode(struct hdspm *hdspm, int mode)
{
hdspm_set_toggle_setting(hdspm,
@@ -2645,18 +2644,7 @@ static int hdspm_set_clock_source(struct hdspm * hdspm, int mode)
static int snd_hdspm_info_clock_source(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 9;
-
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item =
- uinfo->value.enumerated.items - 1;
-
- strcpy(uinfo->value.enumerated.name,
- texts_freq[uinfo->value.enumerated.item+1]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 9, texts_freq + 1);
}
static int snd_hdspm_get_clock_source(struct snd_kcontrol *kcontrol,
@@ -2704,11 +2692,11 @@ static int snd_hdspm_put_clock_source(struct snd_kcontrol *kcontrol,
}
-/**
+/*
* Returns the current preferred sync reference setting.
* The semantics of the return value are depending on the
* card, please see the comments for clarification.
- **/
+ */
static int hdspm_pref_sync_ref(struct hdspm * hdspm)
{
switch (hdspm->io_type) {
@@ -2807,11 +2795,11 @@ static int hdspm_pref_sync_ref(struct hdspm * hdspm)
}
-/**
+/*
* Set the preferred sync reference to <pref>. The semantics
* of <pref> are depending on the card type, see the comments
* for clarification.
- **/
+ */
static int hdspm_set_pref_sync_ref(struct hdspm * hdspm, int pref)
{
int p = 0;
@@ -4113,9 +4101,9 @@ static int snd_hdspm_get_sync_check(struct snd_kcontrol *kcontrol,
-/**
+/*
* TCO controls
- **/
+ */
static void hdspm_tco_write(struct hdspm *hdspm)
{
unsigned int tc[4] = { 0, 0, 0, 0};
@@ -4873,18 +4861,15 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = entry->private_data;
- unsigned int status, status2, control, freq;
+ unsigned int status, status2;
char *pref_sync_ref;
char *autosync_ref;
char *system_clock_mode;
- char *insel;
int x, x2;
status = hdspm_read(hdspm, HDSPM_statusRegister);
status2 = hdspm_read(hdspm, HDSPM_statusRegister2);
- control = hdspm->control_register;
- freq = hdspm_read(hdspm, HDSPM_timecodeRegister);
snd_iprintf(buffer, "%s (Card #%d) Rev.%x Status2first3bits: %x\n",
hdspm->card_name, hdspm->card->number + 1,
@@ -4947,17 +4932,6 @@ snd_hdspm_proc_read_madi(struct snd_info_entry *entry,
snd_iprintf(buffer, "Line out: %s\n",
(hdspm->control_register & HDSPM_LineOut) ? "on " : "off");
- switch (hdspm->control_register & HDSPM_InputMask) {
- case HDSPM_InputOptical:
- insel = "Optical";
- break;
- case HDSPM_InputCoaxial:
- insel = "Coaxial";
- break;
- default:
- insel = "Unknown";
- }
-
snd_iprintf(buffer,
"ClearTrackMarker = %s, Transmit in %s Channel Mode, "
"Auto Input %s\n",
@@ -5202,15 +5176,13 @@ snd_hdspm_proc_read_raydat(struct snd_info_entry *entry,
struct snd_info_buffer *buffer)
{
struct hdspm *hdspm = entry->private_data;
- unsigned int status1, status2, status3, control, i;
+ unsigned int status1, status2, status3, i;
unsigned int lock, sync;
status1 = hdspm_read(hdspm, HDSPM_RD_STATUS_1); /* s1 */
status2 = hdspm_read(hdspm, HDSPM_RD_STATUS_2); /* freq */
status3 = hdspm_read(hdspm, HDSPM_RD_STATUS_3); /* s2 */
- control = hdspm->control_register;
-
snd_iprintf(buffer, "STATUS1: 0x%08x\n", status1);
snd_iprintf(buffer, "STATUS2: 0x%08x\n", status2);
snd_iprintf(buffer, "STATUS3: 0x%08x\n", status3);
@@ -5431,7 +5403,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
HDSPM_midi2IRQPending | HDSPM_midi3IRQPending);
/* now = get_cycles(); */
- /**
+ /*
* LAT_2..LAT_0 period counter (win) counter (mac)
* 6 4096 ~256053425 ~514672358
* 5 2048 ~128024983 ~257373821
@@ -5440,7 +5412,7 @@ static irqreturn_t snd_hdspm_interrupt(int irq, void *dev_id)
* 2 256 ~16003039 ~32260176
* 1 128 ~7998738 ~16194507
* 0 64 ~3998231 ~8191558
- **/
+ */
/*
dev_info(hdspm->card->dev, "snd_hdspm_interrupt %llu @ %llx\n",
now-hdspm->last_interrupt, status & 0xFFC0);
diff --git a/sound/pci/rme9652/rme9652.c b/sound/pci/rme9652/rme9652.c
index fa9a2a8..6521521 100644
--- a/sound/pci/rme9652/rme9652.c
+++ b/sound/pci/rme9652/rme9652.c
@@ -920,15 +920,9 @@ static int rme9652_set_adat1_input(struct snd_rme9652 *rme9652, int internal)
static int snd_rme9652_info_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {"ADAT1", "Internal"};
+ static const char * const texts[2] = {"ADAT1", "Internal"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_rme9652_get_adat1_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -991,15 +985,9 @@ static int rme9652_set_spdif_input(struct snd_rme9652 *rme9652, int in)
static int snd_rme9652_info_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"ADAT1", "Coaxial", "Internal"};
+ static const char * const texts[3] = {"ADAT1", "Coaxial", "Internal"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_rme9652_get_spdif_in(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1140,15 +1128,11 @@ static int rme9652_set_sync_mode(struct snd_rme9652 *rme9652, int mode)
static int snd_rme9652_info_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[3] = {"AutoSync", "Master", "Word Clock"};
+ static const char * const texts[3] = {
+ "AutoSync", "Master", "Word Clock"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 3;
- if (uinfo->value.enumerated.item > 2)
- uinfo->value.enumerated.item = 2;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 3, texts);
}
static int snd_rme9652_get_sync_mode(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1231,16 +1215,14 @@ static int rme9652_set_sync_pref(struct snd_rme9652 *rme9652, int pref)
static int snd_rme9652_info_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"};
+ static const char * const texts[4] = {
+ "IEC958 In", "ADAT1 In", "ADAT2 In", "ADAT3 In"
+ };
struct snd_rme9652 *rme9652 = snd_kcontrol_chip(kcontrol);
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1,
+ rme9652->ss_channels == RME9652_NCHANNELS ? 4 : 3,
+ texts);
}
static int snd_rme9652_get_sync_pref(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
@@ -1392,15 +1374,11 @@ static int snd_rme9652_get_spdif_rate(struct snd_kcontrol *kcontrol, struct snd_
static int snd_rme9652_info_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {"No Lock", "Lock", "No Lock Sync", "Lock Sync"};
+ static const char * const texts[4] = {
+ "No Lock", "Lock", "No Lock Sync", "Lock Sync"
+ };
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item >= uinfo->value.enumerated.items)
- uinfo->value.enumerated.item = uinfo->value.enumerated.items - 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 4, texts);
}
static int snd_rme9652_get_adat_sync(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/sonicvibes.c b/sound/pci/sonicvibes.c
index 5b0d317..313a732 100644
--- a/sound/pci/sonicvibes.c
+++ b/sound/pci/sonicvibes.c
@@ -918,17 +918,11 @@ static int snd_sonicvibes_pcm(struct sonicvibes *sonic, int device,
static int snd_sonicvibes_info_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_info *uinfo)
{
- static char *texts[7] = {
+ static const char * const texts[7] = {
"CD", "PCM", "Aux1", "Line", "Aux0", "Mic", "Mix"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 7;
- if (uinfo->value.enumerated.item >= 7)
- uinfo->value.enumerated.item = 6;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 7, texts);
}
static int snd_sonicvibes_get_mux(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
diff --git a/sound/pci/trident/trident_main.c b/sound/pci/trident/trident_main.c
index da875dc..57cd757 100644
--- a/sound/pci/trident/trident_main.c
+++ b/sound/pci/trident/trident_main.c
@@ -3702,8 +3702,7 @@ static int snd_trident_free(struct snd_trident *trident)
free_irq(trident->irq, trident);
if (trident->tlb.buffer.area) {
outl(0, TRID_REG(trident, NX_TLBC));
- if (trident->tlb.memhdr)
- snd_util_memhdr_free(trident->tlb.memhdr);
+ snd_util_memhdr_free(trident->tlb.memhdr);
if (trident->tlb.silent_page.area)
snd_dma_free_pages(&trident->tlb.silent_page);
vfree(trident->tlb.shadow_entries);
diff --git a/sound/pci/via82xx.c b/sound/pci/via82xx.c
index ecedf4d..e088467 100644
--- a/sound/pci/via82xx.c
+++ b/sound/pci/via82xx.c
@@ -1610,16 +1610,10 @@ static int snd_via8233_capture_source_info(struct snd_kcontrol *kcontrol,
/* formerly they were "Line" and "Mic", but it looks like that they
* have nothing to do with the actual physical connections...
*/
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Input1", "Input2"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item >= 2)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snd_via8233_capture_source_get(struct snd_kcontrol *kcontrol,
diff --git a/sound/pci/vx222/vx222_ops.c b/sound/pci/vx222/vx222_ops.c
index 2d15702..52c1a8d 100644
--- a/sound/pci/vx222/vx222_ops.c
+++ b/sound/pci/vx222/vx222_ops.c
@@ -92,6 +92,7 @@ static inline unsigned long vx2_reg_addr(struct vx_core *_chip, int reg)
/**
* snd_vx_inb - read a byte from the register
+ * @chip: VX core instance
* @offset: register enum
*/
static unsigned char vx2_inb(struct vx_core *chip, int offset)
@@ -101,6 +102,7 @@ static unsigned char vx2_inb(struct vx_core *chip, int offset)
/**
* snd_vx_outb - write a byte on the register
+ * @chip: VX core instance
* @offset: the register offset
* @val: the value to write
*/
@@ -114,6 +116,7 @@ static void vx2_outb(struct vx_core *chip, int offset, unsigned char val)
/**
* snd_vx_inl - read a 32bit word from the register
+ * @chip: VX core instance
* @offset: register enum
*/
static unsigned int vx2_inl(struct vx_core *chip, int offset)
@@ -123,6 +126,7 @@ static unsigned int vx2_inl(struct vx_core *chip, int offset)
/**
* snd_vx_outl - write a 32bit word on the register
+ * @chip: VX core instance
* @offset: the register enum
* @val: the value to write
*/
@@ -223,6 +227,7 @@ static int vx2_test_xilinx(struct vx_core *_chip)
/**
* vx_setup_pseudo_dma - set up the pseudo dma read/write mode.
+ * @chip: VX core instance
* @do_write: 0 = read, 1 = set up for DMA write
*/
static void vx2_setup_pseudo_dma(struct vx_core *chip, int do_write)
diff --git a/sound/pcmcia/vx/vxpocket.c b/sound/pcmcia/vx/vxpocket.c
index 92ec114..b16f42d 100644
--- a/sound/pcmcia/vx/vxpocket.c
+++ b/sound/pcmcia/vx/vxpocket.c
@@ -174,6 +174,7 @@ static int snd_vxpocket_new(struct snd_card *card, int ibl,
/**
* snd_vxpocket_assign_resources - initialize the hardware and card instance.
+ * @chip: VX core instance
* @port: i/o port for the card
* @irq: irq number for the card
*
diff --git a/sound/ppc/pmac.c b/sound/ppc/pmac.c
index 8a431bc..5a13b22 100644
--- a/sound/ppc/pmac.c
+++ b/sound/ppc/pmac.c
@@ -887,8 +887,7 @@ static int snd_pmac_free(struct snd_pmac *chip)
}
}
- if (chip->pdev)
- pci_dev_put(chip->pdev);
+ pci_dev_put(chip->pdev);
of_node_put(chip->node);
kfree(chip);
return 0;
diff --git a/sound/ppc/tumbler.c b/sound/ppc/tumbler.c
index b9ffc17..24c8766 100644
--- a/sound/ppc/tumbler.c
+++ b/sound/ppc/tumbler.c
@@ -795,16 +795,11 @@ static int snapper_set_capture_source(struct pmac_tumbler *mix)
static int snapper_info_capture_source(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[2] = {
+ static const char * const texts[2] = {
"Line", "Mic"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name, texts[uinfo->value.enumerated.item]);
- return 0;
+
+ return snd_ctl_enum_info(uinfo, 1, 2, texts);
}
static int snapper_get_capture_source(struct snd_kcontrol *kcontrol,
diff --git a/sound/soc/Makefile b/sound/soc/Makefile
index d88edfc..865e090 100644
--- a/sound/soc/Makefile
+++ b/sound/soc/Makefile
@@ -1,10 +1,14 @@
snd-soc-core-objs := soc-core.o soc-dapm.o soc-jack.o soc-cache.o soc-utils.o
-snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o
+snd-soc-core-objs += soc-pcm.o soc-compress.o soc-io.o soc-devres.o soc-ops.o
ifneq ($(CONFIG_SND_SOC_GENERIC_DMAENGINE_PCM),)
snd-soc-core-objs += soc-generic-dmaengine-pcm.o
endif
+ifneq ($(CONFIG_SND_SOC_AC97_BUS),)
+snd-soc-core-objs += soc-ac97.o
+endif
+
obj-$(CONFIG_SND_SOC) += snd-soc-core.o
obj-$(CONFIG_SND_SOC) += codecs/
obj-$(CONFIG_SND_SOC) += generic/
diff --git a/sound/soc/atmel/Kconfig b/sound/soc/atmel/Kconfig
index 27e3fc4..fb38783 100644
--- a/sound/soc/atmel/Kconfig
+++ b/sound/soc/atmel/Kconfig
@@ -52,12 +52,3 @@ config SND_AT91_SOC_SAM9X5_WM8731
help
Say Y if you want to add support for audio SoC on an
at91sam9x5 based board that is using WM8731 codec.
-
-config SND_AT91_SOC_AFEB9260
- tristate "SoC Audio support for AFEB9260 board"
- depends on ARCH_AT91 && ATMEL_SSC && ARCH_AT91 && MACH_AFEB9260 && SND_ATMEL_SOC
- select SND_ATMEL_SOC_PDC
- select SND_ATMEL_SOC_SSC
- select SND_SOC_TLV320AIC23_I2C
- help
- Say Y here to support sound on AFEB9260 board.
diff --git a/sound/soc/atmel/Makefile b/sound/soc/atmel/Makefile
index 5baabc8..466a821 100644
--- a/sound/soc/atmel/Makefile
+++ b/sound/soc/atmel/Makefile
@@ -17,4 +17,3 @@ snd-soc-sam9x5-wm8731-objs := sam9x5_wm8731.o
obj-$(CONFIG_SND_AT91_SOC_SAM9G20_WM8731) += snd-soc-sam9g20-wm8731.o
obj-$(CONFIG_SND_ATMEL_SOC_WM8904) += snd-atmel-soc-wm8904.o
obj-$(CONFIG_SND_AT91_SOC_SAM9X5_WM8731) += snd-soc-sam9x5-wm8731.o
-obj-$(CONFIG_SND_AT91_SOC_AFEB9260) += snd-soc-afeb9260.o
diff --git a/sound/soc/atmel/atmel-pcm-dma.c b/sound/soc/atmel/atmel-pcm-dma.c
index b79a2a8..33fb3bb 100644
--- a/sound/soc/atmel/atmel-pcm-dma.c
+++ b/sound/soc/atmel/atmel-pcm-dma.c
@@ -80,9 +80,7 @@ static void atmel_pcm_dma_irq(u32 ssc_sr,
/* stop RX and capture: will be enabled again at restart */
ssc_writex(prtd->ssc->regs, SSC_CR, prtd->mask->ssc_disable);
- snd_pcm_stream_lock(substream);
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock(substream);
+ snd_pcm_stop_xrun(substream);
/* now drain RHR and read status to remove xrun condition */
ssc_readx(prtd->ssc->regs, SSC_RHR);
diff --git a/sound/soc/atmel/atmel_ssc_dai.c b/sound/soc/atmel/atmel_ssc_dai.c
index f403f39..b1cc2a4 100644
--- a/sound/soc/atmel/atmel_ssc_dai.c
+++ b/sound/soc/atmel/atmel_ssc_dai.c
@@ -310,7 +310,10 @@ static int atmel_ssc_set_dai_clkdiv(struct snd_soc_dai *cpu_dai,
* transmit and receive, so if a value has already
* been set, it must match this value.
*/
- if (ssc_p->cmr_div == 0)
+ if (ssc_p->dir_mask !=
+ (SSC_DIR_MASK_PLAYBACK | SSC_DIR_MASK_CAPTURE))
+ ssc_p->cmr_div = div;
+ else if (ssc_p->cmr_div == 0)
ssc_p->cmr_div = div;
else
if (div != ssc_p->cmr_div)
diff --git a/sound/soc/atmel/snd-soc-afeb9260.c b/sound/soc/atmel/snd-soc-afeb9260.c
deleted file mode 100644
index 9579799..0000000
--- a/sound/soc/atmel/snd-soc-afeb9260.c
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * afeb9260.c -- SoC audio for AFEB9260
- *
- * Copyright (C) 2009 Sergey Lapin <slapin@ossfans.org>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT 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/moduleparam.h>
-#include <linux/kernel.h>
-#include <linux/clk.h>
-#include <linux/platform_device.h>
-
-#include <linux/atmel-ssc.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/soc.h>
-
-#include <asm/mach-types.h>
-#include <mach/hardware.h>
-#include <linux/gpio.h>
-
-#include "../codecs/tlv320aic23.h"
-#include "atmel-pcm.h"
-#include "atmel_ssc_dai.h"
-
-#define CODEC_CLOCK 12000000
-
-static int afeb9260_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params)
-{
- struct snd_soc_pcm_runtime *rtd = substream->private_data;
- struct snd_soc_dai *codec_dai = rtd->codec_dai;
- int err;
-
- /* Set the codec system clock for DAC and ADC */
- err =
- snd_soc_dai_set_sysclk(codec_dai, 0, CODEC_CLOCK, SND_SOC_CLOCK_IN);
-
- if (err < 0) {
- printk(KERN_ERR "can't set codec system clock\n");
- return err;
- }
-
- return err;
-}
-
-static struct snd_soc_ops afeb9260_ops = {
- .hw_params = afeb9260_hw_params,
-};
-
-static const struct snd_soc_dapm_widget tlv320aic23_dapm_widgets[] = {
- SND_SOC_DAPM_HP("Headphone Jack", NULL),
- SND_SOC_DAPM_LINE("Line In", NULL),
- SND_SOC_DAPM_MIC("Mic Jack", NULL),
-};
-
-static const struct snd_soc_dapm_route afeb9260_audio_map[] = {
- {"Headphone Jack", NULL, "LHPOUT"},
- {"Headphone Jack", NULL, "RHPOUT"},
-
- {"LLINEIN", NULL, "Line In"},
- {"RLINEIN", NULL, "Line In"},
-
- {"MICIN", NULL, "Mic Jack"},
-};
-
-
-/* Digital audio interface glue - connects codec <--> CPU */
-static struct snd_soc_dai_link afeb9260_dai = {
- .name = "TLV320AIC23",
- .stream_name = "AIC23",
- .cpu_dai_name = "atmel-ssc-dai.0",
- .codec_dai_name = "tlv320aic23-hifi",
- .platform_name = "atmel_pcm-audio",
- .codec_name = "tlv320aic23-codec.0-001a",
- .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_IF |
- SND_SOC_DAIFMT_CBM_CFM,
- .ops = &afeb9260_ops,
-};
-
-/* Audio machine driver */
-static struct snd_soc_card snd_soc_machine_afeb9260 = {
- .name = "AFEB9260",
- .owner = THIS_MODULE,
- .dai_link = &afeb9260_dai,
- .num_links = 1,
-
- .dapm_widgets = tlv320aic23_dapm_widgets,
- .num_dapm_widgets = ARRAY_SIZE(tlv320aic23_dapm_widgets),
- .dapm_routes = afeb9260_audio_map,
- .num_dapm_routes = ARRAY_SIZE(afeb9260_audio_map),
-};
-
-static struct platform_device *afeb9260_snd_device;
-
-static int __init afeb9260_soc_init(void)
-{
- int err;
- struct device *dev;
-
- if (!(machine_is_afeb9260()))
- return -ENODEV;
-
-
- afeb9260_snd_device = platform_device_alloc("soc-audio", -1);
- if (!afeb9260_snd_device) {
- printk(KERN_ERR "ASoC: Platform device allocation failed\n");
- return -ENOMEM;
- }
-
- platform_set_drvdata(afeb9260_snd_device, &snd_soc_machine_afeb9260);
- err = platform_device_add(afeb9260_snd_device);
- if (err)
- goto err1;
-
- dev = &afeb9260_snd_device->dev;
-
- return 0;
-err1:
- platform_device_put(afeb9260_snd_device);
- return err;
-}
-
-static void __exit afeb9260_soc_exit(void)
-{
- platform_device_unregister(afeb9260_snd_device);
-}
-
-module_init(afeb9260_soc_init);
-module_exit(afeb9260_soc_exit);
-
-MODULE_AUTHOR("Sergey Lapin <slapin@ossfans.org>");
-MODULE_DESCRIPTION("ALSA SoC for AFEB9260");
-MODULE_LICENSE("GPL");
-
diff --git a/sound/soc/au1x/ac97c.c b/sound/soc/au1x/ac97c.c
index c8a2de1..5159a50 100644
--- a/sound/soc/au1x/ac97c.c
+++ b/sound/soc/au1x/ac97c.c
@@ -205,7 +205,7 @@ static int au1xac97c_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver au1xac97c_dai_driver = {
.name = "alchemy-ac97c",
- .ac97_control = 1,
+ .bus_control = true,
.probe = au1xac97c_dai_probe,
.playback = {
.rates = AC97_RATES,
diff --git a/sound/soc/au1x/psc-ac97.c b/sound/soc/au1x/psc-ac97.c
index 84f31e1..c6daec9 100644
--- a/sound/soc/au1x/psc-ac97.c
+++ b/sound/soc/au1x/psc-ac97.c
@@ -343,7 +343,7 @@ static const struct snd_soc_dai_ops au1xpsc_ac97_dai_ops = {
};
static const struct snd_soc_dai_driver au1xpsc_ac97_dai_template = {
- .ac97_control = 1,
+ .bus_control = true,
.probe = au1xpsc_ac97_probe,
.playback = {
.rates = AC97_RATES,
diff --git a/sound/soc/blackfin/bf5xx-ac97.c b/sound/soc/blackfin/bf5xx-ac97.c
index e82eb37..6bf21a6 100644
--- a/sound/soc/blackfin/bf5xx-ac97.c
+++ b/sound/soc/blackfin/bf5xx-ac97.c
@@ -260,7 +260,7 @@ static int bf5xx_ac97_resume(struct snd_soc_dai *dai)
#endif
static struct snd_soc_dai_driver bfin_ac97_dai = {
- .ac97_control = 1,
+ .bus_control = true,
.suspend = bf5xx_ac97_suspend,
.resume = bf5xx_ac97_resume,
.playback = {
diff --git a/sound/soc/blackfin/bf5xx-ad1980.c b/sound/soc/blackfin/bf5xx-ad1980.c
index 3450e8f..0fa81a5 100644
--- a/sound/soc/blackfin/bf5xx-ad1980.c
+++ b/sound/soc/blackfin/bf5xx-ad1980.c
@@ -46,8 +46,6 @@
#include <linux/gpio.h>
#include <asm/portmux.h>
-#include "../codecs/ad1980.h"
-
#include "bf5xx-ac97.h"
static struct snd_soc_card bf5xx_board;
diff --git a/sound/soc/cirrus/Kconfig b/sound/soc/cirrus/Kconfig
index 5477c54..7b7fbcd 100644
--- a/sound/soc/cirrus/Kconfig
+++ b/sound/soc/cirrus/Kconfig
@@ -36,7 +36,8 @@ config SND_EP93XX_SOC_EDB93XX
tristate "SoC Audio support for Cirrus Logic EDB93xx boards"
depends on SND_EP93XX_SOC && (MACH_EDB9301 || MACH_EDB9302 || MACH_EDB9302A || MACH_EDB9307A || MACH_EDB9315A)
select SND_EP93XX_SOC_I2S
- select SND_SOC_CS4271
+ select SND_SOC_CS4271_I2C if I2C
+ select SND_SOC_CS4271_SPI if SPI_MASTER
help
Say Y or M here if you want to add support for I2S audio on the
Cirrus Logic EDB93xx boards.
diff --git a/sound/soc/cirrus/ep93xx-ac97.c b/sound/soc/cirrus/ep93xx-ac97.c
index f30dadf..6b8a366 100644
--- a/sound/soc/cirrus/ep93xx-ac97.c
+++ b/sound/soc/cirrus/ep93xx-ac97.c
@@ -338,7 +338,7 @@ static const struct snd_soc_dai_ops ep93xx_ac97_dai_ops = {
static struct snd_soc_dai_driver ep93xx_ac97_dai = {
.name = "ep93xx-ac97",
.id = 0,
- .ac97_control = 1,
+ .bus_control = true,
.probe = ep93xx_ac97_dai_probe,
.playback = {
.stream_name = "AC97 Playback",
diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig
index a68d173..883c577 100644
--- a/sound/soc/codecs/Kconfig
+++ b/sound/soc/codecs/Kconfig
@@ -50,7 +50,8 @@ config SND_SOC_ALL_CODECS
select SND_SOC_CS42L73 if I2C
select SND_SOC_CS4265 if I2C
select SND_SOC_CS4270 if I2C
- select SND_SOC_CS4271 if SND_SOC_I2C_AND_SPI
+ select SND_SOC_CS4271_I2C if I2C
+ select SND_SOC_CS4271_SPI if SPI_MASTER
select SND_SOC_CS42XX8_I2C if I2C
select SND_SOC_CX20442 if TTY
select SND_SOC_DA7210 if I2C
@@ -85,7 +86,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_RT5645 if I2C
select SND_SOC_RT5651 if I2C
select SND_SOC_RT5670 if I2C
- select SND_SOC_RT5677 if I2C
+ select SND_SOC_RT5677 if I2C && SPI_MASTER
select SND_SOC_SGTL5000 if I2C
select SND_SOC_SI476X if MFD_SI476X_CORE
select SND_SOC_SIRF_AUDIO_CODEC
@@ -101,6 +102,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_STAC9766 if SND_SOC_AC97_BUS
select SND_SOC_TAS2552 if I2C
select SND_SOC_TAS5086 if I2C
+ select SND_SOC_TFA9879 if I2C
select SND_SOC_TLV320AIC23_I2C if I2C
select SND_SOC_TLV320AIC23_SPI if SPI_MASTER
select SND_SOC_TLV320AIC26 if SPI_MASTER
@@ -109,6 +111,7 @@ config SND_SOC_ALL_CODECS
select SND_SOC_TLV320AIC3X if I2C
select SND_SOC_TPA6130A2 if I2C
select SND_SOC_TLV320DAC33 if I2C
+ select SND_SOC_TS3A227E if I2C
select SND_SOC_TWL4030 if TWL4030_CORE
select SND_SOC_TWL6040 if TWL6040_CORE
select SND_SOC_UDA134X
@@ -223,6 +226,7 @@ config SND_SOC_AD193X_I2C
select SND_SOC_AD193X
config SND_SOC_AD1980
+ select REGMAP_AC97
tristate
config SND_SOC_AD73311
@@ -336,7 +340,8 @@ config SND_SOC_CS42L51
tristate
config SND_SOC_CS42L51_I2C
- tristate
+ tristate "Cirrus Logic CS42L51 CODEC (I2C)"
+ depends on I2C
select SND_SOC_CS42L51
config SND_SOC_CS42L52
@@ -370,8 +375,19 @@ config SND_SOC_CS4270_VD33_ERRATA
depends on SND_SOC_CS4270
config SND_SOC_CS4271
- tristate "Cirrus Logic CS4271 CODEC"
- depends on SND_SOC_I2C_AND_SPI
+ tristate
+
+config SND_SOC_CS4271_I2C
+ tristate "Cirrus Logic CS4271 CODEC (I2C)"
+ depends on I2C
+ select SND_SOC_CS4271
+ select REGMAP_I2C
+
+config SND_SOC_CS4271_SPI
+ tristate "Cirrus Logic CS4271 CODEC (SPI)"
+ depends on SPI_MASTER
+ select SND_SOC_CS4271
+ select REGMAP_SPI
config SND_SOC_CS42XX8
tristate
@@ -487,7 +503,8 @@ config SND_SOC_RT286
depends on I2C
config SND_SOC_RT5631
- tristate
+ tristate "Realtek ALC5631/RT5631 CODEC"
+ depends on I2C
config SND_SOC_RT5640
tristate
@@ -504,6 +521,10 @@ config SND_SOC_RT5670
config SND_SOC_RT5677
tristate
+config SND_SOC_RT5677_SPI
+ tristate
+ default SND_SOC_RT5677
+
#Freescale sgtl5000 codec
config SND_SOC_SGTL5000
tristate "Freescale SGTL5000 CODEC"
@@ -577,15 +598,21 @@ config SND_SOC_TAS5086
tristate "Texas Instruments TAS5086 speaker amplifier"
depends on I2C
+config SND_SOC_TFA9879
+ tristate "NXP Semiconductors TFA9879 amplifier"
+ depends on I2C
+
config SND_SOC_TLV320AIC23
tristate
config SND_SOC_TLV320AIC23_I2C
- tristate
+ tristate "Texas Instruments TLV320AIC23 audio CODEC - I2C"
+ depends on I2C
select SND_SOC_TLV320AIC23
config SND_SOC_TLV320AIC23_SPI
- tristate
+ tristate "Texas Instruments TLV320AIC23 audio CODEC - SPI"
+ depends on SPI_MASTER
select SND_SOC_TLV320AIC23
config SND_SOC_TLV320AIC26
@@ -607,6 +634,10 @@ config SND_SOC_TLV320AIC3X
config SND_SOC_TLV320DAC33
tristate
+config SND_SOC_TS3A227E
+ tristate "TI Headset/Mic detect and keypress chip"
+ depends on I2C
+
config SND_SOC_TWL4030
select MFD_TWL4030_AUDIO
tristate
diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile
index 5dce451..bbdfd1e 100644
--- a/sound/soc/codecs/Makefile
+++ b/sound/soc/codecs/Makefile
@@ -41,6 +41,8 @@ snd-soc-cs42l73-objs := cs42l73.o
snd-soc-cs4265-objs := cs4265.o
snd-soc-cs4270-objs := cs4270.o
snd-soc-cs4271-objs := cs4271.o
+snd-soc-cs4271-i2c-objs := cs4271-i2c.o
+snd-soc-cs4271-spi-objs := cs4271-spi.o
snd-soc-cs42xx8-objs := cs42xx8.o
snd-soc-cs42xx8-i2c-objs := cs42xx8-i2c.o
snd-soc-cx20442-objs := cx20442.o
@@ -80,6 +82,7 @@ snd-soc-rt5645-objs := rt5645.o
snd-soc-rt5651-objs := rt5651.o
snd-soc-rt5670-objs := rt5670.o
snd-soc-rt5677-objs := rt5677.o
+snd-soc-rt5677-spi-objs := rt5677-spi.o
snd-soc-sgtl5000-objs := sgtl5000.o
snd-soc-alc5623-objs := alc5623.o
snd-soc-alc5632-objs := alc5632.o
@@ -101,6 +104,7 @@ snd-soc-sta350-objs := sta350.o
snd-soc-sta529-objs := sta529.o
snd-soc-stac9766-objs := stac9766.o
snd-soc-tas5086-objs := tas5086.o
+snd-soc-tfa9879-objs := tfa9879.o
snd-soc-tlv320aic23-objs := tlv320aic23.o
snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o
snd-soc-tlv320aic23-spi-objs := tlv320aic23-spi.o
@@ -109,6 +113,7 @@ snd-soc-tlv320aic31xx-objs := tlv320aic31xx.o
snd-soc-tlv320aic32x4-objs := tlv320aic32x4.o
snd-soc-tlv320aic3x-objs := tlv320aic3x.o
snd-soc-tlv320dac33-objs := tlv320dac33.o
+snd-soc-ts3a227e-objs := ts3a227e.o
snd-soc-twl4030-objs := twl4030.o
snd-soc-twl6040-objs := twl6040.o
snd-soc-uda134x-objs := uda134x.o
@@ -217,6 +222,8 @@ obj-$(CONFIG_SND_SOC_CS42L73) += snd-soc-cs42l73.o
obj-$(CONFIG_SND_SOC_CS4265) += snd-soc-cs4265.o
obj-$(CONFIG_SND_SOC_CS4270) += snd-soc-cs4270.o
obj-$(CONFIG_SND_SOC_CS4271) += snd-soc-cs4271.o
+obj-$(CONFIG_SND_SOC_CS4271_I2C) += snd-soc-cs4271-i2c.o
+obj-$(CONFIG_SND_SOC_CS4271_SPI) += snd-soc-cs4271-spi.o
obj-$(CONFIG_SND_SOC_CS42XX8) += snd-soc-cs42xx8.o
obj-$(CONFIG_SND_SOC_CS42XX8_I2C) += snd-soc-cs42xx8-i2c.o
obj-$(CONFIG_SND_SOC_CX20442) += snd-soc-cx20442.o
@@ -256,6 +263,7 @@ obj-$(CONFIG_SND_SOC_RT5645) += snd-soc-rt5645.o
obj-$(CONFIG_SND_SOC_RT5651) += snd-soc-rt5651.o
obj-$(CONFIG_SND_SOC_RT5670) += snd-soc-rt5670.o
obj-$(CONFIG_SND_SOC_RT5677) += snd-soc-rt5677.o
+obj-$(CONFIG_SND_SOC_RT5677_SPI) += snd-soc-rt5677-spi.o
obj-$(CONFIG_SND_SOC_SGTL5000) += snd-soc-sgtl5000.o
obj-$(CONFIG_SND_SOC_SIGMADSP) += snd-soc-sigmadsp.o
obj-$(CONFIG_SND_SOC_SIGMADSP_I2C) += snd-soc-sigmadsp-i2c.o
@@ -274,6 +282,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o
obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o
obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o
obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o
+obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o
obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o
obj-$(CONFIG_SND_SOC_TLV320AIC23_SPI) += snd-soc-tlv320aic23-spi.o
@@ -282,6 +291,7 @@ obj-$(CONFIG_SND_SOC_TLV320AIC31XX) += snd-soc-tlv320aic31xx.o
obj-$(CONFIG_SND_SOC_TLV320AIC32X4) += snd-soc-tlv320aic32x4.o
obj-$(CONFIG_SND_SOC_TLV320AIC3X) += snd-soc-tlv320aic3x.o
obj-$(CONFIG_SND_SOC_TLV320DAC33) += snd-soc-tlv320dac33.o
+obj-$(CONFIG_SND_SOC_TS3A227E) += snd-soc-ts3a227e.o
obj-$(CONFIG_SND_SOC_TWL4030) += snd-soc-twl4030.o
obj-$(CONFIG_SND_SOC_TWL6040) += snd-soc-twl6040.o
obj-$(CONFIG_SND_SOC_UDA134X) += snd-soc-uda134x.o
diff --git a/sound/soc/codecs/ab8500-codec.c b/sound/soc/codecs/ab8500-codec.c
index fd43827..7dfbc99 100644
--- a/sound/soc/codecs/ab8500-codec.c
+++ b/sound/soc/codecs/ab8500-codec.c
@@ -126,13 +126,13 @@ struct ab8500_codec_drvdata_dbg {
/* Private data for AB8500 device-driver */
struct ab8500_codec_drvdata {
struct regmap *regmap;
+ struct mutex ctrl_lock;
/* Sidetone */
long *sid_fir_values;
enum sid_state sid_status;
/* ANC */
- struct mutex anc_lock;
long *anc_fir_values;
long *anc_iir_values;
enum anc_state anc_status;
@@ -1129,9 +1129,9 @@ static int sid_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
- mutex_lock(&codec->mutex);
+ mutex_lock(&drvdata->ctrl_lock);
ucontrol->value.integer.value[0] = drvdata->sid_status;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&drvdata->ctrl_lock);
return 0;
}
@@ -1154,7 +1154,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
return -EIO;
}
- mutex_lock(&codec->mutex);
+ mutex_lock(&drvdata->ctrl_lock);
sidconf = snd_soc_read(codec, AB8500_SIDFIRCONF);
if (((sidconf & BIT(AB8500_SIDFIRCONF_FIRSIDBUSY)) != 0)) {
@@ -1185,7 +1185,7 @@ static int sid_status_control_put(struct snd_kcontrol *kcontrol,
drvdata->sid_status = SID_FIR_CONFIGURED;
out:
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&drvdata->ctrl_lock);
dev_dbg(codec->dev, "%s: Exit\n", __func__);
@@ -1198,9 +1198,9 @@ static int anc_status_control_get(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct ab8500_codec_drvdata *drvdata = dev_get_drvdata(codec->dev);
- mutex_lock(&codec->mutex);
+ mutex_lock(&drvdata->ctrl_lock);
ucontrol->value.integer.value[0] = drvdata->anc_status;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&drvdata->ctrl_lock);
return 0;
}
@@ -1217,7 +1217,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
dev_dbg(dev, "%s: Enter.\n", __func__);
- mutex_lock(&drvdata->anc_lock);
+ mutex_lock(&drvdata->ctrl_lock);
req = ucontrol->value.integer.value[0];
if (req >= ARRAY_SIZE(enum_anc_state)) {
@@ -1244,9 +1244,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
}
snd_soc_dapm_sync(&codec->dapm);
- mutex_lock(&codec->mutex);
anc_configure(codec, apply_fir, apply_iir);
- mutex_unlock(&codec->mutex);
if (apply_fir) {
if (drvdata->anc_status == ANC_IIR_CONFIGURED)
@@ -1265,7 +1263,7 @@ static int anc_status_control_put(struct snd_kcontrol *kcontrol,
snd_soc_dapm_sync(&codec->dapm);
cleanup:
- mutex_unlock(&drvdata->anc_lock);
+ mutex_unlock(&drvdata->ctrl_lock);
if (status < 0)
dev_err(dev, "%s: Unable to configure ANC! (status = %d)\n",
@@ -1294,14 +1292,15 @@ static int filter_control_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
struct filter_control *fc =
(struct filter_control *)kcontrol->private_value;
unsigned int i;
- mutex_lock(&codec->mutex);
+ mutex_lock(&drvdata->ctrl_lock);
for (i = 0; i < fc->count; i++)
ucontrol->value.integer.value[i] = fc->value[i];
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&drvdata->ctrl_lock);
return 0;
}
@@ -1310,14 +1309,15 @@ static int filter_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
+ struct ab8500_codec_drvdata *drvdata = snd_soc_codec_get_drvdata(codec);
struct filter_control *fc =
(struct filter_control *)kcontrol->private_value;
unsigned int i;
- mutex_lock(&codec->mutex);
+ mutex_lock(&drvdata->ctrl_lock);
for (i = 0; i < fc->count; i++)
fc->value[i] = ucontrol->value.integer.value[i];
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&drvdata->ctrl_lock);
return 0;
}
@@ -2545,7 +2545,7 @@ static int ab8500_codec_probe(struct snd_soc_codec *codec)
(void)snd_soc_dapm_disable_pin(&codec->dapm, "ANC Configure Input");
- mutex_init(&drvdata->anc_lock);
+ mutex_init(&drvdata->ctrl_lock);
return status;
}
diff --git a/sound/soc/codecs/ac97.c b/sound/soc/codecs/ac97.c
index bd9b183..c6e5a31 100644
--- a/sound/soc/codecs/ac97.c
+++ b/sound/soc/codecs/ac97.c
@@ -37,10 +37,11 @@ static int ac97_prepare(struct snd_pcm_substream *substream,
struct snd_soc_dai *dai)
{
struct snd_soc_codec *codec = dai->codec;
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
int reg = (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) ?
AC97_PCM_FRONT_DAC_RATE : AC97_PCM_LR_ADC_RATE;
- return snd_ac97_set_rate(codec->ac97, reg, substream->runtime->rate);
+ return snd_ac97_set_rate(ac97, reg, substream->runtime->rate);
}
#define STD_AC97_RATES (SNDRV_PCM_RATE_8000 | SNDRV_PCM_RATE_11025 |\
@@ -53,7 +54,6 @@ static const struct snd_soc_dai_ops ac97_dai_ops = {
static struct snd_soc_dai_driver ac97_dai = {
.name = "ac97-hifi",
- .ac97_control = 1,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 1,
@@ -71,6 +71,7 @@ static struct snd_soc_dai_driver ac97_dai = {
static int ac97_soc_probe(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97;
struct snd_ac97_bus *ac97_bus;
struct snd_ac97_template ac97_template;
int ret;
@@ -82,24 +83,31 @@ static int ac97_soc_probe(struct snd_soc_codec *codec)
return ret;
memset(&ac97_template, 0, sizeof(struct snd_ac97_template));
- ret = snd_ac97_mixer(ac97_bus, &ac97_template, &codec->ac97);
+ ret = snd_ac97_mixer(ac97_bus, &ac97_template, &ac97);
if (ret < 0)
return ret;
+ snd_soc_codec_set_drvdata(codec, ac97);
+
return 0;
}
#ifdef CONFIG_PM
static int ac97_soc_suspend(struct snd_soc_codec *codec)
{
- snd_ac97_suspend(codec->ac97);
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ snd_ac97_suspend(ac97);
return 0;
}
static int ac97_soc_resume(struct snd_soc_codec *codec)
{
- snd_ac97_resume(codec->ac97);
+
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ snd_ac97_resume(ac97);
return 0;
}
diff --git a/sound/soc/codecs/ad193x.c b/sound/soc/codecs/ad193x.c
index 6844d0b..387530b 100644
--- a/sound/soc/codecs/ad193x.c
+++ b/sound/soc/codecs/ad193x.c
@@ -72,11 +72,13 @@ static const struct snd_kcontrol_new ad193x_snd_controls[] = {
};
static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
- SND_SOC_DAPM_DAC("DAC", "Playback", AD193X_DAC_CTRL0, 0, 1),
+ SND_SOC_DAPM_DAC("DAC", "Playback", SND_SOC_NOPM, 0, 0),
+ SND_SOC_DAPM_PGA("DAC Output", AD193X_DAC_CTRL0, 0, 1, NULL, 0),
SND_SOC_DAPM_ADC("ADC", "Capture", SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_SUPPLY("PLL_PWR", AD193X_PLL_CLK_CTRL0, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("ADC_PWR", AD193X_ADC_CTRL0, 0, 1, NULL, 0),
SND_SOC_DAPM_SUPPLY("SYSCLK", AD193X_PLL_CLK_CTRL0, 7, 0, NULL, 0),
+ SND_SOC_DAPM_VMID("VMID"),
SND_SOC_DAPM_OUTPUT("DAC1OUT"),
SND_SOC_DAPM_OUTPUT("DAC2OUT"),
SND_SOC_DAPM_OUTPUT("DAC3OUT"),
@@ -87,13 +89,15 @@ static const struct snd_soc_dapm_widget ad193x_dapm_widgets[] = {
static const struct snd_soc_dapm_route audio_paths[] = {
{ "DAC", NULL, "SYSCLK" },
+ { "DAC Output", NULL, "DAC" },
+ { "DAC Output", NULL, "VMID" },
{ "ADC", NULL, "SYSCLK" },
{ "DAC", NULL, "ADC_PWR" },
{ "ADC", NULL, "ADC_PWR" },
- { "DAC1OUT", NULL, "DAC" },
- { "DAC2OUT", NULL, "DAC" },
- { "DAC3OUT", NULL, "DAC" },
- { "DAC4OUT", NULL, "DAC" },
+ { "DAC1OUT", NULL, "DAC Output" },
+ { "DAC2OUT", NULL, "DAC Output" },
+ { "DAC3OUT", NULL, "DAC Output" },
+ { "DAC4OUT", NULL, "DAC Output" },
{ "ADC", NULL, "ADC1IN" },
{ "ADC", NULL, "ADC2IN" },
{ "SYSCLK", NULL, "PLL_PWR" },
diff --git a/sound/soc/codecs/ad1980.c b/sound/soc/codecs/ad1980.c
index 304d300..2860eef 100644
--- a/sound/soc/codecs/ad1980.c
+++ b/sound/soc/codecs/ad1980.c
@@ -24,34 +24,86 @@
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/device.h>
+#include <linux/regmap.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/ac97_codec.h>
#include <sound/initval.h>
#include <sound/soc.h>
-#include "ad1980.h"
+static const struct reg_default ad1980_reg_defaults[] = {
+ { 0x02, 0x8000 },
+ { 0x04, 0x8000 },
+ { 0x06, 0x8000 },
+ { 0x0c, 0x8008 },
+ { 0x0e, 0x8008 },
+ { 0x10, 0x8808 },
+ { 0x12, 0x8808 },
+ { 0x16, 0x8808 },
+ { 0x18, 0x8808 },
+ { 0x1a, 0x0000 },
+ { 0x1c, 0x8000 },
+ { 0x20, 0x0000 },
+ { 0x28, 0x03c7 },
+ { 0x2c, 0xbb80 },
+ { 0x2e, 0xbb80 },
+ { 0x30, 0xbb80 },
+ { 0x32, 0xbb80 },
+ { 0x36, 0x8080 },
+ { 0x38, 0x8080 },
+ { 0x3a, 0x2000 },
+ { 0x60, 0x0000 },
+ { 0x62, 0x0000 },
+ { 0x72, 0x0000 },
+ { 0x74, 0x1001 },
+ { 0x76, 0x0000 },
+};
-/*
- * AD1980 register cache
- */
-static const u16 ad1980_reg[] = {
- 0x0090, 0x8000, 0x8000, 0x8000, /* 0 - 6 */
- 0x0000, 0x0000, 0x8008, 0x8008, /* 8 - e */
- 0x8808, 0x8808, 0x0000, 0x8808, /* 10 - 16 */
- 0x8808, 0x0000, 0x8000, 0x0000, /* 18 - 1e */
- 0x0000, 0x0000, 0x0000, 0x0000, /* 20 - 26 */
- 0x03c7, 0x0000, 0xbb80, 0xbb80, /* 28 - 2e */
- 0xbb80, 0xbb80, 0x0000, 0x8080, /* 30 - 36 */
- 0x8080, 0x2000, 0x0000, 0x0000, /* 38 - 3e */
- 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
- 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
- 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
- 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
- 0x8080, 0x0000, 0x0000, 0x0000, /* 60 - 66 */
- 0x0000, 0x0000, 0x0000, 0x0000, /* reserved */
- 0x0000, 0x0000, 0x1001, 0x0000, /* 70 - 76 */
- 0x0000, 0x0000, 0x4144, 0x5370 /* 78 - 7e */
+static bool ad1980_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AC97_RESET ... AC97_MASTER_MONO:
+ case AC97_PHONE ... AC97_CD:
+ case AC97_AUX ... AC97_GENERAL_PURPOSE:
+ case AC97_POWERDOWN ... AC97_PCM_LR_ADC_RATE:
+ case AC97_SPDIF:
+ case AC97_CODEC_CLASS_REV:
+ case AC97_PCI_SVID:
+ case AC97_AD_CODEC_CFG:
+ case AC97_AD_JACK_SPDIF:
+ case AC97_AD_SERIAL_CFG:
+ case AC97_VENDOR_ID1:
+ case AC97_VENDOR_ID2:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool ad1980_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case AC97_VENDOR_ID1:
+ case AC97_VENDOR_ID2:
+ return false;
+ default:
+ return ad1980_readable_reg(dev, reg);
+ }
+}
+
+static const struct regmap_config ad1980_regmap_config = {
+ .reg_bits = 16,
+ .reg_stride = 2,
+ .val_bits = 16,
+ .max_register = 0x7e,
+ .cache_type = REGCACHE_RBTREE,
+
+ .volatile_reg = regmap_ac97_default_volatile,
+ .readable_reg = ad1980_readable_reg,
+ .writeable_reg = ad1980_writeable_reg,
+
+ .reg_defaults = ad1980_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ad1980_reg_defaults),
};
static const char *ad1980_rec_sel[] = {"Mic", "CD", "NC", "AUX", "Line",
@@ -134,45 +186,8 @@ static const struct snd_soc_dapm_route ad1980_dapm_routes[] = {
{ "HP_OUT_R", NULL, "Playback" },
};
-static unsigned int ac97_read(struct snd_soc_codec *codec,
- unsigned int reg)
-{
- u16 *cache = codec->reg_cache;
-
- switch (reg) {
- case AC97_RESET:
- case AC97_INT_PAGING:
- case AC97_POWERDOWN:
- case AC97_EXTENDED_STATUS:
- case AC97_VENDOR_ID1:
- case AC97_VENDOR_ID2:
- return soc_ac97_ops->read(codec->ac97, reg);
- default:
- reg = reg >> 1;
-
- if (reg >= ARRAY_SIZE(ad1980_reg))
- return -EINVAL;
-
- return cache[reg];
- }
-}
-
-static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
- unsigned int val)
-{
- u16 *cache = codec->reg_cache;
-
- soc_ac97_ops->write(codec->ac97, reg, val);
- reg = reg >> 1;
- if (reg < ARRAY_SIZE(ad1980_reg))
- cache[reg] = val;
-
- return 0;
-}
-
static struct snd_soc_dai_driver ad1980_dai = {
.name = "ad1980-hifi",
- .ac97_control = 1,
.playback = {
.stream_name = "Playback",
.channels_min = 2,
@@ -189,108 +204,115 @@ static struct snd_soc_dai_driver ad1980_dai = {
static int ad1980_reset(struct snd_soc_codec *codec, int try_warm)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
unsigned int retry_cnt = 0;
do {
if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(codec->ac97);
- if (ac97_read(codec, AC97_RESET) == 0x0090)
+ soc_ac97_ops->warm_reset(ac97);
+ if (snd_soc_read(codec, AC97_RESET) == 0x0090)
return 1;
}
- soc_ac97_ops->reset(codec->ac97);
+ soc_ac97_ops->reset(ac97);
/*
* Set bit 16slot in register 74h, then every slot will has only
* 16 bits. This command is sent out in 20bit mode, in which
* case the first nibble of data is eaten by the addr. (Tag is
* always 16 bit)
*/
- ac97_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
+ snd_soc_write(codec, AC97_AD_SERIAL_CFG, 0x9900);
- if (ac97_read(codec, AC97_RESET) == 0x0090)
+ if (snd_soc_read(codec, AC97_RESET) == 0x0090)
return 0;
} while (retry_cnt++ < 10);
- printk(KERN_ERR "AD1980 AC97 reset failed\n");
+ dev_err(codec->dev, "Failed to reset: AC97 link error\n");
+
return -EIO;
}
static int ad1980_soc_probe(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97;
+ struct regmap *regmap;
int ret;
u16 vendor_id2;
u16 ext_status;
- printk(KERN_INFO "AD1980 SoC Audio Codec\n");
-
- ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
- if (ret < 0) {
- printk(KERN_ERR "ad1980: failed to register AC97 codec\n");
+ ac97 = snd_soc_new_ac97_codec(codec);
+ if (IS_ERR(ac97)) {
+ ret = PTR_ERR(ac97);
+ dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
return ret;
}
+ regmap = regmap_init_ac97(ac97, &ad1980_regmap_config);
+ if (IS_ERR(regmap)) {
+ ret = PTR_ERR(regmap);
+ goto err_free_ac97;
+ }
+
+ snd_soc_codec_init_regmap(codec, regmap);
+ snd_soc_codec_set_drvdata(codec, ac97);
+
ret = ad1980_reset(codec, 0);
- if (ret < 0) {
- printk(KERN_ERR "Failed to reset AD1980: AC97 link error\n");
+ if (ret < 0)
goto reset_err;
- }
/* Read out vendor ID to make sure it is ad1980 */
- if (ac97_read(codec, AC97_VENDOR_ID1) != 0x4144) {
+ if (snd_soc_read(codec, AC97_VENDOR_ID1) != 0x4144) {
ret = -ENODEV;
goto reset_err;
}
- vendor_id2 = ac97_read(codec, AC97_VENDOR_ID2);
+ vendor_id2 = snd_soc_read(codec, AC97_VENDOR_ID2);
if (vendor_id2 != 0x5370) {
if (vendor_id2 != 0x5374) {
ret = -ENODEV;
goto reset_err;
} else {
- printk(KERN_WARNING "ad1980: "
- "Found AD1981 - only 2/2 IN/OUT Channels "
- "supported\n");
+ dev_warn(codec->dev,
+ "Found AD1981 - only 2/2 IN/OUT Channels supported\n");
}
}
/* unmute captures and playbacks volume */
- ac97_write(codec, AC97_MASTER, 0x0000);
- ac97_write(codec, AC97_PCM, 0x0000);
- ac97_write(codec, AC97_REC_GAIN, 0x0000);
- ac97_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
- ac97_write(codec, AC97_SURROUND_MASTER, 0x0000);
+ snd_soc_write(codec, AC97_MASTER, 0x0000);
+ snd_soc_write(codec, AC97_PCM, 0x0000);
+ snd_soc_write(codec, AC97_REC_GAIN, 0x0000);
+ snd_soc_write(codec, AC97_CENTER_LFE_MASTER, 0x0000);
+ snd_soc_write(codec, AC97_SURROUND_MASTER, 0x0000);
/*power on LFE/CENTER/Surround DACs*/
- ext_status = ac97_read(codec, AC97_EXTENDED_STATUS);
- ac97_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
-
- snd_soc_add_codec_controls(codec, ad1980_snd_ac97_controls,
- ARRAY_SIZE(ad1980_snd_ac97_controls));
+ ext_status = snd_soc_read(codec, AC97_EXTENDED_STATUS);
+ snd_soc_write(codec, AC97_EXTENDED_STATUS, ext_status&~0x3800);
return 0;
reset_err:
- snd_soc_free_ac97_codec(codec);
+ snd_soc_codec_exit_regmap(codec);
+err_free_ac97:
+ snd_soc_free_ac97_codec(ac97);
return ret;
}
static int ad1980_soc_remove(struct snd_soc_codec *codec)
{
- snd_soc_free_ac97_codec(codec);
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_codec_exit_regmap(codec);
+ snd_soc_free_ac97_codec(ac97);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_ad1980 = {
.probe = ad1980_soc_probe,
.remove = ad1980_soc_remove,
- .reg_cache_size = ARRAY_SIZE(ad1980_reg),
- .reg_word_size = sizeof(u16),
- .reg_cache_default = ad1980_reg,
- .reg_cache_step = 2,
- .write = ac97_write,
- .read = ac97_read,
+ .controls = ad1980_snd_ac97_controls,
+ .num_controls = ARRAY_SIZE(ad1980_snd_ac97_controls),
.dapm_widgets = ad1980_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ad1980_dapm_widgets),
.dapm_routes = ad1980_dapm_routes,
diff --git a/sound/soc/codecs/ad1980.h b/sound/soc/codecs/ad1980.h
deleted file mode 100644
index eb0af44..0000000
--- a/sound/soc/codecs/ad1980.h
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * ad1980.h -- ad1980 Soc Audio driver
- *
- * WARNING:
- *
- * Because Analog Devices Inc. discontinued the ad1980 sound chip since
- * Sep. 2009, this ad1980 driver is not maintained, tested and supported
- * by ADI now.
- */
-
-#ifndef _AD1980_H
-#define _AD1980_H
-/* Bit definition of Power-Down Control/Status Register */
-#define ADC 0x0001
-#define DAC 0x0002
-#define ANL 0x0004
-#define REF 0x0008
-#define PR0 0x0100
-#define PR1 0x0200
-#define PR2 0x0400
-#define PR3 0x0800
-#define PR4 0x1000
-#define PR5 0x2000
-#define PR6 0x4000
-
-#endif
diff --git a/sound/soc/codecs/adau1373.c b/sound/soc/codecs/adau1373.c
index 7c784ad..783dcb5 100644
--- a/sound/soc/codecs/adau1373.c
+++ b/sound/soc/codecs/adau1373.c
@@ -551,7 +551,7 @@ static const struct snd_kcontrol_new adau1373_drc_controls[] = {
static int adau1373_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int pll_id = w->name[3] - '1';
unsigned int val;
@@ -823,7 +823,7 @@ static const struct snd_soc_dapm_widget adau1373_dapm_widgets[] = {
static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
- struct snd_soc_codec *codec = source->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int dai;
const char *clk;
@@ -844,7 +844,7 @@ static int adau1373_check_aif_clk(struct snd_soc_dapm_widget *source,
static int adau1373_check_src(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
- struct snd_soc_codec *codec = source->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct adau1373 *adau1373 = snd_soc_codec_get_drvdata(codec);
unsigned int dai;
diff --git a/sound/soc/codecs/adau1701.c b/sound/soc/codecs/adau1701.c
index 370b742..d4e219b 100644
--- a/sound/soc/codecs/adau1701.c
+++ b/sound/soc/codecs/adau1701.c
@@ -22,9 +22,14 @@
#include <sound/pcm_params.h>
#include <sound/soc.h>
+#include <asm/unaligned.h>
+
#include "sigmadsp.h"
#include "adau1701.h"
+#define ADAU1701_SAFELOAD_DATA(i) (0x0810 + (i))
+#define ADAU1701_SAFELOAD_ADDR(i) (0x0815 + (i))
+
#define ADAU1701_DSPCTRL 0x081c
#define ADAU1701_SEROCTL 0x081e
#define ADAU1701_SERICTL 0x081f
@@ -42,6 +47,7 @@
#define ADAU1701_DSPCTRL_CR (1 << 2)
#define ADAU1701_DSPCTRL_DAM (1 << 3)
#define ADAU1701_DSPCTRL_ADM (1 << 4)
+#define ADAU1701_DSPCTRL_IST (1 << 5)
#define ADAU1701_DSPCTRL_SR_48 0x00
#define ADAU1701_DSPCTRL_SR_96 0x01
#define ADAU1701_DSPCTRL_SR_192 0x02
@@ -102,7 +108,10 @@ struct adau1701 {
unsigned int pll_clkdiv;
unsigned int sysclk;
struct regmap *regmap;
+ struct i2c_client *client;
u8 pin_config[12];
+
+ struct sigmadsp *sigmadsp;
};
static const struct snd_kcontrol_new adau1701_controls[] = {
@@ -159,6 +168,7 @@ static bool adau1701_volatile_reg(struct device *dev, unsigned int reg)
{
switch (reg) {
case ADAU1701_DACSET:
+ case ADAU1701_DSPCTRL:
return true;
default:
return false;
@@ -238,12 +248,58 @@ static int adau1701_reg_read(void *context, unsigned int reg,
return 0;
}
-static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
+static int adau1701_safeload(struct sigmadsp *sigmadsp, unsigned int addr,
+ const uint8_t bytes[], size_t len)
+{
+ struct i2c_client *client = to_i2c_client(sigmadsp->dev);
+ struct adau1701 *adau1701 = i2c_get_clientdata(client);
+ unsigned int val;
+ unsigned int i;
+ uint8_t buf[10];
+ int ret;
+
+ ret = regmap_read(adau1701->regmap, ADAU1701_DSPCTRL, &val);
+ if (ret)
+ return ret;
+
+ if (val & ADAU1701_DSPCTRL_IST)
+ msleep(50);
+
+ for (i = 0; i < len / 4; i++) {
+ put_unaligned_le16(ADAU1701_SAFELOAD_DATA(i), buf);
+ buf[2] = 0x00;
+ memcpy(buf + 3, bytes + i * 4, 4);
+ ret = i2c_master_send(client, buf, 7);
+ if (ret < 0)
+ return ret;
+ else if (ret != 7)
+ return -EIO;
+
+ put_unaligned_le16(ADAU1701_SAFELOAD_ADDR(i), buf);
+ put_unaligned_le16(addr + i, buf + 2);
+ ret = i2c_master_send(client, buf, 4);
+ if (ret < 0)
+ return ret;
+ else if (ret != 4)
+ return -EIO;
+ }
+
+ return regmap_update_bits(adau1701->regmap, ADAU1701_DSPCTRL,
+ ADAU1701_DSPCTRL_IST, ADAU1701_DSPCTRL_IST);
+}
+
+static const struct sigmadsp_ops adau1701_sigmadsp_ops = {
+ .safeload = adau1701_safeload,
+};
+
+static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv,
+ unsigned int rate)
{
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
- struct i2c_client *client = to_i2c_client(codec->dev);
int ret;
+ sigmadsp_reset(adau1701->sigmadsp);
+
if (clkdiv != ADAU1707_CLKDIV_UNSET &&
gpio_is_valid(adau1701->gpio_pll_mode[0]) &&
gpio_is_valid(adau1701->gpio_pll_mode[1])) {
@@ -284,7 +340,7 @@ static int adau1701_reset(struct snd_soc_codec *codec, unsigned int clkdiv)
* know the correct PLL setup
*/
if (clkdiv != ADAU1707_CLKDIV_UNSET) {
- ret = process_sigma_firmware(client, ADAU1701_FIRMWARE);
+ ret = sigmadsp_setup(adau1701->sigmadsp, rate);
if (ret) {
dev_warn(codec->dev, "Failed to load firmware\n");
return ret;
@@ -385,7 +441,7 @@ static int adau1701_hw_params(struct snd_pcm_substream *substream,
* firmware upload.
*/
if (clkdiv != adau1701->pll_clkdiv) {
- ret = adau1701_reset(codec, clkdiv);
+ ret = adau1701_reset(codec, clkdiv, params_rate(params));
if (ret < 0)
return ret;
}
@@ -554,6 +610,14 @@ static int adau1701_set_sysclk(struct snd_soc_codec *codec, int clk_id,
return 0;
}
+static int adau1701_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(dai->codec);
+
+ return sigmadsp_restrict_params(adau1701->sigmadsp, substream);
+}
+
#define ADAU1701_RATES (SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_96000 | \
SNDRV_PCM_RATE_192000)
@@ -564,6 +628,7 @@ static const struct snd_soc_dai_ops adau1701_dai_ops = {
.set_fmt = adau1701_set_dai_fmt,
.hw_params = adau1701_hw_params,
.digital_mute = adau1701_digital_mute,
+ .startup = adau1701_startup,
};
static struct snd_soc_dai_driver adau1701_dai = {
@@ -600,6 +665,10 @@ static int adau1701_probe(struct snd_soc_codec *codec)
unsigned int val;
struct adau1701 *adau1701 = snd_soc_codec_get_drvdata(codec);
+ ret = sigmadsp_attach(adau1701->sigmadsp, &codec->component);
+ if (ret)
+ return ret;
+
/*
* Let the pll_clkdiv variable default to something that won't happen
* at runtime. That way, we can postpone the firmware download from
@@ -609,7 +678,7 @@ static int adau1701_probe(struct snd_soc_codec *codec)
adau1701->pll_clkdiv = ADAU1707_CLKDIV_UNSET;
/* initalize with pre-configured pll mode settings */
- ret = adau1701_reset(codec, adau1701->pll_clkdiv);
+ ret = adau1701_reset(codec, adau1701->pll_clkdiv, 0);
if (ret < 0)
return ret;
@@ -667,6 +736,7 @@ static int adau1701_i2c_probe(struct i2c_client *client,
if (!adau1701)
return -ENOMEM;
+ adau1701->client = client;
adau1701->regmap = devm_regmap_init(dev, NULL, client,
&adau1701_regmap);
if (IS_ERR(adau1701->regmap))
@@ -722,6 +792,12 @@ static int adau1701_i2c_probe(struct i2c_client *client,
adau1701->gpio_pll_mode[1] = gpio_pll_mode[1];
i2c_set_clientdata(client, adau1701);
+
+ adau1701->sigmadsp = devm_sigmadsp_init_i2c(client,
+ &adau1701_sigmadsp_ops, ADAU1701_FIRMWARE);
+ if (IS_ERR(adau1701->sigmadsp))
+ return PTR_ERR(adau1701->sigmadsp);
+
ret = snd_soc_register_codec(&client->dev, &adau1701_codec_drv,
&adau1701_dai, 1);
return ret;
diff --git a/sound/soc/codecs/adau1761.c b/sound/soc/codecs/adau1761.c
index 91f6028..a1baeee 100644
--- a/sound/soc/codecs/adau1761.c
+++ b/sound/soc/codecs/adau1761.c
@@ -255,7 +255,8 @@ static const struct snd_kcontrol_new adau1761_input_mux_control =
static int adau1761_dejitter_fixup(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
/* After any power changes have been made the dejitter circuit
* has to be reinitialized. */
@@ -702,11 +703,6 @@ static int adau1761_codec_probe(struct snd_soc_codec *codec)
ARRAY_SIZE(adau1761_dapm_routes));
if (ret)
return ret;
-
- ret = adau17x1_load_firmware(adau, codec->dev,
- ADAU1761_FIRMWARE);
- if (ret)
- dev_warn(codec->dev, "Failed to firmware\n");
}
ret = adau17x1_add_routes(codec);
@@ -775,16 +771,20 @@ int adau1761_probe(struct device *dev, struct regmap *regmap,
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
{
struct snd_soc_dai_driver *dai_drv;
+ const char *firmware_name;
int ret;
- ret = adau17x1_probe(dev, regmap, type, switch_mode);
- if (ret)
- return ret;
-
- if (type == ADAU1361)
+ if (type == ADAU1361) {
dai_drv = &adau1361_dai_driver;
- else
+ firmware_name = NULL;
+ } else {
dai_drv = &adau1761_dai_driver;
+ firmware_name = ADAU1761_FIRMWARE;
+ }
+
+ ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
+ if (ret)
+ return ret;
return snd_soc_register_codec(dev, &adau1761_codec_driver, dai_drv, 1);
}
@@ -798,6 +798,7 @@ const struct regmap_config adau1761_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(adau1761_reg_defaults),
.readable_reg = adau1761_readable_register,
.volatile_reg = adau17x1_volatile_register,
+ .precious_reg = adau17x1_precious_register,
.cache_type = REGCACHE_RBTREE,
};
EXPORT_SYMBOL_GPL(adau1761_regmap_config);
diff --git a/sound/soc/codecs/adau1781.c b/sound/soc/codecs/adau1781.c
index e9fc00f..35581f4 100644
--- a/sound/soc/codecs/adau1781.c
+++ b/sound/soc/codecs/adau1781.c
@@ -174,7 +174,7 @@ static const struct snd_kcontrol_new adau1781_mono_mixer_controls[] = {
static int adau1781_dejitter_fixup(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
/* After any power changes have been made the dejitter circuit
@@ -385,7 +385,6 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
{
struct adau1781_platform_data *pdata = dev_get_platdata(codec->dev);
struct adau *adau = snd_soc_codec_get_drvdata(codec);
- const char *firmware;
int ret;
ret = adau17x1_add_widgets(codec);
@@ -422,25 +421,10 @@ static int adau1781_codec_probe(struct snd_soc_codec *codec)
return ret;
}
- switch (adau->type) {
- case ADAU1381:
- firmware = ADAU1381_FIRMWARE;
- break;
- case ADAU1781:
- firmware = ADAU1781_FIRMWARE;
- break;
- default:
- return -EINVAL;
- }
-
ret = adau17x1_add_routes(codec);
if (ret < 0)
return ret;
- ret = adau17x1_load_firmware(adau, codec->dev, firmware);
- if (ret)
- dev_warn(codec->dev, "Failed to load firmware\n");
-
return 0;
}
@@ -488,6 +472,7 @@ const struct regmap_config adau1781_regmap_config = {
.num_reg_defaults = ARRAY_SIZE(adau1781_reg_defaults),
.readable_reg = adau1781_readable_register,
.volatile_reg = adau17x1_volatile_register,
+ .precious_reg = adau17x1_precious_register,
.cache_type = REGCACHE_RBTREE,
};
EXPORT_SYMBOL_GPL(adau1781_regmap_config);
@@ -495,9 +480,21 @@ EXPORT_SYMBOL_GPL(adau1781_regmap_config);
int adau1781_probe(struct device *dev, struct regmap *regmap,
enum adau17x1_type type, void (*switch_mode)(struct device *dev))
{
+ const char *firmware_name;
int ret;
- ret = adau17x1_probe(dev, regmap, type, switch_mode);
+ switch (type) {
+ case ADAU1381:
+ firmware_name = ADAU1381_FIRMWARE;
+ break;
+ case ADAU1781:
+ firmware_name = ADAU1781_FIRMWARE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = adau17x1_probe(dev, regmap, type, switch_mode, firmware_name);
if (ret)
return ret;
diff --git a/sound/soc/codecs/adau17x1.c b/sound/soc/codecs/adau17x1.c
index 3e16c1c..fa2e690 100644
--- a/sound/soc/codecs/adau17x1.c
+++ b/sound/soc/codecs/adau17x1.c
@@ -61,7 +61,8 @@ static const struct snd_kcontrol_new adau17x1_controls[] = {
static int adau17x1_pll_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct adau *adau = snd_soc_codec_get_drvdata(w->codec);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct adau *adau = snd_soc_codec_get_drvdata(codec);
int ret;
if (SND_SOC_DAPM_EVENT_ON(event)) {
@@ -307,6 +308,7 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
struct adau *adau = snd_soc_codec_get_drvdata(codec);
unsigned int val, div, dsp_div;
unsigned int freq;
+ int ret;
if (adau->clk_src == ADAU17X1_CLK_SRC_PLL)
freq = adau->pll_freq;
@@ -356,6 +358,12 @@ static int adau17x1_hw_params(struct snd_pcm_substream *substream,
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, dsp_div);
}
+ if (adau->sigmadsp) {
+ ret = adau17x1_setup_firmware(adau, params_rate(params));
+ if (ret < 0)
+ return ret;
+ }
+
if (adau->dai_fmt != SND_SOC_DAIFMT_RIGHT_J)
return 0;
@@ -661,12 +669,24 @@ static int adau17x1_set_dai_tdm_slot(struct snd_soc_dai *dai,
return 0;
}
+static int adau17x1_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct adau *adau = snd_soc_codec_get_drvdata(dai->codec);
+
+ if (adau->sigmadsp)
+ return sigmadsp_restrict_params(adau->sigmadsp, substream);
+
+ return 0;
+}
+
const struct snd_soc_dai_ops adau17x1_dai_ops = {
.hw_params = adau17x1_hw_params,
.set_sysclk = adau17x1_set_dai_sysclk,
.set_fmt = adau17x1_set_dai_fmt,
.set_pll = adau17x1_set_dai_pll,
.set_tdm_slot = adau17x1_set_dai_tdm_slot,
+ .startup = adau17x1_startup,
};
EXPORT_SYMBOL_GPL(adau17x1_dai_ops);
@@ -687,8 +707,22 @@ int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
}
EXPORT_SYMBOL_GPL(adau17x1_set_micbias_voltage);
+bool adau17x1_precious_register(struct device *dev, unsigned int reg)
+{
+ /* SigmaDSP parameter memory */
+ if (reg < 0x400)
+ return true;
+
+ return false;
+}
+EXPORT_SYMBOL_GPL(adau17x1_precious_register);
+
bool adau17x1_readable_register(struct device *dev, unsigned int reg)
{
+ /* SigmaDSP parameter memory */
+ if (reg < 0x400)
+ return true;
+
switch (reg) {
case ADAU17X1_CLOCK_CONTROL:
case ADAU17X1_PLL_CONTROL:
@@ -745,8 +779,7 @@ bool adau17x1_volatile_register(struct device *dev, unsigned int reg)
}
EXPORT_SYMBOL_GPL(adau17x1_volatile_register);
-int adau17x1_load_firmware(struct adau *adau, struct device *dev,
- const char *firmware)
+int adau17x1_setup_firmware(struct adau *adau, unsigned int rate)
{
int ret;
int dspsr;
@@ -758,7 +791,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 1);
regmap_write(adau->regmap, ADAU17X1_DSP_SAMPLING_RATE, 0xf);
- ret = process_sigma_firmware_regmap(dev, adau->regmap, firmware);
+ ret = sigmadsp_setup(adau->sigmadsp, rate);
if (ret) {
regmap_write(adau->regmap, ADAU17X1_DSP_ENABLE, 0);
return ret;
@@ -767,7 +800,7 @@ int adau17x1_load_firmware(struct adau *adau, struct device *dev,
return 0;
}
-EXPORT_SYMBOL_GPL(adau17x1_load_firmware);
+EXPORT_SYMBOL_GPL(adau17x1_setup_firmware);
int adau17x1_add_widgets(struct snd_soc_codec *codec)
{
@@ -787,8 +820,21 @@ int adau17x1_add_widgets(struct snd_soc_codec *codec)
ret = snd_soc_dapm_new_controls(&codec->dapm,
adau17x1_dsp_dapm_widgets,
ARRAY_SIZE(adau17x1_dsp_dapm_widgets));
+ if (ret)
+ return ret;
+
+ if (!adau->sigmadsp)
+ return 0;
+
+ ret = sigmadsp_attach(adau->sigmadsp, &codec->component);
+ if (ret) {
+ dev_err(codec->dev, "Failed to attach firmware: %d\n",
+ ret);
+ return ret;
+ }
}
- return ret;
+
+ return 0;
}
EXPORT_SYMBOL_GPL(adau17x1_add_widgets);
@@ -829,7 +875,8 @@ int adau17x1_resume(struct snd_soc_codec *codec)
EXPORT_SYMBOL_GPL(adau17x1_resume);
int adau17x1_probe(struct device *dev, struct regmap *regmap,
- enum adau17x1_type type, void (*switch_mode)(struct device *dev))
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev),
+ const char *firmware_name)
{
struct adau *adau;
@@ -846,6 +893,16 @@ int adau17x1_probe(struct device *dev, struct regmap *regmap,
dev_set_drvdata(dev, adau);
+ if (firmware_name) {
+ adau->sigmadsp = devm_sigmadsp_init_regmap(dev, regmap, NULL,
+ firmware_name);
+ if (IS_ERR(adau->sigmadsp)) {
+ dev_warn(dev, "Could not find firmware file: %ld\n",
+ PTR_ERR(adau->sigmadsp));
+ adau->sigmadsp = NULL;
+ }
+ }
+
if (switch_mode)
switch_mode(dev);
diff --git a/sound/soc/codecs/adau17x1.h b/sound/soc/codecs/adau17x1.h
index e4a557f..e13583e 100644
--- a/sound/soc/codecs/adau17x1.h
+++ b/sound/soc/codecs/adau17x1.h
@@ -4,6 +4,8 @@
#include <linux/regmap.h>
#include <linux/platform_data/adau17x1.h>
+#include "sigmadsp.h"
+
enum adau17x1_type {
ADAU1361,
ADAU1761,
@@ -42,22 +44,24 @@ struct adau {
bool dsp_bypass[2];
struct regmap *regmap;
+ struct sigmadsp *sigmadsp;
};
int adau17x1_add_widgets(struct snd_soc_codec *codec);
int adau17x1_add_routes(struct snd_soc_codec *codec);
int adau17x1_probe(struct device *dev, struct regmap *regmap,
- enum adau17x1_type type, void (*switch_mode)(struct device *dev));
+ enum adau17x1_type type, void (*switch_mode)(struct device *dev),
+ const char *firmware_name);
int adau17x1_set_micbias_voltage(struct snd_soc_codec *codec,
enum adau17x1_micbias_voltage micbias);
bool adau17x1_readable_register(struct device *dev, unsigned int reg);
bool adau17x1_volatile_register(struct device *dev, unsigned int reg);
+bool adau17x1_precious_register(struct device *dev, unsigned int reg);
int adau17x1_resume(struct snd_soc_codec *codec);
extern const struct snd_soc_dai_ops adau17x1_dai_ops;
-int adau17x1_load_firmware(struct adau *adau, struct device *dev,
- const char *firmware);
+int adau17x1_setup_firmware(struct adau *adau, unsigned int rate);
bool adau17x1_has_dsp(struct adau *adau);
#define ADAU17X1_CLOCK_CONTROL 0x4000
diff --git a/sound/soc/codecs/adav80x.c b/sound/soc/codecs/adav80x.c
index ce3cdca..b67480f 100644
--- a/sound/soc/codecs/adav80x.c
+++ b/sound/soc/codecs/adav80x.c
@@ -212,7 +212,7 @@ static const struct snd_soc_dapm_widget adav80x_dapm_widgets[] = {
static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
- struct snd_soc_codec *codec = source->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
const char *clk;
@@ -236,7 +236,7 @@ static int adav80x_dapm_sysclk_check(struct snd_soc_dapm_widget *source,
static int adav80x_dapm_pll_check(struct snd_soc_dapm_widget *source,
struct snd_soc_dapm_widget *sink)
{
- struct snd_soc_codec *codec = source->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
struct adav80x *adav80x = snd_soc_codec_get_drvdata(codec);
return adav80x->pll_src == ADAV80X_PLL_SRC_XTAL;
diff --git a/sound/soc/codecs/ak4535.c b/sound/soc/codecs/ak4535.c
index 30e2978..9130d91 100644
--- a/sound/soc/codecs/ak4535.c
+++ b/sound/soc/codecs/ak4535.c
@@ -373,33 +373,9 @@ static struct snd_soc_dai_driver ak4535_dai = {
.ops = &ak4535_dai_ops,
};
-static int ak4535_suspend(struct snd_soc_codec *codec)
-{
- ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int ak4535_resume(struct snd_soc_codec *codec)
{
snd_soc_cache_sync(codec);
- ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
-static int ak4535_probe(struct snd_soc_codec *codec)
-{
- /* power on device */
- ak4535_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- snd_soc_add_codec_controls(codec, ak4535_snd_controls,
- ARRAY_SIZE(ak4535_snd_controls));
- return 0;
-}
-
-/* power down chip */
-static int ak4535_remove(struct snd_soc_codec *codec)
-{
- ak4535_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -416,11 +392,12 @@ static const struct regmap_config ak4535_regmap = {
};
static struct snd_soc_codec_driver soc_codec_dev_ak4535 = {
- .probe = ak4535_probe,
- .remove = ak4535_remove,
- .suspend = ak4535_suspend,
.resume = ak4535_resume,
.set_bias_level = ak4535_set_bias_level,
+ .suspend_bias_off = true,
+
+ .controls = ak4535_snd_controls,
+ .num_controls = ARRAY_SIZE(ak4535_snd_controls),
.dapm_widgets = ak4535_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(ak4535_dapm_widgets),
.dapm_routes = ak4535_audio_map,
diff --git a/sound/soc/codecs/ak4641.c b/sound/soc/codecs/ak4641.c
index 7afe8f4..70861c7 100644
--- a/sound/soc/codecs/ak4641.c
+++ b/sound/soc/codecs/ak4641.c
@@ -505,39 +505,7 @@ static struct snd_soc_dai_driver ak4641_dai[] = {
},
};
-static int ak4641_suspend(struct snd_soc_codec *codec)
-{
- ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int ak4641_resume(struct snd_soc_codec *codec)
-{
- ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
-static int ak4641_probe(struct snd_soc_codec *codec)
-{
- /* power on device */
- ak4641_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int ak4641_remove(struct snd_soc_codec *codec)
-{
- ak4641_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-
static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
- .probe = ak4641_probe,
- .remove = ak4641_remove,
- .suspend = ak4641_suspend,
- .resume = ak4641_resume,
.controls = ak4641_snd_controls,
.num_controls = ARRAY_SIZE(ak4641_snd_controls),
.dapm_widgets = ak4641_dapm_widgets,
@@ -545,6 +513,7 @@ static struct snd_soc_codec_driver soc_codec_dev_ak4641 = {
.dapm_routes = ak4641_audio_map,
.num_dapm_routes = ARRAY_SIZE(ak4641_audio_map),
.set_bias_level = ak4641_set_bias_level,
+ .suspend_bias_off = true,
};
static const struct regmap_config ak4641_regmap = {
diff --git a/sound/soc/codecs/ak4642.c b/sound/soc/codecs/ak4642.c
index 0417125..dde8b49 100644
--- a/sound/soc/codecs/ak4642.c
+++ b/sound/soc/codecs/ak4642.c
@@ -491,23 +491,7 @@ static int ak4642_resume(struct snd_soc_codec *codec)
return 0;
}
-
-static int ak4642_probe(struct snd_soc_codec *codec)
-{
- ak4642_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int ak4642_remove(struct snd_soc_codec *codec)
-{
- ak4642_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_ak4642 = {
- .probe = ak4642_probe,
- .remove = ak4642_remove,
.resume = ak4642_resume,
.set_bias_level = ak4642_set_bias_level,
.controls = ak4642_snd_controls,
diff --git a/sound/soc/codecs/ak4671.c b/sound/soc/codecs/ak4671.c
index 998fa0c..686cacb 100644
--- a/sound/soc/codecs/ak4671.c
+++ b/sound/soc/codecs/ak4671.c
@@ -611,20 +611,7 @@ static struct snd_soc_dai_driver ak4671_dai = {
.ops = &ak4671_dai_ops,
};
-static int ak4671_probe(struct snd_soc_codec *codec)
-{
- return ak4671_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
-static int ak4671_remove(struct snd_soc_codec *codec)
-{
- ak4671_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_ak4671 = {
- .probe = ak4671_probe,
- .remove = ak4671_remove,
.set_bias_level = ak4671_set_bias_level,
.controls = ak4671_snd_controls,
.num_controls = ARRAY_SIZE(ak4671_snd_controls),
diff --git a/sound/soc/codecs/alc5623.c b/sound/soc/codecs/alc5623.c
index 9d0755a..bdf8c5a 100644
--- a/sound/soc/codecs/alc5623.c
+++ b/sound/soc/codecs/alc5623.c
@@ -866,7 +866,6 @@ static int alc5623_suspend(struct snd_soc_codec *codec)
{
struct alc5623_priv *alc5623 = snd_soc_codec_get_drvdata(codec);
- alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
regcache_cache_only(alc5623->regmap, true);
return 0;
@@ -887,15 +886,6 @@ static int alc5623_resume(struct snd_soc_codec *codec)
return ret;
}
- alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- /* charge alc5623 caps */
- if (codec->dapm.suspend_bias_level == SND_SOC_BIAS_ON) {
- alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- codec->dapm.bias_level = SND_SOC_BIAS_ON;
- alc5623_set_bias_level(codec, codec->dapm.bias_level);
- }
-
return 0;
}
@@ -906,9 +896,6 @@ static int alc5623_probe(struct snd_soc_codec *codec)
alc5623_reset(codec);
- /* power on device */
- alc5623_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
if (alc5623->add_ctrl) {
snd_soc_write(codec, ALC5623_ADD_CTRL_REG,
alc5623->add_ctrl);
@@ -964,19 +951,12 @@ static int alc5623_probe(struct snd_soc_codec *codec)
return 0;
}
-/* power down chip */
-static int alc5623_remove(struct snd_soc_codec *codec)
-{
- alc5623_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_device_alc5623 = {
.probe = alc5623_probe,
- .remove = alc5623_remove,
.suspend = alc5623_suspend,
.resume = alc5623_resume,
.set_bias_level = alc5623_set_bias_level,
+ .suspend_bias_off = true,
};
static const struct regmap_config alc5623_regmap = {
diff --git a/sound/soc/codecs/alc5632.c b/sound/soc/codecs/alc5632.c
index 85942ca..d1fdbc2 100644
--- a/sound/soc/codecs/alc5632.c
+++ b/sound/soc/codecs/alc5632.c
@@ -1038,23 +1038,15 @@ static struct snd_soc_dai_driver alc5632_dai = {
};
#ifdef CONFIG_PM
-static int alc5632_suspend(struct snd_soc_codec *codec)
-{
- alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int alc5632_resume(struct snd_soc_codec *codec)
{
struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
regcache_sync(alc5632->regmap);
- alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
#else
-#define alc5632_suspend NULL
#define alc5632_resume NULL
#endif
@@ -1062,9 +1054,6 @@ static int alc5632_probe(struct snd_soc_codec *codec)
{
struct alc5632_priv *alc5632 = snd_soc_codec_get_drvdata(codec);
- /* power on device */
- alc5632_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
switch (alc5632->id) {
case 0x5c:
snd_soc_add_codec_controls(codec, alc5632_vol_snd_controls,
@@ -1077,19 +1066,12 @@ static int alc5632_probe(struct snd_soc_codec *codec)
return 0;
}
-/* power down chip */
-static int alc5632_remove(struct snd_soc_codec *codec)
-{
- alc5632_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_device_alc5632 = {
.probe = alc5632_probe,
- .remove = alc5632_remove,
- .suspend = alc5632_suspend,
.resume = alc5632_resume,
.set_bias_level = alc5632_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = alc5632_snd_controls,
.num_controls = ARRAY_SIZE(alc5632_snd_controls),
.dapm_widgets = alc5632_dapm_widgets,
diff --git a/sound/soc/codecs/arizona.c b/sound/soc/codecs/arizona.c
index 0c05e7a..9550d74 100644
--- a/sound/soc/codecs/arizona.c
+++ b/sound/soc/codecs/arizona.c
@@ -61,6 +61,11 @@
#define ARIZONA_FLL_MIN_OUTDIV 2
#define ARIZONA_FLL_MAX_OUTDIV 7
+#define ARIZONA_FMT_DSP_MODE_A 0
+#define ARIZONA_FMT_DSP_MODE_B 1
+#define ARIZONA_FMT_I2S_MODE 2
+#define ARIZONA_FMT_LEFT_JUSTIFIED_MODE 3
+
#define arizona_fll_err(_fll, fmt, ...) \
dev_err(_fll->arizona->dev, "FLL%d: " fmt, _fll->id, ##__VA_ARGS__)
#define arizona_fll_warn(_fll, fmt, ...) \
@@ -648,7 +653,7 @@ SOC_ENUM_SINGLE_DECL(arizona_in_hpf_cut_enum,
EXPORT_SYMBOL_GPL(arizona_in_hpf_cut_enum);
static const char * const arizona_in_dmic_osr_text[] = {
- "1.536MHz", "3.072MHz", "6.144MHz",
+ "1.536MHz", "3.072MHz", "6.144MHz", "768kHz",
};
const struct soc_enum arizona_in_dmic_osr[] = {
@@ -946,10 +951,26 @@ static int arizona_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
case SND_SOC_DAIFMT_DSP_A:
- mode = 0;
+ mode = ARIZONA_FMT_DSP_MODE_A;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
+ != SND_SOC_DAIFMT_CBM_CFM) {
+ arizona_aif_err(dai, "DSP_B not valid in slave mode\n");
+ return -EINVAL;
+ }
+ mode = ARIZONA_FMT_DSP_MODE_B;
break;
case SND_SOC_DAIFMT_I2S:
- mode = 2;
+ mode = ARIZONA_FMT_I2S_MODE;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ if ((fmt & SND_SOC_DAIFMT_MASTER_MASK)
+ != SND_SOC_DAIFMT_CBM_CFM) {
+ arizona_aif_err(dai, "LEFT_J not valid in slave mode\n");
+ return -EINVAL;
+ }
+ mode = ARIZONA_FMT_LEFT_JUSTIFIED_MODE;
break;
default:
arizona_aif_err(dai, "Unsupported DAI format %d\n",
@@ -1164,13 +1185,13 @@ static void arizona_wm5102_set_dac_comp(struct snd_soc_codec *codec,
{ 0x80, 0x0 },
};
- mutex_lock(&codec->mutex);
+ mutex_lock(&arizona->dac_comp_lock);
dac_comp[1].def = arizona->dac_comp_coeff;
if (rate >= 176400)
dac_comp[2].def = arizona->dac_comp_enabled;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&arizona->dac_comp_lock);
regmap_multi_reg_write(arizona->regmap,
dac_comp,
@@ -1298,7 +1319,8 @@ static int arizona_hw_params(struct snd_pcm_substream *substream,
/* Force multiple of 2 channels for I2S mode */
val = snd_soc_read(codec, base + ARIZONA_AIF_FORMAT);
- if ((channels & 1) && (val & ARIZONA_AIF1_FMT_MASK)) {
+ val &= ARIZONA_AIF1_FMT_MASK;
+ if ((channels & 1) && (val == ARIZONA_FMT_I2S_MODE)) {
arizona_aif_dbg(dai, "Forcing stereo mode\n");
bclk_target /= channels;
bclk_target *= channels + 1;
diff --git a/sound/soc/codecs/cq93vc.c b/sound/soc/codecs/cq93vc.c
index 537327c..8d638e8 100644
--- a/sound/soc/codecs/cq93vc.c
+++ b/sound/soc/codecs/cq93vc.c
@@ -62,14 +62,10 @@ static int cq93vc_mute(struct snd_soc_dai *dai, int mute)
static int cq93vc_set_dai_sysclk(struct snd_soc_dai *codec_dai,
int clk_id, unsigned int freq, int dir)
{
- struct snd_soc_codec *codec = codec_dai->codec;
- struct davinci_vc *davinci_vc = codec->dev->platform_data;
-
switch (freq) {
case 22579200:
case 27000000:
case 33868800:
- davinci_vc->cq93vc.sysclk = freq;
return 0;
}
@@ -126,32 +122,6 @@ static struct snd_soc_dai_driver cq93vc_dai = {
.ops = &cq93vc_dai_ops,
};
-static int cq93vc_resume(struct snd_soc_codec *codec)
-{
- cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int cq93vc_probe(struct snd_soc_codec *codec)
-{
- struct davinci_vc *davinci_vc = codec->dev->platform_data;
-
- davinci_vc->cq93vc.codec = codec;
-
- /* Off, with power on */
- cq93vc_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int cq93vc_remove(struct snd_soc_codec *codec)
-{
- cq93vc_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
static struct regmap *cq93vc_get_regmap(struct device *dev)
{
struct davinci_vc *davinci_vc = dev->platform_data;
@@ -161,9 +131,6 @@ static struct regmap *cq93vc_get_regmap(struct device *dev)
static struct snd_soc_codec_driver soc_codec_dev_cq93vc = {
.set_bias_level = cq93vc_set_bias_level,
- .probe = cq93vc_probe,
- .remove = cq93vc_remove,
- .resume = cq93vc_resume,
.get_regmap = cq93vc_get_regmap,
.controls = cq93vc_snd_controls,
.num_controls = ARRAY_SIZE(cq93vc_snd_controls),
diff --git a/sound/soc/codecs/cs4265.c b/sound/soc/codecs/cs4265.c
index 4fdd47d..ce60868 100644
--- a/sound/soc/codecs/cs4265.c
+++ b/sound/soc/codecs/cs4265.c
@@ -32,7 +32,6 @@
#include "cs4265.h"
struct cs4265_private {
- struct device *dev;
struct regmap *regmap;
struct gpio_desc *reset_gpio;
u8 format;
@@ -598,7 +597,6 @@ static int cs4265_i2c_probe(struct i2c_client *i2c_client,
GFP_KERNEL);
if (cs4265 == NULL)
return -ENOMEM;
- cs4265->dev = &i2c_client->dev;
cs4265->regmap = devm_regmap_init_i2c(i2c_client, &cs4265_regmap);
if (IS_ERR(cs4265->regmap)) {
diff --git a/sound/soc/codecs/cs4271-i2c.c b/sound/soc/codecs/cs4271-i2c.c
new file mode 100644
index 0000000..b264da0
--- /dev/null
+++ b/sound/soc/codecs/cs4271-i2c.c
@@ -0,0 +1,62 @@
+/*
+ * CS4271 I2C audio driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cs4271.h"
+
+static int cs4271_i2c_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct regmap_config config;
+
+ config = cs4271_regmap_config;
+ config.reg_bits = 8;
+ config.val_bits = 8;
+
+ return cs4271_probe(&client->dev,
+ devm_regmap_init_i2c(client, &config));
+}
+
+static int cs4271_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+ return 0;
+}
+
+static const struct i2c_device_id cs4271_i2c_id[] = {
+ { "cs4271", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+
+static struct i2c_driver cs4271_i2c_driver = {
+ .driver = {
+ .name = "cs4271",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cs4271_dt_ids),
+ },
+ .probe = cs4271_i2c_probe,
+ .remove = cs4271_i2c_remove,
+ .id_table = cs4271_i2c_id,
+};
+module_i2c_driver(cs4271_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC CS4271 I2C Driver");
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271-spi.c b/sound/soc/codecs/cs4271-spi.c
new file mode 100644
index 0000000..acd49d8
--- /dev/null
+++ b/sound/soc/codecs/cs4271-spi.c
@@ -0,0 +1,55 @@
+/*
+ * CS4271 SPI audio driver
+ *
+ * Copyright (c) 2010 Alexander Sverdlin <subaparts@yandex.ru>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT 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/spi/spi.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include "cs4271.h"
+
+static int cs4271_spi_probe(struct spi_device *spi)
+{
+ struct regmap_config config;
+
+ config = cs4271_regmap_config;
+ config.reg_bits = 16;
+ config.val_bits = 8;
+ config.read_flag_mask = 0x21;
+ config.write_flag_mask = 0x20;
+
+ return cs4271_probe(&spi->dev, devm_regmap_init_spi(spi, &config));
+}
+
+static int cs4271_spi_remove(struct spi_device *spi)
+{
+ snd_soc_unregister_codec(&spi->dev);
+ return 0;
+}
+
+static struct spi_driver cs4271_spi_driver = {
+ .driver = {
+ .name = "cs4271",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(cs4271_dt_ids),
+ },
+ .probe = cs4271_spi_probe,
+ .remove = cs4271_spi_remove,
+};
+module_spi_driver(cs4271_spi_driver);
+
+MODULE_DESCRIPTION("ASoC CS4271 SPI Driver");
+MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/cs4271.c b/sound/soc/codecs/cs4271.c
index 93cec52..79a4efc 100644
--- a/sound/soc/codecs/cs4271.c
+++ b/sound/soc/codecs/cs4271.c
@@ -23,8 +23,6 @@
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/gpio.h>
-#include <linux/i2c.h>
-#include <linux/spi/spi.h>
#include <linux/of.h>
#include <linux/of_device.h>
#include <linux/of_gpio.h>
@@ -32,6 +30,7 @@
#include <sound/soc.h>
#include <sound/tlv.h>
#include <sound/cs4271.h>
+#include "cs4271.h"
#define CS4271_PCM_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S24_LE | \
@@ -527,14 +526,15 @@ static int cs4271_soc_resume(struct snd_soc_codec *codec)
#endif /* CONFIG_PM */
#ifdef CONFIG_OF
-static const struct of_device_id cs4271_dt_ids[] = {
+const struct of_device_id cs4271_dt_ids[] = {
{ .compatible = "cirrus,cs4271", },
{ }
};
MODULE_DEVICE_TABLE(of, cs4271_dt_ids);
+EXPORT_SYMBOL_GPL(cs4271_dt_ids);
#endif
-static int cs4271_probe(struct snd_soc_codec *codec)
+static int cs4271_codec_probe(struct snd_soc_codec *codec)
{
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
struct cs4271_platform_data *cs4271plat = codec->dev->platform_data;
@@ -587,7 +587,7 @@ static int cs4271_probe(struct snd_soc_codec *codec)
return 0;
}
-static int cs4271_remove(struct snd_soc_codec *codec)
+static int cs4271_codec_remove(struct snd_soc_codec *codec)
{
struct cs4271_private *cs4271 = snd_soc_codec_get_drvdata(codec);
@@ -599,8 +599,8 @@ static int cs4271_remove(struct snd_soc_codec *codec)
};
static struct snd_soc_codec_driver soc_codec_dev_cs4271 = {
- .probe = cs4271_probe,
- .remove = cs4271_remove,
+ .probe = cs4271_codec_probe,
+ .remove = cs4271_codec_remove,
.suspend = cs4271_soc_suspend,
.resume = cs4271_soc_resume,
@@ -642,14 +642,8 @@ static int cs4271_common_probe(struct device *dev,
return 0;
}
-#if defined(CONFIG_SPI_MASTER)
-
-static const struct regmap_config cs4271_spi_regmap = {
- .reg_bits = 16,
- .val_bits = 8,
+const struct regmap_config cs4271_regmap_config = {
.max_register = CS4271_LASTREG,
- .read_flag_mask = 0x21,
- .write_flag_mask = 0x20,
.reg_defaults = cs4271_reg_defaults,
.num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
@@ -657,140 +651,27 @@ static const struct regmap_config cs4271_spi_regmap = {
.volatile_reg = cs4271_volatile_reg,
};
+EXPORT_SYMBOL_GPL(cs4271_regmap_config);
-static int cs4271_spi_probe(struct spi_device *spi)
+int cs4271_probe(struct device *dev, struct regmap *regmap)
{
struct cs4271_private *cs4271;
int ret;
- ret = cs4271_common_probe(&spi->dev, &cs4271);
- if (ret < 0)
- return ret;
-
- spi_set_drvdata(spi, cs4271);
- cs4271->regmap = devm_regmap_init_spi(spi, &cs4271_spi_regmap);
- if (IS_ERR(cs4271->regmap))
- return PTR_ERR(cs4271->regmap);
-
- return snd_soc_register_codec(&spi->dev, &soc_codec_dev_cs4271,
- &cs4271_dai, 1);
-}
-
-static int cs4271_spi_remove(struct spi_device *spi)
-{
- snd_soc_unregister_codec(&spi->dev);
- return 0;
-}
-
-static struct spi_driver cs4271_spi_driver = {
- .driver = {
- .name = "cs4271",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(cs4271_dt_ids),
- },
- .probe = cs4271_spi_probe,
- .remove = cs4271_spi_remove,
-};
-#endif /* defined(CONFIG_SPI_MASTER) */
-
-#if IS_ENABLED(CONFIG_I2C)
-static const struct i2c_device_id cs4271_i2c_id[] = {
- {"cs4271", 0},
- {}
-};
-MODULE_DEVICE_TABLE(i2c, cs4271_i2c_id);
+ if (IS_ERR(regmap))
+ return PTR_ERR(regmap);
-static const struct regmap_config cs4271_i2c_regmap = {
- .reg_bits = 8,
- .val_bits = 8,
- .max_register = CS4271_LASTREG,
-
- .reg_defaults = cs4271_reg_defaults,
- .num_reg_defaults = ARRAY_SIZE(cs4271_reg_defaults),
- .cache_type = REGCACHE_RBTREE,
-
- .volatile_reg = cs4271_volatile_reg,
-};
-
-static int cs4271_i2c_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct cs4271_private *cs4271;
- int ret;
-
- ret = cs4271_common_probe(&client->dev, &cs4271);
+ ret = cs4271_common_probe(dev, &cs4271);
if (ret < 0)
return ret;
- i2c_set_clientdata(client, cs4271);
- cs4271->regmap = devm_regmap_init_i2c(client, &cs4271_i2c_regmap);
- if (IS_ERR(cs4271->regmap))
- return PTR_ERR(cs4271->regmap);
+ dev_set_drvdata(dev, cs4271);
+ cs4271->regmap = regmap;
- return snd_soc_register_codec(&client->dev, &soc_codec_dev_cs4271,
- &cs4271_dai, 1);
-}
-
-static int cs4271_i2c_remove(struct i2c_client *client)
-{
- snd_soc_unregister_codec(&client->dev);
- return 0;
-}
-
-static struct i2c_driver cs4271_i2c_driver = {
- .driver = {
- .name = "cs4271",
- .owner = THIS_MODULE,
- .of_match_table = of_match_ptr(cs4271_dt_ids),
- },
- .id_table = cs4271_i2c_id,
- .probe = cs4271_i2c_probe,
- .remove = cs4271_i2c_remove,
-};
-#endif /* IS_ENABLED(CONFIG_I2C) */
-
-/*
- * We only register our serial bus driver here without
- * assignment to particular chip. So if any of the below
- * fails, there is some problem with I2C or SPI subsystem.
- * In most cases this module will be compiled with support
- * of only one serial bus.
- */
-static int __init cs4271_modinit(void)
-{
- int ret;
-
-#if IS_ENABLED(CONFIG_I2C)
- ret = i2c_add_driver(&cs4271_i2c_driver);
- if (ret) {
- pr_err("Failed to register CS4271 I2C driver: %d\n", ret);
- return ret;
- }
-#endif
-
-#if defined(CONFIG_SPI_MASTER)
- ret = spi_register_driver(&cs4271_spi_driver);
- if (ret) {
- pr_err("Failed to register CS4271 SPI driver: %d\n", ret);
- return ret;
- }
-#endif
-
- return 0;
-}
-module_init(cs4271_modinit);
-
-static void __exit cs4271_modexit(void)
-{
-#if defined(CONFIG_SPI_MASTER)
- spi_unregister_driver(&cs4271_spi_driver);
-#endif
-
-#if IS_ENABLED(CONFIG_I2C)
- i2c_del_driver(&cs4271_i2c_driver);
-#endif
+ return snd_soc_register_codec(dev, &soc_codec_dev_cs4271, &cs4271_dai,
+ 1);
}
-module_exit(cs4271_modexit);
+EXPORT_SYMBOL_GPL(cs4271_probe);
MODULE_AUTHOR("Alexander Sverdlin <subaparts@yandex.ru>");
MODULE_DESCRIPTION("Cirrus Logic CS4271 ALSA SoC Codec Driver");
diff --git a/sound/soc/codecs/cs4271.h b/sound/soc/codecs/cs4271.h
new file mode 100644
index 0000000..9adad8e
--- /dev/null
+++ b/sound/soc/codecs/cs4271.h
@@ -0,0 +1,11 @@
+#ifndef _CS4271_PRIV_H
+#define _CS4271_PRIV_H
+
+#include <linux/regmap.h>
+
+extern const struct of_device_id cs4271_dt_ids[];
+extern const struct regmap_config cs4271_regmap_config;
+
+int cs4271_probe(struct device *dev, struct regmap *regmap);
+
+#endif
diff --git a/sound/soc/codecs/cs42l51.c b/sound/soc/codecs/cs42l51.c
index 669c38f..b395152 100644
--- a/sound/soc/codecs/cs42l51.c
+++ b/sound/soc/codecs/cs42l51.c
@@ -153,15 +153,17 @@ static const struct snd_kcontrol_new cs42l51_snd_controls[] = {
static int cs42l51_pdn_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+
switch (event) {
case SND_SOC_DAPM_PRE_PMD:
- snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+ snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
CS42L51_POWER_CTL1_PDN,
CS42L51_POWER_CTL1_PDN);
break;
default:
case SND_SOC_DAPM_POST_PMD:
- snd_soc_update_bits(w->codec, CS42L51_POWER_CTL1,
+ snd_soc_update_bits(codec, CS42L51_POWER_CTL1,
CS42L51_POWER_CTL1_PDN, 0);
break;
}
diff --git a/sound/soc/codecs/cs42l73.c b/sound/soc/codecs/cs42l73.c
index 2f8b946..7c55537 100644
--- a/sound/soc/codecs/cs42l73.c
+++ b/sound/soc/codecs/cs42l73.c
@@ -584,7 +584,7 @@ static const struct snd_kcontrol_new cs42l73_snd_controls[] = {
static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMD:
@@ -600,7 +600,7 @@ static int cs42l73_spklo_spk_amp_event(struct snd_soc_dapm_widget *w,
static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMD:
@@ -618,7 +618,7 @@ static int cs42l73_ear_amp_event(struct snd_soc_dapm_widget *w,
static int cs42l73_hp_amp_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct cs42l73_private *priv = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMD:
diff --git a/sound/soc/codecs/hdmi.c b/sound/soc/codecs/hdmi.c
index 1087fd5..1391ad5 100644
--- a/sound/soc/codecs/hdmi.c
+++ b/sound/soc/codecs/hdmi.c
@@ -47,6 +47,7 @@ static struct snd_soc_dai_driver hdmi_codec_dai = {
SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000,
.formats = SNDRV_PCM_FMTBIT_S16_LE |
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S32_LE,
+ .sig_bits = 24,
},
.capture = {
.stream_name = "Capture",
@@ -75,6 +76,7 @@ static struct snd_soc_codec_driver hdmi_codec = {
.num_dapm_widgets = ARRAY_SIZE(hdmi_widgets),
.dapm_routes = hdmi_routes,
.num_dapm_routes = ARRAY_SIZE(hdmi_routes),
+ .ignore_pmdown_time = true,
};
static int hdmi_codec_probe(struct platform_device *pdev)
diff --git a/sound/soc/codecs/lm49453.c b/sound/soc/codecs/lm49453.c
index c1ae576..c4dfde9 100644
--- a/sound/soc/codecs/lm49453.c
+++ b/sound/soc/codecs/lm49453.c
@@ -1395,15 +1395,7 @@ static struct snd_soc_dai_driver lm49453_dai[] = {
},
};
-/* power down chip */
-static int lm49453_remove(struct snd_soc_codec *codec)
-{
- lm49453_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_lm49453 = {
- .remove = lm49453_remove,
.set_bias_level = lm49453_set_bias_level,
.controls = lm49453_snd_controls,
.num_controls = ARRAY_SIZE(lm49453_snd_controls),
diff --git a/sound/soc/codecs/max98088.c b/sound/soc/codecs/max98088.c
index 2cd3e54..805b3f8 100644
--- a/sound/soc/codecs/max98088.c
+++ b/sound/soc/codecs/max98088.c
@@ -875,7 +875,7 @@ static const struct snd_kcontrol_new max98088_right_ADC_mixer_controls[] = {
static int max98088_mic_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
switch (event) {
@@ -905,7 +905,7 @@ static int max98088_mic_event(struct snd_soc_dapm_widget *w,
static int max98088_line_pga(struct snd_soc_dapm_widget *w,
int event, int line, u8 channel)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
u8 *state;
@@ -1887,25 +1887,6 @@ static void max98088_handle_pdata(struct snd_soc_codec *codec)
max98088_handle_eq_pdata(codec);
}
-#ifdef CONFIG_PM
-static int max98088_suspend(struct snd_soc_codec *codec)
-{
- max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int max98088_resume(struct snd_soc_codec *codec)
-{
- max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define max98088_suspend NULL
-#define max98088_resume NULL
-#endif
-
static int max98088_probe(struct snd_soc_codec *codec)
{
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
@@ -1946,9 +1927,6 @@ static int max98088_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, M98088_REG_51_PWR_SYS, M98088_PWRSV);
- /* initialize registers cache to hardware default */
- max98088_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
snd_soc_write(codec, M98088_REG_0F_IRQ_ENABLE, 0x00);
snd_soc_write(codec, M98088_REG_22_MIX_DAC,
@@ -1974,7 +1952,6 @@ static int max98088_remove(struct snd_soc_codec *codec)
{
struct max98088_priv *max98088 = snd_soc_codec_get_drvdata(codec);
- max98088_set_bias_level(codec, SND_SOC_BIAS_OFF);
kfree(max98088->eq_texts);
return 0;
@@ -1983,9 +1960,9 @@ static int max98088_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_max98088 = {
.probe = max98088_probe,
.remove = max98088_remove,
- .suspend = max98088_suspend,
- .resume = max98088_resume,
.set_bias_level = max98088_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = max98088_snd_controls,
.num_controls = ARRAY_SIZE(max98088_snd_controls),
.dapm_widgets = max98088_dapm_widgets,
diff --git a/sound/soc/codecs/max98090.c b/sound/soc/codecs/max98090.c
index 1229554..151f718 100644
--- a/sound/soc/codecs/max98090.c
+++ b/sound/soc/codecs/max98090.c
@@ -806,7 +806,7 @@ static const struct snd_kcontrol_new max98091_snd_controls[] = {
static int max98090_micinput_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
unsigned int val = snd_soc_read(codec, w->reg);
@@ -1311,6 +1311,10 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"MIC1 Input", NULL, "MIC1"},
{"MIC2 Input", NULL, "MIC2"},
+ {"DMICL", NULL, "DMICL_ENA"},
+ {"DMICL", NULL, "DMICR_ENA"},
+ {"DMICR", NULL, "DMICL_ENA"},
+ {"DMICR", NULL, "DMICR_ENA"},
{"DMICL", NULL, "AHPF"},
{"DMICR", NULL, "AHPF"},
@@ -1368,8 +1372,6 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"DMIC Mux", "ADC", "ADCR"},
{"DMIC Mux", "DMIC", "DMICL"},
{"DMIC Mux", "DMIC", "DMICR"},
- {"DMIC Mux", "DMIC", "DMICL_ENA"},
- {"DMIC Mux", "DMIC", "DMICR_ENA"},
{"LBENL Mux", "Normal", "DMIC Mux"},
{"LBENL Mux", "Loopback", "LTENL Mux"},
@@ -1395,8 +1397,8 @@ static const struct snd_soc_dapm_route max98090_dapm_routes[] = {
{"STENL Mux", "Sidetone Left", "DMICL"},
{"STENR Mux", "Sidetone Right", "ADCR"},
{"STENR Mux", "Sidetone Right", "DMICR"},
- {"DACL", "NULL", "STENL Mux"},
- {"DACR", "NULL", "STENL Mux"},
+ {"DACL", NULL, "STENL Mux"},
+ {"DACR", NULL, "STENR Mux"},
{"AIFINL", NULL, "SHDN"},
{"AIFINR", NULL, "SHDN"},
@@ -1826,27 +1828,155 @@ static int max98090_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static const int comp_pclk_rates[] = {
- 11289600, 12288000, 12000000, 13000000, 19200000
-};
-
-static const int dmic_micclk[] = {
- 2, 2, 2, 2, 4, 2
-};
+static const int dmic_divisors[] = { 2, 3, 4, 5, 6, 8 };
static const int comp_lrclk_rates[] = {
8000, 16000, 32000, 44100, 48000, 96000
};
-static const int dmic_comp[6][6] = {
- {7, 8, 3, 3, 3, 3},
- {7, 8, 3, 3, 3, 3},
- {7, 8, 3, 3, 3, 3},
- {7, 8, 3, 1, 1, 1},
- {7, 8, 3, 1, 2, 2},
- {7, 8, 3, 3, 3, 3}
+struct dmic_table {
+ int pclk;
+ struct {
+ int freq;
+ int comp[6]; /* One each for 8, 16, 32, 44.1, 48, and 96 kHz */
+ } settings[6]; /* One for each dmic divisor. */
};
+static const struct dmic_table dmic_table[] = { /* One for each pclk freq. */
+ {
+ .pclk = 11289600,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ },
+ },
+ {
+ .pclk = 12000000,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ }
+ },
+ {
+ .pclk = 12288000,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 1, .comp = { 7, 8, 2, 2, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 6, 6, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 3, 3, 3, 3 } },
+ }
+ },
+ {
+ .pclk = 13000000,
+ .settings = {
+ { .freq = 2, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 1, .comp = { 7, 8, 0, 0, 0, 0 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 0, .comp = { 7, 8, 4, 4, 5, 5 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 1, 1 } },
+ }
+ },
+ {
+ .pclk = 19200000,
+ .settings = {
+ { .freq = 2, .comp = { 0, 0, 0, 0, 0, 0 } },
+ { .freq = 1, .comp = { 7, 8, 1, 1, 1, 1 } },
+ { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+ { .freq = 0, .comp = { 7, 8, 2, 2, 3, 3 } },
+ { .freq = 0, .comp = { 7, 8, 1, 1, 2, 2 } },
+ { .freq = 0, .comp = { 7, 8, 5, 5, 6, 6 } },
+ }
+ },
+};
+
+static int max98090_find_divisor(int target_freq, int pclk)
+{
+ int current_diff = INT_MAX;
+ int test_diff = INT_MAX;
+ int divisor_index = 0;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dmic_divisors); i++) {
+ test_diff = abs(target_freq - (pclk / dmic_divisors[i]));
+ if (test_diff < current_diff) {
+ current_diff = test_diff;
+ divisor_index = i;
+ }
+ }
+
+ return divisor_index;
+}
+
+static int max98090_find_closest_pclk(int pclk)
+{
+ int m1;
+ int m2;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(dmic_table); i++) {
+ if (pclk == dmic_table[i].pclk)
+ return i;
+ if (pclk < dmic_table[i].pclk) {
+ if (i == 0)
+ return i;
+ m1 = pclk - dmic_table[i-1].pclk;
+ m2 = dmic_table[i].pclk - pclk;
+ if (m1 < m2)
+ return i - 1;
+ else
+ return i;
+ }
+ }
+
+ return -EINVAL;
+}
+
+static int max98090_configure_dmic(struct max98090_priv *max98090,
+ int target_dmic_clk, int pclk, int fs)
+{
+ int micclk_index;
+ int pclk_index;
+ int dmic_freq;
+ int dmic_comp;
+ int i;
+
+ pclk_index = max98090_find_closest_pclk(pclk);
+ if (pclk_index < 0)
+ return pclk_index;
+
+ micclk_index = max98090_find_divisor(target_dmic_clk, pclk);
+
+ for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
+ if (fs <= (comp_lrclk_rates[i] + comp_lrclk_rates[i+1]) / 2)
+ break;
+ }
+
+ dmic_freq = dmic_table[pclk_index].settings[micclk_index].freq;
+ dmic_comp = dmic_table[pclk_index].settings[micclk_index].comp[i];
+
+ regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_ENABLE,
+ M98090_MICCLK_MASK,
+ micclk_index << M98090_MICCLK_SHIFT);
+
+ regmap_update_bits(max98090->regmap, M98090_REG_DIGITAL_MIC_CONFIG,
+ M98090_DMIC_COMP_MASK | M98090_DMIC_FREQ_MASK,
+ dmic_comp << M98090_DMIC_COMP_SHIFT |
+ dmic_freq << M98090_DMIC_FREQ_SHIFT);
+
+ return 0;
+}
+
static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params,
struct snd_soc_dai *dai)
@@ -1854,7 +1984,6 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
struct snd_soc_codec *codec = dai->codec;
struct max98090_priv *max98090 = snd_soc_codec_get_drvdata(codec);
struct max98090_cdata *cdata;
- int i, j;
cdata = &max98090->dai[0];
max98090->bclk = snd_soc_params_to_bclk(params);
@@ -1893,27 +2022,8 @@ static int max98090_dai_hw_params(struct snd_pcm_substream *substream,
snd_soc_update_bits(codec, M98090_REG_FILTER_CONFIG,
M98090_DHF_MASK, M98090_DHF_MASK);
- /* Check for supported PCLK to LRCLK ratios */
- for (j = 0; j < ARRAY_SIZE(comp_pclk_rates); j++) {
- if (comp_pclk_rates[j] == max98090->sysclk) {
- break;
- }
- }
-
- for (i = 0; i < ARRAY_SIZE(comp_lrclk_rates) - 1; i++) {
- if (max98090->lrclk <= (comp_lrclk_rates[i] +
- comp_lrclk_rates[i + 1]) / 2) {
- break;
- }
- }
-
- snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_ENABLE,
- M98090_MICCLK_MASK,
- dmic_micclk[j] << M98090_MICCLK_SHIFT);
-
- snd_soc_update_bits(codec, M98090_REG_DIGITAL_MIC_CONFIG,
- M98090_DMIC_COMP_MASK,
- dmic_comp[j][i] << M98090_DMIC_COMP_SHIFT);
+ max98090_configure_dmic(max98090, max98090->dmic_freq, max98090->pclk,
+ max98090->lrclk);
return 0;
}
@@ -1944,12 +2054,15 @@ static int max98090_dai_set_sysclk(struct snd_soc_dai *dai,
if ((freq >= 10000000) && (freq <= 20000000)) {
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV1);
+ max98090->pclk = freq;
} else if ((freq > 20000000) && (freq <= 40000000)) {
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV2);
+ max98090->pclk = freq >> 1;
} else if ((freq > 40000000) && (freq <= 60000000)) {
snd_soc_write(codec, M98090_REG_SYSTEM_CLOCK,
M98090_PSCLK_DIV4);
+ max98090->pclk = freq >> 2;
} else {
dev_err(codec->dev, "Invalid master clock frequency\n");
return -EINVAL;
@@ -2324,6 +2437,7 @@ static int max98090_probe(struct snd_soc_codec *codec)
/* Initialize private data */
max98090->sysclk = (unsigned)-1;
+ max98090->pclk = (unsigned)-1;
max98090->master = false;
cdata = &max98090->dai[0];
@@ -2463,6 +2577,11 @@ static int max98090_i2c_probe(struct i2c_client *i2c,
i2c_set_clientdata(i2c, max98090);
max98090->pdata = i2c->dev.platform_data;
+ ret = of_property_read_u32(i2c->dev.of_node, "maxim,dmic-freq",
+ &max98090->dmic_freq);
+ if (ret < 0)
+ max98090->dmic_freq = MAX98090_DEFAULT_DMIC_FREQ;
+
max98090->regmap = devm_regmap_init_i2c(i2c, &max98090_regmap);
if (IS_ERR(max98090->regmap)) {
ret = PTR_ERR(max98090->regmap);
diff --git a/sound/soc/codecs/max98090.h b/sound/soc/codecs/max98090.h
index a5f6bad..21ff743 100644
--- a/sound/soc/codecs/max98090.h
+++ b/sound/soc/codecs/max98090.h
@@ -12,6 +12,12 @@
#define _MAX98090_H
/*
+ * The default operating frequency for a DMIC attached to the codec.
+ * This can be overridden by a device tree property.
+ */
+#define MAX98090_DEFAULT_DMIC_FREQ 2500000
+
+/*
* MAX98090 Register Definitions
*/
@@ -1518,8 +1524,10 @@ struct max98090_priv {
struct max98090_pdata *pdata;
struct clk *mclk;
unsigned int sysclk;
+ unsigned int pclk;
unsigned int bclk;
unsigned int lrclk;
+ u32 dmic_freq;
struct max98090_cdata dai[1];
int jack_state;
struct delayed_work jack_work;
diff --git a/sound/soc/codecs/max98095.c b/sound/soc/codecs/max98095.c
index 0ee6797..8fba0c3 100644
--- a/sound/soc/codecs/max98095.c
+++ b/sound/soc/codecs/max98095.c
@@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/clk.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -57,6 +58,7 @@ struct max98095_priv {
unsigned int mic2pre;
struct snd_soc_jack *headphone_jack;
struct snd_soc_jack *mic_jack;
+ struct mutex lock;
};
static const struct reg_default max98095_reg_def[] = {
@@ -864,7 +866,7 @@ static const struct snd_kcontrol_new max98095_right_ADC_mixer_controls[] = {
static int max98095_mic_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
switch (event) {
@@ -894,7 +896,7 @@ static int max98095_mic_event(struct snd_soc_dapm_widget *w,
static int max98095_line_pga(struct snd_soc_dapm_widget *w,
int event, u8 channel)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
u8 *state;
@@ -942,7 +944,7 @@ static int max98095_pga_in2_event(struct snd_soc_dapm_widget *w,
static int max98095_lineout_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
- struct snd_soc_codec *codec = w->codec;
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
@@ -1803,7 +1805,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
- mutex_lock(&codec->mutex);
+ mutex_lock(&max98095->lock);
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
m98095_eq_band(codec, channel, 0, coef_set->band1);
m98095_eq_band(codec, channel, 1, coef_set->band2);
@@ -1811,7 +1813,7 @@ static int max98095_put_eq_enum(struct snd_kcontrol *kcontrol,
m98095_eq_band(codec, channel, 3, coef_set->band4);
m98095_eq_band(codec, channel, 4, coef_set->band5);
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&max98095->lock);
/* Restore the original on/off state */
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
@@ -1957,12 +1959,12 @@ static int max98095_put_bq_enum(struct snd_kcontrol *kcontrol,
regsave = snd_soc_read(codec, M98095_088_CFG_LEVEL);
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, 0);
- mutex_lock(&codec->mutex);
+ mutex_lock(&max98095->lock);
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, M98095_SEG);
m98095_biquad_band(codec, channel, 0, coef_set->band1);
m98095_biquad_band(codec, channel, 1, coef_set->band2);
snd_soc_update_bits(codec, M98095_00F_HOST_CFG, M98095_SEG, 0);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&max98095->lock);
/* Restore the original on/off state */
snd_soc_update_bits(codec, M98095_088_CFG_LEVEL, regmask, regsave);
@@ -2317,9 +2319,6 @@ static int max98095_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, M98095_097_PWR_SYS, M98095_PWRSV);
- /* initialize registers cache to hardware default */
- max98095_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
snd_soc_write(codec, M98095_048_MIX_DAC_LR,
M98095_DAI1L_TO_DACL|M98095_DAI1R_TO_DACR);
@@ -2359,8 +2358,6 @@ static int max98095_remove(struct snd_soc_codec *codec)
struct max98095_priv *max98095 = snd_soc_codec_get_drvdata(codec);
struct i2c_client *client = to_i2c_client(codec->dev);
- max98095_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
if (max98095->headphone_jack || max98095->mic_jack)
max98095_jack_detect_disable(codec);
@@ -2395,6 +2392,8 @@ static int max98095_i2c_probe(struct i2c_client *i2c,
if (max98095 == NULL)
return -ENOMEM;
+ mutex_init(&max98095->lock);
+
max98095->regmap = devm_regmap_init_i2c(i2c, &max98095_regmap);
if (IS_ERR(max98095->regmap)) {
ret = PTR_ERR(max98095->regmap);
diff --git a/sound/soc/codecs/max9850.c b/sound/soc/codecs/max9850.c
index 4fdf5aa..10f8e47 100644
--- a/sound/soc/codecs/max9850.c
+++ b/sound/soc/codecs/max9850.c
@@ -291,25 +291,6 @@ static struct snd_soc_dai_driver max9850_dai = {
.ops = &max9850_dai_ops,
};
-#ifdef CONFIG_PM
-static int max9850_suspend(struct snd_soc_codec *codec)
-{
- max9850_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int max9850_resume(struct snd_soc_codec *codec)
-{
- max9850_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define max9850_suspend NULL
-#define max9850_resume NULL
-#endif
-
static int max9850_probe(struct snd_soc_codec *codec)
{
/* enable zero-detect */
@@ -324,9 +305,8 @@ static int max9850_probe(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_max9850 = {
.probe = max9850_probe,
- .suspend = max9850_suspend,
- .resume = max9850_resume,
.set_bias_level = max9850_set_bias_level,
+ .suspend_bias_off = true,
.controls = max9850_controls,
.num_controls = ARRAY_SIZE(max9850_controls),
diff --git a/sound/soc/codecs/rt286.c b/sound/soc/codecs/rt286.c
index 4aa555c..2cd4fe4 100644
--- a/sound/soc/codecs/rt286.c
+++ b/sound/soc/codecs/rt286.c
@@ -17,6 +17,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/dmi.h>
#include <linux/acpi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -36,11 +37,13 @@
struct rt286_priv {
struct regmap *regmap;
+ struct snd_soc_codec *codec;
struct rt286_platform_data pdata;
struct i2c_client *i2c;
struct snd_soc_jack *jack;
struct delayed_work jack_detect_work;
int sys_clk;
+ int clk_id;
struct reg_default *index_cache;
};
@@ -188,7 +191,7 @@ static int rt286_hw_write(void *context, unsigned int reg, unsigned int value)
u8 data[4];
int ret, i;
- /*handle index registers*/
+ /* handle index registers */
if (reg <= 0xff) {
rt286_hw_write(client, RT286_COEF_INDEX, reg);
for (i = 0; i < INDEX_CACHE_SIZE; i++) {
@@ -231,7 +234,7 @@ static int rt286_hw_read(void *context, unsigned int reg, unsigned int *value)
__be32 be_reg;
unsigned int index, vid, buf = 0x0;
- /*handle index registers*/
+ /* handle index registers */
if (reg <= 0xff) {
rt286_hw_write(client, RT286_COEF_INDEX, reg);
reg = RT286_PROC_COEF;
@@ -298,7 +301,6 @@ static int rt286_support_power_controls[] = {
static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
{
unsigned int val, buf;
- int i;
*hp = false;
*mic = false;
@@ -309,67 +311,44 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
if (*hp) {
/* power on HV,VERF */
regmap_update_bits(rt286->regmap,
- RT286_POWER_CTRL1, 0x1001, 0x0);
+ RT286_DC_GAIN, 0x200, 0x200);
+
+ snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
+ "HV");
+ snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
+ "VREF");
/* power LDO1 */
- regmap_update_bits(rt286->regmap,
- RT286_POWER_CTRL2, 0x4, 0x4);
- regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
- regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
+ snd_soc_dapm_force_enable_pin(&rt286->codec->dapm,
+ "LDO1");
+ snd_soc_dapm_sync(&rt286->codec->dapm);
- msleep(200);
- i = 40;
- while (((val & 0x0800) == 0) && (i > 0)) {
- regmap_read(rt286->regmap,
- RT286_CBJ_CTRL2, &val);
- i--;
- msleep(20);
- }
+ regmap_write(rt286->regmap, RT286_SET_MIC1, 0x24);
+ msleep(50);
- if (0x0400 == (val & 0x0700)) {
- *mic = false;
+ regmap_update_bits(rt286->regmap,
+ RT286_CBJ_CTRL1, 0xfcc0, 0xd400);
+ msleep(300);
+ regmap_read(rt286->regmap, RT286_CBJ_CTRL2, &val);
- regmap_write(rt286->regmap,
- RT286_SET_MIC1, 0x20);
- /* power off HV,VERF */
- regmap_update_bits(rt286->regmap,
- RT286_POWER_CTRL1, 0x1001, 0x1001);
- regmap_update_bits(rt286->regmap,
- RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
- regmap_update_bits(rt286->regmap,
- RT286_CBJ_CTRL1, 0x0030, 0x0000);
- regmap_update_bits(rt286->regmap,
- RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
- } else if ((0x0200 == (val & 0x0700)) ||
- (0x0100 == (val & 0x0700))) {
+ if (0x0070 == (val & 0x0070)) {
*mic = true;
- regmap_update_bits(rt286->regmap,
- RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
- regmap_update_bits(rt286->regmap,
- RT286_CBJ_CTRL1, 0x0030, 0x0020);
- regmap_update_bits(rt286->regmap,
- RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
} else {
- *mic = false;
+ regmap_update_bits(rt286->regmap,
+ RT286_CBJ_CTRL1, 0xfcc0, 0xe400);
+ msleep(300);
+ regmap_read(rt286->regmap,
+ RT286_CBJ_CTRL2, &val);
+ if (0x0070 == (val & 0x0070))
+ *mic = true;
+ else
+ *mic = false;
}
-
- regmap_update_bits(rt286->regmap,
- RT286_MISC_CTRL1,
- 0x0060, 0x0000);
- } else {
- regmap_update_bits(rt286->regmap,
- RT286_MISC_CTRL1,
- 0x0060, 0x0020);
regmap_update_bits(rt286->regmap,
- RT286_A_BIAS_CTRL3,
- 0xc000, 0x8000);
- regmap_update_bits(rt286->regmap,
- RT286_CBJ_CTRL1,
- 0x0030, 0x0020);
- regmap_update_bits(rt286->regmap,
- RT286_A_BIAS_CTRL2,
- 0xc000, 0x8000);
+ RT286_DC_GAIN, 0x200, 0x0);
+ } else {
*mic = false;
+ regmap_write(rt286->regmap, RT286_SET_MIC1, 0x20);
}
} else {
regmap_read(rt286->regmap, RT286_GET_HP_SENSE, &buf);
@@ -378,6 +357,12 @@ static int rt286_jack_detect(struct rt286_priv *rt286, bool *hp, bool *mic)
*mic = buf & 0x80000000;
}
+ snd_soc_dapm_disable_pin(&rt286->codec->dapm, "HV");
+ snd_soc_dapm_disable_pin(&rt286->codec->dapm, "VREF");
+ if (!*hp)
+ snd_soc_dapm_disable_pin(&rt286->codec->dapm, "LDO1");
+ snd_soc_dapm_sync(&rt286->codec->dapm);
+
return 0;
}
@@ -415,6 +400,17 @@ int rt286_mic_detect(struct snd_soc_codec *codec, struct snd_soc_jack *jack)
}
EXPORT_SYMBOL_GPL(rt286_mic_detect);
+static int is_mclk_mode(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(source->codec);
+
+ if (rt286->clk_id == RT286_SCLK_S_MCLK)
+ return 1;
+ else
+ return 0;
+}
+
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -6350, 50, 0);
static const DECLARE_TLV_DB_SCALE(mic_vol_tlv, 0, 1000, 0);
@@ -568,7 +564,84 @@ static int rt286_adc_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt286_vref_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec,
+ RT286_CBJ_CTRL1, 0x0400, 0x0000);
+ mdelay(50);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt286_ldo2_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x08);
+ break;
+ case SND_SOC_DAPM_PRE_PMD:
+ snd_soc_update_bits(codec, RT286_POWER_CTRL2, 0x38, 0x30);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt286_mic1_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ snd_soc_update_bits(codec,
+ RT286_A_BIAS_CTRL3, 0xc000, 0x8000);
+ snd_soc_update_bits(codec,
+ RT286_A_BIAS_CTRL2, 0xc000, 0x8000);
+ break;
+ case SND_SOC_DAPM_POST_PMD:
+ snd_soc_update_bits(codec,
+ RT286_A_BIAS_CTRL3, 0xc000, 0x0000);
+ snd_soc_update_bits(codec,
+ RT286_A_BIAS_CTRL2, 0xc000, 0x0000);
+ break;
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY_S("HV", 1, RT286_POWER_CTRL1,
+ 12, 1, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("VREF", RT286_POWER_CTRL1,
+ 0, 1, rt286_vref_event, SND_SOC_DAPM_PRE_PMU),
+ SND_SOC_DAPM_SUPPLY_S("LDO1", 1, RT286_POWER_CTRL2,
+ 2, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("LDO2", 2, RT286_POWER_CTRL1,
+ 13, 1, rt286_ldo2_event, SND_SOC_DAPM_PRE_PMD |
+ SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_SUPPLY("MCLK MODE", RT286_PLL_CTRL1,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY("MIC1 Input Buffer", SND_SOC_NOPM,
+ 0, 0, rt286_mic1_event, SND_SOC_DAPM_PRE_PMU |
+ SND_SOC_DAPM_POST_PMD),
+
/* Input Lines */
SND_SOC_DAPM_INPUT("DMIC1 Pin"),
SND_SOC_DAPM_INPUT("DMIC2 Pin"),
@@ -642,6 +715,25 @@ static const struct snd_soc_dapm_widget rt286_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt286_dapm_routes[] = {
+ {"ADC 0", NULL, "MCLK MODE", is_mclk_mode},
+ {"ADC 1", NULL, "MCLK MODE", is_mclk_mode},
+ {"Front", NULL, "MCLK MODE", is_mclk_mode},
+ {"Surround", NULL, "MCLK MODE", is_mclk_mode},
+
+ {"HP Power", NULL, "LDO1"},
+ {"HP Power", NULL, "LDO2"},
+
+ {"MIC1", NULL, "LDO1"},
+ {"MIC1", NULL, "LDO2"},
+ {"MIC1", NULL, "HV"},
+ {"MIC1", NULL, "VREF"},
+ {"MIC1", NULL, "MIC1 Input Buffer"},
+
+ {"SPO", NULL, "LDO1"},
+ {"SPO", NULL, "LDO2"},
+ {"SPO", NULL, "HV"},
+ {"SPO", NULL, "VREF"},
+
{"DMIC1", NULL, "DMIC1 Pin"},
{"DMIC2", NULL, "DMIC2 Pin"},
{"DMIC1", NULL, "DMIC Receiver"},
@@ -880,6 +972,7 @@ static int rt286_set_dai_sysclk(struct snd_soc_dai *dai,
}
rt286->sys_clk = freq;
+ rt286->clk_id = clk_id;
return 0;
}
@@ -915,13 +1008,18 @@ static int rt286_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_ON:
mdelay(10);
+ snd_soc_update_bits(codec,
+ RT286_CBJ_CTRL1, 0x0400, 0x0400);
+ snd_soc_update_bits(codec,
+ RT286_DC_GAIN, 0x200, 0x0);
+
break;
case SND_SOC_BIAS_STANDBY:
snd_soc_write(codec,
RT286_SET_AUDIO_POWER, AC_PWRST_D3);
snd_soc_update_bits(codec,
- RT286_DC_GAIN, 0x200, 0x0);
+ RT286_CBJ_CTRL1, 0x0400, 0x0000);
break;
default:
@@ -962,6 +1060,7 @@ static int rt286_probe(struct snd_soc_codec *codec)
{
struct rt286_priv *rt286 = snd_soc_codec_get_drvdata(codec);
+ rt286->codec = codec;
codec->dapm.bias_level = SND_SOC_BIAS_OFF;
if (rt286->i2c->irq) {
@@ -1107,6 +1206,16 @@ static const struct acpi_device_id rt286_acpi_match[] = {
};
MODULE_DEVICE_TABLE(acpi, rt286_acpi_match);
+static struct dmi_system_id force_combo_jack_table[] = {
+ {
+ .ident = "Intel Wilson Beach",
+ .matches = {
+ DMI_MATCH(DMI_BOARD_NAME, "Wilson Beach SDS")
+ }
+ },
+ { }
+};
+
static int rt286_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1142,6 +1251,9 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
if (pdata)
rt286->pdata = *pdata;
+ if (dmi_check_system(force_combo_jack_table))
+ rt286->pdata.cbj_en = true;
+
regmap_write(rt286->regmap, RT286_SET_AUDIO_POWER, AC_PWRST_D3);
for (i = 0; i < RT286_POWER_REG_LEN; i++)
@@ -1152,7 +1264,6 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
if (!rt286->pdata.cbj_en) {
regmap_write(rt286->regmap, RT286_CBJ_CTRL2, 0x0000);
regmap_write(rt286->regmap, RT286_MIC1_DET_CTRL, 0x0816);
- regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
regmap_update_bits(rt286->regmap,
RT286_CBJ_CTRL1, 0xf000, 0xb000);
} else {
@@ -1169,10 +1280,12 @@ static int rt286_i2c_probe(struct i2c_client *i2c,
mdelay(10);
- /*Power down LDO2*/
- regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0x8, 0x0);
+ regmap_write(rt286->regmap, RT286_MISC_CTRL1, 0x0000);
+ /* Power down LDO, VREF */
+ regmap_update_bits(rt286->regmap, RT286_POWER_CTRL2, 0xc, 0x0);
+ regmap_update_bits(rt286->regmap, RT286_POWER_CTRL1, 0x1001, 0x1001);
- /*Set depop parameter*/
+ /* Set depop parameter */
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL2, 0x403a, 0x401a);
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL3, 0xf777, 0x4737);
regmap_update_bits(rt286->regmap, RT286_DEPOP_CTRL4, 0x00ff, 0x003f);
diff --git a/sound/soc/codecs/rt5631.c b/sound/soc/codecs/rt5631.c
index 1ba27db..6d7b7ca 100644
--- a/sound/soc/codecs/rt5631.c
+++ b/sound/soc/codecs/rt5631.c
@@ -1612,29 +1612,6 @@ static int rt5631_probe(struct snd_soc_codec *codec)
return 0;
}
-static int rt5631_remove(struct snd_soc_codec *codec)
-{
- rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-#ifdef CONFIG_PM
-static int rt5631_suspend(struct snd_soc_codec *codec)
-{
- rt5631_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int rt5631_resume(struct snd_soc_codec *codec)
-{
- rt5631_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define rt5631_suspend NULL
-#define rt5631_resume NULL
-#endif
-
#define RT5631_STEREO_RATES SNDRV_PCM_RATE_8000_96000
#define RT5631_FORMAT (SNDRV_PCM_FMTBIT_S16_LE | \
SNDRV_PCM_FMTBIT_S20_3LE | \
@@ -1672,10 +1649,8 @@ static struct snd_soc_dai_driver rt5631_dai[] = {
static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
.probe = rt5631_probe,
- .remove = rt5631_remove,
- .suspend = rt5631_suspend,
- .resume = rt5631_resume,
.set_bias_level = rt5631_set_bias_level,
+ .suspend_bias_off = true,
.controls = rt5631_snd_controls,
.num_controls = ARRAY_SIZE(rt5631_snd_controls),
.dapm_widgets = rt5631_dapm_widgets,
@@ -1686,10 +1661,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5631 = {
static const struct i2c_device_id rt5631_i2c_id[] = {
{ "rt5631", 0 },
+ { "alc5631", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5631_i2c_id);
+#ifdef CONFIG_OF
+static struct of_device_id rt5631_i2c_dt_ids[] = {
+ { .compatible = "realtek,rt5631"},
+ { .compatible = "realtek,alc5631"},
+ { }
+};
+MODULE_DEVICE_TABLE(of, rt5631_i2c_dt_ids);
+#endif
+
static const struct regmap_config rt5631_regmap_config = {
.reg_bits = 8,
.val_bits = 16,
@@ -1734,6 +1719,7 @@ static struct i2c_driver rt5631_i2c_driver = {
.driver = {
.name = "rt5631",
.owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(rt5631_i2c_dt_ids),
},
.probe = rt5631_i2c_probe,
.remove = rt5631_i2c_remove,
diff --git a/sound/soc/codecs/rt5645.c b/sound/soc/codecs/rt5645.c
index d16331e..a7789a8 100644
--- a/sound/soc/codecs/rt5645.c
+++ b/sound/soc/codecs/rt5645.c
@@ -554,6 +554,53 @@ static int is_sys_clk_from_pll(struct snd_soc_dapm_widget *source,
return 0;
}
+static int is_using_asrc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ unsigned int reg, shift, val;
+
+ switch (source->shift) {
+ case 0:
+ reg = RT5645_ASRC_3;
+ shift = 0;
+ break;
+ case 1:
+ reg = RT5645_ASRC_3;
+ shift = 4;
+ break;
+ case 3:
+ reg = RT5645_ASRC_2;
+ shift = 0;
+ break;
+ case 8:
+ reg = RT5645_ASRC_2;
+ shift = 4;
+ break;
+ case 9:
+ reg = RT5645_ASRC_2;
+ shift = 8;
+ break;
+ case 10:
+ reg = RT5645_ASRC_2;
+ shift = 12;
+ break;
+ default:
+ return 0;
+ }
+
+ val = (snd_soc_read(source->codec, reg) >> shift) & 0xf;
+ switch (val) {
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ return 1;
+ default:
+ return 0;
+ }
+
+}
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5645_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5645_STO1_ADC_MIXER,
@@ -1246,6 +1293,30 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("Mic Det Power", RT5645_PWR_VOL,
RT5645_PWR_MIC_DET_BIT, 0, NULL, 0),
+ /* ASRC */
+ SND_SOC_DAPM_SUPPLY_S("I2S1 ASRC", 1, RT5645_ASRC_1,
+ 11, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("I2S2 ASRC", 1, RT5645_ASRC_1,
+ 12, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC STO ASRC", 1, RT5645_ASRC_1,
+ 10, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO L ASRC", 1, RT5645_ASRC_1,
+ 9, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5645_ASRC_1,
+ 8, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5645_ASRC_1,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5645_ASRC_1,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5645_ASRC_1,
+ 4, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5645_ASRC_1,
+ 3, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC MONO L ASRC", 1, RT5645_ASRC_1,
+ 1, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("ADC MONO R ASRC", 1, RT5645_ASRC_1,
+ 0, 0, NULL, 0),
+
/* Input Side */
/* micbias */
SND_SOC_DAPM_MICBIAS("micbias1", RT5645_PWR_ANLG2,
@@ -1504,6 +1575,17 @@ static const struct snd_soc_dapm_widget rt5645_dapm_widgets[] = {
};
static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
+ { "adc stereo1 filter", NULL, "ADC STO1 ASRC", is_using_asrc },
+ { "adc stereo2 filter", NULL, "ADC STO2 ASRC", is_using_asrc },
+ { "adc mono left filter", NULL, "ADC MONO L ASRC", is_using_asrc },
+ { "adc mono right filter", NULL, "ADC MONO R ASRC", is_using_asrc },
+ { "dac mono left filter", NULL, "DAC MONO L ASRC", is_using_asrc },
+ { "dac mono right filter", NULL, "DAC MONO R ASRC", is_using_asrc },
+ { "dac stereo1 filter", NULL, "DAC STO ASRC", is_using_asrc },
+
+ { "I2S1", NULL, "I2S1 ASRC" },
+ { "I2S2", NULL, "I2S2 ASRC" },
+
{ "IN1P", NULL, "LDO2" },
{ "IN2P", NULL, "LDO2" },
@@ -1550,12 +1632,15 @@ static const struct snd_soc_dapm_route rt5645_dapm_routes[] = {
{ "Stereo1 DMIC Mux", "DMIC1", "DMIC1" },
{ "Stereo1 DMIC Mux", "DMIC2", "DMIC2" },
+ { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC" },
{ "Mono DMIC L Mux", "DMIC1", "DMIC L1" },
{ "Mono DMIC L Mux", "DMIC2", "DMIC L2" },
+ { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC" },
{ "Mono DMIC R Mux", "DMIC1", "DMIC R1" },
{ "Mono DMIC R Mux", "DMIC2", "DMIC R2" },
+ { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC" },
{ "Stereo1 ADC L2 Mux", "DMIC", "Stereo1 DMIC Mux" },
{ "Stereo1 ADC L2 Mux", "DAC MIX", "DAC MIXL" },
@@ -2029,8 +2114,11 @@ static int rt5645_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
struct snd_soc_codec *codec = dai->codec;
unsigned int val = 0;
- if (rx_mask || tx_mask)
+ if (rx_mask || tx_mask) {
val |= (1 << 14);
+ snd_soc_update_bits(codec, RT5645_BASS_BACK,
+ RT5645_G_BB_BST_MASK, RT5645_G_BB_BST_25DB);
+ }
switch (slots) {
case 4:
@@ -2071,8 +2159,8 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
switch (level) {
- case SND_SOC_BIAS_STANDBY:
- if (SND_SOC_BIAS_OFF == codec->dapm.bias_level) {
+ case SND_SOC_BIAS_PREPARE:
+ if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
RT5645_PWR_VREF1 | RT5645_PWR_MB |
RT5645_PWR_BG | RT5645_PWR_VREF2,
@@ -2087,15 +2175,24 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
}
break;
+ case SND_SOC_BIAS_STANDBY:
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_VREF1 | RT5645_PWR_MB |
+ RT5645_PWR_BG | RT5645_PWR_VREF2,
+ RT5645_PWR_VREF1 | RT5645_PWR_MB |
+ RT5645_PWR_BG | RT5645_PWR_VREF2);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2,
+ RT5645_PWR_FV1 | RT5645_PWR_FV2);
+ break;
+
case SND_SOC_BIAS_OFF:
snd_soc_write(codec, RT5645_DEPOP_M2, 0x1100);
snd_soc_write(codec, RT5645_GEN_CTRL1, 0x0128);
- snd_soc_write(codec, RT5645_PWR_DIG1, 0x0000);
- snd_soc_write(codec, RT5645_PWR_DIG2, 0x0000);
- snd_soc_write(codec, RT5645_PWR_VOL, 0x0000);
- snd_soc_write(codec, RT5645_PWR_MIXER, 0x0000);
- snd_soc_write(codec, RT5645_PWR_ANLG1, 0x0000);
- snd_soc_write(codec, RT5645_PWR_ANLG2, 0x0000);
+ snd_soc_update_bits(codec, RT5645_PWR_ANLG1,
+ RT5645_PWR_VREF1 | RT5645_PWR_MB |
+ RT5645_PWR_BG | RT5645_PWR_VREF2 |
+ RT5645_PWR_FV1 | RT5645_PWR_FV2, 0x0);
break;
default:
@@ -2106,8 +2203,7 @@ static int rt5645_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int rt5645_jack_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack)
+static int rt5645_jack_detect(struct snd_soc_codec *codec)
{
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
int gpio_state, jack_type = 0;
@@ -2145,34 +2241,44 @@ static int rt5645_jack_detect(struct snd_soc_codec *codec,
snd_soc_dapm_disable_pin(&codec->dapm, "micbias1");
snd_soc_dapm_disable_pin(&codec->dapm, "micbias2");
- snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
+ if (rt5645->pdata.jd_mode == 0)
+ snd_soc_dapm_disable_pin(&codec->dapm, "LDO2");
snd_soc_dapm_disable_pin(&codec->dapm, "Mic Det Power");
snd_soc_dapm_sync(&codec->dapm);
}
- snd_soc_jack_report(rt5645->jack, jack_type, SND_JACK_HEADSET);
-
+ snd_soc_jack_report(rt5645->hp_jack, jack_type, SND_JACK_HEADPHONE);
+ snd_soc_jack_report(rt5645->mic_jack, jack_type, SND_JACK_MICROPHONE);
return 0;
}
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack)
+ struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack)
{
struct rt5645_priv *rt5645 = snd_soc_codec_get_drvdata(codec);
- rt5645->jack = jack;
-
- rt5645_jack_detect(codec, rt5645->jack);
+ rt5645->hp_jack = hp_jack;
+ rt5645->mic_jack = mic_jack;
+ rt5645_jack_detect(codec);
return 0;
}
EXPORT_SYMBOL_GPL(rt5645_set_jack_detect);
+static void rt5645_jack_detect_work(struct work_struct *work)
+{
+ struct rt5645_priv *rt5645 =
+ container_of(work, struct rt5645_priv, jack_detect_work.work);
+
+ rt5645_jack_detect(rt5645->codec);
+}
+
static irqreturn_t rt5645_irq(int irq, void *data)
{
struct rt5645_priv *rt5645 = data;
- rt5645_jack_detect(rt5645->codec, rt5645->jack);
+ queue_delayed_work(system_power_efficient_wq,
+ &rt5645->jack_detect_work, msecs_to_jiffies(250));
return IRQ_HANDLED;
}
@@ -2187,6 +2293,13 @@ static int rt5645_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, RT5645_CHARGE_PUMP, 0x0300, 0x0200);
+ /* for JD function */
+ if (rt5645->pdata.en_jd_func) {
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "JD Power");
+ snd_soc_dapm_force_enable_pin(&codec->dapm, "LDO2");
+ snd_soc_dapm_sync(&codec->dapm);
+ }
+
return 0;
}
@@ -2420,6 +2533,51 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
}
+ if (rt5645->pdata.en_jd_func) {
+ regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+ RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU,
+ RT5645_IRQ_CLK_GATE_CTRL | RT5645_MICINDET_MANU);
+ regmap_update_bits(rt5645->regmap, RT5645_IN1_CTRL1,
+ RT5645_CBJ_BST1_EN, RT5645_CBJ_BST1_EN);
+ regmap_update_bits(rt5645->regmap, RT5645_JD_CTRL3,
+ RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL,
+ RT5645_JD_CBJ_EN | RT5645_JD_CBJ_POL);
+ regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+ RT5645_IRQ_CLK_INT, RT5645_IRQ_CLK_INT);
+ }
+
+ if (rt5645->pdata.jd_mode) {
+ regmap_update_bits(rt5645->regmap, RT5645_IRQ_CTRL2,
+ RT5645_IRQ_JD_1_1_EN, RT5645_IRQ_JD_1_1_EN);
+ regmap_update_bits(rt5645->regmap, RT5645_GEN_CTRL3,
+ RT5645_JD_PSV_MODE, RT5645_JD_PSV_MODE);
+ regmap_update_bits(rt5645->regmap, RT5645_HPO_MIXER,
+ RT5645_IRQ_PSV_MODE, RT5645_IRQ_PSV_MODE);
+ regmap_update_bits(rt5645->regmap, RT5645_MICBIAS,
+ RT5645_MIC2_OVCD_EN, RT5645_MIC2_OVCD_EN);
+ regmap_update_bits(rt5645->regmap, RT5645_GPIO_CTRL1,
+ RT5645_GP1_PIN_IRQ, RT5645_GP1_PIN_IRQ);
+ switch (rt5645->pdata.jd_mode) {
+ case 1:
+ regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+ RT5645_JD1_MODE_MASK,
+ RT5645_JD1_MODE_0);
+ break;
+ case 2:
+ regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+ RT5645_JD1_MODE_MASK,
+ RT5645_JD1_MODE_1);
+ break;
+ case 3:
+ regmap_update_bits(rt5645->regmap, RT5645_A_JD_CTRL1,
+ RT5645_JD1_MODE_MASK,
+ RT5645_JD1_MODE_2);
+ break;
+ default:
+ break;
+ }
+ }
+
if (rt5645->i2c->irq) {
ret = request_threaded_irq(rt5645->i2c->irq, NULL, rt5645_irq,
IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING
@@ -2438,6 +2596,8 @@ static int rt5645_i2c_probe(struct i2c_client *i2c,
dev_err(&i2c->dev, "Fail gpio_direction hp_det_gpio\n");
}
+ INIT_DELAYED_WORK(&rt5645->jack_detect_work, rt5645_jack_detect_work);
+
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5645,
rt5645_dai, ARRAY_SIZE(rt5645_dai));
}
@@ -2449,6 +2609,8 @@ static int rt5645_i2c_remove(struct i2c_client *i2c)
if (i2c->irq)
free_irq(i2c->irq, rt5645);
+ cancel_delayed_work_sync(&rt5645->jack_detect_work);
+
if (gpio_is_valid(rt5645->pdata.hp_det_gpio))
gpio_free(rt5645->pdata.hp_det_gpio);
diff --git a/sound/soc/codecs/rt5645.h b/sound/soc/codecs/rt5645.h
index 50c62c5..a815e36 100644
--- a/sound/soc/codecs/rt5645.h
+++ b/sound/soc/codecs/rt5645.h
@@ -594,6 +594,7 @@
#define RT5645_M_DAC1_HM_SFT 14
#define RT5645_M_HPVOL_HM (0x1 << 13)
#define RT5645_M_HPVOL_HM_SFT 13
+#define RT5645_IRQ_PSV_MODE (0x1 << 12)
/* SPK Left Mixer Control (0x46) */
#define RT5645_G_RM_L_SM_L_MASK (0x3 << 14)
@@ -1348,6 +1349,12 @@
#define RT5645_PWR_CLK25M_SFT 4
#define RT5645_PWR_CLK25M_PD (0x0 << 4)
#define RT5645_PWR_CLK25M_PU (0x1 << 4)
+#define RT5645_IRQ_CLK_MCLK (0x0 << 3)
+#define RT5645_IRQ_CLK_INT (0x1 << 3)
+#define RT5645_JD1_MODE_MASK (0x3 << 0)
+#define RT5645_JD1_MODE_0 (0x0 << 0)
+#define RT5645_JD1_MODE_1 (0x1 << 0)
+#define RT5645_JD1_MODE_2 (0x2 << 0)
/* VAD Control 4 (0x9d) */
#define RT5645_VAD_SEL_MASK (0x3 << 8)
@@ -1636,6 +1643,7 @@
#define RT5645_OT_P_SFT 10
#define RT5645_OT_P_NOR (0x0 << 10)
#define RT5645_OT_P_INV (0x1 << 10)
+#define RT5645_IRQ_JD_1_1_EN (0x1 << 9)
/* IRQ Control 2 (0xbe) */
#define RT5645_IRQ_MB1_OC_MASK (0x1 << 15)
@@ -1853,6 +1861,7 @@
#define RT5645_M_BB_HPF_R_SFT 6
#define RT5645_G_BB_BST_MASK (0x3f)
#define RT5645_G_BB_BST_SFT 0
+#define RT5645_G_BB_BST_25DB 0x14
/* MP3 Plus Control 1 (0xd0) */
#define RT5645_M_MP3_L_MASK (0x1 << 15)
@@ -2116,6 +2125,10 @@ enum {
#define RT5645_RXDP2_SEL_ADC (0x1 << 3)
#define RT5645_RXDP2_SEL_SFT (3)
+/* General Control3 (0xfc) */
+#define RT5645_JD_PSV_MODE (0x1 << 12)
+#define RT5645_IRQ_CLK_GATE_CTRL (0x1 << 11)
+#define RT5645_MICINDET_MANU (0x1 << 7)
/* Vendor ID (0xfd) */
#define RT5645_VER_C 0x2
@@ -2167,7 +2180,9 @@ struct rt5645_priv {
struct rt5645_platform_data pdata;
struct regmap *regmap;
struct i2c_client *i2c;
- struct snd_soc_jack *jack;
+ struct snd_soc_jack *hp_jack;
+ struct snd_soc_jack *mic_jack;
+ struct delayed_work jack_detect_work;
int sysclk;
int sysclk_src;
@@ -2181,6 +2196,6 @@ struct rt5645_priv {
};
int rt5645_set_jack_detect(struct snd_soc_codec *codec,
- struct snd_soc_jack *jack);
+ struct snd_soc_jack *hp_jack, struct snd_soc_jack *mic_jack);
#endif /* __RT5645_H__ */
diff --git a/sound/soc/codecs/rt5670.c b/sound/soc/codecs/rt5670.c
index 9bd8b4f..8a0833d 100644
--- a/sound/soc/codecs/rt5670.c
+++ b/sound/soc/codecs/rt5670.c
@@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/platform_device.h>
+#include <linux/acpi.h>
#include <linux/spi/spi.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -575,6 +576,18 @@ static int is_using_asrc(struct snd_soc_dapm_widget *source,
}
+static int can_use_asrc(struct snd_soc_dapm_widget *source,
+ struct snd_soc_dapm_widget *sink)
+{
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(source->dapm);
+ struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
+ if (rt5670->sysclk > rt5670->lrck[RT5670_AIF1] * 384)
+ return 1;
+
+ return 0;
+}
+
/* Digital Mixer */
static const struct snd_kcontrol_new rt5670_sto1_adc_l_mix[] = {
SOC_DAPM_SINGLE("ADC1 Switch", RT5670_STO1_ADC_MIXER,
@@ -1281,6 +1294,14 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
9, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("DAC MONO R ASRC", 1, RT5670_ASRC_1,
8, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO1 ASRC", 1, RT5670_ASRC_1,
+ 7, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC STO2 ASRC", 1, RT5670_ASRC_1,
+ 6, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC MONO L ASRC", 1, RT5670_ASRC_1,
+ 5, 0, NULL, 0),
+ SND_SOC_DAPM_SUPPLY_S("DMIC MONO R ASRC", 1, RT5670_ASRC_1,
+ 4, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC STO1 ASRC", 1, RT5670_ASRC_1,
3, 0, NULL, 0),
SND_SOC_DAPM_SUPPLY_S("ADC STO2 ASRC", 1, RT5670_ASRC_1,
@@ -1595,29 +1616,40 @@ static const struct snd_soc_dapm_widget rt5670_dapm_widgets[] = {
/* PDM */
SND_SOC_DAPM_SUPPLY("PDM1 Power", RT5670_PWR_DIG2,
RT5670_PWR_PDM1_BIT, 0, NULL, 0),
- SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
- RT5670_PWR_PDM2_BIT, 0, NULL, 0),
SND_SOC_DAPM_MUX("PDM1 L Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM1_L_SFT, 1, &rt5670_pdm1_l_mux),
SND_SOC_DAPM_MUX("PDM1 R Mux", RT5670_PDM_OUT_CTRL,
RT5670_M_PDM1_R_SFT, 1, &rt5670_pdm1_r_mux),
- SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
- RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
- SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
- RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
/* Output Lines */
SND_SOC_DAPM_OUTPUT("HPOL"),
SND_SOC_DAPM_OUTPUT("HPOR"),
SND_SOC_DAPM_OUTPUT("LOUTL"),
SND_SOC_DAPM_OUTPUT("LOUTR"),
+};
+
+static const struct snd_soc_dapm_widget rt5670_specific_dapm_widgets[] = {
+ SND_SOC_DAPM_SUPPLY("PDM2 Power", RT5670_PWR_DIG2,
+ RT5670_PWR_PDM2_BIT, 0, NULL, 0),
+ SND_SOC_DAPM_MUX("PDM2 L Mux", RT5670_PDM_OUT_CTRL,
+ RT5670_M_PDM2_L_SFT, 1, &rt5670_pdm2_l_mux),
+ SND_SOC_DAPM_MUX("PDM2 R Mux", RT5670_PDM_OUT_CTRL,
+ RT5670_M_PDM2_R_SFT, 1, &rt5670_pdm2_r_mux),
SND_SOC_DAPM_OUTPUT("PDM1L"),
SND_SOC_DAPM_OUTPUT("PDM1R"),
SND_SOC_DAPM_OUTPUT("PDM2L"),
SND_SOC_DAPM_OUTPUT("PDM2R"),
};
+static const struct snd_soc_dapm_widget rt5672_specific_dapm_widgets[] = {
+ SND_SOC_DAPM_PGA("SPO Amp", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_OUTPUT("SPOLP"),
+ SND_SOC_DAPM_OUTPUT("SPOLN"),
+ SND_SOC_DAPM_OUTPUT("SPORP"),
+ SND_SOC_DAPM_OUTPUT("SPORN"),
+};
+
static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "ADC Stereo1 Filter", NULL, "ADC STO1 ASRC", is_using_asrc },
{ "ADC Stereo2 Filter", NULL, "ADC STO2 ASRC", is_using_asrc },
@@ -1626,9 +1658,13 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "DAC Mono Left Filter", NULL, "DAC MONO L ASRC", is_using_asrc },
{ "DAC Mono Right Filter", NULL, "DAC MONO R ASRC", is_using_asrc },
{ "DAC Stereo1 Filter", NULL, "DAC STO ASRC", is_using_asrc },
+ { "Stereo1 DMIC Mux", NULL, "DMIC STO1 ASRC", can_use_asrc },
+ { "Stereo2 DMIC Mux", NULL, "DMIC STO2 ASRC", can_use_asrc },
+ { "Mono DMIC L Mux", NULL, "DMIC MONO L ASRC", can_use_asrc },
+ { "Mono DMIC R Mux", NULL, "DMIC MONO R ASRC", can_use_asrc },
- { "I2S1", NULL, "I2S1 ASRC" },
- { "I2S2", NULL, "I2S2 ASRC" },
+ { "I2S1", NULL, "I2S1 ASRC", can_use_asrc},
+ { "I2S2", NULL, "I2S2 ASRC", can_use_asrc},
{ "DMIC1", NULL, "DMIC L1" },
{ "DMIC1", NULL, "DMIC R1" },
@@ -1970,12 +2006,6 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "PDM1 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
{ "PDM1 R Mux", "Mono DAC", "Mono DAC MIXR" },
{ "PDM1 R Mux", NULL, "PDM1 Power" },
- { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
- { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
- { "PDM2 L Mux", NULL, "PDM2 Power" },
- { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
- { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
- { "PDM2 R Mux", NULL, "PDM2 Power" },
{ "HP Amp", NULL, "HPO MIX" },
{ "HP Amp", NULL, "Mic Det Power" },
@@ -1993,13 +2023,30 @@ static const struct snd_soc_dapm_route rt5670_dapm_routes[] = {
{ "LOUTR", NULL, "LOUT R Playback" },
{ "LOUTL", NULL, "Improve HP Amp Drv" },
{ "LOUTR", NULL, "Improve HP Amp Drv" },
+};
+static const struct snd_soc_dapm_route rt5670_specific_dapm_routes[] = {
+ { "PDM2 L Mux", "Stereo DAC", "Stereo DAC MIXL" },
+ { "PDM2 L Mux", "Mono DAC", "Mono DAC MIXL" },
+ { "PDM2 L Mux", NULL, "PDM2 Power" },
+ { "PDM2 R Mux", "Stereo DAC", "Stereo DAC MIXR" },
+ { "PDM2 R Mux", "Mono DAC", "Mono DAC MIXR" },
+ { "PDM2 R Mux", NULL, "PDM2 Power" },
{ "PDM1L", NULL, "PDM1 L Mux" },
{ "PDM1R", NULL, "PDM1 R Mux" },
{ "PDM2L", NULL, "PDM2 L Mux" },
{ "PDM2R", NULL, "PDM2 R Mux" },
};
+static const struct snd_soc_dapm_route rt5672_specific_dapm_routes[] = {
+ { "SPO Amp", NULL, "PDM1 L Mux" },
+ { "SPO Amp", NULL, "PDM1 R Mux" },
+ { "SPOLP", NULL, "SPO Amp" },
+ { "SPOLN", NULL, "SPO Amp" },
+ { "SPORP", NULL, "SPO Amp" },
+ { "SPORN", NULL, "SPO Amp" },
+};
+
static int rt5670_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params, struct snd_soc_dai *dai)
{
@@ -2287,6 +2334,8 @@ static int rt5670_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
static int rt5670_set_bias_level(struct snd_soc_codec *codec,
enum snd_soc_bias_level level)
{
+ struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+
switch (level) {
case SND_SOC_BIAS_PREPARE:
if (SND_SOC_BIAS_STANDBY == codec->dapm.bias_level) {
@@ -2308,16 +2357,27 @@ static int rt5670_set_bias_level(struct snd_soc_codec *codec,
}
break;
case SND_SOC_BIAS_STANDBY:
- snd_soc_write(codec, RT5670_PWR_DIG1, 0x0000);
- snd_soc_write(codec, RT5670_PWR_DIG2, 0x0001);
- snd_soc_write(codec, RT5670_PWR_VOL, 0x0000);
- snd_soc_write(codec, RT5670_PWR_MIXER, 0x0001);
- snd_soc_write(codec, RT5670_PWR_ANLG1, 0x2800);
- snd_soc_write(codec, RT5670_PWR_ANLG2, 0x0004);
- snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
+ snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+ RT5670_PWR_VREF1 | RT5670_PWR_VREF2 |
+ RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
RT5670_LDO_SEL_MASK, 0x1);
break;
+ case SND_SOC_BIAS_OFF:
+ if (rt5670->pdata.jd_mode)
+ snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+ RT5670_PWR_VREF1 | RT5670_PWR_MB |
+ RT5670_PWR_BG | RT5670_PWR_VREF2 |
+ RT5670_PWR_FV1 | RT5670_PWR_FV2,
+ RT5670_PWR_MB | RT5670_PWR_BG);
+ else
+ snd_soc_update_bits(codec, RT5670_PWR_ANLG1,
+ RT5670_PWR_VREF1 | RT5670_PWR_MB |
+ RT5670_PWR_BG | RT5670_PWR_VREF2 |
+ RT5670_PWR_FV1 | RT5670_PWR_FV2, 0);
+
+ snd_soc_update_bits(codec, RT5670_DIG_MISC, 0x1, 0x0);
+ break;
default:
break;
@@ -2331,6 +2391,29 @@ static int rt5670_probe(struct snd_soc_codec *codec)
{
struct rt5670_priv *rt5670 = snd_soc_codec_get_drvdata(codec);
+ switch (snd_soc_read(codec, RT5670_RESET) & RT5670_ID_MASK) {
+ case RT5670_ID_5670:
+ case RT5670_ID_5671:
+ snd_soc_dapm_new_controls(&codec->dapm,
+ rt5670_specific_dapm_widgets,
+ ARRAY_SIZE(rt5670_specific_dapm_widgets));
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5670_specific_dapm_routes,
+ ARRAY_SIZE(rt5670_specific_dapm_routes));
+ break;
+ case RT5670_ID_5672:
+ snd_soc_dapm_new_controls(&codec->dapm,
+ rt5672_specific_dapm_widgets,
+ ARRAY_SIZE(rt5672_specific_dapm_widgets));
+ snd_soc_dapm_add_routes(&codec->dapm,
+ rt5672_specific_dapm_routes,
+ ARRAY_SIZE(rt5672_specific_dapm_routes));
+ break;
+ default:
+ dev_err(codec->dev,
+ "The driver is for RT5670 RT5671 or RT5672 only\n");
+ return -ENODEV;
+ }
rt5670->codec = codec;
return 0;
@@ -2452,10 +2535,20 @@ static const struct regmap_config rt5670_regmap = {
static const struct i2c_device_id rt5670_i2c_id[] = {
{ "rt5670", 0 },
+ { "rt5671", 0 },
+ { "rt5672", 0 },
{ }
};
MODULE_DEVICE_TABLE(i2c, rt5670_i2c_id);
+#ifdef CONFIG_ACPI
+static struct acpi_device_id rt5670_acpi_match[] = {
+ { "10EC5670", 0},
+ { },
+};
+MODULE_DEVICE_TABLE(acpi, rt5670_acpi_match);
+#endif
+
static int rt5670_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -2644,6 +2737,7 @@ static struct i2c_driver rt5670_i2c_driver = {
.driver = {
.name = "rt5670",
.owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(rt5670_acpi_match),
},
.probe = rt5670_i2c_probe,
.remove = rt5670_i2c_remove,
diff --git a/sound/soc/codecs/rt5670.h b/sound/soc/codecs/rt5670.h
index a0b5c85..d11b9c2 100644
--- a/sound/soc/codecs/rt5670.h
+++ b/sound/soc/codecs/rt5670.h
@@ -228,6 +228,12 @@
#define RT5670_R_VOL_MASK (0x3f)
#define RT5670_R_VOL_SFT 0
+/* SW Reset & Device ID (0x00) */
+#define RT5670_ID_MASK (0x3 << 1)
+#define RT5670_ID_5670 (0x0 << 1)
+#define RT5670_ID_5672 (0x1 << 1)
+#define RT5670_ID_5671 (0x2 << 1)
+
/* Combo Jack Control 1 (0x0a) */
#define RT5670_CBJ_BST1_MASK (0xf << 12)
#define RT5670_CBJ_BST1_SFT (12)
diff --git a/sound/soc/codecs/rt5677-spi.c b/sound/soc/codecs/rt5677-spi.c
new file mode 100644
index 0000000..ef6348c
--- /dev/null
+++ b/sound/soc/codecs/rt5677-spi.c
@@ -0,0 +1,130 @@
+/*
+ * rt5677-spi.c -- RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/input.h>
+#include <linux/spi/spi.h>
+#include <linux/device.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/interrupt.h>
+#include <linux/irq.h>
+#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/sched.h>
+#include <linux/kthread.h>
+#include <linux/uaccess.h>
+#include <linux/miscdevice.h>
+#include <linux/regulator/consumer.h>
+#include <linux/pm_qos.h>
+#include <linux/sysfs.h>
+#include <linux/clk.h>
+#include <linux/firmware.h>
+
+#include "rt5677-spi.h"
+
+static struct spi_device *g_spi;
+
+/**
+ * rt5677_spi_write - Write data to SPI.
+ * @txbuf: Data Buffer for writing.
+ * @len: Data length.
+ *
+ *
+ * Returns true for success.
+ */
+int rt5677_spi_write(u8 *txbuf, size_t len)
+{
+ int status;
+
+ status = spi_write(g_spi, txbuf, len);
+
+ if (status)
+ dev_err(&g_spi->dev, "rt5677_spi_write error %d\n", status);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_write);
+
+/**
+ * rt5677_spi_burst_write - Write data to SPI by rt5677 dsp memory address.
+ * @addr: Start address.
+ * @txbuf: Data Buffer for writng.
+ * @len: Data length, it must be a multiple of 8.
+ *
+ *
+ * Returns true for success.
+ */
+int rt5677_spi_burst_write(u32 addr, const struct firmware *fw)
+{
+ u8 spi_cmd = RT5677_SPI_CMD_BURST_WRITE;
+ u8 *write_buf;
+ unsigned int i, end, offset = 0;
+
+ write_buf = kmalloc(RT5677_SPI_BUF_LEN + 6, GFP_KERNEL);
+
+ if (write_buf == NULL)
+ return -ENOMEM;
+
+ while (offset < fw->size) {
+ if (offset + RT5677_SPI_BUF_LEN <= fw->size)
+ end = RT5677_SPI_BUF_LEN;
+ else
+ end = fw->size % RT5677_SPI_BUF_LEN;
+
+ write_buf[0] = spi_cmd;
+ write_buf[1] = ((addr + offset) & 0xff000000) >> 24;
+ write_buf[2] = ((addr + offset) & 0x00ff0000) >> 16;
+ write_buf[3] = ((addr + offset) & 0x0000ff00) >> 8;
+ write_buf[4] = ((addr + offset) & 0x000000ff) >> 0;
+
+ for (i = 0; i < end; i += 8) {
+ write_buf[i + 12] = fw->data[offset + i + 0];
+ write_buf[i + 11] = fw->data[offset + i + 1];
+ write_buf[i + 10] = fw->data[offset + i + 2];
+ write_buf[i + 9] = fw->data[offset + i + 3];
+ write_buf[i + 8] = fw->data[offset + i + 4];
+ write_buf[i + 7] = fw->data[offset + i + 5];
+ write_buf[i + 6] = fw->data[offset + i + 6];
+ write_buf[i + 5] = fw->data[offset + i + 7];
+ }
+
+ write_buf[end + 5] = spi_cmd;
+
+ rt5677_spi_write(write_buf, end + 6);
+
+ offset += RT5677_SPI_BUF_LEN;
+ }
+
+ kfree(write_buf);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rt5677_spi_burst_write);
+
+static int rt5677_spi_probe(struct spi_device *spi)
+{
+ g_spi = spi;
+ return 0;
+}
+
+static struct spi_driver rt5677_spi_driver = {
+ .driver = {
+ .name = "rt5677",
+ .owner = THIS_MODULE,
+ },
+ .probe = rt5677_spi_probe,
+};
+module_spi_driver(rt5677_spi_driver);
+
+MODULE_DESCRIPTION("ASoC RT5677 SPI driver");
+MODULE_AUTHOR("Oder Chiou <oder_chiou@realtek.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/rt5677-spi.h b/sound/soc/codecs/rt5677-spi.h
new file mode 100644
index 0000000..ec41b2b
--- /dev/null
+++ b/sound/soc/codecs/rt5677-spi.h
@@ -0,0 +1,21 @@
+/*
+ * rt5677-spi.h -- RT5677 ALSA SoC audio codec driver
+ *
+ * Copyright 2013 Realtek Semiconductor Corp.
+ * Author: Oder Chiou <oder_chiou@realtek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __RT5677_SPI_H__
+#define __RT5677_SPI_H__
+
+#define RT5677_SPI_BUF_LEN 240
+#define RT5677_SPI_CMD_BURST_WRITE 0x05
+
+int rt5677_spi_write(u8 *txbuf, size_t len);
+int rt5677_spi_burst_write(u32 addr, const struct firmware *fw);
+
+#endif /* __RT5677_SPI_H__ */
diff --git a/sound/soc/codecs/rt5677.c b/sound/soc/codecs/rt5677.c
index 16aa4d9..81fe146 100644
--- a/sound/soc/codecs/rt5677.c
+++ b/sound/soc/codecs/rt5677.c
@@ -20,6 +20,7 @@
#include <linux/i2c.h>
#include <linux/platform_device.h>
#include <linux/spi/spi.h>
+#include <linux/firmware.h>
#include <linux/gpio.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -31,6 +32,7 @@
#include "rl6231.h"
#include "rt5677.h"
+#include "rt5677-spi.h"
#define RT5677_DEVICE_ID 0x6327
@@ -53,12 +55,13 @@ static const struct regmap_range_cfg rt5677_ranges[] = {
};
static const struct reg_default init_list[] = {
+ {RT5677_ASRC_12, 0x0018},
{RT5677_PR_BASE + 0x3d, 0x364d},
- {RT5677_PR_BASE + 0x17, 0x4fc0},
- {RT5677_PR_BASE + 0x13, 0x0312},
- {RT5677_PR_BASE + 0x1e, 0x0000},
- {RT5677_PR_BASE + 0x12, 0x0eaa},
- {RT5677_PR_BASE + 0x14, 0x018a},
+ {RT5677_PR_BASE + 0x17, 0x4fc0},
+ {RT5677_PR_BASE + 0x13, 0x0312},
+ {RT5677_PR_BASE + 0x1e, 0x0000},
+ {RT5677_PR_BASE + 0x12, 0x0eaa},
+ {RT5677_PR_BASE + 0x14, 0x018a},
};
#define RT5677_INIT_REG_LEN ARRAY_SIZE(init_list)
@@ -171,7 +174,7 @@ static const struct reg_default rt5677_reg[] = {
{RT5677_ASRC_9 , 0x0000},
{RT5677_ASRC_10 , 0x0000},
{RT5677_ASRC_11 , 0x0000},
- {RT5677_ASRC_12 , 0x0008},
+ {RT5677_ASRC_12 , 0x0018},
{RT5677_ASRC_13 , 0x0000},
{RT5677_ASRC_14 , 0x0000},
{RT5677_ASRC_15 , 0x0000},
@@ -537,10 +540,232 @@ static bool rt5677_readable_register(struct device *dev, unsigned int reg)
}
}
+/**
+ * rt5677_dsp_mode_i2c_write_addr - Write value to address on DSP mode.
+ * @rt5677: Private Data.
+ * @addr: Address index.
+ * @value: Address data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_write_addr(struct rt5677_priv *rt5677,
+ unsigned int addr, unsigned int value, unsigned int opcode)
+{
+ struct snd_soc_codec *codec = rt5677->codec;
+ int ret;
+
+ mutex_lock(&rt5677->dsp_cmd_lock);
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
+ addr >> 16);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
+ addr & 0xffff);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB,
+ value >> 16);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set data msb value: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB,
+ value & 0xffff);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set data lsb value: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
+ opcode);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
+ goto err;
+ }
+
+err:
+ mutex_unlock(&rt5677->dsp_cmd_lock);
+
+ return ret;
+}
+
+/**
+ * rt5677_dsp_mode_i2c_read_addr - Read value from address on DSP mode.
+ * rt5677: Private Data.
+ * @addr: Address index.
+ * @value: Address data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_read_addr(
+ struct rt5677_priv *rt5677, unsigned int addr, unsigned int *value)
+{
+ struct snd_soc_codec *codec = rt5677->codec;
+ int ret;
+ unsigned int msb, lsb;
+
+ mutex_lock(&rt5677->dsp_cmd_lock);
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_MSB,
+ addr >> 16);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set addr msb value: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_ADDR_LSB,
+ addr & 0xffff);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set addr lsb value: %d\n", ret);
+ goto err;
+ }
+
+ ret = regmap_write(rt5677->regmap_physical, RT5677_DSP_I2C_OP_CODE,
+ 0x0002);
+ if (ret < 0) {
+ dev_err(codec->dev, "Failed to set op code value: %d\n", ret);
+ goto err;
+ }
+
+ regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_MSB, &msb);
+ regmap_read(rt5677->regmap_physical, RT5677_DSP_I2C_DATA_LSB, &lsb);
+ *value = (msb << 16) | lsb;
+
+err:
+ mutex_unlock(&rt5677->dsp_cmd_lock);
+
+ return ret;
+}
+
+/**
+ * rt5677_dsp_mode_i2c_write - Write register on DSP mode.
+ * rt5677: Private Data.
+ * @reg: Register index.
+ * @value: Register data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_write(struct rt5677_priv *rt5677,
+ unsigned int reg, unsigned int value)
+{
+ return rt5677_dsp_mode_i2c_write_addr(rt5677, 0x18020000 + reg * 2,
+ value, 0x0001);
+}
+
+/**
+ * rt5677_dsp_mode_i2c_read - Read register on DSP mode.
+ * @codec: SoC audio codec device.
+ * @reg: Register index.
+ * @value: Register data.
+ *
+ *
+ * Returns 0 for success or negative error code.
+ */
+static int rt5677_dsp_mode_i2c_read(
+ struct rt5677_priv *rt5677, unsigned int reg, unsigned int *value)
+{
+ int ret = rt5677_dsp_mode_i2c_read_addr(rt5677, 0x18020000 + reg * 2,
+ value);
+
+ *value &= 0xffff;
+
+ return ret;
+}
+
+static void rt5677_set_dsp_mode(struct snd_soc_codec *codec, bool on)
+{
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+ if (on) {
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x2);
+ rt5677->is_dsp_mode = true;
+ } else {
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x2, 0x0);
+ rt5677->is_dsp_mode = false;
+ }
+}
+
+static int rt5677_set_dsp_vad(struct snd_soc_codec *codec, bool on)
+{
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+ static bool activity;
+ int ret;
+
+ if (on && !activity) {
+ activity = true;
+
+ regcache_cache_only(rt5677->regmap, false);
+ regcache_cache_bypass(rt5677->regmap, true);
+
+ regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x1, 0x1);
+ regmap_update_bits(rt5677->regmap,
+ RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0f00);
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+ RT5677_LDO1_SEL_MASK, 0x0);
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
+ RT5677_PWR_LDO1, RT5677_PWR_LDO1);
+ regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK1,
+ RT5677_MCLK_SRC_MASK, RT5677_MCLK2_SRC);
+ regmap_update_bits(rt5677->regmap, RT5677_GLB_CLK2,
+ RT5677_PLL2_PR_SRC_MASK | RT5677_DSP_CLK_SRC_MASK,
+ RT5677_PLL2_PR_SRC_MCLK2 | RT5677_DSP_CLK_SRC_BYPASS);
+ regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x07ff);
+ regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x07fd);
+ rt5677_set_dsp_mode(codec, true);
+
+ ret = request_firmware(&rt5677->fw1, RT5677_FIRMWARE1,
+ codec->dev);
+ if (ret == 0) {
+ rt5677_spi_burst_write(0x50000000, rt5677->fw1);
+ release_firmware(rt5677->fw1);
+ }
+
+ ret = request_firmware(&rt5677->fw2, RT5677_FIRMWARE2,
+ codec->dev);
+ if (ret == 0) {
+ rt5677_spi_burst_write(0x60000000, rt5677->fw2);
+ release_firmware(rt5677->fw2);
+ }
+
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x0);
+
+ regcache_cache_bypass(rt5677->regmap, false);
+ regcache_cache_only(rt5677->regmap, true);
+ } else if (!on && activity) {
+ activity = false;
+
+ regcache_cache_only(rt5677->regmap, false);
+ regcache_cache_bypass(rt5677->regmap, true);
+
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_DSP1, 0x1, 0x1);
+ rt5677_set_dsp_mode(codec, false);
+ regmap_write(rt5677->regmap, RT5677_PWR_DSP1, 0x0001);
+
+ regmap_write(rt5677->regmap, RT5677_RESET, 0x10ec);
+
+ regcache_cache_bypass(rt5677->regmap, false);
+ regcache_mark_dirty(rt5677->regmap);
+ regcache_sync(rt5677->regmap);
+ }
+
+ return 0;
+}
+
static const DECLARE_TLV_DB_SCALE(out_vol_tlv, -4650, 150, 0);
-static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -65625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(dac_vol_tlv, -6525, 75, 0);
static const DECLARE_TLV_DB_SCALE(in_vol_tlv, -3450, 150, 0);
-static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -17625, 375, 0);
+static const DECLARE_TLV_DB_SCALE(adc_vol_tlv, -1725, 75, 0);
static const DECLARE_TLV_DB_SCALE(adc_bst_tlv, 0, 1200, 0);
static const DECLARE_TLV_DB_SCALE(st_vol_tlv, -4650, 150, 0);
@@ -556,6 +781,31 @@ static unsigned int bst_tlv[] = {
8, 8, TLV_DB_SCALE_ITEM(5200, 0, 0),
};
+static int rt5677_dsp_vad_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+ ucontrol->value.integer.value[0] = rt5677->dsp_vad_en;
+
+ return 0;
+}
+
+static int rt5677_dsp_vad_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_codec *codec = snd_kcontrol_chip(kcontrol);
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+ rt5677->dsp_vad_en = !!ucontrol->value.integer.value[0];
+
+ if (codec->dapm.bias_level == SND_SOC_BIAS_OFF)
+ rt5677_set_dsp_vad(codec, rt5677->dsp_vad_en);
+
+ return 0;
+}
+
static const struct snd_kcontrol_new rt5677_snd_controls[] = {
/* OUTPUT Control */
SOC_SINGLE("OUT1 Playback Switch", RT5677_LOUT1,
@@ -567,13 +817,13 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
/* DAC Digital Volume */
SOC_DOUBLE_TLV("DAC1 Playback Volume", RT5677_DAC1_DIG_VOL,
- RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC2 Playback Volume", RT5677_DAC2_DIG_VOL,
- RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC3 Playback Volume", RT5677_DAC3_DIG_VOL,
- RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
SOC_DOUBLE_TLV("DAC4 Playback Volume", RT5677_DAC4_DIG_VOL,
- RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 175, 0, dac_vol_tlv),
+ RT5677_L_VOL_SFT, RT5677_R_VOL_SFT, 87, 0, dac_vol_tlv),
/* IN1/IN2 Control */
SOC_SINGLE_TLV("IN1 Boost", RT5677_IN1, RT5677_BST_SFT1, 8, 0, bst_tlv),
@@ -592,19 +842,19 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
RT5677_L_MUTE_SFT, RT5677_R_MUTE_SFT, 1, 1),
SOC_DOUBLE_TLV("ADC1 Capture Volume", RT5677_STO1_ADC_DIG_VOL,
- RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+ RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("ADC2 Capture Volume", RT5677_STO2_ADC_DIG_VOL,
- RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+ RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("ADC3 Capture Volume", RT5677_STO3_ADC_DIG_VOL,
- RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+ RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("ADC4 Capture Volume", RT5677_STO4_ADC_DIG_VOL,
- RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 127, 0,
+ RT5677_STO1_ADC_L_VOL_SFT, RT5677_STO1_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
SOC_DOUBLE_TLV("Mono ADC Capture Volume", RT5677_MONO_ADC_DIG_VOL,
- RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 127, 0,
+ RT5677_MONO_ADC_L_VOL_SFT, RT5677_MONO_ADC_R_VOL_SFT, 63, 0,
adc_vol_tlv),
/* Sidetone Control */
@@ -627,6 +877,9 @@ static const struct snd_kcontrol_new rt5677_snd_controls[] = {
SOC_DOUBLE_TLV("Mono ADC Boost Volume", RT5677_ADC_BST_CTRL2,
RT5677_MONO_ADC_L_BST_SFT, RT5677_MONO_ADC_R_BST_SFT, 3, 0,
adc_bst_tlv),
+
+ SOC_SINGLE_EXT("DSP VAD Switch", SND_SOC_NOPM, 0, 1, 0,
+ rt5677_dsp_vad_get, rt5677_dsp_vad_put),
};
/**
@@ -1086,7 +1339,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_ib45_bypass_src_mux =
SOC_DAPM_ENUM("IB45 Bypass Source", rt5677_ib45_bypass_src_enum);
-/* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */
+/* Stereo ADC Source 2 */ /* MX-27 MX26 MX25 [11:10] */
static const char * const rt5677_stereo_adc2_src[] = {
"DD MIX1", "DMIC", "Stereo DAC MIX"
};
@@ -1171,7 +1424,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_sto2_adc_lr_mux =
SOC_DAPM_ENUM("Stereo2 ADC LR Source", rt5677_stereo2_adc_lr_enum);
-/* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */
+/* Stereo1 ADC Source 1 */ /* MX-27 MX26 MX25 [13:12] */
static const char * const rt5677_stereo_adc1_src[] = {
"DD MIX1", "ADC1/2", "Stereo DAC MIX"
};
@@ -1443,7 +1696,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_pdm2_r_mux =
SOC_DAPM_ENUM("PDM2 Source", rt5677_pdm2_r_enum);
-/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0]*/
+/* TDM IF1/2 SLB ADC1 Data Selection */ /* MX-3C MX-41 [5:4] MX-08 [1:0] */
static const char * const rt5677_if12_adc1_src[] = {
"STO1 ADC MIX", "OB01", "VAD ADC"
};
@@ -1521,7 +1774,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_slb_adc3_mux =
SOC_DAPM_ENUM("SLB ADC3 Source", rt5677_slb_adc3_enum);
-/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */
+/* TDM IF1/2 SLB ADC4 Data Selection */ /* MX-3C MX-41 [11:10] MX-08 [7:6] */
static const char * const rt5677_if12_adc4_src[] = {
"STO4 ADC MIX", "OB67", "OB01"
};
@@ -1547,7 +1800,7 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_slb_adc4_mux =
SOC_DAPM_ENUM("SLB ADC4 Source", rt5677_slb_adc4_enum);
-/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4]*/
+/* Interface3/4 ADC Data Input */ /* MX-2F [3:0] MX-30 [7:4] */
static const char * const rt5677_if34_adc_src[] = {
"STO1 ADC MIX", "STO2 ADC MIX", "STO3 ADC MIX", "STO4 ADC MIX",
"MONO ADC MIX", "OB01", "OB23", "VAD ADC"
@@ -1567,6 +1820,213 @@ static SOC_ENUM_SINGLE_DECL(
static const struct snd_kcontrol_new rt5677_if4_adc_mux =
SOC_DAPM_ENUM("IF4 ADC Source", rt5677_if4_adc_enum);
+/* TDM IF1/2 ADC Data Selection */ /* MX-3B MX-40 [7:6][5:4][3:2][1:0] */
+static const char * const rt5677_if12_adc_swap_src[] = {
+ "L/R", "R/L", "L/L", "R/R"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_adc1_swap_enum, RT5677_TDM1_CTRL1,
+ RT5677_IF1_ADC1_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc1_swap_mux =
+ SOC_DAPM_ENUM("IF1 ADC1 Swap Source", rt5677_if1_adc1_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_adc2_swap_enum, RT5677_TDM1_CTRL1,
+ RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc2_swap_mux =
+ SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if1_adc2_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_adc3_swap_enum, RT5677_TDM1_CTRL1,
+ RT5677_IF1_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc3_swap_mux =
+ SOC_DAPM_ENUM("IF1 ADC3 Swap Source", rt5677_if1_adc3_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_adc4_swap_enum, RT5677_TDM1_CTRL1,
+ RT5677_IF1_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc4_swap_mux =
+ SOC_DAPM_ENUM("IF1 ADC4 Swap Source", rt5677_if1_adc4_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_adc1_swap_enum, RT5677_TDM2_CTRL1,
+ RT5677_IF1_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc1_swap_mux =
+ SOC_DAPM_ENUM("IF1 ADC2 Swap Source", rt5677_if2_adc1_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_adc2_swap_enum, RT5677_TDM2_CTRL1,
+ RT5677_IF2_ADC2_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc2_swap_mux =
+ SOC_DAPM_ENUM("IF2 ADC2 Swap Source", rt5677_if2_adc2_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_adc3_swap_enum, RT5677_TDM2_CTRL1,
+ RT5677_IF2_ADC3_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc3_swap_mux =
+ SOC_DAPM_ENUM("IF2 ADC3 Swap Source", rt5677_if2_adc3_swap_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_adc4_swap_enum, RT5677_TDM2_CTRL1,
+ RT5677_IF2_ADC4_SWAP_SFT, rt5677_if12_adc_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc4_swap_mux =
+ SOC_DAPM_ENUM("IF2 ADC4 Swap Source", rt5677_if2_adc4_swap_enum);
+
+/* TDM IF1 ADC Data Selection */ /* MX-3C [2:0] */
+static const char * const rt5677_if1_adc_tdm_swap_src[] = {
+ "1/2/3/4", "2/1/3/4", "2/3/1/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
+ "3/1/2/4", "3/4/1/2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_adc_tdm_swap_enum, RT5677_TDM1_CTRL2,
+ RT5677_IF1_ADC_CTRL_SFT, rt5677_if1_adc_tdm_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if1_adc_tdm_swap_mux =
+ SOC_DAPM_ENUM("IF1 ADC TDM Swap Source", rt5677_if1_adc_tdm_swap_enum);
+
+/* TDM IF2 ADC Data Selection */ /* MX-41[2:0] */
+static const char * const rt5677_if2_adc_tdm_swap_src[] = {
+ "1/2/3/4", "2/1/3/4", "3/1/2/4", "4/1/2/3", "1/3/2/4", "1/4/2/3",
+ "2/3/1/4", "3/4/1/2"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_adc_tdm_swap_enum, RT5677_TDM2_CTRL2,
+ RT5677_IF2_ADC_CTRL_SFT, rt5677_if2_adc_tdm_swap_src);
+
+static const struct snd_kcontrol_new rt5677_if2_adc_tdm_swap_mux =
+ SOC_DAPM_ENUM("IF2 ADC TDM Swap Source", rt5677_if2_adc_tdm_swap_enum);
+
+/* TDM IF1/2 DAC Data Selection */ /* MX-3E[14:12][10:8][6:4][2:0]
+ MX-3F[14:12][10:8][6:4][2:0]
+ MX-43[14:12][10:8][6:4][2:0]
+ MX-44[14:12][10:8][6:4][2:0] */
+static const char * const rt5677_if12_dac_tdm_sel_src[] = {
+ "Slot0", "Slot1", "Slot2", "Slot3", "Slot4", "Slot5", "Slot6", "Slot7"
+};
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac0_tdm_sel_enum, RT5677_TDM1_CTRL4,
+ RT5677_IF1_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac0_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC0 TDM Source", rt5677_if1_dac0_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac1_tdm_sel_enum, RT5677_TDM1_CTRL4,
+ RT5677_IF1_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac1_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC1 TDM Source", rt5677_if1_dac1_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac2_tdm_sel_enum, RT5677_TDM1_CTRL4,
+ RT5677_IF1_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac2_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC2 TDM Source", rt5677_if1_dac2_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac3_tdm_sel_enum, RT5677_TDM1_CTRL4,
+ RT5677_IF1_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac3_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC3 TDM Source", rt5677_if1_dac3_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac4_tdm_sel_enum, RT5677_TDM1_CTRL5,
+ RT5677_IF1_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac4_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC4 TDM Source", rt5677_if1_dac4_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac5_tdm_sel_enum, RT5677_TDM1_CTRL5,
+ RT5677_IF1_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac5_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC5 TDM Source", rt5677_if1_dac5_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac6_tdm_sel_enum, RT5677_TDM1_CTRL5,
+ RT5677_IF1_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac6_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC6 TDM Source", rt5677_if1_dac6_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if1_dac7_tdm_sel_enum, RT5677_TDM1_CTRL5,
+ RT5677_IF1_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if1_dac7_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF1 DAC7 TDM Source", rt5677_if1_dac7_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac0_tdm_sel_enum, RT5677_TDM2_CTRL4,
+ RT5677_IF2_DAC0_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac0_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC0 TDM Source", rt5677_if2_dac0_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac1_tdm_sel_enum, RT5677_TDM2_CTRL4,
+ RT5677_IF2_DAC1_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac1_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC1 TDM Source", rt5677_if2_dac1_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac2_tdm_sel_enum, RT5677_TDM2_CTRL4,
+ RT5677_IF2_DAC2_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac2_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC2 TDM Source", rt5677_if2_dac2_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac3_tdm_sel_enum, RT5677_TDM2_CTRL4,
+ RT5677_IF2_DAC3_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac3_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC3 TDM Source", rt5677_if2_dac3_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac4_tdm_sel_enum, RT5677_TDM2_CTRL5,
+ RT5677_IF2_DAC4_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac4_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC4 TDM Source", rt5677_if2_dac4_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac5_tdm_sel_enum, RT5677_TDM2_CTRL5,
+ RT5677_IF2_DAC5_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac5_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC5 TDM Source", rt5677_if2_dac5_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac6_tdm_sel_enum, RT5677_TDM2_CTRL5,
+ RT5677_IF2_DAC6_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac6_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC6 TDM Source", rt5677_if2_dac6_tdm_sel_enum);
+
+static SOC_ENUM_SINGLE_DECL(
+ rt5677_if2_dac7_tdm_sel_enum, RT5677_TDM2_CTRL5,
+ RT5677_IF2_DAC7_SFT, rt5677_if12_dac_tdm_sel_src);
+
+static const struct snd_kcontrol_new rt5677_if2_dac7_tdm_sel_mux =
+ SOC_DAPM_ENUM("IF2 DAC7 TDM Source", rt5677_if2_dac7_tdm_sel_enum);
+
static int rt5677_bst1_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
@@ -1678,6 +2138,77 @@ static int rt5677_set_micbias1_event(struct snd_soc_dapm_widget *w,
return 0;
}
+static int rt5677_if1_adc_tdm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+ unsigned int value;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_read(rt5677->regmap, RT5677_TDM1_CTRL2, &value);
+ if (value & RT5677_IF1_ADC_CTRL_MASK)
+ regmap_update_bits(rt5677->regmap, RT5677_TDM1_CTRL1,
+ RT5677_IF1_ADC_MODE_MASK,
+ RT5677_IF1_ADC_MODE_TDM);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5677_if2_adc_tdm_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+ unsigned int value;
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ regmap_read(rt5677->regmap, RT5677_TDM2_CTRL2, &value);
+ if (value & RT5677_IF2_ADC_CTRL_MASK)
+ regmap_update_bits(rt5677->regmap, RT5677_TDM2_CTRL1,
+ RT5677_IF2_ADC_MODE_MASK,
+ RT5677_IF2_ADC_MODE_TDM);
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
+static int rt5677_vref_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol, int event)
+{
+ struct snd_soc_codec *codec = w->codec;
+ struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+
+ switch (event) {
+ case SND_SOC_DAPM_POST_PMU:
+ if (codec->dapm.bias_level != SND_SOC_BIAS_ON &&
+ !rt5677->is_vref_slow) {
+ mdelay(20);
+ regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+ RT5677_PWR_FV1 | RT5677_PWR_FV2,
+ RT5677_PWR_FV1 | RT5677_PWR_FV2);
+ rt5677->is_vref_slow = true;
+ }
+ break;
+
+ default:
+ return 0;
+ }
+
+ return 0;
+}
+
static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_SUPPLY("PLL1", RT5677_PWR_ANLG2, RT5677_PWR_PLL1_BIT,
0, rt5677_set_pll1_event, SND_SOC_DAPM_POST_PMU),
@@ -1837,10 +2368,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_PGA("Stereo4 ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Sto2 ADC LR MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
SND_SOC_DAPM_PGA("Mono ADC MIX", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1_ADC1", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1_ADC2", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1_ADC3", SND_SOC_NOPM, 0, 0, NULL, 0),
- SND_SOC_DAPM_PGA("IF1_ADC4", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF1 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
+ SND_SOC_DAPM_PGA("IF2 ADC", SND_SOC_NOPM, 0, 0, NULL, 0),
/* DSP */
SND_SOC_DAPM_MUX("IB9 Mux", SND_SOC_NOPM, 0, 0,
@@ -1963,6 +2492,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
&rt5677_if1_adc3_mux),
SND_SOC_DAPM_MUX("IF1 ADC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if1_adc4_mux),
+ SND_SOC_DAPM_MUX("IF1 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_adc1_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_adc2_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_adc3_swap_mux),
+ SND_SOC_DAPM_MUX("IF1 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_adc4_swap_mux),
+ SND_SOC_DAPM_MUX_E("IF1 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_adc_tdm_swap_mux, rt5677_if1_adc_tdm_event,
+ SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("IF2 ADC1 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc1_mux),
SND_SOC_DAPM_MUX("IF2 ADC2 Mux", SND_SOC_NOPM, 0, 0,
@@ -1971,6 +2511,17 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
&rt5677_if2_adc3_mux),
SND_SOC_DAPM_MUX("IF2 ADC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if2_adc4_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC1 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_adc1_swap_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC2 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_adc2_swap_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC3 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_adc3_swap_mux),
+ SND_SOC_DAPM_MUX("IF2 ADC4 Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_adc4_swap_mux),
+ SND_SOC_DAPM_MUX_E("IF2 ADC TDM Swap Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_adc_tdm_swap_mux, rt5677_if2_adc_tdm_event,
+ SND_SOC_DAPM_PRE_PMU),
SND_SOC_DAPM_MUX("IF3 ADC Mux", SND_SOC_NOPM, 0, 0,
&rt5677_if3_adc_mux),
SND_SOC_DAPM_MUX("IF4 ADC Mux", SND_SOC_NOPM, 0, 0,
@@ -1984,6 +2535,40 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_MUX("SLB ADC4 Mux", SND_SOC_NOPM, 0, 0,
&rt5677_slb_adc4_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC0 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac0_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac1_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac2_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC3 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac3_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC4 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac4_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC5 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac5_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC6 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac6_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF1 DAC7 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if1_dac7_tdm_sel_mux),
+
+ SND_SOC_DAPM_MUX("IF2 DAC0 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac0_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC1 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac1_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC2 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac2_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC3 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac3_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC4 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac4_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC5 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac5_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC6 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac6_tdm_sel_mux),
+ SND_SOC_DAPM_MUX("IF2 DAC7 Mux", SND_SOC_NOPM, 0, 0,
+ &rt5677_if2_dac7_tdm_sel_mux),
+
/* Audio Interface */
SND_SOC_DAPM_AIF_IN("AIF1RX", "AIF1 Playback", 0, SND_SOC_NOPM, 0, 0),
SND_SOC_DAPM_AIF_OUT("AIF1TX", "AIF1 Capture", 0, SND_SOC_NOPM, 0, 0),
@@ -2022,7 +2607,7 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
rt5677_ob_7_mix, ARRAY_SIZE(rt5677_ob_7_mix)),
/* Output Side */
- /* DAC mixer before sound effect */
+ /* DAC mixer before sound effect */
SND_SOC_DAPM_MIXER("DAC1 MIXL", SND_SOC_NOPM, 0, 0,
rt5677_dac_l_mix, ARRAY_SIZE(rt5677_dac_l_mix)),
SND_SOC_DAPM_MIXER("DAC1 MIXR", SND_SOC_NOPM, 0, 0,
@@ -2109,13 +2694,20 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_MUX("PDM2 R Mux", RT5677_PDM_OUT_CTRL, RT5677_M_PDM2_R_SFT,
1, &rt5677_pdm2_r_mux),
- SND_SOC_DAPM_PGA_S("LOUT1 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
+ SND_SOC_DAPM_PGA_S("LOUT1 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO1_BIT,
0, NULL, 0),
- SND_SOC_DAPM_PGA_S("LOUT2 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
+ SND_SOC_DAPM_PGA_S("LOUT2 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO2_BIT,
0, NULL, 0),
- SND_SOC_DAPM_PGA_S("LOUT3 amp", 1, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
+ SND_SOC_DAPM_PGA_S("LOUT3 amp", 0, RT5677_PWR_ANLG1, RT5677_PWR_LO3_BIT,
0, NULL, 0),
+ SND_SOC_DAPM_PGA_S("LOUT1 vref", 1, SND_SOC_NOPM, 0, 0,
+ rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("LOUT2 vref", 1, SND_SOC_NOPM, 0, 0,
+ rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+ SND_SOC_DAPM_PGA_S("LOUT3 vref", 1, SND_SOC_NOPM, 0, 0,
+ rt5677_vref_event, SND_SOC_DAPM_POST_PMU),
+
/* Output Lines */
SND_SOC_DAPM_OUTPUT("LOUT1"),
SND_SOC_DAPM_OUTPUT("LOUT2"),
@@ -2124,6 +2716,8 @@ static const struct snd_soc_dapm_widget rt5677_dapm_widgets[] = {
SND_SOC_DAPM_OUTPUT("PDM1R"),
SND_SOC_DAPM_OUTPUT("PDM2L"),
SND_SOC_DAPM_OUTPUT("PDM2R"),
+
+ SND_SOC_DAPM_POST("vref", rt5677_vref_event),
};
static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
@@ -2354,11 +2948,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF1 ADC4 Mux", "OB67", "OB67" },
{ "IF1 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
+ { "IF1 ADC1 Swap Mux", "L/R", "IF1 ADC1 Mux" },
+ { "IF1 ADC1 Swap Mux", "R/L", "IF1 ADC1 Mux" },
+ { "IF1 ADC1 Swap Mux", "L/L", "IF1 ADC1 Mux" },
+ { "IF1 ADC1 Swap Mux", "R/R", "IF1 ADC1 Mux" },
+
+ { "IF1 ADC2 Swap Mux", "L/R", "IF1 ADC2 Mux" },
+ { "IF1 ADC2 Swap Mux", "R/L", "IF1 ADC2 Mux" },
+ { "IF1 ADC2 Swap Mux", "L/L", "IF1 ADC2 Mux" },
+ { "IF1 ADC2 Swap Mux", "R/R", "IF1 ADC2 Mux" },
+
+ { "IF1 ADC3 Swap Mux", "L/R", "IF1 ADC3 Mux" },
+ { "IF1 ADC3 Swap Mux", "R/L", "IF1 ADC3 Mux" },
+ { "IF1 ADC3 Swap Mux", "L/L", "IF1 ADC3 Mux" },
+ { "IF1 ADC3 Swap Mux", "R/R", "IF1 ADC3 Mux" },
+
+ { "IF1 ADC4 Swap Mux", "L/R", "IF1 ADC4 Mux" },
+ { "IF1 ADC4 Swap Mux", "R/L", "IF1 ADC4 Mux" },
+ { "IF1 ADC4 Swap Mux", "L/L", "IF1 ADC4 Mux" },
+ { "IF1 ADC4 Swap Mux", "R/R", "IF1 ADC4 Mux" },
+
+ { "IF1 ADC", NULL, "IF1 ADC1 Swap Mux" },
+ { "IF1 ADC", NULL, "IF1 ADC2 Swap Mux" },
+ { "IF1 ADC", NULL, "IF1 ADC3 Swap Mux" },
+ { "IF1 ADC", NULL, "IF1 ADC4 Swap Mux" },
+
+ { "IF1 ADC TDM Swap Mux", "1/2/3/4", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "2/1/3/4", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "2/3/1/4", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "4/1/2/3", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "1/3/2/4", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "1/4/2/3", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "3/1/2/4", "IF1 ADC" },
+ { "IF1 ADC TDM Swap Mux", "3/4/1/2", "IF1 ADC" },
+
{ "AIF1TX", NULL, "I2S1" },
- { "AIF1TX", NULL, "IF1 ADC1 Mux" },
- { "AIF1TX", NULL, "IF1 ADC2 Mux" },
- { "AIF1TX", NULL, "IF1 ADC3 Mux" },
- { "AIF1TX", NULL, "IF1 ADC4 Mux" },
+ { "AIF1TX", NULL, "IF1 ADC TDM Swap Mux" },
{ "IF2 ADC1 Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
{ "IF2 ADC1 Mux", "OB01", "OB01 Bypass Mux" },
@@ -2375,11 +3000,42 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF2 ADC4 Mux", "OB67", "OB67" },
{ "IF2 ADC4 Mux", "OB01", "OB01 Bypass Mux" },
+ { "IF2 ADC1 Swap Mux", "L/R", "IF2 ADC1 Mux" },
+ { "IF2 ADC1 Swap Mux", "R/L", "IF2 ADC1 Mux" },
+ { "IF2 ADC1 Swap Mux", "L/L", "IF2 ADC1 Mux" },
+ { "IF2 ADC1 Swap Mux", "R/R", "IF2 ADC1 Mux" },
+
+ { "IF2 ADC2 Swap Mux", "L/R", "IF2 ADC2 Mux" },
+ { "IF2 ADC2 Swap Mux", "R/L", "IF2 ADC2 Mux" },
+ { "IF2 ADC2 Swap Mux", "L/L", "IF2 ADC2 Mux" },
+ { "IF2 ADC2 Swap Mux", "R/R", "IF2 ADC2 Mux" },
+
+ { "IF2 ADC3 Swap Mux", "L/R", "IF2 ADC3 Mux" },
+ { "IF2 ADC3 Swap Mux", "R/L", "IF2 ADC3 Mux" },
+ { "IF2 ADC3 Swap Mux", "L/L", "IF2 ADC3 Mux" },
+ { "IF2 ADC3 Swap Mux", "R/R", "IF2 ADC3 Mux" },
+
+ { "IF2 ADC4 Swap Mux", "L/R", "IF2 ADC4 Mux" },
+ { "IF2 ADC4 Swap Mux", "R/L", "IF2 ADC4 Mux" },
+ { "IF2 ADC4 Swap Mux", "L/L", "IF2 ADC4 Mux" },
+ { "IF2 ADC4 Swap Mux", "R/R", "IF2 ADC4 Mux" },
+
+ { "IF2 ADC", NULL, "IF2 ADC1 Swap Mux" },
+ { "IF2 ADC", NULL, "IF2 ADC2 Swap Mux" },
+ { "IF2 ADC", NULL, "IF2 ADC3 Swap Mux" },
+ { "IF2 ADC", NULL, "IF2 ADC4 Swap Mux" },
+
+ { "IF2 ADC TDM Swap Mux", "1/2/3/4", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "2/1/3/4", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "3/1/2/4", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "4/1/2/3", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "1/3/2/4", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "1/4/2/3", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "2/3/1/4", "IF2 ADC" },
+ { "IF2 ADC TDM Swap Mux", "3/4/1/2", "IF2 ADC" },
+
{ "AIF2TX", NULL, "I2S2" },
- { "AIF2TX", NULL, "IF2 ADC1 Mux" },
- { "AIF2TX", NULL, "IF2 ADC2 Mux" },
- { "AIF2TX", NULL, "IF2 ADC3 Mux" },
- { "AIF2TX", NULL, "IF2 ADC4 Mux" },
+ { "AIF2TX", NULL, "IF2 ADC TDM Swap Mux" },
{ "IF3 ADC Mux", "STO1 ADC MIX", "Stereo1 ADC MIX" },
{ "IF3 ADC Mux", "STO2 ADC MIX", "Stereo2 ADC MIX" },
@@ -2569,14 +3225,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF1 DAC6", NULL, "I2S1" },
{ "IF1 DAC7", NULL, "I2S1" },
- { "IF1 DAC01", NULL, "IF1 DAC0" },
- { "IF1 DAC01", NULL, "IF1 DAC1" },
- { "IF1 DAC23", NULL, "IF1 DAC2" },
- { "IF1 DAC23", NULL, "IF1 DAC3" },
- { "IF1 DAC45", NULL, "IF1 DAC4" },
- { "IF1 DAC45", NULL, "IF1 DAC5" },
- { "IF1 DAC67", NULL, "IF1 DAC6" },
- { "IF1 DAC67", NULL, "IF1 DAC7" },
+ { "IF1 DAC0 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC0 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC0 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC0 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC0 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC0 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC0 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC0 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC1 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC1 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC1 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC1 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC1 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC1 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC1 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC1 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC2 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC2 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC2 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC2 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC2 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC2 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC2 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC2 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC3 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC3 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC3 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC3 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC3 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC3 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC3 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC3 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC4 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC4 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC4 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC4 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC4 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC4 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC4 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC4 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC5 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC5 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC5 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC5 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC5 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC5 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC5 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC5 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC6 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC6 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC6 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC6 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC6 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC6 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC6 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC6 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC7 Mux", "Slot0", "IF1 DAC0" },
+ { "IF1 DAC7 Mux", "Slot1", "IF1 DAC1" },
+ { "IF1 DAC7 Mux", "Slot2", "IF1 DAC2" },
+ { "IF1 DAC7 Mux", "Slot3", "IF1 DAC3" },
+ { "IF1 DAC7 Mux", "Slot4", "IF1 DAC4" },
+ { "IF1 DAC7 Mux", "Slot5", "IF1 DAC5" },
+ { "IF1 DAC7 Mux", "Slot6", "IF1 DAC6" },
+ { "IF1 DAC7 Mux", "Slot7", "IF1 DAC7" },
+
+ { "IF1 DAC01", NULL, "IF1 DAC0 Mux" },
+ { "IF1 DAC01", NULL, "IF1 DAC1 Mux" },
+ { "IF1 DAC23", NULL, "IF1 DAC2 Mux" },
+ { "IF1 DAC23", NULL, "IF1 DAC3 Mux" },
+ { "IF1 DAC45", NULL, "IF1 DAC4 Mux" },
+ { "IF1 DAC45", NULL, "IF1 DAC5 Mux" },
+ { "IF1 DAC67", NULL, "IF1 DAC6 Mux" },
+ { "IF1 DAC67", NULL, "IF1 DAC7 Mux" },
{ "IF2 DAC0", NULL, "AIF2RX" },
{ "IF2 DAC1", NULL, "AIF2RX" },
@@ -2595,14 +3323,86 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "IF2 DAC6", NULL, "I2S2" },
{ "IF2 DAC7", NULL, "I2S2" },
- { "IF2 DAC01", NULL, "IF2 DAC0" },
- { "IF2 DAC01", NULL, "IF2 DAC1" },
- { "IF2 DAC23", NULL, "IF2 DAC2" },
- { "IF2 DAC23", NULL, "IF2 DAC3" },
- { "IF2 DAC45", NULL, "IF2 DAC4" },
- { "IF2 DAC45", NULL, "IF2 DAC5" },
- { "IF2 DAC67", NULL, "IF2 DAC6" },
- { "IF2 DAC67", NULL, "IF2 DAC7" },
+ { "IF2 DAC0 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC0 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC0 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC0 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC0 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC0 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC0 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC0 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC1 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC1 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC1 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC1 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC1 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC1 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC1 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC1 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC2 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC2 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC2 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC2 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC2 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC2 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC2 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC2 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC3 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC3 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC3 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC3 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC3 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC3 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC3 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC3 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC4 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC4 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC4 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC4 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC4 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC4 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC4 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC4 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC5 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC5 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC5 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC5 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC5 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC5 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC5 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC5 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC6 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC6 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC6 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC6 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC6 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC6 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC6 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC6 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC7 Mux", "Slot0", "IF2 DAC0" },
+ { "IF2 DAC7 Mux", "Slot1", "IF2 DAC1" },
+ { "IF2 DAC7 Mux", "Slot2", "IF2 DAC2" },
+ { "IF2 DAC7 Mux", "Slot3", "IF2 DAC3" },
+ { "IF2 DAC7 Mux", "Slot4", "IF2 DAC4" },
+ { "IF2 DAC7 Mux", "Slot5", "IF2 DAC5" },
+ { "IF2 DAC7 Mux", "Slot6", "IF2 DAC6" },
+ { "IF2 DAC7 Mux", "Slot7", "IF2 DAC7" },
+
+ { "IF2 DAC01", NULL, "IF2 DAC0 Mux" },
+ { "IF2 DAC01", NULL, "IF2 DAC1 Mux" },
+ { "IF2 DAC23", NULL, "IF2 DAC2 Mux" },
+ { "IF2 DAC23", NULL, "IF2 DAC3 Mux" },
+ { "IF2 DAC45", NULL, "IF2 DAC4 Mux" },
+ { "IF2 DAC45", NULL, "IF2 DAC5 Mux" },
+ { "IF2 DAC67", NULL, "IF2 DAC6 Mux" },
+ { "IF2 DAC67", NULL, "IF2 DAC7 Mux" },
{ "IF3 DAC", NULL, "AIF3RX" },
{ "IF3 DAC", NULL, "I2S3" },
@@ -2806,9 +3606,13 @@ static const struct snd_soc_dapm_route rt5677_dapm_routes[] = {
{ "LOUT2 amp", NULL, "DAC 2" },
{ "LOUT3 amp", NULL, "DAC 3" },
- { "LOUT1", NULL, "LOUT1 amp" },
- { "LOUT2", NULL, "LOUT2 amp" },
- { "LOUT3", NULL, "LOUT3 amp" },
+ { "LOUT1 vref", NULL, "LOUT1 amp" },
+ { "LOUT2 vref", NULL, "LOUT2 amp" },
+ { "LOUT3 vref", NULL, "LOUT3 amp" },
+
+ { "LOUT1", NULL, "LOUT1 vref" },
+ { "LOUT2", NULL, "LOUT2 vref" },
+ { "LOUT3", NULL, "LOUT3 vref" },
{ "PDM1L", NULL, "PDM1 L Mux" },
{ "PDM1R", NULL, "PDM1 R Mux" },
@@ -2837,7 +3641,8 @@ static int rt5677_hw_params(struct snd_pcm_substream *substream,
rt5677->lrck[dai->id] = params_rate(params);
pre_div = rl6231_get_clk_info(rt5677->sysclk, rt5677->lrck[dai->id]);
if (pre_div < 0) {
- dev_err(codec->dev, "Unsupported clock setting\n");
+ dev_err(codec->dev, "Unsupported clock setting: sysclk=%dHz lrck=%dHz\n",
+ rt5677->sysclk, rt5677->lrck[dai->id]);
return -EINVAL;
}
frame_size = snd_soc_params_to_frame_size(params);
@@ -3181,6 +3986,8 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
case SND_SOC_BIAS_PREPARE:
if (codec->dapm.bias_level == SND_SOC_BIAS_STANDBY) {
+ rt5677_set_dsp_vad(codec, false);
+
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
RT5677_LDO1_SEL_MASK | RT5677_LDO2_SEL_MASK,
0x0055);
@@ -3188,14 +3995,12 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
RT5677_PR_BASE + RT5677_BIAS_CUR4,
0x0f00, 0x0f00);
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
+ RT5677_PWR_FV1 | RT5677_PWR_FV2 |
RT5677_PWR_VREF1 | RT5677_PWR_MB |
RT5677_PWR_BG | RT5677_PWR_VREF2,
RT5677_PWR_VREF1 | RT5677_PWR_MB |
RT5677_PWR_BG | RT5677_PWR_VREF2);
- mdelay(20);
- regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG1,
- RT5677_PWR_FV1 | RT5677_PWR_FV2,
- RT5677_PWR_FV1 | RT5677_PWR_FV2);
+ rt5677->is_vref_slow = false;
regmap_update_bits(rt5677->regmap, RT5677_PWR_ANLG2,
RT5677_PWR_CORE, RT5677_PWR_CORE);
regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC,
@@ -3214,6 +4019,9 @@ static int rt5677_set_bias_level(struct snd_soc_codec *codec,
regmap_write(rt5677->regmap, RT5677_PWR_ANLG2, 0x0000);
regmap_update_bits(rt5677->regmap,
RT5677_PR_BASE + RT5677_BIAS_CUR4, 0x0f00, 0x0000);
+
+ if (rt5677->dsp_vad_en)
+ rt5677_set_dsp_vad(codec, true);
break;
default:
@@ -3309,6 +4117,78 @@ static int rt5677_gpio_direction_in(struct gpio_chip *chip, unsigned offset)
return 0;
}
+/** Configures the gpio as
+ * 0 - floating
+ * 1 - pull down
+ * 2 - pull up
+ */
+static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
+ int value)
+{
+ int shift;
+
+ switch (offset) {
+ case RT5677_GPIO1 ... RT5677_GPIO2:
+ shift = 2 * (1 - offset);
+ regmap_update_bits(rt5677->regmap,
+ RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL2,
+ 0x3 << shift,
+ (value & 0x3) << shift);
+ break;
+
+ case RT5677_GPIO3 ... RT5677_GPIO6:
+ shift = 2 * (9 - offset);
+ regmap_update_bits(rt5677->regmap,
+ RT5677_PR_BASE + RT5677_DIG_IN_PIN_ST_CTRL3,
+ 0x3 << shift,
+ (value & 0x3) << shift);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static int rt5677_to_irq(struct gpio_chip *chip, unsigned offset)
+{
+ struct rt5677_priv *rt5677 = gpio_to_rt5677(chip);
+ struct regmap_irq_chip_data *data = rt5677->irq_data;
+ int irq;
+
+ if (offset >= RT5677_GPIO1 && offset <= RT5677_GPIO3) {
+ if ((rt5677->pdata.jd1_gpio == 1 && offset == RT5677_GPIO1) ||
+ (rt5677->pdata.jd1_gpio == 2 &&
+ offset == RT5677_GPIO2) ||
+ (rt5677->pdata.jd1_gpio == 3 &&
+ offset == RT5677_GPIO3)) {
+ irq = RT5677_IRQ_JD1;
+ } else {
+ return -ENXIO;
+ }
+ }
+
+ if (offset >= RT5677_GPIO4 && offset <= RT5677_GPIO6) {
+ if ((rt5677->pdata.jd2_gpio == 1 && offset == RT5677_GPIO4) ||
+ (rt5677->pdata.jd2_gpio == 2 &&
+ offset == RT5677_GPIO5) ||
+ (rt5677->pdata.jd2_gpio == 3 &&
+ offset == RT5677_GPIO6)) {
+ irq = RT5677_IRQ_JD2;
+ } else if ((rt5677->pdata.jd3_gpio == 1 &&
+ offset == RT5677_GPIO4) ||
+ (rt5677->pdata.jd3_gpio == 2 &&
+ offset == RT5677_GPIO5) ||
+ (rt5677->pdata.jd3_gpio == 3 &&
+ offset == RT5677_GPIO6)) {
+ irq = RT5677_IRQ_JD3;
+ } else {
+ return -ENXIO;
+ }
+ }
+
+ return regmap_irq_get_virq(data, irq);
+}
+
static struct gpio_chip rt5677_template_chip = {
.label = "rt5677",
.owner = THIS_MODULE,
@@ -3316,6 +4196,7 @@ static struct gpio_chip rt5677_template_chip = {
.set = rt5677_gpio_set,
.direction_input = rt5677_gpio_direction_in,
.get = rt5677_gpio_get,
+ .to_irq = rt5677_to_irq,
.can_sleep = 1,
};
@@ -3341,6 +4222,11 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
gpiochip_remove(&rt5677->gpio_chip);
}
#else
+static void rt5677_gpio_config(struct rt5677_priv *rt5677, unsigned offset,
+ int value)
+{
+}
+
static void rt5677_init_gpio(struct i2c_client *i2c)
{
}
@@ -3353,6 +4239,7 @@ static void rt5677_free_gpio(struct i2c_client *i2c)
static int rt5677_probe(struct snd_soc_codec *codec)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
+ int i;
rt5677->codec = codec;
@@ -3371,6 +4258,37 @@ static int rt5677_probe(struct snd_soc_codec *codec)
regmap_write(rt5677->regmap, RT5677_DIG_MISC, 0x0020);
regmap_write(rt5677->regmap, RT5677_PWR_DSP2, 0x0c00);
+ for (i = 0; i < RT5677_GPIO_NUM; i++)
+ rt5677_gpio_config(rt5677, i, rt5677->pdata.gpio_config[i]);
+
+ if (rt5677->irq_data) {
+ regmap_update_bits(rt5677->regmap, RT5677_GPIO_CTRL1, 0x8000,
+ 0x8000);
+ regmap_update_bits(rt5677->regmap, RT5677_DIG_MISC, 0x0018,
+ 0x0008);
+
+ if (rt5677->pdata.jd1_gpio)
+ regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+ RT5677_SEL_GPIO_JD1_MASK,
+ rt5677->pdata.jd1_gpio <<
+ RT5677_SEL_GPIO_JD1_SFT);
+
+ if (rt5677->pdata.jd2_gpio)
+ regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+ RT5677_SEL_GPIO_JD2_MASK,
+ rt5677->pdata.jd2_gpio <<
+ RT5677_SEL_GPIO_JD2_SFT);
+
+ if (rt5677->pdata.jd3_gpio)
+ regmap_update_bits(rt5677->regmap, RT5677_JD_CTRL1,
+ RT5677_SEL_GPIO_JD3_MASK,
+ rt5677->pdata.jd3_gpio <<
+ RT5677_SEL_GPIO_JD3_SFT);
+ }
+
+ mutex_init(&rt5677->dsp_cmd_lock);
+ mutex_init(&rt5677->dsp_pri_lock);
+
return 0;
}
@@ -3390,8 +4308,11 @@ static int rt5677_suspend(struct snd_soc_codec *codec)
{
struct rt5677_priv *rt5677 = snd_soc_codec_get_drvdata(codec);
- regcache_cache_only(rt5677->regmap, true);
- regcache_mark_dirty(rt5677->regmap);
+ if (!rt5677->dsp_vad_en) {
+ regcache_cache_only(rt5677->regmap, true);
+ regcache_mark_dirty(rt5677->regmap);
+ }
+
if (gpio_is_valid(rt5677->pow_ldo2))
gpio_set_value_cansleep(rt5677->pow_ldo2, 0);
@@ -3406,8 +4327,11 @@ static int rt5677_resume(struct snd_soc_codec *codec)
gpio_set_value_cansleep(rt5677->pow_ldo2, 1);
msleep(10);
}
- regcache_cache_only(rt5677->regmap, false);
- regcache_sync(rt5677->regmap);
+
+ if (!rt5677->dsp_vad_en) {
+ regcache_cache_only(rt5677->regmap, false);
+ regcache_sync(rt5677->regmap);
+ }
return 0;
}
@@ -3416,6 +4340,51 @@ static int rt5677_resume(struct snd_soc_codec *codec)
#define rt5677_resume NULL
#endif
+static int rt5677_read(void *context, unsigned int reg, unsigned int *val)
+{
+ struct i2c_client *client = context;
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
+
+ if (rt5677->is_dsp_mode) {
+ if (reg > 0xff) {
+ mutex_lock(&rt5677->dsp_pri_lock);
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+ reg & 0xff);
+ rt5677_dsp_mode_i2c_read(rt5677, RT5677_PRIV_DATA, val);
+ mutex_unlock(&rt5677->dsp_pri_lock);
+ } else {
+ rt5677_dsp_mode_i2c_read(rt5677, reg, val);
+ }
+ } else {
+ regmap_read(rt5677->regmap_physical, reg, val);
+ }
+
+ return 0;
+}
+
+static int rt5677_write(void *context, unsigned int reg, unsigned int val)
+{
+ struct i2c_client *client = context;
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(client);
+
+ if (rt5677->is_dsp_mode) {
+ if (reg > 0xff) {
+ mutex_lock(&rt5677->dsp_pri_lock);
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_INDEX,
+ reg & 0xff);
+ rt5677_dsp_mode_i2c_write(rt5677, RT5677_PRIV_DATA,
+ val);
+ mutex_unlock(&rt5677->dsp_pri_lock);
+ } else {
+ rt5677_dsp_mode_i2c_write(rt5677, reg, val);
+ }
+ } else {
+ regmap_write(rt5677->regmap_physical, reg, val);
+ }
+
+ return 0;
+}
+
#define RT5677_STEREO_RATES SNDRV_PCM_RATE_8000_96000
#define RT5677_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE | \
SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S8)
@@ -3541,6 +4510,20 @@ static struct snd_soc_codec_driver soc_codec_dev_rt5677 = {
.num_dapm_routes = ARRAY_SIZE(rt5677_dapm_routes),
};
+static const struct regmap_config rt5677_regmap_physical = {
+ .name = "physical",
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .max_register = RT5677_VENDOR_ID2 + 1 + (ARRAY_SIZE(rt5677_ranges) *
+ RT5677_PR_SPACING),
+ .readable_reg = rt5677_readable_register,
+
+ .cache_type = REGCACHE_NONE,
+ .ranges = rt5677_ranges,
+ .num_ranges = ARRAY_SIZE(rt5677_ranges),
+};
+
static const struct regmap_config rt5677_regmap = {
.reg_bits = 8,
.val_bits = 16,
@@ -3550,6 +4533,8 @@ static const struct regmap_config rt5677_regmap = {
.volatile_reg = rt5677_volatile_register,
.readable_reg = rt5677_readable_register,
+ .reg_read = rt5677_read,
+ .reg_write = rt5677_write,
.cache_type = REGCACHE_RBTREE,
.reg_defaults = rt5677_reg,
@@ -3590,9 +4575,77 @@ static int rt5677_parse_dt(struct rt5677_priv *rt5677, struct device_node *np)
(rt5677->pow_ldo2 != -ENOENT))
return rt5677->pow_ldo2;
+ of_property_read_u8_array(np, "realtek,gpio-config",
+ rt5677->pdata.gpio_config, RT5677_GPIO_NUM);
+
+ of_property_read_u32(np, "realtek,jd1-gpio", &rt5677->pdata.jd1_gpio);
+ of_property_read_u32(np, "realtek,jd2-gpio", &rt5677->pdata.jd2_gpio);
+ of_property_read_u32(np, "realtek,jd3-gpio", &rt5677->pdata.jd3_gpio);
+
+ return 0;
+}
+
+static struct regmap_irq rt5677_irqs[] = {
+ [RT5677_IRQ_JD1] = {
+ .reg_offset = 0,
+ .mask = RT5677_EN_IRQ_GPIO_JD1,
+ },
+ [RT5677_IRQ_JD2] = {
+ .reg_offset = 0,
+ .mask = RT5677_EN_IRQ_GPIO_JD2,
+ },
+ [RT5677_IRQ_JD3] = {
+ .reg_offset = 0,
+ .mask = RT5677_EN_IRQ_GPIO_JD3,
+ },
+};
+
+static struct regmap_irq_chip rt5677_irq_chip = {
+ .name = "rt5677",
+ .irqs = rt5677_irqs,
+ .num_irqs = ARRAY_SIZE(rt5677_irqs),
+
+ .num_regs = 1,
+ .status_base = RT5677_IRQ_CTRL1,
+ .mask_base = RT5677_IRQ_CTRL1,
+ .mask_invert = 1,
+};
+
+static int rt5677_init_irq(struct i2c_client *i2c)
+{
+ int ret;
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+ if (!rt5677->pdata.jd1_gpio &&
+ !rt5677->pdata.jd2_gpio &&
+ !rt5677->pdata.jd3_gpio)
+ return 0;
+
+ if (!i2c->irq) {
+ dev_err(&i2c->dev, "No interrupt specified\n");
+ return -EINVAL;
+ }
+
+ ret = regmap_add_irq_chip(rt5677->regmap, i2c->irq,
+ IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT, 0,
+ &rt5677_irq_chip, &rt5677->irq_data);
+
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to register IRQ chip: %d\n", ret);
+ return ret;
+ }
+
return 0;
}
+static void rt5677_free_irq(struct i2c_client *i2c)
+{
+ struct rt5677_priv *rt5677 = i2c_get_clientdata(i2c);
+
+ if (rt5677->irq_data)
+ regmap_del_irq_chip(i2c->irq, rt5677->irq_data);
+}
+
static int rt5677_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -3638,7 +4691,16 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
msleep(10);
}
- rt5677->regmap = devm_regmap_init_i2c(i2c, &rt5677_regmap);
+ rt5677->regmap_physical = devm_regmap_init_i2c(i2c,
+ &rt5677_regmap_physical);
+ if (IS_ERR(rt5677->regmap_physical)) {
+ ret = PTR_ERR(rt5677->regmap_physical);
+ dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
+ ret);
+ return ret;
+ }
+
+ rt5677->regmap = devm_regmap_init(&i2c->dev, NULL, i2c, &rt5677_regmap);
if (IS_ERR(rt5677->regmap)) {
ret = PTR_ERR(rt5677->regmap);
dev_err(&i2c->dev, "Failed to allocate register map: %d\n",
@@ -3690,6 +4752,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
}
rt5677_init_gpio(i2c);
+ rt5677_init_irq(i2c);
return snd_soc_register_codec(&i2c->dev, &soc_codec_dev_rt5677,
rt5677_dai, ARRAY_SIZE(rt5677_dai));
@@ -3698,6 +4761,7 @@ static int rt5677_i2c_probe(struct i2c_client *i2c,
static int rt5677_i2c_remove(struct i2c_client *i2c)
{
snd_soc_unregister_codec(&i2c->dev);
+ rt5677_free_irq(i2c);
rt5677_free_gpio(i2c);
return 0;
diff --git a/sound/soc/codecs/rt5677.h b/sound/soc/codecs/rt5677.h
index d4eb6d5..c0a625f 100644
--- a/sound/soc/codecs/rt5677.h
+++ b/sound/soc/codecs/rt5677.h
@@ -13,6 +13,7 @@
#define __RT5677_H__
#include <sound/rt5677.h>
+#include <linux/gpio/driver.h>
/* Info */
#define RT5677_RESET 0x00
@@ -305,10 +306,10 @@
#define RT5677_R_MUTE_SFT 7
#define RT5677_VOL_R_MUTE (0x1 << 6)
#define RT5677_VOL_R_SFT 6
-#define RT5677_L_VOL_MASK (0x3f << 8)
-#define RT5677_L_VOL_SFT 8
-#define RT5677_R_VOL_MASK (0x3f)
-#define RT5677_R_VOL_SFT 0
+#define RT5677_L_VOL_MASK (0x7f << 9)
+#define RT5677_L_VOL_SFT 9
+#define RT5677_R_VOL_MASK (0x7f << 1)
+#define RT5677_R_VOL_SFT 1
/* LOUT1 Control (0x01) */
#define RT5677_LOUT1_L_MUTE (0x1 << 15)
@@ -446,16 +447,16 @@
#define RT5677_SEL_DAC2_R_SRC_SFT 0
/* Stereo1 ADC Digital Volume Control (0x1c) */
-#define RT5677_STO1_ADC_L_VOL_MASK (0x7f << 8)
-#define RT5677_STO1_ADC_L_VOL_SFT 8
-#define RT5677_STO1_ADC_R_VOL_MASK (0x7f)
-#define RT5677_STO1_ADC_R_VOL_SFT 0
+#define RT5677_STO1_ADC_L_VOL_MASK (0x3f << 9)
+#define RT5677_STO1_ADC_L_VOL_SFT 9
+#define RT5677_STO1_ADC_R_VOL_MASK (0x3f << 1)
+#define RT5677_STO1_ADC_R_VOL_SFT 1
/* Mono ADC Digital Volume Control (0x1d) */
-#define RT5677_MONO_ADC_L_VOL_MASK (0x7f << 8)
-#define RT5677_MONO_ADC_L_VOL_SFT 8
-#define RT5677_MONO_ADC_R_VOL_MASK (0x7f)
-#define RT5677_MONO_ADC_R_VOL_SFT 0
+#define RT5677_MONO_ADC_L_VOL_MASK (0x3f << 9)
+#define RT5677_MONO_ADC_L_VOL_SFT 9
+#define RT5677_MONO_ADC_R_VOL_MASK (0x3f << 1)
+#define RT5677_MONO_ADC_R_VOL_SFT 1
/* Stereo 1/2 ADC Boost Gain Control (0x1e) */
#define RT5677_STO1_ADC_L_BST_MASK (0x3 << 14)
@@ -798,7 +799,21 @@
#define RT5677_PDM2_I2C_EXE (0x1 << 1)
#define RT5677_PDM2_I2C_BUSY (0x1 << 0)
-/* MX3C TDM1 control 1 (0x3c) */
+/* TDM1 control 1 (0x3b) */
+#define RT5677_IF1_ADC_MODE_MASK (0x1 << 12)
+#define RT5677_IF1_ADC_MODE_SFT 12
+#define RT5677_IF1_ADC_MODE_I2S (0x0 << 12)
+#define RT5677_IF1_ADC_MODE_TDM (0x1 << 12)
+#define RT5677_IF1_ADC1_SWAP_MASK (0x3 << 6)
+#define RT5677_IF1_ADC1_SWAP_SFT 6
+#define RT5677_IF1_ADC2_SWAP_MASK (0x3 << 4)
+#define RT5677_IF1_ADC2_SWAP_SFT 4
+#define RT5677_IF1_ADC3_SWAP_MASK (0x3 << 2)
+#define RT5677_IF1_ADC3_SWAP_SFT 2
+#define RT5677_IF1_ADC4_SWAP_MASK (0x3 << 0)
+#define RT5677_IF1_ADC4_SWAP_SFT 0
+
+/* TDM1 control 2 (0x3c) */
#define RT5677_IF1_ADC4_MASK (0x3 << 10)
#define RT5677_IF1_ADC4_SFT 10
#define RT5677_IF1_ADC3_MASK (0x3 << 8)
@@ -807,8 +822,44 @@
#define RT5677_IF1_ADC2_SFT 6
#define RT5677_IF1_ADC1_MASK (0x3 << 4)
#define RT5677_IF1_ADC1_SFT 4
-
-/* MX41 TDM2 control 1 (0x41) */
+#define RT5677_IF1_ADC_CTRL_MASK (0x7 << 0)
+#define RT5677_IF1_ADC_CTRL_SFT 0
+
+/* TDM1 control 4 (0x3e) */
+#define RT5677_IF1_DAC0_MASK (0x7 << 12)
+#define RT5677_IF1_DAC0_SFT 12
+#define RT5677_IF1_DAC1_MASK (0x7 << 8)
+#define RT5677_IF1_DAC1_SFT 8
+#define RT5677_IF1_DAC2_MASK (0x7 << 4)
+#define RT5677_IF1_DAC2_SFT 4
+#define RT5677_IF1_DAC3_MASK (0x7 << 0)
+#define RT5677_IF1_DAC3_SFT 0
+
+/* TDM1 control 5 (0x3f) */
+#define RT5677_IF1_DAC4_MASK (0x7 << 12)
+#define RT5677_IF1_DAC4_SFT 12
+#define RT5677_IF1_DAC5_MASK (0x7 << 8)
+#define RT5677_IF1_DAC5_SFT 8
+#define RT5677_IF1_DAC6_MASK (0x7 << 4)
+#define RT5677_IF1_DAC6_SFT 4
+#define RT5677_IF1_DAC7_MASK (0x7 << 0)
+#define RT5677_IF1_DAC7_SFT 0
+
+/* TDM2 control 1 (0x40) */
+#define RT5677_IF2_ADC_MODE_MASK (0x1 << 12)
+#define RT5677_IF2_ADC_MODE_SFT 12
+#define RT5677_IF2_ADC_MODE_I2S (0x0 << 12)
+#define RT5677_IF2_ADC_MODE_TDM (0x1 << 12)
+#define RT5677_IF2_ADC1_SWAP_MASK (0x3 << 6)
+#define RT5677_IF2_ADC1_SWAP_SFT 6
+#define RT5677_IF2_ADC2_SWAP_MASK (0x3 << 4)
+#define RT5677_IF2_ADC2_SWAP_SFT 4
+#define RT5677_IF2_ADC3_SWAP_MASK (0x3 << 2)
+#define RT5677_IF2_ADC3_SWAP_SFT 2
+#define RT5677_IF2_ADC4_SWAP_MASK (0x3 << 0)
+#define RT5677_IF2_ADC4_SWAP_SFT 0
+
+/* TDM2 control 2 (0x41) */
#define RT5677_IF2_ADC4_MASK (0x3 << 10)
#define RT5677_IF2_ADC4_SFT 10
#define RT5677_IF2_ADC3_MASK (0x3 << 8)
@@ -817,6 +868,28 @@
#define RT5677_IF2_ADC2_SFT 6
#define RT5677_IF2_ADC1_MASK (0x3 << 4)
#define RT5677_IF2_ADC1_SFT 4
+#define RT5677_IF2_ADC_CTRL_MASK (0x7 << 0)
+#define RT5677_IF2_ADC_CTRL_SFT 0
+
+/* TDM2 control 4 (0x43) */
+#define RT5677_IF2_DAC0_MASK (0x7 << 12)
+#define RT5677_IF2_DAC0_SFT 12
+#define RT5677_IF2_DAC1_MASK (0x7 << 8)
+#define RT5677_IF2_DAC1_SFT 8
+#define RT5677_IF2_DAC2_MASK (0x7 << 4)
+#define RT5677_IF2_DAC2_SFT 4
+#define RT5677_IF2_DAC3_MASK (0x7 << 0)
+#define RT5677_IF2_DAC3_SFT 0
+
+/* TDM2 control 5 (0x44) */
+#define RT5677_IF2_DAC4_MASK (0x7 << 12)
+#define RT5677_IF2_DAC4_SFT 12
+#define RT5677_IF2_DAC5_MASK (0x7 << 8)
+#define RT5677_IF2_DAC5_SFT 8
+#define RT5677_IF2_DAC6_MASK (0x7 << 4)
+#define RT5677_IF2_DAC6_SFT 4
+#define RT5677_IF2_DAC7_MASK (0x7 << 0)
+#define RT5677_IF2_DAC7_SFT 0
/* Digital Microphone Control 1 (0x50) */
#define RT5677_DMIC_1_EN_MASK (0x1 << 15)
@@ -1367,6 +1440,48 @@
#define RT5677_SEL_SRC_IB01 (0x1 << 0)
#define RT5677_SEL_SRC_IB01_SFT 0
+/* Jack Detect Control 1 (0xb5) */
+#define RT5677_SEL_GPIO_JD1_MASK (0x3 << 14)
+#define RT5677_SEL_GPIO_JD1_SFT 14
+#define RT5677_SEL_GPIO_JD2_MASK (0x3 << 12)
+#define RT5677_SEL_GPIO_JD2_SFT 12
+#define RT5677_SEL_GPIO_JD3_MASK (0x3 << 10)
+#define RT5677_SEL_GPIO_JD3_SFT 10
+
+/* IRQ Control 1 (0xbd) */
+#define RT5677_STA_GPIO_JD1 (0x1 << 15)
+#define RT5677_STA_GPIO_JD1_SFT 15
+#define RT5677_EN_IRQ_GPIO_JD1 (0x1 << 14)
+#define RT5677_EN_IRQ_GPIO_JD1_SFT 14
+#define RT5677_EN_GPIO_JD1_STICKY (0x1 << 13)
+#define RT5677_EN_GPIO_JD1_STICKY_SFT 13
+#define RT5677_INV_GPIO_JD1 (0x1 << 12)
+#define RT5677_INV_GPIO_JD1_SFT 12
+#define RT5677_STA_GPIO_JD2 (0x1 << 11)
+#define RT5677_STA_GPIO_JD2_SFT 11
+#define RT5677_EN_IRQ_GPIO_JD2 (0x1 << 10)
+#define RT5677_EN_IRQ_GPIO_JD2_SFT 10
+#define RT5677_EN_GPIO_JD2_STICKY (0x1 << 9)
+#define RT5677_EN_GPIO_JD2_STICKY_SFT 9
+#define RT5677_INV_GPIO_JD2 (0x1 << 8)
+#define RT5677_INV_GPIO_JD2_SFT 8
+#define RT5677_STA_MICBIAS1_OVCD (0x1 << 7)
+#define RT5677_STA_MICBIAS1_OVCD_SFT 7
+#define RT5677_EN_IRQ_MICBIAS1_OVCD (0x1 << 6)
+#define RT5677_EN_IRQ_MICBIAS1_OVCD_SFT 6
+#define RT5677_EN_MICBIAS1_OVCD_STICKY (0x1 << 5)
+#define RT5677_EN_MICBIAS1_OVCD_STICKY_SFT 5
+#define RT5677_INV_MICBIAS1_OVCD (0x1 << 4)
+#define RT5677_INV_MICBIAS1_OVCD_SFT 4
+#define RT5677_STA_GPIO_JD3 (0x1 << 3)
+#define RT5677_STA_GPIO_JD3_SFT 3
+#define RT5677_EN_IRQ_GPIO_JD3 (0x1 << 2)
+#define RT5677_EN_IRQ_GPIO_JD3_SFT 2
+#define RT5677_EN_GPIO_JD3_STICKY (0x1 << 1)
+#define RT5677_EN_GPIO_JD3_STICKY_SFT 1
+#define RT5677_INV_GPIO_JD3 (0x1 << 0)
+#define RT5677_INV_GPIO_JD3_SFT 0
+
/* GPIO status (0xbf) */
#define RT5677_GPIO6_STATUS_MASK (0x1 << 5)
#define RT5677_GPIO6_STATUS_SFT 5
@@ -1506,6 +1621,9 @@
#define RT5677_GPIO5_FUNC_GPIO (0x0 << 9)
#define RT5677_GPIO5_FUNC_DMIC (0x1 << 9)
+#define RT5677_FIRMWARE1 "rt5677_dsp_fw1.bin"
+#define RT5677_FIRMWARE2 "rt5677_dsp_fw2.bin"
+
/* System Clock Source */
enum {
RT5677_SCLK_S_MCLK,
@@ -1541,10 +1659,18 @@ enum {
RT5677_GPIO_NUM,
};
+enum {
+ RT5677_IRQ_JD1,
+ RT5677_IRQ_JD2,
+ RT5677_IRQ_JD3,
+};
+
struct rt5677_priv {
struct snd_soc_codec *codec;
struct rt5677_platform_data pdata;
- struct regmap *regmap;
+ struct regmap *regmap, *regmap_physical;
+ const struct firmware *fw1, *fw2;
+ struct mutex dsp_cmd_lock, dsp_pri_lock;
int sysclk;
int sysclk_src;
@@ -1558,6 +1684,10 @@ struct rt5677_priv {
#ifdef CONFIG_GPIOLIB
struct gpio_chip gpio_chip;
#endif
+ bool dsp_vad_en;
+ struct regmap_irq_chip_data *irq_data;
+ bool is_dsp_mode;
+ bool is_vref_slow;
};
#endif /* __RT5677_H__ */
diff --git a/sound/soc/codecs/sgtl5000.c b/sound/soc/codecs/sgtl5000.c
index dab9b15..29cf7ce 100644
--- a/sound/soc/codecs/sgtl5000.c
+++ b/sound/soc/codecs/sgtl5000.c
@@ -16,6 +16,7 @@
#include <linux/pm.h>
#include <linux/i2c.h>
#include <linux/clk.h>
+#include <linux/log2.h>
#include <linux/regmap.h>
#include <linux/regulator/driver.h>
#include <linux/regulator/machine.h>
@@ -121,6 +122,13 @@ struct ldo_regulator {
bool enabled;
};
+enum sgtl5000_micbias_resistor {
+ SGTL5000_MICBIAS_OFF = 0,
+ SGTL5000_MICBIAS_2K = 2,
+ SGTL5000_MICBIAS_4K = 4,
+ SGTL5000_MICBIAS_8K = 8,
+};
+
/* sgtl5000 private structure in codec */
struct sgtl5000_priv {
int sysclk; /* sysclk rate */
@@ -131,6 +139,8 @@ struct sgtl5000_priv {
struct regmap *regmap;
struct clk *mclk;
int revision;
+ u8 micbias_resistor;
+ u8 micbias_voltage;
};
/*
@@ -145,12 +155,14 @@ struct sgtl5000_priv {
static int mic_bias_event(struct snd_soc_dapm_widget *w,
struct snd_kcontrol *kcontrol, int event)
{
+ struct sgtl5000_priv *sgtl5000 = snd_soc_codec_get_drvdata(w->codec);
+
switch (event) {
case SND_SOC_DAPM_POST_PMU:
- /* change mic bias resistor to 4Kohm */
+ /* change mic bias resistor */
snd_soc_update_bits(w->codec, SGTL5000_CHIP_MIC_CTRL,
- SGTL5000_BIAS_R_MASK,
- SGTL5000_BIAS_R_4k << SGTL5000_BIAS_R_SHIFT);
+ SGTL5000_BIAS_R_MASK,
+ sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
break;
case SND_SOC_DAPM_PRE_PMD:
@@ -530,16 +542,16 @@ static int sgtl5000_set_dai_sysclk(struct snd_soc_dai *codec_dai,
/*
* set clock according to i2s frame clock,
- * sgtl5000 provide 2 clock sources.
- * 1. sys_mclk. sample freq can only configure to
+ * sgtl5000 provides 2 clock sources:
+ * 1. sys_mclk: sample freq can only be configured to
* 1/256, 1/384, 1/512 of sys_mclk.
- * 2. pll. can derive any audio clocks.
+ * 2. pll: can derive any audio clocks.
*
* clock setting rules:
- * 1. in slave mode, only sys_mclk can use.
- * 2. as constraint by sys_mclk, sample freq should
- * set to 32k, 44.1k and above.
- * 3. using sys_mclk prefer to pll to save power.
+ * 1. in slave mode, only sys_mclk can be used
+ * 2. as constraint by sys_mclk, sample freq should be set to 32 kHz, 44.1 kHz
+ * and above.
+ * 3. usage of sys_mclk is preferred over pll to save power.
*/
static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
{
@@ -549,8 +561,8 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
/*
* sample freq should be divided by frame clock,
- * if frame clock lower than 44.1khz, sample feq should set to
- * 32khz or 44.1khz.
+ * if frame clock is lower than 44.1 kHz, sample freq should be set to
+ * 32 kHz or 44.1 kHz.
*/
switch (frame_rate) {
case 8000:
@@ -603,9 +615,10 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
/*
* calculate the divider of mclk/sample_freq,
- * factor of freq =96k can only be 256, since mclk in range (12m,27m)
+ * factor of freq = 96 kHz can only be 256, since mclk is in the range
+ * of 8 MHz - 27 MHz
*/
- switch (sgtl5000->sysclk / sys_fs) {
+ switch (sgtl5000->sysclk / frame_rate) {
case 256:
clk_ctl |= SGTL5000_MCLK_FREQ_256FS <<
SGTL5000_MCLK_FREQ_SHIFT;
@@ -619,7 +632,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
SGTL5000_MCLK_FREQ_SHIFT;
break;
default:
- /* if mclk not satisify the divider, use pll */
+ /* if mclk does not satisfy the divider, use pll */
if (sgtl5000->master) {
clk_ctl |= SGTL5000_MCLK_FREQ_PLL <<
SGTL5000_MCLK_FREQ_SHIFT;
@@ -628,7 +641,7 @@ static int sgtl5000_set_clock(struct snd_soc_codec *codec, int frame_rate)
"PLL not supported in slave mode\n");
dev_err(codec->dev, "%d ratio is not supported. "
"SYS_MCLK needs to be 256, 384 or 512 * fs\n",
- sgtl5000->sysclk / sys_fs);
+ sgtl5000->sysclk / frame_rate);
return -EINVAL;
}
}
@@ -795,7 +808,7 @@ static int ldo_regulator_enable(struct regulator_dev *dev)
SGTL5000_LINEREG_D_POWERUP,
SGTL5000_LINEREG_D_POWERUP);
- /* when internal ldo enabled, simple digital power can be disabled */
+ /* when internal ldo is enabled, simple digital power can be disabled */
snd_soc_update_bits(codec, SGTL5000_CHIP_ANA_POWER,
SGTL5000_LINREG_SIMPLE_POWERUP,
0);
@@ -1079,7 +1092,7 @@ static bool sgtl5000_readable(struct device *dev, unsigned int reg)
/*
* sgtl5000 has 3 internal power supplies:
* 1. VAG, normally set to vdda/2
- * 2. chargepump, set to different value
+ * 2. charge pump, set to different value
* according to voltage of vdda and vddio
* 3. line out VAG, normally set to vddio/2
*
@@ -1325,8 +1338,13 @@ static int sgtl5000_probe(struct snd_soc_codec *codec)
SGTL5000_HP_ZCD_EN |
SGTL5000_ADC_ZCD_EN);
- snd_soc_write(codec, SGTL5000_CHIP_MIC_CTRL, 2);
+ snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+ SGTL5000_BIAS_R_MASK,
+ sgtl5000->micbias_resistor << SGTL5000_BIAS_R_SHIFT);
+ snd_soc_update_bits(codec, SGTL5000_CHIP_MIC_CTRL,
+ SGTL5000_BIAS_R_MASK,
+ sgtl5000->micbias_voltage << SGTL5000_BIAS_R_SHIFT);
/*
* disable DAP
* TODO:
@@ -1416,10 +1434,10 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
{
struct sgtl5000_priv *sgtl5000;
int ret, reg, rev;
- unsigned int mclk;
+ struct device_node *np = client->dev.of_node;
+ u32 value;
- sgtl5000 = devm_kzalloc(&client->dev, sizeof(struct sgtl5000_priv),
- GFP_KERNEL);
+ sgtl5000 = devm_kzalloc(&client->dev, sizeof(*sgtl5000), GFP_KERNEL);
if (!sgtl5000)
return -ENOMEM;
@@ -1440,14 +1458,6 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
return ret;
}
- /* SGTL5000 SYS_MCLK should be between 8 and 27 MHz */
- mclk = clk_get_rate(sgtl5000->mclk);
- if (mclk < 8000000 || mclk > 27000000) {
- dev_err(&client->dev, "Invalid SYS_CLK frequency: %u.%03uMHz\n",
- mclk / 1000000, mclk / 1000 % 1000);
- return -EINVAL;
- }
-
ret = clk_prepare_enable(sgtl5000->mclk);
if (ret)
return ret;
@@ -1469,6 +1479,47 @@ static int sgtl5000_i2c_probe(struct i2c_client *client,
dev_info(&client->dev, "sgtl5000 revision 0x%x\n", rev);
sgtl5000->revision = rev;
+ if (np) {
+ if (!of_property_read_u32(np,
+ "micbias-resistor-k-ohms", &value)) {
+ switch (value) {
+ case SGTL5000_MICBIAS_OFF:
+ sgtl5000->micbias_resistor = 0;
+ break;
+ case SGTL5000_MICBIAS_2K:
+ sgtl5000->micbias_resistor = 1;
+ break;
+ case SGTL5000_MICBIAS_4K:
+ sgtl5000->micbias_resistor = 2;
+ break;
+ case SGTL5000_MICBIAS_8K:
+ sgtl5000->micbias_resistor = 3;
+ break;
+ default:
+ sgtl5000->micbias_resistor = 2;
+ dev_err(&client->dev,
+ "Unsuitable MicBias resistor\n");
+ }
+ } else {
+ /* default is 4Kohms */
+ sgtl5000->micbias_resistor = 2;
+ }
+ if (!of_property_read_u32(np,
+ "micbias-voltage-m-volts", &value)) {
+ /* 1250mV => 0 */
+ /* steps of 250mV */
+ if ((value >= 1250) && (value <= 3000))
+ sgtl5000->micbias_voltage = (value / 250) - 5;
+ else {
+ sgtl5000->micbias_voltage = 0;
+ dev_err(&client->dev,
+ "Unsuitable MicBias resistor\n");
+ }
+ } else {
+ sgtl5000->micbias_voltage = 0;
+ }
+ }
+
i2c_set_clientdata(client, sgtl5000);
/* Ensure sgtl5000 will start with sane register values */
diff --git a/sound/soc/codecs/sigmadsp-i2c.c b/sound/soc/codecs/sigmadsp-i2c.c
index 246081a..21ca3a5 100644
--- a/sound/soc/codecs/sigmadsp-i2c.c
+++ b/sound/soc/codecs/sigmadsp-i2c.c
@@ -6,29 +6,88 @@
* Licensed under the GPL-2 or later.
*/
-#include <linux/i2c.h>
#include <linux/export.h>
+#include <linux/i2c.h>
#include <linux/module.h>
+#include <linux/slab.h>
+#include <asm/unaligned.h>
#include "sigmadsp.h"
-static int sigma_action_write_i2c(void *control_data,
- const struct sigma_action *sa, size_t len)
+static int sigmadsp_write_i2c(void *control_data,
+ unsigned int addr, const uint8_t data[], size_t len)
+{
+ uint8_t *buf;
+ int ret;
+
+ buf = kzalloc(2 + len, GFP_KERNEL | GFP_DMA);
+ if (!buf)
+ return -ENOMEM;
+
+ put_unaligned_be16(addr, buf);
+ memcpy(buf + 2, data, len);
+
+ ret = i2c_master_send(control_data, buf, len + 2);
+
+ kfree(buf);
+
+ return ret;
+}
+
+static int sigmadsp_read_i2c(void *control_data,
+ unsigned int addr, uint8_t data[], size_t len)
{
- return i2c_master_send(control_data, (const unsigned char *)&sa->addr,
- len);
+ struct i2c_client *client = control_data;
+ struct i2c_msg msgs[2];
+ uint8_t buf[2];
+ int ret;
+
+ put_unaligned_be16(addr, buf);
+
+ msgs[0].addr = client->addr;
+ msgs[0].len = sizeof(buf);
+ msgs[0].buf = buf;
+ msgs[0].flags = 0;
+
+ msgs[1].addr = client->addr;
+ msgs[1].len = len;
+ msgs[1].buf = data;
+ msgs[1].flags = I2C_M_RD;
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0)
+ return ret;
+ else if (ret != ARRAY_SIZE(msgs))
+ return -EIO;
+ return 0;
}
-int process_sigma_firmware(struct i2c_client *client, const char *name)
+/**
+ * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * @client: The parent I2C device
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
+ const struct sigmadsp_ops *ops, const char *firmware_name)
{
- struct sigma_firmware ssfw;
+ struct sigmadsp *sigmadsp;
+
+ sigmadsp = devm_sigmadsp_init(&client->dev, ops, firmware_name);
+ if (IS_ERR(sigmadsp))
+ return sigmadsp;
- ssfw.control_data = client;
- ssfw.write = sigma_action_write_i2c;
+ sigmadsp->control_data = client;
+ sigmadsp->write = sigmadsp_write_i2c;
+ sigmadsp->read = sigmadsp_read_i2c;
- return _process_sigma_firmware(&client->dev, &ssfw, name);
+ return sigmadsp;
}
-EXPORT_SYMBOL(process_sigma_firmware);
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init_i2c);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("SigmaDSP I2C firmware loader");
diff --git a/sound/soc/codecs/sigmadsp-regmap.c b/sound/soc/codecs/sigmadsp-regmap.c
index f78ed8d..912861b 100644
--- a/sound/soc/codecs/sigmadsp-regmap.c
+++ b/sound/soc/codecs/sigmadsp-regmap.c
@@ -12,24 +12,48 @@
#include "sigmadsp.h"
-static int sigma_action_write_regmap(void *control_data,
- const struct sigma_action *sa, size_t len)
+static int sigmadsp_write_regmap(void *control_data,
+ unsigned int addr, const uint8_t data[], size_t len)
{
- return regmap_raw_write(control_data, be16_to_cpu(sa->addr),
- sa->payload, len - 2);
+ return regmap_raw_write(control_data, addr,
+ data, len);
}
-int process_sigma_firmware_regmap(struct device *dev, struct regmap *regmap,
- const char *name)
+static int sigmadsp_read_regmap(void *control_data,
+ unsigned int addr, uint8_t data[], size_t len)
{
- struct sigma_firmware ssfw;
+ return regmap_raw_read(control_data, addr,
+ data, len);
+}
+
+/**
+ * devm_sigmadsp_init_i2c() - Initialize SigmaDSP instance
+ * @dev: The parent device
+ * @regmap: Regmap instance to use
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
+ struct regmap *regmap, const struct sigmadsp_ops *ops,
+ const char *firmware_name)
+{
+ struct sigmadsp *sigmadsp;
+
+ sigmadsp = devm_sigmadsp_init(dev, ops, firmware_name);
+ if (IS_ERR(sigmadsp))
+ return sigmadsp;
- ssfw.control_data = regmap;
- ssfw.write = sigma_action_write_regmap;
+ sigmadsp->control_data = regmap;
+ sigmadsp->write = sigmadsp_write_regmap;
+ sigmadsp->read = sigmadsp_read_regmap;
- return _process_sigma_firmware(dev, &ssfw, name);
+ return sigmadsp;
}
-EXPORT_SYMBOL(process_sigma_firmware_regmap);
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init_regmap);
MODULE_AUTHOR("Lars-Peter Clausen <lars@metafoo.de>");
MODULE_DESCRIPTION("SigmaDSP regmap firmware loader");
diff --git a/sound/soc/codecs/sigmadsp.c b/sound/soc/codecs/sigmadsp.c
index f2de7e0..d53680a 100644
--- a/sound/soc/codecs/sigmadsp.c
+++ b/sound/soc/codecs/sigmadsp.c
@@ -1,23 +1,74 @@
/*
* Load Analog Devices SigmaStudio firmware files
*
- * Copyright 2009-2011 Analog Devices Inc.
+ * Copyright 2009-2014 Analog Devices Inc.
*
* Licensed under the GPL-2 or later.
*/
#include <linux/crc32.h>
-#include <linux/delay.h>
#include <linux/firmware.h>
#include <linux/kernel.h>
#include <linux/i2c.h>
#include <linux/regmap.h>
#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <sound/control.h>
+#include <sound/soc.h>
#include "sigmadsp.h"
#define SIGMA_MAGIC "ADISIGM"
+#define SIGMA_FW_CHUNK_TYPE_DATA 0
+#define SIGMA_FW_CHUNK_TYPE_CONTROL 1
+#define SIGMA_FW_CHUNK_TYPE_SAMPLERATES 2
+
+struct sigmadsp_control {
+ struct list_head head;
+ uint32_t samplerates;
+ unsigned int addr;
+ unsigned int num_bytes;
+ const char *name;
+ struct snd_kcontrol *kcontrol;
+ bool cached;
+ uint8_t cache[];
+};
+
+struct sigmadsp_data {
+ struct list_head head;
+ uint32_t samplerates;
+ unsigned int addr;
+ unsigned int length;
+ uint8_t data[];
+};
+
+struct sigma_fw_chunk {
+ __le32 length;
+ __le32 tag;
+ __le32 samplerates;
+} __packed;
+
+struct sigma_fw_chunk_data {
+ struct sigma_fw_chunk chunk;
+ __le16 addr;
+ uint8_t data[];
+} __packed;
+
+struct sigma_fw_chunk_control {
+ struct sigma_fw_chunk chunk;
+ __le16 type;
+ __le16 addr;
+ __le16 num_bytes;
+ const char name[];
+} __packed;
+
+struct sigma_fw_chunk_samplerate {
+ struct sigma_fw_chunk chunk;
+ __le32 samplerates[];
+} __packed;
+
struct sigma_firmware_header {
unsigned char magic[7];
u8 version;
@@ -28,12 +79,286 @@ enum {
SIGMA_ACTION_WRITEXBYTES = 0,
SIGMA_ACTION_WRITESINGLE,
SIGMA_ACTION_WRITESAFELOAD,
- SIGMA_ACTION_DELAY,
- SIGMA_ACTION_PLLWAIT,
- SIGMA_ACTION_NOOP,
SIGMA_ACTION_END,
};
+struct sigma_action {
+ u8 instr;
+ u8 len_hi;
+ __le16 len;
+ __be16 addr;
+ unsigned char payload[];
+} __packed;
+
+static int sigmadsp_write(struct sigmadsp *sigmadsp, unsigned int addr,
+ const uint8_t data[], size_t len)
+{
+ return sigmadsp->write(sigmadsp->control_data, addr, data, len);
+}
+
+static int sigmadsp_read(struct sigmadsp *sigmadsp, unsigned int addr,
+ uint8_t data[], size_t len)
+{
+ return sigmadsp->read(sigmadsp->control_data, addr, data, len);
+}
+
+static int sigmadsp_ctrl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *info)
+{
+ struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+
+ info->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ info->count = ctrl->num_bytes;
+
+ return 0;
+}
+
+static int sigmadsp_ctrl_write(struct sigmadsp *sigmadsp,
+ struct sigmadsp_control *ctrl, void *data)
+{
+ /* safeload loads up to 20 bytes in a atomic operation */
+ if (ctrl->num_bytes > 4 && ctrl->num_bytes <= 20 && sigmadsp->ops &&
+ sigmadsp->ops->safeload)
+ return sigmadsp->ops->safeload(sigmadsp, ctrl->addr, data,
+ ctrl->num_bytes);
+ else
+ return sigmadsp_write(sigmadsp, ctrl->addr, data,
+ ctrl->num_bytes);
+}
+
+static int sigmadsp_ctrl_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+ struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
+ uint8_t *data;
+ int ret = 0;
+
+ mutex_lock(&sigmadsp->lock);
+
+ data = ucontrol->value.bytes.data;
+
+ if (!(kcontrol->vd[0].access & SNDRV_CTL_ELEM_ACCESS_INACTIVE))
+ ret = sigmadsp_ctrl_write(sigmadsp, ctrl, data);
+
+ if (ret == 0) {
+ memcpy(ctrl->cache, data, ctrl->num_bytes);
+ ctrl->cached = true;
+ }
+
+ mutex_unlock(&sigmadsp->lock);
+
+ return ret;
+}
+
+static int sigmadsp_ctrl_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+ struct sigmadsp *sigmadsp = snd_kcontrol_chip(kcontrol);
+ int ret = 0;
+
+ mutex_lock(&sigmadsp->lock);
+
+ if (!ctrl->cached) {
+ ret = sigmadsp_read(sigmadsp, ctrl->addr, ctrl->cache,
+ ctrl->num_bytes);
+ }
+
+ if (ret == 0) {
+ ctrl->cached = true;
+ memcpy(ucontrol->value.bytes.data, ctrl->cache,
+ ctrl->num_bytes);
+ }
+
+ mutex_unlock(&sigmadsp->lock);
+
+ return ret;
+}
+
+static void sigmadsp_control_free(struct snd_kcontrol *kcontrol)
+{
+ struct sigmadsp_control *ctrl = (void *)kcontrol->private_value;
+
+ ctrl->kcontrol = NULL;
+}
+
+static bool sigma_fw_validate_control_name(const char *name, unsigned int len)
+{
+ unsigned int i;
+
+ for (i = 0; i < len; i++) {
+ /* Normal ASCII characters are valid */
+ if (name[i] < ' ' || name[i] > '~')
+ return false;
+ }
+
+ return true;
+}
+
+static int sigma_fw_load_control(struct sigmadsp *sigmadsp,
+ const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+ const struct sigma_fw_chunk_control *ctrl_chunk;
+ struct sigmadsp_control *ctrl;
+ unsigned int num_bytes;
+ size_t name_len;
+ char *name;
+ int ret;
+
+ if (length <= sizeof(*ctrl_chunk))
+ return -EINVAL;
+
+ ctrl_chunk = (const struct sigma_fw_chunk_control *)chunk;
+
+ name_len = length - sizeof(*ctrl_chunk);
+ if (name_len >= SNDRV_CTL_ELEM_ID_NAME_MAXLEN)
+ name_len = SNDRV_CTL_ELEM_ID_NAME_MAXLEN - 1;
+
+ /* Make sure there are no non-displayable characaters in the string */
+ if (!sigma_fw_validate_control_name(ctrl_chunk->name, name_len))
+ return -EINVAL;
+
+ num_bytes = le16_to_cpu(ctrl_chunk->num_bytes);
+ ctrl = kzalloc(sizeof(*ctrl) + num_bytes, GFP_KERNEL);
+ if (!ctrl)
+ return -ENOMEM;
+
+ name = kzalloc(name_len + 1, GFP_KERNEL);
+ if (!name) {
+ ret = -ENOMEM;
+ goto err_free_ctrl;
+ }
+ memcpy(name, ctrl_chunk->name, name_len);
+ name[name_len] = '\0';
+ ctrl->name = name;
+
+ ctrl->addr = le16_to_cpu(ctrl_chunk->addr);
+ ctrl->num_bytes = num_bytes;
+ ctrl->samplerates = le32_to_cpu(chunk->samplerates);
+
+ list_add_tail(&ctrl->head, &sigmadsp->ctrl_list);
+
+ return 0;
+
+err_free_ctrl:
+ kfree(ctrl);
+
+ return ret;
+}
+
+static int sigma_fw_load_data(struct sigmadsp *sigmadsp,
+ const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+ const struct sigma_fw_chunk_data *data_chunk;
+ struct sigmadsp_data *data;
+
+ if (length <= sizeof(*data_chunk))
+ return -EINVAL;
+
+ data_chunk = (struct sigma_fw_chunk_data *)chunk;
+
+ length -= sizeof(*data_chunk);
+
+ data = kzalloc(sizeof(*data) + length, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->addr = le16_to_cpu(data_chunk->addr);
+ data->length = length;
+ data->samplerates = le32_to_cpu(chunk->samplerates);
+ memcpy(data->data, data_chunk->data, length);
+ list_add_tail(&data->head, &sigmadsp->data_list);
+
+ return 0;
+}
+
+static int sigma_fw_load_samplerates(struct sigmadsp *sigmadsp,
+ const struct sigma_fw_chunk *chunk, unsigned int length)
+{
+ const struct sigma_fw_chunk_samplerate *rate_chunk;
+ unsigned int num_rates;
+ unsigned int *rates;
+ unsigned int i;
+
+ rate_chunk = (const struct sigma_fw_chunk_samplerate *)chunk;
+
+ num_rates = (length - sizeof(*rate_chunk)) / sizeof(__le32);
+
+ if (num_rates > 32 || num_rates == 0)
+ return -EINVAL;
+
+ /* We only allow one samplerates block per file */
+ if (sigmadsp->rate_constraints.count)
+ return -EINVAL;
+
+ rates = kcalloc(num_rates, sizeof(*rates), GFP_KERNEL);
+ if (!rates)
+ return -ENOMEM;
+
+ for (i = 0; i < num_rates; i++)
+ rates[i] = le32_to_cpu(rate_chunk->samplerates[i]);
+
+ sigmadsp->rate_constraints.count = num_rates;
+ sigmadsp->rate_constraints.list = rates;
+
+ return 0;
+}
+
+static int sigmadsp_fw_load_v2(struct sigmadsp *sigmadsp,
+ const struct firmware *fw)
+{
+ struct sigma_fw_chunk *chunk;
+ unsigned int length, pos;
+ int ret;
+
+ /*
+ * Make sure that there is at least one chunk to avoid integer
+ * underflows later on. Empty firmware is still valid though.
+ */
+ if (fw->size < sizeof(*chunk) + sizeof(struct sigma_firmware_header))
+ return 0;
+
+ pos = sizeof(struct sigma_firmware_header);
+
+ while (pos < fw->size - sizeof(*chunk)) {
+ chunk = (struct sigma_fw_chunk *)(fw->data + pos);
+
+ length = le32_to_cpu(chunk->length);
+
+ if (length > fw->size - pos || length < sizeof(*chunk))
+ return -EINVAL;
+
+ switch (le32_to_cpu(chunk->tag)) {
+ case SIGMA_FW_CHUNK_TYPE_DATA:
+ ret = sigma_fw_load_data(sigmadsp, chunk, length);
+ break;
+ case SIGMA_FW_CHUNK_TYPE_CONTROL:
+ ret = sigma_fw_load_control(sigmadsp, chunk, length);
+ break;
+ case SIGMA_FW_CHUNK_TYPE_SAMPLERATES:
+ ret = sigma_fw_load_samplerates(sigmadsp, chunk, length);
+ break;
+ default:
+ dev_warn(sigmadsp->dev, "Unknown chunk type: %d\n",
+ chunk->tag);
+ ret = 0;
+ break;
+ }
+
+ if (ret)
+ return ret;
+
+ /*
+ * This can not overflow since if length is larger than the
+ * maximum firmware size (0x4000000) we'll error out earilier.
+ */
+ pos += ALIGN(length, sizeof(__le32));
+ }
+
+ return 0;
+}
+
static inline u32 sigma_action_len(struct sigma_action *sa)
{
return (sa->len_hi << 16) | le16_to_cpu(sa->len);
@@ -62,11 +387,11 @@ static size_t sigma_action_size(struct sigma_action *sa)
* Returns a negative error value in case of an error, 0 if processing of
* the firmware should be stopped after this action, 1 otherwise.
*/
-static int
-process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
+static int process_sigma_action(struct sigmadsp *sigmadsp,
+ struct sigma_action *sa)
{
size_t len = sigma_action_len(sa);
- int ret;
+ struct sigmadsp_data *data;
pr_debug("%s: instr:%i addr:%#x len:%zu\n", __func__,
sa->instr, sa->addr, len);
@@ -75,13 +400,17 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
case SIGMA_ACTION_WRITEXBYTES:
case SIGMA_ACTION_WRITESINGLE:
case SIGMA_ACTION_WRITESAFELOAD:
- ret = ssfw->write(ssfw->control_data, sa, len);
- if (ret < 0)
+ if (len < 3)
return -EINVAL;
- break;
- case SIGMA_ACTION_DELAY:
- udelay(len);
- len = 0;
+
+ data = kzalloc(sizeof(*data) + len - 2, GFP_KERNEL);
+ if (!data)
+ return -ENOMEM;
+
+ data->addr = be16_to_cpu(sa->addr);
+ data->length = len - 2;
+ memcpy(data->data, sa->payload, data->length);
+ list_add_tail(&data->head, &sigmadsp->data_list);
break;
case SIGMA_ACTION_END:
return 0;
@@ -92,22 +421,24 @@ process_sigma_action(struct sigma_firmware *ssfw, struct sigma_action *sa)
return 1;
}
-static int
-process_sigma_actions(struct sigma_firmware *ssfw)
+static int sigmadsp_fw_load_v1(struct sigmadsp *sigmadsp,
+ const struct firmware *fw)
{
struct sigma_action *sa;
- size_t size;
+ size_t size, pos;
int ret;
- while (ssfw->pos + sizeof(*sa) <= ssfw->fw->size) {
- sa = (struct sigma_action *)(ssfw->fw->data + ssfw->pos);
+ pos = sizeof(struct sigma_firmware_header);
+
+ while (pos + sizeof(*sa) <= fw->size) {
+ sa = (struct sigma_action *)(fw->data + pos);
size = sigma_action_size(sa);
- ssfw->pos += size;
- if (ssfw->pos > ssfw->fw->size || size == 0)
+ pos += size;
+ if (pos > fw->size || size == 0)
break;
- ret = process_sigma_action(ssfw, sa);
+ ret = process_sigma_action(sigmadsp, sa);
pr_debug("%s: action returned %i\n", __func__, ret);
@@ -115,29 +446,47 @@ process_sigma_actions(struct sigma_firmware *ssfw)
return ret;
}
- if (ssfw->pos != ssfw->fw->size)
+ if (pos != fw->size)
return -EINVAL;
return 0;
}
-int _process_sigma_firmware(struct device *dev,
- struct sigma_firmware *ssfw, const char *name)
+static void sigmadsp_firmware_release(struct sigmadsp *sigmadsp)
{
- int ret;
- struct sigma_firmware_header *ssfw_head;
+ struct sigmadsp_control *ctrl, *_ctrl;
+ struct sigmadsp_data *data, *_data;
+
+ list_for_each_entry_safe(ctrl, _ctrl, &sigmadsp->ctrl_list, head) {
+ kfree(ctrl->name);
+ kfree(ctrl);
+ }
+
+ list_for_each_entry_safe(data, _data, &sigmadsp->data_list, head)
+ kfree(data);
+
+ INIT_LIST_HEAD(&sigmadsp->ctrl_list);
+ INIT_LIST_HEAD(&sigmadsp->data_list);
+}
+
+static void devm_sigmadsp_release(struct device *dev, void *res)
+{
+ sigmadsp_firmware_release((struct sigmadsp *)res);
+}
+
+static int sigmadsp_firmware_load(struct sigmadsp *sigmadsp, const char *name)
+{
+ const struct sigma_firmware_header *ssfw_head;
const struct firmware *fw;
+ int ret;
u32 crc;
- pr_debug("%s: loading firmware %s\n", __func__, name);
-
/* first load the blob */
- ret = request_firmware(&fw, name, dev);
+ ret = request_firmware(&fw, name, sigmadsp->dev);
if (ret) {
pr_debug("%s: request_firmware() failed with %i\n", __func__, ret);
- return ret;
+ goto done;
}
- ssfw->fw = fw;
/* then verify the header */
ret = -EINVAL;
@@ -149,13 +498,13 @@ int _process_sigma_firmware(struct device *dev,
* overflows later in the loading process.
*/
if (fw->size < sizeof(*ssfw_head) || fw->size >= 0x4000000) {
- dev_err(dev, "Failed to load firmware: Invalid size\n");
+ dev_err(sigmadsp->dev, "Failed to load firmware: Invalid size\n");
goto done;
}
ssfw_head = (void *)fw->data;
if (memcmp(ssfw_head->magic, SIGMA_MAGIC, ARRAY_SIZE(ssfw_head->magic))) {
- dev_err(dev, "Failed to load firmware: Invalid magic\n");
+ dev_err(sigmadsp->dev, "Failed to load firmware: Invalid magic\n");
goto done;
}
@@ -163,23 +512,303 @@ int _process_sigma_firmware(struct device *dev,
fw->size - sizeof(*ssfw_head));
pr_debug("%s: crc=%x\n", __func__, crc);
if (crc != le32_to_cpu(ssfw_head->crc)) {
- dev_err(dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
+ dev_err(sigmadsp->dev, "Failed to load firmware: Wrong crc checksum: expected %x got %x\n",
le32_to_cpu(ssfw_head->crc), crc);
goto done;
}
- ssfw->pos = sizeof(*ssfw_head);
+ switch (ssfw_head->version) {
+ case 1:
+ ret = sigmadsp_fw_load_v1(sigmadsp, fw);
+ break;
+ case 2:
+ ret = sigmadsp_fw_load_v2(sigmadsp, fw);
+ break;
+ default:
+ dev_err(sigmadsp->dev,
+ "Failed to load firmware: Invalid version %d. Supported firmware versions: 1, 2\n",
+ ssfw_head->version);
+ ret = -EINVAL;
+ break;
+ }
- /* finally process all of the actions */
- ret = process_sigma_actions(ssfw);
+ if (ret)
+ sigmadsp_firmware_release(sigmadsp);
- done:
+done:
release_firmware(fw);
- pr_debug("%s: loaded %s\n", __func__, name);
+ return ret;
+}
+
+static int sigmadsp_init(struct sigmadsp *sigmadsp, struct device *dev,
+ const struct sigmadsp_ops *ops, const char *firmware_name)
+{
+ sigmadsp->ops = ops;
+ sigmadsp->dev = dev;
+
+ INIT_LIST_HEAD(&sigmadsp->ctrl_list);
+ INIT_LIST_HEAD(&sigmadsp->data_list);
+ mutex_init(&sigmadsp->lock);
+
+ return sigmadsp_firmware_load(sigmadsp, firmware_name);
+}
+
+/**
+ * devm_sigmadsp_init() - Initialize SigmaDSP instance
+ * @dev: The parent device
+ * @ops: The sigmadsp_ops to use for this instance
+ * @firmware_name: Name of the firmware file to load
+ *
+ * Allocates a SigmaDSP instance and loads the specified firmware file.
+ *
+ * Returns a pointer to a struct sigmadsp on success, or a PTR_ERR() on error.
+ */
+struct sigmadsp *devm_sigmadsp_init(struct device *dev,
+ const struct sigmadsp_ops *ops, const char *firmware_name)
+{
+ struct sigmadsp *sigmadsp;
+ int ret;
+
+ sigmadsp = devres_alloc(devm_sigmadsp_release, sizeof(*sigmadsp),
+ GFP_KERNEL);
+ if (!sigmadsp)
+ return ERR_PTR(-ENOMEM);
+
+ ret = sigmadsp_init(sigmadsp, dev, ops, firmware_name);
+ if (ret) {
+ devres_free(sigmadsp);
+ return ERR_PTR(ret);
+ }
+
+ devres_add(dev, sigmadsp);
+
+ return sigmadsp;
+}
+EXPORT_SYMBOL_GPL(devm_sigmadsp_init);
+
+static int sigmadsp_rate_to_index(struct sigmadsp *sigmadsp, unsigned int rate)
+{
+ unsigned int i;
+
+ for (i = 0; i < sigmadsp->rate_constraints.count; i++) {
+ if (sigmadsp->rate_constraints.list[i] == rate)
+ return i;
+ }
+
+ return -EINVAL;
+}
+
+static unsigned int sigmadsp_get_samplerate_mask(struct sigmadsp *sigmadsp,
+ unsigned int samplerate)
+{
+ int samplerate_index;
+
+ if (samplerate == 0)
+ return 0;
+
+ if (sigmadsp->rate_constraints.count) {
+ samplerate_index = sigmadsp_rate_to_index(sigmadsp, samplerate);
+ if (samplerate_index < 0)
+ return 0;
+
+ return BIT(samplerate_index);
+ } else {
+ return ~0;
+ }
+}
+
+static bool sigmadsp_samplerate_valid(unsigned int supported,
+ unsigned int requested)
+{
+ /* All samplerates are supported */
+ if (!supported)
+ return true;
+
+ return supported & requested;
+}
+
+static int sigmadsp_alloc_control(struct sigmadsp *sigmadsp,
+ struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
+{
+ struct snd_kcontrol_new template;
+ struct snd_kcontrol *kcontrol;
+
+ memset(&template, 0, sizeof(template));
+ template.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
+ template.name = ctrl->name;
+ template.info = sigmadsp_ctrl_info;
+ template.get = sigmadsp_ctrl_get;
+ template.put = sigmadsp_ctrl_put;
+ template.private_value = (unsigned long)ctrl;
+ template.access = SNDRV_CTL_ELEM_ACCESS_READWRITE;
+ if (!sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask))
+ template.access |= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+
+ kcontrol = snd_ctl_new1(&template, sigmadsp);
+ if (!kcontrol)
+ return -ENOMEM;
+
+ kcontrol->private_free = sigmadsp_control_free;
+ ctrl->kcontrol = kcontrol;
+
+ return snd_ctl_add(sigmadsp->component->card->snd_card, kcontrol);
+}
+
+static void sigmadsp_activate_ctrl(struct sigmadsp *sigmadsp,
+ struct sigmadsp_control *ctrl, unsigned int samplerate_mask)
+{
+ struct snd_card *card = sigmadsp->component->card->snd_card;
+ struct snd_kcontrol_volatile *vd;
+ struct snd_ctl_elem_id id;
+ bool active;
+ bool changed = false;
+
+ active = sigmadsp_samplerate_valid(ctrl->samplerates, samplerate_mask);
+
+ down_write(&card->controls_rwsem);
+ if (!ctrl->kcontrol) {
+ up_write(&card->controls_rwsem);
+ return;
+ }
+
+ id = ctrl->kcontrol->id;
+ vd = &ctrl->kcontrol->vd[0];
+ if (active == (bool)(vd->access & SNDRV_CTL_ELEM_ACCESS_INACTIVE)) {
+ vd->access ^= SNDRV_CTL_ELEM_ACCESS_INACTIVE;
+ changed = true;
+ }
+ up_write(&card->controls_rwsem);
+
+ if (active && changed) {
+ mutex_lock(&sigmadsp->lock);
+ if (ctrl->cached)
+ sigmadsp_ctrl_write(sigmadsp, ctrl, ctrl->cache);
+ mutex_unlock(&sigmadsp->lock);
+ }
+
+ if (changed)
+ snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_INFO, &id);
+}
+
+/**
+ * sigmadsp_attach() - Attach a sigmadsp instance to a ASoC component
+ * @sigmadsp: The sigmadsp instance to attach
+ * @component: The component to attach to
+ *
+ * Typically called in the components probe callback.
+ *
+ * Note, once this function has been called the firmware must not be released
+ * until after the ALSA snd_card that the component belongs to has been
+ * disconnected, even if sigmadsp_attach() returns an error.
+ */
+int sigmadsp_attach(struct sigmadsp *sigmadsp,
+ struct snd_soc_component *component)
+{
+ struct sigmadsp_control *ctrl;
+ unsigned int samplerate_mask;
+ int ret;
+
+ sigmadsp->component = component;
+
+ samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp,
+ sigmadsp->current_samplerate);
+
+ list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head) {
+ ret = sigmadsp_alloc_control(sigmadsp, ctrl, samplerate_mask);
+ if (ret)
+ return ret;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_attach);
+
+/**
+ * sigmadsp_setup() - Setup the DSP for the specified samplerate
+ * @sigmadsp: The sigmadsp instance to configure
+ * @samplerate: The samplerate the DSP should be configured for
+ *
+ * Loads the appropriate firmware program and parameter memory (if not already
+ * loaded) and enables the controls for the specified samplerate. Any control
+ * parameter changes that have been made previously will be restored.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int samplerate)
+{
+ struct sigmadsp_control *ctrl;
+ unsigned int samplerate_mask;
+ struct sigmadsp_data *data;
+ int ret;
+
+ if (sigmadsp->current_samplerate == samplerate)
+ return 0;
+
+ samplerate_mask = sigmadsp_get_samplerate_mask(sigmadsp, samplerate);
+ if (samplerate_mask == 0)
+ return -EINVAL;
+
+ list_for_each_entry(data, &sigmadsp->data_list, head) {
+ if (!sigmadsp_samplerate_valid(data->samplerates,
+ samplerate_mask))
+ continue;
+ ret = sigmadsp_write(sigmadsp, data->addr, data->data,
+ data->length);
+ if (ret)
+ goto err;
+ }
+
+ list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
+ sigmadsp_activate_ctrl(sigmadsp, ctrl, samplerate_mask);
+
+ sigmadsp->current_samplerate = samplerate;
+
+ return 0;
+err:
+ sigmadsp_reset(sigmadsp);
return ret;
}
-EXPORT_SYMBOL_GPL(_process_sigma_firmware);
+EXPORT_SYMBOL_GPL(sigmadsp_setup);
+
+/**
+ * sigmadsp_reset() - Notify the sigmadsp instance that the DSP has been reset
+ * @sigmadsp: The sigmadsp instance to reset
+ *
+ * Should be called whenever the DSP has been reset and parameter and program
+ * memory need to be re-loaded.
+ */
+void sigmadsp_reset(struct sigmadsp *sigmadsp)
+{
+ struct sigmadsp_control *ctrl;
+
+ list_for_each_entry(ctrl, &sigmadsp->ctrl_list, head)
+ sigmadsp_activate_ctrl(sigmadsp, ctrl, false);
+
+ sigmadsp->current_samplerate = 0;
+}
+EXPORT_SYMBOL_GPL(sigmadsp_reset);
+
+/**
+ * sigmadsp_restrict_params() - Applies DSP firmware specific constraints
+ * @sigmadsp: The sigmadsp instance
+ * @substream: The substream to restrict
+ *
+ * Applies samplerate constraints that may be required by the firmware Should
+ * typically be called from the CODEC/component drivers startup callback.
+ *
+ * Returns 0 on success, a negative error code otherwise.
+ */
+int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
+ struct snd_pcm_substream *substream)
+{
+ if (sigmadsp->rate_constraints.count == 0)
+ return 0;
+
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE, &sigmadsp->rate_constraints);
+}
+EXPORT_SYMBOL_GPL(sigmadsp_restrict_params);
MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/sigmadsp.h b/sound/soc/codecs/sigmadsp.h
index c47cd23..614475c 100644
--- a/sound/soc/codecs/sigmadsp.h
+++ b/sound/soc/codecs/sigmadsp.h
@@ -11,31 +11,56 @@
#include <linux/device.h>
#include <linux/regmap.h>
+#include <linux/list.h>
-struct sigma_action {
- u8 instr;
- u8 len_hi;
- __le16 len;
- __be16 addr;
- unsigned char payload[];
-} __packed;
+#include <sound/pcm.h>
-struct sigma_firmware {
- const struct firmware *fw;
- size_t pos;
+struct sigmadsp;
+struct snd_soc_component;
+struct snd_pcm_substream;
+
+struct sigmadsp_ops {
+ int (*safeload)(struct sigmadsp *sigmadsp, unsigned int addr,
+ const uint8_t *data, size_t len);
+};
+
+struct sigmadsp {
+ const struct sigmadsp_ops *ops;
+
+ struct list_head ctrl_list;
+ struct list_head data_list;
+
+ struct snd_pcm_hw_constraint_list rate_constraints;
+
+ unsigned int current_samplerate;
+ struct snd_soc_component *component;
+ struct device *dev;
+
+ struct mutex lock;
void *control_data;
- int (*write)(void *control_data, const struct sigma_action *sa,
- size_t len);
+ int (*write)(void *, unsigned int, const uint8_t *, size_t);
+ int (*read)(void *, unsigned int, uint8_t *, size_t);
};
-int _process_sigma_firmware(struct device *dev,
- struct sigma_firmware *ssfw, const char *name);
+struct sigmadsp *devm_sigmadsp_init(struct device *dev,
+ const struct sigmadsp_ops *ops, const char *firmware_name);
+void sigmadsp_reset(struct sigmadsp *sigmadsp);
+
+int sigmadsp_restrict_params(struct sigmadsp *sigmadsp,
+ struct snd_pcm_substream *substream);
struct i2c_client;
-extern int process_sigma_firmware(struct i2c_client *client, const char *name);
-extern int process_sigma_firmware_regmap(struct device *dev,
- struct regmap *regmap, const char *name);
+struct sigmadsp *devm_sigmadsp_init_regmap(struct device *dev,
+ struct regmap *regmap, const struct sigmadsp_ops *ops,
+ const char *firmware_name);
+struct sigmadsp *devm_sigmadsp_init_i2c(struct i2c_client *client,
+ const struct sigmadsp_ops *ops, const char *firmware_name);
+
+int sigmadsp_attach(struct sigmadsp *sigmadsp,
+ struct snd_soc_component *component);
+int sigmadsp_setup(struct sigmadsp *sigmadsp, unsigned int rate);
+void sigmadsp_reset(struct sigmadsp *sigmadsp);
#endif
diff --git a/sound/soc/codecs/sirf-audio-codec.c b/sound/soc/codecs/sirf-audio-codec.c
index 06ba492..07eea20 100644
--- a/sound/soc/codecs/sirf-audio-codec.c
+++ b/sound/soc/codecs/sirf-audio-codec.c
@@ -120,7 +120,8 @@ static int atlas6_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
{
#define ATLAS6_CODEC_ENABLE_BITS (1 << 29)
#define ATLAS6_CODEC_RESET_BITS (1 << 28)
- struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_PRE_PMU:
enable_and_reset_codec(sirf_audio_codec->regmap,
@@ -142,7 +143,8 @@ static int prima2_codec_enable_and_reset_event(struct snd_soc_dapm_widget *w,
{
#define PRIMA2_CODEC_ENABLE_BITS (1 << 27)
#define PRIMA2_CODEC_RESET_BITS (1 << 26)
- struct sirf_audio_codec *sirf_audio_codec = dev_get_drvdata(w->codec->dev);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(w->dapm);
+ struct sirf_audio_codec *sirf_audio_codec = snd_soc_codec_get_drvdata(codec);
switch (event) {
case SND_SOC_DAPM_POST_PMU:
enable_and_reset_codec(sirf_audio_codec->regmap,
diff --git a/sound/soc/codecs/sn95031.c b/sound/soc/codecs/sn95031.c
index cf8fa40..31d97cd 100644
--- a/sound/soc/codecs/sn95031.c
+++ b/sound/soc/codecs/sn95031.c
@@ -867,25 +867,16 @@ static int sn95031_codec_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, SN95031_SSR2, 0x10);
snd_soc_write(codec, SN95031_SSR3, 0x40);
- snd_soc_add_codec_controls(codec, sn95031_snd_controls,
- ARRAY_SIZE(sn95031_snd_controls));
-
- return 0;
-}
-
-static int sn95031_codec_remove(struct snd_soc_codec *codec)
-{
- pr_debug("codec_remove called\n");
- sn95031_set_vaud_bias(codec, SND_SOC_BIAS_OFF);
-
return 0;
}
static struct snd_soc_codec_driver sn95031_codec = {
.probe = sn95031_codec_probe,
- .remove = sn95031_codec_remove,
.set_bias_level = sn95031_set_vaud_bias,
.idle_bias_off = true,
+
+ .controls = sn95031_snd_controls,
+ .num_controls = ARRAY_SIZE(sn95031_snd_controls),
.dapm_widgets = sn95031_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(sn95031_dapm_widgets),
.dapm_routes = sn95031_audio_map,
diff --git a/sound/soc/codecs/ssm4567.c b/sound/soc/codecs/ssm4567.c
index 4b5c17f..a984485 100644
--- a/sound/soc/codecs/ssm4567.c
+++ b/sound/soc/codecs/ssm4567.c
@@ -69,6 +69,22 @@
#define SSM4567_DAC_FS_64000_96000 0x3
#define SSM4567_DAC_FS_128000_192000 0x4
+/* SAI_CTRL_1 */
+#define SSM4567_SAI_CTRL_1_BCLK BIT(6)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK (0x3 << 4)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_32 (0x0 << 4)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_48 (0x1 << 4)
+#define SSM4567_SAI_CTRL_1_TDM_BLCKS_64 (0x2 << 4)
+#define SSM4567_SAI_CTRL_1_FSYNC BIT(3)
+#define SSM4567_SAI_CTRL_1_LJ BIT(2)
+#define SSM4567_SAI_CTRL_1_TDM BIT(1)
+#define SSM4567_SAI_CTRL_1_PDM BIT(0)
+
+/* SAI_CTRL_2 */
+#define SSM4567_SAI_CTRL_2_AUTO_SLOT BIT(3)
+#define SSM4567_SAI_CTRL_2_TDM_SLOT_MASK 0x7
+#define SSM4567_SAI_CTRL_2_TDM_SLOT(x) (x)
+
struct ssm4567 {
struct regmap *regmap;
};
@@ -145,15 +161,24 @@ static const struct snd_kcontrol_new ssm4567_snd_controls[] = {
SOC_SINGLE_TLV("Master Playback Volume", SSM4567_REG_DAC_VOLUME, 0,
0xff, 1, ssm4567_vol_tlv),
SOC_SINGLE("DAC Low Power Mode Switch", SSM4567_REG_DAC_CTRL, 4, 1, 0),
+ SOC_SINGLE("DAC High Pass Filter Switch", SSM4567_REG_DAC_CTRL,
+ 5, 1, 0),
};
+static const struct snd_kcontrol_new ssm4567_amplifier_boost_control =
+ SOC_DAPM_SINGLE("Switch", SSM4567_REG_POWER_CTRL, 1, 1, 1);
+
static const struct snd_soc_dapm_widget ssm4567_dapm_widgets[] = {
SND_SOC_DAPM_DAC("DAC", "HiFi Playback", SSM4567_REG_POWER_CTRL, 2, 1),
+ SND_SOC_DAPM_SWITCH("Amplifier Boost", SSM4567_REG_POWER_CTRL, 3, 1,
+ &ssm4567_amplifier_boost_control),
SND_SOC_DAPM_OUTPUT("OUT"),
};
static const struct snd_soc_dapm_route ssm4567_routes[] = {
+ { "OUT", NULL, "Amplifier Boost" },
+ { "Amplifier Boost", "Switch", "DAC" },
{ "OUT", NULL, "DAC" },
};
@@ -192,6 +217,107 @@ static int ssm4567_mute(struct snd_soc_dai *dai, int mute)
SSM4567_DAC_MUTE, val);
}
+static int ssm4567_set_tdm_slot(struct snd_soc_dai *dai, unsigned int tx_mask,
+ unsigned int rx_mask, int slots, int width)
+{
+ struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
+ unsigned int blcks;
+ int slot;
+ int ret;
+
+ if (tx_mask == 0)
+ return -EINVAL;
+
+ if (rx_mask && rx_mask != tx_mask)
+ return -EINVAL;
+
+ slot = __ffs(tx_mask);
+ if (tx_mask != BIT(slot))
+ return -EINVAL;
+
+ switch (width) {
+ case 32:
+ blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_32;
+ break;
+ case 48:
+ blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_48;
+ break;
+ case 64:
+ blcks = SSM4567_SAI_CTRL_1_TDM_BLCKS_64;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_2,
+ SSM4567_SAI_CTRL_2_AUTO_SLOT | SSM4567_SAI_CTRL_2_TDM_SLOT_MASK,
+ SSM4567_SAI_CTRL_2_TDM_SLOT(slot));
+ if (ret)
+ return ret;
+
+ return regmap_update_bits(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1,
+ SSM4567_SAI_CTRL_1_TDM_BLCKS_MASK, blcks);
+}
+
+static int ssm4567_set_dai_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct ssm4567 *ssm4567 = snd_soc_dai_get_drvdata(dai);
+ unsigned int ctrl1 = 0;
+ bool invert_fclk;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ invert_fclk = false;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
+ invert_fclk = false;
+ break;
+ case SND_SOC_DAIFMT_NB_IF:
+ ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
+ invert_fclk = true;
+ break;
+ case SND_SOC_DAIFMT_IB_IF:
+ ctrl1 |= SSM4567_SAI_CTRL_1_BCLK;
+ invert_fclk = true;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ ctrl1 |= SSM4567_SAI_CTRL_1_LJ;
+ invert_fclk = !invert_fclk;
+ break;
+ case SND_SOC_DAIFMT_DSP_A:
+ ctrl1 |= SSM4567_SAI_CTRL_1_TDM;
+ break;
+ case SND_SOC_DAIFMT_DSP_B:
+ ctrl1 |= SSM4567_SAI_CTRL_1_TDM | SSM4567_SAI_CTRL_1_LJ;
+ break;
+ case SND_SOC_DAIFMT_PDM:
+ ctrl1 |= SSM4567_SAI_CTRL_1_PDM;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (invert_fclk)
+ ctrl1 |= SSM4567_SAI_CTRL_1_FSYNC;
+
+ return regmap_write(ssm4567->regmap, SSM4567_REG_SAI_CTRL_1, ctrl1);
+}
+
static int ssm4567_set_power(struct ssm4567 *ssm4567, bool enable)
{
int ret = 0;
@@ -246,6 +372,8 @@ static int ssm4567_set_bias_level(struct snd_soc_codec *codec,
static const struct snd_soc_dai_ops ssm4567_dai_ops = {
.hw_params = ssm4567_hw_params,
.digital_mute = ssm4567_mute,
+ .set_fmt = ssm4567_set_dai_fmt,
+ .set_tdm_slot = ssm4567_set_tdm_slot,
};
static struct snd_soc_dai_driver ssm4567_dai = {
diff --git a/sound/soc/codecs/sta32x.c b/sound/soc/codecs/sta32x.c
index 4874085..7e18200 100644
--- a/sound/soc/codecs/sta32x.c
+++ b/sound/soc/codecs/sta32x.c
@@ -833,23 +833,6 @@ static struct snd_soc_dai_driver sta32x_dai = {
.ops = &sta32x_dai_ops,
};
-#ifdef CONFIG_PM
-static int sta32x_suspend(struct snd_soc_codec *codec)
-{
- sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int sta32x_resume(struct snd_soc_codec *codec)
-{
- sta32x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define sta32x_suspend NULL
-#define sta32x_resume NULL
-#endif
-
static int sta32x_probe(struct snd_soc_codec *codec)
{
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
@@ -936,7 +919,6 @@ static int sta32x_remove(struct snd_soc_codec *codec)
struct sta32x_priv *sta32x = snd_soc_codec_get_drvdata(codec);
sta32x_watchdog_stop(sta32x);
- sta32x_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_disable(ARRAY_SIZE(sta32x->supplies), sta32x->supplies);
return 0;
@@ -955,9 +937,8 @@ static bool sta32x_reg_is_volatile(struct device *dev, unsigned int reg)
static const struct snd_soc_codec_driver sta32x_codec = {
.probe = sta32x_probe,
.remove = sta32x_remove,
- .suspend = sta32x_suspend,
- .resume = sta32x_resume,
.set_bias_level = sta32x_set_bias_level,
+ .suspend_bias_off = true,
.controls = sta32x_snd_controls,
.num_controls = ARRAY_SIZE(sta32x_snd_controls),
.dapm_widgets = sta32x_dapm_widgets,
diff --git a/sound/soc/codecs/sta350.c b/sound/soc/codecs/sta350.c
index cc97dd5..bda2ee1 100644
--- a/sound/soc/codecs/sta350.c
+++ b/sound/soc/codecs/sta350.c
@@ -912,23 +912,6 @@ static struct snd_soc_dai_driver sta350_dai = {
.ops = &sta350_dai_ops,
};
-#ifdef CONFIG_PM
-static int sta350_suspend(struct snd_soc_codec *codec)
-{
- sta350_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int sta350_resume(struct snd_soc_codec *codec)
-{
- sta350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define sta350_suspend NULL
-#define sta350_resume NULL
-#endif
-
static int sta350_probe(struct snd_soc_codec *codec)
{
struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
@@ -1065,7 +1048,6 @@ static int sta350_remove(struct snd_soc_codec *codec)
{
struct sta350_priv *sta350 = snd_soc_codec_get_drvdata(codec);
- sta350_set_bias_level(codec, SND_SOC_BIAS_OFF);
regulator_bulk_disable(ARRAY_SIZE(sta350->supplies), sta350->supplies);
return 0;
@@ -1074,9 +1056,8 @@ static int sta350_remove(struct snd_soc_codec *codec)
static const struct snd_soc_codec_driver sta350_codec = {
.probe = sta350_probe,
.remove = sta350_remove,
- .suspend = sta350_suspend,
- .resume = sta350_resume,
.set_bias_level = sta350_set_bias_level,
+ .suspend_bias_off = true,
.controls = sta350_snd_controls,
.num_controls = ARRAY_SIZE(sta350_snd_controls),
.dapm_widgets = sta350_dapm_widgets,
diff --git a/sound/soc/codecs/sta529.c b/sound/soc/codecs/sta529.c
index 89c748d..b0f436d 100644
--- a/sound/soc/codecs/sta529.c
+++ b/sound/soc/codecs/sta529.c
@@ -319,41 +319,10 @@ static struct snd_soc_dai_driver sta529_dai = {
.ops = &sta529_dai_ops,
};
-static int sta529_probe(struct snd_soc_codec *codec)
-{
- sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-/* power down chip */
-static int sta529_remove(struct snd_soc_codec *codec)
-{
- sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int sta529_suspend(struct snd_soc_codec *codec)
-{
- sta529_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int sta529_resume(struct snd_soc_codec *codec)
-{
- sta529_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
static const struct snd_soc_codec_driver sta529_codec_driver = {
- .probe = sta529_probe,
- .remove = sta529_remove,
.set_bias_level = sta529_set_bias_level,
- .suspend = sta529_suspend,
- .resume = sta529_resume,
+ .suspend_bias_off = true,
+
.controls = sta529_snd_controls,
.num_controls = ARRAY_SIZE(sta529_snd_controls),
};
diff --git a/sound/soc/codecs/stac9766.c b/sound/soc/codecs/stac9766.c
index 53b810d..dbff0c89 100644
--- a/sound/soc/codecs/stac9766.c
+++ b/sound/soc/codecs/stac9766.c
@@ -139,18 +139,19 @@ static const struct snd_kcontrol_new stac9766_snd_ac97_controls[] = {
static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
- soc_ac97_ops->write(codec->ac97, reg, val);
+ soc_ac97_ops->write(ac97, reg, val);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return 0;
}
if (reg / 2 >= ARRAY_SIZE(stac9766_reg))
return -EIO;
- soc_ac97_ops->write(codec->ac97, reg, val);
+ soc_ac97_ops->write(ac97, reg, val);
cache[reg / 2] = val;
return 0;
}
@@ -158,11 +159,12 @@ static int stac9766_ac97_write(struct snd_soc_codec *codec, unsigned int reg,
static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 val = 0, *cache = codec->reg_cache;
if (reg > AC97_STAC_PAGE0) {
stac9766_ac97_write(codec, AC97_INT_PAGING, 0);
- val = soc_ac97_ops->read(codec->ac97, reg - AC97_STAC_PAGE0);
+ val = soc_ac97_ops->read(ac97, reg - AC97_STAC_PAGE0);
stac9766_ac97_write(codec, AC97_INT_PAGING, 1);
return val;
}
@@ -173,7 +175,7 @@ static unsigned int stac9766_ac97_read(struct snd_soc_codec *codec,
reg == AC97_INT_PAGING || reg == AC97_VENDOR_ID1 ||
reg == AC97_VENDOR_ID2) {
- val = soc_ac97_ops->read(codec->ac97, reg);
+ val = soc_ac97_ops->read(ac97, reg);
return val;
}
return cache[reg / 2];
@@ -240,45 +242,41 @@ static int stac9766_set_bias_level(struct snd_soc_codec *codec,
static int stac9766_reset(struct snd_soc_codec *codec, int try_warm)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(codec->ac97);
+ soc_ac97_ops->warm_reset(ac97);
if (stac9766_ac97_read(codec, 0) == stac9766_reg[0])
return 1;
}
- soc_ac97_ops->reset(codec->ac97);
+ soc_ac97_ops->reset(ac97);
if (soc_ac97_ops->warm_reset)
- soc_ac97_ops->warm_reset(codec->ac97);
+ soc_ac97_ops->warm_reset(ac97);
if (stac9766_ac97_read(codec, 0) != stac9766_reg[0])
return -EIO;
return 0;
}
-static int stac9766_codec_suspend(struct snd_soc_codec *codec)
-{
- stac9766_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int stac9766_codec_resume(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 id, reset;
reset = 0;
/* give the codec an AC97 warm reset to start the link */
reset:
if (reset > 5) {
- printk(KERN_ERR "stac9766 failed to resume");
+ dev_err(codec->dev, "Failed to resume\n");
return -EIO;
}
- codec->ac97->bus->ops->warm_reset(codec->ac97);
- id = soc_ac97_ops->read(codec->ac97, AC97_VENDOR_ID2);
+ ac97->bus->ops->warm_reset(ac97);
+ id = soc_ac97_ops->read(ac97, AC97_VENDOR_ID2);
if (id != 0x4c13) {
stac9766_reset(codec, 0);
reset++;
goto reset;
}
- stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -294,7 +292,6 @@ static const struct snd_soc_dai_ops stac9766_dai_ops_digital = {
static struct snd_soc_dai_driver stac9766_dai[] = {
{
.name = "stac9766-hifi-analog",
- .ac97_control = 1,
/* stream cababilities */
.playback = {
@@ -316,7 +313,6 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
},
{
.name = "stac9766-hifi-IEC958",
- .ac97_control = 1,
/* stream cababilities */
.playback = {
@@ -334,46 +330,48 @@ static struct snd_soc_dai_driver stac9766_dai[] = {
static int stac9766_codec_probe(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97;
int ret = 0;
- ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
- if (ret < 0)
- goto codec_err;
+ ac97 = snd_soc_new_ac97_codec(codec);
+ if (IS_ERR(ac97))
+ return PTR_ERR(ac97);
+
+ snd_soc_codec_set_drvdata(codec, ac97);
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
stac9766_reset(codec, 0);
ret = stac9766_reset(codec, 1);
if (ret < 0) {
- printk(KERN_ERR "Failed to reset STAC9766: AC97 link error\n");
+ dev_err(codec->dev, "Failed to reset: AC97 link error\n");
goto codec_err;
}
- stac9766_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- snd_soc_add_codec_controls(codec, stac9766_snd_ac97_controls,
- ARRAY_SIZE(stac9766_snd_ac97_controls));
-
return 0;
codec_err:
- snd_soc_free_ac97_codec(codec);
+ snd_soc_free_ac97_codec(ac97);
return ret;
}
static int stac9766_codec_remove(struct snd_soc_codec *codec)
{
- snd_soc_free_ac97_codec(codec);
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_free_ac97_codec(ac97);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_stac9766 = {
+ .controls = stac9766_snd_ac97_controls,
+ .num_controls = ARRAY_SIZE(stac9766_snd_ac97_controls),
.write = stac9766_ac97_write,
.read = stac9766_ac97_read,
.set_bias_level = stac9766_set_bias_level,
+ .suspend_bias_off = true,
.probe = stac9766_codec_probe,
.remove = stac9766_codec_remove,
- .suspend = stac9766_codec_suspend,
.resume = stac9766_codec_resume,
.reg_cache_size = ARRAY_SIZE(stac9766_reg),
.reg_word_size = sizeof(u16),
diff --git a/sound/soc/codecs/tas2552.c b/sound/soc/codecs/tas2552.c
index f039dc8..b505212 100644
--- a/sound/soc/codecs/tas2552.c
+++ b/sound/soc/codecs/tas2552.c
@@ -345,7 +345,6 @@ static const struct reg_default tas2552_init_regs[] = {
static int tas2552_codec_probe(struct snd_soc_codec *codec)
{
struct tas2552_data *tas2552 = snd_soc_codec_get_drvdata(codec);
- struct snd_soc_dapm_context *dapm = &codec->dapm;
int ret;
tas2552->codec = codec;
@@ -390,11 +389,6 @@ static int tas2552_codec_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, TAS2552_CFG_2, TAS2552_BOOST_EN |
TAS2552_APT_EN | TAS2552_LIM_EN);
- snd_soc_dapm_new_controls(dapm, tas2552_dapm_widgets,
- ARRAY_SIZE(tas2552_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, tas2552_audio_map,
- ARRAY_SIZE(tas2552_audio_map));
-
return 0;
patch_fail:
@@ -462,6 +456,10 @@ static struct snd_soc_codec_driver soc_codec_dev_tas2552 = {
.resume = tas2552_resume,
.controls = tas2552_snd_controls,
.num_controls = ARRAY_SIZE(tas2552_snd_controls),
+ .dapm_widgets = tas2552_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tas2552_dapm_widgets),
+ .dapm_routes = tas2552_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(tas2552_audio_map),
};
static const struct regmap_config tas2552_regmap_config = {
diff --git a/sound/soc/codecs/tfa9879.c b/sound/soc/codecs/tfa9879.c
new file mode 100644
index 0000000..16f1b71
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.c
@@ -0,0 +1,328 @@
+/*
+ * tfa9879.c -- driver for NXP Semiconductors TFA9879
+ *
+ * Copyright (C) 2014 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * 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/init.h>
+#include <linux/i2c.h>
+#include <linux/regmap.h>
+#include <sound/soc.h>
+#include <sound/tlv.h>
+#include <sound/pcm_params.h>
+
+#include "tfa9879.h"
+
+struct tfa9879_priv {
+ struct regmap *regmap;
+ int lsb_justified;
+};
+
+static int tfa9879_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+ int fs;
+ int i2s_set = 0;
+
+ switch (params_rate(params)) {
+ case 8000:
+ fs = TFA9879_I2S_FS_8000;
+ break;
+ case 11025:
+ fs = TFA9879_I2S_FS_11025;
+ break;
+ case 12000:
+ fs = TFA9879_I2S_FS_12000;
+ break;
+ case 16000:
+ fs = TFA9879_I2S_FS_16000;
+ break;
+ case 22050:
+ fs = TFA9879_I2S_FS_22050;
+ break;
+ case 24000:
+ fs = TFA9879_I2S_FS_24000;
+ break;
+ case 32000:
+ fs = TFA9879_I2S_FS_32000;
+ break;
+ case 44100:
+ fs = TFA9879_I2S_FS_44100;
+ break;
+ case 48000:
+ fs = TFA9879_I2S_FS_48000;
+ break;
+ case 64000:
+ fs = TFA9879_I2S_FS_64000;
+ break;
+ case 88200:
+ fs = TFA9879_I2S_FS_88200;
+ break;
+ case 96000:
+ fs = TFA9879_I2S_FS_96000;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (params_width(params)) {
+ case 16:
+ i2s_set = TFA9879_I2S_SET_LSB_J_16;
+ break;
+ case 24:
+ i2s_set = TFA9879_I2S_SET_LSB_J_24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ if (tfa9879->lsb_justified)
+ snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+ TFA9879_I2S_SET_MASK,
+ i2s_set << TFA9879_I2S_SET_SHIFT);
+
+ snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+ TFA9879_I2S_FS_MASK,
+ fs << TFA9879_I2S_FS_SHIFT);
+ return 0;
+}
+
+static int tfa9879_digital_mute(struct snd_soc_dai *dai, int mute)
+{
+ struct snd_soc_codec *codec = dai->codec;
+
+ snd_soc_update_bits(codec, TFA9879_MISC_CONTROL,
+ TFA9879_S_MUTE_MASK,
+ !!mute << TFA9879_S_MUTE_SHIFT);
+
+ return 0;
+}
+
+static int tfa9879_set_fmt(struct snd_soc_dai *dai, unsigned int fmt)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct tfa9879_priv *tfa9879 = snd_soc_codec_get_drvdata(codec);
+ int i2s_set;
+ int sck_pol;
+
+ switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
+ case SND_SOC_DAIFMT_CBS_CFS:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_INV_MASK) {
+ case SND_SOC_DAIFMT_NB_NF:
+ sck_pol = TFA9879_SCK_POL_NORMAL;
+ break;
+ case SND_SOC_DAIFMT_IB_NF:
+ sck_pol = TFA9879_SCK_POL_INVERSE;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) {
+ case SND_SOC_DAIFMT_I2S:
+ tfa9879->lsb_justified = 0;
+ i2s_set = TFA9879_I2S_SET_I2S_24;
+ break;
+ case SND_SOC_DAIFMT_LEFT_J:
+ tfa9879->lsb_justified = 0;
+ i2s_set = TFA9879_I2S_SET_MSB_J_24;
+ break;
+ case SND_SOC_DAIFMT_RIGHT_J:
+ tfa9879->lsb_justified = 1;
+ i2s_set = TFA9879_I2S_SET_LSB_J_24;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+ TFA9879_SCK_POL_MASK,
+ sck_pol << TFA9879_SCK_POL_SHIFT);
+ snd_soc_update_bits(codec, TFA9879_SERIAL_INTERFACE_1,
+ TFA9879_I2S_SET_MASK,
+ i2s_set << TFA9879_I2S_SET_SHIFT);
+ return 0;
+}
+
+static struct reg_default tfa9879_regs[] = {
+ { TFA9879_DEVICE_CONTROL, 0x0000 }, /* 0x00 */
+ { TFA9879_SERIAL_INTERFACE_1, 0x0a18 }, /* 0x01 */
+ { TFA9879_PCM_IOM2_FORMAT_1, 0x0007 }, /* 0x02 */
+ { TFA9879_SERIAL_INTERFACE_2, 0x0a18 }, /* 0x03 */
+ { TFA9879_PCM_IOM2_FORMAT_2, 0x0007 }, /* 0x04 */
+ { TFA9879_EQUALIZER_A1, 0x59dd }, /* 0x05 */
+ { TFA9879_EQUALIZER_A2, 0xc63e }, /* 0x06 */
+ { TFA9879_EQUALIZER_B1, 0x651a }, /* 0x07 */
+ { TFA9879_EQUALIZER_B2, 0xe53e }, /* 0x08 */
+ { TFA9879_EQUALIZER_C1, 0x4616 }, /* 0x09 */
+ { TFA9879_EQUALIZER_C2, 0xd33e }, /* 0x0a */
+ { TFA9879_EQUALIZER_D1, 0x4df3 }, /* 0x0b */
+ { TFA9879_EQUALIZER_D2, 0xea3e }, /* 0x0c */
+ { TFA9879_EQUALIZER_E1, 0x5ee0 }, /* 0x0d */
+ { TFA9879_EQUALIZER_E2, 0xf93e }, /* 0x0e */
+ { TFA9879_BYPASS_CONTROL, 0x0093 }, /* 0x0f */
+ { TFA9879_DYNAMIC_RANGE_COMPR, 0x92ba }, /* 0x10 */
+ { TFA9879_BASS_TREBLE, 0x12a5 }, /* 0x11 */
+ { TFA9879_HIGH_PASS_FILTER, 0x0004 }, /* 0x12 */
+ { TFA9879_VOLUME_CONTROL, 0x10bd }, /* 0x13 */
+ { TFA9879_MISC_CONTROL, 0x0000 }, /* 0x14 */
+};
+
+static bool tfa9879_volatile_reg(struct device *dev, unsigned int reg)
+{
+ return reg == TFA9879_MISC_STATUS;
+}
+
+static const DECLARE_TLV_DB_SCALE(volume_tlv, -7050, 50, 1);
+static const DECLARE_TLV_DB_SCALE(tb_gain_tlv, -1800, 200, 0);
+static const char * const tb_freq_text[] = {
+ "Low", "Mid", "High"
+};
+static const struct soc_enum treble_freq_enum =
+ SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_TRBLE_SHIFT,
+ ARRAY_SIZE(tb_freq_text), tb_freq_text);
+static const struct soc_enum bass_freq_enum =
+ SOC_ENUM_SINGLE(TFA9879_BASS_TREBLE, TFA9879_F_BASS_SHIFT,
+ ARRAY_SIZE(tb_freq_text), tb_freq_text);
+
+static const struct snd_kcontrol_new tfa9879_controls[] = {
+ SOC_SINGLE_TLV("PCM Playback Volume", TFA9879_VOLUME_CONTROL,
+ TFA9879_VOL_SHIFT, 0xbd, 1, volume_tlv),
+ SOC_SINGLE_TLV("Treble Volume", TFA9879_BASS_TREBLE,
+ TFA9879_G_TRBLE_SHIFT, 18, 0, tb_gain_tlv),
+ SOC_SINGLE_TLV("Bass Volume", TFA9879_BASS_TREBLE,
+ TFA9879_G_BASS_SHIFT, 18, 0, tb_gain_tlv),
+ SOC_ENUM("Treble Corner Freq", treble_freq_enum),
+ SOC_ENUM("Bass Corner Freq", bass_freq_enum),
+};
+
+static const struct snd_soc_dapm_widget tfa9879_dapm_widgets[] = {
+SND_SOC_DAPM_AIF_IN("AIFINL", "Playback", 0, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_AIF_IN("AIFINR", "Playback", 1, SND_SOC_NOPM, 0, 0),
+SND_SOC_DAPM_DAC("DAC", NULL, TFA9879_DEVICE_CONTROL, TFA9879_OPMODE_SHIFT, 0),
+SND_SOC_DAPM_OUTPUT("LINEOUT"),
+SND_SOC_DAPM_SUPPLY("POWER", TFA9879_DEVICE_CONTROL, TFA9879_POWERUP_SHIFT, 0,
+ NULL, 0),
+};
+
+static const struct snd_soc_dapm_route tfa9879_dapm_routes[] = {
+ { "DAC", NULL, "AIFINL" },
+ { "DAC", NULL, "AIFINR" },
+
+ { "LINEOUT", NULL, "DAC" },
+
+ { "DAC", NULL, "POWER" },
+};
+
+static const struct snd_soc_codec_driver tfa9879_codec = {
+ .controls = tfa9879_controls,
+ .num_controls = ARRAY_SIZE(tfa9879_controls),
+
+ .dapm_widgets = tfa9879_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(tfa9879_dapm_widgets),
+ .dapm_routes = tfa9879_dapm_routes,
+ .num_dapm_routes = ARRAY_SIZE(tfa9879_dapm_routes),
+};
+
+static const struct regmap_config tfa9879_regmap = {
+ .reg_bits = 8,
+ .val_bits = 16,
+
+ .volatile_reg = tfa9879_volatile_reg,
+ .max_register = TFA9879_MISC_STATUS,
+ .reg_defaults = tfa9879_regs,
+ .num_reg_defaults = ARRAY_SIZE(tfa9879_regs),
+ .cache_type = REGCACHE_RBTREE,
+};
+
+static const struct snd_soc_dai_ops tfa9879_dai_ops = {
+ .hw_params = tfa9879_hw_params,
+ .digital_mute = tfa9879_digital_mute,
+ .set_fmt = tfa9879_set_fmt,
+};
+
+#define TFA9879_RATES SNDRV_PCM_RATE_8000_96000
+
+#define TFA9879_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
+ SNDRV_PCM_FMTBIT_S24_LE)
+
+static struct snd_soc_dai_driver tfa9879_dai = {
+ .name = "tfa9879-hifi",
+ .playback = {
+ .stream_name = "Playback",
+ .channels_min = 2,
+ .channels_max = 2,
+ .rates = TFA9879_RATES,
+ .formats = TFA9879_FORMATS, },
+ .ops = &tfa9879_dai_ops,
+};
+
+static int tfa9879_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct tfa9879_priv *tfa9879;
+ int i;
+
+ tfa9879 = devm_kzalloc(&i2c->dev, sizeof(*tfa9879), GFP_KERNEL);
+ if (IS_ERR(tfa9879))
+ return PTR_ERR(tfa9879);
+
+ i2c_set_clientdata(i2c, tfa9879);
+
+ tfa9879->regmap = devm_regmap_init_i2c(i2c, &tfa9879_regmap);
+ if (IS_ERR(tfa9879->regmap))
+ return PTR_ERR(tfa9879->regmap);
+
+ /* Ensure the device is in reset state */
+ for (i = 0; i < ARRAY_SIZE(tfa9879_regs); i++)
+ regmap_write(tfa9879->regmap,
+ tfa9879_regs[i].reg, tfa9879_regs[i].def);
+
+ return snd_soc_register_codec(&i2c->dev, &tfa9879_codec,
+ &tfa9879_dai, 1);
+}
+
+static int tfa9879_i2c_remove(struct i2c_client *client)
+{
+ snd_soc_unregister_codec(&client->dev);
+
+ return 0;
+}
+
+static const struct i2c_device_id tfa9879_i2c_id[] = {
+ { "tfa9879", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, tfa9879_i2c_id);
+
+static struct i2c_driver tfa9879_i2c_driver = {
+ .driver = {
+ .name = "tfa9879",
+ .owner = THIS_MODULE,
+ },
+ .probe = tfa9879_i2c_probe,
+ .remove = tfa9879_i2c_remove,
+ .id_table = tfa9879_i2c_id,
+};
+
+module_i2c_driver(tfa9879_i2c_driver);
+
+MODULE_DESCRIPTION("ASoC NXP Semiconductors TFA9879 driver");
+MODULE_AUTHOR("Peter Rosin <peda@axentia.se>");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/codecs/tfa9879.h b/sound/soc/codecs/tfa9879.h
new file mode 100644
index 0000000..3408c90
--- /dev/null
+++ b/sound/soc/codecs/tfa9879.h
@@ -0,0 +1,202 @@
+/*
+ * tfa9879.h -- driver for NXP Semiconductors TFA9879
+ *
+ * Copyright (C) 2014 Axentia Technologies AB
+ * Author: Peter Rosin <peda@axentia.se>
+ *
+ * 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 _TFA9879_H
+#define _TFA9879_H
+
+#define TFA9879_DEVICE_CONTROL 0x00
+#define TFA9879_SERIAL_INTERFACE_1 0x01
+#define TFA9879_PCM_IOM2_FORMAT_1 0x02
+#define TFA9879_SERIAL_INTERFACE_2 0x03
+#define TFA9879_PCM_IOM2_FORMAT_2 0x04
+#define TFA9879_EQUALIZER_A1 0x05
+#define TFA9879_EQUALIZER_A2 0x06
+#define TFA9879_EQUALIZER_B1 0x07
+#define TFA9879_EQUALIZER_B2 0x08
+#define TFA9879_EQUALIZER_C1 0x09
+#define TFA9879_EQUALIZER_C2 0x0a
+#define TFA9879_EQUALIZER_D1 0x0b
+#define TFA9879_EQUALIZER_D2 0x0c
+#define TFA9879_EQUALIZER_E1 0x0d
+#define TFA9879_EQUALIZER_E2 0x0e
+#define TFA9879_BYPASS_CONTROL 0x0f
+#define TFA9879_DYNAMIC_RANGE_COMPR 0x10
+#define TFA9879_BASS_TREBLE 0x11
+#define TFA9879_HIGH_PASS_FILTER 0x12
+#define TFA9879_VOLUME_CONTROL 0x13
+#define TFA9879_MISC_CONTROL 0x14
+#define TFA9879_MISC_STATUS 0x15
+
+/* TFA9879_DEVICE_CONTROL */
+#define TFA9879_INPUT_SEL_MASK 0x0010
+#define TFA9879_INPUT_SEL_SHIFT 4
+#define TFA9879_OPMODE_MASK 0x0008
+#define TFA9879_OPMODE_SHIFT 3
+#define TFA9879_RESET_MASK 0x0002
+#define TFA9879_RESET_SHIFT 1
+#define TFA9879_POWERUP_MASK 0x0001
+#define TFA9879_POWERUP_SHIFT 0
+
+/* TFA9879_SERIAL_INTERFACE */
+#define TFA9879_MONO_SEL_MASK 0x0c00
+#define TFA9879_MONO_SEL_SHIFT 10
+#define TFA9879_MONO_SEL_LEFT 0
+#define TFA9879_MONO_SEL_RIGHT 1
+#define TFA9879_MONO_SEL_BOTH 2
+#define TFA9879_I2S_FS_MASK 0x03c0
+#define TFA9879_I2S_FS_SHIFT 6
+#define TFA9879_I2S_FS_8000 0
+#define TFA9879_I2S_FS_11025 1
+#define TFA9879_I2S_FS_12000 2
+#define TFA9879_I2S_FS_16000 3
+#define TFA9879_I2S_FS_22050 4
+#define TFA9879_I2S_FS_24000 5
+#define TFA9879_I2S_FS_32000 6
+#define TFA9879_I2S_FS_44100 7
+#define TFA9879_I2S_FS_48000 8
+#define TFA9879_I2S_FS_64000 9
+#define TFA9879_I2S_FS_88200 10
+#define TFA9879_I2S_FS_96000 11
+#define TFA9879_I2S_SET_MASK 0x0038
+#define TFA9879_I2S_SET_SHIFT 3
+#define TFA9879_I2S_SET_MSB_J_24 2
+#define TFA9879_I2S_SET_I2S_24 3
+#define TFA9879_I2S_SET_LSB_J_16 4
+#define TFA9879_I2S_SET_LSB_J_18 5
+#define TFA9879_I2S_SET_LSB_J_20 6
+#define TFA9879_I2S_SET_LSB_J_24 7
+#define TFA9879_SCK_POL_MASK 0x0004
+#define TFA9879_SCK_POL_SHIFT 2
+#define TFA9879_SCK_POL_NORMAL 0
+#define TFA9879_SCK_POL_INVERSE 1
+#define TFA9879_I_MODE_MASK 0x0003
+#define TFA9879_I_MODE_SHIFT 0
+#define TFA9879_I_MODE_I2S 0
+#define TFA9879_I_MODE_PCM_IOM2_SHORT 1
+#define TFA9879_I_MODE_PCM_IOM2_LONG 2
+
+/* TFA9879_PCM_IOM2_FORMAT */
+#define TFA9879_PCM_FS_MASK 0x0800
+#define TFA9879_PCM_FS_SHIFT 11
+#define TFA9879_A_LAW_MASK 0x0400
+#define TFA9879_A_LAW_SHIFT 10
+#define TFA9879_PCM_COMP_MASK 0x0200
+#define TFA9879_PCM_COMP_SHIFT 9
+#define TFA9879_PCM_DL_MASK 0x0100
+#define TFA9879_PCM_DL_SHIFT 8
+#define TFA9879_D1_SLOT_MASK 0x00f0
+#define TFA9879_D1_SLOT_SHIFT 4
+#define TFA9879_D2_SLOT_MASK 0x000f
+#define TFA9879_D2_SLOT_SHIFT 0
+
+/* TFA9879_EQUALIZER_X1 */
+#define TFA9879_T1_MASK 0x8000
+#define TFA9879_T1_SHIFT 15
+#define TFA9879_K1M_MASK 0x7ff0
+#define TFA9879_K1M_SHIFT 4
+#define TFA9879_K1E_MASK 0x000f
+#define TFA9879_K1E_SHIFT 0
+
+/* TFA9879_EQUALIZER_X2 */
+#define TFA9879_T2_MASK 0x8000
+#define TFA9879_T2_SHIFT 15
+#define TFA9879_K2M_MASK 0x7800
+#define TFA9879_K2M_SHIFT 11
+#define TFA9879_K2E_MASK 0x0700
+#define TFA9879_K2E_SHIFT 8
+#define TFA9879_K0_MASK 0x00fe
+#define TFA9879_K0_SHIFT 1
+#define TFA9879_S_MASK 0x0001
+#define TFA9879_S_SHIFT 0
+
+/* TFA9879_BYPASS_CONTROL */
+#define TFA9879_L_OCP_MASK 0x00c0
+#define TFA9879_L_OCP_SHIFT 6
+#define TFA9879_L_OTP_MASK 0x0030
+#define TFA9879_L_OTP_SHIFT 4
+#define TFA9879_CLIPCTRL_MASK 0x0008
+#define TFA9879_CLIPCTRL_SHIFT 3
+#define TFA9879_HPF_BP_MASK 0x0004
+#define TFA9879_HPF_BP_SHIFT 2
+#define TFA9879_DRC_BP_MASK 0x0002
+#define TFA9879_DRC_BP_SHIFT 1
+#define TFA9879_EQ_BP_MASK 0x0001
+#define TFA9879_EQ_BP_SHIFT 0
+
+/* TFA9879_DYNAMIC_RANGE_COMPR */
+#define TFA9879_AT_LVL_MASK 0xf000
+#define TFA9879_AT_LVL_SHIFT 12
+#define TFA9879_AT_RATE_MASK 0x0f00
+#define TFA9879_AT_RATE_SHIFT 8
+#define TFA9879_RL_LVL_MASK 0x00f0
+#define TFA9879_RL_LVL_SHIFT 4
+#define TFA9879_RL_RATE_MASK 0x000f
+#define TFA9879_RL_RATE_SHIFT 0
+
+/* TFA9879_BASS_TREBLE */
+#define TFA9879_G_TRBLE_MASK 0x3e00
+#define TFA9879_G_TRBLE_SHIFT 9
+#define TFA9879_F_TRBLE_MASK 0x0180
+#define TFA9879_F_TRBLE_SHIFT 7
+#define TFA9879_G_BASS_MASK 0x007c
+#define TFA9879_G_BASS_SHIFT 2
+#define TFA9879_F_BASS_MASK 0x0003
+#define TFA9879_F_BASS_SHIFT 0
+
+/* TFA9879_HIGH_PASS_FILTER */
+#define TFA9879_HP_CTRL_MASK 0x00ff
+#define TFA9879_HP_CTRL_SHIFT 0
+
+/* TFA9879_VOLUME_CONTROL */
+#define TFA9879_ZR_CRSS_MASK 0x1000
+#define TFA9879_ZR_CRSS_SHIFT 12
+#define TFA9879_VOL_MASK 0x00ff
+#define TFA9879_VOL_SHIFT 0
+
+/* TFA9879_MISC_CONTROL */
+#define TFA9879_DE_PHAS_MASK 0x0c00
+#define TFA9879_DE_PHAS_SHIFT 10
+#define TFA9879_H_MUTE_MASK 0x0200
+#define TFA9879_H_MUTE_SHIFT 9
+#define TFA9879_S_MUTE_MASK 0x0100
+#define TFA9879_S_MUTE_SHIFT 8
+#define TFA9879_P_LIM_MASK 0x00ff
+#define TFA9879_P_LIM_SHIFT 0
+
+/* TFA9879_MISC_STATUS */
+#define TFA9879_PS_MASK 0x4000
+#define TFA9879_PS_SHIFT 14
+#define TFA9879_PORA_MASK 0x2000
+#define TFA9879_PORA_SHIFT 13
+#define TFA9879_AMP_MASK 0x0600
+#define TFA9879_AMP_SHIFT 9
+#define TFA9879_IBP_2_MASK 0x0100
+#define TFA9879_IBP_2_SHIFT 8
+#define TFA9879_OFP_2_MASK 0x0080
+#define TFA9879_OFP_2_SHIFT 7
+#define TFA9879_UFP_2_MASK 0x0040
+#define TFA9879_UFP_2_SHIFT 6
+#define TFA9879_IBP_1_MASK 0x0020
+#define TFA9879_IBP_1_SHIFT 5
+#define TFA9879_OFP_1_MASK 0x0010
+#define TFA9879_OFP_1_SHIFT 4
+#define TFA9879_UFP_1_MASK 0x0008
+#define TFA9879_UFP_1_SHIFT 3
+#define TFA9879_OCPOKA_MASK 0x0004
+#define TFA9879_OCPOKA_SHIFT 2
+#define TFA9879_OCPOKB_MASK 0x0002
+#define TFA9879_OCPOKB_SHIFT 1
+#define TFA9879_OTPOK_MASK 0x0001
+#define TFA9879_OTPOK_SHIFT 0
+
+#endif
diff --git a/sound/soc/codecs/tlv320aic23.c b/sound/soc/codecs/tlv320aic23.c
index d671679..cc17e7e 100644
--- a/sound/soc/codecs/tlv320aic23.c
+++ b/sound/soc/codecs/tlv320aic23.c
@@ -540,19 +540,11 @@ static struct snd_soc_dai_driver tlv320aic23_dai = {
.ops = &tlv320aic23_dai_ops,
};
-static int tlv320aic23_suspend(struct snd_soc_codec *codec)
-{
- tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
static int tlv320aic23_resume(struct snd_soc_codec *codec)
{
struct aic23 *aic23 = snd_soc_codec_get_drvdata(codec);
regcache_mark_dirty(aic23->regmap);
regcache_sync(aic23->regmap);
- tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
}
@@ -562,9 +554,6 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
/* Reset codec */
snd_soc_write(codec, TLV320AIC23_RESET, 0);
- /* power on device */
- tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
snd_soc_write(codec, TLV320AIC23_DIGT, TLV320AIC23_DEEMP_44K);
/* Unmute input */
@@ -589,18 +578,12 @@ static int tlv320aic23_codec_probe(struct snd_soc_codec *codec)
return 0;
}
-static int tlv320aic23_remove(struct snd_soc_codec *codec)
-{
- tlv320aic23_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_tlv320aic23 = {
.probe = tlv320aic23_codec_probe,
- .remove = tlv320aic23_remove,
- .suspend = tlv320aic23_suspend,
.resume = tlv320aic23_resume,
.set_bias_level = tlv320aic23_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = tlv320aic23_snd_controls,
.num_controls = ARRAY_SIZE(tlv320aic23_snd_controls),
.dapm_widgets = tlv320aic23_dapm_widgets,
diff --git a/sound/soc/codecs/tlv320aic31xx.c b/sound/soc/codecs/tlv320aic31xx.c
index 145fe5b..dc3223d 100644
--- a/sound/soc/codecs/tlv320aic31xx.c
+++ b/sound/soc/codecs/tlv320aic31xx.c
@@ -911,12 +911,13 @@ static int aic31xx_set_dai_sysclk(struct snd_soc_dai *codec_dai,
}
aic31xx->p_div = i;
- for (i = 0; aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++) {
- if (i == ARRAY_SIZE(aic31xx_divs)) {
- dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
- __func__, freq);
- return -EINVAL;
- }
+ for (i = 0; i < ARRAY_SIZE(aic31xx_divs) &&
+ aic31xx_divs[i].mclk_p != freq/aic31xx->p_div; i++)
+ ;
+ if (i == ARRAY_SIZE(aic31xx_divs)) {
+ dev_err(aic31xx->dev, "%s: Unsupported frequency %d\n",
+ __func__, freq);
+ return -EINVAL;
}
/* set clock on MCLK, BCLK, or GPIO1 as PLL input */
@@ -1056,18 +1057,6 @@ static int aic31xx_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int aic31xx_suspend(struct snd_soc_codec *codec)
-{
- aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int aic31xx_resume(struct snd_soc_codec *codec)
-{
- aic31xx_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int aic31xx_codec_probe(struct snd_soc_codec *codec)
{
int ret = 0;
@@ -1110,8 +1099,6 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec)
{
struct aic31xx_priv *aic31xx = snd_soc_codec_get_drvdata(codec);
int i;
- /* power down chip */
- aic31xx_set_bias_level(codec, SND_SOC_BIAS_OFF);
for (i = 0; i < ARRAY_SIZE(aic31xx->supplies); i++)
regulator_unregister_notifier(aic31xx->supplies[i].consumer,
@@ -1123,9 +1110,9 @@ static int aic31xx_codec_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_driver_aic31xx = {
.probe = aic31xx_codec_probe,
.remove = aic31xx_codec_remove,
- .suspend = aic31xx_suspend,
- .resume = aic31xx_resume,
.set_bias_level = aic31xx_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = aic31xx_snd_controls,
.num_controls = ARRAY_SIZE(aic31xx_snd_controls),
.dapm_widgets = aic31xx_dapm_widgets,
diff --git a/sound/soc/codecs/tlv320aic32x4.c b/sound/soc/codecs/tlv320aic32x4.c
index 6ea662d..015467e 100644
--- a/sound/soc/codecs/tlv320aic32x4.c
+++ b/sound/soc/codecs/tlv320aic32x4.c
@@ -597,18 +597,6 @@ static struct snd_soc_dai_driver aic32x4_dai = {
.symmetric_rates = 1,
};
-static int aic32x4_suspend(struct snd_soc_codec *codec)
-{
- aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int aic32x4_resume(struct snd_soc_codec *codec)
-{
- aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int aic32x4_probe(struct snd_soc_codec *codec)
{
struct aic32x4_priv *aic32x4 = snd_soc_codec_get_drvdata(codec);
@@ -654,8 +642,6 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, AIC32X4_RMICPGANIN,
AIC32X4_RMICPGANIN_CM1R_10K);
- aic32x4_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/*
* Workaround: for an unknown reason, the ADC needs to be powered up
* and down for the first capture to work properly. It seems related to
@@ -669,18 +655,10 @@ static int aic32x4_probe(struct snd_soc_codec *codec)
return 0;
}
-static int aic32x4_remove(struct snd_soc_codec *codec)
-{
- aic32x4_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_aic32x4 = {
.probe = aic32x4_probe,
- .remove = aic32x4_remove,
- .suspend = aic32x4_suspend,
- .resume = aic32x4_resume,
.set_bias_level = aic32x4_set_bias_level,
+ .suspend_bias_off = true,
.controls = aic32x4_snd_controls,
.num_controls = ARRAY_SIZE(aic32x4_snd_controls),
diff --git a/sound/soc/codecs/tlv320aic3x.c b/sound/soc/codecs/tlv320aic3x.c
index f7c2a57..b7ebce0 100644
--- a/sound/soc/codecs/tlv320aic3x.c
+++ b/sound/soc/codecs/tlv320aic3x.c
@@ -78,6 +78,8 @@ struct aic3x_priv {
struct aic3x_disable_nb disable_nb[AIC3X_NUM_SUPPLIES];
struct aic3x_setup_data *setup;
unsigned int sysclk;
+ unsigned int dai_fmt;
+ unsigned int tdm_delay;
struct list_head list;
int master;
int gpio_reset;
@@ -214,61 +216,78 @@ static int mic_bias_event(struct snd_soc_dapm_widget *w,
return 0;
}
-static const char *aic3x_left_dac_mux[] = { "DAC_L1", "DAC_L3", "DAC_L2" };
-static const char *aic3x_right_dac_mux[] = { "DAC_R1", "DAC_R3", "DAC_R2" };
-static const char *aic3x_left_hpcom_mux[] =
- { "differential of HPLOUT", "constant VCM", "single-ended" };
-static const char *aic3x_right_hpcom_mux[] =
- { "differential of HPROUT", "constant VCM", "single-ended",
- "differential of HPLCOM", "external feedback" };
-static const char *aic3x_linein_mode_mux[] = { "single-ended", "differential" };
-static const char *aic3x_adc_hpf[] =
- { "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" };
-
-#define LDAC_ENUM 0
-#define RDAC_ENUM 1
-#define LHPCOM_ENUM 2
-#define RHPCOM_ENUM 3
-#define LINE1L_2_L_ENUM 4
-#define LINE1L_2_R_ENUM 5
-#define LINE1R_2_L_ENUM 6
-#define LINE1R_2_R_ENUM 7
-#define LINE2L_ENUM 8
-#define LINE2R_ENUM 9
-#define ADC_HPF_ENUM 10
-
-static const struct soc_enum aic3x_enum[] = {
- SOC_ENUM_SINGLE(DAC_LINE_MUX, 6, 3, aic3x_left_dac_mux),
- SOC_ENUM_SINGLE(DAC_LINE_MUX, 4, 3, aic3x_right_dac_mux),
- SOC_ENUM_SINGLE(HPLCOM_CFG, 4, 3, aic3x_left_hpcom_mux),
- SOC_ENUM_SINGLE(HPRCOM_CFG, 3, 5, aic3x_right_hpcom_mux),
- SOC_ENUM_SINGLE(LINE1L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
- SOC_ENUM_SINGLE(LINE1L_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
- SOC_ENUM_SINGLE(LINE1R_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
- SOC_ENUM_SINGLE(LINE1R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
- SOC_ENUM_SINGLE(LINE2L_2_LADC_CTRL, 7, 2, aic3x_linein_mode_mux),
- SOC_ENUM_SINGLE(LINE2R_2_RADC_CTRL, 7, 2, aic3x_linein_mode_mux),
- SOC_ENUM_DOUBLE(AIC3X_CODEC_DFILT_CTRL, 6, 4, 4, aic3x_adc_hpf),
-};
-
-static const char *aic3x_agc_level[] =
- { "-5.5dB", "-8dB", "-10dB", "-12dB", "-14dB", "-17dB", "-20dB", "-24dB" };
-static const struct soc_enum aic3x_agc_level_enum[] = {
- SOC_ENUM_SINGLE(LAGC_CTRL_A, 4, 8, aic3x_agc_level),
- SOC_ENUM_SINGLE(RAGC_CTRL_A, 4, 8, aic3x_agc_level),
-};
-
-static const char *aic3x_agc_attack[] = { "8ms", "11ms", "16ms", "20ms" };
-static const struct soc_enum aic3x_agc_attack_enum[] = {
- SOC_ENUM_SINGLE(LAGC_CTRL_A, 2, 4, aic3x_agc_attack),
- SOC_ENUM_SINGLE(RAGC_CTRL_A, 2, 4, aic3x_agc_attack),
-};
-
-static const char *aic3x_agc_decay[] = { "100ms", "200ms", "400ms", "500ms" };
-static const struct soc_enum aic3x_agc_decay_enum[] = {
- SOC_ENUM_SINGLE(LAGC_CTRL_A, 0, 4, aic3x_agc_decay),
- SOC_ENUM_SINGLE(RAGC_CTRL_A, 0, 4, aic3x_agc_decay),
-};
+static const char * const aic3x_left_dac_mux[] = {
+ "DAC_L1", "DAC_L3", "DAC_L2" };
+static SOC_ENUM_SINGLE_DECL(aic3x_left_dac_enum, DAC_LINE_MUX, 6,
+ aic3x_left_dac_mux);
+
+static const char * const aic3x_right_dac_mux[] = {
+ "DAC_R1", "DAC_R3", "DAC_R2" };
+static SOC_ENUM_SINGLE_DECL(aic3x_right_dac_enum, DAC_LINE_MUX, 4,
+ aic3x_right_dac_mux);
+
+static const char * const aic3x_left_hpcom_mux[] = {
+ "differential of HPLOUT", "constant VCM", "single-ended" };
+static SOC_ENUM_SINGLE_DECL(aic3x_left_hpcom_enum, HPLCOM_CFG, 4,
+ aic3x_left_hpcom_mux);
+
+static const char * const aic3x_right_hpcom_mux[] = {
+ "differential of HPROUT", "constant VCM", "single-ended",
+ "differential of HPLCOM", "external feedback" };
+static SOC_ENUM_SINGLE_DECL(aic3x_right_hpcom_enum, HPRCOM_CFG, 3,
+ aic3x_right_hpcom_mux);
+
+static const char * const aic3x_linein_mode_mux[] = {
+ "single-ended", "differential" };
+static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_l_enum, LINE1L_2_LADC_CTRL, 7,
+ aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line1l_2_r_enum, LINE1L_2_RADC_CTRL, 7,
+ aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_l_enum, LINE1R_2_LADC_CTRL, 7,
+ aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line1r_2_r_enum, LINE1R_2_RADC_CTRL, 7,
+ aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line2l_2_ldac_enum, LINE2L_2_LADC_CTRL, 7,
+ aic3x_linein_mode_mux);
+static SOC_ENUM_SINGLE_DECL(aic3x_line2r_2_rdac_enum, LINE2R_2_RADC_CTRL, 7,
+ aic3x_linein_mode_mux);
+
+static const char * const aic3x_adc_hpf[] = {
+ "Disabled", "0.0045xFs", "0.0125xFs", "0.025xFs" };
+static SOC_ENUM_DOUBLE_DECL(aic3x_adc_hpf_enum, AIC3X_CODEC_DFILT_CTRL, 6, 4,
+ aic3x_adc_hpf);
+
+static const char * const aic3x_agc_level[] = {
+ "-5.5dB", "-8dB", "-10dB", "-12dB",
+ "-14dB", "-17dB", "-20dB", "-24dB" };
+static SOC_ENUM_SINGLE_DECL(aic3x_lagc_level_enum, LAGC_CTRL_A, 4,
+ aic3x_agc_level);
+static SOC_ENUM_SINGLE_DECL(aic3x_ragc_level_enum, RAGC_CTRL_A, 4,
+ aic3x_agc_level);
+
+static const char * const aic3x_agc_attack[] = {
+ "8ms", "11ms", "16ms", "20ms" };
+static SOC_ENUM_SINGLE_DECL(aic3x_lagc_attack_enum, LAGC_CTRL_A, 2,
+ aic3x_agc_attack);
+static SOC_ENUM_SINGLE_DECL(aic3x_ragc_attack_enum, RAGC_CTRL_A, 2,
+ aic3x_agc_attack);
+
+static const char * const aic3x_agc_decay[] = {
+ "100ms", "200ms", "400ms", "500ms" };
+static SOC_ENUM_SINGLE_DECL(aic3x_lagc_decay_enum, LAGC_CTRL_A, 0,
+ aic3x_agc_decay);
+static SOC_ENUM_SINGLE_DECL(aic3x_ragc_decay_enum, RAGC_CTRL_A, 0,
+ aic3x_agc_decay);
+
+static const char * const aic3x_poweron_time[] = {
+ "0us", "10us", "100us", "1ms", "10ms", "50ms",
+ "100ms", "200ms", "400ms", "800ms", "2s", "4s" };
+static SOC_ENUM_SINGLE_DECL(aic3x_poweron_time_enum, HPOUT_POP_REDUCTION, 4,
+ aic3x_poweron_time);
+
+static const char * const aic3x_rampup_step[] = { "0ms", "1ms", "2ms", "4ms" };
+static SOC_ENUM_SINGLE_DECL(aic3x_rampup_step_enum, HPOUT_POP_REDUCTION, 2,
+ aic3x_rampup_step);
/*
* DAC digital volumes. From -63.5 to 0 dB in 0.5 dB steps
@@ -383,12 +402,12 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
* adjust PGA to max value when ADC is on and will never go back.
*/
SOC_DOUBLE_R("AGC Switch", LAGC_CTRL_A, RAGC_CTRL_A, 7, 0x01, 0),
- SOC_ENUM("Left AGC Target level", aic3x_agc_level_enum[0]),
- SOC_ENUM("Right AGC Target level", aic3x_agc_level_enum[1]),
- SOC_ENUM("Left AGC Attack time", aic3x_agc_attack_enum[0]),
- SOC_ENUM("Right AGC Attack time", aic3x_agc_attack_enum[1]),
- SOC_ENUM("Left AGC Decay time", aic3x_agc_decay_enum[0]),
- SOC_ENUM("Right AGC Decay time", aic3x_agc_decay_enum[1]),
+ SOC_ENUM("Left AGC Target level", aic3x_lagc_level_enum),
+ SOC_ENUM("Right AGC Target level", aic3x_ragc_level_enum),
+ SOC_ENUM("Left AGC Attack time", aic3x_lagc_attack_enum),
+ SOC_ENUM("Right AGC Attack time", aic3x_ragc_attack_enum),
+ SOC_ENUM("Left AGC Decay time", aic3x_lagc_decay_enum),
+ SOC_ENUM("Right AGC Decay time", aic3x_ragc_decay_enum),
/* De-emphasis */
SOC_DOUBLE("De-emphasis Switch", AIC3X_CODEC_DFILT_CTRL, 2, 0, 0x01, 0),
@@ -398,7 +417,11 @@ static const struct snd_kcontrol_new aic3x_snd_controls[] = {
0, 119, 0, adc_tlv),
SOC_DOUBLE_R("PGA Capture Switch", LADC_VOL, RADC_VOL, 7, 0x01, 1),
- SOC_ENUM("ADC HPF Cut-off", aic3x_enum[ADC_HPF_ENUM]),
+ SOC_ENUM("ADC HPF Cut-off", aic3x_adc_hpf_enum),
+
+ /* Pop reduction */
+ SOC_ENUM("Output Driver Power-On time", aic3x_poweron_time_enum),
+ SOC_ENUM("Output Driver Ramp-up step", aic3x_rampup_step_enum),
};
static const struct snd_kcontrol_new aic3x_mono_controls[] = {
@@ -425,19 +448,19 @@ static const struct snd_kcontrol_new aic3x_classd_amp_gain_ctrl =
/* Left DAC Mux */
static const struct snd_kcontrol_new aic3x_left_dac_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LDAC_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_left_dac_enum);
/* Right DAC Mux */
static const struct snd_kcontrol_new aic3x_right_dac_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[RDAC_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_right_dac_enum);
/* Left HPCOM Mux */
static const struct snd_kcontrol_new aic3x_left_hpcom_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LHPCOM_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_left_hpcom_enum);
/* Right HPCOM Mux */
static const struct snd_kcontrol_new aic3x_right_hpcom_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[RHPCOM_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_right_hpcom_enum);
/* Left Line Mixer */
static const struct snd_kcontrol_new aic3x_left_line_mixer_controls[] = {
@@ -529,23 +552,23 @@ static const struct snd_kcontrol_new aic3x_right_pga_mixer_controls[] = {
/* Left Line1 Mux */
static const struct snd_kcontrol_new aic3x_left_line1l_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_L_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_line1l_2_l_enum);
static const struct snd_kcontrol_new aic3x_right_line1l_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE1L_2_R_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_line1l_2_r_enum);
/* Right Line1 Mux */
static const struct snd_kcontrol_new aic3x_right_line1r_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_R_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_line1r_2_r_enum);
static const struct snd_kcontrol_new aic3x_left_line1r_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE1R_2_L_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_line1r_2_l_enum);
/* Left Line2 Mux */
static const struct snd_kcontrol_new aic3x_left_line2_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE2L_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_line2l_2_ldac_enum);
/* Right Line2 Mux */
static const struct snd_kcontrol_new aic3x_right_line2_mux_controls =
-SOC_DAPM_ENUM("Route", aic3x_enum[LINE2R_ENUM]);
+SOC_DAPM_ENUM("Route", aic3x_line2r_2_rdac_enum);
static const struct snd_soc_dapm_widget aic3x_dapm_widgets[] = {
/* Left DAC to Left Outputs */
@@ -1009,6 +1032,25 @@ found:
return 0;
}
+static int aic3x_prepare(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct snd_soc_codec *codec = dai->codec;
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ int delay = 0;
+
+ /* TDM slot selection only valid in DSP_A/_B mode */
+ if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_A)
+ delay += (aic3x->tdm_delay + 1);
+ else if (aic3x->dai_fmt == SND_SOC_DAIFMT_DSP_B)
+ delay += aic3x->tdm_delay;
+
+ /* Configure data delay */
+ snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, aic3x->tdm_delay);
+
+ return 0;
+}
+
static int aic3x_mute(struct snd_soc_dai *dai, int mute)
{
struct snd_soc_codec *codec = dai->codec;
@@ -1048,7 +1090,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
struct snd_soc_codec *codec = codec_dai->codec;
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
u8 iface_areg, iface_breg;
- int delay = 0;
iface_areg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLA) & 0x3f;
iface_breg = snd_soc_read(codec, AIC3X_ASD_INTF_CTRLB) & 0x3f;
@@ -1076,7 +1117,6 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
case (SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF):
break;
case (SND_SOC_DAIFMT_DSP_A | SND_SOC_DAIFMT_IB_NF):
- delay = 1;
case (SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF):
iface_breg |= (0x01 << 6);
break;
@@ -1090,10 +1130,45 @@ static int aic3x_set_dai_fmt(struct snd_soc_dai *codec_dai,
return -EINVAL;
}
+ aic3x->dai_fmt = fmt & SND_SOC_DAIFMT_FORMAT_MASK;
+
/* set iface */
snd_soc_write(codec, AIC3X_ASD_INTF_CTRLA, iface_areg);
snd_soc_write(codec, AIC3X_ASD_INTF_CTRLB, iface_breg);
- snd_soc_write(codec, AIC3X_ASD_INTF_CTRLC, delay);
+
+ return 0;
+}
+
+static int aic3x_set_dai_tdm_slot(struct snd_soc_dai *codec_dai,
+ unsigned int tx_mask, unsigned int rx_mask,
+ int slots, int slot_width)
+{
+ struct snd_soc_codec *codec = codec_dai->codec;
+ struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
+ unsigned int lsb;
+
+ if (tx_mask != rx_mask) {
+ dev_err(codec->dev, "tx and rx masks must be symmetric\n");
+ return -EINVAL;
+ }
+
+ if (unlikely(!tx_mask)) {
+ dev_err(codec->dev, "tx and rx masks need to be non 0\n");
+ return -EINVAL;
+ }
+
+ /* TDM based on DSP mode requires slots to be adjacent */
+ lsb = __ffs(tx_mask);
+ if ((lsb + 1) != __fls(tx_mask)) {
+ dev_err(codec->dev, "Invalid mask, slots must be adjacent\n");
+ return -EINVAL;
+ }
+
+ aic3x->tdm_delay = lsb * slot_width;
+
+ /* DOUT in high-impedance on inactive bit clocks */
+ snd_soc_update_bits(codec, AIC3X_ASD_INTF_CTRLA,
+ DOUT_TRISTATE, DOUT_TRISTATE);
return 0;
}
@@ -1212,9 +1287,11 @@ static int aic3x_set_bias_level(struct snd_soc_codec *codec,
static const struct snd_soc_dai_ops aic3x_dai_ops = {
.hw_params = aic3x_hw_params,
+ .prepare = aic3x_prepare,
.digital_mute = aic3x_mute,
.set_sysclk = aic3x_set_dai_sysclk,
.set_fmt = aic3x_set_dai_fmt,
+ .set_tdm_slot = aic3x_set_dai_tdm_slot,
};
static struct snd_soc_dai_driver aic3x_dai = {
@@ -1414,7 +1491,6 @@ static int aic3x_remove(struct snd_soc_codec *codec)
struct aic3x_priv *aic3x = snd_soc_codec_get_drvdata(codec);
int i;
- aic3x_set_bias_level(codec, SND_SOC_BIAS_OFF);
list_del(&aic3x->list);
for (i = 0; i < ARRAY_SIZE(aic3x->supplies); i++)
regulator_unregister_notifier(aic3x->supplies[i].consumer,
diff --git a/sound/soc/codecs/tlv320aic3x.h b/sound/soc/codecs/tlv320aic3x.h
index e521ac3..89fa692 100644
--- a/sound/soc/codecs/tlv320aic3x.h
+++ b/sound/soc/codecs/tlv320aic3x.h
@@ -169,6 +169,7 @@
/* Audio serial data interface control register A bits */
#define BIT_CLK_MASTER 0x80
#define WORD_CLK_MASTER 0x40
+#define DOUT_TRISTATE 0x20
/* Codec Datapath setup register 7 */
#define FSREF_44100 (1 << 7)
diff --git a/sound/soc/codecs/tlv320dac33.c b/sound/soc/codecs/tlv320dac33.c
index e21ed93..0fe2ced 100644
--- a/sound/soc/codecs/tlv320dac33.c
+++ b/sound/soc/codecs/tlv320dac33.c
@@ -1436,8 +1436,6 @@ static int dac33_soc_remove(struct snd_soc_codec *codec)
{
struct tlv320dac33_priv *dac33 = snd_soc_codec_get_drvdata(codec);
- dac33_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
if (dac33->irq >= 0) {
free_irq(dac33->irq, dac33->codec);
destroy_workqueue(dac33->dac33_wq);
diff --git a/sound/soc/codecs/ts3a227e.c b/sound/soc/codecs/ts3a227e.c
new file mode 100644
index 0000000..1d12057
--- /dev/null
+++ b/sound/soc/codecs/ts3a227e.c
@@ -0,0 +1,314 @@
+/*
+ * TS3A227E Autonomous Audio Accessory Detection and Configuration Switch
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/gpio.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/of_gpio.h>
+#include <linux/regmap.h>
+
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/soc.h>
+
+struct ts3a227e {
+ struct regmap *regmap;
+ struct snd_soc_jack *jack;
+ bool plugged;
+ bool mic_present;
+ unsigned int buttons_held;
+};
+
+/* Button values to be reported on the jack */
+static const int ts3a227e_buttons[] = {
+ SND_JACK_BTN_0,
+ SND_JACK_BTN_1,
+ SND_JACK_BTN_2,
+ SND_JACK_BTN_3,
+};
+
+#define TS3A227E_NUM_BUTTONS 4
+#define TS3A227E_JACK_MASK (SND_JACK_HEADPHONE | \
+ SND_JACK_MICROPHONE | \
+ SND_JACK_BTN_0 | \
+ SND_JACK_BTN_1 | \
+ SND_JACK_BTN_2 | \
+ SND_JACK_BTN_3)
+
+/* TS3A227E registers */
+#define TS3A227E_REG_DEVICE_ID 0x00
+#define TS3A227E_REG_INTERRUPT 0x01
+#define TS3A227E_REG_KP_INTERRUPT 0x02
+#define TS3A227E_REG_INTERRUPT_DISABLE 0x03
+#define TS3A227E_REG_SETTING_1 0x04
+#define TS3A227E_REG_SETTING_2 0x05
+#define TS3A227E_REG_SETTING_3 0x06
+#define TS3A227E_REG_SWITCH_CONTROL_1 0x07
+#define TS3A227E_REG_SWITCH_CONTROL_2 0x08
+#define TS3A227E_REG_SWITCH_STATUS_1 0x09
+#define TS3A227E_REG_SWITCH_STATUS_2 0x0a
+#define TS3A227E_REG_ACCESSORY_STATUS 0x0b
+#define TS3A227E_REG_ADC_OUTPUT 0x0c
+#define TS3A227E_REG_KP_THRESHOLD_1 0x0d
+#define TS3A227E_REG_KP_THRESHOLD_2 0x0e
+#define TS3A227E_REG_KP_THRESHOLD_3 0x0f
+
+/* TS3A227E_REG_INTERRUPT 0x01 */
+#define INS_REM_EVENT 0x01
+#define DETECTION_COMPLETE_EVENT 0x02
+
+/* TS3A227E_REG_KP_INTERRUPT 0x02 */
+#define PRESS_MASK(idx) (0x01 << (2 * (idx)))
+#define RELEASE_MASK(idx) (0x02 << (2 * (idx)))
+
+/* TS3A227E_REG_INTERRUPT_DISABLE 0x03 */
+#define INS_REM_INT_DISABLE 0x01
+#define DETECTION_COMPLETE_INT_DISABLE 0x02
+#define ADC_COMPLETE_INT_DISABLE 0x04
+#define INTB_DISABLE 0x08
+
+/* TS3A227E_REG_SETTING_2 0x05 */
+#define KP_ENABLE 0x04
+
+/* TS3A227E_REG_ACCESSORY_STATUS 0x0b */
+#define TYPE_3_POLE 0x01
+#define TYPE_4_POLE_OMTP 0x02
+#define TYPE_4_POLE_STANDARD 0x04
+#define JACK_INSERTED 0x08
+#define EITHER_MIC_MASK (TYPE_4_POLE_OMTP | TYPE_4_POLE_STANDARD)
+
+static const struct reg_default ts3a227e_reg_defaults[] = {
+ { TS3A227E_REG_DEVICE_ID, 0x10 },
+ { TS3A227E_REG_INTERRUPT, 0x00 },
+ { TS3A227E_REG_KP_INTERRUPT, 0x00 },
+ { TS3A227E_REG_INTERRUPT_DISABLE, 0x08 },
+ { TS3A227E_REG_SETTING_1, 0x23 },
+ { TS3A227E_REG_SETTING_2, 0x00 },
+ { TS3A227E_REG_SETTING_3, 0x0e },
+ { TS3A227E_REG_SWITCH_CONTROL_1, 0x00 },
+ { TS3A227E_REG_SWITCH_CONTROL_2, 0x00 },
+ { TS3A227E_REG_SWITCH_STATUS_1, 0x0c },
+ { TS3A227E_REG_SWITCH_STATUS_2, 0x00 },
+ { TS3A227E_REG_ACCESSORY_STATUS, 0x00 },
+ { TS3A227E_REG_ADC_OUTPUT, 0x00 },
+ { TS3A227E_REG_KP_THRESHOLD_1, 0x20 },
+ { TS3A227E_REG_KP_THRESHOLD_2, 0x40 },
+ { TS3A227E_REG_KP_THRESHOLD_3, 0x68 },
+};
+
+static bool ts3a227e_readable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TS3A227E_REG_DEVICE_ID ... TS3A227E_REG_KP_THRESHOLD_3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool ts3a227e_writeable_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TS3A227E_REG_INTERRUPT_DISABLE ... TS3A227E_REG_SWITCH_CONTROL_2:
+ case TS3A227E_REG_KP_THRESHOLD_1 ... TS3A227E_REG_KP_THRESHOLD_3:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static bool ts3a227e_volatile_reg(struct device *dev, unsigned int reg)
+{
+ switch (reg) {
+ case TS3A227E_REG_INTERRUPT ... TS3A227E_REG_INTERRUPT_DISABLE:
+ case TS3A227E_REG_SETTING_2:
+ case TS3A227E_REG_SWITCH_STATUS_1 ... TS3A227E_REG_ADC_OUTPUT:
+ return true;
+ default:
+ return false;
+ }
+}
+
+static void ts3a227e_jack_report(struct ts3a227e *ts3a227e)
+{
+ unsigned int i;
+ int report = 0;
+
+ if (!ts3a227e->jack)
+ return;
+
+ if (ts3a227e->plugged)
+ report = SND_JACK_HEADPHONE;
+ if (ts3a227e->mic_present)
+ report |= SND_JACK_MICROPHONE;
+ for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
+ if (ts3a227e->buttons_held & (1 << i))
+ report |= ts3a227e_buttons[i];
+ }
+ snd_soc_jack_report(ts3a227e->jack, report, TS3A227E_JACK_MASK);
+}
+
+static void ts3a227e_new_jack_state(struct ts3a227e *ts3a227e, unsigned acc_reg)
+{
+ bool plugged, mic_present;
+
+ plugged = !!(acc_reg & JACK_INSERTED);
+ mic_present = plugged && !!(acc_reg & EITHER_MIC_MASK);
+
+ ts3a227e->plugged = plugged;
+
+ if (mic_present != ts3a227e->mic_present) {
+ ts3a227e->mic_present = mic_present;
+ ts3a227e->buttons_held = 0;
+ if (mic_present) {
+ /* Enable key press detection. */
+ regmap_update_bits(ts3a227e->regmap,
+ TS3A227E_REG_SETTING_2,
+ KP_ENABLE, KP_ENABLE);
+ }
+ }
+}
+
+static irqreturn_t ts3a227e_interrupt(int irq, void *data)
+{
+ struct ts3a227e *ts3a227e = (struct ts3a227e *)data;
+ struct regmap *regmap = ts3a227e->regmap;
+ unsigned int int_reg, kp_int_reg, acc_reg, i;
+
+ /* Check for plug/unplug. */
+ regmap_read(regmap, TS3A227E_REG_INTERRUPT, &int_reg);
+ if (int_reg & (DETECTION_COMPLETE_EVENT | INS_REM_EVENT)) {
+ regmap_read(regmap, TS3A227E_REG_ACCESSORY_STATUS, &acc_reg);
+ ts3a227e_new_jack_state(ts3a227e, acc_reg);
+ }
+
+ /* Report any key events. */
+ regmap_read(regmap, TS3A227E_REG_KP_INTERRUPT, &kp_int_reg);
+ for (i = 0; i < TS3A227E_NUM_BUTTONS; i++) {
+ if (kp_int_reg & PRESS_MASK(i))
+ ts3a227e->buttons_held |= (1 << i);
+ if (kp_int_reg & RELEASE_MASK(i))
+ ts3a227e->buttons_held &= ~(1 << i);
+ }
+
+ ts3a227e_jack_report(ts3a227e);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * ts3a227e_enable_jack_detect - Specify a jack for event reporting
+ *
+ * @component: component to register the jack with
+ * @jack: jack to use to report headset and button events on
+ *
+ * After this function has been called the headset insert/remove and button
+ * events 0-3 will be routed to the given jack. Jack can be null to stop
+ * reporting.
+ */
+int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack)
+{
+ struct ts3a227e *ts3a227e = snd_soc_component_get_drvdata(component);
+
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_0, KEY_MEDIA);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_1, KEY_VOLUMEUP);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_2, KEY_VOLUMEDOWN);
+ snd_jack_set_key(jack->jack, SND_JACK_BTN_3, KEY_VOICECOMMAND);
+
+ ts3a227e->jack = jack;
+ ts3a227e_jack_report(ts3a227e);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ts3a227e_enable_jack_detect);
+
+static struct snd_soc_component_driver ts3a227e_soc_driver;
+
+static const struct regmap_config ts3a227e_regmap_config = {
+ .val_bits = 8,
+ .reg_bits = 8,
+
+ .max_register = TS3A227E_REG_KP_THRESHOLD_3,
+ .readable_reg = ts3a227e_readable_reg,
+ .writeable_reg = ts3a227e_writeable_reg,
+ .volatile_reg = ts3a227e_volatile_reg,
+
+ .cache_type = REGCACHE_RBTREE,
+ .reg_defaults = ts3a227e_reg_defaults,
+ .num_reg_defaults = ARRAY_SIZE(ts3a227e_reg_defaults),
+};
+
+static int ts3a227e_i2c_probe(struct i2c_client *i2c,
+ const struct i2c_device_id *id)
+{
+ struct ts3a227e *ts3a227e;
+ struct device *dev = &i2c->dev;
+ int ret;
+
+ ts3a227e = devm_kzalloc(&i2c->dev, sizeof(*ts3a227e), GFP_KERNEL);
+ if (ts3a227e == NULL)
+ return -ENOMEM;
+
+ i2c_set_clientdata(i2c, ts3a227e);
+
+ ts3a227e->regmap = devm_regmap_init_i2c(i2c, &ts3a227e_regmap_config);
+ if (IS_ERR(ts3a227e->regmap))
+ return PTR_ERR(ts3a227e->regmap);
+
+ ret = devm_request_threaded_irq(dev, i2c->irq, NULL, ts3a227e_interrupt,
+ IRQF_TRIGGER_LOW | IRQF_ONESHOT,
+ "TS3A227E", ts3a227e);
+ if (ret) {
+ dev_err(dev, "Cannot request irq %d (%d)\n", i2c->irq, ret);
+ return ret;
+ }
+
+ ret = devm_snd_soc_register_component(&i2c->dev, &ts3a227e_soc_driver,
+ NULL, 0);
+ if (ret)
+ return ret;
+
+ /* Enable interrupts except for ADC complete. */
+ regmap_update_bits(ts3a227e->regmap, TS3A227E_REG_INTERRUPT_DISABLE,
+ INTB_DISABLE | ADC_COMPLETE_INT_DISABLE,
+ ADC_COMPLETE_INT_DISABLE);
+
+ return 0;
+}
+
+static const struct i2c_device_id ts3a227e_i2c_ids[] = {
+ { "ts3a227e", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ts3a227e_i2c_ids);
+
+static const struct of_device_id ts3a227e_of_match[] = {
+ { .compatible = "ti,ts3a227e", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, ts3a227e_of_match);
+
+static struct i2c_driver ts3a227e_driver = {
+ .driver = {
+ .name = "ts3a227e",
+ .owner = THIS_MODULE,
+ .of_match_table = of_match_ptr(ts3a227e_of_match),
+ },
+ .probe = ts3a227e_i2c_probe,
+ .id_table = ts3a227e_i2c_ids,
+};
+module_i2c_driver(ts3a227e_driver);
+
+MODULE_DESCRIPTION("ASoC ts3a227e driver");
+MODULE_AUTHOR("Dylan Reid <dgreid@chromium.org>");
+MODULE_LICENSE("GPL v2");
diff --git a/sound/soc/codecs/ts3a227e.h b/sound/soc/codecs/ts3a227e.h
new file mode 100644
index 0000000..e2acf9c
--- /dev/null
+++ b/sound/soc/codecs/ts3a227e.h
@@ -0,0 +1,17 @@
+/*
+ * TS3A227E Autonous Audio Accessory Detection and Configureation Switch
+ *
+ * Copyright (C) 2014 Google, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef _TS3A227E_H
+#define _TS3A227E_H
+
+int ts3a227e_enable_jack_detect(struct snd_soc_component *component,
+ struct snd_soc_jack *jack);
+
+#endif
diff --git a/sound/soc/codecs/twl4030.c b/sound/soc/codecs/twl4030.c
index b6b0cb3..27f3b21 100644
--- a/sound/soc/codecs/twl4030.c
+++ b/sound/soc/codecs/twl4030.c
@@ -2177,8 +2177,6 @@ static int twl4030_soc_remove(struct snd_soc_codec *codec)
struct twl4030_priv *twl4030 = snd_soc_codec_get_drvdata(codec);
struct twl4030_codec_data *pdata = twl4030->pdata;
- twl4030_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
if (pdata && pdata->hs_extmute && gpio_is_valid(pdata->hs_extmute_gpio))
gpio_free(pdata->hs_extmute_gpio);
diff --git a/sound/soc/codecs/twl6040.c b/sound/soc/codecs/twl6040.c
index 0f6067f..5ff2b1e 100644
--- a/sound/soc/codecs/twl6040.c
+++ b/sound/soc/codecs/twl6040.c
@@ -1095,25 +1095,6 @@ static struct snd_soc_dai_driver twl6040_dai[] = {
},
};
-#ifdef CONFIG_PM
-static int twl6040_suspend(struct snd_soc_codec *codec)
-{
- twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int twl6040_resume(struct snd_soc_codec *codec)
-{
- twl6040_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define twl6040_suspend NULL
-#define twl6040_resume NULL
-#endif
-
static int twl6040_probe(struct snd_soc_codec *codec)
{
struct twl6040_data *priv;
@@ -1160,7 +1141,6 @@ static int twl6040_remove(struct snd_soc_codec *codec)
struct twl6040_data *priv = snd_soc_codec_get_drvdata(codec);
free_irq(priv->plug_irq, codec);
- twl6040_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
@@ -1168,11 +1148,10 @@ static int twl6040_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_twl6040 = {
.probe = twl6040_probe,
.remove = twl6040_remove,
- .suspend = twl6040_suspend,
- .resume = twl6040_resume,
.read = twl6040_read,
.write = twl6040_write,
.set_bias_level = twl6040_set_bias_level,
+ .suspend_bias_off = true,
.ignore_pmdown_time = true,
.controls = twl6040_snd_controls,
diff --git a/sound/soc/codecs/uda134x.c b/sound/soc/codecs/uda134x.c
index 32b2f78..4056260 100644
--- a/sound/soc/codecs/uda134x.c
+++ b/sound/soc/codecs/uda134x.c
@@ -518,11 +518,6 @@ static int uda134x_soc_probe(struct snd_soc_codec *codec)
uda134x_reset(codec);
- if (pd->is_powered_on_standby)
- uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
- else
- uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
if (pd->model == UDA134X_UDA1341) {
widgets = uda1341_dapm_widgets;
num_widgets = ARRAY_SIZE(uda1341_dapm_widgets);
@@ -574,44 +569,21 @@ static int uda134x_soc_remove(struct snd_soc_codec *codec)
{
struct uda134x_priv *uda134x = snd_soc_codec_get_drvdata(codec);
- uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
kfree(uda134x);
return 0;
}
-#if defined(CONFIG_PM)
-static int uda134x_soc_suspend(struct snd_soc_codec *codec)
-{
- uda134x_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- uda134x_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int uda134x_soc_resume(struct snd_soc_codec *codec)
-{
- uda134x_set_bias_level(codec, SND_SOC_BIAS_PREPARE);
- uda134x_set_bias_level(codec, SND_SOC_BIAS_ON);
- return 0;
-}
-#else
-#define uda134x_soc_suspend NULL
-#define uda134x_soc_resume NULL
-#endif /* CONFIG_PM */
-
static struct snd_soc_codec_driver soc_codec_dev_uda134x = {
.probe = uda134x_soc_probe,
.remove = uda134x_soc_remove,
- .suspend = uda134x_soc_suspend,
- .resume = uda134x_soc_resume,
.reg_cache_size = sizeof(uda134x_reg),
.reg_word_size = sizeof(u8),
.reg_cache_default = uda134x_reg,
.reg_cache_step = 1,
.read = uda134x_read_reg_cache,
- .write = uda134x_write,
.set_bias_level = uda134x_set_bias_level,
+ .suspend_bias_off = true,
+
.dapm_widgets = uda134x_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(uda134x_dapm_widgets),
.dapm_routes = uda134x_dapm_routes,
diff --git a/sound/soc/codecs/uda1380.c b/sound/soc/codecs/uda1380.c
index e62e707..dc7778b 100644
--- a/sound/soc/codecs/uda1380.c
+++ b/sound/soc/codecs/uda1380.c
@@ -693,18 +693,6 @@ static struct snd_soc_dai_driver uda1380_dai[] = {
},
};
-static int uda1380_suspend(struct snd_soc_codec *codec)
-{
- uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int uda1380_resume(struct snd_soc_codec *codec)
-{
- uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int uda1380_probe(struct snd_soc_codec *codec)
{
struct uda1380_platform_data *pdata =codec->dev->platform_data;
@@ -739,8 +727,6 @@ static int uda1380_probe(struct snd_soc_codec *codec)
INIT_WORK(&uda1380->work, uda1380_flush_work);
- /* power on device */
- uda1380_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* set clock input */
switch (pdata->dac_clk) {
case UDA1380_DAC_CLK_SYSCLK:
@@ -766,8 +752,6 @@ static int uda1380_remove(struct snd_soc_codec *codec)
{
struct uda1380_platform_data *pdata =codec->dev->platform_data;
- uda1380_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
gpio_free(pdata->gpio_reset);
gpio_free(pdata->gpio_power);
@@ -777,11 +761,11 @@ static int uda1380_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_uda1380 = {
.probe = uda1380_probe,
.remove = uda1380_remove,
- .suspend = uda1380_suspend,
- .resume = uda1380_resume,
.read = uda1380_read_reg_cache,
.write = uda1380_write,
.set_bias_level = uda1380_set_bias_level,
+ .suspend_bias_off = true,
+
.reg_cache_size = ARRAY_SIZE(uda1380_reg),
.reg_word_size = sizeof(u16),
.reg_cache_default = uda1380_reg,
diff --git a/sound/soc/codecs/wl1273.c b/sound/soc/codecs/wl1273.c
index f3d4e88..00aea41 100644
--- a/sound/soc/codecs/wl1273.c
+++ b/sound/soc/codecs/wl1273.c
@@ -452,7 +452,6 @@ static int wl1273_probe(struct snd_soc_codec *codec)
{
struct wl1273_core **core = codec->dev->platform_data;
struct wl1273_priv *wl1273;
- int r;
dev_dbg(codec->dev, "%s.\n", __func__);
@@ -470,12 +469,7 @@ static int wl1273_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, wl1273);
- r = snd_soc_add_codec_controls(codec, wl1273_controls,
- ARRAY_SIZE(wl1273_controls));
- if (r)
- kfree(wl1273);
-
- return r;
+ return 0;
}
static int wl1273_remove(struct snd_soc_codec *codec)
@@ -492,6 +486,8 @@ static struct snd_soc_codec_driver soc_codec_dev_wl1273 = {
.probe = wl1273_probe,
.remove = wl1273_remove,
+ .controls = wl1273_controls,
+ .num_controls = ARRAY_SIZE(wl1273_controls),
.dapm_widgets = wl1273_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wl1273_dapm_widgets),
.dapm_routes = wl1273_dapm_routes,
diff --git a/sound/soc/codecs/wm5102.c b/sound/soc/codecs/wm5102.c
index f602349..d78fb8d 100644
--- a/sound/soc/codecs/wm5102.c
+++ b/sound/soc/codecs/wm5102.c
@@ -619,10 +619,10 @@ static int wm5102_out_comp_coeff_get(struct snd_kcontrol *kcontrol,
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
uint16_t data;
- mutex_lock(&codec->mutex);
+ mutex_lock(&arizona->dac_comp_lock);
data = cpu_to_be16(arizona->dac_comp_coeff);
memcpy(ucontrol->value.bytes.data, &data, sizeof(data));
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -633,11 +633,11 @@ static int wm5102_out_comp_coeff_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- mutex_lock(&codec->mutex);
+ mutex_lock(&arizona->dac_comp_lock);
memcpy(&arizona->dac_comp_coeff, ucontrol->value.bytes.data,
sizeof(arizona->dac_comp_coeff));
arizona->dac_comp_coeff = be16_to_cpu(arizona->dac_comp_coeff);
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -648,9 +648,9 @@ static int wm5102_out_comp_switch_get(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- mutex_lock(&codec->mutex);
+ mutex_lock(&arizona->dac_comp_lock);
ucontrol->value.integer.value[0] = arizona->dac_comp_enabled;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -661,9 +661,9 @@ static int wm5102_out_comp_switch_put(struct snd_kcontrol *kcontrol,
struct snd_soc_codec *codec = snd_soc_kcontrol_codec(kcontrol);
struct arizona *arizona = dev_get_drvdata(codec->dev->parent);
- mutex_lock(&codec->mutex);
+ mutex_lock(&arizona->dac_comp_lock);
arizona->dac_comp_enabled = ucontrol->value.integer.value[0];
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&arizona->dac_comp_lock);
return 0;
}
@@ -1900,6 +1900,8 @@ static int wm5102_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm5102);
+ mutex_init(&arizona->dac_comp_lock);
+
wm5102->core.arizona = arizona;
wm5102->core.num_inputs = 6;
diff --git a/sound/soc/codecs/wm8350.c b/sound/soc/codecs/wm8350.c
index 628ec77..87f664b 100644
--- a/sound/soc/codecs/wm8350.c
+++ b/sound/soc/codecs/wm8350.c
@@ -1242,19 +1242,6 @@ static int wm8350_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm8350_suspend(struct snd_soc_codec *codec)
-{
- wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8350_resume(struct snd_soc_codec *codec)
-{
- wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
static void wm8350_hp_work(struct wm8350_data *priv,
struct wm8350_jack_data *jack,
u16 mask)
@@ -1565,9 +1552,6 @@ static int wm8350_codec_probe(struct snd_soc_codec *codec)
wm8350_register_irq(wm8350, WM8350_IRQ_CODEC_MICD,
wm8350_mic_handler, 0, "Microphone detect", priv);
-
- wm8350_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
@@ -1596,8 +1580,6 @@ static int wm8350_codec_remove(struct snd_soc_codec *codec)
* wait for its completion */
flush_delayed_work(&codec->dapm.delayed_work);
- wm8350_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
wm8350_clear_bits(wm8350, WM8350_POWER_MGMT_5, WM8350_CODEC_ENA);
return 0;
@@ -1613,10 +1595,9 @@ static struct regmap *wm8350_get_regmap(struct device *dev)
static struct snd_soc_codec_driver soc_codec_dev_wm8350 = {
.probe = wm8350_codec_probe,
.remove = wm8350_codec_remove,
- .suspend = wm8350_suspend,
- .resume = wm8350_resume,
.get_regmap = wm8350_get_regmap,
.set_bias_level = wm8350_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8350_snd_controls,
.num_controls = ARRAY_SIZE(wm8350_snd_controls),
diff --git a/sound/soc/codecs/wm8400.c b/sound/soc/codecs/wm8400.c
index 72471be..385894f 100644
--- a/sound/soc/codecs/wm8400.c
+++ b/sound/soc/codecs/wm8400.c
@@ -58,12 +58,10 @@ static struct regulator_bulk_data power[] = {
/* codec private data */
struct wm8400_priv {
- struct snd_soc_codec *codec;
struct wm8400 *wm8400;
u16 fake_register;
unsigned int sysclk;
unsigned int pcmclk;
- struct work_struct work;
int fll_in, fll_out;
};
@@ -1278,30 +1276,6 @@ static struct snd_soc_dai_driver wm8400_dai = {
.ops = &wm8400_dai_ops,
};
-static int wm8400_suspend(struct snd_soc_codec *codec)
-{
- wm8400_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8400_resume(struct snd_soc_codec *codec)
-{
- wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static void wm8400_probe_deferred(struct work_struct *work)
-{
- struct wm8400_priv *priv = container_of(work, struct wm8400_priv,
- work);
- struct snd_soc_codec *codec = priv->codec;
-
- /* charge output caps */
- wm8400_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-}
-
static int wm8400_codec_probe(struct snd_soc_codec *codec)
{
struct wm8400 *wm8400 = dev_get_platdata(codec->dev);
@@ -1316,7 +1290,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
snd_soc_codec_set_drvdata(codec, priv);
priv->wm8400 = wm8400;
- priv->codec = codec;
ret = devm_regulator_bulk_get(wm8400->dev,
ARRAY_SIZE(power), &power[0]);
@@ -1325,8 +1298,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
return ret;
}
- INIT_WORK(&priv->work, wm8400_probe_deferred);
-
wm8400_codec_reset(codec);
reg = snd_soc_read(codec, WM8400_POWER_MANAGEMENT_1);
@@ -1343,8 +1314,6 @@ static int wm8400_codec_probe(struct snd_soc_codec *codec)
snd_soc_write(codec, WM8400_LEFT_OUTPUT_VOLUME, 0x50 | (1<<8));
snd_soc_write(codec, WM8400_RIGHT_OUTPUT_VOLUME, 0x50 | (1<<8));
- if (!schedule_work(&priv->work))
- return -EINVAL;
return 0;
}
@@ -1369,10 +1338,9 @@ static struct regmap *wm8400_get_regmap(struct device *dev)
static struct snd_soc_codec_driver soc_codec_dev_wm8400 = {
.probe = wm8400_codec_probe,
.remove = wm8400_codec_remove,
- .suspend = wm8400_suspend,
- .resume = wm8400_resume,
.get_regmap = wm8400_get_regmap,
.set_bias_level = wm8400_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8400_snd_controls,
.num_controls = ARRAY_SIZE(wm8400_snd_controls),
diff --git a/sound/soc/codecs/wm8510.c b/sound/soc/codecs/wm8510.c
index e11127f..8736ad0 100644
--- a/sound/soc/codecs/wm8510.c
+++ b/sound/soc/codecs/wm8510.c
@@ -575,41 +575,17 @@ static struct snd_soc_dai_driver wm8510_dai = {
.symmetric_rates = 1,
};
-static int wm8510_suspend(struct snd_soc_codec *codec)
-{
- wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8510_resume(struct snd_soc_codec *codec)
-{
- wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int wm8510_probe(struct snd_soc_codec *codec)
{
wm8510_reset(codec);
- /* power on device */
- wm8510_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-/* power down chip */
-static int wm8510_remove(struct snd_soc_codec *codec)
-{
- wm8510_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8510 = {
.probe = wm8510_probe,
- .remove = wm8510_remove,
- .suspend = wm8510_suspend,
- .resume = wm8510_resume,
.set_bias_level = wm8510_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8510_snd_controls,
.num_controls = ARRAY_SIZE(wm8510_snd_controls),
diff --git a/sound/soc/codecs/wm8523.c b/sound/soc/codecs/wm8523.c
index ec1f574..b1cc94f 100644
--- a/sound/soc/codecs/wm8523.c
+++ b/sound/soc/codecs/wm8523.c
@@ -372,23 +372,6 @@ static struct snd_soc_dai_driver wm8523_dai = {
.ops = &wm8523_dai_ops,
};
-#ifdef CONFIG_PM
-static int wm8523_suspend(struct snd_soc_codec *codec)
-{
- wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8523_resume(struct snd_soc_codec *codec)
-{
- wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8523_suspend NULL
-#define wm8523_resume NULL
-#endif
-
static int wm8523_probe(struct snd_soc_codec *codec)
{
struct wm8523_priv *wm8523 = snd_soc_codec_get_drvdata(codec);
@@ -402,23 +385,13 @@ static int wm8523_probe(struct snd_soc_codec *codec)
WM8523_DACR_VU, WM8523_DACR_VU);
snd_soc_update_bits(codec, WM8523_DAC_CTRL3, WM8523_ZC, WM8523_ZC);
- wm8523_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int wm8523_remove(struct snd_soc_codec *codec)
-{
- wm8523_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8523 = {
.probe = wm8523_probe,
- .remove = wm8523_remove,
- .suspend = wm8523_suspend,
- .resume = wm8523_resume,
.set_bias_level = wm8523_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8523_controls,
.num_controls = ARRAY_SIZE(wm8523_controls),
diff --git a/sound/soc/codecs/wm8580.c b/sound/soc/codecs/wm8580.c
index 911605e..0a887c5 100644
--- a/sound/soc/codecs/wm8580.c
+++ b/sound/soc/codecs/wm8580.c
@@ -882,8 +882,6 @@ static int wm8580_probe(struct snd_soc_codec *codec)
goto err_regulator_enable;
}
- wm8580_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
err_regulator_enable:
@@ -897,8 +895,6 @@ static int wm8580_remove(struct snd_soc_codec *codec)
{
struct wm8580_priv *wm8580 = snd_soc_codec_get_drvdata(codec);
- wm8580_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
regulator_bulk_disable(ARRAY_SIZE(wm8580->supplies), wm8580->supplies);
return 0;
diff --git a/sound/soc/codecs/wm8711.c b/sound/soc/codecs/wm8711.c
index 32187e7..121e46d 100644
--- a/sound/soc/codecs/wm8711.c
+++ b/sound/soc/codecs/wm8711.c
@@ -350,19 +350,6 @@ static struct snd_soc_dai_driver wm8711_dai = {
.ops = &wm8711_ops,
};
-static int wm8711_suspend(struct snd_soc_codec *codec)
-{
- snd_soc_write(codec, WM8711_ACTIVE, 0x0);
- wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8711_resume(struct snd_soc_codec *codec)
-{
- wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int wm8711_probe(struct snd_soc_codec *codec)
{
int ret;
@@ -373,8 +360,6 @@ static int wm8711_probe(struct snd_soc_codec *codec)
return ret;
}
- wm8711_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/* Latch the update bits */
snd_soc_update_bits(codec, WM8711_LOUT1V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8711_ROUT1V, 0x0100, 0x0100);
@@ -383,19 +368,11 @@ static int wm8711_probe(struct snd_soc_codec *codec)
}
-/* power down chip */
-static int wm8711_remove(struct snd_soc_codec *codec)
-{
- wm8711_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8711 = {
.probe = wm8711_probe,
- .remove = wm8711_remove,
- .suspend = wm8711_suspend,
- .resume = wm8711_resume,
.set_bias_level = wm8711_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = wm8711_snd_controls,
.num_controls = ARRAY_SIZE(wm8711_snd_controls),
.dapm_widgets = wm8711_dapm_widgets,
diff --git a/sound/soc/codecs/wm8728.c b/sound/soc/codecs/wm8728.c
index 38ff826..55c7fb4 100644
--- a/sound/soc/codecs/wm8728.c
+++ b/sound/soc/codecs/wm8728.c
@@ -212,40 +212,10 @@ static struct snd_soc_dai_driver wm8728_dai = {
.ops = &wm8728_dai_ops,
};
-static int wm8728_suspend(struct snd_soc_codec *codec)
-{
- wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8728_resume(struct snd_soc_codec *codec)
-{
- wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int wm8728_probe(struct snd_soc_codec *codec)
-{
- /* power on device */
- wm8728_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int wm8728_remove(struct snd_soc_codec *codec)
-{
- wm8728_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8728 = {
- .probe = wm8728_probe,
- .remove = wm8728_remove,
- .suspend = wm8728_suspend,
- .resume = wm8728_resume,
.set_bias_level = wm8728_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = wm8728_snd_controls,
.num_controls = ARRAY_SIZE(wm8728_snd_controls),
.dapm_widgets = wm8728_dapm_widgets,
diff --git a/sound/soc/codecs/wm8731.c b/sound/soc/codecs/wm8731.c
index eebb328..b9211b4 100644
--- a/sound/soc/codecs/wm8731.c
+++ b/sound/soc/codecs/wm8731.c
@@ -24,6 +24,7 @@
#include <linux/regulator/consumer.h>
#include <linux/spi/spi.h>
#include <linux/of_device.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/pcm_params.h>
@@ -50,6 +51,8 @@ struct wm8731_priv {
int sysclk_type;
int playback_fs;
bool deemph;
+
+ struct mutex lock;
};
@@ -138,7 +141,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
if (deemph > 1)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ mutex_lock(&wm8731->lock);
if (wm8731->deemph != deemph) {
wm8731->deemph = deemph;
@@ -146,7 +149,7 @@ static int wm8731_put_deemph(struct snd_kcontrol *kcontrol,
ret = 1;
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&wm8731->lock);
return ret;
}
@@ -559,25 +562,6 @@ static struct snd_soc_dai_driver wm8731_dai = {
.symmetric_rates = 1,
};
-#ifdef CONFIG_PM
-static int wm8731_suspend(struct snd_soc_codec *codec)
-{
- wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8731_resume(struct snd_soc_codec *codec)
-{
- wm8731_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define wm8731_suspend NULL
-#define wm8731_resume NULL
-#endif
-
static int wm8731_probe(struct snd_soc_codec *codec)
{
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
@@ -633,8 +617,6 @@ static int wm8731_remove(struct snd_soc_codec *codec)
{
struct wm8731_priv *wm8731 = snd_soc_codec_get_drvdata(codec);
- wm8731_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
regulator_bulk_disable(ARRAY_SIZE(wm8731->supplies), wm8731->supplies);
return 0;
@@ -643,9 +625,9 @@ static int wm8731_remove(struct snd_soc_codec *codec)
static struct snd_soc_codec_driver soc_codec_dev_wm8731 = {
.probe = wm8731_probe,
.remove = wm8731_remove,
- .suspend = wm8731_suspend,
- .resume = wm8731_resume,
.set_bias_level = wm8731_set_bias_level,
+ .suspend_bias_off = true,
+
.dapm_widgets = wm8731_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm8731_dapm_widgets),
.dapm_routes = wm8731_intercon,
@@ -680,11 +662,12 @@ static int wm8731_spi_probe(struct spi_device *spi)
struct wm8731_priv *wm8731;
int ret;
- wm8731 = devm_kzalloc(&spi->dev, sizeof(struct wm8731_priv),
- GFP_KERNEL);
+ wm8731 = devm_kzalloc(&spi->dev, sizeof(*wm8731), GFP_KERNEL);
if (wm8731 == NULL)
return -ENOMEM;
+ mutex_init(&wm8731->lock);
+
wm8731->regmap = devm_regmap_init_spi(spi, &wm8731_regmap);
if (IS_ERR(wm8731->regmap)) {
ret = PTR_ERR(wm8731->regmap);
diff --git a/sound/soc/codecs/wm8737.c b/sound/soc/codecs/wm8737.c
index 744a422..ada9ac1 100644
--- a/sound/soc/codecs/wm8737.c
+++ b/sound/soc/codecs/wm8737.c
@@ -277,17 +277,6 @@ static const struct snd_soc_dapm_route intercon[] = {
{ "AIF", NULL, "ADCR" },
};
-static int wm8737_add_widgets(struct snd_soc_codec *codec)
-{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
-
- snd_soc_dapm_new_controls(dapm, wm8737_dapm_widgets,
- ARRAY_SIZE(wm8737_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, intercon, ARRAY_SIZE(intercon));
-
- return 0;
-}
-
/* codec mclk clock divider coefficients */
static const struct {
u32 mclk;
@@ -548,23 +537,6 @@ static struct snd_soc_dai_driver wm8737_dai = {
.ops = &wm8737_dai_ops,
};
-#ifdef CONFIG_PM
-static int wm8737_suspend(struct snd_soc_codec *codec)
-{
- wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8737_resume(struct snd_soc_codec *codec)
-{
- wm8737_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8737_suspend NULL
-#define wm8737_resume NULL
-#endif
-
static int wm8737_probe(struct snd_soc_codec *codec)
{
struct wm8737_priv *wm8737 = snd_soc_codec_get_drvdata(codec);
@@ -593,10 +565,6 @@ static int wm8737_probe(struct snd_soc_codec *codec)
/* Bias level configuration will have done an extra enable */
regulator_bulk_disable(ARRAY_SIZE(wm8737->supplies), wm8737->supplies);
- snd_soc_add_codec_controls(codec, wm8737_snd_controls,
- ARRAY_SIZE(wm8737_snd_controls));
- wm8737_add_widgets(codec);
-
return 0;
err_enable:
@@ -605,18 +573,17 @@ err_get:
return ret;
}
-static int wm8737_remove(struct snd_soc_codec *codec)
-{
- wm8737_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8737 = {
.probe = wm8737_probe,
- .remove = wm8737_remove,
- .suspend = wm8737_suspend,
- .resume = wm8737_resume,
.set_bias_level = wm8737_set_bias_level,
+ .suspend_bias_off = true,
+
+ .controls = wm8737_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8737_snd_controls),
+ .dapm_widgets = wm8737_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8737_dapm_widgets),
+ .dapm_routes = intercon,
+ .num_dapm_routes = ARRAY_SIZE(intercon),
};
static const struct of_device_id wm8737_of_match[] = {
diff --git a/sound/soc/codecs/wm8750.c b/sound/soc/codecs/wm8750.c
index 67653a2..f6847fd 100644
--- a/sound/soc/codecs/wm8750.c
+++ b/sound/soc/codecs/wm8750.c
@@ -686,18 +686,6 @@ static struct snd_soc_dai_driver wm8750_dai = {
.ops = &wm8750_dai_ops,
};
-static int wm8750_suspend(struct snd_soc_codec *codec)
-{
- wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8750_resume(struct snd_soc_codec *codec)
-{
- wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int wm8750_probe(struct snd_soc_codec *codec)
{
int ret;
@@ -708,9 +696,6 @@ static int wm8750_probe(struct snd_soc_codec *codec)
return ret;
}
- /* charge output caps */
- wm8750_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/* set the update bits */
snd_soc_update_bits(codec, WM8750_LDAC, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8750_RDAC, 0x0100, 0x0100);
@@ -724,18 +709,10 @@ static int wm8750_probe(struct snd_soc_codec *codec)
return ret;
}
-static int wm8750_remove(struct snd_soc_codec *codec)
-{
- wm8750_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8750 = {
.probe = wm8750_probe,
- .remove = wm8750_remove,
- .suspend = wm8750_suspend,
- .resume = wm8750_resume,
.set_bias_level = wm8750_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8750_snd_controls,
.num_controls = ARRAY_SIZE(wm8750_snd_controls),
diff --git a/sound/soc/codecs/wm8776.c b/sound/soc/codecs/wm8776.c
index 70952ce..c13050b 100644
--- a/sound/soc/codecs/wm8776.c
+++ b/sound/soc/codecs/wm8776.c
@@ -408,24 +408,6 @@ static struct snd_soc_dai_driver wm8776_dai[] = {
},
};
-#ifdef CONFIG_PM
-static int wm8776_suspend(struct snd_soc_codec *codec)
-{
- wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm8776_resume(struct snd_soc_codec *codec)
-{
- wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8776_suspend NULL
-#define wm8776_resume NULL
-#endif
-
static int wm8776_probe(struct snd_soc_codec *codec)
{
int ret = 0;
@@ -436,8 +418,6 @@ static int wm8776_probe(struct snd_soc_codec *codec)
return ret;
}
- wm8776_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/* Latch the update bits; right channel only since we always
* update both. */
snd_soc_update_bits(codec, WM8776_HPRVOL, 0x100, 0x100);
@@ -446,19 +426,10 @@ static int wm8776_probe(struct snd_soc_codec *codec)
return ret;
}
-/* power down chip */
-static int wm8776_remove(struct snd_soc_codec *codec)
-{
- wm8776_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8776 = {
.probe = wm8776_probe,
- .remove = wm8776_remove,
- .suspend = wm8776_suspend,
- .resume = wm8776_resume,
.set_bias_level = wm8776_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8776_snd_controls,
.num_controls = ARRAY_SIZE(wm8776_snd_controls),
diff --git a/sound/soc/codecs/wm8804.c b/sound/soc/codecs/wm8804.c
index 3addc5f..1315f76 100644
--- a/sound/soc/codecs/wm8804.c
+++ b/sound/soc/codecs/wm8804.c
@@ -524,7 +524,6 @@ static int wm8804_remove(struct snd_soc_codec *codec)
int i;
wm8804 = snd_soc_codec_get_drvdata(codec);
- wm8804_set_bias_level(codec, SND_SOC_BIAS_OFF);
for (i = 0; i < ARRAY_SIZE(wm8804->supplies); ++i)
regulator_unregister_notifier(wm8804->supplies[i].consumer,
@@ -606,8 +605,6 @@ static int wm8804_probe(struct snd_soc_codec *codec)
goto err_reg_enable;
}
- wm8804_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
err_reg_enable:
diff --git a/sound/soc/codecs/wm8900.c b/sound/soc/codecs/wm8900.c
index 44a5f15..3a0d4b7 100644
--- a/sound/soc/codecs/wm8900.c
+++ b/sound/soc/codecs/wm8900.c
@@ -1209,16 +1209,8 @@ static int wm8900_probe(struct snd_soc_codec *codec)
return 0;
}
-/* power down chip */
-static int wm8900_remove(struct snd_soc_codec *codec)
-{
- wm8900_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8900 = {
.probe = wm8900_probe,
- .remove = wm8900_remove,
.suspend = wm8900_suspend,
.resume = wm8900_resume,
.set_bias_level = wm8900_set_bias_level,
diff --git a/sound/soc/codecs/wm8903.c b/sound/soc/codecs/wm8903.c
index c038b3e..cc6b0ef 100644
--- a/sound/soc/codecs/wm8903.c
+++ b/sound/soc/codecs/wm8903.c
@@ -26,6 +26,7 @@
#include <linux/regmap.h>
#include <linux/slab.h>
#include <linux/irq.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -117,12 +118,12 @@ static const struct reg_default wm8903_reg_defaults[] = {
struct wm8903_priv {
struct wm8903_platform_data *pdata;
struct device *dev;
- struct snd_soc_codec *codec;
struct regmap *regmap;
int sysclk;
int irq;
+ struct mutex lock;
int fs;
int deemph;
@@ -457,7 +458,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
if (deemph > 1)
return -EINVAL;
- mutex_lock(&codec->mutex);
+ mutex_lock(&wm8903->lock);
if (wm8903->deemph != deemph) {
wm8903->deemph = deemph;
@@ -465,7 +466,7 @@ static int wm8903_put_deemph(struct snd_kcontrol *kcontrol,
ret = 1;
}
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&wm8903->lock);
return ret;
}
@@ -1757,21 +1758,12 @@ static struct snd_soc_dai_driver wm8903_dai = {
.symmetric_rates = 1,
};
-static int wm8903_suspend(struct snd_soc_codec *codec)
-{
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
static int wm8903_resume(struct snd_soc_codec *codec)
{
struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
regcache_sync(wm8903->regmap);
- wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
@@ -1889,33 +1881,12 @@ static void wm8903_free_gpio(struct wm8903_priv *wm8903)
}
#endif
-static int wm8903_probe(struct snd_soc_codec *codec)
-{
- struct wm8903_priv *wm8903 = snd_soc_codec_get_drvdata(codec);
-
- wm8903->codec = codec;
-
- /* power on device */
- wm8903_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-/* power down chip */
-static int wm8903_remove(struct snd_soc_codec *codec)
-{
- wm8903_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8903 = {
- .probe = wm8903_probe,
- .remove = wm8903_remove,
- .suspend = wm8903_suspend,
.resume = wm8903_resume,
.set_bias_level = wm8903_set_bias_level,
.seq_notifier = wm8903_seq_notifier,
+ .suspend_bias_off = true,
+
.controls = wm8903_snd_controls,
.num_controls = ARRAY_SIZE(wm8903_snd_controls),
.dapm_widgets = wm8903_dapm_widgets,
@@ -2023,6 +1994,8 @@ static int wm8903_i2c_probe(struct i2c_client *i2c,
GFP_KERNEL);
if (wm8903 == NULL)
return -ENOMEM;
+
+ mutex_init(&wm8903->lock);
wm8903->dev = &i2c->dev;
wm8903->regmap = devm_regmap_init_i2c(i2c, &wm8903_regmap);
diff --git a/sound/soc/codecs/wm8940.c b/sound/soc/codecs/wm8940.c
index 5201104..e4142b4 100644
--- a/sound/soc/codecs/wm8940.c
+++ b/sound/soc/codecs/wm8940.c
@@ -695,17 +695,6 @@ static struct snd_soc_dai_driver wm8940_dai = {
.symmetric_rates = 1,
};
-static int wm8940_suspend(struct snd_soc_codec *codec)
-{
- return wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
-}
-
-static int wm8940_resume(struct snd_soc_codec *codec)
-{
- wm8940_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int wm8940_probe(struct snd_soc_codec *codec)
{
struct wm8940_setup_data *pdata = codec->dev->platform_data;
@@ -736,18 +725,11 @@ static int wm8940_probe(struct snd_soc_codec *codec)
return ret;
}
-static int wm8940_remove(struct snd_soc_codec *codec)
-{
- wm8940_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8940 = {
.probe = wm8940_probe,
- .remove = wm8940_remove,
- .suspend = wm8940_suspend,
- .resume = wm8940_resume,
.set_bias_level = wm8940_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = wm8940_snd_controls,
.num_controls = ARRAY_SIZE(wm8940_snd_controls),
.dapm_widgets = wm8940_dapm_widgets,
diff --git a/sound/soc/codecs/wm8955.c b/sound/soc/codecs/wm8955.c
index 09d91d9..1173f7f 100644
--- a/sound/soc/codecs/wm8955.c
+++ b/sound/soc/codecs/wm8955.c
@@ -866,29 +866,6 @@ static struct snd_soc_dai_driver wm8955_dai = {
.ops = &wm8955_dai_ops,
};
-#ifdef CONFIG_PM
-static int wm8955_suspend(struct snd_soc_codec *codec)
-{
- struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
-
- wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- regcache_mark_dirty(wm8955->regmap);
-
- return 0;
-}
-
-static int wm8955_resume(struct snd_soc_codec *codec)
-{
- wm8955_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define wm8955_suspend NULL
-#define wm8955_resume NULL
-#endif
-
static int wm8955_probe(struct snd_soc_codec *codec)
{
struct wm8955_priv *wm8955 = snd_soc_codec_get_drvdata(codec);
@@ -964,18 +941,10 @@ err_enable:
return ret;
}
-static int wm8955_remove(struct snd_soc_codec *codec)
-{
- wm8955_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8955 = {
.probe = wm8955_probe,
- .remove = wm8955_remove,
- .suspend = wm8955_suspend,
- .resume = wm8955_resume,
.set_bias_level = wm8955_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8955_snd_controls,
.num_controls = ARRAY_SIZE(wm8955_snd_controls),
diff --git a/sound/soc/codecs/wm8958-dsp2.c b/sound/soc/codecs/wm8958-dsp2.c
index 0dada7f..3cbc82b 100644
--- a/sound/soc/codecs/wm8958-dsp2.c
+++ b/sound/soc/codecs/wm8958-dsp2.c
@@ -867,9 +867,9 @@ static void wm8958_enh_eq_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (fw && (wm8958_dsp2_fw(codec, "ENH_EQ", fw, true) == 0)) {
- mutex_lock(&codec->mutex);
+ mutex_lock(&wm8994->fw_lock);
wm8994->enh_eq = fw;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&wm8994->fw_lock);
}
}
@@ -879,9 +879,9 @@ static void wm8958_mbc_vss_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (fw && (wm8958_dsp2_fw(codec, "MBC+VSS", fw, true) == 0)) {
- mutex_lock(&codec->mutex);
+ mutex_lock(&wm8994->fw_lock);
wm8994->mbc_vss = fw;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&wm8994->fw_lock);
}
}
@@ -891,9 +891,9 @@ static void wm8958_mbc_loaded(const struct firmware *fw, void *context)
struct wm8994_priv *wm8994 = snd_soc_codec_get_drvdata(codec);
if (fw && (wm8958_dsp2_fw(codec, "MBC", fw, true) == 0)) {
- mutex_lock(&codec->mutex);
+ mutex_lock(&wm8994->fw_lock);
wm8994->mbc = fw;
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&wm8994->fw_lock);
}
}
diff --git a/sound/soc/codecs/wm8960.c b/sound/soc/codecs/wm8960.c
index 4dc4e85..031a1ae 100644
--- a/sound/soc/codecs/wm8960.c
+++ b/sound/soc/codecs/wm8960.c
@@ -125,9 +125,10 @@ struct wm8960_priv {
struct snd_soc_dapm_widget *out3;
bool deemph;
int playback_fs;
+ struct wm8960_data pdata;
};
-#define wm8960_reset(c) snd_soc_write(c, WM8960_RESET, 0)
+#define wm8960_reset(c) regmap_write(c, WM8960_RESET, 0)
/* enumerated controls */
static const char *wm8960_polarity[] = {"No Inversion", "Left Inverted",
@@ -440,8 +441,8 @@ static const struct snd_soc_dapm_route audio_paths_capless[] = {
static int wm8960_add_widgets(struct snd_soc_codec *codec)
{
- struct wm8960_data *pdata = codec->dev->platform_data;
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
+ struct wm8960_data *pdata = &wm8960->pdata;
struct snd_soc_dapm_context *dapm = &codec->dapm;
struct snd_soc_dapm_widget *w;
@@ -942,56 +943,15 @@ static struct snd_soc_dai_driver wm8960_dai = {
.symmetric_rates = 1,
};
-static int wm8960_suspend(struct snd_soc_codec *codec)
-{
- struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-
- wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8960_resume(struct snd_soc_codec *codec)
-{
- struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-
- wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int wm8960_probe(struct snd_soc_codec *codec)
{
struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
- struct wm8960_data *pdata = dev_get_platdata(codec->dev);
- int ret;
-
- wm8960->set_bias_level = wm8960_set_bias_level_out3;
-
- if (!pdata) {
- dev_warn(codec->dev, "No platform data supplied\n");
- } else {
- if (pdata->capless)
- wm8960->set_bias_level = wm8960_set_bias_level_capless;
- }
-
- ret = wm8960_reset(codec);
- if (ret < 0) {
- dev_err(codec->dev, "Failed to issue reset\n");
- return ret;
- }
-
- wm8960->set_bias_level(codec, SND_SOC_BIAS_STANDBY);
+ struct wm8960_data *pdata = &wm8960->pdata;
- /* Latch the update bits */
- snd_soc_update_bits(codec, WM8960_LINVOL, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_RINVOL, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_LADC, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_RADC, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_LDAC, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_RDAC, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_LOUT1, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_ROUT1, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_LOUT2, 0x100, 0x100);
- snd_soc_update_bits(codec, WM8960_ROUT2, 0x100, 0x100);
+ if (pdata->capless)
+ wm8960->set_bias_level = wm8960_set_bias_level_capless;
+ else
+ wm8960->set_bias_level = wm8960_set_bias_level_out3;
snd_soc_add_codec_controls(codec, wm8960_snd_controls,
ARRAY_SIZE(wm8960_snd_controls));
@@ -1000,21 +960,10 @@ static int wm8960_probe(struct snd_soc_codec *codec)
return 0;
}
-/* power down chip */
-static int wm8960_remove(struct snd_soc_codec *codec)
-{
- struct wm8960_priv *wm8960 = snd_soc_codec_get_drvdata(codec);
-
- wm8960->set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8960 = {
.probe = wm8960_probe,
- .remove = wm8960_remove,
- .suspend = wm8960_suspend,
- .resume = wm8960_resume,
.set_bias_level = wm8960_set_bias_level,
+ .suspend_bias_off = true,
};
static const struct regmap_config wm8960_regmap = {
@@ -1029,6 +978,18 @@ static const struct regmap_config wm8960_regmap = {
.volatile_reg = wm8960_volatile,
};
+static void wm8960_set_pdata_from_of(struct i2c_client *i2c,
+ struct wm8960_data *pdata)
+{
+ const struct device_node *np = i2c->dev.of_node;
+
+ if (of_property_read_bool(np, "wlf,capless"))
+ pdata->capless = true;
+
+ if (of_property_read_bool(np, "wlf,shared-lrclk"))
+ pdata->shared_lrclk = true;
+}
+
static int wm8960_i2c_probe(struct i2c_client *i2c,
const struct i2c_device_id *id)
{
@@ -1045,7 +1006,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
if (IS_ERR(wm8960->regmap))
return PTR_ERR(wm8960->regmap);
- if (pdata && pdata->shared_lrclk) {
+ if (pdata)
+ memcpy(&wm8960->pdata, pdata, sizeof(struct wm8960_data));
+ else if (i2c->dev.of_node)
+ wm8960_set_pdata_from_of(i2c, &wm8960->pdata);
+
+ ret = wm8960_reset(wm8960->regmap);
+ if (ret != 0) {
+ dev_err(&i2c->dev, "Failed to issue reset\n");
+ return ret;
+ }
+
+ if (wm8960->pdata.shared_lrclk) {
ret = regmap_update_bits(wm8960->regmap, WM8960_ADDCTL2,
0x4, 0x4);
if (ret != 0) {
@@ -1055,6 +1027,18 @@ static int wm8960_i2c_probe(struct i2c_client *i2c,
}
}
+ /* Latch the update bits */
+ regmap_update_bits(wm8960->regmap, WM8960_LINVOL, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_RINVOL, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LADC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_RADC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LDAC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_RDAC, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LOUT1, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_ROUT1, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_LOUT2, 0x100, 0x100);
+ regmap_update_bits(wm8960->regmap, WM8960_ROUT2, 0x100, 0x100);
+
i2c_set_clientdata(i2c, wm8960);
ret = snd_soc_register_codec(&i2c->dev,
@@ -1075,10 +1059,17 @@ static const struct i2c_device_id wm8960_i2c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8960_i2c_id);
+static const struct of_device_id wm8960_of_match[] = {
+ { .compatible = "wlf,wm8960", },
+ { }
+};
+MODULE_DEVICE_TABLE(of, wm8960_of_match);
+
static struct i2c_driver wm8960_i2c_driver = {
.driver = {
.name = "wm8960",
.owner = THIS_MODULE,
+ .of_match_table = wm8960_of_match,
},
.probe = wm8960_i2c_probe,
.remove = wm8960_i2c_remove,
diff --git a/sound/soc/codecs/wm8961.c b/sound/soc/codecs/wm8961.c
index 41d23e9..eeffd05 100644
--- a/sound/soc/codecs/wm8961.c
+++ b/sound/soc/codecs/wm8961.c
@@ -835,7 +835,6 @@ static struct snd_soc_dai_driver wm8961_dai = {
static int wm8961_probe(struct snd_soc_codec *codec)
{
- struct snd_soc_dapm_context *dapm = &codec->dapm;
u16 reg;
/* Enable class W */
@@ -871,50 +870,33 @@ static int wm8961_probe(struct snd_soc_codec *codec)
reg &= ~WM8961_MANUAL_MODE;
snd_soc_write(codec, WM8961_CLOCKING_3, reg);
- wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- snd_soc_add_codec_controls(codec, wm8961_snd_controls,
- ARRAY_SIZE(wm8961_snd_controls));
- snd_soc_dapm_new_controls(dapm, wm8961_dapm_widgets,
- ARRAY_SIZE(wm8961_dapm_widgets));
- snd_soc_dapm_add_routes(dapm, audio_paths, ARRAY_SIZE(audio_paths));
-
- return 0;
-}
-
-static int wm8961_remove(struct snd_soc_codec *codec)
-{
- wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
#ifdef CONFIG_PM
-static int wm8961_suspend(struct snd_soc_codec *codec)
-{
- wm8961_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
static int wm8961_resume(struct snd_soc_codec *codec)
{
snd_soc_cache_sync(codec);
- wm8961_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
return 0;
}
#else
-#define wm8961_suspend NULL
#define wm8961_resume NULL
#endif
static struct snd_soc_codec_driver soc_codec_dev_wm8961 = {
.probe = wm8961_probe,
- .remove = wm8961_remove,
- .suspend = wm8961_suspend,
.resume = wm8961_resume,
.set_bias_level = wm8961_set_bias_level,
+ .suspend_bias_off = true,
+
+ .controls = wm8961_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8961_snd_controls),
+ .dapm_widgets = wm8961_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8961_dapm_widgets),
+ .dapm_routes = audio_paths,
+ .num_dapm_routes = ARRAY_SIZE(audio_paths),
};
static const struct regmap_config wm8961_regmap = {
diff --git a/sound/soc/codecs/wm8962.c b/sound/soc/codecs/wm8962.c
index 9077411..1534d88 100644
--- a/sound/soc/codecs/wm8962.c
+++ b/sound/soc/codecs/wm8962.c
@@ -26,6 +26,7 @@
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/workqueue.h>
+#include <linux/mutex.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -67,6 +68,7 @@ struct wm8962_priv {
int fll_fref;
int fll_fout;
+ struct mutex dsp2_ena_lock;
u16 dsp2_ena;
struct delayed_work mic_work;
@@ -1570,7 +1572,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
int dsp2_running = snd_soc_read(codec, WM8962_DSP2_POWER_MANAGEMENT) &
WM8962_DSP2_ENA;
- mutex_lock(&codec->mutex);
+ mutex_lock(&wm8962->dsp2_ena_lock);
if (ucontrol->value.integer.value[0])
wm8962->dsp2_ena |= 1 << shift;
@@ -1590,7 +1592,7 @@ static int wm8962_dsp2_ena_put(struct snd_kcontrol *kcontrol,
}
out:
- mutex_unlock(&codec->mutex);
+ mutex_unlock(&wm8962->dsp2_ena_lock);
return ret;
}
@@ -3552,11 +3554,12 @@ static int wm8962_i2c_probe(struct i2c_client *i2c,
unsigned int reg;
int ret, i, irq_pol, trigger;
- wm8962 = devm_kzalloc(&i2c->dev, sizeof(struct wm8962_priv),
- GFP_KERNEL);
+ wm8962 = devm_kzalloc(&i2c->dev, sizeof(*wm8962), GFP_KERNEL);
if (wm8962 == NULL)
return -ENOMEM;
+ mutex_init(&wm8962->dsp2_ena_lock);
+
i2c_set_clientdata(i2c, wm8962);
INIT_DELAYED_WORK(&wm8962->mic_work, wm8962_mic_work);
diff --git a/sound/soc/codecs/wm8974.c b/sound/soc/codecs/wm8974.c
index 682e9ed..ff0e464 100644
--- a/sound/soc/codecs/wm8974.c
+++ b/sound/soc/codecs/wm8974.c
@@ -568,18 +568,6 @@ static struct snd_soc_dai_driver wm8974_dai = {
.symmetric_rates = 1,
};
-static int wm8974_suspend(struct snd_soc_codec *codec)
-{
- wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8974_resume(struct snd_soc_codec *codec)
-{
- wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static const struct regmap_config wm8974_regmap = {
.reg_bits = 7,
.val_bits = 9,
@@ -599,24 +587,13 @@ static int wm8974_probe(struct snd_soc_codec *codec)
return ret;
}
- wm8974_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return ret;
-}
-
-/* power down chip */
-static int wm8974_remove(struct snd_soc_codec *codec)
-{
- wm8974_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8974 = {
.probe = wm8974_probe,
- .remove = wm8974_remove,
- .suspend = wm8974_suspend,
- .resume = wm8974_resume,
.set_bias_level = wm8974_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8974_snd_controls,
.num_controls = ARRAY_SIZE(wm8974_snd_controls),
diff --git a/sound/soc/codecs/wm8978.c b/sound/soc/codecs/wm8978.c
index ee2ba57..cf70329 100644
--- a/sound/soc/codecs/wm8978.c
+++ b/sound/soc/codecs/wm8978.c
@@ -991,21 +991,11 @@ static int wm8978_probe(struct snd_soc_codec *codec)
for (i = 0; i < ARRAY_SIZE(update_reg); i++)
snd_soc_update_bits(codec, update_reg[i], 0x100, 0x100);
- wm8978_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-/* power down chip */
-static int wm8978_remove(struct snd_soc_codec *codec)
-{
- wm8978_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8978 = {
.probe = wm8978_probe,
- .remove = wm8978_remove,
.suspend = wm8978_suspend,
.resume = wm8978_resume,
.set_bias_level = wm8978_set_bias_level,
diff --git a/sound/soc/codecs/wm8983.c b/sound/soc/codecs/wm8983.c
index ac5defd..5d1cf08 100644
--- a/sound/soc/codecs/wm8983.c
+++ b/sound/soc/codecs/wm8983.c
@@ -967,29 +967,6 @@ static int wm8983_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-#ifdef CONFIG_PM
-static int wm8983_suspend(struct snd_soc_codec *codec)
-{
- wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8983_resume(struct snd_soc_codec *codec)
-{
- wm8983_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8983_suspend NULL
-#define wm8983_resume NULL
-#endif
-
-static int wm8983_remove(struct snd_soc_codec *codec)
-{
- wm8983_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int wm8983_probe(struct snd_soc_codec *codec)
{
int ret;
@@ -1055,10 +1032,8 @@ static struct snd_soc_dai_driver wm8983_dai = {
static struct snd_soc_codec_driver soc_codec_dev_wm8983 = {
.probe = wm8983_probe,
- .remove = wm8983_remove,
- .suspend = wm8983_suspend,
- .resume = wm8983_resume,
.set_bias_level = wm8983_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8983_snd_controls,
.num_controls = ARRAY_SIZE(wm8983_snd_controls),
.dapm_widgets = wm8983_dapm_widgets,
diff --git a/sound/soc/codecs/wm8985.c b/sound/soc/codecs/wm8985.c
index ee38019..0b3b54c 100644
--- a/sound/soc/codecs/wm8985.c
+++ b/sound/soc/codecs/wm8985.c
@@ -961,29 +961,6 @@ static int wm8985_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-#ifdef CONFIG_PM
-static int wm8985_suspend(struct snd_soc_codec *codec)
-{
- wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8985_resume(struct snd_soc_codec *codec)
-{
- wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-#else
-#define wm8985_suspend NULL
-#define wm8985_resume NULL
-#endif
-
-static int wm8985_remove(struct snd_soc_codec *codec)
-{
- wm8985_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int wm8985_probe(struct snd_soc_codec *codec)
{
size_t i;
@@ -1023,7 +1000,6 @@ static int wm8985_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8985_BIAS_CTRL, WM8985_BIASCUT,
WM8985_BIASCUT);
- wm8985_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
return 0;
err_reg_enable:
@@ -1064,10 +1040,8 @@ static struct snd_soc_dai_driver wm8985_dai = {
static struct snd_soc_codec_driver soc_codec_dev_wm8985 = {
.probe = wm8985_probe,
- .remove = wm8985_remove,
- .suspend = wm8985_suspend,
- .resume = wm8985_resume,
.set_bias_level = wm8985_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8985_snd_controls,
.num_controls = ARRAY_SIZE(wm8985_snd_controls),
diff --git a/sound/soc/codecs/wm8988.c b/sound/soc/codecs/wm8988.c
index a5130d9..e418199 100644
--- a/sound/soc/codecs/wm8988.c
+++ b/sound/soc/codecs/wm8988.c
@@ -793,21 +793,6 @@ static struct snd_soc_dai_driver wm8988_dai = {
.symmetric_rates = 1,
};
-static int wm8988_suspend(struct snd_soc_codec *codec)
-{
- struct wm8988_priv *wm8988 = snd_soc_codec_get_drvdata(codec);
-
- wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
- regcache_mark_dirty(wm8988->regmap);
- return 0;
-}
-
-static int wm8988_resume(struct snd_soc_codec *codec)
-{
- wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
static int wm8988_probe(struct snd_soc_codec *codec)
{
int ret = 0;
@@ -825,23 +810,13 @@ static int wm8988_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM8988_ROUT2V, 0x0100, 0x0100);
snd_soc_update_bits(codec, WM8988_RINVOL, 0x0100, 0x0100);
- wm8988_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
-static int wm8988_remove(struct snd_soc_codec *codec)
-{
- wm8988_set_bias_level(codec, SND_SOC_BIAS_OFF);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm8988 = {
.probe = wm8988_probe,
- .remove = wm8988_remove,
- .suspend = wm8988_suspend,
- .resume = wm8988_resume,
.set_bias_level = wm8988_set_bias_level,
+ .suspend_bias_off = true,
.controls = wm8988_snd_controls,
.num_controls = ARRAY_SIZE(wm8988_snd_controls),
diff --git a/sound/soc/codecs/wm8990.c b/sound/soc/codecs/wm8990.c
index 03e43e3..8a58422 100644
--- a/sound/soc/codecs/wm8990.c
+++ b/sound/soc/codecs/wm8990.c
@@ -1271,18 +1271,6 @@ static struct snd_soc_dai_driver wm8990_dai = {
.ops = &wm8990_dai_ops,
};
-static int wm8990_suspend(struct snd_soc_codec *codec)
-{
- wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8990_resume(struct snd_soc_codec *codec)
-{
- wm8990_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
/*
* initialise the WM8990 driver
* register the mixer and dsp interfaces with the kernel
@@ -1309,19 +1297,11 @@ static int wm8990_probe(struct snd_soc_codec *codec)
return 0;
}
-/* power down chip */
-static int wm8990_remove(struct snd_soc_codec *codec)
-{
- wm8990_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm8990 = {
.probe = wm8990_probe,
- .remove = wm8990_remove,
- .suspend = wm8990_suspend,
- .resume = wm8990_resume,
.set_bias_level = wm8990_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = wm8990_snd_controls,
.num_controls = ARRAY_SIZE(wm8990_snd_controls),
.dapm_widgets = wm8990_dapm_widgets,
diff --git a/sound/soc/codecs/wm8991.c b/sound/soc/codecs/wm8991.c
index d0be897..b0ac2c3 100644
--- a/sound/soc/codecs/wm8991.c
+++ b/sound/soc/codecs/wm8991.c
@@ -1227,32 +1227,6 @@ static int wm8991_set_bias_level(struct snd_soc_codec *codec,
return 0;
}
-static int wm8991_suspend(struct snd_soc_codec *codec)
-{
- wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8991_resume(struct snd_soc_codec *codec)
-{
- wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- return 0;
-}
-
-/* power down chip */
-static int wm8991_remove(struct snd_soc_codec *codec)
-{
- wm8991_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
-static int wm8991_probe(struct snd_soc_codec *codec)
-{
- wm8991_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-
#define WM8991_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S20_3LE |\
SNDRV_PCM_FMTBIT_S24_LE)
@@ -1293,11 +1267,9 @@ static struct snd_soc_dai_driver wm8991_dai = {
};
static struct snd_soc_codec_driver soc_codec_dev_wm8991 = {
- .probe = wm8991_probe,
- .remove = wm8991_remove,
- .suspend = wm8991_suspend,
- .resume = wm8991_resume,
.set_bias_level = wm8991_set_bias_level,
+ .suspend_bias_off = true,
+
.controls = wm8991_snd_controls,
.num_controls = ARRAY_SIZE(wm8991_snd_controls),
.dapm_widgets = wm8991_dapm_widgets,
diff --git a/sound/soc/codecs/wm8993.c b/sound/soc/codecs/wm8993.c
index 93b14ed..53c6fe3 100644
--- a/sound/soc/codecs/wm8993.c
+++ b/sound/soc/codecs/wm8993.c
@@ -1486,7 +1486,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
{
struct wm8993_priv *wm8993 = snd_soc_codec_get_drvdata(codec);
struct snd_soc_dapm_context *dapm = &codec->dapm;
- int ret;
wm8993->hubs_data.hp_startup_mode = 1;
wm8993->hubs_data.dcs_codes_l = -2;
@@ -1518,10 +1517,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
wm8993->pdata.micbias1_lvl,
wm8993->pdata.micbias2_lvl);
- ret = wm8993_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- if (ret != 0)
- return ret;
-
snd_soc_add_codec_controls(codec, wm8993_snd_controls,
ARRAY_SIZE(wm8993_snd_controls));
if (wm8993->pdata.num_retune_configs != 0) {
@@ -1550,12 +1545,6 @@ static int wm8993_probe(struct snd_soc_codec *codec)
}
-static int wm8993_remove(struct snd_soc_codec *codec)
-{
- wm8993_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
#ifdef CONFIG_PM
static int wm8993_suspend(struct snd_soc_codec *codec)
{
@@ -1629,7 +1618,6 @@ static const struct regmap_config wm8993_regmap = {
static struct snd_soc_codec_driver soc_codec_dev_wm8993 = {
.probe = wm8993_probe,
- .remove = wm8993_remove,
.suspend = wm8993_suspend,
.resume = wm8993_resume,
.set_bias_level = wm8993_set_bias_level,
diff --git a/sound/soc/codecs/wm8994.c b/sound/soc/codecs/wm8994.c
index 1fcb9f3..36b767f 100644
--- a/sound/soc/codecs/wm8994.c
+++ b/sound/soc/codecs/wm8994.c
@@ -4391,8 +4391,6 @@ static int wm8994_codec_remove(struct snd_soc_codec *codec)
struct wm8994 *control = wm8994->wm8994;
int i;
- wm8994_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
for (i = 0; i < ARRAY_SIZE(wm8994->fll_locked); i++)
wm8994_free_irq(wm8994->wm8994, WM8994_IRQ_FLL1_LOCK + i,
&wm8994->fll_locked[i]);
@@ -4457,6 +4455,8 @@ static int wm8994_probe(struct platform_device *pdev)
return -ENOMEM;
platform_set_drvdata(pdev, wm8994);
+ mutex_init(&wm8994->fw_lock);
+
wm8994->wm8994 = dev_get_drvdata(pdev->dev.parent);
pm_runtime_enable(&pdev->dev);
diff --git a/sound/soc/codecs/wm8994.h b/sound/soc/codecs/wm8994.h
index 6536f8d..dd73387 100644
--- a/sound/soc/codecs/wm8994.h
+++ b/sound/soc/codecs/wm8994.h
@@ -13,6 +13,7 @@
#include <linux/firmware.h>
#include <linux/completion.h>
#include <linux/workqueue.h>
+#include <linux/mutex.h>
#include "wm_hubs.h"
@@ -156,6 +157,7 @@ struct wm8994_priv {
unsigned int aif1clk_disable:1;
unsigned int aif2clk_disable:1;
+ struct mutex fw_lock;
int dsp_active;
const struct firmware *cur_fw;
const struct firmware *mbc;
diff --git a/sound/soc/codecs/wm8995.c b/sound/soc/codecs/wm8995.c
index 1288ede..c280f0a 100644
--- a/sound/soc/codecs/wm8995.c
+++ b/sound/soc/codecs/wm8995.c
@@ -2004,7 +2004,6 @@ static int wm8995_remove(struct snd_soc_codec *codec)
int i;
wm8995 = snd_soc_codec_get_drvdata(codec);
- wm8995_set_bias_level(codec, SND_SOC_BIAS_OFF);
for (i = 0; i < ARRAY_SIZE(wm8995->supplies); ++i)
regulator_unregister_notifier(wm8995->supplies[i].consumer,
@@ -2078,8 +2077,6 @@ static int wm8995_probe(struct snd_soc_codec *codec)
goto err_reg_enable;
}
- wm8995_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
/* Latch volume updates (right only; we always do left then right). */
snd_soc_update_bits(codec, WM8995_AIF1_DAC1_RIGHT_VOLUME,
WM8995_AIF1DAC1_VU_MASK, WM8995_AIF1DAC1_VU);
@@ -2102,13 +2099,6 @@ static int wm8995_probe(struct snd_soc_codec *codec)
wm8995_update_class_w(codec);
- snd_soc_add_codec_controls(codec, wm8995_snd_controls,
- ARRAY_SIZE(wm8995_snd_controls));
- snd_soc_dapm_new_controls(&codec->dapm, wm8995_dapm_widgets,
- ARRAY_SIZE(wm8995_dapm_widgets));
- snd_soc_dapm_add_routes(&codec->dapm, wm8995_intercon,
- ARRAY_SIZE(wm8995_intercon));
-
return 0;
err_reg_enable:
@@ -2205,6 +2195,13 @@ static struct snd_soc_codec_driver soc_codec_dev_wm8995 = {
.remove = wm8995_remove,
.set_bias_level = wm8995_set_bias_level,
.idle_bias_off = true,
+
+ .controls = wm8995_snd_controls,
+ .num_controls = ARRAY_SIZE(wm8995_snd_controls),
+ .dapm_widgets = wm8995_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(wm8995_dapm_widgets),
+ .dapm_routes = wm8995_intercon,
+ .num_dapm_routes = ARRAY_SIZE(wm8995_intercon),
};
static struct regmap_config wm8995_regmap = {
diff --git a/sound/soc/codecs/wm9081.c b/sound/soc/codecs/wm9081.c
index 0cdc9e2..b1d946f 100644
--- a/sound/soc/codecs/wm9081.c
+++ b/sound/soc/codecs/wm9081.c
@@ -1277,15 +1277,8 @@ static int wm9081_probe(struct snd_soc_codec *codec)
return 0;
}
-static int wm9081_remove(struct snd_soc_codec *codec)
-{
- wm9081_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm9081 = {
.probe = wm9081_probe,
- .remove = wm9081_remove,
.set_sysclk = wm9081_set_sysclk,
.set_bias_level = wm9081_set_bias_level,
diff --git a/sound/soc/codecs/wm9090.c b/sound/soc/codecs/wm9090.c
index a13f072..6ffe8dc 100644
--- a/sound/soc/codecs/wm9090.c
+++ b/sound/soc/codecs/wm9090.c
@@ -550,45 +550,15 @@ static int wm9090_probe(struct snd_soc_codec *codec)
snd_soc_update_bits(codec, WM9090_CLOCKING_1,
WM9090_TOCLK_ENA, WM9090_TOCLK_ENA);
- wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
wm9090_add_controls(codec);
return 0;
}
-#ifdef CONFIG_PM
-static int wm9090_suspend(struct snd_soc_codec *codec)
-{
- wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
-static int wm9090_resume(struct snd_soc_codec *codec)
-{
- wm9090_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
-
- return 0;
-}
-#else
-#define wm9090_suspend NULL
-#define wm9090_resume NULL
-#endif
-
-static int wm9090_remove(struct snd_soc_codec *codec)
-{
- wm9090_set_bias_level(codec, SND_SOC_BIAS_OFF);
-
- return 0;
-}
-
static struct snd_soc_codec_driver soc_codec_dev_wm9090 = {
.probe = wm9090_probe,
- .remove = wm9090_remove,
- .suspend = wm9090_suspend,
- .resume = wm9090_resume,
.set_bias_level = wm9090_set_bias_level,
+ .suspend_bias_off = true,
};
static const struct regmap_config wm9090_regmap = {
diff --git a/sound/soc/codecs/wm9705.c b/sound/soc/codecs/wm9705.c
index c0b7f45..d3a800f 100644
--- a/sound/soc/codecs/wm9705.c
+++ b/sound/soc/codecs/wm9705.c
@@ -203,13 +203,14 @@ static const struct snd_soc_dapm_route wm9705_audio_map[] = {
/* We use a register cache to enhance read performance. */
static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
switch (reg) {
case AC97_RESET:
case AC97_VENDOR_ID1:
case AC97_VENDOR_ID2:
- return soc_ac97_ops->read(codec->ac97, reg);
+ return soc_ac97_ops->read(ac97, reg);
default:
reg = reg >> 1;
@@ -223,9 +224,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec, unsigned int reg)
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
- soc_ac97_ops->write(codec->ac97, reg, val);
+ soc_ac97_ops->write(ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9705_reg)))
cache[reg] = val;
@@ -263,7 +265,6 @@ static const struct snd_soc_dai_ops wm9705_dai_ops = {
static struct snd_soc_dai_driver wm9705_dai[] = {
{
.name = "wm9705-hifi",
- .ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -294,36 +295,41 @@ static struct snd_soc_dai_driver wm9705_dai[] = {
static int wm9705_reset(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
if (soc_ac97_ops->reset) {
- soc_ac97_ops->reset(codec->ac97);
+ soc_ac97_ops->reset(ac97);
if (ac97_read(codec, 0) == wm9705_reg[0])
return 0; /* Success */
}
+ dev_err(codec->dev, "Failed to reset: AC97 link error\n");
+
return -EIO;
}
#ifdef CONFIG_PM
static int wm9705_soc_suspend(struct snd_soc_codec *codec)
{
- soc_ac97_ops->write(codec->ac97, AC97_POWERDOWN, 0xffff);
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ soc_ac97_ops->write(ac97, AC97_POWERDOWN, 0xffff);
return 0;
}
static int wm9705_soc_resume(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
int i, ret;
u16 *cache = codec->reg_cache;
ret = wm9705_reset(codec);
- if (ret < 0) {
- printk(KERN_ERR "could not reset AC97 codec\n");
+ if (ret < 0)
return ret;
- }
for (i = 2; i < ARRAY_SIZE(wm9705_reg) << 1; i += 2) {
- soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
+ soc_ac97_ops->write(ac97, i, cache[i>>1]);
}
return 0;
@@ -335,31 +341,34 @@ static int wm9705_soc_resume(struct snd_soc_codec *codec)
static int wm9705_soc_probe(struct snd_soc_codec *codec)
{
+ struct snd_ac97 *ac97;
int ret = 0;
- ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
- if (ret < 0) {
- printk(KERN_ERR "wm9705: failed to register AC97 codec\n");
+ ac97 = snd_soc_new_ac97_codec(codec);
+ if (IS_ERR(ac97)) {
+ ret = PTR_ERR(ac97);
+ dev_err(codec->dev, "Failed to register AC97 codec\n");
return ret;
}
+ snd_soc_codec_set_drvdata(codec, ac97);
+
ret = wm9705_reset(codec);
if (ret)
goto reset_err;
- snd_soc_add_codec_controls(codec, wm9705_snd_ac97_controls,
- ARRAY_SIZE(wm9705_snd_ac97_controls));
-
return 0;
reset_err:
- snd_soc_free_ac97_codec(codec);
+ snd_soc_free_ac97_codec(ac97);
return ret;
}
static int wm9705_soc_remove(struct snd_soc_codec *codec)
{
- snd_soc_free_ac97_codec(codec);
+ struct snd_ac97 *ac97 = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_free_ac97_codec(ac97);
return 0;
}
@@ -374,6 +383,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9705 = {
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
.reg_cache_default = wm9705_reg,
+
+ .controls = wm9705_snd_ac97_controls,
+ .num_controls = ARRAY_SIZE(wm9705_snd_ac97_controls),
.dapm_widgets = wm9705_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm9705_dapm_widgets),
.dapm_routes = wm9705_audio_map,
diff --git a/sound/soc/codecs/wm9712.c b/sound/soc/codecs/wm9712.c
index c5eb746..7c45971 100644
--- a/sound/soc/codecs/wm9712.c
+++ b/sound/soc/codecs/wm9712.c
@@ -23,6 +23,12 @@
#include <sound/tlv.h>
#include "wm9712.h"
+struct wm9712_priv {
+ struct snd_ac97 *ac97;
+ unsigned int hp_mixer[2];
+ struct mutex lock;
+};
+
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg);
static int ac97_write(struct snd_soc_codec *codec,
@@ -48,12 +54,10 @@ static const u16 wm9712_reg[] = {
0x0000, 0x0000, 0x0000, 0x0000, /* 6e */
0x0000, 0x0000, 0x0000, 0x0006, /* 76 */
0x0001, 0x0000, 0x574d, 0x4c12, /* 7e */
- 0x0000, 0x0000 /* virtual hp mixers */
};
-/* virtual HP mixers regs */
-#define HPL_MIXER 0x80
-#define HPR_MIXER 0x82
+#define HPL_MIXER 0x0
+#define HPR_MIXER 0x1
static const char *wm9712_alc_select[] = {"None", "Left", "Right", "Stereo"};
static const char *wm9712_alc_mux[] = {"Stereo", "Left", "Right", "None"};
@@ -157,75 +161,108 @@ SOC_SINGLE_TLV("Mic 2 Volume", AC97_MIC, 0, 31, 1, main_tlv),
SOC_SINGLE_TLV("Mic Boost Volume", AC97_MIC, 7, 1, 0, boost_tlv),
};
+static const unsigned int wm9712_mixer_mute_regs[] = {
+ AC97_VIDEO,
+ AC97_PCM,
+ AC97_LINE,
+ AC97_PHONE,
+ AC97_CD,
+ AC97_PC_BEEP,
+};
+
/* We have to create a fake left and right HP mixers because
* the codec only has a single control that is shared by both channels.
* This makes it impossible to determine the audio path.
*/
-static int mixer_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *k, int event)
+static int wm9712_hp_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- u16 l, r, beep, line, phone, mic, pcm, aux;
-
- l = ac97_read(w->codec, HPL_MIXER);
- r = ac97_read(w->codec, HPR_MIXER);
- beep = ac97_read(w->codec, AC97_PC_BEEP);
- mic = ac97_read(w->codec, AC97_VIDEO);
- phone = ac97_read(w->codec, AC97_PHONE);
- line = ac97_read(w->codec, AC97_LINE);
- pcm = ac97_read(w->codec, AC97_PCM);
- aux = ac97_read(w->codec, AC97_CD);
-
- if (l & 0x1 || r & 0x1)
- ac97_write(w->codec, AC97_VIDEO, mic & 0x7fff);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = ucontrol->value.enumerated.item[0];
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int mixer, mask, shift, old;
+ struct snd_soc_dapm_update update;
+ bool change;
+
+ mixer = mc->shift >> 8;
+ shift = mc->shift & 0xff;
+ mask = 1 << shift;
+
+ mutex_lock(&wm9712->lock);
+ old = wm9712->hp_mixer[mixer];
+ if (ucontrol->value.enumerated.item[0])
+ wm9712->hp_mixer[mixer] |= mask;
else
- ac97_write(w->codec, AC97_VIDEO, mic | 0x8000);
+ wm9712->hp_mixer[mixer] &= ~mask;
+
+ change = old != wm9712->hp_mixer[mixer];
+ if (change) {
+ update.kcontrol = kcontrol;
+ update.reg = wm9712_mixer_mute_regs[shift];
+ update.mask = 0x8000;
+ if ((wm9712->hp_mixer[0] & mask) ||
+ (wm9712->hp_mixer[1] & mask))
+ update.val = 0x0;
+ else
+ update.val = 0x8000;
+
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
+ &update);
+ }
- if (l & 0x2 || r & 0x2)
- ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
- else
- ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
+ mutex_unlock(&wm9712->lock);
- if (l & 0x4 || r & 0x4)
- ac97_write(w->codec, AC97_LINE, line & 0x7fff);
- else
- ac97_write(w->codec, AC97_LINE, line | 0x8000);
+ return change;
+}
- if (l & 0x8 || r & 0x8)
- ac97_write(w->codec, AC97_PHONE, phone & 0x7fff);
- else
- ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
+static int wm9712_hp_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int shift, mixer;
- if (l & 0x10 || r & 0x10)
- ac97_write(w->codec, AC97_CD, aux & 0x7fff);
- else
- ac97_write(w->codec, AC97_CD, aux | 0x8000);
+ mixer = mc->shift >> 8;
+ shift = mc->shift & 0xff;
- if (l & 0x20 || r & 0x20)
- ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff);
- else
- ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
+ ucontrol->value.enumerated.item[0] =
+ (wm9712->hp_mixer[mixer] >> shift) & 1;
return 0;
}
+#define WM9712_HP_MIXER_CTRL(xname, xmixer, xshift) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = wm9712_hp_mixer_get, .put = wm9712_hp_mixer_put, \
+ .private_value = SOC_SINGLE_VALUE(SND_SOC_NOPM, \
+ (xmixer << 8) | xshift, 1, 0, 0) \
+}
+
/* Left Headphone Mixers */
static const struct snd_kcontrol_new wm9712_hpl_mixer_controls[] = {
- SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPL_MIXER, 5, 1, 0),
- SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 4, 1, 0),
- SOC_DAPM_SINGLE("Phone Bypass Switch", HPL_MIXER, 3, 1, 0),
- SOC_DAPM_SINGLE("Line Bypass Switch", HPL_MIXER, 2, 1, 0),
- SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 1, 1, 0),
- SOC_DAPM_SINGLE("Mic Sidetone Switch", HPL_MIXER, 0, 1, 0),
+ WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPL_MIXER, 5),
+ WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 4),
+ WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPL_MIXER, 3),
+ WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPL_MIXER, 2),
+ WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 1),
+ WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPL_MIXER, 0),
};
/* Right Headphone Mixers */
static const struct snd_kcontrol_new wm9712_hpr_mixer_controls[] = {
- SOC_DAPM_SINGLE("PCBeep Bypass Switch", HPR_MIXER, 5, 1, 0),
- SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 4, 1, 0),
- SOC_DAPM_SINGLE("Phone Bypass Switch", HPR_MIXER, 3, 1, 0),
- SOC_DAPM_SINGLE("Line Bypass Switch", HPR_MIXER, 2, 1, 0),
- SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 1, 1, 0),
- SOC_DAPM_SINGLE("Mic Sidetone Switch", HPR_MIXER, 0, 1, 0),
+ WM9712_HP_MIXER_CTRL("PCBeep Bypass Switch", HPR_MIXER, 5),
+ WM9712_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 4),
+ WM9712_HP_MIXER_CTRL("Phone Bypass Switch", HPR_MIXER, 3),
+ WM9712_HP_MIXER_CTRL("Line Bypass Switch", HPR_MIXER, 2),
+ WM9712_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 1),
+ WM9712_HP_MIXER_CTRL("Mic Sidetone Switch", HPR_MIXER, 0),
};
/* Speaker Mixer */
@@ -299,12 +336,10 @@ SND_SOC_DAPM_MUX("Right Mic Select Source", SND_SOC_NOPM, 0, 0,
SND_SOC_DAPM_MUX("Differential Source", SND_SOC_NOPM, 0, 0,
&wm9712_diff_sel_controls),
SND_SOC_DAPM_MIXER("AC97 Mixer", SND_SOC_NOPM, 0, 0, NULL, 0),
-SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_INT_PAGING, 9, 1,
- &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls),
- mixer_event, SND_SOC_DAPM_POST_REG),
-SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_INT_PAGING, 8, 1,
- &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls),
- mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_INT_PAGING, 9, 1,
+ &wm9712_hpl_mixer_controls[0], ARRAY_SIZE(wm9712_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_INT_PAGING, 8, 1,
+ &wm9712_hpr_mixer_controls[0], ARRAY_SIZE(wm9712_hpr_mixer_controls)),
SND_SOC_DAPM_MIXER("Phone Mixer", AC97_INT_PAGING, 6, 1,
&wm9712_phone_mixer_controls[0], ARRAY_SIZE(wm9712_phone_mixer_controls)),
SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_INT_PAGING, 7, 1,
@@ -450,12 +485,13 @@ static const struct snd_soc_dapm_route wm9712_audio_map[] = {
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_REC_GAIN)
- return soc_ac97_ops->read(codec->ac97, reg);
+ return soc_ac97_ops->read(wm9712->ac97, reg);
else {
reg = reg >> 1;
@@ -469,10 +505,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
- if (reg < 0x7c)
- soc_ac97_ops->write(codec->ac97, reg, val);
+ soc_ac97_ops->write(wm9712->ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9712_reg)))
cache[reg] = val;
@@ -532,7 +568,6 @@ static const struct snd_soc_dai_ops wm9712_dai_ops_aux = {
static struct snd_soc_dai_driver wm9712_dai[] = {
{
.name = "wm9712-hifi",
- .ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -581,40 +616,35 @@ static int wm9712_set_bias_level(struct snd_soc_codec *codec,
static int wm9712_reset(struct snd_soc_codec *codec, int try_warm)
{
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+
if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(codec->ac97);
+ soc_ac97_ops->warm_reset(wm9712->ac97);
if (ac97_read(codec, 0) == wm9712_reg[0])
return 1;
}
- soc_ac97_ops->reset(codec->ac97);
+ soc_ac97_ops->reset(wm9712->ac97);
if (soc_ac97_ops->warm_reset)
- soc_ac97_ops->warm_reset(codec->ac97);
+ soc_ac97_ops->warm_reset(wm9712->ac97);
if (ac97_read(codec, 0) != wm9712_reg[0])
goto err;
return 0;
err:
- printk(KERN_ERR "WM9712 AC97 reset failed\n");
+ dev_err(codec->dev, "Failed to reset: AC97 link error\n");
return -EIO;
}
-static int wm9712_soc_suspend(struct snd_soc_codec *codec)
-{
- wm9712_set_bias_level(codec, SND_SOC_BIAS_OFF);
- return 0;
-}
-
static int wm9712_soc_resume(struct snd_soc_codec *codec)
{
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
int i, ret;
u16 *cache = codec->reg_cache;
ret = wm9712_reset(codec, 1);
- if (ret < 0) {
- printk(KERN_ERR "could not reset AC97 codec\n");
+ if (ret < 0)
return ret;
- }
wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -624,7 +654,7 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
if (i == AC97_INT_PAGING || i == AC97_POWERDOWN ||
(i > 0x58 && i != 0x5c))
continue;
- soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
+ soc_ac97_ops->write(wm9712->ac97, i, cache[i>>1]);
}
}
@@ -633,52 +663,53 @@ static int wm9712_soc_resume(struct snd_soc_codec *codec)
static int wm9712_soc_probe(struct snd_soc_codec *codec)
{
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
int ret = 0;
- ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
- if (ret < 0) {
- printk(KERN_ERR "wm9712: failed to register AC97 codec\n");
+ wm9712->ac97 = snd_soc_new_ac97_codec(codec);
+ if (IS_ERR(wm9712->ac97)) {
+ ret = PTR_ERR(wm9712->ac97);
+ dev_err(codec->dev, "Failed to register AC97 codec: %d\n", ret);
return ret;
}
ret = wm9712_reset(codec, 0);
- if (ret < 0) {
- printk(KERN_ERR "Failed to reset WM9712: AC97 link error\n");
+ if (ret < 0)
goto reset_err;
- }
/* set alc mux to none */
ac97_write(codec, AC97_VIDEO, ac97_read(codec, AC97_VIDEO) | 0x3000);
- wm9712_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
- snd_soc_add_codec_controls(codec, wm9712_snd_ac97_controls,
- ARRAY_SIZE(wm9712_snd_ac97_controls));
-
return 0;
reset_err:
- snd_soc_free_ac97_codec(codec);
+ snd_soc_free_ac97_codec(wm9712->ac97);
return ret;
}
static int wm9712_soc_remove(struct snd_soc_codec *codec)
{
- snd_soc_free_ac97_codec(codec);
+ struct wm9712_priv *wm9712 = snd_soc_codec_get_drvdata(codec);
+
+ snd_soc_free_ac97_codec(wm9712->ac97);
return 0;
}
static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
.probe = wm9712_soc_probe,
.remove = wm9712_soc_remove,
- .suspend = wm9712_soc_suspend,
.resume = wm9712_soc_resume,
.read = ac97_read,
.write = ac97_write,
.set_bias_level = wm9712_set_bias_level,
+ .suspend_bias_off = true,
.reg_cache_size = ARRAY_SIZE(wm9712_reg),
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
.reg_cache_default = wm9712_reg,
+
+ .controls = wm9712_snd_ac97_controls,
+ .num_controls = ARRAY_SIZE(wm9712_snd_ac97_controls),
.dapm_widgets = wm9712_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm9712_dapm_widgets),
.dapm_routes = wm9712_audio_map,
@@ -687,6 +718,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9712 = {
static int wm9712_probe(struct platform_device *pdev)
{
+ struct wm9712_priv *wm9712;
+
+ wm9712 = devm_kzalloc(&pdev->dev, sizeof(*wm9712), GFP_KERNEL);
+ if (wm9712 == NULL)
+ return -ENOMEM;
+
+ mutex_init(&wm9712->lock);
+
+ platform_set_drvdata(pdev, wm9712);
+
return snd_soc_register_codec(&pdev->dev,
&soc_codec_dev_wm9712, wm9712_dai, ARRAY_SIZE(wm9712_dai));
}
diff --git a/sound/soc/codecs/wm9713.c b/sound/soc/codecs/wm9713.c
index bddee30..5df7f6d 100644
--- a/sound/soc/codecs/wm9713.c
+++ b/sound/soc/codecs/wm9713.c
@@ -30,7 +30,10 @@
#include "wm9713.h"
struct wm9713_priv {
+ struct snd_ac97 *ac97;
u32 pll_in; /* PLL input frequency */
+ unsigned int hp_mixer[2];
+ struct mutex lock;
};
static unsigned int ac97_read(struct snd_soc_codec *codec,
@@ -59,13 +62,10 @@ static const u16 wm9713_reg[] = {
0x0000, 0x0000, 0x0000, 0x0000,
0x0000, 0x0000, 0x0000, 0x0006,
0x0001, 0x0000, 0x574d, 0x4c13,
- 0x0000, 0x0000, 0x0000
};
-/* virtual HP mixers regs */
-#define HPL_MIXER 0x80
-#define HPR_MIXER 0x82
-#define MICB_MUX 0x82
+#define HPL_MIXER 0
+#define HPR_MIXER 1
static const char *wm9713_mic_mixer[] = {"Stereo", "Mic 1", "Mic 2", "Mute"};
static const char *wm9713_rec_mux[] = {"Stereo", "Left", "Right", "Mute"};
@@ -110,7 +110,7 @@ SOC_ENUM_SINGLE(AC97_REC_GAIN_MIC, 10, 8, wm9713_dac_inv), /* dac invert 2 15 */
SOC_ENUM_SINGLE(AC97_GENERAL_PURPOSE, 15, 2, wm9713_bass), /* bass control 16 */
SOC_ENUM_SINGLE(AC97_PCI_SVID, 5, 2, wm9713_ng_type), /* noise gate type 17 */
SOC_ENUM_SINGLE(AC97_3D_CONTROL, 12, 3, wm9713_mic_select), /* mic selection 18 */
-SOC_ENUM_SINGLE(MICB_MUX, 0, 2, wm9713_micb_select), /* mic selection 19 */
+SOC_ENUM_SINGLE_VIRT(2, wm9713_micb_select), /* mic selection 19 */
};
static const DECLARE_TLV_DB_SCALE(out_tlv, -4650, 150, 0);
@@ -234,6 +234,14 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
return 0;
}
+static const unsigned int wm9713_mixer_mute_regs[] = {
+ AC97_PC_BEEP,
+ AC97_MASTER_TONE,
+ AC97_PHONE,
+ AC97_REC_SEL,
+ AC97_PCM,
+ AC97_AUX,
+};
/* We have to create a fake left and right HP mixers because
* the codec only has a single control that is shared by both channels.
@@ -241,73 +249,95 @@ static int wm9713_voice_shutdown(struct snd_soc_dapm_widget *w,
* register map, thus we add a new (virtual) register to help determine the
* audio route within the device.
*/
-static int mixer_event(struct snd_soc_dapm_widget *w,
- struct snd_kcontrol *kcontrol, int event)
+static int wm9713_hp_mixer_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
{
- u16 l, r, beep, tone, phone, rec, pcm, aux;
-
- l = ac97_read(w->codec, HPL_MIXER);
- r = ac97_read(w->codec, HPR_MIXER);
- beep = ac97_read(w->codec, AC97_PC_BEEP);
- tone = ac97_read(w->codec, AC97_MASTER_TONE);
- phone = ac97_read(w->codec, AC97_PHONE);
- rec = ac97_read(w->codec, AC97_REC_SEL);
- pcm = ac97_read(w->codec, AC97_PCM);
- aux = ac97_read(w->codec, AC97_AUX);
-
- if (event & SND_SOC_DAPM_PRE_REG)
- return 0;
- if ((l & 0x1) || (r & 0x1))
- ac97_write(w->codec, AC97_PC_BEEP, beep & 0x7fff);
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+ unsigned int val = ucontrol->value.enumerated.item[0];
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int mixer, mask, shift, old;
+ struct snd_soc_dapm_update update;
+ bool change;
+
+ mixer = mc->shift >> 8;
+ shift = mc->shift & 0xff;
+ mask = (1 << shift);
+
+ mutex_lock(&wm9713->lock);
+ old = wm9713->hp_mixer[mixer];
+ if (ucontrol->value.enumerated.item[0])
+ wm9713->hp_mixer[mixer] |= mask;
else
- ac97_write(w->codec, AC97_PC_BEEP, beep | 0x8000);
+ wm9713->hp_mixer[mixer] &= ~mask;
+
+ change = old != wm9713->hp_mixer[mixer];
+ if (change) {
+ update.kcontrol = kcontrol;
+ update.reg = wm9713_mixer_mute_regs[shift];
+ update.mask = 0x8000;
+ if ((wm9713->hp_mixer[0] & mask) ||
+ (wm9713->hp_mixer[1] & mask))
+ update.val = 0x0;
+ else
+ update.val = 0x8000;
+
+ snd_soc_dapm_mixer_update_power(dapm, kcontrol, val,
+ &update);
+ }
- if ((l & 0x2) || (r & 0x2))
- ac97_write(w->codec, AC97_MASTER_TONE, tone & 0x7fff);
- else
- ac97_write(w->codec, AC97_MASTER_TONE, tone | 0x8000);
+ mutex_unlock(&wm9713->lock);
- if ((l & 0x4) || (r & 0x4))
- ac97_write(w->codec, AC97_PHONE, phone & 0x7fff);
- else
- ac97_write(w->codec, AC97_PHONE, phone | 0x8000);
+ return change;
+}
- if ((l & 0x8) || (r & 0x8))
- ac97_write(w->codec, AC97_REC_SEL, rec & 0x7fff);
- else
- ac97_write(w->codec, AC97_REC_SEL, rec | 0x8000);
+static int wm9713_hp_mixer_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_dapm_context *dapm = snd_soc_dapm_kcontrol_dapm(kcontrol);
+ struct snd_soc_codec *codec = snd_soc_dapm_to_codec(dapm);
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int mixer, shift;
- if ((l & 0x10) || (r & 0x10))
- ac97_write(w->codec, AC97_PCM, pcm & 0x7fff);
- else
- ac97_write(w->codec, AC97_PCM, pcm | 0x8000);
+ mixer = mc->shift >> 8;
+ shift = mc->shift & 0xff;
- if ((l & 0x20) || (r & 0x20))
- ac97_write(w->codec, AC97_AUX, aux & 0x7fff);
- else
- ac97_write(w->codec, AC97_AUX, aux | 0x8000);
+ ucontrol->value.enumerated.item[0] =
+ (wm9713->hp_mixer[mixer] >> shift) & 1;
return 0;
}
+#define WM9713_HP_MIXER_CTRL(xname, xmixer, xshift) { \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_volsw, \
+ .get = wm9713_hp_mixer_get, .put = wm9713_hp_mixer_put, \
+ .private_value = SOC_DOUBLE_VALUE(SND_SOC_NOPM, \
+ xshift, xmixer, 1, 0, 0) \
+}
+
/* Left Headphone Mixers */
static const struct snd_kcontrol_new wm9713_hpl_mixer_controls[] = {
-SOC_DAPM_SINGLE("Beep Playback Switch", HPL_MIXER, 5, 1, 0),
-SOC_DAPM_SINGLE("Voice Playback Switch", HPL_MIXER, 4, 1, 0),
-SOC_DAPM_SINGLE("Aux Playback Switch", HPL_MIXER, 3, 1, 0),
-SOC_DAPM_SINGLE("PCM Playback Switch", HPL_MIXER, 2, 1, 0),
-SOC_DAPM_SINGLE("MonoIn Playback Switch", HPL_MIXER, 1, 1, 0),
-SOC_DAPM_SINGLE("Bypass Playback Switch", HPL_MIXER, 0, 1, 0),
+WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPL_MIXER, 5),
+WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPL_MIXER, 4),
+WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPL_MIXER, 3),
+WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPL_MIXER, 2),
+WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPL_MIXER, 1),
+WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPL_MIXER, 0),
};
/* Right Headphone Mixers */
static const struct snd_kcontrol_new wm9713_hpr_mixer_controls[] = {
-SOC_DAPM_SINGLE("Beep Playback Switch", HPR_MIXER, 5, 1, 0),
-SOC_DAPM_SINGLE("Voice Playback Switch", HPR_MIXER, 4, 1, 0),
-SOC_DAPM_SINGLE("Aux Playback Switch", HPR_MIXER, 3, 1, 0),
-SOC_DAPM_SINGLE("PCM Playback Switch", HPR_MIXER, 2, 1, 0),
-SOC_DAPM_SINGLE("MonoIn Playback Switch", HPR_MIXER, 1, 1, 0),
-SOC_DAPM_SINGLE("Bypass Playback Switch", HPR_MIXER, 0, 1, 0),
+WM9713_HP_MIXER_CTRL("Beep Playback Switch", HPR_MIXER, 5),
+WM9713_HP_MIXER_CTRL("Voice Playback Switch", HPR_MIXER, 4),
+WM9713_HP_MIXER_CTRL("Aux Playback Switch", HPR_MIXER, 3),
+WM9713_HP_MIXER_CTRL("PCM Playback Switch", HPR_MIXER, 2),
+WM9713_HP_MIXER_CTRL("MonoIn Playback Switch", HPR_MIXER, 1),
+WM9713_HP_MIXER_CTRL("Bypass Playback Switch", HPR_MIXER, 0),
};
/* headphone capture mux */
@@ -429,12 +459,10 @@ SND_SOC_DAPM_MUX("Mic A Source", SND_SOC_NOPM, 0, 0,
&wm9713_mic_sel_mux_controls),
SND_SOC_DAPM_MUX("Mic B Source", SND_SOC_NOPM, 0, 0,
&wm9713_micb_sel_mux_controls),
-SND_SOC_DAPM_MIXER_E("Left HP Mixer", AC97_EXTENDED_MID, 3, 1,
- &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls),
- mixer_event, SND_SOC_DAPM_POST_REG),
-SND_SOC_DAPM_MIXER_E("Right HP Mixer", AC97_EXTENDED_MID, 2, 1,
- &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls),
- mixer_event, SND_SOC_DAPM_POST_REG),
+SND_SOC_DAPM_MIXER("Left HP Mixer", AC97_EXTENDED_MID, 3, 1,
+ &wm9713_hpl_mixer_controls[0], ARRAY_SIZE(wm9713_hpl_mixer_controls)),
+SND_SOC_DAPM_MIXER("Right HP Mixer", AC97_EXTENDED_MID, 2, 1,
+ &wm9713_hpr_mixer_controls[0], ARRAY_SIZE(wm9713_hpr_mixer_controls)),
SND_SOC_DAPM_MIXER("Mono Mixer", AC97_EXTENDED_MID, 0, 1,
&wm9713_mono_mixer_controls[0], ARRAY_SIZE(wm9713_mono_mixer_controls)),
SND_SOC_DAPM_MIXER("Speaker Mixer", AC97_EXTENDED_MID, 1, 1,
@@ -647,12 +675,13 @@ static const struct snd_soc_dapm_route wm9713_audio_map[] = {
static unsigned int ac97_read(struct snd_soc_codec *codec,
unsigned int reg)
{
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
u16 *cache = codec->reg_cache;
if (reg == AC97_RESET || reg == AC97_GPIO_STATUS ||
reg == AC97_VENDOR_ID1 || reg == AC97_VENDOR_ID2 ||
reg == AC97_CD)
- return soc_ac97_ops->read(codec->ac97, reg);
+ return soc_ac97_ops->read(wm9713->ac97, reg);
else {
reg = reg >> 1;
@@ -666,9 +695,10 @@ static unsigned int ac97_read(struct snd_soc_codec *codec,
static int ac97_write(struct snd_soc_codec *codec, unsigned int reg,
unsigned int val)
{
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+
u16 *cache = codec->reg_cache;
- if (reg < 0x7c)
- soc_ac97_ops->write(codec->ac97, reg, val);
+ soc_ac97_ops->write(wm9713->ac97, reg, val);
reg = reg >> 1;
if (reg < (ARRAY_SIZE(wm9713_reg)))
cache[reg] = val;
@@ -689,7 +719,8 @@ struct _pll_div {
* to allow rounding later */
#define FIXED_PLL_SIZE ((1 << 22) * 10)
-static void pll_factors(struct _pll_div *pll_div, unsigned int source)
+static void pll_factors(struct snd_soc_codec *codec,
+ struct _pll_div *pll_div, unsigned int source)
{
u64 Kpart;
unsigned int K, Ndiv, Nmod, target;
@@ -724,7 +755,7 @@ static void pll_factors(struct _pll_div *pll_div, unsigned int source)
Ndiv = target / source;
if ((Ndiv < 5) || (Ndiv > 12))
- printk(KERN_WARNING
+ dev_warn(codec->dev,
"WM9713 PLL N value %u out of recommended range!\n",
Ndiv);
@@ -768,7 +799,7 @@ static int wm9713_set_pll(struct snd_soc_codec *codec,
return 0;
}
- pll_factors(&pll_div, freq_in);
+ pll_factors(codec, &pll_div, freq_in);
if (pll_div.k == 0) {
reg = (pll_div.n << 12) | (pll_div.lf << 11) |
@@ -1049,7 +1080,6 @@ static const struct snd_soc_dai_ops wm9713_dai_ops_voice = {
static struct snd_soc_dai_driver wm9713_dai[] = {
{
.name = "wm9713-hifi",
- .ac97_control = 1,
.playback = {
.stream_name = "HiFi Playback",
.channels_min = 1,
@@ -1095,17 +1125,22 @@ static struct snd_soc_dai_driver wm9713_dai[] = {
int wm9713_reset(struct snd_soc_codec *codec, int try_warm)
{
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
+
if (try_warm && soc_ac97_ops->warm_reset) {
- soc_ac97_ops->warm_reset(codec->ac97);
+ soc_ac97_ops->warm_reset(wm9713->ac97);
if (ac97_read(codec, 0) == wm9713_reg[0])
return 1;
}
- soc_ac97_ops->reset(codec->ac97);
+ soc_ac97_ops->reset(wm9713->ac97);
if (soc_ac97_ops->warm_reset)
- soc_ac97_ops->warm_reset(codec->ac97);
- if (ac97_read(codec, 0) != wm9713_reg[0])
+ soc_ac97_ops->warm_reset(wm9713->ac97);
+ if (ac97_read(codec, 0) != wm9713_reg[0]) {
+ dev_err(codec->dev, "Failed to reset: AC97 link error\n");
return -EIO;
+ }
+
return 0;
}
EXPORT_SYMBOL_GPL(wm9713_reset);
@@ -1163,10 +1198,8 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
u16 *cache = codec->reg_cache;
ret = wm9713_reset(codec, 1);
- if (ret < 0) {
- printk(KERN_ERR "could not reset AC97 codec\n");
+ if (ret < 0)
return ret;
- }
wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
@@ -1180,7 +1213,7 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
if (i == AC97_POWERDOWN || i == AC97_EXTENDED_MID ||
i == AC97_EXTENDED_MSTATUS || i > 0x66)
continue;
- soc_ac97_ops->write(codec->ac97, i, cache[i>>1]);
+ soc_ac97_ops->write(wm9713->ac97, i, cache[i>>1]);
}
}
@@ -1189,50 +1222,36 @@ static int wm9713_soc_resume(struct snd_soc_codec *codec)
static int wm9713_soc_probe(struct snd_soc_codec *codec)
{
- struct wm9713_priv *wm9713;
+ struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
int ret = 0, reg;
- wm9713 = kzalloc(sizeof(struct wm9713_priv), GFP_KERNEL);
- if (wm9713 == NULL)
- return -ENOMEM;
- snd_soc_codec_set_drvdata(codec, wm9713);
-
- ret = snd_soc_new_ac97_codec(codec, soc_ac97_ops, 0);
- if (ret < 0)
- goto codec_err;
+ wm9713->ac97 = snd_soc_new_ac97_codec(codec);
+ if (IS_ERR(wm9713->ac97))
+ return PTR_ERR(wm9713->ac97);
/* do a cold reset for the controller and then try
* a warm reset followed by an optional cold reset for codec */
wm9713_reset(codec, 0);
ret = wm9713_reset(codec, 1);
- if (ret < 0) {
- printk(KERN_ERR "Failed to reset WM9713: AC97 link error\n");
+ if (ret < 0)
goto reset_err;
- }
-
- wm9713_set_bias_level(codec, SND_SOC_BIAS_STANDBY);
/* unmute the adc - move to kcontrol */
reg = ac97_read(codec, AC97_CD) & 0x7fff;
ac97_write(codec, AC97_CD, reg);
- snd_soc_add_codec_controls(codec, wm9713_snd_ac97_controls,
- ARRAY_SIZE(wm9713_snd_ac97_controls));
-
return 0;
reset_err:
- snd_soc_free_ac97_codec(codec);
-codec_err:
- kfree(wm9713);
+ snd_soc_free_ac97_codec(wm9713->ac97);
return ret;
}
static int wm9713_soc_remove(struct snd_soc_codec *codec)
{
struct wm9713_priv *wm9713 = snd_soc_codec_get_drvdata(codec);
- snd_soc_free_ac97_codec(codec);
- kfree(wm9713);
+
+ snd_soc_free_ac97_codec(wm9713->ac97);
return 0;
}
@@ -1248,6 +1267,9 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
.reg_word_size = sizeof(u16),
.reg_cache_step = 2,
.reg_cache_default = wm9713_reg,
+
+ .controls = wm9713_snd_ac97_controls,
+ .num_controls = ARRAY_SIZE(wm9713_snd_ac97_controls),
.dapm_widgets = wm9713_dapm_widgets,
.num_dapm_widgets = ARRAY_SIZE(wm9713_dapm_widgets),
.dapm_routes = wm9713_audio_map,
@@ -1256,6 +1278,16 @@ static struct snd_soc_codec_driver soc_codec_dev_wm9713 = {
static int wm9713_probe(struct platform_device *pdev)
{
+ struct wm9713_priv *wm9713;
+
+ wm9713 = devm_kzalloc(&pdev->dev, sizeof(*wm9713), GFP_KERNEL);
+ if (wm9713 == NULL)
+ return -ENOMEM;
+
+ mutex_init(&wm9713->lock);
+
+ platform_set_drvdata(pdev, wm9713);
+
return snd_soc_register_codec(&pdev->dev,
&soc_codec_dev_wm9713, wm9713_dai, ARRAY_SIZE(wm9713_dai));
}
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c
index 6712478..720d6e8 100644
--- a/sound/soc/codecs/wm_adsp.c
+++ b/sound/soc/codecs/wm_adsp.c
@@ -21,6 +21,7 @@
#include <linux/regmap.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
+#include <linux/vmalloc.h>
#include <linux/workqueue.h>
#include <sound/core.h>
#include <sound/pcm.h>
@@ -169,11 +170,12 @@ static struct wm_adsp_buf *wm_adsp_buf_alloc(const void *src, size_t len,
if (buf == NULL)
return NULL;
- buf->buf = kmemdup(src, len, GFP_KERNEL | GFP_DMA);
+ buf->buf = vmalloc(len);
if (!buf->buf) {
- kfree(buf);
+ vfree(buf);
return NULL;
}
+ memcpy(buf->buf, src, len);
if (list)
list_add_tail(&buf->list, list);
@@ -188,7 +190,7 @@ static void wm_adsp_buf_free(struct list_head *list)
struct wm_adsp_buf,
list);
list_del(&buf->list);
- kfree(buf->buf);
+ vfree(buf->buf);
kfree(buf);
}
}
@@ -684,38 +686,24 @@ static int wm_adsp_load(struct wm_adsp *dsp)
}
if (reg) {
- size_t to_write = PAGE_SIZE;
- size_t remain = le32_to_cpu(region->len);
- const u8 *data = region->data;
-
- while (remain > 0) {
- if (remain < PAGE_SIZE)
- to_write = remain;
-
- buf = wm_adsp_buf_alloc(data,
- to_write,
- &buf_list);
- if (!buf) {
- adsp_err(dsp, "Out of memory\n");
- ret = -ENOMEM;
- goto out_fw;
- }
-
- ret = regmap_raw_write_async(regmap, reg,
- buf->buf,
- to_write);
- if (ret != 0) {
- adsp_err(dsp,
- "%s.%d: Failed to write %zd bytes at %d in %s: %d\n",
- file, regions,
- to_write, offset,
- region_name, ret);
- goto out_fw;
- }
+ buf = wm_adsp_buf_alloc(region->data,
+ le32_to_cpu(region->len),
+ &buf_list);
+ if (!buf) {
+ adsp_err(dsp, "Out of memory\n");
+ ret = -ENOMEM;
+ goto out_fw;
+ }
- data += to_write;
- reg += to_write / 2;
- remain -= to_write;
+ ret = regmap_raw_write_async(regmap, reg, buf->buf,
+ le32_to_cpu(region->len));
+ if (ret != 0) {
+ adsp_err(dsp,
+ "%s.%d: Failed to write %d bytes at %d in %s: %d\n",
+ file, regions,
+ le32_to_cpu(region->len), offset,
+ region_name, ret);
+ goto out_fw;
}
}
@@ -1065,8 +1053,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
be32_to_cpu(adsp1_alg[i].zm));
region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
+ if (!region) {
+ ret = -ENOMEM;
+ goto out;
+ }
region->type = WMFW_ADSP1_DM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].dm);
@@ -1083,8 +1073,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
}
region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
+ if (!region) {
+ ret = -ENOMEM;
+ goto out;
+ }
region->type = WMFW_ADSP1_ZM;
region->alg = be32_to_cpu(adsp1_alg[i].alg.id);
region->base = be32_to_cpu(adsp1_alg[i].zm);
@@ -1113,8 +1105,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
be32_to_cpu(adsp2_alg[i].zm));
region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
+ if (!region) {
+ ret = -ENOMEM;
+ goto out;
+ }
region->type = WMFW_ADSP2_XM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].xm);
@@ -1131,8 +1125,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
}
region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
+ if (!region) {
+ ret = -ENOMEM;
+ goto out;
+ }
region->type = WMFW_ADSP2_YM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].ym);
@@ -1149,8 +1145,10 @@ static int wm_adsp_setup_algs(struct wm_adsp *dsp)
}
region = kzalloc(sizeof(*region), GFP_KERNEL);
- if (!region)
- return -ENOMEM;
+ if (!region) {
+ ret = -ENOMEM;
+ goto out;
+ }
region->type = WMFW_ADSP2_ZM;
region->alg = be32_to_cpu(adsp2_alg[i].alg.id);
region->base = be32_to_cpu(adsp2_alg[i].zm);
@@ -1595,13 +1593,6 @@ static void wm_adsp2_boot_work(struct work_struct *work)
if (ret != 0)
goto err;
- ret = regmap_update_bits_async(dsp->regmap,
- dsp->base + ADSP2_CONTROL,
- ADSP2_CORE_ENA,
- ADSP2_CORE_ENA);
- if (ret != 0)
- goto err;
-
dsp->running = true;
return;
@@ -1651,8 +1642,8 @@ int wm_adsp2_event(struct snd_soc_dapm_widget *w,
ret = regmap_update_bits(dsp->regmap,
dsp->base + ADSP2_CONTROL,
- ADSP2_START,
- ADSP2_START);
+ ADSP2_CORE_ENA | ADSP2_START,
+ ADSP2_CORE_ENA | ADSP2_START);
if (ret != 0)
goto err;
break;
diff --git a/sound/soc/davinci/davinci-mcasp.c b/sound/soc/davinci/davinci-mcasp.c
index 0eed9b1..0dab382 100644
--- a/sound/soc/davinci/davinci-mcasp.c
+++ b/sound/soc/davinci/davinci-mcasp.c
@@ -70,6 +70,7 @@ struct davinci_mcasp {
void __iomem *base;
u32 fifo_base;
struct device *dev;
+ struct snd_pcm_substream *substreams[2];
/* McASP specific data */
int tdm_slots;
@@ -80,6 +81,7 @@ struct davinci_mcasp {
u8 bclk_div;
u16 bclk_lrclk_ratio;
int streams;
+ u32 irq_request[2];
int sysclk_freq;
bool bclk_master;
@@ -90,6 +92,9 @@ struct davinci_mcasp {
bool dat_port;
+ /* Used for comstraint setting on the second stream */
+ u32 channels;
+
#ifdef CONFIG_PM_SLEEP
struct davinci_mcasp_context context;
#endif
@@ -154,9 +159,16 @@ static bool mcasp_is_synchronous(struct davinci_mcasp *mcasp)
static void mcasp_start_rx(struct davinci_mcasp *mcasp)
{
+ if (mcasp->rxnumevt) { /* enable FIFO */
+ u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
+ }
+
+ /* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXCLKRST);
-
/*
* When ASYNC == 0 the transmit and receive sections operate
* synchronously from the transmit clock and frame sync. We need to make
@@ -167,74 +179,69 @@ static void mcasp_start_rx(struct davinci_mcasp *mcasp)
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
}
+ /* Activate serializer(s) */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSERCLR);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
-
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_RXBUF_REG, 0);
-
+ /* Release RX state machine */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXSMRST);
+ /* Release Frame Sync generator */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, RXFSRST);
-
if (mcasp_is_synchronous(mcasp))
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+
+ /* enable receive IRQs */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
+ mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
}
static void mcasp_start_tx(struct davinci_mcasp *mcasp)
{
- u8 offset = 0, i;
u32 cnt;
+ if (mcasp->txnumevt) { /* enable FIFO */
+ u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
+ }
+
+ /* Start clocks */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXHCLKRST);
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXCLKRST);
+ /* Activate serializer(s) */
mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSERCLR);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
- mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
- for (i = 0; i < mcasp->num_serializer; i++) {
- if (mcasp->serial_dir[i] == TX_MODE) {
- offset = i;
- break;
- }
- }
-
- /* wait for TX ready */
+ /* wait for XDATA to be cleared */
cnt = 0;
- while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_XRSRCTL_REG(offset)) &
- TXSTATE) && (cnt < 100000))
+ while (!(mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG) &
+ ~XRDATA) && (cnt < 100000))
cnt++;
- mcasp_set_reg(mcasp, DAVINCI_MCASP_TXBUF_REG, 0);
+ /* Release TX state machine */
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXSMRST);
+ /* Release Frame Sync generator */
+ mcasp_set_ctl_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, TXFSRST);
+
+ /* enable transmit IRQs */
+ mcasp_set_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
+ mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
}
static void davinci_mcasp_start(struct davinci_mcasp *mcasp, int stream)
{
- u32 reg;
-
mcasp->streams++;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (mcasp->txnumevt) { /* enable FIFO */
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
- mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
- }
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
mcasp_start_tx(mcasp);
- } else {
- if (mcasp->rxnumevt) { /* enable FIFO */
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
- mcasp_set_bits(mcasp, reg, FIFO_ENABLE);
- }
+ else
mcasp_start_rx(mcasp);
- }
}
static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
{
+ /* disable IRQ sources */
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLR_REG,
+ mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE]);
+
/*
* In synchronous mode stop the TX clocks if no other stream is
* running
@@ -244,12 +251,22 @@ static void mcasp_stop_rx(struct davinci_mcasp *mcasp)
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLR_REG, 0);
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, 0xFFFFFFFF);
+
+ if (mcasp->rxnumevt) { /* disable FIFO */
+ u32 reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
+
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ }
}
static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
{
u32 val = 0;
+ /* disable IRQ sources */
+ mcasp_clr_bits(mcasp, DAVINCI_MCASP_EVTCTLX_REG,
+ mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK]);
+
/*
* In synchronous mode keep TX clocks running if the capture stream is
* still running.
@@ -259,27 +276,92 @@ static void mcasp_stop_tx(struct davinci_mcasp *mcasp)
mcasp_set_reg(mcasp, DAVINCI_MCASP_GBLCTLX_REG, val);
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, 0xFFFFFFFF);
+
+ if (mcasp->txnumevt) { /* disable FIFO */
+ u32 reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
+
+ mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
+ }
}
static void davinci_mcasp_stop(struct davinci_mcasp *mcasp, int stream)
{
- u32 reg;
-
mcasp->streams--;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
- if (mcasp->txnumevt) { /* disable FIFO */
- reg = mcasp->fifo_base + MCASP_WFIFOCTL_OFFSET;
- mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
- }
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
mcasp_stop_tx(mcasp);
- } else {
- if (mcasp->rxnumevt) { /* disable FIFO */
- reg = mcasp->fifo_base + MCASP_RFIFOCTL_OFFSET;
- mcasp_clr_bits(mcasp, reg, FIFO_ENABLE);
- }
+ else
mcasp_stop_rx(mcasp);
+}
+
+static irqreturn_t davinci_mcasp_tx_irq_handler(int irq, void *data)
+{
+ struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+ struct snd_pcm_substream *substream;
+ u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK];
+ u32 handled_mask = 0;
+ u32 stat;
+
+ stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG);
+ if (stat & XUNDRN & irq_mask) {
+ dev_warn(mcasp->dev, "Transmit buffer underflow\n");
+ handled_mask |= XUNDRN;
+
+ substream = mcasp->substreams[SNDRV_PCM_STREAM_PLAYBACK];
+ if (substream) {
+ snd_pcm_stream_lock_irq(substream);
+ if (snd_pcm_running(substream))
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irq(substream);
+ }
}
+
+ if (!handled_mask)
+ dev_warn(mcasp->dev, "unhandled tx event. txstat: 0x%08x\n",
+ stat);
+
+ if (stat & XRERR)
+ handled_mask |= XRERR;
+
+ /* Ack the handled event only */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_TXSTAT_REG, handled_mask);
+
+ return IRQ_RETVAL(handled_mask);
+}
+
+static irqreturn_t davinci_mcasp_rx_irq_handler(int irq, void *data)
+{
+ struct davinci_mcasp *mcasp = (struct davinci_mcasp *)data;
+ struct snd_pcm_substream *substream;
+ u32 irq_mask = mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE];
+ u32 handled_mask = 0;
+ u32 stat;
+
+ stat = mcasp_get_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG);
+ if (stat & ROVRN & irq_mask) {
+ dev_warn(mcasp->dev, "Receive buffer overflow\n");
+ handled_mask |= ROVRN;
+
+ substream = mcasp->substreams[SNDRV_PCM_STREAM_CAPTURE];
+ if (substream) {
+ snd_pcm_stream_lock_irq(substream);
+ if (snd_pcm_running(substream))
+ snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ snd_pcm_stream_unlock_irq(substream);
+ }
+ }
+
+ if (!handled_mask)
+ dev_warn(mcasp->dev, "unhandled rx event. rxstat: 0x%08x\n",
+ stat);
+
+ if (stat & XRERR)
+ handled_mask |= XRERR;
+
+ /* Ack the handled event only */
+ mcasp_set_reg(mcasp, DAVINCI_MCASP_RXSTAT_REG, handled_mask);
+
+ return IRQ_RETVAL(handled_mask);
}
static int davinci_mcasp_set_dai_fmt(struct snd_soc_dai *cpu_dai,
@@ -500,8 +582,17 @@ static int davinci_config_channel_size(struct davinci_mcasp *mcasp,
* both left and right channels), so it has to be divided by number of
* tdm-slots (for I2S - divided by 2).
*/
- if (mcasp->bclk_lrclk_ratio)
- word_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
+ if (mcasp->bclk_lrclk_ratio) {
+ u32 slot_length = mcasp->bclk_lrclk_ratio / mcasp->tdm_slots;
+
+ /*
+ * When we have more bclk then it is needed for the data, we
+ * need to use the rotation to move the received samples to have
+ * correct alignment.
+ */
+ rx_rotate = (slot_length - word_length) / 4;
+ word_length = slot_length;
+ }
/* mapping of the XSSZ bit-field as described in the datasheet */
fmt = (word_length >> 1) - 1;
@@ -635,19 +726,29 @@ static int mcasp_common_hw_param(struct davinci_mcasp *mcasp, int stream,
return 0;
}
-static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
+static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream,
+ int channels)
{
int i, active_slots;
+ int total_slots;
+ int active_serializers;
u32 mask = 0;
u32 busel = 0;
- if ((mcasp->tdm_slots < 2) || (mcasp->tdm_slots > 32)) {
- dev_err(mcasp->dev, "tdm slot %d not supported\n",
- mcasp->tdm_slots);
- return -EINVAL;
- }
+ total_slots = mcasp->tdm_slots;
+
+ /*
+ * If more than one serializer is needed, then use them with
+ * their specified tdm_slots count. Otherwise, one serializer
+ * can cope with the transaction using as many slots as channels
+ * in the stream, requires channels symmetry
+ */
+ active_serializers = (channels + total_slots - 1) / total_slots;
+ if (active_serializers == 1)
+ active_slots = channels;
+ else
+ active_slots = total_slots;
- active_slots = (mcasp->tdm_slots > 31) ? 32 : mcasp->tdm_slots;
for (i = 0; i < active_slots; i++)
mask |= (1 << i);
@@ -659,12 +760,12 @@ static int mcasp_i2s_hw_param(struct davinci_mcasp *mcasp, int stream)
mcasp_set_reg(mcasp, DAVINCI_MCASP_TXTDM_REG, mask);
mcasp_set_bits(mcasp, DAVINCI_MCASP_TXFMT_REG, busel | TXORD);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_TXFMCTL_REG,
- FSXMOD(mcasp->tdm_slots), FSXMOD(0x1FF));
+ FSXMOD(total_slots), FSXMOD(0x1FF));
mcasp_set_reg(mcasp, DAVINCI_MCASP_RXTDM_REG, mask);
mcasp_set_bits(mcasp, DAVINCI_MCASP_RXFMT_REG, busel | RXORD);
mcasp_mod_bits(mcasp, DAVINCI_MCASP_RXFMCTL_REG,
- FSRMOD(mcasp->tdm_slots), FSRMOD(0x1FF));
+ FSRMOD(total_slots), FSRMOD(0x1FF));
return 0;
}
@@ -778,7 +879,8 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
ret = mcasp_dit_hw_param(mcasp, params_rate(params));
else
- ret = mcasp_i2s_hw_param(mcasp, substream->stream);
+ ret = mcasp_i2s_hw_param(mcasp, substream->stream,
+ channels);
if (ret)
return ret;
@@ -826,6 +928,9 @@ static int davinci_mcasp_hw_params(struct snd_pcm_substream *substream,
davinci_config_channel_size(mcasp, word_length);
+ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE)
+ mcasp->channels = channels;
+
return 0;
}
@@ -854,7 +959,65 @@ static int davinci_mcasp_trigger(struct snd_pcm_substream *substream,
return ret;
}
+static int davinci_mcasp_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+ u32 max_channels = 0;
+ int i, dir;
+
+ mcasp->substreams[substream->stream] = substream;
+
+ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+ return 0;
+
+ /*
+ * Limit the maximum allowed channels for the first stream:
+ * number of serializers for the direction * tdm slots per serializer
+ */
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ dir = TX_MODE;
+ else
+ dir = RX_MODE;
+
+ for (i = 0; i < mcasp->num_serializer; i++) {
+ if (mcasp->serial_dir[i] == dir)
+ max_channels++;
+ }
+ max_channels *= mcasp->tdm_slots;
+ /*
+ * If the already active stream has less channels than the calculated
+ * limnit based on the seirializers * tdm_slots, we need to use that as
+ * a constraint for the second stream.
+ * Otherwise (first stream or less allowed channels) we use the
+ * calculated constraint.
+ */
+ if (mcasp->channels && mcasp->channels < max_channels)
+ max_channels = mcasp->channels;
+
+ snd_pcm_hw_constraint_minmax(substream->runtime,
+ SNDRV_PCM_HW_PARAM_CHANNELS,
+ 2, max_channels);
+ return 0;
+}
+
+static void davinci_mcasp_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *cpu_dai)
+{
+ struct davinci_mcasp *mcasp = snd_soc_dai_get_drvdata(cpu_dai);
+
+ mcasp->substreams[substream->stream] = NULL;
+
+ if (mcasp->op_mode == DAVINCI_MCASP_DIT_MODE)
+ return;
+
+ if (!cpu_dai->active)
+ mcasp->channels = 0;
+}
+
static const struct snd_soc_dai_ops davinci_mcasp_dai_ops = {
+ .startup = davinci_mcasp_startup,
+ .shutdown = davinci_mcasp_shutdown,
.trigger = davinci_mcasp_trigger,
.hw_params = davinci_mcasp_hw_params,
.set_fmt = davinci_mcasp_set_dai_fmt,
@@ -971,6 +1134,7 @@ static struct snd_soc_dai_driver davinci_mcasp_dai[] = {
},
.ops = &davinci_mcasp_dai_ops,
+ .symmetric_samplebits = 1,
},
{
.name = "davinci-mcasp.1",
@@ -1194,6 +1358,8 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
struct resource *mem, *ioarea, *res, *dat;
struct davinci_mcasp_pdata *pdata;
struct davinci_mcasp *mcasp;
+ char *irq_name;
+ int irq;
int ret;
if (!pdev->dev.platform_data && !pdev->dev.of_node) {
@@ -1235,6 +1401,7 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
ret = pm_runtime_get_sync(&pdev->dev);
if (IS_ERR_VALUE(ret)) {
dev_err(&pdev->dev, "pm_runtime_get_sync() failed\n");
+ pm_runtime_disable(&pdev->dev);
return ret;
}
@@ -1246,7 +1413,21 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
}
mcasp->op_mode = pdata->op_mode;
- mcasp->tdm_slots = pdata->tdm_slots;
+ /* sanity check for tdm slots parameter */
+ if (mcasp->op_mode == DAVINCI_MCASP_IIS_MODE) {
+ if (pdata->tdm_slots < 2) {
+ dev_err(&pdev->dev, "invalid tdm slots: %d\n",
+ pdata->tdm_slots);
+ mcasp->tdm_slots = 2;
+ } else if (pdata->tdm_slots > 32) {
+ dev_err(&pdev->dev, "invalid tdm slots: %d\n",
+ pdata->tdm_slots);
+ mcasp->tdm_slots = 32;
+ } else {
+ mcasp->tdm_slots = pdata->tdm_slots;
+ }
+ }
+
mcasp->num_serializer = pdata->num_serializer;
#ifdef CONFIG_PM_SLEEP
mcasp->context.xrsr_regs = devm_kzalloc(&pdev->dev,
@@ -1260,6 +1441,36 @@ static int davinci_mcasp_probe(struct platform_device *pdev)
mcasp->dev = &pdev->dev;
+ irq = platform_get_irq_byname(pdev, "rx");
+ if (irq >= 0) {
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_rx\n",
+ dev_name(&pdev->dev));
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ davinci_mcasp_rx_irq_handler,
+ IRQF_ONESHOT, irq_name, mcasp);
+ if (ret) {
+ dev_err(&pdev->dev, "RX IRQ request failed\n");
+ goto err;
+ }
+
+ mcasp->irq_request[SNDRV_PCM_STREAM_CAPTURE] = ROVRN;
+ }
+
+ irq = platform_get_irq_byname(pdev, "tx");
+ if (irq >= 0) {
+ irq_name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%s_tx\n",
+ dev_name(&pdev->dev));
+ ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
+ davinci_mcasp_tx_irq_handler,
+ IRQF_ONESHOT, irq_name, mcasp);
+ if (ret) {
+ dev_err(&pdev->dev, "TX IRQ request failed\n");
+ goto err;
+ }
+
+ mcasp->irq_request[SNDRV_PCM_STREAM_PLAYBACK] = XUNDRN;
+ }
+
dat = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dat");
if (dat)
mcasp->dat_port = true;
diff --git a/sound/soc/davinci/davinci-mcasp.h b/sound/soc/davinci/davinci-mcasp.h
index 98fbc45..79dc511 100644
--- a/sound/soc/davinci/davinci-mcasp.h
+++ b/sound/soc/davinci/davinci-mcasp.h
@@ -253,6 +253,13 @@
#define TXFSRST BIT(12) /* Frame Sync Generator Reset */
/*
+ * DAVINCI_MCASP_TXSTAT_REG - Transmitter Status Register Bits
+ * DAVINCI_MCASP_RXSTAT_REG - Receiver Status Register Bits
+ */
+#define XRERR BIT(8) /* Transmit/Receive error */
+#define XRDATA BIT(5) /* Transmit/Receive data ready */
+
+/*
* DAVINCI_MCASP_AMUTE_REG - Mute Control Register Bits
*/
#define MUTENA(val) (val)
@@ -279,6 +286,16 @@
#define TXDATADMADIS BIT(0)
/*
+ * DAVINCI_MCASP_EVTCTLR_REG - Receiver Interrupt Control Register Bits
+ */
+#define ROVRN BIT(0)
+
+/*
+ * DAVINCI_MCASP_EVTCTLX_REG - Transmitter Interrupt Control Register Bits
+ */
+#define XUNDRN BIT(0)
+
+/*
* DAVINCI_MCASP_W[R]FIFOCTL - Write/Read FIFO Control Register bits
*/
#define FIFO_ENABLE BIT(16)
diff --git a/sound/soc/dwc/designware_i2s.c b/sound/soc/dwc/designware_i2s.c
index e961388..08f0229 100644
--- a/sound/soc/dwc/designware_i2s.c
+++ b/sound/soc/dwc/designware_i2s.c
@@ -338,31 +338,34 @@ static int dw_i2s_probe(struct platform_device *pdev)
return -EINVAL;
}
- res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!res) {
- dev_err(&pdev->dev, "no i2s resource defined\n");
- return -ENODEV;
- }
-
- if (!devm_request_mem_region(&pdev->dev, res->start,
- resource_size(res), pdev->name)) {
- dev_err(&pdev->dev, "i2s region already claimed\n");
- return -EBUSY;
- }
-
dev = devm_kzalloc(&pdev->dev, sizeof(*dev), GFP_KERNEL);
if (!dev) {
dev_warn(&pdev->dev, "kzalloc fail\n");
return -ENOMEM;
}
- dev->i2s_base = devm_ioremap(&pdev->dev, res->start,
- resource_size(res));
- if (!dev->i2s_base) {
- dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+ dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
+ if (!dw_i2s_dai) {
+ dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
return -ENOMEM;
}
+ dw_i2s_dai->ops = &dw_i2s_dai_ops;
+ dw_i2s_dai->suspend = dw_i2s_suspend;
+ dw_i2s_dai->resume = dw_i2s_resume;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "no i2s resource defined\n");
+ return -ENODEV;
+ }
+
+ dev->i2s_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(dev->i2s_base)) {
+ dev_err(&pdev->dev, "ioremap fail for i2s_region\n");
+ return PTR_ERR(dev->i2s_base);
+ }
+
cap = pdata->cap;
dev->capability = cap;
dev->i2s_clk_cfg = pdata->i2s_clk_cfg;
@@ -388,13 +391,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
if (ret < 0)
goto err_clk_put;
- dw_i2s_dai = devm_kzalloc(&pdev->dev, sizeof(*dw_i2s_dai), GFP_KERNEL);
- if (!dw_i2s_dai) {
- dev_err(&pdev->dev, "mem allocation failed for dai driver\n");
- ret = -ENOMEM;
- goto err_clk_disable;
- }
-
if (cap & DWC_I2S_PLAY) {
dev_dbg(&pdev->dev, " designware: play supported\n");
dw_i2s_dai->playback.channels_min = MIN_CHANNEL_NUM;
@@ -411,10 +407,6 @@ static int dw_i2s_probe(struct platform_device *pdev)
dw_i2s_dai->capture.rates = pdata->snd_rates;
}
- dw_i2s_dai->ops = &dw_i2s_dai_ops;
- dw_i2s_dai->suspend = dw_i2s_suspend;
- dw_i2s_dai->resume = dw_i2s_resume;
-
dev->dev = &pdev->dev;
dev_set_drvdata(&pdev->dev, dev);
ret = snd_soc_register_component(&pdev->dev, &dw_i2s_component,
diff --git a/sound/soc/fsl/eukrea-tlv320.c b/sound/soc/fsl/eukrea-tlv320.c
index eb093d5..b175b01 100644
--- a/sound/soc/fsl/eukrea-tlv320.c
+++ b/sound/soc/fsl/eukrea-tlv320.c
@@ -105,7 +105,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
int ret;
int int_port = 0, ext_port;
struct device_node *np = pdev->dev.of_node;
- struct device_node *ssi_np, *codec_np;
+ struct device_node *ssi_np = NULL, *codec_np = NULL;
eukrea_tlv320.dev = &pdev->dev;
if (np) {
@@ -217,8 +217,7 @@ static int eukrea_tlv320_probe(struct platform_device *pdev)
err:
if (ret)
dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
- if (np)
- of_node_put(ssi_np);
+ of_node_put(ssi_np);
return ret;
}
diff --git a/sound/soc/fsl/fsl-asoc-card.c b/sound/soc/fsl/fsl-asoc-card.c
index 007c772..3f6959c 100644
--- a/sound/soc/fsl/fsl-asoc-card.c
+++ b/sound/soc/fsl/fsl-asoc-card.c
@@ -51,6 +51,7 @@ struct codec_priv {
* @sysclk_freq[2]: SYSCLK rates for set_sysclk()
* @sysclk_dir[2]: SYSCLK directions for set_sysclk()
* @sysclk_id[2]: SYSCLK ids for set_sysclk()
+ * @slot_width: Slot width of each frame
*
* Note: [1] for tx and [0] for rx
*/
@@ -58,6 +59,7 @@ struct cpu_priv {
unsigned long sysclk_freq[2];
u32 sysclk_dir[2];
u32 sysclk_id[2];
+ u32 slot_width;
};
/**
@@ -125,7 +127,12 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
priv->sample_rate = params_rate(params);
priv->sample_format = params_format(params);
- if (priv->card.set_bias_level)
+ /*
+ * If codec-dai is DAI Master and all configurations are already in the
+ * set_bias_level(), bypass the remaining settings in hw_params().
+ * Note: (dai_fmt & CBM_CFM) includes CBM_CFM and CBM_CFS.
+ */
+ if (priv->card.set_bias_level && priv->dai_fmt & SND_SOC_DAIFMT_CBM_CFM)
return 0;
/* Specific configurations of DAIs starts from here */
@@ -137,6 +144,15 @@ static int fsl_asoc_card_hw_params(struct snd_pcm_substream *substream,
return ret;
}
+ if (cpu_priv->slot_width) {
+ ret = snd_soc_dai_set_tdm_slot(rtd->cpu_dai, 0x3, 0x3, 2,
+ cpu_priv->slot_width);
+ if (ret) {
+ dev_err(dev, "failed to set TDM slot for cpu dai\n");
+ return ret;
+ }
+ }
+
return 0;
}
@@ -448,6 +464,7 @@ static int fsl_asoc_card_probe(struct platform_device *pdev)
priv->cpu_priv.sysclk_freq[RX] = priv->codec_priv.mclk_freq;
priv->cpu_priv.sysclk_dir[TX] = SND_SOC_CLOCK_OUT;
priv->cpu_priv.sysclk_dir[RX] = SND_SOC_CLOCK_OUT;
+ priv->cpu_priv.slot_width = 32;
priv->dai_fmt |= SND_SOC_DAIFMT_CBS_CFS;
} else if (of_device_is_compatible(np, "fsl,imx-audio-sgtl5000")) {
priv->codec_priv.mclk_id = SGTL5000_SYSCLK;
diff --git a/sound/soc/fsl/fsl_dma.c b/sound/soc/fsl/fsl_dma.c
index a609aaf..b2b1088 100644
--- a/sound/soc/fsl/fsl_dma.c
+++ b/sound/soc/fsl/fsl_dma.c
@@ -151,14 +151,7 @@ static const struct snd_pcm_hardware fsl_dma_hardware = {
*/
static void fsl_dma_abort_stream(struct snd_pcm_substream *substream)
{
- unsigned long flags;
-
- snd_pcm_stream_lock_irqsave(substream, flags);
-
- if (snd_pcm_running(substream))
- snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
-
- snd_pcm_stream_unlock_irqrestore(substream, flags);
+ snd_pcm_stop_xrun(substream);
}
/**
diff --git a/sound/soc/fsl/fsl_esai.c b/sound/soc/fsl/fsl_esai.c
index a645e29..ca319d5 100644
--- a/sound/soc/fsl/fsl_esai.c
+++ b/sound/soc/fsl/fsl_esai.c
@@ -513,10 +513,15 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
u32 width = snd_pcm_format_width(params_format(params));
u32 channels = params_channels(params);
u32 pins = DIV_ROUND_UP(channels, esai_priv->slots);
+ u32 slot_width = width;
u32 bclk, mask, val;
int ret;
- bclk = params_rate(params) * esai_priv->slot_width * esai_priv->slots;
+ /* Override slot_width if being specifially set */
+ if (esai_priv->slot_width)
+ slot_width = esai_priv->slot_width;
+
+ bclk = params_rate(params) * slot_width * esai_priv->slots;
ret = fsl_esai_set_bclk(dai, tx, bclk);
if (ret)
@@ -538,7 +543,7 @@ static int fsl_esai_hw_params(struct snd_pcm_substream *substream,
regmap_update_bits(esai_priv->regmap, REG_ESAI_xFCR(tx), mask, val);
mask = ESAI_xCR_xSWS_MASK | (tx ? ESAI_xCR_PADC : 0);
- val = ESAI_xCR_xSWS(esai_priv->slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
+ val = ESAI_xCR_xSWS(slot_width, width) | (tx ? ESAI_xCR_PADC : 0);
regmap_update_bits(esai_priv->regmap, REG_ESAI_xCR(tx), mask, val);
@@ -780,9 +785,6 @@ static int fsl_esai_probe(struct platform_device *pdev)
return ret;
}
- /* Set a default slot size */
- esai_priv->slot_width = 32;
-
/* Set a default slot number */
esai_priv->slots = 2;
diff --git a/sound/soc/fsl/fsl_ssi.c b/sound/soc/fsl/fsl_ssi.c
index e695517..b6b0d25 100644
--- a/sound/soc/fsl/fsl_ssi.c
+++ b/sound/soc/fsl/fsl_ssi.c
@@ -67,8 +67,6 @@
/**
* FSLSSI_I2S_FORMATS: audio formats supported by the SSI
*
- * This driver currently only supports the SSI running in I2S slave mode.
- *
* The SSI has a limitation in that the samples must be in the same byte
* order as the host CPU. This is because when multiple bytes are written
* to the STX register, the bytes and bits must be written in the same
@@ -1099,7 +1097,7 @@ static const struct snd_soc_component_driver fsl_ssi_component = {
};
static struct snd_soc_dai_driver fsl_ssi_ac97_dai = {
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
@@ -1363,7 +1361,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
return PTR_ERR(ssi_private->regs);
}
- ssi_private->irq = irq_of_parse_and_map(np, 0);
+ ssi_private->irq = platform_get_irq(pdev, 0);
if (!ssi_private->irq) {
dev_err(&pdev->dev, "no irq for node %s\n", np->full_name);
return -ENXIO;
@@ -1389,7 +1387,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
if (ssi_private->soc->imx) {
ret = fsl_ssi_imx_probe(pdev, ssi_private, iomem);
if (ret)
- goto error_irqmap;
+ return ret;
}
ret = snd_soc_register_component(&pdev->dev, &fsl_ssi_component,
@@ -1412,7 +1410,7 @@ static int fsl_ssi_probe(struct platform_device *pdev)
ret = fsl_ssi_debugfs_create(&ssi_private->dbg_stats, &pdev->dev);
if (ret)
- goto error_asoc_register;
+ goto error_irq;
/*
* If codec-handle property is missing from SSI node, we assume
@@ -1460,10 +1458,6 @@ error_asoc_register:
if (ssi_private->soc->imx)
fsl_ssi_imx_clean(pdev, ssi_private);
-error_irqmap:
- if (ssi_private->use_dma)
- irq_dispose_mapping(ssi_private->irq);
-
return ret;
}
@@ -1480,9 +1474,6 @@ static int fsl_ssi_remove(struct platform_device *pdev)
if (ssi_private->soc->imx)
fsl_ssi_imx_clean(pdev, ssi_private);
- if (ssi_private->use_dma)
- irq_dispose_mapping(ssi_private->irq);
-
return 0;
}
diff --git a/sound/soc/fsl/imx-sgtl5000.c b/sound/soc/fsl/imx-sgtl5000.c
index 1cb22dd..1dab963 100644
--- a/sound/soc/fsl/imx-sgtl5000.c
+++ b/sound/soc/fsl/imx-sgtl5000.c
@@ -175,10 +175,8 @@ static int imx_sgtl5000_probe(struct platform_device *pdev)
fail:
if (data && !IS_ERR(data->codec_clk))
clk_put(data->codec_clk);
- if (ssi_np)
- of_node_put(ssi_np);
- if (codec_np)
- of_node_put(codec_np);
+ of_node_put(ssi_np);
+ of_node_put(codec_np);
return ret;
}
diff --git a/sound/soc/fsl/imx-spdif.c b/sound/soc/fsl/imx-spdif.c
index e1dc401..0c9068e 100644
--- a/sound/soc/fsl/imx-spdif.c
+++ b/sound/soc/fsl/imx-spdif.c
@@ -74,8 +74,7 @@ static int imx_spdif_audio_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, data);
end:
- if (spdif_np)
- of_node_put(spdif_np);
+ of_node_put(spdif_np);
return ret;
}
diff --git a/sound/soc/fsl/imx-ssi.c b/sound/soc/fsl/imx-ssi.c
index ab2fdd7..60b0a5b 100644
--- a/sound/soc/fsl/imx-ssi.c
+++ b/sound/soc/fsl/imx-ssi.c
@@ -382,7 +382,7 @@ static struct snd_soc_dai_driver imx_ssi_dai = {
static struct snd_soc_dai_driver imx_ac97_dai = {
.probe = imx_ssi_dai_probe,
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
diff --git a/sound/soc/fsl/imx-wm8962.c b/sound/soc/fsl/imx-wm8962.c
index 3a3d17c..48179ff 100644
--- a/sound/soc/fsl/imx-wm8962.c
+++ b/sound/soc/fsl/imx-wm8962.c
@@ -281,10 +281,8 @@ static int imx_wm8962_probe(struct platform_device *pdev)
clk_fail:
clk_disable_unprepare(data->codec_clk);
fail:
- if (ssi_np)
- of_node_put(ssi_np);
- if (codec_np)
- of_node_put(codec_np);
+ of_node_put(ssi_np);
+ of_node_put(codec_np);
return ret;
}
diff --git a/sound/soc/fsl/mpc5200_dma.c b/sound/soc/fsl/mpc5200_dma.c
index f2b5d75..0b82e20 100644
--- a/sound/soc/fsl/mpc5200_dma.c
+++ b/sound/soc/fsl/mpc5200_dma.c
@@ -327,9 +327,6 @@ static int psc_dma_new(struct snd_soc_pcm_runtime *rtd)
goto capture_alloc_err;
}
- if (rtd->codec->ac97)
- rtd->codec->ac97->private_data = psc_dma;
-
return 0;
capture_alloc_err:
diff --git a/sound/soc/fsl/mpc5200_psc_ac97.c b/sound/soc/fsl/mpc5200_psc_ac97.c
index 24eafa2..c6ed6ba 100644
--- a/sound/soc/fsl/mpc5200_psc_ac97.c
+++ b/sound/soc/fsl/mpc5200_psc_ac97.c
@@ -237,7 +237,7 @@ static const struct snd_soc_dai_ops psc_ac97_digital_ops = {
static struct snd_soc_dai_driver psc_ac97_dai[] = {
{
.name = "mpc5200-psc-ac97.0",
- .ac97_control = 1,
+ .bus_control = true,
.probe = psc_ac97_probe,
.playback = {
.stream_name = "AC97 Playback",
@@ -257,7 +257,7 @@ static struct snd_soc_dai_driver psc_ac97_dai[] = {
},
{
.name = "mpc5200-psc-ac97.1",
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.stream_name = "AC97 SPDIF",
.channels_min = 1,
@@ -282,7 +282,6 @@ static const struct snd_soc_component_driver psc_ac97_component = {
static int psc_ac97_of_probe(struct platform_device *op)
{
int rc;
- struct snd_ac97 ac97;
struct mpc52xx_psc __iomem *regs;
rc = mpc5200_audio_dma_create(op);
@@ -304,7 +303,6 @@ static int psc_ac97_of_probe(struct platform_device *op)
psc_dma = dev_get_drvdata(&op->dev);
regs = psc_dma->psc_regs;
- ac97.private_data = psc_dma;
psc_dma->imr = 0;
out_be16(&psc_dma->psc_regs->isr_imr.imr, psc_dma->imr);
diff --git a/sound/soc/generic/simple-card.c b/sound/soc/generic/simple-card.c
index d1b7293..ece22d5 100644
--- a/sound/soc/generic/simple-card.c
+++ b/sound/soc/generic/simple-card.c
@@ -29,7 +29,9 @@ struct simple_card_data {
} *dai_props;
unsigned int mclk_fs;
int gpio_hp_det;
+ int gpio_hp_det_invert;
int gpio_mic_det;
+ int gpio_mic_det_invert;
struct snd_soc_dai_link dai_link[]; /* dynamically allocated */
};
@@ -148,6 +150,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
simple_card_hp_jack_pins);
simple_card_hp_jack_gpio.gpio = priv->gpio_hp_det;
+ simple_card_hp_jack_gpio.invert = priv->gpio_hp_det_invert;
snd_soc_jack_add_gpios(&simple_card_hp_jack, 1,
&simple_card_hp_jack_gpio);
}
@@ -159,6 +162,7 @@ static int asoc_simple_card_dai_init(struct snd_soc_pcm_runtime *rtd)
ARRAY_SIZE(simple_card_mic_jack_pins),
simple_card_mic_jack_pins);
simple_card_mic_jack_gpio.gpio = priv->gpio_mic_det;
+ simple_card_mic_jack_gpio.invert = priv->gpio_mic_det_invert;
snd_soc_jack_add_gpios(&simple_card_mic_jack, 1,
&simple_card_mic_jack_gpio);
}
@@ -226,6 +230,52 @@ asoc_simple_card_sub_parse_of(struct device_node *np,
return 0;
}
+static int asoc_simple_card_parse_daifmt(struct device_node *node,
+ struct simple_card_data *priv,
+ struct device_node *codec,
+ char *prefix, int idx)
+{
+ struct device *dev = simple_priv_to_dev(priv);
+ struct device_node *bitclkmaster = NULL;
+ struct device_node *framemaster = NULL;
+ struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
+ struct asoc_simple_dai *cpu_dai = &dai_props->cpu_dai;
+ struct asoc_simple_dai *codec_dai = &dai_props->codec_dai;
+ unsigned int daifmt;
+
+ daifmt = snd_soc_of_parse_daifmt(node, prefix,
+ &bitclkmaster, &framemaster);
+ daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
+
+ if (strlen(prefix) && !bitclkmaster && !framemaster) {
+ /*
+ * No dai-link level and master setting was not found from
+ * sound node level, revert back to legacy DT parsing and
+ * take the settings from codec node.
+ */
+ dev_dbg(dev, "Revert to legacy daifmt parsing\n");
+
+ cpu_dai->fmt = codec_dai->fmt =
+ snd_soc_of_parse_daifmt(codec, NULL, NULL, NULL) |
+ (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
+ } else {
+ if (codec == bitclkmaster)
+ daifmt |= (codec == framemaster) ?
+ SND_SOC_DAIFMT_CBM_CFM : SND_SOC_DAIFMT_CBM_CFS;
+ else
+ daifmt |= (codec == framemaster) ?
+ SND_SOC_DAIFMT_CBS_CFM : SND_SOC_DAIFMT_CBS_CFS;
+
+ cpu_dai->fmt = daifmt;
+ codec_dai->fmt = daifmt;
+ }
+
+ of_node_put(bitclkmaster);
+ of_node_put(framemaster);
+
+ return 0;
+}
+
static int asoc_simple_card_dai_link_of(struct device_node *node,
struct simple_card_data *priv,
int idx,
@@ -234,10 +284,8 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
struct device *dev = simple_priv_to_dev(priv);
struct snd_soc_dai_link *dai_link = simple_priv_to_link(priv, idx);
struct simple_dai_props *dai_props = simple_priv_to_props(priv, idx);
- struct device_node *np = NULL;
- struct device_node *bitclkmaster = NULL;
- struct device_node *framemaster = NULL;
- unsigned int daifmt;
+ struct device_node *cpu = NULL;
+ struct device_node *codec = NULL;
char *name;
char prop[128];
char *prefix = "";
@@ -247,85 +295,36 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
if (is_top_level_node)
prefix = "simple-audio-card,";
- daifmt = snd_soc_of_parse_daifmt(node, prefix,
- &bitclkmaster, &framemaster);
- daifmt &= ~SND_SOC_DAIFMT_MASTER_MASK;
-
snprintf(prop, sizeof(prop), "%scpu", prefix);
- np = of_get_child_by_name(node, prop);
- if (!np) {
+ cpu = of_get_child_by_name(node, prop);
+
+ snprintf(prop, sizeof(prop), "%scodec", prefix);
+ codec = of_get_child_by_name(node, prop);
+
+ if (!cpu || !codec) {
ret = -EINVAL;
dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
goto dai_link_of_err;
}
- ret = asoc_simple_card_sub_parse_of(np, &dai_props->cpu_dai,
+ ret = asoc_simple_card_parse_daifmt(node, priv,
+ codec, prefix, idx);
+ if (ret < 0)
+ goto dai_link_of_err;
+
+ ret = asoc_simple_card_sub_parse_of(cpu, &dai_props->cpu_dai,
&dai_link->cpu_of_node,
&dai_link->cpu_dai_name,
&cpu_args);
if (ret < 0)
goto dai_link_of_err;
- dai_props->cpu_dai.fmt = daifmt;
- switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
- case 0x11:
- dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
- break;
- case 0x10:
- dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
- break;
- case 0x01:
- dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
- break;
- default:
- dai_props->cpu_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
- break;
- }
-
- of_node_put(np);
- snprintf(prop, sizeof(prop), "%scodec", prefix);
- np = of_get_child_by_name(node, prop);
- if (!np) {
- ret = -EINVAL;
- dev_err(dev, "%s: Can't find %s DT node\n", __func__, prop);
- goto dai_link_of_err;
- }
-
- ret = asoc_simple_card_sub_parse_of(np, &dai_props->codec_dai,
+ ret = asoc_simple_card_sub_parse_of(codec, &dai_props->codec_dai,
&dai_link->codec_of_node,
&dai_link->codec_dai_name, NULL);
if (ret < 0)
goto dai_link_of_err;
- if (strlen(prefix) && !bitclkmaster && !framemaster) {
- /*
- * No DAI link level and master setting was found
- * from sound node level, revert back to legacy DT
- * parsing and take the settings from codec node.
- */
- dev_dbg(dev, "%s: Revert to legacy daifmt parsing\n",
- __func__);
- dai_props->cpu_dai.fmt = dai_props->codec_dai.fmt =
- snd_soc_of_parse_daifmt(np, NULL, NULL, NULL) |
- (daifmt & ~SND_SOC_DAIFMT_CLOCK_MASK);
- } else {
- dai_props->codec_dai.fmt = daifmt;
- switch (((np == bitclkmaster) << 4) | (np == framemaster)) {
- case 0x11:
- dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFM;
- break;
- case 0x10:
- dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBM_CFS;
- break;
- case 0x01:
- dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFM;
- break;
- default:
- dai_props->codec_dai.fmt |= SND_SOC_DAIFMT_CBS_CFS;
- break;
- }
- }
-
if (!dai_link->cpu_dai_name || !dai_link->codec_dai_name) {
ret = -EINVAL;
goto dai_link_of_err;
@@ -368,12 +367,9 @@ static int asoc_simple_card_dai_link_of(struct device_node *node,
dai_link->cpu_dai_name = NULL;
dai_link_of_err:
- if (np)
- of_node_put(np);
- if (bitclkmaster)
- of_node_put(bitclkmaster);
- if (framemaster)
- of_node_put(framemaster);
+ of_node_put(cpu);
+ of_node_put(codec);
+
return ret;
}
@@ -381,6 +377,7 @@ static int asoc_simple_card_parse_of(struct device_node *node,
struct simple_card_data *priv)
{
struct device *dev = simple_priv_to_dev(priv);
+ enum of_gpio_flags flags;
u32 val;
int ret;
@@ -436,13 +433,15 @@ static int asoc_simple_card_parse_of(struct device_node *node,
return ret;
}
- priv->gpio_hp_det = of_get_named_gpio(node,
- "simple-audio-card,hp-det-gpio", 0);
+ priv->gpio_hp_det = of_get_named_gpio_flags(node,
+ "simple-audio-card,hp-det-gpio", 0, &flags);
+ priv->gpio_hp_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
if (priv->gpio_hp_det == -EPROBE_DEFER)
return -EPROBE_DEFER;
- priv->gpio_mic_det = of_get_named_gpio(node,
- "simple-audio-card,mic-det-gpio", 0);
+ priv->gpio_mic_det = of_get_named_gpio_flags(node,
+ "simple-audio-card,mic-det-gpio", 0, &flags);
+ priv->gpio_mic_det_invert = !!(flags & OF_GPIO_ACTIVE_LOW);
if (priv->gpio_mic_det == -EPROBE_DEFER)
return -EPROBE_DEFER;
@@ -457,18 +456,13 @@ static int asoc_simple_card_unref(struct platform_device *pdev)
{
struct snd_soc_card *card = platform_get_drvdata(pdev);
struct snd_soc_dai_link *dai_link;
- struct device_node *np;
int num_links;
for (num_links = 0, dai_link = card->dai_link;
num_links < card->num_links;
num_links++, dai_link++) {
- np = (struct device_node *) dai_link->cpu_of_node;
- if (np)
- of_node_put(np);
- np = (struct device_node *) dai_link->codec_of_node;
- if (np)
- of_node_put(np);
+ of_node_put(dai_link->cpu_of_node);
+ of_node_put(dai_link->codec_of_node);
}
return 0;
}
diff --git a/sound/soc/intel/Kconfig b/sound/soc/intel/Kconfig
index f5b4a9c7..e989ecf 100644
--- a/sound/soc/intel/Kconfig
+++ b/sound/soc/intel/Kconfig
@@ -3,6 +3,7 @@ config SND_MFLD_MACHINE
depends on INTEL_SCU_IPC
select SND_SOC_SN95031
select SND_SST_MFLD_PLATFORM
+ select SND_SST_IPC_PCI
help
This adds support for ASoC machine driver for Intel(R) MID Medfield platform
used as alsa device in audio substem in Intel(R) MID devices
@@ -12,10 +13,23 @@ config SND_MFLD_MACHINE
config SND_SST_MFLD_PLATFORM
tristate
+config SND_SST_IPC
+ tristate
+
+config SND_SST_IPC_PCI
+ tristate
+ select SND_SST_IPC
+
+config SND_SST_IPC_ACPI
+ tristate
+ select SND_SST_IPC
+ depends on ACPI
+
config SND_SOC_INTEL_SST
tristate "ASoC support for Intel(R) Smart Sound Technology"
select SND_SOC_INTEL_SST_ACPI if ACPI
depends on (X86 || COMPILE_TEST)
+ depends on DW_DMAC_CORE
help
This adds support for Intel(R) Smart Sound Technology (SST).
Say Y if you have such a device
@@ -32,7 +46,8 @@ config SND_SOC_INTEL_BAYTRAIL
config SND_SOC_INTEL_HASWELL_MACH
tristate "ASoC Audio DSP support for Intel Haswell Lynxpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && I2C && \\
+ I2C_DESIGNWARE_PLATFORM
select SND_SOC_INTEL_HASWELL
select SND_SOC_RT5640
help
@@ -61,7 +76,8 @@ config SND_SOC_INTEL_BYT_MAX98090_MACH
config SND_SOC_INTEL_BROADWELL_MACH
tristate "ASoC Audio DSP support for Intel Broadwell Wildcatpoint"
- depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC
+ depends on SND_SOC_INTEL_SST && X86_INTEL_LPSS && DW_DMAC && \\
+ I2C_DESIGNWARE_PLATFORM
select SND_SOC_INTEL_HASWELL
select SND_COMPRESS_OFFLOAD
select SND_SOC_RT286
@@ -70,3 +86,27 @@ config SND_SOC_INTEL_BROADWELL_MACH
Ultrabook platforms.
Say Y if you have such a device
If unsure select "N".
+
+config SND_SOC_INTEL_BYTCR_RT5640_MACH
+ tristate "ASoC Audio DSP Support for MID BYT Platform"
+ depends on X86
+ select SND_SOC_RT5640
+ select SND_SST_MFLD_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) MID Baytrail platform
+ used as alsa device in audio substem in Intel(R) MID devices
+ Say Y if you have such a device
+ If unsure select "N".
+
+config SND_SOC_INTEL_CHT_BSW_RT5672_MACH
+ tristate "ASoC Audio driver for Intel Cherrytrail & Braswell with RT5672 codec"
+ depends on X86_INTEL_LPSS
+ select SND_SOC_RT5670
+ select SND_SST_MFLD_PLATFORM
+ select SND_SST_IPC_ACPI
+ help
+ This adds support for ASoC machine driver for Intel(R) Cherrytrail & Braswell
+ platforms with RT5672 audio codec.
+ Say Y if you have such a device
+ If unsure select "N".
diff --git a/sound/soc/intel/Makefile b/sound/soc/intel/Makefile
index f841786..e928ec3 100644
--- a/sound/soc/intel/Makefile
+++ b/sound/soc/intel/Makefile
@@ -26,8 +26,15 @@ snd-soc-sst-haswell-objs := haswell.o
snd-soc-sst-byt-rt5640-mach-objs := byt-rt5640.o
snd-soc-sst-byt-max98090-mach-objs := byt-max98090.o
snd-soc-sst-broadwell-objs := broadwell.o
+snd-soc-sst-bytcr-dpcm-rt5640-objs := bytcr_dpcm_rt5640.o
+snd-soc-sst-cht-bsw-rt5672-objs := cht_bsw_rt5672.o
obj-$(CONFIG_SND_SOC_INTEL_HASWELL_MACH) += snd-soc-sst-haswell.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_RT5640_MACH) += snd-soc-sst-byt-rt5640-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BYT_MAX98090_MACH) += snd-soc-sst-byt-max98090-mach.o
obj-$(CONFIG_SND_SOC_INTEL_BROADWELL_MACH) += snd-soc-sst-broadwell.o
+obj-$(CONFIG_SND_SOC_INTEL_BYTCR_RT5640_MACH) += snd-soc-sst-bytcr-dpcm-rt5640.o
+obj-$(CONFIG_SND_SOC_INTEL_CHT_BSW_RT5672_MACH) += snd-soc-sst-cht-bsw-rt5672.o
+
+# DSP driver
+obj-$(CONFIG_SND_SST_IPC) += sst/
diff --git a/sound/soc/intel/broadwell.c b/sound/soc/intel/broadwell.c
index 0e550f1..c256764 100644
--- a/sound/soc/intel/broadwell.c
+++ b/sound/soc/intel/broadwell.c
@@ -19,6 +19,7 @@
#include <sound/core.h>
#include <sound/pcm.h>
#include <sound/soc.h>
+#include <sound/jack.h>
#include <sound/pcm_params.h>
#include "sst-dsp.h"
@@ -26,8 +27,26 @@
#include "../codecs/rt286.h"
+static struct snd_soc_jack broadwell_headset;
+/* Headset jack detection DAPM pins */
+static struct snd_soc_jack_pin broadwell_headset_pins[] = {
+ {
+ .pin = "Mic Jack",
+ .mask = SND_JACK_MICROPHONE,
+ },
+ {
+ .pin = "Headphone Jack",
+ .mask = SND_JACK_HEADPHONE,
+ },
+};
+
+static const struct snd_kcontrol_new broadwell_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Speaker"),
+ SOC_DAPM_PIN_SWITCH("Headphone Jack"),
+};
+
static const struct snd_soc_dapm_widget broadwell_widgets[] = {
- SND_SOC_DAPM_HP("Headphones", NULL),
+ SND_SOC_DAPM_HP("Headphone Jack", NULL),
SND_SOC_DAPM_SPK("Speaker", NULL),
SND_SOC_DAPM_MIC("Mic Jack", NULL),
SND_SOC_DAPM_MIC("DMIC1", NULL),
@@ -42,7 +61,7 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
{"Speaker", NULL, "SPOL"},
/* HP jack connectors - unknown if we have jack deteck */
- {"Headphones", NULL, "HPO Pin"},
+ {"Headphone Jack", NULL, "HPO Pin"},
/* other jacks */
{"MIC1", NULL, "Mic Jack"},
@@ -57,6 +76,27 @@ static const struct snd_soc_dapm_route broadwell_rt286_map[] = {
{"AIF1 Playback", NULL, "SSP0 CODEC OUT"},
};
+static int broadwell_rt286_codec_init(struct snd_soc_pcm_runtime *rtd)
+{
+ struct snd_soc_codec *codec = rtd->codec;
+ int ret = 0;
+ ret = snd_soc_jack_new(codec, "Headset",
+ SND_JACK_HEADSET | SND_JACK_BTN_0, &broadwell_headset);
+
+ if (ret)
+ return ret;
+
+ ret = snd_soc_jack_add_pins(&broadwell_headset,
+ ARRAY_SIZE(broadwell_headset_pins),
+ broadwell_headset_pins);
+ if (ret)
+ return ret;
+
+ rt286_mic_detect(codec, &broadwell_headset);
+ return 0;
+}
+
+
static int broadwell_ssp0_fixup(struct snd_soc_pcm_runtime *rtd,
struct snd_pcm_hw_params *params)
{
@@ -116,7 +156,7 @@ static int broadwell_rtd_init(struct snd_soc_pcm_runtime *rtd)
}
/* always connected - check HP for jack detect */
- snd_soc_dapm_enable_pin(dapm, "Headphones");
+ snd_soc_dapm_enable_pin(dapm, "Headphone Jack");
snd_soc_dapm_enable_pin(dapm, "Speaker");
snd_soc_dapm_enable_pin(dapm, "Mic Jack");
snd_soc_dapm_enable_pin(dapm, "Line Jack");
@@ -131,7 +171,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
/* Front End DAI links */
{
.name = "System PCM",
- .stream_name = "System Playback",
+ .stream_name = "System Playback/Capture",
.cpu_dai_name = "System Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 1,
@@ -140,6 +180,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
.init = broadwell_rtd_init,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
+ .dpcm_capture = 1,
},
{
.name = "Offload0",
@@ -174,18 +215,6 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
},
- {
- .name = "Capture PCM",
- .stream_name = "Capture",
- .cpu_dai_name = "Capture Pin",
- .platform_name = "haswell-pcm-audio",
- .dynamic = 1,
- .codec_name = "snd-soc-dummy",
- .codec_dai_name = "snd-soc-dummy-dai",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- },
-
/* Back End DAI links */
{
/* SSP0 - Codec */
@@ -196,6 +225,7 @@ static struct snd_soc_dai_link broadwell_rt286_dais[] = {
.no_pcm = 1,
.codec_name = "i2c-INT343A:00",
.codec_dai_name = "rt286-aif1",
+ .init = broadwell_rt286_codec_init,
.dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF |
SND_SOC_DAIFMT_CBS_CFS,
.ignore_suspend = 1,
@@ -213,6 +243,8 @@ static struct snd_soc_card broadwell_rt286 = {
.owner = THIS_MODULE,
.dai_link = broadwell_rt286_dais,
.num_links = ARRAY_SIZE(broadwell_rt286_dais),
+ .controls = broadwell_controls,
+ .num_controls = ARRAY_SIZE(broadwell_controls),
.dapm_widgets = broadwell_widgets,
.num_dapm_widgets = ARRAY_SIZE(broadwell_widgets),
.dapm_routes = broadwell_rt286_map,
diff --git a/sound/soc/intel/bytcr_dpcm_rt5640.c b/sound/soc/intel/bytcr_dpcm_rt5640.c
new file mode 100644
index 0000000..f5d0fc1
--- /dev/null
+++ b/sound/soc/intel/bytcr_dpcm_rt5640.c
@@ -0,0 +1,230 @@
+/*
+ * byt_cr_dpcm_rt5640.c - ASoc Machine driver for Intel Byt CR platform
+ *
+ * Copyright (C) 2014 Intel Corp
+ * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/device.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../codecs/rt5640.h"
+#include "sst-atom-controls.h"
+
+static const struct snd_soc_dapm_widget byt_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+};
+
+static const struct snd_soc_dapm_route byt_audio_map[] = {
+ {"IN2P", NULL, "Headset Mic"},
+ {"IN2N", NULL, "Headset Mic"},
+ {"Headset Mic", NULL, "MICBIAS1"},
+ {"IN1P", NULL, "MICBIAS1"},
+ {"LDO2", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Ext Spk", NULL, "SPOLP"},
+ {"Ext Spk", NULL, "SPOLN"},
+ {"Ext Spk", NULL, "SPORP"},
+ {"Ext Spk", NULL, "SPORN"},
+
+ {"AIF1 Playback", NULL, "ssp2 Tx"},
+ {"ssp2 Tx", NULL, "codec_out0"},
+ {"ssp2 Tx", NULL, "codec_out1"},
+ {"codec_in0", NULL, "ssp2 Rx"},
+ {"codec_in1", NULL, "ssp2 Rx"},
+ {"ssp2 Rx", NULL, "AIF1 Capture"},
+};
+
+static const struct snd_kcontrol_new byt_mc_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int byt_aif1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ snd_soc_dai_set_bclk_ratio(codec_dai, 50);
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5640_SCLK_S_PLL1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec clock %d\n", ret);
+ return ret;
+ }
+
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5640_PLL1_S_BCLK1,
+ params_rate(params) * 50,
+ params_rate(params) * 512);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static const struct snd_soc_pcm_stream byt_dai_params = {
+ .formats = SNDRV_PCM_FMTBIT_S24_LE,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .channels_min = 2,
+ .channels_max = 2,
+};
+
+static int byt_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP2 to 24-bit */
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static unsigned int rates_48000[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+ .count = ARRAY_SIZE(rates_48000),
+ .list = rates_48000,
+};
+
+static int byt_aif1_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_48000);
+}
+
+static struct snd_soc_ops byt_aif1_ops = {
+ .startup = byt_aif1_startup,
+};
+
+static struct snd_soc_ops byt_be_ssp2_ops = {
+ .hw_params = byt_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link byt_dailink[] = {
+ [MERR_DPCM_AUDIO] = {
+ .name = "Baytrail Audio Port",
+ .stream_name = "Baytrail Audio",
+ .cpu_dai_name = "media-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .ignore_suspend = 1,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &byt_aif1_ops,
+ },
+ [MERR_DPCM_COMPR] = {
+ .name = "Baytrail Compressed Port",
+ .stream_name = "Baytrail Compress",
+ .cpu_dai_name = "compress-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ },
+ /* back ends */
+ {
+ .name = "SSP2-Codec",
+ .be_id = 1,
+ .cpu_dai_name = "ssp2-port",
+ .platform_name = "sst-mfld-platform",
+ .no_pcm = 1,
+ .codec_dai_name = "rt5640-aif1",
+ .codec_name = "i2c-10EC5640:00",
+ .dai_fmt = SND_SOC_DAIFMT_I2S | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBS_CFS,
+ .be_hw_params_fixup = byt_codec_fixup,
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &byt_be_ssp2_ops,
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_byt = {
+ .name = "baytrailcraudio",
+ .dai_link = byt_dailink,
+ .num_links = ARRAY_SIZE(byt_dailink),
+ .dapm_widgets = byt_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(byt_dapm_widgets),
+ .dapm_routes = byt_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(byt_audio_map),
+ .controls = byt_mc_controls,
+ .num_controls = ARRAY_SIZE(byt_mc_controls),
+};
+
+static int snd_byt_mc_probe(struct platform_device *pdev)
+{
+ int ret_val = 0;
+
+ /* register the soc card */
+ snd_soc_card_byt.dev = &pdev->dev;
+
+ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_byt);
+ if (ret_val) {
+ dev_err(&pdev->dev, "devm_snd_soc_register_card failed %d\n", ret_val);
+ return ret_val;
+ }
+ platform_set_drvdata(pdev, &snd_soc_card_byt);
+ return ret_val;
+}
+
+static struct platform_driver snd_byt_mc_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bytt100_rt5640",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = snd_byt_mc_probe,
+};
+
+module_platform_driver(snd_byt_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
+MODULE_AUTHOR("Subhransu S. Prusty <subhransu.s.prusty@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:bytrt5640-audio");
diff --git a/sound/soc/intel/cht_bsw_rt5672.c b/sound/soc/intel/cht_bsw_rt5672.c
new file mode 100644
index 0000000..9b8b561
--- /dev/null
+++ b/sound/soc/intel/cht_bsw_rt5672.c
@@ -0,0 +1,285 @@
+/*
+ * cht_bsw_rt5672.c - ASoc Machine driver for Intel Cherryview-based platforms
+ * Cherrytrail and Braswell, with RT5672 codec.
+ *
+ * Copyright (C) 2014 Intel Corp
+ * Author: Subhransu S. Prusty <subhransu.s.prusty@intel.com>
+ * Mengdong Lin <mengdong.lin@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include "../codecs/rt5670.h"
+#include "sst-atom-controls.h"
+
+/* The platform clock #3 outputs 19.2Mhz clock to codec as I2S MCLK */
+#define CHT_PLAT_CLK_3_HZ 19200000
+#define CHT_CODEC_DAI "rt5670-aif1"
+
+static inline struct snd_soc_dai *cht_get_codec_dai(struct snd_soc_card *card)
+{
+ int i;
+
+ for (i = 0; i < card->num_rtd; i++) {
+ struct snd_soc_pcm_runtime *rtd;
+
+ rtd = card->rtd + i;
+ if (!strncmp(rtd->codec_dai->name, CHT_CODEC_DAI,
+ strlen(CHT_CODEC_DAI)))
+ return rtd->codec_dai;
+ }
+ return NULL;
+}
+
+static int platform_clock_control(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct snd_soc_dapm_context *dapm = w->dapm;
+ struct snd_soc_card *card = dapm->card;
+ struct snd_soc_dai *codec_dai;
+
+ codec_dai = cht_get_codec_dai(card);
+ if (!codec_dai) {
+ dev_err(card->dev, "Codec dai not found; Unable to set platform clock\n");
+ return -EIO;
+ }
+
+ if (!SND_SOC_DAPM_EVENT_OFF(event))
+ return 0;
+
+ /* Set codec sysclk source to its internal clock because codec PLL will
+ * be off when idle and MCLK will also be off by ACPI when codec is
+ * runtime suspended. Codec needs clock for jack detection and button
+ * press.
+ */
+ snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_RCCLK,
+ 0, SND_SOC_CLOCK_IN);
+
+ return 0;
+}
+
+static const struct snd_soc_dapm_widget cht_dapm_widgets[] = {
+ SND_SOC_DAPM_HP("Headphone", NULL),
+ SND_SOC_DAPM_MIC("Headset Mic", NULL),
+ SND_SOC_DAPM_MIC("Int Mic", NULL),
+ SND_SOC_DAPM_SPK("Ext Spk", NULL),
+ SND_SOC_DAPM_SUPPLY("Platform Clock", SND_SOC_NOPM, 0, 0,
+ platform_clock_control, SND_SOC_DAPM_POST_PMD),
+};
+
+static const struct snd_soc_dapm_route cht_audio_map[] = {
+ {"IN1P", NULL, "Headset Mic"},
+ {"IN1N", NULL, "Headset Mic"},
+ {"DMIC L1", NULL, "Int Mic"},
+ {"DMIC R1", NULL, "Int Mic"},
+ {"Headphone", NULL, "HPOL"},
+ {"Headphone", NULL, "HPOR"},
+ {"Ext Spk", NULL, "SPOLP"},
+ {"Ext Spk", NULL, "SPOLN"},
+ {"Ext Spk", NULL, "SPORP"},
+ {"Ext Spk", NULL, "SPORN"},
+ {"AIF1 Playback", NULL, "ssp2 Tx"},
+ {"ssp2 Tx", NULL, "codec_out0"},
+ {"ssp2 Tx", NULL, "codec_out1"},
+ {"codec_in0", NULL, "ssp2 Rx"},
+ {"codec_in1", NULL, "ssp2 Rx"},
+ {"ssp2 Rx", NULL, "AIF1 Capture"},
+ {"Headphone", NULL, "Platform Clock"},
+ {"Headset Mic", NULL, "Platform Clock"},
+ {"Int Mic", NULL, "Platform Clock"},
+ {"Ext Spk", NULL, "Platform Clock"},
+};
+
+static const struct snd_kcontrol_new cht_mc_controls[] = {
+ SOC_DAPM_PIN_SWITCH("Headphone"),
+ SOC_DAPM_PIN_SWITCH("Headset Mic"),
+ SOC_DAPM_PIN_SWITCH("Int Mic"),
+ SOC_DAPM_PIN_SWITCH("Ext Spk"),
+};
+
+static int cht_aif1_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int ret;
+
+ /* set codec PLL source to the 19.2MHz platform clock (MCLK) */
+ ret = snd_soc_dai_set_pll(codec_dai, 0, RT5670_PLL1_S_MCLK,
+ CHT_PLAT_CLK_3_HZ, params_rate(params) * 512);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec pll: %d\n", ret);
+ return ret;
+ }
+
+ /* set codec sysclk source to PLL */
+ ret = snd_soc_dai_set_sysclk(codec_dai, RT5670_SCLK_S_PLL1,
+ params_rate(params) * 512,
+ SND_SOC_CLOCK_IN);
+ if (ret < 0) {
+ dev_err(rtd->dev, "can't set codec sysclk: %d\n", ret);
+ return ret;
+ }
+ return 0;
+}
+
+static int cht_codec_init(struct snd_soc_pcm_runtime *runtime)
+{
+ int ret;
+ struct snd_soc_dai *codec_dai = runtime->codec_dai;
+
+ /* TDM 4 slots 24 bit, set Rx & Tx bitmask to 4 active slots */
+ ret = snd_soc_dai_set_tdm_slot(codec_dai, 0xF, 0xF, 4, 24);
+ if (ret < 0) {
+ dev_err(runtime->dev, "can't set codec TDM slot %d\n", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int cht_codec_fixup(struct snd_soc_pcm_runtime *rtd,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_interval *rate = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_RATE);
+ struct snd_interval *channels = hw_param_interval(params,
+ SNDRV_PCM_HW_PARAM_CHANNELS);
+
+ /* The DSP will covert the FE rate to 48k, stereo, 24bits */
+ rate->min = rate->max = 48000;
+ channels->min = channels->max = 2;
+
+ /* set SSP2 to 24-bit */
+ snd_mask_set(&params->masks[SNDRV_PCM_HW_PARAM_FORMAT -
+ SNDRV_PCM_HW_PARAM_FIRST_MASK],
+ SNDRV_PCM_FORMAT_S24_LE);
+ return 0;
+}
+
+static unsigned int rates_48000[] = {
+ 48000,
+};
+
+static struct snd_pcm_hw_constraint_list constraints_48000 = {
+ .count = ARRAY_SIZE(rates_48000),
+ .list = rates_48000,
+};
+
+static int cht_aif1_startup(struct snd_pcm_substream *substream)
+{
+ return snd_pcm_hw_constraint_list(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_RATE,
+ &constraints_48000);
+}
+
+static struct snd_soc_ops cht_aif1_ops = {
+ .startup = cht_aif1_startup,
+};
+
+static struct snd_soc_ops cht_be_ssp2_ops = {
+ .hw_params = cht_aif1_hw_params,
+};
+
+static struct snd_soc_dai_link cht_dailink[] = {
+ /* Front End DAI links */
+ [MERR_DPCM_AUDIO] = {
+ .name = "Audio Port",
+ .stream_name = "Audio",
+ .cpu_dai_name = "media-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ .ignore_suspend = 1,
+ .dynamic = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &cht_aif1_ops,
+ },
+ [MERR_DPCM_COMPR] = {
+ .name = "Compressed Port",
+ .stream_name = "Compress",
+ .cpu_dai_name = "compress-cpu-dai",
+ .codec_dai_name = "snd-soc-dummy-dai",
+ .codec_name = "snd-soc-dummy",
+ .platform_name = "sst-mfld-platform",
+ },
+
+ /* Back End DAI links */
+ {
+ /* SSP2 - Codec */
+ .name = "SSP2-Codec",
+ .be_id = 1,
+ .cpu_dai_name = "ssp2-port",
+ .platform_name = "sst-mfld-platform",
+ .no_pcm = 1,
+ .codec_dai_name = "rt5670-aif1",
+ .codec_name = "i2c-10EC5670:00",
+ .dai_fmt = SND_SOC_DAIFMT_DSP_B | SND_SOC_DAIFMT_IB_NF
+ | SND_SOC_DAIFMT_CBS_CFS,
+ .init = cht_codec_init,
+ .be_hw_params_fixup = cht_codec_fixup,
+ .ignore_suspend = 1,
+ .dpcm_playback = 1,
+ .dpcm_capture = 1,
+ .ops = &cht_be_ssp2_ops,
+ },
+};
+
+/* SoC card */
+static struct snd_soc_card snd_soc_card_cht = {
+ .name = "cherrytrailcraudio",
+ .dai_link = cht_dailink,
+ .num_links = ARRAY_SIZE(cht_dailink),
+ .dapm_widgets = cht_dapm_widgets,
+ .num_dapm_widgets = ARRAY_SIZE(cht_dapm_widgets),
+ .dapm_routes = cht_audio_map,
+ .num_dapm_routes = ARRAY_SIZE(cht_audio_map),
+ .controls = cht_mc_controls,
+ .num_controls = ARRAY_SIZE(cht_mc_controls),
+};
+
+static int snd_cht_mc_probe(struct platform_device *pdev)
+{
+ int ret_val = 0;
+
+ /* register the soc card */
+ snd_soc_card_cht.dev = &pdev->dev;
+ ret_val = devm_snd_soc_register_card(&pdev->dev, &snd_soc_card_cht);
+ if (ret_val) {
+ dev_err(&pdev->dev,
+ "snd_soc_register_card failed %d\n", ret_val);
+ return ret_val;
+ }
+ platform_set_drvdata(pdev, &snd_soc_card_cht);
+ return ret_val;
+}
+
+static struct platform_driver snd_cht_mc_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cht-bsw-rt5672",
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = snd_cht_mc_probe,
+};
+
+module_platform_driver(snd_cht_mc_driver);
+
+MODULE_DESCRIPTION("ASoC Intel(R) Baytrail CR Machine driver");
+MODULE_AUTHOR("Subhransu S. Prusty, Mengdong Lin");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:cht-bsw-rt5672");
diff --git a/sound/soc/intel/haswell.c b/sound/soc/intel/haswell.c
index 3981982..cb8a482 100644
--- a/sound/soc/intel/haswell.c
+++ b/sound/soc/intel/haswell.c
@@ -109,7 +109,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
/* Front End DAI links */
{
.name = "System",
- .stream_name = "System Playback",
+ .stream_name = "System Playback/Capture",
.cpu_dai_name = "System Pin",
.platform_name = "haswell-pcm-audio",
.dynamic = 1,
@@ -118,6 +118,7 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
.init = haswell_rtd_init,
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_playback = 1,
+ .dpcm_capture = 1,
},
{
.name = "Offload0",
@@ -152,17 +153,6 @@ static struct snd_soc_dai_link haswell_rt5640_dais[] = {
.trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
.dpcm_capture = 1,
},
- {
- .name = "Capture",
- .stream_name = "Capture",
- .cpu_dai_name = "Capture Pin",
- .platform_name = "haswell-pcm-audio",
- .dynamic = 1,
- .codec_name = "snd-soc-dummy",
- .codec_dai_name = "snd-soc-dummy-dai",
- .trigger = {SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST},
- .dpcm_capture = 1,
- },
/* Back End DAI links */
{
diff --git a/sound/soc/intel/sst-atom-controls.c b/sound/soc/intel/sst-atom-controls.c
index 7104a34..90aa5c0 100644
--- a/sound/soc/intel/sst-atom-controls.c
+++ b/sound/soc/intel/sst-atom-controls.c
@@ -15,6 +15,9 @@
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
+ * In the dpcm driver modelling when a particular FE/BE/Mixer/Pipe is active
+ * we forward the settings and parameters, rest we keep the values in
+ * driver and forward when DAPM enables them
* ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
*/
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -81,6 +84,183 @@ static int sst_fill_and_send_cmd(struct sst_data *drv,
return ret;
}
+/**
+ * tx map value is a bitfield where each bit represents a FW channel
+ *
+ * 3 2 1 0 # 0 = codec0, 1 = codec1
+ * RLRLRLRL # 3, 4 = reserved
+ *
+ * e.g. slot 0 rx map = 00001100b -> data from slot 0 goes into codec_in1 L,R
+ */
+static u8 sst_ssp_tx_map[SST_MAX_TDM_SLOTS] = {
+ 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default rx map */
+};
+
+/**
+ * rx map value is a bitfield where each bit represents a slot
+ *
+ * 76543210 # 0 = slot 0, 1 = slot 1
+ *
+ * e.g. codec1_0 tx map = 00000101b -> data from codec_out1_0 goes into slot 0, 2
+ */
+static u8 sst_ssp_rx_map[SST_MAX_TDM_SLOTS] = {
+ 0x1, 0x2, 0x4, 0x8, 0x10, 0x20, 0x40, 0x80, /* default tx map */
+};
+
+/**
+ * NOTE: this is invoked with lock held
+ */
+static int sst_send_slot_map(struct sst_data *drv)
+{
+ struct sst_param_sba_ssp_slot_map cmd;
+
+ SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+ cmd.header.command_id = SBA_SET_SSP_SLOT_MAP;
+ cmd.header.length = sizeof(struct sst_param_sba_ssp_slot_map)
+ - sizeof(struct sst_dsp_header);
+
+ cmd.param_id = SBA_SET_SSP_SLOT_MAP;
+ cmd.param_len = sizeof(cmd.rx_slot_map) + sizeof(cmd.tx_slot_map)
+ + sizeof(cmd.ssp_index);
+ cmd.ssp_index = SSP_CODEC;
+
+ memcpy(cmd.rx_slot_map, &sst_ssp_tx_map[0], sizeof(cmd.rx_slot_map));
+ memcpy(cmd.tx_slot_map, &sst_ssp_rx_map[0], sizeof(cmd.tx_slot_map));
+
+ return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+ SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+}
+
+int sst_slot_enum_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct sst_enum *e = (struct sst_enum *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = 1;
+ uinfo->value.enumerated.items = e->max;
+
+ if (uinfo->value.enumerated.item > e->max - 1)
+ uinfo->value.enumerated.item = e->max - 1;
+ strcpy(uinfo->value.enumerated.name,
+ e->texts[uinfo->value.enumerated.item]);
+
+ return 0;
+}
+
+/**
+ * sst_slot_get - get the status of the interleaver/deinterleaver control
+ *
+ * Searches the map where the control status is stored, and gets the
+ * channel/slot which is currently set for this enumerated control. Since it is
+ * an enumerated control, there is only one possible value.
+ */
+static int sst_slot_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct sst_enum *e = (void *)kcontrol->private_value;
+ struct snd_soc_component *c = snd_kcontrol_chip(kcontrol);
+ struct sst_data *drv = snd_soc_component_get_drvdata(c);
+ unsigned int ctl_no = e->reg;
+ unsigned int is_tx = e->tx;
+ unsigned int val, mux;
+ u8 *map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
+
+ mutex_lock(&drv->lock);
+ val = 1 << ctl_no;
+ /* search which slot/channel has this bit set - there should be only one */
+ for (mux = e->max; mux > 0; mux--)
+ if (map[mux - 1] & val)
+ break;
+
+ ucontrol->value.enumerated.item[0] = mux;
+ mutex_unlock(&drv->lock);
+
+ dev_dbg(c->dev, "%s - %s map = %#x\n",
+ is_tx ? "tx channel" : "rx slot",
+ e->texts[mux], mux ? map[mux - 1] : -1);
+ return 0;
+}
+
+/* sst_check_and_send_slot_map - helper for checking power state and sending
+ * slot map cmd
+ *
+ * called with lock held
+ */
+static int sst_check_and_send_slot_map(struct sst_data *drv, struct snd_kcontrol *kcontrol)
+{
+ struct sst_enum *e = (void *)kcontrol->private_value;
+ int ret = 0;
+
+ if (e->w && e->w->power)
+ ret = sst_send_slot_map(drv);
+ else
+ dev_err(&drv->pdev->dev, "Slot control: %s doesn't have DAPM widget!!!\n",
+ kcontrol->id.name);
+ return ret;
+}
+
+/**
+ * sst_slot_put - set the status of interleaver/deinterleaver control
+ *
+ * (de)interleaver controls are defined in opposite sense to be user-friendly
+ *
+ * Instead of the enum value being the value written to the register, it is the
+ * register address; and the kcontrol number (register num) is the value written
+ * to the register. This is so that there can be only one value for each
+ * slot/channel since there is only one control for each slot/channel.
+ *
+ * This means that whenever an enum is set, we need to clear the bit
+ * for that kcontrol_no for all the interleaver OR deinterleaver registers
+ */
+static int sst_slot_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *c = snd_soc_kcontrol_component(kcontrol);
+ struct sst_data *drv = snd_soc_component_get_drvdata(c);
+ struct sst_enum *e = (void *)kcontrol->private_value;
+ int i, ret = 0;
+ unsigned int ctl_no = e->reg;
+ unsigned int is_tx = e->tx;
+ unsigned int slot_channel_no;
+ unsigned int val, mux;
+ u8 *map;
+
+ map = is_tx ? sst_ssp_rx_map : sst_ssp_tx_map;
+
+ val = 1 << ctl_no;
+ mux = ucontrol->value.enumerated.item[0];
+ if (mux > e->max - 1)
+ return -EINVAL;
+
+ mutex_lock(&drv->lock);
+ /* first clear all registers of this bit */
+ for (i = 0; i < e->max; i++)
+ map[i] &= ~val;
+
+ if (mux == 0) {
+ /* kctl set to 'none' and we reset the bits so send IPC */
+ ret = sst_check_and_send_slot_map(drv, kcontrol);
+
+ mutex_unlock(&drv->lock);
+ return ret;
+ }
+
+ /* offset by one to take "None" into account */
+ slot_channel_no = mux - 1;
+ map[slot_channel_no] |= val;
+
+ dev_dbg(c->dev, "%s %s map = %#x\n",
+ is_tx ? "tx channel" : "rx slot",
+ e->texts[mux], map[slot_channel_no]);
+
+ ret = sst_check_and_send_slot_map(drv, kcontrol);
+
+ mutex_unlock(&drv->lock);
+ return ret;
+}
+
static int sst_send_algo_cmd(struct sst_data *drv,
struct sst_algo_control *bc)
{
@@ -104,6 +284,34 @@ static int sst_send_algo_cmd(struct sst_data *drv,
return ret;
}
+/**
+ * sst_find_and_send_pipe_algo - send all the algo parameters for a pipe
+ *
+ * The algos which are in each pipeline are sent to the firmware one by one
+ *
+ * Called with lock held
+ */
+static int sst_find_and_send_pipe_algo(struct sst_data *drv,
+ const char *pipe, struct sst_ids *ids)
+{
+ int ret = 0;
+ struct sst_algo_control *bc;
+ struct sst_module *algo = NULL;
+
+ dev_dbg(&drv->pdev->dev, "Enter: widget=%s\n", pipe);
+
+ list_for_each_entry(algo, &ids->algo_list, node) {
+ bc = (void *)algo->kctl->private_value;
+
+ dev_dbg(&drv->pdev->dev, "Found algo control name=%s pipe=%s\n",
+ algo->kctl->id.name, pipe);
+ ret = sst_send_algo_cmd(drv, bc);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
static int sst_algo_bytes_ctl_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
@@ -162,6 +370,743 @@ static int sst_algo_control_set(struct snd_kcontrol *kcontrol,
return ret;
}
+static int sst_gain_ctl_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = mc->stereo ? 2 : 1;
+ uinfo->value.integer.min = mc->min;
+ uinfo->value.integer.max = mc->max;
+
+ return 0;
+}
+
+/**
+ * sst_send_gain_cmd - send the gain algorithm IPC to the FW
+ * @gv: the stored value of gain (also contains rampduration)
+ * @mute: flag that indicates whether this was called from the
+ * digital_mute callback or directly. If called from the
+ * digital_mute callback, module will be muted/unmuted based on this
+ * flag. The flag is always 0 if called directly.
+ *
+ * Called with sst_data.lock held
+ *
+ * The user-set gain value is sent only if the user-controllable 'mute' control
+ * is OFF (indicated by gv->mute). Otherwise, the mute value (MIN value) is
+ * sent.
+ */
+static int sst_send_gain_cmd(struct sst_data *drv, struct sst_gain_value *gv,
+ u16 task_id, u16 loc_id, u16 module_id, int mute)
+{
+ struct sst_cmd_set_gain_dual cmd;
+
+ dev_dbg(&drv->pdev->dev, "Enter\n");
+
+ cmd.header.command_id = MMX_SET_GAIN;
+ SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+ cmd.gain_cell_num = 1;
+
+ if (mute || gv->mute) {
+ cmd.cell_gains[0].cell_gain_left = SST_GAIN_MIN_VALUE;
+ cmd.cell_gains[0].cell_gain_right = SST_GAIN_MIN_VALUE;
+ } else {
+ cmd.cell_gains[0].cell_gain_left = gv->l_gain;
+ cmd.cell_gains[0].cell_gain_right = gv->r_gain;
+ }
+
+ SST_FILL_DESTINATION(2, cmd.cell_gains[0].dest,
+ loc_id, module_id);
+ cmd.cell_gains[0].gain_time_constant = gv->ramp_duration;
+
+ cmd.header.length = sizeof(struct sst_cmd_set_gain_dual)
+ - sizeof(struct sst_dsp_header);
+
+ /* we are with lock held, so call the unlocked api to send */
+ return sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_SET_PARAMS,
+ SST_FLAG_BLOCKED, task_id, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+}
+
+static int sst_gain_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
+ struct sst_gain_value *gv = mc->gain_val;
+
+ switch (mc->type) {
+ case SST_GAIN_TLV:
+ ucontrol->value.integer.value[0] = gv->l_gain;
+ ucontrol->value.integer.value[1] = gv->r_gain;
+ break;
+
+ case SST_GAIN_MUTE:
+ ucontrol->value.integer.value[0] = gv->mute ? 1 : 0;
+ break;
+
+ case SST_GAIN_RAMP_DURATION:
+ ucontrol->value.integer.value[0] = gv->ramp_duration;
+ break;
+
+ default:
+ dev_err(component->dev, "Invalid Input- gain type:%d\n",
+ mc->type);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int sst_gain_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ int ret = 0;
+ struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
+ struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+ struct sst_gain_mixer_control *mc = (void *)kcontrol->private_value;
+ struct sst_gain_value *gv = mc->gain_val;
+
+ mutex_lock(&drv->lock);
+
+ switch (mc->type) {
+ case SST_GAIN_TLV:
+ gv->l_gain = ucontrol->value.integer.value[0];
+ gv->r_gain = ucontrol->value.integer.value[1];
+ dev_dbg(cmpnt->dev, "%s: Volume %d, %d\n",
+ mc->pname, gv->l_gain, gv->r_gain);
+ break;
+
+ case SST_GAIN_MUTE:
+ gv->mute = !!ucontrol->value.integer.value[0];
+ dev_dbg(cmpnt->dev, "%s: Mute %d\n", mc->pname, gv->mute);
+ break;
+
+ case SST_GAIN_RAMP_DURATION:
+ gv->ramp_duration = ucontrol->value.integer.value[0];
+ dev_dbg(cmpnt->dev, "%s: Ramp Delay%d\n",
+ mc->pname, gv->ramp_duration);
+ break;
+
+ default:
+ mutex_unlock(&drv->lock);
+ dev_err(cmpnt->dev, "Invalid Input- gain type:%d\n",
+ mc->type);
+ return -EINVAL;
+ }
+
+ if (mc->w && mc->w->power)
+ ret = sst_send_gain_cmd(drv, gv, mc->task_id,
+ mc->pipe_id | mc->instance_id, mc->module_id, 0);
+ mutex_unlock(&drv->lock);
+
+ return ret;
+}
+
+static int sst_set_pipe_gain(struct sst_ids *ids,
+ struct sst_data *drv, int mute);
+
+static int sst_send_pipe_module_params(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *kcontrol)
+{
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct sst_data *drv = snd_soc_component_get_drvdata(c);
+ struct sst_ids *ids = w->priv;
+
+ mutex_lock(&drv->lock);
+ sst_find_and_send_pipe_algo(drv, w->name, ids);
+ sst_set_pipe_gain(ids, drv, 0);
+ mutex_unlock(&drv->lock);
+
+ return 0;
+}
+
+static int sst_generic_modules_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ return sst_send_pipe_module_params(w, k);
+ return 0;
+}
+
+static const DECLARE_TLV_DB_SCALE(sst_gain_tlv_common, SST_GAIN_MIN_VALUE * 10, 10, 0);
+
+/* Look up table to convert MIXER SW bit regs to SWM inputs */
+static const uint swm_mixer_input_ids[SST_SWM_INPUT_COUNT] = {
+ [SST_IP_CODEC0] = SST_SWM_IN_CODEC0,
+ [SST_IP_CODEC1] = SST_SWM_IN_CODEC1,
+ [SST_IP_LOOP0] = SST_SWM_IN_SPROT_LOOP,
+ [SST_IP_LOOP1] = SST_SWM_IN_MEDIA_LOOP1,
+ [SST_IP_LOOP2] = SST_SWM_IN_MEDIA_LOOP2,
+ [SST_IP_PCM0] = SST_SWM_IN_PCM0,
+ [SST_IP_PCM1] = SST_SWM_IN_PCM1,
+ [SST_IP_MEDIA0] = SST_SWM_IN_MEDIA0,
+ [SST_IP_MEDIA1] = SST_SWM_IN_MEDIA1,
+ [SST_IP_MEDIA2] = SST_SWM_IN_MEDIA2,
+ [SST_IP_MEDIA3] = SST_SWM_IN_MEDIA3,
+};
+
+/**
+ * fill_swm_input - fill in the SWM input ids given the register
+ *
+ * The register value is a bit-field inicated which mixer inputs are ON. Use the
+ * lookup table to get the input-id and fill it in the structure.
+ */
+static int fill_swm_input(struct snd_soc_component *cmpnt,
+ struct swm_input_ids *swm_input, unsigned int reg)
+{
+ uint i, is_set, nb_inputs = 0;
+ u16 input_loc_id;
+
+ dev_dbg(cmpnt->dev, "reg: %#x\n", reg);
+ for (i = 0; i < SST_SWM_INPUT_COUNT; i++) {
+ is_set = reg & BIT(i);
+ if (!is_set)
+ continue;
+
+ input_loc_id = swm_mixer_input_ids[i];
+ SST_FILL_DESTINATION(2, swm_input->input_id,
+ input_loc_id, SST_DEFAULT_MODULE_ID);
+ nb_inputs++;
+ swm_input++;
+ dev_dbg(cmpnt->dev, "input id: %#x, nb_inputs: %d\n",
+ input_loc_id, nb_inputs);
+
+ if (nb_inputs == SST_CMD_SWM_MAX_INPUTS) {
+ dev_warn(cmpnt->dev, "SET_SWM cmd max inputs reached");
+ break;
+ }
+ }
+ return nb_inputs;
+}
+
+
+/**
+ * called with lock held
+ */
+static int sst_set_pipe_gain(struct sst_ids *ids,
+ struct sst_data *drv, int mute)
+{
+ int ret = 0;
+ struct sst_gain_mixer_control *mc;
+ struct sst_gain_value *gv;
+ struct sst_module *gain = NULL;
+
+ list_for_each_entry(gain, &ids->gain_list, node) {
+ struct snd_kcontrol *kctl = gain->kctl;
+
+ dev_dbg(&drv->pdev->dev, "control name=%s\n", kctl->id.name);
+ mc = (void *)kctl->private_value;
+ gv = mc->gain_val;
+
+ ret = sst_send_gain_cmd(drv, gv, mc->task_id,
+ mc->pipe_id | mc->instance_id, mc->module_id, mute);
+ if (ret)
+ return ret;
+ }
+ return ret;
+}
+
+static int sst_swm_mixer_event(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ struct sst_cmd_set_swm cmd;
+ struct snd_soc_component *cmpnt = snd_soc_dapm_to_component(w->dapm);
+ struct sst_data *drv = snd_soc_component_get_drvdata(cmpnt);
+ struct sst_ids *ids = w->priv;
+ bool set_mixer = false;
+ struct soc_mixer_control *mc;
+ int val = 0;
+ int i = 0;
+
+ dev_dbg(cmpnt->dev, "widget = %s\n", w->name);
+ /*
+ * Identify which mixer input is on and send the bitmap of the
+ * inputs as an IPC to the DSP.
+ */
+ for (i = 0; i < w->num_kcontrols; i++) {
+ if (dapm_kcontrol_get_value(w->kcontrols[i])) {
+ mc = (struct soc_mixer_control *)(w->kcontrols[i])->private_value;
+ val |= 1 << mc->shift;
+ }
+ }
+ dev_dbg(cmpnt->dev, "val = %#x\n", val);
+
+ switch (event) {
+ case SND_SOC_DAPM_PRE_PMU:
+ case SND_SOC_DAPM_POST_PMD:
+ set_mixer = true;
+ break;
+ case SND_SOC_DAPM_POST_REG:
+ if (w->power)
+ set_mixer = true;
+ break;
+ default:
+ set_mixer = false;
+ }
+
+ if (set_mixer == false)
+ return 0;
+
+ if (SND_SOC_DAPM_EVENT_ON(event) ||
+ event == SND_SOC_DAPM_POST_REG)
+ cmd.switch_state = SST_SWM_ON;
+ else
+ cmd.switch_state = SST_SWM_OFF;
+
+ SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+ /* MMX_SET_SWM == SBA_SET_SWM */
+ cmd.header.command_id = SBA_SET_SWM;
+
+ SST_FILL_DESTINATION(2, cmd.output_id,
+ ids->location_id, SST_DEFAULT_MODULE_ID);
+ cmd.nb_inputs = fill_swm_input(cmpnt, &cmd.input[0], val);
+ cmd.header.length = offsetof(struct sst_cmd_set_swm, input)
+ - sizeof(struct sst_dsp_header)
+ + (cmd.nb_inputs * sizeof(cmd.input[0]));
+
+ return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+ ids->task_id, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+}
+
+/* SBA mixers - 16 inputs */
+#define SST_SBA_DECLARE_MIX_CONTROLS(kctl_name) \
+ static const struct snd_kcontrol_new kctl_name[] = { \
+ SOC_DAPM_SINGLE("codec_in0 Switch", SND_SOC_NOPM, SST_IP_CODEC0, 1, 0), \
+ SOC_DAPM_SINGLE("codec_in1 Switch", SND_SOC_NOPM, SST_IP_CODEC1, 1, 0), \
+ SOC_DAPM_SINGLE("sprot_loop_in Switch", SND_SOC_NOPM, SST_IP_LOOP0, 1, 0), \
+ SOC_DAPM_SINGLE("media_loop1_in Switch", SND_SOC_NOPM, SST_IP_LOOP1, 1, 0), \
+ SOC_DAPM_SINGLE("media_loop2_in Switch", SND_SOC_NOPM, SST_IP_LOOP2, 1, 0), \
+ SOC_DAPM_SINGLE("pcm0_in Switch", SND_SOC_NOPM, SST_IP_PCM0, 1, 0), \
+ SOC_DAPM_SINGLE("pcm1_in Switch", SND_SOC_NOPM, SST_IP_PCM1, 1, 0), \
+ }
+
+#define SST_SBA_MIXER_GRAPH_MAP(mix_name) \
+ { mix_name, "codec_in0 Switch", "codec_in0" }, \
+ { mix_name, "codec_in1 Switch", "codec_in1" }, \
+ { mix_name, "sprot_loop_in Switch", "sprot_loop_in" }, \
+ { mix_name, "media_loop1_in Switch", "media_loop1_in" }, \
+ { mix_name, "media_loop2_in Switch", "media_loop2_in" }, \
+ { mix_name, "pcm0_in Switch", "pcm0_in" }, \
+ { mix_name, "pcm1_in Switch", "pcm1_in" }
+
+#define SST_MMX_DECLARE_MIX_CONTROLS(kctl_name) \
+ static const struct snd_kcontrol_new kctl_name[] = { \
+ SOC_DAPM_SINGLE("media0_in Switch", SND_SOC_NOPM, SST_IP_MEDIA0, 1, 0), \
+ SOC_DAPM_SINGLE("media1_in Switch", SND_SOC_NOPM, SST_IP_MEDIA1, 1, 0), \
+ SOC_DAPM_SINGLE("media2_in Switch", SND_SOC_NOPM, SST_IP_MEDIA2, 1, 0), \
+ SOC_DAPM_SINGLE("media3_in Switch", SND_SOC_NOPM, SST_IP_MEDIA3, 1, 0), \
+ }
+
+SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media0_controls);
+SST_MMX_DECLARE_MIX_CONTROLS(sst_mix_media1_controls);
+
+/* 18 SBA mixers */
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_pcm2_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_sprot_l0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l1_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_media_l2_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_voip_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec0_controls);
+SST_SBA_DECLARE_MIX_CONTROLS(sst_mix_codec1_controls);
+
+/*
+ * sst_handle_vb_timer - Start/Stop the DSP scheduler
+ *
+ * The DSP expects first cmd to be SBA_VB_START, so at first startup send
+ * that.
+ * DSP expects last cmd to be SBA_VB_IDLE, so at last shutdown send that.
+ *
+ * Do refcount internally so that we send command only at first start
+ * and last end. Since SST driver does its own ref count, invoke sst's
+ * power ops always!
+ */
+int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable)
+{
+ int ret = 0;
+ struct sst_cmd_generic cmd;
+ struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
+ static int timer_usage;
+
+ if (enable)
+ cmd.header.command_id = SBA_VB_START;
+ else
+ cmd.header.command_id = SBA_IDLE;
+ dev_dbg(dai->dev, "enable=%u, usage=%d\n", enable, timer_usage);
+
+ SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+ cmd.header.length = 0;
+
+ if (enable) {
+ ret = sst->ops->power(sst->dev, true);
+ if (ret < 0)
+ return ret;
+ }
+
+ mutex_lock(&drv->lock);
+ if (enable)
+ timer_usage++;
+ else
+ timer_usage--;
+
+ /*
+ * Send the command only if this call is the first enable or last
+ * disable
+ */
+ if ((enable && (timer_usage == 1)) ||
+ (!enable && (timer_usage == 0))) {
+ ret = sst_fill_and_send_cmd_unlocked(drv, SST_IPC_IA_CMD,
+ SST_FLAG_BLOCKED, SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+ if (ret && enable) {
+ timer_usage--;
+ enable = false;
+ }
+ }
+ mutex_unlock(&drv->lock);
+
+ if (!enable)
+ sst->ops->power(sst->dev, false);
+ return ret;
+}
+
+/**
+ * sst_ssp_config - contains SSP configuration for media UC
+ */
+static const struct sst_ssp_config sst_ssp_configs = {
+ .ssp_id = SSP_CODEC,
+ .bits_per_slot = 24,
+ .slots = 4,
+ .ssp_mode = SSP_MODE_MASTER,
+ .pcm_mode = SSP_PCM_MODE_NETWORK,
+ .duplex = SSP_DUPLEX,
+ .ssp_protocol = SSP_MODE_PCM,
+ .fs_width = 1,
+ .fs_frequency = SSP_FS_48_KHZ,
+ .active_slot_map = 0xF,
+ .start_delay = 0,
+};
+
+int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable)
+{
+ struct sst_cmd_sba_hw_set_ssp cmd;
+ struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
+ const struct sst_ssp_config *config;
+
+ dev_info(dai->dev, "Enter: enable=%d port_name=%s\n", enable, id);
+
+ SST_FILL_DEFAULT_DESTINATION(cmd.header.dst);
+ cmd.header.command_id = SBA_HW_SET_SSP;
+ cmd.header.length = sizeof(struct sst_cmd_sba_hw_set_ssp)
+ - sizeof(struct sst_dsp_header);
+
+ config = &sst_ssp_configs;
+ dev_dbg(dai->dev, "ssp_id: %u\n", config->ssp_id);
+
+ if (enable)
+ cmd.switch_state = SST_SWITCH_ON;
+ else
+ cmd.switch_state = SST_SWITCH_OFF;
+
+ cmd.selection = config->ssp_id;
+ cmd.nb_bits_per_slots = config->bits_per_slot;
+ cmd.nb_slots = config->slots;
+ cmd.mode = config->ssp_mode | (config->pcm_mode << 1);
+ cmd.duplex = config->duplex;
+ cmd.active_tx_slot_map = config->active_slot_map;
+ cmd.active_rx_slot_map = config->active_slot_map;
+ cmd.frame_sync_frequency = config->fs_frequency;
+ cmd.frame_sync_polarity = SSP_FS_ACTIVE_HIGH;
+ cmd.data_polarity = 1;
+ cmd.frame_sync_width = config->fs_width;
+ cmd.ssp_protocol = config->ssp_protocol;
+ cmd.start_delay = config->start_delay;
+ cmd.reserved1 = cmd.reserved2 = 0xFF;
+
+ return sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+ SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+}
+
+static int sst_set_be_modules(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ int ret = 0;
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct sst_data *drv = snd_soc_component_get_drvdata(c);
+
+ dev_dbg(c->dev, "Enter: widget=%s\n", w->name);
+
+ if (SND_SOC_DAPM_EVENT_ON(event)) {
+ ret = sst_send_slot_map(drv);
+ if (ret)
+ return ret;
+ ret = sst_send_pipe_module_params(w, k);
+ }
+ return ret;
+}
+
+static int sst_set_media_path(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ int ret = 0;
+ struct sst_cmd_set_media_path cmd;
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct sst_data *drv = snd_soc_component_get_drvdata(c);
+ struct sst_ids *ids = w->priv;
+
+ dev_dbg(c->dev, "widget=%s\n", w->name);
+ dev_dbg(c->dev, "task=%u, location=%#x\n",
+ ids->task_id, ids->location_id);
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ cmd.switch_state = SST_PATH_ON;
+ else
+ cmd.switch_state = SST_PATH_OFF;
+
+ SST_FILL_DESTINATION(2, cmd.header.dst,
+ ids->location_id, SST_DEFAULT_MODULE_ID);
+
+ /* MMX_SET_MEDIA_PATH == SBA_SET_MEDIA_PATH */
+ cmd.header.command_id = MMX_SET_MEDIA_PATH;
+ cmd.header.length = sizeof(struct sst_cmd_set_media_path)
+ - sizeof(struct sst_dsp_header);
+
+ ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+ ids->task_id, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+ if (ret)
+ return ret;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ ret = sst_send_pipe_module_params(w, k);
+ return ret;
+}
+
+static int sst_set_media_loop(struct snd_soc_dapm_widget *w,
+ struct snd_kcontrol *k, int event)
+{
+ int ret = 0;
+ struct sst_cmd_sba_set_media_loop_map cmd;
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct sst_data *drv = snd_soc_component_get_drvdata(c);
+ struct sst_ids *ids = w->priv;
+
+ dev_dbg(c->dev, "Enter:widget=%s\n", w->name);
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ cmd.switch_state = SST_SWITCH_ON;
+ else
+ cmd.switch_state = SST_SWITCH_OFF;
+
+ SST_FILL_DESTINATION(2, cmd.header.dst,
+ ids->location_id, SST_DEFAULT_MODULE_ID);
+
+ cmd.header.command_id = SBA_SET_MEDIA_LOOP_MAP;
+ cmd.header.length = sizeof(struct sst_cmd_sba_set_media_loop_map)
+ - sizeof(struct sst_dsp_header);
+ cmd.param.part.cfg.rate = 2; /* 48khz */
+
+ cmd.param.part.cfg.format = ids->format; /* stereo/Mono */
+ cmd.param.part.cfg.s_length = 1; /* 24bit left justified */
+ cmd.map = 0; /* Algo sequence: Gain - DRP - FIR - IIR */
+
+ ret = sst_fill_and_send_cmd(drv, SST_IPC_IA_CMD, SST_FLAG_BLOCKED,
+ SST_TASK_SBA, 0, &cmd,
+ sizeof(cmd.header) + cmd.header.length);
+ if (ret)
+ return ret;
+
+ if (SND_SOC_DAPM_EVENT_ON(event))
+ ret = sst_send_pipe_module_params(w, k);
+ return ret;
+}
+
+static const struct snd_soc_dapm_widget sst_dapm_widgets[] = {
+ SST_AIF_IN("codec_in0", sst_set_be_modules),
+ SST_AIF_IN("codec_in1", sst_set_be_modules),
+ SST_AIF_OUT("codec_out0", sst_set_be_modules),
+ SST_AIF_OUT("codec_out1", sst_set_be_modules),
+
+ /* Media Paths */
+ /* MediaX IN paths are set via ALLOC, so no SET_MEDIA_PATH command */
+ SST_PATH_INPUT("media0_in", SST_TASK_MMX, SST_SWM_IN_MEDIA0, sst_generic_modules_event),
+ SST_PATH_INPUT("media1_in", SST_TASK_MMX, SST_SWM_IN_MEDIA1, NULL),
+ SST_PATH_INPUT("media2_in", SST_TASK_MMX, SST_SWM_IN_MEDIA2, sst_set_media_path),
+ SST_PATH_INPUT("media3_in", SST_TASK_MMX, SST_SWM_IN_MEDIA3, NULL),
+ SST_PATH_OUTPUT("media0_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA0, sst_set_media_path),
+ SST_PATH_OUTPUT("media1_out", SST_TASK_MMX, SST_SWM_OUT_MEDIA1, sst_set_media_path),
+
+ /* SBA PCM Paths */
+ SST_PATH_INPUT("pcm0_in", SST_TASK_SBA, SST_SWM_IN_PCM0, sst_set_media_path),
+ SST_PATH_INPUT("pcm1_in", SST_TASK_SBA, SST_SWM_IN_PCM1, sst_set_media_path),
+ SST_PATH_OUTPUT("pcm0_out", SST_TASK_SBA, SST_SWM_OUT_PCM0, sst_set_media_path),
+ SST_PATH_OUTPUT("pcm1_out", SST_TASK_SBA, SST_SWM_OUT_PCM1, sst_set_media_path),
+ SST_PATH_OUTPUT("pcm2_out", SST_TASK_SBA, SST_SWM_OUT_PCM2, sst_set_media_path),
+
+ /* SBA Loops */
+ SST_PATH_INPUT("sprot_loop_in", SST_TASK_SBA, SST_SWM_IN_SPROT_LOOP, NULL),
+ SST_PATH_INPUT("media_loop1_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP1, NULL),
+ SST_PATH_INPUT("media_loop2_in", SST_TASK_SBA, SST_SWM_IN_MEDIA_LOOP2, NULL),
+ SST_PATH_MEDIA_LOOP_OUTPUT("sprot_loop_out", SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP, SST_FMT_MONO, sst_set_media_loop),
+ SST_PATH_MEDIA_LOOP_OUTPUT("media_loop1_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1, SST_FMT_MONO, sst_set_media_loop),
+ SST_PATH_MEDIA_LOOP_OUTPUT("media_loop2_out", SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2, SST_FMT_STEREO, sst_set_media_loop),
+
+ /* Media Mixers */
+ SST_SWM_MIXER("media0_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA0,
+ sst_mix_media0_controls, sst_swm_mixer_event),
+ SST_SWM_MIXER("media1_out mix 0", SND_SOC_NOPM, SST_TASK_MMX, SST_SWM_OUT_MEDIA1,
+ sst_mix_media1_controls, sst_swm_mixer_event),
+
+ /* SBA PCM mixers */
+ SST_SWM_MIXER("pcm0_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM0,
+ sst_mix_pcm0_controls, sst_swm_mixer_event),
+ SST_SWM_MIXER("pcm1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM1,
+ sst_mix_pcm1_controls, sst_swm_mixer_event),
+ SST_SWM_MIXER("pcm2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_PCM2,
+ sst_mix_pcm2_controls, sst_swm_mixer_event),
+
+ /* SBA Loop mixers */
+ SST_SWM_MIXER("sprot_loop_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_SPROT_LOOP,
+ sst_mix_sprot_l0_controls, sst_swm_mixer_event),
+ SST_SWM_MIXER("media_loop1_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP1,
+ sst_mix_media_l1_controls, sst_swm_mixer_event),
+ SST_SWM_MIXER("media_loop2_out mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_MEDIA_LOOP2,
+ sst_mix_media_l2_controls, sst_swm_mixer_event),
+
+ /* SBA Backend mixers */
+ SST_SWM_MIXER("codec_out0 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC0,
+ sst_mix_codec0_controls, sst_swm_mixer_event),
+ SST_SWM_MIXER("codec_out1 mix 0", SND_SOC_NOPM, SST_TASK_SBA, SST_SWM_OUT_CODEC1,
+ sst_mix_codec1_controls, sst_swm_mixer_event),
+};
+
+static const struct snd_soc_dapm_route intercon[] = {
+ {"media0_in", NULL, "Compress Playback"},
+ {"media1_in", NULL, "Headset Playback"},
+ {"media2_in", NULL, "pcm0_out"},
+
+ {"media0_out mix 0", "media0_in Switch", "media0_in"},
+ {"media0_out mix 0", "media1_in Switch", "media1_in"},
+ {"media0_out mix 0", "media2_in Switch", "media2_in"},
+ {"media0_out mix 0", "media3_in Switch", "media3_in"},
+ {"media1_out mix 0", "media0_in Switch", "media0_in"},
+ {"media1_out mix 0", "media1_in Switch", "media1_in"},
+ {"media1_out mix 0", "media2_in Switch", "media2_in"},
+ {"media1_out mix 0", "media3_in Switch", "media3_in"},
+
+ {"media0_out", NULL, "media0_out mix 0"},
+ {"media1_out", NULL, "media1_out mix 0"},
+ {"pcm0_in", NULL, "media0_out"},
+ {"pcm1_in", NULL, "media1_out"},
+
+ {"Headset Capture", NULL, "pcm1_out"},
+ {"Headset Capture", NULL, "pcm2_out"},
+ {"pcm0_out", NULL, "pcm0_out mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("pcm0_out mix 0"),
+ {"pcm1_out", NULL, "pcm1_out mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("pcm1_out mix 0"),
+ {"pcm2_out", NULL, "pcm2_out mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("pcm2_out mix 0"),
+
+ {"media_loop1_in", NULL, "media_loop1_out"},
+ {"media_loop1_out", NULL, "media_loop1_out mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("media_loop1_out mix 0"),
+ {"media_loop2_in", NULL, "media_loop2_out"},
+ {"media_loop2_out", NULL, "media_loop2_out mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("media_loop2_out mix 0"),
+ {"sprot_loop_in", NULL, "sprot_loop_out"},
+ {"sprot_loop_out", NULL, "sprot_loop_out mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("sprot_loop_out mix 0"),
+
+ {"codec_out0", NULL, "codec_out0 mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("codec_out0 mix 0"),
+ {"codec_out1", NULL, "codec_out1 mix 0"},
+ SST_SBA_MIXER_GRAPH_MAP("codec_out1 mix 0"),
+
+};
+static const char * const slot_names[] = {
+ "none",
+ "slot 0", "slot 1", "slot 2", "slot 3",
+ "slot 4", "slot 5", "slot 6", "slot 7", /* not supported by FW */
+};
+
+static const char * const channel_names[] = {
+ "none",
+ "codec_out0_0", "codec_out0_1", "codec_out1_0", "codec_out1_1",
+ "codec_out2_0", "codec_out2_1", "codec_out3_0", "codec_out3_1", /* not supported by FW */
+};
+
+#define SST_INTERLEAVER(xpname, slot_name, slotno) \
+ SST_SSP_SLOT_CTL(xpname, "tx interleaver", slot_name, slotno, true, \
+ channel_names, sst_slot_get, sst_slot_put)
+
+#define SST_DEINTERLEAVER(xpname, channel_name, channel_no) \
+ SST_SSP_SLOT_CTL(xpname, "rx deinterleaver", channel_name, channel_no, false, \
+ slot_names, sst_slot_get, sst_slot_put)
+
+static const struct snd_kcontrol_new sst_slot_controls[] = {
+ SST_INTERLEAVER("codec_out", "slot 0", 0),
+ SST_INTERLEAVER("codec_out", "slot 1", 1),
+ SST_INTERLEAVER("codec_out", "slot 2", 2),
+ SST_INTERLEAVER("codec_out", "slot 3", 3),
+ SST_DEINTERLEAVER("codec_in", "codec_in0_0", 0),
+ SST_DEINTERLEAVER("codec_in", "codec_in0_1", 1),
+ SST_DEINTERLEAVER("codec_in", "codec_in1_0", 2),
+ SST_DEINTERLEAVER("codec_in", "codec_in1_1", 3),
+};
+
+/* Gain helper with min/max set */
+#define SST_GAIN(name, path_id, task_id, instance, gain_var) \
+ SST_GAIN_KCONTROLS(name, "Gain", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \
+ SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \
+ sst_gain_get, sst_gain_put, \
+ SST_MODULE_ID_GAIN_CELL, path_id, instance, task_id, \
+ sst_gain_tlv_common, gain_var)
+
+#define SST_VOLUME(name, path_id, task_id, instance, gain_var) \
+ SST_GAIN_KCONTROLS(name, "Volume", SST_GAIN_MIN_VALUE, SST_GAIN_MAX_VALUE, \
+ SST_GAIN_TC_MIN, SST_GAIN_TC_MAX, \
+ sst_gain_get, sst_gain_put, \
+ SST_MODULE_ID_VOLUME, path_id, instance, task_id, \
+ sst_gain_tlv_common, gain_var)
+
+static struct sst_gain_value sst_gains[];
+
+static const struct snd_kcontrol_new sst_gain_controls[] = {
+ SST_GAIN("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[0]),
+ SST_GAIN("media1_in", SST_PATH_INDEX_MEDIA1_IN, SST_TASK_MMX, 0, &sst_gains[1]),
+ SST_GAIN("media2_in", SST_PATH_INDEX_MEDIA2_IN, SST_TASK_MMX, 0, &sst_gains[2]),
+ SST_GAIN("media3_in", SST_PATH_INDEX_MEDIA3_IN, SST_TASK_MMX, 0, &sst_gains[3]),
+
+ SST_GAIN("pcm0_in", SST_PATH_INDEX_PCM0_IN, SST_TASK_SBA, 0, &sst_gains[4]),
+ SST_GAIN("pcm1_in", SST_PATH_INDEX_PCM1_IN, SST_TASK_SBA, 0, &sst_gains[5]),
+ SST_GAIN("pcm1_out", SST_PATH_INDEX_PCM1_OUT, SST_TASK_SBA, 0, &sst_gains[6]),
+ SST_GAIN("pcm2_out", SST_PATH_INDEX_PCM2_OUT, SST_TASK_SBA, 0, &sst_gains[7]),
+
+ SST_GAIN("codec_in0", SST_PATH_INDEX_CODEC_IN0, SST_TASK_SBA, 0, &sst_gains[8]),
+ SST_GAIN("codec_in1", SST_PATH_INDEX_CODEC_IN1, SST_TASK_SBA, 0, &sst_gains[9]),
+ SST_GAIN("codec_out0", SST_PATH_INDEX_CODEC_OUT0, SST_TASK_SBA, 0, &sst_gains[10]),
+ SST_GAIN("codec_out1", SST_PATH_INDEX_CODEC_OUT1, SST_TASK_SBA, 0, &sst_gains[11]),
+ SST_GAIN("media_loop1_out", SST_PATH_INDEX_MEDIA_LOOP1_OUT, SST_TASK_SBA, 0, &sst_gains[12]),
+ SST_GAIN("media_loop2_out", SST_PATH_INDEX_MEDIA_LOOP2_OUT, SST_TASK_SBA, 0, &sst_gains[13]),
+ SST_GAIN("sprot_loop_out", SST_PATH_INDEX_SPROT_LOOP_OUT, SST_TASK_SBA, 0, &sst_gains[14]),
+ SST_VOLUME("media0_in", SST_PATH_INDEX_MEDIA0_IN, SST_TASK_MMX, 0, &sst_gains[15]),
+};
+
+#define SST_GAIN_NUM_CONTROLS 3
+/* the SST_GAIN macro above will create three alsa controls for each
+ * instance invoked, gain, mute and ramp duration, which use the same gain
+ * cell sst_gain to keep track of data
+ * To calculate number of gain cell instances we need to device by 3 in
+ * below caulcation for gain cell memory.
+ * This gets rid of static number and issues while adding new controls
+ */
+static struct sst_gain_value sst_gains[ARRAY_SIZE(sst_gain_controls)/SST_GAIN_NUM_CONTROLS];
+
static const struct snd_kcontrol_new sst_algo_controls[] = {
SST_ALGO_KCONTROL_BYTES("media_loop1_out", "fir", 272, SST_MODULE_ID_FIR_24,
SST_PATH_INDEX_MEDIA_LOOP1_OUT, 0, SST_TASK_SBA, SBA_VB_SET_FIR),
@@ -198,21 +1143,280 @@ static int sst_algo_control_init(struct device *dev)
return 0;
}
-int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+static bool is_sst_dapm_widget(struct snd_soc_dapm_widget *w)
+{
+ switch (w->id) {
+ case snd_soc_dapm_pga:
+ case snd_soc_dapm_aif_in:
+ case snd_soc_dapm_aif_out:
+ case snd_soc_dapm_input:
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_mixer:
+ return true;
+ default:
+ return false;
+ }
+}
+
+/**
+ * sst_send_pipe_gains - send gains for the front-end DAIs
+ *
+ * The gains in the pipes connected to the front-ends are muted/unmuted
+ * automatically via the digital_mute() DAPM callback. This function sends the
+ * gains for the front-end pipes.
+ */
+int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute)
+{
+ struct sst_data *drv = snd_soc_dai_get_drvdata(dai);
+ struct snd_soc_dapm_widget *w;
+ struct snd_soc_dapm_path *p = NULL;
+
+ dev_dbg(dai->dev, "enter, dai-name=%s dir=%d\n", dai->name, stream);
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ dev_dbg(dai->dev, "Stream name=%s\n",
+ dai->playback_widget->name);
+ w = dai->playback_widget;
+ list_for_each_entry(p, &w->sinks, list_source) {
+ if (p->connected && !p->connected(w, p->sink))
+ continue;
+
+ if (p->connect && p->sink->power &&
+ is_sst_dapm_widget(p->sink)) {
+ struct sst_ids *ids = p->sink->priv;
+
+ dev_dbg(dai->dev, "send gains for widget=%s\n",
+ p->sink->name);
+ mutex_lock(&drv->lock);
+ sst_set_pipe_gain(ids, drv, mute);
+ mutex_unlock(&drv->lock);
+ }
+ }
+ } else {
+ dev_dbg(dai->dev, "Stream name=%s\n",
+ dai->capture_widget->name);
+ w = dai->capture_widget;
+ list_for_each_entry(p, &w->sources, list_sink) {
+ if (p->connected && !p->connected(w, p->sink))
+ continue;
+
+ if (p->connect && p->source->power &&
+ is_sst_dapm_widget(p->source)) {
+ struct sst_ids *ids = p->source->priv;
+
+ dev_dbg(dai->dev, "send gain for widget=%s\n",
+ p->source->name);
+ mutex_lock(&drv->lock);
+ sst_set_pipe_gain(ids, drv, mute);
+ mutex_unlock(&drv->lock);
+ }
+ }
+ }
+ return 0;
+}
+
+/**
+ * sst_fill_module_list - populate the list of modules/gains for a pipe
+ *
+ *
+ * Fills the widget pointer in the kcontrol private data, and also fills the
+ * kcontrol pointer in the widget private data.
+ *
+ * Widget pointer is used to send the algo/gain in the .put() handler if the
+ * widget is powerd on.
+ *
+ * Kcontrol pointer is used to send the algo/gain in the widget power ON/OFF
+ * event handler. Each widget (pipe) has multiple algos stored in the algo_list.
+ */
+static int sst_fill_module_list(struct snd_kcontrol *kctl,
+ struct snd_soc_dapm_widget *w, int type)
{
+ struct sst_module *module = NULL;
+ struct snd_soc_component *c = snd_soc_dapm_to_component(w->dapm);
+ struct sst_ids *ids = w->priv;
int ret = 0;
+
+ module = devm_kzalloc(c->dev, sizeof(*module), GFP_KERNEL);
+ if (!module)
+ return -ENOMEM;
+
+ if (type == SST_MODULE_GAIN) {
+ struct sst_gain_mixer_control *mc = (void *)kctl->private_value;
+
+ mc->w = w;
+ module->kctl = kctl;
+ list_add_tail(&module->node, &ids->gain_list);
+ } else if (type == SST_MODULE_ALGO) {
+ struct sst_algo_control *bc = (void *)kctl->private_value;
+
+ bc->w = w;
+ module->kctl = kctl;
+ list_add_tail(&module->node, &ids->algo_list);
+ } else {
+ dev_err(c->dev, "invoked for unknown type %d module %s",
+ type, kctl->id.name);
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+/**
+ * sst_fill_widget_module_info - fill list of gains/algos for the pipe
+ * @widget: pipe modelled as a DAPM widget
+ *
+ * Fill the list of gains/algos for the widget by looking at all the card
+ * controls and comparing the name of the widget with the first part of control
+ * name. First part of control name contains the pipe name (widget name).
+ */
+static int sst_fill_widget_module_info(struct snd_soc_dapm_widget *w,
+ struct snd_soc_platform *platform)
+{
+ struct snd_kcontrol *kctl;
+ int index, ret = 0;
+ struct snd_card *card = platform->component.card->snd_card;
+ char *idx;
+
+ down_read(&card->controls_rwsem);
+
+ list_for_each_entry(kctl, &card->controls, list) {
+ idx = strstr(kctl->id.name, " ");
+ if (idx == NULL)
+ continue;
+ index = strlen(kctl->id.name) - strlen(idx);
+
+ if (strstr(kctl->id.name, "Volume") &&
+ !strncmp(kctl->id.name, w->name, index))
+ ret = sst_fill_module_list(kctl, w, SST_MODULE_GAIN);
+
+ else if (strstr(kctl->id.name, "params") &&
+ !strncmp(kctl->id.name, w->name, index))
+ ret = sst_fill_module_list(kctl, w, SST_MODULE_ALGO);
+
+ else if (strstr(kctl->id.name, "Switch") &&
+ !strncmp(kctl->id.name, w->name, index) &&
+ strstr(kctl->id.name, "Gain")) {
+ struct sst_gain_mixer_control *mc =
+ (void *)kctl->private_value;
+
+ mc->w = w;
+
+ } else if (strstr(kctl->id.name, "interleaver") &&
+ !strncmp(kctl->id.name, w->name, index)) {
+ struct sst_enum *e = (void *)kctl->private_value;
+
+ e->w = w;
+
+ } else if (strstr(kctl->id.name, "deinterleaver") &&
+ !strncmp(kctl->id.name, w->name, index)) {
+
+ struct sst_enum *e = (void *)kctl->private_value;
+
+ e->w = w;
+ }
+
+ if (ret < 0) {
+ up_read(&card->controls_rwsem);
+ return ret;
+ }
+ }
+
+ up_read(&card->controls_rwsem);
+ return 0;
+}
+
+/**
+ * sst_fill_linked_widgets - fill the parent pointer for the linked widget
+ */
+static void sst_fill_linked_widgets(struct snd_soc_platform *platform,
+ struct sst_ids *ids)
+{
+ struct snd_soc_dapm_widget *w;
+ unsigned int len = strlen(ids->parent_wname);
+
+ list_for_each_entry(w, &platform->component.card->widgets, list) {
+ if (!strncmp(ids->parent_wname, w->name, len)) {
+ ids->parent_w = w;
+ break;
+ }
+ }
+}
+
+/**
+ * sst_map_modules_to_pipe - fill algo/gains list for all pipes
+ */
+static int sst_map_modules_to_pipe(struct snd_soc_platform *platform)
+{
+ struct snd_soc_dapm_widget *w;
+ int ret = 0;
+
+ list_for_each_entry(w, &platform->component.card->widgets, list) {
+ if (is_sst_dapm_widget(w) && (w->priv)) {
+ struct sst_ids *ids = w->priv;
+
+ dev_dbg(platform->dev, "widget type=%d name=%s\n",
+ w->id, w->name);
+ INIT_LIST_HEAD(&ids->algo_list);
+ INIT_LIST_HEAD(&ids->gain_list);
+ ret = sst_fill_widget_module_info(w, platform);
+
+ if (ret < 0)
+ return ret;
+
+ /* fill linked widgets */
+ if (ids->parent_wname != NULL)
+ sst_fill_linked_widgets(platform, ids);
+ }
+ }
+ return 0;
+}
+
+int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform)
+{
+ int i, ret = 0;
+ struct snd_soc_dapm_context *dapm =
+ snd_soc_component_get_dapm(&platform->component);
struct sst_data *drv = snd_soc_platform_get_drvdata(platform);
+ unsigned int gains = ARRAY_SIZE(sst_gain_controls)/3;
drv->byte_stream = devm_kzalloc(platform->dev,
SST_MAX_BIN_BYTES, GFP_KERNEL);
if (!drv->byte_stream)
return -ENOMEM;
- /*Initialize algo control params*/
+ snd_soc_dapm_new_controls(dapm, sst_dapm_widgets,
+ ARRAY_SIZE(sst_dapm_widgets));
+ snd_soc_dapm_add_routes(dapm, intercon,
+ ARRAY_SIZE(intercon));
+ snd_soc_dapm_new_widgets(dapm->card);
+
+ for (i = 0; i < gains; i++) {
+ sst_gains[i].mute = SST_GAIN_MUTE_DEFAULT;
+ sst_gains[i].l_gain = SST_GAIN_VOLUME_DEFAULT;
+ sst_gains[i].r_gain = SST_GAIN_VOLUME_DEFAULT;
+ sst_gains[i].ramp_duration = SST_GAIN_RAMP_DURATION_DEFAULT;
+ }
+
+ ret = snd_soc_add_platform_controls(platform, sst_gain_controls,
+ ARRAY_SIZE(sst_gain_controls));
+ if (ret)
+ return ret;
+
+ /* Initialize algo control params */
ret = sst_algo_control_init(platform->dev);
if (ret)
return ret;
ret = snd_soc_add_platform_controls(platform, sst_algo_controls,
ARRAY_SIZE(sst_algo_controls));
+ if (ret)
+ return ret;
+
+ ret = snd_soc_add_platform_controls(platform, sst_slot_controls,
+ ARRAY_SIZE(sst_slot_controls));
+ if (ret)
+ return ret;
+
+ ret = sst_map_modules_to_pipe(platform);
+
return ret;
}
diff --git a/sound/soc/intel/sst-atom-controls.h b/sound/soc/intel/sst-atom-controls.h
index a73e894..dfebfdd 100644
--- a/sound/soc/intel/sst-atom-controls.h
+++ b/sound/soc/intel/sst-atom-controls.h
@@ -23,6 +23,9 @@
#ifndef __SST_ATOM_CONTROLS_H__
#define __SST_ATOM_CONTROLS_H__
+#include <sound/soc.h>
+#include <sound/tlv.h>
+
enum {
MERR_DPCM_AUDIO = 0,
MERR_DPCM_COMPR,
@@ -360,16 +363,416 @@ struct sst_dsp_header {
struct sst_cmd_generic {
struct sst_dsp_header header;
} __packed;
+
+struct swm_input_ids {
+ struct sst_destination_id input_id;
+} __packed;
+
+struct sst_cmd_set_swm {
+ struct sst_dsp_header header;
+ struct sst_destination_id output_id;
+ u16 switch_state;
+ u16 nb_inputs;
+ struct swm_input_ids input[SST_CMD_SWM_MAX_INPUTS];
+} __packed;
+
+struct sst_cmd_set_media_path {
+ struct sst_dsp_header header;
+ u16 switch_state;
+} __packed;
+
+struct pcm_cfg {
+ u8 s_length:2;
+ u8 rate:3;
+ u8 format:3;
+} __packed;
+
+struct sst_cmd_set_speech_path {
+ struct sst_dsp_header header;
+ u16 switch_state;
+ struct {
+ u16 rsvd:8;
+ struct pcm_cfg cfg;
+ } config;
+} __packed;
+
+struct gain_cell {
+ struct sst_destination_id dest;
+ s16 cell_gain_left;
+ s16 cell_gain_right;
+ u16 gain_time_constant;
+} __packed;
+
+#define NUM_GAIN_CELLS 1
+struct sst_cmd_set_gain_dual {
+ struct sst_dsp_header header;
+ u16 gain_cell_num;
+ struct gain_cell cell_gains[NUM_GAIN_CELLS];
+} __packed;
struct sst_cmd_set_params {
struct sst_destination_id dst;
u16 command_id;
char params[0];
} __packed;
+
+
+struct sst_cmd_sba_vb_start {
+ struct sst_dsp_header header;
+} __packed;
+
+union sba_media_loop_params {
+ struct {
+ u16 rsvd:8;
+ struct pcm_cfg cfg;
+ } part;
+ u16 full;
+} __packed;
+
+struct sst_cmd_sba_set_media_loop_map {
+ struct sst_dsp_header header;
+ u16 switch_state;
+ union sba_media_loop_params param;
+ u16 map;
+} __packed;
+
+struct sst_cmd_tone_stop {
+ struct sst_dsp_header header;
+ u16 switch_state;
+} __packed;
+
+enum sst_ssp_mode {
+ SSP_MODE_MASTER = 0,
+ SSP_MODE_SLAVE = 1,
+};
+
+enum sst_ssp_pcm_mode {
+ SSP_PCM_MODE_NORMAL = 0,
+ SSP_PCM_MODE_NETWORK = 1,
+};
+
+enum sst_ssp_duplex {
+ SSP_DUPLEX = 0,
+ SSP_RX = 1,
+ SSP_TX = 2,
+};
+
+enum sst_ssp_fs_frequency {
+ SSP_FS_8_KHZ = 0,
+ SSP_FS_16_KHZ = 1,
+ SSP_FS_44_1_KHZ = 2,
+ SSP_FS_48_KHZ = 3,
+};
+
+enum sst_ssp_fs_polarity {
+ SSP_FS_ACTIVE_LOW = 0,
+ SSP_FS_ACTIVE_HIGH = 1,
+};
+
+enum sst_ssp_protocol {
+ SSP_MODE_PCM = 0,
+ SSP_MODE_I2S = 1,
+};
+
+enum sst_ssp_port_id {
+ SSP_MODEM = 0,
+ SSP_BT = 1,
+ SSP_FM = 2,
+ SSP_CODEC = 3,
+};
+
+struct sst_cmd_sba_hw_set_ssp {
+ struct sst_dsp_header header;
+ u16 selection; /* 0:SSP0(def), 1:SSP1, 2:SSP2 */
+
+ u16 switch_state;
+
+ u16 nb_bits_per_slots:6; /* 0-32 bits, 24 (def) */
+ u16 nb_slots:4; /* 0-8: slots per frame */
+ u16 mode:3; /* 0:Master, 1: Slave */
+ u16 duplex:3;
+
+ u16 active_tx_slot_map:8; /* Bit map, 0:off, 1:on */
+ u16 reserved1:8;
+
+ u16 active_rx_slot_map:8; /* Bit map 0: Off, 1:On */
+ u16 reserved2:8;
+
+ u16 frame_sync_frequency;
+
+ u16 frame_sync_polarity:8;
+ u16 data_polarity:8;
+
+ u16 frame_sync_width; /* 1 to N clocks */
+ u16 ssp_protocol:8;
+ u16 start_delay:8; /* Start delay in terms of clock ticks */
+} __packed;
+
+#define SST_MAX_TDM_SLOTS 8
+
+struct sst_param_sba_ssp_slot_map {
+ struct sst_dsp_header header;
+
+ u16 param_id;
+ u16 param_len;
+ u16 ssp_index;
+
+ u8 rx_slot_map[SST_MAX_TDM_SLOTS];
+ u8 tx_slot_map[SST_MAX_TDM_SLOTS];
+} __packed;
+
+enum {
+ SST_PROBE_EXTRACTOR = 0,
+ SST_PROBE_INJECTOR = 1,
+};
+
+/**** widget defines *****/
+
+#define SST_MODULE_GAIN 1
+#define SST_MODULE_ALGO 2
+
+#define SST_FMT_MONO 0
+#define SST_FMT_STEREO 3
+
+/* physical SSP numbers */
+enum {
+ SST_SSP0 = 0,
+ SST_SSP1,
+ SST_SSP2,
+ SST_SSP_LAST = SST_SSP2,
+};
+
+#define SST_NUM_SSPS (SST_SSP_LAST + 1) /* physical SSPs */
+#define SST_MAX_SSP_MUX 2 /* single SSP muxed between pipes */
+#define SST_MAX_SSP_DOMAINS 2 /* domains present in each pipe */
+
+struct sst_module {
+ struct snd_kcontrol *kctl;
+ struct list_head node;
+};
+
+struct sst_ssp_config {
+ u8 ssp_id;
+ u8 bits_per_slot;
+ u8 slots;
+ u8 ssp_mode;
+ u8 pcm_mode;
+ u8 duplex;
+ u8 ssp_protocol;
+ u8 fs_frequency;
+ u8 active_slot_map;
+ u8 start_delay;
+ u16 fs_width;
+};
+
+struct sst_ssp_cfg {
+ const u8 ssp_number;
+ const int *mux_shift;
+ const int (*domain_shift)[SST_MAX_SSP_MUX];
+ const struct sst_ssp_config (*ssp_config)[SST_MAX_SSP_MUX][SST_MAX_SSP_DOMAINS];
+};
+
+struct sst_ids {
+ u16 location_id;
+ u16 module_id;
+ u8 task_id;
+ u8 format;
+ u8 reg;
+ const char *parent_wname;
+ struct snd_soc_dapm_widget *parent_w;
+ struct list_head algo_list;
+ struct list_head gain_list;
+ const struct sst_pcm_format *pcm_fmt;
+};
+
+
+#define SST_AIF_IN(wname, wevent) \
+{ .id = snd_soc_dapm_aif_in, .name = wname, .sname = NULL, \
+ .reg = SND_SOC_NOPM, .shift = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
+ .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
+}
+
+#define SST_AIF_OUT(wname, wevent) \
+{ .id = snd_soc_dapm_aif_out, .name = wname, .sname = NULL, \
+ .reg = SND_SOC_NOPM, .shift = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
+ .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
+}
+
+#define SST_INPUT(wname, wevent) \
+{ .id = snd_soc_dapm_input, .name = wname, .sname = NULL, \
+ .reg = SND_SOC_NOPM, .shift = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
+ .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
+}
+
+#define SST_OUTPUT(wname, wevent) \
+{ .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \
+ .reg = SND_SOC_NOPM, .shift = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
+ .priv = (void *)&(struct sst_ids) { .task_id = 0, .location_id = 0 } \
+}
+
+#define SST_DAPM_OUTPUT(wname, wloc_id, wtask_id, wformat, wevent) \
+{ .id = snd_soc_dapm_output, .name = wname, .sname = NULL, \
+ .reg = SND_SOC_NOPM, .shift = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD, \
+ .priv = (void *)&(struct sst_ids) { .location_id = wloc_id, .task_id = wtask_id,\
+ .pcm_fmt = wformat, } \
+}
+
+#define SST_PATH(wname, wtask, wloc_id, wevent, wflags) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
+ .kcontrol_news = NULL, .num_kcontrols = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = wflags, \
+ .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, } \
+}
+
+#define SST_LINKED_PATH(wname, wtask, wloc_id, linked_wname, wevent, wflags) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
+ .kcontrol_news = NULL, .num_kcontrols = 0, \
+ .on_val = 1, .off_val = 0, \
+ .event = wevent, .event_flags = wflags, \
+ .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \
+ .parent_wname = linked_wname} \
+}
+
+#define SST_PATH_MEDIA_LOOP(wname, wtask, wloc_id, wformat, wevent, wflags) \
+{ .id = snd_soc_dapm_pga, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
+ .kcontrol_news = NULL, .num_kcontrols = 0, \
+ .event = wevent, .event_flags = wflags, \
+ .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \
+ .format = wformat,} \
+}
+
+/* output is triggered before input */
+#define SST_PATH_INPUT(name, task_id, loc_id, event) \
+ SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+
+#define SST_PATH_LINKED_INPUT(name, task_id, loc_id, linked_wname, event) \
+ SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \
+ SND_SOC_DAPM_POST_PMU | SND_SOC_DAPM_PRE_PMD)
+
+#define SST_PATH_OUTPUT(name, task_id, loc_id, event) \
+ SST_PATH(name, task_id, loc_id, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
+
+#define SST_PATH_LINKED_OUTPUT(name, task_id, loc_id, linked_wname, event) \
+ SST_LINKED_PATH(name, task_id, loc_id, linked_wname, event, \
+ SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
+
+#define SST_PATH_MEDIA_LOOP_OUTPUT(name, task_id, loc_id, format, event) \
+ SST_PATH_MEDIA_LOOP(name, task_id, loc_id, format, event, SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD)
+
+
+#define SST_SWM_MIXER(wname, wreg, wtask, wloc_id, wcontrols, wevent) \
+{ .id = snd_soc_dapm_mixer, .name = wname, .reg = SND_SOC_NOPM, .shift = 0, \
+ .kcontrol_news = wcontrols, .num_kcontrols = ARRAY_SIZE(wcontrols),\
+ .event = wevent, .event_flags = SND_SOC_DAPM_PRE_PMU | SND_SOC_DAPM_POST_PMD | \
+ SND_SOC_DAPM_POST_REG, \
+ .priv = (void *)&(struct sst_ids) { .task_id = wtask, .location_id = wloc_id, \
+ .reg = wreg } \
+}
+
+enum sst_gain_kcontrol_type {
+ SST_GAIN_TLV,
+ SST_GAIN_MUTE,
+ SST_GAIN_RAMP_DURATION,
+};
+
+struct sst_gain_mixer_control {
+ bool stereo;
+ enum sst_gain_kcontrol_type type;
+ struct sst_gain_value *gain_val;
+ int max;
+ int min;
+ u16 instance_id;
+ u16 module_id;
+ u16 pipe_id;
+ u16 task_id;
+ char pname[44];
+ struct snd_soc_dapm_widget *w;
+};
+
+struct sst_gain_value {
+ u16 ramp_duration;
+ s16 l_gain;
+ s16 r_gain;
+ bool mute;
+};
+#define SST_GAIN_VOLUME_DEFAULT (-1440)
+#define SST_GAIN_RAMP_DURATION_DEFAULT 5 /* timeconstant */
+#define SST_GAIN_MUTE_DEFAULT true
+
+#define SST_GAIN_KCONTROL_TLV(xname, xhandler_get, xhandler_put, \
+ xmod, xpipe, xinstance, xtask, tlv_array, xgain_val, \
+ xmin, xmax, xpname) \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .access = SNDRV_CTL_ELEM_ACCESS_TLV_READ | \
+ SNDRV_CTL_ELEM_ACCESS_READWRITE, \
+ .tlv.p = (tlv_array), \
+ .info = sst_gain_ctl_info,\
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
+ { .stereo = true, .max = xmax, .min = xmin, .type = SST_GAIN_TLV, \
+ .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
+ .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
+
+#define SST_GAIN_KCONTROL_INT(xname, xhandler_get, xhandler_put, \
+ xmod, xpipe, xinstance, xtask, xtype, xgain_val, \
+ xmin, xmax, xpname) \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = sst_gain_ctl_info, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
+ { .stereo = false, .max = xmax, .min = xmin, .type = xtype, \
+ .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
+ .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
+
+#define SST_GAIN_KCONTROL_BOOL(xname, xhandler_get, xhandler_put,\
+ xmod, xpipe, xinstance, xtask, xgain_val, xpname) \
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, .name = xname, \
+ .info = snd_soc_info_bool_ext, \
+ .get = xhandler_get, .put = xhandler_put, \
+ .private_value = (unsigned long)&(struct sst_gain_mixer_control) \
+ { .stereo = false, .type = SST_GAIN_MUTE, \
+ .module_id = xmod, .pipe_id = xpipe, .task_id = xtask,\
+ .instance_id = xinstance, .gain_val = xgain_val, .pname = xpname}
#define SST_CONTROL_NAME(xpname, xmname, xinstance, xtype) \
xpname " " xmname " " #xinstance " " xtype
#define SST_COMBO_CONTROL_NAME(xpname, xmname, xinstance, xtype, xsubmodule) \
xpname " " xmname " " #xinstance " " xtype " " xsubmodule
+
+/*
+ * 3 Controls for each Gain module
+ * e.g. - pcm0_in Gain 0 Volume
+ * - pcm0_in Gain 0 Ramp Delay
+ * - pcm0_in Gain 0 Switch
+ */
+#define SST_GAIN_KCONTROLS(xpname, xmname, xmin_gain, xmax_gain, xmin_tc, xmax_tc, \
+ xhandler_get, xhandler_put, \
+ xmod, xpipe, xinstance, xtask, tlv_array, xgain_val) \
+ { SST_GAIN_KCONTROL_INT(SST_CONTROL_NAME(xpname, xmname, xinstance, "Ramp Delay"), \
+ xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, SST_GAIN_RAMP_DURATION, \
+ xgain_val, xmin_tc, xmax_tc, xpname) }, \
+ { SST_GAIN_KCONTROL_BOOL(SST_CONTROL_NAME(xpname, xmname, xinstance, "Switch"), \
+ xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, \
+ xgain_val, xpname) } ,\
+ { SST_GAIN_KCONTROL_TLV(SST_CONTROL_NAME(xpname, xmname, xinstance, "Volume"), \
+ xhandler_get, xhandler_put, xmod, xpipe, xinstance, xtask, tlv_array, \
+ xgain_val, xmin_gain, xmax_gain, xpname) }
+
+#define SST_GAIN_TC_MIN 5
+#define SST_GAIN_TC_MAX 5000
+#define SST_GAIN_MIN_VALUE -1440 /* in 0.1 DB units */
+#define SST_GAIN_MAX_VALUE 360
+
enum sst_algo_kcontrol_type {
SST_ALGO_PARAMS,
SST_ALGO_BYPASS,
@@ -439,4 +842,29 @@ struct sst_enum {
struct snd_soc_dapm_widget *w;
};
+/* only 4 slots/channels supported atm */
+#define SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts) \
+ (struct sst_enum){ .reg = s_ch_no, .tx = is_tx, .max = 4+1, .texts = xtexts, }
+
+#define SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name) \
+ xpname " " xmname " " s_ch_name
+
+#define SST_SSP_SLOT_CTL(xpname, xmname, s_ch_name, s_ch_no, is_tx, xtexts, xget, xput) \
+{ .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \
+ .name = SST_SLOT_CTL_NAME(xpname, xmname, s_ch_name), \
+ .info = sst_slot_enum_info, \
+ .get = xget, .put = xput, \
+ .private_value = (unsigned long)&SST_SSP_SLOT_ENUM(s_ch_no, is_tx, xtexts), \
+}
+
+#define SST_MUX_CTL_NAME(xpname, xinstance) \
+ xpname " " #xinstance
+
+#define SST_SSP_MUX_ENUM(xreg, xshift, xtexts) \
+ (struct soc_enum) SOC_ENUM_DOUBLE(xreg, xshift, xshift, ARRAY_SIZE(xtexts), xtexts)
+
+#define SST_SSP_MUX_CTL(xpname, xinstance, xreg, xshift, xtexts) \
+ SOC_DAPM_ENUM(SST_MUX_CTL_NAME(xpname, xinstance), \
+ SST_SSP_MUX_ENUM(xreg, xshift, xtexts))
+
#endif
diff --git a/sound/soc/intel/sst-baytrail-dsp.c b/sound/soc/intel/sst-baytrail-dsp.c
index fc58876..5a9e567 100644
--- a/sound/soc/intel/sst-baytrail-dsp.c
+++ b/sound/soc/intel/sst-baytrail-dsp.c
@@ -67,17 +67,12 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
{
struct dma_block_info *block;
struct sst_module *mod;
- struct sst_module_data block_data;
struct sst_module_template template;
int count;
memset(&template, 0, sizeof(template));
template.id = module->type;
template.entry = module->entry_point;
- template.p.type = SST_MEM_DRAM;
- template.p.data_type = SST_DATA_P;
- template.s.type = SST_MEM_DRAM;
- template.s.data_type = SST_DATA_S;
mod = sst_module_new(fw, &template, NULL);
if (mod == NULL)
@@ -94,19 +89,19 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
switch (block->type) {
case SST_BYT_IRAM:
- block_data.offset = block->ram_offset +
+ mod->offset = block->ram_offset +
dsp->addr.iram_offset;
- block_data.type = SST_MEM_IRAM;
+ mod->type = SST_MEM_IRAM;
break;
case SST_BYT_DRAM:
- block_data.offset = block->ram_offset +
+ mod->offset = block->ram_offset +
dsp->addr.dram_offset;
- block_data.type = SST_MEM_DRAM;
+ mod->type = SST_MEM_DRAM;
break;
case SST_BYT_CACHE:
- block_data.offset = block->ram_offset +
+ mod->offset = block->ram_offset +
(dsp->addr.fw_ext - dsp->addr.lpe);
- block_data.type = SST_MEM_CACHE;
+ mod->type = SST_MEM_CACHE;
break;
default:
dev_err(dsp->dev, "wrong ram type 0x%x in block0x%x\n",
@@ -114,11 +109,10 @@ static int sst_byt_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
return -EINVAL;
}
- block_data.size = block->size;
- block_data.data_type = SST_DATA_M;
- block_data.data = (void *)block + sizeof(*block);
+ mod->size = block->size;
+ mod->data = (void *)block + sizeof(*block);
- sst_module_insert_fixed_block(mod, &block_data);
+ sst_module_alloc_blocks(mod);
block = (void *)block + sizeof(*block) + block->size;
}
diff --git a/sound/soc/intel/sst-dsp-priv.h b/sound/soc/intel/sst-dsp-priv.h
index ffb308b..b9da030 100644
--- a/sound/soc/intel/sst-dsp-priv.h
+++ b/sound/soc/intel/sst-dsp-priv.h
@@ -26,6 +26,9 @@ struct sst_mem_block;
struct sst_module;
struct sst_fw;
+/* do we need to remove or keep */
+#define DSP_DRAM_ADDR_OFFSET 0x400000
+
/*
* DSP Operations exported by platform Audio DSP driver.
*/
@@ -33,6 +36,9 @@ struct sst_ops {
/* DSP core boot / reset */
void (*boot)(struct sst_dsp *);
void (*reset)(struct sst_dsp *);
+ int (*wake)(struct sst_dsp *);
+ void (*sleep)(struct sst_dsp *);
+ void (*stall)(struct sst_dsp *);
/* Shim IO */
void (*write)(void __iomem *addr, u32 offset, u32 value);
@@ -67,6 +73,8 @@ struct sst_addr {
u32 shim_offset;
u32 iram_offset;
u32 dram_offset;
+ u32 dsp_iram_offset;
+ u32 dsp_dram_offset;
void __iomem *lpe;
void __iomem *shim;
void __iomem *pci_cfg;
@@ -84,15 +92,6 @@ struct sst_mailbox {
};
/*
- * Audio DSP Firmware data types.
- */
-enum sst_data_type {
- SST_DATA_M = 0, /* module block data */
- SST_DATA_P = 1, /* peristant data (text, data) */
- SST_DATA_S = 2, /* scratch data (usually buffers) */
-};
-
-/*
* Audio DSP memory block types.
*/
enum sst_mem_type {
@@ -125,23 +124,6 @@ struct sst_fw {
};
/*
- * Audio DSP Generic Module data.
- *
- * This is used to dsecribe any sections of persistent (text and data) and
- * scratch (buffers) of module data in ADSP memory space.
- */
-struct sst_module_data {
-
- enum sst_mem_type type; /* destination memory type */
- enum sst_data_type data_type; /* type of module data */
-
- u32 size; /* size in bytes */
- int32_t offset; /* offset in FW file */
- u32 data_offset; /* offset in ADSP memory space */
- void *data; /* module data */
-};
-
-/*
* Audio DSP Generic Module Template.
*
* Used to define and register a new FW module. This data is extracted from
@@ -150,15 +132,52 @@ struct sst_module_data {
struct sst_module_template {
u32 id;
u32 entry; /* entry point */
- struct sst_module_data s; /* scratch data */
- struct sst_module_data p; /* peristant data */
+ u32 scratch_size;
+ u32 persistent_size;
+};
+
+/*
+ * Block Allocator - Used to allocate blocks of DSP memory.
+ */
+struct sst_block_allocator {
+ u32 id;
+ u32 offset;
+ int size;
+ enum sst_mem_type type;
+};
+
+/*
+ * Runtime Module Instance - A module object can be instanciated multiple
+ * times within the DSP FW.
+ */
+struct sst_module_runtime {
+ struct sst_dsp *dsp;
+ int id;
+ struct sst_module *module; /* parent module we belong too */
+
+ u32 persistent_offset; /* private memory offset */
+ void *private;
+
+ struct list_head list;
+ struct list_head block_list; /* list of blocks used */
+};
+
+/*
+ * Runtime Module Context - The runtime context must be manually stored by the
+ * driver prior to enter S3 and restored after leaving S3. This should really be
+ * part of the memory context saved by the enter D3 message IPC ???
+ */
+struct sst_module_runtime_context {
+ dma_addr_t dma_buffer;
+ u32 *buffer;
};
/*
* Audio DSP Generic Module.
*
* Each Firmware file can consist of 1..N modules. A module can span multiple
- * ADSP memory blocks. The simplest FW will be a file with 1 module.
+ * ADSP memory blocks. The simplest FW will be a file with 1 module. A module
+ * can be instanciated multiple times in the DSP.
*/
struct sst_module {
struct sst_dsp *dsp;
@@ -167,10 +186,13 @@ struct sst_module {
/* module configuration */
u32 id;
u32 entry; /* module entry point */
- u32 offset; /* module offset in firmware file */
+ s32 offset; /* module offset in firmware file */
u32 size; /* module size */
- struct sst_module_data s; /* scratch data */
- struct sst_module_data p; /* peristant data */
+ u32 scratch_size; /* global scratch memory required */
+ u32 persistent_size; /* private memory required */
+ enum sst_mem_type type; /* destination memory type */
+ u32 data_offset; /* offset in ADSP memory space */
+ void *data; /* module data */
/* runtime */
u32 usage_count; /* can be unloaded if count == 0 */
@@ -180,6 +202,7 @@ struct sst_module {
struct list_head block_list; /* Module list of blocks in use */
struct list_head list; /* DSP list of modules */
struct list_head list_fw; /* FW list of modules */
+ struct list_head runtime_list; /* list of runtime module objects*/
};
/*
@@ -208,7 +231,6 @@ struct sst_mem_block {
struct sst_block_ops *ops; /* block operations, if any */
/* block status */
- enum sst_data_type data_type; /* data type held in this block */
u32 bytes_used; /* bytes in use by modules */
void *private; /* generic core does not touch this */
int users; /* number of modules using this block */
@@ -253,6 +275,11 @@ struct sst_dsp {
struct list_head module_list;
struct list_head fw_list;
+ /* scratch buffer */
+ struct list_head scratch_block_list;
+ u32 scratch_offset;
+ u32 scratch_size;
+
/* platform data */
struct sst_pdata *pdata;
@@ -290,18 +317,33 @@ void sst_fw_unload(struct sst_fw *sst_fw);
/* Create/Free firmware modules */
struct sst_module *sst_module_new(struct sst_fw *sst_fw,
struct sst_module_template *template, void *private);
-void sst_module_free(struct sst_module *sst_module);
-int sst_module_insert(struct sst_module *sst_module);
-int sst_module_remove(struct sst_module *sst_module);
-int sst_module_insert_fixed_block(struct sst_module *module,
- struct sst_module_data *data);
+void sst_module_free(struct sst_module *module);
struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id);
-
-/* allocate/free pesistent/scratch memory regions managed by drv */
-struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp);
-void sst_mem_block_free_scratch(struct sst_dsp *dsp,
- struct sst_module *scratch);
-int sst_block_module_remove(struct sst_module *module);
+int sst_module_alloc_blocks(struct sst_module *module);
+int sst_module_free_blocks(struct sst_module *module);
+
+/* Create/Free firmware module runtime instances */
+struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
+ int id, void *private);
+void sst_module_runtime_free(struct sst_module_runtime *runtime);
+struct sst_module_runtime *sst_module_runtime_get_from_id(
+ struct sst_module *module, u32 id);
+int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
+ int offset);
+int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime);
+int sst_module_runtime_save(struct sst_module_runtime *runtime,
+ struct sst_module_runtime_context *context);
+int sst_module_runtime_restore(struct sst_module_runtime *runtime,
+ struct sst_module_runtime_context *context);
+
+/* generic block allocation */
+int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+ struct list_head *block_list);
+int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list);
+
+/* scratch allocation */
+int sst_block_alloc_scratch(struct sst_dsp *dsp);
+void sst_block_free_scratch(struct sst_dsp *dsp);
/* Register the DSPs memory blocks - would be nice to read from ACPI */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
@@ -309,4 +351,10 @@ struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
void *private);
void sst_mem_block_unregister_all(struct sst_dsp *dsp);
+/* Create/Free DMA resources */
+int sst_dma_new(struct sst_dsp *sst);
+void sst_dma_free(struct sst_dma *dma);
+
+u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
+ enum sst_mem_type type);
#endif
diff --git a/sound/soc/intel/sst-dsp.c b/sound/soc/intel/sst-dsp.c
index cd23060..86e4108 100644
--- a/sound/soc/intel/sst-dsp.c
+++ b/sound/soc/intel/sst-dsp.c
@@ -245,6 +245,29 @@ int sst_dsp_boot(struct sst_dsp *sst)
}
EXPORT_SYMBOL_GPL(sst_dsp_boot);
+int sst_dsp_wake(struct sst_dsp *sst)
+{
+ if (sst->ops->wake)
+ return sst->ops->wake(sst);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_wake);
+
+void sst_dsp_sleep(struct sst_dsp *sst)
+{
+ if (sst->ops->sleep)
+ sst->ops->sleep(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_sleep);
+
+void sst_dsp_stall(struct sst_dsp *sst)
+{
+ if (sst->ops->stall)
+ sst->ops->stall(sst);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_stall);
+
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg)
{
sst_dsp_shim_write_unlocked(dsp, SST_IPCX, msg | SST_IPCX_BUSY);
@@ -352,6 +375,7 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
INIT_LIST_HEAD(&sst->free_block_list);
INIT_LIST_HEAD(&sst->module_list);
INIT_LIST_HEAD(&sst->fw_list);
+ INIT_LIST_HEAD(&sst->scratch_block_list);
/* Initialise SST Audio DSP */
if (sst->ops->init) {
@@ -366,6 +390,10 @@ struct sst_dsp *sst_dsp_new(struct device *dev,
if (err)
goto irq_err;
+ err = sst_dma_new(sst);
+ if (err)
+ dev_warn(dev, "sst_dma_new failed %d\n", err);
+
return sst;
irq_err:
@@ -381,6 +409,9 @@ void sst_dsp_free(struct sst_dsp *sst)
free_irq(sst->irq, sst);
if (sst->ops->free)
sst->ops->free(sst);
+
+ if (sst->dma)
+ sst_dma_free(sst->dma);
}
EXPORT_SYMBOL_GPL(sst_dsp_free);
diff --git a/sound/soc/intel/sst-dsp.h b/sound/soc/intel/sst-dsp.h
index 3165dfa..f291e32 100644
--- a/sound/soc/intel/sst-dsp.h
+++ b/sound/soc/intel/sst-dsp.h
@@ -30,6 +30,9 @@
#define SST_DMA_TYPE_DW 1
#define SST_DMA_TYPE_MID 2
+/* autosuspend delay 5s*/
+#define SST_RUNTIME_SUSPEND_DELAY (5 * 1000)
+
/* SST Shim register map
* The register naming can differ between products. Some products also
* contain extra functionality.
@@ -156,12 +159,18 @@
#define SST_VDRTCTL3 0xaC
/* VDRTCTL0 */
-#define SST_VDRTCL0_APLLSE_MASK 1
-#define SST_VDRTCL0_DSRAMPGE_SHIFT 16
-#define SST_VDRTCL0_DSRAMPGE_MASK (0xffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
-#define SST_VDRTCL0_ISRAMPGE_SHIFT 6
+#define SST_VDRTCL0_D3PGD (1 << 0)
+#define SST_VDRTCL0_D3SRAMPGD (1 << 1)
+#define SST_VDRTCL0_DSRAMPGE_SHIFT 12
+#define SST_VDRTCL0_DSRAMPGE_MASK (0xfffff << SST_VDRTCL0_DSRAMPGE_SHIFT)
+#define SST_VDRTCL0_ISRAMPGE_SHIFT 2
#define SST_VDRTCL0_ISRAMPGE_MASK (0x3ff << SST_VDRTCL0_ISRAMPGE_SHIFT)
+/* VDRTCTL2 */
+#define SST_VDRTCL2_DCLCGE (1 << 1)
+#define SST_VDRTCL2_DTCGE (1 << 10)
+#define SST_VDRTCL2_APLLSE_MASK (1 << 31)
+
/* PMCS */
#define SST_PMCS 0x84
#define SST_PMCS_PS_MASK 0x3
@@ -245,6 +254,17 @@ void sst_memcpy_fromio_32(struct sst_dsp *sst,
/* DSP reset & boot */
void sst_dsp_reset(struct sst_dsp *sst);
int sst_dsp_boot(struct sst_dsp *sst);
+int sst_dsp_wake(struct sst_dsp *sst);
+void sst_dsp_sleep(struct sst_dsp *sst);
+void sst_dsp_stall(struct sst_dsp *sst);
+
+/* DMA */
+int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id);
+void sst_dsp_dma_put_channel(struct sst_dsp *dsp);
+int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
+ dma_addr_t src_addr, size_t size);
+int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
+ dma_addr_t src_addr, size_t size);
/* Msg IO */
void sst_dsp_ipc_msg_tx(struct sst_dsp *dsp, u32 msg);
diff --git a/sound/soc/intel/sst-firmware.c b/sound/soc/intel/sst-firmware.c
index 3bb43da..4a5bde9 100644
--- a/sound/soc/intel/sst-firmware.c
+++ b/sound/soc/intel/sst-firmware.c
@@ -23,6 +23,11 @@
#include <linux/dma-mapping.h>
#include <linux/dmaengine.h>
#include <linux/pci.h>
+#include <linux/acpi.h>
+
+/* supported DMA engine drivers */
+#include <linux/platform_data/dma-dw.h>
+#include <linux/dma/dw.h>
#include <asm/page.h>
#include <asm/pgtable.h>
@@ -30,16 +35,301 @@
#include "sst-dsp.h"
#include "sst-dsp-priv.h"
-static void block_module_remove(struct sst_module *module);
+#define SST_DMA_RESOURCES 2
+#define SST_DSP_DMA_MAX_BURST 0x3
+#define SST_HSW_BLOCK_ANY 0xffffffff
+
+#define SST_HSW_MASK_DMA_ADDR_DSP 0xfff00000
+
+struct sst_dma {
+ struct sst_dsp *sst;
+
+ struct dw_dma_chip *chip;
+
+ struct dma_async_tx_descriptor *desc;
+ struct dma_chan *ch;
+};
+
+static inline void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
+{
+ /* __iowrite32_copy use 32bit size values so divide by 4 */
+ __iowrite32_copy((void *)dest, src, bytes/4);
+}
+
+static void sst_dma_transfer_complete(void *arg)
+{
+ struct sst_dsp *sst = (struct sst_dsp *)arg;
+
+ dev_dbg(sst->dev, "DMA: callback\n");
+}
+
+static int sst_dsp_dma_copy(struct sst_dsp *sst, dma_addr_t dest_addr,
+ dma_addr_t src_addr, size_t size)
+{
+ struct dma_async_tx_descriptor *desc;
+ struct sst_dma *dma = sst->dma;
+
+ if (dma->ch == NULL) {
+ dev_err(sst->dev, "error: no DMA channel\n");
+ return -ENODEV;
+ }
+
+ dev_dbg(sst->dev, "DMA: src: 0x%lx dest 0x%lx size %zu\n",
+ (unsigned long)src_addr, (unsigned long)dest_addr, size);
+
+ desc = dma->ch->device->device_prep_dma_memcpy(dma->ch, dest_addr,
+ src_addr, size, DMA_CTRL_ACK);
+ if (!desc){
+ dev_err(sst->dev, "error: dma prep memcpy failed\n");
+ return -EINVAL;
+ }
+
+ desc->callback = sst_dma_transfer_complete;
+ desc->callback_param = sst;
+
+ desc->tx_submit(desc);
+ dma_wait_for_async_tx(desc);
+
+ return 0;
+}
+
+/* copy to DSP */
+int sst_dsp_dma_copyto(struct sst_dsp *sst, dma_addr_t dest_addr,
+ dma_addr_t src_addr, size_t size)
+{
+ return sst_dsp_dma_copy(sst, dest_addr | SST_HSW_MASK_DMA_ADDR_DSP,
+ src_addr, size);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_copyto);
+
+/* copy from DSP */
+int sst_dsp_dma_copyfrom(struct sst_dsp *sst, dma_addr_t dest_addr,
+ dma_addr_t src_addr, size_t size)
+{
+ return sst_dsp_dma_copy(sst, dest_addr,
+ src_addr | SST_HSW_MASK_DMA_ADDR_DSP, size);
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_copyfrom);
+
+/* remove module from memory - callers hold locks */
+static void block_list_remove(struct sst_dsp *dsp,
+ struct list_head *block_list)
+{
+ struct sst_mem_block *block, *tmp;
+ int err;
+
+ /* disable each block */
+ list_for_each_entry(block, block_list, module_list) {
+
+ if (block->ops && block->ops->disable) {
+ err = block->ops->disable(block);
+ if (err < 0)
+ dev_err(dsp->dev,
+ "error: cant disable block %d:%d\n",
+ block->type, block->index);
+ }
+ }
+
+ /* mark each block as free */
+ list_for_each_entry_safe(block, tmp, block_list, module_list) {
+ list_del(&block->module_list);
+ list_move(&block->list, &dsp->free_block_list);
+ dev_dbg(dsp->dev, "block freed %d:%d at offset 0x%x\n",
+ block->type, block->index, block->offset);
+ }
+}
+
+/* prepare the memory block to receive data from host - callers hold locks */
+static int block_list_prepare(struct sst_dsp *dsp,
+ struct list_head *block_list)
+{
+ struct sst_mem_block *block;
+ int ret = 0;
+
+ /* enable each block so that's it'e ready for data */
+ list_for_each_entry(block, block_list, module_list) {
+
+ if (block->ops && block->ops->enable && !block->users) {
+ ret = block->ops->enable(block);
+ if (ret < 0) {
+ dev_err(dsp->dev,
+ "error: cant disable block %d:%d\n",
+ block->type, block->index);
+ goto err;
+ }
+ }
+ }
+ return ret;
+
+err:
+ list_for_each_entry(block, block_list, module_list) {
+ if (block->ops && block->ops->disable)
+ block->ops->disable(block);
+ }
+ return ret;
+}
+
+static struct dw_dma_platform_data dw_pdata = {
+ .is_private = 1,
+ .chan_allocation_order = CHAN_ALLOCATION_ASCENDING,
+ .chan_priority = CHAN_PRIORITY_ASCENDING,
+};
+
+static struct dw_dma_chip *dw_probe(struct device *dev, struct resource *mem,
+ int irq)
+{
+ struct dw_dma_chip *chip;
+ int err;
+
+ chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+ if (!chip)
+ return ERR_PTR(-ENOMEM);
+
+ chip->irq = irq;
+ chip->regs = devm_ioremap_resource(dev, mem);
+ if (IS_ERR(chip->regs))
+ return ERR_CAST(chip->regs);
+
+ err = dma_coerce_mask_and_coherent(dev, DMA_BIT_MASK(31));
+ if (err)
+ return ERR_PTR(err);
+
+ chip->dev = dev;
+ err = dw_dma_probe(chip, &dw_pdata);
+ if (err)
+ return ERR_PTR(err);
+
+ return chip;
+}
+
+static void dw_remove(struct dw_dma_chip *chip)
+{
+ dw_dma_remove(chip);
+}
+
+static bool dma_chan_filter(struct dma_chan *chan, void *param)
+{
+ struct sst_dsp *dsp = (struct sst_dsp *)param;
+
+ return chan->device->dev == dsp->dma_dev;
+}
-static void sst_memcpy32(volatile void __iomem *dest, void *src, u32 bytes)
+int sst_dsp_dma_get_channel(struct sst_dsp *dsp, int chan_id)
{
- u32 i;
+ struct sst_dma *dma = dsp->dma;
+ struct dma_slave_config slave;
+ dma_cap_mask_t mask;
+ int ret;
+
+ /* The Intel MID DMA engine driver needs the slave config set but
+ * Synopsis DMA engine driver safely ignores the slave config */
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_MEMCPY, mask);
+
+ dma->ch = dma_request_channel(mask, dma_chan_filter, dsp);
+ if (dma->ch == NULL) {
+ dev_err(dsp->dev, "error: DMA request channel failed\n");
+ return -EIO;
+ }
+
+ memset(&slave, 0, sizeof(slave));
+ slave.direction = DMA_MEM_TO_DEV;
+ slave.src_addr_width =
+ slave.dst_addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ slave.src_maxburst = slave.dst_maxburst = SST_DSP_DMA_MAX_BURST;
+
+ ret = dmaengine_slave_config(dma->ch, &slave);
+ if (ret) {
+ dev_err(dsp->dev, "error: unable to set DMA slave config %d\n",
+ ret);
+ dma_release_channel(dma->ch);
+ dma->ch = NULL;
+ }
- /* copy one 32 bit word at a time as 64 bit access is not supported */
- for (i = 0; i < bytes; i += 4)
- memcpy_toio(dest + i, src + i, 4);
+ return ret;
}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_get_channel);
+
+void sst_dsp_dma_put_channel(struct sst_dsp *dsp)
+{
+ struct sst_dma *dma = dsp->dma;
+
+ if (!dma->ch)
+ return;
+
+ dma_release_channel(dma->ch);
+ dma->ch = NULL;
+}
+EXPORT_SYMBOL_GPL(sst_dsp_dma_put_channel);
+
+int sst_dma_new(struct sst_dsp *sst)
+{
+ struct sst_pdata *sst_pdata = sst->pdata;
+ struct sst_dma *dma;
+ struct resource mem;
+ const char *dma_dev_name;
+ int ret = 0;
+
+ /* configure the correct platform data for whatever DMA engine
+ * is attached to the ADSP IP. */
+ switch (sst->pdata->dma_engine) {
+ case SST_DMA_TYPE_DW:
+ dma_dev_name = "dw_dmac";
+ break;
+ case SST_DMA_TYPE_MID:
+ dma_dev_name = "Intel MID DMA";
+ break;
+ default:
+ dev_err(sst->dev, "error: invalid DMA engine %d\n",
+ sst->pdata->dma_engine);
+ return -EINVAL;
+ }
+
+ dma = devm_kzalloc(sst->dev, sizeof(struct sst_dma), GFP_KERNEL);
+ if (!dma)
+ return -ENOMEM;
+
+ dma->sst = sst;
+
+ memset(&mem, 0, sizeof(mem));
+
+ mem.start = sst->addr.lpe_base + sst_pdata->dma_base;
+ mem.end = sst->addr.lpe_base + sst_pdata->dma_base + sst_pdata->dma_size - 1;
+ mem.flags = IORESOURCE_MEM;
+
+ /* now register DMA engine device */
+ dma->chip = dw_probe(sst->dma_dev, &mem, sst_pdata->irq);
+ if (IS_ERR(dma->chip)) {
+ dev_err(sst->dev, "error: DMA device register failed\n");
+ ret = PTR_ERR(dma->chip);
+ goto err_dma_dev;
+ }
+
+ sst->dma = dma;
+ sst->fw_use_dma = true;
+ return 0;
+
+err_dma_dev:
+ devm_kfree(sst->dev, dma);
+ return ret;
+}
+EXPORT_SYMBOL(sst_dma_new);
+
+void sst_dma_free(struct sst_dma *dma)
+{
+
+ if (dma == NULL)
+ return;
+
+ if (dma->ch)
+ dma_release_channel(dma->ch);
+
+ if (dma->chip)
+ dw_remove(dma->chip);
+
+}
+EXPORT_SYMBOL(sst_dma_free);
/* create new generic firmware object */
struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
@@ -71,6 +361,12 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
/* copy FW data to DMA-able memory */
memcpy((void *)sst_fw->dma_buf, (void *)fw->data, fw->size);
+ if (dsp->fw_use_dma) {
+ err = sst_dsp_dma_get_channel(dsp, 0);
+ if (err < 0)
+ goto chan_err;
+ }
+
/* call core specific FW paser to load FW data into DSP */
err = dsp->ops->parse_fw(sst_fw);
if (err < 0) {
@@ -78,6 +374,9 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
goto parse_err;
}
+ if (dsp->fw_use_dma)
+ sst_dsp_dma_put_channel(dsp);
+
mutex_lock(&dsp->mutex);
list_add(&sst_fw->list, &dsp->fw_list);
mutex_unlock(&dsp->mutex);
@@ -85,9 +384,13 @@ struct sst_fw *sst_fw_new(struct sst_dsp *dsp,
return sst_fw;
parse_err:
- dma_free_coherent(dsp->dev, sst_fw->size,
+ if (dsp->fw_use_dma)
+ sst_dsp_dma_put_channel(dsp);
+chan_err:
+ dma_free_coherent(dsp->dma_dev, sst_fw->size,
sst_fw->dma_buf,
sst_fw->dmable_fw_paddr);
+ sst_fw->dma_buf = NULL;
kfree(sst_fw);
return NULL;
}
@@ -111,21 +414,37 @@ EXPORT_SYMBOL_GPL(sst_fw_reload);
void sst_fw_unload(struct sst_fw *sst_fw)
{
- struct sst_dsp *dsp = sst_fw->dsp;
- struct sst_module *module, *tmp;
+ struct sst_dsp *dsp = sst_fw->dsp;
+ struct sst_module *module, *mtmp;
+ struct sst_module_runtime *runtime, *rtmp;
+
+ dev_dbg(dsp->dev, "unloading firmware\n");
+
+ mutex_lock(&dsp->mutex);
+
+ /* check module by module */
+ list_for_each_entry_safe(module, mtmp, &dsp->module_list, list) {
+ if (module->sst_fw == sst_fw) {
+
+ /* remove runtime modules */
+ list_for_each_entry_safe(runtime, rtmp, &module->runtime_list, list) {
- dev_dbg(dsp->dev, "unloading firmware\n");
+ block_list_remove(dsp, &runtime->block_list);
+ list_del(&runtime->list);
+ kfree(runtime);
+ }
+
+ /* now remove the module */
+ block_list_remove(dsp, &module->block_list);
+ list_del(&module->list);
+ kfree(module);
+ }
+ }
- mutex_lock(&dsp->mutex);
- list_for_each_entry_safe(module, tmp, &dsp->module_list, list) {
- if (module->sst_fw == sst_fw) {
- block_module_remove(module);
- list_del(&module->list);
- kfree(module);
- }
- }
+ /* remove all scratch blocks */
+ block_list_remove(dsp, &dsp->scratch_block_list);
- mutex_unlock(&dsp->mutex);
+ mutex_unlock(&dsp->mutex);
}
EXPORT_SYMBOL_GPL(sst_fw_unload);
@@ -138,7 +457,8 @@ void sst_fw_free(struct sst_fw *sst_fw)
list_del(&sst_fw->list);
mutex_unlock(&dsp->mutex);
- dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
+ if (sst_fw->dma_buf)
+ dma_free_coherent(dsp->dma_dev, sst_fw->size, sst_fw->dma_buf,
sst_fw->dmable_fw_paddr);
kfree(sst_fw);
}
@@ -175,11 +495,11 @@ struct sst_module *sst_module_new(struct sst_fw *sst_fw,
sst_module->id = template->id;
sst_module->dsp = dsp;
sst_module->sst_fw = sst_fw;
-
- memcpy(&sst_module->s, &template->s, sizeof(struct sst_module_data));
- memcpy(&sst_module->p, &template->p, sizeof(struct sst_module_data));
+ sst_module->scratch_size = template->scratch_size;
+ sst_module->persistent_size = template->persistent_size;
INIT_LIST_HEAD(&sst_module->block_list);
+ INIT_LIST_HEAD(&sst_module->runtime_list);
mutex_lock(&dsp->mutex);
list_add(&sst_module->list, &dsp->module_list);
@@ -202,73 +522,122 @@ void sst_module_free(struct sst_module *sst_module)
}
EXPORT_SYMBOL_GPL(sst_module_free);
-static struct sst_mem_block *find_block(struct sst_dsp *dsp, int type,
- u32 offset)
+struct sst_module_runtime *sst_module_runtime_new(struct sst_module *module,
+ int id, void *private)
+{
+ struct sst_dsp *dsp = module->dsp;
+ struct sst_module_runtime *runtime;
+
+ runtime = kzalloc(sizeof(*runtime), GFP_KERNEL);
+ if (runtime == NULL)
+ return NULL;
+
+ runtime->id = id;
+ runtime->dsp = dsp;
+ runtime->module = module;
+ INIT_LIST_HEAD(&runtime->block_list);
+
+ mutex_lock(&dsp->mutex);
+ list_add(&runtime->list, &module->runtime_list);
+ mutex_unlock(&dsp->mutex);
+
+ return runtime;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_new);
+
+void sst_module_runtime_free(struct sst_module_runtime *runtime)
+{
+ struct sst_dsp *dsp = runtime->dsp;
+
+ mutex_lock(&dsp->mutex);
+ list_del(&runtime->list);
+ mutex_unlock(&dsp->mutex);
+
+ kfree(runtime);
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_free);
+
+static struct sst_mem_block *find_block(struct sst_dsp *dsp,
+ struct sst_block_allocator *ba)
{
struct sst_mem_block *block;
list_for_each_entry(block, &dsp->free_block_list, list) {
- if (block->type == type && block->offset == offset)
+ if (block->type == ba->type && block->offset == ba->offset)
return block;
}
return NULL;
}
-static int block_alloc_contiguous(struct sst_module *module,
- struct sst_module_data *data, u32 offset, int size)
+/* Block allocator must be on block boundary */
+static int block_alloc_contiguous(struct sst_dsp *dsp,
+ struct sst_block_allocator *ba, struct list_head *block_list)
{
struct list_head tmp = LIST_HEAD_INIT(tmp);
- struct sst_dsp *dsp = module->dsp;
struct sst_mem_block *block;
+ u32 block_start = SST_HSW_BLOCK_ANY;
+ int size = ba->size, offset = ba->offset;
+
+ while (ba->size > 0) {
- while (size > 0) {
- block = find_block(dsp, data->type, offset);
+ block = find_block(dsp, ba);
if (!block) {
list_splice(&tmp, &dsp->free_block_list);
+
+ ba->size = size;
+ ba->offset = offset;
return -ENOMEM;
}
list_move_tail(&block->list, &tmp);
- offset += block->size;
- size -= block->size;
+ ba->offset += block->size;
+ ba->size -= block->size;
}
+ ba->size = size;
+ ba->offset = offset;
+
+ list_for_each_entry(block, &tmp, list) {
+
+ if (block->offset < block_start)
+ block_start = block->offset;
- list_for_each_entry(block, &tmp, list)
- list_add(&block->module_list, &module->block_list);
+ list_add(&block->module_list, block_list);
+
+ dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
+ block->type, block->index, block->offset);
+ }
list_splice(&tmp, &dsp->used_block_list);
return 0;
}
-/* allocate free DSP blocks for module data - callers hold locks */
-static int block_alloc(struct sst_module *module,
- struct sst_module_data *data)
+/* allocate first free DSP blocks for data - callers hold locks */
+static int block_alloc(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+ struct list_head *block_list)
{
- struct sst_dsp *dsp = module->dsp;
struct sst_mem_block *block, *tmp;
int ret = 0;
- if (data->size == 0)
+ if (ba->size == 0)
return 0;
/* find first free whole blocks that can hold module */
list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
/* ignore blocks with wrong type */
- if (block->type != data->type)
+ if (block->type != ba->type)
continue;
- if (data->size > block->size)
+ if (ba->size > block->size)
continue;
- data->offset = block->offset;
- block->data_type = data->data_type;
- block->bytes_used = data->size % block->size;
- list_add(&block->module_list, &module->block_list);
+ ba->offset = block->offset;
+ block->bytes_used = ba->size % block->size;
+ list_add(&block->module_list, block_list);
list_move(&block->list, &dsp->used_block_list);
- dev_dbg(dsp->dev, " *module %d added block %d:%d\n",
- module->id, block->type, block->index);
+ dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
+ block->type, block->index, block->offset);
return 0;
}
@@ -276,15 +645,19 @@ static int block_alloc(struct sst_module *module,
list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
/* ignore blocks with wrong type */
- if (block->type != data->type)
+ if (block->type != ba->type)
continue;
/* do we span > 1 blocks */
- if (data->size > block->size) {
- ret = block_alloc_contiguous(module, data,
- block->offset, data->size);
+ if (ba->size > block->size) {
+
+ /* align ba to block boundary */
+ ba->offset = block->offset;
+
+ ret = block_alloc_contiguous(dsp, ba, block_list);
if (ret == 0)
return ret;
+
}
}
@@ -292,93 +665,74 @@ static int block_alloc(struct sst_module *module,
return -ENOMEM;
}
-/* remove module from memory - callers hold locks */
-static void block_module_remove(struct sst_module *module)
+int sst_alloc_blocks(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+ struct list_head *block_list)
{
- struct sst_mem_block *block, *tmp;
- struct sst_dsp *dsp = module->dsp;
- int err;
+ int ret;
- /* disable each block */
- list_for_each_entry(block, &module->block_list, module_list) {
+ dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n",
+ ba->size, ba->offset, ba->type);
- if (block->ops && block->ops->disable) {
- err = block->ops->disable(block);
- if (err < 0)
- dev_err(dsp->dev,
- "error: cant disable block %d:%d\n",
- block->type, block->index);
- }
- }
+ mutex_lock(&dsp->mutex);
- /* mark each block as free */
- list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
- list_del(&block->module_list);
- list_move(&block->list, &dsp->free_block_list);
+ ret = block_alloc(dsp, ba, block_list);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: can't alloc blocks %d\n", ret);
+ goto out;
}
-}
-
-/* prepare the memory block to receive data from host - callers hold locks */
-static int block_module_prepare(struct sst_module *module)
-{
- struct sst_mem_block *block;
- int ret = 0;
- /* enable each block so that's it'e ready for module P/S data */
- list_for_each_entry(block, &module->block_list, module_list) {
+ /* prepare DSP blocks for module usage */
+ ret = block_list_prepare(dsp, block_list);
+ if (ret < 0)
+ dev_err(dsp->dev, "error: prepare failed\n");
- if (block->ops && block->ops->enable) {
- ret = block->ops->enable(block);
- if (ret < 0) {
- dev_err(module->dsp->dev,
- "error: cant disable block %d:%d\n",
- block->type, block->index);
- goto err;
- }
- }
- }
+out:
+ mutex_unlock(&dsp->mutex);
return ret;
+}
+EXPORT_SYMBOL_GPL(sst_alloc_blocks);
-err:
- list_for_each_entry(block, &module->block_list, module_list) {
- if (block->ops && block->ops->disable)
- block->ops->disable(block);
- }
- return ret;
+int sst_free_blocks(struct sst_dsp *dsp, struct list_head *block_list)
+{
+ mutex_lock(&dsp->mutex);
+ block_list_remove(dsp, block_list);
+ mutex_unlock(&dsp->mutex);
+ return 0;
}
+EXPORT_SYMBOL_GPL(sst_free_blocks);
/* allocate memory blocks for static module addresses - callers hold locks */
-static int block_alloc_fixed(struct sst_module *module,
- struct sst_module_data *data)
+static int block_alloc_fixed(struct sst_dsp *dsp, struct sst_block_allocator *ba,
+ struct list_head *block_list)
{
- struct sst_dsp *dsp = module->dsp;
struct sst_mem_block *block, *tmp;
- u32 end = data->offset + data->size, block_end;
+ u32 end = ba->offset + ba->size, block_end;
int err;
/* only IRAM/DRAM blocks are managed */
- if (data->type != SST_MEM_IRAM && data->type != SST_MEM_DRAM)
+ if (ba->type != SST_MEM_IRAM && ba->type != SST_MEM_DRAM)
return 0;
/* are blocks already attached to this module */
- list_for_each_entry_safe(block, tmp, &module->block_list, module_list) {
+ list_for_each_entry_safe(block, tmp, block_list, module_list) {
- /* force compacting mem blocks of the same data_type */
- if (block->data_type != data->data_type)
+ /* ignore blocks with wrong type */
+ if (block->type != ba->type)
continue;
block_end = block->offset + block->size;
/* find block that holds section */
- if (data->offset >= block->offset && end < block_end)
+ if (ba->offset >= block->offset && end <= block_end)
return 0;
/* does block span more than 1 section */
- if (data->offset >= block->offset && data->offset < block_end) {
+ if (ba->offset >= block->offset && ba->offset < block_end) {
- err = block_alloc_contiguous(module, data,
- block->offset + block->size,
- data->size - block->size);
+ /* align ba to block boundary */
+ ba->size -= block_end - ba->offset;
+ ba->offset = block_end;
+ err = block_alloc_contiguous(dsp, ba, block_list);
if (err < 0)
return -ENOMEM;
@@ -391,82 +745,270 @@ static int block_alloc_fixed(struct sst_module *module,
list_for_each_entry_safe(block, tmp, &dsp->free_block_list, list) {
block_end = block->offset + block->size;
+ /* ignore blocks with wrong type */
+ if (block->type != ba->type)
+ continue;
+
/* find block that holds section */
- if (data->offset >= block->offset && end < block_end) {
+ if (ba->offset >= block->offset && end <= block_end) {
/* add block */
- block->data_type = data->data_type;
list_move(&block->list, &dsp->used_block_list);
- list_add(&block->module_list, &module->block_list);
+ list_add(&block->module_list, block_list);
+ dev_dbg(dsp->dev, "block allocated %d:%d at offset 0x%x\n",
+ block->type, block->index, block->offset);
return 0;
}
/* does block span more than 1 section */
- if (data->offset >= block->offset && data->offset < block_end) {
+ if (ba->offset >= block->offset && ba->offset < block_end) {
- err = block_alloc_contiguous(module, data,
- block->offset, data->size);
+ /* align ba to block boundary */
+ ba->offset = block->offset;
+
+ err = block_alloc_contiguous(dsp, ba, block_list);
if (err < 0)
return -ENOMEM;
return 0;
}
-
}
return -ENOMEM;
}
/* Load fixed module data into DSP memory blocks */
-int sst_module_insert_fixed_block(struct sst_module *module,
- struct sst_module_data *data)
+int sst_module_alloc_blocks(struct sst_module *module)
{
struct sst_dsp *dsp = module->dsp;
+ struct sst_fw *sst_fw = module->sst_fw;
+ struct sst_block_allocator ba;
int ret;
+ ba.size = module->size;
+ ba.type = module->type;
+ ba.offset = module->offset;
+
+ dev_dbg(dsp->dev, "block request 0x%x bytes at offset 0x%x type %d\n",
+ ba.size, ba.offset, ba.type);
+
mutex_lock(&dsp->mutex);
/* alloc blocks that includes this section */
- ret = block_alloc_fixed(module, data);
+ ret = block_alloc_fixed(dsp, &ba, &module->block_list);
if (ret < 0) {
dev_err(dsp->dev,
"error: no free blocks for section at offset 0x%x size 0x%x\n",
- data->offset, data->size);
+ module->offset, module->size);
mutex_unlock(&dsp->mutex);
return -ENOMEM;
}
/* prepare DSP blocks for module copy */
- ret = block_module_prepare(module);
+ ret = block_list_prepare(dsp, &module->block_list);
if (ret < 0) {
dev_err(dsp->dev, "error: fw module prepare failed\n");
goto err;
}
/* copy partial module data to blocks */
- sst_memcpy32(dsp->addr.lpe + data->offset, data->data, data->size);
+ if (dsp->fw_use_dma) {
+ ret = sst_dsp_dma_copyto(dsp,
+ dsp->addr.lpe_base + module->offset,
+ sst_fw->dmable_fw_paddr + module->data_offset,
+ module->size);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: module copy failed\n");
+ goto err;
+ }
+ } else
+ sst_memcpy32(dsp->addr.lpe + module->offset, module->data,
+ module->size);
mutex_unlock(&dsp->mutex);
return ret;
err:
- block_module_remove(module);
+ block_list_remove(dsp, &module->block_list);
mutex_unlock(&dsp->mutex);
return ret;
}
-EXPORT_SYMBOL_GPL(sst_module_insert_fixed_block);
+EXPORT_SYMBOL_GPL(sst_module_alloc_blocks);
/* Unload entire module from DSP memory */
-int sst_block_module_remove(struct sst_module *module)
+int sst_module_free_blocks(struct sst_module *module)
{
struct sst_dsp *dsp = module->dsp;
mutex_lock(&dsp->mutex);
- block_module_remove(module);
+ block_list_remove(dsp, &module->block_list);
mutex_unlock(&dsp->mutex);
return 0;
}
-EXPORT_SYMBOL_GPL(sst_block_module_remove);
+EXPORT_SYMBOL_GPL(sst_module_free_blocks);
+
+int sst_module_runtime_alloc_blocks(struct sst_module_runtime *runtime,
+ int offset)
+{
+ struct sst_dsp *dsp = runtime->dsp;
+ struct sst_module *module = runtime->module;
+ struct sst_block_allocator ba;
+ int ret;
+
+ if (module->persistent_size == 0)
+ return 0;
+
+ ba.size = module->persistent_size;
+ ba.type = SST_MEM_DRAM;
+
+ mutex_lock(&dsp->mutex);
+
+ /* do we need to allocate at a fixed address ? */
+ if (offset != 0) {
+
+ ba.offset = offset;
+
+ dev_dbg(dsp->dev, "persistent fixed block request 0x%x bytes type %d offset 0x%x\n",
+ ba.size, ba.type, ba.offset);
+
+ /* alloc blocks that includes this section */
+ ret = block_alloc_fixed(dsp, &ba, &runtime->block_list);
+
+ } else {
+ dev_dbg(dsp->dev, "persistent block request 0x%x bytes type %d\n",
+ ba.size, ba.type);
+
+ /* alloc blocks that includes this section */
+ ret = block_alloc(dsp, &ba, &runtime->block_list);
+ }
+ if (ret < 0) {
+ dev_err(dsp->dev,
+ "error: no free blocks for runtime module size 0x%x\n",
+ module->persistent_size);
+ mutex_unlock(&dsp->mutex);
+ return -ENOMEM;
+ }
+ runtime->persistent_offset = ba.offset;
+
+ /* prepare DSP blocks for module copy */
+ ret = block_list_prepare(dsp, &runtime->block_list);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: runtime block prepare failed\n");
+ goto err;
+ }
+
+ mutex_unlock(&dsp->mutex);
+ return ret;
+
+err:
+ block_list_remove(dsp, &module->block_list);
+ mutex_unlock(&dsp->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_alloc_blocks);
+
+int sst_module_runtime_free_blocks(struct sst_module_runtime *runtime)
+{
+ struct sst_dsp *dsp = runtime->dsp;
+
+ mutex_lock(&dsp->mutex);
+ block_list_remove(dsp, &runtime->block_list);
+ mutex_unlock(&dsp->mutex);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_free_blocks);
+
+int sst_module_runtime_save(struct sst_module_runtime *runtime,
+ struct sst_module_runtime_context *context)
+{
+ struct sst_dsp *dsp = runtime->dsp;
+ struct sst_module *module = runtime->module;
+ int ret = 0;
+
+ dev_dbg(dsp->dev, "saving runtime %d memory at 0x%x size 0x%x\n",
+ runtime->id, runtime->persistent_offset,
+ module->persistent_size);
+
+ context->buffer = dma_alloc_coherent(dsp->dma_dev,
+ module->persistent_size,
+ &context->dma_buffer, GFP_DMA | GFP_KERNEL);
+ if (!context->buffer) {
+ dev_err(dsp->dev, "error: DMA context alloc failed\n");
+ return -ENOMEM;
+ }
+
+ mutex_lock(&dsp->mutex);
+
+ if (dsp->fw_use_dma) {
+
+ ret = sst_dsp_dma_get_channel(dsp, 0);
+ if (ret < 0)
+ goto err;
+
+ ret = sst_dsp_dma_copyfrom(dsp, context->dma_buffer,
+ dsp->addr.lpe_base + runtime->persistent_offset,
+ module->persistent_size);
+ sst_dsp_dma_put_channel(dsp);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: context copy failed\n");
+ goto err;
+ }
+ } else
+ sst_memcpy32(context->buffer, dsp->addr.lpe +
+ runtime->persistent_offset,
+ module->persistent_size);
+
+err:
+ mutex_unlock(&dsp->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_save);
+
+int sst_module_runtime_restore(struct sst_module_runtime *runtime,
+ struct sst_module_runtime_context *context)
+{
+ struct sst_dsp *dsp = runtime->dsp;
+ struct sst_module *module = runtime->module;
+ int ret = 0;
+
+ dev_dbg(dsp->dev, "restoring runtime %d memory at 0x%x size 0x%x\n",
+ runtime->id, runtime->persistent_offset,
+ module->persistent_size);
+
+ mutex_lock(&dsp->mutex);
+
+ if (!context->buffer) {
+ dev_info(dsp->dev, "no context buffer need to restore!\n");
+ goto err;
+ }
+
+ if (dsp->fw_use_dma) {
+
+ ret = sst_dsp_dma_get_channel(dsp, 0);
+ if (ret < 0)
+ goto err;
+
+ ret = sst_dsp_dma_copyto(dsp,
+ dsp->addr.lpe_base + runtime->persistent_offset,
+ context->dma_buffer, module->persistent_size);
+ sst_dsp_dma_put_channel(dsp);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: module copy failed\n");
+ goto err;
+ }
+ } else
+ sst_memcpy32(dsp->addr.lpe + runtime->persistent_offset,
+ context->buffer, module->persistent_size);
+
+ dma_free_coherent(dsp->dma_dev, module->persistent_size,
+ context->buffer, context->dma_buffer);
+ context->buffer = NULL;
+
+err:
+ mutex_unlock(&dsp->mutex);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_restore);
/* register a DSP memory block for use with FW based modules */
struct sst_mem_block *sst_mem_block_register(struct sst_dsp *dsp, u32 offset,
@@ -519,80 +1061,84 @@ void sst_mem_block_unregister_all(struct sst_dsp *dsp)
EXPORT_SYMBOL_GPL(sst_mem_block_unregister_all);
/* allocate scratch buffer blocks */
-struct sst_module *sst_mem_block_alloc_scratch(struct sst_dsp *dsp)
+int sst_block_alloc_scratch(struct sst_dsp *dsp)
{
- struct sst_module *sst_module, *scratch;
- struct sst_mem_block *block, *tmp;
- u32 block_size;
- int ret = 0;
-
- scratch = kzalloc(sizeof(struct sst_module), GFP_KERNEL);
- if (scratch == NULL)
- return NULL;
+ struct sst_module *module;
+ struct sst_block_allocator ba;
+ int ret;
mutex_lock(&dsp->mutex);
/* calculate required scratch size */
- list_for_each_entry(sst_module, &dsp->module_list, list) {
- if (scratch->s.size < sst_module->s.size)
- scratch->s.size = sst_module->s.size;
+ dsp->scratch_size = 0;
+ list_for_each_entry(module, &dsp->module_list, list) {
+ dev_dbg(dsp->dev, "module %d scratch req 0x%x bytes\n",
+ module->id, module->scratch_size);
+ if (dsp->scratch_size < module->scratch_size)
+ dsp->scratch_size = module->scratch_size;
}
- dev_dbg(dsp->dev, "scratch buffer required is %d bytes\n",
- scratch->s.size);
-
- /* init scratch module */
- scratch->dsp = dsp;
- scratch->s.type = SST_MEM_DRAM;
- scratch->s.data_type = SST_DATA_S;
- INIT_LIST_HEAD(&scratch->block_list);
+ dev_dbg(dsp->dev, "scratch buffer required is 0x%x bytes\n",
+ dsp->scratch_size);
- /* check free blocks before looking at used blocks for space */
- if (!list_empty(&dsp->free_block_list))
- block = list_first_entry(&dsp->free_block_list,
- struct sst_mem_block, list);
- else
- block = list_first_entry(&dsp->used_block_list,
- struct sst_mem_block, list);
- block_size = block->size;
+ if (dsp->scratch_size == 0) {
+ dev_info(dsp->dev, "no modules need scratch buffer\n");
+ mutex_unlock(&dsp->mutex);
+ return 0;
+ }
/* allocate blocks for module scratch buffers */
dev_dbg(dsp->dev, "allocating scratch blocks\n");
- ret = block_alloc(scratch, &scratch->s);
+
+ ba.size = dsp->scratch_size;
+ ba.type = SST_MEM_DRAM;
+
+ /* do we need to allocate at fixed offset */
+ if (dsp->scratch_offset != 0) {
+
+ dev_dbg(dsp->dev, "block request 0x%x bytes type %d at 0x%x\n",
+ ba.size, ba.type, ba.offset);
+
+ ba.offset = dsp->scratch_offset;
+
+ /* alloc blocks that includes this section */
+ ret = block_alloc_fixed(dsp, &ba, &dsp->scratch_block_list);
+
+ } else {
+ dev_dbg(dsp->dev, "block request 0x%x bytes type %d\n",
+ ba.size, ba.type);
+
+ ba.offset = 0;
+ ret = block_alloc(dsp, &ba, &dsp->scratch_block_list);
+ }
if (ret < 0) {
dev_err(dsp->dev, "error: can't alloc scratch blocks\n");
- goto err;
+ mutex_unlock(&dsp->mutex);
+ return ret;
}
- /* assign the same offset of scratch to each module */
- list_for_each_entry(sst_module, &dsp->module_list, list)
- sst_module->s.offset = scratch->s.offset;
-
- mutex_unlock(&dsp->mutex);
- return scratch;
+ ret = block_list_prepare(dsp, &dsp->scratch_block_list);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: scratch block prepare failed\n");
+ mutex_unlock(&dsp->mutex);
+ return ret;
+ }
-err:
- list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
- list_del(&block->module_list);
+ /* assign the same offset of scratch to each module */
+ dsp->scratch_offset = ba.offset;
mutex_unlock(&dsp->mutex);
- return NULL;
+ return dsp->scratch_size;
}
-EXPORT_SYMBOL_GPL(sst_mem_block_alloc_scratch);
+EXPORT_SYMBOL_GPL(sst_block_alloc_scratch);
/* free all scratch blocks */
-void sst_mem_block_free_scratch(struct sst_dsp *dsp,
- struct sst_module *scratch)
+void sst_block_free_scratch(struct sst_dsp *dsp)
{
- struct sst_mem_block *block, *tmp;
-
mutex_lock(&dsp->mutex);
-
- list_for_each_entry_safe(block, tmp, &scratch->block_list, module_list)
- list_del(&block->module_list);
-
+ block_list_remove(dsp, &dsp->scratch_block_list);
mutex_unlock(&dsp->mutex);
}
-EXPORT_SYMBOL_GPL(sst_mem_block_free_scratch);
+EXPORT_SYMBOL_GPL(sst_block_free_scratch);
/* get a module from it's unique ID */
struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
@@ -612,3 +1158,40 @@ struct sst_module *sst_module_get_from_id(struct sst_dsp *dsp, u32 id)
return NULL;
}
EXPORT_SYMBOL_GPL(sst_module_get_from_id);
+
+struct sst_module_runtime *sst_module_runtime_get_from_id(
+ struct sst_module *module, u32 id)
+{
+ struct sst_module_runtime *runtime;
+ struct sst_dsp *dsp = module->dsp;
+
+ mutex_lock(&dsp->mutex);
+
+ list_for_each_entry(runtime, &module->runtime_list, list) {
+ if (runtime->id == id) {
+ mutex_unlock(&dsp->mutex);
+ return runtime;
+ }
+ }
+
+ mutex_unlock(&dsp->mutex);
+ return NULL;
+}
+EXPORT_SYMBOL_GPL(sst_module_runtime_get_from_id);
+
+/* returns block address in DSP address space */
+u32 sst_dsp_get_offset(struct sst_dsp *dsp, u32 offset,
+ enum sst_mem_type type)
+{
+ switch (type) {
+ case SST_MEM_IRAM:
+ return offset - dsp->addr.iram_offset +
+ dsp->addr.dsp_iram_offset;
+ case SST_MEM_DRAM:
+ return offset - dsp->addr.dram_offset +
+ dsp->addr.dsp_dram_offset;
+ default:
+ return 0;
+ }
+}
+EXPORT_SYMBOL_GPL(sst_dsp_get_offset);
diff --git a/sound/soc/intel/sst-haswell-dsp.c b/sound/soc/intel/sst-haswell-dsp.c
index 4b6c163..57039b0 100644
--- a/sound/soc/intel/sst-haswell-dsp.c
+++ b/sound/soc/intel/sst-haswell-dsp.c
@@ -42,6 +42,10 @@
#define SST_LP_SHIM_OFFSET 0xE7000
#define SST_WPT_IRAM_OFFSET 0xA0000
#define SST_LP_IRAM_OFFSET 0x80000
+#define SST_WPT_DSP_DRAM_OFFSET 0x400000
+#define SST_WPT_DSP_IRAM_OFFSET 0x00000
+#define SST_LPT_DSP_DRAM_OFFSET 0x400000
+#define SST_LPT_DSP_IRAM_OFFSET 0x00000
#define SST_SHIM_PM_REG 0x84
@@ -86,9 +90,8 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
{
struct dma_block_info *block;
struct sst_module *mod;
- struct sst_module_data block_data;
struct sst_module_template template;
- int count;
+ int count, ret;
void __iomem *ram;
/* TODO: allowed module types need to be configurable */
@@ -109,13 +112,9 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
memset(&template, 0, sizeof(template));
template.id = module->type;
- template.entry = module->entry_point;
- template.p.size = module->info.persistent_size;
- template.p.type = SST_MEM_DRAM;
- template.p.data_type = SST_DATA_P;
- template.s.size = module->info.scratch_size;
- template.s.type = SST_MEM_DRAM;
- template.s.data_type = SST_DATA_S;
+ template.entry = module->entry_point - 4;
+ template.persistent_size = module->info.persistent_size;
+ template.scratch_size = module->info.scratch_size;
mod = sst_module_new(fw, &template, NULL);
if (mod == NULL)
@@ -135,14 +134,14 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
switch (block->type) {
case SST_HSW_IRAM:
ram = dsp->addr.lpe;
- block_data.offset =
+ mod->offset =
block->ram_offset + dsp->addr.iram_offset;
- block_data.type = SST_MEM_IRAM;
+ mod->type = SST_MEM_IRAM;
break;
case SST_HSW_DRAM:
ram = dsp->addr.lpe;
- block_data.offset = block->ram_offset;
- block_data.type = SST_MEM_DRAM;
+ mod->offset = block->ram_offset;
+ mod->type = SST_MEM_DRAM;
break;
default:
dev_err(dsp->dev, "error: bad type 0x%x for block 0x%x\n",
@@ -151,30 +150,34 @@ static int hsw_parse_module(struct sst_dsp *dsp, struct sst_fw *fw,
return -EINVAL;
}
- block_data.size = block->size;
- block_data.data_type = SST_DATA_M;
- block_data.data = (void *)block + sizeof(*block);
- block_data.data_offset = block_data.data - fw->dma_buf;
+ mod->size = block->size;
+ mod->data = (void *)block + sizeof(*block);
+ mod->data_offset = mod->data - fw->dma_buf;
- dev_dbg(dsp->dev, "copy firmware block %d type 0x%x "
+ dev_dbg(dsp->dev, "module block %d type 0x%x "
"size 0x%x ==> ram %p offset 0x%x\n",
- count, block->type, block->size, ram,
+ count, mod->type, block->size, ram,
block->ram_offset);
- sst_module_insert_fixed_block(mod, &block_data);
+ ret = sst_module_alloc_blocks(mod);
+ if (ret < 0) {
+ dev_err(dsp->dev, "error: could not allocate blocks for module %d\n",
+ count);
+ sst_module_free(mod);
+ return ret;
+ }
block = (void *)block + sizeof(*block) + block->size;
}
+
return 0;
}
static int hsw_parse_fw_image(struct sst_fw *sst_fw)
{
struct fw_header *header;
- struct sst_module *scratch;
struct fw_module_header *module;
struct sst_dsp *dsp = sst_fw->dsp;
- struct sst_hsw *hsw = sst_fw->private;
int ret, count;
/* Read the header information from the data pointer */
@@ -204,12 +207,8 @@ static int hsw_parse_fw_image(struct sst_fw *sst_fw)
module = (void *)module + sizeof(*module) + module->mod_size;
}
- /* allocate persistent/scratch mem regions */
- scratch = sst_mem_block_alloc_scratch(dsp);
- if (scratch == NULL)
- return -ENOMEM;
-
- sst_hsw_set_scratch_module(hsw, scratch);
+ /* allocate scratch mem regions */
+ sst_block_alloc_scratch(dsp);
return 0;
}
@@ -248,8 +247,94 @@ static irqreturn_t hsw_irq(int irq, void *context)
return ret;
}
-static void hsw_boot(struct sst_dsp *sst)
+static void hsw_set_dsp_D3(struct sst_dsp *sst)
+{
+ u32 val;
+ u32 reg;
+
+ /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ /* enable power gating and switch off DRAM & IRAM blocks */
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ val |= SST_VDRTCL0_DSRAMPGE_MASK |
+ SST_VDRTCL0_ISRAMPGE_MASK;
+ val &= ~(SST_VDRTCL0_D3PGD | SST_VDRTCL0_D3SRAMPGD);
+ writel(val, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+ /* switch off audio PLL */
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ val |= SST_VDRTCL2_APLLSE_MASK;
+ writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ /* disable MCLK(clkctl.smos = 0) */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CLKCTL,
+ SST_CLKCTL_MASK, 0);
+
+ /* Set D3 state, delay 50 us */
+ val = readl(sst->addr.pci_cfg + SST_PMCS);
+ val |= SST_PMCS_PS_MASK;
+ writel(val, sst->addr.pci_cfg + SST_PMCS);
+ udelay(50);
+
+ /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ udelay(50);
+
+}
+
+static void hsw_reset(struct sst_dsp *sst)
{
+ /* put DSP into reset and stall */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_RST | SST_CSR_STALL,
+ SST_CSR_RST | SST_CSR_STALL);
+
+ /* keep in reset for 10ms */
+ mdelay(10);
+
+ /* take DSP out of reset and keep stalled for FW loading */
+ sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
+ SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
+}
+
+static int hsw_set_dsp_D0(struct sst_dsp *sst)
+{
+ int tries = 10;
+ u32 reg;
+
+ /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg &= ~(SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE);
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ /* Disable D3PG (VDRTCTL0.D3PGD = 1) */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ reg |= SST_VDRTCL0_D3PGD;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+ /* Set D0 state */
+ reg = readl(sst->addr.pci_cfg + SST_PMCS);
+ reg &= ~SST_PMCS_PS_MASK;
+ writel(reg, sst->addr.pci_cfg + SST_PMCS);
+
+ /* check that ADSP shim is enabled */
+ while (tries--) {
+ reg = readl(sst->addr.pci_cfg + SST_PMCS) & SST_PMCS_PS_MASK;
+ if (reg == 0)
+ goto finish;
+
+ msleep(1);
+ }
+
+ return -ENODEV;
+
+finish:
/* select SSP1 19.2MHz base clock, SSP clock 0, turn off Low Power Clock */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
SST_CSR_S1IOCS | SST_CSR_SBCS1 | SST_CSR_LPCS, 0x0);
@@ -264,34 +349,96 @@ static void hsw_boot(struct sst_dsp *sst)
SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0,
SST_CLKCTL_MASK | SST_CLKCTL_DCPLCG | SST_CLKCTL_SCOE0);
+ /* Stall and reset core, set CSR */
+ hsw_reset(sst);
+
+ /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg |= SST_VDRTCL2_DCLCGE | SST_VDRTCL2_DTCGE;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ udelay(50);
+
+ /* switch on audio PLL */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ reg &= ~SST_VDRTCL2_APLLSE_MASK;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ /* set default power gating control, enable power gating control for all blocks. that is,
+ can't be accessed, please enable each block before accessing. */
+ reg = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
+ reg |= SST_VDRTCL0_DSRAMPGE_MASK | SST_VDRTCL0_ISRAMPGE_MASK;
+ writel(reg, sst->addr.pci_cfg + SST_VDRTCTL0);
+
+
/* disable DMA finish function for SSP0 & SSP1 */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR2, SST_CSR2_SDFD_SSP1,
SST_CSR2_SDFD_SSP1);
- /* enable DMA engine 0,1 all channels to access host memory */
- sst_dsp_shim_update_bits_unlocked(sst, SST_HMDC,
- SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff),
- SST_HMDC_HDDA1(0xff) | SST_HMDC_HDDA0(0xff));
+ /* set on-demond mode on engine 0,1 for all channels */
+ sst_dsp_shim_update_bits(sst, SST_HMDC,
+ SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
+ SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
+
+ /* Enable Interrupt from both sides */
+ sst_dsp_shim_update_bits(sst, SST_IMRX, (SST_IMRX_BUSY | SST_IMRX_DONE),
+ 0x0);
+ sst_dsp_shim_update_bits(sst, SST_IMRD, (SST_IMRD_DONE | SST_IMRD_BUSY |
+ SST_IMRD_SSP0 | SST_IMRD_DMAC), 0x0);
+
+ /* clear IPC registers */
+ sst_dsp_shim_write(sst, SST_IPCX, 0x0);
+ sst_dsp_shim_write(sst, SST_IPCD, 0x0);
+ sst_dsp_shim_write(sst, 0x80, 0x6);
+ sst_dsp_shim_write(sst, 0xe0, 0x300a);
+
+ return 0;
+}
- /* disable all clock gating */
- writel(0x0, sst->addr.pci_cfg + SST_VDRTCTL2);
+static void hsw_boot(struct sst_dsp *sst)
+{
+ /* set oportunistic mode on engine 0,1 for all channels */
+ sst_dsp_shim_update_bits(sst, SST_HMDC,
+ SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH, 0);
/* set DSP to RUN */
sst_dsp_shim_update_bits_unlocked(sst, SST_CSR, SST_CSR_STALL, 0x0);
}
-static void hsw_reset(struct sst_dsp *sst)
+static void hsw_stall(struct sst_dsp *sst)
+{
+ /* stall DSP */
+ sst_dsp_shim_update_bits(sst, SST_CSR,
+ SST_CSR_24MHZ_LPCS | SST_CSR_STALL,
+ SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
+}
+
+static void hsw_sleep(struct sst_dsp *sst)
{
+ dev_dbg(sst->dev, "HSW_PM dsp runtime suspend\n");
+
/* put DSP into reset and stall */
- sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
- SST_CSR_RST | SST_CSR_STALL, SST_CSR_RST | SST_CSR_STALL);
+ sst_dsp_shim_update_bits(sst, SST_CSR,
+ SST_CSR_24MHZ_LPCS | SST_CSR_RST | SST_CSR_STALL,
+ SST_CSR_RST | SST_CSR_STALL | SST_CSR_24MHZ_LPCS);
- /* keep in reset for 10ms */
- mdelay(10);
+ hsw_set_dsp_D3(sst);
+ dev_dbg(sst->dev, "HSW_PM dsp runtime suspend exit\n");
+}
- /* take DSP out of reset and keep stalled for FW loading */
- sst_dsp_shim_update_bits_unlocked(sst, SST_CSR,
- SST_CSR_RST | SST_CSR_STALL, SST_CSR_STALL);
+static int hsw_wake(struct sst_dsp *sst)
+{
+ int ret;
+
+ dev_dbg(sst->dev, "HSW_PM dsp runtime resume\n");
+
+ ret = hsw_set_dsp_D0(sst);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(sst->dev, "HSW_PM dsp runtime resume exit\n");
+
+ return 0;
}
struct sst_adsp_memregion {
@@ -396,6 +543,11 @@ static int hsw_block_enable(struct sst_mem_block *block)
dev_dbg(block->dsp->dev, " enabled block %d:%d at offset 0x%x\n",
block->type, block->index, block->offset);
+ /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ val &= ~SST_VDRTCL2_DCLCGE;
+ writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
bit = hsw_block_get_bit(block);
writel(val & ~bit, sst->addr.pci_cfg + SST_VDRTCTL0);
@@ -403,6 +555,13 @@ static int hsw_block_enable(struct sst_mem_block *block)
/* wait 18 DSP clock ticks */
udelay(10);
+ /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ val |= SST_VDRTCL2_DCLCGE;
+ writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ udelay(50);
+
/*add a dummy read before the SRAM block is written, otherwise the writing may miss bytes sometimes.*/
sst_mem_block_dummy_read(block);
return 0;
@@ -420,10 +579,26 @@ static int hsw_block_disable(struct sst_mem_block *block)
dev_dbg(block->dsp->dev, " disabled block %d:%d at offset 0x%x\n",
block->type, block->index, block->offset);
+ /* Disable core clock gating (VDRTCTL2.DCLCGE = 0) */
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ val &= ~SST_VDRTCL2_DCLCGE;
+ writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+
val = readl(sst->addr.pci_cfg + SST_VDRTCTL0);
bit = hsw_block_get_bit(block);
writel(val | bit, sst->addr.pci_cfg + SST_VDRTCTL0);
+ /* wait 18 DSP clock ticks */
+ udelay(10);
+
+ /* Enable core clock gating (VDRTCTL2.DCLCGE = 1), delay 50 us */
+ val = readl(sst->addr.pci_cfg + SST_VDRTCTL2);
+ val |= SST_VDRTCL2_DCLCGE;
+ writel(val, sst->addr.pci_cfg + SST_VDRTCTL2);
+
+ udelay(50);
+
return 0;
}
@@ -432,27 +607,6 @@ static struct sst_block_ops sst_hsw_ops = {
.disable = hsw_block_disable,
};
-static int hsw_enable_shim(struct sst_dsp *sst)
-{
- int tries = 10;
- u32 reg;
-
- /* enable shim */
- reg = readl(sst->addr.pci_cfg + SST_SHIM_PM_REG);
- writel(reg & ~0x3, sst->addr.pci_cfg + SST_SHIM_PM_REG);
-
- /* check that ADSP shim is enabled */
- while (tries--) {
- reg = sst_dsp_shim_read_unlocked(sst, SST_CSR);
- if (reg != 0xffffffff)
- return 0;
-
- msleep(1);
- }
-
- return -ENODEV;
-}
-
static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
{
const struct sst_adsp_memregion *region;
@@ -467,12 +621,16 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
region = lp_region;
region_count = ARRAY_SIZE(lp_region);
sst->addr.iram_offset = SST_LP_IRAM_OFFSET;
+ sst->addr.dsp_iram_offset = SST_LPT_DSP_IRAM_OFFSET;
+ sst->addr.dsp_dram_offset = SST_LPT_DSP_DRAM_OFFSET;
sst->addr.shim_offset = SST_LP_SHIM_OFFSET;
break;
case SST_DEV_ID_WILDCAT_POINT:
region = wpt_region;
region_count = ARRAY_SIZE(wpt_region);
sst->addr.iram_offset = SST_WPT_IRAM_OFFSET;
+ sst->addr.dsp_iram_offset = SST_WPT_DSP_IRAM_OFFSET;
+ sst->addr.dsp_dram_offset = SST_WPT_DSP_DRAM_OFFSET;
sst->addr.shim_offset = SST_WPT_SHIM_OFFSET;
break;
default:
@@ -487,7 +645,7 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
}
/* enable the DSP SHIM */
- ret = hsw_enable_shim(sst);
+ ret = hsw_set_dsp_D0(sst);
if (ret < 0) {
dev_err(dev, "error: failed to set DSP D0 and reset SHIM\n");
return ret;
@@ -497,10 +655,6 @@ static int hsw_init(struct sst_dsp *sst, struct sst_pdata *pdata)
if (ret)
return ret;
- /* Enable Interrupt from both sides */
- sst_dsp_shim_update_bits_unlocked(sst, SST_IMRX, 0x3, 0x0);
- sst_dsp_shim_update_bits_unlocked(sst, SST_IMRD,
- (0x3 | 0x1 << 16 | 0x3 << 21), 0x0);
/* register DSP memory blocks - ideally we should get this from ACPI */
for (i = 0; i < region_count; i++) {
@@ -532,6 +686,9 @@ static void hsw_free(struct sst_dsp *sst)
struct sst_ops haswell_ops = {
.reset = hsw_reset,
.boot = hsw_boot,
+ .stall = hsw_stall,
+ .wake = hsw_wake,
+ .sleep = hsw_sleep,
.write = sst_shim32_write,
.read = sst_shim32_read,
.write64 = sst_shim32_write64,
diff --git a/sound/soc/intel/sst-haswell-ipc.c b/sound/soc/intel/sst-haswell-ipc.c
index b629151..3f8c482 100644
--- a/sound/soc/intel/sst-haswell-ipc.c
+++ b/sound/soc/intel/sst-haswell-ipc.c
@@ -30,6 +30,7 @@
#include <linux/firmware.h>
#include <linux/dma-mapping.h>
#include <linux/debugfs.h>
+#include <linux/pm_runtime.h>
#include "sst-haswell-ipc.h"
#include "sst-dsp.h"
@@ -276,6 +277,7 @@ struct sst_hsw {
struct sst_hsw_ipc_fw_version version;
struct sst_module *scratch;
bool fw_done;
+ struct sst_fw *sst_fw;
/* stream */
struct list_head stream_list;
@@ -289,6 +291,8 @@ struct sst_hsw {
/* DX */
struct sst_hsw_ipc_dx_reply dx;
+ void *dx_context;
+ dma_addr_t dx_context_paddr;
/* boot */
wait_queue_head_t boot_wait;
@@ -1038,14 +1042,9 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
trace_ipc_request("set stream volume", stream->reply.stream_hw_id);
- if (channel > 1)
+ if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL)
return -EINVAL;
- if (stream->mute[channel]) {
- stream->mute_volume[channel] = volume;
- return 0;
- }
-
header = IPC_GLB_TYPE(IPC_GLB_STREAM_MESSAGE) |
IPC_STR_TYPE(IPC_STR_STAGE_MESSAGE);
header |= (stream->reply.stream_hw_id << IPC_STR_ID_SHIFT);
@@ -1053,9 +1052,28 @@ int sst_hsw_stream_set_volume(struct sst_hsw *hsw,
header |= (stage_id << IPC_STG_ID_SHIFT);
req = &stream->vol_req;
- req->channel = channel;
req->target_volume = volume;
+ /* set both at same time ? */
+ if (channel == SST_HSW_CHANNELS_ALL) {
+ if (hsw->mute[0] && hsw->mute[1]) {
+ hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
+ return 0;
+ } else if (hsw->mute[0])
+ req->channel = 1;
+ else if (hsw->mute[1])
+ req->channel = 0;
+ else
+ req->channel = SST_HSW_CHANNELS_ALL;
+ } else {
+ /* set only 1 channel */
+ if (hsw->mute[channel]) {
+ hsw->mute_volume[channel] = volume;
+ return 0;
+ }
+ req->channel = channel;
+ }
+
ret = ipc_tx_message_wait(hsw, header, req, sizeof(*req), NULL, 0);
if (ret < 0) {
dev_err(hsw->dev, "error: set stream volume failed\n");
@@ -1134,8 +1152,11 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
trace_ipc_request("set mixer volume", volume);
+ if (channel >= 2 && channel != SST_HSW_CHANNELS_ALL)
+ return -EINVAL;
+
/* set both at same time ? */
- if (channel == 2) {
+ if (channel == SST_HSW_CHANNELS_ALL) {
if (hsw->mute[0] && hsw->mute[1]) {
hsw->mute_volume[0] = hsw->mute_volume[1] = volume;
return 0;
@@ -1144,7 +1165,7 @@ int sst_hsw_mixer_set_volume(struct sst_hsw *hsw, u32 stage_id, u32 channel,
else if (hsw->mute[1])
req.channel = 0;
else
- req.channel = 0xffffffff;
+ req.channel = SST_HSW_CHANNELS_ALL;
} else {
/* set only 1 channel */
if (hsw->mute[channel]) {
@@ -1256,10 +1277,6 @@ int sst_hsw_stream_set_channels(struct sst_hsw *hsw,
return -EINVAL;
}
- /* stereo is only supported atm */
- if (channels != 2)
- return -EINVAL;
-
stream->request.format.ch_num = channels;
return 0;
}
@@ -1355,10 +1372,11 @@ int sst_hsw_stream_buffer(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
}
int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
- struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
- u32 entry_point)
+ struct sst_hsw_stream *stream, struct sst_module_runtime *runtime)
{
struct sst_hsw_module_map *map = &stream->request.map;
+ struct sst_dsp *dsp = sst_hsw_get_dsp(hsw);
+ struct sst_module *module = runtime->module;
if (stream->commited) {
dev_err(hsw->dev, "error: stream committed for set module\n");
@@ -1367,36 +1385,25 @@ int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
/* only support initial module atm */
map->module_entries_count = 1;
- map->module_entries[0].module_id = module_id;
- map->module_entries[0].entry_point = entry_point;
-
- return 0;
-}
-
-int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
- struct sst_hsw_stream *stream, u32 offset, u32 size)
-{
- if (stream->commited) {
- dev_err(hsw->dev, "error: stream committed for set pmem\n");
- return -EINVAL;
- }
-
- stream->request.persistent_mem.offset = offset;
- stream->request.persistent_mem.size = size;
-
- return 0;
-}
-
-int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
- struct sst_hsw_stream *stream, u32 offset, u32 size)
-{
- if (stream->commited) {
- dev_err(hsw->dev, "error: stream committed for set smem\n");
- return -EINVAL;
- }
-
- stream->request.scratch_mem.offset = offset;
- stream->request.scratch_mem.size = size;
+ map->module_entries[0].module_id = module->id;
+ map->module_entries[0].entry_point = module->entry;
+
+ stream->request.persistent_mem.offset =
+ sst_dsp_get_offset(dsp, runtime->persistent_offset, SST_MEM_DRAM);
+ stream->request.persistent_mem.size = module->persistent_size;
+
+ stream->request.scratch_mem.offset =
+ sst_dsp_get_offset(dsp, dsp->scratch_offset, SST_MEM_DRAM);
+ stream->request.scratch_mem.size = dsp->scratch_size;
+
+ dev_dbg(hsw->dev, "module %d runtime %d using:\n", module->id,
+ runtime->id);
+ dev_dbg(hsw->dev, " persistent offset 0x%x bytes 0x%x\n",
+ stream->request.persistent_mem.offset,
+ stream->request.persistent_mem.size);
+ dev_dbg(hsw->dev, " scratch offset 0x%x bytes 0x%x\n",
+ stream->request.scratch_mem.offset,
+ stream->request.scratch_mem.size);
return 0;
}
@@ -1630,6 +1637,10 @@ int sst_hsw_device_set_config(struct sst_hsw *hsw,
config.clock_frequency = mclk;
config.mode = mode;
config.clock_divider = clock_divider;
+ if (mode == SST_HSW_DEVICE_TDM_CLOCK_MASTER)
+ config.channels = 4;
+ else
+ config.channels = 2;
trace_hsw_device_config_req(&config);
@@ -1673,34 +1684,283 @@ int sst_hsw_dx_set_state(struct sst_hsw *hsw,
dev_dbg(hsw->dev, "ipc: got %d entry numbers for state %d\n",
dx->entries_no, state);
- memcpy(&hsw->dx, dx, sizeof(*dx));
- return 0;
+ return ret;
}
-/* Used to save state into hsw->dx_reply */
-int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
- u32 *offset, u32 *size, u32 *source)
+struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
+ int mod_id, int offset)
{
- struct sst_hsw_ipc_dx_memory_item *dx_mem;
- struct sst_hsw_ipc_dx_reply *dx_reply;
- int entry_no;
+ struct sst_dsp *dsp = hsw->dsp;
+ struct sst_module *module;
+ struct sst_module_runtime *runtime;
+ int err;
- dx_reply = &hsw->dx;
- entry_no = dx_reply->entries_no;
+ module = sst_module_get_from_id(dsp, mod_id);
+ if (module == NULL) {
+ dev_err(dsp->dev, "error: failed to get module %d for pcm\n",
+ mod_id);
+ return NULL;
+ }
+
+ runtime = sst_module_runtime_new(module, mod_id, NULL);
+ if (runtime == NULL) {
+ dev_err(dsp->dev, "error: failed to create module %d runtime\n",
+ mod_id);
+ return NULL;
+ }
+
+ err = sst_module_runtime_alloc_blocks(runtime, offset);
+ if (err < 0) {
+ dev_err(dsp->dev, "error: failed to alloc blocks for module %d runtime\n",
+ mod_id);
+ sst_module_runtime_free(runtime);
+ return NULL;
+ }
+
+ dev_dbg(dsp->dev, "runtime id %d created for module %d\n", runtime->id,
+ mod_id);
+ return runtime;
+}
+
+void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime)
+{
+ sst_module_runtime_free_blocks(runtime);
+ sst_module_runtime_free(runtime);
+}
+
+#ifdef CONFIG_PM
+static int sst_hsw_dx_state_dump(struct sst_hsw *hsw)
+{
+ struct sst_dsp *sst = hsw->dsp;
+ u32 item, offset, size;
+ int ret = 0;
- trace_ipc_request("PM get Dx state", entry_no);
+ trace_ipc_request("PM state dump. Items #", SST_HSW_MAX_DX_REGIONS);
- if (item >= entry_no)
+ if (hsw->dx.entries_no > SST_HSW_MAX_DX_REGIONS) {
+ dev_err(hsw->dev,
+ "error: number of FW context regions greater than %d\n",
+ SST_HSW_MAX_DX_REGIONS);
+ memset(&hsw->dx, 0, sizeof(hsw->dx));
return -EINVAL;
+ }
+
+ ret = sst_dsp_dma_get_channel(sst, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
+ return ret;
+ }
+
+ /* set on-demond mode on engine 0 channel 3 */
+ sst_dsp_shim_update_bits(sst, SST_HMDC,
+ SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH,
+ SST_HMDC_HDDA_E0_ALLCH | SST_HMDC_HDDA_E1_ALLCH);
+
+ for (item = 0; item < hsw->dx.entries_no; item++) {
+ if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP
+ && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET
+ && hsw->dx.mem_info[item].offset <
+ DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) {
+
+ offset = hsw->dx.mem_info[item].offset
+ - DSP_DRAM_ADDR_OFFSET;
+ size = (hsw->dx.mem_info[item].size + 3) & (~3);
+
+ ret = sst_dsp_dma_copyfrom(sst, hsw->dx_context_paddr + offset,
+ sst->addr.lpe_base + offset, size);
+ if (ret < 0) {
+ dev_err(hsw->dev,
+ "error: FW context dump failed\n");
+ memset(&hsw->dx, 0, sizeof(hsw->dx));
+ goto out;
+ }
+ }
+ }
+
+out:
+ sst_dsp_dma_put_channel(sst);
+ return ret;
+}
+
+static int sst_hsw_dx_state_restore(struct sst_hsw *hsw)
+{
+ struct sst_dsp *sst = hsw->dsp;
+ u32 item, offset, size;
+ int ret;
+
+ for (item = 0; item < hsw->dx.entries_no; item++) {
+ if (hsw->dx.mem_info[item].source == SST_HSW_DX_TYPE_MEMORY_DUMP
+ && hsw->dx.mem_info[item].offset > DSP_DRAM_ADDR_OFFSET
+ && hsw->dx.mem_info[item].offset <
+ DSP_DRAM_ADDR_OFFSET + SST_HSW_DX_CONTEXT_SIZE) {
+
+ offset = hsw->dx.mem_info[item].offset
+ - DSP_DRAM_ADDR_OFFSET;
+ size = (hsw->dx.mem_info[item].size + 3) & (~3);
+
+ ret = sst_dsp_dma_copyto(sst, sst->addr.lpe_base + offset,
+ hsw->dx_context_paddr + offset, size);
+ if (ret < 0) {
+ dev_err(hsw->dev,
+ "error: FW context restore failed\n");
+ return ret;
+ }
+ }
+ }
+
+ return 0;
+}
+
+static void sst_hsw_drop_all(struct sst_hsw *hsw)
+{
+ struct ipc_message *msg, *tmp;
+ unsigned long flags;
+ int tx_drop_cnt = 0, rx_drop_cnt = 0;
- dx_mem = &dx_reply->mem_info[item];
- *offset = dx_mem->offset;
- *size = dx_mem->size;
- *source = dx_mem->source;
+ /* drop all TX and Rx messages before we stall + reset DSP */
+ spin_lock_irqsave(&hsw->dsp->spinlock, flags);
+
+ list_for_each_entry_safe(msg, tmp, &hsw->tx_list, list) {
+ list_move(&msg->list, &hsw->empty_list);
+ tx_drop_cnt++;
+ }
+
+ list_for_each_entry_safe(msg, tmp, &hsw->rx_list, list) {
+ list_move(&msg->list, &hsw->empty_list);
+ rx_drop_cnt++;
+ }
+
+ spin_unlock_irqrestore(&hsw->dsp->spinlock, flags);
+
+ if (tx_drop_cnt || rx_drop_cnt)
+ dev_err(hsw->dev, "dropped IPC msg RX=%d, TX=%d\n",
+ tx_drop_cnt, rx_drop_cnt);
+}
+
+int sst_hsw_dsp_load(struct sst_hsw *hsw)
+{
+ struct sst_dsp *dsp = hsw->dsp;
+ int ret;
+
+ dev_dbg(hsw->dev, "loading audio DSP....");
+
+ ret = sst_dsp_wake(dsp);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: failed to wake audio DSP\n");
+ return -ENODEV;
+ }
+
+ ret = sst_dsp_dma_get_channel(dsp, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
+ return ret;
+ }
+
+ ret = sst_fw_reload(hsw->sst_fw);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: SST FW reload failed\n");
+ sst_dsp_dma_put_channel(dsp);
+ return -ENOMEM;
+ }
+ sst_dsp_dma_put_channel(dsp);
return 0;
}
+static int sst_hsw_dsp_restore(struct sst_hsw *hsw)
+{
+ struct sst_dsp *dsp = hsw->dsp;
+ int ret;
+
+ dev_dbg(hsw->dev, "restoring audio DSP....");
+
+ ret = sst_dsp_dma_get_channel(dsp, 0);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: cant allocate dma channel %d\n", ret);
+ return ret;
+ }
+
+ ret = sst_hsw_dx_state_restore(hsw);
+ if (ret < 0) {
+ dev_err(hsw->dev, "error: SST FW context restore failed\n");
+ sst_dsp_dma_put_channel(dsp);
+ return -ENOMEM;
+ }
+ sst_dsp_dma_put_channel(dsp);
+
+ /* wait for DSP boot completion */
+ sst_dsp_boot(dsp);
+
+ return ret;
+}
+
+int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw)
+{
+ int ret;
+
+ dev_dbg(hsw->dev, "audio dsp runtime suspend\n");
+
+ ret = sst_hsw_dx_set_state(hsw, SST_HSW_DX_STATE_D3, &hsw->dx);
+ if (ret < 0)
+ return ret;
+
+ sst_dsp_stall(hsw->dsp);
+
+ ret = sst_hsw_dx_state_dump(hsw);
+ if (ret < 0)
+ return ret;
+
+ sst_hsw_drop_all(hsw);
+
+ return 0;
+}
+
+int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw)
+{
+ sst_fw_unload(hsw->sst_fw);
+ sst_block_free_scratch(hsw->dsp);
+
+ hsw->boot_complete = false;
+
+ sst_dsp_sleep(hsw->dsp);
+
+ return 0;
+}
+
+int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw)
+{
+ struct device *dev = hsw->dev;
+ int ret;
+
+ dev_dbg(dev, "audio dsp runtime resume\n");
+
+ if (hsw->boot_complete)
+ return 1; /* tell caller no action is required */
+
+ ret = sst_hsw_dsp_restore(hsw);
+ if (ret < 0)
+ dev_err(dev, "error: audio DSP boot failure\n");
+
+ ret = wait_event_timeout(hsw->boot_wait, hsw->boot_complete,
+ msecs_to_jiffies(IPC_BOOT_MSECS));
+ if (ret == 0) {
+ dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n",
+ sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD),
+ sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX));
+ return -EIO;
+ }
+
+ /* Set ADSP SSP port settings */
+ ret = sst_hsw_device_set_config(hsw, SST_HSW_DEVICE_SSP_0,
+ SST_HSW_DEVICE_MCLK_FREQ_24_MHZ,
+ SST_HSW_DEVICE_CLOCK_MASTER, 9);
+ if (ret < 0)
+ dev_err(dev, "error: SSP re-initialization failed\n");
+
+ return ret;
+}
+#endif
+
static int msg_empty_list_init(struct sst_hsw *hsw)
{
int i;
@@ -1718,12 +1978,6 @@ static int msg_empty_list_init(struct sst_hsw *hsw)
return 0;
}
-void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
- struct sst_module *scratch)
-{
- hsw->scratch = scratch;
-}
-
struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw)
{
return hsw->dsp;
@@ -1738,7 +1992,6 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
{
struct sst_hsw_ipc_fw_version version;
struct sst_hsw *hsw;
- struct sst_fw *hsw_sst_fw;
int ret;
dev_dbg(dev, "initialising Audio DSP IPC\n");
@@ -1780,12 +2033,19 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
goto dsp_err;
}
+ /* allocate DMA buffer for context storage */
+ hsw->dx_context = dma_alloc_coherent(hsw->dsp->dma_dev,
+ SST_HSW_DX_CONTEXT_SIZE, &hsw->dx_context_paddr, GFP_KERNEL);
+ if (hsw->dx_context == NULL) {
+ ret = -ENOMEM;
+ goto dma_err;
+ }
+
/* keep the DSP in reset state for base FW loading */
sst_dsp_reset(hsw->dsp);
- hsw_sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
-
- if (hsw_sst_fw == NULL) {
+ hsw->sst_fw = sst_fw_new(hsw->dsp, pdata->fw, hsw);
+ if (hsw->sst_fw == NULL) {
ret = -ENODEV;
dev_err(dev, "error: failed to load firmware\n");
goto fw_err;
@@ -1797,7 +2057,9 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
msecs_to_jiffies(IPC_BOOT_MSECS));
if (ret == 0) {
ret = -EIO;
- dev_err(hsw->dev, "error: ADSP boot timeout\n");
+ dev_err(hsw->dev, "error: audio DSP boot timeout IPCD 0x%x IPCX 0x%x\n",
+ sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCD),
+ sst_dsp_shim_read_unlocked(hsw->dsp, SST_IPCX));
goto boot_err;
}
@@ -1816,8 +2078,11 @@ int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata)
boot_err:
sst_dsp_reset(hsw->dsp);
- sst_fw_free(hsw_sst_fw);
+ sst_fw_free(hsw->sst_fw);
fw_err:
+ dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
+ hsw->dx_context, hsw->dx_context_paddr);
+dma_err:
sst_dsp_free(hsw->dsp);
dsp_err:
kthread_stop(hsw->tx_thread);
@@ -1834,6 +2099,8 @@ void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata)
sst_dsp_reset(hsw->dsp);
sst_fw_free_all(hsw->dsp);
+ dma_free_coherent(hsw->dsp->dma_dev, SST_HSW_DX_CONTEXT_SIZE,
+ hsw->dx_context, hsw->dx_context_paddr);
sst_dsp_free(hsw->dsp);
kfree(hsw->scratch);
kthread_stop(hsw->tx_thread);
diff --git a/sound/soc/intel/sst-haswell-ipc.h b/sound/soc/intel/sst-haswell-ipc.h
index 2ac194a..138e894 100644
--- a/sound/soc/intel/sst-haswell-ipc.h
+++ b/sound/soc/intel/sst-haswell-ipc.h
@@ -21,8 +21,10 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
-#define SST_HSW_NO_CHANNELS 2
+#define SST_HSW_NO_CHANNELS 4
#define SST_HSW_MAX_DX_REGIONS 14
+#define SST_HSW_DX_CONTEXT_SIZE (640 * 1024)
+#define SST_HSW_CHANNELS_ALL 0xffffffff
#define SST_HSW_FW_LOG_CONFIG_DWORDS 12
#define SST_HSW_GLOBAL_LOG 15
@@ -40,6 +42,7 @@ struct sst_hsw_stream;
struct sst_hsw_log_stream;
struct sst_pdata;
struct sst_module;
+struct sst_module_runtime;
extern struct sst_ops haswell_ops;
/* Stream Allocate Path ID */
@@ -84,6 +87,7 @@ enum sst_hsw_device_mclk {
enum sst_hsw_device_mode {
SST_HSW_DEVICE_CLOCK_SLAVE = 0,
SST_HSW_DEVICE_CLOCK_MASTER = 1,
+ SST_HSW_DEVICE_TDM_CLOCK_MASTER = 2,
};
/* DX Power State */
@@ -295,7 +299,8 @@ struct sst_hsw_ipc_device_config_req {
u32 clock_frequency;
u32 mode;
u16 clock_divider;
- u16 reserved;
+ u8 channels;
+ u8 reserved;
} __attribute__((packed));
/* Audio Data formats */
@@ -430,8 +435,7 @@ int sst_hsw_stream_set_map_config(struct sst_hsw *hsw,
int sst_hsw_stream_set_style(struct sst_hsw *hsw, struct sst_hsw_stream *stream,
enum sst_hsw_interleaving style);
int sst_hsw_stream_set_module_info(struct sst_hsw *hsw,
- struct sst_hsw_stream *stream, enum sst_hsw_module_id module_id,
- u32 entry_point);
+ struct sst_hsw_stream *stream, struct sst_module_runtime *runtime);
int sst_hsw_stream_set_pmemory_info(struct sst_hsw *hsw,
struct sst_hsw_stream *stream, u32 offset, u32 size);
int sst_hsw_stream_set_smemory_info(struct sst_hsw *hsw,
@@ -484,7 +488,16 @@ int sst_hsw_dx_get_state(struct sst_hsw *hsw, u32 item,
int sst_hsw_dsp_init(struct device *dev, struct sst_pdata *pdata);
void sst_hsw_dsp_free(struct device *dev, struct sst_pdata *pdata);
struct sst_dsp *sst_hsw_get_dsp(struct sst_hsw *hsw);
-void sst_hsw_set_scratch_module(struct sst_hsw *hsw,
- struct sst_module *scratch);
+
+/* runtime module management */
+struct sst_module_runtime *sst_hsw_runtime_module_create(struct sst_hsw *hsw,
+ int mod_id, int offset);
+void sst_hsw_runtime_module_free(struct sst_module_runtime *runtime);
+
+/* PM */
+int sst_hsw_dsp_runtime_resume(struct sst_hsw *hsw);
+int sst_hsw_dsp_runtime_suspend(struct sst_hsw *hsw);
+int sst_hsw_dsp_load(struct sst_hsw *hsw);
+int sst_hsw_dsp_runtime_sleep(struct sst_hsw *hsw);
#endif
diff --git a/sound/soc/intel/sst-haswell-pcm.c b/sound/soc/intel/sst-haswell-pcm.c
index 4df867c..0180b38 100644
--- a/sound/soc/intel/sst-haswell-pcm.c
+++ b/sound/soc/intel/sst-haswell-pcm.c
@@ -18,6 +18,7 @@
#include <linux/dma-mapping.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/pm_runtime.h>
#include <asm/page.h>
#include <asm/pgtable.h>
#include <sound/core.h>
@@ -73,6 +74,13 @@ static const u32 volume_map[] = {
#define HSW_PCM_PERIODS_MAX 64
#define HSW_PCM_PERIODS_MIN 2
+#define HSW_PCM_DAI_ID_SYSTEM 0
+#define HSW_PCM_DAI_ID_OFFLOAD0 1
+#define HSW_PCM_DAI_ID_OFFLOAD1 2
+#define HSW_PCM_DAI_ID_LOOPBACK 3
+#define HSW_PCM_DAI_ID_CAPTURE 4
+
+
static const struct snd_pcm_hardware hsw_pcm_hardware = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_MMAP_VALID |
@@ -89,22 +97,39 @@ static const struct snd_pcm_hardware hsw_pcm_hardware = {
.buffer_bytes_max = HSW_PCM_PERIODS_MAX * PAGE_SIZE,
};
+struct hsw_pcm_module_map {
+ int dai_id;
+ enum sst_hsw_module_id mod_id;
+};
+
/* private data for each PCM DSP stream */
struct hsw_pcm_data {
int dai_id;
struct sst_hsw_stream *stream;
+ struct sst_module_runtime *runtime;
+ struct sst_module_runtime_context context;
+ struct snd_pcm *hsw_pcm;
u32 volume[2];
struct snd_pcm_substream *substream;
struct snd_compr_stream *cstream;
unsigned int wpos;
struct mutex mutex;
bool allocated;
+ int persistent_offset;
+};
+
+enum hsw_pm_state {
+ HSW_PM_STATE_D3 = 0,
+ HSW_PM_STATE_D0 = 1,
};
/* private data for the driver */
struct hsw_priv_data {
/* runtime DSP */
struct sst_hsw *hsw;
+ struct device *dev;
+ enum hsw_pm_state pm_state;
+ struct snd_soc_card *soc_card;
/* page tables */
struct snd_dma_buffer dmab[HSW_PCM_COUNT][2];
@@ -138,21 +163,25 @@ static inline unsigned int hsw_ipc_to_mixer(u32 value)
static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(platform);
struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
mutex_lock(&pcm_data->mutex);
+ pm_runtime_get_sync(pdata->dev);
if (!pcm_data->stream) {
pcm_data->volume[0] =
hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
pcm_data->volume[1] =
hsw_mixer_to_ipc(ucontrol->value.integer.value[1]);
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
mutex_unlock(&pcm_data->mutex);
return 0;
}
@@ -160,7 +189,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
if (ucontrol->value.integer.value[0] ==
ucontrol->value.integer.value[1]) {
volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
- sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 2, volume);
+ /* apply volume value to all channels */
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, SST_HSW_CHANNELS_ALL, volume);
} else {
volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 0, volume);
@@ -168,6 +198,8 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0, 1, volume);
}
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
mutex_unlock(&pcm_data->mutex);
return 0;
}
@@ -175,21 +207,25 @@ static int hsw_stream_volume_put(struct snd_kcontrol *kcontrol,
static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
struct soc_mixer_control *mc =
(struct soc_mixer_control *)kcontrol->private_value;
+ struct hsw_priv_data *pdata =
+ snd_soc_platform_get_drvdata(platform);
struct hsw_pcm_data *pcm_data = &pdata->pcm[mc->reg];
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
mutex_lock(&pcm_data->mutex);
+ pm_runtime_get_sync(pdata->dev);
if (!pcm_data->stream) {
ucontrol->value.integer.value[0] =
hsw_ipc_to_mixer(pcm_data->volume[0]);
ucontrol->value.integer.value[1] =
hsw_ipc_to_mixer(pcm_data->volume[1]);
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
mutex_unlock(&pcm_data->mutex);
return 0;
}
@@ -198,6 +234,9 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
sst_hsw_stream_get_volume(hsw, pcm_data->stream, 0, 1, &volume);
ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
mutex_unlock(&pcm_data->mutex);
return 0;
@@ -206,16 +245,18 @@ static int hsw_stream_volume_get(struct snd_kcontrol *kcontrol,
static int hsw_volume_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
struct sst_hsw *hsw = pdata->hsw;
u32 volume;
+ pm_runtime_get_sync(pdata->dev);
+
if (ucontrol->value.integer.value[0] ==
ucontrol->value.integer.value[1]) {
volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
- sst_hsw_mixer_set_volume(hsw, 0, 2, volume);
+ sst_hsw_mixer_set_volume(hsw, 0, SST_HSW_CHANNELS_ALL, volume);
} else {
volume = hsw_mixer_to_ipc(ucontrol->value.integer.value[0]);
@@ -225,23 +266,28 @@ static int hsw_volume_put(struct snd_kcontrol *kcontrol,
sst_hsw_mixer_set_volume(hsw, 0, 1, volume);
}
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
return 0;
}
static int hsw_volume_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_soc_component *cmpnt = snd_soc_kcontrol_component(kcontrol);
- struct hsw_priv_data *pdata = snd_soc_component_get_drvdata(cmpnt);
+ struct snd_soc_platform *platform = snd_soc_kcontrol_platform(kcontrol);
+ struct hsw_priv_data *pdata = snd_soc_platform_get_drvdata(platform);
struct sst_hsw *hsw = pdata->hsw;
unsigned int volume = 0;
+ pm_runtime_get_sync(pdata->dev);
sst_hsw_mixer_get_volume(hsw, 0, 0, &volume);
ucontrol->value.integer.value[0] = hsw_ipc_to_mixer(volume);
sst_hsw_mixer_get_volume(hsw, 0, 1, &volume);
ucontrol->value.integer.value[1] = hsw_ipc_to_mixer(volume);
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
return 0;
}
@@ -252,23 +298,19 @@ static const DECLARE_TLV_DB_SCALE(hsw_vol_tlv, -9000, 300, 1);
static const struct snd_kcontrol_new hsw_volume_controls[] = {
/* Global DSP volume */
SOC_DOUBLE_EXT_TLV("Master Playback Volume", 0, 0, 8,
- ARRAY_SIZE(volume_map) -1, 0,
+ ARRAY_SIZE(volume_map) - 1, 0,
hsw_volume_get, hsw_volume_put, hsw_vol_tlv),
/* Offload 0 volume */
SOC_DOUBLE_EXT_TLV("Media0 Playback Volume", 1, 0, 8,
- ARRAY_SIZE(volume_map), 0,
+ ARRAY_SIZE(volume_map) - 1, 0,
hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
/* Offload 1 volume */
SOC_DOUBLE_EXT_TLV("Media1 Playback Volume", 2, 0, 8,
- ARRAY_SIZE(volume_map), 0,
- hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
- /* Loopback volume */
- SOC_DOUBLE_EXT_TLV("Loopback Capture Volume", 3, 0, 8,
- ARRAY_SIZE(volume_map), 0,
+ ARRAY_SIZE(volume_map) - 1, 0,
hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
/* Mic Capture volume */
- SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 4, 0, 8,
- ARRAY_SIZE(volume_map), 0,
+ SOC_DOUBLE_EXT_TLV("Mic Capture Volume", 0, 0, 8,
+ ARRAY_SIZE(volume_map) - 1, 0,
hsw_stream_volume_get, hsw_stream_volume_put, hsw_vol_tlv),
};
@@ -354,8 +396,14 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
/* DSP stream type depends on DAI ID */
switch (rtd->cpu_dai->id) {
case 0:
- stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
- module_id = SST_HSW_MODULE_PCM_SYSTEM;
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ stream_type = SST_HSW_STREAM_TYPE_SYSTEM;
+ module_id = SST_HSW_MODULE_PCM_SYSTEM;
+ }
+ else {
+ stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
+ module_id = SST_HSW_MODULE_PCM_CAPTURE;
+ }
break;
case 1:
case 2:
@@ -368,10 +416,6 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
path_id = SST_HSW_STREAM_PATH_SSP0_OUT;
module_id = SST_HSW_MODULE_PCM_REFERENCE;
break;
- case 4:
- stream_type = SST_HSW_STREAM_TYPE_CAPTURE;
- module_id = SST_HSW_MODULE_PCM_CAPTURE;
- break;
default:
dev_err(rtd->dev, "error: invalid DAI ID %d\n",
rtd->cpu_dai->id);
@@ -421,13 +465,7 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
return ret;
}
- /* we only support stereo atm */
channels = params_channels(params);
- if (channels != 2) {
- dev_err(rtd->dev, "error: invalid channels %d\n", channels);
- return -EINVAL;
- }
-
map = create_channel_map(SST_HSW_CHANNEL_CONFIG_STEREO);
sst_hsw_stream_set_map_config(hsw, pcm_data->stream,
map, SST_HSW_CHANNEL_CONFIG_STEREO);
@@ -478,35 +516,23 @@ static int hsw_pcm_hw_params(struct snd_pcm_substream *substream,
return -EINVAL;
}
- /* we use hardcoded memory offsets atm, will be updated for new FW */
- if (stream_type == SST_HSW_STREAM_TYPE_CAPTURE) {
- sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
- SST_HSW_MODULE_PCM_CAPTURE, module_data->entry);
- sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
- 0x449400, 0x4000);
- sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
- 0x400000, 0);
- } else { /* stream_type == SST_HSW_STREAM_TYPE_SYSTEM */
- sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
- SST_HSW_MODULE_PCM_SYSTEM, module_data->entry);
-
- sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
- module_data->offset, module_data->size);
- sst_hsw_stream_set_pmemory_info(hsw, pcm_data->stream,
- 0x44d400, 0x3800);
-
- sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
- module_data->offset, module_data->size);
- sst_hsw_stream_set_smemory_info(hsw, pcm_data->stream,
- 0x400000, 0);
- }
+ sst_hsw_stream_set_module_info(hsw, pcm_data->stream,
+ pcm_data->runtime);
ret = sst_hsw_stream_commit(hsw, pcm_data->stream);
if (ret < 0) {
dev_err(rtd->dev, "error: failed to commit stream %d\n", ret);
return ret;
}
- pcm_data->allocated = true;
+
+ if (!pcm_data->allocated) {
+ /* Set previous saved volume */
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+ 0, pcm_data->volume[0]);
+ sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
+ 1, pcm_data->volume[1]);
+ pcm_data->allocated = true;
+ }
ret = sst_hsw_stream_pause(hsw, pcm_data->stream, 1);
if (ret < 0)
@@ -558,7 +584,7 @@ static u32 hsw_notify_pointer(struct sst_hsw_stream *stream, void *data)
pos = frames_to_bytes(runtime,
(runtime->control->appl_ptr % runtime->buffer_size));
- dev_dbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
+ dev_vdbg(rtd->dev, "PCM: App pointer %d bytes\n", pos);
/* let alsa know we have play a period */
snd_pcm_period_elapsed(substream);
@@ -580,7 +606,7 @@ static snd_pcm_uframes_t hsw_pcm_pointer(struct snd_pcm_substream *substream)
offset = bytes_to_frames(runtime, position);
ppos = sst_hsw_get_dsp_presentation_position(hsw, pcm_data->stream);
- dev_dbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
+ dev_vdbg(rtd->dev, "PCM: DMA pointer %du bytes, pos %llu\n",
position, ppos);
return offset;
}
@@ -596,6 +622,7 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
pcm_data = &pdata->pcm[rtd->cpu_dai->id];
mutex_lock(&pcm_data->mutex);
+ pm_runtime_get_sync(pdata->dev);
snd_soc_pcm_set_drvdata(rtd, pcm_data);
pcm_data->substream = substream;
@@ -606,16 +633,12 @@ static int hsw_pcm_open(struct snd_pcm_substream *substream)
hsw_notify_pointer, pcm_data);
if (pcm_data->stream == NULL) {
dev_err(rtd->dev, "error: failed to create stream\n");
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
mutex_unlock(&pcm_data->mutex);
return -EINVAL;
}
- /* Set previous saved volume */
- sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
- 0, pcm_data->volume[0]);
- sst_hsw_stream_set_volume(hsw, pcm_data->stream, 0,
- 1, pcm_data->volume[1]);
-
mutex_unlock(&pcm_data->mutex);
return 0;
}
@@ -645,6 +668,8 @@ static int hsw_pcm_close(struct snd_pcm_substream *substream)
pcm_data->stream = NULL;
out:
+ pm_runtime_mark_last_busy(pdata->dev);
+ pm_runtime_put_autosuspend(pdata->dev);
mutex_unlock(&pcm_data->mutex);
return ret;
}
@@ -660,6 +685,56 @@ static struct snd_pcm_ops hsw_pcm_ops = {
.page = snd_pcm_sgbuf_ops_page,
};
+/* static mappings between PCMs and modules - may be dynamic in future */
+static struct hsw_pcm_module_map mod_map[] = {
+ {HSW_PCM_DAI_ID_SYSTEM, SST_HSW_MODULE_PCM_SYSTEM},
+ {HSW_PCM_DAI_ID_OFFLOAD0, SST_HSW_MODULE_PCM},
+ {HSW_PCM_DAI_ID_OFFLOAD1, SST_HSW_MODULE_PCM},
+ {HSW_PCM_DAI_ID_LOOPBACK, SST_HSW_MODULE_PCM_REFERENCE},
+ {HSW_PCM_DAI_ID_CAPTURE, SST_HSW_MODULE_PCM_CAPTURE},
+};
+
+static int hsw_pcm_create_modules(struct hsw_priv_data *pdata)
+{
+ struct sst_hsw *hsw = pdata->hsw;
+ struct hsw_pcm_data *pcm_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+ pcm_data = &pdata->pcm[i];
+
+ /* create new runtime module, use same offset if recreated */
+ pcm_data->runtime = sst_hsw_runtime_module_create(hsw,
+ mod_map[i].mod_id, pcm_data->persistent_offset);
+ if (pcm_data->runtime == NULL)
+ goto err;
+ pcm_data->persistent_offset =
+ pcm_data->runtime->persistent_offset;
+ }
+
+ return 0;
+
+err:
+ for (--i; i >= 0; i--) {
+ pcm_data = &pdata->pcm[i];
+ sst_hsw_runtime_module_free(pcm_data->runtime);
+ }
+
+ return -ENODEV;
+}
+
+static void hsw_pcm_free_modules(struct hsw_priv_data *pdata)
+{
+ struct hsw_pcm_data *pcm_data;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(mod_map); i++) {
+ pcm_data = &pdata->pcm[i];
+
+ sst_hsw_runtime_module_free(pcm_data->runtime);
+ }
+}
+
static void hsw_pcm_free(struct snd_pcm *pcm)
{
snd_pcm_lib_preallocate_free_for_all(pcm);
@@ -670,6 +745,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
struct snd_pcm *pcm = rtd->pcm;
struct snd_soc_platform *platform = rtd->platform;
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
+ struct hsw_priv_data *priv_data = dev_get_drvdata(platform->dev);
struct device *dev = pdata->dma_dev;
int ret = 0;
@@ -686,6 +762,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
return ret;
}
}
+ priv_data->pcm[rtd->cpu_dai->id].hsw_pcm = pcm;
return ret;
}
@@ -696,6 +773,7 @@ static int hsw_pcm_new(struct snd_soc_pcm_runtime *rtd)
static struct snd_soc_dai_driver hsw_dais[] = {
{
.name = "System Pin",
+ .id = HSW_PCM_DAI_ID_SYSTEM,
.playback = {
.stream_name = "System Playback",
.channels_min = 2,
@@ -703,10 +781,18 @@ static struct snd_soc_dai_driver hsw_dais[] = {
.rates = SNDRV_PCM_RATE_48000,
.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
},
+ .capture = {
+ .stream_name = "Analog Capture",
+ .channels_min = 2,
+ .channels_max = 4,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
+ },
},
{
/* PCM */
.name = "Offload0 Pin",
+ .id = HSW_PCM_DAI_ID_OFFLOAD0,
.playback = {
.stream_name = "Offload0 Playback",
.channels_min = 2,
@@ -718,6 +804,7 @@ static struct snd_soc_dai_driver hsw_dais[] = {
{
/* PCM */
.name = "Offload1 Pin",
+ .id = HSW_PCM_DAI_ID_OFFLOAD1,
.playback = {
.stream_name = "Offload1 Playback",
.channels_min = 2,
@@ -728,6 +815,7 @@ static struct snd_soc_dai_driver hsw_dais[] = {
},
{
.name = "Loopback Pin",
+ .id = HSW_PCM_DAI_ID_LOOPBACK,
.capture = {
.stream_name = "Loopback Capture",
.channels_min = 2,
@@ -736,16 +824,6 @@ static struct snd_soc_dai_driver hsw_dais[] = {
.formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
},
},
- {
- .name = "Capture Pin",
- .capture = {
- .stream_name = "Analog Capture",
- .channels_min = 2,
- .channels_max = 2,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S24_LE | SNDRV_PCM_FMTBIT_S16_LE,
- },
- },
};
static const struct snd_soc_dapm_widget widgets[] = {
@@ -776,9 +854,20 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
{
struct hsw_priv_data *priv_data = snd_soc_platform_get_drvdata(platform);
struct sst_pdata *pdata = dev_get_platdata(platform->dev);
- struct device *dma_dev = pdata->dma_dev;
+ struct device *dma_dev, *dev;
int i, ret = 0;
+ if (!pdata)
+ return -ENODEV;
+
+ dev = platform->dev;
+ dma_dev = pdata->dma_dev;
+
+ priv_data->hsw = pdata->dsp;
+ priv_data->dev = platform->dev;
+ priv_data->pm_state = HSW_PM_STATE_D0;
+ priv_data->soc_card = platform->component.card;
+
/* allocate DSP buffer page tables */
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
@@ -801,6 +890,16 @@ static int hsw_pcm_probe(struct snd_soc_platform *platform)
}
}
+ /* allocate runtime modules */
+ hsw_pcm_create_modules(priv_data);
+
+ /* enable runtime PM with auto suspend */
+ pm_runtime_set_autosuspend_delay(platform->dev,
+ SST_RUNTIME_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(platform->dev);
+ pm_runtime_enable(platform->dev);
+ pm_runtime_idle(platform->dev);
+
return 0;
err:
@@ -819,6 +918,9 @@ static int hsw_pcm_remove(struct snd_soc_platform *platform)
snd_soc_platform_get_drvdata(platform);
int i;
+ pm_runtime_disable(platform->dev);
+ hsw_pcm_free_modules(priv_data);
+
for (i = 0; i < ARRAY_SIZE(hsw_dais); i++) {
if (hsw_dais[i].playback.channels_min)
snd_dma_free_pages(&priv_data->dmab[i][0]);
@@ -896,10 +998,181 @@ static int hsw_pcm_dev_remove(struct platform_device *pdev)
return 0;
}
+#ifdef CONFIG_PM_RUNTIME
+
+static int hsw_pcm_runtime_idle(struct device *dev)
+{
+ return 0;
+}
+
+static int hsw_pcm_runtime_suspend(struct device *dev)
+{
+ struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+ struct sst_hsw *hsw = pdata->hsw;
+
+ if (pdata->pm_state == HSW_PM_STATE_D3)
+ return 0;
+
+ sst_hsw_dsp_runtime_suspend(hsw);
+ sst_hsw_dsp_runtime_sleep(hsw);
+ pdata->pm_state = HSW_PM_STATE_D3;
+
+ return 0;
+}
+
+static int hsw_pcm_runtime_resume(struct device *dev)
+{
+ struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+ struct sst_hsw *hsw = pdata->hsw;
+ int ret;
+
+ if (pdata->pm_state == HSW_PM_STATE_D0)
+ return 0;
+
+ ret = sst_hsw_dsp_load(hsw);
+ if (ret < 0) {
+ dev_err(dev, "failed to reload %d\n", ret);
+ return ret;
+ }
+
+ ret = hsw_pcm_create_modules(pdata);
+ if (ret < 0) {
+ dev_err(dev, "failed to create modules %d\n", ret);
+ return ret;
+ }
+
+ ret = sst_hsw_dsp_runtime_resume(hsw);
+ if (ret < 0)
+ return ret;
+ else if (ret == 1) /* no action required */
+ return 0;
+
+ pdata->pm_state = HSW_PM_STATE_D0;
+ return ret;
+}
+
+#else
+#define hsw_pcm_runtime_idle NULL
+#define hsw_pcm_runtime_suspend NULL
+#define hsw_pcm_runtime_resume NULL
+#endif
+
+#if defined(CONFIG_PM_SLEEP) && defined(CONFIG_PM_RUNTIME)
+
+static void hsw_pcm_complete(struct device *dev)
+{
+ struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+ struct sst_hsw *hsw = pdata->hsw;
+ struct hsw_pcm_data *pcm_data;
+ int i, err;
+
+ if (pdata->pm_state == HSW_PM_STATE_D0)
+ return;
+
+ err = sst_hsw_dsp_load(hsw);
+ if (err < 0) {
+ dev_err(dev, "failed to reload %d\n", err);
+ return;
+ }
+
+ err = hsw_pcm_create_modules(pdata);
+ if (err < 0) {
+ dev_err(dev, "failed to create modules %d\n", err);
+ return;
+ }
+
+ for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
+ pcm_data = &pdata->pcm[i];
+
+ if (!pcm_data->substream)
+ continue;
+
+ err = sst_module_runtime_restore(pcm_data->runtime,
+ &pcm_data->context);
+ if (err < 0)
+ dev_err(dev, "failed to restore context for PCM %d\n", i);
+ }
+
+ snd_soc_resume(pdata->soc_card->dev);
+
+ err = sst_hsw_dsp_runtime_resume(hsw);
+ if (err < 0)
+ return;
+ else if (err == 1) /* no action required */
+ return;
+
+ pdata->pm_state = HSW_PM_STATE_D0;
+ return;
+}
+
+static int hsw_pcm_prepare(struct device *dev)
+{
+ struct hsw_priv_data *pdata = dev_get_drvdata(dev);
+ struct sst_hsw *hsw = pdata->hsw;
+ struct hsw_pcm_data *pcm_data;
+ int i, err;
+
+ if (pdata->pm_state == HSW_PM_STATE_D3)
+ return 0;
+ /* suspend all active streams */
+ for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
+ pcm_data = &pdata->pcm[i];
+
+ if (!pcm_data->substream)
+ continue;
+ dev_dbg(dev, "suspending pcm %d\n", i);
+ snd_pcm_suspend_all(pcm_data->hsw_pcm);
+
+ /* We need to wait until the DSP FW stops the streams */
+ msleep(2);
+ }
+
+ snd_soc_suspend(pdata->soc_card->dev);
+ snd_soc_poweroff(pdata->soc_card->dev);
+
+ /* enter D3 state and stall */
+ sst_hsw_dsp_runtime_suspend(hsw);
+
+ /* preserve persistent memory */
+ for (i = 0; i < HSW_PCM_DAI_ID_CAPTURE + 1; i++) {
+ pcm_data = &pdata->pcm[i];
+
+ if (!pcm_data->substream)
+ continue;
+
+ dev_dbg(dev, "saving context pcm %d\n", i);
+ err = sst_module_runtime_save(pcm_data->runtime,
+ &pcm_data->context);
+ if (err < 0)
+ dev_err(dev, "failed to save context for PCM %d\n", i);
+ }
+
+ /* put the DSP to sleep */
+ sst_hsw_dsp_runtime_sleep(hsw);
+ pdata->pm_state = HSW_PM_STATE_D3;
+
+ return 0;
+}
+
+#else
+#define hsw_pcm_prepare NULL
+#define hsw_pcm_complete NULL
+#endif
+
+static const struct dev_pm_ops hsw_pcm_pm = {
+ .runtime_idle = hsw_pcm_runtime_idle,
+ .runtime_suspend = hsw_pcm_runtime_suspend,
+ .runtime_resume = hsw_pcm_runtime_resume,
+ .prepare = hsw_pcm_prepare,
+ .complete = hsw_pcm_complete,
+};
+
static struct platform_driver hsw_pcm_driver = {
.driver = {
.name = "haswell-pcm-audio",
.owner = THIS_MODULE,
+ .pm = &hsw_pcm_pm,
+
},
.probe = hsw_pcm_dev_probe,
diff --git a/sound/soc/intel/sst-mfld-platform-compress.c b/sound/soc/intel/sst-mfld-platform-compress.c
index 59467775..3951689 100644
--- a/sound/soc/intel/sst-mfld-platform-compress.c
+++ b/sound/soc/intel/sst-mfld-platform-compress.c
@@ -67,8 +67,11 @@ static int sst_platform_compr_open(struct snd_compr_stream *cstream)
goto out_ops;
}
stream->compr_ops = sst->compr_ops;
-
stream->id = 0;
+
+ /* Turn on LPE */
+ sst->compr_ops->power(sst->dev, true);
+
sst_set_stream_status(stream, SST_PLATFORM_INIT);
runtime->private_data = stream;
return 0;
@@ -83,6 +86,9 @@ static int sst_platform_compr_free(struct snd_compr_stream *cstream)
int ret_val = 0, str_id;
stream = cstream->runtime->private_data;
+ /* Turn off LPE */
+ sst->compr_ops->power(sst->dev, false);
+
/*need to check*/
str_id = stream->id;
if (str_id)
diff --git a/sound/soc/intel/sst-mfld-platform-pcm.c b/sound/soc/intel/sst-mfld-platform-pcm.c
index aa9b600..6032f18 100644
--- a/sound/soc/intel/sst-mfld-platform-pcm.c
+++ b/sound/soc/intel/sst-mfld-platform-pcm.c
@@ -101,35 +101,11 @@ static struct sst_dev_stream_map dpcm_strm_map[] = {
{MERR_DPCM_AUDIO, 0, SNDRV_PCM_STREAM_CAPTURE, PIPE_PCM1_OUT, SST_TASK_ID_MEDIA, 0},
};
-/* MFLD - MSIC */
-static struct snd_soc_dai_driver sst_platform_dai[] = {
+static int sst_media_digital_mute(struct snd_soc_dai *dai, int mute, int stream)
{
- .name = "Headset-cpu-dai",
- .id = 0,
- .playback = {
- .channels_min = SST_STEREO,
- .channels_max = SST_STEREO,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S24_LE,
- },
- .capture = {
- .channels_min = 1,
- .channels_max = 5,
- .rates = SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S24_LE,
- },
-},
-{
- .name = "Compress-cpu-dai",
- .compress_dai = 1,
- .playback = {
- .channels_min = SST_STEREO,
- .channels_max = SST_STEREO,
- .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
- .formats = SNDRV_PCM_FMTBIT_S16_LE,
- },
-},
-};
+
+ return sst_send_pipe_gains(dai, stream, mute);
+}
/* helper functions */
void sst_set_stream_status(struct sst_runtime_stream *stream,
@@ -451,12 +427,133 @@ static int sst_media_hw_free(struct snd_pcm_substream *substream,
return snd_pcm_lib_free_pages(substream);
}
+static int sst_enable_ssp(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ int ret = 0;
+
+ if (!dai->active) {
+ ret = sst_handle_vb_timer(dai, true);
+ if (ret)
+ return ret;
+ ret = send_ssp_cmd(dai, dai->name, 1);
+ }
+ return ret;
+}
+
+static void sst_disable_ssp(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ if (!dai->active) {
+ send_ssp_cmd(dai, dai->name, 0);
+ sst_handle_vb_timer(dai, false);
+ }
+}
+
static struct snd_soc_dai_ops sst_media_dai_ops = {
.startup = sst_media_open,
.shutdown = sst_media_close,
.prepare = sst_media_prepare,
.hw_params = sst_media_hw_params,
.hw_free = sst_media_hw_free,
+ .mute_stream = sst_media_digital_mute,
+};
+
+static struct snd_soc_dai_ops sst_compr_dai_ops = {
+ .mute_stream = sst_media_digital_mute,
+};
+
+static struct snd_soc_dai_ops sst_be_dai_ops = {
+ .startup = sst_enable_ssp,
+ .shutdown = sst_disable_ssp,
+};
+
+static struct snd_soc_dai_driver sst_platform_dai[] = {
+{
+ .name = "media-cpu-dai",
+ .ops = &sst_media_dai_ops,
+ .playback = {
+ .stream_name = "Headset Playback",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "Headset Capture",
+ .channels_min = 1,
+ .channels_max = 2,
+ .rates = SNDRV_PCM_RATE_44100|SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "compress-cpu-dai",
+ .compress_dai = 1,
+ .ops = &sst_compr_dai_ops,
+ .playback = {
+ .stream_name = "Compress Playback",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+/* BE CPU Dais */
+{
+ .name = "ssp0-port",
+ .ops = &sst_be_dai_ops,
+ .playback = {
+ .stream_name = "ssp0 Tx",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "ssp0 Rx",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "ssp1-port",
+ .ops = &sst_be_dai_ops,
+ .playback = {
+ .stream_name = "ssp1 Tx",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "ssp1 Rx",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_8000|SNDRV_PCM_RATE_16000|SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
+{
+ .name = "ssp2-port",
+ .ops = &sst_be_dai_ops,
+ .playback = {
+ .stream_name = "ssp2 Tx",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .capture = {
+ .stream_name = "ssp2 Rx",
+ .channels_min = SST_STEREO,
+ .channels_max = SST_STEREO,
+ .rates = SNDRV_PCM_RATE_48000,
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+},
};
static int sst_platform_open(struct snd_pcm_substream *substream)
@@ -609,6 +706,7 @@ static int sst_platform_probe(struct platform_device *pdev)
pdata->pdev_strm_map = dpcm_strm_map;
pdata->strm_map_size = ARRAY_SIZE(dpcm_strm_map);
drv->pdata = pdata;
+ drv->pdev = pdev;
mutex_init(&drv->lock);
dev_set_drvdata(&pdev->dev, drv);
diff --git a/sound/soc/intel/sst-mfld-platform.h b/sound/soc/intel/sst-mfld-platform.h
index 19f83ec..79c8d12 100644
--- a/sound/soc/intel/sst-mfld-platform.h
+++ b/sound/soc/intel/sst-mfld-platform.h
@@ -117,6 +117,7 @@ struct compress_sst_ops {
int (*get_codec_caps)(struct snd_compr_codec_caps *codec);
int (*set_metadata)(struct device *dev, unsigned int str_id,
struct snd_compr_metadata *mdata);
+ int (*power)(struct device *dev, bool state);
};
struct sst_ops {
@@ -153,6 +154,10 @@ struct sst_device {
struct sst_data;
int sst_dsp_init_v2_dpcm(struct snd_soc_platform *platform);
+int sst_send_pipe_gains(struct snd_soc_dai *dai, int stream, int mute);
+int send_ssp_cmd(struct snd_soc_dai *dai, const char *id, bool enable);
+int sst_handle_vb_timer(struct snd_soc_dai *dai, bool enable);
+
void sst_set_stream_status(struct sst_runtime_stream *stream, int state);
int sst_fill_stream_params(void *substream, const struct sst_data *ctx,
struct snd_sst_params *str_params, bool is_compress);
diff --git a/sound/soc/intel/sst/Makefile b/sound/soc/intel/sst/Makefile
new file mode 100644
index 0000000..fd21726
--- /dev/null
+++ b/sound/soc/intel/sst/Makefile
@@ -0,0 +1,7 @@
+snd-intel-sst-core-objs := sst.o sst_ipc.o sst_stream.o sst_drv_interface.o sst_loader.o sst_pvt.o
+snd-intel-sst-pci-objs += sst_pci.o
+snd-intel-sst-acpi-objs += sst_acpi.o
+
+obj-$(CONFIG_SND_SST_IPC) += snd-intel-sst-core.o
+obj-$(CONFIG_SND_SST_IPC_PCI) += snd-intel-sst-pci.o
+obj-$(CONFIG_SND_SST_IPC_ACPI) += snd-intel-sst-acpi.o
diff --git a/sound/soc/intel/sst/sst.c b/sound/soc/intel/sst/sst.c
new file mode 100644
index 0000000..8a8d56a
--- /dev/null
+++ b/sound/soc/intel/sst/sst.c
@@ -0,0 +1,437 @@
+/*
+ * sst.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/async.h>
+#include <linux/acpi.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../sst-dsp.h"
+
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine Driver");
+MODULE_LICENSE("GPL v2");
+
+static inline bool sst_is_process_reply(u32 msg_id)
+{
+ return ((msg_id & PROCESS_MSG) ? true : false);
+}
+
+static inline bool sst_validate_mailbox_size(unsigned int size)
+{
+ return ((size <= SST_MAILBOX_SIZE) ? true : false);
+}
+
+static irqreturn_t intel_sst_interrupt_mrfld(int irq, void *context)
+{
+ union interrupt_reg_mrfld isr;
+ union ipc_header_mrfld header;
+ union sst_imr_reg_mrfld imr;
+ struct ipc_post *msg = NULL;
+ unsigned int size = 0;
+ struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
+ irqreturn_t retval = IRQ_HANDLED;
+
+ /* Interrupt arrived, check src */
+ isr.full = sst_shim_read64(drv->shim, SST_ISRX);
+
+ if (isr.part.done_interrupt) {
+ /* Clear done bit */
+ spin_lock(&drv->ipc_spin_lock);
+ header.full = sst_shim_read64(drv->shim,
+ drv->ipc_reg.ipcx);
+ header.p.header_high.part.done = 0;
+ sst_shim_write64(drv->shim, drv->ipc_reg.ipcx, header.full);
+
+ /* write 1 to clear status register */;
+ isr.part.done_interrupt = 1;
+ sst_shim_write64(drv->shim, SST_ISRX, isr.full);
+ spin_unlock(&drv->ipc_spin_lock);
+
+ /* we can send more messages to DSP so trigger work */
+ queue_work(drv->post_msg_wq, &drv->ipc_post_msg_wq);
+ retval = IRQ_HANDLED;
+ }
+
+ if (isr.part.busy_interrupt) {
+ /* message from dsp so copy that */
+ spin_lock(&drv->ipc_spin_lock);
+ imr.full = sst_shim_read64(drv->shim, SST_IMRX);
+ imr.part.busy_interrupt = 1;
+ sst_shim_write64(drv->shim, SST_IMRX, imr.full);
+ spin_unlock(&drv->ipc_spin_lock);
+ header.full = sst_shim_read64(drv->shim, drv->ipc_reg.ipcd);
+
+ if (sst_create_ipc_msg(&msg, header.p.header_high.part.large)) {
+ drv->ops->clear_interrupt(drv);
+ return IRQ_HANDLED;
+ }
+
+ if (header.p.header_high.part.large) {
+ size = header.p.header_low_payload;
+ if (sst_validate_mailbox_size(size)) {
+ memcpy_fromio(msg->mailbox_data,
+ drv->mailbox + drv->mailbox_recv_offset, size);
+ } else {
+ dev_err(drv->dev,
+ "Mailbox not copied, payload size is: %u\n", size);
+ header.p.header_low_payload = 0;
+ }
+ }
+
+ msg->mrfld_header = header;
+ msg->is_process_reply =
+ sst_is_process_reply(header.p.header_high.part.msg_id);
+ spin_lock(&drv->rx_msg_lock);
+ list_add_tail(&msg->node, &drv->rx_list);
+ spin_unlock(&drv->rx_msg_lock);
+ drv->ops->clear_interrupt(drv);
+ retval = IRQ_WAKE_THREAD;
+ }
+ return retval;
+}
+
+static irqreturn_t intel_sst_irq_thread_mrfld(int irq, void *context)
+{
+ struct intel_sst_drv *drv = (struct intel_sst_drv *) context;
+ struct ipc_post *__msg, *msg = NULL;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
+ if (list_empty(&drv->rx_list)) {
+ spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
+ return IRQ_HANDLED;
+ }
+
+ list_for_each_entry_safe(msg, __msg, &drv->rx_list, node) {
+ list_del(&msg->node);
+ spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
+ if (msg->is_process_reply)
+ drv->ops->process_message(msg);
+ else
+ drv->ops->process_reply(drv, msg);
+
+ if (msg->is_large)
+ kfree(msg->mailbox_data);
+ kfree(msg);
+ spin_lock_irqsave(&drv->rx_msg_lock, irq_flags);
+ }
+ spin_unlock_irqrestore(&drv->rx_msg_lock, irq_flags);
+ return IRQ_HANDLED;
+}
+
+static int sst_save_dsp_context_v2(struct intel_sst_drv *sst)
+{
+ int ret = 0;
+
+ ret = sst_prepare_and_post_msg(sst, SST_TASK_ID_MEDIA, IPC_CMD,
+ IPC_PREP_D3, PIPE_RSVD, 0, NULL, NULL,
+ true, true, false, true);
+
+ if (ret < 0) {
+ dev_err(sst->dev, "not suspending FW!!, Err: %d\n", ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+
+static struct intel_sst_ops mrfld_ops = {
+ .interrupt = intel_sst_interrupt_mrfld,
+ .irq_thread = intel_sst_irq_thread_mrfld,
+ .clear_interrupt = intel_sst_clear_intr_mrfld,
+ .start = sst_start_mrfld,
+ .reset = intel_sst_reset_dsp_mrfld,
+ .post_message = sst_post_message_mrfld,
+ .process_reply = sst_process_reply_mrfld,
+ .save_dsp_context = sst_save_dsp_context_v2,
+ .alloc_stream = sst_alloc_stream_mrfld,
+ .post_download = sst_post_download_mrfld,
+};
+
+int sst_driver_ops(struct intel_sst_drv *sst)
+{
+
+ switch (sst->dev_id) {
+ case SST_MRFLD_PCI_ID:
+ case SST_BYT_ACPI_ID:
+ case SST_CHV_ACPI_ID:
+ sst->tstamp = SST_TIME_STAMP_MRFLD;
+ sst->ops = &mrfld_ops;
+ return 0;
+
+ default:
+ dev_err(sst->dev,
+ "SST Driver capablities missing for dev_id: %x", sst->dev_id);
+ return -EINVAL;
+ };
+}
+
+void sst_process_pending_msg(struct work_struct *work)
+{
+ struct intel_sst_drv *ctx = container_of(work,
+ struct intel_sst_drv, ipc_post_msg_wq);
+
+ ctx->ops->post_message(ctx, NULL, false);
+}
+
+static int sst_workqueue_init(struct intel_sst_drv *ctx)
+{
+ INIT_LIST_HEAD(&ctx->memcpy_list);
+ INIT_LIST_HEAD(&ctx->rx_list);
+ INIT_LIST_HEAD(&ctx->ipc_dispatch_list);
+ INIT_LIST_HEAD(&ctx->block_list);
+ INIT_WORK(&ctx->ipc_post_msg_wq, sst_process_pending_msg);
+ init_waitqueue_head(&ctx->wait_queue);
+
+ ctx->post_msg_wq =
+ create_singlethread_workqueue("sst_post_msg_wq");
+ if (!ctx->post_msg_wq)
+ return -EBUSY;
+ return 0;
+}
+
+static void sst_init_locks(struct intel_sst_drv *ctx)
+{
+ mutex_init(&ctx->sst_lock);
+ spin_lock_init(&ctx->rx_msg_lock);
+ spin_lock_init(&ctx->ipc_spin_lock);
+ spin_lock_init(&ctx->block_lock);
+}
+
+int sst_alloc_drv_context(struct intel_sst_drv **ctx,
+ struct device *dev, unsigned int dev_id)
+{
+ *ctx = devm_kzalloc(dev, sizeof(struct intel_sst_drv), GFP_KERNEL);
+ if (!(*ctx))
+ return -ENOMEM;
+
+ (*ctx)->dev = dev;
+ (*ctx)->dev_id = dev_id;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(sst_alloc_drv_context);
+
+int sst_context_init(struct intel_sst_drv *ctx)
+{
+ int ret = 0, i;
+
+ if (!ctx->pdata)
+ return -EINVAL;
+
+ if (!ctx->pdata->probe_data)
+ return -EINVAL;
+
+ memcpy(&ctx->info, ctx->pdata->probe_data, sizeof(ctx->info));
+
+ ret = sst_driver_ops(ctx);
+ if (ret != 0)
+ return -EINVAL;
+
+ sst_init_locks(ctx);
+ sst_set_fw_state_locked(ctx, SST_RESET);
+
+ /* pvt_id 0 reserved for async messages */
+ ctx->pvt_id = 1;
+ ctx->stream_cnt = 0;
+ ctx->fw_in_mem = NULL;
+ /* we use memcpy, so set to 0 */
+ ctx->use_dma = 0;
+ ctx->use_lli = 0;
+
+ if (sst_workqueue_init(ctx))
+ return -EINVAL;
+
+ ctx->mailbox_recv_offset = ctx->pdata->ipc_info->mbox_recv_off;
+ ctx->ipc_reg.ipcx = SST_IPCX + ctx->pdata->ipc_info->ipc_offset;
+ ctx->ipc_reg.ipcd = SST_IPCD + ctx->pdata->ipc_info->ipc_offset;
+
+ dev_info(ctx->dev, "Got drv data max stream %d\n",
+ ctx->info.max_streams);
+
+ for (i = 1; i <= ctx->info.max_streams; i++) {
+ struct stream_info *stream = &ctx->streams[i];
+
+ memset(stream, 0, sizeof(*stream));
+ stream->pipe_id = PIPE_RSVD;
+ mutex_init(&stream->lock);
+ }
+
+ /* Register the ISR */
+ ret = devm_request_threaded_irq(ctx->dev, ctx->irq_num, ctx->ops->interrupt,
+ ctx->ops->irq_thread, 0, SST_DRV_NAME,
+ ctx);
+ if (ret)
+ goto do_free_mem;
+
+ dev_dbg(ctx->dev, "Registered IRQ %#x\n", ctx->irq_num);
+
+ /* default intr are unmasked so set this as masked */
+ sst_shim_write64(ctx->shim, SST_IMRX, 0xFFFF0038);
+
+ ctx->qos = devm_kzalloc(ctx->dev,
+ sizeof(struct pm_qos_request), GFP_KERNEL);
+ if (!ctx->qos) {
+ ret = -ENOMEM;
+ goto do_free_mem;
+ }
+ pm_qos_add_request(ctx->qos, PM_QOS_CPU_DMA_LATENCY,
+ PM_QOS_DEFAULT_VALUE);
+
+ dev_dbg(ctx->dev, "Requesting FW %s now...\n", ctx->firmware_name);
+ ret = request_firmware_nowait(THIS_MODULE, true, ctx->firmware_name,
+ ctx->dev, GFP_KERNEL, ctx, sst_firmware_load_cb);
+ if (ret) {
+ dev_err(ctx->dev, "Firmware download failed:%d\n", ret);
+ goto do_free_mem;
+ }
+ sst_register(ctx->dev);
+ return 0;
+
+do_free_mem:
+ destroy_workqueue(ctx->post_msg_wq);
+ return ret;
+}
+EXPORT_SYMBOL_GPL(sst_context_init);
+
+void sst_context_cleanup(struct intel_sst_drv *ctx)
+{
+ pm_runtime_get_noresume(ctx->dev);
+ pm_runtime_disable(ctx->dev);
+ sst_unregister(ctx->dev);
+ sst_set_fw_state_locked(ctx, SST_SHUTDOWN);
+ flush_scheduled_work();
+ destroy_workqueue(ctx->post_msg_wq);
+ pm_qos_remove_request(ctx->qos);
+ kfree(ctx->fw_sg_list.src);
+ kfree(ctx->fw_sg_list.dst);
+ ctx->fw_sg_list.list_len = 0;
+ kfree(ctx->fw_in_mem);
+ ctx->fw_in_mem = NULL;
+ sst_memcpy_free_resources(ctx);
+ ctx = NULL;
+}
+EXPORT_SYMBOL_GPL(sst_context_cleanup);
+
+static inline void sst_save_shim64(struct intel_sst_drv *ctx,
+ void __iomem *shim,
+ struct sst_shim_regs64 *shim_regs)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
+
+ shim_regs->imrx = sst_shim_read64(shim, SST_IMRX),
+
+ spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
+}
+
+static inline void sst_restore_shim64(struct intel_sst_drv *ctx,
+ void __iomem *shim,
+ struct sst_shim_regs64 *shim_regs)
+{
+ unsigned long irq_flags;
+
+ /*
+ * we only need to restore IMRX for this case, rest will be
+ * initialize by FW or driver when firmware is loaded
+ */
+ spin_lock_irqsave(&ctx->ipc_spin_lock, irq_flags);
+ sst_shim_write64(shim, SST_IMRX, shim_regs->imrx),
+ spin_unlock_irqrestore(&ctx->ipc_spin_lock, irq_flags);
+}
+
+void sst_configure_runtime_pm(struct intel_sst_drv *ctx)
+{
+ pm_runtime_set_autosuspend_delay(ctx->dev, SST_SUSPEND_DELAY);
+ pm_runtime_use_autosuspend(ctx->dev);
+ /*
+ * For acpi devices, the actual physical device state is
+ * initially active. So change the state to active before
+ * enabling the pm
+ */
+ pm_runtime_enable(ctx->dev);
+
+ if (acpi_disabled)
+ pm_runtime_set_active(ctx->dev);
+ else
+ pm_runtime_put_noidle(ctx->dev);
+
+ sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
+}
+EXPORT_SYMBOL_GPL(sst_configure_runtime_pm);
+
+static int intel_sst_runtime_suspend(struct device *dev)
+{
+ int ret = 0;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (ctx->sst_state == SST_RESET) {
+ dev_dbg(dev, "LPE is already in RESET state, No action\n");
+ return 0;
+ }
+ /* save fw context */
+ if (ctx->ops->save_dsp_context(ctx))
+ return -EBUSY;
+
+ /* Move the SST state to Reset */
+ sst_set_fw_state_locked(ctx, SST_RESET);
+
+ synchronize_irq(ctx->irq_num);
+ flush_workqueue(ctx->post_msg_wq);
+
+ /* save the shim registers because PMC doesn't save state */
+ sst_save_shim64(ctx, ctx->shim, ctx->shim_regs64);
+
+ return ret;
+}
+
+static int intel_sst_runtime_resume(struct device *dev)
+{
+ int ret = 0;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (ctx->sst_state == SST_RESET) {
+ ret = sst_load_fw(ctx);
+ if (ret) {
+ dev_err(dev, "FW download fail %d\n", ret);
+ sst_set_fw_state_locked(ctx, SST_RESET);
+ }
+ }
+ return ret;
+}
+
+const struct dev_pm_ops intel_sst_pm = {
+ .runtime_suspend = intel_sst_runtime_suspend,
+ .runtime_resume = intel_sst_runtime_resume,
+};
+EXPORT_SYMBOL_GPL(intel_sst_pm);
diff --git a/sound/soc/intel/sst/sst.h b/sound/soc/intel/sst/sst.h
new file mode 100644
index 0000000..7f4bbfc
--- /dev/null
+++ b/sound/soc/intel/sst/sst.h
@@ -0,0 +1,546 @@
+/*
+ * sst.h - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * Common private declarations for SST
+ */
+#ifndef __SST_H__
+#define __SST_H__
+
+#include <linux/firmware.h>
+
+/* driver names */
+#define SST_DRV_NAME "intel_sst_driver"
+#define SST_MRFLD_PCI_ID 0x119A
+#define SST_BYT_ACPI_ID 0x80860F28
+#define SST_CHV_ACPI_ID 0x808622A8
+
+#define SST_SUSPEND_DELAY 2000
+#define FW_CONTEXT_MEM (64*1024)
+#define SST_ICCM_BOUNDARY 4
+#define SST_CONFIG_SSP_SIGN 0x7ffe8001
+
+#define MRFLD_FW_VIRTUAL_BASE 0xC0000000
+#define MRFLD_FW_DDR_BASE_OFFSET 0x0
+#define MRFLD_FW_FEATURE_BASE_OFFSET 0x4
+#define MRFLD_FW_BSS_RESET_BIT 0
+
+extern const struct dev_pm_ops intel_sst_pm;
+enum sst_states {
+ SST_FW_LOADING = 1,
+ SST_FW_RUNNING,
+ SST_RESET,
+ SST_SHUTDOWN,
+};
+
+enum sst_algo_ops {
+ SST_SET_ALGO = 0,
+ SST_GET_ALGO = 1,
+};
+
+#define SST_BLOCK_TIMEOUT 1000
+
+#define FW_SIGNATURE_SIZE 4
+
+/* stream states */
+enum sst_stream_states {
+ STREAM_UN_INIT = 0, /* Freed/Not used stream */
+ STREAM_RUNNING = 1, /* Running */
+ STREAM_PAUSED = 2, /* Paused stream */
+ STREAM_DECODE = 3, /* stream is in decoding only state */
+ STREAM_INIT = 4, /* stream init, waiting for data */
+ STREAM_RESET = 5, /* force reset on recovery */
+};
+
+enum sst_ram_type {
+ SST_IRAM = 1,
+ SST_DRAM = 2,
+ SST_DDR = 5,
+ SST_CUSTOM_INFO = 7, /* consists of FW binary information */
+};
+
+/* SST shim registers to structure mapping */
+union interrupt_reg {
+ struct {
+ u64 done_interrupt:1;
+ u64 busy_interrupt:1;
+ u64 rsvd:62;
+ } part;
+ u64 full;
+};
+
+union sst_pisr_reg {
+ struct {
+ u32 pssp0:1;
+ u32 pssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:26;
+ } part;
+ u32 full;
+};
+
+union sst_pimr_reg {
+ struct {
+ u32 ssp0:1;
+ u32 ssp1:1;
+ u32 rsvd0:3;
+ u32 dmac:1;
+ u32 rsvd1:10;
+ u32 ssp0_sc:1;
+ u32 ssp1_sc:1;
+ u32 rsvd2:3;
+ u32 dmac_sc:1;
+ u32 rsvd3:10;
+ } part;
+ u32 full;
+};
+
+union config_status_reg_mrfld {
+ struct {
+ u64 lpe_reset:1;
+ u64 lpe_reset_vector:1;
+ u64 runstall:1;
+ u64 pwaitmode:1;
+ u64 clk_sel:3;
+ u64 rsvd2:1;
+ u64 sst_clk:3;
+ u64 xt_snoop:1;
+ u64 rsvd3:4;
+ u64 clk_sel1:6;
+ u64 clk_enable:3;
+ u64 rsvd4:6;
+ u64 slim0baseclk:1;
+ u64 rsvd:32;
+ } part;
+ u64 full;
+};
+
+union interrupt_reg_mrfld {
+ struct {
+ u64 done_interrupt:1;
+ u64 busy_interrupt:1;
+ u64 rsvd:62;
+ } part;
+ u64 full;
+};
+
+union sst_imr_reg_mrfld {
+ struct {
+ u64 done_interrupt:1;
+ u64 busy_interrupt:1;
+ u64 rsvd:62;
+ } part;
+ u64 full;
+};
+
+/**
+ * struct sst_block - This structure is used to block a user/fw data call to another
+ * fw/user call
+ *
+ * @condition: condition for blocking check
+ * @ret_code: ret code when block is released
+ * @data: data ptr
+ * @size: size of data
+ * @on: block condition
+ * @msg_id: msg_id = msgid in mfld/ctp, mrfld = NULL
+ * @drv_id: str_id in mfld/ctp, = drv_id in mrfld
+ * @node: list head node
+ */
+struct sst_block {
+ bool condition;
+ int ret_code;
+ void *data;
+ u32 size;
+ bool on;
+ u32 msg_id;
+ u32 drv_id;
+ struct list_head node;
+};
+
+/**
+ * struct stream_info - structure that holds the stream information
+ *
+ * @status : stream current state
+ * @prev : stream prev state
+ * @ops : stream operation pb/cp/drm...
+ * @bufs: stream buffer list
+ * @lock : stream mutex for protecting state
+ * @pcm_substream : PCM substream
+ * @period_elapsed : PCM period elapsed callback
+ * @sfreq : stream sampling freq
+ * @str_type : stream type
+ * @cumm_bytes : cummulative bytes decoded
+ * @str_type : stream type
+ * @src : stream source
+ */
+struct stream_info {
+ unsigned int status;
+ unsigned int prev;
+ unsigned int ops;
+ struct mutex lock;
+
+ void *pcm_substream;
+ void (*period_elapsed)(void *pcm_substream);
+
+ unsigned int sfreq;
+ u32 cumm_bytes;
+
+ void *compr_cb_param;
+ void (*compr_cb)(void *compr_cb_param);
+
+ void *drain_cb_param;
+ void (*drain_notify)(void *drain_cb_param);
+
+ unsigned int num_ch;
+ unsigned int pipe_id;
+ unsigned int str_id;
+ unsigned int task_id;
+};
+
+#define SST_FW_SIGN "$SST"
+#define SST_FW_LIB_SIGN "$LIB"
+
+/**
+ * struct sst_fw_header - FW file headers
+ *
+ * @signature : FW signature
+ * @file_size: size of fw image
+ * @modules : # of modules
+ * @file_format : version of header format
+ * @reserved : reserved fields
+ */
+struct sst_fw_header {
+ unsigned char signature[FW_SIGNATURE_SIZE];
+ u32 file_size;
+ u32 modules;
+ u32 file_format;
+ u32 reserved[4];
+};
+
+/**
+ * struct fw_module_header - module header in FW
+ *
+ * @signature: module signature
+ * @mod_size: size of module
+ * @blocks: block count
+ * @type: block type
+ * @entry_point: module netry point
+ */
+struct fw_module_header {
+ unsigned char signature[FW_SIGNATURE_SIZE];
+ u32 mod_size;
+ u32 blocks;
+ u32 type;
+ u32 entry_point;
+};
+
+/**
+ * struct fw_block_info - block header for FW
+ *
+ * @type: block ram type I/D
+ * @size: size of block
+ * @ram_offset: offset in ram
+ */
+struct fw_block_info {
+ enum sst_ram_type type;
+ u32 size;
+ u32 ram_offset;
+ u32 rsvd;
+};
+
+struct sst_runtime_param {
+ struct snd_sst_runtime_params param;
+};
+
+struct sst_sg_list {
+ struct scatterlist *src;
+ struct scatterlist *dst;
+ int list_len;
+ unsigned int sg_idx;
+};
+
+struct sst_memcpy_list {
+ struct list_head memcpylist;
+ void *dstn;
+ const void *src;
+ u32 size;
+ bool is_io;
+};
+
+/*Firmware Module Information*/
+enum sst_lib_dwnld_status {
+ SST_LIB_NOT_FOUND = 0,
+ SST_LIB_FOUND,
+ SST_LIB_DOWNLOADED,
+};
+
+struct sst_module_info {
+ const char *name; /*Library name*/
+ u32 id; /*Module ID*/
+ u32 entry_pt; /*Module entry point*/
+ u8 status; /*module status*/
+ u8 rsvd1;
+ u16 rsvd2;
+};
+
+/*
+ * Structure for managing the Library Region(1.5MB)
+ * in DDR in Merrifield
+ */
+struct sst_mem_mgr {
+ phys_addr_t current_base;
+ int avail;
+ unsigned int count;
+};
+
+struct sst_ipc_reg {
+ int ipcx;
+ int ipcd;
+};
+
+struct sst_shim_regs64 {
+ u64 csr;
+ u64 pisr;
+ u64 pimr;
+ u64 isrx;
+ u64 isrd;
+ u64 imrx;
+ u64 imrd;
+ u64 ipcx;
+ u64 ipcd;
+ u64 isrsc;
+ u64 isrlpesc;
+ u64 imrsc;
+ u64 imrlpesc;
+ u64 ipcsc;
+ u64 ipclpesc;
+ u64 clkctl;
+ u64 csr2;
+};
+
+/**
+ * struct intel_sst_drv - driver ops
+ *
+ * @sst_state : current sst device state
+ * @dev_id : device identifier, pci_id for pci devices and acpi_id for acpi
+ * devices
+ * @shim : SST shim pointer
+ * @mailbox : SST mailbox pointer
+ * @iram : SST IRAM pointer
+ * @dram : SST DRAM pointer
+ * @pdata : SST info passed as a part of pci platform data
+ * @shim_phy_add : SST shim phy addr
+ * @shim_regs64: Struct to save shim registers
+ * @ipc_dispatch_list : ipc messages dispatched
+ * @rx_list : to copy the process_reply/process_msg from DSP
+ * @ipc_post_msg_wq : wq to post IPC messages context
+ * @mad_ops : MAD driver operations registered
+ * @mad_wq : MAD driver wq
+ * @post_msg_wq : wq to post IPC messages
+ * @streams : sst stream contexts
+ * @list_lock : sst driver list lock (deprecated)
+ * @ipc_spin_lock : spin lock to handle audio shim access and ipc queue
+ * @block_lock : spin lock to add block to block_list and assign pvt_id
+ * @rx_msg_lock : spin lock to handle the rx messages from the DSP
+ * @scard_ops : sst card ops
+ * @pci : sst pci device struture
+ * @dev : pointer to current device struct
+ * @sst_lock : sst device lock
+ * @pvt_id : sst private id
+ * @stream_cnt : total sst active stream count
+ * @pb_streams : total active pb streams
+ * @cp_streams : total active cp streams
+ * @audio_start : audio status
+ * @qos : PM Qos struct
+ * firmware_name : Firmware / Library name
+ */
+struct intel_sst_drv {
+ int sst_state;
+ int irq_num;
+ unsigned int dev_id;
+ void __iomem *ddr;
+ void __iomem *shim;
+ void __iomem *mailbox;
+ void __iomem *iram;
+ void __iomem *dram;
+ unsigned int mailbox_add;
+ unsigned int iram_base;
+ unsigned int dram_base;
+ unsigned int shim_phy_add;
+ unsigned int iram_end;
+ unsigned int dram_end;
+ unsigned int ddr_end;
+ unsigned int ddr_base;
+ unsigned int mailbox_recv_offset;
+ struct sst_shim_regs64 *shim_regs64;
+ struct list_head block_list;
+ struct list_head ipc_dispatch_list;
+ struct sst_platform_info *pdata;
+ struct list_head rx_list;
+ struct work_struct ipc_post_msg_wq;
+ wait_queue_head_t wait_queue;
+ struct workqueue_struct *post_msg_wq;
+ unsigned int tstamp;
+ /* str_id 0 is not used */
+ struct stream_info streams[MAX_NUM_STREAMS+1];
+ spinlock_t ipc_spin_lock;
+ spinlock_t block_lock;
+ spinlock_t rx_msg_lock;
+ struct pci_dev *pci;
+ struct device *dev;
+ volatile long unsigned pvt_id;
+ struct mutex sst_lock;
+ unsigned int stream_cnt;
+ unsigned int csr_value;
+ void *fw_in_mem;
+ struct sst_sg_list fw_sg_list, library_list;
+ struct intel_sst_ops *ops;
+ struct sst_info info;
+ struct pm_qos_request *qos;
+ unsigned int use_dma;
+ unsigned int use_lli;
+ atomic_t fw_clear_context;
+ bool lib_dwnld_reqd;
+ struct list_head memcpy_list;
+ struct sst_ipc_reg ipc_reg;
+ struct sst_mem_mgr lib_mem_mgr;
+ /*
+ * Holder for firmware name. Due to async call it needs to be
+ * persistent till worker thread gets called
+ */
+ char firmware_name[20];
+};
+
+/* misc definitions */
+#define FW_DWNL_ID 0x01
+
+struct intel_sst_ops {
+ irqreturn_t (*interrupt)(int, void *);
+ irqreturn_t (*irq_thread)(int, void *);
+ void (*clear_interrupt)(struct intel_sst_drv *ctx);
+ int (*start)(struct intel_sst_drv *ctx);
+ int (*reset)(struct intel_sst_drv *ctx);
+ void (*process_reply)(struct intel_sst_drv *ctx, struct ipc_post *msg);
+ int (*post_message)(struct intel_sst_drv *ctx,
+ struct ipc_post *msg, bool sync);
+ void (*process_message)(struct ipc_post *msg);
+ void (*set_bypass)(bool set);
+ int (*save_dsp_context)(struct intel_sst_drv *sst);
+ void (*restore_dsp_context)(void);
+ int (*alloc_stream)(struct intel_sst_drv *ctx, void *params);
+ void (*post_download)(struct intel_sst_drv *sst);
+};
+
+int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int id);
+int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id);
+int sst_send_byte_stream_mrfld(struct intel_sst_drv *ctx,
+ struct snd_sst_bytes_v2 *sbytes);
+int sst_set_stream_param(int str_id, struct snd_sst_params *str_param);
+int sst_set_metadata(int str_id, char *params);
+int sst_get_stream(struct intel_sst_drv *sst_drv_ctx,
+ struct snd_sst_params *str_param);
+int sst_get_stream_allocated(struct intel_sst_drv *ctx,
+ struct snd_sst_params *str_param,
+ struct snd_sst_lib_download **lib_dnld);
+int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
+ int str_id, bool partial_drain);
+int sst_post_message_mrfld(struct intel_sst_drv *ctx,
+ struct ipc_post *msg, bool sync);
+void sst_process_reply_mrfld(struct intel_sst_drv *ctx, struct ipc_post *msg);
+int sst_start_mrfld(struct intel_sst_drv *ctx);
+int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *ctx);
+void intel_sst_clear_intr_mrfld(struct intel_sst_drv *ctx);
+
+int sst_load_fw(struct intel_sst_drv *ctx);
+int sst_load_library(struct snd_sst_lib_download *lib, u8 ops);
+void sst_post_download_mrfld(struct intel_sst_drv *ctx);
+int sst_get_block_stream(struct intel_sst_drv *sst_drv_ctx);
+void sst_memcpy_free_resources(struct intel_sst_drv *ctx);
+
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block);
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block);
+int sst_create_ipc_msg(struct ipc_post **arg, bool large);
+int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id);
+void sst_clean_stream(struct stream_info *stream);
+int intel_sst_register_compress(struct intel_sst_drv *sst);
+int intel_sst_remove_compress(struct intel_sst_drv *sst);
+void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id);
+int sst_send_sync_msg(int ipc, int str_id);
+int sst_get_num_channel(struct snd_sst_params *str_param);
+int sst_get_sfreq(struct snd_sst_params *str_param);
+int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params);
+void sst_restore_fw_context(void);
+struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
+ u32 msg_id, u32 drv_id);
+int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large,
+ struct intel_sst_drv *sst_drv_ctx, struct sst_block **block,
+ u32 msg_id, u32 drv_id);
+int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed);
+int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
+ u32 drv_id, u32 ipc, void *data, u32 size);
+int sst_request_firmware_async(struct intel_sst_drv *ctx);
+int sst_driver_ops(struct intel_sst_drv *sst);
+struct sst_platform_info *sst_get_acpi_driver_data(const char *hid);
+void sst_firmware_load_cb(const struct firmware *fw, void *context);
+int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
+ int task_id, int ipc_msg, int cmd_id, int pipe_id,
+ size_t mbox_data_len, const void *mbox_data, void **data,
+ bool large, bool fill_dsp, bool sync, bool response);
+
+void sst_process_pending_msg(struct work_struct *work);
+int sst_assign_pvt_id(struct intel_sst_drv *sst_drv_ctx);
+void sst_init_stream(struct stream_info *stream,
+ int codec, int sst_id, int ops, u8 slot);
+int sst_validate_strid(struct intel_sst_drv *sst_drv_ctx, int str_id);
+struct stream_info *get_stream_info(struct intel_sst_drv *sst_drv_ctx,
+ int str_id);
+int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx,
+ u32 pipe_id);
+u32 relocate_imr_addr_mrfld(u32 base_addr);
+void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst,
+ struct ipc_post *msg);
+int sst_pm_runtime_put(struct intel_sst_drv *sst_drv);
+int sst_shim_write(void __iomem *addr, int offset, int value);
+u32 sst_shim_read(void __iomem *addr, int offset);
+u64 sst_reg_read64(void __iomem *addr, int offset);
+int sst_shim_write64(void __iomem *addr, int offset, u64 value);
+u64 sst_shim_read64(void __iomem *addr, int offset);
+void sst_set_fw_state_locked(
+ struct intel_sst_drv *sst_drv_ctx, int sst_state);
+void sst_fill_header_mrfld(union ipc_header_mrfld *header,
+ int msg, int task_id, int large, int drv_id);
+void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg,
+ int pipe_id, int len);
+
+int sst_register(struct device *);
+int sst_unregister(struct device *);
+
+int sst_alloc_drv_context(struct intel_sst_drv **ctx,
+ struct device *dev, unsigned int dev_id);
+int sst_context_init(struct intel_sst_drv *ctx);
+void sst_context_cleanup(struct intel_sst_drv *ctx);
+void sst_configure_runtime_pm(struct intel_sst_drv *ctx);
+#endif
diff --git a/sound/soc/intel/sst/sst_acpi.c b/sound/soc/intel/sst/sst_acpi.c
new file mode 100644
index 0000000..31124aa
--- /dev/null
+++ b/sound/soc/intel/sst/sst_acpi.c
@@ -0,0 +1,383 @@
+/*
+ * sst_acpi.c - SST (LPE) driver init file for ACPI enumeration.
+ *
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * Authors: Ramesh Babu K V <Ramesh.Babu@intel.com>
+ * Authors: Omair Mohammed Abdullah <omair.m.abdullah@intel.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/slab.h>
+#include <linux/io.h>
+#include <linux/miscdevice.h>
+#include <linux/platform_device.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/acpi.h>
+#include <asm/platform_sst_audio.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <acpi/acbuffer.h>
+#include <acpi/platform/acenv.h>
+#include <acpi/platform/aclinux.h>
+#include <acpi/actypes.h>
+#include <acpi/acpi_bus.h>
+#include "../sst-mfld-platform.h"
+#include "../sst-dsp.h"
+#include "sst.h"
+
+struct sst_machines {
+ char codec_id[32];
+ char board[32];
+ char machine[32];
+ void (*machine_quirk)(void);
+ char firmware[32];
+ struct sst_platform_info *pdata;
+
+};
+
+/* LPE viewpoint addresses */
+#define SST_BYT_IRAM_PHY_START 0xff2c0000
+#define SST_BYT_IRAM_PHY_END 0xff2d4000
+#define SST_BYT_DRAM_PHY_START 0xff300000
+#define SST_BYT_DRAM_PHY_END 0xff320000
+#define SST_BYT_IMR_VIRT_START 0xc0000000 /* virtual addr in LPE */
+#define SST_BYT_IMR_VIRT_END 0xc01fffff
+#define SST_BYT_SHIM_PHY_ADDR 0xff340000
+#define SST_BYT_MBOX_PHY_ADDR 0xff344000
+#define SST_BYT_DMA0_PHY_ADDR 0xff298000
+#define SST_BYT_DMA1_PHY_ADDR 0xff29c000
+#define SST_BYT_SSP0_PHY_ADDR 0xff2a0000
+#define SST_BYT_SSP2_PHY_ADDR 0xff2a2000
+
+#define BYT_FW_MOD_TABLE_OFFSET 0x80000
+#define BYT_FW_MOD_TABLE_SIZE 0x100
+#define BYT_FW_MOD_OFFSET (BYT_FW_MOD_TABLE_OFFSET + BYT_FW_MOD_TABLE_SIZE)
+
+static const struct sst_info byt_fwparse_info = {
+ .use_elf = false,
+ .max_streams = 25,
+ .iram_start = SST_BYT_IRAM_PHY_START,
+ .iram_end = SST_BYT_IRAM_PHY_END,
+ .iram_use = true,
+ .dram_start = SST_BYT_DRAM_PHY_START,
+ .dram_end = SST_BYT_DRAM_PHY_END,
+ .dram_use = true,
+ .imr_start = SST_BYT_IMR_VIRT_START,
+ .imr_end = SST_BYT_IMR_VIRT_END,
+ .imr_use = true,
+ .mailbox_start = SST_BYT_MBOX_PHY_ADDR,
+ .num_probes = 0,
+ .lpe_viewpt_rqd = true,
+};
+
+static const struct sst_ipc_info byt_ipc_info = {
+ .ipc_offset = 0,
+ .mbox_recv_off = 0x400,
+};
+
+static const struct sst_lib_dnld_info byt_lib_dnld_info = {
+ .mod_base = SST_BYT_IMR_VIRT_START,
+ .mod_end = SST_BYT_IMR_VIRT_END,
+ .mod_table_offset = BYT_FW_MOD_TABLE_OFFSET,
+ .mod_table_size = BYT_FW_MOD_TABLE_SIZE,
+ .mod_ddr_dnld = false,
+};
+
+static const struct sst_res_info byt_rvp_res_info = {
+ .shim_offset = 0x140000,
+ .shim_size = 0x000100,
+ .shim_phy_addr = SST_BYT_SHIM_PHY_ADDR,
+ .ssp0_offset = 0xa0000,
+ .ssp0_size = 0x1000,
+ .dma0_offset = 0x98000,
+ .dma0_size = 0x4000,
+ .dma1_offset = 0x9c000,
+ .dma1_size = 0x4000,
+ .iram_offset = 0x0c0000,
+ .iram_size = 0x14000,
+ .dram_offset = 0x100000,
+ .dram_size = 0x28000,
+ .mbox_offset = 0x144000,
+ .mbox_size = 0x1000,
+ .acpi_lpe_res_index = 0,
+ .acpi_ddr_index = 2,
+ .acpi_ipc_irq_index = 5,
+};
+
+static struct sst_platform_info byt_rvp_platform_data = {
+ .probe_data = &byt_fwparse_info,
+ .ipc_info = &byt_ipc_info,
+ .lib_info = &byt_lib_dnld_info,
+ .res_info = &byt_rvp_res_info,
+ .platform = "sst-mfld-platform",
+};
+
+/* Cherryview (Cherrytrail and Braswell) uses same mrfld dpcm fw as Baytrail,
+ * so pdata is same as Baytrail.
+ */
+static struct sst_platform_info chv_platform_data = {
+ .probe_data = &byt_fwparse_info,
+ .ipc_info = &byt_ipc_info,
+ .lib_info = &byt_lib_dnld_info,
+ .res_info = &byt_rvp_res_info,
+ .platform = "sst-mfld-platform",
+};
+
+static int sst_platform_get_resources(struct intel_sst_drv *ctx)
+{
+ struct resource *rsrc;
+ struct platform_device *pdev = to_platform_device(ctx->dev);
+
+ /* All ACPI resource request here */
+ /* Get Shim addr */
+ rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
+ ctx->pdata->res_info->acpi_lpe_res_index);
+ if (!rsrc) {
+ dev_err(ctx->dev, "Invalid SHIM base from IFWI");
+ return -EIO;
+ }
+ dev_info(ctx->dev, "LPE base: %#x size:%#x", (unsigned int) rsrc->start,
+ (unsigned int)resource_size(rsrc));
+
+ ctx->iram_base = rsrc->start + ctx->pdata->res_info->iram_offset;
+ ctx->iram_end = ctx->iram_base + ctx->pdata->res_info->iram_size - 1;
+ dev_info(ctx->dev, "IRAM base: %#x", ctx->iram_base);
+ ctx->iram = devm_ioremap_nocache(ctx->dev, ctx->iram_base,
+ ctx->pdata->res_info->iram_size);
+ if (!ctx->iram) {
+ dev_err(ctx->dev, "unable to map IRAM");
+ return -EIO;
+ }
+
+ ctx->dram_base = rsrc->start + ctx->pdata->res_info->dram_offset;
+ ctx->dram_end = ctx->dram_base + ctx->pdata->res_info->dram_size - 1;
+ dev_info(ctx->dev, "DRAM base: %#x", ctx->dram_base);
+ ctx->dram = devm_ioremap_nocache(ctx->dev, ctx->dram_base,
+ ctx->pdata->res_info->dram_size);
+ if (!ctx->dram) {
+ dev_err(ctx->dev, "unable to map DRAM");
+ return -EIO;
+ }
+
+ ctx->shim_phy_add = rsrc->start + ctx->pdata->res_info->shim_offset;
+ dev_info(ctx->dev, "SHIM base: %#x", ctx->shim_phy_add);
+ ctx->shim = devm_ioremap_nocache(ctx->dev, ctx->shim_phy_add,
+ ctx->pdata->res_info->shim_size);
+ if (!ctx->shim) {
+ dev_err(ctx->dev, "unable to map SHIM");
+ return -EIO;
+ }
+
+ /* reassign physical address to LPE viewpoint address */
+ ctx->shim_phy_add = ctx->pdata->res_info->shim_phy_addr;
+
+ /* Get mailbox addr */
+ ctx->mailbox_add = rsrc->start + ctx->pdata->res_info->mbox_offset;
+ dev_info(ctx->dev, "Mailbox base: %#x", ctx->mailbox_add);
+ ctx->mailbox = devm_ioremap_nocache(ctx->dev, ctx->mailbox_add,
+ ctx->pdata->res_info->mbox_size);
+ if (!ctx->mailbox) {
+ dev_err(ctx->dev, "unable to map mailbox");
+ return -EIO;
+ }
+
+ /* reassign physical address to LPE viewpoint address */
+ ctx->mailbox_add = ctx->info.mailbox_start;
+
+ rsrc = platform_get_resource(pdev, IORESOURCE_MEM,
+ ctx->pdata->res_info->acpi_ddr_index);
+ if (!rsrc) {
+ dev_err(ctx->dev, "Invalid DDR base from IFWI");
+ return -EIO;
+ }
+ ctx->ddr_base = rsrc->start;
+ ctx->ddr_end = rsrc->end;
+ dev_info(ctx->dev, "DDR base: %#x", ctx->ddr_base);
+ ctx->ddr = devm_ioremap_nocache(ctx->dev, ctx->ddr_base,
+ resource_size(rsrc));
+ if (!ctx->ddr) {
+ dev_err(ctx->dev, "unable to map DDR");
+ return -EIO;
+ }
+
+ /* Find the IRQ */
+ ctx->irq_num = platform_get_irq(pdev,
+ ctx->pdata->res_info->acpi_ipc_irq_index);
+ return 0;
+}
+
+static acpi_status sst_acpi_mach_match(acpi_handle handle, u32 level,
+ void *context, void **ret)
+{
+ *(bool *)context = true;
+ return AE_OK;
+}
+
+static struct sst_machines *sst_acpi_find_machine(
+ struct sst_machines *machines)
+{
+ struct sst_machines *mach;
+ bool found = false;
+
+ for (mach = machines; mach->codec_id; mach++)
+ if (ACPI_SUCCESS(acpi_get_devices(mach->codec_id,
+ sst_acpi_mach_match,
+ &found, NULL)) && found)
+ return mach;
+
+ return NULL;
+}
+
+int sst_acpi_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ int ret = 0;
+ struct intel_sst_drv *ctx;
+ const struct acpi_device_id *id;
+ struct sst_machines *mach;
+ struct platform_device *mdev;
+ struct platform_device *plat_dev;
+ unsigned int dev_id;
+
+ id = acpi_match_device(dev->driver->acpi_match_table, dev);
+ if (!id)
+ return -ENODEV;
+ dev_dbg(dev, "for %s", id->id);
+
+ mach = (struct sst_machines *)id->driver_data;
+ mach = sst_acpi_find_machine(mach);
+ if (mach == NULL) {
+ dev_err(dev, "No matching machine driver found\n");
+ return -ENODEV;
+ }
+
+ ret = kstrtouint(id->id, 16, &dev_id);
+ if (ret < 0) {
+ dev_err(dev, "Unique device id conversion error: %d\n", ret);
+ return ret;
+ }
+
+ dev_dbg(dev, "ACPI device id: %x\n", dev_id);
+
+ plat_dev = platform_device_register_data(dev, mach->pdata->platform, -1, NULL, 0);
+ if (plat_dev == NULL) {
+ dev_err(dev, "Failed to create machine device: %s\n", mach->pdata->platform);
+ return -ENODEV;
+ }
+
+ /* Create platform device for sst machine driver */
+ mdev = platform_device_register_data(dev, mach->machine, -1, NULL, 0);
+ if (mdev == NULL) {
+ dev_err(dev, "Failed to create machine device: %s\n", mach->machine);
+ return -ENODEV;
+ }
+
+ ret = sst_alloc_drv_context(&ctx, dev, dev_id);
+ if (ret < 0)
+ return ret;
+
+ /* Fill sst platform data */
+ ctx->pdata = mach->pdata;
+ strcpy(ctx->firmware_name, mach->firmware);
+
+ ret = sst_platform_get_resources(ctx);
+ if (ret)
+ return ret;
+
+ ret = sst_context_init(ctx);
+ if (ret < 0)
+ return ret;
+
+ /* need to save shim registers in BYT */
+ ctx->shim_regs64 = devm_kzalloc(ctx->dev, sizeof(*ctx->shim_regs64),
+ GFP_KERNEL);
+ if (!ctx->shim_regs64) {
+ return -ENOMEM;
+ goto do_sst_cleanup;
+ }
+
+ sst_configure_runtime_pm(ctx);
+ platform_set_drvdata(pdev, ctx);
+ return ret;
+
+do_sst_cleanup:
+ sst_context_cleanup(ctx);
+ platform_set_drvdata(pdev, NULL);
+ dev_err(ctx->dev, "failed with %d\n", ret);
+ return ret;
+}
+
+/**
+* intel_sst_remove - remove function
+*
+* @pdev: platform device structure
+*
+* This function is called by OS when a device is unloaded
+* This frees the interrupt etc
+*/
+int sst_acpi_remove(struct platform_device *pdev)
+{
+ struct intel_sst_drv *ctx;
+
+ ctx = platform_get_drvdata(pdev);
+ sst_context_cleanup(ctx);
+ platform_set_drvdata(pdev, NULL);
+ return 0;
+}
+
+static struct sst_machines sst_acpi_bytcr[] = {
+ {"10EC5640", "T100", "bytt100_rt5640", NULL, "fw_sst_0f28.bin",
+ &byt_rvp_platform_data },
+ {},
+};
+
+/* Cherryview-based platforms: CherryTrail and Braswell */
+static struct sst_machines sst_acpi_chv[] = {
+ {"10EC5670", "cht-bsw", "cht-bsw-rt5672", NULL, "fw_sst_22a8.bin",
+ &chv_platform_data },
+ {},
+};
+
+static const struct acpi_device_id sst_acpi_ids[] = {
+ { "80860F28", (unsigned long)&sst_acpi_bytcr},
+ { "808622A8", (unsigned long) &sst_acpi_chv},
+ { },
+};
+
+MODULE_DEVICE_TABLE(acpi, sst_acpi_ids);
+
+static struct platform_driver sst_acpi_driver = {
+ .driver = {
+ .name = "intel_sst_acpi",
+ .owner = THIS_MODULE,
+ .acpi_match_table = ACPI_PTR(sst_acpi_ids),
+ .pm = &intel_sst_pm,
+ },
+ .probe = sst_acpi_probe,
+ .remove = sst_acpi_remove,
+};
+
+module_platform_driver(sst_acpi_driver);
+
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine ACPI Driver");
+MODULE_AUTHOR("Ramesh Babu K V");
+MODULE_AUTHOR("Omair Mohammed Abdullah");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("sst");
diff --git a/sound/soc/intel/sst/sst_drv_interface.c b/sound/soc/intel/sst/sst_drv_interface.c
new file mode 100644
index 0000000..5f75ef3
--- /dev/null
+++ b/sound/soc/intel/sst/sst_drv_interface.c
@@ -0,0 +1,686 @@
+/*
+ * sst_drv_interface.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com)
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/delay.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <linux/math64.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../sst-dsp.h"
+
+
+
+#define NUM_CODEC 2
+#define MIN_FRAGMENT 2
+#define MAX_FRAGMENT 4
+#define MIN_FRAGMENT_SIZE (50 * 1024)
+#define MAX_FRAGMENT_SIZE (1024 * 1024)
+#define SST_GET_BYTES_PER_SAMPLE(pcm_wd_sz) (((pcm_wd_sz + 15) >> 4) << 1)
+
+int free_stream_context(struct intel_sst_drv *ctx, unsigned int str_id)
+{
+ struct stream_info *stream;
+ int ret = 0;
+
+ stream = get_stream_info(ctx, str_id);
+ if (stream) {
+ /* str_id is valid, so stream is alloacted */
+ ret = sst_free_stream(ctx, str_id);
+ if (ret)
+ sst_clean_stream(&ctx->streams[str_id]);
+ return ret;
+ } else {
+ dev_err(ctx->dev, "we tried to free stream context %d which was freed!!!\n", str_id);
+ }
+ return ret;
+}
+
+int sst_get_stream_allocated(struct intel_sst_drv *ctx,
+ struct snd_sst_params *str_param,
+ struct snd_sst_lib_download **lib_dnld)
+{
+ int retval;
+
+ retval = ctx->ops->alloc_stream(ctx, str_param);
+ if (retval > 0)
+ dev_dbg(ctx->dev, "Stream allocated %d\n", retval);
+ return retval;
+
+}
+
+/*
+ * sst_get_sfreq - this function returns the frequency of the stream
+ *
+ * @str_param : stream params
+ */
+int sst_get_sfreq(struct snd_sst_params *str_param)
+{
+ switch (str_param->codec) {
+ case SST_CODEC_TYPE_PCM:
+ return str_param->sparams.uc.pcm_params.sfreq;
+ case SST_CODEC_TYPE_AAC:
+ return str_param->sparams.uc.aac_params.externalsr;
+ case SST_CODEC_TYPE_MP3:
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * sst_get_num_channel - get number of channels for the stream
+ *
+ * @str_param : stream params
+ */
+int sst_get_num_channel(struct snd_sst_params *str_param)
+{
+ switch (str_param->codec) {
+ case SST_CODEC_TYPE_PCM:
+ return str_param->sparams.uc.pcm_params.num_chan;
+ case SST_CODEC_TYPE_MP3:
+ return str_param->sparams.uc.mp3_params.num_chan;
+ case SST_CODEC_TYPE_AAC:
+ return str_param->sparams.uc.aac_params.num_chan;
+ default:
+ return -EINVAL;
+ }
+}
+
+/*
+ * sst_get_stream - this function prepares for stream allocation
+ *
+ * @str_param : stream param
+ */
+int sst_get_stream(struct intel_sst_drv *ctx,
+ struct snd_sst_params *str_param)
+{
+ int retval;
+ struct stream_info *str_info;
+
+ /* stream is not allocated, we are allocating */
+ retval = ctx->ops->alloc_stream(ctx, str_param);
+ if (retval <= 0) {
+ return -EIO;
+ }
+ /* store sampling freq */
+ str_info = &ctx->streams[retval];
+ str_info->sfreq = sst_get_sfreq(str_param);
+
+ return retval;
+}
+
+static int sst_power_control(struct device *dev, bool state)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ dev_dbg(ctx->dev, "state:%d", state);
+ if (state == true)
+ return pm_runtime_get_sync(dev);
+ else
+ return sst_pm_runtime_put(ctx);
+}
+
+/*
+ * sst_open_pcm_stream - Open PCM interface
+ *
+ * @str_param: parameters of pcm stream
+ *
+ * This function is called by MID sound card driver to open
+ * a new pcm interface
+ */
+static int sst_open_pcm_stream(struct device *dev,
+ struct snd_sst_params *str_param)
+{
+ int retval;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (!str_param)
+ return -EINVAL;
+
+ retval = sst_get_stream(ctx, str_param);
+ if (retval > 0)
+ ctx->stream_cnt++;
+ else
+ dev_err(ctx->dev, "sst_get_stream returned err %d\n", retval);
+
+ return retval;
+}
+
+static int sst_cdev_open(struct device *dev,
+ struct snd_sst_params *str_params, struct sst_compress_cb *cb)
+{
+ int str_id, retval;
+ struct stream_info *stream;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ retval = pm_runtime_get_sync(ctx->dev);
+ if (retval < 0)
+ return retval;
+
+ str_id = sst_get_stream(ctx, str_params);
+ if (str_id > 0) {
+ dev_dbg(dev, "stream allocated in sst_cdev_open %d\n", str_id);
+ stream = &ctx->streams[str_id];
+ stream->compr_cb = cb->compr_cb;
+ stream->compr_cb_param = cb->param;
+ stream->drain_notify = cb->drain_notify;
+ stream->drain_cb_param = cb->drain_cb_param;
+ } else {
+ dev_err(dev, "stream encountered error during alloc %d\n", str_id);
+ str_id = -EINVAL;
+ sst_pm_runtime_put(ctx);
+ }
+ return str_id;
+}
+
+static int sst_cdev_close(struct device *dev, unsigned int str_id)
+{
+ int retval;
+ struct stream_info *stream;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ stream = get_stream_info(ctx, str_id);
+ if (!stream) {
+ dev_err(dev, "stream info is NULL for str %d!!!\n", str_id);
+ return -EINVAL;
+ }
+
+ if (stream->status == STREAM_RESET) {
+ dev_dbg(dev, "stream in reset state...\n");
+ stream->status = STREAM_UN_INIT;
+
+ retval = 0;
+ goto put;
+ }
+
+ retval = sst_free_stream(ctx, str_id);
+put:
+ stream->compr_cb_param = NULL;
+ stream->compr_cb = NULL;
+
+ if (retval)
+ dev_err(dev, "free stream returned err %d\n", retval);
+
+ dev_dbg(dev, "End\n");
+ return retval;
+
+}
+
+static int sst_cdev_ack(struct device *dev, unsigned int str_id,
+ unsigned long bytes)
+{
+ struct stream_info *stream;
+ struct snd_sst_tstamp fw_tstamp = {0,};
+ int offset;
+ void __iomem *addr;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ stream = get_stream_info(ctx, str_id);
+ if (!stream)
+ return -EINVAL;
+
+ /* update bytes sent */
+ stream->cumm_bytes += bytes;
+ dev_dbg(dev, "bytes copied %d inc by %ld\n", stream->cumm_bytes, bytes);
+
+ memcpy_fromio(&fw_tstamp,
+ ((void *)(ctx->mailbox + ctx->tstamp)
+ +(str_id * sizeof(fw_tstamp))),
+ sizeof(fw_tstamp));
+
+ fw_tstamp.bytes_copied = stream->cumm_bytes;
+ dev_dbg(dev, "bytes sent to fw %llu inc by %ld\n",
+ fw_tstamp.bytes_copied, bytes);
+
+ addr = ((void *)(ctx->mailbox + ctx->tstamp)) +
+ (str_id * sizeof(fw_tstamp));
+ offset = offsetof(struct snd_sst_tstamp, bytes_copied);
+ sst_shim_write(addr, offset, fw_tstamp.bytes_copied);
+ return 0;
+}
+
+static int sst_cdev_set_metadata(struct device *dev,
+ unsigned int str_id, struct snd_compr_metadata *metadata)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ dev_dbg(dev, "set metadata for stream %d\n", str_id);
+
+ str_info = get_stream_info(ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+
+ dev_dbg(dev, "pipe id = %d\n", str_info->pipe_id);
+ retval = sst_prepare_and_post_msg(ctx, str_info->task_id, IPC_CMD,
+ IPC_IA_SET_STREAM_PARAMS_MRFLD, str_info->pipe_id,
+ sizeof(*metadata), metadata, NULL,
+ true, true, true, false);
+
+ return retval;
+}
+
+static int sst_cdev_stream_pause(struct device *dev, unsigned int str_id)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ return sst_pause_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_pause_release(struct device *dev,
+ unsigned int str_id)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ return sst_resume_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_start(struct device *dev, unsigned int str_id)
+{
+ struct stream_info *str_info;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ str_info = get_stream_info(ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_RUNNING;
+ return sst_start_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_drop(struct device *dev, unsigned int str_id)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ return sst_drop_stream(ctx, str_id);
+}
+
+static int sst_cdev_stream_drain(struct device *dev, unsigned int str_id)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ return sst_drain_stream(ctx, str_id, false);
+}
+
+static int sst_cdev_stream_partial_drain(struct device *dev,
+ unsigned int str_id)
+{
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ return sst_drain_stream(ctx, str_id, true);
+}
+
+static int sst_cdev_tstamp(struct device *dev, unsigned int str_id,
+ struct snd_compr_tstamp *tstamp)
+{
+ struct snd_sst_tstamp fw_tstamp = {0,};
+ struct stream_info *stream;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ memcpy_fromio(&fw_tstamp,
+ ((void *)(ctx->mailbox + ctx->tstamp)
+ +(str_id * sizeof(fw_tstamp))),
+ sizeof(fw_tstamp));
+
+ stream = get_stream_info(ctx, str_id);
+ if (!stream)
+ return -EINVAL;
+ dev_dbg(dev, "rb_counter %llu in bytes\n", fw_tstamp.ring_buffer_counter);
+
+ tstamp->copied_total = fw_tstamp.ring_buffer_counter;
+ tstamp->pcm_frames = fw_tstamp.frames_decoded;
+ tstamp->pcm_io_frames = div_u64(fw_tstamp.hardware_counter,
+ (u64)((stream->num_ch) * SST_GET_BYTES_PER_SAMPLE(24)));
+ tstamp->sampling_rate = fw_tstamp.sampling_frequency;
+
+ dev_dbg(dev, "PCM = %u\n", tstamp->pcm_io_frames);
+ dev_dbg(dev, "Ptr Query on strid = %d copied_total %d, decodec %d\n",
+ str_id, tstamp->copied_total, tstamp->pcm_frames);
+ dev_dbg(dev, "rendered %d\n", tstamp->pcm_io_frames);
+
+ return 0;
+}
+
+static int sst_cdev_caps(struct snd_compr_caps *caps)
+{
+ caps->num_codecs = NUM_CODEC;
+ caps->min_fragment_size = MIN_FRAGMENT_SIZE; /* 50KB */
+ caps->max_fragment_size = MAX_FRAGMENT_SIZE; /* 1024KB */
+ caps->min_fragments = MIN_FRAGMENT;
+ caps->max_fragments = MAX_FRAGMENT;
+ caps->codecs[0] = SND_AUDIOCODEC_MP3;
+ caps->codecs[1] = SND_AUDIOCODEC_AAC;
+ return 0;
+}
+
+static struct snd_compr_codec_caps caps_mp3 = {
+ .num_descriptors = 1,
+ .descriptor[0].max_ch = 2,
+ .descriptor[0].sample_rates[0] = 48000,
+ .descriptor[0].sample_rates[1] = 44100,
+ .descriptor[0].sample_rates[2] = 32000,
+ .descriptor[0].sample_rates[3] = 16000,
+ .descriptor[0].sample_rates[4] = 8000,
+ .descriptor[0].num_sample_rates = 5,
+ .descriptor[0].bit_rate[0] = 320,
+ .descriptor[0].bit_rate[1] = 192,
+ .descriptor[0].num_bitrates = 2,
+ .descriptor[0].profiles = 0,
+ .descriptor[0].modes = SND_AUDIOCHANMODE_MP3_STEREO,
+ .descriptor[0].formats = 0,
+};
+
+static struct snd_compr_codec_caps caps_aac = {
+ .num_descriptors = 2,
+ .descriptor[1].max_ch = 2,
+ .descriptor[0].sample_rates[0] = 48000,
+ .descriptor[0].sample_rates[1] = 44100,
+ .descriptor[0].sample_rates[2] = 32000,
+ .descriptor[0].sample_rates[3] = 16000,
+ .descriptor[0].sample_rates[4] = 8000,
+ .descriptor[0].num_sample_rates = 5,
+ .descriptor[1].bit_rate[0] = 320,
+ .descriptor[1].bit_rate[1] = 192,
+ .descriptor[1].num_bitrates = 2,
+ .descriptor[1].profiles = 0,
+ .descriptor[1].modes = 0,
+ .descriptor[1].formats =
+ (SND_AUDIOSTREAMFORMAT_MP4ADTS |
+ SND_AUDIOSTREAMFORMAT_RAW),
+};
+
+static int sst_cdev_codec_caps(struct snd_compr_codec_caps *codec)
+{
+ if (codec->codec == SND_AUDIOCODEC_MP3)
+ *codec = caps_mp3;
+ else if (codec->codec == SND_AUDIOCODEC_AAC)
+ *codec = caps_aac;
+ else
+ return -EINVAL;
+
+ return 0;
+}
+
+void sst_cdev_fragment_elapsed(struct intel_sst_drv *ctx, int str_id)
+{
+ struct stream_info *stream;
+
+ dev_dbg(ctx->dev, "fragment elapsed from firmware for str_id %d\n",
+ str_id);
+ stream = &ctx->streams[str_id];
+ if (stream->compr_cb)
+ stream->compr_cb(stream->compr_cb_param);
+}
+
+/*
+ * sst_close_pcm_stream - Close PCM interface
+ *
+ * @str_id: stream id to be closed
+ *
+ * This function is called by MID sound card driver to close
+ * an existing pcm interface
+ */
+static int sst_close_pcm_stream(struct device *dev, unsigned int str_id)
+{
+ struct stream_info *stream;
+ int retval = 0;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ stream = get_stream_info(ctx, str_id);
+ if (!stream) {
+ dev_err(ctx->dev, "stream info is NULL for str %d!!!\n", str_id);
+ return -EINVAL;
+ }
+
+ if (stream->status == STREAM_RESET) {
+ /* silently fail here as we have cleaned the stream earlier */
+ dev_dbg(ctx->dev, "stream in reset state...\n");
+
+ retval = 0;
+ goto put;
+ }
+
+ retval = free_stream_context(ctx, str_id);
+put:
+ stream->pcm_substream = NULL;
+ stream->status = STREAM_UN_INIT;
+ stream->period_elapsed = NULL;
+ ctx->stream_cnt--;
+
+ if (retval)
+ dev_err(ctx->dev, "free stream returned err %d\n", retval);
+
+ dev_dbg(ctx->dev, "Exit\n");
+ return 0;
+}
+
+static inline int sst_calc_tstamp(struct intel_sst_drv *ctx,
+ struct pcm_stream_info *info,
+ struct snd_pcm_substream *substream,
+ struct snd_sst_tstamp *fw_tstamp)
+{
+ size_t delay_bytes, delay_frames;
+ size_t buffer_sz;
+ u32 pointer_bytes, pointer_samples;
+
+ dev_dbg(ctx->dev, "mrfld ring_buffer_counter %llu in bytes\n",
+ fw_tstamp->ring_buffer_counter);
+ dev_dbg(ctx->dev, "mrfld hardware_counter %llu in bytes\n",
+ fw_tstamp->hardware_counter);
+ if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
+ delay_bytes = (size_t) (fw_tstamp->ring_buffer_counter -
+ fw_tstamp->hardware_counter);
+ else
+ delay_bytes = (size_t) (fw_tstamp->hardware_counter -
+ fw_tstamp->ring_buffer_counter);
+ delay_frames = bytes_to_frames(substream->runtime, delay_bytes);
+ buffer_sz = snd_pcm_lib_buffer_bytes(substream);
+ div_u64_rem(fw_tstamp->ring_buffer_counter, buffer_sz, &pointer_bytes);
+ pointer_samples = bytes_to_samples(substream->runtime, pointer_bytes);
+
+ dev_dbg(ctx->dev, "pcm delay %zu in bytes\n", delay_bytes);
+
+ info->buffer_ptr = pointer_samples / substream->runtime->channels;
+
+ info->pcm_delay = delay_frames / substream->runtime->channels;
+ dev_dbg(ctx->dev, "buffer ptr %llu pcm_delay rep: %llu\n",
+ info->buffer_ptr, info->pcm_delay);
+ return 0;
+}
+
+static int sst_read_timestamp(struct device *dev, struct pcm_stream_info *info)
+{
+ struct stream_info *stream;
+ struct snd_pcm_substream *substream;
+ struct snd_sst_tstamp fw_tstamp;
+ unsigned int str_id;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ str_id = info->str_id;
+ stream = get_stream_info(ctx, str_id);
+ if (!stream)
+ return -EINVAL;
+
+ if (!stream->pcm_substream)
+ return -EINVAL;
+ substream = stream->pcm_substream;
+
+ memcpy_fromio(&fw_tstamp,
+ ((void *)(ctx->mailbox + ctx->tstamp)
+ + (str_id * sizeof(fw_tstamp))),
+ sizeof(fw_tstamp));
+ return sst_calc_tstamp(ctx, info, substream, &fw_tstamp);
+}
+
+static int sst_stream_start(struct device *dev, int str_id)
+{
+ struct stream_info *str_info;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (ctx->sst_state != SST_FW_RUNNING)
+ return 0;
+ str_info = get_stream_info(ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_RUNNING;
+ sst_start_stream(ctx, str_id);
+
+ return 0;
+}
+
+static int sst_stream_drop(struct device *dev, int str_id)
+{
+ struct stream_info *str_info;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (ctx->sst_state != SST_FW_RUNNING)
+ return 0;
+
+ str_info = get_stream_info(ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ str_info->prev = STREAM_UN_INIT;
+ str_info->status = STREAM_INIT;
+ return sst_drop_stream(ctx, str_id);
+}
+
+static int sst_stream_init(struct device *dev, struct pcm_stream_info *str_info)
+{
+ int str_id = 0;
+ struct stream_info *stream;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ str_id = str_info->str_id;
+
+ if (ctx->sst_state != SST_FW_RUNNING)
+ return 0;
+
+ stream = get_stream_info(ctx, str_id);
+ if (!stream)
+ return -EINVAL;
+
+ dev_dbg(ctx->dev, "setting the period ptrs\n");
+ stream->pcm_substream = str_info->arg;
+ stream->period_elapsed = str_info->period_elapsed;
+ stream->sfreq = str_info->sfreq;
+ stream->prev = stream->status;
+ stream->status = STREAM_INIT;
+ dev_dbg(ctx->dev,
+ "pcm_substream %p, period_elapsed %p, sfreq %d, status %d\n",
+ stream->pcm_substream, stream->period_elapsed,
+ stream->sfreq, stream->status);
+
+ return 0;
+}
+
+/*
+ * sst_set_byte_stream - Set generic params
+ *
+ * @cmd: control cmd to be set
+ * @arg: command argument
+ *
+ * This function is called by MID sound card driver to configure
+ * SST runtime params.
+ */
+static int sst_send_byte_stream(struct device *dev,
+ struct snd_sst_bytes_v2 *bytes)
+{
+ int ret_val = 0;
+ struct intel_sst_drv *ctx = dev_get_drvdata(dev);
+
+ if (NULL == bytes)
+ return -EINVAL;
+ ret_val = pm_runtime_get_sync(ctx->dev);
+ if (ret_val < 0)
+ return ret_val;
+
+ ret_val = sst_send_byte_stream_mrfld(ctx, bytes);
+ sst_pm_runtime_put(ctx);
+
+ return ret_val;
+}
+
+static struct sst_ops pcm_ops = {
+ .open = sst_open_pcm_stream,
+ .stream_init = sst_stream_init,
+ .stream_start = sst_stream_start,
+ .stream_drop = sst_stream_drop,
+ .stream_read_tstamp = sst_read_timestamp,
+ .send_byte_stream = sst_send_byte_stream,
+ .close = sst_close_pcm_stream,
+ .power = sst_power_control,
+};
+
+static struct compress_sst_ops compr_ops = {
+ .open = sst_cdev_open,
+ .close = sst_cdev_close,
+ .stream_pause = sst_cdev_stream_pause,
+ .stream_pause_release = sst_cdev_stream_pause_release,
+ .stream_start = sst_cdev_stream_start,
+ .stream_drop = sst_cdev_stream_drop,
+ .stream_drain = sst_cdev_stream_drain,
+ .stream_partial_drain = sst_cdev_stream_partial_drain,
+ .tstamp = sst_cdev_tstamp,
+ .ack = sst_cdev_ack,
+ .get_caps = sst_cdev_caps,
+ .get_codec_caps = sst_cdev_codec_caps,
+ .set_metadata = sst_cdev_set_metadata,
+ .power = sst_power_control,
+};
+
+static struct sst_device sst_dsp_device = {
+ .name = "Intel(R) SST LPE",
+ .dev = NULL,
+ .ops = &pcm_ops,
+ .compr_ops = &compr_ops,
+};
+
+/*
+ * sst_register - function to register DSP
+ *
+ * This functions registers DSP with the platform driver
+ */
+int sst_register(struct device *dev)
+{
+ int ret_val;
+
+ sst_dsp_device.dev = dev;
+ ret_val = sst_register_dsp(&sst_dsp_device);
+ if (ret_val)
+ dev_err(dev, "Unable to register DSP with platform driver\n");
+
+ return ret_val;
+}
+
+int sst_unregister(struct device *dev)
+{
+ return sst_unregister_dsp(&sst_dsp_device);
+}
diff --git a/sound/soc/intel/sst/sst_ipc.c b/sound/soc/intel/sst/sst_ipc.c
new file mode 100644
index 0000000..484e609
--- /dev/null
+++ b/sound/soc/intel/sst/sst_ipc.c
@@ -0,0 +1,373 @@
+/*
+ * sst_ipc.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corporation
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/intel-mid.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../sst-dsp.h"
+
+struct sst_block *sst_create_block(struct intel_sst_drv *ctx,
+ u32 msg_id, u32 drv_id)
+{
+ struct sst_block *msg = NULL;
+
+ dev_dbg(ctx->dev, "Enter\n");
+ msg = kzalloc(sizeof(*msg), GFP_KERNEL);
+ if (!msg)
+ return NULL;
+ msg->condition = false;
+ msg->on = true;
+ msg->msg_id = msg_id;
+ msg->drv_id = drv_id;
+ spin_lock_bh(&ctx->block_lock);
+ list_add_tail(&msg->node, &ctx->block_list);
+ spin_unlock_bh(&ctx->block_lock);
+
+ return msg;
+}
+
+/*
+ * while handling the interrupts, we need to check for message status and
+ * then if we are blocking for a message
+ *
+ * here we are unblocking the blocked ones, this is based on id we have
+ * passed and search that for block threads.
+ * We will not find block in two cases
+ * a) when its small message and block in not there, so silently ignore
+ * them
+ * b) when we are actually not able to find the block (bug perhaps)
+ *
+ * Since we have bit of small messages we can spam kernel log with err
+ * print on above so need to keep as debug prints which should be enabled
+ * via dynamic debug while debugging IPC issues
+ */
+int sst_wake_up_block(struct intel_sst_drv *ctx, int result,
+ u32 drv_id, u32 ipc, void *data, u32 size)
+{
+ struct sst_block *block = NULL;
+
+ dev_dbg(ctx->dev, "Enter\n");
+
+ spin_lock_bh(&ctx->block_lock);
+ list_for_each_entry(block, &ctx->block_list, node) {
+ dev_dbg(ctx->dev, "Block ipc %d, drv_id %d\n", block->msg_id,
+ block->drv_id);
+ if (block->msg_id == ipc && block->drv_id == drv_id) {
+ dev_dbg(ctx->dev, "free up the block\n");
+ block->ret_code = result;
+ block->data = data;
+ block->size = size;
+ block->condition = true;
+ spin_unlock_bh(&ctx->block_lock);
+ wake_up(&ctx->wait_queue);
+ return 0;
+ }
+ }
+ spin_unlock_bh(&ctx->block_lock);
+ dev_dbg(ctx->dev,
+ "Block not found or a response received for a short msg for ipc %d, drv_id %d\n",
+ ipc, drv_id);
+ return -EINVAL;
+}
+
+int sst_free_block(struct intel_sst_drv *ctx, struct sst_block *freed)
+{
+ struct sst_block *block = NULL, *__block;
+
+ dev_dbg(ctx->dev, "Enter\n");
+ spin_lock_bh(&ctx->block_lock);
+ list_for_each_entry_safe(block, __block, &ctx->block_list, node) {
+ if (block == freed) {
+ pr_debug("pvt_id freed --> %d\n", freed->drv_id);
+ /* toggle the index position of pvt_id */
+ list_del(&freed->node);
+ spin_unlock_bh(&ctx->block_lock);
+ kfree(freed->data);
+ freed->data = NULL;
+ kfree(freed);
+ return 0;
+ }
+ }
+ spin_unlock_bh(&ctx->block_lock);
+ dev_err(ctx->dev, "block is already freed!!!\n");
+ return -EINVAL;
+}
+
+int sst_post_message_mrfld(struct intel_sst_drv *sst_drv_ctx,
+ struct ipc_post *ipc_msg, bool sync)
+{
+ struct ipc_post *msg = ipc_msg;
+ union ipc_header_mrfld header;
+ unsigned int loop_count = 0;
+ int retval = 0;
+ unsigned long irq_flags;
+
+ dev_dbg(sst_drv_ctx->dev, "Enter: sync: %d\n", sync);
+ spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX);
+ if (sync) {
+ while (header.p.header_high.part.busy) {
+ if (loop_count > 25) {
+ dev_err(sst_drv_ctx->dev,
+ "sst: Busy wait failed, cant send this msg\n");
+ retval = -EBUSY;
+ goto out;
+ }
+ cpu_relax();
+ loop_count++;
+ header.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCX);
+ }
+ } else {
+ if (list_empty(&sst_drv_ctx->ipc_dispatch_list)) {
+ /* queue is empty, nothing to send */
+ spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ dev_dbg(sst_drv_ctx->dev,
+ "Empty msg queue... NO Action\n");
+ return 0;
+ }
+
+ if (header.p.header_high.part.busy) {
+ spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ dev_dbg(sst_drv_ctx->dev, "Busy not free... post later\n");
+ return 0;
+ }
+
+ /* copy msg from list */
+ msg = list_entry(sst_drv_ctx->ipc_dispatch_list.next,
+ struct ipc_post, node);
+ list_del(&msg->node);
+ }
+ dev_dbg(sst_drv_ctx->dev, "sst: Post message: header = %x\n",
+ msg->mrfld_header.p.header_high.full);
+ dev_dbg(sst_drv_ctx->dev, "sst: size = 0x%x\n",
+ msg->mrfld_header.p.header_low_payload);
+
+ if (msg->mrfld_header.p.header_high.part.large)
+ memcpy_toio(sst_drv_ctx->mailbox + SST_MAILBOX_SEND,
+ msg->mailbox_data,
+ msg->mrfld_header.p.header_low_payload);
+
+ sst_shim_write64(sst_drv_ctx->shim, SST_IPCX, msg->mrfld_header.full);
+
+out:
+ spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ kfree(msg->mailbox_data);
+ kfree(msg);
+ return retval;
+}
+
+void intel_sst_clear_intr_mrfld(struct intel_sst_drv *sst_drv_ctx)
+{
+ union interrupt_reg_mrfld isr;
+ union interrupt_reg_mrfld imr;
+ union ipc_header_mrfld clear_ipc;
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+ imr.full = sst_shim_read64(sst_drv_ctx->shim, SST_IMRX);
+ isr.full = sst_shim_read64(sst_drv_ctx->shim, SST_ISRX);
+
+ /* write 1 to clear*/
+ isr.part.busy_interrupt = 1;
+ sst_shim_write64(sst_drv_ctx->shim, SST_ISRX, isr.full);
+
+ /* Set IA done bit */
+ clear_ipc.full = sst_shim_read64(sst_drv_ctx->shim, SST_IPCD);
+
+ clear_ipc.p.header_high.part.busy = 0;
+ clear_ipc.p.header_high.part.done = 1;
+ clear_ipc.p.header_low_payload = IPC_ACK_SUCCESS;
+ sst_shim_write64(sst_drv_ctx->shim, SST_IPCD, clear_ipc.full);
+ /* un mask busy interrupt */
+ imr.part.busy_interrupt = 0;
+ sst_shim_write64(sst_drv_ctx->shim, SST_IMRX, imr.full);
+ spin_unlock_irqrestore(&sst_drv_ctx->ipc_spin_lock, irq_flags);
+}
+
+
+/*
+ * process_fw_init - process the FW init msg
+ *
+ * @msg: IPC message mailbox data from FW
+ *
+ * This function processes the FW init msg from FW
+ * marks FW state and prints debug info of loaded FW
+ */
+static void process_fw_init(struct intel_sst_drv *sst_drv_ctx,
+ void *msg)
+{
+ struct ipc_header_fw_init *init =
+ (struct ipc_header_fw_init *)msg;
+ int retval = 0;
+
+ dev_dbg(sst_drv_ctx->dev, "*** FW Init msg came***\n");
+ if (init->result) {
+ sst_set_fw_state_locked(sst_drv_ctx, SST_RESET);
+ dev_err(sst_drv_ctx->dev, "FW Init failed, Error %x\n",
+ init->result);
+ retval = init->result;
+ goto ret;
+ }
+
+ret:
+ sst_wake_up_block(sst_drv_ctx, retval, FW_DWNL_ID, 0 , NULL, 0);
+}
+
+static void process_fw_async_msg(struct intel_sst_drv *sst_drv_ctx,
+ struct ipc_post *msg)
+{
+ u32 msg_id;
+ int str_id;
+ u32 data_size, i;
+ void *data_offset;
+ struct stream_info *stream;
+ union ipc_header_high msg_high;
+ u32 msg_low, pipe_id;
+
+ msg_high = msg->mrfld_header.p.header_high;
+ msg_low = msg->mrfld_header.p.header_low_payload;
+ msg_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->cmd_id;
+ data_offset = (msg->mailbox_data + sizeof(struct ipc_dsp_hdr));
+ data_size = msg_low - (sizeof(struct ipc_dsp_hdr));
+
+ switch (msg_id) {
+ case IPC_SST_PERIOD_ELAPSED_MRFLD:
+ pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
+ str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
+ if (str_id > 0) {
+ dev_dbg(sst_drv_ctx->dev,
+ "Period elapsed rcvd for pipe id 0x%x\n",
+ pipe_id);
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->period_elapsed)
+ stream->period_elapsed(stream->pcm_substream);
+ if (stream->compr_cb)
+ stream->compr_cb(stream->compr_cb_param);
+ }
+ break;
+
+ case IPC_IA_DRAIN_STREAM_MRFLD:
+ pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
+ str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
+ if (str_id > 0) {
+ stream = &sst_drv_ctx->streams[str_id];
+ if (stream->drain_notify)
+ stream->drain_notify(stream->drain_cb_param);
+ }
+ break;
+
+ case IPC_IA_FW_ASYNC_ERR_MRFLD:
+ dev_err(sst_drv_ctx->dev, "FW sent async error msg:\n");
+ for (i = 0; i < (data_size/4); i++)
+ print_hex_dump(KERN_DEBUG, NULL, DUMP_PREFIX_NONE,
+ 16, 4, data_offset, data_size, false);
+ break;
+
+ case IPC_IA_FW_INIT_CMPLT_MRFLD:
+ process_fw_init(sst_drv_ctx, data_offset);
+ break;
+
+ case IPC_IA_BUF_UNDER_RUN_MRFLD:
+ pipe_id = ((struct ipc_dsp_hdr *)msg->mailbox_data)->pipe_id;
+ str_id = get_stream_id_mrfld(sst_drv_ctx, pipe_id);
+ if (str_id > 0)
+ dev_err(sst_drv_ctx->dev,
+ "Buffer under-run for pipe:%#x str_id:%d\n",
+ pipe_id, str_id);
+ break;
+
+ default:
+ dev_err(sst_drv_ctx->dev,
+ "Unrecognized async msg from FW msg_id %#x\n", msg_id);
+ }
+}
+
+void sst_process_reply_mrfld(struct intel_sst_drv *sst_drv_ctx,
+ struct ipc_post *msg)
+{
+ unsigned int drv_id;
+ void *data;
+ union ipc_header_high msg_high;
+ u32 msg_low;
+ struct ipc_dsp_hdr *dsp_hdr;
+ unsigned int cmd_id;
+
+ msg_high = msg->mrfld_header.p.header_high;
+ msg_low = msg->mrfld_header.p.header_low_payload;
+
+ dev_dbg(sst_drv_ctx->dev, "IPC process message header %x payload %x\n",
+ msg->mrfld_header.p.header_high.full,
+ msg->mrfld_header.p.header_low_payload);
+
+ drv_id = msg_high.part.drv_id;
+
+ /* Check for async messages first */
+ if (drv_id == SST_ASYNC_DRV_ID) {
+ /*FW sent async large message*/
+ process_fw_async_msg(sst_drv_ctx, msg);
+ return;
+ }
+
+ /* FW sent short error response for an IPC */
+ if (msg_high.part.result && drv_id && !msg_high.part.large) {
+ /* 32-bit FW error code in msg_low */
+ dev_err(sst_drv_ctx->dev, "FW sent error response 0x%x", msg_low);
+ sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
+ msg_high.part.drv_id,
+ msg_high.part.msg_id, NULL, 0);
+ return;
+ }
+
+ /*
+ * Process all valid responses
+ * if it is a large message, the payload contains the size to
+ * copy from mailbox
+ **/
+ if (msg_high.part.large) {
+ data = kzalloc(msg_low, GFP_KERNEL);
+ if (!data)
+ return;
+ memcpy(data, (void *) msg->mailbox_data, msg_low);
+ /* Copy command id so that we can use to put sst to reset */
+ dsp_hdr = (struct ipc_dsp_hdr *)data;
+ cmd_id = dsp_hdr->cmd_id;
+ dev_dbg(sst_drv_ctx->dev, "cmd_id %d\n", dsp_hdr->cmd_id);
+ if (sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
+ msg_high.part.drv_id,
+ msg_high.part.msg_id, data, msg_low))
+ kfree(data);
+ } else {
+ sst_wake_up_block(sst_drv_ctx, msg_high.part.result,
+ msg_high.part.drv_id,
+ msg_high.part.msg_id, NULL, 0);
+ }
+
+}
diff --git a/sound/soc/intel/sst/sst_loader.c b/sound/soc/intel/sst/sst_loader.c
new file mode 100644
index 0000000..b580f96
--- /dev/null
+++ b/sound/soc/intel/sst/sst_loader.c
@@ -0,0 +1,456 @@
+/*
+ * sst_dsp.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This file contains all dsp controlling functions like firmware download,
+ * setting/resetting dsp cores, etc
+ */
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/fs.h>
+#include <linux/sched.h>
+#include <linux/firmware.h>
+#include <linux/dmaengine.h>
+#include <linux/pm_runtime.h>
+#include <linux/pm_qos.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../sst-dsp.h"
+
+static inline void memcpy32_toio(void __iomem *dst, const void *src, int count)
+{
+ /* __iowrite32_copy uses 32-bit count values so divide by 4 for
+ * right count in words
+ */
+ __iowrite32_copy(dst, src, count/4);
+}
+
+/**
+ * intel_sst_reset_dsp_mrfld - Resetting SST DSP
+ *
+ * This resets DSP in case of MRFLD platfroms
+ */
+int intel_sst_reset_dsp_mrfld(struct intel_sst_drv *sst_drv_ctx)
+{
+ union config_status_reg_mrfld csr;
+
+ dev_dbg(sst_drv_ctx->dev, "sst: Resetting the DSP in mrfld\n");
+ csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+
+ dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+ csr.full |= 0x7;
+ sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+ csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+
+ dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+ csr.full &= ~(0x1);
+ sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+ dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+ return 0;
+}
+
+/**
+ * sst_start_merrifield - Start the SST DSP processor
+ *
+ * This starts the DSP in MERRIFIELD platfroms
+ */
+int sst_start_mrfld(struct intel_sst_drv *sst_drv_ctx)
+{
+ union config_status_reg_mrfld csr;
+
+ dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP in mrfld LALALALA\n");
+ csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+ dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+ csr.full |= 0x7;
+ sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+ dev_dbg(sst_drv_ctx->dev, "value:0x%llx\n", csr.full);
+
+ csr.part.xt_snoop = 1;
+ csr.full &= ~(0x5);
+ sst_shim_write64(sst_drv_ctx->shim, SST_CSR, csr.full);
+
+ csr.full = sst_shim_read64(sst_drv_ctx->shim, SST_CSR);
+ dev_dbg(sst_drv_ctx->dev, "sst: Starting the DSP_merrifield:%llx\n",
+ csr.full);
+ return 0;
+}
+
+static int sst_validate_fw_image(struct intel_sst_drv *ctx, unsigned long size,
+ struct fw_module_header **module, u32 *num_modules)
+{
+ struct sst_fw_header *header;
+ const void *sst_fw_in_mem = ctx->fw_in_mem;
+
+ dev_dbg(ctx->dev, "Enter\n");
+
+ /* Read the header information from the data pointer */
+ header = (struct sst_fw_header *)sst_fw_in_mem;
+ dev_dbg(ctx->dev,
+ "header sign=%s size=%x modules=%x fmt=%x size=%zx\n",
+ header->signature, header->file_size, header->modules,
+ header->file_format, sizeof(*header));
+
+ /* verify FW */
+ if ((strncmp(header->signature, SST_FW_SIGN, 4) != 0) ||
+ (size != header->file_size + sizeof(*header))) {
+ /* Invalid FW signature */
+ dev_err(ctx->dev, "InvalidFW sign/filesize mismatch\n");
+ return -EINVAL;
+ }
+ *num_modules = header->modules;
+ *module = (void *)sst_fw_in_mem + sizeof(*header);
+
+ return 0;
+}
+
+/*
+ * sst_fill_memcpy_list - Fill the memcpy list
+ *
+ * @memcpy_list: List to be filled
+ * @destn: Destination addr to be filled in the list
+ * @src: Source addr to be filled in the list
+ * @size: Size to be filled in the list
+ *
+ * Adds the node to the list after required fields
+ * are populated in the node
+ */
+static int sst_fill_memcpy_list(struct list_head *memcpy_list,
+ void *destn, const void *src, u32 size, bool is_io)
+{
+ struct sst_memcpy_list *listnode;
+
+ listnode = kzalloc(sizeof(*listnode), GFP_KERNEL);
+ if (listnode == NULL)
+ return -ENOMEM;
+ listnode->dstn = destn;
+ listnode->src = src;
+ listnode->size = size;
+ listnode->is_io = is_io;
+ list_add_tail(&listnode->memcpylist, memcpy_list);
+
+ return 0;
+}
+
+/**
+ * sst_parse_module_memcpy - Parse audio FW modules and populate the memcpy list
+ *
+ * @sst_drv_ctx : driver context
+ * @module : FW module header
+ * @memcpy_list : Pointer to the list to be populated
+ * Create the memcpy list as the number of block to be copied
+ * returns error or 0 if module sizes are proper
+ */
+static int sst_parse_module_memcpy(struct intel_sst_drv *sst_drv_ctx,
+ struct fw_module_header *module, struct list_head *memcpy_list)
+{
+ struct fw_block_info *block;
+ u32 count;
+ int ret_val = 0;
+ void __iomem *ram_iomem;
+
+ dev_dbg(sst_drv_ctx->dev, "module sign %s size %x blocks %x type %x\n",
+ module->signature, module->mod_size,
+ module->blocks, module->type);
+ dev_dbg(sst_drv_ctx->dev, "module entrypoint 0x%x\n", module->entry_point);
+
+ block = (void *)module + sizeof(*module);
+
+ for (count = 0; count < module->blocks; count++) {
+ if (block->size <= 0) {
+ dev_err(sst_drv_ctx->dev, "block size invalid\n");
+ return -EINVAL;
+ }
+ switch (block->type) {
+ case SST_IRAM:
+ ram_iomem = sst_drv_ctx->iram;
+ break;
+ case SST_DRAM:
+ ram_iomem = sst_drv_ctx->dram;
+ break;
+ case SST_DDR:
+ ram_iomem = sst_drv_ctx->ddr;
+ break;
+ case SST_CUSTOM_INFO:
+ block = (void *)block + sizeof(*block) + block->size;
+ continue;
+ default:
+ dev_err(sst_drv_ctx->dev, "wrong ram type0x%x in block0x%x\n",
+ block->type, count);
+ return -EINVAL;
+ }
+
+ ret_val = sst_fill_memcpy_list(memcpy_list,
+ ram_iomem + block->ram_offset,
+ (void *)block + sizeof(*block), block->size, 1);
+ if (ret_val)
+ return ret_val;
+
+ block = (void *)block + sizeof(*block) + block->size;
+ }
+ return 0;
+}
+
+/**
+ * sst_parse_fw_memcpy - parse the firmware image & populate the list for memcpy
+ *
+ * @ctx : pointer to drv context
+ * @size : size of the firmware
+ * @fw_list : pointer to list_head to be populated
+ * This function parses the FW image and saves the parsed image in the list
+ * for memcpy
+ */
+static int sst_parse_fw_memcpy(struct intel_sst_drv *ctx, unsigned long size,
+ struct list_head *fw_list)
+{
+ struct fw_module_header *module;
+ u32 count, num_modules;
+ int ret_val;
+
+ ret_val = sst_validate_fw_image(ctx, size, &module, &num_modules);
+ if (ret_val)
+ return ret_val;
+
+ for (count = 0; count < num_modules; count++) {
+ ret_val = sst_parse_module_memcpy(ctx, module, fw_list);
+ if (ret_val)
+ return ret_val;
+ module = (void *)module + sizeof(*module) + module->mod_size;
+ }
+
+ return 0;
+}
+
+/**
+ * sst_do_memcpy - function initiates the memcpy
+ *
+ * @memcpy_list: Pter to memcpy list on which the memcpy needs to be initiated
+ *
+ * Triggers the memcpy
+ */
+static void sst_do_memcpy(struct list_head *memcpy_list)
+{
+ struct sst_memcpy_list *listnode;
+
+ list_for_each_entry(listnode, memcpy_list, memcpylist) {
+ if (listnode->is_io == true)
+ memcpy32_toio((void __iomem *)listnode->dstn,
+ listnode->src, listnode->size);
+ else
+ memcpy(listnode->dstn, listnode->src, listnode->size);
+ }
+}
+
+void sst_memcpy_free_resources(struct intel_sst_drv *sst_drv_ctx)
+{
+ struct sst_memcpy_list *listnode, *tmplistnode;
+
+ /* Free the list */
+ if (!list_empty(&sst_drv_ctx->memcpy_list)) {
+ list_for_each_entry_safe(listnode, tmplistnode,
+ &sst_drv_ctx->memcpy_list, memcpylist) {
+ list_del(&listnode->memcpylist);
+ kfree(listnode);
+ }
+ }
+}
+
+static int sst_cache_and_parse_fw(struct intel_sst_drv *sst,
+ const struct firmware *fw)
+{
+ int retval = 0;
+
+ sst->fw_in_mem = kzalloc(fw->size, GFP_KERNEL);
+ if (!sst->fw_in_mem) {
+ retval = -ENOMEM;
+ goto end_release;
+ }
+ dev_dbg(sst->dev, "copied fw to %p", sst->fw_in_mem);
+ dev_dbg(sst->dev, "phys: %lx", (unsigned long)virt_to_phys(sst->fw_in_mem));
+ memcpy(sst->fw_in_mem, fw->data, fw->size);
+ retval = sst_parse_fw_memcpy(sst, fw->size, &sst->memcpy_list);
+ if (retval) {
+ dev_err(sst->dev, "Failed to parse fw\n");
+ kfree(sst->fw_in_mem);
+ sst->fw_in_mem = NULL;
+ }
+
+end_release:
+ release_firmware(fw);
+ return retval;
+
+}
+
+void sst_firmware_load_cb(const struct firmware *fw, void *context)
+{
+ struct intel_sst_drv *ctx = context;
+
+ dev_dbg(ctx->dev, "Enter\n");
+
+ if (fw == NULL) {
+ dev_err(ctx->dev, "request fw failed\n");
+ return;
+ }
+
+ mutex_lock(&ctx->sst_lock);
+
+ if (ctx->sst_state != SST_RESET ||
+ ctx->fw_in_mem != NULL) {
+ if (fw != NULL)
+ release_firmware(fw);
+ mutex_unlock(&ctx->sst_lock);
+ return;
+ }
+
+ dev_dbg(ctx->dev, "Request Fw completed\n");
+ sst_cache_and_parse_fw(ctx, fw);
+ mutex_unlock(&ctx->sst_lock);
+}
+
+/*
+ * sst_request_fw - requests audio fw from kernel and saves a copy
+ *
+ * This function requests the SST FW from the kernel, parses it and
+ * saves a copy in the driver context
+ */
+static int sst_request_fw(struct intel_sst_drv *sst)
+{
+ int retval = 0;
+ const struct firmware *fw;
+
+ retval = request_firmware(&fw, sst->firmware_name, sst->dev);
+ if (fw == NULL) {
+ dev_err(sst->dev, "fw is returning as null\n");
+ return -EINVAL;
+ }
+ if (retval) {
+ dev_err(sst->dev, "request fw failed %d\n", retval);
+ return retval;
+ }
+ mutex_lock(&sst->sst_lock);
+ retval = sst_cache_and_parse_fw(sst, fw);
+ mutex_unlock(&sst->sst_lock);
+
+ return retval;
+}
+
+/*
+ * Writing the DDR physical base to DCCM offset
+ * so that FW can use it to setup TLB
+ */
+static void sst_dccm_config_write(void __iomem *dram_base,
+ unsigned int ddr_base)
+{
+ void __iomem *addr;
+ u32 bss_reset = 0;
+
+ addr = (void __iomem *)(dram_base + MRFLD_FW_DDR_BASE_OFFSET);
+ memcpy32_toio(addr, (void *)&ddr_base, sizeof(u32));
+ bss_reset |= (1 << MRFLD_FW_BSS_RESET_BIT);
+ addr = (void __iomem *)(dram_base + MRFLD_FW_FEATURE_BASE_OFFSET);
+ memcpy32_toio(addr, &bss_reset, sizeof(u32));
+
+}
+
+void sst_post_download_mrfld(struct intel_sst_drv *ctx)
+{
+ sst_dccm_config_write(ctx->dram, ctx->ddr_base);
+ dev_dbg(ctx->dev, "config written to DCCM\n");
+}
+
+/**
+ * sst_load_fw - function to load FW into DSP
+ * Transfers the FW to DSP using dma/memcpy
+ */
+int sst_load_fw(struct intel_sst_drv *sst_drv_ctx)
+{
+ int ret_val = 0;
+ struct sst_block *block;
+
+ dev_dbg(sst_drv_ctx->dev, "sst_load_fw\n");
+
+ if (sst_drv_ctx->sst_state != SST_RESET ||
+ sst_drv_ctx->sst_state == SST_SHUTDOWN)
+ return -EAGAIN;
+
+ if (!sst_drv_ctx->fw_in_mem) {
+ dev_dbg(sst_drv_ctx->dev, "sst: FW not in memory retry to download\n");
+ ret_val = sst_request_fw(sst_drv_ctx);
+ if (ret_val)
+ return ret_val;
+ }
+
+ BUG_ON(!sst_drv_ctx->fw_in_mem);
+ block = sst_create_block(sst_drv_ctx, 0, FW_DWNL_ID);
+ if (block == NULL)
+ return -ENOMEM;
+
+ /* Prevent C-states beyond C6 */
+ pm_qos_update_request(sst_drv_ctx->qos, 0);
+
+ sst_drv_ctx->sst_state = SST_FW_LOADING;
+
+ ret_val = sst_drv_ctx->ops->reset(sst_drv_ctx);
+ if (ret_val)
+ goto restore;
+
+ sst_do_memcpy(&sst_drv_ctx->memcpy_list);
+
+ /* Write the DRAM/DCCM config before enabling FW */
+ if (sst_drv_ctx->ops->post_download)
+ sst_drv_ctx->ops->post_download(sst_drv_ctx);
+
+ /* bring sst out of reset */
+ ret_val = sst_drv_ctx->ops->start(sst_drv_ctx);
+ if (ret_val)
+ goto restore;
+
+ ret_val = sst_wait_timeout(sst_drv_ctx, block);
+ if (ret_val) {
+ dev_err(sst_drv_ctx->dev, "fw download failed %d\n" , ret_val);
+ /* FW download failed due to timeout */
+ ret_val = -EBUSY;
+
+ }
+
+
+restore:
+ /* Re-enable Deeper C-states beyond C6 */
+ pm_qos_update_request(sst_drv_ctx->qos, PM_QOS_DEFAULT_VALUE);
+ sst_free_block(sst_drv_ctx, block);
+ dev_dbg(sst_drv_ctx->dev, "fw load successful!!!\n");
+
+ if (sst_drv_ctx->ops->restore_dsp_context)
+ sst_drv_ctx->ops->restore_dsp_context();
+ sst_drv_ctx->sst_state = SST_FW_RUNNING;
+ return ret_val;
+}
+
diff --git a/sound/soc/intel/sst/sst_pci.c b/sound/soc/intel/sst/sst_pci.c
new file mode 100644
index 0000000..3a0b3bf
--- /dev/null
+++ b/sound/soc/intel/sst/sst_pci.c
@@ -0,0 +1,209 @@
+/*
+ * sst_pci.c - SST (LPE) driver init file for pci enumeration.
+ *
+ * Copyright (C) 2008-14 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/soc.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+
+static int sst_platform_get_resources(struct intel_sst_drv *ctx)
+{
+ int ddr_base, ret = 0;
+ struct pci_dev *pci = ctx->pci;
+
+ ret = pci_request_regions(pci, SST_DRV_NAME);
+ if (ret)
+ return ret;
+
+ /* map registers */
+ /* DDR base */
+ if (ctx->dev_id == SST_MRFLD_PCI_ID) {
+ ctx->ddr_base = pci_resource_start(pci, 0);
+ /* check that the relocated IMR base matches with FW Binary */
+ ddr_base = relocate_imr_addr_mrfld(ctx->ddr_base);
+ if (!ctx->pdata->lib_info) {
+ dev_err(ctx->dev, "lib_info pointer NULL\n");
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ if (ddr_base != ctx->pdata->lib_info->mod_base) {
+ dev_err(ctx->dev,
+ "FW LSP DDR BASE does not match with IFWI\n");
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ ctx->ddr_end = pci_resource_end(pci, 0);
+
+ ctx->ddr = pcim_iomap(pci, 0,
+ pci_resource_len(pci, 0));
+ if (!ctx->ddr) {
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ dev_dbg(ctx->dev, "sst: DDR Ptr %p\n", ctx->ddr);
+ } else {
+ ctx->ddr = NULL;
+ }
+ /* SHIM */
+ ctx->shim_phy_add = pci_resource_start(pci, 1);
+ ctx->shim = pcim_iomap(pci, 1, pci_resource_len(pci, 1));
+ if (!ctx->shim) {
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ dev_dbg(ctx->dev, "SST Shim Ptr %p\n", ctx->shim);
+
+ /* Shared SRAM */
+ ctx->mailbox_add = pci_resource_start(pci, 2);
+ ctx->mailbox = pcim_iomap(pci, 2, pci_resource_len(pci, 2));
+ if (!ctx->mailbox) {
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ dev_dbg(ctx->dev, "SRAM Ptr %p\n", ctx->mailbox);
+
+ /* IRAM */
+ ctx->iram_end = pci_resource_end(pci, 3);
+ ctx->iram_base = pci_resource_start(pci, 3);
+ ctx->iram = pcim_iomap(pci, 3, pci_resource_len(pci, 3));
+ if (!ctx->iram) {
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ dev_dbg(ctx->dev, "IRAM Ptr %p\n", ctx->iram);
+
+ /* DRAM */
+ ctx->dram_end = pci_resource_end(pci, 4);
+ ctx->dram_base = pci_resource_start(pci, 4);
+ ctx->dram = pcim_iomap(pci, 4, pci_resource_len(pci, 4));
+ if (!ctx->dram) {
+ ret = -EINVAL;
+ goto do_release_regions;
+ }
+ dev_dbg(ctx->dev, "DRAM Ptr %p\n", ctx->dram);
+do_release_regions:
+ pci_release_regions(pci);
+ return 0;
+}
+
+/*
+ * intel_sst_probe - PCI probe function
+ *
+ * @pci: PCI device structure
+ * @pci_id: PCI device ID structure
+ *
+ */
+static int intel_sst_probe(struct pci_dev *pci,
+ const struct pci_device_id *pci_id)
+{
+ int ret = 0;
+ struct intel_sst_drv *sst_drv_ctx;
+ struct sst_platform_info *sst_pdata = pci->dev.platform_data;
+
+ dev_dbg(&pci->dev, "Probe for DID %x\n", pci->device);
+ ret = sst_alloc_drv_context(&sst_drv_ctx, &pci->dev, pci->device);
+ if (ret < 0)
+ return ret;
+
+ sst_drv_ctx->pdata = sst_pdata;
+ sst_drv_ctx->irq_num = pci->irq;
+ snprintf(sst_drv_ctx->firmware_name, sizeof(sst_drv_ctx->firmware_name),
+ "%s%04x%s", "fw_sst_",
+ sst_drv_ctx->dev_id, ".bin");
+
+ ret = sst_context_init(sst_drv_ctx);
+ if (ret < 0)
+ return ret;
+
+ /* Init the device */
+ ret = pcim_enable_device(pci);
+ if (ret) {
+ dev_err(sst_drv_ctx->dev,
+ "device can't be enabled. Returned err: %d\n", ret);
+ goto do_free_drv_ctx;
+ }
+ sst_drv_ctx->pci = pci_dev_get(pci);
+ ret = sst_platform_get_resources(sst_drv_ctx);
+ if (ret < 0)
+ goto do_free_drv_ctx;
+
+ pci_set_drvdata(pci, sst_drv_ctx);
+ sst_configure_runtime_pm(sst_drv_ctx);
+
+ return ret;
+
+do_free_drv_ctx:
+ sst_context_cleanup(sst_drv_ctx);
+ dev_err(sst_drv_ctx->dev, "Probe failed with %d\n", ret);
+ return ret;
+}
+
+/**
+ * intel_sst_remove - PCI remove function
+ *
+ * @pci: PCI device structure
+ *
+ * This function is called by OS when a device is unloaded
+ * This frees the interrupt etc
+ */
+static void intel_sst_remove(struct pci_dev *pci)
+{
+ struct intel_sst_drv *sst_drv_ctx = pci_get_drvdata(pci);
+
+ sst_context_cleanup(sst_drv_ctx);
+ pci_dev_put(sst_drv_ctx->pci);
+ pci_release_regions(pci);
+ pci_set_drvdata(pci, NULL);
+}
+
+/* PCI Routines */
+static struct pci_device_id intel_sst_ids[] = {
+ { PCI_VDEVICE(INTEL, SST_MRFLD_PCI_ID), 0},
+ { 0, }
+};
+
+static struct pci_driver sst_driver = {
+ .name = SST_DRV_NAME,
+ .id_table = intel_sst_ids,
+ .probe = intel_sst_probe,
+ .remove = intel_sst_remove,
+#ifdef CONFIG_PM
+ .driver = {
+ .pm = &intel_sst_pm,
+ },
+#endif
+};
+
+module_pci_driver(sst_driver);
+
+MODULE_DESCRIPTION("Intel (R) SST(R) Audio Engine PCI Driver");
+MODULE_AUTHOR("Vinod Koul <vinod.koul@intel.com>");
+MODULE_AUTHOR("Harsha Priya <priya.harsha@intel.com>");
+MODULE_AUTHOR("Dharageswari R <dharageswari.r@intel.com>");
+MODULE_AUTHOR("KP Jeeja <jeeja.kp@intel.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("sst");
diff --git a/sound/soc/intel/sst/sst_pvt.c b/sound/soc/intel/sst/sst_pvt.c
new file mode 100644
index 0000000..4b77208
--- /dev/null
+++ b/sound/soc/intel/sst/sst_pvt.c
@@ -0,0 +1,449 @@
+/*
+ * sst_pvt.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/kobject.h>
+#include <linux/pci.h>
+#include <linux/fs.h>
+#include <linux/firmware.h>
+#include <linux/pm_runtime.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <sound/asound.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../sst-dsp.h"
+
+int sst_shim_write(void __iomem *addr, int offset, int value)
+{
+ writel(value, addr + offset);
+ return 0;
+}
+
+u32 sst_shim_read(void __iomem *addr, int offset)
+{
+ return readl(addr + offset);
+}
+
+u64 sst_reg_read64(void __iomem *addr, int offset)
+{
+ u64 val = 0;
+
+ memcpy_fromio(&val, addr + offset, sizeof(val));
+
+ return val;
+}
+
+int sst_shim_write64(void __iomem *addr, int offset, u64 value)
+{
+ memcpy_toio(addr + offset, &value, sizeof(value));
+ return 0;
+}
+
+u64 sst_shim_read64(void __iomem *addr, int offset)
+{
+ u64 val = 0;
+
+ memcpy_fromio(&val, addr + offset, sizeof(val));
+ return val;
+}
+
+void sst_set_fw_state_locked(
+ struct intel_sst_drv *sst_drv_ctx, int sst_state)
+{
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_drv_ctx->sst_state = sst_state;
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+}
+
+/*
+ * sst_wait_interruptible - wait on event
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ *
+ * This function waits without a timeout (and is interruptable) for a
+ * given block event
+ */
+int sst_wait_interruptible(struct intel_sst_drv *sst_drv_ctx,
+ struct sst_block *block)
+{
+ int retval = 0;
+
+ if (!wait_event_interruptible(sst_drv_ctx->wait_queue,
+ block->condition)) {
+ /* event wake */
+ if (block->ret_code < 0) {
+ dev_err(sst_drv_ctx->dev,
+ "stream failed %d\n", block->ret_code);
+ retval = -EBUSY;
+ } else {
+ dev_dbg(sst_drv_ctx->dev, "event up\n");
+ retval = 0;
+ }
+ } else {
+ dev_err(sst_drv_ctx->dev, "signal interrupted\n");
+ retval = -EINTR;
+ }
+ return retval;
+
+}
+
+unsigned long long read_shim_data(struct intel_sst_drv *sst, int addr)
+{
+ unsigned long long val = 0;
+
+ switch (sst->dev_id) {
+ case SST_MRFLD_PCI_ID:
+ case SST_BYT_ACPI_ID:
+ val = sst_shim_read64(sst->shim, addr);
+ break;
+ }
+ return val;
+}
+
+void write_shim_data(struct intel_sst_drv *sst, int addr,
+ unsigned long long data)
+{
+ switch (sst->dev_id) {
+ case SST_MRFLD_PCI_ID:
+ case SST_BYT_ACPI_ID:
+ sst_shim_write64(sst->shim, addr, (u64) data);
+ break;
+ }
+}
+
+/*
+ * sst_wait_timeout - wait on event for timeout
+ *
+ * @sst_drv_ctx: Driver context
+ * @block: Driver block to wait on
+ *
+ * This function waits with a timeout value (and is not interruptible) on a
+ * given block event
+ */
+int sst_wait_timeout(struct intel_sst_drv *sst_drv_ctx, struct sst_block *block)
+{
+ int retval = 0;
+
+ /*
+ * NOTE:
+ * Observed that FW processes the alloc msg and replies even
+ * before the alloc thread has finished execution
+ */
+ dev_dbg(sst_drv_ctx->dev,
+ "waiting for condition %x ipc %d drv_id %d\n",
+ block->condition, block->msg_id, block->drv_id);
+ if (wait_event_timeout(sst_drv_ctx->wait_queue,
+ block->condition,
+ msecs_to_jiffies(SST_BLOCK_TIMEOUT))) {
+ /* event wake */
+ dev_dbg(sst_drv_ctx->dev, "Event wake %x\n",
+ block->condition);
+ dev_dbg(sst_drv_ctx->dev, "message ret: %d\n",
+ block->ret_code);
+ retval = -block->ret_code;
+ } else {
+ block->on = false;
+ dev_err(sst_drv_ctx->dev,
+ "Wait timed-out condition:%#x, msg_id:%#x fw_state %#x\n",
+ block->condition, block->msg_id, sst_drv_ctx->sst_state);
+ sst_drv_ctx->sst_state = SST_RESET;
+
+ retval = -EBUSY;
+ }
+ return retval;
+}
+
+/*
+ * sst_create_ipc_msg - create a IPC message
+ *
+ * @arg: ipc message
+ * @large: large or short message
+ *
+ * this function allocates structures to send a large or short
+ * message to the firmware
+ */
+int sst_create_ipc_msg(struct ipc_post **arg, bool large)
+{
+ struct ipc_post *msg;
+
+ msg = kzalloc(sizeof(struct ipc_post), GFP_ATOMIC);
+ if (!msg)
+ return -ENOMEM;
+ if (large) {
+ msg->mailbox_data = kzalloc(SST_MAILBOX_SIZE, GFP_ATOMIC);
+ if (!msg->mailbox_data) {
+ kfree(msg);
+ return -ENOMEM;
+ }
+ } else {
+ msg->mailbox_data = NULL;
+ }
+ msg->is_large = large;
+ *arg = msg;
+ return 0;
+}
+
+/*
+ * sst_create_block_and_ipc_msg - Creates IPC message and sst block
+ * @arg: passed to sst_create_ipc_message API
+ * @large: large or short message
+ * @sst_drv_ctx: sst driver context
+ * @block: return block allocated
+ * @msg_id: IPC
+ * @drv_id: stream id or private id
+ */
+int sst_create_block_and_ipc_msg(struct ipc_post **arg, bool large,
+ struct intel_sst_drv *sst_drv_ctx, struct sst_block **block,
+ u32 msg_id, u32 drv_id)
+{
+ int retval = 0;
+
+ retval = sst_create_ipc_msg(arg, large);
+ if (retval)
+ return retval;
+ *block = sst_create_block(sst_drv_ctx, msg_id, drv_id);
+ if (*block == NULL) {
+ kfree(*arg);
+ return -ENOMEM;
+ }
+ return retval;
+}
+
+/*
+ * sst_clean_stream - clean the stream context
+ *
+ * @stream: stream structure
+ *
+ * this function resets the stream contexts
+ * should be called in free
+ */
+void sst_clean_stream(struct stream_info *stream)
+{
+ stream->status = STREAM_UN_INIT;
+ stream->prev = STREAM_UN_INIT;
+ mutex_lock(&stream->lock);
+ stream->cumm_bytes = 0;
+ mutex_unlock(&stream->lock);
+}
+
+int sst_prepare_and_post_msg(struct intel_sst_drv *sst,
+ int task_id, int ipc_msg, int cmd_id, int pipe_id,
+ size_t mbox_data_len, const void *mbox_data, void **data,
+ bool large, bool fill_dsp, bool sync, bool response)
+{
+ struct ipc_post *msg = NULL;
+ struct ipc_dsp_hdr dsp_hdr;
+ struct sst_block *block;
+ int ret = 0, pvt_id;
+
+ pvt_id = sst_assign_pvt_id(sst);
+ if (pvt_id < 0)
+ return pvt_id;
+
+ if (response)
+ ret = sst_create_block_and_ipc_msg(
+ &msg, large, sst, &block, ipc_msg, pvt_id);
+ else
+ ret = sst_create_ipc_msg(&msg, large);
+
+ if (ret < 0) {
+ test_and_clear_bit(pvt_id, &sst->pvt_id);
+ return -ENOMEM;
+ }
+
+ dev_dbg(sst->dev, "pvt_id = %d, pipe id = %d, task = %d ipc_msg: %d\n",
+ pvt_id, pipe_id, task_id, ipc_msg);
+ sst_fill_header_mrfld(&msg->mrfld_header, ipc_msg,
+ task_id, large, pvt_id);
+ msg->mrfld_header.p.header_low_payload = sizeof(dsp_hdr) + mbox_data_len;
+ msg->mrfld_header.p.header_high.part.res_rqd = !sync;
+ dev_dbg(sst->dev, "header:%x\n",
+ msg->mrfld_header.p.header_high.full);
+ dev_dbg(sst->dev, "response rqd: %x",
+ msg->mrfld_header.p.header_high.part.res_rqd);
+ dev_dbg(sst->dev, "msg->mrfld_header.p.header_low_payload:%d",
+ msg->mrfld_header.p.header_low_payload);
+ if (fill_dsp) {
+ sst_fill_header_dsp(&dsp_hdr, cmd_id, pipe_id, mbox_data_len);
+ memcpy(msg->mailbox_data, &dsp_hdr, sizeof(dsp_hdr));
+ if (mbox_data_len) {
+ memcpy(msg->mailbox_data + sizeof(dsp_hdr),
+ mbox_data, mbox_data_len);
+ }
+ }
+
+ if (sync)
+ sst->ops->post_message(sst, msg, true);
+ else
+ sst_add_to_dispatch_list_and_post(sst, msg);
+
+ if (response) {
+ ret = sst_wait_timeout(sst, block);
+ if (ret < 0) {
+ goto out;
+ } else if(block->data) {
+ if (!data)
+ goto out;
+ *data = kzalloc(block->size, GFP_KERNEL);
+ if (!(*data)) {
+ ret = -ENOMEM;
+ goto out;
+ } else
+ memcpy(data, (void *) block->data, block->size);
+ }
+ }
+out:
+ if (response)
+ sst_free_block(sst, block);
+ test_and_clear_bit(pvt_id, &sst->pvt_id);
+ return ret;
+}
+
+int sst_pm_runtime_put(struct intel_sst_drv *sst_drv)
+{
+ int ret;
+
+ pm_runtime_mark_last_busy(sst_drv->dev);
+ ret = pm_runtime_put_autosuspend(sst_drv->dev);
+ if (ret < 0)
+ return ret;
+ return 0;
+}
+
+void sst_fill_header_mrfld(union ipc_header_mrfld *header,
+ int msg, int task_id, int large, int drv_id)
+{
+ header->full = 0;
+ header->p.header_high.part.msg_id = msg;
+ header->p.header_high.part.task_id = task_id;
+ header->p.header_high.part.large = large;
+ header->p.header_high.part.drv_id = drv_id;
+ header->p.header_high.part.done = 0;
+ header->p.header_high.part.busy = 1;
+ header->p.header_high.part.res_rqd = 1;
+}
+
+void sst_fill_header_dsp(struct ipc_dsp_hdr *dsp, int msg,
+ int pipe_id, int len)
+{
+ dsp->cmd_id = msg;
+ dsp->mod_index_id = 0xff;
+ dsp->pipe_id = pipe_id;
+ dsp->length = len;
+ dsp->mod_id = 0;
+}
+
+#define SST_MAX_BLOCKS 15
+/*
+ * sst_assign_pvt_id - assign a pvt id for stream
+ *
+ * @sst_drv_ctx : driver context
+ *
+ * this function assigns a private id for calls that dont have stream
+ * context yet, should be called with lock held
+ * uses bits for the id, and finds first free bits and assigns that
+ */
+int sst_assign_pvt_id(struct intel_sst_drv *drv)
+{
+ int local;
+
+ spin_lock(&drv->block_lock);
+ /* find first zero index from lsb */
+ local = ffz(drv->pvt_id);
+ dev_dbg(drv->dev, "pvt_id assigned --> %d\n", local);
+ if (local >= SST_MAX_BLOCKS){
+ spin_unlock(&drv->block_lock);
+ dev_err(drv->dev, "PVT _ID error: no free id blocks ");
+ return -EINVAL;
+ }
+ /* toggle the index */
+ change_bit(local, &drv->pvt_id);
+ spin_unlock(&drv->block_lock);
+ return local;
+}
+
+void sst_init_stream(struct stream_info *stream,
+ int codec, int sst_id, int ops, u8 slot)
+{
+ stream->status = STREAM_INIT;
+ stream->prev = STREAM_UN_INIT;
+ stream->ops = ops;
+}
+
+int sst_validate_strid(
+ struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ if (str_id <= 0 || str_id > sst_drv_ctx->info.max_streams) {
+ dev_err(sst_drv_ctx->dev,
+ "SST ERR: invalid stream id : %d, max %d\n",
+ str_id, sst_drv_ctx->info.max_streams);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+struct stream_info *get_stream_info(
+ struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ if (sst_validate_strid(sst_drv_ctx, str_id))
+ return NULL;
+ return &sst_drv_ctx->streams[str_id];
+}
+
+int get_stream_id_mrfld(struct intel_sst_drv *sst_drv_ctx,
+ u32 pipe_id)
+{
+ int i;
+
+ for (i = 1; i <= sst_drv_ctx->info.max_streams; i++)
+ if (pipe_id == sst_drv_ctx->streams[i].pipe_id)
+ return i;
+
+ dev_dbg(sst_drv_ctx->dev, "no such pipe_id(%u)", pipe_id);
+ return -1;
+}
+
+u32 relocate_imr_addr_mrfld(u32 base_addr)
+{
+ /* Get the difference from 512MB aligned base addr */
+ /* relocate the base */
+ base_addr = MRFLD_FW_VIRTUAL_BASE + (base_addr % (512 * 1024 * 1024));
+ return base_addr;
+}
+EXPORT_SYMBOL_GPL(relocate_imr_addr_mrfld);
+
+void sst_add_to_dispatch_list_and_post(struct intel_sst_drv *sst,
+ struct ipc_post *msg)
+{
+ unsigned long irq_flags;
+
+ spin_lock_irqsave(&sst->ipc_spin_lock, irq_flags);
+ list_add_tail(&msg->node, &sst->ipc_dispatch_list);
+ spin_unlock_irqrestore(&sst->ipc_spin_lock, irq_flags);
+ sst->ops->post_message(sst, NULL, false);
+}
diff --git a/sound/soc/intel/sst/sst_stream.c b/sound/soc/intel/sst/sst_stream.c
new file mode 100644
index 0000000..dae2a41
--- /dev/null
+++ b/sound/soc/intel/sst/sst_stream.c
@@ -0,0 +1,437 @@
+/*
+ * sst_stream.c - Intel SST Driver for audio engine
+ *
+ * Copyright (C) 2008-14 Intel Corp
+ * Authors: Vinod Koul <vinod.koul@intel.com>
+ * Harsha Priya <priya.harsha@intel.com>
+ * Dharageswari R <dharageswari.r@intel.com>
+ * KP Jeeja <jeeja.kp@intel.com>
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+#include <linux/pci.h>
+#include <linux/firmware.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/pm_runtime.h>
+#include <sound/core.h>
+#include <sound/pcm.h>
+#include <sound/soc.h>
+#include <sound/compress_driver.h>
+#include <asm/platform_sst_audio.h>
+#include "../sst-mfld-platform.h"
+#include "sst.h"
+#include "../sst-dsp.h"
+
+int sst_alloc_stream_mrfld(struct intel_sst_drv *sst_drv_ctx, void *params)
+{
+ struct snd_sst_alloc_mrfld alloc_param;
+ struct snd_sst_params *str_params;
+ struct snd_sst_tstamp fw_tstamp;
+ struct stream_info *str_info;
+ struct snd_sst_alloc_response *response;
+ unsigned int str_id, pipe_id, task_id;
+ int i, num_ch, ret = 0;
+ void *data = NULL;
+
+ dev_dbg(sst_drv_ctx->dev, "Enter\n");
+ BUG_ON(!params);
+
+ str_params = (struct snd_sst_params *)params;
+ memset(&alloc_param, 0, sizeof(alloc_param));
+ alloc_param.operation = str_params->ops;
+ alloc_param.codec_type = str_params->codec;
+ alloc_param.sg_count = str_params->aparams.sg_count;
+ alloc_param.ring_buf_info[0].addr =
+ str_params->aparams.ring_buf_info[0].addr;
+ alloc_param.ring_buf_info[0].size =
+ str_params->aparams.ring_buf_info[0].size;
+ alloc_param.frag_size = str_params->aparams.frag_size;
+
+ memcpy(&alloc_param.codec_params, &str_params->sparams,
+ sizeof(struct snd_sst_stream_params));
+
+ /*
+ * fill channel map params for multichannel support.
+ * Ideally channel map should be received from upper layers
+ * for multichannel support.
+ * Currently hardcoding as per FW reqm.
+ */
+ num_ch = sst_get_num_channel(str_params);
+ for (i = 0; i < 8; i++) {
+ if (i < num_ch)
+ alloc_param.codec_params.uc.pcm_params.channel_map[i] = i;
+ else
+ alloc_param.codec_params.uc.pcm_params.channel_map[i] = 0xFF;
+ }
+
+ str_id = str_params->stream_id;
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (str_info == NULL) {
+ dev_err(sst_drv_ctx->dev, "get stream info returned null\n");
+ return -EINVAL;
+ }
+
+ pipe_id = str_params->device_type;
+ task_id = str_params->task;
+ sst_drv_ctx->streams[str_id].pipe_id = pipe_id;
+ sst_drv_ctx->streams[str_id].task_id = task_id;
+ sst_drv_ctx->streams[str_id].num_ch = num_ch;
+
+ if (sst_drv_ctx->info.lpe_viewpt_rqd)
+ alloc_param.ts = sst_drv_ctx->info.mailbox_start +
+ sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
+ else
+ alloc_param.ts = sst_drv_ctx->mailbox_add +
+ sst_drv_ctx->tstamp + (str_id * sizeof(fw_tstamp));
+
+ dev_dbg(sst_drv_ctx->dev, "alloc tstamp location = 0x%x\n",
+ alloc_param.ts);
+ dev_dbg(sst_drv_ctx->dev, "assigned pipe id 0x%x to task %d\n",
+ pipe_id, task_id);
+
+ /* allocate device type context */
+ sst_init_stream(&sst_drv_ctx->streams[str_id], alloc_param.codec_type,
+ str_id, alloc_param.operation, 0);
+
+ dev_info(sst_drv_ctx->dev, "Alloc for str %d pipe %#x\n",
+ str_id, pipe_id);
+ ret = sst_prepare_and_post_msg(sst_drv_ctx, task_id, IPC_CMD,
+ IPC_IA_ALLOC_STREAM_MRFLD, pipe_id, sizeof(alloc_param),
+ &alloc_param, data, true, true, false, true);
+
+ if (ret < 0) {
+ dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
+ /* alloc failed, so reset the state to uninit */
+ str_info->status = STREAM_UN_INIT;
+ str_id = ret;
+ } else if (data) {
+ response = (struct snd_sst_alloc_response *)data;
+ ret = response->str_type.result;
+ if (!ret)
+ goto out;
+ dev_err(sst_drv_ctx->dev, "FW alloc failed ret %d\n", ret);
+ if (ret == SST_ERR_STREAM_IN_USE) {
+ dev_err(sst_drv_ctx->dev,
+ "FW not in clean state, send free for:%d\n", str_id);
+ sst_free_stream(sst_drv_ctx, str_id);
+ }
+ str_id = -ret;
+ }
+out:
+ kfree(data);
+ return str_id;
+}
+
+/**
+* sst_start_stream - Send msg for a starting stream
+* @str_id: stream ID
+*
+* This function is called by any function which wants to start
+* a stream.
+*/
+int sst_start_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+ u16 data = 0;
+
+ dev_dbg(sst_drv_ctx->dev, "sst_start_stream for %d\n", str_id);
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ if (str_info->status != STREAM_RUNNING)
+ return -EBADRQC;
+
+ retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
+ IPC_CMD, IPC_IA_START_STREAM_MRFLD, str_info->pipe_id,
+ sizeof(u16), &data, NULL, true, true, true, false);
+
+ return retval;
+}
+
+int sst_send_byte_stream_mrfld(struct intel_sst_drv *sst_drv_ctx,
+ struct snd_sst_bytes_v2 *bytes)
+{ struct ipc_post *msg = NULL;
+ u32 length;
+ int pvt_id, ret = 0;
+ struct sst_block *block = NULL;
+
+ dev_dbg(sst_drv_ctx->dev,
+ "type:%u ipc_msg:%u block:%u task_id:%u pipe: %#x length:%#x\n",
+ bytes->type, bytes->ipc_msg, bytes->block, bytes->task_id,
+ bytes->pipe_id, bytes->len);
+
+ if (sst_create_ipc_msg(&msg, true))
+ return -ENOMEM;
+
+ pvt_id = sst_assign_pvt_id(sst_drv_ctx);
+ sst_fill_header_mrfld(&msg->mrfld_header, bytes->ipc_msg,
+ bytes->task_id, 1, pvt_id);
+ msg->mrfld_header.p.header_high.part.res_rqd = bytes->block;
+ length = bytes->len;
+ msg->mrfld_header.p.header_low_payload = length;
+ dev_dbg(sst_drv_ctx->dev, "length is %d\n", length);
+ memcpy(msg->mailbox_data, &bytes->bytes, bytes->len);
+ if (bytes->block) {
+ block = sst_create_block(sst_drv_ctx, bytes->ipc_msg, pvt_id);
+ if (block == NULL) {
+ kfree(msg);
+ ret = -ENOMEM;
+ goto out;
+ }
+ }
+
+ sst_add_to_dispatch_list_and_post(sst_drv_ctx, msg);
+ dev_dbg(sst_drv_ctx->dev, "msg->mrfld_header.p.header_low_payload:%d",
+ msg->mrfld_header.p.header_low_payload);
+
+ if (bytes->block) {
+ ret = sst_wait_timeout(sst_drv_ctx, block);
+ if (ret) {
+ dev_err(sst_drv_ctx->dev, "fw returned err %d\n", ret);
+ sst_free_block(sst_drv_ctx, block);
+ goto out;
+ }
+ }
+ if (bytes->type == SND_SST_BYTES_GET) {
+ /*
+ * copy the reply and send back
+ * we need to update only sz and payload
+ */
+ if (bytes->block) {
+ unsigned char *r = block->data;
+
+ dev_dbg(sst_drv_ctx->dev, "read back %d bytes",
+ bytes->len);
+ memcpy(bytes->bytes, r, bytes->len);
+ }
+ }
+ if (bytes->block)
+ sst_free_block(sst_drv_ctx, block);
+out:
+ test_and_clear_bit(pvt_id, &sst_drv_ctx->pvt_id);
+ return 0;
+}
+
+/*
+ * sst_pause_stream - Send msg for a pausing stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to pause
+ * an already running stream.
+ */
+int sst_pause_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_pause_stream for %d\n", str_id);
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ if (str_info->status == STREAM_PAUSED)
+ return 0;
+ if (str_info->status == STREAM_RUNNING ||
+ str_info->status == STREAM_INIT) {
+ if (str_info->prev == STREAM_UN_INIT)
+ return -EBADRQC;
+
+ retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
+ IPC_IA_PAUSE_STREAM_MRFLD, str_info->pipe_id,
+ 0, NULL, NULL, true, true, false, true);
+
+ if (retval == 0) {
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_PAUSED;
+ } else if (retval == SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ }
+ } else {
+ retval = -EBADRQC;
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:BADRQC for stream\n ");
+ }
+
+ return retval;
+}
+
+/**
+ * sst_resume_stream - Send msg for resuming stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to resume
+ * an already paused stream.
+ */
+int sst_resume_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_resume_stream for %d\n", str_id);
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ if (str_info->status == STREAM_RUNNING)
+ return 0;
+ if (str_info->status == STREAM_PAUSED) {
+ retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
+ IPC_CMD, IPC_IA_RESUME_STREAM_MRFLD,
+ str_info->pipe_id, 0, NULL, NULL,
+ true, true, false, true);
+
+ if (!retval) {
+ if (str_info->prev == STREAM_RUNNING)
+ str_info->status = STREAM_RUNNING;
+ else
+ str_info->status = STREAM_INIT;
+ str_info->prev = STREAM_PAUSED;
+ } else if (retval == -SST_ERR_INVALID_STREAM_ID) {
+ retval = -EINVAL;
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ }
+ } else {
+ retval = -EBADRQC;
+ dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream\n");
+ }
+
+ return retval;
+}
+
+
+/**
+ * sst_drop_stream - Send msg for stopping stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to stop
+ * a stream.
+ */
+int sst_drop_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drop_stream for %d\n", str_id);
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+
+ if (str_info->status != STREAM_UN_INIT) {
+ str_info->prev = STREAM_UN_INIT;
+ str_info->status = STREAM_INIT;
+ str_info->cumm_bytes = 0;
+ retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id,
+ IPC_CMD, IPC_IA_DROP_STREAM_MRFLD,
+ str_info->pipe_id, 0, NULL, NULL,
+ true, true, true, false);
+ } else {
+ retval = -EBADRQC;
+ dev_dbg(sst_drv_ctx->dev, "BADQRC for stream, state %x\n",
+ str_info->status);
+ }
+ return retval;
+}
+
+/**
+* sst_drain_stream - Send msg for draining stream
+* @str_id: stream ID
+*
+* This function is called by any function which wants to drain
+* a stream.
+*/
+int sst_drain_stream(struct intel_sst_drv *sst_drv_ctx,
+ int str_id, bool partial_drain)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_drain_stream for %d\n", str_id);
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ if (str_info->status != STREAM_RUNNING &&
+ str_info->status != STREAM_INIT &&
+ str_info->status != STREAM_PAUSED) {
+ dev_err(sst_drv_ctx->dev, "SST ERR: BADQRC for stream = %d\n",
+ str_info->status);
+ return -EBADRQC;
+ }
+
+ retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
+ IPC_IA_DRAIN_STREAM_MRFLD, str_info->pipe_id,
+ sizeof(u8), &partial_drain, NULL, true, true, false, false);
+ /*
+ * with new non blocked drain implementation in core we dont need to
+ * wait for respsonse, and need to only invoke callback for drain
+ * complete
+ */
+
+ return retval;
+}
+
+/**
+ * sst_free_stream - Frees a stream
+ * @str_id: stream ID
+ *
+ * This function is called by any function which wants to free
+ * a stream.
+ */
+int sst_free_stream(struct intel_sst_drv *sst_drv_ctx, int str_id)
+{
+ int retval = 0;
+ struct stream_info *str_info;
+ struct intel_sst_ops *ops;
+
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:sst_free_stream for %d\n", str_id);
+
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ if (sst_drv_ctx->sst_state == SST_RESET) {
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ return -ENODEV;
+ }
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ str_info = get_stream_info(sst_drv_ctx, str_id);
+ if (!str_info)
+ return -EINVAL;
+ ops = sst_drv_ctx->ops;
+
+ mutex_lock(&str_info->lock);
+ if (str_info->status != STREAM_UN_INIT) {
+ str_info->prev = str_info->status;
+ str_info->status = STREAM_UN_INIT;
+ mutex_unlock(&str_info->lock);
+
+ dev_info(sst_drv_ctx->dev, "Free for str %d pipe %#x\n",
+ str_id, str_info->pipe_id);
+ retval = sst_prepare_and_post_msg(sst_drv_ctx, str_info->task_id, IPC_CMD,
+ IPC_IA_FREE_STREAM_MRFLD, str_info->pipe_id, 0,
+ NULL, NULL, true, true, false, true);
+
+ dev_dbg(sst_drv_ctx->dev, "sst: wait for free returned %d\n",
+ retval);
+ mutex_lock(&sst_drv_ctx->sst_lock);
+ sst_clean_stream(str_info);
+ mutex_unlock(&sst_drv_ctx->sst_lock);
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:Stream freed\n");
+ } else {
+ mutex_unlock(&str_info->lock);
+ retval = -EBADRQC;
+ dev_dbg(sst_drv_ctx->dev, "SST DBG:BADQRC for stream\n");
+ }
+
+ return retval;
+}
diff --git a/sound/soc/jz4740/qi_lb60.c b/sound/soc/jz4740/qi_lb60.c
index 5cb91f9..0fb7d2a 100644
--- a/sound/soc/jz4740/qi_lb60.c
+++ b/sound/soc/jz4740/qi_lb60.c
@@ -77,25 +77,18 @@ static int qi_lb60_probe(struct platform_device *pdev)
{
struct qi_lb60 *qi_lb60;
struct snd_soc_card *card = &qi_lb60_card;
- int ret;
qi_lb60 = devm_kzalloc(&pdev->dev, sizeof(*qi_lb60), GFP_KERNEL);
if (!qi_lb60)
return -ENOMEM;
- qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd");
+ qi_lb60->snd_gpio = devm_gpiod_get(&pdev->dev, "snd", GPIOD_OUT_LOW);
if (IS_ERR(qi_lb60->snd_gpio))
return PTR_ERR(qi_lb60->snd_gpio);
- ret = gpiod_direction_output(qi_lb60->snd_gpio, 0);
- if (ret)
- return ret;
- qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp");
+ qi_lb60->amp_gpio = devm_gpiod_get(&pdev->dev, "amp", GPIOD_OUT_LOW);
if (IS_ERR(qi_lb60->amp_gpio))
return PTR_ERR(qi_lb60->amp_gpio);
- ret = gpiod_direction_output(qi_lb60->amp_gpio, 0);
- if (ret)
- return ret;
card->dev = &pdev->dev;
diff --git a/sound/soc/mxs/mxs-saif.c b/sound/soc/mxs/mxs-saif.c
index 231d7e7..83b2fea 100644
--- a/sound/soc/mxs/mxs-saif.c
+++ b/sound/soc/mxs/mxs-saif.c
@@ -773,7 +773,7 @@ static int mxs_saif_probe(struct platform_device *pdev)
saif->dev = &pdev->dev;
ret = devm_request_irq(&pdev->dev, saif->irq, mxs_saif_irq, 0,
- "mxs-saif", saif);
+ dev_name(&pdev->dev), saif);
if (ret) {
dev_err(&pdev->dev, "failed to request irq\n");
return ret;
diff --git a/sound/soc/mxs/mxs-sgtl5000.c b/sound/soc/mxs/mxs-sgtl5000.c
index 61822cc..3bba6cf 100644
--- a/sound/soc/mxs/mxs-sgtl5000.c
+++ b/sound/soc/mxs/mxs-sgtl5000.c
@@ -49,13 +49,6 @@ static int mxs_sgtl5000_hw_params(struct snd_pcm_substream *substream,
break;
}
- /* Sgtl5000 sysclk should be >= 8MHz and <= 27M */
- if (mclk < 8000000 || mclk > 27000000) {
- dev_err(codec_dai->dev, "Invalid mclk frequency: %u.%03uMHz\n",
- mclk / 1000000, mclk / 1000 % 1000);
- return -EINVAL;
- }
-
/* Set SGTL5000's SYSCLK (provided by SAIF MCLK) */
ret = snd_soc_dai_set_sysclk(codec_dai, SGTL5000_SYSCLK, mclk, 0);
if (ret) {
diff --git a/sound/soc/nuc900/nuc900-ac97.c b/sound/soc/nuc900/nuc900-ac97.c
index f2f67942..dff443e 100644
--- a/sound/soc/nuc900/nuc900-ac97.c
+++ b/sound/soc/nuc900/nuc900-ac97.c
@@ -298,7 +298,7 @@ static const struct snd_soc_dai_ops nuc900_ac97_dai_ops = {
static struct snd_soc_dai_driver nuc900_ac97_dai = {
.probe = nuc900_ac97_probe,
.remove = nuc900_ac97_remove,
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.rates = SNDRV_PCM_RATE_8000_48000,
.formats = SNDRV_PCM_FMTBIT_S16_LE,
diff --git a/sound/soc/omap/Kconfig b/sound/soc/omap/Kconfig
index d44463a..a2cd348 100644
--- a/sound/soc/omap/Kconfig
+++ b/sound/soc/omap/Kconfig
@@ -12,8 +12,20 @@ config SND_OMAP_SOC_MCBSP
config SND_OMAP_SOC_MCPDM
tristate
-config SND_OMAP_SOC_HDMI
- tristate
+config SND_OMAP_SOC_HDMI_AUDIO
+ tristate "HDMI audio support for OMAP4+ based SoCs"
+ depends on SND_OMAP_SOC
+ help
+ For HDMI audio to work OMAPDSS HDMI support should be
+ enabled.
+ The hdmi audio driver implements cpu-dai component using the
+ callbacks provided by OMAPDSS and registers the component
+ under DSS HDMI device. Omap-pcm is registered for platform
+ component also under DSS HDMI device. Dummy codec is used as
+ as codec component. The hdmi audio driver implements also
+ the card and registers it under its own platform device.
+ The device for the dirver is registered by OMAPDSS hdmi
+ driver.
config SND_OMAP_SOC_N810
tristate "SoC Audio support for Nokia N810"
@@ -25,15 +37,15 @@ config SND_OMAP_SOC_N810
Say Y if you want to add support for SoC audio on Nokia N810.
config SND_OMAP_SOC_RX51
- tristate "SoC Audio support for Nokia RX-51"
- depends on SND_OMAP_SOC && ARM && (MACH_NOKIA_RX51 || COMPILE_TEST) && I2C
+ tristate "SoC Audio support for Nokia N900 (RX-51)"
+ depends on SND_OMAP_SOC && ARM && I2C
select SND_OMAP_SOC_MCBSP
select SND_SOC_TLV320AIC3X
select SND_SOC_TPA6130A2
depends on GPIOLIB
help
- Say Y if you want to add support for SoC audio on Nokia RX-51
- hardware. This is also known as Nokia N900 product.
+ Say Y if you want to add support for SoC audio on Nokia N900
+ cellphone.
config SND_OMAP_SOC_AMS_DELTA
tristate "SoC Audio support for Amstrad E3 (Delta) videophone"
@@ -100,16 +112,6 @@ config SND_OMAP_SOC_OMAP_ABE_TWL6040
- PandaBoard (4430)
- PandaBoardES (4460)
-config SND_OMAP_SOC_OMAP_HDMI
- tristate "SoC Audio support for Texas Instruments OMAP HDMI"
- depends on SND_OMAP_SOC && OMAP4_DSS_HDMI && OMAP2_DSS
- select SND_OMAP_SOC_HDMI
- select SND_SOC_HDMI_CODEC
- select OMAP4_DSS_HDMI_AUDIO
- help
- Say Y if you want to add support for SoC HDMI audio on Texas Instruments
- OMAP4 chips
-
config SND_OMAP_SOC_OMAP3_PANDORA
tristate "SoC Audio support for OMAP3 Pandora"
depends on TWL4030_CORE && SND_OMAP_SOC && MACH_OMAP3_PANDORA
diff --git a/sound/soc/omap/Makefile b/sound/soc/omap/Makefile
index a725905..db36fbd 100644
--- a/sound/soc/omap/Makefile
+++ b/sound/soc/omap/Makefile
@@ -3,13 +3,13 @@ snd-soc-omap-objs := omap-pcm.o
snd-soc-omap-dmic-objs := omap-dmic.o
snd-soc-omap-mcbsp-objs := omap-mcbsp.o mcbsp.o
snd-soc-omap-mcpdm-objs := omap-mcpdm.o
-snd-soc-omap-hdmi-objs := omap-hdmi.o
+snd-soc-omap-hdmi-audio-objs := omap-hdmi-audio.o
obj-$(CONFIG_SND_OMAP_SOC) += snd-soc-omap.o
obj-$(CONFIG_SND_OMAP_SOC_DMIC) += snd-soc-omap-dmic.o
obj-$(CONFIG_SND_OMAP_SOC_MCBSP) += snd-soc-omap-mcbsp.o
obj-$(CONFIG_SND_OMAP_SOC_MCPDM) += snd-soc-omap-mcpdm.o
-obj-$(CONFIG_SND_OMAP_SOC_HDMI) += snd-soc-omap-hdmi.o
+obj-$(CONFIG_SND_OMAP_SOC_HDMI_AUDIO) += snd-soc-omap-hdmi-audio.o
# OMAP Machine Support
snd-soc-n810-objs := n810.o
@@ -20,7 +20,6 @@ snd-soc-am3517evm-objs := am3517evm.o
snd-soc-omap-abe-twl6040-objs := omap-abe-twl6040.o
snd-soc-omap-twl4030-objs := omap-twl4030.o
snd-soc-omap3pandora-objs := omap3pandora.o
-snd-soc-omap-hdmi-card-objs := omap-hdmi-card.o
obj-$(CONFIG_SND_OMAP_SOC_N810) += snd-soc-n810.o
obj-$(CONFIG_SND_OMAP_SOC_RX51) += snd-soc-rx51.o
@@ -30,4 +29,3 @@ obj-$(CONFIG_SND_OMAP_SOC_AM3517EVM) += snd-soc-am3517evm.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_ABE_TWL6040) += snd-soc-omap-abe-twl6040.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP_TWL4030) += snd-soc-omap-twl4030.o
obj-$(CONFIG_SND_OMAP_SOC_OMAP3_PANDORA) += snd-soc-omap3pandora.o
-obj-$(CONFIG_SND_OMAP_SOC_OMAP_HDMI) += snd-soc-omap-hdmi-card.o
diff --git a/sound/soc/omap/mcbsp.c b/sound/soc/omap/mcbsp.c
index 86c7538..68a1252 100644
--- a/sound/soc/omap/mcbsp.c
+++ b/sound/soc/omap/mcbsp.c
@@ -621,8 +621,7 @@ void omap_mcbsp_free(struct omap_mcbsp *mcbsp)
mcbsp->reg_cache = NULL;
spin_unlock(&mcbsp->lock);
- if (reg_cache)
- kfree(reg_cache);
+ kfree(reg_cache);
}
/*
diff --git a/sound/soc/omap/omap-hdmi-audio.c b/sound/soc/omap/omap-hdmi-audio.c
new file mode 100644
index 0000000..3f9ac7d
--- /dev/null
+++ b/sound/soc/omap/omap-hdmi-audio.c
@@ -0,0 +1,407 @@
+/*
+ * omap-hdmi-audio.c -- OMAP4+ DSS HDMI audio support library
+ *
+ * Copyright (C) 2014 Texas Instruments Incorporated - http://www.ti.com
+ *
+ * Author: Jyri Sarha <jsarha@ti.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/err.h>
+#include <linux/string.h>
+#include <linux/platform_device.h>
+#include <sound/soc.h>
+#include <sound/pcm_params.h>
+#include <sound/dmaengine_pcm.h>
+#include <uapi/sound/asound.h>
+#include <sound/asoundef.h>
+#include <sound/omap-pcm.h>
+#include <sound/omap-hdmi-audio.h>
+#include <video/omapdss.h>
+
+#define DRV_NAME "omap-hdmi-audio"
+
+struct hdmi_audio_data {
+ struct snd_soc_card *card;
+
+ const struct omap_hdmi_audio_ops *ops;
+ struct device *dssdev;
+ struct snd_dmaengine_dai_dma_data dma_data;
+ struct omap_dss_audio dss_audio;
+ struct snd_aes_iec958 iec;
+ struct snd_cea_861_aud_if cea;
+
+ struct mutex current_stream_lock;
+ struct snd_pcm_substream *current_stream;
+};
+
+static
+struct hdmi_audio_data *card_drvdata_substream(struct snd_pcm_substream *ss)
+{
+ struct snd_soc_pcm_runtime *rtd = ss->private_data;
+
+ return snd_soc_card_get_drvdata(rtd->card);
+}
+
+static void hdmi_dai_abort(struct device *dev)
+{
+ struct hdmi_audio_data *ad = dev_get_drvdata(dev);
+
+ mutex_lock(&ad->current_stream_lock);
+ if (ad->current_stream && ad->current_stream->runtime &&
+ snd_pcm_running(ad->current_stream)) {
+ dev_err(dev, "HDMI display disabled, aborting playback\n");
+ snd_pcm_stream_lock_irq(ad->current_stream);
+ snd_pcm_stop(ad->current_stream, SNDRV_PCM_STATE_DISCONNECTED);
+ snd_pcm_stream_unlock_irq(ad->current_stream);
+ }
+ mutex_unlock(&ad->current_stream_lock);
+}
+
+static int hdmi_dai_startup(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+ int ret;
+ /*
+ * Make sure that the period bytes are multiple of the DMA packet size.
+ * Largest packet size we use is 32 32-bit words = 128 bytes
+ */
+ ret = snd_pcm_hw_constraint_step(substream->runtime, 0,
+ SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
+ if (ret < 0) {
+ dev_err(dai->dev, "could not apply constraint\n");
+ return ret;
+ }
+
+ snd_soc_dai_set_dma_data(dai, substream, &ad->dma_data);
+
+ mutex_lock(&ad->current_stream_lock);
+ ad->current_stream = substream;
+ mutex_unlock(&ad->current_stream_lock);
+
+ ret = ad->ops->audio_startup(ad->dssdev, hdmi_dai_abort);
+
+ if (ret) {
+ mutex_lock(&ad->current_stream_lock);
+ ad->current_stream = NULL;
+ mutex_unlock(&ad->current_stream_lock);
+ }
+
+ return ret;
+}
+
+static int hdmi_dai_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+ struct snd_aes_iec958 *iec = &ad->iec;
+ struct snd_cea_861_aud_if *cea = &ad->cea;
+
+ WARN_ON(ad->current_stream != substream);
+
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ ad->dma_data.maxburst = 16;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ ad->dma_data.maxburst = 32;
+ break;
+ default:
+ dev_err(dai->dev, "format not supported!\n");
+ return -EINVAL;
+ }
+
+ ad->dss_audio.iec = iec;
+ ad->dss_audio.cea = cea;
+ /*
+ * fill the IEC-60958 channel status word
+ */
+ /* initialize the word bytes */
+ memset(iec->status, 0, sizeof(iec->status));
+
+ /* specify IEC-60958-3 (commercial use) */
+ iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
+
+ /* specify that the audio is LPCM*/
+ iec->status[0] &= ~IEC958_AES0_NONAUDIO;
+
+ iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
+
+ iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
+
+ iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
+
+ iec->status[1] = IEC958_AES1_CON_GENERAL;
+
+ iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
+
+ iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
+
+ switch (params_rate(params)) {
+ case 32000:
+ iec->status[3] |= IEC958_AES3_CON_FS_32000;
+ break;
+ case 44100:
+ iec->status[3] |= IEC958_AES3_CON_FS_44100;
+ break;
+ case 48000:
+ iec->status[3] |= IEC958_AES3_CON_FS_48000;
+ break;
+ case 88200:
+ iec->status[3] |= IEC958_AES3_CON_FS_88200;
+ break;
+ case 96000:
+ iec->status[3] |= IEC958_AES3_CON_FS_96000;
+ break;
+ case 176400:
+ iec->status[3] |= IEC958_AES3_CON_FS_176400;
+ break;
+ case 192000:
+ iec->status[3] |= IEC958_AES3_CON_FS_192000;
+ break;
+ default:
+ dev_err(dai->dev, "rate not supported!\n");
+ return -EINVAL;
+ }
+
+ /* specify the clock accuracy */
+ iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
+
+ /*
+ * specify the word length. The same word length value can mean
+ * two different lengths. Hence, we need to specify the maximum
+ * word length as well.
+ */
+ switch (params_format(params)) {
+ case SNDRV_PCM_FORMAT_S16_LE:
+ iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
+ iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
+ break;
+ case SNDRV_PCM_FORMAT_S24_LE:
+ iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
+ iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
+ break;
+ default:
+ dev_err(dai->dev, "format not supported!\n");
+ return -EINVAL;
+ }
+
+ /*
+ * Fill the CEA-861 audio infoframe (see spec for details)
+ */
+
+ cea->db1_ct_cc = (params_channels(params) - 1)
+ & CEA861_AUDIO_INFOFRAME_DB1CC;
+ cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
+
+ cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
+ cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
+
+ cea->db3 = 0; /* not used, all zeros */
+
+ /*
+ * The OMAP HDMI IP requires to use the 8-channel channel code when
+ * transmitting more than two channels.
+ */
+ if (params_channels(params) == 2)
+ cea->db4_ca = 0x0;
+ else
+ cea->db4_ca = 0x13;
+
+ cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
+ /* the expression is trivial but makes clear what we are doing */
+ cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
+
+ return ad->ops->audio_config(ad->dssdev, &ad->dss_audio);
+}
+
+static int hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+ int err = 0;
+
+ WARN_ON(ad->current_stream != substream);
+
+ switch (cmd) {
+ case SNDRV_PCM_TRIGGER_START:
+ case SNDRV_PCM_TRIGGER_RESUME:
+ case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
+ err = ad->ops->audio_start(ad->dssdev);
+ break;
+ case SNDRV_PCM_TRIGGER_STOP:
+ case SNDRV_PCM_TRIGGER_SUSPEND:
+ case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
+ ad->ops->audio_stop(ad->dssdev);
+ break;
+ default:
+ err = -EINVAL;
+ }
+ return err;
+}
+
+static void hdmi_dai_shutdown(struct snd_pcm_substream *substream,
+ struct snd_soc_dai *dai)
+{
+ struct hdmi_audio_data *ad = card_drvdata_substream(substream);
+
+ WARN_ON(ad->current_stream != substream);
+
+ ad->ops->audio_shutdown(ad->dssdev);
+
+ mutex_lock(&ad->current_stream_lock);
+ ad->current_stream = NULL;
+ mutex_unlock(&ad->current_stream_lock);
+}
+
+static const struct snd_soc_dai_ops hdmi_dai_ops = {
+ .startup = hdmi_dai_startup,
+ .hw_params = hdmi_dai_hw_params,
+ .trigger = hdmi_dai_trigger,
+ .shutdown = hdmi_dai_shutdown,
+};
+
+static const struct snd_soc_component_driver omap_hdmi_component = {
+ .name = "omapdss_hdmi",
+};
+
+static struct snd_soc_dai_driver omap5_hdmi_dai = {
+ .name = "omap5-hdmi-dai",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE,
+ },
+ .ops = &hdmi_dai_ops,
+};
+
+static struct snd_soc_dai_driver omap4_hdmi_dai = {
+ .name = "omap4-hdmi-dai",
+ .playback = {
+ .channels_min = 2,
+ .channels_max = 8,
+ .rates = (SNDRV_PCM_RATE_32000 | SNDRV_PCM_RATE_44100 |
+ SNDRV_PCM_RATE_48000 | SNDRV_PCM_RATE_88200 |
+ SNDRV_PCM_RATE_96000 | SNDRV_PCM_RATE_176400 |
+ SNDRV_PCM_RATE_192000),
+ .formats = SNDRV_PCM_FMTBIT_S16_LE | SNDRV_PCM_FMTBIT_S24_LE,
+ },
+ .ops = &hdmi_dai_ops,
+};
+
+static int omap_hdmi_audio_probe(struct platform_device *pdev)
+{
+ struct omap_hdmi_audio_pdata *ha = pdev->dev.platform_data;
+ struct device *dev = &pdev->dev;
+ struct hdmi_audio_data *ad;
+ struct snd_soc_dai_driver *dai_drv;
+ struct snd_soc_card *card;
+ int ret;
+
+ if (!ha) {
+ dev_err(dev, "No platform data\n");
+ return -EINVAL;
+ }
+
+ ad = devm_kzalloc(dev, sizeof(*ad), GFP_KERNEL);
+ if (!ad)
+ return -ENOMEM;
+ ad->dssdev = ha->dev;
+ ad->ops = ha->ops;
+ ad->dma_data.addr = ha->audio_dma_addr;
+ ad->dma_data.filter_data = "audio_tx";
+ ad->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
+ mutex_init(&ad->current_stream_lock);
+
+ switch (ha->dss_version) {
+ case OMAPDSS_VER_OMAP4430_ES1:
+ case OMAPDSS_VER_OMAP4430_ES2:
+ case OMAPDSS_VER_OMAP4:
+ dai_drv = &omap4_hdmi_dai;
+ break;
+ case OMAPDSS_VER_OMAP5:
+ dai_drv = &omap5_hdmi_dai;
+ break;
+ default:
+ return -EINVAL;
+ }
+ ret = snd_soc_register_component(ad->dssdev, &omap_hdmi_component,
+ dai_drv, 1);
+ if (ret)
+ return ret;
+
+ ret = omap_pcm_platform_register(ad->dssdev);
+ if (ret)
+ return ret;
+
+ card = devm_kzalloc(dev, sizeof(*card), GFP_KERNEL);
+ card->name = devm_kasprintf(dev, GFP_KERNEL,
+ "HDMI %s", dev_name(ad->dssdev));
+ card->owner = THIS_MODULE;
+ card->dai_link =
+ devm_kzalloc(dev, sizeof(*(card->dai_link)), GFP_KERNEL);
+ card->dai_link->name = card->name;
+ card->dai_link->stream_name = card->name;
+ card->dai_link->cpu_dai_name = dev_name(ad->dssdev);
+ card->dai_link->platform_name = dev_name(ad->dssdev);
+ card->dai_link->codec_name = "snd-soc-dummy";
+ card->dai_link->codec_dai_name = "snd-soc-dummy-dai";
+ card->num_links = 1;
+ card->dev = dev;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(dev, "snd_soc_register_card failed (%d)\n", ret);
+ snd_soc_unregister_component(ad->dssdev);
+ return ret;
+ }
+
+ ad->card = card;
+ snd_soc_card_set_drvdata(card, ad);
+
+ dev_set_drvdata(dev, ad);
+
+ return 0;
+}
+
+static int omap_hdmi_audio_remove(struct platform_device *pdev)
+{
+ struct hdmi_audio_data *ad = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(ad->card);
+ snd_soc_unregister_component(ad->dssdev);
+ return 0;
+}
+
+static struct platform_driver hdmi_audio_driver = {
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = omap_hdmi_audio_probe,
+ .remove = omap_hdmi_audio_remove,
+};
+
+module_platform_driver(hdmi_audio_driver);
+
+MODULE_AUTHOR("Jyri Sarha <jsarha@ti.com>");
+MODULE_DESCRIPTION("OMAP HDMI Audio Driver");
+MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi-card.c b/sound/soc/omap/omap-hdmi-card.c
deleted file mode 100644
index f649fe8..0000000
--- a/sound/soc/omap/omap-hdmi-card.c
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * omap-hdmi-card.c
- *
- * OMAP ALSA SoC machine driver for TI OMAP HDMI
- * Copyright (C) 2011 Texas Instruments Incorporated - http://www.ti.com/
- * Author: Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/module.h>
-#include <sound/pcm.h>
-#include <sound/soc.h>
-#include <asm/mach-types.h>
-#include <video/omapdss.h>
-
-#define DRV_NAME "omap-hdmi-audio"
-
-static struct snd_soc_dai_link omap_hdmi_dai = {
- .name = "HDMI",
- .stream_name = "HDMI",
- .cpu_dai_name = "omap-hdmi-audio-dai",
- .platform_name = "omap-hdmi-audio-dai",
- .codec_name = "hdmi-audio-codec",
- .codec_dai_name = "hdmi-hifi",
-};
-
-static struct snd_soc_card snd_soc_omap_hdmi = {
- .name = "OMAPHDMI",
- .owner = THIS_MODULE,
- .dai_link = &omap_hdmi_dai,
- .num_links = 1,
-};
-
-static int omap_hdmi_probe(struct platform_device *pdev)
-{
- struct snd_soc_card *card = &snd_soc_omap_hdmi;
- int ret;
-
- card->dev = &pdev->dev;
-
- ret = snd_soc_register_card(card);
- if (ret) {
- dev_err(&pdev->dev, "snd_soc_register_card failed (%d)\n", ret);
- card->dev = NULL;
- return ret;
- }
- return 0;
-}
-
-static int omap_hdmi_remove(struct platform_device *pdev)
-{
- struct snd_soc_card *card = platform_get_drvdata(pdev);
-
- snd_soc_unregister_card(card);
- card->dev = NULL;
- return 0;
-}
-
-static struct platform_driver omap_hdmi_driver = {
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
- .probe = omap_hdmi_probe,
- .remove = omap_hdmi_remove,
-};
-
-module_platform_driver(omap_hdmi_driver);
-
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("OMAP HDMI machine ASoC driver");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.c b/sound/soc/omap/omap-hdmi.c
deleted file mode 100644
index eb9c392..0000000
--- a/sound/soc/omap/omap-hdmi.c
+++ /dev/null
@@ -1,364 +0,0 @@
-/*
- * omap-hdmi.c
- *
- * OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
- * Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/device.h>
-#include <sound/core.h>
-#include <sound/pcm.h>
-#include <sound/pcm_params.h>
-#include <sound/initval.h>
-#include <sound/soc.h>
-#include <sound/asound.h>
-#include <sound/asoundef.h>
-#include <sound/dmaengine_pcm.h>
-#include <video/omapdss.h>
-#include <sound/omap-pcm.h>
-
-#include "omap-hdmi.h"
-
-#define DRV_NAME "omap-hdmi-audio-dai"
-
-struct hdmi_priv {
- struct snd_dmaengine_dai_dma_data dma_data;
- unsigned int dma_req;
- struct omap_dss_audio dss_audio;
- struct snd_aes_iec958 iec;
- struct snd_cea_861_aud_if cea;
- struct omap_dss_device *dssdev;
-};
-
-static int omap_hdmi_dai_startup(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
- int err;
- /*
- * Make sure that the period bytes are multiple of the DMA packet size.
- * Largest packet size we use is 32 32-bit words = 128 bytes
- */
- err = snd_pcm_hw_constraint_step(substream->runtime, 0,
- SNDRV_PCM_HW_PARAM_PERIOD_BYTES, 128);
- if (err < 0) {
- dev_err(dai->dev, "could not apply constraint\n");
- return err;
- }
-
- if (!priv->dssdev->driver->audio_supported(priv->dssdev)) {
- dev_err(dai->dev, "audio not supported\n");
- return -ENODEV;
- }
-
- snd_soc_dai_set_dma_data(dai, substream, &priv->dma_data);
-
- return 0;
-}
-
-static int omap_hdmi_dai_prepare(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-
- return priv->dssdev->driver->audio_enable(priv->dssdev);
-}
-
-static int omap_hdmi_dai_hw_params(struct snd_pcm_substream *substream,
- struct snd_pcm_hw_params *params,
- struct snd_soc_dai *dai)
-{
- struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
- struct snd_aes_iec958 *iec = &priv->iec;
- struct snd_cea_861_aud_if *cea = &priv->cea;
- int err = 0;
-
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- priv->dma_data.maxburst = 16;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- priv->dma_data.maxburst = 32;
- break;
- default:
- dev_err(dai->dev, "format not supported!\n");
- return -EINVAL;
- }
-
- /*
- * fill the IEC-60958 channel status word
- */
- /* initialize the word bytes */
- memset(iec->status, 0, sizeof(iec->status));
-
- /* specify IEC-60958-3 (commercial use) */
- iec->status[0] &= ~IEC958_AES0_PROFESSIONAL;
-
- /* specify that the audio is LPCM*/
- iec->status[0] &= ~IEC958_AES0_NONAUDIO;
-
- iec->status[0] |= IEC958_AES0_CON_NOT_COPYRIGHT;
-
- iec->status[0] |= IEC958_AES0_CON_EMPHASIS_NONE;
-
- iec->status[0] |= IEC958_AES1_PRO_MODE_NOTID;
-
- iec->status[1] = IEC958_AES1_CON_GENERAL;
-
- iec->status[2] |= IEC958_AES2_CON_SOURCE_UNSPEC;
-
- iec->status[2] |= IEC958_AES2_CON_CHANNEL_UNSPEC;
-
- switch (params_rate(params)) {
- case 32000:
- iec->status[3] |= IEC958_AES3_CON_FS_32000;
- break;
- case 44100:
- iec->status[3] |= IEC958_AES3_CON_FS_44100;
- break;
- case 48000:
- iec->status[3] |= IEC958_AES3_CON_FS_48000;
- break;
- case 88200:
- iec->status[3] |= IEC958_AES3_CON_FS_88200;
- break;
- case 96000:
- iec->status[3] |= IEC958_AES3_CON_FS_96000;
- break;
- case 176400:
- iec->status[3] |= IEC958_AES3_CON_FS_176400;
- break;
- case 192000:
- iec->status[3] |= IEC958_AES3_CON_FS_192000;
- break;
- default:
- dev_err(dai->dev, "rate not supported!\n");
- return -EINVAL;
- }
-
- /* specify the clock accuracy */
- iec->status[3] |= IEC958_AES3_CON_CLOCK_1000PPM;
-
- /*
- * specify the word length. The same word length value can mean
- * two different lengths. Hence, we need to specify the maximum
- * word length as well.
- */
- switch (params_format(params)) {
- case SNDRV_PCM_FORMAT_S16_LE:
- iec->status[4] |= IEC958_AES4_CON_WORDLEN_20_16;
- iec->status[4] &= ~IEC958_AES4_CON_MAX_WORDLEN_24;
- break;
- case SNDRV_PCM_FORMAT_S24_LE:
- iec->status[4] |= IEC958_AES4_CON_WORDLEN_24_20;
- iec->status[4] |= IEC958_AES4_CON_MAX_WORDLEN_24;
- break;
- default:
- dev_err(dai->dev, "format not supported!\n");
- return -EINVAL;
- }
-
- /*
- * Fill the CEA-861 audio infoframe (see spec for details)
- */
-
- cea->db1_ct_cc = (params_channels(params) - 1)
- & CEA861_AUDIO_INFOFRAME_DB1CC;
- cea->db1_ct_cc |= CEA861_AUDIO_INFOFRAME_DB1CT_FROM_STREAM;
-
- cea->db2_sf_ss = CEA861_AUDIO_INFOFRAME_DB2SF_FROM_STREAM;
- cea->db2_sf_ss |= CEA861_AUDIO_INFOFRAME_DB2SS_FROM_STREAM;
-
- cea->db3 = 0; /* not used, all zeros */
-
- /*
- * The OMAP HDMI IP requires to use the 8-channel channel code when
- * transmitting more than two channels.
- */
- if (params_channels(params) == 2)
- cea->db4_ca = 0x0;
- else
- cea->db4_ca = 0x13;
-
- cea->db5_dminh_lsv = CEA861_AUDIO_INFOFRAME_DB5_DM_INH_PROHIBITED;
- /* the expression is trivial but makes clear what we are doing */
- cea->db5_dminh_lsv |= (0 & CEA861_AUDIO_INFOFRAME_DB5_LSV);
-
- priv->dss_audio.iec = iec;
- priv->dss_audio.cea = cea;
-
- err = priv->dssdev->driver->audio_config(priv->dssdev,
- &priv->dss_audio);
-
- return err;
-}
-
-static int omap_hdmi_dai_trigger(struct snd_pcm_substream *substream, int cmd,
- struct snd_soc_dai *dai)
-{
- struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
- int err = 0;
-
- switch (cmd) {
- case SNDRV_PCM_TRIGGER_START:
- case SNDRV_PCM_TRIGGER_RESUME:
- case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
- err = priv->dssdev->driver->audio_start(priv->dssdev);
- break;
- case SNDRV_PCM_TRIGGER_STOP:
- case SNDRV_PCM_TRIGGER_SUSPEND:
- case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
- priv->dssdev->driver->audio_stop(priv->dssdev);
- break;
- default:
- err = -EINVAL;
- }
- return err;
-}
-
-static void omap_hdmi_dai_shutdown(struct snd_pcm_substream *substream,
- struct snd_soc_dai *dai)
-{
- struct hdmi_priv *priv = snd_soc_dai_get_drvdata(dai);
-
- priv->dssdev->driver->audio_disable(priv->dssdev);
-}
-
-static const struct snd_soc_dai_ops omap_hdmi_dai_ops = {
- .startup = omap_hdmi_dai_startup,
- .hw_params = omap_hdmi_dai_hw_params,
- .prepare = omap_hdmi_dai_prepare,
- .trigger = omap_hdmi_dai_trigger,
- .shutdown = omap_hdmi_dai_shutdown,
-};
-
-static struct snd_soc_dai_driver omap_hdmi_dai = {
- .playback = {
- .channels_min = 2,
- .channels_max = 8,
- .rates = OMAP_HDMI_RATES,
- .formats = OMAP_HDMI_FORMATS,
- },
- .ops = &omap_hdmi_dai_ops,
-};
-
-static const struct snd_soc_component_driver omap_hdmi_component = {
- .name = DRV_NAME,
-};
-
-static int omap_hdmi_probe(struct platform_device *pdev)
-{
- int ret;
- struct resource *hdmi_rsrc;
- struct hdmi_priv *hdmi_data;
- bool hdmi_dev_found = false;
-
- hdmi_data = devm_kzalloc(&pdev->dev, sizeof(*hdmi_data), GFP_KERNEL);
- if (hdmi_data == NULL) {
- dev_err(&pdev->dev, "Cannot allocate memory for HDMI data\n");
- return -ENOMEM;
- }
-
- hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_MEM, 0);
- if (!hdmi_rsrc) {
- dev_err(&pdev->dev, "Cannot obtain IORESOURCE_MEM HDMI\n");
- return -ENODEV;
- }
-
- hdmi_data->dma_data.addr = hdmi_rsrc->start + OMAP_HDMI_AUDIO_DMA_PORT;
-
- hdmi_rsrc = platform_get_resource(pdev, IORESOURCE_DMA, 0);
- if (!hdmi_rsrc) {
- dev_err(&pdev->dev, "Cannot obtain IORESOURCE_DMA HDMI\n");
- return -ENODEV;
- }
-
- hdmi_data->dma_req = hdmi_rsrc->start;
- hdmi_data->dma_data.filter_data = &hdmi_data->dma_req;
- hdmi_data->dma_data.addr_width = DMA_SLAVE_BUSWIDTH_4_BYTES;
-
- /*
- * TODO: We assume that there is only one DSS HDMI device. Future
- * OMAP implementations may support more than one HDMI devices and
- * we should provided separate audio support for all of them.
- */
- /* Find an HDMI device. */
- for_each_dss_dev(hdmi_data->dssdev) {
- omap_dss_get_device(hdmi_data->dssdev);
-
- if (!hdmi_data->dssdev->driver) {
- omap_dss_put_device(hdmi_data->dssdev);
- continue;
- }
-
- if (hdmi_data->dssdev->type == OMAP_DISPLAY_TYPE_HDMI) {
- hdmi_dev_found = true;
- break;
- }
- }
-
- if (!hdmi_dev_found) {
- dev_err(&pdev->dev, "no driver for HDMI display found\n");
- return -ENODEV;
- }
-
- dev_set_drvdata(&pdev->dev, hdmi_data);
- ret = snd_soc_register_component(&pdev->dev, &omap_hdmi_component,
- &omap_hdmi_dai, 1);
-
- if (ret)
- return ret;
-
- return omap_pcm_platform_register(&pdev->dev);
-}
-
-static int omap_hdmi_remove(struct platform_device *pdev)
-{
- struct hdmi_priv *hdmi_data = dev_get_drvdata(&pdev->dev);
-
- snd_soc_unregister_component(&pdev->dev);
-
- if (hdmi_data == NULL) {
- dev_err(&pdev->dev, "cannot obtain HDMi data\n");
- return -ENODEV;
- }
-
- omap_dss_put_device(hdmi_data->dssdev);
- return 0;
-}
-
-static struct platform_driver hdmi_dai_driver = {
- .driver = {
- .name = DRV_NAME,
- .owner = THIS_MODULE,
- },
- .probe = omap_hdmi_probe,
- .remove = omap_hdmi_remove,
-};
-
-module_platform_driver(hdmi_dai_driver);
-
-MODULE_AUTHOR("Jorge Candelaria <jorge.candelaria@ti.com>");
-MODULE_AUTHOR("Ricardo Neri <ricardo.neri@ti.com>");
-MODULE_DESCRIPTION("OMAP HDMI SoC Interface");
-MODULE_LICENSE("GPL");
-MODULE_ALIAS("platform:" DRV_NAME);
diff --git a/sound/soc/omap/omap-hdmi.h b/sound/soc/omap/omap-hdmi.h
deleted file mode 100644
index 6ad2bf4..0000000
--- a/sound/soc/omap/omap-hdmi.h
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * omap-hdmi.h
- *
- * Definitions for OMAP ALSA SoC DAI driver for HDMI audio on OMAP4 processors.
- * Copyright (C) 2010-2011 Texas Instruments Incorporated - http://www.ti.com/
- * Authors: Jorge Candelaria <jorge.candelaria@ti.com>
- * Ricardo Neri <ricardo.neri@ti.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
- * 02110-1301 USA
- *
- */
-
-#ifndef __OMAP_HDMI_H__
-#define __OMAP_HDMI_H__
-
-#define OMAP_HDMI_AUDIO_DMA_PORT 0x8c
-
-#define OMAP_HDMI_RATES (SNDRV_PCM_RATE_32000 | \
- SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000 | \
- SNDRV_PCM_RATE_88200 | SNDRV_PCM_RATE_96000 | \
- SNDRV_PCM_RATE_176400 | SNDRV_PCM_RATE_192000)
-
-#define OMAP_HDMI_FORMATS (SNDRV_PCM_FMTBIT_S16_LE | \
- SNDRV_PCM_FMTBIT_S24_LE)
-
-#endif
diff --git a/sound/soc/pxa/mioa701_wm9713.c b/sound/soc/pxa/mioa701_wm9713.c
index 595eee3..a6b2be2 100644
--- a/sound/soc/pxa/mioa701_wm9713.c
+++ b/sound/soc/pxa/mioa701_wm9713.c
@@ -127,15 +127,12 @@ static const struct snd_soc_dapm_route audio_map[] = {
static int mioa701_wm9713_init(struct snd_soc_pcm_runtime *rtd)
{
struct snd_soc_codec *codec = rtd->codec;
- unsigned short reg;
/* Prepare GPIO8 for rear speaker amplifier */
- reg = codec->driver->read(codec, AC97_GPIO_CFG);
- codec->driver->write(codec, AC97_GPIO_CFG, reg | 0x0100);
+ snd_soc_update_bits(codec, AC97_GPIO_CFG, 0x100, 0x100);
/* Prepare MIC input */
- reg = codec->driver->read(codec, AC97_3D_CONTROL);
- codec->driver->write(codec, AC97_3D_CONTROL, reg | 0xc000);
+ snd_soc_update_bits(codec, AC97_3D_CONTROL, 0xc000, 0xc000);
return 0;
}
diff --git a/sound/soc/pxa/pxa-ssp.c b/sound/soc/pxa/pxa-ssp.c
index a8e0974..cbba063 100644
--- a/sound/soc/pxa/pxa-ssp.c
+++ b/sound/soc/pxa/pxa-ssp.c
@@ -97,7 +97,7 @@ static int pxa_ssp_startup(struct snd_pcm_substream *substream,
int ret = 0;
if (!cpu_dai->active) {
- clk_enable(ssp->clk);
+ clk_prepare_enable(ssp->clk);
pxa_ssp_disable(ssp);
}
@@ -121,7 +121,7 @@ static void pxa_ssp_shutdown(struct snd_pcm_substream *substream,
if (!cpu_dai->active) {
pxa_ssp_disable(ssp);
- clk_disable(ssp->clk);
+ clk_disable_unprepare(ssp->clk);
}
kfree(snd_soc_dai_get_dma_data(cpu_dai, substream));
@@ -136,7 +136,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
struct ssp_device *ssp = priv->ssp;
if (!cpu_dai->active)
- clk_enable(ssp->clk);
+ clk_prepare_enable(ssp->clk);
priv->cr0 = __raw_readl(ssp->mmio_base + SSCR0);
priv->cr1 = __raw_readl(ssp->mmio_base + SSCR1);
@@ -144,7 +144,7 @@ static int pxa_ssp_suspend(struct snd_soc_dai *cpu_dai)
priv->psp = __raw_readl(ssp->mmio_base + SSPSP);
pxa_ssp_disable(ssp);
- clk_disable(ssp->clk);
+ clk_disable_unprepare(ssp->clk);
return 0;
}
@@ -154,7 +154,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
struct ssp_device *ssp = priv->ssp;
uint32_t sssr = SSSR_ROR | SSSR_TUR | SSSR_BCE;
- clk_enable(ssp->clk);
+ clk_prepare_enable(ssp->clk);
__raw_writel(sssr, ssp->mmio_base + SSSR);
__raw_writel(priv->cr0 & ~SSCR0_SSE, ssp->mmio_base + SSCR0);
@@ -165,7 +165,7 @@ static int pxa_ssp_resume(struct snd_soc_dai *cpu_dai)
if (cpu_dai->active)
pxa_ssp_enable(ssp);
else
- clk_disable(ssp->clk);
+ clk_disable_unprepare(ssp->clk);
return 0;
}
@@ -256,11 +256,11 @@ static int pxa_ssp_set_dai_sysclk(struct snd_soc_dai *cpu_dai,
/* The SSP clock must be disabled when changing SSP clock mode
* on PXA2xx. On PXA3xx it must be enabled when doing so. */
if (ssp->type != PXA3xx_SSP)
- clk_disable(ssp->clk);
+ clk_disable_unprepare(ssp->clk);
val = pxa_ssp_read_reg(ssp, SSCR0) | sscr0;
pxa_ssp_write_reg(ssp, SSCR0, val);
if (ssp->type != PXA3xx_SSP)
- clk_enable(ssp->clk);
+ clk_prepare_enable(ssp->clk);
return 0;
}
diff --git a/sound/soc/pxa/pxa2xx-ac97.c b/sound/soc/pxa/pxa2xx-ac97.c
index ae956e3..73ca282 100644
--- a/sound/soc/pxa/pxa2xx-ac97.c
+++ b/sound/soc/pxa/pxa2xx-ac97.c
@@ -157,7 +157,7 @@ static const struct snd_soc_dai_ops pxa_ac97_mic_dai_ops = {
static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
{
.name = "pxa2xx-ac97",
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
@@ -174,7 +174,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
},
{
.name = "pxa2xx-ac97-aux",
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.stream_name = "AC97 Aux Playback",
.channels_min = 1,
@@ -191,7 +191,7 @@ static struct snd_soc_dai_driver pxa_ac97_dai_driver[] = {
},
{
.name = "pxa2xx-ac97-mic",
- .ac97_control = 1,
+ .bus_control = true,
.capture = {
.stream_name = "AC97 Mic Capture",
.channels_min = 1,
diff --git a/sound/soc/pxa/spitz.c b/sound/soc/pxa/spitz.c
index 1373b01..d7d5fb2 100644
--- a/sound/soc/pxa/spitz.c
+++ b/sound/soc/pxa/spitz.c
@@ -305,19 +305,15 @@ static struct snd_soc_card snd_soc_spitz = {
.num_dapm_routes = ARRAY_SIZE(spitz_audio_map),
};
-static struct platform_device *spitz_snd_device;
-
-static int __init spitz_init(void)
+static int spitz_probe(struct platform_device *pdev)
{
+ struct snd_soc_card *card = &snd_soc_spitz;
int ret;
- if (!(machine_is_spitz() || machine_is_borzoi() || machine_is_akita()))
- return -ENODEV;
-
- if (machine_is_borzoi() || machine_is_spitz())
- spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
- else
+ if (machine_is_akita())
spitz_mic_gpio = AKITA_GPIO_MIC_BIAS;
+ else
+ spitz_mic_gpio = SPITZ_GPIO_MIC_BIAS;
ret = gpio_request(spitz_mic_gpio, "MIC GPIO");
if (ret)
@@ -327,37 +323,45 @@ static int __init spitz_init(void)
if (ret)
goto err2;
- spitz_snd_device = platform_device_alloc("soc-audio", -1);
- if (!spitz_snd_device) {
- ret = -ENOMEM;
+ card->dev = &pdev->dev;
+
+ ret = snd_soc_register_card(card);
+ if (ret) {
+ dev_err(&pdev->dev, "snd_soc_register_card() failed: %d\n",
+ ret);
goto err2;
}
- platform_set_drvdata(spitz_snd_device, &snd_soc_spitz);
-
- ret = platform_device_add(spitz_snd_device);
- if (ret)
- goto err3;
-
return 0;
-err3:
- platform_device_put(spitz_snd_device);
err2:
gpio_free(spitz_mic_gpio);
err1:
return ret;
}
-static void __exit spitz_exit(void)
+static int spitz_remove(struct platform_device *pdev)
{
- platform_device_unregister(spitz_snd_device);
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
gpio_free(spitz_mic_gpio);
+ return 0;
}
-module_init(spitz_init);
-module_exit(spitz_exit);
+static struct platform_driver spitz_driver = {
+ .driver = {
+ .name = "spitz-audio",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ },
+ .probe = spitz_probe,
+ .remove = spitz_remove,
+};
+
+module_platform_driver(spitz_driver);
MODULE_AUTHOR("Richard Purdie");
MODULE_DESCRIPTION("ALSA SoC Spitz");
MODULE_LICENSE("GPL");
+MODULE_ALIAS("platform:spitz-audio");
diff --git a/sound/soc/rockchip/Kconfig b/sound/soc/rockchip/Kconfig
index 78fc159..e181826 100644
--- a/sound/soc/rockchip/Kconfig
+++ b/sound/soc/rockchip/Kconfig
@@ -1,11 +1,16 @@
config SND_SOC_ROCKCHIP
tristate "ASoC support for Rockchip"
depends on COMPILE_TEST || ARCH_ROCKCHIP
- select SND_SOC_GENERIC_DMAENGINE_PCM
help
Say Y or M if you want to add support for codecs attached to
the Rockchip SoCs' Audio interfaces. You will also need to
select the audio interfaces to support below.
config SND_SOC_ROCKCHIP_I2S
- tristate
+ tristate "Rockchip I2S Device Driver"
+ depends on CLKDEV_LOOKUP && SND_SOC_ROCKCHIP
+ select SND_SOC_GENERIC_DMAENGINE_PCM
+ help
+ Say Y or M if you want to add support for I2S driver for
+ Rockchip I2S device. The device supports upto maximum of
+ 8 channels each for play and record.
diff --git a/sound/soc/samsung/Kconfig b/sound/soc/samsung/Kconfig
index 55a3869..fc67f97 100644
--- a/sound/soc/samsung/Kconfig
+++ b/sound/soc/samsung/Kconfig
@@ -1,6 +1,6 @@
config SND_SOC_SAMSUNG
tristate "ASoC support for Samsung"
- depends on PLAT_SAMSUNG
+ depends on (PLAT_SAMSUNG || ARCH_EXYNOS)
depends on S3C64XX_PL080 || !ARCH_S3C64XX
depends on S3C24XX_DMAC || !ARCH_S3C24XX
select SND_SOC_GENERIC_DMAENGINE_PCM
@@ -239,3 +239,9 @@ config SND_SOC_ODROIDX2
select SND_SAMSUNG_I2S
help
Say Y here to enable audio support for the Odroid-X2/U3.
+
+config SND_SOC_ARNDALE_RT5631_ALC5631
+ tristate "Audio support for RT5631(ALC5631) on Arndale Board"
+ depends on SND_SOC_SAMSUNG
+ select SND_SAMSUNG_I2S
+ select SND_SOC_RT5631
diff --git a/sound/soc/samsung/Makefile b/sound/soc/samsung/Makefile
index 91505dd..31e3dba 100644
--- a/sound/soc/samsung/Makefile
+++ b/sound/soc/samsung/Makefile
@@ -45,6 +45,7 @@ snd-soc-lowland-objs := lowland.o
snd-soc-littlemill-objs := littlemill.o
snd-soc-bells-objs := bells.o
snd-soc-odroidx2-max98090-objs := odroidx2_max98090.o
+snd-soc-arndale-rt5631-objs := arndale_rt5631.o
obj-$(CONFIG_SND_SOC_SAMSUNG_JIVE_WM8750) += snd-soc-jive-wm8750.o
obj-$(CONFIG_SND_SOC_SAMSUNG_NEO1973_WM8753) += snd-soc-neo1973-wm8753.o
@@ -71,3 +72,4 @@ obj-$(CONFIG_SND_SOC_LOWLAND) += snd-soc-lowland.o
obj-$(CONFIG_SND_SOC_LITTLEMILL) += snd-soc-littlemill.o
obj-$(CONFIG_SND_SOC_BELLS) += snd-soc-bells.o
obj-$(CONFIG_SND_SOC_ODROIDX2) += snd-soc-odroidx2-max98090.o
+obj-$(CONFIG_SND_SOC_ARNDALE_RT5631_ALC5631) += snd-soc-arndale-rt5631.o
diff --git a/sound/soc/samsung/ac97.c b/sound/soc/samsung/ac97.c
index e161511..7952a62 100644
--- a/sound/soc/samsung/ac97.c
+++ b/sound/soc/samsung/ac97.c
@@ -288,7 +288,7 @@ static int s3c_ac97_mic_dai_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver s3c_ac97_dai[] = {
[S3C_AC97_DAI_PCM] = {
.name = "samsung-ac97",
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.stream_name = "AC97 Playback",
.channels_min = 2,
@@ -306,7 +306,7 @@ static struct snd_soc_dai_driver s3c_ac97_dai[] = {
},
[S3C_AC97_DAI_MIC] = {
.name = "samsung-ac97-mic",
- .ac97_control = 1,
+ .bus_control = true,
.capture = {
.stream_name = "AC97 Mic Capture",
.channels_min = 1,
diff --git a/sound/soc/samsung/arndale_rt5631.c b/sound/soc/samsung/arndale_rt5631.c
new file mode 100644
index 0000000..1e2b61c
--- /dev/null
+++ b/sound/soc/samsung/arndale_rt5631.c
@@ -0,0 +1,150 @@
+/*
+ * arndale_rt5631.c
+ *
+ * Copyright (c) 2014, Insignal Co., Ltd.
+ *
+ * Author: Claude <claude@insginal.co.kr>
+ *
+ * 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/platform_device.h>
+#include <linux/clk.h>
+
+#include <sound/soc.h>
+#include <sound/soc-dapm.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+
+#include "i2s.h"
+
+static int arndale_hw_params(struct snd_pcm_substream *substream,
+ struct snd_pcm_hw_params *params)
+{
+ struct snd_soc_pcm_runtime *rtd = substream->private_data;
+ struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
+ struct snd_soc_dai *codec_dai = rtd->codec_dai;
+ int rfs, ret;
+ unsigned long rclk;
+
+ rfs = 256;
+
+ rclk = params_rate(params) * rfs;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_CDCLK,
+ 0, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(cpu_dai, SAMSUNG_I2S_RCLKSRC_0,
+ 0, SND_SOC_CLOCK_OUT);
+
+ if (ret < 0)
+ return ret;
+
+ ret = snd_soc_dai_set_sysclk(codec_dai, 0, rclk, SND_SOC_CLOCK_OUT);
+ if (ret < 0)
+ return ret;
+
+ return 0;
+}
+
+static struct snd_soc_ops arndale_ops = {
+ .hw_params = arndale_hw_params,
+};
+
+static struct snd_soc_dai_link arndale_rt5631_dai[] = {
+ {
+ .name = "RT5631 HiFi",
+ .stream_name = "Primary",
+ .codec_dai_name = "rt5631-hifi",
+ .dai_fmt = SND_SOC_DAIFMT_I2S
+ | SND_SOC_DAIFMT_NB_NF
+ | SND_SOC_DAIFMT_CBS_CFS,
+ .ops = &arndale_ops,
+ },
+};
+
+static struct snd_soc_card arndale_rt5631 = {
+ .name = "Arndale RT5631",
+ .dai_link = arndale_rt5631_dai,
+ .num_links = ARRAY_SIZE(arndale_rt5631_dai),
+};
+
+static int arndale_audio_probe(struct platform_device *pdev)
+{
+ int n, ret;
+ struct device_node *np = pdev->dev.of_node;
+ struct snd_soc_card *card = &arndale_rt5631;
+
+ card->dev = &pdev->dev;
+
+ for (n = 0; np && n < ARRAY_SIZE(arndale_rt5631_dai); n++) {
+ if (!arndale_rt5631_dai[n].cpu_dai_name) {
+ arndale_rt5631_dai[n].cpu_of_node = of_parse_phandle(np,
+ "samsung,audio-cpu", n);
+
+ if (!arndale_rt5631_dai[n].cpu_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'samsung,audio-cpu' missing or invalid\n");
+ return -EINVAL;
+ }
+ }
+ if (!arndale_rt5631_dai[n].platform_name)
+ arndale_rt5631_dai[n].platform_of_node =
+ arndale_rt5631_dai[n].cpu_of_node;
+
+ arndale_rt5631_dai[n].codec_name = NULL;
+ arndale_rt5631_dai[n].codec_of_node = of_parse_phandle(np,
+ "samsung,audio-codec", n);
+ if (!arndale_rt5631_dai[0].codec_of_node) {
+ dev_err(&pdev->dev,
+ "Property 'samsung,audio-codec' missing or invalid\n");
+ return -EINVAL;
+ }
+ }
+
+ ret = devm_snd_soc_register_card(card->dev, card);
+
+ if (ret)
+ dev_err(&pdev->dev, "snd_soc_register_card() failed:%d\n", ret);
+
+ return ret;
+}
+
+static int arndale_audio_remove(struct platform_device *pdev)
+{
+ struct snd_soc_card *card = platform_get_drvdata(pdev);
+
+ snd_soc_unregister_card(card);
+
+ return 0;
+}
+
+static const struct of_device_id samsung_arndale_rt5631_of_match[] __maybe_unused = {
+ { .compatible = "samsung,arndale-rt5631", },
+ { .compatible = "samsung,arndale-alc5631", },
+ {},
+};
+MODULE_DEVICE_TABLE(of, samsung_arndale_rt5631_of_match);
+
+static struct platform_driver arndale_audio_driver = {
+ .driver = {
+ .name = "arndale-audio",
+ .owner = THIS_MODULE,
+ .pm = &snd_soc_pm_ops,
+ .of_match_table = of_match_ptr(samsung_arndale_rt5631_of_match),
+ },
+ .probe = arndale_audio_probe,
+ .remove = arndale_audio_remove,
+};
+
+module_platform_driver(arndale_audio_driver);
+
+MODULE_AUTHOR("Claude <claude@insignal.co.kr>");
+MODULE_DESCRIPTION("ALSA SoC Driver for Arndale Board");
+MODULE_LICENSE("GPL");
diff --git a/sound/soc/samsung/i2s-regs.h b/sound/soc/samsung/i2s-regs.h
index 821a502..9170c31 100644
--- a/sound/soc/samsung/i2s-regs.h
+++ b/sound/soc/samsung/i2s-regs.h
@@ -33,8 +33,9 @@
#define I2SLVL3ADDR 0x3c
#define I2SSTR1 0x40
#define I2SVER 0x44
-#define I2SFIC2 0x48
+#define I2SFIC1 0x48
#define I2STDM 0x4c
+#define I2SFSTA 0x50
#define CON_RSTCLR (1 << 31)
#define CON_FRXOFSTATUS (1 << 26)
@@ -93,8 +94,6 @@
#define MOD_BLC_24BIT (2 << 13)
#define MOD_BLC_MASK (3 << 13)
-#define MOD_IMS_SYSMUX (1 << 10)
-#define MOD_SLAVE (1 << 11)
#define MOD_TXONLY (0 << 8)
#define MOD_RXONLY (1 << 8)
#define MOD_TXRX (2 << 8)
@@ -132,7 +131,10 @@
#define EXYNOS5420_MOD_BCLK_256FS 8
#define EXYNOS5420_MOD_BCLK_MASK 0xf
-#define MOD_CDCLKCON (1 << 12)
+#define EXYNOS7_MOD_RCLK_64FS 4
+#define EXYNOS7_MOD_RCLK_128FS 5
+#define EXYNOS7_MOD_RCLK_96FS 6
+#define EXYNOS7_MOD_RCLK_192FS 7
#define PSR_PSREN (1 << 15)
diff --git a/sound/soc/samsung/i2s.c b/sound/soc/samsung/i2s.c
index 9d51347..c7aafcd 100644
--- a/sound/soc/samsung/i2s.c
+++ b/sound/soc/samsung/i2s.c
@@ -36,9 +36,24 @@ enum samsung_dai_type {
TYPE_SEC,
};
+struct samsung_i2s_variant_regs {
+ unsigned int bfs_off;
+ unsigned int rfs_off;
+ unsigned int sdf_off;
+ unsigned int txr_off;
+ unsigned int rclksrc_off;
+ unsigned int mss_off;
+ unsigned int cdclkcon_off;
+ unsigned int lrp_off;
+ unsigned int bfs_mask;
+ unsigned int rfs_mask;
+ unsigned int ftx0cnt_off;
+};
+
struct samsung_i2s_dai_data {
int dai_type;
u32 quirks;
+ const struct samsung_i2s_variant_regs *i2s_variant_regs;
};
struct i2s_dai {
@@ -81,6 +96,7 @@ struct i2s_dai {
u32 suspend_i2scon;
u32 suspend_i2spsr;
unsigned long gpios[7]; /* i2s gpio line numbers */
+ const struct samsung_i2s_variant_regs *variant_regs;
};
/* Lock for cross i/f checks */
@@ -95,7 +111,8 @@ static inline bool is_secondary(struct i2s_dai *i2s)
/* If operating in SoC-Slave mode */
static inline bool is_slave(struct i2s_dai *i2s)
{
- return (readl(i2s->addr + I2SMOD) & MOD_SLAVE) ? true : false;
+ u32 mod = readl(i2s->addr + I2SMOD);
+ return (mod & (1 << i2s->variant_regs->mss_off)) ? true : false;
}
/* If this interface of the controller is transmitting data */
@@ -200,14 +217,14 @@ static inline bool is_manager(struct i2s_dai *i2s)
static inline unsigned get_rfs(struct i2s_dai *i2s)
{
u32 rfs;
-
- if (i2s->quirks & QUIRK_SUPPORTS_TDM)
- rfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_RCLK_SHIFT;
- else
- rfs = (readl(i2s->addr + I2SMOD) >> MOD_RCLK_SHIFT);
- rfs &= MOD_RCLK_MASK;
+ rfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->rfs_off;
+ rfs &= i2s->variant_regs->rfs_mask;
switch (rfs) {
+ case 7: return 192;
+ case 6: return 96;
+ case 5: return 128;
+ case 4: return 64;
case 3: return 768;
case 2: return 384;
case 1: return 512;
@@ -219,15 +236,23 @@ static inline unsigned get_rfs(struct i2s_dai *i2s)
static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
{
u32 mod = readl(i2s->addr + I2SMOD);
- int rfs_shift;
+ int rfs_shift = i2s->variant_regs->rfs_off;
- if (i2s->quirks & QUIRK_SUPPORTS_TDM)
- rfs_shift = EXYNOS5420_MOD_RCLK_SHIFT;
- else
- rfs_shift = MOD_RCLK_SHIFT;
- mod &= ~(MOD_RCLK_MASK << rfs_shift);
+ mod &= ~(i2s->variant_regs->rfs_mask << rfs_shift);
switch (rfs) {
+ case 192:
+ mod |= (EXYNOS7_MOD_RCLK_192FS << rfs_shift);
+ break;
+ case 96:
+ mod |= (EXYNOS7_MOD_RCLK_96FS << rfs_shift);
+ break;
+ case 128:
+ mod |= (EXYNOS7_MOD_RCLK_128FS << rfs_shift);
+ break;
+ case 64:
+ mod |= (EXYNOS7_MOD_RCLK_64FS << rfs_shift);
+ break;
case 768:
mod |= (MOD_RCLK_768FS << rfs_shift);
break;
@@ -249,14 +274,8 @@ static inline void set_rfs(struct i2s_dai *i2s, unsigned rfs)
static inline unsigned get_bfs(struct i2s_dai *i2s)
{
u32 bfs;
-
- if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
- bfs = readl(i2s->addr + I2SMOD) >> EXYNOS5420_MOD_BCLK_SHIFT;
- bfs &= EXYNOS5420_MOD_BCLK_MASK;
- } else {
- bfs = readl(i2s->addr + I2SMOD) >> MOD_BCLK_SHIFT;
- bfs &= MOD_BCLK_MASK;
- }
+ bfs = readl(i2s->addr + I2SMOD) >> i2s->variant_regs->bfs_off;
+ bfs &= i2s->variant_regs->bfs_mask;
switch (bfs) {
case 8: return 256;
@@ -275,16 +294,8 @@ static inline unsigned get_bfs(struct i2s_dai *i2s)
static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
{
u32 mod = readl(i2s->addr + I2SMOD);
- int bfs_shift;
int tdm = i2s->quirks & QUIRK_SUPPORTS_TDM;
-
- if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
- bfs_shift = EXYNOS5420_MOD_BCLK_SHIFT;
- mod &= ~(EXYNOS5420_MOD_BCLK_MASK << bfs_shift);
- } else {
- bfs_shift = MOD_BCLK_SHIFT;
- mod &= ~(MOD_BCLK_MASK << bfs_shift);
- }
+ int bfs_shift = i2s->variant_regs->bfs_off;
/* Non-TDM I2S controllers do not support BCLK > 48 * FS */
if (!tdm && bfs > 48) {
@@ -292,6 +303,8 @@ static inline void set_bfs(struct i2s_dai *i2s, unsigned bfs)
return;
}
+ mod &= ~(i2s->variant_regs->bfs_mask << bfs_shift);
+
switch (bfs) {
case 48:
mod |= (MOD_BCLK_48FS << bfs_shift);
@@ -346,8 +359,9 @@ static inline int get_blc(struct i2s_dai *i2s)
static void i2s_txctrl(struct i2s_dai *i2s, int on)
{
void __iomem *addr = i2s->addr;
+ int txr_off = i2s->variant_regs->txr_off;
u32 con = readl(addr + I2SCON);
- u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+ u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
if (on) {
con |= CON_ACTIVE;
@@ -362,9 +376,9 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
}
if (any_rx_active(i2s))
- mod |= MOD_TXRX;
+ mod |= 2 << txr_off;
else
- mod |= MOD_TXONLY;
+ mod |= 0 << txr_off;
} else {
if (is_secondary(i2s)) {
con |= CON_TXSDMA_PAUSE;
@@ -382,7 +396,7 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
con |= CON_TXCH_PAUSE;
if (any_rx_active(i2s))
- mod |= MOD_RXONLY;
+ mod |= 1 << txr_off;
else
con &= ~CON_ACTIVE;
}
@@ -395,23 +409,24 @@ static void i2s_txctrl(struct i2s_dai *i2s, int on)
static void i2s_rxctrl(struct i2s_dai *i2s, int on)
{
void __iomem *addr = i2s->addr;
+ int txr_off = i2s->variant_regs->txr_off;
u32 con = readl(addr + I2SCON);
- u32 mod = readl(addr + I2SMOD) & ~MOD_MASK;
+ u32 mod = readl(addr + I2SMOD) & ~(3 << txr_off);
if (on) {
con |= CON_RXDMA_ACTIVE | CON_ACTIVE;
con &= ~(CON_RXDMA_PAUSE | CON_RXCH_PAUSE);
if (any_tx_active(i2s))
- mod |= MOD_TXRX;
+ mod |= 2 << txr_off;
else
- mod |= MOD_RXONLY;
+ mod |= 1 << txr_off;
} else {
con |= CON_RXDMA_PAUSE | CON_RXCH_PAUSE;
con &= ~CON_RXDMA_ACTIVE;
if (any_tx_active(i2s))
- mod |= MOD_TXONLY;
+ mod |= 0 << txr_off;
else
con &= ~CON_ACTIVE;
}
@@ -451,6 +466,9 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
u32 mod = readl(i2s->addr + I2SMOD);
+ const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
+ unsigned int cdcon_mask = 1 << i2s_regs->cdclkcon_off;
+ unsigned int rsrc_mask = 1 << i2s_regs->rclksrc_off;
switch (clk_id) {
case SAMSUNG_I2S_OPCLK:
@@ -465,18 +483,18 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
if ((rfs && other && other->rfs && (other->rfs != rfs)) ||
(any_active(i2s) &&
(((dir == SND_SOC_CLOCK_IN)
- && !(mod & MOD_CDCLKCON)) ||
+ && !(mod & cdcon_mask)) ||
((dir == SND_SOC_CLOCK_OUT)
- && (mod & MOD_CDCLKCON))))) {
+ && (mod & cdcon_mask))))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
}
if (dir == SND_SOC_CLOCK_IN)
- mod |= MOD_CDCLKCON;
+ mod |= 1 << i2s_regs->cdclkcon_off;
else
- mod &= ~MOD_CDCLKCON;
+ mod &= ~(1 << i2s_regs->cdclkcon_off);
i2s->rfs = rfs;
break;
@@ -491,8 +509,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
if (!any_active(i2s)) {
if (i2s->op_clk && !IS_ERR(i2s->op_clk)) {
- if ((clk_id && !(mod & MOD_IMS_SYSMUX)) ||
- (!clk_id && (mod & MOD_IMS_SYSMUX))) {
+ if ((clk_id && !(mod & rsrc_mask)) ||
+ (!clk_id && (mod & rsrc_mask))) {
clk_disable_unprepare(i2s->op_clk);
clk_put(i2s->op_clk);
} else {
@@ -520,8 +538,8 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
other->op_clk = i2s->op_clk;
other->rclk_srcrate = i2s->rclk_srcrate;
}
- } else if ((!clk_id && (mod & MOD_IMS_SYSMUX))
- || (clk_id && !(mod & MOD_IMS_SYSMUX))) {
+ } else if ((!clk_id && (mod & rsrc_mask))
+ || (clk_id && !(mod & rsrc_mask))) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
@@ -533,11 +551,11 @@ static int i2s_set_sysclk(struct snd_soc_dai *dai,
}
if (clk_id == 0)
- mod &= ~MOD_IMS_SYSMUX;
+ mod &= ~(1 << i2s_regs->rclksrc_off);
else
- mod |= MOD_IMS_SYSMUX;
- break;
+ mod |= 1 << i2s_regs->rclksrc_off;
+ break;
default:
dev_err(&i2s->pdev->dev, "We don't serve that!\n");
return -EINVAL;
@@ -553,16 +571,12 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
{
struct i2s_dai *i2s = to_info(dai);
u32 mod = readl(i2s->addr + I2SMOD);
- int lrp_shift, sdf_shift, sdf_mask, lrp_rlow;
+ int lrp_shift, sdf_shift, sdf_mask, lrp_rlow, mod_slave;
u32 tmp = 0;
- if (i2s->quirks & QUIRK_SUPPORTS_TDM) {
- lrp_shift = EXYNOS5420_MOD_LRP_SHIFT;
- sdf_shift = EXYNOS5420_MOD_SDF_SHIFT;
- } else {
- lrp_shift = MOD_LRP_SHIFT;
- sdf_shift = MOD_SDF_SHIFT;
- }
+ lrp_shift = i2s->variant_regs->lrp_off;
+ sdf_shift = i2s->variant_regs->sdf_off;
+ mod_slave = 1 << i2s->variant_regs->mss_off;
sdf_mask = MOD_SDF_MASK << sdf_shift;
lrp_rlow = MOD_LR_RLOW << lrp_shift;
@@ -605,7 +619,7 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
switch (fmt & SND_SOC_DAIFMT_MASTER_MASK) {
case SND_SOC_DAIFMT_CBM_CFM:
- tmp |= MOD_SLAVE;
+ tmp |= mod_slave;
break;
case SND_SOC_DAIFMT_CBS_CFS:
/* Set default source clock in Master mode */
@@ -623,13 +637,13 @@ static int i2s_set_fmt(struct snd_soc_dai *dai,
* channel.
*/
if (any_active(i2s) &&
- ((mod & (sdf_mask | lrp_rlow | MOD_SLAVE)) != tmp)) {
+ ((mod & (sdf_mask | lrp_rlow | mod_slave)) != tmp)) {
dev_err(&i2s->pdev->dev,
"%s:%d Other DAI busy\n", __func__, __LINE__);
return -EAGAIN;
}
- mod &= ~(sdf_mask | lrp_rlow | MOD_SLAVE);
+ mod &= ~(sdf_mask | lrp_rlow | mod_slave);
mod |= tmp;
writel(mod, i2s->addr + I2SMOD);
@@ -751,6 +765,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
unsigned long flags;
+ const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
spin_lock_irqsave(&lock, flags);
@@ -761,7 +776,7 @@ static void i2s_shutdown(struct snd_pcm_substream *substream,
other->mode |= DAI_MANAGER;
} else {
u32 mod = readl(i2s->addr + I2SMOD);
- i2s->cdclk_out = !(mod & MOD_CDCLKCON);
+ i2s->cdclk_out = !(mod & (1 << i2s_regs->cdclkcon_off));
if (other)
other->cdclk_out = i2s->cdclk_out;
}
@@ -914,13 +929,14 @@ i2s_delay(struct snd_pcm_substream *substream, struct snd_soc_dai *dai)
struct i2s_dai *i2s = to_info(dai);
u32 reg = readl(i2s->addr + I2SFIC);
snd_pcm_sframes_t delay;
+ const struct samsung_i2s_variant_regs *i2s_regs = i2s->variant_regs;
if (substream->stream == SNDRV_PCM_STREAM_CAPTURE)
delay = FIC_RXCOUNT(reg);
else if (is_secondary(i2s))
delay = FICS_TXCOUNT(readl(i2s->addr + I2SFICS));
else
- delay = FIC_TXCOUNT(reg);
+ delay = (reg >> i2s_regs->ftx0cnt_off) & 0x7f;
return delay;
}
@@ -956,6 +972,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
{
struct i2s_dai *i2s = to_info(dai);
struct i2s_dai *other = i2s->pri_dai ? : i2s->sec_dai;
+ int ret;
if (other && other->clk) { /* If this is probe on secondary */
samsung_asoc_init_dma_data(dai, &other->sec_dai->dma_playback,
@@ -973,9 +990,14 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
if (IS_ERR(i2s->clk)) {
dev_err(&i2s->pdev->dev, "failed to get i2s_clock\n");
iounmap(i2s->addr);
- return -ENOENT;
+ return PTR_ERR(i2s->clk);
+ }
+
+ ret = clk_prepare_enable(i2s->clk);
+ if (ret != 0) {
+ dev_err(&i2s->pdev->dev, "failed to enable clock: %d\n", ret);
+ return ret;
}
- clk_prepare_enable(i2s->clk);
samsung_asoc_init_dma_data(dai, &i2s->dma_playback, &i2s->dma_capture);
@@ -987,7 +1009,7 @@ static int samsung_i2s_dai_probe(struct snd_soc_dai *dai)
if (i2s->quirks & QUIRK_NEED_RSTCLR)
writel(CON_RSTCLR, i2s->addr + I2SCON);
- if (i2s->quirks & QUIRK_SEC_DAI)
+ if (i2s->quirks & QUIRK_SUPPORTS_IDMA)
idma_reg_addr_init(i2s->addr,
i2s->sec_dai->idma_playback.dma_addr);
@@ -1199,10 +1221,9 @@ static int samsung_i2s_probe(struct platform_device *pdev)
quirks = i2s_dai_data->quirks;
if (of_property_read_u32(np, "samsung,idma-addr",
&idma_addr)) {
- if (quirks & QUIRK_SEC_DAI) {
- dev_err(&pdev->dev, "idma address is not"\
+ if (quirks & QUIRK_SUPPORTS_IDMA) {
+ dev_info(&pdev->dev, "idma address is not"\
"specified");
- return -EINVAL;
}
}
}
@@ -1228,6 +1249,7 @@ static int samsung_i2s_probe(struct platform_device *pdev)
pri_dai->dma_capture.dma_size = 4;
pri_dai->base = regs_base;
pri_dai->quirks = quirks;
+ pri_dai->variant_regs = i2s_dai_data->i2s_variant_regs;
if (quirks & QUIRK_PRI_6CHAN)
pri_dai->i2s_dai_drv.playback.channels_max = 6;
@@ -1302,20 +1324,93 @@ static int samsung_i2s_remove(struct platform_device *pdev)
return 0;
}
+static const struct samsung_i2s_variant_regs i2sv3_regs = {
+ .bfs_off = 1,
+ .rfs_off = 3,
+ .sdf_off = 5,
+ .txr_off = 8,
+ .rclksrc_off = 10,
+ .mss_off = 11,
+ .cdclkcon_off = 12,
+ .lrp_off = 7,
+ .bfs_mask = 0x3,
+ .rfs_mask = 0x3,
+ .ftx0cnt_off = 8,
+};
+
+static const struct samsung_i2s_variant_regs i2sv6_regs = {
+ .bfs_off = 0,
+ .rfs_off = 4,
+ .sdf_off = 6,
+ .txr_off = 8,
+ .rclksrc_off = 10,
+ .mss_off = 11,
+ .cdclkcon_off = 12,
+ .lrp_off = 15,
+ .bfs_mask = 0xf,
+ .rfs_mask = 0x3,
+ .ftx0cnt_off = 8,
+};
+
+static const struct samsung_i2s_variant_regs i2sv7_regs = {
+ .bfs_off = 0,
+ .rfs_off = 4,
+ .sdf_off = 7,
+ .txr_off = 9,
+ .rclksrc_off = 11,
+ .mss_off = 12,
+ .cdclkcon_off = 22,
+ .lrp_off = 15,
+ .bfs_mask = 0xf,
+ .rfs_mask = 0x7,
+ .ftx0cnt_off = 0,
+};
+
+static const struct samsung_i2s_variant_regs i2sv5_i2s1_regs = {
+ .bfs_off = 0,
+ .rfs_off = 3,
+ .sdf_off = 6,
+ .txr_off = 8,
+ .rclksrc_off = 10,
+ .mss_off = 11,
+ .cdclkcon_off = 12,
+ .lrp_off = 15,
+ .bfs_mask = 0x7,
+ .rfs_mask = 0x7,
+ .ftx0cnt_off = 8,
+};
+
static const struct samsung_i2s_dai_data i2sv3_dai_type = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_NO_MUXPSR,
+ .i2s_variant_regs = &i2sv3_regs,
};
static const struct samsung_i2s_dai_data i2sv5_dai_type = {
.dai_type = TYPE_PRI,
- .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR,
+ .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
+ QUIRK_SUPPORTS_IDMA,
+ .i2s_variant_regs = &i2sv3_regs,
};
static const struct samsung_i2s_dai_data i2sv6_dai_type = {
.dai_type = TYPE_PRI,
.quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
+ QUIRK_SUPPORTS_TDM | QUIRK_SUPPORTS_IDMA,
+ .i2s_variant_regs = &i2sv6_regs,
+};
+
+static const struct samsung_i2s_dai_data i2sv7_dai_type = {
+ .dai_type = TYPE_PRI,
+ .quirks = QUIRK_PRI_6CHAN | QUIRK_SEC_DAI | QUIRK_NEED_RSTCLR |
QUIRK_SUPPORTS_TDM,
+ .i2s_variant_regs = &i2sv7_regs,
+};
+
+static const struct samsung_i2s_dai_data i2sv5_dai_type_i2s1 = {
+ .dai_type = TYPE_PRI,
+ .quirks = QUIRK_PRI_6CHAN | QUIRK_NEED_RSTCLR,
+ .i2s_variant_regs = &i2sv5_i2s1_regs,
};
static const struct samsung_i2s_dai_data samsung_dai_type_pri = {
@@ -1329,10 +1424,13 @@ static const struct samsung_i2s_dai_data samsung_dai_type_sec = {
static struct platform_device_id samsung_i2s_driver_ids[] = {
{
.name = "samsung-i2s",
- .driver_data = (kernel_ulong_t)&samsung_dai_type_pri,
+ .driver_data = (kernel_ulong_t)&i2sv3_dai_type,
}, {
.name = "samsung-i2s-sec",
.driver_data = (kernel_ulong_t)&samsung_dai_type_sec,
+ }, {
+ .name = "samsung-i2sv4",
+ .driver_data = (kernel_ulong_t)&i2sv5_dai_type,
},
{},
};
@@ -1349,6 +1447,12 @@ static const struct of_device_id exynos_i2s_match[] = {
}, {
.compatible = "samsung,exynos5420-i2s",
.data = &i2sv6_dai_type,
+ }, {
+ .compatible = "samsung,exynos7-i2s",
+ .data = &i2sv7_dai_type,
+ }, {
+ .compatible = "samsung,exynos7-i2s1",
+ .data = &i2sv5_dai_type_i2s1,
},
{},
};
diff --git a/sound/soc/samsung/odroidx2_max98090.c b/sound/soc/samsung/odroidx2_max98090.c
index 3c8f604..d7640e7 100644
--- a/sound/soc/samsung/odroidx2_max98090.c
+++ b/sound/soc/samsung/odroidx2_max98090.c
@@ -153,8 +153,8 @@ static int odroidx2_audio_remove(struct platform_device *pdev)
snd_soc_unregister_card(card);
- of_node_put((struct device_node *)odroidx2_dai[0].cpu_of_node);
- of_node_put((struct device_node *)odroidx2_dai[0].codec_of_node);
+ of_node_put(odroidx2_dai[0].cpu_of_node);
+ of_node_put(odroidx2_dai[0].codec_of_node);
return 0;
}
diff --git a/sound/soc/sh/fsi.c b/sound/soc/sh/fsi.c
index 88e5df4..8869971 100644
--- a/sound/soc/sh/fsi.c
+++ b/sound/soc/sh/fsi.c
@@ -842,12 +842,9 @@ static int fsi_clk_disable(struct device *dev,
return -EINVAL;
if (1 == clock->count--) {
- if (clock->xck)
- clk_disable(clock->xck);
- if (clock->ick)
- clk_disable(clock->ick);
- if (clock->div)
- clk_disable(clock->div);
+ clk_disable(clock->xck);
+ clk_disable(clock->ick);
+ clk_disable(clock->div);
}
return 0;
diff --git a/sound/soc/sh/hac.c b/sound/soc/sh/hac.c
index 0af2e4d..d5f567e 100644
--- a/sound/soc/sh/hac.c
+++ b/sound/soc/sh/hac.c
@@ -272,7 +272,7 @@ static const struct snd_soc_dai_ops hac_dai_ops = {
static struct snd_soc_dai_driver sh4_hac_dai[] = {
{
.name = "hac-dai.0",
- .ac97_control = 1,
+ .bus_control = true,
.playback = {
.rates = AC97_RATES,
.formats = AC97_FMTS,
diff --git a/sound/soc/sh/rcar/adg.c b/sound/soc/sh/rcar/adg.c
index fc41a0e..14d1a71 100644
--- a/sound/soc/sh/rcar/adg.c
+++ b/sound/soc/sh/rcar/adg.c
@@ -430,7 +430,7 @@ int rsnd_adg_probe(struct platform_device *pdev,
adg->clk[CLKI] = devm_clk_get(dev, "clk_i");
for_each_rsnd_clk(clk, adg, i)
- dev_dbg(dev, "clk %d : %p\n", i, clk);
+ dev_dbg(dev, "clk %d : %p : %ld\n", i, clk, clk_get_rate(clk));
rsnd_adg_ssi_clk_init(priv, adg);
diff --git a/sound/soc/sh/rcar/core.c b/sound/soc/sh/rcar/core.c
index 7004219..75308bb 100644
--- a/sound/soc/sh/rcar/core.c
+++ b/sound/soc/sh/rcar/core.c
@@ -349,7 +349,7 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
dma_name);
if (!dma->chan) {
dev_err(dev, "can't get dma channel\n");
- return -EIO;
+ goto rsnd_dma_channel_err;
}
ret = dmaengine_slave_config(dma->chan, &cfg);
@@ -363,8 +363,15 @@ int rsnd_dma_init(struct rsnd_priv *priv, struct rsnd_dma *dma,
rsnd_dma_init_err:
rsnd_dma_quit(priv, dma);
+rsnd_dma_channel_err:
- return ret;
+ /*
+ * DMA failed. try to PIO mode
+ * see
+ * rsnd_ssi_fallback()
+ * rsnd_rdai_continuance_probe()
+ */
+ return -EAGAIN;
}
void rsnd_dma_quit(struct rsnd_priv *priv,
@@ -409,9 +416,16 @@ u32 rsnd_get_adinr(struct rsnd_mod *mod)
({ \
struct rsnd_priv *priv = rsnd_mod_to_priv(mod); \
struct device *dev = rsnd_priv_to_dev(priv); \
- dev_dbg(dev, "%s [%d] %s\n", \
- rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \
- (mod)->ops->func(mod, rdai); \
+ u32 mask = 1 << __rsnd_mod_shift_##func; \
+ u32 call = __rsnd_mod_call_##func << __rsnd_mod_shift_##func; \
+ int ret = 0; \
+ if ((mod->status & mask) == call) { \
+ dev_dbg(dev, "%s[%d] %s\n", \
+ rsnd_mod_name(mod), rsnd_mod_id(mod), #func); \
+ ret = (mod)->ops->func(mod, rdai); \
+ mod->status = (mod->status & ~mask) | (~call & mask); \
+ } \
+ ret; \
})
#define rsnd_mod_call(mod, func, rdai...) \
@@ -456,6 +470,13 @@ static int rsnd_dai_connect(struct rsnd_mod *mod,
return 0;
}
+static void rsnd_dai_disconnect(struct rsnd_mod *mod,
+ struct rsnd_dai_stream *io)
+{
+ mod->io = NULL;
+ io->mod[mod->type] = NULL;
+}
+
int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai)
{
int id = rdai - priv->rdai;
@@ -686,6 +707,20 @@ static const struct snd_soc_dai_ops rsnd_soc_dai_ops = {
ret; \
})
+#define rsnd_path_break(priv, io, type) \
+{ \
+ struct rsnd_mod *mod; \
+ int id = -1; \
+ \
+ if (rsnd_is_enable_path(io, type)) { \
+ id = rsnd_info_id(priv, io, type); \
+ if (id >= 0) { \
+ mod = rsnd_##type##_mod_get(priv, id); \
+ rsnd_dai_disconnect(mod, io); \
+ } \
+ } \
+}
+
static int rsnd_path_init(struct rsnd_priv *priv,
struct rsnd_dai *rdai,
struct rsnd_dai_stream *io)
@@ -934,6 +969,150 @@ static struct snd_pcm_ops rsnd_pcm_ops = {
};
/*
+ * snd_kcontrol
+ */
+#define kcontrol_to_cfg(kctrl) ((struct rsnd_kctrl_cfg *)kctrl->private_value)
+static int rsnd_kctrl_info(struct snd_kcontrol *kctrl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+
+ if (cfg->texts) {
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = cfg->size;
+ uinfo->value.enumerated.items = cfg->max;
+ if (uinfo->value.enumerated.item >= cfg->max)
+ uinfo->value.enumerated.item = cfg->max - 1;
+ strlcpy(uinfo->value.enumerated.name,
+ cfg->texts[uinfo->value.enumerated.item],
+ sizeof(uinfo->value.enumerated.name));
+ } else {
+ uinfo->count = cfg->size;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = cfg->max;
+ uinfo->type = (cfg->max == 1) ?
+ SNDRV_CTL_ELEM_TYPE_BOOLEAN :
+ SNDRV_CTL_ELEM_TYPE_INTEGER;
+ }
+
+ return 0;
+}
+
+static int rsnd_kctrl_get(struct snd_kcontrol *kctrl,
+ struct snd_ctl_elem_value *uc)
+{
+ struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+ int i;
+
+ for (i = 0; i < cfg->size; i++)
+ if (cfg->texts)
+ uc->value.enumerated.item[i] = cfg->val[i];
+ else
+ uc->value.integer.value[i] = cfg->val[i];
+
+ return 0;
+}
+
+static int rsnd_kctrl_put(struct snd_kcontrol *kctrl,
+ struct snd_ctl_elem_value *uc)
+{
+ struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
+ struct rsnd_kctrl_cfg *cfg = kcontrol_to_cfg(kctrl);
+ int i, change = 0;
+
+ for (i = 0; i < cfg->size; i++) {
+ if (cfg->texts) {
+ change |= (uc->value.enumerated.item[i] != cfg->val[i]);
+ cfg->val[i] = uc->value.enumerated.item[i];
+ } else {
+ change |= (uc->value.integer.value[i] != cfg->val[i]);
+ cfg->val[i] = uc->value.integer.value[i];
+ }
+ }
+
+ if (change)
+ cfg->update(mod);
+
+ return change;
+}
+
+static int __rsnd_kctrl_new(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ struct rsnd_kctrl_cfg *cfg,
+ void (*update)(struct rsnd_mod *mod))
+{
+ struct snd_card *card = rtd->card->snd_card;
+ struct snd_kcontrol *kctrl;
+ struct snd_kcontrol_new knew = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = name,
+ .info = rsnd_kctrl_info,
+ .get = rsnd_kctrl_get,
+ .put = rsnd_kctrl_put,
+ .private_value = (unsigned long)cfg,
+ };
+ int ret;
+
+ kctrl = snd_ctl_new1(&knew, mod);
+ if (!kctrl)
+ return -ENOMEM;
+
+ ret = snd_ctl_add(card, kctrl);
+ if (ret < 0)
+ return ret;
+
+ cfg->update = update;
+
+ return 0;
+}
+
+int rsnd_kctrl_new_m(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ void (*update)(struct rsnd_mod *mod),
+ struct rsnd_kctrl_cfg_m *_cfg,
+ u32 max)
+{
+ _cfg->cfg.max = max;
+ _cfg->cfg.size = RSND_DVC_CHANNELS;
+ _cfg->cfg.val = _cfg->val;
+ return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+}
+
+int rsnd_kctrl_new_s(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ void (*update)(struct rsnd_mod *mod),
+ struct rsnd_kctrl_cfg_s *_cfg,
+ u32 max)
+{
+ _cfg->cfg.max = max;
+ _cfg->cfg.size = 1;
+ _cfg->cfg.val = &_cfg->val;
+ return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+}
+
+int rsnd_kctrl_new_e(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ struct rsnd_kctrl_cfg_s *_cfg,
+ void (*update)(struct rsnd_mod *mod),
+ const char * const *texts,
+ u32 max)
+{
+ _cfg->cfg.max = max;
+ _cfg->cfg.size = 1;
+ _cfg->cfg.val = &_cfg->val;
+ _cfg->cfg.texts = texts;
+ return __rsnd_kctrl_new(mod, rdai, rtd, name, &_cfg->cfg, update);
+}
+
+/*
* snd_soc_platform
*/
@@ -976,6 +1155,49 @@ static const struct snd_soc_component_driver rsnd_soc_component = {
.name = "rsnd",
};
+static int rsnd_rdai_continuance_probe(struct rsnd_priv *priv,
+ struct rsnd_dai *rdai,
+ int is_play)
+{
+ struct rsnd_dai_stream *io = is_play ? &rdai->playback : &rdai->capture;
+ int ret;
+
+ ret = rsnd_dai_call(probe, io, rdai);
+ if (ret == -EAGAIN) {
+ /*
+ * Fallback to PIO mode
+ */
+
+ /*
+ * call "remove" for SSI/SRC/DVC
+ * SSI will be switch to PIO mode if it was DMA mode
+ * see
+ * rsnd_dma_init()
+ * rsnd_ssi_fallback()
+ */
+ rsnd_dai_call(remove, io, rdai);
+
+ /*
+ * remove SRC/DVC from DAI,
+ */
+ rsnd_path_break(priv, io, src);
+ rsnd_path_break(priv, io, dvc);
+
+ /*
+ * fallback
+ */
+ rsnd_dai_call(fallback, io, rdai);
+
+ /*
+ * retry to "probe".
+ * DAI has SSI which is PIO mode only now.
+ */
+ ret = rsnd_dai_call(probe, io, rdai);
+ }
+
+ return ret;
+}
+
/*
* rsnd probe
*/
@@ -1037,11 +1259,11 @@ static int rsnd_probe(struct platform_device *pdev)
}
for_each_rsnd_dai(rdai, priv, i) {
- ret = rsnd_dai_call(probe, &rdai->playback, rdai);
+ ret = rsnd_rdai_continuance_probe(priv, rdai, 1);
if (ret)
goto exit_snd_probe;
- ret = rsnd_dai_call(probe, &rdai->capture, rdai);
+ ret = rsnd_rdai_continuance_probe(priv, rdai, 0);
if (ret)
goto exit_snd_probe;
}
diff --git a/sound/soc/sh/rcar/dvc.c b/sound/soc/sh/rcar/dvc.c
index 3f44393..5380a48 100644
--- a/sound/soc/sh/rcar/dvc.c
+++ b/sound/soc/sh/rcar/dvc.c
@@ -11,8 +11,6 @@
#include "rsnd.h"
#define RSND_DVC_NAME_SIZE 16
-#define RSND_DVC_VOLUME_MAX 100
-#define RSND_DVC_VOLUME_NUM 2
#define DVC_NAME "dvc"
@@ -20,8 +18,11 @@ struct rsnd_dvc {
struct rsnd_dvc_platform_info *info; /* rcar_snd.h */
struct rsnd_mod mod;
struct clk *clk;
- u8 volume[RSND_DVC_VOLUME_NUM];
- u8 mute[RSND_DVC_VOLUME_NUM];
+ struct rsnd_kctrl_cfg_m volume;
+ struct rsnd_kctrl_cfg_m mute;
+ struct rsnd_kctrl_cfg_s ren; /* Ramp Enable */
+ struct rsnd_kctrl_cfg_s rup; /* Ramp Rate Up */
+ struct rsnd_kctrl_cfg_s rdown; /* Ramp Rate Down */
};
#define rsnd_mod_to_dvc(_mod) \
@@ -33,23 +34,87 @@ struct rsnd_dvc {
((pos) = (struct rsnd_dvc *)(priv)->dvc + i); \
i++)
+static const char const *dvc_ramp_rate[] = {
+ "128 dB/1 step", /* 00000 */
+ "64 dB/1 step", /* 00001 */
+ "32 dB/1 step", /* 00010 */
+ "16 dB/1 step", /* 00011 */
+ "8 dB/1 step", /* 00100 */
+ "4 dB/1 step", /* 00101 */
+ "2 dB/1 step", /* 00110 */
+ "1 dB/1 step", /* 00111 */
+ "0.5 dB/1 step", /* 01000 */
+ "0.25 dB/1 step", /* 01001 */
+ "0.125 dB/1 step", /* 01010 */
+ "0.125 dB/2 steps", /* 01011 */
+ "0.125 dB/4 steps", /* 01100 */
+ "0.125 dB/8 steps", /* 01101 */
+ "0.125 dB/16 steps", /* 01110 */
+ "0.125 dB/32 steps", /* 01111 */
+ "0.125 dB/64 steps", /* 10000 */
+ "0.125 dB/128 steps", /* 10001 */
+ "0.125 dB/256 steps", /* 10010 */
+ "0.125 dB/512 steps", /* 10011 */
+ "0.125 dB/1024 steps", /* 10100 */
+ "0.125 dB/2048 steps", /* 10101 */
+ "0.125 dB/4096 steps", /* 10110 */
+ "0.125 dB/8192 steps", /* 10111 */
+};
+
static void rsnd_dvc_volume_update(struct rsnd_mod *mod)
{
struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
- u32 max = (0x00800000 - 1);
- u32 vol[RSND_DVC_VOLUME_NUM];
+ u32 val[RSND_DVC_CHANNELS];
+ u32 dvucr = 0;
u32 mute = 0;
int i;
- for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
- vol[i] = max / RSND_DVC_VOLUME_MAX * dvc->volume[i];
- mute |= (!!dvc->mute[i]) << i;
+ for (i = 0; i < dvc->mute.cfg.size; i++)
+ mute |= (!!dvc->mute.cfg.val[i]) << i;
+
+ /* Disable DVC Register access */
+ rsnd_mod_write(mod, DVC_DVUER, 0);
+
+ /* Enable Ramp */
+ if (dvc->ren.val) {
+ dvucr |= 0x10;
+
+ /* Digital Volume Max */
+ for (i = 0; i < RSND_DVC_CHANNELS; i++)
+ val[i] = dvc->volume.cfg.max;
+
+ rsnd_mod_write(mod, DVC_VRCTR, 0xff);
+ rsnd_mod_write(mod, DVC_VRPDR, dvc->rup.val << 8 |
+ dvc->rdown.val);
+ /*
+ * FIXME !!
+ * use scale-downed Digital Volume
+ * as Volume Ramp
+ * 7F FFFF -> 3FF
+ */
+ rsnd_mod_write(mod, DVC_VRDBR,
+ 0x3ff - (dvc->volume.val[0] >> 13));
+
+ } else {
+ for (i = 0; i < RSND_DVC_CHANNELS; i++)
+ val[i] = dvc->volume.val[i];
+ }
+
+ /* Enable Digital Volume */
+ dvucr |= 0x100;
+ rsnd_mod_write(mod, DVC_VOL0R, val[0]);
+ rsnd_mod_write(mod, DVC_VOL1R, val[1]);
+
+ /* Enable Mute */
+ if (mute) {
+ dvucr |= 0x1;
+ rsnd_mod_write(mod, DVC_ZCMCR, mute);
}
- rsnd_mod_write(mod, DVC_VOL0R, vol[0]);
- rsnd_mod_write(mod, DVC_VOL1R, vol[1]);
+ rsnd_mod_write(mod, DVC_DVUCR, dvucr);
- rsnd_mod_write(mod, DVC_ZCMCR, mute);
+ /* Enable DVC Register access */
+ rsnd_mod_write(mod, DVC_DVUER, 1);
}
static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
@@ -58,7 +123,8 @@ static int rsnd_dvc_probe_gen2(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod));
+ dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0;
}
@@ -102,16 +168,11 @@ static int rsnd_dvc_init(struct rsnd_mod *dvc_mod,
rsnd_mod_write(dvc_mod, DVC_ADINR, rsnd_get_adinr(dvc_mod));
- /* enable Volume / Mute */
- rsnd_mod_write(dvc_mod, DVC_DVUCR, 0x101);
-
/* ch0/ch1 Volume */
rsnd_dvc_volume_update(dvc_mod);
rsnd_mod_write(dvc_mod, DVC_DVUIR, 0);
- rsnd_mod_write(dvc_mod, DVC_DVUER, 1);
-
rsnd_adg_set_cmd_timsel_gen2(rdai, dvc_mod, io);
return 0;
@@ -143,86 +204,6 @@ static int rsnd_dvc_stop(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_dvc_volume_info(struct snd_kcontrol *kctrl,
- struct snd_ctl_elem_info *uinfo)
-{
- struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
- struct rsnd_dvc *dvc = rsnd_mod_to_dvc(mod);
- u8 *val = (u8 *)kctrl->private_value;
-
- uinfo->count = RSND_DVC_VOLUME_NUM;
- uinfo->value.integer.min = 0;
-
- if (val == dvc->volume) {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->value.integer.max = RSND_DVC_VOLUME_MAX;
- } else {
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- uinfo->value.integer.max = 1;
- }
-
- return 0;
-}
-
-static int rsnd_dvc_volume_get(struct snd_kcontrol *kctrl,
- struct snd_ctl_elem_value *ucontrol)
-{
- u8 *val = (u8 *)kctrl->private_value;
- int i;
-
- for (i = 0; i < RSND_DVC_VOLUME_NUM; i++)
- ucontrol->value.integer.value[i] = val[i];
-
- return 0;
-}
-
-static int rsnd_dvc_volume_put(struct snd_kcontrol *kctrl,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct rsnd_mod *mod = snd_kcontrol_chip(kctrl);
- u8 *val = (u8 *)kctrl->private_value;
- int i, change = 0;
-
- for (i = 0; i < RSND_DVC_VOLUME_NUM; i++) {
- change |= (ucontrol->value.integer.value[i] != val[i]);
- val[i] = ucontrol->value.integer.value[i];
- }
-
- if (change)
- rsnd_dvc_volume_update(mod);
-
- return change;
-}
-
-static int __rsnd_dvc_pcm_new(struct rsnd_mod *mod,
- struct rsnd_dai *rdai,
- struct snd_soc_pcm_runtime *rtd,
- const unsigned char *name,
- u8 *private)
-{
- struct snd_card *card = rtd->card->snd_card;
- struct snd_kcontrol *kctrl;
- struct snd_kcontrol_new knew = {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = name,
- .info = rsnd_dvc_volume_info,
- .get = rsnd_dvc_volume_get,
- .put = rsnd_dvc_volume_put,
- .private_value = (unsigned long)private,
- };
- int ret;
-
- kctrl = snd_ctl_new1(&knew, mod);
- if (!kctrl)
- return -ENOMEM;
-
- ret = snd_ctl_add(card, kctrl);
- if (ret < 0)
- return ret;
-
- return 0;
-}
-
static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd)
@@ -232,18 +213,48 @@ static int rsnd_dvc_pcm_new(struct rsnd_mod *mod,
int ret;
/* Volume */
- ret = __rsnd_dvc_pcm_new(mod, rdai, rtd,
+ ret = rsnd_kctrl_new_m(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"DVC Out Playback Volume" : "DVC In Capture Volume",
- dvc->volume);
+ rsnd_dvc_volume_update,
+ &dvc->volume, 0x00800000 - 1);
if (ret < 0)
return ret;
/* Mute */
- ret = __rsnd_dvc_pcm_new(mod, rdai, rtd,
+ ret = rsnd_kctrl_new_m(mod, rdai, rtd,
rsnd_dai_is_play(rdai, io) ?
"DVC Out Mute Switch" : "DVC In Mute Switch",
- dvc->mute);
+ rsnd_dvc_volume_update,
+ &dvc->mute, 1);
+ if (ret < 0)
+ return ret;
+
+ /* Ramp */
+ ret = rsnd_kctrl_new_s(mod, rdai, rtd,
+ rsnd_dai_is_play(rdai, io) ?
+ "DVC Out Ramp Switch" : "DVC In Ramp Switch",
+ rsnd_dvc_volume_update,
+ &dvc->ren, 1);
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_kctrl_new_e(mod, rdai, rtd,
+ rsnd_dai_is_play(rdai, io) ?
+ "DVC Out Ramp Up Rate" : "DVC In Ramp Up Rate",
+ &dvc->rup,
+ rsnd_dvc_volume_update,
+ dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
+ if (ret < 0)
+ return ret;
+
+ ret = rsnd_kctrl_new_e(mod, rdai, rtd,
+ rsnd_dai_is_play(rdai, io) ?
+ "DVC Out Ramp Down Rate" : "DVC In Ramp Down Rate",
+ &dvc->rdown,
+ rsnd_dvc_volume_update,
+ dvc_ramp_rate, ARRAY_SIZE(dvc_ramp_rate));
+
if (ret < 0)
return ret;
diff --git a/sound/soc/sh/rcar/gen.c b/sound/soc/sh/rcar/gen.c
index f95e7ab..87a6f2d 100644
--- a/sound/soc/sh/rcar/gen.c
+++ b/sound/soc/sh/rcar/gen.c
@@ -8,6 +8,17 @@
* it under the terms of the GNU General Public License version 2 as
* published by the Free Software Foundation.
*/
+
+/*
+ * #define DEBUG
+ *
+ * you can also add below in
+ * ${LINUX}/drivers/base/regmap/regmap.c
+ * for regmap debug
+ *
+ * #define LOG_DEVICE "xxxx.rcar_sound"
+ */
+
#include "rsnd.h"
struct rsnd_gen {
@@ -67,9 +78,10 @@ u32 rsnd_read(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return 0;
- regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
+ dev_dbg(dev, "r %s[%d] - %4d : %08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod), reg, val);
- dev_dbg(dev, "r %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, val);
+ regmap_fields_read(gen->regs[reg], rsnd_mod_id(mod), &val);
return val;
}
@@ -84,9 +96,10 @@ void rsnd_write(struct rsnd_priv *priv,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
- regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
+ dev_dbg(dev, "w %s[%d] - %4d : %08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data);
- dev_dbg(dev, "w %s - 0x%04d : %08x\n", rsnd_mod_name(mod), reg, data);
+ regmap_fields_write(gen->regs[reg], rsnd_mod_id(mod), data);
}
void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
@@ -98,11 +111,11 @@ void rsnd_bset(struct rsnd_priv *priv, struct rsnd_mod *mod,
if (!rsnd_is_accessible_reg(priv, gen, reg))
return;
+ dev_dbg(dev, "b %s[%d] - %4d : %08x/%08x\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod), reg, data, mask);
+
regmap_fields_update_bits(gen->regs[reg], rsnd_mod_id(mod),
mask, data);
-
- dev_dbg(dev, "b %s - 0x%04d : %08x/%08x\n",
- rsnd_mod_name(mod), reg, data, mask);
}
#define rsnd_gen_regmap_init(priv, id_size, reg_id, conf) \
@@ -311,6 +324,9 @@ static int rsnd_gen2_probe(struct platform_device *pdev,
RSND_GEN_M_REG(DVC_ADINR, 0xe08, 0x100),
RSND_GEN_M_REG(DVC_DVUCR, 0xe10, 0x100),
RSND_GEN_M_REG(DVC_ZCMCR, 0xe14, 0x100),
+ RSND_GEN_M_REG(DVC_VRCTR, 0xe18, 0x100),
+ RSND_GEN_M_REG(DVC_VRPDR, 0xe1c, 0x100),
+ RSND_GEN_M_REG(DVC_VRDBR, 0xe20, 0x100),
RSND_GEN_M_REG(DVC_VOL0R, 0xe28, 0x100),
RSND_GEN_M_REG(DVC_VOL1R, 0xe2c, 0x100),
RSND_GEN_M_REG(DVC_DVUER, 0xe48, 0x100),
diff --git a/sound/soc/sh/rcar/rsnd.h b/sound/soc/sh/rcar/rsnd.h
index d119adf..5826c8a 100644
--- a/sound/soc/sh/rcar/rsnd.h
+++ b/sound/soc/sh/rcar/rsnd.h
@@ -91,6 +91,9 @@ enum rsnd_reg {
RSND_REG_SHARE20,
RSND_REG_SHARE21,
RSND_REG_SHARE22,
+ RSND_REG_SHARE23,
+ RSND_REG_SHARE24,
+ RSND_REG_SHARE25,
RSND_REG_MAX,
};
@@ -129,6 +132,9 @@ enum rsnd_reg {
#define RSND_REG_CMD_CTRL RSND_REG_SHARE20
#define RSND_REG_CMDOUT_TIMSEL RSND_REG_SHARE21
#define RSND_REG_BUSIF_DALIGN RSND_REG_SHARE22
+#define RSND_REG_DVC_VRCTR RSND_REG_SHARE23
+#define RSND_REG_DVC_VRPDR RSND_REG_SHARE24
+#define RSND_REG_DVC_VRDBR RSND_REG_SHARE25
struct rsnd_of_data;
struct rsnd_priv;
@@ -200,6 +206,8 @@ struct rsnd_mod_ops {
int (*pcm_new)(struct rsnd_mod *mod,
struct rsnd_dai *rdai,
struct snd_soc_pcm_runtime *rtd);
+ int (*fallback)(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai);
};
struct rsnd_dai_stream;
@@ -210,7 +218,35 @@ struct rsnd_mod {
struct rsnd_mod_ops *ops;
struct rsnd_dma dma;
struct rsnd_dai_stream *io;
+ u32 status;
};
+/*
+ * status
+ *
+ * bit
+ * 0 0: probe 1: remove
+ * 1 0: init 1: quit
+ * 2 0: start 1: stop
+ * 3 0: pcm_new
+ * 4 0: fallback
+ */
+#define __rsnd_mod_shift_probe 0
+#define __rsnd_mod_shift_remove 0
+#define __rsnd_mod_shift_init 1
+#define __rsnd_mod_shift_quit 1
+#define __rsnd_mod_shift_start 2
+#define __rsnd_mod_shift_stop 2
+#define __rsnd_mod_shift_pcm_new 3
+#define __rsnd_mod_shift_fallback 4
+
+#define __rsnd_mod_call_probe 0
+#define __rsnd_mod_call_remove 1
+#define __rsnd_mod_call_init 0
+#define __rsnd_mod_call_quit 1
+#define __rsnd_mod_call_start 0
+#define __rsnd_mod_call_stop 1
+#define __rsnd_mod_call_pcm_new 0
+#define __rsnd_mod_call_fallback 0
#define rsnd_mod_to_priv(mod) ((mod)->priv)
#define rsnd_mod_to_dma(mod) (&(mod)->dma)
@@ -267,7 +303,8 @@ struct rsnd_dai *rsnd_dai_get(struct rsnd_priv *priv, int id);
int rsnd_dai_is_play(struct rsnd_dai *rdai, struct rsnd_dai_stream *io);
int rsnd_dai_id(struct rsnd_priv *priv, struct rsnd_dai *rdai);
#define rsnd_dai_get_platform_info(rdai) ((rdai)->info)
-#define rsnd_io_to_runtime(io) ((io)->substream->runtime)
+#define rsnd_io_to_runtime(io) ((io)->substream ? \
+ (io)->substream->runtime : NULL)
void rsnd_dai_pointer_update(struct rsnd_dai_stream *io, int cnt);
int rsnd_dai_pointer_offset(struct rsnd_dai_stream *io, int additional);
@@ -382,6 +419,51 @@ struct rsnd_priv {
})
/*
+ * rsnd_kctrl
+ */
+struct rsnd_kctrl_cfg {
+ unsigned int max;
+ unsigned int size;
+ u32 *val;
+ const char * const *texts;
+ void (*update)(struct rsnd_mod *mod);
+};
+
+#define RSND_DVC_CHANNELS 2
+struct rsnd_kctrl_cfg_m {
+ struct rsnd_kctrl_cfg cfg;
+ u32 val[RSND_DVC_CHANNELS];
+};
+
+struct rsnd_kctrl_cfg_s {
+ struct rsnd_kctrl_cfg cfg;
+ u32 val;
+};
+
+int rsnd_kctrl_new_m(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ void (*update)(struct rsnd_mod *mod),
+ struct rsnd_kctrl_cfg_m *_cfg,
+ u32 max);
+int rsnd_kctrl_new_s(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ void (*update)(struct rsnd_mod *mod),
+ struct rsnd_kctrl_cfg_s *_cfg,
+ u32 max);
+int rsnd_kctrl_new_e(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai,
+ struct snd_soc_pcm_runtime *rtd,
+ const unsigned char *name,
+ struct rsnd_kctrl_cfg_s *_cfg,
+ void (*update)(struct rsnd_mod *mod),
+ const char * const *texts,
+ u32 max);
+
+/*
* R-Car SRC
*/
int rsnd_src_probe(struct platform_device *pdev,
@@ -395,10 +477,11 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai,
int use_busif);
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
- struct rsnd_dai *rdai,
- int use_busif);
-int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai);
+int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai);
+int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai);
#define rsnd_src_nr(priv) ((priv)->src_nr)
@@ -410,6 +493,7 @@ int rsnd_ssi_probe(struct platform_device *pdev,
struct rsnd_priv *priv);
struct rsnd_mod *rsnd_ssi_mod_get(struct rsnd_priv *priv, int id);
int rsnd_ssi_is_pin_sharing(struct rsnd_mod *mod);
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod);
/*
* R-Car DVC
diff --git a/sound/soc/sh/rcar/src.c b/sound/soc/sh/rcar/src.c
index 9183e01..eede3ac 100644
--- a/sound/soc/sh/rcar/src.c
+++ b/sound/soc/sh/rcar/src.c
@@ -175,30 +175,47 @@ int rsnd_src_ssiu_start(struct rsnd_mod *ssi_mod,
}
int rsnd_src_ssiu_stop(struct rsnd_mod *ssi_mod,
- struct rsnd_dai *rdai,
- int use_busif)
+ struct rsnd_dai *rdai)
{
/*
* DMA settings for SSIU
*/
- if (use_busif)
- rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
+ rsnd_mod_write(ssi_mod, SSI_CTRL, 0);
return 0;
}
-int rsnd_src_enable_ssi_irq(struct rsnd_mod *ssi_mod,
+int rsnd_src_ssi_irq_enable(struct rsnd_mod *ssi_mod,
struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
- /* enable PIO interrupt if Gen2 */
- if (rsnd_is_gen2(priv))
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ /* enable SSI interrupt if Gen2 */
+ if (rsnd_ssi_is_dma_mode(ssi_mod))
+ rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0e000000);
+ else
rsnd_mod_write(ssi_mod, INT_ENABLE, 0x0f000000);
return 0;
}
+int rsnd_src_ssi_irq_disable(struct rsnd_mod *ssi_mod,
+ struct rsnd_dai *rdai)
+{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(ssi_mod);
+
+ if (rsnd_is_gen1(priv))
+ return 0;
+
+ /* disable SSI interrupt if Gen2 */
+ rsnd_mod_write(ssi_mod, INT_ENABLE, 0x00000000);
+
+ return 0;
+}
+
unsigned int rsnd_src_get_ssi_rate(struct rsnd_priv *priv,
struct rsnd_dai_stream *io,
struct snd_pcm_runtime *runtime)
@@ -239,12 +256,6 @@ static int rsnd_src_set_convert_rate(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_SWRSR, 0);
rsnd_mod_write(mod, SRC_SWRSR, 1);
- /*
- * Initialize the operation of the SRC internal circuits
- * see rsnd_src_start()
- */
- rsnd_mod_write(mod, SRC_SRCIR, 1);
-
/* Set channel number and output bit length */
rsnd_mod_write(mod, SRC_ADINR, rsnd_get_adinr(mod));
@@ -269,6 +280,12 @@ static int rsnd_src_init(struct rsnd_mod *mod,
clk_prepare_enable(src->clk);
+ /*
+ * Initialize the operation of the SRC internal circuits
+ * see rsnd_src_start()
+ */
+ rsnd_mod_write(mod, SRC_SRCIR, 1);
+
return 0;
}
@@ -282,32 +299,20 @@ static int rsnd_src_quit(struct rsnd_mod *mod,
return 0;
}
-static int rsnd_src_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai)
+static int rsnd_src_start(struct rsnd_mod *mod)
{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
-
/*
* Cancel the initialization and operate the SRC function
- * see rsnd_src_set_convert_rate()
+ * see rsnd_src_init()
*/
rsnd_mod_write(mod, SRC_SRCIR, 0);
- if (rsnd_src_convert_rate(src))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
-
return 0;
}
-
-static int rsnd_src_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai)
+static int rsnd_src_stop(struct rsnd_mod *mod)
{
- struct rsnd_src *src = rsnd_mod_to_src(mod);
-
- if (rsnd_src_convert_rate(src))
- rsnd_mod_write(mod, SRC_ROUTE_MODE0, 0);
-
+ /* nothing to do */
return 0;
}
@@ -414,6 +419,7 @@ static int rsnd_src_set_convert_timing_gen1(struct rsnd_mod *mod,
static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
+ struct rsnd_src *src = rsnd_mod_to_src(mod);
int ret;
ret = rsnd_src_set_convert_rate(mod, rdai);
@@ -427,6 +433,10 @@ static int rsnd_src_set_convert_rate_gen1(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_MNFSR,
rsnd_mod_read(mod, SRC_IFSVR) / 100 * 98);
+ /* Gen1/Gen2 are not compatible */
+ if (rsnd_src_convert_rate(src))
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+
/* no SRC_BFSSR settings, since SRC_SRCCR::BUFMD is 0 */
return 0;
@@ -438,7 +448,8 @@ static int rsnd_src_probe_gen1(struct rsnd_mod *mod,
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
- dev_dbg(dev, "%s (Gen1) is probed\n", rsnd_mod_name(mod));
+ dev_dbg(dev, "%s[%d] (Gen1) is probed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
return 0;
}
@@ -474,7 +485,7 @@ static int rsnd_src_start_gen1(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), (1 << id));
- return rsnd_src_start(mod, rdai);
+ return rsnd_src_start(mod);
}
static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
@@ -484,7 +495,7 @@ static int rsnd_src_stop_gen1(struct rsnd_mod *mod,
rsnd_mod_bset(mod, SRC_ROUTE_CTRL, (1 << id), 0);
- return rsnd_src_stop(mod, rdai);
+ return rsnd_src_stop(mod);
}
static struct rsnd_mod_ops rsnd_src_gen1_ops = {
@@ -507,16 +518,17 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
struct rsnd_src *src = rsnd_mod_to_src(mod);
+ u32 convert_rate = rsnd_src_convert_rate(src);
uint ratio;
int ret;
/* 6 - 1/6 are very enough ratio for SRC_BSDSR */
- if (!rsnd_src_convert_rate(src))
+ if (!convert_rate)
ratio = 0;
- else if (rsnd_src_convert_rate(src) > runtime->rate)
- ratio = 100 * rsnd_src_convert_rate(src) / runtime->rate;
+ else if (convert_rate > runtime->rate)
+ ratio = 100 * convert_rate / runtime->rate;
else
- ratio = 100 * runtime->rate / rsnd_src_convert_rate(src);
+ ratio = 100 * runtime->rate / convert_rate;
if (ratio > 600) {
dev_err(dev, "FSO/FSI ratio error\n");
@@ -529,6 +541,11 @@ static int rsnd_src_set_convert_rate_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_SRCCR, 0x00011110);
+ if (convert_rate) {
+ /* Gen1/Gen2 are not compatible */
+ rsnd_mod_write(mod, SRC_ROUTE_MODE0, 1);
+ }
+
switch (rsnd_mod_id(mod)) {
case 5:
case 6:
@@ -578,9 +595,11 @@ static int rsnd_src_probe_gen2(struct rsnd_mod *mod,
rsnd_info_is_playback(priv, src),
src->info->dma_id);
if (ret < 0)
- dev_err(dev, "SRC DMA failed\n");
-
- dev_dbg(dev, "%s (Gen2) is probed\n", rsnd_mod_name(mod));
+ dev_err(dev, "%s[%d] (Gen2) failed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
+ else
+ dev_dbg(dev, "%s[%d] (Gen2) is probed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
@@ -624,7 +643,7 @@ static int rsnd_src_start_gen2(struct rsnd_mod *mod,
rsnd_mod_write(mod, SRC_CTRL, val);
- return rsnd_src_start(mod, rdai);
+ return rsnd_src_start(mod);
}
static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
@@ -636,7 +655,7 @@ static int rsnd_src_stop_gen2(struct rsnd_mod *mod,
rsnd_dma_stop(rsnd_mod_to_dma(&src->mod));
- return rsnd_src_stop(mod, rdai);
+ return rsnd_src_stop(mod);
}
static struct rsnd_mod_ops rsnd_src_gen2_ops = {
diff --git a/sound/soc/sh/rcar/ssi.c b/sound/soc/sh/rcar/ssi.c
index 34e8400..3844fbe 100644
--- a/sound/soc/sh/rcar/ssi.c
+++ b/sound/soc/sh/rcar/ssi.c
@@ -68,7 +68,6 @@ struct rsnd_ssi {
struct rsnd_dai *rdai;
u32 cr_own;
u32 cr_clk;
- u32 cr_etc;
int err;
unsigned int usrcnt;
unsigned int rate;
@@ -83,7 +82,7 @@ struct rsnd_ssi {
#define rsnd_ssi_nr(priv) ((priv)->ssi_nr)
#define rsnd_mod_to_ssi(_mod) container_of((_mod), struct rsnd_ssi, mod)
#define rsnd_dma_to_ssi(dma) rsnd_mod_to_ssi(rsnd_dma_to_mod(dma))
-#define rsnd_ssi_pio_available(ssi) ((ssi)->info->pio_irq > 0)
+#define rsnd_ssi_pio_available(ssi) ((ssi)->info->irq > 0)
#define rsnd_ssi_dma_available(ssi) \
rsnd_dma_available(rsnd_mod_to_dma(&(ssi)->mod))
#define rsnd_ssi_clk_from_parent(ssi) ((ssi)->parent)
@@ -96,6 +95,9 @@ static int rsnd_ssi_use_busif(struct rsnd_mod *mod)
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
int use_busif = 0;
+ if (!rsnd_ssi_is_dma_mode(mod))
+ return 0;
+
if (!(rsnd_ssi_mode_flags(ssi) & RSND_SSI_NO_BUSIF))
use_busif = 1;
if (rsnd_io_to_mod_src(io))
@@ -159,7 +161,8 @@ static int rsnd_ssi_master_clk_start(struct rsnd_ssi *ssi,
ssi->cr_clk = FORCE | SWL_32 |
SCKD | SWSD | CKDV(j);
- dev_dbg(dev, "ssi%d outputs %u Hz\n",
+ dev_dbg(dev, "%s[%d] outputs %u Hz\n",
+ rsnd_mod_name(&ssi->mod),
rsnd_mod_id(&ssi->mod), rate);
return 0;
@@ -184,6 +187,7 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
{
struct rsnd_priv *priv = rsnd_mod_to_priv(&ssi->mod);
struct device *dev = rsnd_priv_to_dev(priv);
+ u32 cr_mode;
u32 cr;
if (0 == ssi->usrcnt) {
@@ -197,16 +201,29 @@ static void rsnd_ssi_hw_start(struct rsnd_ssi *ssi,
}
}
+ cr_mode = rsnd_ssi_is_dma_mode(&ssi->mod) ?
+ DMEN : /* DMA : enable DMA */
+ DIEN; /* PIO : enable Data interrupt */
+
+
cr = ssi->cr_own |
ssi->cr_clk |
- ssi->cr_etc |
- EN;
+ cr_mode |
+ UIEN | OIEN | EN;
rsnd_mod_write(&ssi->mod, SSICR, cr);
+ /* enable WS continue */
+ if (rsnd_dai_is_clk_master(rdai))
+ rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+
+ /* clear error status */
+ rsnd_mod_write(&ssi->mod, SSISR, 0);
+
ssi->usrcnt++;
- dev_dbg(dev, "ssi%d hw started\n", rsnd_mod_id(&ssi->mod));
+ dev_dbg(dev, "%s[%d] hw started\n",
+ rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
}
static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
@@ -249,7 +266,8 @@ static void rsnd_ssi_hw_stop(struct rsnd_ssi *ssi,
clk_disable_unprepare(ssi->clk);
}
- dev_dbg(dev, "ssi%d hw stopped\n", rsnd_mod_id(&ssi->mod));
+ dev_dbg(dev, "%s[%d] hw stopped\n",
+ rsnd_mod_name(&ssi->mod), rsnd_mod_id(&ssi->mod));
}
/*
@@ -334,25 +352,54 @@ static void rsnd_ssi_record_error(struct rsnd_ssi *ssi, u32 status)
}
}
-/*
- * SSI PIO
- */
-static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
+static int rsnd_ssi_start(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+
+ rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
+
+ rsnd_ssi_hw_start(ssi, rdai, io);
+
+ rsnd_src_ssi_irq_enable(mod, rdai);
+
+ return 0;
+}
+
+static int rsnd_ssi_stop(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
+{
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+
+ rsnd_src_ssi_irq_disable(mod, rdai);
+
+ rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
+
+ rsnd_ssi_hw_stop(ssi, rdai);
+
+ rsnd_src_ssiu_stop(mod, rdai);
+
+ return 0;
+}
+
+static irqreturn_t rsnd_ssi_interrupt(int irq, void *data)
{
struct rsnd_ssi *ssi = data;
+ struct rsnd_dai *rdai = ssi->rdai;
struct rsnd_mod *mod = &ssi->mod;
struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
u32 status = rsnd_mod_read(mod, SSISR);
- irqreturn_t ret = IRQ_NONE;
- if (io && (status & DIRQ)) {
- struct rsnd_dai *rdai = ssi->rdai;
+ if (!io)
+ return IRQ_NONE;
+
+ /* PIO only */
+ if (status & DIRQ) {
struct snd_pcm_runtime *runtime = rsnd_io_to_runtime(io);
u32 *buf = (u32 *)(runtime->dma_area +
rsnd_dai_pointer_offset(io, 0));
- rsnd_ssi_record_error(ssi, status);
-
/*
* 8/16/32 data can be assesse to TDR/RDR register
* directly as 32bit data
@@ -364,73 +411,60 @@ static irqreturn_t rsnd_ssi_pio_interrupt(int irq, void *data)
*buf = rsnd_mod_read(mod, SSIRDR);
rsnd_dai_pointer_update(io, sizeof(*buf));
+ }
+
+ /* PIO / DMA */
+ if (status & (UIRQ | OIRQ)) {
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+
+ /*
+ * restart SSI
+ */
+ rsnd_ssi_stop(mod, rdai);
+ rsnd_ssi_start(mod, rdai);
- ret = IRQ_HANDLED;
+ dev_dbg(dev, "%s[%d] restart\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
}
- return ret;
+ rsnd_ssi_record_error(ssi, status);
+
+ return IRQ_HANDLED;
}
+/*
+ * SSI PIO
+ */
static int rsnd_ssi_pio_probe(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
struct device *dev = rsnd_priv_to_dev(priv);
struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- int irq = ssi->info->pio_irq;
int ret;
- ret = devm_request_irq(dev, irq,
- rsnd_ssi_pio_interrupt,
+ ret = devm_request_irq(dev, ssi->info->irq,
+ rsnd_ssi_interrupt,
IRQF_SHARED,
dev_name(dev), ssi);
if (ret)
- dev_err(dev, "SSI request interrupt failed\n");
-
- dev_dbg(dev, "%s (PIO) is probed\n", rsnd_mod_name(mod));
+ dev_err(dev, "%s[%d] (PIO) request interrupt failed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
+ else
+ dev_dbg(dev, "%s[%d] (PIO) is probed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
-static int rsnd_ssi_pio_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
-
- /* enable PIO IRQ */
- ssi->cr_etc = UIEN | OIEN | DIEN;
-
- rsnd_src_ssiu_start(mod, rdai, 0);
-
- rsnd_src_enable_ssi_irq(mod, rdai);
-
- rsnd_ssi_hw_start(ssi, rdai, io);
-
- return 0;
-}
-
-static int rsnd_ssi_pio_stop(struct rsnd_mod *mod,
- struct rsnd_dai *rdai)
-{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
-
- ssi->cr_etc = 0;
-
- rsnd_ssi_hw_stop(ssi, rdai);
-
- rsnd_src_ssiu_stop(mod, rdai, 0);
-
- return 0;
-}
-
static struct rsnd_mod_ops rsnd_ssi_pio_ops = {
.name = SSI_NAME,
.probe = rsnd_ssi_pio_probe,
.init = rsnd_ssi_init,
.quit = rsnd_ssi_quit,
- .start = rsnd_ssi_pio_start,
- .stop = rsnd_ssi_pio_stop,
+ .start = rsnd_ssi_start,
+ .stop = rsnd_ssi_stop,
};
static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
@@ -442,15 +476,28 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
int dma_id = ssi->info->dma_id;
int ret;
+ ret = devm_request_irq(dev, ssi->info->irq,
+ rsnd_ssi_interrupt,
+ IRQF_SHARED,
+ dev_name(dev), ssi);
+ if (ret)
+ goto rsnd_ssi_dma_probe_fail;
+
ret = rsnd_dma_init(
priv, rsnd_mod_to_dma(mod),
rsnd_info_is_playback(priv, ssi),
dma_id);
+ if (ret)
+ goto rsnd_ssi_dma_probe_fail;
- if (ret < 0)
- dev_err(dev, "SSI DMA failed\n");
+ dev_dbg(dev, "%s[%d] (DMA) is probed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
+
+ return ret;
- dev_dbg(dev, "%s (DMA) is probed\n", rsnd_mod_name(mod));
+rsnd_ssi_dma_probe_fail:
+ dev_err(dev, "%s[%d] (DMA) is failed\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
return ret;
}
@@ -458,30 +505,48 @@ static int rsnd_ssi_dma_probe(struct rsnd_mod *mod,
static int rsnd_ssi_dma_remove(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
+ int irq = ssi->info->irq;
+
rsnd_dma_quit(rsnd_mod_to_priv(mod), rsnd_mod_to_dma(mod));
+ /* PIO will request IRQ again */
+ devm_free_irq(dev, irq, ssi);
+
return 0;
}
-static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
- struct rsnd_dai *rdai)
+static int rsnd_ssi_fallback(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
- struct rsnd_dai_stream *io = rsnd_mod_to_io(mod);
+ struct rsnd_priv *priv = rsnd_mod_to_priv(mod);
+ struct device *dev = rsnd_priv_to_dev(priv);
- /* enable DMA transfer */
- ssi->cr_etc = DMEN;
+ /*
+ * fallback to PIO
+ *
+ * SSI .probe might be called again.
+ * see
+ * rsnd_rdai_continuance_probe()
+ */
+ mod->ops = &rsnd_ssi_pio_ops;
- rsnd_src_ssiu_start(mod, rdai, rsnd_ssi_use_busif(mod));
+ dev_info(dev, "%s[%d] fallback to PIO mode\n",
+ rsnd_mod_name(mod), rsnd_mod_id(mod));
- rsnd_dma_start(dma);
+ return 0;
+}
- rsnd_ssi_hw_start(ssi, ssi->rdai, io);
+static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
+ struct rsnd_dai *rdai)
+{
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
- /* enable WS continue */
- if (rsnd_dai_is_clk_master(rdai))
- rsnd_mod_write(&ssi->mod, SSIWSR, CONT);
+ rsnd_ssi_start(mod, rdai);
+
+ rsnd_dma_start(dma);
return 0;
}
@@ -489,18 +554,11 @@ static int rsnd_ssi_dma_start(struct rsnd_mod *mod,
static int rsnd_ssi_dma_stop(struct rsnd_mod *mod,
struct rsnd_dai *rdai)
{
- struct rsnd_ssi *ssi = rsnd_mod_to_ssi(mod);
- struct rsnd_dma *dma = rsnd_mod_to_dma(&ssi->mod);
-
- ssi->cr_etc = 0;
-
- rsnd_ssi_record_error(ssi, rsnd_mod_read(mod, SSISR));
-
- rsnd_ssi_hw_stop(ssi, rdai);
+ struct rsnd_dma *dma = rsnd_mod_to_dma(mod);
rsnd_dma_stop(dma);
- rsnd_src_ssiu_stop(mod, rdai, 1);
+ rsnd_ssi_stop(mod, rdai);
return 0;
}
@@ -519,8 +577,15 @@ static struct rsnd_mod_ops rsnd_ssi_dma_ops = {
.quit = rsnd_ssi_quit,
.start = rsnd_ssi_dma_start,
.stop = rsnd_ssi_dma_stop,
+ .fallback = rsnd_ssi_fallback,
};
+int rsnd_ssi_is_dma_mode(struct rsnd_mod *mod)
+{
+ return mod->ops == &rsnd_ssi_dma_ops;
+}
+
+
/*
* Non SSI
*/
@@ -614,7 +679,7 @@ static void rsnd_of_parse_ssi(struct platform_device *pdev,
/*
* irq
*/
- ssi_info->pio_irq = irq_of_parse_and_map(np, 0);
+ ssi_info->irq = irq_of_parse_and_map(np, 0);
/*
* DMA
diff --git a/sound/soc/soc-ac97.c b/sound/soc/soc-ac97.c
new file mode 100644
index 0000000..2e10e9a
--- /dev/null
+++ b/sound/soc/soc-ac97.c
@@ -0,0 +1,256 @@
+/*
+ * soc-ac97.c -- ALSA SoC Audio Layer AC97 support
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * with code, comments and ideas from :-
+ * Richard Purdie <richard@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/ctype.h>
+#include <linux/delay.h>
+#include <linux/export.h>
+#include <linux/gpio.h>
+#include <linux/init.h>
+#include <linux/of_gpio.h>
+#include <linux/of.h>
+#include <linux/pinctrl/consumer.h>
+#include <linux/slab.h>
+#include <sound/ac97_codec.h>
+#include <sound/soc.h>
+
+struct snd_ac97_reset_cfg {
+ struct pinctrl *pctl;
+ struct pinctrl_state *pstate_reset;
+ struct pinctrl_state *pstate_warm_reset;
+ struct pinctrl_state *pstate_run;
+ int gpio_sdata;
+ int gpio_sync;
+ int gpio_reset;
+};
+
+static struct snd_ac97_bus soc_ac97_bus = {
+ .ops = NULL, /* Gets initialized in snd_soc_set_ac97_ops() */
+};
+
+static void soc_ac97_device_release(struct device *dev)
+{
+ kfree(to_ac97_t(dev));
+}
+
+/**
+ * snd_soc_new_ac97_codec - initailise AC97 device
+ * @codec: audio codec
+ *
+ * Initialises AC97 codec resources for use by ad-hoc devices only.
+ */
+struct snd_ac97 *snd_soc_new_ac97_codec(struct snd_soc_codec *codec)
+{
+ struct snd_ac97 *ac97;
+ int ret;
+
+ ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
+ if (ac97 == NULL)
+ return ERR_PTR(-ENOMEM);
+
+ ac97->bus = &soc_ac97_bus;
+ ac97->num = 0;
+
+ ac97->dev.bus = &ac97_bus_type;
+ ac97->dev.parent = codec->component.card->dev;
+ ac97->dev.release = soc_ac97_device_release;
+
+ dev_set_name(&ac97->dev, "%d-%d:%s",
+ codec->component.card->snd_card->number, 0,
+ codec->component.name);
+
+ ret = device_register(&ac97->dev);
+ if (ret) {
+ put_device(&ac97->dev);
+ return ERR_PTR(ret);
+ }
+
+ return ac97;
+}
+EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
+
+/**
+ * snd_soc_free_ac97_codec - free AC97 codec device
+ * @codec: audio codec
+ *
+ * Frees AC97 codec device resources.
+ */
+void snd_soc_free_ac97_codec(struct snd_ac97 *ac97)
+{
+ device_del(&ac97->dev);
+ ac97->bus = NULL;
+ put_device(&ac97->dev);
+}
+EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
+
+static struct snd_ac97_reset_cfg snd_ac97_rst_cfg;
+
+static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97)
+{
+ struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
+
+ pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset);
+
+ gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1);
+
+ udelay(10);
+
+ gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
+
+ pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
+ msleep(2);
+}
+
+static void snd_soc_ac97_reset(struct snd_ac97 *ac97)
+{
+ struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
+
+ pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset);
+
+ gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
+ gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0);
+ gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0);
+
+ udelay(10);
+
+ gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1);
+
+ pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
+ msleep(2);
+}
+
+static int snd_soc_ac97_parse_pinctl(struct device *dev,
+ struct snd_ac97_reset_cfg *cfg)
+{
+ struct pinctrl *p;
+ struct pinctrl_state *state;
+ int gpio;
+ int ret;
+
+ p = devm_pinctrl_get(dev);
+ if (IS_ERR(p)) {
+ dev_err(dev, "Failed to get pinctrl\n");
+ return PTR_ERR(p);
+ }
+ cfg->pctl = p;
+
+ state = pinctrl_lookup_state(p, "ac97-reset");
+ if (IS_ERR(state)) {
+ dev_err(dev, "Can't find pinctrl state ac97-reset\n");
+ return PTR_ERR(state);
+ }
+ cfg->pstate_reset = state;
+
+ state = pinctrl_lookup_state(p, "ac97-warm-reset");
+ if (IS_ERR(state)) {
+ dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
+ return PTR_ERR(state);
+ }
+ cfg->pstate_warm_reset = state;
+
+ state = pinctrl_lookup_state(p, "ac97-running");
+ if (IS_ERR(state)) {
+ dev_err(dev, "Can't find pinctrl state ac97-running\n");
+ return PTR_ERR(state);
+ }
+ cfg->pstate_run = state;
+
+ gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0);
+ if (gpio < 0) {
+ dev_err(dev, "Can't find ac97-sync gpio\n");
+ return gpio;
+ }
+ ret = devm_gpio_request(dev, gpio, "AC97 link sync");
+ if (ret) {
+ dev_err(dev, "Failed requesting ac97-sync gpio\n");
+ return ret;
+ }
+ cfg->gpio_sync = gpio;
+
+ gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1);
+ if (gpio < 0) {
+ dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio);
+ return gpio;
+ }
+ ret = devm_gpio_request(dev, gpio, "AC97 link sdata");
+ if (ret) {
+ dev_err(dev, "Failed requesting ac97-sdata gpio\n");
+ return ret;
+ }
+ cfg->gpio_sdata = gpio;
+
+ gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
+ if (gpio < 0) {
+ dev_err(dev, "Can't find ac97-reset gpio\n");
+ return gpio;
+ }
+ ret = devm_gpio_request(dev, gpio, "AC97 link reset");
+ if (ret) {
+ dev_err(dev, "Failed requesting ac97-reset gpio\n");
+ return ret;
+ }
+ cfg->gpio_reset = gpio;
+
+ return 0;
+}
+
+struct snd_ac97_bus_ops *soc_ac97_ops;
+EXPORT_SYMBOL_GPL(soc_ac97_ops);
+
+int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
+{
+ if (ops == soc_ac97_ops)
+ return 0;
+
+ if (soc_ac97_ops && ops)
+ return -EBUSY;
+
+ soc_ac97_ops = ops;
+ soc_ac97_bus.ops = ops;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
+
+/**
+ * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions
+ *
+ * This function sets the reset and warm_reset properties of ops and parses
+ * the device node of pdev to get pinctrl states and gpio numbers to use.
+ */
+int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
+ struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct snd_ac97_reset_cfg cfg;
+ int ret;
+
+ ret = snd_soc_ac97_parse_pinctl(dev, &cfg);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_set_ac97_ops(ops);
+ if (ret)
+ return ret;
+
+ ops->warm_reset = snd_soc_ac97_warm_reset;
+ ops->reset = snd_soc_ac97_reset;
+
+ snd_ac97_rst_cfg = cfg;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
diff --git a/sound/soc/soc-cache.c b/sound/soc/soc-cache.c
index a9f82b5..07f4335 100644
--- a/sound/soc/soc-cache.c
+++ b/sound/soc/soc-cache.c
@@ -15,56 +15,6 @@
#include <linux/export.h>
#include <linux/slab.h>
-#include <trace/events/asoc.h>
-
-static bool snd_soc_set_cache_val(void *base, unsigned int idx,
- unsigned int val, unsigned int word_size)
-{
- switch (word_size) {
- case 1: {
- u8 *cache = base;
- if (cache[idx] == val)
- return true;
- cache[idx] = val;
- break;
- }
- case 2: {
- u16 *cache = base;
- if (cache[idx] == val)
- return true;
- cache[idx] = val;
- break;
- }
- default:
- WARN(1, "Invalid word_size %d\n", word_size);
- break;
- }
- return false;
-}
-
-static unsigned int snd_soc_get_cache_val(const void *base, unsigned int idx,
- unsigned int word_size)
-{
- if (!base)
- return -1;
-
- switch (word_size) {
- case 1: {
- const u8 *cache = base;
- return cache[idx];
- }
- case 2: {
- const u16 *cache = base;
- return cache[idx];
- }
- default:
- WARN(1, "Invalid word_size %d\n", word_size);
- break;
- }
- /* unreachable */
- return -1;
-}
-
int snd_soc_cache_init(struct snd_soc_codec *codec)
{
const struct snd_soc_codec_driver *codec_drv = codec->driver;
@@ -75,8 +25,6 @@ int snd_soc_cache_init(struct snd_soc_codec *codec)
if (!reg_size)
return 0;
- mutex_init(&codec->cache_rw_mutex);
-
dev_dbg(codec->dev, "ASoC: Initializing cache for %s codec\n",
codec->component.name);
@@ -103,100 +51,3 @@ int snd_soc_cache_exit(struct snd_soc_codec *codec)
codec->reg_cache = NULL;
return 0;
}
-
-/**
- * snd_soc_cache_read: Fetch the value of a given register from the cache.
- *
- * @codec: CODEC to configure.
- * @reg: The register index.
- * @value: The value to be returned.
- */
-int snd_soc_cache_read(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int *value)
-{
- if (!value)
- return -EINVAL;
-
- mutex_lock(&codec->cache_rw_mutex);
- if (!ZERO_OR_NULL_PTR(codec->reg_cache))
- *value = snd_soc_get_cache_val(codec->reg_cache, reg,
- codec->driver->reg_word_size);
- mutex_unlock(&codec->cache_rw_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_cache_read);
-
-/**
- * snd_soc_cache_write: Set the value of a given register in the cache.
- *
- * @codec: CODEC to configure.
- * @reg: The register index.
- * @value: The new register value.
- */
-int snd_soc_cache_write(struct snd_soc_codec *codec,
- unsigned int reg, unsigned int value)
-{
- mutex_lock(&codec->cache_rw_mutex);
- if (!ZERO_OR_NULL_PTR(codec->reg_cache))
- snd_soc_set_cache_val(codec->reg_cache, reg, value,
- codec->driver->reg_word_size);
- mutex_unlock(&codec->cache_rw_mutex);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_cache_write);
-
-static int snd_soc_flat_cache_sync(struct snd_soc_codec *codec)
-{
- int i;
- int ret;
- const struct snd_soc_codec_driver *codec_drv;
- unsigned int val;
-
- codec_drv = codec->driver;
- for (i = 0; i < codec_drv->reg_cache_size; ++i) {
- ret = snd_soc_cache_read(codec, i, &val);
- if (ret)
- return ret;
- if (codec_drv->reg_cache_default)
- if (snd_soc_get_cache_val(codec_drv->reg_cache_default,
- i, codec_drv->reg_word_size) == val)
- continue;
-
- ret = snd_soc_write(codec, i, val);
- if (ret)
- return ret;
- dev_dbg(codec->dev, "ASoC: Synced register %#x, value = %#x\n",
- i, val);
- }
- return 0;
-}
-
-/**
- * snd_soc_cache_sync: Sync the register cache with the hardware.
- *
- * @codec: CODEC to configure.
- *
- * Any registers that should not be synced should be marked as
- * volatile. In general drivers can choose not to use the provided
- * syncing functionality if they so require.
- */
-int snd_soc_cache_sync(struct snd_soc_codec *codec)
-{
- const char *name = "flat";
- int ret;
-
- if (!codec->cache_sync)
- return 0;
-
- dev_dbg(codec->dev, "ASoC: Syncing cache for %s codec\n",
- codec->component.name);
- trace_snd_soc_cache_sync(codec, name, "start");
- ret = snd_soc_flat_cache_sync(codec);
- if (!ret)
- codec->cache_sync = 0;
- trace_snd_soc_cache_sync(codec, name, "end");
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_cache_sync);
diff --git a/sound/soc/soc-compress.c b/sound/soc/soc-compress.c
index cecfab3c..590a82f 100644
--- a/sound/soc/soc-compress.c
+++ b/sound/soc/soc-compress.c
@@ -258,10 +258,7 @@ static int soc_compr_free_fe(struct snd_compr_stream *cstream)
list_for_each_entry(dpcm, &fe->dpcm[stream].be_clients, list_be)
dpcm->state = SND_SOC_DPCM_LINK_STATE_FREE;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
- else
- dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_STOP);
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_CLOSE;
fe->dpcm[stream].runtime_update = SND_SOC_DPCM_UPDATE_NO;
@@ -456,11 +453,7 @@ static int soc_compr_set_params_fe(struct snd_compr_stream *cstream,
if (ret < 0)
goto out;
- if (stream == SNDRV_PCM_STREAM_PLAYBACK)
- dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
- else
- dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
-
+ dpcm_dapm_stream_event(fe, stream, SND_SOC_DAPM_STREAM_START);
fe->dpcm[stream].state = SND_SOC_DPCM_STATE_PREPARE;
out:
diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c
index b60ff56..9357210 100644
--- a/sound/soc/soc-core.c
+++ b/sound/soc/soc-core.c
@@ -34,9 +34,6 @@
#include <linux/ctype.h>
#include <linux/slab.h>
#include <linux/of.h>
-#include <linux/gpio.h>
-#include <linux/of_gpio.h>
-#include <sound/ac97_codec.h>
#include <sound/core.h>
#include <sound/jack.h>
#include <sound/pcm.h>
@@ -69,16 +66,6 @@ static int pmdown_time = 5000;
module_param(pmdown_time, int, 0);
MODULE_PARM_DESC(pmdown_time, "DAPM stream powerdown time (msecs)");
-struct snd_ac97_reset_cfg {
- struct pinctrl *pctl;
- struct pinctrl_state *pstate_reset;
- struct pinctrl_state *pstate_warm_reset;
- struct pinctrl_state *pstate_run;
- int gpio_sdata;
- int gpio_sync;
- int gpio_reset;
-};
-
/* returns the minimum number of bytes needed to represent
* a particular given value */
static int min_bytes_needed(unsigned long val)
@@ -309,9 +296,6 @@ static void soc_init_codec_debugfs(struct snd_soc_component *component)
{
struct snd_soc_codec *codec = snd_soc_component_to_codec(component);
- debugfs_create_bool("cache_sync", 0444, codec->component.debugfs_root,
- &codec->cache_sync);
-
codec->debugfs_reg = debugfs_create_file("codec_reg", 0644,
codec->component.debugfs_root,
codec, &codec_reg_fops);
@@ -499,40 +483,6 @@ struct snd_soc_pcm_runtime *snd_soc_get_pcm_runtime(struct snd_soc_card *card,
}
EXPORT_SYMBOL_GPL(snd_soc_get_pcm_runtime);
-#ifdef CONFIG_SND_SOC_AC97_BUS
-/* unregister ac97 codec */
-static int soc_ac97_dev_unregister(struct snd_soc_codec *codec)
-{
- if (codec->ac97->dev.bus)
- device_unregister(&codec->ac97->dev);
- return 0;
-}
-
-/* stop no dev release warning */
-static void soc_ac97_device_release(struct device *dev){}
-
-/* register ac97 codec to bus */
-static int soc_ac97_dev_register(struct snd_soc_codec *codec)
-{
- int err;
-
- codec->ac97->dev.bus = &ac97_bus_type;
- codec->ac97->dev.parent = codec->component.card->dev;
- codec->ac97->dev.release = soc_ac97_device_release;
-
- dev_set_name(&codec->ac97->dev, "%d-%d:%s",
- codec->component.card->snd_card->number, 0,
- codec->component.name);
- err = device_register(&codec->ac97->dev);
- if (err < 0) {
- dev_err(codec->dev, "ASoC: Can't register ac97 bus\n");
- codec->ac97->dev.bus = NULL;
- return err;
- }
- return 0;
-}
-#endif
-
static void codec2codec_close_delayed_work(struct work_struct *work)
{
/* Currently nothing to do for c2c links
@@ -592,17 +542,12 @@ int snd_soc_suspend(struct device *dev)
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- struct snd_soc_platform *platform = card->rtd[i].platform;
if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->driver->suspend && !cpu_dai->driver->ac97_control)
+ if (cpu_dai->driver->suspend && !cpu_dai->driver->bus_control)
cpu_dai->driver->suspend(cpu_dai);
- if (platform->driver->suspend && !platform->suspended) {
- platform->driver->suspend(cpu_dai);
- platform->suspended = 1;
- }
}
/* close any waiting streams and save state */
@@ -629,8 +574,8 @@ int snd_soc_suspend(struct device *dev)
SND_SOC_DAPM_STREAM_SUSPEND);
}
- /* Recheck all analogue paths too */
- dapm_mark_io_dirty(&card->dapm);
+ /* Recheck all endpoints too, their state is affected by suspend */
+ dapm_mark_endpoints_dirty(card);
snd_soc_dapm_sync(&card->dapm);
/* suspend all CODECs */
@@ -656,7 +601,6 @@ int snd_soc_suspend(struct device *dev)
if (codec->driver->suspend)
codec->driver->suspend(codec);
codec->suspended = 1;
- codec->cache_sync = 1;
if (codec->component.regmap)
regcache_mark_dirty(codec->component.regmap);
/* deactivate pins to sleep state */
@@ -676,7 +620,7 @@ int snd_soc_suspend(struct device *dev)
if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->driver->suspend && cpu_dai->driver->ac97_control)
+ if (cpu_dai->driver->suspend && cpu_dai->driver->bus_control)
cpu_dai->driver->suspend(cpu_dai);
/* deactivate pins to sleep state */
@@ -712,14 +656,14 @@ static void soc_resume_deferred(struct work_struct *work)
if (card->resume_pre)
card->resume_pre(card);
- /* resume AC97 DAIs */
+ /* resume control bus DAIs */
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->driver->resume && cpu_dai->driver->ac97_control)
+ if (cpu_dai->driver->resume && cpu_dai->driver->bus_control)
cpu_dai->driver->resume(cpu_dai);
}
@@ -775,17 +719,12 @@ static void soc_resume_deferred(struct work_struct *work)
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- struct snd_soc_platform *platform = card->rtd[i].platform;
if (card->rtd[i].dai_link->ignore_suspend)
continue;
- if (cpu_dai->driver->resume && !cpu_dai->driver->ac97_control)
+ if (cpu_dai->driver->resume && !cpu_dai->driver->bus_control)
cpu_dai->driver->resume(cpu_dai);
- if (platform->driver->resume && platform->suspended) {
- platform->driver->resume(cpu_dai);
- platform->suspended = 0;
- }
}
if (card->resume_post)
@@ -796,8 +735,8 @@ static void soc_resume_deferred(struct work_struct *work)
/* userspace can access us now we are back as we were before */
snd_power_change_state(card->snd_card, SNDRV_CTL_POWER_D0);
- /* Recheck all analogue paths too */
- dapm_mark_io_dirty(&card->dapm);
+ /* Recheck all endpoints too, their state is affected by suspend */
+ dapm_mark_endpoints_dirty(card);
snd_soc_dapm_sync(&card->dapm);
}
@@ -805,7 +744,8 @@ static void soc_resume_deferred(struct work_struct *work)
int snd_soc_resume(struct device *dev)
{
struct snd_soc_card *card = dev_get_drvdata(dev);
- int i, ac97_control = 0;
+ bool bus_control = false;
+ int i;
/* If the card is not initialized yet there is nothing to do */
if (!card->instantiated)
@@ -828,17 +768,18 @@ int snd_soc_resume(struct device *dev)
}
}
- /* AC97 devices might have other drivers hanging off them so
- * need to resume immediately. Other drivers don't have that
- * problem and may take a substantial amount of time to resume
+ /*
+ * DAIs that also act as the control bus master might have other drivers
+ * hanging off them so need to resume immediately. Other drivers don't
+ * have that problem and may take a substantial amount of time to resume
* due to I/O costs and anti-pop so handle them out of line.
*/
for (i = 0; i < card->num_rtd; i++) {
struct snd_soc_dai *cpu_dai = card->rtd[i].cpu_dai;
- ac97_control |= cpu_dai->driver->ac97_control;
+ bus_control |= cpu_dai->driver->bus_control;
}
- if (ac97_control) {
- dev_dbg(dev, "ASoC: Resuming AC97 immediately\n");
+ if (bus_control) {
+ dev_dbg(dev, "ASoC: Resuming control bus master immediately\n");
soc_resume_deferred(&card->deferred_resume_work);
} else {
dev_dbg(dev, "ASoC: Scheduling resume work\n");
@@ -1251,25 +1192,22 @@ static int soc_probe_link_components(struct snd_soc_card *card, int num,
return 0;
}
-static int soc_probe_codec_dai(struct snd_soc_card *card,
- struct snd_soc_dai *codec_dai,
- int order)
+static int soc_probe_dai(struct snd_soc_dai *dai, int order)
{
int ret;
- if (!codec_dai->probed && codec_dai->driver->probe_order == order) {
- if (codec_dai->driver->probe) {
- ret = codec_dai->driver->probe(codec_dai);
+ if (!dai->probed && dai->driver->probe_order == order) {
+ if (dai->driver->probe) {
+ ret = dai->driver->probe(dai);
if (ret < 0) {
- dev_err(codec_dai->dev,
- "ASoC: failed to probe CODEC DAI %s: %d\n",
- codec_dai->name, ret);
+ dev_err(dai->dev,
+ "ASoC: failed to probe DAI %s: %d\n",
+ dai->name, ret);
return ret;
}
}
- /* mark codec_dai as probed and add to card dai list */
- codec_dai->probed = 1;
+ dai->probed = 1;
}
return 0;
@@ -1319,40 +1257,22 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
{
struct snd_soc_dai_link *dai_link = &card->dai_link[num];
struct snd_soc_pcm_runtime *rtd = &card->rtd[num];
- struct snd_soc_platform *platform = rtd->platform;
struct snd_soc_dai *cpu_dai = rtd->cpu_dai;
int i, ret;
dev_dbg(card->dev, "ASoC: probe %s dai link %d late %d\n",
card->name, num, order);
- /* config components */
- cpu_dai->platform = platform;
- cpu_dai->card = card;
- for (i = 0; i < rtd->num_codecs; i++)
- rtd->codec_dais[i]->card = card;
-
/* set default power off timeout */
rtd->pmdown_time = pmdown_time;
- /* probe the cpu_dai */
- if (!cpu_dai->probed &&
- cpu_dai->driver->probe_order == order) {
- if (cpu_dai->driver->probe) {
- ret = cpu_dai->driver->probe(cpu_dai);
- if (ret < 0) {
- dev_err(cpu_dai->dev,
- "ASoC: failed to probe CPU DAI %s: %d\n",
- cpu_dai->name, ret);
- return ret;
- }
- }
- cpu_dai->probed = 1;
- }
+ ret = soc_probe_dai(cpu_dai, order);
+ if (ret)
+ return ret;
/* probe the CODEC DAI */
for (i = 0; i < rtd->num_codecs; i++) {
- ret = soc_probe_codec_dai(card, rtd->codec_dais[i], order);
+ ret = soc_probe_dai(rtd->codec_dais[i], order);
if (ret)
return ret;
}
@@ -1422,84 +1342,9 @@ static int soc_probe_link_dais(struct snd_soc_card *card, int num, int order)
}
}
- /* add platform data for AC97 devices */
- for (i = 0; i < rtd->num_codecs; i++) {
- if (rtd->codec_dais[i]->driver->ac97_control)
- snd_ac97_dev_add_pdata(rtd->codec_dais[i]->codec->ac97,
- rtd->cpu_dai->ac97_pdata);
- }
-
return 0;
}
-#ifdef CONFIG_SND_SOC_AC97_BUS
-static int soc_register_ac97_codec(struct snd_soc_codec *codec,
- struct snd_soc_dai *codec_dai)
-{
- int ret;
-
- /* Only instantiate AC97 if not already done by the adaptor
- * for the generic AC97 subsystem.
- */
- if (codec_dai->driver->ac97_control && !codec->ac97_registered) {
- /*
- * It is possible that the AC97 device is already registered to
- * the device subsystem. This happens when the device is created
- * via snd_ac97_mixer(). Currently only SoC codec that does so
- * is the generic AC97 glue but others migh emerge.
- *
- * In those cases we don't try to register the device again.
- */
- if (!codec->ac97_created)
- return 0;
-
- ret = soc_ac97_dev_register(codec);
- if (ret < 0) {
- dev_err(codec->dev,
- "ASoC: AC97 device register failed: %d\n", ret);
- return ret;
- }
-
- codec->ac97_registered = 1;
- }
- return 0;
-}
-
-static void soc_unregister_ac97_codec(struct snd_soc_codec *codec)
-{
- if (codec->ac97_registered) {
- soc_ac97_dev_unregister(codec);
- codec->ac97_registered = 0;
- }
-}
-
-static int soc_register_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
-{
- int i, ret;
-
- for (i = 0; i < rtd->num_codecs; i++) {
- struct snd_soc_dai *codec_dai = rtd->codec_dais[i];
-
- ret = soc_register_ac97_codec(codec_dai->codec, codec_dai);
- if (ret) {
- while (--i >= 0)
- soc_unregister_ac97_codec(codec_dai->codec);
- return ret;
- }
- }
-
- return 0;
-}
-
-static void soc_unregister_ac97_dai_link(struct snd_soc_pcm_runtime *rtd)
-{
- int i;
-
- for (i = 0; i < rtd->num_codecs; i++)
- soc_unregister_ac97_codec(rtd->codec_dais[i]->codec);
-}
-#endif
-
static int soc_bind_aux_dev(struct snd_soc_card *card, int num)
{
struct snd_soc_pcm_runtime *rtd = &card->rtd_aux[num];
@@ -1793,20 +1638,6 @@ static int snd_soc_instantiate_card(struct snd_soc_card *card)
goto probe_aux_dev_err;
}
-#ifdef CONFIG_SND_SOC_AC97_BUS
- /* register any AC97 codecs */
- for (i = 0; i < card->num_rtd; i++) {
- ret = soc_register_ac97_dai_link(&card->rtd[i]);
- if (ret < 0) {
- dev_err(card->dev,
- "ASoC: failed to register AC97: %d\n", ret);
- while (--i >= 0)
- soc_unregister_ac97_dai_link(&card->rtd[i]);
- goto probe_aux_dev_err;
- }
- }
-#endif
-
card->instantiated = 1;
snd_soc_dapm_sync(&card->dapm);
mutex_unlock(&card->mutex);
@@ -1949,216 +1780,6 @@ static struct platform_driver soc_driver = {
};
/**
- * snd_soc_new_ac97_codec - initailise AC97 device
- * @codec: audio codec
- * @ops: AC97 bus operations
- * @num: AC97 codec number
- *
- * Initialises AC97 codec resources for use by ad-hoc devices only.
- */
-int snd_soc_new_ac97_codec(struct snd_soc_codec *codec,
- struct snd_ac97_bus_ops *ops, int num)
-{
- codec->ac97 = kzalloc(sizeof(struct snd_ac97), GFP_KERNEL);
- if (codec->ac97 == NULL)
- return -ENOMEM;
-
- codec->ac97->bus = kzalloc(sizeof(struct snd_ac97_bus), GFP_KERNEL);
- if (codec->ac97->bus == NULL) {
- kfree(codec->ac97);
- codec->ac97 = NULL;
- return -ENOMEM;
- }
-
- codec->ac97->bus->ops = ops;
- codec->ac97->num = num;
-
- /*
- * Mark the AC97 device to be created by us. This way we ensure that the
- * device will be registered with the device subsystem later on.
- */
- codec->ac97_created = 1;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_new_ac97_codec);
-
-static struct snd_ac97_reset_cfg snd_ac97_rst_cfg;
-
-static void snd_soc_ac97_warm_reset(struct snd_ac97 *ac97)
-{
- struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
-
- pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_warm_reset);
-
- gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 1);
-
- udelay(10);
-
- gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
-
- pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
- msleep(2);
-}
-
-static void snd_soc_ac97_reset(struct snd_ac97 *ac97)
-{
- struct pinctrl *pctl = snd_ac97_rst_cfg.pctl;
-
- pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_reset);
-
- gpio_direction_output(snd_ac97_rst_cfg.gpio_sync, 0);
- gpio_direction_output(snd_ac97_rst_cfg.gpio_sdata, 0);
- gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 0);
-
- udelay(10);
-
- gpio_direction_output(snd_ac97_rst_cfg.gpio_reset, 1);
-
- pinctrl_select_state(pctl, snd_ac97_rst_cfg.pstate_run);
- msleep(2);
-}
-
-static int snd_soc_ac97_parse_pinctl(struct device *dev,
- struct snd_ac97_reset_cfg *cfg)
-{
- struct pinctrl *p;
- struct pinctrl_state *state;
- int gpio;
- int ret;
-
- p = devm_pinctrl_get(dev);
- if (IS_ERR(p)) {
- dev_err(dev, "Failed to get pinctrl\n");
- return PTR_ERR(p);
- }
- cfg->pctl = p;
-
- state = pinctrl_lookup_state(p, "ac97-reset");
- if (IS_ERR(state)) {
- dev_err(dev, "Can't find pinctrl state ac97-reset\n");
- return PTR_ERR(state);
- }
- cfg->pstate_reset = state;
-
- state = pinctrl_lookup_state(p, "ac97-warm-reset");
- if (IS_ERR(state)) {
- dev_err(dev, "Can't find pinctrl state ac97-warm-reset\n");
- return PTR_ERR(state);
- }
- cfg->pstate_warm_reset = state;
-
- state = pinctrl_lookup_state(p, "ac97-running");
- if (IS_ERR(state)) {
- dev_err(dev, "Can't find pinctrl state ac97-running\n");
- return PTR_ERR(state);
- }
- cfg->pstate_run = state;
-
- gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 0);
- if (gpio < 0) {
- dev_err(dev, "Can't find ac97-sync gpio\n");
- return gpio;
- }
- ret = devm_gpio_request(dev, gpio, "AC97 link sync");
- if (ret) {
- dev_err(dev, "Failed requesting ac97-sync gpio\n");
- return ret;
- }
- cfg->gpio_sync = gpio;
-
- gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 1);
- if (gpio < 0) {
- dev_err(dev, "Can't find ac97-sdata gpio %d\n", gpio);
- return gpio;
- }
- ret = devm_gpio_request(dev, gpio, "AC97 link sdata");
- if (ret) {
- dev_err(dev, "Failed requesting ac97-sdata gpio\n");
- return ret;
- }
- cfg->gpio_sdata = gpio;
-
- gpio = of_get_named_gpio(dev->of_node, "ac97-gpios", 2);
- if (gpio < 0) {
- dev_err(dev, "Can't find ac97-reset gpio\n");
- return gpio;
- }
- ret = devm_gpio_request(dev, gpio, "AC97 link reset");
- if (ret) {
- dev_err(dev, "Failed requesting ac97-reset gpio\n");
- return ret;
- }
- cfg->gpio_reset = gpio;
-
- return 0;
-}
-
-struct snd_ac97_bus_ops *soc_ac97_ops;
-EXPORT_SYMBOL_GPL(soc_ac97_ops);
-
-int snd_soc_set_ac97_ops(struct snd_ac97_bus_ops *ops)
-{
- if (ops == soc_ac97_ops)
- return 0;
-
- if (soc_ac97_ops && ops)
- return -EBUSY;
-
- soc_ac97_ops = ops;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops);
-
-/**
- * snd_soc_set_ac97_ops_of_reset - Set ac97 ops with generic ac97 reset functions
- *
- * This function sets the reset and warm_reset properties of ops and parses
- * the device node of pdev to get pinctrl states and gpio numbers to use.
- */
-int snd_soc_set_ac97_ops_of_reset(struct snd_ac97_bus_ops *ops,
- struct platform_device *pdev)
-{
- struct device *dev = &pdev->dev;
- struct snd_ac97_reset_cfg cfg;
- int ret;
-
- ret = snd_soc_ac97_parse_pinctl(dev, &cfg);
- if (ret)
- return ret;
-
- ret = snd_soc_set_ac97_ops(ops);
- if (ret)
- return ret;
-
- ops->warm_reset = snd_soc_ac97_warm_reset;
- ops->reset = snd_soc_ac97_reset;
-
- snd_ac97_rst_cfg = cfg;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_set_ac97_ops_of_reset);
-
-/**
- * snd_soc_free_ac97_codec - free AC97 codec device
- * @codec: audio codec
- *
- * Frees AC97 codec device resources.
- */
-void snd_soc_free_ac97_codec(struct snd_soc_codec *codec)
-{
-#ifdef CONFIG_SND_SOC_AC97_BUS
- soc_unregister_ac97_codec(codec);
-#endif
- kfree(codec->ac97->bus);
- kfree(codec->ac97);
- codec->ac97 = NULL;
- codec->ac97_created = 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_free_ac97_codec);
-
-/**
* snd_soc_cnew - create new control
* @_template: control template
* @data: control private data
@@ -2326,7 +1947,7 @@ EXPORT_SYMBOL_GPL(snd_soc_add_card_controls);
int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
const struct snd_kcontrol_new *controls, int num_controls)
{
- struct snd_card *card = dai->card->snd_card;
+ struct snd_card *card = dai->component->card->snd_card;
return snd_soc_add_controls(card, dai->dev, controls, num_controls,
NULL, dai);
@@ -2334,1020 +1955,6 @@ int snd_soc_add_dai_controls(struct snd_soc_dai *dai,
EXPORT_SYMBOL_GPL(snd_soc_add_dai_controls);
/**
- * snd_soc_info_enum_double - enumerated double mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about a double enumerated
- * mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = e->shift_l == e->shift_r ? 1 : 2;
- uinfo->value.enumerated.items = e->items;
-
- if (uinfo->value.enumerated.item >= e->items)
- uinfo->value.enumerated.item = e->items - 1;
- strlcpy(uinfo->value.enumerated.name,
- e->texts[uinfo->value.enumerated.item],
- sizeof(uinfo->value.enumerated.name));
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
-
-/**
- * snd_soc_get_enum_double - enumerated double mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a double enumerated mixer.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int val, item;
- unsigned int reg_val;
- int ret;
-
- ret = snd_soc_component_read(component, e->reg, &reg_val);
- if (ret)
- return ret;
- val = (reg_val >> e->shift_l) & e->mask;
- item = snd_soc_enum_val_to_item(e, val);
- ucontrol->value.enumerated.item[0] = item;
- if (e->shift_l != e->shift_r) {
- val = (reg_val >> e->shift_l) & e->mask;
- item = snd_soc_enum_val_to_item(e, val);
- ucontrol->value.enumerated.item[1] = item;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
-
-/**
- * snd_soc_put_enum_double - enumerated double mixer put callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a double enumerated mixer.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
- unsigned int *item = ucontrol->value.enumerated.item;
- unsigned int val;
- unsigned int mask;
-
- if (item[0] >= e->items)
- return -EINVAL;
- val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
- mask = e->mask << e->shift_l;
- if (e->shift_l != e->shift_r) {
- if (item[1] >= e->items)
- return -EINVAL;
- val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
- mask |= e->mask << e->shift_r;
- }
-
- return snd_soc_component_update_bits(component, e->reg, mask, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
-
-/**
- * snd_soc_read_signed - Read a codec register and interprete as signed value
- * @component: component
- * @reg: Register to read
- * @mask: Mask to use after shifting the register value
- * @shift: Right shift of register value
- * @sign_bit: Bit that describes if a number is negative or not.
- * @signed_val: Pointer to where the read value should be stored
- *
- * This functions reads a codec register. The register value is shifted right
- * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
- * the given registervalue into a signed integer if sign_bit is non-zero.
- *
- * Returns 0 on sucess, otherwise an error value
- */
-static int snd_soc_read_signed(struct snd_soc_component *component,
- unsigned int reg, unsigned int mask, unsigned int shift,
- unsigned int sign_bit, int *signed_val)
-{
- int ret;
- unsigned int val;
-
- ret = snd_soc_component_read(component, reg, &val);
- if (ret < 0)
- return ret;
-
- val = (val >> shift) & mask;
-
- if (!sign_bit) {
- *signed_val = val;
- return 0;
- }
-
- /* non-negative number */
- if (!(val & BIT(sign_bit))) {
- *signed_val = val;
- return 0;
- }
-
- ret = val;
-
- /*
- * The register most probably does not contain a full-sized int.
- * Instead we have an arbitrary number of bits in a signed
- * representation which has to be translated into a full-sized int.
- * This is done by filling up all bits above the sign-bit.
- */
- ret |= ~((int)(BIT(sign_bit) - 1));
-
- *signed_val = ret;
-
- return 0;
-}
-
-/**
- * snd_soc_info_volsw - single mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about a single mixer control, or a double
- * mixer control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int platform_max;
-
- if (!mc->platform_max)
- mc->platform_max = mc->max;
- platform_max = mc->platform_max;
-
- if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
- else
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
-
- uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max - mc->min;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
-
-/**
- * snd_soc_get_volsw - single mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a single mixer control, or a double mixer
- * control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- int sign_bit = mc->sign_bit;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- int val;
- int ret;
-
- if (sign_bit)
- mask = BIT(sign_bit + 1) - 1;
-
- ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[0] = val - min;
- if (invert)
- ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
-
- if (snd_soc_volsw_is_stereo(mc)) {
- if (reg == reg2)
- ret = snd_soc_read_signed(component, reg, mask, rshift,
- sign_bit, &val);
- else
- ret = snd_soc_read_signed(component, reg2, mask, shift,
- sign_bit, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[1] = val - min;
- if (invert)
- ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
-
-/**
- * snd_soc_put_volsw - single mixer put callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a single mixer control, or a double mixer
- * control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- unsigned int sign_bit = mc->sign_bit;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- int err;
- bool type_2r = false;
- unsigned int val2 = 0;
- unsigned int val, val_mask;
-
- if (sign_bit)
- mask = BIT(sign_bit + 1) - 1;
-
- val = ((ucontrol->value.integer.value[0] + min) & mask);
- if (invert)
- val = max - val;
- val_mask = mask << shift;
- val = val << shift;
- if (snd_soc_volsw_is_stereo(mc)) {
- val2 = ((ucontrol->value.integer.value[1] + min) & mask);
- if (invert)
- val2 = max - val2;
- if (reg == reg2) {
- val_mask |= mask << rshift;
- val |= val2 << rshift;
- } else {
- val2 = val2 << shift;
- type_2r = true;
- }
- }
- err = snd_soc_component_update_bits(component, reg, val_mask, val);
- if (err < 0)
- return err;
-
- if (type_2r)
- err = snd_soc_component_update_bits(component, reg2, val_mask,
- val2);
-
- return err;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
-
-/**
- * snd_soc_get_volsw_sx - single mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a single mixer control, or a double mixer
- * control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- int mask = (1 << (fls(min + max) - 1)) - 1;
- unsigned int val;
- int ret;
-
- ret = snd_soc_component_read(component, reg, &val);
- if (ret < 0)
- return ret;
-
- ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- ret = snd_soc_component_read(component, reg2, &val);
- if (ret < 0)
- return ret;
-
- val = ((val >> rshift) - min) & mask;
- ucontrol->value.integer.value[1] = val;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
-
-/**
- * snd_soc_put_volsw_sx - double mixer set callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to set the value of a double mixer control that spans 2 registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
-
- unsigned int reg = mc->reg;
- unsigned int reg2 = mc->rreg;
- unsigned int shift = mc->shift;
- unsigned int rshift = mc->rshift;
- int max = mc->max;
- int min = mc->min;
- int mask = (1 << (fls(min + max) - 1)) - 1;
- int err = 0;
- unsigned int val, val_mask, val2 = 0;
-
- val_mask = mask << shift;
- val = (ucontrol->value.integer.value[0] + min) & mask;
- val = val << shift;
-
- err = snd_soc_component_update_bits(component, reg, val_mask, val);
- if (err < 0)
- return err;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- val_mask = mask << rshift;
- val2 = (ucontrol->value.integer.value[1] + min) & mask;
- val2 = val2 << rshift;
-
- err = snd_soc_component_update_bits(component, reg2, val_mask,
- val2);
- }
- return err;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
-
-/**
- * snd_soc_info_volsw_s8 - signed mixer info callback
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information about a signed mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_volsw_s8(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int platform_max;
- int min = mc->min;
-
- if (!mc->platform_max)
- mc->platform_max = mc->max;
- platform_max = mc->platform_max;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 2;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max - min;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_s8);
-
-/**
- * snd_soc_get_volsw_s8 - signed mixer get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value of a signed mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_s8(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int val;
- int min = mc->min;
- int ret;
-
- ret = snd_soc_component_read(component, reg, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[0] =
- ((signed char)(val & 0xff))-min;
- ucontrol->value.integer.value[1] =
- ((signed char)((val >> 8) & 0xff))-min;
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_s8);
-
-/**
- * snd_soc_put_volsw_sgn - signed mixer put callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value of a signed mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_s8(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- int min = mc->min;
- unsigned int val;
-
- val = (ucontrol->value.integer.value[0]+min) & 0xff;
- val |= ((ucontrol->value.integer.value[1]+min) & 0xff) << 8;
-
- return snd_soc_component_update_bits(component, reg, 0xffff, val);
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_s8);
-
-/**
- * snd_soc_info_volsw_range - single mixer info callback with range.
- * @kcontrol: mixer control
- * @uinfo: control element information
- *
- * Callback to provide information, within a range, about a single
- * mixer control.
- *
- * returns 0 for success.
- */
-int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- int platform_max;
- int min = mc->min;
-
- if (!mc->platform_max)
- mc->platform_max = mc->max;
- platform_max = mc->platform_max;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
- uinfo->value.integer.min = 0;
- uinfo->value.integer.max = platform_max - min;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
-
-/**
- * snd_soc_put_volsw_range - single mixer put value callback with range.
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to set the value, within a range, for a single mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- unsigned int reg = mc->reg;
- unsigned int rreg = mc->rreg;
- unsigned int shift = mc->shift;
- int min = mc->min;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- unsigned int val, val_mask;
- int ret;
-
- if (invert)
- val = (max - ucontrol->value.integer.value[0]) & mask;
- else
- val = ((ucontrol->value.integer.value[0] + min) & mask);
- val_mask = mask << shift;
- val = val << shift;
-
- ret = snd_soc_component_update_bits(component, reg, val_mask, val);
- if (ret < 0)
- return ret;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- if (invert)
- val = (max - ucontrol->value.integer.value[1]) & mask;
- else
- val = ((ucontrol->value.integer.value[1] + min) & mask);
- val_mask = mask << shift;
- val = val << shift;
-
- ret = snd_soc_component_update_bits(component, rreg, val_mask,
- val);
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
-
-/**
- * snd_soc_get_volsw_range - single mixer get callback with range
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback to get the value, within a range, of a single mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int rreg = mc->rreg;
- unsigned int shift = mc->shift;
- int min = mc->min;
- int max = mc->max;
- unsigned int mask = (1 << fls(max)) - 1;
- unsigned int invert = mc->invert;
- unsigned int val;
- int ret;
-
- ret = snd_soc_component_read(component, reg, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[0] = (val >> shift) & mask;
- if (invert)
- ucontrol->value.integer.value[0] =
- max - ucontrol->value.integer.value[0];
- else
- ucontrol->value.integer.value[0] =
- ucontrol->value.integer.value[0] - min;
-
- if (snd_soc_volsw_is_stereo(mc)) {
- ret = snd_soc_component_read(component, rreg, &val);
- if (ret)
- return ret;
-
- ucontrol->value.integer.value[1] = (val >> shift) & mask;
- if (invert)
- ucontrol->value.integer.value[1] =
- max - ucontrol->value.integer.value[1];
- else
- ucontrol->value.integer.value[1] =
- ucontrol->value.integer.value[1] - min;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
-
-/**
- * snd_soc_limit_volume - Set new limit to an existing volume control.
- *
- * @codec: where to look for the control
- * @name: Name of the control
- * @max: new maximum limit
- *
- * Return 0 for success, else error.
- */
-int snd_soc_limit_volume(struct snd_soc_codec *codec,
- const char *name, int max)
-{
- struct snd_card *card = codec->component.card->snd_card;
- struct snd_kcontrol *kctl;
- struct soc_mixer_control *mc;
- int found = 0;
- int ret = -EINVAL;
-
- /* Sanity check for name and max */
- if (unlikely(!name || max <= 0))
- return -EINVAL;
-
- list_for_each_entry(kctl, &card->controls, list) {
- if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) {
- found = 1;
- break;
- }
- }
- if (found) {
- mc = (struct soc_mixer_control *)kctl->private_value;
- if (max <= mc->max) {
- mc->platform_max = max;
- ret = 0;
- }
- }
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
-
-int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_bytes *params = (void *)kcontrol->private_value;
-
- uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- uinfo->count = params->num_regs * component->val_bytes;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_bytes_info);
-
-int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_bytes *params = (void *)kcontrol->private_value;
- int ret;
-
- if (component->regmap)
- ret = regmap_raw_read(component->regmap, params->base,
- ucontrol->value.bytes.data,
- params->num_regs * component->val_bytes);
- else
- ret = -EINVAL;
-
- /* Hide any masked bytes to ensure consistent data reporting */
- if (ret == 0 && params->mask) {
- switch (component->val_bytes) {
- case 1:
- ucontrol->value.bytes.data[0] &= ~params->mask;
- break;
- case 2:
- ((u16 *)(&ucontrol->value.bytes.data))[0]
- &= cpu_to_be16(~params->mask);
- break;
- case 4:
- ((u32 *)(&ucontrol->value.bytes.data))[0]
- &= cpu_to_be32(~params->mask);
- break;
- default:
- return -EINVAL;
- }
- }
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
-
-int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_bytes *params = (void *)kcontrol->private_value;
- int ret, len;
- unsigned int val, mask;
- void *data;
-
- if (!component->regmap || !params->num_regs)
- return -EINVAL;
-
- len = params->num_regs * component->val_bytes;
-
- data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
- if (!data)
- return -ENOMEM;
-
- /*
- * If we've got a mask then we need to preserve the register
- * bits. We shouldn't modify the incoming data so take a
- * copy.
- */
- if (params->mask) {
- ret = regmap_read(component->regmap, params->base, &val);
- if (ret != 0)
- goto out;
-
- val &= params->mask;
-
- switch (component->val_bytes) {
- case 1:
- ((u8 *)data)[0] &= ~params->mask;
- ((u8 *)data)[0] |= val;
- break;
- case 2:
- mask = ~params->mask;
- ret = regmap_parse_val(component->regmap,
- &mask, &mask);
- if (ret != 0)
- goto out;
-
- ((u16 *)data)[0] &= mask;
-
- ret = regmap_parse_val(component->regmap,
- &val, &val);
- if (ret != 0)
- goto out;
-
- ((u16 *)data)[0] |= val;
- break;
- case 4:
- mask = ~params->mask;
- ret = regmap_parse_val(component->regmap,
- &mask, &mask);
- if (ret != 0)
- goto out;
-
- ((u32 *)data)[0] &= mask;
-
- ret = regmap_parse_val(component->regmap,
- &val, &val);
- if (ret != 0)
- goto out;
-
- ((u32 *)data)[0] |= val;
- break;
- default:
- ret = -EINVAL;
- goto out;
- }
- }
-
- ret = regmap_raw_write(component->regmap, params->base,
- data, len);
-
-out:
- kfree(data);
-
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
-
-int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *ucontrol)
-{
- struct soc_bytes_ext *params = (void *)kcontrol->private_value;
-
- ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
- ucontrol->count = params->max;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext);
-
-int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag,
- unsigned int size, unsigned int __user *tlv)
-{
- struct soc_bytes_ext *params = (void *)kcontrol->private_value;
- unsigned int count = size < params->max ? size : params->max;
- int ret = -ENXIO;
-
- switch (op_flag) {
- case SNDRV_CTL_TLV_OP_READ:
- if (params->get)
- ret = params->get(tlv, count);
- break;
- case SNDRV_CTL_TLV_OP_WRITE:
- if (params->put)
- ret = params->put(tlv, count);
- break;
- }
- return ret;
-}
-EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback);
-
-/**
- * snd_soc_info_xr_sx - signed multi register info callback
- * @kcontrol: mreg control
- * @uinfo: control element information
- *
- * Callback to provide information of a control that can
- * span multiple codec registers which together
- * forms a single signed value in a MSB/LSB manner.
- *
- * Returns 0 for success.
- */
-int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_info *uinfo)
-{
- struct soc_mreg_control *mc =
- (struct soc_mreg_control *)kcontrol->private_value;
- uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
- uinfo->count = 1;
- uinfo->value.integer.min = mc->min;
- uinfo->value.integer.max = mc->max;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
-
-/**
- * snd_soc_get_xr_sx - signed multi register get callback
- * @kcontrol: mreg control
- * @ucontrol: control element information
- *
- * Callback to get the value of a control that can span
- * multiple codec registers which together forms a single
- * signed value in a MSB/LSB manner. The control supports
- * specifying total no of bits used to allow for bitfields
- * across the multiple codec registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mreg_control *mc =
- (struct soc_mreg_control *)kcontrol->private_value;
- unsigned int regbase = mc->regbase;
- unsigned int regcount = mc->regcount;
- unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
- unsigned int regwmask = (1<<regwshift)-1;
- unsigned int invert = mc->invert;
- unsigned long mask = (1UL<<mc->nbits)-1;
- long min = mc->min;
- long max = mc->max;
- long val = 0;
- unsigned int regval;
- unsigned int i;
- int ret;
-
- for (i = 0; i < regcount; i++) {
- ret = snd_soc_component_read(component, regbase+i, &regval);
- if (ret)
- return ret;
- val |= (regval & regwmask) << (regwshift*(regcount-i-1));
- }
- val &= mask;
- if (min < 0 && val > max)
- val |= ~mask;
- if (invert)
- val = max - val;
- ucontrol->value.integer.value[0] = val;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
-
-/**
- * snd_soc_put_xr_sx - signed multi register get callback
- * @kcontrol: mreg control
- * @ucontrol: control element information
- *
- * Callback to set the value of a control that can span
- * multiple codec registers which together forms a single
- * signed value in a MSB/LSB manner. The control supports
- * specifying total no of bits used to allow for bitfields
- * across the multiple codec registers.
- *
- * Returns 0 for success.
- */
-int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mreg_control *mc =
- (struct soc_mreg_control *)kcontrol->private_value;
- unsigned int regbase = mc->regbase;
- unsigned int regcount = mc->regcount;
- unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
- unsigned int regwmask = (1<<regwshift)-1;
- unsigned int invert = mc->invert;
- unsigned long mask = (1UL<<mc->nbits)-1;
- long max = mc->max;
- long val = ucontrol->value.integer.value[0];
- unsigned int i, regval, regmask;
- int err;
-
- if (invert)
- val = max - val;
- val &= mask;
- for (i = 0; i < regcount; i++) {
- regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
- regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
- err = snd_soc_component_update_bits(component, regbase+i,
- regmask, regval);
- if (err < 0)
- return err;
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
-
-/**
- * snd_soc_get_strobe - strobe get callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback get the value of a strobe mixer control.
- *
- * Returns 0 for success.
- */
-int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int shift = mc->shift;
- unsigned int mask = 1 << shift;
- unsigned int invert = mc->invert != 0;
- unsigned int val;
- int ret;
-
- ret = snd_soc_component_read(component, reg, &val);
- if (ret)
- return ret;
-
- val &= mask;
-
- if (shift != 0 && val != 0)
- val = val >> shift;
- ucontrol->value.enumerated.item[0] = val ^ invert;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
-
-/**
- * snd_soc_put_strobe - strobe put callback
- * @kcontrol: mixer control
- * @ucontrol: control element information
- *
- * Callback strobe a register bit to high then low (or the inverse)
- * in one pass of a single mixer enum control.
- *
- * Returns 1 for success.
- */
-int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
-{
- struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
- struct soc_mixer_control *mc =
- (struct soc_mixer_control *)kcontrol->private_value;
- unsigned int reg = mc->reg;
- unsigned int shift = mc->shift;
- unsigned int mask = 1 << shift;
- unsigned int invert = mc->invert != 0;
- unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
- unsigned int val1 = (strobe ^ invert) ? mask : 0;
- unsigned int val2 = (strobe ^ invert) ? 0 : mask;
- int err;
-
- err = snd_soc_component_update_bits(component, reg, mask, val1);
- if (err < 0)
- return err;
-
- return snd_soc_component_update_bits(component, reg, mask, val2);
-}
-EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
-
-/**
* snd_soc_dai_set_sysclk - configure DAI system or master clock.
* @dai: DAI
* @clk_id: DAI specific clock ID
@@ -3996,22 +2603,62 @@ static int snd_soc_component_initialize(struct snd_soc_component *component,
return 0;
}
-static void snd_soc_component_init_regmap(struct snd_soc_component *component)
+static void snd_soc_component_setup_regmap(struct snd_soc_component *component)
{
- if (!component->regmap)
- component->regmap = dev_get_regmap(component->dev, NULL);
- if (component->regmap) {
- int val_bytes = regmap_get_val_bytes(component->regmap);
- /* Errors are legitimate for non-integer byte multiples */
- if (val_bytes > 0)
- component->val_bytes = val_bytes;
- }
+ int val_bytes = regmap_get_val_bytes(component->regmap);
+
+ /* Errors are legitimate for non-integer byte multiples */
+ if (val_bytes > 0)
+ component->val_bytes = val_bytes;
+}
+
+#ifdef CONFIG_REGMAP
+
+/**
+ * snd_soc_component_init_regmap() - Initialize regmap instance for the component
+ * @component: The component for which to initialize the regmap instance
+ * @regmap: The regmap instance that should be used by the component
+ *
+ * This function allows deferred assignment of the regmap instance that is
+ * associated with the component. Only use this if the regmap instance is not
+ * yet ready when the component is registered. The function must also be called
+ * before the first IO attempt of the component.
+ */
+void snd_soc_component_init_regmap(struct snd_soc_component *component,
+ struct regmap *regmap)
+{
+ component->regmap = regmap;
+ snd_soc_component_setup_regmap(component);
+}
+EXPORT_SYMBOL_GPL(snd_soc_component_init_regmap);
+
+/**
+ * snd_soc_component_exit_regmap() - De-initialize regmap instance for the component
+ * @component: The component for which to de-initialize the regmap instance
+ *
+ * Calls regmap_exit() on the regmap instance associated to the component and
+ * removes the regmap instance from the component.
+ *
+ * This function should only be used if snd_soc_component_init_regmap() was used
+ * to initialize the regmap instance.
+ */
+void snd_soc_component_exit_regmap(struct snd_soc_component *component)
+{
+ regmap_exit(component->regmap);
+ component->regmap = NULL;
}
+EXPORT_SYMBOL_GPL(snd_soc_component_exit_regmap);
+
+#endif
static void snd_soc_component_add_unlocked(struct snd_soc_component *component)
{
- if (!component->write && !component->read)
- snd_soc_component_init_regmap(component);
+ if (!component->write && !component->read) {
+ if (!component->regmap)
+ component->regmap = dev_get_regmap(component->dev, NULL);
+ if (component->regmap)
+ snd_soc_component_setup_regmap(component);
+ }
list_add(&component->list, &component_list);
}
@@ -4362,7 +3009,6 @@ int snd_soc_register_codec(struct device *dev,
codec->dev = dev;
codec->driver = codec_drv;
codec->component.val_bytes = codec_drv->reg_word_size;
- mutex_init(&codec->mutex);
#ifdef CONFIG_DEBUG_FS
codec->component.init_debugfs = soc_init_codec_debugfs;
@@ -4585,7 +3231,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname)
{
struct device_node *np = card->dev->of_node;
- int num_routes;
+ int num_routes, old_routes;
struct snd_soc_dapm_route *routes;
int i, ret;
@@ -4603,7 +3249,9 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
return -EINVAL;
}
- routes = devm_kzalloc(card->dev, num_routes * sizeof(*routes),
+ old_routes = card->num_dapm_routes;
+ routes = devm_kzalloc(card->dev,
+ (old_routes + num_routes) * sizeof(*routes),
GFP_KERNEL);
if (!routes) {
dev_err(card->dev,
@@ -4611,9 +3259,11 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
return -EINVAL;
}
+ memcpy(routes, card->dapm_routes, old_routes * sizeof(*routes));
+
for (i = 0; i < num_routes; i++) {
ret = of_property_read_string_index(np, propname,
- 2 * i, &routes[i].sink);
+ 2 * i, &routes[old_routes + i].sink);
if (ret) {
dev_err(card->dev,
"ASoC: Property '%s' index %d could not be read: %d\n",
@@ -4621,7 +3271,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
return -EINVAL;
}
ret = of_property_read_string_index(np, propname,
- (2 * i) + 1, &routes[i].source);
+ (2 * i) + 1, &routes[old_routes + i].source);
if (ret) {
dev_err(card->dev,
"ASoC: Property '%s' index %d could not be read: %d\n",
@@ -4630,7 +3280,7 @@ int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
}
}
- card->num_dapm_routes = num_routes;
+ card->num_dapm_routes += num_routes;
card->dapm_routes = routes;
return 0;
@@ -4750,36 +3400,30 @@ unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
}
EXPORT_SYMBOL_GPL(snd_soc_of_parse_daifmt);
-int snd_soc_of_get_dai_name(struct device_node *of_node,
- const char **dai_name)
+static int snd_soc_get_dai_name(struct of_phandle_args *args,
+ const char **dai_name)
{
struct snd_soc_component *pos;
- struct of_phandle_args args;
- int ret;
-
- ret = of_parse_phandle_with_args(of_node, "sound-dai",
- "#sound-dai-cells", 0, &args);
- if (ret)
- return ret;
-
- ret = -EPROBE_DEFER;
+ int ret = -EPROBE_DEFER;
mutex_lock(&client_mutex);
list_for_each_entry(pos, &component_list, list) {
- if (pos->dev->of_node != args.np)
+ if (pos->dev->of_node != args->np)
continue;
if (pos->driver->of_xlate_dai_name) {
- ret = pos->driver->of_xlate_dai_name(pos, &args, dai_name);
+ ret = pos->driver->of_xlate_dai_name(pos,
+ args,
+ dai_name);
} else {
int id = -1;
- switch (args.args_count) {
+ switch (args->args_count) {
case 0:
id = 0; /* same as dai_drv[0] */
break;
case 1:
- id = args.args[0];
+ id = args->args[0];
break;
default:
/* not supported */
@@ -4801,6 +3445,21 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
break;
}
mutex_unlock(&client_mutex);
+ return ret;
+}
+
+int snd_soc_of_get_dai_name(struct device_node *of_node,
+ const char **dai_name)
+{
+ struct of_phandle_args args;
+ int ret;
+
+ ret = of_parse_phandle_with_args(of_node, "sound-dai",
+ "#sound-dai-cells", 0, &args);
+ if (ret)
+ return ret;
+
+ ret = snd_soc_get_dai_name(&args, dai_name);
of_node_put(args.np);
@@ -4808,6 +3467,77 @@ int snd_soc_of_get_dai_name(struct device_node *of_node,
}
EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_name);
+/*
+ * snd_soc_of_get_dai_link_codecs - Parse a list of CODECs in the devicetree
+ * @dev: Card device
+ * @of_node: Device node
+ * @dai_link: DAI link
+ *
+ * Builds an array of CODEC DAI components from the DAI link property
+ * 'sound-dai'.
+ * The array is set in the DAI link and the number of DAIs is set accordingly.
+ * The device nodes in the array (of_node) must be dereferenced by the caller.
+ *
+ * Returns 0 for success
+ */
+int snd_soc_of_get_dai_link_codecs(struct device *dev,
+ struct device_node *of_node,
+ struct snd_soc_dai_link *dai_link)
+{
+ struct of_phandle_args args;
+ struct snd_soc_dai_link_component *component;
+ char *name;
+ int index, num_codecs, ret;
+
+ /* Count the number of CODECs */
+ name = "sound-dai";
+ num_codecs = of_count_phandle_with_args(of_node, name,
+ "#sound-dai-cells");
+ if (num_codecs <= 0) {
+ if (num_codecs == -ENOENT)
+ dev_err(dev, "No 'sound-dai' property\n");
+ else
+ dev_err(dev, "Bad phandle in 'sound-dai'\n");
+ return num_codecs;
+ }
+ component = devm_kzalloc(dev,
+ sizeof *component * num_codecs,
+ GFP_KERNEL);
+ if (!component)
+ return -ENOMEM;
+ dai_link->codecs = component;
+ dai_link->num_codecs = num_codecs;
+
+ /* Parse the list */
+ for (index = 0, component = dai_link->codecs;
+ index < dai_link->num_codecs;
+ index++, component++) {
+ ret = of_parse_phandle_with_args(of_node, name,
+ "#sound-dai-cells",
+ index, &args);
+ if (ret)
+ goto err;
+ component->of_node = args.np;
+ ret = snd_soc_get_dai_name(&args, &component->dai_name);
+ if (ret < 0)
+ goto err;
+ }
+ return 0;
+err:
+ for (index = 0, component = dai_link->codecs;
+ index < dai_link->num_codecs;
+ index++, component++) {
+ if (!component->of_node)
+ break;
+ of_node_put(component->of_node);
+ component->of_node = NULL;
+ }
+ dai_link->codecs = NULL;
+ dai_link->num_codecs = 0;
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_of_get_dai_link_codecs);
+
static int __init snd_soc_init(void)
{
#ifdef CONFIG_DEBUG_FS
diff --git a/sound/soc/soc-dapm.c b/sound/soc/soc-dapm.c
index c61cb9c..c5136bb 100644
--- a/sound/soc/soc-dapm.c
+++ b/sound/soc/soc-dapm.c
@@ -159,27 +159,135 @@ static void dapm_mark_dirty(struct snd_soc_dapm_widget *w, const char *reason)
}
}
-void dapm_mark_io_dirty(struct snd_soc_dapm_context *dapm)
+/*
+ * dapm_widget_invalidate_input_paths() - Invalidate the cached number of input
+ * paths
+ * @w: The widget for which to invalidate the cached number of input paths
+ *
+ * The function resets the cached number of inputs for the specified widget and
+ * all widgets that can be reached via outgoing paths from the widget.
+ *
+ * This function must be called if the number of input paths for a widget might
+ * have changed. E.g. if the source state of a widget changes or a path is added
+ * or activated with the widget as the sink.
+ */
+static void dapm_widget_invalidate_input_paths(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_widget *sink;
+ struct snd_soc_dapm_path *p;
+ LIST_HEAD(list);
+
+ dapm_assert_locked(w->dapm);
+
+ if (w->inputs == -1)
+ return;
+
+ w->inputs = -1;
+ list_add_tail(&w->work_list, &list);
+
+ list_for_each_entry(w, &list, work_list) {
+ list_for_each_entry(p, &w->sinks, list_source) {
+ if (p->is_supply || p->weak || !p->connect)
+ continue;
+ sink = p->sink;
+ if (sink->inputs != -1) {
+ sink->inputs = -1;
+ list_add_tail(&sink->work_list, &list);
+ }
+ }
+ }
+}
+
+/*
+ * dapm_widget_invalidate_output_paths() - Invalidate the cached number of
+ * output paths
+ * @w: The widget for which to invalidate the cached number of output paths
+ *
+ * Resets the cached number of outputs for the specified widget and all widgets
+ * that can be reached via incoming paths from the widget.
+ *
+ * This function must be called if the number of output paths for a widget might
+ * have changed. E.g. if the sink state of a widget changes or a path is added
+ * or activated with the widget as the source.
+ */
+static void dapm_widget_invalidate_output_paths(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_widget *source;
+ struct snd_soc_dapm_path *p;
+ LIST_HEAD(list);
+
+ dapm_assert_locked(w->dapm);
+
+ if (w->outputs == -1)
+ return;
+
+ w->outputs = -1;
+ list_add_tail(&w->work_list, &list);
+
+ list_for_each_entry(w, &list, work_list) {
+ list_for_each_entry(p, &w->sources, list_sink) {
+ if (p->is_supply || p->weak || !p->connect)
+ continue;
+ source = p->source;
+ if (source->outputs != -1) {
+ source->outputs = -1;
+ list_add_tail(&source->work_list, &list);
+ }
+ }
+ }
+}
+
+/*
+ * dapm_path_invalidate() - Invalidates the cached number of inputs and outputs
+ * for the widgets connected to a path
+ * @p: The path to invalidate
+ *
+ * Resets the cached number of inputs for the sink of the path and the cached
+ * number of outputs for the source of the path.
+ *
+ * This function must be called when a path is added, removed or the connected
+ * state changes.
+ */
+static void dapm_path_invalidate(struct snd_soc_dapm_path *p)
+{
+ /*
+ * Weak paths or supply paths do not influence the number of input or
+ * output paths of their neighbors.
+ */
+ if (p->weak || p->is_supply)
+ return;
+
+ /*
+ * The number of connected endpoints is the sum of the number of
+ * connected endpoints of all neighbors. If a node with 0 connected
+ * endpoints is either connected or disconnected that sum won't change,
+ * so there is no need to re-check the path.
+ */
+ if (p->source->inputs != 0)
+ dapm_widget_invalidate_input_paths(p->sink);
+ if (p->sink->outputs != 0)
+ dapm_widget_invalidate_output_paths(p->source);
+}
+
+void dapm_mark_endpoints_dirty(struct snd_soc_card *card)
{
- struct snd_soc_card *card = dapm->card;
struct snd_soc_dapm_widget *w;
mutex_lock(&card->dapm_mutex);
list_for_each_entry(w, &card->widgets, list) {
- switch (w->id) {
- case snd_soc_dapm_input:
- case snd_soc_dapm_output:
- dapm_mark_dirty(w, "Rechecking inputs and outputs");
- break;
- default:
- break;
+ if (w->is_sink || w->is_source) {
+ dapm_mark_dirty(w, "Rechecking endpoints");
+ if (w->is_sink)
+ dapm_widget_invalidate_output_paths(w);
+ if (w->is_source)
+ dapm_widget_invalidate_input_paths(w);
}
}
mutex_unlock(&card->dapm_mutex);
}
-EXPORT_SYMBOL_GPL(dapm_mark_io_dirty);
+EXPORT_SYMBOL_GPL(dapm_mark_endpoints_dirty);
/* create a new dapm widget */
static inline struct snd_soc_dapm_widget *dapm_cnew_widget(
@@ -386,8 +494,6 @@ static void dapm_reset(struct snd_soc_card *card)
list_for_each_entry(w, &card->widgets, list) {
w->new_power = w->power;
w->power_checked = false;
- w->inputs = -1;
- w->outputs = -1;
}
}
@@ -469,10 +575,9 @@ out:
/* connect mux widget to its interconnecting audio paths */
static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
- struct snd_soc_dapm_path *path, const char *control_name,
- const struct snd_kcontrol_new *kcontrol)
+ struct snd_soc_dapm_path *path, const char *control_name)
{
+ const struct snd_kcontrol_new *kcontrol = &path->sink->kcontrol_news[0];
struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
unsigned int val, item;
int i;
@@ -493,10 +598,7 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
for (i = 0; i < e->items; i++) {
if (!(strcmp(control_name, e->texts[i]))) {
- list_add(&path->list, &dapm->card->paths);
- list_add(&path->list_sink, &dest->sources);
- list_add(&path->list_source, &src->sinks);
- path->name = (char*)e->texts[i];
+ path->name = e->texts[i];
if (i == item)
path->connect = 1;
else
@@ -509,11 +611,10 @@ static int dapm_connect_mux(struct snd_soc_dapm_context *dapm,
}
/* set up initial codec paths */
-static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
- struct snd_soc_dapm_path *p, int i)
+static void dapm_set_mixer_path_status(struct snd_soc_dapm_path *p, int i)
{
struct soc_mixer_control *mc = (struct soc_mixer_control *)
- w->kcontrol_news[i].private_value;
+ p->sink->kcontrol_news[i].private_value;
unsigned int reg = mc->reg;
unsigned int shift = mc->shift;
unsigned int max = mc->max;
@@ -522,7 +623,7 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
unsigned int val;
if (reg != SND_SOC_NOPM) {
- soc_dapm_read(w->dapm, reg, &val);
+ soc_dapm_read(p->sink->dapm, reg, &val);
val = (val >> shift) & mask;
if (invert)
val = max - val;
@@ -534,19 +635,15 @@ static void dapm_set_mixer_path_status(struct snd_soc_dapm_widget *w,
/* connect mixer widget to its interconnecting audio paths */
static int dapm_connect_mixer(struct snd_soc_dapm_context *dapm,
- struct snd_soc_dapm_widget *src, struct snd_soc_dapm_widget *dest,
struct snd_soc_dapm_path *path, const char *control_name)
{
int i;
/* search for mixer kcontrol */
- for (i = 0; i < dest->num_kcontrols; i++) {
- if (!strcmp(control_name, dest->kcontrol_news[i].name)) {
- list_add(&path->list, &dapm->card->paths);
- list_add(&path->list_sink, &dest->sources);
- list_add(&path->list_source, &src->sinks);
- path->name = dest->kcontrol_news[i].name;
- dapm_set_mixer_path_status(dest, path, i);
+ for (i = 0; i < path->sink->num_kcontrols; i++) {
+ if (!strcmp(control_name, path->sink->kcontrol_news[i].name)) {
+ path->name = path->sink->kcontrol_news[i].name;
+ dapm_set_mixer_path_status(path, i);
return 0;
}
}
@@ -738,8 +835,10 @@ static int dapm_new_mux(struct snd_soc_dapm_widget *w)
if (ret < 0)
return ret;
- list_for_each_entry(path, &w->sources, list_sink)
- dapm_kcontrol_add_path(w->kcontrols[0], path);
+ list_for_each_entry(path, &w->sources, list_sink) {
+ if (path->name)
+ dapm_kcontrol_add_path(w->kcontrols[0], path);
+ }
return 0;
}
@@ -754,34 +853,6 @@ static int dapm_new_pga(struct snd_soc_dapm_widget *w)
return 0;
}
-/* reset 'walked' bit for each dapm path */
-static void dapm_clear_walk_output(struct snd_soc_dapm_context *dapm,
- struct list_head *sink)
-{
- struct snd_soc_dapm_path *p;
-
- list_for_each_entry(p, sink, list_source) {
- if (p->walked) {
- p->walked = 0;
- dapm_clear_walk_output(dapm, &p->sink->sinks);
- }
- }
-}
-
-static void dapm_clear_walk_input(struct snd_soc_dapm_context *dapm,
- struct list_head *source)
-{
- struct snd_soc_dapm_path *p;
-
- list_for_each_entry(p, source, list_sink) {
- if (p->walked) {
- p->walked = 0;
- dapm_clear_walk_input(dapm, &p->source->sources);
- }
- }
-}
-
-
/* We implement power down on suspend by checking the power state of
* the ALSA card - when we are suspending the ALSA state for the card
* is set to D3.
@@ -856,61 +927,23 @@ static int is_connected_output_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT(widget, path_checks);
- switch (widget->id) {
- case snd_soc_dapm_supply:
- case snd_soc_dapm_regulator_supply:
- case snd_soc_dapm_clock_supply:
- case snd_soc_dapm_kcontrol:
- return 0;
- default:
- break;
- }
-
- switch (widget->id) {
- case snd_soc_dapm_adc:
- case snd_soc_dapm_aif_out:
- case snd_soc_dapm_dai_out:
- if (widget->active) {
- widget->outputs = snd_soc_dapm_suspend_check(widget);
- return widget->outputs;
- }
- default:
- break;
- }
-
- if (widget->connected) {
- /* connected pin ? */
- if (widget->id == snd_soc_dapm_output && !widget->ext) {
- widget->outputs = snd_soc_dapm_suspend_check(widget);
- return widget->outputs;
- }
-
- /* connected jack or spk ? */
- if (widget->id == snd_soc_dapm_hp ||
- widget->id == snd_soc_dapm_spk ||
- (widget->id == snd_soc_dapm_line &&
- !list_empty(&widget->sources))) {
- widget->outputs = snd_soc_dapm_suspend_check(widget);
- return widget->outputs;
- }
+ if (widget->is_sink && widget->connected) {
+ widget->outputs = snd_soc_dapm_suspend_check(widget);
+ return widget->outputs;
}
list_for_each_entry(path, &widget->sinks, list_source) {
DAPM_UPDATE_STAT(widget, neighbour_checks);
- if (path->weak)
+ if (path->weak || path->is_supply)
continue;
if (path->walking)
return 1;
- if (path->walked)
- continue;
-
trace_snd_soc_dapm_output_path(widget, path);
- if (path->sink && path->connect) {
- path->walked = 1;
+ if (path->connect) {
path->walking = 1;
/* do we need to add this widget to the list ? */
@@ -952,73 +985,23 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
DAPM_UPDATE_STAT(widget, path_checks);
- switch (widget->id) {
- case snd_soc_dapm_supply:
- case snd_soc_dapm_regulator_supply:
- case snd_soc_dapm_clock_supply:
- case snd_soc_dapm_kcontrol:
- return 0;
- default:
- break;
- }
-
- /* active stream ? */
- switch (widget->id) {
- case snd_soc_dapm_dac:
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_dai_in:
- if (widget->active) {
- widget->inputs = snd_soc_dapm_suspend_check(widget);
- return widget->inputs;
- }
- default:
- break;
- }
-
- if (widget->connected) {
- /* connected pin ? */
- if (widget->id == snd_soc_dapm_input && !widget->ext) {
- widget->inputs = snd_soc_dapm_suspend_check(widget);
- return widget->inputs;
- }
-
- /* connected VMID/Bias for lower pops */
- if (widget->id == snd_soc_dapm_vmid) {
- widget->inputs = snd_soc_dapm_suspend_check(widget);
- return widget->inputs;
- }
-
- /* connected jack ? */
- if (widget->id == snd_soc_dapm_mic ||
- (widget->id == snd_soc_dapm_line &&
- !list_empty(&widget->sinks))) {
- widget->inputs = snd_soc_dapm_suspend_check(widget);
- return widget->inputs;
- }
-
- /* signal generator */
- if (widget->id == snd_soc_dapm_siggen) {
- widget->inputs = snd_soc_dapm_suspend_check(widget);
- return widget->inputs;
- }
+ if (widget->is_source && widget->connected) {
+ widget->inputs = snd_soc_dapm_suspend_check(widget);
+ return widget->inputs;
}
list_for_each_entry(path, &widget->sources, list_sink) {
DAPM_UPDATE_STAT(widget, neighbour_checks);
- if (path->weak)
+ if (path->weak || path->is_supply)
continue;
if (path->walking)
return 1;
- if (path->walked)
- continue;
-
trace_snd_soc_dapm_input_path(widget, path);
- if (path->source && path->connect) {
- path->walked = 1;
+ if (path->connect) {
path->walking = 1;
/* do we need to add this widget to the list ? */
@@ -1060,21 +1043,25 @@ static int is_connected_input_ep(struct snd_soc_dapm_widget *widget,
int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
struct snd_soc_dapm_widget_list **list)
{
- struct snd_soc_card *card = dai->card;
+ struct snd_soc_card *card = dai->component->card;
+ struct snd_soc_dapm_widget *w;
int paths;
mutex_lock_nested(&card->dapm_mutex, SND_SOC_DAPM_CLASS_RUNTIME);
- dapm_reset(card);
- if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
+ /*
+ * For is_connected_{output,input}_ep fully discover the graph we need
+ * to reset the cached number of inputs and outputs.
+ */
+ list_for_each_entry(w, &card->widgets, list) {
+ w->inputs = -1;
+ w->outputs = -1;
+ }
+
+ if (stream == SNDRV_PCM_STREAM_PLAYBACK)
paths = is_connected_output_ep(dai->playback_widget, list);
- dapm_clear_walk_output(&card->dapm,
- &dai->playback_widget->sinks);
- } else {
+ else
paths = is_connected_input_ep(dai->capture_widget, list);
- dapm_clear_walk_input(&card->dapm,
- &dai->capture_widget->sources);
- }
trace_snd_soc_dapm_connected(paths, stream);
mutex_unlock(&card->dapm_mutex);
@@ -1163,44 +1150,10 @@ static int dapm_generic_check_power(struct snd_soc_dapm_widget *w)
DAPM_UPDATE_STAT(w, power_checks);
in = is_connected_input_ep(w, NULL);
- dapm_clear_walk_input(w->dapm, &w->sources);
out = is_connected_output_ep(w, NULL);
- dapm_clear_walk_output(w->dapm, &w->sinks);
return out != 0 && in != 0;
}
-/* Check to see if an ADC has power */
-static int dapm_adc_check_power(struct snd_soc_dapm_widget *w)
-{
- int in;
-
- DAPM_UPDATE_STAT(w, power_checks);
-
- if (w->active) {
- in = is_connected_input_ep(w, NULL);
- dapm_clear_walk_input(w->dapm, &w->sources);
- return in != 0;
- } else {
- return dapm_generic_check_power(w);
- }
-}
-
-/* Check to see if a DAC has power */
-static int dapm_dac_check_power(struct snd_soc_dapm_widget *w)
-{
- int out;
-
- DAPM_UPDATE_STAT(w, power_checks);
-
- if (w->active) {
- out = is_connected_output_ep(w, NULL);
- dapm_clear_walk_output(w->dapm, &w->sinks);
- return out != 0;
- } else {
- return dapm_generic_check_power(w);
- }
-}
-
/* Check to see if a power supply is needed */
static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
{
@@ -1219,9 +1172,6 @@ static int dapm_supply_check_power(struct snd_soc_dapm_widget *w)
!path->connected(path->source, path->sink))
continue;
- if (!path->sink)
- continue;
-
if (dapm_widget_power_check(path->sink))
return 1;
}
@@ -1636,27 +1586,14 @@ static void dapm_widget_set_power(struct snd_soc_dapm_widget *w, bool power,
/* If we changed our power state perhaps our neigbours changed
* also.
*/
- list_for_each_entry(path, &w->sources, list_sink) {
- if (path->source) {
- dapm_widget_set_peer_power(path->source, power,
+ list_for_each_entry(path, &w->sources, list_sink)
+ dapm_widget_set_peer_power(path->source, power, path->connect);
+
+ /* Supplies can't affect their outputs, only their inputs */
+ if (!w->is_supply) {
+ list_for_each_entry(path, &w->sinks, list_source)
+ dapm_widget_set_peer_power(path->sink, power,
path->connect);
- }
- }
- switch (w->id) {
- case snd_soc_dapm_supply:
- case snd_soc_dapm_regulator_supply:
- case snd_soc_dapm_clock_supply:
- case snd_soc_dapm_kcontrol:
- /* Supplies can't affect their outputs, only their inputs */
- break;
- default:
- list_for_each_entry(path, &w->sinks, list_source) {
- if (path->sink) {
- dapm_widget_set_peer_power(path->sink, power,
- path->connect);
- }
- }
- break;
}
if (power)
@@ -1863,10 +1800,14 @@ static ssize_t dapm_widget_power_read_file(struct file *file,
if (!buf)
return -ENOMEM;
- in = is_connected_input_ep(w, NULL);
- dapm_clear_walk_input(w->dapm, &w->sources);
- out = is_connected_output_ep(w, NULL);
- dapm_clear_walk_output(w->dapm, &w->sinks);
+ /* Supply widgets are not handled by is_connected_{input,output}_ep() */
+ if (w->is_supply) {
+ in = 0;
+ out = 0;
+ } else {
+ in = is_connected_input_ep(w, NULL);
+ out = is_connected_output_ep(w, NULL);
+ }
ret = snprintf(buf, PAGE_SIZE, "%s: %s%s in %d out %d",
w->name, w->power ? "On" : "Off",
@@ -2011,32 +1952,45 @@ static inline void dapm_debugfs_cleanup(struct snd_soc_dapm_context *dapm)
#endif
+/*
+ * soc_dapm_connect_path() - Connects or disconnects a path
+ * @path: The path to update
+ * @connect: The new connect state of the path. True if the path is connected,
+ * false if it is disconneted.
+ * @reason: The reason why the path changed (for debugging only)
+ */
+static void soc_dapm_connect_path(struct snd_soc_dapm_path *path,
+ bool connect, const char *reason)
+{
+ if (path->connect == connect)
+ return;
+
+ path->connect = connect;
+ dapm_mark_dirty(path->source, reason);
+ dapm_mark_dirty(path->sink, reason);
+ dapm_path_invalidate(path);
+}
+
/* test and update the power status of a mux widget */
static int soc_dapm_mux_update_power(struct snd_soc_card *card,
struct snd_kcontrol *kcontrol, int mux, struct soc_enum *e)
{
struct snd_soc_dapm_path *path;
int found = 0;
+ bool connect;
lockdep_assert_held(&card->dapm_mutex);
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path(path, kcontrol) {
- if (!path->name || !e->texts[mux])
- continue;
-
found = 1;
/* we now need to match the string in the enum to the path */
- if (!(strcmp(path->name, e->texts[mux]))) {
- path->connect = 1; /* new connection */
- dapm_mark_dirty(path->source, "mux connection");
- } else {
- if (path->connect)
- dapm_mark_dirty(path->source,
- "mux disconnection");
- path->connect = 0; /* old connection must be powered down */
- }
- dapm_mark_dirty(path->sink, "mux change");
+ if (!(strcmp(path->name, e->texts[mux])))
+ connect = true;
+ else
+ connect = false;
+
+ soc_dapm_connect_path(path, connect, "mux update");
}
if (found)
@@ -2075,9 +2029,7 @@ static int soc_dapm_mixer_update_power(struct snd_soc_card *card,
/* find dapm widget path assoc with kcontrol */
dapm_kcontrol_for_each_path(path, kcontrol) {
found = 1;
- path->connect = connect;
- dapm_mark_dirty(path->source, "mixer connection");
- dapm_mark_dirty(path->sink, "mixer update");
+ soc_dapm_connect_path(path, connect, "mixer update");
}
if (found)
@@ -2255,8 +2207,11 @@ static int snd_soc_dapm_set_pin(struct snd_soc_dapm_context *dapm,
return -EINVAL;
}
- if (w->connected != status)
+ if (w->connected != status) {
dapm_mark_dirty(w, "pin configuration");
+ dapm_widget_invalidate_input_paths(w);
+ dapm_widget_invalidate_output_paths(w);
+ }
w->connected = status;
if (status == 0)
@@ -2309,6 +2264,53 @@ int snd_soc_dapm_sync(struct snd_soc_dapm_context *dapm)
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_sync);
+/*
+ * dapm_update_widget_flags() - Re-compute widget sink and source flags
+ * @w: The widget for which to update the flags
+ *
+ * Some widgets have a dynamic category which depends on which neighbors they
+ * are connected to. This function update the category for these widgets.
+ *
+ * This function must be called whenever a path is added or removed to a widget.
+ */
+static void dapm_update_widget_flags(struct snd_soc_dapm_widget *w)
+{
+ struct snd_soc_dapm_path *p;
+
+ switch (w->id) {
+ case snd_soc_dapm_input:
+ w->is_source = 1;
+ list_for_each_entry(p, &w->sources, list_sink) {
+ if (p->source->id == snd_soc_dapm_micbias ||
+ p->source->id == snd_soc_dapm_mic ||
+ p->source->id == snd_soc_dapm_line ||
+ p->source->id == snd_soc_dapm_output) {
+ w->is_source = 0;
+ break;
+ }
+ }
+ break;
+ case snd_soc_dapm_output:
+ w->is_sink = 1;
+ list_for_each_entry(p, &w->sinks, list_source) {
+ if (p->sink->id == snd_soc_dapm_spk ||
+ p->sink->id == snd_soc_dapm_hp ||
+ p->sink->id == snd_soc_dapm_line ||
+ p->sink->id == snd_soc_dapm_input) {
+ w->is_sink = 0;
+ break;
+ }
+ }
+ break;
+ case snd_soc_dapm_line:
+ w->is_sink = !list_empty(&w->sources);
+ w->is_source = !list_empty(&w->sinks);
+ break;
+ default:
+ break;
+ }
+}
+
static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_widget *wsource, struct snd_soc_dapm_widget *wsink,
const char *control,
@@ -2318,6 +2320,27 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
struct snd_soc_dapm_path *path;
int ret;
+ if (wsink->is_supply && !wsource->is_supply) {
+ dev_err(dapm->dev,
+ "Connecting non-supply widget to supply widget is not supported (%s -> %s)\n",
+ wsource->name, wsink->name);
+ return -EINVAL;
+ }
+
+ if (connected && !wsource->is_supply) {
+ dev_err(dapm->dev,
+ "connected() callback only supported for supply widgets (%s -> %s)\n",
+ wsource->name, wsink->name);
+ return -EINVAL;
+ }
+
+ if (wsource->is_supply && control) {
+ dev_err(dapm->dev,
+ "Conditional paths are not supported for supply widgets (%s -> [%s] -> %s)\n",
+ wsource->name, control, wsink->name);
+ return -EINVAL;
+ }
+
path = kzalloc(sizeof(struct snd_soc_dapm_path), GFP_KERNEL);
if (!path)
return -ENOMEM;
@@ -2330,85 +2353,49 @@ static int snd_soc_dapm_add_path(struct snd_soc_dapm_context *dapm,
INIT_LIST_HEAD(&path->list_source);
INIT_LIST_HEAD(&path->list_sink);
- /* check for external widgets */
- if (wsink->id == snd_soc_dapm_input) {
- if (wsource->id == snd_soc_dapm_micbias ||
- wsource->id == snd_soc_dapm_mic ||
- wsource->id == snd_soc_dapm_line ||
- wsource->id == snd_soc_dapm_output)
- wsink->ext = 1;
- }
- if (wsource->id == snd_soc_dapm_output) {
- if (wsink->id == snd_soc_dapm_spk ||
- wsink->id == snd_soc_dapm_hp ||
- wsink->id == snd_soc_dapm_line ||
- wsink->id == snd_soc_dapm_input)
- wsource->ext = 1;
- }
-
- dapm_mark_dirty(wsource, "Route added");
- dapm_mark_dirty(wsink, "Route added");
+ if (wsource->is_supply || wsink->is_supply)
+ path->is_supply = 1;
/* connect static paths */
if (control == NULL) {
- list_add(&path->list, &dapm->card->paths);
- list_add(&path->list_sink, &wsink->sources);
- list_add(&path->list_source, &wsource->sinks);
path->connect = 1;
- return 0;
- }
-
- /* connect dynamic paths */
- switch (wsink->id) {
- case snd_soc_dapm_adc:
- case snd_soc_dapm_dac:
- case snd_soc_dapm_pga:
- case snd_soc_dapm_out_drv:
- case snd_soc_dapm_input:
- case snd_soc_dapm_output:
- case snd_soc_dapm_siggen:
- case snd_soc_dapm_micbias:
- case snd_soc_dapm_vmid:
- case snd_soc_dapm_pre:
- case snd_soc_dapm_post:
- case snd_soc_dapm_supply:
- case snd_soc_dapm_regulator_supply:
- case snd_soc_dapm_clock_supply:
- case snd_soc_dapm_aif_in:
- case snd_soc_dapm_aif_out:
- case snd_soc_dapm_dai_in:
- case snd_soc_dapm_dai_out:
- case snd_soc_dapm_dai_link:
- case snd_soc_dapm_kcontrol:
- list_add(&path->list, &dapm->card->paths);
- list_add(&path->list_sink, &wsink->sources);
- list_add(&path->list_source, &wsource->sinks);
- path->connect = 1;
- return 0;
- case snd_soc_dapm_mux:
- ret = dapm_connect_mux(dapm, wsource, wsink, path, control,
- &wsink->kcontrol_news[0]);
- if (ret != 0)
- goto err;
- break;
- case snd_soc_dapm_switch:
- case snd_soc_dapm_mixer:
- case snd_soc_dapm_mixer_named_ctl:
- ret = dapm_connect_mixer(dapm, wsource, wsink, path, control);
- if (ret != 0)
+ } else {
+ /* connect dynamic paths */
+ switch (wsink->id) {
+ case snd_soc_dapm_mux:
+ ret = dapm_connect_mux(dapm, path, control);
+ if (ret != 0)
+ goto err;
+ break;
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
+ ret = dapm_connect_mixer(dapm, path, control);
+ if (ret != 0)
+ goto err;
+ break;
+ default:
+ dev_err(dapm->dev,
+ "Control not supported for path %s -> [%s] -> %s\n",
+ wsource->name, control, wsink->name);
+ ret = -EINVAL;
goto err;
- break;
- case snd_soc_dapm_hp:
- case snd_soc_dapm_mic:
- case snd_soc_dapm_line:
- case snd_soc_dapm_spk:
- list_add(&path->list, &dapm->card->paths);
- list_add(&path->list_sink, &wsink->sources);
- list_add(&path->list_source, &wsource->sinks);
- path->connect = 0;
- return 0;
+ }
}
+ list_add(&path->list, &dapm->card->paths);
+ list_add(&path->list_sink, &wsink->sources);
+ list_add(&path->list_source, &wsource->sinks);
+
+ dapm_update_widget_flags(wsource);
+ dapm_update_widget_flags(wsink);
+
+ dapm_mark_dirty(wsource, "Route added");
+ dapm_mark_dirty(wsink, "Route added");
+
+ if (dapm->card->instantiated && path->connect)
+ dapm_path_invalidate(path);
+
return 0;
err:
kfree(path);
@@ -2489,6 +2476,7 @@ err:
static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
const struct snd_soc_dapm_route *route)
{
+ struct snd_soc_dapm_widget *wsource, *wsink;
struct snd_soc_dapm_path *path, *p;
const char *sink;
const char *source;
@@ -2526,10 +2514,19 @@ static int snd_soc_dapm_del_route(struct snd_soc_dapm_context *dapm,
}
if (path) {
- dapm_mark_dirty(path->source, "Route removed");
- dapm_mark_dirty(path->sink, "Route removed");
+ wsource = path->source;
+ wsink = path->sink;
+
+ dapm_mark_dirty(wsource, "Route removed");
+ dapm_mark_dirty(wsink, "Route removed");
+ if (path->connect)
+ dapm_path_invalidate(path);
dapm_free_path(path);
+
+ /* Update any path related flags */
+ dapm_update_widget_flags(wsource);
+ dapm_update_widget_flags(wsink);
} else {
dev_warn(dapm->dev, "ASoC: Route %s->%s does not exist\n",
source, sink);
@@ -3087,40 +3084,44 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
}
switch (w->id) {
- case snd_soc_dapm_switch:
- case snd_soc_dapm_mixer:
- case snd_soc_dapm_mixer_named_ctl:
+ case snd_soc_dapm_mic:
+ case snd_soc_dapm_input:
+ w->is_source = 1;
w->power_check = dapm_generic_check_power;
break;
- case snd_soc_dapm_mux:
+ case snd_soc_dapm_spk:
+ case snd_soc_dapm_hp:
+ case snd_soc_dapm_output:
+ w->is_sink = 1;
w->power_check = dapm_generic_check_power;
break;
- case snd_soc_dapm_dai_out:
- w->power_check = dapm_adc_check_power;
- break;
- case snd_soc_dapm_dai_in:
- w->power_check = dapm_dac_check_power;
+ case snd_soc_dapm_vmid:
+ case snd_soc_dapm_siggen:
+ w->is_source = 1;
+ w->power_check = dapm_always_on_check_power;
break;
+ case snd_soc_dapm_mux:
+ case snd_soc_dapm_switch:
+ case snd_soc_dapm_mixer:
+ case snd_soc_dapm_mixer_named_ctl:
case snd_soc_dapm_adc:
case snd_soc_dapm_aif_out:
case snd_soc_dapm_dac:
case snd_soc_dapm_aif_in:
case snd_soc_dapm_pga:
case snd_soc_dapm_out_drv:
- case snd_soc_dapm_input:
- case snd_soc_dapm_output:
case snd_soc_dapm_micbias:
- case snd_soc_dapm_spk:
- case snd_soc_dapm_hp:
- case snd_soc_dapm_mic:
case snd_soc_dapm_line:
case snd_soc_dapm_dai_link:
+ case snd_soc_dapm_dai_out:
+ case snd_soc_dapm_dai_in:
w->power_check = dapm_generic_check_power;
break;
case snd_soc_dapm_supply:
case snd_soc_dapm_regulator_supply:
case snd_soc_dapm_clock_supply:
case snd_soc_dapm_kcontrol:
+ w->is_supply = 1;
w->power_check = dapm_supply_check_power;
break;
default:
@@ -3137,6 +3138,9 @@ snd_soc_dapm_new_control(struct snd_soc_dapm_context *dapm,
INIT_LIST_HEAD(&w->dirty);
list_add(&w->list, &dapm->card->widgets);
+ w->inputs = -1;
+ w->outputs = -1;
+
/* machine layer set ups unconnected pins and insertions */
w->connected = 1;
return w;
@@ -3484,6 +3488,14 @@ static void soc_dapm_dai_stream_event(struct snd_soc_dai *dai, int stream,
case SND_SOC_DAPM_STREAM_PAUSE_RELEASE:
break;
}
+
+ if (w->id == snd_soc_dapm_dai_in) {
+ w->is_source = w->active;
+ dapm_widget_invalidate_input_paths(w);
+ } else {
+ w->is_sink = w->active;
+ dapm_widget_invalidate_output_paths(w);
+ }
}
}
@@ -3610,7 +3622,15 @@ int snd_soc_dapm_force_enable_pin_unlocked(struct snd_soc_dapm_context *dapm,
}
dev_dbg(w->dapm->dev, "ASoC: force enable pin %s\n", pin);
- w->connected = 1;
+ if (!w->connected) {
+ /*
+ * w->force does not affect the number of input or output paths,
+ * so we only have to recheck if w->connected is changed
+ */
+ dapm_widget_invalidate_input_paths(w);
+ dapm_widget_invalidate_output_paths(w);
+ w->connected = 1;
+ }
w->force = 1;
dapm_mark_dirty(w, "force enable");
@@ -3788,35 +3808,54 @@ int snd_soc_dapm_ignore_suspend(struct snd_soc_dapm_context *dapm,
}
EXPORT_SYMBOL_GPL(snd_soc_dapm_ignore_suspend);
+/**
+ * dapm_is_external_path() - Checks if a path is a external path
+ * @card: The card the path belongs to
+ * @path: The path to check
+ *
+ * Returns true if the path is either between two different DAPM contexts or
+ * between two external pins of the same DAPM context. Otherwise returns
+ * false.
+ */
+static bool dapm_is_external_path(struct snd_soc_card *card,
+ struct snd_soc_dapm_path *path)
+{
+ dev_dbg(card->dev,
+ "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
+ path->source->name, path->source->id, path->source->dapm,
+ path->sink->name, path->sink->id, path->sink->dapm);
+
+ /* Connection between two different DAPM contexts */
+ if (path->source->dapm != path->sink->dapm)
+ return true;
+
+ /* Loopback connection from external pin to external pin */
+ if (path->sink->id == snd_soc_dapm_input) {
+ switch (path->source->id) {
+ case snd_soc_dapm_output:
+ case snd_soc_dapm_micbias:
+ return true;
+ default:
+ break;
+ }
+ }
+
+ return false;
+}
+
static bool snd_soc_dapm_widget_in_card_paths(struct snd_soc_card *card,
struct snd_soc_dapm_widget *w)
{
struct snd_soc_dapm_path *p;
- list_for_each_entry(p, &card->paths, list) {
- if ((p->source == w) || (p->sink == w)) {
- dev_dbg(card->dev,
- "... Path %s(id:%d dapm:%p) - %s(id:%d dapm:%p)\n",
- p->source->name, p->source->id, p->source->dapm,
- p->sink->name, p->sink->id, p->sink->dapm);
+ list_for_each_entry(p, &w->sources, list_sink) {
+ if (dapm_is_external_path(card, p))
+ return true;
+ }
- /* Connected to something other than the codec */
- if (p->source->dapm != p->sink->dapm)
- return true;
- /*
- * Loopback connection from codec external pin to
- * codec external pin
- */
- if (p->sink->id == snd_soc_dapm_input) {
- switch (p->source->id) {
- case snd_soc_dapm_output:
- case snd_soc_dapm_micbias:
- return true;
- default:
- break;
- }
- }
- }
+ list_for_each_entry(p, &w->sinks, list_source) {
+ if (dapm_is_external_path(card, p))
+ return true;
}
return false;
diff --git a/sound/soc/soc-jack.c b/sound/soc/soc-jack.c
index ab47fea..4380dcc 100644
--- a/sound/soc/soc-jack.c
+++ b/sound/soc/soc-jack.c
@@ -116,7 +116,7 @@ EXPORT_SYMBOL_GPL(snd_soc_jack_report);
*
* @jack: ASoC jack
* @count: Number of zones
- * @zone: Array of zones
+ * @zones: Array of zones
*
* After this function has been called the zones specified in the
* array will be associated with the jack.
@@ -309,7 +309,7 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
/* GPIO descriptor */
gpios[i].desc = gpiod_get_index(gpios[i].gpiod_dev,
gpios[i].name,
- gpios[i].idx);
+ gpios[i].idx, GPIOD_IN);
if (IS_ERR(gpios[i].desc)) {
ret = PTR_ERR(gpios[i].desc);
dev_err(gpios[i].gpiod_dev,
@@ -327,17 +327,14 @@ int snd_soc_jack_add_gpios(struct snd_soc_jack *jack, int count,
goto undo;
}
- ret = gpio_request(gpios[i].gpio, gpios[i].name);
+ ret = gpio_request_one(gpios[i].gpio, GPIOF_IN,
+ gpios[i].name);
if (ret)
goto undo;
gpios[i].desc = gpio_to_desc(gpios[i].gpio);
}
- ret = gpiod_direction_input(gpios[i].desc);
- if (ret)
- goto err;
-
INIT_DELAYED_WORK(&gpios[i].work, gpio_work);
gpios[i].jack = jack;
diff --git a/sound/soc/soc-ops.c b/sound/soc/soc-ops.c
new file mode 100644
index 0000000..100d92b
--- /dev/null
+++ b/sound/soc/soc-ops.c
@@ -0,0 +1,952 @@
+/*
+ * soc-ops.c -- Generic ASoC operations
+ *
+ * Copyright 2005 Wolfson Microelectronics PLC.
+ * Copyright 2005 Openedhand Ltd.
+ * Copyright (C) 2010 Slimlogic Ltd.
+ * Copyright (C) 2010 Texas Instruments Inc.
+ *
+ * Author: Liam Girdwood <lrg@slimlogic.co.uk>
+ * with code, comments and ideas from :-
+ * Richard Purdie <richard@openedhand.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/pm.h>
+#include <linux/bitops.h>
+#include <linux/ctype.h>
+#include <linux/slab.h>
+#include <sound/core.h>
+#include <sound/jack.h>
+#include <sound/pcm.h>
+#include <sound/pcm_params.h>
+#include <sound/soc.h>
+#include <sound/soc-dpcm.h>
+#include <sound/initval.h>
+
+/**
+ * snd_soc_info_enum_double - enumerated double mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a double enumerated
+ * mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+
+ return snd_ctl_enum_info(uinfo, e->shift_l == e->shift_r ? 1 : 2,
+ e->items, e->texts);
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_enum_double);
+
+/**
+ * snd_soc_get_enum_double - enumerated double mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a double enumerated mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int val, item;
+ unsigned int reg_val;
+ int ret;
+
+ ret = snd_soc_component_read(component, e->reg, &reg_val);
+ if (ret)
+ return ret;
+ val = (reg_val >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[0] = item;
+ if (e->shift_l != e->shift_r) {
+ val = (reg_val >> e->shift_l) & e->mask;
+ item = snd_soc_enum_val_to_item(e, val);
+ ucontrol->value.enumerated.item[1] = item;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_enum_double);
+
+/**
+ * snd_soc_put_enum_double - enumerated double mixer put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a double enumerated mixer.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_enum_double(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_enum *e = (struct soc_enum *)kcontrol->private_value;
+ unsigned int *item = ucontrol->value.enumerated.item;
+ unsigned int val;
+ unsigned int mask;
+
+ if (item[0] >= e->items)
+ return -EINVAL;
+ val = snd_soc_enum_item_to_val(e, item[0]) << e->shift_l;
+ mask = e->mask << e->shift_l;
+ if (e->shift_l != e->shift_r) {
+ if (item[1] >= e->items)
+ return -EINVAL;
+ val |= snd_soc_enum_item_to_val(e, item[1]) << e->shift_r;
+ mask |= e->mask << e->shift_r;
+ }
+
+ return snd_soc_component_update_bits(component, e->reg, mask, val);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_enum_double);
+
+/**
+ * snd_soc_read_signed - Read a codec register and interprete as signed value
+ * @component: component
+ * @reg: Register to read
+ * @mask: Mask to use after shifting the register value
+ * @shift: Right shift of register value
+ * @sign_bit: Bit that describes if a number is negative or not.
+ * @signed_val: Pointer to where the read value should be stored
+ *
+ * This functions reads a codec register. The register value is shifted right
+ * by 'shift' bits and masked with the given 'mask'. Afterwards it translates
+ * the given registervalue into a signed integer if sign_bit is non-zero.
+ *
+ * Returns 0 on sucess, otherwise an error value
+ */
+static int snd_soc_read_signed(struct snd_soc_component *component,
+ unsigned int reg, unsigned int mask, unsigned int shift,
+ unsigned int sign_bit, int *signed_val)
+{
+ int ret;
+ unsigned int val;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ val = (val >> shift) & mask;
+
+ if (!sign_bit) {
+ *signed_val = val;
+ return 0;
+ }
+
+ /* non-negative number */
+ if (!(val & BIT(sign_bit))) {
+ *signed_val = val;
+ return 0;
+ }
+
+ ret = val;
+
+ /*
+ * The register most probably does not contain a full-sized int.
+ * Instead we have an arbitrary number of bits in a signed
+ * representation which has to be translated into a full-sized int.
+ * This is done by filling up all bits above the sign-bit.
+ */
+ ret |= ~((int)(BIT(sign_bit) - 1));
+
+ *signed_val = ret;
+
+ return 0;
+}
+
+/**
+ * snd_soc_info_volsw - single mixer info callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information about a single mixer control, or a double
+ * mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int platform_max;
+
+ if (!mc->platform_max)
+ mc->platform_max = mc->max;
+ platform_max = mc->platform_max;
+
+ if (platform_max == 1 && !strstr(kcontrol->id.name, " Volume"))
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ else
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+
+ uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = platform_max - mc->min;
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw);
+
+/**
+ * snd_soc_get_volsw - single mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ int max = mc->max;
+ int min = mc->min;
+ int sign_bit = mc->sign_bit;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = mc->invert;
+ int val;
+ int ret;
+
+ if (sign_bit)
+ mask = BIT(sign_bit + 1) - 1;
+
+ ret = snd_soc_read_signed(component, reg, mask, shift, sign_bit, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = val - min;
+ if (invert)
+ ucontrol->value.integer.value[0] =
+ max - ucontrol->value.integer.value[0];
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (reg == reg2)
+ ret = snd_soc_read_signed(component, reg, mask, rshift,
+ sign_bit, &val);
+ else
+ ret = snd_soc_read_signed(component, reg2, mask, shift,
+ sign_bit, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[1] = val - min;
+ if (invert)
+ ucontrol->value.integer.value[1] =
+ max - ucontrol->value.integer.value[1];
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw);
+
+/**
+ * snd_soc_put_volsw - single mixer put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ int max = mc->max;
+ int min = mc->min;
+ unsigned int sign_bit = mc->sign_bit;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = mc->invert;
+ int err;
+ bool type_2r = false;
+ unsigned int val2 = 0;
+ unsigned int val, val_mask;
+
+ if (sign_bit)
+ mask = BIT(sign_bit + 1) - 1;
+
+ val = ((ucontrol->value.integer.value[0] + min) & mask);
+ if (invert)
+ val = max - val;
+ val_mask = mask << shift;
+ val = val << shift;
+ if (snd_soc_volsw_is_stereo(mc)) {
+ val2 = ((ucontrol->value.integer.value[1] + min) & mask);
+ if (invert)
+ val2 = max - val2;
+ if (reg == reg2) {
+ val_mask |= mask << rshift;
+ val |= val2 << rshift;
+ } else {
+ val2 = val2 << shift;
+ type_2r = true;
+ }
+ }
+ err = snd_soc_component_update_bits(component, reg, val_mask, val);
+ if (err < 0)
+ return err;
+
+ if (type_2r)
+ err = snd_soc_component_update_bits(component, reg2, val_mask,
+ val2);
+
+ return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw);
+
+/**
+ * snd_soc_get_volsw_sx - single mixer get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a single mixer control, or a double mixer
+ * control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ int max = mc->max;
+ int min = mc->min;
+ int mask = (1 << (fls(min + max) - 1)) - 1;
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret < 0)
+ return ret;
+
+ ucontrol->value.integer.value[0] = ((val >> shift) - min) & mask;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ ret = snd_soc_component_read(component, reg2, &val);
+ if (ret < 0)
+ return ret;
+
+ val = ((val >> rshift) - min) & mask;
+ ucontrol->value.integer.value[1] = val;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_sx);
+
+/**
+ * snd_soc_put_volsw_sx - double mixer set callback
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to set the value of a double mixer control that spans 2 registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+
+ unsigned int reg = mc->reg;
+ unsigned int reg2 = mc->rreg;
+ unsigned int shift = mc->shift;
+ unsigned int rshift = mc->rshift;
+ int max = mc->max;
+ int min = mc->min;
+ int mask = (1 << (fls(min + max) - 1)) - 1;
+ int err = 0;
+ unsigned int val, val_mask, val2 = 0;
+
+ val_mask = mask << shift;
+ val = (ucontrol->value.integer.value[0] + min) & mask;
+ val = val << shift;
+
+ err = snd_soc_component_update_bits(component, reg, val_mask, val);
+ if (err < 0)
+ return err;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ val_mask = mask << rshift;
+ val2 = (ucontrol->value.integer.value[1] + min) & mask;
+ val2 = val2 << rshift;
+
+ err = snd_soc_component_update_bits(component, reg2, val_mask,
+ val2);
+ }
+ return err;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_sx);
+
+/**
+ * snd_soc_info_volsw_range - single mixer info callback with range.
+ * @kcontrol: mixer control
+ * @uinfo: control element information
+ *
+ * Callback to provide information, within a range, about a single
+ * mixer control.
+ *
+ * returns 0 for success.
+ */
+int snd_soc_info_volsw_range(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ int platform_max;
+ int min = mc->min;
+
+ if (!mc->platform_max)
+ mc->platform_max = mc->max;
+ platform_max = mc->platform_max;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = snd_soc_volsw_is_stereo(mc) ? 2 : 1;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = platform_max - min;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_volsw_range);
+
+/**
+ * snd_soc_put_volsw_range - single mixer put value callback with range.
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value, within a range, for a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_volsw_range(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ unsigned int reg = mc->reg;
+ unsigned int rreg = mc->rreg;
+ unsigned int shift = mc->shift;
+ int min = mc->min;
+ int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = mc->invert;
+ unsigned int val, val_mask;
+ int ret;
+
+ if (invert)
+ val = (max - ucontrol->value.integer.value[0]) & mask;
+ else
+ val = ((ucontrol->value.integer.value[0] + min) & mask);
+ val_mask = mask << shift;
+ val = val << shift;
+
+ ret = snd_soc_component_update_bits(component, reg, val_mask, val);
+ if (ret < 0)
+ return ret;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ if (invert)
+ val = (max - ucontrol->value.integer.value[1]) & mask;
+ else
+ val = ((ucontrol->value.integer.value[1] + min) & mask);
+ val_mask = mask << shift;
+ val = val << shift;
+
+ ret = snd_soc_component_update_bits(component, rreg, val_mask,
+ val);
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_volsw_range);
+
+/**
+ * snd_soc_get_volsw_range - single mixer get callback with range
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value, within a range, of a single mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_volsw_range(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int rreg = mc->rreg;
+ unsigned int shift = mc->shift;
+ int min = mc->min;
+ int max = mc->max;
+ unsigned int mask = (1 << fls(max)) - 1;
+ unsigned int invert = mc->invert;
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[0] = (val >> shift) & mask;
+ if (invert)
+ ucontrol->value.integer.value[0] =
+ max - ucontrol->value.integer.value[0];
+ else
+ ucontrol->value.integer.value[0] =
+ ucontrol->value.integer.value[0] - min;
+
+ if (snd_soc_volsw_is_stereo(mc)) {
+ ret = snd_soc_component_read(component, rreg, &val);
+ if (ret)
+ return ret;
+
+ ucontrol->value.integer.value[1] = (val >> shift) & mask;
+ if (invert)
+ ucontrol->value.integer.value[1] =
+ max - ucontrol->value.integer.value[1];
+ else
+ ucontrol->value.integer.value[1] =
+ ucontrol->value.integer.value[1] - min;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_volsw_range);
+
+/**
+ * snd_soc_limit_volume - Set new limit to an existing volume control.
+ *
+ * @codec: where to look for the control
+ * @name: Name of the control
+ * @max: new maximum limit
+ *
+ * Return 0 for success, else error.
+ */
+int snd_soc_limit_volume(struct snd_soc_codec *codec,
+ const char *name, int max)
+{
+ struct snd_card *card = codec->component.card->snd_card;
+ struct snd_kcontrol *kctl;
+ struct soc_mixer_control *mc;
+ int found = 0;
+ int ret = -EINVAL;
+
+ /* Sanity check for name and max */
+ if (unlikely(!name || max <= 0))
+ return -EINVAL;
+
+ list_for_each_entry(kctl, &card->controls, list) {
+ if (!strncmp(kctl->id.name, name, sizeof(kctl->id.name))) {
+ found = 1;
+ break;
+ }
+ }
+ if (found) {
+ mc = (struct soc_mixer_control *)kctl->private_value;
+ if (max <= mc->max) {
+ mc->platform_max = max;
+ ret = 0;
+ }
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_limit_volume);
+
+int snd_soc_bytes_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_bytes *params = (void *)kcontrol->private_value;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ uinfo->count = params->num_regs * component->val_bytes;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_info);
+
+int snd_soc_bytes_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_bytes *params = (void *)kcontrol->private_value;
+ int ret;
+
+ if (component->regmap)
+ ret = regmap_raw_read(component->regmap, params->base,
+ ucontrol->value.bytes.data,
+ params->num_regs * component->val_bytes);
+ else
+ ret = -EINVAL;
+
+ /* Hide any masked bytes to ensure consistent data reporting */
+ if (ret == 0 && params->mask) {
+ switch (component->val_bytes) {
+ case 1:
+ ucontrol->value.bytes.data[0] &= ~params->mask;
+ break;
+ case 2:
+ ((u16 *)(&ucontrol->value.bytes.data))[0]
+ &= cpu_to_be16(~params->mask);
+ break;
+ case 4:
+ ((u32 *)(&ucontrol->value.bytes.data))[0]
+ &= cpu_to_be32(~params->mask);
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_get);
+
+int snd_soc_bytes_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_bytes *params = (void *)kcontrol->private_value;
+ int ret, len;
+ unsigned int val, mask;
+ void *data;
+
+ if (!component->regmap || !params->num_regs)
+ return -EINVAL;
+
+ len = params->num_regs * component->val_bytes;
+
+ data = kmemdup(ucontrol->value.bytes.data, len, GFP_KERNEL | GFP_DMA);
+ if (!data)
+ return -ENOMEM;
+
+ /*
+ * If we've got a mask then we need to preserve the register
+ * bits. We shouldn't modify the incoming data so take a
+ * copy.
+ */
+ if (params->mask) {
+ ret = regmap_read(component->regmap, params->base, &val);
+ if (ret != 0)
+ goto out;
+
+ val &= params->mask;
+
+ switch (component->val_bytes) {
+ case 1:
+ ((u8 *)data)[0] &= ~params->mask;
+ ((u8 *)data)[0] |= val;
+ break;
+ case 2:
+ mask = ~params->mask;
+ ret = regmap_parse_val(component->regmap,
+ &mask, &mask);
+ if (ret != 0)
+ goto out;
+
+ ((u16 *)data)[0] &= mask;
+
+ ret = regmap_parse_val(component->regmap,
+ &val, &val);
+ if (ret != 0)
+ goto out;
+
+ ((u16 *)data)[0] |= val;
+ break;
+ case 4:
+ mask = ~params->mask;
+ ret = regmap_parse_val(component->regmap,
+ &mask, &mask);
+ if (ret != 0)
+ goto out;
+
+ ((u32 *)data)[0] &= mask;
+
+ ret = regmap_parse_val(component->regmap,
+ &val, &val);
+ if (ret != 0)
+ goto out;
+
+ ((u32 *)data)[0] |= val;
+ break;
+ default:
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+
+ ret = regmap_raw_write(component->regmap, params->base,
+ data, len);
+
+out:
+ kfree(data);
+
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_put);
+
+int snd_soc_bytes_info_ext(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *ucontrol)
+{
+ struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+
+ ucontrol->type = SNDRV_CTL_ELEM_TYPE_BYTES;
+ ucontrol->count = params->max;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_info_ext);
+
+int snd_soc_bytes_tlv_callback(struct snd_kcontrol *kcontrol, int op_flag,
+ unsigned int size, unsigned int __user *tlv)
+{
+ struct soc_bytes_ext *params = (void *)kcontrol->private_value;
+ unsigned int count = size < params->max ? size : params->max;
+ int ret = -ENXIO;
+
+ switch (op_flag) {
+ case SNDRV_CTL_TLV_OP_READ:
+ if (params->get)
+ ret = params->get(tlv, count);
+ break;
+ case SNDRV_CTL_TLV_OP_WRITE:
+ if (params->put)
+ ret = params->put(tlv, count);
+ break;
+ }
+ return ret;
+}
+EXPORT_SYMBOL_GPL(snd_soc_bytes_tlv_callback);
+
+/**
+ * snd_soc_info_xr_sx - signed multi register info callback
+ * @kcontrol: mreg control
+ * @uinfo: control element information
+ *
+ * Callback to provide information of a control that can
+ * span multiple codec registers which together
+ * forms a single signed value in a MSB/LSB manner.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_info_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = 1;
+ uinfo->value.integer.min = mc->min;
+ uinfo->value.integer.max = mc->max;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_info_xr_sx);
+
+/**
+ * snd_soc_get_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to get the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ unsigned int regbase = mc->regbase;
+ unsigned int regcount = mc->regcount;
+ unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
+ unsigned int regwmask = (1<<regwshift)-1;
+ unsigned int invert = mc->invert;
+ unsigned long mask = (1UL<<mc->nbits)-1;
+ long min = mc->min;
+ long max = mc->max;
+ long val = 0;
+ unsigned int regval;
+ unsigned int i;
+ int ret;
+
+ for (i = 0; i < regcount; i++) {
+ ret = snd_soc_component_read(component, regbase+i, &regval);
+ if (ret)
+ return ret;
+ val |= (regval & regwmask) << (regwshift*(regcount-i-1));
+ }
+ val &= mask;
+ if (min < 0 && val > max)
+ val |= ~mask;
+ if (invert)
+ val = max - val;
+ ucontrol->value.integer.value[0] = val;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_xr_sx);
+
+/**
+ * snd_soc_put_xr_sx - signed multi register get callback
+ * @kcontrol: mreg control
+ * @ucontrol: control element information
+ *
+ * Callback to set the value of a control that can span
+ * multiple codec registers which together forms a single
+ * signed value in a MSB/LSB manner. The control supports
+ * specifying total no of bits used to allow for bitfields
+ * across the multiple codec registers.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_put_xr_sx(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mreg_control *mc =
+ (struct soc_mreg_control *)kcontrol->private_value;
+ unsigned int regbase = mc->regbase;
+ unsigned int regcount = mc->regcount;
+ unsigned int regwshift = component->val_bytes * BITS_PER_BYTE;
+ unsigned int regwmask = (1<<regwshift)-1;
+ unsigned int invert = mc->invert;
+ unsigned long mask = (1UL<<mc->nbits)-1;
+ long max = mc->max;
+ long val = ucontrol->value.integer.value[0];
+ unsigned int i, regval, regmask;
+ int err;
+
+ if (invert)
+ val = max - val;
+ val &= mask;
+ for (i = 0; i < regcount; i++) {
+ regval = (val >> (regwshift*(regcount-i-1))) & regwmask;
+ regmask = (mask >> (regwshift*(regcount-i-1))) & regwmask;
+ err = snd_soc_component_update_bits(component, regbase+i,
+ regmask, regval);
+ if (err < 0)
+ return err;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_xr_sx);
+
+/**
+ * snd_soc_get_strobe - strobe get callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback get the value of a strobe mixer control.
+ *
+ * Returns 0 for success.
+ */
+int snd_soc_get_strobe(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = 1 << shift;
+ unsigned int invert = mc->invert != 0;
+ unsigned int val;
+ int ret;
+
+ ret = snd_soc_component_read(component, reg, &val);
+ if (ret)
+ return ret;
+
+ val &= mask;
+
+ if (shift != 0 && val != 0)
+ val = val >> shift;
+ ucontrol->value.enumerated.item[0] = val ^ invert;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(snd_soc_get_strobe);
+
+/**
+ * snd_soc_put_strobe - strobe put callback
+ * @kcontrol: mixer control
+ * @ucontrol: control element information
+ *
+ * Callback strobe a register bit to high then low (or the inverse)
+ * in one pass of a single mixer enum control.
+ *
+ * Returns 1 for success.
+ */
+int snd_soc_put_strobe(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct snd_soc_component *component = snd_kcontrol_chip(kcontrol);
+ struct soc_mixer_control *mc =
+ (struct soc_mixer_control *)kcontrol->private_value;
+ unsigned int reg = mc->reg;
+ unsigned int shift = mc->shift;
+ unsigned int mask = 1 << shift;
+ unsigned int invert = mc->invert != 0;
+ unsigned int strobe = ucontrol->value.enumerated.item[0] != 0;
+ unsigned int val1 = (strobe ^ invert) ? mask : 0;
+ unsigned int val2 = (strobe ^ invert) ? 0 : mask;
+ int err;
+
+ err = snd_soc_component_update_bits(component, reg, mask, val1);
+ if (err < 0)
+ return err;
+
+ return snd_soc_component_update_bits(component, reg, mask, val2);
+}
+EXPORT_SYMBOL_GPL(snd_soc_put_strobe);
diff --git a/sound/soc/soc-pcm.c b/sound/soc/soc-pcm.c
index 57277dd..eb87d96e2 100644
--- a/sound/soc/soc-pcm.c
+++ b/sound/soc/soc-pcm.c
@@ -654,6 +654,8 @@ static int soc_pcm_close(struct snd_pcm_substream *substream)
codec_dai->rate = 0;
}
+ snd_soc_dai_digital_mute(cpu_dai, 1, substream->stream);
+
if (cpu_dai->driver->ops->shutdown)
cpu_dai->driver->ops->shutdown(substream, cpu_dai);
@@ -772,6 +774,7 @@ static int soc_pcm_prepare(struct snd_pcm_substream *substream)
for (i = 0; i < rtd->num_codecs; i++)
snd_soc_dai_digital_mute(rtd->codec_dais[i], 0,
substream->stream);
+ snd_soc_dai_digital_mute(cpu_dai, 0, substream->stream);
out:
mutex_unlock(&rtd->pcm_mutex);
@@ -1664,6 +1667,10 @@ int dpcm_be_dai_hw_free(struct snd_soc_pcm_runtime *fe, int stream)
if (!snd_soc_dpcm_can_be_free_stop(fe, be, stream))
continue;
+ /* do not free hw if this BE is used by other FE */
+ if (be->dpcm[stream].users > 1)
+ continue;
+
if ((be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_PARAMS) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_PREPARE) &&
(be->dpcm[stream].state != SND_SOC_DPCM_STATE_HW_FREE) &&
@@ -2288,7 +2295,13 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card)
fe->dai_link->name);
/* skip if FE doesn't have playback capability */
- if (!fe->cpu_dai->driver->playback.channels_min)
+ if (!fe->cpu_dai->driver->playback.channels_min
+ || !fe->codec_dai->driver->playback.channels_min)
+ goto capture;
+
+ /* skip if FE isn't currently playing */
+ if (!fe->cpu_dai->playback_active
+ || !fe->codec_dai->playback_active)
goto capture;
paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_PLAYBACK, &list);
@@ -2318,7 +2331,13 @@ int soc_dpcm_runtime_update(struct snd_soc_card *card)
dpcm_path_put(&list);
capture:
/* skip if FE doesn't have capture capability */
- if (!fe->cpu_dai->driver->capture.channels_min)
+ if (!fe->cpu_dai->driver->capture.channels_min
+ || !fe->codec_dai->driver->capture.channels_min)
+ continue;
+
+ /* skip if FE isn't currently capturing */
+ if (!fe->cpu_dai->capture_active
+ || !fe->codec_dai->capture_active)
continue;
paths = dpcm_path_get(fe, SNDRV_PCM_STREAM_CAPTURE, &list);
diff --git a/sound/soc/tegra/tegra20_ac97.c b/sound/soc/tegra/tegra20_ac97.c
index 3b0fa12..29a9957 100644
--- a/sound/soc/tegra/tegra20_ac97.c
+++ b/sound/soc/tegra/tegra20_ac97.c
@@ -228,7 +228,7 @@ static int tegra20_ac97_probe(struct snd_soc_dai *dai)
static struct snd_soc_dai_driver tegra20_ac97_dai = {
.name = "tegra-ac97-pcm",
- .ac97_control = 1,
+ .bus_control = true,
.probe = tegra20_ac97_probe,
.playback = {
.stream_name = "PCM Playback",
diff --git a/sound/soc/tegra/tegra_rt5640.c b/sound/soc/tegra/tegra_rt5640.c
index a689883..4ebe387 100644
--- a/sound/soc/tegra/tegra_rt5640.c
+++ b/sound/soc/tegra/tegra_rt5640.c
@@ -44,6 +44,7 @@
struct tegra_rt5640 {
struct tegra_asoc_utils_data util_data;
int gpio_hp_det;
+ enum of_gpio_flags gpio_hp_det_flags;
};
static int tegra_rt5640_asoc_hw_params(struct snd_pcm_substream *substream,
@@ -119,6 +120,8 @@ static int tegra_rt5640_asoc_init(struct snd_soc_pcm_runtime *rtd)
if (gpio_is_valid(machine->gpio_hp_det)) {
tegra_rt5640_hp_jack_gpio.gpio = machine->gpio_hp_det;
+ tegra_rt5640_hp_jack_gpio.invert =
+ !!(machine->gpio_hp_det_flags & OF_GPIO_ACTIVE_LOW);
snd_soc_jack_add_gpios(&tegra_rt5640_hp_jack,
1,
&tegra_rt5640_hp_jack_gpio);
@@ -180,7 +183,8 @@ static int tegra_rt5640_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, card);
snd_soc_card_set_drvdata(card, machine);
- machine->gpio_hp_det = of_get_named_gpio(np, "nvidia,hp-det-gpios", 0);
+ machine->gpio_hp_det = of_get_named_gpio_flags(
+ np, "nvidia,hp-det-gpios", 0, &machine->gpio_hp_det_flags);
if (machine->gpio_hp_det == -EPROBE_DEFER)
return -EPROBE_DEFER;
diff --git a/sound/soc/txx9/txx9aclc-ac97.c b/sound/soc/txx9/txx9aclc-ac97.c
index 9edd68d..f7135cd 100644
--- a/sound/soc/txx9/txx9aclc-ac97.c
+++ b/sound/soc/txx9/txx9aclc-ac97.c
@@ -152,7 +152,7 @@ static int txx9aclc_ac97_remove(struct snd_soc_dai *dai)
}
static struct snd_soc_dai_driver txx9aclc_ac97_dai = {
- .ac97_control = 1,
+ .bus_control = true,
.probe = txx9aclc_ac97_probe,
.remove = txx9aclc_ac97_remove,
.playback = {
diff --git a/sound/soc/txx9/txx9aclc.c b/sound/soc/txx9/txx9aclc.c
index cd71fd8..00b7e2d 100644
--- a/sound/soc/txx9/txx9aclc.c
+++ b/sound/soc/txx9/txx9aclc.c
@@ -292,7 +292,7 @@ static int txx9aclc_pcm_new(struct snd_soc_pcm_runtime *rtd)
struct snd_card *card = rtd->card->snd_card;
struct snd_soc_dai *dai = rtd->cpu_dai;
struct snd_pcm *pcm = rtd->pcm;
- struct platform_device *pdev = to_platform_device(dai->platform->dev);
+ struct platform_device *pdev = to_platform_device(rtd->platform->dev);
struct txx9aclc_soc_device *dev;
struct resource *r;
int i;
diff --git a/sound/soc/ux500/mop500.c b/sound/soc/ux500/mop500.c
index b3b66aa..9f2d045 100644
--- a/sound/soc/ux500/mop500.c
+++ b/sound/soc/ux500/mop500.c
@@ -63,12 +63,8 @@ static void mop500_of_node_put(void)
int i;
for (i = 0; i < 2; i++) {
- if (mop500_dai_links[i].cpu_of_node)
- of_node_put((struct device_node *)
- mop500_dai_links[i].cpu_of_node);
- if (mop500_dai_links[i].codec_of_node)
- of_node_put((struct device_node *)
- mop500_dai_links[i].codec_of_node);
+ of_node_put(mop500_dai_links[i].cpu_of_node);
+ of_node_put(mop500_dai_links[i].codec_of_node);
}
}
diff --git a/sound/sparc/cs4231.c b/sound/sparc/cs4231.c
index 4e91bca..06606f9 100644
--- a/sound/sparc/cs4231.c
+++ b/sound/sparc/cs4231.c
@@ -1285,19 +1285,11 @@ static int snd_cs4231_timer(struct snd_card *card)
static int snd_cs4231_info_mux(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static char *texts[4] = {
+ static const char * const texts[4] = {
"Line", "CD", "Mic", "Mix"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 2;
- uinfo->value.enumerated.items = 4;
- if (uinfo->value.enumerated.item > 3)
- uinfo->value.enumerated.item = 3;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 2, 4, texts);
}
static int snd_cs4231_get_mux(struct snd_kcontrol *kcontrol,
diff --git a/sound/usb/6fire/control.c b/sound/usb/6fire/control.c
index 184e398..54656ee 100644
--- a/sound/usb/6fire/control.c
+++ b/sound/usb/6fire/control.c
@@ -25,8 +25,8 @@
#include "comm.h"
#include "chip.h"
-static char *opt_coax_texts[2] = { "Optical", "Coax" };
-static char *line_phono_texts[2] = { "Line", "Phono" };
+static const char * const opt_coax_texts[2] = { "Optical", "Coax" };
+static const char * const line_phono_texts[2] = { "Line", "Phono" };
/*
* data that needs to be sent to device. sets up card internal stuff.
@@ -327,14 +327,7 @@ static int usb6fire_control_input_vol_get(struct snd_kcontrol *kcontrol,
static int usb6fire_control_line_phono_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- line_phono_texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, line_phono_texts);
}
static int usb6fire_control_line_phono_put(struct snd_kcontrol *kcontrol,
@@ -361,14 +354,7 @@ static int usb6fire_control_line_phono_get(struct snd_kcontrol *kcontrol,
static int usb6fire_control_opt_coax_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- opt_coax_texts[uinfo->value.enumerated.item]);
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, 2, opt_coax_texts);
}
static int usb6fire_control_opt_coax_put(struct snd_kcontrol *kcontrol,
diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c
index 3b02e54..62c25e7 100644
--- a/sound/usb/6fire/firmware.c
+++ b/sound/usb/6fire/firmware.c
@@ -316,7 +316,7 @@ static int usb6fire_fw_fpga_upload(
while (c != end) {
for (i = 0; c != end && i < FPGA_BUFSIZE; i++, c++)
- buffer[i] = byte_rev_table[(u8) *c];
+ buffer[i] = bitrev8((u8)*c);
ret = usb6fire_fw_fpga_write(device, buffer, i);
if (ret < 0) {
diff --git a/sound/usb/6fire/pcm.c b/sound/usb/6fire/pcm.c
index ba40489..36f4115 100644
--- a/sound/usb/6fire/pcm.c
+++ b/sound/usb/6fire/pcm.c
@@ -679,25 +679,16 @@ int usb6fire_pcm_init(struct sfire_chip *chip)
void usb6fire_pcm_abort(struct sfire_chip *chip)
{
struct pcm_runtime *rt = chip->pcm;
- unsigned long flags;
int i;
if (rt) {
rt->panic = true;
- if (rt->playback.instance) {
- snd_pcm_stream_lock_irqsave(rt->playback.instance, flags);
- snd_pcm_stop(rt->playback.instance,
- SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(rt->playback.instance, flags);
- }
+ if (rt->playback.instance)
+ snd_pcm_stop_xrun(rt->playback.instance);
- if (rt->capture.instance) {
- snd_pcm_stream_lock_irqsave(rt->capture.instance, flags);
- snd_pcm_stop(rt->capture.instance,
- SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(rt->capture.instance, flags);
- }
+ if (rt->capture.instance)
+ snd_pcm_stop_xrun(rt->capture.instance);
for (i = 0; i < PCM_N_URBS; i++) {
usb_poison_urb(&rt->in_urbs[i].instance);
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2b92f0d..bcee406 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -9,6 +9,7 @@ snd-usb-audio-objs := card.o \
helper.o \
mixer.o \
mixer_quirks.o \
+ mixer_scarlett.o \
pcm.o \
proc.o \
quirks.o \
diff --git a/sound/usb/card.c b/sound/usb/card.c
index f61ebb1..1fab977 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -112,15 +112,13 @@ static struct usb_driver usb_audio_driver;
/*
* disconnect streams
- * called from snd_usb_audio_disconnect()
+ * called from usb_audio_disconnect()
*/
-static void snd_usb_stream_disconnect(struct list_head *head)
+static void snd_usb_stream_disconnect(struct snd_usb_stream *as)
{
int idx;
- struct snd_usb_stream *as;
struct snd_usb_substream *subs;
- as = list_entry(head, struct snd_usb_stream, list);
for (idx = 0; idx < 2; idx++) {
subs = &as->substream[idx];
if (!subs->num_formats)
@@ -307,10 +305,10 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif)
static int snd_usb_audio_free(struct snd_usb_audio *chip)
{
- struct list_head *p, *n;
+ struct snd_usb_endpoint *ep, *n;
- list_for_each_safe(p, n, &chip->ep_list)
- snd_usb_endpoint_free(p);
+ list_for_each_entry_safe(ep, n, &chip->ep_list, list)
+ snd_usb_endpoint_free(ep);
mutex_destroy(&chip->mutex);
kfree(chip);
@@ -323,16 +321,6 @@ static int snd_usb_audio_dev_free(struct snd_device *device)
return snd_usb_audio_free(chip);
}
-static void remove_trailing_spaces(char *str)
-{
- char *p;
-
- if (!*str)
- return;
- for (p = str + strlen(str) - 1; p >= str && isspace(*p); p--)
- *p = 0;
-}
-
/*
* create a chip instance and set its names.
*/
@@ -416,7 +404,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
USB_ID_PRODUCT(chip->usb_id));
}
}
- remove_trailing_spaces(card->shortname);
+ strim(card->shortname);
/* retrieve the vendor and device strings as longname */
if (quirk && quirk->vendor_name && *quirk->vendor_name) {
@@ -430,7 +418,7 @@ static int snd_usb_audio_create(struct usb_interface *intf,
/* we don't really care if there isn't any vendor string */
}
if (len > 0) {
- remove_trailing_spaces(card->longname);
+ strim(card->longname);
if (*card->longname)
strlcat(card->longname, " ", sizeof(card->longname));
}
@@ -475,14 +463,14 @@ static int snd_usb_audio_create(struct usb_interface *intf,
* only at the first time. the successive calls of this function will
* append the pcm interface to the corresponding card.
*/
-static struct snd_usb_audio *
-snd_usb_audio_probe(struct usb_device *dev,
- struct usb_interface *intf,
- const struct usb_device_id *usb_id)
+static int usb_audio_probe(struct usb_interface *intf,
+ const struct usb_device_id *usb_id)
{
- const struct snd_usb_audio_quirk *quirk = (const struct snd_usb_audio_quirk *)usb_id->driver_info;
- int i, err;
+ struct usb_device *dev = interface_to_usbdev(intf);
+ const struct snd_usb_audio_quirk *quirk =
+ (const struct snd_usb_audio_quirk *)usb_id->driver_info;
struct snd_usb_audio *chip;
+ int i, err;
struct usb_host_interface *alts;
int ifnum;
u32 id;
@@ -492,10 +480,11 @@ snd_usb_audio_probe(struct usb_device *dev,
id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
le16_to_cpu(dev->descriptor.idProduct));
if (quirk && quirk->ifnum >= 0 && ifnum != quirk->ifnum)
- goto __err_val;
+ return -ENXIO;
- if (snd_usb_apply_boot_quirk(dev, intf, quirk) < 0)
- goto __err_val;
+ err = snd_usb_apply_boot_quirk(dev, intf, quirk);
+ if (err < 0)
+ return err;
/*
* found a config. now register to ALSA
@@ -508,6 +497,7 @@ snd_usb_audio_probe(struct usb_device *dev,
if (usb_chip[i] && usb_chip[i]->dev == dev) {
if (usb_chip[i]->shutdown) {
dev_err(&dev->dev, "USB device is in the shutdown state, cannot create a card instance\n");
+ err = -EIO;
goto __error;
}
chip = usb_chip[i];
@@ -523,15 +513,16 @@ snd_usb_audio_probe(struct usb_device *dev,
if (enable[i] && ! usb_chip[i] &&
(vid[i] == -1 || vid[i] == USB_ID_VENDOR(id)) &&
(pid[i] == -1 || pid[i] == USB_ID_PRODUCT(id))) {
- if (snd_usb_audio_create(intf, dev, i, quirk,
- &chip) < 0) {
+ err = snd_usb_audio_create(intf, dev, i, quirk,
+ &chip);
+ if (err < 0)
goto __error;
- }
chip->pm_intf = intf;
break;
}
if (!chip) {
dev_err(&dev->dev, "no available usb audio device\n");
+ err = -ENODEV;
goto __error;
}
}
@@ -548,28 +539,32 @@ snd_usb_audio_probe(struct usb_device *dev,
err = 1; /* continue */
if (quirk && quirk->ifnum != QUIRK_NO_INTERFACE) {
/* need some special handlings */
- if ((err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk)) < 0)
+ err = snd_usb_create_quirk(chip, intf, &usb_audio_driver, quirk);
+ if (err < 0)
goto __error;
}
if (err > 0) {
/* create normal USB audio interfaces */
- if (snd_usb_create_streams(chip, ifnum) < 0 ||
- snd_usb_create_mixer(chip, ifnum, ignore_ctl_error) < 0) {
+ err = snd_usb_create_streams(chip, ifnum);
+ if (err < 0)
+ goto __error;
+ err = snd_usb_create_mixer(chip, ifnum, ignore_ctl_error);
+ if (err < 0)
goto __error;
- }
}
/* we are allowed to call snd_card_register() many times */
- if (snd_card_register(chip->card) < 0) {
+ err = snd_card_register(chip->card);
+ if (err < 0)
goto __error;
- }
usb_chip[chip->index] = chip;
chip->num_interfaces++;
chip->probing = 0;
+ usb_set_intfdata(intf, chip);
mutex_unlock(&register_mutex);
- return chip;
+ return 0;
__error:
if (chip) {
@@ -578,17 +573,16 @@ snd_usb_audio_probe(struct usb_device *dev,
chip->probing = 0;
}
mutex_unlock(&register_mutex);
- __err_val:
- return NULL;
+ return err;
}
/*
* we need to take care of counter, since disconnection can be called also
* many times as well as usb_audio_probe().
*/
-static void snd_usb_audio_disconnect(struct usb_device *dev,
- struct snd_usb_audio *chip)
+static void usb_audio_disconnect(struct usb_interface *intf)
{
+ struct snd_usb_audio *chip = usb_get_intfdata(intf);
struct snd_card *card;
struct list_head *p;
bool was_shutdown;
@@ -604,12 +598,14 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
mutex_lock(&register_mutex);
if (!was_shutdown) {
+ struct snd_usb_stream *as;
struct snd_usb_endpoint *ep;
+ struct usb_mixer_interface *mixer;
snd_card_disconnect(card);
/* release the pcm resources */
- list_for_each(p, &chip->pcm_list) {
- snd_usb_stream_disconnect(p);
+ list_for_each_entry(as, &chip->pcm_list, list) {
+ snd_usb_stream_disconnect(as);
}
/* release the endpoint resources */
list_for_each_entry(ep, &chip->ep_list, list) {
@@ -620,8 +616,8 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
snd_usbmidi_disconnect(p);
}
/* release mixer resources */
- list_for_each(p, &chip->mixer_list) {
- snd_usb_mixer_disconnect(p);
+ list_for_each_entry(mixer, &chip->mixer_list, list) {
+ snd_usb_mixer_disconnect(mixer);
}
}
@@ -635,27 +631,6 @@ static void snd_usb_audio_disconnect(struct usb_device *dev,
}
}
-/*
- * new 2.5 USB kernel API
- */
-static int usb_audio_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct snd_usb_audio *chip;
- chip = snd_usb_audio_probe(interface_to_usbdev(intf), intf, id);
- if (chip) {
- usb_set_intfdata(intf, chip);
- return 0;
- } else
- return -EIO;
-}
-
-static void usb_audio_disconnect(struct usb_interface *intf)
-{
- snd_usb_audio_disconnect(interface_to_usbdev(intf),
- usb_get_intfdata(intf));
-}
-
#ifdef CONFIG_PM
int snd_usb_autoresume(struct snd_usb_audio *chip)
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 114e3e7..03b0744 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -348,6 +348,8 @@ static void snd_complete_urb(struct urb *urb)
{
struct snd_urb_ctx *ctx = urb->context;
struct snd_usb_endpoint *ep = ctx->ep;
+ struct snd_pcm_substream *substream;
+ unsigned long flags;
int err;
if (unlikely(urb->status == -ENOENT || /* unlinked */
@@ -364,8 +366,6 @@ static void snd_complete_urb(struct urb *urb)
goto exit_clear;
if (snd_usb_endpoint_implicit_feedback_sink(ep)) {
- unsigned long flags;
-
spin_lock_irqsave(&ep->lock, flags);
list_add_tail(&ctx->ready_list, &ep->ready_playback_urbs);
spin_unlock_irqrestore(&ep->lock, flags);
@@ -389,7 +389,10 @@ static void snd_complete_urb(struct urb *urb)
return;
usb_audio_err(ep->chip, "cannot submit urb (err = %d)\n", err);
- //snd_pcm_stop(substream, SNDRV_PCM_STATE_XRUN);
+ if (ep->data_subs && ep->data_subs->pcm_substream) {
+ substream = ep->data_subs->pcm_substream;
+ snd_pcm_stop_xrun(substream);
+ }
exit_clear:
clear_bit(ctx->index, &ep->active_mask);
@@ -1002,15 +1005,12 @@ void snd_usb_endpoint_release(struct snd_usb_endpoint *ep)
/**
* snd_usb_endpoint_free: Free the resources of an snd_usb_endpoint
*
- * @ep: the list header of the endpoint to free
+ * @ep: the endpoint to free
*
* This free all resources of the given ep.
*/
-void snd_usb_endpoint_free(struct list_head *head)
+void snd_usb_endpoint_free(struct snd_usb_endpoint *ep)
{
- struct snd_usb_endpoint *ep;
-
- ep = list_entry(head, struct snd_usb_endpoint, list);
kfree(ep);
}
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index e61ee5c..6428392 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -24,7 +24,7 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_release(struct snd_usb_endpoint *ep);
-void snd_usb_endpoint_free(struct list_head *head);
+void snd_usb_endpoint_free(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_implicit_feedback_sink(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_next_packet_size(struct snd_usb_endpoint *ep);
diff --git a/sound/usb/midi.c b/sound/usb/midi.c
index d3d4952..5bfb695 100644
--- a/sound/usb/midi.c
+++ b/sound/usb/midi.c
@@ -365,6 +365,8 @@ static void snd_usbmidi_error_timer(unsigned long data)
if (in && in->error_resubmit) {
in->error_resubmit = 0;
for (j = 0; j < INPUT_URBS; ++j) {
+ if (atomic_read(&in->urbs[j]->use_count))
+ continue;
in->urbs[j]->dev = umidi->dev;
snd_usbmidi_submit_urb(in->urbs[j], GFP_ATOMIC);
}
diff --git a/sound/usb/misc/ua101.c b/sound/usb/misc/ua101.c
index a1bab14..9581089 100644
--- a/sound/usb/misc/ua101.c
+++ b/sound/usb/misc/ua101.c
@@ -613,24 +613,14 @@ static int start_usb_playback(struct ua101 *ua)
static void abort_alsa_capture(struct ua101 *ua)
{
- unsigned long flags;
-
- if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states)) {
- snd_pcm_stream_lock_irqsave(ua->capture.substream, flags);
- snd_pcm_stop(ua->capture.substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(ua->capture.substream, flags);
- }
+ if (test_bit(ALSA_CAPTURE_RUNNING, &ua->states))
+ snd_pcm_stop_xrun(ua->capture.substream);
}
static void abort_alsa_playback(struct ua101 *ua)
{
- unsigned long flags;
-
- if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states)) {
- snd_pcm_stream_lock_irqsave(ua->playback.substream, flags);
- snd_pcm_stop(ua->playback.substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(ua->playback.substream, flags);
- }
+ if (test_bit(ALSA_PLAYBACK_RUNNING, &ua->states))
+ snd_pcm_stop_xrun(ua->playback.substream);
}
static int set_stream_hw(struct ua101 *ua, struct snd_pcm_substream *substream,
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c
index 6e354d3..41650d5 100644
--- a/sound/usb/mixer.c
+++ b/sound/usb/mixer.c
@@ -136,6 +136,10 @@ check_mapped_name(const struct usbmix_name_map *p, char *buf, int buflen)
return strlcpy(buf, p->name, buflen);
}
+/* ignore the error value if ignore_ctl_error flag is set */
+#define filter_error(cval, err) \
+ ((cval)->head.mixer->ignore_ctl_error ? 0 : (err))
+
/* check whether the control should be ignored */
static inline int
check_ignored_ctl(const struct usbmix_name_map *p)
@@ -286,13 +290,13 @@ static int get_abs_value(struct usb_mixer_elem_info *cval, int val)
static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
int validx, int *value_ret)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2];
int val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
int timeout = 10;
int idx = 0, err;
- err = snd_usb_autoresume(cval->mixer->chip);
+ err = snd_usb_autoresume(chip);
if (err < 0)
return -EIO;
@@ -300,7 +304,7 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
while (timeout-- > 0) {
if (chip->shutdown)
break;
- idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
if (snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, idx, buf, val_len) >= val_len) {
@@ -316,14 +320,14 @@ static int get_ctl_value_v1(struct usb_mixer_elem_info *cval, int request,
out:
up_read(&chip->shutdown_rwsem);
- snd_usb_autosuspend(cval->mixer->chip);
+ snd_usb_autosuspend(chip);
return err;
}
static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
int validx, int *value_ret)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2 + 3 * sizeof(__u16)]; /* enough space for one range */
unsigned char *val;
int idx = 0, ret, size;
@@ -347,7 +351,7 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request,
if (chip->shutdown) {
ret = -ENODEV;
} else {
- idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), bRequest,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
validx, idx, buf, size);
@@ -392,7 +396,7 @@ static int get_ctl_value(struct usb_mixer_elem_info *cval, int request,
{
validx += cval->idx_off;
- return (cval->mixer->protocol == UAC_VERSION_1) ?
+ return (cval->head.mixer->protocol == UAC_VERSION_1) ?
get_ctl_value_v1(cval, request, validx, value_ret) :
get_ctl_value_v2(cval, request, validx, value_ret);
}
@@ -412,7 +416,7 @@ static inline int get_cur_mix_raw(struct usb_mixer_elem_info *cval,
value);
}
-static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
+int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
int channel, int index, int *value)
{
int err;
@@ -423,8 +427,8 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
}
err = get_cur_mix_raw(cval, channel, value);
if (err < 0) {
- if (!cval->mixer->ignore_ctl_error)
- usb_audio_dbg(cval->mixer->chip,
+ if (!cval->head.mixer->ignore_ctl_error)
+ usb_audio_dbg(cval->head.mixer->chip,
"cannot get current value for control %d ch %d: err = %d\n",
cval->control, channel, err);
return err;
@@ -441,13 +445,13 @@ static int get_cur_mix_value(struct usb_mixer_elem_info *cval,
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
unsigned char buf[2];
int idx = 0, val_len, err, timeout = 10;
validx += cval->idx_off;
- if (cval->mixer->protocol == UAC_VERSION_1) {
+ if (cval->head.mixer->protocol == UAC_VERSION_1) {
val_len = cval->val_type >= USB_MIXER_S16 ? 2 : 1;
} else { /* UAC_VERSION_2 */
/* audio class v2 controls are always 2 bytes in size */
@@ -472,7 +476,7 @@ int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
while (timeout-- > 0) {
if (chip->shutdown)
break;
- idx = snd_usb_ctrl_intf(chip) | (cval->id << 8);
+ idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8);
if (snd_usb_ctl_msg(chip->dev,
usb_sndctrlpipe(chip->dev, 0), request,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
@@ -497,7 +501,7 @@ static int set_cur_ctl_value(struct usb_mixer_elem_info *cval,
return snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, validx, value);
}
-static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
+int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
int index, int value)
{
int err;
@@ -506,7 +510,7 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
cval->ch_readonly & (1 << (channel - 1));
if (read_only) {
- usb_audio_dbg(cval->mixer->chip,
+ usb_audio_dbg(cval->head.mixer->chip,
"%s(): channel %d of control %d is read_only\n",
__func__, channel, cval->control);
return 0;
@@ -565,10 +569,10 @@ static int check_matrix_bitmap(unsigned char *bmap,
* if failed, give up and free the control instance.
*/
-int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
struct snd_kcontrol *kctl)
{
- struct usb_mixer_elem_info *cval = kctl->private_data;
+ struct usb_mixer_interface *mixer = list->mixer;
int err;
while (snd_ctl_find_id(mixer->chip->card, &kctl->id))
@@ -578,9 +582,9 @@ int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
err);
return err;
}
- cval->elem_id = &kctl->id;
- cval->next_id_elem = mixer->id_elems[cval->id];
- mixer->id_elems[cval->id] = cval;
+ list->kctl = kctl;
+ list->next_id_elem = mixer->id_elems[list->id];
+ mixer->id_elems[list->id] = list;
return 0;
}
@@ -815,7 +819,7 @@ static struct usb_feature_control_info audio_feature_info[] = {
};
/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
+void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl)
{
kfree(kctl->private_data);
kctl->private_data = NULL;
@@ -829,7 +833,7 @@ static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
static void volume_control_quirks(struct usb_mixer_elem_info *cval,
struct snd_kcontrol *kctl)
{
- struct snd_usb_audio *chip = cval->mixer->chip;
+ struct snd_usb_audio *chip = cval->head.mixer->chip;
switch (chip->usb_id) {
case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */
case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */
@@ -954,10 +958,10 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
}
if (get_ctl_value(cval, UAC_GET_MAX, (cval->control << 8) | minchn, &cval->max) < 0 ||
get_ctl_value(cval, UAC_GET_MIN, (cval->control << 8) | minchn, &cval->min) < 0) {
- usb_audio_err(cval->mixer->chip,
+ usb_audio_err(cval->head.mixer->chip,
"%d:%d: cannot get min/max values for control %d (id %d)\n",
- cval->id, snd_usb_ctrl_intf(cval->mixer->chip),
- cval->control, cval->id);
+ cval->head.id, snd_usb_ctrl_intf(cval->head.mixer->chip),
+ cval->control, cval->head.id);
return -EINVAL;
}
if (get_ctl_value(cval, UAC_GET_RES,
@@ -998,7 +1002,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
else
test -= cval->res;
if (test < cval->min || test > cval->max ||
- set_cur_mix_value(cval, minchn, 0, test) ||
+ snd_usb_set_cur_mix_value(cval, minchn, 0, test) ||
get_cur_mix_raw(cval, minchn, &check)) {
cval->res = last_valid_res;
break;
@@ -1007,7 +1011,7 @@ static int get_min_max_with_quirks(struct usb_mixer_elem_info *cval,
break;
cval->res *= 2;
}
- set_cur_mix_value(cval, minchn, 0, saved);
+ snd_usb_set_cur_mix_value(cval, minchn, 0, saved);
}
cval->initialized = 1;
@@ -1061,7 +1065,7 @@ static int mixer_ctl_feature_info(struct snd_kcontrol *kcontrol,
kcontrol->vd[0].access &=
~(SNDRV_CTL_ELEM_ACCESS_TLV_READ |
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK);
- snd_ctl_notify(cval->mixer->chip->card,
+ snd_ctl_notify(cval->head.mixer->chip->card,
SNDRV_CTL_EVENT_MASK_INFO,
&kcontrol->id);
}
@@ -1086,9 +1090,9 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
for (c = 0; c < MAX_CHANNELS; c++) {
if (!(cval->cmask & (1 << c)))
continue;
- err = get_cur_mix_value(cval, c + 1, cnt, &val);
+ err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &val);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = get_relative_value(cval, val);
ucontrol->value.integer.value[cnt] = val;
cnt++;
@@ -1096,9 +1100,9 @@ static int mixer_ctl_feature_get(struct snd_kcontrol *kcontrol,
return 0;
} else {
/* master channel */
- err = get_cur_mix_value(cval, 0, 0, &val);
+ err = snd_usb_get_cur_mix_value(cval, 0, 0, &val);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = get_relative_value(cval, val);
ucontrol->value.integer.value[0] = val;
}
@@ -1118,26 +1122,26 @@ static int mixer_ctl_feature_put(struct snd_kcontrol *kcontrol,
for (c = 0; c < MAX_CHANNELS; c++) {
if (!(cval->cmask & (1 << c)))
continue;
- err = get_cur_mix_value(cval, c + 1, cnt, &oval);
+ err = snd_usb_get_cur_mix_value(cval, c + 1, cnt, &oval);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = ucontrol->value.integer.value[cnt];
val = get_abs_value(cval, val);
if (oval != val) {
- set_cur_mix_value(cval, c + 1, cnt, val);
+ snd_usb_set_cur_mix_value(cval, c + 1, cnt, val);
changed = 1;
}
cnt++;
}
} else {
/* master channel */
- err = get_cur_mix_value(cval, 0, 0, &oval);
+ err = snd_usb_get_cur_mix_value(cval, 0, 0, &oval);
if (err < 0)
- return cval->mixer->ignore_ctl_error ? 0 : err;
+ return filter_error(cval, err);
val = ucontrol->value.integer.value[0];
val = get_abs_value(cval, val);
if (val != oval) {
- set_cur_mix_value(cval, 0, 0, val);
+ snd_usb_set_cur_mix_value(cval, 0, 0, val);
changed = 1;
}
}
@@ -1231,8 +1235,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = control;
cval->cmask = ctl_mask;
cval->val_type = audio_feature_info[control-1].type;
@@ -1250,7 +1253,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
/*
* If all channels in the mask are marked read-only, make the control
- * read-only. set_cur_mix_value() will check the mask again and won't
+ * read-only. snd_usb_set_cur_mix_value() will check the mask again and won't
* issue write commands to read-only channels.
*/
if (cval->channels == readonly_mask)
@@ -1263,7 +1266,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
kfree(cval);
return;
}
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
mapped_name = len != 0;
@@ -1290,9 +1293,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
kctl->id.name,
sizeof(kctl->id.name), 1);
if (!len)
- len = snprintf(kctl->id.name,
- sizeof(kctl->id.name),
- "Feature %d", unitid);
+ snprintf(kctl->id.name, sizeof(kctl->id.name),
+ "Feature %d", unitid);
}
if (!mapped_name)
@@ -1305,9 +1307,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
*/
if (!mapped_name && !(state->oterm.type >> 16)) {
if ((state->oterm.type & 0xff00) == 0x0100)
- len = append_ctl_name(kctl, " Capture");
+ append_ctl_name(kctl, " Capture");
else
- len = append_ctl_name(kctl, " Playback");
+ append_ctl_name(kctl, " Playback");
}
append_ctl_name(kctl, control == UAC_FU_MUTE ?
" Switch" : " Volume");
@@ -1344,14 +1346,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc,
range);
usb_audio_warn(state->chip,
"[%d] FU [%s] ch = %d, val = %d/%d/%d",
- cval->id, kctl->id.name, cval->channels,
+ cval->head.id, kctl->id.name, cval->channels,
cval->min, cval->max, cval->res);
}
usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n",
- cval->id, kctl->id.name, cval->channels,
+ cval->head.id, kctl->id.name, cval->channels,
cval->min, cval->max, cval->res);
- snd_usb_mixer_add_control(state->mixer, kctl);
+ snd_usb_mixer_add_control(&cval->head, kctl);
}
/*
@@ -1525,8 +1527,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
if (!cval)
return;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = in_ch + 1; /* based on 1 */
cval->val_type = USB_MIXER_S16;
for (i = 0; i < num_outs; i++) {
@@ -1547,7 +1548,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
kfree(cval);
return;
}
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name));
if (!len)
@@ -1558,8 +1559,8 @@ static void build_mixer_unit_ctl(struct mixer_build *state,
append_ctl_name(kctl, " Volume");
usb_audio_dbg(state->chip, "[%d] MU [%s] ch = %d, val = %d/%d\n",
- cval->id, kctl->id.name, cval->channels, cval->min, cval->max);
- snd_usb_mixer_add_control(state->mixer, kctl);
+ cval->head.id, kctl->id.name, cval->channels, cval->min, cval->max);
+ snd_usb_mixer_add_control(&cval->head, kctl);
}
/*
@@ -1629,12 +1630,10 @@ static int mixer_ctl_procunit_get(struct snd_kcontrol *kcontrol,
int err, val;
err = get_cur_ctl_value(cval, cval->control << 8, &val);
- if (err < 0 && cval->mixer->ignore_ctl_error) {
+ if (err < 0) {
ucontrol->value.integer.value[0] = cval->min;
- return 0;
+ return filter_error(cval, err);
}
- if (err < 0)
- return err;
val = get_relative_value(cval, val);
ucontrol->value.integer.value[0] = val;
return 0;
@@ -1648,11 +1647,8 @@ static int mixer_ctl_procunit_put(struct snd_kcontrol *kcontrol,
int val, oval, err;
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
- if (err < 0) {
- if (cval->mixer->ignore_ctl_error)
- return 0;
- return err;
- }
+ if (err < 0)
+ return filter_error(cval, err);
val = ucontrol->value.integer.value[0];
val = get_abs_value(cval, val);
if (val != oval) {
@@ -1814,8 +1810,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return -ENOMEM;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->control = valinfo->control;
cval->val_type = valinfo->val_type;
cval->channels = 1;
@@ -1847,7 +1842,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
kfree(cval);
return -ENOMEM;
}
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
if (check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name))) {
/* nothing */ ;
@@ -1868,10 +1863,10 @@ static int build_audio_procunit(struct mixer_build *state, int unitid,
usb_audio_dbg(state->chip,
"[%d] PU [%s] ch = %d, val = %d/%d\n",
- cval->id, kctl->id.name, cval->channels,
+ cval->head.id, kctl->id.name, cval->channels,
cval->min, cval->max);
- err = snd_usb_mixer_add_control(state->mixer, kctl);
+ err = snd_usb_mixer_add_control(&cval->head, kctl);
if (err < 0)
return err;
}
@@ -1924,11 +1919,8 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol,
err = get_cur_ctl_value(cval, cval->control << 8, &val);
if (err < 0) {
- if (cval->mixer->ignore_ctl_error) {
- ucontrol->value.enumerated.item[0] = 0;
- return 0;
- }
- return err;
+ ucontrol->value.enumerated.item[0] = 0;
+ return filter_error(cval, err);
}
val = get_relative_value(cval, val);
ucontrol->value.enumerated.item[0] = val;
@@ -1943,11 +1935,8 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol,
int val, oval, err;
err = get_cur_ctl_value(cval, cval->control << 8, &oval);
- if (err < 0) {
- if (cval->mixer->ignore_ctl_error)
- return 0;
- return err;
- }
+ if (err < 0)
+ return filter_error(cval, err);
val = ucontrol->value.enumerated.item[0];
val = get_abs_value(cval, val);
if (val != oval) {
@@ -2024,8 +2013,7 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
cval = kzalloc(sizeof(*cval), GFP_KERNEL);
if (!cval)
return -ENOMEM;
- cval->mixer = state->mixer;
- cval->id = unitid;
+ snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid);
cval->val_type = USB_MIXER_U8;
cval->channels = 1;
cval->min = 1;
@@ -2096,11 +2084,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid,
}
usb_audio_dbg(state->chip, "[%d] SU [%s] items = %d\n",
- cval->id, kctl->id.name, desc->bNrInPins);
- if ((err = snd_usb_mixer_add_control(state->mixer, kctl)) < 0)
- return err;
-
- return 0;
+ cval->head.id, kctl->id.name, desc->bNrInPins);
+ return snd_usb_mixer_add_control(&cval->head, kctl);
}
/*
@@ -2245,25 +2230,21 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer)
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid)
{
- struct usb_mixer_elem_info *info;
+ struct usb_mixer_elem_list *list;
- for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem)
+ for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem)
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- info->elem_id);
+ &list->kctl->id);
}
static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer,
- int unitid,
- struct usb_mixer_elem_info *cval)
+ struct usb_mixer_elem_list *list)
{
+ struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN",
"S8", "U8", "S16", "U16"};
- snd_iprintf(buffer, " Unit: %i\n", unitid);
- if (cval->elem_id)
- snd_iprintf(buffer, " Control: name=\"%s\", index=%i\n",
- cval->elem_id->name, cval->elem_id->index);
snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, "
- "channels=%i, type=\"%s\"\n", cval->id,
+ "channels=%i, type=\"%s\"\n", cval->head.id,
cval->control, cval->cmask, cval->channels,
val_types[cval->val_type]);
snd_iprintf(buffer, " Volume: min=%i, max=%i, dBmin=%i, dBmax=%i\n",
@@ -2275,7 +2256,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
{
struct snd_usb_audio *chip = entry->private_data;
struct usb_mixer_interface *mixer;
- struct usb_mixer_elem_info *cval;
+ struct usb_mixer_elem_list *list;
int unitid;
list_for_each_entry(mixer, &chip->mixer_list, list) {
@@ -2285,9 +2266,17 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
mixer->ignore_ctl_error);
snd_iprintf(buffer, "Card: %s\n", chip->card->longname);
for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) {
- for (cval = mixer->id_elems[unitid]; cval;
- cval = cval->next_id_elem)
- snd_usb_mixer_dump_cval(buffer, unitid, cval);
+ for (list = mixer->id_elems[unitid]; list;
+ list = list->next_id_elem) {
+ snd_iprintf(buffer, " Unit: %i\n", list->id);
+ if (list->kctl)
+ snd_iprintf(buffer,
+ " Control: name=\"%s\", index=%i\n",
+ list->kctl->id.name,
+ list->kctl->id.index);
+ if (list->dump)
+ list->dump(buffer, list);
+ }
}
}
}
@@ -2295,7 +2284,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry,
static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
int attribute, int value, int index)
{
- struct usb_mixer_elem_info *info;
+ struct usb_mixer_elem_list *list;
__u8 unitid = (index >> 8) & 0xff;
__u8 control = (value >> 8) & 0xff;
__u8 channel = value & 0xff;
@@ -2307,7 +2296,13 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
return;
}
- for (info = mixer->id_elems[unitid]; info; info = info->next_id_elem) {
+ for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) {
+ struct usb_mixer_elem_info *info;
+
+ if (!list->kctl)
+ continue;
+
+ info = (struct usb_mixer_elem_info *)list;
if (info->control != control)
continue;
@@ -2320,7 +2315,7 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer,
info->cached = 0;
snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE,
- info->elem_id);
+ &info->head.kctl->id);
break;
case UAC2_CS_RANGE:
@@ -2485,11 +2480,8 @@ _error:
return err;
}
-void snd_usb_mixer_disconnect(struct list_head *p)
+void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer)
{
- struct usb_mixer_interface *mixer;
-
- mixer = list_entry(p, struct usb_mixer_interface, list);
usb_kill_urb(mixer->urb);
usb_kill_urb(mixer->rc_urb);
}
@@ -2521,8 +2513,9 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer)
return 0;
}
-static int restore_mixer_value(struct usb_mixer_elem_info *cval)
+static int restore_mixer_value(struct usb_mixer_elem_list *list)
{
+ struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list;
int c, err, idx;
if (cval->cmask) {
@@ -2531,7 +2524,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
if (!(cval->cmask & (1 << c)))
continue;
if (cval->cached & (1 << c)) {
- err = set_cur_mix_value(cval, c + 1, idx,
+ err = snd_usb_set_cur_mix_value(cval, c + 1, idx,
cval->cache_val[idx]);
if (err < 0)
return err;
@@ -2541,7 +2534,7 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
} else {
/* master */
if (cval->cached) {
- err = set_cur_mix_value(cval, 0, 0, *cval->cache_val);
+ err = snd_usb_set_cur_mix_value(cval, 0, 0, *cval->cache_val);
if (err < 0)
return err;
}
@@ -2552,19 +2545,19 @@ static int restore_mixer_value(struct usb_mixer_elem_info *cval)
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
{
- struct usb_mixer_elem_info *cval;
+ struct usb_mixer_elem_list *list;
int id, err;
- /* FIXME: any mixer quirks? */
-
if (reset_resume) {
/* restore cached mixer values */
for (id = 0; id < MAX_ID_ELEMS; id++) {
- for (cval = mixer->id_elems[id]; cval;
- cval = cval->next_id_elem) {
- err = restore_mixer_value(cval);
- if (err < 0)
- return err;
+ for (list = mixer->id_elems[id]; list;
+ list = list->next_id_elem) {
+ if (list->resume) {
+ err = list->resume(list);
+ if (err < 0)
+ return err;
+ }
}
}
}
@@ -2572,3 +2565,15 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume)
return snd_usb_mixer_activate(mixer);
}
#endif
+
+void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
+ struct usb_mixer_interface *mixer,
+ int unitid)
+{
+ list->mixer = mixer;
+ list->id = unitid;
+ list->dump = snd_usb_mixer_dump_cval;
+#ifdef CONFIG_PM
+ list->resume = restore_mixer_value;
+#endif
+}
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 73b1f64..d3268f0 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -1,6 +1,8 @@
#ifndef __USBMIXER_H
#define __USBMIXER_H
+#include <sound/info.h>
+
struct usb_mixer_interface {
struct snd_usb_audio *chip;
struct usb_host_interface *hostif;
@@ -8,7 +10,7 @@ struct usb_mixer_interface {
unsigned int ignore_ctl_error;
struct urb *urb;
/* array[MAX_ID_ELEMS], indexed by unit id */
- struct usb_mixer_elem_info **id_elems;
+ struct usb_mixer_elem_list **id_elems;
/* the usb audio specification version this interface complies to */
int protocol;
@@ -20,9 +22,6 @@ struct usb_mixer_interface {
struct urb *rc_urb;
struct usb_ctrlrequest *rc_setup_packet;
u8 rc_buffer[6];
-
- u8 audigy2nx_leds[3];
- u8 xonar_u1_status;
};
#define MAX_CHANNELS 16 /* max logical channels */
@@ -36,11 +35,21 @@ enum {
USB_MIXER_U16,
};
-struct usb_mixer_elem_info {
+typedef void (*usb_mixer_elem_dump_func_t)(struct snd_info_buffer *buffer,
+ struct usb_mixer_elem_list *list);
+typedef int (*usb_mixer_elem_resume_func_t)(struct usb_mixer_elem_list *elem);
+
+struct usb_mixer_elem_list {
struct usb_mixer_interface *mixer;
- struct usb_mixer_elem_info *next_id_elem; /* list of controls with same id */
- struct snd_ctl_elem_id *elem_id;
+ struct usb_mixer_elem_list *next_id_elem; /* list of controls with same id */
+ struct snd_kcontrol *kctl;
unsigned int id;
+ usb_mixer_elem_dump_func_t dump;
+ usb_mixer_elem_resume_func_t resume;
+};
+
+struct usb_mixer_elem_info {
+ struct usb_mixer_elem_list head;
unsigned int control; /* CS or ICN (high byte) */
unsigned int cmask; /* channel mask bitmap: 0 = master */
unsigned int idx_off; /* Control index offset */
@@ -53,20 +62,25 @@ struct usb_mixer_elem_info {
int cached;
int cache_val[MAX_CHANNELS];
u8 initialized;
+ void *private_data;
};
int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif,
int ignore_error);
-void snd_usb_mixer_disconnect(struct list_head *p);
+void snd_usb_mixer_disconnect(struct usb_mixer_interface *mixer);
void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid);
int snd_usb_mixer_set_ctl_value(struct usb_mixer_elem_info *cval,
int request, int validx, int value_set);
-int snd_usb_mixer_add_control(struct usb_mixer_interface *mixer,
+int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list,
struct snd_kcontrol *kctl);
+void snd_usb_mixer_elem_init_std(struct usb_mixer_elem_list *list,
+ struct usb_mixer_interface *mixer,
+ int unitid);
+
int snd_usb_mixer_vol_tlv(struct snd_kcontrol *kcontrol, int op_flag,
unsigned int size, unsigned int __user *_tlv);
@@ -75,4 +89,12 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer);
int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume);
#endif
+int snd_usb_set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel,
+ int index, int value);
+
+int snd_usb_get_cur_mix_value(struct usb_mixer_elem_info *cval,
+ int channel, int index, int *value);
+
+extern void snd_usb_mixer_elem_free(struct snd_kcontrol *kctl);
+
#endif /* __USBMIXER_H */
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c
index d1d72ff..1994d41 100644
--- a/sound/usb/mixer_maps.c
+++ b/sound/usb/mixer_maps.c
@@ -179,6 +179,11 @@ static struct usbmix_name_map audigy2nx_map[] = {
{ 0 } /* terminator */
};
+static struct usbmix_name_map mbox1_map[] = {
+ { 1, "Clock" },
+ { 0 } /* terminator */
+};
+
static struct usbmix_selector_map c400_selectors[] = {
{
.id = 0x80,
@@ -416,6 +421,10 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = {
.map = aureon_51_2_map,
},
{
+ .id = USB_ID(0x0dba, 0x1000),
+ .map = mbox1_map,
+ },
+ {
.id = USB_ID(0x13e5, 0x0001),
.map = scratch_live_map,
.ignore_ctl_error = 1,
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c
index 8c9bf4b..dc9df00 100644
--- a/sound/usb/mixer_quirks.c
+++ b/sound/usb/mixer_quirks.c
@@ -41,6 +41,7 @@
#include "usbaudio.h"
#include "mixer.h"
#include "mixer_quirks.h"
+#include "mixer_scarlett.h"
#include "helper.h"
extern struct snd_kcontrol_new *snd_usb_feature_unit_ctl;
@@ -52,13 +53,6 @@ struct std_mono_table {
snd_kcontrol_tlv_rw_t *tlv_callback;
};
-/* private_free callback */
-static void usb_mixer_elem_free(struct snd_kcontrol *kctl)
-{
- kfree(kctl->private_data);
- kctl->private_data = NULL;
-}
-
/* This function allows for the creation of standard UAC controls.
* See the quirks for M-Audio FTUs or Ebox-44.
* If you don't want to set a TLV callback pass NULL.
@@ -75,7 +69,6 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
const char *name,
snd_kcontrol_tlv_rw_t *tlv_callback)
{
- int err;
struct usb_mixer_elem_info *cval;
struct snd_kcontrol *kctl;
@@ -83,8 +76,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
if (!cval)
return -ENOMEM;
- cval->id = unitid;
- cval->mixer = mixer;
+ snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid);
cval->val_type = val_type;
cval->channels = 1;
cval->control = control;
@@ -108,7 +100,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
/* Set name */
snprintf(kctl->id.name, sizeof(kctl->id.name), name);
- kctl->private_free = usb_mixer_elem_free;
+ kctl->private_free = snd_usb_mixer_elem_free;
/* set TLV */
if (tlv_callback) {
@@ -118,11 +110,7 @@ static int snd_create_std_mono_ctl_offset(struct usb_mixer_interface *mixer,
SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK;
}
/* Add control to mixer */
- err = snd_usb_mixer_add_control(mixer, kctl);
- if (err < 0)
- return err;
-
- return 0;
+ return snd_usb_mixer_add_control(&cval->head, kctl);
}
static int snd_create_std_mono_ctl(struct usb_mixer_interface *mixer,
@@ -156,6 +144,32 @@ static int snd_create_std_mono_table(struct usb_mixer_interface *mixer,
return 0;
}
+static int add_single_ctl_with_resume(struct usb_mixer_interface *mixer,
+ int id,
+ usb_mixer_elem_resume_func_t resume,
+ const struct snd_kcontrol_new *knew,
+ struct usb_mixer_elem_list **listp)
+{
+ struct usb_mixer_elem_list *list;
+ struct snd_kcontrol *kctl;
+
+ list = kzalloc(sizeof(*list), GFP_KERNEL);
+ if (!list)
+ return -ENOMEM;
+ if (listp)
+ *listp = list;
+ list->mixer = mixer;
+ list->id = id;
+ list->resume = resume;
+ kctl = snd_ctl_new1(knew, list);
+ if (!kctl) {
+ kfree(list);
+ return -ENOMEM;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+ return snd_usb_mixer_add_control(list, kctl);
+}
+
/*
* Sound Blaster remote control configuration
*
@@ -283,84 +297,90 @@ static int snd_usb_soundblaster_remote_init(struct usb_mixer_interface *mixer)
static int snd_audigy2nx_led_get(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- int index = kcontrol->private_value;
-
- ucontrol->value.integer.value[0] = mixer->audigy2nx_leds[index];
+ ucontrol->value.integer.value[0] = kcontrol->private_value >> 8;
return 0;
}
-static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)
+static int snd_audigy2nx_led_update(struct usb_mixer_interface *mixer,
+ int value, int index)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- int index = kcontrol->private_value;
- int value = ucontrol->value.integer.value[0];
- int err, changed;
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
- if (value > 1)
- return -EINVAL;
- changed = value != mixer->audigy2nx_leds[index];
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown) {
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
err = -ENODEV;
goto out;
}
- if (mixer->chip->usb_id == USB_ID(0x041e, 0x3042))
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ if (chip->usb_id == USB_ID(0x041e, 0x3042))
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
!value, 0, NULL, 0);
/* USB X-Fi S51 Pro */
- if (mixer->chip->usb_id == USB_ID(0x041e, 0x30df))
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ if (chip->usb_id == USB_ID(0x041e, 0x30df))
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
!value, 0, NULL, 0);
else
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x24,
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x24,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
value, index + 2, NULL, 0);
out:
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
- mixer->audigy2nx_leds[index] = value;
- return changed;
+ up_read(&chip->shutdown_rwsem);
+ return err;
}
-static struct snd_kcontrol_new snd_audigy2nx_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "CMSS LED Switch",
- .info = snd_audigy2nx_led_info,
- .get = snd_audigy2nx_led_get,
- .put = snd_audigy2nx_led_put,
- .private_value = 0,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Power LED Switch",
- .info = snd_audigy2nx_led_info,
- .get = snd_audigy2nx_led_get,
- .put = snd_audigy2nx_led_put,
- .private_value = 1,
- },
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Dolby Digital LED Switch",
- .info = snd_audigy2nx_led_info,
- .get = snd_audigy2nx_led_get,
- .put = snd_audigy2nx_led_put,
- .private_value = 2,
- },
+static int snd_audigy2nx_led_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_interface *mixer = list->mixer;
+ int index = kcontrol->private_value & 0xff;
+ int value = ucontrol->value.integer.value[0];
+ int old_value = kcontrol->private_value >> 8;
+ int err;
+
+ if (value > 1)
+ return -EINVAL;
+ if (value == old_value)
+ return 0;
+ kcontrol->private_value = (value << 8) | index;
+ err = snd_audigy2nx_led_update(mixer, value, index);
+ return err < 0 ? err : 1;
+}
+
+static int snd_audigy2nx_led_resume(struct usb_mixer_elem_list *list)
+{
+ int priv_value = list->kctl->private_value;
+
+ return snd_audigy2nx_led_update(list->mixer, priv_value >> 8,
+ priv_value & 0xff);
+}
+
+/* name and private_value are set dynamically */
+static struct snd_kcontrol_new snd_audigy2nx_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .info = snd_audigy2nx_led_info,
+ .get = snd_audigy2nx_led_get,
+ .put = snd_audigy2nx_led_put,
+};
+
+static const char * const snd_audigy2nx_led_names[] = {
+ "CMSS LED Switch",
+ "Power LED Switch",
+ "Dolby Digital LED Switch",
};
static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
{
int i, err;
- for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_controls); ++i) {
+ for (i = 0; i < ARRAY_SIZE(snd_audigy2nx_led_names); ++i) {
+ struct snd_kcontrol_new knew;
+
/* USB X-Fi S51 doesn't have a CMSS LED */
if ((mixer->chip->usb_id == USB_ID(0x041e, 0x3042)) && i == 0)
continue;
@@ -373,12 +393,16 @@ static int snd_audigy2nx_controls_create(struct usb_mixer_interface *mixer)
mixer->chip->usb_id == USB_ID(0x041e, 0x30df) ||
mixer->chip->usb_id == USB_ID(0x041e, 0x3048)))
break;
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_audigy2nx_controls[i], mixer));
+
+ knew = snd_audigy2nx_control;
+ knew.name = snd_audigy2nx_led_names[i];
+ knew.private_value = (1 << 8) | i; /* LED on as default */
+ err = add_single_ctl_with_resume(mixer, 0,
+ snd_audigy2nx_led_resume,
+ &knew, NULL);
if (err < 0)
return err;
}
- mixer->audigy2nx_leds[1] = 1; /* Power LED is on by default */
return 0;
}
@@ -437,19 +461,9 @@ static void snd_audigy2nx_proc_read(struct snd_info_entry *entry,
static int snd_emu0204_ch_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[2] = {"1/2",
- "3/4"
- };
+ static const char * const texts[2] = {"1/2", "3/4"};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 2;
- if (uinfo->value.enumerated.item > 1)
- uinfo->value.enumerated.item = 1;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
@@ -459,100 +473,122 @@ static int snd_emu0204_ch_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_emu0204_ch_switch_update(struct usb_mixer_interface *mixer,
+ int value)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- unsigned int value = ucontrol->value.enumerated.item[0];
- int err, changed;
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
unsigned char buf[2];
- if (value > 1)
- return -EINVAL;
-
- buf[0] = 0x01;
- buf[1] = value ? 0x02 : 0x01;
-
- changed = value != kcontrol->private_value;
- down_read(&mixer->chip->shutdown_rwsem);
+ down_read(&chip->shutdown_rwsem);
if (mixer->chip->shutdown) {
err = -ENODEV;
goto out;
}
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), UAC_SET_CUR,
+
+ buf[0] = 0x01;
+ buf[1] = value ? 0x02 : 0x01;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
0x0400, 0x0e00, buf, 2);
out:
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
+static int snd_emu0204_ch_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_interface *mixer = list->mixer;
+ unsigned int value = ucontrol->value.enumerated.item[0];
+ int err;
+
+ if (value > 1)
+ return -EINVAL;
+
+ if (value == kcontrol->private_value)
+ return 0;
+
kcontrol->private_value = value;
- return changed;
+ err = snd_emu0204_ch_switch_update(mixer, value);
+ return err < 0 ? err : 1;
}
+static int snd_emu0204_ch_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_emu0204_ch_switch_update(list->mixer,
+ list->kctl->private_value);
+}
-static struct snd_kcontrol_new snd_emu0204_controls[] = {
- {
- .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
- .name = "Front Jack Channels",
- .info = snd_emu0204_ch_switch_info,
- .get = snd_emu0204_ch_switch_get,
- .put = snd_emu0204_ch_switch_put,
- .private_value = 0,
- },
+static struct snd_kcontrol_new snd_emu0204_control = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Front Jack Channels",
+ .info = snd_emu0204_ch_switch_info,
+ .get = snd_emu0204_ch_switch_get,
+ .put = snd_emu0204_ch_switch_put,
+ .private_value = 0,
};
static int snd_emu0204_controls_create(struct usb_mixer_interface *mixer)
{
- int i, err;
-
- for (i = 0; i < ARRAY_SIZE(snd_emu0204_controls); ++i) {
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_emu0204_controls[i], mixer));
- if (err < 0)
- return err;
- }
-
- return 0;
+ return add_single_ctl_with_resume(mixer, 0,
+ snd_emu0204_ch_switch_resume,
+ &snd_emu0204_control, NULL);
}
+
/* ASUS Xonar U1 / U3 controls */
static int snd_xonar_u1_switch_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
-
- ucontrol->value.integer.value[0] = !!(mixer->xonar_u1_status & 0x02);
+ ucontrol->value.integer.value[0] = !!(kcontrol->private_value & 0x02);
return 0;
}
+static int snd_xonar_u1_switch_update(struct usb_mixer_interface *mixer,
+ unsigned char status)
+{
+ struct snd_usb_audio *chip = mixer->chip;
+ int err;
+
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
+ err = -ENODEV;
+ else
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x08,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
+ 50, 0, &status, 1);
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
static int snd_xonar_u1_switch_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
u8 old_status, new_status;
- int err, changed;
+ int err;
- old_status = mixer->xonar_u1_status;
+ old_status = kcontrol->private_value;
if (ucontrol->value.integer.value[0])
new_status = old_status | 0x02;
else
new_status = old_status & ~0x02;
- changed = new_status != old_status;
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- err = -ENODEV;
- else
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0), 0x08,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
- 50, 0, &new_status, 1);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
- mixer->xonar_u1_status = new_status;
- return changed;
+ if (new_status == old_status)
+ return 0;
+
+ kcontrol->private_value = new_status;
+ err = snd_xonar_u1_switch_update(list->mixer, new_status);
+ return err < 0 ? err : 1;
+}
+
+static int snd_xonar_u1_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_xonar_u1_switch_update(list->mixer,
+ list->kctl->private_value);
}
static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
@@ -561,82 +597,213 @@ static struct snd_kcontrol_new snd_xonar_u1_output_switch = {
.info = snd_ctl_boolean_mono_info,
.get = snd_xonar_u1_switch_get,
.put = snd_xonar_u1_switch_put,
+ .private_value = 0x05,
};
static int snd_xonar_u1_controls_create(struct usb_mixer_interface *mixer)
{
+ return add_single_ctl_with_resume(mixer, 0,
+ snd_xonar_u1_switch_resume,
+ &snd_xonar_u1_output_switch, NULL);
+}
+
+/* Digidesign Mbox 1 clock source switch (internal/spdif) */
+
+static int snd_mbox1_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = kctl->private_value;
+ return 0;
+}
+
+static int snd_mbox1_switch_update(struct usb_mixer_interface *mixer, int val)
+{
+ struct snd_usb_audio *chip = mixer->chip;
int err;
+ unsigned char buff[3];
+
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto err;
+ }
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_xonar_u1_output_switch, mixer));
+ /* Prepare for magic command to toggle clock source */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_INTERFACE, 0x00, 0x500, buff, 1);
if (err < 0)
- return err;
- mixer->xonar_u1_status = 0x05;
- return 0;
+ goto err;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ goto err;
+
+ /* 2 possibilities: Internal -> send sample rate
+ * S/PDIF sync -> send zeroes
+ * NB: Sample rate locked to 48kHz on purpose to
+ * prevent user from resetting the sample rate
+ * while S/PDIF sync is enabled and confusing
+ * this configuration.
+ */
+ if (val == 0) {
+ buff[0] = 0x80;
+ buff[1] = 0xbb;
+ buff[2] = 0x00;
+ } else {
+ buff[0] = buff[1] = buff[2] = 0x00;
+ }
+
+ /* Send the magic command to toggle the clock source */
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0), 0x1,
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ goto err;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x81, buff, 3);
+ if (err < 0)
+ goto err;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0), 0x81,
+ USB_DIR_IN |
+ USB_TYPE_CLASS |
+ USB_RECIP_ENDPOINT, 0x100, 0x2, buff, 3);
+ if (err < 0)
+ goto err;
+
+err:
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
+static int snd_mbox1_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+ struct usb_mixer_interface *mixer = list->mixer;
+ int err;
+ bool cur_val, new_val;
+
+ cur_val = kctl->private_value;
+ new_val = ucontrol->value.enumerated.item[0];
+ if (cur_val == new_val)
+ return 0;
+
+ kctl->private_value = new_val;
+ err = snd_mbox1_switch_update(mixer, new_val);
+ return err < 0 ? err : 1;
+}
+
+static int snd_mbox1_switch_info(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_info *uinfo)
+{
+ static const char *const texts[2] = {
+ "Internal",
+ "S/PDIF"
+ };
+
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
+}
+
+static int snd_mbox1_switch_resume(struct usb_mixer_elem_list *list)
+{
+ return snd_mbox1_switch_update(list->mixer, list->kctl->private_value);
+}
+
+static struct snd_kcontrol_new snd_mbox1_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "Clock Source",
+ .index = 0,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE,
+ .info = snd_mbox1_switch_info,
+ .get = snd_mbox1_switch_get,
+ .put = snd_mbox1_switch_put,
+ .private_value = 0
+};
+
+static int snd_mbox1_create_sync_switch(struct usb_mixer_interface *mixer)
+{
+ return add_single_ctl_with_resume(mixer, 0,
+ snd_mbox1_switch_resume,
+ &snd_mbox1_switch, NULL);
}
/* Native Instruments device quirks */
#define _MAKE_NI_CONTROL(bRequest,wIndex) ((bRequest) << 16 | (wIndex))
-static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_ni_control_init_val(struct usb_mixer_interface *mixer,
+ struct snd_kcontrol *kctl)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
struct usb_device *dev = mixer->chip->dev;
- u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
- u16 wIndex = kcontrol->private_value & 0xffff;
- u8 tmp;
- int ret;
-
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- ret = -ENODEV;
- else
- ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), bRequest,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
- 0, wIndex,
- &tmp, sizeof(tmp));
- up_read(&mixer->chip->shutdown_rwsem);
+ unsigned int pval = kctl->private_value;
+ u8 value;
+ int err;
- if (ret < 0) {
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0),
+ (pval >> 16) & 0xff,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_IN,
+ 0, pval & 0xffff, &value, 1);
+ if (err < 0) {
dev_err(&dev->dev,
- "unable to issue vendor read request (ret = %d)", ret);
- return ret;
+ "unable to issue vendor read request (ret = %d)", err);
+ return err;
}
- ucontrol->value.integer.value[0] = tmp;
+ kctl->private_value |= (value << 24);
+ return 0;
+}
+static int snd_nativeinstruments_control_get(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.integer.value[0] = kcontrol->private_value >> 24;
return 0;
}
+static int snd_ni_update_cur_val(struct usb_mixer_elem_list *list)
+{
+ struct snd_usb_audio *chip = list->mixer->chip;
+ unsigned int pval = list->kctl->private_value;
+ int err;
+
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
+ err = -ENODEV;
+ else
+ err = usb_control_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0),
+ (pval >> 16) & 0xff,
+ USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
+ pval >> 24, pval & 0xffff, NULL, 0, 1000);
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
static int snd_nativeinstruments_control_put(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- struct usb_device *dev = mixer->chip->dev;
- u8 bRequest = (kcontrol->private_value >> 16) & 0xff;
- u16 wIndex = kcontrol->private_value & 0xffff;
- u16 wValue = ucontrol->value.integer.value[0];
- int ret;
-
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- ret = -ENODEV;
- else
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), bRequest,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE | USB_DIR_OUT,
- wValue, wIndex,
- NULL, 0, 1000);
- up_read(&mixer->chip->shutdown_rwsem);
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ u8 oldval = (kcontrol->private_value >> 24) & 0xff;
+ u8 newval = ucontrol->value.integer.value[0];
+ int err;
- if (ret < 0) {
- dev_err(&dev->dev,
- "unable to issue vendor write request (ret = %d)", ret);
- return ret;
- }
+ if (oldval == newval)
+ return 0;
- return 0;
+ kcontrol->private_value &= ~(0xff << 24);
+ kcontrol->private_value |= newval;
+ err = snd_ni_update_cur_val(list);
+ return err < 0 ? err : 1;
}
static struct snd_kcontrol_new snd_nativeinstruments_ta6_mixers[] = {
@@ -707,16 +874,17 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
};
for (i = 0; i < count; i++) {
- struct snd_kcontrol *c;
+ struct usb_mixer_elem_list *list;
template.name = kc[i].name;
template.private_value = kc[i].private_value;
- c = snd_ctl_new1(&template, mixer);
- err = snd_ctl_add(mixer->chip->card, c);
-
+ err = add_single_ctl_with_resume(mixer, 0,
+ snd_ni_update_cur_val,
+ &template, &list);
if (err < 0)
break;
+ snd_ni_control_init_val(mixer, list->kctl);
}
return err;
@@ -724,170 +892,88 @@ static int snd_nativeinstruments_create_mixer(struct usb_mixer_interface *mixer,
/* M-Audio FastTrack Ultra quirks */
/* FTU Effect switch (also used by C400/C600) */
-struct snd_ftu_eff_switch_priv_val {
- struct usb_mixer_interface *mixer;
- int cached_value;
- int is_cached;
- int bUnitID;
- int validx;
-};
-
static int snd_ftu_eff_switch_info(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_info *uinfo)
{
- static const char *texts[8] = {"Room 1",
- "Room 2",
- "Room 3",
- "Hall 1",
- "Hall 2",
- "Plate",
- "Delay",
- "Echo"
+ static const char *const texts[8] = {
+ "Room 1", "Room 2", "Room 3", "Hall 1",
+ "Hall 2", "Plate", "Delay", "Echo"
};
- uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
- uinfo->count = 1;
- uinfo->value.enumerated.items = 8;
- if (uinfo->value.enumerated.item > 7)
- uinfo->value.enumerated.item = 7;
- strcpy(uinfo->value.enumerated.name,
- texts[uinfo->value.enumerated.item]);
-
- return 0;
+ return snd_ctl_enum_info(uinfo, 1, ARRAY_SIZE(texts), texts);
}
-static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_ftu_eff_switch_init(struct usb_mixer_interface *mixer,
+ struct snd_kcontrol *kctl)
{
- struct snd_usb_audio *chip;
- struct usb_mixer_interface *mixer;
- struct snd_ftu_eff_switch_priv_val *pval;
+ struct usb_device *dev = mixer->chip->dev;
+ unsigned int pval = kctl->private_value;
int err;
unsigned char value[2];
- int id, validx;
-
- const int val_len = 2;
value[0] = 0x00;
value[1] = 0x00;
- pval = (struct snd_ftu_eff_switch_priv_val *)
- kctl->private_value;
+ err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
+ pval & 0xff00,
+ snd_usb_ctrl_intf(mixer->chip) | ((pval & 0xff) << 8),
+ value, 2);
+ if (err < 0)
+ return err;
- if (pval->is_cached) {
- ucontrol->value.enumerated.item[0] = pval->cached_value;
- return 0;
- }
+ kctl->private_value |= value[0] << 24;
+ return 0;
+}
- mixer = (struct usb_mixer_interface *) pval->mixer;
- if (snd_BUG_ON(!mixer))
- return -EINVAL;
+static int snd_ftu_eff_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ ucontrol->value.enumerated.item[0] = kctl->private_value >> 24;
+ return 0;
+}
- chip = (struct snd_usb_audio *) mixer->chip;
- if (snd_BUG_ON(!chip))
- return -EINVAL;
+static int snd_ftu_eff_switch_update(struct usb_mixer_elem_list *list)
+{
+ struct snd_usb_audio *chip = list->mixer->chip;
+ unsigned int pval = list->kctl->private_value;
+ unsigned char value[2];
+ int err;
- id = pval->bUnitID;
- validx = pval->validx;
+ value[0] = pval >> 24;
+ value[1] = 0;
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown)
err = -ENODEV;
else
err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
- value, val_len);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
-
- ucontrol->value.enumerated.item[0] = value[0];
- pval->cached_value = value[0];
- pval->is_cached = 1;
-
- return 0;
+ usb_sndctrlpipe(chip->dev, 0),
+ UAC_SET_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
+ pval & 0xff00,
+ snd_usb_ctrl_intf(chip) | ((pval & 0xff) << 8),
+ value, 2);
+ up_read(&chip->shutdown_rwsem);
+ return err;
}
static int snd_ftu_eff_switch_put(struct snd_kcontrol *kctl,
struct snd_ctl_elem_value *ucontrol)
{
- struct snd_usb_audio *chip;
- struct snd_ftu_eff_switch_priv_val *pval;
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kctl);
+ unsigned int pval = list->kctl->private_value;
+ int cur_val, err, new_val;
- struct usb_mixer_interface *mixer;
- int changed, cur_val, err, new_val;
- unsigned char value[2];
- int id, validx;
-
- const int val_len = 2;
-
- changed = 0;
-
- pval = (struct snd_ftu_eff_switch_priv_val *)
- kctl->private_value;
- cur_val = pval->cached_value;
+ cur_val = pval >> 24;
new_val = ucontrol->value.enumerated.item[0];
+ if (cur_val == new_val)
+ return 0;
- mixer = (struct usb_mixer_interface *) pval->mixer;
- if (snd_BUG_ON(!mixer))
- return -EINVAL;
-
- chip = (struct snd_usb_audio *) mixer->chip;
- if (snd_BUG_ON(!chip))
- return -EINVAL;
-
- id = pval->bUnitID;
- validx = pval->validx;
-
- if (!pval->is_cached) {
- /* Read current value */
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- err = -ENODEV;
- else
- err = snd_usb_ctl_msg(chip->dev,
- usb_rcvctrlpipe(chip->dev, 0), UAC_GET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN,
- validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
- value, val_len);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
-
- cur_val = value[0];
- pval->cached_value = cur_val;
- pval->is_cached = 1;
- }
- /* update value if needed */
- if (cur_val != new_val) {
- value[0] = new_val;
- value[1] = 0;
- down_read(&mixer->chip->shutdown_rwsem);
- if (mixer->chip->shutdown)
- err = -ENODEV;
- else
- err = snd_usb_ctl_msg(chip->dev,
- usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR,
- USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT,
- validx << 8, snd_usb_ctrl_intf(chip) | (id << 8),
- value, val_len);
- up_read(&mixer->chip->shutdown_rwsem);
- if (err < 0)
- return err;
-
- pval->cached_value = new_val;
- pval->is_cached = 1;
- changed = 1;
- }
-
- return changed;
-}
-
-static void kctl_private_value_free(struct snd_kcontrol *kctl)
-{
- kfree((void *)kctl->private_value);
+ kctl->private_value &= ~(0xff << 24);
+ kctl->private_value |= new_val << 24;
+ err = snd_ftu_eff_switch_update(list);
+ return err < 0 ? err : 1;
}
static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
@@ -902,33 +988,16 @@ static int snd_ftu_create_effect_switch(struct usb_mixer_interface *mixer,
.get = snd_ftu_eff_switch_get,
.put = snd_ftu_eff_switch_put
};
-
+ struct usb_mixer_elem_list *list;
int err;
- struct snd_kcontrol *kctl;
- struct snd_ftu_eff_switch_priv_val *pval;
-
- pval = kzalloc(sizeof(*pval), GFP_KERNEL);
- if (!pval)
- return -ENOMEM;
-
- pval->cached_value = 0;
- pval->is_cached = 0;
- pval->mixer = mixer;
- pval->bUnitID = bUnitID;
- pval->validx = validx;
-
- template.private_value = (unsigned long) pval;
- kctl = snd_ctl_new1(&template, mixer->chip);
- if (!kctl) {
- kfree(pval);
- return -ENOMEM;
- }
- kctl->private_free = kctl_private_value_free;
- err = snd_ctl_add(mixer->chip->card, kctl);
+ err = add_single_ctl_with_resume(mixer, bUnitID,
+ snd_ftu_eff_switch_update,
+ &template, &list);
if (err < 0)
return err;
-
+ list->kctl->private_value = (validx << 8) | bUnitID;
+ snd_ftu_eff_switch_init(mixer, list->kctl);
return 0;
}
@@ -1110,7 +1179,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip,
int unitid = 12; /* SamleRate ExtensionUnit ID */
list_for_each_entry(mixer, &chip->mixer_list, list) {
- cval = mixer->id_elems[unitid];
+ cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid];
if (cval) {
snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR,
cval->control << 8,
@@ -1440,7 +1509,8 @@ static int snd_microii_spdif_info(struct snd_kcontrol *kcontrol,
static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
struct snd_ctl_elem_value *ucontrol)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ struct snd_usb_audio *chip = list->mixer->chip;
int err;
struct usb_interface *iface;
struct usb_host_interface *alts;
@@ -1448,17 +1518,23 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
unsigned char data[3];
int rate;
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto end;
+ }
+
ucontrol->value.iec958.status[0] = kcontrol->private_value & 0xff;
ucontrol->value.iec958.status[1] = (kcontrol->private_value >> 8) & 0xff;
ucontrol->value.iec958.status[2] = 0x00;
/* use known values for that card: interface#1 altsetting#1 */
- iface = usb_ifnum_to_if(mixer->chip->dev, 1);
+ iface = usb_ifnum_to_if(chip->dev, 1);
alts = &iface->altsetting[1];
ep = get_endpoint(alts, 0)->bEndpointAddress;
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_rcvctrlpipe(mixer->chip->dev, 0),
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
UAC_GET_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN,
UAC_EP_CS_ATTR_SAMPLE_RATE << 8,
@@ -1473,22 +1549,27 @@ static int snd_microii_spdif_default_get(struct snd_kcontrol *kcontrol,
IEC958_AES3_CON_FS_48000 : IEC958_AES3_CON_FS_44100;
err = 0;
-end:
+ end:
+ up_read(&chip->shutdown_rwsem);
return err;
}
-static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_microii_spdif_default_update(struct usb_mixer_elem_list *list)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
- int err;
+ struct snd_usb_audio *chip = list->mixer->chip;
+ unsigned int pval = list->kctl->private_value;
u8 reg;
- unsigned long priv_backup = kcontrol->private_value;
+ int err;
- reg = ((ucontrol->value.iec958.status[1] & 0x0f) << 4) |
- (ucontrol->value.iec958.status[0] & 0x0f);
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0),
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ reg = ((pval >> 4) & 0xf0) | (pval & 0x0f);
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
reg,
@@ -1498,15 +1579,10 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
if (err < 0)
goto end;
- kcontrol->private_value &= 0xfffff0f0;
- kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
- kcontrol->private_value |= (ucontrol->value.iec958.status[0] & 0x0f);
-
- reg = (ucontrol->value.iec958.status[0] & IEC958_AES0_NONAUDIO) ?
- 0xa0 : 0x20;
- reg |= (ucontrol->value.iec958.status[1] >> 4) & 0x0f;
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0),
+ reg = (pval & IEC958_AES0_NONAUDIO) ? 0xa0 : 0x20;
+ reg |= (pval >> 12) & 0x0f;
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
reg,
@@ -1516,16 +1592,36 @@ static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
if (err < 0)
goto end;
- kcontrol->private_value &= 0xffff0fff;
- kcontrol->private_value |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
+ end:
+ up_read(&chip->shutdown_rwsem);
+ return err;
+}
+
+static int snd_microii_spdif_default_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ unsigned int pval, pval_old;
+ int err;
+
+ pval = pval_old = kcontrol->private_value;
+ pval &= 0xfffff0f0;
+ pval |= (ucontrol->value.iec958.status[1] & 0x0f) << 8;
+ pval |= (ucontrol->value.iec958.status[0] & 0x0f);
+
+ pval &= 0xffff0fff;
+ pval |= (ucontrol->value.iec958.status[1] & 0xf0) << 8;
/* The frequency bits in AES3 cannot be set via register access. */
/* Silently ignore any bits from the request that cannot be set. */
- err = (priv_backup != kcontrol->private_value);
-end:
- return err;
+ if (pval == pval_old)
+ return 0;
+
+ kcontrol->private_value = pval;
+ err = snd_microii_spdif_default_update(list);
+ return err < 0 ? err : 1;
}
static int snd_microii_spdif_mask_get(struct snd_kcontrol *kcontrol,
@@ -1547,15 +1643,20 @@ static int snd_microii_spdif_switch_get(struct snd_kcontrol *kcontrol,
return 0;
}
-static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
- struct snd_ctl_elem_value *ucontrol)
+static int snd_microii_spdif_switch_update(struct usb_mixer_elem_list *list)
{
- struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol);
+ struct snd_usb_audio *chip = list->mixer->chip;
+ u8 reg = list->kctl->private_value;
int err;
- u8 reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
- err = snd_usb_ctl_msg(mixer->chip->dev,
- usb_sndctrlpipe(mixer->chip->dev, 0),
+ down_read(&chip->shutdown_rwsem);
+ if (chip->shutdown) {
+ err = -ENODEV;
+ goto end;
+ }
+
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_sndctrlpipe(chip->dev, 0),
UAC_SET_CUR,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_OTHER,
reg,
@@ -1563,15 +1664,27 @@ static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
NULL,
0);
- if (!err) {
- err = (reg != (kcontrol->private_value & 0x0ff));
- if (err)
- kcontrol->private_value = reg;
- }
-
+ end:
+ up_read(&chip->shutdown_rwsem);
return err;
}
+static int snd_microii_spdif_switch_put(struct snd_kcontrol *kcontrol,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_list *list = snd_kcontrol_chip(kcontrol);
+ u8 reg;
+ int err;
+
+ reg = ucontrol->value.integer.value[0] ? 0x28 : 0x2a;
+ if (reg != list->kctl->private_value)
+ return 0;
+
+ kcontrol->private_value = reg;
+ err = snd_microii_spdif_switch_update(list);
+ return err < 0 ? err : 1;
+}
+
static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
{
.iface = SNDRV_CTL_ELEM_IFACE_PCM,
@@ -1601,10 +1714,17 @@ static struct snd_kcontrol_new snd_microii_mixer_spdif[] = {
static int snd_microii_controls_create(struct usb_mixer_interface *mixer)
{
int err, i;
+ static usb_mixer_elem_resume_func_t resume_funcs[] = {
+ snd_microii_spdif_default_update,
+ NULL,
+ snd_microii_spdif_switch_update
+ };
for (i = 0; i < ARRAY_SIZE(snd_microii_mixer_spdif); ++i) {
- err = snd_ctl_add(mixer->chip->card,
- snd_ctl_new1(&snd_microii_mixer_spdif[i], mixer));
+ err = add_single_ctl_with_resume(mixer, 0,
+ resume_funcs[i],
+ &snd_microii_mixer_spdif[i],
+ NULL);
if (err < 0)
return err;
}
@@ -1661,6 +1781,10 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
err = snd_microii_controls_create(mixer);
break;
+ case USB_ID(0x0dba, 0x1000): /* Digidesign Mbox 1 */
+ err = snd_mbox1_create_sync_switch(mixer);
+ break;
+
case USB_ID(0x17cc, 0x1011): /* Traktor Audio 6 */
err = snd_nativeinstruments_create_mixer(mixer,
snd_nativeinstruments_ta6_mixers,
@@ -1677,6 +1801,14 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer)
/* detection is disabled in mixer_maps.c */
err = snd_create_std_mono_table(mixer, ebox44_table);
break;
+
+ case USB_ID(0x1235, 0x8012): /* Focusrite Scarlett 6i6 */
+ case USB_ID(0x1235, 0x8002): /* Focusrite Scarlett 8i6 */
+ case USB_ID(0x1235, 0x8004): /* Focusrite Scarlett 18i6 */
+ case USB_ID(0x1235, 0x8014): /* Focusrite Scarlett 18i8 */
+ case USB_ID(0x1235, 0x800c): /* Focusrite Scarlett 18i20 */
+ err = snd_scarlett_controls_create(mixer);
+ break;
}
return err;
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c
new file mode 100644
index 0000000..9109652
--- /dev/null
+++ b/sound/usb/mixer_scarlett.c
@@ -0,0 +1,1004 @@
+/*
+ * Scarlett Driver for ALSA
+ *
+ * Copyright (c) 2013 by Tobias Hoffmann
+ * Copyright (c) 2013 by Robin Gareus <robin at gareus.org>
+ * Copyright (c) 2002 by Takashi Iwai <tiwai at suse.de>
+ * Copyright (c) 2014 by Chris J Arges <chris.j.arges at canonical.com>
+ *
+ * Many codes borrowed from audio.c by
+ * Alan Cox (alan at lxorguk.ukuu.org.uk)
+ * Thomas Sailer (sailer at ife.ee.ethz.ch)
+ *
+ * Code cleanup:
+ * David Henningsson <david.henningsson at canonical.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.
+ *
+ */
+
+/*
+ * Rewritten and extended to support more models, e.g. Scarlett 18i8.
+ *
+ * Auto-detection via UAC2 is not feasible to properly discover the vast
+ * majority of features. It's related to both Linux/ALSA's UAC2 as well as
+ * Focusrite's implementation of it. Eventually quirks may be sufficient but
+ * right now it's a major headache to work arount these things.
+ *
+ * NB. Neither the OSX nor the win driver provided by Focusrite performs
+ * discovery, they seem to operate the same as this driver.
+ */
+
+/* Mixer Interface for the Focusrite Scarlett 18i6 audio interface.
+ *
+ * The protocol was reverse engineered by looking at communication between
+ * Scarlett MixControl (v 1.2.128.0) and the Focusrite(R) Scarlett 18i6
+ * (firmware v305) using wireshark and usbmon in January 2013.
+ * Extended in July 2013.
+ *
+ * this mixer gives complete access to all features of the device:
+ * - change Impedance of inputs (Line-in, Mic / Instrument, Hi-Z)
+ * - select clock source
+ * - dynamic input to mixer-matrix assignment
+ * - 18 x 6 mixer-matrix gain stages
+ * - bus routing & volume control
+ * - automatic re-initialization on connect if device was power-cycled
+ *
+ * USB URB commands overview (bRequest = 0x01 = UAC2_CS_CUR)
+ * wIndex
+ * 0x01 Analog Input line/instrument impedance switch, wValue=0x0901 +
+ * channel, data=Line/Inst (2bytes)
+ * pad (-10dB) switch, wValue=0x0b01 + channel, data=Off/On (2bytes)
+ * ?? wValue=0x0803/04, ?? (2bytes)
+ * 0x0a Master Volume, wValue=0x0200+bus[0:all + only 1..4?] data(2bytes)
+ * Bus Mute/Unmute wValue=0x0100+bus[0:all + only 1..4?], data(2bytes)
+ * 0x28 Clock source, wValue=0x0100, data={1:int,2:spdif,3:adat} (1byte)
+ * 0x29 Set Sample-rate, wValue=0x0100, data=sample-rate(4bytes)
+ * 0x32 Mixer mux, wValue=0x0600 + mixer-channel, data=input-to-connect(2bytes)
+ * 0x33 Output mux, wValue=bus, data=input-to-connect(2bytes)
+ * 0x34 Capture mux, wValue=0...18, data=input-to-connect(2bytes)
+ * 0x3c Matrix Mixer gains, wValue=mixer-node data=gain(2bytes)
+ * ?? [sometimes](4bytes, e.g 0x000003be 0x000003bf ...03ff)
+ *
+ * USB reads: (i.e. actually issued by original software)
+ * 0x01 wValue=0x0901+channel (1byte!!), wValue=0x0b01+channed (1byte!!)
+ * 0x29 wValue=0x0100 sample-rate(4bytes)
+ * wValue=0x0200 ?? 1byte (only once)
+ * 0x2a wValue=0x0100 ?? 4bytes, sample-rate2 ??
+ *
+ * USB reads with bRequest = 0x03 = UAC2_CS_MEM
+ * 0x3c wValue=0x0002 1byte: sync status (locked=1)
+ * wValue=0x0000 18*2byte: peak meter (inputs)
+ * wValue=0x0001 8(?)*2byte: peak meter (mix)
+ * wValue=0x0003 6*2byte: peak meter (pcm/daw)
+ *
+ * USB write with bRequest = 0x03
+ * 0x3c Save settings to hardware: wValue=0x005a, data=0xa5
+ *
+ *
+ * <ditaa>
+ * /--------------\ 18chn 6chn /--------------\
+ * | Hardware in +--+-------\ /------+--+ ALSA PCM out |
+ * \--------------/ | | | | \--------------/
+ * | | | |
+ * | v v |
+ * | +---------------+ |
+ * | \ Matrix Mux / |
+ * | +-----+-----+ |
+ * | | |
+ * | | 18chn |
+ * | v |
+ * | +-----------+ |
+ * | | Mixer | |
+ * | | Matrix | |
+ * | | | |
+ * | | 18x6 Gain | |
+ * | | stages | |
+ * | +-----+-----+ |
+ * | | |
+ * | | |
+ * | 18chn | 6chn | 6chn
+ * v v v
+ * =========================
+ * +---------------+ +--—------------+
+ * \ Output Mux / \ Capture Mux /
+ * +-----+-----+ +-----+-----+
+ * | |
+ * | 6chn |
+ * v |
+ * +-------------+ |
+ * | Master Gain | |
+ * +------+------+ |
+ * | |
+ * | 6chn | 18chn
+ * | (3 stereo pairs) |
+ * /--------------\ | | /--------------\
+ * | Hardware out |<--/ \-->| ALSA PCM in |
+ * \--------------/ \--------------/
+ * </ditaa>
+ *
+ */
+
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/audio-v2.h>
+
+#include <sound/core.h>
+#include <sound/control.h>
+#include <sound/tlv.h>
+
+#include "usbaudio.h"
+#include "mixer.h"
+#include "helper.h"
+#include "power.h"
+
+#include "mixer_scarlett.h"
+
+/* some gui mixers can't handle negative ctl values */
+#define SND_SCARLETT_LEVEL_BIAS 128
+#define SND_SCARLETT_MATRIX_IN_MAX 18
+#define SND_SCARLETT_CONTROLS_MAX 10
+#define SND_SCARLETT_OFFSETS_MAX 5
+
+enum {
+ SCARLETT_OUTPUTS,
+ SCARLETT_SWITCH_IMPEDANCE,
+ SCARLETT_SWITCH_PAD,
+};
+
+enum {
+ SCARLETT_OFFSET_PCM = 0,
+ SCARLETT_OFFSET_ANALOG = 1,
+ SCARLETT_OFFSET_SPDIF = 2,
+ SCARLETT_OFFSET_ADAT = 3,
+ SCARLETT_OFFSET_MIX = 4,
+};
+
+struct scarlett_mixer_elem_enum_info {
+ int start;
+ int len;
+ int offsets[SND_SCARLETT_OFFSETS_MAX];
+ char const * const *names;
+};
+
+struct scarlett_mixer_control {
+ unsigned char num;
+ unsigned char type;
+ const char *name;
+};
+
+struct scarlett_device_info {
+ int matrix_in;
+ int matrix_out;
+ int input_len;
+ int output_len;
+
+ struct scarlett_mixer_elem_enum_info opt_master;
+ struct scarlett_mixer_elem_enum_info opt_matrix;
+
+ /* initial values for matrix mux */
+ int matrix_mux_init[SND_SCARLETT_MATRIX_IN_MAX];
+
+ int num_controls; /* number of items in controls */
+ const struct scarlett_mixer_control controls[SND_SCARLETT_CONTROLS_MAX];
+};
+
+/********************** Enum Strings *************************/
+
+static const struct scarlett_mixer_elem_enum_info opt_pad = {
+ .start = 0,
+ .len = 2,
+ .offsets = {},
+ .names = (char const * const []){
+ "0dB", "-10dB"
+ }
+};
+
+static const struct scarlett_mixer_elem_enum_info opt_impedance = {
+ .start = 0,
+ .len = 2,
+ .offsets = {},
+ .names = (char const * const []){
+ "Line", "Hi-Z"
+ }
+};
+
+static const struct scarlett_mixer_elem_enum_info opt_clock = {
+ .start = 1,
+ .len = 3,
+ .offsets = {},
+ .names = (char const * const []){
+ "Internal", "SPDIF", "ADAT"
+ }
+};
+
+static const struct scarlett_mixer_elem_enum_info opt_sync = {
+ .start = 0,
+ .len = 2,
+ .offsets = {},
+ .names = (char const * const []){
+ "No Lock", "Locked"
+ }
+};
+
+static int scarlett_ctl_switch_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_BOOLEAN;
+ uinfo->count = elem->channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = 1;
+ return 0;
+}
+
+static int scarlett_ctl_switch_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, err, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &val);
+ if (err < 0)
+ return err;
+
+ val = !val; /* invert mute logic for mixer */
+ ucontrol->value.integer.value[i] = val;
+ }
+
+ return 0;
+}
+
+static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, changed = 0;
+ int err, oval, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
+ if (err < 0)
+ return err;
+
+ val = ucontrol->value.integer.value[i];
+ val = !val;
+ if (oval != val) {
+ err = snd_usb_set_cur_mix_value(elem, i, i, val);
+ if (err < 0)
+ return err;
+
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+static int scarlett_ctl_resume(struct usb_mixer_elem_list *list)
+{
+ struct usb_mixer_elem_info *elem =
+ container_of(list, struct usb_mixer_elem_info, head);
+ int i;
+
+ for (i = 0; i < elem->channels; i++)
+ if (elem->cached & (1 << i))
+ snd_usb_set_cur_mix_value(elem, i, i,
+ elem->cache_val[i]);
+ return 0;
+}
+
+static int scarlett_ctl_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER;
+ uinfo->count = elem->channels;
+ uinfo->value.integer.min = 0;
+ uinfo->value.integer.max = (int)kctl->private_value +
+ SND_SCARLETT_LEVEL_BIAS;
+ uinfo->value.integer.step = 1;
+ return 0;
+}
+
+static int scarlett_ctl_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, err, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp(val / 256, -128, (int)kctl->private_value) +
+ SND_SCARLETT_LEVEL_BIAS;
+ ucontrol->value.integer.value[i] = val;
+ }
+
+ return 0;
+}
+
+static int scarlett_ctl_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ int i, changed = 0;
+ int err, oval, val;
+
+ for (i = 0; i < elem->channels; i++) {
+ err = snd_usb_get_cur_mix_value(elem, i, i, &oval);
+ if (err < 0)
+ return err;
+
+ val = ucontrol->value.integer.value[i] -
+ SND_SCARLETT_LEVEL_BIAS;
+ val = val * 256;
+ if (oval != val) {
+ err = snd_usb_set_cur_mix_value(elem, i, i, val);
+ if (err < 0)
+ return err;
+
+ changed = 1;
+ }
+ }
+
+ return changed;
+}
+
+static void scarlett_generate_name(int i, char *dst, int offsets[])
+{
+ if (i > offsets[SCARLETT_OFFSET_MIX])
+ sprintf(dst, "Mix %c",
+ 'A'+(i - offsets[SCARLETT_OFFSET_MIX] - 1));
+ else if (i > offsets[SCARLETT_OFFSET_ADAT])
+ sprintf(dst, "ADAT %d", i - offsets[SCARLETT_OFFSET_ADAT]);
+ else if (i > offsets[SCARLETT_OFFSET_SPDIF])
+ sprintf(dst, "SPDIF %d", i - offsets[SCARLETT_OFFSET_SPDIF]);
+ else if (i > offsets[SCARLETT_OFFSET_ANALOG])
+ sprintf(dst, "Analog %d", i - offsets[SCARLETT_OFFSET_ANALOG]);
+ else if (i > offsets[SCARLETT_OFFSET_PCM])
+ sprintf(dst, "PCM %d", i - offsets[SCARLETT_OFFSET_PCM]);
+ else
+ sprintf(dst, "Off");
+}
+
+static int scarlett_ctl_enum_dynamic_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+ unsigned int items = opt->len;
+
+ uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED;
+ uinfo->count = elem->channels;
+ uinfo->value.enumerated.items = items;
+
+ if (uinfo->value.enumerated.item >= items)
+ uinfo->value.enumerated.item = items - 1;
+
+ /* generate name dynamically based on item number and offset info */
+ scarlett_generate_name(uinfo->value.enumerated.item,
+ uinfo->value.enumerated.name,
+ opt->offsets);
+
+ return 0;
+}
+
+static int scarlett_ctl_enum_info(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_info *uinfo)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+
+ return snd_ctl_enum_info(uinfo, elem->channels, opt->len,
+ (const char * const *)opt->names);
+}
+
+static int scarlett_ctl_enum_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+ int err, val;
+
+ err = snd_usb_get_cur_mix_value(elem, 0, 0, &val);
+ if (err < 0)
+ return err;
+
+ val = clamp(val - opt->start, 0, opt->len-1);
+
+ ucontrol->value.enumerated.item[0] = val;
+
+ return 0;
+}
+
+static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct scarlett_mixer_elem_enum_info *opt = elem->private_data;
+ int err, oval, val;
+
+ err = snd_usb_get_cur_mix_value(elem, 0, 0, &oval);
+ if (err < 0)
+ return err;
+
+ val = ucontrol->value.integer.value[0];
+ val = val + opt->start;
+ if (val != oval) {
+ snd_usb_set_cur_mix_value(elem, 0, 0, val);
+ return 1;
+ }
+ return 0;
+}
+
+static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list)
+{
+ struct usb_mixer_elem_info *elem =
+ container_of(list, struct usb_mixer_elem_info, head);
+
+ if (elem->cached)
+ snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val);
+ return 0;
+}
+
+static int scarlett_ctl_meter_get(struct snd_kcontrol *kctl,
+ struct snd_ctl_elem_value *ucontrol)
+{
+ struct usb_mixer_elem_info *elem = kctl->private_data;
+ struct snd_usb_audio *chip = elem->head.mixer->chip;
+ unsigned char buf[2 * MAX_CHANNELS] = {0, };
+ int wValue = (elem->control << 8) | elem->idx_off;
+ int idx = snd_usb_ctrl_intf(chip) | (elem->head.id << 8);
+ int err;
+
+ err = snd_usb_ctl_msg(chip->dev,
+ usb_rcvctrlpipe(chip->dev, 0),
+ UAC2_CS_MEM,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS |
+ USB_DIR_IN, wValue, idx, buf, elem->channels);
+ if (err < 0)
+ return err;
+
+ ucontrol->value.enumerated.item[0] = clamp((int)buf[0], 0, 1);
+ return 0;
+}
+
+static struct snd_kcontrol_new usb_scarlett_ctl_switch = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "",
+ .info = scarlett_ctl_switch_info,
+ .get = scarlett_ctl_switch_get,
+ .put = scarlett_ctl_switch_put,
+};
+
+static const DECLARE_TLV_DB_SCALE(db_scale_scarlett_gain, -12800, 100, 0);
+
+static struct snd_kcontrol_new usb_scarlett_ctl = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .name = "",
+ .info = scarlett_ctl_info,
+ .get = scarlett_ctl_get,
+ .put = scarlett_ctl_put,
+ .private_value = 6, /* max value */
+ .tlv = { .p = db_scale_scarlett_gain }
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_master = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
+ SNDRV_CTL_ELEM_ACCESS_TLV_READ,
+ .name = "",
+ .info = scarlett_ctl_info,
+ .get = scarlett_ctl_get,
+ .put = scarlett_ctl_put,
+ .private_value = 6, /* max value */
+ .tlv = { .p = db_scale_scarlett_gain }
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "",
+ .info = scarlett_ctl_enum_info,
+ .get = scarlett_ctl_enum_get,
+ .put = scarlett_ctl_enum_put,
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_dynamic_enum = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .name = "",
+ .info = scarlett_ctl_enum_dynamic_info,
+ .get = scarlett_ctl_enum_get,
+ .put = scarlett_ctl_enum_put,
+};
+
+static struct snd_kcontrol_new usb_scarlett_ctl_sync = {
+ .iface = SNDRV_CTL_ELEM_IFACE_MIXER,
+ .access = SNDRV_CTL_ELEM_ACCESS_READ | SNDRV_CTL_ELEM_ACCESS_VOLATILE,
+ .name = "",
+ .info = scarlett_ctl_enum_info,
+ .get = scarlett_ctl_meter_get,
+};
+
+static int add_new_ctl(struct usb_mixer_interface *mixer,
+ const struct snd_kcontrol_new *ncontrol,
+ usb_mixer_elem_resume_func_t resume,
+ int index, int offset, int num,
+ int val_type, int channels, const char *name,
+ const struct scarlett_mixer_elem_enum_info *opt,
+ struct usb_mixer_elem_info **elem_ret
+)
+{
+ struct snd_kcontrol *kctl;
+ struct usb_mixer_elem_info *elem;
+ int err;
+
+ elem = kzalloc(sizeof(*elem), GFP_KERNEL);
+ if (!elem)
+ return -ENOMEM;
+
+ elem->head.mixer = mixer;
+ elem->head.resume = resume;
+ elem->control = offset;
+ elem->idx_off = num;
+ elem->head.id = index;
+ elem->val_type = val_type;
+
+ elem->channels = channels;
+
+ /* add scarlett_mixer_elem_enum_info struct */
+ elem->private_data = (void *)opt;
+
+ kctl = snd_ctl_new1(ncontrol, elem);
+ if (!kctl) {
+ kfree(elem);
+ return -ENOMEM;
+ }
+ kctl->private_free = snd_usb_mixer_elem_free;
+
+ strlcpy(kctl->id.name, name, sizeof(kctl->id.name));
+
+ err = snd_usb_mixer_add_control(&elem->head, kctl);
+ if (err < 0)
+ return err;
+
+ if (elem_ret)
+ *elem_ret = elem;
+
+ return 0;
+}
+
+static int add_output_ctls(struct usb_mixer_interface *mixer,
+ int index, const char *name,
+ const struct scarlett_device_info *info)
+{
+ int err;
+ char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ struct usb_mixer_elem_info *elem;
+
+ /* Add mute switch */
+ snprintf(mx, sizeof(mx), "Master %d (%s) Playback Switch",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
+ scarlett_ctl_resume, 0x0a, 0x01,
+ 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ /* Add volume control and initialize to 0 */
+ snprintf(mx, sizeof(mx), "Master %d (%s) Playback Volume",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
+ scarlett_ctl_resume, 0x0a, 0x02,
+ 2*index+1, USB_MIXER_S16, 2, mx, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ /* Add L channel source playback enumeration */
+ snprintf(mx, sizeof(mx), "Master %dL (%s) Source Playback Enum",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x33, 0x00,
+ 2*index, USB_MIXER_S16, 1, mx, &info->opt_master,
+ &elem);
+ if (err < 0)
+ return err;
+
+ /* Add R channel source playback enumeration */
+ snprintf(mx, sizeof(mx), "Master %dR (%s) Source Playback Enum",
+ index + 1, name);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x33, 0x00,
+ 2*index+1, USB_MIXER_S16, 1, mx, &info->opt_master,
+ &elem);
+ if (err < 0)
+ return err;
+
+ return 0;
+}
+
+/********************** device-specific config *************************/
+
+/* untested... */
+static struct scarlett_device_info s6i6_info = {
+ .matrix_in = 18,
+ .matrix_out = 8,
+ .input_len = 6,
+ .output_len = 6,
+
+ .opt_master = {
+ .start = -1,
+ .len = 27,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 19,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .num_controls = 0,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 12, 13, 14, 15, /* Analog -> 1..4 */
+ 16, 17, /* SPDIF -> 5,6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */
+ 8, 9, 10, 11
+ }
+};
+
+/* untested... */
+static struct scarlett_device_info s8i6_info = {
+ .matrix_in = 18,
+ .matrix_out = 6,
+ .input_len = 8,
+ .output_len = 6,
+
+ .opt_master = {
+ .start = -1,
+ .len = 25,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 19,
+ .offsets = {0, 12, 16, 18, 18},
+ .names = NULL
+ },
+
+ .num_controls = 7,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 12, 13, 14, 15, /* Analog -> 1..4 */
+ 16, 17, /* SPDIF -> 5,6 */
+ 0, 1, 2, 3, 4, 5, 6, 7, /* PCM[1..12] -> 7..18 */
+ 8, 9, 10, 11
+ }
+};
+
+static struct scarlett_device_info s18i6_info = {
+ .matrix_in = 18,
+ .matrix_out = 6,
+ .input_len = 18,
+ .output_len = 6,
+
+ .opt_master = {
+ .start = -1,
+ .len = 31,
+ .offsets = {0, 6, 14, 16, 24},
+ .names = NULL,
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 25,
+ .offsets = {0, 6, 14, 16, 24},
+ .names = NULL,
+ },
+
+ .num_controls = 5,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 6, 7, 8, 9, 10, 11, 12, 13, /* Analog -> 1..8 */
+ 16, 17, 18, 19, 20, 21, /* ADAT[1..6] -> 9..14 */
+ 14, 15, /* SPDIF -> 15,16 */
+ 0, 1 /* PCM[1,2] -> 17,18 */
+ }
+};
+
+static struct scarlett_device_info s18i8_info = {
+ .matrix_in = 18,
+ .matrix_out = 8,
+ .input_len = 18,
+ .output_len = 8,
+
+ .opt_master = {
+ .start = -1,
+ .len = 35,
+ .offsets = {0, 8, 16, 18, 26},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 27,
+ .offsets = {0, 8, 16, 18, 26},
+ .names = NULL
+ },
+
+ .num_controls = 10,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Headphone 1" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Headphone 2" },
+ { .num = 3, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ },
+
+ .matrix_mux_init = {
+ 8, 9, 10, 11, 12, 13, 14, 15, /* Analog -> 1..8 */
+ 18, 19, 20, 21, 22, 23, /* ADAT[1..6] -> 9..14 */
+ 16, 17, /* SPDIF -> 15,16 */
+ 0, 1 /* PCM[1,2] -> 17,18 */
+ }
+};
+
+static struct scarlett_device_info s18i20_info = {
+ .matrix_in = 18,
+ .matrix_out = 8,
+ .input_len = 18,
+ .output_len = 20,
+
+ .opt_master = {
+ .start = -1,
+ .len = 47,
+ .offsets = {0, 20, 28, 30, 38},
+ .names = NULL
+ },
+
+ .opt_matrix = {
+ .start = -1,
+ .len = 39,
+ .offsets = {0, 20, 28, 30, 38},
+ .names = NULL
+ },
+
+ .num_controls = 10,
+ .controls = {
+ { .num = 0, .type = SCARLETT_OUTPUTS, .name = "Monitor" },
+ { .num = 1, .type = SCARLETT_OUTPUTS, .name = "Line 3/4" },
+ { .num = 2, .type = SCARLETT_OUTPUTS, .name = "Line 5/6" },
+ { .num = 3, .type = SCARLETT_OUTPUTS, .name = "Line 7/8" },
+ { .num = 4, .type = SCARLETT_OUTPUTS, .name = "Line 9/10" },
+ { .num = 5, .type = SCARLETT_OUTPUTS, .name = "SPDIF" },
+ { .num = 6, .type = SCARLETT_OUTPUTS, .name = "ADAT 1/2" },
+ { .num = 7, .type = SCARLETT_OUTPUTS, .name = "ADAT 3/4" },
+ { .num = 8, .type = SCARLETT_OUTPUTS, .name = "ADAT 5/6" },
+ { .num = 9, .type = SCARLETT_OUTPUTS, .name = "ADAT 7/8" },
+ /*{ .num = 1, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 1, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_IMPEDANCE, .name = NULL},
+ { .num = 2, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 3, .type = SCARLETT_SWITCH_PAD, .name = NULL},
+ { .num = 4, .type = SCARLETT_SWITCH_PAD, .name = NULL},*/
+ },
+
+ .matrix_mux_init = {
+ 20, 21, 22, 23, 24, 25, 26, 27, /* Analog -> 1..8 */
+ 30, 31, 32, 33, 34, 35, /* ADAT[1..6] -> 9..14 */
+ 28, 29, /* SPDIF -> 15,16 */
+ 0, 1 /* PCM[1,2] -> 17,18 */
+ }
+};
+
+
+static int scarlett_controls_create_generic(struct usb_mixer_interface *mixer,
+ struct scarlett_device_info *info)
+{
+ int i, err;
+ char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ const struct scarlett_mixer_control *ctl;
+ struct usb_mixer_elem_info *elem;
+
+ /* create master switch and playback volume */
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_switch,
+ scarlett_ctl_resume, 0x0a, 0x01, 0,
+ USB_MIXER_S16, 1, "Master Playback Switch", NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_master,
+ scarlett_ctl_resume, 0x0a, 0x02, 0,
+ USB_MIXER_S16, 1, "Master Playback Volume", NULL,
+ &elem);
+ if (err < 0)
+ return err;
+
+ /* iterate through controls in info struct and create each one */
+ for (i = 0; i < info->num_controls; i++) {
+ ctl = &info->controls[i];
+
+ switch (ctl->type) {
+ case SCARLETT_OUTPUTS:
+ err = add_output_ctls(mixer, ctl->num, ctl->name, info);
+ if (err < 0)
+ return err;
+ break;
+ case SCARLETT_SWITCH_IMPEDANCE:
+ sprintf(mx, "Input %d Impedance Switch", ctl->num);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
+ scarlett_ctl_enum_resume, 0x01,
+ 0x09, ctl->num, USB_MIXER_S16, 1, mx,
+ &opt_impedance, &elem);
+ if (err < 0)
+ return err;
+ break;
+ case SCARLETT_SWITCH_PAD:
+ sprintf(mx, "Input %d Pad Switch", ctl->num);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
+ scarlett_ctl_enum_resume, 0x01,
+ 0x0b, ctl->num, USB_MIXER_S16, 1, mx,
+ &opt_pad, &elem);
+ if (err < 0)
+ return err;
+ break;
+ }
+ }
+
+ return 0;
+}
+
+/*
+ * Create and initialize a mixer for the Focusrite(R) Scarlett
+ */
+int snd_scarlett_controls_create(struct usb_mixer_interface *mixer)
+{
+ int err, i, o;
+ char mx[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
+ struct scarlett_device_info *info;
+ struct usb_mixer_elem_info *elem;
+ static char sample_rate_buffer[4] = { '\x80', '\xbb', '\x00', '\x00' };
+
+ /* only use UAC_VERSION_2 */
+ if (!mixer->protocol)
+ return 0;
+
+ switch (mixer->chip->usb_id) {
+ case USB_ID(0x1235, 0x8012):
+ info = &s6i6_info;
+ break;
+ case USB_ID(0x1235, 0x8002):
+ info = &s8i6_info;
+ break;
+ case USB_ID(0x1235, 0x8004):
+ info = &s18i6_info;
+ break;
+ case USB_ID(0x1235, 0x8014):
+ info = &s18i8_info;
+ break;
+ case USB_ID(0x1235, 0x800c):
+ info = &s18i20_info;
+ break;
+ default: /* device not (yet) supported */
+ return -EINVAL;
+ }
+
+ /* generic function to create controls */
+ err = scarlett_controls_create_generic(mixer, info);
+ if (err < 0)
+ return err;
+
+ /* setup matrix controls */
+ for (i = 0; i < info->matrix_in; i++) {
+ snprintf(mx, sizeof(mx), "Matrix %02d Input Playback Route",
+ i+1);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x32,
+ 0x06, i, USB_MIXER_S16, 1, mx,
+ &info->opt_matrix, &elem);
+ if (err < 0)
+ return err;
+
+ for (o = 0; o < info->matrix_out; o++) {
+ sprintf(mx, "Matrix %02d Mix %c Playback Volume", i+1,
+ o+'A');
+ err = add_new_ctl(mixer, &usb_scarlett_ctl,
+ scarlett_ctl_resume, 0x3c, 0x00,
+ (i << 3) + (o & 0x07), USB_MIXER_S16,
+ 1, mx, NULL, &elem);
+ if (err < 0)
+ return err;
+
+ }
+ }
+
+ for (i = 0; i < info->input_len; i++) {
+ snprintf(mx, sizeof(mx), "Input Source %02d Capture Route",
+ i+1);
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_dynamic_enum,
+ scarlett_ctl_enum_resume, 0x34,
+ 0x00, i, USB_MIXER_S16, 1, mx,
+ &info->opt_master, &elem);
+ if (err < 0)
+ return err;
+ }
+
+ /* val_len == 1 needed here */
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_enum,
+ scarlett_ctl_enum_resume, 0x28, 0x01, 0,
+ USB_MIXER_U8, 1, "Sample Clock Source",
+ &opt_clock, &elem);
+ if (err < 0)
+ return err;
+
+ /* val_len == 1 and UAC2_CS_MEM */
+ err = add_new_ctl(mixer, &usb_scarlett_ctl_sync, NULL, 0x3c, 0x00, 2,
+ USB_MIXER_U8, 1, "Sample Clock Sync Status",
+ &opt_sync, &elem);
+ if (err < 0)
+ return err;
+
+ /* initialize sampling rate to 48000 */
+ err = snd_usb_ctl_msg(mixer->chip->dev,
+ usb_sndctrlpipe(mixer->chip->dev, 0), UAC2_CS_CUR,
+ USB_RECIP_INTERFACE | USB_TYPE_CLASS |
+ USB_DIR_OUT, 0x0100, snd_usb_ctrl_intf(mixer->chip) |
+ (0x29 << 8), sample_rate_buffer, 4);
+ if (err < 0)
+ return err;
+
+ return err;
+}
diff --git a/sound/usb/mixer_scarlett.h b/sound/usb/mixer_scarlett.h
new file mode 100644
index 0000000..19c592a
--- /dev/null
+++ b/sound/usb/mixer_scarlett.h
@@ -0,0 +1,6 @@
+#ifndef __USB_MIXER_SCARLETT_H
+#define __USB_MIXER_SCARLETT_H
+
+int snd_scarlett_controls_create(struct usb_mixer_interface *mixer);
+
+#endif /* __USB_MIXER_SCARLETT_H */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index c62a165..0d8aba5 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -482,6 +482,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
/* set interface */
if (subs->interface != fmt->iface ||
subs->altset_idx != fmt->altset_idx) {
+
+ err = snd_usb_select_mode_quirk(subs, fmt);
+ if (err < 0)
+ return -EIO;
+
err = usb_set_interface(dev, fmt->iface, fmt->altsetting);
if (err < 0) {
dev_err(&dev->dev,
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c657752..0a598af 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2667,57 +2667,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.type = QUIRK_MIDI_NOVATION
}
},
-{
- /*
- * Focusrite Scarlett 18i6
- *
- * Avoid mixer creation, which otherwise fails because some of
- * the interface descriptor subtypes for interface 0 are
- * unknown. That should be fixed or worked-around but this at
- * least allows the device to be used successfully with a DAW
- * and an external mixer. See comments below about other
- * ignored interfaces.
- */
- USB_DEVICE(0x1235, 0x8004),
- .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
- .vendor_name = "Focusrite",
- .product_name = "Scarlett 18i6",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_COMPOSITE,
- .data = & (const struct snd_usb_audio_quirk[]) {
- {
- /* InterfaceSubClass 1 (Control Device) */
- .ifnum = 0,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = 1,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- .ifnum = 2,
- .type = QUIRK_AUDIO_STANDARD_INTERFACE
- },
- {
- /* InterfaceSubClass 1 (Control Device) */
- .ifnum = 3,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = 4,
- .type = QUIRK_MIDI_STANDARD_INTERFACE
- },
- {
- /* InterfaceSubClass 1 (Device Firmware Update) */
- .ifnum = 5,
- .type = QUIRK_IGNORE_INTERFACE
- },
- {
- .ifnum = -1
- }
- }
- }
-},
/* Access Music devices */
{
@@ -2804,133 +2753,45 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
-/* Hauppauge HVR-950Q and HVR-850 */
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7200),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7210),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7217),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x721b),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x721e),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x721f),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7240),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-850",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x2040, 0x7280),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
-{
- USB_DEVICE_VENDOR_SPEC(0x0fd9, 0x0008),
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE |
- USB_DEVICE_ID_MATCH_INT_CLASS |
- USB_DEVICE_ID_MATCH_INT_SUBCLASS,
- .bInterfaceClass = USB_CLASS_AUDIO,
- .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL,
- .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
- .vendor_name = "Hauppauge",
- .product_name = "HVR-950Q",
- .ifnum = QUIRK_ANY_INTERFACE,
- .type = QUIRK_AUDIO_ALIGN_TRANSFER,
- }
-},
+/*
+ * Auvitek au0828 devices with audio interface.
+ * This should be kept in sync with drivers/media/usb/au0828/au0828-cards.c
+ * Please notice that some drivers are DVB only, and don't need to be
+ * here. That's the case, for example, of DVICO_FUSIONHDTV7.
+ */
+
+#define AU0828_DEVICE(vid, pid, vname, pname) { \
+ USB_DEVICE_VENDOR_SPEC(vid, pid), \
+ .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
+ USB_DEVICE_ID_MATCH_INT_CLASS | \
+ USB_DEVICE_ID_MATCH_INT_SUBCLASS, \
+ .bInterfaceClass = USB_CLASS_AUDIO, \
+ .bInterfaceSubClass = USB_SUBCLASS_AUDIOCONTROL, \
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { \
+ .vendor_name = vname, \
+ .product_name = pname, \
+ .ifnum = QUIRK_ANY_INTERFACE, \
+ .type = QUIRK_AUDIO_ALIGN_TRANSFER, \
+ } \
+}
+
+AU0828_DEVICE(0x2040, 0x7200, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x7240, "Hauppauge", "HVR-850"),
+AU0828_DEVICE(0x2040, 0x7210, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x7217, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x721b, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x721e, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x721f, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x7280, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x0fd9, 0x0008, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x7201, "Hauppauge", "HVR-950Q-MXL"),
+AU0828_DEVICE(0x2040, 0x7211, "Hauppauge", "HVR-950Q-MXL"),
+AU0828_DEVICE(0x2040, 0x7281, "Hauppauge", "HVR-950Q-MXL"),
+AU0828_DEVICE(0x05e1, 0x0480, "Hauppauge", "Woodbury"),
+AU0828_DEVICE(0x2040, 0x8200, "Hauppauge", "Woodbury"),
+AU0828_DEVICE(0x2040, 0x7260, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x7213, "Hauppauge", "HVR-950Q"),
+AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"),
/* Digidesign Mbox */
{
@@ -2944,7 +2805,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.data = (const struct snd_usb_audio_quirk[]){
{
.ifnum = 0,
- .type = QUIRK_IGNORE_INTERFACE,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
},
{
.ifnum = 1,
@@ -2955,16 +2816,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.iface = 1,
.altsetting = 1,
.altset_idx = 1,
- .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .attributes = 0x4,
.endpoint = 0x02,
- .ep_attr = 0x01,
- .rates = SNDRV_PCM_RATE_44100 |
- SNDRV_PCM_RATE_48000,
- .rate_min = 44100,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_SYNC,
+ .maxpacksize = 0x130,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
.rate_max = 48000,
- .nr_rates = 2,
+ .nr_rates = 1,
.rate_table = (unsigned int[]) {
- 44100, 48000
+ 48000
+ }
+ }
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3BE,
+ .channels = 2,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = 0x4,
+ .endpoint = 0x81,
+ .ep_attr = USB_ENDPOINT_XFER_ISOC |
+ USB_ENDPOINT_SYNC_ASYNC,
+ .maxpacksize = 0x130,
+ .rates = SNDRV_PCM_RATE_48000,
+ .rate_min = 48000,
+ .rate_max = 48000,
+ .nr_rates = 1,
+ .rate_table = (unsigned int[]) {
+ 48000
}
}
},
@@ -2972,7 +2857,6 @@ YAMAHA_DEVICE(0x7010, "UB99"),
.ifnum = -1
}
}
-
}
},
@@ -3203,6 +3087,46 @@ YAMAHA_DEVICE(0x7010, "UB99"),
{
/*
+ * ZOOM R16/24 in audio interface mode.
+ * Mixer descriptors are garbage, further quirks will be needed
+ * to make any of it functional, thus disabled for now.
+ * Playback stream appears to start and run fine but no sound
+ * is produced, so also disabled for now.
+ */
+ USB_DEVICE(0x1686, 0x00dd),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ /* Mixer */
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE,
+ },
+ {
+ /* Playback */
+ .ifnum = 1,
+ .type = QUIRK_IGNORE_INTERFACE,
+ },
+ {
+ /* Capture */
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE,
+ },
+ {
+ /* Midi */
+ .ifnum = 3,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = -1
+ },
+ }
+ }
+},
+
+{
+ /*
* Some USB MIDI devices don't have an audio control interface,
* so we have to grab MIDI streaming interfaces here.
*/
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c
index 60dfe0d..4dbfb3d 100644
--- a/sound/usb/quirks.c
+++ b/sound/usb/quirks.c
@@ -43,12 +43,13 @@
static int create_composite_quirk(struct snd_usb_audio *chip,
struct usb_interface *iface,
struct usb_driver *driver,
- const struct snd_usb_audio_quirk *quirk)
+ const struct snd_usb_audio_quirk *quirk_comp)
{
int probed_ifnum = get_iface_desc(iface->altsetting)->bInterfaceNumber;
+ const struct snd_usb_audio_quirk *quirk;
int err;
- for (quirk = quirk->data; quirk->ifnum >= 0; ++quirk) {
+ for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
if (!iface)
continue;
@@ -58,9 +59,17 @@ static int create_composite_quirk(struct snd_usb_audio *chip,
err = snd_usb_create_quirk(chip, iface, driver, quirk);
if (err < 0)
return err;
- if (quirk->ifnum != probed_ifnum)
+ }
+
+ for (quirk = quirk_comp->data; quirk->ifnum >= 0; ++quirk) {
+ iface = usb_ifnum_to_if(chip->dev, quirk->ifnum);
+ if (!iface)
+ continue;
+ if (quirk->ifnum != probed_ifnum &&
+ !usb_interface_claimed(iface))
usb_driver_claim_interface(driver, iface, (void *)-1L);
}
+
return 0;
}
@@ -1102,6 +1111,44 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs,
}
}
+
+/* Marantz/Denon USB DACs need a vendor cmd to switch
+ * between PCM and native DSD mode
+ */
+int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
+ struct audioformat *fmt)
+{
+ struct usb_device *dev = subs->dev;
+ int err;
+
+ switch (subs->stream->chip->usb_id) {
+ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
+ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+
+ /* First switch to alt set 0, otherwise the mode switch cmd
+ * will not be accepted by the DAC
+ */
+ err = usb_set_interface(dev, fmt->iface, 0);
+ if (err < 0)
+ return err;
+
+ mdelay(20); /* Delay needed after setting the interface */
+
+ switch (fmt->altsetting) {
+ case 2: /* DSD mode requested */
+ case 1: /* PCM mode requested */
+ err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), 0,
+ USB_DIR_OUT|USB_TYPE_VENDOR|USB_RECIP_INTERFACE,
+ fmt->altsetting - 1, 1, NULL, 0);
+ if (err < 0)
+ return err;
+ break;
+ }
+ mdelay(20);
+ }
+ return 0;
+}
+
void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep)
{
/*
@@ -1160,6 +1207,14 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
break;
}
}
+
+ /* Zoom R16/24 needs a tiny delay here, otherwise requests like
+ * get/set frequency return as failed despite actually succeeding.
+ */
+ if ((le16_to_cpu(dev->descriptor.idVendor) == 0x1686) &&
+ (le16_to_cpu(dev->descriptor.idProduct) == 0x00dd) &&
+ (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS)
+ mdelay(1);
}
/*
@@ -1204,5 +1259,16 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
break;
}
+ /* Denon/Marantz devices with USB DAC functionality */
+ switch (chip->usb_id) {
+ case USB_ID(0x154e, 0x3005): /* Marantz HD-DAC1 */
+ case USB_ID(0x154e, 0x3006): /* Marantz SA-14S1 */
+ if (fp->altsetting == 2)
+ return SNDRV_PCM_FMTBIT_DSD_U32_BE;
+ break;
+ default:
+ break;
+ }
+
return 0;
}
diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h
index 665e972..1b86238 100644
--- a/sound/usb/quirks.h
+++ b/sound/usb/quirks.h
@@ -31,6 +31,9 @@ void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe,
__u8 request, __u8 requesttype, __u16 value,
__u16 index, void *data, __u16 size);
+int snd_usb_select_mode_quirk(struct snd_usb_substream *subs,
+ struct audioformat *fmt);
+
u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip,
struct audioformat *fp,
unsigned int sample_bytes);
diff --git a/sound/usb/usx2y/usbusx2yaudio.c b/sound/usb/usx2y/usbusx2yaudio.c
index a63330d..61d5dc2 100644
--- a/sound/usb/usx2y/usbusx2yaudio.c
+++ b/sound/usb/usx2y/usbusx2yaudio.c
@@ -272,13 +272,8 @@ static void usX2Y_clients_stop(struct usX2Ydev *usX2Y)
for (s = 0; s < 4; s++) {
struct snd_usX2Y_substream *subs = usX2Y->subs[s];
if (subs) {
- if (atomic_read(&subs->state) >= state_PRERUNNING) {
- unsigned long flags;
-
- snd_pcm_stream_lock_irqsave(subs->pcm_substream, flags);
- snd_pcm_stop(subs->pcm_substream, SNDRV_PCM_STATE_XRUN);
- snd_pcm_stream_unlock_irqrestore(subs->pcm_substream, flags);
- }
+ if (atomic_read(&subs->state) >= state_PRERUNNING)
+ snd_pcm_stop_xrun(subs->pcm_substream);
for (u = 0; u < NRURBS; u++) {
struct urb *urb = subs->urb[u];
if (NULL != urb)
diff --git a/tools/lib/traceevent/plugin_scsi.c b/tools/lib/traceevent/plugin_scsi.c
index eda326f..3727de4 100644
--- a/tools/lib/traceevent/plugin_scsi.c
+++ b/tools/lib/traceevent/plugin_scsi.c
@@ -85,8 +85,9 @@ typedef unsigned int u32;
#define MOVE_MEDIUM 0xa5
#define EXCHANGE_MEDIUM 0xa6
#define READ_12 0xa8
+#define SERVICE_ACTION_OUT_12 0xa9
#define WRITE_12 0xaa
-#define READ_MEDIA_SERIAL_NUMBER 0xab
+#define SERVICE_ACTION_IN_12 0xab
#define WRITE_VERIFY_12 0xae
#define VERIFY_12 0xaf
#define SEARCH_HIGH_12 0xb0
@@ -107,7 +108,9 @@ typedef unsigned int u32;
#define VERIFY_16 0x8f
#define SYNCHRONIZE_CACHE_16 0x91
#define WRITE_SAME_16 0x93
-#define SERVICE_ACTION_IN 0x9e
+#define SERVICE_ACTION_BIDIRECTIONAL 0x9d
+#define SERVICE_ACTION_IN_16 0x9e
+#define SERVICE_ACTION_OUT_16 0x9f
/* values for service action in */
#define SAI_READ_CAPACITY_16 0x10
#define SAI_GET_LBA_STATUS 0x12
@@ -393,7 +396,7 @@ scsi_trace_parse_cdb(struct trace_seq *p, unsigned char *cdb, int len)
return scsi_trace_rw16(p, cdb, len);
case UNMAP:
return scsi_trace_unmap(p, cdb, len);
- case SERVICE_ACTION_IN:
+ case SERVICE_ACTION_IN_16:
return scsi_trace_service_action_in(p, cdb, len);
case VARIABLE_LENGTH_CMD:
return scsi_trace_varlen(p, cdb, len);
diff --git a/tools/perf/.gitignore b/tools/perf/.gitignore
index 717221e..40399c3 100644
--- a/tools/perf/.gitignore
+++ b/tools/perf/.gitignore
@@ -2,6 +2,8 @@ PERF-CFLAGS
PERF-GUI-VARS
PERF-VERSION-FILE
perf
+perf-read-vdso32
+perf-read-vdsox32
perf-help
perf-record
perf-report
diff --git a/tools/perf/Documentation/perf-record.txt b/tools/perf/Documentation/perf-record.txt
index 398f8d5..af9a54e 100644
--- a/tools/perf/Documentation/perf-record.txt
+++ b/tools/perf/Documentation/perf-record.txt
@@ -214,6 +214,12 @@ if combined with -a or -C options.
After starting the program, wait msecs before measuring. This is useful to
filter out the startup phase of the program, which is often very different.
+-I::
+--intr-regs::
+Capture machine state (registers) at interrupt, i.e., on counter overflows for
+each sample. List of captured registers depends on the architecture. This option
+is off by default.
+
SEE ALSO
--------
linkperf:perf-stat[1], linkperf:perf-list[1]
diff --git a/tools/perf/Documentation/perf-report.txt b/tools/perf/Documentation/perf-report.txt
index 0927bf4..dd7cccd 100644
--- a/tools/perf/Documentation/perf-report.txt
+++ b/tools/perf/Documentation/perf-report.txt
@@ -159,7 +159,7 @@ OPTIONS
--dump-raw-trace::
Dump raw trace in ASCII.
--g [type,min[,limit],order[,key]]::
+-g [type,min[,limit],order[,key][,branch]]::
--call-graph::
Display call chains using type, min percent threshold, optional print
limit and order.
@@ -177,6 +177,11 @@ OPTIONS
- function: compare on functions
- address: compare on individual code addresses
+ branch can be:
+ - branch: include last branch information in callgraph
+ when available. Usually more convenient to use --branch-history
+ for this.
+
Default: fractal,0.5,callee,function.
--children::
@@ -266,6 +271,11 @@ OPTIONS
branch stacks and it will automatically switch to the branch view mode,
unless --no-branch-stack is used.
+--branch-history::
+ Add the addresses of sampled taken branches to the callstack.
+ This allows to examine the path the program took to each sample.
+ The data collection must have used -b (or -j) and -g.
+
--objdump=<path>::
Path to objdump binary.
diff --git a/tools/perf/Makefile.perf b/tools/perf/Makefile.perf
index 262916f..478efa9 100644
--- a/tools/perf/Makefile.perf
+++ b/tools/perf/Makefile.perf
@@ -60,6 +60,15 @@ include config/utilities.mak
#
# Define NO_LIBDW_DWARF_UNWIND if you do not want libdw support
# for dwarf backtrace post unwind.
+#
+# Define NO_PERF_READ_VDSO32 if you do not want to build perf-read-vdso32
+# for reading the 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_PERF_READ_VDSOX32 if you do not want to build perf-read-vdsox32
+# for reading the x32 mode 32-bit compatibility VDSO in 64-bit mode
+#
+# Define NO_ZLIB if you do not want to support compressed kernel modules
+
ifeq ($(srctree),)
srctree := $(patsubst %/,%,$(dir $(shell pwd)))
@@ -171,11 +180,16 @@ $(OUTPUT)python/perf.so: $(PYTHON_EXT_SRCS) $(PYTHON_EXT_DEPS)
SCRIPTS = $(patsubst %.sh,%,$(SCRIPT_SH))
-#
-# Single 'perf' binary right now:
-#
PROGRAMS += $(OUTPUT)perf
+ifndef NO_PERF_READ_VDSO32
+PROGRAMS += $(OUTPUT)perf-read-vdso32
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+PROGRAMS += $(OUTPUT)perf-read-vdsox32
+endif
+
# what 'all' will build and 'install' will install, in perfexecdir
ALL_PROGRAMS = $(PROGRAMS) $(SCRIPTS)
@@ -247,12 +261,14 @@ LIB_H += util/annotate.h
LIB_H += util/cache.h
LIB_H += util/callchain.h
LIB_H += util/build-id.h
+LIB_H += util/db-export.h
LIB_H += util/debug.h
LIB_H += util/pmu.h
LIB_H += util/event.h
LIB_H += util/evsel.h
LIB_H += util/evlist.h
LIB_H += util/exec_cmd.h
+LIB_H += util/find-vdso-map.c
LIB_H += util/levenshtein.h
LIB_H += util/machine.h
LIB_H += util/map.h
@@ -304,6 +320,7 @@ LIB_H += ui/util.h
LIB_H += ui/ui.h
LIB_H += util/data.h
LIB_H += util/kvm-stat.h
+LIB_H += util/thread-stack.h
LIB_OBJS += $(OUTPUT)util/abspath.o
LIB_OBJS += $(OUTPUT)util/alias.o
@@ -311,6 +328,7 @@ LIB_OBJS += $(OUTPUT)util/annotate.o
LIB_OBJS += $(OUTPUT)util/build-id.o
LIB_OBJS += $(OUTPUT)util/config.o
LIB_OBJS += $(OUTPUT)util/ctype.o
+LIB_OBJS += $(OUTPUT)util/db-export.o
LIB_OBJS += $(OUTPUT)util/pmu.o
LIB_OBJS += $(OUTPUT)util/environment.o
LIB_OBJS += $(OUTPUT)util/event.o
@@ -380,6 +398,7 @@ LIB_OBJS += $(OUTPUT)util/srcline.o
LIB_OBJS += $(OUTPUT)util/data.o
LIB_OBJS += $(OUTPUT)util/tsc.o
LIB_OBJS += $(OUTPUT)util/cloexec.o
+LIB_OBJS += $(OUTPUT)util/thread-stack.o
LIB_OBJS += $(OUTPUT)ui/setup.o
LIB_OBJS += $(OUTPUT)ui/helpline.o
@@ -478,8 +497,6 @@ ifneq ($(OUTPUT),)
endif
ifdef NO_LIBELF
-EXTLIBS := $(filter-out -lelf,$(EXTLIBS))
-
# Remove ELF/DWARF dependent codes
LIB_OBJS := $(filter-out $(OUTPUT)util/symbol-elf.o,$(LIB_OBJS))
LIB_OBJS := $(filter-out $(OUTPUT)util/dwarf-aux.o,$(LIB_OBJS))
@@ -568,6 +585,10 @@ ifndef NO_LIBNUMA
BUILTIN_OBJS += $(OUTPUT)bench/numa.o
endif
+ifndef NO_ZLIB
+ LIB_OBJS += $(OUTPUT)util/zlib.o
+endif
+
ifdef ASCIIDOC8
export ASCIIDOC8
endif
@@ -732,6 +753,16 @@ $(OUTPUT)scripts/python/Perf-Trace-Util/Context.o: scripts/python/Perf-Trace-Uti
$(OUTPUT)perf-%: %.o $(PERFLIBS)
$(QUIET_LINK)$(CC) $(CFLAGS) -o $@ $(LDFLAGS) $(filter %.o,$^) $(LIBS)
+ifndef NO_PERF_READ_VDSO32
+$(OUTPUT)perf-read-vdso32: perf-read-vdso.c util/find-vdso-map.c
+ $(QUIET_CC)$(CC) -m32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
+ifndef NO_PERF_READ_VDSOX32
+$(OUTPUT)perf-read-vdsox32: perf-read-vdso.c util/find-vdso-map.c
+ $(QUIET_CC)$(CC) -mx32 $(filter -static,$(LDFLAGS)) -Wall -Werror -o $@ perf-read-vdso.c
+endif
+
$(LIB_OBJS) $(BUILTIN_OBJS): $(LIB_H)
$(patsubst perf-%,%.o,$(PROGRAMS)): $(LIB_H) $(wildcard */*.h)
@@ -876,6 +907,14 @@ install-bin: all install-gtk
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(bindir_SQ)'; \
$(INSTALL) $(OUTPUT)perf '$(DESTDIR_SQ)$(bindir_SQ)'; \
$(LN) '$(DESTDIR_SQ)$(bindir_SQ)/perf' '$(DESTDIR_SQ)$(bindir_SQ)/trace'
+ifndef NO_PERF_READ_VDSO32
+ $(call QUIET_INSTALL, perf-read-vdso32) \
+ $(INSTALL) $(OUTPUT)perf-read-vdso32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
+ifndef NO_PERF_READ_VDSOX32
+ $(call QUIET_INSTALL, perf-read-vdsox32) \
+ $(INSTALL) $(OUTPUT)perf-read-vdsox32 '$(DESTDIR_SQ)$(bindir_SQ)';
+endif
$(call QUIET_INSTALL, libexec) \
$(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(perfexec_instdir_SQ)'
$(call QUIET_INSTALL, perf-archive) \
@@ -928,7 +967,7 @@ config-clean:
clean: $(LIBTRACEEVENT)-clean $(LIBAPIKFS)-clean config-clean
$(call QUIET_CLEAN, core-objs) $(RM) $(LIB_OBJS) $(BUILTIN_OBJS) $(LIB_FILE) $(OUTPUT)perf-archive $(OUTPUT)perf-with-kcore $(OUTPUT)perf.o $(LANG_BINDINGS) $(GTK_OBJS)
- $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf
+ $(call QUIET_CLEAN, core-progs) $(RM) $(ALL_PROGRAMS) perf perf-read-vdso32 perf-read-vdsox32
$(call QUIET_CLEAN, core-gen) $(RM) *.spec *.pyc *.pyo */*.pyc */*.pyo $(OUTPUT)common-cmds.h TAGS tags cscope* $(OUTPUT)PERF-VERSION-FILE $(OUTPUT)PERF-CFLAGS $(OUTPUT)PERF-FEATURES $(OUTPUT)util/*-bison* $(OUTPUT)util/*-flex*
$(QUIET_SUBDIR0)Documentation $(QUIET_SUBDIR1) clean
$(python-clean)
diff --git a/tools/perf/arch/powerpc/util/skip-callchain-idx.c b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
index d73ef8b..3bb50ea 100644
--- a/tools/perf/arch/powerpc/util/skip-callchain-idx.c
+++ b/tools/perf/arch/powerpc/util/skip-callchain-idx.c
@@ -145,7 +145,7 @@ static Dwarf_Frame *get_dwarf_frame(Dwfl_Module *mod, Dwarf_Addr pc)
* yet used)
* -1 in case of errors
*/
-static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
+static int check_return_addr(struct dso *dso, Dwarf_Addr pc)
{
int rc = -1;
Dwfl *dwfl;
@@ -156,15 +156,27 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
Dwarf_Addr end = pc;
bool signalp;
- dwfl = dwfl_begin(&offline_callbacks);
- if (!dwfl) {
- pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
- return -1;
- }
+ dwfl = dso->dwfl;
- if (dwfl_report_offline(dwfl, "", exec_file, -1) == NULL) {
- pr_debug("dwfl_report_offline() failed %s\n", dwarf_errmsg(-1));
- goto out;
+ if (!dwfl) {
+ dwfl = dwfl_begin(&offline_callbacks);
+ if (!dwfl) {
+ pr_debug("dwfl_begin() failed: %s\n", dwarf_errmsg(-1));
+ return -1;
+ }
+
+ if (dwfl_report_offline(dwfl, "", dso->long_name, -1) == NULL) {
+ pr_debug("dwfl_report_offline() failed %s\n",
+ dwarf_errmsg(-1));
+ /*
+ * We normally cache the DWARF debug info and never
+ * call dwfl_end(). But to prevent fd leak, free in
+ * case of error.
+ */
+ dwfl_end(dwfl);
+ goto out;
+ }
+ dso->dwfl = dwfl;
}
mod = dwfl_addrmodule(dwfl, pc);
@@ -194,7 +206,6 @@ static int check_return_addr(const char *exec_file, Dwarf_Addr pc)
rc = check_return_reg(ra_regno, frame);
out:
- dwfl_end(dwfl);
return rc;
}
@@ -221,8 +232,7 @@ out:
* index: of callchain entry that needs to be ignored (if any)
* -1 if no entry needs to be ignored or in case of errors
*/
-int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
- struct ip_callchain *chain)
+int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain)
{
struct addr_location al;
struct dso *dso = NULL;
@@ -235,7 +245,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
ip = chain->ips[2];
- thread__find_addr_location(thread, machine, PERF_RECORD_MISC_USER,
+ thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, &al);
if (al.map)
@@ -246,7 +256,7 @@ int arch_skip_callchain_idx(struct machine *machine, struct thread *thread,
return skip_slot;
}
- rc = check_return_addr(dso->long_name, ip);
+ rc = check_return_addr(dso, ip);
pr_debug("DSO %s, nr %" PRIx64 ", ip 0x%" PRIx64 "rc %d\n",
dso->long_name, chain->nr, ip, rc);
diff --git a/tools/perf/builtin-diff.c b/tools/perf/builtin-diff.c
index 25114c9..1ce425d 100644
--- a/tools/perf/builtin-diff.c
+++ b/tools/perf/builtin-diff.c
@@ -357,6 +357,7 @@ static int diff__process_sample_event(struct perf_tool *tool __maybe_unused,
static struct perf_tool tool = {
.sample = diff__process_sample_event,
.mmap = perf_event__process_mmap,
+ .mmap2 = perf_event__process_mmap2,
.comm = perf_event__process_comm,
.exit = perf_event__process_exit,
.fork = perf_event__process_fork,
diff --git a/tools/perf/builtin-inject.c b/tools/perf/builtin-inject.c
index de99ca1..84df2de 100644
--- a/tools/perf/builtin-inject.c
+++ b/tools/perf/builtin-inject.c
@@ -217,8 +217,7 @@ static int perf_event__inject_buildid(struct perf_tool *tool,
goto repipe;
}
- thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
- sample->ip, &al);
+ thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
if (al.map != NULL) {
if (!al.map->dso->hit) {
@@ -410,6 +409,7 @@ int cmd_inject(int argc, const char **argv, const char *prefix __maybe_unused)
.tracing_data = perf_event__repipe_op2_synth,
.finished_round = perf_event__repipe_op2_synth,
.build_id = perf_event__repipe_op2_synth,
+ .id_index = perf_event__repipe_op2_synth,
},
.input_name = "-",
.samples = LIST_HEAD_INIT(inject.samples),
diff --git a/tools/perf/builtin-kvm.c b/tools/perf/builtin-kvm.c
index b65eb050..3c0f3d4 100644
--- a/tools/perf/builtin-kvm.c
+++ b/tools/perf/builtin-kvm.c
@@ -1132,6 +1132,10 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
"-m", "1024",
"-c", "1",
};
+ const char * const kvm_stat_record_usage[] = {
+ "perf kvm stat record [<options>]",
+ NULL
+ };
const char * const *events_tp;
events_tp_size = 0;
@@ -1159,6 +1163,27 @@ kvm_events_record(struct perf_kvm_stat *kvm, int argc, const char **argv)
for (j = 1; j < (unsigned int)argc; j++, i++)
rec_argv[i] = argv[j];
+ set_option_flag(record_options, 'e', "event", PARSE_OPT_HIDDEN);
+ set_option_flag(record_options, 0, "filter", PARSE_OPT_HIDDEN);
+ set_option_flag(record_options, 'R', "raw-samples", PARSE_OPT_HIDDEN);
+
+ set_option_flag(record_options, 'F', "freq", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 0, "group", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'g', NULL, PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 0, "call-graph", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'd', "data", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'T', "timestamp", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'P', "period", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'n', "no-samples", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'N', "no-buildid-cache", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'B', "no-buildid", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'G', "cgroup", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'b', "branch-any", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'j', "branch-filter", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 'W', "weight", PARSE_OPT_DISABLED);
+ set_option_flag(record_options, 0, "transaction", PARSE_OPT_DISABLED);
+
+ record_usage = kvm_stat_record_usage;
return cmd_record(i, rec_argv, NULL);
}
diff --git a/tools/perf/builtin-probe.c b/tools/perf/builtin-probe.c
index 7af26ac..921bb69 100644
--- a/tools/perf/builtin-probe.c
+++ b/tools/perf/builtin-probe.c
@@ -55,6 +55,7 @@ static struct {
bool show_funcs;
bool mod_events;
bool uprobes;
+ bool quiet;
int nevents;
struct perf_probe_event events[MAX_PROBES];
struct strlist *dellist;
@@ -312,9 +313,11 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
#endif
NULL
};
- const struct option options[] = {
+ struct option options[] = {
OPT_INCR('v', "verbose", &verbose,
"be more verbose (show parsed arguments, etc)"),
+ OPT_BOOLEAN('q', "quiet", &params.quiet,
+ "be quiet (do not show any mesages)"),
OPT_BOOLEAN('l', "list", &params.list_events,
"list up current probe events"),
OPT_CALLBACK('d', "del", NULL, "[GROUP:]EVENT", "delete a probe event.",
@@ -382,6 +385,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
};
int ret;
+ set_option_flag(options, 'a', "add", PARSE_OPT_EXCLUSIVE);
+ set_option_flag(options, 'd', "del", PARSE_OPT_EXCLUSIVE);
+ set_option_flag(options, 'l', "list", PARSE_OPT_EXCLUSIVE);
+#ifdef HAVE_DWARF_SUPPORT
+ set_option_flag(options, 'L', "line", PARSE_OPT_EXCLUSIVE);
+ set_option_flag(options, 'V', "vars", PARSE_OPT_EXCLUSIVE);
+#endif
+
argc = parse_options(argc, argv, options, probe_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (argc > 0) {
@@ -396,6 +407,14 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
}
}
+ if (params.quiet) {
+ if (verbose != 0) {
+ pr_err(" Error: -v and -q are exclusive.\n");
+ return -EINVAL;
+ }
+ verbose = -1;
+ }
+
if (params.max_probe_points == 0)
params.max_probe_points = MAX_PROBES;
@@ -409,22 +428,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
symbol_conf.try_vmlinux_path = (symbol_conf.vmlinux_name == NULL);
if (params.list_events) {
- if (params.mod_events) {
- pr_err(" Error: Don't use --list with --add/--del.\n");
- usage_with_options(probe_usage, options);
- }
- if (params.show_lines) {
- pr_err(" Error: Don't use --list with --line.\n");
- usage_with_options(probe_usage, options);
- }
- if (params.show_vars) {
- pr_err(" Error: Don't use --list with --vars.\n");
- usage_with_options(probe_usage, options);
- }
- if (params.show_funcs) {
- pr_err(" Error: Don't use --list with --funcs.\n");
- usage_with_options(probe_usage, options);
- }
if (params.uprobes) {
pr_warning(" Error: Don't use --list with --exec.\n");
usage_with_options(probe_usage, options);
@@ -435,19 +438,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
return ret;
}
if (params.show_funcs) {
- if (params.nevents != 0 || params.dellist) {
- pr_err(" Error: Don't use --funcs with"
- " --add/--del.\n");
- usage_with_options(probe_usage, options);
- }
- if (params.show_lines) {
- pr_err(" Error: Don't use --funcs with --line.\n");
- usage_with_options(probe_usage, options);
- }
- if (params.show_vars) {
- pr_err(" Error: Don't use --funcs with --vars.\n");
- usage_with_options(probe_usage, options);
- }
if (!params.filter)
params.filter = strfilter__new(DEFAULT_FUNC_FILTER,
NULL);
@@ -462,16 +452,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
#ifdef HAVE_DWARF_SUPPORT
if (params.show_lines) {
- if (params.mod_events) {
- pr_err(" Error: Don't use --line with"
- " --add/--del.\n");
- usage_with_options(probe_usage, options);
- }
- if (params.show_vars) {
- pr_err(" Error: Don't use --line with --vars.\n");
- usage_with_options(probe_usage, options);
- }
-
ret = show_line_range(&params.line_range, params.target,
params.uprobes);
if (ret < 0)
@@ -479,11 +459,6 @@ __cmd_probe(int argc, const char **argv, const char *prefix __maybe_unused)
return ret;
}
if (params.show_vars) {
- if (params.mod_events) {
- pr_err(" Error: Don't use --vars with"
- " --add/--del.\n");
- usage_with_options(probe_usage, options);
- }
if (!params.filter)
params.filter = strfilter__new(DEFAULT_VAR_FILTER,
NULL);
diff --git a/tools/perf/builtin-record.c b/tools/perf/builtin-record.c
index 2583a9b..8648c6d 100644
--- a/tools/perf/builtin-record.c
+++ b/tools/perf/builtin-record.c
@@ -200,6 +200,17 @@ static int process_buildids(struct record *rec)
if (size == 0)
return 0;
+ /*
+ * During this process, it'll load kernel map and replace the
+ * dso->long_name to a real pathname it found. In this case
+ * we prefer the vmlinux path like
+ * /lib/modules/3.16.4/build/vmlinux
+ *
+ * rather than build-id path (in debug directory).
+ * $HOME/.debug/.build-id/f0/6e17aa50adf4d00b88925e03775de107611551
+ */
+ symbol_conf.ignore_vmlinux_buildid = true;
+
return __perf_session__process_events(session, start,
size - start,
size, &build_id__mark_dso_hit_ops);
@@ -680,11 +691,12 @@ static int perf_record_config(const char *var, const char *value, void *cb)
return perf_default_config(var, value, cb);
}
-static const char * const record_usage[] = {
+static const char * const __record_usage[] = {
"perf record [<options>] [<command>]",
"perf record [<options>] -- <command> [<options>]",
NULL
};
+const char * const *record_usage = __record_usage;
/*
* XXX Ideally would be local to cmd_record() and passed to a record__new
@@ -725,7 +737,7 @@ const char record_callchain_help[] = CALLCHAIN_HELP "fp";
* perf_evlist__prepare_workload, etc instead of fork+exec'in 'perf record',
* using pipes, etc.
*/
-const struct option record_options[] = {
+struct option __record_options[] = {
OPT_CALLBACK('e', "event", &record.evlist, "event",
"event selector. use 'perf list' to list available events",
parse_events_option),
@@ -799,9 +811,13 @@ const struct option record_options[] = {
"sample transaction flags (special events only)"),
OPT_BOOLEAN(0, "per-thread", &record.opts.target.per_thread,
"use per-thread mmaps"),
+ OPT_BOOLEAN('I', "intr-regs", &record.opts.sample_intr_regs,
+ "Sample machine registers on interrupt"),
OPT_END()
};
+struct option *record_options = __record_options;
+
int cmd_record(int argc, const char **argv, const char *prefix __maybe_unused)
{
int err = -ENOMEM;
diff --git a/tools/perf/builtin-report.c b/tools/perf/builtin-report.c
index 140a6cd..3936760 100644
--- a/tools/perf/builtin-report.c
+++ b/tools/perf/builtin-report.c
@@ -226,8 +226,9 @@ static int report__setup_sample_type(struct report *rep)
return -EINVAL;
}
if (symbol_conf.use_callchain) {
- ui__error("Selected -g but no callchain data. Did "
- "you call 'perf record' without -g?\n");
+ ui__error("Selected -g or --branch-history but no "
+ "callchain data. Did\n"
+ "you call 'perf record' without -g?\n");
return -1;
}
} else if (!rep->dont_use_callchains &&
@@ -575,6 +576,7 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
struct stat st;
bool has_br_stack = false;
int branch_mode = -1;
+ bool branch_call_mode = false;
char callchain_default_opt[] = "fractal,0.5,callee";
const char * const report_usage[] = {
"perf report [<options>]",
@@ -637,8 +639,8 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
"regex filter to identify parent, see: '--sort parent'"),
OPT_BOOLEAN('x', "exclude-other", &symbol_conf.exclude_other,
"Only display entries with parent-match"),
- OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order",
- "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address). "
+ OPT_CALLBACK_DEFAULT('g', "call-graph", &report, "output_type,min_percent[,print_limit],call_order[,branch]",
+ "Display callchains using output_type (graph, flat, fractal, or none) , min percent threshold, optional print limit, callchain order, key (function or address), add branches. "
"Default: fractal,0.5,callee,function", &report_parse_callchain_opt, callchain_default_opt),
OPT_BOOLEAN(0, "children", &symbol_conf.cumulate_callchain,
"Accumulate callchains of children and show total overhead as well"),
@@ -684,7 +686,10 @@ int cmd_report(int argc, const char **argv, const char *prefix __maybe_unused)
OPT_BOOLEAN(0, "group", &symbol_conf.event_group,
"Show event group information together"),
OPT_CALLBACK_NOOPT('b', "branch-stack", &branch_mode, "",
- "use branch records for histogram filling", parse_branch_mode),
+ "use branch records for per branch histogram filling",
+ parse_branch_mode),
+ OPT_BOOLEAN(0, "branch-history", &branch_call_mode,
+ "add last branch records to call history"),
OPT_STRING(0, "objdump", &objdump_path, "path",
"objdump binary to use for disassembly and annotations"),
OPT_BOOLEAN(0, "demangle", &symbol_conf.demangle,
@@ -745,10 +750,24 @@ repeat:
has_br_stack = perf_header__has_feat(&session->header,
HEADER_BRANCH_STACK);
- if ((branch_mode == -1 && has_br_stack) || branch_mode == 1) {
+ /*
+ * Branch mode is a tristate:
+ * -1 means default, so decide based on the file having branch data.
+ * 0/1 means the user chose a mode.
+ */
+ if (((branch_mode == -1 && has_br_stack) || branch_mode == 1) &&
+ branch_call_mode == -1) {
sort__mode = SORT_MODE__BRANCH;
symbol_conf.cumulate_callchain = false;
}
+ if (branch_call_mode) {
+ callchain_param.key = CCKEY_ADDRESS;
+ callchain_param.branch_callstack = 1;
+ symbol_conf.use_callchain = true;
+ callchain_register_param(&callchain_param);
+ if (sort_order == NULL)
+ sort_order = "srcline,symbol,dso";
+ }
if (report.mem_mode) {
if (sort__mode == SORT_MODE__BRANCH) {
diff --git a/tools/perf/builtin-script.c b/tools/perf/builtin-script.c
index 9708a12..ce304df 100644
--- a/tools/perf/builtin-script.c
+++ b/tools/perf/builtin-script.c
@@ -23,7 +23,6 @@ static char const *generate_script_lang;
static bool debug_mode;
static u64 last_timestamp;
static u64 nr_unordered;
-extern const struct option record_options[];
static bool no_callchain;
static bool latency_format;
static bool system_wide;
@@ -379,7 +378,6 @@ static void print_sample_start(struct perf_sample *sample,
static void print_sample_addr(union perf_event *event,
struct perf_sample *sample,
- struct machine *machine,
struct thread *thread,
struct perf_event_attr *attr)
{
@@ -390,7 +388,7 @@ static void print_sample_addr(union perf_event *event,
if (!sample_addr_correlates_sym(attr))
return;
- perf_event__preprocess_sample_addr(event, sample, machine, thread, &al);
+ perf_event__preprocess_sample_addr(event, sample, thread, &al);
if (PRINT_FIELD(SYM)) {
printf(" ");
@@ -438,7 +436,7 @@ static void print_sample_bts(union perf_event *event,
((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
!output[attr->type].user_set)) {
printf(" => ");
- print_sample_addr(event, sample, al->machine, thread, attr);
+ print_sample_addr(event, sample, thread, attr);
}
if (print_srcline_last)
@@ -475,7 +473,7 @@ static void process_event(union perf_event *event, struct perf_sample *sample,
event_format__print(evsel->tp_format, sample->cpu,
sample->raw_data, sample->raw_size);
if (PRINT_FIELD(ADDR))
- print_sample_addr(event, sample, al->machine, thread, attr);
+ print_sample_addr(event, sample, thread, attr);
if (PRINT_FIELD(IP)) {
if (!symbol_conf.use_callchain)
diff --git a/tools/perf/builtin-stat.c b/tools/perf/builtin-stat.c
index 055ce92..8910863 100644
--- a/tools/perf/builtin-stat.c
+++ b/tools/perf/builtin-stat.c
@@ -388,20 +388,102 @@ static void update_shadow_stats(struct perf_evsel *counter, u64 *count)
update_stats(&runtime_itlb_cache_stats[0], count[0]);
}
+static void zero_per_pkg(struct perf_evsel *counter)
+{
+ if (counter->per_pkg_mask)
+ memset(counter->per_pkg_mask, 0, MAX_NR_CPUS);
+}
+
+static int check_per_pkg(struct perf_evsel *counter, int cpu, bool *skip)
+{
+ unsigned long *mask = counter->per_pkg_mask;
+ struct cpu_map *cpus = perf_evsel__cpus(counter);
+ int s;
+
+ *skip = false;
+
+ if (!counter->per_pkg)
+ return 0;
+
+ if (cpu_map__empty(cpus))
+ return 0;
+
+ if (!mask) {
+ mask = zalloc(MAX_NR_CPUS);
+ if (!mask)
+ return -ENOMEM;
+
+ counter->per_pkg_mask = mask;
+ }
+
+ s = cpu_map__get_socket(cpus, cpu);
+ if (s < 0)
+ return -1;
+
+ *skip = test_and_set_bit(s, mask) == 1;
+ return 0;
+}
+
+static int read_cb(struct perf_evsel *evsel, int cpu, int thread __maybe_unused,
+ struct perf_counts_values *count)
+{
+ struct perf_counts_values *aggr = &evsel->counts->aggr;
+ static struct perf_counts_values zero;
+ bool skip = false;
+
+ if (check_per_pkg(evsel, cpu, &skip)) {
+ pr_err("failed to read per-pkg counter\n");
+ return -1;
+ }
+
+ if (skip)
+ count = &zero;
+
+ switch (aggr_mode) {
+ case AGGR_CORE:
+ case AGGR_SOCKET:
+ case AGGR_NONE:
+ if (!evsel->snapshot)
+ perf_evsel__compute_deltas(evsel, cpu, count);
+ perf_counts_values__scale(count, scale, NULL);
+ evsel->counts->cpu[cpu] = *count;
+ update_shadow_stats(evsel, count->values);
+ break;
+ case AGGR_GLOBAL:
+ aggr->val += count->val;
+ if (scale) {
+ aggr->ena += count->ena;
+ aggr->run += count->run;
+ }
+ default:
+ break;
+ }
+
+ return 0;
+}
+
+static int read_counter(struct perf_evsel *counter);
+
/*
* Read out the results of a single counter:
* aggregate counts across CPUs in system-wide mode
*/
static int read_counter_aggr(struct perf_evsel *counter)
{
+ struct perf_counts_values *aggr = &counter->counts->aggr;
struct perf_stat *ps = counter->priv;
u64 *count = counter->counts->aggr.values;
int i;
- if (__perf_evsel__read(counter, perf_evsel__nr_cpus(counter),
- thread_map__nr(evsel_list->threads), scale) < 0)
+ aggr->val = aggr->ena = aggr->run = 0;
+
+ if (read_counter(counter))
return -1;
+ if (!counter->snapshot)
+ perf_evsel__compute_deltas(counter, -1, aggr);
+ perf_counts_values__scale(aggr, scale, &counter->counts->scaled);
+
for (i = 0; i < 3; i++)
update_stats(&ps->res_stats[i], count[i]);
@@ -424,16 +506,21 @@ static int read_counter_aggr(struct perf_evsel *counter)
*/
static int read_counter(struct perf_evsel *counter)
{
- u64 *count;
- int cpu;
+ int nthreads = thread_map__nr(evsel_list->threads);
+ int ncpus = perf_evsel__nr_cpus(counter);
+ int cpu, thread;
- for (cpu = 0; cpu < perf_evsel__nr_cpus(counter); cpu++) {
- if (__perf_evsel__read_on_cpu(counter, cpu, 0, scale) < 0)
- return -1;
+ if (counter->system_wide)
+ nthreads = 1;
- count = counter->counts->cpu[cpu].values;
+ if (counter->per_pkg)
+ zero_per_pkg(counter);
- update_shadow_stats(counter, count);
+ for (thread = 0; thread < nthreads; thread++) {
+ for (cpu = 0; cpu < ncpus; cpu++) {
+ if (perf_evsel__read_cb(counter, cpu, thread, read_cb))
+ return -1;
+ }
}
return 0;
diff --git a/tools/perf/builtin-timechart.c b/tools/perf/builtin-timechart.c
index 35b425b..f3bb1a4 100644
--- a/tools/perf/builtin-timechart.c
+++ b/tools/perf/builtin-timechart.c
@@ -528,7 +528,7 @@ static const char *cat_backtrace(union perf_event *event,
}
tal.filtered = 0;
- thread__find_addr_location(al.thread, machine, cpumode,
+ thread__find_addr_location(al.thread, cpumode,
MAP__FUNCTION, ip, &tal);
if (tal.sym)
@@ -1963,7 +1963,7 @@ int cmd_timechart(int argc, const char **argv,
NULL
};
- const struct option record_options[] = {
+ const struct option timechart_record_options[] = {
OPT_BOOLEAN('P', "power-only", &tchart.power_only, "output power data only"),
OPT_BOOLEAN('T', "tasks-only", &tchart.tasks_only,
"output processes data only"),
@@ -1972,7 +1972,7 @@ int cmd_timechart(int argc, const char **argv,
OPT_BOOLEAN('g', "callchain", &tchart.with_backtrace, "record callchain"),
OPT_END()
};
- const char * const record_usage[] = {
+ const char * const timechart_record_usage[] = {
"perf timechart record [<options>]",
NULL
};
@@ -1985,7 +1985,8 @@ int cmd_timechart(int argc, const char **argv,
}
if (argc && !strncmp(argv[0], "rec", 3)) {
- argc = parse_options(argc, argv, record_options, record_usage,
+ argc = parse_options(argc, argv, timechart_record_options,
+ timechart_record_usage,
PARSE_OPT_STOP_AT_NON_OPTION);
if (tchart.power_only && tchart.tasks_only) {
diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
index fb12645..83a4835 100644
--- a/tools/perf/builtin-trace.c
+++ b/tools/perf/builtin-trace.c
@@ -1846,7 +1846,7 @@ static int trace__pgfault(struct trace *trace,
if (trace->summary_only)
return 0;
- thread__find_addr_location(thread, trace->host, cpumode, MAP__FUNCTION,
+ thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
sample->ip, &al);
trace__fprintf_entry_head(trace, thread, 0, sample->time, trace->output);
@@ -1859,11 +1859,11 @@ static int trace__pgfault(struct trace *trace,
fprintf(trace->output, "] => ");
- thread__find_addr_location(thread, trace->host, cpumode, MAP__VARIABLE,
+ thread__find_addr_location(thread, cpumode, MAP__VARIABLE,
sample->addr, &al);
if (!al.map) {
- thread__find_addr_location(thread, trace->host, cpumode,
+ thread__find_addr_location(thread, cpumode,
MAP__FUNCTION, sample->addr, &al);
if (al.map)
diff --git a/tools/perf/config/Makefile b/tools/perf/config/Makefile
index 58f6091..5d4b039 100644
--- a/tools/perf/config/Makefile
+++ b/tools/perf/config/Makefile
@@ -150,7 +150,7 @@ CFLAGS += -std=gnu99
# adding assembler files missing the .GNU-stack linker note.
LDFLAGS += -Wl,-z,noexecstack
-EXTLIBS = -lelf -lpthread -lrt -lm -ldl
+EXTLIBS = -lpthread -lrt -lm -ldl
ifneq ($(OUTPUT),)
OUTPUT_FEATURES = $(OUTPUT)config/feature-checks/
@@ -200,7 +200,8 @@ CORE_FEATURE_TESTS = \
libunwind \
stackprotector-all \
timerfd \
- libdw-dwarf-unwind
+ libdw-dwarf-unwind \
+ zlib
LIB_FEATURE_TESTS = \
dwarf \
@@ -214,7 +215,8 @@ LIB_FEATURE_TESTS = \
libpython \
libslang \
libunwind \
- libdw-dwarf-unwind
+ libdw-dwarf-unwind \
+ zlib
VF_FEATURE_TESTS = \
backtrace \
@@ -230,7 +232,9 @@ VF_FEATURE_TESTS = \
bionic \
liberty \
liberty-z \
- cplus-demangle
+ cplus-demangle \
+ compile-32 \
+ compile-x32
# Set FEATURE_CHECK_(C|LD)FLAGS-all for all CORE_FEATURE_TESTS features.
# If in the future we need per-feature checks/flags for features not
@@ -350,6 +354,7 @@ endif # NO_LIBELF
ifndef NO_LIBELF
CFLAGS += -DHAVE_LIBELF_SUPPORT
+ EXTLIBS += -lelf
ifeq ($(feature-libelf-mmap), 1)
CFLAGS += -DHAVE_LIBELF_MMAP_SUPPORT
@@ -369,7 +374,7 @@ ifndef NO_LIBELF
else
CFLAGS += -DHAVE_DWARF_SUPPORT $(LIBDW_CFLAGS)
LDFLAGS += $(LIBDW_LDFLAGS)
- EXTLIBS += -lelf -ldw
+ EXTLIBS += -ldw
endif # PERF_HAVE_DWARF_REGS
endif # NO_DWARF
endif # NO_LIBELF
@@ -602,6 +607,15 @@ ifneq ($(filter -lbfd,$(EXTLIBS)),)
CFLAGS += -DHAVE_LIBBFD_SUPPORT
endif
+ifndef NO_ZLIB
+ ifeq ($(feature-zlib), 1)
+ CFLAGS += -DHAVE_ZLIB_SUPPORT
+ EXTLIBS += -lz
+ else
+ NO_ZLIB := 1
+ endif
+endif
+
ifndef NO_BACKTRACE
ifeq ($(feature-backtrace), 1)
CFLAGS += -DHAVE_BACKTRACE_SUPPORT
@@ -622,6 +636,31 @@ ifdef HAVE_KVM_STAT_SUPPORT
CFLAGS += -DHAVE_KVM_STAT_SUPPORT
endif
+ifeq (${IS_64_BIT}, 1)
+ ifndef NO_PERF_READ_VDSO32
+ $(call feature_check,compile-32)
+ ifeq ($(feature-compile-32), 1)
+ CFLAGS += -DHAVE_PERF_READ_VDSO32
+ else
+ NO_PERF_READ_VDSO32 := 1
+ endif
+ endif
+ ifneq (${IS_X86_64}, 1)
+ NO_PERF_READ_VDSOX32 := 1
+ endif
+ ifndef NO_PERF_READ_VDSOX32
+ $(call feature_check,compile-x32)
+ ifeq ($(feature-compile-x32), 1)
+ CFLAGS += -DHAVE_PERF_READ_VDSOX32
+ else
+ NO_PERF_READ_VDSOX32 := 1
+ endif
+ endif
+else
+ NO_PERF_READ_VDSO32 := 1
+ NO_PERF_READ_VDSOX32 := 1
+endif
+
# Among the variables below, these:
# perfexecdir
# template_dir
diff --git a/tools/perf/config/Makefile.arch b/tools/perf/config/Makefile.arch
index 4b06719..851cd01 100644
--- a/tools/perf/config/Makefile.arch
+++ b/tools/perf/config/Makefile.arch
@@ -21,3 +21,11 @@ ifeq ($(ARCH),x86_64)
RAW_ARCH := x86_64
endif
endif
+
+ifeq (${IS_X86_64}, 1)
+ IS_64_BIT := 1
+else ifeq ($(ARCH),x86)
+ IS_64_BIT := 0
+else
+ IS_64_BIT := $(shell echo __LP64__ | ${CC} ${CFLAGS} -E -x c - | tail -n 1)
+endif
diff --git a/tools/perf/config/feature-checks/Makefile b/tools/perf/config/feature-checks/Makefile
index 72ab298..53f19b5 100644
--- a/tools/perf/config/feature-checks/Makefile
+++ b/tools/perf/config/feature-checks/Makefile
@@ -27,7 +27,10 @@ FILES= \
test-libunwind-debug-frame.bin \
test-stackprotector-all.bin \
test-timerfd.bin \
- test-libdw-dwarf-unwind.bin
+ test-libdw-dwarf-unwind.bin \
+ test-compile-32.bin \
+ test-compile-x32.bin \
+ test-zlib.bin
CC := $(CROSS_COMPILE)gcc -MD
PKG_CONFIG := $(CROSS_COMPILE)pkg-config
@@ -39,7 +42,7 @@ BUILD = $(CC) $(CFLAGS) -o $(OUTPUT)$@ $(patsubst %.bin,%.c,$@) $(LDFLAGS)
###############################
test-all.bin:
- $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl
+ $(BUILD) -Werror -fstack-protector-all -O2 -Werror -D_FORTIFY_SOURCE=2 -ldw -lelf -lnuma -lelf -laudit -I/usr/include/slang -lslang $(shell $(PKG_CONFIG) --libs --cflags gtk+-2.0 2>/dev/null) $(FLAGS_PERL_EMBED) $(FLAGS_PYTHON_EMBED) -DPACKAGE='"perf"' -lbfd -ldl -lz
test-hello.bin:
$(BUILD)
@@ -131,6 +134,15 @@ test-libdw-dwarf-unwind.bin:
test-sync-compare-and-swap.bin:
$(BUILD) -Werror
+test-compile-32.bin:
+ $(CC) -m32 -o $(OUTPUT)$@ test-compile.c
+
+test-compile-x32.bin:
+ $(CC) -mx32 -o $(OUTPUT)$@ test-compile.c
+
+test-zlib.bin:
+ $(BUILD) -lz
+
-include *.d
###############################
diff --git a/tools/perf/config/feature-checks/test-all.c b/tools/perf/config/feature-checks/test-all.c
index a7d022e..652e009 100644
--- a/tools/perf/config/feature-checks/test-all.c
+++ b/tools/perf/config/feature-checks/test-all.c
@@ -93,6 +93,10 @@
# include "test-sync-compare-and-swap.c"
#undef main
+#define main main_test_zlib
+# include "test-zlib.c"
+#undef main
+
int main(int argc, char *argv[])
{
main_test_libpython();
@@ -116,6 +120,7 @@ int main(int argc, char *argv[])
main_test_stackprotector_all();
main_test_libdw_dwarf_unwind();
main_test_sync_compare_and_swap(argc, argv);
+ main_test_zlib();
return 0;
}
diff --git a/tools/perf/config/feature-checks/test-compile.c b/tools/perf/config/feature-checks/test-compile.c
new file mode 100644
index 0000000..31dbf45
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-compile.c
@@ -0,0 +1,4 @@
+int main(void)
+{
+ return 0;
+}
diff --git a/tools/perf/config/feature-checks/test-zlib.c b/tools/perf/config/feature-checks/test-zlib.c
new file mode 100644
index 0000000..e111fff
--- /dev/null
+++ b/tools/perf/config/feature-checks/test-zlib.c
@@ -0,0 +1,9 @@
+#include <zlib.h>
+
+int main(void)
+{
+ z_stream zs;
+
+ inflateInit(&zs);
+ return 0;
+}
diff --git a/tools/perf/perf-read-vdso.c b/tools/perf/perf-read-vdso.c
new file mode 100644
index 0000000..764e254
--- /dev/null
+++ b/tools/perf/perf-read-vdso.c
@@ -0,0 +1,34 @@
+#include <stdio.h>
+#include <string.h>
+
+#define VDSO__MAP_NAME "[vdso]"
+
+/*
+ * Include definition of find_vdso_map() also used in util/vdso.c for
+ * building perf.
+ */
+#include "util/find-vdso-map.c"
+
+int main(void)
+{
+ void *start, *end;
+ size_t size, written;
+
+ if (find_vdso_map(&start, &end))
+ return 1;
+
+ size = end - start;
+
+ while (size) {
+ written = fwrite(start, 1, size, stdout);
+ if (!written)
+ return 1;
+ start += written;
+ size -= written;
+ }
+
+ if (fflush(stdout))
+ return 1;
+
+ return 0;
+}
diff --git a/tools/perf/perf.h b/tools/perf/perf.h
index 220d44e..1dabb85 100644
--- a/tools/perf/perf.h
+++ b/tools/perf/perf.h
@@ -52,6 +52,7 @@ struct record_opts {
bool sample_weight;
bool sample_time;
bool period;
+ bool sample_intr_regs;
unsigned int freq;
unsigned int mmap_pages;
unsigned int user_freq;
@@ -62,4 +63,7 @@ struct record_opts {
unsigned initial_delay;
};
+struct option;
+extern const char * const *record_usage;
+extern struct option *record_options;
#endif
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-record b/tools/perf/scripts/python/bin/export-to-postgresql-record
new file mode 100644
index 0000000..221d66e
--- /dev/null
+++ b/tools/perf/scripts/python/bin/export-to-postgresql-record
@@ -0,0 +1,8 @@
+#!/bin/bash
+
+#
+# export perf data to a postgresql database. Can cover
+# perf ip samples (excluding the tracepoints). No special
+# record requirements, just record what you want to export.
+#
+perf record $@
diff --git a/tools/perf/scripts/python/bin/export-to-postgresql-report b/tools/perf/scripts/python/bin/export-to-postgresql-report
new file mode 100644
index 0000000..cd335b6
--- /dev/null
+++ b/tools/perf/scripts/python/bin/export-to-postgresql-report
@@ -0,0 +1,29 @@
+#!/bin/bash
+# description: export perf data to a postgresql database
+# args: [database name] [columns] [calls]
+n_args=0
+for i in "$@"
+do
+ if expr match "$i" "-" > /dev/null ; then
+ break
+ fi
+ n_args=$(( $n_args + 1 ))
+done
+if [ "$n_args" -gt 3 ] ; then
+ echo "usage: export-to-postgresql-report [database name] [columns] [calls]"
+ exit
+fi
+if [ "$n_args" -gt 2 ] ; then
+ dbname=$1
+ columns=$2
+ calls=$3
+ shift 3
+elif [ "$n_args" -gt 1 ] ; then
+ dbname=$1
+ columns=$2
+ shift 2
+elif [ "$n_args" -gt 0 ] ; then
+ dbname=$1
+ shift
+fi
+perf script $@ -s "$PERF_EXEC_PATH"/scripts/python/export-to-postgresql.py $dbname $columns $calls
diff --git a/tools/perf/scripts/python/export-to-postgresql.py b/tools/perf/scripts/python/export-to-postgresql.py
new file mode 100644
index 0000000..4cdafd8
--- /dev/null
+++ b/tools/perf/scripts/python/export-to-postgresql.py
@@ -0,0 +1,444 @@
+# export-to-postgresql.py: export perf data to a postgresql database
+# Copyright (c) 2014, Intel Corporation.
+#
+# This program is free software; you can redistribute it and/or modify it
+# under the terms and conditions of the GNU General Public License,
+# version 2, as published by the Free Software Foundation.
+#
+# This program is distributed in the hope it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+# more details.
+
+import os
+import sys
+import struct
+import datetime
+
+from PySide.QtSql import *
+
+# Need to access PostgreSQL C library directly to use COPY FROM STDIN
+from ctypes import *
+libpq = CDLL("libpq.so.5")
+PQconnectdb = libpq.PQconnectdb
+PQconnectdb.restype = c_void_p
+PQfinish = libpq.PQfinish
+PQstatus = libpq.PQstatus
+PQexec = libpq.PQexec
+PQexec.restype = c_void_p
+PQresultStatus = libpq.PQresultStatus
+PQputCopyData = libpq.PQputCopyData
+PQputCopyData.argtypes = [ c_void_p, c_void_p, c_int ]
+PQputCopyEnd = libpq.PQputCopyEnd
+PQputCopyEnd.argtypes = [ c_void_p, c_void_p ]
+
+sys.path.append(os.environ['PERF_EXEC_PATH'] + \
+ '/scripts/python/Perf-Trace-Util/lib/Perf/Trace')
+
+# These perf imports are not used at present
+#from perf_trace_context import *
+#from Core import *
+
+perf_db_export_mode = True
+perf_db_export_calls = False
+
+def usage():
+ print >> sys.stderr, "Usage is: export-to-postgresql.py <database name> [<columns>] [<calls>]"
+ print >> sys.stderr, "where: columns 'all' or 'branches'"
+ print >> sys.stderr, " calls 'calls' => create calls table"
+ raise Exception("Too few arguments")
+
+if (len(sys.argv) < 2):
+ usage()
+
+dbname = sys.argv[1]
+
+if (len(sys.argv) >= 3):
+ columns = sys.argv[2]
+else:
+ columns = "all"
+
+if columns not in ("all", "branches"):
+ usage()
+
+branches = (columns == "branches")
+
+if (len(sys.argv) >= 4):
+ if (sys.argv[3] == "calls"):
+ perf_db_export_calls = True
+ else:
+ usage()
+
+output_dir_name = os.getcwd() + "/" + dbname + "-perf-data"
+os.mkdir(output_dir_name)
+
+def do_query(q, s):
+ if (q.exec_(s)):
+ return
+ raise Exception("Query failed: " + q.lastError().text())
+
+print datetime.datetime.today(), "Creating database..."
+
+db = QSqlDatabase.addDatabase('QPSQL')
+query = QSqlQuery(db)
+db.setDatabaseName('postgres')
+db.open()
+try:
+ do_query(query, 'CREATE DATABASE ' + dbname)
+except:
+ os.rmdir(output_dir_name)
+ raise
+query.finish()
+query.clear()
+db.close()
+
+db.setDatabaseName(dbname)
+db.open()
+
+query = QSqlQuery(db)
+do_query(query, 'SET client_min_messages TO WARNING')
+
+do_query(query, 'CREATE TABLE selected_events ('
+ 'id bigint NOT NULL,'
+ 'name varchar(80))')
+do_query(query, 'CREATE TABLE machines ('
+ 'id bigint NOT NULL,'
+ 'pid integer,'
+ 'root_dir varchar(4096))')
+do_query(query, 'CREATE TABLE threads ('
+ 'id bigint NOT NULL,'
+ 'machine_id bigint,'
+ 'process_id bigint,'
+ 'pid integer,'
+ 'tid integer)')
+do_query(query, 'CREATE TABLE comms ('
+ 'id bigint NOT NULL,'
+ 'comm varchar(16))')
+do_query(query, 'CREATE TABLE comm_threads ('
+ 'id bigint NOT NULL,'
+ 'comm_id bigint,'
+ 'thread_id bigint)')
+do_query(query, 'CREATE TABLE dsos ('
+ 'id bigint NOT NULL,'
+ 'machine_id bigint,'
+ 'short_name varchar(256),'
+ 'long_name varchar(4096),'
+ 'build_id varchar(64))')
+do_query(query, 'CREATE TABLE symbols ('
+ 'id bigint NOT NULL,'
+ 'dso_id bigint,'
+ 'sym_start bigint,'
+ 'sym_end bigint,'
+ 'binding integer,'
+ 'name varchar(2048))')
+do_query(query, 'CREATE TABLE branch_types ('
+ 'id integer NOT NULL,'
+ 'name varchar(80))')
+
+if branches:
+ do_query(query, 'CREATE TABLE samples ('
+ 'id bigint NOT NULL,'
+ 'evsel_id bigint,'
+ 'machine_id bigint,'
+ 'thread_id bigint,'
+ 'comm_id bigint,'
+ 'dso_id bigint,'
+ 'symbol_id bigint,'
+ 'sym_offset bigint,'
+ 'ip bigint,'
+ 'time bigint,'
+ 'cpu integer,'
+ 'to_dso_id bigint,'
+ 'to_symbol_id bigint,'
+ 'to_sym_offset bigint,'
+ 'to_ip bigint,'
+ 'branch_type integer,'
+ 'in_tx boolean)')
+else:
+ do_query(query, 'CREATE TABLE samples ('
+ 'id bigint NOT NULL,'
+ 'evsel_id bigint,'
+ 'machine_id bigint,'
+ 'thread_id bigint,'
+ 'comm_id bigint,'
+ 'dso_id bigint,'
+ 'symbol_id bigint,'
+ 'sym_offset bigint,'
+ 'ip bigint,'
+ 'time bigint,'
+ 'cpu integer,'
+ 'to_dso_id bigint,'
+ 'to_symbol_id bigint,'
+ 'to_sym_offset bigint,'
+ 'to_ip bigint,'
+ 'period bigint,'
+ 'weight bigint,'
+ 'transaction bigint,'
+ 'data_src bigint,'
+ 'branch_type integer,'
+ 'in_tx boolean)')
+
+if perf_db_export_calls:
+ do_query(query, 'CREATE TABLE call_paths ('
+ 'id bigint NOT NULL,'
+ 'parent_id bigint,'
+ 'symbol_id bigint,'
+ 'ip bigint)')
+ do_query(query, 'CREATE TABLE calls ('
+ 'id bigint NOT NULL,'
+ 'thread_id bigint,'
+ 'comm_id bigint,'
+ 'call_path_id bigint,'
+ 'call_time bigint,'
+ 'return_time bigint,'
+ 'branch_count bigint,'
+ 'call_id bigint,'
+ 'return_id bigint,'
+ 'parent_call_path_id bigint,'
+ 'flags integer)')
+
+do_query(query, 'CREATE VIEW samples_view AS '
+ 'SELECT '
+ 'id,'
+ 'time,'
+ 'cpu,'
+ '(SELECT pid FROM threads WHERE id = thread_id) AS pid,'
+ '(SELECT tid FROM threads WHERE id = thread_id) AS tid,'
+ '(SELECT comm FROM comms WHERE id = comm_id) AS command,'
+ '(SELECT name FROM selected_events WHERE id = evsel_id) AS event,'
+ 'to_hex(ip) AS ip_hex,'
+ '(SELECT name FROM symbols WHERE id = symbol_id) AS symbol,'
+ 'sym_offset,'
+ '(SELECT short_name FROM dsos WHERE id = dso_id) AS dso_short_name,'
+ 'to_hex(to_ip) AS to_ip_hex,'
+ '(SELECT name FROM symbols WHERE id = to_symbol_id) AS to_symbol,'
+ 'to_sym_offset,'
+ '(SELECT short_name FROM dsos WHERE id = to_dso_id) AS to_dso_short_name,'
+ '(SELECT name FROM branch_types WHERE id = branch_type) AS branch_type_name,'
+ 'in_tx'
+ ' FROM samples')
+
+
+file_header = struct.pack("!11sii", "PGCOPY\n\377\r\n\0", 0, 0)
+file_trailer = "\377\377"
+
+def open_output_file(file_name):
+ path_name = output_dir_name + "/" + file_name
+ file = open(path_name, "w+")
+ file.write(file_header)
+ return file
+
+def close_output_file(file):
+ file.write(file_trailer)
+ file.close()
+
+def copy_output_file_direct(file, table_name):
+ close_output_file(file)
+ sql = "COPY " + table_name + " FROM '" + file.name + "' (FORMAT 'binary')"
+ do_query(query, sql)
+
+# Use COPY FROM STDIN because security may prevent postgres from accessing the files directly
+def copy_output_file(file, table_name):
+ conn = PQconnectdb("dbname = " + dbname)
+ if (PQstatus(conn)):
+ raise Exception("COPY FROM STDIN PQconnectdb failed")
+ file.write(file_trailer)
+ file.seek(0)
+ sql = "COPY " + table_name + " FROM STDIN (FORMAT 'binary')"
+ res = PQexec(conn, sql)
+ if (PQresultStatus(res) != 4):
+ raise Exception("COPY FROM STDIN PQexec failed")
+ data = file.read(65536)
+ while (len(data)):
+ ret = PQputCopyData(conn, data, len(data))
+ if (ret != 1):
+ raise Exception("COPY FROM STDIN PQputCopyData failed, error " + str(ret))
+ data = file.read(65536)
+ ret = PQputCopyEnd(conn, None)
+ if (ret != 1):
+ raise Exception("COPY FROM STDIN PQputCopyEnd failed, error " + str(ret))
+ PQfinish(conn)
+
+def remove_output_file(file):
+ name = file.name
+ file.close()
+ os.unlink(name)
+
+evsel_file = open_output_file("evsel_table.bin")
+machine_file = open_output_file("machine_table.bin")
+thread_file = open_output_file("thread_table.bin")
+comm_file = open_output_file("comm_table.bin")
+comm_thread_file = open_output_file("comm_thread_table.bin")
+dso_file = open_output_file("dso_table.bin")
+symbol_file = open_output_file("symbol_table.bin")
+branch_type_file = open_output_file("branch_type_table.bin")
+sample_file = open_output_file("sample_table.bin")
+if perf_db_export_calls:
+ call_path_file = open_output_file("call_path_table.bin")
+ call_file = open_output_file("call_table.bin")
+
+def trace_begin():
+ print datetime.datetime.today(), "Writing to intermediate files..."
+ # id == 0 means unknown. It is easier to create records for them than replace the zeroes with NULLs
+ evsel_table(0, "unknown")
+ machine_table(0, 0, "unknown")
+ thread_table(0, 0, 0, -1, -1)
+ comm_table(0, "unknown")
+ dso_table(0, 0, "unknown", "unknown", "")
+ symbol_table(0, 0, 0, 0, 0, "unknown")
+ sample_table(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)
+ if perf_db_export_calls:
+ call_path_table(0, 0, 0, 0)
+
+unhandled_count = 0
+
+def trace_end():
+ print datetime.datetime.today(), "Copying to database..."
+ copy_output_file(evsel_file, "selected_events")
+ copy_output_file(machine_file, "machines")
+ copy_output_file(thread_file, "threads")
+ copy_output_file(comm_file, "comms")
+ copy_output_file(comm_thread_file, "comm_threads")
+ copy_output_file(dso_file, "dsos")
+ copy_output_file(symbol_file, "symbols")
+ copy_output_file(branch_type_file, "branch_types")
+ copy_output_file(sample_file, "samples")
+ if perf_db_export_calls:
+ copy_output_file(call_path_file, "call_paths")
+ copy_output_file(call_file, "calls")
+
+ print datetime.datetime.today(), "Removing intermediate files..."
+ remove_output_file(evsel_file)
+ remove_output_file(machine_file)
+ remove_output_file(thread_file)
+ remove_output_file(comm_file)
+ remove_output_file(comm_thread_file)
+ remove_output_file(dso_file)
+ remove_output_file(symbol_file)
+ remove_output_file(branch_type_file)
+ remove_output_file(sample_file)
+ if perf_db_export_calls:
+ remove_output_file(call_path_file)
+ remove_output_file(call_file)
+ os.rmdir(output_dir_name)
+ print datetime.datetime.today(), "Adding primary keys"
+ do_query(query, 'ALTER TABLE selected_events ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE machines ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE threads ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE comms ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE comm_threads ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE dsos ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE symbols ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE branch_types ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE samples ADD PRIMARY KEY (id)')
+ if perf_db_export_calls:
+ do_query(query, 'ALTER TABLE call_paths ADD PRIMARY KEY (id)')
+ do_query(query, 'ALTER TABLE calls ADD PRIMARY KEY (id)')
+
+ print datetime.datetime.today(), "Adding foreign keys"
+ do_query(query, 'ALTER TABLE threads '
+ 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id),'
+ 'ADD CONSTRAINT processfk FOREIGN KEY (process_id) REFERENCES threads (id)')
+ do_query(query, 'ALTER TABLE comm_threads '
+ 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
+ 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id)')
+ do_query(query, 'ALTER TABLE dsos '
+ 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id)')
+ do_query(query, 'ALTER TABLE symbols '
+ 'ADD CONSTRAINT dsofk FOREIGN KEY (dso_id) REFERENCES dsos (id)')
+ do_query(query, 'ALTER TABLE samples '
+ 'ADD CONSTRAINT evselfk FOREIGN KEY (evsel_id) REFERENCES selected_events (id),'
+ 'ADD CONSTRAINT machinefk FOREIGN KEY (machine_id) REFERENCES machines (id),'
+ 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
+ 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
+ 'ADD CONSTRAINT dsofk FOREIGN KEY (dso_id) REFERENCES dsos (id),'
+ 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id),'
+ 'ADD CONSTRAINT todsofk FOREIGN KEY (to_dso_id) REFERENCES dsos (id),'
+ 'ADD CONSTRAINT tosymbolfk FOREIGN KEY (to_symbol_id) REFERENCES symbols (id)')
+ if perf_db_export_calls:
+ do_query(query, 'ALTER TABLE call_paths '
+ 'ADD CONSTRAINT parentfk FOREIGN KEY (parent_id) REFERENCES call_paths (id),'
+ 'ADD CONSTRAINT symbolfk FOREIGN KEY (symbol_id) REFERENCES symbols (id)')
+ do_query(query, 'ALTER TABLE calls '
+ 'ADD CONSTRAINT threadfk FOREIGN KEY (thread_id) REFERENCES threads (id),'
+ 'ADD CONSTRAINT commfk FOREIGN KEY (comm_id) REFERENCES comms (id),'
+ 'ADD CONSTRAINT call_pathfk FOREIGN KEY (call_path_id) REFERENCES call_paths (id),'
+ 'ADD CONSTRAINT callfk FOREIGN KEY (call_id) REFERENCES samples (id),'
+ 'ADD CONSTRAINT returnfk FOREIGN KEY (return_id) REFERENCES samples (id),'
+ 'ADD CONSTRAINT parent_call_pathfk FOREIGN KEY (parent_call_path_id) REFERENCES call_paths (id)')
+ do_query(query, 'CREATE INDEX pcpid_idx ON calls (parent_call_path_id)')
+
+ if (unhandled_count):
+ print datetime.datetime.today(), "Warning: ", unhandled_count, " unhandled events"
+ print datetime.datetime.today(), "Done"
+
+def trace_unhandled(event_name, context, event_fields_dict):
+ global unhandled_count
+ unhandled_count += 1
+
+def sched__sched_switch(*x):
+ pass
+
+def evsel_table(evsel_id, evsel_name, *x):
+ n = len(evsel_name)
+ fmt = "!hiqi" + str(n) + "s"
+ value = struct.pack(fmt, 2, 8, evsel_id, n, evsel_name)
+ evsel_file.write(value)
+
+def machine_table(machine_id, pid, root_dir, *x):
+ n = len(root_dir)
+ fmt = "!hiqiii" + str(n) + "s"
+ value = struct.pack(fmt, 3, 8, machine_id, 4, pid, n, root_dir)
+ machine_file.write(value)
+
+def thread_table(thread_id, machine_id, process_id, pid, tid, *x):
+ value = struct.pack("!hiqiqiqiiii", 5, 8, thread_id, 8, machine_id, 8, process_id, 4, pid, 4, tid)
+ thread_file.write(value)
+
+def comm_table(comm_id, comm_str, *x):
+ n = len(comm_str)
+ fmt = "!hiqi" + str(n) + "s"
+ value = struct.pack(fmt, 2, 8, comm_id, n, comm_str)
+ comm_file.write(value)
+
+def comm_thread_table(comm_thread_id, comm_id, thread_id, *x):
+ fmt = "!hiqiqiq"
+ value = struct.pack(fmt, 3, 8, comm_thread_id, 8, comm_id, 8, thread_id)
+ comm_thread_file.write(value)
+
+def dso_table(dso_id, machine_id, short_name, long_name, build_id, *x):
+ n1 = len(short_name)
+ n2 = len(long_name)
+ n3 = len(build_id)
+ fmt = "!hiqiqi" + str(n1) + "si" + str(n2) + "si" + str(n3) + "s"
+ value = struct.pack(fmt, 5, 8, dso_id, 8, machine_id, n1, short_name, n2, long_name, n3, build_id)
+ dso_file.write(value)
+
+def symbol_table(symbol_id, dso_id, sym_start, sym_end, binding, symbol_name, *x):
+ n = len(symbol_name)
+ fmt = "!hiqiqiqiqiii" + str(n) + "s"
+ value = struct.pack(fmt, 6, 8, symbol_id, 8, dso_id, 8, sym_start, 8, sym_end, 4, binding, n, symbol_name)
+ symbol_file.write(value)
+
+def branch_type_table(branch_type, name, *x):
+ n = len(name)
+ fmt = "!hiii" + str(n) + "s"
+ value = struct.pack(fmt, 2, 4, branch_type, n, name)
+ branch_type_file.write(value)
+
+def sample_table(sample_id, evsel_id, machine_id, thread_id, comm_id, dso_id, symbol_id, sym_offset, ip, time, cpu, to_dso_id, to_symbol_id, to_sym_offset, to_ip, period, weight, transaction, data_src, branch_type, in_tx, *x):
+ if branches:
+ value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiiiB", 17, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 4, branch_type, 1, in_tx)
+ else:
+ value = struct.pack("!hiqiqiqiqiqiqiqiqiqiqiiiqiqiqiqiqiqiqiqiiiB", 21, 8, sample_id, 8, evsel_id, 8, machine_id, 8, thread_id, 8, comm_id, 8, dso_id, 8, symbol_id, 8, sym_offset, 8, ip, 8, time, 4, cpu, 8, to_dso_id, 8, to_symbol_id, 8, to_sym_offset, 8, to_ip, 8, period, 8, weight, 8, transaction, 8, data_src, 4, branch_type, 1, in_tx)
+ sample_file.write(value)
+
+def call_path_table(cp_id, parent_id, symbol_id, ip, *x):
+ fmt = "!hiqiqiqiq"
+ value = struct.pack(fmt, 4, 8, cp_id, 8, parent_id, 8, symbol_id, 8, ip)
+ call_path_file.write(value)
+
+def call_return_table(cr_id, thread_id, comm_id, call_path_id, call_time, return_time, branch_count, call_id, return_id, parent_call_path_id, flags, *x):
+ fmt = "!hiqiqiqiqiqiqiqiqiqiqii"
+ value = struct.pack(fmt, 11, 8, cr_id, 8, thread_id, 8, comm_id, 8, call_path_id, 8, call_time, 8, return_time, 8, branch_count, 8, call_id, 8, return_id, 8, parent_call_path_id, 4, flags)
+ call_file.write(value)
diff --git a/tools/perf/tests/builtin-test.c b/tools/perf/tests/builtin-test.c
index 162c978..4b7d9ab 100644
--- a/tools/perf/tests/builtin-test.c
+++ b/tools/perf/tests/builtin-test.c
@@ -85,7 +85,7 @@ static struct test {
.func = test__hists_link,
},
{
- .desc = "Try 'use perf' in python, checking link problems",
+ .desc = "Try 'import perf' in python, checking link problems",
.func = test__python_use,
},
{
diff --git a/tools/perf/tests/code-reading.c b/tools/perf/tests/code-reading.c
index 67f2d63..f671ec3 100644
--- a/tools/perf/tests/code-reading.c
+++ b/tools/perf/tests/code-reading.c
@@ -133,8 +133,7 @@ static int read_via_objdump(const char *filename, u64 addr, void *buf,
}
static int read_object_code(u64 addr, size_t len, u8 cpumode,
- struct thread *thread, struct machine *machine,
- struct state *state)
+ struct thread *thread, struct state *state)
{
struct addr_location al;
unsigned char buf1[BUFSZ];
@@ -145,8 +144,7 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
pr_debug("Reading object code for memory address: %#"PRIx64"\n", addr);
- thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION, addr,
- &al);
+ thread__find_addr_map(thread, cpumode, MAP__FUNCTION, addr, &al);
if (!al.map || !al.map->dso) {
pr_debug("thread__find_addr_map failed\n");
return -1;
@@ -170,8 +168,8 @@ static int read_object_code(u64 addr, size_t len, u8 cpumode,
len = al.map->end - addr;
/* Read the object code using perf */
- ret_len = dso__data_read_offset(al.map->dso, machine, al.addr, buf1,
- len);
+ ret_len = dso__data_read_offset(al.map->dso, thread->mg->machine,
+ al.addr, buf1, len);
if (ret_len != len) {
pr_debug("dso__data_read_offset failed\n");
return -1;
@@ -264,8 +262,7 @@ static int process_sample_event(struct machine *machine,
cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
- return read_object_code(sample.ip, READLEN, cpumode, thread, machine,
- state);
+ return read_object_code(sample.ip, READLEN, cpumode, thread, state);
}
static int process_event(struct machine *machine, struct perf_evlist *evlist,
diff --git a/tools/perf/tests/dwarf-unwind.c b/tools/perf/tests/dwarf-unwind.c
index fc25e57..ab28cca 100644
--- a/tools/perf/tests/dwarf-unwind.c
+++ b/tools/perf/tests/dwarf-unwind.c
@@ -59,7 +59,7 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
}
__attribute__ ((noinline))
-static int unwind_thread(struct thread *thread, struct machine *machine)
+static int unwind_thread(struct thread *thread)
{
struct perf_sample sample;
unsigned long cnt = 0;
@@ -72,7 +72,7 @@ static int unwind_thread(struct thread *thread, struct machine *machine)
goto out;
}
- err = unwind__get_entries(unwind_entry, &cnt, machine, thread,
+ err = unwind__get_entries(unwind_entry, &cnt, thread,
&sample, MAX_STACK);
if (err)
pr_debug("unwind failed\n");
@@ -89,21 +89,21 @@ static int unwind_thread(struct thread *thread, struct machine *machine)
}
__attribute__ ((noinline))
-static int krava_3(struct thread *thread, struct machine *machine)
+static int krava_3(struct thread *thread)
{
- return unwind_thread(thread, machine);
+ return unwind_thread(thread);
}
__attribute__ ((noinline))
-static int krava_2(struct thread *thread, struct machine *machine)
+static int krava_2(struct thread *thread)
{
- return krava_3(thread, machine);
+ return krava_3(thread);
}
__attribute__ ((noinline))
-static int krava_1(struct thread *thread, struct machine *machine)
+static int krava_1(struct thread *thread)
{
- return krava_2(thread, machine);
+ return krava_2(thread);
}
int test__dwarf_unwind(void)
@@ -137,7 +137,7 @@ int test__dwarf_unwind(void)
goto out;
}
- err = krava_1(thread, machine);
+ err = krava_1(thread);
out:
machine__delete_threads(machine);
diff --git a/tools/perf/tests/hists_filter.c b/tools/perf/tests/hists_filter.c
index 5a31787..74f257a 100644
--- a/tools/perf/tests/hists_filter.c
+++ b/tools/perf/tests/hists_filter.c
@@ -43,7 +43,7 @@ static struct sample fake_samples[] = {
};
static int add_hist_entries(struct perf_evlist *evlist,
- struct machine *machine __maybe_unused)
+ struct machine *machine)
{
struct perf_evsel *evsel;
struct addr_location al;
diff --git a/tools/perf/tests/mmap-thread-lookup.c b/tools/perf/tests/mmap-thread-lookup.c
index 4a456fe..2113f1c 100644
--- a/tools/perf/tests/mmap-thread-lookup.c
+++ b/tools/perf/tests/mmap-thread-lookup.c
@@ -187,7 +187,7 @@ static int mmap_events(synth_cb synth)
pr_debug("looking for map %p\n", td->map);
- thread__find_addr_map(thread, machine,
+ thread__find_addr_map(thread,
PERF_RECORD_MISC_USER, MAP__FUNCTION,
(unsigned long) (td->map + 1), &al);
diff --git a/tools/perf/tests/sample-parsing.c b/tools/perf/tests/sample-parsing.c
index ca292f9..4908c64 100644
--- a/tools/perf/tests/sample-parsing.c
+++ b/tools/perf/tests/sample-parsing.c
@@ -126,16 +126,28 @@ static bool samples_same(const struct perf_sample *s1,
if (type & PERF_SAMPLE_TRANSACTION)
COMP(transaction);
+ if (type & PERF_SAMPLE_REGS_INTR) {
+ size_t sz = hweight_long(s1->intr_regs.mask) * sizeof(u64);
+
+ COMP(intr_regs.mask);
+ COMP(intr_regs.abi);
+ if (s1->intr_regs.abi &&
+ (!s1->intr_regs.regs || !s2->intr_regs.regs ||
+ memcmp(s1->intr_regs.regs, s2->intr_regs.regs, sz))) {
+ pr_debug("Samples differ at 'intr_regs'\n");
+ return false;
+ }
+ }
+
return true;
}
-static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
+static int do_test(u64 sample_type, u64 sample_regs, u64 read_format)
{
struct perf_evsel evsel = {
.needs_swap = false,
.attr = {
.sample_type = sample_type,
- .sample_regs_user = sample_regs_user,
.read_format = read_format,
},
};
@@ -154,7 +166,7 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
/* 1 branch_entry */
.data = {1, 211, 212, 213},
};
- u64 user_regs[64];
+ u64 regs[64];
const u64 raw_data[] = {0x123456780a0b0c0dULL, 0x1102030405060708ULL};
const u64 data[] = {0x2211443366558877ULL, 0, 0xaabbccddeeff4321ULL};
struct perf_sample sample = {
@@ -176,8 +188,8 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.branch_stack = &branch_stack.branch_stack,
.user_regs = {
.abi = PERF_SAMPLE_REGS_ABI_64,
- .mask = sample_regs_user,
- .regs = user_regs,
+ .mask = sample_regs,
+ .regs = regs,
},
.user_stack = {
.size = sizeof(data),
@@ -187,14 +199,25 @@ static int do_test(u64 sample_type, u64 sample_regs_user, u64 read_format)
.time_enabled = 0x030a59d664fca7deULL,
.time_running = 0x011b6ae553eb98edULL,
},
+ .intr_regs = {
+ .abi = PERF_SAMPLE_REGS_ABI_64,
+ .mask = sample_regs,
+ .regs = regs,
+ },
};
struct sample_read_value values[] = {{1, 5}, {9, 3}, {2, 7}, {6, 4},};
struct perf_sample sample_out;
size_t i, sz, bufsz;
int err, ret = -1;
- for (i = 0; i < sizeof(user_regs); i++)
- *(i + (u8 *)user_regs) = i & 0xfe;
+ if (sample_type & PERF_SAMPLE_REGS_USER)
+ evsel.attr.sample_regs_user = sample_regs;
+
+ if (sample_type & PERF_SAMPLE_REGS_INTR)
+ evsel.attr.sample_regs_intr = sample_regs;
+
+ for (i = 0; i < sizeof(regs); i++)
+ *(i + (u8 *)regs) = i & 0xfe;
if (read_format & PERF_FORMAT_GROUP) {
sample.read.group.nr = 4;
@@ -271,7 +294,7 @@ int test__sample_parsing(void)
{
const u64 rf[] = {4, 5, 6, 7, 12, 13, 14, 15};
u64 sample_type;
- u64 sample_regs_user;
+ u64 sample_regs;
size_t i;
int err;
@@ -280,7 +303,7 @@ int test__sample_parsing(void)
* were added. Please actually update the test rather than just change
* the condition below.
*/
- if (PERF_SAMPLE_MAX > PERF_SAMPLE_TRANSACTION << 1) {
+ if (PERF_SAMPLE_MAX > PERF_SAMPLE_REGS_INTR << 1) {
pr_debug("sample format has changed, some new PERF_SAMPLE_ bit was introduced - test needs updating\n");
return -1;
}
@@ -297,22 +320,24 @@ int test__sample_parsing(void)
}
continue;
}
+ sample_regs = 0;
if (sample_type == PERF_SAMPLE_REGS_USER)
- sample_regs_user = 0x3fff;
- else
- sample_regs_user = 0;
+ sample_regs = 0x3fff;
+
+ if (sample_type == PERF_SAMPLE_REGS_INTR)
+ sample_regs = 0xff0fff;
- err = do_test(sample_type, sample_regs_user, 0);
+ err = do_test(sample_type, sample_regs, 0);
if (err)
return err;
}
/* Test all sample format bits together */
sample_type = PERF_SAMPLE_MAX - 1;
- sample_regs_user = 0x3fff;
+ sample_regs = 0x3fff; /* shared yb intr and user regs */
for (i = 0; i < ARRAY_SIZE(rf); i++) {
- err = do_test(sample_type, sample_regs_user, rf[i]);
+ err = do_test(sample_type, sample_regs, rf[i]);
if (err)
return err;
}
diff --git a/tools/perf/ui/browsers/annotate.c b/tools/perf/ui/browsers/annotate.c
index f0697a3..1e0a2fd 100644
--- a/tools/perf/ui/browsers/annotate.c
+++ b/tools/perf/ui/browsers/annotate.c
@@ -27,6 +27,7 @@ static struct annotate_browser_opt {
bool hide_src_code,
use_offset,
jump_arrows,
+ show_linenr,
show_nr_jumps;
} annotate_browser__opts = {
.use_offset = true,
@@ -128,7 +129,11 @@ static void annotate_browser__write(struct ui_browser *browser, void *entry, int
if (!*dl->line)
slsmg_write_nstring(" ", width - pcnt_width);
else if (dl->offset == -1) {
- printed = scnprintf(bf, sizeof(bf), "%*s ",
+ if (dl->line_nr && annotate_browser__opts.show_linenr)
+ printed = scnprintf(bf, sizeof(bf), "%-*d ",
+ ab->addr_width + 1, dl->line_nr);
+ else
+ printed = scnprintf(bf, sizeof(bf), "%*s ",
ab->addr_width, " ");
slsmg_write_nstring(bf, printed);
slsmg_write_nstring(dl->line, width - printed - pcnt_width + 1);
@@ -733,6 +738,7 @@ static int annotate_browser__run(struct annotate_browser *browser,
"o Toggle disassembler output/simplified view\n"
"s Toggle source code view\n"
"/ Search string\n"
+ "k Toggle line numbers\n"
"r Run available scripts\n"
"? Search string backwards\n");
continue;
@@ -741,6 +747,10 @@ static int annotate_browser__run(struct annotate_browser *browser,
script_browse(NULL);
continue;
}
+ case 'k':
+ annotate_browser__opts.show_linenr =
+ !annotate_browser__opts.show_linenr;
+ break;
case 'H':
nd = browser->curr_hot;
break;
@@ -984,6 +994,7 @@ static struct annotate_config {
} annotate__configs[] = {
ANNOTATE_CFG(hide_src_code),
ANNOTATE_CFG(jump_arrows),
+ ANNOTATE_CFG(show_linenr),
ANNOTATE_CFG(show_nr_jumps),
ANNOTATE_CFG(use_offset),
};
diff --git a/tools/perf/ui/browsers/hists.c b/tools/perf/ui/browsers/hists.c
index cfb976b..502daff 100644
--- a/tools/perf/ui/browsers/hists.c
+++ b/tools/perf/ui/browsers/hists.c
@@ -227,10 +227,14 @@ static void callchain_node__init_have_children_rb_tree(struct callchain_node *no
}
}
-static void callchain_node__init_have_children(struct callchain_node *node)
+static void callchain_node__init_have_children(struct callchain_node *node,
+ bool has_sibling)
{
struct callchain_list *chain;
+ chain = list_entry(node->val.next, struct callchain_list, list);
+ chain->ms.has_children = has_sibling;
+
if (!list_empty(&node->val)) {
chain = list_entry(node->val.prev, struct callchain_list, list);
chain->ms.has_children = !RB_EMPTY_ROOT(&node->rb_root);
@@ -241,11 +245,12 @@ static void callchain_node__init_have_children(struct callchain_node *node)
static void callchain__init_have_children(struct rb_root *root)
{
- struct rb_node *nd;
+ struct rb_node *nd = rb_first(root);
+ bool has_sibling = nd && rb_next(nd);
for (nd = rb_first(root); nd; nd = rb_next(nd)) {
struct callchain_node *node = rb_entry(nd, struct callchain_node, rb_node);
- callchain_node__init_have_children(node);
+ callchain_node__init_have_children(node, has_sibling);
}
}
@@ -463,23 +468,6 @@ out:
return key;
}
-static char *callchain_list__sym_name(struct callchain_list *cl,
- char *bf, size_t bfsize, bool show_dso)
-{
- int printed;
-
- if (cl->ms.sym)
- printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
- else
- printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
-
- if (show_dso)
- scnprintf(bf + printed, bfsize - printed, " %s",
- cl->ms.map ? cl->ms.map->dso->short_name : "unknown");
-
- return bf;
-}
-
struct callchain_print_arg {
/* for hists browser */
off_t row_offset;
@@ -559,8 +547,11 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
struct rb_node *node;
int first_row = row, offset = level * LEVEL_OFFSET_STEP;
u64 new_total;
+ bool need_percent;
node = rb_first(root);
+ need_percent = !!rb_next(node);
+
while (node) {
struct callchain_node *child = rb_entry(node, struct callchain_node, rb_node);
struct rb_node *next = rb_next(node);
@@ -577,7 +568,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
if (first)
first = false;
- else if (level > 1)
+ else if (need_percent)
extra_offset = LEVEL_OFFSET_STEP;
folded_sign = callchain_list__folded(chain);
@@ -590,7 +581,7 @@ static int hist_browser__show_callchain(struct hist_browser *browser,
str = callchain_list__sym_name(chain, bf, sizeof(bf),
browser->show_dso);
- if (was_first && level > 1) {
+ if (was_first && need_percent) {
double percent = cumul * 100.0 / total;
if (asprintf(&alloc_str, "%2.2f%% %s", percent, str) < 0)
@@ -807,6 +798,13 @@ static int hist_browser__show_entry(struct hist_browser *browser,
.is_current_entry = current_entry,
};
+ if (callchain_param.mode == CHAIN_GRAPH_REL) {
+ if (symbol_conf.cumulate_callchain)
+ total = entry->stat_acc->period;
+ else
+ total = entry->stat.period;
+ }
+
printed += hist_browser__show_callchain(browser,
&entry->sorted_chain, 1, row, total,
hist_browser__show_callchain_entry, &arg,
diff --git a/tools/perf/ui/gtk/hists.c b/tools/perf/ui/gtk/hists.c
index fc654fb..4b3585e 100644
--- a/tools/perf/ui/gtk/hists.c
+++ b/tools/perf/ui/gtk/hists.c
@@ -89,15 +89,6 @@ void perf_gtk__init_hpp(void)
perf_gtk__hpp_color_overhead_acc;
}
-static void callchain_list__sym_name(struct callchain_list *cl,
- char *bf, size_t bfsize)
-{
- if (cl->ms.sym)
- scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
- else
- scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
-}
-
static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
GtkTreeIter *parent, int col, u64 total)
{
@@ -128,7 +119,7 @@ static void perf_gtk__add_callchain(struct rb_root *root, GtkTreeStore *store,
scnprintf(buf, sizeof(buf), "%5.2f%%", percent);
gtk_tree_store_set(store, &iter, 0, buf, -1);
- callchain_list__sym_name(chain, buf, sizeof(buf));
+ callchain_list__sym_name(chain, buf, sizeof(buf), false);
gtk_tree_store_set(store, &iter, col, buf, -1);
if (need_new_parent) {
diff --git a/tools/perf/ui/stdio/hist.c b/tools/perf/ui/stdio/hist.c
index 15b451a..dfcbc90 100644
--- a/tools/perf/ui/stdio/hist.c
+++ b/tools/perf/ui/stdio/hist.c
@@ -41,6 +41,7 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
{
int i;
size_t ret = 0;
+ char bf[1024];
ret += callchain__fprintf_left_margin(fp, left_margin);
for (i = 0; i < depth; i++) {
@@ -56,11 +57,8 @@ static size_t ipchain__fprintf_graph(FILE *fp, struct callchain_list *chain,
} else
ret += fprintf(fp, "%s", " ");
}
- if (chain->ms.sym)
- ret += fprintf(fp, "%s\n", chain->ms.sym->name);
- else
- ret += fprintf(fp, "0x%0" PRIx64 "\n", chain->ip);
-
+ fputs(callchain_list__sym_name(chain, bf, sizeof(bf), false), fp);
+ fputc('\n', fp);
return ret;
}
@@ -168,6 +166,7 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
struct rb_node *node;
int i = 0;
int ret = 0;
+ char bf[1024];
/*
* If have one single callchain root, don't bother printing
@@ -196,10 +195,8 @@ static size_t callchain__fprintf_graph(FILE *fp, struct rb_root *root,
} else
ret += callchain__fprintf_left_margin(fp, left_margin);
- if (chain->ms.sym)
- ret += fprintf(fp, " %s\n", chain->ms.sym->name);
- else
- ret += fprintf(fp, " %p\n", (void *)(long)chain->ip);
+ ret += fprintf(fp, "%s\n", callchain_list__sym_name(chain, bf, sizeof(bf),
+ false));
if (++entries_printed == callchain_param.print_limit)
break;
@@ -219,6 +216,7 @@ static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
{
struct callchain_list *chain;
size_t ret = 0;
+ char bf[1024];
if (!node)
return 0;
@@ -229,11 +227,8 @@ static size_t __callchain__fprintf_flat(FILE *fp, struct callchain_node *node,
list_for_each_entry(chain, &node->val, list) {
if (chain->ip >= PERF_CONTEXT_MAX)
continue;
- if (chain->ms.sym)
- ret += fprintf(fp, " %s\n", chain->ms.sym->name);
- else
- ret += fprintf(fp, " %p\n",
- (void *)(long)chain->ip);
+ ret += fprintf(fp, " %s\n", callchain_list__sym_name(chain,
+ bf, sizeof(bf), false));
}
return ret;
diff --git a/tools/perf/util/annotate.c b/tools/perf/util/annotate.c
index 7dabde1..79999ce 100644
--- a/tools/perf/util/annotate.c
+++ b/tools/perf/util/annotate.c
@@ -17,11 +17,13 @@
#include "debug.h"
#include "annotate.h"
#include "evsel.h"
+#include <regex.h>
#include <pthread.h>
#include <linux/bitops.h>
const char *disassembler_style;
const char *objdump_path;
+static regex_t file_lineno;
static struct ins *ins__find(const char *name);
static int disasm_line__parse(char *line, char **namep, char **rawp);
@@ -570,13 +572,15 @@ out_free_name:
return -1;
}
-static struct disasm_line *disasm_line__new(s64 offset, char *line, size_t privsize)
+static struct disasm_line *disasm_line__new(s64 offset, char *line,
+ size_t privsize, int line_nr)
{
struct disasm_line *dl = zalloc(sizeof(*dl) + privsize);
if (dl != NULL) {
dl->offset = offset;
dl->line = strdup(line);
+ dl->line_nr = line_nr;
if (dl->line == NULL)
goto out_delete;
@@ -788,13 +792,15 @@ static int disasm_line__print(struct disasm_line *dl, struct symbol *sym, u64 st
* The ops.raw part will be parsed further according to type of the instruction.
*/
static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
- FILE *file, size_t privsize)
+ FILE *file, size_t privsize,
+ int *line_nr)
{
struct annotation *notes = symbol__annotation(sym);
struct disasm_line *dl;
char *line = NULL, *parsed_line, *tmp, *tmp2, *c;
size_t line_len;
s64 line_ip, offset = -1;
+ regmatch_t match[2];
if (getline(&line, &line_len, file) < 0)
return -1;
@@ -812,6 +818,12 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
line_ip = -1;
parsed_line = line;
+ /* /filename:linenr ? Save line number and ignore. */
+ if (regexec(&file_lineno, line, 2, match, 0) == 0) {
+ *line_nr = atoi(line + match[1].rm_so);
+ return 0;
+ }
+
/*
* Strip leading spaces:
*/
@@ -842,8 +854,9 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
parsed_line = tmp2 + 1;
}
- dl = disasm_line__new(offset, parsed_line, privsize);
+ dl = disasm_line__new(offset, parsed_line, privsize, *line_nr);
free(line);
+ (*line_nr)++;
if (dl == NULL)
return -1;
@@ -869,6 +882,11 @@ static int symbol__parse_objdump_line(struct symbol *sym, struct map *map,
return 0;
}
+static __attribute__((constructor)) void symbol__init_regexpr(void)
+{
+ regcomp(&file_lineno, "^/[^:]+:([0-9]+)", REG_EXTENDED);
+}
+
static void delete_last_nop(struct symbol *sym)
{
struct annotation *notes = symbol__annotation(sym);
@@ -904,6 +922,7 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
char symfs_filename[PATH_MAX];
struct kcore_extract kce;
bool delete_extract = false;
+ int lineno = 0;
if (filename)
symbol__join_symfs(symfs_filename, filename);
@@ -915,6 +934,8 @@ int symbol__annotate(struct symbol *sym, struct map *map, size_t privsize)
return -ENOMEM;
}
goto fallback;
+ } else if (dso__is_kcore(dso)) {
+ goto fallback;
} else if (readlink(symfs_filename, command, sizeof(command)) < 0 ||
strstr(command, "[kernel.kallsyms]") ||
access(symfs_filename, R_OK)) {
@@ -982,7 +1003,7 @@ fallback:
snprintf(command, sizeof(command),
"%s %s%s --start-address=0x%016" PRIx64
" --stop-address=0x%016" PRIx64
- " -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
+ " -l -d %s %s -C %s 2>/dev/null|grep -v %s|expand",
objdump_path ? objdump_path : "objdump",
disassembler_style ? "-M " : "",
disassembler_style ? disassembler_style : "",
@@ -999,7 +1020,8 @@ fallback:
goto out_free_filename;
while (!feof(file))
- if (symbol__parse_objdump_line(sym, map, file, privsize) < 0)
+ if (symbol__parse_objdump_line(sym, map, file, privsize,
+ &lineno) < 0)
break;
/*
@@ -1170,7 +1192,7 @@ static int symbol__get_source_line(struct symbol *sym, struct map *map,
goto next;
offset = start + i;
- src_line->path = get_srcline(map->dso, offset);
+ src_line->path = get_srcline(map->dso, offset, NULL, false);
insert_source_line(&tmp_root, src_line);
next:
diff --git a/tools/perf/util/annotate.h b/tools/perf/util/annotate.h
index 112d6e2..0784a94 100644
--- a/tools/perf/util/annotate.h
+++ b/tools/perf/util/annotate.h
@@ -58,6 +58,7 @@ struct disasm_line {
char *line;
char *name;
struct ins *ins;
+ int line_nr;
struct ins_operands ops;
};
diff --git a/tools/perf/util/build-id.c b/tools/perf/util/build-id.c
index a904a4c..e8d79e5 100644
--- a/tools/perf/util/build-id.c
+++ b/tools/perf/util/build-id.c
@@ -15,6 +15,11 @@
#include "debug.h"
#include "session.h"
#include "tool.h"
+#include "header.h"
+#include "vdso.h"
+
+
+static bool no_buildid_cache;
int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
union perf_event *event,
@@ -33,8 +38,7 @@ int build_id__mark_dso_hit(struct perf_tool *tool __maybe_unused,
return -1;
}
- thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
- sample->ip, &al);
+ thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, &al);
if (al.map != NULL)
al.map->dso->hit = 1;
@@ -106,3 +110,343 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size)
build_id_hex, build_id_hex + 2);
return bf;
}
+
+#define dsos__for_each_with_build_id(pos, head) \
+ list_for_each_entry(pos, head, node) \
+ if (!pos->has_build_id) \
+ continue; \
+ else
+
+static int write_buildid(const char *name, size_t name_len, u8 *build_id,
+ pid_t pid, u16 misc, int fd)
+{
+ int err;
+ struct build_id_event b;
+ size_t len;
+
+ len = name_len + 1;
+ len = PERF_ALIGN(len, NAME_ALIGN);
+
+ memset(&b, 0, sizeof(b));
+ memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
+ b.pid = pid;
+ b.header.misc = misc;
+ b.header.size = sizeof(b) + len;
+
+ err = writen(fd, &b, sizeof(b));
+ if (err < 0)
+ return err;
+
+ return write_padded(fd, name, name_len + 1, len);
+}
+
+static int __dsos__write_buildid_table(struct list_head *head,
+ struct machine *machine,
+ pid_t pid, u16 misc, int fd)
+{
+ char nm[PATH_MAX];
+ struct dso *pos;
+
+ dsos__for_each_with_build_id(pos, head) {
+ int err;
+ const char *name;
+ size_t name_len;
+
+ if (!pos->hit)
+ continue;
+
+ if (dso__is_vdso(pos)) {
+ name = pos->short_name;
+ name_len = pos->short_name_len + 1;
+ } else if (dso__is_kcore(pos)) {
+ machine__mmap_name(machine, nm, sizeof(nm));
+ name = nm;
+ name_len = strlen(nm) + 1;
+ } else {
+ name = pos->long_name;
+ name_len = pos->long_name_len + 1;
+ }
+
+ err = write_buildid(name, name_len, pos->build_id,
+ pid, misc, fd);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int machine__write_buildid_table(struct machine *machine, int fd)
+{
+ int err;
+ u16 kmisc = PERF_RECORD_MISC_KERNEL,
+ umisc = PERF_RECORD_MISC_USER;
+
+ if (!machine__is_host(machine)) {
+ kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
+ umisc = PERF_RECORD_MISC_GUEST_USER;
+ }
+
+ err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
+ machine->pid, kmisc, fd);
+ if (err == 0)
+ err = __dsos__write_buildid_table(&machine->user_dsos.head,
+ machine, machine->pid, umisc,
+ fd);
+ return err;
+}
+
+int perf_session__write_buildid_table(struct perf_session *session, int fd)
+{
+ struct rb_node *nd;
+ int err = machine__write_buildid_table(&session->machines.host, fd);
+
+ if (err)
+ return err;
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+ err = machine__write_buildid_table(pos, fd);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+static int __dsos__hit_all(struct list_head *head)
+{
+ struct dso *pos;
+
+ list_for_each_entry(pos, head, node)
+ pos->hit = true;
+
+ return 0;
+}
+
+static int machine__hit_all_dsos(struct machine *machine)
+{
+ int err;
+
+ err = __dsos__hit_all(&machine->kernel_dsos.head);
+ if (err)
+ return err;
+
+ return __dsos__hit_all(&machine->user_dsos.head);
+}
+
+int dsos__hit_all(struct perf_session *session)
+{
+ struct rb_node *nd;
+ int err;
+
+ err = machine__hit_all_dsos(&session->machines.host);
+ if (err)
+ return err;
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+
+ err = machine__hit_all_dsos(pos);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+void disable_buildid_cache(void)
+{
+ no_buildid_cache = true;
+}
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+ const char *name, bool is_kallsyms, bool is_vdso)
+{
+ const size_t size = PATH_MAX;
+ char *realname, *filename = zalloc(size),
+ *linkname = zalloc(size), *targetname;
+ int len, err = -1;
+ bool slash = is_kallsyms || is_vdso;
+
+ if (is_kallsyms) {
+ if (symbol_conf.kptr_restrict) {
+ pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
+ err = 0;
+ goto out_free;
+ }
+ realname = (char *) name;
+ } else
+ realname = realpath(name, NULL);
+
+ if (realname == NULL || filename == NULL || linkname == NULL)
+ goto out_free;
+
+ len = scnprintf(filename, size, "%s%s%s",
+ debugdir, slash ? "/" : "",
+ is_vdso ? DSO__NAME_VDSO : realname);
+ if (mkdir_p(filename, 0755))
+ goto out_free;
+
+ snprintf(filename + len, size - len, "/%s", sbuild_id);
+
+ if (access(filename, F_OK)) {
+ if (is_kallsyms) {
+ if (copyfile("/proc/kallsyms", filename))
+ goto out_free;
+ } else if (link(realname, filename) && copyfile(name, filename))
+ goto out_free;
+ }
+
+ len = scnprintf(linkname, size, "%s/.build-id/%.2s",
+ debugdir, sbuild_id);
+
+ if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
+ goto out_free;
+
+ snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
+ targetname = filename + strlen(debugdir) - 5;
+ memcpy(targetname, "../..", 5);
+
+ if (symlink(targetname, linkname) == 0)
+ err = 0;
+out_free:
+ if (!is_kallsyms)
+ free(realname);
+ free(filename);
+ free(linkname);
+ return err;
+}
+
+static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
+ const char *name, const char *debugdir,
+ bool is_kallsyms, bool is_vdso)
+{
+ char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+
+ build_id__sprintf(build_id, build_id_size, sbuild_id);
+
+ return build_id_cache__add_s(sbuild_id, debugdir, name,
+ is_kallsyms, is_vdso);
+}
+
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
+{
+ const size_t size = PATH_MAX;
+ char *filename = zalloc(size),
+ *linkname = zalloc(size);
+ int err = -1;
+
+ if (filename == NULL || linkname == NULL)
+ goto out_free;
+
+ snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+ debugdir, sbuild_id, sbuild_id + 2);
+
+ if (access(linkname, F_OK))
+ goto out_free;
+
+ if (readlink(linkname, filename, size - 1) < 0)
+ goto out_free;
+
+ if (unlink(linkname))
+ goto out_free;
+
+ /*
+ * Since the link is relative, we must make it absolute:
+ */
+ snprintf(linkname, size, "%s/.build-id/%.2s/%s",
+ debugdir, sbuild_id, filename);
+
+ if (unlink(linkname))
+ goto out_free;
+
+ err = 0;
+out_free:
+ free(filename);
+ free(linkname);
+ return err;
+}
+
+static int dso__cache_build_id(struct dso *dso, struct machine *machine,
+ const char *debugdir)
+{
+ bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
+ bool is_vdso = dso__is_vdso(dso);
+ const char *name = dso->long_name;
+ char nm[PATH_MAX];
+
+ if (dso__is_kcore(dso)) {
+ is_kallsyms = true;
+ machine__mmap_name(machine, nm, sizeof(nm));
+ name = nm;
+ }
+ return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
+ debugdir, is_kallsyms, is_vdso);
+}
+
+static int __dsos__cache_build_ids(struct list_head *head,
+ struct machine *machine, const char *debugdir)
+{
+ struct dso *pos;
+ int err = 0;
+
+ dsos__for_each_with_build_id(pos, head)
+ if (dso__cache_build_id(pos, machine, debugdir))
+ err = -1;
+
+ return err;
+}
+
+static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
+{
+ int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
+ debugdir);
+ ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
+ debugdir);
+ return ret;
+}
+
+int perf_session__cache_build_ids(struct perf_session *session)
+{
+ struct rb_node *nd;
+ int ret;
+ char debugdir[PATH_MAX];
+
+ if (no_buildid_cache)
+ return 0;
+
+ snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
+
+ if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
+ return -1;
+
+ ret = machine__cache_build_ids(&session->machines.host, debugdir);
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+ ret |= machine__cache_build_ids(pos, debugdir);
+ }
+ return ret ? -1 : 0;
+}
+
+static bool machine__read_build_ids(struct machine *machine, bool with_hits)
+{
+ bool ret;
+
+ ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
+ ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
+ return ret;
+}
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
+{
+ struct rb_node *nd;
+ bool ret = machine__read_build_ids(&session->machines.host, with_hits);
+
+ for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
+ struct machine *pos = rb_entry(nd, struct machine, rb_node);
+ ret |= machine__read_build_ids(pos, with_hits);
+ }
+
+ return ret;
+}
diff --git a/tools/perf/util/build-id.h b/tools/perf/util/build-id.h
index ae39256..8236319 100644
--- a/tools/perf/util/build-id.h
+++ b/tools/perf/util/build-id.h
@@ -15,4 +15,16 @@ char *dso__build_id_filename(const struct dso *dso, char *bf, size_t size);
int build_id__mark_dso_hit(struct perf_tool *tool, union perf_event *event,
struct perf_sample *sample, struct perf_evsel *evsel,
struct machine *machine);
+
+int dsos__hit_all(struct perf_session *session);
+
+bool perf_session__read_build_ids(struct perf_session *session, bool with_hits);
+int perf_session__write_buildid_table(struct perf_session *session, int fd);
+int perf_session__cache_build_ids(struct perf_session *session);
+
+int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
+ const char *name, bool is_kallsyms, bool is_vdso);
+int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
+void disable_buildid_cache(void);
+
#endif
diff --git a/tools/perf/util/callchain.c b/tools/perf/util/callchain.c
index c84d3f8..cf524a3 100644
--- a/tools/perf/util/callchain.c
+++ b/tools/perf/util/callchain.c
@@ -149,6 +149,10 @@ static int parse_callchain_sort_key(const char *value)
callchain_param.key = CCKEY_ADDRESS;
return 0;
}
+ if (!strncmp(value, "branch", strlen(value))) {
+ callchain_param.branch_callstack = 1;
+ return 0;
+ }
return -1;
}
@@ -754,8 +758,8 @@ int sample__resolve_callchain(struct perf_sample *sample, struct symbol **parent
if (symbol_conf.use_callchain || symbol_conf.cumulate_callchain ||
sort__has_parent) {
- return machine__resolve_callchain(al->machine, evsel, al->thread,
- sample, parent, al, max_stack);
+ return thread__resolve_callchain(al->thread, evsel, sample,
+ parent, al, max_stack);
}
return 0;
}
@@ -808,3 +812,32 @@ int fill_callchain_info(struct addr_location *al, struct callchain_cursor_node *
out:
return 1;
}
+
+char *callchain_list__sym_name(struct callchain_list *cl,
+ char *bf, size_t bfsize, bool show_dso)
+{
+ int printed;
+
+ if (cl->ms.sym) {
+ if (callchain_param.key == CCKEY_ADDRESS &&
+ cl->ms.map && !cl->srcline)
+ cl->srcline = get_srcline(cl->ms.map->dso,
+ map__rip_2objdump(cl->ms.map,
+ cl->ip),
+ cl->ms.sym, false);
+ if (cl->srcline)
+ printed = scnprintf(bf, bfsize, "%s %s",
+ cl->ms.sym->name, cl->srcline);
+ else
+ printed = scnprintf(bf, bfsize, "%s", cl->ms.sym->name);
+ } else
+ printed = scnprintf(bf, bfsize, "%#" PRIx64, cl->ip);
+
+ if (show_dso)
+ scnprintf(bf + printed, bfsize - printed, " %s",
+ cl->ms.map ?
+ cl->ms.map->dso->short_name :
+ "unknown");
+
+ return bf;
+}
diff --git a/tools/perf/util/callchain.h b/tools/perf/util/callchain.h
index 94cfefd..dbc08cf 100644
--- a/tools/perf/util/callchain.h
+++ b/tools/perf/util/callchain.h
@@ -63,6 +63,7 @@ struct callchain_param {
sort_chain_func_t sort;
enum chain_order order;
enum chain_key key;
+ bool branch_callstack;
};
extern struct callchain_param callchain_param;
@@ -70,6 +71,7 @@ extern struct callchain_param callchain_param;
struct callchain_list {
u64 ip;
struct map_symbol ms;
+ char *srcline;
struct list_head list;
};
@@ -184,15 +186,16 @@ static inline void callchain_cursor_snapshot(struct callchain_cursor *dest,
}
#ifdef HAVE_SKIP_CALLCHAIN_IDX
-extern int arch_skip_callchain_idx(struct machine *machine,
- struct thread *thread, struct ip_callchain *chain);
+extern int arch_skip_callchain_idx(struct thread *thread, struct ip_callchain *chain);
#else
-static inline int arch_skip_callchain_idx(struct machine *machine __maybe_unused,
- struct thread *thread __maybe_unused,
+static inline int arch_skip_callchain_idx(struct thread *thread __maybe_unused,
struct ip_callchain *chain __maybe_unused)
{
return -1;
}
#endif
+char *callchain_list__sym_name(struct callchain_list *cl,
+ char *bf, size_t bfsize, bool show_dso);
+
#endif /* __PERF_CALLCHAIN_H */
diff --git a/tools/perf/util/comm.h b/tools/perf/util/comm.h
index 51c10ab..71c9c39 100644
--- a/tools/perf/util/comm.h
+++ b/tools/perf/util/comm.h
@@ -12,6 +12,10 @@ struct comm {
u64 start;
struct list_head list;
bool exec;
+ union { /* Tool specific area */
+ void *priv;
+ u64 db_id;
+ };
};
void comm__free(struct comm *comm);
diff --git a/tools/perf/util/db-export.c b/tools/perf/util/db-export.c
new file mode 100644
index 0000000..c81dae3
--- /dev/null
+++ b/tools/perf/util/db-export.c
@@ -0,0 +1,428 @@
+/*
+ * db-export.c: Support for exporting data suitable for import to a database
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <errno.h>
+
+#include "evsel.h"
+#include "machine.h"
+#include "thread.h"
+#include "comm.h"
+#include "symbol.h"
+#include "event.h"
+#include "util.h"
+#include "thread-stack.h"
+#include "db-export.h"
+
+struct deferred_export {
+ struct list_head node;
+ struct comm *comm;
+};
+
+static int db_export__deferred(struct db_export *dbe)
+{
+ struct deferred_export *de;
+ int err;
+
+ while (!list_empty(&dbe->deferred)) {
+ de = list_entry(dbe->deferred.next, struct deferred_export,
+ node);
+ err = dbe->export_comm(dbe, de->comm);
+ list_del(&de->node);
+ free(de);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static void db_export__free_deferred(struct db_export *dbe)
+{
+ struct deferred_export *de;
+
+ while (!list_empty(&dbe->deferred)) {
+ de = list_entry(dbe->deferred.next, struct deferred_export,
+ node);
+ list_del(&de->node);
+ free(de);
+ }
+}
+
+static int db_export__defer_comm(struct db_export *dbe, struct comm *comm)
+{
+ struct deferred_export *de;
+
+ de = zalloc(sizeof(struct deferred_export));
+ if (!de)
+ return -ENOMEM;
+
+ de->comm = comm;
+ list_add_tail(&de->node, &dbe->deferred);
+
+ return 0;
+}
+
+int db_export__init(struct db_export *dbe)
+{
+ memset(dbe, 0, sizeof(struct db_export));
+ INIT_LIST_HEAD(&dbe->deferred);
+ return 0;
+}
+
+int db_export__flush(struct db_export *dbe)
+{
+ return db_export__deferred(dbe);
+}
+
+void db_export__exit(struct db_export *dbe)
+{
+ db_export__free_deferred(dbe);
+ call_return_processor__free(dbe->crp);
+ dbe->crp = NULL;
+}
+
+int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel)
+{
+ if (evsel->db_id)
+ return 0;
+
+ evsel->db_id = ++dbe->evsel_last_db_id;
+
+ if (dbe->export_evsel)
+ return dbe->export_evsel(dbe, evsel);
+
+ return 0;
+}
+
+int db_export__machine(struct db_export *dbe, struct machine *machine)
+{
+ if (machine->db_id)
+ return 0;
+
+ machine->db_id = ++dbe->machine_last_db_id;
+
+ if (dbe->export_machine)
+ return dbe->export_machine(dbe, machine);
+
+ return 0;
+}
+
+int db_export__thread(struct db_export *dbe, struct thread *thread,
+ struct machine *machine, struct comm *comm)
+{
+ u64 main_thread_db_id = 0;
+ int err;
+
+ if (thread->db_id)
+ return 0;
+
+ thread->db_id = ++dbe->thread_last_db_id;
+
+ if (thread->pid_ != -1) {
+ struct thread *main_thread;
+
+ if (thread->pid_ == thread->tid) {
+ main_thread = thread;
+ } else {
+ main_thread = machine__findnew_thread(machine,
+ thread->pid_,
+ thread->pid_);
+ if (!main_thread)
+ return -ENOMEM;
+ err = db_export__thread(dbe, main_thread, machine,
+ comm);
+ if (err)
+ return err;
+ if (comm) {
+ err = db_export__comm_thread(dbe, comm, thread);
+ if (err)
+ return err;
+ }
+ }
+ main_thread_db_id = main_thread->db_id;
+ }
+
+ if (dbe->export_thread)
+ return dbe->export_thread(dbe, thread, main_thread_db_id,
+ machine);
+
+ return 0;
+}
+
+int db_export__comm(struct db_export *dbe, struct comm *comm,
+ struct thread *main_thread)
+{
+ int err;
+
+ if (comm->db_id)
+ return 0;
+
+ comm->db_id = ++dbe->comm_last_db_id;
+
+ if (dbe->export_comm) {
+ if (main_thread->comm_set)
+ err = dbe->export_comm(dbe, comm);
+ else
+ err = db_export__defer_comm(dbe, comm);
+ if (err)
+ return err;
+ }
+
+ return db_export__comm_thread(dbe, comm, main_thread);
+}
+
+int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
+ struct thread *thread)
+{
+ u64 db_id;
+
+ db_id = ++dbe->comm_thread_last_db_id;
+
+ if (dbe->export_comm_thread)
+ return dbe->export_comm_thread(dbe, db_id, comm, thread);
+
+ return 0;
+}
+
+int db_export__dso(struct db_export *dbe, struct dso *dso,
+ struct machine *machine)
+{
+ if (dso->db_id)
+ return 0;
+
+ dso->db_id = ++dbe->dso_last_db_id;
+
+ if (dbe->export_dso)
+ return dbe->export_dso(dbe, dso, machine);
+
+ return 0;
+}
+
+int db_export__symbol(struct db_export *dbe, struct symbol *sym,
+ struct dso *dso)
+{
+ u64 *sym_db_id = symbol__priv(sym);
+
+ if (*sym_db_id)
+ return 0;
+
+ *sym_db_id = ++dbe->symbol_last_db_id;
+
+ if (dbe->export_symbol)
+ return dbe->export_symbol(dbe, sym, dso);
+
+ return 0;
+}
+
+static struct thread *get_main_thread(struct machine *machine, struct thread *thread)
+{
+ if (thread->pid_ == thread->tid)
+ return thread;
+
+ if (thread->pid_ == -1)
+ return NULL;
+
+ return machine__find_thread(machine, thread->pid_, thread->pid_);
+}
+
+static int db_ids_from_al(struct db_export *dbe, struct addr_location *al,
+ u64 *dso_db_id, u64 *sym_db_id, u64 *offset)
+{
+ int err;
+
+ if (al->map) {
+ struct dso *dso = al->map->dso;
+
+ err = db_export__dso(dbe, dso, al->machine);
+ if (err)
+ return err;
+ *dso_db_id = dso->db_id;
+
+ if (!al->sym) {
+ al->sym = symbol__new(al->addr, 0, 0, "unknown");
+ if (al->sym)
+ symbols__insert(&dso->symbols[al->map->type],
+ al->sym);
+ }
+
+ if (al->sym) {
+ u64 *db_id = symbol__priv(al->sym);
+
+ err = db_export__symbol(dbe, al->sym, dso);
+ if (err)
+ return err;
+ *sym_db_id = *db_id;
+ *offset = al->addr - al->sym->start;
+ }
+ }
+
+ return 0;
+}
+
+int db_export__branch_type(struct db_export *dbe, u32 branch_type,
+ const char *name)
+{
+ if (dbe->export_branch_type)
+ return dbe->export_branch_type(dbe, branch_type, name);
+
+ return 0;
+}
+
+int db_export__sample(struct db_export *dbe, union perf_event *event,
+ struct perf_sample *sample, struct perf_evsel *evsel,
+ struct thread *thread, struct addr_location *al)
+{
+ struct export_sample es = {
+ .event = event,
+ .sample = sample,
+ .evsel = evsel,
+ .thread = thread,
+ .al = al,
+ };
+ struct thread *main_thread;
+ struct comm *comm = NULL;
+ int err;
+
+ err = db_export__evsel(dbe, evsel);
+ if (err)
+ return err;
+
+ err = db_export__machine(dbe, al->machine);
+ if (err)
+ return err;
+
+ main_thread = get_main_thread(al->machine, thread);
+ if (main_thread)
+ comm = machine__thread_exec_comm(al->machine, main_thread);
+
+ err = db_export__thread(dbe, thread, al->machine, comm);
+ if (err)
+ return err;
+
+ if (comm) {
+ err = db_export__comm(dbe, comm, main_thread);
+ if (err)
+ return err;
+ es.comm_db_id = comm->db_id;
+ }
+
+ es.db_id = ++dbe->sample_last_db_id;
+
+ err = db_ids_from_al(dbe, al, &es.dso_db_id, &es.sym_db_id, &es.offset);
+ if (err)
+ return err;
+
+ if ((evsel->attr.sample_type & PERF_SAMPLE_ADDR) &&
+ sample_addr_correlates_sym(&evsel->attr)) {
+ struct addr_location addr_al;
+
+ perf_event__preprocess_sample_addr(event, sample, thread, &addr_al);
+ err = db_ids_from_al(dbe, &addr_al, &es.addr_dso_db_id,
+ &es.addr_sym_db_id, &es.addr_offset);
+ if (err)
+ return err;
+ if (dbe->crp) {
+ err = thread_stack__process(thread, comm, sample, al,
+ &addr_al, es.db_id,
+ dbe->crp);
+ if (err)
+ return err;
+ }
+ }
+
+ if (dbe->export_sample)
+ return dbe->export_sample(dbe, &es);
+
+ return 0;
+}
+
+static struct {
+ u32 branch_type;
+ const char *name;
+} branch_types[] = {
+ {0, "no branch"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL, "call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN, "return"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CONDITIONAL, "conditional jump"},
+ {PERF_IP_FLAG_BRANCH, "unconditional jump"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_INTERRUPT,
+ "software interrupt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_INTERRUPT,
+ "return from interrupt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_SYSCALLRET,
+ "system call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_RETURN | PERF_IP_FLAG_SYSCALLRET,
+ "return from system call"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_ASYNC, "asynchronous branch"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_CALL | PERF_IP_FLAG_ASYNC |
+ PERF_IP_FLAG_INTERRUPT, "hardware interrupt"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TX_ABORT, "transaction abort"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_BEGIN, "trace begin"},
+ {PERF_IP_FLAG_BRANCH | PERF_IP_FLAG_TRACE_END, "trace end"},
+ {0, NULL}
+};
+
+int db_export__branch_types(struct db_export *dbe)
+{
+ int i, err = 0;
+
+ for (i = 0; branch_types[i].name ; i++) {
+ err = db_export__branch_type(dbe, branch_types[i].branch_type,
+ branch_types[i].name);
+ if (err)
+ break;
+ }
+ return err;
+}
+
+int db_export__call_path(struct db_export *dbe, struct call_path *cp)
+{
+ int err;
+
+ if (cp->db_id)
+ return 0;
+
+ if (cp->parent) {
+ err = db_export__call_path(dbe, cp->parent);
+ if (err)
+ return err;
+ }
+
+ cp->db_id = ++dbe->call_path_last_db_id;
+
+ if (dbe->export_call_path)
+ return dbe->export_call_path(dbe, cp);
+
+ return 0;
+}
+
+int db_export__call_return(struct db_export *dbe, struct call_return *cr)
+{
+ int err;
+
+ if (cr->db_id)
+ return 0;
+
+ err = db_export__call_path(dbe, cr->cp);
+ if (err)
+ return err;
+
+ cr->db_id = ++dbe->call_return_last_db_id;
+
+ if (dbe->export_call_return)
+ return dbe->export_call_return(dbe, cr);
+
+ return 0;
+}
diff --git a/tools/perf/util/db-export.h b/tools/perf/util/db-export.h
new file mode 100644
index 0000000..adbd22d
--- /dev/null
+++ b/tools/perf/util/db-export.h
@@ -0,0 +1,107 @@
+/*
+ * db-export.h: Support for exporting data suitable for import to a database
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __PERF_DB_EXPORT_H
+#define __PERF_DB_EXPORT_H
+
+#include <linux/types.h>
+#include <linux/list.h>
+
+struct perf_evsel;
+struct machine;
+struct thread;
+struct comm;
+struct dso;
+struct perf_sample;
+struct addr_location;
+struct call_return_processor;
+struct call_path;
+struct call_return;
+
+struct export_sample {
+ union perf_event *event;
+ struct perf_sample *sample;
+ struct perf_evsel *evsel;
+ struct thread *thread;
+ struct addr_location *al;
+ u64 db_id;
+ u64 comm_db_id;
+ u64 dso_db_id;
+ u64 sym_db_id;
+ u64 offset; /* ip offset from symbol start */
+ u64 addr_dso_db_id;
+ u64 addr_sym_db_id;
+ u64 addr_offset; /* addr offset from symbol start */
+};
+
+struct db_export {
+ int (*export_evsel)(struct db_export *dbe, struct perf_evsel *evsel);
+ int (*export_machine)(struct db_export *dbe, struct machine *machine);
+ int (*export_thread)(struct db_export *dbe, struct thread *thread,
+ u64 main_thread_db_id, struct machine *machine);
+ int (*export_comm)(struct db_export *dbe, struct comm *comm);
+ int (*export_comm_thread)(struct db_export *dbe, u64 db_id,
+ struct comm *comm, struct thread *thread);
+ int (*export_dso)(struct db_export *dbe, struct dso *dso,
+ struct machine *machine);
+ int (*export_symbol)(struct db_export *dbe, struct symbol *sym,
+ struct dso *dso);
+ int (*export_branch_type)(struct db_export *dbe, u32 branch_type,
+ const char *name);
+ int (*export_sample)(struct db_export *dbe, struct export_sample *es);
+ int (*export_call_path)(struct db_export *dbe, struct call_path *cp);
+ int (*export_call_return)(struct db_export *dbe,
+ struct call_return *cr);
+ struct call_return_processor *crp;
+ u64 evsel_last_db_id;
+ u64 machine_last_db_id;
+ u64 thread_last_db_id;
+ u64 comm_last_db_id;
+ u64 comm_thread_last_db_id;
+ u64 dso_last_db_id;
+ u64 symbol_last_db_id;
+ u64 sample_last_db_id;
+ u64 call_path_last_db_id;
+ u64 call_return_last_db_id;
+ struct list_head deferred;
+};
+
+int db_export__init(struct db_export *dbe);
+int db_export__flush(struct db_export *dbe);
+void db_export__exit(struct db_export *dbe);
+int db_export__evsel(struct db_export *dbe, struct perf_evsel *evsel);
+int db_export__machine(struct db_export *dbe, struct machine *machine);
+int db_export__thread(struct db_export *dbe, struct thread *thread,
+ struct machine *machine, struct comm *comm);
+int db_export__comm(struct db_export *dbe, struct comm *comm,
+ struct thread *main_thread);
+int db_export__comm_thread(struct db_export *dbe, struct comm *comm,
+ struct thread *thread);
+int db_export__dso(struct db_export *dbe, struct dso *dso,
+ struct machine *machine);
+int db_export__symbol(struct db_export *dbe, struct symbol *sym,
+ struct dso *dso);
+int db_export__branch_type(struct db_export *dbe, u32 branch_type,
+ const char *name);
+int db_export__sample(struct db_export *dbe, union perf_event *event,
+ struct perf_sample *sample, struct perf_evsel *evsel,
+ struct thread *thread, struct addr_location *al);
+
+int db_export__branch_types(struct db_export *dbe);
+
+int db_export__call_path(struct db_export *dbe, struct call_path *cp);
+int db_export__call_return(struct db_export *dbe, struct call_return *cr);
+
+#endif
diff --git a/tools/perf/util/debug.c b/tools/perf/util/debug.c
index ba357f3..ad60b2f 100644
--- a/tools/perf/util/debug.c
+++ b/tools/perf/util/debug.c
@@ -19,13 +19,14 @@
int verbose;
bool dump_trace = false, quiet = false;
int debug_ordered_events;
+static int redirect_to_stderr;
static int _eprintf(int level, int var, const char *fmt, va_list args)
{
int ret = 0;
if (var >= level) {
- if (use_browser >= 1)
+ if (use_browser >= 1 && !redirect_to_stderr)
ui_helpline__vshow(fmt, args);
else
ret = vfprintf(stderr, fmt, args);
@@ -145,6 +146,7 @@ static struct debug_variable {
} debug_variables[] = {
{ .name = "verbose", .ptr = &verbose },
{ .name = "ordered-events", .ptr = &debug_ordered_events},
+ { .name = "stderr", .ptr = &redirect_to_stderr},
{ .name = NULL, }
};
diff --git a/tools/perf/util/dso.c b/tools/perf/util/dso.c
index 0247acf..45be944 100644
--- a/tools/perf/util/dso.c
+++ b/tools/perf/util/dso.c
@@ -21,8 +21,10 @@ char dso__symtab_origin(const struct dso *dso)
[DSO_BINARY_TYPE__BUILDID_DEBUGINFO] = 'b',
[DSO_BINARY_TYPE__SYSTEM_PATH_DSO] = 'd',
[DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE] = 'K',
+ [DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP] = 'm',
[DSO_BINARY_TYPE__GUEST_KALLSYMS] = 'g',
[DSO_BINARY_TYPE__GUEST_KMODULE] = 'G',
+ [DSO_BINARY_TYPE__GUEST_KMODULE_COMP] = 'M',
[DSO_BINARY_TYPE__GUEST_VMLINUX] = 'V',
};
@@ -112,11 +114,13 @@ int dso__read_binary_type_filename(const struct dso *dso,
break;
case DSO_BINARY_TYPE__GUEST_KMODULE:
+ case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
path__join3(filename, size, symbol_conf.symfs,
root_dir, dso->long_name);
break;
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
__symbol__join_symfs(filename, size, dso->long_name);
break;
@@ -137,6 +141,73 @@ int dso__read_binary_type_filename(const struct dso *dso,
return ret;
}
+static const struct {
+ const char *fmt;
+ int (*decompress)(const char *input, int output);
+} compressions[] = {
+#ifdef HAVE_ZLIB_SUPPORT
+ { "gz", gzip_decompress_to_file },
+#endif
+ { NULL, NULL },
+};
+
+bool is_supported_compression(const char *ext)
+{
+ unsigned i;
+
+ for (i = 0; compressions[i].fmt; i++) {
+ if (!strcmp(ext, compressions[i].fmt))
+ return true;
+ }
+ return false;
+}
+
+bool is_kmodule_extension(const char *ext)
+{
+ if (strncmp(ext, "ko", 2))
+ return false;
+
+ if (ext[2] == '\0' || (ext[2] == '.' && is_supported_compression(ext+3)))
+ return true;
+
+ return false;
+}
+
+bool is_kernel_module(const char *pathname, bool *compressed)
+{
+ const char *ext = strrchr(pathname, '.');
+
+ if (ext == NULL)
+ return false;
+
+ if (is_supported_compression(ext + 1)) {
+ if (compressed)
+ *compressed = true;
+ ext -= 3;
+ } else if (compressed)
+ *compressed = false;
+
+ return is_kmodule_extension(ext + 1);
+}
+
+bool decompress_to_file(const char *ext, const char *filename, int output_fd)
+{
+ unsigned i;
+
+ for (i = 0; compressions[i].fmt; i++) {
+ if (!strcmp(ext, compressions[i].fmt))
+ return !compressions[i].decompress(filename,
+ output_fd);
+ }
+ return false;
+}
+
+bool dso__needs_decompress(struct dso *dso)
+{
+ return dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
+}
+
/*
* Global list of open DSOs and the counter.
*/
diff --git a/tools/perf/util/dso.h b/tools/perf/util/dso.h
index acb651a..3782c82 100644
--- a/tools/perf/util/dso.h
+++ b/tools/perf/util/dso.h
@@ -22,7 +22,9 @@ enum dso_binary_type {
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE,
+ DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+ DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
DSO_BINARY_TYPE__KCORE,
DSO_BINARY_TYPE__GUEST_KCORE,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
@@ -127,6 +129,7 @@ struct dso {
const char *long_name;
u16 long_name_len;
u16 short_name_len;
+ void *dwfl; /* DWARF debug info */
/* dso data file */
struct {
@@ -138,6 +141,11 @@ struct dso {
struct list_head open_entry;
} data;
+ union { /* Tool specific area */
+ void *priv;
+ u64 db_id;
+ };
+
char name[0];
};
@@ -179,6 +187,11 @@ int dso__kernel_module_get_build_id(struct dso *dso, const char *root_dir);
char dso__symtab_origin(const struct dso *dso);
int dso__read_binary_type_filename(const struct dso *dso, enum dso_binary_type type,
char *root_dir, char *filename, size_t size);
+bool is_supported_compression(const char *ext);
+bool is_kmodule_extension(const char *ext);
+bool is_kernel_module(const char *pathname, bool *compressed);
+bool decompress_to_file(const char *ext, const char *filename, int output_fd);
+bool dso__needs_decompress(struct dso *dso);
/*
* The dso__data_* external interface provides following functions:
diff --git a/tools/perf/util/event.c b/tools/perf/util/event.c
index 4af6b27..6c6d044 100644
--- a/tools/perf/util/event.c
+++ b/tools/perf/util/event.c
@@ -28,6 +28,7 @@ static const char *perf_event__names[] = {
[PERF_RECORD_HEADER_TRACING_DATA] = "TRACING_DATA",
[PERF_RECORD_HEADER_BUILD_ID] = "BUILD_ID",
[PERF_RECORD_FINISHED_ROUND] = "FINISHED_ROUND",
+ [PERF_RECORD_ID_INDEX] = "ID_INDEX",
};
const char *perf_event__name(unsigned int id)
@@ -730,12 +731,12 @@ int perf_event__process(struct perf_tool *tool __maybe_unused,
return machine__process_event(machine, event, sample);
}
-void thread__find_addr_map(struct thread *thread,
- struct machine *machine, u8 cpumode,
+void thread__find_addr_map(struct thread *thread, u8 cpumode,
enum map_type type, u64 addr,
struct addr_location *al)
{
struct map_groups *mg = thread->mg;
+ struct machine *machine = mg->machine;
bool load_map = false;
al->machine = machine;
@@ -806,14 +807,14 @@ try_again:
}
}
-void thread__find_addr_location(struct thread *thread, struct machine *machine,
+void thread__find_addr_location(struct thread *thread,
u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al)
{
- thread__find_addr_map(thread, machine, cpumode, type, addr, al);
+ thread__find_addr_map(thread, cpumode, type, addr, al);
if (al->map != NULL)
al->sym = map__find_symbol(al->map, al->addr,
- machine->symbol_filter);
+ thread->mg->machine->symbol_filter);
else
al->sym = NULL;
}
@@ -842,8 +843,7 @@ int perf_event__preprocess_sample(const union perf_event *event,
machine->vmlinux_maps[MAP__FUNCTION] == NULL)
machine__create_kernel_maps(machine);
- thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
- sample->ip, al);
+ thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->ip, al);
dump_printf(" ...... dso: %s\n",
al->map ? al->map->dso->long_name :
al->level == 'H' ? "[hypervisor]" : "<not found>");
@@ -902,16 +902,14 @@ bool sample_addr_correlates_sym(struct perf_event_attr *attr)
void perf_event__preprocess_sample_addr(union perf_event *event,
struct perf_sample *sample,
- struct machine *machine,
struct thread *thread,
struct addr_location *al)
{
u8 cpumode = event->header.misc & PERF_RECORD_MISC_CPUMODE_MASK;
- thread__find_addr_map(thread, machine, cpumode, MAP__FUNCTION,
- sample->addr, al);
+ thread__find_addr_map(thread, cpumode, MAP__FUNCTION, sample->addr, al);
if (!al->map)
- thread__find_addr_map(thread, machine, cpumode, MAP__VARIABLE,
+ thread__find_addr_map(thread, cpumode, MAP__VARIABLE,
sample->addr, al);
al->cpu = sample->cpu;
diff --git a/tools/perf/util/event.h b/tools/perf/util/event.h
index 5699e7e..c4ffe2b 100644
--- a/tools/perf/util/event.h
+++ b/tools/perf/util/event.h
@@ -143,6 +143,32 @@ struct branch_stack {
struct branch_entry entries[0];
};
+enum {
+ PERF_IP_FLAG_BRANCH = 1ULL << 0,
+ PERF_IP_FLAG_CALL = 1ULL << 1,
+ PERF_IP_FLAG_RETURN = 1ULL << 2,
+ PERF_IP_FLAG_CONDITIONAL = 1ULL << 3,
+ PERF_IP_FLAG_SYSCALLRET = 1ULL << 4,
+ PERF_IP_FLAG_ASYNC = 1ULL << 5,
+ PERF_IP_FLAG_INTERRUPT = 1ULL << 6,
+ PERF_IP_FLAG_TX_ABORT = 1ULL << 7,
+ PERF_IP_FLAG_TRACE_BEGIN = 1ULL << 8,
+ PERF_IP_FLAG_TRACE_END = 1ULL << 9,
+ PERF_IP_FLAG_IN_TX = 1ULL << 10,
+};
+
+#define PERF_BRANCH_MASK (\
+ PERF_IP_FLAG_BRANCH |\
+ PERF_IP_FLAG_CALL |\
+ PERF_IP_FLAG_RETURN |\
+ PERF_IP_FLAG_CONDITIONAL |\
+ PERF_IP_FLAG_SYSCALLRET |\
+ PERF_IP_FLAG_ASYNC |\
+ PERF_IP_FLAG_INTERRUPT |\
+ PERF_IP_FLAG_TX_ABORT |\
+ PERF_IP_FLAG_TRACE_BEGIN |\
+ PERF_IP_FLAG_TRACE_END)
+
struct perf_sample {
u64 ip;
u32 pid, tid;
@@ -162,6 +188,7 @@ struct perf_sample {
struct ip_callchain *callchain;
struct branch_stack *branch_stack;
struct regs_dump user_regs;
+ struct regs_dump intr_regs;
struct stack_dump user_stack;
struct sample_read read;
};
@@ -187,6 +214,7 @@ enum perf_user_event_type { /* above any possible kernel type */
PERF_RECORD_HEADER_TRACING_DATA = 66,
PERF_RECORD_HEADER_BUILD_ID = 67,
PERF_RECORD_FINISHED_ROUND = 68,
+ PERF_RECORD_ID_INDEX = 69,
PERF_RECORD_HEADER_MAX
};
@@ -214,6 +242,7 @@ struct events_stats {
u32 nr_invalid_chains;
u32 nr_unknown_id;
u32 nr_unprocessable_samples;
+ u32 nr_unordered_events;
};
struct attr_event {
@@ -239,6 +268,19 @@ struct tracing_data_event {
u32 size;
};
+struct id_index_entry {
+ u64 id;
+ u64 idx;
+ u64 cpu;
+ u64 tid;
+};
+
+struct id_index_event {
+ struct perf_event_header header;
+ u64 nr;
+ struct id_index_entry entries[0];
+};
+
union perf_event {
struct perf_event_header header;
struct mmap_event mmap;
@@ -253,6 +295,7 @@ union perf_event {
struct event_type_event event_type;
struct tracing_data_event tracing_data;
struct build_id_event build_id;
+ struct id_index_event id_index;
};
void perf_event__print_totals(void);
@@ -322,7 +365,6 @@ bool is_bts_event(struct perf_event_attr *attr);
bool sample_addr_correlates_sym(struct perf_event_attr *attr);
void perf_event__preprocess_sample_addr(union perf_event *event,
struct perf_sample *sample,
- struct machine *machine,
struct thread *thread,
struct addr_location *al);
diff --git a/tools/perf/util/evlist.c b/tools/perf/util/evlist.c
index 3c9e77d..cfbe2b9 100644
--- a/tools/perf/util/evlist.c
+++ b/tools/perf/util/evlist.c
@@ -413,7 +413,7 @@ int perf_evlist__alloc_pollfd(struct perf_evlist *evlist)
int nfds = 0;
struct perf_evsel *evsel;
- list_for_each_entry(evsel, &evlist->entries, node) {
+ evlist__for_each(evlist, evsel) {
if (evsel->system_wide)
nfds += nr_cpus;
else
@@ -527,6 +527,22 @@ static int perf_evlist__id_add_fd(struct perf_evlist *evlist,
return 0;
}
+static void perf_evlist__set_sid_idx(struct perf_evlist *evlist,
+ struct perf_evsel *evsel, int idx, int cpu,
+ int thread)
+{
+ struct perf_sample_id *sid = SID(evsel, cpu, thread);
+ sid->idx = idx;
+ if (evlist->cpus && cpu >= 0)
+ sid->cpu = evlist->cpus->map[cpu];
+ else
+ sid->cpu = -1;
+ if (!evsel->system_wide && evlist->threads && thread >= 0)
+ sid->tid = evlist->threads->map[thread];
+ else
+ sid->tid = -1;
+}
+
struct perf_sample_id *perf_evlist__id2sid(struct perf_evlist *evlist, u64 id)
{
struct hlist_head *head;
@@ -800,14 +816,26 @@ static int perf_evlist__mmap_per_evsel(struct perf_evlist *evlist, int idx,
perf_evlist__mmap_get(evlist, idx);
}
- if (__perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
+ /*
+ * The system_wide flag causes a selected event to be opened
+ * always without a pid. Consequently it will never get a
+ * POLLHUP, but it is used for tracking in combination with
+ * other events, so it should not need to be polled anyway.
+ * Therefore don't add it for polling.
+ */
+ if (!evsel->system_wide &&
+ __perf_evlist__add_pollfd(evlist, fd, idx) < 0) {
perf_evlist__mmap_put(evlist, idx);
return -1;
}
- if ((evsel->attr.read_format & PERF_FORMAT_ID) &&
- perf_evlist__id_add_fd(evlist, evsel, cpu, thread, fd) < 0)
- return -1;
+ if (evsel->attr.read_format & PERF_FORMAT_ID) {
+ if (perf_evlist__id_add_fd(evlist, evsel, cpu, thread,
+ fd) < 0)
+ return -1;
+ perf_evlist__set_sid_idx(evlist, evsel, idx, cpu,
+ thread);
+ }
}
return 0;
diff --git a/tools/perf/util/evsel.c b/tools/perf/util/evsel.c
index 2f9e680..1e90c85 100644
--- a/tools/perf/util/evsel.c
+++ b/tools/perf/util/evsel.c
@@ -658,9 +658,22 @@ void perf_evsel__config(struct perf_evsel *evsel, struct record_opts *opts)
attr->mmap_data = track;
}
+ /*
+ * We don't allow user space callchains for function trace
+ * event, due to issues with page faults while tracing page
+ * fault handler and its overall trickiness nature.
+ */
+ if (perf_evsel__is_function_event(evsel))
+ evsel->attr.exclude_callchain_user = 1;
+
if (callchain_param.enabled && !evsel->no_aux_samples)
perf_evsel__config_callgraph(evsel);
+ if (opts->sample_intr_regs) {
+ attr->sample_regs_intr = PERF_REGS_MASK;
+ perf_evsel__set_sample_bit(evsel, REGS_INTR);
+ }
+
if (target__has_cpu(&opts->target))
perf_evsel__set_sample_bit(evsel, CPU);
@@ -853,8 +866,6 @@ void perf_evsel__exit(struct perf_evsel *evsel)
perf_evsel__free_id(evsel);
close_cgroup(evsel->cgrp);
zfree(&evsel->group_name);
- if (evsel->tp_format)
- pevent_free_format(evsel->tp_format);
zfree(&evsel->name);
perf_evsel__object.fini(evsel);
}
@@ -865,9 +876,8 @@ void perf_evsel__delete(struct perf_evsel *evsel)
free(evsel);
}
-static inline void compute_deltas(struct perf_evsel *evsel,
- int cpu,
- struct perf_counts_values *count)
+void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
+ struct perf_counts_values *count)
{
struct perf_counts_values tmp;
@@ -887,81 +897,60 @@ static inline void compute_deltas(struct perf_evsel *evsel,
count->run = count->run - tmp.run;
}
-int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
- int cpu, int thread, bool scale)
+void perf_counts_values__scale(struct perf_counts_values *count,
+ bool scale, s8 *pscaled)
{
- struct perf_counts_values count;
- size_t nv = scale ? 3 : 1;
-
- if (FD(evsel, cpu, thread) < 0)
- return -EINVAL;
-
- if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
- return -ENOMEM;
-
- if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
- return -errno;
-
- compute_deltas(evsel, cpu, &count);
+ s8 scaled = 0;
if (scale) {
- if (count.run == 0)
- count.val = 0;
- else if (count.run < count.ena)
- count.val = (u64)((double)count.val * count.ena / count.run + 0.5);
+ if (count->run == 0) {
+ scaled = -1;
+ count->val = 0;
+ } else if (count->run < count->ena) {
+ scaled = 1;
+ count->val = (u64)((double) count->val * count->ena / count->run + 0.5);
+ }
} else
- count.ena = count.run = 0;
+ count->ena = count->run = 0;
- evsel->counts->cpu[cpu] = count;
- return 0;
+ if (pscaled)
+ *pscaled = scaled;
}
-int __perf_evsel__read(struct perf_evsel *evsel,
- int ncpus, int nthreads, bool scale)
+int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
+ perf_evsel__read_cb_t cb)
{
- size_t nv = scale ? 3 : 1;
- int cpu, thread;
- struct perf_counts_values *aggr = &evsel->counts->aggr, count;
+ struct perf_counts_values count;
- if (evsel->system_wide)
- nthreads = 1;
+ memset(&count, 0, sizeof(count));
- aggr->val = aggr->ena = aggr->run = 0;
+ if (FD(evsel, cpu, thread) < 0)
+ return -EINVAL;
- for (cpu = 0; cpu < ncpus; cpu++) {
- for (thread = 0; thread < nthreads; thread++) {
- if (FD(evsel, cpu, thread) < 0)
- continue;
+ if (readn(FD(evsel, cpu, thread), &count, sizeof(count)) < 0)
+ return -errno;
- if (readn(FD(evsel, cpu, thread),
- &count, nv * sizeof(u64)) < 0)
- return -errno;
+ return cb(evsel, cpu, thread, &count);
+}
- aggr->val += count.val;
- if (scale) {
- aggr->ena += count.ena;
- aggr->run += count.run;
- }
- }
- }
+int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
+ int cpu, int thread, bool scale)
+{
+ struct perf_counts_values count;
+ size_t nv = scale ? 3 : 1;
- compute_deltas(evsel, -1, aggr);
+ if (FD(evsel, cpu, thread) < 0)
+ return -EINVAL;
- evsel->counts->scaled = 0;
- if (scale) {
- if (aggr->run == 0) {
- evsel->counts->scaled = -1;
- aggr->val = 0;
- return 0;
- }
+ if (evsel->counts == NULL && perf_evsel__alloc_counts(evsel, cpu + 1) < 0)
+ return -ENOMEM;
- if (aggr->run < aggr->ena) {
- evsel->counts->scaled = 1;
- aggr->val = (u64)((double)aggr->val * aggr->ena / aggr->run + 0.5);
- }
- } else
- aggr->ena = aggr->run = 0;
+ if (readn(FD(evsel, cpu, thread), &count, nv * sizeof(u64)) < 0)
+ return -errno;
+ perf_evsel__compute_deltas(evsel, cpu, &count);
+ perf_counts_values__scale(&count, scale, NULL);
+ evsel->counts->cpu[cpu] = count;
return 0;
}
@@ -1039,6 +1028,7 @@ static size_t perf_event_attr__fprintf(struct perf_event_attr *attr, FILE *fp)
ret += PRINT_ATTR_X64(branch_sample_type);
ret += PRINT_ATTR_X64(sample_regs_user);
ret += PRINT_ATTR_U32(sample_stack_user);
+ ret += PRINT_ATTR_X64(sample_regs_intr);
ret += fprintf(fp, "%.60s\n", graph_dotted_line);
@@ -1538,6 +1528,23 @@ int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
array++;
}
+ data->intr_regs.abi = PERF_SAMPLE_REGS_ABI_NONE;
+ if (type & PERF_SAMPLE_REGS_INTR) {
+ OVERFLOW_CHECK_u64(array);
+ data->intr_regs.abi = *array;
+ array++;
+
+ if (data->intr_regs.abi != PERF_SAMPLE_REGS_ABI_NONE) {
+ u64 mask = evsel->attr.sample_regs_intr;
+
+ sz = hweight_long(mask) * sizeof(u64);
+ OVERFLOW_CHECK(array, sz, max_size);
+ data->intr_regs.mask = mask;
+ data->intr_regs.regs = (u64 *)array;
+ array = (void *)array + sz;
+ }
+ }
+
return 0;
}
@@ -1633,6 +1640,16 @@ size_t perf_event__sample_event_size(const struct perf_sample *sample, u64 type,
if (type & PERF_SAMPLE_TRANSACTION)
result += sizeof(u64);
+ if (type & PERF_SAMPLE_REGS_INTR) {
+ if (sample->intr_regs.abi) {
+ result += sizeof(u64);
+ sz = hweight_long(sample->intr_regs.mask) * sizeof(u64);
+ result += sz;
+ } else {
+ result += sizeof(u64);
+ }
+ }
+
return result;
}
@@ -1811,6 +1828,17 @@ int perf_event__synthesize_sample(union perf_event *event, u64 type,
array++;
}
+ if (type & PERF_SAMPLE_REGS_INTR) {
+ if (sample->intr_regs.abi) {
+ *array++ = sample->intr_regs.abi;
+ sz = hweight_long(sample->intr_regs.mask) * sizeof(u64);
+ memcpy(array, sample->intr_regs.regs, sz);
+ array = (void *)array + sz;
+ } else {
+ *array++ = 0;
+ }
+ }
+
return 0;
}
@@ -1940,7 +1968,7 @@ static int sample_type__fprintf(FILE *fp, bool *first, u64 value)
bit_name(READ), bit_name(CALLCHAIN), bit_name(ID), bit_name(CPU),
bit_name(PERIOD), bit_name(STREAM_ID), bit_name(RAW),
bit_name(BRANCH_STACK), bit_name(REGS_USER), bit_name(STACK_USER),
- bit_name(IDENTIFIER),
+ bit_name(IDENTIFIER), bit_name(REGS_INTR),
{ .name = NULL, }
};
#undef bit_name
diff --git a/tools/perf/util/evsel.h b/tools/perf/util/evsel.h
index 163c560..3862274 100644
--- a/tools/perf/util/evsel.h
+++ b/tools/perf/util/evsel.h
@@ -36,6 +36,9 @@ struct perf_sample_id {
struct hlist_node node;
u64 id;
struct perf_evsel *evsel;
+ int idx;
+ int cpu;
+ pid_t tid;
/* Holds total ID period value for PERF_SAMPLE_READ processing. */
u64 period;
@@ -54,6 +57,7 @@ struct cgroup_sel;
* @is_pos: the position (counting backwards) of the event id (PERF_SAMPLE_ID or
* PERF_SAMPLE_IDENTIFIER) in a non-sample event i.e. if sample_id_all
* is used there is an id sample appended to non-sample events
+ * @priv: And what is in its containing unnamed union are tool specific
*/
struct perf_evsel {
struct list_head node;
@@ -69,10 +73,12 @@ struct perf_evsel {
char *name;
double scale;
const char *unit;
+ bool snapshot;
struct event_format *tp_format;
union {
void *priv;
off_t id_offset;
+ u64 db_id;
};
struct cgroup_sel *cgrp;
void *handler;
@@ -86,6 +92,8 @@ struct perf_evsel {
bool immediate;
bool system_wide;
bool tracking;
+ bool per_pkg;
+ unsigned long *per_pkg_mask;
/* parse modifier helper */
int exclude_GH;
int nr_members;
@@ -105,6 +113,12 @@ struct thread_map;
struct perf_evlist;
struct record_opts;
+void perf_counts_values__scale(struct perf_counts_values *count,
+ bool scale, s8 *pscaled);
+
+void perf_evsel__compute_deltas(struct perf_evsel *evsel, int cpu,
+ struct perf_counts_values *count);
+
int perf_evsel__object_config(size_t object_size,
int (*init)(struct perf_evsel *evsel),
void (*fini)(struct perf_evsel *evsel));
@@ -222,6 +236,13 @@ static inline bool perf_evsel__match2(struct perf_evsel *e1,
(a)->attr.type == (b)->attr.type && \
(a)->attr.config == (b)->attr.config)
+typedef int (perf_evsel__read_cb_t)(struct perf_evsel *evsel,
+ int cpu, int thread,
+ struct perf_counts_values *count);
+
+int perf_evsel__read_cb(struct perf_evsel *evsel, int cpu, int thread,
+ perf_evsel__read_cb_t cb);
+
int __perf_evsel__read_on_cpu(struct perf_evsel *evsel,
int cpu, int thread, bool scale);
@@ -251,35 +272,6 @@ static inline int perf_evsel__read_on_cpu_scaled(struct perf_evsel *evsel,
return __perf_evsel__read_on_cpu(evsel, cpu, thread, true);
}
-int __perf_evsel__read(struct perf_evsel *evsel, int ncpus, int nthreads,
- bool scale);
-
-/**
- * perf_evsel__read - Read the aggregate results on all CPUs
- *
- * @evsel - event selector to read value
- * @ncpus - Number of cpus affected, from zero
- * @nthreads - Number of threads affected, from zero
- */
-static inline int perf_evsel__read(struct perf_evsel *evsel,
- int ncpus, int nthreads)
-{
- return __perf_evsel__read(evsel, ncpus, nthreads, false);
-}
-
-/**
- * perf_evsel__read_scaled - Read the aggregate results on all CPUs, scaled
- *
- * @evsel - event selector to read value
- * @ncpus - Number of cpus affected, from zero
- * @nthreads - Number of threads affected, from zero
- */
-static inline int perf_evsel__read_scaled(struct perf_evsel *evsel,
- int ncpus, int nthreads)
-{
- return __perf_evsel__read(evsel, ncpus, nthreads, true);
-}
-
int perf_evsel__parse_sample(struct perf_evsel *evsel, union perf_event *event,
struct perf_sample *sample);
diff --git a/tools/perf/util/find-vdso-map.c b/tools/perf/util/find-vdso-map.c
new file mode 100644
index 0000000..95ef1cf
--- /dev/null
+++ b/tools/perf/util/find-vdso-map.c
@@ -0,0 +1,30 @@
+static int find_vdso_map(void **start, void **end)
+{
+ FILE *maps;
+ char line[128];
+ int found = 0;
+
+ maps = fopen("/proc/self/maps", "r");
+ if (!maps) {
+ fprintf(stderr, "vdso: cannot open maps\n");
+ return -1;
+ }
+
+ while (!found && fgets(line, sizeof(line), maps)) {
+ int m = -1;
+
+ /* We care only about private r-x mappings. */
+ if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
+ start, end, &m))
+ continue;
+ if (m < 0)
+ continue;
+
+ if (!strncmp(&line[m], VDSO__MAP_NAME,
+ sizeof(VDSO__MAP_NAME) - 1))
+ found = 1;
+ }
+
+ fclose(maps);
+ return !found;
+}
diff --git a/tools/perf/util/header.c b/tools/perf/util/header.c
index 26f5b2f..b20e40c 100644
--- a/tools/perf/util/header.c
+++ b/tools/perf/util/header.c
@@ -24,8 +24,6 @@
#include "build-id.h"
#include "data.h"
-static bool no_buildid_cache = false;
-
static u32 header_argc;
static const char **header_argv;
@@ -79,10 +77,7 @@ static int do_write(int fd, const void *buf, size_t size)
return 0;
}
-#define NAME_ALIGN 64
-
-static int write_padded(int fd, const void *bf, size_t count,
- size_t count_aligned)
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned)
{
static const char zero_buf[NAME_ALIGN];
int err = do_write(fd, bf, count);
@@ -171,340 +166,6 @@ perf_header__set_cmdline(int argc, const char **argv)
return 0;
}
-#define dsos__for_each_with_build_id(pos, head) \
- list_for_each_entry(pos, head, node) \
- if (!pos->has_build_id) \
- continue; \
- else
-
-static int write_buildid(const char *name, size_t name_len, u8 *build_id,
- pid_t pid, u16 misc, int fd)
-{
- int err;
- struct build_id_event b;
- size_t len;
-
- len = name_len + 1;
- len = PERF_ALIGN(len, NAME_ALIGN);
-
- memset(&b, 0, sizeof(b));
- memcpy(&b.build_id, build_id, BUILD_ID_SIZE);
- b.pid = pid;
- b.header.misc = misc;
- b.header.size = sizeof(b) + len;
-
- err = do_write(fd, &b, sizeof(b));
- if (err < 0)
- return err;
-
- return write_padded(fd, name, name_len + 1, len);
-}
-
-static int __dsos__hit_all(struct list_head *head)
-{
- struct dso *pos;
-
- list_for_each_entry(pos, head, node)
- pos->hit = true;
-
- return 0;
-}
-
-static int machine__hit_all_dsos(struct machine *machine)
-{
- int err;
-
- err = __dsos__hit_all(&machine->kernel_dsos.head);
- if (err)
- return err;
-
- return __dsos__hit_all(&machine->user_dsos.head);
-}
-
-int dsos__hit_all(struct perf_session *session)
-{
- struct rb_node *nd;
- int err;
-
- err = machine__hit_all_dsos(&session->machines.host);
- if (err)
- return err;
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
-
- err = machine__hit_all_dsos(pos);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int __dsos__write_buildid_table(struct list_head *head,
- struct machine *machine,
- pid_t pid, u16 misc, int fd)
-{
- char nm[PATH_MAX];
- struct dso *pos;
-
- dsos__for_each_with_build_id(pos, head) {
- int err;
- const char *name;
- size_t name_len;
-
- if (!pos->hit)
- continue;
-
- if (dso__is_vdso(pos)) {
- name = pos->short_name;
- name_len = pos->short_name_len + 1;
- } else if (dso__is_kcore(pos)) {
- machine__mmap_name(machine, nm, sizeof(nm));
- name = nm;
- name_len = strlen(nm) + 1;
- } else {
- name = pos->long_name;
- name_len = pos->long_name_len + 1;
- }
-
- err = write_buildid(name, name_len, pos->build_id,
- pid, misc, fd);
- if (err)
- return err;
- }
-
- return 0;
-}
-
-static int machine__write_buildid_table(struct machine *machine, int fd)
-{
- int err;
- u16 kmisc = PERF_RECORD_MISC_KERNEL,
- umisc = PERF_RECORD_MISC_USER;
-
- if (!machine__is_host(machine)) {
- kmisc = PERF_RECORD_MISC_GUEST_KERNEL;
- umisc = PERF_RECORD_MISC_GUEST_USER;
- }
-
- err = __dsos__write_buildid_table(&machine->kernel_dsos.head, machine,
- machine->pid, kmisc, fd);
- if (err == 0)
- err = __dsos__write_buildid_table(&machine->user_dsos.head,
- machine, machine->pid, umisc,
- fd);
- return err;
-}
-
-static int dsos__write_buildid_table(struct perf_header *header, int fd)
-{
- struct perf_session *session = container_of(header,
- struct perf_session, header);
- struct rb_node *nd;
- int err = machine__write_buildid_table(&session->machines.host, fd);
-
- if (err)
- return err;
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- err = machine__write_buildid_table(pos, fd);
- if (err)
- break;
- }
- return err;
-}
-
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
- const char *name, bool is_kallsyms, bool is_vdso)
-{
- const size_t size = PATH_MAX;
- char *realname, *filename = zalloc(size),
- *linkname = zalloc(size), *targetname;
- int len, err = -1;
- bool slash = is_kallsyms || is_vdso;
-
- if (is_kallsyms) {
- if (symbol_conf.kptr_restrict) {
- pr_debug("Not caching a kptr_restrict'ed /proc/kallsyms\n");
- err = 0;
- goto out_free;
- }
- realname = (char *) name;
- } else
- realname = realpath(name, NULL);
-
- if (realname == NULL || filename == NULL || linkname == NULL)
- goto out_free;
-
- len = scnprintf(filename, size, "%s%s%s",
- debugdir, slash ? "/" : "",
- is_vdso ? DSO__NAME_VDSO : realname);
- if (mkdir_p(filename, 0755))
- goto out_free;
-
- snprintf(filename + len, size - len, "/%s", sbuild_id);
-
- if (access(filename, F_OK)) {
- if (is_kallsyms) {
- if (copyfile("/proc/kallsyms", filename))
- goto out_free;
- } else if (link(realname, filename) && copyfile(name, filename))
- goto out_free;
- }
-
- len = scnprintf(linkname, size, "%s/.build-id/%.2s",
- debugdir, sbuild_id);
-
- if (access(linkname, X_OK) && mkdir_p(linkname, 0755))
- goto out_free;
-
- snprintf(linkname + len, size - len, "/%s", sbuild_id + 2);
- targetname = filename + strlen(debugdir) - 5;
- memcpy(targetname, "../..", 5);
-
- if (symlink(targetname, linkname) == 0)
- err = 0;
-out_free:
- if (!is_kallsyms)
- free(realname);
- free(filename);
- free(linkname);
- return err;
-}
-
-static int build_id_cache__add_b(const u8 *build_id, size_t build_id_size,
- const char *name, const char *debugdir,
- bool is_kallsyms, bool is_vdso)
-{
- char sbuild_id[BUILD_ID_SIZE * 2 + 1];
-
- build_id__sprintf(build_id, build_id_size, sbuild_id);
-
- return build_id_cache__add_s(sbuild_id, debugdir, name,
- is_kallsyms, is_vdso);
-}
-
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir)
-{
- const size_t size = PATH_MAX;
- char *filename = zalloc(size),
- *linkname = zalloc(size);
- int err = -1;
-
- if (filename == NULL || linkname == NULL)
- goto out_free;
-
- snprintf(linkname, size, "%s/.build-id/%.2s/%s",
- debugdir, sbuild_id, sbuild_id + 2);
-
- if (access(linkname, F_OK))
- goto out_free;
-
- if (readlink(linkname, filename, size - 1) < 0)
- goto out_free;
-
- if (unlink(linkname))
- goto out_free;
-
- /*
- * Since the link is relative, we must make it absolute:
- */
- snprintf(linkname, size, "%s/.build-id/%.2s/%s",
- debugdir, sbuild_id, filename);
-
- if (unlink(linkname))
- goto out_free;
-
- err = 0;
-out_free:
- free(filename);
- free(linkname);
- return err;
-}
-
-static int dso__cache_build_id(struct dso *dso, struct machine *machine,
- const char *debugdir)
-{
- bool is_kallsyms = dso->kernel && dso->long_name[0] != '/';
- bool is_vdso = dso__is_vdso(dso);
- const char *name = dso->long_name;
- char nm[PATH_MAX];
-
- if (dso__is_kcore(dso)) {
- is_kallsyms = true;
- machine__mmap_name(machine, nm, sizeof(nm));
- name = nm;
- }
- return build_id_cache__add_b(dso->build_id, sizeof(dso->build_id), name,
- debugdir, is_kallsyms, is_vdso);
-}
-
-static int __dsos__cache_build_ids(struct list_head *head,
- struct machine *machine, const char *debugdir)
-{
- struct dso *pos;
- int err = 0;
-
- dsos__for_each_with_build_id(pos, head)
- if (dso__cache_build_id(pos, machine, debugdir))
- err = -1;
-
- return err;
-}
-
-static int machine__cache_build_ids(struct machine *machine, const char *debugdir)
-{
- int ret = __dsos__cache_build_ids(&machine->kernel_dsos.head, machine,
- debugdir);
- ret |= __dsos__cache_build_ids(&machine->user_dsos.head, machine,
- debugdir);
- return ret;
-}
-
-static int perf_session__cache_build_ids(struct perf_session *session)
-{
- struct rb_node *nd;
- int ret;
- char debugdir[PATH_MAX];
-
- snprintf(debugdir, sizeof(debugdir), "%s", buildid_dir);
-
- if (mkdir(debugdir, 0755) != 0 && errno != EEXIST)
- return -1;
-
- ret = machine__cache_build_ids(&session->machines.host, debugdir);
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- ret |= machine__cache_build_ids(pos, debugdir);
- }
- return ret ? -1 : 0;
-}
-
-static bool machine__read_build_ids(struct machine *machine, bool with_hits)
-{
- bool ret;
-
- ret = __dsos__read_build_ids(&machine->kernel_dsos.head, with_hits);
- ret |= __dsos__read_build_ids(&machine->user_dsos.head, with_hits);
- return ret;
-}
-
-static bool perf_session__read_build_ids(struct perf_session *session, bool with_hits)
-{
- struct rb_node *nd;
- bool ret = machine__read_build_ids(&session->machines.host, with_hits);
-
- for (nd = rb_first(&session->machines.guests); nd; nd = rb_next(nd)) {
- struct machine *pos = rb_entry(nd, struct machine, rb_node);
- ret |= machine__read_build_ids(pos, with_hits);
- }
-
- return ret;
-}
-
static int write_tracing_data(int fd, struct perf_header *h __maybe_unused,
struct perf_evlist *evlist)
{
@@ -523,13 +184,12 @@ static int write_build_id(int fd, struct perf_header *h,
if (!perf_session__read_build_ids(session, true))
return -1;
- err = dsos__write_buildid_table(h, fd);
+ err = perf_session__write_buildid_table(session, fd);
if (err < 0) {
pr_debug("failed to write buildid table\n");
return err;
}
- if (!no_buildid_cache)
- perf_session__cache_build_ids(session);
+ perf_session__cache_build_ids(session);
return 0;
}
@@ -601,8 +261,10 @@ static int __write_cpudesc(int fd, const char *cpuinfo_proc)
break;
}
- if (ret)
+ if (ret) {
+ ret = -1;
goto done;
+ }
s = buf;
@@ -965,7 +627,8 @@ static int write_total_mem(int fd, struct perf_header *h __maybe_unused,
n = sscanf(buf, "%*s %"PRIu64, &mem);
if (n == 1)
ret = do_write(fd, &mem, sizeof(mem));
- }
+ } else
+ ret = -1;
free(buf);
fclose(fp);
return ret;
@@ -1603,7 +1266,7 @@ static int __event_process_build_id(struct build_id_event *bev,
dso__set_build_id(dso, &bev->build_id);
- if (filename[0] == '[')
+ if (!is_kernel_module(filename, NULL))
dso->kernel = dso_type;
build_id__sprintf(dso->build_id, sizeof(dso->build_id),
@@ -2477,6 +2140,7 @@ static const int attr_file_abi_sizes[] = {
[1] = PERF_ATTR_SIZE_VER1,
[2] = PERF_ATTR_SIZE_VER2,
[3] = PERF_ATTR_SIZE_VER3,
+ [4] = PERF_ATTR_SIZE_VER4,
0,
};
@@ -3124,8 +2788,3 @@ int perf_event__process_build_id(struct perf_tool *tool __maybe_unused,
session);
return 0;
}
-
-void disable_buildid_cache(void)
-{
- no_buildid_cache = true;
-}
diff --git a/tools/perf/util/header.h b/tools/perf/util/header.h
index 8f5cbae..3bb90ac 100644
--- a/tools/perf/util/header.h
+++ b/tools/perf/util/header.h
@@ -122,10 +122,6 @@ int perf_header__process_sections(struct perf_header *header, int fd,
int perf_header__fprintf_info(struct perf_session *s, FILE *fp, bool full);
-int build_id_cache__add_s(const char *sbuild_id, const char *debugdir,
- const char *name, bool is_kallsyms, bool is_vdso);
-int build_id_cache__remove_s(const char *sbuild_id, const char *debugdir);
-
int perf_event__synthesize_attr(struct perf_tool *tool,
struct perf_event_attr *attr, u32 ids, u64 *id,
perf_event__handler_t process);
@@ -151,7 +147,9 @@ int perf_event__process_build_id(struct perf_tool *tool,
struct perf_session *session);
bool is_perf_magic(u64 magic);
-int dsos__hit_all(struct perf_session *session);
+#define NAME_ALIGN 64
+
+int write_padded(int fd, const void *bf, size_t count, size_t count_aligned);
/*
* arch specific callback
diff --git a/tools/perf/util/include/linux/bitmap.h b/tools/perf/util/include/linux/bitmap.h
index 01ffd12..40bd214 100644
--- a/tools/perf/util/include/linux/bitmap.h
+++ b/tools/perf/util/include/linux/bitmap.h
@@ -46,4 +46,21 @@ static inline void bitmap_or(unsigned long *dst, const unsigned long *src1,
__bitmap_or(dst, src1, src2, nbits);
}
+/**
+ * test_and_set_bit - Set a bit and return its old value
+ * @nr: Bit to set
+ * @addr: Address to count from
+ */
+static inline int test_and_set_bit(int nr, unsigned long *addr)
+{
+ unsigned long mask = BIT_MASK(nr);
+ unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
+ unsigned long old;
+
+ old = *p;
+ *p = old | mask;
+
+ return (old & mask) != 0;
+}
+
#endif /* _PERF_BITOPS_H */
diff --git a/tools/perf/util/include/linux/bitops.h b/tools/perf/util/include/linux/bitops.h
index dadfa7e..c329416 100644
--- a/tools/perf/util/include/linux/bitops.h
+++ b/tools/perf/util/include/linux/bitops.h
@@ -15,6 +15,8 @@
#define BITS_TO_U64(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u64))
#define BITS_TO_U32(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(u32))
#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE)
+#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
+#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
#define for_each_set_bit(bit, addr, size) \
for ((bit) = find_first_bit((addr), (size)); \
diff --git a/tools/perf/util/machine.c b/tools/perf/util/machine.c
index 34fc7c8..15dd0a9 100644
--- a/tools/perf/util/machine.c
+++ b/tools/perf/util/machine.c
@@ -12,6 +12,7 @@
#include <stdbool.h>
#include <symbol/kallsyms.h>
#include "unwind.h"
+#include "linux/hash.h"
static void dsos__init(struct dsos *dsos)
{
@@ -21,7 +22,7 @@ static void dsos__init(struct dsos *dsos)
int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
{
- map_groups__init(&machine->kmaps);
+ map_groups__init(&machine->kmaps, machine);
RB_CLEAR_NODE(&machine->rb_node);
dsos__init(&machine->user_dsos);
dsos__init(&machine->kernel_dsos);
@@ -32,7 +33,6 @@ int machine__init(struct machine *machine, const char *root_dir, pid_t pid)
machine->vdso_info = NULL;
- machine->kmaps.machine = machine;
machine->pid = pid;
machine->symbol_filter = NULL;
@@ -319,7 +319,7 @@ static void machine__update_thread_pid(struct machine *machine,
goto out_err;
if (!leader->mg)
- leader->mg = map_groups__new();
+ leader->mg = map_groups__new(machine);
if (!leader->mg)
goto out_err;
@@ -465,6 +465,7 @@ struct map *machine__new_module(struct machine *machine, u64 start,
{
struct map *map;
struct dso *dso = __dsos__findnew(&machine->kernel_dsos, filename);
+ bool compressed;
if (dso == NULL)
return NULL;
@@ -477,6 +478,11 @@ struct map *machine__new_module(struct machine *machine, u64 start,
dso->symtab_type = DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE;
else
dso->symtab_type = DSO_BINARY_TYPE__GUEST_KMODULE;
+
+ /* _KMODULE_COMP should be next to _KMODULE */
+ if (is_kernel_module(filename, &compressed) && compressed)
+ dso->symtab_type++;
+
map_groups__insert(&machine->kmaps, map);
return map;
}
@@ -862,8 +868,14 @@ static int map_groups__set_modules_path_dir(struct map_groups *mg,
struct map *map;
char *long_name;
- if (dot == NULL || strcmp(dot, ".ko"))
+ if (dot == NULL)
continue;
+
+ /* On some system, modules are compressed like .ko.gz */
+ if (is_supported_compression(dot + 1) &&
+ is_kmodule_extension(dot - 2))
+ dot -= 3;
+
snprintf(dso_name, sizeof(dso_name), "[%.*s]",
(int)(dot - dent->d_name), dent->d_name);
@@ -1045,6 +1057,11 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
dot = strrchr(name, '.');
if (dot == NULL)
goto out_problem;
+ /* On some system, modules are compressed like .ko.gz */
+ if (is_supported_compression(dot + 1))
+ dot -= 3;
+ if (!is_kmodule_extension(dot + 1))
+ goto out_problem;
snprintf(short_module_name, sizeof(short_module_name),
"[%.*s]", (int)(dot - name), name);
strxfrchar(short_module_name, '-', '_');
@@ -1069,8 +1086,20 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
* Should be there already, from the build-id table in
* the header.
*/
- struct dso *kernel = __dsos__findnew(&machine->kernel_dsos,
- kmmap_prefix);
+ struct dso *kernel = NULL;
+ struct dso *dso;
+
+ list_for_each_entry(dso, &machine->kernel_dsos.head, node) {
+ if (is_kernel_module(dso->long_name, NULL))
+ continue;
+
+ kernel = dso;
+ break;
+ }
+
+ if (kernel == NULL)
+ kernel = __dsos__findnew(&machine->kernel_dsos,
+ kmmap_prefix);
if (kernel == NULL)
goto out_problem;
@@ -1078,6 +1107,9 @@ static int machine__process_kernel_mmap_event(struct machine *machine,
if (__machine__create_kernel_maps(machine, kernel) < 0)
goto out_problem;
+ if (strstr(kernel->long_name, "vmlinux"))
+ dso__set_short_name(kernel, "[kernel.vmlinux]", false);
+
machine__set_kernel_mmap_len(machine, event);
/*
@@ -1290,7 +1322,7 @@ static bool symbol__match_regex(struct symbol *sym, regex_t *regex)
return 0;
}
-static void ip__resolve_ams(struct machine *machine, struct thread *thread,
+static void ip__resolve_ams(struct thread *thread,
struct addr_map_symbol *ams,
u64 ip)
{
@@ -1304,7 +1336,7 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
* Thus, we have to try consecutively until we find a match
* or else, the symbol is unknown
*/
- thread__find_cpumode_addr_location(thread, machine, MAP__FUNCTION, ip, &al);
+ thread__find_cpumode_addr_location(thread, MAP__FUNCTION, ip, &al);
ams->addr = ip;
ams->al_addr = al.addr;
@@ -1312,23 +1344,21 @@ static void ip__resolve_ams(struct machine *machine, struct thread *thread,
ams->map = al.map;
}
-static void ip__resolve_data(struct machine *machine, struct thread *thread,
+static void ip__resolve_data(struct thread *thread,
u8 m, struct addr_map_symbol *ams, u64 addr)
{
struct addr_location al;
memset(&al, 0, sizeof(al));
- thread__find_addr_location(thread, machine, m, MAP__VARIABLE, addr,
- &al);
+ thread__find_addr_location(thread, m, MAP__VARIABLE, addr, &al);
if (al.map == NULL) {
/*
* some shared data regions have execute bit set which puts
* their mapping in the MAP__FUNCTION type array.
* Check there as a fallback option before dropping the sample.
*/
- thread__find_addr_location(thread, machine, m, MAP__FUNCTION, addr,
- &al);
+ thread__find_addr_location(thread, m, MAP__FUNCTION, addr, &al);
}
ams->addr = addr;
@@ -1345,14 +1375,45 @@ struct mem_info *sample__resolve_mem(struct perf_sample *sample,
if (!mi)
return NULL;
- ip__resolve_ams(al->machine, al->thread, &mi->iaddr, sample->ip);
- ip__resolve_data(al->machine, al->thread, al->cpumode,
- &mi->daddr, sample->addr);
+ ip__resolve_ams(al->thread, &mi->iaddr, sample->ip);
+ ip__resolve_data(al->thread, al->cpumode, &mi->daddr, sample->addr);
mi->data_src.val = sample->data_src;
return mi;
}
+static int add_callchain_ip(struct thread *thread,
+ struct symbol **parent,
+ struct addr_location *root_al,
+ int cpumode,
+ u64 ip)
+{
+ struct addr_location al;
+
+ al.filtered = 0;
+ al.sym = NULL;
+ if (cpumode == -1)
+ thread__find_cpumode_addr_location(thread, MAP__FUNCTION,
+ ip, &al);
+ else
+ thread__find_addr_location(thread, cpumode, MAP__FUNCTION,
+ ip, &al);
+ if (al.sym != NULL) {
+ if (sort__has_parent && !*parent &&
+ symbol__match_regex(al.sym, &parent_regex))
+ *parent = al.sym;
+ else if (have_ignore_callees && root_al &&
+ symbol__match_regex(al.sym, &ignore_callees_regex)) {
+ /* Treat this symbol as the root,
+ forgetting its callees. */
+ *root_al = al;
+ callchain_cursor_reset(&callchain_cursor);
+ }
+ }
+
+ return callchain_cursor_append(&callchain_cursor, al.addr, al.map, al.sym);
+}
+
struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
struct addr_location *al)
{
@@ -1364,16 +1425,57 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
return NULL;
for (i = 0; i < bs->nr; i++) {
- ip__resolve_ams(al->machine, al->thread, &bi[i].to, bs->entries[i].to);
- ip__resolve_ams(al->machine, al->thread, &bi[i].from, bs->entries[i].from);
+ ip__resolve_ams(al->thread, &bi[i].to, bs->entries[i].to);
+ ip__resolve_ams(al->thread, &bi[i].from, bs->entries[i].from);
bi[i].flags = bs->entries[i].flags;
}
return bi;
}
-static int machine__resolve_callchain_sample(struct machine *machine,
- struct thread *thread,
+#define CHASHSZ 127
+#define CHASHBITS 7
+#define NO_ENTRY 0xff
+
+#define PERF_MAX_BRANCH_DEPTH 127
+
+/* Remove loops. */
+static int remove_loops(struct branch_entry *l, int nr)
+{
+ int i, j, off;
+ unsigned char chash[CHASHSZ];
+
+ memset(chash, NO_ENTRY, sizeof(chash));
+
+ BUG_ON(PERF_MAX_BRANCH_DEPTH > 255);
+
+ for (i = 0; i < nr; i++) {
+ int h = hash_64(l[i].from, CHASHBITS) % CHASHSZ;
+
+ /* no collision handling for now */
+ if (chash[h] == NO_ENTRY) {
+ chash[h] = i;
+ } else if (l[chash[h]].from == l[i].from) {
+ bool is_loop = true;
+ /* check if it is a real loop */
+ off = 0;
+ for (j = chash[h]; j < i && i + off < nr; j++, off++)
+ if (l[j].from != l[i + off].from) {
+ is_loop = false;
+ break;
+ }
+ if (is_loop) {
+ memmove(l + i, l + i + off,
+ (nr - (i + off)) * sizeof(*l));
+ nr -= off;
+ }
+ }
+ }
+ return nr;
+}
+
+static int thread__resolve_callchain_sample(struct thread *thread,
struct ip_callchain *chain,
+ struct branch_stack *branch,
struct symbol **parent,
struct addr_location *root_al,
int max_stack)
@@ -1383,24 +1485,83 @@ static int machine__resolve_callchain_sample(struct machine *machine,
int i;
int j;
int err;
- int skip_idx __maybe_unused;
+ int skip_idx = -1;
+ int first_call = 0;
+
+ /*
+ * Based on DWARF debug information, some architectures skip
+ * a callchain entry saved by the kernel.
+ */
+ if (chain->nr < PERF_MAX_STACK_DEPTH)
+ skip_idx = arch_skip_callchain_idx(thread, chain);
callchain_cursor_reset(&callchain_cursor);
+ /*
+ * Add branches to call stack for easier browsing. This gives
+ * more context for a sample than just the callers.
+ *
+ * This uses individual histograms of paths compared to the
+ * aggregated histograms the normal LBR mode uses.
+ *
+ * Limitations for now:
+ * - No extra filters
+ * - No annotations (should annotate somehow)
+ */
+
+ if (branch && callchain_param.branch_callstack) {
+ int nr = min(max_stack, (int)branch->nr);
+ struct branch_entry be[nr];
+
+ if (branch->nr > PERF_MAX_BRANCH_DEPTH) {
+ pr_warning("corrupted branch chain. skipping...\n");
+ goto check_calls;
+ }
+
+ for (i = 0; i < nr; i++) {
+ if (callchain_param.order == ORDER_CALLEE) {
+ be[i] = branch->entries[i];
+ /*
+ * Check for overlap into the callchain.
+ * The return address is one off compared to
+ * the branch entry. To adjust for this
+ * assume the calling instruction is not longer
+ * than 8 bytes.
+ */
+ if (i == skip_idx ||
+ chain->ips[first_call] >= PERF_CONTEXT_MAX)
+ first_call++;
+ else if (be[i].from < chain->ips[first_call] &&
+ be[i].from >= chain->ips[first_call] - 8)
+ first_call++;
+ } else
+ be[i] = branch->entries[branch->nr - i - 1];
+ }
+
+ nr = remove_loops(be, nr);
+
+ for (i = 0; i < nr; i++) {
+ err = add_callchain_ip(thread, parent, root_al,
+ -1, be[i].to);
+ if (!err)
+ err = add_callchain_ip(thread, parent, root_al,
+ -1, be[i].from);
+ if (err == -EINVAL)
+ break;
+ if (err)
+ return err;
+ }
+ chain_nr -= nr;
+ }
+
+check_calls:
if (chain->nr > PERF_MAX_STACK_DEPTH) {
pr_warning("corrupted callchain. skipping...\n");
return 0;
}
- /*
- * Based on DWARF debug information, some architectures skip
- * a callchain entry saved by the kernel.
- */
- skip_idx = arch_skip_callchain_idx(machine, thread, chain);
-
- for (i = 0; i < chain_nr; i++) {
+ for (i = first_call; i < chain_nr; i++) {
u64 ip;
- struct addr_location al;
if (callchain_param.order == ORDER_CALLEE)
j = i;
@@ -1437,24 +1598,10 @@ static int machine__resolve_callchain_sample(struct machine *machine,
continue;
}
- al.filtered = 0;
- thread__find_addr_location(thread, machine, cpumode,
- MAP__FUNCTION, ip, &al);
- if (al.sym != NULL) {
- if (sort__has_parent && !*parent &&
- symbol__match_regex(al.sym, &parent_regex))
- *parent = al.sym;
- else if (have_ignore_callees && root_al &&
- symbol__match_regex(al.sym, &ignore_callees_regex)) {
- /* Treat this symbol as the root,
- forgetting its callees. */
- *root_al = al;
- callchain_cursor_reset(&callchain_cursor);
- }
- }
-
- err = callchain_cursor_append(&callchain_cursor,
- ip, al.map, al.sym);
+ err = add_callchain_ip(thread, parent, root_al,
+ cpumode, ip);
+ if (err == -EINVAL)
+ break;
if (err)
return err;
}
@@ -1469,19 +1616,16 @@ static int unwind_entry(struct unwind_entry *entry, void *arg)
entry->map, entry->sym);
}
-int machine__resolve_callchain(struct machine *machine,
- struct perf_evsel *evsel,
- struct thread *thread,
- struct perf_sample *sample,
- struct symbol **parent,
- struct addr_location *root_al,
- int max_stack)
+int thread__resolve_callchain(struct thread *thread,
+ struct perf_evsel *evsel,
+ struct perf_sample *sample,
+ struct symbol **parent,
+ struct addr_location *root_al,
+ int max_stack)
{
- int ret;
-
- ret = machine__resolve_callchain_sample(machine, thread,
- sample->callchain, parent,
- root_al, max_stack);
+ int ret = thread__resolve_callchain_sample(thread, sample->callchain,
+ sample->branch_stack,
+ parent, root_al, max_stack);
if (ret)
return ret;
@@ -1495,7 +1639,7 @@ int machine__resolve_callchain(struct machine *machine,
(!sample->user_stack.size))
return 0;
- return unwind__get_entries(unwind_entry, &callchain_cursor, machine,
+ return unwind__get_entries(unwind_entry, &callchain_cursor,
thread, sample, max_stack);
}
diff --git a/tools/perf/util/machine.h b/tools/perf/util/machine.h
index 2b651a7..e8b7779 100644
--- a/tools/perf/util/machine.h
+++ b/tools/perf/util/machine.h
@@ -40,6 +40,10 @@ struct machine {
u64 kernel_start;
symbol_filter_t symbol_filter;
pid_t *current_tid;
+ union { /* Tool specific area */
+ void *priv;
+ u64 db_id;
+ };
};
static inline
@@ -122,13 +126,12 @@ struct branch_info *sample__resolve_bstack(struct perf_sample *sample,
struct addr_location *al);
struct mem_info *sample__resolve_mem(struct perf_sample *sample,
struct addr_location *al);
-int machine__resolve_callchain(struct machine *machine,
- struct perf_evsel *evsel,
- struct thread *thread,
- struct perf_sample *sample,
- struct symbol **parent,
- struct addr_location *root_al,
- int max_stack);
+int thread__resolve_callchain(struct thread *thread,
+ struct perf_evsel *evsel,
+ struct perf_sample *sample,
+ struct symbol **parent,
+ struct addr_location *root_al,
+ int max_stack);
/*
* Default guest kernel is defined by parameter --guestkallsyms
diff --git a/tools/perf/util/map.c b/tools/perf/util/map.c
index 2137c45..62ca9f2 100644
--- a/tools/perf/util/map.c
+++ b/tools/perf/util/map.c
@@ -360,7 +360,7 @@ int map__fprintf_srcline(struct map *map, u64 addr, const char *prefix,
if (map && map->dso) {
srcline = get_srcline(map->dso,
- map__rip_2objdump(map, addr));
+ map__rip_2objdump(map, addr), NULL, true);
if (srcline != SRCLINE_UNKNOWN)
ret = fprintf(fp, "%s%s", prefix, srcline);
free_srcline(srcline);
@@ -413,14 +413,14 @@ u64 map__objdump_2mem(struct map *map, u64 ip)
return ip + map->reloc;
}
-void map_groups__init(struct map_groups *mg)
+void map_groups__init(struct map_groups *mg, struct machine *machine)
{
int i;
for (i = 0; i < MAP__NR_TYPES; ++i) {
mg->maps[i] = RB_ROOT;
INIT_LIST_HEAD(&mg->removed_maps[i]);
}
- mg->machine = NULL;
+ mg->machine = machine;
mg->refcnt = 1;
}
@@ -471,12 +471,12 @@ bool map_groups__empty(struct map_groups *mg)
return true;
}
-struct map_groups *map_groups__new(void)
+struct map_groups *map_groups__new(struct machine *machine)
{
struct map_groups *mg = malloc(sizeof(*mg));
if (mg != NULL)
- map_groups__init(mg);
+ map_groups__init(mg, machine);
return mg;
}
diff --git a/tools/perf/util/map.h b/tools/perf/util/map.h
index 2f83954..6951a9d 100644
--- a/tools/perf/util/map.h
+++ b/tools/perf/util/map.h
@@ -64,7 +64,7 @@ struct map_groups {
int refcnt;
};
-struct map_groups *map_groups__new(void);
+struct map_groups *map_groups__new(struct machine *machine);
void map_groups__delete(struct map_groups *mg);
bool map_groups__empty(struct map_groups *mg);
@@ -150,7 +150,7 @@ void maps__remove(struct rb_root *maps, struct map *map);
struct map *maps__find(struct rb_root *maps, u64 addr);
struct map *maps__first(struct rb_root *maps);
struct map *maps__next(struct map *map);
-void map_groups__init(struct map_groups *mg);
+void map_groups__init(struct map_groups *mg, struct machine *machine);
void map_groups__exit(struct map_groups *mg);
int map_groups__clone(struct map_groups *mg,
struct map_groups *parent, enum map_type type);
diff --git a/tools/perf/util/parse-events.c b/tools/perf/util/parse-events.c
index c659a3c..77b43fe 100644
--- a/tools/perf/util/parse-events.c
+++ b/tools/perf/util/parse-events.c
@@ -681,6 +681,8 @@ int parse_events_add_pmu(struct list_head *list, int *idx,
if (evsel) {
evsel->unit = info.unit;
evsel->scale = info.scale;
+ evsel->per_pkg = info.per_pkg;
+ evsel->snapshot = info.snapshot;
}
return evsel ? 0 : -ENOMEM;
diff --git a/tools/perf/util/parse-options.c b/tools/perf/util/parse-options.c
index bf48092..f62dee7b 100644
--- a/tools/perf/util/parse-options.c
+++ b/tools/perf/util/parse-options.c
@@ -42,7 +42,26 @@ static int get_value(struct parse_opt_ctx_t *p,
return opterror(opt, "takes no value", flags);
if (unset && (opt->flags & PARSE_OPT_NONEG))
return opterror(opt, "isn't available", flags);
-
+ if (opt->flags & PARSE_OPT_DISABLED)
+ return opterror(opt, "is not usable", flags);
+
+ if (opt->flags & PARSE_OPT_EXCLUSIVE) {
+ if (p->excl_opt) {
+ char msg[128];
+
+ if (((flags & OPT_SHORT) && p->excl_opt->short_name) ||
+ p->excl_opt->long_name == NULL) {
+ scnprintf(msg, sizeof(msg), "cannot be used with switch `%c'",
+ p->excl_opt->short_name);
+ } else {
+ scnprintf(msg, sizeof(msg), "cannot be used with %s",
+ p->excl_opt->long_name);
+ }
+ opterror(opt, msg, flags);
+ return -3;
+ }
+ p->excl_opt = opt;
+ }
if (!(flags & OPT_SHORT) && p->opt) {
switch (opt->type) {
case OPTION_CALLBACK:
@@ -343,13 +362,14 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
const char * const usagestr[])
{
int internal_help = !(ctx->flags & PARSE_OPT_NO_INTERNAL_HELP);
+ int excl_short_opt = 1;
+ const char *arg;
/* we must reset ->opt, unknown short option leave it dangling */
ctx->opt = NULL;
for (; ctx->argc; ctx->argc--, ctx->argv++) {
- const char *arg = ctx->argv[0];
-
+ arg = ctx->argv[0];
if (*arg != '-' || !arg[1]) {
if (ctx->flags & PARSE_OPT_STOP_AT_NON_OPTION)
break;
@@ -358,19 +378,21 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
}
if (arg[1] != '-') {
- ctx->opt = arg + 1;
+ ctx->opt = ++arg;
if (internal_help && *ctx->opt == 'h')
return usage_with_options_internal(usagestr, options, 0);
switch (parse_short_opt(ctx, options)) {
case -1:
- return parse_options_usage(usagestr, options, arg + 1, 1);
+ return parse_options_usage(usagestr, options, arg, 1);
case -2:
goto unknown;
+ case -3:
+ goto exclusive;
default:
break;
}
if (ctx->opt)
- check_typos(arg + 1, options);
+ check_typos(arg, options);
while (ctx->opt) {
if (internal_help && *ctx->opt == 'h')
return usage_with_options_internal(usagestr, options, 0);
@@ -387,6 +409,8 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
ctx->argv[0] = strdup(ctx->opt - 1);
*(char *)ctx->argv[0] = '-';
goto unknown;
+ case -3:
+ goto exclusive;
default:
break;
}
@@ -402,19 +426,23 @@ int parse_options_step(struct parse_opt_ctx_t *ctx,
break;
}
- if (internal_help && !strcmp(arg + 2, "help-all"))
+ arg += 2;
+ if (internal_help && !strcmp(arg, "help-all"))
return usage_with_options_internal(usagestr, options, 1);
- if (internal_help && !strcmp(arg + 2, "help"))
+ if (internal_help && !strcmp(arg, "help"))
return usage_with_options_internal(usagestr, options, 0);
- if (!strcmp(arg + 2, "list-opts"))
+ if (!strcmp(arg, "list-opts"))
return PARSE_OPT_LIST_OPTS;
- if (!strcmp(arg + 2, "list-cmds"))
+ if (!strcmp(arg, "list-cmds"))
return PARSE_OPT_LIST_SUBCMDS;
- switch (parse_long_opt(ctx, arg + 2, options)) {
+ switch (parse_long_opt(ctx, arg, options)) {
case -1:
- return parse_options_usage(usagestr, options, arg + 2, 0);
+ return parse_options_usage(usagestr, options, arg, 0);
case -2:
goto unknown;
+ case -3:
+ excl_short_opt = 0;
+ goto exclusive;
default:
break;
}
@@ -426,6 +454,17 @@ unknown:
ctx->opt = NULL;
}
return PARSE_OPT_DONE;
+
+exclusive:
+ parse_options_usage(usagestr, options, arg, excl_short_opt);
+ if ((excl_short_opt && ctx->excl_opt->short_name) ||
+ ctx->excl_opt->long_name == NULL) {
+ char opt = ctx->excl_opt->short_name;
+ parse_options_usage(NULL, options, &opt, 1);
+ } else {
+ parse_options_usage(NULL, options, ctx->excl_opt->long_name, 0);
+ }
+ return PARSE_OPT_HELP;
}
int parse_options_end(struct parse_opt_ctx_t *ctx)
@@ -509,6 +548,8 @@ static void print_option_help(const struct option *opts, int full)
}
if (!full && (opts->flags & PARSE_OPT_HIDDEN))
return;
+ if (opts->flags & PARSE_OPT_DISABLED)
+ return;
pos = fprintf(stderr, " ");
if (opts->short_name)
@@ -679,3 +720,16 @@ int parse_opt_verbosity_cb(const struct option *opt,
}
return 0;
}
+
+void set_option_flag(struct option *opts, int shortopt, const char *longopt,
+ int flag)
+{
+ for (; opts->type != OPTION_END; opts++) {
+ if ((shortopt && opts->short_name == shortopt) ||
+ (opts->long_name && longopt &&
+ !strcmp(opts->long_name, longopt))) {
+ opts->flags |= flag;
+ break;
+ }
+ }
+}
diff --git a/tools/perf/util/parse-options.h b/tools/perf/util/parse-options.h
index b59ba85..97b153f 100644
--- a/tools/perf/util/parse-options.h
+++ b/tools/perf/util/parse-options.h
@@ -38,6 +38,8 @@ enum parse_opt_option_flags {
PARSE_OPT_NONEG = 4,
PARSE_OPT_HIDDEN = 8,
PARSE_OPT_LASTARG_DEFAULT = 16,
+ PARSE_OPT_DISABLED = 32,
+ PARSE_OPT_EXCLUSIVE = 64,
};
struct option;
@@ -173,6 +175,7 @@ struct parse_opt_ctx_t {
const char **out;
int argc, cpidx;
const char *opt;
+ const struct option *excl_opt;
int flags;
};
@@ -211,4 +214,5 @@ extern int parse_opt_verbosity_cb(const struct option *, const char *, int);
extern const char *parse_options_fix_filename(const char *prefix, const char *file);
+void set_option_flag(struct option *opts, int sopt, const char *lopt, int flag);
#endif /* __PERF_PARSE_OPTIONS_H */
diff --git a/tools/perf/util/pmu.c b/tools/perf/util/pmu.c
index e243ad9..5c9c494 100644
--- a/tools/perf/util/pmu.c
+++ b/tools/perf/util/pmu.c
@@ -163,6 +163,41 @@ error:
return -1;
}
+static int
+perf_pmu__parse_per_pkg(struct perf_pmu_alias *alias, char *dir, char *name)
+{
+ char path[PATH_MAX];
+ int fd;
+
+ snprintf(path, PATH_MAX, "%s/%s.per-pkg", dir, name);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ close(fd);
+
+ alias->per_pkg = true;
+ return 0;
+}
+
+static int perf_pmu__parse_snapshot(struct perf_pmu_alias *alias,
+ char *dir, char *name)
+{
+ char path[PATH_MAX];
+ int fd;
+
+ snprintf(path, PATH_MAX, "%s/%s.snapshot", dir, name);
+
+ fd = open(path, O_RDONLY);
+ if (fd == -1)
+ return -1;
+
+ alias->snapshot = true;
+ close(fd);
+ return 0;
+}
+
static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FILE *file)
{
struct perf_pmu_alias *alias;
@@ -181,6 +216,7 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
INIT_LIST_HEAD(&alias->terms);
alias->scale = 1.0;
alias->unit[0] = '\0';
+ alias->per_pkg = false;
ret = parse_events_terms(&alias->terms, buf);
if (ret) {
@@ -194,6 +230,8 @@ static int perf_pmu__new_alias(struct list_head *list, char *dir, char *name, FI
*/
perf_pmu__parse_unit(alias, dir, name);
perf_pmu__parse_scale(alias, dir, name);
+ perf_pmu__parse_per_pkg(alias, dir, name);
+ perf_pmu__parse_snapshot(alias, dir, name);
list_add_tail(&alias->list, list);
@@ -209,6 +247,10 @@ static inline bool pmu_alias_info_file(char *name)
return true;
if (len > 6 && !strcmp(name + len - 6, ".scale"))
return true;
+ if (len > 8 && !strcmp(name + len - 8, ".per-pkg"))
+ return true;
+ if (len > 9 && !strcmp(name + len - 9, ".snapshot"))
+ return true;
return false;
}
@@ -617,23 +659,27 @@ static struct perf_pmu_alias *pmu_find_alias(struct perf_pmu *pmu,
}
-static int check_unit_scale(struct perf_pmu_alias *alias,
- const char **unit, double *scale)
+static int check_info_data(struct perf_pmu_alias *alias,
+ struct perf_pmu_info *info)
{
/*
* Only one term in event definition can
- * define unit and scale, fail if there's
- * more than one.
+ * define unit, scale and snapshot, fail
+ * if there's more than one.
*/
- if ((*unit && alias->unit) ||
- (*scale && alias->scale))
+ if ((info->unit && alias->unit) ||
+ (info->scale && alias->scale) ||
+ (info->snapshot && alias->snapshot))
return -EINVAL;
if (alias->unit)
- *unit = alias->unit;
+ info->unit = alias->unit;
if (alias->scale)
- *scale = alias->scale;
+ info->scale = alias->scale;
+
+ if (alias->snapshot)
+ info->snapshot = alias->snapshot;
return 0;
}
@@ -649,12 +695,15 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
struct perf_pmu_alias *alias;
int ret;
+ info->per_pkg = false;
+
/*
* Mark unit and scale as not set
* (different from default values, see below)
*/
- info->unit = NULL;
- info->scale = 0.0;
+ info->unit = NULL;
+ info->scale = 0.0;
+ info->snapshot = false;
list_for_each_entry_safe(term, h, head_terms, list) {
alias = pmu_find_alias(pmu, term);
@@ -664,10 +713,13 @@ int perf_pmu__check_alias(struct perf_pmu *pmu, struct list_head *head_terms,
if (ret)
return ret;
- ret = check_unit_scale(alias, &info->unit, &info->scale);
+ ret = check_info_data(alias, info);
if (ret)
return ret;
+ if (alias->per_pkg)
+ info->per_pkg = true;
+
list_del(&term->list);
free(term);
}
@@ -747,15 +799,18 @@ void print_pmu_events(const char *event_glob, bool name_only)
pmu = NULL;
len = 0;
- while ((pmu = perf_pmu__scan(pmu)) != NULL)
+ while ((pmu = perf_pmu__scan(pmu)) != NULL) {
list_for_each_entry(alias, &pmu->aliases, list)
len++;
- aliases = malloc(sizeof(char *) * len);
+ if (pmu->selectable)
+ len++;
+ }
+ aliases = zalloc(sizeof(char *) * len);
if (!aliases)
- return;
+ goto out_enomem;
pmu = NULL;
j = 0;
- while ((pmu = perf_pmu__scan(pmu)) != NULL)
+ while ((pmu = perf_pmu__scan(pmu)) != NULL) {
list_for_each_entry(alias, &pmu->aliases, list) {
char *name = format_alias(buf, sizeof(buf), pmu, alias);
bool is_cpu = !strcmp(pmu->name, "cpu");
@@ -765,13 +820,23 @@ void print_pmu_events(const char *event_glob, bool name_only)
(!is_cpu && strglobmatch(alias->name,
event_glob))))
continue;
- aliases[j] = name;
+
if (is_cpu && !name_only)
- aliases[j] = format_alias_or(buf, sizeof(buf),
- pmu, alias);
- aliases[j] = strdup(aliases[j]);
+ name = format_alias_or(buf, sizeof(buf), pmu, alias);
+
+ aliases[j] = strdup(name);
+ if (aliases[j] == NULL)
+ goto out_enomem;
j++;
}
+ if (pmu->selectable) {
+ char *s;
+ if (asprintf(&s, "%s//", pmu->name) < 0)
+ goto out_enomem;
+ aliases[j] = s;
+ j++;
+ }
+ }
len = j;
qsort(aliases, len, sizeof(char *), cmp_string);
for (j = 0; j < len; j++) {
@@ -780,12 +845,20 @@ void print_pmu_events(const char *event_glob, bool name_only)
continue;
}
printf(" %-50s [Kernel PMU event]\n", aliases[j]);
- zfree(&aliases[j]);
printed++;
}
if (printed)
printf("\n");
- free(aliases);
+out_free:
+ for (j = 0; j < len; j++)
+ zfree(&aliases[j]);
+ zfree(&aliases);
+ return;
+
+out_enomem:
+ printf("FATAL: not enough memory to print PMU events\n");
+ if (aliases)
+ goto out_free;
}
bool pmu_have_event(const char *pname, const char *name)
diff --git a/tools/perf/util/pmu.h b/tools/perf/util/pmu.h
index fe9dfbe..6b1249f 100644
--- a/tools/perf/util/pmu.h
+++ b/tools/perf/util/pmu.h
@@ -18,6 +18,7 @@ struct perf_event_attr;
struct perf_pmu {
char *name;
__u32 type;
+ bool selectable;
struct perf_event_attr *default_config;
struct cpu_map *cpus;
struct list_head format; /* HEAD struct perf_pmu_format -> list */
@@ -28,6 +29,8 @@ struct perf_pmu {
struct perf_pmu_info {
const char *unit;
double scale;
+ bool per_pkg;
+ bool snapshot;
};
#define UNIT_MAX_LEN 31 /* max length for event unit name */
@@ -38,6 +41,8 @@ struct perf_pmu_alias {
struct list_head list; /* ELEM */
char unit[UNIT_MAX_LEN+1];
double scale;
+ bool per_pkg;
+ bool snapshot;
};
struct perf_pmu *perf_pmu__find(const char *name);
diff --git a/tools/perf/util/probe-event.c b/tools/perf/util/probe-event.c
index c150ca4..28eb141 100644
--- a/tools/perf/util/probe-event.c
+++ b/tools/perf/util/probe-event.c
@@ -1910,21 +1910,21 @@ static int show_perf_probe_event(struct perf_probe_event *pev,
if (ret < 0)
return ret;
- printf(" %-20s (on %s", buf, place);
+ pr_info(" %-20s (on %s", buf, place);
if (module)
- printf(" in %s", module);
+ pr_info(" in %s", module);
if (pev->nargs > 0) {
- printf(" with");
+ pr_info(" with");
for (i = 0; i < pev->nargs; i++) {
ret = synthesize_perf_probe_arg(&pev->args[i],
buf, 128);
if (ret < 0)
break;
- printf(" %s", buf);
+ pr_info(" %s", buf);
}
}
- printf(")\n");
+ pr_info(")\n");
free(place);
return ret;
}
@@ -2124,7 +2124,7 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
}
ret = 0;
- printf("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
+ pr_info("Added new event%s\n", (ntevs > 1) ? "s:" : ":");
for (i = 0; i < ntevs; i++) {
tev = &tevs[i];
if (pev->event)
@@ -2179,8 +2179,8 @@ static int __add_probe_trace_events(struct perf_probe_event *pev,
if (ret >= 0) {
/* Show how to use the event. */
- printf("\nYou can now use it in all perf tools, such as:\n\n");
- printf("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
+ pr_info("\nYou can now use it in all perf tools, such as:\n\n");
+ pr_info("\tperf record -e %s:%s -aR sleep 1\n\n", tev->group,
tev->event);
}
@@ -2444,7 +2444,7 @@ static int __del_trace_probe_event(int fd, struct str_node *ent)
goto error;
}
- printf("Removed event: %s\n", ent->s);
+ pr_info("Removed event: %s\n", ent->s);
return 0;
error:
pr_warning("Failed to delete event: %s\n",
diff --git a/tools/perf/util/scripting-engines/trace-event-perl.c b/tools/perf/util/scripting-engines/trace-event-perl.c
index 0a01bac..22ebc46 100644
--- a/tools/perf/util/scripting-engines/trace-event-perl.c
+++ b/tools/perf/util/scripting-engines/trace-event-perl.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <ctype.h>
#include <errno.h>
+#include <linux/bitmap.h>
#include "../util.h"
#include <EXTERN.h>
@@ -57,7 +58,7 @@ INTERP my_perl;
#define FTRACE_MAX_EVENT \
((1 << (sizeof(unsigned short) * 8)) - 1)
-struct event_format *events[FTRACE_MAX_EVENT];
+static DECLARE_BITMAP(events_defined, FTRACE_MAX_EVENT);
extern struct scripting_context *scripting_context;
@@ -238,35 +239,15 @@ static void define_event_symbols(struct event_format *event,
define_event_symbols(event, ev_name, args->next);
}
-static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
-{
- static char ev_name[256];
- struct event_format *event;
- int type = evsel->attr.config;
-
- if (events[type])
- return events[type];
-
- events[type] = event = evsel->tp_format;
- if (!event)
- return NULL;
-
- sprintf(ev_name, "%s::%s", event->system, event->name);
-
- define_event_symbols(event, ev_name, event->print_fmt.args);
-
- return event;
-}
-
static void perl_process_tracepoint(struct perf_sample *sample,
struct perf_evsel *evsel,
struct thread *thread)
{
+ struct event_format *event = evsel->tp_format;
struct format_field *field;
static char handler[256];
unsigned long long val;
unsigned long s, ns;
- struct event_format *event;
int pid;
int cpu = sample->cpu;
void *data = sample->raw_data;
@@ -278,7 +259,6 @@ static void perl_process_tracepoint(struct perf_sample *sample,
if (evsel->attr.type != PERF_TYPE_TRACEPOINT)
return;
- event = find_cache_event(evsel);
if (!event)
die("ug! no event found for type %" PRIu64, (u64)evsel->attr.config);
@@ -286,6 +266,9 @@ static void perl_process_tracepoint(struct perf_sample *sample,
sprintf(handler, "%s::%s", event->system, event->name);
+ if (!test_and_set_bit(event->id, events_defined))
+ define_event_symbols(event, handler, event->print_fmt.args);
+
s = nsecs / NSECS_PER_SEC;
ns = nsecs - s * NSECS_PER_SEC;
diff --git a/tools/perf/util/scripting-engines/trace-event-python.c b/tools/perf/util/scripting-engines/trace-event-python.c
index 496f21c..d808a32 100644
--- a/tools/perf/util/scripting-engines/trace-event-python.c
+++ b/tools/perf/util/scripting-engines/trace-event-python.c
@@ -24,7 +24,9 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <stdbool.h>
#include <errno.h>
+#include <linux/bitmap.h>
#include "../../perf.h"
#include "../debug.h"
@@ -33,6 +35,10 @@
#include "../util.h"
#include "../event.h"
#include "../thread.h"
+#include "../comm.h"
+#include "../machine.h"
+#include "../db-export.h"
+#include "../thread-stack.h"
#include "../trace-event.h"
#include "../machine.h"
@@ -41,7 +47,7 @@ PyMODINIT_FUNC initperf_trace_context(void);
#define FTRACE_MAX_EVENT \
((1 << (sizeof(unsigned short) * 8)) - 1)
-struct event_format *events[FTRACE_MAX_EVENT];
+static DECLARE_BITMAP(events_defined, FTRACE_MAX_EVENT);
#define MAX_FIELDS 64
#define N_COMMON_FIELDS 7
@@ -53,6 +59,24 @@ static int zero_flag_atom;
static PyObject *main_module, *main_dict;
+struct tables {
+ struct db_export dbe;
+ PyObject *evsel_handler;
+ PyObject *machine_handler;
+ PyObject *thread_handler;
+ PyObject *comm_handler;
+ PyObject *comm_thread_handler;
+ PyObject *dso_handler;
+ PyObject *symbol_handler;
+ PyObject *branch_type_handler;
+ PyObject *sample_handler;
+ PyObject *call_path_handler;
+ PyObject *call_return_handler;
+ bool db_export_mode;
+};
+
+static struct tables tables_global;
+
static void handler_call_die(const char *handler_name) NORETURN;
static void handler_call_die(const char *handler_name)
{
@@ -232,31 +256,6 @@ static void define_event_symbols(struct event_format *event,
define_event_symbols(event, ev_name, args->next);
}
-static inline struct event_format *find_cache_event(struct perf_evsel *evsel)
-{
- static char ev_name[256];
- struct event_format *event;
- int type = evsel->attr.config;
-
- /*
- * XXX: Do we really need to cache this since now we have evsel->tp_format
- * cached already? Need to re-read this "cache" routine that as well calls
- * define_event_symbols() :-\
- */
- if (events[type])
- return events[type];
-
- events[type] = event = evsel->tp_format;
- if (!event)
- return NULL;
-
- sprintf(ev_name, "%s__%s", event->system, event->name);
-
- define_event_symbols(event, ev_name, event->print_fmt.args);
-
- return event;
-}
-
static PyObject *get_field_numeric_entry(struct event_format *event,
struct format_field *field, void *data)
{
@@ -312,9 +311,9 @@ static PyObject *python_process_callchain(struct perf_sample *sample,
if (!symbol_conf.use_callchain || !sample->callchain)
goto exit;
- if (machine__resolve_callchain(al->machine, evsel, al->thread,
- sample, NULL, NULL,
- PERF_MAX_STACK_DEPTH) != 0) {
+ if (thread__resolve_callchain(al->thread, evsel,
+ sample, NULL, NULL,
+ PERF_MAX_STACK_DEPTH) != 0) {
pr_err("Failed to resolve callchain. Skipping\n");
goto exit;
}
@@ -380,12 +379,12 @@ static void python_process_tracepoint(struct perf_sample *sample,
struct thread *thread,
struct addr_location *al)
{
+ struct event_format *event = evsel->tp_format;
PyObject *handler, *context, *t, *obj, *callchain;
PyObject *dict = NULL;
static char handler_name[256];
struct format_field *field;
unsigned long s, ns;
- struct event_format *event;
unsigned n = 0;
int pid;
int cpu = sample->cpu;
@@ -397,7 +396,6 @@ static void python_process_tracepoint(struct perf_sample *sample,
if (!t)
Py_FatalError("couldn't create Python tuple");
- event = find_cache_event(evsel);
if (!event)
die("ug! no event found for type %d", (int)evsel->attr.config);
@@ -405,6 +403,9 @@ static void python_process_tracepoint(struct perf_sample *sample,
sprintf(handler_name, "%s__%s", event->system, event->name);
+ if (!test_and_set_bit(event->id, events_defined))
+ define_event_symbols(event, handler_name, event->print_fmt.args);
+
handler = get_handler(handler_name);
if (!handler) {
dict = PyDict_New();
@@ -475,6 +476,289 @@ static void python_process_tracepoint(struct perf_sample *sample,
Py_DECREF(t);
}
+static PyObject *tuple_new(unsigned int sz)
+{
+ PyObject *t;
+
+ t = PyTuple_New(sz);
+ if (!t)
+ Py_FatalError("couldn't create Python tuple");
+ return t;
+}
+
+static int tuple_set_u64(PyObject *t, unsigned int pos, u64 val)
+{
+#if BITS_PER_LONG == 64
+ return PyTuple_SetItem(t, pos, PyInt_FromLong(val));
+#endif
+#if BITS_PER_LONG == 32
+ return PyTuple_SetItem(t, pos, PyLong_FromLongLong(val));
+#endif
+}
+
+static int tuple_set_s32(PyObject *t, unsigned int pos, s32 val)
+{
+ return PyTuple_SetItem(t, pos, PyInt_FromLong(val));
+}
+
+static int tuple_set_string(PyObject *t, unsigned int pos, const char *s)
+{
+ return PyTuple_SetItem(t, pos, PyString_FromString(s));
+}
+
+static int python_export_evsel(struct db_export *dbe, struct perf_evsel *evsel)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(2);
+
+ tuple_set_u64(t, 0, evsel->db_id);
+ tuple_set_string(t, 1, perf_evsel__name(evsel));
+
+ call_object(tables->evsel_handler, t, "evsel_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_machine(struct db_export *dbe,
+ struct machine *machine)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(3);
+
+ tuple_set_u64(t, 0, machine->db_id);
+ tuple_set_s32(t, 1, machine->pid);
+ tuple_set_string(t, 2, machine->root_dir ? machine->root_dir : "");
+
+ call_object(tables->machine_handler, t, "machine_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_thread(struct db_export *dbe, struct thread *thread,
+ u64 main_thread_db_id, struct machine *machine)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(5);
+
+ tuple_set_u64(t, 0, thread->db_id);
+ tuple_set_u64(t, 1, machine->db_id);
+ tuple_set_u64(t, 2, main_thread_db_id);
+ tuple_set_s32(t, 3, thread->pid_);
+ tuple_set_s32(t, 4, thread->tid);
+
+ call_object(tables->thread_handler, t, "thread_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_comm(struct db_export *dbe, struct comm *comm)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(2);
+
+ tuple_set_u64(t, 0, comm->db_id);
+ tuple_set_string(t, 1, comm__str(comm));
+
+ call_object(tables->comm_handler, t, "comm_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_comm_thread(struct db_export *dbe, u64 db_id,
+ struct comm *comm, struct thread *thread)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(3);
+
+ tuple_set_u64(t, 0, db_id);
+ tuple_set_u64(t, 1, comm->db_id);
+ tuple_set_u64(t, 2, thread->db_id);
+
+ call_object(tables->comm_thread_handler, t, "comm_thread_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_dso(struct db_export *dbe, struct dso *dso,
+ struct machine *machine)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ char sbuild_id[BUILD_ID_SIZE * 2 + 1];
+ PyObject *t;
+
+ build_id__sprintf(dso->build_id, sizeof(dso->build_id), sbuild_id);
+
+ t = tuple_new(5);
+
+ tuple_set_u64(t, 0, dso->db_id);
+ tuple_set_u64(t, 1, machine->db_id);
+ tuple_set_string(t, 2, dso->short_name);
+ tuple_set_string(t, 3, dso->long_name);
+ tuple_set_string(t, 4, sbuild_id);
+
+ call_object(tables->dso_handler, t, "dso_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_symbol(struct db_export *dbe, struct symbol *sym,
+ struct dso *dso)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ u64 *sym_db_id = symbol__priv(sym);
+ PyObject *t;
+
+ t = tuple_new(6);
+
+ tuple_set_u64(t, 0, *sym_db_id);
+ tuple_set_u64(t, 1, dso->db_id);
+ tuple_set_u64(t, 2, sym->start);
+ tuple_set_u64(t, 3, sym->end);
+ tuple_set_s32(t, 4, sym->binding);
+ tuple_set_string(t, 5, sym->name);
+
+ call_object(tables->symbol_handler, t, "symbol_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_branch_type(struct db_export *dbe, u32 branch_type,
+ const char *name)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(2);
+
+ tuple_set_s32(t, 0, branch_type);
+ tuple_set_string(t, 1, name);
+
+ call_object(tables->branch_type_handler, t, "branch_type_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_sample(struct db_export *dbe,
+ struct export_sample *es)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+
+ t = tuple_new(21);
+
+ tuple_set_u64(t, 0, es->db_id);
+ tuple_set_u64(t, 1, es->evsel->db_id);
+ tuple_set_u64(t, 2, es->al->machine->db_id);
+ tuple_set_u64(t, 3, es->thread->db_id);
+ tuple_set_u64(t, 4, es->comm_db_id);
+ tuple_set_u64(t, 5, es->dso_db_id);
+ tuple_set_u64(t, 6, es->sym_db_id);
+ tuple_set_u64(t, 7, es->offset);
+ tuple_set_u64(t, 8, es->sample->ip);
+ tuple_set_u64(t, 9, es->sample->time);
+ tuple_set_s32(t, 10, es->sample->cpu);
+ tuple_set_u64(t, 11, es->addr_dso_db_id);
+ tuple_set_u64(t, 12, es->addr_sym_db_id);
+ tuple_set_u64(t, 13, es->addr_offset);
+ tuple_set_u64(t, 14, es->sample->addr);
+ tuple_set_u64(t, 15, es->sample->period);
+ tuple_set_u64(t, 16, es->sample->weight);
+ tuple_set_u64(t, 17, es->sample->transaction);
+ tuple_set_u64(t, 18, es->sample->data_src);
+ tuple_set_s32(t, 19, es->sample->flags & PERF_BRANCH_MASK);
+ tuple_set_s32(t, 20, !!(es->sample->flags & PERF_IP_FLAG_IN_TX));
+
+ call_object(tables->sample_handler, t, "sample_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_call_path(struct db_export *dbe, struct call_path *cp)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ PyObject *t;
+ u64 parent_db_id, sym_db_id;
+
+ parent_db_id = cp->parent ? cp->parent->db_id : 0;
+ sym_db_id = cp->sym ? *(u64 *)symbol__priv(cp->sym) : 0;
+
+ t = tuple_new(4);
+
+ tuple_set_u64(t, 0, cp->db_id);
+ tuple_set_u64(t, 1, parent_db_id);
+ tuple_set_u64(t, 2, sym_db_id);
+ tuple_set_u64(t, 3, cp->ip);
+
+ call_object(tables->call_path_handler, t, "call_path_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_export_call_return(struct db_export *dbe,
+ struct call_return *cr)
+{
+ struct tables *tables = container_of(dbe, struct tables, dbe);
+ u64 comm_db_id = cr->comm ? cr->comm->db_id : 0;
+ PyObject *t;
+
+ t = tuple_new(11);
+
+ tuple_set_u64(t, 0, cr->db_id);
+ tuple_set_u64(t, 1, cr->thread->db_id);
+ tuple_set_u64(t, 2, comm_db_id);
+ tuple_set_u64(t, 3, cr->cp->db_id);
+ tuple_set_u64(t, 4, cr->call_time);
+ tuple_set_u64(t, 5, cr->return_time);
+ tuple_set_u64(t, 6, cr->branch_count);
+ tuple_set_u64(t, 7, cr->call_ref);
+ tuple_set_u64(t, 8, cr->return_ref);
+ tuple_set_u64(t, 9, cr->cp->parent->db_id);
+ tuple_set_s32(t, 10, cr->flags);
+
+ call_object(tables->call_return_handler, t, "call_return_table");
+
+ Py_DECREF(t);
+
+ return 0;
+}
+
+static int python_process_call_return(struct call_return *cr, void *data)
+{
+ struct db_export *dbe = data;
+
+ return db_export__call_return(dbe, cr);
+}
+
static void python_process_general_event(struct perf_sample *sample,
struct perf_evsel *evsel,
struct thread *thread,
@@ -551,19 +835,25 @@ exit:
Py_DECREF(t);
}
-static void python_process_event(union perf_event *event __maybe_unused,
+static void python_process_event(union perf_event *event,
struct perf_sample *sample,
struct perf_evsel *evsel,
struct thread *thread,
struct addr_location *al)
{
+ struct tables *tables = &tables_global;
+
switch (evsel->attr.type) {
case PERF_TYPE_TRACEPOINT:
python_process_tracepoint(sample, evsel, thread, al);
break;
/* Reserve for future process_hw/sw/raw APIs */
default:
- python_process_general_event(sample, evsel, thread, al);
+ if (tables->db_export_mode)
+ db_export__sample(&tables->dbe, event, sample, evsel,
+ thread, al);
+ else
+ python_process_general_event(sample, evsel, thread, al);
}
}
@@ -589,11 +879,79 @@ error:
return -1;
}
+#define SET_TABLE_HANDLER_(name, handler_name, table_name) do { \
+ tables->handler_name = get_handler(#table_name); \
+ if (tables->handler_name) \
+ tables->dbe.export_ ## name = python_export_ ## name; \
+} while (0)
+
+#define SET_TABLE_HANDLER(name) \
+ SET_TABLE_HANDLER_(name, name ## _handler, name ## _table)
+
+static void set_table_handlers(struct tables *tables)
+{
+ const char *perf_db_export_mode = "perf_db_export_mode";
+ const char *perf_db_export_calls = "perf_db_export_calls";
+ PyObject *db_export_mode, *db_export_calls;
+ bool export_calls = false;
+ int ret;
+
+ memset(tables, 0, sizeof(struct tables));
+ if (db_export__init(&tables->dbe))
+ Py_FatalError("failed to initialize export");
+
+ db_export_mode = PyDict_GetItemString(main_dict, perf_db_export_mode);
+ if (!db_export_mode)
+ return;
+
+ ret = PyObject_IsTrue(db_export_mode);
+ if (ret == -1)
+ handler_call_die(perf_db_export_mode);
+ if (!ret)
+ return;
+
+ tables->dbe.crp = NULL;
+ db_export_calls = PyDict_GetItemString(main_dict, perf_db_export_calls);
+ if (db_export_calls) {
+ ret = PyObject_IsTrue(db_export_calls);
+ if (ret == -1)
+ handler_call_die(perf_db_export_calls);
+ export_calls = !!ret;
+ }
+
+ if (export_calls) {
+ tables->dbe.crp =
+ call_return_processor__new(python_process_call_return,
+ &tables->dbe);
+ if (!tables->dbe.crp)
+ Py_FatalError("failed to create calls processor");
+ }
+
+ tables->db_export_mode = true;
+ /*
+ * Reserve per symbol space for symbol->db_id via symbol__priv()
+ */
+ symbol_conf.priv_size = sizeof(u64);
+
+ SET_TABLE_HANDLER(evsel);
+ SET_TABLE_HANDLER(machine);
+ SET_TABLE_HANDLER(thread);
+ SET_TABLE_HANDLER(comm);
+ SET_TABLE_HANDLER(comm_thread);
+ SET_TABLE_HANDLER(dso);
+ SET_TABLE_HANDLER(symbol);
+ SET_TABLE_HANDLER(branch_type);
+ SET_TABLE_HANDLER(sample);
+ SET_TABLE_HANDLER(call_path);
+ SET_TABLE_HANDLER(call_return);
+}
+
/*
* Start trace script
*/
static int python_start_script(const char *script, int argc, const char **argv)
{
+ struct tables *tables = &tables_global;
const char **command_line;
char buf[PATH_MAX];
int i, err = 0;
@@ -632,6 +990,14 @@ static int python_start_script(const char *script, int argc, const char **argv)
free(command_line);
+ set_table_handlers(tables);
+
+ if (tables->db_export_mode) {
+ err = db_export__branch_types(&tables->dbe);
+ if (err)
+ goto error;
+ }
+
return err;
error:
Py_Finalize();
@@ -642,7 +1008,9 @@ error:
static int python_flush_script(void)
{
- return 0;
+ struct tables *tables = &tables_global;
+
+ return db_export__flush(&tables->dbe);
}
/*
@@ -650,8 +1018,12 @@ static int python_flush_script(void)
*/
static int python_stop_script(void)
{
+ struct tables *tables = &tables_global;
+
try_call_object("trace_end", NULL);
+ db_export__exit(&tables->dbe);
+
Py_XDECREF(main_dict);
Py_XDECREF(main_module);
Py_Finalize();
diff --git a/tools/perf/util/session.c b/tools/perf/util/session.c
index 6702ac2..5f0e05a 100644
--- a/tools/perf/util/session.c
+++ b/tools/perf/util/session.c
@@ -228,6 +228,15 @@ static int process_finished_round(struct perf_tool *tool,
union perf_event *event,
struct perf_session *session);
+static int process_id_index_stub(struct perf_tool *tool __maybe_unused,
+ union perf_event *event __maybe_unused,
+ struct perf_session *perf_session
+ __maybe_unused)
+{
+ dump_printf(": unhandled!\n");
+ return 0;
+}
+
void perf_tool__fill_defaults(struct perf_tool *tool)
{
if (tool->sample == NULL)
@@ -262,6 +271,8 @@ void perf_tool__fill_defaults(struct perf_tool *tool)
else
tool->finished_round = process_finished_round_stub;
}
+ if (tool->id_index == NULL)
+ tool->id_index = process_id_index_stub;
}
static void swap_sample_id_all(union perf_event *event, void *data)
@@ -460,6 +471,7 @@ static perf_event__swap_op perf_event__swap_ops[] = {
[PERF_RECORD_HEADER_EVENT_TYPE] = perf_event__event_type_swap,
[PERF_RECORD_HEADER_TRACING_DATA] = perf_event__tracing_data_swap,
[PERF_RECORD_HEADER_BUILD_ID] = NULL,
+ [PERF_RECORD_ID_INDEX] = perf_event__all64_swap,
[PERF_RECORD_HEADER_MAX] = NULL,
};
@@ -521,15 +533,11 @@ int perf_session_queue_event(struct perf_session *s, union perf_event *event,
return -ETIME;
if (timestamp < oe->last_flush) {
- WARN_ONCE(1, "Timestamp below last timeslice flush\n");
-
- pr_oe_time(timestamp, "out of order event");
+ pr_oe_time(timestamp, "out of order event\n");
pr_oe_time(oe->last_flush, "last flush, last_flush_type %d\n",
oe->last_flush_type);
- /* We could get out of order messages after forced flush. */
- if (oe->last_flush_type != OE_FLUSH__HALF)
- return -EINVAL;
+ s->stats.nr_unordered_events++;
}
new = ordered_events__new(oe, timestamp, event);
@@ -580,15 +588,46 @@ static void regs_dump__printf(u64 mask, u64 *regs)
}
}
+static const char *regs_abi[] = {
+ [PERF_SAMPLE_REGS_ABI_NONE] = "none",
+ [PERF_SAMPLE_REGS_ABI_32] = "32-bit",
+ [PERF_SAMPLE_REGS_ABI_64] = "64-bit",
+};
+
+static inline const char *regs_dump_abi(struct regs_dump *d)
+{
+ if (d->abi > PERF_SAMPLE_REGS_ABI_64)
+ return "unknown";
+
+ return regs_abi[d->abi];
+}
+
+static void regs__printf(const char *type, struct regs_dump *regs)
+{
+ u64 mask = regs->mask;
+
+ printf("... %s regs: mask 0x%" PRIx64 " ABI %s\n",
+ type,
+ mask,
+ regs_dump_abi(regs));
+
+ regs_dump__printf(mask, regs->regs);
+}
+
static void regs_user__printf(struct perf_sample *sample)
{
struct regs_dump *user_regs = &sample->user_regs;
- if (user_regs->regs) {
- u64 mask = user_regs->mask;
- printf("... user regs: mask 0x%" PRIx64 "\n", mask);
- regs_dump__printf(mask, user_regs->regs);
- }
+ if (user_regs->regs)
+ regs__printf("user", user_regs);
+}
+
+static void regs_intr__printf(struct perf_sample *sample)
+{
+ struct regs_dump *intr_regs = &sample->intr_regs;
+
+ if (intr_regs->regs)
+ regs__printf("intr", intr_regs);
}
static void stack_user__printf(struct stack_dump *dump)
@@ -687,6 +726,9 @@ static void dump_sample(struct perf_evsel *evsel, union perf_event *event,
if (sample_type & PERF_SAMPLE_REGS_USER)
regs_user__printf(sample);
+ if (sample_type & PERF_SAMPLE_REGS_INTR)
+ regs_intr__printf(sample);
+
if (sample_type & PERF_SAMPLE_STACK_USER)
stack_user__printf(&sample->user_stack);
@@ -888,11 +930,26 @@ static s64 perf_session__process_user_event(struct perf_session *session,
return tool->build_id(tool, event, session);
case PERF_RECORD_FINISHED_ROUND:
return tool->finished_round(tool, event, session);
+ case PERF_RECORD_ID_INDEX:
+ return tool->id_index(tool, event, session);
default:
return -EINVAL;
}
}
+int perf_session__deliver_synth_event(struct perf_session *session,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_tool *tool)
+{
+ events_stats__inc(&session->stats, event->header.type);
+
+ if (event->header.type >= PERF_RECORD_USER_TYPE_START)
+ return perf_session__process_user_event(session, event, tool, 0);
+
+ return perf_session__deliver_event(session, event, sample, tool, 0);
+}
+
static void event_swap(union perf_event *event, bool sample_id_all)
{
perf_event__swap_op swap;
@@ -1057,6 +1114,9 @@ static void perf_session__warn_about_errors(const struct perf_session *session,
"Do you have a KVM guest running and not using 'perf kvm'?\n",
session->stats.nr_unprocessable_samples);
}
+
+ if (session->stats.nr_unordered_events != 0)
+ ui__warning("%u out of order events recorded.\n", session->stats.nr_unordered_events);
}
volatile int session_done;
@@ -1417,9 +1477,9 @@ void perf_evsel__print_ip(struct perf_evsel *evsel, struct perf_sample *sample,
if (symbol_conf.use_callchain && sample->callchain) {
struct addr_location node_al;
- if (machine__resolve_callchain(al->machine, evsel, al->thread,
- sample, NULL, NULL,
- PERF_MAX_STACK_DEPTH) != 0) {
+ if (thread__resolve_callchain(al->thread, evsel,
+ sample, NULL, NULL,
+ PERF_MAX_STACK_DEPTH) != 0) {
if (verbose)
error("Failed to resolve callchain. Skipping\n");
return;
@@ -1594,3 +1654,111 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
out:
return err;
}
+
+int perf_event__process_id_index(struct perf_tool *tool __maybe_unused,
+ union perf_event *event,
+ struct perf_session *session)
+{
+ struct perf_evlist *evlist = session->evlist;
+ struct id_index_event *ie = &event->id_index;
+ size_t i, nr, max_nr;
+
+ max_nr = (ie->header.size - sizeof(struct id_index_event)) /
+ sizeof(struct id_index_entry);
+ nr = ie->nr;
+ if (nr > max_nr)
+ return -EINVAL;
+
+ if (dump_trace)
+ fprintf(stdout, " nr: %zu\n", nr);
+
+ for (i = 0; i < nr; i++) {
+ struct id_index_entry *e = &ie->entries[i];
+ struct perf_sample_id *sid;
+
+ if (dump_trace) {
+ fprintf(stdout, " ... id: %"PRIu64, e->id);
+ fprintf(stdout, " idx: %"PRIu64, e->idx);
+ fprintf(stdout, " cpu: %"PRId64, e->cpu);
+ fprintf(stdout, " tid: %"PRId64"\n", e->tid);
+ }
+
+ sid = perf_evlist__id2sid(evlist, e->id);
+ if (!sid)
+ return -ENOENT;
+ sid->idx = e->idx;
+ sid->cpu = e->cpu;
+ sid->tid = e->tid;
+ }
+ return 0;
+}
+
+int perf_event__synthesize_id_index(struct perf_tool *tool,
+ perf_event__handler_t process,
+ struct perf_evlist *evlist,
+ struct machine *machine)
+{
+ union perf_event *ev;
+ struct perf_evsel *evsel;
+ size_t nr = 0, i = 0, sz, max_nr, n;
+ int err;
+
+ pr_debug2("Synthesizing id index\n");
+
+ max_nr = (UINT16_MAX - sizeof(struct id_index_event)) /
+ sizeof(struct id_index_entry);
+
+ evlist__for_each(evlist, evsel)
+ nr += evsel->ids;
+
+ n = nr > max_nr ? max_nr : nr;
+ sz = sizeof(struct id_index_event) + n * sizeof(struct id_index_entry);
+ ev = zalloc(sz);
+ if (!ev)
+ return -ENOMEM;
+
+ ev->id_index.header.type = PERF_RECORD_ID_INDEX;
+ ev->id_index.header.size = sz;
+ ev->id_index.nr = n;
+
+ evlist__for_each(evlist, evsel) {
+ u32 j;
+
+ for (j = 0; j < evsel->ids; j++) {
+ struct id_index_entry *e;
+ struct perf_sample_id *sid;
+
+ if (i >= n) {
+ err = process(tool, ev, NULL, machine);
+ if (err)
+ goto out_err;
+ nr -= n;
+ i = 0;
+ }
+
+ e = &ev->id_index.entries[i++];
+
+ e->id = evsel->id[j];
+
+ sid = perf_evlist__id2sid(evlist, e->id);
+ if (!sid) {
+ free(ev);
+ return -ENOENT;
+ }
+
+ e->idx = sid->idx;
+ e->cpu = sid->cpu;
+ e->tid = sid->tid;
+ }
+ }
+
+ sz = sizeof(struct id_index_event) + nr * sizeof(struct id_index_entry);
+ ev->id_index.header.size = sz;
+ ev->id_index.nr = nr;
+
+ err = process(tool, ev, NULL, machine);
+out_err:
+ free(ev);
+
+ return err;
+}
diff --git a/tools/perf/util/session.h b/tools/perf/util/session.h
index a4be851..dc26ebf 100644
--- a/tools/perf/util/session.h
+++ b/tools/perf/util/session.h
@@ -126,4 +126,19 @@ int __perf_session__set_tracepoints_handlers(struct perf_session *session,
extern volatile int session_done;
#define session_done() ACCESS_ONCE(session_done)
+
+int perf_session__deliver_synth_event(struct perf_session *session,
+ union perf_event *event,
+ struct perf_sample *sample,
+ struct perf_tool *tool);
+
+int perf_event__process_id_index(struct perf_tool *tool,
+ union perf_event *event,
+ struct perf_session *session);
+
+int perf_event__synthesize_id_index(struct perf_tool *tool,
+ perf_event__handler_t process,
+ struct perf_evlist *evlist,
+ struct machine *machine);
+
#endif /* __PERF_SESSION_H */
diff --git a/tools/perf/util/sort.c b/tools/perf/util/sort.c
index 9402885..9139dda 100644
--- a/tools/perf/util/sort.c
+++ b/tools/perf/util/sort.c
@@ -291,7 +291,8 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
else {
struct map *map = left->ms.map;
left->srcline = get_srcline(map->dso,
- map__rip_2objdump(map, left->ip));
+ map__rip_2objdump(map, left->ip),
+ left->ms.sym, true);
}
}
if (!right->srcline) {
@@ -300,7 +301,8 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
else {
struct map *map = right->ms.map;
right->srcline = get_srcline(map->dso,
- map__rip_2objdump(map, right->ip));
+ map__rip_2objdump(map, right->ip),
+ right->ms.sym, true);
}
}
return strcmp(right->srcline, left->srcline);
@@ -309,7 +311,7 @@ sort__srcline_cmp(struct hist_entry *left, struct hist_entry *right)
static int hist_entry__srcline_snprintf(struct hist_entry *he, char *bf,
size_t size, unsigned int width)
{
- return repsep_snprintf(bf, size, "%*.*-s", width, width, he->srcline);
+ return repsep_snprintf(bf, size, "%-*.*s", width, width, he->srcline);
}
struct sort_entry sort_srcline = {
diff --git a/tools/perf/util/srcline.c b/tools/perf/util/srcline.c
index f3e4bc5..e73b6a5 100644
--- a/tools/perf/util/srcline.c
+++ b/tools/perf/util/srcline.c
@@ -8,6 +8,8 @@
#include "util/util.h"
#include "util/debug.h"
+#include "symbol.h"
+
#ifdef HAVE_LIBBFD_SUPPORT
/*
@@ -250,7 +252,8 @@ void dso__free_a2l(struct dso *dso __maybe_unused)
*/
#define A2L_FAIL_LIMIT 123
-char *get_srcline(struct dso *dso, unsigned long addr)
+char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym,
+ bool show_sym)
{
char *file = NULL;
unsigned line = 0;
@@ -258,7 +261,7 @@ char *get_srcline(struct dso *dso, unsigned long addr)
const char *dso_name;
if (!dso->has_srcline)
- return SRCLINE_UNKNOWN;
+ goto out;
if (dso->symsrc_filename)
dso_name = dso->symsrc_filename;
@@ -274,7 +277,7 @@ char *get_srcline(struct dso *dso, unsigned long addr)
if (!addr2line(dso_name, addr, &file, &line, dso))
goto out;
- if (asprintf(&srcline, "%s:%u", file, line) < 0) {
+ if (asprintf(&srcline, "%s:%u", basename(file), line) < 0) {
free(file);
goto out;
}
@@ -289,7 +292,13 @@ out:
dso->has_srcline = 0;
dso__free_a2l(dso);
}
- return SRCLINE_UNKNOWN;
+ if (sym) {
+ if (asprintf(&srcline, "%s+%ld", show_sym ? sym->name : "",
+ addr - sym->start) < 0)
+ return SRCLINE_UNKNOWN;
+ } else if (asprintf(&srcline, "%s[%lx]", dso->short_name, addr) < 0)
+ return SRCLINE_UNKNOWN;
+ return srcline;
}
void free_srcline(char *srcline)
diff --git a/tools/perf/util/symbol-elf.c b/tools/perf/util/symbol-elf.c
index 1e23a5b..06fcd1b 100644
--- a/tools/perf/util/symbol-elf.c
+++ b/tools/perf/util/symbol-elf.c
@@ -11,6 +11,27 @@
#include <symbol/kallsyms.h>
#include "debug.h"
+#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
+extern char *cplus_demangle(const char *, int);
+
+static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
+{
+ return cplus_demangle(c, i);
+}
+#else
+#ifdef NO_DEMANGLE
+static inline char *bfd_demangle(void __maybe_unused *v,
+ const char __maybe_unused *c,
+ int __maybe_unused i)
+{
+ return NULL;
+}
+#else
+#define PACKAGE 'perf'
+#include <bfd.h>
+#endif
+#endif
+
#ifndef HAVE_ELF_GETPHDRNUM_SUPPORT
static int elf_getphdrnum(Elf *elf, size_t *dst)
{
@@ -546,6 +567,35 @@ static int dso__swap_init(struct dso *dso, unsigned char eidata)
return 0;
}
+static int decompress_kmodule(struct dso *dso, const char *name,
+ enum dso_binary_type type)
+{
+ int fd;
+ const char *ext = strrchr(name, '.');
+ char tmpbuf[] = "/tmp/perf-kmod-XXXXXX";
+
+ if ((type != DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP &&
+ type != DSO_BINARY_TYPE__GUEST_KMODULE_COMP) ||
+ type != dso->symtab_type)
+ return -1;
+
+ if (!ext || !is_supported_compression(ext + 1))
+ return -1;
+
+ fd = mkstemp(tmpbuf);
+ if (fd < 0)
+ return -1;
+
+ if (!decompress_to_file(ext + 1, name, fd)) {
+ close(fd);
+ fd = -1;
+ }
+
+ unlink(tmpbuf);
+
+ return fd;
+}
+
bool symsrc__possibly_runtime(struct symsrc *ss)
{
return ss->dynsym || ss->opdsec;
@@ -571,7 +621,11 @@ int symsrc__init(struct symsrc *ss, struct dso *dso, const char *name,
Elf *elf;
int fd;
- fd = open(name, O_RDONLY);
+ if (dso__needs_decompress(dso))
+ fd = decompress_kmodule(dso, name, type);
+ else
+ fd = open(name, O_RDONLY);
+
if (fd < 0)
return -1;
diff --git a/tools/perf/util/symbol-minimal.c b/tools/perf/util/symbol-minimal.c
index c9541fe..fa585c6 100644
--- a/tools/perf/util/symbol-minimal.c
+++ b/tools/perf/util/symbol-minimal.c
@@ -341,7 +341,6 @@ int dso__load_sym(struct dso *dso, struct map *map __maybe_unused,
if (filename__read_build_id(ss->name, build_id, BUILD_ID_SIZE) > 0) {
dso__set_build_id(dso, build_id);
- return 1;
}
return 0;
}
diff --git a/tools/perf/util/symbol.c b/tools/perf/util/symbol.c
index 0783311..c24c5b8 100644
--- a/tools/perf/util/symbol.c
+++ b/tools/perf/util/symbol.c
@@ -51,7 +51,9 @@ static enum dso_binary_type binary_type_symtab[] = {
DSO_BINARY_TYPE__BUILDID_DEBUGINFO,
DSO_BINARY_TYPE__SYSTEM_PATH_DSO,
DSO_BINARY_TYPE__GUEST_KMODULE,
+ DSO_BINARY_TYPE__GUEST_KMODULE_COMP,
DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE,
+ DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP,
DSO_BINARY_TYPE__OPENEMBEDDED_DEBUGINFO,
DSO_BINARY_TYPE__NOT_FOUND,
};
@@ -1300,7 +1302,9 @@ static bool dso__is_compatible_symtab_type(struct dso *dso, bool kmod,
return dso->kernel == DSO_TYPE_GUEST_KERNEL;
case DSO_BINARY_TYPE__GUEST_KMODULE:
+ case DSO_BINARY_TYPE__GUEST_KMODULE_COMP:
case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE:
+ case DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP:
/*
* kernel modules know their symtab type - it's set when
* creating a module dso in machine__new_module().
@@ -1368,7 +1372,9 @@ int dso__load(struct dso *dso, struct map *map, symbol_filter_t filter)
return -1;
kmod = dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE ||
- dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE;
+ dso->symtab_type == DSO_BINARY_TYPE__SYSTEM_PATH_KMODULE_COMP ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE ||
+ dso->symtab_type == DSO_BINARY_TYPE__GUEST_KMODULE_COMP;
/*
* Iterate over candidate debug images.
@@ -1505,12 +1511,10 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
symbol_filter_t filter)
{
int i, err = 0;
- char *filename;
+ char *filename = NULL;
- pr_debug("Looking at the vmlinux_path (%d entries long)\n",
- vmlinux_path__nr_entries + 1);
-
- filename = dso__build_id_filename(dso, NULL, 0);
+ if (!symbol_conf.ignore_vmlinux_buildid)
+ filename = dso__build_id_filename(dso, NULL, 0);
if (filename != NULL) {
err = dso__load_vmlinux(dso, map, filename, true, filter);
if (err > 0)
@@ -1518,6 +1522,9 @@ int dso__load_vmlinux_path(struct dso *dso, struct map *map,
free(filename);
}
+ pr_debug("Looking at the vmlinux_path (%d entries long)\n",
+ vmlinux_path__nr_entries + 1);
+
for (i = 0; i < vmlinux_path__nr_entries; ++i) {
err = dso__load_vmlinux(dso, map, vmlinux_path[i], false, filter);
if (err > 0)
diff --git a/tools/perf/util/symbol.h b/tools/perf/util/symbol.h
index eb2c19b..9d602e9 100644
--- a/tools/perf/util/symbol.h
+++ b/tools/perf/util/symbol.h
@@ -23,27 +23,6 @@
#include "dso.h"
-#ifdef HAVE_CPLUS_DEMANGLE_SUPPORT
-extern char *cplus_demangle(const char *, int);
-
-static inline char *bfd_demangle(void __maybe_unused *v, const char *c, int i)
-{
- return cplus_demangle(c, i);
-}
-#else
-#ifdef NO_DEMANGLE
-static inline char *bfd_demangle(void __maybe_unused *v,
- const char __maybe_unused *c,
- int __maybe_unused i)
-{
- return NULL;
-}
-#else
-#define PACKAGE 'perf'
-#include <bfd.h>
-#endif
-#endif
-
/*
* libelf 0.8.x and earlier do not support ELF_C_READ_MMAP;
* for newer versions we can use mmap to reduce memory usage:
@@ -105,6 +84,7 @@ struct symbol_conf {
unsigned short nr_events;
bool try_vmlinux_path,
ignore_vmlinux,
+ ignore_vmlinux_buildid,
show_kernel_path,
use_modules,
sort_by_name,
@@ -122,7 +102,8 @@ struct symbol_conf {
demangle,
demangle_kernel,
filter_relative,
- show_hist_headers;
+ show_hist_headers,
+ branch_callstack;
const char *vmlinux_name,
*kallsyms_name,
*source_prefix,
diff --git a/tools/perf/util/thread-stack.c b/tools/perf/util/thread-stack.c
new file mode 100644
index 0000000..9ed59a4
--- /dev/null
+++ b/tools/perf/util/thread-stack.c
@@ -0,0 +1,747 @@
+/*
+ * thread-stack.c: Synthesize a thread's stack using call / return events
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#include <linux/rbtree.h>
+#include <linux/list.h>
+#include "thread.h"
+#include "event.h"
+#include "machine.h"
+#include "util.h"
+#include "debug.h"
+#include "symbol.h"
+#include "comm.h"
+#include "thread-stack.h"
+
+#define CALL_PATH_BLOCK_SHIFT 8
+#define CALL_PATH_BLOCK_SIZE (1 << CALL_PATH_BLOCK_SHIFT)
+#define CALL_PATH_BLOCK_MASK (CALL_PATH_BLOCK_SIZE - 1)
+
+struct call_path_block {
+ struct call_path cp[CALL_PATH_BLOCK_SIZE];
+ struct list_head node;
+};
+
+/**
+ * struct call_path_root - root of all call paths.
+ * @call_path: root call path
+ * @blocks: list of blocks to store call paths
+ * @next: next free space
+ * @sz: number of spaces
+ */
+struct call_path_root {
+ struct call_path call_path;
+ struct list_head blocks;
+ size_t next;
+ size_t sz;
+};
+
+/**
+ * struct call_return_processor - provides a call-back to consume call-return
+ * information.
+ * @cpr: call path root
+ * @process: call-back that accepts call/return information
+ * @data: anonymous data for call-back
+ */
+struct call_return_processor {
+ struct call_path_root *cpr;
+ int (*process)(struct call_return *cr, void *data);
+ void *data;
+};
+
+#define STACK_GROWTH 2048
+
+/**
+ * struct thread_stack_entry - thread stack entry.
+ * @ret_addr: return address
+ * @timestamp: timestamp (if known)
+ * @ref: external reference (e.g. db_id of sample)
+ * @branch_count: the branch count when the entry was created
+ * @cp: call path
+ * @no_call: a 'call' was not seen
+ */
+struct thread_stack_entry {
+ u64 ret_addr;
+ u64 timestamp;
+ u64 ref;
+ u64 branch_count;
+ struct call_path *cp;
+ bool no_call;
+};
+
+/**
+ * struct thread_stack - thread stack constructed from 'call' and 'return'
+ * branch samples.
+ * @stack: array that holds the stack
+ * @cnt: number of entries in the stack
+ * @sz: current maximum stack size
+ * @trace_nr: current trace number
+ * @branch_count: running branch count
+ * @kernel_start: kernel start address
+ * @last_time: last timestamp
+ * @crp: call/return processor
+ * @comm: current comm
+ */
+struct thread_stack {
+ struct thread_stack_entry *stack;
+ size_t cnt;
+ size_t sz;
+ u64 trace_nr;
+ u64 branch_count;
+ u64 kernel_start;
+ u64 last_time;
+ struct call_return_processor *crp;
+ struct comm *comm;
+};
+
+static int thread_stack__grow(struct thread_stack *ts)
+{
+ struct thread_stack_entry *new_stack;
+ size_t sz, new_sz;
+
+ new_sz = ts->sz + STACK_GROWTH;
+ sz = new_sz * sizeof(struct thread_stack_entry);
+
+ new_stack = realloc(ts->stack, sz);
+ if (!new_stack)
+ return -ENOMEM;
+
+ ts->stack = new_stack;
+ ts->sz = new_sz;
+
+ return 0;
+}
+
+static struct thread_stack *thread_stack__new(struct thread *thread,
+ struct call_return_processor *crp)
+{
+ struct thread_stack *ts;
+
+ ts = zalloc(sizeof(struct thread_stack));
+ if (!ts)
+ return NULL;
+
+ if (thread_stack__grow(ts)) {
+ free(ts);
+ return NULL;
+ }
+
+ if (thread->mg && thread->mg->machine)
+ ts->kernel_start = machine__kernel_start(thread->mg->machine);
+ else
+ ts->kernel_start = 1ULL << 63;
+ ts->crp = crp;
+
+ return ts;
+}
+
+static int thread_stack__push(struct thread_stack *ts, u64 ret_addr)
+{
+ int err = 0;
+
+ if (ts->cnt == ts->sz) {
+ err = thread_stack__grow(ts);
+ if (err) {
+ pr_warning("Out of memory: discarding thread stack\n");
+ ts->cnt = 0;
+ }
+ }
+
+ ts->stack[ts->cnt++].ret_addr = ret_addr;
+
+ return err;
+}
+
+static void thread_stack__pop(struct thread_stack *ts, u64 ret_addr)
+{
+ size_t i;
+
+ /*
+ * In some cases there may be functions which are not seen to return.
+ * For example when setjmp / longjmp has been used. Or the perf context
+ * switch in the kernel which doesn't stop and start tracing in exactly
+ * the same code path. When that happens the return address will be
+ * further down the stack. If the return address is not found at all,
+ * we assume the opposite (i.e. this is a return for a call that wasn't
+ * seen for some reason) and leave the stack alone.
+ */
+ for (i = ts->cnt; i; ) {
+ if (ts->stack[--i].ret_addr == ret_addr) {
+ ts->cnt = i;
+ return;
+ }
+ }
+}
+
+static bool thread_stack__in_kernel(struct thread_stack *ts)
+{
+ if (!ts->cnt)
+ return false;
+
+ return ts->stack[ts->cnt - 1].cp->in_kernel;
+}
+
+static int thread_stack__call_return(struct thread *thread,
+ struct thread_stack *ts, size_t idx,
+ u64 timestamp, u64 ref, bool no_return)
+{
+ struct call_return_processor *crp = ts->crp;
+ struct thread_stack_entry *tse;
+ struct call_return cr = {
+ .thread = thread,
+ .comm = ts->comm,
+ .db_id = 0,
+ };
+
+ tse = &ts->stack[idx];
+ cr.cp = tse->cp;
+ cr.call_time = tse->timestamp;
+ cr.return_time = timestamp;
+ cr.branch_count = ts->branch_count - tse->branch_count;
+ cr.call_ref = tse->ref;
+ cr.return_ref = ref;
+ if (tse->no_call)
+ cr.flags |= CALL_RETURN_NO_CALL;
+ if (no_return)
+ cr.flags |= CALL_RETURN_NO_RETURN;
+
+ return crp->process(&cr, crp->data);
+}
+
+static int thread_stack__flush(struct thread *thread, struct thread_stack *ts)
+{
+ struct call_return_processor *crp = ts->crp;
+ int err;
+
+ if (!crp) {
+ ts->cnt = 0;
+ return 0;
+ }
+
+ while (ts->cnt) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ ts->last_time, 0, true);
+ if (err) {
+ pr_err("Error flushing thread stack!\n");
+ ts->cnt = 0;
+ return err;
+ }
+ }
+
+ return 0;
+}
+
+int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+ u64 to_ip, u16 insn_len, u64 trace_nr)
+{
+ if (!thread)
+ return -EINVAL;
+
+ if (!thread->ts) {
+ thread->ts = thread_stack__new(thread, NULL);
+ if (!thread->ts) {
+ pr_warning("Out of memory: no thread stack\n");
+ return -ENOMEM;
+ }
+ thread->ts->trace_nr = trace_nr;
+ }
+
+ /*
+ * When the trace is discontinuous, the trace_nr changes. In that case
+ * the stack might be completely invalid. Better to report nothing than
+ * to report something misleading, so flush the stack.
+ */
+ if (trace_nr != thread->ts->trace_nr) {
+ if (thread->ts->trace_nr)
+ thread_stack__flush(thread, thread->ts);
+ thread->ts->trace_nr = trace_nr;
+ }
+
+ /* Stop here if thread_stack__process() is in use */
+ if (thread->ts->crp)
+ return 0;
+
+ if (flags & PERF_IP_FLAG_CALL) {
+ u64 ret_addr;
+
+ if (!to_ip)
+ return 0;
+ ret_addr = from_ip + insn_len;
+ if (ret_addr == to_ip)
+ return 0; /* Zero-length calls are excluded */
+ return thread_stack__push(thread->ts, ret_addr);
+ } else if (flags & PERF_IP_FLAG_RETURN) {
+ if (!from_ip)
+ return 0;
+ thread_stack__pop(thread->ts, to_ip);
+ }
+
+ return 0;
+}
+
+void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr)
+{
+ if (!thread || !thread->ts)
+ return;
+
+ if (trace_nr != thread->ts->trace_nr) {
+ if (thread->ts->trace_nr)
+ thread_stack__flush(thread, thread->ts);
+ thread->ts->trace_nr = trace_nr;
+ }
+}
+
+void thread_stack__free(struct thread *thread)
+{
+ if (thread->ts) {
+ thread_stack__flush(thread, thread->ts);
+ zfree(&thread->ts->stack);
+ zfree(&thread->ts);
+ }
+}
+
+void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+ size_t sz, u64 ip)
+{
+ size_t i;
+
+ if (!thread || !thread->ts)
+ chain->nr = 1;
+ else
+ chain->nr = min(sz, thread->ts->cnt + 1);
+
+ chain->ips[0] = ip;
+
+ for (i = 1; i < chain->nr; i++)
+ chain->ips[i] = thread->ts->stack[thread->ts->cnt - i].ret_addr;
+}
+
+static void call_path__init(struct call_path *cp, struct call_path *parent,
+ struct symbol *sym, u64 ip, bool in_kernel)
+{
+ cp->parent = parent;
+ cp->sym = sym;
+ cp->ip = sym ? 0 : ip;
+ cp->db_id = 0;
+ cp->in_kernel = in_kernel;
+ RB_CLEAR_NODE(&cp->rb_node);
+ cp->children = RB_ROOT;
+}
+
+static struct call_path_root *call_path_root__new(void)
+{
+ struct call_path_root *cpr;
+
+ cpr = zalloc(sizeof(struct call_path_root));
+ if (!cpr)
+ return NULL;
+ call_path__init(&cpr->call_path, NULL, NULL, 0, false);
+ INIT_LIST_HEAD(&cpr->blocks);
+ return cpr;
+}
+
+static void call_path_root__free(struct call_path_root *cpr)
+{
+ struct call_path_block *pos, *n;
+
+ list_for_each_entry_safe(pos, n, &cpr->blocks, node) {
+ list_del(&pos->node);
+ free(pos);
+ }
+ free(cpr);
+}
+
+static struct call_path *call_path__new(struct call_path_root *cpr,
+ struct call_path *parent,
+ struct symbol *sym, u64 ip,
+ bool in_kernel)
+{
+ struct call_path_block *cpb;
+ struct call_path *cp;
+ size_t n;
+
+ if (cpr->next < cpr->sz) {
+ cpb = list_last_entry(&cpr->blocks, struct call_path_block,
+ node);
+ } else {
+ cpb = zalloc(sizeof(struct call_path_block));
+ if (!cpb)
+ return NULL;
+ list_add_tail(&cpb->node, &cpr->blocks);
+ cpr->sz += CALL_PATH_BLOCK_SIZE;
+ }
+
+ n = cpr->next++ & CALL_PATH_BLOCK_MASK;
+ cp = &cpb->cp[n];
+
+ call_path__init(cp, parent, sym, ip, in_kernel);
+
+ return cp;
+}
+
+static struct call_path *call_path__findnew(struct call_path_root *cpr,
+ struct call_path *parent,
+ struct symbol *sym, u64 ip, u64 ks)
+{
+ struct rb_node **p;
+ struct rb_node *node_parent = NULL;
+ struct call_path *cp;
+ bool in_kernel = ip >= ks;
+
+ if (sym)
+ ip = 0;
+
+ if (!parent)
+ return call_path__new(cpr, parent, sym, ip, in_kernel);
+
+ p = &parent->children.rb_node;
+ while (*p != NULL) {
+ node_parent = *p;
+ cp = rb_entry(node_parent, struct call_path, rb_node);
+
+ if (cp->sym == sym && cp->ip == ip)
+ return cp;
+
+ if (sym < cp->sym || (sym == cp->sym && ip < cp->ip))
+ p = &(*p)->rb_left;
+ else
+ p = &(*p)->rb_right;
+ }
+
+ cp = call_path__new(cpr, parent, sym, ip, in_kernel);
+ if (!cp)
+ return NULL;
+
+ rb_link_node(&cp->rb_node, node_parent, p);
+ rb_insert_color(&cp->rb_node, &parent->children);
+
+ return cp;
+}
+
+struct call_return_processor *
+call_return_processor__new(int (*process)(struct call_return *cr, void *data),
+ void *data)
+{
+ struct call_return_processor *crp;
+
+ crp = zalloc(sizeof(struct call_return_processor));
+ if (!crp)
+ return NULL;
+ crp->cpr = call_path_root__new();
+ if (!crp->cpr)
+ goto out_free;
+ crp->process = process;
+ crp->data = data;
+ return crp;
+
+out_free:
+ free(crp);
+ return NULL;
+}
+
+void call_return_processor__free(struct call_return_processor *crp)
+{
+ if (crp) {
+ call_path_root__free(crp->cpr);
+ free(crp);
+ }
+}
+
+static int thread_stack__push_cp(struct thread_stack *ts, u64 ret_addr,
+ u64 timestamp, u64 ref, struct call_path *cp,
+ bool no_call)
+{
+ struct thread_stack_entry *tse;
+ int err;
+
+ if (ts->cnt == ts->sz) {
+ err = thread_stack__grow(ts);
+ if (err)
+ return err;
+ }
+
+ tse = &ts->stack[ts->cnt++];
+ tse->ret_addr = ret_addr;
+ tse->timestamp = timestamp;
+ tse->ref = ref;
+ tse->branch_count = ts->branch_count;
+ tse->cp = cp;
+ tse->no_call = no_call;
+
+ return 0;
+}
+
+static int thread_stack__pop_cp(struct thread *thread, struct thread_stack *ts,
+ u64 ret_addr, u64 timestamp, u64 ref,
+ struct symbol *sym)
+{
+ int err;
+
+ if (!ts->cnt)
+ return 1;
+
+ if (ts->cnt == 1) {
+ struct thread_stack_entry *tse = &ts->stack[0];
+
+ if (tse->cp->sym == sym)
+ return thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ }
+
+ if (ts->stack[ts->cnt - 1].ret_addr == ret_addr) {
+ return thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ } else {
+ size_t i = ts->cnt - 1;
+
+ while (i--) {
+ if (ts->stack[i].ret_addr != ret_addr)
+ continue;
+ i += 1;
+ while (ts->cnt > i) {
+ err = thread_stack__call_return(thread, ts,
+ --ts->cnt,
+ timestamp, ref,
+ true);
+ if (err)
+ return err;
+ }
+ return thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ }
+ }
+
+ return 1;
+}
+
+static int thread_stack__bottom(struct thread *thread, struct thread_stack *ts,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref)
+{
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp;
+ struct symbol *sym;
+ u64 ip;
+
+ if (sample->ip) {
+ ip = sample->ip;
+ sym = from_al->sym;
+ } else if (sample->addr) {
+ ip = sample->addr;
+ sym = to_al->sym;
+ } else {
+ return 0;
+ }
+
+ cp = call_path__findnew(cpr, &cpr->call_path, sym, ip,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+
+ return thread_stack__push_cp(thread->ts, ip, sample->time, ref, cp,
+ true);
+}
+
+static int thread_stack__no_call_return(struct thread *thread,
+ struct thread_stack *ts,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref)
+{
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp, *parent;
+ u64 ks = ts->kernel_start;
+ int err;
+
+ if (sample->ip >= ks && sample->addr < ks) {
+ /* Return to userspace, so pop all kernel addresses */
+ while (thread_stack__in_kernel(ts)) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ sample->time, ref,
+ true);
+ if (err)
+ return err;
+ }
+
+ /* If the stack is empty, push the userspace address */
+ if (!ts->cnt) {
+ cp = call_path__findnew(cpr, &cpr->call_path,
+ to_al->sym, sample->addr,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+ return thread_stack__push_cp(ts, 0, sample->time, ref,
+ cp, true);
+ }
+ } else if (thread_stack__in_kernel(ts) && sample->ip < ks) {
+ /* Return to userspace, so pop all kernel addresses */
+ while (thread_stack__in_kernel(ts)) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ sample->time, ref,
+ true);
+ if (err)
+ return err;
+ }
+ }
+
+ if (ts->cnt)
+ parent = ts->stack[ts->cnt - 1].cp;
+ else
+ parent = &cpr->call_path;
+
+ /* This 'return' had no 'call', so push and pop top of stack */
+ cp = call_path__findnew(cpr, parent, from_al->sym, sample->ip,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+
+ err = thread_stack__push_cp(ts, sample->addr, sample->time, ref, cp,
+ true);
+ if (err)
+ return err;
+
+ return thread_stack__pop_cp(thread, ts, sample->addr, sample->time, ref,
+ to_al->sym);
+}
+
+static int thread_stack__trace_begin(struct thread *thread,
+ struct thread_stack *ts, u64 timestamp,
+ u64 ref)
+{
+ struct thread_stack_entry *tse;
+ int err;
+
+ if (!ts->cnt)
+ return 0;
+
+ /* Pop trace end */
+ tse = &ts->stack[ts->cnt - 1];
+ if (tse->cp->sym == NULL && tse->cp->ip == 0) {
+ err = thread_stack__call_return(thread, ts, --ts->cnt,
+ timestamp, ref, false);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+static int thread_stack__trace_end(struct thread_stack *ts,
+ struct perf_sample *sample, u64 ref)
+{
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp;
+ u64 ret_addr;
+
+ /* No point having 'trace end' on the bottom of the stack */
+ if (!ts->cnt || (ts->cnt == 1 && ts->stack[0].ref == ref))
+ return 0;
+
+ cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp, NULL, 0,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+
+ ret_addr = sample->ip + sample->insn_len;
+
+ return thread_stack__push_cp(ts, ret_addr, sample->time, ref, cp,
+ false);
+}
+
+int thread_stack__process(struct thread *thread, struct comm *comm,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref,
+ struct call_return_processor *crp)
+{
+ struct thread_stack *ts = thread->ts;
+ int err = 0;
+
+ if (ts) {
+ if (!ts->crp) {
+ /* Supersede thread_stack__event() */
+ thread_stack__free(thread);
+ thread->ts = thread_stack__new(thread, crp);
+ if (!thread->ts)
+ return -ENOMEM;
+ ts = thread->ts;
+ ts->comm = comm;
+ }
+ } else {
+ thread->ts = thread_stack__new(thread, crp);
+ if (!thread->ts)
+ return -ENOMEM;
+ ts = thread->ts;
+ ts->comm = comm;
+ }
+
+ /* Flush stack on exec */
+ if (ts->comm != comm && thread->pid_ == thread->tid) {
+ err = thread_stack__flush(thread, ts);
+ if (err)
+ return err;
+ ts->comm = comm;
+ }
+
+ /* If the stack is empty, put the current symbol on the stack */
+ if (!ts->cnt) {
+ err = thread_stack__bottom(thread, ts, sample, from_al, to_al,
+ ref);
+ if (err)
+ return err;
+ }
+
+ ts->branch_count += 1;
+ ts->last_time = sample->time;
+
+ if (sample->flags & PERF_IP_FLAG_CALL) {
+ struct call_path_root *cpr = ts->crp->cpr;
+ struct call_path *cp;
+ u64 ret_addr;
+
+ if (!sample->ip || !sample->addr)
+ return 0;
+
+ ret_addr = sample->ip + sample->insn_len;
+ if (ret_addr == sample->addr)
+ return 0; /* Zero-length calls are excluded */
+
+ cp = call_path__findnew(cpr, ts->stack[ts->cnt - 1].cp,
+ to_al->sym, sample->addr,
+ ts->kernel_start);
+ if (!cp)
+ return -ENOMEM;
+ err = thread_stack__push_cp(ts, ret_addr, sample->time, ref,
+ cp, false);
+ } else if (sample->flags & PERF_IP_FLAG_RETURN) {
+ if (!sample->ip || !sample->addr)
+ return 0;
+
+ err = thread_stack__pop_cp(thread, ts, sample->addr,
+ sample->time, ref, from_al->sym);
+ if (err) {
+ if (err < 0)
+ return err;
+ err = thread_stack__no_call_return(thread, ts, sample,
+ from_al, to_al, ref);
+ }
+ } else if (sample->flags & PERF_IP_FLAG_TRACE_BEGIN) {
+ err = thread_stack__trace_begin(thread, ts, sample->time, ref);
+ } else if (sample->flags & PERF_IP_FLAG_TRACE_END) {
+ err = thread_stack__trace_end(ts, sample, ref);
+ }
+
+ return err;
+}
diff --git a/tools/perf/util/thread-stack.h b/tools/perf/util/thread-stack.h
new file mode 100644
index 0000000..b843bbe
--- /dev/null
+++ b/tools/perf/util/thread-stack.h
@@ -0,0 +1,111 @@
+/*
+ * thread-stack.h: Synthesize a thread's stack using call / return events
+ * Copyright (c) 2014, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ *
+ */
+
+#ifndef __PERF_THREAD_STACK_H
+#define __PERF_THREAD_STACK_H
+
+#include <sys/types.h>
+
+#include <linux/types.h>
+#include <linux/rbtree.h>
+
+struct thread;
+struct comm;
+struct ip_callchain;
+struct symbol;
+struct dso;
+struct call_return_processor;
+struct comm;
+struct perf_sample;
+struct addr_location;
+
+/*
+ * Call/Return flags.
+ *
+ * CALL_RETURN_NO_CALL: 'return' but no matching 'call'
+ * CALL_RETURN_NO_RETURN: 'call' but no matching 'return'
+ */
+enum {
+ CALL_RETURN_NO_CALL = 1 << 0,
+ CALL_RETURN_NO_RETURN = 1 << 1,
+};
+
+/**
+ * struct call_return - paired call/return information.
+ * @thread: thread in which call/return occurred
+ * @comm: comm in which call/return occurred
+ * @cp: call path
+ * @call_time: timestamp of call (if known)
+ * @return_time: timestamp of return (if known)
+ * @branch_count: number of branches seen between call and return
+ * @call_ref: external reference to 'call' sample (e.g. db_id)
+ * @return_ref: external reference to 'return' sample (e.g. db_id)
+ * @db_id: id used for db-export
+ * @flags: Call/Return flags
+ */
+struct call_return {
+ struct thread *thread;
+ struct comm *comm;
+ struct call_path *cp;
+ u64 call_time;
+ u64 return_time;
+ u64 branch_count;
+ u64 call_ref;
+ u64 return_ref;
+ u64 db_id;
+ u32 flags;
+};
+
+/**
+ * struct call_path - node in list of calls leading to a function call.
+ * @parent: call path to the parent function call
+ * @sym: symbol of function called
+ * @ip: only if sym is null, the ip of the function
+ * @db_id: id used for db-export
+ * @in_kernel: whether function is a in the kernel
+ * @rb_node: node in parent's tree of called functions
+ * @children: tree of call paths of functions called
+ *
+ * In combination with the call_return structure, the call_path structure
+ * defines a context-sensitve call-graph.
+ */
+struct call_path {
+ struct call_path *parent;
+ struct symbol *sym;
+ u64 ip;
+ u64 db_id;
+ bool in_kernel;
+ struct rb_node rb_node;
+ struct rb_root children;
+};
+
+int thread_stack__event(struct thread *thread, u32 flags, u64 from_ip,
+ u64 to_ip, u16 insn_len, u64 trace_nr);
+void thread_stack__set_trace_nr(struct thread *thread, u64 trace_nr);
+void thread_stack__sample(struct thread *thread, struct ip_callchain *chain,
+ size_t sz, u64 ip);
+void thread_stack__free(struct thread *thread);
+
+struct call_return_processor *
+call_return_processor__new(int (*process)(struct call_return *cr, void *data),
+ void *data);
+void call_return_processor__free(struct call_return_processor *crp);
+int thread_stack__process(struct thread *thread, struct comm *comm,
+ struct perf_sample *sample,
+ struct addr_location *from_al,
+ struct addr_location *to_al, u64 ref,
+ struct call_return_processor *crp);
+
+#endif
diff --git a/tools/perf/util/thread.c b/tools/perf/util/thread.c
index c414117..9ebc8b1 100644
--- a/tools/perf/util/thread.c
+++ b/tools/perf/util/thread.c
@@ -4,6 +4,7 @@
#include <string.h>
#include "session.h"
#include "thread.h"
+#include "thread-stack.h"
#include "util.h"
#include "debug.h"
#include "comm.h"
@@ -15,7 +16,7 @@ int thread__init_map_groups(struct thread *thread, struct machine *machine)
pid_t pid = thread->pid_;
if (pid == thread->tid || pid == -1) {
- thread->mg = map_groups__new();
+ thread->mg = map_groups__new(machine);
} else {
leader = machine__findnew_thread(machine, pid, pid);
if (leader)
@@ -66,6 +67,8 @@ void thread__delete(struct thread *thread)
{
struct comm *comm, *tmp;
+ thread_stack__free(thread);
+
if (thread->mg) {
map_groups__put(thread->mg);
thread->mg = NULL;
@@ -100,15 +103,14 @@ struct comm *thread__exec_comm(const struct thread *thread)
return last;
}
-/* CHECKME: time should always be 0 if event aren't ordered */
int __thread__set_comm(struct thread *thread, const char *str, u64 timestamp,
bool exec)
{
struct comm *new, *curr = thread__comm(thread);
int err;
- /* Override latest entry if it had no specific time coverage */
- if (!curr->start && !curr->exec) {
+ /* Override the default :tid entry */
+ if (!thread->comm_set) {
err = comm__override(curr, str, timestamp, exec);
if (err)
return err;
@@ -198,7 +200,6 @@ int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp)
}
void thread__find_cpumode_addr_location(struct thread *thread,
- struct machine *machine,
enum map_type type, u64 addr,
struct addr_location *al)
{
@@ -211,8 +212,7 @@ void thread__find_cpumode_addr_location(struct thread *thread,
};
for (i = 0; i < ARRAY_SIZE(cpumodes); i++) {
- thread__find_addr_location(thread, machine, cpumodes[i], type,
- addr, al);
+ thread__find_addr_location(thread, cpumodes[i], type, addr, al);
if (al->map)
break;
}
diff --git a/tools/perf/util/thread.h b/tools/perf/util/thread.h
index 8c75fa7..160fd06 100644
--- a/tools/perf/util/thread.h
+++ b/tools/perf/util/thread.h
@@ -8,6 +8,8 @@
#include "symbol.h"
#include <strlist.h>
+struct thread_stack;
+
struct thread {
union {
struct rb_node rb_node;
@@ -23,8 +25,10 @@ struct thread {
bool dead; /* if set thread has exited */
struct list_head comm_list;
int comm_len;
+ u64 db_id;
void *priv;
+ struct thread_stack *ts;
};
struct machine;
@@ -54,16 +58,15 @@ void thread__insert_map(struct thread *thread, struct map *map);
int thread__fork(struct thread *thread, struct thread *parent, u64 timestamp);
size_t thread__fprintf(struct thread *thread, FILE *fp);
-void thread__find_addr_map(struct thread *thread, struct machine *machine,
+void thread__find_addr_map(struct thread *thread,
u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al);
-void thread__find_addr_location(struct thread *thread, struct machine *machine,
+void thread__find_addr_location(struct thread *thread,
u8 cpumode, enum map_type type, u64 addr,
struct addr_location *al);
void thread__find_cpumode_addr_location(struct thread *thread,
- struct machine *machine,
enum map_type type, u64 addr,
struct addr_location *al);
diff --git a/tools/perf/util/tool.h b/tools/perf/util/tool.h
index f116369..bb2708b 100644
--- a/tools/perf/util/tool.h
+++ b/tools/perf/util/tool.h
@@ -39,7 +39,8 @@ struct perf_tool {
event_attr_op attr;
event_op2 tracing_data;
event_op2 finished_round,
- build_id;
+ build_id,
+ id_index;
bool ordered_events;
bool ordering_requires_timestamps;
};
diff --git a/tools/perf/util/unwind-libdw.c b/tools/perf/util/unwind-libdw.c
index 7419768..2dcfe9a 100644
--- a/tools/perf/util/unwind-libdw.c
+++ b/tools/perf/util/unwind-libdw.c
@@ -26,7 +26,7 @@ static int __report_module(struct addr_location *al, u64 ip,
Dwfl_Module *mod;
struct dso *dso = NULL;
- thread__find_addr_location(ui->thread, ui->machine,
+ thread__find_addr_location(ui->thread,
PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, al);
@@ -89,7 +89,7 @@ static int access_dso_mem(struct unwind_info *ui, Dwarf_Addr addr,
struct addr_location al;
ssize_t size;
- thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, addr, &al);
if (!al.map) {
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
@@ -164,14 +164,14 @@ frame_callback(Dwfl_Frame *state, void *arg)
}
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
- struct machine *machine, struct thread *thread,
+ struct thread *thread,
struct perf_sample *data,
int max_stack)
{
struct unwind_info ui = {
.sample = data,
.thread = thread,
- .machine = machine,
+ .machine = thread->mg->machine,
.cb = cb,
.arg = arg,
.max_stack = max_stack,
diff --git a/tools/perf/util/unwind-libunwind.c b/tools/perf/util/unwind-libunwind.c
index 4d45c0d..371219a 100644
--- a/tools/perf/util/unwind-libunwind.c
+++ b/tools/perf/util/unwind-libunwind.c
@@ -284,7 +284,7 @@ static struct map *find_map(unw_word_t ip, struct unwind_info *ui)
{
struct addr_location al;
- thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, &al);
return al.map;
}
@@ -374,7 +374,7 @@ static int access_dso_mem(struct unwind_info *ui, unw_word_t addr,
struct addr_location al;
ssize_t size;
- thread__find_addr_map(ui->thread, ui->machine, PERF_RECORD_MISC_USER,
+ thread__find_addr_map(ui->thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, addr, &al);
if (!al.map) {
pr_debug("unwind: no map for %lx\n", (unsigned long)addr);
@@ -476,14 +476,13 @@ static void put_unwind_info(unw_addr_space_t __maybe_unused as,
pr_debug("unwind: put_unwind_info called\n");
}
-static int entry(u64 ip, struct thread *thread, struct machine *machine,
+static int entry(u64 ip, struct thread *thread,
unwind_entry_cb_t cb, void *arg)
{
struct unwind_entry e;
struct addr_location al;
- thread__find_addr_location(thread, machine,
- PERF_RECORD_MISC_USER,
+ thread__find_addr_location(thread, PERF_RECORD_MISC_USER,
MAP__FUNCTION, ip, &al);
e.ip = ip;
@@ -586,21 +585,21 @@ static int get_entries(struct unwind_info *ui, unwind_entry_cb_t cb,
unw_word_t ip;
unw_get_reg(&c, UNW_REG_IP, &ip);
- ret = ip ? entry(ip, ui->thread, ui->machine, cb, arg) : 0;
+ ret = ip ? entry(ip, ui->thread, cb, arg) : 0;
}
return ret;
}
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
- struct machine *machine, struct thread *thread,
+ struct thread *thread,
struct perf_sample *data, int max_stack)
{
u64 ip;
struct unwind_info ui = {
.sample = data,
.thread = thread,
- .machine = machine,
+ .machine = thread->mg->machine,
};
int ret;
@@ -611,7 +610,7 @@ int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
if (ret)
return ret;
- ret = entry(ip, thread, machine, cb, arg);
+ ret = entry(ip, thread, cb, arg);
if (ret)
return -ENOMEM;
diff --git a/tools/perf/util/unwind.h b/tools/perf/util/unwind.h
index f50b737..12790cf 100644
--- a/tools/perf/util/unwind.h
+++ b/tools/perf/util/unwind.h
@@ -16,7 +16,6 @@ typedef int (*unwind_entry_cb_t)(struct unwind_entry *entry, void *arg);
#ifdef HAVE_DWARF_UNWIND_SUPPORT
int unwind__get_entries(unwind_entry_cb_t cb, void *arg,
- struct machine *machine,
struct thread *thread,
struct perf_sample *data, int max_stack);
/* libunwind specific */
@@ -38,7 +37,6 @@ static inline void unwind__finish_access(struct thread *thread __maybe_unused) {
static inline int
unwind__get_entries(unwind_entry_cb_t cb __maybe_unused,
void *arg __maybe_unused,
- struct machine *machine __maybe_unused,
struct thread *thread __maybe_unused,
struct perf_sample *data __maybe_unused,
int max_stack __maybe_unused)
diff --git a/tools/perf/util/util.h b/tools/perf/util/util.h
index 80bfdaa..419bee0 100644
--- a/tools/perf/util/util.h
+++ b/tools/perf/util/util.h
@@ -154,7 +154,6 @@ extern void set_die_routine(void (*routine)(const char *err, va_list params) NOR
extern int prefixcmp(const char *str, const char *prefix);
extern void set_buildid_dir(void);
-extern void disable_buildid_cache(void);
static inline const char *skip_prefix(const char *str, const char *prefix)
{
@@ -338,8 +337,10 @@ static inline int path__join3(char *bf, size_t size,
}
struct dso;
+struct symbol;
-char *get_srcline(struct dso *dso, unsigned long addr);
+char *get_srcline(struct dso *dso, unsigned long addr, struct symbol *sym,
+ bool show_sym);
void free_srcline(char *srcline);
int filename__read_int(const char *filename, int *value);
@@ -351,4 +352,9 @@ void mem_bswap_32(void *src, int byte_size);
const char *get_filename_for_perf_kvm(void);
bool find_process(const char *name);
+
+#ifdef HAVE_ZLIB_SUPPORT
+int gzip_decompress_to_file(const char *input, int output_fd);
+#endif
+
#endif /* GIT_COMPAT_UTIL_H */
diff --git a/tools/perf/util/vdso.c b/tools/perf/util/vdso.c
index adca693..5c7dd79 100644
--- a/tools/perf/util/vdso.c
+++ b/tools/perf/util/vdso.c
@@ -12,9 +12,16 @@
#include "util.h"
#include "symbol.h"
#include "machine.h"
+#include "thread.h"
#include "linux/string.h"
#include "debug.h"
+/*
+ * Include definition of find_vdso_map() also used in perf-read-vdso.c for
+ * building perf-read-vdso32 and perf-read-vdsox32.
+ */
+#include "find-vdso-map.c"
+
#define VDSO__TEMP_FILE_NAME "/tmp/perf-vdso.so-XXXXXX"
struct vdso_file {
@@ -22,10 +29,15 @@ struct vdso_file {
bool error;
char temp_file_name[sizeof(VDSO__TEMP_FILE_NAME)];
const char *dso_name;
+ const char *read_prog;
};
struct vdso_info {
struct vdso_file vdso;
+#if BITS_PER_LONG == 64
+ struct vdso_file vdso32;
+ struct vdso_file vdsox32;
+#endif
};
static struct vdso_info *vdso_info__new(void)
@@ -35,42 +47,23 @@ static struct vdso_info *vdso_info__new(void)
.temp_file_name = VDSO__TEMP_FILE_NAME,
.dso_name = DSO__NAME_VDSO,
},
+#if BITS_PER_LONG == 64
+ .vdso32 = {
+ .temp_file_name = VDSO__TEMP_FILE_NAME,
+ .dso_name = DSO__NAME_VDSO32,
+ .read_prog = "perf-read-vdso32",
+ },
+ .vdsox32 = {
+ .temp_file_name = VDSO__TEMP_FILE_NAME,
+ .dso_name = DSO__NAME_VDSOX32,
+ .read_prog = "perf-read-vdsox32",
+ },
+#endif
};
return memdup(&vdso_info_init, sizeof(vdso_info_init));
}
-static int find_vdso_map(void **start, void **end)
-{
- FILE *maps;
- char line[128];
- int found = 0;
-
- maps = fopen("/proc/self/maps", "r");
- if (!maps) {
- pr_err("vdso: cannot open maps\n");
- return -1;
- }
-
- while (!found && fgets(line, sizeof(line), maps)) {
- int m = -1;
-
- /* We care only about private r-x mappings. */
- if (2 != sscanf(line, "%p-%p r-xp %*x %*x:%*x %*u %n",
- start, end, &m))
- continue;
- if (m < 0)
- continue;
-
- if (!strncmp(&line[m], VDSO__MAP_NAME,
- sizeof(VDSO__MAP_NAME) - 1))
- found = 1;
- }
-
- fclose(maps);
- return !found;
-}
-
static char *get_file(struct vdso_file *vdso_file)
{
char *vdso = NULL;
@@ -117,6 +110,12 @@ void vdso__exit(struct machine *machine)
if (vdso_info->vdso.found)
unlink(vdso_info->vdso.temp_file_name);
+#if BITS_PER_LONG == 64
+ if (vdso_info->vdso32.found)
+ unlink(vdso_info->vdso32.temp_file_name);
+ if (vdso_info->vdsox32.found)
+ unlink(vdso_info->vdsox32.temp_file_name);
+#endif
zfree(&machine->vdso_info);
}
@@ -135,6 +134,153 @@ static struct dso *vdso__new(struct machine *machine, const char *short_name,
return dso;
}
+#if BITS_PER_LONG == 64
+
+static enum dso_type machine__thread_dso_type(struct machine *machine,
+ struct thread *thread)
+{
+ enum dso_type dso_type = DSO__TYPE_UNKNOWN;
+ struct map *map;
+ struct dso *dso;
+
+ map = map_groups__first(thread->mg, MAP__FUNCTION);
+ for (; map ; map = map_groups__next(map)) {
+ dso = map->dso;
+ if (!dso || dso->long_name[0] != '/')
+ continue;
+ dso_type = dso__type(dso, machine);
+ if (dso_type != DSO__TYPE_UNKNOWN)
+ break;
+ }
+
+ return dso_type;
+}
+
+static int vdso__do_copy_compat(FILE *f, int fd)
+{
+ char buf[4096];
+ size_t count;
+
+ while (1) {
+ count = fread(buf, 1, sizeof(buf), f);
+ if (ferror(f))
+ return -errno;
+ if (feof(f))
+ break;
+ if (count && writen(fd, buf, count) != (ssize_t)count)
+ return -errno;
+ }
+
+ return 0;
+}
+
+static int vdso__copy_compat(const char *prog, int fd)
+{
+ FILE *f;
+ int err;
+
+ f = popen(prog, "r");
+ if (!f)
+ return -errno;
+
+ err = vdso__do_copy_compat(f, fd);
+
+ if (pclose(f) == -1)
+ return -errno;
+
+ return err;
+}
+
+static int vdso__create_compat_file(const char *prog, char *temp_name)
+{
+ int fd, err;
+
+ fd = mkstemp(temp_name);
+ if (fd < 0)
+ return -errno;
+
+ err = vdso__copy_compat(prog, fd);
+
+ if (close(fd) == -1)
+ return -errno;
+
+ return err;
+}
+
+static const char *vdso__get_compat_file(struct vdso_file *vdso_file)
+{
+ int err;
+
+ if (vdso_file->found)
+ return vdso_file->temp_file_name;
+
+ if (vdso_file->error)
+ return NULL;
+
+ err = vdso__create_compat_file(vdso_file->read_prog,
+ vdso_file->temp_file_name);
+ if (err) {
+ pr_err("%s failed, error %d\n", vdso_file->read_prog, err);
+ vdso_file->error = true;
+ return NULL;
+ }
+
+ vdso_file->found = true;
+
+ return vdso_file->temp_file_name;
+}
+
+static struct dso *vdso__findnew_compat(struct machine *machine,
+ struct vdso_file *vdso_file)
+{
+ const char *file_name;
+ struct dso *dso;
+
+ dso = dsos__find(&machine->user_dsos, vdso_file->dso_name, true);
+ if (dso)
+ return dso;
+
+ file_name = vdso__get_compat_file(vdso_file);
+ if (!file_name)
+ return NULL;
+
+ return vdso__new(machine, vdso_file->dso_name, file_name);
+}
+
+static int vdso__dso_findnew_compat(struct machine *machine,
+ struct thread *thread,
+ struct vdso_info *vdso_info,
+ struct dso **dso)
+{
+ enum dso_type dso_type;
+
+ dso_type = machine__thread_dso_type(machine, thread);
+
+#ifndef HAVE_PERF_READ_VDSO32
+ if (dso_type == DSO__TYPE_32BIT)
+ return 0;
+#endif
+#ifndef HAVE_PERF_READ_VDSOX32
+ if (dso_type == DSO__TYPE_X32BIT)
+ return 0;
+#endif
+
+ switch (dso_type) {
+ case DSO__TYPE_32BIT:
+ *dso = vdso__findnew_compat(machine, &vdso_info->vdso32);
+ return 1;
+ case DSO__TYPE_X32BIT:
+ *dso = vdso__findnew_compat(machine, &vdso_info->vdsox32);
+ return 1;
+ case DSO__TYPE_UNKNOWN:
+ case DSO__TYPE_64BIT:
+ default:
+ return 0;
+ }
+}
+
+#endif
+
struct dso *vdso__dso_findnew(struct machine *machine,
struct thread *thread __maybe_unused)
{
@@ -148,6 +294,11 @@ struct dso *vdso__dso_findnew(struct machine *machine,
if (!vdso_info)
return NULL;
+#if BITS_PER_LONG == 64
+ if (vdso__dso_findnew_compat(machine, thread, vdso_info, &dso))
+ return dso;
+#endif
+
dso = dsos__find(&machine->user_dsos, DSO__NAME_VDSO, true);
if (!dso) {
char *file;
@@ -164,5 +315,7 @@ struct dso *vdso__dso_findnew(struct machine *machine,
bool dso__is_vdso(struct dso *dso)
{
- return !strcmp(dso->short_name, DSO__NAME_VDSO);
+ return !strcmp(dso->short_name, DSO__NAME_VDSO) ||
+ !strcmp(dso->short_name, DSO__NAME_VDSO32) ||
+ !strcmp(dso->short_name, DSO__NAME_VDSOX32);
}
diff --git a/tools/perf/util/vdso.h b/tools/perf/util/vdso.h
index af9d692..d97da16 100644
--- a/tools/perf/util/vdso.h
+++ b/tools/perf/util/vdso.h
@@ -7,7 +7,9 @@
#define VDSO__MAP_NAME "[vdso]"
-#define DSO__NAME_VDSO "[vdso]"
+#define DSO__NAME_VDSO "[vdso]"
+#define DSO__NAME_VDSO32 "[vdso32]"
+#define DSO__NAME_VDSOX32 "[vdsox32]"
static inline bool is_vdso_map(const char *filename)
{
diff --git a/tools/perf/util/zlib.c b/tools/perf/util/zlib.c
new file mode 100644
index 0000000..495a449
--- /dev/null
+++ b/tools/perf/util/zlib.c
@@ -0,0 +1,78 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/mman.h>
+#include <zlib.h>
+
+#include "util/util.h"
+#include "util/debug.h"
+
+
+#define CHUNK_SIZE 16384
+
+int gzip_decompress_to_file(const char *input, int output_fd)
+{
+ int ret = Z_STREAM_ERROR;
+ int input_fd;
+ void *ptr;
+ int len;
+ struct stat stbuf;
+ unsigned char buf[CHUNK_SIZE];
+ z_stream zs = {
+ .zalloc = Z_NULL,
+ .zfree = Z_NULL,
+ .opaque = Z_NULL,
+ .avail_in = 0,
+ .next_in = Z_NULL,
+ };
+
+ input_fd = open(input, O_RDONLY);
+ if (input_fd < 0)
+ return -1;
+
+ if (fstat(input_fd, &stbuf) < 0)
+ goto out_close;
+
+ ptr = mmap(NULL, stbuf.st_size, PROT_READ, MAP_PRIVATE, input_fd, 0);
+ if (ptr == MAP_FAILED)
+ goto out_close;
+
+ if (inflateInit2(&zs, 16 + MAX_WBITS) != Z_OK)
+ goto out_unmap;
+
+ zs.next_in = ptr;
+ zs.avail_in = stbuf.st_size;
+
+ do {
+ zs.next_out = buf;
+ zs.avail_out = CHUNK_SIZE;
+
+ ret = inflate(&zs, Z_NO_FLUSH);
+ switch (ret) {
+ case Z_NEED_DICT:
+ ret = Z_DATA_ERROR;
+ /* fall through */
+ case Z_DATA_ERROR:
+ case Z_MEM_ERROR:
+ goto out;
+ default:
+ break;
+ }
+
+ len = CHUNK_SIZE - zs.avail_out;
+ if (writen(output_fd, buf, len) != len) {
+ ret = Z_DATA_ERROR;
+ goto out;
+ }
+
+ } while (ret != Z_STREAM_END);
+
+out:
+ inflateEnd(&zs);
+out_unmap:
+ munmap(ptr, stbuf.st_size);
+out_close:
+ close(input_fd);
+
+ return ret == Z_STREAM_END ? 0 : -1;
+}
diff --git a/tools/power/cpupower/utils/cpuidle-info.c b/tools/power/cpupower/utils/cpuidle-info.c
index 75e66de..458d69b 100644
--- a/tools/power/cpupower/utils/cpuidle-info.c
+++ b/tools/power/cpupower/utils/cpuidle-info.c
@@ -22,13 +22,13 @@
static void cpuidle_cpu_output(unsigned int cpu, int verbose)
{
- unsigned int idlestates, idlestate;
+ int idlestates, idlestate;
char *tmp;
printf(_ ("Analyzing CPU %d:\n"), cpu);
idlestates = sysfs_get_idlestate_count(cpu);
- if (idlestates == 0) {
+ if (idlestates < 1) {
printf(_("CPU %u: No idle states\n"), cpu);
return;
}
@@ -100,10 +100,10 @@ static void cpuidle_general_output(void)
static void proc_cpuidle_cpu_output(unsigned int cpu)
{
long max_allowed_cstate = 2000000000;
- unsigned int cstate, cstates;
+ int cstate, cstates;
cstates = sysfs_get_idlestate_count(cpu);
- if (cstates == 0) {
+ if (cstates < 1) {
printf(_("CPU %u: No C-states info\n"), cpu);
return;
}
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index bf13981..b9cd036 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -684,11 +684,8 @@ sub set_value {
}
${$overrides}{$lvalue} = $prvalue;
}
- if ($rvalue =~ /^\s*$/) {
- delete $opt{$lvalue};
- } else {
- $opt{$lvalue} = $prvalue;
- }
+
+ $opt{$lvalue} = $prvalue;
}
sub set_eval {
@@ -2005,7 +2002,7 @@ sub get_version {
# get the release name
return if ($have_version);
doprint "$make kernelrelease ... ";
- $version = `$make kernelrelease | tail -1`;
+ $version = `$make -s kernelrelease | tail -1`;
chomp($version);
doprint "$version\n";
$have_version = 1;
@@ -3571,7 +3568,9 @@ sub test_this_config {
undef %configs;
assign_configs \%configs, $output_config;
- return $config if (!defined($configs{$config}));
+ if (!defined($configs{$config}) || $configs{$config} =~ /^#/) {
+ return $config;
+ }
doprint "disabling config $config did not change .config\n";
@@ -3945,12 +3944,22 @@ for (my $i = 0, my $repeat = 1; $i <= $opt{"NUM_TESTS"}; $i += $repeat) {
}
}
+sub option_defined {
+ my ($option) = @_;
+
+ if (defined($opt{$option}) && $opt{$option} !~ /^\s*$/) {
+ return 1;
+ }
+
+ return 0;
+}
+
sub __set_test_option {
my ($name, $i) = @_;
my $option = "$name\[$i\]";
- if (defined($opt{$option})) {
+ if (option_defined($option)) {
return $opt{$option};
}
@@ -3958,13 +3967,13 @@ sub __set_test_option {
if ($i >= $test &&
$i < $test + $repeat_tests{$test}) {
$option = "$name\[$test\]";
- if (defined($opt{$option})) {
+ if (option_defined($option)) {
return $opt{$option};
}
}
}
- if (defined($opt{$name})) {
+ if (option_defined($name)) {
return $opt{$name};
}
@@ -4077,8 +4086,14 @@ for (my $i = 1; $i <= $opt{"NUM_TESTS"}; $i++) {
my $installme = "";
$installme = " no_install" if ($no_install);
+ my $name = "";
+
+ if (defined($test_name)) {
+ $name = " ($test_name)";
+ }
+
doprint "\n\n";
- doprint "RUNNING TEST $i of $opt{NUM_TESTS} with option $test_type $run_type$installme\n\n";
+ doprint "RUNNING TEST $i of $opt{NUM_TESTS}$name with option $test_type $run_type$installme\n\n";
if (defined($pre_test)) {
run_command $pre_test;
diff --git a/tools/testing/selftests/ftrace/ftracetest b/tools/testing/selftests/ftrace/ftracetest
index 5152476..da48812 100755
--- a/tools/testing/selftests/ftrace/ftracetest
+++ b/tools/testing/selftests/ftrace/ftracetest
@@ -13,6 +13,7 @@ echo "Usage: ftracetest [options] [testcase(s)] [testcase-directory(s)]"
echo " Options:"
echo " -h|--help Show help message"
echo " -k|--keep Keep passed test logs"
+echo " -v|--verbose Show all stdout messages in testcases"
echo " -d|--debug Debug mode (trace all shell commands)"
exit $1
}
@@ -37,7 +38,7 @@ abspath() {
}
find_testcases() { #directory
- echo `find $1 -name \*.tc`
+ echo `find $1 -name \*.tc | sort`
}
parse_opts() { # opts
@@ -53,6 +54,10 @@ parse_opts() { # opts
KEEP_LOG=1
shift 1
;;
+ --verbose|-v)
+ VERBOSE=1
+ shift 1
+ ;;
--debug|-d)
DEBUG=1
shift 1
@@ -90,6 +95,7 @@ TEST_CASES=`find_testcases $TEST_DIR`
LOG_DIR=$TOP_DIR/logs/`date +%Y%m%d-%H%M%S`/
KEEP_LOG=0
DEBUG=0
+VERBOSE=0
# Parse command-line options
parse_opts $*
@@ -135,15 +141,12 @@ TOTAL_RESULT=0
CASENO=0
testcase() { # testfile
CASENO=$((CASENO+1))
- prlog -n "[$CASENO]"`grep "^#[ \t]*description:" $1 | cut -f2 -d:`
+ desc=`grep "^#[ \t]*description:" $1 | cut -f2 -d:`
+ prlog -n "[$CASENO]$desc"
}
-eval_result() { # retval sigval
- local retval=$2
- if [ $2 -eq 0 ]; then
- test $1 -ne 0 && retval=$FAIL
- fi
- case $retval in
+eval_result() { # sigval
+ case $1 in
$PASS)
prlog " [PASS]"
PASSED_CASES="$PASSED_CASES $CASENO"
@@ -187,6 +190,9 @@ SIG_RESULT=
SIG_BASE=36 # Use realtime signals
SIG_PID=$$
+SIG_FAIL=$((SIG_BASE + FAIL))
+trap 'SIG_RESULT=$FAIL' $SIG_FAIL
+
SIG_UNRESOLVED=$((SIG_BASE + UNRESOLVED))
exit_unresolved () {
kill -s $SIG_UNRESOLVED $SIG_PID
@@ -215,17 +221,25 @@ exit_xfail () {
}
trap 'SIG_RESULT=$XFAIL' $SIG_XFAIL
+__run_test() { # testfile
+ # setup PID and PPID, $$ is not updated.
+ (cd $TRACING_DIR; read PID _ < /proc/self/stat ; set -e; set -x; . $1)
+ [ $? -ne 0 ] && kill -s $SIG_FAIL $SIG_PID
+}
+
# Run one test case
run_test() { # testfile
local testname=`basename $1`
- local testlog=`mktemp --tmpdir=$LOG_DIR ${testname}-XXXXXX.log`
+ local testlog=`mktemp $LOG_DIR/${testname}-log.XXXXXX`
testcase $1
echo "execute: "$1 > $testlog
SIG_RESULT=0
- # setup PID and PPID, $$ is not updated.
- (cd $TRACING_DIR; read PID _ < /proc/self/stat ;
- set -e; set -x; . $1) >> $testlog 2>&1
- eval_result $? $SIG_RESULT
+ if [ $VERBOSE -ne 0 ]; then
+ __run_test $1 2>> $testlog | tee -a $testlog
+ else
+ __run_test $1 >> $testlog 2>&1
+ fi
+ eval_result $SIG_RESULT
if [ $? -eq 0 ]; then
# Remove test log if the test was done as it was expected.
[ $KEEP_LOG -eq 0 ] && rm $testlog
@@ -235,6 +249,9 @@ run_test() { # testfile
fi
}
+# load in the helper functions
+. $TEST_DIR/functions
+
# Main loop
for t in $TEST_CASES; do
run_test $t
diff --git a/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc b/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc
new file mode 100644
index 0000000..fd9c49a
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/00basic/basic4.tc
@@ -0,0 +1,5 @@
+#!/bin/sh
+# description: Basic event tracing check
+test -f available_events -a -f set_event -a -d events
+# check scheduler events are available
+grep -q sched available_events && exit 0 || exit -1 \ No newline at end of file
diff --git a/tools/testing/selftests/ftrace/test.d/event/event-enable.tc b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
new file mode 100644
index 0000000..668616d
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/event/event-enable.tc
@@ -0,0 +1,53 @@
+#!/bin/sh
+# description: event tracing - enable/disable with event level files
+
+do_reset() {
+ echo > set_event
+ clear_trace
+}
+
+fail() { #msg
+ do_reset
+ echo $1
+ exit -1
+}
+
+if [ ! -f set_event -o ! -d events/sched ]; then
+ echo "event tracing is not supported"
+ exit_unsupported
+fi
+
+reset_tracer
+do_reset
+
+echo 'sched:sched_switch' > set_event
+usleep 1
+
+count=`cat trace | grep sched_switch | wc -l`
+if [ $count -eq 0 ]; then
+ fail "sched_switch events are not recorded"
+fi
+
+do_reset
+
+echo 1 > events/sched/sched_switch/enable
+usleep 1
+
+count=`cat trace | grep sched_switch | wc -l`
+if [ $count -eq 0 ]; then
+ fail "sched_switch events are not recorded"
+fi
+
+do_reset
+
+echo 0 > events/sched/sched_switch/enable
+usleep 1
+
+count=`cat trace | grep sched_switch | wc -l`
+if [ $count -ne 0 ]; then
+ fail "sched_switch events should not be recorded"
+fi
+
+do_reset
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
new file mode 100644
index 0000000..655c415
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/event/subsystem-enable.tc
@@ -0,0 +1,53 @@
+#!/bin/sh
+# description: event tracing - enable/disable with subsystem level files
+
+do_reset() {
+ echo > set_event
+ clear_trace
+}
+
+fail() { #msg
+ do_reset
+ echo $1
+ exit -1
+}
+
+if [ ! -f set_event -o ! -d events/sched ]; then
+ echo "event tracing is not supported"
+ exit_unsupported
+fi
+
+reset_tracer
+do_reset
+
+echo 'sched:*' > set_event
+usleep 1
+
+count=`cat trace | grep -v ^# | awk '{ print $5 }' | sort -u | wc -l`
+if [ $count -lt 3 ]; then
+ fail "at least fork, exec and exit events should be recorded"
+fi
+
+do_reset
+
+echo 1 > events/sched/enable
+usleep 1
+
+count=`cat trace | grep -v ^# | awk '{ print $5 }' | sort -u | wc -l`
+if [ $count -lt 3 ]; then
+ fail "at least fork, exec and exit events should be recorded"
+fi
+
+do_reset
+
+echo 0 > events/sched/enable
+usleep 1
+
+count=`cat trace | grep -v ^# | awk '{ print $5 }' | sort -u | wc -l`
+if [ $count -ne 0 ]; then
+ fail "any of scheduler events should not be recorded"
+fi
+
+do_reset
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc b/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc
new file mode 100644
index 0000000..4808457
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/event/toplevel-enable.tc
@@ -0,0 +1,47 @@
+#!/bin/sh
+# description: event tracing - enable/disable with top level files
+
+do_reset() {
+ echo > set_event
+ clear_trace
+}
+
+fail() { #msg
+ do_reset
+ echo $1
+ exit -1
+}
+
+if [ ! -f available_events -o ! -f set_event -o ! -d events ]; then
+ echo "event tracing is not supported"
+ exit_unsupported
+fi
+
+reset_tracer
+do_reset
+
+echo '*:*' > set_event
+count=`cat trace | grep -v ^# | wc -l`
+if [ $count -eq 0 ]; then
+ fail "none of events are recorded"
+fi
+
+do_reset
+
+echo 1 > events/enable
+count=`cat trace | grep -v ^# | wc -l`
+if [ $count -eq 0 ]; then
+ fail "none of events are recorded"
+fi
+
+do_reset
+
+echo 0 > events/enable
+count=`cat trace | grep -v ^# | wc -l`
+if [ $count -ne 0 ]; then
+ fail "any of events should not be recorded"
+fi
+
+do_reset
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc
new file mode 100644
index 0000000..c15e018
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter-stack.tc
@@ -0,0 +1,89 @@
+#!/bin/sh
+# description: ftrace - function graph filters with stack tracer
+
+# Make sure that function graph filtering works, and is not
+# affected by other tracers enabled (like stack tracer)
+
+if ! grep -q function_graph available_tracers; then
+ echo "no function graph tracer configured"
+ exit_unsupported
+fi
+
+if [ ! -f set_ftrace_filter ]; then
+ echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
+ exit_unsupported
+fi
+
+do_reset() {
+ reset_tracer
+ echo 0 > /proc/sys/kernel/stack_tracer_enabled
+ enable_tracing
+ clear_trace
+ echo > set_ftrace_filter
+}
+
+fail() { # msg
+ do_reset
+ echo $1
+ exit -1
+}
+
+disable_tracing
+clear_trace;
+
+# filter something, schedule is always good
+if ! echo "schedule" > set_ftrace_filter; then
+ # test for powerpc 64
+ if ! echo ".schedule" > set_ftrace_filter; then
+ fail "can not enable schedule filter"
+ fi
+fi
+
+echo function_graph > current_tracer
+
+if [ ! -f stack_trace ]; then
+ echo "Stack tracer not configured"
+ do_reset
+ exit_unsupported;
+fi
+
+echo "Now testing with stack tracer"
+
+echo 1 > /proc/sys/kernel/stack_tracer_enabled
+
+disable_tracing
+clear_trace
+enable_tracing
+sleep 1
+
+count=`cat trace | grep '()' | grep -v schedule | wc -l`
+
+if [ $count -ne 0 ]; then
+ fail "Graph filtering not working with stack tracer?"
+fi
+
+# Make sure we did find something
+count=`cat trace | grep 'schedule()' | wc -l`
+if [ $count -eq 0 ]; then
+ fail "No schedule traces found?"
+fi
+
+echo 0 > /proc/sys/kernel/stack_tracer_enabled
+clear_trace
+sleep 1
+
+
+count=`cat trace | grep '()' | grep -v schedule | wc -l`
+
+if [ $count -ne 0 ]; then
+ fail "Graph filtering not working after stack tracer disabled?"
+fi
+
+count=`cat trace | grep 'schedule()' | wc -l`
+if [ $count -eq 0 ]; then
+ fail "No schedule traces found?"
+fi
+
+do_reset
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc
new file mode 100644
index 0000000..6af5f63
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/fgraph-filter.tc
@@ -0,0 +1,52 @@
+#!/bin/sh
+# description: ftrace - function graph filters
+
+# Make sure that function graph filtering works
+
+if ! grep -q function_graph available_tracers; then
+ echo "no function graph tracer configured"
+ exit_unsupported
+fi
+
+do_reset() {
+ reset_tracer
+ enable_tracing
+ clear_trace
+}
+
+fail() { # msg
+ do_reset
+ echo $1
+ exit -1
+}
+
+disable_tracing
+clear_trace
+
+# filter something, schedule is always good
+if ! echo "schedule" > set_ftrace_filter; then
+ # test for powerpc 64
+ if ! echo ".schedule" > set_ftrace_filter; then
+ fail "can not enable schedule filter"
+ fi
+fi
+
+echo function_graph > current_tracer
+enable_tracing
+sleep 1
+# search for functions (has "()" on the line), and make sure
+# that only the schedule function was found
+count=`cat trace | grep '()' | grep -v schedule | wc -l`
+if [ $count -ne 0 ]; then
+ fail "Graph filtering not working by itself?"
+fi
+
+# Make sure we did find something
+count=`cat trace | grep 'schedule()' | wc -l`
+if [ $count -eq 0 ]; then
+ fail "No schedule traces found?"
+fi
+
+do_reset
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc b/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc
new file mode 100644
index 0000000..2e719cb
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/func_profiler.tc
@@ -0,0 +1,80 @@
+#!/bin/sh
+# description: ftrace - function profiler with function tracing
+
+# There was a bug after a rewrite of the ftrace infrastructure that
+# caused the function_profiler not to be able to run with the function
+# tracer, because the function_profiler used the function_graph tracer
+# and it was assumed the two could not run simultaneously.
+#
+# There was another related bug where the solution to the first bug
+# broke the way filtering of the function tracer worked.
+#
+# This test triggers those bugs on those kernels.
+#
+# We need function_graph and profiling to to run this test
+if ! grep -q function_graph available_tracers; then
+ echo "no function graph tracer configured"
+ exit_unsupported;
+fi
+
+if [ ! -f set_ftrace_filter ]; then
+ echo "set_ftrace_filter not found? Is dynamic ftrace not set?"
+ exit_unsupported
+fi
+
+if [ ! -f function_profile_enabled ]; then
+ echo "function_profile_enabled not found, function profiling enabled?"
+ exit_unsupported
+fi
+
+fail() { # mesg
+ reset_tracer
+ echo > set_ftrace_filter
+ echo $1
+ exit -1
+}
+
+echo "Testing function tracer with profiler:"
+echo "enable function tracer"
+echo function > current_tracer
+echo "enable profiler"
+echo 1 > function_profile_enabled
+
+sleep 1
+
+echo "Now filter on just schedule"
+echo '*schedule' > set_ftrace_filter
+clear_trace
+
+echo "Now disable function profiler"
+echo 0 > function_profile_enabled
+
+sleep 1
+
+# make sure only schedule functions exist
+
+echo "testing if only schedule is being traced"
+if grep -v -e '^#' -e 'schedule' trace; then
+ fail "more than schedule was found"
+fi
+
+echo "Make sure schedule was traced"
+if ! grep -e 'schedule' trace > /dev/null; then
+ cat trace
+ fail "can not find schedule in trace"
+fi
+
+echo > set_ftrace_filter
+clear_trace
+
+sleep 1
+
+echo "make sure something other than scheduler is being traced"
+if ! grep -v -e '^#' -e 'schedule' trace > /dev/null; then
+ cat trace
+ fail "no other functions besides schedule was found"
+fi
+
+reset_tracer
+
+exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/functions b/tools/testing/selftests/ftrace/test.d/functions
new file mode 100644
index 0000000..5d8cd06
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/functions
@@ -0,0 +1,16 @@
+
+clear_trace() { # reset trace output
+ echo > trace
+}
+
+disable_tracing() { # stop trace recording
+ echo 0 > tracing_on
+}
+
+enable_tracing() { # start trace recording
+ echo 1 > tracing_on
+}
+
+reset_tracer() { # reset the current tracer
+ echo nop > current_tracer
+}
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
index 1b8b665..a5a4262 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/add_and_remove.tc
@@ -9,3 +9,4 @@ echo p:myevent do_fork > kprobe_events
grep myevent kprobe_events
test -d events/kprobes/myevent
echo > kprobe_events
+clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
index b55c840..d8c7bb6 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/busy_check.tc
@@ -11,3 +11,4 @@ echo 1 > events/kprobes/myevent/enable
echo > kprobe_events && exit 1 # this must fail
echo 0 > events/kprobes/myevent/enable
echo > kprobe_events # this must succeed
+clear_trace
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
index a603d3f..c45ee27 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_args.tc
@@ -12,5 +12,6 @@ echo 1 > events/kprobes/testprobe/enable
( echo "forked")
echo 0 > events/kprobes/testprobe/enable
echo "-:testprobe" >> kprobe_events
+clear_trace
test -d events/kprobes/testprobe && exit 1 || exit 0
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
new file mode 100644
index 0000000..ab41d2b
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kprobe_ftrace.tc
@@ -0,0 +1,55 @@
+#!/bin/sh
+# description: Kprobe dynamic event with function tracer
+
+[ -f kprobe_events ] || exit_unsupported # this is configurable
+grep function available_tracers || exit_unsupported # this is configurable
+
+# prepare
+echo nop > current_tracer
+echo do_fork > set_ftrace_filter
+echo 0 > events/enable
+echo > kprobe_events
+echo 'p:testprobe do_fork' > kprobe_events
+
+# kprobe on / ftrace off
+echo 1 > events/kprobes/testprobe/enable
+echo > trace
+( echo "forked")
+grep testprobe trace
+! grep 'do_fork <-' trace
+
+# kprobe on / ftrace on
+echo function > current_tracer
+echo > trace
+( echo "forked")
+grep testprobe trace
+grep 'do_fork <-' trace
+
+# kprobe off / ftrace on
+echo 0 > events/kprobes/testprobe/enable
+echo > trace
+( echo "forked")
+! grep testprobe trace
+grep 'do_fork <-' trace
+
+# kprobe on / ftrace on
+echo 1 > events/kprobes/testprobe/enable
+echo function > current_tracer
+echo > trace
+( echo "forked")
+grep testprobe trace
+grep 'do_fork <-' trace
+
+# kprobe on / ftrace off
+echo nop > current_tracer
+echo > trace
+( echo "forked")
+grep testprobe trace
+! grep 'do_fork <-' trace
+
+# cleanup
+echo nop > current_tracer
+echo > set_ftrace_filter
+echo 0 > events/kprobes/testprobe/enable
+echo > kprobe_events
+echo > trace
diff --git a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
index 283c29e..3171798 100644
--- a/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
+++ b/tools/testing/selftests/ftrace/test.d/kprobe/kretprobe_args.tc
@@ -12,4 +12,5 @@ echo 1 > events/kprobes/testprobe2/enable
( echo "forked")
echo 0 > events/kprobes/testprobe2/enable
echo '-:testprobe2' >> kprobe_events
+clear_trace
test -d events/kprobes/testprobe2 && exit 1 || exit 0
diff --git a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
index f6b2b47..8ca9f21 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm-test-1-run.sh
@@ -45,7 +45,7 @@ trap 'rm -rf $T' 0
touch $T
. $KVM/bin/functions.sh
-. $KVPATH/ver_functions.sh
+. $CONFIGFRAG/ver_functions.sh
config_template=${1}
config_dir=`echo $config_template | sed -e 's,/[^/]*$,,'`
@@ -168,8 +168,8 @@ then
touch $resdir/buildonly
exit 0
fi
-echo $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
-( $QEMU $qemu_args -m 512 -kernel $builddir/$BOOT_IMAGE -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
+echo $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append \"$qemu_append $boot_args\" > $resdir/qemu-cmd
+( $QEMU $qemu_args -m 512 -kernel $resdir/bzImage -append "$qemu_append $boot_args"; echo $? > $resdir/qemu-retval ) &
qemu_pid=$!
commandcompleted=0
echo Monitoring qemu job at pid $qemu_pid
diff --git a/tools/testing/selftests/rcutorture/bin/kvm.sh b/tools/testing/selftests/rcutorture/bin/kvm.sh
index e527dc9..368d64a 100755
--- a/tools/testing/selftests/rcutorture/bin/kvm.sh
+++ b/tools/testing/selftests/rcutorture/bin/kvm.sh
@@ -47,7 +47,6 @@ resdir=""
configs=""
cpus=0
ds=`date +%Y.%m.%d-%H:%M:%S`
-kversion=""
. functions.sh
@@ -64,7 +63,6 @@ usage () {
echo " --duration minutes"
echo " --interactive"
echo " --kmake-arg kernel-make-arguments"
- echo " --kversion vN.NN"
echo " --mac nn:nn:nn:nn:nn:nn"
echo " --no-initrd"
echo " --qemu-args qemu-system-..."
@@ -128,11 +126,6 @@ do
TORTURE_KMAKE_ARG="$2"
shift
;;
- --kversion)
- checkarg --kversion "(kernel version)" $# "$2" '^v[0-9.]*$' '^error'
- kversion=$2
- shift
- ;;
--mac)
checkarg --mac "(MAC address)" $# "$2" '^\([0-9a-fA-F]\{2\}:\)\{5\}[0-9a-fA-F]\{2\}$' error
TORTURE_QEMU_MAC=$2
@@ -170,11 +163,10 @@ do
done
CONFIGFRAG=${KVM}/configs/${TORTURE_SUITE}; export CONFIGFRAG
-KVPATH=${CONFIGFRAG}/$kversion; export KVPATH
if test -z "$configs"
then
- configs="`cat $CONFIGFRAG/$kversion/CFLIST`"
+ configs="`cat $CONFIGFRAG/CFLIST`"
fi
if test -z "$resdir"
@@ -186,10 +178,10 @@ fi
touch $T/cfgcpu
for CF in $configs
do
- if test -f "$CONFIGFRAG/$kversion/$CF"
+ if test -f "$CONFIGFRAG/$CF"
then
- cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$kversion/$CF`
- cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$kversion/$CF" "$cpu_count"`
+ cpu_count=`configNR_CPUS.sh $CONFIGFRAG/$CF`
+ cpu_count=`configfrag_boot_cpus "$TORTURE_BOOTARGS" "$CONFIGFRAG/$CF" "$cpu_count"`
echo $CF $cpu_count >> $T/cfgcpu
else
echo "The --configs file $CF does not exist, terminating."
@@ -252,7 +244,6 @@ END {
cat << ___EOF___ > $T/script
CONFIGFRAG="$CONFIGFRAG"; export CONFIGFRAG
KVM="$KVM"; export KVM
-KVPATH="$KVPATH"; export KVPATH
PATH="$PATH"; export PATH
TORTURE_BOOT_IMAGE="$TORTURE_BOOT_IMAGE"; export TORTURE_BOOT_IMAGE
TORTURE_BUILDONLY="$TORTURE_BUILDONLY"; export TORTURE_BUILDONLY
@@ -285,7 +276,7 @@ then
fi
___EOF___
awk < $T/cfgcpu.pack \
- -v CONFIGDIR="$CONFIGFRAG/$kversion/" \
+ -v CONFIGDIR="$CONFIGFRAG/" \
-v KVM="$KVM" \
-v ncpus=$cpus \
-v rd=$resdir/$ds/ \
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY02 b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
index f4feaee..36e41df 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TINY02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY02
@@ -7,6 +7,8 @@ CONFIG_HZ_PERIODIC=y
CONFIG_NO_HZ_IDLE=n
CONFIG_NO_HZ_FULL=n
CONFIG_RCU_TRACE=y
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
CONFIG_PREEMPT_COUNT=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TINY02.boot b/tools/testing/selftests/rcutorture/configs/rcu/TINY02.boot
new file mode 100644
index 0000000..0f08027
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TINY02.boot
@@ -0,0 +1,2 @@
+rcupdate.rcu_self_test=1
+rcupdate.rcu_self_test_bh=1
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE01 b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
index 38e3895..f8a10a7 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE01
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE01
@@ -2,7 +2,7 @@ CONFIG_SMP=y
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
@@ -14,6 +14,5 @@ CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ZERO=y
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02 b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
index ea119ba..629122f 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02
@@ -3,7 +3,7 @@ CONFIG_NR_CPUS=8
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
@@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=n
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
index 19cf948..a25de47 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE02-T
@@ -3,7 +3,7 @@ CONFIG_NR_CPUS=8
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
@@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=n
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE03 b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
index f4567fb..53f24e0 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE03
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE03
@@ -3,7 +3,7 @@ CONFIG_NR_CPUS=8
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=y
CONFIG_NO_HZ_IDLE=n
CONFIG_NO_HZ_FULL=n
@@ -15,7 +15,6 @@ CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
+CONFIG_RCU_KTHREAD_PRIO=2
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE04 b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
index 0a262fb..0f84db3 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE04
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE04
@@ -19,5 +19,4 @@ CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_RCU_CPU_STALL_VERBOSE=y
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05 b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
index 3a06b97..212e3bf 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05
@@ -19,5 +19,4 @@ CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_PROVE_RCU=y
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot
index 3b42b8b..15b3e1a 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE05.boot
@@ -1 +1,2 @@
rcutorture.torture_type=sched
+rcupdate.rcu_self_test_sched=1
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06 b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
index 8f084cc..7eee63b 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE06
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06
@@ -20,5 +20,4 @@ CONFIG_DEBUG_LOCK_ALLOC=y
CONFIG_PROVE_LOCKING=y
CONFIG_PROVE_RCU=y
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot
new file mode 100644
index 0000000..da9a03a
--- /dev/null
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE06.boot
@@ -0,0 +1,3 @@
+rcupdate.rcu_self_test=1
+rcupdate.rcu_self_test_bh=1
+rcupdate.rcu_self_test_sched=1
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE07 b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
index 8f10176..92a97fa 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE07
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE07
@@ -19,5 +19,4 @@ CONFIG_RCU_FANOUT_EXACT=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08 b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
index 69a2e25..5812027 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08
@@ -3,7 +3,7 @@ CONFIG_NR_CPUS=16
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
@@ -18,7 +18,8 @@ CONFIG_RCU_FANOUT_LEAF=2
CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ALL=y
CONFIG_DEBUG_LOCK_ALLOC=n
+CONFIG_PROVE_LOCKING=y
+CONFIG_PROVE_RCU=y
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
index a0f32fb..3eaecca 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08-T
@@ -3,7 +3,7 @@ CONFIG_NR_CPUS=16
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
@@ -19,6 +19,5 @@ CONFIG_RCU_NOCB_CPU=y
CONFIG_RCU_NOCB_CPU_ALL=y
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot b/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot
index 3b42b8b..2561daf 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE08.boot
@@ -1 +1,3 @@
rcutorture.torture_type=sched
+rcupdate.rcu_self_test=1
+rcupdate.rcu_self_test_sched=1
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/TREE09 b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
index b7a62a5..6076b36 100644
--- a/tools/testing/selftests/rcutorture/configs/rcu/TREE09
+++ b/tools/testing/selftests/rcutorture/configs/rcu/TREE09
@@ -3,7 +3,7 @@ CONFIG_NR_CPUS=1
CONFIG_PREEMPT_NONE=n
CONFIG_PREEMPT_VOLUNTARY=n
CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
+#CHECK#CONFIG_PREEMPT_RCU=y
CONFIG_HZ_PERIODIC=n
CONFIG_NO_HZ_IDLE=y
CONFIG_NO_HZ_FULL=n
@@ -14,6 +14,5 @@ CONFIG_HIBERNATION=n
CONFIG_RCU_NOCB_CPU=n
CONFIG_DEBUG_LOCK_ALLOC=n
CONFIG_RCU_CPU_STALL_INFO=n
-CONFIG_RCU_CPU_STALL_VERBOSE=n
CONFIG_RCU_BOOST=n
CONFIG_DEBUG_OBJECTS_RCU_HEAD=n
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST
deleted file mode 100644
index 1822394..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/CFLIST
+++ /dev/null
@@ -1,14 +0,0 @@
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index d3ef873..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 02e4185..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b3100f6..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index c56b445..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index 90d924f..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/N5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh
deleted file mode 100644
index 023f312..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH
deleted file mode 100644
index 6fd0235..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/NT3-NH
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index f72402d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 0f3b667..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b035e14..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index 3ccf6a9..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index a55c008..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/P5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,27 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh
deleted file mode 100644
index e3361c3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH
deleted file mode 100644
index 64abfc3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/PT2-NH
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh
deleted file mode 100644
index 5ace37a..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v0.0/ver_functions.sh
+++ /dev/null
@@ -1,33 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# 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, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# per_version_boot_params bootparam-string config-file seconds
-#
-# Adds per-version torture-module parameters to kernels supporting them.
-# Which old kernels do not.
-per_version_boot_params () {
- echo rcutorture.stat_interval=15 \
- rcutorture.shutdown_secs=$3 \
- rcutorture.rcutorture_runnable=1 \
- rcutorture.test_no_idle_hz=1 \
- rcutorture.verbose=1
-}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST
deleted file mode 100644
index da4cbc66..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/CFLIST
+++ /dev/null
@@ -1,17 +0,0 @@
-sysidleY.2013.06.19a
-sysidleN.2013.06.19a
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-P6---t-nh-SD-smp-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index d81e11d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 02e4185..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b3100f6..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index c56b445..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index 90d924f..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp
deleted file mode 100644
index 0ccc36d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N6---t-nh-SD-smp-hp
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_NR_CPUS=1
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP
deleted file mode 100644
index 3f640cf..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N7-4-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,26 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP
deleted file mode 100644
index 285da2d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/N8-2-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=14
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh
deleted file mode 100644
index 023f312..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH
deleted file mode 100644
index 6fd0235..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/NT3-NH
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index 9647c44..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 0f3b667..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b035e14..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index 3ccf6a9..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index a55c008..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,27 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp
deleted file mode 100644
index f4c9175..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P6---t-nh-SD-smp-hp
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=n
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP
deleted file mode 100644
index 77a8c5b..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=n
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all
deleted file mode 100644
index 0eecebc..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-all
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none
deleted file mode 100644
index 0eecebc..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-HP-none
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=y
-CONFIG_RCU_NOCB_CPU_ZERO=n
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp
deleted file mode 100644
index 588bc70..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/P7-4-T-NH-SD-SMP-hp
+++ /dev/null
@@ -1,30 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=16
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_RCU_NOCB_CPU=y
-CONFIG_RCU_NOCB_CPU_NONE=n
-CONFIG_RCU_NOCB_CPU_ZERO=y
-CONFIG_RCU_NOCB_CPU_ALL=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_SLUB=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh
deleted file mode 100644
index e3361c3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH
deleted file mode 100644
index 64abfc3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.12/PT2-NH
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST
deleted file mode 100644
index 1822394..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/CFLIST
+++ /dev/null
@@ -1,14 +0,0 @@
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index d81e11d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 02e4185..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b3100f6..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index c56b445..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index 90d924f..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/N5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh
deleted file mode 100644
index 023f312..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH
deleted file mode 100644
index 6fd0235..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/NT3-NH
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index 9647c44..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 0f3b667..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b035e14..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index 3ccf6a9..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index a55c008..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/P5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,27 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh
deleted file mode 100644
index e3361c3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH
deleted file mode 100644
index 64abfc3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/PT2-NH
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh
deleted file mode 100644
index bae5569..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.3/ver_functions.sh
+++ /dev/null
@@ -1,44 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# 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, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
- if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
- then
- echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
- echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
- fi
-}
-
-# per_version_boot_params bootparam-string config-file seconds
-#
-# Adds per-version torture-module parameters to kernels supporting them.
-per_version_boot_params () {
- echo $1 `rcutorture_param_onoff "$1" "$2"` \
- rcutorture.stat_interval=15 \
- rcutorture.shutdown_secs=$3 \
- rcutorture.rcutorture_runnable=1 \
- rcutorture.test_no_idle_hz=1 \
- rcutorture.verbose=1
-}
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST
deleted file mode 100644
index 1822394..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/CFLIST
+++ /dev/null
@@ -1,14 +0,0 @@
-P1-S-T-NH-SD-SMP-HP
-P2-2-t-nh-sd-SMP-hp
-P3-3-T-nh-SD-SMP-hp
-P4-A-t-NH-sd-SMP-HP
-P5-U-T-NH-sd-SMP-hp
-N1-S-T-NH-SD-SMP-HP
-N2-2-t-nh-sd-SMP-hp
-N3-3-T-nh-SD-SMP-hp
-N4-A-t-NH-sd-SMP-HP
-N5-U-T-NH-sd-SMP-hp
-PT1-nh
-PT2-NH
-NT1-nh
-NT3-NH
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index d81e11d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,19 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 02e4185..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b3100f6..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index c56b445..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,18 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index 90d924f..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/N5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-#CHECK#CONFIG_TREE_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh
deleted file mode 100644
index 023f312..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH
deleted file mode 100644
index 6fd0235..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/NT3-NH
+++ /dev/null
@@ -1,20 +0,0 @@
-#CHECK#CONFIG_TINY_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=y
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=n
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP
deleted file mode 100644
index 9647c44..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P1-S-T-NH-SD-SMP-HP
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_RCU_FAST_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=8
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp
deleted file mode 100644
index 0f3b667..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P2-2-t-nh-sd-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=4
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp
deleted file mode 100644
index b035e14..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P3-3-T-nh-SD-SMP-hp
+++ /dev/null
@@ -1,20 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_NO_HZ=n
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=2
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP
deleted file mode 100644
index 3ccf6a9..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P4-A-t-NH-sd-SMP-HP
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_RCU_TRACE=n
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=n
-CONFIG_HOTPLUG_CPU=y
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
deleted file mode 100644
index a55c008..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/P5-U-T-NH-sd-SMP-hp
+++ /dev/null
@@ -1,27 +0,0 @@
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_CPU_STALL_INFO=y
-CONFIG_NO_HZ=y
-CONFIG_SMP=y
-CONFIG_RCU_FANOUT=6
-CONFIG_NR_CPUS=8
-CONFIG_RCU_FANOUT_EXACT=y
-CONFIG_HOTPLUG_CPU=n
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-#CHECK#CONFIG_TREE_PREEMPT_RCU=y
-CONFIG_DEBUG_KERNEL=y
-CONFIG_DEBUG_OBJECTS=y
-CONFIG_DEBUG_OBJECTS_RCU_HEAD=y
-CONFIG_RT_MUTEXES=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh
deleted file mode 100644
index e3361c3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT1-nh
+++ /dev/null
@@ -1,23 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_BOOST=y
-CONFIG_RCU_BOOST_PRIO=2
-CONFIG_RCU_TRACE=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=n
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH
deleted file mode 100644
index 64abfc3..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/PT2-NH
+++ /dev/null
@@ -1,22 +0,0 @@
-CONFIG_TINY_PREEMPT_RCU=y
-CONFIG_RCU_TORTURE_TEST=m
-CONFIG_MODULE_UNLOAD=y
-CONFIG_SUSPEND=n
-CONFIG_HIBERNATION=n
-#
-CONFIG_SMP=n
-#
-CONFIG_HOTPLUG_CPU=n
-#
-CONFIG_NO_HZ=y
-#
-CONFIG_PREEMPT_NONE=n
-CONFIG_PREEMPT_VOLUNTARY=n
-CONFIG_PREEMPT=y
-CONFIG_PROVE_LOCKING=y
-CONFIG_PROVE_RCU=y
-CONFIG_SYSFS_DEPRECATED_V2=y
-CONFIG_IKCONFIG=y
-CONFIG_IKCONFIG_PROC=y
-CONFIG_PRINTK_TIME=y
-
diff --git a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh b/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh
deleted file mode 100644
index 8977d8d..0000000
--- a/tools/testing/selftests/rcutorture/configs/rcu/v3.5/ver_functions.sh
+++ /dev/null
@@ -1,57 +0,0 @@
-#!/bin/bash
-#
-# Kernel-version-dependent shell functions for the rest of the scripts.
-#
-# 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, you can access it online at
-# http://www.gnu.org/licenses/gpl-2.0.html.
-#
-# Copyright (C) IBM Corporation, 2013
-#
-# Authors: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
-
-# rcutorture_param_n_barrier_cbs bootparam-string
-#
-# Adds n_barrier_cbs rcutorture module parameter to kernels having it.
-rcutorture_param_n_barrier_cbs () {
- if echo $1 | grep -q "rcutorture\.n_barrier_cbs"
- then
- :
- else
- echo rcutorture.n_barrier_cbs=4
- fi
-}
-
-# rcutorture_param_onoff bootparam-string config-file
-#
-# Adds onoff rcutorture module parameters to kernels having it.
-rcutorture_param_onoff () {
- if ! bootparam_hotplug_cpu "$1" && configfrag_hotplug_cpu "$2"
- then
- echo CPU-hotplug kernel, adding rcutorture onoff. 1>&2
- echo rcutorture.onoff_interval=3 rcutorture.onoff_holdoff=30
- fi
-}
-
-# per_version_boot_params bootparam-string config-file seconds
-#
-# Adds per-version torture-module parameters to kernels supporting them.
-per_version_boot_params () {
- echo $1 `rcutorture_param_onoff "$1" "$2"` \
- `rcutorture_param_n_barrier_cbs "$1"` \
- rcutorture.stat_interval=15 \
- rcutorture.shutdown_secs=$3 \
- rcutorture.rcutorture_runnable=1 \
- rcutorture.test_no_idle_hz=1 \
- rcutorture.verbose=1
-}
diff --git a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
index 28db67b..9ef33a7 100644
--- a/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
+++ b/tools/testing/selftests/rcutorture/doc/TINY_RCU.txt
@@ -34,7 +34,7 @@ CONFIG_PREEMPT
CONFIG_PREEMPT_RCU
CONFIG_SMP
CONFIG_TINY_RCU
-CONFIG_TREE_PREEMPT_RCU
+CONFIG_PREEMPT_RCU
CONFIG_TREE_RCU
All forced by CONFIG_TINY_RCU.
diff --git a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
index 3e588db..ec03c88 100644
--- a/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
+++ b/tools/testing/selftests/rcutorture/doc/TREE_RCU-kconfig.txt
@@ -1,5 +1,5 @@
This document gives a brief rationale for the TREE_RCU-related test
-cases, a group that includes TREE_PREEMPT_RCU.
+cases, a group that includes PREEMPT_RCU.
Kconfig Parameters:
@@ -14,10 +14,9 @@ CONFIG_NO_HZ_FULL_SYSIDLE -- Do one.
CONFIG_PREEMPT -- Do half. (First three and #8.)
CONFIG_PROVE_LOCKING -- Do all but two, covering CONFIG_PROVE_RCU and not.
CONFIG_PROVE_RCU -- Do all but one under CONFIG_PROVE_LOCKING.
-CONFIG_RCU_BOOST -- one of TREE_PREEMPT_RCU.
-CONFIG_RCU_BOOST_PRIO -- set to 2 for _BOOST testing.
-CONFIG_RCU_CPU_STALL_INFO -- do one with and without _VERBOSE.
-CONFIG_RCU_CPU_STALL_VERBOSE -- do one with and without _INFO.
+CONFIG_RCU_BOOST -- one of PREEMPT_RCU.
+CONFIG_RCU_KTHREAD_PRIO -- set to 2 for _BOOST testing.
+CONFIG_RCU_CPU_STALL_INFO -- Do one.
CONFIG_RCU_FANOUT -- Cover hierarchy as currently, but overlap with others.
CONFIG_RCU_FANOUT_EXACT -- Do one.
CONFIG_RCU_FANOUT_LEAF -- Do one non-default.
@@ -27,7 +26,7 @@ CONFIG_RCU_NOCB_CPU_ALL -- Do one.
CONFIG_RCU_NOCB_CPU_NONE -- Do one.
CONFIG_RCU_NOCB_CPU_ZERO -- Do one.
CONFIG_RCU_TRACE -- Do half.
-CONFIG_SMP -- Need one !SMP for TREE_PREEMPT_RCU.
+CONFIG_SMP -- Need one !SMP for PREEMPT_RCU.
RCU-bh: Do one with PREEMPT and one with !PREEMPT.
RCU-sched: Do one with PREEMPT but not BOOST.
@@ -77,7 +76,7 @@ CONFIG_RCU_CPU_STALL_TIMEOUT
CONFIG_RCU_STALL_COMMON
- Implied by TREE_RCU and TREE_PREEMPT_RCU.
+ Implied by TREE_RCU and PREEMPT_RCU.
CONFIG_RCU_TORTURE_TEST
CONFIG_RCU_TORTURE_TEST_RUNNABLE
@@ -88,7 +87,7 @@ CONFIG_RCU_USER_QS
Redundant with CONFIG_NO_HZ_FULL.
-CONFIG_TREE_PREEMPT_RCU
+CONFIG_PREEMPT_RCU
CONFIG_TREE_RCU
These are controlled by CONFIG_PREEMPT.
diff --git a/tools/virtio/linux/virtio.h b/tools/virtio/linux/virtio.h
index 5a2d1f0..8eb6421 100644
--- a/tools/virtio/linux/virtio.h
+++ b/tools/virtio/linux/virtio.h
@@ -6,31 +6,11 @@
/* TODO: empty stubs for now. Broken but enough for virtio_ring.c */
#define list_add_tail(a, b) do {} while (0)
#define list_del(a) do {} while (0)
-
-#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-#define BITS_PER_BYTE 8
-#define BITS_PER_LONG (sizeof(long) * BITS_PER_BYTE)
-#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
-
-/* TODO: Not atomic as it should be:
- * we don't use this for anything important. */
-static inline void clear_bit(int nr, volatile unsigned long *addr)
-{
- unsigned long mask = BIT_MASK(nr);
- unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
-
- *p &= ~mask;
-}
-
-static inline int test_bit(int nr, const volatile unsigned long *addr)
-{
- return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
-}
/* end of stubs */
struct virtio_device {
void *dev;
- unsigned long features[1];
+ u64 features;
};
struct virtqueue {
diff --git a/tools/virtio/linux/virtio_config.h b/tools/virtio/linux/virtio_config.h
index 5049967..83b27e8 100644
--- a/tools/virtio/linux/virtio_config.h
+++ b/tools/virtio/linux/virtio_config.h
@@ -2,5 +2,5 @@
#define VIRTIO_TRANSPORT_F_END 32
#define virtio_has_feature(dev, feature) \
- test_bit((feature), (dev)->features)
+ (__virtio_test_bit((dev), feature))
diff --git a/tools/virtio/virtio_test.c b/tools/virtio/virtio_test.c
index 00ea679..db3437c 100644
--- a/tools/virtio/virtio_test.c
+++ b/tools/virtio/virtio_test.c
@@ -60,7 +60,7 @@ void vhost_vq_setup(struct vdev_info *dev, struct vq_info *info)
{
struct vhost_vring_state state = { .index = info->idx };
struct vhost_vring_file file = { .index = info->idx };
- unsigned long long features = dev->vdev.features[0];
+ unsigned long long features = dev->vdev.features;
struct vhost_vring_addr addr = {
.index = info->idx,
.desc_user_addr = (uint64_t)(unsigned long)info->vring.desc,
@@ -113,8 +113,7 @@ static void vdev_info_init(struct vdev_info* dev, unsigned long long features)
{
int r;
memset(dev, 0, sizeof *dev);
- dev->vdev.features[0] = features;
- dev->vdev.features[1] = features >> 32;
+ dev->vdev.features = features;
dev->buf_size = 1024;
dev->buf = malloc(dev->buf_size);
assert(dev->buf);
diff --git a/tools/virtio/vringh_test.c b/tools/virtio/vringh_test.c
index 14a4f4c..9d4b1bc 100644
--- a/tools/virtio/vringh_test.c
+++ b/tools/virtio/vringh_test.c
@@ -304,7 +304,7 @@ static int parallel_test(unsigned long features,
close(to_guest[1]);
close(to_host[0]);
- gvdev.vdev.features[0] = features;
+ gvdev.vdev.features = features;
gvdev.to_host_fd = to_host[1];
gvdev.notifies = 0;
@@ -449,13 +449,13 @@ int main(int argc, char *argv[])
bool fast_vringh = false, parallel = false;
getrange = getrange_iov;
- vdev.features[0] = 0;
+ vdev.features = 0;
while (argv[1]) {
if (strcmp(argv[1], "--indirect") == 0)
- vdev.features[0] |= (1 << VIRTIO_RING_F_INDIRECT_DESC);
+ __virtio_set_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC);
else if (strcmp(argv[1], "--eventidx") == 0)
- vdev.features[0] |= (1 << VIRTIO_RING_F_EVENT_IDX);
+ __virtio_set_bit(&vdev, VIRTIO_RING_F_EVENT_IDX);
else if (strcmp(argv[1], "--slow-range") == 0)
getrange = getrange_slow;
else if (strcmp(argv[1], "--fast-vringh") == 0)
@@ -468,7 +468,7 @@ int main(int argc, char *argv[])
}
if (parallel)
- return parallel_test(vdev.features[0], getrange, fast_vringh);
+ return parallel_test(vdev.features, getrange, fast_vringh);
if (posix_memalign(&__user_addr_min, PAGE_SIZE, USER_MEM) != 0)
abort();
@@ -483,7 +483,7 @@ int main(int argc, char *argv[])
/* Set up host side. */
vring_init(&vrh.vring, RINGSIZE, __user_addr_min, ALIGN);
- vringh_init_user(&vrh, vdev.features[0], RINGSIZE, true,
+ vringh_init_user(&vrh, vdev.features, RINGSIZE, true,
vrh.vring.desc, vrh.vring.avail, vrh.vring.used);
/* No descriptor to get yet... */
@@ -652,13 +652,13 @@ int main(int argc, char *argv[])
}
/* Test weird (but legal!) indirect. */
- if (vdev.features[0] & (1 << VIRTIO_RING_F_INDIRECT_DESC)) {
+ if (__virtio_test_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC)) {
char *data = __user_addr_max - USER_MEM/4;
struct vring_desc *d = __user_addr_max - USER_MEM/2;
struct vring vring;
/* Force creation of direct, which we modify. */
- vdev.features[0] &= ~(1 << VIRTIO_RING_F_INDIRECT_DESC);
+ __virtio_clear_bit(&vdev, VIRTIO_RING_F_INDIRECT_DESC);
vq = vring_new_virtqueue(0, RINGSIZE, ALIGN, &vdev, true,
__user_addr_min,
never_notify_host,
OpenPOWER on IntegriCloud